summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CREDITS4
-rw-r--r--Documentation/00-INDEX2
-rw-r--r--Documentation/ABI/testing/debugfs-pfo-nx-crypto45
-rw-r--r--Documentation/ABI/testing/dev-kmsg90
-rw-r--r--Documentation/ABI/testing/sysfs-bus-iio (renamed from drivers/staging/iio/Documentation/sysfs-bus-iio)52
-rw-r--r--Documentation/ABI/testing/sysfs-bus-usb19
-rw-r--r--Documentation/ABI/testing/sysfs-class-extcon97
-rw-r--r--Documentation/ABI/testing/sysfs-devices-power35
-rw-r--r--Documentation/ABI/testing/sysfs-devices-system-cpu25
-rw-r--r--Documentation/ABI/testing/sysfs-driver-wacom23
-rw-r--r--Documentation/ABI/testing/sysfs-power59
-rw-r--r--Documentation/DocBook/Makefile2
-rw-r--r--Documentation/DocBook/kernel-api.tmpl13
-rw-r--r--Documentation/DocBook/kernel-hacking.tmpl2
-rw-r--r--Documentation/DocBook/libata.tmpl2
-rw-r--r--Documentation/DocBook/mcabook.tmpl107
-rw-r--r--Documentation/DocBook/media/Makefile4
-rw-r--r--Documentation/DocBook/media/dvb/dvbproperty.xml160
-rw-r--r--Documentation/DocBook/media/v4l/biblio.xml29
-rw-r--r--Documentation/DocBook/media/v4l/common.xml38
-rw-r--r--Documentation/DocBook/media/v4l/compat.xml75
-rw-r--r--Documentation/DocBook/media/v4l/controls.xml714
-rw-r--r--Documentation/DocBook/media/v4l/dev-subdev.xml202
-rw-r--r--Documentation/DocBook/media/v4l/io.xml12
-rw-r--r--Documentation/DocBook/media/v4l/pixfmt-srggb10.xml2
-rw-r--r--Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml29
-rw-r--r--Documentation/DocBook/media/v4l/pixfmt.xml6
-rw-r--r--Documentation/DocBook/media/v4l/subdev-image-processing-crop.dia614
-rw-r--r--Documentation/DocBook/media/v4l/subdev-image-processing-crop.svg63
-rw-r--r--Documentation/DocBook/media/v4l/subdev-image-processing-full.dia1588
-rw-r--r--Documentation/DocBook/media/v4l/subdev-image-processing-full.svg163
-rw-r--r--Documentation/DocBook/media/v4l/subdev-image-processing-scaling-multi-source.dia1152
-rw-r--r--Documentation/DocBook/media/v4l/subdev-image-processing-scaling-multi-source.svg116
-rw-r--r--Documentation/DocBook/media/v4l/v4l2.xml44
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-create-bufs.xml16
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-cropcap.xml4
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml211
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml4
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml119
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-enum-fmt.xml4
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-enuminput.xml2
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-enumoutput.xml2
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-g-crop.xml4
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-g-dv-preset.xml6
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml130
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml26
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-g-fmt.xml2
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-g-frequency.xml6
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-g-parm.xml5
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml2
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-g-tuner.xml2
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml6
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-query-dv-preset.xml4
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-query-dv-timings.xml104
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-queryctrl.xml41
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-reqbufs.xml7
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml5
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-subdev-g-crop.xml9
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml228
-rw-r--r--Documentation/HOWTO32
-rw-r--r--Documentation/Makefile2
-rw-r--r--Documentation/arm/00-INDEX2
-rw-r--r--Documentation/arm/IXP200069
-rw-r--r--Documentation/arm/SPEAr/overview.txt13
-rw-r--r--Documentation/blackfin/bfin-gpio-notes.txt2
-rw-r--r--Documentation/cgroups/resource_counter.txt4
-rw-r--r--Documentation/devices.txt11
-rw-r--r--Documentation/devicetree/bindings/arm/atmel-adc.txt65
-rw-r--r--Documentation/devicetree/bindings/arm/gic.txt35
-rw-r--r--Documentation/devicetree/bindings/arm/lpc32xx-mic.txt38
-rw-r--r--Documentation/devicetree/bindings/arm/lpc32xx.txt8
-rw-r--r--Documentation/devicetree/bindings/arm/mrvl/intc.txt40
-rw-r--r--Documentation/devicetree/bindings/arm/mrvl/mrvl.txt (renamed from Documentation/devicetree/bindings/arm/mrvl.txt)8
-rw-r--r--Documentation/devicetree/bindings/arm/mrvl/timer.txt13
-rw-r--r--Documentation/devicetree/bindings/arm/spear.txt18
-rw-r--r--Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-mc.txt16
-rw-r--r--Documentation/devicetree/bindings/arm/tegra/nvidia,tegra30-mc.txt18
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-nmk.txt31
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio_lpc32xx.txt43
-rw-r--r--Documentation/devicetree/bindings/gpio/mrvl-gpio.txt18
-rw-r--r--Documentation/devicetree/bindings/i2c/mrvl-i2c.txt15
-rw-r--r--Documentation/devicetree/bindings/i2c/pnx.txt36
-rw-r--r--Documentation/devicetree/bindings/input/spear-keyboard.txt20
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/lpc32xx-tsc.txt16
-rw-r--r--Documentation/devicetree/bindings/input/twl6040-vibra.txt37
-rw-r--r--Documentation/devicetree/bindings/misc/bmp085.txt20
-rw-r--r--Documentation/devicetree/bindings/mtd/orion-nand.txt50
-rw-r--r--Documentation/devicetree/bindings/net/can/fsl-flexcan.txt2
-rw-r--r--Documentation/devicetree/bindings/net/lpc-eth.txt24
-rw-r--r--Documentation/devicetree/bindings/pinctrl/pinctrl_spear.txt108
-rw-r--r--Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt49
-rw-r--r--Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt17
-rw-r--r--Documentation/devicetree/bindings/sound/mxs-saif.txt36
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt32
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt15
-rw-r--r--Documentation/devicetree/bindings/sound/tegra-audio-trimslice.txt14
-rw-r--r--Documentation/devicetree/bindings/sound/tegra-audio-wm8753.txt54
-rw-r--r--Documentation/devicetree/bindings/staging/iio/adc/lpc32xx-adc.txt16
-rw-r--r--Documentation/devicetree/bindings/staging/iio/adc/spear-adc.txt26
-rw-r--r--Documentation/devicetree/bindings/usb/isp1301.txt25
-rw-r--r--Documentation/devicetree/bindings/usb/lpc32xx-udc.txt28
-rw-r--r--Documentation/devicetree/bindings/usb/ohci-nxp.txt24
-rw-r--r--Documentation/devicetree/bindings/usb/spear-usb.txt39
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt2
-rw-r--r--Documentation/devicetree/bindings/watchdog/pnx4008-wdt.txt13
-rw-r--r--Documentation/devicetree/booting-without-of.txt55
-rwxr-xr-xDocumentation/dvb/get_dvb_firmware20
-rw-r--r--Documentation/dvb/opera-firmware.txt4
-rw-r--r--Documentation/dynamic-debug-howto.txt184
-rw-r--r--Documentation/edac.txt2
-rw-r--r--Documentation/eisa.txt2
-rw-r--r--Documentation/extcon/porting-android-switch-class124
-rw-r--r--Documentation/feature-removal-schedule.txt41
-rw-r--r--Documentation/filesystems/nfs/pnfs.txt2
-rw-r--r--Documentation/filesystems/qnx6.txt28
-rw-r--r--Documentation/gpio.txt3
-rw-r--r--Documentation/hwmon/ina2xx29
-rw-r--r--Documentation/hwmon/it8730
-rw-r--r--Documentation/hwmon/wm831x2
-rw-r--r--Documentation/ioctl/ioctl-number.txt1
-rw-r--r--Documentation/kernel-parameters.txt24
-rw-r--r--Documentation/mca.txt313
-rw-r--r--Documentation/media-framework.txt19
-rw-r--r--Documentation/memory-devices/ti-emif.txt57
-rw-r--r--Documentation/memory-hotplug.txt2
-rw-r--r--Documentation/misc-devices/mei/.gitignore1
-rw-r--r--Documentation/misc-devices/mei/Makefile8
-rw-r--r--Documentation/misc-devices/mei/TODO2
-rw-r--r--Documentation/misc-devices/mei/mei-amt-version.c (renamed from drivers/staging/mei/mei-amt-version.c)2
-rw-r--r--Documentation/misc-devices/mei/mei.txt (renamed from drivers/staging/mei/mei.txt)0
-rw-r--r--Documentation/networking/can.txt2
-rw-r--r--Documentation/nfc/nfc-hci.txt45
-rw-r--r--Documentation/parisc/debugging2
-rw-r--r--Documentation/power/suspend-and-cpuhotplug.txt2
-rw-r--r--Documentation/ramoops.txt16
-rw-r--r--Documentation/scheduler/sched-design-CFS.txt6
-rw-r--r--Documentation/scheduler/sched-domains.txt4
-rw-r--r--Documentation/scsi/00-INDEX2
-rw-r--r--Documentation/scsi/ibmmca.txt1402
-rw-r--r--Documentation/scsi/scsi-parameters.txt6
-rw-r--r--Documentation/scsi/scsi_mid_low_api.txt2
-rw-r--r--Documentation/serial/stallion.txt22
-rw-r--r--Documentation/sound/alsa/ALSA-Configuration.txt2
-rw-r--r--Documentation/sound/alsa/compress_offload.txt2
-rw-r--r--Documentation/sound/oss/ALS4
-rw-r--r--Documentation/static-keys.txt2
-rw-r--r--Documentation/trace/uprobetracer.txt113
-rw-r--r--Documentation/usb/dwc3.txt2
-rw-r--r--Documentation/usb/functionfs.txt67
-rw-r--r--Documentation/usb/wusb-cbaf2
-rw-r--r--Documentation/video4linux/4CCs.txt32
-rw-r--r--Documentation/video4linux/README.cpia22
-rw-r--r--Documentation/video4linux/gspca.txt1
-rw-r--r--Documentation/video4linux/v4l2-controls.txt21
-rw-r--r--Documentation/video4linux/v4l2-framework.txt106
-rw-r--r--Documentation/vme_api.txt (renamed from drivers/staging/vme/vme_api.txt)0
-rw-r--r--Documentation/watchdog/src/watchdog-test.c20
-rw-r--r--Documentation/watchdog/watchdog-kernel-api.txt2
-rw-r--r--Documentation/zh_CN/magic-number.txt2
-rw-r--r--MAINTAINERS167
-rw-r--r--Makefile39
-rw-r--r--README222
-rw-r--r--arch/Kconfig17
-rw-r--r--arch/alpha/Kconfig4
-rw-r--r--arch/alpha/include/asm/gpio.h59
-rw-r--r--arch/alpha/include/asm/io.h5
-rw-r--r--arch/alpha/include/asm/processor.h3
-rw-r--r--arch/alpha/include/asm/sysinfo.h1
-rw-r--r--arch/alpha/include/asm/unistd.h6
-rw-r--r--arch/alpha/kernel/osf_sys.c166
-rw-r--r--arch/alpha/kernel/pci_iommu.c20
-rw-r--r--arch/alpha/kernel/perf_event.c3
-rw-r--r--arch/alpha/kernel/signal.c80
-rw-r--r--arch/alpha/kernel/systbls.S10
-rw-r--r--arch/arm/Kconfig77
-rw-r--r--arch/arm/Makefile2
-rw-r--r--arch/arm/boot/compressed/head-xscale.S7
-rw-r--r--arch/arm/boot/dts/at91sam9260.dtsi273
-rw-r--r--arch/arm/boot/dts/at91sam9263.dtsi220
-rw-r--r--arch/arm/boot/dts/at91sam9263ek.dts156
-rw-r--r--arch/arm/boot/dts/at91sam9g20.dtsi222
-rw-r--r--arch/arm/boot/dts/at91sam9g20ek.dts29
-rw-r--r--arch/arm/boot/dts/at91sam9g20ek_2mmc.dts29
-rw-r--r--arch/arm/boot/dts/at91sam9g20ek_common.dtsi142
-rw-r--r--arch/arm/boot/dts/at91sam9g45.dtsi37
-rw-r--r--arch/arm/boot/dts/at91sam9n12.dtsi221
-rw-r--r--arch/arm/boot/dts/at91sam9n12ek.dts84
-rw-r--r--arch/arm/boot/dts/at91sam9x5.dtsi38
-rw-r--r--arch/arm/boot/dts/db8500.dtsi63
-rw-r--r--arch/arm/boot/dts/emev2-kzm9d.dts26
-rw-r--r--arch/arm/boot/dts/emev2.dtsi63
-rw-r--r--arch/arm/boot/dts/ethernut5.dts84
-rw-r--r--arch/arm/boot/dts/kirkwood-dns320.dts64
-rw-r--r--arch/arm/boot/dts/kirkwood-dns325.dts59
-rw-r--r--arch/arm/boot/dts/kirkwood-ib62x0.dts44
-rw-r--r--arch/arm/boot/dts/kirkwood-iconnect.dts26
-rw-r--r--arch/arm/boot/dts/kirkwood.dtsi15
-rw-r--r--arch/arm/boot/dts/kizbox.dts138
-rw-r--r--arch/arm/boot/dts/lpc32xx.dtsi292
-rw-r--r--arch/arm/boot/dts/mmp2-brownstone.dts38
-rw-r--r--arch/arm/boot/dts/mmp2.dtsi220
-rw-r--r--arch/arm/boot/dts/omap3-beagle.dts49
-rw-r--r--arch/arm/boot/dts/omap3.dtsi102
-rw-r--r--arch/arm/boot/dts/omap4-panda.dts71
-rw-r--r--arch/arm/boot/dts/omap4-sdp.dts140
-rw-r--r--arch/arm/boot/dts/omap4.dtsi117
-rw-r--r--arch/arm/boot/dts/phy3250.dts145
-rw-r--r--arch/arm/boot/dts/pxa168.dtsi67
-rw-r--r--arch/arm/boot/dts/pxa910-dkb.dts38
-rw-r--r--arch/arm/boot/dts/pxa910.dtsi140
-rw-r--r--arch/arm/boot/dts/r8a7740-armadillo800eva.dts22
-rw-r--r--arch/arm/boot/dts/sh7372.dtsi21
-rw-r--r--arch/arm/boot/dts/sh73a0-kzm9g.dts22
-rw-r--r--arch/arm/boot/dts/snowball.dts40
-rw-r--r--arch/arm/boot/dts/spear300-evb.dts221
-rw-r--r--arch/arm/boot/dts/spear300.dtsi77
-rw-r--r--arch/arm/boot/dts/spear310-evb.dts172
-rw-r--r--arch/arm/boot/dts/spear310.dtsi80
-rw-r--r--arch/arm/boot/dts/spear320-evb.dts173
-rw-r--r--arch/arm/boot/dts/spear320.dtsi95
-rw-r--r--arch/arm/boot/dts/spear3xx.dtsi144
-rw-r--r--arch/arm/boot/dts/spear600-evb.dts4
-rw-r--r--arch/arm/boot/dts/spear600.dtsi8
-rw-r--r--arch/arm/boot/dts/tegra-cardhu.dts44
-rw-r--r--arch/arm/boot/dts/tegra-harmony.dts224
-rw-r--r--arch/arm/boot/dts/tegra-paz00.dts220
-rw-r--r--arch/arm/boot/dts/tegra-seaboard.dts243
-rw-r--r--arch/arm/boot/dts/tegra-trimslice.dts230
-rw-r--r--arch/arm/boot/dts/tegra-ventana.dts230
-rw-r--r--arch/arm/boot/dts/tny_a9260.dts15
-rw-r--r--arch/arm/boot/dts/tny_a9260_common.dtsi83
-rw-r--r--arch/arm/boot/dts/tny_a9263.dts97
-rw-r--r--arch/arm/boot/dts/tny_a9g20.dts15
-rw-r--r--arch/arm/boot/dts/twl4030.dtsi47
-rw-r--r--arch/arm/boot/dts/twl6030.dtsi86
-rw-r--r--arch/arm/boot/dts/usb_a9260.dts23
-rw-r--r--arch/arm/boot/dts/usb_a9260_common.dtsi117
-rw-r--r--arch/arm/boot/dts/usb_a9263.dts131
-rw-r--r--arch/arm/boot/dts/usb_a9g20.dts102
-rw-r--r--arch/arm/common/Makefile2
-rw-r--r--arch/arm/common/uengine.c507
-rw-r--r--arch/arm/configs/armadillo800eva_defconfig142
-rw-r--r--arch/arm/configs/at91_dt_defconfig196
-rw-r--r--arch/arm/configs/at91rm9200_defconfig1
-rw-r--r--arch/arm/configs/bcmring_defconfig2
-rw-r--r--arch/arm/configs/imx_v4_v5_defconfig4
-rw-r--r--arch/arm/configs/ixp2000_defconfig99
-rw-r--r--arch/arm/configs/ixp23xx_defconfig105
-rw-r--r--arch/arm/configs/kzm9g_defconfig139
-rw-r--r--arch/arm/configs/lpc32xx_defconfig44
-rw-r--r--arch/arm/configs/nhk8815_defconfig1
-rw-r--r--arch/arm/configs/omap2plus_defconfig2
-rw-r--r--arch/arm/configs/spear3xx_defconfig52
-rw-r--r--arch/arm/configs/spear6xx_defconfig41
-rw-r--r--arch/arm/include/asm/hardware/cs89712.h49
-rw-r--r--arch/arm/include/asm/hardware/ep7212.h83
-rw-r--r--arch/arm/include/asm/hardware/uengine.h62
-rw-r--r--arch/arm/include/asm/processor.h3
-rw-r--r--arch/arm/kernel/perf_event_v6.c4
-rw-r--r--arch/arm/kernel/perf_event_v7.c4
-rw-r--r--arch/arm/kernel/perf_event_xscale.c8
-rw-r--r--arch/arm/kernel/signal.c11
-rw-r--r--arch/arm/kernel/sys_oabi-compat.c4
-rw-r--r--arch/arm/mach-at91/Kconfig194
-rw-r--r--arch/arm/mach-at91/Makefile27
-rw-r--r--arch/arm/mach-at91/Makefile.boot14
-rw-r--r--arch/arm/mach-at91/at91rm9200.c12
-rw-r--r--arch/arm/mach-at91/at91rm9200_devices.c12
-rw-r--r--arch/arm/mach-at91/at91sam9260.c20
-rw-r--r--arch/arm/mach-at91/at91sam9260_devices.c122
-rw-r--r--arch/arm/mach-at91/at91sam9261.c12
-rw-r--r--arch/arm/mach-at91/at91sam9261_devices.c12
-rw-r--r--arch/arm/mach-at91/at91sam9263.c22
-rw-r--r--arch/arm/mach-at91/at91sam9263_devices.c32
-rw-r--r--arch/arm/mach-at91/at91sam9g45.c21
-rw-r--r--arch/arm/mach-at91/at91sam9g45_devices.c143
-rw-r--r--arch/arm/mach-at91/at91sam9n12.c233
-rw-r--r--arch/arm/mach-at91/at91sam9rl.c12
-rw-r--r--arch/arm/mach-at91/at91sam9rl_devices.c12
-rw-r--r--arch/arm/mach-at91/at91sam9x5.c6
-rw-r--r--arch/arm/mach-at91/board-1arm.c24
-rw-r--r--arch/arm/mach-at91/board-afeb-9260v1.c28
-rw-r--r--arch/arm/mach-at91/board-cam60.c8
-rw-r--r--arch/arm/mach-at91/board-carmeva.c18
-rw-r--r--arch/arm/mach-at91/board-cpu9krea.c52
-rw-r--r--arch/arm/mach-at91/board-cpuat91.c40
-rw-r--r--arch/arm/mach-at91/board-csb337.c13
-rw-r--r--arch/arm/mach-at91/board-csb637.c8
-rw-r--r--arch/arm/mach-at91/board-dt.c8
-rw-r--r--arch/arm/mach-at91/board-eb9200.c24
-rw-r--r--arch/arm/mach-at91/board-ecbat91.c20
-rw-r--r--arch/arm/mach-at91/board-eco920.c13
-rw-r--r--arch/arm/mach-at91/board-flexibity.c8
-rw-r--r--arch/arm/mach-at91/board-foxg20.c71
-rw-r--r--arch/arm/mach-at91/board-gsia18s.c63
-rw-r--r--arch/arm/mach-at91/board-kafa.c20
-rw-r--r--arch/arm/mach-at91/board-kb9202.c32
-rw-r--r--arch/arm/mach-at91/board-neocore926.c14
-rw-r--r--arch/arm/mach-at91/board-pcontrol-g20.c21
-rw-r--r--arch/arm/mach-at91/board-picotux200.c18
-rw-r--r--arch/arm/mach-at91/board-qil-a9260.c31
-rw-r--r--arch/arm/mach-at91/board-rm9200dk.c24
-rw-r--r--arch/arm/mach-at91/board-rm9200ek.c24
-rw-r--r--arch/arm/mach-at91/board-rsi-ews.c36
-rw-r--r--arch/arm/mach-at91/board-sam9-l9260.c30
-rw-r--r--arch/arm/mach-at91/board-sam9260ek.c24
-rw-r--r--arch/arm/mach-at91/board-sam9261ek.c14
-rw-r--r--arch/arm/mach-at91/board-sam9263ek.c14
-rw-r--r--arch/arm/mach-at91/board-sam9g20ek.c38
-rw-r--r--arch/arm/mach-at91/board-sam9m10g45ek.c28
-rw-r--r--arch/arm/mach-at91/board-sam9rlek.c14
-rw-r--r--arch/arm/mach-at91/board-snapper9260.c18
-rw-r--r--arch/arm/mach-at91/board-stamp9g20.c64
-rw-r--r--arch/arm/mach-at91/board-usb-a926x.c12
-rw-r--r--arch/arm/mach-at91/board-yl-9200.c36
-rw-r--r--arch/arm/mach-at91/clock.c15
-rw-r--r--arch/arm/mach-at91/cpuidle.c8
-rw-r--r--arch/arm/mach-at91/generic.h11
-rw-r--r--arch/arm/mach-at91/include/mach/at91rm9200.h5
-rw-r--r--arch/arm/mach-at91/include/mach/at91sam9260.h7
-rw-r--r--arch/arm/mach-at91/include/mach/at91sam9261.h4
-rw-r--r--arch/arm/mach-at91/include/mach/at91sam9263.h4
-rw-r--r--arch/arm/mach-at91/include/mach/at91sam9g45.h5
-rw-r--r--arch/arm/mach-at91/include/mach/at91sam9n12.h60
-rw-r--r--arch/arm/mach-at91/include/mach/at91sam9n12_matrix.h53
-rw-r--r--arch/arm/mach-at91/include/mach/at91sam9rl.h5
-rw-r--r--arch/arm/mach-at91/include/mach/at91sam9x5.h8
-rw-r--r--arch/arm/mach-at91/include/mach/board.h1
-rw-r--r--arch/arm/mach-at91/include/mach/cpu.h38
-rw-r--r--arch/arm/mach-at91/include/mach/hardware.h17
-rw-r--r--arch/arm/mach-at91/include/mach/uncompress.h178
-rw-r--r--arch/arm/mach-at91/pm.c12
-rw-r--r--arch/arm/mach-at91/pm.h15
-rw-r--r--arch/arm/mach-at91/pm_slowclock.S2
-rw-r--r--arch/arm/mach-at91/setup.c6
-rw-r--r--arch/arm/mach-at91/soc.h19
-rw-r--r--arch/arm/mach-clps711x/Kconfig21
-rw-r--r--arch/arm/mach-clps711x/common.c17
-rw-r--r--arch/arm/mach-clps711x/include/mach/clps711x.h (renamed from arch/arm/include/asm/hardware/clps7111.h)130
-rw-r--r--arch/arm/mach-clps711x/include/mach/debug-macro.S5
-rw-r--r--arch/arm/mach-clps711x/include/mach/entry-macro.S3
-rw-r--r--arch/arm/mach-clps711x/include/mach/hardware.h59
-rw-r--r--arch/arm/mach-clps711x/include/mach/irqs.h5
-rw-r--r--arch/arm/mach-clps711x/include/mach/time.h49
-rw-r--r--arch/arm/mach-clps711x/include/mach/uncompress.h21
-rw-r--r--arch/arm/mach-clps711x/p720t-leds.c3
-rw-r--r--arch/arm/mach-davinci/board-da850-evm.c2
-rw-r--r--arch/arm/mach-davinci/davinci.h4
-rw-r--r--arch/arm/mach-davinci/devices-da8xx.c2
-rw-r--r--arch/arm/mach-davinci/dm355.c2
-rw-r--r--arch/arm/mach-davinci/dm365.c2
-rw-r--r--arch/arm/mach-davinci/dma.c6
-rw-r--r--arch/arm/mach-davinci/include/mach/da8xx.h3
-rw-r--r--arch/arm/mach-davinci/include/mach/psc.h2
-rw-r--r--arch/arm/mach-dove/common.c2
-rw-r--r--arch/arm/mach-dove/mpp.c8
-rw-r--r--arch/arm/mach-ep93xx/Kconfig5
-rw-r--r--arch/arm/mach-ep93xx/core.c110
-rw-r--r--arch/arm/mach-exynos/Kconfig12
-rw-r--r--arch/arm/mach-exynos/cpuidle.c53
-rw-r--r--arch/arm/mach-exynos/dev-ahci.c12
-rw-r--r--arch/arm/mach-exynos/dev-audio.c156
-rw-r--r--arch/arm/mach-exynos/include/mach/irqs.h1
-rw-r--r--arch/arm/mach-exynos/include/mach/map.h4
-rw-r--r--arch/arm/mach-exynos/include/mach/regs-pmu.h3
-rw-r--r--arch/arm/mach-exynos/mach-armlex4210.c16
-rw-r--r--arch/arm/mach-exynos/mach-nuri.c46
-rw-r--r--arch/arm/mach-exynos/mach-origen.c37
-rw-r--r--arch/arm/mach-exynos/mach-smdk4x12.c18
-rw-r--r--arch/arm/mach-exynos/mach-smdkv310.c47
-rw-r--r--arch/arm/mach-exynos/mach-universal_c210.c46
-rw-r--r--arch/arm/mach-exynos/setup-usb-phy.c100
-rw-r--r--arch/arm/mach-imx/Kconfig41
-rw-r--r--arch/arm/mach-imx/Makefile4
-rw-r--r--arch/arm/mach-imx/eukrea_mbimx27-baseboard.c2
-rw-r--r--arch/arm/mach-imx/eukrea_mbimx51-baseboard.c206
-rw-r--r--arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c51
-rw-r--r--arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c42
-rw-r--r--arch/arm/mach-imx/eukrea_mbimxsd51-baseboard.c (renamed from arch/arm/mach-imx/eukrea_mbimxsd-baseboard.c)120
-rw-r--r--arch/arm/mach-imx/imx51-dt.c3
-rw-r--r--arch/arm/mach-imx/imx53-dt.c3
-rw-r--r--arch/arm/mach-imx/mach-cpuimx35.c2
-rw-r--r--arch/arm/mach-imx/mach-cpuimx51.c301
-rw-r--r--arch/arm/mach-imx/mach-cpuimx51sd.c50
-rw-r--r--arch/arm/mach-imx/mach-eukrea_cpuimx25.c2
-rw-r--r--arch/arm/mach-imx/mach-imx27_visstrim_m10.c57
-rw-r--r--arch/arm/mach-imx/mach-imx6q.c7
-rw-r--r--arch/arm/mach-imx/mach-mx1ads.c2
-rw-r--r--arch/arm/mach-imx/mach-mx21ads.c3
-rw-r--r--arch/arm/mach-imx/mach-mx31_3ds.c22
-rw-r--r--arch/arm/mach-imx/mach-mx31lite.c2
-rw-r--r--arch/arm/mach-imx/mach-mx31moboard.c22
-rw-r--r--arch/arm/mach-imx/mach-mx35_3ds.c198
-rw-r--r--arch/arm/mach-imx/mach-mx51_efikamx.c3
-rw-r--r--arch/arm/mach-imx/mach-mx51_efikasb.c2
-rw-r--r--arch/arm/mach-imx/mach-pcm037.c2
-rw-r--r--arch/arm/mach-imx/mach-pcm043.c2
-rw-r--r--arch/arm/mach-imx/mach-vpr200.c2
-rw-r--r--arch/arm/mach-imx/mm-imx1.c2
-rw-r--r--arch/arm/mach-imx/mm-imx21.c2
-rw-r--r--arch/arm/mach-imx/mm-imx25.c2
-rw-r--r--arch/arm/mach-imx/mm-imx27.c2
-rw-r--r--arch/arm/mach-imx/mm-imx3.c2
-rw-r--r--arch/arm/mach-imx/mm-imx5.c2
-rw-r--r--arch/arm/mach-ixp2000/Kconfig72
-rw-r--r--arch/arm/mach-ixp2000/Makefile14
-rw-r--r--arch/arm/mach-ixp2000/Makefile.boot3
-rw-r--r--arch/arm/mach-ixp2000/core.c520
-rw-r--r--arch/arm/mach-ixp2000/enp2611.c258
-rw-r--r--arch/arm/mach-ixp2000/include/mach/debug-macro.S25
-rw-r--r--arch/arm/mach-ixp2000/include/mach/enp2611.h46
-rw-r--r--arch/arm/mach-ixp2000/include/mach/entry-macro.S54
-rw-r--r--arch/arm/mach-ixp2000/include/mach/gpio-ixp2000.h48
-rw-r--r--arch/arm/mach-ixp2000/include/mach/hardware.h36
-rw-r--r--arch/arm/mach-ixp2000/include/mach/io.h133
-rw-r--r--arch/arm/mach-ixp2000/include/mach/irqs.h207
-rw-r--r--arch/arm/mach-ixp2000/include/mach/ixdp2x00.h92
-rw-r--r--arch/arm/mach-ixp2000/include/mach/ixdp2x01.h57
-rw-r--r--arch/arm/mach-ixp2000/include/mach/ixp2000-regs.h451
-rw-r--r--arch/arm/mach-ixp2000/include/mach/memory.h31
-rw-r--r--arch/arm/mach-ixp2000/include/mach/platform.h153
-rw-r--r--arch/arm/mach-ixp2000/include/mach/timex.h13
-rw-r--r--arch/arm/mach-ixp2000/include/mach/uncompress.h47
-rw-r--r--arch/arm/mach-ixp2000/ixdp2400.c180
-rw-r--r--arch/arm/mach-ixp2000/ixdp2800.c295
-rw-r--r--arch/arm/mach-ixp2000/ixdp2x00.c306
-rw-r--r--arch/arm/mach-ixp2000/ixdp2x01.c483
-rw-r--r--arch/arm/mach-ixp2000/pci.c246
-rw-r--r--arch/arm/mach-ixp23xx/Kconfig25
-rw-r--r--arch/arm/mach-ixp23xx/Makefile11
-rw-r--r--arch/arm/mach-ixp23xx/Makefile.boot2
-rw-r--r--arch/arm/mach-ixp23xx/core.c455
-rw-r--r--arch/arm/mach-ixp23xx/espresso.c93
-rw-r--r--arch/arm/mach-ixp23xx/include/mach/debug-macro.S25
-rw-r--r--arch/arm/mach-ixp23xx/include/mach/entry-macro.S31
-rw-r--r--arch/arm/mach-ixp23xx/include/mach/hardware.h32
-rw-r--r--arch/arm/mach-ixp23xx/include/mach/io.h22
-rw-r--r--arch/arm/mach-ixp23xx/include/mach/irqs.h223
-rw-r--r--arch/arm/mach-ixp23xx/include/mach/ixdp2351.h89
-rw-r--r--arch/arm/mach-ixp23xx/include/mach/ixp23xx.h298
-rw-r--r--arch/arm/mach-ixp23xx/include/mach/memory.h34
-rw-r--r--arch/arm/mach-ixp23xx/include/mach/platform.h58
-rw-r--r--arch/arm/mach-ixp23xx/include/mach/time.h3
-rw-r--r--arch/arm/mach-ixp23xx/include/mach/timex.h7
-rw-r--r--arch/arm/mach-ixp23xx/include/mach/uncompress.h40
-rw-r--r--arch/arm/mach-ixp23xx/ixdp2351.c347
-rw-r--r--arch/arm/mach-ixp23xx/pci.c288
-rw-r--r--arch/arm/mach-ixp23xx/roadrunner.c180
-rw-r--r--arch/arm/mach-kirkwood/Kconfig22
-rw-r--r--arch/arm/mach-kirkwood/Makefile3
-rw-r--r--arch/arm/mach-kirkwood/Makefile.boot4
-rw-r--r--arch/arm/mach-kirkwood/board-dnskw.c275
-rw-r--r--arch/arm/mach-kirkwood/board-dt.c13
-rw-r--r--arch/arm/mach-kirkwood/board-ib62x0.c143
-rw-r--r--arch/arm/mach-kirkwood/board-iconnect.c165
-rw-r--r--arch/arm/mach-kirkwood/common.c12
-rw-r--r--arch/arm/mach-kirkwood/common.h18
-rw-r--r--arch/arm/mach-lpc32xx/Kconfig26
-rw-r--r--arch/arm/mach-lpc32xx/clock.c77
-rw-r--r--arch/arm/mach-lpc32xx/common.c188
-rw-r--r--arch/arm/mach-lpc32xx/common.h14
-rw-r--r--arch/arm/mach-lpc32xx/include/mach/gpio.h9
-rw-r--r--arch/arm/mach-lpc32xx/include/mach/i2c.h63
-rw-r--r--arch/arm/mach-lpc32xx/irq.c78
-rw-r--r--arch/arm/mach-lpc32xx/phy3250.c149
-rw-r--r--arch/arm/mach-mmp/Kconfig36
-rw-r--r--arch/arm/mach-mmp/Makefile14
-rw-r--r--arch/arm/mach-mmp/aspenite.c20
-rw-r--r--arch/arm/mach-mmp/devices.c282
-rw-r--r--arch/arm/mach-mmp/include/mach/addr-map.h12
-rw-r--r--arch/arm/mach-mmp/include/mach/devices.h3
-rw-r--r--arch/arm/mach-mmp/include/mach/entry-macro.S4
-rw-r--r--arch/arm/mach-mmp/include/mach/irqs.h27
-rw-r--r--arch/arm/mach-mmp/include/mach/pm-mmp2.h61
-rw-r--r--arch/arm/mach-mmp/include/mach/pm-pxa910.h77
-rw-r--r--arch/arm/mach-mmp/include/mach/pxa168.h8
-rw-r--r--arch/arm/mach-mmp/include/mach/pxa910.h3
-rw-r--r--arch/arm/mach-mmp/include/mach/regs-apbc.h3
-rw-r--r--arch/arm/mach-mmp/include/mach/regs-apmu.h3
-rw-r--r--arch/arm/mach-mmp/include/mach/regs-usb.h253
-rw-r--r--arch/arm/mach-mmp/irq-mmp2.c158
-rw-r--r--arch/arm/mach-mmp/irq-pxa168.c54
-rw-r--r--arch/arm/mach-mmp/irq.c458
-rw-r--r--arch/arm/mach-mmp/mmp-dt.c66
-rw-r--r--arch/arm/mach-mmp/mmp2-dt.c60
-rw-r--r--arch/arm/mach-mmp/pm-mmp2.c264
-rw-r--r--arch/arm/mach-mmp/pm-pxa910.c285
-rw-r--r--arch/arm/mach-mmp/pxa168.c20
-rw-r--r--arch/arm/mach-mmp/pxa910.c2
-rw-r--r--arch/arm/mach-mmp/time.c81
-rw-r--r--arch/arm/mach-mmp/ttc_dkb.c48
-rw-r--r--arch/arm/mach-msm/board-msm7x30.c1
-rw-r--r--arch/arm/mach-msm/board-qsd8x50.c1
-rw-r--r--arch/arm/mach-msm/include/mach/debug-macro.S3
-rw-r--r--arch/arm/mach-msm/scm.c3
-rw-r--r--arch/arm/mach-mxs/Kconfig2
-rw-r--r--arch/arm/mach-mxs/include/mach/common.h2
-rw-r--r--arch/arm/mach-mxs/mach-apx4devkit.c2
-rw-r--r--arch/arm/mach-mxs/mach-m28evk.c2
-rw-r--r--arch/arm/mach-mxs/mach-mx23evk.c2
-rw-r--r--arch/arm/mach-mxs/mach-mx28evk.c2
-rw-r--r--arch/arm/mach-mxs/mach-stmp378x_devb.c2
-rw-r--r--arch/arm/mach-mxs/mach-tx28.c2
-rw-r--r--arch/arm/mach-mxs/mm.c11
-rw-r--r--arch/arm/mach-nomadik/Kconfig1
-rw-r--r--arch/arm/mach-omap1/Kconfig1
-rw-r--r--arch/arm/mach-omap1/Makefile13
-rw-r--r--arch/arm/mach-omap1/ams-delta-fiq.c2
-rw-r--r--arch/arm/mach-omap1/board-fsample.c16
-rw-r--r--arch/arm/mach-omap1/board-h2.c17
-rw-r--r--arch/arm/mach-omap1/board-h3.c16
-rw-r--r--arch/arm/mach-omap1/board-nand.c37
-rw-r--r--arch/arm/mach-omap1/board-palmz71.c4
-rw-r--r--arch/arm/mach-omap1/board-perseus2.c16
-rw-r--r--arch/arm/mach-omap1/clock.c3
-rw-r--r--arch/arm/mach-omap1/common.h15
-rw-r--r--arch/arm/mach-omap1/fpga.c2
-rw-r--r--arch/arm/mach-omap1/gpio15xx.c2
-rw-r--r--arch/arm/mach-omap1/gpio16xx.c5
-rw-r--r--arch/arm/mach-omap1/gpio7xx.c7
-rw-r--r--arch/arm/mach-omap1/id.c2
-rw-r--r--arch/arm/mach-omap1/io.c3
-rw-r--r--arch/arm/mach-omap1/irq.c2
-rw-r--r--arch/arm/mach-omap1/lcd_dma.c7
-rw-r--r--arch/arm/mach-omap1/ocpi.c (renamed from arch/arm/plat-omap/ocpi.c)7
-rw-r--r--arch/arm/mach-omap1/pm.c9
-rw-r--r--arch/arm/mach-omap1/reset.c2
-rw-r--r--arch/arm/mach-omap1/timer.c3
-rw-r--r--arch/arm/mach-omap1/usb.c3
-rw-r--r--arch/arm/mach-omap2/Kconfig1
-rw-r--r--arch/arm/mach-omap2/Makefile13
-rw-r--r--arch/arm/mach-omap2/am35xx-emac.c37
-rw-r--r--arch/arm/mach-omap2/board-3430sdp.c38
-rw-r--r--arch/arm/mach-omap2/board-4430sdp.c91
-rw-r--r--arch/arm/mach-omap2/board-am3517crane.c2
-rw-r--r--arch/arm/mach-omap2/board-am3517evm.c25
-rw-r--r--arch/arm/mach-omap2/board-cm-t35.c35
-rw-r--r--arch/arm/mach-omap2/board-devkit8000.c30
-rw-r--r--arch/arm/mach-omap2/board-flash.c4
-rw-r--r--arch/arm/mach-omap2/board-flash.h11
-rw-r--r--arch/arm/mach-omap2/board-generic.c37
-rw-r--r--arch/arm/mach-omap2/board-igep0020.c116
-rw-r--r--arch/arm/mach-omap2/board-omap3beagle.c44
-rw-r--r--arch/arm/mach-omap2/board-omap3evm.c37
-rw-r--r--arch/arm/mach-omap2/board-omap3logic.c26
-rw-r--r--arch/arm/mach-omap2/board-omap3stalker.c29
-rw-r--r--arch/arm/mach-omap2/board-omap4panda.c119
-rw-r--r--arch/arm/mach-omap2/board-overo.c25
-rw-r--r--arch/arm/mach-omap2/board-rx51-peripherals.c92
-rw-r--r--arch/arm/mach-omap2/board-rx51.c38
-rw-r--r--arch/arm/mach-omap2/board-zoom-display.c1
-rw-r--r--arch/arm/mach-omap2/clock.c2
-rw-r--r--arch/arm/mach-omap2/clock3xxx_data.c25
-rw-r--r--arch/arm/mach-omap2/clock44xx_data.c11
-rw-r--r--arch/arm/mach-omap2/clockdomain.c7
-rw-r--r--arch/arm/mach-omap2/clockdomain44xx.c6
-rw-r--r--arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c10
-rw-r--r--arch/arm/mach-omap2/clockdomains3xxx_data.c6
-rw-r--r--arch/arm/mach-omap2/clockdomains44xx_data.c2
-rw-r--r--arch/arm/mach-omap2/clockdomains_common_data.c24
-rw-r--r--arch/arm/mach-omap2/cm-regbits-34xx.h4
-rw-r--r--arch/arm/mach-omap2/cminst44xx.c28
-rw-r--r--arch/arm/mach-omap2/common.c1
-rw-r--r--arch/arm/mach-omap2/common.h6
-rw-r--r--arch/arm/mach-omap2/cpuidle34xx.c298
-rw-r--r--arch/arm/mach-omap2/cpuidle44xx.c126
-rw-r--r--arch/arm/mach-omap2/devices.c47
-rw-r--r--arch/arm/mach-omap2/dpll3xxx.c23
-rw-r--r--arch/arm/mach-omap2/dsp.c5
-rw-r--r--arch/arm/mach-omap2/gpio.c13
-rw-r--r--arch/arm/mach-omap2/gpmc-onenand.c3
-rw-r--r--arch/arm/mach-omap2/gpmc.c3
-rw-r--r--arch/arm/mach-omap2/hdq1w.c72
-rw-r--r--arch/arm/mach-omap2/hwspinlock.c2
-rw-r--r--arch/arm/mach-omap2/id.c5
-rw-r--r--arch/arm/mach-omap2/io.c19
-rw-r--r--arch/arm/mach-omap2/irq.c6
-rw-r--r--arch/arm/mach-omap2/mailbox.c6
-rw-r--r--arch/arm/mach-omap2/msdi.c88
-rw-r--r--arch/arm/mach-omap2/mux.c2
-rw-r--r--arch/arm/mach-omap2/omap-secure.c1
-rw-r--r--arch/arm/mach-omap2/omap-wakeupgen.c2
-rw-r--r--arch/arm/mach-omap2/omap4-common.c58
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c1143
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_2420_data.c1580
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_2430_data.c1968
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_interconnect_data.c9
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c22
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_2xxx_interconnect_data.c266
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c585
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_3xxx_data.c3087
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_44xx_data.c6323
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_common_data.h76
-rw-r--r--arch/arm/mach-omap2/pm.h21
-rw-r--r--arch/arm/mach-omap2/pm24xx.c3
-rw-r--r--arch/arm/mach-omap2/pm34xx.c10
-rw-r--r--arch/arm/mach-omap2/powerdomain.c10
-rw-r--r--arch/arm/mach-omap2/powerdomain.h1
-rw-r--r--arch/arm/mach-omap2/prcm-common.h17
-rw-r--r--arch/arm/mach-omap2/prcm.c8
-rw-r--r--arch/arm/mach-omap2/prm_common.c4
-rw-r--r--arch/arm/mach-omap2/prminst44xx.c27
-rw-r--r--arch/arm/mach-omap2/serial.c10
-rw-r--r--arch/arm/mach-omap2/timer.c22
-rw-r--r--arch/arm/mach-omap2/twl-common.c190
-rw-r--r--arch/arm/mach-omap2/twl-common.h2
-rw-r--r--arch/arm/mach-omap2/usb-tusb6010.c2
-rw-r--r--arch/arm/mach-omap2/vc3xxx_data.c1
-rw-r--r--arch/arm/mach-omap2/voltage.c21
-rw-r--r--arch/arm/mach-omap2/wd_timer.c45
-rw-r--r--arch/arm/mach-omap2/wd_timer.h1
-rw-r--r--arch/arm/mach-orion5x/Kconfig1
-rw-r--r--arch/arm/mach-orion5x/addr-map.c2
-rw-r--r--arch/arm/mach-orion5x/common.c2
-rw-r--r--arch/arm/mach-orion5x/common.h1
-rw-r--r--arch/arm/mach-orion5x/dns323-setup.c25
-rw-r--r--arch/arm/mach-orion5x/ts78xx-fpga.h6
-rw-r--r--arch/arm/mach-orion5x/ts78xx-setup.c52
-rw-r--r--arch/arm/mach-pnx4008/i2c.c64
-rw-r--r--arch/arm/mach-pnx4008/include/mach/i2c.h64
-rw-r--r--arch/arm/mach-pxa/balloon3.c4
-rw-r--r--arch/arm/mach-pxa/cm-x300.c4
-rw-r--r--arch/arm/mach-pxa/em-x270.c5
-rw-r--r--arch/arm/mach-pxa/hx4700.c47
-rw-r--r--arch/arm/mach-pxa/include/mach/mfp-pxa27x.h1
-rw-r--r--arch/arm/mach-pxa/include/mach/mioa701.h3
-rw-r--r--arch/arm/mach-pxa/include/mach/pcm990_baseboard.h68
-rw-r--r--arch/arm/mach-pxa/magician.c8
-rw-r--r--arch/arm/mach-pxa/mioa701.c6
-rw-r--r--arch/arm/mach-pxa/palm27x.c4
-rw-r--r--arch/arm/mach-pxa/pcm990-baseboard.c83
-rw-r--r--arch/arm/mach-pxa/spitz.c4
-rw-r--r--arch/arm/mach-pxa/stargate2.c5
-rw-r--r--arch/arm/mach-pxa/vpac270.c4
-rw-r--r--arch/arm/mach-pxa/z2.c4
-rw-r--r--arch/arm/mach-s3c24xx/bast-ide.c36
-rw-r--r--arch/arm/mach-s3c24xx/mach-amlm5900.c9
-rw-r--r--arch/arm/mach-s3c24xx/mach-anubis.c62
-rw-r--r--arch/arm/mach-s3c24xx/mach-at2440evb.c19
-rw-r--r--arch/arm/mach-s3c24xx/mach-bast.c45
-rw-r--r--arch/arm/mach-s3c24xx/mach-gta02.c7
-rw-r--r--arch/arm/mach-s3c24xx/mach-h1940.c9
-rw-r--r--arch/arm/mach-s3c24xx/mach-mini2440.c19
-rw-r--r--arch/arm/mach-s3c24xx/mach-nexcoder.c6
-rw-r--r--arch/arm/mach-s3c24xx/mach-osiris.c12
-rw-r--r--arch/arm/mach-s3c24xx/mach-otom.c6
-rw-r--r--arch/arm/mach-s3c24xx/mach-qt2410.c12
-rw-r--r--arch/arm/mach-s3c24xx/mach-rx1950.c9
-rw-r--r--arch/arm/mach-s3c24xx/mach-tct_hammer.c7
-rw-r--r--arch/arm/mach-s3c24xx/mach-vr1000.c39
-rw-r--r--arch/arm/mach-s3c24xx/simtec-nor.c6
-rw-r--r--arch/arm/mach-s3c64xx/Kconfig4
-rw-r--r--arch/arm/mach-s3c64xx/dev-audio.c120
-rw-r--r--arch/arm/mach-s3c64xx/dev-uart.c48
-rw-r--r--arch/arm/mach-s3c64xx/mach-anw6410.c19
-rw-r--r--arch/arm/mach-s3c64xx/mach-crag6410.c46
-rw-r--r--arch/arm/mach-s3c64xx/mach-mini6410.c19
-rw-r--r--arch/arm/mach-s3c64xx/mach-real6410.c19
-rw-r--r--arch/arm/mach-s3c64xx/mach-smartq.c2
-rw-r--r--arch/arm/mach-s3c64xx/mach-smdk6410.c15
-rw-r--r--arch/arm/mach-s5p64x0/dev-audio.c72
-rw-r--r--arch/arm/mach-s5pc100/dev-audio.c138
-rw-r--r--arch/arm/mach-s5pv210/Kconfig1
-rw-r--r--arch/arm/mach-s5pv210/dev-audio.c156
-rw-r--r--arch/arm/mach-s5pv210/mach-goni.c6
-rw-r--r--arch/arm/mach-s5pv210/mach-smdkv210.c19
-rw-r--r--arch/arm/mach-shmobile/Kconfig31
-rw-r--r--arch/arm/mach-shmobile/Makefile5
-rw-r--r--arch/arm/mach-shmobile/board-ap4evb.c37
-rw-r--r--arch/arm/mach-shmobile/board-armadillo800eva.c784
-rw-r--r--arch/arm/mach-shmobile/board-bonito.c2
-rw-r--r--arch/arm/mach-shmobile/board-kzm9d.c85
-rw-r--r--arch/arm/mach-shmobile/board-kzm9g.c460
-rw-r--r--arch/arm/mach-shmobile/board-mackerel.c45
-rw-r--r--arch/arm/mach-shmobile/clock-emev2.c249
-rw-r--r--arch/arm/mach-shmobile/clock-r8a7740.c128
-rw-r--r--arch/arm/mach-shmobile/include/mach/common.h2
-rw-r--r--arch/arm/mach-shmobile/include/mach/emev2.h19
-rw-r--r--arch/arm/mach-shmobile/include/mach/intc.h44
-rw-r--r--arch/arm/mach-shmobile/include/mach/irqs.h2
-rw-r--r--arch/arm/mach-shmobile/include/mach/sh7372.h2
-rw-r--r--arch/arm/mach-shmobile/include/mach/sh73a0.h37
-rw-r--r--arch/arm/mach-shmobile/intc-sh7372.c34
-rw-r--r--arch/arm/mach-shmobile/pfc-r8a7740.c39
-rw-r--r--arch/arm/mach-shmobile/pfc-sh73a0.c4
-rw-r--r--arch/arm/mach-shmobile/platsmp.c21
-rw-r--r--arch/arm/mach-shmobile/setup-emev2.c452
-rw-r--r--arch/arm/mach-shmobile/setup-r8a7740.c19
-rw-r--r--arch/arm/mach-shmobile/setup-sh7372.c58
-rw-r--r--arch/arm/mach-shmobile/smp-emev2.c97
-rw-r--r--arch/arm/mach-shmobile/timer.c18
-rw-r--r--arch/arm/mach-spear3xx/Kconfig37
-rw-r--r--arch/arm/mach-spear3xx/Makefile13
-rw-r--r--arch/arm/mach-spear3xx/Makefile.boot4
-rw-r--r--arch/arm/mach-spear3xx/clock.c280
-rw-r--r--arch/arm/mach-spear3xx/include/mach/generic.h164
-rw-r--r--arch/arm/mach-spear3xx/include/mach/hardware.h24
-rw-r--r--arch/arm/mach-spear3xx/include/mach/irqs.h130
-rw-r--r--arch/arm/mach-spear3xx/include/mach/misc_regs.h144
-rw-r--r--arch/arm/mach-spear3xx/include/mach/spear.h47
-rw-r--r--arch/arm/mach-spear3xx/include/mach/spear300.h54
-rw-r--r--arch/arm/mach-spear3xx/include/mach/spear310.h58
-rw-r--r--arch/arm/mach-spear3xx/include/mach/spear320.h67
-rw-r--r--arch/arm/mach-spear3xx/spear300.c654
-rw-r--r--arch/arm/mach-spear3xx/spear300_evb.c75
-rw-r--r--arch/arm/mach-spear3xx/spear310.c476
-rw-r--r--arch/arm/mach-spear3xx/spear310_evb.c81
-rw-r--r--arch/arm/mach-spear3xx/spear320.c725
-rw-r--r--arch/arm/mach-spear3xx/spear320_evb.c79
-rw-r--r--arch/arm/mach-spear3xx/spear3xx.c547
-rw-r--r--arch/arm/mach-spear6xx/Kconfig18
-rw-r--r--arch/arm/mach-spear6xx/Makefile.boot2
-rw-r--r--arch/arm/mach-spear6xx/clock.c186
-rw-r--r--arch/arm/mach-spear6xx/include/mach/generic.h29
-rw-r--r--arch/arm/mach-spear6xx/include/mach/hardware.h24
-rw-r--r--arch/arm/mach-spear6xx/include/mach/irqs.h75
-rw-r--r--arch/arm/mach-spear6xx/include/mach/misc_regs.h154
-rw-r--r--arch/arm/mach-spear6xx/include/mach/spear.h55
-rw-r--r--arch/arm/mach-spear6xx/include/mach/spear600.h21
-rw-r--r--arch/arm/mach-spear6xx/spear6xx.c417
-rw-r--r--arch/arm/mach-tegra/Makefile3
-rw-r--r--arch/arm/mach-tegra/board-dt-tegra20.c38
-rw-r--r--arch/arm/mach-tegra/board-harmony-pinmux.c266
-rw-r--r--arch/arm/mach-tegra/board-harmony.c3
-rw-r--r--arch/arm/mach-tegra/board-paz00-pinmux.c263
-rw-r--r--arch/arm/mach-tegra/board-paz00.c3
-rw-r--r--arch/arm/mach-tegra/board-pinmux.c105
-rw-r--r--arch/arm/mach-tegra/board-pinmux.h40
-rw-r--r--arch/arm/mach-tegra/board-seaboard-pinmux.c346
-rw-r--r--arch/arm/mach-tegra/board-seaboard.c24
-rw-r--r--arch/arm/mach-tegra/board-trimslice-pinmux.c264
-rw-r--r--arch/arm/mach-tegra/board-trimslice.c18
-rw-r--r--arch/arm/mach-tegra/devices.c16
-rw-r--r--arch/arm/mach-tegra/devices.h1
-rw-r--r--arch/arm/mach-tegra/include/mach/dma.h4
-rw-r--r--arch/arm/mach-tegra/include/mach/gpio-tegra.h9
-rw-r--r--arch/arm/mach-tegra/include/mach/pinmux-tegra20.h184
-rw-r--r--arch/arm/mach-tegra/include/mach/pinmux-tegra30.h320
-rw-r--r--arch/arm/mach-tegra/include/mach/pinmux.h302
-rw-r--r--arch/arm/mach-tegra/pinmux-tegra20-tables.c244
-rw-r--r--arch/arm/mach-tegra/pinmux-tegra30-tables.c376
-rw-r--r--arch/arm/mach-tegra/pinmux.c987
-rw-r--r--arch/arm/mach-tegra/tegra2_clocks.c10
-rw-r--r--arch/arm/mach-tegra/usb_phy.c1
-rw-r--r--arch/arm/mach-ux500/Kconfig28
-rw-r--r--arch/arm/mach-ux500/Makefile9
-rw-r--r--arch/arm/mach-ux500/board-mop500-msp.c267
-rw-r--r--arch/arm/mach-ux500/board-mop500-msp.h14
-rw-r--r--arch/arm/mach-ux500/board-mop500-pins.c733
-rw-r--r--arch/arm/mach-ux500/board-mop500-uib.c2
-rw-r--r--arch/arm/mach-ux500/board-mop500.c178
-rw-r--r--arch/arm/mach-ux500/board-mop500.h10
-rw-r--r--arch/arm/mach-ux500/board-u5500-sdi.c74
-rw-r--r--arch/arm/mach-ux500/board-u5500.c162
-rw-r--r--arch/arm/mach-ux500/cache-l2x0.c18
-rw-r--r--arch/arm/mach-ux500/clock.c38
-rw-r--r--arch/arm/mach-ux500/cpu-db5500.c247
-rw-r--r--arch/arm/mach-ux500/cpu-db8500.c43
-rw-r--r--arch/arm/mach-ux500/cpu.c22
-rw-r--r--arch/arm/mach-ux500/cpuidle.c171
-rw-r--r--arch/arm/mach-ux500/devices-common.h62
-rw-r--r--arch/arm/mach-ux500/devices-db5500.h99
-rw-r--r--arch/arm/mach-ux500/devices-db8500.c3
-rw-r--r--arch/arm/mach-ux500/devices-db8500.h14
-rw-r--r--arch/arm/mach-ux500/dma-db5500.c137
-rw-r--r--arch/arm/mach-ux500/id.c9
-rw-r--r--arch/arm/mach-ux500/include/mach/crypto-ux500.h22
-rw-r--r--arch/arm/mach-ux500/include/mach/db5500-regs.h143
-rw-r--r--arch/arm/mach-ux500/include/mach/db8500-regs.h6
-rw-r--r--arch/arm/mach-ux500/include/mach/debug-macro.S4
-rw-r--r--arch/arm/mach-ux500/include/mach/devices.h4
-rw-r--r--arch/arm/mach-ux500/include/mach/hardware.h7
-rw-r--r--arch/arm/mach-ux500/include/mach/id.h17
-rw-r--r--arch/arm/mach-ux500/include/mach/irqs-board-u5500.h21
-rw-r--r--arch/arm/mach-ux500/include/mach/irqs-db5500.h113
-rw-r--r--arch/arm/mach-ux500/include/mach/irqs.h7
-rw-r--r--arch/arm/mach-ux500/include/mach/mbox-db5500.h88
-rw-r--r--arch/arm/mach-ux500/include/mach/msp.h29
-rw-r--r--arch/arm/mach-ux500/include/mach/setup.h6
-rw-r--r--arch/arm/mach-ux500/include/mach/uncompress.h7
-rw-r--r--arch/arm/mach-ux500/mbox-db5500.c565
-rw-r--r--arch/arm/mach-ux500/modem-irq-db5500.c143
-rw-r--r--arch/arm/mach-ux500/pins-db5500.h620
-rw-r--r--arch/arm/mach-ux500/pins-db8500.h72
-rw-r--r--arch/arm/mach-ux500/platsmp.c8
-rw-r--r--arch/arm/mach-ux500/ste-dma40-db5500.h135
-rw-r--r--arch/arm/mach-ux500/timer.c37
-rw-r--r--arch/arm/mm/cache-tauros2.c24
-rw-r--r--arch/arm/mm/proc-mohawk.S35
-rw-r--r--arch/arm/nwfpe/fpmodule.c2
-rw-r--r--arch/arm/plat-mxc/include/mach/iomux-mx51.h48
-rw-r--r--arch/arm/plat-mxc/include/mach/iomux-mx53.h4
-rw-r--r--arch/arm/plat-mxc/include/mach/mx2_cam.h2
-rw-r--r--arch/arm/plat-nomadik/include/plat/gpio-nomadik.h8
-rw-r--r--arch/arm/plat-nomadik/include/plat/pincfg.h32
-rw-r--r--arch/arm/plat-omap/Makefile3
-rw-r--r--arch/arm/plat-omap/common.c1
-rw-r--r--arch/arm/plat-omap/devices.c4
-rw-r--r--arch/arm/plat-omap/dma.c13
-rw-r--r--arch/arm/plat-omap/dmtimer.c3
-rw-r--r--arch/arm/plat-omap/include/plat/board.h2
-rw-r--r--arch/arm/plat-omap/include/plat/clkdev_omap.h4
-rw-r--r--arch/arm/plat-omap/include/plat/common.h2
-rw-r--r--arch/arm/plat-omap/include/plat/cpu.h1
-rw-r--r--arch/arm/plat-omap/include/plat/dma.h1
-rw-r--r--arch/arm/plat-omap/include/plat/dmtimer.h6
-rw-r--r--arch/arm/plat-omap/include/plat/gpio.h3
-rw-r--r--arch/arm/plat-omap/include/plat/hdq1w.h36
-rw-r--r--arch/arm/plat-omap/include/plat/mmc.h4
-rw-r--r--arch/arm/plat-omap/include/plat/omap-serial.h1
-rw-r--r--arch/arm/plat-omap/include/plat/omap_hwmod.h41
-rw-r--r--arch/arm/plat-omap/omap_device.c2
-rw-r--r--arch/arm/plat-omap/sram.c4
-rw-r--r--arch/arm/plat-omap/usb.c8
-rw-r--r--arch/arm/plat-orion/gpio.c27
-rw-r--r--arch/arm/plat-orion/include/plat/gpio.h2
-rw-r--r--arch/arm/plat-samsung/devs.c18
-rw-r--r--arch/arm/plat-samsung/include/plat/regs-usb-hsotg.h379
-rw-r--r--arch/arm/plat-samsung/include/plat/sdhci.h7
-rw-r--r--arch/arm/plat-samsung/platformdata.c2
-rw-r--r--arch/arm/plat-spear/Kconfig4
-rw-r--r--arch/arm/plat-spear/Makefile4
-rw-r--r--arch/arm/plat-spear/include/plat/debug-macro.S2
-rw-r--r--arch/arm/plat-spear/include/plat/hardware.h17
-rw-r--r--arch/arm/plat-spear/include/plat/padmux.h92
-rw-r--r--arch/arm/plat-spear/include/plat/pl080.h21
-rw-r--r--arch/arm/plat-spear/include/plat/uncompress.h2
-rw-r--r--arch/arm/plat-spear/padmux.c164
-rw-r--r--arch/arm/plat-spear/pl080.c80
-rw-r--r--arch/arm/plat-spear/restart.c2
-rw-r--r--arch/arm/plat-spear/time.c17
-rw-r--r--arch/avr32/Kconfig7
-rw-r--r--arch/avr32/include/asm/processor.h3
-rw-r--r--arch/avr32/include/asm/signal.h7
-rw-r--r--arch/avr32/kernel/signal.c30
-rw-r--r--arch/blackfin/Kconfig13
-rw-r--r--arch/blackfin/include/asm/processor.h2
-rw-r--r--arch/blackfin/kernel/signal.c21
-rw-r--r--arch/c6x/Kconfig8
-rw-r--r--arch/c6x/include/asm/processor.h3
-rw-r--r--arch/c6x/kernel/signal.c3
-rw-r--r--arch/cris/Kconfig7
-rw-r--r--arch/cris/arch-v10/kernel/signal.c50
-rw-r--r--arch/cris/arch-v32/kernel/signal.c66
-rw-r--r--arch/cris/include/asm/processor.h4
-rw-r--r--arch/frv/include/asm/processor.h3
-rw-r--r--arch/frv/kernel/process.c11
-rw-r--r--arch/frv/kernel/signal.c47
-rw-r--r--arch/h8300/Kconfig.cpu2
-rw-r--r--arch/h8300/include/asm/processor.h2
-rw-r--r--arch/h8300/include/asm/unistd.h1
-rw-r--r--arch/h8300/kernel/signal.c122
-rw-r--r--arch/h8300/kernel/syscalls.S6
-rw-r--r--arch/hexagon/Kconfig37
-rw-r--r--arch/hexagon/Makefile5
-rw-r--r--arch/hexagon/include/asm/processor.h7
-rw-r--r--arch/hexagon/include/asm/spinlock_types.h2
-rw-r--r--arch/hexagon/kernel/dma.c2
-rw-r--r--arch/hexagon/kernel/signal.c4
-rw-r--r--arch/hexagon/kernel/time.c6
-rw-r--r--arch/hexagon/mm/vm_fault.c22
-rw-r--r--arch/ia64/Kconfig9
-rw-r--r--arch/ia64/include/asm/Kbuild1
-rw-r--r--arch/ia64/include/asm/gpio.h59
-rw-r--r--arch/ia64/include/asm/processor.h8
-rw-r--r--arch/ia64/include/asm/topology.h25
-rw-r--r--arch/ia64/kernel/fsys.S191
-rw-r--r--arch/ia64/kernel/signal.c15
-rw-r--r--arch/m32r/Kconfig4
-rw-r--r--arch/m32r/include/asm/processor.h2
-rw-r--r--arch/m32r/include/asm/signal.h7
-rw-r--r--arch/m32r/kernel/signal.c12
-rw-r--r--arch/m68k/Kconfig11
-rw-r--r--arch/m68k/Kconfig.cpu3
-rw-r--r--arch/m68k/include/asm/processor.h3
-rw-r--r--arch/m68k/include/asm/thread_info.h1
-rw-r--r--arch/m68k/kernel/entry_mm.S6
-rw-r--r--arch/m68k/kernel/signal.c41
-rw-r--r--arch/m68k/platform/68328/entry.S2
-rw-r--r--arch/m68k/platform/68360/entry.S2
-rw-r--r--arch/m68k/platform/coldfire/entry.S2
-rw-r--r--arch/m68k/platform/coldfire/m532x.c2
-rw-r--r--arch/microblaze/Kconfig9
-rw-r--r--arch/microblaze/include/asm/gpio.h57
-rw-r--r--arch/microblaze/include/asm/processor.h1
-rw-r--r--arch/microblaze/kernel/entry-nommu.S20
-rw-r--r--arch/microblaze/kernel/entry.S30
-rw-r--r--arch/microblaze/kernel/signal.c85
-rw-r--r--arch/mips/Kconfig21
-rw-r--r--arch/mips/Kconfig.debug2
-rw-r--r--arch/mips/bcm47xx/setup.c15
-rw-r--r--arch/mips/bcm47xx/sprom.c28
-rw-r--r--arch/mips/include/asm/mach-bcm47xx/bcm47xx.h9
-rw-r--r--arch/mips/include/asm/mach-ip27/topology.h17
-rw-r--r--arch/mips/include/asm/processor.h3
-rw-r--r--arch/mips/kernel/mips-mt.c2
-rw-r--r--arch/mips/kernel/perf_event_mipsxx.c2
-rw-r--r--arch/mips/kernel/signal.c20
-rw-r--r--arch/mips/kernel/signal32.c20
-rw-r--r--arch/mips/kernel/signal_n32.c10
-rw-r--r--arch/mips/lantiq/xway/gpio.c2
-rw-r--r--arch/mips/lantiq/xway/gpio_ebu.c2
-rw-r--r--arch/mips/lantiq/xway/gpio_stp.c2
-rw-r--r--arch/mips/sni/pcimt.c2
-rw-r--r--arch/mn10300/Kconfig8
-rw-r--r--arch/mn10300/include/asm/processor.h3
-rw-r--r--arch/mn10300/kernel/process.c10
-rw-r--r--arch/mn10300/kernel/signal.c35
-rw-r--r--arch/openrisc/Kconfig7
-rw-r--r--arch/openrisc/include/asm/gpio.h69
-rw-r--r--arch/openrisc/include/asm/processor.h4
-rw-r--r--arch/parisc/hpux/fs.c4
-rw-r--r--arch/parisc/include/asm/kbdleds.h19
-rw-r--r--arch/parisc/include/asm/processor.h3
-rw-r--r--arch/parisc/kernel/signal.c15
-rw-r--r--arch/powerpc/Kconfig17
-rw-r--r--arch/powerpc/Makefile49
-rw-r--r--arch/powerpc/boot/dts/bluestone.dts25
-rw-r--r--arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig1
-rw-r--r--arch/powerpc/configs/chroma_defconfig2
-rw-r--r--arch/powerpc/configs/g5_defconfig1
-rw-r--r--arch/powerpc/configs/gamecube_defconfig2
-rw-r--r--arch/powerpc/configs/maple_defconfig1
-rw-r--r--arch/powerpc/configs/mpc85xx_defconfig1
-rw-r--r--arch/powerpc/configs/mpc85xx_smp_defconfig1
-rw-r--r--arch/powerpc/configs/pasemi_defconfig1
-rw-r--r--arch/powerpc/configs/ps3_defconfig6
-rw-r--r--arch/powerpc/configs/wii_defconfig2
-rw-r--r--arch/powerpc/include/asm/asm-compat.h11
-rw-r--r--arch/powerpc/include/asm/cputhreads.h2
-rw-r--r--arch/powerpc/include/asm/gpio.h57
-rw-r--r--arch/powerpc/include/asm/hvcall.h25
-rw-r--r--arch/powerpc/include/asm/lppaca.h196
-rw-r--r--arch/powerpc/include/asm/lv1call.h4
-rw-r--r--arch/powerpc/include/asm/pSeries_reconfig.h12
-rw-r--r--arch/powerpc/include/asm/ppc_asm.h10
-rw-r--r--arch/powerpc/include/asm/processor.h3
-rw-r--r--arch/powerpc/include/asm/ptrace.h6
-rw-r--r--arch/powerpc/include/asm/switch_to.h6
-rw-r--r--arch/powerpc/include/asm/thread_info.h1
-rw-r--r--arch/powerpc/include/asm/topology.h36
-rw-r--r--arch/powerpc/include/asm/vio.h46
-rw-r--r--arch/powerpc/kernel/asm-offsets.c4
-rw-r--r--arch/powerpc/kernel/entry_64.S30
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S4
-rw-r--r--arch/powerpc/kernel/head_44x.S8
-rw-r--r--arch/powerpc/kernel/head_fsl_booke.S8
-rw-r--r--arch/powerpc/kernel/irq.c2
-rw-r--r--arch/powerpc/kernel/misc_32.S203
-rw-r--r--arch/powerpc/kernel/paca.c3
-rw-r--r--arch/powerpc/kernel/process.c21
-rw-r--r--arch/powerpc/kernel/prom_init.c17
-rw-r--r--arch/powerpc/kernel/ptrace.c42
-rw-r--r--arch/powerpc/kernel/ptrace32.c32
-rw-r--r--arch/powerpc/kernel/signal_32.c17
-rw-r--r--arch/powerpc/kernel/vector.S10
-rw-r--r--arch/powerpc/kernel/vio.c273
-rw-r--r--arch/powerpc/lib/copyuser_64.S6
-rw-r--r--arch/powerpc/lib/mem_64.S6
-rw-r--r--arch/powerpc/lib/memcpy_64.S6
-rw-r--r--arch/powerpc/mm/hugetlbpage.c3
-rw-r--r--arch/powerpc/perf/core-book3s.c3
-rw-r--r--arch/powerpc/perf/core-fsl-emb.c3
-rw-r--r--arch/powerpc/platforms/44x/Kconfig2
-rw-r--r--arch/powerpc/platforms/Kconfig.cputype43
-rw-r--r--arch/powerpc/platforms/powermac/low_i2c.c1
-rw-r--r--arch/powerpc/platforms/ps3/Kconfig22
-rw-r--r--arch/powerpc/platforms/ps3/mm.c77
-rw-r--r--arch/powerpc/platforms/ps3/platform.h16
-rw-r--r--arch/powerpc/platforms/ps3/repository.c198
-rw-r--r--arch/powerpc/platforms/pseries/Kconfig2
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c2
-rw-r--r--arch/powerpc/platforms/pseries/plpar_wrappers.h4
-rw-r--r--arch/powerpc/platforms/pseries/reconfig.c7
-rw-r--r--arch/powerpc/sysdev/ppc4xx_msi.c42
-rw-r--r--arch/s390/Kconfig14
-rw-r--r--arch/s390/include/asm/processor.h3
-rw-r--r--arch/s390/kernel/compat_linux.c18
-rw-r--r--arch/s390/kernel/signal.c9
-rw-r--r--arch/score/Kconfig5
-rw-r--r--arch/score/include/asm/processor.h1
-rw-r--r--arch/score/kernel/signal.c29
-rw-r--r--arch/sh/Kconfig60
-rw-r--r--arch/sh/Kconfig.cpu2
-rw-r--r--arch/sh/Makefile4
-rw-r--r--arch/sh/boards/Kconfig9
-rw-r--r--arch/sh/boards/board-edosk7705.c4
-rw-r--r--arch/sh/boards/board-edosk7760.c16
-rw-r--r--arch/sh/boards/board-espt.c3
-rw-r--r--arch/sh/boards/board-magicpanelr2.c27
-rw-r--r--arch/sh/boards/board-polaris.c1
-rw-r--r--arch/sh/boards/board-secureedge5410.c1
-rw-r--r--arch/sh/boards/board-sh7757lcr.c27
-rw-r--r--arch/sh/boards/board-sh7785lcr.c15
-rw-r--r--arch/sh/boards/board-urquell.c3
-rw-r--r--arch/sh/boards/mach-ap325rxa/setup.c15
-rw-r--r--arch/sh/boards/mach-cayman/setup.c1
-rw-r--r--arch/sh/boards/mach-ecovec24/setup.c70
-rw-r--r--arch/sh/boards/mach-hp6xx/setup.c5
-rw-r--r--arch/sh/boards/mach-kfr2r09/setup.c15
-rw-r--r--arch/sh/boards/mach-lboxre2/setup.c1
-rw-r--r--arch/sh/boards/mach-microdev/setup.c1
-rw-r--r--arch/sh/boards/mach-migor/setup.c13
-rw-r--r--arch/sh/boards/mach-rsk/Kconfig10
-rw-r--r--arch/sh/boards/mach-rsk/Makefile2
-rw-r--r--arch/sh/boards/mach-rsk/devices-rsk7264.c58
-rw-r--r--arch/sh/boards/mach-rsk/devices-rsk7269.c60
-rw-r--r--arch/sh/boards/mach-sdk7780/setup.c1
-rw-r--r--arch/sh/boards/mach-se/7206/setup.c1
-rw-r--r--arch/sh/boards/mach-se/770x/setup.c11
-rw-r--r--arch/sh/boards/mach-se/7721/setup.c1
-rw-r--r--arch/sh/boards/mach-se/7722/setup.c3
-rw-r--r--arch/sh/boards/mach-se/7724/setup.c47
-rw-r--r--arch/sh/boards/mach-se/7751/setup.c1
-rw-r--r--arch/sh/boards/mach-se/7780/setup.c1
-rw-r--r--arch/sh/boards/mach-se/board-se7619.c1
-rw-r--r--arch/sh/boards/mach-sh03/setup.c1
-rw-r--r--arch/sh/boards/mach-sh7763rdp/setup.c6
-rw-r--r--arch/sh/configs/rsk7264_defconfig80
-rw-r--r--arch/sh/configs/rsk7269_defconfig65
-rw-r--r--arch/sh/configs/sh7785lcr_32bit_defconfig2
-rw-r--r--arch/sh/drivers/dma/Kconfig17
-rw-r--r--arch/sh/drivers/dma/dma-sh.c290
-rw-r--r--arch/sh/drivers/dma/dma-sysfs.c2
-rw-r--r--arch/sh/drivers/pci/fixups-landisk.c3
-rw-r--r--arch/sh/drivers/pci/fixups-r7780rp.c7
-rw-r--r--arch/sh/drivers/pci/fixups-sdk7780.c18
-rw-r--r--arch/sh/drivers/pci/fixups-se7751.c5
-rw-r--r--arch/sh/drivers/pci/fixups-sh03.c19
-rw-r--r--arch/sh/drivers/pci/fixups-snapgear.c11
-rw-r--r--arch/sh/drivers/pci/pcie-sh7786.c3
-rw-r--r--arch/sh/include/asm/dma-sh.h87
-rw-r--r--arch/sh/include/asm/dma.h9
-rw-r--r--arch/sh/include/asm/fixmap.h2
-rw-r--r--arch/sh/include/asm/i2c-sh7760.h2
-rw-r--r--arch/sh/include/asm/io.h5
-rw-r--r--arch/sh/include/asm/io_noioport.h41
-rw-r--r--arch/sh/include/asm/irq.h13
-rw-r--r--arch/sh/include/asm/kdebug.h2
-rw-r--r--arch/sh/include/asm/kgdb.h30
-rw-r--r--arch/sh/include/asm/machvec.h1
-rw-r--r--arch/sh/include/asm/pgtable_64.h3
-rw-r--r--arch/sh/include/asm/processor.h5
-rw-r--r--arch/sh/include/asm/processor_32.h3
-rw-r--r--arch/sh/include/asm/processor_64.h4
-rw-r--r--arch/sh/include/asm/stackprotector.h27
-rw-r--r--arch/sh/include/asm/syscalls_32.h4
-rw-r--r--arch/sh/include/asm/thread_info.h46
-rw-r--r--arch/sh/include/asm/topology.h25
-rw-r--r--arch/sh/include/asm/traps_64.h14
-rw-r--r--arch/sh/include/asm/unistd.h4
-rw-r--r--arch/sh/include/cpu-sh2/cpu/dma.h23
-rw-r--r--arch/sh/include/cpu-sh2a/cpu/dma.h1
-rw-r--r--arch/sh/include/cpu-sh2a/cpu/sh7264.h176
-rw-r--r--arch/sh/include/cpu-sh2a/cpu/sh7269.h201
-rw-r--r--arch/sh/include/cpu-sh3/cpu/dma.h13
-rw-r--r--arch/sh/include/cpu-sh4/cpu/dma-sh4a.h83
-rw-r--r--arch/sh/include/cpu-sh4/cpu/dma.h25
-rw-r--r--arch/sh/include/cpu-sh4/cpu/freq.h5
-rw-r--r--arch/sh/include/cpu-sh4/cpu/sh7734.h306
-rw-r--r--arch/sh/include/cpu-sh4a/cpu/dma.h72
-rw-r--r--arch/sh/include/cpu-sh5/cpu/dma.h6
-rw-r--r--arch/sh/include/mach-common/mach/hp6xx.h7
-rw-r--r--arch/sh/include/mach-common/mach/lboxre2.h13
-rw-r--r--arch/sh/include/mach-common/mach/sdk7780.h5
-rw-r--r--arch/sh/include/mach-common/mach/titan.h12
-rw-r--r--arch/sh/include/mach-dreamcast/mach/dma.h2
-rw-r--r--arch/sh/include/mach-landisk/mach/iodata_landisk.h19
-rw-r--r--arch/sh/include/mach-se/mach/se.h19
-rw-r--r--arch/sh/include/mach-se/mach/se7343.h9
-rw-r--r--arch/sh/include/mach-se/mach/se7721.h6
-rw-r--r--arch/sh/include/mach-se/mach/se7722.h9
-rw-r--r--arch/sh/include/mach-se/mach/se7724.h7
-rw-r--r--arch/sh/include/mach-se/mach/se7751.h3
-rw-r--r--arch/sh/include/mach-se/mach/se7780.h7
-rw-r--r--arch/sh/kernel/cpu/proc.c4
-rw-r--r--arch/sh/kernel/cpu/sh2/setup-sh7619.c6
-rw-r--r--arch/sh/kernel/cpu/sh2a/Makefile4
-rw-r--r--arch/sh/kernel/cpu/sh2a/clock-sh7264.c153
-rw-r--r--arch/sh/kernel/cpu/sh2a/clock-sh7269.c184
-rw-r--r--arch/sh/kernel/cpu/sh2a/pinmux-sh7264.c2136
-rw-r--r--arch/sh/kernel/cpu/sh2a/pinmux-sh7269.c2800
-rw-r--r--arch/sh/kernel/cpu/sh2a/probe.c6
-rw-r--r--arch/sh/kernel/cpu/sh2a/setup-mxg.c2
-rw-r--r--arch/sh/kernel/cpu/sh2a/setup-sh7201.c16
-rw-r--r--arch/sh/kernel/cpu/sh2a/setup-sh7203.c8
-rw-r--r--arch/sh/kernel/cpu/sh2a/setup-sh7206.c8
-rw-r--r--arch/sh/kernel/cpu/sh2a/setup-sh7264.c606
-rw-r--r--arch/sh/kernel/cpu/sh2a/setup-sh7269.c615
-rw-r--r--arch/sh/kernel/cpu/sh3/entry.S11
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7705.c13
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh770x.c15
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7710.c13
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7720.c32
-rw-r--r--arch/sh/kernel/cpu/sh4/probe.c3
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh4-202.c12
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7750.c17
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7760.c26
-rw-r--r--arch/sh/kernel/cpu/sh4a/Makefile3
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7734.c266
-rw-r--r--arch/sh/kernel/cpu/sh4a/pinmux-sh7734.c2497
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7343.c31
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7366.c23
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7722.c47
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7723.c47
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7724.c77
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7734.c800
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7757.c90
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7763.c30
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7770.c39
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7780.c37
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7785.c43
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7786.c47
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-shx3.c31
-rw-r--r--arch/sh/kernel/cpu/sh5/entry.S22
-rw-r--r--arch/sh/kernel/cpu/sh5/fpu.c3
-rw-r--r--arch/sh/kernel/irq.c6
-rw-r--r--arch/sh/kernel/kgdb.c105
-rw-r--r--arch/sh/kernel/machvec.c3
-rw-r--r--arch/sh/kernel/process.c14
-rw-r--r--arch/sh/kernel/process_32.c14
-rw-r--r--arch/sh/kernel/signal_32.c53
-rw-r--r--arch/sh/kernel/signal_64.c84
-rw-r--r--arch/sh/kernel/traps_64.c2
-rw-r--r--arch/sh/mm/Makefile8
-rw-r--r--arch/sh/mm/fault.c514
-rw-r--r--arch/sh/mm/fault_32.c374
-rw-r--r--arch/sh/mm/fault_64.c265
-rw-r--r--arch/sh/mm/tlb-sh5.c40
-rw-r--r--arch/sh/mm/tlbex_32.c78
-rw-r--r--arch/sh/mm/tlbex_64.c166
-rw-r--r--arch/sh/mm/tlbflush_64.c294
-rw-r--r--arch/sh/tools/mach-types2
-rw-r--r--arch/sparc/Kconfig12
-rw-r--r--arch/sparc/configs/sparc64_defconfig2
-rw-r--r--arch/sparc/include/asm/gpio.h40
-rw-r--r--arch/sparc/include/asm/processor_32.h3
-rw-r--r--arch/sparc/include/asm/processor_64.h3
-rw-r--r--arch/sparc/include/asm/topology_64.h19
-rw-r--r--arch/sparc/kernel/perf_event.c4
-rw-r--r--arch/sparc/kernel/signal32.c10
-rw-r--r--arch/sparc/kernel/signal_32.c12
-rw-r--r--arch/sparc/kernel/signal_64.c13
-rw-r--r--arch/sparc/kernel/sys_sparc32.c4
-rw-r--r--arch/sparc/kernel/sys_sparc_32.c17
-rw-r--r--arch/tile/Kconfig6
-rw-r--r--arch/tile/include/asm/processor.h3
-rw-r--r--arch/tile/include/asm/topology.h26
-rw-r--r--arch/um/Kconfig.common10
-rw-r--r--arch/um/Kconfig.um1
-rw-r--r--arch/um/defconfig1
-rw-r--r--arch/um/drivers/chan_kern.c9
-rw-r--r--arch/um/drivers/line.c2
-rw-r--r--arch/um/drivers/net_kern.c4
-rw-r--r--arch/um/drivers/port_kern.c2
-rw-r--r--arch/um/drivers/xterm_kern.c2
-rw-r--r--arch/um/include/asm/pgtable.h10
-rw-r--r--arch/um/include/asm/processor-generic.h5
-rw-r--r--arch/um/include/asm/thread_info.h2
-rw-r--r--arch/um/include/shared/irq_kern.h2
-rw-r--r--arch/um/kernel/irq.c9
-rw-r--r--arch/um/kernel/process.c10
-rw-r--r--arch/um/kernel/signal.c23
-rw-r--r--arch/um/kernel/skas/syscall.c2
-rw-r--r--arch/um/kernel/tlb.c1
-rw-r--r--arch/um/os-Linux/skas/mem.c10
-rw-r--r--arch/unicore32/Kconfig6
-rw-r--r--arch/unicore32/include/asm/processor.h3
-rw-r--r--arch/unicore32/kernel/signal.c18
-rw-r--r--arch/x86/Kconfig89
-rw-r--r--arch/x86/Makefile6
-rw-r--r--arch/x86/boot/compressed/eboot.c14
-rw-r--r--arch/x86/boot/header.S26
-rw-r--r--arch/x86/boot/main.c18
-rw-r--r--arch/x86/boot/tools/build.c24
-rw-r--r--arch/x86/crypto/aesni-intel_glue.c793
-rw-r--r--arch/x86/ia32/ia32_signal.c12
-rw-r--r--arch/x86/ia32/ia32entry.S9
-rw-r--r--arch/x86/ia32/sys_ia32.c27
-rw-r--r--arch/x86/include/asm/apic.h23
-rw-r--r--arch/x86/include/asm/apicdef.h2
-rw-r--r--arch/x86/include/asm/asm.h38
-rw-r--r--arch/x86/include/asm/atomic64_32.h10
-rw-r--r--arch/x86/include/asm/bootparam.h3
-rw-r--r--arch/x86/include/asm/compat.h2
-rw-r--r--arch/x86/include/asm/current.h2
-rw-r--r--arch/x86/include/asm/desc.h1
-rw-r--r--arch/x86/include/asm/device.h4
-rw-r--r--arch/x86/include/asm/dma-mapping.h9
-rw-r--r--arch/x86/include/asm/fpu-internal.h6
-rw-r--r--arch/x86/include/asm/ftrace.h3
-rw-r--r--arch/x86/include/asm/gpio.h57
-rw-r--r--arch/x86/include/asm/hardirq.h9
-rw-r--r--arch/x86/include/asm/io_apic.h35
-rw-r--r--arch/x86/include/asm/irq_regs.h4
-rw-r--r--arch/x86/include/asm/kbdleds.h17
-rw-r--r--arch/x86/include/asm/kdebug.h1
-rw-r--r--arch/x86/include/asm/kvm_host.h5
-rw-r--r--arch/x86/include/asm/mca.h43
-rw-r--r--arch/x86/include/asm/mca_dma.h201
-rw-r--r--arch/x86/include/asm/mmu_context.h12
-rw-r--r--arch/x86/include/asm/mmzone_32.h6
-rw-r--r--arch/x86/include/asm/mpspec.h2
-rw-r--r--arch/x86/include/asm/mpspec_def.h3
-rw-r--r--arch/x86/include/asm/msr-index.h5
-rw-r--r--arch/x86/include/asm/msr.h9
-rw-r--r--arch/x86/include/asm/nops.h4
-rw-r--r--arch/x86/include/asm/paravirt.h6
-rw-r--r--arch/x86/include/asm/percpu.h24
-rw-r--r--arch/x86/include/asm/perf_event.h12
-rw-r--r--arch/x86/include/asm/processor.h3
-rw-r--r--arch/x86/include/asm/segment.h4
-rw-r--r--arch/x86/include/asm/smp.h4
-rw-r--r--arch/x86/include/asm/spinlock.h2
-rw-r--r--arch/x86/include/asm/stackprotector.h4
-rw-r--r--arch/x86/include/asm/thread_info.h4
-rw-r--r--arch/x86/include/asm/tlbflush.h10
-rw-r--r--arch/x86/include/asm/topology.h38
-rw-r--r--arch/x86/include/asm/uaccess.h25
-rw-r--r--arch/x86/include/asm/uprobes.h57
-rw-r--r--arch/x86/include/asm/vga.h6
-rw-r--r--arch/x86/include/asm/x86_init.h9
-rw-r--r--arch/x86/include/asm/xor_32.h6
-rw-r--r--arch/x86/include/asm/xor_64.h8
-rw-r--r--arch/x86/include/asm/xor_avx.h214
-rw-r--r--arch/x86/include/asm/xsave.h10
-rw-r--r--arch/x86/kernel/Makefile2
-rw-r--r--arch/x86/kernel/acpi/boot.c2
-rw-r--r--arch/x86/kernel/apic/apic.c12
-rw-r--r--arch/x86/kernel/apic/apic_flat_64.c2
-rw-r--r--arch/x86/kernel/apic/apic_noop.c1
-rw-r--r--arch/x86/kernel/apic/apic_numachip.c1
-rw-r--r--arch/x86/kernel/apic/bigsmp_32.c1
-rw-r--r--arch/x86/kernel/apic/es7000_32.c2
-rw-r--r--arch/x86/kernel/apic/io_apic.c109
-rw-r--r--arch/x86/kernel/apic/numaq_32.c1
-rw-r--r--arch/x86/kernel/apic/probe_32.c1
-rw-r--r--arch/x86/kernel/apic/summit_32.c1
-rw-r--r--arch/x86/kernel/apic/x2apic_cluster.c1
-rw-r--r--arch/x86/kernel/apic/x2apic_phys.c1
-rw-r--r--arch/x86/kernel/apic/x2apic_uv_x.c1
-rw-r--r--arch/x86/kernel/check.c20
-rw-r--r--arch/x86/kernel/cpu/common.c2
-rw-r--r--arch/x86/kernel/cpu/intel_cacheinfo.c4
-rw-r--r--arch/x86/kernel/cpu/match.c2
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce.c41
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce_amd.c65
-rw-r--r--arch/x86/kernel/cpu/perf_event.c7
-rw-r--r--arch/x86/kernel/cpu/perf_event_amd.c22
-rw-r--r--arch/x86/kernel/cpu/perf_event_amd_ibs.c570
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel.c4
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_ds.c6
-rw-r--r--arch/x86/kernel/cpu/perf_event_p4.c6
-rw-r--r--arch/x86/kernel/dumpstack.c23
-rw-r--r--arch/x86/kernel/dumpstack_32.c2
-rw-r--r--arch/x86/kernel/dumpstack_64.c2
-rw-r--r--arch/x86/kernel/entry_32.S47
-rw-r--r--arch/x86/kernel/entry_64.S16
-rw-r--r--arch/x86/kernel/ftrace.c500
-rw-r--r--arch/x86/kernel/head_32.S223
-rw-r--r--arch/x86/kernel/head_64.S80
-rw-r--r--arch/x86/kernel/hpet.c66
-rw-r--r--arch/x86/kernel/i387.c2
-rw-r--r--arch/x86/kernel/kprobes.c4
-rw-r--r--arch/x86/kernel/mca_32.c476
-rw-r--r--arch/x86/kernel/microcode_core.c9
-rw-r--r--arch/x86/kernel/mpparse.c11
-rw-r--r--arch/x86/kernel/nmi.c24
-rw-r--r--arch/x86/kernel/nmi_selftest.c13
-rw-r--r--arch/x86/kernel/paravirt.c12
-rw-r--r--arch/x86/kernel/pci-calgary_64.c8
-rw-r--r--arch/x86/kernel/process.c39
-rw-r--r--arch/x86/kernel/process_32.c11
-rw-r--r--arch/x86/kernel/process_64.c19
-rw-r--r--arch/x86/kernel/reboot.c277
-rw-r--r--arch/x86/kernel/setup.c18
-rw-r--r--arch/x86/kernel/signal.c18
-rw-r--r--arch/x86/kernel/smp.c100
-rw-r--r--arch/x86/kernel/smpboot.c108
-rw-r--r--arch/x86/kernel/test_rodata.c10
-rw-r--r--arch/x86/kernel/time.c6
-rw-r--r--arch/x86/kernel/traps.c12
-rw-r--r--arch/x86/kernel/uprobes.c674
-rw-r--r--arch/x86/kernel/vsmp_64.c40
-rw-r--r--arch/x86/kernel/x86_init.c8
-rw-r--r--arch/x86/kernel/xsave.c2
-rw-r--r--arch/x86/lib/checksum_32.S9
-rw-r--r--arch/x86/lib/copy_user_64.S63
-rw-r--r--arch/x86/lib/copy_user_nocache_64.S50
-rw-r--r--arch/x86/lib/csum-copy_64.S16
-rw-r--r--arch/x86/lib/getuser.S9
-rw-r--r--arch/x86/lib/putuser.S12
-rw-r--r--arch/x86/lib/usercopy_32.c232
-rw-r--r--arch/x86/mm/extable.c142
-rw-r--r--arch/x86/mm/fault.c2
-rw-r--r--arch/x86/mm/init.c21
-rw-r--r--arch/x86/mm/init_64.c23
-rw-r--r--arch/x86/mm/numa_emulation.c8
-rw-r--r--arch/x86/mm/tlb.c16
-rw-r--r--arch/x86/pci/Makefile2
-rw-r--r--arch/x86/pci/fixup.c20
-rw-r--r--arch/x86/pci/sta2x11-fixup.c366
-rw-r--r--arch/x86/platform/olpc/olpc-xo1-sci.c43
-rw-r--r--arch/x86/platform/visws/visws_quirks.c2
-rw-r--r--arch/x86/tools/relocs.c12
-rw-r--r--arch/x86/um/asm/elf.h42
-rw-r--r--arch/x86/um/asm/ptrace.h34
-rw-r--r--arch/x86/um/asm/ptrace_32.h23
-rw-r--r--arch/x86/um/asm/ptrace_64.h26
-rw-r--r--arch/x86/um/checksum_32.S9
-rw-r--r--arch/x86/um/shared/sysdep/ptrace.h67
-rw-r--r--arch/x86/um/shared/sysdep/ptrace_32.h92
-rw-r--r--arch/x86/um/shared/sysdep/ptrace_64.h101
-rw-r--r--arch/x86/um/signal.c29
-rw-r--r--arch/x86/um/sys_call_table_64.c1
-rw-r--r--arch/x86/um/syscalls_32.c12
-rw-r--r--arch/x86/um/sysrq_32.c8
-rw-r--r--arch/x86/um/sysrq_64.c8
-rw-r--r--arch/x86/um/tls_32.c2
-rw-r--r--arch/x86/video/fbdev.c20
-rw-r--r--arch/x86/xen/Makefile2
-rw-r--r--arch/x86/xen/apic.c33
-rw-r--r--arch/x86/xen/enlighten.c2
-rw-r--r--arch/x86/xen/mmu.c4
-rw-r--r--arch/x86/xen/xen-asm_32.S6
-rw-r--r--arch/x86/xen/xen-ops.h4
-rw-r--r--arch/xtensa/include/asm/gpio.h60
-rw-r--r--arch/xtensa/include/asm/processor.h3
-rw-r--r--arch/xtensa/include/asm/signal.h7
-rw-r--r--arch/xtensa/include/asm/syscall.h4
-rw-r--r--arch/xtensa/include/asm/thread_info.h1
-rw-r--r--arch/xtensa/include/asm/unistd.h2
-rw-r--r--arch/xtensa/kernel/entry.S6
-rw-r--r--arch/xtensa/kernel/process.c9
-rw-r--r--arch/xtensa/kernel/signal.c73
-rw-r--r--arch/xtensa/variants/s6000/dmac.c2
-rw-r--r--arch/xtensa/variants/s6000/gpio.c4
-rw-r--r--arch/xtensa/variants/s6000/include/variant/dmac.h2
-rw-r--r--arch/xtensa/variants/s6000/irq.c4
-rw-r--r--block/blk-cgroup.c45
-rw-r--r--crypto/xor.c18
-rw-r--r--drivers/Kconfig8
-rw-r--r--drivers/Makefile5
-rw-r--r--drivers/acpi/glue.c2
-rw-r--r--drivers/acpi/pci_link.c12
-rw-r--r--drivers/acpi/sleep.c8
-rw-r--r--drivers/acpi/utils.c30
-rw-r--r--drivers/ata/Kconfig9
-rw-r--r--drivers/ata/Makefile1
-rw-r--r--drivers/ata/ata_generic.c2
-rw-r--r--drivers/ata/ata_piix.c36
-rw-r--r--drivers/ata/libata-core.c7
-rw-r--r--drivers/ata/libata-eh.c24
-rw-r--r--drivers/ata/pata_ep93xx.c1044
-rw-r--r--drivers/base/bus.c3
-rw-r--r--drivers/base/core.c58
-rw-r--r--drivers/base/cpu.c4
-rw-r--r--drivers/base/devres.c35
-rw-r--r--drivers/base/devtmpfs.c6
-rw-r--r--drivers/base/dma-buf.c12
-rw-r--r--drivers/base/driver.c2
-rw-r--r--drivers/base/power/domain.c176
-rw-r--r--drivers/base/power/domain_governor.c166
-rw-r--r--drivers/base/power/main.c10
-rw-r--r--drivers/base/power/qos.c19
-rw-r--r--drivers/base/power/runtime.c103
-rw-r--r--drivers/base/power/sysfs.c54
-rw-r--r--drivers/base/power/wakeup.c174
-rw-r--r--drivers/base/regmap/Kconfig1
-rw-r--r--drivers/bcma/core.c3
-rw-r--r--drivers/bcma/driver_pci.c53
-rw-r--r--drivers/bcma/driver_pci_host.c10
-rw-r--r--drivers/bcma/host_pci.c7
-rw-r--r--drivers/bcma/scan.c73
-rw-r--r--drivers/bcma/sprom.c149
-rw-r--r--drivers/bluetooth/ath3k.c7
-rw-r--r--drivers/bluetooth/bcm203x.c1
-rw-r--r--drivers/bluetooth/bfusb.c1
-rw-r--r--drivers/bluetooth/bpa10x.c1
-rw-r--r--drivers/bluetooth/btmrvl_drv.h3
-rw-r--r--drivers/bluetooth/btmrvl_main.c56
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c112
-rw-r--r--drivers/bluetooth/btusb.c17
-rw-r--r--drivers/bluetooth/hci_ldisc.c2
-rw-r--r--drivers/bluetooth/hci_vhci.c3
-rw-r--r--drivers/char/Kconfig8
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/agp/generic.c4
-rw-r--r--drivers/char/agp/intel-agp.c5
-rw-r--r--drivers/char/agp/intel-agp.h14
-rw-r--r--drivers/char/agp/intel-gtt.c45
-rw-r--r--drivers/char/agp/sgi-agp.c1
-rw-r--r--drivers/char/hw_random/Kconfig17
-rw-r--r--drivers/char/hw_random/Makefile1
-rw-r--r--drivers/char/hw_random/omap-rng.c22
-rw-r--r--drivers/char/hw_random/pseries-rng.c96
-rw-r--r--drivers/char/mem.c42
-rw-r--r--drivers/char/ramoops.c250
-rw-r--r--drivers/char/xilinx_hwicap/xilinx_hwicap.c30
-rw-r--r--drivers/char/xilinx_hwicap/xilinx_hwicap.h2
-rw-r--r--drivers/clocksource/Kconfig2
-rw-r--r--drivers/cpufreq/db8500-cpufreq.c2
-rw-r--r--drivers/crypto/Kconfig28
-rw-r--r--drivers/crypto/Makefile1
-rw-r--r--drivers/crypto/amcc/crypto4xx_core.c2
-rw-r--r--drivers/crypto/caam/caamalg.c14
-rw-r--r--drivers/crypto/caam/ctrl.c16
-rw-r--r--drivers/crypto/nx/Makefile11
-rw-r--r--drivers/crypto/nx/nx-aes-cbc.c141
-rw-r--r--drivers/crypto/nx/nx-aes-ccm.c468
-rw-r--r--drivers/crypto/nx/nx-aes-ctr.c178
-rw-r--r--drivers/crypto/nx/nx-aes-ecb.c139
-rw-r--r--drivers/crypto/nx/nx-aes-gcm.c353
-rw-r--r--drivers/crypto/nx/nx-aes-xcbc.c236
-rw-r--r--drivers/crypto/nx/nx-sha256.c246
-rw-r--r--drivers/crypto/nx/nx-sha512.c265
-rw-r--r--drivers/crypto/nx/nx.c716
-rw-r--r--drivers/crypto/nx/nx.h193
-rw-r--r--drivers/crypto/nx/nx_csbcpb.h205
-rw-r--r--drivers/crypto/nx/nx_debugfs.c103
-rw-r--r--drivers/crypto/ux500/Kconfig30
-rw-r--r--drivers/crypto/ux500/Makefile8
-rw-r--r--drivers/crypto/ux500/cryp/Makefile13
-rw-r--r--drivers/crypto/ux500/cryp/cryp.c389
-rw-r--r--drivers/crypto/ux500/cryp/cryp.h308
-rw-r--r--drivers/crypto/ux500/cryp/cryp_core.c1784
-rw-r--r--drivers/crypto/ux500/cryp/cryp_irq.c45
-rw-r--r--drivers/crypto/ux500/cryp/cryp_irq.h31
-rw-r--r--drivers/crypto/ux500/cryp/cryp_irqp.h125
-rw-r--r--drivers/crypto/ux500/cryp/cryp_p.h123
-rw-r--r--drivers/crypto/ux500/hash/Makefile11
-rw-r--r--drivers/crypto/ux500/hash/hash_alg.h395
-rw-r--r--drivers/crypto/ux500/hash/hash_core.c2009
-rw-r--r--drivers/devfreq/Kconfig2
-rw-r--r--drivers/devfreq/governor_performance.c7
-rw-r--r--drivers/devfreq/governor_powersave.c7
-rw-r--r--drivers/edac/edac_core.h4
-rw-r--r--drivers/edac/edac_device.c8
-rw-r--r--drivers/edac/i7core_edac.c10
-rw-r--r--drivers/edac/sb_edac.c6
-rw-r--r--drivers/extcon/Kconfig32
-rw-r--r--drivers/extcon/Makefile7
-rw-r--r--drivers/extcon/extcon-max8997.c (renamed from drivers/misc/max8997-muic.c)206
-rw-r--r--drivers/extcon/extcon_class.c832
-rw-r--r--drivers/extcon/extcon_gpio.c169
-rw-r--r--drivers/firewire/core-card.c5
-rw-r--r--drivers/firewire/core-cdev.c51
-rw-r--r--drivers/firewire/core-device.c116
-rw-r--r--drivers/firewire/core-iso.c80
-rw-r--r--drivers/firewire/core-transaction.c35
-rw-r--r--drivers/firewire/core.h22
-rw-r--r--drivers/firewire/nosy.c20
-rw-r--r--drivers/firewire/ohci.c42
-rw-r--r--drivers/firewire/sbp2.c28
-rw-r--r--drivers/gpio/Kconfig45
-rw-r--r--drivers/gpio/Makefile5
-rw-r--r--drivers/gpio/devres.c32
-rw-r--r--drivers/gpio/gpio-bt8xx.c12
-rw-r--r--drivers/gpio/gpio-em.c418
-rw-r--r--drivers/gpio/gpio-ep93xx.c2
-rw-r--r--drivers/gpio/gpio-generic.c16
-rw-r--r--drivers/gpio/gpio-langwell.c91
-rw-r--r--drivers/gpio/gpio-lpc32xx.c52
-rw-r--r--drivers/gpio/gpio-mcp23s08.c2
-rw-r--r--drivers/gpio/gpio-ml-ioh.c12
-rw-r--r--drivers/gpio/gpio-mpc8xxx.c3
-rw-r--r--drivers/gpio/gpio-msic.c339
-rw-r--r--drivers/gpio/gpio-mxc.c2
-rw-r--r--drivers/gpio/gpio-mxs.c2
-rw-r--r--drivers/gpio/gpio-omap.c106
-rw-r--r--drivers/gpio/gpio-pca953x.c43
-rw-r--r--drivers/gpio/gpio-pch.c12
-rw-r--r--drivers/gpio/gpio-pxa.c116
-rw-r--r--drivers/gpio/gpio-rc5t583.c180
-rw-r--r--drivers/gpio/gpio-samsung.c407
-rw-r--r--drivers/gpio/gpio-sodaville.c14
-rw-r--r--drivers/gpio/gpio-tegra.c39
-rw-r--r--drivers/gpio/gpiolib-of.c (renamed from drivers/of/gpio.c)80
-rw-r--r--drivers/gpio/gpiolib.c18
-rw-r--r--drivers/gpu/drm/Kconfig6
-rw-r--r--drivers/gpu/drm/Makefile3
-rw-r--r--drivers/gpu/drm/ast/Kconfig16
-rw-r--r--drivers/gpu/drm/ast/Makefile9
-rw-r--r--drivers/gpu/drm/ast/ast_dram_tables.h144
-rw-r--r--drivers/gpu/drm/ast/ast_drv.c244
-rw-r--r--drivers/gpu/drm/ast/ast_drv.h356
-rw-r--r--drivers/gpu/drm/ast/ast_fb.c341
-rw-r--r--drivers/gpu/drm/ast/ast_main.c527
-rw-r--r--drivers/gpu/drm/ast/ast_mode.c1160
-rw-r--r--drivers/gpu/drm/ast/ast_post.c1780
-rw-r--r--drivers/gpu/drm/ast/ast_tables.h265
-rw-r--r--drivers/gpu/drm/ast/ast_ttm.c453
-rw-r--r--drivers/gpu/drm/cirrus/Kconfig12
-rw-r--r--drivers/gpu/drm/cirrus/Makefile5
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_drv.c108
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_drv.h246
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_fbdev.c307
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_main.c335
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_mode.c629
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_ttm.c453
-rw-r--r--drivers/gpu/drm/drm_cache.c23
-rw-r--r--drivers/gpu/drm/drm_context.c9
-rw-r--r--drivers/gpu/drm/drm_crtc.c583
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c35
-rw-r--r--drivers/gpu/drm/drm_drv.c4
-rw-r--r--drivers/gpu/drm/drm_edid.c222
-rw-r--r--drivers/gpu/drm/drm_edid_load.c12
-rw-r--r--drivers/gpu/drm/drm_edid_modes.h292
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c10
-rw-r--r--drivers/gpu/drm/drm_gem.c35
-rw-r--r--drivers/gpu/drm/drm_ioctl.c4
-rw-r--r--drivers/gpu/drm/drm_irq.c23
-rw-r--r--drivers/gpu/drm/drm_lock.c2
-rw-r--r--drivers/gpu/drm/drm_prime.c48
-rw-r--r--drivers/gpu/drm/drm_stub.c7
-rw-r--r--drivers/gpu/drm/drm_sysfs.c10
-rw-r--r--drivers/gpu/drm/drm_vm.c18
-rw-r--r--drivers/gpu/drm/exynos/Kconfig12
-rw-r--r--drivers/gpu/drm/exynos/Makefile2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_buf.c12
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.h4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dmabuf.c272
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dmabuf.h39
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c43
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h17
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fb.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_g2d.c937
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_g2d.h36
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.c89
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.h12
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_hdmi.c77
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_hdmi.h6
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_plane.c10
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c429
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.c401
-rw-r--r--drivers/gpu/drm/exynos/regs-hdmi.h6
-rw-r--r--drivers/gpu/drm/gma500/Makefile5
-rw-r--r--drivers/gpu/drm/gma500/cdv_device.c231
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_crt.c30
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_display.c697
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_hdmi.c7
-rw-r--r--drivers/gpu/drm/gma500/cdv_intel_lvds.c76
-rw-r--r--drivers/gpu/drm/gma500/framebuffer.c57
-rw-r--r--drivers/gpu/drm/gma500/gem.c2
-rw-r--r--drivers/gpu/drm/gma500/gtt.c32
-rw-r--r--drivers/gpu/drm/gma500/intel_bios.c274
-rw-r--r--drivers/gpu/drm/gma500/intel_bios.h161
-rw-r--r--drivers/gpu/drm/gma500/mdfld_device.c452
-rw-r--r--drivers/gpu/drm/gma500/mdfld_dsi_dpi.c1
-rw-r--r--drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c24
-rw-r--r--drivers/gpu/drm/gma500/mdfld_intel_display.c330
-rw-r--r--drivers/gpu/drm/gma500/mid_bios.c295
-rw-r--r--drivers/gpu/drm/gma500/oaktrail.h25
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_crtc.c134
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_device.c138
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_hdmi.c66
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c2
-rw-r--r--drivers/gpu/drm/gma500/oaktrail_lvds.c4
-rw-r--r--drivers/gpu/drm/gma500/opregion.c344
-rw-r--r--drivers/gpu/drm/gma500/opregion.h (renamed from drivers/gpu/drm/gma500/intel_opregion.c)64
-rw-r--r--drivers/gpu/drm/gma500/psb_device.c75
-rw-r--r--drivers/gpu/drm/gma500/psb_drv.c66
-rw-r--r--drivers/gpu/drm/gma500/psb_drv.h208
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_display.c348
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_drv.h9
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_reg.h35
-rw-r--r--drivers/gpu/drm/gma500/psb_intel_sdvo.c9
-rw-r--r--drivers/gpu/drm/gma500/psb_irq.c36
-rw-r--r--drivers/gpu/drm/gma500/psb_lid.c14
-rw-r--r--drivers/gpu/drm/i915/Makefile7
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c383
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c1160
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c277
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h245
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c1916
-rw-r--r--drivers/gpu/drm/i915/i915_gem_debug.c16
-rw-r--r--drivers/gpu/drm/i915/i915_gem_dmabuf.c171
-rw-r--r--drivers/gpu/drm/i915/i915_gem_evict.c38
-rw-r--r--drivers/gpu/drm/i915/i915_gem_execbuffer.c200
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c96
-rw-r--r--drivers/gpu/drm/i915/i915_gem_stolen.c202
-rw-r--r--drivers/gpu/drm/i915/i915_gem_tiling.c18
-rw-r--r--drivers/gpu/drm/i915/i915_ioc32.c5
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c1732
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h488
-rw-r--r--drivers/gpu/drm/i915/i915_suspend.c18
-rw-r--r--drivers/gpu/drm/i915/i915_sysfs.c111
-rw-r--r--drivers/gpu/drm/i915/i915_trace_points.c2
-rw-r--r--drivers/gpu/drm/i915/intel_acpi.c3
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c45
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c76
-rw-r--r--drivers/gpu/drm/i915/intel_ddi.c755
-rw-r--r--drivers/gpu/drm/i915/intel_display.c4338
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c46
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h105
-rw-r--r--drivers/gpu/drm/i915/intel_dvo.c6
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c2
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c310
-rw-r--r--drivers/gpu/drm/i915/intel_i2c.c384
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c11
-rw-r--r--drivers/gpu/drm/i915/intel_modes.c3
-rw-r--r--drivers/gpu/drm/i915/intel_opregion.c71
-rw-r--r--drivers/gpu/drm/i915/intel_overlay.c209
-rw-r--r--drivers/gpu/drm/i915/intel_panel.c29
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c3796
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c725
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.h23
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c107
-rw-r--r--drivers/gpu/drm/i915/intel_sprite.c102
-rw-r--r--drivers/gpu/drm/i915/intel_tv.c16
-rw-r--r--drivers/gpu/drm/mgag200/Kconfig15
-rw-r--r--drivers/gpu/drm/mgag200/Makefile5
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_drv.c116
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_drv.h276
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_fb.c294
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_i2c.c156
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_main.c388
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_mode.c1533
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_reg.h661
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_ttm.c452
-rw-r--r--drivers/gpu/drm/nouveau/Makefile11
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_acpi.c3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c51
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c385
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_channel.c88
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c8
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_debugfs.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c40
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dma.h35
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dp.c21
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.c23
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h176
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c34
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.c578
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.h52
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fifo.h32
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gem.c11
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gpio.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_grctx.h4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_hw.c5
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mem.c19
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_object.c215
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_perf.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.h4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_prime.c163
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_sgdma.c9
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_software.h69
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c270
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_vm.c57
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_vm.h6
-rw-r--r--drivers/gpu/drm/nouveau/nv04_crtc.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv04_display.c11
-rw-r--r--drivers/gpu/drm/nouveau/nv04_fbcon.c48
-rw-r--r--drivers/gpu/drm/nouveau/nv04_fence.c140
-rw-r--r--drivers/gpu/drm/nouveau/nv04_fifo.c419
-rw-r--r--drivers/gpu/drm/nouveau/nv04_graph.c39
-rw-r--r--drivers/gpu/drm/nouveau/nv04_instmem.c23
-rw-r--r--drivers/gpu/drm/nouveau/nv04_software.c147
-rw-r--r--drivers/gpu/drm/nouveau/nv10_fence.c214
-rw-r--r--drivers/gpu/drm/nouveau/nv10_fifo.c278
-rw-r--r--drivers/gpu/drm/nouveau/nv10_graph.c13
-rw-r--r--drivers/gpu/drm/nouveau/nv17_fifo.c177
-rw-r--r--drivers/gpu/drm/nouveau/nv20_graph.c8
-rw-r--r--drivers/gpu/drm/nouveau/nv31_mpeg.c4
-rw-r--r--drivers/gpu/drm/nouveau/nv40_fifo.c351
-rw-r--r--drivers/gpu/drm/nouveau/nv40_graph.c37
-rw-r--r--drivers/gpu/drm/nouveau/nv40_grctx.c32
-rw-r--r--drivers/gpu/drm/nouveau/nv40_pm.c1
-rw-r--r--drivers/gpu/drm/nouveau/nv50_crtc.c102
-rw-r--r--drivers/gpu/drm/nouveau/nv50_cursor.c12
-rw-r--r--drivers/gpu/drm/nouveau/nv50_dac.c6
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c75
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.h1
-rw-r--r--drivers/gpu/drm/nouveau/nv50_evo.c4
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fb.c4
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fbcon.c59
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fifo.c596
-rw-r--r--drivers/gpu/drm/nouveau/nv50_graph.c229
-rw-r--r--drivers/gpu/drm/nouveau/nv50_grctx.c33
-rw-r--r--drivers/gpu/drm/nouveau/nv50_instmem.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv50_mpeg.c19
-rw-r--r--drivers/gpu/drm/nouveau/nv50_software.c214
-rw-r--r--drivers/gpu/drm/nouveau/nv50_sor.c6
-rw-r--r--drivers/gpu/drm/nouveau/nv50_vm.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv84_fence.c177
-rw-r--r--drivers/gpu/drm/nouveau/nv84_fifo.c241
-rw-r--r--drivers/gpu/drm/nouveau/nv98_crypt.c166
-rw-r--r--drivers/gpu/drm/nouveau/nv98_crypt.fuc698
-rw-r--r--drivers/gpu/drm/nouveau/nv98_crypt.fuc.h584
-rw-r--r--drivers/gpu/drm/nouveau/nva3_copy.c31
-rw-r--r--drivers/gpu/drm/nouveau/nva3_pm.c290
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_fbcon.c54
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_fence.c184
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_fifo.c310
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_graph.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_pm.c189
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_software.c153
-rw-r--r--drivers/gpu/drm/nouveau/nvd0_display.c16
-rw-r--r--drivers/gpu/drm/nouveau/nve0_fifo.c423
-rw-r--r--drivers/gpu/drm/nouveau/nve0_graph.c831
-rw-r--r--drivers/gpu/drm/nouveau/nve0_graph.h89
-rw-r--r--drivers/gpu/drm/nouveau/nve0_grctx.c2777
-rw-r--r--drivers/gpu/drm/radeon/Makefile5
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c7
-rw-r--r--drivers/gpu/drm/radeon/atombios_dp.c27
-rw-r--r--drivers/gpu/drm/radeon/atombios_encoders.c20
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c155
-rw-r--r--drivers/gpu/drm/radeon/evergreen_blit_kms.c3
-rw-r--r--drivers/gpu/drm/radeon/evergreen_cs.c10
-rw-r--r--drivers/gpu/drm/radeon/evergreen_hdmi.c216
-rw-r--r--drivers/gpu/drm/radeon/evergreen_reg.h2
-rw-r--r--drivers/gpu/drm/radeon/evergreend.h220
-rw-r--r--drivers/gpu/drm/radeon/ni.c41
-rw-r--r--drivers/gpu/drm/radeon/r100.c121
-rw-r--r--drivers/gpu/drm/radeon/r200.c2
-rw-r--r--drivers/gpu/drm/radeon/r300.c34
-rw-r--r--drivers/gpu/drm/radeon/r420.c7
-rw-r--r--drivers/gpu/drm/radeon/r520.c8
-rw-r--r--drivers/gpu/drm/radeon/r600.c191
-rw-r--r--drivers/gpu/drm/radeon/r600_audio.c215
-rw-r--r--drivers/gpu/drm/radeon/r600_blit_kms.c101
-rw-r--r--drivers/gpu/drm/radeon/r600_cs.c22
-rw-r--r--drivers/gpu/drm/radeon/r600_hdmi.c464
-rw-r--r--drivers/gpu/drm/radeon/r600_reg.h45
-rw-r--r--drivers/gpu/drm/radeon/r600d.h233
-rw-r--r--drivers/gpu/drm/radeon/radeon.h235
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.c44
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.h27
-rw-r--r--drivers/gpu/drm/radeon/radeon_benchmark.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_combios.c66
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c56
-rw-r--r--drivers/gpu/drm/radeon/radeon_cp.c12
-rw-r--r--drivers/gpu/drm/radeon/radeon_cs.c143
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c42
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c113
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c18
-rw-r--r--drivers/gpu/drm/radeon/radeon_fence.c621
-rw-r--r--drivers/gpu/drm/radeon/radeon_gart.c28
-rw-r--r--drivers/gpu/drm/radeon/radeon_gem.c22
-rw-r--r--drivers/gpu/drm/radeon/radeon_irq_kms.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon_kms.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_encoders.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h15
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c6
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.h30
-rw-r--r--drivers/gpu/drm/radeon/radeon_pm.c18
-rw-r--r--drivers/gpu/drm/radeon/radeon_prime.c176
-rw-r--r--drivers/gpu/drm/radeon/radeon_ring.c396
-rw-r--r--drivers/gpu/drm/radeon/radeon_sa.c325
-rw-r--r--drivers/gpu/drm/radeon/radeon_semaphore.c187
-rw-r--r--drivers/gpu/drm/radeon/radeon_test.c8
-rw-r--r--drivers/gpu/drm/radeon/radeon_ttm.c67
-rw-r--r--drivers/gpu/drm/radeon/rs400.c7
-rw-r--r--drivers/gpu/drm/radeon/rs600.c48
-rw-r--r--drivers/gpu/drm/radeon/rs600d.h14
-rw-r--r--drivers/gpu/drm/radeon/rs690.c7
-rw-r--r--drivers/gpu/drm/radeon/rv515.c8
-rw-r--r--drivers/gpu/drm/radeon/rv770.c12
-rw-r--r--drivers/gpu/drm/radeon/rv770d.h191
-rw-r--r--drivers/gpu/drm/radeon/si.c30
-rw-r--r--drivers/gpu/drm/savage/savage_bci.c2
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c17
-rw-r--r--drivers/gpu/drm/udl/udl_drv.c8
-rw-r--r--drivers/gpu/drm/udl/udl_drv.h3
-rw-r--r--drivers/gpu/drm/udl/udl_fb.c9
-rw-r--r--drivers/gpu/drm/udl/udl_gem.c75
-rw-r--r--drivers/gpu/drm/udl/udl_modeset.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_resource.c2
-rw-r--r--drivers/gpu/vga/Kconfig1
-rw-r--r--drivers/gpu/vga/vga_switcheroo.c284
-rw-r--r--drivers/gpu/vga/vgaarb.c9
-rw-r--r--drivers/hid/Kconfig36
-rw-r--r--drivers/hid/Makefile3
-rw-r--r--drivers/hid/hid-apple.c5
-rw-r--r--drivers/hid/hid-aureal.c54
-rw-r--r--drivers/hid/hid-core.c316
-rw-r--r--drivers/hid/hid-generic.c53
-rw-r--r--drivers/hid/hid-hyperv.c15
-rw-r--r--drivers/hid/hid-ids.h8
-rw-r--r--drivers/hid/hid-input.c36
-rw-r--r--drivers/hid/hid-lg.c55
-rw-r--r--drivers/hid/hid-lg.h5
-rw-r--r--drivers/hid/hid-lg4ff.c258
-rw-r--r--drivers/hid/hid-logitech-dj.c76
-rw-r--r--drivers/hid/hid-multitouch.c233
-rw-r--r--drivers/hid/hid-uclogic.c141
-rw-r--r--drivers/hid/hid-wacom.c302
-rw-r--r--drivers/hid/hid-waltop.c230
-rw-r--r--drivers/hid/hid-wiimote-core.c16
-rw-r--r--drivers/hid/hidraw.c19
-rw-r--r--drivers/hid/usbhid/hid-core.c146
-rw-r--r--drivers/hid/usbhid/hid-quirks.c1
-rw-r--r--drivers/hid/usbhid/hiddev.c9
-rw-r--r--drivers/hid/usbhid/usbhid.h1
-rw-r--r--drivers/hid/usbhid/usbmouse.c7
-rw-r--r--drivers/hv/channel_mgmt.c73
-rw-r--r--drivers/hv/hv.c2
-rw-r--r--drivers/hv/hv_kvp.c3
-rw-r--r--drivers/hv/hv_util.c9
-rw-r--r--drivers/hv/hyperv_vmbus.h2
-rw-r--r--drivers/hwmon/Kconfig15
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/acpi_power_meter.c166
-rw-r--r--drivers/hwmon/ad7314.c11
-rw-r--r--drivers/hwmon/fam15h_power.c13
-rw-r--r--drivers/hwmon/ina2xx.c368
-rw-r--r--drivers/hwmon/it87.c384
-rw-r--r--drivers/hwmon/k10temp.c13
-rw-r--r--drivers/hwmon/k8temp.c13
-rw-r--r--drivers/hwmon/ntc_thermistor.c191
-rw-r--r--drivers/i2c/busses/Kconfig2
-rw-r--r--drivers/i2c/busses/i2c-imx.c8
-rw-r--r--drivers/i2c/busses/i2c-mxs.c6
-rw-r--r--drivers/i2c/busses/i2c-pnx.c157
-rw-r--r--drivers/i2c/busses/i2c-powermac.c98
-rw-r--r--drivers/i2c/busses/i2c-s6000.c2
-rw-r--r--drivers/i2c/busses/i2c-s6000.h2
-rw-r--r--drivers/iio/Kconfig54
-rw-r--r--drivers/iio/Makefile13
-rw-r--r--drivers/iio/adc/Kconfig16
-rw-r--r--drivers/iio/adc/Makefile5
-rw-r--r--drivers/iio/adc/at91_adc.c802
-rw-r--r--drivers/iio/amplifiers/Kconfig17
-rw-r--r--drivers/iio/amplifiers/Makefile5
-rw-r--r--drivers/iio/amplifiers/ad8366.c222
-rw-r--r--drivers/iio/iio_core.h (renamed from drivers/staging/iio/iio_core.h)6
-rw-r--r--drivers/iio/iio_core_trigger.h (renamed from drivers/staging/iio/iio_core_trigger.h)0
-rw-r--r--drivers/iio/industrialio-buffer.c (renamed from drivers/staging/iio/industrialio-buffer.c)91
-rw-r--r--drivers/iio/industrialio-core.c (renamed from drivers/staging/iio/industrialio-core.c)94
-rw-r--r--drivers/iio/industrialio-event.c (renamed from drivers/staging/iio/industrialio-event.c)14
-rw-r--r--drivers/iio/industrialio-trigger.c (renamed from drivers/staging/iio/industrialio-trigger.c)24
-rw-r--r--drivers/iio/inkern.c (renamed from drivers/staging/iio/inkern.c)8
-rw-r--r--drivers/iio/kfifo_buf.c (renamed from drivers/staging/iio/kfifo_buf.c)3
-rw-r--r--drivers/input/Kconfig17
-rw-r--r--drivers/input/Makefile2
-rw-r--r--drivers/input/evdev.c69
-rw-r--r--drivers/input/ff-memless.c3
-rw-r--r--drivers/input/gameport/emu10k1-gp.c13
-rw-r--r--drivers/input/gameport/fm801-gp.c16
-rw-r--r--drivers/input/joystick/a3d.c13
-rw-r--r--drivers/input/joystick/adi.c17
-rw-r--r--drivers/input/joystick/cobra.c13
-rw-r--r--drivers/input/joystick/gf2k.c13
-rw-r--r--drivers/input/joystick/grip.c13
-rw-r--r--drivers/input/joystick/grip_mp.c13
-rw-r--r--drivers/input/joystick/guillemot.c13
-rw-r--r--drivers/input/joystick/iforce/iforce-main.c3
-rw-r--r--drivers/input/joystick/iforce/iforce-packets.c16
-rw-r--r--drivers/input/joystick/iforce/iforce-usb.c18
-rw-r--r--drivers/input/joystick/iforce/iforce.h1
-rw-r--r--drivers/input/joystick/interact.c13
-rw-r--r--drivers/input/joystick/joydump.c13
-rw-r--r--drivers/input/joystick/magellan.c17
-rw-r--r--drivers/input/joystick/sidewinder.c13
-rw-r--r--drivers/input/joystick/spaceball.c17
-rw-r--r--drivers/input/joystick/spaceorb.c17
-rw-r--r--drivers/input/joystick/stinger.c17
-rw-r--r--drivers/input/joystick/tmdc.c13
-rw-r--r--drivers/input/joystick/twidjoy.c17
-rw-r--r--drivers/input/joystick/warrior.c17
-rw-r--r--drivers/input/joystick/xpad.c35
-rw-r--r--drivers/input/joystick/zhenhua.c17
-rw-r--r--drivers/input/keyboard/Kconfig32
-rw-r--r--drivers/input/keyboard/Makefile1
-rw-r--r--drivers/input/keyboard/adp5588-keys.c1
-rw-r--r--drivers/input/keyboard/atkbd.c2
-rw-r--r--drivers/input/keyboard/ep93xx_keypad.c44
-rw-r--r--drivers/input/keyboard/hil_kbd.c13
-rw-r--r--drivers/input/keyboard/imx_keypad.c17
-rw-r--r--drivers/input/keyboard/lkkbd.c17
-rw-r--r--drivers/input/keyboard/lm8333.c235
-rw-r--r--drivers/input/keyboard/matrix_keypad.c99
-rw-r--r--drivers/input/keyboard/newtonkbd.c13
-rw-r--r--drivers/input/keyboard/nomadik-ske-keypad.c20
-rw-r--r--drivers/input/keyboard/omap-keypad.c20
-rw-r--r--drivers/input/keyboard/omap4-keypad.c133
-rw-r--r--drivers/input/keyboard/pmic8xxx-keypad.c20
-rw-r--r--drivers/input/keyboard/samsung-keypad.c20
-rw-r--r--drivers/input/keyboard/spear-keyboard.c92
-rw-r--r--drivers/input/keyboard/stmpe-keypad.c16
-rw-r--r--drivers/input/keyboard/stowaway.c13
-rw-r--r--drivers/input/keyboard/sunkbd.c17
-rw-r--r--drivers/input/keyboard/tc3589x-keypad.c41
-rw-r--r--drivers/input/keyboard/tca8418_keypad.c15
-rw-r--r--drivers/input/keyboard/tegra-kbc.c68
-rw-r--r--drivers/input/keyboard/tnetv107x-keypad.c21
-rw-r--r--drivers/input/keyboard/twl4030_keypad.c25
-rw-r--r--drivers/input/keyboard/w90p910_keypad.c27
-rw-r--r--drivers/input/keyboard/xtkbd.c13
-rw-r--r--drivers/input/matrix-keymap.c163
-rw-r--r--drivers/input/misc/cm109.c33
-rw-r--r--drivers/input/misc/cma3000_d0x.c2
-rw-r--r--drivers/input/misc/keyspan_remote.c23
-rw-r--r--drivers/input/misc/mpu3050.c2
-rw-r--r--drivers/input/misc/powermate.c13
-rw-r--r--drivers/input/misc/twl6040-vibra.c46
-rw-r--r--drivers/input/misc/yealink.c31
-rw-r--r--drivers/input/mouse/Kconfig12
-rw-r--r--drivers/input/mouse/Makefile1
-rw-r--r--drivers/input/mouse/alps.c81
-rw-r--r--drivers/input/mouse/alps.h2
-rw-r--r--drivers/input/mouse/appletouch.c59
-rw-r--r--drivers/input/mouse/bcm5974.c24
-rw-r--r--drivers/input/mouse/navpoint.c369
-rw-r--r--drivers/input/mouse/sentelic.c34
-rw-r--r--drivers/input/mouse/sentelic.h8
-rw-r--r--drivers/input/mouse/sermouse.c13
-rw-r--r--drivers/input/mouse/synaptics.c20
-rw-r--r--drivers/input/mouse/vsxxxaa.c14
-rw-r--r--drivers/input/of_keymap.c87
-rw-r--r--drivers/input/serio/pcips2.c15
-rw-r--r--drivers/input/serio/ps2mult.c13
-rw-r--r--drivers/input/serio/serio_raw.c65
-rw-r--r--drivers/input/serio/xilinx_ps2.c35
-rw-r--r--drivers/input/tablet/acecad.c15
-rw-r--r--drivers/input/tablet/aiptek.c30
-rw-r--r--drivers/input/tablet/gtco.c110
-rw-r--r--drivers/input/tablet/kbtab.c15
-rw-r--r--drivers/input/tablet/wacom.h4
-rw-r--r--drivers/input/tablet/wacom_sys.c255
-rw-r--r--drivers/input/tablet/wacom_wac.c298
-rw-r--r--drivers/input/tablet/wacom_wac.h13
-rw-r--r--drivers/input/touchscreen/Kconfig38
-rw-r--r--drivers/input/touchscreen/Makefile2
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c33
-rw-r--r--drivers/input/touchscreen/da9052_tsi.c370
-rw-r--r--drivers/input/touchscreen/dynapro.c17
-rw-r--r--drivers/input/touchscreen/elo.c17
-rw-r--r--drivers/input/touchscreen/fujitsu_ts.c13
-rw-r--r--drivers/input/touchscreen/gunze.c17
-rw-r--r--drivers/input/touchscreen/h3600_ts_input.c17
-rw-r--r--drivers/input/touchscreen/hampshire.c17
-rw-r--r--drivers/input/touchscreen/inexio.c17
-rw-r--r--drivers/input/touchscreen/lpc32xx_ts.c10
-rw-r--r--drivers/input/touchscreen/mtouch.c17
-rw-r--r--drivers/input/touchscreen/penmount.c17
-rw-r--r--drivers/input/touchscreen/st1232.c20
-rw-r--r--drivers/input/touchscreen/touchit213.c17
-rw-r--r--drivers/input/touchscreen/touchright.c17
-rw-r--r--drivers/input/touchscreen/touchwin.c17
-rw-r--r--drivers/input/touchscreen/tsc40.c12
-rw-r--r--drivers/input/touchscreen/usbtouchscreen.c77
-rw-r--r--drivers/input/touchscreen/wacom_i2c.c282
-rw-r--r--drivers/input/touchscreen/wacom_w8001.c13
-rw-r--r--drivers/iommu/Kconfig4
-rw-r--r--drivers/isdn/gigaset/bas-gigaset.c1
-rw-r--r--drivers/isdn/gigaset/usb-gigaset.c1
-rw-r--r--drivers/isdn/hardware/mISDN/hfcsusb.c1
-rw-r--r--drivers/isdn/hardware/mISDN/hfcsusb.h6
-rw-r--r--drivers/isdn/hisax/hfc_usb.c1
-rw-r--r--drivers/isdn/hisax/st5481_init.c1
-rw-r--r--drivers/isdn/i4l/isdn_common.c5
-rw-r--r--drivers/isdn/i4l/isdn_tty.c466
-rw-r--r--drivers/macintosh/Kconfig23
-rw-r--r--drivers/macintosh/Makefile14
-rw-r--r--drivers/macintosh/ams/ams-i2c.c2
-rw-r--r--drivers/macintosh/therm_adt746x.c480
-rw-r--r--drivers/macintosh/windfarm.h51
-rw-r--r--drivers/macintosh/windfarm_ad7417_sensor.c347
-rw-r--r--drivers/macintosh/windfarm_core.c23
-rw-r--r--drivers/macintosh/windfarm_cpufreq_clamp.c6
-rw-r--r--drivers/macintosh/windfarm_fcu_controls.c613
-rw-r--r--drivers/macintosh/windfarm_lm75_sensor.c135
-rw-r--r--drivers/macintosh/windfarm_lm87_sensor.c201
-rw-r--r--drivers/macintosh/windfarm_max6690_sensor.c109
-rw-r--r--drivers/macintosh/windfarm_mpu.h105
-rw-r--r--drivers/macintosh/windfarm_pm72.c847
-rw-r--r--drivers/macintosh/windfarm_pm81.c25
-rw-r--r--drivers/macintosh/windfarm_pm91.c33
-rw-r--r--drivers/macintosh/windfarm_rm31.c740
-rw-r--r--drivers/macintosh/windfarm_smu_controls.c1
-rw-r--r--drivers/macintosh/windfarm_smu_sat.c132
-rw-r--r--drivers/mca/Kconfig14
-rw-r--r--drivers/mca/Makefile7
-rw-r--r--drivers/mca/mca-bus.c169
-rw-r--r--drivers/mca/mca-device.c218
-rw-r--r--drivers/mca/mca-driver.c63
-rw-r--r--drivers/mca/mca-legacy.c329
-rw-r--r--drivers/mca/mca-proc.c249
-rw-r--r--drivers/md/bitmap.c1100
-rw-r--r--drivers/md/bitmap.h60
-rw-r--r--drivers/md/dm-raid.c22
-rw-r--r--drivers/md/md.c370
-rw-r--r--drivers/md/md.h12
-rw-r--r--drivers/md/raid1.c22
-rw-r--r--drivers/md/raid10.c1281
-rw-r--r--drivers/md/raid10.h34
-rw-r--r--drivers/md/raid5.c252
-rw-r--r--drivers/md/raid5.h7
-rw-r--r--drivers/media/common/saa7146_fops.c126
-rw-r--r--drivers/media/common/saa7146_hlp.c23
-rw-r--r--drivers/media/common/saa7146_vbi.c54
-rw-r--r--drivers/media/common/saa7146_video.c367
-rw-r--r--drivers/media/common/tuners/Kconfig27
-rw-r--r--drivers/media/common/tuners/Makefile4
-rw-r--r--drivers/media/common/tuners/fc0011.c524
-rw-r--r--drivers/media/common/tuners/fc0011.h41
-rw-r--r--drivers/media/common/tuners/fc0012-priv.h43
-rw-r--r--drivers/media/common/tuners/fc0012.c467
-rw-r--r--drivers/media/common/tuners/fc0012.h44
-rw-r--r--drivers/media/common/tuners/fc0013-priv.h44
-rw-r--r--drivers/media/common/tuners/fc0013.c634
-rw-r--r--drivers/media/common/tuners/fc0013.h57
-rw-r--r--drivers/media/common/tuners/fc001x-common.h (renamed from arch/arm/include/asm/hardware/ep7211.h)35
-rw-r--r--drivers/media/common/tuners/tua9001.c215
-rw-r--r--drivers/media/common/tuners/tua9001.h46
-rw-r--r--drivers/media/common/tuners/tua9001_priv.h34
-rw-r--r--drivers/media/common/tuners/xc5000.c7
-rw-r--r--drivers/media/common/tuners/xc5000.h2
-rw-r--r--drivers/media/dvb/bt8xx/dst_ca.c2
-rw-r--r--drivers/media/dvb/ddbridge/ddbridge-core.c3
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.c10
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.h2
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c80
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h18
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig13
-rw-r--r--drivers/media/dvb/dvb-usb/Makefile3
-rw-r--r--drivers/media/dvb/dvb-usb/af9015.c495
-rw-r--r--drivers/media/dvb/dvb-usb/af9035.c1242
-rw-r--r--drivers/media/dvb/dvb-usb/af9035.h113
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_core.c24
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_devices.c7
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h12
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-urb.c12
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb.h3
-rw-r--r--drivers/media/dvb/dvb-usb/dw2102.c76
-rw-r--r--drivers/media/dvb/dvb-usb/it913x.c4
-rw-r--r--drivers/media/dvb/dvb-usb/lmedm04.c5
-rw-r--r--drivers/media/dvb/dvb-usb/mxl111sf-tuner.c1
-rw-r--r--drivers/media/dvb/dvb-usb/mxl111sf.c850
-rw-r--r--drivers/media/dvb/dvb-usb/rtl28xxu.c28
-rw-r--r--drivers/media/dvb/frontends/Kconfig35
-rw-r--r--drivers/media/dvb/frontends/Makefile7
-rw-r--r--drivers/media/dvb/frontends/af9013.c13
-rw-r--r--drivers/media/dvb/frontends/af9033.c980
-rw-r--r--drivers/media/dvb/frontends/af9033.h75
-rw-r--r--drivers/media/dvb/frontends/af9033_priv.h470
-rw-r--r--drivers/media/dvb/frontends/au8522_common.c259
-rw-r--r--drivers/media/dvb/frontends/au8522_dig.c215
-rw-r--r--drivers/media/dvb/frontends/au8522_priv.h2
-rw-r--r--drivers/media/dvb/frontends/cx24110.c7
-rw-r--r--drivers/media/dvb/frontends/cxd2820r_core.c4
-rw-r--r--drivers/media/dvb/frontends/dib7000p.c5
-rw-r--r--drivers/media/dvb/frontends/dib9000.c131
-rw-r--r--drivers/media/dvb/frontends/drxd.h14
-rw-r--r--drivers/media/dvb/frontends/drxk_hard.c18
-rw-r--r--drivers/media/dvb/frontends/drxk_map.h2
-rw-r--r--drivers/media/dvb/frontends/ds3000.c5
-rw-r--r--drivers/media/dvb/frontends/it913x-fe.c26
-rw-r--r--drivers/media/dvb/frontends/lg2160.c1468
-rw-r--r--drivers/media/dvb/frontends/lg2160.h84
-rw-r--r--drivers/media/dvb/frontends/lgs8gxx.c3
-rw-r--r--drivers/media/dvb/frontends/m88rs2000.c29
-rw-r--r--drivers/media/dvb/frontends/rtl2830.c201
-rw-r--r--drivers/media/dvb/frontends/rtl2830_priv.h1
-rw-r--r--drivers/media/dvb/frontends/stb0899_drv.c8
-rw-r--r--drivers/media/dvb/frontends/stb6100.c3
-rw-r--r--drivers/media/dvb/frontends/stv0297.c2
-rw-r--r--drivers/media/dvb/frontends/stv0900_sw.c2
-rw-r--r--drivers/media/dvb/frontends/stv090x.c2
-rw-r--r--drivers/media/dvb/frontends/zl10353.c5
-rw-r--r--drivers/media/dvb/mantis/hopper_cards.c3
-rw-r--r--drivers/media/dvb/mantis/mantis_cards.c3
-rw-r--r--drivers/media/dvb/mantis/mantis_dma.c4
-rw-r--r--drivers/media/dvb/mantis/mantis_evm.c3
-rw-r--r--drivers/media/dvb/ngene/ngene-core.c4
-rw-r--r--drivers/media/dvb/pluto2/pluto2.c8
-rw-r--r--drivers/media/dvb/siano/smssdio.c4
-rw-r--r--drivers/media/dvb/siano/smsusb.c2
-rw-r--r--drivers/media/dvb/ttpci/av7110_v4l.c72
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c6
-rw-r--r--drivers/media/media-entity.c57
-rw-r--r--drivers/media/radio/Kconfig4
-rw-r--r--drivers/media/radio/dsbr100.c528
-rw-r--r--drivers/media/radio/radio-gemtek.c25
-rw-r--r--drivers/media/radio/radio-isa.c173
-rw-r--r--drivers/media/radio/radio-isa.h9
-rw-r--r--drivers/media/radio/radio-keene.c36
-rw-r--r--drivers/media/radio/radio-mr800.c524
-rw-r--r--drivers/media/radio/radio-rtrack2.c1
-rw-r--r--drivers/media/radio/radio-sf16fmi.c14
-rw-r--r--drivers/media/radio/radio-sf16fmr2.c144
-rw-r--r--drivers/media/radio/radio-timb.c2
-rw-r--r--drivers/media/radio/saa7706h.c2
-rw-r--r--drivers/media/radio/si470x/radio-si470x-common.c305
-rw-r--r--drivers/media/radio/si470x/radio-si470x-i2c.c65
-rw-r--r--drivers/media/radio/si470x/radio-si470x-usb.c265
-rw-r--r--drivers/media/radio/si470x/radio-si470x.h14
-rw-r--r--drivers/media/radio/tef6862.c2
-rw-r--r--drivers/media/radio/wl128x/fmdrv_v4l2.c4
-rw-r--r--drivers/media/rc/Kconfig1
-rw-r--r--drivers/media/rc/ati_remote.c146
-rw-r--r--drivers/media/rc/fintek-cir.c13
-rw-r--r--drivers/media/rc/imon.c2
-rw-r--r--drivers/media/rc/ir-raw.c8
-rw-r--r--drivers/media/rc/ir-sanyo-decoder.c4
-rw-r--r--drivers/media/rc/ite-cir.c14
-rw-r--r--drivers/media/rc/keymaps/Makefile3
-rw-r--r--drivers/media/rc/keymaps/rc-asus-ps3-100.c91
-rw-r--r--drivers/media/rc/keymaps/rc-it913x-v2.c2
-rw-r--r--drivers/media/rc/keymaps/rc-medion-x10-digitainer.c123
-rw-r--r--drivers/media/rc/keymaps/rc-medion-x10-or2x.c108
-rw-r--r--drivers/media/rc/mceusb.c5
-rw-r--r--drivers/media/rc/nuvoton-cir.c26
-rw-r--r--drivers/media/rc/rc-loopback.c1
-rw-r--r--drivers/media/rc/redrat3.c2
-rw-r--r--drivers/media/video/Kconfig48
-rw-r--r--drivers/media/video/Makefile5
-rw-r--r--drivers/media/video/adp1653.c9
-rw-r--r--drivers/media/video/adv7180.c417
-rw-r--r--drivers/media/video/adv7343.c4
-rw-r--r--drivers/media/video/aptina-pll.c5
-rw-r--r--drivers/media/video/arv.c7
-rw-r--r--drivers/media/video/as3645a.c10
-rw-r--r--drivers/media/video/atmel-isi.c18
-rw-r--r--drivers/media/video/au0828/Kconfig3
-rw-r--r--drivers/media/video/au0828/au0828-cards.c2
-rw-r--r--drivers/media/video/au0828/au0828-dvb.c27
-rw-r--r--drivers/media/video/au0828/au0828-video.c25
-rw-r--r--drivers/media/video/blackfin/bfin_capture.c4
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c4
-rw-r--r--drivers/media/video/bw-qcam.c132
-rw-r--r--drivers/media/video/c-qcam.c140
-rw-r--r--drivers/media/video/cpia2/cpia2.h34
-rw-r--r--drivers/media/video/cpia2/cpia2_core.c142
-rw-r--r--drivers/media/video/cpia2/cpia2_usb.c78
-rw-r--r--drivers/media/video/cpia2/cpia2_v4l.c850
-rw-r--r--drivers/media/video/cpia2/cpia2dev.h50
-rw-r--r--drivers/media/video/cx18/cx18-alsa-main.c1
-rw-r--r--drivers/media/video/cx18/cx18-alsa-pcm.c10
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c2
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.c6
-rw-r--r--drivers/media/video/cx18/cx18-streams.c3
-rw-r--r--drivers/media/video/cx231xx/cx231xx-417.c18
-rw-r--r--drivers/media/video/cx231xx/cx231xx-audio.c18
-rw-r--r--drivers/media/video/cx231xx/cx231xx-avcore.c148
-rw-r--r--drivers/media/video/cx231xx/cx231xx-core.c76
-rw-r--r--drivers/media/video/cx231xx/cx231xx-vbi.c6
-rw-r--r--drivers/media/video/cx231xx/cx231xx-video.c20
-rw-r--r--drivers/media/video/cx23885/cx23885-cards.c9
-rw-r--r--drivers/media/video/cx23885/cx23885-core.c7
-rw-r--r--drivers/media/video/cx23885/cx23885-dvb.c7
-rw-r--r--drivers/media/video/cx23885/cx23885.h1
-rw-r--r--drivers/media/video/cx23885/cx23888-ir.c4
-rw-r--r--drivers/media/video/cx25821/cx25821-alsa.c2
-rw-r--r--drivers/media/video/cx25821/cx25821-audio-upstream.c3
-rw-r--r--drivers/media/video/cx25821/cx25821-core.c14
-rw-r--r--drivers/media/video/cx25821/cx25821-i2c.c3
-rw-r--r--drivers/media/video/cx25821/cx25821-medusa-video.c13
-rw-r--r--drivers/media/video/cx25821/cx25821-video-upstream-ch2.c3
-rw-r--r--drivers/media/video/cx25821/cx25821-video-upstream.c3
-rw-r--r--drivers/media/video/cx25821/cx25821-video.c25
-rw-r--r--drivers/media/video/cx25821/cx25821-video.h2
-rw-r--r--drivers/media/video/cx25840/cx25840-ir.c6
-rw-r--r--drivers/media/video/davinci/Kconfig1
-rw-r--r--drivers/media/video/davinci/vpbe_display.c4
-rw-r--r--drivers/media/video/davinci/vpfe_capture.c2
-rw-r--r--drivers/media/video/davinci/vpif_capture.c4
-rw-r--r--drivers/media/video/davinci/vpif_display.c4
-rw-r--r--drivers/media/video/em28xx/Kconfig4
-rw-r--r--drivers/media/video/em28xx/Makefile5
-rw-r--r--drivers/media/video/em28xx/em28xx-audio.c11
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c81
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c30
-rw-r--r--drivers/media/video/em28xx/em28xx-dvb.c11
-rw-r--r--drivers/media/video/em28xx/em28xx-i2c.c3
-rw-r--r--drivers/media/video/em28xx/em28xx-input.c250
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c13
-rw-r--r--drivers/media/video/em28xx/em28xx.h60
-rw-r--r--drivers/media/video/et61x251/Kconfig18
-rw-r--r--drivers/media/video/et61x251/Makefile4
-rw-r--r--drivers/media/video/et61x251/et61x251.h213
-rw-r--r--drivers/media/video/et61x251/et61x251_core.c2683
-rw-r--r--drivers/media/video/et61x251/et61x251_sensor.h108
-rw-r--r--drivers/media/video/et61x251/et61x251_tas5130d1b.c143
-rw-r--r--drivers/media/video/fsl-viu.c4
-rw-r--r--drivers/media/video/gspca/Makefile2
-rw-r--r--drivers/media/video/gspca/autogain_functions.c178
-rw-r--r--drivers/media/video/gspca/autogain_functions.h6
-rw-r--r--drivers/media/video/gspca/conex.c4
-rw-r--r--drivers/media/video/gspca/finepix.c18
-rw-r--r--drivers/media/video/gspca/gl860/gl860.c3
-rw-r--r--drivers/media/video/gspca/gspca.c545
-rw-r--r--drivers/media/video/gspca/gspca.h26
-rw-r--r--drivers/media/video/gspca/jl2005bcd.c10
-rw-r--r--drivers/media/video/gspca/mars.c292
-rw-r--r--drivers/media/video/gspca/nw80x.c2
-rw-r--r--drivers/media/video/gspca/ov519.c10
-rw-r--r--drivers/media/video/gspca/ov534.c146
-rw-r--r--drivers/media/video/gspca/ov534_9.c2
-rw-r--r--drivers/media/video/gspca/pac207.c336
-rw-r--r--drivers/media/video/gspca/pac7302.c185
-rw-r--r--drivers/media/video/gspca/pac7311.c505
-rw-r--r--drivers/media/video/gspca/sn9c20x.c594
-rw-r--r--drivers/media/video/gspca/sonixb.c2
-rw-r--r--drivers/media/video/gspca/sonixj.c5
-rw-r--r--drivers/media/video/gspca/sq905.c12
-rw-r--r--drivers/media/video/gspca/sq905c.c10
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx.c21
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx.h3
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c143
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h7
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c359
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h12
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_sensor.h4
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_st6422.c236
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_st6422.h4
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c198
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h8
-rw-r--r--drivers/media/video/gspca/topro.c6
-rw-r--r--drivers/media/video/gspca/vicam.c13
-rw-r--r--drivers/media/video/gspca/zc3xx.c620
-rw-r--r--drivers/media/video/hdpvr/hdpvr-control.c2
-rw-r--r--drivers/media/video/hdpvr/hdpvr-core.c4
-rw-r--r--drivers/media/video/hdpvr/hdpvr-video.c2
-rw-r--r--drivers/media/video/hexium_gemini.c129
-rw-r--r--drivers/media/video/hexium_orion.c24
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c4
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.c6
-rw-r--r--drivers/media/video/ivtv/ivtv-ioctl.c8
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c4
-rw-r--r--drivers/media/video/ivtv/ivtvfb.c2
-rw-r--r--drivers/media/video/m5mols/m5mols.h81
-rw-r--r--drivers/media/video/m5mols/m5mols_capture.c11
-rw-r--r--drivers/media/video/m5mols/m5mols_controls.c479
-rw-r--r--drivers/media/video/m5mols/m5mols_core.c93
-rw-r--r--drivers/media/video/m5mols/m5mols_reg.h1
-rw-r--r--drivers/media/video/marvell-ccic/mcam-core.c1
-rw-r--r--drivers/media/video/mem2mem_testdev.c6
-rw-r--r--drivers/media/video/meye.c2
-rw-r--r--drivers/media/video/msp3400-driver.c15
-rw-r--r--drivers/media/video/mt9m032.c4
-rw-r--r--drivers/media/video/mt9p031.c161
-rw-r--r--drivers/media/video/mt9t112.c1
-rw-r--r--drivers/media/video/mt9v032.c2
-rw-r--r--drivers/media/video/mx1_camera.c14
-rw-r--r--drivers/media/video/mx2_camera.c78
-rw-r--r--drivers/media/video/mx2_emmaprp.c8
-rw-r--r--drivers/media/video/mx3_camera.c41
-rw-r--r--drivers/media/video/mxb.c351
-rw-r--r--drivers/media/video/mxb.h42
-rw-r--r--drivers/media/video/omap1_camera.c22
-rw-r--r--drivers/media/video/omap24xxcam-dma.c20
-rw-r--r--drivers/media/video/omap24xxcam.c3
-rw-r--r--drivers/media/video/omap24xxcam.h14
-rw-r--r--drivers/media/video/omap3isp/isp.c59
-rw-r--r--drivers/media/video/omap3isp/isp.h8
-rw-r--r--drivers/media/video/omap3isp/ispccdc.c256
-rw-r--r--drivers/media/video/omap3isp/ispccdc.h12
-rw-r--r--drivers/media/video/omap3isp/ispccp2.c24
-rw-r--r--drivers/media/video/omap3isp/ispcsi2.c21
-rw-r--r--drivers/media/video/omap3isp/ispcsi2.h1
-rw-r--r--drivers/media/video/omap3isp/ispcsiphy.c4
-rw-r--r--drivers/media/video/omap3isp/ispcsiphy.h15
-rw-r--r--drivers/media/video/omap3isp/isppreview.c634
-rw-r--r--drivers/media/video/omap3isp/isppreview.h76
-rw-r--r--drivers/media/video/omap3isp/ispqueue.h2
-rw-r--r--drivers/media/video/omap3isp/ispresizer.c139
-rw-r--r--drivers/media/video/omap3isp/ispstat.c2
-rw-r--r--drivers/media/video/omap3isp/ispvideo.c303
-rw-r--r--drivers/media/video/omap3isp/ispvideo.h5
-rw-r--r--drivers/media/video/ov5642.c2
-rw-r--r--drivers/media/video/pms.c239
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h6
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c193
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.h9
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-v4l2.c1341
-rw-r--r--drivers/media/video/pwc/pwc-if.c191
-rw-r--r--drivers/media/video/pwc/pwc-v4l.c145
-rw-r--r--drivers/media/video/pwc/pwc.h21
-rw-r--r--drivers/media/video/pxa_camera.c15
-rw-r--r--drivers/media/video/s2255drv.c11
-rw-r--r--drivers/media/video/s5p-fimc/Kconfig48
-rw-r--r--drivers/media/video/s5p-fimc/Makefile6
-rw-r--r--drivers/media/video/s5p-fimc/fimc-capture.c506
-rw-r--r--drivers/media/video/s5p-fimc/fimc-core.c1159
-rw-r--r--drivers/media/video/s5p-fimc/fimc-core.h272
-rw-r--r--drivers/media/video/s5p-fimc/fimc-lite-reg.c300
-rw-r--r--drivers/media/video/s5p-fimc/fimc-lite-reg.h150
-rw-r--r--drivers/media/video/s5p-fimc/fimc-lite.c1576
-rw-r--r--drivers/media/video/s5p-fimc/fimc-lite.h213
-rw-r--r--drivers/media/video/s5p-fimc/fimc-m2m.c824
-rw-r--r--drivers/media/video/s5p-fimc/fimc-mdevice.c476
-rw-r--r--drivers/media/video/s5p-fimc/fimc-mdevice.h18
-rw-r--r--drivers/media/video/s5p-fimc/fimc-reg.c616
-rw-r--r--drivers/media/video/s5p-fimc/fimc-reg.h326
-rw-r--r--drivers/media/video/s5p-fimc/mipi-csis.c21
-rw-r--r--drivers/media/video/s5p-fimc/regs-fimc.h301
-rw-r--r--drivers/media/video/s5p-g2d/g2d.c69
-rw-r--r--drivers/media/video/s5p-g2d/g2d.h1
-rw-r--r--drivers/media/video/s5p-jpeg/jpeg-core.c68
-rw-r--r--drivers/media/video/s5p-jpeg/jpeg-core.h2
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc.c81
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc_common.h2
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c16
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc_enc.c6
-rw-r--r--drivers/media/video/s5p-mfc/s5p_mfc_opr.c28
-rw-r--r--drivers/media/video/s5p-tv/hdmi_drv.c480
-rw-r--r--drivers/media/video/s5p-tv/hdmiphy_drv.c225
-rw-r--r--drivers/media/video/s5p-tv/mixer.h3
-rw-r--r--drivers/media/video/s5p-tv/mixer_drv.c2
-rw-r--r--drivers/media/video/s5p-tv/mixer_reg.c15
-rw-r--r--drivers/media/video/s5p-tv/mixer_video.c10
-rw-r--r--drivers/media/video/s5p-tv/regs-hdmi.h1
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c45
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c39
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c7
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c2
-rw-r--r--drivers/media/video/saa7134/saa7134.h1
-rw-r--r--drivers/media/video/saa7164/saa7164-vbi.c4
-rw-r--r--drivers/media/video/saa7164/saa7164.h5
-rw-r--r--drivers/media/video/sh_mobile_ceu_camera.c92
-rw-r--r--drivers/media/video/sh_vou.c4
-rw-r--r--drivers/media/video/smiapp-pll.c418
-rw-r--r--drivers/media/video/smiapp-pll.h103
-rw-r--r--drivers/media/video/smiapp/Kconfig6
-rw-r--r--drivers/media/video/smiapp/Makefile5
-rw-r--r--drivers/media/video/smiapp/smiapp-core.c2894
-rw-r--r--drivers/media/video/smiapp/smiapp-limits.c132
-rw-r--r--drivers/media/video/smiapp/smiapp-limits.h128
-rw-r--r--drivers/media/video/smiapp/smiapp-quirk.c306
-rw-r--r--drivers/media/video/smiapp/smiapp-quirk.h83
-rw-r--r--drivers/media/video/smiapp/smiapp-reg-defs.h503
-rw-r--r--drivers/media/video/smiapp/smiapp-reg.h122
-rw-r--r--drivers/media/video/smiapp/smiapp-regs.c273
-rw-r--r--drivers/media/video/smiapp/smiapp-regs.h49
-rw-r--r--drivers/media/video/smiapp/smiapp.h252
-rw-r--r--drivers/media/video/sn9c102/sn9c102_core.c4
-rw-r--r--drivers/media/video/soc_camera.c55
-rw-r--r--drivers/media/video/soc_mediabus.c54
-rw-r--r--drivers/media/video/sta2x11_vip.c1550
-rw-r--r--drivers/media/video/sta2x11_vip.h40
-rw-r--r--drivers/media/video/stk-webcam.c8
-rw-r--r--drivers/media/video/tda9840.c75
-rw-r--r--drivers/media/video/tlg2300/pd-video.c1
-rw-r--r--drivers/media/video/tm6000/tm6000-input.c3
-rw-r--r--drivers/media/video/tm6000/tm6000-stds.c2
-rw-r--r--drivers/media/video/tm6000/tm6000-video.c14
-rw-r--r--drivers/media/video/tm6000/tm6000.h2
-rw-r--r--drivers/media/video/tuner-core.c15
-rw-r--r--drivers/media/video/tvp5150.c11
-rw-r--r--drivers/media/video/tvp7002.c105
-rw-r--r--drivers/media/video/usbvision/usbvision-core.c12
-rw-r--r--drivers/media/video/usbvision/usbvision-video.c4
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c330
-rw-r--r--drivers/media/video/uvc/uvc_queue.c43
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c50
-rw-r--r--drivers/media/video/uvc/uvcvideo.h26
-rw-r--r--drivers/media/video/v4l2-compat-ioctl32.c15
-rw-r--r--drivers/media/video/v4l2-ctrls.c302
-rw-r--r--drivers/media/video/v4l2-dev.c218
-rw-r--r--drivers/media/video/v4l2-event.c71
-rw-r--r--drivers/media/video/v4l2-ioctl.c662
-rw-r--r--drivers/media/video/v4l2-subdev.c143
-rw-r--r--drivers/media/video/via-camera.c15
-rw-r--r--drivers/media/video/videobuf-core.c3
-rw-r--r--drivers/media/video/videobuf-dma-contig.c199
-rw-r--r--drivers/media/video/videobuf-dvb.c3
-rw-r--r--drivers/media/video/videobuf2-core.c50
-rw-r--r--drivers/media/video/vivi.c223
-rw-r--r--drivers/media/video/w9966.c94
-rw-r--r--drivers/media/video/zoran/zoran_device.c2
-rw-r--r--drivers/media/video/zoran/zoran_driver.c20
-rw-r--r--drivers/media/video/zr364xx.c2
-rw-r--r--drivers/memory/Kconfig43
-rw-r--r--drivers/memory/Makefile7
-rw-r--r--drivers/memory/emif.c1670
-rw-r--r--drivers/memory/emif.h589
-rw-r--r--drivers/memory/tegra20-mc.c257
-rw-r--r--drivers/memory/tegra30-mc.c382
-rw-r--r--drivers/message/i2o/i2o_proc.c13
-rw-r--r--drivers/mfd/Kconfig36
-rw-r--r--drivers/mfd/Makefile3
-rw-r--r--drivers/mfd/ab5500-core.c1439
-rw-r--r--drivers/mfd/ab5500-debugfs.c807
-rw-r--r--drivers/mfd/ab5500-debugfs.h22
-rw-r--r--drivers/mfd/db5500-prcmu.c451
-rw-r--r--drivers/mfd/mc13xxx-core.c3
-rw-r--r--drivers/mfd/tps65911-comparator.c2
-rw-r--r--drivers/misc/Kconfig35
-rw-r--r--drivers/misc/Makefile4
-rw-r--r--drivers/misc/ad525x_dpot.c2
-rw-r--r--drivers/misc/bh1780gli.c2
-rw-r--r--drivers/misc/bmp085-i2c.c91
-rw-r--r--drivers/misc/bmp085-spi.c91
-rw-r--r--drivers/misc/bmp085.c356
-rw-r--r--drivers/misc/bmp085.h33
-rw-r--r--drivers/misc/c2port/Kconfig6
-rw-r--r--drivers/misc/eeprom/at25.c19
-rw-r--r--drivers/misc/mei/Kconfig (renamed from drivers/staging/mei/Kconfig)0
-rw-r--r--drivers/misc/mei/Makefile (renamed from drivers/staging/mei/Makefile)0
-rw-r--r--drivers/misc/mei/hw.h (renamed from drivers/staging/mei/hw.h)0
-rw-r--r--drivers/misc/mei/init.c (renamed from drivers/staging/mei/init.c)4
-rw-r--r--drivers/misc/mei/interface.c (renamed from drivers/staging/mei/interface.c)2
-rw-r--r--drivers/misc/mei/interface.h (renamed from drivers/staging/mei/interface.h)5
-rw-r--r--drivers/misc/mei/interrupt.c (renamed from drivers/staging/mei/interrupt.c)2
-rw-r--r--drivers/misc/mei/iorw.c (renamed from drivers/staging/mei/iorw.c)2
-rw-r--r--drivers/misc/mei/main.c (renamed from drivers/staging/mei/main.c)41
-rw-r--r--drivers/misc/mei/mei_dev.h (renamed from drivers/staging/mei/mei_dev.h)2
-rw-r--r--drivers/misc/mei/wd.c (renamed from drivers/staging/mei/wd.c)76
-rw-r--r--drivers/misc/pch_phub.c4
-rw-r--r--drivers/misc/pti.c2
-rw-r--r--drivers/mmc/host/mxs-mmc.c8
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c9
-rw-r--r--drivers/mmc/host/sdhci-tegra.c24
-rw-r--r--drivers/mtd/devices/docg3.c16
-rw-r--r--drivers/mtd/nand/autcpu12.c10
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.c9
-rw-r--r--drivers/mtd/nand/h1910.c2
-rw-r--r--drivers/mtd/nand/orion_nand.c47
-rw-r--r--drivers/mtd/ubi/Kconfig8
-rw-r--r--drivers/mtd/ubi/Makefile5
-rw-r--r--drivers/mtd/ubi/attach.c (renamed from drivers/mtd/ubi/scan.c)970
-rw-r--r--drivers/mtd/ubi/build.c85
-rw-r--r--drivers/mtd/ubi/cdev.c36
-rw-r--r--drivers/mtd/ubi/debug.c137
-rw-r--r--drivers/mtd/ubi/debug.h98
-rw-r--r--drivers/mtd/ubi/eba.c68
-rw-r--r--drivers/mtd/ubi/gluebi.c2
-rw-r--r--drivers/mtd/ubi/io.c211
-rw-r--r--drivers/mtd/ubi/kapi.c61
-rw-r--r--drivers/mtd/ubi/scan.h174
-rw-r--r--drivers/mtd/ubi/ubi-media.h8
-rw-r--r--drivers/mtd/ubi/ubi.h179
-rw-r--r--drivers/mtd/ubi/upd.c16
-rw-r--r--drivers/mtd/ubi/vmt.c62
-rw-r--r--drivers/mtd/ubi/vtbl.c228
-rw-r--r--drivers/mtd/ubi/wl.c260
-rw-r--r--drivers/net/can/flexcan.c6
-rw-r--r--drivers/net/can/sja1000/Kconfig2
-rw-r--r--drivers/net/ethernet/3com/typhoon.c3
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c3
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.c4
-rw-r--r--drivers/net/ethernet/freescale/fec.c9
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c2
-rw-r--r--drivers/net/ethernet/nxp/lpc_eth.c71
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c3
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c3
-rw-r--r--drivers/net/ethernet/realtek/r8169.c2
-rw-r--r--drivers/net/ethernet/s6gmac.c4
-rw-r--r--drivers/net/ethernet/tehuti/tehuti.c4
-rw-r--r--drivers/net/irda/Kconfig6
-rw-r--r--drivers/net/irda/irda-usb.c2
-rw-r--r--drivers/net/irda/kingsun-sir.c42
-rw-r--r--drivers/net/irda/ks959-sir.c31
-rw-r--r--drivers/net/irda/ksdazzle-sir.c46
-rw-r--r--drivers/net/irda/stir4200.c6
-rw-r--r--drivers/net/usb/asix.c1
-rw-r--r--drivers/net/usb/catc.c26
-rw-r--r--drivers/net/usb/cdc-phonet.c1
-rw-r--r--drivers/net/usb/cdc_eem.c1
-rw-r--r--drivers/net/usb/cdc_ether.c1
-rw-r--r--drivers/net/usb/cdc_ncm.c1
-rw-r--r--drivers/net/usb/cdc_subset.c1
-rw-r--r--drivers/net/usb/cx82310_eth.c1
-rw-r--r--drivers/net/usb/dm9601.c1
-rw-r--r--drivers/net/usb/gl620a.c1
-rw-r--r--drivers/net/usb/hso.c106
-rw-r--r--drivers/net/usb/int51x1.c1
-rw-r--r--drivers/net/usb/ipheth.c35
-rw-r--r--drivers/net/usb/kalmia.c3
-rw-r--r--drivers/net/usb/kaweth.c64
-rw-r--r--drivers/net/usb/lg-vl600.c1
-rw-r--r--drivers/net/usb/mcs7830.c1
-rw-r--r--drivers/net/usb/net1080.c1
-rw-r--r--drivers/net/usb/pegasus.c1
-rw-r--r--drivers/net/usb/plusb.c1
-rw-r--r--drivers/net/usb/qmi_wwan.c1
-rw-r--r--drivers/net/usb/rndis_host.c1
-rw-r--r--drivers/net/usb/rtl8150.c18
-rw-r--r--drivers/net/usb/sierra_net.c1
-rw-r--r--drivers/net/usb/smsc75xx.c1
-rw-r--r--drivers/net/usb/smsc95xx.c1
-rw-r--r--drivers/net/usb/zaurus.c1
-rw-r--r--drivers/net/wan/Kconfig31
-rw-r--r--drivers/net/wan/Makefile5
-rw-r--r--drivers/net/wireless/at76c50x-usb.c3
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c238
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.h2
-rw-r--r--drivers/net/wireless/ath/ath6kl/core.h33
-rw-r--r--drivers/net/wireless/ath/ath6kl/debug.c12
-rw-r--r--drivers/net/wireless/ath/ath6kl/htc_mbox.c45
-rw-r--r--drivers/net/wireless/ath/ath6kl/htc_pipe.c11
-rw-r--r--drivers/net/wireless/ath/ath6kl/init.c29
-rw-r--r--drivers/net/wireless/ath/ath6kl/main.c104
-rw-r--r--drivers/net/wireless/ath/ath6kl/sdio.c17
-rw-r--r--drivers/net/wireless/ath/ath6kl/txrx.c12
-rw-r--r--drivers/net/wireless/ath/ath6kl/usb.c13
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.c94
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.h24
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_calib.c50
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_mci.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_rtt.c84
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_rtt.h5
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c9
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h9
-rw-r--r--drivers/net/wireless/ath/carl9170/usb.c1
-rw-r--r--drivers/net/wireless/b43/bus.c6
-rw-r--r--drivers/net/wireless/b43/dma.c2
-rw-r--r--drivers/net/wireless/b43/main.c4
-rw-r--r--drivers/net/wireless/b43legacy/main.c4
-rw-r--r--drivers/net/wireless/b43legacy/phy.c4
-rw-r--r--drivers/net/wireless/b43legacy/radio.c10
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c244
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c32
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c350
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c265
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h37
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/usb.c3
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/Makefile3
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/aiutils.c479
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/aiutils.h24
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/antsel.c16
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/channel.c7
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c11
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/main.c142
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/nicpci.c826
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/nicpci.h77
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/otp.c410
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/otp.h36
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c67
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c333
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy_shim.c9
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h3
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/pub.h228
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/srom.c980
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/srom.h29
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/stf.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-lib.c35
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rxon.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c19
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-mac80211.c5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.c8
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c52
-rw-r--r--drivers/net/wireless/libertas/if_usb.c1
-rw-r--r--drivers/net/wireless/libertas_tf/if_usb.c1
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c5
-rw-r--r--drivers/net/wireless/mwifiex/Makefile2
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c498
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.h2
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c21
-rw-r--r--drivers/net/wireless/mwifiex/decl.h13
-rw-r--r--drivers/net/wireless/mwifiex/fw.h159
-rw-r--r--drivers/net/wireless/mwifiex/ie.c396
-rw-r--r--drivers/net/wireless/mwifiex/init.c1
-rw-r--r--drivers/net/wireless/mwifiex/ioctl.h32
-rw-r--r--drivers/net/wireless/mwifiex/join.c26
-rw-r--r--drivers/net/wireless/mwifiex/main.c57
-rw-r--r--drivers/net/wireless/mwifiex/main.h26
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmd.c69
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmdresp.c8
-rw-r--r--drivers/net/wireless/mwifiex/sta_event.c51
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c9
-rw-r--r--drivers/net/wireless/mwifiex/uap_cmd.c432
-rw-r--r--drivers/net/wireless/mwifiex/wmm.c4
-rw-r--r--drivers/net/wireless/orinoco/orinoco_usb.c1
-rw-r--r--drivers/net/wireless/p54/p54usb.c1
-rw-r--r--drivers/net/wireless/rndis_wlan.c15
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c1
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187/dev.c1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/sw.c1
-rw-r--r--drivers/net/wireless/ti/wl12xx/Kconfig1
-rw-r--r--drivers/net/wireless/ti/wlcore/Kconfig2
-rw-r--r--drivers/net/wireless/ti/wlcore/acx.c80
-rw-r--r--drivers/net/wireless/ti/wlcore/acx.h30
-rw-r--r--drivers/net/wireless/ti/wlcore/boot.c3
-rw-r--r--drivers/net/wireless/ti/wlcore/cmd.c8
-rw-r--r--drivers/net/wireless/ti/wlcore/event.c29
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c323
-rw-r--r--drivers/net/wireless/ti/wlcore/rx.c36
-rw-r--r--drivers/net/wireless/ti/wlcore/rx.h4
-rw-r--r--drivers/net/wireless/ti/wlcore/wl12xx.h41
-rw-r--r--drivers/net/wireless/ti/wlcore/wlcore.h6
-rw-r--r--drivers/net/wireless/zd1201.c1
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c1
-rw-r--r--drivers/net/xen-netfront.c6
-rw-r--r--drivers/nfc/Kconfig13
-rw-r--r--drivers/nfc/Makefile1
-rw-r--r--drivers/nfc/pn533.c19
-rw-r--r--drivers/nfc/pn544_hci.c947
-rw-r--r--drivers/of/Kconfig12
-rw-r--r--drivers/of/Makefile2
-rw-r--r--drivers/of/address.c1
-rw-r--r--drivers/of/of_spi.c99
-rw-r--r--drivers/parisc/superio.c2
-rw-r--r--drivers/parport/parport_amiga.c36
-rw-r--r--drivers/parport/parport_atari.c9
-rw-r--r--drivers/parport/parport_mfc3.c35
-rw-r--r--drivers/parport/parport_pc.c292
-rw-r--r--drivers/parport/parport_sunbpp.c21
-rw-r--r--drivers/pci/pci-sysfs.c5
-rw-r--r--drivers/pcmcia/Kconfig2
-rw-r--r--drivers/pcmcia/Makefile1
-rw-r--r--drivers/pcmcia/pxa2xx_hx4700.c121
-rw-r--r--drivers/pinctrl/Kconfig12
-rw-r--r--drivers/pinctrl/Makefile4
-rw-r--r--drivers/pinctrl/pinctrl-nomadik-db8500.c857
-rw-r--r--drivers/pinctrl/pinctrl-nomadik.c (renamed from drivers/gpio/gpio-nomadik.c)857
-rw-r--r--drivers/pinctrl/pinctrl-nomadik.h77
-rw-r--r--drivers/pinctrl/pinctrl-tegra.c236
-rw-r--r--drivers/pinctrl/pinctrl-tegra.h23
-rw-r--r--drivers/pinctrl/pinctrl-tegra20.c40
-rw-r--r--drivers/pinctrl/pinctrl-tegra30.c40
-rw-r--r--drivers/pinctrl/spear/Kconfig34
-rw-r--r--drivers/pinctrl/spear/Makefile7
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear.c354
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear.h142
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear300.c708
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear310.c431
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear320.c3468
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear3xx.c588
-rw-r--r--drivers/pinctrl/spear/pinctrl-spear3xx.h92
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c2
-rw-r--r--drivers/power/bq27x00_battery.c2
-rw-r--r--drivers/ps3/ps3av.c24
-rw-r--r--drivers/ptp/Kconfig2
-rw-r--r--drivers/regulator/tps65910-regulator.c20
-rw-r--r--drivers/remoteproc/remoteproc_core.c3
-rw-r--r--drivers/rtc/Kconfig2
-rw-r--r--drivers/s390/char/con3215.c142
-rw-r--r--drivers/s390/char/keyboard.c30
-rw-r--r--drivers/s390/char/keyboard.h14
-rw-r--r--drivers/s390/char/sclp_tty.c33
-rw-r--r--drivers/s390/char/sclp_vt220.c33
-rw-r--r--drivers/s390/char/tty3270.c121
-rw-r--r--drivers/scsi/Kconfig83
-rw-r--r--drivers/scsi/Makefile2
-rw-r--r--drivers/scsi/aha1542.c66
-rw-r--r--drivers/scsi/aic94xx/aic94xx_seq.c3
-rw-r--r--drivers/scsi/esp_scsi.c2
-rw-r--r--drivers/scsi/fd_mcs.c1354
-rw-r--r--drivers/scsi/ibmmca.c2379
-rw-r--r--drivers/scsi/qla1280.c7
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c3
-rw-r--r--drivers/scsi/scsi_error.c6
-rw-r--r--drivers/scsi/sim710.c124
-rw-r--r--drivers/sh/clk/cpg.c77
-rw-r--r--drivers/sh/intc/dynamic.c8
-rw-r--r--drivers/spi/spi-ath79.c3
-rw-r--r--drivers/spi/spi-coldfire-qspi.c255
-rw-r--r--drivers/spi/spi-dw-pci.c13
-rw-r--r--drivers/spi/spi-ep93xx.c37
-rw-r--r--drivers/spi/spi-fsl-espi.c1
-rw-r--r--drivers/spi/spi-fsl-lib.c2
-rw-r--r--drivers/spi/spi-fsl-spi.c2
-rw-r--r--drivers/spi/spi-imx.c8
-rw-r--r--drivers/spi/spi-lm70llp.c3
-rw-r--r--drivers/spi/spi-mpc52xx.c3
-rw-r--r--drivers/spi/spi-omap2-mcspi.c373
-rw-r--r--drivers/spi/spi-ppc4xx.c4
-rw-r--r--drivers/spi/spi-pxa2xx-pci.c12
-rw-r--r--drivers/spi/spi-rspi.c320
-rw-r--r--drivers/spi/spi-sirf.c20
-rw-r--r--drivers/spi/spi-topcliff-pch.c3
-rw-r--r--drivers/spi/spi.c98
-rw-r--r--drivers/ssb/b43_pci_bridge.c2
-rw-r--r--drivers/ssb/pci.c88
-rw-r--r--drivers/staging/Kconfig16
-rw-r--r--drivers/staging/Makefile7
-rw-r--r--drivers/staging/android/Kconfig33
-rw-r--r--drivers/staging/android/Makefile3
-rw-r--r--drivers/staging/android/alarm-dev.c137
-rw-r--r--drivers/staging/android/alarm.c601
-rw-r--r--drivers/staging/android/android_alarm.h59
-rw-r--r--drivers/staging/android/ashmem.c2
-rw-r--r--drivers/staging/android/binder.h10
-rw-r--r--drivers/staging/android/logger.c113
-rw-r--r--drivers/staging/android/ram_console.c2
-rw-r--r--drivers/staging/android/switch/Kconfig11
-rw-r--r--drivers/staging/android/switch/Makefile4
-rw-r--r--drivers/staging/android/switch/switch.h53
-rw-r--r--drivers/staging/android/switch/switch_class.c174
-rw-r--r--drivers/staging/android/switch/switch_gpio.c172
-rw-r--r--drivers/staging/android/timed_output.c1
-rw-r--r--drivers/staging/asus_oled/asus_oled.c6
-rw-r--r--drivers/staging/bcm/Adapter.h883
-rw-r--r--drivers/staging/bcm/DDRInit.c26
-rw-r--r--drivers/staging/bcm/IPv6Protocol.c409
-rw-r--r--drivers/staging/bcm/Misc.c2
-rw-r--r--drivers/staging/ccg/Kconfig20
-rw-r--r--drivers/staging/ccg/Makefile4
-rw-r--r--drivers/staging/ccg/TODO6
-rw-r--r--drivers/staging/ccg/ccg.c1299
-rw-r--r--drivers/staging/ccg/sysfs-class-ccg_usb158
-rw-r--r--drivers/staging/comedi/Kconfig253
-rw-r--r--drivers/staging/comedi/comedi.h2
-rw-r--r--drivers/staging/comedi/comedi_fops.c729
-rw-r--r--drivers/staging/comedi/comedidev.h72
-rw-r--r--drivers/staging/comedi/drivers.c326
-rw-r--r--drivers/staging/comedi/drivers/8255.c73
-rw-r--r--drivers/staging/comedi/drivers/acl7225b.c55
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_common.c3556
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_common.h145
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c18
-rw-r--r--drivers/staging/comedi/drivers/adl_pci6208.c263
-rw-r--r--drivers/staging/comedi/drivers/adl_pci7230.c133
-rw-r--r--drivers/staging/comedi/drivers/adl_pci7296.c77
-rw-r--r--drivers/staging/comedi/drivers/adl_pci7432.c149
-rw-r--r--drivers/staging/comedi/drivers/adl_pci8164.c301
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9111.c106
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9118.c182
-rw-r--r--drivers/staging/comedi/drivers/adq12b.c250
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1710.c223
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1723.c103
-rw-r--r--drivers/staging/comedi/drivers/adv_pci_dio.c130
-rw-r--r--drivers/staging/comedi/drivers/aio_aio12_8.c33
-rw-r--r--drivers/staging/comedi/drivers/aio_iiro_16.c113
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200.c99
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc236.c85
-rw-r--r--drivers/staging/comedi/drivers/amplc_pc263.c87
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci224.c256
-rw-r--r--drivers/staging/comedi/drivers/amplc_pci230.c120
-rw-r--r--drivers/staging/comedi/drivers/c6xdigio.c44
-rw-r--r--drivers/staging/comedi/drivers/cb_das16_cs.c9
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas.c109
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas64.c142
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidda.c175
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidio.c131
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdas.c123
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdda.c132
-rw-r--r--drivers/staging/comedi/drivers/comedi_bond.c216
-rw-r--r--drivers/staging/comedi/drivers/comedi_parport.c38
-rw-r--r--drivers/staging/comedi/drivers/comedi_test.c373
-rw-r--r--drivers/staging/comedi/drivers/contec_pci_dio.c163
-rw-r--r--drivers/staging/comedi/drivers/daqboard2000.c87
-rw-r--r--drivers/staging/comedi/drivers/das08.c132
-rw-r--r--drivers/staging/comedi/drivers/das08.h2
-rw-r--r--drivers/staging/comedi/drivers/das16.c891
-rw-r--r--drivers/staging/comedi/drivers/das16m1.c219
-rw-r--r--drivers/staging/comedi/drivers/das1800.c61
-rw-r--r--drivers/staging/comedi/drivers/das6402.c68
-rw-r--r--drivers/staging/comedi/drivers/das800.c8
-rw-r--r--drivers/staging/comedi/drivers/dmm32at.c15
-rw-r--r--drivers/staging/comedi/drivers/dt2801.c283
-rw-r--r--drivers/staging/comedi/drivers/dt2811.c309
-rw-r--r--drivers/staging/comedi/drivers/dt2814.c116
-rw-r--r--drivers/staging/comedi/drivers/dt2815.c42
-rw-r--r--drivers/staging/comedi/drivers/dt2817.c37
-rw-r--r--drivers/staging/comedi/drivers/dt282x.c397
-rw-r--r--drivers/staging/comedi/drivers/dt3000.c234
-rw-r--r--drivers/staging/comedi/drivers/dt9812.c43
-rw-r--r--drivers/staging/comedi/drivers/dyna_pci10xx.c79
-rw-r--r--drivers/staging/comedi/drivers/fl512.c47
-rw-r--r--drivers/staging/comedi/drivers/gsc_hpdi.c98
-rw-r--r--drivers/staging/comedi/drivers/icp_multi.c289
-rw-r--r--drivers/staging/comedi/drivers/ii_pci20kc.c36
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.c84
-rw-r--r--drivers/staging/comedi/drivers/ke_counter.c98
-rw-r--r--drivers/staging/comedi/drivers/me4000.c432
-rw-r--r--drivers/staging/comedi/drivers/me_daq.c101
-rw-r--r--drivers/staging/comedi/drivers/mite.h4
-rw-r--r--drivers/staging/comedi/drivers/mpc624.c236
-rw-r--r--drivers/staging/comedi/drivers/mpc8260cpm.c114
-rw-r--r--drivers/staging/comedi/drivers/multiq3.c37
-rw-r--r--drivers/staging/comedi/drivers/ni_6527.c10
-rw-r--r--drivers/staging/comedi/drivers/ni_65xx.c9
-rw-r--r--drivers/staging/comedi/drivers/ni_660x.c15
-rw-r--r--drivers/staging/comedi/drivers/ni_670x.c12
-rw-r--r--drivers/staging/comedi/drivers/ni_at_a2150.c360
-rw-r--r--drivers/staging/comedi/drivers/ni_at_ao.c238
-rw-r--r--drivers/staging/comedi/drivers/ni_atmio.c94
-rw-r--r--drivers/staging/comedi/drivers/ni_atmio16d.c82
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_700.c17
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_dio24.c17
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.c9
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.h2
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_cs.c10
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_cs.c13
-rw-r--r--drivers/staging/comedi/drivers/ni_pcidio.c142
-rw-r--r--drivers/staging/comedi/drivers/ni_pcimio.c198
-rw-r--r--drivers/staging/comedi/drivers/ni_tio_internal.h36
-rw-r--r--drivers/staging/comedi/drivers/pcl711.c75
-rw-r--r--drivers/staging/comedi/drivers/pcl724.c65
-rw-r--r--drivers/staging/comedi/drivers/pcl725.c37
-rw-r--r--drivers/staging/comedi/drivers/pcl726.c46
-rw-r--r--drivers/staging/comedi/drivers/pcl730.c57
-rw-r--r--drivers/staging/comedi/drivers/pcl812.c166
-rw-r--r--drivers/staging/comedi/drivers/pcl816.c153
-rw-r--r--drivers/staging/comedi/drivers/pcl818.c166
-rw-r--r--drivers/staging/comedi/drivers/pcm3724.c51
-rw-r--r--drivers/staging/comedi/drivers/pcm3730.c37
-rw-r--r--drivers/staging/comedi/drivers/pcmad.c63
-rw-r--r--drivers/staging/comedi/drivers/pcmda12.c224
-rw-r--r--drivers/staging/comedi/drivers/pcmmio.c661
-rw-r--r--drivers/staging/comedi/drivers/pcmuio.c542
-rw-r--r--drivers/staging/comedi/drivers/poc.c205
-rw-r--r--drivers/staging/comedi/drivers/quatech_daqp_cs.c16
-rw-r--r--drivers/staging/comedi/drivers/rtd520.c188
-rw-r--r--drivers/staging/comedi/drivers/rti800.c54
-rw-r--r--drivers/staging/comedi/drivers/rti802.c37
-rw-r--r--drivers/staging/comedi/drivers/s526.c495
-rw-r--r--drivers/staging/comedi/drivers/s626.c137
-rw-r--r--drivers/staging/comedi/drivers/serial2002.c69
-rw-r--r--drivers/staging/comedi/drivers/skel.c9
-rw-r--r--drivers/staging/comedi/drivers/ssv_dnp.c223
-rw-r--r--drivers/staging/comedi/drivers/unioxx5.c453
-rw-r--r--drivers/staging/comedi/drivers/usbdux.c149
-rw-r--r--drivers/staging/comedi/drivers/usbduxfast.c93
-rw-r--r--drivers/staging/comedi/drivers/usbduxsigma.c48
-rw-r--r--drivers/staging/comedi/drivers/vmk80xx.c113
-rw-r--r--drivers/staging/comedi/internal.h6
-rw-r--r--drivers/staging/et131x/et131x.c10
-rw-r--r--drivers/staging/frontier/alphatrack.c15
-rw-r--r--drivers/staging/frontier/tranzport.c16
-rw-r--r--drivers/staging/gdm72xx/Kconfig46
-rw-r--r--drivers/staging/gdm72xx/Makefile6
-rw-r--r--drivers/staging/gdm72xx/TODO5
-rw-r--r--drivers/staging/gdm72xx/gdm_qos.c460
-rw-r--r--drivers/staging/gdm72xx/gdm_qos.h93
-rw-r--r--drivers/staging/gdm72xx/gdm_sdio.c754
-rw-r--r--drivers/staging/gdm72xx/gdm_sdio.h72
-rw-r--r--drivers/staging/gdm72xx/gdm_usb.c798
-rw-r--r--drivers/staging/gdm72xx/gdm_usb.h85
-rw-r--r--drivers/staging/gdm72xx/gdm_wimax.c1026
-rw-r--r--drivers/staging/gdm72xx/gdm_wimax.h92
-rw-r--r--drivers/staging/gdm72xx/hci.h218
-rw-r--r--drivers/staging/gdm72xx/netlink_k.c150
-rw-r--r--drivers/staging/gdm72xx/netlink_k.h24
-rw-r--r--drivers/staging/gdm72xx/sdio_boot.c159
-rw-r--r--drivers/staging/gdm72xx/sdio_boot.h21
-rw-r--r--drivers/staging/gdm72xx/usb_boot.c404
-rw-r--r--drivers/staging/gdm72xx/usb_boot.h22
-rw-r--r--drivers/staging/gdm72xx/usb_ids.h82
-rw-r--r--drivers/staging/gdm72xx/wm_ioctl.h97
-rw-r--r--drivers/staging/iio/Documentation/device.txt4
-rw-r--r--drivers/staging/iio/Documentation/generic_buffer.c4
-rw-r--r--drivers/staging/iio/Documentation/iio_event_monitor.c2
-rwxr-xr-xdrivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl25836
-rwxr-xr-xdrivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2x7x13
-rw-r--r--drivers/staging/iio/Documentation/sysfs-bus-iio-ad719220
-rw-r--r--drivers/staging/iio/Documentation/sysfs-bus-iio-dds81
-rw-r--r--drivers/staging/iio/Documentation/sysfs-bus-iio-light15
-rw-r--r--drivers/staging/iio/Documentation/trigger.txt2
-rw-r--r--drivers/staging/iio/Kconfig46
-rw-r--r--drivers/staging/iio/Makefile8
-rw-r--r--drivers/staging/iio/TODO2
-rw-r--r--drivers/staging/iio/accel/adis16201_core.c123
-rw-r--r--drivers/staging/iio/accel/adis16201_ring.c9
-rw-r--r--drivers/staging/iio/accel/adis16201_trigger.c10
-rw-r--r--drivers/staging/iio/accel/adis16203_core.c108
-rw-r--r--drivers/staging/iio/accel/adis16203_ring.c16
-rw-r--r--drivers/staging/iio/accel/adis16203_trigger.c10
-rw-r--r--drivers/staging/iio/accel/adis16204_core.c115
-rw-r--r--drivers/staging/iio/accel/adis16204_ring.c16
-rw-r--r--drivers/staging/iio/accel/adis16204_trigger.c10
-rw-r--r--drivers/staging/iio/accel/adis16209_core.c159
-rw-r--r--drivers/staging/iio/accel/adis16209_ring.c17
-rw-r--r--drivers/staging/iio/accel/adis16209_trigger.c10
-rw-r--r--drivers/staging/iio/accel/adis16220_core.c39
-rw-r--r--drivers/staging/iio/accel/adis16240_core.c129
-rw-r--r--drivers/staging/iio/accel/adis16240_ring.c16
-rw-r--r--drivers/staging/iio/accel/adis16240_trigger.c10
-rw-r--r--drivers/staging/iio/accel/kxsd9.c16
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_core.c50
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_ring.c25
-rw-r--r--drivers/staging/iio/accel/sca3000_core.c66
-rw-r--r--drivers/staging/iio/accel/sca3000_ring.c12
-rw-r--r--drivers/staging/iio/adc/Kconfig27
-rw-r--r--drivers/staging/iio/adc/Makefile1
-rw-r--r--drivers/staging/iio/adc/ad7192.c81
-rw-r--r--drivers/staging/iio/adc/ad7280a.c31
-rw-r--r--drivers/staging/iio/adc/ad7291.c26
-rw-r--r--drivers/staging/iio/adc/ad7298.h1
-rw-r--r--drivers/staging/iio/adc/ad7298_core.c79
-rw-r--r--drivers/staging/iio/adc/ad7298_ring.c46
-rw-r--r--drivers/staging/iio/adc/ad7476.h1
-rw-r--r--drivers/staging/iio/adc/ad7476_core.c60
-rw-r--r--drivers/staging/iio/adc/ad7476_ring.c58
-rw-r--r--drivers/staging/iio/adc/ad7606_core.c39
-rw-r--r--drivers/staging/iio/adc/ad7606_par.c2
-rw-r--r--drivers/staging/iio/adc/ad7606_ring.c30
-rw-r--r--drivers/staging/iio/adc/ad7606_spi.c2
-rw-r--r--drivers/staging/iio/adc/ad7780.c44
-rw-r--r--drivers/staging/iio/adc/ad7793.c103
-rw-r--r--drivers/staging/iio/adc/ad7816.c26
-rw-r--r--drivers/staging/iio/adc/ad7887.h1
-rw-r--r--drivers/staging/iio/adc/ad7887_core.c20
-rw-r--r--drivers/staging/iio/adc/ad7887_ring.c46
-rw-r--r--drivers/staging/iio/adc/ad799x.h1
-rw-r--r--drivers/staging/iio/adc/ad799x_core.c62
-rw-r--r--drivers/staging/iio/adc/ad799x_ring.c44
-rw-r--r--drivers/staging/iio/adc/adt7310.c40
-rw-r--r--drivers/staging/iio/adc/adt7410.c40
-rw-r--r--drivers/staging/iio/adc/lpc32xx_adc.c35
-rw-r--r--drivers/staging/iio/adc/max1363_core.c33
-rw-r--r--drivers/staging/iio/adc/max1363_ring.c10
-rw-r--r--drivers/staging/iio/adc/spear_adc.c448
-rw-r--r--drivers/staging/iio/addac/adt7316.c152
-rw-r--r--drivers/staging/iio/cdc/ad7150.c24
-rw-r--r--drivers/staging/iio/cdc/ad7152.c30
-rw-r--r--drivers/staging/iio/cdc/ad7746.c49
-rw-r--r--drivers/staging/iio/dac/Kconfig6
-rw-r--r--drivers/staging/iio/dac/ad5064.c29
-rw-r--r--drivers/staging/iio/dac/ad5360.c21
-rw-r--r--drivers/staging/iio/dac/ad5380.c25
-rw-r--r--drivers/staging/iio/dac/ad5421.c19
-rw-r--r--drivers/staging/iio/dac/ad5446.c293
-rw-r--r--drivers/staging/iio/dac/ad5446.h20
-rw-r--r--drivers/staging/iio/dac/ad5504.c27
-rw-r--r--drivers/staging/iio/dac/ad5624r_spi.c23
-rw-r--r--drivers/staging/iio/dac/ad5686.c25
-rw-r--r--drivers/staging/iio/dac/ad5764.c17
-rw-r--r--drivers/staging/iio/dac/ad5791.c25
-rw-r--r--drivers/staging/iio/dac/max517.c15
-rw-r--r--drivers/staging/iio/dds/dds.h110
-rw-r--r--drivers/staging/iio/frequency/Kconfig (renamed from drivers/staging/iio/dds/Kconfig)0
-rw-r--r--drivers/staging/iio/frequency/Makefile (renamed from drivers/staging/iio/dds/Makefile)0
-rw-r--r--drivers/staging/iio/frequency/ad5930.c (renamed from drivers/staging/iio/dds/ad5930.c)12
-rw-r--r--drivers/staging/iio/frequency/ad9832.c (renamed from drivers/staging/iio/dds/ad9832.c)36
-rw-r--r--drivers/staging/iio/frequency/ad9832.h (renamed from drivers/staging/iio/dds/ad9832.h)0
-rw-r--r--drivers/staging/iio/frequency/ad9834.c (renamed from drivers/staging/iio/dds/ad9834.c)74
-rw-r--r--drivers/staging/iio/frequency/ad9834.h (renamed from drivers/staging/iio/dds/ad9834.h)0
-rw-r--r--drivers/staging/iio/frequency/ad9850.c (renamed from drivers/staging/iio/dds/ad9850.c)12
-rw-r--r--drivers/staging/iio/frequency/ad9852.c (renamed from drivers/staging/iio/dds/ad9852.c)12
-rw-r--r--drivers/staging/iio/frequency/ad9910.c (renamed from drivers/staging/iio/dds/ad9910.c)12
-rw-r--r--drivers/staging/iio/frequency/ad9951.c (renamed from drivers/staging/iio/dds/ad9951.c)12
-rw-r--r--drivers/staging/iio/frequency/dds.h110
-rw-r--r--drivers/staging/iio/gyro/adis16060_core.c18
-rw-r--r--drivers/staging/iio/gyro/adis16080_core.c16
-rw-r--r--drivers/staging/iio/gyro/adis16130_core.c12
-rw-r--r--drivers/staging/iio/gyro/adis16260_core.c116
-rw-r--r--drivers/staging/iio/gyro/adis16260_ring.c16
-rw-r--r--drivers/staging/iio/gyro/adis16260_trigger.c10
-rw-r--r--drivers/staging/iio/gyro/adxrs450.h2
-rw-r--r--drivers/staging/iio/gyro/adxrs450_core.c24
-rw-r--r--drivers/staging/iio/iio_dummy_evgen.c4
-rw-r--r--drivers/staging/iio/iio_hwmon.c4
-rw-r--r--drivers/staging/iio/iio_simple_dummy.c35
-rw-r--r--drivers/staging/iio/iio_simple_dummy_buffer.c21
-rw-r--r--drivers/staging/iio/iio_simple_dummy_events.c8
-rw-r--r--drivers/staging/iio/impedance-analyzer/ad5933.c83
-rw-r--r--drivers/staging/iio/imu/adis16400_core.c141
-rw-r--r--drivers/staging/iio/imu/adis16400_ring.c20
-rw-r--r--drivers/staging/iio/imu/adis16400_trigger.c10
-rw-r--r--drivers/staging/iio/light/Kconfig37
-rw-r--r--drivers/staging/iio/light/Makefile2
-rw-r--r--drivers/staging/iio/light/isl29018.c211
-rw-r--r--drivers/staging/iio/light/isl29028.c566
-rw-r--r--drivers/staging/iio/light/tsl2563.c24
-rw-r--r--drivers/staging/iio/light/tsl2583.c34
-rwxr-xr-xdrivers/staging/iio/light/tsl2x7x.h100
-rwxr-xr-xdrivers/staging/iio/light/tsl2x7x_core.c2082
-rw-r--r--drivers/staging/iio/magnetometer/Kconfig8
-rw-r--r--drivers/staging/iio/magnetometer/ak8975.c19
-rw-r--r--drivers/staging/iio/magnetometer/hmc5843.c522
-rw-r--r--drivers/staging/iio/meter/ade7753.c22
-rw-r--r--drivers/staging/iio/meter/ade7754.c22
-rw-r--r--drivers/staging/iio/meter/ade7758_core.c299
-rw-r--r--drivers/staging/iio/meter/ade7758_ring.c33
-rw-r--r--drivers/staging/iio/meter/ade7758_trigger.c10
-rw-r--r--drivers/staging/iio/meter/ade7759.c22
-rw-r--r--drivers/staging/iio/meter/ade7854-i2c.c22
-rw-r--r--drivers/staging/iio/meter/ade7854-spi.c22
-rw-r--r--drivers/staging/iio/meter/ade7854.c28
-rw-r--r--drivers/staging/iio/meter/meter.h2
-rw-r--r--drivers/staging/iio/resolver/ad2s1200.c12
-rw-r--r--drivers/staging/iio/resolver/ad2s1210.c38
-rw-r--r--drivers/staging/iio/resolver/ad2s90.c11
-rw-r--r--drivers/staging/iio/ring_sw.c2
-rw-r--r--drivers/staging/iio/ring_sw.h2
-rw-r--r--drivers/staging/iio/trigger/iio-trig-bfin-timer.c10
-rw-r--r--drivers/staging/iio/trigger/iio-trig-gpio.c10
-rw-r--r--drivers/staging/iio/trigger/iio-trig-periodic-rtc.c8
-rw-r--r--drivers/staging/iio/trigger/iio-trig-sysfs.c10
-rw-r--r--drivers/staging/ipack/Kconfig20
-rw-r--r--drivers/staging/ipack/Makefile6
-rw-r--r--drivers/staging/ipack/TODO46
-rw-r--r--drivers/staging/ipack/bridges/Kconfig8
-rw-r--r--drivers/staging/ipack/bridges/Makefile1
-rw-r--r--drivers/staging/ipack/bridges/tpci200.c1141
-rw-r--r--drivers/staging/ipack/bridges/tpci200.h162
-rw-r--r--drivers/staging/ipack/devices/Kconfig7
-rw-r--r--drivers/staging/ipack/devices/Makefile1
-rw-r--r--drivers/staging/ipack/devices/ipoctal.c901
-rw-r--r--drivers/staging/ipack/devices/ipoctal.h80
-rw-r--r--drivers/staging/ipack/devices/scc2698.h228
-rw-r--r--drivers/staging/ipack/ipack.c205
-rw-r--r--drivers/staging/ipack/ipack.h183
-rw-r--r--drivers/staging/line6/config.h48
-rw-r--r--drivers/staging/line6/driver.c88
-rw-r--r--drivers/staging/line6/midi.c2
-rw-r--r--drivers/staging/line6/midibuf.c2
-rw-r--r--drivers/staging/line6/pcm.c2
-rw-r--r--drivers/staging/line6/toneport.c2
-rw-r--r--drivers/staging/media/as102/as102_drv.c34
-rw-r--r--drivers/staging/media/as102/as102_fe.c2
-rw-r--r--drivers/staging/media/as102/as102_fw.c5
-rw-r--r--drivers/staging/media/as102/as102_usb_drv.c12
-rw-r--r--drivers/staging/media/as102/as102_usb_drv.h2
-rw-r--r--drivers/staging/media/as102/as10x_cmd.c28
-rw-r--r--drivers/staging/media/dt3155v4l/dt3155v4l.c4
-rw-r--r--drivers/staging/media/easycap/easycap_ioctl.c1
-rw-r--r--drivers/staging/media/easycap/easycap_main.c1645
-rw-r--r--drivers/staging/media/go7007/README2
-rw-r--r--drivers/staging/media/go7007/go7007-v4l2.c2
-rw-r--r--drivers/staging/media/go7007/go7007.txt1
-rw-r--r--drivers/staging/media/go7007/s2250-loader.c28
-rw-r--r--drivers/staging/media/lirc/lirc_imon.c84
-rw-r--r--drivers/staging/media/lirc/lirc_sasem.c104
-rw-r--r--drivers/staging/media/lirc/lirc_ttusbir.c13
-rw-r--r--drivers/staging/mei/TODO10
-rw-r--r--drivers/staging/net/Kconfig38
-rw-r--r--drivers/staging/net/Makefile5
-rw-r--r--drivers/staging/net/TODO5
-rw-r--r--drivers/staging/net/pc300-falc-lh.h (renamed from drivers/net/wan/pc300-falc-lh.h)0
-rw-r--r--drivers/staging/net/pc300.h (renamed from drivers/net/wan/pc300.h)0
-rw-r--r--drivers/staging/net/pc300_drv.c (renamed from drivers/net/wan/pc300_drv.c)0
-rw-r--r--drivers/staging/net/pc300_tty.c (renamed from drivers/net/wan/pc300_tty.c)0
-rw-r--r--drivers/staging/nvec/nvec.h2
-rw-r--r--drivers/staging/octeon/ethernet-rx.c2
-rw-r--r--drivers/staging/octeon/ethernet-tx.c10
-rw-r--r--drivers/staging/octeon/ethernet-util.h2
-rw-r--r--drivers/staging/octeon/ethernet.c2
-rw-r--r--drivers/staging/olpc_dcon/olpc_dcon.c29
-rw-r--r--drivers/staging/olpc_dcon/olpc_dcon_xo_1.c2
-rw-r--r--drivers/staging/omapdrm/Makefile1
-rw-r--r--drivers/staging/omapdrm/omap_crtc.c7
-rw-r--r--drivers/staging/omapdrm/omap_dmm_tiler.c4
-rw-r--r--drivers/staging/omapdrm/omap_drv.c10
-rw-r--r--drivers/staging/omapdrm/omap_drv.h14
-rw-r--r--drivers/staging/omapdrm/omap_fb.c7
-rw-r--r--drivers/staging/omapdrm/omap_gem.c130
-rw-r--r--drivers/staging/omapdrm/omap_gem_dmabuf.c220
-rw-r--r--drivers/staging/omapdrm/tcm-sita.c2
-rw-r--r--drivers/staging/ozwpan/README2
-rw-r--r--drivers/staging/ozwpan/ozappif.h12
-rw-r--r--drivers/staging/ozwpan/ozcdev.c17
-rw-r--r--drivers/staging/ozwpan/ozevent.c195
-rw-r--r--drivers/staging/ozwpan/ozevent.h11
-rw-r--r--drivers/staging/ozwpan/ozeventdef.h19
-rw-r--r--drivers/staging/ozwpan/ozhcd.c6
-rw-r--r--drivers/staging/ozwpan/ozmain.c8
-rw-r--r--drivers/staging/ozwpan/ozusbsvc.c2
-rw-r--r--drivers/staging/panel/panel.c2
-rw-r--r--drivers/staging/quatech_usb2/Kconfig15
-rw-r--r--drivers/staging/quatech_usb2/Makefile1
-rw-r--r--drivers/staging/quatech_usb2/TODO8
-rw-r--r--drivers/staging/quatech_usb2/quatech_usb2.c1976
-rw-r--r--drivers/staging/ramster/Kconfig2
-rw-r--r--drivers/staging/ramster/cluster/tcp.c4
-rw-r--r--drivers/staging/ramster/xvmalloc.c2
-rw-r--r--drivers/staging/ramster/zcache-main.c6
-rw-r--r--drivers/staging/rtl8187se/Makefile2
-rw-r--r--drivers/staging/rtl8187se/ieee80211/dot11d.c2
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211.h14
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c26
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c2
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c7
-rw-r--r--drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c2
-rw-r--r--drivers/staging/rtl8187se/r8180.h10
-rw-r--r--drivers/staging/rtl8187se/r8180_core.c33
-rw-r--r--drivers/staging/rtl8187se/r8180_dm.c16
-rw-r--r--drivers/staging/rtl8187se/r8180_rtl8225z2.c4
-rw-r--r--drivers/staging/rtl8187se/r8180_wx.c6
-rw-r--r--drivers/staging/rtl8187se/r8180_wx.h2
-rw-r--r--drivers/staging/rtl8187se/r8185b_init.c1329
-rw-r--r--drivers/staging/rtl8192e/Kconfig4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c3
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c2
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c2
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_core.c13
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_core.h3
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_dm.c22
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_wx.c4
-rw-r--r--drivers/staging/rtl8192e/rtl819x_TSProc.c2
-rw-r--r--drivers/staging/rtl8192e/rtllib.h18
-rw-r--r--drivers/staging/rtl8192e/rtllib_rx.c10
-rw-r--r--drivers/staging/rtl8192e/rtllib_softmac.c35
-rw-r--r--drivers/staging/rtl8192e/rtllib_softmac_wx.c4
-rw-r--r--drivers/staging/rtl8192e/rtllib_tx.c14
-rw-r--r--drivers/staging/rtl8192e/rtllib_wx.c4
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_module.c2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c4
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c2
-rw-r--r--drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c7
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c2
-rw-r--r--drivers/staging/rtl8192u/r8180_93cx6.c2
-rw-r--r--drivers/staging/rtl8192u/r8180_93cx6.h2
-rw-r--r--drivers/staging/rtl8192u/r8192U.h9
-rw-r--r--drivers/staging/rtl8192u/r8192U_core.c60
-rw-r--r--drivers/staging/rtl8192u/r8192U_dm.c74
-rw-r--r--drivers/staging/rtl8192u/r8192U_hw.h2
-rw-r--r--drivers/staging/rtl8192u/r8192U_wx.c12
-rw-r--r--drivers/staging/rtl8192u/r8192U_wx.h2
-rw-r--r--drivers/staging/rtl8192u/r819xU_HTType.h2
-rw-r--r--drivers/staging/rtl8192u/r819xU_cmdpkt.c12
-rw-r--r--drivers/staging/rtl8192u/r819xU_firmware.c4
-rw-r--r--drivers/staging/rtl8192u/r819xU_phy.c16
-rw-r--r--drivers/staging/rtl8192u/r819xU_phyreg.h2
-rw-r--r--drivers/staging/rtl8712/big_endian.h94
-rw-r--r--drivers/staging/rtl8712/drv_types.h2
-rw-r--r--drivers/staging/rtl8712/generic.h178
-rw-r--r--drivers/staging/rtl8712/hal_init.c1
-rw-r--r--drivers/staging/rtl8712/ieee80211.h2
-rw-r--r--drivers/staging/rtl8712/if_ether.h141
-rw-r--r--drivers/staging/rtl8712/ip.h137
-rw-r--r--drivers/staging/rtl8712/little_endian.h94
-rw-r--r--drivers/staging/rtl8712/os_intfs.c4
-rw-r--r--drivers/staging/rtl8712/osdep_service.h3
-rw-r--r--drivers/staging/rtl8712/rtl8712_cmd.c7
-rw-r--r--drivers/staging/rtl8712/rtl8712_cmd.h2
-rw-r--r--drivers/staging/rtl8712/rtl8712_efuse.c2
-rw-r--r--drivers/staging/rtl8712/rtl8712_gp_bitdef.h2
-rw-r--r--drivers/staging/rtl8712/rtl8712_hal.h4
-rw-r--r--drivers/staging/rtl8712/rtl8712_led.c6
-rw-r--r--drivers/staging/rtl8712/rtl8712_recv.c9
-rw-r--r--drivers/staging/rtl8712/rtl8712_xmit.c1
-rw-r--r--drivers/staging/rtl8712/rtl871x_byteorder.h32
-rw-r--r--drivers/staging/rtl8712/rtl871x_cmd.c1
-rw-r--r--drivers/staging/rtl8712/rtl871x_cmd.h2
-rw-r--r--drivers/staging/rtl8712/rtl871x_io.h2
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_linux.c19
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_set.c2
-rw-r--r--drivers/staging/rtl8712/rtl871x_mlme.c8
-rw-r--r--drivers/staging/rtl8712/rtl871x_mlme.h6
-rw-r--r--drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h4
-rw-r--r--drivers/staging/rtl8712/rtl871x_recv.c4
-rw-r--r--drivers/staging/rtl8712/rtl871x_xmit.c3
-rw-r--r--drivers/staging/rtl8712/rtl871x_xmit.h2
-rw-r--r--drivers/staging/rtl8712/swab.h131
-rw-r--r--drivers/staging/rtl8712/usb_halinit.c4
-rw-r--r--drivers/staging/rtl8712/usb_intf.c36
-rw-r--r--drivers/staging/rtl8712/usb_ops.c1
-rw-r--r--drivers/staging/rtl8712/wifi.h1
-rw-r--r--drivers/staging/rtl8712/xmit_linux.c6
-rw-r--r--drivers/staging/rts5139/ms.c11
-rw-r--r--drivers/staging/rts5139/ms.h2
-rw-r--r--drivers/staging/rts5139/ms_mg.c4
-rw-r--r--drivers/staging/rts5139/rts51x.c83
-rw-r--r--drivers/staging/rts5139/rts51x.h10
-rw-r--r--drivers/staging/rts5139/rts51x_card.c52
-rw-r--r--drivers/staging/rts5139/rts51x_card.h11
-rw-r--r--drivers/staging/rts5139/rts51x_chip.c178
-rw-r--r--drivers/staging/rts5139/rts51x_chip.h95
-rw-r--r--drivers/staging/rts5139/rts51x_fop.c5
-rw-r--r--drivers/staging/rts5139/rts51x_fop.h5
-rw-r--r--drivers/staging/rts5139/rts51x_scsi.c93
-rw-r--r--drivers/staging/rts5139/rts51x_scsi.h5
-rw-r--r--drivers/staging/rts5139/rts51x_sys.h54
-rw-r--r--drivers/staging/rts5139/rts51x_transport.c282
-rw-r--r--drivers/staging/rts5139/rts51x_transport.h12
-rw-r--r--drivers/staging/rts5139/sd.c142
-rw-r--r--drivers/staging/rts5139/sd.h29
-rw-r--r--drivers/staging/rts5139/sd_cprm.c166
-rw-r--r--drivers/staging/rts5139/xd.c122
-rw-r--r--drivers/staging/rts5139/xd.h2
-rw-r--r--drivers/staging/rts_pstor/ms.c2
-rw-r--r--drivers/staging/rts_pstor/rtsx_transport.c4
-rw-r--r--drivers/staging/sep/sep_driver_config.h6
-rw-r--r--drivers/staging/sep/sep_main.c12
-rw-r--r--drivers/staging/serial/68360serial.c2979
-rw-r--r--drivers/staging/serial/Kconfig16
-rw-r--r--drivers/staging/serial/Makefile1
-rw-r--r--drivers/staging/serial/TODO6
-rw-r--r--drivers/staging/serqt_usb2/serqt_usb2.c79
-rw-r--r--drivers/staging/sm7xx/smtcfb.c232
-rw-r--r--drivers/staging/sm7xx/smtcfb.h8
-rw-r--r--drivers/staging/telephony/ixj.c228
-rw-r--r--drivers/staging/tidspbridge/core/io_sm.c2
-rw-r--r--drivers/staging/tidspbridge/core/ue_deh.c2
-rw-r--r--drivers/staging/usbip/stub_dev.c12
-rw-r--r--drivers/staging/usbip/usbip_common.h17
-rw-r--r--drivers/staging/usbip/usbip_protocol.txt2
-rw-r--r--drivers/staging/usbip/userspace/libsrc/vhci_driver.c20
-rw-r--r--drivers/staging/usbip/vhci_hcd.c8
-rw-r--r--drivers/staging/usbip/vhci_rx.c2
-rw-r--r--drivers/staging/usbip/vhci_sysfs.c4
-rw-r--r--drivers/staging/vme/Makefile7
-rw-r--r--drivers/staging/vme/TODO5
-rw-r--r--drivers/staging/vme/devices/Kconfig3
-rw-r--r--drivers/staging/vme/devices/vme_pio2_cntr.c2
-rw-r--r--drivers/staging/vme/devices/vme_pio2_core.c3
-rw-r--r--drivers/staging/vme/devices/vme_pio2_gpio.c5
-rw-r--r--drivers/staging/vme/devices/vme_user.c45
-rw-r--r--drivers/staging/vt6655/wpa.c4
-rw-r--r--drivers/staging/vt6656/dpc.c2
-rw-r--r--drivers/staging/vt6656/ioctl.c24
-rw-r--r--drivers/staging/vt6656/main_usb.c4
-rw-r--r--drivers/staging/vt6656/wpa.c4
-rw-r--r--drivers/staging/wlags49_h2/README.ubuntu2
-rw-r--r--drivers/staging/wlags49_h2/hcf.c10
-rw-r--r--drivers/staging/wlags49_h2/hcf.h12
-rw-r--r--drivers/staging/wlags49_h2/mmd.c12
-rw-r--r--drivers/staging/wlags49_h2/wl_cs.c3
-rw-r--r--drivers/staging/wlags49_h2/wl_netdev.c9
-rw-r--r--drivers/staging/wlags49_h2/wl_pci.c4
-rw-r--r--drivers/staging/wlags49_h2/wl_profile.c8
-rw-r--r--drivers/staging/wlags49_h2/wl_util.c11
-rw-r--r--drivers/staging/wlan-ng/cfg80211.c10
-rw-r--r--drivers/staging/wlan-ng/prism2mgmt.c4
-rw-r--r--drivers/staging/xgifb/XGI_main.h221
-rw-r--r--drivers/staging/xgifb/XGI_main_26.c101
-rw-r--r--drivers/staging/xgifb/XGIfb.h6
-rw-r--r--drivers/staging/xgifb/vb_init.c78
-rw-r--r--drivers/staging/xgifb/vb_setmode.c1457
-rw-r--r--drivers/staging/xgifb/vb_struct.h27
-rw-r--r--drivers/staging/xgifb/vb_table.h725
-rw-r--r--drivers/staging/xgifb/vgatypes.h2
-rw-r--r--drivers/staging/zsmalloc/zsmalloc-main.c40
-rw-r--r--drivers/staging/zsmalloc/zsmalloc_int.h2
-rw-r--r--drivers/target/Kconfig1
-rw-r--r--drivers/target/Makefile1
-rw-r--r--drivers/target/sbp/Kconfig11
-rw-r--r--drivers/target/sbp/Makefile1
-rw-r--r--drivers/target/sbp/sbp_target.c2621
-rw-r--r--drivers/target/sbp/sbp_target.h251
-rw-r--r--drivers/tty/amiserial.c14
-rw-r--r--drivers/tty/bfin_jtag_comm.c44
-rw-r--r--drivers/tty/cyclades.c2
-rw-r--r--drivers/tty/hvc/hvc_console.c96
-rw-r--r--drivers/tty/hvc/hvc_console.h4
-rw-r--r--drivers/tty/hvc/hvc_xen.c4
-rw-r--r--drivers/tty/hvc/hvcs.c74
-rw-r--r--drivers/tty/hvc/hvsi.c128
-rw-r--r--drivers/tty/hvc/hvsi_lib.c2
-rw-r--r--drivers/tty/ipwireless/tty.c81
-rw-r--r--drivers/tty/mxser.c2
-rw-r--r--drivers/tty/n_r3964.c11
-rw-r--r--drivers/tty/n_tty.c9
-rw-r--r--drivers/tty/pty.c40
-rw-r--r--drivers/tty/serial/68328serial.c383
-rw-r--r--drivers/tty/serial/68328serial.h186
-rw-r--r--drivers/tty/serial/8250/8250.c312
-rw-r--r--drivers/tty/serial/8250/8250.h16
-rw-r--r--drivers/tty/serial/8250/8250_em.c186
-rw-r--r--drivers/tty/serial/8250/8250_mca.c61
-rw-r--r--drivers/tty/serial/8250/8250_pci.c63
-rw-r--r--drivers/tty/serial/8250/Kconfig17
-rw-r--r--drivers/tty/serial/8250/Makefile2
-rw-r--r--drivers/tty/serial/amba-pl011.c117
-rw-r--r--drivers/tty/serial/bfin_uart.c74
-rw-r--r--drivers/tty/serial/clps711x.c1
-rw-r--r--drivers/tty/serial/crisv10.c36
-rw-r--r--drivers/tty/serial/imx.c8
-rw-r--r--drivers/tty/serial/mxs-auart.c10
-rw-r--r--drivers/tty/serial/of_serial.c26
-rw-r--r--drivers/tty/serial/omap-serial.c74
-rw-r--r--drivers/tty/serial/pch_uart.c53
-rw-r--r--drivers/tty/serial/serial_core.c1
-rw-r--r--drivers/tty/serial/sh-sci.c49
-rw-r--r--drivers/tty/synclink.c4
-rw-r--r--drivers/tty/synclink_gt.c4
-rw-r--r--drivers/tty/synclinkmp.c4
-rw-r--r--drivers/tty/tty_buffer.c85
-rw-r--r--drivers/tty/tty_io.c76
-rw-r--r--drivers/tty/tty_ldisc.c37
-rw-r--r--drivers/tty/tty_mutex.c60
-rw-r--r--drivers/tty/tty_port.c6
-rw-r--r--drivers/tty/vt/consolemap.c123
-rw-r--r--drivers/tty/vt/keyboard.c20
-rw-r--r--drivers/tty/vt/vt.c68
-rw-r--r--drivers/tty/vt/vt_ioctl.c25
-rw-r--r--drivers/uio/uio_pdrv_genirq.c8
-rw-r--r--drivers/usb/Kconfig4
-rw-r--r--drivers/usb/Makefile2
-rw-r--r--drivers/usb/atm/cxacru.c34
-rw-r--r--drivers/usb/atm/speedtch.c2
-rw-r--r--drivers/usb/atm/ueagle-atm.c15
-rw-r--r--drivers/usb/atm/usbatm.c30
-rw-r--r--drivers/usb/atm/xusbatm.c4
-rw-r--r--drivers/usb/chipidea/Kconfig32
-rw-r--r--drivers/usb/chipidea/Makefile14
-rw-r--r--drivers/usb/chipidea/bits.h90
-rw-r--r--drivers/usb/chipidea/ci.h313
-rw-r--r--drivers/usb/chipidea/ci13xxx_msm.c (renamed from drivers/usb/gadget/ci13xxx_msm.c)60
-rw-r--r--drivers/usb/chipidea/ci13xxx_pci.c (renamed from drivers/usb/gadget/ci13xxx_pci.c)154
-rw-r--r--drivers/usb/chipidea/core.c474
-rw-r--r--drivers/usb/chipidea/debug.c804
-rw-r--r--drivers/usb/chipidea/debug.h56
-rw-r--r--drivers/usb/chipidea/host.c160
-rw-r--r--drivers/usb/chipidea/host.h17
-rw-r--r--drivers/usb/chipidea/udc.c1809
-rw-r--r--drivers/usb/chipidea/udc.h93
-rw-r--r--drivers/usb/class/cdc-acm.c1
-rw-r--r--drivers/usb/class/cdc-wdm.c38
-rw-r--r--drivers/usb/class/usblp.c82
-rw-r--r--drivers/usb/core/Kconfig53
-rw-r--r--drivers/usb/core/Makefile2
-rw-r--r--drivers/usb/core/devio.c93
-rw-r--r--drivers/usb/core/driver.c103
-rw-r--r--drivers/usb/core/file.c4
-rw-r--r--drivers/usb/core/hcd.c15
-rw-r--r--drivers/usb/core/hub.c676
-rw-r--r--drivers/usb/core/inode.c748
-rw-r--r--drivers/usb/core/message.c38
-rw-r--r--drivers/usb/core/quirks.c3
-rw-r--r--drivers/usb/core/sysfs.c6
-rw-r--r--drivers/usb/core/urb.c21
-rw-r--r--drivers/usb/core/usb-acpi.c117
-rw-r--r--drivers/usb/core/usb.c9
-rw-r--r--drivers/usb/core/usb.h7
-rw-r--r--drivers/usb/dwc3/Kconfig2
-rw-r--r--drivers/usb/dwc3/core.c31
-rw-r--r--drivers/usb/dwc3/core.h40
-rw-r--r--drivers/usb/dwc3/dwc3-omap.c32
-rw-r--r--drivers/usb/dwc3/ep0.c157
-rw-r--r--drivers/usb/dwc3/gadget.c151
-rw-r--r--drivers/usb/dwc3/gadget.h1
-rw-r--r--drivers/usb/dwc3/host.c19
-rw-r--r--drivers/usb/dwc3/io.h16
-rw-r--r--drivers/usb/gadget/Kconfig68
-rw-r--r--drivers/usb/gadget/Makefile4
-rw-r--r--drivers/usb/gadget/amd5536udc.c27
-rw-r--r--drivers/usb/gadget/amd5536udc.h1
-rw-r--r--drivers/usb/gadget/at91_udc.c77
-rw-r--r--drivers/usb/gadget/at91_udc.h3
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.c76
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.h1
-rw-r--r--drivers/usb/gadget/ci13xxx_udc.c2996
-rw-r--r--drivers/usb/gadget/ci13xxx_udc.h227
-rw-r--r--drivers/usb/gadget/composite.c107
-rw-r--r--drivers/usb/gadget/dummy_hcd.c8
-rw-r--r--drivers/usb/gadget/f_fs.c52
-rw-r--r--drivers/usb/gadget/f_hid.c2
-rw-r--r--drivers/usb/gadget/f_loopback.c4
-rw-r--r--drivers/usb/gadget/f_mass_storage.c7
-rw-r--r--drivers/usb/gadget/f_rndis.c30
-rw-r--r--drivers/usb/gadget/f_sourcesink.c424
-rw-r--r--drivers/usb/gadget/fsl_qe_udc.c371
-rw-r--r--drivers/usb/gadget/fsl_qe_udc.h1
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c55
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.h12
-rw-r--r--drivers/usb/gadget/fusb300_udc.c4
-rw-r--r--drivers/usb/gadget/fusb300_udc.h1
-rw-r--r--drivers/usb/gadget/g_ffs.c200
-rw-r--r--drivers/usb/gadget/g_zero.h5
-rw-r--r--drivers/usb/gadget/gadget_chips.h3
-rw-r--r--drivers/usb/gadget/goku_udc.c32
-rw-r--r--drivers/usb/gadget/goku_udc.h1
-rw-r--r--drivers/usb/gadget/imx_udc.c53
-rw-r--r--drivers/usb/gadget/langwell_udc.c3434
-rw-r--r--drivers/usb/gadget/langwell_udc.h224
-rw-r--r--drivers/usb/gadget/lpc32xx_udc.c3538
-rw-r--r--drivers/usb/gadget/m66592-udc.c10
-rw-r--r--drivers/usb/gadget/m66592-udc.h2
-rw-r--r--drivers/usb/gadget/mv_udc.h1
-rw-r--r--drivers/usb/gadget/mv_udc_core.c19
-rw-r--r--drivers/usb/gadget/omap_udc.c19
-rw-r--r--drivers/usb/gadget/omap_udc.h1
-rw-r--r--drivers/usb/gadget/pch_udc.c29
-rw-r--r--drivers/usb/gadget/printer.c470
-rw-r--r--drivers/usb/gadget/pxa25x_udc.c26
-rw-r--r--drivers/usb/gadget/pxa25x_udc.h1
-rw-r--r--drivers/usb/gadget/r8a66597-udc.c29
-rw-r--r--drivers/usb/gadget/r8a66597-udc.h3
-rw-r--r--drivers/usb/gadget/s3c-hsotg.c1633
-rw-r--r--drivers/usb/gadget/s3c-hsotg.h377
-rw-r--r--drivers/usb/gadget/s3c-hsudc.c9
-rw-r--r--drivers/usb/gadget/s3c2410_udc.c14
-rw-r--r--drivers/usb/gadget/s3c2410_udc.h1
-rw-r--r--drivers/usb/gadget/u_ether.c8
-rw-r--r--drivers/usb/gadget/u_ether.h46
-rw-r--r--drivers/usb/gadget/u_serial.c57
-rw-r--r--drivers/usb/gadget/uvc_queue.c2
-rw-r--r--drivers/usb/gadget/uvc_v4l2.c2
-rw-r--r--drivers/usb/gadget/zero.c19
-rw-r--r--drivers/usb/host/Kconfig43
-rw-r--r--drivers/usb/host/Makefile2
-rw-r--r--drivers/usb/host/bcma-hcd.c335
-rw-r--r--drivers/usb/host/ehci-dbg.c6
-rw-r--r--drivers/usb/host/ehci-fsl.c41
-rw-r--r--drivers/usb/host/ehci-fsl.h13
-rw-r--r--drivers/usb/host/ehci-hcd.c36
-rw-r--r--drivers/usb/host/ehci-hub.c22
-rw-r--r--drivers/usb/host/ehci-omap.c22
-rw-r--r--drivers/usb/host/ehci-pci.c4
-rw-r--r--drivers/usb/host/ehci-platform.c6
-rw-r--r--drivers/usb/host/ehci-q.c19
-rw-r--r--drivers/usb/host/ehci-s5p.c4
-rw-r--r--drivers/usb/host/ehci-sched.c55
-rw-r--r--drivers/usb/host/ehci-sead3.c266
-rw-r--r--drivers/usb/host/ehci-sh.c8
-rw-r--r--drivers/usb/host/ehci-spear.c36
-rw-r--r--drivers/usb/host/ehci-tegra.c82
-rw-r--r--drivers/usb/host/fhci-tds.c2
-rw-r--r--drivers/usb/host/fsl-mph-dr-of.c41
-rw-r--r--drivers/usb/host/isp1760-hcd.c9
-rw-r--r--drivers/usb/host/isp1760-if.c8
-rw-r--r--drivers/usb/host/ohci-at91.c16
-rw-r--r--drivers/usb/host/ohci-au1xxx.c3
-rw-r--r--drivers/usb/host/ohci-cns3xxx.c3
-rw-r--r--drivers/usb/host/ohci-da8xx.c2
-rw-r--r--drivers/usb/host/ohci-dbg.c4
-rw-r--r--drivers/usb/host/ohci-ep93xx.c9
-rw-r--r--drivers/usb/host/ohci-exynos.c3
-rw-r--r--drivers/usb/host/ohci-hcd.c21
-rw-r--r--drivers/usb/host/ohci-nxp.c173
-rw-r--r--drivers/usb/host/ohci-omap.c10
-rw-r--r--drivers/usb/host/ohci-platform.c4
-rw-r--r--drivers/usb/host/ohci-pnx8550.c3
-rw-r--r--drivers/usb/host/ohci-ppc-of.c5
-rw-r--r--drivers/usb/host/ohci-ppc-soc.c3
-rw-r--r--drivers/usb/host/ohci-ps3.c3
-rw-r--r--drivers/usb/host/ohci-pxa27x.c3
-rw-r--r--drivers/usb/host/ohci-s3c2410.c3
-rw-r--r--drivers/usb/host/ohci-sa1111.c4
-rw-r--r--drivers/usb/host/ohci-sh.c8
-rw-r--r--drivers/usb/host/ohci-spear.c36
-rw-r--r--drivers/usb/host/ohci-ssb.c260
-rw-r--r--drivers/usb/host/ohci-tmio.c3
-rw-r--r--drivers/usb/host/ohci-xls.c3
-rw-r--r--drivers/usb/host/oxu210hp-hcd.c13
-rw-r--r--drivers/usb/host/pci-quirks.c32
-rw-r--r--drivers/usb/host/r8a66597-hcd.c20
-rw-r--r--drivers/usb/host/ssb-hcd.c280
-rw-r--r--drivers/usb/host/xhci-hub.c41
-rw-r--r--drivers/usb/host/xhci-mem.c39
-rw-r--r--drivers/usb/host/xhci-pci.c14
-rw-r--r--drivers/usb/host/xhci-ring.c28
-rw-r--r--drivers/usb/host/xhci.c483
-rw-r--r--drivers/usb/host/xhci.h17
-rw-r--r--drivers/usb/image/mdc800.c19
-rw-r--r--drivers/usb/misc/appledisplay.c12
-rw-r--r--drivers/usb/misc/emi26.c59
-rw-r--r--drivers/usb/misc/emi62.c62
-rw-r--r--drivers/usb/misc/idmouse.c9
-rw-r--r--drivers/usb/misc/iowarrior.c4
-rw-r--r--drivers/usb/misc/ldusb.c15
-rw-r--r--drivers/usb/misc/legousbtower.c45
-rw-r--r--drivers/usb/misc/rio500.c65
-rw-r--r--drivers/usb/misc/usblcd.c24
-rw-r--r--drivers/usb/misc/usbtest.c17
-rw-r--r--drivers/usb/misc/uss720.c49
-rw-r--r--drivers/usb/misc/yurex.c54
-rw-r--r--drivers/usb/musb/Kconfig8
-rw-r--r--drivers/usb/musb/Makefile1
-rw-r--r--drivers/usb/musb/cppi_dma.c1
-rw-r--r--drivers/usb/musb/musb_core.c4
-rw-r--r--drivers/usb/musb/musb_dsps.c711
-rw-r--r--drivers/usb/otg/gpio_vbus.c81
-rw-r--r--drivers/usb/otg/twl6030-usb.c4
-rw-r--r--drivers/usb/phy/Kconfig17
-rw-r--r--drivers/usb/phy/Makefile7
-rw-r--r--drivers/usb/phy/isp1301.c77
-rw-r--r--drivers/usb/renesas_usbhs/mod_gadget.c19
-rw-r--r--drivers/usb/serial/Kconfig9
-rw-r--r--drivers/usb/serial/Makefile1
-rw-r--r--drivers/usb/serial/aircable.c16
-rw-r--r--drivers/usb/serial/ark3116.c36
-rw-r--r--drivers/usb/serial/belkin_sa.c47
-rw-r--r--drivers/usb/serial/bus.c9
-rw-r--r--drivers/usb/serial/ch341.c48
-rw-r--r--drivers/usb/serial/console.c9
-rw-r--r--drivers/usb/serial/cp210x.c32
-rw-r--r--drivers/usb/serial/cyberjack.c27
-rw-r--r--drivers/usb/serial/cypress_m8.c45
-rw-r--r--drivers/usb/serial/digi_acceleport.c35
-rw-r--r--drivers/usb/serial/empeg.c13
-rw-r--r--drivers/usb/serial/ezusb.c2
-rw-r--r--drivers/usb/serial/f81232.c37
-rw-r--r--drivers/usb/serial/ftdi_sio.c47
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h8
-rw-r--r--drivers/usb/serial/funsoft.c9
-rw-r--r--drivers/usb/serial/garmin_gps.c29
-rw-r--r--drivers/usb/serial/generic.c68
-rw-r--r--drivers/usb/serial/hp4x.c9
-rw-r--r--drivers/usb/serial/io_edgeport.c2
-rw-r--r--drivers/usb/serial/io_tables.h7
-rw-r--r--drivers/usb/serial/io_ti.c27
-rw-r--r--drivers/usb/serial/ipaq.c52
-rw-r--r--drivers/usb/serial/ipw.c18
-rw-r--r--drivers/usb/serial/ir-usb.c72
-rw-r--r--drivers/usb/serial/iuu_phoenix.c47
-rw-r--r--drivers/usb/serial/keyspan.c53
-rw-r--r--drivers/usb/serial/keyspan.h7
-rw-r--r--drivers/usb/serial/keyspan_pda.c17
-rw-r--r--drivers/usb/serial/kl5kusb105.c18
-rw-r--r--drivers/usb/serial/kobil_sct.c19
-rw-r--r--drivers/usb/serial/mct_u232.c33
-rw-r--r--drivers/usb/serial/metro-usb.c92
-rw-r--r--drivers/usb/serial/mos7720.c49
-rw-r--r--drivers/usb/serial/mos7840.c298
-rw-r--r--drivers/usb/serial/moto_modem.c9
-rw-r--r--drivers/usb/serial/navman.c26
-rw-r--r--drivers/usb/serial/omninet.c24
-rw-r--r--drivers/usb/serial/opticon.c53
-rw-r--r--drivers/usb/serial/option.c18
-rw-r--r--drivers/usb/serial/oti6858.c44
-rw-r--r--drivers/usb/serial/pl2303.c114
-rw-r--r--drivers/usb/serial/qcaux.c9
-rw-r--r--drivers/usb/serial/qcserial.c41
-rw-r--r--drivers/usb/serial/quatech2.c1155
-rw-r--r--drivers/usb/serial/safe_serial.c11
-rw-r--r--drivers/usb/serial/siemens_mpi.c9
-rw-r--r--drivers/usb/serial/sierra.c56
-rw-r--r--drivers/usb/serial/spcp8x5.c24
-rw-r--r--drivers/usb/serial/ssu100.c33
-rw-r--r--drivers/usb/serial/symbolserial.c30
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c65
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.h1
-rw-r--r--drivers/usb/serial/usb-serial.c109
-rw-r--r--drivers/usb/serial/usb_debug.c9
-rw-r--r--drivers/usb/serial/usb_wwan.c50
-rw-r--r--drivers/usb/serial/visor.c98
-rw-r--r--drivers/usb/serial/vivopay-serial.c9
-rw-r--r--drivers/usb/serial/whiteheat.c569
-rw-r--r--drivers/usb/serial/zio.c9
-rw-r--r--drivers/usb/storage/ene_ub6250.c6
-rw-r--r--drivers/usb/storage/unusual_devs.h9
-rw-r--r--drivers/usb/storage/usb.c22
-rw-r--r--drivers/usb/usb-skeleton.c36
-rw-r--r--drivers/video/au1100fb.c2
-rw-r--r--drivers/video/clps711xfb.c1
-rw-r--r--drivers/video/efifb.c79
-rw-r--r--drivers/video/mxsfb.c9
-rw-r--r--drivers/video/omap2/displays/Kconfig8
-rw-r--r--drivers/video/omap2/displays/Makefile2
-rw-r--r--drivers/video/omap2/displays/panel-taal.c22
-rw-r--r--drivers/video/omap2/displays/panel-tfp410.c (renamed from drivers/video/omap2/displays/panel-dvi.c)134
-rw-r--r--drivers/video/omap2/dss/dsi.c133
-rw-r--r--drivers/video/udlfb.c2
-rw-r--r--drivers/vme/Kconfig (renamed from drivers/staging/vme/Kconfig)6
-rw-r--r--drivers/vme/Makefile7
-rw-r--r--drivers/vme/boards/Kconfig (renamed from drivers/staging/vme/boards/Kconfig)0
-rw-r--r--drivers/vme/boards/Makefile (renamed from drivers/staging/vme/boards/Makefile)0
-rw-r--r--drivers/vme/boards/vme_vmivme7805.c (renamed from drivers/staging/vme/boards/vme_vmivme7805.c)0
-rw-r--r--drivers/vme/boards/vme_vmivme7805.h (renamed from drivers/staging/vme/boards/vme_vmivme7805.h)0
-rw-r--r--drivers/vme/bridges/Kconfig (renamed from drivers/staging/vme/bridges/Kconfig)0
-rw-r--r--drivers/vme/bridges/Makefile (renamed from drivers/staging/vme/bridges/Makefile)0
-rw-r--r--drivers/vme/bridges/vme_ca91cx42.c (renamed from drivers/staging/vme/bridges/vme_ca91cx42.c)8
-rw-r--r--drivers/vme/bridges/vme_ca91cx42.h (renamed from drivers/staging/vme/bridges/vme_ca91cx42.h)0
-rw-r--r--drivers/vme/bridges/vme_tsi148.c (renamed from drivers/staging/vme/bridges/vme_tsi148.c)189
-rw-r--r--drivers/vme/bridges/vme_tsi148.h (renamed from drivers/staging/vme/bridges/vme_tsi148.h)21
-rw-r--r--drivers/vme/vme.c (renamed from drivers/staging/vme/vme.c)41
-rw-r--r--drivers/vme/vme_bridge.h (renamed from drivers/staging/vme/vme_bridge.h)0
-rw-r--r--drivers/w1/Kconfig2
-rw-r--r--drivers/w1/slaves/w1_ds2408.c2
-rw-r--r--drivers/w1/w1.c2
-rw-r--r--drivers/w1/w1_io.c22
-rw-r--r--drivers/watchdog/Kconfig38
-rw-r--r--drivers/watchdog/Makefile2
-rw-r--r--drivers/watchdog/ar7_wdt.c33
-rw-r--r--drivers/watchdog/hpwdt.c13
-rw-r--r--drivers/watchdog/i6300esb.c14
-rw-r--r--drivers/watchdog/ie6xx_wdt.c348
-rw-r--r--drivers/watchdog/it87_wdt.c7
-rw-r--r--drivers/watchdog/ixp2000_wdt.c215
-rw-r--r--drivers/watchdog/pcwd_pci.c18
-rw-r--r--drivers/watchdog/pnx4008_wdt.c10
-rw-r--r--drivers/watchdog/s3c2410_wdt.c7
-rw-r--r--drivers/watchdog/sch311x_wdt.c39
-rw-r--r--drivers/watchdog/shwdt.c306
-rw-r--r--drivers/watchdog/sp5100_tco.c2
-rw-r--r--drivers/watchdog/via_wdt.c18
-rw-r--r--drivers/watchdog/wdt_pci.c34
-rw-r--r--drivers/watchdog/wm831x_wdt.c13
-rw-r--r--drivers/xen/Kconfig2
-rw-r--r--fs/attr.c8
-rw-r--r--fs/binfmt_elf.c12
-rw-r--r--fs/binfmt_elf_fdpic.c12
-rw-r--r--fs/btrfs/disk-io.c2
-rw-r--r--fs/compat.c4
-rw-r--r--fs/dcache.c2
-rw-r--r--fs/devpts/inode.c24
-rw-r--r--fs/dlm/ast.c3
-rw-r--r--fs/dlm/dlm_internal.h16
-rw-r--r--fs/dlm/lock.c541
-rw-r--r--fs/dlm/lock.h7
-rw-r--r--fs/dlm/lockspace.c20
-rw-r--r--fs/dlm/lowcomms.c28
-rw-r--r--fs/dlm/memory.c8
-rw-r--r--fs/dlm/rcom.c61
-rw-r--r--fs/dlm/recover.c73
-rw-r--r--fs/dlm/recoverd.c15
-rw-r--r--fs/dlm/requestqueue.c43
-rw-r--r--fs/ecryptfs/messaging.c2
-rw-r--r--fs/eventpoll.c90
-rw-r--r--fs/exec.c30
-rw-r--r--fs/ext2/balloc.c5
-rw-r--r--fs/ext2/ext2.h8
-rw-r--r--fs/ext2/inode.c20
-rw-r--r--fs/ext2/super.c31
-rw-r--r--fs/ext3/balloc.c5
-rw-r--r--fs/ext3/ext3.h8
-rw-r--r--fs/ext3/inode.c32
-rw-r--r--fs/ext3/super.c35
-rw-r--r--fs/ext4/balloc.c4
-rw-r--r--fs/ext4/ext4.h4
-rw-r--r--fs/ext4/ialloc.c4
-rw-r--r--fs/ext4/inode.c34
-rw-r--r--fs/ext4/migrate.c4
-rw-r--r--fs/ext4/super.c38
-rw-r--r--fs/fcntl.c6
-rw-r--r--fs/gfs2/incore.h1
-rw-r--r--fs/gfs2/lock_dlm.c2
-rw-r--r--fs/gfs2/ops_fstype.c7
-rw-r--r--fs/gfs2/sys.c10
-rw-r--r--fs/inode.c12
-rw-r--r--fs/ioprio.c18
-rw-r--r--fs/locks.c2
-rw-r--r--fs/namei.c29
-rw-r--r--fs/nfsd/auth.c5
-rw-r--r--fs/open.c16
-rw-r--r--fs/proc/array.c15
-rw-r--r--fs/proc/base.c93
-rw-r--r--fs/proc/inode.c4
-rw-r--r--fs/proc/proc_sysctl.c4
-rw-r--r--fs/proc/root.c2
-rw-r--r--fs/pstore/Kconfig17
-rw-r--r--fs/pstore/Makefile3
-rw-r--r--fs/pstore/ram.c383
-rw-r--r--fs/pstore/ram_core.c (renamed from drivers/staging/android/persistent_ram.c)161
-rw-r--r--fs/stat.c12
-rw-r--r--fs/sysfs/dir.c37
-rw-r--r--fs/sysfs/inode.c4
-rw-r--r--fs/ubifs/Kconfig23
-rw-r--r--fs/ubifs/Makefile5
-rw-r--r--fs/ubifs/commit.c14
-rw-r--r--fs/ubifs/debug.c158
-rw-r--r--fs/ubifs/debug.h217
-rw-r--r--fs/ubifs/dir.c10
-rw-r--r--fs/ubifs/file.c4
-rw-r--r--fs/ubifs/gc.c2
-rw-r--r--fs/ubifs/io.c74
-rw-r--r--fs/ubifs/journal.c10
-rw-r--r--fs/ubifs/log.c18
-rw-r--r--fs/ubifs/lprops.c18
-rw-r--r--fs/ubifs/lpt.c78
-rw-r--r--fs/ubifs/lpt_commit.c86
-rw-r--r--fs/ubifs/master.c8
-rw-r--r--fs/ubifs/orphan.c25
-rw-r--r--fs/ubifs/recovery.c43
-rw-r--r--fs/ubifs/replay.c27
-rw-r--r--fs/ubifs/sb.c26
-rw-r--r--fs/ubifs/scan.c14
-rw-r--r--fs/ubifs/super.c31
-rw-r--r--fs/ubifs/tnc.c26
-rw-r--r--fs/ubifs/tnc_commit.c28
-rw-r--r--fs/ubifs/tnc_misc.c36
-rw-r--r--fs/ubifs/ubifs.h26
-rw-r--r--fs/ubifs/xattr.c4
-rw-r--r--fs/xfs/Makefile2
-rw-r--r--fs/xfs/xfs_ag.h18
-rw-r--r--fs/xfs/xfs_alloc.c585
-rw-r--r--fs/xfs/xfs_alloc.h28
-rw-r--r--fs/xfs/xfs_alloc_btree.c9
-rw-r--r--fs/xfs/xfs_aops.c218
-rw-r--r--fs/xfs/xfs_attr.c25
-rw-r--r--fs/xfs/xfs_attr_leaf.c3
-rw-r--r--fs/xfs/xfs_bmap.c32
-rw-r--r--fs/xfs/xfs_bmap.h3
-rw-r--r--fs/xfs/xfs_bmap_btree.c1
-rw-r--r--fs/xfs/xfs_btree.c1
-rw-r--r--fs/xfs/xfs_buf.c593
-rw-r--r--fs/xfs/xfs_buf.h96
-rw-r--r--fs/xfs/xfs_buf_item.c123
-rw-r--r--fs/xfs/xfs_da_btree.c17
-rw-r--r--fs/xfs/xfs_dfrag.c2
-rw-r--r--fs/xfs/xfs_dir2.c1
-rw-r--r--fs/xfs/xfs_dir2_block.c1
-rw-r--r--fs/xfs/xfs_dir2_data.c1
-rw-r--r--fs/xfs/xfs_dir2_leaf.c1
-rw-r--r--fs/xfs/xfs_dir2_node.c1
-rw-r--r--fs/xfs/xfs_dir2_sf.c1
-rw-r--r--fs/xfs/xfs_discard.c6
-rw-r--r--fs/xfs/xfs_dquot.c91
-rw-r--r--fs/xfs/xfs_dquot.h3
-rw-r--r--fs/xfs/xfs_dquot_item.c162
-rw-r--r--fs/xfs/xfs_error.c1
-rw-r--r--fs/xfs/xfs_export.c1
-rw-r--r--fs/xfs/xfs_extent_busy.c603
-rw-r--r--fs/xfs/xfs_extent_busy.h69
-rw-r--r--fs/xfs/xfs_extfree_item.c59
-rw-r--r--fs/xfs/xfs_file.c327
-rw-r--r--fs/xfs/xfs_fsops.c82
-rw-r--r--fs/xfs/xfs_ialloc.c10
-rw-r--r--fs/xfs/xfs_ialloc.h9
-rw-r--r--fs/xfs/xfs_ialloc_btree.c1
-rw-r--r--fs/xfs/xfs_iget.c24
-rw-r--r--fs/xfs/xfs_inode.c132
-rw-r--r--fs/xfs/xfs_inode.h5
-rw-r--r--fs/xfs/xfs_inode_item.c176
-rw-r--r--fs/xfs/xfs_inode_item.h2
-rw-r--r--fs/xfs/xfs_inum.h5
-rw-r--r--fs/xfs/xfs_ioctl.c2
-rw-r--r--fs/xfs/xfs_ioctl32.c2
-rw-r--r--fs/xfs/xfs_iomap.c59
-rw-r--r--fs/xfs/xfs_iops.c15
-rw-r--r--fs/xfs/xfs_itable.c1
-rw-r--r--fs/xfs/xfs_log.c49
-rw-r--r--fs/xfs/xfs_log.h1
-rw-r--r--fs/xfs/xfs_log_cil.c253
-rw-r--r--fs/xfs/xfs_log_priv.h2
-rw-r--r--fs/xfs/xfs_log_recover.c103
-rw-r--r--fs/xfs/xfs_message.c1
-rw-r--r--fs/xfs/xfs_mount.c77
-rw-r--r--fs/xfs/xfs_mount.h2
-rw-r--r--fs/xfs/xfs_qm.c196
-rw-r--r--fs/xfs/xfs_qm_bhv.c2
-rw-r--r--fs/xfs/xfs_qm_syscalls.c1
-rw-r--r--fs/xfs/xfs_quotaops.c1
-rw-r--r--fs/xfs/xfs_rename.c1
-rw-r--r--fs/xfs/xfs_rtalloc.c10
-rw-r--r--fs/xfs/xfs_rw.c156
-rw-r--r--fs/xfs/xfs_rw.h47
-rw-r--r--fs/xfs/xfs_super.c49
-rw-r--r--fs/xfs/xfs_sync.c281
-rw-r--r--fs/xfs/xfs_trace.c2
-rw-r--r--fs/xfs/xfs_trace.h53
-rw-r--r--fs/xfs/xfs_trans.c7
-rw-r--r--fs/xfs/xfs_trans.h18
-rw-r--r--fs/xfs/xfs_trans_ail.c207
-rw-r--r--fs/xfs/xfs_trans_buf.c126
-rw-r--r--fs/xfs/xfs_trans_dquot.c2
-rw-r--r--fs/xfs/xfs_trans_extfree.c1
-rw-r--r--fs/xfs/xfs_trans_inode.c2
-rw-r--r--fs/xfs/xfs_trans_priv.h12
-rw-r--r--fs/xfs/xfs_types.h5
-rw-r--r--fs/xfs/xfs_utils.c2
-rw-r--r--fs/xfs/xfs_vnodeops.c31
-rw-r--r--include/acpi/acpi_bus.h36
-rw-r--r--include/asm-generic/gpio.h6
-rw-r--r--include/asm-generic/vmlinux.lds.h2
-rw-r--r--include/drm/drm.h6
-rw-r--r--include/drm/drmP.h19
-rw-r--r--include/drm/drm_crtc.h86
-rw-r--r--include/drm/drm_crtc_helper.h23
-rw-r--r--include/drm/drm_dp_helper.h8
-rw-r--r--include/drm/drm_edid.h26
-rw-r--r--include/drm/drm_fixed.h1
-rw-r--r--include/drm/drm_mode.h16
-rw-r--r--include/drm/exynos_drm.h99
-rw-r--r--include/drm/i915_drm.h3
-rw-r--r--include/drm/radeon_drm.h1
-rw-r--r--include/drm/ttm/ttm_bo_api.h9
-rw-r--r--include/drm/ttm/ttm_bo_driver.h2
-rw-r--r--include/linux/Kbuild4
-rw-r--r--include/linux/alarmtimer.h3
-rw-r--r--include/linux/basic_mmio_gpio.h6
-rw-r--r--include/linux/bcma/bcma.h8
-rw-r--r--include/linux/bcma/bcma_driver_pci.h11
-rw-r--r--include/linux/bootmem.h3
-rw-r--r--include/linux/capability.h7
-rw-r--r--include/linux/cgroup.h81
-rw-r--r--include/linux/cpu.h2
-rw-r--r--include/linux/cred.h33
-rw-r--r--include/linux/cs5535.h1
-rw-r--r--include/linux/device.h34
-rw-r--r--include/linux/dlm.h1
-rw-r--r--include/linux/dvb/frontend.h51
-rw-r--r--include/linux/dvb/version.h2
-rw-r--r--include/linux/dynamic_debug.h22
-rw-r--r--include/linux/eventpoll.h12
-rw-r--r--include/linux/extcon.h324
-rw-r--r--include/linux/extcon/extcon_gpio.h52
-rw-r--r--include/linux/firewire.h17
-rw-r--r--include/linux/fixp-arith.h (renamed from drivers/input/fixp-arith.h)0
-rw-r--r--include/linux/fs.h42
-rw-r--r--include/linux/fsl_devices.h9
-rw-r--r--include/linux/ftrace.h19
-rw-r--r--include/linux/gameport.h13
-rw-r--r--include/linux/generic_serial.h64
-rw-r--r--include/linux/gpio.h59
-rw-r--r--include/linux/hid.h36
-rw-r--r--include/linux/hidraw.h4
-rw-r--r--include/linux/hyperv.h4
-rw-r--r--include/linux/i2c-pnx.h10
-rw-r--r--include/linux/i2c/adp5588.h1
-rw-r--r--include/linux/i2o-dev.h2
-rw-r--r--include/linux/if_arp.h2
-rw-r--r--include/linux/iio/buffer.h (renamed from drivers/staging/iio/buffer.h)4
-rw-r--r--include/linux/iio/consumer.h (renamed from drivers/staging/iio/consumer.h)2
-rw-r--r--include/linux/iio/driver.h (renamed from drivers/staging/iio/driver.h)0
-rw-r--r--include/linux/iio/events.h (renamed from drivers/staging/iio/events.h)2
-rw-r--r--include/linux/iio/iio.h (renamed from drivers/staging/iio/iio.h)101
-rw-r--r--include/linux/iio/kfifo_buf.h (renamed from drivers/staging/iio/kfifo_buf.h)4
-rw-r--r--include/linux/iio/machine.h (renamed from drivers/staging/iio/machine.h)0
-rw-r--r--include/linux/iio/sysfs.h (renamed from drivers/staging/iio/sysfs.h)0
-rw-r--r--include/linux/iio/trigger.h (renamed from drivers/staging/iio/trigger.h)8
-rw-r--r--include/linux/iio/trigger_consumer.h (renamed from drivers/staging/iio/trigger_consumer.h)0
-rw-r--r--include/linux/iio/types.h (renamed from drivers/staging/iio/types.h)2
-rw-r--r--include/linux/input/lm8333.h24
-rw-r--r--include/linux/input/matrix_keypad.h54
-rw-r--r--include/linux/input/navpoint.h12
-rw-r--r--include/linux/ipx.h2
-rw-r--r--include/linux/irq.h5
-rw-r--r--include/linux/irqdomain.h3
-rw-r--r--include/linux/isdn.h26
-rw-r--r--include/linux/kernel.h13
-rw-r--r--include/linux/libata.h1
-rw-r--r--include/linux/lockdep.h18
-rw-r--r--include/linux/mca-legacy.h66
-rw-r--r--include/linux/mca.h148
-rw-r--r--include/linux/mei.h (renamed from drivers/staging/mei/mei.h)0
-rw-r--r--include/linux/mfd/abx500.h5
-rw-r--r--include/linux/mfd/abx500/ab5500.h140
-rw-r--r--include/linux/mfd/asic3.h1
-rw-r--r--include/linux/mfd/db5500-prcmu.h105
-rw-r--r--include/linux/mfd/dbx500-prcmu.h242
-rw-r--r--include/linux/mfd/max8997.h23
-rw-r--r--include/linux/mfd/mc13xxx.h11
-rw-r--r--include/linux/mfd/rc5t583.h2
-rw-r--r--include/linux/mfd/wm831x/pdata.h2
-rw-r--r--include/linux/micrel_phy.h2
-rw-r--r--include/linux/mm_types.h2
-rw-r--r--include/linux/mmzone.h2
-rw-r--r--include/linux/mod_devicetable.h4
-rw-r--r--include/linux/moduleparam.h3
-rw-r--r--include/linux/mtd/ubi.h31
-rw-r--r--include/linux/nfc/pn544.h7
-rw-r--r--include/linux/nl80211.h8
-rw-r--r--include/linux/of_gpio.h1
-rw-r--r--include/linux/of_irq.h12
-rw-r--r--include/linux/of_serial.h17
-rw-r--r--include/linux/of_spi.h23
-rw-r--r--include/linux/pagemap.h64
-rw-r--r--include/linux/percpu.h54
-rw-r--r--include/linux/perf_event.h5
-rw-r--r--include/linux/pid_namespace.h2
-rw-r--r--include/linux/pinctrl/pinctrl-state.h13
-rw-r--r--include/linux/platform_data/at91_adc.h61
-rw-r--r--include/linux/platform_data/ehci-sh.h28
-rw-r--r--include/linux/platform_data/emif_plat.h128
-rw-r--r--include/linux/platform_data/gpio-em.h10
-rw-r--r--include/linux/platform_data/ina2xx.h19
-rw-r--r--include/linux/platform_data/s3c-hsotg.h (renamed from arch/arm/plat-samsung/include/plat/udc-hs.h)5
-rw-r--r--include/linux/platform_data/tegra_usb.h1
-rw-r--r--include/linux/pm.h2
-rw-r--r--include/linux/pm_domain.h13
-rw-r--r--include/linux/pm_runtime.h3
-rw-r--r--include/linux/pm_wakeup.h15
-rw-r--r--include/linux/printk.h13
-rw-r--r--include/linux/proc_fs.h4
-rw-r--r--include/linux/pstore_ram.h (renamed from drivers/staging/android/persistent_ram.h)30
-rw-r--r--include/linux/quotaops.h4
-rw-r--r--include/linux/raid/md_p.h15
-rw-r--r--include/linux/raid/pq.h18
-rw-r--r--include/linux/ramoops.h17
-rw-r--r--include/linux/rational.h2
-rw-r--r--include/linux/res_counter.h2
-rw-r--r--include/linux/ring_buffer.h6
-rw-r--r--include/linux/sched.h62
-rw-r--r--include/linux/serial.h2
-rw-r--r--include/linux/serial_8250.h3
-rw-r--r--include/linux/serial_core.h5
-rw-r--r--include/linux/serial_sci.h2
-rw-r--r--include/linux/serio.h13
-rw-r--r--include/linux/sh_clk.h34
-rw-r--r--include/linux/sh_intc.h1
-rw-r--r--include/linux/shmem_fs.h4
-rw-r--r--include/linux/signal.h1
-rw-r--r--include/linux/spi/eeprom.h10
-rw-r--r--include/linux/spi/rspi.h31
-rw-r--r--include/linux/ssb/ssb.h1
-rw-r--r--include/linux/ssb/ssb_regs.h61
-rw-r--r--include/linux/stat.h5
-rw-r--r--include/linux/suspend.h14
-rw-r--r--include/linux/sysfs.h12
-rw-r--r--include/linux/tcp.h2
-rw-r--r--include/linux/ti_wilink_st.h2
-rw-r--r--include/linux/time.h1
-rw-r--r--include/linux/topology.h46
-rw-r--r--include/linux/tty.h23
-rw-r--r--include/linux/tty_ldisc.h2
-rw-r--r--include/linux/uidgid.h200
-rw-r--r--include/linux/uprobes.h165
-rw-r--r--include/linux/usb.h79
-rw-r--r--include/linux/usb/ch11.h2
-rw-r--r--include/linux/usb/ch9.h58
-rw-r--r--include/linux/usb/chipidea.h28
-rw-r--r--include/linux/usb/composite.h6
-rw-r--r--include/linux/usb/functionfs.h4
-rw-r--r--include/linux/usb/gpio_vbus.h2
-rw-r--r--include/linux/usb/hcd.h32
-rw-r--r--include/linux/usb/isp1301.h80
-rw-r--r--include/linux/usb/langwell_udc.h310
-rw-r--r--include/linux/usb/serial.h34
-rw-r--r--include/linux/user_namespace.h39
-rw-r--r--include/linux/uuid.h4
-rw-r--r--include/linux/v4l2-dv-timings.h816
-rw-r--r--include/linux/v4l2-subdev.h41
-rw-r--r--include/linux/vga_switcheroo.h19
-rw-r--r--include/linux/vgaarb.h7
-rw-r--r--include/linux/videodev2.h372
-rw-r--r--include/linux/vme.h (renamed from drivers/staging/vme/vme.h)0
-rw-r--r--include/linux/vt_kern.h1
-rw-r--r--include/media/media-entity.h5
-rw-r--r--include/media/mt9p031.h19
-rw-r--r--include/media/omap3isp.h29
-rw-r--r--include/media/rc-map.h3
-rw-r--r--include/media/s5p_fimc.h16
-rw-r--r--include/media/saa7146.h4
-rw-r--r--include/media/saa7146_vv.h25
-rw-r--r--include/media/sh_mobile_ceu.h1
-rw-r--r--include/media/smiapp.h84
-rw-r--r--include/media/soc_camera.h6
-rw-r--r--include/media/soc_mediabus.h21
-rw-r--r--include/media/v4l2-ctrls.h40
-rw-r--r--include/media/v4l2-dev.h25
-rw-r--r--include/media/v4l2-event.h24
-rw-r--r--include/media/v4l2-ioctl.h6
-rw-r--r--include/media/v4l2-subdev.h55
-rw-r--r--include/media/videobuf-dma-contig.h10
-rw-r--r--include/memory/jedec_ddr.h175
-rw-r--r--include/mtd/ubi-user.h34
-rw-r--r--include/net/bluetooth/bluetooth.h32
-rw-r--r--include/net/bluetooth/hci.h8
-rw-r--r--include/net/bluetooth/hci_core.h67
-rw-r--r--include/net/bluetooth/l2cap.h93
-rw-r--r--include/net/bluetooth/mgmt.h9
-rw-r--r--include/net/bluetooth/smp.h2
-rw-r--r--include/net/cfg80211.h6
-rw-r--r--include/net/mac80211.h12
-rw-r--r--include/net/nfc/hci.h6
-rw-r--r--include/net/nfc/nfc.h19
-rw-r--r--include/net/nfc/shdlc.h2
-rw-r--r--include/net/sock.h12
-rw-r--r--include/net/tcp_memcontrol.h4
-rw-r--r--include/sound/asound.h14
-rw-r--r--include/sound/asoundef.h41
-rw-r--r--include/sound/cs42l52.h36
-rw-r--r--include/sound/max98095.h12
-rw-r--r--include/sound/sh_fsi.h18
-rw-r--r--include/sound/simple_card.h38
-rw-r--r--include/sound/soc-dai.h4
-rw-r--r--include/sound/soc-dapm.h28
-rw-r--r--include/sound/soc-dpcm.h138
-rw-r--r--include/sound/soc.h118
-rw-r--r--include/trace/events/asoc.h80
-rw-r--r--include/trace/events/ext3.h4
-rw-r--r--include/trace/events/ext4.h4
-rw-r--r--include/trace/events/power.h34
-rw-r--r--include/trace/events/workqueue.h2
-rw-r--r--include/video/omap-panel-nokia-dsi.h3
-rw-r--r--include/video/omap-panel-tfp410.h (renamed from include/video/omap-panel-dvi.h)18
-rw-r--r--include/video/omapdss.h28
-rw-r--r--init/Kconfig148
-rw-r--r--init/main.c33
-rw-r--r--ipc/mqueue.c10
-rw-r--r--ipc/namespace.c2
-rw-r--r--kernel/capability.c21
-rw-r--r--kernel/cgroup.c570
-rw-r--r--kernel/cgroup_freezer.c11
-rw-r--r--kernel/compat.c10
-rw-r--r--kernel/cpuset.c31
-rw-r--r--kernel/cred.c44
-rw-r--r--kernel/events/Makefile3
-rw-r--r--kernel/events/core.c11
-rw-r--r--kernel/events/uprobes.c1667
-rw-r--r--kernel/exit.c6
-rw-r--r--kernel/extable.c8
-rw-r--r--kernel/fork.c11
-rw-r--r--kernel/groups.c50
-rw-r--r--kernel/irq/irqdomain.c106
-rw-r--r--kernel/irq/manage.c6
-rw-r--r--kernel/kfifo.c1
-rw-r--r--kernel/module.c5
-rw-r--r--kernel/params.c62
-rw-r--r--kernel/pid.c3
-rw-r--r--kernel/power/Kconfig27
-rw-r--r--kernel/power/Makefile2
-rw-r--r--kernel/power/autosleep.c127
-rw-r--r--kernel/power/hibernate.c13
-rw-r--r--kernel/power/main.c160
-rw-r--r--kernel/power/power.h27
-rw-r--r--kernel/power/swap.c62
-rw-r--r--kernel/power/wakelock.c259
-rw-r--r--kernel/printk.c1390
-rw-r--r--kernel/ptrace.c15
-rw-r--r--kernel/res_counter.c71
-rw-r--r--kernel/sched/core.c443
-rw-r--r--kernel/sched/debug.c12
-rw-r--r--kernel/sched/fair.c462
-rw-r--r--kernel/sched/idle_task.c2
-rw-r--r--kernel/sched/rt.c56
-rw-r--r--kernel/sched/sched.h8
-rw-r--r--kernel/semaphore.c2
-rw-r--r--kernel/signal.c80
-rw-r--r--kernel/sys.c266
-rw-r--r--kernel/time/Kconfig58
-rw-r--r--kernel/time/alarmtimer.c4
-rw-r--r--kernel/time/ntp.c8
-rw-r--r--kernel/time/timekeeping.c4
-rw-r--r--kernel/timer.c12
-rw-r--r--kernel/trace/Kconfig23
-rw-r--r--kernel/trace/Makefile3
-rw-r--r--kernel/trace/ftrace.c242
-rw-r--r--kernel/trace/ring_buffer.c585
-rw-r--r--kernel/trace/trace.c503
-rw-r--r--kernel/trace/trace.h9
-rw-r--r--kernel/trace/trace_kprobe.c899
-rw-r--r--kernel/trace/trace_printk.c4
-rw-r--r--kernel/trace/trace_probe.c839
-rw-r--r--kernel/trace/trace_probe.h161
-rw-r--r--kernel/trace/trace_uprobe.c788
-rw-r--r--kernel/trace/trace_workqueue.c300
-rw-r--r--kernel/uid16.c48
-rw-r--r--kernel/user.c51
-rw-r--r--kernel/user_namespace.c595
-rw-r--r--kernel/utsname.c2
-rw-r--r--kernel/workqueue.c21
-rw-r--r--lib/Kconfig8
-rw-r--r--lib/Kconfig.debug42
-rw-r--r--lib/Makefile2
-rw-r--r--lib/dynamic_debug.c190
-rw-r--r--lib/jedec_ddr_data.c135
-rw-r--r--lib/kobject.c14
-rw-r--r--lib/raid6/Makefile2
-rw-r--r--lib/raid6/algos.c127
-rw-r--r--lib/raid6/mktables.c25
-rw-r--r--lib/raid6/recov.c15
-rw-r--r--lib/raid6/recov_ssse3.c335
-rw-r--r--lib/raid6/test/Makefile2
-rw-r--r--lib/raid6/test/test.c32
-rw-r--r--lib/raid6/x86.h15
-rw-r--r--lib/rational.c2
-rw-r--r--mm/memcontrol.c115
-rw-r--r--mm/memory.c3
-rw-r--r--mm/mempolicy.c45
-rw-r--r--mm/migrate.c4
-rw-r--r--mm/mmap.c33
-rw-r--r--mm/oom_kill.c4
-rw-r--r--mm/page_alloc.c13
-rw-r--r--mm/shmem.c22
-rw-r--r--net/atm/lec.h4
-rw-r--r--net/bluetooth/af_bluetooth.c8
-rw-r--r--net/bluetooth/bnep/core.c2
-rw-r--r--net/bluetooth/hci_conn.c56
-rw-r--r--net/bluetooth/hci_core.c267
-rw-r--r--net/bluetooth/hci_event.c75
-rw-r--r--net/bluetooth/hci_sysfs.c5
-rw-r--r--net/bluetooth/hidp/core.c27
-rw-r--r--net/bluetooth/l2cap_core.c762
-rw-r--r--net/bluetooth/l2cap_sock.c76
-rw-r--r--net/bluetooth/mgmt.c286
-rw-r--r--net/bluetooth/rfcomm/sock.c14
-rw-r--r--net/bluetooth/rfcomm/tty.c137
-rw-r--r--net/bluetooth/sco.c75
-rw-r--r--net/bluetooth/smp.c2
-rw-r--r--net/caif/Kconfig2
-rw-r--r--net/core/netprio_cgroup.c30
-rw-r--r--net/core/sock.c14
-rw-r--r--net/ipv4/fib_semantics.c12
-rw-r--r--net/ipv4/ping.c11
-rw-r--r--net/ipv4/route.c1
-rw-r--r--net/ipv4/tcp.c2
-rw-r--r--net/ipv4/tcp_input.c5
-rw-r--r--net/ipv4/tcp_memcontrol.c77
-rw-r--r--net/ipv4/udp.c30
-rw-r--r--net/mac80211/agg-tx.c10
-rw-r--r--net/mac80211/debugfs_netdev.c2
-rw-r--r--net/mac80211/ibss.c5
-rw-r--r--net/mac80211/iface.c4
-rw-r--r--net/mac80211/main.c3
-rw-r--r--net/mac80211/mesh.c6
-rw-r--r--net/mac80211/mesh_hwmp.c5
-rw-r--r--net/mac80211/mesh_plink.c65
-rw-r--r--net/mac80211/rx.c6
-rw-r--r--net/mac80211/wep.c15
-rw-r--r--net/mac80211/wpa.c10
-rw-r--r--net/netfilter/xt_TEE.c12
-rw-r--r--net/nfc/core.c112
-rw-r--r--net/nfc/hci/Kconfig1
-rw-r--r--net/nfc/hci/core.c78
-rw-r--r--net/nfc/hci/shdlc.c12
-rw-r--r--net/nfc/llcp/commands.c4
-rw-r--r--net/nfc/llcp/llcp.c7
-rw-r--r--net/nfc/llcp/sock.c57
-rw-r--r--net/nfc/nci/core.c27
-rw-r--r--net/nfc/nci/data.c8
-rw-r--r--net/nfc/nci/lib.c1
-rw-r--r--net/nfc/nci/ntf.c2
-rw-r--r--net/nfc/netlink.c6
-rw-r--r--net/nfc/nfc.h2
-rw-r--r--net/sched/cls_cgroup.c31
-rw-r--r--net/socket.c4
-rw-r--r--net/sunrpc/auth_generic.c4
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c7
-rw-r--r--net/sunrpc/auth_unix.c15
-rw-r--r--net/sunrpc/svcauth_unix.c18
-rw-r--r--net/wireless/chan.c2
-rw-r--r--net/wireless/core.c4
-rw-r--r--net/wireless/core.h2
-rw-r--r--net/wireless/nl80211.c69
-rw-r--r--net/wireless/util.c2
-rw-r--r--scripts/.gitignore1
-rw-r--r--scripts/Makefile3
-rw-r--r--scripts/kconfig/mconf.c2
-rw-r--r--scripts/kconfig/nconf.c2
-rw-r--r--scripts/mod/file2alias.c5
-rw-r--r--scripts/mod/modpost.c17
-rw-r--r--scripts/sortextable.c322
-rw-r--r--scripts/sortextable.h191
-rw-r--r--security/commoncap.c61
-rw-r--r--security/device_cgroup.c10
-rw-r--r--security/keys/key.c2
-rw-r--r--security/keys/permission.c5
-rw-r--r--security/keys/process_keys.c2
-rw-r--r--sound/atmel/ac97c.c2
-rw-r--r--sound/core/jack.c5
-rw-r--r--sound/core/pcm_lib.c18
-rw-r--r--sound/core/pcm_native.c12
-rw-r--r--sound/core/sound_oss.c6
-rw-r--r--sound/drivers/aloop.c62
-rw-r--r--sound/firewire/amdtp.c49
-rw-r--r--sound/firewire/amdtp.h29
-rw-r--r--sound/firewire/cmp.c2
-rw-r--r--sound/firewire/lib.c28
-rw-r--r--sound/firewire/lib.h1
-rw-r--r--sound/i2c/other/tea575x-tuner.c3
-rw-r--r--sound/isa/als100.c2
-rw-r--r--sound/pci/Kconfig2
-rw-r--r--sound/pci/ad1889.c15
-rw-r--r--sound/pci/ali5451/ali5451.c15
-rw-r--r--sound/pci/als300.c15
-rw-r--r--sound/pci/als4000.c15
-rw-r--r--sound/pci/atiixp.c16
-rw-r--r--sound/pci/atiixp_modem.c16
-rw-r--r--sound/pci/au88x0/au88x0.c17
-rw-r--r--sound/pci/aw2/aw2-alsa.c23
-rw-r--r--sound/pci/azt3328.c23
-rw-r--r--sound/pci/bt87x.c19
-rw-r--r--sound/pci/ca0106/ca0106_main.c17
-rw-r--r--sound/pci/cmipci.c15
-rw-r--r--sound/pci/cs4281.c15
-rw-r--r--sound/pci/cs46xx/cs46xx.c15
-rw-r--r--sound/pci/cs5530.c16
-rw-r--r--sound/pci/cs5535audio/cs5535audio.c15
-rw-r--r--sound/pci/ctxfi/xfi.c13
-rw-r--r--sound/pci/echoaudio/echoaudio.c22
-rw-r--r--sound/pci/emu10k1/emu10k1.c15
-rw-r--r--sound/pci/emu10k1/emu10k1x.c17
-rw-r--r--sound/pci/ens1370.c15
-rw-r--r--sound/pci/es1938.c15
-rw-r--r--sound/pci/es1968.c15
-rw-r--r--sound/pci/fm801.c15
-rw-r--r--sound/pci/hda/Makefile2
-rw-r--r--sound/pci/hda/hda_auto_parser.c760
-rw-r--r--sound/pci/hda/hda_auto_parser.h160
-rw-r--r--sound/pci/hda/hda_codec.c1027
-rw-r--r--sound/pci/hda/hda_codec.h15
-rw-r--r--sound/pci/hda/hda_intel.c57
-rw-r--r--sound/pci/hda/hda_jack.c1
-rw-r--r--sound/pci/hda/hda_jack.h2
-rw-r--r--sound/pci/hda/hda_local.h122
-rw-r--r--sound/pci/hda/patch_analog.c14
-rw-r--r--sound/pci/hda/patch_ca0110.c8
-rw-r--r--sound/pci/hda/patch_ca0132.c9
-rw-r--r--sound/pci/hda/patch_cirrus.c30
-rw-r--r--sound/pci/hda/patch_cmedia.c1
-rw-r--r--sound/pci/hda/patch_conexant.c186
-rw-r--r--sound/pci/hda/patch_hdmi.c4
-rw-r--r--sound/pci/hda/patch_realtek.c467
-rw-r--r--sound/pci/hda/patch_sigmatel.c120
-rw-r--r--sound/pci/hda/patch_via.c33
-rw-r--r--sound/pci/ice1712/ice1712.c15
-rw-r--r--sound/pci/ice1712/ice1724.c15
-rw-r--r--sound/pci/intel8x0.c16
-rw-r--r--sound/pci/intel8x0m.c16
-rw-r--r--sound/pci/korg1212/korg1212.c15
-rw-r--r--sound/pci/lola/lola.c15
-rw-r--r--sound/pci/lx6464es/lx6464es.c17
-rw-r--r--sound/pci/maestro3.c15
-rw-r--r--sound/pci/mixart/mixart.c15
-rw-r--r--sound/pci/nm256/nm256.c16
-rw-r--r--sound/pci/oxygen/oxygen.c21
-rw-r--r--sound/pci/oxygen/virtuoso.c13
-rw-r--r--sound/pci/oxygen/xonar_dg.c7
-rw-r--r--sound/pci/pcxhr/pcxhr.c15
-rw-r--r--sound/pci/riptide/riptide.c3
-rw-r--r--sound/pci/rme32.c15
-rw-r--r--sound/pci/rme96.c15
-rw-r--r--sound/pci/rme9652/hdsp.c15
-rw-r--r--sound/pci/rme9652/hdspm.c16
-rw-r--r--sound/pci/rme9652/rme9652.c15
-rw-r--r--sound/pci/sis7019.c13
-rw-r--r--sound/pci/sonicvibes.c15
-rw-r--r--sound/pci/trident/trident.c15
-rw-r--r--sound/pci/via82xx.c15
-rw-r--r--sound/pci/via82xx_modem.c15
-rw-r--r--sound/pci/vx222/vx222.c15
-rw-r--r--sound/pci/ymfpci/ymfpci.c15
-rw-r--r--sound/sh/sh_dac_audio.c4
-rw-r--r--sound/soc/Kconfig5
-rw-r--r--sound/soc/Makefile3
-rw-r--r--sound/soc/blackfin/bf5xx-ssm2602.c37
-rw-r--r--sound/soc/codecs/Kconfig20
-rw-r--r--sound/soc/codecs/Makefile12
-rw-r--r--sound/soc/codecs/ac97.c6
-rw-r--r--sound/soc/codecs/ad1836.c4
-rw-r--r--sound/soc/codecs/ad193x.c4
-rw-r--r--sound/soc/codecs/adau1701.c3
-rw-r--r--sound/soc/codecs/ak4104.c3
-rw-r--r--sound/soc/codecs/ak4535.c3
-rw-r--r--sound/soc/codecs/ak4641.c113
-rw-r--r--sound/soc/codecs/alc5623.c23
-rw-r--r--sound/soc/codecs/alc5632.c31
-rw-r--r--sound/soc/codecs/cs4270.c11
-rw-r--r--sound/soc/codecs/cs4271.c3
-rw-r--r--sound/soc/codecs/cs42l51.c9
-rw-r--r--sound/soc/codecs/cs42l52.c1295
-rw-r--r--sound/soc/codecs/cs42l52.h274
-rw-r--r--sound/soc/codecs/cs42l73.c93
-rw-r--r--sound/soc/codecs/da7210.c379
-rw-r--r--sound/soc/codecs/jz4740.c3
-rw-r--r--sound/soc/codecs/lm49453.c1550
-rw-r--r--sound/soc/codecs/lm49453.h380
-rw-r--r--sound/soc/codecs/max98095.c158
-rw-r--r--sound/soc/codecs/max98095.h22
-rw-r--r--sound/soc/codecs/mc13783.c786
-rw-r--r--sound/soc/codecs/mc13783.h28
-rw-r--r--sound/soc/codecs/ml26124.c681
-rw-r--r--sound/soc/codecs/ml26124.h184
-rw-r--r--sound/soc/codecs/omap-hdmi.c69
-rw-r--r--sound/soc/codecs/rt5631.c110
-rw-r--r--sound/soc/codecs/sgtl5000.c25
-rw-r--r--sound/soc/codecs/ssm2602.c138
-rw-r--r--sound/soc/codecs/sta32x.c3
-rw-r--r--sound/soc/codecs/tlv320aic23.c13
-rw-r--r--sound/soc/codecs/tlv320aic26.c3
-rw-r--r--sound/soc/codecs/tlv320aic3x.c21
-rw-r--r--sound/soc/codecs/tlv320dac33.c35
-rw-r--r--sound/soc/codecs/twl4030.c18
-rw-r--r--sound/soc/codecs/twl6040.c450
-rw-r--r--sound/soc/codecs/uda134x.c6
-rw-r--r--sound/soc/codecs/uda1380.c6
-rw-r--r--sound/soc/codecs/wl1273.c6
-rw-r--r--sound/soc/codecs/wm1250-ev1.c65
-rw-r--r--sound/soc/codecs/wm5100-tables.c125
-rw-r--r--sound/soc/codecs/wm5100.c47
-rw-r--r--sound/soc/codecs/wm5100.h159
-rw-r--r--sound/soc/codecs/wm8350.c187
-rw-r--r--sound/soc/codecs/wm8400.c135
-rw-r--r--sound/soc/codecs/wm8510.c3
-rw-r--r--sound/soc/codecs/wm8523.c3
-rw-r--r--sound/soc/codecs/wm8728.c3
-rw-r--r--sound/soc/codecs/wm8731.c37
-rw-r--r--sound/soc/codecs/wm8737.c3
-rw-r--r--sound/soc/codecs/wm8741.c3
-rw-r--r--sound/soc/codecs/wm8750.c3
-rw-r--r--sound/soc/codecs/wm8753.c6
-rw-r--r--sound/soc/codecs/wm8900.c3
-rw-r--r--sound/soc/codecs/wm8903.c3
-rw-r--r--sound/soc/codecs/wm8940.c3
-rw-r--r--sound/soc/codecs/wm8960.c3
-rw-r--r--sound/soc/codecs/wm8962.c18
-rw-r--r--sound/soc/codecs/wm8971.c3
-rw-r--r--sound/soc/codecs/wm8978.c3
-rw-r--r--sound/soc/codecs/wm8988.c3
-rw-r--r--sound/soc/codecs/wm8990.c3
-rw-r--r--sound/soc/codecs/wm8993.c86
-rw-r--r--sound/soc/codecs/wm8994.c290
-rw-r--r--sound/soc/codecs/wm8994.h3
-rw-r--r--sound/soc/codecs/wm8996.c12
-rw-r--r--sound/soc/codecs/wm9081.c5
-rw-r--r--sound/soc/codecs/wm9705.c6
-rw-r--r--sound/soc/codecs/wm9712.c10
-rw-r--r--sound/soc/codecs/wm_hubs.c220
-rw-r--r--sound/soc/codecs/wm_hubs.h12
-rw-r--r--sound/soc/ep93xx/ep93xx-ac97.c74
-rw-r--r--sound/soc/ep93xx/ep93xx-i2s.c49
-rw-r--r--sound/soc/fsl/Kconfig129
-rw-r--r--sound/soc/fsl/Makefile31
-rw-r--r--sound/soc/fsl/eukrea-tlv320.c (renamed from sound/soc/imx/eukrea-tlv320.c)2
-rw-r--r--sound/soc/fsl/fsl_ssi.c167
-rw-r--r--sound/soc/fsl/fsl_utils.c91
-rw-r--r--sound/soc/fsl/fsl_utils.h26
-rw-r--r--sound/soc/fsl/imx-audmux.c (renamed from sound/soc/imx/imx-audmux.c)0
-rw-r--r--sound/soc/fsl/imx-audmux.h (renamed from sound/soc/imx/imx-audmux.h)0
-rw-r--r--sound/soc/fsl/imx-mc13783.c156
-rw-r--r--sound/soc/fsl/imx-pcm-dma.c (renamed from sound/soc/imx/imx-pcm-dma-mx2.c)3
-rw-r--r--sound/soc/fsl/imx-pcm-fiq.c (renamed from sound/soc/imx/imx-pcm-fiq.c)0
-rw-r--r--sound/soc/fsl/imx-pcm.c (renamed from sound/soc/imx/imx-pcm.c)0
-rw-r--r--sound/soc/fsl/imx-pcm.h (renamed from sound/soc/imx/imx-pcm.h)1
-rw-r--r--sound/soc/fsl/imx-sgtl5000.c221
-rw-r--r--sound/soc/fsl/imx-ssi.c (renamed from sound/soc/imx/imx-ssi.c)2
-rw-r--r--sound/soc/fsl/imx-ssi.h (renamed from sound/soc/imx/imx-ssi.h)0
-rw-r--r--sound/soc/fsl/mpc8610_hpcd.c166
-rw-r--r--sound/soc/fsl/mx27vis-aic32x4.c (renamed from sound/soc/imx/mx27vis-aic32x4.c)0
-rw-r--r--sound/soc/fsl/p1022_ds.c158
-rw-r--r--sound/soc/fsl/phycore-ac97.c (renamed from sound/soc/imx/phycore-ac97.c)0
-rw-r--r--sound/soc/fsl/wm1133-ev1.c (renamed from sound/soc/imx/wm1133-ev1.c)0
-rw-r--r--sound/soc/generic/Kconfig4
-rw-r--r--sound/soc/generic/Makefile3
-rw-r--r--sound/soc/generic/simple-card.c114
-rw-r--r--sound/soc/imx/Kconfig79
-rw-r--r--sound/soc/imx/Makefile22
-rw-r--r--sound/soc/jz4740/jz4740-i2s.c4
-rw-r--r--sound/soc/mxs/mxs-pcm.c24
-rw-r--r--sound/soc/mxs/mxs-pcm.h3
-rw-r--r--sound/soc/mxs/mxs-saif.c100
-rw-r--r--sound/soc/mxs/mxs-saif.h1
-rw-r--r--sound/soc/mxs/mxs-sgtl5000.c50
-rw-r--r--sound/soc/omap/Kconfig1
-rw-r--r--sound/soc/pxa/pxa-ssp.c28
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.c4
-rw-r--r--sound/soc/samsung/littlemill.c102
-rw-r--r--sound/soc/samsung/lowland.c75
-rw-r--r--sound/soc/samsung/speyside.c33
-rw-r--r--sound/soc/sh/Kconfig24
-rw-r--r--sound/soc/sh/Makefile6
-rw-r--r--sound/soc/sh/fsi-ak4642.c108
-rw-r--r--sound/soc/sh/fsi-da7210.c81
-rw-r--r--sound/soc/sh/fsi-hdmi.c118
-rw-r--r--sound/soc/sh/fsi.c224
-rw-r--r--sound/soc/soc-core.c690
-rw-r--r--sound/soc/soc-dapm.c562
-rw-r--r--sound/soc/soc-jack.c5
-rw-r--r--sound/soc/soc-pcm.c1718
-rw-r--r--sound/soc/tegra/Kconfig68
-rw-r--r--sound/soc/tegra/Makefile20
-rw-r--r--sound/soc/tegra/tegra20_das.c233
-rw-r--r--sound/soc/tegra/tegra20_das.h134
-rw-r--r--sound/soc/tegra/tegra20_i2s.c494
-rw-r--r--sound/soc/tegra/tegra20_i2s.h164
-rw-r--r--sound/soc/tegra/tegra20_spdif.c404
-rw-r--r--sound/soc/tegra/tegra20_spdif.h471
-rw-r--r--sound/soc/tegra/tegra30_ahub.c631
-rw-r--r--sound/soc/tegra/tegra30_ahub.h483
-rw-r--r--sound/soc/tegra/tegra30_i2s.c536
-rw-r--r--sound/soc/tegra/tegra30_i2s.h242
-rw-r--r--sound/soc/tegra/tegra_alc5632.c48
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.c37
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.h9
-rw-r--r--sound/soc/tegra/tegra_das.c261
-rw-r--r--sound/soc/tegra/tegra_das.h135
-rw-r--r--sound/soc/tegra/tegra_i2s.c459
-rw-r--r--sound/soc/tegra/tegra_i2s.h166
-rw-r--r--sound/soc/tegra/tegra_pcm.c28
-rw-r--r--sound/soc/tegra/tegra_pcm.h5
-rw-r--r--sound/soc/tegra/tegra_spdif.c364
-rw-r--r--sound/soc/tegra/tegra_spdif.h473
-rw-r--r--sound/soc/tegra/tegra_wm8753.c224
-rw-r--r--sound/soc/tegra/tegra_wm8903.c29
-rw-r--r--sound/soc/tegra/trimslice.c41
-rw-r--r--sound/soc/ux500/Kconfig14
-rw-r--r--sound/soc/ux500/Makefile4
-rw-r--r--sound/soc/ux500/ux500_msp_dai.c843
-rw-r--r--sound/soc/ux500/ux500_msp_dai.h79
-rw-r--r--sound/soc/ux500/ux500_msp_i2s.c742
-rw-r--r--sound/soc/ux500/ux500_msp_i2s.h553
-rw-r--r--sound/sound_core.c2
-rw-r--r--sound/usb/card.c10
-rw-r--r--sound/usb/card.h86
-rw-r--r--sound/usb/endpoint.c1609
-rw-r--r--sound/usb/endpoint.h32
-rw-r--r--sound/usb/mixer.c50
-rw-r--r--sound/usb/mixer.h3
-rw-r--r--sound/usb/mixer_maps.c13
-rw-r--r--sound/usb/mixer_quirks.c472
-rw-r--r--sound/usb/pcm.c453
-rw-r--r--sound/usb/proc.c38
-rw-r--r--sound/usb/stream.c31
-rw-r--r--sound/usb/usbaudio.h2
-rw-r--r--tools/Makefile77
-rw-r--r--tools/lib/traceevent/Makefile303
-rw-r--r--tools/lib/traceevent/event-parse.c5065
-rw-r--r--tools/lib/traceevent/event-parse.h804
-rw-r--r--tools/lib/traceevent/event-utils.h80
-rw-r--r--tools/lib/traceevent/parse-filter.c2262
-rw-r--r--tools/lib/traceevent/parse-utils.c110
-rw-r--r--tools/lib/traceevent/trace-seq.c200
-rw-r--r--tools/perf/Documentation/perf-evlist.txt8
-rw-r--r--tools/perf/Documentation/perf-probe.txt19
-rw-r--r--tools/perf/Documentation/perf-record.txt2
-rw-r--r--tools/perf/Documentation/perfconfig.example1
-rw-r--r--tools/perf/Makefile132
-rw-r--r--tools/perf/builtin-buildid-list.c6
-rw-r--r--tools/perf/builtin-evlist.c103
-rw-r--r--tools/perf/builtin-inject.c5
-rw-r--r--tools/perf/builtin-kmem.c6
-rw-r--r--tools/perf/builtin-lock.c26
-rw-r--r--tools/perf/builtin-probe.c86
-rw-r--r--tools/perf/builtin-record.c69
-rw-r--r--tools/perf/builtin-report.c21
-rw-r--r--tools/perf/builtin-sched.c42
-rw-r--r--tools/perf/builtin-script.c2
-rw-r--r--tools/perf/builtin-stat.c86
-rw-r--r--tools/perf/builtin-test.c565
-rw-r--r--tools/perf/builtin-top.c59
-rw-r--r--tools/perf/perf.h8
-rw-r--r--tools/perf/ui/browser.c (renamed from tools/perf/util/ui/browser.c)116
-rw-r--r--tools/perf/ui/browser.h (renamed from tools/perf/util/ui/browser.h)9
-rw-r--r--tools/perf/ui/browsers/annotate.c867
-rw-r--r--tools/perf/ui/browsers/hists.c (renamed from tools/perf/util/ui/browsers/hists.c)26
-rw-r--r--tools/perf/ui/browsers/map.c (renamed from tools/perf/util/ui/browsers/map.c)6
-rw-r--r--tools/perf/ui/browsers/map.h (renamed from tools/perf/util/ui/browsers/map.h)0
-rw-r--r--tools/perf/ui/gtk/browser.c (renamed from tools/perf/util/gtk/browser.c)31
-rw-r--r--tools/perf/ui/gtk/gtk.h (renamed from tools/perf/util/gtk/gtk.h)0
-rw-r--r--tools/perf/ui/gtk/setup.c12
-rw-r--r--tools/perf/ui/helpline.c (renamed from tools/perf/util/ui/helpline.c)0
-rw-r--r--tools/perf/ui/helpline.h (renamed from tools/perf/util/ui/helpline.h)0
-rw-r--r--tools/perf/ui/keysyms.h (renamed from tools/perf/util/ui/keysyms.h)0
-rw-r--r--tools/perf/ui/libslang.h (renamed from tools/perf/util/ui/libslang.h)0
-rw-r--r--tools/perf/ui/progress.c (renamed from tools/perf/util/ui/progress.c)0
-rw-r--r--tools/perf/ui/progress.h (renamed from tools/perf/util/ui/progress.h)0
-rw-r--r--tools/perf/ui/setup.c45
-rw-r--r--tools/perf/ui/tui/setup.c (renamed from tools/perf/util/ui/setup.c)77
-rw-r--r--tools/perf/ui/ui.h (renamed from tools/perf/util/ui/ui.h)0
-rw-r--r--tools/perf/ui/util.c (renamed from tools/perf/util/ui/util.c)0
-rw-r--r--tools/perf/ui/util.h (renamed from tools/perf/util/ui/util.h)0
-rw-r--r--tools/perf/util/annotate.c599
-rw-r--r--tools/perf/util/annotate.h67
-rw-r--r--tools/perf/util/build-id.c2
-rw-r--r--tools/perf/util/cache.h24
-rw-r--r--tools/perf/util/debug.c1
-rw-r--r--tools/perf/util/debug.h2
-rw-r--r--tools/perf/util/evlist.c16
-rw-r--r--tools/perf/util/evlist.h4
-rw-r--r--tools/perf/util/evsel.c21
-rw-r--r--tools/perf/util/header.c27
-rw-r--r--tools/perf/util/header.h2
-rw-r--r--tools/perf/util/hist.c2
-rw-r--r--tools/perf/util/hist.h2
-rw-r--r--tools/perf/util/parse-events-test.c625
-rw-r--r--tools/perf/util/parse-events.c114
-rw-r--r--tools/perf/util/parse-events.h43
-rw-r--r--tools/perf/util/parse-events.l26
-rw-r--r--tools/perf/util/parse-events.y93
-rw-r--r--tools/perf/util/pmu.c74
-rw-r--r--tools/perf/util/probe-event.c422
-rw-r--r--tools/perf/util/probe-event.h12
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c16
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c16
-rw-r--r--tools/perf/util/session.c96
-rw-r--r--tools/perf/util/symbol.c8
-rw-r--r--tools/perf/util/symbol.h6
-rw-r--r--tools/perf/util/target.c142
-rw-r--r--tools/perf/util/target.h65
-rw-r--r--tools/perf/util/thread_map.h2
-rw-r--r--tools/perf/util/top.c19
-rw-r--r--tools/perf/util/top.h6
-rw-r--r--tools/perf/util/trace-event-info.c4
-rw-r--r--tools/perf/util/trace-event-parse.c3142
-rw-r--r--tools/perf/util/trace-event-read.c44
-rw-r--r--tools/perf/util/trace-event.h269
-rw-r--r--tools/perf/util/types.h5
-rw-r--r--tools/perf/util/ui/browsers/annotate.c433
-rw-r--r--tools/perf/util/usage.c38
-rw-r--r--tools/perf/util/util.c10
-rw-r--r--tools/perf/util/util.h5
-rw-r--r--tools/power/cpupower/man/cpupower-set.19
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.c35
-rw-r--r--tools/scripts/Makefile.include58
-rw-r--r--tools/testing/ktest/examples/README32
-rw-r--r--tools/testing/ktest/examples/crosstests.conf260
-rw-r--r--tools/testing/ktest/examples/include/bisect.conf90
-rw-r--r--tools/testing/ktest/examples/include/defaults.conf157
-rw-r--r--tools/testing/ktest/examples/include/min-config.conf60
-rw-r--r--tools/testing/ktest/examples/include/patchcheck.conf74
-rw-r--r--tools/testing/ktest/examples/include/tests.conf74
-rw-r--r--tools/testing/ktest/examples/kvm.conf88
-rw-r--r--tools/testing/ktest/examples/snowball.conf53
-rw-r--r--tools/testing/ktest/examples/test.conf62
-rwxr-xr-xtools/testing/ktest/ktest.pl36
-rw-r--r--tools/testing/ktest/sample.conf18
-rw-r--r--tools/usb/ffs-test.c2
-rw-r--r--tools/usb/testusb.c5
4457 files changed, 277707 insertions, 158807 deletions
diff --git a/CREDITS b/CREDITS
index 370b4c7da39b..d8fe12a9421f 100644
--- a/CREDITS
+++ b/CREDITS
@@ -3814,8 +3814,8 @@ D: INFO-SHEET, former maintainer
D: Author of the longest-living linux bug
N: Jonathan Woithe
-E: jwoithe@physics.adelaide.edu.au
-W: http://www.physics.adelaide.edu.au/~jwoithe
+E: jwoithe@just42.net
+W: http:/www.just42.net/jwoithe
D: ALS-007 sound card extensions to Sound Blaster driver
S: 20 Jordan St
S: Valley View, SA 5093
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
index 2214f123a976..49c051380daf 100644
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -218,8 +218,6 @@ m68k/
- directory with info about Linux on Motorola 68k architecture.
magic-number.txt
- list of magic numbers used to mark/protect kernel data structures.
-mca.txt
- - info on supporting Micro Channel Architecture (e.g. PS/2) systems.
md.txt
- info on boot arguments for the multiple devices driver.
memory-barriers.txt
diff --git a/Documentation/ABI/testing/debugfs-pfo-nx-crypto b/Documentation/ABI/testing/debugfs-pfo-nx-crypto
new file mode 100644
index 000000000000..685d5a448423
--- /dev/null
+++ b/Documentation/ABI/testing/debugfs-pfo-nx-crypto
@@ -0,0 +1,45 @@
+What: /sys/kernel/debug/nx-crypto/*
+Date: March 2012
+KernelVersion: 3.4
+Contact: Kent Yoder <key@linux.vnet.ibm.com>
+Description:
+
+ These debugfs interfaces are built by the nx-crypto driver, built in
+arch/powerpc/crypto/nx.
+
+Error Detection
+===============
+
+errors:
+- A u32 providing a total count of errors since the driver was loaded. The
+only errors counted here are those returned from the hcall, H_COP_OP.
+
+last_error:
+- The most recent non-zero return code from the H_COP_OP hcall. -EBUSY is not
+recorded here (the hcall will retry until -EBUSY goes away).
+
+last_error_pid:
+- The process ID of the process who received the most recent error from the
+hcall.
+
+Device Use
+==========
+
+aes_bytes:
+- The total number of bytes encrypted using AES in any of the driver's
+supported modes.
+
+aes_ops:
+- The total number of AES operations submitted to the hardware.
+
+sha256_bytes:
+- The total number of bytes hashed by the hardware using SHA-256.
+
+sha256_ops:
+- The total number of SHA-256 operations submitted to the hardware.
+
+sha512_bytes:
+- The total number of bytes hashed by the hardware using SHA-512.
+
+sha512_ops:
+- The total number of SHA-512 operations submitted to the hardware.
diff --git a/Documentation/ABI/testing/dev-kmsg b/Documentation/ABI/testing/dev-kmsg
new file mode 100644
index 000000000000..281ecc5f9709
--- /dev/null
+++ b/Documentation/ABI/testing/dev-kmsg
@@ -0,0 +1,90 @@
+What: /dev/kmsg
+Date: Mai 2012
+KernelVersion: 3.5
+Contact: Kay Sievers <kay@vrfy.org>
+Description: The /dev/kmsg character device node provides userspace access
+ to the kernel's printk buffer.
+
+ Injecting messages:
+ Every write() to the opened device node places a log entry in
+ the kernel's printk buffer.
+
+ The logged line can be prefixed with a <N> syslog prefix, which
+ carries the syslog priority and facility. The single decimal
+ prefix number is composed of the 3 lowest bits being the syslog
+ priority and the higher bits the syslog facility number.
+
+ If no prefix is given, the priority number is the default kernel
+ log priority and the facility number is set to LOG_USER (1). It
+ is not possible to inject messages from userspace with the
+ facility number LOG_KERN (0), to make sure that the origin of
+ the messages can always be reliably determined.
+
+ Accessing the buffer:
+ Every read() from the opened device node receives one record
+ of the kernel's printk buffer.
+
+ The first read() directly following an open() always returns
+ first message in the buffer; there is no kernel-internal
+ persistent state; many readers can concurrently open the device
+ and read from it, without affecting other readers.
+
+ Every read() will receive the next available record. If no more
+ records are available read() will block, or if O_NONBLOCK is
+ used -EAGAIN returned.
+
+ Messages in the record ring buffer get overwritten as whole,
+ there are never partial messages received by read().
+
+ In case messages get overwritten in the circular buffer while
+ the device is kept open, the next read() will return -EPIPE,
+ and the seek position be updated to the next available record.
+ Subsequent reads() will return available records again.
+
+ Unlike the classic syslog() interface, the 64 bit record
+ sequence numbers allow to calculate the amount of lost
+ messages, in case the buffer gets overwritten. And they allow
+ to reconnect to the buffer and reconstruct the read position
+ if needed, without limiting the interface to a single reader.
+
+ The device supports seek with the following parameters:
+ SEEK_SET, 0
+ seek to the first entry in the buffer
+ SEEK_END, 0
+ seek after the last entry in the buffer
+ SEEK_DATA, 0
+ seek after the last record available at the time
+ the last SYSLOG_ACTION_CLEAR was issued.
+
+ The output format consists of a prefix carrying the syslog
+ prefix including priority and facility, the 64 bit message
+ sequence number and the monotonic timestamp in microseconds.
+ The values are separated by a ','. Future extensions might
+ add more comma separated values before the terminating ';'.
+ Unknown values should be gracefully ignored.
+
+ The human readable text string starts directly after the ';'
+ and is terminated by a '\n'. Untrusted values derived from
+ hardware or other facilities are printed, therefore
+ all non-printable characters in the log message are escaped
+ by "\x00" C-style hex encoding.
+
+ A line starting with ' ', is a continuation line, adding
+ key/value pairs to the log message, which provide the machine
+ readable context of the message, for reliable processing in
+ userspace.
+
+ Example:
+ 7,160,424069;pci_root PNP0A03:00: host bridge window [io 0x0000-0x0cf7] (ignored)
+ SUBSYSTEM=acpi
+ DEVICE=+acpi:PNP0A03:00
+ 6,339,5140900;NET: Registered protocol family 10
+ 30,340,5690716;udevd[80]: starting version 181
+
+ The DEVICE= key uniquely identifies devices the following way:
+ b12:8 - block dev_t
+ c127:3 - char dev_t
+ n8 - netdev ifindex
+ +sound:card0 - subsystem:devname
+
+Users: dmesg(1), userspace kernel log consumers
diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index 46a995d6d261..5bc8a476c15e 100644
--- a/drivers/staging/iio/Documentation/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -108,7 +108,7 @@ Description:
physically equivalent inputs when non differential readings are
separately available. In differential only parts, then all that
is required is a consistent labeling. Units after application
- of scale and offset are nanofarads..
+ of scale and offset are nanofarads.
What: /sys/bus/iio/devices/iio:deviceX/in_temp_raw
What: /sys/bus/iio/devices/iio:deviceX/in_tempX_raw
@@ -119,7 +119,7 @@ KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
Raw (unscaled no bias removal etc) temperature measurement.
- It an axis is specified it generally means that the temperature
+ If an axis is specified it generally means that the temperature
sensor is associated with one part of a compound device (e.g.
a gyroscope axis). Units after application of scale and offset
are milli degrees Celsuis.
@@ -232,7 +232,7 @@ Description:
If known for a device, scale to be applied to <type>Y[_name]_raw
post addition of <type>[Y][_name]_offset in order to obtain the
measured value in <type> units as specified in
- <type>[Y][_name]_raw documentation.. If shared across all in
+ <type>[Y][_name]_raw documentation. If shared across all in
channels then Y and <x|y|z> are not present and the value is
called <type>[Y][_name]_scale. The peak modifier means this
value is applied to <type>Y[_name]_peak_raw values.
@@ -243,6 +243,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_calibbias
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_calibbias
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibbias
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibbias
+What: /sys/bus/iio/devices/iio:deviceX/in_illuminance0_calibbias
+What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calibbias
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
@@ -258,6 +260,8 @@ What /sys/bus/iio/devices/iio:deviceX/in_accel_z_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibscale
What /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibscale
+what /sys/bus/iio/devices/iio:deviceX/in_illuminance0_calibscale
+what /sys/bus/iio/devices/iio:deviceX/in_proximity0_calibscale
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
@@ -276,6 +280,13 @@ Description:
If a discrete set of scale values are available, they
are listed in this attribute.
+What /sys/bus/iio/devices/iio:deviceX/out_voltageY_hardwaregain
+KernelVersion: 2.6.35
+Contact: linux-iio@vger.kernel.org
+Description:
+ Hardware applied gain factor. If shared across all channels,
+ <type>_hardwaregain is used.
+
What: /sys/.../in_accel_filter_low_pass_3db_frequency
What: /sys/.../in_magn_filter_low_pass_3db_frequency
What: /sys/.../in_anglvel_filter_low_pass_3db_frequency
@@ -453,10 +464,14 @@ What: /sys/.../events/in_magn_z_raw_thresh_rising_value
What: /sys/.../events/in_magn_z_raw_thresh_falling_value
What: /sys/.../events/in_voltageY_supply_raw_thresh_rising_value
What: /sys/.../events/in_voltageY_supply_raw_thresh_falling_value
+What: /sys/.../events/in_voltageY_raw_thresh_rising_value
What: /sys/.../events/in_voltageY_raw_thresh_falling_value
-What: /sys/.../events/in_voltageY_raw_thresh_falling_value
-What: /sys/.../events/in_tempY_raw_thresh_falling_value
+What: /sys/.../events/in_tempY_raw_thresh_rising_value
What: /sys/.../events/in_tempY_raw_thresh_falling_value
+What: /sys/.../events/in_illuminance0_thresh_falling_value
+what: /sys/.../events/in_illuminance0_thresh_rising_value
+what: /sys/.../events/in_proximity0_thresh_falling_value
+what: /sys/.../events/in_proximity0_thresh_rising_value
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
@@ -490,9 +505,9 @@ What: /sys/.../events/in_magn_z_raw_roc_rising_value
What: /sys/.../events/in_magn_z_raw_roc_falling_value
What: /sys/.../events/in_voltageY_supply_raw_roc_rising_value
What: /sys/.../events/in_voltageY_supply_raw_roc_falling_value
+What: /sys/.../events/in_voltageY_raw_roc_rising_value
What: /sys/.../events/in_voltageY_raw_roc_falling_value
-What: /sys/.../events/in_voltageY_raw_roc_falling_value
-What: /sys/.../events/in_tempY_raw_roc_falling_value
+What: /sys/.../events/in_tempY_raw_roc_rising_value
What: /sys/.../events/in_tempY_raw_roc_falling_value
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
@@ -556,6 +571,8 @@ What: /sys/.../events/in_tempY_thresh_falling_period
What: /sys/.../events/in_tempY_roc_rising_period
What: /sys/.../events/in_tempY_roc_falling_period
What: /sys/.../events/in_accel_x&y&z_mag_falling_period
+What: /sys/.../events/in_intensity0_thresh_period
+What: /sys/.../events/in_proximity0_thresh_period
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
@@ -718,24 +735,3 @@ Contact: linux-iio@vger.kernel.org
Description:
This attribute is used to read the amount of quadrature error
present in the device at a given time.
-
-What: /sys/.../iio:deviceX/ac_excitation_en
-KernelVersion: 3.1.0
-Contact: linux-iio@vger.kernel.org
-Description:
- This attribute, if available, is used to enable the AC
- excitation mode found on some converters. In ac excitation mode,
- the polarity of the excitation voltage is reversed on
- alternate cycles, to eliminate DC errors.
-
-What: /sys/.../iio:deviceX/bridge_switch_en
-KernelVersion: 3.1.0
-Contact: linux-iio@vger.kernel.org
-Description:
- This attribute, if available, is used to close or open the
- bridge power down switch found on some converters.
- In bridge applications, such as strain gauges and load cells,
- the bridge itself consumes the majority of the current in the
- system. To minimize the current consumption of the system,
- the bridge can be disconnected (when it is not being used
- using the bridge_switch_en attribute.
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb
index 7c22a532fdfb..6df4e6f57560 100644
--- a/Documentation/ABI/testing/sysfs-bus-usb
+++ b/Documentation/ABI/testing/sysfs-bus-usb
@@ -135,6 +135,17 @@ Description:
for the device and attempt to bind to it. For example:
# echo "8086 10f5" > /sys/bus/usb/drivers/foo/new_id
+ Reading from this file will list all dynamically added
+ device IDs in the same format, with one entry per
+ line. For example:
+ # cat /sys/bus/usb/drivers/foo/new_id
+ 8086 10f5
+ dead beef 06
+ f00d cafe
+
+ The list will be truncated at PAGE_SIZE bytes due to
+ sysfs restrictions.
+
What: /sys/bus/usb-serial/drivers/.../new_id
Date: October 2011
Contact: linux-usb@vger.kernel.org
@@ -157,6 +168,10 @@ Description:
match the driver to the device. For example:
# echo "046d c315" > /sys/bus/usb/drivers/foo/remove_id
+ Reading from this file will list the dynamically added
+ device IDs, exactly like reading from the entry
+ "/sys/bus/usb/drivers/.../new_id"
+
What: /sys/bus/usb/device/.../avoid_reset_quirk
Date: December 2009
Contact: Oliver Neukum <oliver@neukum.org>
@@ -189,7 +204,7 @@ Contact: Matthew Garrett <mjg@redhat.com>
Description:
Some information about whether a given USB device is
physically fixed to the platform can be inferred from a
- combination of hub decriptor bits and platform-specific data
+ combination of hub descriptor bits and platform-specific data
such as ACPI. This file will read either "removable" or
"fixed" if the information is available, and "unknown"
- otherwise. \ No newline at end of file
+ otherwise.
diff --git a/Documentation/ABI/testing/sysfs-class-extcon b/Documentation/ABI/testing/sysfs-class-extcon
new file mode 100644
index 000000000000..20ab361bd8c6
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-extcon
@@ -0,0 +1,97 @@
+What: /sys/class/extcon/.../
+Date: February 2012
+Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+ Provide a place in sysfs for the extcon objects.
+ This allows accessing extcon specific variables.
+ The name of extcon object denoted as ... is the name given
+ with extcon_dev_register.
+
+ One extcon device denotes a single external connector
+ port. An external connector may have multiple cables
+ attached simultaneously. Many of docks, cradles, and
+ accessory cables have such capability. For example,
+ the 30-pin port of Nuri board (/arch/arm/mach-exynos)
+ may have both HDMI and Charger attached, or analog audio,
+ video, and USB cables attached simulteneously.
+
+ If there are cables mutually exclusive with each other,
+ such binary relations may be expressed with extcon_dev's
+ mutually_exclusive array.
+
+What: /sys/class/extcon/.../name
+Date: February 2012
+Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+ The /sys/class/extcon/.../name shows the name of the extcon
+ object. If the extcon object has an optional callback
+ "show_name" defined, the callback will provide the name with
+ this sysfs node.
+
+What: /sys/class/extcon/.../state
+Date: February 2012
+Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+ The /sys/class/extcon/.../state shows and stores the cable
+ attach/detach information of the corresponding extcon object.
+ If the extcon object has an optional callback "show_state"
+ defined, the showing function is overriden with the optional
+ callback.
+
+ If the default callback for showing function is used, the
+ format is like this:
+ # cat state
+ USB_OTG=1
+ HDMI=0
+ TA=1
+ EAR_JACK=0
+ #
+ In this example, the extcon device have USB_OTG and TA
+ cables attached and HDMI and EAR_JACK cables detached.
+
+ In order to update the state of an extcon device, enter a hex
+ state number starting with 0x.
+ echo 0xHEX > state
+
+ This updates the whole state of the extcon dev.
+ Inputs of all the methods are required to meet the
+ mutually_exclusive contidions if they exist.
+
+ It is recommended to use this "global" state interface if
+ you need to enter the value atomically. The later state
+ interface associated with each cable cannot update
+ multiple cable states of an extcon device simultaneously.
+
+What: /sys/class/extcon/.../cable.x/name
+Date: February 2012
+Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+ The /sys/class/extcon/.../cable.x/name shows the name of cable
+ "x" (integer between 0 and 31) of an extcon device.
+
+What: /sys/class/extcon/.../cable.x/state
+Date: February 2012
+Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+ The /sys/class/extcon/.../cable.x/name shows and stores the
+ state of cable "x" (integer between 0 and 31) of an extcon
+ device. The state value is either 0 (detached) or 1
+ (attached).
+
+What: /sys/class/extcon/.../mutually_exclusive/...
+Date: December 2011
+Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
+Description:
+ Shows the relations of mutually exclusiveness. For example,
+ if the mutually_exclusive array of extcon_dev is
+ {0x3, 0x5, 0xC, 0x0}, the, the output is:
+ # ls mutually_exclusive/
+ 0x3
+ 0x5
+ 0xc
+ #
+
+ Note that mutually_exclusive is a sub-directory of the extcon
+ device and the file names under the mutually_exclusive
+ directory show the mutually-exclusive sets, not the contents
+ of the files.
diff --git a/Documentation/ABI/testing/sysfs-devices-power b/Documentation/ABI/testing/sysfs-devices-power
index 840f7d64d483..45000f0db4d4 100644
--- a/Documentation/ABI/testing/sysfs-devices-power
+++ b/Documentation/ABI/testing/sysfs-devices-power
@@ -96,16 +96,26 @@ Description:
is read-only. If the device is not enabled to wake up the
system from sleep states, this attribute is not present.
-What: /sys/devices/.../power/wakeup_hit_count
-Date: September 2010
+What: /sys/devices/.../power/wakeup_abort_count
+Date: February 2012
Contact: Rafael J. Wysocki <rjw@sisk.pl>
Description:
- The /sys/devices/.../wakeup_hit_count attribute contains the
+ The /sys/devices/.../wakeup_abort_count attribute contains the
number of times the processing of a wakeup event associated with
- the device might prevent the system from entering a sleep state.
- This attribute is read-only. If the device is not enabled to
- wake up the system from sleep states, this attribute is not
- present.
+ the device might have aborted system transition into a sleep
+ state in progress. This attribute is read-only. If the device
+ is not enabled to wake up the system from sleep states, this
+ attribute is not present.
+
+What: /sys/devices/.../power/wakeup_expire_count
+Date: February 2012
+Contact: Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+ The /sys/devices/.../wakeup_expire_count attribute contains the
+ number of times a wakeup event associated with the device has
+ been reported with a timeout that expired. This attribute is
+ read-only. If the device is not enabled to wake up the system
+ from sleep states, this attribute is not present.
What: /sys/devices/.../power/wakeup_active
Date: September 2010
@@ -148,6 +158,17 @@ Description:
not enabled to wake up the system from sleep states, this
attribute is not present.
+What: /sys/devices/.../power/wakeup_prevent_sleep_time_ms
+Date: February 2012
+Contact: Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+ The /sys/devices/.../wakeup_prevent_sleep_time_ms attribute
+ contains the total time the device has been preventing
+ opportunistic transitions to sleep states from occuring.
+ This attribute is read-only. If the device is not enabled to
+ wake up the system from sleep states, this attribute is not
+ present.
+
What: /sys/devices/.../power/autosuspend_delay_ms
Date: September 2010
Contact: Alan Stern <stern@rowland.harvard.edu>
diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu
index e7be75b96e4b..5dab36448b44 100644
--- a/Documentation/ABI/testing/sysfs-devices-system-cpu
+++ b/Documentation/ABI/testing/sysfs-devices-system-cpu
@@ -9,31 +9,6 @@ Description:
/sys/devices/system/cpu/cpu#/
-What: /sys/devices/system/cpu/sched_mc_power_savings
- /sys/devices/system/cpu/sched_smt_power_savings
-Date: June 2006
-Contact: Linux kernel mailing list <linux-kernel@vger.kernel.org>
-Description: Discover and adjust the kernel's multi-core scheduler support.
-
- Possible values are:
-
- 0 - No power saving load balance (default value)
- 1 - Fill one thread/core/package first for long running threads
- 2 - Also bias task wakeups to semi-idle cpu package for power
- savings
-
- sched_mc_power_savings is dependent upon SCHED_MC, which is
- itself architecture dependent.
-
- sched_smt_power_savings is dependent upon SCHED_SMT, which
- is itself architecture dependent.
-
- The two files are independent of each other. It is possible
- that one file may be present without the other.
-
- Introduced by git commit 5c45bf27.
-
-
What: /sys/devices/system/cpu/kernel_max
/sys/devices/system/cpu/offline
/sys/devices/system/cpu/online
diff --git a/Documentation/ABI/testing/sysfs-driver-wacom b/Documentation/ABI/testing/sysfs-driver-wacom
index 0130d6683c14..8d55a83d6921 100644
--- a/Documentation/ABI/testing/sysfs-driver-wacom
+++ b/Documentation/ABI/testing/sysfs-driver-wacom
@@ -9,15 +9,24 @@ Description:
or 0 otherwise. Writing to this file one of these values
switches reporting speed.
+What: /sys/class/leds/0005\:056A\:00BD.0001\:selector\:*/
+Date: May 2012
+Kernel Version: 3.5
+Contact: linux-bluetooth@vger.kernel.org
+Description:
+ LED selector for Intuos4 WL. There are 4 leds, but only one LED
+ can be lit at a time. Max brightness is 127.
+
What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/led
Date: August 2011
Contact: linux-input@vger.kernel.org
Description:
Attribute group for control of the status LEDs and the OLEDs.
This attribute group is only available for Intuos 4 M, L,
- and XL (with LEDs and OLEDs) and Cintiq 21UX2 and Cintiq 24HD
- (LEDs only). Therefore its presence implicitly signifies the
- presence of said LEDs and OLEDs on the tablet device.
+ and XL (with LEDs and OLEDs), Intuos 5 (LEDs only), and Cintiq
+ 21UX2 and Cintiq 24HD (LEDs only). Therefore its presence
+ implicitly signifies the presence of said LEDs and OLEDs on the
+ tablet device.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/status0_luminance
Date: August 2011
@@ -40,10 +49,10 @@ What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/status_led0
Date: August 2011
Contact: linux-input@vger.kernel.org
Description:
- Writing to this file sets which one of the four (for Intuos 4)
- or of the right four (for Cintiq 21UX2 and Cintiq 24HD) status
- LEDs is active (0..3). The other three LEDs on the same side are
- always inactive.
+ Writing to this file sets which one of the four (for Intuos 4
+ and Intuos 5) or of the right four (for Cintiq 21UX2 and Cintiq
+ 24HD) status LEDs is active (0..3). The other three LEDs on the
+ same side are always inactive.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<cfg>.<intf>/wacom_led/status_led1_select
Date: September 2011
diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power
index b464d12761ba..31725ffeeb3a 100644
--- a/Documentation/ABI/testing/sysfs-power
+++ b/Documentation/ABI/testing/sysfs-power
@@ -172,3 +172,62 @@ Description:
Reading from this file will display the current value, which is
set to 1 MB by default.
+
+What: /sys/power/autosleep
+Date: April 2012
+Contact: Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+ The /sys/power/autosleep file can be written one of the strings
+ returned by reads from /sys/power/state. If that happens, a
+ work item attempting to trigger a transition of the system to
+ the sleep state represented by that string is queued up. This
+ attempt will only succeed if there are no active wakeup sources
+ in the system at that time. After every execution, regardless
+ of whether or not the attempt to put the system to sleep has
+ succeeded, the work item requeues itself until user space
+ writes "off" to /sys/power/autosleep.
+
+ Reading from this file causes the last string successfully
+ written to it to be returned.
+
+What: /sys/power/wake_lock
+Date: February 2012
+Contact: Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+ The /sys/power/wake_lock file allows user space to create
+ wakeup source objects and activate them on demand (if one of
+ those wakeup sources is active, reads from the
+ /sys/power/wakeup_count file block or return false). When a
+ string without white space is written to /sys/power/wake_lock,
+ it will be assumed to represent a wakeup source name. If there
+ is a wakeup source object with that name, it will be activated
+ (unless active already). Otherwise, a new wakeup source object
+ will be registered, assigned the given name and activated.
+ If a string written to /sys/power/wake_lock contains white
+ space, the part of the string preceding the white space will be
+ regarded as a wakeup source name and handled as descrived above.
+ The other part of the string will be regarded as a timeout (in
+ nanoseconds) such that the wakeup source will be automatically
+ deactivated after it has expired. The timeout, if present, is
+ set regardless of the current state of the wakeup source object
+ in question.
+
+ Reads from this file return a string consisting of the names of
+ wakeup sources created with the help of it that are active at
+ the moment, separated with spaces.
+
+
+What: /sys/power/wake_unlock
+Date: February 2012
+Contact: Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+ The /sys/power/wake_unlock file allows user space to deactivate
+ wakeup sources created with the help of /sys/power/wake_lock.
+ When a string is written to /sys/power/wake_unlock, it will be
+ assumed to represent the name of a wakeup source to deactivate.
+ If a wakeup source object of that name exists and is active at
+ the moment, it will be deactivated.
+
+ Reads from this file return a string consisting of the names of
+ wakeup sources created with the help of /sys/power/wake_lock
+ that are inactive at the moment, separated with spaces.
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 66725a3d30dc..bc3d9f8c0a90 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -6,7 +6,7 @@
# To add a new book the only step required is to add the book to the
# list of DOCBOOKS.
-DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \
+DOCBOOKS := z8530book.xml device-drivers.xml \
kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
writing_usb_driver.xml networking.xml \
kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index 7160652a8736..00687ee9d363 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -212,19 +212,6 @@ X!Edrivers/pci/hotplug.c
<sect1><title>PCI Hotplug Support Library</title>
!Edrivers/pci/hotplug/pci_hotplug_core.c
</sect1>
- <sect1><title>MCA Architecture</title>
- <sect2><title>MCA Device Functions</title>
- <para>
- Refer to the file arch/x86/kernel/mca_32.c for more information.
- </para>
-<!-- FIXME: Removed for now since no structured comments in source
-X!Earch/x86/kernel/mca_32.c
--->
- </sect2>
- <sect2><title>MCA Bus DMA</title>
-!Iarch/x86/include/asm/mca_dma.h
- </sect2>
- </sect1>
</chapter>
<chapter id="firmware">
diff --git a/Documentation/DocBook/kernel-hacking.tmpl b/Documentation/DocBook/kernel-hacking.tmpl
index 07a9c48de5a2..eee71426ecb8 100644
--- a/Documentation/DocBook/kernel-hacking.tmpl
+++ b/Documentation/DocBook/kernel-hacking.tmpl
@@ -1289,7 +1289,7 @@ static struct block_device_operations opt_fops = {
* Sparc assembly will do this to ya.
*/
C_LABEL(cputypvar):
- .asciz "compatability"
+ .asciz "compatibility"
/* Tested on SS-5, SS-10. Probably someone at Sun applied a spell-checker. */
.align 4
diff --git a/Documentation/DocBook/libata.tmpl b/Documentation/DocBook/libata.tmpl
index 31df1aa00710..deb71baed328 100644
--- a/Documentation/DocBook/libata.tmpl
+++ b/Documentation/DocBook/libata.tmpl
@@ -918,7 +918,7 @@ and other resources, etc.
<title>HSM violation</title>
<para>
This error is indicated when STATUS value doesn't match HSM
- requirement during issuing or excution any ATA/ATAPI command.
+ requirement during issuing or execution any ATA/ATAPI command.
</para>
<itemizedlist>
diff --git a/Documentation/DocBook/mcabook.tmpl b/Documentation/DocBook/mcabook.tmpl
deleted file mode 100644
index 467ccac6ec50..000000000000
--- a/Documentation/DocBook/mcabook.tmpl
+++ /dev/null
@@ -1,107 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
- "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
-
-<book id="MCAGuide">
- <bookinfo>
- <title>MCA Driver Programming Interface</title>
-
- <authorgroup>
- <author>
- <firstname>Alan</firstname>
- <surname>Cox</surname>
- <affiliation>
- <address>
- <email>alan@lxorguk.ukuu.org.uk</email>
- </address>
- </affiliation>
- </author>
- <author>
- <firstname>David</firstname>
- <surname>Weinehall</surname>
- </author>
- <author>
- <firstname>Chris</firstname>
- <surname>Beauregard</surname>
- </author>
- </authorgroup>
-
- <copyright>
- <year>2000</year>
- <holder>Alan Cox</holder>
- <holder>David Weinehall</holder>
- <holder>Chris Beauregard</holder>
- </copyright>
-
- <legalnotice>
- <para>
- This documentation 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.
- </para>
-
- <para>
- 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.
- </para>
-
- <para>
- You should have received a copy of the GNU General Public
- License along with this program; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- MA 02111-1307 USA
- </para>
-
- <para>
- For more details see the file COPYING in the source
- distribution of Linux.
- </para>
- </legalnotice>
- </bookinfo>
-
-<toc></toc>
-
- <chapter id="intro">
- <title>Introduction</title>
- <para>
- The MCA bus functions provide a generalised interface to find MCA
- bus cards, to claim them for a driver, and to read and manipulate POS
- registers without being aware of the motherboard internals or
- certain deep magic specific to onboard devices.
- </para>
- <para>
- The basic interface to the MCA bus devices is the slot. Each slot
- is numbered and virtual slot numbers are assigned to the internal
- devices. Using a pci_dev as other busses do does not really make
- sense in the MCA context as the MCA bus resources require card
- specific interpretation.
- </para>
- <para>
- Finally the MCA bus functions provide a parallel set of DMA
- functions mimicing the ISA bus DMA functions as closely as possible,
- although also supporting the additional DMA functionality on the
- MCA bus controllers.
- </para>
- </chapter>
- <chapter id="bugs">
- <title>Known Bugs And Assumptions</title>
- <para>
- None.
- </para>
- </chapter>
-
- <chapter id="pubfunctions">
- <title>Public Functions Provided</title>
-!Edrivers/mca/mca-legacy.c
- </chapter>
-
- <chapter id="dmafunctions">
- <title>DMA Functions Provided</title>
-!Iarch/x86/include/asm/mca_dma.h
- </chapter>
-
-</book>
diff --git a/Documentation/DocBook/media/Makefile b/Documentation/DocBook/media/Makefile
index 6628b4b9cac4..362520992ced 100644
--- a/Documentation/DocBook/media/Makefile
+++ b/Documentation/DocBook/media/Makefile
@@ -70,6 +70,8 @@ IOCTLS = \
VIDIOC_SUBDEV_ENUM_MBUS_CODE \
VIDIOC_SUBDEV_ENUM_FRAME_SIZE \
VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL \
+ VIDIOC_SUBDEV_G_SELECTION \
+ VIDIOC_SUBDEV_S_SELECTION \
TYPES = \
$(shell perl -ne 'print "$$1 " if /^typedef\s+[^\s]+\s+([^\s]+)\;/' $(srctree)/include/linux/videodev2.h) \
@@ -193,7 +195,7 @@ DVB_DOCUMENTED = \
#
install_media_images = \
- $(Q)cp $(OBJIMGFILES) $(MEDIA_OBJ_DIR)/media_api
+ $(Q)cp $(OBJIMGFILES) $(MEDIA_SRC_DIR)/v4l/*.svg $(MEDIA_OBJ_DIR)/media_api
$(MEDIA_OBJ_DIR)/%: $(MEDIA_SRC_DIR)/%.b64
$(Q)base64 -d $< >$@
diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml
index c7a4ca517859..e633c097a8d1 100644
--- a/Documentation/DocBook/media/dvb/dvbproperty.xml
+++ b/Documentation/DocBook/media/dvb/dvbproperty.xml
@@ -531,6 +531,139 @@ typedef enum fe_delivery_system {
here are referring to what can be found in the TMCC-structure -
independent of the mode.</para>
</section>
+ <section id="DTV-ATSCMH-FIC-VER">
+ <title><constant>DTV_ATSCMH_FIC_VER</constant></title>
+ <para>Version number of the FIC (Fast Information Channel) signaling data.</para>
+ <para>FIC is used for relaying information to allow rapid service acquisition by the receiver.</para>
+ <para>Possible values: 0, 1, 2, 3, ..., 30, 31</para>
+ </section>
+ <section id="DTV-ATSCMH-PARADE-ID">
+ <title><constant>DTV_ATSCMH_PARADE_ID</constant></title>
+ <para>Parade identification number</para>
+ <para>A parade is a collection of up to eight MH groups, conveying one or two ensembles.</para>
+ <para>Possible values: 0, 1, 2, 3, ..., 126, 127</para>
+ </section>
+ <section id="DTV-ATSCMH-NOG">
+ <title><constant>DTV_ATSCMH_NOG</constant></title>
+ <para>Number of MH groups per MH subframe for a designated parade.</para>
+ <para>Possible values: 1, 2, 3, 4, 5, 6, 7, 8</para>
+ </section>
+ <section id="DTV-ATSCMH-TNOG">
+ <title><constant>DTV_ATSCMH_TNOG</constant></title>
+ <para>Total number of MH groups including all MH groups belonging to all MH parades in one MH subframe.</para>
+ <para>Possible values: 0, 1, 2, 3, ..., 30, 31</para>
+ </section>
+ <section id="DTV-ATSCMH-SGN">
+ <title><constant>DTV_ATSCMH_SGN</constant></title>
+ <para>Start group number.</para>
+ <para>Possible values: 0, 1, 2, 3, ..., 14, 15</para>
+ </section>
+ <section id="DTV-ATSCMH-PRC">
+ <title><constant>DTV_ATSCMH_PRC</constant></title>
+ <para>Parade repetition cycle.</para>
+ <para>Possible values: 1, 2, 3, 4, 5, 6, 7, 8</para>
+ </section>
+ <section id="DTV-ATSCMH-RS-FRAME-MODE">
+ <title><constant>DTV_ATSCMH_RS_FRAME_MODE</constant></title>
+ <para>RS frame mode.</para>
+ <para>Possible values are:</para>
+<programlisting>
+typedef enum atscmh_rs_frame_mode {
+ ATSCMH_RSFRAME_PRI_ONLY = 0,
+ ATSCMH_RSFRAME_PRI_SEC = 1,
+} atscmh_rs_frame_mode_t;
+</programlisting>
+ </section>
+ <section id="DTV-ATSCMH-RS-FRAME-ENSEMBLE">
+ <title><constant>DTV_ATSCMH_RS_FRAME_ENSEMBLE</constant></title>
+ <para>RS frame ensemble.</para>
+ <para>Possible values are:</para>
+<programlisting>
+typedef enum atscmh_rs_frame_ensemble {
+ ATSCMH_RSFRAME_ENS_PRI = 0,
+ ATSCMH_RSFRAME_ENS_SEC = 1,
+} atscmh_rs_frame_ensemble_t;
+</programlisting>
+ </section>
+ <section id="DTV-ATSCMH-RS-CODE-MODE-PRI">
+ <title><constant>DTV_ATSCMH_RS_CODE_MODE_PRI</constant></title>
+ <para>RS code mode (primary).</para>
+ <para>Possible values are:</para>
+<programlisting>
+typedef enum atscmh_rs_code_mode {
+ ATSCMH_RSCODE_211_187 = 0,
+ ATSCMH_RSCODE_223_187 = 1,
+ ATSCMH_RSCODE_235_187 = 2,
+} atscmh_rs_code_mode_t;
+</programlisting>
+ </section>
+ <section id="DTV-ATSCMH-RS-CODE-MODE-SEC">
+ <title><constant>DTV_ATSCMH_RS_CODE_MODE_SEC</constant></title>
+ <para>RS code mode (secondary).</para>
+ <para>Possible values are:</para>
+<programlisting>
+typedef enum atscmh_rs_code_mode {
+ ATSCMH_RSCODE_211_187 = 0,
+ ATSCMH_RSCODE_223_187 = 1,
+ ATSCMH_RSCODE_235_187 = 2,
+} atscmh_rs_code_mode_t;
+</programlisting>
+ </section>
+ <section id="DTV-ATSCMH-SCCC-BLOCK-MODE">
+ <title><constant>DTV_ATSCMH_SCCC_BLOCK_MODE</constant></title>
+ <para>Series Concatenated Convolutional Code Block Mode.</para>
+ <para>Possible values are:</para>
+<programlisting>
+typedef enum atscmh_sccc_block_mode {
+ ATSCMH_SCCC_BLK_SEP = 0,
+ ATSCMH_SCCC_BLK_COMB = 1,
+} atscmh_sccc_block_mode_t;
+</programlisting>
+ </section>
+ <section id="DTV-ATSCMH-SCCC-CODE-MODE-A">
+ <title><constant>DTV_ATSCMH_SCCC_CODE_MODE_A</constant></title>
+ <para>Series Concatenated Convolutional Code Rate.</para>
+ <para>Possible values are:</para>
+<programlisting>
+typedef enum atscmh_sccc_code_mode {
+ ATSCMH_SCCC_CODE_HLF = 0,
+ ATSCMH_SCCC_CODE_QTR = 1,
+} atscmh_sccc_code_mode_t;
+</programlisting>
+ </section>
+ <section id="DTV-ATSCMH-SCCC-CODE-MODE-B">
+ <title><constant>DTV_ATSCMH_SCCC_CODE_MODE_B</constant></title>
+ <para>Series Concatenated Convolutional Code Rate.</para>
+ <para>Possible values are:</para>
+<programlisting>
+typedef enum atscmh_sccc_code_mode {
+ ATSCMH_SCCC_CODE_HLF = 0,
+ ATSCMH_SCCC_CODE_QTR = 1,
+} atscmh_sccc_code_mode_t;
+</programlisting>
+ </section>
+ <section id="DTV-ATSCMH-SCCC-CODE-MODE-C">
+ <title><constant>DTV_ATSCMH_SCCC_CODE_MODE_C</constant></title>
+ <para>Series Concatenated Convolutional Code Rate.</para>
+ <para>Possible values are:</para>
+<programlisting>
+typedef enum atscmh_sccc_code_mode {
+ ATSCMH_SCCC_CODE_HLF = 0,
+ ATSCMH_SCCC_CODE_QTR = 1,
+} atscmh_sccc_code_mode_t;
+</programlisting>
+ </section>
+ <section id="DTV-ATSCMH-SCCC-CODE-MODE-D">
+ <title><constant>DTV_ATSCMH_SCCC_CODE_MODE_D</constant></title>
+ <para>Series Concatenated Convolutional Code Rate.</para>
+ <para>Possible values are:</para>
+<programlisting>
+typedef enum atscmh_sccc_code_mode {
+ ATSCMH_SCCC_CODE_HLF = 0,
+ ATSCMH_SCCC_CODE_QTR = 1,
+} atscmh_sccc_code_mode_t;
+</programlisting>
+ </section>
</section>
<section id="DTV-API-VERSION">
<title><constant>DTV_API_VERSION</constant></title>
@@ -774,6 +907,33 @@ typedef enum fe_hierarchy {
<listitem><para><link linkend="DTV-BANDWIDTH-HZ"><constant>DTV_BANDWIDTH_HZ</constant></link></para></listitem>
</itemizedlist>
</section>
+ <section id="atscmh-params">
+ <title>ATSC-MH delivery system</title>
+ <para>The following parameters are valid for ATSC-MH:</para>
+ <itemizedlist mark='opencircle'>
+ <listitem><para><link linkend="DTV-API-VERSION"><constant>DTV_API_VERSION</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-DELIVERY-SYSTEM"><constant>DTV_DELIVERY_SYSTEM</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-TUNE"><constant>DTV_TUNE</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-CLEAR"><constant>DTV_CLEAR</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-FREQUENCY"><constant>DTV_FREQUENCY</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-BANDWIDTH-HZ"><constant>DTV_BANDWIDTH_HZ</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-ATSCMH-FIC-VER"><constant>DTV_ATSCMH_FIC_VER</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-ATSCMH-PARADE-ID"><constant>DTV_ATSCMH_PARADE_ID</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-ATSCMH-NOG"><constant>DTV_ATSCMH_NOG</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-ATSCMH-TNOG"><constant>DTV_ATSCMH_TNOG</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-ATSCMH-SGN"><constant>DTV_ATSCMH_SGN</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-ATSCMH-PRC"><constant>DTV_ATSCMH_PRC</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-ATSCMH-RS-FRAME-MODE"><constant>DTV_ATSCMH_RS_FRAME_MODE</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-ATSCMH-RS-FRAME-ENSEMBLE"><constant>DTV_ATSCMH_RS_FRAME_ENSEMBLE</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-ATSCMH-CODE-MODE-PRI"><constant>DTV_ATSCMH_CODE_MODE_PRI</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-ATSCMH-CODE-MODE-SEC"><constant>DTV_ATSCMH_CODE_MODE_SEC</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-ATSCMH-SCCC-BLOCK-MODE"><constant>DTV_ATSCMH_SCCC_BLOCK_MODE</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE_MODE-A"><constant>DTV_ATSCMH_SCCC_CODE_MODE_A</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE_MODE-B"><constant>DTV_ATSCMH_SCCC_CODE_MODE_B</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE_MODE-C"><constant>DTV_ATSCMH_SCCC_CODE_MODE_C</constant></link></para></listitem>
+ <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE_MODE-D"><constant>DTV_ATSCMH_SCCC_CODE_MODE_D</constant></link></para></listitem>
+ </itemizedlist>
+ </section>
</section>
<section id="frontend-property-cable-systems">
<title>Properties used on cable delivery systems</title>
diff --git a/Documentation/DocBook/media/v4l/biblio.xml b/Documentation/DocBook/media/v4l/biblio.xml
index 7dc65c592a87..7c49facecd25 100644
--- a/Documentation/DocBook/media/v4l/biblio.xml
+++ b/Documentation/DocBook/media/v4l/biblio.xml
@@ -197,4 +197,33 @@ in the frequency range from 87,5 to 108,0 MHz</title>
<title>NTSC-4: United States RBDS Standard</title>
</biblioentry>
+ <biblioentry id="iso12232">
+ <abbrev>ISO&nbsp;12232:2006</abbrev>
+ <authorgroup>
+ <corpauthor>International Organization for Standardization
+(<ulink url="http://www.iso.org">http://www.iso.org</ulink>)</corpauthor>
+ </authorgroup>
+ <title>Photography &mdash; Digital still cameras &mdash; Determination
+ of exposure index, ISO speed ratings, standard output sensitivity, and
+ recommended exposure index</title>
+ </biblioentry>
+
+ <biblioentry id="cea861">
+ <abbrev>CEA-861-E</abbrev>
+ <authorgroup>
+ <corpauthor>Consumer Electronics Association
+(<ulink url="http://www.ce.org">http://www.ce.org</ulink>)</corpauthor>
+ </authorgroup>
+ <title>A DTV Profile for Uncompressed High Speed Digital Interfaces</title>
+ </biblioentry>
+
+ <biblioentry id="vesadmt">
+ <abbrev>VESA&nbsp;DMT</abbrev>
+ <authorgroup>
+ <corpauthor>Video Electronics Standards Association
+(<ulink url="http://www.vesa.org">http://www.vesa.org</ulink>)</corpauthor>
+ </authorgroup>
+ <title>VESA and Industry Standards and Guidelines for Computer Display Monitor Timing (DMT)</title>
+ </biblioentry>
+
</bibliography>
diff --git a/Documentation/DocBook/media/v4l/common.xml b/Documentation/DocBook/media/v4l/common.xml
index c79278acfb0e..4101aeb56540 100644
--- a/Documentation/DocBook/media/v4l/common.xml
+++ b/Documentation/DocBook/media/v4l/common.xml
@@ -724,41 +724,49 @@ if (-1 == ioctl (fd, &VIDIOC-S-STD;, &amp;std_id)) {
}
</programlisting>
</example>
+ </section>
<section id="dv-timings">
<title>Digital Video (DV) Timings</title>
<para>
- The video standards discussed so far has been dealing with Analog TV and the
+ The video standards discussed so far have been dealing with Analog TV and the
corresponding video timings. Today there are many more different hardware interfaces
such as High Definition TV interfaces (HDMI), VGA, DVI connectors etc., that carry
video signals and there is a need to extend the API to select the video timings
for these interfaces. Since it is not possible to extend the &v4l2-std-id; due to
-the limited bits available, a new set of IOCTLs is added to set/get video timings at
+the limited bits available, a new set of IOCTLs was added to set/get video timings at
the input and output: </para><itemizedlist>
<listitem>
- <para>DV Presets: Digital Video (DV) presets. These are IDs representing a
+ <para>DV Timings: This will allow applications to define detailed
+video timings for the interface. This includes parameters such as width, height,
+polarities, frontporch, backporch etc. The <filename>linux/v4l2-dv-timings.h</filename>
+header can be used to get the timings of the formats in the <xref linkend="cea861" /> and
+<xref linkend="vesadmt" /> standards.
+ </para>
+ </listitem>
+ <listitem>
+ <para>DV Presets: Digital Video (DV) presets (<emphasis role="bold">deprecated</emphasis>).
+ These are IDs representing a
video timing at the input/output. Presets are pre-defined timings implemented
by the hardware according to video standards. A __u32 data type is used to represent
a preset unlike the bit mask that is used in &v4l2-std-id; allowing future extensions
-to support as many different presets as needed.</para>
- </listitem>
- <listitem>
- <para>Custom DV Timings: This will allow applications to define more detailed
-custom video timings for the interface. This includes parameters such as width, height,
-polarities, frontporch, backporch etc.
- </para>
+to support as many different presets as needed. This API is deprecated in favor of the DV Timings
+API.</para>
</listitem>
</itemizedlist>
+ <para>To enumerate and query the attributes of the DV timings supported by a device,
+ applications use the &VIDIOC-ENUM-DV-TIMINGS; and &VIDIOC-DV-TIMINGS-CAP; ioctls.
+ To set DV timings for the device, applications use the
+&VIDIOC-S-DV-TIMINGS; ioctl and to get current DV timings they use the
+&VIDIOC-G-DV-TIMINGS; ioctl. To detect the DV timings as seen by the video receiver applications
+use the &VIDIOC-QUERY-DV-TIMINGS; ioctl.</para>
<para>To enumerate and query the attributes of DV presets supported by a device,
applications use the &VIDIOC-ENUM-DV-PRESETS; ioctl. To get the current DV preset,
applications use the &VIDIOC-G-DV-PRESET; ioctl and to set a preset they use the
-&VIDIOC-S-DV-PRESET; ioctl.</para>
- <para>To set custom DV timings for the device, applications use the
-&VIDIOC-S-DV-TIMINGS; ioctl and to get current custom DV timings they use the
-&VIDIOC-G-DV-TIMINGS; ioctl.</para>
+&VIDIOC-S-DV-PRESET; ioctl. To detect the preset as seen by the video receiver applications
+use the &VIDIOC-QUERY-DV-PRESET; ioctl.</para>
<para>Applications can make use of the <xref linkend="input-capabilities" /> and
<xref linkend="output-capabilities"/> flags to decide what ioctls are available to set the
video timings for the device.</para>
- </section>
</section>
&sub-controls;
diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml
index bce97c50391b..ea42ef824948 100644
--- a/Documentation/DocBook/media/v4l/compat.xml
+++ b/Documentation/DocBook/media/v4l/compat.xml
@@ -2407,6 +2407,54 @@ details.</para>
<para>Added <link linkend="jpeg-controls">JPEG compression control
class</link>.</para>
</listitem>
+ <listitem>
+ <para>Extended the DV Timings API:
+ &VIDIOC-ENUM-DV-TIMINGS;, &VIDIOC-QUERY-DV-TIMINGS; and
+ &VIDIOC-DV-TIMINGS-CAP;.</para>
+ </listitem>
+ </orderedlist>
+ </section>
+
+ <section>
+ <title>V4L2 in Linux 3.5</title>
+ <orderedlist>
+ <listitem>
+ <para>Added integer menus, the new type will be
+ V4L2_CTRL_TYPE_INTEGER_MENU.</para>
+ </listitem>
+ <listitem>
+ <para>Added selection API for V4L2 subdev interface:
+ &VIDIOC-SUBDEV-G-SELECTION; and
+ &VIDIOC-SUBDEV-S-SELECTION;.</para>
+ </listitem>
+ <listitem>
+ <para> Added <constant>V4L2_COLORFX_ANTIQUE</constant>,
+ <constant>V4L2_COLORFX_ART_FREEZE</constant>,
+ <constant>V4L2_COLORFX_AQUA</constant>,
+ <constant>V4L2_COLORFX_SILHOUETTE</constant>,
+ <constant>V4L2_COLORFX_SOLARIZATION</constant>,
+ <constant>V4L2_COLORFX_VIVID</constant> and
+ <constant>V4L2_COLORFX_ARBITRARY_CBCR</constant> menu items
+ to the <constant>V4L2_CID_COLORFX</constant> control.</para>
+ </listitem>
+ <listitem>
+ <para> Added <constant>V4L2_CID_COLORFX_CBCR</constant> control.</para>
+ </listitem>
+ <listitem>
+ <para> Added camera controls <constant>V4L2_CID_AUTO_EXPOSURE_BIAS</constant>,
+ <constant>V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE</constant>,
+ <constant>V4L2_CID_IMAGE_STABILIZATION</constant>,
+ <constant>V4L2_CID_ISO_SENSITIVITY</constant>,
+ <constant>V4L2_CID_ISO_SENSITIVITY_AUTO</constant>,
+ <constant>V4L2_CID_EXPOSURE_METERING</constant>,
+ <constant>V4L2_CID_SCENE_MODE</constant>,
+ <constant>V4L2_CID_3A_LOCK</constant>,
+ <constant>V4L2_CID_AUTO_FOCUS_START</constant>,
+ <constant>V4L2_CID_AUTO_FOCUS_STOP</constant>,
+ <constant>V4L2_CID_AUTO_FOCUS_STATUS</constant> and
+ <constant>V4L2_CID_AUTO_FOCUS_RANGE</constant>.
+ </para>
+ </listitem>
</orderedlist>
</section>
@@ -2508,6 +2556,10 @@ and may change in the future.</para>
ioctls.</para>
</listitem>
<listitem>
+ <para>&VIDIOC-DECODER-CMD; and &VIDIOC-TRY-DECODER-CMD;
+ioctls.</para>
+ </listitem>
+ <listitem>
<para>&VIDIOC-DBG-G-REGISTER; and &VIDIOC-DBG-S-REGISTER;
ioctls.</para>
</listitem>
@@ -2515,6 +2567,10 @@ ioctls.</para>
<para>&VIDIOC-DBG-G-CHIP-IDENT; ioctl.</para>
</listitem>
<listitem>
+ <para>&VIDIOC-ENUM-DV-TIMINGS;, &VIDIOC-QUERY-DV-TIMINGS; and
+ &VIDIOC-DV-TIMINGS-CAP; ioctls.</para>
+ </listitem>
+ <listitem>
<para>Flash API. <xref linkend="flash-controls" /></para>
</listitem>
<listitem>
@@ -2523,6 +2579,14 @@ ioctls.</para>
<listitem>
<para>Selection API. <xref linkend="selection-api" /></para>
</listitem>
+ <listitem>
+ <para>Sub-device selection API: &VIDIOC-SUBDEV-G-SELECTION;
+ and &VIDIOC-SUBDEV-S-SELECTION; ioctls.</para>
+ </listitem>
+ <listitem>
+ <para><link linkend="v4l2-auto-focus-area"><constant>
+ V4L2_CID_AUTO_FOCUS_AREA</constant></link> control.</para>
+ </listitem>
</itemizedlist>
</section>
@@ -2538,6 +2602,17 @@ interfaces and should not be implemented in new drivers.</para>
<constant>VIDIOC_S_MPEGCOMP</constant> ioctls. Use Extended Controls,
<xref linkend="extended-controls" />.</para>
</listitem>
+ <listitem>
+ <para>&VIDIOC-G-DV-PRESET;, &VIDIOC-S-DV-PRESET;, &VIDIOC-ENUM-DV-PRESETS; and
+ &VIDIOC-QUERY-DV-PRESET; ioctls. Use the DV Timings API (<xref linkend="dv-timings" />).</para>
+ </listitem>
+ <listitem>
+ <para><constant>VIDIOC_SUBDEV_G_CROP</constant> and
+ <constant>VIDIOC_SUBDEV_S_CROP</constant> ioctls. Use
+ <constant>VIDIOC_SUBDEV_G_SELECTION</constant> and
+ <constant>VIDIOC_SUBDEV_S_SELECTION</constant>, <xref
+ linkend="vidioc-subdev-g-selection" />.</para>
+ </listitem>
</itemizedlist>
</section>
</section>
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index b84f25e9cc87..676bc46f9c52 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -285,18 +285,92 @@ minimum value disables backlight compensation.</entry>
<row id="v4l2-colorfx">
<entry><constant>V4L2_CID_COLORFX</constant></entry>
<entry>enum</entry>
- <entry>Selects a color effect. Possible values for
-<constant>enum v4l2_colorfx</constant> are:
-<constant>V4L2_COLORFX_NONE</constant> (0),
-<constant>V4L2_COLORFX_BW</constant> (1),
-<constant>V4L2_COLORFX_SEPIA</constant> (2),
-<constant>V4L2_COLORFX_NEGATIVE</constant> (3),
-<constant>V4L2_COLORFX_EMBOSS</constant> (4),
-<constant>V4L2_COLORFX_SKETCH</constant> (5),
-<constant>V4L2_COLORFX_SKY_BLUE</constant> (6),
-<constant>V4L2_COLORFX_GRASS_GREEN</constant> (7),
-<constant>V4L2_COLORFX_SKIN_WHITEN</constant> (8) and
-<constant>V4L2_COLORFX_VIVID</constant> (9).</entry>
+ <entry>Selects a color effect. The following values are defined:
+ </entry>
+ </row><row>
+ <entry></entry>
+ <entry></entry>
+ <entrytbl spanname="descr" cols="2">
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_COLORFX_NONE</constant>&nbsp;</entry>
+ <entry>Color effect is disabled.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_ANTIQUE</constant>&nbsp;</entry>
+ <entry>An aging (old photo) effect.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_ART_FREEZE</constant>&nbsp;</entry>
+ <entry>Frost color effect.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_AQUA</constant>&nbsp;</entry>
+ <entry>Water color, cool tone.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_BW</constant>&nbsp;</entry>
+ <entry>Black and white.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_EMBOSS</constant>&nbsp;</entry>
+ <entry>Emboss, the highlights and shadows replace light/dark boundaries
+ and low contrast areas are set to a gray background.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_GRASS_GREEN</constant>&nbsp;</entry>
+ <entry>Grass green.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_NEGATIVE</constant>&nbsp;</entry>
+ <entry>Negative.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_SEPIA</constant>&nbsp;</entry>
+ <entry>Sepia tone.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_SKETCH</constant>&nbsp;</entry>
+ <entry>Sketch.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_SKIN_WHITEN</constant>&nbsp;</entry>
+ <entry>Skin whiten.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_SKY_BLUE</constant>&nbsp;</entry>
+ <entry>Sky blue.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_SOLARIZATION</constant>&nbsp;</entry>
+ <entry>Solarization, the image is partially reversed in tone,
+ only color values above or below a certain threshold are inverted.
+ </entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_SILHOUETTE</constant>&nbsp;</entry>
+ <entry>Silhouette (outline).</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_VIVID</constant>&nbsp;</entry>
+ <entry>Vivid colors.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORFX_SET_CBCR</constant>&nbsp;</entry>
+ <entry>The Cb and Cr chroma components are replaced by fixed
+ coefficients determined by <constant>V4L2_CID_COLORFX_CBCR</constant>
+ control.</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ </row>
+ <row>
+ <entry><constant>V4L2_CID_COLORFX_CBCR</constant></entry>
+ <entry>integer</entry>
+ <entry>Determines the Cb and Cr coefficients for <constant>V4L2_COLORFX_SET_CBCR</constant>
+ color effect. Bits [7:0] of the supplied 32 bit value are interpreted as
+ Cr component, bits [15:8] as Cb component and bits [31:16] must be zero.
+ </entry>
</row>
<row>
<entry><constant>V4L2_CID_ROTATE</constant></entry>
@@ -2023,7 +2097,7 @@ Possible values are:</entry>
<entry>integer</entry>
</row>
<row><entry spanname="descr">Cyclic intra macroblock refresh. This is the number of continuous macroblocks
-refreshed every frame. Each frame a succesive set of macroblocks is refreshed until the cycle completes and starts from the
+refreshed every frame. Each frame a successive set of macroblocks is refreshed until the cycle completes and starts from the
top of the frame. Applicable to H264, H263 and MPEG4 encoder.</entry>
</row>
@@ -2183,7 +2257,7 @@ Applicable to the MPEG4 and H264 encoders.</entry>
<entry>integer</entry>
</row>
<row><entry spanname="descr">The Video Buffer Verifier size in kilobytes, it is used as a limitation of frame skip.
-The VBV is defined in the standard as a mean to verify that the produced stream will be succesfully decoded.
+The VBV is defined in the standard as a mean to verify that the produced stream will be successfully decoded.
The standard describes it as "Part of a hypothetical decoder that is conceptually connected to the
output of the encoder. Its purpose is to provide a constraint on the variability of the data rate that an
encoder or editing process may produce.".
@@ -2196,7 +2270,7 @@ Applicable to the MPEG1, MPEG2, MPEG4 encoders.</entry>
<entry>integer</entry>
</row>
<row><entry spanname="descr">The Coded Picture Buffer size in kilobytes, it is used as a limitation of frame skip.
-The CPB is defined in the H264 standard as a mean to verify that the produced stream will be succesfully decoded.
+The CPB is defined in the H264 standard as a mean to verify that the produced stream will be successfully decoded.
Applicable to the H264 encoder.</entry>
</row>
@@ -2775,6 +2849,51 @@ remain constant.</entry>
<row><entry></entry></row>
<row>
+ <entry spanname="id"><constant>V4L2_CID_EXPOSURE_BIAS</constant>&nbsp;</entry>
+ <entry>integer menu</entry>
+ </row><row><entry spanname="descr"> Determines the automatic
+exposure compensation, it is effective only when <constant>V4L2_CID_EXPOSURE_AUTO</constant>
+control is set to <constant>AUTO</constant>, <constant>SHUTTER_PRIORITY </constant>
+or <constant>APERTURE_PRIORITY</constant>.
+It is expressed in terms of EV, drivers should interpret the values as 0.001 EV
+units, where the value 1000 stands for +1 EV.
+<para>Increasing the exposure compensation value is equivalent to decreasing
+the exposure value (EV) and will increase the amount of light at the image
+sensor. The camera performs the exposure compensation by adjusting absolute
+exposure time and/or aperture.</para></entry>
+ </row>
+ <row><entry></entry></row>
+
+ <row id="v4l2-exposure-metering">
+ <entry spanname="id"><constant>V4L2_CID_EXPOSURE_METERING</constant>&nbsp;</entry>
+ <entry>enum&nbsp;v4l2_exposure_metering</entry>
+ </row><row><entry spanname="descr">Determines how the camera measures
+the amount of light available for the frame exposure. Possible values are:</entry>
+ </row>
+ <row>
+ <entrytbl spanname="descr" cols="2">
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_EXPOSURE_METERING_AVERAGE</constant>&nbsp;</entry>
+ <entry>Use the light information coming from the entire frame
+and average giving no weighting to any particular portion of the metered area.
+ </entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_EXPOSURE_METERING_CENTER_WEIGHTED</constant>&nbsp;</entry>
+ <entry>Average the light information coming from the entire frame
+giving priority to the center of the metered area.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_EXPOSURE_METERING_SPOT</constant>&nbsp;</entry>
+ <entry>Measure only very small area at the center of the frame.</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ </row>
+ <row><entry></entry></row>
+
+ <row>
<entry spanname="id"><constant>V4L2_CID_PAN_RELATIVE</constant>&nbsp;</entry>
<entry>integer</entry>
</row><row><entry spanname="descr">This control turns the
@@ -2857,13 +2976,107 @@ negative values towards infinity. This is a write-only control.</entry>
<row>
<entry spanname="id"><constant>V4L2_CID_FOCUS_AUTO</constant>&nbsp;</entry>
<entry>boolean</entry>
- </row><row><entry spanname="descr">Enables automatic focus
-adjustments. The effect of manual focus adjustments while this feature
+ </row><row><entry spanname="descr">Enables continuous automatic
+focus adjustments. The effect of manual focus adjustments while this feature
is enabled is undefined, drivers should ignore such requests.</entry>
</row>
<row><entry></entry></row>
<row>
+ <entry spanname="id"><constant>V4L2_CID_AUTO_FOCUS_START</constant>&nbsp;</entry>
+ <entry>button</entry>
+ </row><row><entry spanname="descr">Starts single auto focus process.
+The effect of setting this control when <constant>V4L2_CID_FOCUS_AUTO</constant>
+is set to <constant>TRUE</constant> (1) is undefined, drivers should ignore
+such requests.</entry>
+ </row>
+ <row><entry></entry></row>
+
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_AUTO_FOCUS_STOP</constant>&nbsp;</entry>
+ <entry>button</entry>
+ </row><row><entry spanname="descr">Aborts automatic focusing
+started with <constant>V4L2_CID_AUTO_FOCUS_START</constant> control. It is
+effective only when the continuous autofocus is disabled, that is when
+<constant>V4L2_CID_FOCUS_AUTO</constant> control is set to <constant>FALSE
+</constant> (0).</entry>
+ </row>
+ <row><entry></entry></row>
+
+ <row id="v4l2-auto-focus-status">
+ <entry spanname="id">
+ <constant>V4L2_CID_AUTO_FOCUS_STATUS</constant>&nbsp;</entry>
+ <entry>bitmask</entry>
+ </row>
+ <row><entry spanname="descr">The automatic focus status. This is a read-only
+ control.</entry>
+ </row>
+ <row>
+ <entrytbl spanname="descr" cols="2">
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_AUTO_FOCUS_STATUS_IDLE</constant>&nbsp;</entry>
+ <entry>Automatic focus is not active.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_AUTO_FOCUS_STATUS_BUSY</constant>&nbsp;</entry>
+ <entry>Automatic focusing is in progress.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_AUTO_FOCUS_STATUS_REACHED</constant>&nbsp;</entry>
+ <entry>Focus has been reached.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_AUTO_FOCUS_STATUS_FAILED</constant>&nbsp;</entry>
+ <entry>Automatic focus has failed, the driver will not
+ transition from this state until another action is
+ performed by an application.</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ </row>
+ <row><entry spanname="descr">
+Setting <constant>V4L2_LOCK_FOCUS</constant> lock bit of the <constant>V4L2_CID_3A_LOCK
+</constant> control may stop updates of the <constant>V4L2_CID_AUTO_FOCUS_STATUS</constant>
+control value.</entry>
+ </row>
+ <row><entry></entry></row>
+
+ <row id="v4l2-auto-focus-range">
+ <entry spanname="id">
+ <constant>V4L2_CID_AUTO_FOCUS_RANGE</constant>&nbsp;</entry>
+ <entry>enum&nbsp;v4l2_auto_focus_range</entry>
+ </row>
+ <row><entry spanname="descr">Determines auto focus distance range
+for which lens may be adjusted. </entry>
+ </row>
+ <row>
+ <entrytbl spanname="descr" cols="2">
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_AUTO_FOCUS_RANGE_AUTO</constant>&nbsp;</entry>
+ <entry>The camera automatically selects the focus range.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_AUTO_FOCUS_RANGE_NORMAL</constant>&nbsp;</entry>
+ <entry>Normal distance range, limited for best automatic focus
+performance.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_AUTO_FOCUS_RANGE_MACRO</constant>&nbsp;</entry>
+ <entry>Macro (close-up) auto focus. The camera will
+use its minimum possible distance for auto focus.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_AUTO_FOCUS_RANGE_INFINITY</constant>&nbsp;</entry>
+ <entry>The lens is set to focus on an object at infinite distance.</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ </row>
+ <row><entry></entry></row>
+
+ <row>
<entry spanname="id"><constant>V4L2_CID_ZOOM_ABSOLUTE</constant>&nbsp;</entry>
<entry>integer</entry>
</row><row><entry spanname="descr">Specify the objective lens
@@ -2932,6 +3145,295 @@ camera sensor on or off, or specify its strength. Such band-stop filters can
be used, for example, to filter out the fluorescent light component.</entry>
</row>
<row><entry></entry></row>
+
+ <row id="v4l2-auto-n-preset-white-balance">
+ <entry spanname="id"><constant>V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE</constant>&nbsp;</entry>
+ <entry>enum&nbsp;v4l2_auto_n_preset_white_balance</entry>
+ </row><row><entry spanname="descr">Sets white balance to automatic,
+manual or a preset. The presets determine color temperature of the light as
+a hint to the camera for white balance adjustments resulting in most accurate
+color representation. The following white balance presets are listed in order
+of increasing color temperature.</entry>
+ </row>
+ <row>
+ <entrytbl spanname="descr" cols="2">
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_WHITE_BALANCE_MANUAL</constant>&nbsp;</entry>
+ <entry>Manual white balance.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_WHITE_BALANCE_AUTO</constant>&nbsp;</entry>
+ <entry>Automatic white balance adjustments.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_WHITE_BALANCE_INCANDESCENT</constant>&nbsp;</entry>
+ <entry>White balance setting for incandescent (tungsten) lighting.
+It generally cools down the colors and corresponds approximately to 2500...3500 K
+color temperature range.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_WHITE_BALANCE_FLUORESCENT</constant>&nbsp;</entry>
+ <entry>White balance preset for fluorescent lighting.
+It corresponds approximately to 4000...5000 K color temperature.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_WHITE_BALANCE_FLUORESCENT_H</constant>&nbsp;</entry>
+ <entry>With this setting the camera will compensate for
+fluorescent H lighting.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_WHITE_BALANCE_HORIZON</constant>&nbsp;</entry>
+ <entry>White balance setting for horizon daylight.
+It corresponds approximately to 5000 K color temperature.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_WHITE_BALANCE_DAYLIGHT</constant>&nbsp;</entry>
+ <entry>White balance preset for daylight (with clear sky).
+It corresponds approximately to 5000...6500 K color temperature.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_WHITE_BALANCE_FLASH</constant>&nbsp;</entry>
+ <entry>With this setting the camera will compensate for the flash
+light. It slightly warms up the colors and corresponds roughly to 5000...5500 K
+color temperature.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_WHITE_BALANCE_CLOUDY</constant>&nbsp;</entry>
+ <entry>White balance preset for moderately overcast sky.
+This option corresponds approximately to 6500...8000 K color temperature
+range.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_WHITE_BALANCE_SHADE</constant>&nbsp;</entry>
+ <entry>White balance preset for shade or heavily overcast
+sky. It corresponds approximately to 9000...10000 K color temperature.
+</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ </row>
+ <row><entry></entry></row>
+
+ <row id="v4l2-wide-dynamic-range">
+ <entry spanname="id"><constant>V4L2_CID_WIDE_DYNAMIC_RANGE</constant></entry>
+ <entry>boolean</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Enables or disables the camera's wide dynamic
+range feature. This feature allows to obtain clear images in situations where
+intensity of the illumination varies significantly throughout the scene, i.e.
+there are simultaneously very dark and very bright areas. It is most commonly
+realized in cameras by combining two subsequent frames with different exposure
+times. <footnote id="ctypeconv"><para> This control may be changed to a menu
+control in the future, if more options are required.</para></footnote></entry>
+ </row>
+ <row><entry></entry></row>
+
+ <row id="v4l2-image-stabilization">
+ <entry spanname="id"><constant>V4L2_CID_IMAGE_STABILIZATION</constant></entry>
+ <entry>boolean</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Enables or disables image stabilization.
+ <footnoteref linkend="ctypeconv"/></entry>
+ </row>
+ <row><entry></entry></row>
+
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_ISO_SENSITIVITY</constant>&nbsp;</entry>
+ <entry>integer menu</entry>
+ </row><row><entry spanname="descr">Determines ISO equivalent of an
+image sensor indicating the sensor's sensitivity to light. The numbers are
+expressed in arithmetic scale, as per <xref linkend="iso12232" /> standard,
+where doubling the sensor sensitivity is represented by doubling the numerical
+ISO value. Applications should interpret the values as standard ISO values
+multiplied by 1000, e.g. control value 800 stands for ISO 0.8. Drivers will
+usually support only a subset of standard ISO values. The effect of setting
+this control while the <constant>V4L2_CID_ISO_SENSITIVITY_AUTO</constant>
+control is set to a value other than <constant>V4L2_CID_ISO_SENSITIVITY_MANUAL
+</constant> is undefined, drivers should ignore such requests.</entry>
+ </row>
+ <row><entry></entry></row>
+
+ <row id="v4l2-iso-sensitivity-auto-type">
+ <entry spanname="id"><constant>V4L2_CID_ISO_SENSITIVITY_AUTO</constant>&nbsp;</entry>
+ <entry>enum&nbsp;v4l2_iso_sensitivity_type</entry>
+ </row><row><entry spanname="descr">Enables or disables automatic ISO
+sensitivity adjustments.</entry>
+ </row>
+ <row>
+ <entrytbl spanname="descr" cols="2">
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_CID_ISO_SENSITIVITY_MANUAL</constant>&nbsp;</entry>
+ <entry>Manual ISO sensitivity.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_CID_ISO_SENSITIVITY_AUTO</constant>&nbsp;</entry>
+ <entry>Automatic ISO sensitivity adjustments.</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ </row>
+ <row><entry></entry></row>
+
+ <row id="v4l2-scene-mode">
+ <entry spanname="id"><constant>V4L2_CID_SCENE_MODE</constant>&nbsp;</entry>
+ <entry>enum&nbsp;v4l2_scene_mode</entry>
+ </row><row><entry spanname="descr">This control allows to select
+scene programs as the camera automatic modes optimized for common shooting
+scenes. Within these modes the camera determines best exposure, aperture,
+focusing, light metering, white balance and equivalent sensitivity. The
+controls of those parameters are influenced by the scene mode control.
+An exact behavior in each mode is subject to the camera specification.
+
+<para>When the scene mode feature is not used, this control should be set to
+<constant>V4L2_SCENE_MODE_NONE</constant> to make sure the other possibly
+related controls are accessible. The following scene programs are defined:
+</para>
+</entry>
+ </row>
+ <row>
+ <entrytbl spanname="descr" cols="2">
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_NONE</constant>&nbsp;</entry>
+ <entry>The scene mode feature is disabled.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_BACKLIGHT</constant>&nbsp;</entry>
+ <entry>Backlight. Compensates for dark shadows when light is
+ coming from behind a subject, also by automatically turning
+ on the flash.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_BEACH_SNOW</constant>&nbsp;</entry>
+ <entry>Beach and snow. This mode compensates for all-white or
+bright scenes, which tend to look gray and low contrast, when camera's automatic
+exposure is based on an average scene brightness. To compensate, this mode
+automatically slightly overexposes the frames. The white balance may also be
+adjusted to compensate for the fact that reflected snow looks bluish rather
+than white.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_CANDLELIGHT</constant>&nbsp;</entry>
+ <entry>Candle light. The camera generally raises the ISO
+sensitivity and lowers the shutter speed. This mode compensates for relatively
+close subject in the scene. The flash is disabled in order to preserve the
+ambiance of the light.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_DAWN_DUSK</constant>&nbsp;</entry>
+ <entry>Dawn and dusk. Preserves the colors seen in low
+natural light before dusk and after down. The camera may turn off the flash,
+and automatically focus at infinity. It will usually boost saturation and
+lower the shutter speed.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_FALL_COLORS</constant>&nbsp;</entry>
+ <entry>Fall colors. Increases saturation and adjusts white
+balance for color enhancement. Pictures of autumn leaves get saturated reds
+and yellows.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_FIREWORKS</constant>&nbsp;</entry>
+ <entry>Fireworks. Long exposure times are used to capture
+the expanding burst of light from a firework. The camera may invoke image
+stabilization.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_LANDSCAPE</constant>&nbsp;</entry>
+ <entry>Landscape. The camera may choose a small aperture to
+provide deep depth of field and long exposure duration to help capture detail
+in dim light conditions. The focus is fixed at infinity. Suitable for distant
+and wide scenery.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_NIGHT</constant>&nbsp;</entry>
+ <entry>Night, also known as Night Landscape. Designed for low
+light conditions, it preserves detail in the dark areas without blowing out bright
+objects. The camera generally sets itself to a medium-to-high ISO sensitivity,
+with a relatively long exposure time, and turns flash off. As such, there will be
+increased image noise and the possibility of blurred image.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_PARTY_INDOOR</constant>&nbsp;</entry>
+ <entry>Party and indoor. Designed to capture indoor scenes
+that are lit by indoor background lighting as well as the flash. The camera
+usually increases ISO sensitivity, and adjusts exposure for the low light
+conditions.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_PORTRAIT</constant>&nbsp;</entry>
+ <entry>Portrait. The camera adjusts the aperture so that the
+depth of field is reduced, which helps to isolate the subject against a smooth
+background. Most cameras recognize the presence of faces in the scene and focus
+on them. The color hue is adjusted to enhance skin tones. The intensity of the
+flash is often reduced.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_SPORTS</constant>&nbsp;</entry>
+ <entry>Sports. Significantly increases ISO and uses a fast
+shutter speed to freeze motion of rapidly-moving subjects. Increased image
+noise may be seen in this mode.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_SUNSET</constant>&nbsp;</entry>
+ <entry>Sunset. Preserves deep hues seen in sunsets and
+sunrises. It bumps up the saturation.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SCENE_MODE_TEXT</constant>&nbsp;</entry>
+ <entry>Text. It applies extra contrast and sharpness, it is
+typically a black-and-white mode optimized for readability. Automatic focus
+may be switched to close-up mode and this setting may also involve some
+lens-distortion correction.</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ </row>
+ <row><entry></entry></row>
+
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_3A_LOCK</constant></entry>
+ <entry>bitmask</entry>
+ </row>
+ <row>
+ <entry spanname="descr">This control locks or unlocks the automatic
+focus, exposure and white balance. The automatic adjustments can be paused
+independently by setting the corresponding lock bit to 1. The camera then retains
+the settings until the lock bit is cleared. The following lock bits are defined:
+</entry>
+ </row>
+ <row>
+ <entrytbl spanname="descr" cols="2">
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_LOCK_EXPOSURE</constant></entry>
+ <entry>Automatic exposure adjustments lock.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_LOCK_WHITE_BALANCE</constant></entry>
+ <entry>Automatic white balance adjustments lock.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_LOCK_FOCUS</constant></entry>
+ <entry>Automatic focus lock.</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ </row>
+ <row><entry spanname="descr">
+When a given algorithm is not enabled, drivers should ignore requests
+to lock it and should return no error. An example might be an application
+setting bit <constant>V4L2_LOCK_WHITE_BALANCE</constant> when the
+<constant>V4L2_CID_AUTO_WHITE_BALANCE</constant> control is set to
+<constant>FALSE</constant>. The value of this control may be changed
+by exposure, white balance or focus controls.</entry>
+ </row>
+ <row><entry></entry></row>
+
</tbody>
</tgroup>
</table>
@@ -3476,7 +3978,7 @@ interface and may change in the future.</para>
<entry spanname="id"><constant>V4L2_CID_JPEG_CHROMA_SUBSAMPLING</constant></entry>
<entry>menu</entry>
</row>
- <row id="jpeg-chroma-subsampling-control">
+ <row id="v4l2-jpeg-chroma-subsampling">
<entry spanname="descr">The chroma subsampling factors describe how
each component of an input image is sampled, in respect to maximum
sample rate in each spatial dimension. See <xref linkend="itu-t81"/>,
@@ -3486,7 +3988,7 @@ interface and may change in the future.</para>
from RGB to Y'CbCr color space.
</entry>
</row>
- <row>
+ <row id = "v4l2-jpeg-chroma-subsampling">
<entrytbl spanname="descr" cols="2">
<tbody valign="top">
<row>
@@ -3538,12 +4040,12 @@ interface and may change in the future.</para>
</entry>
</row>
<row id="jpeg-quality-control">
- <entry spanname="id"><constant>V4L2_CID_JPEG_COMPRESION_QUALITY</constant></entry>
+ <entry spanname="id"><constant>V4L2_CID_JPEG_COMPRESSION_QUALITY</constant></entry>
<entry>integer</entry>
</row>
<row>
<entry spanname="descr">
- <constant>V4L2_CID_JPEG_COMPRESION_QUALITY</constant> control
+ <constant>V4L2_CID_JPEG_COMPRESSION_QUALITY</constant> control
determines trade-off between image quality and size.
It provides simpler method for applications to control image quality,
without a need for direct reconfiguration of luminance and chrominance
@@ -3551,7 +4053,7 @@ interface and may change in the future.</para>
In cases where a driver uses quantization tables configured directly
by an application, using interfaces defined elsewhere, <constant>
- V4L2_CID_JPEG_COMPRESION_QUALITY</constant> control should be set
+ V4L2_CID_JPEG_COMPRESSION_QUALITY</constant> control should be set
by driver to 0.
<para>The value range of this control is driver-specific. Only
@@ -3599,4 +4101,172 @@ interface and may change in the future.</para>
to <xref linkend="itu-t81"/>, <xref linkend="jfif"/>,
<xref linkend="w3c-jpeg-jfif"/>.</para>
</section>
+
+ <section id="image-source-controls">
+ <title>Image Source Control Reference</title>
+
+ <note>
+ <title>Experimental</title>
+
+ <para>This is an <link
+ linkend="experimental">experimental</link> interface and may
+ change in the future.</para>
+ </note>
+
+ <para>
+ The Image Source control class is intended for low-level
+ control of image source devices such as image sensors. The
+ devices feature an analogue to digital converter and a bus
+ transmitter to transmit the image data out of the device.
+ </para>
+
+ <table pgwide="1" frame="none" id="image-source-control-id">
+ <title>Image Source Control IDs</title>
+
+ <tgroup cols="4">
+ <colspec colname="c1" colwidth="1*" />
+ <colspec colname="c2" colwidth="6*" />
+ <colspec colname="c3" colwidth="2*" />
+ <colspec colname="c4" colwidth="6*" />
+ <spanspec namest="c1" nameend="c2" spanname="id" />
+ <spanspec namest="c2" nameend="c4" spanname="descr" />
+ <thead>
+ <row>
+ <entry spanname="id" align="left">ID</entry>
+ <entry align="left">Type</entry>
+ </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row><entry></entry></row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_IMAGE_SOURCE_CLASS</constant></entry>
+ <entry>class</entry>
+ </row>
+ <row>
+ <entry spanname="descr">The IMAGE_SOURCE class descriptor.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_VBLANK</constant></entry>
+ <entry>integer</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Vertical blanking. The idle period
+ after every frame during which no image data is produced.
+ The unit of vertical blanking is a line. Every line has
+ length of the image width plus horizontal blanking at the
+ pixel rate defined by
+ <constant>V4L2_CID_PIXEL_RATE</constant> control in the
+ same sub-device.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_HBLANK</constant></entry>
+ <entry>integer</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Horizontal blanking. The idle
+ period after every line of image data during which no
+ image data is produced. The unit of horizontal blanking is
+ pixels.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_ANALOGUE_GAIN</constant></entry>
+ <entry>integer</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Analogue gain is gain affecting
+ all colour components in the pixel matrix. The gain
+ operation is performed in the analogue domain before A/D
+ conversion.
+ </entry>
+ </row>
+ <row><entry></entry></row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </section>
+
+ <section id="image-process-controls">
+ <title>Image Process Control Reference</title>
+
+ <note>
+ <title>Experimental</title>
+
+ <para>This is an <link
+ linkend="experimental">experimental</link> interface and may
+ change in the future.</para>
+ </note>
+
+ <para>
+ The Image Source control class is intended for low-level control of
+ image processing functions. Unlike
+ <constant>V4L2_CID_IMAGE_SOURCE_CLASS</constant>, the controls in
+ this class affect processing the image, and do not control capturing
+ of it.
+ </para>
+
+ <table pgwide="1" frame="none" id="image-process-control-id">
+ <title>Image Source Control IDs</title>
+
+ <tgroup cols="4">
+ <colspec colname="c1" colwidth="1*" />
+ <colspec colname="c2" colwidth="6*" />
+ <colspec colname="c3" colwidth="2*" />
+ <colspec colname="c4" colwidth="6*" />
+ <spanspec namest="c1" nameend="c2" spanname="id" />
+ <spanspec namest="c2" nameend="c4" spanname="descr" />
+ <thead>
+ <row>
+ <entry spanname="id" align="left">ID</entry>
+ <entry align="left">Type</entry>
+ </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row><entry></entry></row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_IMAGE_PROC_CLASS</constant></entry>
+ <entry>class</entry>
+ </row>
+ <row>
+ <entry spanname="descr">The IMAGE_PROC class descriptor.</entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_LINK_FREQ</constant></entry>
+ <entry>integer menu</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Data bus frequency. Together with the
+ media bus pixel code, bus type (clock cycles per sample), the
+ data bus frequency defines the pixel rate
+ (<constant>V4L2_CID_PIXEL_RATE</constant>) in the
+ pixel array (or possibly elsewhere, if the device is not an
+ image sensor). The frame rate can be calculated from the pixel
+ clock, image width and height and horizontal and vertical
+ blanking. While the pixel rate control may be defined elsewhere
+ than in the subdev containing the pixel array, the frame rate
+ cannot be obtained from that information. This is because only
+ on the pixel array it can be assumed that the vertical and
+ horizontal blanking information is exact: no other blanking is
+ allowed in the pixel array. The selection of frame rate is
+ performed by selecting the desired horizontal and vertical
+ blanking. The unit of this control is Hz. </entry>
+ </row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_PIXEL_RATE</constant></entry>
+ <entry>64-bit integer</entry>
+ </row>
+ <row>
+ <entry spanname="descr">Pixel rate in the source pads of
+ the subdev. This control is read-only and its unit is
+ pixels / second.
+ </entry>
+ </row>
+ <row><entry></entry></row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </section>
</section>
diff --git a/Documentation/DocBook/media/v4l/dev-subdev.xml b/Documentation/DocBook/media/v4l/dev-subdev.xml
index 0916a7343a16..4afcbbec5eda 100644
--- a/Documentation/DocBook/media/v4l/dev-subdev.xml
+++ b/Documentation/DocBook/media/v4l/dev-subdev.xml
@@ -76,11 +76,12 @@
<wordasword>format</wordasword> means the combination of media bus data
format, frame width and frame height.</para></note>
- <para>Image formats are typically negotiated on video capture and output
- devices using the <link linkend="crop">cropping and scaling</link> ioctls.
- The driver is responsible for configuring every block in the video pipeline
- according to the requested format at the pipeline input and/or
- output.</para>
+ <para>Image formats are typically negotiated on video capture and
+ output devices using the format and <link
+ linkend="vidioc-subdev-g-selection">selection</link> ioctls. The
+ driver is responsible for configuring every block in the video
+ pipeline according to the requested format at the pipeline input
+ and/or output.</para>
<para>For complex devices, such as often found in embedded systems,
identical image sizes at the output of a pipeline can be achieved using
@@ -276,11 +277,11 @@
</section>
<section>
- <title>Cropping and scaling</title>
+ <title>Selections: cropping, scaling and composition</title>
<para>Many sub-devices support cropping frames on their input or output
pads (or possible even on both). Cropping is used to select the area of
- interest in an image, typically on a video sensor or video decoder. It can
+ interest in an image, typically on an image sensor or a video decoder. It can
also be used as part of digital zoom implementations to select the area of
the image that will be scaled up.</para>
@@ -288,26 +289,179 @@
&v4l2-rect; by the coordinates of the top left corner and the rectangle
size. Both the coordinates and sizes are expressed in pixels.</para>
- <para>The crop rectangle is retrieved and set using the
- &VIDIOC-SUBDEV-G-CROP; and &VIDIOC-SUBDEV-S-CROP; ioctls. Like for pad
- formats, drivers store try and active crop rectangles. The format
- negotiation mechanism applies to crop settings as well.</para>
-
- <para>On input pads, cropping is applied relatively to the current pad
- format. The pad format represents the image size as received by the
- sub-device from the previous block in the pipeline, and the crop rectangle
- represents the sub-image that will be transmitted further inside the
- sub-device for processing. The crop rectangle be entirely containted
- inside the input image size.</para>
-
- <para>Input crop rectangle are reset to their default value when the input
- image format is modified. Drivers should use the input image size as the
- crop rectangle default value, but hardware requirements may prevent this.
- </para>
+ <para>As for pad formats, drivers store try and active
+ rectangles for the selection targets of ACTUAL type <xref
+ linkend="v4l2-subdev-selection-targets">.</xref></para>
+
+ <para>On sink pads, cropping is applied relative to the
+ current pad format. The pad format represents the image size as
+ received by the sub-device from the previous block in the
+ pipeline, and the crop rectangle represents the sub-image that
+ will be transmitted further inside the sub-device for
+ processing.</para>
+
+ <para>The scaling operation changes the size of the image by
+ scaling it to new dimensions. The scaling ratio isn't specified
+ explicitly, but is implied from the original and scaled image
+ sizes. Both sizes are represented by &v4l2-rect;.</para>
+
+ <para>Scaling support is optional. When supported by a subdev,
+ the crop rectangle on the subdev's sink pad is scaled to the
+ size configured using the &VIDIOC-SUBDEV-S-SELECTION; IOCTL
+ using <constant>V4L2_SUBDEV_SEL_COMPOSE_ACTUAL</constant>
+ selection target on the same pad. If the subdev supports scaling
+ but not composing, the top and left values are not used and must
+ always be set to zero.</para>
+
+ <para>On source pads, cropping is similar to sink pads, with the
+ exception that the source size from which the cropping is
+ performed, is the COMPOSE rectangle on the sink pad. In both
+ sink and source pads, the crop rectangle must be entirely
+ contained inside the source image size for the crop
+ operation.</para>
+
+ <para>The drivers should always use the closest possible
+ rectangle the user requests on all selection targets, unless
+ specifically told otherwise.
+ <constant>V4L2_SUBDEV_SEL_FLAG_SIZE_GE</constant> and
+ <constant>V4L2_SUBDEV_SEL_FLAG_SIZE_LE</constant> flags may be
+ used to round the image size either up or down. <xref
+ linkend="v4l2-subdev-selection-flags"></xref></para>
+ </section>
+
+ <section>
+ <title>Types of selection targets</title>
+
+ <section>
+ <title>ACTUAL targets</title>
+
+ <para>ACTUAL targets reflect the actual hardware configuration
+ at any point of time. There is a BOUNDS target
+ corresponding to every ACTUAL.</para>
+ </section>
+
+ <section>
+ <title>BOUNDS targets</title>
+
+ <para>BOUNDS targets is the smallest rectangle that contains
+ all valid ACTUAL rectangles. It may not be possible to set the
+ ACTUAL rectangle as large as the BOUNDS rectangle, however.
+ This may be because e.g. a sensor's pixel array is not
+ rectangular but cross-shaped or round. The maximum size may
+ also be smaller than the BOUNDS rectangle.</para>
+ </section>
- <para>Cropping behaviour on output pads is not defined.</para>
+ </section>
+
+ <section>
+ <title>Order of configuration and format propagation</title>
+
+ <para>Inside subdevs, the order of image processing steps will
+ always be from the sink pad towards the source pad. This is also
+ reflected in the order in which the configuration must be
+ performed by the user: the changes made will be propagated to
+ any subsequent stages. If this behaviour is not desired, the
+ user must set
+ <constant>V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG</constant> flag. This
+ flag causes no propagation of the changes are allowed in any
+ circumstances. This may also cause the accessed rectangle to be
+ adjusted by the driver, depending on the properties of the
+ underlying hardware.</para>
+
+ <para>The coordinates to a step always refer to the actual size
+ of the previous step. The exception to this rule is the source
+ compose rectangle, which refers to the sink compose bounds
+ rectangle --- if it is supported by the hardware.</para>
+
+ <orderedlist>
+ <listitem>Sink pad format. The user configures the sink pad
+ format. This format defines the parameters of the image the
+ entity receives through the pad for further processing.</listitem>
+
+ <listitem>Sink pad actual crop selection. The sink pad crop
+ defines the crop performed to the sink pad format.</listitem>
+
+ <listitem>Sink pad actual compose selection. The size of the
+ sink pad compose rectangle defines the scaling ratio compared
+ to the size of the sink pad crop rectangle. The location of
+ the compose rectangle specifies the location of the actual
+ sink compose rectangle in the sink compose bounds
+ rectangle.</listitem>
+
+ <listitem>Source pad actual crop selection. Crop on the source
+ pad defines crop performed to the image in the sink compose
+ bounds rectangle.</listitem>
+
+ <listitem>Source pad format. The source pad format defines the
+ output pixel format of the subdev, as well as the other
+ parameters with the exception of the image width and height.
+ Width and height are defined by the size of the source pad
+ actual crop selection.</listitem>
+ </orderedlist>
+
+ <para>Accessing any of the above rectangles not supported by the
+ subdev will return <constant>EINVAL</constant>. Any rectangle
+ referring to a previous unsupported rectangle coordinates will
+ instead refer to the previous supported rectangle. For example,
+ if sink crop is not supported, the compose selection will refer
+ to the sink pad format dimensions instead.</para>
+
+ <figure id="subdev-image-processing-crop">
+ <title>Image processing in subdevs: simple crop example</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="subdev-image-processing-crop.svg"
+ format="SVG" scale="200" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>In the above example, the subdev supports cropping on its
+ sink pad. To configure it, the user sets the media bus format on
+ the subdev's sink pad. Now the actual crop rectangle can be set
+ on the sink pad --- the location and size of this rectangle
+ reflect the location and size of a rectangle to be cropped from
+ the sink format. The size of the sink crop rectangle will also
+ be the size of the format of the subdev's source pad.</para>
+
+ <figure id="subdev-image-processing-scaling-multi-source">
+ <title>Image processing in subdevs: scaling with multiple sources</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="subdev-image-processing-scaling-multi-source.svg"
+ format="SVG" scale="200" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>In this example, the subdev is capable of first cropping,
+ then scaling and finally cropping for two source pads
+ individually from the resulting scaled image. The location of
+ the scaled image in the cropped image is ignored in sink compose
+ target. Both of the locations of the source crop rectangles
+ refer to the sink scaling rectangle, independently cropping an
+ area at location specified by the source crop rectangle from
+ it.</para>
+
+ <figure id="subdev-image-processing-full">
+ <title>Image processing in subdevs: scaling and composition
+ with multiple sinks and sources</title>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="subdev-image-processing-full.svg"
+ format="SVG" scale="200" />
+ </imageobject>
+ </mediaobject>
+ </figure>
+
+ <para>The subdev driver supports two sink pads and two source
+ pads. The images from both of the sink pads are individually
+ cropped, then scaled and further composed on the composition
+ bounds rectangle. From that, two independent streams are cropped
+ and sent out of the subdev from the source pads.</para>
</section>
+
</section>
&sub-subdev-formats;
diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml
index b815929b5bba..fd6aca2922b6 100644
--- a/Documentation/DocBook/media/v4l/io.xml
+++ b/Documentation/DocBook/media/v4l/io.xml
@@ -543,12 +543,13 @@ and can range from zero to the number of buffers allocated
with the &VIDIOC-REQBUFS; ioctl (&v4l2-requestbuffers; <structfield>count</structfield>) minus one.</entry>
</row>
<row>
- <entry>&v4l2-buf-type;</entry>
+ <entry>__u32</entry>
<entry><structfield>type</structfield></entry>
<entry></entry>
<entry>Type of the buffer, same as &v4l2-format;
<structfield>type</structfield> or &v4l2-requestbuffers;
-<structfield>type</structfield>, set by the application.</entry>
+<structfield>type</structfield>, set by the application. See <xref
+linkend="v4l2-buf-type" /></entry>
</row>
<row>
<entry>__u32</entry>
@@ -568,7 +569,7 @@ refers to an input stream, applications when an output stream.</entry>
linkend="buffer-flags" />.</entry>
</row>
<row>
- <entry>&v4l2-field;</entry>
+ <entry>__u32</entry>
<entry><structfield>field</structfield></entry>
<entry></entry>
<entry>Indicates the field order of the image in the
@@ -630,11 +631,12 @@ bandwidth. These devices identify by not enumerating any video
standards, see <xref linkend="standard" />.</para></entry>
</row>
<row>
- <entry>&v4l2-memory;</entry>
+ <entry>__u32</entry>
<entry><structfield>memory</structfield></entry>
<entry></entry>
<entry>This field must be set by applications and/or drivers
-in accordance with the selected I/O method.</entry>
+in accordance with the selected I/O method. See <xref linkend="v4l2-memory"
+ /></entry>
</row>
<row>
<entry>union</entry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb10.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb10.xml
index 7b274092e60c..c1c62a9acc2a 100644
--- a/Documentation/DocBook/media/v4l/pixfmt-srggb10.xml
+++ b/Documentation/DocBook/media/v4l/pixfmt-srggb10.xml
@@ -1,4 +1,4 @@
- <refentry>
+ <refentry id="pixfmt-srggb10">
<refmeta>
<refentrytitle>V4L2_PIX_FMT_SRGGB10 ('RG10'),
V4L2_PIX_FMT_SGRBG10 ('BA10'),
diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml
new file mode 100644
index 000000000000..8eace3e2e7d4
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/pixfmt-srggb10dpcm8.xml
@@ -0,0 +1,29 @@
+ <refentry id="pixfmt-srggb10dpcm8">
+ <refmeta>
+ <refentrytitle>
+ V4L2_PIX_FMT_SBGGR10DPCM8 ('bBA8'),
+ V4L2_PIX_FMT_SGBRG10DPCM8 ('bGA8'),
+ V4L2_PIX_FMT_SGRBG10DPCM8 ('BD10'),
+ V4L2_PIX_FMT_SRGGB10DPCM8 ('bRA8'),
+ </refentrytitle>
+ &manvol;
+ </refmeta>
+ <refnamediv>
+ <refname id="V4L2-PIX-FMT-SBGGR10DPCM8"><constant>V4L2_PIX_FMT_SBGGR10DPCM8</constant></refname>
+ <refname id="V4L2-PIX-FMT-SGBRG10DPCM8"><constant>V4L2_PIX_FMT_SGBRG10DPCM8</constant></refname>
+ <refname id="V4L2-PIX-FMT-SGRBG10DPCM8"><constant>V4L2_PIX_FMT_SGRBG10DPCM8</constant></refname>
+ <refname id="V4L2-PIX-FMT-SRGGB10DPCM8"><constant>V4L2_PIX_FMT_SRGGB10DPCM8</constant></refname>
+ <refpurpose>10-bit Bayer formats compressed to 8 bits</refpurpose>
+ </refnamediv>
+ <refsect1>
+ <title>Description</title>
+
+ <para>The following four pixel formats are raw sRGB / Bayer formats
+ with 10 bits per colour compressed to 8 bits each, using DPCM
+ compression. DPCM, differential pulse-code modulation, is lossy.
+ Each colour component consumes 8 bits of memory. In other respects
+ this format is similar to <xref
+ linkend="pixfmt-srggb10">.</xref></para>
+
+ </refsect1>
+ </refentry>
diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml
index 31eaae2469f9..f5ac15ed0549 100644
--- a/Documentation/DocBook/media/v4l/pixfmt.xml
+++ b/Documentation/DocBook/media/v4l/pixfmt.xml
@@ -673,6 +673,7 @@ access the palette, this must be done with ioctls of the Linux framebuffer API.<
&sub-srggb8;
&sub-sbggr16;
&sub-srggb10;
+ &sub-srggb10dpcm8;
&sub-srggb12;
</section>
@@ -876,11 +877,6 @@ kernel sources in the file <filename>Documentation/video4linux/cx2341x/README.hm
<entry>'S561'</entry>
<entry>Compressed GBRG Bayer format used by the gspca driver.</entry>
</row>
- <row id="V4L2-PIX-FMT-SGRBG10DPCM8">
- <entry><constant>V4L2_PIX_FMT_SGRBG10DPCM8</constant></entry>
- <entry>'DB10'</entry>
- <entry>10 bit raw Bayer DPCM compressed to 8 bits.</entry>
- </row>
<row id="V4L2-PIX-FMT-PAC207">
<entry><constant>V4L2_PIX_FMT_PAC207</constant></entry>
<entry>'P207'</entry>
diff --git a/Documentation/DocBook/media/v4l/subdev-image-processing-crop.dia b/Documentation/DocBook/media/v4l/subdev-image-processing-crop.dia
new file mode 100644
index 000000000000..e32ba5362e1d
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/subdev-image-processing-crop.dia
@@ -0,0 +1,614 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
+ <dia:diagramdata>
+ <dia:attribute name="background">
+ <dia:color val="#ffffff"/>
+ </dia:attribute>
+ <dia:attribute name="pagebreak">
+ <dia:color val="#000099"/>
+ </dia:attribute>
+ <dia:attribute name="paper">
+ <dia:composite type="paper">
+ <dia:attribute name="name">
+ <dia:string>#A4#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="tmargin">
+ <dia:real val="2.8222000598907471"/>
+ </dia:attribute>
+ <dia:attribute name="bmargin">
+ <dia:real val="2.8222000598907471"/>
+ </dia:attribute>
+ <dia:attribute name="lmargin">
+ <dia:real val="2.8222000598907471"/>
+ </dia:attribute>
+ <dia:attribute name="rmargin">
+ <dia:real val="2.8222000598907471"/>
+ </dia:attribute>
+ <dia:attribute name="is_portrait">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="scaling">
+ <dia:real val="0.49000000953674316"/>
+ </dia:attribute>
+ <dia:attribute name="fitto">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="grid">
+ <dia:composite type="grid">
+ <dia:attribute name="width_x">
+ <dia:real val="1"/>
+ </dia:attribute>
+ <dia:attribute name="width_y">
+ <dia:real val="1"/>
+ </dia:attribute>
+ <dia:attribute name="visible_x">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="visible_y">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:composite type="color"/>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#d8e5e5"/>
+ </dia:attribute>
+ <dia:attribute name="guides">
+ <dia:composite type="guides">
+ <dia:attribute name="hguides"/>
+ <dia:attribute name="vguides"/>
+ </dia:composite>
+ </dia:attribute>
+ </dia:diagramdata>
+ <dia:layer name="Background" visible="true" active="true">
+ <dia:object type="Standard - Box" version="0" id="O0">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-0.4,6.5"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-0.45,6.45;23.1387,16.2"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-0.4,6.5"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="23.48871579904775"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="9.6500000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Box" version="0" id="O1">
+ <dia:attribute name="obj_pos">
+ <dia:point val="0.225,9.45"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="0.175,9.4;8.225,14.7"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="0.225,9.45"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="7.9499999999999975"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="5.1999999999999975"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="border_color">
+ <dia:color val="#a52a2a"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Box" version="0" id="O2">
+ <dia:attribute name="obj_pos">
+ <dia:point val="3.175,10.55"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="3.125,10.5;7.925,14.45"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="3.175,10.55"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="4.6999999999999975"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="3.8499999999999979"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="border_color">
+ <dia:color val="#0000ff"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O3">
+ <dia:attribute name="obj_pos">
+ <dia:point val="3.725,11.3875"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="3.725,10.7925;6.6025,13.14"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#sink
+crop
+selection#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="3.725,11.3875"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#0000ff"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O4">
+ <dia:attribute name="obj_pos">
+ <dia:point val="1.475,7.9"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="1.475,7.305;1.475,8.0525"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="1.475,7.9"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O5">
+ <dia:attribute name="obj_pos">
+ <dia:point val="0.426918,7.89569"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="0.426918,7.30069;3.90942,8.84819"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#sink media
+bus format#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="0.426918,7.89569"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#a52a2a"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O6">
+ <dia:attribute name="obj_pos">
+ <dia:point val="17.4887,7.75"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="17.4887,7.155;21.8112,8.7025"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#source media
+bus format#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="17.4887,7.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#8b6914"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Box" version="0" id="O7">
+ <dia:attribute name="obj_pos">
+ <dia:point val="17.5244,9.5417"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="17.4744,9.4917;22.2387,13.35"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="17.5244,9.5417"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="4.6643157990477508"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="3.758300000000002"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="border_color">
+ <dia:color val="#8b6914"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O8">
+ <dia:attribute name="obj_pos">
+ <dia:point val="17.5244,13.3"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="3.12132,13.2463;17.5781,14.4537"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="17.5244,13.3"/>
+ <dia:point val="3.175,14.4"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O7" connection="5"/>
+ <dia:connection handle="1" to="O2" connection="5"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O9">
+ <dia:attribute name="obj_pos">
+ <dia:point val="17.5244,9.5417"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="3.12162,9.48832;17.5778,10.6034"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="17.5244,9.5417"/>
+ <dia:point val="3.175,10.55"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O7" connection="0"/>
+ <dia:connection handle="1" to="O2" connection="0"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O10">
+ <dia:attribute name="obj_pos">
+ <dia:point val="22.1887,13.3"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="7.82132,13.2463;22.2424,14.4537"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="22.1887,13.3"/>
+ <dia:point val="7.875,14.4"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O7" connection="7"/>
+ <dia:connection handle="1" to="O2" connection="7"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O11">
+ <dia:attribute name="obj_pos">
+ <dia:point val="22.1887,9.5417"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="7.82161,9.48831;22.2421,10.6034"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="22.1887,9.5417"/>
+ <dia:point val="7.875,10.55"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O7" connection="2"/>
+ <dia:connection handle="1" to="O2" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Geometric - Perfect Circle" version="1" id="O12">
+ <dia:attribute name="obj_pos">
+ <dia:point val="23.23,10.5742"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="23.18,10.5242;24.13,11.4742"/>
+ </dia:attribute>
+ <dia:attribute name="meta">
+ <dia:composite type="dict"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="23.23,10.5742"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="0.84999999999999787"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="0.84999999999999787"/>
+ </dia:attribute>
+ <dia:attribute name="line_width">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="line_colour">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="fill_colour">
+ <dia:color val="#ffffff"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="0"/>
+ <dia:real val="1"/>
+ </dia:attribute>
+ <dia:attribute name="flip_horizontal">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="flip_vertical">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="subscale">
+ <dia:real val="1"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O13">
+ <dia:attribute name="obj_pos">
+ <dia:point val="24.08,10.9992"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="24.03,10.6388;32.4953,11.3624"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="24.08,10.9992"/>
+ <dia:point val="32.3835,11.0007"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O12" connection="3"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O14">
+ <dia:attribute name="obj_pos">
+ <dia:point val="25.3454,10.49"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="25.3454,9.895;29.9904,10.6425"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#pad 1 (source)#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="25.3454,10.49"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Geometric - Perfect Circle" version="1" id="O15">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-1.44491,11.6506"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-1.49491,11.6006;-0.54491,12.5506"/>
+ </dia:attribute>
+ <dia:attribute name="meta">
+ <dia:composite type="dict"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-1.44491,11.6506"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="0.84999999999999787"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="0.84999999999999787"/>
+ </dia:attribute>
+ <dia:attribute name="line_width">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="line_colour">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="fill_colour">
+ <dia:color val="#ffffff"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="0"/>
+ <dia:real val="1"/>
+ </dia:attribute>
+ <dia:attribute name="flip_horizontal">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="flip_vertical">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="subscale">
+ <dia:real val="1"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O16">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-9.61991,12.09"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-9.67,11.7149;-1.33311,12.4385"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="-9.61991,12.09"/>
+ <dia:point val="-1.44491,12.0756"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="1" to="O15" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O17">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-7.39291,11.49"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-7.39291,10.895;-3.58791,11.6425"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#pad 0 (sink)#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="-7.39291,11.49"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ </dia:layer>
+</dia:diagram>
diff --git a/Documentation/DocBook/media/v4l/subdev-image-processing-crop.svg b/Documentation/DocBook/media/v4l/subdev-image-processing-crop.svg
new file mode 100644
index 000000000000..18b0f5de9ed2
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/subdev-image-processing-crop.svg
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd">
+<svg width="43cm" height="10cm" viewBox="-194 128 844 196" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="-8" y="130" width="469.774" height="193"/>
+ <g>
+ <rect style="fill: #ffffff" x="4.5" y="189" width="159" height="104"/>
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a52a2a" x="4.5" y="189" width="159" height="104"/>
+ </g>
+ <g>
+ <rect style="fill: #ffffff" x="63.5" y="211" width="94" height="77"/>
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" x="63.5" y="211" width="94" height="77"/>
+ </g>
+ <text style="fill: #0000ff;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="74.5" y="227.75">
+ <tspan x="74.5" y="227.75">sink</tspan>
+ <tspan x="74.5" y="243.75">crop</tspan>
+ <tspan x="74.5" y="259.75">selection</tspan>
+ </text>
+ <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="29.5" y="158">
+ <tspan x="29.5" y="158"></tspan>
+ </text>
+ <text style="fill: #a52a2a;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="8.53836" y="157.914">
+ <tspan x="8.53836" y="157.914">sink media</tspan>
+ <tspan x="8.53836" y="173.914">bus format</tspan>
+ </text>
+ <text style="fill: #8b6914;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="349.774" y="155">
+ <tspan x="349.774" y="155">source media</tspan>
+ <tspan x="349.774" y="171">bus format</tspan>
+ </text>
+ <g>
+ <rect style="fill: #ffffff" x="350.488" y="190.834" width="93.2863" height="75.166"/>
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #8b6914" x="350.488" y="190.834" width="93.2863" height="75.166"/>
+ </g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="350.488" y1="266" x2="63.5" y2="288"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="350.488" y1="190.834" x2="63.5" y2="211"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="443.774" y1="266" x2="157.5" y2="288"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="443.774" y1="190.834" x2="157.5" y2="211"/>
+ <g>
+ <ellipse style="fill: #ffffff" cx="473.1" cy="219.984" rx="8.5" ry="8.5"/>
+ <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="473.1" cy="219.984" rx="8.5" ry="8.5"/>
+ <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="473.1" cy="219.984" rx="8.5" ry="8.5"/>
+ </g>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="481.6" y1="219.984" x2="637.934" y2="220.012"/>
+ <polygon style="fill: #000000" points="645.434,220.014 635.433,225.012 637.934,220.012 635.435,215.012 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="645.434,220.014 635.433,225.012 637.934,220.012 635.435,215.012 "/>
+ </g>
+ <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="506.908" y="209.8">
+ <tspan x="506.908" y="209.8">pad 1 (source)</tspan>
+ </text>
+ <g>
+ <ellipse style="fill: #ffffff" cx="-20.3982" cy="241.512" rx="8.5" ry="8.5"/>
+ <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-20.3982" cy="241.512" rx="8.5" ry="8.5"/>
+ <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-20.3982" cy="241.512" rx="8.5" ry="8.5"/>
+ </g>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="-192.398" y1="241.8" x2="-38.6343" y2="241.529"/>
+ <polygon style="fill: #000000" points="-31.1343,241.516 -41.1254,246.534 -38.6343,241.529 -41.1431,236.534 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="-31.1343,241.516 -41.1254,246.534 -38.6343,241.529 -41.1431,236.534 "/>
+ </g>
+ <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="-147.858" y="229.8">
+ <tspan x="-147.858" y="229.8">pad 0 (sink)</tspan>
+ </text>
+</svg>
diff --git a/Documentation/DocBook/media/v4l/subdev-image-processing-full.dia b/Documentation/DocBook/media/v4l/subdev-image-processing-full.dia
new file mode 100644
index 000000000000..a0d782927840
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/subdev-image-processing-full.dia
@@ -0,0 +1,1588 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
+ <dia:diagramdata>
+ <dia:attribute name="background">
+ <dia:color val="#ffffff"/>
+ </dia:attribute>
+ <dia:attribute name="pagebreak">
+ <dia:color val="#000099"/>
+ </dia:attribute>
+ <dia:attribute name="paper">
+ <dia:composite type="paper">
+ <dia:attribute name="name">
+ <dia:string>#A4#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="tmargin">
+ <dia:real val="2.8222000598907471"/>
+ </dia:attribute>
+ <dia:attribute name="bmargin">
+ <dia:real val="2.8222000598907471"/>
+ </dia:attribute>
+ <dia:attribute name="lmargin">
+ <dia:real val="2.8222000598907471"/>
+ </dia:attribute>
+ <dia:attribute name="rmargin">
+ <dia:real val="2.8222000598907471"/>
+ </dia:attribute>
+ <dia:attribute name="is_portrait">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="scaling">
+ <dia:real val="0.49000000953674316"/>
+ </dia:attribute>
+ <dia:attribute name="fitto">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="grid">
+ <dia:composite type="grid">
+ <dia:attribute name="width_x">
+ <dia:real val="1"/>
+ </dia:attribute>
+ <dia:attribute name="width_y">
+ <dia:real val="1"/>
+ </dia:attribute>
+ <dia:attribute name="visible_x">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="visible_y">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:composite type="color"/>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#d8e5e5"/>
+ </dia:attribute>
+ <dia:attribute name="guides">
+ <dia:composite type="guides">
+ <dia:attribute name="hguides"/>
+ <dia:attribute name="vguides"/>
+ </dia:composite>
+ </dia:attribute>
+ </dia:diagramdata>
+ <dia:layer name="Background" visible="true" active="true">
+ <dia:object type="Standard - Box" version="0" id="O0">
+ <dia:attribute name="obj_pos">
+ <dia:point val="15.945,6.45"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="15.895,6.4;26.4,18.95"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="15.945,6.45"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="10.404999999254942"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="12.449999999999992"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="border_color">
+ <dia:color val="#ff765a"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Box" version="0" id="O1">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-0.1,3.65"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-0.15,3.6;40.25,20.85"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-0.1,3.65"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="40.300000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="17.149999999999999"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Geometric - Perfect Circle" version="1" id="O2">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-1.05,7.9106"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-1.1,7.8606;-0.15,8.8106"/>
+ </dia:attribute>
+ <dia:attribute name="meta">
+ <dia:composite type="dict"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-1.05,7.9106"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="0.84999999999999787"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="0.84999999999999787"/>
+ </dia:attribute>
+ <dia:attribute name="line_width">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="line_colour">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="fill_colour">
+ <dia:color val="#ffffff"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="0"/>
+ <dia:real val="1"/>
+ </dia:attribute>
+ <dia:attribute name="flip_horizontal">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="flip_vertical">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="subscale">
+ <dia:real val="1"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Geometric - Perfect Circle" version="1" id="O3">
+ <dia:attribute name="obj_pos">
+ <dia:point val="40.3366,9.8342"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="40.2866,9.7842;41.2366,10.7342"/>
+ </dia:attribute>
+ <dia:attribute name="meta">
+ <dia:composite type="dict"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="40.3366,9.8342"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="0.84999999999999787"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="0.84999999999999787"/>
+ </dia:attribute>
+ <dia:attribute name="line_width">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="line_colour">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="fill_colour">
+ <dia:color val="#ffffff"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="0"/>
+ <dia:real val="1"/>
+ </dia:attribute>
+ <dia:attribute name="flip_horizontal">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="flip_vertical">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="subscale">
+ <dia:real val="1"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O4">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-9.225,8.35"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-9.27509,7.97487;-0.938197,8.69848"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="-9.225,8.35"/>
+ <dia:point val="-1.05,8.3356"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="1" to="O2" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O5">
+ <dia:attribute name="obj_pos">
+ <dia:point val="41.1866,10.2592"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="41.1366,9.89879;49.6019,10.6224"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="41.1866,10.2592"/>
+ <dia:point val="49.4901,10.2607"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O3" connection="3"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O6">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-6.998,7.75"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-6.998,7.155;-3.193,7.9025"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#pad 0 (sink)#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="-6.998,7.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O7">
+ <dia:attribute name="obj_pos">
+ <dia:point val="42.452,9.75"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="42.452,9.155;47.097,9.9025"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#pad 2 (source)#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="42.452,9.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Box" version="0" id="O8">
+ <dia:attribute name="obj_pos">
+ <dia:point val="0.275,6"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="0.225,5.95;8.275,11.25"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="0.275,6"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="7.9499999999999975"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="5.1999999999999975"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="border_color">
+ <dia:color val="#a52a2a"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Box" version="0" id="O9">
+ <dia:attribute name="obj_pos">
+ <dia:point val="3.125,6.8"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="3.075,6.75;7.875,10.7"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="3.125,6.8"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="4.6999999999999975"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="3.8499999999999979"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="border_color">
+ <dia:color val="#0000ff"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O10">
+ <dia:attribute name="obj_pos">
+ <dia:point val="1.525,4.45"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="1.525,3.855;1.525,4.6025"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="1.525,4.45"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O11">
+ <dia:attribute name="obj_pos">
+ <dia:point val="0.476918,4.44569"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="0.476918,3.85069;3.95942,5.39819"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#sink media
+bus format#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="0.476918,4.44569"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#a52a2a"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Box" version="0" id="O12">
+ <dia:attribute name="obj_pos">
+ <dia:point val="16.6822,9.28251"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="16.6322,9.23251;24.9922,17.9564"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="16.6822,9.28251"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="8.2600228398861297"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="8.6238900617957164"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="border_color">
+ <dia:color val="#00ff00"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O13">
+ <dia:attribute name="obj_pos">
+ <dia:point val="16.6822,17.9064"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="3.05732,10.5823;16.7499,17.9741"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="16.6822,17.9064"/>
+ <dia:point val="3.125,10.65"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O12" connection="5"/>
+ <dia:connection handle="1" to="O9" connection="5"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O14">
+ <dia:attribute name="obj_pos">
+ <dia:point val="16.6822,9.28251"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="3.06681,6.74181;16.7404,9.3407"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="16.6822,9.28251"/>
+ <dia:point val="3.125,6.8"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O12" connection="0"/>
+ <dia:connection handle="1" to="O9" connection="0"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O15">
+ <dia:attribute name="obj_pos">
+ <dia:point val="24.9422,17.9064"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="7.75945,10.5845;25.0077,17.9719"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="24.9422,17.9064"/>
+ <dia:point val="7.825,10.65"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O12" connection="7"/>
+ <dia:connection handle="1" to="O9" connection="7"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O16">
+ <dia:attribute name="obj_pos">
+ <dia:point val="24.9422,9.28251"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="7.76834,6.74334;24.9989,9.33917"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="24.9422,9.28251"/>
+ <dia:point val="7.825,6.8"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O12" connection="2"/>
+ <dia:connection handle="1" to="O9" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O17">
+ <dia:attribute name="obj_pos">
+ <dia:point val="16.7352,7.47209"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="16.7352,6.87709;22.5602,8.42459"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#sink compose
+selection (scaling)#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="16.7352,7.47209"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#00ff00"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Box" version="0" id="O18">
+ <dia:attribute name="obj_pos">
+ <dia:point val="20.4661,9.72825"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="20.4161,9.67825;25.5254,13.3509"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="20.4661,9.72825"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="5.009308462554376"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="3.5726155970598077"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="border_color">
+ <dia:color val="#a020f0"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O19">
+ <dia:attribute name="obj_pos">
+ <dia:point val="34.475,5.2564"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="34.475,4.6614;38.7975,6.2089"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#source media
+bus format#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="34.475,5.2564"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#8b6914"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Box" version="0" id="O20">
+ <dia:attribute name="obj_pos">
+ <dia:point val="34.4244,8.6917"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="34.3744,8.6417;39.4837,12.3143"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="34.4244,8.6917"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="5.009308462554376"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="3.5726155970598077"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="border_color">
+ <dia:color val="#8b6914"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O21">
+ <dia:attribute name="obj_pos">
+ <dia:point val="34.4244,12.2643"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="20.4125,12.2107;34.478,13.3545"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="34.4244,12.2643"/>
+ <dia:point val="20.4661,13.3009"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O20" connection="5"/>
+ <dia:connection handle="1" to="O18" connection="5"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O22">
+ <dia:attribute name="obj_pos">
+ <dia:point val="34.4244,8.6917"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="20.4125,8.63813;34.478,9.78182"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="34.4244,8.6917"/>
+ <dia:point val="20.4661,9.72825"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O20" connection="0"/>
+ <dia:connection handle="1" to="O18" connection="0"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O23">
+ <dia:attribute name="obj_pos">
+ <dia:point val="39.4337,12.2643"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="25.4218,12.2107;39.4873,13.3545"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="39.4337,12.2643"/>
+ <dia:point val="25.4754,13.3009"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O20" connection="7"/>
+ <dia:connection handle="1" to="O18" connection="7"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O24">
+ <dia:attribute name="obj_pos">
+ <dia:point val="39.4337,8.6917"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="25.4218,8.63813;39.4873,9.78182"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="39.4337,8.6917"/>
+ <dia:point val="25.4754,9.72825"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O20" connection="2"/>
+ <dia:connection handle="1" to="O18" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O25">
+ <dia:attribute name="obj_pos">
+ <dia:point val="16.25,5.15"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="16.25,4.555;21.68,6.1025"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#sink compose
+bounds selection#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="16.25,5.15"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#ff765a"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Geometric - Perfect Circle" version="1" id="O26">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-1.02991,16.6506"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-1.07991,16.6006;-0.12991,17.5506"/>
+ </dia:attribute>
+ <dia:attribute name="meta">
+ <dia:composite type="dict"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-1.02991,16.6506"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="0.84999999999999787"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="0.84999999999999787"/>
+ </dia:attribute>
+ <dia:attribute name="line_width">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="line_colour">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="fill_colour">
+ <dia:color val="#ffffff"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="0"/>
+ <dia:real val="1"/>
+ </dia:attribute>
+ <dia:attribute name="flip_horizontal">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="flip_vertical">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="subscale">
+ <dia:real val="1"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O27">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-9.20491,17.09"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-9.255,16.7149;-0.918107,17.4385"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="-9.20491,17.09"/>
+ <dia:point val="-1.02991,17.0756"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="1" to="O26" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O28">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-6.95,16.45"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-6.95,15.855;-3.145,16.6025"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#pad 1 (sink)#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="-6.95,16.45"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Box" version="0" id="O29">
+ <dia:attribute name="obj_pos">
+ <dia:point val="0.390412,14.64"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="0.340412,14.59;6.045,18.8"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="0.390412,14.64"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="5.604587512785236"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="4.1099999999999994"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="border_color">
+ <dia:color val="#a52a2a"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Box" version="0" id="O30">
+ <dia:attribute name="obj_pos">
+ <dia:point val="2.645,15.74"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="2.595,15.69;5.6,18.3"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="2.645,15.74"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="2.904999999254942"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2.5100000000000016"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="border_color">
+ <dia:color val="#0000ff"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O31">
+ <dia:attribute name="obj_pos">
+ <dia:point val="1.595,12.99"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="1.595,12.395;1.595,13.1425"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="1.595,12.99"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O32">
+ <dia:attribute name="obj_pos">
+ <dia:point val="17.945,12.595"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="2.58596,12.536;18.004,15.799"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="17.945,12.595"/>
+ <dia:point val="2.645,15.74"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O36" connection="0"/>
+ <dia:connection handle="1" to="O30" connection="0"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O33">
+ <dia:attribute name="obj_pos">
+ <dia:point val="17.945,15.8"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="2.58772,15.7427;18.0023,18.3073"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="17.945,15.8"/>
+ <dia:point val="2.645,18.25"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O36" connection="5"/>
+ <dia:connection handle="1" to="O30" connection="5"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O34">
+ <dia:attribute name="obj_pos">
+ <dia:point val="21.7,15.8"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="5.49307,15.7431;21.7569,18.3069"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="21.7,15.8"/>
+ <dia:point val="5.55,18.25"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O36" connection="7"/>
+ <dia:connection handle="1" to="O30" connection="7"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O35">
+ <dia:attribute name="obj_pos">
+ <dia:point val="21.7,12.595"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="5.49136,12.5364;21.7586,15.7986"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="21.7,12.595"/>
+ <dia:point val="5.55,15.74"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O36" connection="2"/>
+ <dia:connection handle="1" to="O30" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Box" version="0" id="O36">
+ <dia:attribute name="obj_pos">
+ <dia:point val="17.945,12.595"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="17.895,12.545;21.75,15.85"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="17.945,12.595"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="3.7549999992549452"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="3.2049999992549427"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="border_color">
+ <dia:color val="#00ff00"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Box" version="0" id="O37">
+ <dia:attribute name="obj_pos">
+ <dia:point val="22.1631,14.2233"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="22.1131,14.1733;25.45,16.7"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="22.1631,14.2233"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="3.2369000000000021"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2.4267000000000003"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="border_color">
+ <dia:color val="#a020f0"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Box" version="0" id="O38">
+ <dia:attribute name="obj_pos">
+ <dia:point val="34.6714,16.2367"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="34.6214,16.1867;37.9,18.75"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="34.6714,16.2367"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="3.178600000000003"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="2.4632999999999967"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="border_color">
+ <dia:color val="#8b6914"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O39">
+ <dia:attribute name="obj_pos">
+ <dia:point val="34.6714,18.7"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="22.1057,16.5926;34.7288,18.7574"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="34.6714,18.7"/>
+ <dia:point val="22.1631,16.65"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O38" connection="5"/>
+ <dia:connection handle="1" to="O37" connection="5"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O40">
+ <dia:attribute name="obj_pos">
+ <dia:point val="34.6714,16.2367"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="22.1058,14.166;34.7287,16.294"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="34.6714,16.2367"/>
+ <dia:point val="22.1631,14.2233"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O38" connection="0"/>
+ <dia:connection handle="1" to="O37" connection="0"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O41">
+ <dia:attribute name="obj_pos">
+ <dia:point val="37.85,18.7"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="25.3425,16.5925;37.9075,18.7575"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="37.85,18.7"/>
+ <dia:point val="25.4,16.65"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O38" connection="7"/>
+ <dia:connection handle="1" to="O37" connection="7"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O42">
+ <dia:attribute name="obj_pos">
+ <dia:point val="37.85,16.2367"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="25.3427,14.166;37.9073,16.294"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="37.85,16.2367"/>
+ <dia:point val="25.4,14.2233"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O38" connection="2"/>
+ <dia:connection handle="1" to="O37" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Geometric - Perfect Circle" version="1" id="O43">
+ <dia:attribute name="obj_pos">
+ <dia:point val="40.347,16.7742"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="40.297,16.7242;41.247,17.6742"/>
+ </dia:attribute>
+ <dia:attribute name="meta">
+ <dia:composite type="dict"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="40.347,16.7742"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="0.84999999999999787"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="0.84999999999999787"/>
+ </dia:attribute>
+ <dia:attribute name="line_width">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="line_colour">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="fill_colour">
+ <dia:color val="#ffffff"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="0"/>
+ <dia:real val="1"/>
+ </dia:attribute>
+ <dia:attribute name="flip_horizontal">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="flip_vertical">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="subscale">
+ <dia:real val="1"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O44">
+ <dia:attribute name="obj_pos">
+ <dia:point val="41.197,17.1992"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="41.147,16.8388;49.6123,17.5624"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="41.197,17.1992"/>
+ <dia:point val="49.5005,17.2007"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O43" connection="3"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O45">
+ <dia:attribute name="obj_pos">
+ <dia:point val="42.4624,16.69"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="42.4624,16.095;47.1074,16.8425"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#pad 3 (source)#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="42.4624,16.69"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O46">
+ <dia:attribute name="obj_pos">
+ <dia:point val="9.85,4.55"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="9.85,3.955;12.7275,6.3025"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#sink
+crop
+selection#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="9.85,4.55"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#0000ff"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O47">
+ <dia:attribute name="obj_pos">
+ <dia:point val="27.65,4.75"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="27.65,4.155;30.5275,6.5025"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#source
+crop
+selection#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="27.65,4.75"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#a020f0"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O48">
+ <dia:attribute name="obj_pos">
+ <dia:point val="10.55,6.6"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="7.7135,6.39438;10.6035,7.11605"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="10.55,6.6"/>
+ <dia:point val="7.825,6.8"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#0000ff"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="1" to="O9" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O49">
+ <dia:attribute name="obj_pos">
+ <dia:point val="10.45,6.55"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="5.48029,6.48236;10.5176,15.8387"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="10.45,6.55"/>
+ <dia:point val="5.55,15.74"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#0000ff"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="1" to="O30" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O50">
+ <dia:attribute name="obj_pos">
+ <dia:point val="27.5246,6.66071"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="25.406,6.59136;27.594,9.82122"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="27.5246,6.66071"/>
+ <dia:point val="25.4754,9.72825"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#a020f0"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="1" to="O18" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O51">
+ <dia:attribute name="obj_pos">
+ <dia:point val="27.5036,6.68935"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="25.2161,6.62775;27.5652,14.331"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="27.5036,6.68935"/>
+ <dia:point val="25.4,14.2233"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#a020f0"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="1" to="O37" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ </dia:layer>
+</dia:diagram>
diff --git a/Documentation/DocBook/media/v4l/subdev-image-processing-full.svg b/Documentation/DocBook/media/v4l/subdev-image-processing-full.svg
new file mode 100644
index 000000000000..3322cf4c0093
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/subdev-image-processing-full.svg
@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd">
+<svg width="59cm" height="18cm" viewBox="-186 71 1178 346" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <g>
+ <rect style="fill: #ffffff" x="318.9" y="129" width="208.1" height="249"/>
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #ff765a" x="318.9" y="129" width="208.1" height="249"/>
+ </g>
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="-2" y="73" width="806" height="343"/>
+ <g>
+ <ellipse style="fill: #ffffff" cx="-12.5" cy="166.712" rx="8.5" ry="8.5"/>
+ <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-12.5" cy="166.712" rx="8.5" ry="8.5"/>
+ <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-12.5" cy="166.712" rx="8.5" ry="8.5"/>
+ </g>
+ <g>
+ <ellipse style="fill: #ffffff" cx="815.232" cy="205.184" rx="8.5" ry="8.5"/>
+ <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="815.232" cy="205.184" rx="8.5" ry="8.5"/>
+ <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="815.232" cy="205.184" rx="8.5" ry="8.5"/>
+ </g>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="-184.5" y1="167" x2="-30.7361" y2="166.729"/>
+ <polygon style="fill: #000000" points="-23.2361,166.716 -33.2272,171.734 -30.7361,166.729 -33.2449,161.734 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="-23.2361,166.716 -33.2272,171.734 -30.7361,166.729 -33.2449,161.734 "/>
+ </g>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="823.732" y1="205.184" x2="980.066" y2="205.212"/>
+ <polygon style="fill: #000000" points="987.566,205.214 977.565,210.212 980.066,205.212 977.567,200.212 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="987.566,205.214 977.565,210.212 980.066,205.212 977.567,200.212 "/>
+ </g>
+ <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="-139.96" y="155">
+ <tspan x="-139.96" y="155">pad 0 (sink)</tspan>
+ </text>
+ <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="849.04" y="195">
+ <tspan x="849.04" y="195">pad 2 (source)</tspan>
+ </text>
+ <g>
+ <rect style="fill: #ffffff" x="5.5" y="120" width="159" height="104"/>
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a52a2a" x="5.5" y="120" width="159" height="104"/>
+ </g>
+ <g>
+ <rect style="fill: #ffffff" x="62.5" y="136" width="94" height="77"/>
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" x="62.5" y="136" width="94" height="77"/>
+ </g>
+ <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="30.5" y="89">
+ <tspan x="30.5" y="89"></tspan>
+ </text>
+ <text style="fill: #a52a2a;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="9.53836" y="88.9138">
+ <tspan x="9.53836" y="88.9138">sink media</tspan>
+ <tspan x="9.53836" y="104.914">bus format</tspan>
+ </text>
+ <g>
+ <rect style="fill: #ffffff" x="333.644" y="185.65" width="165.2" height="172.478"/>
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #00ff00" x="333.644" y="185.65" width="165.2" height="172.478"/>
+ </g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="333.644" y1="358.128" x2="62.5" y2="213"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="333.644" y1="185.65" x2="62.5" y2="136"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="498.844" y1="358.128" x2="156.5" y2="213"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="498.844" y1="185.65" x2="156.5" y2="136"/>
+ <text style="fill: #00ff00;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="334.704" y="149.442">
+ <tspan x="334.704" y="149.442">sink compose</tspan>
+ <tspan x="334.704" y="165.442">selection (scaling)</tspan>
+ </text>
+ <g>
+ <rect style="fill: #ffffff" x="409.322" y="194.565" width="100.186" height="71.4523"/>
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x="409.322" y="194.565" width="100.186" height="71.4523"/>
+ </g>
+ <text style="fill: #8b6914;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="689.5" y="105.128">
+ <tspan x="689.5" y="105.128">source media</tspan>
+ <tspan x="689.5" y="121.128">bus format</tspan>
+ </text>
+ <g>
+ <rect style="fill: #ffffff" x="688.488" y="173.834" width="100.186" height="71.4523"/>
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #8b6914" x="688.488" y="173.834" width="100.186" height="71.4523"/>
+ </g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="688.488" y1="245.286" x2="409.322" y2="266.018"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="688.488" y1="173.834" x2="409.322" y2="194.565"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="788.674" y1="245.286" x2="509.508" y2="266.018"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="788.674" y1="173.834" x2="509.508" y2="194.565"/>
+ <text style="fill: #ff765a;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="325" y="103">
+ <tspan x="325" y="103">sink compose</tspan>
+ <tspan x="325" y="119">bounds selection</tspan>
+ </text>
+ <g>
+ <ellipse style="fill: #ffffff" cx="-12.0982" cy="341.512" rx="8.5" ry="8.5"/>
+ <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-12.0982" cy="341.512" rx="8.5" ry="8.5"/>
+ <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-12.0982" cy="341.512" rx="8.5" ry="8.5"/>
+ </g>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="-184.098" y1="341.8" x2="-30.3343" y2="341.529"/>
+ <polygon style="fill: #000000" points="-22.8343,341.516 -32.8254,346.534 -30.3343,341.529 -32.8431,336.534 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="-22.8343,341.516 -32.8254,346.534 -30.3343,341.529 -32.8431,336.534 "/>
+ </g>
+ <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="-139" y="329">
+ <tspan x="-139" y="329">pad 1 (sink)</tspan>
+ </text>
+ <g>
+ <rect style="fill: #ffffff" x="7.80824" y="292.8" width="112.092" height="82.2"/>
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a52a2a" x="7.80824" y="292.8" width="112.092" height="82.2"/>
+ </g>
+ <g>
+ <rect style="fill: #ffffff" x="52.9" y="314.8" width="58.1" height="50.2"/>
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" x="52.9" y="314.8" width="58.1" height="50.2"/>
+ </g>
+ <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="31.9" y="259.8">
+ <tspan x="31.9" y="259.8"></tspan>
+ </text>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="358.9" y1="251.9" x2="52.9" y2="314.8"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="358.9" y1="316" x2="52.9" y2="365"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="434" y1="316" x2="111" y2="365"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="434" y1="251.9" x2="111" y2="314.8"/>
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #00ff00" x="358.9" y="251.9" width="75.1" height="64.1"/>
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x="443.262" y="284.466" width="64.738" height="48.534"/>
+ <g>
+ <rect style="fill: #ffffff" x="693.428" y="324.734" width="63.572" height="49.266"/>
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #8b6914" x="693.428" y="324.734" width="63.572" height="49.266"/>
+ </g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="693.428" y1="374" x2="443.262" y2="333"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="693.428" y1="324.734" x2="443.262" y2="284.466"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="757" y1="374" x2="508" y2="333"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="757" y1="324.734" x2="508" y2="284.466"/>
+ <g>
+ <ellipse style="fill: #ffffff" cx="815.44" cy="343.984" rx="8.5" ry="8.5"/>
+ <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="815.44" cy="343.984" rx="8.5" ry="8.5"/>
+ <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="815.44" cy="343.984" rx="8.5" ry="8.5"/>
+ </g>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="823.94" y1="343.984" x2="980.274" y2="344.012"/>
+ <polygon style="fill: #000000" points="987.774,344.014 977.773,349.012 980.274,344.012 977.775,339.012 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="987.774,344.014 977.773,349.012 980.274,344.012 977.775,339.012 "/>
+ </g>
+ <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="849.248" y="333.8">
+ <tspan x="849.248" y="333.8">pad 3 (source)</tspan>
+ </text>
+ <text style="fill: #0000ff;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="197" y="91">
+ <tspan x="197" y="91">sink</tspan>
+ <tspan x="197" y="107">crop</tspan>
+ <tspan x="197" y="123">selection</tspan>
+ </text>
+ <text style="fill: #a020f0;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="553" y="95">
+ <tspan x="553" y="95">source</tspan>
+ <tspan x="553" y="111">crop</tspan>
+ <tspan x="553" y="127">selection</tspan>
+ </text>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" x1="211" y1="132" x2="166.21" y2="135.287"/>
+ <polygon style="fill: #0000ff" points="158.73,135.836 168.337,130.118 166.21,135.287 169.069,140.091 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" points="158.73,135.836 168.337,130.118 166.21,135.287 169.069,140.091 "/>
+ </g>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" x1="209" y1="131" x2="115.581" y2="306.209"/>
+ <polygon style="fill: #0000ff" points="112.052,312.827 112.345,301.65 115.581,306.209 121.169,306.355 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" points="112.052,312.827 112.345,301.65 115.581,306.209 121.169,306.355 "/>
+ </g>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x1="550.492" y1="133.214" x2="514.916" y2="186.469"/>
+ <polygon style="fill: #a020f0" points="510.75,192.706 512.147,181.613 514.916,186.469 520.463,187.168 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" points="510.75,192.706 512.147,181.613 514.916,186.469 520.463,187.168 "/>
+ </g>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x1="550.072" y1="133.787" x2="510.618" y2="275.089"/>
+ <polygon style="fill: #a020f0" points="508.601,282.312 506.475,271.336 510.618,275.089 516.106,274.025 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" points="508.601,282.312 506.475,271.336 510.618,275.089 516.106,274.025 "/>
+ </g>
+</svg>
diff --git a/Documentation/DocBook/media/v4l/subdev-image-processing-scaling-multi-source.dia b/Documentation/DocBook/media/v4l/subdev-image-processing-scaling-multi-source.dia
new file mode 100644
index 000000000000..0cd50a7bda80
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/subdev-image-processing-scaling-multi-source.dia
@@ -0,0 +1,1152 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<dia:diagram xmlns:dia="http://www.lysator.liu.se/~alla/dia/">
+ <dia:diagramdata>
+ <dia:attribute name="background">
+ <dia:color val="#ffffff"/>
+ </dia:attribute>
+ <dia:attribute name="pagebreak">
+ <dia:color val="#000099"/>
+ </dia:attribute>
+ <dia:attribute name="paper">
+ <dia:composite type="paper">
+ <dia:attribute name="name">
+ <dia:string>#A4#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="tmargin">
+ <dia:real val="2.8222000598907471"/>
+ </dia:attribute>
+ <dia:attribute name="bmargin">
+ <dia:real val="2.8222000598907471"/>
+ </dia:attribute>
+ <dia:attribute name="lmargin">
+ <dia:real val="2.8222000598907471"/>
+ </dia:attribute>
+ <dia:attribute name="rmargin">
+ <dia:real val="2.8222000598907471"/>
+ </dia:attribute>
+ <dia:attribute name="is_portrait">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="scaling">
+ <dia:real val="0.49000000953674316"/>
+ </dia:attribute>
+ <dia:attribute name="fitto">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="grid">
+ <dia:composite type="grid">
+ <dia:attribute name="width_x">
+ <dia:real val="1"/>
+ </dia:attribute>
+ <dia:attribute name="width_y">
+ <dia:real val="1"/>
+ </dia:attribute>
+ <dia:attribute name="visible_x">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="visible_y">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:composite type="color"/>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#d8e5e5"/>
+ </dia:attribute>
+ <dia:attribute name="guides">
+ <dia:composite type="guides">
+ <dia:attribute name="hguides"/>
+ <dia:attribute name="vguides"/>
+ </dia:composite>
+ </dia:attribute>
+ </dia:diagramdata>
+ <dia:layer name="Background" visible="true" active="true">
+ <dia:object type="Standard - Box" version="0" id="O0">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-0.4,6.5"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-0.45,6.45;39.95,22.9"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-0.4,6.5"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="40.299999999999997"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="16.349999999999998"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Box" version="0" id="O1">
+ <dia:attribute name="obj_pos">
+ <dia:point val="0.225,9.45"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="0.175,9.4;8.225,14.7"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="0.225,9.45"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="7.9499999999999975"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="5.1999999999999975"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="border_color">
+ <dia:color val="#a52a2a"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Box" version="0" id="O2">
+ <dia:attribute name="obj_pos">
+ <dia:point val="2.475,10.2"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="2.425,10.15;7.225,14.1"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="2.475,10.2"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="4.6999999999999975"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="3.8499999999999979"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="border_color">
+ <dia:color val="#0000ff"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O3">
+ <dia:attribute name="obj_pos">
+ <dia:point val="3,11.2"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="3,10.605;5.8775,12.9525"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#sink
+crop
+selection#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="3,11.2"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#0000ff"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O4">
+ <dia:attribute name="obj_pos">
+ <dia:point val="1.475,7.9"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="1.475,7.305;1.475,8.0525"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>##</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="1.475,7.9"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O5">
+ <dia:attribute name="obj_pos">
+ <dia:point val="0.426918,7.89569"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="0.426918,7.30069;3.90942,8.84819"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#sink media
+bus format#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="0.426918,7.89569"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#a52a2a"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Box" version="0" id="O6">
+ <dia:attribute name="obj_pos">
+ <dia:point val="16.6822,9.28251"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="16.6322,9.23251;24.9922,17.9564"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="16.6822,9.28251"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="8.2600228398861297"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="8.6238900617957164"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="border_color">
+ <dia:color val="#00ff00"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O7">
+ <dia:attribute name="obj_pos">
+ <dia:point val="16.6822,17.9064"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="2.41365,13.9886;16.7436,17.9678"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="16.6822,17.9064"/>
+ <dia:point val="2.475,14.05"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O6" connection="5"/>
+ <dia:connection handle="1" to="O2" connection="5"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O8">
+ <dia:attribute name="obj_pos">
+ <dia:point val="16.6822,9.28251"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="2.42188,9.22939;16.7353,10.2531"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="16.6822,9.28251"/>
+ <dia:point val="2.475,10.2"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O6" connection="0"/>
+ <dia:connection handle="1" to="O2" connection="0"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O9">
+ <dia:attribute name="obj_pos">
+ <dia:point val="24.9422,17.9064"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="7.11553,13.9905;25.0017,17.9659"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="24.9422,17.9064"/>
+ <dia:point val="7.175,14.05"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O6" connection="7"/>
+ <dia:connection handle="1" to="O2" connection="7"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O10">
+ <dia:attribute name="obj_pos">
+ <dia:point val="24.9422,9.28251"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="7.12249,9.23;24.9947,10.2525"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="24.9422,9.28251"/>
+ <dia:point val="7.175,10.2"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O6" connection="2"/>
+ <dia:connection handle="1" to="O2" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O11">
+ <dia:attribute name="obj_pos">
+ <dia:point val="16.7352,7.47209"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="16.7352,6.87709;22.5602,8.42459"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#sink compose
+selection (scaling)#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="16.7352,7.47209"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#00ff00"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Box" version="0" id="O12">
+ <dia:attribute name="obj_pos">
+ <dia:point val="19.1161,9.97825"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="19.0661,9.92825;24.1754,13.6009"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="19.1161,9.97825"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="5.009308462554376"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="3.5726155970598077"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="border_color">
+ <dia:color val="#a020f0"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O13">
+ <dia:attribute name="obj_pos">
+ <dia:point val="27.1661,7.47209"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="27.1661,6.87709;30.0436,9.22459"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#source
+crop
+selection#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="27.1661,7.47209"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#a020f0"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O14">
+ <dia:attribute name="obj_pos">
+ <dia:point val="34.575,7.8564"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="34.575,7.2614;38.8975,8.8089"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#source media
+bus format#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="34.575,7.8564"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#8b6914"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Box" version="0" id="O15">
+ <dia:attribute name="obj_pos">
+ <dia:point val="34.5244,11.2917"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="34.4744,11.2417;39.5837,14.9143"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="34.5244,11.2917"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="5.009308462554376"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="3.5726155970598077"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="border_color">
+ <dia:color val="#8b6914"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O16">
+ <dia:attribute name="obj_pos">
+ <dia:point val="34.5244,14.8643"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="19.062,13.4968;34.5785,14.9184"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="34.5244,14.8643"/>
+ <dia:point val="19.1161,13.5509"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O15" connection="5"/>
+ <dia:connection handle="1" to="O12" connection="5"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O17">
+ <dia:attribute name="obj_pos">
+ <dia:point val="34.5244,11.2917"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="19.062,9.92418;34.5785,11.3458"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="34.5244,11.2917"/>
+ <dia:point val="19.1161,9.97825"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O15" connection="0"/>
+ <dia:connection handle="1" to="O12" connection="0"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O18">
+ <dia:attribute name="obj_pos">
+ <dia:point val="39.5337,14.8643"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="24.0713,13.4968;39.5878,14.9184"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="39.5337,14.8643"/>
+ <dia:point val="24.1254,13.5509"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O15" connection="7"/>
+ <dia:connection handle="1" to="O12" connection="7"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O19">
+ <dia:attribute name="obj_pos">
+ <dia:point val="39.5337,11.2917"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="24.0713,9.92418;39.5878,11.3458"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="39.5337,11.2917"/>
+ <dia:point val="24.1254,9.97825"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O15" connection="2"/>
+ <dia:connection handle="1" to="O12" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Geometric - Perfect Circle" version="1" id="O20">
+ <dia:attribute name="obj_pos">
+ <dia:point val="39.98,12.0742"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="39.93,12.0242;40.88,12.9742"/>
+ </dia:attribute>
+ <dia:attribute name="meta">
+ <dia:composite type="dict"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="39.98,12.0742"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="0.84999999999999787"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="0.84999999999999787"/>
+ </dia:attribute>
+ <dia:attribute name="line_width">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="line_colour">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="fill_colour">
+ <dia:color val="#ffffff"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="0"/>
+ <dia:real val="1"/>
+ </dia:attribute>
+ <dia:attribute name="flip_horizontal">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="flip_vertical">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="subscale">
+ <dia:real val="1"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O21">
+ <dia:attribute name="obj_pos">
+ <dia:point val="40.83,12.4992"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="40.78,12.1388;49.2453,12.8624"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="40.83,12.4992"/>
+ <dia:point val="49.1335,12.5007"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O20" connection="3"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O22">
+ <dia:attribute name="obj_pos">
+ <dia:point val="42.0954,11.99"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="42.0954,11.395;46.7404,12.1425"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#pad 1 (source)#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="42.0954,11.99"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Geometric - Perfect Circle" version="1" id="O23">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-1.44491,11.6506"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-1.49491,11.6006;-0.54491,12.5506"/>
+ </dia:attribute>
+ <dia:attribute name="meta">
+ <dia:composite type="dict"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="-1.44491,11.6506"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="0.84999999999999787"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="0.84999999999999787"/>
+ </dia:attribute>
+ <dia:attribute name="line_width">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="line_colour">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="fill_colour">
+ <dia:color val="#ffffff"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="0"/>
+ <dia:real val="1"/>
+ </dia:attribute>
+ <dia:attribute name="flip_horizontal">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="flip_vertical">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="subscale">
+ <dia:real val="1"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O24">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-9.61991,12.09"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-9.67,11.7149;-1.33311,12.4385"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="-9.61991,12.09"/>
+ <dia:point val="-1.44491,12.0756"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="1" to="O23" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O25">
+ <dia:attribute name="obj_pos">
+ <dia:point val="-7.39291,11.49"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="-7.39291,10.895;-3.58791,11.6425"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#pad 0 (sink)#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="-7.39291,11.49"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Box" version="0" id="O26">
+ <dia:attribute name="obj_pos">
+ <dia:point val="19.4911,13.8333"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="19.4411,13.7833;24.5504,17.4559"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="19.4911,13.8333"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="5.009308462554376"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="3.5726155970598077"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="border_color">
+ <dia:color val="#a020f0"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Box" version="0" id="O27">
+ <dia:attribute name="obj_pos">
+ <dia:point val="34.4994,17.2967"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="34.4494,17.2467;39.5587,20.9193"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="34.4994,17.2967"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="5.009308462554376"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="3.5726155970598077"/>
+ </dia:attribute>
+ <dia:attribute name="border_width">
+ <dia:real val="0.10000000149011612"/>
+ </dia:attribute>
+ <dia:attribute name="border_color">
+ <dia:color val="#8b6914"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O28">
+ <dia:attribute name="obj_pos">
+ <dia:point val="34.4994,20.8693"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="19.4311,17.3459;34.5594,20.9293"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="34.4994,20.8693"/>
+ <dia:point val="19.4911,17.4059"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O27" connection="5"/>
+ <dia:connection handle="1" to="O26" connection="5"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O29">
+ <dia:attribute name="obj_pos">
+ <dia:point val="34.4994,17.2967"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="19.4311,13.7733;34.5594,17.3567"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="34.4994,17.2967"/>
+ <dia:point val="19.4911,13.8333"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O27" connection="0"/>
+ <dia:connection handle="1" to="O26" connection="0"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O30">
+ <dia:attribute name="obj_pos">
+ <dia:point val="39.5087,20.8693"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="24.4404,17.3459;39.5687,20.9293"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="39.5087,20.8693"/>
+ <dia:point val="24.5004,17.4059"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O27" connection="7"/>
+ <dia:connection handle="1" to="O26" connection="7"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O31">
+ <dia:attribute name="obj_pos">
+ <dia:point val="39.5087,17.2967"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="24.4404,13.7733;39.5687,17.3567"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="39.5087,17.2967"/>
+ <dia:point val="24.5004,13.8333"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#e60505"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="4"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O27" connection="2"/>
+ <dia:connection handle="1" to="O26" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Geometric - Perfect Circle" version="1" id="O32">
+ <dia:attribute name="obj_pos">
+ <dia:point val="39.855,18.7792"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="39.805,18.7292;40.755,19.6792"/>
+ </dia:attribute>
+ <dia:attribute name="meta">
+ <dia:composite type="dict"/>
+ </dia:attribute>
+ <dia:attribute name="elem_corner">
+ <dia:point val="39.855,18.7792"/>
+ </dia:attribute>
+ <dia:attribute name="elem_width">
+ <dia:real val="0.84999999999999787"/>
+ </dia:attribute>
+ <dia:attribute name="elem_height">
+ <dia:real val="0.84999999999999787"/>
+ </dia:attribute>
+ <dia:attribute name="line_width">
+ <dia:real val="0.10000000000000001"/>
+ </dia:attribute>
+ <dia:attribute name="line_colour">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="fill_colour">
+ <dia:color val="#ffffff"/>
+ </dia:attribute>
+ <dia:attribute name="show_background">
+ <dia:boolean val="true"/>
+ </dia:attribute>
+ <dia:attribute name="line_style">
+ <dia:enum val="0"/>
+ <dia:real val="1"/>
+ </dia:attribute>
+ <dia:attribute name="flip_horizontal">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="flip_vertical">
+ <dia:boolean val="false"/>
+ </dia:attribute>
+ <dia:attribute name="subscale">
+ <dia:real val="1"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O33">
+ <dia:attribute name="obj_pos">
+ <dia:point val="40.705,19.2042"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="40.655,18.8438;49.1203,19.5674"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="40.705,19.2042"/>
+ <dia:point val="49.0085,19.2057"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="0" to="O32" connection="3"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Text" version="1" id="O34">
+ <dia:attribute name="obj_pos">
+ <dia:point val="41.9704,18.695"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="41.9704,18.1;46.6154,18.8475"/>
+ </dia:attribute>
+ <dia:attribute name="text">
+ <dia:composite type="text">
+ <dia:attribute name="string">
+ <dia:string>#pad 2 (source)#</dia:string>
+ </dia:attribute>
+ <dia:attribute name="font">
+ <dia:font family="sans" style="0" name="Helvetica"/>
+ </dia:attribute>
+ <dia:attribute name="height">
+ <dia:real val="0.80000000000000004"/>
+ </dia:attribute>
+ <dia:attribute name="pos">
+ <dia:point val="41.9704,18.695"/>
+ </dia:attribute>
+ <dia:attribute name="color">
+ <dia:color val="#000000"/>
+ </dia:attribute>
+ <dia:attribute name="alignment">
+ <dia:enum val="0"/>
+ </dia:attribute>
+ </dia:composite>
+ </dia:attribute>
+ <dia:attribute name="valign">
+ <dia:enum val="3"/>
+ </dia:attribute>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O35">
+ <dia:attribute name="obj_pos">
+ <dia:point val="27.3,9.55"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="24.0146,9.49376;27.3562,10.255"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="27.3,9.55"/>
+ <dia:point val="24.1254,9.97825"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#a020f0"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="1" to="O12" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ <dia:object type="Standard - Line" version="0" id="O36">
+ <dia:attribute name="obj_pos">
+ <dia:point val="27.3454,9.53624"/>
+ </dia:attribute>
+ <dia:attribute name="obj_bb">
+ <dia:rectangle val="24.4311,9.46695;27.4147,13.9265"/>
+ </dia:attribute>
+ <dia:attribute name="conn_endpoints">
+ <dia:point val="27.3454,9.53624"/>
+ <dia:point val="24.5004,13.8333"/>
+ </dia:attribute>
+ <dia:attribute name="numcp">
+ <dia:int val="1"/>
+ </dia:attribute>
+ <dia:attribute name="line_color">
+ <dia:color val="#a020f0"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow">
+ <dia:enum val="22"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_length">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:attribute name="end_arrow_width">
+ <dia:real val="0.5"/>
+ </dia:attribute>
+ <dia:connections>
+ <dia:connection handle="1" to="O26" connection="2"/>
+ </dia:connections>
+ </dia:object>
+ </dia:layer>
+</dia:diagram>
diff --git a/Documentation/DocBook/media/v4l/subdev-image-processing-scaling-multi-source.svg b/Documentation/DocBook/media/v4l/subdev-image-processing-scaling-multi-source.svg
new file mode 100644
index 000000000000..2340c0f8bc92
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/subdev-image-processing-scaling-multi-source.svg
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd">
+<svg width="59cm" height="17cm" viewBox="-194 128 1179 330" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x="-8" y="130" width="806" height="327"/>
+ <g>
+ <rect style="fill: #ffffff" x="4.5" y="189" width="159" height="104"/>
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a52a2a" x="4.5" y="189" width="159" height="104"/>
+ </g>
+ <g>
+ <rect style="fill: #ffffff" x="49.5" y="204" width="94" height="77"/>
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #0000ff" x="49.5" y="204" width="94" height="77"/>
+ </g>
+ <text style="fill: #0000ff;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="60" y="224">
+ <tspan x="60" y="224">sink</tspan>
+ <tspan x="60" y="240">crop</tspan>
+ <tspan x="60" y="256">selection</tspan>
+ </text>
+ <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="29.5" y="158">
+ <tspan x="29.5" y="158"></tspan>
+ </text>
+ <text style="fill: #a52a2a;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="8.53836" y="157.914">
+ <tspan x="8.53836" y="157.914">sink media</tspan>
+ <tspan x="8.53836" y="173.914">bus format</tspan>
+ </text>
+ <g>
+ <rect style="fill: #ffffff" x="333.644" y="185.65" width="165.2" height="172.478"/>
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #00ff00" x="333.644" y="185.65" width="165.2" height="172.478"/>
+ </g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="333.644" y1="358.128" x2="49.5" y2="281"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="333.644" y1="185.65" x2="49.5" y2="204"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="498.844" y1="358.128" x2="143.5" y2="281"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="498.844" y1="185.65" x2="143.5" y2="204"/>
+ <text style="fill: #00ff00;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="334.704" y="149.442">
+ <tspan x="334.704" y="149.442">sink compose</tspan>
+ <tspan x="334.704" y="165.442">selection (scaling)</tspan>
+ </text>
+ <g>
+ <rect style="fill: #ffffff" x="382.322" y="199.565" width="100.186" height="71.4523"/>
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x="382.322" y="199.565" width="100.186" height="71.4523"/>
+ </g>
+ <text style="fill: #a020f0;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="543.322" y="149.442">
+ <tspan x="543.322" y="149.442">source</tspan>
+ <tspan x="543.322" y="165.442">crop</tspan>
+ <tspan x="543.322" y="181.442">selection</tspan>
+ </text>
+ <text style="fill: #8b6914;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="691.5" y="157.128">
+ <tspan x="691.5" y="157.128">source media</tspan>
+ <tspan x="691.5" y="173.128">bus format</tspan>
+ </text>
+ <g>
+ <rect style="fill: #ffffff" x="690.488" y="225.834" width="100.186" height="71.4523"/>
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #8b6914" x="690.488" y="225.834" width="100.186" height="71.4523"/>
+ </g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="690.488" y1="297.286" x2="382.322" y2="271.018"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="690.488" y1="225.834" x2="382.322" y2="199.565"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="790.674" y1="297.286" x2="482.508" y2="271.018"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="790.674" y1="225.834" x2="482.508" y2="199.565"/>
+ <g>
+ <ellipse style="fill: #ffffff" cx="808.1" cy="249.984" rx="8.5" ry="8.5"/>
+ <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="808.1" cy="249.984" rx="8.5" ry="8.5"/>
+ <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="808.1" cy="249.984" rx="8.5" ry="8.5"/>
+ </g>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="816.6" y1="249.984" x2="972.934" y2="250.012"/>
+ <polygon style="fill: #000000" points="980.434,250.014 970.433,255.012 972.934,250.012 970.435,245.012 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="980.434,250.014 970.433,255.012 972.934,250.012 970.435,245.012 "/>
+ </g>
+ <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="841.908" y="239.8">
+ <tspan x="841.908" y="239.8">pad 1 (source)</tspan>
+ </text>
+ <g>
+ <ellipse style="fill: #ffffff" cx="-20.3982" cy="241.512" rx="8.5" ry="8.5"/>
+ <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-20.3982" cy="241.512" rx="8.5" ry="8.5"/>
+ <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="-20.3982" cy="241.512" rx="8.5" ry="8.5"/>
+ </g>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="-192.398" y1="241.8" x2="-38.6343" y2="241.529"/>
+ <polygon style="fill: #000000" points="-31.1343,241.516 -41.1254,246.534 -38.6343,241.529 -41.1431,236.534 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="-31.1343,241.516 -41.1254,246.534 -38.6343,241.529 -41.1431,236.534 "/>
+ </g>
+ <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="-147.858" y="229.8">
+ <tspan x="-147.858" y="229.8">pad 0 (sink)</tspan>
+ </text>
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x="389.822" y="276.666" width="100.186" height="71.4523"/>
+ <g>
+ <rect style="fill: #ffffff" x="689.988" y="345.934" width="100.186" height="71.4523"/>
+ <rect style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #8b6914" x="689.988" y="345.934" width="100.186" height="71.4523"/>
+ </g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="689.988" y1="417.386" x2="389.822" y2="348.118"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="689.988" y1="345.934" x2="389.822" y2="276.666"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="790.174" y1="417.386" x2="490.008" y2="348.118"/>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke-dasharray: 4; stroke: #e60505" x1="790.174" y1="345.934" x2="490.008" y2="276.666"/>
+ <g>
+ <ellipse style="fill: #ffffff" cx="805.6" cy="384.084" rx="8.5" ry="8.5"/>
+ <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="805.6" cy="384.084" rx="8.5" ry="8.5"/>
+ <ellipse style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" cx="805.6" cy="384.084" rx="8.5" ry="8.5"/>
+ </g>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" x1="814.1" y1="384.084" x2="970.434" y2="384.112"/>
+ <polygon style="fill: #000000" points="977.934,384.114 967.933,389.112 970.434,384.112 967.935,379.112 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #000000" points="977.934,384.114 967.933,389.112 970.434,384.112 967.935,379.112 "/>
+ </g>
+ <text style="fill: #000000;text-anchor:start;font-size:12.8;font-family:sanserif;font-style:normal;font-weight:normal" x="839.408" y="373.9">
+ <tspan x="839.408" y="373.9">pad 2 (source)</tspan>
+ </text>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x1="546" y1="191" x2="492.157" y2="198.263"/>
+ <polygon style="fill: #a020f0" points="484.724,199.266 493.966,192.974 492.157,198.263 495.303,202.884 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" points="484.724,199.266 493.966,192.974 492.157,198.263 495.303,202.884 "/>
+ </g>
+ <g>
+ <line style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" x1="546.908" y1="190.725" x2="495.383" y2="268.548"/>
+ <polygon style="fill: #a020f0" points="491.242,274.802 492.594,263.703 495.383,268.548 500.932,269.224 "/>
+ <polygon style="fill: none; fill-opacity:0; stroke-width: 2; stroke: #a020f0" points="491.242,274.802 492.594,263.703 495.383,268.548 500.932,269.224 "/>
+ </g>
+</svg>
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
index 8ae38876172e..015c561754b7 100644
--- a/Documentation/DocBook/media/v4l/v4l2.xml
+++ b/Documentation/DocBook/media/v4l/v4l2.xml
@@ -28,8 +28,8 @@ documentation.</contrib>
<firstname>Hans</firstname>
<surname>Verkuil</surname>
<contrib>Designed and documented the VIDIOC_LOG_STATUS ioctl,
-the extended control ioctls and major parts of the sliced VBI
-API.</contrib>
+the extended control ioctls, major parts of the sliced VBI API, the
+MPEG encoder and decoder APIs and the DV Timings API.</contrib>
<affiliation>
<address>
<email>hverkuil@xs4all.nl</email>
@@ -96,6 +96,17 @@ Remote Controller chapter.</contrib>
</address>
</affiliation>
</author>
+
+ <author>
+ <firstname>Sakari</firstname>
+ <surname>Ailus</surname>
+ <contrib>Subdev selections API.</contrib>
+ <affiliation>
+ <address>
+ <email>sakari.ailus@iki.fi</email>
+ </address>
+ </affiliation>
+ </author>
</authorgroup>
<copyright>
@@ -112,6 +123,7 @@ Remote Controller chapter.</contrib>
<year>2009</year>
<year>2010</year>
<year>2011</year>
+ <year>2012</year>
<holder>Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin
Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab,
Pawel Osciak</holder>
@@ -128,6 +140,28 @@ structs, ioctls) must be noted in more detail in the history chapter
applications. -->
<revision>
+ <revnumber>3.5</revnumber>
+ <date>2012-05-07</date>
+ <authorinitials>sa, sn</authorinitials>
+ <revremark>Added V4L2_CTRL_TYPE_INTEGER_MENU and V4L2 subdev
+ selections API. Improved the description of V4L2_CID_COLORFX
+ control, added V4L2_CID_COLORFX_CBCR control.
+ Added camera controls V4L2_CID_AUTO_EXPOSURE_BIAS,
+ V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, V4L2_CID_IMAGE_STABILIZATION,
+ V4L2_CID_ISO_SENSITIVITY, V4L2_CID_ISO_SENSITIVITY_AUTO,
+ V4L2_CID_EXPOSURE_METERING, V4L2_CID_SCENE_MODE,
+ V4L2_CID_3A_LOCK, V4L2_CID_AUTO_FOCUS_START,
+ V4L2_CID_AUTO_FOCUS_STOP, V4L2_CID_AUTO_FOCUS_STATUS
+ and V4L2_CID_AUTO_FOCUS_RANGE.
+ </revremark>
+ <date>2012-05-01</date>
+ <authorinitials>hv</authorinitials>
+ <revremark>Added VIDIOC_ENUM_DV_TIMINGS, VIDIOC_QUERY_DV_TIMINGS and
+ VIDIOC_DV_TIMINGS_CAP.
+ </revremark>
+ </revision>
+
+ <revision>
<revnumber>3.4</revnumber>
<date>2012-01-25</date>
<authorinitials>sn</authorinitials>
@@ -433,7 +467,7 @@ and discussions on the V4L mailing list.</revremark>
</partinfo>
<title>Video for Linux Two API Specification</title>
- <subtitle>Revision 3.3</subtitle>
+ <subtitle>Revision 3.5</subtitle>
<chapter id="common">
&sub-common;
@@ -491,10 +525,12 @@ and discussions on the V4L mailing list.</revremark>
&sub-dbg-g-register;
&sub-decoder-cmd;
&sub-dqevent;
+ &sub-dv-timings-cap;
&sub-encoder-cmd;
&sub-enumaudio;
&sub-enumaudioout;
&sub-enum-dv-presets;
+ &sub-enum-dv-timings;
&sub-enum-fmt;
&sub-enum-framesizes;
&sub-enum-frameintervals;
@@ -529,6 +565,7 @@ and discussions on the V4L mailing list.</revremark>
&sub-querycap;
&sub-queryctrl;
&sub-query-dv-preset;
+ &sub-query-dv-timings;
&sub-querystd;
&sub-prepare-buf;
&sub-reqbufs;
@@ -540,6 +577,7 @@ and discussions on the V4L mailing list.</revremark>
&sub-subdev-g-crop;
&sub-subdev-g-fmt;
&sub-subdev-g-frame-interval;
+ &sub-subdev-g-selection;
&sub-subscribe-event;
<!-- End of ioctls. -->
&sub-mmap;
diff --git a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
index 73ae8a6cd004..765549ff8a71 100644
--- a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
@@ -48,6 +48,12 @@
<refsect1>
<title>Description</title>
+ <note>
+ <title>Experimental</title>
+ <para>This is an <link linkend="experimental"> experimental </link>
+ interface and may change in the future.</para>
+ </note>
+
<para>This ioctl is used to create buffers for <link linkend="mmap">memory
mapped</link> or <link linkend="userp">user pointer</link>
I/O. It can be used as an alternative or in addition to the
@@ -94,16 +100,18 @@ information.</para>
<entry>The number of buffers requested or granted.</entry>
</row>
<row>
- <entry>&v4l2-memory;</entry>
+ <entry>__u32</entry>
<entry><structfield>memory</structfield></entry>
<entry>Applications set this field to
<constant>V4L2_MEMORY_MMAP</constant> or
-<constant>V4L2_MEMORY_USERPTR</constant>.</entry>
+<constant>V4L2_MEMORY_USERPTR</constant>. See <xref linkend="v4l2-memory"
+/></entry>
</row>
<row>
- <entry>&v4l2-format;</entry>
+ <entry>__u32</entry>
<entry><structfield>format</structfield></entry>
- <entry>Filled in by the application, preserved by the driver.</entry>
+ <entry>Filled in by the application, preserved by the driver.
+ See <xref linkend="v4l2-format" />.</entry>
</row>
<row>
<entry>__u32</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-cropcap.xml b/Documentation/DocBook/media/v4l/vidioc-cropcap.xml
index b4f2f255211e..f1bac2c6e978 100644
--- a/Documentation/DocBook/media/v4l/vidioc-cropcap.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-cropcap.xml
@@ -65,7 +65,7 @@ output.</para>
&cs-str;
<tbody valign="top">
<row>
- <entry>&v4l2-buf-type;</entry>
+ <entry>__u32</entry>
<entry><structfield>type</structfield></entry>
<entry>Type of the data stream, set by the application.
Only these types are valid here:
@@ -73,7 +73,7 @@ Only these types are valid here:
<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant>,
<constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>, and custom (driver
defined) types with code <constant>V4L2_BUF_TYPE_PRIVATE</constant>
-and higher.</entry>
+and higher. See <xref linkend="v4l2-buf-type" />.</entry>
</row>
<row>
<entry>struct <link linkend="v4l2-rect-crop">v4l2_rect</link></entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml b/Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml
new file mode 100644
index 000000000000..6673ce582050
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/vidioc-dv-timings-cap.xml
@@ -0,0 +1,211 @@
+<refentry id="vidioc-dv-timings-cap">
+ <refmeta>
+ <refentrytitle>ioctl VIDIOC_DV_TIMINGS_CAP</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>VIDIOC_DV_TIMINGS_CAP</refname>
+ <refpurpose>The capabilities of the Digital Video receiver/transmitter</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>struct v4l2_dv_timings_cap *<parameter>argp</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>VIDIOC_DV_TIMINGS_CAP</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>argp</parameter></term>
+ <listitem>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <note>
+ <title>Experimental</title>
+ <para>This is an <link linkend="experimental"> experimental </link>
+ interface and may change in the future.</para>
+ </note>
+
+ <para>To query the available timings, applications initialize the
+<structfield>index</structfield> field and zero the reserved array of &v4l2-dv-timings-cap;
+and call the <constant>VIDIOC_DV_TIMINGS_CAP</constant> ioctl with a pointer to this
+structure. Drivers fill the rest of the structure or return an
+&EINVAL; when the index is out of bounds. To enumerate all supported DV timings,
+applications shall begin at index zero, incrementing by one until the
+driver returns <errorcode>EINVAL</errorcode>. Note that drivers may enumerate a
+different set of DV timings after switching the video input or
+output.</para>
+
+ <table pgwide="1" frame="none" id="v4l2-bt-timings-cap">
+ <title>struct <structname>v4l2_bt_timings_cap</structname></title>
+ <tgroup cols="3">
+ &cs-str;
+ <tbody valign="top">
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>min_width</structfield></entry>
+ <entry>Minimum width of the active video in pixels.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>max_width</structfield></entry>
+ <entry>Maximum width of the active video in pixels.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>min_height</structfield></entry>
+ <entry>Minimum height of the active video in lines.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>max_height</structfield></entry>
+ <entry>Maximum height of the active video in lines.</entry>
+ </row>
+ <row>
+ <entry>__u64</entry>
+ <entry><structfield>min_pixelclock</structfield></entry>
+ <entry>Minimum pixelclock frequency in Hz.</entry>
+ </row>
+ <row>
+ <entry>__u64</entry>
+ <entry><structfield>max_pixelclock</structfield></entry>
+ <entry>Maximum pixelclock frequency in Hz.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>standards</structfield></entry>
+ <entry>The video standard(s) supported by the hardware.
+ See <xref linkend="dv-bt-standards"/> for a list of standards.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>capabilities</structfield></entry>
+ <entry>Several flags giving more information about the capabilities.
+ See <xref linkend="dv-bt-cap-capabilities"/> for a description of the flags.
+ </entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>reserved</structfield>[16]</entry>
+ <entry></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table pgwide="1" frame="none" id="v4l2-dv-timings-cap">
+ <title>struct <structname>v4l2_dv_timings_cap</structname></title>
+ <tgroup cols="4">
+ &cs-str;
+ <tbody valign="top">
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>type</structfield></entry>
+ <entry>Type of DV timings as listed in <xref linkend="dv-timing-types"/>.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>reserved</structfield>[3]</entry>
+ <entry>Reserved for future extensions. Drivers must set the array to zero.</entry>
+ </row>
+ <row>
+ <entry>union</entry>
+ <entry><structfield></structfield></entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry>&v4l2-bt-timings-cap;</entry>
+ <entry><structfield>bt</structfield></entry>
+ <entry>BT.656/1120 timings capabilities of the hardware.</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry>__u32</entry>
+ <entry><structfield>raw_data</structfield>[32]</entry>
+ <entry></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table pgwide="1" frame="none" id="dv-bt-cap-capabilities">
+ <title>DV BT Timing capabilities</title>
+ <tgroup cols="2">
+ &cs-str;
+ <tbody valign="top">
+ <row>
+ <entry>Flag</entry>
+ <entry>Description</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry>V4L2_DV_BT_CAP_INTERLACED</entry>
+ <entry>Interlaced formats are supported.
+ </entry>
+ </row>
+ <row>
+ <entry>V4L2_DV_BT_CAP_PROGRESSIVE</entry>
+ <entry>Progressive formats are supported.
+ </entry>
+ </row>
+ <row>
+ <entry>V4L2_DV_BT_CAP_REDUCED_BLANKING</entry>
+ <entry>CVT/GTF specific: the timings can make use of reduced blanking (CVT)
+or the 'Secondary GTF' curve (GTF).
+ </entry>
+ </row>
+ <row>
+ <entry>V4L2_DV_BT_CAP_CUSTOM</entry>
+ <entry>Can support non-standard timings, i.e. timings not belonging to the
+standards set in the <structfield>standards</structfield> field.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </refsect1>
+
+ <refsect1>
+ &return-value;
+ </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml b/Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml
index 0be17c232d3a..509f0012d2a6 100644
--- a/Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-enum-dv-presets.xml
@@ -48,6 +48,10 @@
<refsect1>
<title>Description</title>
+ <para>This ioctl is <emphasis role="bold">deprecated</emphasis>.
+ New drivers and applications should use &VIDIOC-ENUM-DV-TIMINGS; instead.
+ </para>
+
<para>To query the attributes of a DV preset, applications initialize the
<structfield>index</structfield> field and zero the reserved array of &v4l2-dv-enum-preset;
and call the <constant>VIDIOC_ENUM_DV_PRESETS</constant> ioctl with a pointer to this
diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml b/Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml
new file mode 100644
index 000000000000..24c3bf4fd29a
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/vidioc-enum-dv-timings.xml
@@ -0,0 +1,119 @@
+<refentry id="vidioc-enum-dv-timings">
+ <refmeta>
+ <refentrytitle>ioctl VIDIOC_ENUM_DV_TIMINGS</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>VIDIOC_ENUM_DV_TIMINGS</refname>
+ <refpurpose>Enumerate supported Digital Video timings</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>struct v4l2_enum_dv_timings *<parameter>argp</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>VIDIOC_ENUM_DV_TIMINGS</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>argp</parameter></term>
+ <listitem>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <note>
+ <title>Experimental</title>
+ <para>This is an <link linkend="experimental"> experimental </link>
+ interface and may change in the future.</para>
+ </note>
+
+ <para>While some DV receivers or transmitters support a wide range of timings, others
+support only a limited number of timings. With this ioctl applications can enumerate a list
+of known supported timings. Call &VIDIOC-DV-TIMINGS-CAP; to check if it also supports other
+standards or even custom timings that are not in this list.</para>
+
+ <para>To query the available timings, applications initialize the
+<structfield>index</structfield> field and zero the reserved array of &v4l2-enum-dv-timings;
+and call the <constant>VIDIOC_ENUM_DV_TIMINGS</constant> ioctl with a pointer to this
+structure. Drivers fill the rest of the structure or return an
+&EINVAL; when the index is out of bounds. To enumerate all supported DV timings,
+applications shall begin at index zero, incrementing by one until the
+driver returns <errorcode>EINVAL</errorcode>. Note that drivers may enumerate a
+different set of DV timings after switching the video input or
+output.</para>
+
+ <table pgwide="1" frame="none" id="v4l2-enum-dv-timings">
+ <title>struct <structname>v4l2_enum_dv_timings</structname></title>
+ <tgroup cols="3">
+ &cs-str;
+ <tbody valign="top">
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>index</structfield></entry>
+ <entry>Number of the DV timings, set by the
+application.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>reserved</structfield>[3]</entry>
+ <entry>Reserved for future extensions. Drivers must set the array to zero.</entry>
+ </row>
+ <row>
+ <entry>&v4l2-dv-timings;</entry>
+ <entry><structfield>timings</structfield></entry>
+ <entry>The timings.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </refsect1>
+
+ <refsect1>
+ &return-value;
+
+ <variablelist>
+ <varlistentry>
+ <term><errorcode>EINVAL</errorcode></term>
+ <listitem>
+ <para>The &v4l2-enum-dv-timings; <structfield>index</structfield>
+is out of bounds.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+</refentry>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "v4l2.sgml"
+indent-tabs-mode: nil
+End:
+-->
diff --git a/Documentation/DocBook/media/v4l/vidioc-enum-fmt.xml b/Documentation/DocBook/media/v4l/vidioc-enum-fmt.xml
index 347d142e7431..81ebe48317fe 100644
--- a/Documentation/DocBook/media/v4l/vidioc-enum-fmt.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-enum-fmt.xml
@@ -71,7 +71,7 @@ the application. This is in no way related to the <structfield>
pixelformat</structfield> field.</entry>
</row>
<row>
- <entry>&v4l2-buf-type;</entry>
+ <entry>__u32</entry>
<entry><structfield>type</structfield></entry>
<entry>Type of the data stream, set by the application.
Only these types are valid here:
@@ -81,7 +81,7 @@ Only these types are valid here:
<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE</constant>,
<constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>, and custom (driver
defined) types with code <constant>V4L2_BUF_TYPE_PRIVATE</constant>
-and higher.</entry>
+and higher. See <xref linkend="v4l2-buf-type" />.</entry>
</row>
<row>
<entry>__u32</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enuminput.xml b/Documentation/DocBook/media/v4l/vidioc-enuminput.xml
index 9b8efcd6e947..46d5a044a537 100644
--- a/Documentation/DocBook/media/v4l/vidioc-enuminput.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-enuminput.xml
@@ -285,7 +285,7 @@ input/output interface to linux-media@vger.kernel.org on 19 Oct 2009.
<row>
<entry><constant>V4L2_IN_CAP_CUSTOM_TIMINGS</constant></entry>
<entry>0x00000002</entry>
- <entry>This input supports setting custom video timings by using VIDIOC_S_DV_TIMINGS.</entry>
+ <entry>This input supports setting video timings by using VIDIOC_S_DV_TIMINGS.</entry>
</row>
<row>
<entry><constant>V4L2_IN_CAP_STD</constant></entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml b/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml
index a64d5ef103fa..428020000ef0 100644
--- a/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml
@@ -170,7 +170,7 @@ input/output interface to linux-media@vger.kernel.org on 19 Oct 2009.
<row>
<entry><constant>V4L2_OUT_CAP_CUSTOM_TIMINGS</constant></entry>
<entry>0x00000002</entry>
- <entry>This output supports setting custom video timings by using VIDIOC_S_DV_TIMINGS.</entry>
+ <entry>This output supports setting video timings by using VIDIOC_S_DV_TIMINGS.</entry>
</row>
<row>
<entry><constant>V4L2_OUT_CAP_STD</constant></entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-crop.xml b/Documentation/DocBook/media/v4l/vidioc-g-crop.xml
index 01a50640dce0..c4ff3b1887fb 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-crop.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-crop.xml
@@ -100,14 +100,14 @@ changed and <constant>VIDIOC_S_CROP</constant> returns the
&cs-str;
<tbody valign="top">
<row>
- <entry>&v4l2-buf-type;</entry>
+ <entry>__u32</entry>
<entry><structfield>type</structfield></entry>
<entry>Type of the data stream, set by the application.
Only these types are valid here: <constant>V4L2_BUF_TYPE_VIDEO_CAPTURE</constant>,
<constant>V4L2_BUF_TYPE_VIDEO_OUTPUT</constant>,
<constant>V4L2_BUF_TYPE_VIDEO_OVERLAY</constant>, and custom (driver
defined) types with code <constant>V4L2_BUF_TYPE_PRIVATE</constant>
-and higher.</entry>
+and higher. See <xref linkend="v4l2-buf-type" />.</entry>
</row>
<row>
<entry>&v4l2-rect;</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-dv-preset.xml b/Documentation/DocBook/media/v4l/vidioc-g-dv-preset.xml
index 7940c1149393..61be9fa3803a 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-dv-preset.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-dv-preset.xml
@@ -48,6 +48,12 @@
<refsect1>
<title>Description</title>
+
+ <para>These ioctls are <emphasis role="bold">deprecated</emphasis>.
+ New drivers and applications should use &VIDIOC-G-DV-TIMINGS; and &VIDIOC-S-DV-TIMINGS;
+ instead.
+ </para>
+
<para>To query and select the current DV preset, applications
use the <constant>VIDIOC_G_DV_PRESET</constant> and <constant>VIDIOC_S_DV_PRESET</constant>
ioctls which take a pointer to a &v4l2-dv-preset; type as argument.
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml b/Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml
index 4a8648ae9a63..eda1a2991bbe 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-dv-timings.xml
@@ -7,7 +7,7 @@
<refnamediv>
<refname>VIDIOC_G_DV_TIMINGS</refname>
<refname>VIDIOC_S_DV_TIMINGS</refname>
- <refpurpose>Get or set custom DV timings for input or output</refpurpose>
+ <refpurpose>Get or set DV timings for input or output</refpurpose>
</refnamediv>
<refsynopsisdiv>
@@ -48,12 +48,15 @@
<refsect1>
<title>Description</title>
- <para>To set custom DV timings for the input or output, applications use the
-<constant>VIDIOC_S_DV_TIMINGS</constant> ioctl and to get the current custom timings,
+ <para>To set DV timings for the input or output, applications use the
+<constant>VIDIOC_S_DV_TIMINGS</constant> ioctl and to get the current timings,
applications use the <constant>VIDIOC_G_DV_TIMINGS</constant> ioctl. The detailed timing
information is filled in using the structure &v4l2-dv-timings;. These ioctls take
a pointer to the &v4l2-dv-timings; structure as argument. If the ioctl is not supported
or the timing values are not correct, the driver returns &EINVAL;.</para>
+<para>The <filename>linux/v4l2-dv-timings.h</filename> header can be used to get the
+timings of the formats in the <xref linkend="cea861" /> and <xref linkend="vesadmt" />
+standards.</para>
</refsect1>
<refsect1>
@@ -83,12 +86,13 @@ or the timing values are not correct, the driver returns &EINVAL;.</para>
<row>
<entry>__u32</entry>
<entry><structfield>width</structfield></entry>
- <entry>Width of the active video in pixels</entry>
+ <entry>Width of the active video in pixels.</entry>
</row>
<row>
<entry>__u32</entry>
<entry><structfield>height</structfield></entry>
- <entry>Height of the active video in lines</entry>
+ <entry>Height of the active video frame in lines. So for interlaced formats the
+ height of the active video in each field is <structfield>height</structfield>/2.</entry>
</row>
<row>
<entry>__u32</entry>
@@ -125,32 +129,52 @@ bit 0 (V4L2_DV_VSYNC_POS_POL) is for vertical sync polarity and bit 1 (V4L2_DV_H
<row>
<entry>__u32</entry>
<entry><structfield>vfrontporch</structfield></entry>
- <entry>Vertical front porch in lines</entry>
+ <entry>Vertical front porch in lines. For interlaced formats this refers to the
+ odd field (aka field 1).</entry>
</row>
<row>
<entry>__u32</entry>
<entry><structfield>vsync</structfield></entry>
- <entry>Vertical sync length in lines</entry>
+ <entry>Vertical sync length in lines. For interlaced formats this refers to the
+ odd field (aka field 1).</entry>
</row>
<row>
<entry>__u32</entry>
<entry><structfield>vbackporch</structfield></entry>
- <entry>Vertical back porch in lines</entry>
+ <entry>Vertical back porch in lines. For interlaced formats this refers to the
+ odd field (aka field 1).</entry>
</row>
<row>
<entry>__u32</entry>
<entry><structfield>il_vfrontporch</structfield></entry>
- <entry>Vertical front porch in lines for bottom field of interlaced field formats</entry>
+ <entry>Vertical front porch in lines for the even field (aka field 2) of
+ interlaced field formats.</entry>
</row>
<row>
<entry>__u32</entry>
<entry><structfield>il_vsync</structfield></entry>
- <entry>Vertical sync length in lines for bottom field of interlaced field formats</entry>
+ <entry>Vertical sync length in lines for the even field (aka field 2) of
+ interlaced field formats.</entry>
</row>
<row>
<entry>__u32</entry>
<entry><structfield>il_vbackporch</structfield></entry>
- <entry>Vertical back porch in lines for bottom field of interlaced field formats</entry>
+ <entry>Vertical back porch in lines for the even field (aka field 2) of
+ interlaced field formats.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>standards</structfield></entry>
+ <entry>The video standard(s) this format belongs to. This will be filled in by
+ the driver. Applications must set this to 0. See <xref linkend="dv-bt-standards"/>
+ for a list of standards.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>flags</structfield></entry>
+ <entry>Several flags giving more information about the format.
+ See <xref linkend="dv-bt-flags"/> for a description of the flags.
+ </entry>
</row>
</tbody>
</tgroup>
@@ -211,6 +235,90 @@ bit 0 (V4L2_DV_VSYNC_POS_POL) is for vertical sync polarity and bit 1 (V4L2_DV_H
</tbody>
</tgroup>
</table>
+ <table pgwide="1" frame="none" id="dv-bt-standards">
+ <title>DV BT Timing standards</title>
+ <tgroup cols="2">
+ &cs-str;
+ <tbody valign="top">
+ <row>
+ <entry>Timing standard</entry>
+ <entry>Description</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry>V4L2_DV_BT_STD_CEA861</entry>
+ <entry>The timings follow the CEA-861 Digital TV Profile standard</entry>
+ </row>
+ <row>
+ <entry>V4L2_DV_BT_STD_DMT</entry>
+ <entry>The timings follow the VESA Discrete Monitor Timings standard</entry>
+ </row>
+ <row>
+ <entry>V4L2_DV_BT_STD_CVT</entry>
+ <entry>The timings follow the VESA Coordinated Video Timings standard</entry>
+ </row>
+ <row>
+ <entry>V4L2_DV_BT_STD_GTF</entry>
+ <entry>The timings follow the VESA Generalized Timings Formula standard</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <table pgwide="1" frame="none" id="dv-bt-flags">
+ <title>DV BT Timing flags</title>
+ <tgroup cols="2">
+ &cs-str;
+ <tbody valign="top">
+ <row>
+ <entry>Flag</entry>
+ <entry>Description</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry>V4L2_DV_FL_REDUCED_BLANKING</entry>
+ <entry>CVT/GTF specific: the timings use reduced blanking (CVT) or the 'Secondary
+GTF' curve (GTF). In both cases the horizontal and/or vertical blanking
+intervals are reduced, allowing a higher resolution over the same
+bandwidth. This is a read-only flag, applications must not set this.
+ </entry>
+ </row>
+ <row>
+ <entry>V4L2_DV_FL_CAN_REDUCE_FPS</entry>
+ <entry>CEA-861 specific: set for CEA-861 formats with a framerate that is a multiple
+of six. These formats can be optionally played at 1 / 1.001 speed to
+be compatible with 60 Hz based standards such as NTSC and PAL-M that use a framerate of
+29.97 frames per second. If the transmitter can't generate such frequencies, then the
+flag will also be cleared. This is a read-only flag, applications must not set this.
+ </entry>
+ </row>
+ <row>
+ <entry>V4L2_DV_FL_REDUCED_FPS</entry>
+ <entry>CEA-861 specific: only valid for video transmitters, the flag is cleared
+by receivers. It is also only valid for formats with the V4L2_DV_FL_CAN_REDUCE_FPS flag
+set, for other formats the flag will be cleared by the driver.
+
+If the application sets this flag, then the pixelclock used to set up the transmitter is
+divided by 1.001 to make it compatible with NTSC framerates. If the transmitter
+can't generate such frequencies, then the flag will also be cleared.
+ </entry>
+ </row>
+ <row>
+ <entry>V4L2_DV_FL_HALF_LINE</entry>
+ <entry>Specific to interlaced formats: if set, then field 1 (aka the odd field)
+is really one half-line longer and field 2 (aka the even field) is really one half-line
+shorter, so each field has exactly the same number of half-lines. Whether half-lines can be
+detected or used depends on the hardware.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
</refsect1>
<refsect1>
&return-value;
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
index b17a7aac6997..e3d5afcdafbb 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
@@ -265,6 +265,32 @@ These controls are described in <xref
These controls are described in <xref
linkend="flash-controls" />.</entry>
</row>
+ <row>
+ <entry><constant>V4L2_CTRL_CLASS_JPEG</constant></entry>
+ <entry>0x9d0000</entry>
+ <entry>The class containing JPEG compression controls.
+These controls are described in <xref
+ linkend="jpeg-controls" />.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_CTRL_CLASS_IMAGE_SOURCE</constant></entry>
+ <entry>0x9e0000</entry> <entry>The class containing image
+ source controls. These controls are described in <xref
+ linkend="image-source-controls" />.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_CTRL_CLASS_IMAGE_PROC</constant></entry>
+ <entry>0x9f0000</entry> <entry>The class containing image
+ processing controls. These controls are described in <xref
+ linkend="image-process-controls" />.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_CTRL_CLASS_JPEG</constant></entry>
+ <entry>0x9d0000</entry>
+ <entry>The class containing JPEG compression controls.
+These controls are described in <xref
+ linkend="jpeg-controls" />.</entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml b/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml
index 17fbda15137b..52acff193a6f 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml
@@ -116,7 +116,7 @@ this ioctl.</para>
<colspec colname="c4" />
<tbody valign="top">
<row>
- <entry>&v4l2-buf-type;</entry>
+ <entry>__u32</entry>
<entry><structfield>type</structfield></entry>
<entry></entry>
<entry>Type of the data stream, see <xref
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml b/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml
index 66e9a5257861..69c178a4d205 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-frequency.xml
@@ -95,14 +95,14 @@ the &v4l2-output; <structfield>modulator</structfield> field and the
&v4l2-modulator; <structfield>index</structfield> field.</entry>
</row>
<row>
- <entry>&v4l2-tuner-type;</entry>
+ <entry>__u32</entry>
<entry><structfield>type</structfield></entry>
<entry>The tuner type. This is the same value as in the
-&v4l2-tuner; <structfield>type</structfield> field. The type must be set
+&v4l2-tuner; <structfield>type</structfield> field. See The type must be set
to <constant>V4L2_TUNER_RADIO</constant> for <filename>/dev/radioX</filename>
device nodes, and to <constant>V4L2_TUNER_ANALOG_TV</constant>
for all others. The field is not applicable to modulators, &ie; ignored
-by drivers.</entry>
+by drivers. See <xref linkend="v4l2-tuner-type" /></entry>
</row>
<row>
<entry>__u32</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-parm.xml b/Documentation/DocBook/media/v4l/vidioc-g-parm.xml
index 19b1d85dd668..f83d2cdd1185 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-parm.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-parm.xml
@@ -75,11 +75,12 @@ devices.</para>
&cs-ustr;
<tbody valign="top">
<row>
- <entry>&v4l2-buf-type;</entry>
+ <entry>__u32</entry>
<entry><structfield>type</structfield></entry>
<entry></entry>
<entry>The buffer (stream) type, same as &v4l2-format;
-<structfield>type</structfield>, set by the application.</entry>
+<structfield>type</structfield>, set by the application. See <xref
+ linkend="v4l2-buf-type" /></entry>
</row>
<row>
<entry>union</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml b/Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml
index 71741daaf725..bd015d1563ff 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-sliced-vbi-cap.xml
@@ -148,7 +148,7 @@ using the &VIDIOC-S-FMT; ioctl as described in <xref
<structfield>service_lines</structfield>[1][0] to zero.</entry>
</row>
<row>
- <entry>&v4l2-buf-type;</entry>
+ <entry>__u32</entry>
<entry><structfield>type</structfield></entry>
<entry>Type of the data stream, see <xref
linkend="v4l2-buf-type" />. Should be
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml b/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
index 91ec2fb658f8..62a1aa200a36 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
@@ -107,7 +107,7 @@ user.<!-- FIXME Video inputs already have a name, the purpose of this
field is not quite clear.--></para></entry>
</row>
<row>
- <entry>&v4l2-tuner-type;</entry>
+ <entry>__u32</entry>
<entry><structfield>type</structfield></entry>
<entry spanname="hspan">Type of the tuner, see <xref
linkend="v4l2-tuner-type" />.</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
index 7bde698760e4..fa7ad7e33228 100644
--- a/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-prepare-buf.xml
@@ -48,6 +48,12 @@
<refsect1>
<title>Description</title>
+ <note>
+ <title>Experimental</title>
+ <para>This is an <link linkend="experimental"> experimental </link>
+ interface and may change in the future.</para>
+ </note>
+
<para>Applications can optionally call the
<constant>VIDIOC_PREPARE_BUF</constant> ioctl to pass ownership of the buffer
to the driver before actually enqueuing it, using the
diff --git a/Documentation/DocBook/media/v4l/vidioc-query-dv-preset.xml b/Documentation/DocBook/media/v4l/vidioc-query-dv-preset.xml
index 23b17f604211..1bc8aeb3ff1f 100644
--- a/Documentation/DocBook/media/v4l/vidioc-query-dv-preset.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-query-dv-preset.xml
@@ -49,6 +49,10 @@ input</refpurpose>
<refsect1>
<title>Description</title>
+ <para>This ioctl is <emphasis role="bold">deprecated</emphasis>.
+ New drivers and applications should use &VIDIOC-QUERY-DV-TIMINGS; instead.
+ </para>
+
<para>The hardware may be able to detect the current DV preset
automatically, similar to sensing the video standard. To do so, applications
call <constant> VIDIOC_QUERY_DV_PRESET</constant> with a pointer to a
diff --git a/Documentation/DocBook/media/v4l/vidioc-query-dv-timings.xml b/Documentation/DocBook/media/v4l/vidioc-query-dv-timings.xml
new file mode 100644
index 000000000000..44935a0ffcf0
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/vidioc-query-dv-timings.xml
@@ -0,0 +1,104 @@
+<refentry id="vidioc-query-dv-timings">
+ <refmeta>
+ <refentrytitle>ioctl VIDIOC_QUERY_DV_TIMINGS</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>VIDIOC_QUERY_DV_TIMINGS</refname>
+ <refpurpose>Sense the DV preset received by the current
+input</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>struct v4l2_dv_timings *<parameter>argp</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>VIDIOC_QUERY_DV_TIMINGS</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>argp</parameter></term>
+ <listitem>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <note>
+ <title>Experimental</title>
+ <para>This is an <link linkend="experimental"> experimental </link>
+ interface and may change in the future.</para>
+ </note>
+
+ <para>The hardware may be able to detect the current DV timings
+automatically, similar to sensing the video standard. To do so, applications
+call <constant>VIDIOC_QUERY_DV_TIMINGS</constant> with a pointer to a
+&v4l2-dv-timings;. Once the hardware detects the timings, it will fill in the
+timings structure.
+
+If the timings could not be detected because there was no signal, then
+<errorcode>ENOLINK</errorcode> is returned. If a signal was detected, but
+it was unstable and the receiver could not lock to the signal, then
+<errorcode>ENOLCK</errorcode> is returned. If the receiver could lock to the signal,
+but the format is unsupported (e.g. because the pixelclock is out of range
+of the hardware capabilities), then the driver fills in whatever timings it
+could find and returns <errorcode>ERANGE</errorcode>. In that case the application
+can call &VIDIOC-DV-TIMINGS-CAP; to compare the found timings with the hardware's
+capabilities in order to give more precise feedback to the user.
+</para>
+ </refsect1>
+
+ <refsect1>
+ &return-value;
+
+ <variablelist>
+ <varlistentry>
+ <term><errorcode>ENOLINK</errorcode></term>
+ <listitem>
+ <para>No timings could be detected because no signal was found.
+</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>ENOLCK</errorcode></term>
+ <listitem>
+ <para>The signal was unstable and the hardware could not lock on to it.
+</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>ERANGE</errorcode></term>
+ <listitem>
+ <para>Timings were found, but they are out of range of the hardware
+capabilities.
+</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
index 36660d311b51..e6645b996558 100644
--- a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
@@ -127,7 +127,7 @@ the first control with a higher ID. Drivers which do not support this
flag yet always return an &EINVAL;.</entry>
</row>
<row>
- <entry>&v4l2-ctrl-type;</entry>
+ <entry>__u32</entry>
<entry><structfield>type</structfield></entry>
<entry>Type of control, see <xref
linkend="v4l2-ctrl-type" />.</entry>
@@ -215,11 +215,12 @@ the array to zero.</entry>
<table pgwide="1" frame="none" id="v4l2-querymenu">
<title>struct <structname>v4l2_querymenu</structname></title>
- <tgroup cols="3">
+ <tgroup cols="4">
&cs-str;
<tbody valign="top">
<row>
<entry>__u32</entry>
+ <entry></entry>
<entry><structfield>id</structfield></entry>
<entry>Identifies the control, set by the application
from the respective &v4l2-queryctrl;
@@ -227,18 +228,38 @@ from the respective &v4l2-queryctrl;
</row>
<row>
<entry>__u32</entry>
+ <entry></entry>
<entry><structfield>index</structfield></entry>
<entry>Index of the menu item, starting at zero, set by
the application.</entry>
</row>
<row>
+ <entry>union</entry>
+ <entry></entry>
+ <entry></entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry></entry>
<entry>__u8</entry>
<entry><structfield>name</structfield>[32]</entry>
<entry>Name of the menu item, a NUL-terminated ASCII
-string. This information is intended for the user.</entry>
+string. This information is intended for the user. This field is valid
+for <constant>V4L2_CTRL_FLAG_MENU</constant> type controls.</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry>__s64</entry>
+ <entry><structfield>value</structfield></entry>
+ <entry>
+ Value of the integer menu item. This field is valid for
+ <constant>V4L2_CTRL_FLAG_INTEGER_MENU</constant> type
+ controls.
+ </entry>
</row>
<row>
<entry>__u32</entry>
+ <entry></entry>
<entry><structfield>reserved</structfield></entry>
<entry>Reserved for future extensions. Drivers must set
the array to zero.</entry>
@@ -292,6 +313,20 @@ the menu items can be enumerated with the
<constant>VIDIOC_QUERYMENU</constant> ioctl.</entry>
</row>
<row>
+ <entry><constant>V4L2_CTRL_TYPE_INTEGER_MENU</constant></entry>
+ <entry>&ge; 0</entry>
+ <entry>1</entry>
+ <entry>N-1</entry>
+ <entry>
+ The control has a menu of N choices. The values of the
+ menu items can be enumerated with the
+ <constant>VIDIOC_QUERYMENU</constant> ioctl. This is
+ similar to <constant>V4L2_CTRL_TYPE_MENU</constant>
+ except that instead of strings, the menu items are
+ signed 64-bit integers.
+ </entry>
+ </row>
+ <row>
<entry><constant>V4L2_CTRL_TYPE_BITMASK</constant></entry>
<entry>0</entry>
<entry>n/a</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-reqbufs.xml b/Documentation/DocBook/media/v4l/vidioc-reqbufs.xml
index 7be4b1d29b90..d7c95057bc51 100644
--- a/Documentation/DocBook/media/v4l/vidioc-reqbufs.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-reqbufs.xml
@@ -92,18 +92,19 @@ streamoff.--></para>
<entry>The number of buffers requested or granted.</entry>
</row>
<row>
- <entry>&v4l2-buf-type;</entry>
+ <entry>__u32</entry>
<entry><structfield>type</structfield></entry>
<entry>Type of the stream or buffers, this is the same
as the &v4l2-format; <structfield>type</structfield> field. See <xref
linkend="v4l2-buf-type" /> for valid values.</entry>
</row>
<row>
- <entry>&v4l2-memory;</entry>
+ <entry>__u32</entry>
<entry><structfield>memory</structfield></entry>
<entry>Applications set this field to
<constant>V4L2_MEMORY_MMAP</constant> or
-<constant>V4L2_MEMORY_USERPTR</constant>.</entry>
+<constant>V4L2_MEMORY_USERPTR</constant>. See <xref linkend="v4l2-memory"
+/>.</entry>
</row>
<row>
<entry>__u32</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml b/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml
index 18b1a8266f7c..407dfceb71f0 100644
--- a/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-s-hw-freq-seek.xml
@@ -73,10 +73,11 @@ same value as in the &v4l2-input; <structfield>tuner</structfield>
field and the &v4l2-tuner; <structfield>index</structfield> field.</entry>
</row>
<row>
- <entry>&v4l2-tuner-type;</entry>
+ <entry>__u32</entry>
<entry><structfield>type</structfield></entry>
<entry>The tuner type. This is the same value as in the
-&v4l2-tuner; <structfield>type</structfield> field.</entry>
+&v4l2-tuner; <structfield>type</structfield> field. See <xref
+ linkend="v4l2-tuner-type" /></entry>
</row>
<row>
<entry>__u32</entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-crop.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-crop.xml
index 06197323a8cc..4cddd788c589 100644
--- a/Documentation/DocBook/media/v4l/vidioc-subdev-g-crop.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-subdev-g-crop.xml
@@ -58,9 +58,12 @@
<title>Description</title>
<note>
- <title>Experimental</title>
- <para>This is an <link linkend="experimental">experimental</link>
- interface and may change in the future.</para>
+ <title>Obsolete</title>
+
+ <para>This is an <link linkend="obsolete">obsolete</link>
+ interface and may be removed in the future. It is superseded by
+ <link linkend="vidioc-subdev-g-selection">the selection
+ API</link>.</para>
</note>
<para>To retrieve the current crop rectangle applications set the
diff --git a/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
new file mode 100644
index 000000000000..208e9f0da3f3
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/vidioc-subdev-g-selection.xml
@@ -0,0 +1,228 @@
+<refentry id="vidioc-subdev-g-selection">
+ <refmeta>
+ <refentrytitle>ioctl VIDIOC_SUBDEV_G_SELECTION, VIDIOC_SUBDEV_S_SELECTION</refentrytitle>
+ &manvol;
+ </refmeta>
+
+ <refnamediv>
+ <refname>VIDIOC_SUBDEV_G_SELECTION</refname>
+ <refname>VIDIOC_SUBDEV_S_SELECTION</refname>
+ <refpurpose>Get or set selection rectangles on a subdev pad</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>int <function>ioctl</function></funcdef>
+ <paramdef>int <parameter>fd</parameter></paramdef>
+ <paramdef>int <parameter>request</parameter></paramdef>
+ <paramdef>struct v4l2_subdev_selection *<parameter>argp</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><parameter>fd</parameter></term>
+ <listitem>
+ <para>&fd;</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>request</parameter></term>
+ <listitem>
+ <para>VIDIOC_SUBDEV_G_SELECTION, VIDIOC_SUBDEV_S_SELECTION</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><parameter>argp</parameter></term>
+ <listitem>
+ <para></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Description</title>
+
+ <note>
+ <title>Experimental</title>
+ <para>This is an <link linkend="experimental">experimental</link>
+ interface and may change in the future.</para>
+ </note>
+
+ <para>The selections are used to configure various image
+ processing functionality performed by the subdevs which affect the
+ image size. This currently includes cropping, scaling and
+ composition.</para>
+
+ <para>The selection API replaces <link
+ linkend="vidioc-subdev-g-crop">the old subdev crop API</link>. All
+ the function of the crop API, and more, are supported by the
+ selections API.</para>
+
+ <para>See <xref linkend="subdev"></xref> for
+ more information on how each selection target affects the image
+ processing pipeline inside the subdevice.</para>
+
+ <section>
+ <title>Types of selection targets</title>
+
+ <para>There are two types of selection targets: actual and bounds.
+ The ACTUAL targets are the targets which configure the hardware.
+ The BOUNDS target will return a rectangle that contain all
+ possible ACTUAL rectangles.</para>
+ </section>
+
+ <section>
+ <title>Discovering supported features</title>
+
+ <para>To discover which targets are supported, the user can
+ perform <constant>VIDIOC_SUBDEV_G_SELECTION</constant> on them.
+ Any unsupported target will return
+ <constant>EINVAL</constant>.</para>
+ </section>
+
+ <table pgwide="1" frame="none" id="v4l2-subdev-selection-targets">
+ <title>V4L2 subdev selection targets</title>
+ <tgroup cols="3">
+ &cs-def;
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL</constant></entry>
+ <entry>0x0000</entry>
+ <entry>Actual crop. Defines the cropping
+ performed by the processing step.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS</constant></entry>
+ <entry>0x0002</entry>
+ <entry>Bounds of the crop rectangle.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL</constant></entry>
+ <entry>0x0100</entry>
+ <entry>Actual compose rectangle. Used to configure scaling
+ on sink pads and composition on source pads.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS</constant></entry>
+ <entry>0x0102</entry>
+ <entry>Bounds of the compose rectangle.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table pgwide="1" frame="none" id="v4l2-subdev-selection-flags">
+ <title>V4L2 subdev selection flags</title>
+ <tgroup cols="3">
+ &cs-def;
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_SUBDEV_SEL_FLAG_SIZE_GE</constant></entry>
+ <entry>(1 &lt;&lt; 0)</entry> <entry>Suggest the driver it
+ should choose greater or equal rectangle (in size) than
+ was requested. Albeit the driver may choose a lesser size,
+ it will only do so due to hardware limitations. Without
+ this flag (and
+ <constant>V4L2_SUBDEV_SEL_FLAG_SIZE_LE</constant>) the
+ behaviour is to choose the closest possible
+ rectangle.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SUBDEV_SEL_FLAG_SIZE_LE</constant></entry>
+ <entry>(1 &lt;&lt; 1)</entry> <entry>Suggest the driver it
+ should choose lesser or equal rectangle (in size) than was
+ requested. Albeit the driver may choose a greater size, it
+ will only do so due to hardware limitations.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG</constant></entry>
+ <entry>(1 &lt;&lt; 2)</entry>
+ <entry>The configuration should not be propagated to any
+ further processing steps. If this flag is not given, the
+ configuration is propagated inside the subdevice to all
+ further processing steps.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table pgwide="1" frame="none" id="v4l2-subdev-selection">
+ <title>struct <structname>v4l2_subdev_selection</structname></title>
+ <tgroup cols="3">
+ &cs-str;
+ <tbody valign="top">
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>which</structfield></entry>
+ <entry>Active or try selection, from
+ &v4l2-subdev-format-whence;.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>pad</structfield></entry>
+ <entry>Pad number as reported by the media framework.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>target</structfield></entry>
+ <entry>Target selection rectangle. See
+ <xref linkend="v4l2-subdev-selection-targets">.</xref>.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>flags</structfield></entry>
+ <entry>Flags. See
+ <xref linkend="v4l2-subdev-selection-flags">.</xref></entry>
+ </row>
+ <row>
+ <entry>&v4l2-rect;</entry>
+ <entry><structfield>rect</structfield></entry>
+ <entry>Selection rectangle, in pixels.</entry>
+ </row>
+ <row>
+ <entry>__u32</entry>
+ <entry><structfield>reserved</structfield>[8]</entry>
+ <entry>Reserved for future extensions. Applications and drivers must
+ set the array to zero.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </refsect1>
+
+ <refsect1>
+ &return-value;
+
+ <variablelist>
+ <varlistentry>
+ <term><errorcode>EBUSY</errorcode></term>
+ <listitem>
+ <para>The selection rectangle can't be changed because the
+ pad is currently busy. This can be caused, for instance, by
+ an active video stream on the pad. The ioctl must not be
+ retried without performing another action to fix the problem
+ first. Only returned by
+ <constant>VIDIOC_SUBDEV_S_SELECTION</constant></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><errorcode>EINVAL</errorcode></term>
+ <listitem>
+ <para>The &v4l2-subdev-selection;
+ <structfield>pad</structfield> references a non-existing
+ pad, the <structfield>which</structfield> field references a
+ non-existing format, or the selection target is not
+ supported on the given subdev pad.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+</refentry>
diff --git a/Documentation/HOWTO b/Documentation/HOWTO
index f7ade3b3b40d..59c080f084ef 100644
--- a/Documentation/HOWTO
+++ b/Documentation/HOWTO
@@ -218,16 +218,16 @@ The development process
Linux kernel development process currently consists of a few different
main kernel "branches" and lots of different subsystem-specific kernel
branches. These different branches are:
- - main 2.6.x kernel tree
- - 2.6.x.y -stable kernel tree
- - 2.6.x -git kernel patches
+ - main 3.x kernel tree
+ - 3.x.y -stable kernel tree
+ - 3.x -git kernel patches
- subsystem specific kernel trees and patches
- - the 2.6.x -next kernel tree for integration tests
+ - the 3.x -next kernel tree for integration tests
-2.6.x kernel tree
+3.x kernel tree
-----------------
-2.6.x kernels are maintained by Linus Torvalds, and can be found on
-kernel.org in the pub/linux/kernel/v2.6/ directory. Its development
+3.x kernels are maintained by Linus Torvalds, and can be found on
+kernel.org in the pub/linux/kernel/v3.x/ directory. Its development
process is as follows:
- As soon as a new kernel is released a two weeks window is open,
during this period of time maintainers can submit big diffs to
@@ -262,20 +262,20 @@ mailing list about kernel releases:
released according to perceived bug status, not according to a
preconceived timeline."
-2.6.x.y -stable kernel tree
+3.x.y -stable kernel tree
---------------------------
-Kernels with 4-part versions are -stable kernels. They contain
+Kernels with 3-part versions are -stable kernels. They contain
relatively small and critical fixes for security problems or significant
-regressions discovered in a given 2.6.x kernel.
+regressions discovered in a given 3.x kernel.
This is the recommended branch for users who want the most recent stable
kernel and are not interested in helping test development/experimental
versions.
-If no 2.6.x.y kernel is available, then the highest numbered 2.6.x
+If no 3.x.y kernel is available, then the highest numbered 3.x
kernel is the current stable kernel.
-2.6.x.y are maintained by the "stable" team <stable@vger.kernel.org>, and
+3.x.y are maintained by the "stable" team <stable@vger.kernel.org>, and
are released as needs dictate. The normal release period is approximately
two weeks, but it can be longer if there are no pressing problems. A
security-related problem, instead, can cause a release to happen almost
@@ -285,7 +285,7 @@ The file Documentation/stable_kernel_rules.txt in the kernel tree
documents what kinds of changes are acceptable for the -stable tree, and
how the release process works.
-2.6.x -git patches
+3.x -git patches
------------------
These are daily snapshots of Linus' kernel tree which are managed in a
git repository (hence the name.) These patches are usually released
@@ -317,13 +317,13 @@ revisions to it, and maintainers can mark patches as under review,
accepted, or rejected. Most of these patchwork sites are listed at
http://patchwork.kernel.org/.
-2.6.x -next kernel tree for integration tests
+3.x -next kernel tree for integration tests
---------------------------------------------
-Before updates from subsystem trees are merged into the mainline 2.6.x
+Before updates from subsystem trees are merged into the mainline 3.x
tree, they need to be integration-tested. For this purpose, a special
testing repository exists into which virtually all subsystem trees are
pulled on an almost daily basis:
- http://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git
+ http://git.kernel.org/?p=linux/kernel/git/next/linux-next.git
http://linux.f-seidel.de/linux-next/pmwiki/
This way, the -next kernel gives a summary outlook onto what will be
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 30b656ece7aa..31d302bc5863 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -1,3 +1,3 @@
obj-m := DocBook/ accounting/ auxdisplay/ connector/ \
filesystems/ filesystems/configfs/ ia64/ laptops/ networking/ \
- pcmcia/ spi/ timers/ watchdog/src/
+ pcmcia/ spi/ timers/ watchdog/src/ misc-devices/mei/
diff --git a/Documentation/arm/00-INDEX b/Documentation/arm/00-INDEX
index 91c24a1e8a9e..36420e116c90 100644
--- a/Documentation/arm/00-INDEX
+++ b/Documentation/arm/00-INDEX
@@ -4,8 +4,6 @@ Booting
- requirements for booting
Interrupts
- ARM Interrupt subsystem documentation
-IXP2000
- - Release Notes for Linux on Intel's IXP2000 Network Processor
msm
- MSM specific documentation
Netwinder
diff --git a/Documentation/arm/IXP2000 b/Documentation/arm/IXP2000
deleted file mode 100644
index 68d21d92a30b..000000000000
--- a/Documentation/arm/IXP2000
+++ /dev/null
@@ -1,69 +0,0 @@
-
--------------------------------------------------------------------------
-Release Notes for Linux on Intel's IXP2000 Network Processor
-
-Maintained by Deepak Saxena <dsaxena@plexity.net>
--------------------------------------------------------------------------
-
-1. Overview
-
-Intel's IXP2000 family of NPUs (IXP2400, IXP2800, IXP2850) is designed
-for high-performance network applications such high-availability
-telecom systems. In addition to an XScale core, it contains up to 8
-"MicroEngines" that run special code, several high-end networking
-interfaces (UTOPIA, SPI, etc), a PCI host bridge, one serial port,
-flash interface, and some other odds and ends. For more information, see:
-
-http://developer.intel.com
-
-2. Linux Support
-
-Linux currently supports the following features on the IXP2000 NPUs:
-
-- On-chip serial
-- PCI
-- Flash (MTD/JFFS2)
-- I2C through GPIO
-- Timers (watchdog, OS)
-
-That is about all we can support under Linux ATM b/c the core networking
-components of the chip are accessed via Intel's closed source SDK.
-Please contact Intel directly on issues with using those. There is
-also a mailing list run by some folks at Princeton University that might
-be of help: https://lists.cs.princeton.edu/mailman/listinfo/ixp2xxx
-
-WHATEVER YOU DO, DO NOT POST EMAIL TO THE LINUX-ARM OR LINUX-ARM-KERNEL
-MAILING LISTS REGARDING THE INTEL SDK.
-
-3. Supported Platforms
-
-- Intel IXDP2400 Reference Platform
-- Intel IXDP2800 Reference Platform
-- Intel IXDP2401 Reference Platform
-- Intel IXDP2801 Reference Platform
-- RadiSys ENP-2611
-
-4. Usage Notes
-
-- The IXP2000 platforms usually have rather complex PCI bus topologies
- with large memory space requirements. In addition, b/c of the way the
- Intel SDK is designed, devices are enumerated in a very specific
- way. B/c of this this, we use "pci=firmware" option in the kernel
- command line so that we do not re-enumerate the bus.
-
-- IXDP2x01 systems have variable clock tick rates that we cannot determine
- via HW registers. The "ixdp2x01_clk=XXX" cmd line options allow you
- to pass the clock rate to the board port.
-
-5. Thanks
-
-The IXP2000 work has been funded by Intel Corp. and MontaVista Software, Inc.
-
-The following people have contributed patches/comments/etc:
-
-Naeem F. Afzal
-Lennert Buytenhek
-Jeffrey Daly
-
--------------------------------------------------------------------------
-Last Update: 8/09/2004
diff --git a/Documentation/arm/SPEAr/overview.txt b/Documentation/arm/SPEAr/overview.txt
index 253a35c6f782..28a9af953b9d 100644
--- a/Documentation/arm/SPEAr/overview.txt
+++ b/Documentation/arm/SPEAr/overview.txt
@@ -17,14 +17,14 @@ Introduction
SPEAr (Platform)
- SPEAr3XX (3XX SOC series, based on ARM9)
- SPEAr300 (SOC)
- - SPEAr300_EVB (Evaluation Board)
+ - SPEAr300 Evaluation Board
- SPEAr310 (SOC)
- - SPEAr310_EVB (Evaluation Board)
+ - SPEAr310 Evaluation Board
- SPEAr320 (SOC)
- - SPEAr320_EVB (Evaluation Board)
+ - SPEAr320 Evaluation Board
- SPEAr6XX (6XX SOC series, based on ARM9)
- SPEAr600 (SOC)
- - SPEAr600_EVB (Evaluation Board)
+ - SPEAr600 Evaluation Board
- SPEAr13XX (13XX SOC series, based on ARM CORTEXA9)
- SPEAr1300 (SOC)
@@ -51,10 +51,11 @@ Introduction
Common file for machines of spear3xx family is mach-spear3xx/spear3xx.c and for
spear6xx is mach-spear6xx/spear6xx.c. mach-spear* also contain soc/machine
specific files, like spear300.c, spear310.c, spear320.c and spear600.c.
- mach-spear* also contains board specific files for each machine type.
+ mach-spear* doesn't contains board specific files as they fully support
+ Flattened Device Tree.
Document Author
---------------
- Viresh Kumar, (c) 2010 ST Microelectronics
+ Viresh Kumar <viresh.kumar@st.com>, (c) 2010-2012 ST Microelectronics
diff --git a/Documentation/blackfin/bfin-gpio-notes.txt b/Documentation/blackfin/bfin-gpio-notes.txt
index d36b01f778b9..d245f39c3d01 100644
--- a/Documentation/blackfin/bfin-gpio-notes.txt
+++ b/Documentation/blackfin/bfin-gpio-notes.txt
@@ -53,7 +53,7 @@
3. But there are some exceptions
- Kernel permit the identical GPIO be requested both as GPIO and GPIO
- interrut.
+ interrupt.
Some drivers, like gpio-keys, need this behavior. Kernel only print out
warning messages like,
bfin-gpio: GPIO 24 is already reserved by gpio-keys: BTN0, and you are
diff --git a/Documentation/cgroups/resource_counter.txt b/Documentation/cgroups/resource_counter.txt
index 95b24d766eab..f3c4ec3626a2 100644
--- a/Documentation/cgroups/resource_counter.txt
+++ b/Documentation/cgroups/resource_counter.txt
@@ -77,11 +77,11 @@ to work with it.
where the charging failed.
d. int res_counter_charge_locked
- (struct res_counter *rc, unsigned long val)
+ (struct res_counter *rc, unsigned long val, bool force)
The same as res_counter_charge(), but it must not acquire/release the
res_counter->lock internally (it must be called with res_counter->lock
- held).
+ held). The force parameter indicates whether we can bypass the limit.
e. void res_counter_uncharge[_locked]
(struct res_counter *rc, unsigned long val)
diff --git a/Documentation/devices.txt b/Documentation/devices.txt
index 00383186d8fb..47a154f30290 100644
--- a/Documentation/devices.txt
+++ b/Documentation/devices.txt
@@ -98,7 +98,8 @@ Your cooperation is appreciated.
8 = /dev/random Nondeterministic random number gen.
9 = /dev/urandom Faster, less secure random number gen.
10 = /dev/aio Asynchronous I/O notification interface
- 11 = /dev/kmsg Writes to this come out as printk's
+ 11 = /dev/kmsg Writes to this come out as printk's, reads
+ export the buffered printk records.
12 = /dev/oldmem Used by crashdump kernels to access
the memory of the kernel that crashed.
@@ -846,13 +847,7 @@ Your cooperation is appreciated.
...
31 = /dev/tap15 16th Ethertap device
- 36 block MCA ESDI hard disk
- 0 = /dev/eda First ESDI disk whole disk
- 64 = /dev/edb Second ESDI disk whole disk
- ...
-
- Partitions are handled in the same way as IDE disks
- (see major number 3).
+ 36 block OBSOLETE (was MCA ESDI hard disk)
37 char IDE tape
0 = /dev/ht0 First IDE tape
diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
new file mode 100644
index 000000000000..c63097d6afeb
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
@@ -0,0 +1,65 @@
+* AT91's Analog to Digital Converter (ADC)
+
+Required properties:
+ - compatible: Should be "atmel,at91sam9260-adc"
+ - reg: Should contain ADC registers location and length
+ - interrupts: Should contain the IRQ line for the ADC
+ - atmel,adc-channel-base: Offset of the first channel data register
+ - atmel,adc-channels-used: Bitmask of the channels muxed and enable for this
+ device
+ - atmel,adc-drdy-mask: Mask of the DRDY interruption in the ADC
+ - atmel,adc-num-channels: Number of channels available in the ADC
+ - atmel,adc-startup-time: Startup Time of the ADC in microseconds as
+ defined in the datasheet
+ - atmel,adc-status-register: Offset of the Interrupt Status Register
+ - atmel,adc-trigger-register: Offset of the Trigger Register
+ - atmel,adc-vref: Reference voltage in millivolts for the conversions
+
+Optional properties:
+ - atmel,adc-use-external: Boolean to enable of external triggers
+
+Optional trigger Nodes:
+ - Required properties:
+ * trigger-name: Name of the trigger exposed to the user
+ * trigger-value: Value to put in the Trigger register
+ to activate this trigger
+ - Optional properties:
+ * trigger-external: Is the trigger an external trigger?
+
+Examples:
+adc0: adc@fffb0000 {
+ compatible = "atmel,at91sam9260-adc";
+ reg = <0xfffb0000 0x100>;
+ interrupts = <20 4>;
+ atmel,adc-channel-base = <0x30>;
+ atmel,adc-channels-used = <0xff>;
+ atmel,adc-drdy-mask = <0x10000>;
+ atmel,adc-num-channels = <8>;
+ atmel,adc-startup-time = <40>;
+ atmel,adc-status-register = <0x1c>;
+ atmel,adc-trigger-register = <0x08>;
+ atmel,adc-use-external;
+ atmel,adc-vref = <3300>;
+
+ trigger@0 {
+ trigger-name = "external-rising";
+ trigger-value = <0x1>;
+ trigger-external;
+ };
+ trigger@1 {
+ trigger-name = "external-falling";
+ trigger-value = <0x2>;
+ trigger-external;
+ };
+
+ trigger@2 {
+ trigger-name = "external-any";
+ trigger-value = <0x3>;
+ trigger-external;
+ };
+
+ trigger@3 {
+ trigger-name = "continuous";
+ trigger-value = <0x6>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt
index 9b4b82a721b6..62eb8df1e08d 100644
--- a/Documentation/devicetree/bindings/arm/gic.txt
+++ b/Documentation/devicetree/bindings/arm/gic.txt
@@ -11,7 +11,9 @@ have PPIs or SGIs.
Main node required properties:
- compatible : should be one of:
+ "arm,cortex-a15-gic"
"arm,cortex-a9-gic"
+ "arm,cortex-a7-gic"
"arm,arm11mp-gic"
- interrupt-controller : Identifies the node as an interrupt controller
- #interrupt-cells : Specifies the number of cells needed to encode an
@@ -39,8 +41,9 @@ Main node required properties:
the GIC cpu interface register base and size.
Optional
-- interrupts : Interrupt source of the parent interrupt controller. Only
- present on secondary GICs.
+- interrupts : Interrupt source of the parent interrupt controller on
+ secondary GICs, or VGIC maintainance interrupt on primary GIC (see
+ below).
- cpu-offset : per-cpu offset within the distributor and cpu interface
regions, used when the GIC doesn't have banked registers. The offset is
@@ -57,3 +60,31 @@ Example:
<0xfff10100 0x100>;
};
+
+* GIC virtualization extensions (VGIC)
+
+For ARM cores that support the virtualization extensions, additional
+properties must be described (they only exist if the GIC is the
+primary interrupt controller).
+
+Required properties:
+
+- reg : Additional regions specifying the base physical address and
+ size of the VGIC registers. The first additional region is the GIC
+ virtual interface control register base and size. The 2nd additional
+ region is the GIC virtual cpu interface register base and size.
+
+- interrupts : VGIC maintainance interrupt.
+
+Example:
+
+ interrupt-controller@2c001000 {
+ compatible = "arm,cortex-a15-gic";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0x2c001000 0x1000>,
+ <0x2c002000 0x1000>,
+ <0x2c004000 0x2000>,
+ <0x2c006000 0x2000>;
+ interrupts = <1 9 0xf04>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/lpc32xx-mic.txt b/Documentation/devicetree/bindings/arm/lpc32xx-mic.txt
new file mode 100644
index 000000000000..539adca19e8f
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/lpc32xx-mic.txt
@@ -0,0 +1,38 @@
+* NXP LPC32xx Main Interrupt Controller
+ (MIC, including SIC1 and SIC2 secondary controllers)
+
+Required properties:
+- compatible: Should be "nxp,lpc3220-mic"
+- interrupt-controller: Identifies the node as an interrupt controller.
+- interrupt-parent: Empty for the interrupt controller itself
+- #interrupt-cells: The number of cells to define the interrupts. Should be 2.
+ The first cell is the IRQ number
+ The second cell is used to specify mode:
+ 1 = low-to-high edge triggered
+ 2 = high-to-low edge triggered
+ 4 = active high level-sensitive
+ 8 = active low level-sensitive
+ Default for internal sources should be set to 4 (active high).
+- reg: Should contain MIC registers location and length
+
+Examples:
+ /*
+ * MIC
+ */
+ mic: interrupt-controller@40008000 {
+ compatible = "nxp,lpc3220-mic";
+ interrupt-controller;
+ interrupt-parent;
+ #interrupt-cells = <2>;
+ reg = <0x40008000 0xC000>;
+ };
+
+ /*
+ * ADC
+ */
+ adc@40048000 {
+ compatible = "nxp,lpc3220-adc";
+ reg = <0x40048000 0x1000>;
+ interrupt-parent = <&mic>;
+ interrupts = <39 4>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/lpc32xx.txt b/Documentation/devicetree/bindings/arm/lpc32xx.txt
new file mode 100644
index 000000000000..56ec8ddc4a3b
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/lpc32xx.txt
@@ -0,0 +1,8 @@
+NXP LPC32xx Platforms Device Tree Bindings
+------------------------------------------
+
+Boards with the NXP LPC32xx SoC shall have the following properties:
+
+Required root node property:
+
+compatible: must be "nxp,lpc3220", "nxp,lpc3230", "nxp,lpc3240" or "nxp,lpc3250"
diff --git a/Documentation/devicetree/bindings/arm/mrvl/intc.txt b/Documentation/devicetree/bindings/arm/mrvl/intc.txt
new file mode 100644
index 000000000000..80b9a94d9a23
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mrvl/intc.txt
@@ -0,0 +1,40 @@
+* Marvell MMP Interrupt controller
+
+Required properties:
+- compatible : Should be "mrvl,mmp-intc", "mrvl,mmp2-intc" or
+ "mrvl,mmp2-mux-intc"
+- reg : Address and length of the register set of the interrupt controller.
+ If the interrupt controller is intc, address and length means the range
+ of the whold interrupt controller. If the interrupt controller is mux-intc,
+ address and length means one register. Since address of mux-intc is in the
+ range of intc. mux-intc is secondary interrupt controller.
+- reg-names : Name of the register set of the interrupt controller. It's
+ only required in mux-intc interrupt controller.
+- interrupts : Should be the port interrupt shared by mux interrupts. It's
+ only required in mux-intc interrupt controller.
+- interrupt-controller : Identifies the node as an interrupt controller.
+- #interrupt-cells : Specifies the number of cells needed to encode an
+ interrupt source.
+- mrvl,intc-nr-irqs : Specifies the number of interrupts in the interrupt
+ controller.
+- mrvl,clr-mfp-irq : Specifies the interrupt that needs to clear MFP edge
+ detection first.
+
+Example:
+ intc: interrupt-controller@d4282000 {
+ compatible = "mrvl,mmp2-intc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0xd4282000 0x1000>;
+ mrvl,intc-nr-irqs = <64>;
+ };
+
+ intcmux4@d4282150 {
+ compatible = "mrvl,mmp2-mux-intc";
+ interrupts = <4>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x150 0x4>, <0x168 0x4>;
+ reg-names = "mux status", "mux mask";
+ mrvl,intc-nr-irqs = <2>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/mrvl.txt b/Documentation/devicetree/bindings/arm/mrvl/mrvl.txt
index d8de933e9d81..117d741a2e4f 100644
--- a/Documentation/devicetree/bindings/arm/mrvl.txt
+++ b/Documentation/devicetree/bindings/arm/mrvl/mrvl.txt
@@ -4,3 +4,11 @@ Marvell Platforms Device Tree Bindings
PXA168 Aspenite Board
Required root node properties:
- compatible = "mrvl,pxa168-aspenite", "mrvl,pxa168";
+
+PXA910 DKB Board
+Required root node properties:
+ - compatible = "mrvl,pxa910-dkb";
+
+MMP2 Brownstone Board
+Required root node properties:
+ - compatible = "mrvl,mmp2-brownstone";
diff --git a/Documentation/devicetree/bindings/arm/mrvl/timer.txt b/Documentation/devicetree/bindings/arm/mrvl/timer.txt
new file mode 100644
index 000000000000..9a6e251462e7
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mrvl/timer.txt
@@ -0,0 +1,13 @@
+* Marvell MMP Timer controller
+
+Required properties:
+- compatible : Should be "mrvl,mmp-timer".
+- reg : Address and length of the register set of timer controller.
+- interrupts : Should be the interrupt number.
+
+Example:
+ timer0: timer@d4014000 {
+ compatible = "mrvl,mmp-timer";
+ reg = <0xd4014000 0x100>;
+ interrupts = <13>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/spear.txt b/Documentation/devicetree/bindings/arm/spear.txt
index f8e54f092328..aa5f355cc947 100644
--- a/Documentation/devicetree/bindings/arm/spear.txt
+++ b/Documentation/devicetree/bindings/arm/spear.txt
@@ -6,3 +6,21 @@ Boards with the ST SPEAr600 SoC shall have the following properties:
Required root node property:
compatible = "st,spear600";
+
+Boards with the ST SPEAr300 SoC shall have the following properties:
+
+Required root node property:
+
+compatible = "st,spear300";
+
+Boards with the ST SPEAr310 SoC shall have the following properties:
+
+Required root node property:
+
+compatible = "st,spear310";
+
+Boards with the ST SPEAr320 SoC shall have the following properties:
+
+Required root node property:
+
+compatible = "st,spear320";
diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-mc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-mc.txt
new file mode 100644
index 000000000000..c25a0a55151d
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-mc.txt
@@ -0,0 +1,16 @@
+NVIDIA Tegra20 MC(Memory Controller)
+
+Required properties:
+- compatible : "nvidia,tegra20-mc"
+- reg : Should contain 2 register ranges(address and length); see the
+ example below. Note that the MC registers are interleaved with the
+ GART registers, and hence must be represented as multiple ranges.
+- interrupts : Should contain MC General interrupt.
+
+Example:
+ mc {
+ compatible = "nvidia,tegra20-mc";
+ reg = <0x7000f000 0x024
+ 0x7000f03c 0x3c4>;
+ interrupts = <0 77 0x04>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra30-mc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra30-mc.txt
new file mode 100644
index 000000000000..e47e73f612f4
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra30-mc.txt
@@ -0,0 +1,18 @@
+NVIDIA Tegra30 MC(Memory Controller)
+
+Required properties:
+- compatible : "nvidia,tegra30-mc"
+- reg : Should contain 4 register ranges(address and length); see the
+ example below. Note that the MC registers are interleaved with the
+ SMMU registers, and hence must be represented as multiple ranges.
+- interrupts : Should contain MC General interrupt.
+
+Example:
+ mc {
+ compatible = "nvidia,tegra30-mc";
+ reg = <0x7000f000 0x010
+ 0x7000f03c 0x1b4
+ 0x7000f200 0x028
+ 0x7000f284 0x17c>;
+ interrupts = <0 77 0x04>;
+ };
diff --git a/Documentation/devicetree/bindings/gpio/gpio-nmk.txt b/Documentation/devicetree/bindings/gpio/gpio-nmk.txt
new file mode 100644
index 000000000000..ee87467ad8d6
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-nmk.txt
@@ -0,0 +1,31 @@
+Nomadik GPIO controller
+
+Required properties:
+- compatible : Should be "st,nomadik-gpio".
+- reg : Physical base address and length of the controller's registers.
+- interrupts : The interrupt outputs from the controller.
+- #gpio-cells : Should be two:
+ The first cell is the pin number.
+ The second cell is used to specify optional parameters:
+ - bits[3:0] trigger type and level flags:
+ 1 = low-to-high edge triggered.
+ 2 = high-to-low edge triggered.
+ 4 = active high level-sensitive.
+ 8 = active low level-sensitive.
+- gpio-controller : Marks the device node as a GPIO controller.
+- interrupt-controller : Marks the device node as an interrupt controller.
+- gpio-bank : Specifies which bank a controller owns.
+- st,supports-sleepmode : Specifies whether controller can sleep or not
+
+Example:
+
+ gpio1: gpio@8012e080 {
+ compatible = "st,nomadik-gpio";
+ reg = <0x8012e080 0x80>;
+ interrupts = <0 120 0x4>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ supports-sleepmode;
+ gpio-bank = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/gpio/gpio_lpc32xx.txt b/Documentation/devicetree/bindings/gpio/gpio_lpc32xx.txt
new file mode 100644
index 000000000000..49819367a011
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio_lpc32xx.txt
@@ -0,0 +1,43 @@
+NXP LPC32xx SoC GPIO controller
+
+Required properties:
+- compatible: must be "nxp,lpc3220-gpio"
+- reg: Physical base address and length of the controller's registers.
+- gpio-controller: Marks the device node as a GPIO controller.
+- #gpio-cells: Should be 3:
+ 1) bank:
+ 0: GPIO P0
+ 1: GPIO P1
+ 2: GPIO P2
+ 3: GPIO P3
+ 4: GPI P3
+ 5: GPO P3
+ 2) pin number
+ 3) optional parameters:
+ - bit 0 specifies polarity (0 for normal, 1 for inverted)
+- reg: Index of the GPIO group
+
+Example:
+
+ gpio: gpio@40028000 {
+ compatible = "nxp,lpc3220-gpio";
+ reg = <0x40028000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <3>; /* bank, pin, flags */
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ led0 {
+ gpios = <&gpio 5 1 1>; /* GPO_P3 1, active low */
+ linux,default-trigger = "heartbeat";
+ default-state = "off";
+ };
+
+ led1 {
+ gpios = <&gpio 5 14 1>; /* GPO_P3 14, active low */
+ linux,default-trigger = "timer";
+ default-state = "off";
+ };
+ };
diff --git a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt
index 1e34cfe5ebea..05428f39d9ac 100644
--- a/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt
+++ b/Documentation/devicetree/bindings/gpio/mrvl-gpio.txt
@@ -3,19 +3,25 @@
Required properties:
- compatible : Should be "mrvl,pxa-gpio" or "mrvl,mmp-gpio"
- reg : Address and length of the register set for the device
-- interrupts : Should be the port interrupt shared by all gpio pins, if
-- interrupt-name : Should be the name of irq resource.
- one number.
+- interrupts : Should be the port interrupt shared by all gpio pins.
+ There're three gpio interrupts in arch-pxa, and they're gpio0,
+ gpio1 and gpio_mux. There're only one gpio interrupt in arch-mmp,
+ gpio_mux.
+- interrupt-name : Should be the name of irq resource. Each interrupt
+ binds its interrupt-name.
+- interrupt-controller : Identifies the node as an interrupt controller.
+- #interrupt-cells: Specifies the number of cells needed to encode an
+ interrupt source.
- gpio-controller : Marks the device node as a gpio controller.
- #gpio-cells : Should be one. It is the pin number.
Example:
gpio: gpio@d4019000 {
- compatible = "mrvl,mmp-gpio", "mrvl,pxa-gpio";
+ compatible = "mrvl,mmp-gpio";
reg = <0xd4019000 0x1000>;
- interrupts = <49>, <17>, <18>;
- interrupt-name = "gpio_mux", "gpio0", "gpio1";
+ interrupts = <49>;
+ interrupt-name = "gpio_mux";
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
diff --git a/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt b/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt
index 071eb3caae91..b891ee218354 100644
--- a/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt
+++ b/Documentation/devicetree/bindings/i2c/mrvl-i2c.txt
@@ -3,34 +3,31 @@
Required properties :
- reg : Offset and length of the register set for the device
- - compatible : should be "mrvl,mmp-twsi" where CHIP is the name of a
+ - compatible : should be "mrvl,mmp-twsi" where mmp is the name of a
compatible processor, e.g. pxa168, pxa910, mmp2, mmp3.
For the pxa2xx/pxa3xx, an additional node "mrvl,pxa-i2c" is required
as shown in the example below.
Recommended properties :
- - interrupts : <a b> where a is the interrupt number and b is a
- field that represents an encoding of the sense and level
- information for the interrupt. This should be encoded based on
- the information in section 2) depending on the type of interrupt
- controller you have.
+ - interrupts : the interrupt number
- interrupt-parent : the phandle for the interrupt controller that
- services interrupts for this device.
+ services interrupts for this device. If the parent is the default
+ interrupt controller in device tree, it could be ignored.
- mrvl,i2c-polling : Disable interrupt of i2c controller. Polling
status register of i2c controller instead.
- mrvl,i2c-fast-mode : Enable fast mode of i2c controller.
Examples:
twsi1: i2c@d4011000 {
- compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c";
+ compatible = "mrvl,mmp-twsi";
reg = <0xd4011000 0x1000>;
interrupts = <7>;
mrvl,i2c-fast-mode;
};
twsi2: i2c@d4025000 {
- compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c";
+ compatible = "mrvl,mmp-twsi";
reg = <0xd4025000 0x1000>;
interrupts = <58>;
};
diff --git a/Documentation/devicetree/bindings/i2c/pnx.txt b/Documentation/devicetree/bindings/i2c/pnx.txt
new file mode 100644
index 000000000000..fe98ada33ee4
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/pnx.txt
@@ -0,0 +1,36 @@
+* NXP PNX I2C Controller
+
+Required properties:
+
+ - reg: Offset and length of the register set for the device
+ - compatible: should be "nxp,pnx-i2c"
+ - interrupts: configure one interrupt line
+ - #address-cells: always 1 (for i2c addresses)
+ - #size-cells: always 0
+ - interrupt-parent: the phandle for the interrupt controller that
+ services interrupts for this device.
+
+Optional properties:
+
+ - clock-frequency: desired I2C bus clock frequency in Hz, Default: 100000 Hz
+
+Examples:
+
+ i2c1: i2c@400a0000 {
+ compatible = "nxp,pnx-i2c";
+ reg = <0x400a0000 0x100>;
+ interrupt-parent = <&mic>;
+ interrupts = <51 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ i2c2: i2c@400a8000 {
+ compatible = "nxp,pnx-i2c";
+ reg = <0x400a8000 0x100>;
+ interrupt-parent = <&mic>;
+ interrupts = <50 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-frequency = <100000>;
+ };
diff --git a/Documentation/devicetree/bindings/input/spear-keyboard.txt b/Documentation/devicetree/bindings/input/spear-keyboard.txt
new file mode 100644
index 000000000000..4a846d26da23
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/spear-keyboard.txt
@@ -0,0 +1,20 @@
+* SPEAr keyboard controller
+
+Required properties:
+- compatible: "st,spear300-kbd"
+
+Optional properties, in addition to those specified by the shared
+matrix-keyboard bindings:
+- autorepeat: bool: enables key autorepeat
+- st,mode: keyboard mode: 0 - 9x9, 1 - 6x6, 2 - 2x2
+
+Example:
+
+kbd@fc400000 {
+ compatible = "st,spear300-kbd";
+ reg = <0xfc400000 0x100>;
+ linux,keymap = < 0x00030012
+ 0x0102003a >;
+ autorepeat;
+ st,mode = <0>;
+};
diff --git a/Documentation/devicetree/bindings/input/touchscreen/lpc32xx-tsc.txt b/Documentation/devicetree/bindings/input/touchscreen/lpc32xx-tsc.txt
new file mode 100644
index 000000000000..41cbf4b7a670
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/lpc32xx-tsc.txt
@@ -0,0 +1,16 @@
+* NXP LPC32xx SoC Touchscreen Controller (TSC)
+
+Required properties:
+- compatible: must be "nxp,lpc3220-tsc"
+- reg: physical base address of the controller and length of memory mapped
+ region.
+- interrupts: The TSC/ADC interrupt
+
+Example:
+
+ tsc@40048000 {
+ compatible = "nxp,lpc3220-tsc";
+ reg = <0x40048000 0x1000>;
+ interrupt-parent = <&mic>;
+ interrupts = <39 0>;
+ };
diff --git a/Documentation/devicetree/bindings/input/twl6040-vibra.txt b/Documentation/devicetree/bindings/input/twl6040-vibra.txt
new file mode 100644
index 000000000000..5b1918b818fb
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/twl6040-vibra.txt
@@ -0,0 +1,37 @@
+Vibra driver for the twl6040 family
+
+The vibra driver is a child of the twl6040 MFD dirver.
+Documentation/devicetree/bindings/mfd/twl6040.txt
+
+Required properties:
+- compatible : Must be "ti,twl6040-vibra";
+- interrupts: 4, Vibra overcurrent interrupt
+- vddvibl-supply: Regulator supplying the left vibra motor
+- vddvibr-supply: Regulator supplying the right vibra motor
+- vibldrv_res: Board specific left driver resistance
+- vibrdrv_res: Board specific right driver resistance
+- viblmotor_res: Board specific left motor resistance
+- vibrmotor_res: Board specific right motor resistance
+
+Optional properties:
+- vddvibl_uV: If the vddvibl default voltage need to be changed
+- vddvibr_uV: If the vddvibr default voltage need to be changed
+
+Example:
+/*
+ * 8-channel high quality low-power audio codec
+ * http://www.ti.com/lit/ds/symlink/twl6040.pdf
+ */
+twl6040: twl6040@4b {
+ ...
+ twl6040_vibra: twl6040@1 {
+ compatible = "ti,twl6040-vibra";
+ interrupts = <4>;
+ vddvibl-supply = <&vbat>;
+ vddvibr-supply = <&vbat>;
+ vibldrv_res = <8>;
+ vibrdrv_res = <3>;
+ viblmotor_res = <10>;
+ vibrmotor_res = <10>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/misc/bmp085.txt b/Documentation/devicetree/bindings/misc/bmp085.txt
new file mode 100644
index 000000000000..91dfda2e4e11
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/bmp085.txt
@@ -0,0 +1,20 @@
+BMP085/BMP18x digital pressure sensors
+
+Required properties:
+- compatible: bosch,bmp085
+
+Optional properties:
+- chip-id: configurable chip id for non-default chip revisions
+- temp-measurement-period: temperature measurement period (milliseconds)
+- default-oversampling: default oversampling value to be used at startup,
+ value range is 0-3 with rising sensitivity.
+
+Example:
+
+pressure@77 {
+ compatible = "bosch,bmp085";
+ reg = <0x77>;
+ chip-id = <10>;
+ temp-measurement-period = <100>;
+ default-oversampling = <2>;
+};
diff --git a/Documentation/devicetree/bindings/mtd/orion-nand.txt b/Documentation/devicetree/bindings/mtd/orion-nand.txt
new file mode 100644
index 000000000000..b2356b7d2fa4
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/orion-nand.txt
@@ -0,0 +1,50 @@
+NAND support for Marvell Orion SoC platforms
+
+Required properties:
+- compatible : "mrvl,orion-nand".
+- reg : Base physical address of the NAND and length of memory mapped
+ region
+
+Optional properties:
+- cle : Address line number connected to CLE. Default is 0
+- ale : Address line number connected to ALE. Default is 1
+- bank-width : Width in bytes of the device. Default is 1
+- chip-delay : Chip dependent delay for transferring data from array to read
+ registers in usecs
+
+The device tree may optionally contain sub-nodes describing partitions of the
+address space. See partition.txt for more detail.
+
+Example:
+
+nand@f4000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ cle = <0>;
+ ale = <1>;
+ bank-width = <1>;
+ chip-delay = <25>;
+ compatible = "mrvl,orion-nand";
+ reg = <0xf4000000 0x400>;
+
+ partition@0 {
+ label = "u-boot";
+ reg = <0x0000000 0x100000>;
+ read-only;
+ };
+
+ partition@100000 {
+ label = "uImage";
+ reg = <0x0100000 0x200000>;
+ };
+
+ partition@300000 {
+ label = "dtb";
+ reg = <0x0300000 0x100000>;
+ };
+
+ partition@400000 {
+ label = "root";
+ reg = <0x0400000 0x7d00000>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
index 1ad80d5865a9..f31b686d4556 100644
--- a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
+++ b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
@@ -1,4 +1,4 @@
-Flexcan CAN contoller on Freescale's ARM and PowerPC system-on-a-chip (SOC).
+Flexcan CAN controller on Freescale's ARM and PowerPC system-on-a-chip (SOC).
Required properties:
diff --git a/Documentation/devicetree/bindings/net/lpc-eth.txt b/Documentation/devicetree/bindings/net/lpc-eth.txt
new file mode 100644
index 000000000000..585021acd178
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/lpc-eth.txt
@@ -0,0 +1,24 @@
+* NXP LPC32xx SoC Ethernet Controller
+
+Required properties:
+- compatible: Should be "nxp,lpc-eth"
+- reg: Address and length of the register set for the device
+- interrupts: Should contain ethernet controller interrupt
+
+Optional properties:
+- phy-mode: String, operation mode of the PHY interface.
+ Supported values are: "mii", "rmii" (default)
+- use-iram: Use LPC32xx internal SRAM (IRAM) for DMA buffering
+- local-mac-address : 6 bytes, mac address
+
+Example:
+
+ mac: ethernet@31060000 {
+ compatible = "nxp,lpc-eth";
+ reg = <0x31060000 0x1000>;
+ interrupt-parent = <&mic>;
+ interrupts = <29 0>;
+
+ phy-mode = "rmii";
+ use-iram;
+ };
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl_spear.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl_spear.txt
new file mode 100644
index 000000000000..3664d37e6799
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl_spear.txt
@@ -0,0 +1,108 @@
+ST Microelectronics, SPEAr pinmux controller
+
+Required properties:
+- compatible : "st,spear300-pinmux"
+ : "st,spear310-pinmux"
+ : "st,spear320-pinmux"
+- reg : Address range of the pinctrl registers
+- st,pinmux-mode: Mandatory for SPEAr300 and SPEAr320 and invalid for others.
+ - Its values for SPEAr300:
+ - NAND_MODE : <0>
+ - NOR_MODE : <1>
+ - PHOTO_FRAME_MODE : <2>
+ - LEND_IP_PHONE_MODE : <3>
+ - HEND_IP_PHONE_MODE : <4>
+ - LEND_WIFI_PHONE_MODE : <5>
+ - HEND_WIFI_PHONE_MODE : <6>
+ - ATA_PABX_WI2S_MODE : <7>
+ - ATA_PABX_I2S_MODE : <8>
+ - CAML_LCDW_MODE : <9>
+ - CAMU_LCD_MODE : <10>
+ - CAMU_WLCD_MODE : <11>
+ - CAML_LCD_MODE : <12>
+ - Its values for SPEAr320:
+ - AUTO_NET_SMII_MODE : <0>
+ - AUTO_NET_MII_MODE : <1>
+ - AUTO_EXP_MODE : <2>
+ - SMALL_PRINTERS_MODE : <3>
+ - EXTENDED_MODE : <4>
+
+Please refer to pinctrl-bindings.txt in this directory for details of the common
+pinctrl bindings used by client devices.
+
+SPEAr's pinmux nodes act as a container for an abitrary number of subnodes. Each
+of these subnodes represents muxing for a pin, a group, or a list of pins or
+groups.
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content.
+
+Required subnode-properties:
+- st,pins : An array of strings. Each string contains the name of a pin or
+ group.
+- st,function: A string containing the name of the function to mux to the pin or
+ group. See the SPEAr's TRM to determine which are valid for each pin or group.
+
+ Valid values for group and function names can be found from looking at the
+ group and function arrays in driver files:
+ drivers/pinctrl/spear/pinctrl-spear3*0.c
+
+Valid values for group names are:
+For All SPEAr3xx machines:
+ "firda_grp", "i2c0_grp", "ssp_cs_grp", "ssp0_grp", "mii0_grp",
+ "gpio0_pin0_grp", "gpio0_pin1_grp", "gpio0_pin2_grp", "gpio0_pin3_grp",
+ "gpio0_pin4_grp", "gpio0_pin5_grp", "uart0_ext_grp", "uart0_grp",
+ "timer_0_1_grp", timer_0_1_pins, "timer_2_3_grp"
+
+For SPEAr300 machines:
+ "fsmc_2chips_grp", "fsmc_4chips_grp", "clcd_lcdmode_grp",
+ "clcd_pfmode_grp", "tdm_grp", "i2c_clk_grp_grp", "caml_grp", "camu_grp",
+ "dac_grp", "i2s_grp", "sdhci_4bit_grp", "sdhci_8bit_grp",
+ "gpio1_0_to_3_grp", "gpio1_4_to_7_grp"
+
+For SPEAr310 machines:
+ "emi_cs_0_to_5_grp", "uart1_grp", "uart2_grp", "uart3_grp", "uart4_grp",
+ "uart5_grp", "fsmc_grp", "rs485_0_grp", "rs485_1_grp", "tdm_grp"
+
+For SPEAr320 machines:
+ "clcd_grp", "emi_grp", "fsmc_8bit_grp", "fsmc_16bit_grp", "spp_grp",
+ "sdhci_led_grp", "sdhci_cd_12_grp", "sdhci_cd_51_grp", "i2s_grp",
+ "uart1_grp", "uart1_modem_2_to_7_grp", "uart1_modem_31_to_36_grp",
+ "uart1_modem_34_to_45_grp", "uart1_modem_80_to_85_grp", "uart2_grp",
+ "uart3_8_9_grp", "uart3_15_16_grp", "uart3_41_42_grp",
+ "uart3_52_53_grp", "uart3_73_74_grp", "uart3_94_95_grp",
+ "uart3_98_99_grp", "uart4_6_7_grp", "uart4_13_14_grp",
+ "uart4_39_40_grp", "uart4_71_72_grp", "uart4_92_93_grp",
+ "uart4_100_101_grp", "uart5_4_5_grp", "uart5_37_38_grp",
+ "uart5_69_70_grp", "uart5_90_91_grp", "uart6_2_3_grp",
+ "uart6_88_89_grp", "rs485_grp", "touchscreen_grp", "can0_grp",
+ "can1_grp", "pwm0_1_pin_8_9_grp", "pwm0_1_pin_14_15_grp",
+ "pwm0_1_pin_30_31_grp", "pwm0_1_pin_37_38_grp", "pwm0_1_pin_42_43_grp",
+ "pwm0_1_pin_59_60_grp", "pwm0_1_pin_88_89_grp", "pwm2_pin_7_grp",
+ "pwm2_pin_13_grp", "pwm2_pin_29_grp", "pwm2_pin_34_grp",
+ "pwm2_pin_41_grp", "pwm2_pin_58_grp", "pwm2_pin_87_grp",
+ "pwm3_pin_6_grp", "pwm3_pin_12_grp", "pwm3_pin_28_grp",
+ "pwm3_pin_40_grp", "pwm3_pin_57_grp", "pwm3_pin_86_grp",
+ "ssp1_17_20_grp", "ssp1_36_39_grp", "ssp1_48_51_grp", "ssp1_65_68_grp",
+ "ssp1_94_97_grp", "ssp2_13_16_grp", "ssp2_32_35_grp", "ssp2_44_47_grp",
+ "ssp2_61_64_grp", "ssp2_90_93_grp", "mii2_grp", "smii0_1_grp",
+ "rmii0_1_grp", "i2c1_8_9_grp", "i2c1_98_99_grp", "i2c2_0_1_grp",
+ "i2c2_2_3_grp", "i2c2_19_20_grp", "i2c2_75_76_grp", "i2c2_96_97_grp"
+
+Valid values for function names are:
+For All SPEAr3xx machines:
+ "firda", "i2c0", "ssp_cs", "ssp0", "mii0", "gpio0", "uart0_ext",
+ "uart0", "timer_0_1", "timer_2_3"
+
+For SPEAr300 machines:
+ "fsmc", "clcd", "tdm", "i2c1", "cam", "dac", "i2s", "sdhci", "gpio1"
+
+For SPEAr310 machines:
+ "emi", "uart1", "uart2", "uart3", "uart4", "uart5", "fsmc", "rs485_0",
+ "rs485_1", "tdm"
+
+For SPEAr320 machines:
+ "clcd", "emi", "fsmc", "spp", "sdhci", "i2s", "uart1", "uart1_modem",
+ "uart2", "uart3", "uart4", "uart5", "uart6", "rs485", "touchscreen",
+ "can0", "can1", "pwm0_1", "pwm2", "pwm3", "ssp1", "ssp2", "mii2",
+ "mii0_1", "i2c1", "i2c2"
diff --git a/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt b/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt
new file mode 100644
index 000000000000..e4acdd891e49
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt
@@ -0,0 +1,49 @@
+Freescale i.MX audio complex with SGTL5000 codec
+
+Required properties:
+- compatible : "fsl,imx-audio-sgtl5000"
+- model : The user-visible name of this sound complex
+- ssi-controller : The phandle of the i.MX SSI controller
+- audio-codec : The phandle of the SGTL5000 audio codec
+- audio-routing : A list of the connections between audio components.
+ Each entry is a pair of strings, the first being the connection's sink,
+ the second being the connection's source. Valid names could be power
+ supplies, SGTL5000 pins, and the jacks on the board:
+
+ Power supplies:
+ * Mic Bias
+
+ SGTL5000 pins:
+ * MIC_IN
+ * LINE_IN
+ * HP_OUT
+ * LINE_OUT
+
+ Board connectors:
+ * Mic Jack
+ * Line In Jack
+ * Headphone Jack
+ * Line Out Jack
+ * Ext Spk
+
+- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX)
+- mux-ext-port : The external port of the i.MX audio muxer
+
+Note: The AUDMUX port numbering should start at 1, which is consistent with
+hardware manual.
+
+Example:
+
+sound {
+ compatible = "fsl,imx51-babbage-sgtl5000",
+ "fsl,imx-audio-sgtl5000";
+ model = "imx51-babbage-sgtl5000";
+ ssi-controller = <&ssi1>;
+ audio-codec = <&sgtl5000>;
+ audio-routing =
+ "MIC_IN", "Mic Jack",
+ "Mic Jack", "Mic Bias",
+ "Headphone Jack", "HP_OUT";
+ mux-int-port = <1>;
+ mux-ext-port = <3>;
+};
diff --git a/Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt b/Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt
new file mode 100644
index 000000000000..601c518eddaa
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mxs-audio-sgtl5000.txt
@@ -0,0 +1,17 @@
+* Freescale MXS audio complex with SGTL5000 codec
+
+Required properties:
+- compatible: "fsl,mxs-audio-sgtl5000"
+- model: The user-visible name of this sound complex
+- saif-controllers: The phandle list of the MXS SAIF controller
+- audio-codec: The phandle of the SGTL5000 audio codec
+
+Example:
+
+sound {
+ compatible = "fsl,imx28-evk-sgtl5000",
+ "fsl,mxs-audio-sgtl5000";
+ model = "imx28-evk-sgtl5000";
+ saif-controllers = <&saif0 &saif1>;
+ audio-codec = <&sgtl5000>;
+};
diff --git a/Documentation/devicetree/bindings/sound/mxs-saif.txt b/Documentation/devicetree/bindings/sound/mxs-saif.txt
new file mode 100644
index 000000000000..c37ba6143d9b
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/mxs-saif.txt
@@ -0,0 +1,36 @@
+* Freescale MXS Serial Audio Interface (SAIF)
+
+Required properties:
+- compatible: Should be "fsl,<chip>-saif"
+- reg: Should contain registers location and length
+- interrupts: Should contain ERROR and DMA interrupts
+- fsl,saif-dma-channel: APBX DMA channel for the SAIF
+
+Optional properties:
+- fsl,saif-master: phandle to the master SAIF. It's only required for
+ the slave SAIF.
+
+Note: Each SAIF controller should have an alias correctly numbered
+in "aliases" node.
+
+Example:
+
+aliases {
+ saif0 = &saif0;
+ saif1 = &saif1;
+};
+
+saif0: saif@80042000 {
+ compatible = "fsl,imx28-saif";
+ reg = <0x80042000 2000>;
+ interrupts = <59 80>;
+ fsl,saif-dma-channel = <4>;
+};
+
+saif1: saif@80046000 {
+ compatible = "fsl,imx28-saif";
+ reg = <0x80046000 2000>;
+ interrupts = <58 81>;
+ fsl,saif-dma-channel = <5>;
+ fsl,saif-master = <&saif0>;
+};
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt
new file mode 100644
index 000000000000..1ac7b1642186
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt
@@ -0,0 +1,32 @@
+NVIDIA Tegra30 AHUB (Audio Hub)
+
+Required properties:
+- compatible : "nvidia,tegra30-ahub"
+- reg : Should contain the register physical address and length for each of
+ the AHUB's APBIF registers and the AHUB's own registers.
+- interrupts : Should contain AHUB interrupt
+- nvidia,dma-request-selector : The Tegra DMA controller's phandle and
+ request selector for the first APBIF channel.
+- ranges : The bus address mapping for the configlink register bus.
+ Can be empty since the mapping is 1:1.
+- #address-cells : For the configlink bus. Should be <1>;
+- #size-cells : For the configlink bus. Should be <1>.
+
+AHUB client modules need to specify the IDs of their CIFs (Client InterFaces).
+For RX CIFs, the numbers indicate the register number within AHUB routing
+register space (APBIF 0..3 RX, I2S 0..5 RX, DAM 0..2 RX 0..1, SPDIF RX 0..1).
+For TX CIFs, the numbers indicate the bit position within the AHUB routing
+registers (APBIF 0..3 TX, I2S 0..5 TX, DAM 0..2 TX, SPDIF TX 0..1).
+
+Example:
+
+ahub@70080000 {
+ compatible = "nvidia,tegra30-ahub";
+ reg = <0x70080000 0x200 0x70080200 0x100>;
+ interrupts = < 0 103 0x04 >;
+ nvidia,dma-request-selector = <&apbdma 1>;
+
+ ranges;
+ #address-cells = <1>;
+ #size-cells = <1>;
+};
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt
new file mode 100644
index 000000000000..dfa6c037124a
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt
@@ -0,0 +1,15 @@
+NVIDIA Tegra30 I2S controller
+
+Required properties:
+- compatible : "nvidia,tegra30-i2s"
+- reg : Should contain I2S registers location and length
+- nvidia,ahub-cif-ids : The list of AHUB CIF IDs for this port, rx (playback)
+ first, tx (capture) second. See nvidia,tegra30-ahub.txt for values.
+
+Example:
+
+i2s@70002800 {
+ compatible = "nvidia,tegra30-i2s";
+ reg = <0x70080300 0x100>;
+ nvidia,ahub-cif-ids = <4 4>;
+};
diff --git a/Documentation/devicetree/bindings/sound/tegra-audio-trimslice.txt b/Documentation/devicetree/bindings/sound/tegra-audio-trimslice.txt
new file mode 100644
index 000000000000..04b14cfb1f16
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/tegra-audio-trimslice.txt
@@ -0,0 +1,14 @@
+NVIDIA Tegra audio complex for TrimSlice
+
+Required properties:
+- compatible : "nvidia,tegra-audio-trimslice"
+- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller
+- nvidia,audio-codec : The phandle of the WM8903 audio codec
+
+Example:
+
+sound {
+ compatible = "nvidia,tegra-audio-trimslice";
+ nvidia,i2s-controller = <&tegra_i2s1>;
+ nvidia,audio-codec = <&codec>;
+};
diff --git a/Documentation/devicetree/bindings/sound/tegra-audio-wm8753.txt b/Documentation/devicetree/bindings/sound/tegra-audio-wm8753.txt
new file mode 100644
index 000000000000..c4dd39ce6165
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/tegra-audio-wm8753.txt
@@ -0,0 +1,54 @@
+NVIDIA Tegra audio complex
+
+Required properties:
+- compatible : "nvidia,tegra-audio-wm8753"
+- nvidia,model : The user-visible name of this sound complex.
+- nvidia,audio-routing : A list of the connections between audio components.
+ Each entry is a pair of strings, the first being the connection's sink,
+ the second being the connection's source. Valid names for sources and
+ sinks are the WM8753's pins, and the jacks on the board:
+
+ WM8753 pins:
+
+ * LOUT1
+ * LOUT2
+ * ROUT1
+ * ROUT2
+ * MONO1
+ * MONO2
+ * OUT3
+ * OUT4
+ * LINE1
+ * LINE2
+ * RXP
+ * RXN
+ * ACIN
+ * ACOP
+ * MIC1N
+ * MIC1
+ * MIC2N
+ * MIC2
+ * Mic Bias
+
+ Board connectors:
+
+ * Headphone Jack
+ * Mic Jack
+
+- nvidia,i2s-controller : The phandle of the Tegra I2S1 controller
+- nvidia,audio-codec : The phandle of the WM8753 audio codec
+Example:
+
+sound {
+ compatible = "nvidia,tegra-audio-wm8753-whistler",
+ "nvidia,tegra-audio-wm8753"
+ nvidia,model = "tegra-wm8753-harmony";
+
+ nvidia,audio-routing =
+ "Headphone Jack", "LOUT1",
+ "Headphone Jack", "ROUT1";
+
+ nvidia,i2s-controller = <&i2s1>;
+ nvidia,audio-codec = <&wm8753>;
+};
+
diff --git a/Documentation/devicetree/bindings/staging/iio/adc/lpc32xx-adc.txt b/Documentation/devicetree/bindings/staging/iio/adc/lpc32xx-adc.txt
new file mode 100644
index 000000000000..b3629d3a9adf
--- /dev/null
+++ b/Documentation/devicetree/bindings/staging/iio/adc/lpc32xx-adc.txt
@@ -0,0 +1,16 @@
+* NXP LPC32xx SoC ADC controller
+
+Required properties:
+- compatible: must be "nxp,lpc3220-adc"
+- reg: physical base address of the controller and length of memory mapped
+ region.
+- interrupts: The ADC interrupt
+
+Example:
+
+ adc@40048000 {
+ compatible = "nxp,lpc3220-adc";
+ reg = <0x40048000 0x1000>;
+ interrupt-parent = <&mic>;
+ interrupts = <39 0>;
+ };
diff --git a/Documentation/devicetree/bindings/staging/iio/adc/spear-adc.txt b/Documentation/devicetree/bindings/staging/iio/adc/spear-adc.txt
new file mode 100644
index 000000000000..02ea23a63f20
--- /dev/null
+++ b/Documentation/devicetree/bindings/staging/iio/adc/spear-adc.txt
@@ -0,0 +1,26 @@
+* ST SPEAr ADC device driver
+
+Required properties:
+- compatible: Should be "st,spear600-adc"
+- reg: Address and length of the register set for the device
+- interrupt-parent: Should be the phandle for the interrupt controller
+ that services interrupts for this device
+- interrupts: Should contain the ADC interrupt
+- sampling-frequency: Default sampling frequency
+
+Optional properties:
+- vref-external: External voltage reference in milli-volts. If omitted
+ the internal voltage reference will be used.
+- average-samples: Number of samples to generate an average value. If
+ omitted, single data conversion will be used.
+
+Examples:
+
+ adc: adc@d8200000 {
+ compatible = "st,spear600-adc";
+ reg = <0xd8200000 0x1000>;
+ interrupt-parent = <&vic1>;
+ interrupts = <6>;
+ sampling-frequency = <5000000>;
+ vref-external = <2500>; /* 2.5V VRef */
+ };
diff --git a/Documentation/devicetree/bindings/usb/isp1301.txt b/Documentation/devicetree/bindings/usb/isp1301.txt
new file mode 100644
index 000000000000..5405d99d9aaa
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/isp1301.txt
@@ -0,0 +1,25 @@
+* NXP ISP1301 USB transceiver
+
+Required properties:
+- compatible: must be "nxp,isp1301"
+- reg: I2C address of the ISP1301 device
+
+Optional properties of devices using ISP1301:
+- transceiver: phandle of isp1301 - this helps the ISP1301 driver to find the
+ ISP1301 instance associated with the respective USB driver
+
+Example:
+
+ isp1301: usb-transceiver@2c {
+ compatible = "nxp,isp1301";
+ reg = <0x2c>;
+ };
+
+ usbd@31020000 {
+ compatible = "nxp,lpc3220-udc";
+ reg = <0x31020000 0x300>;
+ interrupt-parent = <&mic>;
+ interrupts = <0x3d 0>, <0x3e 0>, <0x3c 0>, <0x3a 0>;
+ transceiver = <&isp1301>;
+ status = "okay";
+ };
diff --git a/Documentation/devicetree/bindings/usb/lpc32xx-udc.txt b/Documentation/devicetree/bindings/usb/lpc32xx-udc.txt
new file mode 100644
index 000000000000..29f12a533f66
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/lpc32xx-udc.txt
@@ -0,0 +1,28 @@
+* NXP LPC32xx SoC USB Device Controller (UDC)
+
+Required properties:
+- compatible: Must be "nxp,lpc3220-udc"
+- reg: Physical base address of the controller and length of memory mapped
+ region.
+- interrupts: The USB interrupts:
+ * USB Device Low Priority Interrupt
+ * USB Device High Priority Interrupt
+ * USB Device DMA Interrupt
+ * External USB Transceiver Interrupt (OTG ATX)
+- transceiver: phandle of the associated ISP1301 device - this is necessary for
+ the UDC controller for connecting to the USB physical layer
+
+Example:
+
+ isp1301: usb-transceiver@2c {
+ compatible = "nxp,isp1301";
+ reg = <0x2c>;
+ };
+
+ usbd@31020000 {
+ compatible = "nxp,lpc3220-udc";
+ reg = <0x31020000 0x300>;
+ interrupt-parent = <&mic>;
+ interrupts = <0x3d 0>, <0x3e 0>, <0x3c 0>, <0x3a 0>;
+ transceiver = <&isp1301>;
+ };
diff --git a/Documentation/devicetree/bindings/usb/ohci-nxp.txt b/Documentation/devicetree/bindings/usb/ohci-nxp.txt
new file mode 100644
index 000000000000..71e28c1017ed
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/ohci-nxp.txt
@@ -0,0 +1,24 @@
+* OHCI controller, NXP ohci-nxp variant
+
+Required properties:
+- compatible: must be "nxp,ohci-nxp"
+- reg: physical base address of the controller and length of memory mapped
+ region.
+- interrupts: The OHCI interrupt
+- transceiver: phandle of the associated ISP1301 device - this is necessary for
+ the UDC controller for connecting to the USB physical layer
+
+Example (LPC32xx):
+
+ isp1301: usb-transceiver@2c {
+ compatible = "nxp,isp1301";
+ reg = <0x2c>;
+ };
+
+ ohci@31020000 {
+ compatible = "nxp,ohci-nxp";
+ reg = <0x31020000 0x300>;
+ interrupt-parent = <&mic>;
+ interrupts = <0x3b 0>;
+ transceiver = <&isp1301>;
+ };
diff --git a/Documentation/devicetree/bindings/usb/spear-usb.txt b/Documentation/devicetree/bindings/usb/spear-usb.txt
new file mode 100644
index 000000000000..f8a464a25653
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/spear-usb.txt
@@ -0,0 +1,39 @@
+ST SPEAr SoC USB controllers:
+-----------------------------
+
+EHCI:
+-----
+
+Required properties:
+- compatible: "st,spear600-ehci"
+- interrupt-parent: Should be the phandle for the interrupt controller
+ that services interrupts for this device
+- interrupts: Should contain the EHCI interrupt
+
+Example:
+
+ ehci@e1800000 {
+ compatible = "st,spear600-ehci", "usb-ehci";
+ reg = <0xe1800000 0x1000>;
+ interrupt-parent = <&vic1>;
+ interrupts = <27>;
+ };
+
+
+OHCI:
+-----
+
+Required properties:
+- compatible: "st,spear600-ohci"
+- interrupt-parent: Should be the phandle for the interrupt controller
+ that services interrupts for this device
+- interrupts: Should contain the OHCI interrupt
+
+Example:
+
+ ohci@e1900000 {
+ compatible = "st,spear600-ohci", "usb-ohci";
+ reg = <0xe1800000 0x1000>;
+ interrupt-parent = <&vic1>;
+ interrupts = <26>;
+ };
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 82ac057a24a9..6eab91747a86 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -8,11 +8,13 @@ amcc Applied Micro Circuits Corporation (APM, formally AMCC)
apm Applied Micro Circuits Corporation (APM)
arm ARM Ltd.
atmel Atmel Corporation
+bosch Bosch Sensortec GmbH
cavium Cavium, Inc.
chrp Common Hardware Reference Platform
cortina Cortina Systems, Inc.
dallas Maxim Integrated Products (formerly Dallas Semiconductor)
denx Denx Software Engineering
+emmicro EM Microelectronic
epson Seiko Epson Corp.
est ESTeem Wireless Modems
fsl Freescale Semiconductor
diff --git a/Documentation/devicetree/bindings/watchdog/pnx4008-wdt.txt b/Documentation/devicetree/bindings/watchdog/pnx4008-wdt.txt
new file mode 100644
index 000000000000..7c7f6887c796
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/pnx4008-wdt.txt
@@ -0,0 +1,13 @@
+* NXP PNX watchdog timer
+
+Required properties:
+- compatible: must be "nxp,pnx4008-wdt"
+- reg: physical base address of the controller and length of memory mapped
+ region.
+
+Example:
+
+ watchdog@4003C000 {
+ compatible = "nxp,pnx4008-wdt";
+ reg = <0x4003C000 0x1000>;
+ };
diff --git a/Documentation/devicetree/booting-without-of.txt b/Documentation/devicetree/booting-without-of.txt
index da0bfeb4253d..d4d66757354e 100644
--- a/Documentation/devicetree/booting-without-of.txt
+++ b/Documentation/devicetree/booting-without-of.txt
@@ -551,12 +551,13 @@ Here is an example of a simple device-tree. In this example, an "o"
designates a node followed by the node unit name. Properties are
presented with their name followed by their content. "content"
represents an ASCII string (zero terminated) value, while <content>
-represents a 32-bit hexadecimal value. The various nodes in this
-example will be discussed in a later chapter. At this point, it is
-only meant to give you a idea of what a device-tree looks like. I have
-purposefully kept the "name" and "linux,phandle" properties which
-aren't necessary in order to give you a better idea of what the tree
-looks like in practice.
+represents a 32-bit value, specified in decimal or hexadecimal (the
+latter prefixed 0x). The various nodes in this example will be
+discussed in a later chapter. At this point, it is only meant to give
+you a idea of what a device-tree looks like. I have purposefully kept
+the "name" and "linux,phandle" properties which aren't necessary in
+order to give you a better idea of what the tree looks like in
+practice.
/ o device-tree
|- name = "device-tree"
@@ -576,14 +577,14 @@ looks like in practice.
| |- name = "PowerPC,970"
| |- device_type = "cpu"
| |- reg = <0>
- | |- clock-frequency = <5f5e1000>
+ | |- clock-frequency = <0x5f5e1000>
| |- 64-bit
| |- linux,phandle = <2>
|
o memory@0
| |- name = "memory"
| |- device_type = "memory"
- | |- reg = <00000000 00000000 00000000 20000000>
+ | |- reg = <0x00000000 0x00000000 0x00000000 0x20000000>
| |- linux,phandle = <3>
|
o chosen
@@ -1010,8 +1011,8 @@ compatibility.
#size-cells = <1>;
#interrupt-cells = <2>;
device_type = "soc";
- ranges = <00000000 e0000000 00100000>
- reg = <e0000000 00003000>;
+ ranges = <0x00000000 0xe0000000 0x00100000>
+ reg = <0xe0000000 0x00003000>;
bus-frequency = <0>;
}
@@ -1085,16 +1086,16 @@ supported currently at the toplevel.
* terminated string
*/
- property2 = <1234abcd>; /* define a property containing a
+ property2 = <0x1234abcd>; /* define a property containing a
* numerical 32-bit value (hexadecimal)
*/
- property3 = <12345678 12345678 deadbeef>;
+ property3 = <0x12345678 0x12345678 0xdeadbeef>;
/* define a property containing 3
* numerical 32-bit values (cells) in
* hexadecimal
*/
- property4 = [0a 0b 0c 0d de ea ad be ef];
+ property4 = [0x0a 0x0b 0x0c 0x0d 0xde 0xea 0xad 0xbe 0xef];
/* define a property whose content is
* an arbitrary array of bytes
*/
@@ -1350,10 +1351,10 @@ Appendix A - Sample SOC node for MPC8540
model = "TSEC";
compatible = "gianfar", "simple-bus";
reg = <0x24000 0x1000>;
- local-mac-address = [ 00 E0 0C 00 73 00 ];
- interrupts = <29 2 30 2 34 2>;
+ local-mac-address = [ 0x00 0xE0 0x0C 0x00 0x73 0x00 ];
+ interrupts = <0x29 2 0x30 2 0x34 2>;
phy-handle = <&phy0>;
- sleep = <&pmc 00000080>;
+ sleep = <&pmc 0x00000080>;
ranges;
mdio@24520 {
@@ -1385,10 +1386,10 @@ Appendix A - Sample SOC node for MPC8540
model = "TSEC";
compatible = "gianfar";
reg = <0x25000 0x1000>;
- local-mac-address = [ 00 E0 0C 00 73 01 ];
- interrupts = <13 2 14 2 18 2>;
+ local-mac-address = [ 0x00 0xE0 0x0C 0x00 0x73 0x01 ];
+ interrupts = <0x13 2 0x14 2 0x18 2>;
phy-handle = <&phy1>;
- sleep = <&pmc 00000040>;
+ sleep = <&pmc 0x00000040>;
};
ethernet@26000 {
@@ -1396,17 +1397,17 @@ Appendix A - Sample SOC node for MPC8540
model = "FEC";
compatible = "gianfar";
reg = <0x26000 0x1000>;
- local-mac-address = [ 00 E0 0C 00 73 02 ];
- interrupts = <41 2>;
+ local-mac-address = [ 0x00 0xE0 0x0C 0x00 0x73 0x02 ];
+ interrupts = <0x41 2>;
phy-handle = <&phy3>;
- sleep = <&pmc 00000020>;
+ sleep = <&pmc 0x00000020>;
};
serial@4500 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "fsl,mpc8540-duart", "simple-bus";
- sleep = <&pmc 00000002>;
+ sleep = <&pmc 0x00000002>;
ranges;
serial@4500 {
@@ -1414,7 +1415,7 @@ Appendix A - Sample SOC node for MPC8540
compatible = "ns16550";
reg = <0x4500 0x100>;
clock-frequency = <0>;
- interrupts = <42 2>;
+ interrupts = <0x42 2>;
};
serial@4600 {
@@ -1422,7 +1423,7 @@ Appendix A - Sample SOC node for MPC8540
compatible = "ns16550";
reg = <0x4600 0x100>;
clock-frequency = <0>;
- interrupts = <42 2>;
+ interrupts = <0x42 2>;
};
};
@@ -1436,11 +1437,11 @@ Appendix A - Sample SOC node for MPC8540
};
i2c@3000 {
- interrupts = <43 2>;
+ interrupts = <0x43 2>;
reg = <0x3000 0x100>;
compatible = "fsl-i2c";
dfsrr;
- sleep = <&pmc 00000004>;
+ sleep = <&pmc 0x00000004>;
};
pmc: power@e0070 {
diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware
index d1d4a179a382..fbb241174486 100755
--- a/Documentation/dvb/get_dvb_firmware
+++ b/Documentation/dvb/get_dvb_firmware
@@ -28,7 +28,8 @@ use IO::Handle;
"opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718",
"af9015", "ngene", "az6027", "lme2510_lg", "lme2510c_s7395",
"lme2510c_s7395_old", "drxk", "drxk_terratec_h5",
- "drxk_hauppauge_hvr930c", "tda10071", "it9135", "it9137");
+ "drxk_hauppauge_hvr930c", "tda10071", "it9135", "it9137",
+ "drxk_pctv");
# Check args
syntax() if (scalar(@ARGV) != 1);
@@ -730,6 +731,23 @@ sub tda10071 {
"$fwfile";
}
+sub drxk_pctv {
+ my $sourcefile = "PCTV_460e_reference.zip";
+ my $url = "ftp://ftp.pctvsystems.com/TV/driver/PCTV%2070e%2080e%20100e%20320e%20330e%20800e/";
+ my $hash = "4403de903bf2593464c8d74bbc200a57";
+ my $fwfile = "dvb-demod-drxk-pctv.fw";
+ my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+ checkstandard();
+
+ wgetfile($sourcefile, $url . $sourcefile);
+ verify($sourcefile, $hash);
+ unzip($sourcefile, $tmpdir);
+ extract("$tmpdir/PCTV\ 70e\ 80e\ 100e\ 320e\ 330e\ 800e/32\ bit/emOEM.sys", 0x72b80, 42692, $fwfile);
+
+ "$fwfile";
+}
+
# ---------------------------------------------------------------
# Utilities
diff --git a/Documentation/dvb/opera-firmware.txt b/Documentation/dvb/opera-firmware.txt
index 93e784c2607b..fb6683188ef7 100644
--- a/Documentation/dvb/opera-firmware.txt
+++ b/Documentation/dvb/opera-firmware.txt
@@ -8,7 +8,7 @@ from the windriver disk into this directory.
Then run
-./get_dvb_firware opera1
+./get_dvb_firmware opera1
and after that you have 2 files:
@@ -24,4 +24,4 @@ After that the driver can load the firmware
in kernel config and have hotplug running).
-Marco Gittler <g.marco@freenet.de> \ No newline at end of file
+Marco Gittler <g.marco@freenet.de>
diff --git a/Documentation/dynamic-debug-howto.txt b/Documentation/dynamic-debug-howto.txt
index 74e6c7782678..6e1684981da2 100644
--- a/Documentation/dynamic-debug-howto.txt
+++ b/Documentation/dynamic-debug-howto.txt
@@ -2,17 +2,17 @@
Introduction
============
-This document describes how to use the dynamic debug (ddebug) feature.
+This document describes how to use the dynamic debug (dyndbg) feature.
-Dynamic debug is designed to allow you to dynamically enable/disable kernel
-code to obtain additional kernel information. Currently, if
-CONFIG_DYNAMIC_DEBUG is set, then all pr_debug()/dev_dbg() calls can be
-dynamically enabled per-callsite.
+Dynamic debug is designed to allow you to dynamically enable/disable
+kernel code to obtain additional kernel information. Currently, if
+CONFIG_DYNAMIC_DEBUG is set, then all pr_debug()/dev_dbg() calls can
+be dynamically enabled per-callsite.
Dynamic debug has even more useful features:
- * Simple query language allows turning on and off debugging statements by
- matching any combination of 0 or 1 of:
+ * Simple query language allows turning on and off debugging
+ statements by matching any combination of 0 or 1 of:
- source filename
- function name
@@ -20,17 +20,19 @@ Dynamic debug has even more useful features:
- module name
- format string
- * Provides a debugfs control file: <debugfs>/dynamic_debug/control which can be
- read to display the complete list of known debug statements, to help guide you
+ * Provides a debugfs control file: <debugfs>/dynamic_debug/control
+ which can be read to display the complete list of known debug
+ statements, to help guide you
Controlling dynamic debug Behaviour
===================================
The behaviour of pr_debug()/dev_dbg()s are controlled via writing to a
-control file in the 'debugfs' filesystem. Thus, you must first mount the debugfs
-filesystem, in order to make use of this feature. Subsequently, we refer to the
-control file as: <debugfs>/dynamic_debug/control. For example, if you want to
-enable printing from source file 'svcsock.c', line 1603 you simply do:
+control file in the 'debugfs' filesystem. Thus, you must first mount
+the debugfs filesystem, in order to make use of this feature.
+Subsequently, we refer to the control file as:
+<debugfs>/dynamic_debug/control. For example, if you want to enable
+printing from source file 'svcsock.c', line 1603 you simply do:
nullarbor:~ # echo 'file svcsock.c line 1603 +p' >
<debugfs>/dynamic_debug/control
@@ -44,15 +46,15 @@ nullarbor:~ # echo 'file svcsock.c wtf 1 +p' >
Viewing Dynamic Debug Behaviour
===========================
-You can view the currently configured behaviour of all the debug statements
-via:
+You can view the currently configured behaviour of all the debug
+statements via:
nullarbor:~ # cat <debugfs>/dynamic_debug/control
# filename:lineno [module]function flags format
-/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:323 [svcxprt_rdma]svc_rdma_cleanup - "SVCRDMA Module Removed, deregister RPC RDMA transport\012"
-/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:341 [svcxprt_rdma]svc_rdma_init - "\011max_inline : %d\012"
-/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:340 [svcxprt_rdma]svc_rdma_init - "\011sq_depth : %d\012"
-/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:338 [svcxprt_rdma]svc_rdma_init - "\011max_requests : %d\012"
+/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:323 [svcxprt_rdma]svc_rdma_cleanup =_ "SVCRDMA Module Removed, deregister RPC RDMA transport\012"
+/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:341 [svcxprt_rdma]svc_rdma_init =_ "\011max_inline : %d\012"
+/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:340 [svcxprt_rdma]svc_rdma_init =_ "\011sq_depth : %d\012"
+/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:338 [svcxprt_rdma]svc_rdma_init =_ "\011max_requests : %d\012"
...
@@ -65,12 +67,12 @@ nullarbor:~ # grep -i rdma <debugfs>/dynamic_debug/control | wc -l
nullarbor:~ # grep -i tcp <debugfs>/dynamic_debug/control | wc -l
42
-Note in particular that the third column shows the enabled behaviour
-flags for each debug statement callsite (see below for definitions of the
-flags). The default value, no extra behaviour enabled, is "-". So
-you can view all the debug statement callsites with any non-default flags:
+The third column shows the currently enabled flags for each debug
+statement callsite (see below for definitions of the flags). The
+default value, with no flags enabled, is "=_". So you can view all
+the debug statement callsites with any non-default flags:
-nullarbor:~ # awk '$3 != "-"' <debugfs>/dynamic_debug/control
+nullarbor:~ # awk '$3 != "=_"' <debugfs>/dynamic_debug/control
# filename:lineno [module]function flags format
/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c:1603 [sunrpc]svc_send p "svc_process: st_sendto returned %d\012"
@@ -103,15 +105,14 @@ specifications, followed by a flags change specification.
command ::= match-spec* flags-spec
-The match-spec's are used to choose a subset of the known dprintk()
+The match-spec's are used to choose a subset of the known pr_debug()
callsites to which to apply the flags-spec. Think of them as a query
with implicit ANDs between each pair. Note that an empty list of
-match-specs is possible, but is not very useful because it will not
-match any debug statement callsites.
+match-specs will select all debug statement callsites.
-A match specification comprises a keyword, which controls the attribute
-of the callsite to be compared, and a value to compare against. Possible
-keywords are:
+A match specification comprises a keyword, which controls the
+attribute of the callsite to be compared, and a value to compare
+against. Possible keywords are:
match-spec ::= 'func' string |
'file' string |
@@ -164,15 +165,15 @@ format
characters (") or single quote characters (').
Examples:
- format svcrdma: // many of the NFS/RDMA server dprintks
- format readahead // some dprintks in the readahead cache
+ format svcrdma: // many of the NFS/RDMA server pr_debugs
+ format readahead // some pr_debugs in the readahead cache
format nfsd:\040SETATTR // one way to match a format with whitespace
format "nfsd: SETATTR" // a neater way to match a format with whitespace
format 'nfsd: SETATTR' // yet another way to match a format with whitespace
line
The given line number or range of line numbers is compared
- against the line number of each dprintk() callsite. A single
+ against the line number of each pr_debug() callsite. A single
line number matches the callsite line number exactly. A
range of line numbers matches any callsite between the first
and last line number inclusive. An empty first number means
@@ -188,51 +189,93 @@ The flags specification comprises a change operation followed
by one or more flag characters. The change operation is one
of the characters:
--
- remove the given flags
-
-+
- add the given flags
-
-=
- set the flags to the given flags
+ - remove the given flags
+ + add the given flags
+ = set the flags to the given flags
The flags are:
-f
- Include the function name in the printed message
-l
- Include line number in the printed message
-m
- Include module name in the printed message
-p
- Causes a printk() message to be emitted to dmesg
-t
- Include thread ID in messages not generated from interrupt context
+ p enables the pr_debug() callsite.
+ f Include the function name in the printed message
+ l Include line number in the printed message
+ m Include module name in the printed message
+ t Include thread ID in messages not generated from interrupt context
+ _ No flags are set. (Or'd with others on input)
+
+For display, the flags are preceded by '='
+(mnemonic: what the flags are currently equal to).
-Note the regexp ^[-+=][flmpt]+$ matches a flags specification.
-Note also that there is no convenient syntax to remove all
-the flags at once, you need to use "-flmpt".
+Note the regexp ^[-+=][flmpt_]+$ matches a flags specification.
+To clear all flags at once, use "=_" or "-flmpt".
-Debug messages during boot process
+Debug messages during Boot Process
==================================
-To be able to activate debug messages during the boot process,
-even before userspace and debugfs exists, use the boot parameter:
-ddebug_query="QUERY"
+To activate debug messages for core code and built-in modules during
+the boot process, even before userspace and debugfs exists, use
+dyndbg="QUERY", module.dyndbg="QUERY", or ddebug_query="QUERY"
+(ddebug_query is obsoleted by dyndbg, and deprecated). QUERY follows
+the syntax described above, but must not exceed 1023 characters. Your
+bootloader may impose lower limits.
+
+These dyndbg params are processed just after the ddebug tables are
+processed, as part of the arch_initcall. Thus you can enable debug
+messages in all code run after this arch_initcall via this boot
+parameter.
-QUERY follows the syntax described above, but must not exceed 1023
-characters. The enablement of debug messages is done as an arch_initcall.
-Thus you can enable debug messages in all code processed after this
-arch_initcall via this boot parameter.
On an x86 system for example ACPI enablement is a subsys_initcall and
-ddebug_query="file ec.c +p"
+ dyndbg="file ec.c +p"
will show early Embedded Controller transactions during ACPI setup if
your machine (typically a laptop) has an Embedded Controller.
PCI (or other devices) initialization also is a hot candidate for using
this boot parameter for debugging purposes.
+If foo module is not built-in, foo.dyndbg will still be processed at
+boot time, without effect, but will be reprocessed when module is
+loaded later. dyndbg_query= and bare dyndbg= are only processed at
+boot.
+
+
+Debug Messages at Module Initialization Time
+============================================
+
+When "modprobe foo" is called, modprobe scans /proc/cmdline for
+foo.params, strips "foo.", and passes them to the kernel along with
+params given in modprobe args or /etc/modprob.d/*.conf files,
+in the following order:
+
+1. # parameters given via /etc/modprobe.d/*.conf
+ options foo dyndbg=+pt
+ options foo dyndbg # defaults to +p
+
+2. # foo.dyndbg as given in boot args, "foo." is stripped and passed
+ foo.dyndbg=" func bar +p; func buz +mp"
+
+3. # args to modprobe
+ modprobe foo dyndbg==pmf # override previous settings
+
+These dyndbg queries are applied in order, with last having final say.
+This allows boot args to override or modify those from /etc/modprobe.d
+(sensible, since 1 is system wide, 2 is kernel or boot specific), and
+modprobe args to override both.
+
+In the foo.dyndbg="QUERY" form, the query must exclude "module foo".
+"foo" is extracted from the param-name, and applied to each query in
+"QUERY", and only 1 match-spec of each type is allowed.
+
+The dyndbg option is a "fake" module parameter, which means:
+
+- modules do not need to define it explicitly
+- every module gets it tacitly, whether they use pr_debug or not
+- it doesnt appear in /sys/module/$module/parameters/
+ To see it, grep the control file, or inspect /proc/cmdline.
+
+For CONFIG_DYNAMIC_DEBUG kernels, any settings given at boot-time (or
+enabled by -DDEBUG flag during compilation) can be disabled later via
+the sysfs interface if the debug messages are no longer needed:
+
+ echo "module module_name -p" > <debugfs>/dynamic_debug/control
Examples
========
@@ -260,3 +303,18 @@ nullarbor:~ # echo -n 'func svc_process -p' >
// enable messages for NFS calls READ, READLINK, READDIR and READDIR+.
nullarbor:~ # echo -n 'format "nfsd: READ" +p' >
<debugfs>/dynamic_debug/control
+
+// enable all messages
+nullarbor:~ # echo -n '+p' > <debugfs>/dynamic_debug/control
+
+// add module, function to all enabled messages
+nullarbor:~ # echo -n '+mf' > <debugfs>/dynamic_debug/control
+
+// boot-args example, with newlines and comments for readability
+Kernel command line: ...
+ // see whats going on in dyndbg=value processing
+ dynamic_debug.verbose=1
+ // enable pr_debugs in 2 builtins, #cmt is stripped
+ dyndbg="module params +p #cmt ; module sys +p"
+ // enable pr_debugs in 2 functions in a module loaded later
+ pc87360.dyndbg="func pc87360_init_device +p; func pc87360_find +p"
diff --git a/Documentation/edac.txt b/Documentation/edac.txt
index fdcc49fad8e1..03df2b020332 100644
--- a/Documentation/edac.txt
+++ b/Documentation/edac.txt
@@ -734,7 +734,7 @@ were done at i7core_edac driver. This chapter will cover those differences
associated with a physical CPU socket.
Each MC have 3 physical read channels, 3 physical write channels and
- 3 logic channels. The driver currenty sees it as just 3 channels.
+ 3 logic channels. The driver currently sees it as just 3 channels.
Each channel can have up to 3 DIMMs.
The minimum known unity is DIMMs. There are no information about csrows.
diff --git a/Documentation/eisa.txt b/Documentation/eisa.txt
index 38cf0c7b559f..a55e4910924e 100644
--- a/Documentation/eisa.txt
+++ b/Documentation/eisa.txt
@@ -179,7 +179,7 @@ CONFIG_ALPHA_JENSEN or CONFIG_EISA_VLB_PRIMING are set.
Converting an EISA driver to the new API mostly involves *deleting*
code (since probing is now in the core EISA code). Unfortunately, most
-drivers share their probing routine between ISA, MCA and EISA. Special
+drivers share their probing routine between ISA, and EISA. Special
care must be taken when ripping out the EISA code, so other busses
won't suffer from these surgical strikes...
diff --git a/Documentation/extcon/porting-android-switch-class b/Documentation/extcon/porting-android-switch-class
new file mode 100644
index 000000000000..eb0fa5f4fe88
--- /dev/null
+++ b/Documentation/extcon/porting-android-switch-class
@@ -0,0 +1,124 @@
+
+ Staging/Android Switch Class Porting Guide
+ (linux/drivers/staging/android/switch)
+ (c) Copyright 2012 Samsung Electronics
+
+AUTHORS
+MyungJoo Ham <myungjoo.ham@samsung.com>
+
+/*****************************************************************
+ * CHAPTER 1. *
+ * PORTING SWITCH CLASS DEVICE DRIVERS *
+ *****************************************************************/
+
+****** STEP 1. Basic Functionality
+ No extcon extended feature, but switch features only.
+
+- struct switch_dev (fed to switch_dev_register/unregister)
+ @name: no change
+ @dev: no change
+ @index: drop (not used in switch device driver side anyway)
+ @state: no change
+ If you have used @state with magic numbers, keep it
+ at this step.
+ @print_name: no change but type change (switch_dev->extcon_dev)
+ @print_state: no change but type change (switch_dev->extcon_dev)
+
+- switch_dev_register(sdev, dev)
+ => extcon_dev_register(edev, dev)
+ : no change but type change (sdev->edev)
+- switch_dev_unregister(sdev)
+ => extcon_dev_unregister(edev)
+ : no change but type change (sdev->edev)
+- switch_get_state(sdev)
+ => extcon_get_state(edev)
+ : no change but type change (sdev->edev) and (return: int->u32)
+- switch_set_state(sdev, state)
+ => extcon_set_state(edev, state)
+ : no change but type change (sdev->edev) and (state: int->u32)
+
+With this changes, the ex-switch extcon class device works as it once
+worked as switch class device. However, it will now have additional
+interfaces (both ABI and in-kernel API) and different ABI locations.
+However, if CONFIG_ANDROID is enabled without CONFIG_ANDROID_SWITCH,
+/sys/class/switch/* will be symbolically linked to /sys/class/extcon/
+so that they are still compatible with legacy userspace processes.
+
+****** STEP 2. Multistate (no more magic numbers in state value)
+ Extcon's extended features for switch device drivers with
+ complex features usually required magic numbers in state
+ value of switch_dev. With extcon, such magic numbers that
+ support multiple cables (
+
+ 1. Define cable names at edev->supported_cable.
+ 2. (Recommended) remove print_state callback.
+ 3. Use extcon_get_cable_state_(edev, index) or
+ extcon_get_cable_state(edev, cable_name) instead of
+ extcon_get_state(edev) if you intend to get a state of a specific
+ cable. Same for set_state. This way, you can remove the usage of
+ magic numbers in state value.
+ 4. Use extcon_update_state() if you are updating specific bits of
+ the state value.
+
+Example: a switch device driver w/ magic numbers for two cables.
+ "0x00": no cables connected.
+ "0x01": cable 1 connected
+ "0x02": cable 2 connected
+ "0x03": cable 1 and 2 connected
+ 1. edev->supported_cable = {"1", "2", NULL};
+ 2. edev->print_state = NULL;
+ 3. extcon_get_cable_state_(edev, 0) shows cable 1's state.
+ extcon_get_cable_state(edev, "1") shows cable 1's state.
+ extcon_set_cable_state_(edev, 1) sets cable 2's state.
+ extcon_set_cable_state(edev, "2") sets cable 2's state
+ 4. extcon_update_state(edev, 0x01, 0) sets the least bit's 0.
+
+****** STEP 3. Notify other device drivers
+
+ You can notify others of the cable attach/detach events with
+notifier chains.
+
+ At the side of other device drivers (the extcon device itself
+does not need to get notified of its own events), there are two
+methods to register notifier_block for cable events:
+(a) for a specific cable or (b) for every cable.
+
+ (a) extcon_register_interest(obj, extcon_name, cable_name, nb)
+ Example: want to get news of "MAX8997_MUIC"'s "USB" cable
+
+ obj = kzalloc(sizeof(struct extcon_specific_cable_nb),
+ GFP_KERNEL);
+ nb->notifier_call = the_callback_to_handle_usb;
+
+ extcon_register_intereset(obj, "MAX8997_MUIC", "USB", nb);
+
+ (b) extcon_register_notifier(edev, nb)
+ Call nb for any changes in edev.
+
+ Please note that in order to properly behave with method (a),
+the extcon device driver should support multistate feature (STEP 2).
+
+****** STEP 4. Inter-cable relation (mutually exclusive)
+
+ You can provide inter-cable mutually exclusiveness information
+for an extcon device. When cables A and B are declared to be mutually
+exclusive, the two cables cannot be in ATTACHED state simulteneously.
+
+
+/*****************************************************************
+ * CHAPTER 2. *
+ * PORTING USERSPACE w/ SWITCH CLASS DEVICE SUPPORT *
+ *****************************************************************/
+
+****** ABI Location
+
+ If "CONFIG_ANDROID" is enabled and "CONFIG_ANDROID_SWITCH" is
+disabled, /sys/class/switch/* are created as symbolic links to
+/sys/class/extcon/*. Because CONFIG_ANDROID_SWITCH creates
+/sys/class/switch directory, we disable symboling linking if
+CONFIG_ANDROID_SWITCH is enabled.
+
+ The two files of switch class, name and state, are provided with
+extcon, too. When the multistate support (STEP 2 of CHAPTER 1.) is
+not enabled or print_state callback is supplied, the output of
+state ABI is same with switch class.
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index e4b57756b9f5..50d82ae09e2a 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -2,7 +2,14 @@ The following is a list of files and features that are going to be
removed in the kernel source tree. Every entry should contain what
exactly is going away, why it is happening, and who is going to be doing
the work. When the feature is removed from the kernel, it should also
-be removed from this file.
+be removed from this file. The suggested deprecation period is 3 releases.
+
+---------------------------
+
+What: ddebug_query="query" boot cmdline param
+When: v3.8
+Why: obsoleted by dyndbg="query" and module.dyndbg="query"
+Who: Jim Cromie <jim.cromie@gmail.com>, Jason Baron <jbaron@redhat.com>
---------------------------
@@ -534,6 +541,18 @@ Who: Kees Cook <keescook@chromium.org>
----------------------------
+What: Removing the pn544 raw driver.
+When: 3.6
+Why: With the introduction of the NFC HCI and SHDL kernel layers, pn544.c
+ is being replaced by pn544_hci.c which is accessible through the netlink
+ and socket NFC APIs. Moreover, pn544.c is outdated and does not seem to
+ work properly with the latest Android stacks.
+ Having 2 drivers for the same hardware is confusing and as such we
+ should only keep the one following the kernel NFC APIs.
+Who: Samuel Ortiz <sameo@linux.intel.com>
+
+----------------------------
+
What: setitimer accepts user NULL pointer (value)
When: 3.6
Why: setitimer is not returning -EFAULT if user pointer is NULL. This
@@ -542,6 +561,15 @@ Who: Sasikantha Babu <sasikanth.v19@gmail.com>
----------------------------
+What: remove bogus DV presets V4L2_DV_1080I29_97, V4L2_DV_1080I30 and
+ V4L2_DV_1080I25
+When: 3.6
+Why: These HDTV formats do not exist and were added by a confused mind
+ (that was me, to be precise...)
+Who: Hans Verkuil <hans.verkuil@cisco.com>
+
+----------------------------
+
What: V4L2_CID_HCENTER, V4L2_CID_VCENTER V4L2 controls
When: 3.7
Why: The V4L2_CID_VCENTER, V4L2_CID_HCENTER controls have been deprecated
@@ -549,3 +577,14 @@ Why: The V4L2_CID_VCENTER, V4L2_CID_HCENTER controls have been deprecated
There are newer controls (V4L2_CID_PAN*, V4L2_CID_TILT*) that provide
similar functionality.
Who: Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
+
+----------------------------
+
+What: cgroup option updates via remount
+When: March 2013
+Why: Remount currently allows changing bound subsystems and
+ release_agent. Rebinding is hardly useful as it only works
+ when the hierarchy is empty and release_agent itself should be
+ replaced with conventional fsnotify.
+
+----------------------------
diff --git a/Documentation/filesystems/nfs/pnfs.txt b/Documentation/filesystems/nfs/pnfs.txt
index c7919c6e3bea..52ae07f5f578 100644
--- a/Documentation/filesystems/nfs/pnfs.txt
+++ b/Documentation/filesystems/nfs/pnfs.txt
@@ -93,7 +93,7 @@ The API to the login script is as follows:
(allways exists)
(More protocols can be defined in the future.
The client does not interpret this string it is
- passed unchanged as recieved from the Server)
+ passed unchanged as received from the Server)
-o osdname of the requested target OSD
(Might be empty)
(A string which denotes the OSD name, there is a
diff --git a/Documentation/filesystems/qnx6.txt b/Documentation/filesystems/qnx6.txt
index 050223ea03c7..e59f2f09f56e 100644
--- a/Documentation/filesystems/qnx6.txt
+++ b/Documentation/filesystems/qnx6.txt
@@ -17,7 +17,7 @@ concepts of blocks, inodes and directories.
On QNX it is possible to create little endian and big endian qnx6 filesystems.
This feature makes it possible to create and use a different endianness fs
for the target (QNX is used on quite a range of embedded systems) plattform
-running on a different endianess.
+running on a different endianness.
The Linux driver handles endianness transparently. (LE and BE)
Blocks
@@ -26,7 +26,7 @@ Blocks
The space in the device or file is split up into blocks. These are a fixed
size of 512, 1024, 2048 or 4096, which is decided when the filesystem is
created.
-Blockpointers are 32bit, so the maximum space that can be adressed is
+Blockpointers are 32bit, so the maximum space that can be addressed is
2^32 * 4096 bytes or 16TB
The superblocks
@@ -47,16 +47,16 @@ inactive superblock.
Each superblock holds a set of root inodes for the different filesystem
parts. (Inode, Bitmap and Longfilenames)
Each of these root nodes holds information like total size of the stored
-data and the adressing levels in that specific tree.
-If the level value is 0, up to 16 direct blocks can be adressed by each
+data and the addressing levels in that specific tree.
+If the level value is 0, up to 16 direct blocks can be addressed by each
node.
-Level 1 adds an additional indirect adressing level where each indirect
-adressing block holds up to blocksize / 4 bytes pointers to data blocks.
-Level 2 adds an additional indirect adressig block level (so, already up
-to 16 * 256 * 256 = 1048576 blocks that can be adressed by such a tree)a
+Level 1 adds an additional indirect addressing level where each indirect
+addressing block holds up to blocksize / 4 bytes pointers to data blocks.
+Level 2 adds an additional indirect addressing block level (so, already up
+to 16 * 256 * 256 = 1048576 blocks that can be addressed by such a tree).
Unused block pointers are always set to ~0 - regardless of root node,
-indirect adressing blocks or inodes.
+indirect addressing blocks or inodes.
Data leaves are always on the lowest level. So no data is stored on upper
tree levels.
@@ -64,7 +64,7 @@ The first Superblock is located at 0x2000. (0x2000 is the bootblock size)
The Audi MMI 3G first superblock directly starts at byte 0.
Second superblock position can either be calculated from the superblock
information (total number of filesystem blocks) or by taking the highest
-device address, zeroing the last 3 bytes and then substracting 0x1000 from
+device address, zeroing the last 3 bytes and then subtracting 0x1000 from
that address.
0x1000 is the size reserved for each superblock - regardless of the
@@ -83,8 +83,8 @@ size, number of blocks used, access time, change time and modification time.
Object mode field is POSIX format. (which makes things easier)
There are also pointers to the first 16 blocks, if the object data can be
-adressed with 16 direct blocks.
-For more than 16 blocks an indirect adressing in form of another tree is
+addressed with 16 direct blocks.
+For more than 16 blocks an indirect addressing in form of another tree is
used. (scheme is the same as the one used for the superblock root nodes)
The filesize is stored 64bit. Inode counting starts with 1. (whilst long
@@ -118,13 +118,13 @@ no block pointers and the directory file record pointing to the target file
inode.
Character and block special devices do not exist in QNX as those files
-are handled by the QNX kernel/drivers and created in /dev independant of the
+are handled by the QNX kernel/drivers and created in /dev independent of the
underlaying filesystem.
Long filenames
--------------
-Long filenames are stored in a seperate adressing tree. The staring point
+Long filenames are stored in a separate addressing tree. The staring point
is the longfilename root node in the active superblock.
Each data block (tree leaves) holds one long filename. That filename is
limited to 510 bytes. The first two starting bytes are used as length field
diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt
index 620a07844e8c..e08a883de36e 100644
--- a/Documentation/gpio.txt
+++ b/Documentation/gpio.txt
@@ -322,6 +322,9 @@ where 'flags' is currently defined to specify the following properties:
* GPIOF_OPEN_DRAIN - gpio pin is open drain type.
* GPIOF_OPEN_SOURCE - gpio pin is open source type.
+ * GPIOF_EXPORT_DIR_FIXED - export gpio to sysfs, keep direction
+ * GPIOF_EXPORT_DIR_CHANGEABLE - also export, allow changing direction
+
since GPIOF_INIT_* are only valid when configured as output, so group valid
combinations as:
diff --git a/Documentation/hwmon/ina2xx b/Documentation/hwmon/ina2xx
new file mode 100644
index 000000000000..f50a6cc27616
--- /dev/null
+++ b/Documentation/hwmon/ina2xx
@@ -0,0 +1,29 @@
+Kernel driver ina2xx
+====================
+
+Supported chips:
+ * Texas Instruments INA219
+ Prefix: 'ina219'
+ Addresses: I2C 0x40 - 0x4f
+ Datasheet: Publicly available at the Texas Instruments website
+ http://www.ti.com/
+
+ * Texas Instruments INA226
+ Prefix: 'ina226'
+ Addresses: I2C 0x40 - 0x4f
+ Datasheet: Publicly available at the Texas Instruments website
+ http://www.ti.com/
+
+Author: Lothar Felten <l-felten@ti.com>
+
+Description
+-----------
+
+The INA219 is a high-side current shunt and power monitor with an I2C
+interface. The INA219 monitors both shunt drop and supply voltage, with
+programmable conversion times and filtering.
+
+The INA226 is a current shunt and power monitor with an I2C interface.
+The INA226 monitors both a shunt voltage drop and bus supply voltage.
+
+The shunt value in micro-ohms can be set via platform data.
diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87
index 23b7def21ba8..87850d86c559 100644
--- a/Documentation/hwmon/it87
+++ b/Documentation/hwmon/it87
@@ -30,6 +30,14 @@ Supported chips:
Prefix: 'it8728'
Addresses scanned: from Super I/O config space (8 I/O ports)
Datasheet: Not publicly available
+ * IT8782F
+ Prefix: 'it8782'
+ Addresses scanned: from Super I/O config space (8 I/O ports)
+ Datasheet: Not publicly available
+ * IT8783E/F
+ Prefix: 'it8783'
+ Addresses scanned: from Super I/O config space (8 I/O ports)
+ Datasheet: Not publicly available
* SiS950 [clone of IT8705F]
Prefix: 'it87'
Addresses scanned: from Super I/O config space (8 I/O ports)
@@ -63,7 +71,7 @@ Module Parameters
Hardware Interfaces
-------------------
-All the chips suported by this driver are LPC Super-I/O chips, accessed
+All the chips supported by this driver are LPC Super-I/O chips, accessed
through the LPC bus (ISA-like I/O ports). The IT8712F additionally has an
SMBus interface to the hardware monitoring functions. This driver no
longer supports this interface though, as it is slower and less reliable
@@ -75,7 +83,8 @@ Description
-----------
This driver implements support for the IT8705F, IT8712F, IT8716F,
-IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E and SiS950 chips.
+IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, IT8781F, IT8782F,
+IT8783E/F, and SiS950 chips.
These chips are 'Super I/O chips', supporting floppy disks, infrared ports,
joysticks and other miscellaneous stuff. For hardware monitoring, they
@@ -99,11 +108,11 @@ The IT8716F, IT8718F, IT8720F, IT8721F/IT8758E and later IT8712F revisions
have support for 2 additional fans. The additional fans are supported by the
driver.
-The IT8716F, IT8718F, IT8720F and IT8721F/IT8758E, and late IT8712F and
-IT8705F also have optional 16-bit tachometer counters for fans 1 to 3. This
-is better (no more fan clock divider mess) but not compatible with the older
-chips and revisions. The 16-bit tachometer mode is enabled by the driver when
-one of the above chips is detected.
+The IT8716F, IT8718F, IT8720F, IT8721F/IT8758E, IT8782F, IT8783E/F, and late
+IT8712F and IT8705F also have optional 16-bit tachometer counters for fans 1 to
+3. This is better (no more fan clock divider mess) but not compatible with the
+older chips and revisions. The 16-bit tachometer mode is enabled by the driver
+when one of the above chips is detected.
The IT8726F is just bit enhanced IT8716F with additional hardware
for AMD power sequencing. Therefore the chip will appear as IT8716F
@@ -131,9 +140,10 @@ inputs can measure voltages between 0 and 4.08 volts, with a resolution of
0.016 volt (except IT8721F/IT8758E and IT8728F: 0.012 volt.) The battery
voltage in8 does not have limit registers.
-On the IT8721F/IT8758E, some voltage inputs are internal and scaled inside
-the chip (in7, in8 and optionally in3). The driver handles this transparently
-so user-space doesn't have to care.
+On the IT8721F/IT8758E, IT8782F, and IT8783E/F, some voltage inputs are
+internal and scaled inside the chip (in7 (optional for IT8782F and IT8783E/F),
+in8 and optionally in3). The driver handles this transparently so user-space
+doesn't have to care.
The VID lines (IT8712F/IT8716F/IT8718F/IT8720F) encode the core voltage value:
the voltage level your processor should work with. This is hardcoded by
diff --git a/Documentation/hwmon/wm831x b/Documentation/hwmon/wm831x
index 24f47d8f6a42..11446757c8c8 100644
--- a/Documentation/hwmon/wm831x
+++ b/Documentation/hwmon/wm831x
@@ -22,7 +22,7 @@ reporting of all the input values but does not provide any alarms.
Voltage Monitoring
------------------
-Voltages are sampled by a 12 bit ADC. Voltages in milivolts are 1.465
+Voltages are sampled by a 12 bit ADC. Voltages in millivolts are 1.465
times the ADC value.
Temperature Monitoring
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index e34b531dc316..915f28c470e9 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -120,6 +120,7 @@ Code Seq#(hex) Include File Comments
'G' 00-0F linux/gigaset_dev.h conflict!
'H' 00-7F linux/hiddev.h conflict!
'H' 00-0F linux/hidraw.h conflict!
+'H' 01 linux/mei.h conflict!
'H' 00-0F sound/asound.h conflict!
'H' 20-40 sound/asound_fm.h conflict!
'H' 80-8F sound/sfnt_info.h conflict!
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index e275432ef2c7..b69cfdc12112 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -70,7 +70,6 @@ parameter is applicable:
M68k M68k architecture is enabled.
These options have more detailed description inside of
Documentation/m68k/kernel-options.txt.
- MCA MCA bus support is enabled.
MDA MDA console support is enabled.
MIPS MIPS architecture is enabled.
MOUSE Appropriate mouse support is enabled.
@@ -611,7 +610,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
ddebug_query= [KNL,DYNAMIC_DEBUG] Enable debug messages at early boot
time. See Documentation/dynamic-debug-howto.txt for
- details.
+ details. Deprecated, see dyndbg.
debug [KNL] Enable kernel debugging (events log level).
@@ -731,6 +730,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
dscc4.setup= [NET]
+ dyndbg[="val"] [KNL,DYNAMIC_DEBUG]
+ module.dyndbg[="val"]
+ Enable debug messages at boot time. See
+ Documentation/dynamic-debug-howto.txt for details.
+
earlycon= [KNL] Output early console device and options.
uart[8250],io,<addr>[,options]
uart[8250],mmio,<addr>[,options]
@@ -983,6 +987,20 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
i8k.restricted [HW] Allow controlling fans only if SYS_ADMIN
capability is set.
+ i915.invert_brightness=
+ [DRM] Invert the sense of the variable that is used to
+ set the brightness of the panel backlight. Normally a
+ brightness value of 0 indicates backlight switched off,
+ and the maximum of the brightness value sets the backlight
+ to maximum brightness. If this parameter is set to 0
+ (default) and the machine requires it, or this parameter
+ is set to 1, a brightness value of 0 sets the backlight
+ to maximum brightness, and the maximum of the brightness
+ value switches the backlight off.
+ -1 -- never invert brightness
+ 0 -- machine default
+ 1 -- force brightness inversion
+
icn= [HW,ISDN]
Format: <io>[,<membase>[,<icn_id>[,<icn_id2>]]]
@@ -2458,6 +2476,8 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
resume= [SWSUSP]
Specify the partition device for software suspend
+ Format:
+ {/dev/<dev> | PARTUUID=<uuid> | <int>:<int> | <hex>}
resume_offset= [SWSUSP]
Specify the offset from the beginning of the partition
diff --git a/Documentation/mca.txt b/Documentation/mca.txt
deleted file mode 100644
index dfd130c2207d..000000000000
--- a/Documentation/mca.txt
+++ /dev/null
@@ -1,313 +0,0 @@
-i386 Micro Channel Architecture Support
-=======================================
-
-MCA support is enabled using the CONFIG_MCA define. A machine with a MCA
-bus will have the kernel variable MCA_bus set, assuming the BIOS feature
-bits are set properly (see arch/i386/boot/setup.S for information on
-how this detection is done).
-
-Adapter Detection
-=================
-
-The ideal MCA adapter detection is done through the use of the
-Programmable Option Select registers. Generic functions for doing
-this have been added in include/linux/mca.h and arch/x86/kernel/mca_32.c.
-Everything needed to detect adapters and read (and write) configuration
-information is there. A number of MCA-specific drivers already use
-this. The typical probe code looks like the following:
-
- #include <linux/mca.h>
-
- unsigned char pos2, pos3, pos4, pos5;
- struct net_device* dev;
- int slot;
-
- if( MCA_bus ) {
- slot = mca_find_adapter( ADAPTER_ID, 0 );
- if( slot == MCA_NOTFOUND ) {
- return -ENODEV;
- }
- /* optional - see below */
- mca_set_adapter_name( slot, "adapter name & description" );
- mca_set_adapter_procfn( slot, dev_getinfo, dev );
-
- /* read the POS registers. Most devices only use 2 and 3 */
- pos2 = mca_read_stored_pos( slot, 2 );
- pos3 = mca_read_stored_pos( slot, 3 );
- pos4 = mca_read_stored_pos( slot, 4 );
- pos5 = mca_read_stored_pos( slot, 5 );
- } else {
- return -ENODEV;
- }
-
- /* extract configuration from pos[2345] and set everything up */
-
-Loadable modules should modify this to test that the specified IRQ and
-IO ports (plus whatever other stuff) match. See 3c523.c for example
-code (actually, smc-mca.c has a slightly more complex example that can
-handle a list of adapter ids).
-
-Keep in mind that devices should never directly access the POS registers
-(via inb(), outb(), etc). While it's generally safe, there is a small
-potential for blowing up hardware when it's done at the wrong time.
-Furthermore, accessing a POS register disables a device temporarily.
-This is usually okay during startup, but do _you_ want to rely on it?
-During initial configuration, mca_init() reads all the POS registers
-into memory. mca_read_stored_pos() accesses that data. mca_read_pos()
-and mca_write_pos() are also available for (safer) direct POS access,
-but their use is _highly_ discouraged. mca_write_pos() is particularly
-dangerous, as it is possible for adapters to be put in inconsistent
-states (i.e. sharing IO address, etc) and may result in crashes, toasted
-hardware, and blindness.
-
-User level drivers (such as the AGX X server) can use /proc/mca/pos to
-find adapters (see below).
-
-Some MCA adapters can also be detected via the usual ISA-style device
-probing (many SCSI adapters, for example). This sort of thing is highly
-discouraged. Perfectly good information is available telling you what's
-there, so there's no excuse for messing with random IO ports. However,
-we MCA people still appreciate any ISA-style driver that will work with
-our hardware. You take what you can get...
-
-Level-Triggered Interrupts
-==========================
-
-Because MCA uses level-triggered interrupts, a few problems arise with
-what might best be described as the ISA mindset and its effects on
-drivers. These sorts of problems are expected to become less common as
-more people use shared IRQs on PCI machines.
-
-In general, an interrupt must be acknowledged not only at the ICU (which
-is done automagically by the kernel), but at the device level. In
-particular, IRQ 0 must be reset after a timer interrupt (now done in
-arch/x86/kernel/time.c) or the first timer interrupt hangs the system.
-There were also problems with the 1.3.x floppy drivers, but that seems
-to have been fixed.
-
-IRQs are also shareable, and most MCA-specific devices should be coded
-with shared IRQs in mind.
-
-/proc/mca
-=========
-
-/proc/mca is a directory containing various files for adapters and
-other stuff.
-
- /proc/mca/pos Straight listing of POS registers
- /proc/mca/slot[1-8] Information on adapter in specific slot
- /proc/mca/video Same for integrated video
- /proc/mca/scsi Same for integrated SCSI
- /proc/mca/machine Machine information
-
-See Appendix A for a sample.
-
-Device drivers can easily add their own information function for
-specific slots (including integrated ones) via the
-mca_set_adapter_procfn() call. Drivers that support this are ESDI, IBM
-SCSI, and 3c523. If a device is also a module, make sure that the proc
-function is removed in the module cleanup. This will require storing
-the slot information in a private structure somewhere. See the 3c523
-driver for details.
-
-Your typical proc function will look something like this:
-
- static int
- dev_getinfo( char* buf, int slot, void* d ) {
- struct net_device* dev = (struct net_device*) d;
- int len = 0;
-
- len += sprintf( buf+len, "Device: %s\n", dev->name );
- len += sprintf( buf+len, "IRQ: %d\n", dev->irq );
- len += sprintf( buf+len, "IO Port: %#lx-%#lx\n", ... );
- ...
-
- return len;
- }
-
-Some of the standard MCA information will already be printed, so don't
-bother repeating it. Don't try putting in more than 3K of information.
-
-Enable this function with:
- mca_set_adapter_procfn( slot, dev_getinfo, dev );
-
-Disable it with:
- mca_set_adapter_procfn( slot, NULL, NULL );
-
-It is also recommended that, even if you don't write a proc function, to
-set the name of the adapter (i.e. "PS/2 ESDI Controller") via
-mca_set_adapter_name( int slot, char* name ).
-
-MCA Device Drivers
-==================
-
-Currently, there are a number of MCA-specific device drivers.
-
-1) PS/2 SCSI
- drivers/scsi/ibmmca.c
- drivers/scsi/ibmmca.h
- The driver for the IBM SCSI subsystem. Includes both integrated
- controllers and adapter cards. May require command-line arg
- "ibmmcascsi=io_port" to force detection of an adapter. If you have a
- machine with a front-panel display (i.e. model 95), you can use
- "ibmmcascsi=display" to enable a drive activity indicator.
-
-2) 3c523
- drivers/net/3c523.c
- drivers/net/3c523.h
- 3Com 3c523 Etherlink/MC ethernet driver.
-
-3) SMC Ultra/MCA and IBM Adapter/A
- drivers/net/smc-mca.c
- drivers/net/smc-mca.h
- Driver for the MCA version of the SMC Ultra and various other
- OEM'ed and work-alike cards (Elite, Adapter/A, etc).
-
-4) NE/2
- driver/net/ne2.c
- driver/net/ne2.h
- The NE/2 is the MCA version of the NE2000. This may not work
- with clones that have a different adapter id than the original
- NE/2.
-
-5) Future Domain MCS-600/700, OEM'd IBM Fast SCSI Adapter/A and
- Reply Sound Blaster/SCSI (SCSI part)
- Better support for these cards than the driver for ISA.
- Supports multiple cards with IRQ sharing.
-
-Also added boot time option of scsi-probe, which can do reordering of
-SCSI host adapters. This will direct the kernel on the order which
-SCSI adapter should be detected. Example:
- scsi-probe=ibmmca,fd_mcs,adaptec1542,buslogic
-
-The serial drivers were modified to support the extended IO port range
-of the typical MCA system (also #ifdef CONFIG_MCA).
-
-The following devices work with existing drivers:
-1) Token-ring
-2) Future Domain SCSI (MCS-600, MCS-700, not MCS-350, OEM'ed IBM SCSI)
-3) Adaptec 1640 SCSI (using the aha1542 driver)
-4) Bustek/Buslogic SCSI (various)
-5) Probably all Arcnet cards.
-6) Some, possibly all, MCA IDE controllers.
-7) 3Com 3c529 (MCA version of 3c509) (patched)
-
-8) Intel EtherExpressMC (patched version)
- You need to have CONFIG_MCA defined to have EtherExpressMC support.
-9) Reply Sound Blaster/SCSI (SB part) (patched version)
-
-Bugs & Other Weirdness
-======================
-
-NMIs tend to occur with MCA machines because of various hardware
-weirdness, bus timeouts, and many other non-critical things. Some basic
-code to handle them (inspired by the NetBSD MCA code) has been added to
-detect the guilty device, but it's pretty incomplete. If NMIs are a
-persistent problem (on some model 70 or 80s, they occur every couple
-shell commands), the CONFIG_IGNORE_NMI flag will take care of that.
-
-Various Pentium machines have had serious problems with the FPU test in
-bugs.h. Basically, the machine hangs after the HLT test. This occurs,
-as far as we know, on the Pentium-equipped 85s, 95s, and some PC Servers.
-The PCI/MCA PC 750s are fine as far as I can tell. The ``mca-pentium''
-boot-prompt flag will disable the FPU bug check if this is a problem
-with your machine.
-
-The model 80 has a raft of problems that are just too weird and unique
-to get into here. Some people have no trouble while others have nothing
-but problems. I'd suspect some problems are related to the age of the
-average 80 and accompanying hardware deterioration, although others
-are definitely design problems with the hardware. Among the problems
-include SCSI controller problems, ESDI controller problems, and serious
-screw-ups in the floppy controller. Oh, and the parallel port is also
-pretty flaky. There were about 5 or 6 different model 80 motherboards
-produced to fix various obscure problems. As far as I know, it's pretty
-much impossible to tell which bugs a particular model 80 has (other than
-triggering them, that is).
-
-Drivers are required for some MCA memory adapters. If you're suddenly
-short a few megs of RAM, this might be the reason. The (I think) Enhanced
-Memory Adapter commonly found on the model 70 is one. There's a very
-alpha driver floating around, but it's pretty ugly (disassembled from
-the DOS driver, actually). See the MCA Linux web page (URL below)
-for more current memory info.
-
-The Thinkpad 700 and 720 will work, but various components are either
-non-functional, flaky, or we don't know anything about them. The
-graphics controller is supposed to be some WD, but we can't get things
-working properly. The PCMCIA slots don't seem to work. Ditto for APM.
-The serial ports work, but detection seems to be flaky.
-
-Credits
-=======
-A whole pile of people have contributed to the MCA code. I'd include
-their names here, but I don't have a list handy. Check the MCA Linux
-home page (URL below) for a perpetually out-of-date list.
-
-=====================================================================
-MCA Linux Home Page: http://www.dgmicro.com/mca/
-
-Christophe Beauregard
-chrisb@truespectra.com
-cpbeaure@calum.csclub.uwaterloo.ca
-
-=====================================================================
-Appendix A: Sample /proc/mca
-
-This is from my model 8595. Slot 1 contains the standard IBM SCSI
-adapter, slot 3 is an Adaptec AHA-1640, slot 5 is a XGA-1 video adapter,
-and slot 7 is the 3c523 Etherlink/MC.
-
-/proc/mca/machine:
-Model Id: 0xf8
-Submodel Id: 0x14
-BIOS Revision: 0x5
-
-/proc/mca/pos:
-Slot 1: ff 8e f1 fc a0 ff ff ff IBM SCSI Adapter w/Cache
-Slot 2: ff ff ff ff ff ff ff ff
-Slot 3: 1f 0f 81 3b bf b6 ff ff
-Slot 4: ff ff ff ff ff ff ff ff
-Slot 5: db 8f 1d 5e fd c0 00 00
-Slot 6: ff ff ff ff ff ff ff ff
-Slot 7: 42 60 ff 08 ff ff ff ff 3Com 3c523 Etherlink/MC
-Slot 8: ff ff ff ff ff ff ff ff
-Video : ff ff ff ff ff ff ff ff
-SCSI : ff ff ff ff ff ff ff ff
-
-/proc/mca/slot1:
-Slot: 1
-Adapter Name: IBM SCSI Adapter w/Cache
-Id: 8eff
-Enabled: Yes
-POS: ff 8e f1 fc a0 ff ff ff
-Subsystem PUN: 7
-Detected at boot: Yes
-
-/proc/mca/slot3:
-Slot: 3
-Adapter Name: Unknown
-Id: 0f1f
-Enabled: Yes
-POS: 1f 0f 81 3b bf b6 ff ff
-
-/proc/mca/slot5:
-Slot: 5
-Adapter Name: Unknown
-Id: 8fdb
-Enabled: Yes
-POS: db 8f 1d 5e fd c0 00 00
-
-/proc/mca/slot7:
-Slot: 7
-Adapter Name: 3Com 3c523 Etherlink/MC
-Id: 6042
-Enabled: Yes
-POS: 42 60 ff 08 ff ff ff ff
-Revision: 0xe
-IRQ: 9
-IO Address: 0x3300-0x3308
-Memory: 0xd8000-0xdbfff
-Transceiver: External
-Device: eth0
-Hardware Address: 02 60 8c 45 c4 2a
diff --git a/Documentation/media-framework.txt b/Documentation/media-framework.txt
index 3a0f879533ce..802875413873 100644
--- a/Documentation/media-framework.txt
+++ b/Documentation/media-framework.txt
@@ -335,6 +335,9 @@ the media_entity pipe field.
Calls to media_entity_pipeline_start() can be nested. The pipeline pointer must
be identical for all nested calls to the function.
+media_entity_pipeline_start() may return an error. In that case, it will
+clean up any the changes it did by itself.
+
When stopping the stream, drivers must notify the entities with
media_entity_pipeline_stop(struct media_entity *entity);
@@ -351,3 +354,19 @@ If other operations need to be disallowed on streaming entities (such as
changing entities configuration parameters) drivers can explicitly check the
media_entity stream_count field to find out if an entity is streaming. This
operation must be done with the media_device graph_mutex held.
+
+
+Link validation
+---------------
+
+Link validation is performed by media_entity_pipeline_start() for any
+entity which has sink pads in the pipeline. The
+media_entity::link_validate() callback is used for that purpose. In
+link_validate() callback, entity driver should check that the properties of
+the source pad of the connected entity and its own sink pad match. It is up
+to the type of the entity (and in the end, the properties of the hardware)
+what matching actually means.
+
+Subsystems should facilitate link validation by providing subsystem specific
+helper functions to provide easy access for commonly needed information, and
+in the end provide a way to use driver-specific callbacks.
diff --git a/Documentation/memory-devices/ti-emif.txt b/Documentation/memory-devices/ti-emif.txt
new file mode 100644
index 000000000000..f4ad9a7d0f4b
--- /dev/null
+++ b/Documentation/memory-devices/ti-emif.txt
@@ -0,0 +1,57 @@
+TI EMIF SDRAM Controller Driver:
+
+Author
+========
+Aneesh V <aneesh@ti.com>
+
+Location
+============
+driver/memory/emif.c
+
+Supported SoCs:
+===================
+TI OMAP44xx
+TI OMAP54xx
+
+Menuconfig option:
+==========================
+Device Drivers
+ Memory devices
+ Texas Instruments EMIF driver
+
+Description
+===========
+This driver is for the EMIF module available in Texas Instruments
+SoCs. EMIF is an SDRAM controller that, based on its revision,
+supports one or more of DDR2, DDR3, and LPDDR2 SDRAM protocols.
+This driver takes care of only LPDDR2 memories presently. The
+functions of the driver includes re-configuring AC timing
+parameters and other settings during frequency, voltage and
+temperature changes
+
+Platform Data (see include/linux/platform_data/emif_plat.h):
+=====================================================================
+DDR device details and other board dependent and SoC dependent
+information can be passed through platform data (struct emif_platform_data)
+- DDR device details: 'struct ddr_device_info'
+- Device AC timings: 'struct lpddr2_timings' and 'struct lpddr2_min_tck'
+- Custom configurations: customizable policy options through
+ 'struct emif_custom_configs'
+- IP revision
+- PHY type
+
+Interface to the external world:
+================================
+EMIF driver registers notifiers for voltage and frequency changes
+affecting EMIF and takes appropriate actions when these are invoked.
+- freq_pre_notify_handling()
+- freq_post_notify_handling()
+- volt_notify_handling()
+
+Debugfs
+========
+The driver creates two debugfs entries per device.
+- regcache_dump : dump of register values calculated and saved for all
+ frequencies used so far.
+- mr4 : last polled value of MR4 register in the LPDDR2 device. MR4
+ indicates the current temperature level of the device.
diff --git a/Documentation/memory-hotplug.txt b/Documentation/memory-hotplug.txt
index 8f485d72cf25..6d0c2519cf47 100644
--- a/Documentation/memory-hotplug.txt
+++ b/Documentation/memory-hotplug.txt
@@ -341,7 +341,7 @@ Need more implementation yet....
--------------------------------
8. Memory hotplug event notifier
--------------------------------
-Memory hotplug has event notifer. There are 6 types of notification.
+Memory hotplug has event notifier. There are 6 types of notification.
MEMORY_GOING_ONLINE
Generated before new memory becomes available in order to be able to
diff --git a/Documentation/misc-devices/mei/.gitignore b/Documentation/misc-devices/mei/.gitignore
new file mode 100644
index 000000000000..f356b81ca1ec
--- /dev/null
+++ b/Documentation/misc-devices/mei/.gitignore
@@ -0,0 +1 @@
+mei-amt-version
diff --git a/Documentation/misc-devices/mei/Makefile b/Documentation/misc-devices/mei/Makefile
new file mode 100644
index 000000000000..00e8c3e836ff
--- /dev/null
+++ b/Documentation/misc-devices/mei/Makefile
@@ -0,0 +1,8 @@
+# kbuild trick to avoid linker error. Can be omitted if a module is built.
+obj- := dummy.o
+
+# List of programs to build
+hostprogs-y := mei-amt-version
+HOSTCFLAGS_mei-amt-version.o += -I$(objtree)/usr/include
+# Tell kbuild to always build the programs
+always := $(hostprogs-y)
diff --git a/Documentation/misc-devices/mei/TODO b/Documentation/misc-devices/mei/TODO
new file mode 100644
index 000000000000..6b3625d3058c
--- /dev/null
+++ b/Documentation/misc-devices/mei/TODO
@@ -0,0 +1,2 @@
+TODO:
+ - Cleanup and split the timer function
diff --git a/drivers/staging/mei/mei-amt-version.c b/Documentation/misc-devices/mei/mei-amt-version.c
index ac2a507be253..01804f216312 100644
--- a/drivers/staging/mei/mei-amt-version.c
+++ b/Documentation/misc-devices/mei/mei-amt-version.c
@@ -74,7 +74,7 @@
#include <stdint.h>
#include <stdbool.h>
#include <bits/wordsize.h>
-#include "mei.h"
+#include <linux/mei.h>
/*****************************************************************************
* Intel Management Engine Interface
diff --git a/drivers/staging/mei/mei.txt b/Documentation/misc-devices/mei/mei.txt
index 2785697da59d..2785697da59d 100644
--- a/drivers/staging/mei/mei.txt
+++ b/Documentation/misc-devices/mei/mei.txt
diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt
index 56ca3b75376e..ac295399f0d4 100644
--- a/Documentation/networking/can.txt
+++ b/Documentation/networking/can.txt
@@ -649,7 +649,7 @@ solution for a couple of reasons:
The CAN device must be configured via netlink interface. The supported
netlink message types are defined and briefly described in
"include/linux/can/netlink.h". CAN link support for the program "ip"
- of the IPROUTE2 utility suite is avaiable and it can be used as shown
+ of the IPROUTE2 utility suite is available and it can be used as shown
below:
- Setting CAN device properties:
diff --git a/Documentation/nfc/nfc-hci.txt b/Documentation/nfc/nfc-hci.txt
index 216b7254fcc3..320f9336c781 100644
--- a/Documentation/nfc/nfc-hci.txt
+++ b/Documentation/nfc/nfc-hci.txt
@@ -22,9 +22,9 @@ response to arrive.
HCI events can also be received from the host controller. They will be handled
and a translation will be forwarded to NFC Core as needed.
HCI uses 2 execution contexts:
-- one if for executing commands : nfc_hci_msg_tx_work(). Only one command
+- one for executing commands : nfc_hci_msg_tx_work(). Only one command
can be executing at any given moment.
-- one if for dispatching received events and responses : nfc_hci_msg_rx_work()
+- one for dispatching received events and commands : nfc_hci_msg_rx_work().
HCI Session initialization:
---------------------------
@@ -52,18 +52,42 @@ entry points:
struct nfc_hci_ops {
int (*open)(struct nfc_hci_dev *hdev);
void (*close)(struct nfc_hci_dev *hdev);
+ int (*hci_ready) (struct nfc_hci_dev *hdev);
int (*xmit)(struct nfc_hci_dev *hdev, struct sk_buff *skb);
int (*start_poll)(struct nfc_hci_dev *hdev, u32 protocols);
int (*target_from_gate)(struct nfc_hci_dev *hdev, u8 gate,
struct nfc_target *target);
+ int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate,
+ struct nfc_target *target);
+ int (*data_exchange) (struct nfc_hci_dev *hdev,
+ struct nfc_target *target,
+ struct sk_buff *skb, struct sk_buff **res_skb);
+ int (*check_presence)(struct nfc_hci_dev *hdev,
+ struct nfc_target *target);
};
-open() and close() shall turn the hardware on and off. xmit() shall simply
-write a frame to the chip. start_poll() is an optional entrypoint that shall
-set the hardware in polling mode. This must be implemented only if the hardware
-uses proprietary gates or a mechanism slightly different from the HCI standard.
-target_from_gate() is another optional entrypoint to return the protocols
+- open() and close() shall turn the hardware on and off.
+- hci_ready() is an optional entry point that is called right after the hci
+session has been set up. The driver can use it to do additional initialization
+that must be performed using HCI commands.
+- xmit() shall simply write a frame to the chip.
+- start_poll() is an optional entrypoint that shall set the hardware in polling
+mode. This must be implemented only if the hardware uses proprietary gates or a
+mechanism slightly different from the HCI standard.
+- target_from_gate() is an optional entrypoint to return the nfc protocols
corresponding to a proprietary gate.
+- complete_target_discovered() is an optional entry point to let the driver
+perform additional proprietary processing necessary to auto activate the
+discovered target.
+- data_exchange() must be implemented by the driver if proprietary HCI commands
+are required to send data to the tag. Some tag types will require custom
+commands, others can be written to using the standard HCI commands. The driver
+can check the tag type and either do proprietary processing, or return 1 to ask
+for standard processing.
+- check_presence() is an optional entry point that will be called regularly
+by the core to check that an activated tag is still in the field. If this is
+not implemented, the core will not be able to push tag_lost events to the user
+space
On the rx path, the driver is responsible to push incoming HCP frames to HCI
using nfc_hci_recv_frame(). HCI will take care of re-aggregation and handling
@@ -99,7 +123,8 @@ fast, cannot sleep. stores incoming frames into an shdlc rx queue
handles shdlc rx & tx queues. Dispatches HCI cmd responses.
- HCI Tx Cmd worker (MSGTXWQ)
-Serialize execution of HCI commands. Complete execution in case of resp timeout.
+Serializes execution of HCI commands. Completes execution in case of response
+timeout.
- HCI Rx worker (MSGRXWQ)
Dispatches incoming HCI commands or events.
@@ -133,11 +158,11 @@ able to complete the command with a timeout error if no response arrive.
SMW context gets scheduled and invokes nfc_shdlc_sm_work(). This function
handles shdlc framing in and out. It uses the driver xmit to send frames and
receives incoming frames in an skb queue filled from the driver IRQ handler.
-SHDLC I(nformation) frames payload are HCP fragments. They are agregated to
+SHDLC I(nformation) frames payload are HCP fragments. They are aggregated to
form complete HCI frames, which can be a response, command, or event.
HCI Responses are dispatched immediately from this context to unblock
-waiting command execution. Reponse processing involves invoking the completion
+waiting command execution. Response processing involves invoking the completion
callback that was provided by nfc_hci_msg_tx_work() when it sent the command.
The completion callback will then wake the syscall context.
diff --git a/Documentation/parisc/debugging b/Documentation/parisc/debugging
index d728594058e5..7d75223fa18d 100644
--- a/Documentation/parisc/debugging
+++ b/Documentation/parisc/debugging
@@ -34,6 +34,6 @@ registers interruption handlers read to find out where the machine
was interrupted - so if you get an interruption between the instruction
that clears the Q bit and the RFI that sets it again you don't know
where exactly it happened. If you're lucky the IAOQ will point to the
-instrucion that cleared the Q bit, if you're not it points anywhere
+instruction that cleared the Q bit, if you're not it points anywhere
at all. Usually Q bit problems will show themselves in unexplainable
system hangs or running off the end of physical memory.
diff --git a/Documentation/power/suspend-and-cpuhotplug.txt b/Documentation/power/suspend-and-cpuhotplug.txt
index f28f9a6f0347..e13dafc8e8f1 100644
--- a/Documentation/power/suspend-and-cpuhotplug.txt
+++ b/Documentation/power/suspend-and-cpuhotplug.txt
@@ -29,7 +29,7 @@ More details follow:
Write 'mem' to
/sys/power/state
- syfs file
+ sysfs file
|
v
Acquire pm_mutex lock
diff --git a/Documentation/ramoops.txt b/Documentation/ramoops.txt
index 8fb1ba7fe7bf..4ba7db231cb2 100644
--- a/Documentation/ramoops.txt
+++ b/Documentation/ramoops.txt
@@ -3,7 +3,7 @@ Ramoops oops/panic logger
Sergiu Iordache <sergiu@chromium.org>
-Updated: 8 August 2011
+Updated: 17 November 2011
0. Introduction
@@ -30,6 +30,11 @@ variable while setting 0 in that variable dumps only the panics.
The module uses a counter to record multiple dumps but the counter gets reset
on restart (i.e. new dumps after the restart will overwrite old ones).
+Ramoops also supports software ECC protection of persistent memory regions.
+This might be useful when a hardware reset was used to bring the machine back
+to life (i.e. a watchdog triggered). In such cases, RAM may be somewhat
+corrupt, but usually it is restorable.
+
2. Setting the parameters
Setting the ramoops parameters can be done in 2 different manners:
@@ -38,7 +43,7 @@ Setting the ramoops parameters can be done in 2 different manners:
2. Use a platform device and set the platform data. The parameters can then
be set through that platform data. An example of doing that is:
-#include <linux/ramoops.h>
+#include <linux/pstore_ram.h>
[...]
static struct ramoops_platform_data ramoops_data = {
@@ -46,6 +51,7 @@ static struct ramoops_platform_data ramoops_data = {
.mem_address = <...>,
.record_size = <...>,
.dump_oops = <...>,
+ .ecc = <...>,
};
static struct platform_device ramoops_dev = {
@@ -71,6 +77,6 @@ timestamp and a new line. The dump then continues with the actual data.
4. Reading the data
-The dump data can be read from memory (through /dev/mem or other means).
-Getting the module parameters, which are needed in order to parse the data, can
-be done through /sys/module/ramoops/parameters/* .
+The dump data can be read from the pstore filesystem. The format for these
+files is "dmesg-ramoops-N", where N is the record number in memory. To delete
+a stored record from RAM, simply unlink the respective pstore file.
diff --git a/Documentation/scheduler/sched-design-CFS.txt b/Documentation/scheduler/sched-design-CFS.txt
index 91ecff07cede..d529e02d928d 100644
--- a/Documentation/scheduler/sched-design-CFS.txt
+++ b/Documentation/scheduler/sched-design-CFS.txt
@@ -130,7 +130,7 @@ CFS implements three scheduling policies:
idle timer scheduler in order to avoid to get into priority
inversion problems which would deadlock the machine.
-SCHED_FIFO/_RR are implemented in sched_rt.c and are as specified by
+SCHED_FIFO/_RR are implemented in sched/rt.c and are as specified by
POSIX.
The command chrt from util-linux-ng 2.13.1.1 can set all of these except
@@ -145,9 +145,9 @@ Classes," an extensible hierarchy of scheduler modules. These modules
encapsulate scheduling policy details and are handled by the scheduler core
without the core code assuming too much about them.
-sched_fair.c implements the CFS scheduler described above.
+sched/fair.c implements the CFS scheduler described above.
-sched_rt.c implements SCHED_FIFO and SCHED_RR semantics, in a simpler way than
+sched/rt.c implements SCHED_FIFO and SCHED_RR semantics, in a simpler way than
the previous vanilla scheduler did. It uses 100 runqueues (for all 100 RT
priority levels, instead of 140 in the previous scheduler) and it needs no
expired array.
diff --git a/Documentation/scheduler/sched-domains.txt b/Documentation/scheduler/sched-domains.txt
index b7ee379b651b..443f0c76bab4 100644
--- a/Documentation/scheduler/sched-domains.txt
+++ b/Documentation/scheduler/sched-domains.txt
@@ -61,10 +61,6 @@ The implementor should read comments in include/linux/sched.h:
struct sched_domain fields, SD_FLAG_*, SD_*_INIT to get an idea of
the specifics and what to tune.
-For SMT, the architecture must define CONFIG_SCHED_SMT and provide a
-cpumask_t cpu_sibling_map[NR_CPUS], where cpu_sibling_map[i] is the mask of
-all "i"'s siblings as well as "i" itself.
-
Architectures may retain the regular override the default SD_*_INIT flags
while using the generic domain builder in kernel/sched.c if they wish to
retain the traditional SMT->SMP->NUMA topology (or some subset of that). This
diff --git a/Documentation/scsi/00-INDEX b/Documentation/scsi/00-INDEX
index b7dd6502bec5..9b0787f965e9 100644
--- a/Documentation/scsi/00-INDEX
+++ b/Documentation/scsi/00-INDEX
@@ -56,8 +56,6 @@ g_NCR5380.txt
- info on driver for NCR5380 and NCR53c400 based adapters
hptiop.txt
- HIGHPOINT ROCKETRAID 3xxx RAID DRIVER
-ibmmca.txt
- - info on driver for IBM adapters with MCA bus
in2000.txt
- info on in2000 driver
libsas.txt
diff --git a/Documentation/scsi/ibmmca.txt b/Documentation/scsi/ibmmca.txt
deleted file mode 100644
index ac41a9fcac77..000000000000
--- a/Documentation/scsi/ibmmca.txt
+++ /dev/null
@@ -1,1402 +0,0 @@
-
- -=< The IBM Microchannel SCSI-Subsystem >=-
-
- for the IBM PS/2 series
-
- Low Level Software-Driver for Linux
-
- Copyright (c) 1995 Strom Systems, Inc. under the terms of the GNU
- General Public License. Originally written by Martin Kolinek, December 1995.
- Officially modified and maintained by Michael Lang since January 1999.
-
- Version 4.0a
-
- Last update: January 3, 2001
-
- Before you Start
- ----------------
- This is the common README.ibmmca file for all driver releases of the
- IBM MCA SCSI driver for Linux. Please note, that driver releases 4.0
- or newer do not work with kernel versions older than 2.4.0, while driver
- versions older than 4.0 do not work with kernels 2.4.0 or later! If you
- try to compile your kernel with the wrong driver source, the
- compilation is aborted and you get a corresponding error message. This is
- no bug in the driver; it prevents you from using the wrong source code
- with the wrong kernel version.
-
- Authors of this Driver
- ----------------------
- - Chris Beauregard (improvement of the SCSI-device mapping by the driver)
- - Martin Kolinek (origin, first release of this driver)
- - Klaus Kudielka (multiple SCSI-host management/detection, adaption to
- Linux Kernel 2.1.x, module support)
- - Michael Lang (assigning original pun/lun mapping, dynamical ldn
- assignment, rewritten adapter detection, this file,
- patches, official driver maintenance and subsequent
- debugging, related with the driver)
-
- Table of Contents
- -----------------
- 1 Abstract
- 2 Driver Description
- 2.1 IBM SCSI-Subsystem Detection
- 2.2 Physical Units, Logical Units, and Logical Devices
- 2.3 SCSI-Device Recognition and dynamical ldn Assignment
- 2.4 SCSI-Device Order
- 2.5 Regular SCSI-Command-Processing
- 2.6 Abort & Reset Commands
- 2.7 Disk Geometry
- 2.8 Kernel Boot Option
- 2.9 Driver Module Support
- 2.10 Multiple Hostadapter Support
- 2.11 /proc/scsi-Filesystem Information
- 2.12 /proc/mca-Filesystem Information
- 2.13 Supported IBM SCSI-Subsystems
- 2.14 Linux Kernel Versions
- 3 Code History
- 4 To do
- 5 Users' Manual
- 5.1 Commandline Parameters
- 5.2 Troubleshooting
- 5.3 Bug reports
- 5.4 Support WWW-page
- 6 References
- 7 Credits to
- 7.1 People
- 7.2 Sponsors & Supporters
- 8 Trademarks
- 9 Disclaimer
-
- * * *
-
- 1 Abstract
- ----------
- This README-file describes the IBM SCSI-subsystem low level driver for
- Linux. The descriptions which were formerly kept in the source code have
- been taken out of this file to simplify the codes readability. The driver
- description has been updated, as most of the former description was already
- quite outdated. The history of the driver development is also kept inside
- here. Multiple historical developments have been summarized to shorten the
- text size a bit. At the end of this file you can find a small manual for
- this driver and hints to get it running on your machine.
-
- 2 Driver Description
- --------------------
- 2.1 IBM SCSI-Subsystem Detection
- --------------------------------
- This is done in the ibmmca_detect() function. It first checks, if the
- Microchannel-bus support is enabled, as the IBM SCSI-subsystem needs the
- Microchannel. In a next step, a free interrupt is chosen and the main
- interrupt handler is connected to it to handle answers of the SCSI-
- subsystem(s). If the F/W SCSI-adapter is forced by the BIOS to use IRQ11
- instead of IRQ14, IRQ11 is used for the IBM SCSI-2 F/W adapter. In a
- further step it is checked, if the adapter gets detected by force from
- the kernel commandline, where the I/O port and the SCSI-subsystem id can
- be specified. The next step checks if there is an integrated SCSI-subsystem
- installed. This register area is fixed through all IBM PS/2 MCA-machines
- and appears as something like a virtual slot 10 of the MCA-bus. On most
- PS/2 machines, the POS registers of slot 10 are set to 0xff or 0x00 if not
- integrated SCSI-controller is available. But on certain PS/2s, like model
- 9595, this slot 10 is used to store other information which at earlier
- stage confused the driver and resulted in the detection of some ghost-SCSI.
- If POS-register 2 and 3 are not 0x00 and not 0xff, but all other POS
- registers are either 0xff or 0x00, there must be an integrated SCSI-
- subsystem present and it will be registered as IBM Integrated SCSI-
- Subsystem. The next step checks, if there is a slot-adapter installed on
- the MCA-bus. To get this, the first two POS-registers, that represent the
- adapter ID are checked. If they fit to one of the ids, stored in the
- adapter list, a SCSI-subsystem is assumed to be found in a slot and will be
- registered. This check is done through all possible MCA-bus slots to allow
- more than one SCSI-adapter to be present in the PS/2-system and this is
- already the first point of problems. Looking into the technical reference
- manual for the IBM PS/2 common interfaces, the POS2 register must have
- different interpretation of its single bits to avoid overlapping I/O
- regions. While one can assume, that the integrated subsystem has a fix
- I/O-address at 0x3540 - 0x3547, further installed IBM SCSI-adapters must
- use a different I/O-address. This is expressed by bit 1 to 3 of POS2
- (multiplied by 8 + 0x3540). Bits 2 and 3 are reserved for the integrated
- subsystem, but not for the adapters! The following list shows, how the
- bits of POS2 and POS3 should be interpreted.
-
- The POS2-register of all PS/2 models' integrated SCSI-subsystems has the
- following interpretation of bits:
- Bit 7 - 4 : Chip Revision ID (Release)
- Bit 3 - 2 : Reserved
- Bit 1 : 8k NVRAM Disabled
- Bit 0 : Chip Enable (EN-Signal)
- The POS3-register is interpreted as follows (for most IBM SCSI-subsys.):
- Bit 7 - 5 : SCSI ID
- Bit 4 - 0 : Reserved = 0
- The slot-adapters have different interpretation of these bits. The IBM SCSI
- adapter (w/Cache) and the IBM SCSI-2 F/W adapter use the following
- interpretation of the POS2 register:
- Bit 7 - 4 : ROM Segment Address Select
- Bit 3 - 1 : Adapter I/O Address Select (*8+0x3540)
- Bit 0 : Adapter Enable (EN-Signal)
- and for the POS3 register:
- Bit 7 - 5 : SCSI ID
- Bit 4 : Fairness Enable (SCSI ID3 f. F/W)
- Bit 3 - 0 : Arbitration Level
- The most modern product of the series is the IBM SCSI-2 F/W adapter, it
- allows dual-bus SCSI and SCSI-wide addressing, which means, PUNs may be
- between 0 and 15. Here, Bit 4 is the high-order bit of the 4-bit wide
- adapter PUN expression. In short words, this means, that IBM PS/2 machines
- can only support 1 single integrated subsystem by default. Additional
- slot-adapters get ports assigned by the automatic configuration tool.
-
- One day I found a patch in ibmmca_detect(), forcing the I/O-address to be
- 0x3540 for integrated SCSI-subsystems, there was a remark placed, that on
- integrated IBM SCSI-subsystems of model 56, the POS2 register was showing 5.
- This means, that really for these models, POS2 has to be interpreted
- sticking to the technical reference guide. In this case, the bit 2 (4) is
- a reserved bit and may not be interpreted. These differences between the
- adapters and the integrated controllers are taken into account by the
- detection routine of the driver on from version >3.0g.
-
- Every time, a SCSI-subsystem is discovered, the ibmmca_register() function
- is called. This function checks first, if the requested area for the I/O-
- address of this SCSI-subsystem is still available and assigns this I/O-
- area to the SCSI-subsystem. There are always 8 sequential I/O-addresses
- taken for each individual SCSI-subsystem found, which are:
-
- Offset Type Permissions
- 0 Command Interface Register 1 Read/Write
- 1 Command Interface Register 2 Read/Write
- 2 Command Interface Register 3 Read/Write
- 3 Command Interface Register 4 Read/Write
- 4 Attention Register Read/Write
- 5 Basic Control Register Read/Write
- 6 Interrupt Status Register Read
- 7 Basic Status Register Read
-
- After the I/O-address range is assigned, the host-adapter is assigned
- to a local structure which keeps all adapter information needed for the
- driver itself and the mid- and higher-level SCSI-drivers. The SCSI pun/lun
- and the adapters' ldn tables are initialized and get probed afterwards by
- the check_devices() function. If no further adapters are found,
- ibmmca_detect() quits.
-
- 2.2 Physical Units, Logical Units, and Logical Devices
- ------------------------------------------------------
- There can be up to 56 devices on the SCSI bus (besides the adapter):
- there are up to 7 "physical units" (each identified by physical unit
- number or pun, also called the scsi id, this is the number you select
- with hardware jumpers), and each physical unit can have up to 8
- "logical units" (each identified by logical unit number, or lun,
- between 0 and 7). The IBM SCSI-2 F/W adapter offers this on up to two
- busses and provides support for 30 logical devices at the same time, where
- in wide-addressing mode you can have 16 puns with 32 luns on each device.
- This section describes the handling of devices on non-F/W adapters.
- Just imagine, that you can have 16 * 32 = 512 devices on a F/W adapter
- which means a lot of possible devices for such a small machine.
-
- Typically the adapter has pun=7, so puns of other physical units
- are between 0 and 6(15). On a wide-adapter a pun higher than 7 is
- possible, but is normally not used. Almost all physical units have only
- one logical unit, with lun=0. A CD-ROM jukebox would be an example of a
- physical unit with more than one logical unit.
-
- The embedded microprocessor of the IBM SCSI-subsystem hides the complex
- two-dimensional (pun,lun) organization from the operating system.
- When the machine is powered-up (or rebooted), the embedded microprocessor
- checks, on its own, all 56 possible (pun,lun) combinations, and the first
- 15 devices found are assigned into a one-dimensional array of so-called
- "logical devices", identified by "logical device numbers" or ldn. The last
- ldn=15 is reserved for the subsystem itself. Wide adapters may have
- to check up to 15 * 8 = 120 pun/lun combinations.
-
- 2.3 SCSI-Device Recognition and Dynamical ldn Assignment
- --------------------------------------------------------
- One consequence of information hiding is that the real (pun,lun)
- numbers are also hidden. The two possibilities to get around this problem
- are to offer fake pun/lun combinations to the operating system or to
- delete the whole mapping of the adapter and to reassign the ldns, using
- the immediate assign command of the SCSI-subsystem for probing through
- all possible pun/lun combinations. An ldn is a "logical device number"
- which is used by IBM SCSI-subsystems to access some valid SCSI-device.
- At the beginning of the development of this driver, the following approach
- was used:
-
- First, the driver checked the ldn's (0 to 6) to find out which ldn's
- have devices assigned. This was done by the functions check_devices() and
- device_exists(). The interrupt handler has a special paragraph of code
- (see local_checking_phase_flag) to assist in the checking. Assume, for
- example, that three logical devices were found assigned at ldn 0, 1, 2.
- These are presented to the upper layer of Linux SCSI driver
- as devices with bogus (pun, lun) equal to (0,0), (1,0), (2,0).
- On the other hand, if the upper layer issues a command to device
- say (4,0), this driver returns DID_NO_CONNECT error.
-
- In a second step of the driver development, the following improvement has
- been applied: The first approach limited the number of devices to 7, far
- fewer than the 15 that it could use, then it just mapped ldn ->
- (ldn/8,ldn%8) for pun,lun. We ended up with a real mishmash of puns
- and luns, but it all seemed to work.
-
- The latest development, which is implemented from the driver version 3.0
- and later, realizes the device recognition in the following way:
- The physical SCSI-devices on the SCSI-bus are probed via immediate_assign-
- and device_inquiry-commands, that is all implemented in a completely new
- made check_devices() subroutine. This delivers an exact map of the physical
- SCSI-world that is now stored in the get_scsi[][]-array. This means,
- that the once hidden pun,lun assignment is now known to this driver.
- It no longer believes in default-settings of the subsystem and maps all
- ldns to existing pun,lun "by foot". This assures full control of the ldn
- mapping and allows dynamical remapping of ldns to different pun,lun, if
- there are more SCSI-devices installed than ldns available (n>15). The
- ldns from 0 to 6 get 'hardwired' by this driver to puns 0 to 7 at lun=0,
- excluding the pun of the subsystem. This assures, that at least simple
- SCSI-installations have optimum access-speed and are not touched by
- dynamical remapping. The ldns 7 to 14 are put to existing devices with
- lun>0 or to non-existing devices, in order to satisfy the subsystem, if
- there are less than 15 SCSI-devices connected. In the case of more than 15
- devices, the dynamical mapping goes active. If the get_scsi[][] reports a
- device to be existent, but it has no ldn assigned, it gets an ldn out of 7
- to 14. The numbers are assigned in cyclic order, therefore it takes 8
- dynamical reassignments on the SCSI-devices until a certain device
- loses its ldn again. This assures that dynamical remapping is avoided
- during intense I/O between up to 15 SCSI-devices (means pun,lun
- combinations). A further advantage of this method is that people who
- build their kernel without probing on all luns will get what they expect,
- because the driver just won't assign everything with lun>0 when
- multiple lun probing is inactive.
-
- 2.4 SCSI-Device Order
- ---------------------
- Because of the now correct recognition of physical pun,lun, and
- their report to mid-level- and higher-level-drivers, the new reported puns
- can be different from the old, faked puns. Therefore, Linux will eventually
- change /dev/sdXXX assignments and prompt you for corrupted superblock
- repair on boottime. In this case DO NOT PANIC, YOUR DISKS ARE STILL OK!!!
- You have to reboot (CTRL-D) with an old kernel and set the /etc/fstab-file
- entries right. After that, the system should come up as errorfree as before.
- If your boot-partition is not coming up, also edit the /etc/lilo.conf-file
- in a Linux session booted on old kernel and run lilo before reboot. Check
- lilo.conf anyway to get boot on other partitions with foreign OSes right
- again. But there exists a feature of this driver that allows you to change
- the assignment order of the SCSI-devices by flipping the PUN-assignment.
- See the next paragraph for a description.
-
- The problem for this is, that Linux does not assign the SCSI-devices in the
- way as described in the ANSI-SCSI-standard. Linux assigns /dev/sda to
- the device with at minimum id 0. But the first drive should be at id 6,
- because for historical reasons, drive at id 6 has, by hardware, the highest
- priority and a drive at id 0 the lowest. IBM was one of the rare producers,
- where the BIOS assigns drives belonging to the ANSI-SCSI-standard. Most
- other producers' BIOS does not (I think even Adaptec-BIOS). The
- IBMMCA_SCSI_ORDER_STANDARD flag, which you set while configuring the
- kernel enables to choose the preferred way of SCSI-device-assignment.
- Defining this flag would result in Linux determining the devices in the
- same order as DOS and OS/2 does on your MCA-machine. This is also standard
- on most industrial computers and OSes, like e.g. OS-9. Leaving this flag
- undefined will get your devices ordered in the default way of Linux. See
- also the remarks of Chris Beauregard from Dec 15, 1997 and the followups
- in section 3.
-
- 2.5 Regular SCSI-Command-Processing
- -----------------------------------
- Only three functions get involved: ibmmca_queuecommand(), issue_cmd(),
- and interrupt_handler().
-
- The upper layer issues a scsi command by calling function
- ibmmca_queuecommand(). This function fills a "subsystem control block"
- (scb) and calls a local function issue_cmd(), which writes a scb
- command into subsystem I/O ports. Once the scb command is carried out,
- the interrupt_handler() is invoked. If a device is determined to be
- existent and it has not assigned any ldn, it gets one dynamically.
- For this, the whole stuff is done in ibmmca_queuecommand().
-
- 2.6 Abort & Reset Commands
- --------------------------
- These are implemented with busy waiting for interrupt to arrive.
- ibmmca_reset() and ibmmca_abort() do not work sufficiently well
- up to now and need still a lot of development work. This seems
- to be a problem with other low-level SCSI drivers too, however
- this should be no excuse.
-
- 2.7 Disk Geometry
- -----------------
- The ibmmca_biosparams() function should return the same disk geometry
- as the bios. This is needed for fdisk, etc. The returned geometry is
- certainly correct for disks smaller than 1 gigabyte. In the meantime,
- it has been proved, that this works fine even with disks larger than
- 1 gigabyte.
-
- 2.8 Kernel Boot Option
- ----------------------
- The function ibmmca_scsi_setup() is called if option ibmmcascsi=n
- is passed to the kernel. See file linux/init/main.c for details.
-
- 2.9 Driver Module Support
- -------------------------
- Is implemented and tested by K. Kudielka. This could probably not work
- on kernels <2.1.0.
-
- 2.10 Multiple Hostadapter Support
- ---------------------------------
- This driver supports up to eight interfaces of type IBM-SCSI-Subsystem.
- Integrated-, and MCA-adapters are automatically recognized. Unrecognizable
- IBM-SCSI-Subsystem interfaces can be specified as kernel-parameters.
-
- 2.11 /proc/scsi-Filesystem Information
- --------------------------------------
- Information about the driver condition is given in
- /proc/scsi/ibmmca/<host_no>. ibmmca_proc_info() provides this information.
-
- This table is quite informative for interested users. It shows the load
- of commands on the subsystem and whether you are running the bypassed
- (software) or integrated (hardware) SCSI-command set (see below). The
- amount of accesses is shown. Read, write, modeselect is shown separately
- in order to help debugging problems with CD-ROMs or tapedrives.
-
- The following table shows the list of 15 logical device numbers, that are
- used by the SCSI-subsystem. The load on each ldn is shown in the table,
- again, read and write commands are split. The last column shows the amount
- of reassignments, that have been applied to the ldns, if you have more than
- 15 pun/lun combinations available on the SCSI-bus.
-
- The last two tables show the pun/lun map and the positions of the ldns
- on this pun/lun map. This may change during operation, when a ldn is
- reassigned to another pun/lun combination. If the necessity for dynamical
- assignments is set to 'no', the ldn structure keeps static.
-
- 2.12 /proc/mca-Filesystem Information
- -------------------------------------
- The slot-file contains all default entries and in addition chip and I/O-
- address information of the SCSI-subsystem. This information is provided
- by ibmmca_getinfo().
-
- 2.13 Supported IBM SCSI-Subsystems
- ----------------------------------
- The following IBM SCSI-subsystems are supported by this driver:
-
- - IBM Fast/Wide SCSI-2 Adapter
- - IBM 7568 Industrial Computer SCSI Adapter w/Cache
- - IBM Expansion Unit SCSI Controller
- - IBM SCSI Adapter w/Cache
- - IBM SCSI Adapter
- - IBM Integrated SCSI Controller
- - All clones, 100% compatible with the chipset and subsystem command
- system of IBM SCSI-adapters (forced detection)
-
- 2.14 Linux Kernel Versions
- --------------------------
- The IBM SCSI-subsystem low level driver is prepared to be used with
- all versions of Linux between 2.0.x and 2.4.x. The compatibility checks
- are fully implemented up from version 3.1e of the driver. This means, that
- you just need the latest ibmmca.h and ibmmca.c file and copy it in the
- linux/drivers/scsi directory. The code is automatically adapted during
- kernel compilation. This is different from kernel 2.4.0! Here version
- 4.0 or later of the driver must be used for kernel 2.4.0 or later. Version
- 4.0 or later does not work together with older kernels! Driver versions
- older than 4.0 do not work together with kernel 2.4.0 or later. They work
- on all older kernels.
-
- 3 Code History
- --------------
- Jan 15 1996: First public release.
- - Martin Kolinek
-
- Jan 23 1996: Scrapped code which reassigned scsi devices to logical
- device numbers. Instead, the existing assignment (created
- when the machine is powered-up or rebooted) is used.
- A side effect is that the upper layer of Linux SCSI
- device driver gets bogus scsi ids (this is benign),
- and also the hard disks are ordered under Linux the
- same way as they are under dos (i.e., C: disk is sda,
- D: disk is sdb, etc.).
- - Martin Kolinek
-
- I think that the CD-ROM is now detected only if a CD is
- inside CD_ROM while Linux boots. This can be fixed later,
- once the driver works on all types of PS/2's.
- - Martin Kolinek
-
- Feb 7 1996: Modified biosparam function. Fixed the CD-ROM detection.
- For now, devices other than harddisk and CD_ROM are
- ignored. Temporarily modified abort() function
- to behave like reset().
- - Martin Kolinek
-
- Mar 31 1996: The integrated scsi subsystem is correctly found
- in PS/2 models 56,57, but not in model 76. Therefore
- the ibmmca_scsi_setup() function has been added today.
- This function allows the user to force detection of
- scsi subsystem. The kernel option has format
- ibmmcascsi=n
- where n is the scsi_id (pun) of the subsystem. Most likely, n is 7.
- - Martin Kolinek
-
- Aug 21 1996: Modified the code which maps ldns to (pun,0). It was
- insufficient for those of us with CD-ROM changers.
- - Chris Beauregard
-
- Dec 14 1996: More improvements to the ldn mapping. See check_devices
- for details. Did more fiddling with the integrated SCSI detection,
- but I think it's ultimately hopeless without actually testing the
- model of the machine. The 56, 57, 76 and 95 (ultimedia) all have
- different integrated SCSI register configurations. However, the 56
- and 57 are the only ones that have problems with forced detection.
- - Chris Beauregard
-
- Mar 8-16 1997: Modified driver to run as a module and to support
- multiple adapters. A structure, called ibmmca_hostdata, is now
- present, containing all the variables, that were once only
- available for one single adapter. The find_subsystem-routine has vanished.
- The hardware recognition is now done in ibmmca_detect directly.
- This routine checks for presence of MCA-bus, checks the interrupt
- level and continues with checking the installed hardware.
- Certain PS/2-models do not recognize a SCSI-subsystem automatically.
- Hence, the setup defined by command-line-parameters is checked first.
- Thereafter, the routine probes for an integrated SCSI-subsystem.
- Finally, adapters are checked. This method has the advantage to cover all
- possible combinations of multiple SCSI-subsystems on one MCA-board. Up to
- eight SCSI-subsystems can be recognized and announced to the upper-level
- drivers with this improvement. A set of defines made changes to other
- routines as small as possible.
- - Klaus Kudielka
-
- May 30 1997: (v1.5b)
- 1) SCSI-command capability enlarged by the recognition of MODE_SELECT.
- This needs the RD-Bit to be disabled on IM_OTHER_SCSI_CMD_CMD which
- allows data to be written from the system to the device. It is a
- necessary step to be allowed to set blocksize of SCSI-tape-drives and
- the tape-speed, without confusing the SCSI-Subsystem.
- 2) The recognition of a tape is included in the check_devices routine.
- This is done by checking for TYPE_TAPE, that is already defined in
- the kernel-scsi-environment. The markup of a tape is done in the
- global ldn_is_tape[] array. If the entry on index ldn
- is 1, there is a tapedrive connected.
- 3) The ldn_is_tape[] array is necessary to distinguish between tape- and
- other devices. Fixed blocklength devices should not cause a problem
- with the SCB-command for read and write in the ibmmca_queuecommand
- subroutine. Therefore, I only derivate the READ_XX, WRITE_XX for
- the tape-devices, as recommended by IBM in this Technical Reference,
- mentioned below. (IBM recommends to avoid using the read/write of the
- subsystem, but the fact was, that read/write causes a command error from
- the subsystem and this causes kernel-panic.)
- 4) In addition, I propose to use the ldn instead of a fix char for the
- display of PS2_DISK_LED_ON(). On 95, one can distinguish between the
- devices that are accessed. It shows activity and easyfies debugging.
- The tape-support has been tested with a SONY SDT-5200 and a HP DDS-2
- (I do not know yet the type). Optimization and CD-ROM audio-support,
- I am working on ...
- - Michael Lang
-
- June 19 1997: (v1.6b)
- 1) Submitting the extra-array ldn_is_tape[] -> to the local ld[]
- device-array.
- 2) CD-ROM Audio-Play seems to work now.
- 3) When using DDS-2 (120M) DAT-Tapes, mtst shows still density-code
- 0x13 for ordinary DDS (61000 BPM) instead 0x24 for DDS-2. This appears
- also on Adaptec 2940 adaptor in a PCI-System. Therefore, I assume that
- the problem is independent of the low-level-driver/bus-architecture.
- 4) Hexadecimal ldn on PS/2-95 LED-display.
- 5) Fixing of the PS/2-LED on/off that it works right with tapedrives and
- does not confuse the disk_rw_in_progress counter.
- - Michael Lang
-
- June 21 1997: (v1.7b)
- 1) Adding of a proc_info routine to inform in /proc/scsi/ibmmca/<host> the
- outer-world about operational load statistics on the different ldns,
- seen by the driver. Everybody that has more than one IBM-SCSI should
- test this, because I only have one and cannot see what happens with more
- than one IBM-SCSI hosts.
- 2) Definition of a driver version-number to have a better recognition of
- the source when there are existing too much releases that may confuse
- the user, when reading about release-specific problems. Up to know,
- I calculated the version-number to be 1.7. Because we are in BETA-test
- yet, it is today 1.7b.
- 3) Sorry for the heavy bug I programmed on June 19 1997! After that, the
- CD-ROM did not work any more! The C7-command was a fake impression
- I got while programming. Now, the READ and WRITE commands for CD-ROM are
- no longer running over the subsystem, but just over
- IM_OTHER_SCSI_CMD_CMD. On my observations (PS/2-95), now CD-ROM mounts
- much faster(!) and hopefully all fancy multimedia-functions, like direct
- digital recording from audio-CDs also work. (I tried it with cdda2wav
- from the cdwtools-package and it filled up the harddisk immediately :-).)
- To easify boolean logics, a further local device-type in ld[], called
- is_cdrom has been included.
- 4) If one uses a SCSI-device of unsupported type/commands, one
- immediately runs into a kernel-panic caused by Command Error. To better
- understand which SCSI-command caused the problem, I extended this
- specific panic-message slightly.
- - Michael Lang
-
- June 25 1997: (v1.8b)
- 1) Some cosmetic changes for the handling of SCSI-device-types.
- Now, also CD-Burners / WORMs and SCSI-scanners should work. For
- MO-drives I have no experience, therefore not yet supported.
- In logical_devices I changed from different type-variables to one
- called 'device_type' where the values, corresponding to scsi.h,
- of a SCSI-device are stored.
- 2) There existed a small bug, that maps a device, coming after a SCSI-tape
- wrong. Therefore, e.g. a CD-ROM changer would have been mapped wrong
- -> problem removed.
- 3) Extension of the logical_device structure. Now it contains also device,
- vendor and revision-level of a SCSI-device for internal usage.
- - Michael Lang
-
- June 26-29 1997: (v2.0b)
- 1) The release number 2.0b is necessary because of the completely new done
- recognition and handling of SCSI-devices with the adapter. As I got
- from Chris the hint, that the subsystem can reassign ldns dynamically,
- I remembered this immediate_assign-command, I found once in the handbook.
- Now, the driver first kills all ldn assignments that are set by default
- on the SCSI-subsystem. After that, it probes on all puns and luns for
- devices by going through all combinations with immediate_assign and
- probing for devices, using device_inquiry. The found physical(!) pun,lun
- structure is stored in get_scsi[][] as device types. This is followed
- by the assignment of all ldns to existing SCSI-devices. If more ldns
- than devices are available, they are assigned to non existing pun,lun
- combinations to satisfy the adapter. With this, the dynamical mapping
- was possible to implement. (For further info see the text in the
- source code and in the description below. Read the description
- below BEFORE installing this driver on your system!)
- 2) Changed the name IBMMCA_DRIVER_VERSION to IBMMCA_SCSI_DRIVER_VERSION.
- 3) The LED-display shows on PS/2-95 no longer the ldn, but the SCSI-ID
- (pun) of the accessed SCSI-device. This is now senseful, because the
- pun known within the driver is exactly the pun of the physical device
- and no longer a fake one.
- 4) The /proc/scsi/ibmmca/<host_no> consists now of the first part, where
- hit-statistics of ldns is shown and a second part, where the maps of
- physical and logical SCSI-devices are displayed. This could be very
- interesting, when one is using more than 15 SCSI-devices in order to
- follow the dynamical remapping of ldns.
- - Michael Lang
-
- June 26-29 1997: (v2.0b-1)
- 1) I forgot to switch the local_checking_phase_flag to 1 and back to 0
- in the dynamical remapping part in ibmmca_queuecommand for the
- device_exist routine. Sorry.
- - Michael Lang
-
- July 1-13 1997: (v3.0b,c)
- 1) Merging of the driver-developments of Klaus Kudielka and Michael Lang
- in order to get a optimum and unified driver-release for the
- IBM-SCSI-Subsystem-Adapter(s).
- For people, using the Kernel-release >=2.1.0, module-support should
- be no problem. For users, running under <2.1.0, module-support may not
- work, because the methods have changed between 2.0.x and 2.1.x.
- 2) Added some more effective statistics for /proc-output.
- 3) Change typecasting at necessary points from (unsigned long) to
- virt_to_bus().
- 4) Included #if... at special points to have specific adaption of the
- driver to kernel 2.0.x and 2.1.x. It should therefore also run with
- later releases.
- 5) Magneto-Optical drives and medium-changers are also recognized, now.
- Therefore, we have a completely gapfree recognition of all SCSI-
- device-types, that are known by Linux up to kernel 2.1.31.
- 6) The flag SCSI_IBMMCA_DEV_RESET has been inserted. If it is set within
- the configuration, each connected SCSI-device will get a reset command
- during boottime. This can be necessary for some special SCSI-devices.
- This flag should be included in Config.in.
- (See also the new Config.in file.)
- Probable next improvement: bad disk handler.
- - Michael Lang
-
- Sept 14 1997: (v3.0c)
- 1) Some debugging and speed optimization applied.
- - Michael Lang
-
- Dec 15, 1997
- - chrisb@truespectra.com
- - made the front panel display thingy optional, specified from the
- command-line via ibmmcascsi=display. Along the lines of the /LED
- option for the OS/2 driver.
- - fixed small bug in the LED display that would hang some machines.
- - reversed ordering of the drives (using the
- IBMMCA_SCSI_ORDER_STANDARD define). This is necessary for two main
- reasons:
- - users who've already installed Linux won't be screwed. Keep
- in mind that not everyone is a kernel hacker.
- - be consistent with the BIOS ordering of the drives. In the
- BIOS, id 6 is C:, id 0 might be D:. With this scheme, they'd be
- backwards. This confuses the crap out of those heathens who've
- got a impure Linux installation (which, <wince>, I'm one of).
- This whole problem arises because IBM is actually non-standard with
- the id to BIOS mappings. You'll find, in fdomain.c, a similar
- comment about a few FD BIOS revisions. The Linux (and apparently
- industry) standard is that C: maps to scsi id (0,0). Let's stick
- with that standard.
- - Since this is technically a branch of my own, I changed the
- version number to 3.0e-cpb.
-
- Jan 17, 1998: (v3.0f)
- 1) Addition of some statistical info for /proc in proc_info.
- 2) Taking care of the SCSI-assignment problem, dealed by Chris at Dec 15
- 1997. In fact, IBM is right, concerning the assignment of SCSI-devices
- to driveletters. It is conform to the ANSI-definition of the SCSI-
- standard to assign drive C: to SCSI-id 6, because it is the highest
- hardware priority after the hostadapter (that has still today by
- default everywhere id 7). Also realtime-operating systems that I use,
- like LynxOS and OS9, which are quite industrial systems use top-down
- numbering of the harddisks, that is also starting at id 6. Now, one
- sits a bit between two chairs. On one hand side, using the define
- IBMMCA_SCSI_ORDER_STANDARD makes Linux assigning disks conform to
- the IBM- and ANSI-SCSI-standard and keeps this driver downward
- compatible to older releases, on the other hand side, people is quite
- habituated in believing that C: is assigned to (0,0) and much other
- SCSI-BIOS do so. Therefore, I moved the IBMMCA_SCSI_ORDER_STANDARD
- define out of the driver and put it into Config.in as subitem of
- 'IBM SCSI support'. A help, added to Documentation/Configure.help
- explains the differences between saying 'y' or 'n' to the user, when
- IBMMCA_SCSI_ORDER_STANDARD prompts, so the ordinary user is enabled to
- choose the way of assignment, depending on his own situation and gusto.
- 3) Adapted SCSI_IBMMCA_DEV_RESET to the local naming convention, so it is
- now called IBMMCA_SCSI_DEV_RESET.
- 4) Optimization of proc_info and its subroutines.
- 5) Added more in-source-comments and extended the driver description by
- some explanation about the SCSI-device-assignment problem.
- - Michael Lang
-
- Jan 18, 1998: (v3.0g)
- 1) Correcting names to be absolutely conform to the later 2.1.x releases.
- This is necessary for
- IBMMCA_SCSI_DEV_RESET -> CONFIG_IBMMCA_SCSI_DEV_RESET
- IBMMCA_SCSI_ORDER_STANDARD -> CONFIG_IBMMCA_SCSI_ORDER_STANDARD
- - Michael Lang
-
- Jan 18, 1999: (v3.1 MCA-team internal)
- 1) The multiple hosts structure is accessed from every subroutine, so there
- is no longer the address of the device structure passed from function
- to function, but only the hostindex. A call by value, nothing more. This
- should really be understood by the compiler and the subsystem should get
- the right values and addresses.
- 2) The SCSI-subsystem detection was not complete and quite hugely buggy up
- to now, compared to the technical manual. The interpretation of the pos2
- register is not as assumed by people before, therefore, I dropped a note
- in the ibmmca_detect function to show the registers' interpretation.
- The pos-registers of integrated SCSI-subsystems do not contain any
- information concerning the IO-port offset, really. Instead, they contain
- some info about the adapter, the chip, the NVRAM .... The I/O-port is
- fixed to 0x3540 - 0x3547. There can be more than one adapters in the
- slots and they get an offset for the I/O area in order to get their own
- I/O-address area. See chapter 2 for detailed description. At least, the
- detection should now work right, even on models other than 95. The 95ers
- came happily around the bug, as their pos2 register contains always 0
- in the critical area. Reserved bits are not allowed to be interpreted,
- therefore, IBM is allowed to set those bits as they like and they may
- really vary between different PS/2 models. So, now, no interpretation
- of reserved bits - hopefully no trouble here anymore.
- 3) The command error, which you may get on models 55, 56, 57, 70, 77 and
- P70 may have been caused by the fact, that adapters of older design do
- not like sending commands to non-existing SCSI-devices and will react
- with a command error as a sign of protest. While this error is not
- present on IBM SCSI Adapter w/cache, it appears on IBM Integrated SCSI
- Adapters. Therefore, I implemented a workaround to forgive those
- adapters their protests, but it is marked up in the statistics, so
- after a successful boot, you can see in /proc/scsi/ibmmca/<host_number>
- how often the command errors have been forgiven to the SCSI-subsystem.
- If the number is bigger than 0, you have a SCSI subsystem of older
- design, what should no longer matter.
- 4) ibmmca_getinfo() has been adapted very carefully, so it shows in the
- slotn file really, what is senseful to be presented.
- 5) ibmmca_register() has been extended in its parameter list in order to
- pass the right name of the SCSI-adapter to Linux.
- - Michael Lang
-
- Feb 6, 1999: (v3.1)
- 1) Finally, after some 3.1Beta-releases, the 3.1 release. Sorry, for
- the delayed release, but it was not finished with the release of
- Kernel 2.2.0.
- - Michael Lang
-
- Feb 10, 1999 (v3.1)
- 1) Added a new commandline parameter called 'bypass' in order to bypass
- every integrated subsystem SCSI-command consequently in case of
- troubles.
- 2) Concatenated read_capacity requests to the harddisks. It gave a lot
- of troubles with some controllers and after I wanted to apply some
- extensions, it jumped out in the same situation, on my w/cache, as like
- on D. Weinehalls' Model 56, having integrated SCSI. This gave me the
- decisive hint to move the code-part out and declare it global. Now
- it seems to work far better and more stable. Let us see what
- the world thinks of it...
- 3) By the way, only Sony DAT-drives seem to show density code 0x13. A
- test with a HP drive gave right results, so the problem is vendor-
- specific and not a problem of the OS or the driver.
- - Michael Lang
-
- Feb 18, 1999 (v3.1d)
- 1) The abort command and the reset function have been checked for
- inconsistencies. From the logical point of thinking, they work
- at their optimum, now, but as the subsystem does not answer with an
- interrupt, abort never finishes, sigh...
- 2) Everything, that is accessed by a busmaster request from the adapter
- is now declared as global variable, even the return-buffer in the
- local checking phase. This assures, that no accesses to undefined memory
- areas are performed.
- 3) In ibmmca.h, the line unchecked_isa_dma is added with 1 in order to
- avoid memory-pointers for the areas higher than 16MByte in order to
- be sure, it also works on 16-Bit Microchannel bus systems.
- 4) A lot of small things have been found, but nothing that endangered the
- driver operations. Just it should be more stable, now.
- - Michael Lang
-
- Feb 20, 1999 (v3.1e)
- 1) I took the warning from the Linux Kernel Hackers Guide serious and
- checked the cmd->result return value to the done-function very carefully.
- It is obvious, that the IBM SCSI only delivers the tsb.dev_status, if
- some error appeared, else it is undefined. Now, this is fixed. Before
- any SCB command gets queued, the tsb.dev_status is set to 0, so the
- cmd->result won't screw up Linux higher level drivers.
- 2) The reset-function has slightly improved. This is still planned for
- abort. During the abort and the reset function, no interrupts are
- allowed. This is however quite hard to cope with, so the INT-status
- register is read. When the interrupt gets queued, one can find its
- status immediately on that register and is enabled to continue in the
- reset function. I had no chance to test this really, only in a bogus
- situation, I got this function running, but the situation was too much
- worse for Linux :-(, so tests will continue.
- 3) Buffers got now consistent. No open address mapping, as before and
- therefore no further troubles with the unassigned memory segmentation
- faults that scrambled probes on 95XX series and even on 85XX series,
- when the kernel is done in a not so perfectly fitting way.
- 4) Spontaneous interrupts from the subsystem, appearing without any
- command previously queued are answered with a DID_BAD_INTR result.
- 5) Taken into account ZP Gus' proposals to reverse the SCSI-device
- scan order. As it does not work on Kernel 2.1.x or 2.2.x, as proposed
- by him, I implemented it in a slightly derived way, which offers in
- addition more flexibility.
- - Michael Lang
-
- Apr 23, 2000 (v3.2pre1)
- 1) During a very long time, I collected a huge amount of bug reports from
- various people, trying really quite different things on their SCSI-
- PS/2s. Today, all these bug reports are taken into account and should be
- mostly solved. The major topics were:
- - Driver crashes during boottime by no obvious reason.
- - Driver panics while the midlevel-SCSI-driver is trying to inquire
- the SCSI-device properties, even though hardware is in perfect state.
- - Displayed info for the various slot-cards is interpreted wrong.
- The main reasons for the crashes were two:
- 1) The commands to check for device information like INQUIRY,
- TEST_UNIT_READY, REQUEST_SENSE and MODE_SENSE cause the devices
- to deliver information of up to 255 bytes. Midlevel drivers offer
- 1024 bytes of space for the answer, but the IBM-SCSI-adapters do
- not accept this, as they stick quite near to ANSI-SCSI and report
- a COMMAND_ERROR message which causes the driver to panic. The main
- problem was located around the INQUIRY command. Now, for all the
- mentioned commands, the buffersize sent to the adapter is at
- maximum 255 which seems to be a quite reasonable solution.
- TEST_UNIT_READY gets a buffersize of 0 to make sure that no
- data is transferred in order to avoid any possible command failure.
- 2) On unsuccessful TEST_UNIT_READY, the mid-level driver has to send
- a REQUEST_SENSE in order to see where the problem is located. This
- REQUEST_SENSE may have various length in its answer-buffer. IBM
- SCSI-subsystems report a command failure if the returned buffersize
- is different from the sent buffersize, but this can be suppressed by
- a special bit, which is now done and problems seem to be solved.
- 2) Code adaption to all kernel-releases. Now, the 3.2 code compiles on
- 2.0.x, 2.1.x, 2.2.x and 2.3.x kernel releases without any code-changes.
- 3) Commandline-parameters are recognized again, even under Kernel 2.3.x or
- higher.
- - Michael Lang
-
- April 27, 2000 (v3.2pre2)
- 1) Bypassed commands get read by the adapter by one cycle instead of two.
- This increases SCSI-performance.
- 2) Synchronous datatransfer is provided for sure to be 5 MHz on older
- SCSI and 10 MHz on internal F/W SCSI-adapter.
- 3) New commandline parameters allow to force the adapter to slow down while
- in synchronous transfer. Could be helpful for very old devices.
- - Michael Lang
-
- June 2, 2000 (v3.2pre5)
- 1) Added Jim Shorney's contribution to make the activity indicator
- flashing in addition to the LED-alphanumeric display-panel on
- models 95A. To be enabled to choose this feature freely, a new
- commandline parameter is added, called 'activity'.
- 2) Added the READ_CONTROL bit for test_unit_ready SCSI-command.
- 3) Added some suppress_exception bits to read_device_capacity and
- all device_inquiry occurrences in the driver code.
- 4) Complaints about the various KERNEL_VERSION implementations are
- taken into account. Every local_LinuxKernelVersion occurrence is
- now replaced by KERNEL_VERSION, defined in linux/version.h.
- Corresponding changes were applied to ibmmca.h, too. This was a
- contribution to all kernel-parts by Philipp Hahn.
- - Michael Lang
-
- July 17, 2000 (v3.2pre8)
- A long period of collecting bug reports from all corners of the world
- now lead to the following corrections to the code:
- 1) SCSI-2 F/W support crashed with a COMMAND ERROR. The reason for this
- was that it is possible to disable Fast-SCSI for the external bus.
- The feature-control command, where this crash appeared regularly, tried
- to set the maximum speed of 10MHz synchronous transfer speed and that
- reports a COMMAND ERROR if external bus Fast-SCSI is disabled. Now,
- the feature-command probes down from maximum speed until the adapter
- stops to complain, which is at the same time the maximum possible
- speed selected in the reference program. So, F/W external can run at
- 5 MHz (slow-) or 10 MHz (fast-SCSI). During feature probing, the
- COMMAND ERROR message is used to detect if the adapter does not complain.
- 2) Up to now, only combined busmode is supported, if you use external
- SCSI-devices, attached to the F/W-controller. If dual bus is selected,
- only the internal SCSI-devices get accessed by Linux. For most
- applications, this should do fine.
- 3) Wide-SCSI-addressing (16-Bit) is now possible for the internal F/W
- bus on the F/W adapter. If F/W adapter is detected, the driver
- automatically uses the extended PUN/LUN <-> LDN mapping tables, which
- are now new from 3.2pre8. This allows PUNs between 0 and 15 and should
- provide more fun with the F/W adapter.
- 4) Several machines use the SCSI: POS registers for internal/undocumented
- storage of system relevant info. This confused the driver, mainly on
- models 9595, as it expected no onboard SCSI only, if all POS in
- the integrated SCSI-area are set to 0x00 or 0xff. Now, the mechanism
- to check for integrated SCSI is much more restrictive and these problems
- should be history.
- - Michael Lang
-
- July 18, 2000 (v3.2pre9)
- This develop rather quickly at the moment. Two major things were still
- missing in 3.2pre8:
- 1) The adapter PUN for F/W adapters has 4-bits, while all other adapters
- have 3-bits. This is now taken into account for F/W.
- 2) When you select CONFIG_IBMMCA_SCSI_ORDER_STANDARD, you should
- normally get the inverse probing order of your devices on the SCSI-bus.
- The ANSI device order gets scrambled in version 3.2pre8!! Now, a new
- and tested algorithm inverts the device-order on the SCSI-bus and
- automatically avoids accidental access to whatever SCSI PUN the adapter
- is set and works with SCSI- and Wide-SCSI-addressing.
- - Michael Lang
-
- July 23, 2000 (v3.2pre10 unpublished)
- 1) LED panel display supports wide-addressing in ibmmca=display mode.
- 2) Adapter-information and autoadaption to address-space is done.
- 3) Auto-probing for maximum synchronous SCSI transfer rate is working.
- 4) Optimization to some embedded function calls is applied.
- 5) Added some comment for the user to wait for SCSI-devices being probed.
- 6) Finished version 3.2 for Kernel 2.4.0. It least, I thought it is but...
- - Michael Lang
-
- July 26, 2000 (v3.2pre11)
- 1) I passed a horrible weekend getting mad with NMIs on kernel 2.2.14 and
- a model 9595. Asking around in the community, nobody except of me has
- seen such errors. Weird, but I am trying to recompile everything on
- the model 9595. Maybe, as I use a specially modified gcc, that could
- cause problems. But, it was not the reason. The true background was,
- that the kernel was compiled for i386 and the 9595 has a 486DX-2.
- Normally, no troubles should appear, but for this special machine,
- only the right processor support is working fine!
- 2) Previous problems with synchronous speed, slowing down from one adapter
- to the next during probing are corrected. Now, local variables store
- the synchronous bitmask for every single adapter found on the MCA bus.
- 3) LED alphanumeric panel support for XX95 systems is now showing some
- alive rotator during boottime. This makes sense, when no monitor is
- connected to the system. You can get rid of all display activity, if
- you do not use any parameter or just ibmmcascsi=activity, for the
- harddrive activity LED, existent on all PS/2, except models 8595-XXX.
- If no monitor is available, please use ibmmcascsi=display, which works
- fine together with the linuxinfo utility for the LED-panel.
- - Michael Lang
-
- July 29, 2000 (v3.2)
- 1) Submission of this driver for kernel 2.4test-XX and 2.2.17.
- - Michael Lang
-
- December 28, 2000 (v3.2d / v4.0)
- 1) The interrupt handler had some wrong statement to wait for. This
- was done due to experimental reasons during 3.2 development but it
- has shown that this is not stable enough. Going back to wait for the
- adapter to be not busy is best.
- 2) Inquiry requests can be shorter than 255 bytes of return buffer. Due
- to a bug in the ibmmca_queuecommand routine, this buffer was forced
- to 255 at minimum. If the memory address, this return buffer is pointing
- to does not offer more space, invalid memory accesses destabilized the
- kernel.
- 3) version 4.0 is only valid for kernel 2.4.0 or later. This is necessary
- to remove old kernel version dependent waste from the driver. 3.2d is
- only distributed with older kernels but keeps compatibility with older
- kernel versions. 4.0 and higher versions cannot be used with older
- kernels anymore!! You must have at least kernel 2.4.0!!
- 4) The commandline argument 'bypass' and all its functionality got removed
- in version 4.0. This was never really necessary, as all troubles were
- based on non-command related reasons up to now, so bypassing commands
- did not help to avoid any bugs. It is kept in 3.2X for debugging reasons.
- 5) Dynamic reassignment of ldns was again verified and analyzed to be
- completely inoperational. This is corrected and should work now.
- 6) All commands that get sent to the SCSI adapter were verified and
- completed in such a way, that they are now completely conform to the
- demands in the technical description of IBM. Main candidates were the
- DEVICE_INQUIRY, REQUEST_SENSE and DEVICE_CAPACITY commands. They must
- be transferred by bypassing the internal command buffer of the adapter
- or else the response can be a random result. GET_POS_INFO would be more
- safe in usage, if one could use the SUPRESS_EXCEPTION_SHORT, but this
- is not allowed by the technical references of IBM. (Sorry, folks, the
- model 80 problem is still a task to be solved in a different way.)
- 7) v3.2d is still hold back for some days for testing, while 4.0 is
- released.
- - Michael Lang
-
- January 3, 2001 (v4.0a)
- 1) A lot of complains after the 2.4.0-prerelease kernel came in about
- the impossibility to compile the driver as a module. This problem is
- solved. In combination with that problem, some unprecise declaration
- of the function option_setup() gave some warnings during compilation.
- This is solved, too by a forward declaration in ibmmca.c.
- 2) #ifdef argument concerning CONFIG_SCSI_IBMMCA is no longer needed and
- was entirely removed.
- 3) Some switch statements got optimized in code, as some minor variables
- in internal SCSI-command handlers.
- - Michael Lang
-
- 4 To do
- -------
- - IBM SCSI-2 F/W external SCSI bus support in separate mode!
- - It seems that the handling of bad disks is really bad -
- non-existent, in fact. However, a low-level driver cannot help
- much, if such things happen.
-
- 5 Users' Manual
- ---------------
- 5.1 Commandline Parameters
- --------------------------
- There exist several features for the IBM SCSI-subsystem driver.
- The commandline parameter format is:
-
- ibmmcascsi=<command1>,<command2>,<command3>,...
-
- where commandN can be one of the following:
-
- display Owners of a model 95 or other PS/2 systems with an
- alphanumeric LED display may set this to have their
- display showing the following output of the 8 digits:
-
- ------DA
-
- where '-' stays dark, 'D' shows the SCSI-device id
- and 'A' shows the SCSI hostindex, being currently
- accessed. During boottime, this will give the message
-
- SCSIini*
-
- on the LED-panel, where the * represents a rotator,
- showing the activity during the probing phase of the
- driver which can take up to two minutes per SCSI-adapter.
- adisplay This works like display, but gives more optical overview
- of the activities on the SCSI-bus. The display will have
- the following output:
-
- 6543210A
-
- where the numbers 0 to 6 light up at the shown position,
- when the SCSI-device is accessed. 'A' shows again the SCSI
- hostindex. If display nor adisplay is set, the internal
- PS/2 harddisk LED is used for media-activities. So, if
- you really do not have a system with a LED-display, you
- should not set display or adisplay. Keep in mind, that
- display and adisplay can only be used alternatively. It
- is not recommended to use this option, if you have some
- wide-addressed devices e.g. at the SCSI-2 F/W adapter in
- your system. In addition, the usage of the display for
- other tasks in parallel, like the linuxinfo-utility makes
- no sense with this option.
- activity This enables the PS/2 harddisk LED activity indicator.
- Most PS/2 have no alphanumeric LED display, but some
- indicator. So you should use this parameter to activate it.
- If you own model 9595 (Server95), you can have both, the
- LED panel and the activity indicator in parallel. However,
- some PS/2s, like the 8595 do not have any harddisk LED
- activity indicator, which means, that you must use the
- alphanumeric LED display if you want to monitor SCSI-
- activity.
- bypass This is obsolete from driver version 4.0, as the adapters
- got that far understood, that the selection between
- integrated and bypassed commands should now work completely
- correct! For historical reasons, the old description is
- kept here:
- This commandline parameter forces the driver never to use
- SCSI-subsystems' integrated SCSI-command set. Except of
- the immediate assign, which is of vital importance for
- every IBM SCSI-subsystem to set its ldns right. Instead,
- the ordinary ANSI-SCSI-commands are used and passed by the
- controller to the SCSI-devices, therefore 'bypass'. The
- effort, done by the subsystem is quite bogus and at a
- minimum and therefore it should work everywhere. This
- could maybe solve troubles with old or integrated SCSI-
- controllers and nasty harddisks. Keep in mind, that using
- this flag will slow-down SCSI-accesses slightly, as the
- software generated commands are always slower than the
- hardware. Non-harddisk devices always get read/write-
- commands in bypass mode. On the most recent releases of
- the Linux IBM-SCSI-driver, the bypass command should be
- no longer a necessary thing, if you are sure about your
- SCSI-hardware!
- normal This is the parameter, introduced on the 2.0.x development
- rail by ZP Gu. This parameter defines the SCSI-device
- scan order in the new industry standard. This means, that
- the first SCSI-device is the one with the lowest pun.
- E.g. harddisk at pun=0 is scanned before harddisk at
- pun=6, which means, that harddisk at pun=0 gets sda
- and the one at pun=6 gets sdb.
- ansi The ANSI-standard for the right scan order, as done by
- IBM, Microware and Microsoft, scans SCSI-devices starting
- at the highest pun, which means, that e.g. harddisk at
- pun=6 gets sda and a harddisk at pun=0 gets sdb. If you
- like to have the same SCSI-device order, as in DOS, OS-9
- or OS/2, just use this parameter.
- fast SCSI-I/O in synchronous mode is done at 5 MHz for IBM-
- SCSI-devices. SCSI-2 Fast/Wide Adapter/A external bus
- should then run at 10 MHz if Fast-SCSI is enabled,
- and at 5 MHz if Fast-SCSI is disabled on the external
- bus. This is the default setting when nothing is
- specified here.
- medium Synchronous rate is at 50% approximately, which means
- 2.5 MHz for IBM SCSI-adapters and 5.0 MHz for F/W ext.
- SCSI-bus (when Fast-SCSI speed enabled on external bus).
- slow The slowest possible synchronous transfer rate is set.
- This means 1.82 MHz for IBM SCSI-adapters and 2.0 MHz
- for F/W external bus at Fast-SCSI speed on the external
- bus.
-
- A further option is that you can force the SCSI-driver to accept a SCSI-
- subsystem at a certain I/O-address with a predefined adapter PUN. This
- is done by entering
-
- commandN = I/O-base
- commandN+1 = adapter PUN
-
- e.g. ibmmcascsi=0x3540,7 will force the driver to detect a SCSI-subsystem
- at I/O-address 0x3540 with adapter PUN 7. Please only use this method, if
- the driver does really not recognize your SCSI-adapter! With driver version
- 3.2, this recognition of various adapters was hugely improved and you
- should try first to remove your commandline arguments of such type with a
- newer driver. I bet, it will be recognized correctly. Even multiple and
- different types of IBM SCSI-adapters should be recognized correctly, too.
- Use the forced detection method only as last solution!
-
- Examples:
-
- ibmmcascsi=adisplay
-
- This will use the advanced display mode for the model 95 LED alphanumeric
- display.
-
- ibmmcascsi=display,0x3558,7
-
- This will activate the default display mode for the model 95 LED display
- and will force the driver to accept a SCSI-subsystem at I/O-base 0x3558
- with adapter PUN 7.
-
- 5.2 Troubleshooting
- -------------------
- The following FAQs should help you to solve some major problems with this
- driver.
-
- Q: "Reset SCSI-devices at boottime" halts the system at boottime, why?
- A: This is only tested with the IBM SCSI Adapter w/cache. It is not
- yet proven to run on other adapters, however you may be lucky.
- In version 3.1d this has been hugely improved and should work better,
- now. Normally you really won't need to activate this flag in the
- kernel configuration, as all post 1989 SCSI-devices should accept
- the reset-signal, when the computer is switched on. The SCSI-
- subsystem generates this reset while being initialized. This flag
- is really reserved for users with very old, very strange or self-made
- SCSI-devices.
- Q: Why is the SCSI-order of my drives mirrored to the device-order
- seen from OS/2 or DOS ?
- A: It depends on the operating system, if it looks at the devices in
- ANSI-SCSI-standard (starting from pun 6 and going down to pun 0) or
- if it just starts at pun 0 and counts up. If you want to be conform
- with OS/2 and DOS, you have to activate this flag in the kernel
- configuration or you should set 'ansi' as parameter for the kernel.
- The parameter 'normal' sets the new industry standard, starting
- from pun 0, scanning up to pun 6. This allows you to change your
- opinion still after having already compiled the kernel.
- Q: Why can't I find IBM MCA SCSI support in the config menu?
- A: You have to activate MCA bus support, first.
- Q: Where can I find the latest info about this driver?
- A: See the file MAINTAINERS for the current WWW-address, which offers
- updates, info and Q/A lists. At this file's origin, the webaddress
- was: http://www.staff.uni-mainz.de/mlang/linux.html
- Q: My SCSI-adapter is not recognized by the driver, what can I do?
- A: Just force it to be recognized by kernel parameters. See section 5.1.
- If this really happens, do also send e-mail to the maintainer, as
- forced detection should be never necessary. Forced detection is in
- principal some flaw of the driver adapter detection and goes into
- bug reports.
- Q: The driver screws up, if it starts to probe SCSI-devices, is there
- some way out of it?
- A: Yes, that was some recognition problem of the correct SCSI-adapter
- and its I/O base addresses. Upgrade your driver to the latest release
- and it should be fine again.
- Q: I get a message: panic IBM MCA SCSI: command error .... , what can
- I do against this?
- A: Previously, I followed the way by ignoring command errors by using
- ibmmcascsi=forgiveall, but this command no longer exists and is
- obsolete. If such a problem appears, it is caused by some segmentation
- fault of the driver, which maps to some unallowed area. The latest
- version of the driver should be ok, as most bugs have been solved.
- Q: There are still kernel panics, even after having set
- ibmmcascsi=forgiveall. Are there other possibilities to prevent
- such panics?
- A: No, get just the latest release of the driver and it should work
- better and better with increasing version number. Forget about this
- ibmmcascsi=forgiveall, as also ignorecmd are obsolete.!
- Q: Linux panics or stops without any comment, but it is probable, that my
- harddisk(s) have bad blocks.
- A: Sorry, the bad-block handling is still a feeble point of this driver,
- but is on the schedule for development in the near future.
- Q: Linux panics while dynamically assigning SCSI-ids or ldns.
- A: If you disconnect a SCSI-device from the machine, while Linux is up
- and the driver uses dynamical reassignment of logical device numbers
- (ldn), it really gets "angry" if it won't find devices, that were still
- present at boottime and stops Linux.
- Q: The system does not recover after an abort-command has been generated.
- A: This is regrettably true, as it is not yet understood, why the
- SCSI-adapter does really NOT generate any interrupt at the end of
- the abort-command. As no interrupt is generated, the abort command
- cannot get finished and the system hangs, sorry, but checks are
- running to hunt down this problem. If there is a real pending command,
- the interrupt MUST get generated after abort. In this case, it
- should finish well.
- Q: The system gets in bad shape after a SCSI-reset, is this known?
- A: Yes, as there are a lot of prescriptions (see the Linux Hackers'
- Guide) what has to be done for reset, we still share the bad shape of
- the reset functions with all other low level SCSI-drivers.
- Astonishingly, reset works in most cases quite ok, but the harddisks
- won't run in synchronous mode anymore after a reset, until you reboot.
- Q: Why does my XXX w/Cache adapter not use read-prefetch?
- A: Ok, that is not completely possible. If a cache is present, the
- adapter tries to use it internally. Explicitly, one can use the cache
- with a read prefetch command, maybe in future, but this requires
- some major overhead of SCSI-commands that risks the performance to
- go down more than it gets improved. Tests with that are running.
- Q: I have a IBM SCSI-2 Fast/Wide adapter, it boots in some way and hangs.
- A: Yes, that is understood, as for sure, your SCSI-2 Fast/Wide adapter
- was in such a case recognized as integrated SCSI-adapter or something
- else, but not as the correct adapter. As the I/O-ports get assigned
- wrongly by that reason, the system should crash in most cases. You
- should upgrade to the latest release of the SCSI-driver. The
- recommended version is 3.2 or later. Here, the F/W support is in
- a stable and reliable condition. Wide-addressing is in addition
- supported.
- Q: I get an Oops message and something like "killing interrupt".
- A: The reason for this is that the IBM SCSI-subsystem only sends a
- termination status back, if some error appeared. In former releases
- of the driver, it was not checked, if the termination status block
- is NULL. From version 3.2, it is taken care of this.
- Q: I have a F/W adapter and the driver sees my internal SCSI-devices,
- but ignores the external ones.
- A: Select combined busmode in the IBM config-program and check for that
- no SCSI-id on the external devices appears on internal devices.
- Reboot afterwards. Dual busmode is supported, but works only for the
- internal bus, yet. External bus is still ignored. Take care for your
- SCSI-ids. If combined bus-mode is activated, on some adapters,
- the wide-addressing is not possible, so devices with ids between 8
- and 15 get ignored by the driver & adapter!
- Q: I have a 9595 and I get a NMI during heavy SCSI I/O e.g. during fsck.
- A COMMAND ERROR is reported and characters on the screen are missing.
- Warm reboot is not possible. Things look like quite weird.
- A: Check the processor type of your 9595. If you have an 80486 or 486DX-2
- processor complex on your mainboard and you compiled a kernel that
- supports 80386 processors, it is possible, that the kernel cannot
- keep track of the PS/2 interrupt handling and stops on an NMI. Just
- compile a kernel for the correct processor type of your PS/2 and
- everything should be fine. This is necessary even if one assumes,
- that some 80486 system should be downward compatible to 80386
- software.
- Q: Some commands hang and interrupts block the machine. After some
- timeout, the syslog reports that it tries to call abort, but the
- machine is frozen.
- A: This can be a busy wait bug in the interrupt handler of driver
- version 3.2. You should at least upgrade to 3.2c if you use
- kernel < 2.4.0 and driver version 4.0 if you use kernel 2.4.0 or
- later (including all test releases).
- Q: I have a PS/2 model 80 and more than 16 MBytes of RAM. The driver
- completely refuses to work, reports NMIs, COMMAND ERRORs or other
- ambiguous stuff. When reducing the RAM size down below 16 MB,
- everything is running smoothly.
- A: No real answer, yet. In any case, one should force the kernel to
- present SCBs only below the 16 MBytes barrier. Maybe this solves the
- problem. Not yet tried, but guessing that it could work. To get this,
- set unchecked_isa_dma argument of ibmmca.h from 0 to 1.
-
- 5.3 Bug reports
- --------------
- If you really find bugs in the source code or the driver will successfully
- refuse to work on your machine, you should send a bug report to me. The
- best for this is to follow the instructions on the WWW-page for this
- driver. Fill out the bug-report form, placed on the WWW-page and ship it,
- so the bugs can be taken into account with maximum efforts. But, please
- do not send bug reports about this driver to Linus Torvalds or Leonard
- Zubkoff, as Linus is buried in E-Mail and Leonard is supervising all
- SCSI-drivers and won't have the time left to look inside every single
- driver to fix a bug and especially DO NOT send modified code to Linus
- Torvalds or Alan J. Cox which has not been checked here!!! They are both
- quite buried in E-mail (as me, sometimes, too) and one should first check
- for problems on my local teststand. Recently, I got a lot of
- bug reports for errors in the ibmmca.c code, which I could not imagine, but
- a look inside some Linux-distribution showed me quite often some modified
- code, which did no longer work on most other machines than the one of the
- modifier. Ok, so now that there is maintenance service available for this
- driver, please use this address first in order to keep the level of
- confusion low. Thank you!
-
- When you get a SCSI-error message that panics your system, a list of
- register-entries of the SCSI-subsystem is shown (from Version 3.1d). With
- this list, it is very easy for the maintainer to localize the problem in
- the driver or in the configuration of the user. Please write down all the
- values from this report and send them to the maintainer. This would really
- help a lot and makes life easier concerning misunderstandings.
-
- Use the bug-report form (see 5.4 for its address) to send all the bug-
- stuff to the maintainer or write e-mail with the values from the table.
-
- 5.4 Support WWW-page
- --------------------
- The address of the IBM SCSI-subsystem supporting WWW-page is:
-
- http://www.staff.uni-mainz.de/mlang/linux.html
-
- Here you can find info about the background of this driver, patches,
- troubleshooting support, news and a bugreport form. Please check that
- WWW-page regularly for latest hints. If ever this URL changes, please
- refer to the MAINTAINERS file in order to get the latest address.
-
- For the bugreport, please fill out the formular on the corresponding
- WWW-page. Read the dedicated instructions and write as much as you
- know about your problem. If you do not like such formulars, please send
- some e-mail directly, but at least with the same information as required by
- the formular.
-
- If you have extensive bug reports, including Oops messages and
- screen-shots, please feel free to send it directly to the address
- of the maintainer, too. The current address of the maintainer is:
-
- Michael Lang <langa2@kph.uni-mainz.de>
-
- 6 References
- ------------
- IBM Corp., "Update for the PS/2 Hardware Interface Technical Reference,
- Common Interfaces", Armonk, September 1991, PN 04G3281,
- (available in the U.S. for $21.75 at 1-800-IBM-PCTB or in Germany for
- around 40,-DM at "Hallo IBM").
-
- IBM Corp., "Personal System/2 Micro Channel SCSI
- Adapter with Cache Technical Reference", Armonk, March 1990, PN 68X2365.
-
- IBM Corp., "Personal System/2 Micro Channel SCSI
- Adapter Technical Reference", Armonk, March 1990, PN 68X2397.
-
- IBM Corp., "SCSI-2 Fast/Wide Adapter/A Technical Reference - Dual Bus",
- Armonk, March 1994, PN 83G7545.
-
- Friedhelm Schmidt, "SCSI-Bus und IDE-Schnittstelle - Moderne Peripherie-
- Schnittstellen: Hardware, Protokollbeschreibung und Anwendung", 2. Aufl.
- Addison Wesley, 1996.
-
- Michael K. Johnson, "The Linux Kernel Hackers' Guide", Version 0.6, Chapel
- Hill - North Carolina, 1995
-
- Andreas Kaiser, "SCSI TAPE BACKUP for OS/2 2.0", Version 2.12, Stuttgart
- 1993
-
- Helmut Rompel, "IBM Computerwelt GUIDE", What is what bei IBM., Systeme *
- Programme * Begriffe, IWT-Verlag GmbH - Muenchen, 1988
-
- 7 Credits to
- ------------
- 7.1 People
- ----------
- Klaus Grimm
- who already a long time ago gave me the old code from the
- SCSI-driver in order to get it running for some old machine
- in our institute.
- Martin Kolinek
- who wrote the first release of the IBM SCSI-subsystem driver.
- Chris Beauregard
- who for a long time maintained MCA-Linux and the SCSI-driver
- in the beginning. Chris, wherever you are: Cheers to you!
- Klaus Kudielka
- with whom in the 2.1.x times, I had a quite fruitful
- cooperation to get the driver running as a module and to get
- it running with multiple SCSI-adapters.
- David Weinehall
- for his excellent maintenance of the MCA-stuff and the quite
- detailed bug reports and ideas for this driver (and his
- patience ;-)).
- Alan J. Cox
- for his bug reports and his bold activities in cross-checking
- the driver-code with his teststand.
-
- 7.2 Sponsors & Supporters
- -------------------------
- "Hallo IBM",
- IBM-Deutschland GmbH
- the service of IBM-Deutschland for customers. Their E-Mail
- service is unbeatable. Whatever old stuff I asked for, I
- always got some helpful answers.
- Karl-Otto Reimers,
- IBM Klub - Sparte IBM Geschichte, Sindelfingen
- for sending me a copy of the w/Cache manual from the
- IBM-Deutschland archives.
- Harald Staiger
- for his extensive hardware donations which allows me today
- still to test the driver in various constellations.
- Erich Fritscher
- for his very kind sponsoring.
- Louis Ohland,
- Charles Lasitter
- for support by shipping me an IBM SCSI-2 Fast/Wide manual.
- In addition, the contribution of various hardware is quite
- decessive and will make it possible to add FWSR (RAID)
- adapter support to the driver in the near future! So,
- complaints about no RAID support won't remain forever.
- Yes, folks, that is no joke, RAID support is going to rise!
- Erik Weber
- for the great deal we made about a model 9595 and the nice
- surrounding equipment and the cool trip to Mannheim
- second-hand computer market. In addition, I would like
- to thank him for his exhaustive SCSI-driver testing on his
- 95er PS/2 park.
- Anthony Hogbin
- for his direct shipment of a SCSI F/W adapter, which allowed
- me immediately on the first stage to try it on model 8557
- together with onboard SCSI adapter and some SCSI w/Cache.
- Andreas Hotz
- for his support by memory and an IBM SCSI-adapter. Collecting
- all this together now allows me to try really things with
- the driver at maximum load and variety on various models in
- a very quick and efficient way.
- Peter Jennewein
- for his model 30, which serves me as part of my teststand
- and his cool remark about how you make an ordinary diskette
- drive working and how to connect it to an IBM-diskette port.
- Johannes Gutenberg-Universitaet, Mainz &
- Institut fuer Kernphysik, Mainz Microtron (MAMI)
- for the offered space, the link, placed on the central
- homepage and the space to store and offer the driver and
- related material and the free working times, which allow
- me to answer all your e-mail.
-
- 8 Trademarks
- ------------
- IBM, PS/2, OS/2, Microchannel are registered trademarks of International
- Business Machines Corporation
-
- MS-DOS is a registered trademark of Microsoft Corporation
-
- Microware, OS-9 are registered trademarks of Microware Systems
-
- 9 Disclaimer
- ------------
- Beside the GNU General Public License and the dependent disclaimers and disclaimers
- concerning the Linux-kernel in special, this SCSI-driver comes without any
- warranty. Its functionality is tested as good as possible on certain
- machines and combinations of computer hardware, which does not exclude,
- that data loss or severe damage of hardware is possible while using this
- part of software on some arbitrary computer hardware or in combination
- with other software packages. It is highly recommended to make backup
- copies of your data before using this software. Furthermore, personal
- injuries by hardware defects, that could be caused by this SCSI-driver are
- not excluded and it is highly recommended to handle this driver with a
- maximum of carefulness.
-
- This driver supports hardware, produced by International Business Machines
- Corporation (IBM).
-
-------
-Michael Lang
-(langa2@kph.uni-mainz.de)
diff --git a/Documentation/scsi/scsi-parameters.txt b/Documentation/scsi/scsi-parameters.txt
index 21e5798526ee..2bfd6f6d2d3d 100644
--- a/Documentation/scsi/scsi-parameters.txt
+++ b/Documentation/scsi/scsi-parameters.txt
@@ -37,9 +37,6 @@ parameters may be changed at runtime by the command
eata= [HW,SCSI]
- fd_mcs= [HW,SCSI]
- See header of drivers/scsi/fd_mcs.c.
-
fdomain= [HW,SCSI]
See header of drivers/scsi/fdomain.c.
@@ -48,9 +45,6 @@ parameters may be changed at runtime by the command
gvp11= [HW,SCSI]
- ibmmcascsi= [HW,MCA,SCSI] IBM MicroChannel SCSI adapter
- See Documentation/mca.txt.
-
in2000= [HW,SCSI]
See header of drivers/scsi/in2000.c.
diff --git a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt
index a340b18cd4eb..2b06aba4fa0f 100644
--- a/Documentation/scsi/scsi_mid_low_api.txt
+++ b/Documentation/scsi/scsi_mid_low_api.txt
@@ -30,7 +30,7 @@ the motherboard (or both). Some aic7xxx based HBAs are dual controllers
and thus represent two hosts. Like most modern HBAs, each aic7xxx host
has its own PCI device address. [The one-to-one correspondence between
a SCSI host and a PCI device is common but not required (e.g. with
-ISA or MCA adapters).]
+ISA adapters).]
The SCSI mid level isolates an LLD from other layers such as the SCSI
upper layer drivers and the block layer.
diff --git a/Documentation/serial/stallion.txt b/Documentation/serial/stallion.txt
index 55090914a9c5..4d798c0cb5cb 100644
--- a/Documentation/serial/stallion.txt
+++ b/Documentation/serial/stallion.txt
@@ -20,10 +20,10 @@ There are two drivers that work with the different families of Stallion
multiport serial boards. One is for the Stallion smart boards - that is
EasyIO, EasyConnection 8/32 and EasyConnection 8/64-PCI, the other for
the true Stallion intelligent multiport boards - EasyConnection 8/64
-(ISA, EISA, MCA), EasyConnection/RA-PCI, ONboard and Brumby.
+(ISA, EISA), EasyConnection/RA-PCI, ONboard and Brumby.
If you are using any of the Stallion intelligent multiport boards (Brumby,
-ONboard, EasyConnection 8/64 (ISA, EISA, MCA), EasyConnection/RA-PCI) with
+ONboard, EasyConnection 8/64 (ISA, EISA), EasyConnection/RA-PCI) with
Linux you will need to get the driver utility package. This contains a
firmware loader and the firmware images necessary to make the devices operate.
@@ -40,7 +40,7 @@ If you are using the EasyIO, EasyConnection 8/32 or EasyConnection 8/64-PCI
boards then you don't need this package, although it does have a serial stats
display program.
-If you require DIP switch settings, EISA or MCA configuration files, or any
+If you require DIP switch settings, or EISA configuration files, or any
other information related to Stallion boards then have a look at Stallion's
web pages at http://www.stallion.com.
@@ -51,13 +51,13 @@ web pages at http://www.stallion.com.
The drivers can be used as loadable modules or compiled into the kernel.
You can choose which when doing a "config" on the kernel.
-All ISA, EISA and MCA boards that you want to use need to be configured into
+All ISA, and EISA boards that you want to use need to be configured into
the driver(s). All PCI boards will be automatically detected when you load
the driver - so they do not need to be entered into the driver(s)
configuration structure. Note that kernel PCI support is required to use PCI
boards.
-There are two methods of configuring ISA, EISA and MCA boards into the drivers.
+There are two methods of configuring ISA and EISA boards into the drivers.
If using the driver as a loadable module then the simplest method is to pass
the driver configuration as module arguments. The other method is to modify
the driver source to add configuration lines for each board in use.
@@ -71,12 +71,12 @@ That makes things pretty simple to get going.
2.1 MODULE DRIVER CONFIGURATION:
The simplest configuration for modules is to use the module load arguments
-to configure any ISA, EISA or MCA boards. PCI boards are automatically
+to configure any ISA or EISA boards. PCI boards are automatically
detected, so do not need any additional configuration at all.
-If using EasyIO, EasyConnection 8/32 ISA or MCA, or EasyConnection 8/63-PCI
+If using EasyIO, EasyConnection 8/32 ISA, or EasyConnection 8/63-PCI
boards then use the "stallion" driver module, Otherwise if you are using
-an EasyConnection 8/64 ISA, EISA or MCA, EasyConnection/RA-PCI, ONboard,
+an EasyConnection 8/64 ISA or EISA, EasyConnection/RA-PCI, ONboard,
Brumby or original Stallion board then use the "istallion" driver module.
Typically to load up the smart board driver use:
@@ -146,7 +146,7 @@ on each system boot. Typically configuration files are put in the
2.2 STATIC DRIVER CONFIGURATION:
For static driver configuration you need to modify the driver source code.
-Entering ISA, EISA and MCA boards into the driver(s) configuration structure
+Entering ISA and EISA boards into the driver(s) configuration structure
involves editing the driver(s) source file. It's pretty easy if you follow
the instructions below. Both drivers can support up to 4 boards. The smart
card driver (the stallion.c driver) supports any combination of EasyIO and
@@ -157,7 +157,7 @@ supports any combination of ONboards, Brumbys, Stallions and EasyConnection
To set up the driver(s) for the boards that you want to use you need to
edit the appropriate driver file and add configuration entries.
-If using EasyIO or EasyConnection 8/32 ISA or MCA boards,
+If using EasyIO or EasyConnection 8/32 ISA boards,
In drivers/char/stallion.c:
- find the definition of the stl_brdconf array (of structures)
near the top of the file
@@ -243,7 +243,7 @@ change it on the board.
On EasyIO and EasyConnection 8/32 boards the IRQ is software programmable, so
if there is a conflict you may need to change the IRQ used for a board. There
are no interrupts to worry about for ONboard, Brumby or EasyConnection 8/64
-(ISA, EISA and MCA) boards. The memory region on EasyConnection 8/64 and
+(ISA and EISA) boards. The memory region on EasyConnection 8/64 and
ONboard boards is software programmable, but not on the Brumby boards.
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 8c16d50f6cb6..221b81016dba 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -1545,7 +1545,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
Module for sound cards based on the C-Media CMI8786/8787/8788 chip:
* Asound A-8788
- * Asus Xonar DG
+ * Asus Xonar DG/DGX
* AuzenTech X-Meridian
* AuzenTech X-Meridian 2G
* Bgears b-Enspirer
diff --git a/Documentation/sound/alsa/compress_offload.txt b/Documentation/sound/alsa/compress_offload.txt
index c83a835350f0..90e9b3a11abc 100644
--- a/Documentation/sound/alsa/compress_offload.txt
+++ b/Documentation/sound/alsa/compress_offload.txt
@@ -18,7 +18,7 @@ processing. Support for such hardware has not been very good in Linux,
mostly because of a lack of a generic API available in the mainline
kernel.
-Rather than requiring a compability break with an API change of the
+Rather than requiring a compatibility break with an API change of the
ALSA PCM interface, a new 'Compressed Data' API is introduced to
provide a control and data-streaming interface for audio DSPs.
diff --git a/Documentation/sound/oss/ALS b/Documentation/sound/oss/ALS
index d01ffbfd5808..bf10bed4574b 100644
--- a/Documentation/sound/oss/ALS
+++ b/Documentation/sound/oss/ALS
@@ -57,10 +57,10 @@ The resulting sound driver will provide the following capabilities:
DSP/PCM/audio out (L&R), FM (L&R) and Mic in (mono).
Jonathan Woithe
-jwoithe@physics.adelaide.edu.au
+jwoithe@just42.net
30 March 1998
Modified 2000-02-26 by Dave Forrest, drf5n@virginia.edu to add ALS100/ALS200
Modified 2000-04-10 by Paul Laufer, pelaufer@csupomona.edu to add ISAPnP info.
-Modified 2000-11-19 by Jonathan Woithe, jwoithe@physics.adelaide.edu.au
+Modified 2000-11-19 by Jonathan Woithe, jwoithe@just42.net
- updated information for kernel 2.4.x.
diff --git a/Documentation/static-keys.txt b/Documentation/static-keys.txt
index d93f3c00f245..9f5263d3152c 100644
--- a/Documentation/static-keys.txt
+++ b/Documentation/static-keys.txt
@@ -235,7 +235,7 @@ label case adds:
6 (mov) + 2 (test) + 2 (jne) = 10 - 5 (5 byte jump 0) = 5 addition bytes.
If we then include the padding bytes, the jump label code saves, 16 total bytes
-of instruction memory for this small fucntion. In this case the non-jump label
+of instruction memory for this small function. In this case the non-jump label
function is 80 bytes long. Thus, we have have saved 20% of the instruction
footprint. We can in fact improve this even further, since the 5-byte no-op
really can be a 2-byte no-op since we can reach the branch with a 2-byte jmp.
diff --git a/Documentation/trace/uprobetracer.txt b/Documentation/trace/uprobetracer.txt
new file mode 100644
index 000000000000..24ce6823a09e
--- /dev/null
+++ b/Documentation/trace/uprobetracer.txt
@@ -0,0 +1,113 @@
+ Uprobe-tracer: Uprobe-based Event Tracing
+ =========================================
+ Documentation written by Srikar Dronamraju
+
+Overview
+--------
+Uprobe based trace events are similar to kprobe based trace events.
+To enable this feature, build your kernel with CONFIG_UPROBE_EVENT=y.
+
+Similar to the kprobe-event tracer, this doesn't need to be activated via
+current_tracer. Instead of that, add probe points via
+/sys/kernel/debug/tracing/uprobe_events, and enable it via
+/sys/kernel/debug/tracing/events/uprobes/<EVENT>/enabled.
+
+However unlike kprobe-event tracer, the uprobe event interface expects the
+user to calculate the offset of the probepoint in the object
+
+Synopsis of uprobe_tracer
+-------------------------
+ p[:[GRP/]EVENT] PATH:SYMBOL[+offs] [FETCHARGS] : Set a probe
+
+ GRP : Group name. If omitted, use "uprobes" for it.
+ EVENT : Event name. If omitted, the event name is generated
+ based on SYMBOL+offs.
+ PATH : path to an executable or a library.
+ SYMBOL[+offs] : Symbol+offset where the probe is inserted.
+
+ FETCHARGS : Arguments. Each probe can have up to 128 args.
+ %REG : Fetch register REG
+
+Event Profiling
+---------------
+ You can check the total number of probe hits and probe miss-hits via
+/sys/kernel/debug/tracing/uprobe_profile.
+ The first column is event name, the second is the number of probe hits,
+the third is the number of probe miss-hits.
+
+Usage examples
+--------------
+To add a probe as a new event, write a new definition to uprobe_events
+as below.
+
+ echo 'p: /bin/bash:0x4245c0' > /sys/kernel/debug/tracing/uprobe_events
+
+ This sets a uprobe at an offset of 0x4245c0 in the executable /bin/bash
+
+ echo > /sys/kernel/debug/tracing/uprobe_events
+
+ This clears all probe points.
+
+The following example shows how to dump the instruction pointer and %ax
+a register at the probed text address. Here we are trying to probe
+function zfree in /bin/zsh
+
+ # cd /sys/kernel/debug/tracing/
+ # cat /proc/`pgrep zsh`/maps | grep /bin/zsh | grep r-xp
+ 00400000-0048a000 r-xp 00000000 08:03 130904 /bin/zsh
+ # objdump -T /bin/zsh | grep -w zfree
+ 0000000000446420 g DF .text 0000000000000012 Base zfree
+
+0x46420 is the offset of zfree in object /bin/zsh that is loaded at
+0x00400000. Hence the command to probe would be :
+
+ # echo 'p /bin/zsh:0x46420 %ip %ax' > uprobe_events
+
+Please note: User has to explicitly calculate the offset of the probepoint
+in the object. We can see the events that are registered by looking at the
+uprobe_events file.
+
+ # cat uprobe_events
+ p:uprobes/p_zsh_0x46420 /bin/zsh:0x00046420 arg1=%ip arg2=%ax
+
+The format of events can be seen by viewing the file events/uprobes/p_zsh_0x46420/format
+
+ # cat events/uprobes/p_zsh_0x46420/format
+ name: p_zsh_0x46420
+ ID: 922
+ format:
+ field:unsigned short common_type; offset:0; size:2; signed:0;
+ field:unsigned char common_flags; offset:2; size:1; signed:0;
+ field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
+ field:int common_pid; offset:4; size:4; signed:1;
+ field:int common_padding; offset:8; size:4; signed:1;
+
+ field:unsigned long __probe_ip; offset:12; size:4; signed:0;
+ field:u32 arg1; offset:16; size:4; signed:0;
+ field:u32 arg2; offset:20; size:4; signed:0;
+
+ print fmt: "(%lx) arg1=%lx arg2=%lx", REC->__probe_ip, REC->arg1, REC->arg2
+
+Right after definition, each event is disabled by default. For tracing these
+events, you need to enable it by:
+
+ # echo 1 > events/uprobes/enable
+
+Lets disable the event after sleeping for some time.
+ # sleep 20
+ # echo 0 > events/uprobes/enable
+
+And you can see the traced information via /sys/kernel/debug/tracing/trace.
+
+ # cat trace
+ # tracer: nop
+ #
+ # TASK-PID CPU# TIMESTAMP FUNCTION
+ # | | | | |
+ zsh-24842 [006] 258544.995456: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79
+ zsh-24842 [007] 258545.000270: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79
+ zsh-24842 [002] 258545.043929: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79
+ zsh-24842 [004] 258547.046129: p_zsh_0x46420: (0x446420) arg1=446421 arg2=79
+
+Each line shows us probes were triggered for a pid 24842 with ip being
+0x446421 and contents of ax register being 79.
diff --git a/Documentation/usb/dwc3.txt b/Documentation/usb/dwc3.txt
index 7b590edae145..1d02c01d1c7c 100644
--- a/Documentation/usb/dwc3.txt
+++ b/Documentation/usb/dwc3.txt
@@ -28,7 +28,7 @@ Please pick something while reading :)
none
- primary handler of the EP-interrupt
- reads the event and tries to process it. Everything that requries
+ reads the event and tries to process it. Everything that requires
sleeping is handed over to the Thread. The event is saved in an
per-endpoint data-structure.
We probably have to pay attention not to process events once we
diff --git a/Documentation/usb/functionfs.txt b/Documentation/usb/functionfs.txt
new file mode 100644
index 000000000000..eaaaea019fc7
--- /dev/null
+++ b/Documentation/usb/functionfs.txt
@@ -0,0 +1,67 @@
+*How FunctionFS works*
+
+From kernel point of view it is just a composite function with some
+unique behaviour. It may be added to an USB configuration only after
+the user space driver has registered by writing descriptors and
+strings (the user space program has to provide the same information
+that kernel level composite functions provide when they are added to
+the configuration).
+
+This in particular means that the composite initialisation functions
+may not be in init section (ie. may not use the __init tag).
+
+From user space point of view it is a file system which when
+mounted provides an "ep0" file. User space driver need to
+write descriptors and strings to that file. It does not need
+to worry about endpoints, interfaces or strings numbers but
+simply provide descriptors such as if the function was the
+only one (endpoints and strings numbers starting from one and
+interface numbers starting from zero). The FunctionFS changes
+them as needed also handling situation when numbers differ in
+different configurations.
+
+When descriptors and strings are written "ep#" files appear
+(one for each declared endpoint) which handle communication on
+a single endpoint. Again, FunctionFS takes care of the real
+numbers and changing of the configuration (which means that
+"ep1" file may be really mapped to (say) endpoint 3 (and when
+configuration changes to (say) endpoint 2)). "ep0" is used
+for receiving events and handling setup requests.
+
+When all files are closed the function disables itself.
+
+What I also want to mention is that the FunctionFS is designed in such
+a way that it is possible to mount it several times so in the end
+a gadget could use several FunctionFS functions. The idea is that
+each FunctionFS instance is identified by the device name used
+when mounting.
+
+One can imagine a gadget that has an Ethernet, MTP and HID interfaces
+where the last two are implemented via FunctionFS. On user space
+level it would look like this:
+
+$ insmod g_ffs.ko idVendor=<ID> iSerialNumber=<string> functions=mtp,hid
+$ mkdir /dev/ffs-mtp && mount -t functionfs mtp /dev/ffs-mtp
+$ ( cd /dev/ffs-mtp && mtp-daemon ) &
+$ mkdir /dev/ffs-hid && mount -t functionfs hid /dev/ffs-hid
+$ ( cd /dev/ffs-hid && hid-daemon ) &
+
+On kernel level the gadget checks ffs_data->dev_name to identify
+whether it's FunctionFS designed for MTP ("mtp") or HID ("hid").
+
+If no "functions" module parameters is supplied, the driver accepts
+just one function with any name.
+
+When "functions" module parameter is supplied, only functions
+with listed names are accepted. In particular, if the "functions"
+parameter's value is just a one-element list, then the behaviour
+is similar to when there is no "functions" at all; however,
+only a function with the specified name is accepted.
+
+The gadget is registered only after all the declared function
+filesystems have been mounted and USB descriptors of all functions
+have been written to their ep0's.
+
+Conversely, the gadget is unregistered after the first USB function
+closes its endpoints.
+
diff --git a/Documentation/usb/wusb-cbaf b/Documentation/usb/wusb-cbaf
index 426ddaaef96f..8b3d43efce90 100644
--- a/Documentation/usb/wusb-cbaf
+++ b/Documentation/usb/wusb-cbaf
@@ -36,7 +36,7 @@ COMMAND/ARGS are
get-cdid DEVICE
- Get the device ID associated to the HOST-CHDI we sent with
+ Get the device ID associated to the HOST-CHID we sent with
'set-chid'. We might not know about it.
set-cc DEVICE
diff --git a/Documentation/video4linux/4CCs.txt b/Documentation/video4linux/4CCs.txt
new file mode 100644
index 000000000000..41241af1ebfe
--- /dev/null
+++ b/Documentation/video4linux/4CCs.txt
@@ -0,0 +1,32 @@
+Guidelines for Linux4Linux pixel format 4CCs
+============================================
+
+Guidelines for Video4Linux 4CC codes defined using v4l2_fourcc() are
+specified in this document. First of the characters defines the nature of
+the pixel format, compression and colour space. The interpretation of the
+other three characters depends on the first one.
+
+Existing 4CCs may not obey these guidelines.
+
+Formats
+=======
+
+Raw bayer
+---------
+
+The following first characters are used by raw bayer formats:
+
+ B: raw bayer, uncompressed
+ b: raw bayer, DPCM compressed
+ a: A-law compressed
+ u: u-law compressed
+
+2nd character: pixel order
+ B: BGGR
+ G: GBRG
+ g: GRBG
+ R: RGGB
+
+3rd character: uncompressed bits-per-pixel 0--9, A--
+
+4th character: compressed bits-per-pixel 0--9, A--
diff --git a/Documentation/video4linux/README.cpia2 b/Documentation/video4linux/README.cpia2
index ce8213d28b67..38e742fd0df7 100644
--- a/Documentation/video4linux/README.cpia2
+++ b/Documentation/video4linux/README.cpia2
@@ -12,7 +12,7 @@ gqcam application to view this stream.
The driver is implemented as two kernel modules. The cpia2 module
contains the camera functions and the V4L interface. The cpia2_usb module
contains usb specific functions. The main reason for this was the size of the
-module was getting out of hand, so I separted them. It is not likely that
+module was getting out of hand, so I separated them. It is not likely that
there will be a parallel port version.
FEATURES:
diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt
index e6c2842407a4..1e6b6531bbcc 100644
--- a/Documentation/video4linux/gspca.txt
+++ b/Documentation/video4linux/gspca.txt
@@ -276,6 +276,7 @@ pac7302 093a:2622 Genius Eye 312
pac7302 093a:2624 PAC7302
pac7302 093a:2625 Genius iSlim 310
pac7302 093a:2626 Labtec 2200
+pac7302 093a:2627 Genius FaceCam 300
pac7302 093a:2628 Genius iLook 300
pac7302 093a:2629 Genious iSlim 300
pac7302 093a:262a Webcam 300k
diff --git a/Documentation/video4linux/v4l2-controls.txt b/Documentation/video4linux/v4l2-controls.txt
index e2492a9d1027..43da22b89728 100644
--- a/Documentation/video4linux/v4l2-controls.txt
+++ b/Documentation/video4linux/v4l2-controls.txt
@@ -130,8 +130,18 @@ Menu controls are added by calling v4l2_ctrl_new_std_menu:
const struct v4l2_ctrl_ops *ops,
u32 id, s32 max, s32 skip_mask, s32 def);
+Or alternatively for integer menu controls, by calling v4l2_ctrl_new_int_menu:
+
+ struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_ops *ops,
+ u32 id, s32 max, s32 def, const s64 *qmenu_int);
+
These functions are typically called right after the v4l2_ctrl_handler_init:
+ static const s64 exp_bias_qmenu[] = {
+ -2, -1, 0, 1, 2
+ };
+
v4l2_ctrl_handler_init(&foo->ctrl_handler, nr_of_controls);
v4l2_ctrl_new_std(&foo->ctrl_handler, &foo_ctrl_ops,
V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
@@ -141,6 +151,11 @@ These functions are typically called right after the v4l2_ctrl_handler_init:
V4L2_CID_POWER_LINE_FREQUENCY,
V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0,
V4L2_CID_POWER_LINE_FREQUENCY_DISABLED);
+ v4l2_ctrl_new_int_menu(&foo->ctrl_handler, &foo_ctrl_ops,
+ V4L2_CID_EXPOSURE_BIAS,
+ ARRAY_SIZE(exp_bias_qmenu) - 1,
+ ARRAY_SIZE(exp_bias_qmenu) / 2 - 1,
+ exp_bias_qmenu);
...
if (foo->ctrl_handler.error) {
int err = foo->ctrl_handler.error;
@@ -164,6 +179,12 @@ controls. There is no min argument since that is always 0 for menu controls,
and instead of a step there is a skip_mask argument: if bit X is 1, then menu
item X is skipped.
+The v4l2_ctrl_new_int_menu function creates a new standard integer menu
+control with driver-specific items in the menu. It differs from
+v4l2_ctrl_new_std_menu in that it doesn't have the mask argument and takes
+as the last argument an array of signed 64-bit integers that form an exact
+menu item list.
+
Note that if something fails, the function will return NULL or an error and
set ctrl_handler->error to the error code. If ctrl_handler->error was already
set, then it will just return and do nothing. This is also true for
diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
index 659b2ba12a4f..1f5905270050 100644
--- a/Documentation/video4linux/v4l2-framework.txt
+++ b/Documentation/video4linux/v4l2-framework.txt
@@ -182,11 +182,11 @@ static int __devinit drv_probe(struct pci_dev *pdev,
}
If you have multiple device nodes then it can be difficult to know when it is
-safe to unregister v4l2_device. For this purpose v4l2_device has refcounting
-support. The refcount is increased whenever video_register_device is called and
-it is decreased whenever that device node is released. When the refcount reaches
-zero, then the v4l2_device release() callback is called. You can do your final
-cleanup there.
+safe to unregister v4l2_device for hotpluggable devices. For this purpose
+v4l2_device has refcounting support. The refcount is increased whenever
+video_register_device is called and it is decreased whenever that device node
+is released. When the refcount reaches zero, then the v4l2_device release()
+callback is called. You can do your final cleanup there.
If other device nodes (e.g. ALSA) are created, then you can increase and
decrease the refcount manually as well by calling:
@@ -197,6 +197,10 @@ or:
int v4l2_device_put(struct v4l2_device *v4l2_dev);
+Since the initial refcount is 1 you also need to call v4l2_device_put in the
+disconnect() callback (for USB devices) or in the remove() callback (for e.g.
+PCI devices), otherwise the refcount will never reach 0.
+
struct v4l2_subdev
------------------
@@ -262,11 +266,16 @@ struct v4l2_subdev_video_ops {
...
};
+struct v4l2_subdev_pad_ops {
+ ...
+};
+
struct v4l2_subdev_ops {
const struct v4l2_subdev_core_ops *core;
const struct v4l2_subdev_tuner_ops *tuner;
const struct v4l2_subdev_audio_ops *audio;
const struct v4l2_subdev_video_ops *video;
+ const struct v4l2_subdev_pad_ops *video;
};
The core ops are common to all subdevs, the other categories are implemented
@@ -303,6 +312,22 @@ Don't forget to cleanup the media entity before the sub-device is destroyed:
media_entity_cleanup(&sd->entity);
+If the subdev driver intends to process video and integrate with the media
+framework, it must implement format related functionality using
+v4l2_subdev_pad_ops instead of v4l2_subdev_video_ops.
+
+In that case, the subdev driver may set the link_validate field to provide
+its own link validation function. The link validation function is called for
+every link in the pipeline where both of the ends of the links are V4L2
+sub-devices. The driver is still responsible for validating the correctness
+of the format configuration between sub-devices and video nodes.
+
+If link_validate op is not set, the default function
+v4l2_subdev_link_validate_default() is used instead. This function ensures
+that width, height and the media bus pixel code are equal on both source and
+sink of the link. Subdev drivers are also free to use this function to
+perform the checks mentioned above in addition to their own checks.
+
A device (bridge) driver needs to register the v4l2_subdev with the
v4l2_device:
@@ -555,19 +580,25 @@ allocated memory.
You should also set these fields:
- v4l2_dev: set to the v4l2_device parent device.
+
- name: set to something descriptive and unique.
+
- fops: set to the v4l2_file_operations struct.
+
- ioctl_ops: if you use the v4l2_ioctl_ops to simplify ioctl maintenance
(highly recommended to use this and it might become compulsory in the
future!), then set this to your v4l2_ioctl_ops struct.
+
- lock: leave to NULL if you want to do all the locking in the driver.
- Otherwise you give it a pointer to a struct mutex_lock and before any
- of the v4l2_file_operations is called this lock will be taken by the
- core and released afterwards.
+ Otherwise you give it a pointer to a struct mutex_lock and before the
+ unlocked_ioctl file operation is called this lock will be taken by the
+ core and released afterwards. See the next section for more details.
+
- prio: keeps track of the priorities. Used to implement VIDIOC_G/S_PRIORITY.
If left to NULL, then it will use the struct v4l2_prio_state in v4l2_device.
If you want to have a separate priority state per (group of) device node(s),
then you can point it to your own struct v4l2_prio_state.
+
- parent: you only set this if v4l2_device was registered with NULL as
the parent device struct. This only happens in cases where one hardware
device has multiple PCI devices that all share the same v4l2_device core.
@@ -577,6 +608,7 @@ You should also set these fields:
(cx8802). Since the v4l2_device cannot be associated with a particular
PCI device it is setup without a parent device. But when the struct
video_device is setup you do know which parent PCI device to use.
+
- flags: optional. Set to V4L2_FL_USE_FH_PRIO if you want to let the framework
handle the VIDIOC_G/S_PRIORITY ioctls. This requires that you use struct
v4l2_fh. Eventually this flag will disappear once all drivers use the core
@@ -587,6 +619,16 @@ in your v4l2_file_operations struct.
Do not use .ioctl! This is deprecated and will go away in the future.
+In some cases you want to tell the core that a function you had specified in
+your v4l2_ioctl_ops should be ignored. You can mark such ioctls by calling this
+function before video_device_register is called:
+
+void v4l2_disable_ioctl(struct video_device *vdev, unsigned int cmd);
+
+This tends to be needed if based on external factors (e.g. which card is
+being used) you want to turns off certain features in v4l2_ioctl_ops without
+having to make a new struct.
+
The v4l2_file_operations struct is a subset of file_operations. The main
difference is that the inode argument is omitted since it is never used.
@@ -609,8 +651,22 @@ v4l2_file_operations and locking
--------------------------------
You can set a pointer to a mutex_lock in struct video_device. Usually this
-will be either a top-level mutex or a mutex per device node. If you want
-finer-grained locking then you have to set it to NULL and do you own locking.
+will be either a top-level mutex or a mutex per device node. By default this
+lock will be used for unlocked_ioctl, but you can disable locking for
+selected ioctls by calling:
+
+ void v4l2_disable_ioctl_locking(struct video_device *vdev, unsigned int cmd);
+
+E.g.: v4l2_disable_ioctl_locking(vdev, VIDIOC_DQBUF);
+
+You have to call this before you register the video_device.
+
+Particularly with USB drivers where certain commands such as setting controls
+can take a long time you may want to do your own locking for the buffer queuing
+ioctls.
+
+If you want still finer-grained locking then you have to set mutex_lock to NULL
+and do you own locking completely.
It is up to the driver developer to decide which method to use. However, if
your driver has high-latency operations (for example, changing the exposure
@@ -618,7 +674,7 @@ of a USB webcam might take a long time), then you might be better off with
doing your own locking if you want to allow the user to do other things with
the device while waiting for the high-latency command to finish.
-If a lock is specified then all file operations will be serialized on that
+If a lock is specified then all ioctl commands will be serialized on that
lock. If you use videobuf then you must pass the same lock to the videobuf
queue initialize function: if videobuf has to wait for a frame to arrive, then
it will temporarily unlock the lock and relock it afterwards. If your driver
@@ -941,21 +997,35 @@ fast.
Useful functions:
-- v4l2_event_queue()
+void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev)
Queue events to video device. The driver's only responsibility is to fill
in the type and the data fields. The other fields will be filled in by
V4L2.
-- v4l2_event_subscribe()
+int v4l2_event_subscribe(struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub, unsigned elems,
+ const struct v4l2_subscribed_event_ops *ops)
The video_device->ioctl_ops->vidioc_subscribe_event must check the driver
is able to produce events with specified event id. Then it calls
- v4l2_event_subscribe() to subscribe the event. The last argument is the
- size of the event queue for this event. If it is 0, then the framework
- will fill in a default value (this depends on the event type).
+ v4l2_event_subscribe() to subscribe the event.
+
+ The elems argument is the size of the event queue for this event. If it is 0,
+ then the framework will fill in a default value (this depends on the event
+ type).
+
+ The ops argument allows the driver to specify a number of callbacks:
+ * add: called when a new listener gets added (subscribing to the same
+ event twice will only cause this callback to get called once)
+ * del: called when a listener stops listening
+ * replace: replace event 'old' with event 'new'.
+ * merge: merge event 'old' into event 'new'.
+ All 4 callbacks are optional, if you don't want to specify any callbacks
+ the ops argument itself maybe NULL.
-- v4l2_event_unsubscribe()
+int v4l2_event_unsubscribe(struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
vidioc_unsubscribe_event in struct v4l2_ioctl_ops. A driver may use
v4l2_event_unsubscribe() directly unless it wants to be involved in
@@ -964,7 +1034,7 @@ Useful functions:
The special type V4L2_EVENT_ALL may be used to unsubscribe all events. The
drivers may want to handle this in a special way.
-- v4l2_event_pending()
+int v4l2_event_pending(struct v4l2_fh *fh)
Returns the number of pending events. Useful when implementing poll.
diff --git a/drivers/staging/vme/vme_api.txt b/Documentation/vme_api.txt
index 856efa35f6e3..856efa35f6e3 100644
--- a/drivers/staging/vme/vme_api.txt
+++ b/Documentation/vme_api.txt
diff --git a/Documentation/watchdog/src/watchdog-test.c b/Documentation/watchdog/src/watchdog-test.c
index 63fdc34ceb98..73ff5cc93e05 100644
--- a/Documentation/watchdog/src/watchdog-test.c
+++ b/Documentation/watchdog/src/watchdog-test.c
@@ -7,6 +7,7 @@
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
+#include <signal.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/watchdog.h>
@@ -29,6 +30,14 @@ static void keep_alive(void)
* The main program. Run the program with "-d" to disable the card,
* or "-e" to enable the card.
*/
+
+void term(int sig)
+{
+ close(fd);
+ fprintf(stderr, "Stopping watchdog ticks...\n");
+ exit(0);
+}
+
int main(int argc, char *argv[])
{
int flags;
@@ -47,26 +56,31 @@ int main(int argc, char *argv[])
ioctl(fd, WDIOC_SETOPTIONS, &flags);
fprintf(stderr, "Watchdog card disabled.\n");
fflush(stderr);
- exit(0);
+ goto end;
} else if (!strncasecmp(argv[1], "-e", 2)) {
flags = WDIOS_ENABLECARD;
ioctl(fd, WDIOC_SETOPTIONS, &flags);
fprintf(stderr, "Watchdog card enabled.\n");
fflush(stderr);
- exit(0);
+ goto end;
} else {
fprintf(stderr, "-d to disable, -e to enable.\n");
fprintf(stderr, "run by itself to tick the card.\n");
fflush(stderr);
- exit(0);
+ goto end;
}
} else {
fprintf(stderr, "Watchdog Ticking Away!\n");
fflush(stderr);
}
+ signal(SIGINT, term);
+
while(1) {
keep_alive();
sleep(1);
}
+end:
+ close(fd);
+ return 0;
}
diff --git a/Documentation/watchdog/watchdog-kernel-api.txt b/Documentation/watchdog/watchdog-kernel-api.txt
index 227f6cd0e5fa..25fe4304f2fc 100644
--- a/Documentation/watchdog/watchdog-kernel-api.txt
+++ b/Documentation/watchdog/watchdog-kernel-api.txt
@@ -59,7 +59,7 @@ It contains following fields:
* bootstatus: status of the device after booting (reported with watchdog
WDIOF_* status bits).
* driver_data: a pointer to the drivers private data of a watchdog device.
- This data should only be accessed via the watchdog_set_drvadata and
+ This data should only be accessed via the watchdog_set_drvdata and
watchdog_get_drvdata routines.
* status: this field contains a number of status bits that give extra
information about the status of the device (Like: is the watchdog timer
diff --git a/Documentation/zh_CN/magic-number.txt b/Documentation/zh_CN/magic-number.txt
index f606ba8598cf..4263022f5002 100644
--- a/Documentation/zh_CN/magic-number.txt
+++ b/Documentation/zh_CN/magic-number.txt
@@ -160,7 +160,7 @@ QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry drivers/scsi/arm/queue.c
HTB_CMAGIC 0xFEFAFEF1 htb_class net/sched/sch_htb.c
NMI_MAGIC 0x48414d4d455201 nmi_s arch/mips/include/asm/sn/nmi.h
-请注意,在声音记忆管理中仍然有每一些被定义的驱动魔术值。查看include/sound/sndmagic.h来获取他们完整的列表信息。很多OSS声音驱动拥有自己从声卡PCI ID构建的魔术值-他们也没有被列在这里。
+请注意,在声音记忆管理中仍然有一些特殊的为每个驱动定义的魔术值。查看include/sound/sndmagic.h来获取他们完整的列表信息。很多OSS声音驱动拥有自己从声卡PCI ID构建的魔术值-他们也没有被列在这里。
IrDA子系统也使用了大量的自己的魔术值,查看include/net/irda/irda.h来获取他们完整的信息。
diff --git a/MAINTAINERS b/MAINTAINERS
index d4abe7572ead..150a29f3cd33 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -640,13 +640,6 @@ S: Maintained
F: drivers/amba/
F: include/linux/amba/bus.h
-ARM/ADI ROADRUNNER MACHINE SUPPORT
-M: Lennert Buytenhek <kernel@wantstofly.org>
-L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S: Maintained
-F: arch/arm/mach-ixp23xx/
-F: arch/arm/mach-ixp23xx/include/mach/
-
ARM/ADS SPHERE MACHINE SUPPORT
M: Lennert Buytenhek <kernel@wantstofly.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -746,7 +739,10 @@ M: Barry Song <baohua.song@csr.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: arch/arm/mach-prima2/
-F: drivers/dma/sirf-dma*
+F: drivers/dma/sirf-dma.c
+F: drivers/i2c/busses/i2c-sirf.c
+F: drivers/pinctrl/pinctrl-sirf.c
+F: drivers/spi/spi-sirf.c
ARM/EBSA110 MACHINE SUPPORT
M: Russell King <linux@arm.linux.org.uk>
@@ -859,21 +855,11 @@ M: Dan Williams <dan.j.williams@intel.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
-ARM/INTEL IXP2000 ARM ARCHITECTURE
-M: Lennert Buytenhek <kernel@wantstofly.org>
-L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S: Maintained
-
ARM/INTEL IXDP2850 MACHINE SUPPORT
M: Lennert Buytenhek <kernel@wantstofly.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
-ARM/INTEL IXP23XX ARM ARCHITECTURE
-M: Lennert Buytenhek <kernel@wantstofly.org>
-L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S: Maintained
-
ARM/INTEL IXP4XX ARM ARCHITECTURE
M: Imre Kaloz <kaloz@openwrt.org>
M: Krzysztof Halasa <khc@pm.waw.pl>
@@ -908,11 +894,12 @@ ARM/MAGICIAN MACHINE SUPPORT
M: Philipp Zabel <philipp.zabel@gmail.com>
S: Maintained
-ARM/Marvell Loki/Kirkwood/MV78xx0/Orion SOC support
-M: Lennert Buytenhek <kernel@wantstofly.org>
-M: Nicolas Pitre <nico@fluxnic.net>
+ARM/Marvell Dove/Kirkwood/MV78xx0/Orion SOC support
+M: Jason Cooper <jason@lakedaemon.net>
+M: Andrew Lunn <andrew@lunn.ch>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S: Odd Fixes
+S: Maintained
+F: arch/arm/mach-dove/
F: arch/arm/mach-kirkwood/
F: arch/arm/mach-mv78xx0/
F: arch/arm/mach-orion5x/
@@ -1331,6 +1318,21 @@ M: Nicolas Ferre <nicolas.ferre@atmel.com>
S: Supported
F: drivers/tty/serial/atmel_serial.c
+ATMEL DMA DRIVER
+M: Nicolas Ferre <nicolas.ferre@atmel.com>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S: Supported
+F: drivers/dma/at_hdmac.c
+F: drivers/dma/at_hdmac_regs.h
+F: arch/arm/mach-at91/include/mach/at_hdmac.h
+
+ATMEL ISI DRIVER
+M: Josh Wu <josh.wu@atmel.com>
+L: linux-media@vger.kernel.org
+S: Supported
+F: drivers/media/video/atmel-isi.c
+F: include/media/atmel-isi.h
+
ATMEL LCDFB DRIVER
M: Nicolas Ferre <nicolas.ferre@atmel.com>
L: linux-fbdev@vger.kernel.org
@@ -1348,10 +1350,22 @@ M: Nicolas Ferre <nicolas.ferre@atmel.com>
S: Supported
F: drivers/spi/spi-atmel.*
+ATMEL Timer Counter (TC) AND CLOCKSOURCE DRIVERS
+M: Nicolas Ferre <nicolas.ferre@atmel.com>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S: Supported
+F: drivers/misc/atmel_tclib.c
+F: drivers/clocksource/tcb_clksrc.c
+
+ATMEL TSADCC DRIVER
+M: Josh Wu <josh.wu@atmel.com>
+L: linux-input@vger.kernel.org
+S: Supported
+F: drivers/input/touchscreen/atmel_tsadcc.c
+
ATMEL USBA UDC DRIVER
M: Nicolas Ferre <nicolas.ferre@atmel.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W: http://avr32linux.org/twiki/bin/view/Main/AtmelUsbDeviceDriver
S: Supported
F: drivers/usb/gadget/atmel_usba_udc.*
@@ -1812,6 +1826,12 @@ L: linux-kernel@zh-kernel.org (moderated for non-subscribers)
S: Maintained
F: Documentation/zh_CN/
+CHIPIDEA USB HIGH SPEED DUAL ROLE CONTROLLER
+M: Alexander Shishkin <alexander.shishkin@linux.intel.com>
+L: linux-usb@vger.kernel.org
+S: Maintained
+F: drivers/usb/chipidea/
+
CISCO VIC ETHERNET NIC DRIVER
M: Christian Benvenuti <benve@cisco.com>
M: Roopa Prabhu <roprabhu@cisco.com>
@@ -2378,10 +2398,10 @@ F: drivers/gpu/drm/
F: include/drm/
INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
-M: Keith Packard <keithp@keithp.com>
+M: Daniel Vetter <daniel.vetter@ffwll.ch>
L: intel-gfx@lists.freedesktop.org (subscribers-only)
L: dri-devel@lists.freedesktop.org
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/keithp/linux.git
+T: git git://people.freedesktop.org/~danvet/drm-intel
S: Supported
F: drivers/gpu/drm/i915
F: include/drm/i915*
@@ -2698,6 +2718,13 @@ S: Maintained
F: Documentation/hwmon/f71805f
F: drivers/hwmon/f71805f.c
+FC0011 TUNER DRIVER
+M: Michael Buesch <m@bues.ch>
+L: linux-media@vger.kernel.org
+S: Maintained
+F: drivers/media/common/tuners/fc0011.h
+F: drivers/media/common/tuners/fc0011.c
+
FANOTIFY
M: Eric Paris <eparis@redhat.com>
S: Maintained
@@ -2756,6 +2783,15 @@ T: git git://git.alsa-project.org/alsa-kernel.git
S: Maintained
F: sound/firewire/
+FIREWIRE SBP-2 TARGET
+M: Chris Boot <bootc@bootc.net>
+L: linux-scsi@vger.kernel.org
+L: target-devel@vger.kernel.org
+L: linux1394-devel@lists.sourceforge.net
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core-2.6.git master
+S: Maintained
+F: drivers/target/sbp/
+
FIREWIRE SUBSYSTEM
M: Stefan Richter <stefanr@s5r6.in-berlin.de>
L: linux1394-devel@lists.sourceforge.net
@@ -2892,7 +2928,7 @@ S: Maintained
F: arch/frv/
FUJITSU LAPTOP EXTRAS
-M: Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
+M: Jonathan Woithe <jwoithe@just42.net>
L: platform-driver-x86@vger.kernel.org
S: Maintained
F: drivers/platform/x86/fujitsu-laptop.c
@@ -3318,12 +3354,6 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux.git
S: Maintained
F: arch/ia64/
-IBM MCA SCSI SUBSYSTEM DRIVER
-M: Michael Lang <langa2@kph.uni-mainz.de>
-W: http://www.uni-mainz.de/~langm000/linux.html
-S: Maintained
-F: drivers/scsi/ibmmca.c
-
IBM Power Linux RAID adapter
M: Brian King <brking@us.ibm.com>
S: Supported
@@ -3386,6 +3416,7 @@ IIO SUBSYSTEM AND DRIVERS
M: Jonathan Cameron <jic23@cam.ac.uk>
L: linux-iio@vger.kernel.org
S: Maintained
+F: drivers/iio/
F: drivers/staging/iio/
IKANOS/ADI EAGLE ADSL USB DRIVER
@@ -3434,6 +3465,8 @@ Q: http://patchwork.kernel.org/project/linux-input/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git
S: Maintained
F: drivers/input/
+F: include/linux/input.h
+F: include/linux/input/
INPUT MULTITOUCH (MT) PROTOCOL
M: Henrik Rydberg <rydberg@euromail.se>
@@ -3605,6 +3638,14 @@ S: Supported
W: http://wireless.kernel.org/en/users/Drivers/iwmc3200wifi
F: drivers/net/wireless/iwmc3200wifi/
+INTEL MANAGEMENT ENGINE (mei)
+M: Tomas Winkler <tomas.winkler@intel.com>
+L: linux-kernel@vger.kernel.org
+S: Supported
+F: include/linux/mei.h
+F: drivers/misc/mei/*
+F: Documentation/mei/*
+
IOC3 ETHERNET DRIVER
M: Ralf Baechle <ralf@linux-mips.org>
L: linux-mips@linux-mips.org
@@ -4420,13 +4461,6 @@ T: git git://git.monstr.eu/linux-2.6-microblaze.git
S: Supported
F: arch/microblaze/
-MICROCHANNEL ARCHITECTURE (MCA)
-M: James Bottomley <James.Bottomley@HansenPartnership.com>
-S: Maintained
-F: Documentation/mca.txt
-F: drivers/mca/
-F: include/linux/mca*
-
MICROTEK X6 SCANNER
M: Oliver Neukum <oliver@neukum.name>
S: Maintained
@@ -5226,6 +5260,14 @@ M: Linus Walleij <linus.walleij@linaro.org>
S: Maintained
F: drivers/pinctrl/
+PIN CONTROLLER - ST SPEAR
+M: Viresh Kumar <viresh.kumar@st.com>
+L: spear-devel@list.st.com
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+W: http://www.st.com/spear
+S: Maintained
+F: driver/pinctrl/spear/
+
PKTCDVD DRIVER
M: Peter Osterlund <petero2@telia.com>
S: Maintained
@@ -6330,21 +6372,6 @@ F: arch/arm/mach-spear*/clock.c
F: arch/arm/plat-spear/clock.c
F: arch/arm/plat-spear/include/plat/clock.h
-SPEAR PAD MULTIPLEXING SUPPORT
-M: Viresh Kumar <viresh.kumar@st.com>
-L: spear-devel@list.st.com
-L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W: http://www.st.com/spear
-S: Maintained
-F: arch/arm/plat-spear/include/plat/padmux.h
-F: arch/arm/plat-spear/padmux.c
-F: arch/arm/mach-spear*/spear*xx.c
-F: arch/arm/mach-spear*/include/mach/generic.h
-F: arch/arm/mach-spear3xx/spear3*0.c
-F: arch/arm/mach-spear3xx/spear3*0_evb.c
-F: arch/arm/mach-spear6xx/spear600.c
-F: arch/arm/mach-spear6xx/spear600_evb.c
-
SPI SUBSYSTEM
M: Grant Likely <grant.likely@secretlab.ca>
L: spi-devel-general@lists.sourceforge.net
@@ -6551,7 +6578,7 @@ M: Paul Mundt <lethal@linux-sh.org>
L: linux-sh@vger.kernel.org
W: http://www.linux-sh.org
Q: http://patchwork.kernel.org/project/linux-sh/list/
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6.git sh-latest
+T: git git://github.com/pmundt/linux-sh.git sh-latest
S: Supported
F: Documentation/sh/
F: arch/sh/
@@ -6669,6 +6696,12 @@ F: drivers/misc/tifm*
F: drivers/mmc/host/tifm_sd.c
F: include/linux/tifm.h
+TI LM49xxx FAMILY ASoC CODEC DRIVERS
+M: M R Swami Reddy <mr.swami.reddy@ti.com>
+L: alsa-devel@alsa-project.org (moderated for non-subscribers)
+S: Maintained
+F: sound/soc/codecs/lm49453*
+
TI TWL4030 SERIES SOC CODEC DRIVER
M: Peter Ujfalusi <peter.ujfalusi@ti.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
@@ -7046,6 +7079,14 @@ W: http://pegasus2.sourceforge.net/
S: Maintained
F: drivers/net/usb/pegasus.*
+USB PHY LAYER
+M: Felipe Balbi <balbi@ti.com>
+L: linux-usb@vger.kernel.org
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
+S: Maintained
+F: drivers/usb/phy/
+F: drivers/usb/otg/
+
USB PRINTER DRIVER (usblp)
M: Pete Zaitcev <zaitcev@redhat.com>
L: linux-usb@vger.kernel.org
@@ -7159,7 +7200,7 @@ F: include/linux/usb/usbnet.h
USB VIDEO CLASS
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
-L: linux-uvc-devel@lists.berlios.de (subscribers-only)
+L: linux-uvc-devel@lists.sourceforge.net (subscribers-only)
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git
W: http://www.ideasonboard.org/uvc/
@@ -7329,6 +7370,18 @@ S: Maintained
F: drivers/vlynq/vlynq.c
F: include/linux/vlynq.h
+VME SUBSYSTEM
+M: Martyn Welch <martyn.welch@ge.com>
+M: Manohar Vanga <manohar.vanga@cern.ch>
+M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+L: devel@driverdev.osuosl.org
+S: Maintained
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
+F: Documentation/vme_api.txt
+F: drivers/staging/vme/
+F: drivers/vme/
+F: include/linux/vme*
+
VMWARE VMXNET3 ETHERNET DRIVER
M: Shreyas Bhatewara <sbhatewara@vmware.com>
M: "VMware, Inc." <pv-drivers@vmware.com>
@@ -7570,7 +7623,7 @@ XFS FILESYSTEM
P: Silicon Graphics Inc
M: Ben Myers <bpm@sgi.com>
M: Alex Elder <elder@kernel.org>
-M: xfs-masters@oss.sgi.com
+M: xfs@oss.sgi.com
L: xfs@oss.sgi.com
W: http://oss.sgi.com/projects/xfs
T: git git://oss.sgi.com/xfs/xfs.git
diff --git a/Makefile b/Makefile
index a6879630a3ea..b62c1e09444a 100644
--- a/Makefile
+++ b/Makefile
@@ -400,8 +400,10 @@ export MODVERDIR := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_ve
# Files to ignore in find ... statements
-RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS -o -name .pc -o -name .hg -o -name .git \) -prune -o
-export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CVS --exclude .pc --exclude .hg --exclude .git
+RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS \
+ -o -name .pc -o -name .hg -o -name .git \) -prune -o
+export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn \
+ --exclude CVS --exclude .pc --exclude .hg --exclude .git
# ===========================================================================
# Rules shared between *config targets and build targets
@@ -564,6 +566,16 @@ else
KBUILD_CFLAGS += -O2
endif
+ifdef CONFIG_READABLE_ASM
+# Disable optimizations that make assembler listings hard to read.
+# reorder blocks reorders the control in the function
+# ipa clone creates specialized cloned functions
+# partial inlining inlines only parts of functions
+KBUILD_CFLAGS += $(call cc-option,-fno-reorder-blocks,) \
+ $(call cc-option,-fno-ipa-cp-clone,) \
+ $(call cc-option,-fno-partial-inlining)
+endif
+
include $(srctree)/arch/$(SRCARCH)/Makefile
ifneq ($(CONFIG_FRAME_WARN),0)
@@ -784,6 +796,10 @@ quiet_cmd_vmlinux_version = GEN .version
quiet_cmd_sysmap = SYSMAP
cmd_sysmap = $(CONFIG_SHELL) $(srctree)/scripts/mksysmap
+# Sort exception table at build time
+quiet_cmd_sortextable = SORTEX
+ cmd_sortextable = $(objtree)/scripts/sortextable
+
# Link of vmlinux
# If CONFIG_KALLSYMS is set .version is already updated
# Generate System.map and verify that the content is consistent
@@ -796,6 +812,12 @@ define rule_vmlinux__
$(call cmd,vmlinux__)
$(Q)echo 'cmd_$@ := $(cmd_vmlinux__)' > $(@D)/.$(@F).cmd
+ $(if $(CONFIG_BUILDTIME_EXTABLE_SORT), \
+ $(Q)$(if $($(quiet)cmd_sortextable), \
+ echo ' $($(quiet)cmd_sortextable) vmlinux' &&) \
+ $(cmd_sortextable) vmlinux)
+
+
$(Q)$(if $($(quiet)cmd_sysmap), \
echo ' $($(quiet)cmd_sysmap) System.map' &&) \
$(cmd_sysmap) $@ System.map; \
@@ -966,7 +988,7 @@ prepare3: include/config/kernel.release
ifneq ($(KBUILD_SRC),)
@$(kecho) ' Using $(srctree) as source for kernel'
$(Q)if [ -f $(srctree)/.config -o -d $(srctree)/include/config ]; then \
- echo " $(srctree) is not clean, please run 'make mrproper'";\
+ echo " $(srctree) is not clean, please run 'make mrproper'"; \
echo " in the '$(srctree)' directory.";\
/bin/false; \
fi;
@@ -1003,8 +1025,8 @@ define filechk_utsrelease.h
endef
define filechk_version.h
- (echo \#define LINUX_VERSION_CODE $(shell \
- expr $(VERSION) \* 65536 + 0$(PATCHLEVEL) \* 256 + 0$(SUBLEVEL)); \
+ (echo \#define LINUX_VERSION_CODE $(shell \
+ expr $(VERSION) \* 65536 + 0$(PATCHLEVEL) \* 256 + 0$(SUBLEVEL)); \
echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))';)
endef
@@ -1471,6 +1493,13 @@ kernelrelease:
kernelversion:
@echo $(KERNELVERSION)
+# Clear a bunch of variables before executing the submake
+tools/: FORCE
+ $(Q)$(MAKE) LDFLAGS= MAKEFLAGS= -C $(src)/tools/
+
+tools/%: FORCE
+ $(Q)$(MAKE) LDFLAGS= MAKEFLAGS= -C $(src)/tools/ $*
+
# Single targets
# ---------------------------------------------------------------------------
# Single targets are compatible with:
diff --git a/README b/README
index 0d5a7ddbe3ee..9beaed0ed620 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
- Linux kernel release 3.x <http://kernel.org/>
+ Linux kernel release 3.x <http://kernel.org/>
These are the release notes for Linux version 3. Read them carefully,
as they tell you what this is all about, explain how to install the
@@ -62,13 +62,13 @@ INSTALLING the kernel source:
directory where you have permissions (eg. your home directory) and
unpack it:
- gzip -cd linux-3.X.tar.gz | tar xvf -
+ gzip -cd linux-3.X.tar.gz | tar xvf -
or
- bzip2 -dc linux-3.X.tar.bz2 | tar xvf -
+ bzip2 -dc linux-3.X.tar.bz2 | tar xvf -
- Replace "XX" with the version number of the latest kernel.
+ Replace "X" with the version number of the latest kernel.
Do NOT use the /usr/src/linux area! This area has a (usually
incomplete) set of kernel headers that are used by the library header
@@ -78,49 +78,43 @@ INSTALLING the kernel source:
- You can also upgrade between 3.x releases by patching. Patches are
distributed in the traditional gzip and the newer bzip2 format. To
install by patching, get all the newer patch files, enter the
- top level directory of the kernel source (linux-3.x) and execute:
+ top level directory of the kernel source (linux-3.X) and execute:
- gzip -cd ../patch-3.x.gz | patch -p1
+ gzip -cd ../patch-3.x.gz | patch -p1
or
- bzip2 -dc ../patch-3.x.bz2 | patch -p1
- (repeat xx for all versions bigger than the version of your current
- source tree, _in_order_) and you should be ok. You may want to remove
- the backup files (xxx~ or xxx.orig), and make sure that there are no
- failed patches (xxx# or xxx.rej). If there are, either you or me has
- made a mistake.
+ bzip2 -dc ../patch-3.x.bz2 | patch -p1
+
+ Replace "x" for all versions bigger than the version "X" of your current
+ source tree, _in_order_, and you should be ok. You may want to remove
+ the backup files (some-file-name~ or some-file-name.orig), and make sure
+ that there are no failed patches (some-file-name# or some-file-name.rej).
+ If there are, either you or I have made a mistake.
Unlike patches for the 3.x kernels, patches for the 3.x.y kernels
(also known as the -stable kernels) are not incremental but instead apply
- directly to the base 3.x kernel. Please read
- Documentation/applying-patches.txt for more information.
+ directly to the base 3.x kernel. For example, if your base kernel is 3.0
+ and you want to apply the 3.0.3 patch, you must not first apply the 3.0.1
+ and 3.0.2 patches. Similarly, if you are running kernel version 3.0.2 and
+ want to jump to 3.0.3, you must first reverse the 3.0.2 patch (that is,
+ patch -R) _before_ applying the 3.0.3 patch. You can read more on this in
+ Documentation/applying-patches.txt
Alternatively, the script patch-kernel can be used to automate this
process. It determines the current kernel version and applies any
patches found.
- linux/scripts/patch-kernel linux
+ linux/scripts/patch-kernel linux
The first argument in the command above is the location of the
kernel source. Patches are applied from the current directory, but
an alternative directory can be specified as the second argument.
- - If you are upgrading between releases using the stable series patches
- (for example, patch-3.x.y), note that these "dot-releases" are
- not incremental and must be applied to the 3.x base tree. For
- example, if your base kernel is 3.0 and you want to apply the
- 3.0.3 patch, you do not and indeed must not first apply the
- 3.0.1 and 3.0.2 patches. Similarly, if you are running kernel
- version 3.0.2 and want to jump to 3.0.3, you must first
- reverse the 3.0.2 patch (that is, patch -R) _before_ applying
- the 3.0.3 patch.
- You can read more on this in Documentation/applying-patches.txt
-
- Make sure you have no stale .o files and dependencies lying around:
- cd linux
- make mrproper
+ cd linux
+ make mrproper
You should now have the sources correctly installed.
@@ -137,21 +131,23 @@ SOFTWARE REQUIREMENTS
BUILD directory for the kernel:
- When compiling the kernel all output files will per default be
+ When compiling the kernel, all output files will per default be
stored together with the kernel source code.
Using the option "make O=output/dir" allow you to specify an alternate
place for the output files (including .config).
Example:
- kernel source code: /usr/src/linux-3.N
- build directory: /home/name/build/kernel
- To configure and build the kernel use:
- cd /usr/src/linux-3.N
- make O=/home/name/build/kernel menuconfig
- make O=/home/name/build/kernel
- sudo make O=/home/name/build/kernel modules_install install
+ kernel source code: /usr/src/linux-3.X
+ build directory: /home/name/build/kernel
+
+ To configure and build the kernel, use:
- Please note: If the 'O=output/dir' option is used then it must be
+ cd /usr/src/linux-3.X
+ make O=/home/name/build/kernel menuconfig
+ make O=/home/name/build/kernel
+ sudo make O=/home/name/build/kernel modules_install install
+
+ Please note: If the 'O=output/dir' option is used, then it must be
used for all invocations of make.
CONFIGURING the kernel:
@@ -163,61 +159,78 @@ CONFIGURING the kernel:
new version with minimal work, use "make oldconfig", which will
only ask you for the answers to new questions.
- - Alternate configuration commands are:
- "make config" Plain text interface.
- "make menuconfig" Text based color menus, radiolists & dialogs.
- "make nconfig" Enhanced text based color menus.
- "make xconfig" X windows (Qt) based configuration tool.
- "make gconfig" X windows (Gtk) based configuration tool.
- "make oldconfig" Default all questions based on the contents of
- your existing ./.config file and asking about
- new config symbols.
- "make silentoldconfig"
- Like above, but avoids cluttering the screen
- with questions already answered.
- Additionally updates the dependencies.
- "make defconfig" Create a ./.config file by using the default
- symbol values from either arch/$ARCH/defconfig
- or arch/$ARCH/configs/${PLATFORM}_defconfig,
- depending on the architecture.
- "make ${PLATFORM}_defconfig"
- Create a ./.config file by using the default
- symbol values from
- arch/$ARCH/configs/${PLATFORM}_defconfig.
- Use "make help" to get a list of all available
- platforms of your architecture.
- "make allyesconfig"
- Create a ./.config file by setting symbol
- values to 'y' as much as possible.
- "make allmodconfig"
- Create a ./.config file by setting symbol
- values to 'm' as much as possible.
- "make allnoconfig" Create a ./.config file by setting symbol
- values to 'n' as much as possible.
- "make randconfig" Create a ./.config file by setting symbol
- values to random values.
+ - Alternative configuration commands are:
+
+ "make config" Plain text interface.
+
+ "make menuconfig" Text based color menus, radiolists & dialogs.
+
+ "make nconfig" Enhanced text based color menus.
+
+ "make xconfig" X windows (Qt) based configuration tool.
+
+ "make gconfig" X windows (Gtk) based configuration tool.
+
+ "make oldconfig" Default all questions based on the contents of
+ your existing ./.config file and asking about
+ new config symbols.
+
+ "make silentoldconfig"
+ Like above, but avoids cluttering the screen
+ with questions already answered.
+ Additionally updates the dependencies.
+
+ "make defconfig" Create a ./.config file by using the default
+ symbol values from either arch/$ARCH/defconfig
+ or arch/$ARCH/configs/${PLATFORM}_defconfig,
+ depending on the architecture.
+
+ "make ${PLATFORM}_defconfig"
+ Create a ./.config file by using the default
+ symbol values from
+ arch/$ARCH/configs/${PLATFORM}_defconfig.
+ Use "make help" to get a list of all available
+ platforms of your architecture.
+
+ "make allyesconfig"
+ Create a ./.config file by setting symbol
+ values to 'y' as much as possible.
+
+ "make allmodconfig"
+ Create a ./.config file by setting symbol
+ values to 'm' as much as possible.
+
+ "make allnoconfig" Create a ./.config file by setting symbol
+ values to 'n' as much as possible.
+
+ "make randconfig" Create a ./.config file by setting symbol
+ values to random values.
You can find more information on using the Linux kernel config tools
in Documentation/kbuild/kconfig.txt.
- NOTES on "make config":
- - having unnecessary drivers will make the kernel bigger, and can
- under some circumstances lead to problems: probing for a
- nonexistent controller card may confuse your other controllers
- - compiling the kernel with "Processor type" set higher than 386
- will result in a kernel that does NOT work on a 386. The
- kernel will detect this on bootup, and give up.
- - A kernel with math-emulation compiled in will still use the
- coprocessor if one is present: the math emulation will just
- never get used in that case. The kernel will be slightly larger,
- but will work on different machines regardless of whether they
- have a math coprocessor or not.
- - the "kernel hacking" configuration details usually result in a
- bigger or slower kernel (or both), and can even make the kernel
- less stable by configuring some routines to actively try to
- break bad code to find kernel problems (kmalloc()). Thus you
- should probably answer 'n' to the questions for
- "development", "experimental", or "debugging" features.
+ - NOTES on "make config":
+
+ - Having unnecessary drivers will make the kernel bigger, and can
+ under some circumstances lead to problems: probing for a
+ nonexistent controller card may confuse your other controllers
+
+ - Compiling the kernel with "Processor type" set higher than 386
+ will result in a kernel that does NOT work on a 386. The
+ kernel will detect this on bootup, and give up.
+
+ - A kernel with math-emulation compiled in will still use the
+ coprocessor if one is present: the math emulation will just
+ never get used in that case. The kernel will be slightly larger,
+ but will work on different machines regardless of whether they
+ have a math coprocessor or not.
+
+ - The "kernel hacking" configuration details usually result in a
+ bigger or slower kernel (or both), and can even make the kernel
+ less stable by configuring some routines to actively try to
+ break bad code to find kernel problems (kmalloc()). Thus you
+ should probably answer 'n' to the questions for "development",
+ "experimental", or "debugging" features.
COMPILING the kernel:
@@ -230,7 +243,7 @@ COMPILING the kernel:
possible to do "make install" if you have lilo installed to suit the
kernel makefiles, but you may want to check your particular lilo setup first.
- To do the actual install you have to be root, but none of the normal
+ To do the actual install, you have to be root, but none of the normal
build should require that. Don't take the name of root in vain.
- If you configured any of the parts of the kernel as `modules', you
@@ -238,13 +251,13 @@ COMPILING the kernel:
- Verbose kernel compile/build output:
- Normally the kernel build system runs in a fairly quiet mode (but not
+ Normally, the kernel build system runs in a fairly quiet mode (but not
totally silent). However, sometimes you or other kernel developers need
to see compile, link, or other commands exactly as they are executed.
For this, use "verbose" build mode. This is done by inserting
"V=1" in the "make" command. E.g.:
- make V=1 all
+ make V=1 all
To have the build system also tell the reason for the rebuild of each
target, use "V=2". The default is "V=0".
@@ -256,6 +269,7 @@ COMPILING the kernel:
are installing a new kernel with the same version number as your
working kernel, make a backup of your modules directory before you
do a "make modules_install".
+
Alternatively, before compiling, use the kernel config option
"LOCALVERSION" to append a unique suffix to the regular kernel version.
LOCALVERSION can be set in the "General Setup" menu.
@@ -267,7 +281,7 @@ COMPILING the kernel:
- Booting a kernel directly from a floppy without the assistance of a
bootloader such as LILO, is no longer supported.
- If you boot Linux from the hard drive, chances are you use LILO which
+ If you boot Linux from the hard drive, chances are you use LILO, which
uses the kernel image as specified in the file /etc/lilo.conf. The
kernel image file is usually /vmlinuz, /boot/vmlinuz, /bzImage or
/boot/bzImage. To use the new kernel, save a copy of the old image
@@ -306,21 +320,21 @@ IF SOMETHING GOES WRONG:
- If the bug results in a message like
- unable to handle kernel paging request at address C0000010
- Oops: 0002
- EIP: 0010:XXXXXXXX
- eax: xxxxxxxx ebx: xxxxxxxx ecx: xxxxxxxx edx: xxxxxxxx
- esi: xxxxxxxx edi: xxxxxxxx ebp: xxxxxxxx
- ds: xxxx es: xxxx fs: xxxx gs: xxxx
- Pid: xx, process nr: xx
- xx xx xx xx xx xx xx xx xx xx
+ unable to handle kernel paging request at address C0000010
+ Oops: 0002
+ EIP: 0010:XXXXXXXX
+ eax: xxxxxxxx ebx: xxxxxxxx ecx: xxxxxxxx edx: xxxxxxxx
+ esi: xxxxxxxx edi: xxxxxxxx ebp: xxxxxxxx
+ ds: xxxx es: xxxx fs: xxxx gs: xxxx
+ Pid: xx, process nr: xx
+ xx xx xx xx xx xx xx xx xx xx
or similar kernel debugging information on your screen or in your
system log, please duplicate it *exactly*. The dump may look
incomprehensible to you, but it does contain information that may
help debugging the problem. The text above the dump is also
important: it tells something about why the kernel dumped code (in
- the above example it's due to a bad kernel pointer). More information
+ the above example, it's due to a bad kernel pointer). More information
on making sense of the dump is in Documentation/oops-tracing.txt
- If you compiled the kernel with CONFIG_KALLSYMS you can send the dump
@@ -328,7 +342,7 @@ IF SOMETHING GOES WRONG:
sense of the dump (but compiling with CONFIG_KALLSYMS is usually preferred).
This utility can be downloaded from
ftp://ftp.<country>.kernel.org/pub/linux/utils/kernel/ksymoops/ .
- Alternately you can do the dump lookup by hand:
+ Alternatively, you can do the dump lookup by hand:
- In debugging dumps like the above, it helps enormously if you can
look up what the EIP value means. The hex value as such doesn't help
@@ -342,7 +356,7 @@ IF SOMETHING GOES WRONG:
the file 'linux/vmlinux'. To extract the namelist and match it against
the EIP from the kernel crash, do:
- nm vmlinux | sort | less
+ nm vmlinux | sort | less
This will give you a list of kernel addresses sorted in ascending
order, from which it is simple to find the function that contains the
@@ -361,7 +375,7 @@ IF SOMETHING GOES WRONG:
kernel image or similar), telling me as much about your setup as
possible will help. Please read the REPORTING-BUGS document for details.
- - Alternately, you can use gdb on a running kernel. (read-only; i.e. you
+ - Alternatively, you can use gdb on a running kernel. (read-only; i.e. you
cannot change values or set break points.) To do this, first compile the
kernel with -g; edit arch/i386/Makefile appropriately, then do a "make
clean". You'll also need to enable CONFIG_PROC_FS (via "make config").
diff --git a/arch/Kconfig b/arch/Kconfig
index 1f9461b9cc89..e9a910876cda 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -76,6 +76,23 @@ config OPTPROBES
depends on KPROBES && HAVE_OPTPROBES
depends on !PREEMPT
+config UPROBES
+ bool "Transparent user-space probes (EXPERIMENTAL)"
+ depends on UPROBE_EVENT && PERF_EVENTS
+ default n
+ help
+ Uprobes is the user-space counterpart to kprobes: they
+ enable instrumentation applications (such as 'perf probe')
+ to establish unintrusive probes in user-space binaries and
+ libraries, by executing handler functions when the probes
+ are hit by user-space applications.
+
+ ( These probes come in the form of single-byte breakpoints,
+ managed by the kernel and kept transparent to the probed
+ application. )
+
+ If in doubt, say "N".
+
config HAVE_EFFICIENT_UNALIGNED_ACCESS
bool
help
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 0893f023efb8..3de74c9f9610 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -16,6 +16,7 @@ config ALPHA
select ARCH_WANT_OPTIONAL_GPIOLIB
select ARCH_HAVE_NMI_SAFE_CMPXCHG
select GENERIC_SMP_IDLE_THREAD
+ select GENERIC_CMOS_UPDATE
help
The Alpha is a 64-bit general-purpose processor designed and
marketed by the Digital Equipment Corporation of blessed memory,
@@ -48,9 +49,6 @@ config GENERIC_CALIBRATE_DELAY
bool
default y
-config GENERIC_CMOS_UPDATE
- def_bool y
-
config GENERIC_GPIO
bool
diff --git a/arch/alpha/include/asm/gpio.h b/arch/alpha/include/asm/gpio.h
index 7dc6a6343c06..b3799d88ffcf 100644
--- a/arch/alpha/include/asm/gpio.h
+++ b/arch/alpha/include/asm/gpio.h
@@ -1,55 +1,4 @@
-/*
- * Generic GPIO API implementation for Alpha.
- *
- * A stright copy of that for PowerPC which was:
- *
- * Copyright (c) 2007-2008 MontaVista Software, Inc.
- *
- * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef _ASM_ALPHA_GPIO_H
-#define _ASM_ALPHA_GPIO_H
-
-#include <linux/errno.h>
-#include <asm-generic/gpio.h>
-
-#ifdef CONFIG_GPIOLIB
-
-/*
- * We don't (yet) implement inlined/rapid versions for on-chip gpios.
- * Just call gpiolib.
- */
-static inline int gpio_get_value(unsigned int gpio)
-{
- return __gpio_get_value(gpio);
-}
-
-static inline void gpio_set_value(unsigned int gpio, int value)
-{
- __gpio_set_value(gpio, value);
-}
-
-static inline int gpio_cansleep(unsigned int gpio)
-{
- return __gpio_cansleep(gpio);
-}
-
-static inline int gpio_to_irq(unsigned int gpio)
-{
- return __gpio_to_irq(gpio);
-}
-
-static inline int irq_to_gpio(unsigned int irq)
-{
- return -EINVAL;
-}
-
-#endif /* CONFIG_GPIOLIB */
-
-#endif /* _ASM_ALPHA_GPIO_H */
+#ifndef __LINUX_GPIO_H
+#warning Include linux/gpio.h instead of asm/gpio.h
+#include <linux/gpio.h>
+#endif
diff --git a/arch/alpha/include/asm/io.h b/arch/alpha/include/asm/io.h
index 7a3d38d5ed6b..5ebab5895edb 100644
--- a/arch/alpha/include/asm/io.h
+++ b/arch/alpha/include/asm/io.h
@@ -489,6 +489,11 @@ extern inline void writeq(u64 b, volatile void __iomem *addr)
}
#endif
+#define ioread16be(p) be16_to_cpu(ioread16(p))
+#define ioread32be(p) be32_to_cpu(ioread32(p))
+#define iowrite16be(v,p) iowrite16(cpu_to_be16(v), (p))
+#define iowrite32be(v,p) iowrite32(cpu_to_be32(v), (p))
+
#define inb_p inb
#define inw_p inw
#define inl_p inl
diff --git a/arch/alpha/include/asm/processor.h b/arch/alpha/include/asm/processor.h
index 94afe5859301..e37b887b3d9f 100644
--- a/arch/alpha/include/asm/processor.h
+++ b/arch/alpha/include/asm/processor.h
@@ -49,9 +49,6 @@ extern void start_thread(struct pt_regs *, unsigned long, unsigned long);
/* Free all resources held by a thread. */
extern void release_thread(struct task_struct *);
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk) do { } while (0)
-
/* Create a kernel thread without removing it from tasklists. */
extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
diff --git a/arch/alpha/include/asm/sysinfo.h b/arch/alpha/include/asm/sysinfo.h
index e77d77cd07b8..0b80e79d75e5 100644
--- a/arch/alpha/include/asm/sysinfo.h
+++ b/arch/alpha/include/asm/sysinfo.h
@@ -15,6 +15,7 @@
#define GSI_GET_HWRPB 101
#define SSI_NVPAIRS 1
+#define SSI_LMF 7
#define SSI_IEEE_FP_CONTROL 14
#define SSI_IEEE_STATE_AT_SIGNAL 15
#define SSI_IEEE_IGNORE_STATE_AT_SIGNAL 16
diff --git a/arch/alpha/include/asm/unistd.h b/arch/alpha/include/asm/unistd.h
index 2207fc61665d..d1f23b722df4 100644
--- a/arch/alpha/include/asm/unistd.h
+++ b/arch/alpha/include/asm/unistd.h
@@ -203,6 +203,12 @@
#define __NR_osf_security 222 /* not implemented */
#define __NR_osf_kloadcall 223 /* not implemented */
+#define __NR_osf_stat 224
+#define __NR_osf_lstat 225
+#define __NR_osf_fstat 226
+#define __NR_osf_statfs64 227
+#define __NR_osf_fstatfs64 228
+
#define __NR_getpgid 233
#define __NR_getsid 234
#define __NR_sigaltstack 235
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 49ee3193477a..98a103621af6 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -191,6 +191,39 @@ SYSCALL_DEFINE6(osf_mmap, unsigned long, addr, unsigned long, len,
return ret;
}
+struct osf_stat {
+ int st_dev;
+ int st_pad1;
+ unsigned st_mode;
+ unsigned short st_nlink;
+ short st_nlink_reserved;
+ unsigned st_uid;
+ unsigned st_gid;
+ int st_rdev;
+ int st_ldev;
+ long st_size;
+ int st_pad2;
+ int st_uatime;
+ int st_pad3;
+ int st_umtime;
+ int st_pad4;
+ int st_uctime;
+ int st_pad5;
+ int st_pad6;
+ unsigned st_flags;
+ unsigned st_gen;
+ long st_spare[4];
+ unsigned st_ino;
+ int st_ino_reserved;
+ int st_atime;
+ int st_atime_reserved;
+ int st_mtime;
+ int st_mtime_reserved;
+ int st_ctime;
+ int st_ctime_reserved;
+ long st_blksize;
+ long st_blocks;
+};
/*
* The OSF/1 statfs structure is much larger, but this should
@@ -209,6 +242,60 @@ struct osf_statfs {
__kernel_fsid_t f_fsid;
};
+struct osf_statfs64 {
+ short f_type;
+ short f_flags;
+ int f_pad1;
+ int f_pad2;
+ int f_pad3;
+ int f_pad4;
+ int f_pad5;
+ int f_pad6;
+ int f_pad7;
+ __kernel_fsid_t f_fsid;
+ u_short f_namemax;
+ short f_reserved1;
+ int f_spare[8];
+ char f_pad8[90];
+ char f_pad9[90];
+ long mount_info[10];
+ u_long f_flags2;
+ long f_spare2[14];
+ long f_fsize;
+ long f_bsize;
+ long f_blocks;
+ long f_bfree;
+ long f_bavail;
+ long f_files;
+ long f_ffree;
+};
+
+static int
+linux_to_osf_stat(struct kstat *lstat, struct osf_stat __user *osf_stat)
+{
+ struct osf_stat tmp = { 0 };
+
+ tmp.st_dev = lstat->dev;
+ tmp.st_mode = lstat->mode;
+ tmp.st_nlink = lstat->nlink;
+ tmp.st_uid = lstat->uid;
+ tmp.st_gid = lstat->gid;
+ tmp.st_rdev = lstat->rdev;
+ tmp.st_ldev = lstat->rdev;
+ tmp.st_size = lstat->size;
+ tmp.st_uatime = lstat->atime.tv_nsec / 1000;
+ tmp.st_umtime = lstat->mtime.tv_nsec / 1000;
+ tmp.st_uctime = lstat->ctime.tv_nsec / 1000;
+ tmp.st_ino = lstat->ino;
+ tmp.st_atime = lstat->atime.tv_sec;
+ tmp.st_mtime = lstat->mtime.tv_sec;
+ tmp.st_ctime = lstat->ctime.tv_sec;
+ tmp.st_blksize = lstat->blksize;
+ tmp.st_blocks = lstat->blocks;
+
+ return copy_to_user(osf_stat, &tmp, sizeof(tmp)) ? -EFAULT : 0;
+}
+
static int
linux_to_osf_statfs(struct kstatfs *linux_stat, struct osf_statfs __user *osf_stat,
unsigned long bufsiz)
@@ -230,6 +317,26 @@ linux_to_osf_statfs(struct kstatfs *linux_stat, struct osf_statfs __user *osf_st
return copy_to_user(osf_stat, &tmp_stat, bufsiz) ? -EFAULT : 0;
}
+static int
+linux_to_osf_statfs64(struct kstatfs *linux_stat, struct osf_statfs64 __user *osf_stat,
+ unsigned long bufsiz)
+{
+ struct osf_statfs64 tmp_stat = { 0 };
+
+ tmp_stat.f_type = linux_stat->f_type;
+ tmp_stat.f_fsize = linux_stat->f_frsize;
+ tmp_stat.f_bsize = linux_stat->f_bsize;
+ tmp_stat.f_blocks = linux_stat->f_blocks;
+ tmp_stat.f_bfree = linux_stat->f_bfree;
+ tmp_stat.f_bavail = linux_stat->f_bavail;
+ tmp_stat.f_files = linux_stat->f_files;
+ tmp_stat.f_ffree = linux_stat->f_ffree;
+ tmp_stat.f_fsid = linux_stat->f_fsid;
+ if (bufsiz > sizeof(tmp_stat))
+ bufsiz = sizeof(tmp_stat);
+ return copy_to_user(osf_stat, &tmp_stat, bufsiz) ? -EFAULT : 0;
+}
+
SYSCALL_DEFINE3(osf_statfs, const char __user *, pathname,
struct osf_statfs __user *, buffer, unsigned long, bufsiz)
{
@@ -240,6 +347,42 @@ SYSCALL_DEFINE3(osf_statfs, const char __user *, pathname,
return error;
}
+SYSCALL_DEFINE2(osf_stat, char __user *, name, struct osf_stat __user *, buf)
+{
+ struct kstat stat;
+ int error;
+
+ error = vfs_stat(name, &stat);
+ if (error)
+ return error;
+
+ return linux_to_osf_stat(&stat, buf);
+}
+
+SYSCALL_DEFINE2(osf_lstat, char __user *, name, struct osf_stat __user *, buf)
+{
+ struct kstat stat;
+ int error;
+
+ error = vfs_lstat(name, &stat);
+ if (error)
+ return error;
+
+ return linux_to_osf_stat(&stat, buf);
+}
+
+SYSCALL_DEFINE2(osf_fstat, int, fd, struct osf_stat __user *, buf)
+{
+ struct kstat stat;
+ int error;
+
+ error = vfs_fstat(fd, &stat);
+ if (error)
+ return error;
+
+ return linux_to_osf_stat(&stat, buf);
+}
+
SYSCALL_DEFINE3(osf_fstatfs, unsigned long, fd,
struct osf_statfs __user *, buffer, unsigned long, bufsiz)
{
@@ -250,6 +393,26 @@ SYSCALL_DEFINE3(osf_fstatfs, unsigned long, fd,
return error;
}
+SYSCALL_DEFINE3(osf_statfs64, char __user *, pathname,
+ struct osf_statfs64 __user *, buffer, unsigned long, bufsiz)
+{
+ struct kstatfs linux_stat;
+ int error = user_statfs(pathname, &linux_stat);
+ if (!error)
+ error = linux_to_osf_statfs64(&linux_stat, buffer, bufsiz);
+ return error;
+}
+
+SYSCALL_DEFINE3(osf_fstatfs64, unsigned long, fd,
+ struct osf_statfs64 __user *, buffer, unsigned long, bufsiz)
+{
+ struct kstatfs linux_stat;
+ int error = fd_statfs(fd, &linux_stat);
+ if (!error)
+ error = linux_to_osf_statfs64(&linux_stat, buffer, bufsiz);
+ return error;
+}
+
/*
* Uhh.. OSF/1 mount parameters aren't exactly obvious..
*
@@ -771,6 +934,9 @@ SYSCALL_DEFINE5(osf_setsysinfo, unsigned long, op, void __user *, buffer,
return 0;
}
+ case SSI_LMF:
+ return 0;
+
default:
break;
}
diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c
index cd634795aa9c..3f844d26d2c7 100644
--- a/arch/alpha/kernel/pci_iommu.c
+++ b/arch/alpha/kernel/pci_iommu.c
@@ -236,7 +236,7 @@ static int pci_dac_dma_supported(struct pci_dev *dev, u64 mask)
ok = 0;
/* If both conditions above are met, we are fine. */
- DBGA("pci_dac_dma_supported %s from %p\n",
+ DBGA("pci_dac_dma_supported %s from %pf\n",
ok ? "yes" : "no", __builtin_return_address(0));
return ok;
@@ -268,7 +268,7 @@ pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size,
&& paddr + size <= __direct_map_size) {
ret = paddr + __direct_map_base;
- DBGA2("pci_map_single: [%p,%zx] -> direct %llx from %p\n",
+ DBGA2("pci_map_single: [%p,%zx] -> direct %llx from %pf\n",
cpu_addr, size, ret, __builtin_return_address(0));
return ret;
@@ -279,7 +279,7 @@ pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size,
if (dac_allowed) {
ret = paddr + alpha_mv.pci_dac_offset;
- DBGA2("pci_map_single: [%p,%zx] -> DAC %llx from %p\n",
+ DBGA2("pci_map_single: [%p,%zx] -> DAC %llx from %pf\n",
cpu_addr, size, ret, __builtin_return_address(0));
return ret;
@@ -316,7 +316,7 @@ pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size,
ret = arena->dma_base + dma_ofs * PAGE_SIZE;
ret += (unsigned long)cpu_addr & ~PAGE_MASK;
- DBGA2("pci_map_single: [%p,%zx] np %ld -> sg %llx from %p\n",
+ DBGA2("pci_map_single: [%p,%zx] np %ld -> sg %llx from %pf\n",
cpu_addr, size, npages, ret, __builtin_return_address(0));
return ret;
@@ -385,14 +385,14 @@ static void alpha_pci_unmap_page(struct device *dev, dma_addr_t dma_addr,
&& dma_addr < __direct_map_base + __direct_map_size) {
/* Nothing to do. */
- DBGA2("pci_unmap_single: direct [%llx,%zx] from %p\n",
+ DBGA2("pci_unmap_single: direct [%llx,%zx] from %pf\n",
dma_addr, size, __builtin_return_address(0));
return;
}
if (dma_addr > 0xffffffff) {
- DBGA2("pci64_unmap_single: DAC [%llx,%zx] from %p\n",
+ DBGA2("pci64_unmap_single: DAC [%llx,%zx] from %pf\n",
dma_addr, size, __builtin_return_address(0));
return;
}
@@ -424,7 +424,7 @@ static void alpha_pci_unmap_page(struct device *dev, dma_addr_t dma_addr,
spin_unlock_irqrestore(&arena->lock, flags);
- DBGA2("pci_unmap_single: sg [%llx,%zx] np %ld from %p\n",
+ DBGA2("pci_unmap_single: sg [%llx,%zx] np %ld from %pf\n",
dma_addr, size, npages, __builtin_return_address(0));
}
@@ -447,7 +447,7 @@ try_again:
cpu_addr = (void *)__get_free_pages(gfp, order);
if (! cpu_addr) {
printk(KERN_INFO "pci_alloc_consistent: "
- "get_free_pages failed from %p\n",
+ "get_free_pages failed from %pf\n",
__builtin_return_address(0));
/* ??? Really atomic allocation? Otherwise we could play
with vmalloc and sg if we can't find contiguous memory. */
@@ -466,7 +466,7 @@ try_again:
goto try_again;
}
- DBGA2("pci_alloc_consistent: %zx -> [%p,%llx] from %p\n",
+ DBGA2("pci_alloc_consistent: %zx -> [%p,%llx] from %pf\n",
size, cpu_addr, *dma_addrp, __builtin_return_address(0));
return cpu_addr;
@@ -486,7 +486,7 @@ static void alpha_pci_free_coherent(struct device *dev, size_t size,
pci_unmap_single(pdev, dma_addr, size, PCI_DMA_BIDIRECTIONAL);
free_pages((unsigned long)cpu_addr, get_order(size));
- DBGA2("pci_free_consistent: [%llx,%zx] from %p\n",
+ DBGA2("pci_free_consistent: [%llx,%zx] from %pf\n",
dma_addr, size, __builtin_return_address(0));
}
diff --git a/arch/alpha/kernel/perf_event.c b/arch/alpha/kernel/perf_event.c
index 0dae252f7a33..d821b17047e0 100644
--- a/arch/alpha/kernel/perf_event.c
+++ b/arch/alpha/kernel/perf_event.c
@@ -824,7 +824,6 @@ static void alpha_perf_event_irq_handler(unsigned long la_ptr,
idx = la_ptr;
- perf_sample_data_init(&data, 0);
for (j = 0; j < cpuc->n_events; j++) {
if (cpuc->current_idx[j] == idx)
break;
@@ -848,7 +847,7 @@ static void alpha_perf_event_irq_handler(unsigned long la_ptr,
hwc = &event->hw;
alpha_perf_event_update(event, hwc, idx, alpha_pmu->pmc_max_period[idx]+1);
- data.period = event->hw.last_period;
+ perf_sample_data_init(&data, 0, hwc->last_period);
if (alpha_perf_event_set_period(event, hwc, idx)) {
if (perf_event_overflow(event, &data, regs)) {
diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
index 35f2ef44de12..10ab2d74ecbb 100644
--- a/arch/alpha/kernel/signal.c
+++ b/arch/alpha/kernel/signal.c
@@ -34,9 +34,6 @@
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
asmlinkage void ret_from_sys_call(void);
-static void do_signal(struct pt_regs *, struct switch_stack *,
- unsigned long, unsigned long);
-
/*
* The OSF/1 sigprocmask calling sequence is different from the
@@ -121,17 +118,8 @@ SYSCALL_DEFINE5(rt_sigaction, int, sig, const struct sigaction __user *, act,
SYSCALL_DEFINE1(sigsuspend, old_sigset_t, mask)
{
sigset_t blocked;
-
- current->saved_sigmask = current->blocked;
-
- mask &= _BLOCKABLE;
siginitset(&blocked, mask);
- set_current_blocked(&blocked);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
+ return sigsuspend(&blocked);
}
asmlinkage int
@@ -376,11 +364,11 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
oldsp = rdusp();
frame = get_sigframe(ka, oldsp, sizeof(*frame));
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- goto give_sigsegv;
+ return -EFAULT;
err |= setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp);
if (err)
- goto give_sigsegv;
+ return -EFAULT;
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
@@ -396,7 +384,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
/* Check that everything was written properly. */
if (err)
- goto give_sigsegv;
+ return err;
/* "Return" to the handler */
regs->r26 = r26;
@@ -410,12 +398,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
current->comm, current->pid, frame, regs->pc, regs->r26);
#endif
-
return 0;
-
-give_sigsegv:
- force_sigsegv(sig, current);
- return -EFAULT;
}
static int
@@ -428,7 +411,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
oldsp = rdusp();
frame = get_sigframe(ka, oldsp, sizeof(*frame));
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- goto give_sigsegv;
+ return -EFAULT;
err |= copy_siginfo_to_user(&frame->info, info);
@@ -443,7 +426,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
set->sig[0], oldsp);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
- goto give_sigsegv;
+ return -EFAULT;
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
@@ -459,7 +442,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
}
if (err)
- goto give_sigsegv;
+ return -EFAULT;
/* "Return" to the handler */
regs->r26 = r26;
@@ -475,31 +458,37 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
#endif
return 0;
-
-give_sigsegv:
- force_sigsegv(sig, current);
- return -EFAULT;
}
/*
* OK, we're invoking a handler.
*/
-static inline int
+static inline void
handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
- sigset_t *oldset, struct pt_regs * regs, struct switch_stack *sw)
+ struct pt_regs * regs, struct switch_stack *sw)
{
+ sigset_t *oldset = &current->blocked;
int ret;
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = &current->saved_sigmask;
+
if (ka->sa.sa_flags & SA_SIGINFO)
ret = setup_rt_frame(sig, ka, info, oldset, regs, sw);
else
ret = setup_frame(sig, ka, oldset, regs, sw);
- if (ret == 0)
- block_sigmask(ka, sig);
-
- return ret;
+ if (ret) {
+ force_sigsegv(sig, current);
+ return;
+ }
+ block_sigmask(ka, sig);
+ /* A signal was successfully delivered, and the
+ saved sigmask was stored on the signal frame,
+ and will be restored by sigreturn. So we can
+ simply clear the restore sigmask flag. */
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
}
static inline void
@@ -547,12 +536,6 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw,
int signr;
unsigned long single_stepping = ptrace_cancel_bpt(current);
struct k_sigaction ka;
- sigset_t *oldset;
-
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
- oldset = &current->saved_sigmask;
- else
- oldset = &current->blocked;
/* This lets the debugger run, ... */
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
@@ -564,14 +547,7 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw,
/* Whee! Actually deliver the signal. */
if (r0)
syscall_restart(r0, r19, regs, &ka);
- if (handle_signal(signr, &ka, &info, oldset, regs, sw) == 0) {
- /* A signal was successfully delivered, and the
- saved sigmask was stored on the signal frame,
- and will be restored by sigreturn. So we can
- simply clear the restore sigmask flag. */
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
- clear_thread_flag(TIF_RESTORE_SIGMASK);
- }
+ handle_signal(signr, &ka, &info, regs, sw);
if (single_stepping)
ptrace_set_bpt(current); /* re-set bpt */
return;
@@ -596,10 +572,8 @@ do_signal(struct pt_regs * regs, struct switch_stack * sw,
}
/* If there's no signal to deliver, we just restore the saved mask. */
- if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
- clear_thread_flag(TIF_RESTORE_SIGMASK);
- sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
- }
+ if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK))
+ set_current_blocked(&current->saved_sigmask);
if (single_stepping)
ptrace_set_bpt(current); /* re-set breakpoint */
@@ -610,7 +584,7 @@ do_notify_resume(struct pt_regs *regs, struct switch_stack *sw,
unsigned long thread_info_flags,
unsigned long r0, unsigned long r19)
{
- if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+ if (thread_info_flags & _TIF_SIGPENDING)
do_signal(regs, sw, r0, r19);
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S
index e534e1c5bc11..87835235f114 100644
--- a/arch/alpha/kernel/systbls.S
+++ b/arch/alpha/kernel/systbls.S
@@ -241,11 +241,11 @@ sys_call_table:
.quad alpha_ni_syscall
.quad alpha_ni_syscall
.quad alpha_ni_syscall
- .quad alpha_ni_syscall
- .quad alpha_ni_syscall /* 225 */
- .quad alpha_ni_syscall
- .quad alpha_ni_syscall
- .quad alpha_ni_syscall
+ .quad sys_osf_stat
+ .quad sys_osf_lstat /* 225 */
+ .quad sys_osf_fstat
+ .quad sys_osf_statfs64
+ .quad sys_osf_fstatfs64
.quad alpha_ni_syscall
.quad alpha_ni_syscall /* 230 */
.quad alpha_ni_syscall
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 002b1c8da225..5458aa9db067 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1,6 +1,7 @@
config ARM
bool
default y
+ select ARCH_HAVE_CUSTOM_GPIO_H
select HAVE_AOUT
select HAVE_DMA_API_DEBUG
select HAVE_IDE if PCI || ISA || PCMCIA
@@ -40,6 +41,8 @@ config ARM
select GENERIC_PCI_IOMAP
select HAVE_BPF_JIT
select GENERIC_SMP_IDLE_THREAD
+ select KTIME_SCALAR
+ select GENERIC_CLOCKEVENTS_BROADCAST if SMP
help
The ARM series is a line of low-power-consumption RISC chip designs
licensed by ARM Ltd and targeted at embedded applications and
@@ -63,22 +66,6 @@ config SYS_SUPPORTS_APM_EMULATION
config GENERIC_GPIO
bool
-config ARCH_USES_GETTIMEOFFSET
- bool
- default n
-
-config GENERIC_CLOCKEVENTS
- bool
-
-config GENERIC_CLOCKEVENTS_BROADCAST
- bool
- depends on GENERIC_CLOCKEVENTS
- default y if SMP
-
-config KTIME_SCALAR
- bool
- default y
-
config HAVE_TCM
bool
select GENERIC_ALLOCATOR
@@ -107,14 +94,6 @@ config EISA
config SBUS
bool
-config MCA
- bool
- help
- MicroChannel Architecture is found in some IBM PS/2 machines and
- laptops. It is a bus system similar to PCI or ISA. See
- <file:Documentation/mca.txt> (and especially the web page given
- there) before attempting to build an MCA bus kernel.
-
config STACKTRACE_SUPPORT
bool
default y
@@ -336,8 +315,8 @@ config ARCH_AT91
select IRQ_DOMAIN
select NEED_MACH_IO_H if PCCARD
help
- This enables support for systems based on the Atmel AT91RM9200,
- AT91SAM9 processors.
+ This enables support for systems based on Atmel
+ AT91RM9200 and AT91SAM9* processors.
config ARCH_BCMRING
bool "Broadcom BCMRING"
@@ -369,12 +348,12 @@ config ARCH_HIGHBANK
Support for the Calxeda Highbank SoC based boards.
config ARCH_CLPS711X
- bool "Cirrus Logic CLPS711x/EP721x-based"
+ bool "Cirrus Logic CLPS711x/EP721x/EP731x-based"
select CPU_ARM720T
select ARCH_USES_GETTIMEOFFSET
select NEED_MACH_MEMORY_H
help
- Support for Cirrus Logic 711x/721x based boards.
+ Support for Cirrus Logic 711x/721x/731x based boards.
config ARCH_CNS3XXX
bool "Cavium Networks CNS3XXX family"
@@ -403,6 +382,8 @@ config ARCH_PRIMA2
select CLKDEV_LOOKUP
select GENERIC_IRQ_CHIP
select MIGHT_HAVE_CACHE_L2X0
+ select PINCTRL
+ select PINCTRL_SIRF
select USE_OF
select ZONE_DMA
help
@@ -465,6 +446,7 @@ config ARCH_MXS
select CLKDEV_LOOKUP
select CLKSRC_MMIO
select HAVE_CLK_PREPARE
+ select PINCTRL
help
Support for Freescale MXS-based family of processors
@@ -524,28 +506,6 @@ config ARCH_IOP33X
help
Support for Intel's IOP33X (XScale) family of processors.
-config ARCH_IXP23XX
- bool "IXP23XX-based"
- depends on MMU
- select CPU_XSC3
- select PCI
- select ARCH_USES_GETTIMEOFFSET
- select NEED_MACH_IO_H
- select NEED_MACH_MEMORY_H
- help
- Support for Intel's IXP23xx (XScale) family of processors.
-
-config ARCH_IXP2000
- bool "IXP2400/2800-based"
- depends on MMU
- select CPU_XSCALE
- select PCI
- select ARCH_USES_GETTIMEOFFSET
- select NEED_MACH_IO_H
- select NEED_MACH_MEMORY_H
- help
- Support for Intel's IXP2400/2800 (XScale) family of processors.
-
config ARCH_IXP4XX
bool "IXP4xx-based"
depends on MMU
@@ -593,6 +553,7 @@ config ARCH_LPC32XX
select USB_ARCH_HAS_OHCI
select CLKDEV_LOOKUP
select GENERIC_CLOCKEVENTS
+ select USE_OF
help
Support for the NXP LPC32XX family of processors
@@ -628,6 +589,7 @@ config ARCH_MMP
select CLKDEV_LOOKUP
select GENERIC_CLOCKEVENTS
select GPIO_PXA
+ select IRQ_DOMAIN
select PLAT_PXA
select SPARSE_IRQ
select GENERIC_ALLOCATOR
@@ -939,6 +901,7 @@ config ARCH_NOMADIK
select CPU_ARM926T
select CLKDEV_LOOKUP
select GENERIC_CLOCKEVENTS
+ select PINCTRL
select MIGHT_HAVE_CACHE_L2X0
select ARCH_REQUIRE_GPIOLIB
help
@@ -1039,10 +1002,6 @@ source "arch/arm/mach-iop13xx/Kconfig"
source "arch/arm/mach-ixp4xx/Kconfig"
-source "arch/arm/mach-ixp2000/Kconfig"
-
-source "arch/arm/mach-ixp23xx/Kconfig"
-
source "arch/arm/mach-kirkwood/Kconfig"
source "arch/arm/mach-ks8695/Kconfig"
@@ -1466,8 +1425,6 @@ endmenu
menu "Kernel Features"
-source "kernel/time/Kconfig"
-
config HAVE_SMP
bool
help
@@ -1934,10 +1891,10 @@ choice
default ZBOOT_ROM_NONE
help
Include experimental SD/MMC loading code in the ROM-able zImage.
- With this enabled it is possible to write the the ROM-able zImage
+ With this enabled it is possible to write the ROM-able zImage
kernel image to an MMC or SD card and boot the kernel straight
from the reset vector. At reset the processor Mask ROM will load
- the first part of the the ROM-able zImage which in turn loads the
+ the first part of the ROM-able zImage which in turn loads the
rest the kernel image to RAM.
config ZBOOT_ROM_NONE
@@ -2279,9 +2236,9 @@ menu "Power management options"
source "kernel/power/Kconfig"
config ARCH_SUSPEND_POSSIBLE
- depends on !ARCH_S5PC100
+ depends on !ARCH_S5PC100 && !ARCH_TEGRA
depends on CPU_ARM920T || CPU_ARM926T || CPU_SA1100 || \
- CPU_V6 || CPU_V6K || CPU_V7 || CPU_XSC3 || CPU_XSCALE
+ CPU_V6 || CPU_V6K || CPU_V7 || CPU_XSC3 || CPU_XSCALE || CPU_MOHAWK
def_bool y
config ARM_CPU_SUSPEND
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 3b18ef7ad278..157900da8782 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -147,8 +147,6 @@ machine-$(CONFIG_ARCH_INTEGRATOR) := integrator
machine-$(CONFIG_ARCH_IOP13XX) := iop13xx
machine-$(CONFIG_ARCH_IOP32X) := iop32x
machine-$(CONFIG_ARCH_IOP33X) := iop33x
-machine-$(CONFIG_ARCH_IXP2000) := ixp2000
-machine-$(CONFIG_ARCH_IXP23XX) := ixp23xx
machine-$(CONFIG_ARCH_IXP4XX) := ixp4xx
machine-$(CONFIG_ARCH_KIRKWOOD) := kirkwood
machine-$(CONFIG_ARCH_KS8695) := ks8695
diff --git a/arch/arm/boot/compressed/head-xscale.S b/arch/arm/boot/compressed/head-xscale.S
index aa5ee49c5c5a..6ab0599c02dd 100644
--- a/arch/arm/boot/compressed/head-xscale.S
+++ b/arch/arm/boot/compressed/head-xscale.S
@@ -32,10 +32,3 @@ __XScale_start:
bic r0, r0, #0x1000 @ clear Icache
mcr p15, 0, r0, c1, c0, 0
-#ifdef CONFIG_ARCH_IXP2000
- mov r1, #-1
- mov r0, #0xd6000000
- str r1, [r0, #0x14]
- str r1, [r0, #0x18]
-#endif
-
diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
new file mode 100644
index 000000000000..f449efc9825f
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9260.dtsi
@@ -0,0 +1,273 @@
+/*
+ * at91sam9260.dtsi - Device Tree Include file for AT91SAM9260 family SoC
+ *
+ * Copyright (C) 2011 Atmel,
+ * 2011 Nicolas Ferre <nicolas.ferre@atmel.com>,
+ * 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ model = "Atmel AT91SAM9260 family SoC";
+ compatible = "atmel,at91sam9260";
+ interrupt-parent = <&aic>;
+
+ aliases {
+ serial0 = &dbgu;
+ serial1 = &usart0;
+ serial2 = &usart1;
+ serial3 = &usart2;
+ serial4 = &usart3;
+ serial5 = &usart4;
+ serial6 = &usart5;
+ gpio0 = &pioA;
+ gpio1 = &pioB;
+ gpio2 = &pioC;
+ tcb0 = &tcb0;
+ tcb1 = &tcb1;
+ };
+ cpus {
+ cpu@0 {
+ compatible = "arm,arm926ejs";
+ };
+ };
+
+ memory {
+ reg = <0x20000000 0x04000000>;
+ };
+
+ ahb {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ apb {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ aic: interrupt-controller@fffff000 {
+ #interrupt-cells = <2>;
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ reg = <0xfffff000 0x200>;
+ };
+
+ ramc0: ramc@ffffea00 {
+ compatible = "atmel,at91sam9260-sdramc";
+ reg = <0xffffea00 0x200>;
+ };
+
+ pmc: pmc@fffffc00 {
+ compatible = "atmel,at91rm9200-pmc";
+ reg = <0xfffffc00 0x100>;
+ };
+
+ rstc@fffffd00 {
+ compatible = "atmel,at91sam9260-rstc";
+ reg = <0xfffffd00 0x10>;
+ };
+
+ shdwc@fffffd10 {
+ compatible = "atmel,at91sam9260-shdwc";
+ reg = <0xfffffd10 0x10>;
+ };
+
+ pit: timer@fffffd30 {
+ compatible = "atmel,at91sam9260-pit";
+ reg = <0xfffffd30 0xf>;
+ interrupts = <1 4>;
+ };
+
+ tcb0: timer@fffa0000 {
+ compatible = "atmel,at91rm9200-tcb";
+ reg = <0xfffa0000 0x100>;
+ interrupts = <17 4 18 4 19 4>;
+ };
+
+ tcb1: timer@fffdc000 {
+ compatible = "atmel,at91rm9200-tcb";
+ reg = <0xfffdc000 0x100>;
+ interrupts = <26 4 27 4 28 4>;
+ };
+
+ pioA: gpio@fffff400 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x100>;
+ interrupts = <2 4>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ };
+
+ pioB: gpio@fffff600 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff600 0x100>;
+ interrupts = <3 4>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ };
+
+ pioC: gpio@fffff800 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff800 0x100>;
+ interrupts = <4 4>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ };
+
+ dbgu: serial@fffff200 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffff200 0x200>;
+ interrupts = <1 4>;
+ status = "disabled";
+ };
+
+ usart0: serial@fffb0000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffb0000 0x200>;
+ interrupts = <6 4>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+ };
+
+ usart1: serial@fffb4000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffb4000 0x200>;
+ interrupts = <7 4>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+ };
+
+ usart2: serial@fffb8000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffb8000 0x200>;
+ interrupts = <8 4>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+ };
+
+ usart3: serial@fffd0000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffd0000 0x200>;
+ interrupts = <23 4>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+ };
+
+ usart4: serial@fffd4000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffd4000 0x200>;
+ interrupts = <24 4>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+ };
+
+ usart5: serial@fffd8000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffd8000 0x200>;
+ interrupts = <25 4>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+ };
+
+ macb0: ethernet@fffc4000 {
+ compatible = "cdns,at32ap7000-macb", "cdns,macb";
+ reg = <0xfffc4000 0x100>;
+ interrupts = <21 4>;
+ status = "disabled";
+ };
+
+ usb1: gadget@fffa4000 {
+ compatible = "atmel,at91rm9200-udc";
+ reg = <0xfffa4000 0x4000>;
+ interrupts = <10 4>;
+ status = "disabled";
+ };
+
+ adc0: adc@fffe0000 {
+ compatible = "atmel,at91sam9260-adc";
+ reg = <0xfffe0000 0x100>;
+ interrupts = <5 4>;
+ atmel,adc-use-external-triggers;
+ atmel,adc-channels-used = <0xf>;
+ atmel,adc-vref = <3300>;
+ atmel,adc-num-channels = <4>;
+ atmel,adc-startup-time = <15>;
+ atmel,adc-channel-base = <0x30>;
+ atmel,adc-drdy-mask = <0x10000>;
+ atmel,adc-status-register = <0x1c>;
+ atmel,adc-trigger-register = <0x04>;
+
+ trigger@0 {
+ trigger-name = "timer-counter-0";
+ trigger-value = <0x1>;
+ };
+ trigger@1 {
+ trigger-name = "timer-counter-1";
+ trigger-value = <0x3>;
+ };
+
+ trigger@2 {
+ trigger-name = "timer-counter-2";
+ trigger-value = <0x5>;
+ };
+
+ trigger@3 {
+ trigger-name = "external";
+ trigger-value = <0x13>;
+ trigger-external;
+ };
+ };
+ };
+
+ nand0: nand@40000000 {
+ compatible = "atmel,at91rm9200-nand";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x40000000 0x10000000
+ 0xffffe800 0x200
+ >;
+ atmel,nand-addr-offset = <21>;
+ atmel,nand-cmd-offset = <22>;
+ gpios = <&pioC 13 0
+ &pioC 14 0
+ 0
+ >;
+ status = "disabled";
+ };
+
+ usb0: ohci@00500000 {
+ compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+ reg = <0x00500000 0x100000>;
+ interrupts = <20 4>;
+ status = "disabled";
+ };
+ };
+
+ i2c@0 {
+ compatible = "i2c-gpio";
+ gpios = <&pioA 23 0 /* sda */
+ &pioA 24 0 /* scl */
+ >;
+ i2c-gpio,sda-open-drain;
+ i2c-gpio,scl-open-drain;
+ i2c-gpio,delay-us = <2>; /* ~100 kHz */
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+};
diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
new file mode 100644
index 000000000000..0209913a65a2
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9263.dtsi
@@ -0,0 +1,220 @@
+/*
+ * at91sam9263.dtsi - Device Tree Include file for AT91SAM9263 family SoC
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2 only.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ model = "Atmel AT91SAM9263 family SoC";
+ compatible = "atmel,at91sam9263";
+ interrupt-parent = <&aic>;
+
+ aliases {
+ serial0 = &dbgu;
+ serial1 = &usart0;
+ serial2 = &usart1;
+ serial3 = &usart2;
+ gpio0 = &pioA;
+ gpio1 = &pioB;
+ gpio2 = &pioC;
+ gpio3 = &pioD;
+ gpio4 = &pioE;
+ tcb0 = &tcb0;
+ };
+ cpus {
+ cpu@0 {
+ compatible = "arm,arm926ejs";
+ };
+ };
+
+ memory {
+ reg = <0x20000000 0x08000000>;
+ };
+
+ ahb {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ apb {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ aic: interrupt-controller@fffff000 {
+ #interrupt-cells = <2>;
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ reg = <0xfffff000 0x200>;
+ };
+
+ pmc: pmc@fffffc00 {
+ compatible = "atmel,at91rm9200-pmc";
+ reg = <0xfffffc00 0x100>;
+ };
+
+ ramc: ramc@ffffe200 {
+ compatible = "atmel,at91sam9260-sdramc";
+ reg = <0xffffe200 0x200
+ 0xffffe800 0x200>;
+ };
+
+ pit: timer@fffffd30 {
+ compatible = "atmel,at91sam9260-pit";
+ reg = <0xfffffd30 0xf>;
+ interrupts = <1 4>;
+ };
+
+ tcb0: timer@fff7c000 {
+ compatible = "atmel,at91rm9200-tcb";
+ reg = <0xfff7c000 0x100>;
+ interrupts = <19 4>;
+ };
+
+ rstc@fffffd00 {
+ compatible = "atmel,at91sam9260-rstc";
+ reg = <0xfffffd00 0x10>;
+ };
+
+ shdwc@fffffd10 {
+ compatible = "atmel,at91sam9260-shdwc";
+ reg = <0xfffffd10 0x10>;
+ };
+
+ pioA: gpio@fffff200 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff200 0x100>;
+ interrupts = <2 4>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ };
+
+ pioB: gpio@fffff400 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x100>;
+ interrupts = <3 4>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ };
+
+ pioC: gpio@fffff600 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff600 0x100>;
+ interrupts = <4 4>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ };
+
+ pioD: gpio@fffff800 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffff800 0x100>;
+ interrupts = <4 4>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ };
+
+ pioE: gpio@fffffa00 {
+ compatible = "atmel,at91rm9200-gpio";
+ reg = <0xfffffa00 0x100>;
+ interrupts = <4 4>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ };
+
+ dbgu: serial@ffffee00 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xffffee00 0x200>;
+ interrupts = <1 4>;
+ status = "disabled";
+ };
+
+ usart0: serial@fff8c000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfff8c000 0x200>;
+ interrupts = <7 4>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+ };
+
+ usart1: serial@fff90000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfff90000 0x200>;
+ interrupts = <8 4>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+ };
+
+ usart2: serial@fff94000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfff94000 0x200>;
+ interrupts = <9 4>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+ };
+
+ macb0: ethernet@fffbc000 {
+ compatible = "cdns,at32ap7000-macb", "cdns,macb";
+ reg = <0xfffbc000 0x100>;
+ interrupts = <21 4>;
+ status = "disabled";
+ };
+
+ usb1: gadget@fff78000 {
+ compatible = "atmel,at91rm9200-udc";
+ reg = <0xfff78000 0x4000>;
+ interrupts = <24 4>;
+ status = "disabled";
+ };
+ };
+
+ nand0: nand@40000000 {
+ compatible = "atmel,at91rm9200-nand";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x40000000 0x10000000
+ 0xffffe000 0x200
+ >;
+ atmel,nand-addr-offset = <21>;
+ atmel,nand-cmd-offset = <22>;
+ gpios = <&pioA 22 0
+ &pioD 15 0
+ 0
+ >;
+ status = "disabled";
+ };
+
+ usb0: ohci@00a00000 {
+ compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+ reg = <0x00a00000 0x100000>;
+ interrupts = <29 4>;
+ status = "disabled";
+ };
+ };
+
+ i2c@0 {
+ compatible = "i2c-gpio";
+ gpios = <&pioB 4 0 /* sda */
+ &pioB 5 0 /* scl */
+ >;
+ i2c-gpio,sda-open-drain;
+ i2c-gpio,scl-open-drain;
+ i2c-gpio,delay-us = <2>; /* ~100 kHz */
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+};
diff --git a/arch/arm/boot/dts/at91sam9263ek.dts b/arch/arm/boot/dts/at91sam9263ek.dts
new file mode 100644
index 000000000000..f86ac4b609fc
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9263ek.dts
@@ -0,0 +1,156 @@
+/*
+ * at91sam9263ek.dts - Device Tree file for Atmel at91sam9263 reference board
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2 only
+ */
+/dts-v1/;
+/include/ "at91sam9263.dtsi"
+
+/ {
+ model = "Atmel at91sam9263ek";
+ compatible = "atmel,at91sam9263ek", "atmel,at91sam9263", "atmel,at91sam9";
+
+ chosen {
+ bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs";
+ };
+
+ memory {
+ reg = <0x20000000 0x4000000>;
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ main_clock: clock@0 {
+ compatible = "atmel,osc", "fixed-clock";
+ clock-frequency = <16367660>;
+ };
+ };
+
+ ahb {
+ apb {
+ dbgu: serial@ffffee00 {
+ status = "okay";
+ };
+
+ usart0: serial@fff8c000 {
+ status = "okay";
+ };
+
+ macb0: ethernet@fffbc000 {
+ phy-mode = "rmii";
+ status = "okay";
+ };
+
+ usb1: gadget@fff78000 {
+ atmel,vbus-gpio = <&pioA 25 0>;
+ status = "okay";
+ };
+ };
+
+ nand0: nand@40000000 {
+ nand-bus-width = <8>;
+ nand-ecc-mode = "soft";
+ nand-on-flash-bbt = <1>;
+ status = "okay";
+
+ at91bootstrap@0 {
+ label = "at91bootstrap";
+ reg = <0x0 0x20000>;
+ };
+
+ barebox@20000 {
+ label = "barebox";
+ reg = <0x20000 0x40000>;
+ };
+
+ bareboxenv@60000 {
+ label = "bareboxenv";
+ reg = <0x60000 0x20000>;
+ };
+
+ bareboxenv2@80000 {
+ label = "bareboxenv2";
+ reg = <0x80000 0x20000>;
+ };
+
+ oftree@80000 {
+ label = "oftree";
+ reg = <0xa0000 0x20000>;
+ };
+
+ kernel@a0000 {
+ label = "kernel";
+ reg = <0xc0000 0x400000>;
+ };
+
+ rootfs@4a0000 {
+ label = "rootfs";
+ reg = <0x4c0000 0x7800000>;
+ };
+
+ data@7ca0000 {
+ label = "data";
+ reg = <0x7cc0000 0x8340000>;
+ };
+ };
+
+ usb0: ohci@00a00000 {
+ num-ports = <2>;
+ status = "okay";
+ atmel,vbus-gpio = <&pioA 24 0
+ &pioA 21 0
+ >;
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ d3 {
+ label = "d3";
+ gpios = <&pioB 7 0>;
+ linux,default-trigger = "heartbeat";
+ };
+
+ d2 {
+ label = "d2";
+ gpios = <&pioC 29 1>;
+ linux,default-trigger = "nand-disk";
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ left_click {
+ label = "left_click";
+ gpios = <&pioC 5 1>;
+ linux,code = <272>;
+ gpio-key,wakeup;
+ };
+
+ right_click {
+ label = "right_click";
+ gpios = <&pioC 4 1>;
+ linux,code = <273>;
+ gpio-key,wakeup;
+ };
+ };
+
+ i2c@0 {
+ status = "okay";
+
+ 24c512@50 {
+ compatible = "24c512";
+ reg = <0x50>;
+ pagesize = <128>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/at91sam9g20.dtsi b/arch/arm/boot/dts/at91sam9g20.dtsi
index 773ef484037a..2a1d1ca8bd86 100644
--- a/arch/arm/boot/dts/at91sam9g20.dtsi
+++ b/arch/arm/boot/dts/at91sam9g20.dtsi
@@ -1,238 +1,26 @@
/*
* at91sam9g20.dtsi - Device Tree Include file for AT91SAM9G20 family SoC
*
- * Copyright (C) 2011 Atmel,
- * 2011 Nicolas Ferre <nicolas.ferre@atmel.com>,
- * 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
*
- * Licensed under GPLv2 or later.
+ * Licensed under GPLv2.
*/
-/include/ "skeleton.dtsi"
+/include/ "at91sam9260.dtsi"
/ {
model = "Atmel AT91SAM9G20 family SoC";
compatible = "atmel,at91sam9g20";
- interrupt-parent = <&aic>;
-
- aliases {
- serial0 = &dbgu;
- serial1 = &usart0;
- serial2 = &usart1;
- serial3 = &usart2;
- serial4 = &usart3;
- serial5 = &usart4;
- serial6 = &usart5;
- gpio0 = &pioA;
- gpio1 = &pioB;
- gpio2 = &pioC;
- tcb0 = &tcb0;
- tcb1 = &tcb1;
- };
- cpus {
- cpu@0 {
- compatible = "arm,arm926ejs";
- };
- };
memory {
reg = <0x20000000 0x08000000>;
};
ahb {
- compatible = "simple-bus";
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
apb {
- compatible = "simple-bus";
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- aic: interrupt-controller@fffff000 {
- #interrupt-cells = <2>;
- compatible = "atmel,at91rm9200-aic";
- interrupt-controller;
- reg = <0xfffff000 0x200>;
- };
-
- ramc0: ramc@ffffea00 {
- compatible = "atmel,at91sam9260-sdramc";
- reg = <0xffffea00 0x200>;
- };
-
- pmc: pmc@fffffc00 {
- compatible = "atmel,at91rm9200-pmc";
- reg = <0xfffffc00 0x100>;
- };
-
- rstc@fffffd00 {
- compatible = "atmel,at91sam9260-rstc";
- reg = <0xfffffd00 0x10>;
- };
-
- shdwc@fffffd10 {
- compatible = "atmel,at91sam9260-shdwc";
- reg = <0xfffffd10 0x10>;
- };
-
- pit: timer@fffffd30 {
- compatible = "atmel,at91sam9260-pit";
- reg = <0xfffffd30 0xf>;
- interrupts = <1 4>;
- };
-
- tcb0: timer@fffa0000 {
- compatible = "atmel,at91rm9200-tcb";
- reg = <0xfffa0000 0x100>;
- interrupts = <17 4 18 4 19 4>;
- };
-
- tcb1: timer@fffdc000 {
- compatible = "atmel,at91rm9200-tcb";
- reg = <0xfffdc000 0x100>;
- interrupts = <26 4 27 4 28 4>;
- };
-
- pioA: gpio@fffff400 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff400 0x100>;
- interrupts = <2 4>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- };
-
- pioB: gpio@fffff600 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff600 0x100>;
- interrupts = <3 4>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- };
-
- pioC: gpio@fffff800 {
- compatible = "atmel,at91rm9200-gpio";
- reg = <0xfffff800 0x100>;
- interrupts = <4 4>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupt-controller;
- };
-
- dbgu: serial@fffff200 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xfffff200 0x200>;
- interrupts = <1 4>;
- status = "disabled";
- };
-
- usart0: serial@fffb0000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xfffb0000 0x200>;
- interrupts = <6 4>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
- };
-
- usart1: serial@fffb4000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xfffb4000 0x200>;
- interrupts = <7 4>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
- };
-
- usart2: serial@fffb8000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xfffb8000 0x200>;
- interrupts = <8 4>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
- };
-
- usart3: serial@fffd0000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xfffd0000 0x200>;
- interrupts = <23 4>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
- };
-
- usart4: serial@fffd4000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xfffd4000 0x200>;
- interrupts = <24 4>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
- };
-
- usart5: serial@fffd8000 {
- compatible = "atmel,at91sam9260-usart";
- reg = <0xfffd8000 0x200>;
- interrupts = <25 4>;
- atmel,use-dma-rx;
- atmel,use-dma-tx;
- status = "disabled";
- };
-
- macb0: ethernet@fffc4000 {
- compatible = "cdns,at32ap7000-macb", "cdns,macb";
- reg = <0xfffc4000 0x100>;
- interrupts = <21 4>;
- status = "disabled";
- };
-
- usb1: gadget@fffa4000 {
- compatible = "atmel,at91rm9200-udc";
- reg = <0xfffa4000 0x4000>;
- interrupts = <10 4>;
- status = "disabled";
+ adc0: adc@fffe0000 {
+ atmel,adc-startup-time = <40>;
};
};
-
- nand0: nand@40000000 {
- compatible = "atmel,at91rm9200-nand";
- #address-cells = <1>;
- #size-cells = <1>;
- reg = <0x40000000 0x10000000
- 0xffffe800 0x200
- >;
- atmel,nand-addr-offset = <21>;
- atmel,nand-cmd-offset = <22>;
- gpios = <&pioC 13 0
- &pioC 14 0
- 0
- >;
- status = "disabled";
- };
-
- usb0: ohci@00500000 {
- compatible = "atmel,at91rm9200-ohci", "usb-ohci";
- reg = <0x00500000 0x100000>;
- interrupts = <20 4>;
- status = "disabled";
- };
- };
-
- i2c@0 {
- compatible = "i2c-gpio";
- gpios = <&pioA 23 0 /* sda */
- &pioA 24 0 /* scl */
- >;
- i2c-gpio,sda-open-drain;
- i2c-gpio,scl-open-drain;
- i2c-gpio,delay-us = <2>; /* ~100 kHz */
- #address-cells = <1>;
- #size-cells = <0>;
- status = "disabled";
};
};
diff --git a/arch/arm/boot/dts/at91sam9g20ek.dts b/arch/arm/boot/dts/at91sam9g20ek.dts
new file mode 100644
index 000000000000..e5324bf9d529
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9g20ek.dts
@@ -0,0 +1,29 @@
+/*
+ * at91sam9g20ek.dts - Device Tree file for Atmel at91sam9g20ek board
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+/dts-v1/;
+/include/ "at91sam9g20ek_common.dtsi"
+
+/ {
+ model = "Atmel at91sam9g20ek";
+ compatible = "atmel,at91sam9g20ek", "atmel,at91sam9g20", "atmel,at91sam9";
+
+ leds {
+ compatible = "gpio-leds";
+
+ ds1 {
+ label = "ds1";
+ gpios = <&pioA 9 0>;
+ linux,default-trigger = "heartbeat";
+ };
+
+ ds5 {
+ label = "ds5";
+ gpios = <&pioA 6 1>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts b/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts
new file mode 100644
index 000000000000..f1b2e148ac8c
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9g20ek_2mmc.dts
@@ -0,0 +1,29 @@
+/*
+ * at91sam9g20ek_2mmc.dts - Device Tree file for Atmel at91sam9g20ek 2 MMC board
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+/dts-v1/;
+/include/ "at91sam9g20ek_common.dtsi"
+
+/ {
+ model = "Atmel at91sam9g20ek 2 mmc";
+ compatible = "atmel,at91sam9g20ek_2mmc", "atmel,at91sam9g20", "atmel,at91sam9";
+
+ leds {
+ compatible = "gpio-leds";
+
+ ds1 {
+ label = "ds1";
+ gpios = <&pioB 9 0>;
+ linux,default-trigger = "heartbeat";
+ };
+
+ ds5 {
+ label = "ds5";
+ gpios = <&pioB 8 1>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
new file mode 100644
index 000000000000..b06c0db273b1
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
@@ -0,0 +1,142 @@
+/*
+ * at91sam9g20ek_common.dtsi - Device Tree file for Atmel at91sam9g20ek board
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+/include/ "at91sam9g20.dtsi"
+
+/ {
+
+ chosen {
+ bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs";
+ };
+
+ memory {
+ reg = <0x20000000 0x4000000>;
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ main_clock: clock@0 {
+ compatible = "atmel,osc", "fixed-clock";
+ clock-frequency = <18432000>;
+ };
+ };
+
+ ahb {
+ apb {
+ dbgu: serial@fffff200 {
+ status = "okay";
+ };
+
+ usart0: serial@fffb0000 {
+ status = "okay";
+ };
+
+ usart1: serial@fffb4000 {
+ status = "okay";
+ };
+
+ macb0: ethernet@fffc4000 {
+ phy-mode = "rmii";
+ status = "okay";
+ };
+
+ usb1: gadget@fffa4000 {
+ atmel,vbus-gpio = <&pioC 5 0>;
+ status = "okay";
+ };
+ };
+
+ nand0: nand@40000000 {
+ nand-bus-width = <8>;
+ nand-ecc-mode = "soft";
+ nand-on-flash-bbt;
+ status = "okay";
+
+ at91bootstrap@0 {
+ label = "at91bootstrap";
+ reg = <0x0 0x20000>;
+ };
+
+ barebox@20000 {
+ label = "barebox";
+ reg = <0x20000 0x40000>;
+ };
+
+ bareboxenv@60000 {
+ label = "bareboxenv";
+ reg = <0x60000 0x20000>;
+ };
+
+ bareboxenv2@80000 {
+ label = "bareboxenv2";
+ reg = <0x80000 0x20000>;
+ };
+
+ oftree@80000 {
+ label = "oftree";
+ reg = <0xa0000 0x20000>;
+ };
+
+ kernel@a0000 {
+ label = "kernel";
+ reg = <0xc0000 0x400000>;
+ };
+
+ rootfs@4a0000 {
+ label = "rootfs";
+ reg = <0x4c0000 0x7800000>;
+ };
+
+ data@7ca0000 {
+ label = "data";
+ reg = <0x7cc0000 0x8340000>;
+ };
+ };
+
+ usb0: ohci@00500000 {
+ num-ports = <2>;
+ status = "okay";
+ };
+ };
+
+ i2c@0 {
+ status = "okay";
+
+ 24c512@50 {
+ compatible = "24c512";
+ reg = <0x50>;
+ };
+
+ wm8731@1b {
+ compatible = "wm8731";
+ reg = <0x1b>;
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ btn3 {
+ label = "Buttin 3";
+ gpios = <&pioA 30 1>;
+ linux,code = <0x103>;
+ gpio-key,wakeup;
+ };
+
+ btn4 {
+ label = "Buttin 4";
+ gpios = <&pioA 31 1>;
+ linux,code = <0x104>;
+ gpio-key,wakeup;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
index c8042147eaa2..7dbccaf199f7 100644
--- a/arch/arm/boot/dts/at91sam9g45.dtsi
+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
@@ -199,6 +199,43 @@
interrupts = <25 4>;
status = "disabled";
};
+
+ adc0: adc@fffb0000 {
+ compatible = "atmel,at91sam9260-adc";
+ reg = <0xfffb0000 0x100>;
+ interrupts = <20 4>;
+ atmel,adc-use-external-triggers;
+ atmel,adc-channels-used = <0xff>;
+ atmel,adc-vref = <3300>;
+ atmel,adc-num-channels = <8>;
+ atmel,adc-startup-time = <40>;
+ atmel,adc-channel-base = <0x30>;
+ atmel,adc-drdy-mask = <0x10000>;
+ atmel,adc-status-register = <0x1c>;
+ atmel,adc-trigger-register = <0x08>;
+
+ trigger@0 {
+ trigger-name = "external-rising";
+ trigger-value = <0x1>;
+ trigger-external;
+ };
+ trigger@1 {
+ trigger-name = "external-falling";
+ trigger-value = <0x2>;
+ trigger-external;
+ };
+
+ trigger@2 {
+ trigger-name = "external-any";
+ trigger-value = <0x3>;
+ trigger-external;
+ };
+
+ trigger@3 {
+ trigger-name = "continuous";
+ trigger-value = <0x6>;
+ };
+ };
};
nand0: nand@40000000 {
diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
new file mode 100644
index 000000000000..cb84de791b5a
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9n12.dtsi
@@ -0,0 +1,221 @@
+/*
+ * at91sam9n12.dtsi - Device Tree include file for AT91SAM9N12 SoC
+ *
+ * Copyright (C) 2012 Atmel,
+ * 2012 Hong Xu <hong.xu@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ model = "Atmel AT91SAM9N12 SoC";
+ compatible = "atmel,at91sam9n12";
+ interrupt-parent = <&aic>;
+
+ aliases {
+ serial0 = &dbgu;
+ serial1 = &usart0;
+ serial2 = &usart1;
+ serial3 = &usart2;
+ serial4 = &usart3;
+ gpio0 = &pioA;
+ gpio1 = &pioB;
+ gpio2 = &pioC;
+ gpio3 = &pioD;
+ tcb0 = &tcb0;
+ tcb1 = &tcb1;
+ };
+ cpus {
+ cpu@0 {
+ compatible = "arm,arm926ejs";
+ };
+ };
+
+ memory {
+ reg = <0x20000000 0x10000000>;
+ };
+
+ ahb {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ apb {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ aic: interrupt-controller@fffff000 {
+ #interrupt-cells = <2>;
+ compatible = "atmel,at91rm9200-aic";
+ interrupt-controller;
+ reg = <0xfffff000 0x200>;
+ };
+
+ ramc0: ramc@ffffe800 {
+ compatible = "atmel,at91sam9g45-ddramc";
+ reg = <0xffffe800 0x200>;
+ };
+
+ pmc: pmc@fffffc00 {
+ compatible = "atmel,at91rm9200-pmc";
+ reg = <0xfffffc00 0x100>;
+ };
+
+ rstc@fffffe00 {
+ compatible = "atmel,at91sam9g45-rstc";
+ reg = <0xfffffe00 0x10>;
+ };
+
+ pit: timer@fffffe30 {
+ compatible = "atmel,at91sam9260-pit";
+ reg = <0xfffffe30 0xf>;
+ interrupts = <1 4>;
+ };
+
+ shdwc@fffffe10 {
+ compatible = "atmel,at91sam9x5-shdwc";
+ reg = <0xfffffe10 0x10>;
+ };
+
+ tcb0: timer@f8008000 {
+ compatible = "atmel,at91sam9x5-tcb";
+ reg = <0xf8008000 0x100>;
+ interrupts = <17 4>;
+ };
+
+ tcb1: timer@f800c000 {
+ compatible = "atmel,at91sam9x5-tcb";
+ reg = <0xf800c000 0x100>;
+ interrupts = <17 4>;
+ };
+
+ dma: dma-controller@ffffec00 {
+ compatible = "atmel,at91sam9g45-dma";
+ reg = <0xffffec00 0x200>;
+ interrupts = <20 4>;
+ };
+
+ pioA: gpio@fffff400 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff400 0x100>;
+ interrupts = <2 4>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ };
+
+ pioB: gpio@fffff600 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff600 0x100>;
+ interrupts = <2 4>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ };
+
+ pioC: gpio@fffff800 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffff800 0x100>;
+ interrupts = <3 4>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ };
+
+ pioD: gpio@fffffa00 {
+ compatible = "atmel,at91sam9x5-gpio", "atmel,at91rm9200-gpio";
+ reg = <0xfffffa00 0x100>;
+ interrupts = <3 4>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupt-controller;
+ };
+
+ dbgu: serial@fffff200 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xfffff200 0x200>;
+ interrupts = <1 4>;
+ status = "disabled";
+ };
+
+ usart0: serial@f801c000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf801c000 0x4000>;
+ interrupts = <5 4>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+ };
+
+ usart1: serial@f8020000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf8020000 0x4000>;
+ interrupts = <6 4>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+ };
+
+ usart2: serial@f8024000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf8024000 0x4000>;
+ interrupts = <7 4>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+ };
+
+ usart3: serial@f8028000 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0xf8028000 0x4000>;
+ interrupts = <8 4>;
+ atmel,use-dma-rx;
+ atmel,use-dma-tx;
+ status = "disabled";
+ };
+ };
+
+ nand0: nand@40000000 {
+ compatible = "atmel,at91rm9200-nand";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = < 0x40000000 0x10000000
+ 0xffffe000 0x00000600
+ 0xffffe600 0x00000200
+ 0x00100000 0x00100000
+ >;
+ atmel,nand-addr-offset = <21>;
+ atmel,nand-cmd-offset = <22>;
+ gpios = <&pioD 5 0
+ &pioD 4 0
+ 0
+ >;
+ status = "disabled";
+ };
+
+ usb0: ohci@00500000 {
+ compatible = "atmel,at91rm9200-ohci", "usb-ohci";
+ reg = <0x00500000 0x00100000>;
+ interrupts = <22 4>;
+ status = "disabled";
+ };
+ };
+
+ i2c@0 {
+ compatible = "i2c-gpio";
+ gpios = <&pioA 30 0 /* sda */
+ &pioA 31 0 /* scl */
+ >;
+ i2c-gpio,sda-open-drain;
+ i2c-gpio,scl-open-drain;
+ i2c-gpio,delay-us = <2>; /* ~100 kHz */
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+};
diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts
new file mode 100644
index 000000000000..f4e43e38f3a1
--- /dev/null
+++ b/arch/arm/boot/dts/at91sam9n12ek.dts
@@ -0,0 +1,84 @@
+/*
+ * at91sam9n12ek.dts - Device Tree file for AT91SAM9N12-EK board
+ *
+ * Copyright (C) 2012 Atmel,
+ * 2012 Hong Xu <hong.xu@atmel.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+/dts-v1/;
+/include/ "at91sam9n12.dtsi"
+
+/ {
+ model = "Atmel AT91SAM9N12-EK";
+ compatible = "atmel,at91sam9n12ek", "atmel,at91sam9n12", "atmel,at91sam9";
+
+ chosen {
+ bootargs = "mem=128M console=ttyS0,115200 root=/dev/mtdblock1 rw rootfstype=jffs2";
+ };
+
+ memory {
+ reg = <0x20000000 0x10000000>;
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ main_clock: clock@0 {
+ compatible = "atmel,osc", "fixed-clock";
+ clock-frequency = <16000000>;
+ };
+ };
+
+ ahb {
+ apb {
+ dbgu: serial@fffff200 {
+ status = "okay";
+ };
+ };
+
+ nand0: nand@40000000 {
+ nand-bus-width = <8>;
+ nand-ecc-mode = "soft";
+ nand-on-flash-bbt;
+ status = "okay";
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ d8 {
+ label = "d8";
+ gpios = <&pioB 4 1>;
+ linux,default-trigger = "mmc0";
+ };
+
+ d9 {
+ label = "d6";
+ gpios = <&pioB 5 1>;
+ linux,default-trigger = "nand-disk";
+ };
+
+ d10 {
+ label = "d7";
+ gpios = <&pioB 6 0>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ enter {
+ label = "Enter";
+ gpios = <&pioB 4 1>;
+ linux,code = <28>;
+ gpio-key,wakeup;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
index dd4ed748469a..6b3ef4339ae7 100644
--- a/arch/arm/boot/dts/at91sam9x5.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -190,6 +190,44 @@
interrupts = <27 4>;
status = "disabled";
};
+
+ adc0: adc@f804c000 {
+ compatible = "atmel,at91sam9260-adc";
+ reg = <0xf804c000 0x100>;
+ interrupts = <19 4>;
+ atmel,adc-use-external;
+ atmel,adc-channels-used = <0xffff>;
+ atmel,adc-vref = <3300>;
+ atmel,adc-num-channels = <12>;
+ atmel,adc-startup-time = <40>;
+ atmel,adc-channel-base = <0x50>;
+ atmel,adc-drdy-mask = <0x1000000>;
+ atmel,adc-status-register = <0x30>;
+ atmel,adc-trigger-register = <0xc0>;
+
+ trigger@0 {
+ trigger-name = "external-rising";
+ trigger-value = <0x1>;
+ trigger-external;
+ };
+
+ trigger@1 {
+ trigger-name = "external-falling";
+ trigger-value = <0x2>;
+ trigger-external;
+ };
+
+ trigger@2 {
+ trigger-name = "external-any";
+ trigger-value = <0x3>;
+ trigger-external;
+ };
+
+ trigger@3 {
+ trigger-name = "continuous";
+ trigger-value = <0x6>;
+ };
+ };
};
nand0: nand@40000000 {
diff --git a/arch/arm/boot/dts/db8500.dtsi b/arch/arm/boot/dts/db8500.dtsi
index 14bc30705099..881bc3987844 100644
--- a/arch/arm/boot/dts/db8500.dtsi
+++ b/arch/arm/boot/dts/db8500.dtsi
@@ -55,83 +55,101 @@
gpio0: gpio@8012e000 {
compatible = "stericsson,db8500-gpio",
- "stmicroelectronics,nomadik-gpio";
+ "st,nomadik-gpio";
reg = <0x8012e000 0x80>;
interrupts = <0 119 0x4>;
supports-sleepmode;
gpio-controller;
+ #gpio-cells = <2>;
+ gpio-bank = <0>;
};
gpio1: gpio@8012e080 {
compatible = "stericsson,db8500-gpio",
- "stmicroelectronics,nomadik-gpio";
+ "st,nomadik-gpio";
reg = <0x8012e080 0x80>;
interrupts = <0 120 0x4>;
supports-sleepmode;
gpio-controller;
+ #gpio-cells = <2>;
+ gpio-bank = <1>;
};
gpio2: gpio@8000e000 {
compatible = "stericsson,db8500-gpio",
- "stmicroelectronics,nomadik-gpio";
+ "st,nomadik-gpio";
reg = <0x8000e000 0x80>;
interrupts = <0 121 0x4>;
supports-sleepmode;
gpio-controller;
+ #gpio-cells = <2>;
+ gpio-bank = <2>;
};
gpio3: gpio@8000e080 {
compatible = "stericsson,db8500-gpio",
- "stmicroelectronics,nomadik-gpio";
+ "st,nomadik-gpio";
reg = <0x8000e080 0x80>;
interrupts = <0 122 0x4>;
supports-sleepmode;
gpio-controller;
+ #gpio-cells = <2>;
+ gpio-bank = <3>;
};
gpio4: gpio@8000e100 {
compatible = "stericsson,db8500-gpio",
- "stmicroelectronics,nomadik-gpio";
+ "st,nomadik-gpio";
reg = <0x8000e100 0x80>;
interrupts = <0 123 0x4>;
supports-sleepmode;
gpio-controller;
+ #gpio-cells = <2>;
+ gpio-bank = <4>;
};
gpio5: gpio@8000e180 {
compatible = "stericsson,db8500-gpio",
- "stmicroelectronics,nomadik-gpio";
+ "st,nomadik-gpio";
reg = <0x8000e180 0x80>;
interrupts = <0 124 0x4>;
supports-sleepmode;
gpio-controller;
+ #gpio-cells = <2>;
+ gpio-bank = <5>;
};
gpio6: gpio@8011e000 {
compatible = "stericsson,db8500-gpio",
- "stmicroelectronics,nomadik-gpio";
+ "st,nomadik-gpio";
reg = <0x8011e000 0x80>;
interrupts = <0 125 0x4>;
supports-sleepmode;
gpio-controller;
+ #gpio-cells = <2>;
+ gpio-bank = <6>;
};
gpio7: gpio@8011e080 {
compatible = "stericsson,db8500-gpio",
- "stmicroelectronics,nomadik-gpio";
+ "st,nomadik-gpio";
reg = <0x8011e080 0x80>;
interrupts = <0 126 0x4>;
supports-sleepmode;
gpio-controller;
+ #gpio-cells = <2>;
+ gpio-bank = <7>;
};
gpio8: gpio@a03fe000 {
compatible = "stericsson,db8500-gpio",
- "stmicroelectronics,nomadik-gpio";
+ "st,nomadik-gpio";
reg = <0xa03fe000 0x80>;
interrupts = <0 127 0x4>;
supports-sleepmode;
gpio-controller;
+ #gpio-cells = <2>;
+ gpio-bank = <8>;
};
usb@a03e0000 {
@@ -153,7 +171,13 @@
reg = <0x80157000 0x1000>;
interrupts = <46 47>;
#address-cells = <1>;
- #size-cells = <0>;
+ #size-cells = <1>;
+ ranges;
+
+ prcmu-timer-4@80157450 {
+ compatible = "stericsson,db8500-prcmu-timer-4";
+ reg = <0x80157450 0xC>;
+ };
ab8500@5 {
compatible = "stericsson,ab8500";
@@ -163,7 +187,7 @@
};
i2c@80004000 {
- compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c";
+ compatible = "stericsson,db8500-i2c", "st,nomadik-i2c";
reg = <0x80004000 0x1000>;
interrupts = <0 21 0x4>;
#address-cells = <1>;
@@ -171,7 +195,7 @@
};
i2c@80122000 {
- compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c";
+ compatible = "stericsson,db8500-i2c", "st,nomadik-i2c";
reg = <0x80122000 0x1000>;
interrupts = <0 22 0x4>;
#address-cells = <1>;
@@ -179,7 +203,7 @@
};
i2c@80128000 {
- compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c";
+ compatible = "stericsson,db8500-i2c", "st,nomadik-i2c";
reg = <0x80128000 0x1000>;
interrupts = <0 55 0x4>;
#address-cells = <1>;
@@ -187,7 +211,7 @@
};
i2c@80110000 {
- compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c";
+ compatible = "stericsson,db8500-i2c", "st,nomadik-i2c";
reg = <0x80110000 0x1000>;
interrupts = <0 12 0x4>;
#address-cells = <1>;
@@ -195,7 +219,7 @@
};
i2c@8012a000 {
- compatible = "stericsson,db8500-i2c", "stmicroelectronics,nomadik-i2c";
+ compatible = "stericsson,db8500-i2c", "st,nomadik-i2c";
reg = <0x8012a000 0x1000>;
interrupts = <0 51 0x4>;
#address-cells = <1>;
@@ -270,5 +294,14 @@
interrupts = <0 100 0x4>;
status = "disabled";
};
+
+ external-bus@50000000 {
+ compatible = "simple-bus";
+ reg = <0x50000000 0x4000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x50000000 0x4000000>;
+ status = "disabled";
+ };
};
};
diff --git a/arch/arm/boot/dts/emev2-kzm9d.dts b/arch/arm/boot/dts/emev2-kzm9d.dts
new file mode 100644
index 000000000000..297e3baba71c
--- /dev/null
+++ b/arch/arm/boot/dts/emev2-kzm9d.dts
@@ -0,0 +1,26 @@
+/*
+ * Device Tree Source for the KZM9D board
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+/dts-v1/;
+
+/include/ "emev2.dtsi"
+
+/ {
+ model = "EMEV2 KZM9D Board";
+ compatible = "renesas,kzm9d", "renesas,emev2";
+
+ memory {
+ device_type = "memory";
+ reg = <0x40000000 0x8000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS1,115200n81";
+ };
+};
diff --git a/arch/arm/boot/dts/emev2.dtsi b/arch/arm/boot/dts/emev2.dtsi
new file mode 100644
index 000000000000..eb504a6c0f4a
--- /dev/null
+++ b/arch/arm/boot/dts/emev2.dtsi
@@ -0,0 +1,63 @@
+/*
+ * Device Tree Source for the EMEV2 SoC
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ compatible = "renesas,emev2";
+ interrupt-parent = <&gic>;
+
+ cpus {
+ cpu@0 {
+ compatible = "arm,cortex-a9";
+ };
+ cpu@1 {
+ compatible = "arm,cortex-a9";
+ };
+ };
+
+ gic: interrupt-controller@e0020000 {
+ compatible = "arm,cortex-a9-gic";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ reg = <0xe0028000 0x1000>,
+ <0xe0020000 0x0100>;
+ };
+
+ sti@e0180000 {
+ compatible = "renesas,em-sti";
+ reg = <0xe0180000 0x54>;
+ interrupts = <0 125 0>;
+ };
+
+ uart@e1020000 {
+ compatible = "renesas,em-uart";
+ reg = <0xe1020000 0x38>;
+ interrupts = <0 8 0>;
+ };
+
+ uart@e1030000 {
+ compatible = "renesas,em-uart";
+ reg = <0xe1030000 0x38>;
+ interrupts = <0 9 0>;
+ };
+
+ uart@e1040000 {
+ compatible = "renesas,em-uart";
+ reg = <0xe1040000 0x38>;
+ interrupts = <0 10 0>;
+ };
+
+ uart@e1050000 {
+ compatible = "renesas,em-uart";
+ reg = <0xe1050000 0x38>;
+ interrupts = <0 11 0>;
+ };
+};
diff --git a/arch/arm/boot/dts/ethernut5.dts b/arch/arm/boot/dts/ethernut5.dts
new file mode 100644
index 000000000000..1ea9d34460a4
--- /dev/null
+++ b/arch/arm/boot/dts/ethernut5.dts
@@ -0,0 +1,84 @@
+/*
+ * ethernut5.dts - Device Tree file for Ethernut 5 board
+ *
+ * Copyright (C) 2012 egnite GmbH <info@egnite.de>
+ *
+ * Licensed under GPLv2.
+ */
+/dts-v1/;
+/include/ "at91sam9260.dtsi"
+
+/ {
+ model = "Ethernut 5";
+ compatible = "egnite,ethernut5", "atmel,at91sam9260", "atmel,at91sam9";
+
+ chosen {
+ bootargs = "console=ttyS0,115200 root=/dev/mtdblock0 rw rootfstype=jffs2";
+ };
+
+ memory {
+ reg = <0x20000000 0x08000000>;
+ };
+
+ ahb {
+ apb {
+ dbgu: serial@fffff200 {
+ status = "okay";
+ };
+
+ usart0: serial@fffb0000 {
+ status = "okay";
+ };
+
+ usart1: serial@fffb4000 {
+ status = "okay";
+ };
+
+ macb0: ethernet@fffc4000 {
+ phy-mode = "rmii";
+ status = "okay";
+ };
+
+ usb1: gadget@fffa4000 {
+ atmel,vbus-gpio = <&pioC 5 0>;
+ status = "okay";
+ };
+ };
+
+ nand0: nand@40000000 {
+ nand-bus-width = <8>;
+ nand-ecc-mode = "soft";
+ nand-on-flash-bbt;
+ status = "okay";
+
+ gpios = <0
+ &pioC 14 0
+ 0
+ >;
+
+ root@0 {
+ label = "root";
+ reg = <0x0 0x08000000>;
+ };
+
+ data@20000 {
+ label = "data";
+ reg = <0x08000000 0x38000000>;
+ };
+ };
+
+ usb0: ohci@00500000 {
+ num-ports = <2>;
+ status = "okay";
+ };
+ };
+
+ i2c@0 {
+ status = "okay";
+
+ pcf8563@50 {
+ compatible = "nxp,pcf8563";
+ reg = <0x51>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/kirkwood-dns320.dts b/arch/arm/boot/dts/kirkwood-dns320.dts
new file mode 100644
index 000000000000..dc09a735b04a
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-dns320.dts
@@ -0,0 +1,64 @@
+/dts-v1/;
+
+/include/ "kirkwood.dtsi"
+
+/ {
+ model = "D-Link DNS-320 NAS (Rev A1)";
+ compatible = "dlink,dns-320-a1", "dlink,dns-320", "dlink,dns-kirkwood", "mrvl,kirkwood-88f6281", "mrvl,kirkwood";
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x8000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200n8 earlyprintk";
+ };
+
+ ocp@f1000000 {
+ serial@12000 {
+ clock-frequency = <166666667>;
+ status = "okay";
+ };
+
+ serial@12100 {
+ clock-frequency = <166666667>;
+ status = "okay";
+ };
+
+ nand@3000000 {
+ status = "okay";
+
+ partition@0 {
+ label = "u-boot";
+ reg = <0x0000000 0x100000>;
+ read-only;
+ };
+
+ partition@100000 {
+ label = "uImage";
+ reg = <0x0100000 0x500000>;
+ };
+
+ partition@600000 {
+ label = "ramdisk";
+ reg = <0x0600000 0x500000>;
+ };
+
+ partition@b00000 {
+ label = "image";
+ reg = <0x0b00000 0x6600000>;
+ };
+
+ partition@7100000 {
+ label = "mini firmware";
+ reg = <0x7100000 0xa00000>;
+ };
+
+ partition@7b00000 {
+ label = "config";
+ reg = <0x7b00000 0x500000>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/kirkwood-dns325.dts b/arch/arm/boot/dts/kirkwood-dns325.dts
new file mode 100644
index 000000000000..c2a5562525d2
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-dns325.dts
@@ -0,0 +1,59 @@
+/dts-v1/;
+
+/include/ "kirkwood.dtsi"
+
+/ {
+ model = "D-Link DNS-325 NAS (Rev A1)";
+ compatible = "dlink,dns-325-a1", "dlink,dns-325", "dlink,dns-kirkwood", "mrvl,kirkwood-88f6281", "mrvl,kirkwood";
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x10000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200n8 earlyprintk";
+ };
+
+ ocp@f1000000 {
+ serial@12000 {
+ clock-frequency = <200000000>;
+ status = "okay";
+ };
+
+ nand@3000000 {
+ status = "okay";
+
+ partition@0 {
+ label = "u-boot";
+ reg = <0x0000000 0x100000>;
+ read-only;
+ };
+
+ partition@100000 {
+ label = "uImage";
+ reg = <0x0100000 0x500000>;
+ };
+
+ partition@600000 {
+ label = "ramdisk";
+ reg = <0x0600000 0x500000>;
+ };
+
+ partition@b00000 {
+ label = "image";
+ reg = <0x0b00000 0x6600000>;
+ };
+
+ partition@7100000 {
+ label = "mini firmware";
+ reg = <0x7100000 0xa00000>;
+ };
+
+ partition@7b00000 {
+ label = "config";
+ reg = <0x7b00000 0x500000>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/kirkwood-ib62x0.dts b/arch/arm/boot/dts/kirkwood-ib62x0.dts
new file mode 100644
index 000000000000..ada0f0c23085
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-ib62x0.dts
@@ -0,0 +1,44 @@
+/dts-v1/;
+
+/include/ "kirkwood.dtsi"
+
+/ {
+ model = "RaidSonic ICY BOX IB-NAS62x0 (Rev B)";
+ compatible = "raidsonic,ib-nas6210-b", "raidsonic,ib-nas6220-b", "raidsonic,ib-nas6210", "raidsonic,ib-nas6220", "raidsonic,ib-nas62x0", "mrvl,kirkwood-88f6281", "mrvl,kirkwood";
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x10000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200n8 earlyprintk";
+ };
+
+ ocp@f1000000 {
+ serial@12000 {
+ clock-frequency = <200000000>;
+ status = "okay";
+ };
+
+ nand@3000000 {
+ status = "okay";
+
+ partition@0 {
+ label = "u-boot";
+ reg = <0x0000000 0x100000>;
+ };
+
+ partition@100000 {
+ label = "uImage";
+ reg = <0x0100000 0x600000>;
+ };
+
+ partition@700000 {
+ label = "root";
+ reg = <0x0700000 0xf900000>;
+ };
+
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/kirkwood-iconnect.dts b/arch/arm/boot/dts/kirkwood-iconnect.dts
new file mode 100644
index 000000000000..1ba75d4adecc
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-iconnect.dts
@@ -0,0 +1,26 @@
+/dts-v1/;
+
+/include/ "kirkwood.dtsi"
+
+/ {
+ model = "Iomega Iconnect";
+ compatible = "iom,iconnect-1.1", "iom,iconnect", "mrvl,kirkwood-88f6281", "mrvl,kirkwood";
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x10000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200n8 earlyprintk mtdparts=orion_nand:0xc0000@0x0(uboot),0x20000@0xa0000(env),0x300000@0x100000(zImage),0x300000@0x540000(initrd),0x1f400000@0x980000(boot)";
+ linux,initrd-start = <0x4500040>;
+ linux,initrd-end = <0x4800000>;
+ };
+
+ ocp@f1000000 {
+ serial@12000 {
+ clock-frequency = <200000000>;
+ status = "ok";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/kirkwood.dtsi b/arch/arm/boot/dts/kirkwood.dtsi
index 3474ef890945..926528b81baa 100644
--- a/arch/arm/boot/dts/kirkwood.dtsi
+++ b/arch/arm/boot/dts/kirkwood.dtsi
@@ -5,7 +5,7 @@
ocp@f1000000 {
compatible = "simple-bus";
- ranges = <0 0xf1000000 0x1000000>;
+ ranges = <0 0xf1000000 0x4000000>;
#address-cells = <1>;
#size-cells = <1>;
@@ -32,5 +32,18 @@
reg = <0x10300 0x20>;
interrupts = <53>;
};
+
+ nand@3000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ cle = <0>;
+ ale = <1>;
+ bank-width = <1>;
+ compatible = "mrvl,orion-nand";
+ reg = <0x3000000 0x400>;
+ chip-delay = <25>;
+ /* set partition map and/or chip-delay in board dts */
+ status = "disabled";
+ };
};
};
diff --git a/arch/arm/boot/dts/kizbox.dts b/arch/arm/boot/dts/kizbox.dts
new file mode 100644
index 000000000000..e8814fe0e277
--- /dev/null
+++ b/arch/arm/boot/dts/kizbox.dts
@@ -0,0 +1,138 @@
+/*
+ * kizbox.dts - Device Tree file for Overkiz Kizbox board
+ *
+ * Copyright (C) 2012 Boris BREZILLON <linux-arm@overkiz.com>
+ *
+ * Licensed under GPLv2.
+ */
+/dts-v1/;
+/include/ "at91sam9g20.dtsi"
+
+/ {
+
+ model = "Overkiz kizbox";
+ compatible = "overkiz,kizbox", "atmel,at91sam9g20", "atmel,at91sam9";
+
+ chosen {
+ bootargs = "panic=5 ubi.mtd=1 rootfstype=ubifs root=ubi0:root";
+ };
+
+ memory {
+ reg = <0x20000000 0x2000000>;
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ main_clock: clock@0 {
+ compatible = "atmel,osc", "fixed-clock";
+ clock-frequency = <18432000>;
+ };
+ };
+
+ ahb {
+ apb {
+ dbgu: serial@fffff200 {
+ status = "okay";
+ };
+
+ usart0: serial@fffb0000 {
+ status = "okay";
+ };
+
+ usart1: serial@fffb4000 {
+ status = "okay";
+ };
+
+ macb0: ethernet@fffc4000 {
+ phy-mode = "mii";
+ status = "okay";
+ };
+
+ };
+
+ nand0: nand@40000000 {
+ nand-bus-width = <8>;
+ nand-ecc-mode = "soft";
+ status = "okay";
+
+ bootloaderkernel@0 {
+ label = "bootloader-kernel";
+ reg = <0x0 0xc0000>;
+ };
+
+ ubi@c0000 {
+ label = "ubi";
+ reg = <0xc0000 0x7f40000>;
+ };
+
+ };
+
+ usb0: ohci@00500000 {
+ num-ports = <1>;
+ status = "okay";
+ };
+ };
+
+ i2c@0 {
+ status = "okay";
+
+ pcf8563@51 {
+ /* nxp pcf8563 rtc */
+ compatible = "nxp,pcf8563";
+ reg = <0x51>;
+ };
+
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ led1g {
+ label = "led1:green";
+ gpios = <&pioB 0 1>;
+ linux,default-trigger = "none";
+ };
+
+ led1r {
+ label = "led1:red";
+ gpios = <&pioB 1 1>;
+ linux,default-trigger = "none";
+ };
+
+ led2g {
+ label = "led2:green";
+ gpios = <&pioB 2 1>;
+ linux,default-trigger = "none";
+ default-state = "on";
+ };
+
+ led2r {
+ label = "led2:red";
+ gpios = <&pioB 3 1>;
+ linux,default-trigger = "none";
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reset {
+ label = "reset";
+ gpios = <&pioB 30 1>;
+ linux,code = <0x100>;
+ gpio-key,wakeup;
+ };
+
+ mode {
+ label = "mode";
+ gpios = <&pioB 31 1>;
+ linux,code = <0x101>;
+ gpio-key,wakeup;
+ };
+ };
+}; \ No newline at end of file
diff --git a/arch/arm/boot/dts/lpc32xx.dtsi b/arch/arm/boot/dts/lpc32xx.dtsi
new file mode 100644
index 000000000000..2d696866f71c
--- /dev/null
+++ b/arch/arm/boot/dts/lpc32xx.dtsi
@@ -0,0 +1,292 @@
+/*
+ * NXP LPC32xx SoC
+ *
+ * Copyright 2012 Roland Stigge <stigge@antcom.de>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ compatible = "nxp,lpc3220";
+ interrupt-parent = <&mic>;
+
+ cpus {
+ cpu@0 {
+ compatible = "arm,arm926ejs";
+ };
+ };
+
+ ahb {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <0x20000000 0x20000000 0x30000000>;
+
+ /*
+ * Enable either SLC or MLC
+ */
+ slc: flash@20020000 {
+ compatible = "nxp,lpc3220-slc";
+ reg = <0x20020000 0x1000>;
+ status = "disable";
+ };
+
+ mlc: flash@200B0000 {
+ compatible = "nxp,lpc3220-mlc";
+ reg = <0x200B0000 0x1000>;
+ status = "disable";
+ };
+
+ dma@31000000 {
+ compatible = "arm,pl080", "arm,primecell";
+ reg = <0x31000000 0x1000>;
+ interrupts = <0x1c 0>;
+ };
+
+ /*
+ * Enable either ohci or usbd (gadget)!
+ */
+ ohci@31020000 {
+ compatible = "nxp,ohci-nxp", "usb-ohci";
+ reg = <0x31020000 0x300>;
+ interrupts = <0x3b 0>;
+ status = "disable";
+ };
+
+ usbd@31020000 {
+ compatible = "nxp,lpc3220-udc";
+ reg = <0x31020000 0x300>;
+ interrupts = <0x3d 0>, <0x3e 0>, <0x3c 0>, <0x3a 0>;
+ status = "disable";
+ };
+
+ clcd@31040000 {
+ compatible = "arm,pl110", "arm,primecell";
+ reg = <0x31040000 0x1000>;
+ interrupts = <0x0e 0>;
+ status = "disable";
+ };
+
+ mac: ethernet@31060000 {
+ compatible = "nxp,lpc-eth";
+ reg = <0x31060000 0x1000>;
+ interrupts = <0x1d 0>;
+ };
+
+ apb {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <0x20000000 0x20000000 0x30000000>;
+
+ ssp0: ssp@20084000 {
+ compatible = "arm,pl022", "arm,primecell";
+ reg = <0x20084000 0x1000>;
+ interrupts = <0x14 0>;
+ };
+
+ spi1: spi@20088000 {
+ compatible = "nxp,lpc3220-spi";
+ reg = <0x20088000 0x1000>;
+ };
+
+ ssp1: ssp@2008c000 {
+ compatible = "arm,pl022", "arm,primecell";
+ reg = <0x2008c000 0x1000>;
+ interrupts = <0x15 0>;
+ };
+
+ spi2: spi@20090000 {
+ compatible = "nxp,lpc3220-spi";
+ reg = <0x20090000 0x1000>;
+ };
+
+ i2s0: i2s@20094000 {
+ compatible = "nxp,lpc3220-i2s";
+ reg = <0x20094000 0x1000>;
+ };
+
+ sd@20098000 {
+ compatible = "arm,pl180", "arm,primecell";
+ reg = <0x20098000 0x1000>;
+ interrupts = <0x0f 0>, <0x0d 0>;
+ };
+
+ i2s1: i2s@2009C000 {
+ compatible = "nxp,lpc3220-i2s";
+ reg = <0x2009C000 0x1000>;
+ };
+
+ uart3: serial@40080000 {
+ compatible = "nxp,serial";
+ reg = <0x40080000 0x1000>;
+ };
+
+ uart4: serial@40088000 {
+ compatible = "nxp,serial";
+ reg = <0x40088000 0x1000>;
+ };
+
+ uart5: serial@40090000 {
+ compatible = "nxp,serial";
+ reg = <0x40090000 0x1000>;
+ };
+
+ uart6: serial@40098000 {
+ compatible = "nxp,serial";
+ reg = <0x40098000 0x1000>;
+ };
+
+ i2c1: i2c@400A0000 {
+ compatible = "nxp,pnx-i2c";
+ reg = <0x400A0000 0x100>;
+ interrupts = <0x33 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pnx,timeout = <0x64>;
+ };
+
+ i2c2: i2c@400A8000 {
+ compatible = "nxp,pnx-i2c";
+ reg = <0x400A8000 0x100>;
+ interrupts = <0x32 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pnx,timeout = <0x64>;
+ };
+
+ i2cusb: i2c@31020300 {
+ compatible = "nxp,pnx-i2c";
+ reg = <0x31020300 0x100>;
+ interrupts = <0x3f 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pnx,timeout = <0x64>;
+ };
+ };
+
+ fab {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <0x20000000 0x20000000 0x30000000>;
+
+ /*
+ * MIC Interrupt controller includes:
+ * MIC @40008000
+ * SIC1 @4000C000
+ * SIC2 @40010000
+ */
+ mic: interrupt-controller@40008000 {
+ compatible = "nxp,lpc3220-mic";
+ interrupt-controller;
+ reg = <0x40008000 0xC000>;
+ #interrupt-cells = <2>;
+ };
+
+ uart1: serial@40014000 {
+ compatible = "nxp,serial";
+ reg = <0x40014000 0x1000>;
+ };
+
+ uart2: serial@40018000 {
+ compatible = "nxp,serial";
+ reg = <0x40018000 0x1000>;
+ };
+
+ uart7: serial@4001C000 {
+ compatible = "nxp,serial";
+ reg = <0x4001C000 0x1000>;
+ };
+
+ rtc@40024000 {
+ compatible = "nxp,lpc3220-rtc";
+ reg = <0x40024000 0x1000>;
+ interrupts = <0x34 0>;
+ };
+
+ gpio: gpio@40028000 {
+ compatible = "nxp,lpc3220-gpio";
+ reg = <0x40028000 0x1000>;
+ /* create a private address space for enumeration */
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ gpio_p0: gpio-bank@0 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <0>;
+ };
+
+ gpio_p1: gpio-bank@1 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <1>;
+ };
+
+ gpio_p2: gpio-bank@2 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <2>;
+ };
+
+ gpio_p3: gpio-bank@3 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <3>;
+ };
+
+ gpi_p3: gpio-bank@4 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <4>;
+ };
+
+ gpo_p3: gpio-bank@5 {
+ gpio-controller;
+ #gpio-cells = <2>;
+ reg = <5>;
+ };
+ };
+
+ watchdog@4003C000 {
+ compatible = "nxp,pnx4008-wdt";
+ reg = <0x4003C000 0x1000>;
+ };
+
+ /*
+ * TSC vs. ADC: Since those two share the same
+ * hardware, you need to choose from one of the
+ * following two and do 'status = "okay";' for one of
+ * them
+ */
+
+ adc@40048000 {
+ compatible = "nxp,lpc3220-adc";
+ reg = <0x40048000 0x1000>;
+ interrupts = <0x27 0>;
+ status = "disable";
+ };
+
+ tsc@40048000 {
+ compatible = "nxp,lpc3220-tsc";
+ reg = <0x40048000 0x1000>;
+ interrupts = <0x27 0>;
+ status = "disable";
+ };
+
+ key@40050000 {
+ compatible = "nxp,lpc3220-key";
+ reg = <0x40050000 0x1000>;
+ };
+
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/mmp2-brownstone.dts b/arch/arm/boot/dts/mmp2-brownstone.dts
new file mode 100644
index 000000000000..153a4b2d12b5
--- /dev/null
+++ b/arch/arm/boot/dts/mmp2-brownstone.dts
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 Marvell Technology Group Ltd.
+ * Author: Haojian Zhuang <haojian.zhuang@marvell.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
+ * publishhed by the Free Software Foundation.
+ */
+
+/dts-v1/;
+/include/ "mmp2.dtsi"
+
+/ {
+ model = "Marvell MMP2 Aspenite Development Board";
+ compatible = "mrvl,mmp2-brownstone", "mrvl,mmp2";
+
+ chosen {
+ bootargs = "console=ttyS2,38400 root=/dev/nfs nfsroot=192.168.1.100:/nfsroot/ ip=192.168.1.101:192.168.1.100::255.255.255.0::eth0:on";
+ };
+
+ memory {
+ reg = <0x00000000 0x04000000>;
+ };
+
+ soc {
+ apb@d4000000 {
+ uart3: uart@d4018000 {
+ status = "okay";
+ };
+ twsi1: i2c@d4011000 {
+ status = "okay";
+ };
+ rtc: rtc@d4010000 {
+ status = "okay";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/mmp2.dtsi b/arch/arm/boot/dts/mmp2.dtsi
new file mode 100644
index 000000000000..80f74e256408
--- /dev/null
+++ b/arch/arm/boot/dts/mmp2.dtsi
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2012 Marvell Technology Group Ltd.
+ * Author: Haojian Zhuang <haojian.zhuang@marvell.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
+ * publishhed by the Free Software Foundation.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ aliases {
+ serial0 = &uart1;
+ serial1 = &uart2;
+ serial2 = &uart3;
+ serial3 = &uart4;
+ i2c0 = &twsi1;
+ i2c1 = &twsi2;
+ };
+
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ interrupt-parent = <&intc>;
+ ranges;
+
+ axi@d4200000 { /* AXI */
+ compatible = "mrvl,axi-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xd4200000 0x00200000>;
+ ranges;
+
+ intc: interrupt-controller@d4282000 {
+ compatible = "mrvl,mmp2-intc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0xd4282000 0x1000>;
+ mrvl,intc-nr-irqs = <64>;
+ };
+
+ intcmux4@d4282150 {
+ compatible = "mrvl,mmp2-mux-intc";
+ interrupts = <4>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x150 0x4>, <0x168 0x4>;
+ reg-names = "mux status", "mux mask";
+ mrvl,intc-nr-irqs = <2>;
+ };
+
+ intcmux5: interrupt-controller@d4282154 {
+ compatible = "mrvl,mmp2-mux-intc";
+ interrupts = <5>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x154 0x4>, <0x16c 0x4>;
+ reg-names = "mux status", "mux mask";
+ mrvl,intc-nr-irqs = <2>;
+ mrvl,clr-mfp-irq = <1>;
+ };
+
+ intcmux9: interrupt-controller@d4282180 {
+ compatible = "mrvl,mmp2-mux-intc";
+ interrupts = <9>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x180 0x4>, <0x17c 0x4>;
+ reg-names = "mux status", "mux mask";
+ mrvl,intc-nr-irqs = <3>;
+ };
+
+ intcmux17: interrupt-controller@d4282158 {
+ compatible = "mrvl,mmp2-mux-intc";
+ interrupts = <17>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x158 0x4>, <0x170 0x4>;
+ reg-names = "mux status", "mux mask";
+ mrvl,intc-nr-irqs = <5>;
+ };
+
+ intcmux35: interrupt-controller@d428215c {
+ compatible = "mrvl,mmp2-mux-intc";
+ interrupts = <35>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x15c 0x4>, <0x174 0x4>;
+ reg-names = "mux status", "mux mask";
+ mrvl,intc-nr-irqs = <15>;
+ };
+
+ intcmux51: interrupt-controller@d4282160 {
+ compatible = "mrvl,mmp2-mux-intc";
+ interrupts = <51>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x160 0x4>, <0x178 0x4>;
+ reg-names = "mux status", "mux mask";
+ mrvl,intc-nr-irqs = <2>;
+ };
+
+ intcmux55: interrupt-controller@d4282188 {
+ compatible = "mrvl,mmp2-mux-intc";
+ interrupts = <55>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x188 0x4>, <0x184 0x4>;
+ reg-names = "mux status", "mux mask";
+ mrvl,intc-nr-irqs = <2>;
+ };
+ };
+
+ apb@d4000000 { /* APB */
+ compatible = "mrvl,apb-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xd4000000 0x00200000>;
+ ranges;
+
+ timer0: timer@d4014000 {
+ compatible = "mrvl,mmp-timer";
+ reg = <0xd4014000 0x100>;
+ interrupts = <13>;
+ };
+
+ uart1: uart@d4030000 {
+ compatible = "mrvl,mmp-uart";
+ reg = <0xd4030000 0x1000>;
+ interrupts = <27>;
+ status = "disabled";
+ };
+
+ uart2: uart@d4017000 {
+ compatible = "mrvl,mmp-uart";
+ reg = <0xd4017000 0x1000>;
+ interrupts = <28>;
+ status = "disabled";
+ };
+
+ uart3: uart@d4018000 {
+ compatible = "mrvl,mmp-uart";
+ reg = <0xd4018000 0x1000>;
+ interrupts = <24>;
+ status = "disabled";
+ };
+
+ uart4: uart@d4016000 {
+ compatible = "mrvl,mmp-uart";
+ reg = <0xd4016000 0x1000>;
+ interrupts = <46>;
+ status = "disabled";
+ };
+
+ gpio@d4019000 {
+ compatible = "mrvl,mmp-gpio";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xd4019000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupts = <49>;
+ interrupt-names = "gpio_mux";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ ranges;
+
+ gcb0: gpio@d4019000 {
+ reg = <0xd4019000 0x4>;
+ };
+
+ gcb1: gpio@d4019004 {
+ reg = <0xd4019004 0x4>;
+ };
+
+ gcb2: gpio@d4019008 {
+ reg = <0xd4019008 0x4>;
+ };
+
+ gcb3: gpio@d4019100 {
+ reg = <0xd4019100 0x4>;
+ };
+
+ gcb4: gpio@d4019104 {
+ reg = <0xd4019104 0x4>;
+ };
+
+ gcb5: gpio@d4019108 {
+ reg = <0xd4019108 0x4>;
+ };
+ };
+
+ twsi1: i2c@d4011000 {
+ compatible = "mrvl,mmp-twsi";
+ reg = <0xd4011000 0x1000>;
+ interrupts = <7>;
+ mrvl,i2c-fast-mode;
+ status = "disabled";
+ };
+
+ twsi2: i2c@d4025000 {
+ compatible = "mrvl,mmp-twsi";
+ reg = <0xd4025000 0x1000>;
+ interrupts = <58>;
+ status = "disabled";
+ };
+
+ rtc: rtc@d4010000 {
+ compatible = "mrvl,mmp-rtc";
+ reg = <0xd4010000 0x1000>;
+ interrupts = <1 0>;
+ interrupt-names = "rtc 1Hz", "rtc alarm";
+ interrupt-parent = <&intcmux5>;
+ status = "disabled";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts
index 9f72cd4cf308..8c756be4d7ad 100644
--- a/arch/arm/boot/dts/omap3-beagle.dts
+++ b/arch/arm/boot/dts/omap3-beagle.dts
@@ -18,3 +18,52 @@
reg = <0x80000000 0x20000000>; /* 512 MB */
};
};
+
+&i2c1 {
+ clock-frequency = <2600000>;
+
+ twl: twl@48 {
+ reg = <0x48>;
+ interrupts = <7>; /* SYS_NIRQ cascaded to intc */
+ interrupt-parent = <&intc>;
+
+ vsim: regulator@10 {
+ compatible = "ti,twl4030-vsim";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3000000>;
+ };
+ };
+};
+
+/include/ "twl4030.dtsi"
+
+&i2c2 {
+ clock-frequency = <400000>;
+};
+
+&i2c3 {
+ clock-frequency = <100000>;
+
+ /*
+ * Display monitor features are burnt in the EEPROM
+ * as EDID data.
+ */
+ eeprom@50 {
+ compatible = "ti,eeprom";
+ reg = <0x50>;
+ };
+};
+
+&mmc1 {
+ vmmc-supply = <&vmmc1>;
+ vmmc_aux-supply = <&vsim>;
+ ti,bus-width = <8>;
+};
+
+&mmc2 {
+ status = "disable";
+};
+
+&mmc3 {
+ status = "disable";
+};
diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi
index c6121357c1eb..99474fa5fac4 100644
--- a/arch/arm/boot/dts/omap3.dtsi
+++ b/arch/arm/boot/dts/omap3.dtsi
@@ -69,6 +69,60 @@
reg = <0x48200000 0x1000>;
};
+ gpio1: gpio@48310000 {
+ compatible = "ti,omap3-gpio";
+ ti,hwmods = "gpio1";
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ gpio2: gpio@49050000 {
+ compatible = "ti,omap3-gpio";
+ ti,hwmods = "gpio2";
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ gpio3: gpio@49052000 {
+ compatible = "ti,omap3-gpio";
+ ti,hwmods = "gpio3";
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ gpio4: gpio@49054000 {
+ compatible = "ti,omap3-gpio";
+ ti,hwmods = "gpio4";
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ gpio5: gpio@49056000 {
+ compatible = "ti,omap3-gpio";
+ ti,hwmods = "gpio5";
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ gpio6: gpio@49058000 {
+ compatible = "ti,omap3-gpio";
+ ti,hwmods = "gpio6";
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
uart1: serial@4806a000 {
compatible = "ti,omap3-uart";
ti,hwmods = "uart1";
@@ -113,5 +167,53 @@
#size-cells = <0>;
ti,hwmods = "i2c3";
};
+
+ mcspi1: spi@48098000 {
+ compatible = "ti,omap2-mcspi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ ti,hwmods = "mcspi1";
+ ti,spi-num-cs = <4>;
+ };
+
+ mcspi2: spi@4809a000 {
+ compatible = "ti,omap2-mcspi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ ti,hwmods = "mcspi2";
+ ti,spi-num-cs = <2>;
+ };
+
+ mcspi3: spi@480b8000 {
+ compatible = "ti,omap2-mcspi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ ti,hwmods = "mcspi3";
+ ti,spi-num-cs = <2>;
+ };
+
+ mcspi4: spi@480ba000 {
+ compatible = "ti,omap2-mcspi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ ti,hwmods = "mcspi4";
+ ti,spi-num-cs = <1>;
+ };
+
+ mmc1: mmc@4809c000 {
+ compatible = "ti,omap3-hsmmc";
+ ti,hwmods = "mmc1";
+ ti,dual-volt;
+ };
+
+ mmc2: mmc@480b4000 {
+ compatible = "ti,omap3-hsmmc";
+ ti,hwmods = "mmc2";
+ };
+
+ mmc3: mmc@480ad000 {
+ compatible = "ti,omap3-hsmmc";
+ ti,hwmods = "mmc3";
+ };
};
};
diff --git a/arch/arm/boot/dts/omap4-panda.dts b/arch/arm/boot/dts/omap4-panda.dts
index 9755ad5917f8..e671361bc791 100644
--- a/arch/arm/boot/dts/omap4-panda.dts
+++ b/arch/arm/boot/dts/omap4-panda.dts
@@ -17,4 +17,75 @@
device_type = "memory";
reg = <0x80000000 0x40000000>; /* 1 GB */
};
+
+ leds {
+ compatible = "gpio-leds";
+ heartbeat {
+ label = "pandaboard::status1";
+ gpios = <&gpio1 7 0>;
+ linux,default-trigger = "heartbeat";
+ };
+
+ mmc {
+ label = "pandaboard::status2";
+ gpios = <&gpio1 8 0>;
+ linux,default-trigger = "mmc0";
+ };
+ };
+};
+
+&i2c1 {
+ clock-frequency = <400000>;
+
+ twl: twl@48 {
+ reg = <0x48>;
+ /* SPI = 0, IRQ# = 7, 4 = active high level-sensitive */
+ interrupts = <0 7 4>; /* IRQ_SYS_1N cascaded to gic */
+ interrupt-parent = <&gic>;
+ };
+};
+
+/include/ "twl6030.dtsi"
+
+&i2c2 {
+ clock-frequency = <400000>;
+};
+
+&i2c3 {
+ clock-frequency = <100000>;
+
+ /*
+ * Display monitor features are burnt in their EEPROM as EDID data.
+ * The EEPROM is connected as I2C slave device.
+ */
+ eeprom@50 {
+ compatible = "ti,eeprom";
+ reg = <0x50>;
+ };
+};
+
+&i2c4 {
+ clock-frequency = <400000>;
+};
+
+&mmc1 {
+ vmmc-supply = <&vmmc>;
+ ti,bus-width = <8>;
+};
+
+&mmc2 {
+ status = "disable";
+};
+
+&mmc3 {
+ status = "disable";
+};
+
+&mmc4 {
+ status = "disable";
+};
+
+&mmc5 {
+ ti,non-removable;
+ ti,bus-width = <4>;
};
diff --git a/arch/arm/boot/dts/omap4-sdp.dts b/arch/arm/boot/dts/omap4-sdp.dts
index 63c6b2b2bf42..e5eeb6f9c6e6 100644
--- a/arch/arm/boot/dts/omap4-sdp.dts
+++ b/arch/arm/boot/dts/omap4-sdp.dts
@@ -17,4 +17,144 @@
device_type = "memory";
reg = <0x80000000 0x40000000>; /* 1 GB */
};
+
+ vdd_eth: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "VDD_ETH";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio2 16 0>; /* gpio line 48 */
+ enable-active-high;
+ regulator-boot-on;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ debug0 {
+ label = "omap4:green:debug0";
+ gpios = <&gpio2 29 0>; /* 61 */
+ };
+
+ debug1 {
+ label = "omap4:green:debug1";
+ gpios = <&gpio1 30 0>; /* 30 */
+ };
+
+ debug2 {
+ label = "omap4:green:debug2";
+ gpios = <&gpio1 7 0>; /* 7 */
+ };
+
+ debug3 {
+ label = "omap4:green:debug3";
+ gpios = <&gpio1 8 0>; /* 8 */
+ };
+
+ debug4 {
+ label = "omap4:green:debug4";
+ gpios = <&gpio2 18 0>; /* 50 */
+ };
+
+ user1 {
+ label = "omap4:blue:user";
+ gpios = <&gpio6 9 0>; /* 169 */
+ };
+
+ user2 {
+ label = "omap4:red:user";
+ gpios = <&gpio6 10 0>; /* 170 */
+ };
+
+ user3 {
+ label = "omap4:green:user";
+ gpios = <&gpio5 11 0>; /* 139 */
+ };
+ };
+};
+
+&i2c1 {
+ clock-frequency = <400000>;
+
+ twl: twl@48 {
+ reg = <0x48>;
+ /* SPI = 0, IRQ# = 7, 4 = active high level-sensitive */
+ interrupts = <0 7 4>; /* IRQ_SYS_1N cascaded to gic */
+ interrupt-parent = <&gic>;
+ };
+};
+
+/include/ "twl6030.dtsi"
+
+&i2c2 {
+ clock-frequency = <400000>;
+};
+
+&i2c3 {
+ clock-frequency = <400000>;
+
+ /*
+ * Temperature Sensor
+ * http://www.ti.com/lit/ds/symlink/tmp105.pdf
+ */
+ tmp105@48 {
+ compatible = "ti,tmp105";
+ reg = <0x48>;
+ };
+
+ /*
+ * Ambient Light Sensor
+ * http://www.rohm.com/products/databook/sensor/pdf/bh1780gli-e.pdf
+ */
+ bh1780@29 {
+ compatible = "rohm,bh1780";
+ reg = <0x29>;
+ };
+};
+
+&i2c4 {
+ clock-frequency = <400000>;
+
+ /*
+ * 3-Axis Digital Compass
+ * http://www.sparkfun.com/datasheets/Sensors/Magneto/HMC5843.pdf
+ */
+ hmc5843@1e {
+ compatible = "honeywell,hmc5843";
+ reg = <0x1e>;
+ };
+};
+
+&mcspi1 {
+ eth@0 {
+ compatible = "ks8851";
+ spi-max-frequency = <24000000>;
+ reg = <0>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <2>; /* gpio line 34 */
+ vdd-supply = <&vdd_eth>;
+ };
+};
+
+&mmc1 {
+ vmmc-supply = <&vmmc>;
+ ti,bus-width = <8>;
+};
+
+&mmc2 {
+ vmmc-supply = <&vaux1>;
+ ti,bus-width = <8>;
+ ti,non-removable;
+};
+
+&mmc3 {
+ status = "disable";
+};
+
+&mmc4 {
+ status = "disable";
+};
+
+&mmc5 {
+ ti,bus-width = <4>;
+ ti,non-removable;
};
diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi
index 3d35559e77bc..359c4979c8aa 100644
--- a/arch/arm/boot/dts/omap4.dtsi
+++ b/arch/arm/boot/dts/omap4.dtsi
@@ -104,6 +104,60 @@
<0x48240100 0x0100>;
};
+ gpio1: gpio@4a310000 {
+ compatible = "ti,omap4-gpio";
+ ti,hwmods = "gpio1";
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ gpio2: gpio@48055000 {
+ compatible = "ti,omap4-gpio";
+ ti,hwmods = "gpio2";
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ gpio3: gpio@48057000 {
+ compatible = "ti,omap4-gpio";
+ ti,hwmods = "gpio3";
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ gpio4: gpio@48059000 {
+ compatible = "ti,omap4-gpio";
+ ti,hwmods = "gpio4";
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ gpio5: gpio@4805b000 {
+ compatible = "ti,omap4-gpio";
+ ti,hwmods = "gpio5";
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ gpio6: gpio@4805d000 {
+ compatible = "ti,omap4-gpio";
+ ti,hwmods = "gpio6";
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
uart1: serial@4806a000 {
compatible = "ti,omap4-uart";
ti,hwmods = "uart1";
@@ -155,5 +209,68 @@
#size-cells = <0>;
ti,hwmods = "i2c4";
};
+
+ mcspi1: spi@48098000 {
+ compatible = "ti,omap4-mcspi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ ti,hwmods = "mcspi1";
+ ti,spi-num-cs = <4>;
+ };
+
+ mcspi2: spi@4809a000 {
+ compatible = "ti,omap4-mcspi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ ti,hwmods = "mcspi2";
+ ti,spi-num-cs = <2>;
+ };
+
+ mcspi3: spi@480b8000 {
+ compatible = "ti,omap4-mcspi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ ti,hwmods = "mcspi3";
+ ti,spi-num-cs = <2>;
+ };
+
+ mcspi4: spi@480ba000 {
+ compatible = "ti,omap4-mcspi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ ti,hwmods = "mcspi4";
+ ti,spi-num-cs = <1>;
+ };
+
+ mmc1: mmc@4809c000 {
+ compatible = "ti,omap4-hsmmc";
+ ti,hwmods = "mmc1";
+ ti,dual-volt;
+ ti,needs-special-reset;
+ };
+
+ mmc2: mmc@480b4000 {
+ compatible = "ti,omap4-hsmmc";
+ ti,hwmods = "mmc2";
+ ti,needs-special-reset;
+ };
+
+ mmc3: mmc@480ad000 {
+ compatible = "ti,omap4-hsmmc";
+ ti,hwmods = "mmc3";
+ ti,needs-special-reset;
+ };
+
+ mmc4: mmc@480d1000 {
+ compatible = "ti,omap4-hsmmc";
+ ti,hwmods = "mmc4";
+ ti,needs-special-reset;
+ };
+
+ mmc5: mmc@480d5000 {
+ compatible = "ti,omap4-hsmmc";
+ ti,hwmods = "mmc5";
+ ti,needs-special-reset;
+ };
};
};
diff --git a/arch/arm/boot/dts/phy3250.dts b/arch/arm/boot/dts/phy3250.dts
new file mode 100644
index 000000000000..0167e86314c0
--- /dev/null
+++ b/arch/arm/boot/dts/phy3250.dts
@@ -0,0 +1,145 @@
+/*
+ * PHYTEC phyCORE-LPC3250 board
+ *
+ * Copyright 2012 Roland Stigge <stigge@antcom.de>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "lpc32xx.dtsi"
+
+/ {
+ model = "PHYTEC phyCORE-LPC3250 board based on NXP LPC3250";
+ compatible = "phytec,phy3250", "nxp,lpc3250";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ memory {
+ device_type = "memory";
+ reg = <0 0x4000000>;
+ };
+
+ ahb {
+ mac: ethernet@31060000 {
+ phy-mode = "rmii";
+ use-iram;
+ };
+
+ /* Here, choose exactly one from: ohci, usbd */
+ ohci@31020000 {
+ transceiver = <&isp1301>;
+ status = "okay";
+ };
+
+/*
+ usbd@31020000 {
+ transceiver = <&isp1301>;
+ status = "okay";
+ };
+*/
+
+ clcd@31040000 {
+ status = "okay";
+ };
+
+ /* 64MB Flash via SLC NAND controller */
+ slc: flash@20020000 {
+ status = "okay";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ mtd0@00000000 {
+ label = "phy3250-boot";
+ reg = <0x00000000 0x00064000>;
+ read-only;
+ };
+
+ mtd1@00064000 {
+ label = "phy3250-uboot";
+ reg = <0x00064000 0x00190000>;
+ read-only;
+ };
+
+ mtd2@001f4000 {
+ label = "phy3250-ubt-prms";
+ reg = <0x001f4000 0x00010000>;
+ };
+
+ mtd3@00204000 {
+ label = "phy3250-kernel";
+ reg = <0x00204000 0x00400000>;
+ };
+
+ mtd4@00604000 {
+ label = "phy3250-rootfs";
+ reg = <0x00604000 0x039fc000>;
+ };
+ };
+
+ apb {
+ i2c1: i2c@400A0000 {
+ clock-frequency = <100000>;
+
+ pcf8563: rtc@51 {
+ compatible = "nxp,pcf8563";
+ reg = <0x51>;
+ };
+
+ uda1380: uda1380@18 {
+ compatible = "nxp,uda1380";
+ reg = <0x18>;
+ power-gpio = <&gpio 0x59 0>;
+ reset-gpio = <&gpio 0x51 0>;
+ dac-clk = "wspll";
+ };
+ };
+
+ i2c2: i2c@400A8000 {
+ clock-frequency = <100000>;
+ };
+
+ i2cusb: i2c@31020300 {
+ clock-frequency = <100000>;
+
+ isp1301: usb-transceiver@2c {
+ compatible = "nxp,isp1301";
+ reg = <0x2c>;
+ };
+ };
+
+ ssp0: ssp@20084000 {
+ eeprom: at25@0 {
+ compatible = "atmel,at25";
+ };
+ };
+ };
+
+ fab {
+ tsc@40048000 {
+ status = "okay";
+ };
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ led0 {
+ gpios = <&gpo_p3 1 1>; /* GPO_P3 1, GPIO 80, active low */
+ linux,default-trigger = "heartbeat";
+ default-state = "off";
+ };
+
+ led1 {
+ gpios = <&gpo_p3 14 1>; /* GPO_P3 14, GPIO 93, active low */
+ linux,default-trigger = "timer";
+ default-state = "off";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/pxa168.dtsi b/arch/arm/boot/dts/pxa168.dtsi
index d32d5128f225..31a718696080 100644
--- a/arch/arm/boot/dts/pxa168.dtsi
+++ b/arch/arm/boot/dts/pxa168.dtsi
@@ -18,13 +18,6 @@
i2c1 = &twsi2;
};
- intc: intc-interrupt-controller@d4282000 {
- compatible = "mrvl,mmp-intc", "mrvl,intc";
- interrupt-controller;
- #interrupt-cells = <1>;
- reg = <0xd4282000 0x1000>;
- };
-
soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -32,6 +25,23 @@
interrupt-parent = <&intc>;
ranges;
+ axi@d4200000 { /* AXI */
+ compatible = "mrvl,axi-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xd4200000 0x00200000>;
+ ranges;
+
+ intc: interrupt-controller@d4282000 {
+ compatible = "mrvl,mmp-intc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0xd4282000 0x1000>;
+ mrvl,intc-nr-irqs = <64>;
+ };
+
+ };
+
apb@d4000000 { /* APB */
compatible = "mrvl,apb-bus", "simple-bus";
#address-cells = <1>;
@@ -39,40 +49,65 @@
reg = <0xd4000000 0x00200000>;
ranges;
+ timer0: timer@d4014000 {
+ compatible = "mrvl,mmp-timer";
+ reg = <0xd4014000 0x100>;
+ interrupts = <13>;
+ };
+
uart1: uart@d4017000 {
- compatible = "mrvl,mmp-uart", "mrvl,pxa-uart";
+ compatible = "mrvl,mmp-uart";
reg = <0xd4017000 0x1000>;
interrupts = <27>;
status = "disabled";
};
uart2: uart@d4018000 {
- compatible = "mrvl,mmp-uart", "mrvl,pxa-uart";
+ compatible = "mrvl,mmp-uart";
reg = <0xd4018000 0x1000>;
interrupts = <28>;
status = "disabled";
};
uart3: uart@d4026000 {
- compatible = "mrvl,mmp-uart", "mrvl,pxa-uart";
+ compatible = "mrvl,mmp-uart";
reg = <0xd4026000 0x1000>;
interrupts = <29>;
status = "disabled";
};
- gpio: gpio@d4019000 {
- compatible = "mrvl,mmp-gpio", "mrvl,pxa-gpio";
+ gpio@d4019000 {
+ compatible = "mrvl,mmp-gpio";
+ #address-cells = <1>;
+ #size-cells = <1>;
reg = <0xd4019000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
interrupts = <49>;
interrupt-names = "gpio_mux";
- gpio-controller;
- #gpio-cells = <1>;
interrupt-controller;
#interrupt-cells = <1>;
+ ranges;
+
+ gcb0: gpio@d4019000 {
+ reg = <0xd4019000 0x4>;
+ };
+
+ gcb1: gpio@d4019004 {
+ reg = <0xd4019004 0x4>;
+ };
+
+ gcb2: gpio@d4019008 {
+ reg = <0xd4019008 0x4>;
+ };
+
+ gcb3: gpio@d4019100 {
+ reg = <0xd4019100 0x4>;
+ };
};
twsi1: i2c@d4011000 {
- compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c";
+ compatible = "mrvl,mmp-twsi";
reg = <0xd4011000 0x1000>;
interrupts = <7>;
mrvl,i2c-fast-mode;
@@ -80,7 +115,7 @@
};
twsi2: i2c@d4025000 {
- compatible = "mrvl,mmp-twsi", "mrvl,pxa-i2c";
+ compatible = "mrvl,mmp-twsi";
reg = <0xd4025000 0x1000>;
interrupts = <58>;
status = "disabled";
diff --git a/arch/arm/boot/dts/pxa910-dkb.dts b/arch/arm/boot/dts/pxa910-dkb.dts
new file mode 100644
index 000000000000..e92be5a474e7
--- /dev/null
+++ b/arch/arm/boot/dts/pxa910-dkb.dts
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 Marvell Technology Group Ltd.
+ * Author: Haojian Zhuang <haojian.zhuang@marvell.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
+ * publishhed by the Free Software Foundation.
+ */
+
+/dts-v1/;
+/include/ "pxa910.dtsi"
+
+/ {
+ model = "Marvell PXA910 DKB Development Board";
+ compatible = "mrvl,pxa910-dkb", "mrvl,pxa910";
+
+ chosen {
+ bootargs = "console=ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.100:/nfsroot/ ip=192.168.1.101:192.168.1.100::255.255.255.0::eth0:on";
+ };
+
+ memory {
+ reg = <0x00000000 0x10000000>;
+ };
+
+ soc {
+ apb@d4000000 {
+ uart1: uart@d4017000 {
+ status = "okay";
+ };
+ twsi1: i2c@d4011000 {
+ status = "okay";
+ };
+ rtc: rtc@d4010000 {
+ status = "okay";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/pxa910.dtsi b/arch/arm/boot/dts/pxa910.dtsi
new file mode 100644
index 000000000000..aebf32de73b4
--- /dev/null
+++ b/arch/arm/boot/dts/pxa910.dtsi
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2012 Marvell Technology Group Ltd.
+ * Author: Haojian Zhuang <haojian.zhuang@marvell.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
+ * publishhed by the Free Software Foundation.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ aliases {
+ serial0 = &uart1;
+ serial1 = &uart2;
+ serial2 = &uart3;
+ i2c0 = &twsi1;
+ i2c1 = &twsi2;
+ };
+
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ interrupt-parent = <&intc>;
+ ranges;
+
+ axi@d4200000 { /* AXI */
+ compatible = "mrvl,axi-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xd4200000 0x00200000>;
+ ranges;
+
+ intc: interrupt-controller@d4282000 {
+ compatible = "mrvl,mmp-intc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0xd4282000 0x1000>;
+ mrvl,intc-nr-irqs = <64>;
+ };
+
+ };
+
+ apb@d4000000 { /* APB */
+ compatible = "mrvl,apb-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xd4000000 0x00200000>;
+ ranges;
+
+ timer0: timer@d4014000 {
+ compatible = "mrvl,mmp-timer";
+ reg = <0xd4014000 0x100>;
+ interrupts = <13>;
+ };
+
+ timer1: timer@d4016000 {
+ compatible = "mrvl,mmp-timer";
+ reg = <0xd4016000 0x100>;
+ interrupts = <29>;
+ status = "disabled";
+ };
+
+ uart1: uart@d4017000 {
+ compatible = "mrvl,mmp-uart";
+ reg = <0xd4017000 0x1000>;
+ interrupts = <27>;
+ status = "disabled";
+ };
+
+ uart2: uart@d4018000 {
+ compatible = "mrvl,mmp-uart";
+ reg = <0xd4018000 0x1000>;
+ interrupts = <28>;
+ status = "disabled";
+ };
+
+ uart3: uart@d4036000 {
+ compatible = "mrvl,mmp-uart";
+ reg = <0xd4036000 0x1000>;
+ interrupts = <59>;
+ status = "disabled";
+ };
+
+ gpio@d4019000 {
+ compatible = "mrvl,mmp-gpio";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xd4019000 0x1000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupts = <49>;
+ interrupt-names = "gpio_mux";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ ranges;
+
+ gcb0: gpio@d4019000 {
+ reg = <0xd4019000 0x4>;
+ };
+
+ gcb1: gpio@d4019004 {
+ reg = <0xd4019004 0x4>;
+ };
+
+ gcb2: gpio@d4019008 {
+ reg = <0xd4019008 0x4>;
+ };
+
+ gcb3: gpio@d4019100 {
+ reg = <0xd4019100 0x4>;
+ };
+ };
+
+ twsi1: i2c@d4011000 {
+ compatible = "mrvl,mmp-twsi";
+ reg = <0xd4011000 0x1000>;
+ interrupts = <7>;
+ mrvl,i2c-fast-mode;
+ status = "disabled";
+ };
+
+ twsi2: i2c@d4037000 {
+ compatible = "mrvl,mmp-twsi";
+ reg = <0xd4037000 0x1000>;
+ interrupts = <54>;
+ status = "disabled";
+ };
+
+ rtc: rtc@d4010000 {
+ compatible = "mrvl,mmp-rtc";
+ reg = <0xd4010000 0x1000>;
+ interrupts = <5 6>;
+ interrupt-names = "rtc 1Hz", "rtc alarm";
+ status = "disabled";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/r8a7740-armadillo800eva.dts b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
new file mode 100644
index 000000000000..a7505a95a3b7
--- /dev/null
+++ b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
@@ -0,0 +1,22 @@
+/*
+ * Device Tree Source for the armadillo 800 eva board
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/dts-v1/;
+/include/ "skeleton.dtsi"
+
+/ {
+ model = "armadillo 800 eva";
+ compatible = "renesas,armadillo800eva";
+
+ memory {
+ device_type = "memory";
+ reg = <0x40000000 0x20000000>;
+ };
+};
diff --git a/arch/arm/boot/dts/sh7372.dtsi b/arch/arm/boot/dts/sh7372.dtsi
new file mode 100644
index 000000000000..677fc603f8b3
--- /dev/null
+++ b/arch/arm/boot/dts/sh7372.dtsi
@@ -0,0 +1,21 @@
+/*
+ * Device Tree Source for the sh7372 SoC
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ compatible = "renesas,sh7372";
+
+ cpus {
+ cpu@0 {
+ compatible = "arm,cortex-a8";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/sh73a0-kzm9g.dts b/arch/arm/boot/dts/sh73a0-kzm9g.dts
new file mode 100644
index 000000000000..bcb911951978
--- /dev/null
+++ b/arch/arm/boot/dts/sh73a0-kzm9g.dts
@@ -0,0 +1,22 @@
+/*
+ * Device Tree Source for the KZM-A9-GT board
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/dts-v1/;
+/include/ "skeleton.dtsi"
+
+/ {
+ model = "KZM-A9-GT";
+ compatible = "renesas,kzm9g", "renesas,sh73a0";
+
+ memory {
+ device_type = "memory";
+ reg = <0x41000000 0x1e800000>;
+ };
+};
diff --git a/arch/arm/boot/dts/snowball.dts b/arch/arm/boot/dts/snowball.dts
index 359c6d679156..d99dc04f0d91 100644
--- a/arch/arm/boot/dts/snowball.dts
+++ b/arch/arm/boot/dts/snowball.dts
@@ -30,35 +30,35 @@
wakeup = <1>;
linux,code = <2>;
label = "userpb";
- gpios = <&gpio1 0>;
+ gpios = <&gpio1 0 0>;
};
button@2 {
debounce_interval = <50>;
wakeup = <1>;
linux,code = <3>;
- label = "userpb";
- gpios = <&gpio4 23>;
+ label = "extkb1";
+ gpios = <&gpio4 23 0>;
};
button@3 {
debounce_interval = <50>;
wakeup = <1>;
linux,code = <4>;
- label = "userpb";
- gpios = <&gpio4 23>;
+ label = "extkb2";
+ gpios = <&gpio4 24 0>;
};
button@4 {
debounce_interval = <50>;
wakeup = <1>;
linux,code = <5>;
- label = "userpb";
- gpios = <&gpio5 1>;
+ label = "extkb3";
+ gpios = <&gpio5 1 0>;
};
button@5 {
debounce_interval = <50>;
wakeup = <1>;
linux,code = <6>;
- label = "userpb";
- gpios = <&gpio5 2>;
+ label = "extkb4";
+ gpios = <&gpio5 2 0>;
};
};
@@ -73,17 +73,19 @@
soc-u9500 {
external-bus@50000000 {
- compatible = "simple-bus";
- reg = <0x50000000 0x10000000>;
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- ethernet@50000000 {
- compatible = "smsc,9111";
- reg = <0x50000000 0x10000>;
- interrupts = <12>;
+ status = "okay";
+
+ ethernet@0 {
+ compatible = "smsc,lan9115";
+ reg = <0 0x10000>;
+ interrupts = <12 0x1>;
interrupt-parent = <&gpio4>;
+
+ reg-shift = <1>;
+ reg-io-width = <2>;
+ smsc,force-internal-phy;
+ smsc,irq-active-high;
+ smsc,irq-push-pull;
};
};
diff --git a/arch/arm/boot/dts/spear300-evb.dts b/arch/arm/boot/dts/spear300-evb.dts
new file mode 100644
index 000000000000..910e264b87c0
--- /dev/null
+++ b/arch/arm/boot/dts/spear300-evb.dts
@@ -0,0 +1,221 @@
+/*
+ * DTS file for SPEAr300 Evaluation Baord
+ *
+ * Copyright 2012 Viresh Kumar <viresh.kumar@st.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "spear300.dtsi"
+
+/ {
+ model = "ST SPEAr300 Evaluation Board";
+ compatible = "st,spear300-evb", "st,spear300";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ memory {
+ reg = <0 0x40000000>;
+ };
+
+ ahb {
+ pinmux@99000000 {
+ st,pinmux-mode = <2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&state_default>;
+
+ state_default: pinmux {
+ i2c0 {
+ st,pins = "i2c0_grp";
+ st,function = "i2c0";
+ };
+ ssp0 {
+ st,pins = "ssp0_grp";
+ st,function = "ssp0";
+ };
+ mii0 {
+ st,pins = "mii0_grp";
+ st,function = "mii0";
+ };
+ uart0 {
+ st,pins = "uart0_grp";
+ st,function = "uart0";
+ };
+ clcd {
+ st,pins = "clcd_pfmode_grp";
+ st,function = "clcd";
+ };
+ sdhci {
+ st,pins = "sdhci_4bit_grp";
+ st,function = "sdhci";
+ };
+ gpio1 {
+ st,pins = "gpio1_4_to_7_grp",
+ "gpio1_0_to_3_grp";
+ st,function = "gpio1";
+ };
+ };
+ };
+
+ clcd@60000000 {
+ status = "okay";
+ };
+
+ dma@fc400000 {
+ status = "okay";
+ };
+
+ fsmc: flash@94000000 {
+ status = "okay";
+ };
+
+ gmac: eth@e0800000 {
+ status = "okay";
+ };
+
+ sdhci@70000000 {
+ int-gpio = <&gpio1 0 0>;
+ power-gpio = <&gpio1 2 1>;
+ status = "okay";
+ };
+
+ smi: flash@fc000000 {
+ status = "okay";
+ };
+
+ spi0: spi@d0100000 {
+ status = "okay";
+ };
+
+ ehci@e1800000 {
+ status = "okay";
+ };
+
+ ohci@e1900000 {
+ status = "okay";
+ };
+
+ ohci@e2100000 {
+ status = "okay";
+ };
+
+ apb {
+ gpio0: gpio@fc980000 {
+ status = "okay";
+ };
+
+ gpio1: gpio@a9000000 {
+ status = "okay";
+ };
+
+ i2c0: i2c@d0180000 {
+ status = "okay";
+ };
+
+ kbd@a0000000 {
+ linux,keymap = < 0x00000001
+ 0x00010002
+ 0x00020003
+ 0x00030004
+ 0x00040005
+ 0x00050006
+ 0x00060007
+ 0x00070008
+ 0x00080009
+ 0x0100000a
+ 0x0101000c
+ 0x0102000d
+ 0x0103000e
+ 0x0104000f
+ 0x01050010
+ 0x01060011
+ 0x01070012
+ 0x01080013
+ 0x02000014
+ 0x02010015
+ 0x02020016
+ 0x02030017
+ 0x02040018
+ 0x02050019
+ 0x0206001a
+ 0x0207001b
+ 0x0208001c
+ 0x0300001d
+ 0x0301001e
+ 0x0302001f
+ 0x03030020
+ 0x03040021
+ 0x03050022
+ 0x03060023
+ 0x03070024
+ 0x03080025
+ 0x04000026
+ 0x04010027
+ 0x04020028
+ 0x04030029
+ 0x0404002a
+ 0x0405002b
+ 0x0406002c
+ 0x0407002d
+ 0x0408002e
+ 0x0500002f
+ 0x05010030
+ 0x05020031
+ 0x05030032
+ 0x05040033
+ 0x05050034
+ 0x05060035
+ 0x05070036
+ 0x05080037
+ 0x06000038
+ 0x06010039
+ 0x0602003a
+ 0x0603003b
+ 0x0604003c
+ 0x0605003d
+ 0x0606003e
+ 0x0607003f
+ 0x06080040
+ 0x07000041
+ 0x07010042
+ 0x07020043
+ 0x07030044
+ 0x07040045
+ 0x07050046
+ 0x07060047
+ 0x07070048
+ 0x07080049
+ 0x0800004a
+ 0x0801004b
+ 0x0802004c
+ 0x0803004d
+ 0x0804004e
+ 0x0805004f
+ 0x08060050
+ 0x08070051
+ 0x08080052 >;
+ autorepeat;
+ st,mode = <0>;
+ status = "okay";
+ };
+
+ rtc@fc900000 {
+ status = "okay";
+ };
+
+ serial@d0000000 {
+ status = "okay";
+ };
+
+ wdt@fc880000 {
+ status = "okay";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/spear300.dtsi b/arch/arm/boot/dts/spear300.dtsi
new file mode 100644
index 000000000000..01c5e358fdb2
--- /dev/null
+++ b/arch/arm/boot/dts/spear300.dtsi
@@ -0,0 +1,77 @@
+/*
+ * DTS file for SPEAr300 SoC
+ *
+ * Copyright 2012 Viresh Kumar <viresh.kumar@st.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/include/ "spear3xx.dtsi"
+
+/ {
+ ahb {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <0x60000000 0x60000000 0x50000000
+ 0xd0000000 0xd0000000 0x30000000>;
+
+ pinmux@99000000 {
+ compatible = "st,spear300-pinmux";
+ reg = <0x99000000 0x1000>;
+ };
+
+ clcd@60000000 {
+ compatible = "arm,clcd-pl110", "arm,primecell";
+ reg = <0x60000000 0x1000>;
+ interrupts = <30>;
+ status = "disabled";
+ };
+
+ fsmc: flash@94000000 {
+ compatible = "st,spear600-fsmc-nand";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x94000000 0x1000 /* FSMC Register */
+ 0x80000000 0x0010>; /* NAND Base */
+ reg-names = "fsmc_regs", "nand_data";
+ st,ale-off = <0x20000>;
+ st,cle-off = <0x10000>;
+ status = "disabled";
+ };
+
+ sdhci@70000000 {
+ compatible = "st,sdhci-spear";
+ reg = <0x70000000 0x100>;
+ interrupts = <1>;
+ status = "disabled";
+ };
+
+ apb {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <0xa0000000 0xa0000000 0x10000000
+ 0xd0000000 0xd0000000 0x30000000>;
+
+ gpio1: gpio@a9000000 {
+ #gpio-cells = <2>;
+ compatible = "arm,pl061", "arm,primecell";
+ gpio-controller;
+ reg = <0xa9000000 0x1000>;
+ status = "disabled";
+ };
+
+ kbd@a0000000 {
+ compatible = "st,spear300-kbd";
+ reg = <0xa0000000 0x1000>;
+ status = "disabled";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/spear310-evb.dts b/arch/arm/boot/dts/spear310-evb.dts
new file mode 100644
index 000000000000..6d95317100ad
--- /dev/null
+++ b/arch/arm/boot/dts/spear310-evb.dts
@@ -0,0 +1,172 @@
+/*
+ * DTS file for SPEAr310 Evaluation Baord
+ *
+ * Copyright 2012 Viresh Kumar <viresh.kumar@st.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "spear310.dtsi"
+
+/ {
+ model = "ST SPEAr310 Evaluation Board";
+ compatible = "st,spear310-evb", "st,spear310";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ memory {
+ reg = <0 0x40000000>;
+ };
+
+ ahb {
+ pinmux@b4000000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&state_default>;
+
+ state_default: pinmux {
+ gpio0 {
+ st,pins = "gpio0_pin0_grp",
+ "gpio0_pin1_grp",
+ "gpio0_pin2_grp",
+ "gpio0_pin3_grp",
+ "gpio0_pin4_grp",
+ "gpio0_pin5_grp";
+ st,function = "gpio0";
+ };
+ i2c0 {
+ st,pins = "i2c0_grp";
+ st,function = "i2c0";
+ };
+ mii0 {
+ st,pins = "mii0_grp";
+ st,function = "mii0";
+ };
+ ssp0 {
+ st,pins = "ssp0_grp";
+ st,function = "ssp0";
+ };
+ uart0 {
+ st,pins = "uart0_grp";
+ st,function = "uart0";
+ };
+ emi {
+ st,pins = "emi_cs_0_to_5_grp";
+ st,function = "emi";
+ };
+ fsmc {
+ st,pins = "fsmc_grp";
+ st,function = "fsmc";
+ };
+ uart1 {
+ st,pins = "uart1_grp";
+ st,function = "uart1";
+ };
+ uart2 {
+ st,pins = "uart2_grp";
+ st,function = "uart2";
+ };
+ uart3 {
+ st,pins = "uart3_grp";
+ st,function = "uart3";
+ };
+ uart4 {
+ st,pins = "uart4_grp";
+ st,function = "uart4";
+ };
+ uart5 {
+ st,pins = "uart5_grp";
+ st,function = "uart5";
+ };
+ };
+ };
+
+ dma@fc400000 {
+ status = "okay";
+ };
+
+ fsmc: flash@44000000 {
+ status = "okay";
+ };
+
+ gmac: eth@e0800000 {
+ status = "okay";
+ };
+
+ smi: flash@fc000000 {
+ status = "okay";
+ clock-rate=<50000000>;
+
+ flash@f8000000 {
+ label = "m25p64";
+ reg = <0xf8000000 0x800000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ st,smi-fast-mode;
+ };
+ };
+
+ spi0: spi@d0100000 {
+ status = "okay";
+ };
+
+ ehci@e1800000 {
+ status = "okay";
+ };
+
+ ohci@e1900000 {
+ status = "okay";
+ };
+
+ ohci@e2100000 {
+ status = "okay";
+ };
+
+ apb {
+ gpio0: gpio@fc980000 {
+ status = "okay";
+ };
+
+ i2c0: i2c@d0180000 {
+ status = "okay";
+ };
+
+ rtc@fc900000 {
+ status = "okay";
+ };
+
+ serial@d0000000 {
+ status = "okay";
+ };
+
+ serial@b2000000 {
+ status = "okay";
+ };
+
+ serial@b2080000 {
+ status = "okay";
+ };
+
+ serial@b2100000 {
+ status = "okay";
+ };
+
+ serial@b2180000 {
+ status = "okay";
+ };
+
+ serial@b2200000 {
+ status = "okay";
+ };
+
+ wdt@fc880000 {
+ status = "okay";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/spear310.dtsi b/arch/arm/boot/dts/spear310.dtsi
new file mode 100644
index 000000000000..e47081c494d9
--- /dev/null
+++ b/arch/arm/boot/dts/spear310.dtsi
@@ -0,0 +1,80 @@
+/*
+ * DTS file for SPEAr310 SoC
+ *
+ * Copyright 2012 Viresh Kumar <viresh.kumar@st.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/include/ "spear3xx.dtsi"
+
+/ {
+ ahb {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <0x40000000 0x40000000 0x10000000
+ 0xb0000000 0xb0000000 0x10000000
+ 0xd0000000 0xd0000000 0x30000000>;
+
+ pinmux@b4000000 {
+ compatible = "st,spear310-pinmux";
+ reg = <0xb4000000 0x1000>;
+ };
+
+ fsmc: flash@44000000 {
+ compatible = "st,spear600-fsmc-nand";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x44000000 0x1000 /* FSMC Register */
+ 0x40000000 0x0010>; /* NAND Base */
+ reg-names = "fsmc_regs", "nand_data";
+ st,ale-off = <0x10000>;
+ st,cle-off = <0x20000>;
+ status = "disabled";
+ };
+
+ apb {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <0xb0000000 0xb0000000 0x10000000
+ 0xd0000000 0xd0000000 0x30000000>;
+
+ serial@b2000000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0xb2000000 0x1000>;
+ status = "disabled";
+ };
+
+ serial@b2080000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0xb2080000 0x1000>;
+ status = "disabled";
+ };
+
+ serial@b2100000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0xb2100000 0x1000>;
+ status = "disabled";
+ };
+
+ serial@b2180000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0xb2180000 0x1000>;
+ status = "disabled";
+ };
+
+ serial@b2200000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0xb2200000 0x1000>;
+ status = "disabled";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/spear320-evb.dts b/arch/arm/boot/dts/spear320-evb.dts
new file mode 100644
index 000000000000..0c6463b71a37
--- /dev/null
+++ b/arch/arm/boot/dts/spear320-evb.dts
@@ -0,0 +1,173 @@
+/*
+ * DTS file for SPEAr320 Evaluation Baord
+ *
+ * Copyright 2012 Viresh Kumar <viresh.kumar@st.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "spear320.dtsi"
+
+/ {
+ model = "ST SPEAr300 Evaluation Board";
+ compatible = "st,spear300-evb", "st,spear300";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ memory {
+ reg = <0 0x40000000>;
+ };
+
+ ahb {
+ pinmux@b3000000 {
+ st,pinmux-mode = <3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&state_default>;
+
+ state_default: pinmux {
+ i2c0 {
+ st,pins = "i2c0_grp";
+ st,function = "i2c0";
+ };
+ mii0 {
+ st,pins = "mii0_grp";
+ st,function = "mii0";
+ };
+ ssp0 {
+ st,pins = "ssp0_grp";
+ st,function = "ssp0";
+ };
+ uart0 {
+ st,pins = "uart0_grp";
+ st,function = "uart0";
+ };
+ sdhci {
+ st,pins = "sdhci_cd_51_grp";
+ st,function = "sdhci";
+ };
+ i2s {
+ st,pins = "i2s_grp";
+ st,function = "i2s";
+ };
+ uart1 {
+ st,pins = "uart1_grp";
+ st,function = "uart1";
+ };
+ uart2 {
+ st,pins = "uart2_grp";
+ st,function = "uart2";
+ };
+ can0 {
+ st,pins = "can0_grp";
+ st,function = "can0";
+ };
+ can1 {
+ st,pins = "can1_grp";
+ st,function = "can1";
+ };
+ mii2 {
+ st,pins = "mii2_grp";
+ st,function = "mii2";
+ };
+ pwm0_1 {
+ st,pins = "pwm0_1_pin_14_15_grp";
+ st,function = "pwm0_1";
+ };
+ pwm2 {
+ st,pins = "pwm2_pin_13_grp";
+ st,function = "pwm2";
+ };
+ };
+ };
+
+ clcd@90000000 {
+ status = "okay";
+ };
+
+ dma@fc400000 {
+ status = "okay";
+ };
+
+ fsmc: flash@4c000000 {
+ status = "okay";
+ };
+
+ gmac: eth@e0800000 {
+ status = "okay";
+ };
+
+ sdhci@70000000 {
+ power-gpio = <&gpio0 2 1>;
+ power_always_enb;
+ status = "okay";
+ };
+
+ smi: flash@fc000000 {
+ status = "okay";
+ };
+
+ spi0: spi@d0100000 {
+ status = "okay";
+ };
+
+ spi1: spi@a5000000 {
+ status = "okay";
+ };
+
+ spi2: spi@a6000000 {
+ status = "okay";
+ };
+
+ ehci@e1800000 {
+ status = "okay";
+ };
+
+ ohci@e1900000 {
+ status = "okay";
+ };
+
+ ohci@e2100000 {
+ status = "okay";
+ };
+
+ apb {
+ gpio0: gpio@fc980000 {
+ status = "okay";
+ };
+
+ i2c0: i2c@d0180000 {
+ status = "okay";
+ };
+
+ i2c1: i2c@a7000000 {
+ status = "okay";
+ };
+
+ rtc@fc900000 {
+ status = "okay";
+ };
+
+ serial@d0000000 {
+ status = "okay";
+ };
+
+ serial@a3000000 {
+ status = "okay";
+ };
+
+ serial@a4000000 {
+ status = "okay";
+ };
+
+ wdt@fc880000 {
+ status = "okay";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/spear320.dtsi b/arch/arm/boot/dts/spear320.dtsi
new file mode 100644
index 000000000000..5372ca399b1f
--- /dev/null
+++ b/arch/arm/boot/dts/spear320.dtsi
@@ -0,0 +1,95 @@
+/*
+ * DTS file for SPEAr320 SoC
+ *
+ * Copyright 2012 Viresh Kumar <viresh.kumar@st.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/include/ "spear3xx.dtsi"
+
+/ {
+ ahb {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <0x40000000 0x40000000 0x80000000
+ 0xd0000000 0xd0000000 0x30000000>;
+
+ pinmux@b3000000 {
+ compatible = "st,spear320-pinmux";
+ reg = <0xb3000000 0x1000>;
+ };
+
+ clcd@90000000 {
+ compatible = "arm,clcd-pl110", "arm,primecell";
+ reg = <0x90000000 0x1000>;
+ interrupts = <33>;
+ status = "disabled";
+ };
+
+ fsmc: flash@4c000000 {
+ compatible = "st,spear600-fsmc-nand";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x4c000000 0x1000 /* FSMC Register */
+ 0x50000000 0x0010>; /* NAND Base */
+ reg-names = "fsmc_regs", "nand_data";
+ st,ale-off = <0x20000>;
+ st,cle-off = <0x10000>;
+ status = "disabled";
+ };
+
+ sdhci@70000000 {
+ compatible = "st,sdhci-spear";
+ reg = <0x70000000 0x100>;
+ interrupts = <29>;
+ status = "disabled";
+ };
+
+ spi1: spi@a5000000 {
+ compatible = "arm,pl022", "arm,primecell";
+ reg = <0xa5000000 0x1000>;
+ status = "disabled";
+ };
+
+ spi2: spi@a6000000 {
+ compatible = "arm,pl022", "arm,primecell";
+ reg = <0xa6000000 0x1000>;
+ status = "disabled";
+ };
+
+ apb {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <0xa0000000 0xa0000000 0x10000000
+ 0xd0000000 0xd0000000 0x30000000>;
+
+ i2c1: i2c@a7000000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0xa7000000 0x1000>;
+ status = "disabled";
+ };
+
+ serial@a3000000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0xa3000000 0x1000>;
+ status = "disabled";
+ };
+
+ serial@a4000000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0xa4000000 0x1000>;
+ status = "disabled";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/spear3xx.dtsi b/arch/arm/boot/dts/spear3xx.dtsi
new file mode 100644
index 000000000000..0ae7c8e86311
--- /dev/null
+++ b/arch/arm/boot/dts/spear3xx.dtsi
@@ -0,0 +1,144 @@
+/*
+ * DTS file for all SPEAr3xx SoCs
+ *
+ * Copyright 2012 Viresh Kumar <viresh.kumar@st.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+ interrupt-parent = <&vic>;
+
+ cpus {
+ cpu@0 {
+ compatible = "arm,arm926ejs";
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0 0x40000000>;
+ };
+
+ ahb {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <0xd0000000 0xd0000000 0x30000000>;
+
+ vic: interrupt-controller@f1100000 {
+ compatible = "arm,pl190-vic";
+ interrupt-controller;
+ reg = <0xf1100000 0x1000>;
+ #interrupt-cells = <1>;
+ };
+
+ dma@fc400000 {
+ compatible = "arm,pl080", "arm,primecell";
+ reg = <0xfc400000 0x1000>;
+ interrupt-parent = <&vic>;
+ interrupts = <8>;
+ status = "disabled";
+ };
+
+ gmac: eth@e0800000 {
+ compatible = "st,spear600-gmac";
+ reg = <0xe0800000 0x8000>;
+ interrupts = <23 22>;
+ interrupt-names = "macirq", "eth_wake_irq";
+ status = "disabled";
+ };
+
+ smi: flash@fc000000 {
+ compatible = "st,spear600-smi";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xfc000000 0x1000>;
+ interrupts = <9>;
+ status = "disabled";
+ };
+
+ spi0: spi@d0100000 {
+ compatible = "arm,pl022", "arm,primecell";
+ reg = <0xd0100000 0x1000>;
+ interrupts = <20>;
+ status = "disabled";
+ };
+
+ ehci@e1800000 {
+ compatible = "st,spear600-ehci", "usb-ehci";
+ reg = <0xe1800000 0x1000>;
+ interrupts = <26>;
+ status = "disabled";
+ };
+
+ ohci@e1900000 {
+ compatible = "st,spear600-ohci", "usb-ohci";
+ reg = <0xe1900000 0x1000>;
+ interrupts = <25>;
+ status = "disabled";
+ };
+
+ ohci@e2100000 {
+ compatible = "st,spear600-ohci", "usb-ohci";
+ reg = <0xe2100000 0x1000>;
+ interrupts = <27>;
+ status = "disabled";
+ };
+
+ apb {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges = <0xd0000000 0xd0000000 0x30000000>;
+
+ gpio0: gpio@fc980000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xfc980000 0x1000>;
+ interrupts = <11>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ status = "disabled";
+ };
+
+ i2c0: i2c@d0180000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0xd0180000 0x1000>;
+ interrupts = <21>;
+ status = "disabled";
+ };
+
+ rtc@fc900000 {
+ compatible = "st,spear-rtc";
+ reg = <0xfc900000 0x1000>;
+ interrupts = <10>;
+ status = "disabled";
+ };
+
+ serial@d0000000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0xd0000000 0x1000>;
+ interrupts = <19>;
+ status = "disabled";
+ };
+
+ wdt@fc880000 {
+ compatible = "arm,sp805", "arm,primecell";
+ reg = <0xfc880000 0x1000>;
+ interrupts = <12>;
+ status = "disabled";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/spear600-evb.dts b/arch/arm/boot/dts/spear600-evb.dts
index 636292e18c90..790a7a8a5ccd 100644
--- a/arch/arm/boot/dts/spear600-evb.dts
+++ b/arch/arm/boot/dts/spear600-evb.dts
@@ -24,6 +24,10 @@
};
ahb {
+ dma@fc400000 {
+ status = "okay";
+ };
+
gmac: ethernet@e0800000 {
phy-mode = "gmii";
status = "okay";
diff --git a/arch/arm/boot/dts/spear600.dtsi b/arch/arm/boot/dts/spear600.dtsi
index ebe0885a2b98..d777e3a6f178 100644
--- a/arch/arm/boot/dts/spear600.dtsi
+++ b/arch/arm/boot/dts/spear600.dtsi
@@ -45,6 +45,14 @@
#interrupt-cells = <1>;
};
+ dma@fc400000 {
+ compatible = "arm,pl080", "arm,primecell";
+ reg = <0xfc400000 0x1000>;
+ interrupt-parent = <&vic1>;
+ interrupts = <10>;
+ status = "disabled";
+ };
+
gmac: ethernet@e0800000 {
compatible = "st,spear600-gmac";
reg = <0xe0800000 0x8000>;
diff --git a/arch/arm/boot/dts/tegra-cardhu.dts b/arch/arm/boot/dts/tegra-cardhu.dts
index ac3fb7558459..0a9f34a2c3aa 100644
--- a/arch/arm/boot/dts/tegra-cardhu.dts
+++ b/arch/arm/boot/dts/tegra-cardhu.dts
@@ -10,6 +10,50 @@
reg = < 0x80000000 0x40000000 >;
};
+ pinmux@70000000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&state_default>;
+
+ state_default: pinmux {
+ sdmmc1_clk_pz0 {
+ nvidia,pins = "sdmmc1_clk_pz0";
+ nvidia,function = "sdmmc1";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ sdmmc1_cmd_pz1 {
+ nvidia,pins = "sdmmc1_cmd_pz1",
+ "sdmmc1_dat0_py7",
+ "sdmmc1_dat1_py6",
+ "sdmmc1_dat2_py5",
+ "sdmmc1_dat3_py4";
+ nvidia,function = "sdmmc1";
+ nvidia,pull = <2>;
+ nvidia,tristate = <0>;
+ };
+ sdmmc4_clk_pcc4 {
+ nvidia,pins = "sdmmc4_clk_pcc4",
+ "sdmmc4_rst_n_pcc3";
+ nvidia,function = "sdmmc4";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ sdmmc4_dat0_paa0 {
+ nvidia,pins = "sdmmc4_dat0_paa0",
+ "sdmmc4_dat1_paa1",
+ "sdmmc4_dat2_paa2",
+ "sdmmc4_dat3_paa3",
+ "sdmmc4_dat4_paa4",
+ "sdmmc4_dat5_paa5",
+ "sdmmc4_dat6_paa6",
+ "sdmmc4_dat7_paa7";
+ nvidia,function = "sdmmc4";
+ nvidia,pull = <2>;
+ nvidia,tristate = <0>;
+ };
+ };
+ };
+
serial@70006000 {
clock-frequency = < 408000000 >;
};
diff --git a/arch/arm/boot/dts/tegra-harmony.dts b/arch/arm/boot/dts/tegra-harmony.dts
index 6e8447dc0202..1a0b1f182944 100644
--- a/arch/arm/boot/dts/tegra-harmony.dts
+++ b/arch/arm/boot/dts/tegra-harmony.dts
@@ -10,6 +10,230 @@
reg = < 0x00000000 0x40000000 >;
};
+ pinmux@70000000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&state_default>;
+
+ state_default: pinmux {
+ ata {
+ nvidia,pins = "ata";
+ nvidia,function = "ide";
+ };
+ atb {
+ nvidia,pins = "atb", "gma", "gme";
+ nvidia,function = "sdio4";
+ };
+ atc {
+ nvidia,pins = "atc";
+ nvidia,function = "nand";
+ };
+ atd {
+ nvidia,pins = "atd", "ate", "gmb", "gmd", "gpu",
+ "spia", "spib", "spic";
+ nvidia,function = "gmi";
+ };
+ cdev1 {
+ nvidia,pins = "cdev1";
+ nvidia,function = "plla_out";
+ };
+ cdev2 {
+ nvidia,pins = "cdev2";
+ nvidia,function = "pllp_out4";
+ };
+ crtp {
+ nvidia,pins = "crtp";
+ nvidia,function = "crt";
+ };
+ csus {
+ nvidia,pins = "csus";
+ nvidia,function = "vi_sensor_clk";
+ };
+ dap1 {
+ nvidia,pins = "dap1";
+ nvidia,function = "dap1";
+ };
+ dap2 {
+ nvidia,pins = "dap2";
+ nvidia,function = "dap2";
+ };
+ dap3 {
+ nvidia,pins = "dap3";
+ nvidia,function = "dap3";
+ };
+ dap4 {
+ nvidia,pins = "dap4";
+ nvidia,function = "dap4";
+ };
+ ddc {
+ nvidia,pins = "ddc";
+ nvidia,function = "i2c2";
+ };
+ dta {
+ nvidia,pins = "dta", "dtd";
+ nvidia,function = "sdio2";
+ };
+ dtb {
+ nvidia,pins = "dtb", "dtc", "dte";
+ nvidia,function = "rsvd1";
+ };
+ dtf {
+ nvidia,pins = "dtf";
+ nvidia,function = "i2c3";
+ };
+ gmc {
+ nvidia,pins = "gmc";
+ nvidia,function = "uartd";
+ };
+ gpu7 {
+ nvidia,pins = "gpu7";
+ nvidia,function = "rtck";
+ };
+ gpv {
+ nvidia,pins = "gpv", "slxa", "slxk";
+ nvidia,function = "pcie";
+ };
+ hdint {
+ nvidia,pins = "hdint", "pta";
+ nvidia,function = "hdmi";
+ };
+ i2cp {
+ nvidia,pins = "i2cp";
+ nvidia,function = "i2cp";
+ };
+ irrx {
+ nvidia,pins = "irrx", "irtx";
+ nvidia,function = "uarta";
+ };
+ kbca {
+ nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
+ "kbce", "kbcf";
+ nvidia,function = "kbc";
+ };
+ lcsn {
+ nvidia,pins = "lcsn", "ld0", "ld1", "ld2",
+ "ld3", "ld4", "ld5", "ld6", "ld7",
+ "ld8", "ld9", "ld10", "ld11", "ld12",
+ "ld13", "ld14", "ld15", "ld16", "ld17",
+ "ldc", "ldi", "lhp0", "lhp1", "lhp2",
+ "lhs", "lm0", "lm1", "lpp", "lpw0",
+ "lpw1", "lpw2", "lsc0", "lsc1", "lsck",
+ "lsda", "lsdi", "lspi", "lvp0", "lvp1",
+ "lvs";
+ nvidia,function = "displaya";
+ };
+ owc {
+ nvidia,pins = "owc", "spdi", "spdo", "uac";
+ nvidia,function = "rsvd2";
+ };
+ pmc {
+ nvidia,pins = "pmc";
+ nvidia,function = "pwr_on";
+ };
+ rm {
+ nvidia,pins = "rm";
+ nvidia,function = "i2c1";
+ };
+ sdb {
+ nvidia,pins = "sdb", "sdc", "sdd";
+ nvidia,function = "pwm";
+ };
+ sdio1 {
+ nvidia,pins = "sdio1";
+ nvidia,function = "sdio1";
+ };
+ slxc {
+ nvidia,pins = "slxc", "slxd";
+ nvidia,function = "spdif";
+ };
+ spid {
+ nvidia,pins = "spid", "spie", "spif";
+ nvidia,function = "spi1";
+ };
+ spig {
+ nvidia,pins = "spig", "spih";
+ nvidia,function = "spi2_alt";
+ };
+ uaa {
+ nvidia,pins = "uaa", "uab", "uda";
+ nvidia,function = "ulpi";
+ };
+ uad {
+ nvidia,pins = "uad";
+ nvidia,function = "irda";
+ };
+ uca {
+ nvidia,pins = "uca", "ucb";
+ nvidia,function = "uartc";
+ };
+ conf_ata {
+ nvidia,pins = "ata", "atb", "atc", "atd", "ate",
+ "cdev1", "dap1", "dtb", "gma", "gmb",
+ "gmc", "gmd", "gme", "gpu7", "gpv",
+ "i2cp", "pta", "rm", "slxa", "slxk",
+ "spia", "spib";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ conf_cdev2 {
+ nvidia,pins = "cdev2", "csus", "spid", "spif";
+ nvidia,pull = <1>;
+ nvidia,tristate = <1>;
+ };
+ conf_ck32 {
+ nvidia,pins = "ck32", "ddrc", "pmca", "pmcb",
+ "pmcc", "pmcd", "pmce", "xm2c", "xm2d";
+ nvidia,pull = <0>;
+ };
+ conf_crtp {
+ nvidia,pins = "crtp", "dap2", "dap3", "dap4",
+ "dtc", "dte", "dtf", "gpu", "sdio1",
+ "slxc", "slxd", "spdi", "spdo", "spig",
+ "uac", "uda";
+ nvidia,pull = <0>;
+ nvidia,tristate = <1>;
+ };
+ conf_ddc {
+ nvidia,pins = "ddc", "dta", "dtd", "kbca",
+ "kbcb", "kbcc", "kbcd", "kbce", "kbcf",
+ "sdc";
+ nvidia,pull = <2>;
+ nvidia,tristate = <0>;
+ };
+ conf_hdint {
+ nvidia,pins = "hdint", "lcsn", "ldc", "lm1",
+ "lpw1", "lsc1", "lsck", "lsda", "lsdi",
+ "lvp0", "owc", "sdb";
+ nvidia,tristate = <1>;
+ };
+ conf_irrx {
+ nvidia,pins = "irrx", "irtx", "sdd", "spic",
+ "spie", "spih", "uaa", "uab", "uad",
+ "uca", "ucb";
+ nvidia,pull = <2>;
+ nvidia,tristate = <1>;
+ };
+ conf_lc {
+ nvidia,pins = "lc", "ls";
+ nvidia,pull = <2>;
+ };
+ conf_ld0 {
+ nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
+ "ld5", "ld6", "ld7", "ld8", "ld9",
+ "ld10", "ld11", "ld12", "ld13", "ld14",
+ "ld15", "ld16", "ld17", "ldi", "lhp0",
+ "lhp1", "lhp2", "lhs", "lm0", "lpp",
+ "lpw0", "lpw2", "lsc0", "lspi", "lvp1",
+ "lvs", "pmc";
+ nvidia,tristate = <0>;
+ };
+ conf_ld17_0 {
+ nvidia,pins = "ld17_0", "ld19_18", "ld21_20",
+ "ld23_22";
+ nvidia,pull = <1>;
+ };
+ };
+ };
+
pmc@7000f400 {
nvidia,invert-interrupt;
};
diff --git a/arch/arm/boot/dts/tegra-paz00.dts b/arch/arm/boot/dts/tegra-paz00.dts
index 6c02abb469d4..10943fb2561c 100644
--- a/arch/arm/boot/dts/tegra-paz00.dts
+++ b/arch/arm/boot/dts/tegra-paz00.dts
@@ -10,6 +10,226 @@
reg = <0x00000000 0x20000000>;
};
+ pinmux@70000000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&state_default>;
+
+ state_default: pinmux {
+ ata {
+ nvidia,pins = "ata", "atc", "atd", "ate",
+ "dap2", "gmb", "gmc", "gmd", "spia",
+ "spib", "spic", "spid", "spie";
+ nvidia,function = "gmi";
+ };
+ atb {
+ nvidia,pins = "atb", "gma", "gme";
+ nvidia,function = "sdio4";
+ };
+ cdev1 {
+ nvidia,pins = "cdev1";
+ nvidia,function = "plla_out";
+ };
+ cdev2 {
+ nvidia,pins = "cdev2";
+ nvidia,function = "pllp_out4";
+ };
+ crtp {
+ nvidia,pins = "crtp";
+ nvidia,function = "crt";
+ };
+ csus {
+ nvidia,pins = "csus";
+ nvidia,function = "pllc_out1";
+ };
+ dap1 {
+ nvidia,pins = "dap1";
+ nvidia,function = "dap1";
+ };
+ dap3 {
+ nvidia,pins = "dap3";
+ nvidia,function = "dap3";
+ };
+ dap4 {
+ nvidia,pins = "dap4";
+ nvidia,function = "dap4";
+ };
+ ddc {
+ nvidia,pins = "ddc";
+ nvidia,function = "i2c2";
+ };
+ dta {
+ nvidia,pins = "dta", "dtb", "dtc", "dtd", "dte";
+ nvidia,function = "rsvd1";
+ };
+ dtf {
+ nvidia,pins = "dtf";
+ nvidia,function = "i2c3";
+ };
+ gpu {
+ nvidia,pins = "gpu", "sdb", "sdd";
+ nvidia,function = "pwm";
+ };
+ gpu7 {
+ nvidia,pins = "gpu7";
+ nvidia,function = "rtck";
+ };
+ gpv {
+ nvidia,pins = "gpv", "slxa", "slxk";
+ nvidia,function = "pcie";
+ };
+ hdint {
+ nvidia,pins = "hdint", "pta";
+ nvidia,function = "hdmi";
+ };
+ i2cp {
+ nvidia,pins = "i2cp";
+ nvidia,function = "i2cp";
+ };
+ irrx {
+ nvidia,pins = "irrx", "irtx";
+ nvidia,function = "uarta";
+ };
+ kbca {
+ nvidia,pins = "kbca", "kbcc", "kbce", "kbcf";
+ nvidia,function = "kbc";
+ };
+ kbcb {
+ nvidia,pins = "kbcb", "kbcd";
+ nvidia,function = "sdio2";
+ };
+ lcsn {
+ nvidia,pins = "lcsn", "ld0", "ld1", "ld2",
+ "ld3", "ld4", "ld5", "ld6", "ld7",
+ "ld8", "ld9", "ld10", "ld11", "ld12",
+ "ld13", "ld14", "ld15", "ld16", "ld17",
+ "ldc", "ldi", "lhp0", "lhp1", "lhp2",
+ "lhs", "lm0", "lm1", "lpp", "lpw0",
+ "lpw1", "lpw2", "lsc0", "lsc1", "lsck",
+ "lsda", "lsdi", "lspi", "lvp0", "lvp1",
+ "lvs";
+ nvidia,function = "displaya";
+ };
+ owc {
+ nvidia,pins = "owc";
+ nvidia,function = "owr";
+ };
+ pmc {
+ nvidia,pins = "pmc";
+ nvidia,function = "pwr_on";
+ };
+ rm {
+ nvidia,pins = "rm";
+ nvidia,function = "i2c1";
+ };
+ sdc {
+ nvidia,pins = "sdc";
+ nvidia,function = "twc";
+ };
+ sdio1 {
+ nvidia,pins = "sdio1";
+ nvidia,function = "sdio1";
+ };
+ slxc {
+ nvidia,pins = "slxc", "slxd";
+ nvidia,function = "spi4";
+ };
+ spdi {
+ nvidia,pins = "spdi", "spdo";
+ nvidia,function = "rsvd2";
+ };
+ spif {
+ nvidia,pins = "spif", "uac";
+ nvidia,function = "rsvd4";
+ };
+ spig {
+ nvidia,pins = "spig", "spih";
+ nvidia,function = "spi2_alt";
+ };
+ uaa {
+ nvidia,pins = "uaa", "uab", "uda";
+ nvidia,function = "ulpi";
+ };
+ uad {
+ nvidia,pins = "uad";
+ nvidia,function = "spdif";
+ };
+ uca {
+ nvidia,pins = "uca", "ucb";
+ nvidia,function = "uartc";
+ };
+ conf_ata {
+ nvidia,pins = "ata", "atb", "atc", "atd", "ate",
+ "cdev1", "dap1", "dap2", "dtf", "gma",
+ "gmb", "gmc", "gmd", "gme", "gpu",
+ "gpu7", "gpv", "i2cp", "pta", "rm",
+ "sdio1", "slxk", "spdo", "uac", "uda";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ conf_cdev2 {
+ nvidia,pins = "cdev2";
+ nvidia,pull = <1>;
+ nvidia,tristate = <0>;
+ };
+ conf_ck32 {
+ nvidia,pins = "ck32", "ddrc", "pmca", "pmcb",
+ "pmcc", "pmcd", "pmce", "xm2c", "xm2d";
+ nvidia,pull = <0>;
+ };
+ conf_crtp {
+ nvidia,pins = "crtp", "dap3", "dap4", "dtb",
+ "dtc", "dte", "slxa", "slxc", "slxd",
+ "spdi";
+ nvidia,pull = <0>;
+ nvidia,tristate = <1>;
+ };
+ conf_csus {
+ nvidia,pins = "csus", "spia", "spib", "spid",
+ "spif";
+ nvidia,pull = <1>;
+ nvidia,tristate = <1>;
+ };
+ conf_ddc {
+ nvidia,pins = "ddc", "irrx", "irtx", "kbca",
+ "kbcb", "kbcc", "kbcd", "kbce", "kbcf",
+ "spic", "spig", "uaa", "uab";
+ nvidia,pull = <2>;
+ nvidia,tristate = <0>;
+ };
+ conf_dta {
+ nvidia,pins = "dta", "dtd", "owc", "sdc", "sdd",
+ "spie", "spih", "uad", "uca", "ucb";
+ nvidia,pull = <2>;
+ nvidia,tristate = <1>;
+ };
+ conf_hdint {
+ nvidia,pins = "hdint", "ld0", "ld1", "ld2",
+ "ld3", "ld4", "ld5", "ld6", "ld7",
+ "ld8", "ld9", "ld10", "ld11", "ld12",
+ "ld13", "ld14", "ld15", "ld16", "ld17",
+ "ldc", "ldi", "lhs", "lsc0", "lspi",
+ "lvs", "pmc";
+ nvidia,tristate = <0>;
+ };
+ conf_lc {
+ nvidia,pins = "lc", "ls";
+ nvidia,pull = <2>;
+ };
+ conf_lcsn {
+ nvidia,pins = "lcsn", "lhp0", "lhp1", "lhp2",
+ "lm0", "lm1", "lpp", "lpw0", "lpw1",
+ "lpw2", "lsc1", "lsck", "lsda", "lsdi",
+ "lvp0", "lvp1", "sdb";
+ nvidia,tristate = <1>;
+ };
+ conf_ld17_0 {
+ nvidia,pins = "ld17_0", "ld19_18", "ld21_20",
+ "ld23_22";
+ nvidia,pull = <1>;
+ };
+ };
+ };
+
i2c@7000c000 {
clock-frequency = <400000>;
diff --git a/arch/arm/boot/dts/tegra-seaboard.dts b/arch/arm/boot/dts/tegra-seaboard.dts
index dbf1c5a171c2..ec33116f5df9 100644
--- a/arch/arm/boot/dts/tegra-seaboard.dts
+++ b/arch/arm/boot/dts/tegra-seaboard.dts
@@ -11,6 +11,249 @@
reg = < 0x00000000 0x40000000 >;
};
+ pinmux@70000000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&state_default>;
+
+ state_default: pinmux {
+ ata {
+ nvidia,pins = "ata";
+ nvidia,function = "ide";
+ };
+ atb {
+ nvidia,pins = "atb", "gma", "gme";
+ nvidia,function = "sdio4";
+ };
+ atc {
+ nvidia,pins = "atc";
+ nvidia,function = "nand";
+ };
+ atd {
+ nvidia,pins = "atd", "ate", "gmb", "spia",
+ "spib", "spic";
+ nvidia,function = "gmi";
+ };
+ cdev1 {
+ nvidia,pins = "cdev1";
+ nvidia,function = "plla_out";
+ };
+ cdev2 {
+ nvidia,pins = "cdev2";
+ nvidia,function = "pllp_out4";
+ };
+ crtp {
+ nvidia,pins = "crtp", "lm1";
+ nvidia,function = "crt";
+ };
+ csus {
+ nvidia,pins = "csus";
+ nvidia,function = "vi_sensor_clk";
+ };
+ dap1 {
+ nvidia,pins = "dap1";
+ nvidia,function = "dap1";
+ };
+ dap2 {
+ nvidia,pins = "dap2";
+ nvidia,function = "dap2";
+ };
+ dap3 {
+ nvidia,pins = "dap3";
+ nvidia,function = "dap3";
+ };
+ dap4 {
+ nvidia,pins = "dap4";
+ nvidia,function = "dap4";
+ };
+ ddc {
+ nvidia,pins = "ddc", "owc", "spdi", "spdo",
+ "uac";
+ nvidia,function = "rsvd2";
+ };
+ dta {
+ nvidia,pins = "dta", "dtb", "dtc", "dtd", "dte";
+ nvidia,function = "vi";
+ };
+ dtf {
+ nvidia,pins = "dtf";
+ nvidia,function = "i2c3";
+ };
+ gmc {
+ nvidia,pins = "gmc";
+ nvidia,function = "uartd";
+ };
+ gmd {
+ nvidia,pins = "gmd";
+ nvidia,function = "sflash";
+ };
+ gpu {
+ nvidia,pins = "gpu";
+ nvidia,function = "pwm";
+ };
+ gpu7 {
+ nvidia,pins = "gpu7";
+ nvidia,function = "rtck";
+ };
+ gpv {
+ nvidia,pins = "gpv", "slxa", "slxk";
+ nvidia,function = "pcie";
+ };
+ hdint {
+ nvidia,pins = "hdint", "lpw0", "lpw2", "lsc1",
+ "lsck", "lsda", "pta";
+ nvidia,function = "hdmi";
+ };
+ i2cp {
+ nvidia,pins = "i2cp";
+ nvidia,function = "i2cp";
+ };
+ irrx {
+ nvidia,pins = "irrx", "irtx";
+ nvidia,function = "uartb";
+ };
+ kbca {
+ nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
+ "kbce", "kbcf";
+ nvidia,function = "kbc";
+ };
+ lcsn {
+ nvidia,pins = "lcsn", "ldc", "lm0", "lpw1",
+ "lsdi", "lvp0";
+ nvidia,function = "rsvd4";
+ };
+ ld0 {
+ nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
+ "ld5", "ld6", "ld7", "ld8", "ld9",
+ "ld10", "ld11", "ld12", "ld13", "ld14",
+ "ld15", "ld16", "ld17", "ldi", "lhp0",
+ "lhp1", "lhp2", "lhs", "lpp", "lsc0",
+ "lspi", "lvp1", "lvs";
+ nvidia,function = "displaya";
+ };
+ pmc {
+ nvidia,pins = "pmc";
+ nvidia,function = "pwr_on";
+ };
+ rm {
+ nvidia,pins = "rm";
+ nvidia,function = "i2c1";
+ };
+ sdb {
+ nvidia,pins = "sdb", "sdc", "sdd";
+ nvidia,function = "sdio3";
+ };
+ sdio1 {
+ nvidia,pins = "sdio1";
+ nvidia,function = "sdio1";
+ };
+ slxc {
+ nvidia,pins = "slxc", "slxd";
+ nvidia,function = "spdif";
+ };
+ spid {
+ nvidia,pins = "spid", "spie", "spif";
+ nvidia,function = "spi1";
+ };
+ spig {
+ nvidia,pins = "spig", "spih";
+ nvidia,function = "spi2_alt";
+ };
+ uaa {
+ nvidia,pins = "uaa", "uab", "uda";
+ nvidia,function = "ulpi";
+ };
+ uad {
+ nvidia,pins = "uad";
+ nvidia,function = "irda";
+ };
+ uca {
+ nvidia,pins = "uca", "ucb";
+ nvidia,function = "uartc";
+ };
+ conf_ata {
+ nvidia,pins = "ata", "atb", "atc", "atd",
+ "cdev1", "cdev2", "dap1", "dap2",
+ "dap4", "dtf", "gma", "gmc", "gmd",
+ "gme", "gpu", "gpu7", "i2cp", "irrx",
+ "irtx", "pta", "rm", "sdc", "sdd",
+ "slxd", "slxk", "spdi", "spdo", "uac",
+ "uad", "uca", "ucb", "uda";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ conf_ate {
+ nvidia,pins = "ate", "csus", "dap3", "ddc",
+ "gpv", "owc", "slxc", "spib", "spid",
+ "spie";
+ nvidia,pull = <0>;
+ nvidia,tristate = <1>;
+ };
+ conf_ck32 {
+ nvidia,pins = "ck32", "ddrc", "pmca", "pmcb",
+ "pmcc", "pmcd", "pmce", "xm2c", "xm2d";
+ nvidia,pull = <0>;
+ };
+ conf_crtp {
+ nvidia,pins = "crtp", "gmb", "slxa", "spia",
+ "spig", "spih";
+ nvidia,pull = <2>;
+ nvidia,tristate = <1>;
+ };
+ conf_dta {
+ nvidia,pins = "dta", "dtb", "dtc", "dtd";
+ nvidia,pull = <1>;
+ nvidia,tristate = <0>;
+ };
+ conf_dte {
+ nvidia,pins = "dte", "spif";
+ nvidia,pull = <1>;
+ nvidia,tristate = <1>;
+ };
+ conf_hdint {
+ nvidia,pins = "hdint", "lcsn", "ldc", "lm1",
+ "lpw1", "lsc1", "lsck", "lsda", "lsdi",
+ "lvp0";
+ nvidia,tristate = <1>;
+ };
+ conf_kbca {
+ nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
+ "kbce", "kbcf", "sdio1", "spic", "uaa",
+ "uab";
+ nvidia,pull = <2>;
+ nvidia,tristate = <0>;
+ };
+ conf_lc {
+ nvidia,pins = "lc", "ls";
+ nvidia,pull = <2>;
+ };
+ conf_ld0 {
+ nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
+ "ld5", "ld6", "ld7", "ld8", "ld9",
+ "ld10", "ld11", "ld12", "ld13", "ld14",
+ "ld15", "ld16", "ld17", "ldi", "lhp0",
+ "lhp1", "lhp2", "lhs", "lm0", "lpp",
+ "lpw0", "lpw2", "lsc0", "lspi", "lvp1",
+ "lvs", "pmc", "sdb";
+ nvidia,tristate = <0>;
+ };
+ conf_ld17_0 {
+ nvidia,pins = "ld17_0", "ld19_18", "ld21_20",
+ "ld23_22";
+ nvidia,pull = <1>;
+ };
+ drive_sdio1 {
+ nvidia,pins = "drive_sdio1";
+ nvidia,high-speed-mode = <0>;
+ nvidia,schmitt = <0>;
+ nvidia,low-power-mode = <3>;
+ nvidia,pull-down-strength = <31>;
+ nvidia,pull-up-strength = <31>;
+ nvidia,slew-rate-rising = <3>;
+ nvidia,slew-rate-falling = <3>;
+ };
+ };
+ };
+
i2c@7000c000 {
clock-frequency = <400000>;
diff --git a/arch/arm/boot/dts/tegra-trimslice.dts b/arch/arm/boot/dts/tegra-trimslice.dts
index 252476867b54..98efd5b0d7f9 100644
--- a/arch/arm/boot/dts/tegra-trimslice.dts
+++ b/arch/arm/boot/dts/tegra-trimslice.dts
@@ -10,6 +10,236 @@
reg = < 0x00000000 0x40000000 >;
};
+ pinmux@70000000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&state_default>;
+
+ state_default: pinmux {
+ ata {
+ nvidia,pins = "ata";
+ nvidia,function = "ide";
+ };
+ atb {
+ nvidia,pins = "atb", "gma";
+ nvidia,function = "sdio4";
+ };
+ atc {
+ nvidia,pins = "atc", "gmb";
+ nvidia,function = "nand";
+ };
+ atd {
+ nvidia,pins = "atd", "ate", "gme", "pta";
+ nvidia,function = "gmi";
+ };
+ cdev1 {
+ nvidia,pins = "cdev1";
+ nvidia,function = "plla_out";
+ };
+ cdev2 {
+ nvidia,pins = "cdev2";
+ nvidia,function = "pllp_out4";
+ };
+ crtp {
+ nvidia,pins = "crtp";
+ nvidia,function = "crt";
+ };
+ csus {
+ nvidia,pins = "csus";
+ nvidia,function = "vi_sensor_clk";
+ };
+ dap1 {
+ nvidia,pins = "dap1";
+ nvidia,function = "dap1";
+ };
+ dap2 {
+ nvidia,pins = "dap2";
+ nvidia,function = "dap2";
+ };
+ dap3 {
+ nvidia,pins = "dap3";
+ nvidia,function = "dap3";
+ };
+ dap4 {
+ nvidia,pins = "dap4";
+ nvidia,function = "dap4";
+ };
+ ddc {
+ nvidia,pins = "ddc";
+ nvidia,function = "i2c2";
+ };
+ dta {
+ nvidia,pins = "dta", "dtb", "dtc", "dtd", "dte";
+ nvidia,function = "vi";
+ };
+ dtf {
+ nvidia,pins = "dtf";
+ nvidia,function = "i2c3";
+ };
+ gmc {
+ nvidia,pins = "gmc", "gmd";
+ nvidia,function = "sflash";
+ };
+ gpu {
+ nvidia,pins = "gpu";
+ nvidia,function = "uarta";
+ };
+ gpu7 {
+ nvidia,pins = "gpu7";
+ nvidia,function = "rtck";
+ };
+ gpv {
+ nvidia,pins = "gpv", "slxa", "slxk";
+ nvidia,function = "pcie";
+ };
+ hdint {
+ nvidia,pins = "hdint";
+ nvidia,function = "hdmi";
+ };
+ i2cp {
+ nvidia,pins = "i2cp";
+ nvidia,function = "i2cp";
+ };
+ irrx {
+ nvidia,pins = "irrx", "irtx";
+ nvidia,function = "uartb";
+ };
+ kbca {
+ nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
+ "kbce", "kbcf";
+ nvidia,function = "kbc";
+ };
+ lcsn {
+ nvidia,pins = "lcsn", "ld0", "ld1", "ld2",
+ "ld3", "ld4", "ld5", "ld6", "ld7",
+ "ld8", "ld9", "ld10", "ld11", "ld12",
+ "ld13", "ld14", "ld15", "ld16", "ld17",
+ "ldc", "ldi", "lhp0", "lhp1", "lhp2",
+ "lhs", "lm0", "lm1", "lpp", "lpw0",
+ "lpw1", "lpw2", "lsc0", "lsc1", "lsck",
+ "lsda", "lsdi", "lspi", "lvp0", "lvp1",
+ "lvs";
+ nvidia,function = "displaya";
+ };
+ owc {
+ nvidia,pins = "owc", "uac";
+ nvidia,function = "rsvd2";
+ };
+ pmc {
+ nvidia,pins = "pmc";
+ nvidia,function = "pwr_on";
+ };
+ rm {
+ nvidia,pins = "rm";
+ nvidia,function = "i2c1";
+ };
+ sdb {
+ nvidia,pins = "sdb", "sdc", "sdd";
+ nvidia,function = "pwm";
+ };
+ sdio1 {
+ nvidia,pins = "sdio1";
+ nvidia,function = "sdio1";
+ };
+ slxc {
+ nvidia,pins = "slxc", "slxd";
+ nvidia,function = "sdio3";
+ };
+ spdi {
+ nvidia,pins = "spdi", "spdo";
+ nvidia,function = "spdif";
+ };
+ spia {
+ nvidia,pins = "spia", "spib", "spic";
+ nvidia,function = "spi2";
+ };
+ spid {
+ nvidia,pins = "spid", "spie", "spif";
+ nvidia,function = "spi1";
+ };
+ spig {
+ nvidia,pins = "spig", "spih";
+ nvidia,function = "spi2_alt";
+ };
+ uaa {
+ nvidia,pins = "uaa", "uab", "uda";
+ nvidia,function = "ulpi";
+ };
+ uad {
+ nvidia,pins = "uad";
+ nvidia,function = "irda";
+ };
+ uca {
+ nvidia,pins = "uca", "ucb";
+ nvidia,function = "uartc";
+ };
+ conf_ata {
+ nvidia,pins = "ata", "atc", "atd", "ate",
+ "crtp", "dap2", "dap3", "dap4", "dta",
+ "dtb", "dtc", "dtd", "dte", "gmb",
+ "gme", "i2cp", "pta", "slxc", "slxd",
+ "spdi", "spdo", "uda";
+ nvidia,pull = <0>;
+ nvidia,tristate = <1>;
+ };
+ conf_atb {
+ nvidia,pins = "atb", "cdev1", "dap1", "gma",
+ "gmc", "gmd", "gpu", "gpu7", "gpv",
+ "sdio1", "slxa", "slxk", "uac";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ conf_cdev2 {
+ nvidia,pins = "cdev2", "csus", "spia", "spib",
+ "spid", "spif";
+ nvidia,pull = <1>;
+ nvidia,tristate = <1>;
+ };
+ conf_ck32 {
+ nvidia,pins = "ck32", "ddrc", "pmca", "pmcb",
+ "pmcc", "pmcd", "pmce", "xm2c", "xm2d";
+ nvidia,pull = <0>;
+ };
+ conf_ddc {
+ nvidia,pins = "ddc", "dtf", "rm", "sdc", "sdd";
+ nvidia,pull = <2>;
+ nvidia,tristate = <0>;
+ };
+ conf_hdint {
+ nvidia,pins = "hdint", "lcsn", "ldc", "lm1",
+ "lpw1", "lsc1", "lsck", "lsda", "lsdi",
+ "lvp0", "pmc";
+ nvidia,tristate = <1>;
+ };
+ conf_irrx {
+ nvidia,pins = "irrx", "irtx", "kbca", "kbcb",
+ "kbcc", "kbcd", "kbce", "kbcf", "owc",
+ "spic", "spie", "spig", "spih", "uaa",
+ "uab", "uad", "uca", "ucb";
+ nvidia,pull = <2>;
+ nvidia,tristate = <1>;
+ };
+ conf_lc {
+ nvidia,pins = "lc", "ls";
+ nvidia,pull = <2>;
+ };
+ conf_ld0 {
+ nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
+ "ld5", "ld6", "ld7", "ld8", "ld9",
+ "ld10", "ld11", "ld12", "ld13", "ld14",
+ "ld15", "ld16", "ld17", "ldi", "lhp0",
+ "lhp1", "lhp2", "lhs", "lm0", "lpp",
+ "lpw0", "lpw2", "lsc0", "lspi", "lvp1",
+ "lvs", "sdb";
+ nvidia,tristate = <0>;
+ };
+ conf_ld17_0 {
+ nvidia,pins = "ld17_0", "ld19_18", "ld21_20",
+ "ld23_22";
+ nvidia,pull = <1>;
+ };
+ };
+ };
+
i2c@7000c000 {
clock-frequency = <400000>;
};
diff --git a/arch/arm/boot/dts/tegra-ventana.dts b/arch/arm/boot/dts/tegra-ventana.dts
index 2dcff8728e90..71eb2e50a668 100644
--- a/arch/arm/boot/dts/tegra-ventana.dts
+++ b/arch/arm/boot/dts/tegra-ventana.dts
@@ -10,6 +10,236 @@
reg = < 0x00000000 0x40000000 >;
};
+ pinmux@70000000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&state_default>;
+
+ state_default: pinmux {
+ ata {
+ nvidia,pins = "ata";
+ nvidia,function = "ide";
+ };
+ atb {
+ nvidia,pins = "atb", "gma", "gme";
+ nvidia,function = "sdio4";
+ };
+ atc {
+ nvidia,pins = "atc";
+ nvidia,function = "nand";
+ };
+ atd {
+ nvidia,pins = "atd", "ate", "gmb", "spia",
+ "spib", "spic";
+ nvidia,function = "gmi";
+ };
+ cdev1 {
+ nvidia,pins = "cdev1";
+ nvidia,function = "plla_out";
+ };
+ cdev2 {
+ nvidia,pins = "cdev2";
+ nvidia,function = "pllp_out4";
+ };
+ crtp {
+ nvidia,pins = "crtp", "lm1";
+ nvidia,function = "crt";
+ };
+ csus {
+ nvidia,pins = "csus";
+ nvidia,function = "vi_sensor_clk";
+ };
+ dap1 {
+ nvidia,pins = "dap1";
+ nvidia,function = "dap1";
+ };
+ dap2 {
+ nvidia,pins = "dap2";
+ nvidia,function = "dap2";
+ };
+ dap3 {
+ nvidia,pins = "dap3";
+ nvidia,function = "dap3";
+ };
+ dap4 {
+ nvidia,pins = "dap4";
+ nvidia,function = "dap4";
+ };
+ ddc {
+ nvidia,pins = "ddc", "owc", "spdi", "spdo",
+ "uac";
+ nvidia,function = "rsvd2";
+ };
+ dta {
+ nvidia,pins = "dta", "dtb", "dtc", "dtd", "dte";
+ nvidia,function = "vi";
+ };
+ dtf {
+ nvidia,pins = "dtf";
+ nvidia,function = "i2c3";
+ };
+ gmc {
+ nvidia,pins = "gmc";
+ nvidia,function = "uartd";
+ };
+ gmd {
+ nvidia,pins = "gmd";
+ nvidia,function = "sflash";
+ };
+ gpu {
+ nvidia,pins = "gpu";
+ nvidia,function = "pwm";
+ };
+ gpu7 {
+ nvidia,pins = "gpu7";
+ nvidia,function = "rtck";
+ };
+ gpv {
+ nvidia,pins = "gpv", "slxa", "slxk";
+ nvidia,function = "pcie";
+ };
+ hdint {
+ nvidia,pins = "hdint", "pta";
+ nvidia,function = "hdmi";
+ };
+ i2cp {
+ nvidia,pins = "i2cp";
+ nvidia,function = "i2cp";
+ };
+ irrx {
+ nvidia,pins = "irrx", "irtx";
+ nvidia,function = "uartb";
+ };
+ kbca {
+ nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
+ "kbce", "kbcf";
+ nvidia,function = "kbc";
+ };
+ lcsn {
+ nvidia,pins = "lcsn", "ldc", "lm0", "lpw1",
+ "lsdi", "lvp0";
+ nvidia,function = "rsvd4";
+ };
+ ld0 {
+ nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
+ "ld5", "ld6", "ld7", "ld8", "ld9",
+ "ld10", "ld11", "ld12", "ld13", "ld14",
+ "ld15", "ld16", "ld17", "ldi", "lhp0",
+ "lhp1", "lhp2", "lhs", "lpp", "lpw0",
+ "lpw2", "lsc0", "lsc1", "lsck", "lsda",
+ "lspi", "lvp1", "lvs";
+ nvidia,function = "displaya";
+ };
+ pmc {
+ nvidia,pins = "pmc";
+ nvidia,function = "pwr_on";
+ };
+ rm {
+ nvidia,pins = "rm";
+ nvidia,function = "i2c1";
+ };
+ sdb {
+ nvidia,pins = "sdb", "sdc", "sdd", "slxc";
+ nvidia,function = "sdio3";
+ };
+ sdio1 {
+ nvidia,pins = "sdio1";
+ nvidia,function = "sdio1";
+ };
+ slxd {
+ nvidia,pins = "slxd";
+ nvidia,function = "spdif";
+ };
+ spid {
+ nvidia,pins = "spid", "spie", "spif";
+ nvidia,function = "spi1";
+ };
+ spig {
+ nvidia,pins = "spig", "spih";
+ nvidia,function = "spi2_alt";
+ };
+ uaa {
+ nvidia,pins = "uaa", "uab", "uda";
+ nvidia,function = "ulpi";
+ };
+ uad {
+ nvidia,pins = "uad";
+ nvidia,function = "irda";
+ };
+ uca {
+ nvidia,pins = "uca", "ucb";
+ nvidia,function = "uartc";
+ };
+ conf_ata {
+ nvidia,pins = "ata", "atb", "atc", "atd",
+ "cdev1", "cdev2", "dap1", "dap2",
+ "dap4", "ddc", "dtf", "gma", "gmc",
+ "gme", "gpu", "gpu7", "i2cp", "irrx",
+ "irtx", "pta", "rm", "sdc", "sdd",
+ "slxc", "slxd", "slxk", "spdi", "spdo",
+ "uac", "uad", "uca", "ucb", "uda";
+ nvidia,pull = <0>;
+ nvidia,tristate = <0>;
+ };
+ conf_ate {
+ nvidia,pins = "ate", "csus", "dap3", "gmd",
+ "gpv", "owc", "spia", "spib", "spic",
+ "spid", "spie", "spig";
+ nvidia,pull = <0>;
+ nvidia,tristate = <1>;
+ };
+ conf_ck32 {
+ nvidia,pins = "ck32", "ddrc", "pmca", "pmcb",
+ "pmcc", "pmcd", "pmce", "xm2c", "xm2d";
+ nvidia,pull = <0>;
+ };
+ conf_crtp {
+ nvidia,pins = "crtp", "gmb", "slxa", "spih";
+ nvidia,pull = <2>;
+ nvidia,tristate = <1>;
+ };
+ conf_dta {
+ nvidia,pins = "dta", "dtb", "dtc", "dtd";
+ nvidia,pull = <1>;
+ nvidia,tristate = <0>;
+ };
+ conf_dte {
+ nvidia,pins = "dte", "spif";
+ nvidia,pull = <1>;
+ nvidia,tristate = <1>;
+ };
+ conf_hdint {
+ nvidia,pins = "hdint", "lcsn", "ldc", "lm1",
+ "lpw1", "lsck", "lsda", "lsdi", "lvp0";
+ nvidia,tristate = <1>;
+ };
+ conf_kbca {
+ nvidia,pins = "kbca", "kbcb", "kbcc", "kbcd",
+ "kbce", "kbcf", "sdio1", "uaa", "uab";
+ nvidia,pull = <2>;
+ nvidia,tristate = <0>;
+ };
+ conf_lc {
+ nvidia,pins = "lc", "ls";
+ nvidia,pull = <2>;
+ };
+ conf_ld0 {
+ nvidia,pins = "ld0", "ld1", "ld2", "ld3", "ld4",
+ "ld5", "ld6", "ld7", "ld8", "ld9",
+ "ld10", "ld11", "ld12", "ld13", "ld14",
+ "ld15", "ld16", "ld17", "ldi", "lhp0",
+ "lhp1", "lhp2", "lhs", "lm0", "lpp",
+ "lpw0", "lpw2", "lsc0", "lsc1", "lspi",
+ "lvp1", "lvs", "pmc", "sdb";
+ nvidia,tristate = <0>;
+ };
+ conf_ld17_0 {
+ nvidia,pins = "ld17_0", "ld19_18", "ld21_20",
+ "ld23_22";
+ nvidia,pull = <1>;
+ };
+ };
+ };
+
i2c@7000c000 {
clock-frequency = <400000>;
diff --git a/arch/arm/boot/dts/tny_a9260.dts b/arch/arm/boot/dts/tny_a9260.dts
new file mode 100644
index 000000000000..367a16dcd5ef
--- /dev/null
+++ b/arch/arm/boot/dts/tny_a9260.dts
@@ -0,0 +1,15 @@
+/*
+ * tny_a9260.dts - Device Tree file for Caloa TNY A9260 board
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+/dts-v1/;
+/include/ "at91sam9260.dtsi"
+/include/ "tny_a9260_common.dtsi"
+
+/ {
+ model = "Calao TNY A9260";
+ compatible = "calao,tny-a9260", "atmel,at91sam9260", "atmel,at91sam9";
+};
diff --git a/arch/arm/boot/dts/tny_a9260_common.dtsi b/arch/arm/boot/dts/tny_a9260_common.dtsi
new file mode 100644
index 000000000000..0e6d3de2e09e
--- /dev/null
+++ b/arch/arm/boot/dts/tny_a9260_common.dtsi
@@ -0,0 +1,83 @@
+/*
+ * tny_a9260_common.dtsi - Device Tree file for Caloa TNY A926x board
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+
+/ {
+ chosen {
+ bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock6 rw rootfstype=ubifs";
+ };
+
+ memory {
+ reg = <0x20000000 0x4000000>;
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ main_clock: clock@0 {
+ compatible = "atmel,osc", "fixed-clock";
+ clock-frequency = <12000000>;
+ };
+ };
+
+ ahb {
+ apb {
+ dbgu: serial@fffff200 {
+ status = "okay";
+ };
+ };
+
+ nand0: nand@40000000 {
+ nand-bus-width = <8>;
+ nand-ecc-mode = "soft";
+ nand-on-flash-bbt;
+ status = "okay";
+
+ at91bootstrap@0 {
+ label = "at91bootstrap";
+ reg = <0x0 0x20000>;
+ };
+
+ barebox@20000 {
+ label = "barebox";
+ reg = <0x20000 0x40000>;
+ };
+
+ bareboxenv@60000 {
+ label = "bareboxenv";
+ reg = <0x60000 0x20000>;
+ };
+
+ bareboxenv2@80000 {
+ label = "bareboxenv2";
+ reg = <0x80000 0x20000>;
+ };
+
+ oftree@80000 {
+ label = "oftree";
+ reg = <0xa0000 0x20000>;
+ };
+
+ kernel@a0000 {
+ label = "kernel";
+ reg = <0xc0000 0x400000>;
+ };
+
+ rootfs@4a0000 {
+ label = "rootfs";
+ reg = <0x4c0000 0x7800000>;
+ };
+
+ data@7ca0000 {
+ label = "data";
+ reg = <0x7cc0000 0x8340000>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/tny_a9263.dts b/arch/arm/boot/dts/tny_a9263.dts
new file mode 100644
index 000000000000..dee9c571306b
--- /dev/null
+++ b/arch/arm/boot/dts/tny_a9263.dts
@@ -0,0 +1,97 @@
+/*
+ * usb_a9263.dts - Device Tree file for Caloa USB A9293 board
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2 only
+ */
+/dts-v1/;
+/include/ "at91sam9263.dtsi"
+
+/ {
+ model = "Calao TNY A9263";
+ compatible = "atmel,tny-a9263", "atmel,at91sam9263", "atmel,at91sam9";
+
+ chosen {
+ bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs";
+ };
+
+ memory {
+ reg = <0x20000000 0x4000000>;
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ main_clock: clock@0 {
+ compatible = "atmel,osc", "fixed-clock";
+ clock-frequency = <12000000>;
+ };
+ };
+
+ ahb {
+ apb {
+ dbgu: serial@ffffee00 {
+ status = "okay";
+ };
+
+ usb1: gadget@fff78000 {
+ atmel,vbus-gpio = <&pioB 11 0>;
+ status = "okay";
+ };
+ };
+
+ nand0: nand@40000000 {
+ nand-bus-width = <8>;
+ nand-ecc-mode = "soft";
+ nand-on-flash-bbt;
+ status = "okay";
+
+ at91bootstrap@0 {
+ label = "at91bootstrap";
+ reg = <0x0 0x20000>;
+ };
+
+ barebox@20000 {
+ label = "barebox";
+ reg = <0x20000 0x40000>;
+ };
+
+ bareboxenv@60000 {
+ label = "bareboxenv";
+ reg = <0x60000 0x20000>;
+ };
+
+ bareboxenv2@80000 {
+ label = "bareboxenv2";
+ reg = <0x80000 0x20000>;
+ };
+
+ oftree@80000 {
+ label = "oftree";
+ reg = <0xa0000 0x20000>;
+ };
+
+ kernel@a0000 {
+ label = "kernel";
+ reg = <0xc0000 0x400000>;
+ };
+
+ rootfs@4a0000 {
+ label = "rootfs";
+ reg = <0x4c0000 0x7800000>;
+ };
+
+ data@7ca0000 {
+ label = "data";
+ reg = <0x7cc0000 0x8340000>;
+ };
+ };
+ };
+
+ i2c@0 {
+ status = "okay";
+ };
+};
diff --git a/arch/arm/boot/dts/tny_a9g20.dts b/arch/arm/boot/dts/tny_a9g20.dts
new file mode 100644
index 000000000000..e1ab64c72dba
--- /dev/null
+++ b/arch/arm/boot/dts/tny_a9g20.dts
@@ -0,0 +1,15 @@
+/*
+ * tny_a9g20.dts - Device Tree file for Caloa TNY A9G20 board
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2.
+ */
+/dts-v1/;
+/include/ "at91sam9g20.dtsi"
+/include/ "tny_a9260_common.dtsi"
+
+/ {
+ model = "Calao TNY A9G20";
+ compatible = "calao,tny-a9g20", "atmel,at91sam9g20", "atmel,at91sam9";
+};
diff --git a/arch/arm/boot/dts/twl4030.dtsi b/arch/arm/boot/dts/twl4030.dtsi
new file mode 100644
index 000000000000..22f4d1394ed3
--- /dev/null
+++ b/arch/arm/boot/dts/twl4030.dtsi
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * Integrated Power Management Chip
+ */
+&twl {
+ compatible = "ti,twl4030";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ rtc {
+ compatible = "ti,twl4030-rtc";
+ interrupts = <11>;
+ };
+
+ vdac: regulator@0 {
+ compatible = "ti,twl4030-vdac";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ vpll2: regulator@1 {
+ compatible = "ti,twl4030-vpll2";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ vmmc1: regulator@2 {
+ compatible = "ti,twl4030-vmmc1";
+ regulator-min-microvolt = <1850000>;
+ regulator-max-microvolt = <3150000>;
+ };
+
+ twl_gpio: gpio {
+ compatible = "ti,twl4030-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+};
diff --git a/arch/arm/boot/dts/twl6030.dtsi b/arch/arm/boot/dts/twl6030.dtsi
new file mode 100644
index 000000000000..3b2f3510d7eb
--- /dev/null
+++ b/arch/arm/boot/dts/twl6030.dtsi
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * Integrated Power Management Chip
+ * http://www.ti.com/lit/ds/symlink/twl6030.pdf
+ */
+&twl {
+ compatible = "ti,twl6030";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ rtc {
+ compatible = "ti,twl4030-rtc";
+ interrupts = <11>;
+ };
+
+ vaux1: regulator@0 {
+ compatible = "ti,twl6030-vaux1";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <3000000>;
+ };
+
+ vaux2: regulator@1 {
+ compatible = "ti,twl6030-vaux2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <2800000>;
+ };
+
+ vaux3: regulator@2 {
+ compatible = "ti,twl6030-vaux3";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <3000000>;
+ };
+
+ vmmc: regulator@3 {
+ compatible = "ti,twl6030-vmmc";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <3000000>;
+ };
+
+ vpp: regulator@4 {
+ compatible = "ti,twl6030-vpp";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2500000>;
+ };
+
+ vusim: regulator@5 {
+ compatible = "ti,twl6030-vusim";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <2900000>;
+ };
+
+ vdac: regulator@6 {
+ compatible = "ti,twl6030-vdac";
+ };
+
+ vana: regulator@7 {
+ compatible = "ti,twl6030-vana";
+ };
+
+ vcxio: regulator@8 {
+ compatible = "ti,twl6030-vcxio";
+ };
+
+ vusb: regulator@9 {
+ compatible = "ti,twl6030-vusb";
+ };
+
+ v1v8: regulator@10 {
+ compatible = "ti,twl6030-v1v8";
+ };
+
+ v2v1: regulator@11 {
+ compatible = "ti,twl6030-v2v1";
+ };
+
+ clk32kg: regulator@12 {
+ compatible = "ti,twl6030-clk32kg";
+ };
+};
diff --git a/arch/arm/boot/dts/usb_a9260.dts b/arch/arm/boot/dts/usb_a9260.dts
new file mode 100644
index 000000000000..296216058c11
--- /dev/null
+++ b/arch/arm/boot/dts/usb_a9260.dts
@@ -0,0 +1,23 @@
+/*
+ * usb_a9260.dts - Device Tree file for Caloa USB A9260 board
+ *
+ * Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+/dts-v1/;
+/include/ "at91sam9260.dtsi"
+/include/ "usb_a9260_common.dtsi"
+
+/ {
+ model = "Calao USB A9260";
+ compatible = "calao,usb-a9260", "atmel,at91sam9260", "atmel,at91sam9";
+
+ chosen {
+ bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs";
+ };
+
+ memory {
+ reg = <0x20000000 0x4000000>;
+ };
+};
diff --git a/arch/arm/boot/dts/usb_a9260_common.dtsi b/arch/arm/boot/dts/usb_a9260_common.dtsi
new file mode 100644
index 000000000000..e70d229baef5
--- /dev/null
+++ b/arch/arm/boot/dts/usb_a9260_common.dtsi
@@ -0,0 +1,117 @@
+/*
+ * usb_a926x.dts - Device Tree file for Caloa USB A926x board
+ *
+ * Copyright (C) 2011-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/ {
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ main_clock: clock@0 {
+ compatible = "atmel,osc", "fixed-clock";
+ clock-frequency = <12000000>;
+ };
+ };
+
+ ahb {
+ apb {
+ dbgu: serial@fffff200 {
+ status = "okay";
+ };
+
+ macb0: ethernet@fffc4000 {
+ phy-mode = "rmii";
+ status = "okay";
+ };
+
+ usb1: gadget@fffa4000 {
+ atmel,vbus-gpio = <&pioC 5 0>;
+ status = "okay";
+ };
+ };
+
+ nand0: nand@40000000 {
+ nand-bus-width = <8>;
+ nand-ecc-mode = "soft";
+ nand-on-flash-bbt;
+ status = "okay";
+
+ at91bootstrap@0 {
+ label = "at91bootstrap";
+ reg = <0x0 0x20000>;
+ };
+
+ barebox@20000 {
+ label = "barebox";
+ reg = <0x20000 0x40000>;
+ };
+
+ bareboxenv@60000 {
+ label = "bareboxenv";
+ reg = <0x60000 0x20000>;
+ };
+
+ bareboxenv2@80000 {
+ label = "bareboxenv2";
+ reg = <0x80000 0x20000>;
+ };
+
+ oftree@80000 {
+ label = "oftree";
+ reg = <0xa0000 0x20000>;
+ };
+
+ kernel@a0000 {
+ label = "kernel";
+ reg = <0xc0000 0x400000>;
+ };
+
+ rootfs@4a0000 {
+ label = "rootfs";
+ reg = <0x4c0000 0x7800000>;
+ };
+
+ data@7ca0000 {
+ label = "data";
+ reg = <0x7cc0000 0x8340000>;
+ };
+ };
+
+ usb0: ohci@00500000 {
+ num-ports = <2>;
+ status = "okay";
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ user_led {
+ label = "user_led";
+ gpios = <&pioB 21 1>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ user_pb {
+ label = "user_pb";
+ gpios = <&pioB 10 1>;
+ linux,code = <28>;
+ gpio-key,wakeup;
+ };
+ };
+
+ i2c@0 {
+ status = "okay";
+ };
+};
diff --git a/arch/arm/boot/dts/usb_a9263.dts b/arch/arm/boot/dts/usb_a9263.dts
new file mode 100644
index 000000000000..6fe05ccb6203
--- /dev/null
+++ b/arch/arm/boot/dts/usb_a9263.dts
@@ -0,0 +1,131 @@
+/*
+ * usb_a9263.dts - Device Tree file for Caloa USB A9293 board
+ *
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Licensed under GPLv2 only
+ */
+/dts-v1/;
+/include/ "at91sam9263.dtsi"
+
+/ {
+ model = "Calao USB A9263";
+ compatible = "atmel,usb-a9263", "atmel,at91sam9263", "atmel,at91sam9";
+
+ chosen {
+ bootargs = "mem=64M console=ttyS0,115200 root=/dev/mtdblock5 rw rootfstype=ubifs";
+ };
+
+ memory {
+ reg = <0x20000000 0x4000000>;
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ main_clock: clock@0 {
+ compatible = "atmel,osc", "fixed-clock";
+ clock-frequency = <12000000>;
+ };
+ };
+
+ ahb {
+ apb {
+ dbgu: serial@ffffee00 {
+ status = "okay";
+ };
+
+ macb0: ethernet@fffbc000 {
+ phy-mode = "rmii";
+ status = "okay";
+ };
+
+ usb1: gadget@fff78000 {
+ atmel,vbus-gpio = <&pioB 11 0>;
+ status = "okay";
+ };
+
+ };
+
+ nand0: nand@40000000 {
+ nand-bus-width = <8>;
+ nand-ecc-mode = "soft";
+ nand-on-flash-bbt;
+ status = "okay";
+
+ at91bootstrap@0 {
+ label = "at91bootstrap";
+ reg = <0x0 0x20000>;
+ };
+
+ barebox@20000 {
+ label = "barebox";
+ reg = <0x20000 0x40000>;
+ };
+
+ bareboxenv@60000 {
+ label = "bareboxenv";
+ reg = <0x60000 0x20000>;
+ };
+
+ bareboxenv2@80000 {
+ label = "bareboxenv2";
+ reg = <0x80000 0x20000>;
+ };
+
+ oftree@80000 {
+ label = "oftree";
+ reg = <0xa0000 0x20000>;
+ };
+
+ kernel@a0000 {
+ label = "kernel";
+ reg = <0xc0000 0x400000>;
+ };
+
+ rootfs@4a0000 {
+ label = "rootfs";
+ reg = <0x4c0000 0x7800000>;
+ };
+
+ data@7ca0000 {
+ label = "data";
+ reg = <0x7cc0000 0x8340000>;
+ };
+ };
+
+ usb0: ohci@00a00000 {
+ num-ports = <2>;
+ status = "okay";
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ user_led {
+ label = "user_led";
+ gpios = <&pioB 21 0>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ user_pb {
+ label = "user_pb";
+ gpios = <&pioB 10 1>;
+ linux,code = <28>;
+ gpio-key,wakeup;
+ };
+ };
+
+ i2c@0 {
+ status = "okay";
+ };
+};
diff --git a/arch/arm/boot/dts/usb_a9g20.dts b/arch/arm/boot/dts/usb_a9g20.dts
index 7c2399c532e5..2dacb16ce4ae 100644
--- a/arch/arm/boot/dts/usb_a9g20.dts
+++ b/arch/arm/boot/dts/usb_a9g20.dts
@@ -7,6 +7,7 @@
*/
/dts-v1/;
/include/ "at91sam9g20.dtsi"
+/include/ "usb_a9260_common.dtsi"
/ {
model = "Calao USB A9G20";
@@ -20,108 +21,7 @@
reg = <0x20000000 0x4000000>;
};
- clocks {
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- main_clock: clock@0 {
- compatible = "atmel,osc", "fixed-clock";
- clock-frequency = <12000000>;
- };
- };
-
- ahb {
- apb {
- dbgu: serial@fffff200 {
- status = "okay";
- };
-
- macb0: ethernet@fffc4000 {
- phy-mode = "rmii";
- status = "okay";
- };
-
- usb1: gadget@fffa4000 {
- atmel,vbus-gpio = <&pioC 5 0>;
- status = "okay";
- };
- };
-
- nand0: nand@40000000 {
- nand-bus-width = <8>;
- nand-ecc-mode = "soft";
- nand-on-flash-bbt;
- status = "okay";
-
- at91bootstrap@0 {
- label = "at91bootstrap";
- reg = <0x0 0x20000>;
- };
-
- barebox@20000 {
- label = "barebox";
- reg = <0x20000 0x40000>;
- };
-
- bareboxenv@60000 {
- label = "bareboxenv";
- reg = <0x60000 0x20000>;
- };
-
- bareboxenv2@80000 {
- label = "bareboxenv2";
- reg = <0x80000 0x20000>;
- };
-
- kernel@a0000 {
- label = "kernel";
- reg = <0xa0000 0x400000>;
- };
-
- rootfs@4a0000 {
- label = "rootfs";
- reg = <0x4a0000 0x7800000>;
- };
-
- data@7ca0000 {
- label = "data";
- reg = <0x7ca0000 0x8360000>;
- };
- };
-
- usb0: ohci@00500000 {
- num-ports = <2>;
- status = "okay";
- };
- };
-
- leds {
- compatible = "gpio-leds";
-
- user_led {
- label = "user_led";
- gpios = <&pioB 21 1>;
- linux,default-trigger = "heartbeat";
- };
- };
-
- gpio_keys {
- compatible = "gpio-keys";
- #address-cells = <1>;
- #size-cells = <0>;
-
- user_pb {
- label = "user_pb";
- gpios = <&pioB 10 1>;
- linux,code = <28>;
- gpio-key,wakeup;
- };
- };
-
i2c@0 {
- status = "okay";
-
rv3029c2@56 {
compatible = "rv3029c2";
reg = <0x56>;
diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile
index 215816f1775f..e8a4e58f1b82 100644
--- a/arch/arm/common/Makefile
+++ b/arch/arm/common/Makefile
@@ -11,7 +11,5 @@ obj-$(CONFIG_DMABOUNCE) += dmabounce.o
obj-$(CONFIG_SHARP_LOCOMO) += locomo.o
obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o
obj-$(CONFIG_SHARP_SCOOP) += scoop.o
-obj-$(CONFIG_ARCH_IXP2000) += uengine.o
-obj-$(CONFIG_ARCH_IXP23XX) += uengine.o
obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o
obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp.o
diff --git a/arch/arm/common/uengine.c b/arch/arm/common/uengine.c
deleted file mode 100644
index bef408f3d76c..000000000000
--- a/arch/arm/common/uengine.c
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * Generic library functions for the microengines found on the Intel
- * IXP2000 series of network processors.
- *
- * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
- * Dedicated to Marija Kulikova.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/io.h>
-#include <mach/hardware.h>
-#include <asm/hardware/uengine.h>
-
-#if defined(CONFIG_ARCH_IXP2000)
-#define IXP_UENGINE_CSR_VIRT_BASE IXP2000_UENGINE_CSR_VIRT_BASE
-#define IXP_PRODUCT_ID IXP2000_PRODUCT_ID
-#define IXP_MISC_CONTROL IXP2000_MISC_CONTROL
-#define IXP_RESET1 IXP2000_RESET1
-#else
-#if defined(CONFIG_ARCH_IXP23XX)
-#define IXP_UENGINE_CSR_VIRT_BASE IXP23XX_UENGINE_CSR_VIRT_BASE
-#define IXP_PRODUCT_ID IXP23XX_PRODUCT_ID
-#define IXP_MISC_CONTROL IXP23XX_MISC_CONTROL
-#define IXP_RESET1 IXP23XX_RESET1
-#else
-#error unknown platform
-#endif
-#endif
-
-#define USTORE_ADDRESS 0x000
-#define USTORE_DATA_LOWER 0x004
-#define USTORE_DATA_UPPER 0x008
-#define CTX_ENABLES 0x018
-#define CC_ENABLE 0x01c
-#define CSR_CTX_POINTER 0x020
-#define INDIRECT_CTX_STS 0x040
-#define ACTIVE_CTX_STS 0x044
-#define INDIRECT_CTX_SIG_EVENTS 0x048
-#define INDIRECT_CTX_WAKEUP_EVENTS 0x050
-#define NN_PUT 0x080
-#define NN_GET 0x084
-#define TIMESTAMP_LOW 0x0c0
-#define TIMESTAMP_HIGH 0x0c4
-#define T_INDEX_BYTE_INDEX 0x0f4
-#define LOCAL_CSR_STATUS 0x180
-
-u32 ixp2000_uengine_mask;
-
-static void *ixp2000_uengine_csr_area(int uengine)
-{
- return ((void *)IXP_UENGINE_CSR_VIRT_BASE) + (uengine << 10);
-}
-
-/*
- * LOCAL_CSR_STATUS=1 after a read or write to a microengine's CSR
- * space means that the microengine we tried to access was also trying
- * to access its own CSR space on the same clock cycle as we did. When
- * this happens, we lose the arbitration process by default, and the
- * read or write we tried to do was not actually performed, so we try
- * again until it succeeds.
- */
-u32 ixp2000_uengine_csr_read(int uengine, int offset)
-{
- void *uebase;
- u32 *local_csr_status;
- u32 *reg;
- u32 value;
-
- uebase = ixp2000_uengine_csr_area(uengine);
-
- local_csr_status = (u32 *)(uebase + LOCAL_CSR_STATUS);
- reg = (u32 *)(uebase + offset);
- do {
- value = ixp2000_reg_read(reg);
- } while (ixp2000_reg_read(local_csr_status) & 1);
-
- return value;
-}
-EXPORT_SYMBOL(ixp2000_uengine_csr_read);
-
-void ixp2000_uengine_csr_write(int uengine, int offset, u32 value)
-{
- void *uebase;
- u32 *local_csr_status;
- u32 *reg;
-
- uebase = ixp2000_uengine_csr_area(uengine);
-
- local_csr_status = (u32 *)(uebase + LOCAL_CSR_STATUS);
- reg = (u32 *)(uebase + offset);
- do {
- ixp2000_reg_write(reg, value);
- } while (ixp2000_reg_read(local_csr_status) & 1);
-}
-EXPORT_SYMBOL(ixp2000_uengine_csr_write);
-
-void ixp2000_uengine_reset(u32 uengine_mask)
-{
- u32 value;
-
- value = ixp2000_reg_read(IXP_RESET1) & ~ixp2000_uengine_mask;
-
- uengine_mask &= ixp2000_uengine_mask;
- ixp2000_reg_wrb(IXP_RESET1, value | uengine_mask);
- ixp2000_reg_wrb(IXP_RESET1, value);
-}
-EXPORT_SYMBOL(ixp2000_uengine_reset);
-
-void ixp2000_uengine_set_mode(int uengine, u32 mode)
-{
- /*
- * CTL_STR_PAR_EN: unconditionally enable parity checking on
- * control store.
- */
- mode |= 0x10000000;
- ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mode);
-
- /*
- * Enable updating of condition codes.
- */
- ixp2000_uengine_csr_write(uengine, CC_ENABLE, 0x00002000);
-
- /*
- * Initialise other per-microengine registers.
- */
- ixp2000_uengine_csr_write(uengine, NN_PUT, 0x00);
- ixp2000_uengine_csr_write(uengine, NN_GET, 0x00);
- ixp2000_uengine_csr_write(uengine, T_INDEX_BYTE_INDEX, 0);
-}
-EXPORT_SYMBOL(ixp2000_uengine_set_mode);
-
-static int make_even_parity(u32 x)
-{
- return hweight32(x) & 1;
-}
-
-static void ustore_write(int uengine, u64 insn)
-{
- /*
- * Generate even parity for top and bottom 20 bits.
- */
- insn |= (u64)make_even_parity((insn >> 20) & 0x000fffff) << 41;
- insn |= (u64)make_even_parity(insn & 0x000fffff) << 40;
-
- /*
- * Write to microstore. The second write auto-increments
- * the USTORE_ADDRESS index register.
- */
- ixp2000_uengine_csr_write(uengine, USTORE_DATA_LOWER, (u32)insn);
- ixp2000_uengine_csr_write(uengine, USTORE_DATA_UPPER, (u32)(insn >> 32));
-}
-
-void ixp2000_uengine_load_microcode(int uengine, u8 *ucode, int insns)
-{
- int i;
-
- /*
- * Start writing to microstore at address 0.
- */
- ixp2000_uengine_csr_write(uengine, USTORE_ADDRESS, 0x80000000);
- for (i = 0; i < insns; i++) {
- u64 insn;
-
- insn = (((u64)ucode[0]) << 32) |
- (((u64)ucode[1]) << 24) |
- (((u64)ucode[2]) << 16) |
- (((u64)ucode[3]) << 8) |
- ((u64)ucode[4]);
- ucode += 5;
-
- ustore_write(uengine, insn);
- }
-
- /*
- * Pad with a few NOPs at the end (to avoid the microengine
- * aborting as it prefetches beyond the last instruction), unless
- * we run off the end of the instruction store first, at which
- * point the address register will wrap back to zero.
- */
- for (i = 0; i < 4; i++) {
- u32 addr;
-
- addr = ixp2000_uengine_csr_read(uengine, USTORE_ADDRESS);
- if (addr == 0x80000000)
- break;
- ustore_write(uengine, 0xf0000c0300ULL);
- }
-
- /*
- * End programming.
- */
- ixp2000_uengine_csr_write(uengine, USTORE_ADDRESS, 0x00000000);
-}
-EXPORT_SYMBOL(ixp2000_uengine_load_microcode);
-
-void ixp2000_uengine_init_context(int uengine, int context, int pc)
-{
- /*
- * Select the right context for indirect access.
- */
- ixp2000_uengine_csr_write(uengine, CSR_CTX_POINTER, context);
-
- /*
- * Initialise signal masks to immediately go to Ready state.
- */
- ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_SIG_EVENTS, 1);
- ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_WAKEUP_EVENTS, 1);
-
- /*
- * Set program counter.
- */
- ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_STS, pc);
-}
-EXPORT_SYMBOL(ixp2000_uengine_init_context);
-
-void ixp2000_uengine_start_contexts(int uengine, u8 ctx_mask)
-{
- u32 mask;
-
- /*
- * Enable the specified context to go to Executing state.
- */
- mask = ixp2000_uengine_csr_read(uengine, CTX_ENABLES);
- mask |= ctx_mask << 8;
- ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mask);
-}
-EXPORT_SYMBOL(ixp2000_uengine_start_contexts);
-
-void ixp2000_uengine_stop_contexts(int uengine, u8 ctx_mask)
-{
- u32 mask;
-
- /*
- * Disable the Ready->Executing transition. Note that this
- * does not stop the context until it voluntarily yields.
- */
- mask = ixp2000_uengine_csr_read(uengine, CTX_ENABLES);
- mask &= ~(ctx_mask << 8);
- ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mask);
-}
-EXPORT_SYMBOL(ixp2000_uengine_stop_contexts);
-
-static int check_ixp_type(struct ixp2000_uengine_code *c)
-{
- u32 product_id;
- u32 rev;
-
- product_id = ixp2000_reg_read(IXP_PRODUCT_ID);
- if (((product_id >> 16) & 0x1f) != 0)
- return 0;
-
- switch ((product_id >> 8) & 0xff) {
-#ifdef CONFIG_ARCH_IXP2000
- case 0: /* IXP2800 */
- if (!(c->cpu_model_bitmask & 4))
- return 0;
- break;
-
- case 1: /* IXP2850 */
- if (!(c->cpu_model_bitmask & 8))
- return 0;
- break;
-
- case 2: /* IXP2400 */
- if (!(c->cpu_model_bitmask & 2))
- return 0;
- break;
-#endif
-
-#ifdef CONFIG_ARCH_IXP23XX
- case 4: /* IXP23xx */
- if (!(c->cpu_model_bitmask & 0x3f0))
- return 0;
- break;
-#endif
-
- default:
- return 0;
- }
-
- rev = product_id & 0xff;
- if (rev < c->cpu_min_revision || rev > c->cpu_max_revision)
- return 0;
-
- return 1;
-}
-
-static void generate_ucode(u8 *ucode, u32 *gpr_a, u32 *gpr_b)
-{
- int offset;
- int i;
-
- offset = 0;
-
- for (i = 0; i < 128; i++) {
- u8 b3;
- u8 b2;
- u8 b1;
- u8 b0;
-
- b3 = (gpr_a[i] >> 24) & 0xff;
- b2 = (gpr_a[i] >> 16) & 0xff;
- b1 = (gpr_a[i] >> 8) & 0xff;
- b0 = gpr_a[i] & 0xff;
-
- /* immed[@ai, (b1 << 8) | b0] */
- /* 11110000 0000VVVV VVVV11VV VVVVVV00 1IIIIIII */
- ucode[offset++] = 0xf0;
- ucode[offset++] = (b1 >> 4);
- ucode[offset++] = (b1 << 4) | 0x0c | (b0 >> 6);
- ucode[offset++] = (b0 << 2);
- ucode[offset++] = 0x80 | i;
-
- /* immed_w1[@ai, (b3 << 8) | b2] */
- /* 11110100 0100VVVV VVVV11VV VVVVVV00 1IIIIIII */
- ucode[offset++] = 0xf4;
- ucode[offset++] = 0x40 | (b3 >> 4);
- ucode[offset++] = (b3 << 4) | 0x0c | (b2 >> 6);
- ucode[offset++] = (b2 << 2);
- ucode[offset++] = 0x80 | i;
- }
-
- for (i = 0; i < 128; i++) {
- u8 b3;
- u8 b2;
- u8 b1;
- u8 b0;
-
- b3 = (gpr_b[i] >> 24) & 0xff;
- b2 = (gpr_b[i] >> 16) & 0xff;
- b1 = (gpr_b[i] >> 8) & 0xff;
- b0 = gpr_b[i] & 0xff;
-
- /* immed[@bi, (b1 << 8) | b0] */
- /* 11110000 0000VVVV VVVV001I IIIIII11 VVVVVVVV */
- ucode[offset++] = 0xf0;
- ucode[offset++] = (b1 >> 4);
- ucode[offset++] = (b1 << 4) | 0x02 | (i >> 6);
- ucode[offset++] = (i << 2) | 0x03;
- ucode[offset++] = b0;
-
- /* immed_w1[@bi, (b3 << 8) | b2] */
- /* 11110100 0100VVVV VVVV001I IIIIII11 VVVVVVVV */
- ucode[offset++] = 0xf4;
- ucode[offset++] = 0x40 | (b3 >> 4);
- ucode[offset++] = (b3 << 4) | 0x02 | (i >> 6);
- ucode[offset++] = (i << 2) | 0x03;
- ucode[offset++] = b2;
- }
-
- /* ctx_arb[kill] */
- ucode[offset++] = 0xe0;
- ucode[offset++] = 0x00;
- ucode[offset++] = 0x01;
- ucode[offset++] = 0x00;
- ucode[offset++] = 0x00;
-}
-
-static int set_initial_registers(int uengine, struct ixp2000_uengine_code *c)
-{
- int per_ctx_regs;
- u32 *gpr_a;
- u32 *gpr_b;
- u8 *ucode;
- int i;
-
- gpr_a = kzalloc(128 * sizeof(u32), GFP_KERNEL);
- gpr_b = kzalloc(128 * sizeof(u32), GFP_KERNEL);
- ucode = kmalloc(513 * 5, GFP_KERNEL);
- if (gpr_a == NULL || gpr_b == NULL || ucode == NULL) {
- kfree(ucode);
- kfree(gpr_b);
- kfree(gpr_a);
- return 1;
- }
-
- per_ctx_regs = 16;
- if (c->uengine_parameters & IXP2000_UENGINE_4_CONTEXTS)
- per_ctx_regs = 32;
-
- for (i = 0; i < 256; i++) {
- struct ixp2000_reg_value *r = c->initial_reg_values + i;
- u32 *bank;
- int inc;
- int j;
-
- if (r->reg == -1)
- break;
-
- bank = (r->reg & 0x400) ? gpr_b : gpr_a;
- inc = (r->reg & 0x80) ? 128 : per_ctx_regs;
-
- j = r->reg & 0x7f;
- while (j < 128) {
- bank[j] = r->value;
- j += inc;
- }
- }
-
- generate_ucode(ucode, gpr_a, gpr_b);
- ixp2000_uengine_load_microcode(uengine, ucode, 513);
- ixp2000_uengine_init_context(uengine, 0, 0);
- ixp2000_uengine_start_contexts(uengine, 0x01);
- for (i = 0; i < 100; i++) {
- u32 status;
-
- status = ixp2000_uengine_csr_read(uengine, ACTIVE_CTX_STS);
- if (!(status & 0x80000000))
- break;
- }
- ixp2000_uengine_stop_contexts(uengine, 0x01);
-
- kfree(ucode);
- kfree(gpr_b);
- kfree(gpr_a);
-
- return !!(i == 100);
-}
-
-int ixp2000_uengine_load(int uengine, struct ixp2000_uengine_code *c)
-{
- int ctx;
-
- if (!check_ixp_type(c))
- return 1;
-
- if (!(ixp2000_uengine_mask & (1 << uengine)))
- return 1;
-
- ixp2000_uengine_reset(1 << uengine);
- ixp2000_uengine_set_mode(uengine, c->uengine_parameters);
- if (set_initial_registers(uengine, c))
- return 1;
- ixp2000_uengine_load_microcode(uengine, c->insns, c->num_insns);
-
- for (ctx = 0; ctx < 8; ctx++)
- ixp2000_uengine_init_context(uengine, ctx, 0);
-
- return 0;
-}
-EXPORT_SYMBOL(ixp2000_uengine_load);
-
-
-static int __init ixp2000_uengine_init(void)
-{
- int uengine;
- u32 value;
-
- /*
- * Determine number of microengines present.
- */
- switch ((ixp2000_reg_read(IXP_PRODUCT_ID) >> 8) & 0x1fff) {
-#ifdef CONFIG_ARCH_IXP2000
- case 0: /* IXP2800 */
- case 1: /* IXP2850 */
- ixp2000_uengine_mask = 0x00ff00ff;
- break;
-
- case 2: /* IXP2400 */
- ixp2000_uengine_mask = 0x000f000f;
- break;
-#endif
-
-#ifdef CONFIG_ARCH_IXP23XX
- case 4: /* IXP23xx */
- ixp2000_uengine_mask = (*IXP23XX_EXP_CFG_FUSE >> 8) & 0xf;
- break;
-#endif
-
- default:
- printk(KERN_INFO "Detected unknown IXP2000 model (%.8x)\n",
- (unsigned int)ixp2000_reg_read(IXP_PRODUCT_ID));
- ixp2000_uengine_mask = 0x00000000;
- break;
- }
-
- /*
- * Reset microengines.
- */
- ixp2000_uengine_reset(ixp2000_uengine_mask);
-
- /*
- * Synchronise timestamp counters across all microengines.
- */
- value = ixp2000_reg_read(IXP_MISC_CONTROL);
- ixp2000_reg_wrb(IXP_MISC_CONTROL, value & ~0x80);
- for (uengine = 0; uengine < 32; uengine++) {
- if (ixp2000_uengine_mask & (1 << uengine)) {
- ixp2000_uengine_csr_write(uengine, TIMESTAMP_LOW, 0);
- ixp2000_uengine_csr_write(uengine, TIMESTAMP_HIGH, 0);
- }
- }
- ixp2000_reg_wrb(IXP_MISC_CONTROL, value | 0x80);
-
- return 0;
-}
-
-subsys_initcall(ixp2000_uengine_init);
diff --git a/arch/arm/configs/armadillo800eva_defconfig b/arch/arm/configs/armadillo800eva_defconfig
new file mode 100644
index 000000000000..ddc9fe6a78ac
--- /dev/null
+++ b/arch/arm/configs/armadillo800eva_defconfig
@@ -0,0 +1,142 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_SHMOBILE=y
+CONFIG_ARCH_R8A7740=y
+CONFIG_MACH_ARMADILLO800EVA=y
+# CONFIG_SH_TIMER_TMU is not set
+# CONFIG_ARM_THUMB is not set
+CONFIG_CPU_BPREDICT_DISABLE=y
+# CONFIG_CACHE_L2X0 is not set
+CONFIG_ARM_ERRATA_430973=y
+CONFIG_ARM_ERRATA_458693=y
+CONFIG_ARM_ERRATA_460075=y
+CONFIG_ARM_ERRATA_720789=y
+CONFIG_ARM_ERRATA_743622=y
+CONFIG_ARM_ERRATA_751472=y
+CONFIG_ARM_ERRATA_754322=y
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_FORCE_MAX_ZONEORDER=13
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=tty0 console=ttySC1,115200 earlyprintk=sh-sci.1,115200 ignore_loglevel root=/dev/nfs ip=dhcp nfsroot=,rsize=4096,wsize=4096"
+CONFIG_CMDLINE_FORCE=y
+CONFIG_KEXEC=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+CONFIG_SH_ETH=y
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_WLAN is not set
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ST1232=y
+# CONFIG_SERIO is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=8
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_SH_MOBILE=y
+# CONFIG_HWMON is not set
+CONFIG_FB=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_SH_MOBILE_LCDC=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_DRIVERS is not set
+# CONFIG_SND_ARM is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_SH4_FSI=y
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_RENESAS_USBHS=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_RENESAS_USBHS_UDC=y
+CONFIG_USB_ETH=m
+CONFIG_MMC=y
+CONFIG_MMC_SDHI=y
+CONFIG_MMC_SH_MMCIF=y
+CONFIG_UIO=y
+CONFIG_UIO_PDRV_GENIRQ=y
+# CONFIG_DNOTIFY is not set
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_ARM_UNWIND is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_ANSI_CPRNG=y
+CONFIG_XZ_DEC=y
diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig
new file mode 100644
index 000000000000..67bc571ed0c3
--- /dev/null
+++ b/arch/arm/configs/at91_dt_defconfig
@@ -0,0 +1,196 @@
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_AT91=y
+CONFIG_SOC_AT91SAM9260=y
+CONFIG_SOC_AT91SAM9263=y
+CONFIG_SOC_AT91SAM9G45=y
+CONFIG_SOC_AT91SAM9X5=y
+CONFIG_MACH_AT91SAM_DT=y
+CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
+CONFIG_AT91_TIMER_HZ=128
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_LEDS=y
+CONFIG_LEDS_CPU=y
+CONFIG_UACCESS_WITH_MEMCPY=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_ARM_ATAG_DTB_COMPAT=y
+CONFIG_CMDLINE="mem=128M console=ttyS0,115200 initrd=0x21100000,25165824 root=/dev/ram0 rw"
+CONFIG_KEXEC=y
+CONFIG_AUTO_ZRELADDR=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_IPV6=y
+# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_BEET is not set
+CONFIG_IPV6_SIT_6RD=y
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_ATMEL=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_GLUEBI=y
+CONFIG_PROC_DEVICETREE=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=4
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_ATMEL_PWM=y
+CONFIG_ATMEL_TCLIB=y
+CONFIG_EEPROM_93CX6=m
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_NETDEVICES=y
+CONFIG_MII=y
+CONFIG_MACB=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+CONFIG_DAVICOM_PHY=y
+CONFIG_MICREL_PHY=y
+# CONFIG_WLAN is not set
+CONFIG_INPUT_POLLDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=480
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=272
+CONFIG_INPUT_JOYDEV=y
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_SERIO is not set
+CONFIG_LEGACY_PTY_COUNT=4
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+CONFIG_HW_RANDOM=y
+CONFIG_I2C=y
+CONFIG_I2C_GPIO=y
+CONFIG_SPI=y
+CONFIG_SPI_ATMEL=y
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_AT91SAM9X_WATCHDOG=y
+CONFIG_SSB=m
+CONFIG_FB=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_ATMEL=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_ATMEL_LCDC=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_ACORN_8x8=y
+CONFIG_FONT_MINI_4x6=y
+CONFIG_LOGO=y
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_ACM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_FTDI_SIO=y
+CONFIG_USB_SERIAL_PL2303=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_AT91=m
+CONFIG_USB_ATMEL_USBA=m
+CONFIG_USB_ETH=m
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_CDC_COMPOSITE=m
+CONFIG_USB_G_ACM_MS=m
+CONFIG_USB_G_MULTI=m
+CONFIG_USB_G_MULTI_CDC=y
+CONFIG_MMC=y
+CONFIG_MMC_ATMELMCI=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_AT91RM9200=y
+CONFIG_RTC_DRV_AT91SAM9=y
+CONFIG_DMADEVICES=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_EXT2_FS=y
+CONFIG_FANOTIFY=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_DEBUG_FS=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_FTRACE is not set
+CONFIG_DEBUG_USER=y
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ARC4=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_USER_API_HASH=m
+CONFIG_CRYPTO_USER_API_SKCIPHER=m
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=m
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC7=m
+CONFIG_AVERAGE=y
diff --git a/arch/arm/configs/at91rm9200_defconfig b/arch/arm/configs/at91rm9200_defconfig
index bbe4e1a1f5d8..d54e2acd3ab1 100644
--- a/arch/arm/configs/at91rm9200_defconfig
+++ b/arch/arm/configs/at91rm9200_defconfig
@@ -14,6 +14,7 @@ CONFIG_MODULE_SRCVERSION_ALL=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_IOSCHED_CFQ is not set
CONFIG_ARCH_AT91=y
+CONFIG_ARCH_AT91RM9200=y
CONFIG_MACH_ONEARM=y
CONFIG_ARCH_AT91RM9200DK=y
CONFIG_MACH_AT91RM9200EK=y
diff --git a/arch/arm/configs/bcmring_defconfig b/arch/arm/configs/bcmring_defconfig
index 795374d48f81..9e6a8fe13164 100644
--- a/arch/arm/configs/bcmring_defconfig
+++ b/arch/arm/configs/bcmring_defconfig
@@ -11,7 +11,7 @@ CONFIG_KALLSYMS_EXTRA_PASS=y
# CONFIG_TIMERFD is not set
# CONFIG_EVENTFD is not set
# CONFIG_AIO is not set
-CONFIG_PERF_COUNTERS=y
+CONFIG_PERF_EVENTS=y
# CONFIG_VM_EVENT_COUNTERS is not set
# CONFIG_SLUB_DEBUG is not set
# CONFIG_COMPAT_BRK is not set
diff --git a/arch/arm/configs/imx_v4_v5_defconfig b/arch/arm/configs/imx_v4_v5_defconfig
index 6b31cb60daab..09a02963cf58 100644
--- a/arch/arm/configs/imx_v4_v5_defconfig
+++ b/arch/arm/configs/imx_v4_v5_defconfig
@@ -92,6 +92,7 @@ CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_MOUSE is not set
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ADS7846=m
+CONFIG_TOUCHSCREEN_MC13783=m
# CONFIG_SERIO is not set
# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_8250=m
@@ -107,7 +108,8 @@ CONFIG_SPI_SPIDEV=y
CONFIG_W1=y
CONFIG_W1_MASTER_MXC=y
CONFIG_W1_SLAVE_THERM=y
-# CONFIG_HWMON is not set
+CONFIG_HWMON=m
+CONFIG_SENSORS_MC13783_ADC=m
CONFIG_WATCHDOG=y
CONFIG_IMX2_WDT=y
CONFIG_MFD_MC13XXX=y
diff --git a/arch/arm/configs/ixp2000_defconfig b/arch/arm/configs/ixp2000_defconfig
deleted file mode 100644
index 8405aded97a3..000000000000
--- a/arch/arm/configs/ixp2000_defconfig
+++ /dev/null
@@ -1,99 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_EXPERT=y
-# CONFIG_HOTPLUG is not set
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_ARCH_IXP2000=y
-CONFIG_ARCH_ENP2611=y
-CONFIG_ARCH_IXDP2400=y
-CONFIG_ARCH_IXDP2800=y
-CONFIG_ARCH_IXDP2401=y
-CONFIG_ARCH_IXDP2801=y
-# CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO is not set
-# CONFIG_ARM_THUMB is not set
-CONFIG_CPU_BIG_ENDIAN=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=ttyS0,57600 root=/dev/nfs ip=bootp mem=64M@0x0"
-CONFIG_FPE_NWFPE=y
-CONFIG_FPE_NWFPE_XP=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_SYN_COOKIES=y
-CONFIG_IPV6=y
-# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET6_XFRM_MODE_BEET is not set
-# CONFIG_IPV6_SIT is not set
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_REDBOOT_PARTS=y
-CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
-CONFIG_MTD_REDBOOT_PARTS_READONLY=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_COMPLEX_MAPPINGS=y
-CONFIG_MTD_IXP2000=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_NBD=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_EEPROM_LEGACY=y
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=y
-CONFIG_NET_ETHERNET=y
-CONFIG_NET_PCI=y
-CONFIG_CS89x0=y
-CONFIG_E100=y
-CONFIG_ENP2611_MSF_NET=y
-CONFIG_WAN=y
-CONFIG_HDLC=y
-CONFIG_HDLC_RAW=y
-CONFIG_HDLC_CISCO=y
-CONFIG_HDLC_FR=y
-CONFIG_HDLC_PPP=y
-CONFIG_DLCI=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=3
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_IXP2000=y
-CONFIG_WATCHDOG=y
-CONFIG_IXP2000_WATCHDOG=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_POSIX_ACL=y
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_POSIX_ACL=y
-CONFIG_INOTIFY=y
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_MUTEXES=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_LL=y
diff --git a/arch/arm/configs/ixp23xx_defconfig b/arch/arm/configs/ixp23xx_defconfig
deleted file mode 100644
index 688717612e91..000000000000
--- a/arch/arm/configs/ixp23xx_defconfig
+++ /dev/null
@@ -1,105 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_EXPERT=y
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_ARCH_IXP23XX=y
-CONFIG_MACH_ESPRESSO=y
-CONFIG_MACH_IXDP2351=y
-CONFIG_MACH_ROADRUNNER=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_CPU_BIG_ENDIAN=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs ip=bootp"
-CONFIG_FPE_NWFPE=y
-CONFIG_FPE_NWFPE_XP=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_SYN_COOKIES=y
-CONFIG_IPV6=y
-# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET6_XFRM_MODE_BEET is not set
-# CONFIG_IPV6_SIT is not set
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-# CONFIG_FW_LOADER is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_REDBOOT_PARTS=y
-CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
-CONFIG_MTD_REDBOOT_PARTS_READONLY=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_COMPLEX_MAPPINGS=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_NBD=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_EEPROM_LEGACY=y
-CONFIG_IDE=y
-CONFIG_BLK_DEV_SIIMAGE=y
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=y
-CONFIG_NET_ETHERNET=y
-CONFIG_NET_PCI=y
-CONFIG_E100=y
-CONFIG_E1000=y
-CONFIG_WAN=y
-CONFIG_HDLC=y
-CONFIG_HDLC_RAW=y
-CONFIG_HDLC_CISCO=y
-CONFIG_HDLC_FR=y
-CONFIG_HDLC_PPP=y
-CONFIG_DLCI=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_WATCHDOG=y
-# CONFIG_USB_HID is not set
-CONFIG_USB=y
-CONFIG_USB_MON=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_UHCI_HCD=y
-CONFIG_USB_STORAGE=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_POSIX_ACL=y
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_POSIX_ACL=y
-CONFIG_INOTIFY=y
-CONFIG_MSDOS_FS=y
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-CONFIG_ROOT_NFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_MUTEXES=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_LL=y
diff --git a/arch/arm/configs/kzm9g_defconfig b/arch/arm/configs/kzm9g_defconfig
new file mode 100644
index 000000000000..e3ebc20ed0a7
--- /dev/null
+++ b/arch/arm/configs/kzm9g_defconfig
@@ -0,0 +1,139 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_EXPERIMENTAL=y
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_EMBEDDED=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_SHMOBILE=y
+CONFIG_KEYBOARD_GPIO_POLLED=y
+CONFIG_ARCH_SH73A0=y
+CONFIG_MACH_KZM9G=y
+CONFIG_MEMORY_START=0x41000000
+CONFIG_MEMORY_SIZE=0x1f000000
+CONFIG_ARM_ERRATA_743622=y
+CONFIG_ARM_ERRATA_754322=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+CONFIG_HIGHMEM=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=tty0 console=ttySC4,115200 root=/dev/nfs ip=dhcp ignore_loglevel earlyprintk=sh-sci.4,115200"
+CONFIG_KEXEC=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+CONFIG_IRDA=y
+CONFIG_SH_IRDA=y
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_NETDEVICES=y
+CONFIG_SMSC911X=y
+# CONFIG_WLAN is not set
+CONFIG_INPUT_SPARSEKMAP=y
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ST1232=y
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=9
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_SH_MOBILE=y
+CONFIG_GPIO_PCF857X=y
+# CONFIG_HWMON is not set
+CONFIG_FB=y
+CONFIG_FB_SH_MOBILE_LCDC=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_LOGO=y
+CONFIG_FB_SH_MOBILE_MERAM=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_DRIVERS is not set
+# CONFIG_SND_ARM is not set
+# CONFIG_SND_USB is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_SH4_FSI=y
+# CONFIG_HID_SUPPORT is not set
+CONFIG_USB=y
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_R8A66597_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_MMC=y
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_SDHI=y
+CONFIG_MMC_SH_MMCIF=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_RTC_CLASS=y
+CONFIG_DMADEVICES=y
+CONFIG_SH_DMAE=y
+CONFIG_ASYNC_TX_DMA=y
+CONFIG_STAGING=y
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_FTRACE is not set
+# CONFIG_ARM_UNWIND is not set
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_DES=y
+CONFIG_CRC16=y
diff --git a/arch/arm/configs/lpc32xx_defconfig b/arch/arm/configs/lpc32xx_defconfig
index fb2088171ca9..4fa60547494a 100644
--- a/arch/arm/configs/lpc32xx_defconfig
+++ b/arch/arm/configs/lpc32xx_defconfig
@@ -2,7 +2,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=14
+CONFIG_LOG_BUF_SHIFT=16
CONFIG_SYSFS_DEPRECATED=y
CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
@@ -10,6 +10,7 @@ CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_EMBEDDED=y
CONFIG_SLAB=y
+CONFIG_JUMP_LABEL=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
@@ -21,6 +22,8 @@ CONFIG_PREEMPT=y
CONFIG_AEABI=y
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_ARM_ATAG_DTB_COMPAT=y
CONFIG_CMDLINE="console=ttyS0,115200n81 root=/dev/ram0"
CONFIG_CPU_IDLE=y
CONFIG_FPE_NWFPE=y
@@ -40,7 +43,8 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_INET_XFRM_MODE_BEET is not set
# CONFIG_INET_LRO is not set
# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
# CONFIG_WIRELESS is not set
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
# CONFIG_FW_LOADER is not set
@@ -55,13 +59,24 @@ CONFIG_BLK_DEV_CRYPTOLOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=1
CONFIG_BLK_DEV_RAM_SIZE=16384
-CONFIG_MISC_DEVICES=y
CONFIG_EEPROM_AT25=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_NETDEVICES=y
CONFIG_MII=y
-CONFIG_PHYLIB=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+CONFIG_LPC_ENET=y
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
CONFIG_SMSC_PHY=y
# CONFIG_WLAN is not set
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
@@ -97,16 +112,22 @@ CONFIG_SND_SEQUENCER=y
CONFIG_SND_MIXER_OSS=y
CONFIG_SND_PCM_OSS=y
CONFIG_SND_SEQUENCER_OSS=y
-CONFIG_SND_DYNAMIC_MINORS=y
+# CONFIG_SND_SUPPORT_OLD_API is not set
# CONFIG_SND_VERBOSE_PROCFS is not set
+CONFIG_SND_DEBUG=y
+CONFIG_SND_DEBUG_VERBOSE=y
# CONFIG_SND_DRIVERS is not set
# CONFIG_SND_ARM is not set
# CONFIG_SND_SPI is not set
CONFIG_SND_SOC=y
# CONFIG_HID_SUPPORT is not set
CONFIG_USB=y
+CONFIG_USB_OHCI_HCD=y
CONFIG_USB_STORAGE=y
-CONFIG_USB_LIBUSUAL=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_LPC32XX=y
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_USB_G_SERIAL=m
CONFIG_MMC=y
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_ARMMMCI=y
@@ -114,10 +135,21 @@ CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_GPIO=y
CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_INTF_DEV_UIE_EMUL=y
+CONFIG_RTC_DRV_DS1374=y
+CONFIG_RTC_DRV_PCF8563=y
CONFIG_RTC_DRV_LPC32XX=y
+CONFIG_DMADEVICES=y
+CONFIG_AMBA_PL08X=y
+CONFIG_STAGING=y
+CONFIG_IIO=y
+CONFIG_LPC32XX_ADC=y
CONFIG_EXT2_FS=y
CONFIG_AUTOFS4_FS=y
CONFIG_MSDOS_FS=y
diff --git a/arch/arm/configs/nhk8815_defconfig b/arch/arm/configs/nhk8815_defconfig
index 37207d1bf44b..bf123c5384d4 100644
--- a/arch/arm/configs/nhk8815_defconfig
+++ b/arch/arm/configs/nhk8815_defconfig
@@ -97,6 +97,7 @@ CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_GPIO=y
CONFIG_DEBUG_GPIO=y
+CONFIG_PINCTRL_NOMADIK=y
# CONFIG_HWMON is not set
# CONFIG_VGA_CONSOLE is not set
CONFIG_RTC_CLASS=y
diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
index d5f00d7eb075..9854ff4279e0 100644
--- a/arch/arm/configs/omap2plus_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -98,6 +98,7 @@ CONFIG_LIBERTAS_USB=m
CONFIG_LIBERTAS_SDIO=m
CONFIG_LIBERTAS_DEBUG=y
CONFIG_USB_USBNET=y
+CONFIG_USB_NET_SMSC95XX=y
CONFIG_USB_ALI_M5632=y
CONFIG_USB_AN2720=y
CONFIG_USB_EPSON2888=y
@@ -175,6 +176,7 @@ CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_DEVICEFS=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_MON=y
+CONFIG_USB_EHCI_HCD=y
CONFIG_USB_WDM=y
CONFIG_USB_STORAGE=y
CONFIG_USB_LIBUSUAL=y
diff --git a/arch/arm/configs/spear3xx_defconfig b/arch/arm/configs/spear3xx_defconfig
index fea7e1f026a3..7ed42912d69a 100644
--- a/arch/arm/configs/spear3xx_defconfig
+++ b/arch/arm/configs/spear3xx_defconfig
@@ -2,33 +2,67 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
CONFIG_PLAT_SPEAR=y
-CONFIG_BOARD_SPEAR300_EVB=y
-CONFIG_BOARD_SPEAR310_EVB=y
-CONFIG_BOARD_SPEAR320_EVB=y
+CONFIG_MACH_SPEAR300=y
+CONFIG_MACH_SPEAR310=y
+CONFIG_MACH_SPEAR320=y
CONFIG_BINFMT_MISC=y
+CONFIG_NET=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_MTD=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_FSMC=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+CONFIG_STMMAC_ETH=y
+# CONFIG_WLAN is not set
CONFIG_INPUT_FF_MEMLESS=y
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_SPEAR=y
# CONFIG_INPUT_MOUSE is not set
+# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
# CONFIG_HW_RANDOM is not set
CONFIG_RAW_DRIVER=y
CONFIG_MAX_RAW_DEVS=8192
+CONFIG_I2C=y
+CONFIG_I2C_DESIGNWARE_PLATFORM=y
+CONFIG_SPI=y
+CONFIG_SPI_PL022=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_PL061=y
# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_ARM_SP805_WATCHDOG=y
+CONFIG_FB=y
+CONFIG_FB_ARMCLCD=y
# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
+CONFIG_USB=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_MMC=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_SPEAR=y
+CONFIG_RTC_CLASS=y
+CONFIG_DMADEVICES=y
+CONFIG_AMBA_PL08X=y
+CONFIG_DMATEST=m
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT2_FS_SECURITY=y
@@ -39,8 +73,6 @@ CONFIG_MSDOS_FS=m
CONFIG_VFAT_FS=m
CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
CONFIG_TMPFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_NLS=y
CONFIG_NLS_DEFAULT="utf8"
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ASCII=m
@@ -48,6 +80,4 @@ CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
CONFIG_DEBUG_INFO=y
-# CONFIG_CRC32 is not set
diff --git a/arch/arm/configs/spear6xx_defconfig b/arch/arm/configs/spear6xx_defconfig
index cef2e836afd2..cf94bc73a0e0 100644
--- a/arch/arm/configs/spear6xx_defconfig
+++ b/arch/arm/configs/spear6xx_defconfig
@@ -2,29 +2,58 @@ CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_BLK_DEV_INITRD=y
-CONFIG_KALLSYMS_EXTRA_PASS=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
CONFIG_PLAT_SPEAR=y
CONFIG_ARCH_SPEAR6XX=y
-CONFIG_BOARD_SPEAR600_EVB=y
+CONFIG_BOARD_SPEAR600_DT=y
CONFIG_BINFMT_MISC=y
+CONFIG_NET=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_MTD=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_FSMC=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+CONFIG_STMMAC_ETH=y
+# CONFIG_WLAN is not set
CONFIG_INPUT_FF_MEMLESS=y
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
CONFIG_RAW_DRIVER=y
CONFIG_MAX_RAW_DEVS=8192
+CONFIG_I2C=y
+CONFIG_I2C_DESIGNWARE_PLATFORM=y
+CONFIG_SPI=y
+CONFIG_SPI_PL022=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_PL061=y
# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+CONFIG_ARM_SP805_WATCHDOG=y
# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
+CONFIG_USB=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_RTC_CLASS=y
+CONFIG_DMADEVICES=y
+CONFIG_AMBA_PL08X=y
+CONFIG_DMATEST=m
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT2_FS_SECURITY=y
@@ -35,8 +64,6 @@ CONFIG_MSDOS_FS=m
CONFIG_VFAT_FS=m
CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
CONFIG_TMPFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_NLS=y
CONFIG_NLS_DEFAULT="utf8"
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ASCII=m
@@ -44,6 +71,4 @@ CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
CONFIG_DEBUG_INFO=y
-# CONFIG_CRC32 is not set
diff --git a/arch/arm/include/asm/hardware/cs89712.h b/arch/arm/include/asm/hardware/cs89712.h
deleted file mode 100644
index f75626933e94..000000000000
--- a/arch/arm/include/asm/hardware/cs89712.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * arch/arm/include/asm/hardware/cs89712.h
- *
- * This file contains the hardware definitions of the CS89712
- * additional internal registers.
- *
- * Copyright (C) 2001 Thomas Gleixner autronix automation <gleixner@autronix.de>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef __ASM_HARDWARE_CS89712_H
-#define __ASM_HARDWARE_CS89712_H
-
-/*
-* CS89712 additional registers
-*/
-
-#define PCDR 0x0002 /* Port C Data register ---------------------------- */
-#define PCDDR 0x0042 /* Port C Data Direction register ------------------ */
-#define SDCONF 0x2300 /* SDRAM Configuration register ---------------------*/
-#define SDRFPR 0x2340 /* SDRAM Refresh period register --------------------*/
-
-#define SDCONF_ACTIVE (1 << 10)
-#define SDCONF_CLKCTL (1 << 9)
-#define SDCONF_WIDTH_4 (0 << 7)
-#define SDCONF_WIDTH_8 (1 << 7)
-#define SDCONF_WIDTH_16 (2 << 7)
-#define SDCONF_WIDTH_32 (3 << 7)
-#define SDCONF_SIZE_16 (0 << 5)
-#define SDCONF_SIZE_64 (1 << 5)
-#define SDCONF_SIZE_128 (2 << 5)
-#define SDCONF_SIZE_256 (3 << 5)
-#define SDCONF_CASLAT_2 (2)
-#define SDCONF_CASLAT_3 (3)
-
-#endif /* __ASM_HARDWARE_CS89712_H */
diff --git a/arch/arm/include/asm/hardware/ep7212.h b/arch/arm/include/asm/hardware/ep7212.h
deleted file mode 100644
index 3b43bbeaf1db..000000000000
--- a/arch/arm/include/asm/hardware/ep7212.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * arch/arm/include/asm/hardware/ep7212.h
- *
- * This file contains the hardware definitions of the EP7212 internal
- * registers.
- *
- * Copyright (C) 2000 Deep Blue Solutions Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef __ASM_HARDWARE_EP7212_H
-#define __ASM_HARDWARE_EP7212_H
-
-/*
- * define EP7212_BASE to be the base address of the region
- * you want to access.
- */
-
-#define EP7212_PHYS_BASE (0x80000000)
-
-#ifndef __ASSEMBLY__
-#define ep_readl(off) __raw_readl(EP7212_BASE + (off))
-#define ep_writel(val,off) __raw_writel(val, EP7212_BASE + (off))
-#endif
-
-/*
- * These registers are specific to the EP7212 only
- */
-#define DAIR 0x2000
-#define DAIR0 0x2040
-#define DAIDR1 0x2080
-#define DAIDR2 0x20c0
-#define DAISR 0x2100
-#define SYSCON3 0x2200
-#define INTSR3 0x2240
-#define INTMR3 0x2280
-#define LEDFLSH 0x22c0
-
-#define DAIR_DAIEN (1 << 16)
-#define DAIR_ECS (1 << 17)
-#define DAIR_LCTM (1 << 19)
-#define DAIR_LCRM (1 << 20)
-#define DAIR_RCTM (1 << 21)
-#define DAIR_RCRM (1 << 22)
-#define DAIR_LBM (1 << 23)
-
-#define DAIDR2_FIFOEN (1 << 15)
-#define DAIDR2_FIFOLEFT (0x0d << 16)
-#define DAIDR2_FIFORIGHT (0x11 << 16)
-
-#define DAISR_RCTS (1 << 0)
-#define DAISR_RCRS (1 << 1)
-#define DAISR_LCTS (1 << 2)
-#define DAISR_LCRS (1 << 3)
-#define DAISR_RCTU (1 << 4)
-#define DAISR_RCRO (1 << 5)
-#define DAISR_LCTU (1 << 6)
-#define DAISR_LCRO (1 << 7)
-#define DAISR_RCNF (1 << 8)
-#define DAISR_RCNE (1 << 9)
-#define DAISR_LCNF (1 << 10)
-#define DAISR_LCNE (1 << 11)
-#define DAISR_FIFO (1 << 12)
-
-#define SYSCON3_ADCCON (1 << 0)
-#define SYSCON3_DAISEL (1 << 3)
-#define SYSCON3_ADCCKNSEN (1 << 4)
-#define SYSCON3_FASTWAKE (1 << 8)
-#define SYSCON3_DAIEN (1 << 9)
-
-#endif /* __ASM_HARDWARE_EP7212_H */
diff --git a/arch/arm/include/asm/hardware/uengine.h b/arch/arm/include/asm/hardware/uengine.h
deleted file mode 100644
index b442d65c6593..000000000000
--- a/arch/arm/include/asm/hardware/uengine.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Generic library functions for the microengines found on the Intel
- * IXP2000 series of network processors.
- *
- * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org>
- * Dedicated to Marija Kulikova.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of the
- * License, or (at your option) any later version.
- */
-
-#ifndef __IXP2000_UENGINE_H
-#define __IXP2000_UENGINE_H
-
-extern u32 ixp2000_uengine_mask;
-
-struct ixp2000_uengine_code
-{
- u32 cpu_model_bitmask;
- u8 cpu_min_revision;
- u8 cpu_max_revision;
-
- u32 uengine_parameters;
-
- struct ixp2000_reg_value {
- int reg;
- u32 value;
- } *initial_reg_values;
-
- int num_insns;
- u8 *insns;
-};
-
-u32 ixp2000_uengine_csr_read(int uengine, int offset);
-void ixp2000_uengine_csr_write(int uengine, int offset, u32 value);
-void ixp2000_uengine_reset(u32 uengine_mask);
-void ixp2000_uengine_set_mode(int uengine, u32 mode);
-void ixp2000_uengine_load_microcode(int uengine, u8 *ucode, int insns);
-void ixp2000_uengine_init_context(int uengine, int context, int pc);
-void ixp2000_uengine_start_contexts(int uengine, u8 ctx_mask);
-void ixp2000_uengine_stop_contexts(int uengine, u8 ctx_mask);
-int ixp2000_uengine_load(int uengine, struct ixp2000_uengine_code *c);
-
-#define IXP2000_UENGINE_8_CONTEXTS 0x00000000
-#define IXP2000_UENGINE_4_CONTEXTS 0x80000000
-#define IXP2000_UENGINE_PRN_UPDATE_EVERY 0x40000000
-#define IXP2000_UENGINE_PRN_UPDATE_ON_ACCESS 0x00000000
-#define IXP2000_UENGINE_NN_FROM_SELF 0x00100000
-#define IXP2000_UENGINE_NN_FROM_PREVIOUS 0x00000000
-#define IXP2000_UENGINE_ASSERT_EMPTY_AT_3 0x000c0000
-#define IXP2000_UENGINE_ASSERT_EMPTY_AT_2 0x00080000
-#define IXP2000_UENGINE_ASSERT_EMPTY_AT_1 0x00040000
-#define IXP2000_UENGINE_ASSERT_EMPTY_AT_0 0x00000000
-#define IXP2000_UENGINE_LM_ADDR1_GLOBAL 0x00020000
-#define IXP2000_UENGINE_LM_ADDR1_PER_CONTEXT 0x00000000
-#define IXP2000_UENGINE_LM_ADDR0_GLOBAL 0x00010000
-#define IXP2000_UENGINE_LM_ADDR0_PER_CONTEXT 0x00000000
-
-
-#endif
diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h
index d7038fa22343..99afa7498260 100644
--- a/arch/arm/include/asm/processor.h
+++ b/arch/arm/include/asm/processor.h
@@ -77,9 +77,6 @@ struct task_struct;
/* Free all resources held by a thread. */
extern void release_thread(struct task_struct *);
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk) do { } while (0)
-
unsigned long get_wchan(struct task_struct *p);
#if __LINUX_ARM_ARCH__ == 6 || defined(CONFIG_ARM_ERRATA_754327)
diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c
index b78af0cc6ef3..ab627a740fa3 100644
--- a/arch/arm/kernel/perf_event_v6.c
+++ b/arch/arm/kernel/perf_event_v6.c
@@ -489,8 +489,6 @@ armv6pmu_handle_irq(int irq_num,
*/
armv6_pmcr_write(pmcr);
- perf_sample_data_init(&data, 0);
-
cpuc = &__get_cpu_var(cpu_hw_events);
for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
struct perf_event *event = cpuc->events[idx];
@@ -509,7 +507,7 @@ armv6pmu_handle_irq(int irq_num,
hwc = &event->hw;
armpmu_event_update(event, hwc, idx);
- data.period = event->hw.last_period;
+ perf_sample_data_init(&data, 0, hwc->last_period);
if (!armpmu_event_set_period(event, hwc, idx))
continue;
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index 00755d82e2f2..d3c536068162 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -1077,8 +1077,6 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)
*/
regs = get_irq_regs();
- perf_sample_data_init(&data, 0);
-
cpuc = &__get_cpu_var(cpu_hw_events);
for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
struct perf_event *event = cpuc->events[idx];
@@ -1097,7 +1095,7 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)
hwc = &event->hw;
armpmu_event_update(event, hwc, idx);
- data.period = event->hw.last_period;
+ perf_sample_data_init(&data, 0, hwc->last_period);
if (!armpmu_event_set_period(event, hwc, idx))
continue;
diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c
index 71a21e6712f5..e34e7254e652 100644
--- a/arch/arm/kernel/perf_event_xscale.c
+++ b/arch/arm/kernel/perf_event_xscale.c
@@ -248,8 +248,6 @@ xscale1pmu_handle_irq(int irq_num, void *dev)
regs = get_irq_regs();
- perf_sample_data_init(&data, 0);
-
cpuc = &__get_cpu_var(cpu_hw_events);
for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
struct perf_event *event = cpuc->events[idx];
@@ -263,7 +261,7 @@ xscale1pmu_handle_irq(int irq_num, void *dev)
hwc = &event->hw;
armpmu_event_update(event, hwc, idx);
- data.period = event->hw.last_period;
+ perf_sample_data_init(&data, 0, hwc->last_period);
if (!armpmu_event_set_period(event, hwc, idx))
continue;
@@ -588,8 +586,6 @@ xscale2pmu_handle_irq(int irq_num, void *dev)
regs = get_irq_regs();
- perf_sample_data_init(&data, 0);
-
cpuc = &__get_cpu_var(cpu_hw_events);
for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
struct perf_event *event = cpuc->events[idx];
@@ -603,7 +599,7 @@ xscale2pmu_handle_irq(int irq_num, void *dev)
hwc = &event->hw;
armpmu_event_update(event, hwc, idx);
- data.period = event->hw.last_period;
+ perf_sample_data_init(&data, 0, hwc->last_period);
if (!armpmu_event_set_period(event, hwc, idx))
continue;
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 73d9a420850d..4e5fdd9bd9e3 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -67,17 +67,8 @@ const unsigned long syscall_restart_code[2] = {
asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask)
{
sigset_t blocked;
-
- current->saved_sigmask = current->blocked;
-
- mask &= _BLOCKABLE;
siginitset(&blocked, mask);
- set_current_blocked(&blocked);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_restore_sigmask();
- return -ERESTARTNOHAND;
+ return sigsuspend(&blocked);
}
asmlinkage int
diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c
index af0aaebf4de6..3e94811690ce 100644
--- a/arch/arm/kernel/sys_oabi-compat.c
+++ b/arch/arm/kernel/sys_oabi-compat.c
@@ -124,8 +124,8 @@ static long cp_oldabi_stat64(struct kstat *stat,
tmp.__st_ino = stat->ino;
tmp.st_mode = stat->mode;
tmp.st_nlink = stat->nlink;
- tmp.st_uid = stat->uid;
- tmp.st_gid = stat->gid;
+ tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid);
+ tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid);
tmp.st_rdev = huge_encode_dev(stat->rdev);
tmp.st_size = stat->size;
tmp.st_blocks = stat->blocks;
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 45db05d8d94c..19505c0a3f01 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -9,15 +9,6 @@ config HAVE_AT91_DBGU0
config HAVE_AT91_DBGU1
bool
-config HAVE_AT91_USART3
- bool
-
-config HAVE_AT91_USART4
- bool
-
-config HAVE_AT91_USART5
- bool
-
config AT91_SAM9_ALT_RESET
bool
default !ARCH_AT91X40
@@ -26,87 +17,129 @@ config AT91_SAM9G45_RESET
bool
default !ARCH_AT91X40
+config SOC_AT91SAM9
+ bool
+ select GENERIC_CLOCKEVENTS
+ select CPU_ARM926T
+
menu "Atmel AT91 System-on-Chip"
-choice
- prompt "Atmel AT91 Processor"
+comment "Atmel AT91 Processor"
-config ARCH_AT91RM9200
+config SOC_AT91SAM9
+ bool
+ select CPU_ARM926T
+ select AT91_SAM9_TIME
+ select AT91_SAM9_SMC
+
+config SOC_AT91RM9200
bool "AT91RM9200"
select CPU_ARM920T
select GENERIC_CLOCKEVENTS
select HAVE_AT91_DBGU0
- select HAVE_AT91_USART3
-config ARCH_AT91SAM9260
- bool "AT91SAM9260 or AT91SAM9XE"
- select CPU_ARM926T
- select GENERIC_CLOCKEVENTS
+config SOC_AT91SAM9260
+ bool "AT91SAM9260, AT91SAM9XE or AT91SAM9G20"
+ select SOC_AT91SAM9
select HAVE_AT91_DBGU0
- select HAVE_AT91_USART3
- select HAVE_AT91_USART4
- select HAVE_AT91_USART5
select HAVE_NET_MACB
+ help
+ Select this if you are using one of Atmel's AT91SAM9260, AT91SAM9XE
+ or AT91SAM9G20 SoC.
-config ARCH_AT91SAM9261
- bool "AT91SAM9261"
- select CPU_ARM926T
- select GENERIC_CLOCKEVENTS
- select HAVE_FB_ATMEL
- select HAVE_AT91_DBGU0
-
-config ARCH_AT91SAM9G10
- bool "AT91SAM9G10"
- select CPU_ARM926T
- select GENERIC_CLOCKEVENTS
+config SOC_AT91SAM9261
+ bool "AT91SAM9261 or AT91SAM9G10"
+ select SOC_AT91SAM9
select HAVE_AT91_DBGU0
select HAVE_FB_ATMEL
+ help
+ Select this if you are using one of Atmel's AT91SAM9261 or AT91SAM9G10 SoC.
-config ARCH_AT91SAM9263
+config SOC_AT91SAM9263
bool "AT91SAM9263"
- select CPU_ARM926T
- select GENERIC_CLOCKEVENTS
+ select SOC_AT91SAM9
+ select HAVE_AT91_DBGU1
select HAVE_FB_ATMEL
select HAVE_NET_MACB
- select HAVE_AT91_DBGU1
-config ARCH_AT91SAM9RL
+config SOC_AT91SAM9RL
bool "AT91SAM9RL"
- select CPU_ARM926T
- select GENERIC_CLOCKEVENTS
- select HAVE_AT91_USART3
- select HAVE_FB_ATMEL
- select HAVE_AT91_DBGU0
-
-config ARCH_AT91SAM9G20
- bool "AT91SAM9G20"
- select CPU_ARM926T
- select GENERIC_CLOCKEVENTS
+ select SOC_AT91SAM9
select HAVE_AT91_DBGU0
- select HAVE_AT91_USART3
- select HAVE_AT91_USART4
- select HAVE_AT91_USART5
- select HAVE_NET_MACB
+ select HAVE_FB_ATMEL
-config ARCH_AT91SAM9G45
- bool "AT91SAM9G45"
- select CPU_ARM926T
- select GENERIC_CLOCKEVENTS
- select HAVE_AT91_USART3
+config SOC_AT91SAM9G45
+ bool "AT91SAM9G45 or AT91SAM9M10 families"
+ select SOC_AT91SAM9
+ select HAVE_AT91_DBGU1
select HAVE_FB_ATMEL
select HAVE_NET_MACB
- select HAVE_AT91_DBGU1
+ help
+ Select this if you are using one of Atmel's AT91SAM9G45 family SoC.
+ This support covers AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11.
-config ARCH_AT91SAM9X5
+config SOC_AT91SAM9X5
bool "AT91SAM9x5 family"
- select CPU_ARM926T
- select GENERIC_CLOCKEVENTS
+ select SOC_AT91SAM9
+ select HAVE_AT91_DBGU0
select HAVE_FB_ATMEL
select HAVE_NET_MACB
+ help
+ Select this if you are using one of Atmel's AT91SAM9x5 family SoC.
+ This means that your SAM9 name finishes with a '5' (except if it is
+ AT91SAM9G45!).
+ This support covers AT91SAM9G15, AT91SAM9G25, AT91SAM9X25, AT91SAM9G35
+ and AT91SAM9X35.
+
+config SOC_AT91SAM9N12
+ bool "AT91SAM9N12 family"
+ select SOC_AT91SAM9
select HAVE_AT91_DBGU0
+ select HAVE_FB_ATMEL
+ help
+ Select this if you are using Atmel's AT91SAM9N12 SoC.
+
+choice
+ prompt "Atmel AT91 Processor Devices for non DT boards"
+
+config ARCH_AT91_NONE
+ bool "None"
+
+config ARCH_AT91RM9200
+ bool "AT91RM9200"
+ select SOC_AT91RM9200
+
+config ARCH_AT91SAM9260
+ bool "AT91SAM9260 or AT91SAM9XE"
+ select SOC_AT91SAM9260
+
+config ARCH_AT91SAM9261
+ bool "AT91SAM9261"
+ select SOC_AT91SAM9261
+
+config ARCH_AT91SAM9G10
+ bool "AT91SAM9G10"
+ select SOC_AT91SAM9261
+
+config ARCH_AT91SAM9263
+ bool "AT91SAM9263"
+ select SOC_AT91SAM9263
+
+config ARCH_AT91SAM9RL
+ bool "AT91SAM9RL"
+ select SOC_AT91SAM9RL
+
+config ARCH_AT91SAM9G20
+ bool "AT91SAM9G20"
+ select SOC_AT91SAM9260
+
+config ARCH_AT91SAM9G45
+ bool "AT91SAM9G45"
+ select SOC_AT91SAM9G45
config ARCH_AT91X40
bool "AT91x40"
+ depends on !MMU
select ARCH_USES_GETTIMEOFFSET
endchoice
@@ -364,6 +397,7 @@ config MACH_AT91SAM9G20EK_2MMC
Select this if you are using an Atmel AT91SAM9G20-EK Evaluation Kit
with 2 SD/MMC Slots. This is the case for AT91SAM9G20-EK rev. C and
onwards.
+ <http://www.atmel.com/tools/SAM9G20-EK.aspx>
config MACH_CPU9G20
bool "Eukrea CPU9G20 board"
@@ -433,9 +467,10 @@ comment "AT91SAM9G45 Board Type"
config MACH_AT91SAM9M10G45EK
bool "Atmel AT91SAM9M10G45-EK Evaluation Kits"
help
- Select this if you are using Atmel's AT91SAM9G45-EKES Evaluation Kit.
- "ES" at the end of the name means that this board is an
- Engineering Sample.
+ Select this if you are using Atmel's AT91SAM9M10G45-EK Evaluation Kit.
+ Those boards can be populated with any SoC of AT91SAM9G45 or AT91SAM9M10
+ families: AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11.
+ <http://www.atmel.com/tools/SAM9M10-G45-EK.aspx>
endif
@@ -515,41 +550,6 @@ config AT91_TIMER_HZ
system clock (of at least several MHz), rounding is less of a
problem so it can be safer to use a decimal values like 100.
-choice
- prompt "Select a UART for early kernel messages"
-
-config AT91_EARLY_DBGU0
- bool "DBGU on rm9200, 9260/9g20, 9261/9g10 and 9rl"
- depends on HAVE_AT91_DBGU0
-
-config AT91_EARLY_DBGU1
- bool "DBGU on 9263 and 9g45"
- depends on HAVE_AT91_DBGU1
-
-config AT91_EARLY_USART0
- bool "USART0"
-
-config AT91_EARLY_USART1
- bool "USART1"
-
-config AT91_EARLY_USART2
- bool "USART2"
- depends on ! ARCH_AT91X40
-
-config AT91_EARLY_USART3
- bool "USART3"
- depends on HAVE_AT91_USART3
-
-config AT91_EARLY_USART4
- bool "USART4"
- depends on HAVE_AT91_USART4
-
-config AT91_EARLY_USART5
- bool "USART5"
- depends on HAVE_AT91_USART5
-
-endchoice
-
endmenu
endif
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index 8512e53bed93..3bb7a51efc9d 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -10,17 +10,26 @@ obj- :=
obj-$(CONFIG_AT91_PMC_UNIT) += clock.o
obj-$(CONFIG_AT91_SAM9_ALT_RESET) += at91sam9_alt_reset.o
obj-$(CONFIG_AT91_SAM9G45_RESET) += at91sam9g45_reset.o
+obj-$(CONFIG_SOC_AT91SAM9) += at91sam926x_time.o sam9_smc.o
# CPU-specific support
-obj-$(CONFIG_ARCH_AT91RM9200) += at91rm9200.o at91rm9200_time.o at91rm9200_devices.o
-obj-$(CONFIG_ARCH_AT91SAM9260) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9261) += at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9G10) += at91sam9261.o at91sam926x_time.o at91sam9261_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263.o at91sam926x_time.o at91sam9263_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl.o at91sam926x_time.o at91sam9rl_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam926x_time.o at91sam9260_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45.o at91sam926x_time.o at91sam9g45_devices.o sam9_smc.o
-obj-$(CONFIG_ARCH_AT91SAM9X5) += at91sam9x5.o at91sam926x_time.o sam9_smc.o
+obj-$(CONFIG_SOC_AT91RM9200) += at91rm9200.o at91rm9200_time.o
+obj-$(CONFIG_SOC_AT91SAM9260) += at91sam9260.o
+obj-$(CONFIG_SOC_AT91SAM9261) += at91sam9261.o
+obj-$(CONFIG_SOC_AT91SAM9263) += at91sam9263.o
+obj-$(CONFIG_SOC_AT91SAM9G45) += at91sam9g45.o
+obj-$(CONFIG_SOC_AT91SAM9N12) += at91sam9n12.o
+obj-$(CONFIG_SOC_AT91SAM9X5) += at91sam9x5.o
+obj-$(CONFIG_SOC_AT91SAM9RL) += at91sam9rl.o
+
+obj-$(CONFIG_ARCH_AT91RM9200) += at91rm9200_devices.o
+obj-$(CONFIG_ARCH_AT91SAM9260) += at91sam9260_devices.o
+obj-$(CONFIG_ARCH_AT91SAM9261) += at91sam9261_devices.o
+obj-$(CONFIG_ARCH_AT91SAM9G10) += at91sam9261_devices.o
+obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263_devices.o
+obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl_devices.o
+obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260_devices.o
+obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45_devices.o
obj-$(CONFIG_ARCH_AT91X40) += at91x40.o at91x40_time.o
# AT91RM9200 board-specific support
diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
index 0da66ca4a4f8..9e84fe4f2aaa 100644
--- a/arch/arm/mach-at91/Makefile.boot
+++ b/arch/arm/mach-at91/Makefile.boot
@@ -14,9 +14,23 @@ initrd_phys-y := 0x20410000
endif
# Keep dtb files sorted alphabetically for each SoC
+# sam9260
+dtb-$(CONFIG_MACH_AT91SAM_DT) += ethernut5.dtb
+dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9260.dtb
+dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9260.dtb
+# sam9263
+dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9263ek.dtb
+dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9263.dtb
+dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9263.dtb
# sam9g20
+dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek.dtb
+dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g20ek_2mmc.dtb
+dtb-$(CONFIG_MACH_AT91SAM_DT) += kizbox.dtb
+dtb-$(CONFIG_MACH_AT91SAM_DT) += tny_a9g20.dtb
dtb-$(CONFIG_MACH_AT91SAM_DT) += usb_a9g20.dtb
# sam9g45
dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9m10g45ek.dtb
+# sam9n12
+dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9n12ek.dtb
# sam9x5
dtb-$(CONFIG_MACH_AT91SAM_DT) += at91sam9g25ek.dtb
diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
index 89106792d067..26917687fc30 100644
--- a/arch/arm/mach-at91/at91rm9200.c
+++ b/arch/arm/mach-at91/at91rm9200.c
@@ -249,18 +249,6 @@ static void __init at91rm9200_register_clocks(void)
clk_register(&pck3);
}
-static struct clk_lookup console_clock_lookup;
-
-void __init at91rm9200_set_console_clock(int id)
-{
- if (id >= ARRAY_SIZE(usart_clocks_lookups))
- return;
-
- console_clock_lookup.con_id = "usart";
- console_clock_lookup.clk = usart_clocks_lookups[id].clk;
- clkdev_add(&console_clock_lookup);
-}
-
/* --------------------------------------------------------------------
* GPIO
* -------------------------------------------------------------------- */
diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
index 60c472861e5e..e6b7d0533dd7 100644
--- a/arch/arm/mach-at91/at91rm9200_devices.c
+++ b/arch/arm/mach-at91/at91rm9200_devices.c
@@ -1152,14 +1152,6 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
at91_uarts[portnr] = pdev;
}
-void __init at91_set_serial_console(unsigned portnr)
-{
- if (portnr < ATMEL_MAX_UART) {
- atmel_default_console_device = at91_uarts[portnr];
- at91rm9200_set_console_clock(at91_uarts[portnr]->id);
- }
-}
-
void __init at91_add_device_serial(void)
{
int i;
@@ -1168,13 +1160,9 @@ void __init at91_add_device_serial(void)
if (at91_uarts[i])
platform_device_register(at91_uarts[i]);
}
-
- if (!atmel_default_console_device)
- printk(KERN_INFO "AT91: No default serial console defined.\n");
}
#else
void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
-void __init at91_set_serial_console(unsigned portnr) {}
void __init at91_add_device_serial(void) {}
#endif
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index 46f774233298..2b1e438ed878 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -55,6 +55,13 @@ static struct clk adc_clk = {
.pmc_mask = 1 << AT91SAM9260_ID_ADC,
.type = CLK_TYPE_PERIPHERAL,
};
+
+static struct clk adc_op_clk = {
+ .name = "adc_op_clk",
+ .type = CLK_TYPE_PERIPHERAL,
+ .rate_hz = 5000000,
+};
+
static struct clk usart0_clk = {
.name = "usart0_clk",
.pmc_mask = 1 << AT91SAM9260_ID_US0,
@@ -166,6 +173,7 @@ static struct clk *periph_clocks[] __initdata = {
&pioB_clk,
&pioC_clk,
&adc_clk,
+ &adc_op_clk,
&usart0_clk,
&usart1_clk,
&usart2_clk,
@@ -268,18 +276,6 @@ static void __init at91sam9260_register_clocks(void)
clk_register(&pck1);
}
-static struct clk_lookup console_clock_lookup;
-
-void __init at91sam9260_set_console_clock(int id)
-{
- if (id >= ARRAY_SIZE(usart_clocks_lookups))
- return;
-
- console_clock_lookup.con_id = "usart";
- console_clock_lookup.clk = usart_clocks_lookups[id].clk;
- clkdev_add(&console_clock_lookup);
-}
-
/* --------------------------------------------------------------------
* GPIO
* -------------------------------------------------------------------- */
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index 5652dde4bbe2..0ded951f785a 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -17,12 +17,15 @@
#include <linux/platform_device.h>
#include <linux/i2c-gpio.h>
+#include <linux/platform_data/at91_adc.h>
+
#include <mach/board.h>
#include <mach/cpu.h>
#include <mach/at91sam9260.h>
#include <mach/at91sam9260_matrix.h>
#include <mach/at91_matrix.h>
#include <mach/at91sam9_smc.h>
+#include <mach/at91_adc.h>
#include "generic.h"
@@ -702,25 +705,8 @@ static struct platform_device at91sam9260_tcb1_device = {
.num_resources = ARRAY_SIZE(tcb1_resources),
};
-#if defined(CONFIG_OF)
-static struct of_device_id tcb_ids[] = {
- { .compatible = "atmel,at91rm9200-tcb" },
- { /*sentinel*/ }
-};
-#endif
-
static void __init at91_add_device_tc(void)
{
-#if defined(CONFIG_OF)
- struct device_node *np;
-
- np = of_find_matching_node(NULL, tcb_ids);
- if (np) {
- of_node_put(np);
- return;
- }
-#endif
-
platform_device_register(&at91sam9260_tcb0_device);
platform_device_register(&at91sam9260_tcb1_device);
}
@@ -1229,14 +1215,6 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
at91_uarts[portnr] = pdev;
}
-void __init at91_set_serial_console(unsigned portnr)
-{
- if (portnr < ATMEL_MAX_UART) {
- atmel_default_console_device = at91_uarts[portnr];
- at91sam9260_set_console_clock(at91_uarts[portnr]->id);
- }
-}
-
void __init at91_add_device_serial(void)
{
int i;
@@ -1245,13 +1223,9 @@ void __init at91_add_device_serial(void)
if (at91_uarts[i])
platform_device_register(at91_uarts[i]);
}
-
- if (!atmel_default_console_device)
- printk(KERN_INFO "AT91: No default serial console defined.\n");
}
#else
void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
-void __init at91_set_serial_console(unsigned portnr) {}
void __init at91_add_device_serial(void) {}
#endif
@@ -1369,6 +1343,93 @@ void __init at91_add_device_cf(struct at91_cf_data *data)
void __init at91_add_device_cf(struct at91_cf_data * data) {}
#endif
+/* --------------------------------------------------------------------
+ * ADCs
+ * -------------------------------------------------------------------- */
+
+#if IS_ENABLED(CONFIG_AT91_ADC)
+static struct at91_adc_data adc_data;
+
+static struct resource adc_resources[] = {
+ [0] = {
+ .start = AT91SAM9260_BASE_ADC,
+ .end = AT91SAM9260_BASE_ADC + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9260_ID_ADC,
+ .end = AT91SAM9260_ID_ADC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device at91_adc_device = {
+ .name = "at91_adc",
+ .id = -1,
+ .dev = {
+ .platform_data = &adc_data,
+ },
+ .resource = adc_resources,
+ .num_resources = ARRAY_SIZE(adc_resources),
+};
+
+static struct at91_adc_trigger at91_adc_triggers[] = {
+ [0] = {
+ .name = "timer-counter-0",
+ .value = AT91_ADC_TRGSEL_TC0 | AT91_ADC_TRGEN,
+ },
+ [1] = {
+ .name = "timer-counter-1",
+ .value = AT91_ADC_TRGSEL_TC1 | AT91_ADC_TRGEN,
+ },
+ [2] = {
+ .name = "timer-counter-2",
+ .value = AT91_ADC_TRGSEL_TC2 | AT91_ADC_TRGEN,
+ },
+ [3] = {
+ .name = "external",
+ .value = AT91_ADC_TRGSEL_EXTERNAL | AT91_ADC_TRGEN,
+ .is_external = true,
+ },
+};
+
+static struct at91_adc_reg_desc at91_adc_register_g20 = {
+ .channel_base = AT91_ADC_CHR(0),
+ .drdy_mask = AT91_ADC_DRDY,
+ .status_register = AT91_ADC_SR,
+ .trigger_register = AT91_ADC_MR,
+};
+
+void __init at91_add_device_adc(struct at91_adc_data *data)
+{
+ if (!data)
+ return;
+
+ if (test_bit(0, &data->channels_used))
+ at91_set_A_periph(AT91_PIN_PC0, 0);
+ if (test_bit(1, &data->channels_used))
+ at91_set_A_periph(AT91_PIN_PC1, 0);
+ if (test_bit(2, &data->channels_used))
+ at91_set_A_periph(AT91_PIN_PC2, 0);
+ if (test_bit(3, &data->channels_used))
+ at91_set_A_periph(AT91_PIN_PC3, 0);
+
+ if (data->use_external_triggers)
+ at91_set_A_periph(AT91_PIN_PA22, 0);
+
+ data->num_channels = 4;
+ data->startup_time = 10;
+ data->registers = &at91_adc_register_g20;
+ data->trigger_number = 4;
+ data->trigger_list = at91_adc_triggers;
+
+ adc_data = *data;
+ platform_device_register(&at91_adc_device);
+}
+#else
+void __init at91_add_device_adc(struct at91_adc_data *data) {}
+#endif
+
/* -------------------------------------------------------------------- */
/*
* These devices are always present and don't need any board-specific
@@ -1376,6 +1437,9 @@ void __init at91_add_device_cf(struct at91_cf_data * data) {}
*/
static int __init at91_add_standard_devices(void)
{
+ if (of_have_populated_dt())
+ return 0;
+
at91_add_device_rtt();
at91_add_device_watchdog();
at91_add_device_tc();
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index 7de81e6222f1..c77d503d09d1 100644
--- a/arch/arm/mach-at91/at91sam9261.c
+++ b/arch/arm/mach-at91/at91sam9261.c
@@ -239,18 +239,6 @@ static void __init at91sam9261_register_clocks(void)
clk_register(&hck1);
}
-static struct clk_lookup console_clock_lookup;
-
-void __init at91sam9261_set_console_clock(int id)
-{
- if (id >= ARRAY_SIZE(usart_clocks_lookups))
- return;
-
- console_clock_lookup.con_id = "usart";
- console_clock_lookup.clk = usart_clocks_lookups[id].clk;
- clkdev_add(&console_clock_lookup);
-}
-
/* --------------------------------------------------------------------
* GPIO
* -------------------------------------------------------------------- */
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index 4db961a93085..9295e90b08ff 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -1051,14 +1051,6 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
at91_uarts[portnr] = pdev;
}
-void __init at91_set_serial_console(unsigned portnr)
-{
- if (portnr < ATMEL_MAX_UART) {
- atmel_default_console_device = at91_uarts[portnr];
- at91sam9261_set_console_clock(at91_uarts[portnr]->id);
- }
-}
-
void __init at91_add_device_serial(void)
{
int i;
@@ -1067,13 +1059,9 @@ void __init at91_add_device_serial(void)
if (at91_uarts[i])
platform_device_register(at91_uarts[i]);
}
-
- if (!atmel_default_console_device)
- printk(KERN_INFO "AT91: No default serial console defined.\n");
}
#else
void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
-void __init at91_set_serial_console(unsigned portnr) {}
void __init at91_add_device_serial(void) {}
#endif
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index ef301be66575..ed91c7e9f7c2 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -199,6 +199,16 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_ID("pioC", &pioCDE_clk),
CLKDEV_CON_ID("pioD", &pioCDE_clk),
CLKDEV_CON_ID("pioE", &pioCDE_clk),
+ /* more usart lookup table for DT entries */
+ CLKDEV_CON_DEV_ID("usart", "ffffee00.serial", &mck),
+ CLKDEV_CON_DEV_ID("usart", "fff8c000.serial", &usart0_clk),
+ CLKDEV_CON_DEV_ID("usart", "fff90000.serial", &usart1_clk),
+ CLKDEV_CON_DEV_ID("usart", "fff94000.serial", &usart2_clk),
+ /* more tc lookup table for DT entries */
+ CLKDEV_CON_DEV_ID("t0_clk", "fff7c000.timer", &tcb_clk),
+ CLKDEV_CON_DEV_ID("hclk", "a00000.ohci", &ohci_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "fffa4000.spi", &spi0_clk),
+ CLKDEV_CON_DEV_ID("spi_clk", "fffa8000.spi", &spi1_clk),
};
static struct clk_lookup usart_clocks_lookups[] = {
@@ -255,18 +265,6 @@ static void __init at91sam9263_register_clocks(void)
clk_register(&pck3);
}
-static struct clk_lookup console_clock_lookup;
-
-void __init at91sam9263_set_console_clock(int id)
-{
- if (id >= ARRAY_SIZE(usart_clocks_lookups))
- return;
-
- console_clock_lookup.con_id = "usart";
- console_clock_lookup.clk = usart_clocks_lookups[id].clk;
- clkdev_add(&console_clock_lookup);
-}
-
/* --------------------------------------------------------------------
* GPIO
* -------------------------------------------------------------------- */
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index fe99206de880..175e0009eaa9 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -953,8 +953,25 @@ static struct platform_device at91sam9263_tcb_device = {
.num_resources = ARRAY_SIZE(tcb_resources),
};
+#if defined(CONFIG_OF)
+static struct of_device_id tcb_ids[] = {
+ { .compatible = "atmel,at91rm9200-tcb" },
+ { /*sentinel*/ }
+};
+#endif
+
static void __init at91_add_device_tc(void)
{
+#if defined(CONFIG_OF)
+ struct device_node *np;
+
+ np = of_find_matching_node(NULL, tcb_ids);
+ if (np) {
+ of_node_put(np);
+ return;
+ }
+#endif
+
platform_device_register(&at91sam9263_tcb_device);
}
#else
@@ -1461,14 +1478,6 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
at91_uarts[portnr] = pdev;
}
-void __init at91_set_serial_console(unsigned portnr)
-{
- if (portnr < ATMEL_MAX_UART) {
- atmel_default_console_device = at91_uarts[portnr];
- at91sam9263_set_console_clock(at91_uarts[portnr]->id);
- }
-}
-
void __init at91_add_device_serial(void)
{
int i;
@@ -1477,13 +1486,9 @@ void __init at91_add_device_serial(void)
if (at91_uarts[i])
platform_device_register(at91_uarts[i]);
}
-
- if (!atmel_default_console_device)
- printk(KERN_INFO "AT91: No default serial console defined.\n");
}
#else
void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
-void __init at91_set_serial_console(unsigned portnr) {}
void __init at91_add_device_serial(void) {}
#endif
@@ -1495,6 +1500,9 @@ void __init at91_add_device_serial(void) {}
*/
static int __init at91_add_standard_devices(void)
{
+ if (of_have_populated_dt())
+ return 0;
+
at91_add_device_rtt();
at91_add_device_watchdog();
at91_add_device_tc();
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
index d222f8333dab..4792682d52b9 100644
--- a/arch/arm/mach-at91/at91sam9g45.c
+++ b/arch/arm/mach-at91/at91sam9g45.c
@@ -176,6 +176,12 @@ static struct clk vdec_clk = {
.type = CLK_TYPE_PERIPHERAL,
};
+static struct clk adc_op_clk = {
+ .name = "adc_op_clk",
+ .type = CLK_TYPE_PERIPHERAL,
+ .rate_hz = 13200000,
+};
+
static struct clk *periph_clocks[] __initdata = {
&pioA_clk,
&pioB_clk,
@@ -204,6 +210,7 @@ static struct clk *periph_clocks[] __initdata = {
&isi_clk,
&udphs_clk,
&mmc1_clk,
+ &adc_op_clk,
// irq0
};
@@ -242,6 +249,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_ID("pioC", &pioC_clk),
CLKDEV_CON_ID("pioD", &pioDE_clk),
CLKDEV_CON_ID("pioE", &pioDE_clk),
+ /* Fake adc clock */
+ CLKDEV_CON_ID("adc_clk", &tsc_clk),
};
static struct clk_lookup usart_clocks_lookups[] = {
@@ -288,18 +297,6 @@ static void __init at91sam9g45_register_clocks(void)
clk_register(&pck1);
}
-static struct clk_lookup console_clock_lookup;
-
-void __init at91sam9g45_set_console_clock(int id)
-{
- if (id >= ARRAY_SIZE(usart_clocks_lookups))
- return;
-
- console_clock_lookup.con_id = "usart";
- console_clock_lookup.clk = usart_clocks_lookups[id].clk;
- clkdev_add(&console_clock_lookup);
-}
-
/* --------------------------------------------------------------------
* GPIO
* -------------------------------------------------------------------- */
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
index 6b008aee1dff..f6747246d649 100644
--- a/arch/arm/mach-at91/at91sam9g45_devices.c
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -19,9 +19,12 @@
#include <linux/i2c-gpio.h>
#include <linux/atmel-mci.h>
+#include <linux/platform_data/at91_adc.h>
+
#include <linux/fb.h>
#include <video/atmel_lcdc.h>
+#include <mach/at91_adc.h>
#include <mach/board.h>
#include <mach/at91sam9g45.h>
#include <mach/at91sam9g45_matrix.h>
@@ -69,15 +72,7 @@ static struct platform_device at_hdmac_device = {
void __init at91_add_device_hdmac(void)
{
-#if defined(CONFIG_OF)
- struct device_node *of_node =
- of_find_node_by_name(NULL, "dma-controller");
-
- if (of_node)
- of_node_put(of_node);
- else
-#endif
- platform_device_register(&at_hdmac_device);
+ platform_device_register(&at_hdmac_device);
}
#else
void __init at91_add_device_hdmac(void) {}
@@ -1094,25 +1089,8 @@ static struct platform_device at91sam9g45_tcb1_device = {
.num_resources = ARRAY_SIZE(tcb1_resources),
};
-#if defined(CONFIG_OF)
-static struct of_device_id tcb_ids[] = {
- { .compatible = "atmel,at91rm9200-tcb" },
- { /*sentinel*/ }
-};
-#endif
-
static void __init at91_add_device_tc(void)
{
-#if defined(CONFIG_OF)
- struct device_node *np;
-
- np = of_find_matching_node(NULL, tcb_ids);
- if (np) {
- of_node_put(np);
- return;
- }
-#endif
-
platform_device_register(&at91sam9g45_tcb0_device);
platform_device_register(&at91sam9g45_tcb1_device);
}
@@ -1207,6 +1185,104 @@ void __init at91_add_device_tsadcc(struct at91_tsadcc_data *data) {}
/* --------------------------------------------------------------------
+ * ADC
+ * -------------------------------------------------------------------- */
+
+#if IS_ENABLED(CONFIG_AT91_ADC)
+static struct at91_adc_data adc_data;
+
+static struct resource adc_resources[] = {
+ [0] = {
+ .start = AT91SAM9G45_BASE_TSC,
+ .end = AT91SAM9G45_BASE_TSC + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = AT91SAM9G45_ID_TSC,
+ .end = AT91SAM9G45_ID_TSC,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device at91_adc_device = {
+ .name = "at91_adc",
+ .id = -1,
+ .dev = {
+ .platform_data = &adc_data,
+ },
+ .resource = adc_resources,
+ .num_resources = ARRAY_SIZE(adc_resources),
+};
+
+static struct at91_adc_trigger at91_adc_triggers[] = {
+ [0] = {
+ .name = "external-rising",
+ .value = 1,
+ .is_external = true,
+ },
+ [1] = {
+ .name = "external-falling",
+ .value = 2,
+ .is_external = true,
+ },
+ [2] = {
+ .name = "external-any",
+ .value = 3,
+ .is_external = true,
+ },
+ [3] = {
+ .name = "continuous",
+ .value = 6,
+ .is_external = false,
+ },
+};
+
+static struct at91_adc_reg_desc at91_adc_register_g45 = {
+ .channel_base = AT91_ADC_CHR(0),
+ .drdy_mask = AT91_ADC_DRDY,
+ .status_register = AT91_ADC_SR,
+ .trigger_register = 0x08,
+};
+
+void __init at91_add_device_adc(struct at91_adc_data *data)
+{
+ if (!data)
+ return;
+
+ if (test_bit(0, &data->channels_used))
+ at91_set_gpio_input(AT91_PIN_PD20, 0);
+ if (test_bit(1, &data->channels_used))
+ at91_set_gpio_input(AT91_PIN_PD21, 0);
+ if (test_bit(2, &data->channels_used))
+ at91_set_gpio_input(AT91_PIN_PD22, 0);
+ if (test_bit(3, &data->channels_used))
+ at91_set_gpio_input(AT91_PIN_PD23, 0);
+ if (test_bit(4, &data->channels_used))
+ at91_set_gpio_input(AT91_PIN_PD24, 0);
+ if (test_bit(5, &data->channels_used))
+ at91_set_gpio_input(AT91_PIN_PD25, 0);
+ if (test_bit(6, &data->channels_used))
+ at91_set_gpio_input(AT91_PIN_PD26, 0);
+ if (test_bit(7, &data->channels_used))
+ at91_set_gpio_input(AT91_PIN_PD27, 0);
+
+ if (data->use_external_triggers)
+ at91_set_A_periph(AT91_PIN_PD28, 0);
+
+ data->num_channels = 8;
+ data->startup_time = 40;
+ data->registers = &at91_adc_register_g45;
+ data->trigger_number = 4;
+ data->trigger_list = at91_adc_triggers;
+
+ adc_data = *data;
+ platform_device_register(&at91_adc_device);
+}
+#else
+void __init at91_add_device_adc(struct at91_adc_data *data) {}
+#endif
+
+/* --------------------------------------------------------------------
* RTT
* -------------------------------------------------------------------- */
@@ -1741,14 +1817,6 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
at91_uarts[portnr] = pdev;
}
-void __init at91_set_serial_console(unsigned portnr)
-{
- if (portnr < ATMEL_MAX_UART) {
- atmel_default_console_device = at91_uarts[portnr];
- at91sam9g45_set_console_clock(at91_uarts[portnr]->id);
- }
-}
-
void __init at91_add_device_serial(void)
{
int i;
@@ -1757,13 +1825,9 @@ void __init at91_add_device_serial(void)
if (at91_uarts[i])
platform_device_register(at91_uarts[i]);
}
-
- if (!atmel_default_console_device)
- printk(KERN_INFO "AT91: No default serial console defined.\n");
}
#else
void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
-void __init at91_set_serial_console(unsigned portnr) {}
void __init at91_add_device_serial(void) {}
#endif
@@ -1775,6 +1839,9 @@ void __init at91_add_device_serial(void) {}
*/
static int __init at91_add_standard_devices(void)
{
+ if (of_have_populated_dt())
+ return 0;
+
at91_add_device_hdmac();
at91_add_device_rtc();
at91_add_device_rtt();
diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
new file mode 100644
index 000000000000..08494664ab78
--- /dev/null
+++ b/arch/arm/mach-at91/at91sam9n12.c
@@ -0,0 +1,233 @@
+/*
+ * SoC specific setup code for the AT91SAM9N12
+ *
+ * Copyright (C) 2012 Atmel Corporation.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <mach/at91sam9n12.h>
+#include <mach/at91_pmc.h>
+#include <mach/cpu.h>
+#include <mach/board.h>
+
+#include "soc.h"
+#include "generic.h"
+#include "clock.h"
+#include "sam9_smc.h"
+
+/* --------------------------------------------------------------------
+ * Clocks
+ * -------------------------------------------------------------------- */
+
+/*
+ * The peripheral clocks.
+ */
+static struct clk pioAB_clk = {
+ .name = "pioAB_clk",
+ .pmc_mask = 1 << AT91SAM9N12_ID_PIOAB,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioCD_clk = {
+ .name = "pioCD_clk",
+ .pmc_mask = 1 << AT91SAM9N12_ID_PIOCD,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart0_clk = {
+ .name = "usart0_clk",
+ .pmc_mask = 1 << AT91SAM9N12_ID_USART0,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart1_clk = {
+ .name = "usart1_clk",
+ .pmc_mask = 1 << AT91SAM9N12_ID_USART1,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart2_clk = {
+ .name = "usart2_clk",
+ .pmc_mask = 1 << AT91SAM9N12_ID_USART2,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart3_clk = {
+ .name = "usart3_clk",
+ .pmc_mask = 1 << AT91SAM9N12_ID_USART3,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk twi0_clk = {
+ .name = "twi0_clk",
+ .pmc_mask = 1 << AT91SAM9N12_ID_TWI0,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk twi1_clk = {
+ .name = "twi1_clk",
+ .pmc_mask = 1 << AT91SAM9N12_ID_TWI1,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk mmc_clk = {
+ .name = "mci_clk",
+ .pmc_mask = 1 << AT91SAM9N12_ID_MCI,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi0_clk = {
+ .name = "spi0_clk",
+ .pmc_mask = 1 << AT91SAM9N12_ID_SPI0,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi1_clk = {
+ .name = "spi1_clk",
+ .pmc_mask = 1 << AT91SAM9N12_ID_SPI1,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk uart0_clk = {
+ .name = "uart0_clk",
+ .pmc_mask = 1 << AT91SAM9N12_ID_UART0,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk uart1_clk = {
+ .name = "uart1_clk",
+ .pmc_mask = 1 << AT91SAM9N12_ID_UART1,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk tcb_clk = {
+ .name = "tcb_clk",
+ .pmc_mask = 1 << AT91SAM9N12_ID_TCB,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pwm_clk = {
+ .name = "pwm_clk",
+ .pmc_mask = 1 << AT91SAM9N12_ID_PWM,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk adc_clk = {
+ .name = "adc_clk",
+ .pmc_mask = 1 << AT91SAM9N12_ID_ADC,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk dma_clk = {
+ .name = "dma_clk",
+ .pmc_mask = 1 << AT91SAM9N12_ID_DMA,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk uhp_clk = {
+ .name = "uhp",
+ .pmc_mask = 1 << AT91SAM9N12_ID_UHP,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk udp_clk = {
+ .name = "udp_clk",
+ .pmc_mask = 1 << AT91SAM9N12_ID_UDP,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk lcdc_clk = {
+ .name = "lcdc_clk",
+ .pmc_mask = 1 << AT91SAM9N12_ID_LCDC,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc_clk = {
+ .name = "ssc_clk",
+ .pmc_mask = 1 << AT91SAM9N12_ID_SSC,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+
+static struct clk *periph_clocks[] __initdata = {
+ &pioAB_clk,
+ &pioCD_clk,
+ &usart0_clk,
+ &usart1_clk,
+ &usart2_clk,
+ &usart3_clk,
+ &twi0_clk,
+ &twi1_clk,
+ &mmc_clk,
+ &spi0_clk,
+ &spi1_clk,
+ &lcdc_clk,
+ &uart0_clk,
+ &uart1_clk,
+ &tcb_clk,
+ &pwm_clk,
+ &adc_clk,
+ &dma_clk,
+ &uhp_clk,
+ &udp_clk,
+ &ssc_clk,
+};
+
+static struct clk_lookup periph_clocks_lookups[] = {
+ /* lookup table for DT entries */
+ CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
+ CLKDEV_CON_DEV_ID("usart", "f801c000.serial", &usart0_clk),
+ CLKDEV_CON_DEV_ID("usart", "f8020000.serial", &usart1_clk),
+ CLKDEV_CON_DEV_ID("usart", "f8024000.serial", &usart2_clk),
+ CLKDEV_CON_DEV_ID("usart", "f8028000.serial", &usart3_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "f8008000.timer", &tcb_clk),
+ CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb_clk),
+ CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma_clk),
+ CLKDEV_CON_ID("pioA", &pioAB_clk),
+ CLKDEV_CON_ID("pioB", &pioAB_clk),
+ CLKDEV_CON_ID("pioC", &pioCD_clk),
+ CLKDEV_CON_ID("pioD", &pioCD_clk),
+ /* additional fake clock for macb_hclk */
+ CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &uhp_clk),
+ CLKDEV_CON_DEV_ID("ohci_clk", "500000.ohci", &uhp_clk),
+};
+
+/*
+ * The two programmable clocks.
+ * You must configure pin multiplexing to bring these signals out.
+ */
+static struct clk pck0 = {
+ .name = "pck0",
+ .pmc_mask = AT91_PMC_PCK0,
+ .type = CLK_TYPE_PROGRAMMABLE,
+ .id = 0,
+};
+static struct clk pck1 = {
+ .name = "pck1",
+ .pmc_mask = AT91_PMC_PCK1,
+ .type = CLK_TYPE_PROGRAMMABLE,
+ .id = 1,
+};
+
+static void __init at91sam9n12_register_clocks(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
+ clk_register(periph_clocks[i]);
+ clk_register(&pck0);
+ clk_register(&pck1);
+
+ clkdev_add_table(periph_clocks_lookups,
+ ARRAY_SIZE(periph_clocks_lookups));
+
+}
+
+/* --------------------------------------------------------------------
+ * AT91SAM9N12 processor initialization
+ * -------------------------------------------------------------------- */
+
+static void __init at91sam9n12_map_io(void)
+{
+ at91_init_sram(0, AT91SAM9N12_SRAM_BASE, AT91SAM9N12_SRAM_SIZE);
+}
+
+void __init at91sam9n12_initialize(void)
+{
+ at91_extern_irq = (1 << AT91SAM9N12_ID_IRQ0);
+
+ /* Register GPIO subsystem (using DT) */
+ at91_gpio_init(NULL, 0);
+}
+
+struct at91_init_soc __initdata at91sam9n12_soc = {
+ .map_io = at91sam9n12_map_io,
+ .register_clocks = at91sam9n12_register_clocks,
+ .init = at91sam9n12_initialize,
+};
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
index d9f2774f385e..e420085a57ef 100644
--- a/arch/arm/mach-at91/at91sam9rl.c
+++ b/arch/arm/mach-at91/at91sam9rl.c
@@ -232,18 +232,6 @@ static void __init at91sam9rl_register_clocks(void)
clk_register(&pck1);
}
-static struct clk_lookup console_clock_lookup;
-
-void __init at91sam9rl_set_console_clock(int id)
-{
- if (id >= ARRAY_SIZE(usart_clocks_lookups))
- return;
-
- console_clock_lookup.con_id = "usart";
- console_clock_lookup.clk = usart_clocks_lookups[id].clk;
- clkdev_add(&console_clock_lookup);
-}
-
/* --------------------------------------------------------------------
* GPIO
* -------------------------------------------------------------------- */
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index fe4ae22e8561..9c0b1481a9a7 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -1192,14 +1192,6 @@ void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
at91_uarts[portnr] = pdev;
}
-void __init at91_set_serial_console(unsigned portnr)
-{
- if (portnr < ATMEL_MAX_UART) {
- atmel_default_console_device = at91_uarts[portnr];
- at91sam9rl_set_console_clock(at91_uarts[portnr]->id);
- }
-}
-
void __init at91_add_device_serial(void)
{
int i;
@@ -1208,13 +1200,9 @@ void __init at91_add_device_serial(void)
if (at91_uarts[i])
platform_device_register(at91_uarts[i]);
}
-
- if (!atmel_default_console_device)
- printk(KERN_INFO "AT91: No default serial console defined.\n");
}
#else
void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
-void __init at91_set_serial_console(unsigned portnr) {}
void __init at91_add_device_serial(void) {}
#endif
diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
index 13c8cae60462..1b144b4d3ce1 100644
--- a/arch/arm/mach-at91/at91sam9x5.c
+++ b/arch/arm/mach-at91/at91sam9x5.c
@@ -120,6 +120,11 @@ static struct clk adc_clk = {
.pmc_mask = 1 << AT91SAM9X5_ID_ADC,
.type = CLK_TYPE_PERIPHERAL,
};
+static struct clk adc_op_clk = {
+ .name = "adc_op_clk",
+ .type = CLK_TYPE_PERIPHERAL,
+ .rate_hz = 5000000,
+};
static struct clk dma0_clk = {
.name = "dma0_clk",
.pmc_mask = 1 << AT91SAM9X5_ID_DMA0,
@@ -205,6 +210,7 @@ static struct clk *periph_clocks[] __initdata = {
&tcb0_clk,
&pwm_clk,
&adc_clk,
+ &adc_op_clk,
&dma0_clk,
&dma1_clk,
&uhphs_clk,
diff --git a/arch/arm/mach-at91/board-1arm.c b/arch/arm/mach-at91/board-1arm.c
index 2628384aaae1..271f994314a4 100644
--- a/arch/arm/mach-at91/board-1arm.c
+++ b/arch/arm/mach-at91/board-1arm.c
@@ -47,20 +47,6 @@ static void __init onearm_init_early(void)
/* Initialize processor: 18.432 MHz crystal */
at91_initialize(18432000);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */
- at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
- /* USART1 on ttyS2 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
- | ATMEL_UART_RI);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
static struct macb_platform_data __initdata onearm_eth_data = {
@@ -82,6 +68,16 @@ static struct at91_udc_data __initdata onearm_udc_data = {
static void __init onearm_board_init(void)
{
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */
+ at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
+
+ /* USART1 on ttyS2 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS
+ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+ | ATMEL_UART_RI);
at91_add_device_serial();
/* Ethernet */
at91_add_device_eth(&onearm_eth_data);
diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c
index 161efbaa1029..b7d8aa7b81e6 100644
--- a/arch/arm/mach-at91/board-afeb-9260v1.c
+++ b/arch/arm/mach-at91/board-afeb-9260v1.c
@@ -52,22 +52,6 @@ static void __init afeb9260_init_early(void)
{
/* Initialize processor: 18.432 MHz crystal */
at91_initialize(18432000);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91SAM9260_ID_US0, 1,
- ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR
- | ATMEL_UART_DCD | ATMEL_UART_RI);
-
- /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
- at91_register_uart(AT91SAM9260_ID_US1, 2,
- ATMEL_UART_CTS | ATMEL_UART_RTS);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
/*
@@ -183,6 +167,18 @@ static struct at91_cf_data afeb9260_cf_data = {
static void __init afeb9260_board_init(void)
{
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ at91_register_uart(AT91SAM9260_ID_US0, 1,
+ ATMEL_UART_CTS | ATMEL_UART_RTS
+ | ATMEL_UART_DTR | ATMEL_UART_DSR
+ | ATMEL_UART_DCD | ATMEL_UART_RI);
+
+ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+ at91_register_uart(AT91SAM9260_ID_US1, 2,
+ ATMEL_UART_CTS | ATMEL_UART_RTS);
at91_add_device_serial();
/* USB Host */
at91_add_device_usbh(&afeb9260_usbh_data);
diff --git a/arch/arm/mach-at91/board-cam60.c b/arch/arm/mach-at91/board-cam60.c
index c6d44ee0c77e..29d3ef0a50fb 100644
--- a/arch/arm/mach-at91/board-cam60.c
+++ b/arch/arm/mach-at91/board-cam60.c
@@ -49,12 +49,6 @@ static void __init cam60_init_early(void)
{
/* Initialize processor: 10 MHz crystal */
at91_initialize(10000000);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
/*
@@ -175,6 +169,8 @@ static void __init cam60_add_device_nand(void)
static void __init cam60_board_init(void)
{
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
at91_add_device_serial();
/* SPI */
at91_add_device_spi(cam60_spi_devices, ARRAY_SIZE(cam60_spi_devices));
diff --git a/arch/arm/mach-at91/board-carmeva.c b/arch/arm/mach-at91/board-carmeva.c
index 59d9cf997537..44328a6d4609 100644
--- a/arch/arm/mach-at91/board-carmeva.c
+++ b/arch/arm/mach-at91/board-carmeva.c
@@ -44,17 +44,6 @@ static void __init carmeva_init_early(void)
{
/* Initialize processor: 20.000 MHz crystal */
at91_initialize(20000000);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
- | ATMEL_UART_RI);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
static struct macb_platform_data __initdata carmeva_eth_data = {
@@ -139,6 +128,13 @@ static struct gpio_led carmeva_leds[] = {
static void __init carmeva_board_init(void)
{
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+ | ATMEL_UART_RI);
at91_add_device_serial();
/* Ethernet */
at91_add_device_eth(&carmeva_eth_data);
diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c
index 5f3680e7c883..69951ec7dbf3 100644
--- a/arch/arm/mach-at91/board-cpu9krea.c
+++ b/arch/arm/mach-at91/board-cpu9krea.c
@@ -52,34 +52,6 @@ static void __init cpu9krea_init_early(void)
{
/* Initialize processor: 18.432 MHz crystal */
at91_initialize(18432000);
-
- /* DGBU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS |
- ATMEL_UART_RTS | ATMEL_UART_DTR | ATMEL_UART_DSR |
- ATMEL_UART_DCD | ATMEL_UART_RI);
-
- /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS |
- ATMEL_UART_RTS);
-
- /* USART2 on ttyS3. (Rx, Tx, RTS, CTS) */
- at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS |
- ATMEL_UART_RTS);
-
- /* USART3 on ttyS4. (Rx, Tx) */
- at91_register_uart(AT91SAM9260_ID_US3, 4, 0);
-
- /* USART4 on ttyS5. (Rx, Tx) */
- at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
-
- /* USART5 on ttyS6. (Rx, Tx) */
- at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
/*
@@ -352,6 +324,30 @@ static void __init cpu9krea_board_init(void)
/* NOR */
cpu9krea_add_device_nor();
/* Serial */
+ /* DGBU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS |
+ ATMEL_UART_RTS | ATMEL_UART_DTR | ATMEL_UART_DSR |
+ ATMEL_UART_DCD | ATMEL_UART_RI);
+
+ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS |
+ ATMEL_UART_RTS);
+
+ /* USART2 on ttyS3. (Rx, Tx, RTS, CTS) */
+ at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS |
+ ATMEL_UART_RTS);
+
+ /* USART3 on ttyS4. (Rx, Tx) */
+ at91_register_uart(AT91SAM9260_ID_US3, 4, 0);
+
+ /* USART4 on ttyS5. (Rx, Tx) */
+ at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
+
+ /* USART5 on ttyS6. (Rx, Tx) */
+ at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
at91_add_device_serial();
/* USB Host */
at91_add_device_usbh(&cpu9krea_usbh_data);
diff --git a/arch/arm/mach-at91/board-cpuat91.c b/arch/arm/mach-at91/board-cpuat91.c
index e094cc81fe25..895cf2dba612 100644
--- a/arch/arm/mach-at91/board-cpuat91.c
+++ b/arch/arm/mach-at91/board-cpuat91.c
@@ -59,28 +59,6 @@ static void __init cpuat91_init_early(void)
/* Initialize processor: 18.432 MHz crystal */
at91_initialize(18432000);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) */
- at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS |
- ATMEL_UART_RTS);
-
- /* USART1 on ttyS2. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS |
- ATMEL_UART_RTS | ATMEL_UART_DTR | ATMEL_UART_DSR |
- ATMEL_UART_DCD | ATMEL_UART_RI);
-
- /* USART2 on ttyS3 (Rx, Tx) */
- at91_register_uart(AT91RM9200_ID_US2, 3, 0);
-
- /* USART3 on ttyS4 (Rx, Tx, CTS, RTS) */
- at91_register_uart(AT91RM9200_ID_US3, 4, ATMEL_UART_CTS |
- ATMEL_UART_RTS);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
static struct macb_platform_data __initdata cpuat91_eth_data = {
@@ -161,6 +139,24 @@ static struct platform_device *platform_devices[] __initdata = {
static void __init cpuat91_board_init(void)
{
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) */
+ at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS |
+ ATMEL_UART_RTS);
+
+ /* USART1 on ttyS2. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS |
+ ATMEL_UART_RTS | ATMEL_UART_DTR | ATMEL_UART_DSR |
+ ATMEL_UART_DCD | ATMEL_UART_RI);
+
+ /* USART2 on ttyS3 (Rx, Tx) */
+ at91_register_uart(AT91RM9200_ID_US2, 3, 0);
+
+ /* USART3 on ttyS4 (Rx, Tx, CTS, RTS) */
+ at91_register_uart(AT91RM9200_ID_US3, 4, ATMEL_UART_CTS |
+ ATMEL_UART_RTS);
at91_add_device_serial();
/* LEDs. */
at91_gpio_leds(cpuat91_leds, ARRAY_SIZE(cpuat91_leds));
diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c
index 1a1547b1ce4e..cd813361cd26 100644
--- a/arch/arm/mach-at91/board-csb337.c
+++ b/arch/arm/mach-at91/board-csb337.c
@@ -47,15 +47,6 @@ static void __init csb337_init_early(void)
{
/* Initialize processor: 3.6864 MHz crystal */
at91_initialize(3686400);
-
- /* Setup the LEDs */
- at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
-
- /* DBGU on ttyS0 */
- at91_register_uart(0, 0, 0);
-
- /* make console=ttyS0 the default */
- at91_set_serial_console(0);
}
static struct macb_platform_data __initdata csb337_eth_data = {
@@ -228,7 +219,11 @@ static struct gpio_led csb_leds[] = {
static void __init csb337_board_init(void)
{
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
/* Serial */
+ /* DBGU on ttyS0 */
+ at91_register_uart(0, 0, 0);
at91_add_device_serial();
/* Ethernet */
at91_add_device_eth(&csb337_eth_data);
diff --git a/arch/arm/mach-at91/board-csb637.c b/arch/arm/mach-at91/board-csb637.c
index f650bf39455d..7c8b05a57d7f 100644
--- a/arch/arm/mach-at91/board-csb637.c
+++ b/arch/arm/mach-at91/board-csb637.c
@@ -44,12 +44,6 @@ static void __init csb637_init_early(void)
{
/* Initialize processor: 3.6864 MHz crystal */
at91_initialize(3686400);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* make console=ttyS0 (ie, DBGU) the default */
- at91_set_serial_console(0);
}
static struct macb_platform_data __initdata csb637_eth_data = {
@@ -118,6 +112,8 @@ static void __init csb637_board_init(void)
/* LED(s) */
at91_gpio_leds(csb_leds, ARRAY_SIZE(csb_leds));
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
at91_add_device_serial();
/* Ethernet */
at91_add_device_eth(&csb637_eth_data);
diff --git a/arch/arm/mach-at91/board-dt.c b/arch/arm/mach-at91/board-dt.c
index c18d4d307801..a1fce05aa7a5 100644
--- a/arch/arm/mach-at91/board-dt.c
+++ b/arch/arm/mach-at91/board-dt.c
@@ -1,10 +1,6 @@
/*
* Setup code for AT91SAM Evaluation Kits with Device Tree support
*
- * Covers: * AT91SAM9G45-EKES board
- * * AT91SAM9M10-EKES board
- * * AT91SAM9M10G45-EK board
- *
* Copyright (C) 2011 Atmel,
* 2011 Nicolas Ferre <nicolas.ferre@atmel.com>
*
@@ -49,9 +45,7 @@ static void __init at91_dt_device_init(void)
}
static const char *at91_dt_board_compat[] __initdata = {
- "atmel,at91sam9m10g45ek",
- "atmel,at91sam9x5ek",
- "calao,usb-a9g20",
+ "atmel,at91sam9",
NULL
};
diff --git a/arch/arm/mach-at91/board-eb9200.c b/arch/arm/mach-at91/board-eb9200.c
index d302ca3eeb64..bd1017297989 100644
--- a/arch/arm/mach-at91/board-eb9200.c
+++ b/arch/arm/mach-at91/board-eb9200.c
@@ -44,20 +44,6 @@ static void __init eb9200_init_early(void)
{
/* Initialize processor: 18.432 MHz crystal */
at91_initialize(18432000);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
- | ATMEL_UART_RI);
-
- /* USART2 on ttyS2. (Rx, Tx) - IRDA */
- at91_register_uart(AT91RM9200_ID_US2, 2, 0);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
static struct macb_platform_data __initdata eb9200_eth_data = {
@@ -101,6 +87,16 @@ static struct i2c_board_info __initdata eb9200_i2c_devices[] = {
static void __init eb9200_board_init(void)
{
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+ | ATMEL_UART_RI);
+
+ /* USART2 on ttyS2. (Rx, Tx) - IRDA */
+ at91_register_uart(AT91RM9200_ID_US2, 2, 0);
at91_add_device_serial();
/* Ethernet */
at91_add_device_eth(&eb9200_eth_data);
diff --git a/arch/arm/mach-at91/board-ecbat91.c b/arch/arm/mach-at91/board-ecbat91.c
index 69966ce4d776..89cc3726a9ce 100644
--- a/arch/arm/mach-at91/board-ecbat91.c
+++ b/arch/arm/mach-at91/board-ecbat91.c
@@ -50,18 +50,6 @@ static void __init ecb_at91init_early(void)
/* Initialize processor: 18.432 MHz crystal */
at91_initialize(18432000);
-
- /* Setup the LEDs */
- at91_init_leds(AT91_PIN_PC7, AT91_PIN_PC7);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1. (Rx & Tx only) */
- at91_register_uart(AT91RM9200_ID_US0, 1, 0);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
static struct macb_platform_data __initdata ecb_at91eth_data = {
@@ -151,7 +139,15 @@ static struct spi_board_info __initdata ecb_at91spi_devices[] = {
static void __init ecb_at91board_init(void)
{
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PC7, AT91_PIN_PC7);
+
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART0 on ttyS1. (Rx & Tx only) */
+ at91_register_uart(AT91RM9200_ID_US0, 1, 0);
at91_add_device_serial();
/* Ethernet */
diff --git a/arch/arm/mach-at91/board-eco920.c b/arch/arm/mach-at91/board-eco920.c
index f23aabef8551..558546cf63f4 100644
--- a/arch/arm/mach-at91/board-eco920.c
+++ b/arch/arm/mach-at91/board-eco920.c
@@ -37,15 +37,6 @@ static void __init eco920_init_early(void)
at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
at91_initialize(18432000);
-
- /* Setup the LEDs */
- at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
-
- /* DBGU on ttyS0. (Rx & Tx only */
- at91_register_uart(0, 0, 0);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
static struct macb_platform_data __initdata eco920_eth_data = {
@@ -103,6 +94,10 @@ static struct spi_board_info eco920_spi_devices[] = {
static void __init eco920_board_init(void)
{
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
+ /* DBGU on ttyS0. (Rx & Tx only */
+ at91_register_uart(0, 0, 0);
at91_add_device_serial();
at91_add_device_eth(&eco920_eth_data);
at91_add_device_usbh(&eco920_usbh_data);
diff --git a/arch/arm/mach-at91/board-flexibity.c b/arch/arm/mach-at91/board-flexibity.c
index 1815152001f7..47658f78105d 100644
--- a/arch/arm/mach-at91/board-flexibity.c
+++ b/arch/arm/mach-at91/board-flexibity.c
@@ -41,12 +41,6 @@ static void __init flexibity_init_early(void)
{
/* Initialize processor: 18.432 MHz crystal */
at91_initialize(18432000);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
/* USB Host port */
@@ -143,6 +137,8 @@ static struct gpio_led flexibity_leds[] = {
static void __init flexibity_board_init(void)
{
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
at91_add_device_serial();
/* USB Host */
at91_add_device_usbh(&flexibity_usbh_data);
diff --git a/arch/arm/mach-at91/board-foxg20.c b/arch/arm/mach-at91/board-foxg20.c
index caf017f0f4ee..33411e6ecb1f 100644
--- a/arch/arm/mach-at91/board-foxg20.c
+++ b/arch/arm/mach-at91/board-foxg20.c
@@ -61,44 +61,6 @@ static void __init foxg20_init_early(void)
{
/* Initialize processor: 18.432 MHz crystal */
at91_initialize(18432000);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91SAM9260_ID_US0, 1,
- ATMEL_UART_CTS
- | ATMEL_UART_RTS
- | ATMEL_UART_DTR
- | ATMEL_UART_DSR
- | ATMEL_UART_DCD
- | ATMEL_UART_RI);
-
- /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
- at91_register_uart(AT91SAM9260_ID_US1, 2,
- ATMEL_UART_CTS
- | ATMEL_UART_RTS);
-
- /* USART2 on ttyS3. (Rx & Tx only) */
- at91_register_uart(AT91SAM9260_ID_US2, 3, 0);
-
- /* USART3 on ttyS4. (Rx, Tx, RTS, CTS) */
- at91_register_uart(AT91SAM9260_ID_US3, 4,
- ATMEL_UART_CTS
- | ATMEL_UART_RTS);
-
- /* USART4 on ttyS5. (Rx & Tx only) */
- at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
-
- /* USART5 on ttyS6. (Rx & Tx only) */
- at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
-
- /* Set the internal pull-up resistor on DRXD */
- at91_set_A_periph(AT91_PIN_PB14, 1);
-
}
/*
@@ -241,6 +203,39 @@ static struct i2c_board_info __initdata foxg20_i2c_devices[] = {
static void __init foxg20_board_init(void)
{
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ at91_register_uart(AT91SAM9260_ID_US0, 1,
+ ATMEL_UART_CTS
+ | ATMEL_UART_RTS
+ | ATMEL_UART_DTR
+ | ATMEL_UART_DSR
+ | ATMEL_UART_DCD
+ | ATMEL_UART_RI);
+
+ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+ at91_register_uart(AT91SAM9260_ID_US1, 2,
+ ATMEL_UART_CTS
+ | ATMEL_UART_RTS);
+
+ /* USART2 on ttyS3. (Rx & Tx only) */
+ at91_register_uart(AT91SAM9260_ID_US2, 3, 0);
+
+ /* USART3 on ttyS4. (Rx, Tx, RTS, CTS) */
+ at91_register_uart(AT91SAM9260_ID_US3, 4,
+ ATMEL_UART_CTS
+ | ATMEL_UART_RTS);
+
+ /* USART4 on ttyS5. (Rx & Tx only) */
+ at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
+
+ /* USART5 on ttyS6. (Rx & Tx only) */
+ at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
+
+ /* Set the internal pull-up resistor on DRXD */
+ at91_set_A_periph(AT91_PIN_PB14, 1);
at91_add_device_serial();
/* USB Host */
at91_add_device_usbh(&foxg20_usbh_data);
diff --git a/arch/arm/mach-at91/board-gsia18s.c b/arch/arm/mach-at91/board-gsia18s.c
index 230e71969fb7..3e0dfa643a86 100644
--- a/arch/arm/mach-at91/board-gsia18s.c
+++ b/arch/arm/mach-at91/board-gsia18s.c
@@ -41,38 +41,6 @@
static void __init gsia18s_init_early(void)
{
stamp9g20_init_early();
-
- /*
- * USART0 on ttyS1 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI).
- * Used for Internal Analog Modem.
- */
- at91_register_uart(AT91SAM9260_ID_US0, 1,
- ATMEL_UART_CTS | ATMEL_UART_RTS |
- ATMEL_UART_DTR | ATMEL_UART_DSR |
- ATMEL_UART_DCD | ATMEL_UART_RI);
- /*
- * USART1 on ttyS2 (Rx, Tx, CTS, RTS).
- * Used for GPS or WiFi or Data stream.
- */
- at91_register_uart(AT91SAM9260_ID_US1, 2,
- ATMEL_UART_CTS | ATMEL_UART_RTS);
- /*
- * USART2 on ttyS3 (Rx, Tx, CTS, RTS).
- * Used for External Modem.
- */
- at91_register_uart(AT91SAM9260_ID_US2, 3,
- ATMEL_UART_CTS | ATMEL_UART_RTS);
- /*
- * USART3 on ttyS4 (Rx, Tx, RTS).
- * Used for RS-485.
- */
- at91_register_uart(AT91SAM9260_ID_US3, 4, ATMEL_UART_RTS);
-
- /*
- * USART4 on ttyS5 (Rx, Tx).
- * Used for TRX433 Radio Module.
- */
- at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
}
/*
@@ -558,6 +526,37 @@ static int __init gsia18s_power_off_init(void)
static void __init gsia18s_board_init(void)
{
+ /*
+ * USART0 on ttyS1 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI).
+ * Used for Internal Analog Modem.
+ */
+ at91_register_uart(AT91SAM9260_ID_US0, 1,
+ ATMEL_UART_CTS | ATMEL_UART_RTS |
+ ATMEL_UART_DTR | ATMEL_UART_DSR |
+ ATMEL_UART_DCD | ATMEL_UART_RI);
+ /*
+ * USART1 on ttyS2 (Rx, Tx, CTS, RTS).
+ * Used for GPS or WiFi or Data stream.
+ */
+ at91_register_uart(AT91SAM9260_ID_US1, 2,
+ ATMEL_UART_CTS | ATMEL_UART_RTS);
+ /*
+ * USART2 on ttyS3 (Rx, Tx, CTS, RTS).
+ * Used for External Modem.
+ */
+ at91_register_uart(AT91SAM9260_ID_US2, 3,
+ ATMEL_UART_CTS | ATMEL_UART_RTS);
+ /*
+ * USART3 on ttyS4 (Rx, Tx, RTS).
+ * Used for RS-485.
+ */
+ at91_register_uart(AT91SAM9260_ID_US3, 4, ATMEL_UART_RTS);
+
+ /*
+ * USART4 on ttyS5 (Rx, Tx).
+ * Used for TRX433 Radio Module.
+ */
+ at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
stamp9g20_board_init();
at91_add_device_usbh(&usbh_data);
at91_add_device_udc(&udc_data);
diff --git a/arch/arm/mach-at91/board-kafa.c b/arch/arm/mach-at91/board-kafa.c
index efde1b2327c8..f260657f32bc 100644
--- a/arch/arm/mach-at91/board-kafa.c
+++ b/arch/arm/mach-at91/board-kafa.c
@@ -47,18 +47,6 @@ static void __init kafa_init_early(void)
/* Initialize processor: 18.432 MHz crystal */
at91_initialize(18432000);
-
- /* Set up the LEDs */
- at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */
- at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
static struct macb_platform_data __initdata kafa_eth_data = {
@@ -79,7 +67,15 @@ static struct at91_udc_data __initdata kafa_udc_data = {
static void __init kafa_board_init(void)
{
+ /* Set up the LEDs */
+ at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4);
+
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */
+ at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
at91_add_device_serial();
/* Ethernet */
at91_add_device_eth(&kafa_eth_data);
diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c
index 59b92aab9bcf..ba39db5482b9 100644
--- a/arch/arm/mach-at91/board-kb9202.c
+++ b/arch/arm/mach-at91/board-kb9202.c
@@ -50,24 +50,6 @@ static void __init kb9202_init_early(void)
/* Initialize processor: 10 MHz crystal */
at91_initialize(10000000);
-
- /* Set up the LEDs */
- at91_init_leds(AT91_PIN_PC19, AT91_PIN_PC18);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1 (Rx & Tx only) */
- at91_register_uart(AT91RM9200_ID_US0, 1, 0);
-
- /* USART1 on ttyS2 (Rx & Tx only) - IRDA (optional) */
- at91_register_uart(AT91RM9200_ID_US1, 2, 0);
-
- /* USART3 on ttyS3 (Rx, Tx, CTS, RTS) - RS485 (optional) */
- at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
static struct macb_platform_data __initdata kb9202_eth_data = {
@@ -115,7 +97,21 @@ static struct atmel_nand_data __initdata kb9202_nand_data = {
static void __init kb9202_board_init(void)
{
+ /* Set up the LEDs */
+ at91_init_leds(AT91_PIN_PC19, AT91_PIN_PC18);
+
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART0 on ttyS1 (Rx & Tx only) */
+ at91_register_uart(AT91RM9200_ID_US0, 1, 0);
+
+ /* USART1 on ttyS2 (Rx & Tx only) - IRDA (optional) */
+ at91_register_uart(AT91RM9200_ID_US1, 2, 0);
+
+ /* USART3 on ttyS3 (Rx, Tx, CTS, RTS) - RS485 (optional) */
+ at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_CTS | ATMEL_UART_RTS);
at91_add_device_serial();
/* Ethernet */
at91_add_device_eth(&kb9202_eth_data);
diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c
index 57d5f6a4726a..d2f4cc161766 100644
--- a/arch/arm/mach-at91/board-neocore926.c
+++ b/arch/arm/mach-at91/board-neocore926.c
@@ -55,15 +55,6 @@ static void __init neocore926_init_early(void)
{
/* Initialize processor: 20 MHz crystal */
at91_initialize(20000000);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */
- at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
/*
@@ -341,6 +332,11 @@ static struct ac97c_platform_data neocore926_ac97_data = {
static void __init neocore926_board_init(void)
{
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */
+ at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
at91_add_device_serial();
/* USB Host */
diff --git a/arch/arm/mach-at91/board-pcontrol-g20.c b/arch/arm/mach-at91/board-pcontrol-g20.c
index b4a12fc184c8..7fe638342421 100644
--- a/arch/arm/mach-at91/board-pcontrol-g20.c
+++ b/arch/arm/mach-at91/board-pcontrol-g20.c
@@ -40,17 +40,6 @@
static void __init pcontrol_g20_init_early(void)
{
stamp9g20_init_early();
-
- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) piggyback A2 */
- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS
- | ATMEL_UART_RTS);
-
- /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) isolated RS485 X5 */
- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS
- | ATMEL_UART_RTS);
-
- /* USART2 on ttyS3. (Rx, Tx) 9bit-Bus Multidrop-mode X4 */
- at91_register_uart(AT91SAM9260_ID_US4, 3, 0);
}
static struct sam9_smc_config __initdata pcontrol_smc_config[2] = { {
@@ -199,6 +188,16 @@ static struct spi_board_info pcontrol_g20_spi_devices[] = {
static void __init pcontrol_g20_board_init(void)
{
+ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) piggyback A2 */
+ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS
+ | ATMEL_UART_RTS);
+
+ /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) isolated RS485 X5 */
+ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS
+ | ATMEL_UART_RTS);
+
+ /* USART2 on ttyS3. (Rx, Tx) 9bit-Bus Multidrop-mode X4 */
+ at91_register_uart(AT91SAM9260_ID_US4, 3, 0);
stamp9g20_board_init();
at91_add_device_usbh(&usbh_data);
at91_add_device_eth(&macb_data);
diff --git a/arch/arm/mach-at91/board-picotux200.c b/arch/arm/mach-at91/board-picotux200.c
index 59e35dd14863..b45c0a5d5ca7 100644
--- a/arch/arm/mach-at91/board-picotux200.c
+++ b/arch/arm/mach-at91/board-picotux200.c
@@ -48,17 +48,6 @@ static void __init picotux200_init_early(void)
{
/* Initialize processor: 18.432 MHz crystal */
at91_initialize(18432000);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
- | ATMEL_UART_RI);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
static struct macb_platform_data __initdata picotux200_eth_data = {
@@ -106,6 +95,13 @@ static struct platform_device picotux200_flash = {
static void __init picotux200_board_init(void)
{
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+ | ATMEL_UART_RI);
at91_add_device_serial();
/* Ethernet */
at91_add_device_eth(&picotux200_eth_data);
diff --git a/arch/arm/mach-at91/board-qil-a9260.c b/arch/arm/mach-at91/board-qil-a9260.c
index b6ed5ed7081a..0c61bf0d272c 100644
--- a/arch/arm/mach-at91/board-qil-a9260.c
+++ b/arch/arm/mach-at91/board-qil-a9260.c
@@ -52,24 +52,6 @@ static void __init ek_init_early(void)
{
/* Initialize processor: 12.000 MHz crystal */
at91_initialize(12000000);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
- | ATMEL_UART_RI);
-
- /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */
- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
- /* USART2 on ttyS3. (Rx, Tx, CTS, RTS) */
- at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
- /* set serial console to ttyS1 (ie, USART0) */
- at91_set_serial_console(1);
-
}
/*
@@ -235,6 +217,19 @@ static struct gpio_led ek_leds[] = {
static void __init ek_board_init(void)
{
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+ | ATMEL_UART_RI);
+
+ /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */
+ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
+
+ /* USART2 on ttyS3. (Rx, Tx, CTS, RTS) */
+ at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS | ATMEL_UART_RTS);
at91_add_device_serial();
/* USB Host */
at91_add_device_usbh(&ek_usbh_data);
diff --git a/arch/arm/mach-at91/board-rm9200dk.c b/arch/arm/mach-at91/board-rm9200dk.c
index 01332aa538b2..afd7a4713766 100644
--- a/arch/arm/mach-at91/board-rm9200dk.c
+++ b/arch/arm/mach-at91/board-rm9200dk.c
@@ -50,20 +50,6 @@ static void __init dk_init_early(void)
{
/* Initialize processor: 18.432 MHz crystal */
at91_initialize(18432000);
-
- /* Setup the LEDs */
- at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
- | ATMEL_UART_RI);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
static struct macb_platform_data __initdata dk_eth_data = {
@@ -190,7 +176,17 @@ static struct gpio_led dk_leds[] = {
static void __init dk_board_init(void)
{
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
+
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+ | ATMEL_UART_RI);
at91_add_device_serial();
/* Ethernet */
at91_add_device_eth(&dk_eth_data);
diff --git a/arch/arm/mach-at91/board-rm9200ek.c b/arch/arm/mach-at91/board-rm9200ek.c
index b2e4fe21f346..2b15b8adec4c 100644
--- a/arch/arm/mach-at91/board-rm9200ek.c
+++ b/arch/arm/mach-at91/board-rm9200ek.c
@@ -50,20 +50,6 @@ static void __init ek_init_early(void)
{
/* Initialize processor: 18.432 MHz crystal */
at91_initialize(18432000);
-
- /* Setup the LEDs */
- at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
- | ATMEL_UART_RI);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
static struct macb_platform_data __initdata ek_eth_data = {
@@ -161,7 +147,17 @@ static struct gpio_led ek_leds[] = {
static void __init ek_board_init(void)
{
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2);
+
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+ | ATMEL_UART_RI);
at91_add_device_serial();
/* Ethernet */
at91_add_device_eth(&ek_eth_data);
diff --git a/arch/arm/mach-at91/board-rsi-ews.c b/arch/arm/mach-at91/board-rsi-ews.c
index af0750fafa29..24ab9be7510f 100644
--- a/arch/arm/mach-at91/board-rsi-ews.c
+++ b/arch/arm/mach-at91/board-rsi-ews.c
@@ -35,26 +35,6 @@ static void __init rsi_ews_init_early(void)
{
/* Initialize processor: 18.432 MHz crystal */
at91_initialize(18432000);
-
- /* Setup the LEDs */
- at91_init_leds(AT91_PIN_PB6, AT91_PIN_PB9);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- /* This one is for debugging */
- at91_register_uart(0, 0, 0);
-
- /* USART1 on ttyS2. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- /* Dialin/-out modem interface */
- at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
- | ATMEL_UART_RI);
-
- /* USART3 on ttyS4. (Rx, Tx, RTS) */
- /* RS485 communication */
- at91_register_uart(AT91RM9200_ID_US3, 4, ATMEL_UART_RTS);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
/*
@@ -204,7 +184,23 @@ static struct platform_device rsiews_nor_flash = {
*/
static void __init rsi_ews_board_init(void)
{
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PB6, AT91_PIN_PB9);
+
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ /* This one is for debugging */
+ at91_register_uart(0, 0, 0);
+
+ /* USART1 on ttyS2. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ /* Dialin/-out modem interface */
+ at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS
+ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+ | ATMEL_UART_RI);
+
+ /* USART3 on ttyS4. (Rx, Tx, RTS) */
+ /* RS485 communication */
+ at91_register_uart(AT91RM9200_ID_US3, 4, ATMEL_UART_RTS);
at91_add_device_serial();
at91_set_gpio_output(AT91_PIN_PA21, 0);
/* Ethernet */
diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c
index e8b116b6cba6..cdd21f2595d2 100644
--- a/arch/arm/mach-at91/board-sam9-l9260.c
+++ b/arch/arm/mach-at91/board-sam9-l9260.c
@@ -48,23 +48,6 @@ static void __init ek_init_early(void)
{
/* Initialize processor: 18.432 MHz crystal */
at91_initialize(18432000);
-
- /* Setup the LEDs */
- at91_init_leds(AT91_PIN_PA9, AT91_PIN_PA6);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
- | ATMEL_UART_RI);
-
- /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */
- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
/*
@@ -184,7 +167,20 @@ static struct at91_mmc_data __initdata ek_mmc_data = {
static void __init ek_board_init(void)
{
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PA9, AT91_PIN_PA6);
+
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+ | ATMEL_UART_RI);
+
+ /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */
+ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
at91_add_device_serial();
/* USB Host */
at91_add_device_usbh(&ek_usbh_data);
diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c
index d5aec55b0eb4..7b3c3913551a 100644
--- a/arch/arm/mach-at91/board-sam9260ek.c
+++ b/arch/arm/mach-at91/board-sam9260ek.c
@@ -54,20 +54,6 @@ static void __init ek_init_early(void)
{
/* Initialize processor: 18.432 MHz crystal */
at91_initialize(18432000);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
- | ATMEL_UART_RI);
-
- /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
/*
@@ -320,6 +306,16 @@ static void __init ek_add_device_buttons(void) {}
static void __init ek_board_init(void)
{
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+ | ATMEL_UART_RI);
+
+ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
at91_add_device_serial();
/* USB Host */
at91_add_device_usbh(&ek_usbh_data);
diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
index 065fed342424..2736453821b0 100644
--- a/arch/arm/mach-at91/board-sam9261ek.c
+++ b/arch/arm/mach-at91/board-sam9261ek.c
@@ -58,15 +58,6 @@ static void __init ek_init_early(void)
{
/* Initialize processor: 18.432 MHz crystal */
at91_initialize(18432000);
-
- /* Setup the LEDs */
- at91_init_leds(AT91_PIN_PA13, AT91_PIN_PA14);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
/*
@@ -577,7 +568,12 @@ static struct gpio_led ek_leds[] = {
static void __init ek_board_init(void)
{
+ /* Setup the LEDs */
+ at91_init_leds(AT91_PIN_PA13, AT91_PIN_PA14);
+
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
at91_add_device_serial();
/* USB Host */
at91_add_device_usbh(&ek_usbh_data);
diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
index 2ffe50f3a9e9..983cb98d2465 100644
--- a/arch/arm/mach-at91/board-sam9263ek.c
+++ b/arch/arm/mach-at91/board-sam9263ek.c
@@ -57,15 +57,6 @@ static void __init ek_init_early(void)
{
/* Initialize processor: 16.367 MHz crystal */
at91_initialize(16367660);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */
- at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
/*
@@ -412,6 +403,11 @@ static struct at91_can_data ek_can_data = {
static void __init ek_board_init(void)
{
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */
+ at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
at91_add_device_serial();
/* USB Host */
at91_add_device_usbh(&ek_usbh_data);
diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
index 8923ec9f5831..6860d3451100 100644
--- a/arch/arm/mach-at91/board-sam9g20ek.c
+++ b/arch/arm/mach-at91/board-sam9g20ek.c
@@ -32,6 +32,8 @@
#include <linux/regulator/fixed.h>
#include <linux/regulator/consumer.h>
+#include <linux/platform_data/at91_adc.h>
+
#include <mach/hardware.h>
#include <asm/setup.h>
#include <asm/mach-types.h>
@@ -65,20 +67,6 @@ static void __init ek_init_early(void)
{
/* Initialize processor: 18.432 MHz crystal */
at91_initialize(18432000);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
- | ATMEL_UART_RI);
-
- /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
/*
@@ -318,6 +306,16 @@ static void __init ek_add_device_buttons(void)
static void __init ek_add_device_buttons(void) {}
#endif
+/*
+ * ADCs
+ */
+
+static struct at91_adc_data ek_adc_data = {
+ .channels_used = BIT(0) | BIT(1) | BIT(2) | BIT(3),
+ .use_external_triggers = true,
+ .vref = 3300,
+};
+
#if defined(CONFIG_REGULATOR_FIXED_VOLTAGE) || defined(CONFIG_REGULATOR_FIXED_VOLTAGE_MODULE)
static struct regulator_consumer_supply ek_audio_consumer_supplies[] = {
REGULATOR_SUPPLY("AVDD", "0-001b"),
@@ -372,6 +370,16 @@ static struct i2c_board_info __initdata ek_i2c_devices[] = {
static void __init ek_board_init(void)
{
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+ | ATMEL_UART_RI);
+
+ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
at91_add_device_serial();
/* USB Host */
at91_add_device_usbh(&ek_usbh_data);
@@ -393,6 +401,8 @@ static void __init ek_board_init(void)
ek_add_device_gpio_leds();
/* Push Buttons */
ek_add_device_buttons();
+ /* ADCs */
+ at91_add_device_adc(&ek_adc_data);
/* PCK0 provides MCLK to the WM8731 */
at91_set_B_periph(AT91_PIN_PC1, 0);
/* SSC (for WM8731) */
diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
index c88e908ddd82..63163dc7df46 100644
--- a/arch/arm/mach-at91/board-sam9m10g45ek.c
+++ b/arch/arm/mach-at91/board-sam9m10g45ek.c
@@ -27,6 +27,8 @@
#include <linux/atmel-mci.h>
#include <linux/delay.h>
+#include <linux/platform_data/at91_adc.h>
+
#include <mach/hardware.h>
#include <video/atmel_lcdc.h>
#include <media/soc_camera.h>
@@ -53,16 +55,6 @@ static void __init ek_init_early(void)
{
/* Initialize processor: 12.000 MHz crystal */
at91_initialize(12000000);
-
- /* DGBU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 not connected on the -EK board */
- /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
- at91_register_uart(AT91SAM9G45_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
/*
@@ -315,6 +307,14 @@ static struct at91_tsadcc_data ek_tsadcc_data = {
.ts_sample_hold_time = 0x0a,
};
+/*
+ * ADCs
+ */
+static struct at91_adc_data ek_adc_data = {
+ .channels_used = BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7),
+ .use_external_triggers = true,
+ .vref = 3300,
+};
/*
* GPIO Buttons
@@ -457,6 +457,12 @@ static struct platform_device *devices[] __initdata = {
static void __init ek_board_init(void)
{
/* Serial */
+ /* DGBU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART0 not connected on the -EK board */
+ /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
+ at91_register_uart(AT91SAM9G45_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
at91_add_device_serial();
/* USB HS Host */
at91_add_device_usbh_ohci(&ek_usbh_hs_data);
@@ -480,6 +486,8 @@ static void __init ek_board_init(void)
at91_add_device_lcdc(&ek_lcdc_data);
/* Touch Screen */
at91_add_device_tsadcc(&ek_tsadcc_data);
+ /* ADC */
+ at91_add_device_adc(&ek_adc_data);
/* Push Buttons */
ek_add_device_buttons();
/* AC97 */
diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
index b109ce2ba864..be3239f13daa 100644
--- a/arch/arm/mach-at91/board-sam9rlek.c
+++ b/arch/arm/mach-at91/board-sam9rlek.c
@@ -42,15 +42,6 @@ static void __init ek_init_early(void)
{
/* Initialize processor: 12.000 MHz crystal */
at91_initialize(12000000);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) */
- at91_register_uart(AT91SAM9RL_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
/*
@@ -296,6 +287,11 @@ static void __init ek_add_device_buttons(void) {}
static void __init ek_board_init(void)
{
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) */
+ at91_register_uart(AT91SAM9RL_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
at91_add_device_serial();
/* USB HS */
at91_add_device_usba(&ek_usba_udc_data);
diff --git a/arch/arm/mach-at91/board-snapper9260.c b/arch/arm/mach-at91/board-snapper9260.c
index ebc9d01ce742..9d446f1bb45f 100644
--- a/arch/arm/mach-at91/board-snapper9260.c
+++ b/arch/arm/mach-at91/board-snapper9260.c
@@ -43,16 +43,6 @@
static void __init snapper9260_init_early(void)
{
at91_initialize(18432000);
-
- /* Debug on ttyS0 */
- at91_register_uart(0, 0, 0);
- at91_set_serial_console(0);
-
- at91_register_uart(AT91SAM9260_ID_US0, 1,
- ATMEL_UART_CTS | ATMEL_UART_RTS);
- at91_register_uart(AT91SAM9260_ID_US1, 2,
- ATMEL_UART_CTS | ATMEL_UART_RTS);
- at91_register_uart(AT91SAM9260_ID_US2, 3, 0);
}
static struct at91_usbh_data __initdata snapper9260_usbh_data = {
@@ -168,6 +158,14 @@ static void __init snapper9260_board_init(void)
snapper9260_i2c_isl1208.irq = gpio_to_irq(AT91_PIN_PA31);
i2c_register_board_info(0, &snapper9260_i2c_isl1208, 1);
+ /* Debug on ttyS0 */
+ at91_register_uart(0, 0, 0);
+
+ at91_register_uart(AT91SAM9260_ID_US0, 1,
+ ATMEL_UART_CTS | ATMEL_UART_RTS);
+ at91_register_uart(AT91SAM9260_ID_US1, 2,
+ ATMEL_UART_CTS | ATMEL_UART_RTS);
+ at91_register_uart(AT91SAM9260_ID_US2, 3, 0);
at91_add_device_serial();
at91_add_device_usbh(&snapper9260_usbh_data);
at91_add_device_udc(&snapper9260_udc_data);
diff --git a/arch/arm/mach-at91/board-stamp9g20.c b/arch/arm/mach-at91/board-stamp9g20.c
index 7640049410a0..ee86f9d7ee72 100644
--- a/arch/arm/mach-at91/board-stamp9g20.c
+++ b/arch/arm/mach-at91/board-stamp9g20.c
@@ -36,44 +36,6 @@ void __init stamp9g20_init_early(void)
{
/* Initialize processor: 18.432 MHz crystal */
at91_initialize(18432000);
-
- /* DGBU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
-}
-
-static void __init stamp9g20evb_init_early(void)
-{
- stamp9g20_init_early();
-
- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR
- | ATMEL_UART_DCD | ATMEL_UART_RI);
-}
-
-static void __init portuxg20_init_early(void)
-{
- stamp9g20_init_early();
-
- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR
- | ATMEL_UART_DCD | ATMEL_UART_RI);
-
- /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */
- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
- /* USART2 on ttyS3. (Rx, Tx, CTS, RTS) */
- at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
- /* USART4 on ttyS5. (Rx, Tx only) */
- at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
-
- /* USART5 on ttyS6. (Rx, Tx only) */
- at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
}
/*
@@ -254,6 +216,8 @@ void add_w1(void)
void __init stamp9g20_board_init(void)
{
/* Serial */
+ /* DGBU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
at91_add_device_serial();
/* NAND */
add_device_nand();
@@ -269,6 +233,22 @@ void __init stamp9g20_board_init(void)
static void __init portuxg20_board_init(void)
{
+ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+ | ATMEL_UART_DTR | ATMEL_UART_DSR
+ | ATMEL_UART_DCD | ATMEL_UART_RI);
+
+ /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */
+ at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
+
+ /* USART2 on ttyS3. (Rx, Tx, CTS, RTS) */
+ at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS | ATMEL_UART_RTS);
+
+ /* USART4 on ttyS5. (Rx, Tx only) */
+ at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
+
+ /* USART5 on ttyS6. (Rx, Tx only) */
+ at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
stamp9g20_board_init();
/* USB Host */
at91_add_device_usbh(&usbh_data);
@@ -286,6 +266,10 @@ static void __init portuxg20_board_init(void)
static void __init stamp9g20evb_board_init(void)
{
+ /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+ | ATMEL_UART_DTR | ATMEL_UART_DSR
+ | ATMEL_UART_DCD | ATMEL_UART_RI);
stamp9g20_board_init();
/* USB Host */
at91_add_device_usbh(&usbh_data);
@@ -303,7 +287,7 @@ MACHINE_START(PORTUXG20, "taskit PortuxG20")
/* Maintainer: taskit GmbH */
.timer = &at91sam926x_timer,
.map_io = at91_map_io,
- .init_early = portuxg20_init_early,
+ .init_early = stamp9g20_init_early,
.init_irq = at91_init_irq_default,
.init_machine = portuxg20_board_init,
MACHINE_END
@@ -312,7 +296,7 @@ MACHINE_START(STAMP9G20, "taskit Stamp9G20")
/* Maintainer: taskit GmbH */
.timer = &at91sam926x_timer,
.map_io = at91_map_io,
- .init_early = stamp9g20evb_init_early,
+ .init_early = stamp9g20_init_early,
.init_irq = at91_init_irq_default,
.init_machine = stamp9g20evb_board_init,
MACHINE_END
diff --git a/arch/arm/mach-at91/board-usb-a926x.c b/arch/arm/mach-at91/board-usb-a926x.c
index b7483a3d0980..95393fcaf199 100644
--- a/arch/arm/mach-at91/board-usb-a926x.c
+++ b/arch/arm/mach-at91/board-usb-a926x.c
@@ -53,12 +53,6 @@ static void __init ek_init_early(void)
{
/* Initialize processor: 12.00 MHz crystal */
at91_initialize(12000000);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
/*
@@ -178,6 +172,10 @@ static struct mtd_partition __initdata ek_nand_partition[] = {
.offset = MTDPART_OFS_NXTBLK,
.size = SZ_128K,
}, {
+ .name = "oftree",
+ .offset = MTDPART_OFS_NXTBLK,
+ .size = SZ_128K,
+ }, {
.name = "kernel",
.offset = MTDPART_OFS_NXTBLK,
.size = 4 * SZ_1M,
@@ -325,6 +323,8 @@ static void __init ek_add_device_leds(void)
static void __init ek_board_init(void)
{
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
at91_add_device_serial();
/* USB Host */
at91_add_device_usbh(&ek_usbh_data);
diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c
index 38dd279d30b2..d56665ea4b55 100644
--- a/arch/arm/mach-at91/board-yl-9200.c
+++ b/arch/arm/mach-at91/board-yl-9200.c
@@ -58,26 +58,6 @@ static void __init yl9200_init_early(void)
/* Initialize processor: 18.432 MHz crystal */
at91_initialize(18432000);
-
- /* Setup the LEDs D2=PB17 (timer), D3=PB16 (cpu) */
- at91_init_leds(AT91_PIN_PB16, AT91_PIN_PB17);
-
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
- | ATMEL_UART_RI);
-
- /* USART0 on ttyS2. (Rx & Tx only to JP3) */
- at91_register_uart(AT91RM9200_ID_US0, 2, 0);
-
- /* USART3 on ttyS3. (Rx, Tx, RTS - RS485 interface) */
- at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_RTS);
-
- /* set serial console to ttyS0 (ie, DBGU) */
- at91_set_serial_console(0);
}
/*
@@ -560,7 +540,23 @@ void __init yl9200_add_device_video(void) {}
static void __init yl9200_board_init(void)
{
+ /* Setup the LEDs D2=PB17 (timer), D3=PB16 (cpu) */
+ at91_init_leds(AT91_PIN_PB16, AT91_PIN_PB17);
+
/* Serial */
+ /* DBGU on ttyS0. (Rx & Tx only) */
+ at91_register_uart(0, 0, 0);
+
+ /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
+ at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
+ | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
+ | ATMEL_UART_RI);
+
+ /* USART0 on ttyS2. (Rx & Tx only to JP3) */
+ at91_register_uart(AT91RM9200_ID_US0, 2, 0);
+
+ /* USART3 on ttyS3. (Rx, Tx, RTS - RS485 interface) */
+ at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_RTS);
at91_add_device_serial();
/* Ethernet */
at91_add_device_eth(&yl9200_eth_data);
diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c
index 6b692824c988..de2ec6b8fea7 100644
--- a/arch/arm/mach-at91/clock.c
+++ b/arch/arm/mach-at91/clock.c
@@ -58,13 +58,15 @@ EXPORT_SYMBOL_GPL(at91_pmc_base);
#define cpu_has_800M_plla() ( cpu_is_at91sam9g20() \
|| cpu_is_at91sam9g45() \
- || cpu_is_at91sam9x5())
+ || cpu_is_at91sam9x5() \
+ || cpu_is_at91sam9n12())
#define cpu_has_300M_plla() (cpu_is_at91sam9g10())
#define cpu_has_pllb() (!(cpu_is_at91sam9rl() \
|| cpu_is_at91sam9g45() \
- || cpu_is_at91sam9x5()))
+ || cpu_is_at91sam9x5() \
+ || cpu_is_at91sam9n12()))
#define cpu_has_upll() (cpu_is_at91sam9g45() \
|| cpu_is_at91sam9x5())
@@ -78,12 +80,15 @@ EXPORT_SYMBOL_GPL(at91_pmc_base);
|| cpu_is_at91sam9x5()))
#define cpu_has_plladiv2() (cpu_is_at91sam9g45() \
- || cpu_is_at91sam9x5())
+ || cpu_is_at91sam9x5() \
+ || cpu_is_at91sam9n12())
#define cpu_has_mdiv3() (cpu_is_at91sam9g45() \
- || cpu_is_at91sam9x5())
+ || cpu_is_at91sam9x5() \
+ || cpu_is_at91sam9n12())
-#define cpu_has_alt_prescaler() (cpu_is_at91sam9x5())
+#define cpu_has_alt_prescaler() (cpu_is_at91sam9x5() \
+ || cpu_is_at91sam9n12())
static LIST_HEAD(clocks);
static DEFINE_SPINLOCK(clk_lock);
diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c
index ece1f9aefb47..0c6381516a5a 100644
--- a/arch/arm/mach-at91/cpuidle.c
+++ b/arch/arm/mach-at91/cpuidle.c
@@ -21,6 +21,7 @@
#include <linux/export.h>
#include <asm/proc-fns.h>
#include <asm/cpuidle.h>
+#include <mach/cpu.h>
#include "pm.h"
@@ -33,7 +34,12 @@ static int at91_enter_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
- at91_standby();
+ if (cpu_is_at91rm9200())
+ at91rm9200_standby();
+ else if (cpu_is_at91sam9g45())
+ at91sam9g45_standby();
+ else
+ at91sam9_standby();
return index;
}
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
index dd9b346c451d..0a60bf837037 100644
--- a/arch/arm/mach-at91/generic.h
+++ b/arch/arm/mach-at91/generic.h
@@ -40,17 +40,6 @@ extern struct sys_timer at91sam926x_timer;
extern struct sys_timer at91x40_timer;
/* Clocks */
-/*
- * function to specify the clock of the default console. As we do not
- * use the device/driver bus, the dev_name is not intialize. So we need
- * to link the clock to a specific con_id only "usart"
- */
-extern void __init at91rm9200_set_console_clock(int id);
-extern void __init at91sam9260_set_console_clock(int id);
-extern void __init at91sam9261_set_console_clock(int id);
-extern void __init at91sam9263_set_console_clock(int id);
-extern void __init at91sam9rl_set_console_clock(int id);
-extern void __init at91sam9g45_set_console_clock(int id);
#ifdef CONFIG_AT91_PMC_UNIT
extern int __init at91_clock_init(unsigned long main_clock);
extern int __init at91_dt_clock_init(void);
diff --git a/arch/arm/mach-at91/include/mach/at91rm9200.h b/arch/arm/mach-at91/include/mach/at91rm9200.h
index 603e6aac2a4f..e67317c67761 100644
--- a/arch/arm/mach-at91/include/mach/at91rm9200.h
+++ b/arch/arm/mach-at91/include/mach/at91rm9200.h
@@ -88,11 +88,6 @@
#define AT91RM9200_BASE_RTC 0xfffffe00 /* Real-Time Clock */
#define AT91RM9200_BASE_MC 0xffffff00 /* Memory Controllers */
-#define AT91_USART0 AT91RM9200_BASE_US0
-#define AT91_USART1 AT91RM9200_BASE_US1
-#define AT91_USART2 AT91RM9200_BASE_US2
-#define AT91_USART3 AT91RM9200_BASE_US3
-
/*
* Internal Memory.
*/
diff --git a/arch/arm/mach-at91/include/mach/at91sam9260.h b/arch/arm/mach-at91/include/mach/at91sam9260.h
index 08ae9afd00fe..416c7b6c56d3 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9260.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9260.h
@@ -95,13 +95,6 @@
#define AT91SAM9260_BASE_WDT 0xfffffd40
#define AT91SAM9260_BASE_GPBR 0xfffffd50
-#define AT91_USART0 AT91SAM9260_BASE_US0
-#define AT91_USART1 AT91SAM9260_BASE_US1
-#define AT91_USART2 AT91SAM9260_BASE_US2
-#define AT91_USART3 AT91SAM9260_BASE_US3
-#define AT91_USART4 AT91SAM9260_BASE_US4
-#define AT91_USART5 AT91SAM9260_BASE_US5
-
/*
* Internal Memory.
diff --git a/arch/arm/mach-at91/include/mach/at91sam9261.h b/arch/arm/mach-at91/include/mach/at91sam9261.h
index 44fbdc12ee62..a041406d06ee 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9261.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9261.h
@@ -79,10 +79,6 @@
#define AT91SAM9261_BASE_WDT 0xfffffd40
#define AT91SAM9261_BASE_GPBR 0xfffffd50
-#define AT91_USART0 AT91SAM9261_BASE_US0
-#define AT91_USART1 AT91SAM9261_BASE_US1
-#define AT91_USART2 AT91SAM9261_BASE_US2
-
/*
* Internal Memory.
diff --git a/arch/arm/mach-at91/include/mach/at91sam9263.h b/arch/arm/mach-at91/include/mach/at91sam9263.h
index d96cbb2e03c4..d201029d60b3 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9263.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9263.h
@@ -95,10 +95,6 @@
#define AT91SAM9263_BASE_RTT1 0xfffffd50
#define AT91SAM9263_BASE_GPBR 0xfffffd60
-#define AT91_USART0 AT91SAM9263_BASE_US0
-#define AT91_USART1 AT91SAM9263_BASE_US1
-#define AT91_USART2 AT91SAM9263_BASE_US2
-
#define AT91_SMC AT91_SMC0
/*
diff --git a/arch/arm/mach-at91/include/mach/at91sam9g45.h b/arch/arm/mach-at91/include/mach/at91sam9g45.h
index d052abcff852..3a4da24d5911 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9g45.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9g45.h
@@ -106,11 +106,6 @@
#define AT91SAM9G45_BASE_RTC 0xfffffdb0
#define AT91SAM9G45_BASE_GPBR 0xfffffd60
-#define AT91_USART0 AT91SAM9G45_BASE_US0
-#define AT91_USART1 AT91SAM9G45_BASE_US1
-#define AT91_USART2 AT91SAM9G45_BASE_US2
-#define AT91_USART3 AT91SAM9G45_BASE_US3
-
/*
* Internal Memory.
*/
diff --git a/arch/arm/mach-at91/include/mach/at91sam9n12.h b/arch/arm/mach-at91/include/mach/at91sam9n12.h
new file mode 100644
index 000000000000..d374b87c0459
--- /dev/null
+++ b/arch/arm/mach-at91/include/mach/at91sam9n12.h
@@ -0,0 +1,60 @@
+/*
+ * SoC specific header file for the AT91SAM9N12
+ *
+ * Copyright (C) 2012 Atmel Corporation
+ *
+ * Common definitions, based on AT91SAM9N12 SoC datasheet
+ *
+ * Licensed under GPLv2 or later
+ */
+
+#ifndef _AT91SAM9N12_H_
+#define _AT91SAM9N12_H_
+
+/*
+ * Peripheral identifiers/interrupts.
+ */
+#define AT91SAM9N12_ID_PIOAB 2 /* Parallel I/O Controller A and B */
+#define AT91SAM9N12_ID_PIOCD 3 /* Parallel I/O Controller C and D */
+#define AT91SAM9N12_ID_FUSE 4 /* FUSE Controller */
+#define AT91SAM9N12_ID_USART0 5 /* USART 0 */
+#define AT91SAM9N12_ID_USART1 6 /* USART 1 */
+#define AT91SAM9N12_ID_USART2 7 /* USART 2 */
+#define AT91SAM9N12_ID_USART3 8 /* USART 3 */
+#define AT91SAM9N12_ID_TWI0 9 /* Two-Wire Interface 0 */
+#define AT91SAM9N12_ID_TWI1 10 /* Two-Wire Interface 1 */
+#define AT91SAM9N12_ID_MCI 12 /* High Speed Multimedia Card Interface */
+#define AT91SAM9N12_ID_SPI0 13 /* Serial Peripheral Interface 0 */
+#define AT91SAM9N12_ID_SPI1 14 /* Serial Peripheral Interface 1 */
+#define AT91SAM9N12_ID_UART0 15 /* UART 0 */
+#define AT91SAM9N12_ID_UART1 16 /* UART 1 */
+#define AT91SAM9N12_ID_TCB 17 /* Timer Counter 0, 1, 2, 3, 4 and 5 */
+#define AT91SAM9N12_ID_PWM 18 /* Pulse Width Modulation Controller */
+#define AT91SAM9N12_ID_ADC 19 /* ADC Controller */
+#define AT91SAM9N12_ID_DMA 20 /* DMA Controller */
+#define AT91SAM9N12_ID_UHP 22 /* USB Host High Speed */
+#define AT91SAM9N12_ID_UDP 23 /* USB Device High Speed */
+#define AT91SAM9N12_ID_LCDC 25 /* LCD Controller */
+#define AT91SAM9N12_ID_ISI 25 /* Image Sensor Interface */
+#define AT91SAM9N12_ID_SSC 28 /* Synchronous Serial Controller */
+#define AT91SAM9N12_ID_TRNG 30 /* TRNG */
+#define AT91SAM9N12_ID_IRQ0 31 /* Advanced Interrupt Controller */
+
+/*
+ * User Peripheral physical base addresses.
+ */
+#define AT91SAM9N12_BASE_USART0 0xf801c000
+#define AT91SAM9N12_BASE_USART1 0xf8020000
+#define AT91SAM9N12_BASE_USART2 0xf8024000
+#define AT91SAM9N12_BASE_USART3 0xf8028000
+
+/*
+ * Internal Memory.
+ */
+#define AT91SAM9N12_SRAM_BASE 0x00300000 /* Internal SRAM base address */
+#define AT91SAM9N12_SRAM_SIZE SZ_32K /* Internal SRAM size (32Kb) */
+
+#define AT91SAM9N12_ROM_BASE 0x00100000 /* Internal ROM base address */
+#define AT91SAM9N12_ROM_SIZE SZ_128K /* Internal ROM size (128Kb) */
+
+#endif
diff --git a/arch/arm/mach-at91/include/mach/at91sam9n12_matrix.h b/arch/arm/mach-at91/include/mach/at91sam9n12_matrix.h
new file mode 100644
index 000000000000..40060cd62fa9
--- /dev/null
+++ b/arch/arm/mach-at91/include/mach/at91sam9n12_matrix.h
@@ -0,0 +1,53 @@
+/*
+ * Matrix-centric header file for the AT91SAM9N12
+ *
+ * Copyright (C) 2012 Atmel Corporation.
+ *
+ * Only EBI related registers.
+ * Write Protect register definitions may be useful.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#ifndef _AT91SAM9N12_MATRIX_H_
+#define _AT91SAM9N12_MATRIX_H_
+
+#define AT91_MATRIX_EBICSA (AT91_MATRIX + 0x118) /* EBI Chip Select Assignment Register */
+#define AT91_MATRIX_EBI_CS1A (1 << 1) /* Chip Select 1 Assignment */
+#define AT91_MATRIX_EBI_CS1A_SMC (0 << 1)
+#define AT91_MATRIX_EBI_CS1A_SDRAMC (1 << 1)
+#define AT91_MATRIX_EBI_CS3A (1 << 3) /* Chip Select 3 Assignment */
+#define AT91_MATRIX_EBI_CS3A_SMC (0 << 3)
+#define AT91_MATRIX_EBI_CS3A_SMC_NANDFLASH (1 << 3)
+#define AT91_MATRIX_EBI_DBPUC (1 << 8) /* Data Bus Pull-up Configuration */
+#define AT91_MATRIX_EBI_DBPU_ON (0 << 8)
+#define AT91_MATRIX_EBI_DBPU_OFF (1 << 8)
+#define AT91_MATRIX_EBI_VDDIOMSEL (1 << 16) /* Memory voltage selection */
+#define AT91_MATRIX_EBI_VDDIOMSEL_1_8V (0 << 16)
+#define AT91_MATRIX_EBI_VDDIOMSEL_3_3V (1 << 16)
+#define AT91_MATRIX_EBI_EBI_IOSR (1 << 17) /* EBI I/O slew rate selection */
+#define AT91_MATRIX_EBI_EBI_IOSR_REDUCED (0 << 17)
+#define AT91_MATRIX_EBI_EBI_IOSR_NORMAL (1 << 17)
+#define AT91_MATRIX_EBI_DDR_IOSR (1 << 18) /* DDR2 dedicated port I/O slew rate selection */
+#define AT91_MATRIX_EBI_DDR_IOSR_REDUCED (0 << 18)
+#define AT91_MATRIX_EBI_DDR_IOSR_NORMAL (1 << 18)
+#define AT91_MATRIX_NFD0_SELECT (1 << 24) /* NAND Flash Data Bus Selection */
+#define AT91_MATRIX_NFD0_ON_D0 (0 << 24)
+#define AT91_MATRIX_NFD0_ON_D16 (1 << 24)
+#define AT91_MATRIX_DDR_MP_EN (1 << 25) /* DDR Multi-port Enable */
+#define AT91_MATRIX_MP_OFF (0 << 25)
+#define AT91_MATRIX_MP_ON (1 << 25)
+
+#define AT91_MATRIX_WPMR (AT91_MATRIX + 0x1E4) /* Write Protect Mode Register */
+#define AT91_MATRIX_WPMR_WPEN (1 << 0) /* Write Protect ENable */
+#define AT91_MATRIX_WPMR_WP_WPDIS (0 << 0)
+#define AT91_MATRIX_WPMR_WP_WPEN (1 << 0)
+#define AT91_MATRIX_WPMR_WPKEY (0xFFFFFF << 8) /* Write Protect KEY */
+
+#define AT91_MATRIX_WPSR (AT91_MATRIX + 0x1E8) /* Write Protect Status Register */
+#define AT91_MATRIX_WPSR_WPVS (1 << 0) /* Write Protect Violation Status */
+#define AT91_MATRIX_WPSR_NO_WPV (0 << 0)
+#define AT91_MATRIX_WPSR_WPV (1 << 0)
+#define AT91_MATRIX_WPSR_WPVSRC (0xFFFF << 8) /* Write Protect Violation Source */
+
+#endif
diff --git a/arch/arm/mach-at91/include/mach/at91sam9rl.h b/arch/arm/mach-at91/include/mach/at91sam9rl.h
index e0073eb10144..a15db56d33fa 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9rl.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9rl.h
@@ -89,11 +89,6 @@
#define AT91SAM9RL_BASE_GPBR 0xfffffd60
#define AT91SAM9RL_BASE_RTC 0xfffffe00
-#define AT91_USART0 AT91SAM9RL_BASE_US0
-#define AT91_USART1 AT91SAM9RL_BASE_US1
-#define AT91_USART2 AT91SAM9RL_BASE_US2
-#define AT91_USART3 AT91SAM9RL_BASE_US3
-
/*
* Internal Memory.
diff --git a/arch/arm/mach-at91/include/mach/at91sam9x5.h b/arch/arm/mach-at91/include/mach/at91sam9x5.h
index 88e43d534cdf..c75ee19b58d3 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9x5.h
+++ b/arch/arm/mach-at91/include/mach/at91sam9x5.h
@@ -55,14 +55,6 @@
#define AT91SAM9X5_BASE_USART2 0xf8024000
/*
- * Base addresses for early serial code (uncompress.h)
- */
-#define AT91_DBGU AT91_BASE_DBGU0
-#define AT91_USART0 AT91SAM9X5_BASE_USART0
-#define AT91_USART1 AT91SAM9X5_BASE_USART1
-#define AT91_USART2 AT91SAM9X5_BASE_USART2
-
-/*
* Internal Memory.
*/
#define AT91SAM9X5_SRAM_BASE 0x00300000 /* Internal SRAM base address */
diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
index 49a821192c65..369afc2ffc5b 100644
--- a/arch/arm/mach-at91/include/mach/board.h
+++ b/arch/arm/mach-at91/include/mach/board.h
@@ -121,7 +121,6 @@ extern void __init at91_add_device_spi(struct spi_board_info *devices, int nr_de
#define ATMEL_UART_RI 0x20
extern void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins);
-extern void __init at91_set_serial_console(unsigned portnr);
extern struct platform_device *atmel_default_console_device;
diff --git a/arch/arm/mach-at91/include/mach/cpu.h b/arch/arm/mach-at91/include/mach/cpu.h
index 0118c3338552..b6504c19d55c 100644
--- a/arch/arm/mach-at91/include/mach/cpu.h
+++ b/arch/arm/mach-at91/include/mach/cpu.h
@@ -25,6 +25,7 @@
#define ARCH_ID_AT91SAM9G45MRL 0x819b05a2 /* aka 9G45-ES2 & non ES lots */
#define ARCH_ID_AT91SAM9G45ES 0x819b05a1 /* 9G45-ES (Engineering Sample) */
#define ARCH_ID_AT91SAM9X5 0x819a05a0
+#define ARCH_ID_AT91SAM9N12 0x819a07a0
#define ARCH_ID_AT91SAM9XE128 0x329973a0
#define ARCH_ID_AT91SAM9XE256 0x329a93a0
@@ -54,6 +55,7 @@
#define ARCH_REVISON_9200_BGA (0 << 0)
#define ARCH_REVISON_9200_PQFP (1 << 0)
+#ifndef __ASSEMBLY__
enum at91_soc_type {
/* 920T */
AT91_SOC_RM9200,
@@ -70,6 +72,9 @@ enum at91_soc_type {
/* SAM9X5 */
AT91_SOC_SAM9X5,
+ /* SAM9N12 */
+ AT91_SOC_SAM9N12,
+
/* Unknown type */
AT91_SOC_NONE
};
@@ -106,7 +111,7 @@ static inline int at91_soc_is_detected(void)
return at91_soc_initdata.type != AT91_SOC_NONE;
}
-#ifdef CONFIG_ARCH_AT91RM9200
+#ifdef CONFIG_SOC_AT91RM9200
#define cpu_is_at91rm9200() (at91_soc_initdata.type == AT91_SOC_RM9200)
#define cpu_is_at91rm9200_bga() (at91_soc_initdata.subtype == AT91_SOC_RM9200_BGA)
#define cpu_is_at91rm9200_pqfp() (at91_soc_initdata.subtype == AT91_SOC_RM9200_PQFP)
@@ -116,45 +121,37 @@ static inline int at91_soc_is_detected(void)
#define cpu_is_at91rm9200_pqfp() (0)
#endif
-#ifdef CONFIG_ARCH_AT91SAM9260
+#ifdef CONFIG_SOC_AT91SAM9260
#define cpu_is_at91sam9xe() (at91_soc_initdata.subtype == AT91_SOC_SAM9XE)
#define cpu_is_at91sam9260() (at91_soc_initdata.type == AT91_SOC_SAM9260)
+#define cpu_is_at91sam9g20() (at91_soc_initdata.type == AT91_SOC_SAM9G20)
#else
#define cpu_is_at91sam9xe() (0)
#define cpu_is_at91sam9260() (0)
-#endif
-
-#ifdef CONFIG_ARCH_AT91SAM9G20
-#define cpu_is_at91sam9g20() (at91_soc_initdata.type == AT91_SOC_SAM9G20)
-#else
#define cpu_is_at91sam9g20() (0)
#endif
-#ifdef CONFIG_ARCH_AT91SAM9261
+#ifdef CONFIG_SOC_AT91SAM9261
#define cpu_is_at91sam9261() (at91_soc_initdata.type == AT91_SOC_SAM9261)
-#else
-#define cpu_is_at91sam9261() (0)
-#endif
-
-#ifdef CONFIG_ARCH_AT91SAM9G10
#define cpu_is_at91sam9g10() (at91_soc_initdata.type == AT91_SOC_SAM9G10)
#else
+#define cpu_is_at91sam9261() (0)
#define cpu_is_at91sam9g10() (0)
#endif
-#ifdef CONFIG_ARCH_AT91SAM9263
+#ifdef CONFIG_SOC_AT91SAM9263
#define cpu_is_at91sam9263() (at91_soc_initdata.type == AT91_SOC_SAM9263)
#else
#define cpu_is_at91sam9263() (0)
#endif
-#ifdef CONFIG_ARCH_AT91SAM9RL
+#ifdef CONFIG_SOC_AT91SAM9RL
#define cpu_is_at91sam9rl() (at91_soc_initdata.type == AT91_SOC_SAM9RL)
#else
#define cpu_is_at91sam9rl() (0)
#endif
-#ifdef CONFIG_ARCH_AT91SAM9G45
+#ifdef CONFIG_SOC_AT91SAM9G45
#define cpu_is_at91sam9g45() (at91_soc_initdata.type == AT91_SOC_SAM9G45)
#define cpu_is_at91sam9g45es() (at91_soc_initdata.subtype == AT91_SOC_SAM9G45ES)
#define cpu_is_at91sam9m10() (at91_soc_initdata.subtype == AT91_SOC_SAM9M10)
@@ -168,7 +165,7 @@ static inline int at91_soc_is_detected(void)
#define cpu_is_at91sam9m11() (0)
#endif
-#ifdef CONFIG_ARCH_AT91SAM9X5
+#ifdef CONFIG_SOC_AT91SAM9X5
#define cpu_is_at91sam9x5() (at91_soc_initdata.type == AT91_SOC_SAM9X5)
#define cpu_is_at91sam9g15() (at91_soc_initdata.subtype == AT91_SOC_SAM9G15)
#define cpu_is_at91sam9g35() (at91_soc_initdata.subtype == AT91_SOC_SAM9G35)
@@ -184,10 +181,17 @@ static inline int at91_soc_is_detected(void)
#define cpu_is_at91sam9x25() (0)
#endif
+#ifdef CONFIG_SOC_AT91SAM9N12
+#define cpu_is_at91sam9n12() (at91_soc_initdata.type == AT91_SOC_SAM9N12)
+#else
+#define cpu_is_at91sam9n12() (0)
+#endif
+
/*
* Since this is ARM, we will never run on any AVR32 CPU. But these
* definitions may reduce clutter in common drivers.
*/
#define cpu_is_at32ap7000() (0)
+#endif /* __ASSEMBLY__ */
#endif /* __MACH_CPU_H__ */
diff --git a/arch/arm/mach-at91/include/mach/hardware.h b/arch/arm/mach-at91/include/mach/hardware.h
index 01db372be8e5..09242b67d277 100644
--- a/arch/arm/mach-at91/include/mach/hardware.h
+++ b/arch/arm/mach-at91/include/mach/hardware.h
@@ -22,27 +22,18 @@
/* 9263, 9g45 */
#define AT91_BASE_DBGU1 0xffffee00
-#if defined(CONFIG_ARCH_AT91RM9200)
+#if defined(CONFIG_ARCH_AT91X40)
+#include <mach/at91x40.h>
+#else
#include <mach/at91rm9200.h>
-#elif defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20)
#include <mach/at91sam9260.h>
-#elif defined(CONFIG_ARCH_AT91SAM9261) || defined(CONFIG_ARCH_AT91SAM9G10)
#include <mach/at91sam9261.h>
-#elif defined(CONFIG_ARCH_AT91SAM9263)
#include <mach/at91sam9263.h>
-#elif defined(CONFIG_ARCH_AT91SAM9RL)
#include <mach/at91sam9rl.h>
-#elif defined(CONFIG_ARCH_AT91SAM9G45)
#include <mach/at91sam9g45.h>
-#elif defined(CONFIG_ARCH_AT91SAM9X5)
#include <mach/at91sam9x5.h>
-#elif defined(CONFIG_ARCH_AT91X40)
-#include <mach/at91x40.h>
-#else
-#error "Unsupported AT91 processor"
-#endif
+#include <mach/at91sam9n12.h>
-#if !defined(CONFIG_ARCH_AT91X40)
/*
* On all at91 except rm9200 and x40 have the System Controller starts
* at address 0xffffc000 and has a size of 16KiB.
diff --git a/arch/arm/mach-at91/include/mach/uncompress.h b/arch/arm/mach-at91/include/mach/uncompress.h
index 4218647c1fcd..6f6118d1576a 100644
--- a/arch/arm/mach-at91/include/mach/uncompress.h
+++ b/arch/arm/mach-at91/include/mach/uncompress.h
@@ -1,7 +1,8 @@
/*
* arch/arm/mach-at91/include/mach/uncompress.h
*
- * Copyright (C) 2003 SAN People
+ * Copyright (C) 2003 SAN People
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.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
@@ -25,22 +26,147 @@
#include <linux/atmel_serial.h>
#include <mach/hardware.h>
-#if defined(CONFIG_AT91_EARLY_DBGU0)
-#define UART_OFFSET AT91_BASE_DBGU0
-#elif defined(CONFIG_AT91_EARLY_DBGU1)
-#define UART_OFFSET AT91_BASE_DBGU1
-#elif defined(CONFIG_AT91_EARLY_USART0)
-#define UART_OFFSET AT91_USART0
-#elif defined(CONFIG_AT91_EARLY_USART1)
-#define UART_OFFSET AT91_USART1
-#elif defined(CONFIG_AT91_EARLY_USART2)
-#define UART_OFFSET AT91_USART2
-#elif defined(CONFIG_AT91_EARLY_USART3)
-#define UART_OFFSET AT91_USART3
-#elif defined(CONFIG_AT91_EARLY_USART4)
-#define UART_OFFSET AT91_USART4
-#elif defined(CONFIG_AT91_EARLY_USART5)
-#define UART_OFFSET AT91_USART5
+#include <mach/at91_dbgu.h>
+#include <mach/cpu.h>
+
+void __iomem *at91_uart;
+
+#if !defined(CONFIG_ARCH_AT91X40)
+static const u32 uarts_rm9200[] = {
+ AT91_BASE_DBGU0,
+ AT91RM9200_BASE_US0,
+ AT91RM9200_BASE_US1,
+ AT91RM9200_BASE_US2,
+ AT91RM9200_BASE_US3,
+ 0,
+};
+
+static const u32 uarts_sam9260[] = {
+ AT91_BASE_DBGU0,
+ AT91SAM9260_BASE_US0,
+ AT91SAM9260_BASE_US1,
+ AT91SAM9260_BASE_US2,
+ AT91SAM9260_BASE_US3,
+ AT91SAM9260_BASE_US4,
+ AT91SAM9260_BASE_US5,
+ 0,
+};
+
+static const u32 uarts_sam9261[] = {
+ AT91_BASE_DBGU0,
+ AT91SAM9261_BASE_US0,
+ AT91SAM9261_BASE_US1,
+ AT91SAM9261_BASE_US2,
+ 0,
+};
+
+static const u32 uarts_sam9263[] = {
+ AT91_BASE_DBGU1,
+ AT91SAM9263_BASE_US0,
+ AT91SAM9263_BASE_US1,
+ AT91SAM9263_BASE_US2,
+ 0,
+};
+
+static const u32 uarts_sam9g45[] = {
+ AT91_BASE_DBGU1,
+ AT91SAM9G45_BASE_US0,
+ AT91SAM9G45_BASE_US1,
+ AT91SAM9G45_BASE_US2,
+ AT91SAM9G45_BASE_US3,
+ 0,
+};
+
+static const u32 uarts_sam9rl[] = {
+ AT91_BASE_DBGU0,
+ AT91SAM9RL_BASE_US0,
+ AT91SAM9RL_BASE_US1,
+ AT91SAM9RL_BASE_US2,
+ AT91SAM9RL_BASE_US3,
+ 0,
+};
+
+static const u32 uarts_sam9x5[] = {
+ AT91_BASE_DBGU0,
+ AT91SAM9X5_BASE_USART0,
+ AT91SAM9X5_BASE_USART1,
+ AT91SAM9X5_BASE_USART2,
+ 0,
+};
+
+static inline const u32* decomp_soc_detect(u32 dbgu_base)
+{
+ u32 cidr, socid;
+
+ cidr = __raw_readl(dbgu_base + AT91_DBGU_CIDR);
+ socid = cidr & ~AT91_CIDR_VERSION;
+
+ switch (socid) {
+ case ARCH_ID_AT91RM9200:
+ return uarts_rm9200;
+
+ case ARCH_ID_AT91SAM9G20:
+ case ARCH_ID_AT91SAM9260:
+ return uarts_sam9260;
+
+ case ARCH_ID_AT91SAM9261:
+ return uarts_sam9261;
+
+ case ARCH_ID_AT91SAM9263:
+ return uarts_sam9263;
+
+ case ARCH_ID_AT91SAM9G45:
+ return uarts_sam9g45;
+
+ case ARCH_ID_AT91SAM9RL64:
+ return uarts_sam9rl;
+
+ case ARCH_ID_AT91SAM9X5:
+ return uarts_sam9x5;
+ }
+
+ /* at91sam9g10 */
+ if ((cidr & ~AT91_CIDR_EXT) == ARCH_ID_AT91SAM9G10) {
+ return uarts_sam9261;
+ }
+ /* at91sam9xe */
+ else if ((cidr & AT91_CIDR_ARCH) == ARCH_FAMILY_AT91SAM9XE) {
+ return uarts_sam9260;
+ }
+
+ return NULL;
+}
+
+static inline void arch_decomp_setup(void)
+{
+ int i = 0;
+ const u32* usarts;
+
+ usarts = decomp_soc_detect(AT91_BASE_DBGU0);
+
+ if (!usarts)
+ usarts = decomp_soc_detect(AT91_BASE_DBGU1);
+ if (!usarts) {
+ at91_uart = NULL;
+ return;
+ }
+
+ do {
+ /* physical address */
+ at91_uart = (void __iomem *)usarts[i];
+
+ if (__raw_readl(at91_uart + ATMEL_US_BRGR))
+ return;
+ i++;
+ } while (usarts[i]);
+
+ at91_uart = NULL;
+}
+#else
+static inline void arch_decomp_setup(void)
+{
+ at91_uart = NULL;
+}
#endif
/*
@@ -52,28 +178,24 @@
*/
static void putc(int c)
{
-#ifdef UART_OFFSET
- void __iomem *sys = (void __iomem *) UART_OFFSET; /* physical address */
+ if (!at91_uart)
+ return;
- while (!(__raw_readl(sys + ATMEL_US_CSR) & ATMEL_US_TXRDY))
+ while (!(__raw_readl(at91_uart + ATMEL_US_CSR) & ATMEL_US_TXRDY))
barrier();
- __raw_writel(c, sys + ATMEL_US_THR);
-#endif
+ __raw_writel(c, at91_uart + ATMEL_US_THR);
}
static inline void flush(void)
{
-#ifdef UART_OFFSET
- void __iomem *sys = (void __iomem *) UART_OFFSET; /* physical address */
+ if (!at91_uart)
+ return;
/* wait for transmission to complete */
- while (!(__raw_readl(sys + ATMEL_US_CSR) & ATMEL_US_TXEMPTY))
+ while (!(__raw_readl(at91_uart + ATMEL_US_CSR) & ATMEL_US_TXEMPTY))
barrier();
-#endif
}
-#define arch_decomp_setup()
-
#define arch_decomp_wdog()
#endif
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index f630250c6b87..1bfaad628731 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -261,7 +261,12 @@ static int at91_pm_enter(suspend_state_t state)
* For ARM 926 based chips, this requirement is weaker
* as at91sam9 can access a RAM in self-refresh mode.
*/
- at91_standby();
+ if (cpu_is_at91rm9200())
+ at91rm9200_standby();
+ else if (cpu_is_at91sam9g45())
+ at91sam9g45_standby();
+ else
+ at91sam9_standby();
break;
case PM_SUSPEND_ON:
@@ -307,10 +312,9 @@ static int __init at91_pm_init(void)
pr_info("AT91: Power Management%s\n", (slow_clock ? " (with slow clock mode)" : ""));
-#ifdef CONFIG_ARCH_AT91RM9200
/* AT91RM9200 SDRAM low-power mode cannot be used with self-refresh. */
- at91_ramc_write(0, AT91RM9200_SDRAMC_LPR, 0);
-#endif
+ if (cpu_is_at91rm9200())
+ at91_ramc_write(0, AT91RM9200_SDRAMC_LPR, 0);
suspend_set_ops(&at91_pm_ops);
diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h
index 89f56f3a802e..38f467c6b710 100644
--- a/arch/arm/mach-at91/pm.h
+++ b/arch/arm/mach-at91/pm.h
@@ -12,7 +12,6 @@
#define __ARCH_ARM_MACH_AT91_PM
#include <mach/at91_ramc.h>
-#ifdef CONFIG_ARCH_AT91RM9200
#include <mach/at91rm9200_sdramc.h>
/*
@@ -43,10 +42,6 @@ static inline void at91rm9200_standby(void)
"r" (lpr));
}
-#define at91_standby at91rm9200_standby
-
-#elif defined(CONFIG_ARCH_AT91SAM9G45)
-
/* We manage both DDRAM/SDRAM controllers, we need more than one value to
* remember.
*/
@@ -75,11 +70,7 @@ static inline void at91sam9g45_standby(void)
at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1);
}
-#define at91_standby at91sam9g45_standby
-
-#else
-
-#ifdef CONFIG_ARCH_AT91SAM9263
+#ifdef CONFIG_SOC_AT91SAM9263
/*
* FIXME either or both the SDRAM controllers (EB0, EB1) might be in use;
* handle those cases both here and in the Suspend-To-RAM support.
@@ -102,8 +93,4 @@ static inline void at91sam9_standby(void)
at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr);
}
-#define at91_standby at91sam9_standby
-
-#endif
-
#endif
diff --git a/arch/arm/mach-at91/pm_slowclock.S b/arch/arm/mach-at91/pm_slowclock.S
index db5452123f17..098c28ddf025 100644
--- a/arch/arm/mach-at91/pm_slowclock.S
+++ b/arch/arm/mach-at91/pm_slowclock.S
@@ -18,7 +18,7 @@
#include <mach/at91_ramc.h>
-#ifdef CONFIG_ARCH_AT91SAM9263
+#ifdef CONFIG_SOC_AT91SAM9263
/*
* FIXME either or both the SDRAM controllers (EB0, EB1) might be in use;
* handle those cases both here and in the Suspend-To-RAM support.
diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
index f44a2e7272e3..944bffb08991 100644
--- a/arch/arm/mach-at91/setup.c
+++ b/arch/arm/mach-at91/setup.c
@@ -143,6 +143,11 @@ static void __init soc_detect(u32 dbgu_base)
at91_soc_initdata.type = AT91_SOC_SAM9X5;
at91_boot_soc = at91sam9x5_soc;
break;
+
+ case ARCH_ID_AT91SAM9N12:
+ at91_soc_initdata.type = AT91_SOC_SAM9N12;
+ at91_boot_soc = at91sam9n12_soc;
+ break;
}
/* at91sam9g10 */
@@ -210,6 +215,7 @@ static const char *soc_name[] = {
[AT91_SOC_SAM9G45] = "at91sam9g45",
[AT91_SOC_SAM9RL] = "at91sam9rl",
[AT91_SOC_SAM9X5] = "at91sam9x5",
+ [AT91_SOC_SAM9N12] = "at91sam9n12",
[AT91_SOC_NONE] = "Unknown"
};
diff --git a/arch/arm/mach-at91/soc.h b/arch/arm/mach-at91/soc.h
index 5db4aa45404a..a9cfeb153719 100644
--- a/arch/arm/mach-at91/soc.h
+++ b/arch/arm/mach-at91/soc.h
@@ -20,36 +20,41 @@ extern struct at91_init_soc at91sam9263_soc;
extern struct at91_init_soc at91sam9g45_soc;
extern struct at91_init_soc at91sam9rl_soc;
extern struct at91_init_soc at91sam9x5_soc;
+extern struct at91_init_soc at91sam9n12_soc;
static inline int at91_soc_is_enabled(void)
{
return at91_boot_soc.init != NULL;
}
-#if !defined(CONFIG_ARCH_AT91RM9200)
+#if !defined(CONFIG_SOC_AT91RM9200)
#define at91rm9200_soc at91_boot_soc
#endif
-#if !(defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9G20))
+#if !defined(CONFIG_SOC_AT91SAM9260)
#define at91sam9260_soc at91_boot_soc
#endif
-#if !(defined(CONFIG_ARCH_AT91SAM9261) || defined(CONFIG_ARCH_AT91SAM9G10))
+#if !defined(CONFIG_SOC_AT91SAM9261)
#define at91sam9261_soc at91_boot_soc
#endif
-#if !defined(CONFIG_ARCH_AT91SAM9263)
+#if !defined(CONFIG_SOC_AT91SAM9263)
#define at91sam9263_soc at91_boot_soc
#endif
-#if !defined(CONFIG_ARCH_AT91SAM9G45)
+#if !defined(CONFIG_SOC_AT91SAM9G45)
#define at91sam9g45_soc at91_boot_soc
#endif
-#if !defined(CONFIG_ARCH_AT91SAM9RL)
+#if !defined(CONFIG_SOC_AT91SAM9RL)
#define at91sam9rl_soc at91_boot_soc
#endif
-#if !defined(CONFIG_ARCH_AT91SAM9X5)
+#if !defined(CONFIG_SOC_AT91SAM9X5)
#define at91sam9x5_soc at91_boot_soc
#endif
+
+#if !defined(CONFIG_SOC_AT91SAM9N12)
+#define at91sam9n12_soc at91_boot_soc
+#endif
diff --git a/arch/arm/mach-clps711x/Kconfig b/arch/arm/mach-clps711x/Kconfig
index eb34bd1251d4..ea036d621581 100644
--- a/arch/arm/mach-clps711x/Kconfig
+++ b/arch/arm/mach-clps711x/Kconfig
@@ -1,6 +1,6 @@
if ARCH_CLPS711X
-menu "CLPS711X/EP721X Implementations"
+menu "CLPS711X/EP721X/EP731X Implementations"
config ARCH_AUTCPU12
bool "AUTCPU12"
@@ -45,26 +45,13 @@ config ARCH_P720T
config ARCH_FORTUNET
bool "FORTUNET"
-# XXX Maybe these should indicate register compatibility
-# instead of being mutually exclusive.
-config ARCH_EP7211
- bool
- depends on ARCH_EDB7211
- default y
-
-config ARCH_EP7212
- bool
- depends on ARCH_P720T || ARCH_CEIVA
- default y
-
config EP72XX_ROM_BOOT
- bool "EP72xx ROM boot"
- depends on ARCH_EP7211 || ARCH_EP7212
- ---help---
+ bool "EP721x/EP731x ROM boot"
+ help
If you say Y here, your CLPS711x-based kernel will use the bootstrap
mode memory map instead of the normal memory map.
- Processors derived from the Cirrus CLPS-711X core support two boot
+ Processors derived from the Cirrus CLPS711X core support two boot
modes. Normal mode boots from the external memory device at CS0.
Bootstrap mode rearranges parts of the memory map, placing an
internal 128 byte bootstrap ROM at CS0. This option performs the
diff --git a/arch/arm/mach-clps711x/common.c b/arch/arm/mach-clps711x/common.c
index 3c5b5bbf24e5..c965fd8eb31a 100644
--- a/arch/arm/mach-clps711x/common.c
+++ b/arch/arm/mach-clps711x/common.c
@@ -36,7 +36,6 @@
#include <asm/page.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
-#include <asm/hardware/clps7111.h>
#include <asm/system_misc.h>
/*
@@ -44,8 +43,8 @@
*/
static struct map_desc clps711x_io_desc[] __initdata = {
{
- .virtual = CLPS7111_VIRT_BASE,
- .pfn = __phys_to_pfn(CLPS7111_PHYS_BASE),
+ .virtual = (unsigned long)CLPS711X_VIRT_BASE,
+ .pfn = __phys_to_pfn(CLPS711X_PHYS_BASE),
.length = SZ_1M,
.type = MT_DEVICE
}
@@ -67,12 +66,6 @@ static void int1_mask(struct irq_data *d)
static void int1_ack(struct irq_data *d)
{
- u32 intmr1;
-
- intmr1 = clps_readl(INTMR1);
- intmr1 &= ~(1 << d->irq);
- clps_writel(intmr1, INTMR1);
-
switch (d->irq) {
case IRQ_CSINT: clps_writel(0, COEOI); break;
case IRQ_TC1OI: clps_writel(0, TC1EOI); break;
@@ -109,12 +102,6 @@ static void int2_mask(struct irq_data *d)
static void int2_ack(struct irq_data *d)
{
- u32 intmr2;
-
- intmr2 = clps_readl(INTMR2);
- intmr2 &= ~(1 << (d->irq - 16));
- clps_writel(intmr2, INTMR2);
-
switch (d->irq) {
case IRQ_KBDINT: clps_writel(0, KBDEOI); break;
}
diff --git a/arch/arm/include/asm/hardware/clps7111.h b/arch/arm/mach-clps711x/include/mach/clps711x.h
index 44477225aed6..1dd806f2847e 100644
--- a/arch/arm/include/asm/hardware/clps7111.h
+++ b/arch/arm/mach-clps711x/include/mach/clps711x.h
@@ -1,8 +1,6 @@
/*
- * arch/arm/include/asm/hardware/clps7111.h
- *
- * This file contains the hardware definitions of the CLPS7111 internal
- * registers.
+ * This file contains the hardware definitions of the Cirrus Logic
+ * ARM7 CLPS711X internal registers.
*
* Copyright (C) 2000 Deep Blue Solutions Ltd.
*
@@ -20,25 +18,18 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef __ASM_HARDWARE_CLPS7111_H
-#define __ASM_HARDWARE_CLPS7111_H
-
-#define CLPS7111_PHYS_BASE (0x80000000)
+#ifndef __MACH_CLPS711X_H
+#define __MACH_CLPS711X_H
-#ifndef __ASSEMBLY__
-#define clps_readb(off) __raw_readb(CLPS7111_BASE + (off))
-#define clps_readw(off) __raw_readw(CLPS7111_BASE + (off))
-#define clps_readl(off) __raw_readl(CLPS7111_BASE + (off))
-#define clps_writeb(val,off) __raw_writeb(val, CLPS7111_BASE + (off))
-#define clps_writew(val,off) __raw_writew(val, CLPS7111_BASE + (off))
-#define clps_writel(val,off) __raw_writel(val, CLPS7111_BASE + (off))
-#endif
+#define CLPS711X_PHYS_BASE (0x80000000)
#define PADR (0x0000)
#define PBDR (0x0001)
+#define PCDR (0x0002)
#define PDDR (0x0003)
#define PADDR (0x0040)
#define PBDDR (0x0041)
+#define PCDDR (0x0042)
#define PDDDR (0x0043)
#define PEDR (0x0080)
#define PEDDR (0x00c0)
@@ -50,7 +41,7 @@
#define INTSR1 (0x0240)
#define INTMR1 (0x0280)
#define LCDCON (0x02c0)
-#define TC1D (0x0300)
+#define TC1D (0x0300)
#define TC2D (0x0340)
#define RTCDR (0x0380)
#define RTCMR (0x03c0)
@@ -85,6 +76,26 @@
#define SS2POP (0x16c0)
#define KBDEOI (0x1700)
+#define DAIR (0x2000)
+#define DAIR0 (0x2040)
+#define DAIDR1 (0x2080)
+#define DAIDR2 (0x20c0)
+#define DAISR (0x2100)
+#define SYSCON3 (0x2200)
+#define INTSR3 (0x2240)
+#define INTMR3 (0x2280)
+#define LEDFLSH (0x22c0)
+#define SDCONF (0x2300)
+#define SDRFPR (0x2340)
+#define UNIQID (0x2440)
+#define DAI64FS (0x2600)
+#define PLLW (0x2610)
+#define PLLR (0xa5a8)
+#define RANDID0 (0x2700)
+#define RANDID1 (0x2704)
+#define RANDID2 (0x2708)
+#define RANDID3 (0x270c)
+
/* common bits: SYSCON1 / SYSCON2 */
#define SYSCON_UARTEN (1 << 8)
@@ -131,6 +142,8 @@
#define SYSFLG1_CTXFF (1 << 25)
#define SYSFLG1_SSIBUSY (1 << 26)
#define SYSFLG1_ID (1 << 29)
+#define SYSFLG1_VERID(x) (((x) >> 30) & 3)
+#define SYSFLG1_VERID_MASK (3 << 30)
#define SYSFLG2_SSRXOF (1 << 0)
#define SYSFLG2_RESVAL (1 << 1)
@@ -178,7 +191,88 @@
#define UBRLCR_WRDLEN8 (3 << 17)
#define UBRLCR_WRDLEN_MASK (3 << 17)
+#define SYNCIO_FRMLEN(x) (((x) & 0x3f) << 7)
+#define SYNCIO_CFGLEN(x) ((x) & 0x7f)
#define SYNCIO_SMCKEN (1 << 13)
#define SYNCIO_TXFRMEN (1 << 14)
-#endif /* __ASM_HARDWARE_CLPS7111_H */
+#define DAIR_RESERVED (0x0404)
+#define DAIR_DAIEN (1 << 16)
+#define DAIR_ECS (1 << 17)
+#define DAIR_LCTM (1 << 19)
+#define DAIR_LCRM (1 << 20)
+#define DAIR_RCTM (1 << 21)
+#define DAIR_RCRM (1 << 22)
+#define DAIR_LBM (1 << 23)
+
+#define DAIDR2_FIFOEN (1 << 15)
+#define DAIDR2_FIFOLEFT (0x0d << 16)
+#define DAIDR2_FIFORIGHT (0x11 << 16)
+
+#define DAISR_RCTS (1 << 0)
+#define DAISR_RCRS (1 << 1)
+#define DAISR_LCTS (1 << 2)
+#define DAISR_LCRS (1 << 3)
+#define DAISR_RCTU (1 << 4)
+#define DAISR_RCRO (1 << 5)
+#define DAISR_LCTU (1 << 6)
+#define DAISR_LCRO (1 << 7)
+#define DAISR_RCNF (1 << 8)
+#define DAISR_RCNE (1 << 9)
+#define DAISR_LCNF (1 << 10)
+#define DAISR_LCNE (1 << 11)
+#define DAISR_FIFO (1 << 12)
+
+#define DAI64FS_I2SF64 (1 << 0)
+#define DAI64FS_AUDIOCLKEN (1 << 1)
+#define DAI64FS_AUDIOCLKSRC (1 << 2)
+#define DAI64FS_MCLK256EN (1 << 3)
+#define DAI64FS_LOOPBACK (1 << 5)
+
+#define SYSCON3_ADCCON (1 << 0)
+#define SYSCON3_CLKCTL0 (1 << 1)
+#define SYSCON3_CLKCTL1 (1 << 2)
+#define SYSCON3_DAISEL (1 << 3)
+#define SYSCON3_ADCCKNSEN (1 << 4)
+#define SYSCON3_VERSN(x) (((x) >> 5) & 7)
+#define SYSCON3_VERSN_MASK (7 << 5)
+#define SYSCON3_FASTWAKE (1 << 8)
+#define SYSCON3_DAIEN (1 << 9)
+#define SYSCON3_128FS SYSCON3_DAIEN
+#define SYSCON3_ENPD67 (1 << 10)
+
+#define SDCONF_ACTIVE (1 << 10)
+#define SDCONF_CLKCTL (1 << 9)
+#define SDCONF_WIDTH_4 (0 << 7)
+#define SDCONF_WIDTH_8 (1 << 7)
+#define SDCONF_WIDTH_16 (2 << 7)
+#define SDCONF_WIDTH_32 (3 << 7)
+#define SDCONF_SIZE_16 (0 << 5)
+#define SDCONF_SIZE_64 (1 << 5)
+#define SDCONF_SIZE_128 (2 << 5)
+#define SDCONF_SIZE_256 (3 << 5)
+#define SDCONF_CASLAT_2 (2)
+#define SDCONF_CASLAT_3 (3)
+
+#define MEMCFG_BUS_WIDTH_32 (1)
+#define MEMCFG_BUS_WIDTH_16 (0)
+#define MEMCFG_BUS_WIDTH_8 (3)
+
+#define MEMCFG_WAITSTATE_8_3 (0 << 2)
+#define MEMCFG_WAITSTATE_7_3 (1 << 2)
+#define MEMCFG_WAITSTATE_6_3 (2 << 2)
+#define MEMCFG_WAITSTATE_5_3 (3 << 2)
+#define MEMCFG_WAITSTATE_4_2 (4 << 2)
+#define MEMCFG_WAITSTATE_3_2 (5 << 2)
+#define MEMCFG_WAITSTATE_2_2 (6 << 2)
+#define MEMCFG_WAITSTATE_1_2 (7 << 2)
+#define MEMCFG_WAITSTATE_8_1 (8 << 2)
+#define MEMCFG_WAITSTATE_7_1 (9 << 2)
+#define MEMCFG_WAITSTATE_6_1 (10 << 2)
+#define MEMCFG_WAITSTATE_5_1 (11 << 2)
+#define MEMCFG_WAITSTATE_4_0 (12 << 2)
+#define MEMCFG_WAITSTATE_3_0 (13 << 2)
+#define MEMCFG_WAITSTATE_2_0 (14 << 2)
+#define MEMCFG_WAITSTATE_1_0 (15 << 2)
+
+#endif /* __MACH_CLPS711X_H */
diff --git a/arch/arm/mach-clps711x/include/mach/debug-macro.S b/arch/arm/mach-clps711x/include/mach/debug-macro.S
index b802e8a51831..118b3d930573 100644
--- a/arch/arm/mach-clps711x/include/mach/debug-macro.S
+++ b/arch/arm/mach-clps711x/include/mach/debug-macro.S
@@ -12,7 +12,6 @@
*/
#include <mach/hardware.h>
-#include <asm/hardware/clps7111.h>
.macro addruart, rp, rv, tmp
#ifndef CONFIG_DEBUG_CLPS711X_UART2
@@ -20,8 +19,8 @@
#else
mov \rp, #0x1000 @ UART2
#endif
- orr \rv, \rp, #CLPS7111_VIRT_BASE
- orr \rp, \rp, #CLPS7111_PHYS_BASE
+ orr \rv, \rp, #CLPS711X_VIRT_BASE
+ orr \rp, \rp, #CLPS711X_PHYS_BASE
.endm
.macro senduart,rd,rx
diff --git a/arch/arm/mach-clps711x/include/mach/entry-macro.S b/arch/arm/mach-clps711x/include/mach/entry-macro.S
index 125af59d7a29..56e5c2c23504 100644
--- a/arch/arm/mach-clps711x/include/mach/entry-macro.S
+++ b/arch/arm/mach-clps711x/include/mach/entry-macro.S
@@ -8,7 +8,6 @@
* warranty of any kind, whether express or implied.
*/
#include <mach/hardware.h>
-#include <asm/hardware/clps7111.h>
.macro get_irqnr_preamble, base, tmp
.endm
@@ -18,7 +17,7 @@
#endif
.macro get_irqnr_and_base, irqnr, stat, base, mask
- mov \base, #CLPS7111_BASE
+ mov \base, #CLPS711X_VIRT_BASE
ldr \stat, [\base, #INTSR1]
ldr \mask, [\base, #INTMR1]
mov \irqnr, #4
diff --git a/arch/arm/mach-clps711x/include/mach/hardware.h b/arch/arm/mach-clps711x/include/mach/hardware.h
index d0b7d870be9c..13a64fcd7dd1 100644
--- a/arch/arm/mach-clps711x/include/mach/hardware.h
+++ b/arch/arm/mach-clps711x/include/mach/hardware.h
@@ -19,12 +19,21 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
+#ifndef __MACH_HARDWARE_H
+#define __MACH_HARDWARE_H
+#include <mach/clps711x.h>
-#define CLPS7111_VIRT_BASE 0xff000000
-#define CLPS7111_BASE CLPS7111_VIRT_BASE
+#define CLPS711X_VIRT_BASE IOMEM(0xff000000)
+
+#ifndef __ASSEMBLY__
+#define clps_readb(off) readb(CLPS711X_VIRT_BASE + (off))
+#define clps_readw(off) readw(CLPS711X_VIRT_BASE + (off))
+#define clps_readl(off) readl(CLPS711X_VIRT_BASE + (off))
+#define clps_writeb(val,off) writeb(val, CLPS711X_VIRT_BASE + (off))
+#define clps_writew(val,off) writew(val, CLPS711X_VIRT_BASE + (off))
+#define clps_writel(val,off) writel(val, CLPS711X_VIRT_BASE + (off))
+#endif
/*
* The physical addresses that the external chip select signals map to is
@@ -52,46 +61,11 @@
#define CS7_PHYS_BASE (0x00000000)
#endif
-#if defined (CONFIG_ARCH_EP7211)
-
-#define EP7211_VIRT_BASE CLPS7111_VIRT_BASE
-#define EP7211_BASE CLPS7111_VIRT_BASE
-#include <asm/hardware/ep7211.h>
-
-#elif defined (CONFIG_ARCH_EP7212)
-
-#define EP7212_VIRT_BASE CLPS7111_VIRT_BASE
-#define EP7212_BASE CLPS7111_VIRT_BASE
-#include <asm/hardware/ep7212.h>
-
-#endif
-
#define SYSPLD_VIRT_BASE 0xfe000000
#define SYSPLD_BASE SYSPLD_VIRT_BASE
-#if defined (CONFIG_ARCH_AUTCPU12)
-
-#define CS89712_VIRT_BASE CLPS7111_VIRT_BASE
-#define CS89712_BASE CLPS7111_VIRT_BASE
-
-#include <asm/hardware/clps7111.h>
-#include <asm/hardware/ep7212.h>
-#include <asm/hardware/cs89712.h>
-
-#endif
-
-
#if defined (CONFIG_ARCH_CDB89712)
-#include <asm/hardware/clps7111.h>
-#include <asm/hardware/ep7212.h>
-#include <asm/hardware/cs89712.h>
-
-/* static cdb89712_map_io() areas */
-#define REGISTER_START 0x80000000
-#define REGISTER_SIZE 0x4000
-#define REGISTER_BASE 0xff000000
-
#define ETHER_START 0x20000000
#define ETHER_SIZE 0x1000
#define ETHER_BASE 0xfe000000
@@ -154,13 +128,6 @@
#if defined (CONFIG_ARCH_CEIVA)
-#define CEIVA_VIRT_BASE CLPS7111_VIRT_BASE
-#define CEIVA_BASE CLPS7111_VIRT_BASE
-
-#include <asm/hardware/clps7111.h>
-#include <asm/hardware/ep7212.h>
-
-
/*
* The two flash banks are wired to chip selects 0 and 1. This is the mapping
* for them.
diff --git a/arch/arm/mach-clps711x/include/mach/irqs.h b/arch/arm/mach-clps711x/include/mach/irqs.h
index 30b7e97285a4..14d215f8ca81 100644
--- a/arch/arm/mach-clps711x/include/mach/irqs.h
+++ b/arch/arm/mach-clps711x/include/mach/irqs.h
@@ -35,7 +35,6 @@
#define IRQ_SSEOTI 15
#define INT1_IRQS (0x0000fff0)
-#define INT1_ACK_IRQS (0x00004f10)
/*
* Interrupts from INTSR2
@@ -47,7 +46,5 @@
#define IRQ_URXINT2 (16+13) /* bit 13 */
#define INT2_IRQS (0x30070000)
-#define INT2_ACK_IRQS (0x00010000)
-
-#define NR_IRQS 30
+#define NR_IRQS 30
diff --git a/arch/arm/mach-clps711x/include/mach/time.h b/arch/arm/mach-clps711x/include/mach/time.h
deleted file mode 100644
index 61fef9129c6a..000000000000
--- a/arch/arm/mach-clps711x/include/mach/time.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * arch/arm/mach-clps711x/include/mach/time.h
- *
- * Copyright (C) 2000 Deep Blue Solutions Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <asm/leds.h>
-#include <asm/hardware/clps7111.h>
-
-extern void clps711x_setup_timer(void);
-
-/*
- * IRQ handler for the timer
- */
-static irqreturn_t
-p720t_timer_interrupt(int irq, void *dev_id)
-{
- struct pt_regs *regs = get_irq_regs();
- do_leds();
- xtime_update(1);
-#ifndef CONFIG_SMP
- update_process_times(user_mode(regs));
-#endif
- do_profile(regs);
- return IRQ_HANDLED;
-}
-
-/*
- * Set up timer interrupt, and return the current time in seconds.
- */
-void __init time_init(void)
-{
- clps711x_setup_timer();
- timer_irq.handler = p720t_timer_interrupt;
- setup_irq(IRQ_TC2OI, &timer_irq);
-}
diff --git a/arch/arm/mach-clps711x/include/mach/uncompress.h b/arch/arm/mach-clps711x/include/mach/uncompress.h
index 35ed731b9f16..7b28d6a47690 100644
--- a/arch/arm/mach-clps711x/include/mach/uncompress.h
+++ b/arch/arm/mach-clps711x/include/mach/uncompress.h
@@ -17,14 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <mach/hardware.h>
-#include <asm/hardware/clps7111.h>
-
-#undef CLPS7111_BASE
-#define CLPS7111_BASE CLPS7111_PHYS_BASE
-
-#define __raw_readl(p) (*(unsigned long *)(p))
-#define __raw_writel(v,p) (*(unsigned long *)(p) = (v))
+#include <mach/clps711x.h>
#ifdef CONFIG_DEBUG_CLPS711X_UART2
#define SYSFLGx SYSFLG2
@@ -34,19 +27,25 @@
#define UARTDRx UARTDR1
#endif
+#define phys_reg(x) (*(volatile u32 *)(CLPS711X_PHYS_BASE + (x)))
+
/*
+ * The following code assumes the serial port has already been
+ * initialized by the bootloader. If you didn't setup a port in
+ * your bootloader then nothing will appear (which might be desired).
+ *
* This does not append a newline
*/
static inline void putc(int c)
{
- while (clps_readl(SYSFLGx) & SYSFLG_UTXFF)
+ while (phys_reg(SYSFLGx) & SYSFLG_UTXFF)
barrier();
- clps_writel(c, UARTDRx);
+ phys_reg(UARTDRx) = c;
}
static inline void flush(void)
{
- while (clps_readl(SYSFLGx) & SYSFLG_UBUSY)
+ while (phys_reg(SYSFLGx) & SYSFLG_UBUSY)
barrier();
}
diff --git a/arch/arm/mach-clps711x/p720t-leds.c b/arch/arm/mach-clps711x/p720t-leds.c
index dd9a6cdbeb02..bbc449fbe14a 100644
--- a/arch/arm/mach-clps711x/p720t-leds.c
+++ b/arch/arm/mach-clps711x/p720t-leds.c
@@ -27,9 +27,6 @@
#include <asm/leds.h>
#include <asm/mach-types.h>
-#include <asm/hardware/clps7111.h>
-#include <asm/hardware/ep7212.h>
-
static void p720t_leds_event(led_event_t ledevt)
{
unsigned long flags;
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index a70de24d1cbc..09f61073c8d9 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -284,7 +284,7 @@ static struct platform_device da850_evm_nandflash_device = {
.resource = da850_evm_nandflash_resource,
};
-static struct platform_device *da850_evm_devices[] __initdata = {
+static struct platform_device *da850_evm_devices[] = {
&da850_evm_nandflash_device,
&da850_evm_norflash_device,
};
diff --git a/arch/arm/mach-davinci/davinci.h b/arch/arm/mach-davinci/davinci.h
index 3e519dad5bb9..8db0fc6809dd 100644
--- a/arch/arm/mach-davinci/davinci.h
+++ b/arch/arm/mach-davinci/davinci.h
@@ -72,7 +72,7 @@ void davinci_map_sysmod(void);
/* DM355 function declarations */
void __init dm355_init(void);
void dm355_init_spi0(unsigned chipselect_mask,
- struct spi_board_info *info, unsigned len);
+ const struct spi_board_info *info, unsigned len);
void __init dm355_init_asp1(u32 evt_enable, struct snd_platform_data *pdata);
void dm355_set_vpfe_config(struct vpfe_config *cfg);
@@ -83,7 +83,7 @@ void __init dm365_init_vc(struct snd_platform_data *pdata);
void __init dm365_init_ks(struct davinci_ks_platform_data *pdata);
void __init dm365_init_rtc(void);
void dm365_init_spi0(unsigned chipselect_mask,
- struct spi_board_info *info, unsigned len);
+ const struct spi_board_info *info, unsigned len);
void dm365_set_vpfe_config(struct vpfe_config *cfg);
/* DM644x function declarations */
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index 42dbf3dc11ab..d1624a315c9a 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -831,7 +831,7 @@ static struct platform_device da8xx_spi_device[] = {
},
};
-int __init da8xx_register_spi(int instance, struct spi_board_info *info,
+int __init da8xx_register_spi(int instance, const struct spi_board_info *info,
unsigned len)
{
int ret;
diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c
index fd3d09aa6cde..678cd99b7336 100644
--- a/arch/arm/mach-davinci/dm355.c
+++ b/arch/arm/mach-davinci/dm355.c
@@ -424,7 +424,7 @@ static struct platform_device dm355_spi0_device = {
};
void __init dm355_init_spi0(unsigned chipselect_mask,
- struct spi_board_info *info, unsigned len)
+ const struct spi_board_info *info, unsigned len)
{
/* for now, assume we need MISO */
davinci_cfg_reg(DM355_SPI0_SDI);
diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c
index 1a2e953082b3..a50d49de1883 100644
--- a/arch/arm/mach-davinci/dm365.c
+++ b/arch/arm/mach-davinci/dm365.c
@@ -676,7 +676,7 @@ static struct platform_device dm365_spi0_device = {
};
void __init dm365_init_spi0(unsigned chipselect_mask,
- struct spi_board_info *info, unsigned len)
+ const struct spi_board_info *info, unsigned len)
{
davinci_cfg_reg(DM365_SPI0_SCLK);
davinci_cfg_reg(DM365_SPI0_SDI);
diff --git a/arch/arm/mach-davinci/dma.c b/arch/arm/mach-davinci/dma.c
index fd33919c95d4..95ce019c9b98 100644
--- a/arch/arm/mach-davinci/dma.c
+++ b/arch/arm/mach-davinci/dma.c
@@ -557,9 +557,9 @@ static int reserve_contiguous_slots(int ctlr, unsigned int id,
if (i == edma_cc[ctlr]->num_slots)
stop_slot = i;
- for (j = start_slot; j < stop_slot; j++)
- if (test_bit(j, tmp_inuse))
- clear_bit(j, edma_cc[ctlr]->edma_inuse);
+ j = start_slot;
+ for_each_set_bit_from(j, tmp_inuse, stop_slot)
+ clear_bit(j, edma_cc[ctlr]->edma_inuse);
if (count)
return -EBUSY;
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index ee3461d7ec1b..a2f1f274f189 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -76,7 +76,8 @@ void __init da850_init(void);
int da830_register_edma(struct edma_rsv_info *rsv);
int da850_register_edma(struct edma_rsv_info *rsv[2]);
int da8xx_register_i2c(int instance, struct davinci_i2c_platform_data *pdata);
-int da8xx_register_spi(int instance, struct spi_board_info *info, unsigned len);
+int da8xx_register_spi(int instance,
+ const struct spi_board_info *info, unsigned len);
int da8xx_register_watchdog(void);
int da8xx_register_usb20(unsigned mA, unsigned potpgt);
int da8xx_register_usb11(struct da8xx_ohci_root_hub *pdata);
diff --git a/arch/arm/mach-davinci/include/mach/psc.h b/arch/arm/mach-davinci/include/mach/psc.h
index 8bc3fc256171..405318e35bf6 100644
--- a/arch/arm/mach-davinci/include/mach/psc.h
+++ b/arch/arm/mach-davinci/include/mach/psc.h
@@ -246,7 +246,7 @@
#define MDSTAT_STATE_MASK 0x3f
#define PDSTAT_STATE_MASK 0x1f
#define MDCTL_FORCE BIT(31)
-#define PDCTL_NEXT BIT(1)
+#define PDCTL_NEXT BIT(0)
#define PDCTL_EPCGOOD BIT(8)
#ifndef __ASSEMBLER__
diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c
index bda7aca04ca0..42ab1e7c4ecc 100644
--- a/arch/arm/mach-dove/common.c
+++ b/arch/arm/mach-dove/common.c
@@ -181,7 +181,7 @@ static int get_tclk(void)
return 166666667;
}
-static void dove_timer_init(void)
+static void __init dove_timer_init(void)
{
orion_time_init(BRIDGE_VIRT_BASE, BRIDGE_INT_TIMER1_CLR,
IRQ_DOVE_BRIDGE, get_tclk());
diff --git a/arch/arm/mach-dove/mpp.c b/arch/arm/mach-dove/mpp.c
index 51e0e411c9cb..7f70afc26f91 100644
--- a/arch/arm/mach-dove/mpp.c
+++ b/arch/arm/mach-dove/mpp.c
@@ -56,7 +56,7 @@ static void dove_mpp_gpio_mode(int start, int end, int gpio_mode)
/* Dump all the extra MPP registers. The platform code will dump the
registers for pins 0-23. */
-static void dove_mpp_dump_regs(void)
+static void __init dove_mpp_dump_regs(void)
{
pr_debug("PMU_CTRL4_CTRL: %08x\n",
readl(DOVE_MPP_CTRL4_VIRT_BASE));
@@ -67,7 +67,7 @@ static void dove_mpp_dump_regs(void)
pr_debug("MPP_GENERAL: %08x\n", readl(DOVE_MPP_GENERAL_VIRT_BASE));
}
-static void dove_mpp_cfg_nfc(int sel)
+static void __init dove_mpp_cfg_nfc(int sel)
{
u32 mpp_gen_cfg = readl(DOVE_MPP_GENERAL_VIRT_BASE);
@@ -78,7 +78,7 @@ static void dove_mpp_cfg_nfc(int sel)
dove_mpp_gpio_mode(64, 71, GPIO_OUTPUT_OK);
}
-static void dove_mpp_cfg_au1(int sel)
+static void __init dove_mpp_cfg_au1(int sel)
{
u32 mpp_ctrl4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
u32 ssp_ctrl1 = readl(DOVE_SSP_CTRL_STATUS_1);
@@ -118,7 +118,7 @@ static void dove_mpp_cfg_au1(int sel)
/* Configure the group registers, enabling GPIO if sel indicates the
pin is to be used for GPIO */
-static void dove_mpp_conf_grp(unsigned int *mpp_grp_list)
+static void __init dove_mpp_conf_grp(unsigned int *mpp_grp_list)
{
u32 mpp_ctrl4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
int gpio_mode;
diff --git a/arch/arm/mach-ep93xx/Kconfig b/arch/arm/mach-ep93xx/Kconfig
index 97a249395b5a..fe3c1fa5462b 100644
--- a/arch/arm/mach-ep93xx/Kconfig
+++ b/arch/arm/mach-ep93xx/Kconfig
@@ -2,6 +2,11 @@ if ARCH_EP93XX
menu "Cirrus EP93xx Implementation Options"
+config EP93XX_SOC_COMMON
+ bool
+ default y
+ select LEDS_GPIO_REGISTER
+
config CRUNCH
bool "Support for MaverickCrunch"
help
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 8d2589588713..66b1494f23a6 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -241,11 +241,7 @@ unsigned int ep93xx_chip_revision(void)
* EP93xx GPIO
*************************************************************************/
static struct resource ep93xx_gpio_resource[] = {
- {
- .start = EP93XX_GPIO_PHYS_BASE,
- .end = EP93XX_GPIO_PHYS_BASE + 0xcc - 1,
- .flags = IORESOURCE_MEM,
- },
+ DEFINE_RES_MEM(EP93XX_GPIO_PHYS_BASE, 0xcc),
};
static struct platform_device ep93xx_gpio_device = {
@@ -288,11 +284,7 @@ static AMBA_APB_DEVICE(uart3, "apb:uart3", 0x00041010, EP93XX_UART3_PHYS_BASE,
{ IRQ_EP93XX_UART3 }, &ep93xx_uart_data);
static struct resource ep93xx_rtc_resource[] = {
- {
- .start = EP93XX_RTC_PHYS_BASE,
- .end = EP93XX_RTC_PHYS_BASE + 0x10c - 1,
- .flags = IORESOURCE_MEM,
- },
+ DEFINE_RES_MEM(EP93XX_RTC_PHYS_BASE, 0x10c),
};
static struct platform_device ep93xx_rtc_device = {
@@ -304,16 +296,8 @@ static struct platform_device ep93xx_rtc_device = {
static struct resource ep93xx_ohci_resources[] = {
- [0] = {
- .start = EP93XX_USB_PHYS_BASE,
- .end = EP93XX_USB_PHYS_BASE + 0x0fff,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_EP93XX_USB,
- .end = IRQ_EP93XX_USB,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_MEM(EP93XX_USB_PHYS_BASE, 0x1000),
+ DEFINE_RES_IRQ(IRQ_EP93XX_USB),
};
@@ -372,15 +356,8 @@ void __init ep93xx_register_flash(unsigned int width,
static struct ep93xx_eth_data ep93xx_eth_data;
static struct resource ep93xx_eth_resource[] = {
- {
- .start = EP93XX_ETHERNET_PHYS_BASE,
- .end = EP93XX_ETHERNET_PHYS_BASE + 0xffff,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_EP93XX_ETHERNET,
- .end = IRQ_EP93XX_ETHERNET,
- .flags = IORESOURCE_IRQ,
- }
+ DEFINE_RES_MEM(EP93XX_ETHERNET_PHYS_BASE, 0x10000),
+ DEFINE_RES_IRQ(IRQ_EP93XX_ETHERNET),
};
static u64 ep93xx_eth_dma_mask = DMA_BIT_MASK(32);
@@ -461,16 +438,8 @@ void __init ep93xx_register_i2c(struct i2c_gpio_platform_data *data,
static struct ep93xx_spi_info ep93xx_spi_master_data;
static struct resource ep93xx_spi_resources[] = {
- {
- .start = EP93XX_SPI_PHYS_BASE,
- .end = EP93XX_SPI_PHYS_BASE + 0x18 - 1,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = IRQ_EP93XX_SSP,
- .end = IRQ_EP93XX_SSP,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_MEM(EP93XX_SPI_PHYS_BASE, 0x18),
+ DEFINE_RES_IRQ(IRQ_EP93XX_SSP),
};
static u64 ep93xx_spi_dma_mask = DMA_BIT_MASK(32);
@@ -513,7 +482,7 @@ void __init ep93xx_register_spi(struct ep93xx_spi_info *info,
/*************************************************************************
* EP93xx LEDs
*************************************************************************/
-static struct gpio_led ep93xx_led_pins[] = {
+static const struct gpio_led ep93xx_led_pins[] __initconst = {
{
.name = "platform:grled",
.gpio = EP93XX_GPIO_LINE_GRLED,
@@ -523,29 +492,16 @@ static struct gpio_led ep93xx_led_pins[] = {
},
};
-static struct gpio_led_platform_data ep93xx_led_data = {
+static const struct gpio_led_platform_data ep93xx_led_data __initconst = {
.num_leds = ARRAY_SIZE(ep93xx_led_pins),
.leds = ep93xx_led_pins,
};
-static struct platform_device ep93xx_leds = {
- .name = "leds-gpio",
- .id = -1,
- .dev = {
- .platform_data = &ep93xx_led_data,
- },
-};
-
-
/*************************************************************************
* EP93xx pwm peripheral handling
*************************************************************************/
static struct resource ep93xx_pwm0_resource[] = {
- {
- .start = EP93XX_PWM_PHYS_BASE,
- .end = EP93XX_PWM_PHYS_BASE + 0x10 - 1,
- .flags = IORESOURCE_MEM,
- },
+ DEFINE_RES_MEM(EP93XX_PWM_PHYS_BASE, 0x10),
};
static struct platform_device ep93xx_pwm0_device = {
@@ -556,11 +512,7 @@ static struct platform_device ep93xx_pwm0_device = {
};
static struct resource ep93xx_pwm1_resource[] = {
- {
- .start = EP93XX_PWM_PHYS_BASE + 0x20,
- .end = EP93XX_PWM_PHYS_BASE + 0x30 - 1,
- .flags = IORESOURCE_MEM,
- },
+ DEFINE_RES_MEM(EP93XX_PWM_PHYS_BASE + 0x20, 0x10),
};
static struct platform_device ep93xx_pwm1_device = {
@@ -628,11 +580,7 @@ EXPORT_SYMBOL(ep93xx_pwm_release_gpio);
static struct ep93xxfb_mach_info ep93xxfb_data;
static struct resource ep93xx_fb_resource[] = {
- {
- .start = EP93XX_RASTER_PHYS_BASE,
- .end = EP93XX_RASTER_PHYS_BASE + 0x800 - 1,
- .flags = IORESOURCE_MEM,
- },
+ DEFINE_RES_MEM(EP93XX_RASTER_PHYS_BASE, 0x800),
};
static struct platform_device ep93xx_fb_device = {
@@ -680,15 +628,8 @@ void __init ep93xx_register_fb(struct ep93xxfb_mach_info *data)
static struct ep93xx_keypad_platform_data ep93xx_keypad_data;
static struct resource ep93xx_keypad_resource[] = {
- {
- .start = EP93XX_KEY_MATRIX_PHYS_BASE,
- .end = EP93XX_KEY_MATRIX_PHYS_BASE + 0x0c - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_EP93XX_KEY,
- .end = IRQ_EP93XX_KEY,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_MEM(EP93XX_KEY_MATRIX_PHYS_BASE, 0x0c),
+ DEFINE_RES_IRQ(IRQ_EP93XX_KEY),
};
static struct platform_device ep93xx_keypad_device = {
@@ -761,11 +702,7 @@ EXPORT_SYMBOL(ep93xx_keypad_release_gpio);
* EP93xx I2S audio peripheral handling
*************************************************************************/
static struct resource ep93xx_i2s_resource[] = {
- {
- .start = EP93XX_I2S_PHYS_BASE,
- .end = EP93XX_I2S_PHYS_BASE + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
+ DEFINE_RES_MEM(EP93XX_I2S_PHYS_BASE, 0x100),
};
static struct platform_device ep93xx_i2s_device = {
@@ -824,16 +761,8 @@ EXPORT_SYMBOL(ep93xx_i2s_release);
* EP93xx AC97 audio peripheral handling
*************************************************************************/
static struct resource ep93xx_ac97_resources[] = {
- {
- .start = EP93XX_AAC_PHYS_BASE,
- .end = EP93XX_AAC_PHYS_BASE + 0xac - 1,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = IRQ_EP93XX_AACINTR,
- .end = IRQ_EP93XX_AACINTR,
- .flags = IORESOURCE_IRQ,
- },
+ DEFINE_RES_MEM(EP93XX_AAC_PHYS_BASE, 0xac),
+ DEFINE_RES_IRQ(IRQ_EP93XX_AACINTR),
};
static struct platform_device ep93xx_ac97_device = {
@@ -889,8 +818,9 @@ void __init ep93xx_init_devices(void)
platform_device_register(&ep93xx_rtc_device);
platform_device_register(&ep93xx_ohci_device);
- platform_device_register(&ep93xx_leds);
platform_device_register(&ep93xx_wdt_device);
+
+ gpio_led_register_device(-1, &ep93xx_led_data);
}
void ep93xx_restart(char mode, const char *cmd)
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index b8df521fb68e..15b05b89cc39 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -200,6 +200,7 @@ config MACH_SMDKV310
select S3C_DEV_HSMMC2
select S3C_DEV_HSMMC3
select SAMSUNG_DEV_BACKLIGHT
+ select EXYNOS_DEV_DRM
select EXYNOS4_DEV_AHCI
select SAMSUNG_DEV_KEYPAD
select EXYNOS4_DEV_DMA
@@ -250,11 +251,13 @@ config MACH_UNIVERSAL_C210
select S3C_DEV_I2C1
select S3C_DEV_I2C3
select S3C_DEV_I2C5
+ select S3C_DEV_USB_HSOTG
select S5P_DEV_I2C_HDMIPHY
select S5P_DEV_MFC
select S5P_DEV_ONENAND
select S5P_DEV_TV
select EXYNOS4_DEV_DMA
+ select EXYNOS_DEV_DRM
select EXYNOS4_SETUP_FIMD0
select EXYNOS4_SETUP_I2C1
select EXYNOS4_SETUP_I2C3
@@ -262,6 +265,7 @@ config MACH_UNIVERSAL_C210
select EXYNOS4_SETUP_SDHCI
select EXYNOS4_SETUP_FIMC
select S5P_SETUP_MIPIPHY
+ select EXYNOS4_SETUP_USB_PHY
help
Machine support for Samsung Mobile Universal S5PC210 Reference
Board.
@@ -280,6 +284,7 @@ config MACH_NURI
select S3C_DEV_I2C3
select S3C_DEV_I2C5
select S3C_DEV_I2C6
+ select S3C_DEV_USB_HSOTG
select S5P_DEV_CSIS0
select S5P_DEV_JPEG
select S5P_DEV_FIMC0
@@ -291,6 +296,7 @@ config MACH_NURI
select S5P_DEV_USB_EHCI
select S5P_SETUP_MIPIPHY
select EXYNOS4_DEV_DMA
+ select EXYNOS_DEV_DRM
select EXYNOS4_SETUP_FIMC
select EXYNOS4_SETUP_FIMD0
select EXYNOS4_SETUP_I2C1
@@ -325,6 +331,7 @@ config MACH_ORIGEN
select S5P_DEV_USB_EHCI
select SAMSUNG_DEV_BACKLIGHT
select SAMSUNG_DEV_PWM
+ select EXYNOS_DEV_DRM
select EXYNOS4_DEV_DMA
select EXYNOS4_DEV_USB_OHCI
select EXYNOS4_SETUP_FIMD0
@@ -345,6 +352,11 @@ config MACH_SMDK4212
select S3C_DEV_I2C7
select S3C_DEV_RTC
select S3C_DEV_WDT
+ select S5P_DEV_FIMC0
+ select S5P_DEV_FIMC1
+ select S5P_DEV_FIMC2
+ select S5P_DEV_FIMC3
+ select S5P_DEV_MFC
select SAMSUNG_DEV_BACKLIGHT
select SAMSUNG_DEV_KEYPAD
select SAMSUNG_DEV_PWM
diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c
index 33ab4e7558af..26dac2893b8e 100644
--- a/arch/arm/mach-exynos/cpuidle.c
+++ b/arch/arm/mach-exynos/cpuidle.c
@@ -20,6 +20,7 @@
#include <asm/smp_scu.h>
#include <asm/suspend.h>
#include <asm/unified.h>
+#include <asm/cpuidle.h>
#include <mach/regs-pmu.h>
#include <mach/pmu.h>
@@ -34,22 +35,12 @@
#define S5P_CHECK_AFTR 0xFCBA0D10
-static int exynos4_enter_idle(struct cpuidle_device *dev,
- struct cpuidle_driver *drv,
- int index);
static int exynos4_enter_lowpower(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index);
static struct cpuidle_state exynos4_cpuidle_set[] __initdata = {
- [0] = {
- .enter = exynos4_enter_idle,
- .exit_latency = 1,
- .target_residency = 100000,
- .flags = CPUIDLE_FLAG_TIME_VALID,
- .name = "C0",
- .desc = "ARM clock gating(WFI)",
- },
+ [0] = ARM_CPUIDLE_WFI_STATE,
[1] = {
.enter = exynos4_enter_lowpower,
.exit_latency = 300,
@@ -63,8 +54,9 @@ static struct cpuidle_state exynos4_cpuidle_set[] __initdata = {
static DEFINE_PER_CPU(struct cpuidle_device, exynos4_cpuidle_device);
static struct cpuidle_driver exynos4_idle_driver = {
- .name = "exynos4_idle",
- .owner = THIS_MODULE,
+ .name = "exynos4_idle",
+ .owner = THIS_MODULE,
+ .en_core_tk_irqen = 1,
};
/* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */
@@ -103,13 +95,8 @@ static int exynos4_enter_core0_aftr(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
- struct timeval before, after;
- int idle_time;
unsigned long tmp;
- local_irq_disable();
- do_gettimeofday(&before);
-
exynos4_set_wakeupmask();
/* Set value of power down register for aftr mode */
@@ -150,34 +137,6 @@ static int exynos4_enter_core0_aftr(struct cpuidle_device *dev,
/* Clear wakeup state register */
__raw_writel(0x0, S5P_WAKEUP_STAT);
- do_gettimeofday(&after);
-
- local_irq_enable();
- idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
- (after.tv_usec - before.tv_usec);
-
- dev->last_residency = idle_time;
- return index;
-}
-
-static int exynos4_enter_idle(struct cpuidle_device *dev,
- struct cpuidle_driver *drv,
- int index)
-{
- struct timeval before, after;
- int idle_time;
-
- local_irq_disable();
- do_gettimeofday(&before);
-
- cpu_do_idle();
-
- do_gettimeofday(&after);
- local_irq_enable();
- idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC +
- (after.tv_usec - before.tv_usec);
-
- dev->last_residency = idle_time;
return index;
}
@@ -192,7 +151,7 @@ static int exynos4_enter_lowpower(struct cpuidle_device *dev,
new_index = drv->safe_state_index;
if (new_index == 0)
- return exynos4_enter_idle(dev, drv, new_index);
+ return arm_cpuidle_simple_enter(dev, drv, new_index);
else
return exynos4_enter_core0_aftr(dev, drv, new_index);
}
diff --git a/arch/arm/mach-exynos/dev-ahci.c b/arch/arm/mach-exynos/dev-ahci.c
index 50ce5b0adcf1..ce1aad3eeeb9 100644
--- a/arch/arm/mach-exynos/dev-ahci.c
+++ b/arch/arm/mach-exynos/dev-ahci.c
@@ -236,16 +236,8 @@ static struct ahci_platform_data exynos4_ahci_pdata = {
};
static struct resource exynos4_ahci_resource[] = {
- [0] = {
- .start = EXYNOS4_PA_SATA,
- .end = EXYNOS4_PA_SATA + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = EXYNOS4_IRQ_SATA,
- .end = EXYNOS4_IRQ_SATA,
- .flags = IORESOURCE_IRQ,
- },
+ [0] = DEFINE_RES_MEM(EXYNOS4_PA_SATA, SZ_64K),
+ [1] = DEFINE_RES_IRQ(EXYNOS4_IRQ_SATA),
};
static u64 exynos4_ahci_dmamask = DMA_BIT_MASK(32);
diff --git a/arch/arm/mach-exynos/dev-audio.c b/arch/arm/mach-exynos/dev-audio.c
index 7199e1ae79b4..b33a5b67b547 100644
--- a/arch/arm/mach-exynos/dev-audio.c
+++ b/arch/arm/mach-exynos/dev-audio.c
@@ -62,26 +62,10 @@ static struct s3c_audio_pdata i2sv5_pdata = {
};
static struct resource exynos4_i2s0_resource[] = {
- [0] = {
- .start = EXYNOS4_PA_I2S0,
- .end = EXYNOS4_PA_I2S0 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_I2S0_TX,
- .end = DMACH_I2S0_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_I2S0_RX,
- .end = DMACH_I2S0_RX,
- .flags = IORESOURCE_DMA,
- },
- [3] = {
- .start = DMACH_I2S0S_TX,
- .end = DMACH_I2S0S_TX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(EXYNOS4_PA_I2S0, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_I2S0_TX),
+ [2] = DEFINE_RES_DMA(DMACH_I2S0_RX),
+ [3] = DEFINE_RES_DMA(DMACH_I2S0S_TX),
};
struct platform_device exynos4_device_i2s0 = {
@@ -110,21 +94,9 @@ static struct s3c_audio_pdata i2sv3_pdata = {
};
static struct resource exynos4_i2s1_resource[] = {
- [0] = {
- .start = EXYNOS4_PA_I2S1,
- .end = EXYNOS4_PA_I2S1 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_I2S1_TX,
- .end = DMACH_I2S1_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_I2S1_RX,
- .end = DMACH_I2S1_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(EXYNOS4_PA_I2S1, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_I2S1_TX),
+ [2] = DEFINE_RES_DMA(DMACH_I2S1_RX),
};
struct platform_device exynos4_device_i2s1 = {
@@ -138,21 +110,9 @@ struct platform_device exynos4_device_i2s1 = {
};
static struct resource exynos4_i2s2_resource[] = {
- [0] = {
- .start = EXYNOS4_PA_I2S2,
- .end = EXYNOS4_PA_I2S2 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_I2S2_TX,
- .end = DMACH_I2S2_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_I2S2_RX,
- .end = DMACH_I2S2_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(EXYNOS4_PA_I2S2, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_I2S2_TX),
+ [2] = DEFINE_RES_DMA(DMACH_I2S2_RX),
};
struct platform_device exynos4_device_i2s2 = {
@@ -192,21 +152,9 @@ static struct s3c_audio_pdata s3c_pcm_pdata = {
};
static struct resource exynos4_pcm0_resource[] = {
- [0] = {
- .start = EXYNOS4_PA_PCM0,
- .end = EXYNOS4_PA_PCM0 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_PCM0_TX,
- .end = DMACH_PCM0_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_PCM0_RX,
- .end = DMACH_PCM0_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(EXYNOS4_PA_PCM0, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_PCM0_TX),
+ [2] = DEFINE_RES_DMA(DMACH_PCM0_RX),
};
struct platform_device exynos4_device_pcm0 = {
@@ -220,21 +168,9 @@ struct platform_device exynos4_device_pcm0 = {
};
static struct resource exynos4_pcm1_resource[] = {
- [0] = {
- .start = EXYNOS4_PA_PCM1,
- .end = EXYNOS4_PA_PCM1 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_PCM1_TX,
- .end = DMACH_PCM1_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_PCM1_RX,
- .end = DMACH_PCM1_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(EXYNOS4_PA_PCM1, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_PCM1_TX),
+ [2] = DEFINE_RES_DMA(DMACH_PCM1_RX),
};
struct platform_device exynos4_device_pcm1 = {
@@ -248,21 +184,9 @@ struct platform_device exynos4_device_pcm1 = {
};
static struct resource exynos4_pcm2_resource[] = {
- [0] = {
- .start = EXYNOS4_PA_PCM2,
- .end = EXYNOS4_PA_PCM2 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_PCM2_TX,
- .end = DMACH_PCM2_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_PCM2_RX,
- .end = DMACH_PCM2_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(EXYNOS4_PA_PCM2, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_PCM2_TX),
+ [2] = DEFINE_RES_DMA(DMACH_PCM2_RX),
};
struct platform_device exynos4_device_pcm2 = {
@@ -283,31 +207,11 @@ static int exynos4_ac97_cfg_gpio(struct platform_device *pdev)
}
static struct resource exynos4_ac97_resource[] = {
- [0] = {
- .start = EXYNOS4_PA_AC97,
- .end = EXYNOS4_PA_AC97 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_AC97_PCMOUT,
- .end = DMACH_AC97_PCMOUT,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_AC97_PCMIN,
- .end = DMACH_AC97_PCMIN,
- .flags = IORESOURCE_DMA,
- },
- [3] = {
- .start = DMACH_AC97_MICIN,
- .end = DMACH_AC97_MICIN,
- .flags = IORESOURCE_DMA,
- },
- [4] = {
- .start = EXYNOS4_IRQ_AC97,
- .end = EXYNOS4_IRQ_AC97,
- .flags = IORESOURCE_IRQ,
- },
+ [0] = DEFINE_RES_MEM(EXYNOS4_PA_AC97, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_AC97_PCMOUT),
+ [2] = DEFINE_RES_DMA(DMACH_AC97_PCMIN),
+ [3] = DEFINE_RES_DMA(DMACH_AC97_MICIN),
+ [4] = DEFINE_RES_IRQ(EXYNOS4_IRQ_AC97),
};
static struct s3c_audio_pdata s3c_ac97_pdata = {
@@ -338,16 +242,8 @@ static int exynos4_spdif_cfg_gpio(struct platform_device *pdev)
}
static struct resource exynos4_spdif_resource[] = {
- [0] = {
- .start = EXYNOS4_PA_SPDIF,
- .end = EXYNOS4_PA_SPDIF + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_SPDIF,
- .end = DMACH_SPDIF,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(EXYNOS4_PA_SPDIF, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_SPDIF),
};
static struct s3c_audio_pdata samsung_spdif_pdata = {
diff --git a/arch/arm/mach-exynos/include/mach/irqs.h b/arch/arm/mach-exynos/include/mach/irqs.h
index 591e78521a9f..c02dae7bf4a3 100644
--- a/arch/arm/mach-exynos/include/mach/irqs.h
+++ b/arch/arm/mach-exynos/include/mach/irqs.h
@@ -189,6 +189,7 @@
#define IRQ_IIC7 EXYNOS4_IRQ_IIC7
#define IRQ_USB_HOST EXYNOS4_IRQ_USB_HOST
+#define IRQ_OTG EXYNOS4_IRQ_USB_HSOTG
#define IRQ_HSMMC0 EXYNOS4_IRQ_HSMMC0
#define IRQ_HSMMC1 EXYNOS4_IRQ_HSMMC1
diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h
index 6e6d11ff352a..e009a66477f4 100644
--- a/arch/arm/mach-exynos/include/mach/map.h
+++ b/arch/arm/mach-exynos/include/mach/map.h
@@ -130,6 +130,9 @@
#define EXYNOS4_PA_HSMMC(x) (0x12510000 + ((x) * 0x10000))
#define EXYNOS4_PA_DWMCI 0x12550000
+#define EXYNOS4_PA_HSOTG 0x12480000
+#define EXYNOS4_PA_USB_HSPHY 0x125B0000
+
#define EXYNOS4_PA_SATA 0x12560000
#define EXYNOS4_PA_SATAPHY 0x125D0000
#define EXYNOS4_PA_SATAPHY_CTRL 0x126B0000
@@ -186,6 +189,7 @@
#define S3C_PA_SPI0 EXYNOS4_PA_SPI0
#define S3C_PA_SPI1 EXYNOS4_PA_SPI1
#define S3C_PA_SPI2 EXYNOS4_PA_SPI2
+#define S3C_PA_USB_HSOTG EXYNOS4_PA_HSOTG
#define S5P_PA_EHCI EXYNOS4_PA_EHCI
#define S5P_PA_FIMC0 EXYNOS4_PA_FIMC0
diff --git a/arch/arm/mach-exynos/include/mach/regs-pmu.h b/arch/arm/mach-exynos/include/mach/regs-pmu.h
index 4c53f38b5a9e..d457d052a420 100644
--- a/arch/arm/mach-exynos/include/mach/regs-pmu.h
+++ b/arch/arm/mach-exynos/include/mach/regs-pmu.h
@@ -163,6 +163,9 @@
#define S5P_CHECK_SLEEP 0x00000BAD
/* Only for EXYNOS4210 */
+#define S5P_USBDEVICE_PHY_CONTROL S5P_PMUREG(0x0704)
+#define S5P_USBDEVICE_PHY_ENABLE (1 << 0)
+
#define S5P_USBHOST_PHY_CONTROL S5P_PMUREG(0x0708)
#define S5P_USBHOST_PHY_ENABLE (1 << 0)
diff --git a/arch/arm/mach-exynos/mach-armlex4210.c b/arch/arm/mach-exynos/mach-armlex4210.c
index d726fcd3acf9..fed7116418eb 100644
--- a/arch/arm/mach-exynos/mach-armlex4210.c
+++ b/arch/arm/mach-exynos/mach-armlex4210.c
@@ -77,7 +77,6 @@ static struct s3c2410_uartcfg armlex4210_uartcfgs[] __initdata = {
static struct s3c_sdhci_platdata armlex4210_hsmmc0_pdata __initdata = {
.cd_type = S3C_SDHCI_CD_PERMANENT,
- .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
#ifdef CONFIG_EXYNOS4_SDHCI_CH0_8BIT
.max_width = 8,
.host_caps = MMC_CAP_8_BIT_DATA,
@@ -88,13 +87,11 @@ static struct s3c_sdhci_platdata armlex4210_hsmmc2_pdata __initdata = {
.cd_type = S3C_SDHCI_CD_GPIO,
.ext_cd_gpio = EXYNOS4_GPX2(5),
.ext_cd_gpio_invert = 1,
- .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
.max_width = 4,
};
static struct s3c_sdhci_platdata armlex4210_hsmmc3_pdata __initdata = {
.cd_type = S3C_SDHCI_CD_PERMANENT,
- .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
.max_width = 4,
};
@@ -121,16 +118,9 @@ static void __init armlex4210_wlan_init(void)
}
static struct resource armlex4210_smsc911x_resources[] = {
- [0] = {
- .start = EXYNOS4_PA_SROM_BANK(3),
- .end = EXYNOS4_PA_SROM_BANK(3) + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_EINT(27),
- .end = IRQ_EINT(27),
- .flags = IORESOURCE_IRQ | IRQF_TRIGGER_HIGH,
- },
+ [0] = DEFINE_RES_MEM(EXYNOS4_PA_SROM_BANK(3), SZ_64K),
+ [1] = DEFINE_RES_NAMED(IRQ_EINT(27), 1, NULL, IORESOURCE_IRQ \
+ | IRQF_TRIGGER_HIGH),
};
static struct smsc911x_platform_config smsc9215_config = {
diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c
index ed90aef404c3..6c31f2ad765d 100644
--- a/arch/arm/mach-exynos/mach-nuri.c
+++ b/arch/arm/mach-exynos/mach-nuri.c
@@ -25,6 +25,8 @@
#include <linux/mmc/host.h>
#include <linux/fb.h>
#include <linux/pwm_backlight.h>
+#include <linux/platform_data/s3c-hsotg.h>
+#include <drm/exynos_drm.h>
#include <video/platform_lcd.h>
#include <media/m5mols.h>
@@ -114,7 +116,6 @@ static struct s3c_sdhci_platdata nuri_hsmmc0_data __initdata = {
MMC_CAP_ERASE),
.host_caps2 = MMC_CAP2_BROKEN_VOLTAGE,
.cd_type = S3C_SDHCI_CD_PERMANENT,
- .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
};
static struct regulator_consumer_supply emmc_supplies[] = {
@@ -155,7 +156,6 @@ static struct s3c_sdhci_platdata nuri_hsmmc2_data __initdata = {
.ext_cd_gpio = EXYNOS4_GPX3(3), /* XEINT_27 */
.ext_cd_gpio_invert = 1,
.cd_type = S3C_SDHCI_CD_GPIO,
- .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
};
/* WLAN */
@@ -164,7 +164,6 @@ static struct s3c_sdhci_platdata nuri_hsmmc3_data __initdata = {
.host_caps = MMC_CAP_4_BIT_DATA |
MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
.cd_type = S3C_SDHCI_CD_EXTERNAL,
- .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
};
static void __init nuri_sdhci_init(void)
@@ -213,6 +212,29 @@ static struct platform_device nuri_gpio_keys = {
},
};
+#ifdef CONFIG_DRM_EXYNOS
+static struct exynos_drm_fimd_pdata drm_fimd_pdata = {
+ .panel = {
+ .timing = {
+ .xres = 1024,
+ .yres = 600,
+ .hsync_len = 40,
+ .left_margin = 79,
+ .right_margin = 200,
+ .vsync_len = 10,
+ .upper_margin = 10,
+ .lower_margin = 11,
+ .refresh = 60,
+ },
+ },
+ .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB |
+ VIDCON0_CLKSEL_LCD,
+ .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
+ .default_win = 3,
+ .bpp = 32,
+};
+
+#else
/* Frame Buffer */
static struct s3c_fb_pd_win nuri_fb_win0 = {
.win_mode = {
@@ -239,6 +261,7 @@ static struct s3c_fb_platdata nuri_fb_pdata __initdata = {
.vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
.setup_gpio = exynos4_fimd0_gpio_setup_24bpp,
};
+#endif
static void nuri_lcd_power_on(struct plat_lcd_data *pd, unsigned int power)
{
@@ -351,6 +374,7 @@ static struct regulator_consumer_supply __initdata max8997_ldo1_[] = {
REGULATOR_SUPPLY("vdd", "s5p-adc"), /* Used by CPU's ADC drv */
};
static struct regulator_consumer_supply __initdata max8997_ldo3_[] = {
+ REGULATOR_SUPPLY("vusb_d", "s3c-hsotg"), /* USB */
REGULATOR_SUPPLY("vdd11", "s5p-mipi-csis.0"), /* MIPI */
};
static struct regulator_consumer_supply __initdata max8997_ldo4_[] = {
@@ -366,7 +390,7 @@ static struct regulator_consumer_supply __initdata max8997_ldo7_[] = {
REGULATOR_SUPPLY("dig_18", "0-001f"), /* HCD803 */
};
static struct regulator_consumer_supply __initdata max8997_ldo8_[] = {
- REGULATOR_SUPPLY("vusb_d", NULL), /* Used by CPU */
+ REGULATOR_SUPPLY("vusb_a", "s3c-hsotg"), /* USB */
REGULATOR_SUPPLY("vdac", NULL), /* Used by CPU */
};
static struct regulator_consumer_supply __initdata max8997_ldo11_[] = {
@@ -822,6 +846,7 @@ static struct regulator_init_data __initdata max8997_esafeout1_data = {
.constraints = {
.name = "SAFEOUT1",
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .always_on = 1,
.state_mem = {
.disabled = 1,
},
@@ -1079,6 +1104,9 @@ static void __init nuri_ehci_init(void)
s5p_ehci_set_platdata(pdata);
}
+/* USB OTG */
+static struct s3c_hsotg_plat nuri_hsotg_pdata;
+
/* CAMERA */
static struct regulator_consumer_supply cam_vt_cam15_supply =
REGULATOR_SUPPLY("vdd_core", "6-003c");
@@ -1291,6 +1319,7 @@ static struct platform_device *nuri_devices[] __initdata = {
&s5p_device_mfc_l,
&s5p_device_mfc_r,
&s5p_device_fimc_md,
+ &s3c_device_usb_hsotg,
/* NURI Devices */
&nuri_gpio_keys,
@@ -1302,6 +1331,9 @@ static struct platform_device *nuri_devices[] __initdata = {
&cam_vdda_fixed_rdev,
&cam_8m_12v_fixed_rdev,
&exynos4_bus_devfreq,
+#ifdef CONFIG_DRM_EXYNOS
+ &exynos_device_drm,
+#endif
};
static void __init nuri_map_io(void)
@@ -1334,11 +1366,17 @@ static void __init nuri_machine_init(void)
i2c_register_board_info(9, i2c9_devs, ARRAY_SIZE(i2c9_devs));
s3c_i2c6_set_platdata(&nuri_i2c6_platdata);
+#ifdef CONFIG_DRM_EXYNOS
+ s5p_device_fimd0.dev.platform_data = &drm_fimd_pdata;
+ exynos4_fimd0_gpio_setup_24bpp();
+#else
s5p_fimd0_set_platdata(&nuri_fb_pdata);
+#endif
nuri_camera_init();
nuri_ehci_init();
+ s3c_hsotg_set_platdata(&nuri_hsotg_pdata);
/* Last */
platform_add_devices(nuri_devices, ARRAY_SIZE(nuri_devices));
diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c
index 878d4c99142d..26124a38bcbd 100644
--- a/arch/arm/mach-exynos/mach-origen.c
+++ b/arch/arm/mach-exynos/mach-origen.c
@@ -45,6 +45,7 @@
#include <mach/ohci.h>
#include <mach/map.h>
+#include <drm/exynos_drm.h>
#include "common.h"
/* Following are default values for UCON, ULCON and UFCON UART registers */
@@ -472,12 +473,10 @@ static struct i2c_board_info i2c0_devs[] __initdata = {
static struct s3c_sdhci_platdata origen_hsmmc0_pdata __initdata = {
.cd_type = S3C_SDHCI_CD_INTERNAL,
- .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
};
static struct s3c_sdhci_platdata origen_hsmmc2_pdata __initdata = {
.cd_type = S3C_SDHCI_CD_INTERNAL,
- .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
};
/* USB EHCI */
@@ -583,6 +582,27 @@ static struct platform_device origen_lcd_hv070wsa = {
.dev.platform_data = &origen_lcd_hv070wsa_data,
};
+#ifdef CONFIG_DRM_EXYNOS
+static struct exynos_drm_fimd_pdata drm_fimd_pdata = {
+ .panel = {
+ .timing = {
+ .left_margin = 64,
+ .right_margin = 16,
+ .upper_margin = 64,
+ .lower_margin = 16,
+ .hsync_len = 48,
+ .vsync_len = 3,
+ .xres = 1024,
+ .yres = 600,
+ },
+ },
+ .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
+ .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC |
+ VIDCON1_INV_VCLK,
+ .default_win = 0,
+ .bpp = 32,
+};
+#else
static struct s3c_fb_pd_win origen_fb_win0 = {
.win_mode = {
.left_margin = 64,
@@ -596,6 +616,8 @@ static struct s3c_fb_pd_win origen_fb_win0 = {
},
.max_bpp = 32,
.default_bpp = 24,
+ .virtual_x = 1024,
+ .virtual_y = 2 * 600,
};
static struct s3c_fb_platdata origen_lcd_pdata __initdata = {
@@ -605,9 +627,10 @@ static struct s3c_fb_platdata origen_lcd_pdata __initdata = {
VIDCON1_INV_VCLK,
.setup_gpio = exynos4_fimd0_gpio_setup_24bpp,
};
+#endif
/* Bluetooth rfkill gpio platform data */
-struct rfkill_gpio_platform_data origen_bt_pdata = {
+static struct rfkill_gpio_platform_data origen_bt_pdata = {
.reset_gpio = EXYNOS4_GPX2(2),
.shutdown_gpio = -1,
.type = RFKILL_TYPE_BLUETOOTH,
@@ -644,6 +667,9 @@ static struct platform_device *origen_devices[] __initdata = {
&s5p_device_mfc_l,
&s5p_device_mfc_r,
&s5p_device_mixer,
+#ifdef CONFIG_DRM_EXYNOS
+ &exynos_device_drm,
+#endif
&exynos4_device_ohci,
&origen_device_gpiokeys,
&origen_lcd_hv070wsa,
@@ -719,7 +745,12 @@ static void __init origen_machine_init(void)
s5p_tv_setup();
s5p_i2c_hdmiphy_set_platdata(NULL);
+#ifdef CONFIG_DRM_EXYNOS
+ s5p_device_fimd0.dev.platform_data = &drm_fimd_pdata;
+ exynos4_fimd0_gpio_setup_24bpp();
+#else
s5p_fimd0_set_platdata(&origen_lcd_pdata);
+#endif
platform_add_devices(origen_devices, ARRAY_SIZE(origen_devices));
diff --git a/arch/arm/mach-exynos/mach-smdk4x12.c b/arch/arm/mach-exynos/mach-smdk4x12.c
index d00e4f016a68..fe772d893cc9 100644
--- a/arch/arm/mach-exynos/mach-smdk4x12.c
+++ b/arch/arm/mach-exynos/mach-smdk4x12.c
@@ -31,6 +31,7 @@
#include <plat/gpio-cfg.h>
#include <plat/iic.h>
#include <plat/keypad.h>
+#include <plat/mfc.h>
#include <plat/regs-serial.h>
#include <plat/sdhci.h>
@@ -85,7 +86,6 @@ static struct s3c2410_uartcfg smdk4x12_uartcfgs[] __initdata = {
static struct s3c_sdhci_platdata smdk4x12_hsmmc2_pdata __initdata = {
.cd_type = S3C_SDHCI_CD_INTERNAL,
- .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
#ifdef CONFIG_EXYNOS4_SDHCI_CH2_8BIT
.max_width = 8,
.host_caps = MMC_CAP_8_BIT_DATA,
@@ -94,7 +94,6 @@ static struct s3c_sdhci_platdata smdk4x12_hsmmc2_pdata __initdata = {
static struct s3c_sdhci_platdata smdk4x12_hsmmc3_pdata __initdata = {
.cd_type = S3C_SDHCI_CD_INTERNAL,
- .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
};
static struct regulator_consumer_supply max8997_buck1 =
@@ -244,6 +243,14 @@ static struct platform_device *smdk4x12_devices[] __initdata = {
&s3c_device_i2c7,
&s3c_device_rtc,
&s3c_device_wdt,
+ &s5p_device_fimc0,
+ &s5p_device_fimc1,
+ &s5p_device_fimc2,
+ &s5p_device_fimc3,
+ &s5p_device_fimc_md,
+ &s5p_device_mfc,
+ &s5p_device_mfc_l,
+ &s5p_device_mfc_r,
&samsung_device_keypad,
};
@@ -256,6 +263,11 @@ static void __init smdk4x12_map_io(void)
s3c24xx_init_uarts(smdk4x12_uartcfgs, ARRAY_SIZE(smdk4x12_uartcfgs));
}
+static void __init smdk4x12_reserve(void)
+{
+ s5p_mfc_reserve_mem(0x43000000, 8 << 20, 0x51000000, 8 << 20);
+}
+
static void __init smdk4x12_machine_init(void)
{
s3c_i2c0_set_platdata(NULL);
@@ -293,6 +305,7 @@ MACHINE_START(SMDK4212, "SMDK4212")
.init_machine = smdk4x12_machine_init,
.timer = &exynos4_timer,
.restart = exynos4_restart,
+ .reserve = &smdk4x12_reserve,
MACHINE_END
MACHINE_START(SMDK4412, "SMDK4412")
@@ -305,4 +318,5 @@ MACHINE_START(SMDK4412, "SMDK4412")
.init_machine = smdk4x12_machine_init,
.timer = &exynos4_timer,
.restart = exynos4_restart,
+ .reserve = &smdk4x12_reserve,
MACHINE_END
diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c
index 83b91fa777c1..5af96064ca51 100644
--- a/arch/arm/mach-exynos/mach-smdkv310.c
+++ b/arch/arm/mach-exynos/mach-smdkv310.c
@@ -44,6 +44,7 @@
#include <mach/map.h>
#include <mach/ohci.h>
+#include <drm/exynos_drm.h>
#include "common.h"
/* Following are default values for UCON, ULCON and UFCON UART registers */
@@ -93,7 +94,6 @@ static struct s3c2410_uartcfg smdkv310_uartcfgs[] __initdata = {
static struct s3c_sdhci_platdata smdkv310_hsmmc0_pdata __initdata = {
.cd_type = S3C_SDHCI_CD_INTERNAL,
- .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
#ifdef CONFIG_EXYNOS4_SDHCI_CH0_8BIT
.max_width = 8,
.host_caps = MMC_CAP_8_BIT_DATA,
@@ -104,12 +104,10 @@ static struct s3c_sdhci_platdata smdkv310_hsmmc1_pdata __initdata = {
.cd_type = S3C_SDHCI_CD_GPIO,
.ext_cd_gpio = EXYNOS4_GPK0(2),
.ext_cd_gpio_invert = 1,
- .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
};
static struct s3c_sdhci_platdata smdkv310_hsmmc2_pdata __initdata = {
.cd_type = S3C_SDHCI_CD_INTERNAL,
- .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
#ifdef CONFIG_EXYNOS4_SDHCI_CH2_8BIT
.max_width = 8,
.host_caps = MMC_CAP_8_BIT_DATA,
@@ -120,7 +118,6 @@ static struct s3c_sdhci_platdata smdkv310_hsmmc3_pdata __initdata = {
.cd_type = S3C_SDHCI_CD_GPIO,
.ext_cd_gpio = EXYNOS4_GPK2(2),
.ext_cd_gpio_invert = 1,
- .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
};
static void lcd_lte480wv_set_power(struct plat_lcd_data *pd,
@@ -160,6 +157,26 @@ static struct platform_device smdkv310_lcd_lte480wv = {
.dev.platform_data = &smdkv310_lcd_lte480wv_data,
};
+#ifdef CONFIG_DRM_EXYNOS
+static struct exynos_drm_fimd_pdata drm_fimd_pdata = {
+ .panel = {
+ .timing = {
+ .left_margin = 13,
+ .right_margin = 8,
+ .upper_margin = 7,
+ .lower_margin = 5,
+ .hsync_len = 3,
+ .vsync_len = 1,
+ .xres = 800,
+ .yres = 480,
+ },
+ },
+ .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB,
+ .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
+ .default_win = 0,
+ .bpp = 32,
+};
+#else
static struct s3c_fb_pd_win smdkv310_fb_win0 = {
.win_mode = {
.left_margin = 13,
@@ -181,18 +198,12 @@ static struct s3c_fb_platdata smdkv310_lcd0_pdata __initdata = {
.vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
.setup_gpio = exynos4_fimd0_gpio_setup_24bpp,
};
+#endif
static struct resource smdkv310_smsc911x_resources[] = {
- [0] = {
- .start = EXYNOS4_PA_SROM_BANK(1),
- .end = EXYNOS4_PA_SROM_BANK(1) + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_EINT(5),
- .end = IRQ_EINT(5),
- .flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
- },
+ [0] = DEFINE_RES_MEM(EXYNOS4_PA_SROM_BANK(1), SZ_64K),
+ [1] = DEFINE_RES_NAMED(IRQ_EINT(5), 1, NULL, IORESOURCE_IRQ \
+ | IRQF_TRIGGER_LOW),
};
static struct smsc911x_platform_config smsc9215_config = {
@@ -273,6 +284,9 @@ static struct platform_device *smdkv310_devices[] __initdata = {
&s5p_device_fimc_md,
&s5p_device_g2d,
&s5p_device_jpeg,
+#ifdef CONFIG_DRM_EXYNOS
+ &exynos_device_drm,
+#endif
&exynos4_device_ac97,
&exynos4_device_i2s0,
&exynos4_device_ohci,
@@ -364,7 +378,12 @@ static void __init smdkv310_machine_init(void)
samsung_keypad_set_platdata(&smdkv310_keypad_data);
samsung_bl_set(&smdkv310_bl_gpio_info, &smdkv310_bl_data);
+#ifdef CONFIG_DRM_EXYNOS
+ s5p_device_fimd0.dev.platform_data = &drm_fimd_pdata;
+ exynos4_fimd0_gpio_setup_24bpp();
+#else
s5p_fimd0_set_platdata(&smdkv310_lcd0_pdata);
+#endif
smdkv310_ehci_init();
smdkv310_ohci_init();
diff --git a/arch/arm/mach-exynos/mach-universal_c210.c b/arch/arm/mach-exynos/mach-universal_c210.c
index a34036eb8ba2..6b731b863275 100644
--- a/arch/arm/mach-exynos/mach-universal_c210.c
+++ b/arch/arm/mach-exynos/mach-universal_c210.c
@@ -23,6 +23,8 @@
#include <linux/i2c-gpio.h>
#include <linux/i2c/mcs.h>
#include <linux/i2c/atmel_mxt_ts.h>
+#include <linux/platform_data/s3c-hsotg.h>
+#include <drm/exynos_drm.h>
#include <asm/mach/arch.h>
#include <asm/hardware/gic.h>
@@ -205,6 +207,7 @@ static struct regulator_init_data lp3974_ldo2_data = {
};
static struct regulator_consumer_supply lp3974_ldo3_consumer[] = {
+ REGULATOR_SUPPLY("vusb_a", "s3c-hsotg"),
REGULATOR_SUPPLY("vdd", "exynos4-hdmi"),
REGULATOR_SUPPLY("vdd_pll", "exynos4-hdmi"),
REGULATOR_SUPPLY("vdd11", "s5p-mipi-csis.0"),
@@ -290,6 +293,7 @@ static struct regulator_init_data lp3974_ldo7_data = {
};
static struct regulator_consumer_supply lp3974_ldo8_consumer[] = {
+ REGULATOR_SUPPLY("vusb_d", "s3c-hsotg"),
REGULATOR_SUPPLY("vdd33a_dac", "s5p-sdo"),
};
@@ -486,7 +490,10 @@ static struct regulator_init_data lp3974_vichg_data = {
static struct regulator_init_data lp3974_esafeout1_data = {
.constraints = {
.name = "SAFEOUT1",
+ .min_uV = 4800000,
+ .max_uV = 4800000,
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .always_on = 1,
.state_mem = {
.enabled = 1,
},
@@ -750,7 +757,6 @@ static struct s3c_sdhci_platdata universal_hsmmc0_data __initdata = {
MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
.host_caps2 = MMC_CAP2_BROKEN_VOLTAGE,
.cd_type = S3C_SDHCI_CD_PERMANENT,
- .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
};
static struct regulator_consumer_supply mmc0_supplies[] = {
@@ -790,7 +796,6 @@ static struct s3c_sdhci_platdata universal_hsmmc2_data __initdata = {
.ext_cd_gpio = EXYNOS4_GPX3(4), /* XEINT_28 */
.ext_cd_gpio_invert = 1,
.cd_type = S3C_SDHCI_CD_GPIO,
- .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL,
};
/* WiFi */
@@ -813,6 +818,29 @@ static struct i2c_board_info i2c1_devs[] __initdata = {
/* Gyro, To be updated */
};
+#ifdef CONFIG_DRM_EXYNOS
+static struct exynos_drm_fimd_pdata drm_fimd_pdata = {
+ .panel = {
+ .timing = {
+ .left_margin = 16,
+ .right_margin = 16,
+ .upper_margin = 2,
+ .lower_margin = 28,
+ .hsync_len = 2,
+ .vsync_len = 1,
+ .xres = 480,
+ .yres = 800,
+ .refresh = 55,
+ },
+ },
+ .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB |
+ VIDCON0_CLKSEL_LCD,
+ .vidcon1 = VIDCON1_INV_VCLK | VIDCON1_INV_VDEN
+ | VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
+ .default_win = 3,
+ .bpp = 32,
+};
+#else
/* Frame Buffer */
static struct s3c_fb_pd_win universal_fb_win0 = {
.win_mode = {
@@ -840,6 +868,7 @@ static struct s3c_fb_platdata universal_lcd_pdata __initdata = {
| VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC,
.setup_gpio = exynos4_fimd0_gpio_setup_24bpp,
};
+#endif
static struct regulator_consumer_supply cam_vt_dio_supply =
REGULATOR_SUPPLY("vdd_core", "0-003c");
@@ -994,6 +1023,9 @@ static struct gpio universal_camera_gpios[] = {
{ GPIO_CAM_VGA_NSTBY, GPIOF_OUT_INIT_LOW, "CAM_VGA_NSTBY" },
};
+/* USB OTG */
+static struct s3c_hsotg_plat universal_hsotg_pdata;
+
static void __init universal_camera_init(void)
{
s3c_set_platdata(&mipi_csis_platdata, sizeof(mipi_csis_platdata),
@@ -1049,6 +1081,10 @@ static struct platform_device *universal_devices[] __initdata = {
&s5p_device_onenand,
&s5p_device_fimd0,
&s5p_device_jpeg,
+#ifdef CONFIG_DRM_EXYNOS
+ &exynos_device_drm,
+#endif
+ &s3c_device_usb_hsotg,
&s5p_device_mfc,
&s5p_device_mfc_l,
&s5p_device_mfc_r,
@@ -1096,12 +1132,18 @@ static void __init universal_machine_init(void)
s5p_i2c_hdmiphy_set_platdata(NULL);
i2c_register_board_info(5, i2c5_devs, ARRAY_SIZE(i2c5_devs));
+#ifdef CONFIG_DRM_EXYNOS
+ s5p_device_fimd0.dev.platform_data = &drm_fimd_pdata;
+ exynos4_fimd0_gpio_setup_24bpp();
+#else
s5p_fimd0_set_platdata(&universal_lcd_pdata);
+#endif
universal_touchkey_init();
i2c_register_board_info(I2C_GPIO_BUS_12, i2c_gpio12_devs,
ARRAY_SIZE(i2c_gpio12_devs));
+ s3c_hsotg_set_platdata(&universal_hsotg_pdata);
universal_camera_init();
/* Last */
diff --git a/arch/arm/mach-exynos/setup-usb-phy.c b/arch/arm/mach-exynos/setup-usb-phy.c
index 41743d21e8c6..1af0a7f44e00 100644
--- a/arch/arm/mach-exynos/setup-usb-phy.c
+++ b/arch/arm/mach-exynos/setup-usb-phy.c
@@ -26,11 +26,71 @@ static int exynos4_usb_host_phy_is_on(void)
return (readl(EXYNOS4_PHYPWR) & PHY1_STD_ANALOG_POWERDOWN) ? 0 : 1;
}
-static int exynos4_usb_phy1_init(struct platform_device *pdev)
+static void exynos4210_usb_phy_clkset(struct platform_device *pdev)
{
- struct clk *otg_clk;
struct clk *xusbxti_clk;
u32 phyclk;
+
+ /* set clock frequency for PLL */
+ phyclk = readl(EXYNOS4_PHYCLK) & ~CLKSEL_MASK;
+
+ xusbxti_clk = clk_get(&pdev->dev, "xusbxti");
+ if (xusbxti_clk && !IS_ERR(xusbxti_clk)) {
+ switch (clk_get_rate(xusbxti_clk)) {
+ case 12 * MHZ:
+ phyclk |= CLKSEL_12M;
+ break;
+ case 24 * MHZ:
+ phyclk |= CLKSEL_24M;
+ break;
+ default:
+ case 48 * MHZ:
+ /* default reference clock */
+ break;
+ }
+ clk_put(xusbxti_clk);
+ }
+
+ writel(phyclk, EXYNOS4_PHYCLK);
+}
+
+static int exynos4210_usb_phy0_init(struct platform_device *pdev)
+{
+ u32 rstcon;
+
+ writel(readl(S5P_USBDEVICE_PHY_CONTROL) | S5P_USBDEVICE_PHY_ENABLE,
+ S5P_USBDEVICE_PHY_CONTROL);
+
+ exynos4210_usb_phy_clkset(pdev);
+
+ /* set to normal PHY0 */
+ writel((readl(EXYNOS4_PHYPWR) & ~PHY0_NORMAL_MASK), EXYNOS4_PHYPWR);
+
+ /* reset PHY0 and Link */
+ rstcon = readl(EXYNOS4_RSTCON) | PHY0_SWRST_MASK;
+ writel(rstcon, EXYNOS4_RSTCON);
+ udelay(10);
+
+ rstcon &= ~PHY0_SWRST_MASK;
+ writel(rstcon, EXYNOS4_RSTCON);
+
+ return 0;
+}
+
+static int exynos4210_usb_phy0_exit(struct platform_device *pdev)
+{
+ writel((readl(EXYNOS4_PHYPWR) | PHY0_ANALOG_POWERDOWN |
+ PHY0_OTG_DISABLE), EXYNOS4_PHYPWR);
+
+ writel(readl(S5P_USBDEVICE_PHY_CONTROL) & ~S5P_USBDEVICE_PHY_ENABLE,
+ S5P_USBDEVICE_PHY_CONTROL);
+
+ return 0;
+}
+
+static int exynos4210_usb_phy1_init(struct platform_device *pdev)
+{
+ struct clk *otg_clk;
u32 rstcon;
int err;
@@ -54,27 +114,7 @@ static int exynos4_usb_phy1_init(struct platform_device *pdev)
writel(readl(S5P_USBHOST_PHY_CONTROL) | S5P_USBHOST_PHY_ENABLE,
S5P_USBHOST_PHY_CONTROL);
- /* set clock frequency for PLL */
- phyclk = readl(EXYNOS4_PHYCLK) & ~CLKSEL_MASK;
-
- xusbxti_clk = clk_get(&pdev->dev, "xusbxti");
- if (xusbxti_clk && !IS_ERR(xusbxti_clk)) {
- switch (clk_get_rate(xusbxti_clk)) {
- case 12 * MHZ:
- phyclk |= CLKSEL_12M;
- break;
- case 24 * MHZ:
- phyclk |= CLKSEL_24M;
- break;
- default:
- case 48 * MHZ:
- /* default reference clock */
- break;
- }
- clk_put(xusbxti_clk);
- }
-
- writel(phyclk, EXYNOS4_PHYCLK);
+ exynos4210_usb_phy_clkset(pdev);
/* floating prevention logic: disable */
writel((readl(EXYNOS4_PHY1CON) | FPENABLEN), EXYNOS4_PHY1CON);
@@ -102,7 +142,7 @@ static int exynos4_usb_phy1_init(struct platform_device *pdev)
return 0;
}
-static int exynos4_usb_phy1_exit(struct platform_device *pdev)
+static int exynos4210_usb_phy1_exit(struct platform_device *pdev)
{
struct clk *otg_clk;
int err;
@@ -136,16 +176,20 @@ static int exynos4_usb_phy1_exit(struct platform_device *pdev)
int s5p_usb_phy_init(struct platform_device *pdev, int type)
{
- if (type == S5P_USB_PHY_HOST)
- return exynos4_usb_phy1_init(pdev);
+ if (type == S5P_USB_PHY_DEVICE)
+ return exynos4210_usb_phy0_init(pdev);
+ else if (type == S5P_USB_PHY_HOST)
+ return exynos4210_usb_phy1_init(pdev);
return -EINVAL;
}
int s5p_usb_phy_exit(struct platform_device *pdev, int type)
{
- if (type == S5P_USB_PHY_HOST)
- return exynos4_usb_phy1_exit(pdev);
+ if (type == S5P_USB_PHY_DEVICE)
+ return exynos4210_usb_phy0_exit(pdev);
+ else if (type == S5P_USB_PHY_HOST)
+ return exynos4210_usb_phy1_exit(pdev);
return -EINVAL;
}
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 7561eca131b0..cca8c0c74794 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -151,6 +151,7 @@ config MACH_MX25_3DS
select IMX_HAVE_PLATFORM_IMX2_WDT
select IMX_HAVE_PLATFORM_IMXDI_RTC
select IMX_HAVE_PLATFORM_IMX_I2C
+ select IMX_HAVE_PLATFORM_IMX_SSI
select IMX_HAVE_PLATFORM_IMX_FB
select IMX_HAVE_PLATFORM_IMX_KEYPAD
select IMX_HAVE_PLATFORM_IMX_UART
@@ -163,6 +164,7 @@ config MACH_EUKREA_CPUIMX25SD
select SOC_IMX25
select IMX_HAVE_PLATFORM_FLEXCAN
select IMX_HAVE_PLATFORM_FSL_USB2_UDC
+ select IMX_HAVE_PLATFORM_IMX2_WDT
select IMX_HAVE_PLATFORM_IMXDI_RTC
select IMX_HAVE_PLATFORM_IMX_FB
select IMX_HAVE_PLATFORM_IMX_I2C
@@ -181,6 +183,7 @@ config MACH_EUKREA_MBIMXSD25_BASEBOARD
bool "Eukrea MBIMXSD development board"
select IMX_HAVE_PLATFORM_GPIO_KEYS
select IMX_HAVE_PLATFORM_IMX_SSI
+ select IMX_HAVE_PLATFORM_SPI_IMX
select LEDS_GPIO_REGISTER
help
This adds board specific devices that can be found on Eukrea's
@@ -493,6 +496,7 @@ config MACH_MX31MOBOARD
select IMX_HAVE_PLATFORM_FSL_USB2_UDC
select IMX_HAVE_PLATFORM_IMX2_WDT
select IMX_HAVE_PLATFORM_IMX_I2C
+ select IMX_HAVE_PLATFORM_IMX_SSI
select IMX_HAVE_PLATFORM_IMX_UART
select IMX_HAVE_PLATFORM_IPU_CORE
select IMX_HAVE_PLATFORM_MXC_EHCI
@@ -571,8 +575,10 @@ config MACH_MX35_3DS
select MXC_DEBUG_BOARD
select IMX_HAVE_PLATFORM_FSL_USB2_UDC
select IMX_HAVE_PLATFORM_IMX2_WDT
+ select IMX_HAVE_PLATFORM_IMX_FB
select IMX_HAVE_PLATFORM_IMX_I2C
select IMX_HAVE_PLATFORM_IMX_UART
+ select IMX_HAVE_PLATFORM_IPU_CORE
select IMX_HAVE_PLATFORM_MXC_EHCI
select IMX_HAVE_PLATFORM_MXC_NAND
select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
@@ -606,6 +612,7 @@ config MACH_EUKREA_MBIMXSD35_BASEBOARD
select IMX_HAVE_PLATFORM_GPIO_KEYS
select IMX_HAVE_PLATFORM_IMX_SSI
select IMX_HAVE_PLATFORM_IPU_CORE
+ select IMX_HAVE_PLATFORM_SPI_IMX
select LEDS_GPIO_REGISTER
help
This adds board specific devices that can be found on Eukrea's
@@ -682,42 +689,13 @@ config MACH_MX51_3DS
Include support for MX51PDK (3DS) platform. This includes specific
configurations for the board and its peripherals.
-config MACH_EUKREA_CPUIMX51
- bool "Support Eukrea CPUIMX51 module"
- select SOC_IMX51
- select IMX_HAVE_PLATFORM_FSL_USB2_UDC
- select IMX_HAVE_PLATFORM_IMX_I2C
- select IMX_HAVE_PLATFORM_IMX_UART
- select IMX_HAVE_PLATFORM_MXC_EHCI
- select IMX_HAVE_PLATFORM_MXC_NAND
- select IMX_HAVE_PLATFORM_SPI_IMX
- help
- Include support for Eukrea CPUIMX51 platform. This includes
- specific configurations for the module and its peripherals.
-
-choice
- prompt "Baseboard"
- depends on MACH_EUKREA_CPUIMX51
- default MACH_EUKREA_MBIMX51_BASEBOARD
-
-config MACH_EUKREA_MBIMX51_BASEBOARD
- prompt "Eukrea MBIMX51 development board"
- bool
- select IMX_HAVE_PLATFORM_IMX_KEYPAD
- select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
- select LEDS_GPIO_REGISTER
- help
- This adds board specific devices that can be found on Eukrea's
- MBIMX51 evaluation board.
-
-endchoice
-
config MACH_EUKREA_CPUIMX51SD
bool "Support Eukrea CPUIMX51SD module"
select SOC_IMX51
select IMX_HAVE_PLATFORM_FSL_USB2_UDC
select IMX_HAVE_PLATFORM_IMX_I2C
select IMX_HAVE_PLATFORM_IMX_UART
+ select IMX_HAVE_PLATFORM_IMX2_WDT
select IMX_HAVE_PLATFORM_MXC_EHCI
select IMX_HAVE_PLATFORM_MXC_NAND
select IMX_HAVE_PLATFORM_SPI_IMX
@@ -733,6 +711,7 @@ choice
config MACH_EUKREA_MBIMXSD51_BASEBOARD
prompt "Eukrea MBIMXSD development board"
bool
+ select IMX_HAVE_PLATFORM_IMX_SSI
select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
select LEDS_GPIO_REGISTER
help
@@ -842,6 +821,8 @@ config SOC_IMX6Q
select HAVE_IMX_MMDC
select HAVE_IMX_SRC
select HAVE_SMP
+ select PINCTRL
+ select PINCTRL_IMX6Q
select USE_OF
help
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index ab939c5046c3..4937c070a57e 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -83,10 +83,8 @@ obj-$(CONFIG_MACH_MX53_EVK) += mach-mx53_evk.o
obj-$(CONFIG_MACH_MX53_SMD) += mach-mx53_smd.o
obj-$(CONFIG_MACH_MX53_LOCO) += mach-mx53_loco.o
obj-$(CONFIG_MACH_MX53_ARD) += mach-mx53_ard.o
-obj-$(CONFIG_MACH_EUKREA_CPUIMX51) += mach-cpuimx51.o
-obj-$(CONFIG_MACH_EUKREA_MBIMX51_BASEBOARD) += eukrea_mbimx51-baseboard.o
obj-$(CONFIG_MACH_EUKREA_CPUIMX51SD) += mach-cpuimx51sd.o
-obj-$(CONFIG_MACH_EUKREA_MBIMXSD51_BASEBOARD) += eukrea_mbimxsd-baseboard.o
+obj-$(CONFIG_MACH_EUKREA_MBIMXSD51_BASEBOARD) += eukrea_mbimxsd51-baseboard.o
obj-$(CONFIG_MX51_EFIKA_COMMON) += mx51_efika.o
obj-$(CONFIG_MACH_MX51_EFIKAMX) += mach-mx51_efikamx.o
obj-$(CONFIG_MACH_MX51_EFIKASB) += mach-mx51_efikasb.o
diff --git a/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c b/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c
index 5f2f91d1798b..b46cab0ced53 100644
--- a/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c
+++ b/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c
@@ -243,7 +243,7 @@ static const struct imxuart_platform_data uart_pdata __initconst = {
static void __maybe_unused ads7846_dev_init(void)
{
if (gpio_request(ADS7846_PENDOWN, "ADS7846 pendown") < 0) {
- printk(KERN_ERR "can't get ads746 pen down GPIO\n");
+ printk(KERN_ERR "can't get ads7846 pen down GPIO\n");
return;
}
gpio_direction_input(ADS7846_PENDOWN);
diff --git a/arch/arm/mach-imx/eukrea_mbimx51-baseboard.c b/arch/arm/mach-imx/eukrea_mbimx51-baseboard.c
deleted file mode 100644
index a6a3ab8f1b1c..000000000000
--- a/arch/arm/mach-imx/eukrea_mbimx51-baseboard.c
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- *
- * Copyright (C) 2010 Eric Bénard <eric@eukrea.com>
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/serial_8250.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/i2c/tsc2007.h>
-#include <linux/leds.h>
-
-#include <mach/common.h>
-#include <mach/hardware.h>
-#include <mach/iomux-mx51.h>
-
-#include <asm/mach/arch.h>
-
-#include "devices-imx51.h"
-
-#define MBIMX51_TSC2007_GPIO IMX_GPIO_NR(3, 30)
-#define MBIMX51_LED0 IMX_GPIO_NR(3, 5)
-#define MBIMX51_LED1 IMX_GPIO_NR(3, 6)
-#define MBIMX51_LED2 IMX_GPIO_NR(3, 7)
-#define MBIMX51_LED3 IMX_GPIO_NR(3, 8)
-
-static const struct gpio_led mbimx51_leds[] __initconst = {
- {
- .name = "led0",
- .default_trigger = "heartbeat",
- .active_low = 1,
- .gpio = MBIMX51_LED0,
- },
- {
- .name = "led1",
- .default_trigger = "nand-disk",
- .active_low = 1,
- .gpio = MBIMX51_LED1,
- },
- {
- .name = "led2",
- .default_trigger = "mmc0",
- .active_low = 1,
- .gpio = MBIMX51_LED2,
- },
- {
- .name = "led3",
- .default_trigger = "default-on",
- .active_low = 1,
- .gpio = MBIMX51_LED3,
- },
-};
-
-static const struct gpio_led_platform_data mbimx51_leds_info __initconst = {
- .leds = mbimx51_leds,
- .num_leds = ARRAY_SIZE(mbimx51_leds),
-};
-
-static iomux_v3_cfg_t mbimx51_pads[] = {
- /* UART2 */
- MX51_PAD_UART2_RXD__UART2_RXD,
- MX51_PAD_UART2_TXD__UART2_TXD,
-
- /* UART3 */
- MX51_PAD_UART3_RXD__UART3_RXD,
- MX51_PAD_UART3_TXD__UART3_TXD,
- MX51_PAD_KEY_COL4__UART3_RTS,
- MX51_PAD_KEY_COL5__UART3_CTS,
-
- /* TSC2007 IRQ */
- MX51_PAD_NANDF_D10__GPIO3_30,
-
- /* LEDS */
- MX51_PAD_DISPB2_SER_DIN__GPIO3_5,
- MX51_PAD_DISPB2_SER_DIO__GPIO3_6,
- MX51_PAD_DISPB2_SER_CLK__GPIO3_7,
- MX51_PAD_DISPB2_SER_RS__GPIO3_8,
-
- /* KPP */
- MX51_PAD_KEY_ROW0__KEY_ROW0,
- MX51_PAD_KEY_ROW1__KEY_ROW1,
- MX51_PAD_KEY_ROW2__KEY_ROW2,
- MX51_PAD_KEY_ROW3__KEY_ROW3,
- MX51_PAD_KEY_COL0__KEY_COL0,
- MX51_PAD_KEY_COL1__KEY_COL1,
- MX51_PAD_KEY_COL2__KEY_COL2,
- MX51_PAD_KEY_COL3__KEY_COL3,
-
- /* SD 1 */
- MX51_PAD_SD1_CMD__SD1_CMD,
- MX51_PAD_SD1_CLK__SD1_CLK,
- MX51_PAD_SD1_DATA0__SD1_DATA0,
- MX51_PAD_SD1_DATA1__SD1_DATA1,
- MX51_PAD_SD1_DATA2__SD1_DATA2,
- MX51_PAD_SD1_DATA3__SD1_DATA3,
-
- /* SD 2 */
- MX51_PAD_SD2_CMD__SD2_CMD,
- MX51_PAD_SD2_CLK__SD2_CLK,
- MX51_PAD_SD2_DATA0__SD2_DATA0,
- MX51_PAD_SD2_DATA1__SD2_DATA1,
- MX51_PAD_SD2_DATA2__SD2_DATA2,
- MX51_PAD_SD2_DATA3__SD2_DATA3,
-};
-
-static const struct imxuart_platform_data uart_pdata __initconst = {
- .flags = IMXUART_HAVE_RTSCTS,
-};
-
-static int mbimx51_keymap[] = {
- KEY(0, 0, KEY_1),
- KEY(0, 1, KEY_2),
- KEY(0, 2, KEY_3),
- KEY(0, 3, KEY_UP),
-
- KEY(1, 0, KEY_4),
- KEY(1, 1, KEY_5),
- KEY(1, 2, KEY_6),
- KEY(1, 3, KEY_LEFT),
-
- KEY(2, 0, KEY_7),
- KEY(2, 1, KEY_8),
- KEY(2, 2, KEY_9),
- KEY(2, 3, KEY_RIGHT),
-
- KEY(3, 0, KEY_0),
- KEY(3, 1, KEY_DOWN),
- KEY(3, 2, KEY_ESC),
- KEY(3, 3, KEY_ENTER),
-};
-
-static const struct matrix_keymap_data mbimx51_map_data __initconst = {
- .keymap = mbimx51_keymap,
- .keymap_size = ARRAY_SIZE(mbimx51_keymap),
-};
-
-static int tsc2007_get_pendown_state(void)
-{
- return !gpio_get_value(MBIMX51_TSC2007_GPIO);
-}
-
-struct tsc2007_platform_data tsc2007_data = {
- .model = 2007,
- .x_plate_ohms = 180,
- .get_pendown_state = tsc2007_get_pendown_state,
-};
-
-static struct i2c_board_info mbimx51_i2c_devices[] = {
- {
- I2C_BOARD_INFO("tsc2007", 0x49),
- .irq = IMX_GPIO_TO_IRQ(MBIMX51_TSC2007_GPIO),
- .platform_data = &tsc2007_data,
- }, {
- I2C_BOARD_INFO("tlv320aic23", 0x1a),
- },
-};
-
-/*
- * baseboard initialization.
- */
-void __init eukrea_mbimx51_baseboard_init(void)
-{
- mxc_iomux_v3_setup_multiple_pads(mbimx51_pads,
- ARRAY_SIZE(mbimx51_pads));
-
- imx51_add_imx_uart(1, NULL);
- imx51_add_imx_uart(2, &uart_pdata);
-
- gpio_request(MBIMX51_LED0, "LED0");
- gpio_direction_output(MBIMX51_LED0, 1);
- gpio_free(MBIMX51_LED0);
- gpio_request(MBIMX51_LED1, "LED1");
- gpio_direction_output(MBIMX51_LED1, 1);
- gpio_free(MBIMX51_LED1);
- gpio_request(MBIMX51_LED2, "LED2");
- gpio_direction_output(MBIMX51_LED2, 1);
- gpio_free(MBIMX51_LED2);
- gpio_request(MBIMX51_LED3, "LED3");
- gpio_direction_output(MBIMX51_LED3, 1);
- gpio_free(MBIMX51_LED3);
-
- gpio_led_register_device(-1, &mbimx51_leds_info);
-
- imx51_add_imx_keypad(&mbimx51_map_data);
-
- gpio_request(MBIMX51_TSC2007_GPIO, "tsc2007_irq");
- gpio_direction_input(MBIMX51_TSC2007_GPIO);
- irq_set_irq_type(gpio_to_irq(MBIMX51_TSC2007_GPIO),
- IRQF_TRIGGER_FALLING);
- i2c_register_board_info(1, mbimx51_i2c_devices,
- ARRAY_SIZE(mbimx51_i2c_devices));
-
- imx51_add_sdhci_esdhc_imx(0, NULL);
- imx51_add_sdhci_esdhc_imx(1, NULL);
-}
diff --git a/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c
index 2cf603e11c4f..dfd2da87c2df 100644
--- a/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c
+++ b/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c
@@ -23,6 +23,7 @@
#include <linux/leds.h>
#include <linux/platform_device.h>
#include <linux/input.h>
+#include <linux/spi/spi.h>
#include <video/platform_lcd.h>
#include <mach/hardware.h>
@@ -87,12 +88,22 @@ static iomux_v3_cfg_t eukrea_mbimxsd_pads[] = {
/* CAN */
MX25_PAD_GPIO_D__CAN2_RX,
MX25_PAD_GPIO_C__CAN2_TX,
+ /* SPI1 */
+ MX25_PAD_CSPI1_MOSI__CSPI1_MOSI,
+ MX25_PAD_CSPI1_MISO__CSPI1_MISO,
+ MX25_PAD_CSPI1_SS0__GPIO_1_16,
+ MX25_PAD_CSPI1_SS1__GPIO_1_17,
+ MX25_PAD_CSPI1_SCLK__CSPI1_SCLK,
+ MX25_PAD_CSPI1_RDY__GPIO_2_22,
};
-#define GPIO_LED1 83
-#define GPIO_SWITCH1 82
-#define GPIO_SD1CD 52
-#define GPIO_LCDPWR 26
+#define GPIO_LED1 IMX_GPIO_NR(3, 19)
+#define GPIO_SWITCH1 IMX_GPIO_NR(3, 18)
+#define GPIO_SD1CD IMX_GPIO_NR(2, 20)
+#define GPIO_LCDPWR IMX_GPIO_NR(1, 26)
+#define GPIO_SPI1_SS0 IMX_GPIO_NR(1, 16)
+#define GPIO_SPI1_SS1 IMX_GPIO_NR(1, 17)
+#define GPIO_SPI1_IRQ IMX_GPIO_NR(2, 22)
static struct imx_fb_videomode eukrea_mximxsd_modes[] = {
{
@@ -228,6 +239,30 @@ static struct esdhc_platform_data sd1_pdata = {
.wp_type = ESDHC_WP_NONE,
};
+static struct spi_board_info eukrea_mbimxsd25_spi_board_info[] __initdata = {
+ {
+ .modalias = "spidev",
+ .max_speed_hz = 20000000,
+ .bus_num = 0,
+ .chip_select = 0,
+ .mode = SPI_MODE_0,
+ },
+ {
+ .modalias = "spidev",
+ .max_speed_hz = 20000000,
+ .bus_num = 0,
+ .chip_select = 1,
+ .mode = SPI_MODE_0,
+ },
+};
+
+static int eukrea_mbimxsd25_spi_cs[] = {GPIO_SPI1_SS0, GPIO_SPI1_SS1};
+
+static const struct spi_imx_master eukrea_mbimxsd25_spi0_data __initconst = {
+ .chipselect = eukrea_mbimxsd25_spi_cs,
+ .num_chipselect = ARRAY_SIZE(eukrea_mbimxsd25_spi_cs),
+};
+
/*
* system init for baseboard usage. Will be called by cpuimx25 init.
*
@@ -257,11 +292,17 @@ void __init eukrea_mbimxsd25_baseboard_init(void)
gpio_request(GPIO_LCDPWR, "LCDPWR");
gpio_direction_output(GPIO_LCDPWR, 1);
- gpio_free(GPIO_SWITCH1);
i2c_register_board_info(0, eukrea_mbimxsd_i2c_devices,
ARRAY_SIZE(eukrea_mbimxsd_i2c_devices));
+ gpio_request(GPIO_SPI1_IRQ, "SPI1_IRQ");
+ gpio_direction_input(GPIO_SPI1_IRQ);
+ gpio_free(GPIO_SPI1_IRQ);
+ imx25_add_spi_imx0(&eukrea_mbimxsd25_spi0_data);
+ spi_register_board_info(eukrea_mbimxsd25_spi_board_info,
+ ARRAY_SIZE(eukrea_mbimxsd25_spi_board_info));
+
platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
gpio_led_register_device(-1, &eukrea_mbimxsd_led_info);
imx_add_gpio_keys(&eukrea_mbimxsd_button_data);
diff --git a/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c
index fd8bf8a425a7..557f6c486053 100644
--- a/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c
+++ b/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c
@@ -27,6 +27,7 @@
#include <linux/leds.h>
#include <linux/platform_device.h>
#include <linux/input.h>
+#include <linux/spi/spi.h>
#include <video/platform_lcd.h>
#include <linux/i2c.h>
@@ -158,12 +159,22 @@ static iomux_v3_cfg_t eukrea_mbimxsd_pads[] = {
MX35_PAD_SD1_DATA3__ESDHC1_DAT3,
/* SD1 CD */
MX35_PAD_LD18__GPIO3_24,
+ /* SPI */
+ MX35_PAD_CSPI1_MOSI__CSPI1_MOSI,
+ MX35_PAD_CSPI1_MISO__CSPI1_MISO,
+ MX35_PAD_CSPI1_SS0__GPIO1_18,
+ MX35_PAD_CSPI1_SS1__GPIO1_19,
+ MX35_PAD_CSPI1_SCLK__CSPI1_SCLK,
+ MX35_PAD_CSPI1_SPI_RDY__GPIO3_5,
};
#define GPIO_LED1 IMX_GPIO_NR(3, 29)
#define GPIO_SWITCH1 IMX_GPIO_NR(3, 25)
#define GPIO_LCDPWR IMX_GPIO_NR(1, 4)
#define GPIO_SD1CD IMX_GPIO_NR(3, 24)
+#define GPIO_SPI1_SS0 IMX_GPIO_NR(1, 18)
+#define GPIO_SPI1_SS1 IMX_GPIO_NR(1, 19)
+#define GPIO_SPI1_IRQ IMX_GPIO_NR(3, 5)
static void eukrea_mbimxsd_lcd_power_set(struct plat_lcd_data *pd,
unsigned int power)
@@ -239,6 +250,30 @@ static struct esdhc_platform_data sd1_pdata = {
.wp_type = ESDHC_WP_NONE,
};
+static struct spi_board_info eukrea_mbimxsd35_spi_board_info[] __initdata = {
+ {
+ .modalias = "spidev",
+ .max_speed_hz = 20000000,
+ .bus_num = 0,
+ .chip_select = 0,
+ .mode = SPI_MODE_0,
+ },
+ {
+ .modalias = "spidev",
+ .max_speed_hz = 20000000,
+ .bus_num = 0,
+ .chip_select = 1,
+ .mode = SPI_MODE_0,
+ },
+};
+
+static int eukrea_mbimxsd35_spi_cs[] = {GPIO_SPI1_SS0, GPIO_SPI1_SS1};
+
+static const struct spi_imx_master eukrea_mbimxsd35_spi0_data __initconst = {
+ .chipselect = eukrea_mbimxsd35_spi_cs,
+ .num_chipselect = ARRAY_SIZE(eukrea_mbimxsd35_spi_cs),
+};
+
/*
* system init for baseboard usage. Will be called by cpuimx35 init.
*
@@ -274,6 +309,13 @@ void __init eukrea_mbimxsd35_baseboard_init(void)
i2c_register_board_info(0, eukrea_mbimxsd_i2c_devices,
ARRAY_SIZE(eukrea_mbimxsd_i2c_devices));
+ gpio_request(GPIO_SPI1_IRQ, "SPI1_IRQ");
+ gpio_direction_input(GPIO_SPI1_IRQ);
+ gpio_free(GPIO_SPI1_IRQ);
+ imx35_add_spi_imx0(&eukrea_mbimxsd35_spi0_data);
+ spi_register_board_info(eukrea_mbimxsd35_spi_board_info,
+ ARRAY_SIZE(eukrea_mbimxsd35_spi_board_info));
+
platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
gpio_led_register_device(-1, &eukrea_mbimxsd_led_info);
imx_add_gpio_keys(&eukrea_mbimxsd_button_data);
diff --git a/arch/arm/mach-imx/eukrea_mbimxsd-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd51-baseboard.c
index aaa592fdb9ce..96a24b73dc23 100644
--- a/arch/arm/mach-imx/eukrea_mbimxsd-baseboard.c
+++ b/arch/arm/mach-imx/eukrea_mbimxsd51-baseboard.c
@@ -28,6 +28,8 @@
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/i2c.h>
+#include <video/platform_lcd.h>
+#include <linux/backlight.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -40,7 +42,7 @@
#include "devices-imx51.h"
-static iomux_v3_cfg_t eukrea_mbimxsd_pads[] = {
+static iomux_v3_cfg_t eukrea_mbimxsd51_pads[] = {
/* LED */
MX51_PAD_NANDF_D10__GPIO3_30,
/* SWITCH */
@@ -66,12 +68,64 @@ static iomux_v3_cfg_t eukrea_mbimxsd_pads[] = {
NEW_PAD_CTRL(MX51_PAD_GPIO1_0__SD1_CD, PAD_CTL_PUS_22K_UP |
PAD_CTL_PKE | PAD_CTL_SRE_FAST |
PAD_CTL_DSE_HIGH | PAD_CTL_PUE | PAD_CTL_HYS),
+ /* SSI */
+ MX51_PAD_AUD3_BB_TXD__AUD3_TXD,
+ MX51_PAD_AUD3_BB_RXD__AUD3_RXD,
+ MX51_PAD_AUD3_BB_CK__AUD3_TXC,
+ MX51_PAD_AUD3_BB_FS__AUD3_TXFS,
+ /* LCD Backlight */
+ MX51_PAD_DI1_D1_CS__GPIO3_4,
+ /* LCD RST */
+ MX51_PAD_CSI1_D9__GPIO3_13,
};
#define GPIO_LED1 IMX_GPIO_NR(3, 30)
#define GPIO_SWITCH1 IMX_GPIO_NR(3, 31)
+#define GPIO_LCDRST IMX_GPIO_NR(3, 13)
+#define GPIO_LCDBL IMX_GPIO_NR(3, 4)
-static const struct gpio_led eukrea_mbimxsd_leds[] __initconst = {
+static void eukrea_mbimxsd51_lcd_power_set(struct plat_lcd_data *pd,
+ unsigned int power)
+{
+ if (power)
+ gpio_direction_output(GPIO_LCDRST, 1);
+ else
+ gpio_direction_output(GPIO_LCDRST, 0);
+}
+
+static struct plat_lcd_data eukrea_mbimxsd51_lcd_power_data = {
+ .set_power = eukrea_mbimxsd51_lcd_power_set,
+};
+
+static struct platform_device eukrea_mbimxsd51_lcd_powerdev = {
+ .name = "platform-lcd",
+ .dev.platform_data = &eukrea_mbimxsd51_lcd_power_data,
+};
+
+static void eukrea_mbimxsd51_bl_set_intensity(int intensity)
+{
+ if (intensity)
+ gpio_direction_output(GPIO_LCDBL, 1);
+ else
+ gpio_direction_output(GPIO_LCDBL, 0);
+}
+
+static struct generic_bl_info eukrea_mbimxsd51_bl_info = {
+ .name = "eukrea_mbimxsd51-bl",
+ .max_intensity = 0xff,
+ .default_intensity = 0xff,
+ .set_bl_intensity = eukrea_mbimxsd51_bl_set_intensity,
+};
+
+static struct platform_device eukrea_mbimxsd51_bl_dev = {
+ .name = "generic-bl",
+ .id = 1,
+ .dev = {
+ .platform_data = &eukrea_mbimxsd51_bl_info,
+ },
+};
+
+static const struct gpio_led eukrea_mbimxsd51_leds[] __initconst = {
{
.name = "led1",
.default_trigger = "heartbeat",
@@ -81,12 +135,12 @@ static const struct gpio_led eukrea_mbimxsd_leds[] __initconst = {
};
static const struct gpio_led_platform_data
- eukrea_mbimxsd_led_info __initconst = {
- .leds = eukrea_mbimxsd_leds,
- .num_leds = ARRAY_SIZE(eukrea_mbimxsd_leds),
+ eukrea_mbimxsd51_led_info __initconst = {
+ .leds = eukrea_mbimxsd51_leds,
+ .num_leds = ARRAY_SIZE(eukrea_mbimxsd51_leds),
};
-static struct gpio_keys_button eukrea_mbimxsd_gpio_buttons[] = {
+static struct gpio_keys_button eukrea_mbimxsd51_gpio_buttons[] = {
{
.gpio = GPIO_SWITCH1,
.code = BTN_0,
@@ -97,21 +151,39 @@ static struct gpio_keys_button eukrea_mbimxsd_gpio_buttons[] = {
};
static const struct gpio_keys_platform_data
- eukrea_mbimxsd_button_data __initconst = {
- .buttons = eukrea_mbimxsd_gpio_buttons,
- .nbuttons = ARRAY_SIZE(eukrea_mbimxsd_gpio_buttons),
+ eukrea_mbimxsd51_button_data __initconst = {
+ .buttons = eukrea_mbimxsd51_gpio_buttons,
+ .nbuttons = ARRAY_SIZE(eukrea_mbimxsd51_gpio_buttons),
};
static const struct imxuart_platform_data uart_pdata __initconst = {
.flags = IMXUART_HAVE_RTSCTS,
};
-static struct i2c_board_info eukrea_mbimxsd_i2c_devices[] = {
+static struct i2c_board_info eukrea_mbimxsd51_i2c_devices[] = {
{
I2C_BOARD_INFO("tlv320aic23", 0x1a),
},
};
+static const
+struct imx_ssi_platform_data eukrea_mbimxsd51_ssi_pdata __initconst = {
+ .flags = IMX_SSI_SYN | IMX_SSI_NET | IMX_SSI_USE_I2S_SLAVE,
+};
+
+static int screen_type;
+
+static int __init eukrea_mbimxsd51_screen_type(char *options)
+{
+ if (!strcmp(options, "dvi"))
+ screen_type = 1;
+ else if (!strcmp(options, "tft"))
+ screen_type = 0;
+
+ return 0;
+}
+__setup("screen_type=", eukrea_mbimxsd51_screen_type);
+
/*
* system init for baseboard usage. Will be called by cpuimx51sd init.
*
@@ -120,8 +192,8 @@ static struct i2c_board_info eukrea_mbimxsd_i2c_devices[] = {
*/
void __init eukrea_mbimxsd51_baseboard_init(void)
{
- if (mxc_iomux_v3_setup_multiple_pads(eukrea_mbimxsd_pads,
- ARRAY_SIZE(eukrea_mbimxsd_pads)))
+ if (mxc_iomux_v3_setup_multiple_pads(eukrea_mbimxsd51_pads,
+ ARRAY_SIZE(eukrea_mbimxsd51_pads)))
printk(KERN_ERR "error setting mbimxsd pads !\n");
imx51_add_imx_uart(1, NULL);
@@ -129,6 +201,8 @@ void __init eukrea_mbimxsd51_baseboard_init(void)
imx51_add_sdhci_esdhc_imx(0, NULL);
+ imx51_add_imx_ssi(0, &eukrea_mbimxsd51_ssi_pdata);
+
gpio_request(GPIO_LED1, "LED1");
gpio_direction_output(GPIO_LED1, 1);
gpio_free(GPIO_LED1);
@@ -137,9 +211,21 @@ void __init eukrea_mbimxsd51_baseboard_init(void)
gpio_direction_input(GPIO_SWITCH1);
gpio_free(GPIO_SWITCH1);
- i2c_register_board_info(0, eukrea_mbimxsd_i2c_devices,
- ARRAY_SIZE(eukrea_mbimxsd_i2c_devices));
-
- gpio_led_register_device(-1, &eukrea_mbimxsd_led_info);
- imx_add_gpio_keys(&eukrea_mbimxsd_button_data);
+ gpio_request(GPIO_LCDRST, "LCDRST");
+ gpio_direction_output(GPIO_LCDRST, 0);
+ gpio_request(GPIO_LCDBL, "LCDBL");
+ gpio_direction_output(GPIO_LCDBL, 0);
+ if (!screen_type) {
+ platform_device_register(&eukrea_mbimxsd51_bl_dev);
+ platform_device_register(&eukrea_mbimxsd51_lcd_powerdev);
+ } else {
+ gpio_free(GPIO_LCDRST);
+ gpio_free(GPIO_LCDBL);
+ }
+
+ i2c_register_board_info(0, eukrea_mbimxsd51_i2c_devices,
+ ARRAY_SIZE(eukrea_mbimxsd51_i2c_devices));
+
+ gpio_led_register_device(-1, &eukrea_mbimxsd51_led_info);
+ imx_add_gpio_keys(&eukrea_mbimxsd51_button_data);
}
diff --git a/arch/arm/mach-imx/imx51-dt.c b/arch/arm/mach-imx/imx51-dt.c
index 5cca573964f0..5f577fbda2c8 100644
--- a/arch/arm/mach-imx/imx51-dt.c
+++ b/arch/arm/mach-imx/imx51-dt.c
@@ -14,6 +14,7 @@
#include <linux/irqdomain.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include <linux/pinctrl/machine.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
#include <mach/common.h>
@@ -81,6 +82,8 @@ static void __init imx51_dt_init(void)
of_irq_init(imx51_irq_match);
+ pinctrl_provide_dummies();
+
node = of_find_matching_node(NULL, imx51_iomuxc_of_match);
if (node) {
of_id = of_match_node(imx51_iomuxc_of_match, node);
diff --git a/arch/arm/mach-imx/imx53-dt.c b/arch/arm/mach-imx/imx53-dt.c
index 4172279b3900..574eca4b89a5 100644
--- a/arch/arm/mach-imx/imx53-dt.c
+++ b/arch/arm/mach-imx/imx53-dt.c
@@ -15,6 +15,7 @@
#include <linux/irqdomain.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include <linux/pinctrl/machine.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
#include <mach/common.h>
@@ -88,6 +89,8 @@ static void __init imx53_dt_init(void)
of_irq_init(imx53_irq_match);
+ pinctrl_provide_dummies();
+
node = of_find_matching_node(NULL, imx53_iomuxc_of_match);
if (node) {
of_id = of_match_node(imx53_iomuxc_of_match, node);
diff --git a/arch/arm/mach-imx/mach-cpuimx35.c b/arch/arm/mach-imx/mach-cpuimx35.c
index 8ecc872b2547..c515f8ede1a1 100644
--- a/arch/arm/mach-imx/mach-cpuimx35.c
+++ b/arch/arm/mach-imx/mach-cpuimx35.c
@@ -194,7 +194,7 @@ static void __init eukrea_cpuimx35_timer_init(void)
mx35_clocks_init();
}
-struct sys_timer eukrea_cpuimx35_timer = {
+static struct sys_timer eukrea_cpuimx35_timer = {
.init = eukrea_cpuimx35_timer_init,
};
diff --git a/arch/arm/mach-imx/mach-cpuimx51.c b/arch/arm/mach-imx/mach-cpuimx51.c
deleted file mode 100644
index 944025da8333..000000000000
--- a/arch/arm/mach-imx/mach-cpuimx51.c
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- *
- * Copyright (C) 2010 Eric Bénard <eric@eukrea.com>
- *
- * based on board-mx51_babbage.c which is
- * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright (C) 2009-2010 Amit Kucheria <amit.kucheria@canonical.com>
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/serial_8250.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-
-#include <mach/eukrea-baseboards.h>
-#include <mach/common.h>
-#include <mach/hardware.h>
-#include <mach/iomux-mx51.h>
-
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/time.h>
-
-#include "devices-imx51.h"
-
-#define CPUIMX51_USBH1_STP IMX_GPIO_NR(1, 27)
-#define CPUIMX51_QUARTA_GPIO IMX_GPIO_NR(3, 28)
-#define CPUIMX51_QUARTB_GPIO IMX_GPIO_NR(3, 25)
-#define CPUIMX51_QUARTC_GPIO IMX_GPIO_NR(3, 26)
-#define CPUIMX51_QUARTD_GPIO IMX_GPIO_NR(3, 27)
-#define CPUIMX51_QUART_XTAL 14745600
-#define CPUIMX51_QUART_REGSHIFT 17
-
-/* USB_CTRL_1 */
-#define MX51_USB_CTRL_1_OFFSET 0x10
-#define MX51_USB_CTRL_UH1_EXT_CLK_EN (1 << 25)
-
-#define MX51_USB_PLLDIV_12_MHZ 0x00
-#define MX51_USB_PLL_DIV_19_2_MHZ 0x01
-#define MX51_USB_PLL_DIV_24_MHZ 0x02
-
-static struct plat_serial8250_port serial_platform_data[] = {
- {
- .mapbase = (unsigned long)(MX51_CS1_BASE_ADDR + 0x400000),
- .irq = IMX_GPIO_TO_IRQ(CPUIMX51_QUARTA_GPIO),
- .irqflags = IRQF_TRIGGER_HIGH,
- .uartclk = CPUIMX51_QUART_XTAL,
- .regshift = CPUIMX51_QUART_REGSHIFT,
- .iotype = UPIO_MEM,
- .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP,
- }, {
- .mapbase = (unsigned long)(MX51_CS1_BASE_ADDR + 0x800000),
- .irq = IMX_GPIO_TO_IRQ(CPUIMX51_QUARTB_GPIO),
- .irqflags = IRQF_TRIGGER_HIGH,
- .uartclk = CPUIMX51_QUART_XTAL,
- .regshift = CPUIMX51_QUART_REGSHIFT,
- .iotype = UPIO_MEM,
- .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP,
- }, {
- .mapbase = (unsigned long)(MX51_CS1_BASE_ADDR + 0x1000000),
- .irq = IMX_GPIO_TO_IRQ(CPUIMX51_QUARTC_GPIO),
- .irqflags = IRQF_TRIGGER_HIGH,
- .uartclk = CPUIMX51_QUART_XTAL,
- .regshift = CPUIMX51_QUART_REGSHIFT,
- .iotype = UPIO_MEM,
- .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP,
- }, {
- .mapbase = (unsigned long)(MX51_CS1_BASE_ADDR + 0x2000000),
- .irq = IMX_GPIO_TO_IRQ(CPUIMX51_QUARTD_GPIO),
- .irqflags = IRQF_TRIGGER_HIGH,
- .uartclk = CPUIMX51_QUART_XTAL,
- .regshift = CPUIMX51_QUART_REGSHIFT,
- .iotype = UPIO_MEM,
- .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP,
- }, {
- }
-};
-
-static struct platform_device serial_device = {
- .name = "serial8250",
- .id = 0,
- .dev = {
- .platform_data = serial_platform_data,
- },
-};
-
-static struct platform_device *devices[] __initdata = {
- &serial_device,
-};
-
-static iomux_v3_cfg_t eukrea_cpuimx51_pads[] = {
- /* UART1 */
- MX51_PAD_UART1_RXD__UART1_RXD,
- MX51_PAD_UART1_TXD__UART1_TXD,
- MX51_PAD_UART1_RTS__UART1_RTS,
- MX51_PAD_UART1_CTS__UART1_CTS,
-
- /* I2C2 */
- MX51_PAD_GPIO1_2__I2C2_SCL,
- MX51_PAD_GPIO1_3__I2C2_SDA,
- MX51_PAD_NANDF_D10__GPIO3_30,
-
- /* QUART IRQ */
- MX51_PAD_NANDF_D15__GPIO3_25,
- MX51_PAD_NANDF_D14__GPIO3_26,
- MX51_PAD_NANDF_D13__GPIO3_27,
- MX51_PAD_NANDF_D12__GPIO3_28,
-
- /* USB HOST1 */
- MX51_PAD_USBH1_CLK__USBH1_CLK,
- MX51_PAD_USBH1_DIR__USBH1_DIR,
- MX51_PAD_USBH1_NXT__USBH1_NXT,
- MX51_PAD_USBH1_DATA0__USBH1_DATA0,
- MX51_PAD_USBH1_DATA1__USBH1_DATA1,
- MX51_PAD_USBH1_DATA2__USBH1_DATA2,
- MX51_PAD_USBH1_DATA3__USBH1_DATA3,
- MX51_PAD_USBH1_DATA4__USBH1_DATA4,
- MX51_PAD_USBH1_DATA5__USBH1_DATA5,
- MX51_PAD_USBH1_DATA6__USBH1_DATA6,
- MX51_PAD_USBH1_DATA7__USBH1_DATA7,
- MX51_PAD_USBH1_STP__USBH1_STP,
-};
-
-static const struct mxc_nand_platform_data
- eukrea_cpuimx51_nand_board_info __initconst = {
- .width = 1,
- .hw_ecc = 1,
- .flash_bbt = 1,
-};
-
-static const struct imxuart_platform_data uart_pdata __initconst = {
- .flags = IMXUART_HAVE_RTSCTS,
-};
-
-static const
-struct imxi2c_platform_data eukrea_cpuimx51_i2c_data __initconst = {
- .bitrate = 100000,
-};
-
-static struct i2c_board_info eukrea_cpuimx51_i2c_devices[] = {
- {
- I2C_BOARD_INFO("pcf8563", 0x51),
- },
-};
-
-/* This function is board specific as the bit mask for the plldiv will also
-be different for other Freescale SoCs, thus a common bitmask is not
-possible and cannot get place in /plat-mxc/ehci.c.*/
-static int initialize_otg_port(struct platform_device *pdev)
-{
- u32 v;
- void __iomem *usb_base;
- void __iomem *usbother_base;
-
- usb_base = ioremap(MX51_USB_OTG_BASE_ADDR, SZ_4K);
- if (!usb_base)
- return -ENOMEM;
- usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
-
- /* Set the PHY clock to 19.2MHz */
- v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
- v &= ~MX5_USB_UTMI_PHYCTRL1_PLLDIV_MASK;
- v |= MX51_USB_PLL_DIV_19_2_MHZ;
- __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
- iounmap(usb_base);
-
- mdelay(10);
-
- return mx51_initialize_usb_hw(0, MXC_EHCI_INTERNAL_PHY);
-}
-
-static int initialize_usbh1_port(struct platform_device *pdev)
-{
- u32 v;
- void __iomem *usb_base;
- void __iomem *usbother_base;
-
- usb_base = ioremap(MX51_USB_OTG_BASE_ADDR, SZ_4K);
- if (!usb_base)
- return -ENOMEM;
- usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
-
- /* The clock for the USBH1 ULPI port will come externally from the PHY. */
- v = __raw_readl(usbother_base + MX51_USB_CTRL_1_OFFSET);
- __raw_writel(v | MX51_USB_CTRL_UH1_EXT_CLK_EN, usbother_base + MX51_USB_CTRL_1_OFFSET);
- iounmap(usb_base);
-
- mdelay(10);
-
- return mx51_initialize_usb_hw(1, MXC_EHCI_POWER_PINS_ENABLED |
- MXC_EHCI_ITC_NO_THRESHOLD);
-}
-
-static const struct mxc_usbh_platform_data dr_utmi_config __initconst = {
- .init = initialize_otg_port,
- .portsc = MXC_EHCI_UTMI_16BIT,
-};
-
-static const struct fsl_usb2_platform_data usb_pdata __initconst = {
- .operating_mode = FSL_USB2_DR_DEVICE,
- .phy_mode = FSL_USB2_PHY_UTMI_WIDE,
-};
-
-static const struct mxc_usbh_platform_data usbh1_config __initconst = {
- .init = initialize_usbh1_port,
- .portsc = MXC_EHCI_MODE_ULPI,
-};
-
-static int otg_mode_host;
-
-static int __init eukrea_cpuimx51_otg_mode(char *options)
-{
- if (!strcmp(options, "host"))
- otg_mode_host = 1;
- else if (!strcmp(options, "device"))
- otg_mode_host = 0;
- else
- pr_info("otg_mode neither \"host\" nor \"device\". "
- "Defaulting to device\n");
- return 0;
-}
-__setup("otg_mode=", eukrea_cpuimx51_otg_mode);
-
-/*
- * Board specific initialization.
- */
-static void __init eukrea_cpuimx51_init(void)
-{
- imx51_soc_init();
-
- mxc_iomux_v3_setup_multiple_pads(eukrea_cpuimx51_pads,
- ARRAY_SIZE(eukrea_cpuimx51_pads));
-
- imx51_add_imx_uart(0, &uart_pdata);
- imx51_add_mxc_nand(&eukrea_cpuimx51_nand_board_info);
-
- gpio_request(CPUIMX51_QUARTA_GPIO, "quarta_irq");
- gpio_direction_input(CPUIMX51_QUARTA_GPIO);
- gpio_free(CPUIMX51_QUARTA_GPIO);
- gpio_request(CPUIMX51_QUARTB_GPIO, "quartb_irq");
- gpio_direction_input(CPUIMX51_QUARTB_GPIO);
- gpio_free(CPUIMX51_QUARTB_GPIO);
- gpio_request(CPUIMX51_QUARTC_GPIO, "quartc_irq");
- gpio_direction_input(CPUIMX51_QUARTC_GPIO);
- gpio_free(CPUIMX51_QUARTC_GPIO);
- gpio_request(CPUIMX51_QUARTD_GPIO, "quartd_irq");
- gpio_direction_input(CPUIMX51_QUARTD_GPIO);
- gpio_free(CPUIMX51_QUARTD_GPIO);
-
- imx51_add_fec(NULL);
- platform_add_devices(devices, ARRAY_SIZE(devices));
-
- imx51_add_imx_i2c(1, &eukrea_cpuimx51_i2c_data);
- i2c_register_board_info(1, eukrea_cpuimx51_i2c_devices,
- ARRAY_SIZE(eukrea_cpuimx51_i2c_devices));
-
- if (otg_mode_host)
- imx51_add_mxc_ehci_otg(&dr_utmi_config);
- else {
- initialize_otg_port(NULL);
- imx51_add_fsl_usb2_udc(&usb_pdata);
- }
- imx51_add_mxc_ehci_hs(1, &usbh1_config);
-
-#ifdef CONFIG_MACH_EUKREA_MBIMX51_BASEBOARD
- eukrea_mbimx51_baseboard_init();
-#endif
-}
-
-static void __init eukrea_cpuimx51_timer_init(void)
-{
- mx51_clocks_init(32768, 24000000, 22579200, 0);
-}
-
-static struct sys_timer mxc_timer = {
- .init = eukrea_cpuimx51_timer_init,
-};
-
-MACHINE_START(EUKREA_CPUIMX51, "Eukrea CPUIMX51 Module")
- /* Maintainer: Eric Bénard <eric@eukrea.com> */
- .atag_offset = 0x100,
- .map_io = mx51_map_io,
- .init_early = imx51_init_early,
- .init_irq = mx51_init_irq,
- .handle_irq = imx51_handle_irq,
- .timer = &mxc_timer,
- .init_machine = eukrea_cpuimx51_init,
- .restart = mxc_restart,
-MACHINE_END
diff --git a/arch/arm/mach-imx/mach-cpuimx51sd.c b/arch/arm/mach-imx/mach-cpuimx51sd.c
index 9fbe923c8b08..ce341a6874fc 100644
--- a/arch/arm/mach-imx/mach-cpuimx51sd.c
+++ b/arch/arm/mach-imx/mach-cpuimx51sd.c
@@ -41,11 +41,13 @@
#define USBH1_RST IMX_GPIO_NR(2, 28)
#define ETH_RST IMX_GPIO_NR(2, 31)
-#define TSC2007_IRQGPIO IMX_GPIO_NR(3, 12)
+#define TSC2007_IRQGPIO_REV2 IMX_GPIO_NR(3, 12)
+#define TSC2007_IRQGPIO_REV3 IMX_GPIO_NR(4, 0)
#define CAN_IRQGPIO IMX_GPIO_NR(1, 1)
#define CAN_RST IMX_GPIO_NR(4, 15)
#define CAN_NCS IMX_GPIO_NR(4, 24)
-#define CAN_RXOBF IMX_GPIO_NR(1, 4)
+#define CAN_RXOBF_REV2 IMX_GPIO_NR(1, 4)
+#define CAN_RXOBF_REV3 IMX_GPIO_NR(3, 12)
#define CAN_RX1BF IMX_GPIO_NR(1, 6)
#define CAN_TXORTS IMX_GPIO_NR(1, 7)
#define CAN_TX1RTS IMX_GPIO_NR(1, 8)
@@ -90,6 +92,10 @@ static iomux_v3_cfg_t eukrea_cpuimx51sd_pads[] = {
MX51_PAD_I2C1_CLK__GPIO4_16,
MX51_PAD_I2C1_DAT__GPIO4_17,
+ /* I2C1 */
+ MX51_PAD_SD2_CMD__I2C1_SCL,
+ MX51_PAD_SD2_CLK__I2C1_SDA,
+
/* CAN */
MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI,
MX51_PAD_CSPI1_MISO__ECSPI1_MISO,
@@ -108,15 +114,27 @@ static iomux_v3_cfg_t eukrea_cpuimx51sd_pads[] = {
NEW_PAD_CTRL(MX51_PAD_GPIO_NAND__GPIO_NAND, PAD_CTL_PUS_22K_UP |
PAD_CTL_PKE | PAD_CTL_SRE_FAST |
PAD_CTL_DSE_HIGH | PAD_CTL_PUE | PAD_CTL_HYS),
+ NEW_PAD_CTRL(MX51_PAD_NANDF_D8__GPIO4_0, PAD_CTL_PUS_22K_UP |
+ PAD_CTL_PKE | PAD_CTL_SRE_FAST |
+ PAD_CTL_DSE_HIGH | PAD_CTL_PUE | PAD_CTL_HYS),
};
static const struct imxuart_platform_data uart_pdata __initconst = {
.flags = IMXUART_HAVE_RTSCTS,
};
+static int tsc2007_get_pendown_state(void)
+{
+ if (mx51_revision() < IMX_CHIP_REVISION_3_0)
+ return !gpio_get_value(TSC2007_IRQGPIO_REV2);
+ else
+ return !gpio_get_value(TSC2007_IRQGPIO_REV3);
+}
+
static struct tsc2007_platform_data tsc2007_info = {
.model = 2007,
.x_plate_ohms = 180,
+ .get_pendown_state = tsc2007_get_pendown_state,
};
static struct i2c_board_info eukrea_cpuimx51sd_i2c_devices[] = {
@@ -126,7 +144,6 @@ static struct i2c_board_info eukrea_cpuimx51sd_i2c_devices[] = {
I2C_BOARD_INFO("tsc2007", 0x49),
.type = "tsc2007",
.platform_data = &tsc2007_info,
- .irq = IMX_GPIO_TO_IRQ(TSC2007_IRQGPIO),
},
};
@@ -255,10 +272,14 @@ static const struct spi_imx_master cpuimx51sd_ecspi1_pdata __initconst = {
.num_chipselect = ARRAY_SIZE(cpuimx51sd_spi1_cs),
};
-static struct platform_device *platform_devices[] __initdata = {
+static struct platform_device *rev2_platform_devices[] __initdata = {
&hsi2c_gpio_device,
};
+static const struct imxi2c_platform_data cpuimx51sd_i2c_data __initconst = {
+ .bitrate = 100000,
+};
+
static void __init eukrea_cpuimx51sd_init(void)
{
imx51_soc_init();
@@ -272,6 +293,7 @@ static void __init eukrea_cpuimx51sd_init(void)
imx51_add_imx_uart(0, &uart_pdata);
imx51_add_mxc_nand(&eukrea_cpuimx51sd_nand_board_info);
+ imx51_add_imx2_wdt(0, NULL);
gpio_request(ETH_RST, "eth_rst");
gpio_set_value(ETH_RST, 1);
@@ -291,13 +313,25 @@ static void __init eukrea_cpuimx51sd_init(void)
spi_register_board_info(cpuimx51sd_spi_device,
ARRAY_SIZE(cpuimx51sd_spi_device));
- gpio_request(TSC2007_IRQGPIO, "tsc2007_irq");
- gpio_direction_input(TSC2007_IRQGPIO);
- gpio_free(TSC2007_IRQGPIO);
+ if (mx51_revision() < IMX_CHIP_REVISION_3_0) {
+ eukrea_cpuimx51sd_i2c_devices[1].irq =
+ gpio_to_irq(TSC2007_IRQGPIO_REV2),
+ platform_add_devices(rev2_platform_devices,
+ ARRAY_SIZE(rev2_platform_devices));
+ gpio_request(TSC2007_IRQGPIO_REV2, "tsc2007_irq");
+ gpio_direction_input(TSC2007_IRQGPIO_REV2);
+ gpio_free(TSC2007_IRQGPIO_REV2);
+ } else {
+ eukrea_cpuimx51sd_i2c_devices[1].irq =
+ gpio_to_irq(TSC2007_IRQGPIO_REV3),
+ imx51_add_imx_i2c(0, &cpuimx51sd_i2c_data);
+ gpio_request(TSC2007_IRQGPIO_REV3, "tsc2007_irq");
+ gpio_direction_input(TSC2007_IRQGPIO_REV3);
+ gpio_free(TSC2007_IRQGPIO_REV3);
+ }
i2c_register_board_info(0, eukrea_cpuimx51sd_i2c_devices,
ARRAY_SIZE(eukrea_cpuimx51sd_i2c_devices));
- platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
if (otg_mode_host)
imx51_add_mxc_ehci_otg(&dr_utmi_config);
diff --git a/arch/arm/mach-imx/mach-eukrea_cpuimx25.c b/arch/arm/mach-imx/mach-eukrea_cpuimx25.c
index 76a97a598b9e..d1e04e676e33 100644
--- a/arch/arm/mach-imx/mach-eukrea_cpuimx25.c
+++ b/arch/arm/mach-imx/mach-eukrea_cpuimx25.c
@@ -106,6 +106,7 @@ static const struct mxc_usbh_platform_data usbh2_pdata __initconst = {
static const struct fsl_usb2_platform_data otg_device_pdata __initconst = {
.operating_mode = FSL_USB2_DR_DEVICE,
.phy_mode = FSL_USB2_PHY_UTMI,
+ .workaround = FLS_USB2_WORKAROUND_ENGCM09152,
};
static int otg_mode_host;
@@ -135,6 +136,7 @@ static void __init eukrea_cpuimx25_init(void)
imx25_add_mxc_nand(&eukrea_cpuimx25_nand_board_info);
imx25_add_imxdi_rtc(NULL);
imx25_add_fec(&mx25_fec_pdata);
+ imx25_add_imx2_wdt(NULL);
i2c_register_board_info(0, eukrea_cpuimx25_i2c_devices,
ARRAY_SIZE(eukrea_cpuimx25_i2c_devices));
diff --git a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
index f7b074f496f0..dff82eb57cd9 100644
--- a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
+++ b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
@@ -38,6 +38,7 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
+#include <asm/system.h>
#include <mach/common.h>
#include <mach/iomux-mx27.h>
@@ -48,6 +49,14 @@
#define OTG_PHY_CS_GPIO (GPIO_PORTF + 17)
#define SDHC1_IRQ IRQ_GPIOB(25)
+#define MOTHERBOARD_BIT2 (GPIO_PORTD + 31)
+#define MOTHERBOARD_BIT1 (GPIO_PORTD + 30)
+#define MOTHERBOARD_BIT0 (GPIO_PORTD + 29)
+
+#define EXPBOARD_BIT2 (GPIO_PORTD + 25)
+#define EXPBOARD_BIT1 (GPIO_PORTD + 27)
+#define EXPBOARD_BIT0 (GPIO_PORTD + 28)
+
static const int visstrim_m10_pins[] __initconst = {
/* UART1 (console) */
PE12_PF_UART1_TXD,
@@ -119,6 +128,23 @@ static const int visstrim_m10_pins[] __initconst = {
PB19_PF_CSI_D7,
PB20_PF_CSI_VSYNC,
PB21_PF_CSI_HSYNC,
+ /* mother board version */
+ MOTHERBOARD_BIT2 | GPIO_GPIO | GPIO_IN | GPIO_PUEN,
+ MOTHERBOARD_BIT1 | GPIO_GPIO | GPIO_IN | GPIO_PUEN,
+ MOTHERBOARD_BIT0 | GPIO_GPIO | GPIO_IN | GPIO_PUEN,
+ /* expansion board version */
+ EXPBOARD_BIT2 | GPIO_GPIO | GPIO_IN | GPIO_PUEN,
+ EXPBOARD_BIT1 | GPIO_GPIO | GPIO_IN | GPIO_PUEN,
+ EXPBOARD_BIT0 | GPIO_GPIO | GPIO_IN | GPIO_PUEN,
+};
+
+static struct gpio visstrim_m10_version_gpios[] = {
+ { EXPBOARD_BIT0, GPIOF_IN, "exp-version-0" },
+ { EXPBOARD_BIT1, GPIOF_IN, "exp-version-1" },
+ { EXPBOARD_BIT2, GPIOF_IN, "exp-version-2" },
+ { MOTHERBOARD_BIT0, GPIOF_IN, "mother-version-0" },
+ { MOTHERBOARD_BIT1, GPIOF_IN, "mother-version-1" },
+ { MOTHERBOARD_BIT2, GPIOF_IN, "mother-version-2" },
};
/* Camera */
@@ -152,7 +178,7 @@ static struct soc_camera_link iclink_tvp5150 = {
static struct mx2_camera_platform_data visstrim_camera = {
.flags = MX2_CAMERA_CCIR | MX2_CAMERA_CCIR_INTERLACE |
- MX2_CAMERA_SWAP16 | MX2_CAMERA_PCLK_SAMPLE_RISING,
+ MX2_CAMERA_PCLK_SAMPLE_RISING,
.clk = 100000,
};
@@ -369,11 +395,40 @@ static const struct imx_ssi_platform_data visstrim_m10_ssi_pdata __initconst = {
.flags = IMX_SSI_DMA | IMX_SSI_SYN,
};
+static void __init visstrim_m10_revision(void)
+{
+ int exp_version = 0;
+ int mo_version = 0;
+ int ret;
+
+ ret = gpio_request_array(visstrim_m10_version_gpios,
+ ARRAY_SIZE(visstrim_m10_version_gpios));
+ if (ret) {
+ pr_err("Failed to request version gpios");
+ return;
+ }
+
+ /* Get expansion board version (negative logic) */
+ exp_version |= !gpio_get_value(EXPBOARD_BIT2) << 2;
+ exp_version |= !gpio_get_value(EXPBOARD_BIT1) << 1;
+ exp_version |= !gpio_get_value(EXPBOARD_BIT0);
+
+ /* Get mother board version (negative logic) */
+ mo_version |= !gpio_get_value(MOTHERBOARD_BIT2) << 2;
+ mo_version |= !gpio_get_value(MOTHERBOARD_BIT1) << 1;
+ mo_version |= !gpio_get_value(MOTHERBOARD_BIT0);
+
+ system_rev = 0x27000;
+ system_rev |= (mo_version << 4);
+ system_rev |= exp_version;
+}
+
static void __init visstrim_m10_board_init(void)
{
int ret;
imx27_soc_init();
+ visstrim_m10_revision();
ret = mxc_gpio_setup_multiple_pins(visstrim_m10_pins,
ARRAY_SIZE(visstrim_m10_pins), "VISSTRIM_M10");
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index da6c1d9af768..3df360a52c17 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -19,6 +19,7 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include <linux/pinctrl/machine.h>
#include <linux/phy.h>
#include <linux/micrel_phy.h>
#include <asm/smp_twd.h>
@@ -77,6 +78,12 @@ static int ksz9021rn_phy_fixup(struct phy_device *phydev)
static void __init imx6q_init_machine(void)
{
+ /*
+ * This should be removed when all imx6q boards have pinctrl
+ * states for devices defined in device tree.
+ */
+ pinctrl_provide_dummies();
+
if (of_machine_is_compatible("fsl,imx6q-sabrelite"))
phy_register_fixup_for_uid(PHY_ID_KSZ9021, MICREL_PHY_ID_MASK,
ksz9021rn_phy_fixup);
diff --git a/arch/arm/mach-imx/mach-mx1ads.c b/arch/arm/mach-imx/mach-mx1ads.c
index 97046088ff1a..7274e7928136 100644
--- a/arch/arm/mach-imx/mach-mx1ads.c
+++ b/arch/arm/mach-imx/mach-mx1ads.c
@@ -134,7 +134,7 @@ static void __init mx1ads_timer_init(void)
mx1_clocks_init(32000);
}
-struct sys_timer mx1ads_timer = {
+static struct sys_timer mx1ads_timer = {
.init = mx1ads_timer_init,
};
diff --git a/arch/arm/mach-imx/mach-mx21ads.c b/arch/arm/mach-imx/mach-mx21ads.c
index e432d4acee1f..d14bbe949a4f 100644
--- a/arch/arm/mach-imx/mach-mx21ads.c
+++ b/arch/arm/mach-imx/mach-mx21ads.c
@@ -304,8 +304,7 @@ static void __init mx21ads_board_init(void)
imx21_add_mxc_nand(&mx21ads_nand_board_info);
platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
- platform_device_register_full(
- (struct platform_device_info *)&mx21ads_cs8900_devinfo);
+ platform_device_register_full(&mx21ads_cs8900_devinfo);
}
static void __init mx21ads_timer_init(void)
diff --git a/arch/arm/mach-imx/mach-mx31_3ds.c b/arch/arm/mach-imx/mach-mx31_3ds.c
index 4d1aab154400..4eafdf275ea2 100644
--- a/arch/arm/mach-imx/mach-mx31_3ds.c
+++ b/arch/arm/mach-imx/mach-mx31_3ds.c
@@ -156,6 +156,11 @@ static int mx31_3ds_pins[] = {
MX31_PIN_CSI_VSYNC__CSI_VSYNC,
MX31_PIN_CSI_D5__GPIO3_5, /* CMOS PWDN */
IOMUX_MODE(MX31_PIN_RI_DTE1, IOMUX_CONFIG_GPIO), /* CMOS reset */
+ /* SSI */
+ MX31_PIN_STXD4__STXD4,
+ MX31_PIN_SRXD4__SRXD4,
+ MX31_PIN_SCK4__SCK4,
+ MX31_PIN_SFS4__SFS4,
};
/*
@@ -488,12 +493,23 @@ static struct mc13xxx_regulator_init_data mx31_3ds_regulators[] = {
};
/* MC13783 */
+static struct mc13xxx_codec_platform_data mx31_3ds_codec = {
+ .dac_ssi_port = MC13783_SSI1_PORT,
+ .adc_ssi_port = MC13783_SSI1_PORT,
+};
+
static struct mc13xxx_platform_data mc13783_pdata = {
.regulators = {
.regulators = mx31_3ds_regulators,
.num_regulators = ARRAY_SIZE(mx31_3ds_regulators),
},
- .flags = MC13XXX_USE_TOUCHSCREEN | MC13XXX_USE_RTC,
+ .codec = &mx31_3ds_codec,
+ .flags = MC13XXX_USE_TOUCHSCREEN | MC13XXX_USE_RTC | MC13XXX_USE_CODEC,
+
+};
+
+static struct imx_ssi_platform_data mx31_3ds_ssi_pdata = {
+ .flags = IMX_SSI_DMA | IMX_SSI_NET,
};
/* SPI */
@@ -741,6 +757,10 @@ static void __init mx31_3ds_init(void)
}
mx31_3ds_init_camera();
+
+ imx31_add_imx_ssi(0, &mx31_3ds_ssi_pdata);
+
+ imx_add_platform_device("imx_mc13783", 0, NULL, 0, NULL, 0);
}
static void __init mx31_3ds_timer_init(void)
diff --git a/arch/arm/mach-imx/mach-mx31lite.c b/arch/arm/mach-imx/mach-mx31lite.c
index 0abef5f13df5..686c60587980 100644
--- a/arch/arm/mach-imx/mach-mx31lite.c
+++ b/arch/arm/mach-imx/mach-mx31lite.c
@@ -283,7 +283,7 @@ static void __init mx31lite_timer_init(void)
mx31_clocks_init(26000000);
}
-struct sys_timer mx31lite_timer = {
+static struct sys_timer mx31lite_timer = {
.init = mx31lite_timer_init,
};
diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c
index f17a15f28316..016791f038b0 100644
--- a/arch/arm/mach-imx/mach-mx31moboard.c
+++ b/arch/arm/mach-imx/mach-mx31moboard.c
@@ -47,6 +47,7 @@
#include <mach/hardware.h>
#include <mach/iomux-mx3.h>
#include <mach/ulpi.h>
+#include <mach/ssi.h>
#include "devices-imx31.h"
@@ -102,6 +103,9 @@ static unsigned int moboard_pins[] = {
MX31_PIN_CSPI3_MOSI__MOSI, MX31_PIN_CSPI3_MISO__MISO,
MX31_PIN_CSPI3_SCLK__SCLK, MX31_PIN_CSPI3_SPI_RDY__SPI_RDY,
MX31_PIN_CSPI2_SS1__CSPI3_SS1,
+ /* SSI */
+ MX31_PIN_STXD4__STXD4, MX31_PIN_SRXD4__SRXD4,
+ MX31_PIN_SCK4__SCK4, MX31_PIN_SFS4__SFS4,
};
static struct physmap_flash_data mx31moboard_flash_data = {
@@ -276,6 +280,11 @@ static struct mc13xxx_buttons_platform_data moboard_buttons = {
.b1on_key = KEY_POWER,
};
+static struct mc13xxx_codec_platform_data moboard_codec = {
+ .dac_ssi_port = MC13783_SSI1_PORT,
+ .adc_ssi_port = MC13783_SSI1_PORT,
+};
+
static struct mc13xxx_platform_data moboard_pmic = {
.regulators = {
.regulators = moboard_regulators,
@@ -283,7 +292,12 @@ static struct mc13xxx_platform_data moboard_pmic = {
},
.leds = &moboard_leds,
.buttons = &moboard_buttons,
- .flags = MC13XXX_USE_RTC | MC13XXX_USE_ADC,
+ .codec = &moboard_codec,
+ .flags = MC13XXX_USE_RTC | MC13XXX_USE_ADC | MC13XXX_USE_CODEC,
+};
+
+static struct imx_ssi_platform_data moboard_ssi_pdata = {
+ .flags = IMX_SSI_DMA | IMX_SSI_NET,
};
static struct spi_board_info moboard_spi_board_info[] __initdata = {
@@ -554,6 +568,10 @@ static void __init mx31moboard_init(void)
moboard_usbh2_init();
+ imx31_add_imx_ssi(0, &moboard_ssi_pdata);
+
+ imx_add_platform_device("imx_mc13783", 0, NULL, 0, NULL, 0);
+
pm_power_off = mx31moboard_poweroff;
switch (mx31moboard_baseboard) {
@@ -580,7 +598,7 @@ static void __init mx31moboard_timer_init(void)
mx31_clocks_init(26000000);
}
-struct sys_timer mx31moboard_timer = {
+static struct sys_timer mx31moboard_timer = {
.init = mx31moboard_timer_init,
};
diff --git a/arch/arm/mach-imx/mach-mx35_3ds.c b/arch/arm/mach-imx/mach-mx35_3ds.c
index 6ae51c6b95b7..28aa19476de7 100644
--- a/arch/arm/mach-imx/mach-mx35_3ds.c
+++ b/arch/arm/mach-imx/mach-mx35_3ds.c
@@ -34,6 +34,8 @@
#include <linux/usb/otg.h>
#include <linux/mtd/physmap.h>
+#include <linux/mfd/mc13892.h>
+#include <linux/regulator/machine.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -96,8 +98,7 @@ static struct i2c_board_info __initdata i2c_devices_3ds[] = {
static int lcd_power_gpio = -ENXIO;
-static int mc9s08dz60_gpiochip_match(struct gpio_chip *chip,
- const void *data)
+static int mc9s08dz60_gpiochip_match(struct gpio_chip *chip, void *data)
{
return !strcmp(chip->label, data);
}
@@ -253,6 +254,8 @@ static iomux_v3_cfg_t mx35pdk_pads[] = {
MX35_PAD_CSI_MCLK__IPU_CSI_MCLK,
MX35_PAD_CSI_PIXCLK__IPU_CSI_PIXCLK,
MX35_PAD_CSI_VSYNC__IPU_CSI_VSYNC,
+ /*PMIC IRQ*/
+ MX35_PAD_GPIO2_0__GPIO2_0,
};
/*
@@ -317,6 +320,193 @@ static struct platform_device mx35_3ds_ov2640 = {
},
};
+static struct regulator_consumer_supply sw1_consumers[] = {
+ {
+ .supply = "cpu_vcc",
+ }
+};
+
+static struct regulator_consumer_supply vcam_consumers[] = {
+ /* sgtl5000 */
+ REGULATOR_SUPPLY("VDDA", "0-000a"),
+};
+
+static struct regulator_consumer_supply vaudio_consumers[] = {
+ REGULATOR_SUPPLY("cmos_vio", "soc-camera-pdrv.0"),
+};
+
+static struct regulator_init_data sw1_init = {
+ .constraints = {
+ .name = "SW1",
+ .min_uV = 600000,
+ .max_uV = 1375000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .valid_modes_mask = 0,
+ .always_on = 1,
+ .boot_on = 1,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(sw1_consumers),
+ .consumer_supplies = sw1_consumers,
+};
+
+static struct regulator_init_data sw2_init = {
+ .constraints = {
+ .name = "SW2",
+ .always_on = 1,
+ .boot_on = 1,
+ }
+};
+
+static struct regulator_init_data sw3_init = {
+ .constraints = {
+ .name = "SW3",
+ .always_on = 1,
+ .boot_on = 1,
+ }
+};
+
+static struct regulator_init_data sw4_init = {
+ .constraints = {
+ .name = "SW4",
+ .always_on = 1,
+ .boot_on = 1,
+ }
+};
+
+static struct regulator_init_data viohi_init = {
+ .constraints = {
+ .name = "VIOHI",
+ .boot_on = 1,
+ }
+};
+
+static struct regulator_init_data vusb_init = {
+ .constraints = {
+ .name = "VUSB",
+ .boot_on = 1,
+ }
+};
+
+static struct regulator_init_data vdig_init = {
+ .constraints = {
+ .name = "VDIG",
+ .boot_on = 1,
+ }
+};
+
+static struct regulator_init_data vpll_init = {
+ .constraints = {
+ .name = "VPLL",
+ .boot_on = 1,
+ }
+};
+
+static struct regulator_init_data vusb2_init = {
+ .constraints = {
+ .name = "VUSB2",
+ .boot_on = 1,
+ }
+};
+
+static struct regulator_init_data vvideo_init = {
+ .constraints = {
+ .name = "VVIDEO",
+ .boot_on = 1
+ }
+};
+
+static struct regulator_init_data vaudio_init = {
+ .constraints = {
+ .name = "VAUDIO",
+ .min_uV = 2300000,
+ .max_uV = 3000000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .boot_on = 1
+ },
+ .num_consumer_supplies = ARRAY_SIZE(vaudio_consumers),
+ .consumer_supplies = vaudio_consumers,
+};
+
+static struct regulator_init_data vcam_init = {
+ .constraints = {
+ .name = "VCAM",
+ .min_uV = 2500000,
+ .max_uV = 3000000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE |
+ REGULATOR_CHANGE_MODE,
+ .valid_modes_mask = REGULATOR_MODE_FAST | REGULATOR_MODE_NORMAL,
+ .boot_on = 1
+ },
+ .num_consumer_supplies = ARRAY_SIZE(vcam_consumers),
+ .consumer_supplies = vcam_consumers,
+};
+
+static struct regulator_init_data vgen1_init = {
+ .constraints = {
+ .name = "VGEN1",
+ }
+};
+
+static struct regulator_init_data vgen2_init = {
+ .constraints = {
+ .name = "VGEN2",
+ .boot_on = 1,
+ }
+};
+
+static struct regulator_init_data vgen3_init = {
+ .constraints = {
+ .name = "VGEN3",
+ }
+};
+
+static struct mc13xxx_regulator_init_data mx35_3ds_regulators[] = {
+ { .id = MC13892_SW1, .init_data = &sw1_init },
+ { .id = MC13892_SW2, .init_data = &sw2_init },
+ { .id = MC13892_SW3, .init_data = &sw3_init },
+ { .id = MC13892_SW4, .init_data = &sw4_init },
+ { .id = MC13892_VIOHI, .init_data = &viohi_init },
+ { .id = MC13892_VPLL, .init_data = &vpll_init },
+ { .id = MC13892_VDIG, .init_data = &vdig_init },
+ { .id = MC13892_VUSB2, .init_data = &vusb2_init },
+ { .id = MC13892_VVIDEO, .init_data = &vvideo_init },
+ { .id = MC13892_VAUDIO, .init_data = &vaudio_init },
+ { .id = MC13892_VCAM, .init_data = &vcam_init },
+ { .id = MC13892_VGEN1, .init_data = &vgen1_init },
+ { .id = MC13892_VGEN2, .init_data = &vgen2_init },
+ { .id = MC13892_VGEN3, .init_data = &vgen3_init },
+ { .id = MC13892_VUSB, .init_data = &vusb_init },
+};
+
+static struct mc13xxx_platform_data mx35_3ds_mc13892_data = {
+ .flags = MC13XXX_USE_RTC | MC13XXX_USE_TOUCHSCREEN,
+ .regulators = {
+ .num_regulators = ARRAY_SIZE(mx35_3ds_regulators),
+ .regulators = mx35_3ds_regulators,
+ },
+};
+
+#define GPIO_PMIC_INT IMX_GPIO_NR(2, 0)
+
+static struct i2c_board_info mx35_3ds_i2c_mc13892 = {
+
+ I2C_BOARD_INFO("mc13892", 0x08),
+ .platform_data = &mx35_3ds_mc13892_data,
+ .irq = IMX_GPIO_TO_IRQ(GPIO_PMIC_INT),
+};
+
+static void __init imx35_3ds_init_mc13892(void)
+{
+ int ret = gpio_request_one(GPIO_PMIC_INT, GPIOF_DIR_IN, "pmic irq");
+
+ if (ret) {
+ pr_err("failed to get pmic irq: %d\n", ret);
+ return;
+ }
+
+ i2c_register_board_info(0, &mx35_3ds_i2c_mc13892, 1);
+}
+
static int mx35_3ds_otg_init(struct platform_device *pdev)
{
return mx35_initialize_usb_hw(pdev->id, MXC_EHCI_INTERNAL_PHY);
@@ -412,6 +602,8 @@ static void __init mx35_3ds_init(void)
imx35_fb_pdev = imx35_add_mx3_sdc_fb(&mx3fb_pdata);
mx35_3ds_lcd.dev.parent = &imx35_fb_pdev->dev;
platform_device_register(&mx35_3ds_lcd);
+
+ imx35_3ds_init_mc13892();
}
static void __init mx35pdk_timer_init(void)
@@ -419,7 +611,7 @@ static void __init mx35pdk_timer_init(void)
mx35_clocks_init();
}
-struct sys_timer mx35pdk_timer = {
+static struct sys_timer mx35pdk_timer = {
.init = mx35pdk_timer_init,
};
diff --git a/arch/arm/mach-imx/mach-mx51_efikamx.c b/arch/arm/mach-imx/mach-mx51_efikamx.c
index 586e9f822124..86e96ef11f9d 100644
--- a/arch/arm/mach-imx/mach-mx51_efikamx.c
+++ b/arch/arm/mach-imx/mach-mx51_efikamx.c
@@ -284,8 +284,7 @@ static struct sys_timer mx51_efikamx_timer = {
.init = mx51_efikamx_timer_init,
};
-MACHINE_START(MX51_EFIKAMX, "Genesi EfikaMX nettop")
- /* Maintainer: Amit Kucheria <amit.kucheria@linaro.org> */
+MACHINE_START(MX51_EFIKAMX, "Genesi Efika MX (Smarttop)")
.atag_offset = 0x100,
.map_io = mx51_map_io,
.init_early = imx51_init_early,
diff --git a/arch/arm/mach-imx/mach-mx51_efikasb.c b/arch/arm/mach-imx/mach-mx51_efikasb.c
index 24aded9e109f..88f837a6cc76 100644
--- a/arch/arm/mach-imx/mach-mx51_efikasb.c
+++ b/arch/arm/mach-imx/mach-mx51_efikasb.c
@@ -280,7 +280,7 @@ static struct sys_timer mx51_efikasb_timer = {
.init = mx51_efikasb_timer_init,
};
-MACHINE_START(MX51_EFIKASB, "Genesi Efika Smartbook")
+MACHINE_START(MX51_EFIKASB, "Genesi Efika MX (Smartbook)")
.atag_offset = 0x100,
.map_io = mx51_map_io,
.init_early = imx51_init_early,
diff --git a/arch/arm/mach-imx/mach-pcm037.c b/arch/arm/mach-imx/mach-pcm037.c
index 5fddf94cc969..10c9795934a3 100644
--- a/arch/arm/mach-imx/mach-pcm037.c
+++ b/arch/arm/mach-imx/mach-pcm037.c
@@ -683,7 +683,7 @@ static void __init pcm037_timer_init(void)
mx31_clocks_init(26000000);
}
-struct sys_timer pcm037_timer = {
+static struct sys_timer pcm037_timer = {
.init = pcm037_timer_init,
};
diff --git a/arch/arm/mach-imx/mach-pcm043.c b/arch/arm/mach-imx/mach-pcm043.c
index 237474fcca23..73585f55cca0 100644
--- a/arch/arm/mach-imx/mach-pcm043.c
+++ b/arch/arm/mach-imx/mach-pcm043.c
@@ -399,7 +399,7 @@ static void __init pcm043_timer_init(void)
mx35_clocks_init();
}
-struct sys_timer pcm043_timer = {
+static struct sys_timer pcm043_timer = {
.init = pcm043_timer_init,
};
diff --git a/arch/arm/mach-imx/mach-vpr200.c b/arch/arm/mach-imx/mach-vpr200.c
index 033257e553ef..add8c69c6c1a 100644
--- a/arch/arm/mach-imx/mach-vpr200.c
+++ b/arch/arm/mach-imx/mach-vpr200.c
@@ -310,7 +310,7 @@ static void __init vpr200_timer_init(void)
mx35_clocks_init();
}
-struct sys_timer vpr200_timer = {
+static struct sys_timer vpr200_timer = {
.init = vpr200_timer_init,
};
diff --git a/arch/arm/mach-imx/mm-imx1.c b/arch/arm/mach-imx/mm-imx1.c
index 2bded591d5c2..fcafd3dafb8c 100644
--- a/arch/arm/mach-imx/mm-imx1.c
+++ b/arch/arm/mach-imx/mm-imx1.c
@@ -18,6 +18,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/pinctrl/machine.h>
#include <asm/mach/map.h>
@@ -58,4 +59,5 @@ void __init imx1_soc_init(void)
MX1_GPIO_INT_PORTC, 0);
mxc_register_gpio("imx1-gpio", 3, MX1_GPIO4_BASE_ADDR, SZ_256,
MX1_GPIO_INT_PORTD, 0);
+ pinctrl_provide_dummies();
}
diff --git a/arch/arm/mach-imx/mm-imx21.c b/arch/arm/mach-imx/mm-imx21.c
index 14d540edfd1e..5f43905e5290 100644
--- a/arch/arm/mach-imx/mm-imx21.c
+++ b/arch/arm/mach-imx/mm-imx21.c
@@ -20,6 +20,7 @@
#include <linux/mm.h>
#include <linux/init.h>
+#include <linux/pinctrl/machine.h>
#include <mach/hardware.h>
#include <mach/common.h>
#include <mach/devices-common.h>
@@ -88,6 +89,7 @@ void __init imx21_soc_init(void)
mxc_register_gpio("imx21-gpio", 4, MX21_GPIO5_BASE_ADDR, SZ_256, MX21_INT_GPIO, 0);
mxc_register_gpio("imx21-gpio", 5, MX21_GPIO6_BASE_ADDR, SZ_256, MX21_INT_GPIO, 0);
+ pinctrl_provide_dummies();
imx_add_imx_dma();
platform_device_register_simple("imx21-audmux", 0, imx21_audmux_res,
ARRAY_SIZE(imx21_audmux_res));
diff --git a/arch/arm/mach-imx/mm-imx25.c b/arch/arm/mach-imx/mm-imx25.c
index 153b457acdc0..6ff37140a4f8 100644
--- a/arch/arm/mach-imx/mm-imx25.c
+++ b/arch/arm/mach-imx/mm-imx25.c
@@ -19,6 +19,7 @@
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/err.h>
+#include <linux/pinctrl/machine.h>
#include <asm/pgtable.h>
#include <asm/mach/map.h>
@@ -95,6 +96,7 @@ void __init imx25_soc_init(void)
mxc_register_gpio("imx31-gpio", 2, MX25_GPIO3_BASE_ADDR, SZ_16K, MX25_INT_GPIO3, 0);
mxc_register_gpio("imx31-gpio", 3, MX25_GPIO4_BASE_ADDR, SZ_16K, MX25_INT_GPIO4, 0);
+ pinctrl_provide_dummies();
/* i.mx25 has the i.mx35 type sdma */
imx_add_imx_sdma("imx35-sdma", MX25_SDMA_BASE_ADDR, MX25_INT_SDMA, &imx25_sdma_pdata);
/* i.mx25 has the i.mx31 type audmux */
diff --git a/arch/arm/mach-imx/mm-imx27.c b/arch/arm/mach-imx/mm-imx27.c
index 8cb3f5e3e569..25662558e018 100644
--- a/arch/arm/mach-imx/mm-imx27.c
+++ b/arch/arm/mach-imx/mm-imx27.c
@@ -20,6 +20,7 @@
#include <linux/mm.h>
#include <linux/init.h>
+#include <linux/pinctrl/machine.h>
#include <mach/hardware.h>
#include <mach/common.h>
#include <mach/devices-common.h>
@@ -89,6 +90,7 @@ void __init imx27_soc_init(void)
mxc_register_gpio("imx21-gpio", 4, MX27_GPIO5_BASE_ADDR, SZ_256, MX27_INT_GPIO, 0);
mxc_register_gpio("imx21-gpio", 5, MX27_GPIO6_BASE_ADDR, SZ_256, MX27_INT_GPIO, 0);
+ pinctrl_provide_dummies();
imx_add_imx_dma();
/* imx27 has the imx21 type audmux */
platform_device_register_simple("imx21-audmux", 0, imx27_audmux_res,
diff --git a/arch/arm/mach-imx/mm-imx3.c b/arch/arm/mach-imx/mm-imx3.c
index 74127389e7ab..9128d15b1eb7 100644
--- a/arch/arm/mach-imx/mm-imx3.c
+++ b/arch/arm/mach-imx/mm-imx3.c
@@ -19,6 +19,7 @@
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/err.h>
+#include <linux/pinctrl/machine.h>
#include <asm/pgtable.h>
#include <asm/system_misc.h>
@@ -267,6 +268,7 @@ void __init imx35_soc_init(void)
mxc_register_gpio("imx31-gpio", 1, MX35_GPIO2_BASE_ADDR, SZ_16K, MX35_INT_GPIO2, 0);
mxc_register_gpio("imx31-gpio", 2, MX35_GPIO3_BASE_ADDR, SZ_16K, MX35_INT_GPIO3, 0);
+ pinctrl_provide_dummies();
if (to_version == 1) {
strncpy(imx35_sdma_pdata.fw_name, "sdma-imx35-to1.bin",
strlen(imx35_sdma_pdata.fw_name));
diff --git a/arch/arm/mach-imx/mm-imx5.c b/arch/arm/mach-imx/mm-imx5.c
index e10f3914fcfe..ba91e6b31cf4 100644
--- a/arch/arm/mach-imx/mm-imx5.c
+++ b/arch/arm/mach-imx/mm-imx5.c
@@ -14,6 +14,7 @@
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/clk.h>
+#include <linux/pinctrl/machine.h>
#include <asm/system_misc.h>
#include <asm/mach/map.h>
@@ -223,6 +224,7 @@ void __init imx53_soc_init(void)
mxc_register_gpio("imx31-gpio", 5, MX53_GPIO6_BASE_ADDR, SZ_16K, MX53_INT_GPIO6_LOW, MX53_INT_GPIO6_HIGH);
mxc_register_gpio("imx31-gpio", 6, MX53_GPIO7_BASE_ADDR, SZ_16K, MX53_INT_GPIO7_LOW, MX53_INT_GPIO7_HIGH);
+ pinctrl_provide_dummies();
/* i.mx53 has the i.mx35 type sdma */
imx_add_imx_sdma("imx35-sdma", MX53_SDMA_BASE_ADDR, MX53_INT_SDMA, &imx53_sdma_pdata);
diff --git a/arch/arm/mach-ixp2000/Kconfig b/arch/arm/mach-ixp2000/Kconfig
deleted file mode 100644
index 08d2707f6ca8..000000000000
--- a/arch/arm/mach-ixp2000/Kconfig
+++ /dev/null
@@ -1,72 +0,0 @@
-
-if ARCH_IXP2000
-
-config ARCH_SUPPORTS_BIG_ENDIAN
- bool
- default y
-
-menu "Intel IXP2400/2800 Implementation Options"
-
-comment "IXP2400/2800 Platforms"
-
-config ARCH_ENP2611
- bool "Support Radisys ENP-2611"
- help
- Say 'Y' here if you want your kernel to support the Radisys
- ENP2611 PCI network processing card. For more information on
- this card, see <file:Documentation/arm/IXP2000>.
-
-config ARCH_IXDP2400
- bool "Support Intel IXDP2400"
- help
- Say 'Y' here if you want your kernel to support the Intel
- IXDP2400 reference platform. For more information on
- this platform, see <file:Documentation/arm/IXP2000>.
-
-config ARCH_IXDP2800
- bool "Support Intel IXDP2800"
- help
- Say 'Y' here if you want your kernel to support the Intel
- IXDP2800 reference platform. For more information on
- this platform, see <file:Documentation/arm/IXP2000>.
-
-config ARCH_IXDP2X00
- bool
- depends on ARCH_IXDP2400 || ARCH_IXDP2800
- default y
-
-config ARCH_IXDP2401
- bool "Support Intel IXDP2401"
- help
- Say 'Y' here if you want your kernel to support the Intel
- IXDP2401 reference platform. For more information on
- this platform, see <file:Documentation/arm/IXP2000>.
-
-config ARCH_IXDP2801
- bool "Support Intel IXDP2801 and IXDP28x5"
- help
- Say 'Y' here if you want your kernel to support the Intel
- IXDP2801/2805/2855 reference platforms. For more information on
- this platform, see <file:Documentation/arm/IXP2000>.
-
-config MACH_IXDP28X5
- bool
- depends on ARCH_IXDP2801
- default y
-
-config ARCH_IXDP2X01
- bool
- depends on ARCH_IXDP2401 || ARCH_IXDP2801
- default y
-
-config IXP2000_SUPPORT_BROKEN_PCI_IO
- bool "Support broken PCI I/O on older IXP2000s"
- default y
- help
- Say 'N' here if you only intend to run your kernel on an
- IXP2000 B0 or later model and do not need the PCI I/O
- byteswap workaround. Say 'Y' otherwise.
-
-endmenu
-
-endif
diff --git a/arch/arm/mach-ixp2000/Makefile b/arch/arm/mach-ixp2000/Makefile
deleted file mode 100644
index 1e6139d42a92..000000000000
--- a/arch/arm/mach-ixp2000/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-obj-y := core.o pci.o
-obj-m :=
-obj-n :=
-obj- :=
-
-obj-$(CONFIG_ARCH_ENP2611) += enp2611.o
-obj-$(CONFIG_ARCH_IXDP2400) += ixdp2400.o
-obj-$(CONFIG_ARCH_IXDP2800) += ixdp2800.o
-obj-$(CONFIG_ARCH_IXDP2X00) += ixdp2x00.o
-obj-$(CONFIG_ARCH_IXDP2X01) += ixdp2x01.o
-
diff --git a/arch/arm/mach-ixp2000/Makefile.boot b/arch/arm/mach-ixp2000/Makefile.boot
deleted file mode 100644
index 9c7af91d93da..000000000000
--- a/arch/arm/mach-ixp2000/Makefile.boot
+++ /dev/null
@@ -1,3 +0,0 @@
- zreladdr-y += 0x00008000
-params_phys-y := 0x00000100
-
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
deleted file mode 100644
index f214cdff01cb..000000000000
--- a/arch/arm/mach-ixp2000/core.c
+++ /dev/null
@@ -1,520 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/core.c
- *
- * Common routines used by all IXP2400/2800 based platforms.
- *
- * Author: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright 2004 (C) MontaVista Software, Inc.
- *
- * Based on work Copyright (C) 2002-2003 Intel Corporation
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-#include <linux/gpio.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/bitops.h>
-#include <linux/serial_8250.h>
-#include <linux/mm.h>
-#include <linux/export.h>
-
-#include <asm/types.h>
-#include <asm/setup.h>
-#include <asm/memory.h>
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/tlbflush.h>
-#include <asm/pgtable.h>
-
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
-#include <asm/mach/irq.h>
-
-#include <mach/gpio-ixp2000.h>
-
-static DEFINE_SPINLOCK(ixp2000_slowport_lock);
-static unsigned long ixp2000_slowport_irq_flags;
-
-/*************************************************************************
- * Slowport access routines
- *************************************************************************/
-void ixp2000_acquire_slowport(struct slowport_cfg *new_cfg, struct slowport_cfg *old_cfg)
-{
- spin_lock_irqsave(&ixp2000_slowport_lock, ixp2000_slowport_irq_flags);
-
- old_cfg->CCR = *IXP2000_SLOWPORT_CCR;
- old_cfg->WTC = *IXP2000_SLOWPORT_WTC2;
- old_cfg->RTC = *IXP2000_SLOWPORT_RTC2;
- old_cfg->PCR = *IXP2000_SLOWPORT_PCR;
- old_cfg->ADC = *IXP2000_SLOWPORT_ADC;
-
- ixp2000_reg_write(IXP2000_SLOWPORT_CCR, new_cfg->CCR);
- ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, new_cfg->WTC);
- ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, new_cfg->RTC);
- ixp2000_reg_write(IXP2000_SLOWPORT_PCR, new_cfg->PCR);
- ixp2000_reg_wrb(IXP2000_SLOWPORT_ADC, new_cfg->ADC);
-}
-
-void ixp2000_release_slowport(struct slowport_cfg *old_cfg)
-{
- ixp2000_reg_write(IXP2000_SLOWPORT_CCR, old_cfg->CCR);
- ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, old_cfg->WTC);
- ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, old_cfg->RTC);
- ixp2000_reg_write(IXP2000_SLOWPORT_PCR, old_cfg->PCR);
- ixp2000_reg_wrb(IXP2000_SLOWPORT_ADC, old_cfg->ADC);
-
- spin_unlock_irqrestore(&ixp2000_slowport_lock,
- ixp2000_slowport_irq_flags);
-}
-
-/*************************************************************************
- * Chip specific mappings shared by all IXP2000 systems
- *************************************************************************/
-static struct map_desc ixp2000_io_desc[] __initdata = {
- {
- .virtual = IXP2000_CAP_VIRT_BASE,
- .pfn = __phys_to_pfn(IXP2000_CAP_PHYS_BASE),
- .length = IXP2000_CAP_SIZE,
- .type = MT_DEVICE,
- }, {
- .virtual = IXP2000_INTCTL_VIRT_BASE,
- .pfn = __phys_to_pfn(IXP2000_INTCTL_PHYS_BASE),
- .length = IXP2000_INTCTL_SIZE,
- .type = MT_DEVICE,
- }, {
- .virtual = IXP2000_PCI_CREG_VIRT_BASE,
- .pfn = __phys_to_pfn(IXP2000_PCI_CREG_PHYS_BASE),
- .length = IXP2000_PCI_CREG_SIZE,
- .type = MT_DEVICE,
- }, {
- .virtual = IXP2000_PCI_CSR_VIRT_BASE,
- .pfn = __phys_to_pfn(IXP2000_PCI_CSR_PHYS_BASE),
- .length = IXP2000_PCI_CSR_SIZE,
- .type = MT_DEVICE,
- }, {
- .virtual = IXP2000_MSF_VIRT_BASE,
- .pfn = __phys_to_pfn(IXP2000_MSF_PHYS_BASE),
- .length = IXP2000_MSF_SIZE,
- .type = MT_DEVICE,
- }, {
- .virtual = IXP2000_SCRATCH_RING_VIRT_BASE,
- .pfn = __phys_to_pfn(IXP2000_SCRATCH_RING_PHYS_BASE),
- .length = IXP2000_SCRATCH_RING_SIZE,
- .type = MT_DEVICE,
- }, {
- .virtual = IXP2000_SRAM0_VIRT_BASE,
- .pfn = __phys_to_pfn(IXP2000_SRAM0_PHYS_BASE),
- .length = IXP2000_SRAM0_SIZE,
- .type = MT_DEVICE,
- }, {
- .virtual = IXP2000_PCI_IO_VIRT_BASE,
- .pfn = __phys_to_pfn(IXP2000_PCI_IO_PHYS_BASE),
- .length = IXP2000_PCI_IO_SIZE,
- .type = MT_DEVICE,
- }, {
- .virtual = IXP2000_PCI_CFG0_VIRT_BASE,
- .pfn = __phys_to_pfn(IXP2000_PCI_CFG0_PHYS_BASE),
- .length = IXP2000_PCI_CFG0_SIZE,
- .type = MT_DEVICE,
- }, {
- .virtual = IXP2000_PCI_CFG1_VIRT_BASE,
- .pfn = __phys_to_pfn(IXP2000_PCI_CFG1_PHYS_BASE),
- .length = IXP2000_PCI_CFG1_SIZE,
- .type = MT_DEVICE,
- }
-};
-
-void __init ixp2000_map_io(void)
-{
- iotable_init(ixp2000_io_desc, ARRAY_SIZE(ixp2000_io_desc));
-
- /* Set slowport to 8-bit mode. */
- ixp2000_reg_wrb(IXP2000_SLOWPORT_FRM, 1);
-}
-
-
-/*************************************************************************
- * Serial port support for IXP2000
- *************************************************************************/
-static struct plat_serial8250_port ixp2000_serial_port[] = {
- {
- .mapbase = IXP2000_UART_PHYS_BASE,
- .membase = (char *)(IXP2000_UART_VIRT_BASE + 3),
- .irq = IRQ_IXP2000_UART,
- .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = 50000000,
- },
- { },
-};
-
-static struct resource ixp2000_uart_resource = {
- .start = IXP2000_UART_PHYS_BASE,
- .end = IXP2000_UART_PHYS_BASE + 0x1f,
- .flags = IORESOURCE_MEM,
-};
-
-static struct platform_device ixp2000_serial_device = {
- .name = "serial8250",
- .id = PLAT8250_DEV_PLATFORM,
- .dev = {
- .platform_data = ixp2000_serial_port,
- },
- .num_resources = 1,
- .resource = &ixp2000_uart_resource,
-};
-
-void __init ixp2000_uart_init(void)
-{
- platform_device_register(&ixp2000_serial_device);
-}
-
-
-/*************************************************************************
- * Timer-tick functions for IXP2000
- *************************************************************************/
-static unsigned ticks_per_jiffy;
-static unsigned ticks_per_usec;
-static unsigned next_jiffy_time;
-static volatile unsigned long *missing_jiffy_timer_csr;
-
-unsigned long ixp2000_gettimeoffset (void)
-{
- unsigned long offset;
-
- offset = next_jiffy_time - *missing_jiffy_timer_csr;
-
- return offset / ticks_per_usec;
-}
-
-static irqreturn_t ixp2000_timer_interrupt(int irq, void *dev_id)
-{
- /* clear timer 1 */
- ixp2000_reg_wrb(IXP2000_T1_CLR, 1);
-
- while ((signed long)(next_jiffy_time - *missing_jiffy_timer_csr)
- >= ticks_per_jiffy) {
- timer_tick();
- next_jiffy_time -= ticks_per_jiffy;
- }
-
- return IRQ_HANDLED;
-}
-
-static struct irqaction ixp2000_timer_irq = {
- .name = "IXP2000 Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
- .handler = ixp2000_timer_interrupt,
-};
-
-void __init ixp2000_init_time(unsigned long tick_rate)
-{
- ticks_per_jiffy = (tick_rate + HZ/2) / HZ;
- ticks_per_usec = tick_rate / 1000000;
-
- /*
- * We use timer 1 as our timer interrupt.
- */
- ixp2000_reg_write(IXP2000_T1_CLR, 0);
- ixp2000_reg_write(IXP2000_T1_CLD, ticks_per_jiffy - 1);
- ixp2000_reg_write(IXP2000_T1_CTL, (1 << 7));
-
- /*
- * We use a second timer as a monotonic counter for tracking
- * missed jiffies. The IXP2000 has four timers, but if we're
- * on an A-step IXP2800, timer 2 and 3 don't work, so on those
- * chips we use timer 4. Timer 4 is the only timer that can
- * be used for the watchdog, so we use timer 2 if we're on a
- * non-buggy chip.
- */
- if ((*IXP2000_PRODUCT_ID & 0x001ffef0) == 0x00000000) {
- printk(KERN_INFO "Enabling IXP2800 erratum #25 workaround\n");
-
- ixp2000_reg_write(IXP2000_T4_CLR, 0);
- ixp2000_reg_write(IXP2000_T4_CLD, -1);
- ixp2000_reg_wrb(IXP2000_T4_CTL, (1 << 7));
- missing_jiffy_timer_csr = IXP2000_T4_CSR;
- } else {
- ixp2000_reg_write(IXP2000_T2_CLR, 0);
- ixp2000_reg_write(IXP2000_T2_CLD, -1);
- ixp2000_reg_wrb(IXP2000_T2_CTL, (1 << 7));
- missing_jiffy_timer_csr = IXP2000_T2_CSR;
- }
- next_jiffy_time = 0xffffffff;
-
- /* register for interrupt */
- setup_irq(IRQ_IXP2000_TIMER1, &ixp2000_timer_irq);
-}
-
-/*************************************************************************
- * GPIO helpers
- *************************************************************************/
-static unsigned long GPIO_IRQ_falling_edge;
-static unsigned long GPIO_IRQ_rising_edge;
-static unsigned long GPIO_IRQ_level_low;
-static unsigned long GPIO_IRQ_level_high;
-
-static void update_gpio_int_csrs(void)
-{
- ixp2000_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge);
- ixp2000_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge);
- ixp2000_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low);
- ixp2000_reg_wrb(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high);
-}
-
-void gpio_line_config(int line, int direction)
-{
- unsigned long flags;
-
- local_irq_save(flags);
- if (direction == GPIO_OUT) {
- /* if it's an output, it ain't an interrupt anymore */
- GPIO_IRQ_falling_edge &= ~(1 << line);
- GPIO_IRQ_rising_edge &= ~(1 << line);
- GPIO_IRQ_level_low &= ~(1 << line);
- GPIO_IRQ_level_high &= ~(1 << line);
- update_gpio_int_csrs();
-
- ixp2000_reg_wrb(IXP2000_GPIO_PDSR, 1 << line);
- } else if (direction == GPIO_IN) {
- ixp2000_reg_wrb(IXP2000_GPIO_PDCR, 1 << line);
- }
- local_irq_restore(flags);
-}
-EXPORT_SYMBOL(gpio_line_config);
-
-
-/*************************************************************************
- * IRQ handling IXP2000
- *************************************************************************/
-static void ixp2000_GPIO_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
- int i;
- unsigned long status = *IXP2000_GPIO_INST;
-
- for (i = 0; i <= 7; i++) {
- if (status & (1<<i)) {
- generic_handle_irq(i + IRQ_IXP2000_GPIO0);
- }
- }
-}
-
-static int ixp2000_GPIO_irq_type(struct irq_data *d, unsigned int type)
-{
- int line = d->irq - IRQ_IXP2000_GPIO0;
-
- /*
- * First, configure this GPIO line as an input.
- */
- ixp2000_reg_write(IXP2000_GPIO_PDCR, 1 << line);
-
- /*
- * Then, set the proper trigger type.
- */
- if (type & IRQ_TYPE_EDGE_FALLING)
- GPIO_IRQ_falling_edge |= 1 << line;
- else
- GPIO_IRQ_falling_edge &= ~(1 << line);
- if (type & IRQ_TYPE_EDGE_RISING)
- GPIO_IRQ_rising_edge |= 1 << line;
- else
- GPIO_IRQ_rising_edge &= ~(1 << line);
- if (type & IRQ_TYPE_LEVEL_LOW)
- GPIO_IRQ_level_low |= 1 << line;
- else
- GPIO_IRQ_level_low &= ~(1 << line);
- if (type & IRQ_TYPE_LEVEL_HIGH)
- GPIO_IRQ_level_high |= 1 << line;
- else
- GPIO_IRQ_level_high &= ~(1 << line);
- update_gpio_int_csrs();
-
- return 0;
-}
-
-static void ixp2000_GPIO_irq_mask_ack(struct irq_data *d)
-{
- unsigned int irq = d->irq;
-
- ixp2000_reg_write(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0)));
-
- ixp2000_reg_write(IXP2000_GPIO_EDSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
- ixp2000_reg_write(IXP2000_GPIO_LDSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
- ixp2000_reg_wrb(IXP2000_GPIO_INST, (1 << (irq - IRQ_IXP2000_GPIO0)));
-}
-
-static void ixp2000_GPIO_irq_mask(struct irq_data *d)
-{
- unsigned int irq = d->irq;
-
- ixp2000_reg_wrb(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0)));
-}
-
-static void ixp2000_GPIO_irq_unmask(struct irq_data *d)
-{
- unsigned int irq = d->irq;
-
- ixp2000_reg_write(IXP2000_GPIO_INSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
-}
-
-static struct irq_chip ixp2000_GPIO_irq_chip = {
- .irq_ack = ixp2000_GPIO_irq_mask_ack,
- .irq_mask = ixp2000_GPIO_irq_mask,
- .irq_unmask = ixp2000_GPIO_irq_unmask,
- .irq_set_type = ixp2000_GPIO_irq_type,
-};
-
-static void ixp2000_pci_irq_mask(struct irq_data *d)
-{
- unsigned long temp = *IXP2000_PCI_XSCALE_INT_ENABLE;
- if (d->irq == IRQ_IXP2000_PCIA)
- ixp2000_reg_wrb(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 26)));
- else if (d->irq == IRQ_IXP2000_PCIB)
- ixp2000_reg_wrb(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 27)));
-}
-
-static void ixp2000_pci_irq_unmask(struct irq_data *d)
-{
- unsigned long temp = *IXP2000_PCI_XSCALE_INT_ENABLE;
- if (d->irq == IRQ_IXP2000_PCIA)
- ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp | (1 << 26)));
- else if (d->irq == IRQ_IXP2000_PCIB)
- ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp | (1 << 27)));
-}
-
-/*
- * Error interrupts. These are used extensively by the microengine drivers
- */
-static void ixp2000_err_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
- int i;
- unsigned long status = *IXP2000_IRQ_ERR_STATUS;
-
- for(i = 31; i >= 0; i--) {
- if(status & (1 << i)) {
- generic_handle_irq(IRQ_IXP2000_DRAM0_MIN_ERR + i);
- }
- }
-}
-
-static void ixp2000_err_irq_mask(struct irq_data *d)
-{
- ixp2000_reg_write(IXP2000_IRQ_ERR_ENABLE_CLR,
- (1 << (d->irq - IRQ_IXP2000_DRAM0_MIN_ERR)));
-}
-
-static void ixp2000_err_irq_unmask(struct irq_data *d)
-{
- ixp2000_reg_write(IXP2000_IRQ_ERR_ENABLE_SET,
- (1 << (d->irq - IRQ_IXP2000_DRAM0_MIN_ERR)));
-}
-
-static struct irq_chip ixp2000_err_irq_chip = {
- .irq_ack = ixp2000_err_irq_mask,
- .irq_mask = ixp2000_err_irq_mask,
- .irq_unmask = ixp2000_err_irq_unmask
-};
-
-static struct irq_chip ixp2000_pci_irq_chip = {
- .irq_ack = ixp2000_pci_irq_mask,
- .irq_mask = ixp2000_pci_irq_mask,
- .irq_unmask = ixp2000_pci_irq_unmask
-};
-
-static void ixp2000_irq_mask(struct irq_data *d)
-{
- ixp2000_reg_wrb(IXP2000_IRQ_ENABLE_CLR, (1 << d->irq));
-}
-
-static void ixp2000_irq_unmask(struct irq_data *d)
-{
- ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << d->irq));
-}
-
-static struct irq_chip ixp2000_irq_chip = {
- .irq_ack = ixp2000_irq_mask,
- .irq_mask = ixp2000_irq_mask,
- .irq_unmask = ixp2000_irq_unmask
-};
-
-void __init ixp2000_init_irq(void)
-{
- int irq;
-
- /*
- * Mask all sources
- */
- ixp2000_reg_write(IXP2000_IRQ_ENABLE_CLR, 0xffffffff);
- ixp2000_reg_write(IXP2000_FIQ_ENABLE_CLR, 0xffffffff);
-
- /* clear all GPIO edge/level detects */
- ixp2000_reg_write(IXP2000_GPIO_REDR, 0);
- ixp2000_reg_write(IXP2000_GPIO_FEDR, 0);
- ixp2000_reg_write(IXP2000_GPIO_LSHR, 0);
- ixp2000_reg_write(IXP2000_GPIO_LSLR, 0);
- ixp2000_reg_write(IXP2000_GPIO_INCR, -1);
-
- /* clear PCI interrupt sources */
- ixp2000_reg_wrb(IXP2000_PCI_XSCALE_INT_ENABLE, 0);
-
- /*
- * Certain bits in the IRQ status register of the
- * IXP2000 are reserved. Instead of trying to map
- * things non 1:1 from bit position to IRQ number,
- * we mark the reserved IRQs as invalid. This makes
- * our mask/unmask code much simpler.
- */
- for (irq = IRQ_IXP2000_SOFT_INT; irq <= IRQ_IXP2000_THDB3; irq++) {
- if ((1 << irq) & IXP2000_VALID_IRQ_MASK) {
- irq_set_chip_and_handler(irq, &ixp2000_irq_chip,
- handle_level_irq);
- set_irq_flags(irq, IRQF_VALID);
- } else set_irq_flags(irq, 0);
- }
-
- for (irq = IRQ_IXP2000_DRAM0_MIN_ERR; irq <= IRQ_IXP2000_SP_INT; irq++) {
- if((1 << (irq - IRQ_IXP2000_DRAM0_MIN_ERR)) &
- IXP2000_VALID_ERR_IRQ_MASK) {
- irq_set_chip_and_handler(irq, &ixp2000_err_irq_chip,
- handle_level_irq);
- set_irq_flags(irq, IRQF_VALID);
- }
- else
- set_irq_flags(irq, 0);
- }
- irq_set_chained_handler(IRQ_IXP2000_ERRSUM, ixp2000_err_irq_handler);
-
- for (irq = IRQ_IXP2000_GPIO0; irq <= IRQ_IXP2000_GPIO7; irq++) {
- irq_set_chip_and_handler(irq, &ixp2000_GPIO_irq_chip,
- handle_level_irq);
- set_irq_flags(irq, IRQF_VALID);
- }
- irq_set_chained_handler(IRQ_IXP2000_GPIO, ixp2000_GPIO_irq_handler);
-
- /*
- * Enable PCI irqs. The actual PCI[AB] decoding is done in
- * entry-macro.S, so we don't need a chained handler for the
- * PCI interrupt source.
- */
- ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << IRQ_IXP2000_PCI));
- for (irq = IRQ_IXP2000_PCIA; irq <= IRQ_IXP2000_PCIB; irq++) {
- irq_set_chip_and_handler(irq, &ixp2000_pci_irq_chip,
- handle_level_irq);
- set_irq_flags(irq, IRQF_VALID);
- }
-}
-
-void ixp2000_restart(char mode, const char *cmd)
-{
- ixp2000_reg_wrb(IXP2000_RESET0, RSTALL);
-}
diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c
deleted file mode 100644
index 73df2f688813..000000000000
--- a/arch/arm/mach-ixp2000/enp2611.c
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/enp2611.c
- *
- * Radisys ENP-2611 support.
- *
- * Created 2004 by Lennert Buytenhek from the ixdp2x01 code. The
- * original version carries the following notices:
- *
- * Original Author: Andrzej Mialkowski <andrzej.mialkowski@intel.com>
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (C) 2002-2003 Intel Corp.
- * Copyright (C) 2003-2004 MontaVista Software, 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/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/bitops.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-
-#include <asm/mach/pci.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/time.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
-
-/*************************************************************************
- * ENP-2611 timer tick configuration
- *************************************************************************/
-static void __init enp2611_timer_init(void)
-{
- ixp2000_init_time(50 * 1000 * 1000);
-}
-
-static struct sys_timer enp2611_timer = {
- .init = enp2611_timer_init,
- .offset = ixp2000_gettimeoffset,
-};
-
-
-/*************************************************************************
- * ENP-2611 I/O
- *************************************************************************/
-static struct map_desc enp2611_io_desc[] __initdata = {
- {
- .virtual = ENP2611_CALEB_VIRT_BASE,
- .pfn = __phys_to_pfn(ENP2611_CALEB_PHYS_BASE),
- .length = ENP2611_CALEB_SIZE,
- .type = MT_DEVICE,
- }, {
- .virtual = ENP2611_PM3386_0_VIRT_BASE,
- .pfn = __phys_to_pfn(ENP2611_PM3386_0_PHYS_BASE),
- .length = ENP2611_PM3386_0_SIZE,
- .type = MT_DEVICE,
- }, {
- .virtual = ENP2611_PM3386_1_VIRT_BASE,
- .pfn = __phys_to_pfn(ENP2611_PM3386_1_PHYS_BASE),
- .length = ENP2611_PM3386_1_SIZE,
- .type = MT_DEVICE,
- }
-};
-
-void __init enp2611_map_io(void)
-{
- ixp2000_map_io();
- iotable_init(enp2611_io_desc, ARRAY_SIZE(enp2611_io_desc));
-}
-
-
-/*************************************************************************
- * ENP-2611 PCI
- *************************************************************************/
-static int enp2611_pci_setup(int nr, struct pci_sys_data *sys)
-{
- sys->mem_offset = 0xe0000000;
- ixp2000_pci_setup(nr, sys);
- return 1;
-}
-
-static void __init enp2611_pci_preinit(void)
-{
- ixp2000_reg_write(IXP2000_PCI_ADDR_EXT, 0x00100000);
- ixp2000_pci_preinit();
- pcibios_setup("firmware");
-}
-
-static inline int enp2611_pci_valid_device(struct pci_bus *bus,
- unsigned int devfn)
-{
- /* The 82559 ethernet controller appears at both PCI:1:0:0 and
- * PCI:1:2:0, so let's pretend the second one isn't there.
- */
- if (bus->number == 0x01 && devfn == 0x10)
- return 0;
-
- return 1;
-}
-
-static int enp2611_pci_read_config(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 *value)
-{
- if (enp2611_pci_valid_device(bus, devfn))
- return ixp2000_pci_read_config(bus, devfn, where, size, value);
-
- return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-static int enp2611_pci_write_config(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 value)
-{
- if (enp2611_pci_valid_device(bus, devfn))
- return ixp2000_pci_write_config(bus, devfn, where, size, value);
-
- return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-static struct pci_ops enp2611_pci_ops = {
- .read = enp2611_pci_read_config,
- .write = enp2611_pci_write_config
-};
-
-static int __init enp2611_pci_map_irq(const struct pci_dev *dev, u8 slot,
- u8 pin)
-{
- int irq;
-
- if (dev->bus->number == 0 && PCI_SLOT(dev->devfn) == 0) {
- /* IXP2400. */
- irq = IRQ_IXP2000_PCIA;
- } else if (dev->bus->number == 0 && PCI_SLOT(dev->devfn) == 1) {
- /* 21555 non-transparent bridge. */
- irq = IRQ_IXP2000_PCIB;
- } else if (dev->bus->number == 0 && PCI_SLOT(dev->devfn) == 4) {
- /* PCI2050B transparent bridge. */
- irq = -1;
- } else if (dev->bus->number == 1 && PCI_SLOT(dev->devfn) == 0) {
- /* 82559 ethernet. */
- irq = IRQ_IXP2000_PCIA;
- } else if (dev->bus->number == 1 && PCI_SLOT(dev->devfn) == 1) {
- /* SPI-3 option board. */
- irq = IRQ_IXP2000_PCIB;
- } else {
- printk(KERN_ERR "enp2611_pci_map_irq() called for unknown "
- "device PCI:%d:%d:%d\n", dev->bus->number,
- PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
- irq = -1;
- }
-
- return irq;
-}
-
-struct hw_pci enp2611_pci __initdata = {
- .nr_controllers = 1,
- .ops = &enp2611_pci_ops,
- .setup = enp2611_pci_setup,
- .preinit = enp2611_pci_preinit,
- .map_irq = enp2611_pci_map_irq,
-};
-
-int __init enp2611_pci_init(void)
-{
- if (machine_is_enp2611())
- pci_common_init(&enp2611_pci);
-
- return 0;
-}
-
-subsys_initcall(enp2611_pci_init);
-
-
-/*************************************************************************
- * ENP-2611 Machine Initialization
- *************************************************************************/
-static struct flash_platform_data enp2611_flash_platform_data = {
- .map_name = "cfi_probe",
- .width = 1,
-};
-
-static struct ixp2000_flash_data enp2611_flash_data = {
- .platform_data = &enp2611_flash_platform_data,
- .nr_banks = 1
-};
-
-static struct resource enp2611_flash_resource = {
- .start = 0xc4000000,
- .end = 0xc4000000 + 0x00ffffff,
- .flags = IORESOURCE_MEM,
-};
-
-static struct platform_device enp2611_flash = {
- .name = "IXP2000-Flash",
- .id = 0,
- .dev = {
- .platform_data = &enp2611_flash_data,
- },
- .num_resources = 1,
- .resource = &enp2611_flash_resource,
-};
-
-static struct ixp2000_i2c_pins enp2611_i2c_gpio_pins = {
- .sda_pin = ENP2611_GPIO_SDA,
- .scl_pin = ENP2611_GPIO_SCL,
-};
-
-static struct platform_device enp2611_i2c_controller = {
- .name = "IXP2000-I2C",
- .id = 0,
- .dev = {
- .platform_data = &enp2611_i2c_gpio_pins
- },
- .num_resources = 0
-};
-
-static struct platform_device *enp2611_devices[] __initdata = {
- &enp2611_flash,
- &enp2611_i2c_controller
-};
-
-static void __init enp2611_init_machine(void)
-{
- platform_add_devices(enp2611_devices, ARRAY_SIZE(enp2611_devices));
- ixp2000_uart_init();
-}
-
-
-MACHINE_START(ENP2611, "Radisys ENP-2611 PCI network processor board")
- /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
- .atag_offset = 0x100,
- .map_io = enp2611_map_io,
- .init_irq = ixp2000_init_irq,
- .timer = &enp2611_timer,
- .init_machine = enp2611_init_machine,
- .restart = ixp2000_restart,
-MACHINE_END
-
-
diff --git a/arch/arm/mach-ixp2000/include/mach/debug-macro.S b/arch/arm/mach-ixp2000/include/mach/debug-macro.S
deleted file mode 100644
index bdd3ccdc2890..000000000000
--- a/arch/arm/mach-ixp2000/include/mach/debug-macro.S
+++ /dev/null
@@ -1,25 +0,0 @@
-/* arch/arm/mach-ixp2000/include/mach/debug-macro.S
- *
- * Debugging macro include header
- *
- * Copyright (C) 1994-1999 Russell King
- * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * 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.
- *
-*/
-
- .macro addruart, rp, rv, tmp
- mov \rp, #0x00030000
-#ifdef __ARMEB__
- orr \rp, \rp, #0x00000003
-#endif
- orr \rv, \rp, #0xfe000000 @ virtual base
- orr \rv, \rv, #0x00f00000
- orr \rp, \rp, #0xc0000000 @ Physical base
- .endm
-
-#define UART_SHIFT 2
-#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-ixp2000/include/mach/enp2611.h b/arch/arm/mach-ixp2000/include/mach/enp2611.h
deleted file mode 100644
index 9ce3690061d5..000000000000
--- a/arch/arm/mach-ixp2000/include/mach/enp2611.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/enp2611.h
- *
- * Register and other defines for Radisys ENP-2611
- *
- * Created 2004 by Lennert Buytenhek from the ixdp2x01 code. The
- * original version carries the following notices:
- *
- * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (C) 2002 Intel Corp.
- * Copyright (C) 2003-2004 MontaVista Software, 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.
- */
-
-#ifndef __ENP2611_H
-#define __ENP2611_H
-
-#define ENP2611_CALEB_PHYS_BASE 0xc5000000
-#define ENP2611_CALEB_VIRT_BASE 0xfe000000
-#define ENP2611_CALEB_SIZE 0x00100000
-
-#define ENP2611_PM3386_0_PHYS_BASE 0xc6000000
-#define ENP2611_PM3386_0_VIRT_BASE 0xfe100000
-#define ENP2611_PM3386_0_SIZE 0x00100000
-
-#define ENP2611_PM3386_1_PHYS_BASE 0xc6400000
-#define ENP2611_PM3386_1_VIRT_BASE 0xfe200000
-#define ENP2611_PM3386_1_SIZE 0x00100000
-
-#define ENP2611_GPIO_SCL 7
-#define ENP2611_GPIO_SDA 6
-
-#define IRQ_ENP2611_THERMAL IRQ_IXP2000_GPIO4
-#define IRQ_ENP2611_OPTION_BOARD IRQ_IXP2000_GPIO3
-#define IRQ_ENP2611_CALEB IRQ_IXP2000_GPIO2
-#define IRQ_ENP2611_PM3386_1 IRQ_IXP2000_GPIO1
-#define IRQ_ENP2611_PM3386_0 IRQ_IXP2000_GPIO0
-
-
-#endif
diff --git a/arch/arm/mach-ixp2000/include/mach/entry-macro.S b/arch/arm/mach-ixp2000/include/mach/entry-macro.S
deleted file mode 100644
index c4444dff9202..000000000000
--- a/arch/arm/mach-ixp2000/include/mach/entry-macro.S
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/entry-macro.S
- *
- * Low-level IRQ helper macros for IXP2000-based platforms
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-#include <mach/irqs.h>
-
- .macro get_irqnr_preamble, base, tmp
- .endm
-
- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
-
- mov \irqnr, #0x0 @clear out irqnr as default
- mov \base, #0xfe000000
- orr \base, \base, #0x00e00000
- orr \base, \base, #0x08
- ldr \irqstat, [\base] @ get interrupts
-
- cmp \irqstat, #0
- beq 1001f
-
- clz \irqnr, \irqstat
- mov \base, #31
- subs \irqnr, \base, \irqnr
-
- /*
- * We handle PCIA and PCIB here so we don't have an
- * extra layer of code just to check these two bits.
- */
- cmp \irqnr, #IRQ_IXP2000_PCI
- bne 1001f
-
- mov \base, #0xfe000000
- orr \base, \base, #0x00c00000
- orr \base, \base, #0x00000100
- orr \base, \base, #0x00000058
- ldr \irqstat, [\base]
-
- mov \tmp, #(1<<26)
- tst \irqstat, \tmp
- movne \irqnr, #IRQ_IXP2000_PCIA
- bne 1001f
-
- mov \tmp, #(1<<27)
- tst \irqstat, \tmp
- movne \irqnr, #IRQ_IXP2000_PCIB
-
-1001:
- .endm
-
diff --git a/arch/arm/mach-ixp2000/include/mach/gpio-ixp2000.h b/arch/arm/mach-ixp2000/include/mach/gpio-ixp2000.h
deleted file mode 100644
index af836c76c3f1..000000000000
--- a/arch/arm/mach-ixp2000/include/mach/gpio-ixp2000.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/gpio.h
- *
- * Copyright (C) 2002 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.
- */
-
-/*
- * IXP2000 GPIO in/out, edge/level detection for IRQs:
- * IRQs are generated on Falling-edge, Rising-Edge, Level-low, Level-High
- * or both Falling-edge and Rising-edge.
- * This must be called *before* the corresponding IRQ is registerd.
- * Use this instead of directly setting the GPIO registers.
- * GPIOs may also be used as GPIOs (e.g. for emulating i2c/smb)
- */
-#ifndef __ASM_ARCH_GPIO_H
-#define __ASM_ARCH_GPIO_H
-
-#ifndef __ASSEMBLY__
-
-#define GPIO_IN 0
-#define GPIO_OUT 1
-
-#define IXP2000_GPIO_LOW 0
-#define IXP2000_GPIO_HIGH 1
-
-extern void gpio_line_config(int line, int direction);
-
-static inline int gpio_line_get(int line)
-{
- return (((*IXP2000_GPIO_PLR) >> line) & 1);
-}
-
-static inline void gpio_line_set(int line, int value)
-{
- if (value == IXP2000_GPIO_HIGH) {
- ixp2000_reg_write(IXP2000_GPIO_POSR, 1 << line);
- } else if (value == IXP2000_GPIO_LOW) {
- ixp2000_reg_write(IXP2000_GPIO_POCR, 1 << line);
- }
-}
-
-#endif /* !__ASSEMBLY__ */
-
-#endif /* ASM_ARCH_IXP2000_GPIO_H_ */
diff --git a/arch/arm/mach-ixp2000/include/mach/hardware.h b/arch/arm/mach-ixp2000/include/mach/hardware.h
deleted file mode 100644
index cdaf1db84003..000000000000
--- a/arch/arm/mach-ixp2000/include/mach/hardware.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/hardware.h
- *
- * Hardware definitions for IXP2400/2800 based systems
- *
- * Original Author: Naeem M Afzal <naeem.m.afzal@intel.com>
- *
- * Maintainer: Deepak Saxena <dsaxena@mvista.com>
- *
- * Copyright (C) 2001-2002 Intel Corp.
- * Copyright (C) 2003-2004 MontaVista Software, 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.
- */
-
-#ifndef __ASM_ARCH_HARDWARE_H__
-#define __ASM_ARCH_HARDWARE_H__
-
-#include "ixp2000-regs.h" /* Chipset Registers */
-
-/*
- * Platform helper functions
- */
-#include "platform.h"
-
-/*
- * Platform-specific bits
- */
-#include "enp2611.h" /* ENP-2611 */
-#include "ixdp2x00.h" /* IXDP2400/2800 */
-#include "ixdp2x01.h" /* IXDP2401/2801 */
-
-#endif /* _ASM_ARCH_HARDWARE_H__ */
diff --git a/arch/arm/mach-ixp2000/include/mach/io.h b/arch/arm/mach-ixp2000/include/mach/io.h
deleted file mode 100644
index f6552d6f35ab..000000000000
--- a/arch/arm/mach-ixp2000/include/mach/io.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/io.h
- *
- * Original Author: Naeem M Afzal <naeem.m.afzal@intel.com>
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (C) 2002 Intel Corp.
- * Copyrgiht (C) 2003-2004 MontaVista Software, Inc.
- *
- * 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 __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#include <mach/hardware.h>
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-/*
- * The A? revisions of the IXP2000s assert byte lanes for PCI I/O
- * transactions the other way round (MEM transactions don't have this
- * issue), so if we want to support those models, we need to override
- * the standard I/O functions.
- *
- * B0 and later have a bit that can be set to 1 to get the proper
- * behavior for I/O transactions, which then allows us to use the
- * standard I/O functions. This is what we do if the user does not
- * explicitly ask for support for pre-B0.
- */
-#ifdef CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO
-#define ___io(p) ((void __iomem *)((p)+IXP2000_PCI_IO_VIRT_BASE))
-
-#define alignb(addr) (void __iomem *)((unsigned long)(addr) ^ 3)
-#define alignw(addr) (void __iomem *)((unsigned long)(addr) ^ 2)
-
-#define outb(v,p) __raw_writeb((v),alignb(___io(p)))
-#define outw(v,p) __raw_writew((v),alignw(___io(p)))
-#define outl(v,p) __raw_writel((v),___io(p))
-
-#define inb(p) ({ unsigned int __v = __raw_readb(alignb(___io(p))); __v; })
-#define inw(p) \
- ({ unsigned int __v = (__raw_readw(alignw(___io(p)))); __v; })
-#define inl(p) \
- ({ unsigned int __v = (__raw_readl(___io(p))); __v; })
-
-#define outsb(p,d,l) __raw_writesb(alignb(___io(p)),d,l)
-#define outsw(p,d,l) __raw_writesw(alignw(___io(p)),d,l)
-#define outsl(p,d,l) __raw_writesl(___io(p),d,l)
-
-#define insb(p,d,l) __raw_readsb(alignb(___io(p)),d,l)
-#define insw(p,d,l) __raw_readsw(alignw(___io(p)),d,l)
-#define insl(p,d,l) __raw_readsl(___io(p),d,l)
-
-#define __is_io_address(p) ((((unsigned long)(p)) & ~(IXP2000_PCI_IO_SIZE - 1)) == IXP2000_PCI_IO_VIRT_BASE)
-
-#define ioread8(p) \
- ({ \
- unsigned int __v; \
- \
- if (__is_io_address(p)) { \
- __v = __raw_readb(alignb(p)); \
- } else { \
- __v = __raw_readb(p); \
- } \
- \
- __v; \
- }) \
-
-#define ioread16(p) \
- ({ \
- unsigned int __v; \
- \
- if (__is_io_address(p)) { \
- __v = __raw_readw(alignw(p)); \
- } else { \
- __v = le16_to_cpu(__raw_readw(p)); \
- } \
- \
- __v; \
- })
-
-#define ioread32(p) \
- ({ \
- unsigned int __v; \
- \
- if (__is_io_address(p)) { \
- __v = __raw_readl(p); \
- } else { \
- __v = le32_to_cpu(__raw_readl(p)); \
- } \
- \
- __v; \
- })
-
-#define iowrite8(v,p) \
- ({ \
- if (__is_io_address(p)) { \
- __raw_writeb((v), alignb(p)); \
- } else { \
- __raw_writeb((v), p); \
- } \
- })
-
-#define iowrite16(v,p) \
- ({ \
- if (__is_io_address(p)) { \
- __raw_writew((v), alignw(p)); \
- } else { \
- __raw_writew(cpu_to_le16(v), p); \
- } \
- })
-
-#define iowrite32(v,p) \
- ({ \
- if (__is_io_address(p)) { \
- __raw_writel((v), p); \
- } else { \
- __raw_writel(cpu_to_le32(v), p); \
- } \
- })
-
-#define ioport_map(port, nr) ___io(port)
-
-#define ioport_unmap(addr)
-#else
-#define __io(p) ((void __iomem *)((p)+IXP2000_PCI_IO_VIRT_BASE))
-#endif
-
-
-#endif
diff --git a/arch/arm/mach-ixp2000/include/mach/irqs.h b/arch/arm/mach-ixp2000/include/mach/irqs.h
deleted file mode 100644
index bee96bcafdca..000000000000
--- a/arch/arm/mach-ixp2000/include/mach/irqs.h
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/irqs.h
- *
- * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (C) 2002 Intel Corp.
- * Copyright (C) 2003-2004 MontaVista Software, Inc.
- *
- * 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 _IRQS_H
-#define _IRQS_H
-
-/*
- * Do NOT add #ifdef MACHINE_FOO in here.
- * Simpy add your machine IRQs here and increase NR_IRQS if needed to
- * hold your machine's IRQ table.
- */
-
-/*
- * Some interrupt numbers go unused b/c the IRQ mask/ummask/status
- * register has those bit reserved. We just mark those interrupts
- * as invalid and this allows us to do mask/unmask with a single
- * shift operation instead of having to map the IRQ number to
- * a HW IRQ number.
- */
-#define IRQ_IXP2000_SOFT_INT 0 /* soft interrupt */
-#define IRQ_IXP2000_ERRSUM 1 /* OR of all bits in ErrorStatus reg*/
-#define IRQ_IXP2000_UART 2
-#define IRQ_IXP2000_GPIO 3
-#define IRQ_IXP2000_TIMER1 4
-#define IRQ_IXP2000_TIMER2 5
-#define IRQ_IXP2000_TIMER3 6
-#define IRQ_IXP2000_TIMER4 7
-#define IRQ_IXP2000_PMU 8
-#define IRQ_IXP2000_SPF 9 /* Slow port framer IRQ */
-#define IRQ_IXP2000_DMA1 10
-#define IRQ_IXP2000_DMA2 11
-#define IRQ_IXP2000_DMA3 12
-#define IRQ_IXP2000_PCI_DOORBELL 13
-#define IRQ_IXP2000_ME_ATTN 14
-#define IRQ_IXP2000_PCI 15 /* PCI INTA or INTB */
-#define IRQ_IXP2000_THDA0 16 /* thread 0-31A */
-#define IRQ_IXP2000_THDA1 17 /* thread 32-63A, IXP2800 only */
-#define IRQ_IXP2000_THDA2 18 /* thread 64-95A */
-#define IRQ_IXP2000_THDA3 19 /* thread 96-127A, IXP2800 only */
-#define IRQ_IXP2000_THDB0 24 /* thread 0-31B */
-#define IRQ_IXP2000_THDB1 25 /* thread 32-63B, IXP2800 only */
-#define IRQ_IXP2000_THDB2 26 /* thread 64-95B */
-#define IRQ_IXP2000_THDB3 27 /* thread 96-127B, IXP2800 only */
-
-/* define generic GPIOs */
-#define IRQ_IXP2000_GPIO0 32
-#define IRQ_IXP2000_GPIO1 33
-#define IRQ_IXP2000_GPIO2 34
-#define IRQ_IXP2000_GPIO3 35
-#define IRQ_IXP2000_GPIO4 36
-#define IRQ_IXP2000_GPIO5 37
-#define IRQ_IXP2000_GPIO6 38
-#define IRQ_IXP2000_GPIO7 39
-
-/* split off the 2 PCI sources */
-#define IRQ_IXP2000_PCIA 40
-#define IRQ_IXP2000_PCIB 41
-
-/* Int sources from IRQ_ERROR_STATUS */
-#define IRQ_IXP2000_DRAM0_MIN_ERR 42
-#define IRQ_IXP2000_DRAM0_MAJ_ERR 43
-#define IRQ_IXP2000_DRAM1_MIN_ERR 44
-#define IRQ_IXP2000_DRAM1_MAJ_ERR 45
-#define IRQ_IXP2000_DRAM2_MIN_ERR 46
-#define IRQ_IXP2000_DRAM2_MAJ_ERR 47
-/* 48-57 reserved */
-#define IRQ_IXP2000_SRAM0_ERR 58
-#define IRQ_IXP2000_SRAM1_ERR 59
-#define IRQ_IXP2000_SRAM2_ERR 60
-#define IRQ_IXP2000_SRAM3_ERR 61
-/* 62-65 reserved */
-#define IRQ_IXP2000_MEDIA_ERR 66
-#define IRQ_IXP2000_PCI_ERR 67
-#define IRQ_IXP2000_SP_INT 68
-
-#define NR_IXP2000_IRQS 69
-
-#define IXP2000_BOARD_IRQ(x) (NR_IXP2000_IRQS + (x))
-
-#define IXP2000_BOARD_IRQ_MASK(irq) (1 << (irq - NR_IXP2000_IRQS))
-
-#define IXP2000_ERR_IRQ_MASK(irq) ( 1 << (irq - IRQ_IXP2000_DRAM0_MIN_ERR))
-#define IXP2000_VALID_ERR_IRQ_MASK (\
- IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_DRAM0_MIN_ERR) | \
- IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_DRAM0_MAJ_ERR) | \
- IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_DRAM1_MIN_ERR) | \
- IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_DRAM1_MAJ_ERR) | \
- IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_DRAM2_MIN_ERR) | \
- IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_DRAM2_MAJ_ERR) | \
- IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_SRAM0_ERR) | \
- IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_SRAM1_ERR) | \
- IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_SRAM2_ERR) | \
- IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_SRAM3_ERR) | \
- IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_MEDIA_ERR) | \
- IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_PCI_ERR) | \
- IXP2000_ERR_IRQ_MASK(IRQ_IXP2000_SP_INT) )
-
-/*
- * This allows for all the on-chip sources plus up to 32 CPLD based
- * IRQs. Should be more than enough.
- */
-#define IXP2000_BOARD_IRQS 32
-#define NR_IRQS (NR_IXP2000_IRQS + IXP2000_BOARD_IRQS)
-
-
-/*
- * IXDP2400 specific IRQs
- */
-#define IRQ_IXDP2400_INGRESS_NPU IXP2000_BOARD_IRQ(0)
-#define IRQ_IXDP2400_ENET IXP2000_BOARD_IRQ(1)
-#define IRQ_IXDP2400_MEDIA_PCI IXP2000_BOARD_IRQ(2)
-#define IRQ_IXDP2400_MEDIA_SP IXP2000_BOARD_IRQ(3)
-#define IRQ_IXDP2400_SF_PCI IXP2000_BOARD_IRQ(4)
-#define IRQ_IXDP2400_SF_SP IXP2000_BOARD_IRQ(5)
-#define IRQ_IXDP2400_PMC IXP2000_BOARD_IRQ(6)
-#define IRQ_IXDP2400_TVM IXP2000_BOARD_IRQ(7)
-
-#define NR_IXDP2400_IRQS ((IRQ_IXDP2400_TVM)+1)
-#define IXDP2400_NR_IRQS NR_IXDP2400_IRQS - NR_IXP2000_IRQS
-
-/* IXDP2800 specific IRQs */
-#define IRQ_IXDP2800_EGRESS_ENET IXP2000_BOARD_IRQ(0)
-#define IRQ_IXDP2800_INGRESS_NPU IXP2000_BOARD_IRQ(1)
-#define IRQ_IXDP2800_PMC IXP2000_BOARD_IRQ(2)
-#define IRQ_IXDP2800_FABRIC_PCI IXP2000_BOARD_IRQ(3)
-#define IRQ_IXDP2800_FABRIC IXP2000_BOARD_IRQ(4)
-#define IRQ_IXDP2800_MEDIA IXP2000_BOARD_IRQ(5)
-
-#define NR_IXDP2800_IRQS ((IRQ_IXDP2800_MEDIA)+1)
-#define IXDP2800_NR_IRQS NR_IXDP2800_IRQS - NR_IXP2000_IRQS
-
-/*
- * IRQs on both IXDP2x01 boards
- */
-#define IRQ_IXDP2X01_SPCI_DB_0 IXP2000_BOARD_IRQ(2)
-#define IRQ_IXDP2X01_SPCI_DB_1 IXP2000_BOARD_IRQ(3)
-#define IRQ_IXDP2X01_SPCI_PMC_INTA IXP2000_BOARD_IRQ(4)
-#define IRQ_IXDP2X01_SPCI_PMC_INTB IXP2000_BOARD_IRQ(5)
-#define IRQ_IXDP2X01_SPCI_PMC_INTC IXP2000_BOARD_IRQ(6)
-#define IRQ_IXDP2X01_SPCI_PMC_INTD IXP2000_BOARD_IRQ(7)
-#define IRQ_IXDP2X01_SPCI_FIC_INT IXP2000_BOARD_IRQ(8)
-#define IRQ_IXDP2X01_IPMI_FROM IXP2000_BOARD_IRQ(16)
-#define IRQ_IXDP2X01_125US IXP2000_BOARD_IRQ(17)
-#define IRQ_IXDP2X01_DB_0_ADD IXP2000_BOARD_IRQ(18)
-#define IRQ_IXDP2X01_DB_1_ADD IXP2000_BOARD_IRQ(19)
-#define IRQ_IXDP2X01_UART1 IXP2000_BOARD_IRQ(21)
-#define IRQ_IXDP2X01_UART2 IXP2000_BOARD_IRQ(22)
-#define IRQ_IXDP2X01_FIC_ADD_INT IXP2000_BOARD_IRQ(24)
-#define IRQ_IXDP2X01_CS8900 IXP2000_BOARD_IRQ(25)
-#define IRQ_IXDP2X01_BBSRAM IXP2000_BOARD_IRQ(26)
-
-#define IXDP2X01_VALID_IRQ_MASK ( \
- IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_SPCI_DB_0) | \
- IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_SPCI_DB_1) | \
- IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_SPCI_PMC_INTA) | \
- IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_SPCI_PMC_INTB) | \
- IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_SPCI_PMC_INTC) | \
- IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_SPCI_PMC_INTD) | \
- IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_SPCI_FIC_INT) | \
- IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_IPMI_FROM) | \
- IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_125US) | \
- IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_DB_0_ADD) | \
- IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_DB_1_ADD) | \
- IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_UART1) | \
- IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_UART2) | \
- IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_FIC_ADD_INT) | \
- IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_CS8900) | \
- IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2X01_BBSRAM) )
-
-/*
- * IXDP2401 specific IRQs
- */
-#define IRQ_IXDP2401_INTA_82546 IXP2000_BOARD_IRQ(0)
-#define IRQ_IXDP2401_INTB_82546 IXP2000_BOARD_IRQ(1)
-
-#define IXDP2401_VALID_IRQ_MASK ( \
- IXDP2X01_VALID_IRQ_MASK | \
- IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2401_INTA_82546) |\
- IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2401_INTB_82546))
-
-/*
- * IXDP2801-specific IRQs
- */
-#define IRQ_IXDP2801_RIV IXP2000_BOARD_IRQ(0)
-#define IRQ_IXDP2801_CNFG_MEDIA IXP2000_BOARD_IRQ(27)
-#define IRQ_IXDP2801_CLOCK_REF IXP2000_BOARD_IRQ(28)
-
-#define IXDP2801_VALID_IRQ_MASK ( \
- IXDP2X01_VALID_IRQ_MASK | \
- IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2801_RIV) |\
- IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2801_CNFG_MEDIA) |\
- IXP2000_BOARD_IRQ_MASK(IRQ_IXDP2801_CLOCK_REF))
-
-#define NR_IXDP2X01_IRQS ((IRQ_IXDP2801_CLOCK_REF) + 1)
-
-#endif /*_IRQS_H*/
diff --git a/arch/arm/mach-ixp2000/include/mach/ixdp2x00.h b/arch/arm/mach-ixp2000/include/mach/ixdp2x00.h
deleted file mode 100644
index 5df8479d9481..000000000000
--- a/arch/arm/mach-ixp2000/include/mach/ixdp2x00.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/ixdp2x00.h
- *
- * Register and other defines for IXDP2[48]00 platforms
- *
- * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (C) 2002 Intel Corp.
- * Copyright (C) 2003-2004 MontaVista Software, 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.
- */
-#ifndef _IXDP2X00_H_
-#define _IXDP2X00_H_
-
-/*
- * On board CPLD memory map
- */
-#define IXDP2X00_PHYS_CPLD_BASE 0xc7000000
-#define IXDP2X00_VIRT_CPLD_BASE 0xfe000000
-#define IXDP2X00_CPLD_SIZE 0x00100000
-
-
-#define IXDP2X00_CPLD_REG(x) \
- (volatile unsigned long *)(IXDP2X00_VIRT_CPLD_BASE | x)
-
-/*
- * IXDP2400 CPLD registers
- */
-#define IXDP2400_CPLD_SYSLED IXDP2X00_CPLD_REG(0x0)
-#define IXDP2400_CPLD_DISP_DATA IXDP2X00_CPLD_REG(0x4)
-#define IXDP2400_CPLD_CLOCK_SPEED IXDP2X00_CPLD_REG(0x8)
-#define IXDP2400_CPLD_INT_STAT IXDP2X00_CPLD_REG(0xc)
-#define IXDP2400_CPLD_REV IXDP2X00_CPLD_REG(0x10)
-#define IXDP2400_CPLD_SYS_CLK_M IXDP2X00_CPLD_REG(0x14)
-#define IXDP2400_CPLD_SYS_CLK_N IXDP2X00_CPLD_REG(0x18)
-#define IXDP2400_CPLD_INT_MASK IXDP2X00_CPLD_REG(0x48)
-
-/*
- * IXDP2800 CPLD registers
- */
-#define IXDP2800_CPLD_INT_STAT IXDP2X00_CPLD_REG(0x0)
-#define IXDP2800_CPLD_INT_MASK IXDP2X00_CPLD_REG(0x140)
-
-
-#define IXDP2X00_GPIO_I2C_ENABLE 0x02
-#define IXDP2X00_GPIO_SCL 0x07
-#define IXDP2X00_GPIO_SDA 0x06
-
-/*
- * PCI devfns for on-board devices. We need these to be able to
- * properly translate IRQs and for device removal.
- */
-#define IXDP2400_SLAVE_ENET_DEVFN 0x18 /* Bus 1 */
-#define IXDP2400_MASTER_ENET_DEVFN 0x20 /* Bus 1 */
-#define IXDP2400_MEDIA_DEVFN 0x28 /* Bus 1 */
-#define IXDP2400_SWITCH_FABRIC_DEVFN 0x30 /* Bus 1 */
-
-#define IXDP2800_SLAVE_ENET_DEVFN 0x20 /* Bus 1 */
-#define IXDP2800_MASTER_ENET_DEVFN 0x18 /* Bus 1 */
-#define IXDP2800_SWITCH_FABRIC_DEVFN 0x30 /* Bus 1 */
-
-#define IXDP2X00_P2P_DEVFN 0x20 /* Bus 0 */
-#define IXDP2X00_21555_DEVFN 0x30 /* Bus 0 */
-#define IXDP2X00_SLAVE_NPU_DEVFN 0x28 /* Bus 1 */
-#define IXDP2X00_PMC_DEVFN 0x38 /* Bus 1 */
-#define IXDP2X00_MASTER_NPU_DEVFN 0x38 /* Bus 1 */
-
-#ifndef __ASSEMBLY__
-/*
- * The master NPU is always PCI master.
- */
-static inline unsigned int ixdp2x00_master_npu(void)
-{
- return !!ixp2000_is_pcimaster();
-}
-
-/*
- * Helper functions used by ixdp2400 and ixdp2800 specific code
- */
-void ixdp2x00_init_irq(volatile unsigned long*, volatile unsigned long *, unsigned long);
-void ixdp2x00_slave_pci_postinit(void);
-void ixdp2x00_init_machine(void);
-void ixdp2x00_map_io(void);
-
-#endif
-
-#endif /*_IXDP2X00_H_ */
diff --git a/arch/arm/mach-ixp2000/include/mach/ixdp2x01.h b/arch/arm/mach-ixp2000/include/mach/ixdp2x01.h
deleted file mode 100644
index 4c1f04083e54..000000000000
--- a/arch/arm/mach-ixp2000/include/mach/ixdp2x01.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/ixdp2x01.h
- *
- * Platform definitions for IXDP2X01 && IXDP2801 systems
- *
- * Author: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright 2004 (c) MontaVista Software, Inc.
- *
- * Based on original code Copyright (c) 2002-2003 Intel Corporation
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __IXDP2X01_H__
-#define __IXDP2X01_H__
-
-#define IXDP2X01_PHYS_CPLD_BASE 0xc6024000
-#define IXDP2X01_VIRT_CPLD_BASE 0xfe000000
-#define IXDP2X01_CPLD_REGION_SIZE 0x00100000
-
-#define IXDP2X01_CPLD_VIRT_REG(reg) (volatile unsigned long*)(IXDP2X01_VIRT_CPLD_BASE | reg)
-#define IXDP2X01_CPLD_PHYS_REG(reg) (IXDP2X01_PHYS_CPLD_BASE | reg)
-
-#define IXDP2X01_UART1_VIRT_BASE IXDP2X01_CPLD_VIRT_REG(0x40)
-#define IXDP2X01_UART1_PHYS_BASE IXDP2X01_CPLD_PHYS_REG(0x40)
-
-#define IXDP2X01_UART2_VIRT_BASE IXDP2X01_CPLD_VIRT_REG(0x60)
-#define IXDP2X01_UART2_PHYS_BASE IXDP2X01_CPLD_PHYS_REG(0x60)
-
-#define IXDP2X01_CS8900_VIRT_BASE IXDP2X01_CPLD_VIRT_REG(0x80)
-#define IXDP2X01_CS8900_VIRT_END (IXDP2X01_CS8900_VIRT_BASE + 16)
-
-#define IXDP2X01_CPLD_RESET_REG IXDP2X01_CPLD_VIRT_REG(0x00)
-#define IXDP2X01_INT_MASK_SET_REG IXDP2X01_CPLD_VIRT_REG(0x08)
-#define IXDP2X01_INT_STAT_REG IXDP2X01_CPLD_VIRT_REG(0x0C)
-#define IXDP2X01_INT_RAW_REG IXDP2X01_CPLD_VIRT_REG(0x10)
-#define IXDP2X01_INT_MASK_CLR_REG IXDP2X01_INT_RAW_REG
-#define IXDP2X01_INT_SIM_REG IXDP2X01_CPLD_VIRT_REG(0x14)
-
-#define IXDP2X01_CPLD_FLASH_REG IXDP2X01_CPLD_VIRT_REG(0x20)
-
-#define IXDP2X01_CPLD_FLASH_INTERN 0x8000
-#define IXDP2X01_CPLD_FLASH_BANK_MASK 0xF
-#define IXDP2X01_FLASH_WINDOW_BITS 25
-#define IXDP2X01_FLASH_WINDOW_SIZE (1 << IXDP2X01_FLASH_WINDOW_BITS)
-#define IXDP2X01_FLASH_WINDOW_MASK (IXDP2X01_FLASH_WINDOW_SIZE - 1)
-
-#define IXDP2X01_UART_CLK 1843200
-
-#define IXDP2X01_GPIO_I2C_ENABLE 0x02
-#define IXDP2X01_GPIO_SCL 0x07
-#define IXDP2X01_GPIO_SDA 0x06
-
-#endif /* __IXDP2x01_H__ */
diff --git a/arch/arm/mach-ixp2000/include/mach/ixp2000-regs.h b/arch/arm/mach-ixp2000/include/mach/ixp2000-regs.h
deleted file mode 100644
index 822f63f2f4a2..000000000000
--- a/arch/arm/mach-ixp2000/include/mach/ixp2000-regs.h
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/ixp2000-regs.h
- *
- * Chipset register definitions for IXP2400/2800 based systems.
- *
- * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
- *
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (C) 2002 Intel Corp.
- * Copyright (C) 2003-2004 MontaVista Software, 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.
- */
-#ifndef _IXP2000_REGS_H_
-#define _IXP2000_REGS_H_
-
-/*
- * IXP2000 linux memory map:
- *
- * virt phys size
- * fb000000 db000000 16M PCI CFG1
- * fc000000 da000000 16M PCI CFG0
- * fd000000 d8000000 16M PCI I/O
- * fe[0-7]00000 8M per-platform mappings
- * fe900000 80000000 1M SRAM #0 (first MB)
- * fea00000 cb400000 1M SCRATCH ring get/put
- * feb00000 c8000000 1M MSF
- * fec00000 df000000 1M PCI CSRs
- * fed00000 de000000 1M PCI CREG
- * fee00000 d6000000 1M INTCTL
- * fef00000 c0000000 1M CAP
- */
-
-/*
- * Static I/O regions.
- *
- * Most of the registers are clumped in 4K regions spread throughout
- * the 0xc0000000 -> 0xc0100000 address range, but we just map in
- * the whole range using a single 1 MB section instead of small
- * 4K pages.
- *
- * CAP stands for CSR Access Proxy.
- *
- * If you change the virtual address of this mapping, please propagate
- * the change to arch/arm/kernel/debug.S, which hardcodes the virtual
- * address of the UART located in this region.
- */
-
-#define IXP2000_CAP_PHYS_BASE 0xc0000000
-#define IXP2000_CAP_VIRT_BASE 0xfef00000
-#define IXP2000_CAP_SIZE 0x00100000
-
-/*
- * Addresses for specific on-chip peripherals.
- */
-#define IXP2000_SLOWPORT_CSR_VIRT_BASE 0xfef80000
-#define IXP2000_GLOBAL_REG_VIRT_BASE 0xfef04000
-#define IXP2000_UART_PHYS_BASE 0xc0030000
-#define IXP2000_UART_VIRT_BASE 0xfef30000
-#define IXP2000_TIMER_VIRT_BASE 0xfef20000
-#define IXP2000_UENGINE_CSR_VIRT_BASE 0xfef18000
-#define IXP2000_GPIO_VIRT_BASE 0xfef10000
-
-/*
- * Devices outside of the 0xc0000000 -> 0xc0100000 range. The virtual
- * addresses of the INTCTL and PCI_CSR mappings are hardcoded in
- * entry-macro.S, so if you ever change these please propagate
- * the change.
- */
-#define IXP2000_INTCTL_PHYS_BASE 0xd6000000
-#define IXP2000_INTCTL_VIRT_BASE 0xfee00000
-#define IXP2000_INTCTL_SIZE 0x00100000
-
-#define IXP2000_PCI_CREG_PHYS_BASE 0xde000000
-#define IXP2000_PCI_CREG_VIRT_BASE 0xfed00000
-#define IXP2000_PCI_CREG_SIZE 0x00100000
-
-#define IXP2000_PCI_CSR_PHYS_BASE 0xdf000000
-#define IXP2000_PCI_CSR_VIRT_BASE 0xfec00000
-#define IXP2000_PCI_CSR_SIZE 0x00100000
-
-#define IXP2000_MSF_PHYS_BASE 0xc8000000
-#define IXP2000_MSF_VIRT_BASE 0xfeb00000
-#define IXP2000_MSF_SIZE 0x00100000
-
-#define IXP2000_SCRATCH_RING_PHYS_BASE 0xcb400000
-#define IXP2000_SCRATCH_RING_VIRT_BASE 0xfea00000
-#define IXP2000_SCRATCH_RING_SIZE 0x00100000
-
-#define IXP2000_SRAM0_PHYS_BASE 0x80000000
-#define IXP2000_SRAM0_VIRT_BASE 0xfe900000
-#define IXP2000_SRAM0_SIZE 0x00100000
-
-#define IXP2000_PCI_IO_PHYS_BASE 0xd8000000
-#define IXP2000_PCI_IO_VIRT_BASE 0xfd000000
-#define IXP2000_PCI_IO_SIZE 0x01000000
-
-#define IXP2000_PCI_CFG0_PHYS_BASE 0xda000000
-#define IXP2000_PCI_CFG0_VIRT_BASE 0xfc000000
-#define IXP2000_PCI_CFG0_SIZE 0x01000000
-
-#define IXP2000_PCI_CFG1_PHYS_BASE 0xdb000000
-#define IXP2000_PCI_CFG1_VIRT_BASE 0xfb000000
-#define IXP2000_PCI_CFG1_SIZE 0x01000000
-
-/*
- * Timers
- */
-#define IXP2000_TIMER_REG(x) ((volatile unsigned long*)(IXP2000_TIMER_VIRT_BASE | (x)))
-/* Timer control */
-#define IXP2000_T1_CTL IXP2000_TIMER_REG(0x00)
-#define IXP2000_T2_CTL IXP2000_TIMER_REG(0x04)
-#define IXP2000_T3_CTL IXP2000_TIMER_REG(0x08)
-#define IXP2000_T4_CTL IXP2000_TIMER_REG(0x0c)
-/* Store initial value */
-#define IXP2000_T1_CLD IXP2000_TIMER_REG(0x10)
-#define IXP2000_T2_CLD IXP2000_TIMER_REG(0x14)
-#define IXP2000_T3_CLD IXP2000_TIMER_REG(0x18)
-#define IXP2000_T4_CLD IXP2000_TIMER_REG(0x1c)
-/* Read current value */
-#define IXP2000_T1_CSR IXP2000_TIMER_REG(0x20)
-#define IXP2000_T2_CSR IXP2000_TIMER_REG(0x24)
-#define IXP2000_T3_CSR IXP2000_TIMER_REG(0x28)
-#define IXP2000_T4_CSR IXP2000_TIMER_REG(0x2c)
-/* Clear associated timer interrupt */
-#define IXP2000_T1_CLR IXP2000_TIMER_REG(0x30)
-#define IXP2000_T2_CLR IXP2000_TIMER_REG(0x34)
-#define IXP2000_T3_CLR IXP2000_TIMER_REG(0x38)
-#define IXP2000_T4_CLR IXP2000_TIMER_REG(0x3c)
-/* Timer watchdog enable for T4 */
-#define IXP2000_TWDE IXP2000_TIMER_REG(0x40)
-
-#define WDT_ENABLE 0x00000001
-#define TIMER_DIVIDER_256 0x00000008
-#define TIMER_ENABLE 0x00000080
-#define IRQ_MASK_TIMER1 (1 << 4)
-
-/*
- * Interrupt controller registers
- */
-#define IXP2000_INTCTL_REG(x) (volatile unsigned long*)(IXP2000_INTCTL_VIRT_BASE | (x))
-#define IXP2000_IRQ_STATUS IXP2000_INTCTL_REG(0x08)
-#define IXP2000_IRQ_ENABLE IXP2000_INTCTL_REG(0x10)
-#define IXP2000_IRQ_ENABLE_SET IXP2000_INTCTL_REG(0x10)
-#define IXP2000_IRQ_ENABLE_CLR IXP2000_INTCTL_REG(0x18)
-#define IXP2000_FIQ_ENABLE_CLR IXP2000_INTCTL_REG(0x14)
-#define IXP2000_IRQ_ERR_STATUS IXP2000_INTCTL_REG(0x24)
-#define IXP2000_IRQ_ERR_ENABLE_SET IXP2000_INTCTL_REG(0x2c)
-#define IXP2000_FIQ_ERR_ENABLE_CLR IXP2000_INTCTL_REG(0x30)
-#define IXP2000_IRQ_ERR_ENABLE_CLR IXP2000_INTCTL_REG(0x34)
-#define IXP2000_IRQ_THD_RAW_STATUS_A_0 IXP2000_INTCTL_REG(0x60)
-#define IXP2000_IRQ_THD_RAW_STATUS_A_1 IXP2000_INTCTL_REG(0x64)
-#define IXP2000_IRQ_THD_RAW_STATUS_A_2 IXP2000_INTCTL_REG(0x68)
-#define IXP2000_IRQ_THD_RAW_STATUS_A_3 IXP2000_INTCTL_REG(0x6c)
-#define IXP2000_IRQ_THD_RAW_STATUS_B_0 IXP2000_INTCTL_REG(0x80)
-#define IXP2000_IRQ_THD_RAW_STATUS_B_1 IXP2000_INTCTL_REG(0x84)
-#define IXP2000_IRQ_THD_RAW_STATUS_B_2 IXP2000_INTCTL_REG(0x88)
-#define IXP2000_IRQ_THD_RAW_STATUS_B_3 IXP2000_INTCTL_REG(0x8c)
-#define IXP2000_IRQ_THD_STATUS_A_0 IXP2000_INTCTL_REG(0xe0)
-#define IXP2000_IRQ_THD_STATUS_A_1 IXP2000_INTCTL_REG(0xe4)
-#define IXP2000_IRQ_THD_STATUS_A_2 IXP2000_INTCTL_REG(0xe8)
-#define IXP2000_IRQ_THD_STATUS_A_3 IXP2000_INTCTL_REG(0xec)
-#define IXP2000_IRQ_THD_STATUS_B_0 IXP2000_INTCTL_REG(0x100)
-#define IXP2000_IRQ_THD_STATUS_B_1 IXP2000_INTCTL_REG(0x104)
-#define IXP2000_IRQ_THD_STATUS_B_2 IXP2000_INTCTL_REG(0x108)
-#define IXP2000_IRQ_THD_STATUS_B_3 IXP2000_INTCTL_REG(0x10c)
-#define IXP2000_IRQ_THD_ENABLE_SET_A_0 IXP2000_INTCTL_REG(0x160)
-#define IXP2000_IRQ_THD_ENABLE_SET_A_1 IXP2000_INTCTL_REG(0x164)
-#define IXP2000_IRQ_THD_ENABLE_SET_A_2 IXP2000_INTCTL_REG(0x168)
-#define IXP2000_IRQ_THD_ENABLE_SET_A_3 IXP2000_INTCTL_REG(0x16c)
-#define IXP2000_IRQ_THD_ENABLE_SET_B_0 IXP2000_INTCTL_REG(0x180)
-#define IXP2000_IRQ_THD_ENABLE_SET_B_1 IXP2000_INTCTL_REG(0x184)
-#define IXP2000_IRQ_THD_ENABLE_SET_B_2 IXP2000_INTCTL_REG(0x188)
-#define IXP2000_IRQ_THD_ENABLE_SET_B_3 IXP2000_INTCTL_REG(0x18c)
-#define IXP2000_IRQ_THD_ENABLE_CLEAR_A_0 IXP2000_INTCTL_REG(0x1e0)
-#define IXP2000_IRQ_THD_ENABLE_CLEAR_A_1 IXP2000_INTCTL_REG(0x1e4)
-#define IXP2000_IRQ_THD_ENABLE_CLEAR_A_2 IXP2000_INTCTL_REG(0x1e8)
-#define IXP2000_IRQ_THD_ENABLE_CLEAR_A_3 IXP2000_INTCTL_REG(0x1ec)
-#define IXP2000_IRQ_THD_ENABLE_CLEAR_B_0 IXP2000_INTCTL_REG(0x200)
-#define IXP2000_IRQ_THD_ENABLE_CLEAR_B_1 IXP2000_INTCTL_REG(0x204)
-#define IXP2000_IRQ_THD_ENABLE_CLEAR_B_2 IXP2000_INTCTL_REG(0x208)
-#define IXP2000_IRQ_THD_ENABLE_CLEAR_B_3 IXP2000_INTCTL_REG(0x20c)
-
-/*
- * Mask of valid IRQs in the 32-bit IRQ register. We use
- * this to mark certain IRQs as being invalid.
- */
-#define IXP2000_VALID_IRQ_MASK 0x0f0fffff
-
-/*
- * PCI config register access from core
- */
-#define IXP2000_PCI_CREG(x) (volatile unsigned long*)(IXP2000_PCI_CREG_VIRT_BASE | (x))
-#define IXP2000_PCI_CMDSTAT IXP2000_PCI_CREG(0x04)
-#define IXP2000_PCI_CSR_BAR IXP2000_PCI_CREG(0x10)
-#define IXP2000_PCI_SRAM_BAR IXP2000_PCI_CREG(0x14)
-#define IXP2000_PCI_SDRAM_BAR IXP2000_PCI_CREG(0x18)
-
-/*
- * PCI CSRs
- */
-#define IXP2000_PCI_CSR(x) (volatile unsigned long*)(IXP2000_PCI_CSR_VIRT_BASE | (x))
-
-/*
- * PCI outbound interrupts
- */
-#define IXP2000_PCI_OUT_INT_STATUS IXP2000_PCI_CSR(0x30)
-#define IXP2000_PCI_OUT_INT_MASK IXP2000_PCI_CSR(0x34)
-/*
- * PCI communications
- */
-#define IXP2000_PCI_MAILBOX0 IXP2000_PCI_CSR(0x50)
-#define IXP2000_PCI_MAILBOX1 IXP2000_PCI_CSR(0x54)
-#define IXP2000_PCI_MAILBOX2 IXP2000_PCI_CSR(0x58)
-#define IXP2000_PCI_MAILBOX3 IXP2000_PCI_CSR(0x5C)
-#define IXP2000_XSCALE_DOORBELL IXP2000_PCI_CSR(0x60)
-#define IXP2000_XSCALE_DOORBELL_SETUP IXP2000_PCI_CSR(0x64)
-#define IXP2000_PCI_DOORBELL IXP2000_PCI_CSR(0x70)
-#define IXP2000_PCI_DOORBELL_SETUP IXP2000_PCI_CSR(0x74)
-
-/*
- * DMA engines
- */
-#define IXP2000_PCI_CH1_BYTE_CNT IXP2000_PCI_CSR(0x80)
-#define IXP2000_PCI_CH1_ADDR IXP2000_PCI_CSR(0x84)
-#define IXP2000_PCI_CH1_DRAM_ADDR IXP2000_PCI_CSR(0x88)
-#define IXP2000_PCI_CH1_DESC_PTR IXP2000_PCI_CSR(0x8C)
-#define IXP2000_PCI_CH1_CNTRL IXP2000_PCI_CSR(0x90)
-#define IXP2000_PCI_CH1_ME_PARAM IXP2000_PCI_CSR(0x94)
-#define IXP2000_PCI_CH2_BYTE_CNT IXP2000_PCI_CSR(0xA0)
-#define IXP2000_PCI_CH2_ADDR IXP2000_PCI_CSR(0xA4)
-#define IXP2000_PCI_CH2_DRAM_ADDR IXP2000_PCI_CSR(0xA8)
-#define IXP2000_PCI_CH2_DESC_PTR IXP2000_PCI_CSR(0xAC)
-#define IXP2000_PCI_CH2_CNTRL IXP2000_PCI_CSR(0xB0)
-#define IXP2000_PCI_CH2_ME_PARAM IXP2000_PCI_CSR(0xB4)
-#define IXP2000_PCI_CH3_BYTE_CNT IXP2000_PCI_CSR(0xC0)
-#define IXP2000_PCI_CH3_ADDR IXP2000_PCI_CSR(0xC4)
-#define IXP2000_PCI_CH3_DRAM_ADDR IXP2000_PCI_CSR(0xC8)
-#define IXP2000_PCI_CH3_DESC_PTR IXP2000_PCI_CSR(0xCC)
-#define IXP2000_PCI_CH3_CNTRL IXP2000_PCI_CSR(0xD0)
-#define IXP2000_PCI_CH3_ME_PARAM IXP2000_PCI_CSR(0xD4)
-#define IXP2000_DMA_INF_MODE IXP2000_PCI_CSR(0xE0)
-/*
- * Size masks for BARs
- */
-#define IXP2000_PCI_SRAM_BASE_ADDR_MASK IXP2000_PCI_CSR(0xFC)
-#define IXP2000_PCI_DRAM_BASE_ADDR_MASK IXP2000_PCI_CSR(0x100)
-/*
- * Control and uEngine related
- */
-#define IXP2000_PCI_CONTROL IXP2000_PCI_CSR(0x13C)
-#define IXP2000_PCI_ADDR_EXT IXP2000_PCI_CSR(0x140)
-#define IXP2000_PCI_ME_PUSH_STATUS IXP2000_PCI_CSR(0x148)
-#define IXP2000_PCI_ME_PUSH_EN IXP2000_PCI_CSR(0x14C)
-#define IXP2000_PCI_ERR_STATUS IXP2000_PCI_CSR(0x150)
-#define IXP2000_PCI_ERR_ENABLE IXP2000_PCI_CSR(0x154)
-/*
- * Inbound PCI interrupt control
- */
-#define IXP2000_PCI_XSCALE_INT_STATUS IXP2000_PCI_CSR(0x158)
-#define IXP2000_PCI_XSCALE_INT_ENABLE IXP2000_PCI_CSR(0x15C)
-
-#define IXP2000_PCICNTL_PNR (1<<17) /* PCI not Reset bit of PCI_CONTROL */
-#define IXP2000_PCICNTL_PCF (1<<28) /* PCI Central function bit */
-#define IXP2000_XSCALE_INT (1<<1) /* Interrupt from XScale to PCI */
-
-/* These are from the IRQ register in the PCI ISR register */
-#define PCI_CONTROL_BE_DEO (1 << 22) /* Big Endian Data Enable Out */
-#define PCI_CONTROL_BE_DEI (1 << 21) /* Big Endian Data Enable In */
-#define PCI_CONTROL_BE_BEO (1 << 20) /* Big Endian Byte Enable Out */
-#define PCI_CONTROL_BE_BEI (1 << 19) /* Big Endian Byte Enable In */
-#define PCI_CONTROL_IEE (1 << 17) /* I/O cycle Endian swap Enable */
-
-#define IXP2000_PCI_RST_REL (1 << 2)
-#define CFG_RST_DIR (*IXP2000_PCI_CONTROL & IXP2000_PCICNTL_PCF)
-#define CFG_PCI_BOOT_HOST (1 << 2)
-#define CFG_BOOT_PROM (1 << 1)
-
-/*
- * SlowPort CSRs
- *
- * The slowport is used to access things like flash, SONET framer control
- * ports, slave microprocessors, CPLDs, and others of chip memory mapped
- * peripherals.
- */
-#define SLOWPORT_CSR(x) (volatile unsigned long*)(IXP2000_SLOWPORT_CSR_VIRT_BASE | (x))
-
-#define IXP2000_SLOWPORT_CCR SLOWPORT_CSR(0x00)
-#define IXP2000_SLOWPORT_WTC1 SLOWPORT_CSR(0x04)
-#define IXP2000_SLOWPORT_WTC2 SLOWPORT_CSR(0x08)
-#define IXP2000_SLOWPORT_RTC1 SLOWPORT_CSR(0x0c)
-#define IXP2000_SLOWPORT_RTC2 SLOWPORT_CSR(0x10)
-#define IXP2000_SLOWPORT_FSR SLOWPORT_CSR(0x14)
-#define IXP2000_SLOWPORT_PCR SLOWPORT_CSR(0x18)
-#define IXP2000_SLOWPORT_ADC SLOWPORT_CSR(0x1C)
-#define IXP2000_SLOWPORT_FAC SLOWPORT_CSR(0x20)
-#define IXP2000_SLOWPORT_FRM SLOWPORT_CSR(0x24)
-#define IXP2000_SLOWPORT_FIN SLOWPORT_CSR(0x28)
-
-/*
- * CCR values.
- * The CCR configures the clock division for the slowport interface.
- */
-#define SLOWPORT_CCR_DIV_1 0x00
-#define SLOWPORT_CCR_DIV_2 0x01
-#define SLOWPORT_CCR_DIV_4 0x02
-#define SLOWPORT_CCR_DIV_6 0x03
-#define SLOWPORT_CCR_DIV_8 0x04
-#define SLOWPORT_CCR_DIV_10 0x05
-#define SLOWPORT_CCR_DIV_12 0x06
-#define SLOWPORT_CCR_DIV_14 0x07
-#define SLOWPORT_CCR_DIV_16 0x08
-#define SLOWPORT_CCR_DIV_18 0x09
-#define SLOWPORT_CCR_DIV_20 0x0a
-#define SLOWPORT_CCR_DIV_22 0x0b
-#define SLOWPORT_CCR_DIV_24 0x0c
-#define SLOWPORT_CCR_DIV_26 0x0d
-#define SLOWPORT_CCR_DIV_28 0x0e
-#define SLOWPORT_CCR_DIV_30 0x0f
-
-/*
- * PCR values. PCR configure the mode of the interface.
- */
-#define SLOWPORT_MODE_FLASH 0x00
-#define SLOWPORT_MODE_LUCENT 0x01
-#define SLOWPORT_MODE_PMC_SIERRA 0x02
-#define SLOWPORT_MODE_INTEL_UP 0x03
-#define SLOWPORT_MODE_MOTOROLA_UP 0x04
-
-/*
- * ADC values. Defines data and address bus widths.
- */
-#define SLOWPORT_ADDR_WIDTH_8 0x00
-#define SLOWPORT_ADDR_WIDTH_16 0x01
-#define SLOWPORT_ADDR_WIDTH_24 0x02
-#define SLOWPORT_ADDR_WIDTH_32 0x03
-#define SLOWPORT_DATA_WIDTH_8 0x00
-#define SLOWPORT_DATA_WIDTH_16 0x10
-#define SLOWPORT_DATA_WIDTH_24 0x20
-#define SLOWPORT_DATA_WIDTH_32 0x30
-
-/*
- * Masks and shifts for various fields in the WTC and RTC registers.
- */
-#define SLOWPORT_WRTC_MASK_HD 0x0003
-#define SLOWPORT_WRTC_MASK_PW 0x003c
-#define SLOWPORT_WRTC_MASK_SU 0x03c0
-
-#define SLOWPORT_WRTC_SHIFT_HD 0x00
-#define SLOWPORT_WRTC_SHIFT_SU 0x02
-#define SLOWPORT_WRTC_SHFIT_PW 0x06
-
-
-/*
- * GPIO registers & GPIO interface.
- */
-#define IXP2000_GPIO_REG(x) ((volatile unsigned long*)(IXP2000_GPIO_VIRT_BASE+(x)))
-#define IXP2000_GPIO_PLR IXP2000_GPIO_REG(0x00)
-#define IXP2000_GPIO_PDPR IXP2000_GPIO_REG(0x04)
-#define IXP2000_GPIO_PDSR IXP2000_GPIO_REG(0x08)
-#define IXP2000_GPIO_PDCR IXP2000_GPIO_REG(0x0c)
-#define IXP2000_GPIO_POPR IXP2000_GPIO_REG(0x10)
-#define IXP2000_GPIO_POSR IXP2000_GPIO_REG(0x14)
-#define IXP2000_GPIO_POCR IXP2000_GPIO_REG(0x18)
-#define IXP2000_GPIO_REDR IXP2000_GPIO_REG(0x1c)
-#define IXP2000_GPIO_FEDR IXP2000_GPIO_REG(0x20)
-#define IXP2000_GPIO_EDSR IXP2000_GPIO_REG(0x24)
-#define IXP2000_GPIO_LSHR IXP2000_GPIO_REG(0x28)
-#define IXP2000_GPIO_LSLR IXP2000_GPIO_REG(0x2c)
-#define IXP2000_GPIO_LDSR IXP2000_GPIO_REG(0x30)
-#define IXP2000_GPIO_INER IXP2000_GPIO_REG(0x34)
-#define IXP2000_GPIO_INSR IXP2000_GPIO_REG(0x38)
-#define IXP2000_GPIO_INCR IXP2000_GPIO_REG(0x3c)
-#define IXP2000_GPIO_INST IXP2000_GPIO_REG(0x40)
-
-/*
- * "Global" registers...whatever that's supposed to mean.
- */
-#define GLOBAL_REG_BASE (IXP2000_GLOBAL_REG_VIRT_BASE + 0x0a00)
-#define GLOBAL_REG(x) (volatile unsigned long*)(GLOBAL_REG_BASE | (x))
-
-#define IXP2000_MAJ_PROD_TYPE_MASK 0x001F0000
-#define IXP2000_MAJ_PROD_TYPE_IXP2000 0x00000000
-#define IXP2000_MIN_PROD_TYPE_MASK 0x0000FF00
-#define IXP2000_MIN_PROD_TYPE_IXP2400 0x00000200
-#define IXP2000_MIN_PROD_TYPE_IXP2850 0x00000100
-#define IXP2000_MIN_PROD_TYPE_IXP2800 0x00000000
-#define IXP2000_MAJ_REV_MASK 0x000000F0
-#define IXP2000_MIN_REV_MASK 0x0000000F
-#define IXP2000_PROD_ID_MASK 0xFFFFFFFF
-
-#define IXP2000_PRODUCT_ID GLOBAL_REG(0x00)
-#define IXP2000_MISC_CONTROL GLOBAL_REG(0x04)
-#define IXP2000_MSF_CLK_CNTRL GLOBAL_REG(0x08)
-#define IXP2000_RESET0 GLOBAL_REG(0x0c)
-#define IXP2000_RESET1 GLOBAL_REG(0x10)
-#define IXP2000_CCR GLOBAL_REG(0x14)
-#define IXP2000_STRAP_OPTIONS GLOBAL_REG(0x18)
-
-#define RSTALL (1 << 16)
-#define WDT_RESET_ENABLE 0x01000000
-
-
-/*
- * MSF registers. The IXP2400 and IXP2800 have somewhat different MSF
- * units, but the registers that differ between the two don't overlap,
- * so we can have one register list for both.
- */
-#define IXP2000_MSF_REG(x) ((volatile unsigned long*)(IXP2000_MSF_VIRT_BASE + (x)))
-#define IXP2000_MSF_RX_CONTROL IXP2000_MSF_REG(0x0000)
-#define IXP2000_MSF_TX_CONTROL IXP2000_MSF_REG(0x0004)
-#define IXP2000_MSF_INTERRUPT_STATUS IXP2000_MSF_REG(0x0008)
-#define IXP2000_MSF_INTERRUPT_ENABLE IXP2000_MSF_REG(0x000c)
-#define IXP2000_MSF_CSIX_TYPE_MAP IXP2000_MSF_REG(0x0010)
-#define IXP2000_MSF_FC_EGRESS_STATUS IXP2000_MSF_REG(0x0014)
-#define IXP2000_MSF_FC_INGRESS_STATUS IXP2000_MSF_REG(0x0018)
-#define IXP2000_MSF_HWM_CONTROL IXP2000_MSF_REG(0x0024)
-#define IXP2000_MSF_FC_STATUS_OVERRIDE IXP2000_MSF_REG(0x0028)
-#define IXP2000_MSF_CLOCK_CONTROL IXP2000_MSF_REG(0x002c)
-#define IXP2000_MSF_RX_PORT_MAP IXP2000_MSF_REG(0x0040)
-#define IXP2000_MSF_RBUF_ELEMENT_DONE IXP2000_MSF_REG(0x0044)
-#define IXP2000_MSF_RX_MPHY_POLL_LIMIT IXP2000_MSF_REG(0x0048)
-#define IXP2000_MSF_RX_CALENDAR_LENGTH IXP2000_MSF_REG(0x0048)
-#define IXP2000_MSF_RX_THREAD_FREELIST_TIMEOUT_0 IXP2000_MSF_REG(0x0050)
-#define IXP2000_MSF_RX_THREAD_FREELIST_TIMEOUT_1 IXP2000_MSF_REG(0x0054)
-#define IXP2000_MSF_RX_THREAD_FREELIST_TIMEOUT_2 IXP2000_MSF_REG(0x0058)
-#define IXP2000_MSF_TX_SEQUENCE_0 IXP2000_MSF_REG(0x0060)
-#define IXP2000_MSF_TX_SEQUENCE_1 IXP2000_MSF_REG(0x0064)
-#define IXP2000_MSF_TX_SEQUENCE_2 IXP2000_MSF_REG(0x0068)
-#define IXP2000_MSF_TX_MPHY_POLL_LIMIT IXP2000_MSF_REG(0x0070)
-#define IXP2000_MSF_TX_CALENDAR_LENGTH IXP2000_MSF_REG(0x0070)
-#define IXP2000_MSF_RX_UP_CONTROL_0 IXP2000_MSF_REG(0x0080)
-#define IXP2000_MSF_RX_UP_CONTROL_1 IXP2000_MSF_REG(0x0084)
-#define IXP2000_MSF_RX_UP_CONTROL_2 IXP2000_MSF_REG(0x0088)
-#define IXP2000_MSF_RX_UP_CONTROL_3 IXP2000_MSF_REG(0x008c)
-#define IXP2000_MSF_TX_UP_CONTROL_0 IXP2000_MSF_REG(0x0090)
-#define IXP2000_MSF_TX_UP_CONTROL_1 IXP2000_MSF_REG(0x0094)
-#define IXP2000_MSF_TX_UP_CONTROL_2 IXP2000_MSF_REG(0x0098)
-#define IXP2000_MSF_TX_UP_CONTROL_3 IXP2000_MSF_REG(0x009c)
-#define IXP2000_MSF_TRAIN_DATA IXP2000_MSF_REG(0x00a0)
-#define IXP2000_MSF_TRAIN_CALENDAR IXP2000_MSF_REG(0x00a4)
-#define IXP2000_MSF_TRAIN_FLOW_CONTROL IXP2000_MSF_REG(0x00a8)
-#define IXP2000_MSF_TX_CALENDAR_0 IXP2000_MSF_REG(0x1000)
-#define IXP2000_MSF_RX_PORT_CALENDAR_STATUS IXP2000_MSF_REG(0x1400)
-
-
-#endif /* _IXP2000_H_ */
diff --git a/arch/arm/mach-ixp2000/include/mach/memory.h b/arch/arm/mach-ixp2000/include/mach/memory.h
deleted file mode 100644
index 5f0c4fd4076a..000000000000
--- a/arch/arm/mach-ixp2000/include/mach/memory.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/memory.h
- *
- * Copyright (c) 2002 Intel Corp.
- * Copyright (c) 2003-2004 MontaVista Software, 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.
- */
-
-#ifndef __ASM_ARCH_MEMORY_H
-#define __ASM_ARCH_MEMORY_H
-
-#define PLAT_PHYS_OFFSET UL(0x00000000)
-
-#include <mach/ixp2000-regs.h>
-
-#define IXP2000_PCI_SDRAM_OFFSET (*IXP2000_PCI_SDRAM_BAR & 0xfffffff0)
-
-#define __phys_to_bus(x) ((x) + (IXP2000_PCI_SDRAM_OFFSET - PHYS_OFFSET))
-#define __bus_to_phys(x) ((x) - (IXP2000_PCI_SDRAM_OFFSET - PHYS_OFFSET))
-
-#define __virt_to_bus(v) __phys_to_bus(__virt_to_phys(v))
-#define __bus_to_virt(b) __phys_to_virt(__bus_to_phys(b))
-#define __pfn_to_bus(p) __phys_to_bus(__pfn_to_phys(p))
-#define __bus_to_pfn(b) __phys_to_pfn(__bus_to_phys(b))
-
-#endif
-
diff --git a/arch/arm/mach-ixp2000/include/mach/platform.h b/arch/arm/mach-ixp2000/include/mach/platform.h
deleted file mode 100644
index 6b500c0858be..000000000000
--- a/arch/arm/mach-ixp2000/include/mach/platform.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/platform.h
- *
- * Various bits of code used by platform-level code.
- *
- * Author: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright 2004 (c) MontaVista Software, Inc.
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-
-#ifndef __ASSEMBLY__
-
-static inline unsigned long ixp2000_reg_read(volatile void *reg)
-{
- return *((volatile unsigned long *)reg);
-}
-
-static inline void ixp2000_reg_write(volatile void *reg, unsigned long val)
-{
- *((volatile unsigned long *)reg) = val;
-}
-
-/*
- * On the IXP2400, we can't use XCB=000 due to chip bugs. We use
- * XCB=101 instead, but that makes all I/O accesses bufferable. This
- * is not a problem in general, but we do have to be slightly more
- * careful because I/O writes are no longer automatically flushed out
- * of the write buffer.
- *
- * In cases where we want to make sure that a write has been flushed
- * out of the write buffer before we proceed, for example when masking
- * a device interrupt before re-enabling IRQs in CPSR, we can use this
- * function, ixp2000_reg_wrb, which performs a write, a readback, and
- * issues a dummy instruction dependent on the value of the readback
- * (mov rX, rX) to make sure that the readback has completed before we
- * continue.
- */
-static inline void ixp2000_reg_wrb(volatile void *reg, unsigned long val)
-{
- unsigned long dummy;
-
- *((volatile unsigned long *)reg) = val;
-
- dummy = *((volatile unsigned long *)reg);
- __asm__ __volatile__("mov %0, %0" : "+r" (dummy));
-}
-
-/*
- * Boards may multiplex different devices on the 2nd channel of
- * the slowport interface that each need different configuration
- * settings. For example, the IXDP2400 uses channel 2 on the interface
- * to access the CPLD, the switch fabric card, and the media card. Each
- * one needs a different mode so drivers must save/restore the mode
- * before and after each operation.
- *
- * acquire_slowport(&your_config);
- * ...
- * do slowport operations
- * ...
- * release_slowport();
- *
- * Note that while you have the slowport, you are holding a spinlock,
- * so your code should be written as if you explicitly acquired a lock.
- *
- * The configuration only affects device 2 on the slowport, so the
- * MTD map driver does not acquire/release the slowport.
- */
-struct slowport_cfg {
- unsigned long CCR; /* Clock divide */
- unsigned long WTC; /* Write Timing Control */
- unsigned long RTC; /* Read Timing Control */
- unsigned long PCR; /* Protocol Control Register */
- unsigned long ADC; /* Address/Data Width Control */
-};
-
-
-void ixp2000_acquire_slowport(struct slowport_cfg *, struct slowport_cfg *);
-void ixp2000_release_slowport(struct slowport_cfg *);
-
-/*
- * IXP2400 A0/A1 and IXP2800 A0/A1/A2 have broken slowport that requires
- * tweaking of addresses in the MTD driver.
- */
-static inline unsigned ixp2000_has_broken_slowport(void)
-{
- unsigned long id = *IXP2000_PRODUCT_ID;
- unsigned long id_prod = id & (IXP2000_MAJ_PROD_TYPE_MASK |
- IXP2000_MIN_PROD_TYPE_MASK);
- return (((id_prod ==
- /* fixed in IXP2400-B0 */
- (IXP2000_MAJ_PROD_TYPE_IXP2000 |
- IXP2000_MIN_PROD_TYPE_IXP2400)) &&
- ((id & IXP2000_MAJ_REV_MASK) == 0)) ||
- ((id_prod ==
- /* fixed in IXP2800-B0 */
- (IXP2000_MAJ_PROD_TYPE_IXP2000 |
- IXP2000_MIN_PROD_TYPE_IXP2800)) &&
- ((id & IXP2000_MAJ_REV_MASK) == 0)) ||
- ((id_prod ==
- /* fixed in IXP2850-B0 */
- (IXP2000_MAJ_PROD_TYPE_IXP2000 |
- IXP2000_MIN_PROD_TYPE_IXP2850)) &&
- ((id & IXP2000_MAJ_REV_MASK) == 0)));
-}
-
-static inline unsigned int ixp2000_has_flash(void)
-{
- return ((*IXP2000_STRAP_OPTIONS) & (CFG_BOOT_PROM));
-}
-
-static inline unsigned int ixp2000_is_pcimaster(void)
-{
- return ((*IXP2000_STRAP_OPTIONS) & (CFG_PCI_BOOT_HOST));
-}
-
-void ixp2000_map_io(void);
-void ixp2000_uart_init(void);
-void ixp2000_init_irq(void);
-void ixp2000_init_time(unsigned long);
-void ixp2000_restart(char, const char *);
-unsigned long ixp2000_gettimeoffset(void);
-
-struct pci_sys_data;
-
-extern struct pci_ops ixp2000_pci_ops;
-u32 *ixp2000_pci_config_addr(unsigned int bus, unsigned int devfn, int where);
-void ixp2000_pci_preinit(void);
-int ixp2000_pci_setup(int, struct pci_sys_data*);
-int ixp2000_pci_read_config(struct pci_bus*, unsigned int, int, int, u32 *);
-int ixp2000_pci_write_config(struct pci_bus*, unsigned int, int, int, u32);
-
-/*
- * Several of the IXP2000 systems have banked flash so we need to extend the
- * flash_platform_data structure with some private pointers
- */
-struct ixp2000_flash_data {
- struct flash_platform_data *platform_data;
- int nr_banks;
- unsigned long (*bank_setup)(unsigned long);
-};
-
-struct ixp2000_i2c_pins {
- unsigned long sda_pin;
- unsigned long scl_pin;
-};
-
-
-#endif /* !__ASSEMBLY__ */
diff --git a/arch/arm/mach-ixp2000/include/mach/timex.h b/arch/arm/mach-ixp2000/include/mach/timex.h
deleted file mode 100644
index 835e659f93d4..000000000000
--- a/arch/arm/mach-ixp2000/include/mach/timex.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/timex.h
- *
- * IXP2000 architecture timex specifications
- */
-
-
-/*
- * Default clock is 50MHz APB, but platform code can override this
- */
-#define CLOCK_TICK_RATE 50000000
-
-
diff --git a/arch/arm/mach-ixp2000/include/mach/uncompress.h b/arch/arm/mach-ixp2000/include/mach/uncompress.h
deleted file mode 100644
index ce363087df78..000000000000
--- a/arch/arm/mach-ixp2000/include/mach/uncompress.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/include/mach/uncompress.h
- *
- *
- * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright 2002 Intel Corp.
- *
- * 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/serial_reg.h>
-
-#define UART_BASE 0xc0030000
-
-#define PHYS(x) ((volatile unsigned long *)(UART_BASE + x))
-
-#define UARTDR PHYS(0x00) /* Transmit reg dlab=0 */
-#define UARTDLL PHYS(0x00) /* Divisor Latch reg dlab=1*/
-#define UARTDLM PHYS(0x04) /* Divisor Latch reg dlab=1*/
-#define UARTIER PHYS(0x04) /* Interrupt enable reg */
-#define UARTFCR PHYS(0x08) /* FIFO control reg dlab =0*/
-#define UARTLCR PHYS(0x0c) /* Control reg */
-#define UARTSR PHYS(0x14) /* Status reg */
-
-
-static inline void putc(int c)
-{
- int j = 0x1000;
-
- while (--j && !(*UARTSR & UART_LSR_THRE))
- barrier();
-
- *UARTDR = c;
-}
-
-static inline void flush(void)
-{
-}
-
-#define arch_decomp_setup()
-#define arch_decomp_wdog()
diff --git a/arch/arm/mach-ixp2000/ixdp2400.c b/arch/arm/mach-ixp2000/ixdp2400.c
deleted file mode 100644
index 4ec44801d303..000000000000
--- a/arch/arm/mach-ixp2000/ixdp2400.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/ixdp2400.c
- *
- * IXDP2400 platform support
- *
- * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (C) 2002 Intel Corp.
- * Copyright (C) 2003-2004 MontaVista Software, 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/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/bitops.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-
-#include <asm/mach/pci.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/time.h>
-#include <asm/mach/flash.h>
-#include <asm/mach/arch.h>
-
-/*************************************************************************
- * IXDP2400 timer tick
- *************************************************************************/
-static void __init ixdp2400_timer_init(void)
-{
- int numerator, denominator;
- int denom_array[] = {2, 4, 8, 16, 1, 2, 4, 8};
-
- numerator = (*(IXDP2400_CPLD_SYS_CLK_M) & 0xFF) *2;
- denominator = denom_array[(*(IXDP2400_CPLD_SYS_CLK_N) & 0x7)];
-
- ixp2000_init_time(((3125000 * numerator) / (denominator)) / 2);
-}
-
-static struct sys_timer ixdp2400_timer = {
- .init = ixdp2400_timer_init,
- .offset = ixp2000_gettimeoffset,
-};
-
-/*************************************************************************
- * IXDP2400 PCI
- *************************************************************************/
-void __init ixdp2400_pci_preinit(void)
-{
- ixp2000_reg_write(IXP2000_PCI_ADDR_EXT, 0x00100000);
- ixp2000_pci_preinit();
- pcibios_setup("firmware");
-}
-
-int ixdp2400_pci_setup(int nr, struct pci_sys_data *sys)
-{
- sys->mem_offset = 0xe0000000;
-
- ixp2000_pci_setup(nr, sys);
-
- return 1;
-}
-
-static int __init ixdp2400_pci_map_irq(const struct pci_dev *dev, u8 slot,
- u8 pin)
-{
- if (ixdp2x00_master_npu()) {
-
- /*
- * Root bus devices. Slave NPU is only one with interrupt.
- * Everything else, we just return -1 b/c nothing else
- * on the root bus has interrupts.
- */
- if(!dev->bus->self) {
- if(dev->devfn == IXDP2X00_SLAVE_NPU_DEVFN )
- return IRQ_IXDP2400_INGRESS_NPU;
-
- return -1;
- }
-
- /*
- * Bridge behind the PMC slot.
- * NOTE: Only INTA from the PMC slot is routed. VERY BAD.
- */
- if(dev->bus->self->devfn == IXDP2X00_PMC_DEVFN &&
- dev->bus->parent->self->devfn == IXDP2X00_P2P_DEVFN &&
- !dev->bus->parent->self->bus->parent)
- return IRQ_IXDP2400_PMC;
-
- /*
- * Device behind the first bridge
- */
- if(dev->bus->self->devfn == IXDP2X00_P2P_DEVFN) {
- switch(dev->devfn) {
- case IXDP2400_MASTER_ENET_DEVFN:
- return IRQ_IXDP2400_ENET;
-
- case IXDP2400_MEDIA_DEVFN:
- return IRQ_IXDP2400_MEDIA_PCI;
-
- case IXDP2400_SWITCH_FABRIC_DEVFN:
- return IRQ_IXDP2400_SF_PCI;
-
- case IXDP2X00_PMC_DEVFN:
- return IRQ_IXDP2400_PMC;
- }
- }
-
- return -1;
- } else return IRQ_IXP2000_PCIB; /* Slave NIC interrupt */
-}
-
-
-static void ixdp2400_pci_postinit(void)
-{
- struct pci_dev *dev;
-
- if (ixdp2x00_master_npu()) {
- dev = pci_get_bus_and_slot(1, IXDP2400_SLAVE_ENET_DEVFN);
- pci_stop_and_remove_bus_device(dev);
- pci_dev_put(dev);
- } else {
- dev = pci_get_bus_and_slot(1, IXDP2400_MASTER_ENET_DEVFN);
- pci_stop_and_remove_bus_device(dev);
- pci_dev_put(dev);
-
- ixdp2x00_slave_pci_postinit();
- }
-}
-
-static struct hw_pci ixdp2400_pci __initdata = {
- .nr_controllers = 1,
- .ops = &ixp2000_pci_ops,
- .setup = ixdp2400_pci_setup,
- .preinit = ixdp2400_pci_preinit,
- .postinit = ixdp2400_pci_postinit,
- .map_irq = ixdp2400_pci_map_irq,
-};
-
-int __init ixdp2400_pci_init(void)
-{
- if (machine_is_ixdp2400())
- pci_common_init(&ixdp2400_pci);
-
- return 0;
-}
-
-subsys_initcall(ixdp2400_pci_init);
-
-void __init ixdp2400_init_irq(void)
-{
- ixdp2x00_init_irq(IXDP2400_CPLD_INT_STAT, IXDP2400_CPLD_INT_MASK, IXDP2400_NR_IRQS);
-}
-
-MACHINE_START(IXDP2400, "Intel IXDP2400 Development Platform")
- /* Maintainer: MontaVista Software, Inc. */
- .atag_offset = 0x100,
- .map_io = ixdp2x00_map_io,
- .init_irq = ixdp2400_init_irq,
- .timer = &ixdp2400_timer,
- .init_machine = ixdp2x00_init_machine,
- .restart = ixp2000_restart,
-MACHINE_END
-
diff --git a/arch/arm/mach-ixp2000/ixdp2800.c b/arch/arm/mach-ixp2000/ixdp2800.c
deleted file mode 100644
index 44378c31d177..000000000000
--- a/arch/arm/mach-ixp2000/ixdp2800.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/ixdp2800.c
- *
- * IXDP2800 platform support
- *
- * Original Author: Jeffrey Daly <jeffrey.daly@intel.com>
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (C) 2002 Intel Corp.
- * Copyright (C) 2003-2004 MontaVista Software, 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/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/bitops.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-
-#include <asm/mach/pci.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/time.h>
-#include <asm/mach/flash.h>
-#include <asm/mach/arch.h>
-
-/*************************************************************************
- * IXDP2800 timer tick
- *************************************************************************/
-
-static void __init ixdp2800_timer_init(void)
-{
- ixp2000_init_time(50000000);
-}
-
-static struct sys_timer ixdp2800_timer = {
- .init = ixdp2800_timer_init,
- .offset = ixp2000_gettimeoffset,
-};
-
-/*************************************************************************
- * IXDP2800 PCI
- *************************************************************************/
-static void __init ixdp2800_slave_disable_pci_master(void)
-{
- *IXP2000_PCI_CMDSTAT &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
-}
-
-static void __init ixdp2800_master_wait_for_slave(void)
-{
- volatile u32 *addr;
-
- printk(KERN_INFO "IXDP2800: waiting for slave NPU to configure "
- "its BAR sizes\n");
-
- addr = ixp2000_pci_config_addr(0, IXDP2X00_SLAVE_NPU_DEVFN,
- PCI_BASE_ADDRESS_1);
- do {
- *addr = 0xffffffff;
- cpu_relax();
- } while (*addr != 0xfe000008);
-
- addr = ixp2000_pci_config_addr(0, IXDP2X00_SLAVE_NPU_DEVFN,
- PCI_BASE_ADDRESS_2);
- do {
- *addr = 0xffffffff;
- cpu_relax();
- } while (*addr != 0xc0000008);
-
- /*
- * Configure the slave's SDRAM BAR by hand.
- */
- *addr = 0x40000008;
-}
-
-static void __init ixdp2800_slave_wait_for_master_enable(void)
-{
- printk(KERN_INFO "IXDP2800: waiting for master NPU to enable us\n");
-
- while ((*IXP2000_PCI_CMDSTAT & PCI_COMMAND_MASTER) == 0)
- cpu_relax();
-}
-
-void __init ixdp2800_pci_preinit(void)
-{
- printk("ixdp2x00_pci_preinit called\n");
-
- *IXP2000_PCI_ADDR_EXT = 0x0001e000;
-
- if (!ixdp2x00_master_npu())
- ixdp2800_slave_disable_pci_master();
-
- *IXP2000_PCI_SRAM_BASE_ADDR_MASK = (0x2000000 - 1) & ~0x3ffff;
- *IXP2000_PCI_DRAM_BASE_ADDR_MASK = (0x40000000 - 1) & ~0xfffff;
-
- ixp2000_pci_preinit();
-
- if (ixdp2x00_master_npu()) {
- /*
- * Wait until the slave set its SRAM/SDRAM BAR sizes
- * correctly before we proceed to scan and enumerate
- * the bus.
- */
- ixdp2800_master_wait_for_slave();
-
- /*
- * We configure the SDRAM BARs by hand because they
- * are 1G and fall outside of the regular allocated
- * PCI address space.
- */
- *IXP2000_PCI_SDRAM_BAR = 0x00000008;
- } else {
- /*
- * Wait for the master to complete scanning the bus
- * and assigning resources before we proceed to scan
- * the bus ourselves. Set pci=firmware to honor the
- * master's resource assignment.
- */
- ixdp2800_slave_wait_for_master_enable();
- pcibios_setup("firmware");
- }
-}
-
-/*
- * We assign the SDRAM BARs for the two IXP2800 CPUs by hand, outside
- * of the regular PCI window, because there's only 512M of outbound PCI
- * memory window on each IXP, while we need 1G for each of the BARs.
- */
-static void __devinit ixp2800_pci_fixup(struct pci_dev *dev)
-{
- if (machine_is_ixdp2800()) {
- dev->resource[2].start = 0;
- dev->resource[2].end = 0;
- dev->resource[2].flags = 0;
- }
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IXP2800, ixp2800_pci_fixup);
-
-static int __init ixdp2800_pci_setup(int nr, struct pci_sys_data *sys)
-{
- sys->mem_offset = 0x00000000;
-
- ixp2000_pci_setup(nr, sys);
-
- return 1;
-}
-
-static int __init ixdp2800_pci_map_irq(const struct pci_dev *dev, u8 slot,
- u8 pin)
-{
- if (ixdp2x00_master_npu()) {
-
- /*
- * Root bus devices. Slave NPU is only one with interrupt.
- * Everything else, we just return -1 which is invalid.
- */
- if(!dev->bus->self) {
- if(dev->devfn == IXDP2X00_SLAVE_NPU_DEVFN )
- return IRQ_IXDP2800_INGRESS_NPU;
-
- return -1;
- }
-
- /*
- * Bridge behind the PMC slot.
- */
- if(dev->bus->self->devfn == IXDP2X00_PMC_DEVFN &&
- dev->bus->parent->self->devfn == IXDP2X00_P2P_DEVFN &&
- !dev->bus->parent->self->bus->parent)
- return IRQ_IXDP2800_PMC;
-
- /*
- * Device behind the first bridge
- */
- if(dev->bus->self->devfn == IXDP2X00_P2P_DEVFN) {
- switch(dev->devfn) {
- case IXDP2X00_PMC_DEVFN:
- return IRQ_IXDP2800_PMC;
-
- case IXDP2800_MASTER_ENET_DEVFN:
- return IRQ_IXDP2800_EGRESS_ENET;
-
- case IXDP2800_SWITCH_FABRIC_DEVFN:
- return IRQ_IXDP2800_FABRIC;
- }
- }
-
- return -1;
- } else return IRQ_IXP2000_PCIB; /* Slave NIC interrupt */
-}
-
-static void __init ixdp2800_master_enable_slave(void)
-{
- volatile u32 *addr;
-
- printk(KERN_INFO "IXDP2800: enabling slave NPU\n");
-
- addr = (volatile u32 *)ixp2000_pci_config_addr(0,
- IXDP2X00_SLAVE_NPU_DEVFN,
- PCI_COMMAND);
-
- *addr |= PCI_COMMAND_MASTER;
-}
-
-static void __init ixdp2800_master_wait_for_slave_bus_scan(void)
-{
- volatile u32 *addr;
-
- printk(KERN_INFO "IXDP2800: waiting for slave to finish bus scan\n");
-
- addr = (volatile u32 *)ixp2000_pci_config_addr(0,
- IXDP2X00_SLAVE_NPU_DEVFN,
- PCI_COMMAND);
- while ((*addr & PCI_COMMAND_MEMORY) == 0)
- cpu_relax();
-}
-
-static void __init ixdp2800_slave_signal_bus_scan_completion(void)
-{
- printk(KERN_INFO "IXDP2800: bus scan done, signaling master\n");
- *IXP2000_PCI_CMDSTAT |= PCI_COMMAND_MEMORY;
-}
-
-static void __init ixdp2800_pci_postinit(void)
-{
- if (!ixdp2x00_master_npu()) {
- ixdp2x00_slave_pci_postinit();
- ixdp2800_slave_signal_bus_scan_completion();
- }
-}
-
-struct __initdata hw_pci ixdp2800_pci __initdata = {
- .nr_controllers = 1,
- .ops = &ixp2000_pci_ops,
- .setup = ixdp2800_pci_setup,
- .preinit = ixdp2800_pci_preinit,
- .postinit = ixdp2800_pci_postinit,
- .map_irq = ixdp2800_pci_map_irq,
-};
-
-int __init ixdp2800_pci_init(void)
-{
- if (machine_is_ixdp2800()) {
- struct pci_dev *dev;
-
- pci_common_init(&ixdp2800_pci);
- if (ixdp2x00_master_npu()) {
- dev = pci_get_bus_and_slot(1, IXDP2800_SLAVE_ENET_DEVFN);
- pci_stop_and_remove_bus_device(dev);
- pci_dev_put(dev);
-
- ixdp2800_master_enable_slave();
- ixdp2800_master_wait_for_slave_bus_scan();
- } else {
- dev = pci_get_bus_and_slot(1, IXDP2800_MASTER_ENET_DEVFN);
- pci_stop_and_remove_bus_device(dev);
- pci_dev_put(dev);
- }
- }
-
- return 0;
-}
-
-subsys_initcall(ixdp2800_pci_init);
-
-void __init ixdp2800_init_irq(void)
-{
- ixdp2x00_init_irq(IXDP2800_CPLD_INT_STAT, IXDP2800_CPLD_INT_MASK, IXDP2800_NR_IRQS);
-}
-
-MACHINE_START(IXDP2800, "Intel IXDP2800 Development Platform")
- /* Maintainer: MontaVista Software, Inc. */
- .atag_offset = 0x100,
- .map_io = ixdp2x00_map_io,
- .init_irq = ixdp2800_init_irq,
- .timer = &ixdp2800_timer,
- .init_machine = ixdp2x00_init_machine,
- .restart = ixp2000_restart,
-MACHINE_END
-
diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c
deleted file mode 100644
index 421e38dc0fac..000000000000
--- a/arch/arm/mach-ixp2000/ixdp2x00.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/ixdp2x00.c
- *
- * Code common to IXDP2400 and IXDP2800 platforms.
- *
- * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (C) 2002 Intel Corp.
- * Copyright (C) 2003-2004 MontaVista Software, 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/gpio.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/bitops.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-
-#include <asm/mach/pci.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/time.h>
-#include <asm/mach/flash.h>
-#include <asm/mach/arch.h>
-
-#include <mach/gpio-ixp2000.h>
-
-/*************************************************************************
- * IXDP2x00 IRQ Initialization
- *************************************************************************/
-static volatile unsigned long *board_irq_mask;
-static volatile unsigned long *board_irq_stat;
-static unsigned long board_irq_count;
-
-#ifdef CONFIG_ARCH_IXDP2400
-/*
- * Slowport configuration for accessing CPLD registers on IXDP2x00
- */
-static struct slowport_cfg slowport_cpld_cfg = {
- .CCR = SLOWPORT_CCR_DIV_2,
- .WTC = 0x00000070,
- .RTC = 0x00000070,
- .PCR = SLOWPORT_MODE_FLASH,
- .ADC = SLOWPORT_ADDR_WIDTH_24 | SLOWPORT_DATA_WIDTH_8
-};
-#endif
-
-static void ixdp2x00_irq_mask(struct irq_data *d)
-{
- unsigned long dummy;
- static struct slowport_cfg old_cfg;
-
- /*
- * This is ugly in common code but really don't know
- * of a better way to handle it. :(
- */
-#ifdef CONFIG_ARCH_IXDP2400
- if (machine_is_ixdp2400())
- ixp2000_acquire_slowport(&slowport_cpld_cfg, &old_cfg);
-#endif
-
- dummy = *board_irq_mask;
- dummy |= IXP2000_BOARD_IRQ_MASK(d->irq);
- ixp2000_reg_wrb(board_irq_mask, dummy);
-
-#ifdef CONFIG_ARCH_IXDP2400
- if (machine_is_ixdp2400())
- ixp2000_release_slowport(&old_cfg);
-#endif
-}
-
-static void ixdp2x00_irq_unmask(struct irq_data *d)
-{
- unsigned long dummy;
- static struct slowport_cfg old_cfg;
-
-#ifdef CONFIG_ARCH_IXDP2400
- if (machine_is_ixdp2400())
- ixp2000_acquire_slowport(&slowport_cpld_cfg, &old_cfg);
-#endif
-
- dummy = *board_irq_mask;
- dummy &= ~IXP2000_BOARD_IRQ_MASK(d->irq);
- ixp2000_reg_wrb(board_irq_mask, dummy);
-
- if (machine_is_ixdp2400())
- ixp2000_release_slowport(&old_cfg);
-}
-
-static void ixdp2x00_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
- volatile u32 ex_interrupt = 0;
- static struct slowport_cfg old_cfg;
- int i;
-
- desc->irq_data.chip->irq_mask(&desc->irq_data);
-
-#ifdef CONFIG_ARCH_IXDP2400
- if (machine_is_ixdp2400())
- ixp2000_acquire_slowport(&slowport_cpld_cfg, &old_cfg);
-#endif
- ex_interrupt = *board_irq_stat & 0xff;
- if (machine_is_ixdp2400())
- ixp2000_release_slowport(&old_cfg);
-
- if(!ex_interrupt) {
- printk(KERN_ERR "Spurious IXDP2x00 CPLD interrupt!\n");
- return;
- }
-
- for(i = 0; i < board_irq_count; i++) {
- if(ex_interrupt & (1 << i)) {
- int cpld_irq = IXP2000_BOARD_IRQ(0) + i;
- generic_handle_irq(cpld_irq);
- }
- }
-
- desc->irq_data.chip->irq_unmask(&desc->irq_data);
-}
-
-static struct irq_chip ixdp2x00_cpld_irq_chip = {
- .irq_ack = ixdp2x00_irq_mask,
- .irq_mask = ixdp2x00_irq_mask,
- .irq_unmask = ixdp2x00_irq_unmask
-};
-
-void __init ixdp2x00_init_irq(volatile unsigned long *stat_reg, volatile unsigned long *mask_reg, unsigned long nr_of_irqs)
-{
- unsigned int irq;
-
- ixp2000_init_irq();
-
- if (!ixdp2x00_master_npu())
- return;
-
- board_irq_stat = stat_reg;
- board_irq_mask = mask_reg;
- board_irq_count = nr_of_irqs;
-
- *board_irq_mask = 0xffffffff;
-
- for(irq = IXP2000_BOARD_IRQ(0); irq < IXP2000_BOARD_IRQ(board_irq_count); irq++) {
- irq_set_chip_and_handler(irq, &ixdp2x00_cpld_irq_chip,
- handle_level_irq);
- set_irq_flags(irq, IRQF_VALID);
- }
-
- /* Hook into PCI interrupt */
- irq_set_chained_handler(IRQ_IXP2000_PCIB, ixdp2x00_irq_handler);
-}
-
-/*************************************************************************
- * IXDP2x00 memory map
- *************************************************************************/
-static struct map_desc ixdp2x00_io_desc __initdata = {
- .virtual = IXDP2X00_VIRT_CPLD_BASE,
- .pfn = __phys_to_pfn(IXDP2X00_PHYS_CPLD_BASE),
- .length = IXDP2X00_CPLD_SIZE,
- .type = MT_DEVICE
-};
-
-void __init ixdp2x00_map_io(void)
-{
- ixp2000_map_io();
-
- iotable_init(&ixdp2x00_io_desc, 1);
-}
-
-/*************************************************************************
- * IXDP2x00-common PCI init
- *
- * The IXDP2[48]00 has a horrid PCI bus layout. Basically the board
- * contains two NPUs (ingress and egress) connected over PCI, both running
- * instances of the kernel. So far so good. Peers on the PCI bus running
- * Linux is a common design in telecom systems. The problem is that instead
- * of all the devices being controlled by a single host, different
- * devices are controlled by different NPUs on the same bus, leading to
- * multiple hosts on the bus. The exact bus layout looks like:
- *
- * Bus 0
- * Master NPU <-------------------+-------------------> Slave NPU
- * |
- * |
- * P2P
- * |
- *
- * Bus 1 |
- * <--+------+---------+---------+------+-->
- * | | | | |
- * | | | | |
- * ... Dev PMC Media Eth0 Eth1 ...
- *
- * The master controls all but Eth1, which is controlled by the
- * slave. What this means is that the both the master and the slave
- * have to scan the bus, but only one of them can enumerate the bus.
- * In addition, after the bus is scanned, each kernel must remove
- * the device(s) it does not control from the PCI dev list otherwise
- * a driver on each NPU will try to manage it and we will have horrible
- * conflicts. Oh..and the slave NPU needs to see the master NPU
- * for Intel's drivers to work properly. Closed source drivers...
- *
- * The way we deal with this is fairly simple but ugly:
- *
- * 1) Let master scan and enumerate the bus completely.
- * 2) Master deletes Eth1 from device list.
- * 3) Slave scans bus and then deletes all but Eth1 (Eth0 on slave)
- * from device list.
- * 4) Find HW designers and LART them.
- *
- * The boards also do not do normal PCI IRQ routing, or any sort of
- * sensical swizzling, so we just need to check where on the bus a
- * device sits and figure out to which CPLD pin the interrupt is routed.
- * See ixdp2[48]00.c files.
- *
- *************************************************************************/
-void ixdp2x00_slave_pci_postinit(void)
-{
- struct pci_dev *dev;
-
- /*
- * Remove PMC device is there is one
- */
- if((dev = pci_get_bus_and_slot(1, IXDP2X00_PMC_DEVFN))) {
- pci_stop_and_remove_bus_device(dev);
- pci_dev_put(dev);
- }
-
- dev = pci_get_bus_and_slot(0, IXDP2X00_21555_DEVFN);
- pci_stop_and_remove_bus_device(dev);
- pci_dev_put(dev);
-}
-
-/**************************************************************************
- * IXDP2x00 Machine Setup
- *************************************************************************/
-static struct flash_platform_data ixdp2x00_platform_data = {
- .map_name = "cfi_probe",
- .width = 1,
-};
-
-static struct ixp2000_flash_data ixdp2x00_flash_data = {
- .platform_data = &ixdp2x00_platform_data,
- .nr_banks = 1
-};
-
-static struct resource ixdp2x00_flash_resource = {
- .start = 0xc4000000,
- .end = 0xc4000000 + 0x00ffffff,
- .flags = IORESOURCE_MEM,
-};
-
-static struct platform_device ixdp2x00_flash = {
- .name = "IXP2000-Flash",
- .id = 0,
- .dev = {
- .platform_data = &ixdp2x00_flash_data,
- },
- .num_resources = 1,
- .resource = &ixdp2x00_flash_resource,
-};
-
-static struct ixp2000_i2c_pins ixdp2x00_i2c_gpio_pins = {
- .sda_pin = IXDP2X00_GPIO_SDA,
- .scl_pin = IXDP2X00_GPIO_SCL,
-};
-
-static struct platform_device ixdp2x00_i2c_controller = {
- .name = "IXP2000-I2C",
- .id = 0,
- .dev = {
- .platform_data = &ixdp2x00_i2c_gpio_pins,
- },
- .num_resources = 0
-};
-
-static struct platform_device *ixdp2x00_devices[] __initdata = {
- &ixdp2x00_flash,
- &ixdp2x00_i2c_controller
-};
-
-void __init ixdp2x00_init_machine(void)
-{
- gpio_line_set(IXDP2X00_GPIO_I2C_ENABLE, 1);
- gpio_line_config(IXDP2X00_GPIO_I2C_ENABLE, GPIO_OUT);
-
- platform_add_devices(ixdp2x00_devices, ARRAY_SIZE(ixdp2x00_devices));
- ixp2000_uart_init();
-}
-
diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c
deleted file mode 100644
index af8b801d7d59..000000000000
--- a/arch/arm/mach-ixp2000/ixdp2x01.c
+++ /dev/null
@@ -1,483 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/ixdp2x01.c
- *
- * Code common to Intel IXDP2401 and IXDP2801 platforms
- *
- * Original Author: Andrzej Mialkowski <andrzej.mialkowski@intel.com>
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (C) 2002-2003 Intel Corp.
- * Copyright (C) 2003-2004 MontaVista Software, 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/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/bitops.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/serial_core.h>
-#include <linux/platform_device.h>
-#include <linux/serial_8250.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-
-#include <asm/mach/pci.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/time.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
-
-/*************************************************************************
- * IXDP2x01 IRQ Handling
- *************************************************************************/
-static void ixdp2x01_irq_mask(struct irq_data *d)
-{
- ixp2000_reg_wrb(IXDP2X01_INT_MASK_SET_REG,
- IXP2000_BOARD_IRQ_MASK(d->irq));
-}
-
-static void ixdp2x01_irq_unmask(struct irq_data *d)
-{
- ixp2000_reg_write(IXDP2X01_INT_MASK_CLR_REG,
- IXP2000_BOARD_IRQ_MASK(d->irq));
-}
-
-static u32 valid_irq_mask;
-
-static void ixdp2x01_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
- u32 ex_interrupt;
- int i;
-
- desc->irq_data.chip->irq_mask(&desc->irq_data);
-
- ex_interrupt = *IXDP2X01_INT_STAT_REG & valid_irq_mask;
-
- if (!ex_interrupt) {
- printk(KERN_ERR "Spurious IXDP2X01 CPLD interrupt!\n");
- return;
- }
-
- for (i = 0; i < IXP2000_BOARD_IRQS; i++) {
- if (ex_interrupt & (1 << i)) {
- int cpld_irq = IXP2000_BOARD_IRQ(0) + i;
- generic_handle_irq(cpld_irq);
- }
- }
-
- desc->irq_data.chip->irq_unmask(&desc->irq_data);
-}
-
-static struct irq_chip ixdp2x01_irq_chip = {
- .irq_mask = ixdp2x01_irq_mask,
- .irq_ack = ixdp2x01_irq_mask,
- .irq_unmask = ixdp2x01_irq_unmask
-};
-
-/*
- * We only do anything if we are the master NPU on the board.
- * The slave NPU only has the ethernet chip going directly to
- * the PCIB interrupt input.
- */
-void __init ixdp2x01_init_irq(void)
-{
- int irq = 0;
-
- /* initialize chip specific interrupts */
- ixp2000_init_irq();
-
- if (machine_is_ixdp2401())
- valid_irq_mask = IXDP2401_VALID_IRQ_MASK;
- else
- valid_irq_mask = IXDP2801_VALID_IRQ_MASK;
-
- /* Mask all interrupts from CPLD, disable simulation */
- ixp2000_reg_write(IXDP2X01_INT_MASK_SET_REG, 0xffffffff);
- ixp2000_reg_wrb(IXDP2X01_INT_SIM_REG, 0);
-
- for (irq = NR_IXP2000_IRQS; irq < NR_IXDP2X01_IRQS; irq++) {
- if (irq & valid_irq_mask) {
- irq_set_chip_and_handler(irq, &ixdp2x01_irq_chip,
- handle_level_irq);
- set_irq_flags(irq, IRQF_VALID);
- } else {
- set_irq_flags(irq, 0);
- }
- }
-
- /* Hook into PCI interrupts */
- irq_set_chained_handler(IRQ_IXP2000_PCIB, ixdp2x01_irq_handler);
-}
-
-
-/*************************************************************************
- * IXDP2x01 memory map
- *************************************************************************/
-static struct map_desc ixdp2x01_io_desc __initdata = {
- .virtual = IXDP2X01_VIRT_CPLD_BASE,
- .pfn = __phys_to_pfn(IXDP2X01_PHYS_CPLD_BASE),
- .length = IXDP2X01_CPLD_REGION_SIZE,
- .type = MT_DEVICE
-};
-
-static void __init ixdp2x01_map_io(void)
-{
- ixp2000_map_io();
- iotable_init(&ixdp2x01_io_desc, 1);
-}
-
-
-/*************************************************************************
- * IXDP2x01 serial ports
- *************************************************************************/
-static struct plat_serial8250_port ixdp2x01_serial_port1[] = {
- {
- .mapbase = (unsigned long)IXDP2X01_UART1_PHYS_BASE,
- .membase = (char *)IXDP2X01_UART1_VIRT_BASE,
- .irq = IRQ_IXDP2X01_UART1,
- .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
- .iotype = UPIO_MEM32,
- .regshift = 2,
- .uartclk = IXDP2X01_UART_CLK,
- },
- { }
-};
-
-static struct resource ixdp2x01_uart_resource1 = {
- .start = IXDP2X01_UART1_PHYS_BASE,
- .end = IXDP2X01_UART1_PHYS_BASE + 0xffff,
- .flags = IORESOURCE_MEM,
-};
-
-static struct platform_device ixdp2x01_serial_device1 = {
- .name = "serial8250",
- .id = PLAT8250_DEV_PLATFORM1,
- .dev = {
- .platform_data = ixdp2x01_serial_port1,
- },
- .num_resources = 1,
- .resource = &ixdp2x01_uart_resource1,
-};
-
-static struct plat_serial8250_port ixdp2x01_serial_port2[] = {
- {
- .mapbase = (unsigned long)IXDP2X01_UART2_PHYS_BASE,
- .membase = (char *)IXDP2X01_UART2_VIRT_BASE,
- .irq = IRQ_IXDP2X01_UART2,
- .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
- .iotype = UPIO_MEM32,
- .regshift = 2,
- .uartclk = IXDP2X01_UART_CLK,
- },
- { }
-};
-
-static struct resource ixdp2x01_uart_resource2 = {
- .start = IXDP2X01_UART2_PHYS_BASE,
- .end = IXDP2X01_UART2_PHYS_BASE + 0xffff,
- .flags = IORESOURCE_MEM,
-};
-
-static struct platform_device ixdp2x01_serial_device2 = {
- .name = "serial8250",
- .id = PLAT8250_DEV_PLATFORM2,
- .dev = {
- .platform_data = ixdp2x01_serial_port2,
- },
- .num_resources = 1,
- .resource = &ixdp2x01_uart_resource2,
-};
-
-static void ixdp2x01_uart_init(void)
-{
- platform_device_register(&ixdp2x01_serial_device1);
- platform_device_register(&ixdp2x01_serial_device2);
-}
-
-
-/*************************************************************************
- * IXDP2x01 timer tick configuration
- *************************************************************************/
-static unsigned int ixdp2x01_clock;
-
-static int __init ixdp2x01_clock_setup(char *str)
-{
- ixdp2x01_clock = simple_strtoul(str, NULL, 10);
-
- return 1;
-}
-
-__setup("ixdp2x01_clock=", ixdp2x01_clock_setup);
-
-static void __init ixdp2x01_timer_init(void)
-{
- if (!ixdp2x01_clock)
- ixdp2x01_clock = 50000000;
-
- ixp2000_init_time(ixdp2x01_clock);
-}
-
-static struct sys_timer ixdp2x01_timer = {
- .init = ixdp2x01_timer_init,
- .offset = ixp2000_gettimeoffset,
-};
-
-/*************************************************************************
- * IXDP2x01 PCI
- *************************************************************************/
-void __init ixdp2x01_pci_preinit(void)
-{
- ixp2000_reg_write(IXP2000_PCI_ADDR_EXT, 0x00000000);
- ixp2000_pci_preinit();
- pcibios_setup("firmware");
-}
-
-#define DEVPIN(dev, pin) ((pin) | ((dev) << 3))
-
-static int __init ixdp2x01_pci_map_irq(const struct pci_dev *dev, u8 slot,
- u8 pin)
-{
- u8 bus = dev->bus->number;
- u32 devpin = DEVPIN(PCI_SLOT(dev->devfn), pin);
- struct pci_bus *tmp_bus = dev->bus;
-
- /* Primary bus, no interrupts here */
- if (bus == 0) {
- return -1;
- }
-
- /* Lookup first leaf in bus tree */
- while ((tmp_bus->parent != NULL) && (tmp_bus->parent->parent != NULL)) {
- tmp_bus = tmp_bus->parent;
- }
-
- /* Select between known bridges */
- switch (tmp_bus->self->devfn | (tmp_bus->self->bus->number << 8)) {
- /* Device is located after first MB bridge */
- case 0x0008:
- if (tmp_bus == dev->bus) {
- /* Device is located directly after first MB bridge */
- switch (devpin) {
- case DEVPIN(1, 1): /* Onboard 82546 ch 0 */
- if (machine_is_ixdp2401())
- return IRQ_IXDP2401_INTA_82546;
- return -1;
- case DEVPIN(1, 2): /* Onboard 82546 ch 1 */
- if (machine_is_ixdp2401())
- return IRQ_IXDP2401_INTB_82546;
- return -1;
- case DEVPIN(0, 1): /* PMC INTA# */
- return IRQ_IXDP2X01_SPCI_PMC_INTA;
- case DEVPIN(0, 2): /* PMC INTB# */
- return IRQ_IXDP2X01_SPCI_PMC_INTB;
- case DEVPIN(0, 3): /* PMC INTC# */
- return IRQ_IXDP2X01_SPCI_PMC_INTC;
- case DEVPIN(0, 4): /* PMC INTD# */
- return IRQ_IXDP2X01_SPCI_PMC_INTD;
- }
- }
- break;
- case 0x0010:
- if (tmp_bus == dev->bus) {
- /* Device is located directly after second MB bridge */
- /* Secondary bus of second bridge */
- switch (devpin) {
- case DEVPIN(0, 1): /* DB#0 */
- return IRQ_IXDP2X01_SPCI_DB_0;
- case DEVPIN(1, 1): /* DB#1 */
- return IRQ_IXDP2X01_SPCI_DB_1;
- }
- } else {
- /* Device is located indirectly after second MB bridge */
- /* Not supported now */
- }
- break;
- }
-
- return -1;
-}
-
-
-static int ixdp2x01_pci_setup(int nr, struct pci_sys_data *sys)
-{
- sys->mem_offset = 0xe0000000;
-
- if (machine_is_ixdp2801() || machine_is_ixdp28x5())
- sys->mem_offset -= ((*IXP2000_PCI_ADDR_EXT & 0xE000) << 16);
-
- return ixp2000_pci_setup(nr, sys);
-}
-
-struct hw_pci ixdp2x01_pci __initdata = {
- .nr_controllers = 1,
- .ops = &ixp2000_pci_ops,
- .setup = ixdp2x01_pci_setup,
- .preinit = ixdp2x01_pci_preinit,
- .map_irq = ixdp2x01_pci_map_irq,
-};
-
-int __init ixdp2x01_pci_init(void)
-{
- if (machine_is_ixdp2401() || machine_is_ixdp2801() ||\
- machine_is_ixdp28x5())
- pci_common_init(&ixdp2x01_pci);
-
- return 0;
-}
-
-subsys_initcall(ixdp2x01_pci_init);
-
-/*************************************************************************
- * IXDP2x01 Machine Initialization
- *************************************************************************/
-static struct flash_platform_data ixdp2x01_flash_platform_data = {
- .map_name = "cfi_probe",
- .width = 1,
-};
-
-static unsigned long ixdp2x01_flash_bank_setup(unsigned long ofs)
-{
- ixp2000_reg_wrb(IXDP2X01_CPLD_FLASH_REG,
- ((ofs >> IXDP2X01_FLASH_WINDOW_BITS) | IXDP2X01_CPLD_FLASH_INTERN));
- return (ofs & IXDP2X01_FLASH_WINDOW_MASK);
-}
-
-static struct ixp2000_flash_data ixdp2x01_flash_data = {
- .platform_data = &ixdp2x01_flash_platform_data,
- .bank_setup = ixdp2x01_flash_bank_setup
-};
-
-static struct resource ixdp2x01_flash_resource = {
- .start = 0xc4000000,
- .end = 0xc4000000 + 0x01ffffff,
- .flags = IORESOURCE_MEM,
-};
-
-static struct platform_device ixdp2x01_flash = {
- .name = "IXP2000-Flash",
- .id = 0,
- .dev = {
- .platform_data = &ixdp2x01_flash_data,
- },
- .num_resources = 1,
- .resource = &ixdp2x01_flash_resource,
-};
-
-static struct ixp2000_i2c_pins ixdp2x01_i2c_gpio_pins = {
- .sda_pin = IXDP2X01_GPIO_SDA,
- .scl_pin = IXDP2X01_GPIO_SCL,
-};
-
-static struct platform_device ixdp2x01_i2c_controller = {
- .name = "IXP2000-I2C",
- .id = 0,
- .dev = {
- .platform_data = &ixdp2x01_i2c_gpio_pins,
- },
- .num_resources = 0
-};
-
-static struct platform_device *ixdp2x01_devices[] __initdata = {
- &ixdp2x01_flash,
- &ixdp2x01_i2c_controller
-};
-
-static void __init ixdp2x01_init_machine(void)
-{
- ixp2000_reg_wrb(IXDP2X01_CPLD_FLASH_REG,
- (IXDP2X01_CPLD_FLASH_BANK_MASK | IXDP2X01_CPLD_FLASH_INTERN));
-
- ixdp2x01_flash_data.nr_banks =
- ((*IXDP2X01_CPLD_FLASH_REG & IXDP2X01_CPLD_FLASH_BANK_MASK) + 1);
-
- platform_add_devices(ixdp2x01_devices, ARRAY_SIZE(ixdp2x01_devices));
- ixp2000_uart_init();
- ixdp2x01_uart_init();
-}
-
-static void ixdp2401_restart(char mode, const char *cmd)
-{
- /*
- * Reset flash banking register so that we are pointing at
- * RedBoot bank.
- */
- ixp2000_reg_write(IXDP2X01_CPLD_FLASH_REG,
- ((0 >> IXDP2X01_FLASH_WINDOW_BITS)
- | IXDP2X01_CPLD_FLASH_INTERN));
- ixp2000_reg_wrb(IXDP2X01_CPLD_RESET_REG, 0xffffffff);
-
- ixp2000_restart(mode, cmd);
-}
-
-static void ixdp280x_restart(char mode, const char *cmd)
-{
- /*
- * On IXDP2801 we need to write this magic sequence to the CPLD
- * to cause a complete reset of the CPU and all external devices
- * and move the flash bank register back to 0.
- */
- unsigned long reset_reg = *IXDP2X01_CPLD_RESET_REG;
-
- reset_reg = 0x55AA0000 | (reset_reg & 0x0000FFFF);
- ixp2000_reg_write(IXDP2X01_CPLD_RESET_REG, reset_reg);
- ixp2000_reg_wrb(IXDP2X01_CPLD_RESET_REG, 0x80000000);
-
- ixp2000_restart(mode, cmd);
-}
-
-#ifdef CONFIG_ARCH_IXDP2401
-MACHINE_START(IXDP2401, "Intel IXDP2401 Development Platform")
- /* Maintainer: MontaVista Software, Inc. */
- .atag_offset = 0x100,
- .map_io = ixdp2x01_map_io,
- .init_irq = ixdp2x01_init_irq,
- .timer = &ixdp2x01_timer,
- .init_machine = ixdp2x01_init_machine,
- .restart = ixdp2401_restart,
-MACHINE_END
-#endif
-
-#ifdef CONFIG_ARCH_IXDP2801
-MACHINE_START(IXDP2801, "Intel IXDP2801 Development Platform")
- /* Maintainer: MontaVista Software, Inc. */
- .atag_offset = 0x100,
- .map_io = ixdp2x01_map_io,
- .init_irq = ixdp2x01_init_irq,
- .timer = &ixdp2x01_timer,
- .init_machine = ixdp2x01_init_machine,
- .restart = ixdp280x_restart,
-MACHINE_END
-
-/*
- * IXDP28x5 is basically an IXDP2801 with a different CPU but Intel
- * changed the machine ID in the bootloader
- */
-MACHINE_START(IXDP28X5, "Intel IXDP2805/2855 Development Platform")
- /* Maintainer: MontaVista Software, Inc. */
- .atag_offset = 0x100,
- .map_io = ixdp2x01_map_io,
- .init_irq = ixdp2x01_init_irq,
- .timer = &ixdp2x01_timer,
- .init_machine = ixdp2x01_init_machine,
- .restart = ixdp280x_restart,
-MACHINE_END
-#endif
-
-
diff --git a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c
deleted file mode 100644
index d706838db023..000000000000
--- a/arch/arm/mach-ixp2000/pci.c
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * arch/arm/mach-ixp2000/pci.c
- *
- * PCI routines for IXDP2400/IXDP2800 boards
- *
- * Original Author: Naeem Afzal <naeem.m.afzal@intel.com>
- * Maintained by: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright 2002 Intel Corp.
- * Copyright (C) 2003-2004 MontaVista Software, 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/sched.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <mach/hardware.h>
-
-#include <asm/mach/pci.h>
-
-static volatile int pci_master_aborts = 0;
-
-static int clear_master_aborts(void);
-
-u32 *
-ixp2000_pci_config_addr(unsigned int bus_nr, unsigned int devfn, int where)
-{
- u32 *paddress;
-
- if (PCI_SLOT(devfn) > 7)
- return 0;
-
- /* Must be dword aligned */
- where &= ~3;
-
- /*
- * For top bus, generate type 0, else type 1
- */
- if (!bus_nr) {
- /* only bits[23:16] are used for IDSEL */
- paddress = (u32 *) (IXP2000_PCI_CFG0_VIRT_BASE
- | (1 << (PCI_SLOT(devfn) + 16))
- | (PCI_FUNC(devfn) << 8) | where);
- } else {
- paddress = (u32 *) (IXP2000_PCI_CFG1_VIRT_BASE
- | (bus_nr << 16)
- | (PCI_SLOT(devfn) << 11)
- | (PCI_FUNC(devfn) << 8) | where);
- }
-
- return paddress;
-}
-
-/*
- * Mask table, bits to mask for quantity of size 1, 2 or 4 bytes.
- * 0 and 3 are not valid indexes...
- */
-static u32 bytemask[] = {
- /*0*/ 0,
- /*1*/ 0xff,
- /*2*/ 0xffff,
- /*3*/ 0,
- /*4*/ 0xffffffff,
-};
-
-
-int ixp2000_pci_read_config(struct pci_bus *bus, unsigned int devfn, int where,
- int size, u32 *value)
-{
- u32 n;
- u32 *addr;
-
- n = where % 4;
-
- addr = ixp2000_pci_config_addr(bus->number, devfn, where);
- if (!addr)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- pci_master_aborts = 0;
- *value = (*addr >> (8*n)) & bytemask[size];
- if (pci_master_aborts) {
- pci_master_aborts = 0;
- *value = 0xffffffff;
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-/*
- * We don't do error checks by calling clear_master_aborts() b/c the
- * assumption is that the caller did a read first to make sure a device
- * exists.
- */
-int ixp2000_pci_write_config(struct pci_bus *bus, unsigned int devfn, int where,
- int size, u32 value)
-{
- u32 mask;
- u32 *addr;
- u32 temp;
-
- mask = ~(bytemask[size] << ((where % 0x4) * 8));
- addr = ixp2000_pci_config_addr(bus->number, devfn, where);
- if (!addr)
- return PCIBIOS_DEVICE_NOT_FOUND;
- temp = (u32) (value) << ((where % 0x4) * 8);
- *addr = (*addr & mask) | temp;
-
- clear_master_aborts();
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-
-struct pci_ops ixp2000_pci_ops = {
- .read = ixp2000_pci_read_config,
- .write = ixp2000_pci_write_config
-};
-
-
-int ixp2000_pci_abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
-{
-
- volatile u32 temp;
- unsigned long flags;
-
- pci_master_aborts = 1;
-
- local_irq_save(flags);
- temp = *(IXP2000_PCI_CONTROL);
- if (temp & ((1 << 8) | (1 << 5))) {
- ixp2000_reg_wrb(IXP2000_PCI_CONTROL, temp);
- }
-
- temp = *(IXP2000_PCI_CMDSTAT);
- if (temp & (1 << 29)) {
- while (temp & (1 << 29)) {
- ixp2000_reg_write(IXP2000_PCI_CMDSTAT, temp);
- temp = *(IXP2000_PCI_CMDSTAT);
- }
- }
- local_irq_restore(flags);
-
- /*
- * If it was an imprecise abort, then we need to correct the
- * return address to be _after_ the instruction.
- */
- if (fsr & (1 << 10))
- regs->ARM_pc += 4;
-
- return 0;
-}
-
-int
-clear_master_aborts(void)
-{
- volatile u32 temp;
- unsigned long flags;
-
- local_irq_save(flags);
- temp = *(IXP2000_PCI_CONTROL);
- if (temp & ((1 << 8) | (1 << 5))) {
- ixp2000_reg_wrb(IXP2000_PCI_CONTROL, temp);
- }
-
- temp = *(IXP2000_PCI_CMDSTAT);
- if (temp & (1 << 29)) {
- while (temp & (1 << 29)) {
- ixp2000_reg_write(IXP2000_PCI_CMDSTAT, temp);
- temp = *(IXP2000_PCI_CMDSTAT);
- }
- }
- local_irq_restore(flags);
-
- return 0;
-}
-
-void __init
-ixp2000_pci_preinit(void)
-{
- pci_set_flags(0);
-
- pcibios_min_io = 0;
- pcibios_min_mem = 0;
-
-#ifndef CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO
- /*
- * Configure the PCI unit to properly byteswap I/O transactions,
- * and verify that it worked.
- */
- ixp2000_reg_write(IXP2000_PCI_CONTROL,
- (*IXP2000_PCI_CONTROL | PCI_CONTROL_IEE));
-
- if ((*IXP2000_PCI_CONTROL & PCI_CONTROL_IEE) == 0)
- panic("IXP2000: PCI I/O is broken on this ixp model, and "
- "the needed workaround has not been configured in");
-#endif
-
- hook_fault_code(16+6, ixp2000_pci_abort_handler, SIGBUS, 0,
- "PCI config cycle to non-existent device");
-}
-
-
-/*
- * IXP2000 systems often have large resource requirements, so we just
- * use our own resource space.
- */
-static struct resource ixp2000_pci_mem_space = {
- .start = 0xe0000000,
- .end = 0xffffffff,
- .flags = IORESOURCE_MEM,
- .name = "PCI Mem Space"
-};
-
-static struct resource ixp2000_pci_io_space = {
- .start = 0x00010000,
- .end = 0x0001ffff,
- .flags = IORESOURCE_IO,
- .name = "PCI I/O Space"
-};
-
-int ixp2000_pci_setup(int nr, struct pci_sys_data *sys)
-{
- if (nr >= 1)
- return 0;
-
- pci_add_resource_offset(&sys->resources,
- &ixp2000_pci_io_space, sys->io_offset);
- pci_add_resource_offset(&sys->resources,
- &ixp2000_pci_mem_space, sys->mem_offset);
-
- return 1;
-}
-
diff --git a/arch/arm/mach-ixp23xx/Kconfig b/arch/arm/mach-ixp23xx/Kconfig
deleted file mode 100644
index 982670ec3866..000000000000
--- a/arch/arm/mach-ixp23xx/Kconfig
+++ /dev/null
@@ -1,25 +0,0 @@
-if ARCH_IXP23XX
-
-config ARCH_SUPPORTS_BIG_ENDIAN
- bool
- default y
-
-menu "Intel IXP23xx Implementation Options"
-
-comment "IXP23xx Platforms"
-
-config MACH_ESPRESSO
- bool "Support IP Fabrics Double Espresso platform"
- help
-
-config MACH_IXDP2351
- bool "Support Intel IXDP2351 platform"
- help
-
-config MACH_ROADRUNNER
- bool "Support ADI RoadRunner platform"
- help
-
-endmenu
-
-endif
diff --git a/arch/arm/mach-ixp23xx/Makefile b/arch/arm/mach-ixp23xx/Makefile
deleted file mode 100644
index 288b371b6d03..000000000000
--- a/arch/arm/mach-ixp23xx/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-obj-y := core.o pci.o
-obj-m :=
-obj-n :=
-obj- :=
-
-obj-$(CONFIG_MACH_ESPRESSO) += espresso.o
-obj-$(CONFIG_MACH_IXDP2351) += ixdp2351.o
-obj-$(CONFIG_MACH_ROADRUNNER) += roadrunner.o
diff --git a/arch/arm/mach-ixp23xx/Makefile.boot b/arch/arm/mach-ixp23xx/Makefile.boot
deleted file mode 100644
index 44fb4a717c3f..000000000000
--- a/arch/arm/mach-ixp23xx/Makefile.boot
+++ /dev/null
@@ -1,2 +0,0 @@
- zreladdr-y += 0x00008000
-params_phys-y := 0x00000100
diff --git a/arch/arm/mach-ixp23xx/core.c b/arch/arm/mach-ixp23xx/core.c
deleted file mode 100644
index d34542425990..000000000000
--- a/arch/arm/mach-ixp23xx/core.c
+++ /dev/null
@@ -1,455 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/core.c
- *
- * Core routines for IXP23xx chips
- *
- * Author: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright 2005 (c) MontaVista Software, Inc.
- *
- * Based on 2.4 code Copyright 2004 (c) Intel Corporation
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/bitops.h>
-#include <linux/serial_8250.h>
-#include <linux/serial_core.h>
-#include <linux/device.h>
-#include <linux/mm.h>
-#include <linux/time.h>
-#include <linux/timex.h>
-
-#include <asm/types.h>
-#include <asm/setup.h>
-#include <asm/memory.h>
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/tlbflush.h>
-#include <asm/pgtable.h>
-#include <asm/system_misc.h>
-
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/arch.h>
-
-
-/*************************************************************************
- * Chip specific mappings shared by all IXP23xx systems
- *************************************************************************/
-static struct map_desc ixp23xx_io_desc[] __initdata = {
- { /* XSI-CPP CSRs */
- .virtual = IXP23XX_XSI2CPP_CSR_VIRT,
- .pfn = __phys_to_pfn(IXP23XX_XSI2CPP_CSR_PHYS),
- .length = IXP23XX_XSI2CPP_CSR_SIZE,
- .type = MT_DEVICE,
- }, { /* Expansion Bus Config */
- .virtual = IXP23XX_EXP_CFG_VIRT,
- .pfn = __phys_to_pfn(IXP23XX_EXP_CFG_PHYS),
- .length = IXP23XX_EXP_CFG_SIZE,
- .type = MT_DEVICE,
- }, { /* UART, Interrupt ctrl, GPIO, timers, NPEs, MACS,.... */
- .virtual = IXP23XX_PERIPHERAL_VIRT,
- .pfn = __phys_to_pfn(IXP23XX_PERIPHERAL_PHYS),
- .length = IXP23XX_PERIPHERAL_SIZE,
- .type = MT_DEVICE,
- }, { /* CAP CSRs */
- .virtual = IXP23XX_CAP_CSR_VIRT,
- .pfn = __phys_to_pfn(IXP23XX_CAP_CSR_PHYS),
- .length = IXP23XX_CAP_CSR_SIZE,
- .type = MT_DEVICE,
- }, { /* MSF CSRs */
- .virtual = IXP23XX_MSF_CSR_VIRT,
- .pfn = __phys_to_pfn(IXP23XX_MSF_CSR_PHYS),
- .length = IXP23XX_MSF_CSR_SIZE,
- .type = MT_DEVICE,
- }, { /* PCI I/O Space */
- .virtual = IXP23XX_PCI_IO_VIRT,
- .pfn = __phys_to_pfn(IXP23XX_PCI_IO_PHYS),
- .length = IXP23XX_PCI_IO_SIZE,
- .type = MT_DEVICE,
- }, { /* PCI Config Space */
- .virtual = IXP23XX_PCI_CFG_VIRT,
- .pfn = __phys_to_pfn(IXP23XX_PCI_CFG_PHYS),
- .length = IXP23XX_PCI_CFG_SIZE,
- .type = MT_DEVICE,
- }, { /* PCI local CFG CSRs */
- .virtual = IXP23XX_PCI_CREG_VIRT,
- .pfn = __phys_to_pfn(IXP23XX_PCI_CREG_PHYS),
- .length = IXP23XX_PCI_CREG_SIZE,
- .type = MT_DEVICE,
- }, { /* PCI MEM Space */
- .virtual = IXP23XX_PCI_MEM_VIRT,
- .pfn = __phys_to_pfn(IXP23XX_PCI_MEM_PHYS),
- .length = IXP23XX_PCI_MEM_SIZE,
- .type = MT_DEVICE,
- }
-};
-
-void __init ixp23xx_map_io(void)
-{
- iotable_init(ixp23xx_io_desc, ARRAY_SIZE(ixp23xx_io_desc));
-}
-
-
-/***************************************************************************
- * IXP23xx Interrupt Handling
- ***************************************************************************/
-enum ixp23xx_irq_type {
- IXP23XX_IRQ_LEVEL, IXP23XX_IRQ_EDGE
-};
-
-static void ixp23xx_config_irq(unsigned int, enum ixp23xx_irq_type);
-
-static int ixp23xx_irq_set_type(struct irq_data *d, unsigned int type)
-{
- int line = d->irq - IRQ_IXP23XX_GPIO6 + 6;
- u32 int_style;
- enum ixp23xx_irq_type irq_type;
- volatile u32 *int_reg;
-
- /*
- * Only GPIOs 6-15 are wired to interrupts on IXP23xx
- */
- if (line < 6 || line > 15)
- return -EINVAL;
-
- switch (type) {
- case IRQ_TYPE_EDGE_BOTH:
- int_style = IXP23XX_GPIO_STYLE_TRANSITIONAL;
- irq_type = IXP23XX_IRQ_EDGE;
- break;
- case IRQ_TYPE_EDGE_RISING:
- int_style = IXP23XX_GPIO_STYLE_RISING_EDGE;
- irq_type = IXP23XX_IRQ_EDGE;
- break;
- case IRQ_TYPE_EDGE_FALLING:
- int_style = IXP23XX_GPIO_STYLE_FALLING_EDGE;
- irq_type = IXP23XX_IRQ_EDGE;
- break;
- case IRQ_TYPE_LEVEL_HIGH:
- int_style = IXP23XX_GPIO_STYLE_ACTIVE_HIGH;
- irq_type = IXP23XX_IRQ_LEVEL;
- break;
- case IRQ_TYPE_LEVEL_LOW:
- int_style = IXP23XX_GPIO_STYLE_ACTIVE_LOW;
- irq_type = IXP23XX_IRQ_LEVEL;
- break;
- default:
- return -EINVAL;
- }
-
- ixp23xx_config_irq(d->irq, irq_type);
-
- if (line >= 8) { /* pins 8-15 */
- line -= 8;
- int_reg = (volatile u32 *)IXP23XX_GPIO_GPIT2R;
- } else { /* pins 0-7 */
- int_reg = (volatile u32 *)IXP23XX_GPIO_GPIT1R;
- }
-
- /*
- * Clear pending interrupts
- */
- *IXP23XX_GPIO_GPISR = (1 << line);
-
- /* Clear the style for the appropriate pin */
- *int_reg &= ~(IXP23XX_GPIO_STYLE_MASK <<
- (line * IXP23XX_GPIO_STYLE_SIZE));
-
- /* Set the new style */
- *int_reg |= (int_style << (line * IXP23XX_GPIO_STYLE_SIZE));
-
- return 0;
-}
-
-static void ixp23xx_irq_mask(struct irq_data *d)
-{
- volatile unsigned long *intr_reg;
- unsigned int irq = d->irq;
-
- if (irq >= 56)
- irq += 8;
-
- intr_reg = IXP23XX_INTR_EN1 + (irq / 32);
- *intr_reg &= ~(1 << (irq % 32));
-}
-
-static void ixp23xx_irq_ack(struct irq_data *d)
-{
- int line = d->irq - IRQ_IXP23XX_GPIO6 + 6;
-
- if ((line < 6) || (line > 15))
- return;
-
- *IXP23XX_GPIO_GPISR = (1 << line);
-}
-
-/*
- * Level triggered interrupts on GPIO lines can only be cleared when the
- * interrupt condition disappears.
- */
-static void ixp23xx_irq_level_unmask(struct irq_data *d)
-{
- volatile unsigned long *intr_reg;
- unsigned int irq = d->irq;
-
- ixp23xx_irq_ack(d);
-
- if (irq >= 56)
- irq += 8;
-
- intr_reg = IXP23XX_INTR_EN1 + (irq / 32);
- *intr_reg |= (1 << (irq % 32));
-}
-
-static void ixp23xx_irq_edge_unmask(struct irq_data *d)
-{
- volatile unsigned long *intr_reg;
- unsigned int irq = d->irq;
-
- if (irq >= 56)
- irq += 8;
-
- intr_reg = IXP23XX_INTR_EN1 + (irq / 32);
- *intr_reg |= (1 << (irq % 32));
-}
-
-static struct irq_chip ixp23xx_irq_level_chip = {
- .irq_ack = ixp23xx_irq_mask,
- .irq_mask = ixp23xx_irq_mask,
- .irq_unmask = ixp23xx_irq_level_unmask,
- .irq_set_type = ixp23xx_irq_set_type
-};
-
-static struct irq_chip ixp23xx_irq_edge_chip = {
- .irq_ack = ixp23xx_irq_ack,
- .irq_mask = ixp23xx_irq_mask,
- .irq_unmask = ixp23xx_irq_edge_unmask,
- .irq_set_type = ixp23xx_irq_set_type
-};
-
-static void ixp23xx_pci_irq_mask(struct irq_data *d)
-{
- unsigned int irq = d->irq;
-
- *IXP23XX_PCI_XSCALE_INT_ENABLE &= ~(1 << (IRQ_IXP23XX_INTA + 27 - irq));
-}
-
-static void ixp23xx_pci_irq_unmask(struct irq_data *d)
-{
- unsigned int irq = d->irq;
-
- *IXP23XX_PCI_XSCALE_INT_ENABLE |= (1 << (IRQ_IXP23XX_INTA + 27 - irq));
-}
-
-/*
- * TODO: Should this just be done at ASM level?
- */
-static void pci_handler(unsigned int irq, struct irq_desc *desc)
-{
- u32 pci_interrupt;
- unsigned int irqno;
-
- pci_interrupt = *IXP23XX_PCI_XSCALE_INT_STATUS;
-
- desc->irq_data.chip->irq_ack(&desc->irq_data);
-
- /* See which PCI_INTA, or PCI_INTB interrupted */
- if (pci_interrupt & (1 << 26)) {
- irqno = IRQ_IXP23XX_INTB;
- } else if (pci_interrupt & (1 << 27)) {
- irqno = IRQ_IXP23XX_INTA;
- } else {
- BUG();
- }
-
- generic_handle_irq(irqno);
-
- desc->irq_data.chip->irq_unmask(&desc->irq_data);
-}
-
-static struct irq_chip ixp23xx_pci_irq_chip = {
- .irq_ack = ixp23xx_pci_irq_mask,
- .irq_mask = ixp23xx_pci_irq_mask,
- .irq_unmask = ixp23xx_pci_irq_unmask
-};
-
-static void ixp23xx_config_irq(unsigned int irq, enum ixp23xx_irq_type type)
-{
- switch (type) {
- case IXP23XX_IRQ_LEVEL:
- irq_set_chip_and_handler(irq, &ixp23xx_irq_level_chip,
- handle_level_irq);
- break;
- case IXP23XX_IRQ_EDGE:
- irq_set_chip_and_handler(irq, &ixp23xx_irq_edge_chip,
- handle_edge_irq);
- break;
- }
- set_irq_flags(irq, IRQF_VALID);
-}
-
-void __init ixp23xx_init_irq(void)
-{
- int irq;
-
- /* Route everything to IRQ */
- *IXP23XX_INTR_SEL1 = 0x0;
- *IXP23XX_INTR_SEL2 = 0x0;
- *IXP23XX_INTR_SEL3 = 0x0;
- *IXP23XX_INTR_SEL4 = 0x0;
-
- /* Mask all sources */
- *IXP23XX_INTR_EN1 = 0x0;
- *IXP23XX_INTR_EN2 = 0x0;
- *IXP23XX_INTR_EN3 = 0x0;
- *IXP23XX_INTR_EN4 = 0x0;
-
- /*
- * Configure all IRQs for level-sensitive operation
- */
- for (irq = 0; irq <= NUM_IXP23XX_RAW_IRQS; irq++) {
- ixp23xx_config_irq(irq, IXP23XX_IRQ_LEVEL);
- }
-
- for (irq = IRQ_IXP23XX_INTA; irq <= IRQ_IXP23XX_INTB; irq++) {
- irq_set_chip_and_handler(irq, &ixp23xx_pci_irq_chip,
- handle_level_irq);
- set_irq_flags(irq, IRQF_VALID);
- }
-
- irq_set_chained_handler(IRQ_IXP23XX_PCI_INT_RPH, pci_handler);
-}
-
-
-/*************************************************************************
- * Timer-tick functions for IXP23xx
- *************************************************************************/
-#define CLOCK_TICKS_PER_USEC (CLOCK_TICK_RATE / USEC_PER_SEC)
-
-static unsigned long next_jiffy_time;
-
-static unsigned long
-ixp23xx_gettimeoffset(void)
-{
- unsigned long elapsed;
-
- elapsed = *IXP23XX_TIMER_CONT - (next_jiffy_time - LATCH);
-
- return elapsed / CLOCK_TICKS_PER_USEC;
-}
-
-static irqreturn_t
-ixp23xx_timer_interrupt(int irq, void *dev_id)
-{
- /* Clear Pending Interrupt by writing '1' to it */
- *IXP23XX_TIMER_STATUS = IXP23XX_TIMER1_INT_PEND;
- while ((signed long)(*IXP23XX_TIMER_CONT - next_jiffy_time) >= LATCH) {
- timer_tick();
- next_jiffy_time += LATCH;
- }
-
- return IRQ_HANDLED;
-}
-
-static struct irqaction ixp23xx_timer_irq = {
- .name = "IXP23xx Timer Tick",
- .handler = ixp23xx_timer_interrupt,
- .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
-};
-
-void __init ixp23xx_init_timer(void)
-{
- /* Clear Pending Interrupt by writing '1' to it */
- *IXP23XX_TIMER_STATUS = IXP23XX_TIMER1_INT_PEND;
-
- /* Setup the Timer counter value */
- *IXP23XX_TIMER1_RELOAD =
- (LATCH & ~IXP23XX_TIMER_RELOAD_MASK) | IXP23XX_TIMER_ENABLE;
-
- *IXP23XX_TIMER_CONT = 0;
- next_jiffy_time = LATCH;
-
- /* Connect the interrupt handler and enable the interrupt */
- setup_irq(IRQ_IXP23XX_TIMER1, &ixp23xx_timer_irq);
-}
-
-struct sys_timer ixp23xx_timer = {
- .init = ixp23xx_init_timer,
- .offset = ixp23xx_gettimeoffset,
-};
-
-
-/*************************************************************************
- * IXP23xx Platform Initialization
- *************************************************************************/
-static struct resource ixp23xx_uart_resources[] = {
- {
- .start = IXP23XX_UART1_PHYS,
- .end = IXP23XX_UART1_PHYS + 0x0fff,
- .flags = IORESOURCE_MEM
- }, {
- .start = IXP23XX_UART2_PHYS,
- .end = IXP23XX_UART2_PHYS + 0x0fff,
- .flags = IORESOURCE_MEM
- }
-};
-
-static struct plat_serial8250_port ixp23xx_uart_data[] = {
- {
- .mapbase = IXP23XX_UART1_PHYS,
- .membase = (char *)(IXP23XX_UART1_VIRT + 3),
- .irq = IRQ_IXP23XX_UART1,
- .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = IXP23XX_UART_XTAL,
- }, {
- .mapbase = IXP23XX_UART2_PHYS,
- .membase = (char *)(IXP23XX_UART2_VIRT + 3),
- .irq = IRQ_IXP23XX_UART2,
- .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = IXP23XX_UART_XTAL,
- },
- { },
-};
-
-static struct platform_device ixp23xx_uart = {
- .name = "serial8250",
- .id = 0,
- .dev.platform_data = ixp23xx_uart_data,
- .num_resources = 2,
- .resource = ixp23xx_uart_resources,
-};
-
-static struct platform_device *ixp23xx_devices[] __initdata = {
- &ixp23xx_uart,
-};
-
-void __init ixp23xx_sys_init(void)
-{
- /* by default, the idle code is disabled */
- disable_hlt();
-
- *IXP23XX_EXP_UNIT_FUSE |= 0xf;
- platform_add_devices(ixp23xx_devices, ARRAY_SIZE(ixp23xx_devices));
-}
-
-void ixp23xx_restart(char mode, const char *cmd)
-{
- /* Use on-chip reset capability */
- *IXP23XX_RESET0 |= IXP23XX_RST_ALL;
-}
diff --git a/arch/arm/mach-ixp23xx/espresso.c b/arch/arm/mach-ixp23xx/espresso.c
deleted file mode 100644
index d142d45dea12..000000000000
--- a/arch/arm/mach-ixp23xx/espresso.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/espresso.c
- *
- * Double Espresso-specific routines
- *
- * Author: Lennert Buytenhek <buytenh@wantstofly.org>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/bitops.h>
-#include <linux/ioport.h>
-#include <linux/serial_8250.h>
-#include <linux/serial_core.h>
-#include <linux/device.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/mtd/physmap.h>
-
-#include <asm/types.h>
-#include <asm/setup.h>
-#include <asm/memory.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-#include <asm/tlbflush.h>
-#include <asm/pgtable.h>
-
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/pci.h>
-
-static int __init espresso_pci_init(void)
-{
- if (machine_is_espresso())
- ixp23xx_pci_slave_init();
-
- return 0;
-};
-subsys_initcall(espresso_pci_init);
-
-static struct physmap_flash_data espresso_flash_data = {
- .width = 2,
-};
-
-static struct resource espresso_flash_resource = {
- .start = 0x90000000,
- .end = 0x91ffffff,
- .flags = IORESOURCE_MEM,
-};
-
-static struct platform_device espresso_flash = {
- .name = "physmap-flash",
- .id = 0,
- .dev = {
- .platform_data = &espresso_flash_data,
- },
- .num_resources = 1,
- .resource = &espresso_flash_resource,
-};
-
-static void __init espresso_init(void)
-{
- platform_device_register(&espresso_flash);
-
- /*
- * Mark flash as writeable.
- */
- IXP23XX_EXP_CS0[0] |= IXP23XX_FLASH_WRITABLE;
- IXP23XX_EXP_CS0[1] |= IXP23XX_FLASH_WRITABLE;
-
- ixp23xx_sys_init();
-}
-
-MACHINE_START(ESPRESSO, "IP Fabrics Double Espresso")
- /* Maintainer: Lennert Buytenhek */
- .map_io = ixp23xx_map_io,
- .init_irq = ixp23xx_init_irq,
- .timer = &ixp23xx_timer,
- .atag_offset = 0x100,
- .init_machine = espresso_init,
- .restart = ixp23xx_restart,
-MACHINE_END
diff --git a/arch/arm/mach-ixp23xx/include/mach/debug-macro.S b/arch/arm/mach-ixp23xx/include/mach/debug-macro.S
deleted file mode 100644
index 5ff524c13744..000000000000
--- a/arch/arm/mach-ixp23xx/include/mach/debug-macro.S
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/debug-macro.S
- *
- * Debugging macro include header
- *
- * Copyright (C) 1994-1999 Russell King
- * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * 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 <mach/ixp23xx.h>
-
- .macro addruart, rp, rv, tmp
- ldr \rp, =IXP23XX_PERIPHERAL_PHYS @ physical
- ldr \rv, =IXP23XX_PERIPHERAL_VIRT @ virtual
-#ifdef __ARMEB__
- orr \rp, \rp, #0x00000003
- orr \rv, \rv, #0x00000003
-#endif
- .endm
-
-#define UART_SHIFT 2
-#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-ixp23xx/include/mach/entry-macro.S b/arch/arm/mach-ixp23xx/include/mach/entry-macro.S
deleted file mode 100644
index 3fd2cb984e42..000000000000
--- a/arch/arm/mach-ixp23xx/include/mach/entry-macro.S
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/entry-macro.S
- */
-
- .macro get_irqnr_preamble, base, tmp
- .endm
-
- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
- ldr \irqnr, =(IXP23XX_INTC_VIRT + IXP23XX_INTR_IRQ_ENC_ST_OFFSET)
- ldr \irqnr, [\irqnr] @ get interrupt number
- cmp \irqnr, #0x0 @ spurious interrupt ?
- movne \irqnr, \irqnr, lsr #2 @ skip unwanted low order bits
- subne \irqnr, \irqnr, #1 @ convert to 0 based
-
-#if 0
- cmp \irqnr, #IRQ_IXP23XX_PCI_INT_RPH
- bne 1001f
- mov \irqnr, #IRQ_IXP23XX_INTA
-
- ldr \irqnr, =0xf5000030
-
- mov \tmp, #(1<<26)
- tst \irqnr, \tmp
- movne \irqnr, #IRQ_IXP23XX_INTB
-
- mov \tmp, #(1<<27)
- tst \irqnr, \tmp
- movne \irqnr, #IRQ_IXP23XX_INTA
-1001:
-#endif
- .endm
diff --git a/arch/arm/mach-ixp23xx/include/mach/hardware.h b/arch/arm/mach-ixp23xx/include/mach/hardware.h
deleted file mode 100644
index 60e55fa10238..000000000000
--- a/arch/arm/mach-ixp23xx/include/mach/hardware.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/hardware.h
- *
- * Copyright (C) 2002-2004 Intel Corporation.
- * Copyricht (C) 2005 MontaVista Software, Inc.
- *
- * 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.
- *
- * Hardware definitions for IXP23XX based systems
- */
-
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-/* PCI IO info */
-
-#include "ixp23xx.h"
-
-/*
- * Platform helper functions
- */
-#include "platform.h"
-
-/*
- * Platform-specific headers
- */
-#include "ixdp2351.h"
-
-
-#endif
diff --git a/arch/arm/mach-ixp23xx/include/mach/io.h b/arch/arm/mach-ixp23xx/include/mach/io.h
deleted file mode 100644
index a7aceb55c130..000000000000
--- a/arch/arm/mach-ixp23xx/include/mach/io.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/io.h
- *
- * Original Author: Naeem M Afzal <naeem.m.afzal@intel.com>
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright (C) 2003-2005 Intel Corp.
- * Copyright (C) 2005 MontaVista Software, Inc
- *
- * 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 __ASM_ARCH_IO_H
-#define __ASM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-#define __io(p) ((void __iomem*)((p) + IXP23XX_PCI_IO_VIRT))
-
-#endif
diff --git a/arch/arm/mach-ixp23xx/include/mach/irqs.h b/arch/arm/mach-ixp23xx/include/mach/irqs.h
deleted file mode 100644
index 3af33a04b8a2..000000000000
--- a/arch/arm/mach-ixp23xx/include/mach/irqs.h
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/irqs.h
- *
- * IRQ definitions for IXP23XX based systems
- *
- * Author: Naeem Afzal <naeem.m.afzal@intel.com>
- *
- * Copyright (C) 2003-2004 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.
- */
-
-#ifndef __ASM_ARCH_IRQS_H
-#define __ASM_ARCH_IRQS_H
-
-#define NR_IXP23XX_IRQS IRQ_IXP23XX_INTB+1
-#define IRQ_IXP23XX_EXTIRQS NR_IXP23XX_IRQS
-
-
-#define IRQ_IXP23XX_DBG0 0 /* Debug/Execution/MBox */
-#define IRQ_IXP23XX_DBG1 1 /* Debug/Execution/MBox */
-#define IRQ_IXP23XX_NPE_TRG 2 /* npe_trigger */
-#define IRQ_IXP23XX_TIMER1 3 /* Timer[0] */
-#define IRQ_IXP23XX_TIMER2 4 /* Timer[1] */
-#define IRQ_IXP23XX_TIMESTAMP 5 /* Timer[2], Time-stamp */
-#define IRQ_IXP23XX_WDOG 6 /* Time[3], Watchdog Timer */
-#define IRQ_IXP23XX_PCI_DBELL 7 /* PCI Doorbell */
-#define IRQ_IXP23XX_PCI_DMA1 8 /* PCI DMA Channel 1 */
-#define IRQ_IXP23XX_PCI_DMA2 9 /* PCI DMA Channel 2 */
-#define IRQ_IXP23XX_PCI_DMA3 10 /* PCI DMA Channel 3 */
-#define IRQ_IXP23XX_PCI_INT_RPH 11 /* pcxg_pci_int_rph */
-#define IRQ_IXP23XX_CPP_PMU 12 /* xpxg_pm_int_rpl */
-#define IRQ_IXP23XX_SWINT0 13 /* S/W Interrupt0 */
-#define IRQ_IXP23XX_SWINT1 14 /* S/W Interrupt1 */
-#define IRQ_IXP23XX_UART2 15 /* UART1 Interrupt */
-#define IRQ_IXP23XX_UART1 16 /* UART0 Interrupt */
-#define IRQ_IXP23XX_XSI_PMU_ROLLOVER 17 /* AHB Performance M. Unit counter rollover */
-#define IRQ_IXP23XX_XSI_AHB_PM0 18 /* intr_pm_o */
-#define IRQ_IXP23XX_XSI_AHB_ECE0 19 /* intr_ece_o */
-#define IRQ_IXP23XX_XSI_AHB_GASKET 20 /* gas_intr_o */
-#define IRQ_IXP23XX_XSI_CPP 21 /* xsi2cpp_int */
-#define IRQ_IXP23XX_CPP_XSI 22 /* cpp2xsi_int */
-#define IRQ_IXP23XX_ME_ATTN0 23 /* ME_ATTN */
-#define IRQ_IXP23XX_ME_ATTN1 24 /* ME_ATTN */
-#define IRQ_IXP23XX_ME_ATTN2 25 /* ME_ATTN */
-#define IRQ_IXP23XX_ME_ATTN3 26 /* ME_ATTN */
-#define IRQ_IXP23XX_PCI_ERR_RPH 27 /* PCXG_PCI_ERR_RPH */
-#define IRQ_IXP23XX_D0XG_ECC_CORR 28 /* D0XG_DRAM_ECC_CORR */
-#define IRQ_IXP23XX_D0XG_ECC_UNCORR 29 /* D0XG_DRAM_ECC_UNCORR */
-#define IRQ_IXP23XX_SRAM_ERR1 30 /* SRAM1_ERR */
-#define IRQ_IXP23XX_SRAM_ERR0 31 /* SRAM0_ERR */
-#define IRQ_IXP23XX_MEDIA_ERR 32 /* MEDIA_ERR */
-#define IRQ_IXP23XX_STH_DRAM_ECC_MAJ 33 /* STH_DRAM0_ECC_MAJ */
-#define IRQ_IXP23XX_GPIO6 34 /* GPIO0 interrupts */
-#define IRQ_IXP23XX_GPIO7 35 /* GPIO1 interrupts */
-#define IRQ_IXP23XX_GPIO8 36 /* GPIO2 interrupts */
-#define IRQ_IXP23XX_GPIO9 37 /* GPIO3 interrupts */
-#define IRQ_IXP23XX_GPIO10 38 /* GPIO4 interrupts */
-#define IRQ_IXP23XX_GPIO11 39 /* GPIO5 interrupts */
-#define IRQ_IXP23XX_GPIO12 40 /* GPIO6 interrupts */
-#define IRQ_IXP23XX_GPIO13 41 /* GPIO7 interrupts */
-#define IRQ_IXP23XX_GPIO14 42 /* GPIO8 interrupts */
-#define IRQ_IXP23XX_GPIO15 43 /* GPIO9 interrupts */
-#define IRQ_IXP23XX_SHAC_RING0 44 /* SHAC Ring Full */
-#define IRQ_IXP23XX_SHAC_RING1 45 /* SHAC Ring Full */
-#define IRQ_IXP23XX_SHAC_RING2 46 /* SHAC Ring Full */
-#define IRQ_IXP23XX_SHAC_RING3 47 /* SHAC Ring Full */
-#define IRQ_IXP23XX_SHAC_RING4 48 /* SHAC Ring Full */
-#define IRQ_IXP23XX_SHAC_RING5 49 /* SHAC Ring Full */
-#define IRQ_IXP23XX_SHAC_RING6 50 /* SHAC RING Full */
-#define IRQ_IXP23XX_SHAC_RING7 51 /* SHAC Ring Full */
-#define IRQ_IXP23XX_SHAC_RING8 52 /* SHAC Ring Full */
-#define IRQ_IXP23XX_SHAC_RING9 53 /* SHAC Ring Full */
-#define IRQ_IXP23XX_SHAC_RING10 54 /* SHAC Ring Full */
-#define IRQ_IXP23XX_SHAC_RING11 55 /* SHAC Ring Full */
-#define IRQ_IXP23XX_ME_THREAD_A0_ME0 56 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A1_ME0 57 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A2_ME0 58 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A3_ME0 59 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A4_ME0 60 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A5_ME0 61 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A6_ME0 62 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A7_ME0 63 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A8_ME1 64 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A9_ME1 65 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A10_ME1 66 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A11_ME1 67 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A12_ME1 68 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A13_ME1 69 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A14_ME1 70 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A15_ME1 71 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A16_ME2 72 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A17_ME2 73 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A18_ME2 74 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A19_ME2 75 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A20_ME2 76 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A21_ME2 77 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A22_ME2 78 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A23_ME2 79 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A24_ME3 80 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A25_ME3 81 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A26_ME3 82 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A27_ME3 83 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A28_ME3 84 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A29_ME3 85 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A30_ME3 86 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_A31_ME3 87 /* ME_THREAD_A */
-#define IRQ_IXP23XX_ME_THREAD_B0_ME0 88 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B1_ME0 89 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B2_ME0 90 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B3_ME0 91 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B4_ME0 92 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B5_ME0 93 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B6_ME0 94 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B7_ME0 95 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B8_ME1 96 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B9_ME1 97 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B10_ME1 98 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B11_ME1 99 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B12_ME1 100 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B13_ME1 101 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B14_ME1 102 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B15_ME1 103 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B16_ME2 104 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B17_ME2 105 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B18_ME2 106 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B19_ME2 107 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B20_ME2 108 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B21_ME2 109 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B22_ME2 110 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B23_ME2 111 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B24_ME3 112 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B25_ME3 113 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B26_ME3 114 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B27_ME3 115 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B28_ME3 116 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B29_ME3 117 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B30_ME3 118 /* ME_THREAD_B */
-#define IRQ_IXP23XX_ME_THREAD_B31_ME3 119 /* ME_THREAD_B */
-
-#define NUM_IXP23XX_RAW_IRQS 120
-
-#define IRQ_IXP23XX_INTA 120 /* Indirect pcxg_pci_int_rph */
-#define IRQ_IXP23XX_INTB 121 /* Indirect pcxg_pci_int_rph */
-
-#define NR_IXP23XX_IRQ (IRQ_IXP23XX_INTB + 1)
-
-/*
- * We default to 32 per-board IRQs. Increase this number if you need
- * more, but keep it realistic.
- */
-#define NR_IXP23XX_MACH_IRQS 32
-
-#define NR_IRQS (NR_IXP23XX_IRQS + NR_IXP23XX_MACH_IRQS)
-
-#define IXP23XX_MACH_IRQ(irq) (NR_IXP23XX_IRQ + (irq))
-
-
-/*
- * IXDP2351-specific interrupts
- */
-
-/*
- * External PCI interrupts signaled through INTB
- *
- */
-#define IXDP2351_INTB_IRQ_BASE 0
-#define IRQ_IXDP2351_INTA_82546 IXP23XX_MACH_IRQ(0)
-#define IRQ_IXDP2351_INTB_82546 IXP23XX_MACH_IRQ(1)
-#define IRQ_IXDP2351_SPCI_DB_0 IXP23XX_MACH_IRQ(2)
-#define IRQ_IXDP2351_SPCI_DB_1 IXP23XX_MACH_IRQ(3)
-#define IRQ_IXDP2351_SPCI_PMC_INTA IXP23XX_MACH_IRQ(4)
-#define IRQ_IXDP2351_SPCI_PMC_INTB IXP23XX_MACH_IRQ(5)
-#define IRQ_IXDP2351_SPCI_PMC_INTC IXP23XX_MACH_IRQ(6)
-#define IRQ_IXDP2351_SPCI_PMC_INTD IXP23XX_MACH_IRQ(7)
-#define IRQ_IXDP2351_SPCI_FIC IXP23XX_MACH_IRQ(8)
-
-#define IXDP2351_INTB_IRQ_BIT(irq) (irq - IXP23XX_MACH_IRQ(0))
-#define IXDP2351_INTB_IRQ_MASK(irq) (1 << IXDP2351_INTB_IRQ_BIT(irq))
-#define IXDP2351_INTB_IRQ_VALID 0x01FF
-#define IXDP2351_INTB_IRQ_NUM 16
-
-/*
- * Other external interrupts signaled through INTA
- */
-#define IXDP2351_INTA_IRQ_BASE 16
-#define IRQ_IXDP2351_IPMI_FROM IXP23XX_MACH_IRQ(16)
-#define IRQ_IXDP2351_125US IXP23XX_MACH_IRQ(17)
-#define IRQ_IXDP2351_DB_0_ADD IXP23XX_MACH_IRQ(18)
-#define IRQ_IXDP2351_DB_1_ADD IXP23XX_MACH_IRQ(19)
-#define IRQ_IXDP2351_DEBUG1 IXP23XX_MACH_IRQ(20)
-#define IRQ_IXDP2351_ADD_UART IXP23XX_MACH_IRQ(21)
-#define IRQ_IXDP2351_FIC_ADD IXP23XX_MACH_IRQ(24)
-#define IRQ_IXDP2351_CS8900 IXP23XX_MACH_IRQ(25)
-#define IRQ_IXDP2351_BBSRAM IXP23XX_MACH_IRQ(26)
-#define IRQ_IXDP2351_CONFIG_MEDIA IXP23XX_MACH_IRQ(27)
-#define IRQ_IXDP2351_CLOCK_REF IXP23XX_MACH_IRQ(28)
-#define IRQ_IXDP2351_A10_NP IXP23XX_MACH_IRQ(29)
-#define IRQ_IXDP2351_A11_NP IXP23XX_MACH_IRQ(30)
-#define IRQ_IXDP2351_DEBUG_NP IXP23XX_MACH_IRQ(31)
-
-#define IXDP2351_INTA_IRQ_BIT(irq) (irq - IXP23XX_MACH_IRQ(16))
-#define IXDP2351_INTA_IRQ_MASK(irq) (1 << IXDP2351_INTA_IRQ_BIT(irq))
-#define IXDP2351_INTA_IRQ_VALID 0xFF3F
-#define IXDP2351_INTA_IRQ_NUM 16
-
-
-/*
- * ADI RoadRunner IRQs
- */
-#define IRQ_ROADRUNNER_PCI_INTA IRQ_IXP23XX_INTA
-#define IRQ_ROADRUNNER_PCI_INTB IRQ_IXP23XX_INTB
-#define IRQ_ROADRUNNER_PCI_INTC IRQ_IXP23XX_GPIO11
-#define IRQ_ROADRUNNER_PCI_INTD IRQ_IXP23XX_GPIO12
-
-/*
- * Put new board definitions here
- */
-
-
-#endif
diff --git a/arch/arm/mach-ixp23xx/include/mach/ixdp2351.h b/arch/arm/mach-ixp23xx/include/mach/ixdp2351.h
deleted file mode 100644
index 663951027de5..000000000000
--- a/arch/arm/mach-ixp23xx/include/mach/ixdp2351.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/ixdp2351.h
- *
- * Register and other defines for IXDP2351
- *
- * Copyright (c) 2002-2004 Intel Corp.
- * Copytight (c) 2005 MontaVista Software, 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.
- */
-
-#ifndef __ASM_ARCH_IXDP2351_H
-#define __ASM_ARCH_IXDP2351_H
-
-/*
- * NP module memory map
- */
-#define IXDP2351_NP_PHYS_BASE (IXP23XX_EXP_BUS_CS4_BASE)
-#define IXDP2351_NP_PHYS_SIZE 0x00100000
-#define IXDP2351_NP_VIRT_BASE 0xeff00000
-
-#define IXDP2351_VIRT_CS8900_BASE (IXDP2351_NP_VIRT_BASE)
-#define IXDP2351_VIRT_CS8900_END (IXDP2351_VIRT_CS8900_BASE + 16)
-
-#define IXDP2351_VIRT_NP_CPLD_BASE (IXP23XX_EXP_BUS_CS4_BASE_VIRT + 0x00010000)
-
-#define IXDP2351_NP_CPLD_REG(reg) ((volatile u16 *)(IXDP2351_VIRT_NP_CPLD_BASE + reg))
-
-#define IXDP2351_NP_CPLD_RESET1_REG IXDP2351_NP_CPLD_REG(0x00)
-#define IXDP2351_NP_CPLD_LED_REG IXDP2351_NP_CPLD_REG(0x02)
-#define IXDP2351_NP_CPLD_VERSION_REG IXDP2351_NP_CPLD_REG(0x04)
-
-/*
- * Base board module memory map
- */
-
-#define IXDP2351_BB_BASE_PHYS (IXP23XX_EXP_BUS_CS5_BASE)
-#define IXDP2351_BB_SIZE 0x01000000
-#define IXDP2351_BB_BASE_VIRT (0xee000000)
-
-#define IXDP2351_BB_AREA_BASE(offset) (IXDP2351_BB_BASE_VIRT + offset)
-
-#define IXDP2351_VIRT_NVRAM_BASE IXDP2351_BB_AREA_BASE(0x0)
-#define IXDP2351_NVRAM_SIZE (0x20000)
-
-#define IXDP2351_VIRT_MB_IXF1104_BASE IXDP2351_BB_AREA_BASE(0x00020000)
-#define IXDP2351_VIRT_ADD_UART_BASE IXDP2351_BB_AREA_BASE(0x000240C0)
-#define IXDP2351_VIRT_FIC_BASE IXDP2351_BB_AREA_BASE(0x00200000)
-#define IXDP2351_VIRT_DB0_BASE IXDP2351_BB_AREA_BASE(0x00400000)
-#define IXDP2351_VIRT_DB1_BASE IXDP2351_BB_AREA_BASE(0x00600000)
-#define IXDP2351_VIRT_CPLD_BASE IXDP2351_BB_AREA_BASE(0x00024000)
-
-/*
- * On board CPLD registers
- */
-#define IXDP2351_CPLD_BB_REG(reg) ((volatile u16 *)(IXDP2351_VIRT_CPLD_BASE + reg))
-
-#define IXDP2351_CPLD_RESET0_REG IXDP2351_CPLD_BB_REG(0x00)
-#define IXDP2351_CPLD_RESET1_REG IXDP2351_CPLD_BB_REG(0x04)
-
-#define IXDP2351_CPLD_RESET1_MAGIC 0x55AA
-#define IXDP2351_CPLD_RESET1_ENABLE 0x8000
-
-#define IXDP2351_CPLD_FPGA_CONFIG_REG IXDP2351_CPLD_BB_REG(0x08)
-#define IXDP2351_CPLD_INTB_MASK_SET_REG IXDP2351_CPLD_BB_REG(0x10)
-#define IXDP2351_CPLD_INTA_MASK_SET_REG IXDP2351_CPLD_BB_REG(0x14)
-#define IXDP2351_CPLD_INTB_STAT_REG IXDP2351_CPLD_BB_REG(0x18)
-#define IXDP2351_CPLD_INTA_STAT_REG IXDP2351_CPLD_BB_REG(0x1C)
-#define IXDP2351_CPLD_INTB_RAW_REG IXDP2351_CPLD_BB_REG(0x20) /* read */
-#define IXDP2351_CPLD_INTA_RAW_REG IXDP2351_CPLD_BB_REG(0x24) /* read */
-#define IXDP2351_CPLD_INTB_MASK_CLR_REG IXDP2351_CPLD_INTB_RAW_REG /* write */
-#define IXDP2351_CPLD_INTA_MASK_CLR_REG IXDP2351_CPLD_INTA_RAW_REG /* write */
-#define IXDP2351_CPLD_INTB_SIM_REG IXDP2351_CPLD_BB_REG(0x28)
-#define IXDP2351_CPLD_INTA_SIM_REG IXDP2351_CPLD_BB_REG(0x2C)
- /* Interrupt bits are defined in irqs.h */
-#define IXDP2351_CPLD_BB_GBE0_REG IXDP2351_CPLD_BB_REG(0x30)
-#define IXDP2351_CPLD_BB_GBE1_REG IXDP2351_CPLD_BB_REG(0x34)
-
-/* #define IXDP2351_CPLD_BB_MISC_REG IXDP2351_CPLD_REG(0x1C) */
-/* #define IXDP2351_CPLD_BB_MISC_REV_MASK 0xFF */
-/* #define IXDP2351_CPLD_BB_GDXCS0_REG IXDP2351_CPLD_REG(0x24) */
-/* #define IXDP2351_CPLD_BB_GDXCS1_REG IXDP2351_CPLD_REG(0x28) */
-/* #define IXDP2351_CPLD_BB_CLOCK_REG IXDP2351_CPLD_REG(0x04) */
-
-
-#endif
diff --git a/arch/arm/mach-ixp23xx/include/mach/ixp23xx.h b/arch/arm/mach-ixp23xx/include/mach/ixp23xx.h
deleted file mode 100644
index 6d02481b1d6d..000000000000
--- a/arch/arm/mach-ixp23xx/include/mach/ixp23xx.h
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/ixp23xx.h
- *
- * Register definitions for IXP23XX
- *
- * Copyright (C) 2003-2005 Intel Corporation.
- * Copyright (C) 2005 MontaVista Software, Inc.
- *
- * Maintainer: Deepak Saxena <dsaxena@plexity.net>
- *
- * 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 __ASM_ARCH_IXP23XX_H
-#define __ASM_ARCH_IXP23XX_H
-
-/*
- * IXP2300 linux memory map:
- *
- * virt phys size
- * fffd0000 a0000000 64K XSI2CPP_CSR
- * fffc0000 c4000000 4K EXP_CFG
- * fff00000 c8000000 64K PERIPHERAL
- * fe000000 1c0000000 16M CAP_CSR
- * fd000000 1c8000000 16M MSF_CSR
- * fb000000 16M ---
- * fa000000 1d8000000 32M PCI_IO
- * f8000000 1da000000 32M PCI_CFG
- * f6000000 1de000000 32M PCI_CREG
- * f4000000 32M ---
- * f0000000 1e0000000 64M PCI_MEM
- * e[c-f]000000 per-platform mappings
- */
-
-
-/****************************************************************************
- * Static mappings.
- ****************************************************************************/
-#define IXP23XX_XSI2CPP_CSR_PHYS 0xa0000000
-#define IXP23XX_XSI2CPP_CSR_VIRT 0xfffd0000
-#define IXP23XX_XSI2CPP_CSR_SIZE 0x00010000
-
-#define IXP23XX_EXP_CFG_PHYS 0xc4000000
-#define IXP23XX_EXP_CFG_VIRT 0xfffc0000
-#define IXP23XX_EXP_CFG_SIZE 0x00001000
-
-#define IXP23XX_PERIPHERAL_PHYS 0xc8000000
-#define IXP23XX_PERIPHERAL_VIRT 0xfff00000
-#define IXP23XX_PERIPHERAL_SIZE 0x00010000
-
-#define IXP23XX_CAP_CSR_PHYS 0x1c0000000ULL
-#define IXP23XX_CAP_CSR_VIRT 0xfe000000
-#define IXP23XX_CAP_CSR_SIZE 0x01000000
-
-#define IXP23XX_MSF_CSR_PHYS 0x1c8000000ULL
-#define IXP23XX_MSF_CSR_VIRT 0xfd000000
-#define IXP23XX_MSF_CSR_SIZE 0x01000000
-
-#define IXP23XX_PCI_IO_PHYS 0x1d8000000ULL
-#define IXP23XX_PCI_IO_VIRT 0xfa000000
-#define IXP23XX_PCI_IO_SIZE 0x02000000
-
-#define IXP23XX_PCI_CFG_PHYS 0x1da000000ULL
-#define IXP23XX_PCI_CFG_VIRT 0xf8000000
-#define IXP23XX_PCI_CFG_SIZE 0x02000000
-#define IXP23XX_PCI_CFG0_VIRT IXP23XX_PCI_CFG_VIRT
-#define IXP23XX_PCI_CFG1_VIRT (IXP23XX_PCI_CFG_VIRT + 0x01000000)
-
-#define IXP23XX_PCI_CREG_PHYS 0x1de000000ULL
-#define IXP23XX_PCI_CREG_VIRT 0xf6000000
-#define IXP23XX_PCI_CREG_SIZE 0x02000000
-#define IXP23XX_PCI_CSR_VIRT (IXP23XX_PCI_CREG_VIRT + 0x01000000)
-
-#define IXP23XX_PCI_MEM_START 0xe0000000
-#define IXP23XX_PCI_MEM_PHYS 0x1e0000000ULL
-#define IXP23XX_PCI_MEM_VIRT 0xf0000000
-#define IXP23XX_PCI_MEM_SIZE 0x04000000
-
-
-/****************************************************************************
- * XSI2CPP CSRs.
- ****************************************************************************/
-#define IXP23XX_XSI2CPP_REG(x) ((volatile unsigned long *)(IXP23XX_XSI2CPP_CSR_VIRT + (x)))
-#define IXP23XX_CPP2XSI_CURR_XFER_REG3 IXP23XX_XSI2CPP_REG(0xf8)
-#define IXP23XX_CPP2XSI_ADDR_31 (1 << 19)
-#define IXP23XX_CPP2XSI_PSH_OFF (1 << 20)
-#define IXP23XX_CPP2XSI_COH_OFF (1 << 21)
-
-
-/****************************************************************************
- * Expansion Bus Config.
- ****************************************************************************/
-#define IXP23XX_EXP_CFG_REG(x) ((volatile unsigned long *)(IXP23XX_EXP_CFG_VIRT + (x)))
-#define IXP23XX_EXP_CS0 IXP23XX_EXP_CFG_REG(0x00)
-#define IXP23XX_EXP_CS1 IXP23XX_EXP_CFG_REG(0x04)
-#define IXP23XX_EXP_CS2 IXP23XX_EXP_CFG_REG(0x08)
-#define IXP23XX_EXP_CS3 IXP23XX_EXP_CFG_REG(0x0c)
-#define IXP23XX_EXP_CS4 IXP23XX_EXP_CFG_REG(0x10)
-#define IXP23XX_EXP_CS5 IXP23XX_EXP_CFG_REG(0x14)
-#define IXP23XX_EXP_CS6 IXP23XX_EXP_CFG_REG(0x18)
-#define IXP23XX_EXP_CS7 IXP23XX_EXP_CFG_REG(0x1c)
-#define IXP23XX_FLASH_WRITABLE (0x2)
-#define IXP23XX_FLASH_BUS8 (0x1)
-
-#define IXP23XX_EXP_CFG0 IXP23XX_EXP_CFG_REG(0x20)
-#define IXP23XX_EXP_CFG1 IXP23XX_EXP_CFG_REG(0x24)
-#define IXP23XX_EXP_CFG0_MEM_MAP (1 << 31)
-#define IXP23XX_EXP_CFG0_XSCALE_SPEED_SEL (3 << 22)
-#define IXP23XX_EXP_CFG0_XSCALE_SPEED_EN (1 << 21)
-#define IXP23XX_EXP_CFG0_CPP_SPEED_SEL (3 << 19)
-#define IXP23XX_EXP_CFG0_CPP_SPEED_EN (1 << 18)
-#define IXP23XX_EXP_CFG0_PCI_SWIN (3 << 16)
-#define IXP23XX_EXP_CFG0_PCI_DWIN (3 << 14)
-#define IXP23XX_EXP_CFG0_PCI33_MODE (1 << 13)
-#define IXP23XX_EXP_CFG0_QDR_SPEED_SEL (1 << 12)
-#define IXP23XX_EXP_CFG0_CPP_DIV_SEL (1 << 5)
-#define IXP23XX_EXP_CFG0_XSI_NOT_PRES (1 << 4)
-#define IXP23XX_EXP_CFG0_PROM_BOOT (1 << 3)
-#define IXP23XX_EXP_CFG0_PCI_ARB (1 << 2)
-#define IXP23XX_EXP_CFG0_PCI_HOST (1 << 1)
-#define IXP23XX_EXP_CFG0_FLASH_WIDTH (1 << 0)
-
-#define IXP23XX_EXP_UNIT_FUSE IXP23XX_EXP_CFG_REG(0x28)
-#define IXP23XX_EXP_MSF_MUX IXP23XX_EXP_CFG_REG(0x30)
-#define IXP23XX_EXP_CFG_FUSE IXP23XX_EXP_CFG_REG(0x34)
-
-#define IXP23XX_EXP_BUS_PHYS 0x90000000
-#define IXP23XX_EXP_BUS_WINDOW_SIZE 0x01000000
-
-#define IXP23XX_EXP_BUS_CS0_BASE (IXP23XX_EXP_BUS_PHYS + 0x00000000)
-#define IXP23XX_EXP_BUS_CS1_BASE (IXP23XX_EXP_BUS_PHYS + 0x01000000)
-#define IXP23XX_EXP_BUS_CS2_BASE (IXP23XX_EXP_BUS_PHYS + 0x02000000)
-#define IXP23XX_EXP_BUS_CS3_BASE (IXP23XX_EXP_BUS_PHYS + 0x03000000)
-#define IXP23XX_EXP_BUS_CS4_BASE (IXP23XX_EXP_BUS_PHYS + 0x04000000)
-#define IXP23XX_EXP_BUS_CS5_BASE (IXP23XX_EXP_BUS_PHYS + 0x05000000)
-#define IXP23XX_EXP_BUS_CS6_BASE (IXP23XX_EXP_BUS_PHYS + 0x06000000)
-#define IXP23XX_EXP_BUS_CS7_BASE (IXP23XX_EXP_BUS_PHYS + 0x07000000)
-
-
-/****************************************************************************
- * Peripherals.
- ****************************************************************************/
-#define IXP23XX_UART1_VIRT (IXP23XX_PERIPHERAL_VIRT + 0x0000)
-#define IXP23XX_UART2_VIRT (IXP23XX_PERIPHERAL_VIRT + 0x1000)
-#define IXP23XX_PMU_VIRT (IXP23XX_PERIPHERAL_VIRT + 0x2000)
-#define IXP23XX_INTC_VIRT (IXP23XX_PERIPHERAL_VIRT + 0x3000)
-#define IXP23XX_GPIO_VIRT (IXP23XX_PERIPHERAL_VIRT + 0x4000)
-#define IXP23XX_TIMER_VIRT (IXP23XX_PERIPHERAL_VIRT + 0x5000)
-#define IXP23XX_NPE0_VIRT (IXP23XX_PERIPHERAL_VIRT + 0x6000)
-#define IXP23XX_DSR_VIRT (IXP23XX_PERIPHERAL_VIRT + 0x7000)
-#define IXP23XX_NPE1_VIRT (IXP23XX_PERIPHERAL_VIRT + 0x8000)
-#define IXP23XX_ETH0_VIRT (IXP23XX_PERIPHERAL_VIRT + 0x9000)
-#define IXP23XX_ETH1_VIRT (IXP23XX_PERIPHERAL_VIRT + 0xA000)
-#define IXP23XX_GIG0_VIRT (IXP23XX_PERIPHERAL_VIRT + 0xB000)
-#define IXP23XX_GIG1_VIRT (IXP23XX_PERIPHERAL_VIRT + 0xC000)
-#define IXP23XX_DDRS_VIRT (IXP23XX_PERIPHERAL_VIRT + 0xD000)
-
-#define IXP23XX_UART1_PHYS (IXP23XX_PERIPHERAL_PHYS + 0x0000)
-#define IXP23XX_UART2_PHYS (IXP23XX_PERIPHERAL_PHYS + 0x1000)
-#define IXP23XX_PMU_PHYS (IXP23XX_PERIPHERAL_PHYS + 0x2000)
-#define IXP23XX_INTC_PHYS (IXP23XX_PERIPHERAL_PHYS + 0x3000)
-#define IXP23XX_GPIO_PHYS (IXP23XX_PERIPHERAL_PHYS + 0x4000)
-#define IXP23XX_TIMER_PHYS (IXP23XX_PERIPHERAL_PHYS + 0x5000)
-#define IXP23XX_NPE0_PHYS (IXP23XX_PERIPHERAL_PHYS + 0x6000)
-#define IXP23XX_DSR_PHYS (IXP23XX_PERIPHERAL_PHYS + 0x7000)
-#define IXP23XX_NPE1_PHYS (IXP23XX_PERIPHERAL_PHYS + 0x8000)
-#define IXP23XX_ETH0_PHYS (IXP23XX_PERIPHERAL_PHYS + 0x9000)
-#define IXP23XX_ETH1_PHYS (IXP23XX_PERIPHERAL_PHYS + 0xA000)
-#define IXP23XX_GIG0_PHYS (IXP23XX_PERIPHERAL_PHYS + 0xB000)
-#define IXP23XX_GIG1_PHYS (IXP23XX_PERIPHERAL_PHYS + 0xC000)
-#define IXP23XX_DDRS_PHYS (IXP23XX_PERIPHERAL_PHYS + 0xD000)
-
-
-/****************************************************************************
- * Interrupt controller.
- ****************************************************************************/
-#define IXP23XX_INTC_REG(x) ((volatile unsigned long *)(IXP23XX_INTC_VIRT + (x)))
-#define IXP23XX_INTR_ST1 IXP23XX_INTC_REG(0x00)
-#define IXP23XX_INTR_ST2 IXP23XX_INTC_REG(0x04)
-#define IXP23XX_INTR_ST3 IXP23XX_INTC_REG(0x08)
-#define IXP23XX_INTR_ST4 IXP23XX_INTC_REG(0x0c)
-#define IXP23XX_INTR_EN1 IXP23XX_INTC_REG(0x10)
-#define IXP23XX_INTR_EN2 IXP23XX_INTC_REG(0x14)
-#define IXP23XX_INTR_EN3 IXP23XX_INTC_REG(0x18)
-#define IXP23XX_INTR_EN4 IXP23XX_INTC_REG(0x1c)
-#define IXP23XX_INTR_SEL1 IXP23XX_INTC_REG(0x20)
-#define IXP23XX_INTR_SEL2 IXP23XX_INTC_REG(0x24)
-#define IXP23XX_INTR_SEL3 IXP23XX_INTC_REG(0x28)
-#define IXP23XX_INTR_SEL4 IXP23XX_INTC_REG(0x2c)
-#define IXP23XX_INTR_IRQ_ST1 IXP23XX_INTC_REG(0x30)
-#define IXP23XX_INTR_IRQ_ST2 IXP23XX_INTC_REG(0x34)
-#define IXP23XX_INTR_IRQ_ST3 IXP23XX_INTC_REG(0x38)
-#define IXP23XX_INTR_IRQ_ST4 IXP23XX_INTC_REG(0x3c)
-#define IXP23XX_INTR_IRQ_ENC_ST_OFFSET 0x54
-
-
-/****************************************************************************
- * GPIO.
- ****************************************************************************/
-#define IXP23XX_GPIO_REG(x) ((volatile unsigned long *)(IXP23XX_GPIO_VIRT + (x)))
-#define IXP23XX_GPIO_GPOUTR IXP23XX_GPIO_REG(0x00)
-#define IXP23XX_GPIO_GPOER IXP23XX_GPIO_REG(0x04)
-#define IXP23XX_GPIO_GPINR IXP23XX_GPIO_REG(0x08)
-#define IXP23XX_GPIO_GPISR IXP23XX_GPIO_REG(0x0c)
-#define IXP23XX_GPIO_GPIT1R IXP23XX_GPIO_REG(0x10)
-#define IXP23XX_GPIO_GPIT2R IXP23XX_GPIO_REG(0x14)
-#define IXP23XX_GPIO_GPCLKR IXP23XX_GPIO_REG(0x18)
-#define IXP23XX_GPIO_GPDBSELR IXP23XX_GPIO_REG(0x1c)
-
-#define IXP23XX_GPIO_STYLE_MASK 0x7
-#define IXP23XX_GPIO_STYLE_ACTIVE_HIGH 0x0
-#define IXP23XX_GPIO_STYLE_ACTIVE_LOW 0x1
-#define IXP23XX_GPIO_STYLE_RISING_EDGE 0x2
-#define IXP23XX_GPIO_STYLE_FALLING_EDGE 0x3
-#define IXP23XX_GPIO_STYLE_TRANSITIONAL 0x4
-
-#define IXP23XX_GPIO_STYLE_SIZE 3
-
-
-/****************************************************************************
- * Timer.
- ****************************************************************************/
-#define IXP23XX_TIMER_REG(x) ((volatile unsigned long *)(IXP23XX_TIMER_VIRT + (x)))
-#define IXP23XX_TIMER_CONT IXP23XX_TIMER_REG(0x00)
-#define IXP23XX_TIMER1_TIMESTAMP IXP23XX_TIMER_REG(0x04)
-#define IXP23XX_TIMER1_RELOAD IXP23XX_TIMER_REG(0x08)
-#define IXP23XX_TIMER2_TIMESTAMP IXP23XX_TIMER_REG(0x0c)
-#define IXP23XX_TIMER2_RELOAD IXP23XX_TIMER_REG(0x10)
-#define IXP23XX_TIMER_WDOG IXP23XX_TIMER_REG(0x14)
-#define IXP23XX_TIMER_WDOG_EN IXP23XX_TIMER_REG(0x18)
-#define IXP23XX_TIMER_WDOG_KEY IXP23XX_TIMER_REG(0x1c)
-#define IXP23XX_TIMER_WDOG_KEY_MAGIC 0x482e
-#define IXP23XX_TIMER_STATUS IXP23XX_TIMER_REG(0x20)
-#define IXP23XX_TIMER_SOFT_RESET IXP23XX_TIMER_REG(0x24)
-#define IXP23XX_TIMER_SOFT_RESET_EN IXP23XX_TIMER_REG(0x28)
-
-#define IXP23XX_TIMER_ENABLE (1 << 0)
-#define IXP23XX_TIMER_ONE_SHOT (1 << 1)
-/* Low order bits of reload value ignored */
-#define IXP23XX_TIMER_RELOAD_MASK (0x3)
-#define IXP23XX_TIMER_DISABLED (0x0)
-#define IXP23XX_TIMER1_INT_PEND (1 << 0)
-#define IXP23XX_TIMER2_INT_PEND (1 << 1)
-#define IXP23XX_TIMER_STATUS_TS_PEND (1 << 2)
-#define IXP23XX_TIMER_STATUS_WDOG_PEND (1 << 3)
-#define IXP23XX_TIMER_STATUS_WARM_RESET (1 << 4)
-
-
-/****************************************************************************
- * CAP CSRs.
- ****************************************************************************/
-#define IXP23XX_GLOBAL_REG(x) ((volatile unsigned long *)(IXP23XX_CAP_CSR_VIRT + 0x4a00 + (x)))
-#define IXP23XX_PRODUCT_ID IXP23XX_GLOBAL_REG(0x00)
-#define IXP23XX_MISC_CONTROL IXP23XX_GLOBAL_REG(0x04)
-#define IXP23XX_MSF_CLK_CNTRL IXP23XX_GLOBAL_REG(0x08)
-#define IXP23XX_RESET0 IXP23XX_GLOBAL_REG(0x0c)
-#define IXP23XX_RESET1 IXP23XX_GLOBAL_REG(0x10)
-#define IXP23XX_STRAP_OPTIONS IXP23XX_GLOBAL_REG(0x18)
-
-#define IXP23XX_ENABLE_WATCHDOG (1 << 24)
-#define IXP23XX_SHPC_INIT_COMP (1 << 21)
-#define IXP23XX_RST_ALL (1 << 16)
-#define IXP23XX_RESET_PCI (1 << 2)
-#define IXP23XX_PCI_UNIT_RESET (1 << 1)
-#define IXP23XX_XSCALE_RESET (1 << 0)
-
-#define IXP23XX_UENGINE_CSR_VIRT_BASE (IXP23XX_CAP_CSR_VIRT + 0x18000)
-
-
-/****************************************************************************
- * PCI CSRs.
- ****************************************************************************/
-#define IXP23XX_PCI_CREG(x) ((volatile unsigned long *)(IXP23XX_PCI_CREG_VIRT + (x)))
-#define IXP23XX_PCI_CMDSTAT IXP23XX_PCI_CREG(0x04)
-#define IXP23XX_PCI_SRAM_BAR IXP23XX_PCI_CREG(0x14)
-#define IXP23XX_PCI_SDRAM_BAR IXP23XX_PCI_CREG(0x18)
-
-
-#define IXP23XX_PCI_CSR(x) ((volatile unsigned long *)(IXP23XX_PCI_CREG_VIRT + 0x01000000 + (x)))
-#define IXP23XX_PCI_OUT_INT_STATUS IXP23XX_PCI_CSR(0x0030)
-#define IXP23XX_PCI_OUT_INT_MASK IXP23XX_PCI_CSR(0x0034)
-#define IXP23XX_PCI_SRAM_BASE_ADDR_MASK IXP23XX_PCI_CSR(0x00fc)
-#define IXP23XX_PCI_DRAM_BASE_ADDR_MASK IXP23XX_PCI_CSR(0x0100)
-#define IXP23XX_PCI_CONTROL IXP23XX_PCI_CSR(0x013c)
-#define IXP23XX_PCI_ADDR_EXT IXP23XX_PCI_CSR(0x0140)
-#define IXP23XX_PCI_ME_PUSH_STATUS IXP23XX_PCI_CSR(0x0148)
-#define IXP23XX_PCI_ME_PUSH_EN IXP23XX_PCI_CSR(0x014c)
-#define IXP23XX_PCI_ERR_STATUS IXP23XX_PCI_CSR(0x0150)
-#define IXP23XX_PCI_ERROR_STATUS IXP23XX_PCI_CSR(0x0150)
-#define IXP23XX_PCI_ERR_ENABLE IXP23XX_PCI_CSR(0x0154)
-#define IXP23XX_PCI_XSCALE_INT_STATUS IXP23XX_PCI_CSR(0x0158)
-#define IXP23XX_PCI_XSCALE_INT_ENABLE IXP23XX_PCI_CSR(0x015c)
-#define IXP23XX_PCI_CPP_ADDR_BITS IXP23XX_PCI_CSR(0x0160)
-
-
-#endif
diff --git a/arch/arm/mach-ixp23xx/include/mach/memory.h b/arch/arm/mach-ixp23xx/include/mach/memory.h
deleted file mode 100644
index 6cf0704e946a..000000000000
--- a/arch/arm/mach-ixp23xx/include/mach/memory.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/memory.h
- *
- * Copyright (c) 2003-2004 Intel Corp.
- *
- * 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.
- */
-
-#ifndef __ASM_ARCH_MEMORY_H
-#define __ASM_ARCH_MEMORY_H
-
-#include <mach/hardware.h>
-
-/*
- * Physical DRAM offset.
- */
-#define PLAT_PHYS_OFFSET (0x00000000)
-
-#define IXP23XX_PCI_SDRAM_OFFSET (*((volatile int *)IXP23XX_PCI_SDRAM_BAR) & 0xfffffff0)
-
-#define __phys_to_bus(x) ((x) + (IXP23XX_PCI_SDRAM_OFFSET - PHYS_OFFSET))
-#define __bus_to_phys(x) ((x) - (IXP23XX_PCI_SDRAM_OFFSET - PHYS_OFFSET))
-
-#define __virt_to_bus(v) __phys_to_bus(__virt_to_phys(v))
-#define __bus_to_virt(b) __phys_to_virt(__bus_to_phys(b))
-#define __pfn_to_bus(p) __phys_to_bus(__pfn_to_phys(p))
-#define __bus_to_pfn(b) __phys_to_pfn(__bus_to_phys(b))
-
-#define arch_is_coherent() 1
-
-#endif
diff --git a/arch/arm/mach-ixp23xx/include/mach/platform.h b/arch/arm/mach-ixp23xx/include/mach/platform.h
deleted file mode 100644
index 798d8b42ab4a..000000000000
--- a/arch/arm/mach-ixp23xx/include/mach/platform.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/platform.h
- *
- * Various bits of code used by platform-level code.
- *
- * Author: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright 2005 (c) MontaVista Software, Inc.
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __ASSEMBLY__
-
-static inline unsigned long ixp2000_reg_read(volatile void *reg)
-{
- return *((volatile unsigned long *)reg);
-}
-
-static inline void ixp2000_reg_write(volatile void *reg, unsigned long val)
-{
- *((volatile unsigned long *)reg) = val;
-}
-
-static inline void ixp2000_reg_wrb(volatile void *reg, unsigned long val)
-{
- *((volatile unsigned long *)reg) = val;
-}
-
-struct pci_sys_data;
-
-void ixp23xx_map_io(void);
-void ixp23xx_init_irq(void);
-void ixp23xx_sys_init(void);
-void ixp23xx_restart(char, const char *);
-int ixp23xx_pci_setup(int, struct pci_sys_data *);
-void ixp23xx_pci_preinit(void);
-extern struct pci_ops ixp23xx_pci_ops;
-void ixp23xx_pci_slave_init(void);
-
-extern struct sys_timer ixp23xx_timer;
-
-#define IXP23XX_UART_XTAL 14745600
-
-#ifndef __ASSEMBLY__
-/*
- * Is system memory on the XSI or CPP bus?
- */
-static inline unsigned ixp23xx_cpp_boot(void)
-{
- return (*IXP23XX_EXP_CFG0 & IXP23XX_EXP_CFG0_XSI_NOT_PRES);
-}
-#endif
-
-
-#endif
diff --git a/arch/arm/mach-ixp23xx/include/mach/time.h b/arch/arm/mach-ixp23xx/include/mach/time.h
deleted file mode 100644
index b61dafc884ac..000000000000
--- a/arch/arm/mach-ixp23xx/include/mach/time.h
+++ /dev/null
@@ -1,3 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/time.h
- */
diff --git a/arch/arm/mach-ixp23xx/include/mach/timex.h b/arch/arm/mach-ixp23xx/include/mach/timex.h
deleted file mode 100644
index e341e9cf9c37..000000000000
--- a/arch/arm/mach-ixp23xx/include/mach/timex.h
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/timex.h
- *
- * XScale architecture timex specifications
- */
-
-#define CLOCK_TICK_RATE 75000000
diff --git a/arch/arm/mach-ixp23xx/include/mach/uncompress.h b/arch/arm/mach-ixp23xx/include/mach/uncompress.h
deleted file mode 100644
index 8b4c358d2c04..000000000000
--- a/arch/arm/mach-ixp23xx/include/mach/uncompress.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/include/mach/uncompress.h
- *
- * Copyright (C) 2002-2004 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.
- */
-
-#ifndef __ASM_ARCH_UNCOMPRESS_H
-#define __ASM_ARCH_UNCOMPRESS_H
-
-#include <mach/ixp23xx.h>
-#include <linux/serial_reg.h>
-
-#define UART_BASE ((volatile u32 *)IXP23XX_UART1_PHYS)
-
-static inline void putc(char c)
-{
- int j;
-
- for (j = 0; j < 0x1000; j++) {
- if (UART_BASE[UART_LSR] & UART_LSR_THRE)
- break;
- barrier();
- }
-
- UART_BASE[UART_TX] = c;
-}
-
-static inline void flush(void)
-{
-}
-
-#define arch_decomp_setup()
-#define arch_decomp_wdog()
-
-
-#endif
diff --git a/arch/arm/mach-ixp23xx/ixdp2351.c b/arch/arm/mach-ixp23xx/ixdp2351.c
deleted file mode 100644
index 8b48e32a8a62..000000000000
--- a/arch/arm/mach-ixp23xx/ixdp2351.c
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/ixdp2351.c
- *
- * IXDP2351 board-specific routines
- *
- * Author: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright 2005 (c) MontaVista Software, Inc.
- *
- * Based on 2.4 code Copyright 2004 (c) Intel Corporation
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/bitops.h>
-#include <linux/ioport.h>
-#include <linux/serial_8250.h>
-#include <linux/serial_core.h>
-#include <linux/device.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/mtd/physmap.h>
-
-#include <asm/types.h>
-#include <asm/setup.h>
-#include <asm/memory.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/tlbflush.h>
-#include <asm/pgtable.h>
-
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/pci.h>
-
-/*
- * IXDP2351 Interrupt Handling
- */
-static void ixdp2351_inta_mask(struct irq_data *d)
-{
- *IXDP2351_CPLD_INTA_MASK_SET_REG = IXDP2351_INTA_IRQ_MASK(d->irq);
-}
-
-static void ixdp2351_inta_unmask(struct irq_data *d)
-{
- *IXDP2351_CPLD_INTA_MASK_CLR_REG = IXDP2351_INTA_IRQ_MASK(d->irq);
-}
-
-static void ixdp2351_inta_handler(unsigned int irq, struct irq_desc *desc)
-{
- u16 ex_interrupt =
- *IXDP2351_CPLD_INTA_STAT_REG & IXDP2351_INTA_IRQ_VALID;
- int i;
-
- desc->irq_data.chip->irq_mask(&desc->irq_data);
-
- for (i = 0; i < IXDP2351_INTA_IRQ_NUM; i++) {
- if (ex_interrupt & (1 << i)) {
- int cpld_irq =
- IXP23XX_MACH_IRQ(IXDP2351_INTA_IRQ_BASE + i);
- generic_handle_irq(cpld_irq);
- }
- }
-
- desc->irq_data.chip->irq_unmask(&desc->irq_data);
-}
-
-static struct irq_chip ixdp2351_inta_chip = {
- .irq_ack = ixdp2351_inta_mask,
- .irq_mask = ixdp2351_inta_mask,
- .irq_unmask = ixdp2351_inta_unmask
-};
-
-static void ixdp2351_intb_mask(struct irq_data *d)
-{
- *IXDP2351_CPLD_INTB_MASK_SET_REG = IXDP2351_INTB_IRQ_MASK(d->irq);
-}
-
-static void ixdp2351_intb_unmask(struct irq_data *d)
-{
- *IXDP2351_CPLD_INTB_MASK_CLR_REG = IXDP2351_INTB_IRQ_MASK(d->irq);
-}
-
-static void ixdp2351_intb_handler(unsigned int irq, struct irq_desc *desc)
-{
- u16 ex_interrupt =
- *IXDP2351_CPLD_INTB_STAT_REG & IXDP2351_INTB_IRQ_VALID;
- int i;
-
- desc->irq_data.chip->irq_ack(&desc->irq_data);
-
- for (i = 0; i < IXDP2351_INTB_IRQ_NUM; i++) {
- if (ex_interrupt & (1 << i)) {
- int cpld_irq =
- IXP23XX_MACH_IRQ(IXDP2351_INTB_IRQ_BASE + i);
- generic_handle_irq(cpld_irq);
- }
- }
-
- desc->irq_data.chip->irq_unmask(&desc->irq_data);
-}
-
-static struct irq_chip ixdp2351_intb_chip = {
- .irq_ack = ixdp2351_intb_mask,
- .irq_mask = ixdp2351_intb_mask,
- .irq_unmask = ixdp2351_intb_unmask
-};
-
-void __init ixdp2351_init_irq(void)
-{
- int irq;
-
- /* Mask all interrupts from CPLD, disable simulation */
- *IXDP2351_CPLD_INTA_MASK_SET_REG = (u16) -1;
- *IXDP2351_CPLD_INTB_MASK_SET_REG = (u16) -1;
- *IXDP2351_CPLD_INTA_SIM_REG = 0;
- *IXDP2351_CPLD_INTB_SIM_REG = 0;
-
- ixp23xx_init_irq();
-
- for (irq = IXP23XX_MACH_IRQ(IXDP2351_INTA_IRQ_BASE);
- irq <
- IXP23XX_MACH_IRQ(IXDP2351_INTA_IRQ_BASE + IXDP2351_INTA_IRQ_NUM);
- irq++) {
- if (IXDP2351_INTA_IRQ_MASK(irq) & IXDP2351_INTA_IRQ_VALID) {
- set_irq_flags(irq, IRQF_VALID);
- irq_set_chip_and_handler(irq, &ixdp2351_inta_chip,
- handle_level_irq);
- }
- }
-
- for (irq = IXP23XX_MACH_IRQ(IXDP2351_INTB_IRQ_BASE);
- irq <
- IXP23XX_MACH_IRQ(IXDP2351_INTB_IRQ_BASE + IXDP2351_INTB_IRQ_NUM);
- irq++) {
- if (IXDP2351_INTB_IRQ_MASK(irq) & IXDP2351_INTB_IRQ_VALID) {
- set_irq_flags(irq, IRQF_VALID);
- irq_set_chip_and_handler(irq, &ixdp2351_intb_chip,
- handle_level_irq);
- }
- }
-
- irq_set_chained_handler(IRQ_IXP23XX_INTA, ixdp2351_inta_handler);
- irq_set_chained_handler(IRQ_IXP23XX_INTB, ixdp2351_intb_handler);
-}
-
-/*
- * IXDP2351 PCI
- */
-
-/*
- * This board does not do normal PCI IRQ routing, or any
- * sort of swizzling, so we just need to check where on the
- * bus the device is and figure out what CPLD pin it is
- * being routed to.
- */
-#define DEVPIN(dev, pin) ((pin) | ((dev) << 3))
-
-static int __init ixdp2351_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
-{
- u8 bus = dev->bus->number;
- u32 devpin = DEVPIN(PCI_SLOT(dev->devfn), pin);
- struct pci_bus *tmp_bus = dev->bus;
-
- /* Primary bus, no interrupts here */
- if (!bus)
- return -1;
-
- /* Lookup first leaf in bus tree */
- while ((tmp_bus->parent != NULL) && (tmp_bus->parent->parent != NULL))
- tmp_bus = tmp_bus->parent;
-
- /* Select between known bridges */
- switch (tmp_bus->self->devfn | (tmp_bus->self->bus->number << 8)) {
- /* Device is located after first bridge */
- case 0x0008:
- if (tmp_bus == dev->bus) {
- /* Device is located directy after first bridge */
- switch (devpin) {
- /* Onboard 82546 */
- case DEVPIN(1, 1): /* Onboard 82546 ch 0 */
- return IRQ_IXDP2351_INTA_82546;
- case DEVPIN(1, 2): /* Onboard 82546 ch 1 */
- return IRQ_IXDP2351_INTB_82546;
- /* PMC SLOT */
- case DEVPIN(0, 1): /* PMCP INTA# */
- case DEVPIN(2, 4): /* PMCS INTD# */
- return IRQ_IXDP2351_SPCI_PMC_INTA;
- case DEVPIN(0, 2): /* PMCP INTB# */
- case DEVPIN(2, 1): /* PMCS INTA# */
- return IRQ_IXDP2351_SPCI_PMC_INTB;
- case DEVPIN(0, 3): /* PMCP INTC# */
- case DEVPIN(2, 2): /* PMCS INTB# */
- return IRQ_IXDP2351_SPCI_PMC_INTC;
- case DEVPIN(0, 4): /* PMCP INTD# */
- case DEVPIN(2, 3): /* PMCS INTC# */
- return IRQ_IXDP2351_SPCI_PMC_INTD;
- }
- } else {
- /* Device is located indirectly after first bridge */
- /* Not supported now */
- return -1;
- }
- break;
- case 0x0010:
- if (tmp_bus == dev->bus) {
- /* Device is located directy after second bridge */
- /* Secondary bus of second bridge */
- switch (devpin) {
- case DEVPIN(0, 1): /* DB#0 */
- case DEVPIN(0, 2):
- case DEVPIN(0, 3):
- case DEVPIN(0, 4):
- return IRQ_IXDP2351_SPCI_DB_0;
- case DEVPIN(1, 1): /* DB#1 */
- case DEVPIN(1, 2):
- case DEVPIN(1, 3):
- case DEVPIN(1, 4):
- return IRQ_IXDP2351_SPCI_DB_1;
- case DEVPIN(2, 1): /* FIC1 */
- case DEVPIN(2, 2):
- case DEVPIN(2, 3):
- case DEVPIN(2, 4):
- case DEVPIN(3, 1): /* FIC2 */
- case DEVPIN(3, 2):
- case DEVPIN(3, 3):
- case DEVPIN(3, 4):
- return IRQ_IXDP2351_SPCI_FIC;
- }
- } else {
- /* Device is located indirectly after second bridge */
- /* Not supported now */
- return -1;
- }
- break;
- }
-
- return -1;
-}
-
-struct hw_pci ixdp2351_pci __initdata = {
- .nr_controllers = 1,
- .ops = &ixp23xx_pci_ops,
- .preinit = ixp23xx_pci_preinit,
- .setup = ixp23xx_pci_setup,
- .map_irq = ixdp2351_map_irq,
-};
-
-int __init ixdp2351_pci_init(void)
-{
- if (machine_is_ixdp2351())
- pci_common_init(&ixdp2351_pci);
-
- return 0;
-}
-
-subsys_initcall(ixdp2351_pci_init);
-
-/*
- * IXDP2351 Static Mapped I/O
- */
-static struct map_desc ixdp2351_io_desc[] __initdata = {
- {
- .virtual = IXDP2351_NP_VIRT_BASE,
- .pfn = __phys_to_pfn((u64)IXDP2351_NP_PHYS_BASE),
- .length = IXDP2351_NP_PHYS_SIZE,
- .type = MT_DEVICE
- }, {
- .virtual = IXDP2351_BB_BASE_VIRT,
- .pfn = __phys_to_pfn((u64)IXDP2351_BB_BASE_PHYS),
- .length = IXDP2351_BB_SIZE,
- .type = MT_DEVICE
- }
-};
-
-static void __init ixdp2351_map_io(void)
-{
- ixp23xx_map_io();
- iotable_init(ixdp2351_io_desc, ARRAY_SIZE(ixdp2351_io_desc));
-}
-
-static struct physmap_flash_data ixdp2351_flash_data = {
- .width = 1,
-};
-
-static struct resource ixdp2351_flash_resource = {
- .start = 0x90000000,
- .end = 0x93ffffff,
- .flags = IORESOURCE_MEM,
-};
-
-static struct platform_device ixdp2351_flash = {
- .name = "physmap-flash",
- .id = 0,
- .dev = {
- .platform_data = &ixdp2351_flash_data,
- },
- .num_resources = 1,
- .resource = &ixdp2351_flash_resource,
-};
-
-static void __init ixdp2351_init(void)
-{
- platform_device_register(&ixdp2351_flash);
-
- /*
- * Mark flash as writeable
- */
- IXP23XX_EXP_CS0[0] |= IXP23XX_FLASH_WRITABLE;
- IXP23XX_EXP_CS0[1] |= IXP23XX_FLASH_WRITABLE;
- IXP23XX_EXP_CS0[2] |= IXP23XX_FLASH_WRITABLE;
- IXP23XX_EXP_CS0[3] |= IXP23XX_FLASH_WRITABLE;
-
- ixp23xx_sys_init();
-}
-
-static void ixdp2351_restart(char mode, const char *cmd)
-{
- /* First try machine specific support */
-
- *IXDP2351_CPLD_RESET1_REG = IXDP2351_CPLD_RESET1_MAGIC;
- (void) *IXDP2351_CPLD_RESET1_REG;
- *IXDP2351_CPLD_RESET1_REG = IXDP2351_CPLD_RESET1_ENABLE;
-
- ixp23xx_restart(mode, cmd);
-}
-
-MACHINE_START(IXDP2351, "Intel IXDP2351 Development Platform")
- /* Maintainer: MontaVista Software, Inc. */
- .map_io = ixdp2351_map_io,
- .init_irq = ixdp2351_init_irq,
- .timer = &ixp23xx_timer,
- .atag_offset = 0x100,
- .init_machine = ixdp2351_init,
- .restart = ixdp2351_restart,
-MACHINE_END
diff --git a/arch/arm/mach-ixp23xx/pci.c b/arch/arm/mach-ixp23xx/pci.c
deleted file mode 100644
index 9211506ef556..000000000000
--- a/arch/arm/mach-ixp23xx/pci.c
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/pci.c
- *
- * PCI routines for IXP23XX based systems
- *
- * Copyright (c) 2005 MontaVista Software, Inc.
- *
- * based on original code:
- *
- * Author: Naeem Afzal <naeem.m.afzal@intel.com>
- * Copyright 2002-2005 Intel Corp.
- *
- * 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/sched.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <asm/sizes.h>
-#include <asm/mach/pci.h>
-#include <mach/hardware.h>
-
-extern int (*external_fault) (unsigned long, struct pt_regs *);
-
-static volatile int pci_master_aborts = 0;
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-int clear_master_aborts(void);
-
-static u32
-*ixp23xx_pci_config_addr(unsigned int bus_nr, unsigned int devfn, int where)
-{
- u32 *paddress;
-
- /*
- * Must be dword aligned
- */
- where &= ~3;
-
- /*
- * For top bus, generate type 0, else type 1
- */
- if (!bus_nr) {
- if (PCI_SLOT(devfn) >= 8)
- return 0;
-
- paddress = (u32 *) (IXP23XX_PCI_CFG0_VIRT
- | (1 << (PCI_SLOT(devfn) + 16))
- | (PCI_FUNC(devfn) << 8) | where);
- } else {
- paddress = (u32 *) (IXP23XX_PCI_CFG1_VIRT
- | (bus_nr << 16)
- | (PCI_SLOT(devfn) << 11)
- | (PCI_FUNC(devfn) << 8) | where);
- }
-
- return paddress;
-}
-
-/*
- * Mask table, bits to mask for quantity of size 1, 2 or 4 bytes.
- * 0 and 3 are not valid indexes...
- */
-static u32 bytemask[] = {
- /*0*/ 0,
- /*1*/ 0xff,
- /*2*/ 0xffff,
- /*3*/ 0,
- /*4*/ 0xffffffff,
-};
-
-static int ixp23xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 *value)
-{
- u32 n;
- u32 *addr;
-
- n = where % 4;
-
- DBG("In config_read(%d) %d from dev %d:%d:%d\n", size, where,
- bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
-
- addr = ixp23xx_pci_config_addr(bus->number, devfn, where);
- if (!addr)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- pci_master_aborts = 0;
- *value = (*addr >> (8*n)) & bytemask[size];
- if (pci_master_aborts) {
- pci_master_aborts = 0;
- *value = 0xffffffff;
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-/*
- * We don't do error checking on the address for writes.
- * It's assumed that the user checked for the device existing first
- * by doing a read first.
- */
-static int ixp23xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 value)
-{
- u32 mask;
- u32 *addr;
- u32 temp;
-
- mask = ~(bytemask[size] << ((where % 0x4) * 8));
- addr = ixp23xx_pci_config_addr(bus->number, devfn, where);
- if (!addr)
- return PCIBIOS_DEVICE_NOT_FOUND;
- temp = (u32) (value) << ((where % 0x4) * 8);
- *addr = (*addr & mask) | temp;
-
- clear_master_aborts();
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-struct pci_ops ixp23xx_pci_ops = {
- .read = ixp23xx_pci_read_config,
- .write = ixp23xx_pci_write_config,
-};
-
-int ixp23xx_pci_abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
-{
- volatile unsigned long temp;
- unsigned long flags;
-
- pci_master_aborts = 1;
-
- local_irq_save(flags);
- temp = *IXP23XX_PCI_CONTROL;
-
- /*
- * master abort and cmd tgt err
- */
- if (temp & ((1 << 8) | (1 << 5)))
- *IXP23XX_PCI_CONTROL = temp;
-
- temp = *IXP23XX_PCI_CMDSTAT;
-
- if (temp & (1 << 29))
- *IXP23XX_PCI_CMDSTAT = temp;
- local_irq_restore(flags);
-
- /*
- * If it was an imprecise abort, then we need to correct the
- * return address to be _after_ the instruction.
- */
- if (fsr & (1 << 10))
- regs->ARM_pc += 4;
-
- return 0;
-}
-
-int clear_master_aborts(void)
-{
- volatile u32 temp;
-
- temp = *IXP23XX_PCI_CONTROL;
-
- /*
- * master abort and cmd tgt err
- */
- if (temp & ((1 << 8) | (1 << 5)))
- *IXP23XX_PCI_CONTROL = temp;
-
- temp = *IXP23XX_PCI_CMDSTAT;
-
- if (temp & (1 << 29))
- *IXP23XX_PCI_CMDSTAT = temp;
-
- return 0;
-}
-
-static void __init ixp23xx_pci_common_init(void)
-{
-#ifdef __ARMEB__
- *IXP23XX_PCI_CONTROL |= 0x20000; /* set I/O swapping */
-#endif
- /*
- * ADDR_31 needs to be clear for PCI memory access to CPP memory
- */
- *IXP23XX_CPP2XSI_CURR_XFER_REG3 &= ~IXP23XX_CPP2XSI_ADDR_31;
- *IXP23XX_CPP2XSI_CURR_XFER_REG3 |= IXP23XX_CPP2XSI_PSH_OFF;
-
- /*
- * Select correct memory for PCI inbound transactions
- */
- if (ixp23xx_cpp_boot()) {
- *IXP23XX_PCI_CPP_ADDR_BITS &= ~(1 << 1);
- } else {
- *IXP23XX_PCI_CPP_ADDR_BITS |= (1 << 1);
-
- /*
- * Enable coherency on A2 silicon.
- */
- if (arch_is_coherent())
- *IXP23XX_CPP2XSI_CURR_XFER_REG3 &= ~IXP23XX_CPP2XSI_COH_OFF;
- }
-}
-
-void __init ixp23xx_pci_preinit(void)
-{
- pcibios_min_io = 0;
- pcibios_min_mem = 0xe0000000;
-
- pci_set_flags(0);
-
- ixp23xx_pci_common_init();
-
- hook_fault_code(16+6, ixp23xx_pci_abort_handler, SIGBUS, 0,
- "PCI config cycle to non-existent device");
-
- *IXP23XX_PCI_ADDR_EXT = 0x0000e000;
-}
-
-/*
- * Prevent PCI layer from seeing the inbound host-bridge resources
- */
-static void __devinit pci_fixup_ixp23xx(struct pci_dev *dev)
-{
- int i;
-
- dev->class &= 0xff;
- dev->class |= PCI_CLASS_BRIDGE_HOST << 8;
- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
- dev->resource[i].start = 0;
- dev->resource[i].end = 0;
- dev->resource[i].flags = 0;
- }
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x9002, pci_fixup_ixp23xx);
-
-/*
- * IXP2300 systems often have large resource requirements, so we just
- * use our own resource space.
- */
-static struct resource ixp23xx_pci_mem_space = {
- .start = IXP23XX_PCI_MEM_START,
- .end = IXP23XX_PCI_MEM_START + IXP23XX_PCI_MEM_SIZE - 1,
- .flags = IORESOURCE_MEM,
- .name = "PCI Mem Space"
-};
-
-static struct resource ixp23xx_pci_io_space = {
- .start = 0x00000100,
- .end = 0x01ffffff,
- .flags = IORESOURCE_IO,
- .name = "PCI I/O Space"
-};
-
-int ixp23xx_pci_setup(int nr, struct pci_sys_data *sys)
-{
- if (nr >= 1)
- return 0;
-
- pci_add_resource_offset(&sys->resources,
- &ixp23xx_pci_io_space, sys->io_offset);
- pci_add_resource_offset(&sys->resources,
- &ixp23xx_pci_mem_space, sys->mem_offset);
-
- return 1;
-}
-
-void __init ixp23xx_pci_slave_init(void)
-{
- ixp23xx_pci_common_init();
-}
diff --git a/arch/arm/mach-ixp23xx/roadrunner.c b/arch/arm/mach-ixp23xx/roadrunner.c
deleted file mode 100644
index 8c0e5de3c609..000000000000
--- a/arch/arm/mach-ixp23xx/roadrunner.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * arch/arm/mach-ixp23xx/roadrunner.c
- *
- * RoadRunner board-specific routines
- *
- * Author: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright 2005 (c) MontaVista Software, Inc.
- *
- * Based on 2.4 code Copyright 2005 (c) ADI Engineering Corporation
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/bitops.h>
-#include <linux/ioport.h>
-#include <linux/serial_8250.h>
-#include <linux/serial_core.h>
-#include <linux/device.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-#include <linux/mtd/physmap.h>
-
-#include <asm/types.h>
-#include <asm/setup.h>
-#include <asm/memory.h>
-#include <mach/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-#include <asm/tlbflush.h>
-#include <asm/pgtable.h>
-
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/pci.h>
-
-/*
- * Interrupt mapping
- */
-#define INTA IRQ_ROADRUNNER_PCI_INTA
-#define INTB IRQ_ROADRUNNER_PCI_INTB
-#define INTC IRQ_ROADRUNNER_PCI_INTC
-#define INTD IRQ_ROADRUNNER_PCI_INTD
-
-#define INTC_PIN IXP23XX_GPIO_PIN_11
-#define INTD_PIN IXP23XX_GPIO_PIN_12
-
-static int __init roadrunner_map_irq(const struct pci_dev *dev, u8 idsel,
- u8 pin)
-{
- static int pci_card_slot_irq[] = {INTB, INTC, INTD, INTA};
- static int pmc_card_slot_irq[] = {INTA, INTB, INTC, INTD};
- static int usb_irq[] = {INTB, INTC, INTD, -1};
- static int mini_pci_1_irq[] = {INTB, INTC, -1, -1};
- static int mini_pci_2_irq[] = {INTC, INTD, -1, -1};
-
- switch(dev->bus->number) {
- case 0:
- switch(dev->devfn) {
- case 0x0: // PCI-PCI bridge
- break;
- case 0x8: // PCI Card Slot
- return pci_card_slot_irq[pin - 1];
- case 0x10: // PMC Slot
- return pmc_card_slot_irq[pin - 1];
- case 0x18: // PMC Slot Secondary Agent
- break;
- case 0x20: // IXP Processor
- break;
- default:
- return NO_IRQ;
- }
- break;
-
- case 1:
- switch(dev->devfn) {
- case 0x0: // IDE Controller
- return (pin == 1) ? INTC : -1;
- case 0x8: // USB fun 0
- case 0x9: // USB fun 1
- case 0xa: // USB fun 2
- return usb_irq[pin - 1];
- case 0x10: // Mini PCI 1
- return mini_pci_1_irq[pin-1];
- case 0x18: // Mini PCI 2
- return mini_pci_2_irq[pin-1];
- case 0x20: // MEM slot
- return (pin == 1) ? INTA : -1;
- default:
- return NO_IRQ;
- }
- break;
-
- default:
- return NO_IRQ;
- }
-
- return NO_IRQ;
-}
-
-static void __init roadrunner_pci_preinit(void)
-{
- irq_set_irq_type(IRQ_ROADRUNNER_PCI_INTC, IRQ_TYPE_LEVEL_LOW);
- irq_set_irq_type(IRQ_ROADRUNNER_PCI_INTD, IRQ_TYPE_LEVEL_LOW);
-
- ixp23xx_pci_preinit();
-}
-
-static struct hw_pci roadrunner_pci __initdata = {
- .nr_controllers = 1,
- .ops = &ixp23xx_pci_ops,
- .preinit = roadrunner_pci_preinit,
- .setup = ixp23xx_pci_setup,
- .map_irq = roadrunner_map_irq,
-};
-
-static int __init roadrunner_pci_init(void)
-{
- if (machine_is_roadrunner())
- pci_common_init(&roadrunner_pci);
-
- return 0;
-};
-
-subsys_initcall(roadrunner_pci_init);
-
-static struct physmap_flash_data roadrunner_flash_data = {
- .width = 2,
-};
-
-static struct resource roadrunner_flash_resource = {
- .start = 0x90000000,
- .end = 0x93ffffff,
- .flags = IORESOURCE_MEM,
-};
-
-static struct platform_device roadrunner_flash = {
- .name = "physmap-flash",
- .id = 0,
- .dev = {
- .platform_data = &roadrunner_flash_data,
- },
- .num_resources = 1,
- .resource = &roadrunner_flash_resource,
-};
-
-static void __init roadrunner_init(void)
-{
- platform_device_register(&roadrunner_flash);
-
- /*
- * Mark flash as writeable
- */
- IXP23XX_EXP_CS0[0] |= IXP23XX_FLASH_WRITABLE;
- IXP23XX_EXP_CS0[1] |= IXP23XX_FLASH_WRITABLE;
- IXP23XX_EXP_CS0[2] |= IXP23XX_FLASH_WRITABLE;
- IXP23XX_EXP_CS0[3] |= IXP23XX_FLASH_WRITABLE;
-
- ixp23xx_sys_init();
-}
-
-MACHINE_START(ROADRUNNER, "ADI Engineering RoadRunner Development Platform")
- /* Maintainer: Deepak Saxena */
- .map_io = ixp23xx_map_io,
- .init_irq = ixp23xx_init_irq,
- .timer = &ixp23xx_timer,
- .atag_offset = 0x100,
- .init_machine = roadrunner_init,
- .restart = ixp23xx_restart,
-MACHINE_END
diff --git a/arch/arm/mach-kirkwood/Kconfig b/arch/arm/mach-kirkwood/Kconfig
index 90ceab761929..199764fe0fb0 100644
--- a/arch/arm/mach-kirkwood/Kconfig
+++ b/arch/arm/mach-kirkwood/Kconfig
@@ -58,6 +58,28 @@ config MACH_DREAMPLUG_DT
Say 'Y' here if you want your kernel to support the
Marvell DreamPlug (Flattened Device Tree).
+config MACH_ICONNECT_DT
+ bool "Iomega Iconnect (Flattened Device Tree)"
+ select ARCH_KIRKWOOD_DT
+ help
+ Say 'Y' here to enable Iomega Iconnect support.
+
+config MACH_DLINK_KIRKWOOD_DT
+ bool "D-Link Kirkwood-based NAS (Flattened Device Tree)"
+ select ARCH_KIRKWOOD_DT
+ help
+ Say 'Y' here if you want your kernel to support the
+ Kirkwood-based D-Link NASes such as DNS-320 & DNS-325,
+ using Flattened Device Tree.
+
+config MACH_IB62X0_DT
+ bool "RaidSonic IB-NAS6210, IB-NAS6220 (Flattened Device Tree)"
+ select ARCH_KIRKWOOD_DT
+ help
+ Say 'Y' here if you want your kernel to support the
+ RaidSonic IB-NAS6210 & IB-NAS6220 devices, using
+ Flattened Device Tree.
+
config MACH_TS219
bool "QNAP TS-110, TS-119, TS-119P+, TS-210, TS-219, TS-219P and TS-219P+ Turbo NAS"
help
diff --git a/arch/arm/mach-kirkwood/Makefile b/arch/arm/mach-kirkwood/Makefile
index e299a9576bf0..d2b05907b10e 100644
--- a/arch/arm/mach-kirkwood/Makefile
+++ b/arch/arm/mach-kirkwood/Makefile
@@ -22,3 +22,6 @@ obj-$(CONFIG_MACH_T5325) += t5325-setup.o
obj-$(CONFIG_CPU_IDLE) += cpuidle.o
obj-$(CONFIG_ARCH_KIRKWOOD_DT) += board-dt.o
obj-$(CONFIG_MACH_DREAMPLUG_DT) += board-dreamplug.o
+obj-$(CONFIG_MACH_ICONNECT_DT) += board-iconnect.o
+obj-$(CONFIG_MACH_DLINK_KIRKWOOD_DT) += board-dnskw.o
+obj-$(CONFIG_MACH_IB62X0_DT) += board-ib62x0.o
diff --git a/arch/arm/mach-kirkwood/Makefile.boot b/arch/arm/mach-kirkwood/Makefile.boot
index 16f938522304..02edbdf5b065 100644
--- a/arch/arm/mach-kirkwood/Makefile.boot
+++ b/arch/arm/mach-kirkwood/Makefile.boot
@@ -3,3 +3,7 @@ params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
dtb-$(CONFIG_MACH_DREAMPLUG_DT) += kirkwood-dreamplug.dtb
+dtb-$(CONFIG_MACH_DLINK_KIRKWOOD_DT) += kirkwood-dns320.dtb
+dtb-$(CONFIG_MACH_DLINK_KIRKWOOD_DT) += kirkwood-dns325.dtb
+dtb-$(CONFIG_MACH_ICONNECT_DT) += kirkwood-iconnect.dtb
+dtb-$(CONFIG_MACH_IB62X0_DT) += kirkwood-ib62x0.dtb
diff --git a/arch/arm/mach-kirkwood/board-dnskw.c b/arch/arm/mach-kirkwood/board-dnskw.c
new file mode 100644
index 000000000000..58c2d68f9443
--- /dev/null
+++ b/arch/arm/mach-kirkwood/board-dnskw.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2012 (C), Jamie Lentin <jm@lentin.co.uk>
+ *
+ * arch/arm/mach-kirkwood/board-dnskw.c
+ *
+ * D-link DNS-320 & DNS-325 NAS Init for drivers not converted to
+ * flattened device tree yet.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/ata_platform.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/of.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <linux/gpio-fan.h>
+#include <linux/leds.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <mach/kirkwood.h>
+#include <mach/bridge-regs.h>
+#include "common.h"
+#include "mpp.h"
+
+static struct mv643xx_eth_platform_data dnskw_ge00_data = {
+ .phy_addr = MV643XX_ETH_PHY_ADDR(8),
+};
+
+static struct mv_sata_platform_data dnskw_sata_data = {
+ .n_ports = 2,
+};
+
+static unsigned int dnskw_mpp_config[] __initdata = {
+ MPP13_UART1_TXD, /* Custom ... */
+ MPP14_UART1_RXD, /* ... Controller (DNS-320 only) */
+ MPP20_SATA1_ACTn, /* LED: White Right HDD */
+ MPP21_SATA0_ACTn, /* LED: White Left HDD */
+ MPP24_GPIO,
+ MPP25_GPIO,
+ MPP26_GPIO, /* LED: Power */
+ MPP27_GPIO, /* LED: Red Right HDD */
+ MPP28_GPIO, /* LED: Red Left HDD */
+ MPP29_GPIO, /* LED: Red USB (DNS-325 only) */
+ MPP30_GPIO,
+ MPP31_GPIO,
+ MPP32_GPIO,
+ MPP33_GPO,
+ MPP34_GPIO, /* Button: Front power */
+ MPP35_GPIO, /* LED: Red USB (DNS-320 only) */
+ MPP36_GPIO, /* Power: Turn off board */
+ MPP37_GPIO, /* Power: Turn back on after power failure */
+ MPP38_GPIO,
+ MPP39_GPIO, /* Power: SATA0 */
+ MPP40_GPIO, /* Power: SATA1 */
+ MPP41_GPIO, /* SATA0 present */
+ MPP42_GPIO, /* SATA1 present */
+ MPP43_GPIO, /* LED: White USB */
+ MPP44_GPIO, /* Fan: Tachometer Pin */
+ MPP45_GPIO, /* Fan: high speed */
+ MPP46_GPIO, /* Fan: low speed */
+ MPP47_GPIO, /* Button: Back unmount */
+ MPP48_GPIO, /* Button: Back reset */
+ MPP49_GPIO, /* Temp Alarm (DNS-325) Pin of U5 (DNS-320) */
+ 0
+};
+
+static struct gpio_led dns325_led_pins[] = {
+ {
+ .name = "dns325:white:power",
+ .gpio = 26,
+ .active_low = 1,
+ .default_trigger = "default-on",
+ },
+ {
+ .name = "dns325:white:usb",
+ .gpio = 43,
+ .active_low = 1,
+ },
+ {
+ .name = "dns325:red:l_hdd",
+ .gpio = 28,
+ .active_low = 1,
+ },
+ {
+ .name = "dns325:red:r_hdd",
+ .gpio = 27,
+ .active_low = 1,
+ },
+ {
+ .name = "dns325:red:usb",
+ .gpio = 29,
+ .active_low = 1,
+ },
+};
+
+static struct gpio_led_platform_data dns325_led_data = {
+ .num_leds = ARRAY_SIZE(dns325_led_pins),
+ .leds = dns325_led_pins,
+};
+
+static struct platform_device dns325_led_device = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &dns325_led_data,
+ },
+};
+
+static struct gpio_led dns320_led_pins[] = {
+ {
+ .name = "dns320:blue:power",
+ .gpio = 26,
+ .active_low = 1,
+ .default_trigger = "default-on",
+ },
+ {
+ .name = "dns320:blue:usb",
+ .gpio = 43,
+ .active_low = 1,
+ },
+ {
+ .name = "dns320:orange:l_hdd",
+ .gpio = 28,
+ .active_low = 1,
+ },
+ {
+ .name = "dns320:orange:r_hdd",
+ .gpio = 27,
+ .active_low = 1,
+ },
+ {
+ .name = "dns320:orange:usb",
+ .gpio = 35,
+ .active_low = 1,
+ },
+};
+
+static struct gpio_led_platform_data dns320_led_data = {
+ .num_leds = ARRAY_SIZE(dns320_led_pins),
+ .leds = dns320_led_pins,
+};
+
+static struct platform_device dns320_led_device = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &dns320_led_data,
+ },
+};
+
+static struct i2c_board_info dns325_i2c_board_info[] __initdata = {
+ {
+ I2C_BOARD_INFO("lm75", 0x48),
+ },
+ /* Something at 0x0c also */
+};
+
+static struct gpio_keys_button dnskw_button_pins[] = {
+ {
+ .code = KEY_POWER,
+ .gpio = 34,
+ .desc = "Power button",
+ .active_low = 1,
+ },
+ {
+ .code = KEY_EJECTCD,
+ .gpio = 47,
+ .desc = "USB unmount button",
+ .active_low = 1,
+ },
+ {
+ .code = KEY_RESTART,
+ .gpio = 48,
+ .desc = "Reset button",
+ .active_low = 1,
+ },
+};
+
+static struct gpio_keys_platform_data dnskw_button_data = {
+ .buttons = dnskw_button_pins,
+ .nbuttons = ARRAY_SIZE(dnskw_button_pins),
+};
+
+static struct platform_device dnskw_button_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .num_resources = 0,
+ .dev = {
+ .platform_data = &dnskw_button_data,
+ }
+};
+
+/* Fan: ADDA AD045HB-G73 40mm 6000rpm@5v */
+static struct gpio_fan_speed dnskw_fan_speed[] = {
+ { 0, 0 },
+ { 3000, 1 },
+ { 6000, 2 },
+};
+static unsigned dnskw_fan_pins[] = {46, 45};
+
+static struct gpio_fan_platform_data dnskw_fan_data = {
+ .num_ctrl = ARRAY_SIZE(dnskw_fan_pins),
+ .ctrl = dnskw_fan_pins,
+ .num_speed = ARRAY_SIZE(dnskw_fan_speed),
+ .speed = dnskw_fan_speed,
+};
+
+static struct platform_device dnskw_fan_device = {
+ .name = "gpio-fan",
+ .id = -1,
+ .dev = {
+ .platform_data = &dnskw_fan_data,
+ },
+};
+
+static void dnskw_power_off(void)
+{
+ gpio_set_value(36, 1);
+}
+
+/* Register any GPIO for output and set the value */
+static void __init dnskw_gpio_register(unsigned gpio, char *name, int def)
+{
+ if (gpio_request(gpio, name) == 0 &&
+ gpio_direction_output(gpio, 0) == 0) {
+ gpio_set_value(gpio, def);
+ if (gpio_export(gpio, 0) != 0)
+ pr_err("dnskw: Failed to export GPIO %s\n", name);
+ } else
+ pr_err("dnskw: Failed to register %s\n", name);
+}
+
+void __init dnskw_init(void)
+{
+ kirkwood_mpp_conf(dnskw_mpp_config);
+
+ kirkwood_ehci_init();
+ kirkwood_ge00_init(&dnskw_ge00_data);
+ kirkwood_sata_init(&dnskw_sata_data);
+ kirkwood_i2c_init();
+
+ platform_device_register(&dnskw_button_device);
+ platform_device_register(&dnskw_fan_device);
+
+ if (of_machine_is_compatible("dlink,dns-325")) {
+ i2c_register_board_info(0, dns325_i2c_board_info,
+ ARRAY_SIZE(dns325_i2c_board_info));
+ platform_device_register(&dns325_led_device);
+
+ } else if (of_machine_is_compatible("dlink,dns-320"))
+ platform_device_register(&dns320_led_device);
+
+ /* Register power-off GPIO. */
+ if (gpio_request(36, "dnskw:power:off") == 0
+ && gpio_direction_output(36, 0) == 0)
+ pm_power_off = dnskw_power_off;
+ else
+ pr_err("dnskw: failed to configure power-off GPIO\n");
+
+ /* Ensure power is supplied to both HDDs */
+ dnskw_gpio_register(39, "dnskw:power:sata0", 1);
+ dnskw_gpio_register(40, "dnskw:power:sata1", 1);
+
+ /* Set NAS to turn back on after a power failure */
+ dnskw_gpio_register(37, "dnskw:power:recover", 1);
+}
diff --git a/arch/arm/mach-kirkwood/board-dt.c b/arch/arm/mach-kirkwood/board-dt.c
index f7fe1b9f3170..10d1969b9e3a 100644
--- a/arch/arm/mach-kirkwood/board-dt.c
+++ b/arch/arm/mach-kirkwood/board-dt.c
@@ -56,11 +56,24 @@ static void __init kirkwood_dt_init(void)
if (of_machine_is_compatible("globalscale,dreamplug"))
dreamplug_init();
+ if (of_machine_is_compatible("dlink,dns-kirkwood"))
+ dnskw_init();
+
+ if (of_machine_is_compatible("iom,iconnect"))
+ iconnect_init();
+
+ if (of_machine_is_compatible("raidsonic,ib-nas62x0"))
+ ib62x0_init();
+
of_platform_populate(NULL, kirkwood_dt_match_table, NULL, NULL);
}
static const char *kirkwood_dt_board_compat[] = {
"globalscale,dreamplug",
+ "dlink,dns-320",
+ "dlink,dns-325",
+ "iom,iconnect",
+ "raidsonic,ib-nas62x0",
NULL
};
diff --git a/arch/arm/mach-kirkwood/board-ib62x0.c b/arch/arm/mach-kirkwood/board-ib62x0.c
new file mode 100644
index 000000000000..eddf1df8891f
--- /dev/null
+++ b/arch/arm/mach-kirkwood/board-ib62x0.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2012 (C), Simon Baatz <gmbnomis@gmail.com>
+ *
+ * arch/arm/mach-kirkwood/board-ib62x0.c
+ *
+ * RaidSonic ICY BOX IB-NAS6210 & IB-NAS6220 init for drivers not
+ * converted to flattened device tree yet.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/partitions.h>
+#include <linux/ata_platform.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/leds.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <mach/kirkwood.h>
+#include "common.h"
+#include "mpp.h"
+
+#define IB62X0_GPIO_POWER_OFF 24
+
+static struct mv643xx_eth_platform_data ib62x0_ge00_data = {
+ .phy_addr = MV643XX_ETH_PHY_ADDR(8),
+};
+
+static struct mv_sata_platform_data ib62x0_sata_data = {
+ .n_ports = 2,
+};
+
+static unsigned int ib62x0_mpp_config[] __initdata = {
+ MPP0_NF_IO2,
+ MPP1_NF_IO3,
+ MPP2_NF_IO4,
+ MPP3_NF_IO5,
+ MPP4_NF_IO6,
+ MPP5_NF_IO7,
+ MPP18_NF_IO0,
+ MPP19_NF_IO1,
+ MPP22_GPIO, /* OS LED red */
+ MPP24_GPIO, /* Power off device */
+ MPP25_GPIO, /* OS LED green */
+ MPP27_GPIO, /* USB transfer LED */
+ MPP28_GPIO, /* Reset button */
+ MPP29_GPIO, /* USB Copy button */
+ 0
+};
+
+static struct gpio_led ib62x0_led_pins[] = {
+ {
+ .name = "ib62x0:green:os",
+ .default_trigger = "default-on",
+ .gpio = 25,
+ .active_low = 0,
+ },
+ {
+ .name = "ib62x0:red:os",
+ .default_trigger = "none",
+ .gpio = 22,
+ .active_low = 0,
+ },
+ {
+ .name = "ib62x0:red:usb_copy",
+ .default_trigger = "none",
+ .gpio = 27,
+ .active_low = 0,
+ },
+};
+
+static struct gpio_led_platform_data ib62x0_led_data = {
+ .leds = ib62x0_led_pins,
+ .num_leds = ARRAY_SIZE(ib62x0_led_pins),
+};
+
+static struct platform_device ib62x0_led_device = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &ib62x0_led_data,
+ }
+};
+
+static struct gpio_keys_button ib62x0_button_pins[] = {
+ {
+ .code = KEY_COPY,
+ .gpio = 29,
+ .desc = "USB Copy",
+ .active_low = 1,
+ },
+ {
+ .code = KEY_RESTART,
+ .gpio = 28,
+ .desc = "Reset",
+ .active_low = 1,
+ },
+};
+
+static struct gpio_keys_platform_data ib62x0_button_data = {
+ .buttons = ib62x0_button_pins,
+ .nbuttons = ARRAY_SIZE(ib62x0_button_pins),
+};
+
+static struct platform_device ib62x0_button_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .num_resources = 0,
+ .dev = {
+ .platform_data = &ib62x0_button_data,
+ }
+};
+
+static void ib62x0_power_off(void)
+{
+ gpio_set_value(IB62X0_GPIO_POWER_OFF, 1);
+}
+
+void __init ib62x0_init(void)
+{
+ /*
+ * Basic setup. Needs to be called early.
+ */
+ kirkwood_mpp_conf(ib62x0_mpp_config);
+
+ kirkwood_ehci_init();
+ kirkwood_ge00_init(&ib62x0_ge00_data);
+ kirkwood_sata_init(&ib62x0_sata_data);
+ platform_device_register(&ib62x0_led_device);
+ platform_device_register(&ib62x0_button_device);
+ if (gpio_request(IB62X0_GPIO_POWER_OFF, "ib62x0:power:off") == 0 &&
+ gpio_direction_output(IB62X0_GPIO_POWER_OFF, 0) == 0)
+ pm_power_off = ib62x0_power_off;
+ else
+ pr_err("board-ib62x0: failed to configure power-off GPIO\n");
+}
diff --git a/arch/arm/mach-kirkwood/board-iconnect.c b/arch/arm/mach-kirkwood/board-iconnect.c
new file mode 100644
index 000000000000..2222c5739519
--- /dev/null
+++ b/arch/arm/mach-kirkwood/board-iconnect.c
@@ -0,0 +1,165 @@
+/*
+ * arch/arm/mach-kirkwood/board-iconnect.c
+ *
+ * Iomega i-connect Board Setup
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/spi/flash.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/orion_spi.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <asm/mach/arch.h>
+#include <mach/kirkwood.h>
+#include "common.h"
+#include "mpp.h"
+
+static struct mv643xx_eth_platform_data iconnect_ge00_data = {
+ .phy_addr = MV643XX_ETH_PHY_ADDR(11),
+};
+
+static struct gpio_led iconnect_led_pins[] = {
+ {
+ .name = "led_level",
+ .gpio = 41,
+ .default_trigger = "default-on",
+ }, {
+ .name = "power:blue",
+ .gpio = 42,
+ .default_trigger = "timer",
+ }, {
+ .name = "power:red",
+ .gpio = 43,
+ }, {
+ .name = "usb1:blue",
+ .gpio = 44,
+ }, {
+ .name = "usb2:blue",
+ .gpio = 45,
+ }, {
+ .name = "usb3:blue",
+ .gpio = 46,
+ }, {
+ .name = "usb4:blue",
+ .gpio = 47,
+ }, {
+ .name = "otb:blue",
+ .gpio = 48,
+ },
+};
+
+static struct gpio_led_platform_data iconnect_led_data = {
+ .leds = iconnect_led_pins,
+ .num_leds = ARRAY_SIZE(iconnect_led_pins),
+ .gpio_blink_set = orion_gpio_led_blink_set,
+};
+
+static struct platform_device iconnect_leds = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = &iconnect_led_data,
+ }
+};
+
+static unsigned int iconnect_mpp_config[] __initdata = {
+ MPP12_GPIO,
+ MPP35_GPIO,
+ MPP41_GPIO,
+ MPP42_GPIO,
+ MPP43_GPIO,
+ MPP44_GPIO,
+ MPP45_GPIO,
+ MPP46_GPIO,
+ MPP47_GPIO,
+ MPP48_GPIO,
+ 0
+};
+
+static struct i2c_board_info __initdata iconnect_board_info[] = {
+ {
+ I2C_BOARD_INFO("lm63", 0x4c),
+ },
+};
+
+static struct mtd_partition iconnect_nand_parts[] = {
+ {
+ .name = "flash",
+ .offset = 0,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+/* yikes... theses are the original input buttons */
+/* but I'm not convinced by the sw event choices */
+static struct gpio_keys_button iconnect_buttons[] = {
+ {
+ .type = EV_SW,
+ .code = SW_LID,
+ .gpio = 12,
+ .desc = "Reset Button",
+ .active_low = 1,
+ .debounce_interval = 100,
+ }, {
+ .type = EV_SW,
+ .code = SW_TABLET_MODE,
+ .gpio = 35,
+ .desc = "OTB Button",
+ .active_low = 1,
+ .debounce_interval = 100,
+ },
+};
+
+static struct gpio_keys_platform_data iconnect_button_data = {
+ .buttons = iconnect_buttons,
+ .nbuttons = ARRAY_SIZE(iconnect_buttons),
+};
+
+static struct platform_device iconnect_button_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .num_resources = 0,
+ .dev = {
+ .platform_data = &iconnect_button_data,
+ },
+};
+
+void __init iconnect_init(void)
+{
+ kirkwood_mpp_conf(iconnect_mpp_config);
+ kirkwood_nand_init(ARRAY_AND_SIZE(iconnect_nand_parts), 25);
+ kirkwood_i2c_init();
+ i2c_register_board_info(0, iconnect_board_info,
+ ARRAY_SIZE(iconnect_board_info));
+
+ kirkwood_ehci_init();
+ kirkwood_ge00_init(&iconnect_ge00_data);
+
+ platform_device_register(&iconnect_button_device);
+ platform_device_register(&iconnect_leds);
+}
+
+static int __init iconnect_pci_init(void)
+{
+ if (of_machine_is_compatible("iom,iconnect"))
+ kirkwood_pcie_init(KW_PCIE0);
+ return 0;
+}
+subsys_initcall(iconnect_pci_init);
diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c
index a02cae881f2f..3ad037385a5e 100644
--- a/arch/arm/mach-kirkwood/common.c
+++ b/arch/arm/mach-kirkwood/common.c
@@ -15,6 +15,7 @@
#include <linux/ata_platform.h>
#include <linux/mtd/nand.h>
#include <linux/dma-mapping.h>
+#include <linux/of.h>
#include <net/dsa.h>
#include <asm/page.h>
#include <asm/timex.h>
@@ -482,6 +483,9 @@ static int __init kirkwood_clock_gate(void)
unsigned int curr = readl(CLOCK_GATING_CTRL);
u32 dev, rev;
+#ifdef CONFIG_OF
+ struct device_node *np;
+#endif
kirkwood_pcie_id(&dev, &rev);
printk(KERN_DEBUG "Gating clock of unused units\n");
printk(KERN_DEBUG "before: 0x%08x\n", curr);
@@ -489,6 +493,14 @@ static int __init kirkwood_clock_gate(void)
/* Make sure those units are accessible */
writel(curr | CGC_SATA0 | CGC_SATA1 | CGC_PEX0 | CGC_PEX1, CLOCK_GATING_CTRL);
+#ifdef CONFIG_OF
+ np = of_find_compatible_node(NULL, NULL, "mrvl,orion-nand");
+ if (np && of_device_is_available(np)) {
+ kirkwood_clk_ctrl |= CGC_RUNIT;
+ of_node_put(np);
+ }
+#endif
+
/* For SATA: first shutdown the phy */
if (!(kirkwood_clk_ctrl & CGC_SATA0)) {
/* Disable PLL and IVREF */
diff --git a/arch/arm/mach-kirkwood/common.h b/arch/arm/mach-kirkwood/common.h
index fa8e7689c436..a34c41a5172e 100644
--- a/arch/arm/mach-kirkwood/common.h
+++ b/arch/arm/mach-kirkwood/common.h
@@ -58,6 +58,24 @@ void dreamplug_init(void);
static inline void dreamplug_init(void) {};
#endif
+#ifdef CONFIG_MACH_DLINK_KIRKWOOD_DT
+void dnskw_init(void);
+#else
+static inline void dnskw_init(void) {};
+#endif
+
+#ifdef CONFIG_MACH_ICONNECT_DT
+void iconnect_init(void);
+#else
+static inline void iconnect_init(void) {};
+#endif
+
+#ifdef CONFIG_MACH_IB62X0_DT
+void ib62x0_init(void);
+#else
+static inline void ib62x0_init(void) {};
+#endif
+
/* early init functions not converted to fdt yet */
char *kirkwood_id(void);
void kirkwood_l2_init(void);
diff --git a/arch/arm/mach-lpc32xx/Kconfig b/arch/arm/mach-lpc32xx/Kconfig
index 75946ac89ee9..e0b3eee83834 100644
--- a/arch/arm/mach-lpc32xx/Kconfig
+++ b/arch/arm/mach-lpc32xx/Kconfig
@@ -29,30 +29,4 @@ config ARCH_LPC32XX_UART6_SELECT
endmenu
-menu "LPC32XX chip components"
-
-config ARCH_LPC32XX_IRAM_FOR_NET
- bool "Use IRAM for network buffers"
- default y
- help
- Say Y here to use the LPC internal fast IRAM (i.e. 256KB SRAM) as
- network buffer. If the total combined required buffer sizes is
- larger than the size of IRAM, then SDRAM will be used instead.
-
- This can be enabled safely if the IRAM is not intended for other
- uses.
-
-config ARCH_LPC32XX_MII_SUPPORT
- bool "Check to enable MII support or leave disabled for RMII support"
- help
- Say Y here to enable MII support, or N for RMII support. Regardless of
- which support is selected, the ethernet interface driver needs to be
- selected in the device driver networking section.
-
- The PHY3250 reference board uses RMII, so users of this board should
- say N.
-
-endmenu
-
endif
-
diff --git a/arch/arm/mach-lpc32xx/clock.c b/arch/arm/mach-lpc32xx/clock.c
index 2fc24ca12054..f6a3ffec1f4b 100644
--- a/arch/arm/mach-lpc32xx/clock.c
+++ b/arch/arm/mach-lpc32xx/clock.c
@@ -1095,49 +1095,42 @@ struct clk *clk_get_parent(struct clk *clk)
}
EXPORT_SYMBOL(clk_get_parent);
-#define _REGISTER_CLOCK(d, n, c) \
- { \
- .dev_id = (d), \
- .con_id = (n), \
- .clk = &(c), \
- },
-
static struct clk_lookup lookups[] = {
- _REGISTER_CLOCK(NULL, "osc_32KHz", osc_32KHz)
- _REGISTER_CLOCK(NULL, "osc_pll397", osc_pll397)
- _REGISTER_CLOCK(NULL, "osc_main", osc_main)
- _REGISTER_CLOCK(NULL, "sys_ck", clk_sys)
- _REGISTER_CLOCK(NULL, "arm_pll_ck", clk_armpll)
- _REGISTER_CLOCK(NULL, "ck_pll5", clk_usbpll)
- _REGISTER_CLOCK(NULL, "hclk_ck", clk_hclk)
- _REGISTER_CLOCK(NULL, "pclk_ck", clk_pclk)
- _REGISTER_CLOCK(NULL, "timer0_ck", clk_timer0)
- _REGISTER_CLOCK(NULL, "timer1_ck", clk_timer1)
- _REGISTER_CLOCK(NULL, "timer2_ck", clk_timer2)
- _REGISTER_CLOCK(NULL, "timer3_ck", clk_timer3)
- _REGISTER_CLOCK(NULL, "vfp9_ck", clk_vfp9)
- _REGISTER_CLOCK(NULL, "clk_dmac", clk_dma)
- _REGISTER_CLOCK("pnx4008-watchdog", NULL, clk_wdt)
- _REGISTER_CLOCK(NULL, "uart3_ck", clk_uart3)
- _REGISTER_CLOCK(NULL, "uart4_ck", clk_uart4)
- _REGISTER_CLOCK(NULL, "uart5_ck", clk_uart5)
- _REGISTER_CLOCK(NULL, "uart6_ck", clk_uart6)
- _REGISTER_CLOCK("pnx-i2c.0", NULL, clk_i2c0)
- _REGISTER_CLOCK("pnx-i2c.1", NULL, clk_i2c1)
- _REGISTER_CLOCK("pnx-i2c.2", NULL, clk_i2c2)
- _REGISTER_CLOCK("dev:ssp0", NULL, clk_ssp0)
- _REGISTER_CLOCK("dev:ssp1", NULL, clk_ssp1)
- _REGISTER_CLOCK("lpc32xx_keys.0", NULL, clk_kscan)
- _REGISTER_CLOCK("lpc32xx-nand.0", "nand_ck", clk_nand)
- _REGISTER_CLOCK("lpc32xx-adc", NULL, clk_adc)
- _REGISTER_CLOCK(NULL, "i2s0_ck", clk_i2s0)
- _REGISTER_CLOCK(NULL, "i2s1_ck", clk_i2s1)
- _REGISTER_CLOCK("ts-lpc32xx", NULL, clk_tsc)
- _REGISTER_CLOCK("dev:mmc0", NULL, clk_mmc)
- _REGISTER_CLOCK("lpc-eth.0", NULL, clk_net)
- _REGISTER_CLOCK("dev:clcd", NULL, clk_lcd)
- _REGISTER_CLOCK("lpc32xx_udc", "ck_usbd", clk_usbd)
- _REGISTER_CLOCK("lpc32xx_rtc", NULL, clk_rtc)
+ CLKDEV_INIT(NULL, "osc_32KHz", &osc_32KHz),
+ CLKDEV_INIT(NULL, "osc_pll397", &osc_pll397),
+ CLKDEV_INIT(NULL, "osc_main", &osc_main),
+ CLKDEV_INIT(NULL, "sys_ck", &clk_sys),
+ CLKDEV_INIT(NULL, "arm_pll_ck", &clk_armpll),
+ CLKDEV_INIT(NULL, "ck_pll5", &clk_usbpll),
+ CLKDEV_INIT(NULL, "hclk_ck", &clk_hclk),
+ CLKDEV_INIT(NULL, "pclk_ck", &clk_pclk),
+ CLKDEV_INIT(NULL, "timer0_ck", &clk_timer0),
+ CLKDEV_INIT(NULL, "timer1_ck", &clk_timer1),
+ CLKDEV_INIT(NULL, "timer2_ck", &clk_timer2),
+ CLKDEV_INIT(NULL, "timer3_ck", &clk_timer3),
+ CLKDEV_INIT(NULL, "vfp9_ck", &clk_vfp9),
+ CLKDEV_INIT("pl08xdmac", NULL, &clk_dma),
+ CLKDEV_INIT("4003c000.watchdog", NULL, &clk_wdt),
+ CLKDEV_INIT(NULL, "uart3_ck", &clk_uart3),
+ CLKDEV_INIT(NULL, "uart4_ck", &clk_uart4),
+ CLKDEV_INIT(NULL, "uart5_ck", &clk_uart5),
+ CLKDEV_INIT(NULL, "uart6_ck", &clk_uart6),
+ CLKDEV_INIT("400a0000.i2c", NULL, &clk_i2c0),
+ CLKDEV_INIT("400a8000.i2c", NULL, &clk_i2c1),
+ CLKDEV_INIT("31020300.i2c", NULL, &clk_i2c2),
+ CLKDEV_INIT("dev:ssp0", NULL, &clk_ssp0),
+ CLKDEV_INIT("dev:ssp1", NULL, &clk_ssp1),
+ CLKDEV_INIT("lpc32xx_keys.0", NULL, &clk_kscan),
+ CLKDEV_INIT("lpc32xx-nand.0", "nand_ck", &clk_nand),
+ CLKDEV_INIT("40048000.adc", NULL, &clk_adc),
+ CLKDEV_INIT(NULL, "i2s0_ck", &clk_i2s0),
+ CLKDEV_INIT(NULL, "i2s1_ck", &clk_i2s1),
+ CLKDEV_INIT("40048000.tsc", NULL, &clk_tsc),
+ CLKDEV_INIT("20098000.sd", NULL, &clk_mmc),
+ CLKDEV_INIT("31060000.ethernet", NULL, &clk_net),
+ CLKDEV_INIT("dev:clcd", NULL, &clk_lcd),
+ CLKDEV_INIT("31020000.usbd", "ck_usbd", &clk_usbd),
+ CLKDEV_INIT("lpc32xx_rtc", NULL, &clk_rtc),
};
static int __init clk_init(void)
diff --git a/arch/arm/mach-lpc32xx/common.c b/arch/arm/mach-lpc32xx/common.c
index bbbf063a74c2..5c96057b6d78 100644
--- a/arch/arm/mach-lpc32xx/common.c
+++ b/arch/arm/mach-lpc32xx/common.c
@@ -27,186 +27,11 @@
#include <asm/mach/map.h>
-#include <mach/i2c.h>
#include <mach/hardware.h>
#include <mach/platform.h>
#include "common.h"
/*
- * Watchdog timer
- */
-static struct resource watchdog_resources[] = {
- [0] = {
- .start = LPC32XX_WDTIM_BASE,
- .end = LPC32XX_WDTIM_BASE + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-struct platform_device lpc32xx_watchdog_device = {
- .name = "pnx4008-watchdog",
- .id = -1,
- .num_resources = ARRAY_SIZE(watchdog_resources),
- .resource = watchdog_resources,
-};
-
-/*
- * I2C busses
- */
-static struct i2c_pnx_data i2c0_data = {
- .name = I2C_CHIP_NAME "1",
- .base = LPC32XX_I2C1_BASE,
- .irq = IRQ_LPC32XX_I2C_1,
-};
-
-static struct i2c_pnx_data i2c1_data = {
- .name = I2C_CHIP_NAME "2",
- .base = LPC32XX_I2C2_BASE,
- .irq = IRQ_LPC32XX_I2C_2,
-};
-
-static struct i2c_pnx_data i2c2_data = {
- .name = "USB-I2C",
- .base = LPC32XX_OTG_I2C_BASE,
- .irq = IRQ_LPC32XX_USB_I2C,
-};
-
-struct platform_device lpc32xx_i2c0_device = {
- .name = "pnx-i2c",
- .id = 0,
- .dev = {
- .platform_data = &i2c0_data,
- },
-};
-
-struct platform_device lpc32xx_i2c1_device = {
- .name = "pnx-i2c",
- .id = 1,
- .dev = {
- .platform_data = &i2c1_data,
- },
-};
-
-struct platform_device lpc32xx_i2c2_device = {
- .name = "pnx-i2c",
- .id = 2,
- .dev = {
- .platform_data = &i2c2_data,
- },
-};
-
-/* TSC (Touch Screen Controller) */
-
-static struct resource lpc32xx_tsc_resources[] = {
- {
- .start = LPC32XX_ADC_BASE,
- .end = LPC32XX_ADC_BASE + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_LPC32XX_TS_IRQ,
- .end = IRQ_LPC32XX_TS_IRQ,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-struct platform_device lpc32xx_tsc_device = {
- .name = "ts-lpc32xx",
- .id = -1,
- .num_resources = ARRAY_SIZE(lpc32xx_tsc_resources),
- .resource = lpc32xx_tsc_resources,
-};
-
-/* RTC */
-
-static struct resource lpc32xx_rtc_resources[] = {
- {
- .start = LPC32XX_RTC_BASE,
- .end = LPC32XX_RTC_BASE + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
- },{
- .start = IRQ_LPC32XX_RTC,
- .end = IRQ_LPC32XX_RTC,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-struct platform_device lpc32xx_rtc_device = {
- .name = "rtc-lpc32xx",
- .id = -1,
- .num_resources = ARRAY_SIZE(lpc32xx_rtc_resources),
- .resource = lpc32xx_rtc_resources,
-};
-
-/*
- * ADC support
- */
-static struct resource adc_resources[] = {
- {
- .start = LPC32XX_ADC_BASE,
- .end = LPC32XX_ADC_BASE + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_LPC32XX_TS_IRQ,
- .end = IRQ_LPC32XX_TS_IRQ,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-struct platform_device lpc32xx_adc_device = {
- .name = "lpc32xx-adc",
- .id = -1,
- .num_resources = ARRAY_SIZE(adc_resources),
- .resource = adc_resources,
-};
-
-/*
- * USB support
- */
-/* The dmamask must be set for OHCI to work */
-static u64 ohci_dmamask = ~(u32) 0;
-static struct resource ohci_resources[] = {
- {
- .start = IO_ADDRESS(LPC32XX_USB_BASE),
- .end = IO_ADDRESS(LPC32XX_USB_BASE + 0x100 - 1),
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_LPC32XX_USB_HOST,
- .flags = IORESOURCE_IRQ,
- },
-};
-struct platform_device lpc32xx_ohci_device = {
- .name = "usb-ohci",
- .id = -1,
- .dev = {
- .dma_mask = &ohci_dmamask,
- .coherent_dma_mask = 0xFFFFFFFF,
- },
- .num_resources = ARRAY_SIZE(ohci_resources),
- .resource = ohci_resources,
-};
-
-/*
- * Network Support
- */
-static struct resource net_resources[] = {
- [0] = DEFINE_RES_MEM(LPC32XX_ETHERNET_BASE, SZ_4K),
- [1] = DEFINE_RES_MEM(LPC32XX_IRAM_BASE, SZ_128K),
- [2] = DEFINE_RES_IRQ(IRQ_LPC32XX_ETHERNET),
-};
-
-static u64 lpc32xx_mac_dma_mask = 0xffffffffUL;
-struct platform_device lpc32xx_net_device = {
- .name = "lpc-eth",
- .id = 0,
- .dev = {
- .dma_mask = &lpc32xx_mac_dma_mask,
- .coherent_dma_mask = 0xffffffffUL,
- },
- .num_resources = ARRAY_SIZE(net_resources),
- .resource = net_resources,
-};
-
-/*
* Returns the unique ID for the device
*/
void lpc32xx_get_uid(u32 devid[4])
@@ -398,3 +223,16 @@ void lpc23xx_restart(char mode, const char *cmd)
while (1)
;
}
+
+static int __init lpc32xx_display_uid(void)
+{
+ u32 uid[4];
+
+ lpc32xx_get_uid(uid);
+
+ printk(KERN_INFO "LPC32XX unique ID: %08x%08x%08x%08x\n",
+ uid[3], uid[2], uid[1], uid[0]);
+
+ return 1;
+}
+arch_initcall(lpc32xx_display_uid);
diff --git a/arch/arm/mach-lpc32xx/common.h b/arch/arm/mach-lpc32xx/common.h
index 68e45e8c9486..afeac3b1fae6 100644
--- a/arch/arm/mach-lpc32xx/common.h
+++ b/arch/arm/mach-lpc32xx/common.h
@@ -23,26 +23,12 @@
#include <linux/platform_device.h>
/*
- * Arch specific platform device structures
- */
-extern struct platform_device lpc32xx_watchdog_device;
-extern struct platform_device lpc32xx_i2c0_device;
-extern struct platform_device lpc32xx_i2c1_device;
-extern struct platform_device lpc32xx_i2c2_device;
-extern struct platform_device lpc32xx_tsc_device;
-extern struct platform_device lpc32xx_adc_device;
-extern struct platform_device lpc32xx_rtc_device;
-extern struct platform_device lpc32xx_ohci_device;
-extern struct platform_device lpc32xx_net_device;
-
-/*
* Other arch specific structures and functions
*/
extern struct sys_timer lpc32xx_timer;
extern void __init lpc32xx_init_irq(void);
extern void __init lpc32xx_map_io(void);
extern void __init lpc32xx_serial_init(void);
-extern void __init lpc32xx_gpio_init(void);
extern void lpc23xx_restart(char, const char *);
diff --git a/arch/arm/mach-lpc32xx/include/mach/gpio.h b/arch/arm/mach-lpc32xx/include/mach/gpio.h
index 40a8c178f10d..2ba6ca412bef 100644
--- a/arch/arm/mach-lpc32xx/include/mach/gpio.h
+++ b/arch/arm/mach-lpc32xx/include/mach/gpio.h
@@ -1 +1,8 @@
-/* empty */
+#ifndef __MACH_GPIO_H
+#define __MACH_GPIO_H
+
+#include "gpio-lpc32xx.h"
+
+#define ARCH_NR_GPIOS (LPC32XX_GPO_P3_GRP + LPC32XX_GPO_P3_MAX)
+
+#endif /* __MACH_GPIO_H */
diff --git a/arch/arm/mach-lpc32xx/include/mach/i2c.h b/arch/arm/mach-lpc32xx/include/mach/i2c.h
deleted file mode 100644
index 034dc9286bcc..000000000000
--- a/arch/arm/mach-lpc32xx/include/mach/i2c.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * PNX4008-specific tweaks for I2C IP3204 block
- *
- * Author: Vitaly Wool <vwool@ru.mvista.com>
- *
- * 2005 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifndef __ASM_ARCH_I2C_H
-#define __ASM_ARCH_I2C_H
-
-enum {
- mstatus_tdi = 0x00000001,
- mstatus_afi = 0x00000002,
- mstatus_nai = 0x00000004,
- mstatus_drmi = 0x00000008,
- mstatus_active = 0x00000020,
- mstatus_scl = 0x00000040,
- mstatus_sda = 0x00000080,
- mstatus_rff = 0x00000100,
- mstatus_rfe = 0x00000200,
- mstatus_tff = 0x00000400,
- mstatus_tfe = 0x00000800,
-};
-
-enum {
- mcntrl_tdie = 0x00000001,
- mcntrl_afie = 0x00000002,
- mcntrl_naie = 0x00000004,
- mcntrl_drmie = 0x00000008,
- mcntrl_daie = 0x00000020,
- mcntrl_rffie = 0x00000040,
- mcntrl_tffie = 0x00000080,
- mcntrl_reset = 0x00000100,
- mcntrl_cdbmode = 0x00000400,
-};
-
-enum {
- rw_bit = 1 << 0,
- start_bit = 1 << 8,
- stop_bit = 1 << 9,
-};
-
-#define I2C_REG_RX(a) ((a)->ioaddr) /* Rx FIFO reg (RO) */
-#define I2C_REG_TX(a) ((a)->ioaddr) /* Tx FIFO reg (WO) */
-#define I2C_REG_STS(a) ((a)->ioaddr + 0x04) /* Status reg (RO) */
-#define I2C_REG_CTL(a) ((a)->ioaddr + 0x08) /* Ctl reg */
-#define I2C_REG_CKL(a) ((a)->ioaddr + 0x0c) /* Clock divider low */
-#define I2C_REG_CKH(a) ((a)->ioaddr + 0x10) /* Clock divider high */
-#define I2C_REG_ADR(a) ((a)->ioaddr + 0x14) /* I2C address */
-#define I2C_REG_RFL(a) ((a)->ioaddr + 0x18) /* Rx FIFO level (RO) */
-#define I2C_REG_TFL(a) ((a)->ioaddr + 0x1c) /* Tx FIFO level (RO) */
-#define I2C_REG_RXB(a) ((a)->ioaddr + 0x20) /* Num of bytes Rx-ed (RO) */
-#define I2C_REG_TXB(a) ((a)->ioaddr + 0x24) /* Num of bytes Tx-ed (RO) */
-#define I2C_REG_TXS(a) ((a)->ioaddr + 0x28) /* Tx slave FIFO (RO) */
-#define I2C_REG_STFL(a) ((a)->ioaddr + 0x2c) /* Tx slave FIFO level (RO) */
-
-#define I2C_CHIP_NAME "PNX4008-I2C"
-
-#endif /* __ASM_ARCH_I2C_H */
diff --git a/arch/arm/mach-lpc32xx/irq.c b/arch/arm/mach-lpc32xx/irq.c
index d080cb1123dd..5b1cc35e6fba 100644
--- a/arch/arm/mach-lpc32xx/irq.c
+++ b/arch/arm/mach-lpc32xx/irq.c
@@ -22,6 +22,11 @@
#include <linux/irq.h>
#include <linux/err.h>
#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
#include <mach/irqs.h>
#include <mach/hardware.h>
@@ -44,6 +49,9 @@
#define SIC1_ATR_DEFAULT 0x00026000
#define SIC2_ATR_DEFAULT 0x00000000
+static struct irq_domain *lpc32xx_mic_domain;
+static struct device_node *lpc32xx_mic_np;
+
struct lpc32xx_event_group_regs {
void __iomem *enab_reg;
void __iomem *edge_reg;
@@ -203,7 +211,7 @@ static void lpc32xx_mask_irq(struct irq_data *d)
{
unsigned int reg, ctrl, mask;
- get_controller(d->irq, &ctrl, &mask);
+ get_controller(d->hwirq, &ctrl, &mask);
reg = __raw_readl(LPC32XX_INTC_MASK(ctrl)) & ~mask;
__raw_writel(reg, LPC32XX_INTC_MASK(ctrl));
@@ -213,7 +221,7 @@ static void lpc32xx_unmask_irq(struct irq_data *d)
{
unsigned int reg, ctrl, mask;
- get_controller(d->irq, &ctrl, &mask);
+ get_controller(d->hwirq, &ctrl, &mask);
reg = __raw_readl(LPC32XX_INTC_MASK(ctrl)) | mask;
__raw_writel(reg, LPC32XX_INTC_MASK(ctrl));
@@ -223,14 +231,14 @@ static void lpc32xx_ack_irq(struct irq_data *d)
{
unsigned int ctrl, mask;
- get_controller(d->irq, &ctrl, &mask);
+ get_controller(d->hwirq, &ctrl, &mask);
__raw_writel(mask, LPC32XX_INTC_RAW_STAT(ctrl));
/* Also need to clear pending wake event */
- if (lpc32xx_events[d->irq].mask != 0)
- __raw_writel(lpc32xx_events[d->irq].mask,
- lpc32xx_events[d->irq].event_group->rawstat_reg);
+ if (lpc32xx_events[d->hwirq].mask != 0)
+ __raw_writel(lpc32xx_events[d->hwirq].mask,
+ lpc32xx_events[d->hwirq].event_group->rawstat_reg);
}
static void __lpc32xx_set_irq_type(unsigned int irq, int use_high_level,
@@ -274,22 +282,22 @@ static int lpc32xx_set_irq_type(struct irq_data *d, unsigned int type)
switch (type) {
case IRQ_TYPE_EDGE_RISING:
/* Rising edge sensitive */
- __lpc32xx_set_irq_type(d->irq, 1, 1);
+ __lpc32xx_set_irq_type(d->hwirq, 1, 1);
break;
case IRQ_TYPE_EDGE_FALLING:
/* Falling edge sensitive */
- __lpc32xx_set_irq_type(d->irq, 0, 1);
+ __lpc32xx_set_irq_type(d->hwirq, 0, 1);
break;
case IRQ_TYPE_LEVEL_LOW:
/* Low level sensitive */
- __lpc32xx_set_irq_type(d->irq, 0, 0);
+ __lpc32xx_set_irq_type(d->hwirq, 0, 0);
break;
case IRQ_TYPE_LEVEL_HIGH:
/* High level sensitive */
- __lpc32xx_set_irq_type(d->irq, 1, 0);
+ __lpc32xx_set_irq_type(d->hwirq, 1, 0);
break;
/* Other modes are not supported */
@@ -298,7 +306,7 @@ static int lpc32xx_set_irq_type(struct irq_data *d, unsigned int type)
}
/* Ok to use the level handler for all types */
- irq_set_handler(d->irq, handle_level_irq);
+ irq_set_handler(d->hwirq, handle_level_irq);
return 0;
}
@@ -307,33 +315,33 @@ static int lpc32xx_irq_wake(struct irq_data *d, unsigned int state)
{
unsigned long eventreg;
- if (lpc32xx_events[d->irq].mask != 0) {
- eventreg = __raw_readl(lpc32xx_events[d->irq].
+ if (lpc32xx_events[d->hwirq].mask != 0) {
+ eventreg = __raw_readl(lpc32xx_events[d->hwirq].
event_group->enab_reg);
if (state)
- eventreg |= lpc32xx_events[d->irq].mask;
+ eventreg |= lpc32xx_events[d->hwirq].mask;
else {
- eventreg &= ~lpc32xx_events[d->irq].mask;
+ eventreg &= ~lpc32xx_events[d->hwirq].mask;
/*
* When disabling the wakeup, clear the latched
* event
*/
- __raw_writel(lpc32xx_events[d->irq].mask,
- lpc32xx_events[d->irq].
+ __raw_writel(lpc32xx_events[d->hwirq].mask,
+ lpc32xx_events[d->hwirq].
event_group->rawstat_reg);
}
__raw_writel(eventreg,
- lpc32xx_events[d->irq].event_group->enab_reg);
+ lpc32xx_events[d->hwirq].event_group->enab_reg);
return 0;
}
/* Clear event */
- __raw_writel(lpc32xx_events[d->irq].mask,
- lpc32xx_events[d->irq].event_group->rawstat_reg);
+ __raw_writel(lpc32xx_events[d->hwirq].mask,
+ lpc32xx_events[d->hwirq].event_group->rawstat_reg);
return -ENODEV;
}
@@ -353,6 +361,7 @@ static void __init lpc32xx_set_default_mappings(unsigned int apr,
}
static struct irq_chip lpc32xx_irq_chip = {
+ .name = "MIC",
.irq_ack = lpc32xx_ack_irq,
.irq_mask = lpc32xx_mask_irq,
.irq_unmask = lpc32xx_unmask_irq,
@@ -386,9 +395,23 @@ static void lpc32xx_sic2_handler(unsigned int irq, struct irq_desc *desc)
}
}
+static int __init __lpc32xx_mic_of_init(struct device_node *node,
+ struct device_node *parent)
+{
+ lpc32xx_mic_np = node;
+
+ return 0;
+}
+
+static const struct of_device_id mic_of_match[] __initconst = {
+ { .compatible = "nxp,lpc3220-mic", .data = __lpc32xx_mic_of_init },
+ { }
+};
+
void __init lpc32xx_init_irq(void)
{
unsigned int i;
+ int irq_base;
/* Setup MIC */
__raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_MIC_BASE));
@@ -448,4 +471,19 @@ void __init lpc32xx_init_irq(void)
LPC32XX_CLKPWR_PIN_RS);
__raw_writel(__raw_readl(LPC32XX_CLKPWR_INT_RS),
LPC32XX_CLKPWR_INT_RS);
+
+ of_irq_init(mic_of_match);
+
+ irq_base = irq_alloc_descs(-1, 0, NR_IRQS, 0);
+ if (irq_base < 0) {
+ pr_warn("Cannot allocate irq_descs, assuming pre-allocated\n");
+ irq_base = 0;
+ }
+
+ lpc32xx_mic_domain = irq_domain_add_legacy(lpc32xx_mic_np, NR_IRQS,
+ irq_base, 0,
+ &irq_domain_simple_ops,
+ NULL);
+ if (!lpc32xx_mic_domain)
+ panic("Unable to add MIC irq domain\n");
}
diff --git a/arch/arm/mach-lpc32xx/phy3250.c b/arch/arm/mach-lpc32xx/phy3250.c
index 7f7401ec7487..540106cdb9ec 100644
--- a/arch/arm/mach-lpc32xx/phy3250.c
+++ b/arch/arm/mach-lpc32xx/phy3250.c
@@ -1,8 +1,9 @@
/*
- * arch/arm/mach-lpc32xx/phy3250.c
+ * Platform support for LPC32xx SoC
*
* Author: Kevin Wells <kevin.wells@nxp.com>
*
+ * Copyright (C) 2012 Roland Stigge <stigge@antcom.de>
* Copyright (C) 2010 NXP Semiconductors
*
* This program is free software; you can redistribute it and/or modify
@@ -25,11 +26,16 @@
#include <linux/device.h>
#include <linux/spi/spi.h>
#include <linux/spi/eeprom.h>
-#include <linux/leds.h>
#include <linux/gpio.h>
#include <linux/amba/bus.h>
#include <linux/amba/clcd.h>
#include <linux/amba/pl022.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
+#include <linux/amba/pl08x.h>
#include <asm/setup.h>
#include <asm/mach-types.h>
@@ -47,7 +53,6 @@
#define SPI0_CS_GPIO LPC32XX_GPIO(LPC32XX_GPIO_P3_GRP, 5)
#define LCD_POWER_GPIO LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 0)
#define BKL_POWER_GPIO LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 4)
-#define LED_GPIO LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 1)
/*
* AMBA LCD controller
@@ -150,9 +155,6 @@ static struct clcd_board lpc32xx_clcd_data = {
.remove = lpc32xx_clcd_remove,
};
-static AMBA_AHB_DEVICE(lpc32xx_clcd, "dev:clcd", 0,
- LPC32XX_LCD_BASE, { IRQ_LPC32XX_LCD }, &lpc32xx_clcd_data);
-
/*
* AMBA SSP (SPI)
*/
@@ -180,8 +182,11 @@ static struct pl022_ssp_controller lpc32xx_ssp0_data = {
.enable_dma = 0,
};
-static AMBA_APB_DEVICE(lpc32xx_ssp0, "dev:ssp0", 0,
- LPC32XX_SSP0_BASE, { IRQ_LPC32XX_SSP0 }, &lpc32xx_ssp0_data);
+static struct pl022_ssp_controller lpc32xx_ssp1_data = {
+ .bus_id = 1,
+ .num_chipselect = 1,
+ .enable_dma = 0,
+};
/* AT25 driver registration */
static int __init phy3250_spi_board_register(void)
@@ -221,73 +226,20 @@ static int __init phy3250_spi_board_register(void)
}
arch_initcall(phy3250_spi_board_register);
-static struct i2c_board_info __initdata phy3250_i2c_board_info[] = {
- {
- I2C_BOARD_INFO("pcf8563", 0x51),
- },
-};
-
-static struct gpio_led phy_leds[] = {
- {
- .name = "led0",
- .gpio = LED_GPIO,
- .active_low = 1,
- .default_trigger = "heartbeat",
- },
-};
-
-static struct gpio_led_platform_data led_data = {
- .leds = phy_leds,
- .num_leds = ARRAY_SIZE(phy_leds),
-};
-
-static struct platform_device lpc32xx_gpio_led_device = {
- .name = "leds-gpio",
- .id = -1,
- .dev.platform_data = &led_data,
+static struct pl08x_platform_data pl08x_pd = {
};
-static struct platform_device *phy3250_devs[] __initdata = {
- &lpc32xx_rtc_device,
- &lpc32xx_tsc_device,
- &lpc32xx_i2c0_device,
- &lpc32xx_i2c1_device,
- &lpc32xx_i2c2_device,
- &lpc32xx_watchdog_device,
- &lpc32xx_gpio_led_device,
- &lpc32xx_adc_device,
- &lpc32xx_ohci_device,
- &lpc32xx_net_device,
+static const struct of_dev_auxdata lpc32xx_auxdata_lookup[] __initconst = {
+ OF_DEV_AUXDATA("arm,pl022", 0x20084000, "dev:ssp0", &lpc32xx_ssp0_data),
+ OF_DEV_AUXDATA("arm,pl022", 0x2008C000, "dev:ssp1", &lpc32xx_ssp1_data),
+ OF_DEV_AUXDATA("arm,pl110", 0x31040000, "dev:clcd", &lpc32xx_clcd_data),
+ OF_DEV_AUXDATA("arm,pl080", 0x31000000, "pl08xdmac", &pl08x_pd),
+ { }
};
-static struct amba_device *amba_devs[] __initdata = {
- &lpc32xx_clcd_device,
- &lpc32xx_ssp0_device,
-};
-
-/*
- * Board specific functions
- */
-static void __init phy3250_board_init(void)
+static void __init lpc3250_machine_init(void)
{
u32 tmp;
- int i;
-
- lpc32xx_gpio_init();
-
- /* Register GPIOs used on this board */
- if (gpio_request(SPI0_CS_GPIO, "spi0 cs"))
- printk(KERN_ERR "Error requesting gpio %u",
- SPI0_CS_GPIO);
- else if (gpio_direction_output(SPI0_CS_GPIO, 1))
- printk(KERN_ERR "Error setting gpio %u to output",
- SPI0_CS_GPIO);
-
- /* Setup network interface for RMII mode */
- tmp = __raw_readl(LPC32XX_CLKPWR_MACCLK_CTRL);
- tmp &= ~LPC32XX_CLKPWR_MACCTRL_PINS_MSK;
- tmp |= LPC32XX_CLKPWR_MACCTRL_USE_RMII_PINS;
- __raw_writel(tmp, LPC32XX_CLKPWR_MACCLK_CTRL);
/* Setup SLC NAND controller muxing */
__raw_writel(LPC32XX_CLKPWR_NANDCLK_SEL_SLC,
@@ -300,6 +252,12 @@ static void __init phy3250_board_init(void)
tmp |= LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_TFT16;
__raw_writel(tmp, LPC32XX_CLKPWR_LCDCLK_CTRL);
+ /* Set up USB power */
+ tmp = __raw_readl(LPC32XX_CLKPWR_USB_CTRL);
+ tmp |= LPC32XX_CLKPWR_USBCTRL_HCLK_EN |
+ LPC32XX_CLKPWR_USBCTRL_USBI2C_EN;
+ __raw_writel(tmp, LPC32XX_CLKPWR_USB_CTRL);
+
/* Set up I2C pull levels */
tmp = __raw_readl(LPC32XX_CLKPWR_I2C_CLK_CTRL);
tmp |= LPC32XX_CLKPWR_I2CCLK_USBI2CHI_DRIVE |
@@ -321,54 +279,51 @@ static void __init phy3250_board_init(void)
/*
* AMBA peripheral clocks need to be enabled prior to AMBA device
* detection or a data fault will occur, so enable the clocks
- * here. However, we don't want to enable them if the peripheral
- * isn't included in the image
+ * here.
*/
-#ifdef CONFIG_FB_ARMCLCD
tmp = __raw_readl(LPC32XX_CLKPWR_LCDCLK_CTRL);
__raw_writel((tmp | LPC32XX_CLKPWR_LCDCTRL_CLK_EN),
LPC32XX_CLKPWR_LCDCLK_CTRL);
-#endif
-#ifdef CONFIG_SPI_PL022
+
tmp = __raw_readl(LPC32XX_CLKPWR_SSP_CLK_CTRL);
__raw_writel((tmp | LPC32XX_CLKPWR_SSPCTRL_SSPCLK0_EN),
LPC32XX_CLKPWR_SSP_CLK_CTRL);
-#endif
- platform_add_devices(phy3250_devs, ARRAY_SIZE(phy3250_devs));
- for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
- struct amba_device *d = amba_devs[i];
- amba_device_register(d, &iomem_resource);
- }
+ tmp = __raw_readl(LPC32XX_CLKPWR_DMA_CLK_CTRL);
+ __raw_writel((tmp | LPC32XX_CLKPWR_DMACLKCTRL_CLK_EN),
+ LPC32XX_CLKPWR_DMA_CLK_CTRL);
/* Test clock needed for UDA1380 initial init */
__raw_writel(LPC32XX_CLKPWR_TESTCLK2_SEL_MOSC |
LPC32XX_CLKPWR_TESTCLK_TESTCLK2_EN,
LPC32XX_CLKPWR_TEST_CLK_SEL);
- i2c_register_board_info(0, phy3250_i2c_board_info,
- ARRAY_SIZE(phy3250_i2c_board_info));
-}
-
-static int __init lpc32xx_display_uid(void)
-{
- u32 uid[4];
-
- lpc32xx_get_uid(uid);
-
- printk(KERN_INFO "LPC32XX unique ID: %08x%08x%08x%08x\n",
- uid[3], uid[2], uid[1], uid[0]);
+ of_platform_populate(NULL, of_default_bus_match_table,
+ lpc32xx_auxdata_lookup, NULL);
- return 1;
+ /* Register GPIOs used on this board */
+ if (gpio_request(SPI0_CS_GPIO, "spi0 cs"))
+ printk(KERN_ERR "Error requesting gpio %u",
+ SPI0_CS_GPIO);
+ else if (gpio_direction_output(SPI0_CS_GPIO, 1))
+ printk(KERN_ERR "Error setting gpio %u to output",
+ SPI0_CS_GPIO);
}
-arch_initcall(lpc32xx_display_uid);
-MACHINE_START(PHY3250, "Phytec 3250 board with the LPC3250 Microcontroller")
- /* Maintainer: Kevin Wells, NXP Semiconductors */
+static char const *lpc32xx_dt_compat[] __initdata = {
+ "nxp,lpc3220",
+ "nxp,lpc3230",
+ "nxp,lpc3240",
+ "nxp,lpc3250",
+ NULL
+};
+
+DT_MACHINE_START(LPC32XX_DT, "LPC32XX SoC (Flattened Device Tree)")
.atag_offset = 0x100,
.map_io = lpc32xx_map_io,
.init_irq = lpc32xx_init_irq,
.timer = &lpc32xx_timer,
- .init_machine = phy3250_board_init,
+ .init_machine = lpc3250_machine_init,
+ .dt_compat = lpc32xx_dt_compat,
.restart = lpc23xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-mmp/Kconfig b/arch/arm/mach-mmp/Kconfig
index 5a90b9a3ab6e..7fddd01b85b9 100644
--- a/arch/arm/mach-mmp/Kconfig
+++ b/arch/arm/mach-mmp/Kconfig
@@ -2,16 +2,6 @@ if ARCH_MMP
menu "Marvell PXA168/910/MMP2 Implmentations"
-config MACH_MMP_DT
- bool "Support MMP2 platforms from device tree"
- select CPU_PXA168
- select CPU_PXA910
- select USE_OF
- help
- Include support for Marvell MMP2 based platforms using
- the device tree. Needn't select any other machine while
- MACH_MMP_DT is enabled.
-
config MACH_ASPENITE
bool "Marvell's PXA168 Aspenite Development Board"
select CPU_PXA168
@@ -94,6 +84,25 @@ config MACH_GPLUGD
Say 'Y' here if you want to support the Marvell PXA168-based
GuruPlug Display (gplugD) Board
+config MACH_MMP_DT
+ bool "Support MMP (ARMv5) platforms from device tree"
+ select CPU_PXA168
+ select CPU_PXA910
+ select USE_OF
+ help
+ Include support for Marvell MMP2 based platforms using
+ the device tree. Needn't select any other machine while
+ MACH_MMP_DT is enabled.
+
+config MACH_MMP2_DT
+ bool "Support MMP2 (ARMv7) platforms from device tree"
+ depends on !CPU_MOHAWK
+ select CPU_MMP2
+ select USE_OF
+ help
+ Include support for Marvell MMP2 based platforms using
+ the device tree.
+
endmenu
config CPU_PXA168
@@ -113,4 +122,11 @@ config CPU_MMP2
select CPU_PJ4
help
Select code specific to MMP2. MMP2 is ARMv7 compatible.
+
+config USB_EHCI_MV_U2O
+ bool "EHCI support for PXA USB OTG controller"
+ depends on USB_EHCI_MV
+ help
+ Enables support for OTG controller which can be switched to host mode.
+
endif
diff --git a/arch/arm/mach-mmp/Makefile b/arch/arm/mach-mmp/Makefile
index 4fc0ff5dc96d..b786f7e6cd1f 100644
--- a/arch/arm/mach-mmp/Makefile
+++ b/arch/arm/mach-mmp/Makefile
@@ -2,12 +2,17 @@
# Makefile for Marvell's PXA168 processors line
#
-obj-y += common.o clock.o devices.o time.o
+obj-y += common.o clock.o devices.o time.o irq.o
# SoC support
-obj-$(CONFIG_CPU_PXA168) += pxa168.o irq-pxa168.o
-obj-$(CONFIG_CPU_PXA910) += pxa910.o irq-pxa168.o
-obj-$(CONFIG_CPU_MMP2) += mmp2.o irq-mmp2.o sram.o
+obj-$(CONFIG_CPU_PXA168) += pxa168.o
+obj-$(CONFIG_CPU_PXA910) += pxa910.o
+obj-$(CONFIG_CPU_MMP2) += mmp2.o sram.o
+
+ifeq ($(CONFIG_PM),y)
+obj-$(CONFIG_CPU_PXA910) += pm-pxa910.o
+obj-$(CONFIG_CPU_MMP2) += pm-mmp2.o
+endif
# board support
obj-$(CONFIG_MACH_ASPENITE) += aspenite.o
@@ -19,5 +24,6 @@ obj-$(CONFIG_MACH_BROWNSTONE) += brownstone.o
obj-$(CONFIG_MACH_FLINT) += flint.o
obj-$(CONFIG_MACH_MARVELL_JASPER) += jasper.o
obj-$(CONFIG_MACH_MMP_DT) += mmp-dt.o
+obj-$(CONFIG_MACH_MMP2_DT) += mmp2-dt.o
obj-$(CONFIG_MACH_TETON_BGA) += teton_bga.o
obj-$(CONFIG_MACH_GPLUGD) += gplugd.o
diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c
index bf5d8e195c3e..223090b1444d 100644
--- a/arch/arm/mach-mmp/aspenite.c
+++ b/arch/arm/mach-mmp/aspenite.c
@@ -17,6 +17,7 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
#include <linux/interrupt.h>
+#include <linux/platform_data/mv_usb.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -221,6 +222,21 @@ static struct pxa27x_keypad_platform_data aspenite_keypad_info __initdata = {
.debounce_interval = 30,
};
+#if defined(CONFIG_USB_EHCI_MV)
+static char *pxa168_sph_clock_name[] = {
+ [0] = "PXA168-USBCLK",
+};
+
+static struct mv_usb_platform_data pxa168_sph_pdata = {
+ .clknum = 1,
+ .clkname = pxa168_sph_clock_name,
+ .mode = MV_USB_MODE_HOST,
+ .phy_init = pxa_usb_phy_init,
+ .phy_deinit = pxa_usb_phy_deinit,
+ .set_vbus = NULL,
+};
+#endif
+
static void __init common_init(void)
{
mfp_config(ARRAY_AND_SIZE(common_pin_config));
@@ -236,6 +252,10 @@ static void __init common_init(void)
/* off-chip devices */
platform_device_register(&smc91x_device);
+
+#if defined(CONFIG_USB_EHCI_MV)
+ pxa168_add_usb_host(&pxa168_sph_pdata);
+#endif
}
MACHINE_START(ASPENITE, "PXA168-based Aspenite Development Platform")
diff --git a/arch/arm/mach-mmp/devices.c b/arch/arm/mach-mmp/devices.c
index 191d9dea8731..dd2d8b103cc8 100644
--- a/arch/arm/mach-mmp/devices.c
+++ b/arch/arm/mach-mmp/devices.c
@@ -9,9 +9,13 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/delay.h>
#include <asm/irq.h>
+#include <mach/irqs.h>
#include <mach/devices.h>
+#include <mach/cputype.h>
+#include <mach/regs-usb.h>
int __init pxa_register_device(struct pxa_device_desc *desc,
void *data, size_t size)
@@ -67,3 +71,281 @@ int __init pxa_register_device(struct pxa_device_desc *desc,
return platform_device_add(pdev);
}
+
+#if defined(CONFIG_USB) || defined(CONFIG_USB_GADGET)
+
+/*****************************************************************************
+ * The registers read/write routines
+ *****************************************************************************/
+
+static unsigned int u2o_get(void __iomem *base, unsigned int offset)
+{
+ return readl_relaxed(base + offset);
+}
+
+static void u2o_set(void __iomem *base, unsigned int offset,
+ unsigned int value)
+{
+ u32 reg;
+
+ reg = readl_relaxed(base + offset);
+ reg |= value;
+ writel_relaxed(reg, base + offset);
+ readl_relaxed(base + offset);
+}
+
+static void u2o_clear(void __iomem *base, unsigned int offset,
+ unsigned int value)
+{
+ u32 reg;
+
+ reg = readl_relaxed(base + offset);
+ reg &= ~value;
+ writel_relaxed(reg, base + offset);
+ readl_relaxed(base + offset);
+}
+
+static void u2o_write(void __iomem *base, unsigned int offset,
+ unsigned int value)
+{
+ writel_relaxed(value, base + offset);
+ readl_relaxed(base + offset);
+}
+
+#if defined(CONFIG_USB_MV_UDC) || defined(CONFIG_USB_EHCI_MV)
+
+#if defined(CONFIG_CPU_PXA910) || defined(CONFIG_CPU_PXA168)
+
+static DEFINE_MUTEX(phy_lock);
+static int phy_init_cnt;
+
+static int usb_phy_init_internal(void __iomem *base)
+{
+ int loops;
+
+ pr_info("Init usb phy!!!\n");
+
+ /* Initialize the USB PHY power */
+ if (cpu_is_pxa910()) {
+ u2o_set(base, UTMI_CTRL, (1<<UTMI_CTRL_INPKT_DELAY_SOF_SHIFT)
+ | (1<<UTMI_CTRL_PU_REF_SHIFT));
+ }
+
+ u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
+ u2o_set(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
+
+ /* UTMI_PLL settings */
+ u2o_clear(base, UTMI_PLL, UTMI_PLL_PLLVDD18_MASK
+ | UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK
+ | UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK
+ | UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK);
+
+ u2o_set(base, UTMI_PLL, 0xee<<UTMI_PLL_FBDIV_SHIFT
+ | 0xb<<UTMI_PLL_REFDIV_SHIFT | 3<<UTMI_PLL_PLLVDD18_SHIFT
+ | 3<<UTMI_PLL_PLLVDD12_SHIFT | 3<<UTMI_PLL_PLLCALI12_SHIFT
+ | 1<<UTMI_PLL_ICP_SHIFT | 3<<UTMI_PLL_KVCO_SHIFT);
+
+ /* UTMI_TX */
+ u2o_clear(base, UTMI_TX, UTMI_TX_REG_EXT_FS_RCAL_EN_MASK
+ | UTMI_TX_TXVDD12_MASK | UTMI_TX_CK60_PHSEL_MASK
+ | UTMI_TX_IMPCAL_VTH_MASK | UTMI_TX_REG_EXT_FS_RCAL_MASK
+ | UTMI_TX_AMP_MASK);
+ u2o_set(base, UTMI_TX, 3<<UTMI_TX_TXVDD12_SHIFT
+ | 4<<UTMI_TX_CK60_PHSEL_SHIFT | 4<<UTMI_TX_IMPCAL_VTH_SHIFT
+ | 8<<UTMI_TX_REG_EXT_FS_RCAL_SHIFT | 3<<UTMI_TX_AMP_SHIFT);
+
+ /* UTMI_RX */
+ u2o_clear(base, UTMI_RX, UTMI_RX_SQ_THRESH_MASK
+ | UTMI_REG_SQ_LENGTH_MASK);
+ u2o_set(base, UTMI_RX, 7<<UTMI_RX_SQ_THRESH_SHIFT
+ | 2<<UTMI_REG_SQ_LENGTH_SHIFT);
+
+ /* UTMI_IVREF */
+ if (cpu_is_pxa168())
+ /* fixing Microsoft Altair board interface with NEC hub issue -
+ * Set UTMI_IVREF from 0x4a3 to 0x4bf */
+ u2o_write(base, UTMI_IVREF, 0x4bf);
+
+ /* toggle VCOCAL_START bit of UTMI_PLL */
+ udelay(200);
+ u2o_set(base, UTMI_PLL, VCOCAL_START);
+ udelay(40);
+ u2o_clear(base, UTMI_PLL, VCOCAL_START);
+
+ /* toggle REG_RCAL_START bit of UTMI_TX */
+ udelay(400);
+ u2o_set(base, UTMI_TX, REG_RCAL_START);
+ udelay(40);
+ u2o_clear(base, UTMI_TX, REG_RCAL_START);
+ udelay(400);
+
+ /* Make sure PHY PLL is ready */
+ loops = 0;
+ while ((u2o_get(base, UTMI_PLL) & PLL_READY) == 0) {
+ mdelay(1);
+ loops++;
+ if (loops > 100) {
+ printk(KERN_WARNING "calibrate timeout, UTMI_PLL %x\n",
+ u2o_get(base, UTMI_PLL));
+ break;
+ }
+ }
+
+ if (cpu_is_pxa168()) {
+ u2o_set(base, UTMI_RESERVE, 1 << 5);
+ /* Turn on UTMI PHY OTG extension */
+ u2o_write(base, UTMI_OTG_ADDON, 1);
+ }
+
+ return 0;
+}
+
+static int usb_phy_deinit_internal(void __iomem *base)
+{
+ pr_info("Deinit usb phy!!!\n");
+
+ if (cpu_is_pxa168())
+ u2o_clear(base, UTMI_OTG_ADDON, UTMI_OTG_ADDON_OTG_ON);
+
+ u2o_clear(base, UTMI_CTRL, UTMI_CTRL_RXBUF_PDWN);
+ u2o_clear(base, UTMI_CTRL, UTMI_CTRL_TXBUF_PDWN);
+ u2o_clear(base, UTMI_CTRL, UTMI_CTRL_USB_CLK_EN);
+ u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PWR_UP_SHIFT);
+ u2o_clear(base, UTMI_CTRL, 1<<UTMI_CTRL_PLL_PWR_UP_SHIFT);
+
+ return 0;
+}
+
+int pxa_usb_phy_init(void __iomem *phy_reg)
+{
+ mutex_lock(&phy_lock);
+ if (phy_init_cnt++ == 0)
+ usb_phy_init_internal(phy_reg);
+ mutex_unlock(&phy_lock);
+ return 0;
+}
+
+void pxa_usb_phy_deinit(void __iomem *phy_reg)
+{
+ WARN_ON(phy_init_cnt == 0);
+
+ mutex_lock(&phy_lock);
+ if (--phy_init_cnt == 0)
+ usb_phy_deinit_internal(phy_reg);
+ mutex_unlock(&phy_lock);
+}
+#endif
+#endif
+#endif
+
+#ifdef CONFIG_USB_SUPPORT
+static u64 usb_dma_mask = ~(u32)0;
+
+#ifdef CONFIG_USB_MV_UDC
+struct resource pxa168_u2o_resources[] = {
+ /* regbase */
+ [0] = {
+ .start = PXA168_U2O_REGBASE + U2x_CAPREGS_OFFSET,
+ .end = PXA168_U2O_REGBASE + USB_REG_RANGE,
+ .flags = IORESOURCE_MEM,
+ .name = "capregs",
+ },
+ /* phybase */
+ [1] = {
+ .start = PXA168_U2O_PHYBASE,
+ .end = PXA168_U2O_PHYBASE + USB_PHY_RANGE,
+ .flags = IORESOURCE_MEM,
+ .name = "phyregs",
+ },
+ [2] = {
+ .start = IRQ_PXA168_USB1,
+ .end = IRQ_PXA168_USB1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device pxa168_device_u2o = {
+ .name = "mv-udc",
+ .id = -1,
+ .resource = pxa168_u2o_resources,
+ .num_resources = ARRAY_SIZE(pxa168_u2o_resources),
+ .dev = {
+ .dma_mask = &usb_dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ }
+};
+#endif /* CONFIG_USB_MV_UDC */
+
+#ifdef CONFIG_USB_EHCI_MV_U2O
+struct resource pxa168_u2oehci_resources[] = {
+ /* regbase */
+ [0] = {
+ .start = PXA168_U2O_REGBASE + U2x_CAPREGS_OFFSET,
+ .end = PXA168_U2O_REGBASE + USB_REG_RANGE,
+ .flags = IORESOURCE_MEM,
+ .name = "capregs",
+ },
+ /* phybase */
+ [1] = {
+ .start = PXA168_U2O_PHYBASE,
+ .end = PXA168_U2O_PHYBASE + USB_PHY_RANGE,
+ .flags = IORESOURCE_MEM,
+ .name = "phyregs",
+ },
+ [2] = {
+ .start = IRQ_PXA168_USB1,
+ .end = IRQ_PXA168_USB1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device pxa168_device_u2oehci = {
+ .name = "pxa-u2oehci",
+ .id = -1,
+ .dev = {
+ .dma_mask = &usb_dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+
+ .num_resources = ARRAY_SIZE(pxa168_u2oehci_resources),
+ .resource = pxa168_u2oehci_resources,
+};
+#endif
+
+#if defined(CONFIG_USB_MV_OTG)
+struct resource pxa168_u2ootg_resources[] = {
+ /* regbase */
+ [0] = {
+ .start = PXA168_U2O_REGBASE + U2x_CAPREGS_OFFSET,
+ .end = PXA168_U2O_REGBASE + USB_REG_RANGE,
+ .flags = IORESOURCE_MEM,
+ .name = "capregs",
+ },
+ /* phybase */
+ [1] = {
+ .start = PXA168_U2O_PHYBASE,
+ .end = PXA168_U2O_PHYBASE + USB_PHY_RANGE,
+ .flags = IORESOURCE_MEM,
+ .name = "phyregs",
+ },
+ [2] = {
+ .start = IRQ_PXA168_USB1,
+ .end = IRQ_PXA168_USB1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device pxa168_device_u2ootg = {
+ .name = "mv-otg",
+ .id = -1,
+ .dev = {
+ .dma_mask = &usb_dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+
+ .num_resources = ARRAY_SIZE(pxa168_u2ootg_resources),
+ .resource = pxa168_u2ootg_resources,
+};
+#endif /* CONFIG_USB_MV_OTG */
+
+#endif
diff --git a/arch/arm/mach-mmp/include/mach/addr-map.h b/arch/arm/mach-mmp/include/mach/addr-map.h
index b1ece08174e8..f88a44c0ef91 100644
--- a/arch/arm/mach-mmp/include/mach/addr-map.h
+++ b/arch/arm/mach-mmp/include/mach/addr-map.h
@@ -31,4 +31,16 @@
#define SMC_CS1_PHYS_BASE 0x90000000
#define SMC_CS1_PHYS_SIZE 0x10000000
+#define APMU_VIRT_BASE (AXI_VIRT_BASE + 0x82800)
+#define APMU_REG(x) (APMU_VIRT_BASE + (x))
+
+#define APBC_VIRT_BASE (APB_VIRT_BASE + 0x015000)
+#define APBC_REG(x) (APBC_VIRT_BASE + (x))
+
+#define MPMU_VIRT_BASE (APB_VIRT_BASE + 0x50000)
+#define MPMU_REG(x) (MPMU_VIRT_BASE + (x))
+
+#define CIU_VIRT_BASE (AXI_VIRT_BASE + 0x82c00)
+#define CIU_REG(x) (CIU_VIRT_BASE + (x))
+
#endif /* __ASM_MACH_ADDR_MAP_H */
diff --git a/arch/arm/mach-mmp/include/mach/devices.h b/arch/arm/mach-mmp/include/mach/devices.h
index d0ec7dae88e4..21217ef11b64 100644
--- a/arch/arm/mach-mmp/include/mach/devices.h
+++ b/arch/arm/mach-mmp/include/mach/devices.h
@@ -50,4 +50,7 @@ struct pxa_device_desc mmp2_device_##_name __initdata = { \
}
extern int pxa_register_device(struct pxa_device_desc *, void *, size_t);
+extern int pxa_usb_phy_init(void __iomem *phy_reg);
+extern void pxa_usb_phy_deinit(void __iomem *phy_reg);
+
#endif /* __MACH_DEVICE_H */
diff --git a/arch/arm/mach-mmp/include/mach/entry-macro.S b/arch/arm/mach-mmp/include/mach/entry-macro.S
index 9cff9e7a2b26..bd152e24e6d7 100644
--- a/arch/arm/mach-mmp/include/mach/entry-macro.S
+++ b/arch/arm/mach-mmp/include/mach/entry-macro.S
@@ -6,13 +6,15 @@
* published by the Free Software Foundation.
*/
+#include <asm/irq.h>
#include <mach/regs-icu.h>
.macro get_irqnr_preamble, base, tmp
mrc p15, 0, \tmp, c0, c0, 0 @ CPUID
and \tmp, \tmp, #0xff00
cmp \tmp, #0x5800
- ldr \base, =ICU_VIRT_BASE
+ ldr \base, =mmp_icu_base
+ ldr \base, [\base, #0]
addne \base, \base, #0x10c @ PJ1 AP INT SEL register
addeq \base, \base, #0x104 @ PJ4 IRQ SEL register
.endm
diff --git a/arch/arm/mach-mmp/include/mach/irqs.h b/arch/arm/mach-mmp/include/mach/irqs.h
index d0e746626a3d..fb492a50a817 100644
--- a/arch/arm/mach-mmp/include/mach/irqs.h
+++ b/arch/arm/mach-mmp/include/mach/irqs.h
@@ -125,7 +125,7 @@
#define IRQ_MMP2_RTC_MUX 5
#define IRQ_MMP2_TWSI1 7
#define IRQ_MMP2_GPU 8
-#define IRQ_MMP2_KEYPAD 9
+#define IRQ_MMP2_KEYPAD_MUX 9
#define IRQ_MMP2_ROTARY 10
#define IRQ_MMP2_TRACKBALL 11
#define IRQ_MMP2_ONEWIRE 12
@@ -163,11 +163,11 @@
#define IRQ_MMP2_DMA_FIQ 47
#define IRQ_MMP2_DMA_RIQ 48
#define IRQ_MMP2_GPIO 49
-#define IRQ_MMP2_SSP_MUX 51
+#define IRQ_MMP2_MIPI_HSI1_MUX 51
#define IRQ_MMP2_MMC2 52
#define IRQ_MMP2_MMC3 53
#define IRQ_MMP2_MMC4 54
-#define IRQ_MMP2_MIPI_HSI 55
+#define IRQ_MMP2_MIPI_HSI0_MUX 55
#define IRQ_MMP2_MSP 58
#define IRQ_MMP2_MIPI_SLIM_DMA 59
#define IRQ_MMP2_PJ4_FREQ_CHG 60
@@ -186,8 +186,14 @@
#define IRQ_MMP2_RTC_ALARM (IRQ_MMP2_RTC_BASE + 0)
#define IRQ_MMP2_RTC (IRQ_MMP2_RTC_BASE + 1)
+/* secondary interrupt of INT #9 */
+#define IRQ_MMP2_KEYPAD_BASE (IRQ_MMP2_RTC_BASE + 2)
+#define IRQ_MMP2_KPC (IRQ_MMP2_KEYPAD_BASE + 0)
+#define IRQ_MMP2_ROTORY (IRQ_MMP2_KEYPAD_BASE + 1)
+#define IRQ_MMP2_TBALL (IRQ_MMP2_KEYPAD_BASE + 2)
+
/* secondary interrupt of INT #17 */
-#define IRQ_MMP2_TWSI_BASE (IRQ_MMP2_RTC_BASE + 2)
+#define IRQ_MMP2_TWSI_BASE (IRQ_MMP2_KEYPAD_BASE + 3)
#define IRQ_MMP2_TWSI2 (IRQ_MMP2_TWSI_BASE + 0)
#define IRQ_MMP2_TWSI3 (IRQ_MMP2_TWSI_BASE + 1)
#define IRQ_MMP2_TWSI4 (IRQ_MMP2_TWSI_BASE + 2)
@@ -212,11 +218,16 @@
#define IRQ_MMP2_COMMRX (IRQ_MMP2_MISC_BASE + 14)
/* secondary interrupt of INT #51 */
-#define IRQ_MMP2_SSP_BASE (IRQ_MMP2_MISC_BASE + 15)
-#define IRQ_MMP2_SSP1_SRDY (IRQ_MMP2_SSP_BASE + 0)
-#define IRQ_MMP2_SSP3_SRDY (IRQ_MMP2_SSP_BASE + 1)
+#define IRQ_MMP2_MIPI_HSI1_BASE (IRQ_MMP2_MISC_BASE + 15)
+#define IRQ_MMP2_HSI1_CAWAKE (IRQ_MMP2_MIPI_HSI1_BASE + 0)
+#define IRQ_MMP2_MIPI_HSI_INT1 (IRQ_MMP2_MIPI_HSI1_BASE + 1)
+
+/* secondary interrupt of INT #55 */
+#define IRQ_MMP2_MIPI_HSI0_BASE (IRQ_MMP2_MIPI_HSI1_BASE + 2)
+#define IRQ_MMP2_HSI0_CAWAKE (IRQ_MMP2_MIPI_HSI0_BASE + 0)
+#define IRQ_MMP2_MIPI_HSI_INT0 (IRQ_MMP2_MIPI_HSI0_BASE + 1)
-#define IRQ_MMP2_MUX_END (IRQ_MMP2_SSP_BASE + 2)
+#define IRQ_MMP2_MUX_END (IRQ_MMP2_MIPI_HSI0_BASE + 2)
#define IRQ_GPIO_START 128
#define MMP_NR_BUILTIN_GPIO 192
diff --git a/arch/arm/mach-mmp/include/mach/pm-mmp2.h b/arch/arm/mach-mmp/include/mach/pm-mmp2.h
new file mode 100644
index 000000000000..98bd66ce8006
--- /dev/null
+++ b/arch/arm/mach-mmp/include/mach/pm-mmp2.h
@@ -0,0 +1,61 @@
+/*
+ * MMP2 Power Management Routines
+ *
+ * This software program is licensed subject to the GNU General Public License
+ * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html
+ *
+ * (C) Copyright 2010 Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+#ifndef __MMP2_PM_H__
+#define __MMP2_PM_H__
+
+#include <mach/addr-map.h>
+
+#define APMU_PJ_IDLE_CFG APMU_REG(0x018)
+#define APMU_PJ_IDLE_CFG_PJ_IDLE (1 << 1)
+#define APMU_PJ_IDLE_CFG_PJ_PWRDWN (1 << 5)
+#define APMU_PJ_IDLE_CFG_PWR_SW(x) ((x) << 16)
+#define APMU_PJ_IDLE_CFG_L2_PWR_SW (1 << 19)
+#define APMU_PJ_IDLE_CFG_ISO_MODE_CNTRL_MASK (3 << 28)
+
+#define APMU_SRAM_PWR_DWN APMU_REG(0x08c)
+
+#define MPMU_SCCR MPMU_REG(0x038)
+#define MPMU_PCR_PJ MPMU_REG(0x1000)
+#define MPMU_PCR_PJ_AXISD (1 << 31)
+#define MPMU_PCR_PJ_SLPEN (1 << 29)
+#define MPMU_PCR_PJ_SPSD (1 << 28)
+#define MPMU_PCR_PJ_DDRCORSD (1 << 27)
+#define MPMU_PCR_PJ_APBSD (1 << 26)
+#define MPMU_PCR_PJ_INTCLR (1 << 24)
+#define MPMU_PCR_PJ_SLPWP0 (1 << 23)
+#define MPMU_PCR_PJ_SLPWP1 (1 << 22)
+#define MPMU_PCR_PJ_SLPWP2 (1 << 21)
+#define MPMU_PCR_PJ_SLPWP3 (1 << 20)
+#define MPMU_PCR_PJ_VCTCXOSD (1 << 19)
+#define MPMU_PCR_PJ_SLPWP4 (1 << 18)
+#define MPMU_PCR_PJ_SLPWP5 (1 << 17)
+#define MPMU_PCR_PJ_SLPWP6 (1 << 16)
+#define MPMU_PCR_PJ_SLPWP7 (1 << 15)
+
+#define MPMU_PLL2_CTRL1 MPMU_REG(0x0414)
+#define MPMU_CGR_PJ MPMU_REG(0x1024)
+#define MPMU_WUCRM_PJ MPMU_REG(0x104c)
+#define MPMU_WUCRM_PJ_WAKEUP(x) (1 << (x))
+#define MPMU_WUCRM_PJ_RTC_ALARM (1 << 17)
+
+enum {
+ POWER_MODE_ACTIVE = 0,
+ POWER_MODE_CORE_INTIDLE,
+ POWER_MODE_CORE_EXTIDLE,
+ POWER_MODE_APPS_IDLE,
+ POWER_MODE_APPS_SLEEP,
+ POWER_MODE_CHIP_SLEEP,
+ POWER_MODE_SYS_SLEEP,
+};
+
+extern void mmp2_pm_enter_lowpower_mode(int state);
+extern int mmp2_set_wake(struct irq_data *d, unsigned int on);
+#endif
diff --git a/arch/arm/mach-mmp/include/mach/pm-pxa910.h b/arch/arm/mach-mmp/include/mach/pm-pxa910.h
new file mode 100644
index 000000000000..8cac8ab5253d
--- /dev/null
+++ b/arch/arm/mach-mmp/include/mach/pm-pxa910.h
@@ -0,0 +1,77 @@
+/*
+ * PXA910 Power Management Routines
+ *
+ * This software program is licensed subject to the GNU General Public License
+ * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html
+ *
+ * (C) Copyright 2009 Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+#ifndef __PXA910_PM_H__
+#define __PXA910_PM_H__
+
+#define APMU_MOH_IDLE_CFG APMU_REG(0x0018)
+#define APMU_MOH_IDLE_CFG_MOH_IDLE (1 << 1)
+#define APMU_MOH_IDLE_CFG_MOH_PWRDWN (1 << 5)
+#define APMU_MOH_IDLE_CFG_MOH_SRAM_PWRDWN (1 << 6)
+#define APMU_MOH_IDLE_CFG_MOH_PWR_SW(x) (((x) & 0x3) << 16)
+#define APMU_MOH_IDLE_CFG_MOH_L2_PWR_SW(x) (((x) & 0x3) << 18)
+#define APMU_MOH_IDLE_CFG_MOH_DIS_MC_SW_REQ (1 << 21)
+#define APMU_MOH_IDLE_CFG_MOH_MC_WAKE_EN (1 << 20)
+
+#define APMU_SQU_CLK_GATE_CTRL APMU_REG(0x001c)
+#define APMU_MC_HW_SLP_TYPE APMU_REG(0x00b0)
+
+#define MPMU_FCCR MPMU_REG(0x0008)
+#define MPMU_APCR MPMU_REG(0x1000)
+#define MPMU_APCR_AXISD (1 << 31)
+#define MPMU_APCR_DSPSD (1 << 30)
+#define MPMU_APCR_SLPEN (1 << 29)
+#define MPMU_APCR_DTCMSD (1 << 28)
+#define MPMU_APCR_DDRCORSD (1 << 27)
+#define MPMU_APCR_APBSD (1 << 26)
+#define MPMU_APCR_BBSD (1 << 25)
+#define MPMU_APCR_SLPWP0 (1 << 23)
+#define MPMU_APCR_SLPWP1 (1 << 22)
+#define MPMU_APCR_SLPWP2 (1 << 21)
+#define MPMU_APCR_SLPWP3 (1 << 20)
+#define MPMU_APCR_VCTCXOSD (1 << 19)
+#define MPMU_APCR_SLPWP4 (1 << 18)
+#define MPMU_APCR_SLPWP5 (1 << 17)
+#define MPMU_APCR_SLPWP6 (1 << 16)
+#define MPMU_APCR_SLPWP7 (1 << 15)
+#define MPMU_APCR_MSASLPEN (1 << 14)
+#define MPMU_APCR_STBYEN (1 << 13)
+
+#define MPMU_AWUCRM MPMU_REG(0x104c)
+#define MPMU_AWUCRM_AP_ASYNC_INT (1 << 25)
+#define MPMU_AWUCRM_AP_FULL_IDLE (1 << 24)
+#define MPMU_AWUCRM_SDH1 (1 << 23)
+#define MPMU_AWUCRM_SDH2 (1 << 22)
+#define MPMU_AWUCRM_KEYPRESS (1 << 21)
+#define MPMU_AWUCRM_TRACKBALL (1 << 20)
+#define MPMU_AWUCRM_NEWROTARY (1 << 19)
+#define MPMU_AWUCRM_RTC_ALARM (1 << 17)
+#define MPMU_AWUCRM_AP2_TIMER_3 (1 << 13)
+#define MPMU_AWUCRM_AP2_TIMER_2 (1 << 12)
+#define MPMU_AWUCRM_AP2_TIMER_1 (1 << 11)
+#define MPMU_AWUCRM_AP1_TIMER_3 (1 << 10)
+#define MPMU_AWUCRM_AP1_TIMER_2 (1 << 9)
+#define MPMU_AWUCRM_AP1_TIMER_1 (1 << 8)
+#define MPMU_AWUCRM_WAKEUP(x) (1 << ((x) & 0x7))
+
+enum {
+ POWER_MODE_ACTIVE = 0,
+ POWER_MODE_CORE_INTIDLE,
+ POWER_MODE_CORE_EXTIDLE,
+ POWER_MODE_APPS_IDLE,
+ POWER_MODE_APPS_SLEEP,
+ POWER_MODE_SYS_SLEEP,
+ POWER_MODE_HIBERNATE,
+ POWER_MODE_UDR,
+};
+
+extern int pxa910_set_wake(struct irq_data *data, unsigned int on);
+
+#endif
diff --git a/arch/arm/mach-mmp/include/mach/pxa168.h b/arch/arm/mach-mmp/include/mach/pxa168.h
index dc03d580a06d..09dcd6e2b6a8 100644
--- a/arch/arm/mach-mmp/include/mach/pxa168.h
+++ b/arch/arm/mach-mmp/include/mach/pxa168.h
@@ -16,6 +16,7 @@ extern void pxa168_clear_keypad_wakeup(void);
#include <plat/pxa27x_keypad.h>
#include <mach/cputype.h>
#include <linux/pxa168_eth.h>
+#include <linux/platform_data/mv_usb.h>
extern struct pxa_device_desc pxa168_device_uart1;
extern struct pxa_device_desc pxa168_device_uart2;
@@ -36,12 +37,9 @@ extern struct pxa_device_desc pxa168_device_fb;
extern struct pxa_device_desc pxa168_device_keypad;
extern struct pxa_device_desc pxa168_device_eth;
-struct pxa168_usb_pdata {
- /* If NULL, default phy init routine for PXA168 would be called */
- int (*phy_init)(void __iomem *usb_phy_reg_base);
-};
/* pdata can be NULL */
-int __init pxa168_add_usb_host(struct pxa168_usb_pdata *pdata);
+extern int __init pxa168_add_usb_host(struct mv_usb_platform_data *pdata);
+
extern struct platform_device pxa168_device_gpio;
diff --git a/arch/arm/mach-mmp/include/mach/pxa910.h b/arch/arm/mach-mmp/include/mach/pxa910.h
index e2e1f1e5e124..793634c837ef 100644
--- a/arch/arm/mach-mmp/include/mach/pxa910.h
+++ b/arch/arm/mach-mmp/include/mach/pxa910.h
@@ -20,6 +20,9 @@ extern struct pxa_device_desc pxa910_device_pwm2;
extern struct pxa_device_desc pxa910_device_pwm3;
extern struct pxa_device_desc pxa910_device_pwm4;
extern struct pxa_device_desc pxa910_device_nand;
+extern struct platform_device pxa168_device_u2o;
+extern struct platform_device pxa168_device_u2ootg;
+extern struct platform_device pxa168_device_u2oehci;
extern struct platform_device pxa910_device_gpio;
extern struct platform_device pxa910_device_rtc;
diff --git a/arch/arm/mach-mmp/include/mach/regs-apbc.h b/arch/arm/mach-mmp/include/mach/regs-apbc.h
index 8a37fb003655..68b0c93ec6a1 100644
--- a/arch/arm/mach-mmp/include/mach/regs-apbc.h
+++ b/arch/arm/mach-mmp/include/mach/regs-apbc.h
@@ -13,9 +13,6 @@
#include <mach/addr-map.h>
-#define APBC_VIRT_BASE (APB_VIRT_BASE + 0x015000)
-#define APBC_REG(x) (APBC_VIRT_BASE + (x))
-
/*
* APB clock register offsets for PXA168
*/
diff --git a/arch/arm/mach-mmp/include/mach/regs-apmu.h b/arch/arm/mach-mmp/include/mach/regs-apmu.h
index 8447ac63e28f..7af8deb63e83 100644
--- a/arch/arm/mach-mmp/include/mach/regs-apmu.h
+++ b/arch/arm/mach-mmp/include/mach/regs-apmu.h
@@ -13,9 +13,6 @@
#include <mach/addr-map.h>
-#define APMU_VIRT_BASE (AXI_VIRT_BASE + 0x82800)
-#define APMU_REG(x) (APMU_VIRT_BASE + (x))
-
/* Clock Reset Control */
#define APMU_IRE APMU_REG(0x048)
#define APMU_LCD APMU_REG(0x04c)
diff --git a/arch/arm/mach-mmp/include/mach/regs-usb.h b/arch/arm/mach-mmp/include/mach/regs-usb.h
new file mode 100644
index 000000000000..b047bf487506
--- /dev/null
+++ b/arch/arm/mach-mmp/include/mach/regs-usb.h
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __ASM_ARCH_REGS_USB_H
+#define __ASM_ARCH_REGS_USB_H
+
+#define PXA168_U2O_REGBASE (0xd4208000)
+#define PXA168_U2O_PHYBASE (0xd4207000)
+
+#define PXA168_U2H_REGBASE (0xd4209000)
+#define PXA168_U2H_PHYBASE (0xd4206000)
+
+#define MMP3_HSIC1_REGBASE (0xf0001000)
+#define MMP3_HSIC1_PHYBASE (0xf0001800)
+
+#define MMP3_HSIC2_REGBASE (0xf0002000)
+#define MMP3_HSIC2_PHYBASE (0xf0002800)
+
+#define MMP3_FSIC_REGBASE (0xf0003000)
+#define MMP3_FSIC_PHYBASE (0xf0003800)
+
+
+#define USB_REG_RANGE (0x1ff)
+#define USB_PHY_RANGE (0xff)
+
+/* registers */
+#define U2x_CAPREGS_OFFSET 0x100
+
+/* phy regs */
+#define UTMI_REVISION 0x0
+#define UTMI_CTRL 0x4
+#define UTMI_PLL 0x8
+#define UTMI_TX 0xc
+#define UTMI_RX 0x10
+#define UTMI_IVREF 0x14
+#define UTMI_T0 0x18
+#define UTMI_T1 0x1c
+#define UTMI_T2 0x20
+#define UTMI_T3 0x24
+#define UTMI_T4 0x28
+#define UTMI_T5 0x2c
+#define UTMI_RESERVE 0x30
+#define UTMI_USB_INT 0x34
+#define UTMI_DBG_CTL 0x38
+#define UTMI_OTG_ADDON 0x3c
+
+/* For UTMICTRL Register */
+#define UTMI_CTRL_USB_CLK_EN (1 << 31)
+/* pxa168 */
+#define UTMI_CTRL_SUSPEND_SET1 (1 << 30)
+#define UTMI_CTRL_SUSPEND_SET2 (1 << 29)
+#define UTMI_CTRL_RXBUF_PDWN (1 << 24)
+#define UTMI_CTRL_TXBUF_PDWN (1 << 11)
+
+#define UTMI_CTRL_INPKT_DELAY_SHIFT 30
+#define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT 28
+#define UTMI_CTRL_PU_REF_SHIFT 20
+#define UTMI_CTRL_ARC_PULLDN_SHIFT 12
+#define UTMI_CTRL_PLL_PWR_UP_SHIFT 1
+#define UTMI_CTRL_PWR_UP_SHIFT 0
+
+/* For UTMI_PLL Register */
+#define UTMI_PLL_PLLCALI12_SHIFT 29
+#define UTMI_PLL_PLLCALI12_MASK (0x3 << 29)
+
+#define UTMI_PLL_PLLVDD18_SHIFT 27
+#define UTMI_PLL_PLLVDD18_MASK (0x3 << 27)
+
+#define UTMI_PLL_PLLVDD12_SHIFT 25
+#define UTMI_PLL_PLLVDD12_MASK (0x3 << 25)
+
+#define UTMI_PLL_CLK_BLK_EN_SHIFT 24
+#define CLK_BLK_EN (0x1 << 24)
+#define PLL_READY (0x1 << 23)
+#define KVCO_EXT (0x1 << 22)
+#define VCOCAL_START (0x1 << 21)
+
+#define UTMI_PLL_KVCO_SHIFT 15
+#define UTMI_PLL_KVCO_MASK (0x7 << 15)
+
+#define UTMI_PLL_ICP_SHIFT 12
+#define UTMI_PLL_ICP_MASK (0x7 << 12)
+
+#define UTMI_PLL_FBDIV_SHIFT 4
+#define UTMI_PLL_FBDIV_MASK (0xFF << 4)
+
+#define UTMI_PLL_REFDIV_SHIFT 0
+#define UTMI_PLL_REFDIV_MASK (0xF << 0)
+
+/* For UTMI_TX Register */
+#define UTMI_TX_REG_EXT_FS_RCAL_SHIFT 27
+#define UTMI_TX_REG_EXT_FS_RCAL_MASK (0xf << 27)
+
+#define UTMI_TX_REG_EXT_FS_RCAL_EN_SHIFT 26
+#define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK (0x1 << 26)
+
+#define UTMI_TX_TXVDD12_SHIFT 22
+#define UTMI_TX_TXVDD12_MASK (0x3 << 22)
+
+#define UTMI_TX_CK60_PHSEL_SHIFT 17
+#define UTMI_TX_CK60_PHSEL_MASK (0xf << 17)
+
+#define UTMI_TX_IMPCAL_VTH_SHIFT 14
+#define UTMI_TX_IMPCAL_VTH_MASK (0x7 << 14)
+
+#define REG_RCAL_START (0x1 << 12)
+
+#define UTMI_TX_LOW_VDD_EN_SHIFT 11
+
+#define UTMI_TX_AMP_SHIFT 0
+#define UTMI_TX_AMP_MASK (0x7 << 0)
+
+/* For UTMI_RX Register */
+#define UTMI_REG_SQ_LENGTH_SHIFT 15
+#define UTMI_REG_SQ_LENGTH_MASK (0x3 << 15)
+
+#define UTMI_RX_SQ_THRESH_SHIFT 4
+#define UTMI_RX_SQ_THRESH_MASK (0xf << 4)
+
+#define UTMI_OTG_ADDON_OTG_ON (1 << 0)
+
+/* For MMP3 USB Phy */
+#define USB2_PLL_REG0 0x4
+#define USB2_PLL_REG1 0x8
+#define USB2_TX_REG0 0x10
+#define USB2_TX_REG1 0x14
+#define USB2_TX_REG2 0x18
+#define USB2_RX_REG0 0x20
+#define USB2_RX_REG1 0x24
+#define USB2_RX_REG2 0x28
+#define USB2_ANA_REG0 0x30
+#define USB2_ANA_REG1 0x34
+#define USB2_ANA_REG2 0x38
+#define USB2_DIG_REG0 0x3C
+#define USB2_DIG_REG1 0x40
+#define USB2_DIG_REG2 0x44
+#define USB2_DIG_REG3 0x48
+#define USB2_TEST_REG0 0x4C
+#define USB2_TEST_REG1 0x50
+#define USB2_TEST_REG2 0x54
+#define USB2_CHARGER_REG0 0x58
+#define USB2_OTG_REG0 0x5C
+#define USB2_PHY_MON0 0x60
+#define USB2_RESETVE_REG0 0x64
+#define USB2_ICID_REG0 0x78
+#define USB2_ICID_REG1 0x7C
+
+/* USB2_PLL_REG0 */
+/* This is for Ax stepping */
+#define USB2_PLL_FBDIV_SHIFT_MMP3 0
+#define USB2_PLL_FBDIV_MASK_MMP3 (0xFF << 0)
+
+#define USB2_PLL_REFDIV_SHIFT_MMP3 8
+#define USB2_PLL_REFDIV_MASK_MMP3 (0xF << 8)
+
+#define USB2_PLL_VDD12_SHIFT_MMP3 12
+#define USB2_PLL_VDD18_SHIFT_MMP3 14
+
+/* This is for B0 stepping */
+#define USB2_PLL_FBDIV_SHIFT_MMP3_B0 0
+#define USB2_PLL_REFDIV_SHIFT_MMP3_B0 9
+#define USB2_PLL_VDD18_SHIFT_MMP3_B0 14
+#define USB2_PLL_FBDIV_MASK_MMP3_B0 0x01FF
+#define USB2_PLL_REFDIV_MASK_MMP3_B0 0x3E00
+
+#define USB2_PLL_CAL12_SHIFT_MMP3 0
+#define USB2_PLL_CALI12_MASK_MMP3 (0x3 << 0)
+
+#define USB2_PLL_VCOCAL_START_SHIFT_MMP3 2
+
+#define USB2_PLL_KVCO_SHIFT_MMP3 4
+#define USB2_PLL_KVCO_MASK_MMP3 (0x7<<4)
+
+#define USB2_PLL_ICP_SHIFT_MMP3 8
+#define USB2_PLL_ICP_MASK_MMP3 (0x7<<8)
+
+#define USB2_PLL_LOCK_BYPASS_SHIFT_MMP3 12
+
+#define USB2_PLL_PU_PLL_SHIFT_MMP3 13
+#define USB2_PLL_PU_PLL_MASK (0x1 << 13)
+
+#define USB2_PLL_READY_MASK_MMP3 (0x1 << 15)
+
+/* USB2_TX_REG0 */
+#define USB2_TX_IMPCAL_VTH_SHIFT_MMP3 8
+#define USB2_TX_IMPCAL_VTH_MASK_MMP3 (0x7 << 8)
+
+#define USB2_TX_RCAL_START_SHIFT_MMP3 13
+
+/* USB2_TX_REG1 */
+#define USB2_TX_CK60_PHSEL_SHIFT_MMP3 0
+#define USB2_TX_CK60_PHSEL_MASK_MMP3 (0xf << 0)
+
+#define USB2_TX_AMP_SHIFT_MMP3 4
+#define USB2_TX_AMP_MASK_MMP3 (0x7 << 4)
+
+#define USB2_TX_VDD12_SHIFT_MMP3 8
+#define USB2_TX_VDD12_MASK_MMP3 (0x3 << 8)
+
+/* USB2_TX_REG2 */
+#define USB2_TX_DRV_SLEWRATE_SHIFT 10
+
+/* USB2_RX_REG0 */
+#define USB2_RX_SQ_THRESH_SHIFT_MMP3 4
+#define USB2_RX_SQ_THRESH_MASK_MMP3 (0xf << 4)
+
+#define USB2_RX_SQ_LENGTH_SHIFT_MMP3 10
+#define USB2_RX_SQ_LENGTH_MASK_MMP3 (0x3 << 10)
+
+/* USB2_ANA_REG1*/
+#define USB2_ANA_PU_ANA_SHIFT_MMP3 14
+
+/* USB2_OTG_REG0 */
+#define USB2_OTG_PU_OTG_SHIFT_MMP3 3
+
+/* fsic registers */
+#define FSIC_MISC 0x4
+#define FSIC_INT 0x28
+#define FSIC_CTRL 0x30
+
+/* HSIC registers */
+#define HSIC_PAD_CTRL 0x4
+
+#define HSIC_CTRL 0x8
+#define HSIC_CTRL_HSIC_ENABLE (1<<7)
+#define HSIC_CTRL_PLL_BYPASS (1<<4)
+
+#define TEST_GRP_0 0xc
+#define TEST_GRP_1 0x10
+
+#define HSIC_INT 0x14
+#define HSIC_INT_READY_INT_EN (1<<10)
+#define HSIC_INT_CONNECT_INT_EN (1<<9)
+#define HSIC_INT_CORE_INT_EN (1<<8)
+#define HSIC_INT_HS_READY (1<<2)
+#define HSIC_INT_CONNECT (1<<1)
+#define HSIC_INT_CORE (1<<0)
+
+#define HSIC_CONFIG 0x18
+#define USBHSIC_CTRL 0x20
+
+#define HSIC_USB_CTRL 0x28
+#define HSIC_USB_CTRL_CLKEN 1
+#define HSIC_USB_CLK_PHY 0x0
+#define HSIC_USB_CLK_PMU 0x1
+
+#endif /* __ASM_ARCH_PXA_U2O_H */
diff --git a/arch/arm/mach-mmp/irq-mmp2.c b/arch/arm/mach-mmp/irq-mmp2.c
deleted file mode 100644
index 7895d277421e..000000000000
--- a/arch/arm/mach-mmp/irq-mmp2.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * linux/arch/arm/mach-mmp/irq-mmp2.c
- *
- * Generic IRQ handling, GPIO IRQ demultiplexing, etc.
- *
- * Author: Haojian Zhuang <haojian.zhuang@marvell.com>
- * Copyright: Marvell International Ltd.
- *
- * 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/init.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-
-#include <mach/irqs.h>
-#include <mach/regs-icu.h>
-#include <mach/mmp2.h>
-
-#include "common.h"
-
-static void icu_mask_irq(struct irq_data *d)
-{
- uint32_t r = __raw_readl(ICU_INT_CONF(d->irq));
-
- r &= ~ICU_INT_ROUTE_PJ4_IRQ;
- __raw_writel(r, ICU_INT_CONF(d->irq));
-}
-
-static void icu_unmask_irq(struct irq_data *d)
-{
- uint32_t r = __raw_readl(ICU_INT_CONF(d->irq));
-
- r |= ICU_INT_ROUTE_PJ4_IRQ;
- __raw_writel(r, ICU_INT_CONF(d->irq));
-}
-
-static struct irq_chip icu_irq_chip = {
- .name = "icu_irq",
- .irq_mask = icu_mask_irq,
- .irq_mask_ack = icu_mask_irq,
- .irq_unmask = icu_unmask_irq,
-};
-
-static void pmic_irq_ack(struct irq_data *d)
-{
- if (d->irq == IRQ_MMP2_PMIC)
- mmp2_clear_pmic_int();
-}
-
-#define SECOND_IRQ_MASK(_name_, irq_base, prefix) \
-static void _name_##_mask_irq(struct irq_data *d) \
-{ \
- uint32_t r; \
- r = __raw_readl(prefix##_MASK) | (1 << (d->irq - irq_base)); \
- __raw_writel(r, prefix##_MASK); \
-}
-
-#define SECOND_IRQ_UNMASK(_name_, irq_base, prefix) \
-static void _name_##_unmask_irq(struct irq_data *d) \
-{ \
- uint32_t r; \
- r = __raw_readl(prefix##_MASK) & ~(1 << (d->irq - irq_base)); \
- __raw_writel(r, prefix##_MASK); \
-}
-
-#define SECOND_IRQ_DEMUX(_name_, irq_base, prefix) \
-static void _name_##_irq_demux(unsigned int irq, struct irq_desc *desc) \
-{ \
- unsigned long status, mask, n; \
- mask = __raw_readl(prefix##_MASK); \
- while (1) { \
- status = __raw_readl(prefix##_STATUS) & ~mask; \
- if (status == 0) \
- break; \
- n = find_first_bit(&status, BITS_PER_LONG); \
- while (n < BITS_PER_LONG) { \
- generic_handle_irq(irq_base + n); \
- n = find_next_bit(&status, BITS_PER_LONG, n+1); \
- } \
- } \
-}
-
-#define SECOND_IRQ_CHIP(_name_, irq_base, prefix) \
-SECOND_IRQ_MASK(_name_, irq_base, prefix) \
-SECOND_IRQ_UNMASK(_name_, irq_base, prefix) \
-SECOND_IRQ_DEMUX(_name_, irq_base, prefix) \
-static struct irq_chip _name_##_irq_chip = { \
- .name = #_name_, \
- .irq_mask = _name_##_mask_irq, \
- .irq_unmask = _name_##_unmask_irq, \
-}
-
-SECOND_IRQ_CHIP(pmic, IRQ_MMP2_PMIC_BASE, MMP2_ICU_INT4);
-SECOND_IRQ_CHIP(rtc, IRQ_MMP2_RTC_BASE, MMP2_ICU_INT5);
-SECOND_IRQ_CHIP(twsi, IRQ_MMP2_TWSI_BASE, MMP2_ICU_INT17);
-SECOND_IRQ_CHIP(misc, IRQ_MMP2_MISC_BASE, MMP2_ICU_INT35);
-SECOND_IRQ_CHIP(ssp, IRQ_MMP2_SSP_BASE, MMP2_ICU_INT51);
-
-static void init_mux_irq(struct irq_chip *chip, int start, int num)
-{
- int irq;
-
- for (irq = start; num > 0; irq++, num--) {
- struct irq_data *d = irq_get_irq_data(irq);
-
- /* mask and clear the IRQ */
- chip->irq_mask(d);
- if (chip->irq_ack)
- chip->irq_ack(d);
-
- irq_set_chip(irq, chip);
- set_irq_flags(irq, IRQF_VALID);
- irq_set_handler(irq, handle_level_irq);
- }
-}
-
-void __init mmp2_init_icu(void)
-{
- int irq;
-
- for (irq = 0; irq < IRQ_MMP2_MUX_BASE; irq++) {
- icu_mask_irq(irq_get_irq_data(irq));
- irq_set_chip(irq, &icu_irq_chip);
- set_irq_flags(irq, IRQF_VALID);
-
- switch (irq) {
- case IRQ_MMP2_PMIC_MUX:
- case IRQ_MMP2_RTC_MUX:
- case IRQ_MMP2_TWSI_MUX:
- case IRQ_MMP2_MISC_MUX:
- case IRQ_MMP2_SSP_MUX:
- break;
- default:
- irq_set_handler(irq, handle_level_irq);
- break;
- }
- }
-
- /* NOTE: IRQ_MMP2_PMIC requires the PMIC MFPR register
- * to be written to clear the interrupt
- */
- pmic_irq_chip.irq_ack = pmic_irq_ack;
-
- init_mux_irq(&pmic_irq_chip, IRQ_MMP2_PMIC_BASE, 2);
- init_mux_irq(&rtc_irq_chip, IRQ_MMP2_RTC_BASE, 2);
- init_mux_irq(&twsi_irq_chip, IRQ_MMP2_TWSI_BASE, 5);
- init_mux_irq(&misc_irq_chip, IRQ_MMP2_MISC_BASE, 15);
- init_mux_irq(&ssp_irq_chip, IRQ_MMP2_SSP_BASE, 2);
-
- irq_set_chained_handler(IRQ_MMP2_PMIC_MUX, pmic_irq_demux);
- irq_set_chained_handler(IRQ_MMP2_RTC_MUX, rtc_irq_demux);
- irq_set_chained_handler(IRQ_MMP2_TWSI_MUX, twsi_irq_demux);
- irq_set_chained_handler(IRQ_MMP2_MISC_MUX, misc_irq_demux);
- irq_set_chained_handler(IRQ_MMP2_SSP_MUX, ssp_irq_demux);
-}
diff --git a/arch/arm/mach-mmp/irq-pxa168.c b/arch/arm/mach-mmp/irq-pxa168.c
deleted file mode 100644
index 89706a0d08f1..000000000000
--- a/arch/arm/mach-mmp/irq-pxa168.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * linux/arch/arm/mach-mmp/irq.c
- *
- * Generic IRQ handling, GPIO IRQ demultiplexing, etc.
- *
- * Author: Bin Yang <bin.yang@marvell.com>
- * Created: Sep 30, 2008
- * Copyright: Marvell International Ltd.
- *
- * 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/init.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-
-#include <mach/regs-icu.h>
-
-#include "common.h"
-
-#define IRQ_ROUTE_TO_AP (ICU_INT_CONF_AP_INT | ICU_INT_CONF_IRQ)
-
-#define PRIORITY_DEFAULT 0x1
-#define PRIORITY_NONE 0x0 /* means IRQ disabled */
-
-static void icu_mask_irq(struct irq_data *d)
-{
- __raw_writel(PRIORITY_NONE, ICU_INT_CONF(d->irq));
-}
-
-static void icu_unmask_irq(struct irq_data *d)
-{
- __raw_writel(IRQ_ROUTE_TO_AP | PRIORITY_DEFAULT, ICU_INT_CONF(d->irq));
-}
-
-static struct irq_chip icu_irq_chip = {
- .name = "icu_irq",
- .irq_ack = icu_mask_irq,
- .irq_mask = icu_mask_irq,
- .irq_unmask = icu_unmask_irq,
-};
-
-void __init icu_init_irq(void)
-{
- int irq;
-
- for (irq = 0; irq < 64; irq++) {
- icu_mask_irq(irq_get_irq_data(irq));
- irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq);
- set_irq_flags(irq, IRQF_VALID);
- }
-}
diff --git a/arch/arm/mach-mmp/irq.c b/arch/arm/mach-mmp/irq.c
new file mode 100644
index 000000000000..fcfe0e3bd701
--- /dev/null
+++ b/arch/arm/mach-mmp/irq.c
@@ -0,0 +1,458 @@
+/*
+ * linux/arch/arm/mach-mmp/irq.c
+ *
+ * Generic IRQ handling, GPIO IRQ demultiplexing, etc.
+ * Copyright (C) 2008 - 2012 Marvell Technology Group Ltd.
+ *
+ * Author: Bin Yang <bin.yang@marvell.com>
+ * Haojian Zhuang <haojian.zhuang@gmail.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/module.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#include <mach/irqs.h>
+
+#ifdef CONFIG_CPU_MMP2
+#include <mach/pm-mmp2.h>
+#endif
+#ifdef CONFIG_CPU_PXA910
+#include <mach/pm-pxa910.h>
+#endif
+
+#include "common.h"
+
+#define MAX_ICU_NR 16
+
+struct icu_chip_data {
+ int nr_irqs;
+ unsigned int virq_base;
+ unsigned int cascade_irq;
+ void __iomem *reg_status;
+ void __iomem *reg_mask;
+ unsigned int conf_enable;
+ unsigned int conf_disable;
+ unsigned int conf_mask;
+ unsigned int clr_mfp_irq_base;
+ unsigned int clr_mfp_hwirq;
+ struct irq_domain *domain;
+};
+
+struct mmp_intc_conf {
+ unsigned int conf_enable;
+ unsigned int conf_disable;
+ unsigned int conf_mask;
+};
+
+void __iomem *mmp_icu_base;
+static struct icu_chip_data icu_data[MAX_ICU_NR];
+static int max_icu_nr;
+
+extern void mmp2_clear_pmic_int(void);
+
+static void icu_mask_ack_irq(struct irq_data *d)
+{
+ struct irq_domain *domain = d->domain;
+ struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data;
+ int hwirq;
+ u32 r;
+
+ hwirq = d->irq - data->virq_base;
+ if (data == &icu_data[0]) {
+ r = readl_relaxed(mmp_icu_base + (hwirq << 2));
+ r &= ~data->conf_mask;
+ r |= data->conf_disable;
+ writel_relaxed(r, mmp_icu_base + (hwirq << 2));
+ } else {
+#ifdef CONFIG_CPU_MMP2
+ if ((data->virq_base == data->clr_mfp_irq_base)
+ && (hwirq == data->clr_mfp_hwirq))
+ mmp2_clear_pmic_int();
+#endif
+ r = readl_relaxed(data->reg_mask) | (1 << hwirq);
+ writel_relaxed(r, data->reg_mask);
+ }
+}
+
+static void icu_mask_irq(struct irq_data *d)
+{
+ struct irq_domain *domain = d->domain;
+ struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data;
+ int hwirq;
+ u32 r;
+
+ hwirq = d->irq - data->virq_base;
+ if (data == &icu_data[0]) {
+ r = readl_relaxed(mmp_icu_base + (hwirq << 2));
+ r &= ~data->conf_mask;
+ r |= data->conf_disable;
+ writel_relaxed(r, mmp_icu_base + (hwirq << 2));
+ } else {
+ r = readl_relaxed(data->reg_mask) | (1 << hwirq);
+ writel_relaxed(r, data->reg_mask);
+ }
+}
+
+static void icu_unmask_irq(struct irq_data *d)
+{
+ struct irq_domain *domain = d->domain;
+ struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data;
+ int hwirq;
+ u32 r;
+
+ hwirq = d->irq - data->virq_base;
+ if (data == &icu_data[0]) {
+ r = readl_relaxed(mmp_icu_base + (hwirq << 2));
+ r &= ~data->conf_mask;
+ r |= data->conf_enable;
+ writel_relaxed(r, mmp_icu_base + (hwirq << 2));
+ } else {
+ r = readl_relaxed(data->reg_mask) & ~(1 << hwirq);
+ writel_relaxed(r, data->reg_mask);
+ }
+}
+
+static struct irq_chip icu_irq_chip = {
+ .name = "icu_irq",
+ .irq_mask = icu_mask_irq,
+ .irq_mask_ack = icu_mask_ack_irq,
+ .irq_unmask = icu_unmask_irq,
+};
+
+static void icu_mux_irq_demux(unsigned int irq, struct irq_desc *desc)
+{
+ struct irq_domain *domain;
+ struct icu_chip_data *data;
+ int i;
+ unsigned long mask, status, n;
+
+ for (i = 1; i < max_icu_nr; i++) {
+ if (irq == icu_data[i].cascade_irq) {
+ domain = icu_data[i].domain;
+ data = (struct icu_chip_data *)domain->host_data;
+ break;
+ }
+ }
+ if (i >= max_icu_nr) {
+ pr_err("Spurious irq %d in MMP INTC\n", irq);
+ return;
+ }
+
+ mask = readl_relaxed(data->reg_mask);
+ while (1) {
+ status = readl_relaxed(data->reg_status) & ~mask;
+ if (status == 0)
+ break;
+ n = find_first_bit(&status, BITS_PER_LONG);
+ while (n < BITS_PER_LONG) {
+ generic_handle_irq(icu_data[i].virq_base + n);
+ n = find_next_bit(&status, BITS_PER_LONG, n + 1);
+ }
+ }
+}
+
+static int mmp_irq_domain_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hw)
+{
+ irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq);
+ set_irq_flags(irq, IRQF_VALID);
+ return 0;
+}
+
+static int mmp_irq_domain_xlate(struct irq_domain *d, struct device_node *node,
+ const u32 *intspec, unsigned int intsize,
+ unsigned long *out_hwirq,
+ unsigned int *out_type)
+{
+ *out_hwirq = intspec[0];
+ return 0;
+}
+
+const struct irq_domain_ops mmp_irq_domain_ops = {
+ .map = mmp_irq_domain_map,
+ .xlate = mmp_irq_domain_xlate,
+};
+
+static struct mmp_intc_conf mmp_conf = {
+ .conf_enable = 0x51,
+ .conf_disable = 0x0,
+ .conf_mask = 0x7f,
+};
+
+static struct mmp_intc_conf mmp2_conf = {
+ .conf_enable = 0x20,
+ .conf_disable = 0x0,
+ .conf_mask = 0x7f,
+};
+
+/* MMP (ARMv5) */
+void __init icu_init_irq(void)
+{
+ int irq;
+
+ max_icu_nr = 1;
+ mmp_icu_base = ioremap(0xd4282000, 0x1000);
+ icu_data[0].conf_enable = mmp_conf.conf_enable;
+ icu_data[0].conf_disable = mmp_conf.conf_disable;
+ icu_data[0].conf_mask = mmp_conf.conf_mask;
+ icu_data[0].nr_irqs = 64;
+ icu_data[0].virq_base = 0;
+ icu_data[0].domain = irq_domain_add_legacy(NULL, 64, 0, 0,
+ &irq_domain_simple_ops,
+ &icu_data[0]);
+ for (irq = 0; irq < 64; irq++) {
+ icu_mask_irq(irq_get_irq_data(irq));
+ irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq);
+ set_irq_flags(irq, IRQF_VALID);
+ }
+ irq_set_default_host(icu_data[0].domain);
+#ifdef CONFIG_CPU_PXA910
+ icu_irq_chip.irq_set_wake = pxa910_set_wake;
+#endif
+}
+
+/* MMP2 (ARMv7) */
+void __init mmp2_init_icu(void)
+{
+ int irq;
+
+ max_icu_nr = 8;
+ mmp_icu_base = ioremap(0xd4282000, 0x1000);
+ icu_data[0].conf_enable = mmp2_conf.conf_enable;
+ icu_data[0].conf_disable = mmp2_conf.conf_disable;
+ icu_data[0].conf_mask = mmp2_conf.conf_mask;
+ icu_data[0].nr_irqs = 64;
+ icu_data[0].virq_base = 0;
+ icu_data[0].domain = irq_domain_add_legacy(NULL, 64, 0, 0,
+ &irq_domain_simple_ops,
+ &icu_data[0]);
+ icu_data[1].reg_status = mmp_icu_base + 0x150;
+ icu_data[1].reg_mask = mmp_icu_base + 0x168;
+ icu_data[1].clr_mfp_irq_base = IRQ_MMP2_PMIC_BASE;
+ icu_data[1].clr_mfp_hwirq = IRQ_MMP2_PMIC - IRQ_MMP2_PMIC_BASE;
+ icu_data[1].nr_irqs = 2;
+ icu_data[1].virq_base = IRQ_MMP2_PMIC_BASE;
+ icu_data[1].domain = irq_domain_add_legacy(NULL, icu_data[1].nr_irqs,
+ icu_data[1].virq_base, 0,
+ &irq_domain_simple_ops,
+ &icu_data[1]);
+ icu_data[2].reg_status = mmp_icu_base + 0x154;
+ icu_data[2].reg_mask = mmp_icu_base + 0x16c;
+ icu_data[2].nr_irqs = 2;
+ icu_data[2].virq_base = IRQ_MMP2_RTC_BASE;
+ icu_data[2].domain = irq_domain_add_legacy(NULL, icu_data[2].nr_irqs,
+ icu_data[2].virq_base, 0,
+ &irq_domain_simple_ops,
+ &icu_data[2]);
+ icu_data[3].reg_status = mmp_icu_base + 0x180;
+ icu_data[3].reg_mask = mmp_icu_base + 0x17c;
+ icu_data[3].nr_irqs = 3;
+ icu_data[3].virq_base = IRQ_MMP2_KEYPAD_BASE;
+ icu_data[3].domain = irq_domain_add_legacy(NULL, icu_data[3].nr_irqs,
+ icu_data[3].virq_base, 0,
+ &irq_domain_simple_ops,
+ &icu_data[3]);
+ icu_data[4].reg_status = mmp_icu_base + 0x158;
+ icu_data[4].reg_mask = mmp_icu_base + 0x170;
+ icu_data[4].nr_irqs = 5;
+ icu_data[4].virq_base = IRQ_MMP2_TWSI_BASE;
+ icu_data[4].domain = irq_domain_add_legacy(NULL, icu_data[4].nr_irqs,
+ icu_data[4].virq_base, 0,
+ &irq_domain_simple_ops,
+ &icu_data[4]);
+ icu_data[5].reg_status = mmp_icu_base + 0x15c;
+ icu_data[5].reg_mask = mmp_icu_base + 0x174;
+ icu_data[5].nr_irqs = 15;
+ icu_data[5].virq_base = IRQ_MMP2_MISC_BASE;
+ icu_data[5].domain = irq_domain_add_legacy(NULL, icu_data[5].nr_irqs,
+ icu_data[5].virq_base, 0,
+ &irq_domain_simple_ops,
+ &icu_data[5]);
+ icu_data[6].reg_status = mmp_icu_base + 0x160;
+ icu_data[6].reg_mask = mmp_icu_base + 0x178;
+ icu_data[6].nr_irqs = 2;
+ icu_data[6].virq_base = IRQ_MMP2_MIPI_HSI1_BASE;
+ icu_data[6].domain = irq_domain_add_legacy(NULL, icu_data[6].nr_irqs,
+ icu_data[6].virq_base, 0,
+ &irq_domain_simple_ops,
+ &icu_data[6]);
+ icu_data[7].reg_status = mmp_icu_base + 0x188;
+ icu_data[7].reg_mask = mmp_icu_base + 0x184;
+ icu_data[7].nr_irqs = 2;
+ icu_data[7].virq_base = IRQ_MMP2_MIPI_HSI0_BASE;
+ icu_data[7].domain = irq_domain_add_legacy(NULL, icu_data[7].nr_irqs,
+ icu_data[7].virq_base, 0,
+ &irq_domain_simple_ops,
+ &icu_data[7]);
+ for (irq = 0; irq < IRQ_MMP2_MUX_END; irq++) {
+ icu_mask_irq(irq_get_irq_data(irq));
+ switch (irq) {
+ case IRQ_MMP2_PMIC_MUX:
+ case IRQ_MMP2_RTC_MUX:
+ case IRQ_MMP2_KEYPAD_MUX:
+ case IRQ_MMP2_TWSI_MUX:
+ case IRQ_MMP2_MISC_MUX:
+ case IRQ_MMP2_MIPI_HSI1_MUX:
+ case IRQ_MMP2_MIPI_HSI0_MUX:
+ irq_set_chip(irq, &icu_irq_chip);
+ irq_set_chained_handler(irq, icu_mux_irq_demux);
+ break;
+ default:
+ irq_set_chip_and_handler(irq, &icu_irq_chip,
+ handle_level_irq);
+ break;
+ }
+ set_irq_flags(irq, IRQF_VALID);
+ }
+ irq_set_default_host(icu_data[0].domain);
+#ifdef CONFIG_CPU_MMP2
+ icu_irq_chip.irq_set_wake = mmp2_set_wake;
+#endif
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id intc_ids[] __initconst = {
+ { .compatible = "mrvl,mmp-intc", .data = &mmp_conf },
+ { .compatible = "mrvl,mmp2-intc", .data = &mmp2_conf },
+ {}
+};
+
+static const struct of_device_id mmp_mux_irq_match[] __initconst = {
+ { .compatible = "mrvl,mmp2-mux-intc" },
+ {}
+};
+
+int __init mmp2_mux_init(struct device_node *parent)
+{
+ struct device_node *node;
+ const struct of_device_id *of_id;
+ struct resource res;
+ int i, irq_base, ret, irq;
+ u32 nr_irqs, mfp_irq;
+
+ node = parent;
+ max_icu_nr = 1;
+ for (i = 1; i < MAX_ICU_NR; i++) {
+ node = of_find_matching_node(node, mmp_mux_irq_match);
+ if (!node)
+ break;
+ of_id = of_match_node(&mmp_mux_irq_match[0], node);
+ ret = of_property_read_u32(node, "mrvl,intc-nr-irqs",
+ &nr_irqs);
+ if (ret) {
+ pr_err("Not found mrvl,intc-nr-irqs property\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ ret = of_address_to_resource(node, 0, &res);
+ if (ret < 0) {
+ pr_err("Not found reg property\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ icu_data[i].reg_status = mmp_icu_base + res.start;
+ ret = of_address_to_resource(node, 1, &res);
+ if (ret < 0) {
+ pr_err("Not found reg property\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ icu_data[i].reg_mask = mmp_icu_base + res.start;
+ icu_data[i].cascade_irq = irq_of_parse_and_map(node, 0);
+ if (!icu_data[i].cascade_irq) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
+ if (irq_base < 0) {
+ pr_err("Failed to allocate IRQ numbers for mux intc\n");
+ ret = irq_base;
+ goto err;
+ }
+ if (!of_property_read_u32(node, "mrvl,clr-mfp-irq",
+ &mfp_irq)) {
+ icu_data[i].clr_mfp_irq_base = irq_base;
+ icu_data[i].clr_mfp_hwirq = mfp_irq;
+ }
+ irq_set_chained_handler(icu_data[i].cascade_irq,
+ icu_mux_irq_demux);
+ icu_data[i].nr_irqs = nr_irqs;
+ icu_data[i].virq_base = irq_base;
+ icu_data[i].domain = irq_domain_add_legacy(node, nr_irqs,
+ irq_base, 0,
+ &mmp_irq_domain_ops,
+ &icu_data[i]);
+ for (irq = irq_base; irq < irq_base + nr_irqs; irq++)
+ icu_mask_irq(irq_get_irq_data(irq));
+ }
+ max_icu_nr = i;
+ return 0;
+err:
+ of_node_put(node);
+ max_icu_nr = i;
+ return ret;
+}
+
+void __init mmp_dt_irq_init(void)
+{
+ struct device_node *node;
+ const struct of_device_id *of_id;
+ struct mmp_intc_conf *conf;
+ int nr_irqs, irq_base, ret, irq;
+
+ node = of_find_matching_node(NULL, intc_ids);
+ if (!node) {
+ pr_err("Failed to find interrupt controller in arch-mmp\n");
+ return;
+ }
+ of_id = of_match_node(intc_ids, node);
+ conf = of_id->data;
+
+ ret = of_property_read_u32(node, "mrvl,intc-nr-irqs", &nr_irqs);
+ if (ret) {
+ pr_err("Not found mrvl,intc-nr-irqs property\n");
+ return;
+ }
+
+ mmp_icu_base = of_iomap(node, 0);
+ if (!mmp_icu_base) {
+ pr_err("Failed to get interrupt controller register\n");
+ return;
+ }
+
+ irq_base = irq_alloc_descs(-1, 0, nr_irqs - NR_IRQS_LEGACY, 0);
+ if (irq_base < 0) {
+ pr_err("Failed to allocate IRQ numbers\n");
+ goto err;
+ } else if (irq_base != NR_IRQS_LEGACY) {
+ pr_err("ICU's irqbase should be started from 0\n");
+ goto err;
+ }
+ icu_data[0].conf_enable = conf->conf_enable;
+ icu_data[0].conf_disable = conf->conf_disable;
+ icu_data[0].conf_mask = conf->conf_mask;
+ icu_data[0].nr_irqs = nr_irqs;
+ icu_data[0].virq_base = 0;
+ icu_data[0].domain = irq_domain_add_legacy(node, nr_irqs, 0, 0,
+ &mmp_irq_domain_ops,
+ &icu_data[0]);
+ irq_set_default_host(icu_data[0].domain);
+ for (irq = 0; irq < nr_irqs; irq++)
+ icu_mask_irq(irq_get_irq_data(irq));
+ mmp2_mux_init(node);
+ return;
+err:
+ iounmap(mmp_icu_base);
+}
+#endif
diff --git a/arch/arm/mach-mmp/mmp-dt.c b/arch/arm/mach-mmp/mmp-dt.c
index 67075395e400..033cc31b3c72 100644
--- a/arch/arm/mach-mmp/mmp-dt.c
+++ b/arch/arm/mach-mmp/mmp-dt.c
@@ -14,14 +14,19 @@
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
#include <mach/irqs.h>
#include "common.h"
-extern struct sys_timer pxa168_timer;
-extern void __init icu_init_irq(void);
+extern void __init mmp_dt_irq_init(void);
+extern void __init mmp_dt_init_timer(void);
-static const struct of_dev_auxdata mmp_auxdata_lookup[] __initconst = {
+static struct sys_timer mmp_dt_timer = {
+ .init = mmp_dt_init_timer,
+};
+
+static const struct of_dev_auxdata pxa168_auxdata_lookup[] __initconst = {
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.0", NULL),
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.1", NULL),
OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4026000, "pxa2xx-uart.2", NULL),
@@ -32,44 +37,47 @@ static const struct of_dev_auxdata mmp_auxdata_lookup[] __initconst = {
{}
};
-static int __init mmp_intc_add_irq_domain(struct device_node *np,
- struct device_node *parent)
-{
- irq_domain_add_simple(np, 0);
- return 0;
-}
-
-static int __init mmp_gpio_add_irq_domain(struct device_node *np,
- struct device_node *parent)
-{
- irq_domain_add_simple(np, IRQ_GPIO_START);
- return 0;
-}
-
-static const struct of_device_id mmp_irq_match[] __initconst = {
- { .compatible = "mrvl,mmp-intc", .data = mmp_intc_add_irq_domain, },
- { .compatible = "mrvl,mmp-gpio", .data = mmp_gpio_add_irq_domain, },
+static const struct of_dev_auxdata pxa910_auxdata_lookup[] __initconst = {
+ OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.0", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.1", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4036000, "pxa2xx-uart.2", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4011000, "pxa2xx-i2c.0", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4037000, "pxa2xx-i2c.1", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-gpio", 0xd4019000, "pxa-gpio", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-rtc", 0xd4010000, "sa1100-rtc", NULL),
{}
};
-static void __init mmp_dt_init(void)
+static void __init pxa168_dt_init(void)
{
+ of_platform_populate(NULL, of_default_bus_match_table,
+ pxa168_auxdata_lookup, NULL);
+}
- of_irq_init(mmp_irq_match);
-
+static void __init pxa910_dt_init(void)
+{
of_platform_populate(NULL, of_default_bus_match_table,
- mmp_auxdata_lookup, NULL);
+ pxa910_auxdata_lookup, NULL);
}
-static const char *pxa168_dt_board_compat[] __initdata = {
+static const char *mmp_dt_board_compat[] __initdata = {
"mrvl,pxa168-aspenite",
+ "mrvl,pxa910-dkb",
NULL,
};
DT_MACHINE_START(PXA168_DT, "Marvell PXA168 (Device Tree Support)")
.map_io = mmp_map_io,
- .init_irq = icu_init_irq,
- .timer = &pxa168_timer,
- .init_machine = mmp_dt_init,
- .dt_compat = pxa168_dt_board_compat,
+ .init_irq = mmp_dt_irq_init,
+ .timer = &mmp_dt_timer,
+ .init_machine = pxa168_dt_init,
+ .dt_compat = mmp_dt_board_compat,
+MACHINE_END
+
+DT_MACHINE_START(PXA910_DT, "Marvell PXA910 (Device Tree Support)")
+ .map_io = mmp_map_io,
+ .init_irq = mmp_dt_irq_init,
+ .timer = &mmp_dt_timer,
+ .init_machine = pxa910_dt_init,
+ .dt_compat = mmp_dt_board_compat,
MACHINE_END
diff --git a/arch/arm/mach-mmp/mmp2-dt.c b/arch/arm/mach-mmp/mmp2-dt.c
new file mode 100644
index 000000000000..535a5ed5977b
--- /dev/null
+++ b/arch/arm/mach-mmp/mmp2-dt.c
@@ -0,0 +1,60 @@
+/*
+ * linux/arch/arm/mach-mmp/mmp2-dt.c
+ *
+ * Copyright (C) 2012 Marvell Technology Group Ltd.
+ * Author: Haojian Zhuang <haojian.zhuang@marvell.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
+ * publishhed by the Free Software Foundation.
+ */
+
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/irqs.h>
+#include <mach/regs-apbc.h>
+
+#include "common.h"
+
+extern void __init mmp_dt_irq_init(void);
+extern void __init mmp_dt_init_timer(void);
+
+static struct sys_timer mmp_dt_timer = {
+ .init = mmp_dt_init_timer,
+};
+
+static const struct of_dev_auxdata mmp2_auxdata_lookup[] __initconst = {
+ OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4030000, "pxa2xx-uart.0", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4017000, "pxa2xx-uart.1", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4018000, "pxa2xx-uart.2", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-uart", 0xd4016000, "pxa2xx-uart.3", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4011000, "pxa2xx-i2c.0", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-twsi", 0xd4025000, "pxa2xx-i2c.1", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-gpio", 0xd4019000, "pxa-gpio", NULL),
+ OF_DEV_AUXDATA("mrvl,mmp-rtc", 0xd4010000, "sa1100-rtc", NULL),
+ {}
+};
+
+static void __init mmp2_dt_init(void)
+{
+ of_platform_populate(NULL, of_default_bus_match_table,
+ mmp2_auxdata_lookup, NULL);
+}
+
+static const char *mmp2_dt_board_compat[] __initdata = {
+ "mrvl,mmp2-brownstone",
+ NULL,
+};
+
+DT_MACHINE_START(MMP2_DT, "Marvell MMP2 (Device Tree Support)")
+ .map_io = mmp_map_io,
+ .init_irq = mmp_dt_irq_init,
+ .timer = &mmp_dt_timer,
+ .init_machine = mmp2_dt_init,
+ .dt_compat = mmp2_dt_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-mmp/pm-mmp2.c b/arch/arm/mach-mmp/pm-mmp2.c
new file mode 100644
index 000000000000..461a191a32d2
--- /dev/null
+++ b/arch/arm/mach-mmp/pm-mmp2.c
@@ -0,0 +1,264 @@
+/*
+ * MMP2 Power Management Routines
+ *
+ * This software program is licensed subject to the GNU General Public License
+ * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html
+ *
+ * (C) Copyright 2012 Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/suspend.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/cputype.h>
+#include <mach/addr-map.h>
+#include <mach/pm-mmp2.h>
+#include <mach/regs-icu.h>
+#include <mach/irqs.h>
+
+int mmp2_set_wake(struct irq_data *d, unsigned int on)
+{
+ int irq = d->irq;
+ struct irq_desc *desc = irq_to_desc(irq);
+ unsigned long data = 0;
+
+ if (unlikely(irq >= nr_irqs)) {
+ pr_err("IRQ nubmers are out of boundary!\n");
+ return -EINVAL;
+ }
+
+ if (on) {
+ if (desc->action)
+ desc->action->flags |= IRQF_NO_SUSPEND;
+ } else {
+ if (desc->action)
+ desc->action->flags &= ~IRQF_NO_SUSPEND;
+ }
+
+ /* enable wakeup sources */
+ switch (irq) {
+ case IRQ_MMP2_RTC:
+ case IRQ_MMP2_RTC_ALARM:
+ data = MPMU_WUCRM_PJ_WAKEUP(4) | MPMU_WUCRM_PJ_RTC_ALARM;
+ break;
+ case IRQ_MMP2_PMIC:
+ data = MPMU_WUCRM_PJ_WAKEUP(7);
+ break;
+ case IRQ_MMP2_MMC2:
+ /* mmc use WAKEUP2, same as GPIO wakeup source */
+ data = MPMU_WUCRM_PJ_WAKEUP(2);
+ break;
+ }
+ if (on) {
+ if (data) {
+ data |= __raw_readl(MPMU_WUCRM_PJ);
+ __raw_writel(data, MPMU_WUCRM_PJ);
+ }
+ } else {
+ if (data) {
+ data = ~data & __raw_readl(MPMU_WUCRM_PJ);
+ __raw_writel(data, MPMU_WUCRM_PJ);
+ }
+ }
+ return 0;
+}
+
+static void pm_scu_clk_disable(void)
+{
+ unsigned int val;
+
+ /* close AXI fabric clock gate */
+ __raw_writel(0x0, CIU_REG(0x64));
+ __raw_writel(0x0, CIU_REG(0x68));
+
+ /* close MCB master clock gate */
+ val = __raw_readl(CIU_REG(0x1c));
+ val |= 0xf0;
+ __raw_writel(val, CIU_REG(0x1c));
+
+ return ;
+}
+
+static void pm_scu_clk_enable(void)
+{
+ unsigned int val;
+
+ /* open AXI fabric clock gate */
+ __raw_writel(0x03003003, CIU_REG(0x64));
+ __raw_writel(0x00303030, CIU_REG(0x68));
+
+ /* open MCB master clock gate */
+ val = __raw_readl(CIU_REG(0x1c));
+ val &= ~(0xf0);
+ __raw_writel(val, CIU_REG(0x1c));
+
+ return ;
+}
+
+static void pm_mpmu_clk_disable(void)
+{
+ /*
+ * disable clocks in MPMU_CGR_PJ register
+ * except clock for APMU_PLL1, APMU_PLL1_2 and AP_26M
+ */
+ __raw_writel(0x0000a010, MPMU_CGR_PJ);
+}
+
+static void pm_mpmu_clk_enable(void)
+{
+ unsigned int val;
+
+ __raw_writel(0xdffefffe, MPMU_CGR_PJ);
+ val = __raw_readl(MPMU_PLL2_CTRL1);
+ val |= (1 << 29);
+ __raw_writel(val, MPMU_PLL2_CTRL1);
+
+ return ;
+}
+
+void mmp2_pm_enter_lowpower_mode(int state)
+{
+ uint32_t idle_cfg, apcr;
+
+ idle_cfg = __raw_readl(APMU_PJ_IDLE_CFG);
+ apcr = __raw_readl(MPMU_PCR_PJ);
+ apcr &= ~(MPMU_PCR_PJ_SLPEN | MPMU_PCR_PJ_DDRCORSD | MPMU_PCR_PJ_APBSD
+ | MPMU_PCR_PJ_AXISD | MPMU_PCR_PJ_VCTCXOSD | (1 << 13));
+ idle_cfg &= ~APMU_PJ_IDLE_CFG_PJ_IDLE;
+
+ switch (state) {
+ case POWER_MODE_SYS_SLEEP:
+ apcr |= MPMU_PCR_PJ_SLPEN; /* set the SLPEN bit */
+ apcr |= MPMU_PCR_PJ_VCTCXOSD; /* set VCTCXOSD */
+ /* fall through */
+ case POWER_MODE_CHIP_SLEEP:
+ apcr |= MPMU_PCR_PJ_SLPEN;
+ /* fall through */
+ case POWER_MODE_APPS_SLEEP:
+ apcr |= MPMU_PCR_PJ_APBSD; /* set APBSD */
+ /* fall through */
+ case POWER_MODE_APPS_IDLE:
+ apcr |= MPMU_PCR_PJ_AXISD; /* set AXISDD bit */
+ apcr |= MPMU_PCR_PJ_DDRCORSD; /* set DDRCORSD bit */
+ idle_cfg |= APMU_PJ_IDLE_CFG_PJ_PWRDWN; /* PJ power down */
+ apcr |= MPMU_PCR_PJ_SPSD;
+ /* fall through */
+ case POWER_MODE_CORE_EXTIDLE:
+ idle_cfg |= APMU_PJ_IDLE_CFG_PJ_IDLE; /* set the IDLE bit */
+ idle_cfg &= ~APMU_PJ_IDLE_CFG_ISO_MODE_CNTRL_MASK;
+ idle_cfg |= APMU_PJ_IDLE_CFG_PWR_SW(3)
+ | APMU_PJ_IDLE_CFG_L2_PWR_SW;
+ break;
+ case POWER_MODE_CORE_INTIDLE:
+ apcr &= ~MPMU_PCR_PJ_SPSD;
+ break;
+ }
+
+ /* set reserve bits */
+ apcr |= (1 << 30) | (1 << 25);
+
+ /* finally write the registers back */
+ __raw_writel(idle_cfg, APMU_PJ_IDLE_CFG);
+ __raw_writel(apcr, MPMU_PCR_PJ); /* 0xfe086000 */
+}
+
+static int mmp2_pm_enter(suspend_state_t state)
+{
+ int temp;
+
+ temp = __raw_readl(MMP2_ICU_INT4_MASK);
+ if (temp & (1 << 1)) {
+ printk(KERN_ERR "%s: PMIC interrupt is handling\n", __func__);
+ return -EAGAIN;
+ }
+
+ temp = __raw_readl(APMU_SRAM_PWR_DWN);
+ temp |= ((1 << 19) | (1 << 18));
+ __raw_writel(temp, APMU_SRAM_PWR_DWN);
+ pm_mpmu_clk_disable();
+ pm_scu_clk_disable();
+
+ printk(KERN_INFO "%s: before suspend\n", __func__);
+ cpu_do_idle();
+ printk(KERN_INFO "%s: after suspend\n", __func__);
+
+ pm_mpmu_clk_enable(); /* enable clocks in MPMU */
+ pm_scu_clk_enable(); /* enable clocks in SCU */
+
+ return 0;
+}
+
+/*
+ * Called after processes are frozen, but before we shut down devices.
+ */
+static int mmp2_pm_prepare(void)
+{
+ mmp2_pm_enter_lowpower_mode(POWER_MODE_SYS_SLEEP);
+
+ return 0;
+}
+
+/*
+ * Called after devices are re-setup, but before processes are thawed.
+ */
+static void mmp2_pm_finish(void)
+{
+ mmp2_pm_enter_lowpower_mode(POWER_MODE_CORE_INTIDLE);
+}
+
+static int mmp2_pm_valid(suspend_state_t state)
+{
+ return ((state == PM_SUSPEND_STANDBY) || (state == PM_SUSPEND_MEM));
+}
+
+/*
+ * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
+ */
+static const struct platform_suspend_ops mmp2_pm_ops = {
+ .valid = mmp2_pm_valid,
+ .prepare = mmp2_pm_prepare,
+ .enter = mmp2_pm_enter,
+ .finish = mmp2_pm_finish,
+};
+
+static int __init mmp2_pm_init(void)
+{
+ uint32_t apcr;
+
+ if (!cpu_is_mmp2())
+ return -EIO;
+
+ suspend_set_ops(&mmp2_pm_ops);
+
+ /*
+ * Set bit 0, Slow clock Select 32K clock input instead of VCXO
+ * VCXO is chosen by default, which would be disabled in suspend
+ */
+ __raw_writel(0x5, MPMU_SCCR);
+
+ /*
+ * Clear bit 23 of CIU_CPU_CONF
+ * direct PJ4 to DDR access through Memory Controller slow queue
+ * fast queue has issue and cause lcd will flick
+ */
+ __raw_writel(__raw_readl(CIU_REG(0x8)) & ~(0x1 << 23), CIU_REG(0x8));
+
+ /* Clear default low power control bit */
+ apcr = __raw_readl(MPMU_PCR_PJ);
+ apcr &= ~(MPMU_PCR_PJ_SLPEN | MPMU_PCR_PJ_DDRCORSD
+ | MPMU_PCR_PJ_APBSD | MPMU_PCR_PJ_AXISD | 1 << 13);
+ __raw_writel(apcr, MPMU_PCR_PJ);
+
+ return 0;
+}
+
+late_initcall(mmp2_pm_init);
diff --git a/arch/arm/mach-mmp/pm-pxa910.c b/arch/arm/mach-mmp/pm-pxa910.c
new file mode 100644
index 000000000000..48981ca801a5
--- /dev/null
+++ b/arch/arm/mach-mmp/pm-pxa910.c
@@ -0,0 +1,285 @@
+/*
+ * PXA910 Power Management Routines
+ *
+ * This software program is licensed subject to the GNU General Public License
+ * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html
+ *
+ * (C) Copyright 2009 Marvell International Ltd.
+ * All Rights Reserved
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/suspend.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/cputype.h>
+#include <mach/addr-map.h>
+#include <mach/pm-pxa910.h>
+#include <mach/regs-icu.h>
+#include <mach/irqs.h>
+
+int pxa910_set_wake(struct irq_data *data, unsigned int on)
+{
+ int irq = data->irq;
+ struct irq_desc *desc = irq_to_desc(data->irq);
+ uint32_t awucrm = 0, apcr = 0;
+
+ if (unlikely(irq >= nr_irqs)) {
+ pr_err("IRQ nubmers are out of boundary!\n");
+ return -EINVAL;
+ }
+
+ if (on) {
+ if (desc->action)
+ desc->action->flags |= IRQF_NO_SUSPEND;
+ } else {
+ if (desc->action)
+ desc->action->flags &= ~IRQF_NO_SUSPEND;
+ }
+
+ /* setting wakeup sources */
+ switch (irq) {
+ /* wakeup line 2 */
+ case IRQ_PXA910_AP_GPIO:
+ awucrm = MPMU_AWUCRM_WAKEUP(2);
+ apcr |= MPMU_APCR_SLPWP2;
+ break;
+ /* wakeup line 3 */
+ case IRQ_PXA910_KEYPAD:
+ awucrm = MPMU_AWUCRM_WAKEUP(3) | MPMU_AWUCRM_KEYPRESS;
+ apcr |= MPMU_APCR_SLPWP3;
+ break;
+ case IRQ_PXA910_ROTARY:
+ awucrm = MPMU_AWUCRM_WAKEUP(3) | MPMU_AWUCRM_NEWROTARY;
+ apcr |= MPMU_APCR_SLPWP3;
+ break;
+ case IRQ_PXA910_TRACKBALL:
+ awucrm = MPMU_AWUCRM_WAKEUP(3) | MPMU_AWUCRM_TRACKBALL;
+ apcr |= MPMU_APCR_SLPWP3;
+ break;
+ /* wakeup line 4 */
+ case IRQ_PXA910_AP1_TIMER1:
+ awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP1_TIMER_1;
+ apcr |= MPMU_APCR_SLPWP4;
+ break;
+ case IRQ_PXA910_AP1_TIMER2:
+ awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP1_TIMER_2;
+ apcr |= MPMU_APCR_SLPWP4;
+ break;
+ case IRQ_PXA910_AP1_TIMER3:
+ awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP1_TIMER_3;
+ apcr |= MPMU_APCR_SLPWP4;
+ break;
+ case IRQ_PXA910_AP2_TIMER1:
+ awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP2_TIMER_1;
+ apcr |= MPMU_APCR_SLPWP4;
+ break;
+ case IRQ_PXA910_AP2_TIMER2:
+ awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP2_TIMER_2;
+ apcr |= MPMU_APCR_SLPWP4;
+ break;
+ case IRQ_PXA910_AP2_TIMER3:
+ awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_AP2_TIMER_3;
+ apcr |= MPMU_APCR_SLPWP4;
+ break;
+ case IRQ_PXA910_RTC_ALARM:
+ awucrm = MPMU_AWUCRM_WAKEUP(4) | MPMU_AWUCRM_RTC_ALARM;
+ apcr |= MPMU_APCR_SLPWP4;
+ break;
+ /* wakeup line 5 */
+ case IRQ_PXA910_USB1:
+ case IRQ_PXA910_USB2:
+ awucrm = MPMU_AWUCRM_WAKEUP(5);
+ apcr |= MPMU_APCR_SLPWP5;
+ break;
+ /* wakeup line 6 */
+ case IRQ_PXA910_MMC:
+ awucrm = MPMU_AWUCRM_WAKEUP(6)
+ | MPMU_AWUCRM_SDH1
+ | MPMU_AWUCRM_SDH2;
+ apcr |= MPMU_APCR_SLPWP6;
+ break;
+ /* wakeup line 7 */
+ case IRQ_PXA910_PMIC_INT:
+ awucrm = MPMU_AWUCRM_WAKEUP(7);
+ apcr |= MPMU_APCR_SLPWP7;
+ break;
+ default:
+ if (irq >= IRQ_GPIO_START && irq < IRQ_BOARD_START) {
+ awucrm = MPMU_AWUCRM_WAKEUP(2);
+ apcr |= MPMU_APCR_SLPWP2;
+ } else
+ printk(KERN_ERR "Error: no defined wake up source irq: %d\n",
+ irq);
+ }
+
+ if (on) {
+ if (awucrm) {
+ awucrm |= __raw_readl(MPMU_AWUCRM);
+ __raw_writel(awucrm, MPMU_AWUCRM);
+ }
+ if (apcr) {
+ apcr = ~apcr & __raw_readl(MPMU_APCR);
+ __raw_writel(apcr, MPMU_APCR);
+ }
+ } else {
+ if (awucrm) {
+ awucrm = ~awucrm & __raw_readl(MPMU_AWUCRM);
+ __raw_writel(awucrm, MPMU_AWUCRM);
+ }
+ if (apcr) {
+ apcr |= __raw_readl(MPMU_APCR);
+ __raw_writel(apcr, MPMU_APCR);
+ }
+ }
+ return 0;
+}
+
+void pxa910_pm_enter_lowpower_mode(int state)
+{
+ uint32_t idle_cfg, apcr;
+
+ idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG);
+ apcr = __raw_readl(MPMU_APCR);
+
+ apcr &= ~(MPMU_APCR_DDRCORSD | MPMU_APCR_APBSD | MPMU_APCR_AXISD
+ | MPMU_APCR_VCTCXOSD | MPMU_APCR_STBYEN);
+ idle_cfg &= ~(APMU_MOH_IDLE_CFG_MOH_IDLE
+ | APMU_MOH_IDLE_CFG_MOH_PWRDWN);
+
+ switch (state) {
+ case POWER_MODE_UDR:
+ /* only shutdown APB in UDR */
+ apcr |= MPMU_APCR_STBYEN | MPMU_APCR_APBSD;
+ /* fall through */
+ case POWER_MODE_SYS_SLEEP:
+ apcr |= MPMU_APCR_SLPEN; /* set the SLPEN bit */
+ apcr |= MPMU_APCR_VCTCXOSD; /* set VCTCXOSD */
+ /* fall through */
+ case POWER_MODE_APPS_SLEEP:
+ apcr |= MPMU_APCR_DDRCORSD; /* set DDRCORSD */
+ /* fall through */
+ case POWER_MODE_APPS_IDLE:
+ apcr |= MPMU_APCR_AXISD; /* set AXISDD bit */
+ /* fall through */
+ case POWER_MODE_CORE_EXTIDLE:
+ idle_cfg |= APMU_MOH_IDLE_CFG_MOH_IDLE;
+ idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWRDWN;
+ idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWR_SW(3)
+ | APMU_MOH_IDLE_CFG_MOH_L2_PWR_SW(3);
+ /* fall through */
+ case POWER_MODE_CORE_INTIDLE:
+ break;
+ }
+
+ /* program the memory controller hardware sleep type and auto wakeup */
+ idle_cfg |= APMU_MOH_IDLE_CFG_MOH_DIS_MC_SW_REQ;
+ idle_cfg |= APMU_MOH_IDLE_CFG_MOH_MC_WAKE_EN;
+ __raw_writel(0x0, APMU_MC_HW_SLP_TYPE); /* auto refresh */
+
+ /* set DSPSD, DTCMSD, BBSD, MSASLPEN */
+ apcr |= MPMU_APCR_DSPSD | MPMU_APCR_DTCMSD | MPMU_APCR_BBSD
+ | MPMU_APCR_MSASLPEN;
+
+ /*always set SLEPEN bit mainly for MSA*/
+ apcr |= MPMU_APCR_SLPEN;
+
+ /* finally write the registers back */
+ __raw_writel(idle_cfg, APMU_MOH_IDLE_CFG);
+ __raw_writel(apcr, MPMU_APCR);
+
+}
+
+static int pxa910_pm_enter(suspend_state_t state)
+{
+ unsigned int idle_cfg, reg = 0;
+
+ /*pmic thread not completed,exit;otherwise system can't be waked up*/
+ reg = __raw_readl(ICU_INT_CONF(IRQ_PXA910_PMIC_INT));
+ if ((reg & 0x3) == 0)
+ return -EAGAIN;
+
+ idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG);
+ idle_cfg |= APMU_MOH_IDLE_CFG_MOH_PWRDWN
+ | APMU_MOH_IDLE_CFG_MOH_SRAM_PWRDWN;
+ __raw_writel(idle_cfg, APMU_MOH_IDLE_CFG);
+
+ /* disable L2 */
+ outer_disable();
+ /* wait for l2 idle */
+ while (!(readl(CIU_REG(0x8)) & (1 << 16)))
+ udelay(1);
+
+ cpu_do_idle();
+
+ /* enable L2 */
+ outer_resume();
+ /* wait for l2 idle */
+ while (!(readl(CIU_REG(0x8)) & (1 << 16)))
+ udelay(1);
+
+ idle_cfg = __raw_readl(APMU_MOH_IDLE_CFG);
+ idle_cfg &= ~(APMU_MOH_IDLE_CFG_MOH_PWRDWN
+ | APMU_MOH_IDLE_CFG_MOH_SRAM_PWRDWN);
+ __raw_writel(idle_cfg, APMU_MOH_IDLE_CFG);
+
+ return 0;
+}
+
+/*
+ * Called after processes are frozen, but before we shut down devices.
+ */
+static int pxa910_pm_prepare(void)
+{
+ pxa910_pm_enter_lowpower_mode(POWER_MODE_UDR);
+ return 0;
+}
+
+/*
+ * Called after devices are re-setup, but before processes are thawed.
+ */
+static void pxa910_pm_finish(void)
+{
+ pxa910_pm_enter_lowpower_mode(POWER_MODE_CORE_INTIDLE);
+}
+
+static int pxa910_pm_valid(suspend_state_t state)
+{
+ return ((state == PM_SUSPEND_STANDBY) || (state == PM_SUSPEND_MEM));
+}
+
+static const struct platform_suspend_ops pxa910_pm_ops = {
+ .valid = pxa910_pm_valid,
+ .prepare = pxa910_pm_prepare,
+ .enter = pxa910_pm_enter,
+ .finish = pxa910_pm_finish,
+};
+
+static int __init pxa910_pm_init(void)
+{
+ uint32_t awucrm = 0;
+
+ if (!cpu_is_pxa910())
+ return -EIO;
+
+ suspend_set_ops(&pxa910_pm_ops);
+
+ /* Set the following bits for MMP3 playback with VCTXO on */
+ __raw_writel(__raw_readl(APMU_SQU_CLK_GATE_CTRL) | (1 << 30),
+ APMU_SQU_CLK_GATE_CTRL);
+ __raw_writel(__raw_readl(MPMU_FCCR) | (1 << 28), MPMU_FCCR);
+
+ awucrm |= MPMU_AWUCRM_AP_ASYNC_INT | MPMU_AWUCRM_AP_FULL_IDLE;
+ __raw_writel(awucrm, MPMU_AWUCRM);
+
+ return 0;
+}
+
+late_initcall(pxa910_pm_init);
diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c
index b24d2c32cba9..62d787c34475 100644
--- a/arch/arm/mach-mmp/pxa168.c
+++ b/arch/arm/mach-mmp/pxa168.c
@@ -14,6 +14,7 @@
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/platform_data/mv_usb.h>
#include <asm/mach/time.h>
#include <asm/system_misc.h>
@@ -27,6 +28,7 @@
#include <mach/mfp.h>
#include <linux/dma-mapping.h>
#include <mach/pxa168.h>
+#include <mach/regs-usb.h>
#include "common.h"
#include "clock.h"
@@ -93,7 +95,7 @@ static struct clk_lookup pxa168_clkregs[] = {
INIT_CLKREG(&clk_gpio, "pxa-gpio", NULL),
INIT_CLKREG(&clk_keypad, "pxa27x-keypad", NULL),
INIT_CLKREG(&clk_eth, "pxa168-eth", "MFUCLK"),
- INIT_CLKREG(&clk_usb, "pxa168-ehci", "PXA168-USBCLK"),
+ INIT_CLKREG(&clk_usb, NULL, "PXA168-USBCLK"),
INIT_CLKREG(&clk_rtc, "sa1100-rtc", NULL),
};
@@ -184,17 +186,17 @@ struct platform_device pxa168_device_gpio = {
struct resource pxa168_usb_host_resources[] = {
/* USB Host conroller register base */
[0] = {
- .start = 0xd4209000,
- .end = 0xd4209000 + 0x200,
+ .start = PXA168_U2H_REGBASE + U2x_CAPREGS_OFFSET,
+ .end = PXA168_U2H_REGBASE + USB_REG_RANGE,
.flags = IORESOURCE_MEM,
- .name = "pxa168-usb-host",
+ .name = "capregs",
},
/* USB PHY register base */
[1] = {
- .start = 0xd4206000,
- .end = 0xd4206000 + 0xff,
+ .start = PXA168_U2H_PHYBASE,
+ .end = PXA168_U2H_PHYBASE + USB_PHY_RANGE,
.flags = IORESOURCE_MEM,
- .name = "pxa168-usb-phy",
+ .name = "phyregs",
},
[2] = {
.start = IRQ_PXA168_USB2,
@@ -205,7 +207,7 @@ struct resource pxa168_usb_host_resources[] = {
static u64 pxa168_usb_host_dmamask = DMA_BIT_MASK(32);
struct platform_device pxa168_device_usb_host = {
- .name = "pxa168-ehci",
+ .name = "pxa-sph",
.id = -1,
.dev = {
.dma_mask = &pxa168_usb_host_dmamask,
@@ -216,7 +218,7 @@ struct platform_device pxa168_device_usb_host = {
.resource = pxa168_usb_host_resources,
};
-int __init pxa168_add_usb_host(struct pxa168_usb_pdata *pdata)
+int __init pxa168_add_usb_host(struct mv_usb_platform_data *pdata)
{
pxa168_device_usb_host.dev.platform_data = pdata;
return platform_device_register(&pxa168_device_usb_host);
diff --git a/arch/arm/mach-mmp/pxa910.c b/arch/arm/mach-mmp/pxa910.c
index 43f8bcc29b67..6da52e9f2bdc 100644
--- a/arch/arm/mach-mmp/pxa910.c
+++ b/arch/arm/mach-mmp/pxa910.c
@@ -109,7 +109,7 @@ static struct clk_lookup pxa910_clkregs[] = {
INIT_CLKREG(&clk_pwm4, "pxa910-pwm.3", NULL),
INIT_CLKREG(&clk_nand, "pxa3xx-nand", NULL),
INIT_CLKREG(&clk_gpio, "pxa-gpio", NULL),
- INIT_CLKREG(&clk_u2o, "pxa-u2o", "U2OCLK"),
+ INIT_CLKREG(&clk_u2o, NULL, "U2OCLK"),
INIT_CLKREG(&clk_rtc, "sa1100-rtc", NULL),
};
diff --git a/arch/arm/mach-mmp/time.c b/arch/arm/mach-mmp/time.c
index 71fc4ee4602c..936447c70977 100644
--- a/arch/arm/mach-mmp/time.c
+++ b/arch/arm/mach-mmp/time.c
@@ -25,6 +25,9 @@
#include <linux/io.h>
#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <asm/sched_clock.h>
#include <mach/addr-map.h>
@@ -41,6 +44,8 @@
#define MAX_DELTA (0xfffffffe)
#define MIN_DELTA (16)
+static void __iomem *mmp_timer_base = TIMERS_VIRT_BASE;
+
/*
* FIXME: the timer needs some delay to stablize the counter capture
*/
@@ -48,12 +53,12 @@ static inline uint32_t timer_read(void)
{
int delay = 100;
- __raw_writel(1, TIMERS_VIRT_BASE + TMR_CVWR(1));
+ __raw_writel(1, mmp_timer_base + TMR_CVWR(1));
while (delay--)
cpu_relax();
- return __raw_readl(TIMERS_VIRT_BASE + TMR_CVWR(1));
+ return __raw_readl(mmp_timer_base + TMR_CVWR(1));
}
static u32 notrace mmp_read_sched_clock(void)
@@ -68,12 +73,12 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
/*
* Clear pending interrupt status.
*/
- __raw_writel(0x01, TIMERS_VIRT_BASE + TMR_ICR(0));
+ __raw_writel(0x01, mmp_timer_base + TMR_ICR(0));
/*
* Disable timer 0.
*/
- __raw_writel(0x02, TIMERS_VIRT_BASE + TMR_CER);
+ __raw_writel(0x02, mmp_timer_base + TMR_CER);
c->event_handler(c);
@@ -90,23 +95,23 @@ static int timer_set_next_event(unsigned long delta,
/*
* Disable timer 0.
*/
- __raw_writel(0x02, TIMERS_VIRT_BASE + TMR_CER);
+ __raw_writel(0x02, mmp_timer_base + TMR_CER);
/*
* Clear and enable timer match 0 interrupt.
*/
- __raw_writel(0x01, TIMERS_VIRT_BASE + TMR_ICR(0));
- __raw_writel(0x01, TIMERS_VIRT_BASE + TMR_IER(0));
+ __raw_writel(0x01, mmp_timer_base + TMR_ICR(0));
+ __raw_writel(0x01, mmp_timer_base + TMR_IER(0));
/*
* Setup new clockevent timer value.
*/
- __raw_writel(delta - 1, TIMERS_VIRT_BASE + TMR_TN_MM(0, 0));
+ __raw_writel(delta - 1, mmp_timer_base + TMR_TN_MM(0, 0));
/*
* Enable timer 0.
*/
- __raw_writel(0x03, TIMERS_VIRT_BASE + TMR_CER);
+ __raw_writel(0x03, mmp_timer_base + TMR_CER);
local_irq_restore(flags);
@@ -124,7 +129,7 @@ static void timer_set_mode(enum clock_event_mode mode,
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
/* disable the matching interrupt */
- __raw_writel(0x00, TIMERS_VIRT_BASE + TMR_IER(0));
+ __raw_writel(0x00, mmp_timer_base + TMR_IER(0));
break;
case CLOCK_EVT_MODE_RESUME:
case CLOCK_EVT_MODE_PERIODIC:
@@ -157,27 +162,27 @@ static struct clocksource cksrc = {
static void __init timer_config(void)
{
- uint32_t ccr = __raw_readl(TIMERS_VIRT_BASE + TMR_CCR);
+ uint32_t ccr = __raw_readl(mmp_timer_base + TMR_CCR);
- __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_CER); /* disable */
+ __raw_writel(0x0, mmp_timer_base + TMR_CER); /* disable */
ccr &= (cpu_is_mmp2()) ? (TMR_CCR_CS_0(0) | TMR_CCR_CS_1(0)) :
(TMR_CCR_CS_0(3) | TMR_CCR_CS_1(3));
- __raw_writel(ccr, TIMERS_VIRT_BASE + TMR_CCR);
+ __raw_writel(ccr, mmp_timer_base + TMR_CCR);
/* set timer 0 to periodic mode, and timer 1 to free-running mode */
- __raw_writel(0x2, TIMERS_VIRT_BASE + TMR_CMR);
+ __raw_writel(0x2, mmp_timer_base + TMR_CMR);
- __raw_writel(0x1, TIMERS_VIRT_BASE + TMR_PLCR(0)); /* periodic */
- __raw_writel(0x7, TIMERS_VIRT_BASE + TMR_ICR(0)); /* clear status */
- __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(0));
+ __raw_writel(0x1, mmp_timer_base + TMR_PLCR(0)); /* periodic */
+ __raw_writel(0x7, mmp_timer_base + TMR_ICR(0)); /* clear status */
+ __raw_writel(0x0, mmp_timer_base + TMR_IER(0));
- __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_PLCR(1)); /* free-running */
- __raw_writel(0x7, TIMERS_VIRT_BASE + TMR_ICR(1)); /* clear status */
- __raw_writel(0x0, TIMERS_VIRT_BASE + TMR_IER(1));
+ __raw_writel(0x0, mmp_timer_base + TMR_PLCR(1)); /* free-running */
+ __raw_writel(0x7, mmp_timer_base + TMR_ICR(1)); /* clear status */
+ __raw_writel(0x0, mmp_timer_base + TMR_IER(1));
/* enable timer 1 counter */
- __raw_writel(0x2, TIMERS_VIRT_BASE + TMR_CER);
+ __raw_writel(0x2, mmp_timer_base + TMR_CER);
}
static struct irqaction timer_irq = {
@@ -203,3 +208,37 @@ void __init timer_init(int irq)
clocksource_register_hz(&cksrc, CLOCK_TICK_RATE);
clockevents_register_device(&ckevt);
}
+
+#ifdef CONFIG_OF
+static struct of_device_id mmp_timer_dt_ids[] = {
+ { .compatible = "mrvl,mmp-timer", },
+ {}
+};
+
+void __init mmp_dt_init_timer(void)
+{
+ struct device_node *np;
+ int irq, ret;
+
+ np = of_find_matching_node(NULL, mmp_timer_dt_ids);
+ if (!np) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (!irq) {
+ ret = -EINVAL;
+ goto out;
+ }
+ mmp_timer_base = of_iomap(np, 0);
+ if (!mmp_timer_base) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ timer_init(irq);
+ return;
+out:
+ pr_err("Failed to get timer from device tree with error:%d\n", ret);
+}
+#endif
diff --git a/arch/arm/mach-mmp/ttc_dkb.c b/arch/arm/mach-mmp/ttc_dkb.c
index 3fc9ed21f97d..7a7de2b12a62 100644
--- a/arch/arm/mach-mmp/ttc_dkb.c
+++ b/arch/arm/mach-mmp/ttc_dkb.c
@@ -17,6 +17,8 @@
#include <linux/interrupt.h>
#include <linux/i2c/pca953x.h>
#include <linux/gpio.h>
+#include <linux/mfd/88pm860x.h>
+#include <linux/platform_data/mv_usb.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -25,6 +27,7 @@
#include <mach/mfp-pxa910.h>
#include <mach/pxa910.h>
#include <mach/irqs.h>
+#include <mach/regs-usb.h>
#include "common.h"
@@ -135,8 +138,18 @@ static struct pca953x_platform_data max7312_data[] = {
},
};
+static struct pm860x_platform_data ttc_dkb_pm8607_info = {
+ .irq_base = IRQ_BOARD_START,
+};
+
static struct i2c_board_info ttc_dkb_i2c_info[] = {
{
+ .type = "88PM860x",
+ .addr = 0x34,
+ .platform_data = &ttc_dkb_pm8607_info,
+ .irq = IRQ_PXA910_PMIC_INT,
+ },
+ {
.type = "max7312",
.addr = 0x23,
.irq = MMP_GPIO_TO_IRQ(80),
@@ -144,6 +157,26 @@ static struct i2c_board_info ttc_dkb_i2c_info[] = {
},
};
+#ifdef CONFIG_USB_SUPPORT
+#if defined(CONFIG_USB_MV_UDC) || defined(CONFIG_USB_EHCI_MV_U2O)
+
+static char *pxa910_usb_clock_name[] = {
+ [0] = "U2OCLK",
+};
+
+static struct mv_usb_platform_data ttc_usb_pdata = {
+ .clknum = 1,
+ .clkname = pxa910_usb_clock_name,
+ .vbus = NULL,
+ .mode = MV_USB_MODE_OTG,
+ .otg_force_a_bus_req = 1,
+ .phy_init = pxa_usb_phy_init,
+ .phy_deinit = pxa_usb_phy_deinit,
+ .set_vbus = NULL,
+};
+#endif
+#endif
+
static void __init ttc_dkb_init(void)
{
mfp_config(ARRAY_AND_SIZE(ttc_dkb_pin_config));
@@ -154,6 +187,21 @@ static void __init ttc_dkb_init(void)
/* off-chip devices */
pxa910_add_twsi(0, NULL, ARRAY_AND_SIZE(ttc_dkb_i2c_info));
platform_add_devices(ARRAY_AND_SIZE(ttc_dkb_devices));
+
+#ifdef CONFIG_USB_MV_UDC
+ pxa168_device_u2o.dev.platform_data = &ttc_usb_pdata;
+ platform_device_register(&pxa168_device_u2o);
+#endif
+
+#ifdef CONFIG_USB_EHCI_MV_U2O
+ pxa168_device_u2oehci.dev.platform_data = &ttc_usb_pdata;
+ platform_device_register(&pxa168_device_u2oehci);
+#endif
+
+#ifdef CONFIG_USB_MV_OTG
+ pxa168_device_u2ootg.dev.platform_data = &ttc_usb_pdata;
+ platform_device_register(&pxa168_device_u2ootg);
+#endif
}
MACHINE_START(TTC_DKB, "PXA910-based TTC_DKB Development Platform")
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index db81ed531031..75b3cfcada6d 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -17,7 +17,6 @@
#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/irq.h>
-#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/io.h>
diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c
index 7e8909c978c3..fbaa4ed95a3c 100644
--- a/arch/arm/mach-msm/board-qsd8x50.c
+++ b/arch/arm/mach-msm/board-qsd8x50.c
@@ -17,7 +17,6 @@
#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/irq.h>
-#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/usb/msm_hsusb.h>
diff --git a/arch/arm/mach-msm/include/mach/debug-macro.S b/arch/arm/mach-msm/include/mach/debug-macro.S
index 3ffd8668c9a5..0e05f88abcd5 100644
--- a/arch/arm/mach-msm/include/mach/debug-macro.S
+++ b/arch/arm/mach-msm/include/mach/debug-macro.S
@@ -30,8 +30,7 @@
@ Write the 1 character to UARTDM_TF
str \rd, [\rx, #0x70]
#else
- teq \rx, #0
- strne \rd, [\rx, #0x0C]
+ str \rd, [\rx, #0x0C]
#endif
.endm
diff --git a/arch/arm/mach-msm/scm.c b/arch/arm/mach-msm/scm.c
index bafabb502580..c536fd6bf827 100644
--- a/arch/arm/mach-msm/scm.c
+++ b/arch/arm/mach-msm/scm.c
@@ -282,6 +282,9 @@ u32 scm_get_version(void)
__asmeq("%1", "r1")
__asmeq("%2", "r0")
__asmeq("%3", "r1")
+#ifdef REQUIRES_SEC
+ ".arch_extension sec\n"
+#endif
"smc #0 @ switch to secure world\n"
: "=r" (r0), "=r" (r1)
: "r" (r0), "r" (r1)
diff --git a/arch/arm/mach-mxs/Kconfig b/arch/arm/mach-mxs/Kconfig
index c57f9964a713..07d5383d68ee 100644
--- a/arch/arm/mach-mxs/Kconfig
+++ b/arch/arm/mach-mxs/Kconfig
@@ -9,11 +9,13 @@ config SOC_IMX23
bool
select CPU_ARM926T
select HAVE_PWM
+ select PINCTRL_IMX23
config SOC_IMX28
bool
select CPU_ARM926T
select HAVE_PWM
+ select PINCTRL_IMX28
comment "MXS platforms:"
diff --git a/arch/arm/mach-mxs/include/mach/common.h b/arch/arm/mach-mxs/include/mach/common.h
index c50c3ea28a9d..8d88399b73ef 100644
--- a/arch/arm/mach-mxs/include/mach/common.h
+++ b/arch/arm/mach-mxs/include/mach/common.h
@@ -19,11 +19,13 @@ extern void mxs_timer_init(struct clk *, int);
extern void mxs_restart(char, const char *);
extern int mxs_saif_clkmux_select(unsigned int clkmux);
+extern void mx23_soc_init(void);
extern int mx23_register_gpios(void);
extern int mx23_clocks_init(void);
extern void mx23_map_io(void);
extern void mx23_init_irq(void);
+extern void mx28_soc_init(void);
extern int mx28_register_gpios(void);
extern int mx28_clocks_init(void);
extern void mx28_map_io(void);
diff --git a/arch/arm/mach-mxs/mach-apx4devkit.c b/arch/arm/mach-mxs/mach-apx4devkit.c
index 48a7fab571a6..5e90b9dcdef8 100644
--- a/arch/arm/mach-mxs/mach-apx4devkit.c
+++ b/arch/arm/mach-mxs/mach-apx4devkit.c
@@ -207,6 +207,8 @@ static int apx4devkit_phy_fixup(struct phy_device *phy)
static void __init apx4devkit_init(void)
{
+ mx28_soc_init();
+
mxs_iomux_setup_multiple_pads(apx4devkit_pads,
ARRAY_SIZE(apx4devkit_pads));
diff --git a/arch/arm/mach-mxs/mach-m28evk.c b/arch/arm/mach-mxs/mach-m28evk.c
index 06d79963611c..4c00c879b893 100644
--- a/arch/arm/mach-mxs/mach-m28evk.c
+++ b/arch/arm/mach-mxs/mach-m28evk.c
@@ -319,6 +319,8 @@ static struct mxs_mmc_platform_data m28evk_mmc_pdata[] __initdata = {
static void __init m28evk_init(void)
{
+ mx28_soc_init();
+
mxs_iomux_setup_multiple_pads(m28evk_pads, ARRAY_SIZE(m28evk_pads));
mx28_add_duart();
diff --git a/arch/arm/mach-mxs/mach-mx23evk.c b/arch/arm/mach-mxs/mach-mx23evk.c
index 5ea1c57d2606..e7272a41939d 100644
--- a/arch/arm/mach-mxs/mach-mx23evk.c
+++ b/arch/arm/mach-mxs/mach-mx23evk.c
@@ -141,6 +141,8 @@ static void __init mx23evk_init(void)
{
int ret;
+ mx23_soc_init();
+
mxs_iomux_setup_multiple_pads(mx23evk_pads, ARRAY_SIZE(mx23evk_pads));
mx23_add_duart();
diff --git a/arch/arm/mach-mxs/mach-mx28evk.c b/arch/arm/mach-mxs/mach-mx28evk.c
index e386c142f93c..da4610ebe9e6 100644
--- a/arch/arm/mach-mxs/mach-mx28evk.c
+++ b/arch/arm/mach-mxs/mach-mx28evk.c
@@ -413,6 +413,8 @@ static void __init mx28evk_init(void)
{
int ret;
+ mx28_soc_init();
+
mxs_iomux_setup_multiple_pads(mx28evk_pads, ARRAY_SIZE(mx28evk_pads));
mx28_add_duart();
diff --git a/arch/arm/mach-mxs/mach-stmp378x_devb.c b/arch/arm/mach-mxs/mach-stmp378x_devb.c
index a626c07b8713..6548965e4a76 100644
--- a/arch/arm/mach-mxs/mach-stmp378x_devb.c
+++ b/arch/arm/mach-mxs/mach-stmp378x_devb.c
@@ -85,6 +85,8 @@ static void __init stmp378x_dvb_init(void)
{
int ret;
+ mx23_soc_init();
+
mxs_iomux_setup_multiple_pads(stmp378x_dvb_pads,
ARRAY_SIZE(stmp378x_dvb_pads));
diff --git a/arch/arm/mach-mxs/mach-tx28.c b/arch/arm/mach-mxs/mach-tx28.c
index 2c0862e655ee..8837029de1a4 100644
--- a/arch/arm/mach-mxs/mach-tx28.c
+++ b/arch/arm/mach-mxs/mach-tx28.c
@@ -146,6 +146,8 @@ static struct mxs_mmc_platform_data tx28_mmc0_pdata __initdata = {
static void __init tx28_stk5v3_init(void)
{
+ mx28_soc_init();
+
mxs_iomux_setup_multiple_pads(tx28_stk5v3_pads,
ARRAY_SIZE(tx28_stk5v3_pads));
diff --git a/arch/arm/mach-mxs/mm.c b/arch/arm/mach-mxs/mm.c
index 50af5ceebf6d..67a384edcf5b 100644
--- a/arch/arm/mach-mxs/mm.c
+++ b/arch/arm/mach-mxs/mm.c
@@ -13,6 +13,7 @@
#include <linux/mm.h>
#include <linux/init.h>
+#include <linux/pinctrl/machine.h>
#include <asm/mach/map.h>
@@ -61,3 +62,13 @@ void __init mx28_init_irq(void)
{
icoll_init_irq();
}
+
+void __init mx23_soc_init(void)
+{
+ pinctrl_provide_dummies();
+}
+
+void __init mx28_soc_init(void)
+{
+ pinctrl_provide_dummies();
+}
diff --git a/arch/arm/mach-nomadik/Kconfig b/arch/arm/mach-nomadik/Kconfig
index 3c5e0f522e9c..365879b47c0e 100644
--- a/arch/arm/mach-nomadik/Kconfig
+++ b/arch/arm/mach-nomadik/Kconfig
@@ -15,6 +15,7 @@ config NOMADIK_8815
config I2C_BITBANG_8815NHK
tristate "Driver for bit-bang busses found on the 8815 NHK"
depends on I2C && MACH_NOMADIK_8815NHK
+ depends on PINCTRL_NOMADIK
select I2C_ALGOBIT
default y
diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig
index dfab466ebd1d..cba3f7191cfc 100644
--- a/arch/arm/mach-omap1/Kconfig
+++ b/arch/arm/mach-omap1/Kconfig
@@ -132,6 +132,7 @@ config MACH_OMAP_PALMTT
config MACH_SX1
bool "Siemens SX1"
+ select I2C
depends on ARCH_OMAP1 && ARCH_OMAP15XX
help
Support for the Siemens SX1 phone. To boot the kernel,
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
index 9923f92b5450..398e9e53e189 100644
--- a/arch/arm/mach-omap1/Makefile
+++ b/arch/arm/mach-omap1/Makefile
@@ -12,6 +12,9 @@ endif
obj-$(CONFIG_OMAP_32K_TIMER) += timer32k.o
+# OCPI interconnect support for 1710, 1610 and 5912
+obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
+
# Power Management
obj-$(CONFIG_PM) += pm.o sleep.o
@@ -28,13 +31,15 @@ usb-fs-$(CONFIG_USB) := usb.o
obj-y += $(usb-fs-m) $(usb-fs-y)
# Specific board support
-obj-$(CONFIG_MACH_OMAP_H2) += board-h2.o board-h2-mmc.o
+obj-$(CONFIG_MACH_OMAP_H2) += board-h2.o board-h2-mmc.o \
+ board-nand.o
obj-$(CONFIG_MACH_OMAP_INNOVATOR) += board-innovator.o
obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o
-obj-$(CONFIG_MACH_OMAP_PERSEUS2) += board-perseus2.o
-obj-$(CONFIG_MACH_OMAP_FSAMPLE) += board-fsample.o
+obj-$(CONFIG_MACH_OMAP_PERSEUS2) += board-perseus2.o board-nand.o
+obj-$(CONFIG_MACH_OMAP_FSAMPLE) += board-fsample.o board-nand.o
obj-$(CONFIG_MACH_OMAP_OSK) += board-osk.o
-obj-$(CONFIG_MACH_OMAP_H3) += board-h3.o board-h3-mmc.o
+obj-$(CONFIG_MACH_OMAP_H3) += board-h3.o board-h3-mmc.o \
+ board-nand.o
obj-$(CONFIG_MACH_VOICEBLUE) += board-voiceblue.o
obj-$(CONFIG_MACH_OMAP_PALMTE) += board-palmte.o
obj-$(CONFIG_MACH_OMAP_PALMZ71) += board-palmz71.o
diff --git a/arch/arm/mach-omap1/ams-delta-fiq.c b/arch/arm/mach-omap1/ams-delta-fiq.c
index cfd98b186fcc..68e8e5654c0a 100644
--- a/arch/arm/mach-omap1/ams-delta-fiq.c
+++ b/arch/arm/mach-omap1/ams-delta-fiq.c
@@ -102,7 +102,7 @@ void __init ams_delta_init_fiq(void)
}
retval = request_irq(INT_DEFERRED_FIQ, deferred_fiq,
- IRQ_TYPE_EDGE_RISING, "deferred_fiq", 0);
+ IRQ_TYPE_EDGE_RISING, "deferred_fiq", NULL);
if (retval < 0) {
pr_err("Failed to get deferred_fiq IRQ, ret=%d\n", retval);
release_fiq(&fh);
diff --git a/arch/arm/mach-omap1/board-fsample.c b/arch/arm/mach-omap1/board-fsample.c
index 80bd43c7f4ec..4a4afb371022 100644
--- a/arch/arm/mach-omap1/board-fsample.c
+++ b/arch/arm/mach-omap1/board-fsample.c
@@ -185,20 +185,6 @@ static struct platform_device nor_device = {
.resource = &nor_resource,
};
-static void nand_cmd_ctl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
-{
- struct nand_chip *this = mtd->priv;
- unsigned long mask;
-
- if (cmd == NAND_CMD_NONE)
- return;
-
- mask = (ctrl & NAND_CLE) ? 0x02 : 0;
- if (ctrl & NAND_ALE)
- mask |= 0x04;
- writeb(cmd, (unsigned long)this->IO_ADDR_W | mask);
-}
-
#define FSAMPLE_NAND_RB_GPIO_PIN 62
static int nand_dev_ready(struct mtd_info *mtd)
@@ -216,7 +202,7 @@ static struct platform_nand_data nand_data = {
.part_probe_types = part_probes,
},
.ctrl = {
- .cmd_ctrl = nand_cmd_ctl,
+ .cmd_ctrl = omap1_nand_cmd_ctl,
.dev_ready = nand_dev_ready,
},
};
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index 553a2e535764..057ec13f0649 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -179,20 +179,6 @@ static struct mtd_partition h2_nand_partitions[] = {
},
};
-static void h2_nand_cmd_ctl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
-{
- struct nand_chip *this = mtd->priv;
- unsigned long mask;
-
- if (cmd == NAND_CMD_NONE)
- return;
-
- mask = (ctrl & NAND_CLE) ? 0x02 : 0;
- if (ctrl & NAND_ALE)
- mask |= 0x04;
- writeb(cmd, (unsigned long)this->IO_ADDR_W | mask);
-}
-
#define H2_NAND_RB_GPIO_PIN 62
static int h2_nand_dev_ready(struct mtd_info *mtd)
@@ -212,9 +198,8 @@ static struct platform_nand_data h2_nand_platdata = {
.part_probe_types = h2_part_probes,
},
.ctrl = {
- .cmd_ctrl = h2_nand_cmd_ctl,
+ .cmd_ctrl = omap1_nand_cmd_ctl,
.dev_ready = h2_nand_dev_ready,
-
},
};
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index 4c19f4c06851..f6ddf8759657 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -181,20 +181,6 @@ static struct mtd_partition nand_partitions[] = {
},
};
-static void nand_cmd_ctl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
-{
- struct nand_chip *this = mtd->priv;
- unsigned long mask;
-
- if (cmd == NAND_CMD_NONE)
- return;
-
- mask = (ctrl & NAND_CLE) ? 0x02 : 0;
- if (ctrl & NAND_ALE)
- mask |= 0x04;
- writeb(cmd, (unsigned long)this->IO_ADDR_W | mask);
-}
-
#define H3_NAND_RB_GPIO_PIN 10
static int nand_dev_ready(struct mtd_info *mtd)
@@ -214,7 +200,7 @@ static struct platform_nand_data nand_platdata = {
.part_probe_types = part_probes,
},
.ctrl = {
- .cmd_ctrl = nand_cmd_ctl,
+ .cmd_ctrl = omap1_nand_cmd_ctl,
.dev_ready = nand_dev_ready,
},
diff --git a/arch/arm/mach-omap1/board-nand.c b/arch/arm/mach-omap1/board-nand.c
new file mode 100644
index 000000000000..4d0835327d20
--- /dev/null
+++ b/arch/arm/mach-omap1/board-nand.c
@@ -0,0 +1,37 @@
+/*
+ * linux/arch/arm/mach-omap1/board-nand.c
+ *
+ * Common OMAP1 board NAND code
+ *
+ * Copyright (C) 2004, 2012 Texas Instruments, Inc.
+ * Copyright (C) 2002 MontaVista Software, Inc.
+ * Copyright (C) 2001 RidgeRun, Inc.
+ * Author: RidgeRun, Inc.
+ * Greg Lonnon (glonnon@ridgerun.com) or info@ridgerun.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/kernel.h>
+#include <linux/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+
+#include "common.h"
+
+void omap1_nand_cmd_ctl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+ struct nand_chip *this = mtd->priv;
+ unsigned long mask;
+
+ if (cmd == NAND_CMD_NONE)
+ return;
+
+ mask = (ctrl & NAND_CLE) ? 0x02 : 0;
+ if (ctrl & NAND_ALE)
+ mask |= 0x04;
+
+ writeb(cmd, this->IO_ADDR_W + mask);
+}
+
diff --git a/arch/arm/mach-omap1/board-palmz71.c b/arch/arm/mach-omap1/board-palmz71.c
index a2c5abcd7c84..61ed4f0247ce 100644
--- a/arch/arm/mach-omap1/board-palmz71.c
+++ b/arch/arm/mach-omap1/board-palmz71.c
@@ -289,10 +289,10 @@ palmz71_gpio_setup(int early)
gpio_direction_input(PALMZ71_USBDETECT_GPIO);
if (request_irq(gpio_to_irq(PALMZ71_USBDETECT_GPIO),
palmz71_powercable, IRQF_SAMPLE_RANDOM,
- "palmz71-cable", 0))
+ "palmz71-cable", NULL))
printk(KERN_ERR
"IRQ request for power cable failed!\n");
- palmz71_powercable(gpio_to_irq(PALMZ71_USBDETECT_GPIO), 0);
+ palmz71_powercable(gpio_to_irq(PALMZ71_USBDETECT_GPIO), NULL);
}
}
diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c
index 76d4ee05a814..a2c88890e767 100644
--- a/arch/arm/mach-omap1/board-perseus2.c
+++ b/arch/arm/mach-omap1/board-perseus2.c
@@ -143,20 +143,6 @@ static struct platform_device nor_device = {
.resource = &nor_resource,
};
-static void nand_cmd_ctl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
-{
- struct nand_chip *this = mtd->priv;
- unsigned long mask;
-
- if (cmd == NAND_CMD_NONE)
- return;
-
- mask = (ctrl & NAND_CLE) ? 0x02 : 0;
- if (ctrl & NAND_ALE)
- mask |= 0x04;
- writeb(cmd, (unsigned long)this->IO_ADDR_W | mask);
-}
-
#define P2_NAND_RB_GPIO_PIN 62
static int nand_dev_ready(struct mtd_info *mtd)
@@ -174,7 +160,7 @@ static struct platform_nand_data nand_data = {
.part_probe_types = part_probes,
},
.ctrl = {
- .cmd_ctrl = nand_cmd_ctl,
+ .cmd_ctrl = omap1_nand_cmd_ctl,
.dev_ready = nand_dev_ready,
},
};
diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c
index 67382ddd8c83..a9ee06b6cb42 100644
--- a/arch/arm/mach-omap1/clock.c
+++ b/arch/arm/mach-omap1/clock.c
@@ -194,9 +194,8 @@ int omap1_select_table_rate(struct clk *clk, unsigned long rate)
{
/* Find the highest supported frequency <= rate and switch to it */
struct mpu_rate * ptr;
- unsigned long dpll1_rate, ref_rate;
+ unsigned long ref_rate;
- dpll1_rate = ck_dpll1_p->rate;
ref_rate = ck_ref_p->rate;
for (ptr = omap1_rate_table; ptr->rate; ptr++) {
diff --git a/arch/arm/mach-omap1/common.h b/arch/arm/mach-omap1/common.h
index af658ad338ec..bb7779b57795 100644
--- a/arch/arm/mach-omap1/common.h
+++ b/arch/arm/mach-omap1/common.h
@@ -27,6 +27,7 @@
#define __ARCH_ARM_MACH_OMAP1_COMMON_H
#include <plat/common.h>
+#include <linux/mtd/mtd.h>
#if defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP850)
void omap7xx_map_io(void);
@@ -56,8 +57,20 @@ void omap1_init_early(void);
void omap1_init_irq(void);
void omap1_restart(char, const char *);
+extern void __init omap_check_revision(void);
+
+extern void omap1_nand_cmd_ctl(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl);
+
extern struct sys_timer omap1_timer;
extern bool omap_32k_timer_init(void);
-extern void __init omap_init_consistent_dma_size(void);
+
+extern u32 omap_irq_flags;
+
+#ifdef CONFIG_ARCH_OMAP16XX
+extern int ocpi_enable(void);
+#else
+static inline int ocpi_enable(void) { return 0; }
+#endif
#endif /* __ARCH_ARM_MACH_OMAP1_COMMON_H */
diff --git a/arch/arm/mach-omap1/fpga.c b/arch/arm/mach-omap1/fpga.c
index 76c67b3f9f61..29ec50fc688d 100644
--- a/arch/arm/mach-omap1/fpga.c
+++ b/arch/arm/mach-omap1/fpga.c
@@ -87,7 +87,7 @@ static void fpga_mask_ack_irq(struct irq_data *d)
fpga_ack_irq(d);
}
-void innovator_fpga_IRQ_demux(unsigned int irq, struct irq_desc *desc)
+static void innovator_fpga_IRQ_demux(unsigned int irq, struct irq_desc *desc)
{
u32 stat;
int fpga_irq;
diff --git a/arch/arm/mach-omap1/gpio15xx.c b/arch/arm/mach-omap1/gpio15xx.c
index 634903ef8292..ebef15e5e7b7 100644
--- a/arch/arm/mach-omap1/gpio15xx.c
+++ b/arch/arm/mach-omap1/gpio15xx.c
@@ -46,7 +46,6 @@ static struct omap_gpio_reg_offs omap15xx_mpuio_regs = {
};
static struct __initdata omap_gpio_platform_data omap15xx_mpu_gpio_config = {
- .virtual_irq_start = IH_MPUIO_BASE,
.is_mpuio = true,
.bank_width = 16,
.bank_stride = 1,
@@ -89,7 +88,6 @@ static struct omap_gpio_reg_offs omap15xx_gpio_regs = {
};
static struct __initdata omap_gpio_platform_data omap15xx_gpio_config = {
- .virtual_irq_start = IH_GPIO_BASE,
.bank_width = 16,
.regs = &omap15xx_gpio_regs,
};
diff --git a/arch/arm/mach-omap1/gpio16xx.c b/arch/arm/mach-omap1/gpio16xx.c
index 1fb3b9ad496e..2a48cd2e1754 100644
--- a/arch/arm/mach-omap1/gpio16xx.c
+++ b/arch/arm/mach-omap1/gpio16xx.c
@@ -52,7 +52,6 @@ static struct omap_gpio_reg_offs omap16xx_mpuio_regs = {
};
static struct __initdata omap_gpio_platform_data omap16xx_mpu_gpio_config = {
- .virtual_irq_start = IH_MPUIO_BASE,
.is_mpuio = true,
.bank_width = 16,
.bank_stride = 1,
@@ -99,7 +98,6 @@ static struct omap_gpio_reg_offs omap16xx_gpio_regs = {
};
static struct __initdata omap_gpio_platform_data omap16xx_gpio1_config = {
- .virtual_irq_start = IH_GPIO_BASE,
.bank_width = 16,
.regs = &omap16xx_gpio_regs,
};
@@ -128,7 +126,6 @@ static struct __initdata resource omap16xx_gpio2_resources[] = {
};
static struct __initdata omap_gpio_platform_data omap16xx_gpio2_config = {
- .virtual_irq_start = IH_GPIO_BASE + 16,
.bank_width = 16,
.regs = &omap16xx_gpio_regs,
};
@@ -157,7 +154,6 @@ static struct __initdata resource omap16xx_gpio3_resources[] = {
};
static struct __initdata omap_gpio_platform_data omap16xx_gpio3_config = {
- .virtual_irq_start = IH_GPIO_BASE + 32,
.bank_width = 16,
.regs = &omap16xx_gpio_regs,
};
@@ -186,7 +182,6 @@ static struct __initdata resource omap16xx_gpio4_resources[] = {
};
static struct __initdata omap_gpio_platform_data omap16xx_gpio4_config = {
- .virtual_irq_start = IH_GPIO_BASE + 48,
.bank_width = 16,
.regs = &omap16xx_gpio_regs,
};
diff --git a/arch/arm/mach-omap1/gpio7xx.c b/arch/arm/mach-omap1/gpio7xx.c
index 4771d6b68b96..acf12b73eace 100644
--- a/arch/arm/mach-omap1/gpio7xx.c
+++ b/arch/arm/mach-omap1/gpio7xx.c
@@ -51,7 +51,6 @@ static struct omap_gpio_reg_offs omap7xx_mpuio_regs = {
};
static struct __initdata omap_gpio_platform_data omap7xx_mpu_gpio_config = {
- .virtual_irq_start = IH_MPUIO_BASE,
.is_mpuio = true,
.bank_width = 16,
.bank_stride = 2,
@@ -93,7 +92,6 @@ static struct omap_gpio_reg_offs omap7xx_gpio_regs = {
};
static struct __initdata omap_gpio_platform_data omap7xx_gpio1_config = {
- .virtual_irq_start = IH_GPIO_BASE,
.bank_width = 32,
.regs = &omap7xx_gpio_regs,
};
@@ -122,7 +120,6 @@ static struct __initdata resource omap7xx_gpio2_resources[] = {
};
static struct __initdata omap_gpio_platform_data omap7xx_gpio2_config = {
- .virtual_irq_start = IH_GPIO_BASE + 32,
.bank_width = 32,
.regs = &omap7xx_gpio_regs,
};
@@ -151,7 +148,6 @@ static struct __initdata resource omap7xx_gpio3_resources[] = {
};
static struct __initdata omap_gpio_platform_data omap7xx_gpio3_config = {
- .virtual_irq_start = IH_GPIO_BASE + 64,
.bank_width = 32,
.regs = &omap7xx_gpio_regs,
};
@@ -180,7 +176,6 @@ static struct __initdata resource omap7xx_gpio4_resources[] = {
};
static struct __initdata omap_gpio_platform_data omap7xx_gpio4_config = {
- .virtual_irq_start = IH_GPIO_BASE + 96,
.bank_width = 32,
.regs = &omap7xx_gpio_regs,
};
@@ -209,7 +204,6 @@ static struct __initdata resource omap7xx_gpio5_resources[] = {
};
static struct __initdata omap_gpio_platform_data omap7xx_gpio5_config = {
- .virtual_irq_start = IH_GPIO_BASE + 128,
.bank_width = 32,
.regs = &omap7xx_gpio_regs,
};
@@ -238,7 +232,6 @@ static struct __initdata resource omap7xx_gpio6_resources[] = {
};
static struct __initdata omap_gpio_platform_data omap7xx_gpio6_config = {
- .virtual_irq_start = IH_GPIO_BASE + 160,
.bank_width = 32,
.regs = &omap7xx_gpio_regs,
};
diff --git a/arch/arm/mach-omap1/id.c b/arch/arm/mach-omap1/id.c
index 2b28e1da14b0..a1b846aacdaf 100644
--- a/arch/arm/mach-omap1/id.c
+++ b/arch/arm/mach-omap1/id.c
@@ -21,6 +21,8 @@
#include <mach/hardware.h>
+#include "common.h"
+
#define OMAP_DIE_ID_0 0xfffe1800
#define OMAP_DIE_ID_1 0xfffe1804
#define OMAP_PRODUCTION_ID_0 0xfffe2000
diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c
index d969a7203d14..71ce017bf5d8 100644
--- a/arch/arm/mach-omap1/io.c
+++ b/arch/arm/mach-omap1/io.c
@@ -18,13 +18,12 @@
#include <plat/mux.h>
#include <plat/tc.h>
+#include <plat/dma.h>
#include "iomap.h"
#include "common.h"
#include "clock.h"
-extern void omap_check_revision(void);
-
/*
* The machine specific code may provide the extra mapping besides the
* default mapping provided here.
diff --git a/arch/arm/mach-omap1/irq.c b/arch/arm/mach-omap1/irq.c
index 4448114fab72..6995fb6a3345 100644
--- a/arch/arm/mach-omap1/irq.c
+++ b/arch/arm/mach-omap1/irq.c
@@ -49,6 +49,8 @@
#include <mach/hardware.h>
+#include "common.h"
+
#define IRQ_BANK(irq) ((irq) >> 5)
#define IRQ_BIT(irq) ((irq) & 0x1f)
diff --git a/arch/arm/mach-omap1/lcd_dma.c b/arch/arm/mach-omap1/lcd_dma.c
index 86ace9aaa663..5769c71815b2 100644
--- a/arch/arm/mach-omap1/lcd_dma.c
+++ b/arch/arm/mach-omap1/lcd_dma.c
@@ -57,7 +57,7 @@ static struct lcd_dma_info {
void *cb_data;
int active;
- unsigned long addr, size;
+ unsigned long addr;
int rotate, data_type, xres, yres;
int vxres;
int mirror;
@@ -77,11 +77,6 @@ void omap_set_lcd_dma_b1(unsigned long addr, u16 fb_xres, u16 fb_yres,
}
EXPORT_SYMBOL(omap_set_lcd_dma_b1);
-void omap_set_lcd_dma_src_port(int port)
-{
- lcd_dma.src_port = port;
-}
-
void omap_set_lcd_dma_ext_controller(int external)
{
lcd_dma.ext_ctrl = external;
diff --git a/arch/arm/plat-omap/ocpi.c b/arch/arm/mach-omap1/ocpi.c
index ebe0c73c8901..238170cab5b7 100644
--- a/arch/arm/plat-omap/ocpi.c
+++ b/arch/arm/mach-omap1/ocpi.c
@@ -4,6 +4,7 @@
* Minimal OCP bus support for omap16xx
*
* Copyright (C) 2003 - 2005 Nokia Corporation
+ * Copyright (C) 2012 Texas Instruments, Inc.
* Written by Tony Lindgren <tony@atomide.com>
*
* Modified for clock framework by Paul Mundt <paul.mundt@nokia.com>.
@@ -35,6 +36,8 @@
#include <mach/hardware.h>
+#include "common.h"
+
#define OCPI_BASE 0xfffec320
#define OCPI_FAULT (OCPI_BASE + 0x00)
#define OCPI_CMD_FAULT (OCPI_BASE + 0x04)
@@ -64,7 +67,7 @@ int ocpi_enable(void)
/* Enable access for OHCI in OCPI */
val = omap_readl(OCPI_PROT);
val &= ~0xff;
- //val &= (1 << 0); /* Allow access only to EMIFS */
+ /* val &= (1 << 0); Allow access only to EMIFS */
omap_writel(val, OCPI_PROT);
val = omap_readl(OCPI_SEC);
@@ -86,7 +89,7 @@ static int __init omap_ocpi_init(void)
clk_enable(ocpi_ck);
ocpi_enable();
- printk("OMAP OCPI interconnect driver loaded\n");
+ pr_info("OMAP OCPI interconnect driver loaded\n");
return 0;
}
diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c
index f66c32912b22..b2560d32b3a0 100644
--- a/arch/arm/mach-omap1/pm.c
+++ b/arch/arm/mach-omap1/pm.c
@@ -569,11 +569,10 @@ static int omap_pm_read_proc(
static void omap_pm_init_proc(void)
{
- struct proc_dir_entry *entry;
-
- entry = create_proc_read_entry("driver/omap_pm",
- S_IWUSR | S_IRUGO, NULL,
- omap_pm_read_proc, NULL);
+ /* XXX Appears to leak memory */
+ create_proc_read_entry("driver/omap_pm",
+ S_IWUSR | S_IRUGO, NULL,
+ omap_pm_read_proc, NULL);
}
#endif /* DEBUG && CONFIG_PROC_FS */
diff --git a/arch/arm/mach-omap1/reset.c b/arch/arm/mach-omap1/reset.c
index f255b153b863..b17709103866 100644
--- a/arch/arm/mach-omap1/reset.c
+++ b/arch/arm/mach-omap1/reset.c
@@ -8,6 +8,8 @@
#include <mach/hardware.h>
+#include "common.h"
+
void omap1_restart(char mode, const char *cmd)
{
/*
diff --git a/arch/arm/mach-omap1/timer.c b/arch/arm/mach-omap1/timer.c
index fb202af01d0d..64c65bcb2d67 100644
--- a/arch/arm/mach-omap1/timer.c
+++ b/arch/arm/mach-omap1/timer.c
@@ -54,8 +54,7 @@ static int omap1_dm_timer_set_src(struct platform_device *pdev,
return 0;
}
-
-int __init omap1_dm_timer_init(void)
+static int __init omap1_dm_timer_init(void)
{
int i;
int ret;
diff --git a/arch/arm/mach-omap1/usb.c b/arch/arm/mach-omap1/usb.c
index 19de03b074e3..e61afd922766 100644
--- a/arch/arm/mach-omap1/usb.c
+++ b/arch/arm/mach-omap1/usb.c
@@ -29,6 +29,8 @@
#include <plat/mux.h>
#include <plat/usb.h>
+#include "common.h"
+
/* These routines should handle the standard chip-specific modes
* for usb0/1/2 ports, covering basic mux and transceiver setup.
*
@@ -138,6 +140,7 @@ static inline void ohci_device_init(struct omap_usb_config *pdata)
if (cpu_is_omap7xx())
ohci_resources[1].start = INT_7XX_USB_HHC_1;
pdata->ohci_device = &ohci_device;
+ pdata->ocpi_enable = &ocpi_enable;
}
#else
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 8141b76283a6..964ee67a3b77 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -17,6 +17,7 @@ config ARCH_OMAP2PLUS_TYPICAL
select MENELAUS if ARCH_OMAP2
select TWL4030_CORE if ARCH_OMAP3 || ARCH_OMAP4
select TWL4030_POWER if ARCH_OMAP3 || ARCH_OMAP4
+ select HIGHMEM
help
Compile a kernel suitable for booting most boards
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 49f92bc1c311..385c083d24b2 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -4,7 +4,7 @@
# Common support
obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer.o pm.o \
- common.o gpio.o dma.o wd_timer.o display.o i2c.o
+ common.o gpio.o dma.o wd_timer.o display.o i2c.o hdq1w.o
omap-2-3-common = irq.o sdrc.o
hwmod-common = omap_hwmod.o \
@@ -118,16 +118,18 @@ obj-$(CONFIG_ARCH_OMAP4) += $(powerdomain-common) \
powerdomains44xx_data.o
# PRCM clockdomain control
-obj-$(CONFIG_ARCH_OMAP2) += clockdomain.o \
+clockdomain-common += clockdomain.o \
+ clockdomains_common_data.o
+obj-$(CONFIG_ARCH_OMAP2) += $(clockdomain-common) \
clockdomain2xxx_3xxx.o \
clockdomains2xxx_3xxx_data.o
obj-$(CONFIG_SOC_OMAP2420) += clockdomains2420_data.o
obj-$(CONFIG_SOC_OMAP2430) += clockdomains2430_data.o
-obj-$(CONFIG_ARCH_OMAP3) += clockdomain.o \
+obj-$(CONFIG_ARCH_OMAP3) += $(clockdomain-common) \
clockdomain2xxx_3xxx.o \
clockdomains2xxx_3xxx_data.o \
clockdomains3xxx_data.o
-obj-$(CONFIG_ARCH_OMAP4) += clockdomain.o \
+obj-$(CONFIG_ARCH_OMAP4) += $(clockdomain-common) \
clockdomain44xx.o \
clockdomains44xx_data.o
@@ -187,6 +189,9 @@ ifneq ($(CONFIG_TIDSPBRIDGE),)
obj-y += dsp.o
endif
+# OMAP2420 MSDI controller integration support ("MMC")
+obj-$(CONFIG_SOC_OMAP2420) += msdi.o
+
# Specific board support
obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o
obj-$(CONFIG_MACH_OMAP_H4) += board-h4.o
diff --git a/arch/arm/mach-omap2/am35xx-emac.c b/arch/arm/mach-omap2/am35xx-emac.c
index 1f97e7475206..447682c4e11c 100644
--- a/arch/arm/mach-omap2/am35xx-emac.c
+++ b/arch/arm/mach-omap2/am35xx-emac.c
@@ -39,26 +39,23 @@ static struct platform_device am35xx_emac_mdio_device = {
static void am35xx_enable_emac_int(void)
{
- u32 regval;
-
- regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
- regval = (regval | AM35XX_CPGMAC_C0_RX_PULSE_CLR |
- AM35XX_CPGMAC_C0_TX_PULSE_CLR |
- AM35XX_CPGMAC_C0_MISC_PULSE_CLR |
- AM35XX_CPGMAC_C0_RX_THRESH_CLR);
- omap_ctrl_writel(regval, AM35XX_CONTROL_LVL_INTR_CLEAR);
- regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
+ u32 v;
+
+ v = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
+ v |= (AM35XX_CPGMAC_C0_RX_PULSE_CLR | AM35XX_CPGMAC_C0_TX_PULSE_CLR |
+ AM35XX_CPGMAC_C0_MISC_PULSE_CLR | AM35XX_CPGMAC_C0_RX_THRESH_CLR);
+ omap_ctrl_writel(v, AM35XX_CONTROL_LVL_INTR_CLEAR);
+ omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR); /* OCP barrier */
}
static void am35xx_disable_emac_int(void)
{
- u32 regval;
+ u32 v;
- regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
- regval = (regval | AM35XX_CPGMAC_C0_RX_PULSE_CLR |
- AM35XX_CPGMAC_C0_TX_PULSE_CLR);
- omap_ctrl_writel(regval, AM35XX_CONTROL_LVL_INTR_CLEAR);
- regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
+ v = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
+ v |= (AM35XX_CPGMAC_C0_RX_PULSE_CLR | AM35XX_CPGMAC_C0_TX_PULSE_CLR);
+ omap_ctrl_writel(v, AM35XX_CONTROL_LVL_INTR_CLEAR);
+ omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR); /* OCP barrier */
}
static struct emac_platform_data am35xx_emac_pdata = {
@@ -92,7 +89,7 @@ static struct platform_device am35xx_emac_device = {
void __init am35xx_emac_init(unsigned long mdio_bus_freq, u8 rmii_en)
{
- unsigned int regval;
+ u32 v;
int err;
am35xx_emac_pdata.rmii_en = rmii_en;
@@ -110,8 +107,8 @@ void __init am35xx_emac_init(unsigned long mdio_bus_freq, u8 rmii_en)
return;
}
- regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
- regval = regval & (~(AM35XX_CPGMACSS_SW_RST));
- omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET);
- regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
+ v = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
+ v &= ~AM35XX_CPGMACSS_SW_RST;
+ omap_ctrl_writel(v, AM35XX_CONTROL_IP_SW_RESET);
+ omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET); /* OCP barrier */
}
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index da75f239873e..37abb0d49b51 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -37,7 +37,7 @@
#include <plat/dma.h>
#include <plat/gpmc.h>
#include <video/omapdss.h>
-#include <video/omap-panel-dvi.h>
+#include <video/omap-panel-tfp410.h>
#include <plat/gpmc-smc91x.h>
@@ -113,9 +113,6 @@ static struct gpio sdp3430_dss_gpios[] __initdata = {
{SDP3430_LCD_PANEL_BACKLIGHT_GPIO, GPIOF_OUT_INIT_LOW, "LCD Backlight"},
};
-static int lcd_enabled;
-static int dvi_enabled;
-
static void __init sdp3430_display_init(void)
{
int r;
@@ -129,44 +126,18 @@ static void __init sdp3430_display_init(void)
static int sdp3430_panel_enable_lcd(struct omap_dss_device *dssdev)
{
- if (dvi_enabled) {
- printk(KERN_ERR "cannot enable LCD, DVI is enabled\n");
- return -EINVAL;
- }
-
gpio_direction_output(SDP3430_LCD_PANEL_ENABLE_GPIO, 1);
gpio_direction_output(SDP3430_LCD_PANEL_BACKLIGHT_GPIO, 1);
- lcd_enabled = 1;
-
return 0;
}
static void sdp3430_panel_disable_lcd(struct omap_dss_device *dssdev)
{
- lcd_enabled = 0;
-
gpio_direction_output(SDP3430_LCD_PANEL_ENABLE_GPIO, 0);
gpio_direction_output(SDP3430_LCD_PANEL_BACKLIGHT_GPIO, 0);
}
-static int sdp3430_panel_enable_dvi(struct omap_dss_device *dssdev)
-{
- if (lcd_enabled) {
- printk(KERN_ERR "cannot enable DVI, LCD is enabled\n");
- return -EINVAL;
- }
-
- dvi_enabled = 1;
-
- return 0;
-}
-
-static void sdp3430_panel_disable_dvi(struct omap_dss_device *dssdev)
-{
- dvi_enabled = 0;
-}
-
static int sdp3430_panel_enable_tv(struct omap_dss_device *dssdev)
{
return 0;
@@ -186,15 +157,14 @@ static struct omap_dss_device sdp3430_lcd_device = {
.platform_disable = sdp3430_panel_disable_lcd,
};
-static struct panel_dvi_platform_data dvi_panel = {
- .platform_enable = sdp3430_panel_enable_dvi,
- .platform_disable = sdp3430_panel_disable_dvi,
+static struct tfp410_platform_data dvi_panel = {
+ .power_down_gpio = -1,
};
static struct omap_dss_device sdp3430_dvi_device = {
.name = "dvi",
.type = OMAP_DISPLAY_TYPE_DPI,
- .driver_name = "dvi",
+ .driver_name = "tfp410",
.data = &dvi_panel,
.phy.dpi.data_lines = 24,
};
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
index 130ab00c09a2..94af6cde2e36 100644
--- a/arch/arm/mach-omap2/board-4430sdp.c
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -384,6 +384,11 @@ static struct platform_device sdp4430_dmic_codec = {
.id = -1,
};
+static struct platform_device sdp4430_hdmi_audio_codec = {
+ .name = "hdmi-audio-codec",
+ .id = -1,
+};
+
static struct omap_abe_twl6040_data sdp4430_abe_audio_data = {
.card_name = "SDP4430",
.has_hs = ABE_TWL6040_LEFT | ABE_TWL6040_RIGHT,
@@ -418,6 +423,7 @@ static struct platform_device *sdp4430_devices[] __initdata = {
&sdp4430_vbat,
&sdp4430_dmic_codec,
&sdp4430_abe_audio,
+ &sdp4430_hdmi_audio_codec,
};
static struct omap_musb_board_data musb_board_data = {
@@ -489,50 +495,6 @@ static struct platform_device omap_vwlan_device = {
},
};
-static int omap4_twl6030_hsmmc_late_init(struct device *dev)
-{
- int irq = 0;
- struct platform_device *pdev = container_of(dev,
- struct platform_device, dev);
- struct omap_mmc_platform_data *pdata = dev->platform_data;
-
- /* Setting MMC1 Card detect Irq */
- if (pdev->id == 0) {
- irq = twl6030_mmc_card_detect_config();
- if (irq < 0) {
- pr_err("Failed configuring MMC1 card detect\n");
- return irq;
- }
- pdata->slots[0].card_detect_irq = irq;
- pdata->slots[0].card_detect = twl6030_mmc_card_detect;
- }
- return 0;
-}
-
-static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
-{
- struct omap_mmc_platform_data *pdata;
-
- /* dev can be null if CONFIG_MMC_OMAP_HS is not set */
- if (!dev) {
- pr_err("Failed %s\n", __func__);
- return;
- }
- pdata = dev->platform_data;
- pdata->init = omap4_twl6030_hsmmc_late_init;
-}
-
-static int __init omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers)
-{
- struct omap2_hsmmc_info *c;
-
- omap_hsmmc_init(controllers);
- for (c = controllers; c->mmc; c++)
- omap4_twl6030_hsmmc_set_late_init(&c->pdev->dev);
-
- return 0;
-}
-
static struct regulator_init_data sdp4430_vaux1 = {
.constraints = {
.min_uV = 1000000,
@@ -615,7 +577,9 @@ static int __init omap4_i2c_init(void)
TWL_COMMON_REGULATOR_VANA |
TWL_COMMON_REGULATOR_VCXIO |
TWL_COMMON_REGULATOR_VUSB |
- TWL_COMMON_REGULATOR_CLK32KG);
+ TWL_COMMON_REGULATOR_CLK32KG |
+ TWL_COMMON_REGULATOR_V1V8 |
+ TWL_COMMON_REGULATOR_V2V1);
omap4_pmic_init("twl6030", &sdp4430_twldata,
&twl6040_data, OMAP44XX_IRQ_SYS_2N);
omap_register_i2c_bus(2, 400, NULL, 0);
@@ -666,6 +630,10 @@ static struct nokia_dsi_panel_data dsi1_panel = {
.use_ext_te = false,
.ext_te_gpio = 101,
.esd_interval = 0,
+ .pin_config = {
+ .num_pins = 6,
+ .pins = { 0, 1, 2, 3, 4, 5 },
+ },
};
static struct omap_dss_device sdp4430_lcd_device = {
@@ -674,13 +642,6 @@ static struct omap_dss_device sdp4430_lcd_device = {
.type = OMAP_DISPLAY_TYPE_DSI,
.data = &dsi1_panel,
.phy.dsi = {
- .clk_lane = 1,
- .clk_pol = 0,
- .data1_lane = 2,
- .data1_pol = 0,
- .data2_lane = 3,
- .data2_pol = 0,
-
.module = 0,
},
@@ -715,6 +676,10 @@ static struct nokia_dsi_panel_data dsi2_panel = {
.use_ext_te = false,
.ext_te_gpio = 103,
.esd_interval = 0,
+ .pin_config = {
+ .num_pins = 6,
+ .pins = { 0, 1, 2, 3, 4, 5 },
+ },
};
static struct omap_dss_device sdp4430_lcd2_device = {
@@ -723,12 +688,6 @@ static struct omap_dss_device sdp4430_lcd2_device = {
.type = OMAP_DISPLAY_TYPE_DSI,
.data = &dsi2_panel,
.phy.dsi = {
- .clk_lane = 1,
- .clk_pol = 0,
- .data1_lane = 2,
- .data1_pol = 0,
- .data2_lane = 3,
- .data2_pol = 0,
.module = 1,
},
@@ -758,21 +717,6 @@ static struct omap_dss_device sdp4430_lcd2_device = {
.channel = OMAP_DSS_CHANNEL_LCD2,
};
-static void sdp4430_lcd_init(void)
-{
- int r;
-
- r = gpio_request_one(dsi1_panel.reset_gpio, GPIOF_DIR_OUT,
- "lcd1_reset_gpio");
- if (r)
- pr_err("%s: Could not get lcd1_reset_gpio\n", __func__);
-
- r = gpio_request_one(dsi2_panel.reset_gpio, GPIOF_DIR_OUT,
- "lcd2_reset_gpio");
- if (r)
- pr_err("%s: Could not get lcd2_reset_gpio\n", __func__);
-}
-
static struct omap_dss_hdmi_data sdp4430_hdmi_data = {
.hpd_gpio = HDMI_GPIO_HPD,
};
@@ -858,7 +802,6 @@ static void __init omap_4430sdp_display_init(void)
if (r)
pr_err("%s: Could not get display_sel GPIO\n", __func__);
- sdp4430_lcd_init();
sdp4430_picodlp_init();
omap_display_init(&sdp4430_dss_data);
/*
diff --git a/arch/arm/mach-omap2/board-am3517crane.c b/arch/arm/mach-omap2/board-am3517crane.c
index c3851e8de28b..3b8a53c1f2a8 100644
--- a/arch/arm/mach-omap2/board-am3517crane.c
+++ b/arch/arm/mach-omap2/board-am3517crane.c
@@ -30,6 +30,7 @@
#include "common.h"
#include <plat/usb.h>
+#include "am35xx-emac.h"
#include "mux.h"
#include "control.h"
@@ -90,6 +91,7 @@ static void __init am3517_crane_init(void)
}
usbhs_init(&usbhs_bdata);
+ am35xx_emac_init(AM35XX_DEFAULT_MDIO_FREQUENCY, 1);
}
MACHINE_START(CRANEBOARD, "AM3517/05 CRANEBOARD")
diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c
index 3645285a3e2b..99790eb646e8 100644
--- a/arch/arm/mach-omap2/board-am3517evm.c
+++ b/arch/arm/mach-omap2/board-am3517evm.c
@@ -37,7 +37,7 @@
#include <plat/usb.h>
#include <video/omapdss.h>
#include <video/omap-panel-generic-dpi.h>
-#include <video/omap-panel-dvi.h>
+#include <video/omap-panel-tfp410.h>
#include "am35xx-emac.h"
#include "mux.h"
@@ -207,31 +207,14 @@ static struct omap_dss_device am3517_evm_tv_device = {
.platform_disable = am3517_evm_panel_disable_tv,
};
-static int am3517_evm_panel_enable_dvi(struct omap_dss_device *dssdev)
-{
- if (lcd_enabled) {
- printk(KERN_ERR "cannot enable DVI, LCD is enabled\n");
- return -EINVAL;
- }
- dvi_enabled = 1;
-
- return 0;
-}
-
-static void am3517_evm_panel_disable_dvi(struct omap_dss_device *dssdev)
-{
- dvi_enabled = 0;
-}
-
-static struct panel_dvi_platform_data dvi_panel = {
- .platform_enable = am3517_evm_panel_enable_dvi,
- .platform_disable = am3517_evm_panel_disable_dvi,
+static struct tfp410_platform_data dvi_panel = {
+ .power_down_gpio = -1,
};
static struct omap_dss_device am3517_evm_dvi_device = {
.type = OMAP_DISPLAY_TYPE_DPI,
.name = "dvi",
- .driver_name = "dvi",
+ .driver_name = "tfp410",
.data = &dvi_panel,
.phy.dpi.data_lines = 24,
};
diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c
index 909a8b91b564..c03df142ea67 100644
--- a/arch/arm/mach-omap2/board-cm-t35.c
+++ b/arch/arm/mach-omap2/board-cm-t35.c
@@ -44,7 +44,7 @@
#include <plat/usb.h>
#include <video/omapdss.h>
#include <video/omap-panel-generic-dpi.h>
-#include <video/omap-panel-dvi.h>
+#include <video/omap-panel-tfp410.h>
#include <plat/mcspi.h>
#include <mach/hardware.h>
@@ -218,25 +218,6 @@ static void cm_t35_panel_disable_lcd(struct omap_dss_device *dssdev)
gpio_set_value(CM_T35_LCD_EN_GPIO, 0);
}
-static int cm_t35_panel_enable_dvi(struct omap_dss_device *dssdev)
-{
- if (lcd_enabled) {
- printk(KERN_ERR "cannot enable DVI, LCD is enabled\n");
- return -EINVAL;
- }
-
- gpio_set_value(CM_T35_DVI_EN_GPIO, 0);
- dvi_enabled = 1;
-
- return 0;
-}
-
-static void cm_t35_panel_disable_dvi(struct omap_dss_device *dssdev)
-{
- gpio_set_value(CM_T35_DVI_EN_GPIO, 1);
- dvi_enabled = 0;
-}
-
static int cm_t35_panel_enable_tv(struct omap_dss_device *dssdev)
{
return 0;
@@ -260,15 +241,14 @@ static struct omap_dss_device cm_t35_lcd_device = {
.phy.dpi.data_lines = 18,
};
-static struct panel_dvi_platform_data dvi_panel = {
- .platform_enable = cm_t35_panel_enable_dvi,
- .platform_disable = cm_t35_panel_disable_dvi,
+static struct tfp410_platform_data dvi_panel = {
+ .power_down_gpio = CM_T35_DVI_EN_GPIO,
};
static struct omap_dss_device cm_t35_dvi_device = {
.name = "dvi",
.type = OMAP_DISPLAY_TYPE_DPI,
- .driver_name = "dvi",
+ .driver_name = "tfp410",
.data = &dvi_panel,
.phy.dpi.data_lines = 24,
};
@@ -316,7 +296,6 @@ static struct spi_board_info cm_t35_lcd_spi_board_info[] __initdata = {
static struct gpio cm_t35_dss_gpios[] __initdata = {
{ CM_T35_LCD_EN_GPIO, GPIOF_OUT_INIT_LOW, "lcd enable" },
{ CM_T35_LCD_BL_GPIO, GPIOF_OUT_INIT_LOW, "lcd bl enable" },
- { CM_T35_DVI_EN_GPIO, GPIOF_OUT_INIT_HIGH, "dvi enable" },
};
static void __init cm_t35_init_display(void)
@@ -335,7 +314,6 @@ static void __init cm_t35_init_display(void)
gpio_export(CM_T35_LCD_EN_GPIO, 0);
gpio_export(CM_T35_LCD_BL_GPIO, 0);
- gpio_export(CM_T35_DVI_EN_GPIO, 0);
msleep(50);
gpio_set_value(CM_T35_LCD_EN_GPIO, 1);
@@ -498,6 +476,10 @@ static struct twl4030_gpio_platform_data cm_t35_gpio_data = {
.setup = cm_t35_twl_gpio_setup,
};
+static struct twl4030_power_data cm_t35_power_data = {
+ .use_poweroff = true,
+};
+
static struct twl4030_platform_data cm_t35_twldata = {
/* platform_data for children goes here */
.keypad = &cm_t35_kp_data,
@@ -505,6 +487,7 @@ static struct twl4030_platform_data cm_t35_twldata = {
.vmmc1 = &cm_t35_vmmc1,
.vsim = &cm_t35_vsim,
.vio = &cm_t35_vio,
+ .power = &cm_t35_power_data,
};
static void __init cm_t35_init_i2c(void)
diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c
index a2010f07de31..b063f0d2faa6 100644
--- a/arch/arm/mach-omap2/board-devkit8000.c
+++ b/arch/arm/mach-omap2/board-devkit8000.c
@@ -47,7 +47,7 @@
#include <plat/usb.h>
#include <video/omapdss.h>
#include <video/omap-panel-generic-dpi.h>
-#include <video/omap-panel-dvi.h>
+#include <video/omap-panel-tfp410.h>
#include <plat/mcspi.h>
#include <linux/input/matrix_keypad.h>
@@ -118,19 +118,6 @@ static void devkit8000_panel_disable_lcd(struct omap_dss_device *dssdev)
gpio_set_value_cansleep(dssdev->reset_gpio, 0);
}
-static int devkit8000_panel_enable_dvi(struct omap_dss_device *dssdev)
-{
- if (gpio_is_valid(dssdev->reset_gpio))
- gpio_set_value_cansleep(dssdev->reset_gpio, 1);
- return 0;
-}
-
-static void devkit8000_panel_disable_dvi(struct omap_dss_device *dssdev)
-{
- if (gpio_is_valid(dssdev->reset_gpio))
- gpio_set_value_cansleep(dssdev->reset_gpio, 0);
-}
-
static struct regulator_consumer_supply devkit8000_vmmc1_supply[] = {
REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"),
};
@@ -154,15 +141,14 @@ static struct omap_dss_device devkit8000_lcd_device = {
.phy.dpi.data_lines = 24,
};
-static struct panel_dvi_platform_data dvi_panel = {
- .platform_enable = devkit8000_panel_enable_dvi,
- .platform_disable = devkit8000_panel_disable_dvi,
+static struct tfp410_platform_data dvi_panel = {
+ .power_down_gpio = -1,
};
static struct omap_dss_device devkit8000_dvi_device = {
.name = "dvi",
.type = OMAP_DISPLAY_TYPE_DPI,
- .driver_name = "dvi",
+ .driver_name = "tfp410",
.data = &dvi_panel,
.phy.dpi.data_lines = 24,
};
@@ -244,13 +230,7 @@ static int devkit8000_twl_gpio_setup(struct device *dev,
}
/* gpio + 7 is "DVI_PD" (out, active low) */
- devkit8000_dvi_device.reset_gpio = gpio + 7;
- ret = gpio_request_one(devkit8000_dvi_device.reset_gpio,
- GPIOF_OUT_INIT_LOW, "DVI PowerDown");
- if (ret < 0) {
- devkit8000_dvi_device.reset_gpio = -EINVAL;
- printk(KERN_ERR "Failed to request GPIO for DVI PowerDown\n");
- }
+ dvi_panel.power_down_gpio = gpio + 7;
return 0;
}
diff --git a/arch/arm/mach-omap2/board-flash.c b/arch/arm/mach-omap2/board-flash.c
index 0349fd2b68d8..70a81f900bb5 100644
--- a/arch/arm/mach-omap2/board-flash.c
+++ b/arch/arm/mach-omap2/board-flash.c
@@ -87,7 +87,7 @@ static struct omap_onenand_platform_data board_onenand_data = {
.dma_channel = -1, /* disable DMA in OMAP OneNAND driver */
};
-static void
+void
__init board_onenand_init(struct mtd_partition *onenand_parts,
u8 nr_parts, u8 cs)
{
@@ -98,7 +98,7 @@ __init board_onenand_init(struct mtd_partition *onenand_parts,
gpmc_onenand_init(&board_onenand_data);
}
#else
-static void
+void
__init board_onenand_init(struct mtd_partition *nor_parts, u8 nr_parts, u8 cs)
{
}
diff --git a/arch/arm/mach-omap2/board-flash.h b/arch/arm/mach-omap2/board-flash.h
index d25503a98417..c44b70d52021 100644
--- a/arch/arm/mach-omap2/board-flash.h
+++ b/arch/arm/mach-omap2/board-flash.h
@@ -47,3 +47,14 @@ static inline void board_nand_init(struct mtd_partition *nand_parts,
{
}
#endif
+
+#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
+ defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)
+extern void board_onenand_init(struct mtd_partition *nand_parts,
+ u8 nr_parts, u8 cs);
+#else
+static inline void board_onenand_init(struct mtd_partition *nand_parts,
+ u8 nr_parts, u8 cs)
+{
+}
+#endif
diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c
index 098d183a0086..7302ba7ff1b9 100644
--- a/arch/arm/mach-omap2/board-generic.c
+++ b/arch/arm/mach-omap2/board-generic.c
@@ -15,7 +15,6 @@
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/irqdomain.h>
-#include <linux/i2c/twl.h>
#include <mach/hardware.h>
#include <asm/hardware/gic.h>
@@ -95,22 +94,6 @@ MACHINE_END
#endif
#ifdef CONFIG_ARCH_OMAP3
-static struct twl4030_platform_data beagle_twldata = {
- .irq_base = TWL4030_IRQ_BASE,
- .irq_end = TWL4030_IRQ_END,
-};
-
-static void __init omap3_i2c_init(void)
-{
- omap3_pmic_init("twl4030", &beagle_twldata);
-}
-
-static void __init omap3_init(void)
-{
- omap3_i2c_init();
- omap_generic_init();
-}
-
static const char *omap3_boards_compat[] __initdata = {
"ti,omap3",
NULL,
@@ -122,7 +105,7 @@ DT_MACHINE_START(OMAP3_DT, "Generic OMAP3 (Flattened Device Tree)")
.init_early = omap3430_init_early,
.init_irq = omap_init_irq,
.handle_irq = omap3_intc_handle_irq,
- .init_machine = omap3_init,
+ .init_machine = omap_generic_init,
.timer = &omap3_timer,
.dt_compat = omap3_boards_compat,
.restart = omap_prcm_restart,
@@ -130,22 +113,6 @@ MACHINE_END
#endif
#ifdef CONFIG_ARCH_OMAP4
-static struct twl4030_platform_data sdp4430_twldata = {
- .irq_base = TWL6030_IRQ_BASE,
- .irq_end = TWL6030_IRQ_END,
-};
-
-static void __init omap4_i2c_init(void)
-{
- omap4_pmic_init("twl6030", &sdp4430_twldata, NULL, 0);
-}
-
-static void __init omap4_init(void)
-{
- omap4_i2c_init();
- omap_generic_init();
-}
-
static const char *omap4_boards_compat[] __initdata = {
"ti,omap4",
NULL,
@@ -157,7 +124,7 @@ DT_MACHINE_START(OMAP4_DT, "Generic OMAP4 (Flattened Device Tree)")
.init_early = omap4430_init_early,
.init_irq = omap_init_irq,
.handle_irq = gic_handle_irq,
- .init_machine = omap4_init,
+ .init_machine = omap_generic_init,
.timer = &omap4_timer,
.dt_compat = omap4_boards_compat,
.restart = omap_prcm_restart,
diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c
index 740cee9369ba..7a274098f67b 100644
--- a/arch/arm/mach-omap2/board-igep0020.c
+++ b/arch/arm/mach-omap2/board-igep0020.c
@@ -24,6 +24,8 @@
#include <linux/i2c/twl.h>
#include <linux/mmc/host.h>
+#include <linux/mtd/nand.h>
+
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -32,13 +34,15 @@
#include <plat/gpmc.h>
#include <plat/usb.h>
#include <video/omapdss.h>
-#include <video/omap-panel-dvi.h>
+#include <video/omap-panel-tfp410.h>
#include <plat/onenand.h>
#include "mux.h"
#include "hsmmc.h"
#include "sdram-numonyx-m65kxxxxam.h"
#include "common-board-devices.h"
+#include "board-flash.h"
+#include "control.h"
#define IGEP2_SMSC911X_CS 5
#define IGEP2_SMSC911X_GPIO 176
@@ -60,6 +64,10 @@
#define IGEP3_GPIO_LED1_RED 16
#define IGEP3_GPIO_USBH_NRESET 183
+#define IGEP_SYSBOOT_MASK 0x1f
+#define IGEP_SYSBOOT_NAND 0x0f
+#define IGEP_SYSBOOT_ONENAND 0x10
+
/*
* IGEP2 Hardware Revision Table
*
@@ -110,8 +118,10 @@ static void __init igep2_get_revision(void)
gpio_free(IGEP2_GPIO_LED1_RED);
}
-#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
- defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)
+#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
+ defined(CONFIG_MTD_ONENAND_OMAP2_MODULE) || \
+ defined(CONFIG_MTD_NAND_OMAP2) || \
+ defined(CONFIG_MTD_NAND_OMAP2_MODULE)
#define ONENAND_MAP 0x20000000
@@ -123,7 +133,7 @@ static void __init igep2_get_revision(void)
* So MTD regards it as 4KiB page size and 256KiB block size 64*(2*2048)
*/
-static struct mtd_partition igep_onenand_partitions[] = {
+static struct mtd_partition igep_flash_partitions[] = {
{
.name = "X-Loader",
.offset = 0,
@@ -151,50 +161,28 @@ static struct mtd_partition igep_onenand_partitions[] = {
},
};
-static struct omap_onenand_platform_data igep_onenand_data = {
- .parts = igep_onenand_partitions,
- .nr_parts = ARRAY_SIZE(igep_onenand_partitions),
- .dma_channel = -1, /* disable DMA in OMAP OneNAND driver */
-};
-
-static struct platform_device igep_onenand_device = {
- .name = "omap2-onenand",
- .id = -1,
- .dev = {
- .platform_data = &igep_onenand_data,
- },
-};
+static inline u32 igep_get_sysboot_value(void)
+{
+ return omap_ctrl_readl(OMAP343X_CONTROL_STATUS) & IGEP_SYSBOOT_MASK;
+}
static void __init igep_flash_init(void)
{
- u8 cs = 0;
- u8 onenandcs = GPMC_CS_NUM + 1;
-
- for (cs = 0; cs < GPMC_CS_NUM; cs++) {
- u32 ret;
- ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
-
- /* Check if NAND/oneNAND is configured */
- if ((ret & 0xC00) == 0x800)
- /* NAND found */
- pr_err("IGEP: Unsupported NAND found\n");
- else {
- ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
- if ((ret & 0x3F) == (ONENAND_MAP >> 24))
- /* ONENAND found */
- onenandcs = cs;
- }
- }
-
- if (onenandcs > GPMC_CS_NUM) {
- pr_err("IGEP: Unable to find configuration in GPMC\n");
- return;
+ u32 mux;
+ mux = igep_get_sysboot_value();
+
+ if (mux == IGEP_SYSBOOT_NAND) {
+ pr_info("IGEP: initializing NAND memory device\n");
+ board_nand_init(igep_flash_partitions,
+ ARRAY_SIZE(igep_flash_partitions),
+ 0, NAND_BUSWIDTH_16);
+ } else if (mux == IGEP_SYSBOOT_ONENAND) {
+ pr_info("IGEP: initializing OneNAND memory device\n");
+ board_onenand_init(igep_flash_partitions,
+ ARRAY_SIZE(igep_flash_partitions), 0);
+ } else {
+ pr_err("IGEP: Flash: unsupported sysboot sequence found\n");
}
-
- igep_onenand_data.cs = onenandcs;
-
- if (platform_device_register(&igep_onenand_device) < 0)
- pr_err("IGEP: Unable to register OneNAND device\n");
}
#else
@@ -444,28 +432,15 @@ static struct twl4030_gpio_platform_data igep_twl4030_gpio_pdata = {
.setup = igep_twl_gpio_setup,
};
-static int igep2_enable_dvi(struct omap_dss_device *dssdev)
-{
- gpio_direction_output(IGEP2_GPIO_DVI_PUP, 1);
-
- return 0;
-}
-
-static void igep2_disable_dvi(struct omap_dss_device *dssdev)
-{
- gpio_direction_output(IGEP2_GPIO_DVI_PUP, 0);
-}
-
-static struct panel_dvi_platform_data dvi_panel = {
- .platform_enable = igep2_enable_dvi,
- .platform_disable = igep2_disable_dvi,
- .i2c_bus_num = 3,
+static struct tfp410_platform_data dvi_panel = {
+ .i2c_bus_num = 3,
+ .power_down_gpio = IGEP2_GPIO_DVI_PUP,
};
static struct omap_dss_device igep2_dvi_device = {
.type = OMAP_DISPLAY_TYPE_DPI,
.name = "dvi",
- .driver_name = "dvi",
+ .driver_name = "tfp410",
.data = &dvi_panel,
.phy.dpi.data_lines = 24,
};
@@ -480,14 +455,6 @@ static struct omap_dss_board_info igep2_dss_data = {
.default_device = &igep2_dvi_device,
};
-static void __init igep2_display_init(void)
-{
- int err = gpio_request_one(IGEP2_GPIO_DVI_PUP, GPIOF_OUT_INIT_HIGH,
- "GPIO_DVI_PUP");
- if (err)
- pr_err("IGEP v2: Could not obtain gpio GPIO_DVI_PUP\n");
-}
-
static struct platform_device *igep_devices[] __initdata = {
&igep_vwlan_device,
};
@@ -540,7 +507,10 @@ static void __init igep_i2c_init(void)
{
int ret;
- omap3_pmic_get_config(&igep_twldata, TWL_COMMON_PDATA_USB, 0);
+ omap3_pmic_get_config(&igep_twldata, TWL_COMMON_PDATA_USB,
+ TWL_COMMON_REGULATOR_VPLL2);
+ igep_twldata.vpll2->constraints.apply_uV = true;
+ igep_twldata.vpll2->constraints.name = "VDVI";
if (machine_is_igep0020()) {
/*
@@ -554,10 +524,7 @@ static void __init igep_i2c_init(void)
igep_twldata.keypad = &igep2_keypad_pdata;
/* Get common pmic data */
- omap3_pmic_get_config(&igep_twldata, TWL_COMMON_PDATA_AUDIO,
- TWL_COMMON_REGULATOR_VPLL2);
- igep_twldata.vpll2->constraints.apply_uV = true;
- igep_twldata.vpll2->constraints.name = "VDVI";
+ omap3_pmic_get_config(&igep_twldata, TWL_COMMON_PDATA_AUDIO, 0);
}
omap3_pmic_init("twl4030", &igep_twldata);
@@ -668,7 +635,6 @@ static void __init igep_init(void)
if (machine_is_igep0020()) {
omap_display_init(&igep2_dss_data);
- igep2_display_init();
igep2_init_smsc911x();
usbhs_init(&igep2_usbhs_bdata);
} else {
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 7be8d659d91d..2a7b9a9da1db 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -42,7 +42,7 @@
#include <plat/board.h>
#include "common.h"
#include <video/omapdss.h>
-#include <video/omap-panel-dvi.h>
+#include <video/omap-panel-tfp410.h>
#include <plat/gpmc.h>
#include <plat/nand.h>
#include <plat/usb.h>
@@ -83,11 +83,13 @@ static struct {
int usb_pwr_level;
int reset_gpio;
int usr_button_gpio;
+ int mmc_caps;
} beagle_config = {
.mmc1_gpio_wp = -EINVAL,
.usb_pwr_level = GPIOF_OUT_INIT_LOW,
.reset_gpio = 129,
.usr_button_gpio = 4,
+ .mmc_caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
};
static struct gpio omap3_beagle_rev_gpios[] __initdata = {
@@ -145,10 +147,12 @@ static void __init omap3_beagle_init_rev(void)
printk(KERN_INFO "OMAP3 Beagle Rev: xM Ax/Bx\n");
omap3_beagle_version = OMAP3BEAGLE_BOARD_XM;
beagle_config.usb_pwr_level = GPIOF_OUT_INIT_HIGH;
+ beagle_config.mmc_caps &= ~MMC_CAP_8_BIT_DATA;
break;
case 2:
printk(KERN_INFO "OMAP3 Beagle Rev: xM C\n");
omap3_beagle_version = OMAP3BEAGLE_BOARD_XMC;
+ beagle_config.mmc_caps &= ~MMC_CAP_8_BIT_DATA;
break;
default:
printk(KERN_INFO "OMAP3 Beagle Rev: unknown %hd\n", beagle_rev);
@@ -189,33 +193,17 @@ static struct mtd_partition omap3beagle_nand_partitions[] = {
/* DSS */
-static int beagle_enable_dvi(struct omap_dss_device *dssdev)
-{
- if (gpio_is_valid(dssdev->reset_gpio))
- gpio_set_value(dssdev->reset_gpio, 1);
-
- return 0;
-}
-
-static void beagle_disable_dvi(struct omap_dss_device *dssdev)
-{
- if (gpio_is_valid(dssdev->reset_gpio))
- gpio_set_value(dssdev->reset_gpio, 0);
-}
-
-static struct panel_dvi_platform_data dvi_panel = {
- .platform_enable = beagle_enable_dvi,
- .platform_disable = beagle_disable_dvi,
+static struct tfp410_platform_data dvi_panel = {
.i2c_bus_num = 3,
+ .power_down_gpio = -1,
};
static struct omap_dss_device beagle_dvi_device = {
.type = OMAP_DISPLAY_TYPE_DPI,
.name = "dvi",
- .driver_name = "dvi",
+ .driver_name = "tfp410",
.data = &dvi_panel,
.phy.dpi.data_lines = 24,
- .reset_gpio = -EINVAL,
};
static struct omap_dss_device beagle_tv_device = {
@@ -236,22 +224,12 @@ static struct omap_dss_board_info beagle_dss_data = {
.default_device = &beagle_dvi_device,
};
-static void __init beagle_display_init(void)
-{
- int r;
-
- r = gpio_request_one(beagle_dvi_device.reset_gpio, GPIOF_OUT_INIT_LOW,
- "DVI reset");
- if (r < 0)
- printk(KERN_ERR "Unable to get DVI reset GPIO\n");
-}
-
#include "sdram-micron-mt46h32m32lf-6.h"
static struct omap2_hsmmc_info mmc[] = {
{
.mmc = 1,
- .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+ .caps = MMC_CAP_4_BIT_DATA,
.gpio_wp = -EINVAL,
.deferred = true,
},
@@ -309,7 +287,7 @@ static int beagle_twl_gpio_setup(struct device *dev,
if (gpio_request_one(gpio + 1, GPIOF_IN, "EHCI_nOC"))
pr_err("%s: unable to configure EHCI_nOC\n", __func__);
}
- beagle_dvi_device.reset_gpio = beagle_config.reset_gpio;
+ dvi_panel.power_down_gpio = beagle_config.reset_gpio;
gpio_request_one(gpio + TWL4030_GPIO_MAX, beagle_config.usb_pwr_level,
"nEN_USB_PWR");
@@ -523,6 +501,7 @@ static void __init omap3_beagle_init(void)
if (beagle_config.mmc1_gpio_wp != -EINVAL)
omap_mux_init_gpio(beagle_config.mmc1_gpio_wp, OMAP_PIN_INPUT);
+ mmc[0].caps = beagle_config.mmc_caps;
omap_hsmmc_init(mmc);
omap3_beagle_i2c_init();
@@ -552,7 +531,6 @@ static void __init omap3_beagle_init(void)
omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
- beagle_display_init();
beagle_opp_init();
}
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index 49df12735b41..ace3c675e9c2 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -46,7 +46,7 @@
#include "common.h"
#include <plat/mcspi.h>
#include <video/omapdss.h>
-#include <video/omap-panel-dvi.h>
+#include <video/omap-panel-tfp410.h>
#include "mux.h"
#include "sdram-micron-mt46h32m32lf-6.h"
@@ -219,35 +219,14 @@ static struct omap_dss_device omap3_evm_tv_device = {
.platform_disable = omap3_evm_disable_tv,
};
-static int omap3_evm_enable_dvi(struct omap_dss_device *dssdev)
-{
- if (lcd_enabled) {
- printk(KERN_ERR "cannot enable DVI, LCD is enabled\n");
- return -EINVAL;
- }
-
- gpio_set_value_cansleep(OMAP3EVM_DVI_PANEL_EN_GPIO, 1);
-
- dvi_enabled = 1;
- return 0;
-}
-
-static void omap3_evm_disable_dvi(struct omap_dss_device *dssdev)
-{
- gpio_set_value_cansleep(OMAP3EVM_DVI_PANEL_EN_GPIO, 0);
-
- dvi_enabled = 0;
-}
-
-static struct panel_dvi_platform_data dvi_panel = {
- .platform_enable = omap3_evm_enable_dvi,
- .platform_disable = omap3_evm_disable_dvi,
+static struct tfp410_platform_data dvi_panel = {
+ .power_down_gpio = OMAP3EVM_DVI_PANEL_EN_GPIO,
};
static struct omap_dss_device omap3_evm_dvi_device = {
.name = "dvi",
.type = OMAP_DISPLAY_TYPE_DPI,
- .driver_name = "dvi",
+ .driver_name = "tfp410",
.data = &dvi_panel,
.phy.dpi.data_lines = 24,
};
@@ -630,13 +609,13 @@ static struct regulator_consumer_supply dummy_supplies[] = {
static void __init omap3_evm_init(void)
{
+ struct omap_board_mux *obm;
+
omap3_evm_get_revision();
regulator_register_fixed(0, dummy_supplies, ARRAY_SIZE(dummy_supplies));
- if (cpu_is_omap3630())
- omap3_mux_init(omap36x_board_mux, OMAP_PACKAGE_CBB);
- else
- omap3_mux_init(omap35x_board_mux, OMAP_PACKAGE_CBB);
+ obm = (cpu_is_omap3630()) ? omap36x_board_mux : omap35x_board_mux;
+ omap3_mux_init(obm, OMAP_PACKAGE_CBB);
omap_board_config = omap3_evm_config;
omap_board_config_size = ARRAY_SIZE(omap3_evm_config);
diff --git a/arch/arm/mach-omap2/board-omap3logic.c b/arch/arm/mach-omap2/board-omap3logic.c
index 9b3c141ff51b..c008bf8e1c36 100644
--- a/arch/arm/mach-omap2/board-omap3logic.c
+++ b/arch/arm/mach-omap2/board-omap3logic.c
@@ -4,8 +4,9 @@
* Copyright (C) 2010 Li-Pro.Net
* Stephan Linz <linz@li-pro.net>
*
- * Copyright (C) 2010 Logic Product Development, Inc.
+ * Copyright (C) 2010-2012 Logic Product Development, Inc.
* Peter Barada <peter.barada@logicpd.com>
+ * Ashwin BIhari <ashwin.bihari@logicpd.com>
*
* Modified from Beagle, EVM, and RX51
*
@@ -45,6 +46,7 @@
#include <plat/gpmc-smsc911x.h>
#include <plat/gpmc.h>
#include <plat/sdrc.h>
+#include <plat/usb.h>
#define OMAP3LOGIC_SMSC911X_CS 1
@@ -85,6 +87,11 @@ static struct twl4030_gpio_platform_data omap3logic_gpio_data = {
| BIT(13) | BIT(15) | BIT(16) | BIT(17),
};
+static struct twl4030_usb_data omap3logic_usb_data = {
+ .usb_mode = T2_USB_MODE_ULPI,
+};
+
+
static struct twl4030_platform_data omap3logic_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
@@ -92,6 +99,7 @@ static struct twl4030_platform_data omap3logic_twldata = {
/* platform_data for children goes here */
.gpio = &omap3logic_gpio_data,
.vmmc1 = &omap3logic_vmmc1,
+ .usb = &omap3logic_usb_data,
};
static int __init omap3logic_i2c_init(void)
@@ -185,6 +193,20 @@ static inline void __init board_smsc911x_init(void)
#ifdef CONFIG_OMAP_MUX
static struct omap_board_mux board_mux[] __initdata = {
+ /* mUSB */
+ OMAP3_MUX(HSUSB0_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+ OMAP3_MUX(HSUSB0_STP, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT),
+ OMAP3_MUX(HSUSB0_DIR, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+ OMAP3_MUX(HSUSB0_NXT, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+ OMAP3_MUX(HSUSB0_DATA0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+ OMAP3_MUX(HSUSB0_DATA1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+ OMAP3_MUX(HSUSB0_DATA2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+ OMAP3_MUX(HSUSB0_DATA3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+ OMAP3_MUX(HSUSB0_DATA4, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+ OMAP3_MUX(HSUSB0_DATA5, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+ OMAP3_MUX(HSUSB0_DATA6, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+ OMAP3_MUX(HSUSB0_DATA7, OMAP_MUX_MODE0 | OMAP_PIN_INPUT),
+
{ .reg_offset = OMAP_MUX_TERMINATOR },
};
#endif
@@ -205,6 +227,8 @@ static void __init omap3logic_init(void)
board_mmc_init();
board_smsc911x_init();
+ usb_musb_init(NULL);
+
/* Ensure SDRC pins are mux'd for self-refresh */
omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
diff --git a/arch/arm/mach-omap2/board-omap3stalker.c b/arch/arm/mach-omap2/board-omap3stalker.c
index 4dffc95bddd2..4396bae91677 100644
--- a/arch/arm/mach-omap2/board-omap3stalker.c
+++ b/arch/arm/mach-omap2/board-omap3stalker.c
@@ -42,7 +42,7 @@
#include <plat/usb.h>
#include <video/omapdss.h>
#include <video/omap-panel-generic-dpi.h>
-#include <video/omap-panel-dvi.h>
+#include <video/omap-panel-tfp410.h>
#include <plat/mcspi.h>
#include <linux/input/matrix_keypad.h>
@@ -92,9 +92,6 @@ static inline void __init omap3stalker_init_eth(void)
#define LCD_PANEL_BKLIGHT_GPIO 210
#define ENABLE_VPLL2_DEV_GRP 0xE0
-static int lcd_enabled;
-static int dvi_enabled;
-
static void __init omap3_stalker_display_init(void)
{
return;
@@ -122,32 +119,14 @@ static struct omap_dss_device omap3_stalker_tv_device = {
.platform_disable = omap3_stalker_disable_tv,
};
-static int omap3_stalker_enable_dvi(struct omap_dss_device *dssdev)
-{
- if (lcd_enabled) {
- printk(KERN_ERR "cannot enable DVI, LCD is enabled\n");
- return -EINVAL;
- }
- gpio_set_value(DSS_ENABLE_GPIO, 1);
- dvi_enabled = 1;
- return 0;
-}
-
-static void omap3_stalker_disable_dvi(struct omap_dss_device *dssdev)
-{
- gpio_set_value(DSS_ENABLE_GPIO, 0);
- dvi_enabled = 0;
-}
-
-static struct panel_dvi_platform_data dvi_panel = {
- .platform_enable = omap3_stalker_enable_dvi,
- .platform_disable = omap3_stalker_disable_dvi,
+static struct tfp410_platform_data dvi_panel = {
+ .power_down_gpio = DSS_ENABLE_GPIO,
};
static struct omap_dss_device omap3_stalker_dvi_device = {
.name = "dvi",
.type = OMAP_DISPLAY_TYPE_DPI,
- .driver_name = "dvi",
+ .driver_name = "tfp410",
.data = &dvi_panel,
.phy.dpi.data_lines = 24,
};
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index 1b782ba53433..68b8fc9ff010 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -28,6 +28,7 @@
#include <linux/mfd/twl6040.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/fixed.h>
+#include <linux/ti_wilink_st.h>
#include <linux/wl12xx.h>
#include <linux/platform_data/omap-abe-twl6040.h>
@@ -42,7 +43,7 @@
#include "common.h"
#include <plat/usb.h>
#include <plat/mmc.h>
-#include <video/omap-panel-dvi.h>
+#include <video/omap-panel-tfp410.h>
#include "hsmmc.h"
#include "control.h"
@@ -58,12 +59,21 @@
#define HDMI_GPIO_HPD 63 /* Hotplug detect */
/* wl127x BT, FM, GPS connectivity chip */
-static int wl1271_gpios[] = {46, -1, -1};
+static struct ti_st_plat_data wilink_platform_data = {
+ .nshutdown_gpio = 46,
+ .dev_name = "/dev/ttyO1",
+ .flow_cntrl = 1,
+ .baud_rate = 3000000,
+ .chip_enable = NULL,
+ .suspend = NULL,
+ .resume = NULL,
+};
+
static struct platform_device wl1271_device = {
.name = "kim",
.id = -1,
.dev = {
- .platform_data = &wl1271_gpios,
+ .platform_data = &wilink_platform_data,
},
};
@@ -117,6 +127,11 @@ static struct platform_device panda_abe_audio = {
},
};
+static struct platform_device panda_hdmi_audio_codec = {
+ .name = "hdmi-audio-codec",
+ .id = -1,
+};
+
static struct platform_device btwilink_device = {
.name = "btwilink",
.id = -1,
@@ -126,6 +141,7 @@ static struct platform_device *panda_devices[] __initdata = {
&leds_gpio,
&wl1271_device,
&panda_abe_audio,
+ &panda_hdmi_audio_codec,
&btwilink_device,
};
@@ -231,60 +247,11 @@ static struct platform_device omap_vwlan_device = {
},
};
-struct wl12xx_platform_data omap_panda_wlan_data __initdata = {
+static struct wl12xx_platform_data omap_panda_wlan_data __initdata = {
/* PANDA ref clock is 38.4 MHz */
.board_ref_clock = 2,
};
-static int omap4_twl6030_hsmmc_late_init(struct device *dev)
-{
- int irq = 0;
- struct platform_device *pdev = container_of(dev,
- struct platform_device, dev);
- struct omap_mmc_platform_data *pdata = dev->platform_data;
-
- if (!pdata) {
- dev_err(dev, "%s: NULL platform data\n", __func__);
- return -EINVAL;
- }
- /* Setting MMC1 Card detect Irq */
- if (pdev->id == 0) {
- irq = twl6030_mmc_card_detect_config();
- if (irq < 0) {
- dev_err(dev, "%s: Error card detect config(%d)\n",
- __func__, irq);
- return irq;
- }
- pdata->slots[0].card_detect = twl6030_mmc_card_detect;
- }
- return 0;
-}
-
-static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
-{
- struct omap_mmc_platform_data *pdata;
-
- /* dev can be null if CONFIG_MMC_OMAP_HS is not set */
- if (!dev) {
- pr_err("Failed omap4_twl6030_hsmmc_set_late_init\n");
- return;
- }
- pdata = dev->platform_data;
-
- pdata->init = omap4_twl6030_hsmmc_late_init;
-}
-
-static int __init omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers)
-{
- struct omap2_hsmmc_info *c;
-
- omap_hsmmc_init(controllers);
- for (c = controllers; c->mmc; c++)
- omap4_twl6030_hsmmc_set_late_init(&c->pdev->dev);
-
- return 0;
-}
-
static struct twl6040_codec_data twl6040_codec = {
/* single-step ramp for headset and handsfree */
.hs_left_step = 0x0f,
@@ -323,7 +290,9 @@ static int __init omap4_panda_i2c_init(void)
TWL_COMMON_REGULATOR_VANA |
TWL_COMMON_REGULATOR_VCXIO |
TWL_COMMON_REGULATOR_VUSB |
- TWL_COMMON_REGULATOR_CLK32KG);
+ TWL_COMMON_REGULATOR_CLK32KG |
+ TWL_COMMON_REGULATOR_V1V8 |
+ TWL_COMMON_REGULATOR_V2V1);
omap4_pmic_init("twl6030", &omap4_panda_twldata,
&twl6040_data, OMAP44XX_IRQ_SYS_2N);
omap_register_i2c_bus(2, 400, NULL, 0);
@@ -420,47 +389,22 @@ static struct omap_board_mux board_mux[] __initdata = {
/* Display DVI */
#define PANDA_DVI_TFP410_POWER_DOWN_GPIO 0
-static int omap4_panda_enable_dvi(struct omap_dss_device *dssdev)
-{
- gpio_set_value(dssdev->reset_gpio, 1);
- return 0;
-}
-
-static void omap4_panda_disable_dvi(struct omap_dss_device *dssdev)
-{
- gpio_set_value(dssdev->reset_gpio, 0);
-}
-
/* Using generic display panel */
-static struct panel_dvi_platform_data omap4_dvi_panel = {
- .platform_enable = omap4_panda_enable_dvi,
- .platform_disable = omap4_panda_disable_dvi,
- .i2c_bus_num = 3,
+static struct tfp410_platform_data omap4_dvi_panel = {
+ .i2c_bus_num = 3,
+ .power_down_gpio = PANDA_DVI_TFP410_POWER_DOWN_GPIO,
};
-struct omap_dss_device omap4_panda_dvi_device = {
+static struct omap_dss_device omap4_panda_dvi_device = {
.type = OMAP_DISPLAY_TYPE_DPI,
.name = "dvi",
- .driver_name = "dvi",
+ .driver_name = "tfp410",
.data = &omap4_dvi_panel,
.phy.dpi.data_lines = 24,
.reset_gpio = PANDA_DVI_TFP410_POWER_DOWN_GPIO,
.channel = OMAP_DSS_CHANNEL_LCD2,
};
-int __init omap4_panda_dvi_init(void)
-{
- int r;
-
- /* Requesting TFP410 DVI GPIO and disabling it, at bootup */
- r = gpio_request_one(omap4_panda_dvi_device.reset_gpio,
- GPIOF_OUT_INIT_LOW, "DVI PD");
- if (r)
- pr_err("Failed to get DVI powerdown GPIO\n");
-
- return r;
-}
-
static struct gpio panda_hdmi_gpios[] = {
{ HDMI_GPIO_CT_CP_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ct_cp_hpd" },
{ HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" },
@@ -509,13 +453,8 @@ static struct omap_dss_board_info omap4_panda_dss_data = {
.default_device = &omap4_panda_dvi_device,
};
-void __init omap4_panda_display_init(void)
+static void __init omap4_panda_display_init(void)
{
- int r;
-
- r = omap4_panda_dvi_init();
- if (r)
- pr_err("error initializing panda DVI\n");
omap_display_init(&omap4_panda_dss_data);
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index 33aa3910b09e..5527c1979a16 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -46,7 +46,7 @@
#include "common.h"
#include <video/omapdss.h>
#include <video/omap-panel-generic-dpi.h>
-#include <video/omap-panel-dvi.h>
+#include <video/omap-panel-tfp410.h>
#include <plat/gpmc.h>
#include <mach/hardware.h>
#include <plat/nand.h>
@@ -167,32 +167,15 @@ static void __init overo_display_init(void)
gpio_export(OVERO_GPIO_LCD_BL, 0);
}
-static int overo_panel_enable_dvi(struct omap_dss_device *dssdev)
-{
- if (lcd_enabled) {
- printk(KERN_ERR "cannot enable DVI, LCD is enabled\n");
- return -EINVAL;
- }
- dvi_enabled = 1;
-
- return 0;
-}
-
-static void overo_panel_disable_dvi(struct omap_dss_device *dssdev)
-{
- dvi_enabled = 0;
-}
-
-static struct panel_dvi_platform_data dvi_panel = {
- .platform_enable = overo_panel_enable_dvi,
- .platform_disable = overo_panel_disable_dvi,
+static struct tfp410_platform_data dvi_panel = {
.i2c_bus_num = 3,
+ .power_down_gpio = -1,
};
static struct omap_dss_device overo_dvi_device = {
.name = "dvi",
.type = OMAP_DISPLAY_TYPE_DPI,
- .driver_name = "dvi",
+ .driver_name = "tfp410",
.data = &dvi_panel,
.phy.dpi.data_lines = 24,
};
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index d87ee0612098..ff53deccecab 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -44,6 +44,7 @@
#include <linux/leds-lp5523.h>
#include <../drivers/staging/iio/light/tsl2563.h>
+#include <linux/lis3lv02d.h>
#include "mux.h"
#include "hsmmc.h"
@@ -63,6 +64,9 @@
#define RX51_TSC2005_RESET_GPIO 104
#define RX51_TSC2005_IRQ_GPIO 100
+#define LIS302_IRQ1_GPIO 181
+#define LIS302_IRQ2_GPIO 180 /* Not yet in use */
+
/* list all spi devices here */
enum {
RX51_SPI_WL1251,
@@ -73,6 +77,77 @@ enum {
static struct wl12xx_platform_data wl1251_pdata;
static struct tsc2005_platform_data tsc2005_pdata;
+#if defined(CONFIG_SENSORS_LIS3_I2C) || defined(CONFIG_SENSORS_LIS3_I2C_MODULE)
+static int lis302_setup(void)
+{
+ int err;
+ int irq1 = LIS302_IRQ1_GPIO;
+ int irq2 = LIS302_IRQ2_GPIO;
+
+ /* gpio for interrupt pin 1 */
+ err = gpio_request(irq1, "lis3lv02dl_irq1");
+ if (err) {
+ printk(KERN_ERR "lis3lv02dl: gpio request failed\n");
+ goto out;
+ }
+
+ /* gpio for interrupt pin 2 */
+ err = gpio_request(irq2, "lis3lv02dl_irq2");
+ if (err) {
+ gpio_free(irq1);
+ printk(KERN_ERR "lis3lv02dl: gpio request failed\n");
+ goto out;
+ }
+
+ gpio_direction_input(irq1);
+ gpio_direction_input(irq2);
+
+out:
+ return err;
+}
+
+static int lis302_release(void)
+{
+ gpio_free(LIS302_IRQ1_GPIO);
+ gpio_free(LIS302_IRQ2_GPIO);
+
+ return 0;
+}
+
+static struct lis3lv02d_platform_data rx51_lis3lv02d_data = {
+ .click_flags = LIS3_CLICK_SINGLE_X | LIS3_CLICK_SINGLE_Y |
+ LIS3_CLICK_SINGLE_Z,
+ /* Limits are 0.5g * value */
+ .click_thresh_x = 8,
+ .click_thresh_y = 8,
+ .click_thresh_z = 10,
+ /* Click must be longer than time limit */
+ .click_time_limit = 9,
+ /* Kind of debounce filter */
+ .click_latency = 50,
+
+ /* Limits for all axis. millig-value / 18 to get HW values */
+ .wakeup_flags = LIS3_WAKEUP_X_HI | LIS3_WAKEUP_Y_HI,
+ .wakeup_thresh = 800 / 18,
+ .wakeup_flags2 = LIS3_WAKEUP_Z_HI ,
+ .wakeup_thresh2 = 900 / 18,
+
+ .hipass_ctrl = LIS3_HIPASS1_DISABLE | LIS3_HIPASS2_DISABLE,
+
+ /* Interrupt line 2 for click detection, line 1 for thresholds */
+ .irq_cfg = LIS3_IRQ2_CLICK | LIS3_IRQ1_FF_WU_12,
+
+ .axis_x = LIS3_DEV_X,
+ .axis_y = LIS3_INV_DEV_Y,
+ .axis_z = LIS3_INV_DEV_Z,
+ .setup_resources = lis302_setup,
+ .release_resources = lis302_release,
+ .st_min_limits = {-32, 3, 3},
+ .st_max_limits = {-3, 32, 32},
+ .irq2 = OMAP_GPIO_IRQ(LIS302_IRQ2_GPIO),
+};
+#endif
+
#if defined(CONFIG_SENSORS_TSL2563) || defined(CONFIG_SENSORS_TSL2563_MODULE)
static struct tsl2563_platform_data rx51_tsl2563_platform_data = {
.cover_comp_gain = 16,
@@ -872,11 +947,11 @@ static struct twl4030_power_data rx51_t2scripts_data __initdata = {
.resource_config = twl4030_rconfig,
};
-struct twl4030_vibra_data rx51_vibra_data __initdata = {
+static struct twl4030_vibra_data rx51_vibra_data __initdata = {
.coexist = 0,
};
-struct twl4030_audio_data rx51_audio_data __initdata = {
+static struct twl4030_audio_data rx51_audio_data __initdata = {
.audio_mclk = 26000000,
.vibra = &rx51_vibra_data,
};
@@ -950,6 +1025,16 @@ static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_2[] = {
}
};
+static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_3[] = {
+#if defined(CONFIG_SENSORS_LIS3_I2C) || defined(CONFIG_SENSORS_LIS3_I2C_MODULE)
+ {
+ I2C_BOARD_INFO("lis3lv02d", 0x1d),
+ .platform_data = &rx51_lis3lv02d_data,
+ .irq = OMAP_GPIO_IRQ(LIS302_IRQ1_GPIO),
+ },
+#endif
+};
+
static int __init rx51_i2c_init(void)
{
if ((system_rev >= SYSTEM_REV_S_USES_VAUX3 && system_rev < 0x100) ||
@@ -971,7 +1056,8 @@ static int __init rx51_i2c_init(void)
omap_pmic_init(1, 2200, "twl5030", INT_34XX_SYS_NIRQ, &rx51_twldata);
omap_register_i2c_bus(2, 100, rx51_peripherals_i2c_board_info_2,
ARRAY_SIZE(rx51_peripherals_i2c_board_info_2));
- omap_register_i2c_bus(3, 400, NULL, 0);
+ omap_register_i2c_bus(3, 400, rx51_peripherals_i2c_board_info_3,
+ ARRAY_SIZE(rx51_peripherals_i2c_board_info_3));
return 0;
}
diff --git a/arch/arm/mach-omap2/board-rx51.c b/arch/arm/mach-omap2/board-rx51.c
index 27f01f051dff..2da92a6ba40a 100644
--- a/arch/arm/mach-omap2/board-rx51.c
+++ b/arch/arm/mach-omap2/board-rx51.c
@@ -59,25 +59,24 @@ static struct platform_device leds_gpio = {
};
/*
- * cpuidle C-states definition override from the default values.
- * The 'exit_latency' field is the sum of sleep and wake-up latencies.
- */
-static struct cpuidle_params rx51_cpuidle_params[] = {
- /* C1 */
- {110 + 162, 5 , 1},
- /* C2 */
- {106 + 180, 309, 1},
- /* C3 */
- {107 + 410, 46057, 0},
- /* C4 */
- {121 + 3374, 46057, 0},
- /* C5 */
- {855 + 1146, 46057, 1},
- /* C6 */
- {7580 + 4134, 484329, 0},
- /* C7 */
- {7505 + 15274, 484329, 1},
-};
+ * cpuidle C-states definition for rx51.
+ *
+ * The 'exit_latency' field is the sum of sleep
+ * and wake-up latencies.
+
+ ---------------------------------------------
+ | state | exit_latency | target_residency |
+ ---------------------------------------------
+ | C1 | 110 + 162 | 5 |
+ | C2 | 106 + 180 | 309 |
+ | C3 | 107 + 410 | 46057 |
+ | C4 | 121 + 3374 | 46057 |
+ | C5 | 855 + 1146 | 46057 |
+ | C6 | 7580 + 4134 | 484329 |
+ | C7 | 7505 + 15274 | 484329 |
+ ---------------------------------------------
+
+*/
extern void __init rx51_peripherals_init(void);
@@ -98,7 +97,6 @@ static void __init rx51_init(void)
struct omap_sdrc_params *sdrc_params;
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
- omap3_pm_init_cpuidle(rx51_cpuidle_params);
omap_serial_init();
sdrc_params = nokia_get_sdram_timings();
diff --git a/arch/arm/mach-omap2/board-zoom-display.c b/arch/arm/mach-omap2/board-zoom-display.c
index a43a765dd092..28187f134fff 100644
--- a/arch/arm/mach-omap2/board-zoom-display.c
+++ b/arch/arm/mach-omap2/board-zoom-display.c
@@ -16,6 +16,7 @@
#include <linux/spi/spi.h>
#include <plat/mcspi.h>
#include <video/omapdss.h>
+#include <mach/board-zoom.h>
#define LCD_PANEL_RESET_GPIO_PROD 96
#define LCD_PANEL_RESET_GPIO_PILOT 55
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index d9f4931513f9..5c4e66542169 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -439,7 +439,7 @@ void omap2_clk_disable_unused(struct clk *clk)
clk->ops->disable(clk);
}
if (clk->clkdm != NULL)
- pwrdm_clkdm_state_switch(clk->clkdm);
+ pwrdm_state_switch(clk->clkdm->pwrdm.ptr);
}
#endif
diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c
index f4a626f7c79e..4e1a3b0e8cc8 100644
--- a/arch/arm/mach-omap2/clock3xxx_data.c
+++ b/arch/arm/mach-omap2/clock3xxx_data.c
@@ -1,7 +1,7 @@
/*
* OMAP3 clock data
*
- * Copyright (C) 2007-2010 Texas Instruments, Inc.
+ * Copyright (C) 2007-2010, 2012 Texas Instruments, Inc.
* Copyright (C) 2007-2011 Nokia Corporation
*
* Written by Paul Walmsley
@@ -1640,6 +1640,7 @@ static struct clk hdq_fck = {
.name = "hdq_fck",
.ops = &clkops_omap2_dflt_wait,
.parent = &core_12m_fck,
+ .clkdm_name = "core_l4_clkdm",
.enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1),
.enable_bit = OMAP3430_EN_HDQ_SHIFT,
.recalc = &followparent_recalc,
@@ -3294,8 +3295,8 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "gfx_l3_ick", &gfx_l3_ick, CK_3430ES1),
CLK(NULL, "gfx_cg1_ck", &gfx_cg1_ck, CK_3430ES1),
CLK(NULL, "gfx_cg2_ck", &gfx_cg2_ck, CK_3430ES1),
- CLK(NULL, "sgx_fck", &sgx_fck, CK_3430ES2PLUS | CK_3517 | CK_36XX),
- CLK(NULL, "sgx_ick", &sgx_ick, CK_3430ES2PLUS | CK_3517 | CK_36XX),
+ CLK(NULL, "sgx_fck", &sgx_fck, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
+ CLK(NULL, "sgx_ick", &sgx_ick, CK_3430ES2PLUS | CK_AM35XX | CK_36XX),
CLK(NULL, "d2d_26m_fck", &d2d_26m_fck, CK_3430ES1),
CLK(NULL, "modem_fck", &modem_fck, CK_34XX | CK_36XX),
CLK(NULL, "sad2d_ick", &sad2d_ick, CK_34XX | CK_36XX),
@@ -3419,7 +3420,7 @@ static struct omap_clk omap3xxx_clks[] = {
CLK(NULL, "per_48m_fck", &per_48m_fck, CK_3XXX),
CLK(NULL, "uart3_fck", &uart3_fck, CK_3XXX),
CLK(NULL, "uart4_fck", &uart4_fck, CK_36XX),
- CLK(NULL, "uart4_fck", &uart4_fck_am35xx, CK_3505 | CK_3517),
+ CLK(NULL, "uart4_fck", &uart4_fck_am35xx, CK_AM35XX),
CLK(NULL, "gpt2_fck", &gpt2_fck, CK_3XXX),
CLK(NULL, "gpt3_fck", &gpt3_fck, CK_3XXX),
CLK(NULL, "gpt4_fck", &gpt4_fck, CK_3XXX),
@@ -3513,21 +3514,9 @@ int __init omap3xxx_clk_init(void)
struct omap_clk *c;
u32 cpu_clkflg = 0;
- /*
- * 3505 must be tested before 3517, since 3517 returns true
- * for both AM3517 chips and AM3517 family chips, which
- * includes 3505. Unfortunately there's no obvious family
- * test for 3517/3505 :-(
- */
- if (cpu_is_omap3505()) {
- cpu_mask = RATE_IN_34XX;
- cpu_clkflg = CK_3505;
- } else if (cpu_is_omap3517()) {
- cpu_mask = RATE_IN_34XX;
- cpu_clkflg = CK_3517;
- } else if (cpu_is_omap3505()) {
+ if (cpu_is_omap3517()) {
cpu_mask = RATE_IN_34XX;
- cpu_clkflg = CK_3505;
+ cpu_clkflg = CK_AM35XX;
} else if (cpu_is_omap3630()) {
cpu_mask = (RATE_IN_34XX | RATE_IN_36XX);
cpu_clkflg = CK_36XX;
diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c
index fa6ea65ad44b..2172f6603848 100644
--- a/arch/arm/mach-omap2/clock44xx_data.c
+++ b/arch/arm/mach-omap2/clock44xx_data.c
@@ -3355,17 +3355,6 @@ static struct omap_clk omap44xx_clks[] = {
CLK(NULL, "auxclk5_ck", &auxclk5_ck, CK_443X),
CLK(NULL, "auxclkreq5_ck", &auxclkreq5_ck, CK_443X),
CLK(NULL, "gpmc_ck", &dummy_ck, CK_443X),
- CLK(NULL, "gpt1_ick", &dummy_ck, CK_443X),
- CLK(NULL, "gpt2_ick", &dummy_ck, CK_443X),
- CLK(NULL, "gpt3_ick", &dummy_ck, CK_443X),
- CLK(NULL, "gpt4_ick", &dummy_ck, CK_443X),
- CLK(NULL, "gpt5_ick", &dummy_ck, CK_443X),
- CLK(NULL, "gpt6_ick", &dummy_ck, CK_443X),
- CLK(NULL, "gpt7_ick", &dummy_ck, CK_443X),
- CLK(NULL, "gpt8_ick", &dummy_ck, CK_443X),
- CLK(NULL, "gpt9_ick", &dummy_ck, CK_443X),
- CLK(NULL, "gpt10_ick", &dummy_ck, CK_443X),
- CLK(NULL, "gpt11_ick", &dummy_ck, CK_443X),
CLK("omap_i2c.1", "ick", &dummy_ck, CK_443X),
CLK("omap_i2c.2", "ick", &dummy_ck, CK_443X),
CLK("omap_i2c.3", "ick", &dummy_ck, CK_443X),
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index ad07689e1563..8664f5a8bfb6 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -840,7 +840,7 @@ void clkdm_allow_idle(struct clockdomain *clkdm)
spin_lock_irqsave(&clkdm->lock, flags);
clkdm->_flags |= _CLKDM_FLAG_HWSUP_ENABLED;
arch_clkdm->clkdm_allow_idle(clkdm);
- pwrdm_clkdm_state_switch(clkdm);
+ pwrdm_state_switch(clkdm->pwrdm.ptr);
spin_unlock_irqrestore(&clkdm->lock, flags);
}
@@ -924,8 +924,7 @@ static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm)
spin_lock_irqsave(&clkdm->lock, flags);
arch_clkdm->clkdm_clk_enable(clkdm);
- pwrdm_wait_transition(clkdm->pwrdm.ptr);
- pwrdm_clkdm_state_switch(clkdm);
+ pwrdm_state_switch(clkdm->pwrdm.ptr);
spin_unlock_irqrestore(&clkdm->lock, flags);
pr_debug("clockdomain: clkdm %s: enabled\n", clkdm->name);
@@ -950,7 +949,7 @@ static int _clkdm_clk_hwmod_disable(struct clockdomain *clkdm)
spin_lock_irqsave(&clkdm->lock, flags);
arch_clkdm->clkdm_clk_disable(clkdm);
- pwrdm_clkdm_state_switch(clkdm);
+ pwrdm_state_switch(clkdm->pwrdm.ptr);
spin_unlock_irqrestore(&clkdm->lock, flags);
pr_debug("clockdomain: clkdm %s: disabled\n", clkdm->name);
diff --git a/arch/arm/mach-omap2/clockdomain44xx.c b/arch/arm/mach-omap2/clockdomain44xx.c
index 935c7f03dab9..4f04dd11d655 100644
--- a/arch/arm/mach-omap2/clockdomain44xx.c
+++ b/arch/arm/mach-omap2/clockdomain44xx.c
@@ -51,6 +51,9 @@ static int omap4_clkdm_clear_all_wkup_sleep_deps(struct clockdomain *clkdm)
struct clkdm_dep *cd;
u32 mask = 0;
+ if (!clkdm->prcm_partition)
+ return 0;
+
for (cd = clkdm->wkdep_srcs; cd && cd->clkdm_name; cd++) {
if (!cd->clkdm)
continue; /* only happens if data is erroneous */
@@ -103,6 +106,9 @@ static int omap4_clkdm_clk_disable(struct clockdomain *clkdm)
{
bool hwsup = false;
+ if (!clkdm->prcm_partition)
+ return 0;
+
hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition,
clkdm->cm_inst, clkdm->clkdm_offs);
diff --git a/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c b/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c
index 0a6a04897d89..839145e1cfbe 100644
--- a/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c
+++ b/arch/arm/mach-omap2/clockdomains2xxx_3xxx_data.c
@@ -89,13 +89,3 @@ struct clockdomain wkup_common_clkdm = {
.pwrdm = { .name = "wkup_pwrdm" },
.dep_bit = OMAP_EN_WKUP_SHIFT,
};
-
-struct clockdomain prm_common_clkdm = {
- .name = "prm_clkdm",
- .pwrdm = { .name = "wkup_pwrdm" },
-};
-
-struct clockdomain cm_common_clkdm = {
- .name = "cm_clkdm",
- .pwrdm = { .name = "core_pwrdm" },
-};
diff --git a/arch/arm/mach-omap2/clockdomains3xxx_data.c b/arch/arm/mach-omap2/clockdomains3xxx_data.c
index b84e138d99c8..6038adb97710 100644
--- a/arch/arm/mach-omap2/clockdomains3xxx_data.c
+++ b/arch/arm/mach-omap2/clockdomains3xxx_data.c
@@ -53,9 +53,9 @@
* 3430ES2 PM_WKDEP_SGX: adds IVA2, removes CORE
*/
static struct clkdm_dep gfx_sgx_3xxx_wkdeps[] = {
- { .clkdm_name = "iva2_clkdm", },
- { .clkdm_name = "mpu_clkdm", },
- { .clkdm_name = "wkup_clkdm", },
+ { .clkdm_name = "iva2_clkdm" },
+ { .clkdm_name = "mpu_clkdm" },
+ { .clkdm_name = "wkup_clkdm" },
{ NULL },
};
diff --git a/arch/arm/mach-omap2/clockdomains44xx_data.c b/arch/arm/mach-omap2/clockdomains44xx_data.c
index bd7ed13515cc..c53425847493 100644
--- a/arch/arm/mach-omap2/clockdomains44xx_data.c
+++ b/arch/arm/mach-omap2/clockdomains44xx_data.c
@@ -430,6 +430,8 @@ static struct clockdomain *clockdomains_omap44xx[] __initdata = {
&l4_wkup_44xx_clkdm,
&emu_sys_44xx_clkdm,
&l3_dma_44xx_clkdm,
+ &prm_common_clkdm,
+ &cm_common_clkdm,
NULL
};
diff --git a/arch/arm/mach-omap2/clockdomains_common_data.c b/arch/arm/mach-omap2/clockdomains_common_data.c
new file mode 100644
index 000000000000..615b1f04967d
--- /dev/null
+++ b/arch/arm/mach-omap2/clockdomains_common_data.c
@@ -0,0 +1,24 @@
+/*
+ * OMAP2+-common clockdomain data
+ *
+ * Copyright (C) 2008-2012 Texas Instruments, Inc.
+ * Copyright (C) 2008-2010 Nokia Corporation
+ *
+ * Paul Walmsley, Jouni Högander
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+
+#include "clockdomain.h"
+
+/* These are implicit clockdomains - they are never defined as such in TRM */
+struct clockdomain prm_common_clkdm = {
+ .name = "prm_clkdm",
+ .pwrdm = { .name = "wkup_pwrdm" },
+};
+
+struct clockdomain cm_common_clkdm = {
+ .name = "cm_clkdm",
+ .pwrdm = { .name = "core_pwrdm" },
+};
diff --git a/arch/arm/mach-omap2/cm-regbits-34xx.h b/arch/arm/mach-omap2/cm-regbits-34xx.h
index b91275908f33..8083a8cdc55f 100644
--- a/arch/arm/mach-omap2/cm-regbits-34xx.h
+++ b/arch/arm/mach-omap2/cm-regbits-34xx.h
@@ -79,7 +79,7 @@
/* CM_CLKSEL1_PLL_IVA2 */
#define OMAP3430_IVA2_CLK_SRC_SHIFT 19
-#define OMAP3430_IVA2_CLK_SRC_MASK (0x3 << 19)
+#define OMAP3430_IVA2_CLK_SRC_MASK (0x7 << 19)
#define OMAP3430_IVA2_DPLL_MULT_SHIFT 8
#define OMAP3430_IVA2_DPLL_MULT_MASK (0x7ff << 8)
#define OMAP3430_IVA2_DPLL_DIV_SHIFT 0
@@ -124,7 +124,7 @@
/* CM_CLKSEL1_PLL_MPU */
#define OMAP3430_MPU_CLK_SRC_SHIFT 19
-#define OMAP3430_MPU_CLK_SRC_MASK (0x3 << 19)
+#define OMAP3430_MPU_CLK_SRC_MASK (0x7 << 19)
#define OMAP3430_MPU_DPLL_MULT_SHIFT 8
#define OMAP3430_MPU_DPLL_MULT_MASK (0x7ff << 8)
#define OMAP3430_MPU_DPLL_DIV_SHIFT 0
diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c
index bd8810c3753f..8c86d294b1a3 100644
--- a/arch/arm/mach-omap2/cminst44xx.c
+++ b/arch/arm/mach-omap2/cminst44xx.c
@@ -32,6 +32,7 @@
#include "prcm44xx.h"
#include "prm44xx.h"
#include "prcm_mpu44xx.h"
+#include "prcm-common.h"
/*
* CLKCTRL_IDLEST_*: possible values for the CM_*_CLKCTRL.IDLEST bitfield:
@@ -49,14 +50,21 @@
#define CLKCTRL_IDLEST_INTERFACE_IDLE 0x2
#define CLKCTRL_IDLEST_DISABLED 0x3
-static u32 _cm_bases[OMAP4_MAX_PRCM_PARTITIONS] = {
- [OMAP4430_INVALID_PRCM_PARTITION] = 0,
- [OMAP4430_PRM_PARTITION] = OMAP4430_PRM_BASE,
- [OMAP4430_CM1_PARTITION] = OMAP4430_CM1_BASE,
- [OMAP4430_CM2_PARTITION] = OMAP4430_CM2_BASE,
- [OMAP4430_SCRM_PARTITION] = 0,
- [OMAP4430_PRCM_MPU_PARTITION] = OMAP4430_PRCM_MPU_BASE,
-};
+static void __iomem *_cm_bases[OMAP4_MAX_PRCM_PARTITIONS];
+
+/**
+ * omap_cm_base_init - Populates the cm partitions
+ *
+ * Populates the base addresses of the _cm_bases
+ * array used for read/write of cm module registers.
+ */
+void omap_cm_base_init(void)
+{
+ _cm_bases[OMAP4430_PRM_PARTITION] = prm_base;
+ _cm_bases[OMAP4430_CM1_PARTITION] = cm_base;
+ _cm_bases[OMAP4430_CM2_PARTITION] = cm2_base;
+ _cm_bases[OMAP4430_PRCM_MPU_PARTITION] = prcm_mpu_base;
+}
/* Private functions */
@@ -106,7 +114,7 @@ u32 omap4_cminst_read_inst_reg(u8 part, s16 inst, u16 idx)
BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS ||
part == OMAP4430_INVALID_PRCM_PARTITION ||
!_cm_bases[part]);
- return __raw_readl(OMAP2_L4_IO_ADDRESS(_cm_bases[part] + inst + idx));
+ return __raw_readl(_cm_bases[part] + inst + idx);
}
/* Write into a register in a CM instance */
@@ -115,7 +123,7 @@ void omap4_cminst_write_inst_reg(u32 val, u8 part, s16 inst, u16 idx)
BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS ||
part == OMAP4430_INVALID_PRCM_PARTITION ||
!_cm_bases[part]);
- __raw_writel(val, OMAP2_L4_IO_ADDRESS(_cm_bases[part] + inst + idx));
+ __raw_writel(val, _cm_bases[part] + inst + idx);
}
/* Read-modify-write a register in CM1. Caller must lock */
diff --git a/arch/arm/mach-omap2/common.c b/arch/arm/mach-omap2/common.c
index 1549c11000d3..8a6953a34fe2 100644
--- a/arch/arm/mach-omap2/common.c
+++ b/arch/arm/mach-omap2/common.c
@@ -166,6 +166,7 @@ static struct omap_globals omap4_globals = {
.prm = OMAP2_L4_IO_ADDRESS(OMAP4430_PRM_BASE),
.cm = OMAP2_L4_IO_ADDRESS(OMAP4430_CM_BASE),
.cm2 = OMAP2_L4_IO_ADDRESS(OMAP4430_CM2_BASE),
+ .prcm_mpu = OMAP2_L4_IO_ADDRESS(OMAP4430_PRCM_MPU_BASE),
};
void __init omap2_set_globals_443x(void)
diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
index 57da7f406e28..d6c9e6180318 100644
--- a/arch/arm/mach-omap2/common.h
+++ b/arch/arm/mach-omap2/common.h
@@ -27,6 +27,7 @@
#ifndef __ASSEMBLER__
#include <linux/delay.h>
+#include <linux/i2c/twl.h>
#include <plat/common.h>
#include <asm/proc-fns.h>
@@ -111,6 +112,7 @@ struct omap_globals {
void __iomem *prm; /* Power and Reset Management */
void __iomem *cm; /* Clock Management */
void __iomem *cm2;
+ void __iomem *prcm_mpu;
};
void omap2_set_globals_242x(void);
@@ -134,8 +136,6 @@ void omap4_map_io(void);
void ti81xx_map_io(void);
void omap_barriers_init(void);
-extern void __init omap_init_consistent_dma_size(void);
-
/**
* omap_test_timeout - busy-loop, testing a condition
* @cond: condition to test until it evaluates to true
@@ -254,6 +254,8 @@ static inline u32 omap4_mpuss_read_prev_context_state(void)
struct omap_sdrc_params;
extern void omap_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
struct omap_sdrc_params *sdrc_cs1);
+struct omap2_hsmmc_info;
+extern int omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers);
#endif /* __ASSEMBLER__ */
#endif /* __ARCH_ARM_MACH_OMAP2PLUS_COMMON_H */
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index 535866489ce3..207bc1c7759f 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -38,40 +38,44 @@
#ifdef CONFIG_CPU_IDLE
-/*
- * The latencies/thresholds for various C states have
- * to be configured from the respective board files.
- * These are some default values (which might not provide
- * the best power savings) used on boards which do not
- * pass these details from the board file.
- */
-static struct cpuidle_params cpuidle_params_table[] = {
- /* C1 */
- {2 + 2, 5, 1},
- /* C2 */
- {10 + 10, 30, 1},
- /* C3 */
- {50 + 50, 300, 1},
- /* C4 */
- {1500 + 1800, 4000, 1},
- /* C5 */
- {2500 + 7500, 12000, 1},
- /* C6 */
- {3000 + 8500, 15000, 1},
- /* C7 */
- {10000 + 30000, 300000, 1},
-};
-#define OMAP3_NUM_STATES ARRAY_SIZE(cpuidle_params_table)
-
/* Mach specific information to be recorded in the C-state driver_data */
struct omap3_idle_statedata {
u32 mpu_state;
u32 core_state;
- u8 valid;
};
-struct omap3_idle_statedata omap3_idle_data[OMAP3_NUM_STATES];
-struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd;
+static struct omap3_idle_statedata omap3_idle_data[] = {
+ {
+ .mpu_state = PWRDM_POWER_ON,
+ .core_state = PWRDM_POWER_ON,
+ },
+ {
+ .mpu_state = PWRDM_POWER_ON,
+ .core_state = PWRDM_POWER_ON,
+ },
+ {
+ .mpu_state = PWRDM_POWER_RET,
+ .core_state = PWRDM_POWER_ON,
+ },
+ {
+ .mpu_state = PWRDM_POWER_OFF,
+ .core_state = PWRDM_POWER_ON,
+ },
+ {
+ .mpu_state = PWRDM_POWER_RET,
+ .core_state = PWRDM_POWER_RET,
+ },
+ {
+ .mpu_state = PWRDM_POWER_OFF,
+ .core_state = PWRDM_POWER_RET,
+ },
+ {
+ .mpu_state = PWRDM_POWER_OFF,
+ .core_state = PWRDM_POWER_OFF,
+ },
+};
+
+static struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd;
static int _cpuidle_allow_idle(struct powerdomain *pwrdm,
struct clockdomain *clkdm)
@@ -91,8 +95,7 @@ static int __omap3_enter_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
- struct omap3_idle_statedata *cx =
- cpuidle_get_statedata(&dev->states_usage[index]);
+ struct omap3_idle_statedata *cx = &omap3_idle_data[index];
u32 mpu_state = cx->mpu_state, core_state = cx->core_state;
local_fiq_disable();
@@ -169,14 +172,12 @@ static inline int omap3_enter_idle(struct cpuidle_device *dev,
* if it satisfies the enable_off_mode condition.
*/
static int next_valid_state(struct cpuidle_device *dev,
- struct cpuidle_driver *drv,
- int index)
+ struct cpuidle_driver *drv, int index)
{
- struct cpuidle_state_usage *curr_usage = &dev->states_usage[index];
- struct cpuidle_state *curr = &drv->states[index];
- struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr_usage);
+ struct omap3_idle_statedata *cx = &omap3_idle_data[index];
u32 mpu_deepest_state = PWRDM_POWER_RET;
u32 core_deepest_state = PWRDM_POWER_RET;
+ int idx;
int next_index = -1;
if (enable_off_mode) {
@@ -191,45 +192,29 @@ static int next_valid_state(struct cpuidle_device *dev,
}
/* Check if current state is valid */
- if ((cx->valid) &&
- (cx->mpu_state >= mpu_deepest_state) &&
- (cx->core_state >= core_deepest_state)) {
+ if ((cx->mpu_state >= mpu_deepest_state) &&
+ (cx->core_state >= core_deepest_state))
return index;
- } else {
- int idx = OMAP3_NUM_STATES - 1;
-
- /* Reach the current state starting at highest C-state */
- for (; idx >= 0; idx--) {
- if (&drv->states[idx] == curr) {
- next_index = idx;
- break;
- }
- }
-
- /* Should never hit this condition */
- WARN_ON(next_index == -1);
- /*
- * Drop to next valid state.
- * Start search from the next (lower) state.
- */
- idx--;
- for (; idx >= 0; idx--) {
- cx = cpuidle_get_statedata(&dev->states_usage[idx]);
- if ((cx->valid) &&
- (cx->mpu_state >= mpu_deepest_state) &&
- (cx->core_state >= core_deepest_state)) {
- next_index = idx;
- break;
- }
+ /*
+ * Drop to next valid state.
+ * Start search from the next (lower) state.
+ */
+ for (idx = index - 1; idx >= 0; idx--) {
+ cx = &omap3_idle_data[idx];
+ if ((cx->mpu_state >= mpu_deepest_state) &&
+ (cx->core_state >= core_deepest_state)) {
+ next_index = idx;
+ break;
}
- /*
- * C1 is always valid.
- * So, no need to check for 'next_index == -1' outside
- * this loop.
- */
}
+ /*
+ * C1 is always valid.
+ * So, no need to check for 'next_index == -1' outside
+ * this loop.
+ */
+
return next_index;
}
@@ -273,7 +258,7 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
* Prevent PER off if CORE is not in retention or off as this
* would disable PER wakeups completely.
*/
- cx = cpuidle_get_statedata(&dev->states_usage[index]);
+ cx = &omap3_idle_data[index];
core_next_state = cx->core_state;
per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd);
if ((per_next_state == PWRDM_POWER_OFF) &&
@@ -298,57 +283,71 @@ select_state:
DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev);
-void omap3_pm_init_cpuidle(struct cpuidle_params *cpuidle_board_params)
-{
- int i;
-
- if (!cpuidle_board_params)
- return;
-
- for (i = 0; i < OMAP3_NUM_STATES; i++) {
- cpuidle_params_table[i].valid = cpuidle_board_params[i].valid;
- cpuidle_params_table[i].exit_latency =
- cpuidle_board_params[i].exit_latency;
- cpuidle_params_table[i].target_residency =
- cpuidle_board_params[i].target_residency;
- }
- return;
-}
-
struct cpuidle_driver omap3_idle_driver = {
.name = "omap3_idle",
.owner = THIS_MODULE,
+ .states = {
+ {
+ .enter = omap3_enter_idle,
+ .exit_latency = 2 + 2,
+ .target_residency = 5,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .name = "C1",
+ .desc = "MPU ON + CORE ON",
+ },
+ {
+ .enter = omap3_enter_idle_bm,
+ .exit_latency = 10 + 10,
+ .target_residency = 30,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .name = "C2",
+ .desc = "MPU ON + CORE ON",
+ },
+ {
+ .enter = omap3_enter_idle_bm,
+ .exit_latency = 50 + 50,
+ .target_residency = 300,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .name = "C3",
+ .desc = "MPU RET + CORE ON",
+ },
+ {
+ .enter = omap3_enter_idle_bm,
+ .exit_latency = 1500 + 1800,
+ .target_residency = 4000,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .name = "C4",
+ .desc = "MPU OFF + CORE ON",
+ },
+ {
+ .enter = omap3_enter_idle_bm,
+ .exit_latency = 2500 + 7500,
+ .target_residency = 12000,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .name = "C5",
+ .desc = "MPU RET + CORE RET",
+ },
+ {
+ .enter = omap3_enter_idle_bm,
+ .exit_latency = 3000 + 8500,
+ .target_residency = 15000,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .name = "C6",
+ .desc = "MPU OFF + CORE RET",
+ },
+ {
+ .enter = omap3_enter_idle_bm,
+ .exit_latency = 10000 + 30000,
+ .target_residency = 30000,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .name = "C7",
+ .desc = "MPU OFF + CORE OFF",
+ },
+ },
+ .state_count = ARRAY_SIZE(omap3_idle_data),
+ .safe_state_index = 0,
};
-/* Helper to fill the C-state common data*/
-static inline void _fill_cstate(struct cpuidle_driver *drv,
- int idx, const char *descr)
-{
- struct cpuidle_state *state = &drv->states[idx];
-
- state->exit_latency = cpuidle_params_table[idx].exit_latency;
- state->target_residency = cpuidle_params_table[idx].target_residency;
- state->flags = CPUIDLE_FLAG_TIME_VALID;
- state->enter = omap3_enter_idle_bm;
- sprintf(state->name, "C%d", idx + 1);
- strncpy(state->desc, descr, CPUIDLE_DESC_LEN);
-
-}
-
-/* Helper to register the driver_data */
-static inline struct omap3_idle_statedata *_fill_cstate_usage(
- struct cpuidle_device *dev,
- int idx)
-{
- struct omap3_idle_statedata *cx = &omap3_idle_data[idx];
- struct cpuidle_state_usage *state_usage = &dev->states_usage[idx];
-
- cx->valid = cpuidle_params_table[idx].valid;
- cpuidle_set_statedata(state_usage, cx);
-
- return cx;
-}
-
/**
* omap3_idle_init - Init routine for OMAP3 idle
*
@@ -358,77 +357,20 @@ static inline struct omap3_idle_statedata *_fill_cstate_usage(
int __init omap3_idle_init(void)
{
struct cpuidle_device *dev;
- struct cpuidle_driver *drv = &omap3_idle_driver;
- struct omap3_idle_statedata *cx;
mpu_pd = pwrdm_lookup("mpu_pwrdm");
core_pd = pwrdm_lookup("core_pwrdm");
per_pd = pwrdm_lookup("per_pwrdm");
cam_pd = pwrdm_lookup("cam_pwrdm");
+ if (!mpu_pd || !core_pd || !per_pd || !cam_pd)
+ return -ENODEV;
- drv->safe_state_index = -1;
- dev = &per_cpu(omap3_idle_dev, smp_processor_id());
-
- /* C1 . MPU WFI + Core active */
- _fill_cstate(drv, 0, "MPU ON + CORE ON");
- (&drv->states[0])->enter = omap3_enter_idle;
- drv->safe_state_index = 0;
- cx = _fill_cstate_usage(dev, 0);
- cx->valid = 1; /* C1 is always valid */
- cx->mpu_state = PWRDM_POWER_ON;
- cx->core_state = PWRDM_POWER_ON;
-
- /* C2 . MPU WFI + Core inactive */
- _fill_cstate(drv, 1, "MPU ON + CORE ON");
- cx = _fill_cstate_usage(dev, 1);
- cx->mpu_state = PWRDM_POWER_ON;
- cx->core_state = PWRDM_POWER_ON;
-
- /* C3 . MPU CSWR + Core inactive */
- _fill_cstate(drv, 2, "MPU RET + CORE ON");
- cx = _fill_cstate_usage(dev, 2);
- cx->mpu_state = PWRDM_POWER_RET;
- cx->core_state = PWRDM_POWER_ON;
-
- /* C4 . MPU OFF + Core inactive */
- _fill_cstate(drv, 3, "MPU OFF + CORE ON");
- cx = _fill_cstate_usage(dev, 3);
- cx->mpu_state = PWRDM_POWER_OFF;
- cx->core_state = PWRDM_POWER_ON;
-
- /* C5 . MPU RET + Core RET */
- _fill_cstate(drv, 4, "MPU RET + CORE RET");
- cx = _fill_cstate_usage(dev, 4);
- cx->mpu_state = PWRDM_POWER_RET;
- cx->core_state = PWRDM_POWER_RET;
-
- /* C6 . MPU OFF + Core RET */
- _fill_cstate(drv, 5, "MPU OFF + CORE RET");
- cx = _fill_cstate_usage(dev, 5);
- cx->mpu_state = PWRDM_POWER_OFF;
- cx->core_state = PWRDM_POWER_RET;
-
- /* C7 . MPU OFF + Core OFF */
- _fill_cstate(drv, 6, "MPU OFF + CORE OFF");
- cx = _fill_cstate_usage(dev, 6);
- /*
- * Erratum i583: implementation for ES rev < Es1.2 on 3630. We cannot
- * enable OFF mode in a stable form for previous revisions.
- * We disable C7 state as a result.
- */
- if (IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583)) {
- cx->valid = 0;
- pr_warn("%s: core off state C7 disabled due to i583\n",
- __func__);
- }
- cx->mpu_state = PWRDM_POWER_OFF;
- cx->core_state = PWRDM_POWER_OFF;
-
- drv->state_count = OMAP3_NUM_STATES;
cpuidle_register_driver(&omap3_idle_driver);
- dev->state_count = OMAP3_NUM_STATES;
+ dev = &per_cpu(omap3_idle_dev, smp_processor_id());
+ dev->cpu = 0;
+
if (cpuidle_register_device(dev)) {
printk(KERN_ERR "%s: CPUidle register device failed\n",
__func__);
diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c
index f386cbe9c889..be1617ca84bd 100644
--- a/arch/arm/mach-omap2/cpuidle44xx.c
+++ b/arch/arm/mach-omap2/cpuidle44xx.c
@@ -24,26 +24,31 @@
#ifdef CONFIG_CPU_IDLE
-/* Machine specific information to be recorded in the C-state driver_data */
+/* Machine specific information */
struct omap4_idle_statedata {
u32 cpu_state;
u32 mpu_logic_state;
u32 mpu_state;
- u8 valid;
};
-static struct cpuidle_params cpuidle_params_table[] = {
- /* C1 - CPU0 ON + CPU1 ON + MPU ON */
- {.exit_latency = 2 + 2 , .target_residency = 5, .valid = 1},
- /* C2- CPU0 OFF + CPU1 OFF + MPU CSWR */
- {.exit_latency = 328 + 440 , .target_residency = 960, .valid = 1},
- /* C3 - CPU0 OFF + CPU1 OFF + MPU OSWR */
- {.exit_latency = 460 + 518 , .target_residency = 1100, .valid = 1},
+static struct omap4_idle_statedata omap4_idle_data[] = {
+ {
+ .cpu_state = PWRDM_POWER_ON,
+ .mpu_state = PWRDM_POWER_ON,
+ .mpu_logic_state = PWRDM_POWER_RET,
+ },
+ {
+ .cpu_state = PWRDM_POWER_OFF,
+ .mpu_state = PWRDM_POWER_RET,
+ .mpu_logic_state = PWRDM_POWER_RET,
+ },
+ {
+ .cpu_state = PWRDM_POWER_OFF,
+ .mpu_state = PWRDM_POWER_RET,
+ .mpu_logic_state = PWRDM_POWER_OFF,
+ },
};
-#define OMAP4_NUM_STATES ARRAY_SIZE(cpuidle_params_table)
-
-struct omap4_idle_statedata omap4_idle_data[OMAP4_NUM_STATES];
static struct powerdomain *mpu_pd, *cpu0_pd, *cpu1_pd;
/**
@@ -60,8 +65,7 @@ static int omap4_enter_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
{
- struct omap4_idle_statedata *cx =
- cpuidle_get_statedata(&dev->states_usage[index]);
+ struct omap4_idle_statedata *cx = &omap4_idle_data[index];
u32 cpu1_state;
int cpu_id = smp_processor_id();
@@ -78,7 +82,7 @@ static int omap4_enter_idle(struct cpuidle_device *dev,
cpu1_state = pwrdm_read_pwrst(cpu1_pd);
if (cpu1_state != PWRDM_POWER_OFF) {
index = drv->safe_state_index;
- cx = cpuidle_get_statedata(&dev->states_usage[index]);
+ cx = &omap4_idle_data[index];
}
if (index > 0)
@@ -133,36 +137,39 @@ struct cpuidle_driver omap4_idle_driver = {
.name = "omap4_idle",
.owner = THIS_MODULE,
.en_core_tk_irqen = 1,
+ .states = {
+ {
+ /* C1 - CPU0 ON + CPU1 ON + MPU ON */
+ .exit_latency = 2 + 2,
+ .target_residency = 5,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .enter = omap4_enter_idle,
+ .name = "C1",
+ .desc = "MPUSS ON"
+ },
+ {
+ /* C2 - CPU0 OFF + CPU1 OFF + MPU CSWR */
+ .exit_latency = 328 + 440,
+ .target_residency = 960,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .enter = omap4_enter_idle,
+ .name = "C2",
+ .desc = "MPUSS CSWR",
+ },
+ {
+ /* C3 - CPU0 OFF + CPU1 OFF + MPU OSWR */
+ .exit_latency = 460 + 518,
+ .target_residency = 1100,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .enter = omap4_enter_idle,
+ .name = "C3",
+ .desc = "MPUSS OSWR",
+ },
+ },
+ .state_count = ARRAY_SIZE(omap4_idle_data),
+ .safe_state_index = 0,
};
-static inline void _fill_cstate(struct cpuidle_driver *drv,
- int idx, const char *descr)
-{
- struct cpuidle_state *state = &drv->states[idx];
-
- state->exit_latency = cpuidle_params_table[idx].exit_latency;
- state->target_residency = cpuidle_params_table[idx].target_residency;
- state->flags = CPUIDLE_FLAG_TIME_VALID;
- state->enter = omap4_enter_idle;
- sprintf(state->name, "C%d", idx + 1);
- strncpy(state->desc, descr, CPUIDLE_DESC_LEN);
-}
-
-static inline struct omap4_idle_statedata *_fill_cstate_usage(
- struct cpuidle_device *dev,
- int idx)
-{
- struct omap4_idle_statedata *cx = &omap4_idle_data[idx];
- struct cpuidle_state_usage *state_usage = &dev->states_usage[idx];
-
- cx->valid = cpuidle_params_table[idx].valid;
- cpuidle_set_statedata(state_usage, cx);
-
- return cx;
-}
-
-
-
/**
* omap4_idle_init - Init routine for OMAP4 idle
*
@@ -171,9 +178,7 @@ static inline struct omap4_idle_statedata *_fill_cstate_usage(
*/
int __init omap4_idle_init(void)
{
- struct omap4_idle_statedata *cx;
struct cpuidle_device *dev;
- struct cpuidle_driver *drv = &omap4_idle_driver;
unsigned int cpu_id = 0;
mpu_pd = pwrdm_lookup("mpu_pwrdm");
@@ -182,42 +187,15 @@ int __init omap4_idle_init(void)
if ((!mpu_pd) || (!cpu0_pd) || (!cpu1_pd))
return -ENODEV;
-
- drv->safe_state_index = -1;
dev = &per_cpu(omap4_idle_dev, cpu_id);
dev->cpu = cpu_id;
- /* C1 - CPU0 ON + CPU1 ON + MPU ON */
- _fill_cstate(drv, 0, "MPUSS ON");
- drv->safe_state_index = 0;
- cx = _fill_cstate_usage(dev, 0);
- cx->valid = 1; /* C1 is always valid */
- cx->cpu_state = PWRDM_POWER_ON;
- cx->mpu_state = PWRDM_POWER_ON;
- cx->mpu_logic_state = PWRDM_POWER_RET;
-
- /* C2 - CPU0 OFF + CPU1 OFF + MPU CSWR */
- _fill_cstate(drv, 1, "MPUSS CSWR");
- cx = _fill_cstate_usage(dev, 1);
- cx->cpu_state = PWRDM_POWER_OFF;
- cx->mpu_state = PWRDM_POWER_RET;
- cx->mpu_logic_state = PWRDM_POWER_RET;
-
- /* C3 - CPU0 OFF + CPU1 OFF + MPU OSWR */
- _fill_cstate(drv, 2, "MPUSS OSWR");
- cx = _fill_cstate_usage(dev, 2);
- cx->cpu_state = PWRDM_POWER_OFF;
- cx->mpu_state = PWRDM_POWER_RET;
- cx->mpu_logic_state = PWRDM_POWER_OFF;
-
- drv->state_count = OMAP4_NUM_STATES;
cpuidle_register_driver(&omap4_idle_driver);
- dev->state_count = OMAP4_NUM_STATES;
if (cpuidle_register_device(dev)) {
pr_err("%s: CPUidle register device failed\n", __func__);
- return -EIO;
- }
+ return -EIO;
+ }
return 0;
}
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index e4336035c0ea..ae62ece04ef9 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -42,7 +42,6 @@
static int __init omap3_l3_init(void)
{
- int l;
struct omap_hwmod *oh;
struct platform_device *pdev;
char oh_name[L3_MODULES_MAX_LEN];
@@ -54,7 +53,7 @@ static int __init omap3_l3_init(void)
if (!(cpu_is_omap34xx()))
return -ENODEV;
- l = snprintf(oh_name, L3_MODULES_MAX_LEN, "l3_main");
+ snprintf(oh_name, L3_MODULES_MAX_LEN, "l3_main");
oh = omap_hwmod_lookup(oh_name);
@@ -72,7 +71,7 @@ postcore_initcall(omap3_l3_init);
static int __init omap4_l3_init(void)
{
- int l, i;
+ int i;
struct omap_hwmod *oh[3];
struct platform_device *pdev;
char oh_name[L3_MODULES_MAX_LEN];
@@ -89,7 +88,7 @@ static int __init omap4_l3_init(void)
return -ENODEV;
for (i = 0; i < L3_MODULES; i++) {
- l = snprintf(oh_name, L3_MODULES_MAX_LEN, "l3_main_%d", i+1);
+ snprintf(oh_name, L3_MODULES_MAX_LEN, "l3_main_%d", i+1);
oh[i] = omap_hwmod_lookup(oh_name);
if (!(oh[i]))
@@ -355,6 +354,36 @@ static void __init omap_init_dmic(void)
static inline void omap_init_dmic(void) {}
#endif
+#if defined(CONFIG_SND_OMAP_SOC_OMAP_HDMI) || \
+ defined(CONFIG_SND_OMAP_SOC_OMAP_HDMI_MODULE)
+
+static struct platform_device omap_hdmi_audio = {
+ .name = "omap-hdmi-audio",
+ .id = -1,
+};
+
+static void __init omap_init_hdmi_audio(void)
+{
+ struct omap_hwmod *oh;
+ struct platform_device *pdev;
+
+ oh = omap_hwmod_lookup("dss_hdmi");
+ if (!oh) {
+ printk(KERN_ERR "Could not look up dss_hdmi hw_mod\n");
+ return;
+ }
+
+ pdev = omap_device_build("omap-hdmi-audio-dai",
+ -1, oh, NULL, 0, NULL, 0, 0);
+ WARN(IS_ERR(pdev),
+ "Can't build omap_device for omap-hdmi-audio-dai.\n");
+
+ platform_device_register(&omap_hdmi_audio);
+}
+#else
+static inline void omap_init_hdmi_audio(void) {}
+#endif
+
#if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE)
#include <plat/mcspi.h>
@@ -701,11 +730,15 @@ static int __init omap2_init_devices(void)
* in alphabetical order so they're easier to sort through.
*/
omap_init_audio();
- omap_init_mcpdm();
- omap_init_dmic();
omap_init_camera();
+ omap_init_hdmi_audio();
omap_init_mbox();
- omap_init_mcspi();
+ /* If dtb is there, the devices will be created dynamically */
+ if (!of_have_populated_dt()) {
+ omap_init_dmic();
+ omap_init_mcpdm();
+ omap_init_mcspi();
+ }
omap_init_pmu();
omap_hdq_init();
omap_init_sti();
diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c
index fc56745676fa..f0f10beeffe8 100644
--- a/arch/arm/mach-omap2/dpll3xxx.c
+++ b/arch/arm/mach-omap2/dpll3xxx.c
@@ -142,7 +142,8 @@ static int _omap3_noncore_dpll_lock(struct clk *clk)
ai = omap3_dpll_autoidle_read(clk);
- omap3_dpll_deny_idle(clk);
+ if (ai)
+ omap3_dpll_deny_idle(clk);
_omap3_dpll_write_clken(clk, DPLL_LOCKED);
@@ -186,8 +187,6 @@ static int _omap3_noncore_dpll_bypass(struct clk *clk)
if (ai)
omap3_dpll_allow_idle(clk);
- else
- omap3_dpll_deny_idle(clk);
return r;
}
@@ -216,8 +215,6 @@ static int _omap3_noncore_dpll_stop(struct clk *clk)
if (ai)
omap3_dpll_allow_idle(clk);
- else
- omap3_dpll_deny_idle(clk);
return 0;
}
@@ -519,6 +516,9 @@ u32 omap3_dpll_autoidle_read(struct clk *clk)
dd = clk->dpll_data;
+ if (!dd->autoidle_reg)
+ return -EINVAL;
+
v = __raw_readl(dd->autoidle_reg);
v &= dd->autoidle_mask;
v >>= __ffs(dd->autoidle_mask);
@@ -545,6 +545,12 @@ void omap3_dpll_allow_idle(struct clk *clk)
dd = clk->dpll_data;
+ if (!dd->autoidle_reg) {
+ pr_debug("clock: DPLL %s: autoidle not supported\n",
+ clk->name);
+ return;
+ }
+
/*
* REVISIT: CORE DPLL can optionally enter low-power bypass
* by writing 0x5 instead of 0x1. Add some mechanism to
@@ -554,6 +560,7 @@ void omap3_dpll_allow_idle(struct clk *clk)
v &= ~dd->autoidle_mask;
v |= DPLL_AUTOIDLE_LOW_POWER_STOP << __ffs(dd->autoidle_mask);
__raw_writel(v, dd->autoidle_reg);
+
}
/**
@@ -572,6 +579,12 @@ void omap3_dpll_deny_idle(struct clk *clk)
dd = clk->dpll_data;
+ if (!dd->autoidle_reg) {
+ pr_debug("clock: DPLL %s: autoidle not supported\n",
+ clk->name);
+ return;
+ }
+
v = __raw_readl(dd->autoidle_reg);
v &= ~dd->autoidle_mask;
v |= DPLL_AUTOIDLE_DISABLE << __ffs(dd->autoidle_mask);
diff --git a/arch/arm/mach-omap2/dsp.c b/arch/arm/mach-omap2/dsp.c
index 74f18f2952df..3376388b317a 100644
--- a/arch/arm/mach-omap2/dsp.c
+++ b/arch/arm/mach-omap2/dsp.c
@@ -57,8 +57,9 @@ static int __init omap_dsp_init(void)
if (pdata->phys_mempool_base) {
pdata->phys_mempool_size = CONFIG_TIDSPBRIDGE_MEMPOOL_SIZE;
- pr_info("%s: %x bytes @ %x\n", __func__,
- pdata->phys_mempool_size, pdata->phys_mempool_base);
+ pr_info("%s: %llx bytes @ %llx\n", __func__,
+ (unsigned long long)pdata->phys_mempool_size,
+ (unsigned long long)pdata->phys_mempool_base);
}
pdev = platform_device_alloc("omap-dsp", -1);
diff --git a/arch/arm/mach-omap2/gpio.c b/arch/arm/mach-omap2/gpio.c
index 2f994e5194e8..9ad7d489b0de 100644
--- a/arch/arm/mach-omap2/gpio.c
+++ b/arch/arm/mach-omap2/gpio.c
@@ -20,6 +20,7 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
+#include <linux/of.h>
#include <plat/omap_hwmod.h>
#include <plat/omap_device.h>
@@ -55,10 +56,9 @@ static int __init omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
dev_attr = (struct omap_gpio_dev_attr *)oh->dev_attr;
pdata->bank_width = dev_attr->bank_width;
pdata->dbck_flag = dev_attr->dbck_flag;
- pdata->virtual_irq_start = IH_GPIO_BASE + 32 * (id - 1);
pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count;
pdata->regs = kzalloc(sizeof(struct omap_gpio_reg_offs), GFP_KERNEL);
- if (!pdata) {
+ if (!pdata->regs) {
pr_err("gpio%d: Memory allocation failed\n", id);
return -ENOMEM;
}
@@ -102,6 +102,8 @@ static int __init omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
pdata->regs->dataout = OMAP4_GPIO_DATAOUT;
pdata->regs->set_dataout = OMAP4_GPIO_SETDATAOUT;
pdata->regs->clr_dataout = OMAP4_GPIO_CLEARDATAOUT;
+ pdata->regs->irqstatus_raw0 = OMAP4_GPIO_IRQSTATUSRAW0;
+ pdata->regs->irqstatus_raw1 = OMAP4_GPIO_IRQSTATUSRAW1;
pdata->regs->irqstatus = OMAP4_GPIO_IRQSTATUS0;
pdata->regs->irqstatus2 = OMAP4_GPIO_IRQSTATUS1;
pdata->regs->irqenable = OMAP4_GPIO_IRQSTATUSSET0;
@@ -146,7 +148,10 @@ static int __init omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
*/
static int __init omap2_gpio_init(void)
{
- return omap_hwmod_for_each_by_class("gpio", omap2_gpio_dev_init,
- NULL);
+ /* If dtb is there, the devices will be created dynamically */
+ if (of_have_populated_dt())
+ return -ENODEV;
+
+ return omap_hwmod_for_each_by_class("gpio", omap2_gpio_dev_init, NULL);
}
postcore_initcall(omap2_gpio_init);
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index 385b3e02c4a6..a0fa9bb2bda5 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -176,7 +176,7 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
const int t_wpl = 40;
const int t_wph = 30;
int min_gpmc_clk_period, t_ces, t_avds, t_avdh, t_ach, t_aavdh, t_rdyo;
- int tick_ns, div, fclk_offset_ns, fclk_offset, gpmc_clk_ns, latency;
+ int div, fclk_offset_ns, fclk_offset, gpmc_clk_ns, latency;
int first_time = 0, hf = 0, vhf = 0, sync_read = 0, sync_write = 0;
int err, ticks_cez;
int cs = cfg->cs, freq = *freq_ptr;
@@ -240,7 +240,6 @@ static int omap2_onenand_set_sync_mode(struct omap_onenand_platform_data *cfg,
break;
}
- tick_ns = gpmc_ticks_to_ns(1);
div = gpmc_cs_calc_divider(cs, min_gpmc_clk_period);
gpmc_clk_ns = gpmc_ticks_to_ns(div);
if (gpmc_clk_ns < 15) /* >66Mhz */
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 00d510858e28..580e684e8825 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -755,8 +755,7 @@ static int __init gpmc_init(void)
irq++;
}
- ret = request_irq(gpmc_irq,
- gpmc_handle_irq, IRQF_SHARED, "gpmc", gpmc_base);
+ ret = request_irq(gpmc_irq, gpmc_handle_irq, IRQF_SHARED, "gpmc", NULL);
if (ret)
pr_err("gpmc: irq-%d could not claim: err %d\n",
gpmc_irq, ret);
diff --git a/arch/arm/mach-omap2/hdq1w.c b/arch/arm/mach-omap2/hdq1w.c
new file mode 100644
index 000000000000..297ebe03f09c
--- /dev/null
+++ b/arch/arm/mach-omap2/hdq1w.c
@@ -0,0 +1,72 @@
+/*
+ * IP block integration code for the HDQ1W/1-wire IP block
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ * Paul Walmsley
+ *
+ * Based on the I2C reset code in arch/arm/mach-omap2/i2c.c by
+ * Avinash.H.M <avinashhm@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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <plat/omap_hwmod.h>
+#include <plat/hdq1w.h>
+
+#include "common.h"
+
+/* Maximum microseconds to wait for OMAP module to softreset */
+#define MAX_MODULE_SOFTRESET_WAIT 10000
+
+/**
+ * omap_hdq1w_reset - reset the OMAP HDQ1W module
+ * @oh: struct omap_hwmod *
+ *
+ * OCP soft reset the HDQ1W IP block. Section 20.6.1.4 "HDQ1W/1-Wire
+ * Software Reset" of the OMAP34xx Technical Reference Manual Revision
+ * ZR (SWPU223R) does not include the rather important fact that, for
+ * the reset to succeed, the HDQ1W module's internal clock gate must be
+ * programmed to allow the clock to propagate to the rest of the
+ * module. In this sense, it's rather similar to the I2C custom reset
+ * function. Returns 0.
+ */
+int omap_hdq1w_reset(struct omap_hwmod *oh)
+{
+ u32 v;
+ int c = 0;
+
+ /* Write to the SOFTRESET bit */
+ omap_hwmod_softreset(oh);
+
+ /* Enable the module's internal clocks */
+ v = omap_hwmod_read(oh, HDQ_CTRL_STATUS_OFFSET);
+ v |= 1 << HDQ_CTRL_STATUS_CLOCKENABLE_SHIFT;
+ omap_hwmod_write(v, oh, HDQ_CTRL_STATUS_OFFSET);
+
+ /* Poll on RESETDONE bit */
+ omap_test_timeout((omap_hwmod_read(oh,
+ oh->class->sysc->syss_offs)
+ & SYSS_RESETDONE_MASK),
+ MAX_MODULE_SOFTRESET_WAIT, c);
+
+ if (c == MAX_MODULE_SOFTRESET_WAIT)
+ pr_warning("%s: %s: softreset failed (waited %d usec)\n",
+ __func__, oh->name, MAX_MODULE_SOFTRESET_WAIT);
+ else
+ pr_debug("%s: %s: softreset in %d usec\n", __func__,
+ oh->name, c);
+
+ return 0;
+}
diff --git a/arch/arm/mach-omap2/hwspinlock.c b/arch/arm/mach-omap2/hwspinlock.c
index 454dfce125ca..8763c8520dc2 100644
--- a/arch/arm/mach-omap2/hwspinlock.c
+++ b/arch/arm/mach-omap2/hwspinlock.c
@@ -28,7 +28,7 @@ static struct hwspinlock_pdata omap_hwspinlock_pdata __initdata = {
.base_id = 0,
};
-int __init hwspinlocks_init(void)
+static int __init hwspinlocks_init(void)
{
int retval = 0;
struct omap_hwmod *oh;
diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c
index 0e79b7bc6aa4..f1398171d8a2 100644
--- a/arch/arm/mach-omap2/id.c
+++ b/arch/arm/mach-omap2/id.c
@@ -478,9 +478,12 @@ void __init omap4xxx_check_revision(void)
case 0xb94e:
switch (rev) {
case 0:
- default:
omap_revision = OMAP4460_REV_ES1_0;
break;
+ case 2:
+ default:
+ omap_revision = OMAP4460_REV_ES1_1;
+ break;
}
break;
case 0xb975:
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index 065bd768987c..4b9491aa36fa 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -31,6 +31,7 @@
#include <plat/omap-pm.h>
#include <plat/omap_hwmod.h>
#include <plat/multi.h>
+#include <plat/dma.h>
#include "iomap.h"
#include "voltage.h"
@@ -363,24 +364,6 @@ static void __init omap_hwmod_init_postsetup(void)
#endif
omap_hwmod_for_each(_set_hwmod_postsetup_state, &postsetup_state);
- /*
- * Set the default postsetup state for unusual modules (like
- * MPU WDT).
- *
- * The postsetup_state is not actually used until
- * omap_hwmod_late_init(), so boards that desire full watchdog
- * coverage of kernel initialization can reprogram the
- * postsetup_state between the calls to
- * omap2_init_common_infra() and omap_sdrc_init().
- *
- * XXX ideally we could detect whether the MPU WDT was currently
- * enabled here and make this conditional
- */
- postsetup_state = _HWMOD_STATE_DISABLED;
- omap_hwmod_for_each_by_class("wd_timer",
- _set_hwmod_postsetup_state,
- &postsetup_state);
-
omap_pm_if_early_init();
}
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
index 65f0d2571c9a..1ecf54565fe2 100644
--- a/arch/arm/mach-omap2/irq.c
+++ b/arch/arm/mach-omap2/irq.c
@@ -25,6 +25,7 @@
#include <mach/hardware.h>
#include "iomap.h"
+#include "common.h"
/* selected INTC register offsets */
@@ -149,7 +150,6 @@ omap_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num)
ct->chip.irq_mask = irq_gc_mask_disable_reg;
ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
- ct->regs.ack = INTC_CONTROL;
ct->regs.enable = INTC_MIR_CLEAR0;
ct->regs.disable = INTC_MIR_SET0;
irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
@@ -231,7 +231,7 @@ static inline void omap_intc_handle_irq(void __iomem *base_addr, struct pt_regs
goto out;
irqnr = readl_relaxed(base_addr + 0xd8);
-#ifdef CONFIG_SOC_OMAPTI816X
+#ifdef CONFIG_SOC_OMAPTI81XX
if (irqnr)
goto out;
irqnr = readl_relaxed(base_addr + 0xf8);
@@ -334,7 +334,7 @@ void omap_intc_restore_context(void)
void omap3_intc_suspend(void)
{
/* A pending interrupt would prevent OMAP from entering suspend */
- omap_ack_irq(0);
+ omap_ack_irq(NULL);
}
void omap3_intc_prepare_idle(void)
diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c
index 415a6f1cf419..19b8b6774862 100644
--- a/arch/arm/mach-omap2/mailbox.c
+++ b/arch/arm/mach-omap2/mailbox.c
@@ -26,9 +26,9 @@
#define MAILBOX_IRQSTATUS(u) (0x100 + 8 * (u))
#define MAILBOX_IRQENABLE(u) (0x104 + 8 * (u))
-#define OMAP4_MAILBOX_IRQSTATUS(u) (0x104 + 10 * (u))
-#define OMAP4_MAILBOX_IRQENABLE(u) (0x108 + 10 * (u))
-#define OMAP4_MAILBOX_IRQENABLE_CLR(u) (0x10c + 10 * (u))
+#define OMAP4_MAILBOX_IRQSTATUS(u) (0x104 + 0x10 * (u))
+#define OMAP4_MAILBOX_IRQENABLE(u) (0x108 + 0x10 * (u))
+#define OMAP4_MAILBOX_IRQENABLE_CLR(u) (0x10c + 0x10 * (u))
#define MAILBOX_IRQ_NEWMSG(m) (1 << (2 * (m)))
#define MAILBOX_IRQ_NOTFULL(m) (1 << (2 * (m) + 1))
diff --git a/arch/arm/mach-omap2/msdi.c b/arch/arm/mach-omap2/msdi.c
new file mode 100644
index 000000000000..ef2a6924731a
--- /dev/null
+++ b/arch/arm/mach-omap2/msdi.c
@@ -0,0 +1,88 @@
+/*
+ * MSDI IP block reset
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ * Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * XXX What about pad muxing?
+ */
+
+#include <linux/kernel.h>
+
+#include <plat/omap_hwmod.h>
+#include <plat/mmc.h>
+
+#include "common.h"
+
+/*
+ * MSDI_CON_OFFSET: offset in bytes of the MSDI IP block's CON register
+ * from the IP block's base address
+ */
+#define MSDI_CON_OFFSET 0x0c
+
+/* Register bitfields in the CON register */
+#define MSDI_CON_POW_MASK BIT(11)
+#define MSDI_CON_CLKD_MASK (0x3f << 0)
+#define MSDI_CON_CLKD_SHIFT 0
+
+/* Maximum microseconds to wait for OMAP module to softreset */
+#define MAX_MODULE_SOFTRESET_WAIT 10000
+
+/* MSDI_TARGET_RESET_CLKD: clock divisor to use throughout the reset */
+#define MSDI_TARGET_RESET_CLKD 0x3ff
+
+/**
+ * omap_msdi_reset - reset the MSDI IP block
+ * @oh: struct omap_hwmod *
+ *
+ * The MSDI IP block on OMAP2420 has to have both the POW and CLKD
+ * fields set inside its CON register for a reset to complete
+ * successfully. This is not documented in the TRM. For CLKD, we use
+ * the value that results in the lowest possible clock rate, to attempt
+ * to avoid disturbing any cards.
+ */
+int omap_msdi_reset(struct omap_hwmod *oh)
+{
+ u16 v = 0;
+ int c = 0;
+
+ /* Write to the SOFTRESET bit */
+ omap_hwmod_softreset(oh);
+
+ /* Enable the MSDI core and internal clock */
+ v |= MSDI_CON_POW_MASK;
+ v |= MSDI_TARGET_RESET_CLKD << MSDI_CON_CLKD_SHIFT;
+ omap_hwmod_write(v, oh, MSDI_CON_OFFSET);
+
+ /* Poll on RESETDONE bit */
+ omap_test_timeout((omap_hwmod_read(oh, oh->class->sysc->syss_offs)
+ & SYSS_RESETDONE_MASK),
+ MAX_MODULE_SOFTRESET_WAIT, c);
+
+ if (c == MAX_MODULE_SOFTRESET_WAIT)
+ pr_warning("%s: %s: softreset failed (waited %d usec)\n",
+ __func__, oh->name, MAX_MODULE_SOFTRESET_WAIT);
+ else
+ pr_debug("%s: %s: softreset in %d usec\n", __func__,
+ oh->name, c);
+
+ /* Disable the MSDI internal clock */
+ v &= ~MSDI_CON_CLKD_MASK;
+ omap_hwmod_write(v, oh, MSDI_CON_OFFSET);
+
+ return 0;
+}
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index 65c33911341f..3268ee24eada 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -247,7 +247,7 @@ int __init omap_mux_init_signal(const char *muxname, int val)
int mux_mode;
mux_mode = omap_mux_get_by_name(muxname, &partition, &mux);
- if (mux_mode < 0)
+ if (mux_mode < 0 || !mux)
return mux_mode;
old_mode = omap_mux_read(partition, mux->reg_offset);
diff --git a/arch/arm/mach-omap2/omap-secure.c b/arch/arm/mach-omap2/omap-secure.c
index d8f8ef40290f..d9ae4a53d818 100644
--- a/arch/arm/mach-omap2/omap-secure.c
+++ b/arch/arm/mach-omap2/omap-secure.c
@@ -18,6 +18,7 @@
#include <asm/cacheflush.h>
#include <asm/memblock.h>
+#include <plat/omap-secure.h>
#include <mach/omap-secure.h>
static phys_addr_t omap_secure_memblock_base;
diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c
index 42cd7fb52414..d811c7790350 100644
--- a/arch/arm/mach-omap2/omap-wakeupgen.c
+++ b/arch/arm/mach-omap2/omap-wakeupgen.c
@@ -259,7 +259,7 @@ static void irq_save_context(void)
/*
* Clear WakeupGen SAR backup status.
*/
-void irq_sar_clear(void)
+static void irq_sar_clear(void)
{
u32 val;
val = __raw_readl(sar_base + SAR_BACKUP_STATUS_OFFSET);
diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index 70de277f5c15..a8161e5f3204 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -25,11 +25,13 @@
#include <plat/irqs.h>
#include <plat/sram.h>
#include <plat/omap-secure.h>
+#include <plat/mmc.h>
#include <mach/hardware.h>
#include <mach/omap-wakeupgen.h>
#include "common.h"
+#include "hsmmc.h"
#include "omap4-sar-layout.h"
#include <linux/export.h>
@@ -207,3 +209,59 @@ static int __init omap4_sar_ram_init(void)
return 0;
}
early_initcall(omap4_sar_ram_init);
+
+#if defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
+static int omap4_twl6030_hsmmc_late_init(struct device *dev)
+{
+ int irq = 0;
+ struct platform_device *pdev = container_of(dev,
+ struct platform_device, dev);
+ struct omap_mmc_platform_data *pdata = dev->platform_data;
+
+ /* Setting MMC1 Card detect Irq */
+ if (pdev->id == 0) {
+ irq = twl6030_mmc_card_detect_config();
+ if (irq < 0) {
+ dev_err(dev, "%s: Error card detect config(%d)\n",
+ __func__, irq);
+ return irq;
+ }
+ pdata->slots[0].card_detect_irq = irq;
+ pdata->slots[0].card_detect = twl6030_mmc_card_detect;
+ }
+ return 0;
+}
+
+static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev)
+{
+ struct omap_mmc_platform_data *pdata;
+
+ /* dev can be null if CONFIG_MMC_OMAP_HS is not set */
+ if (!dev) {
+ pr_err("Failed %s\n", __func__);
+ return;
+ }
+ pdata = dev->platform_data;
+ pdata->init = omap4_twl6030_hsmmc_late_init;
+}
+
+int __init omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers)
+{
+ struct omap2_hsmmc_info *c;
+
+ omap_hsmmc_init(controllers);
+ for (c = controllers; c->mmc; c++) {
+ /* pdev can be null if CONFIG_MMC_OMAP_HS is not set */
+ if (!c->pdev)
+ continue;
+ omap4_twl6030_hsmmc_set_late_init(&c->pdev->dev);
+ }
+
+ return 0;
+}
+#else
+int __init omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers)
+{
+ return 0;
+}
+#endif
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 7144ae651d3d..bf86f7e8f91f 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -2,7 +2,7 @@
* omap_hwmod implementation for OMAP2/3/4
*
* Copyright (C) 2009-2011 Nokia Corporation
- * Copyright (C) 2011 Texas Instruments, Inc.
+ * Copyright (C) 2011-2012 Texas Instruments, Inc.
*
* Paul Walmsley, Benoît Cousson, Kevin Hilman
*
@@ -137,6 +137,7 @@
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
+#include <linux/bootmem.h>
#include "common.h"
#include <plat/cpu.h>
@@ -159,16 +160,58 @@
/* Name of the OMAP hwmod for the MPU */
#define MPU_INITIATOR_NAME "mpu"
+/*
+ * Number of struct omap_hwmod_link records per struct
+ * omap_hwmod_ocp_if record (master->slave and slave->master)
+ */
+#define LINKS_PER_OCP_IF 2
+
/* omap_hwmod_list contains all registered struct omap_hwmods */
static LIST_HEAD(omap_hwmod_list);
/* mpu_oh: used to add/remove MPU initiator from sleepdep list */
static struct omap_hwmod *mpu_oh;
+/*
+ * linkspace: ptr to a buffer that struct omap_hwmod_link records are
+ * allocated from - used to reduce the number of small memory
+ * allocations, which has a significant impact on performance
+ */
+static struct omap_hwmod_link *linkspace;
+
+/*
+ * free_ls, max_ls: array indexes into linkspace; representing the
+ * next free struct omap_hwmod_link index, and the maximum number of
+ * struct omap_hwmod_link records allocated (respectively)
+ */
+static unsigned short free_ls, max_ls, ls_supp;
/* Private functions */
/**
+ * _fetch_next_ocp_if - return the next OCP interface in a list
+ * @p: ptr to a ptr to the list_head inside the ocp_if to return
+ * @i: pointer to the index of the element pointed to by @p in the list
+ *
+ * Return a pointer to the struct omap_hwmod_ocp_if record
+ * containing the struct list_head pointed to by @p, and increment
+ * @p such that a future call to this routine will return the next
+ * record.
+ */
+static struct omap_hwmod_ocp_if *_fetch_next_ocp_if(struct list_head **p,
+ int *i)
+{
+ struct omap_hwmod_ocp_if *oi;
+
+ oi = list_entry(*p, struct omap_hwmod_link, node)->ocp_if;
+ *p = (*p)->next;
+
+ *i = *i + 1;
+
+ return oi;
+}
+
+/**
* _update_sysc_cache - return the module OCP_SYSCONFIG register, keep copy
* @oh: struct omap_hwmod *
*
@@ -582,16 +625,16 @@ static int _init_main_clk(struct omap_hwmod *oh)
*/
static int _init_interface_clks(struct omap_hwmod *oh)
{
+ struct omap_hwmod_ocp_if *os;
+ struct list_head *p;
struct clk *c;
- int i;
+ int i = 0;
int ret = 0;
- if (oh->slaves_cnt == 0)
- return 0;
-
- for (i = 0; i < oh->slaves_cnt; i++) {
- struct omap_hwmod_ocp_if *os = oh->slaves[i];
+ p = oh->slave_ports.next;
+ while (i < oh->slaves_cnt) {
+ os = _fetch_next_ocp_if(&p, &i);
if (!os->clk)
continue;
@@ -643,21 +686,22 @@ static int _init_opt_clks(struct omap_hwmod *oh)
*/
static int _enable_clocks(struct omap_hwmod *oh)
{
- int i;
+ struct omap_hwmod_ocp_if *os;
+ struct list_head *p;
+ int i = 0;
pr_debug("omap_hwmod: %s: enabling clocks\n", oh->name);
if (oh->_clk)
clk_enable(oh->_clk);
- if (oh->slaves_cnt > 0) {
- for (i = 0; i < oh->slaves_cnt; i++) {
- struct omap_hwmod_ocp_if *os = oh->slaves[i];
- struct clk *c = os->_clk;
+ p = oh->slave_ports.next;
- if (c && (os->flags & OCPIF_SWSUP_IDLE))
- clk_enable(c);
- }
+ while (i < oh->slaves_cnt) {
+ os = _fetch_next_ocp_if(&p, &i);
+
+ if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE))
+ clk_enable(os->_clk);
}
/* The opt clocks are controlled by the device driver. */
@@ -673,21 +717,22 @@ static int _enable_clocks(struct omap_hwmod *oh)
*/
static int _disable_clocks(struct omap_hwmod *oh)
{
- int i;
+ struct omap_hwmod_ocp_if *os;
+ struct list_head *p;
+ int i = 0;
pr_debug("omap_hwmod: %s: disabling clocks\n", oh->name);
if (oh->_clk)
clk_disable(oh->_clk);
- if (oh->slaves_cnt > 0) {
- for (i = 0; i < oh->slaves_cnt; i++) {
- struct omap_hwmod_ocp_if *os = oh->slaves[i];
- struct clk *c = os->_clk;
+ p = oh->slave_ports.next;
- if (c && (os->flags & OCPIF_SWSUP_IDLE))
- clk_disable(c);
- }
+ while (i < oh->slaves_cnt) {
+ os = _fetch_next_ocp_if(&p, &i);
+
+ if (os->_clk && (os->flags & OCPIF_SWSUP_IDLE))
+ clk_disable(os->_clk);
}
/* The opt clocks are controlled by the device driver. */
@@ -781,39 +826,6 @@ static int _omap4_wait_target_disable(struct omap_hwmod *oh)
}
/**
- * _omap4_disable_module - enable CLKCTRL modulemode on OMAP4
- * @oh: struct omap_hwmod *
- *
- * Disable the PRCM module mode related to the hwmod @oh.
- * Return EINVAL if the modulemode is not supported and 0 in case of success.
- */
-static int _omap4_disable_module(struct omap_hwmod *oh)
-{
- int v;
-
- /* The module mode does not exist prior OMAP4 */
- if (!cpu_is_omap44xx())
- return -EINVAL;
-
- if (!oh->clkdm || !oh->prcm.omap4.modulemode)
- return -EINVAL;
-
- pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__);
-
- omap4_cminst_module_disable(oh->clkdm->prcm_partition,
- oh->clkdm->cm_inst,
- oh->clkdm->clkdm_offs,
- oh->prcm.omap4.clkctrl_offs);
-
- v = _omap4_wait_target_disable(oh);
- if (v)
- pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
- oh->name);
-
- return 0;
-}
-
-/**
* _count_mpu_irqs - count the number of MPU IRQ lines associated with @oh
* @oh: struct omap_hwmod *oh
*
@@ -883,59 +895,220 @@ static int _count_ocp_if_addr_spaces(struct omap_hwmod_ocp_if *os)
}
/**
- * _find_mpu_port_index - find hwmod OCP slave port ID intended for MPU use
- * @oh: struct omap_hwmod *
+ * _get_mpu_irq_by_name - fetch MPU interrupt line number by name
+ * @oh: struct omap_hwmod * to operate on
+ * @name: pointer to the name of the MPU interrupt number to fetch (optional)
+ * @irq: pointer to an unsigned int to store the MPU IRQ number to
*
- * Returns the array index of the OCP slave port that the MPU
- * addresses the device on, or -EINVAL upon error or not found.
+ * Retrieve a MPU hardware IRQ line number named by @name associated
+ * with the IP block pointed to by @oh. The IRQ number will be filled
+ * into the address pointed to by @dma. When @name is non-null, the
+ * IRQ line number associated with the named entry will be returned.
+ * If @name is null, the first matching entry will be returned. Data
+ * order is not meaningful in hwmod data, so callers are strongly
+ * encouraged to use a non-null @name whenever possible to avoid
+ * unpredictable effects if hwmod data is later added that causes data
+ * ordering to change. Returns 0 upon success or a negative error
+ * code upon error.
*/
-static int __init _find_mpu_port_index(struct omap_hwmod *oh)
+static int _get_mpu_irq_by_name(struct omap_hwmod *oh, const char *name,
+ unsigned int *irq)
{
int i;
- int found = 0;
+ bool found = false;
- if (!oh || oh->slaves_cnt == 0)
- return -EINVAL;
+ if (!oh->mpu_irqs)
+ return -ENOENT;
- for (i = 0; i < oh->slaves_cnt; i++) {
- struct omap_hwmod_ocp_if *os = oh->slaves[i];
+ i = 0;
+ while (oh->mpu_irqs[i].irq != -1) {
+ if (name == oh->mpu_irqs[i].name ||
+ !strcmp(name, oh->mpu_irqs[i].name)) {
+ found = true;
+ break;
+ }
+ i++;
+ }
- if (os->user & OCP_USER_MPU) {
- found = 1;
+ if (!found)
+ return -ENOENT;
+
+ *irq = oh->mpu_irqs[i].irq;
+
+ return 0;
+}
+
+/**
+ * _get_sdma_req_by_name - fetch SDMA request line ID by name
+ * @oh: struct omap_hwmod * to operate on
+ * @name: pointer to the name of the SDMA request line to fetch (optional)
+ * @dma: pointer to an unsigned int to store the request line ID to
+ *
+ * Retrieve an SDMA request line ID named by @name on the IP block
+ * pointed to by @oh. The ID will be filled into the address pointed
+ * to by @dma. When @name is non-null, the request line ID associated
+ * with the named entry will be returned. If @name is null, the first
+ * matching entry will be returned. Data order is not meaningful in
+ * hwmod data, so callers are strongly encouraged to use a non-null
+ * @name whenever possible to avoid unpredictable effects if hwmod
+ * data is later added that causes data ordering to change. Returns 0
+ * upon success or a negative error code upon error.
+ */
+static int _get_sdma_req_by_name(struct omap_hwmod *oh, const char *name,
+ unsigned int *dma)
+{
+ int i;
+ bool found = false;
+
+ if (!oh->sdma_reqs)
+ return -ENOENT;
+
+ i = 0;
+ while (oh->sdma_reqs[i].dma_req != -1) {
+ if (name == oh->sdma_reqs[i].name ||
+ !strcmp(name, oh->sdma_reqs[i].name)) {
+ found = true;
break;
}
+ i++;
}
- if (found)
- pr_debug("omap_hwmod: %s: MPU OCP slave port ID %d\n",
- oh->name, i);
- else
- pr_debug("omap_hwmod: %s: no MPU OCP slave port found\n",
- oh->name);
+ if (!found)
+ return -ENOENT;
+
+ *dma = oh->sdma_reqs[i].dma_req;
- return (found) ? i : -EINVAL;
+ return 0;
}
/**
- * _find_mpu_rt_base - find hwmod register target base addr accessible by MPU
- * @oh: struct omap_hwmod *
+ * _get_addr_space_by_name - fetch address space start & end by name
+ * @oh: struct omap_hwmod * to operate on
+ * @name: pointer to the name of the address space to fetch (optional)
+ * @pa_start: pointer to a u32 to store the starting address to
+ * @pa_end: pointer to a u32 to store the ending address to
*
- * Return the virtual address of the base of the register target of
- * device @oh, or NULL on error.
+ * Retrieve address space start and end addresses for the IP block
+ * pointed to by @oh. The data will be filled into the addresses
+ * pointed to by @pa_start and @pa_end. When @name is non-null, the
+ * address space data associated with the named entry will be
+ * returned. If @name is null, the first matching entry will be
+ * returned. Data order is not meaningful in hwmod data, so callers
+ * are strongly encouraged to use a non-null @name whenever possible
+ * to avoid unpredictable effects if hwmod data is later added that
+ * causes data ordering to change. Returns 0 upon success or a
+ * negative error code upon error.
*/
-static void __iomem * __init _find_mpu_rt_base(struct omap_hwmod *oh, u8 index)
+static int _get_addr_space_by_name(struct omap_hwmod *oh, const char *name,
+ u32 *pa_start, u32 *pa_end)
{
+ int i, j;
struct omap_hwmod_ocp_if *os;
- struct omap_hwmod_addr_space *mem;
- int i = 0, found = 0;
- void __iomem *va_start;
+ struct list_head *p = NULL;
+ bool found = false;
+
+ p = oh->slave_ports.next;
+
+ i = 0;
+ while (i < oh->slaves_cnt) {
+ os = _fetch_next_ocp_if(&p, &i);
+
+ if (!os->addr)
+ return -ENOENT;
+
+ j = 0;
+ while (os->addr[j].pa_start != os->addr[j].pa_end) {
+ if (name == os->addr[j].name ||
+ !strcmp(name, os->addr[j].name)) {
+ found = true;
+ break;
+ }
+ j++;
+ }
+
+ if (found)
+ break;
+ }
+
+ if (!found)
+ return -ENOENT;
+
+ *pa_start = os->addr[j].pa_start;
+ *pa_end = os->addr[j].pa_end;
+
+ return 0;
+}
+
+/**
+ * _save_mpu_port_index - find and save the index to @oh's MPU port
+ * @oh: struct omap_hwmod *
+ *
+ * Determines the array index of the OCP slave port that the MPU uses
+ * to address the device, and saves it into the struct omap_hwmod.
+ * Intended to be called during hwmod registration only. No return
+ * value.
+ */
+static void __init _save_mpu_port_index(struct omap_hwmod *oh)
+{
+ struct omap_hwmod_ocp_if *os = NULL;
+ struct list_head *p;
+ int i = 0;
+
+ if (!oh)
+ return;
- if (!oh || oh->slaves_cnt == 0)
+ oh->_int_flags |= _HWMOD_NO_MPU_PORT;
+
+ p = oh->slave_ports.next;
+
+ while (i < oh->slaves_cnt) {
+ os = _fetch_next_ocp_if(&p, &i);
+ if (os->user & OCP_USER_MPU) {
+ oh->_mpu_port = os;
+ oh->_int_flags &= ~_HWMOD_NO_MPU_PORT;
+ break;
+ }
+ }
+
+ return;
+}
+
+/**
+ * _find_mpu_rt_port - return omap_hwmod_ocp_if accessible by the MPU
+ * @oh: struct omap_hwmod *
+ *
+ * Given a pointer to a struct omap_hwmod record @oh, return a pointer
+ * to the struct omap_hwmod_ocp_if record that is used by the MPU to
+ * communicate with the IP block. This interface need not be directly
+ * connected to the MPU (and almost certainly is not), but is directly
+ * connected to the IP block represented by @oh. Returns a pointer
+ * to the struct omap_hwmod_ocp_if * upon success, or returns NULL upon
+ * error or if there does not appear to be a path from the MPU to this
+ * IP block.
+ */
+static struct omap_hwmod_ocp_if *_find_mpu_rt_port(struct omap_hwmod *oh)
+{
+ if (!oh || oh->_int_flags & _HWMOD_NO_MPU_PORT || oh->slaves_cnt == 0)
return NULL;
- os = oh->slaves[index];
+ return oh->_mpu_port;
+};
+
+/**
+ * _find_mpu_rt_addr_space - return MPU register target address space for @oh
+ * @oh: struct omap_hwmod *
+ *
+ * Returns a pointer to the struct omap_hwmod_addr_space record representing
+ * the register target MPU address space; or returns NULL upon error.
+ */
+static struct omap_hwmod_addr_space * __init _find_mpu_rt_addr_space(struct omap_hwmod *oh)
+{
+ struct omap_hwmod_ocp_if *os;
+ struct omap_hwmod_addr_space *mem;
+ int found = 0, i = 0;
- if (!os->addr)
+ os = _find_mpu_rt_port(oh);
+ if (!os || !os->addr)
return NULL;
do {
@@ -944,20 +1117,7 @@ static void __iomem * __init _find_mpu_rt_base(struct omap_hwmod *oh, u8 index)
found = 1;
} while (!found && mem->pa_start != mem->pa_end);
- if (found) {
- va_start = ioremap(mem->pa_start, mem->pa_end - mem->pa_start);
- if (!va_start) {
- pr_err("omap_hwmod: %s: Could not ioremap\n", oh->name);
- return NULL;
- }
- pr_debug("omap_hwmod: %s: MPU register target at va %p\n",
- oh->name, va_start);
- } else {
- pr_debug("omap_hwmod: %s: no MPU register target found\n",
- oh->name);
- }
-
- return (found) ? va_start : NULL;
+ return (found) ? mem : NULL;
}
/**
@@ -1205,12 +1365,11 @@ static int _wait_target_ready(struct omap_hwmod *oh)
if (!oh)
return -EINVAL;
- if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
+ if (oh->flags & HWMOD_NO_IDLEST)
return 0;
- os = oh->slaves[oh->_mpu_port_index];
-
- if (oh->flags & HWMOD_NO_IDLEST)
+ os = _find_mpu_rt_port(oh);
+ if (!os)
return 0;
/* XXX check module SIDLEMODE */
@@ -1378,13 +1537,73 @@ static int _read_hardreset(struct omap_hwmod *oh, const char *name)
}
/**
+ * _are_any_hardreset_lines_asserted - return true if part of @oh is hard-reset
+ * @oh: struct omap_hwmod *
+ *
+ * If any hardreset line associated with @oh is asserted, then return true.
+ * Otherwise, if @oh has no hardreset lines associated with it, or if
+ * no hardreset lines associated with @oh are asserted, then return false.
+ * This function is used to avoid executing some parts of the IP block
+ * enable/disable sequence if a hardreset line is set.
+ */
+static bool _are_any_hardreset_lines_asserted(struct omap_hwmod *oh)
+{
+ int i;
+
+ if (oh->rst_lines_cnt == 0)
+ return false;
+
+ for (i = 0; i < oh->rst_lines_cnt; i++)
+ if (_read_hardreset(oh, oh->rst_lines[i].name) > 0)
+ return true;
+
+ return false;
+}
+
+/**
+ * _omap4_disable_module - enable CLKCTRL modulemode on OMAP4
+ * @oh: struct omap_hwmod *
+ *
+ * Disable the PRCM module mode related to the hwmod @oh.
+ * Return EINVAL if the modulemode is not supported and 0 in case of success.
+ */
+static int _omap4_disable_module(struct omap_hwmod *oh)
+{
+ int v;
+
+ /* The module mode does not exist prior OMAP4 */
+ if (!cpu_is_omap44xx())
+ return -EINVAL;
+
+ if (!oh->clkdm || !oh->prcm.omap4.modulemode)
+ return -EINVAL;
+
+ pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__);
+
+ omap4_cminst_module_disable(oh->clkdm->prcm_partition,
+ oh->clkdm->cm_inst,
+ oh->clkdm->clkdm_offs,
+ oh->prcm.omap4.clkctrl_offs);
+
+ if (_are_any_hardreset_lines_asserted(oh))
+ return 0;
+
+ v = _omap4_wait_target_disable(oh);
+ if (v)
+ pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
+ oh->name);
+
+ return 0;
+}
+
+/**
* _ocp_softreset - reset an omap_hwmod via the OCP_SYSCONFIG bit
* @oh: struct omap_hwmod *
*
* Resets an omap_hwmod @oh via the OCP_SYSCONFIG bit. hwmod must be
- * enabled for this to work. Returns -EINVAL if the hwmod cannot be
- * reset this way or if the hwmod is in the wrong state, -ETIMEDOUT if
- * the module did not reset in time, or 0 upon success.
+ * enabled for this to work. Returns -ENOENT if the hwmod cannot be
+ * reset this way, -EINVAL if the hwmod is in the wrong state,
+ * -ETIMEDOUT if the module did not reset in time, or 0 upon success.
*
* In OMAP3 a specific SYSSTATUS register is used to get the reset status.
* Starting in OMAP4, some IPs do not have SYSSTATUS registers and instead
@@ -1401,7 +1620,7 @@ static int _ocp_softreset(struct omap_hwmod *oh)
if (!oh->class->sysc ||
!(oh->class->sysc->sysc_flags & SYSC_HAS_SOFTRESET))
- return -EINVAL;
+ return -ENOENT;
/* clocks must be on for this operation */
if (oh->_state != _HWMOD_STATE_ENABLED) {
@@ -1462,32 +1681,60 @@ dis_opt_clks:
* _reset - reset an omap_hwmod
* @oh: struct omap_hwmod *
*
- * Resets an omap_hwmod @oh. The default software reset mechanism for
- * most OMAP IP blocks is triggered via the OCP_SYSCONFIG.SOFTRESET
- * bit. However, some hwmods cannot be reset via this method: some
- * are not targets and therefore have no OCP header registers to
- * access; others (like the IVA) have idiosyncratic reset sequences.
- * So for these relatively rare cases, custom reset code can be
- * supplied in the struct omap_hwmod_class .reset function pointer.
- * Passes along the return value from either _reset() or the custom
- * reset function - these must return -EINVAL if the hwmod cannot be
- * reset this way or if the hwmod is in the wrong state, -ETIMEDOUT if
- * the module did not reset in time, or 0 upon success.
+ * Resets an omap_hwmod @oh. If the module has a custom reset
+ * function pointer defined, then call it to reset the IP block, and
+ * pass along its return value to the caller. Otherwise, if the IP
+ * block has an OCP_SYSCONFIG register with a SOFTRESET bitfield
+ * associated with it, call a function to reset the IP block via that
+ * method, and pass along the return value to the caller. Finally, if
+ * the IP block has some hardreset lines associated with it, assert
+ * all of those, but do _not_ deassert them. (This is because driver
+ * authors have expressed an apparent requirement to control the
+ * deassertion of the hardreset lines themselves.)
+ *
+ * The default software reset mechanism for most OMAP IP blocks is
+ * triggered via the OCP_SYSCONFIG.SOFTRESET bit. However, some
+ * hwmods cannot be reset via this method. Some are not targets and
+ * therefore have no OCP header registers to access. Others (like the
+ * IVA) have idiosyncratic reset sequences. So for these relatively
+ * rare cases, custom reset code can be supplied in the struct
+ * omap_hwmod_class .reset function pointer. Passes along the return
+ * value from either _ocp_softreset() or the custom reset function -
+ * these must return -EINVAL if the hwmod cannot be reset this way or
+ * if the hwmod is in the wrong state, -ETIMEDOUT if the module did
+ * not reset in time, or 0 upon success.
*/
static int _reset(struct omap_hwmod *oh)
{
- int ret;
+ int i, r;
pr_debug("omap_hwmod: %s: resetting\n", oh->name);
- ret = (oh->class->reset) ? oh->class->reset(oh) : _ocp_softreset(oh);
+ if (oh->class->reset) {
+ r = oh->class->reset(oh);
+ } else {
+ if (oh->rst_lines_cnt > 0) {
+ for (i = 0; i < oh->rst_lines_cnt; i++)
+ _assert_hardreset(oh, oh->rst_lines[i].name);
+ return 0;
+ } else {
+ r = _ocp_softreset(oh);
+ if (r == -ENOENT)
+ r = 0;
+ }
+ }
+ /*
+ * OCP_SYSCONFIG bits need to be reprogrammed after a
+ * softreset. The _enable() function should be split to avoid
+ * the rewrite of the OCP_SYSCONFIG register.
+ */
if (oh->class->sysc) {
_update_sysc_cache(oh);
_enable_sysc(oh);
}
- return ret;
+ return r;
}
/**
@@ -1506,10 +1753,9 @@ static int _enable(struct omap_hwmod *oh)
pr_debug("omap_hwmod: %s: enabling\n", oh->name);
/*
- * hwmods with HWMOD_INIT_NO_IDLE flag set are left
- * in enabled state at init.
- * Now that someone is really trying to enable them,
- * just ensure that the hwmod mux is set.
+ * hwmods with HWMOD_INIT_NO_IDLE flag set are left in enabled
+ * state at init. Now that someone is really trying to enable
+ * them, just ensure that the hwmod mux is set.
*/
if (oh->_int_flags & _HWMOD_SKIP_ENABLE) {
/*
@@ -1532,15 +1778,17 @@ static int _enable(struct omap_hwmod *oh)
return -EINVAL;
}
-
/*
- * If an IP contains only one HW reset line, then de-assert it in order
- * to allow the module state transition. Otherwise the PRCM will return
- * Intransition status, and the init will failed.
+ * If an IP block contains HW reset lines and any of them are
+ * asserted, we let integration code associated with that
+ * block handle the enable. We've received very little
+ * information on what those driver authors need, and until
+ * detailed information is provided and the driver code is
+ * posted to the public lists, this is probably the best we
+ * can do.
*/
- if ((oh->_state == _HWMOD_STATE_INITIALIZED ||
- oh->_state == _HWMOD_STATE_DISABLED) && oh->rst_lines_cnt == 1)
- _deassert_hardreset(oh, oh->rst_lines[0].name);
+ if (_are_any_hardreset_lines_asserted(oh))
+ return 0;
/* Mux pins for device runtime if populated */
if (oh->mux && (!oh->mux->enabled ||
@@ -1615,6 +1863,9 @@ static int _idle(struct omap_hwmod *oh)
return -EINVAL;
}
+ if (_are_any_hardreset_lines_asserted(oh))
+ return 0;
+
if (oh->class->sysc)
_idle_sysc(oh);
_del_initiator_dep(oh, mpu_oh);
@@ -1687,7 +1938,7 @@ int omap_hwmod_set_ocp_autoidle(struct omap_hwmod *oh, u8 autoidle)
*/
static int _shutdown(struct omap_hwmod *oh)
{
- int ret;
+ int ret, i;
u8 prev_state;
if (oh->_state != _HWMOD_STATE_IDLE &&
@@ -1697,6 +1948,9 @@ static int _shutdown(struct omap_hwmod *oh)
return -EINVAL;
}
+ if (_are_any_hardreset_lines_asserted(oh))
+ return 0;
+
pr_debug("omap_hwmod: %s: disabling\n", oh->name);
if (oh->class->pre_shutdown) {
@@ -1728,12 +1982,8 @@ static int _shutdown(struct omap_hwmod *oh)
}
/* XXX Should this code also force-disable the optional clocks? */
- /*
- * If an IP contains only one HW reset line, then assert it
- * after disabling the clocks and before shutting down the IP.
- */
- if (oh->rst_lines_cnt == 1)
- _assert_hardreset(oh, oh->rst_lines[0].name);
+ for (i = 0; i < oh->rst_lines_cnt; i++)
+ _assert_hardreset(oh, oh->rst_lines[i].name);
/* Mux pins to safe mode or use populated off mode values */
if (oh->mux)
@@ -1745,59 +1995,186 @@ static int _shutdown(struct omap_hwmod *oh)
}
/**
- * _setup - do initial configuration of omap_hwmod
- * @oh: struct omap_hwmod *
+ * _init_mpu_rt_base - populate the virtual address for a hwmod
+ * @oh: struct omap_hwmod * to locate the virtual address
*
- * Writes the CLOCKACTIVITY bits @clockact to the hwmod @oh
- * OCP_SYSCONFIG register. Returns 0.
+ * Cache the virtual address used by the MPU to access this IP block's
+ * registers. This address is needed early so the OCP registers that
+ * are part of the device's address space can be ioremapped properly.
+ * No return value.
*/
-static int _setup(struct omap_hwmod *oh, void *data)
+static void __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data)
{
- int i, r;
- u8 postsetup_state;
+ struct omap_hwmod_addr_space *mem;
+ void __iomem *va_start;
+
+ if (!oh)
+ return;
+
+ _save_mpu_port_index(oh);
- if (oh->_state != _HWMOD_STATE_CLKS_INITED)
+ if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
+ return;
+
+ mem = _find_mpu_rt_addr_space(oh);
+ if (!mem) {
+ pr_debug("omap_hwmod: %s: no MPU register target found\n",
+ oh->name);
+ return;
+ }
+
+ va_start = ioremap(mem->pa_start, mem->pa_end - mem->pa_start);
+ if (!va_start) {
+ pr_err("omap_hwmod: %s: Could not ioremap\n", oh->name);
+ return;
+ }
+
+ pr_debug("omap_hwmod: %s: MPU register target at va %p\n",
+ oh->name, va_start);
+
+ oh->_mpu_rt_va = va_start;
+}
+
+/**
+ * _init - initialize internal data for the hwmod @oh
+ * @oh: struct omap_hwmod *
+ * @n: (unused)
+ *
+ * Look up the clocks and the address space used by the MPU to access
+ * registers belonging to the hwmod @oh. @oh must already be
+ * registered at this point. This is the first of two phases for
+ * hwmod initialization. Code called here does not touch any hardware
+ * registers, it simply prepares internal data structures. Returns 0
+ * upon success or if the hwmod isn't registered, or -EINVAL upon
+ * failure.
+ */
+static int __init _init(struct omap_hwmod *oh, void *data)
+{
+ int r;
+
+ if (oh->_state != _HWMOD_STATE_REGISTERED)
return 0;
- /* Set iclk autoidle mode */
- if (oh->slaves_cnt > 0) {
- for (i = 0; i < oh->slaves_cnt; i++) {
- struct omap_hwmod_ocp_if *os = oh->slaves[i];
- struct clk *c = os->_clk;
+ _init_mpu_rt_base(oh, NULL);
- if (!c)
- continue;
+ r = _init_clocks(oh, NULL);
+ if (IS_ERR_VALUE(r)) {
+ WARN(1, "omap_hwmod: %s: couldn't init clocks\n", oh->name);
+ return -EINVAL;
+ }
- if (os->flags & OCPIF_SWSUP_IDLE) {
- /* XXX omap_iclk_deny_idle(c); */
- } else {
- /* XXX omap_iclk_allow_idle(c); */
- clk_enable(c);
- }
+ oh->_state = _HWMOD_STATE_INITIALIZED;
+
+ return 0;
+}
+
+/**
+ * _setup_iclk_autoidle - configure an IP block's interface clocks
+ * @oh: struct omap_hwmod *
+ *
+ * Set up the module's interface clocks. XXX This function is still mostly
+ * a stub; implementing this properly requires iclk autoidle usecounting in
+ * the clock code. No return value.
+ */
+static void __init _setup_iclk_autoidle(struct omap_hwmod *oh)
+{
+ struct omap_hwmod_ocp_if *os;
+ struct list_head *p;
+ int i = 0;
+ if (oh->_state != _HWMOD_STATE_INITIALIZED)
+ return;
+
+ p = oh->slave_ports.next;
+
+ while (i < oh->slaves_cnt) {
+ os = _fetch_next_ocp_if(&p, &i);
+ if (!os->_clk)
+ continue;
+
+ if (os->flags & OCPIF_SWSUP_IDLE) {
+ /* XXX omap_iclk_deny_idle(c); */
+ } else {
+ /* XXX omap_iclk_allow_idle(c); */
+ clk_enable(os->_clk);
}
}
- oh->_state = _HWMOD_STATE_INITIALIZED;
+ return;
+}
- /*
- * In the case of hwmod with hardreset that should not be
- * de-assert at boot time, we have to keep the module
- * initialized, because we cannot enable it properly with the
- * reset asserted. Exit without warning because that behavior is
- * expected.
- */
- if ((oh->flags & HWMOD_INIT_NO_RESET) && oh->rst_lines_cnt == 1)
- return 0;
+/**
+ * _setup_reset - reset an IP block during the setup process
+ * @oh: struct omap_hwmod *
+ *
+ * Reset the IP block corresponding to the hwmod @oh during the setup
+ * process. The IP block is first enabled so it can be successfully
+ * reset. Returns 0 upon success or a negative error code upon
+ * failure.
+ */
+static int __init _setup_reset(struct omap_hwmod *oh)
+{
+ int r;
- r = _enable(oh);
- if (r) {
- pr_warning("omap_hwmod: %s: cannot be enabled (%d)\n",
- oh->name, oh->_state);
- return 0;
+ if (oh->_state != _HWMOD_STATE_INITIALIZED)
+ return -EINVAL;
+
+ if (oh->rst_lines_cnt == 0) {
+ r = _enable(oh);
+ if (r) {
+ pr_warning("omap_hwmod: %s: cannot be enabled for reset (%d)\n",
+ oh->name, oh->_state);
+ return -EINVAL;
+ }
}
if (!(oh->flags & HWMOD_INIT_NO_RESET))
- _reset(oh);
+ r = _reset(oh);
+
+ return r;
+}
+
+/**
+ * _setup_postsetup - transition to the appropriate state after _setup
+ * @oh: struct omap_hwmod *
+ *
+ * Place an IP block represented by @oh into a "post-setup" state --
+ * either IDLE, ENABLED, or DISABLED. ("post-setup" simply means that
+ * this function is called at the end of _setup().) The postsetup
+ * state for an IP block can be changed by calling
+ * omap_hwmod_enter_postsetup_state() early in the boot process,
+ * before one of the omap_hwmod_setup*() functions are called for the
+ * IP block.
+ *
+ * The IP block stays in this state until a PM runtime-based driver is
+ * loaded for that IP block. A post-setup state of IDLE is
+ * appropriate for almost all IP blocks with runtime PM-enabled
+ * drivers, since those drivers are able to enable the IP block. A
+ * post-setup state of ENABLED is appropriate for kernels with PM
+ * runtime disabled. The DISABLED state is appropriate for unusual IP
+ * blocks such as the MPU WDTIMER on kernels without WDTIMER drivers
+ * included, since the WDTIMER starts running on reset and will reset
+ * the MPU if left active.
+ *
+ * This post-setup mechanism is deprecated. Once all of the OMAP
+ * drivers have been converted to use PM runtime, and all of the IP
+ * block data and interconnect data is available to the hwmod code, it
+ * should be possible to replace this mechanism with a "lazy reset"
+ * arrangement. In a "lazy reset" setup, each IP block is enabled
+ * when the driver first probes, then all remaining IP blocks without
+ * drivers are either shut down or enabled after the drivers have
+ * loaded. However, this cannot take place until the above
+ * preconditions have been met, since otherwise the late reset code
+ * has no way of knowing which IP blocks are in use by drivers, and
+ * which ones are unused.
+ *
+ * No return value.
+ */
+static void __init _setup_postsetup(struct omap_hwmod *oh)
+{
+ u8 postsetup_state;
+
+ if (oh->rst_lines_cnt > 0)
+ return;
postsetup_state = oh->_postsetup_state;
if (postsetup_state == _HWMOD_STATE_UNKNOWN)
@@ -1821,6 +2198,35 @@ static int _setup(struct omap_hwmod *oh, void *data)
WARN(1, "hwmod: %s: unknown postsetup state %d! defaulting to enabled\n",
oh->name, postsetup_state);
+ return;
+}
+
+/**
+ * _setup - prepare IP block hardware for use
+ * @oh: struct omap_hwmod *
+ * @n: (unused, pass NULL)
+ *
+ * Configure the IP block represented by @oh. This may include
+ * enabling the IP block, resetting it, and placing it into a
+ * post-setup state, depending on the type of IP block and applicable
+ * flags. IP blocks are reset to prevent any previous configuration
+ * by the bootloader or previous operating system from interfering
+ * with power management or other parts of the system. The reset can
+ * be avoided; see omap_hwmod_no_setup_reset(). This is the second of
+ * two phases for hwmod initialization. Code called here generally
+ * affects the IP block hardware, or system integration hardware
+ * associated with the IP block. Returns 0.
+ */
+static int __init _setup(struct omap_hwmod *oh, void *data)
+{
+ if (oh->_state != _HWMOD_STATE_INITIALIZED)
+ return 0;
+
+ _setup_iclk_autoidle(oh);
+
+ if (!_setup_reset(oh))
+ _setup_postsetup(oh);
+
return 0;
}
@@ -1843,8 +2249,6 @@ static int _setup(struct omap_hwmod *oh, void *data)
*/
static int __init _register(struct omap_hwmod *oh)
{
- int ms_id;
-
if (!oh || !oh->name || !oh->class || !oh->class->name ||
(oh->_state != _HWMOD_STATE_UNKNOWN))
return -EINVAL;
@@ -1854,14 +2258,10 @@ static int __init _register(struct omap_hwmod *oh)
if (_lookup(oh->name))
return -EEXIST;
- ms_id = _find_mpu_port_index(oh);
- if (!IS_ERR_VALUE(ms_id))
- oh->_mpu_port_index = ms_id;
- else
- oh->_int_flags |= _HWMOD_NO_MPU_PORT;
-
list_add_tail(&oh->node, &omap_hwmod_list);
+ INIT_LIST_HEAD(&oh->master_ports);
+ INIT_LIST_HEAD(&oh->slave_ports);
spin_lock_init(&oh->_lock);
oh->_state = _HWMOD_STATE_REGISTERED;
@@ -1876,6 +2276,160 @@ static int __init _register(struct omap_hwmod *oh)
return 0;
}
+/**
+ * _alloc_links - return allocated memory for hwmod links
+ * @ml: pointer to a struct omap_hwmod_link * for the master link
+ * @sl: pointer to a struct omap_hwmod_link * for the slave link
+ *
+ * Return pointers to two struct omap_hwmod_link records, via the
+ * addresses pointed to by @ml and @sl. Will first attempt to return
+ * memory allocated as part of a large initial block, but if that has
+ * been exhausted, will allocate memory itself. Since ideally this
+ * second allocation path will never occur, the number of these
+ * 'supplemental' allocations will be logged when debugging is
+ * enabled. Returns 0.
+ */
+static int __init _alloc_links(struct omap_hwmod_link **ml,
+ struct omap_hwmod_link **sl)
+{
+ unsigned int sz;
+
+ if ((free_ls + LINKS_PER_OCP_IF) <= max_ls) {
+ *ml = &linkspace[free_ls++];
+ *sl = &linkspace[free_ls++];
+ return 0;
+ }
+
+ sz = sizeof(struct omap_hwmod_link) * LINKS_PER_OCP_IF;
+
+ *sl = NULL;
+ *ml = alloc_bootmem(sz);
+
+ memset(*ml, 0, sz);
+
+ *sl = (void *)(*ml) + sizeof(struct omap_hwmod_link);
+
+ ls_supp++;
+ pr_debug("omap_hwmod: supplemental link allocations needed: %d\n",
+ ls_supp * LINKS_PER_OCP_IF);
+
+ return 0;
+};
+
+/**
+ * _add_link - add an interconnect between two IP blocks
+ * @oi: pointer to a struct omap_hwmod_ocp_if record
+ *
+ * Add struct omap_hwmod_link records connecting the master IP block
+ * specified in @oi->master to @oi, and connecting the slave IP block
+ * specified in @oi->slave to @oi. This code is assumed to run before
+ * preemption or SMP has been enabled, thus avoiding the need for
+ * locking in this code. Changes to this assumption will require
+ * additional locking. Returns 0.
+ */
+static int __init _add_link(struct omap_hwmod_ocp_if *oi)
+{
+ struct omap_hwmod_link *ml, *sl;
+
+ pr_debug("omap_hwmod: %s -> %s: adding link\n", oi->master->name,
+ oi->slave->name);
+
+ _alloc_links(&ml, &sl);
+
+ ml->ocp_if = oi;
+ INIT_LIST_HEAD(&ml->node);
+ list_add(&ml->node, &oi->master->master_ports);
+ oi->master->masters_cnt++;
+
+ sl->ocp_if = oi;
+ INIT_LIST_HEAD(&sl->node);
+ list_add(&sl->node, &oi->slave->slave_ports);
+ oi->slave->slaves_cnt++;
+
+ return 0;
+}
+
+/**
+ * _register_link - register a struct omap_hwmod_ocp_if
+ * @oi: struct omap_hwmod_ocp_if *
+ *
+ * Registers the omap_hwmod_ocp_if record @oi. Returns -EEXIST if it
+ * has already been registered; -EINVAL if @oi is NULL or if the
+ * record pointed to by @oi is missing required fields; or 0 upon
+ * success.
+ *
+ * XXX The data should be copied into bootmem, so the original data
+ * should be marked __initdata and freed after init. This would allow
+ * unneeded omap_hwmods to be freed on multi-OMAP configurations.
+ */
+static int __init _register_link(struct omap_hwmod_ocp_if *oi)
+{
+ if (!oi || !oi->master || !oi->slave || !oi->user)
+ return -EINVAL;
+
+ if (oi->_int_flags & _OCPIF_INT_FLAGS_REGISTERED)
+ return -EEXIST;
+
+ pr_debug("omap_hwmod: registering link from %s to %s\n",
+ oi->master->name, oi->slave->name);
+
+ /*
+ * Register the connected hwmods, if they haven't been
+ * registered already
+ */
+ if (oi->master->_state != _HWMOD_STATE_REGISTERED)
+ _register(oi->master);
+
+ if (oi->slave->_state != _HWMOD_STATE_REGISTERED)
+ _register(oi->slave);
+
+ _add_link(oi);
+
+ oi->_int_flags |= _OCPIF_INT_FLAGS_REGISTERED;
+
+ return 0;
+}
+
+/**
+ * _alloc_linkspace - allocate large block of hwmod links
+ * @ois: pointer to an array of struct omap_hwmod_ocp_if records to count
+ *
+ * Allocate a large block of struct omap_hwmod_link records. This
+ * improves boot time significantly by avoiding the need to allocate
+ * individual records one by one. If the number of records to
+ * allocate in the block hasn't been manually specified, this function
+ * will count the number of struct omap_hwmod_ocp_if records in @ois
+ * and use that to determine the allocation size. For SoC families
+ * that require multiple list registrations, such as OMAP3xxx, this
+ * estimation process isn't optimal, so manual estimation is advised
+ * in those cases. Returns -EEXIST if the allocation has already occurred
+ * or 0 upon success.
+ */
+static int __init _alloc_linkspace(struct omap_hwmod_ocp_if **ois)
+{
+ unsigned int i = 0;
+ unsigned int sz;
+
+ if (linkspace) {
+ WARN(1, "linkspace already allocated\n");
+ return -EEXIST;
+ }
+
+ if (max_ls == 0)
+ while (ois[i++])
+ max_ls += LINKS_PER_OCP_IF;
+
+ sz = sizeof(struct omap_hwmod_link) * max_ls;
+
+ pr_debug("omap_hwmod: %s: allocating %d byte linkspace (%d links)\n",
+ __func__, sz, max_ls);
+
+ linkspace = alloc_bootmem(sz);
+
+ memset(linkspace, 0, sz);
+
+ return 0;
+}
/* Public functions */
@@ -2004,120 +2558,101 @@ int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data),
}
/**
- * omap_hwmod_register - register an array of hwmods
- * @ohs: pointer to an array of omap_hwmods to register
+ * omap_hwmod_register_links - register an array of hwmod links
+ * @ois: pointer to an array of omap_hwmod_ocp_if to register
*
* Intended to be called early in boot before the clock framework is
- * initialized. If @ohs is not null, will register all omap_hwmods
- * listed in @ohs that are valid for this chip. Returns 0.
+ * initialized. If @ois is not null, will register all omap_hwmods
+ * listed in @ois that are valid for this chip. Returns 0.
*/
-int __init omap_hwmod_register(struct omap_hwmod **ohs)
+int __init omap_hwmod_register_links(struct omap_hwmod_ocp_if **ois)
{
int r, i;
- if (!ohs)
+ if (!ois)
return 0;
+ if (!linkspace) {
+ if (_alloc_linkspace(ois)) {
+ pr_err("omap_hwmod: could not allocate link space\n");
+ return -ENOMEM;
+ }
+ }
+
i = 0;
do {
- r = _register(ohs[i]);
- WARN(r, "omap_hwmod: %s: _register returned %d\n", ohs[i]->name,
- r);
- } while (ohs[++i]);
+ r = _register_link(ois[i]);
+ WARN(r && r != -EEXIST,
+ "omap_hwmod: _register_link(%s -> %s) returned %d\n",
+ ois[i]->master->name, ois[i]->slave->name, r);
+ } while (ois[++i]);
return 0;
}
-/*
- * _populate_mpu_rt_base - populate the virtual address for a hwmod
+/**
+ * _ensure_mpu_hwmod_is_setup - ensure the MPU SS hwmod is init'ed and set up
+ * @oh: pointer to the hwmod currently being set up (usually not the MPU)
*
- * Must be called only from omap_hwmod_setup_*() so ioremap works properly.
- * Assumes the caller takes care of locking if needed.
+ * If the hwmod data corresponding to the MPU subsystem IP block
+ * hasn't been initialized and set up yet, do so now. This must be
+ * done first since sleep dependencies may be added from other hwmods
+ * to the MPU. Intended to be called only by omap_hwmod_setup*(). No
+ * return value.
*/
-static int __init _populate_mpu_rt_base(struct omap_hwmod *oh, void *data)
+static void __init _ensure_mpu_hwmod_is_setup(struct omap_hwmod *oh)
{
- if (oh->_state != _HWMOD_STATE_REGISTERED)
- return 0;
-
- if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
- return 0;
-
- oh->_mpu_rt_va = _find_mpu_rt_base(oh, oh->_mpu_port_index);
-
- return 0;
+ if (!mpu_oh || mpu_oh->_state == _HWMOD_STATE_UNKNOWN)
+ pr_err("omap_hwmod: %s: MPU initiator hwmod %s not yet registered\n",
+ __func__, MPU_INITIATOR_NAME);
+ else if (mpu_oh->_state == _HWMOD_STATE_REGISTERED && oh != mpu_oh)
+ omap_hwmod_setup_one(MPU_INITIATOR_NAME);
}
/**
* omap_hwmod_setup_one - set up a single hwmod
* @oh_name: const char * name of the already-registered hwmod to set up
*
- * Must be called after omap2_clk_init(). Resolves the struct clk
- * names to struct clk pointers for each registered omap_hwmod. Also
- * calls _setup() on each hwmod. Returns -EINVAL upon error or 0 upon
- * success.
+ * Initialize and set up a single hwmod. Intended to be used for a
+ * small number of early devices, such as the timer IP blocks used for
+ * the scheduler clock. Must be called after omap2_clk_init().
+ * Resolves the struct clk names to struct clk pointers for each
+ * registered omap_hwmod. Also calls _setup() on each hwmod. Returns
+ * -EINVAL upon error or 0 upon success.
*/
int __init omap_hwmod_setup_one(const char *oh_name)
{
struct omap_hwmod *oh;
- int r;
pr_debug("omap_hwmod: %s: %s\n", oh_name, __func__);
- if (!mpu_oh) {
- pr_err("omap_hwmod: %s: cannot setup_one: MPU initiator hwmod %s not yet registered\n",
- oh_name, MPU_INITIATOR_NAME);
- return -EINVAL;
- }
-
oh = _lookup(oh_name);
if (!oh) {
WARN(1, "omap_hwmod: %s: hwmod not yet registered\n", oh_name);
return -EINVAL;
}
- if (mpu_oh->_state == _HWMOD_STATE_REGISTERED && oh != mpu_oh)
- omap_hwmod_setup_one(MPU_INITIATOR_NAME);
-
- r = _populate_mpu_rt_base(oh, NULL);
- if (IS_ERR_VALUE(r)) {
- WARN(1, "omap_hwmod: %s: couldn't set mpu_rt_base\n", oh_name);
- return -EINVAL;
- }
-
- r = _init_clocks(oh, NULL);
- if (IS_ERR_VALUE(r)) {
- WARN(1, "omap_hwmod: %s: couldn't init clocks\n", oh_name);
- return -EINVAL;
- }
+ _ensure_mpu_hwmod_is_setup(oh);
+ _init(oh, NULL);
_setup(oh, NULL);
return 0;
}
/**
- * omap_hwmod_setup - do some post-clock framework initialization
+ * omap_hwmod_setup_all - set up all registered IP blocks
*
- * Must be called after omap2_clk_init(). Resolves the struct clk names
- * to struct clk pointers for each registered omap_hwmod. Also calls
- * _setup() on each hwmod. Returns 0 upon success.
+ * Initialize and set up all IP blocks registered with the hwmod code.
+ * Must be called after omap2_clk_init(). Resolves the struct clk
+ * names to struct clk pointers for each registered omap_hwmod. Also
+ * calls _setup() on each hwmod. Returns 0 upon success.
*/
static int __init omap_hwmod_setup_all(void)
{
- int r;
-
- if (!mpu_oh) {
- pr_err("omap_hwmod: %s: MPU initiator hwmod %s not yet registered\n",
- __func__, MPU_INITIATOR_NAME);
- return -EINVAL;
- }
-
- r = omap_hwmod_for_each(_populate_mpu_rt_base, NULL);
-
- r = omap_hwmod_for_each(_init_clocks, NULL);
- WARN(IS_ERR_VALUE(r),
- "omap_hwmod: %s: _init_clocks failed\n", __func__);
+ _ensure_mpu_hwmod_is_setup(NULL);
+ omap_hwmod_for_each(_init, NULL);
omap_hwmod_for_each(_setup, NULL);
return 0;
@@ -2274,6 +2809,10 @@ int omap_hwmod_reset(struct omap_hwmod *oh)
return r;
}
+/*
+ * IP block data retrieval functions
+ */
+
/**
* omap_hwmod_count_resources - count number of struct resources needed by hwmod
* @oh: struct omap_hwmod *
@@ -2292,12 +2831,19 @@ int omap_hwmod_reset(struct omap_hwmod *oh)
*/
int omap_hwmod_count_resources(struct omap_hwmod *oh)
{
- int ret, i;
+ struct omap_hwmod_ocp_if *os;
+ struct list_head *p;
+ int ret;
+ int i = 0;
ret = _count_mpu_irqs(oh) + _count_sdma_reqs(oh);
- for (i = 0; i < oh->slaves_cnt; i++)
- ret += _count_ocp_if_addr_spaces(oh->slaves[i]);
+ p = oh->slave_ports.next;
+
+ while (i < oh->slaves_cnt) {
+ os = _fetch_next_ocp_if(&p, &i);
+ ret += _count_ocp_if_addr_spaces(os);
+ }
return ret;
}
@@ -2314,7 +2860,9 @@ int omap_hwmod_count_resources(struct omap_hwmod *oh)
*/
int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res)
{
- int i, j, mpu_irqs_cnt, sdma_reqs_cnt;
+ struct omap_hwmod_ocp_if *os;
+ struct list_head *p;
+ int i, j, mpu_irqs_cnt, sdma_reqs_cnt, addr_cnt;
int r = 0;
/* For each IRQ, DMA, memory area, fill in array.*/
@@ -2337,11 +2885,11 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res)
r++;
}
- for (i = 0; i < oh->slaves_cnt; i++) {
- struct omap_hwmod_ocp_if *os;
- int addr_cnt;
+ p = oh->slave_ports.next;
- os = oh->slaves[i];
+ i = 0;
+ while (i < oh->slaves_cnt) {
+ os = _fetch_next_ocp_if(&p, &i);
addr_cnt = _count_ocp_if_addr_spaces(os);
for (j = 0; j < addr_cnt; j++) {
@@ -2357,6 +2905,69 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res)
}
/**
+ * omap_hwmod_get_resource_byname - fetch IP block integration data by name
+ * @oh: struct omap_hwmod * to operate on
+ * @type: one of the IORESOURCE_* constants from include/linux/ioport.h
+ * @name: pointer to the name of the data to fetch (optional)
+ * @rsrc: pointer to a struct resource, allocated by the caller
+ *
+ * Retrieve MPU IRQ, SDMA request line, or address space start/end
+ * data for the IP block pointed to by @oh. The data will be filled
+ * into a struct resource record pointed to by @rsrc. The struct
+ * resource must be allocated by the caller. When @name is non-null,
+ * the data associated with the matching entry in the IRQ/SDMA/address
+ * space hwmod data arrays will be returned. If @name is null, the
+ * first array entry will be returned. Data order is not meaningful
+ * in hwmod data, so callers are strongly encouraged to use a non-null
+ * @name whenever possible to avoid unpredictable effects if hwmod
+ * data is later added that causes data ordering to change. This
+ * function is only intended for use by OMAP core code. Device
+ * drivers should not call this function - the appropriate bus-related
+ * data accessor functions should be used instead. Returns 0 upon
+ * success or a negative error code upon error.
+ */
+int omap_hwmod_get_resource_byname(struct omap_hwmod *oh, unsigned int type,
+ const char *name, struct resource *rsrc)
+{
+ int r;
+ unsigned int irq, dma;
+ u32 pa_start, pa_end;
+
+ if (!oh || !rsrc)
+ return -EINVAL;
+
+ if (type == IORESOURCE_IRQ) {
+ r = _get_mpu_irq_by_name(oh, name, &irq);
+ if (r)
+ return r;
+
+ rsrc->start = irq;
+ rsrc->end = irq;
+ } else if (type == IORESOURCE_DMA) {
+ r = _get_sdma_req_by_name(oh, name, &dma);
+ if (r)
+ return r;
+
+ rsrc->start = dma;
+ rsrc->end = dma;
+ } else if (type == IORESOURCE_MEM) {
+ r = _get_addr_space_by_name(oh, name, &pa_start, &pa_end);
+ if (r)
+ return r;
+
+ rsrc->start = pa_start;
+ rsrc->end = pa_end;
+ } else {
+ return -EINVAL;
+ }
+
+ rsrc->flags = type;
+ rsrc->name = name;
+
+ return 0;
+}
+
+/**
* omap_hwmod_get_pwrdm - return pointer to this module's main powerdomain
* @oh: struct omap_hwmod *
*
@@ -2370,6 +2981,7 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res)
struct powerdomain *omap_hwmod_get_pwrdm(struct omap_hwmod *oh)
{
struct clk *c;
+ struct omap_hwmod_ocp_if *oi;
if (!oh)
return NULL;
@@ -2377,9 +2989,10 @@ struct powerdomain *omap_hwmod_get_pwrdm(struct omap_hwmod *oh)
if (oh->_clk) {
c = oh->_clk;
} else {
- if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
+ oi = _find_mpu_rt_port(oh);
+ if (!oi)
return NULL;
- c = oh->slaves[oh->_mpu_port_index]->_clk;
+ c = oi->_clk;
}
if (!c->clkdm)
@@ -2653,10 +3266,10 @@ int omap_hwmod_for_each_by_class(const char *classname,
* @state: state that _setup() should leave the hwmod in
*
* Sets the hwmod state that @oh will enter at the end of _setup()
- * (called by omap_hwmod_setup_*()). Only valid to call between
- * calling omap_hwmod_register() and omap_hwmod_setup_*(). Returns
- * 0 upon success or -EINVAL if there is a problem with the arguments
- * or if the hwmod is in the wrong state.
+ * (called by omap_hwmod_setup_*()). See also the documentation
+ * for _setup_postsetup(), above. Returns 0 upon success or
+ * -EINVAL if there is a problem with the arguments or if the hwmod is
+ * in the wrong state.
*/
int omap_hwmod_set_postsetup_state(struct omap_hwmod *oh, u8 state)
{
diff --git a/arch/arm/mach-omap2/omap_hwmod_2420_data.c b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
index a6bde34e443a..a7640d1b215e 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2420_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2420_data.c
@@ -2,6 +2,7 @@
* omap_hwmod_2420_data.c - hardware modules present on the OMAP2420 chips
*
* Copyright (C) 2009-2011 Nokia Corporation
+ * Copyright (C) 2012 Texas Instruments, Inc.
* Paul Walmsley
*
* This program is free software; you can redistribute it and/or modify
@@ -22,6 +23,7 @@
#include <plat/dmtimer.h>
#include <plat/l3_2xxx.h>
#include <plat/l4_2xxx.h>
+#include <plat/mmc.h>
#include "omap_hwmod_common_data.h"
@@ -32,707 +34,329 @@
/*
* OMAP2420 hardware module integration data
*
- * ALl of the data in this section should be autogeneratable from the
+ * All of the data in this section should be autogeneratable from the
* TI hardware database or other technical documentation. Data that
* is driver-specific or driver-kernel integration-specific belongs
* elsewhere.
*/
-static struct omap_hwmod omap2420_mpu_hwmod;
-static struct omap_hwmod omap2420_iva_hwmod;
-static struct omap_hwmod omap2420_l3_main_hwmod;
-static struct omap_hwmod omap2420_l4_core_hwmod;
-static struct omap_hwmod omap2420_dss_core_hwmod;
-static struct omap_hwmod omap2420_dss_dispc_hwmod;
-static struct omap_hwmod omap2420_dss_rfbi_hwmod;
-static struct omap_hwmod omap2420_dss_venc_hwmod;
-static struct omap_hwmod omap2420_wd_timer2_hwmod;
-static struct omap_hwmod omap2420_gpio1_hwmod;
-static struct omap_hwmod omap2420_gpio2_hwmod;
-static struct omap_hwmod omap2420_gpio3_hwmod;
-static struct omap_hwmod omap2420_gpio4_hwmod;
-static struct omap_hwmod omap2420_dma_system_hwmod;
-static struct omap_hwmod omap2420_mcspi1_hwmod;
-static struct omap_hwmod omap2420_mcspi2_hwmod;
-
-/* L3 -> L4_CORE interface */
-static struct omap_hwmod_ocp_if omap2420_l3_main__l4_core = {
- .master = &omap2420_l3_main_hwmod,
- .slave = &omap2420_l4_core_hwmod,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* MPU -> L3 interface */
-static struct omap_hwmod_ocp_if omap2420_mpu__l3_main = {
- .master = &omap2420_mpu_hwmod,
- .slave = &omap2420_l3_main_hwmod,
- .user = OCP_USER_MPU,
-};
-
-/* Slave interfaces on the L3 interconnect */
-static struct omap_hwmod_ocp_if *omap2420_l3_main_slaves[] = {
- &omap2420_mpu__l3_main,
-};
-
-/* DSS -> l3 */
-static struct omap_hwmod_ocp_if omap2420_dss__l3 = {
- .master = &omap2420_dss_core_hwmod,
- .slave = &omap2420_l3_main_hwmod,
- .fw = {
- .omap2 = {
- .l3_perm_bit = OMAP2_L3_CORE_FW_CONNID_DSS,
- .flags = OMAP_FIREWALL_L3,
- }
- },
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* Master interfaces on the L3 interconnect */
-static struct omap_hwmod_ocp_if *omap2420_l3_main_masters[] = {
- &omap2420_l3_main__l4_core,
-};
-
-/* L3 */
-static struct omap_hwmod omap2420_l3_main_hwmod = {
- .name = "l3_main",
- .class = &l3_hwmod_class,
- .masters = omap2420_l3_main_masters,
- .masters_cnt = ARRAY_SIZE(omap2420_l3_main_masters),
- .slaves = omap2420_l3_main_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_l3_main_slaves),
- .flags = HWMOD_NO_IDLEST,
-};
-
-static struct omap_hwmod omap2420_l4_wkup_hwmod;
-static struct omap_hwmod omap2420_uart1_hwmod;
-static struct omap_hwmod omap2420_uart2_hwmod;
-static struct omap_hwmod omap2420_uart3_hwmod;
-static struct omap_hwmod omap2420_i2c1_hwmod;
-static struct omap_hwmod omap2420_i2c2_hwmod;
-static struct omap_hwmod omap2420_mcbsp1_hwmod;
-static struct omap_hwmod omap2420_mcbsp2_hwmod;
-
-/* l4 core -> mcspi1 interface */
-static struct omap_hwmod_ocp_if omap2420_l4_core__mcspi1 = {
- .master = &omap2420_l4_core_hwmod,
- .slave = &omap2420_mcspi1_hwmod,
- .clk = "mcspi1_ick",
- .addr = omap2_mcspi1_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4 core -> mcspi2 interface */
-static struct omap_hwmod_ocp_if omap2420_l4_core__mcspi2 = {
- .master = &omap2420_l4_core_hwmod,
- .slave = &omap2420_mcspi2_hwmod,
- .clk = "mcspi2_ick",
- .addr = omap2_mcspi2_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4_CORE -> L4_WKUP interface */
-static struct omap_hwmod_ocp_if omap2420_l4_core__l4_wkup = {
- .master = &omap2420_l4_core_hwmod,
- .slave = &omap2420_l4_wkup_hwmod,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 CORE -> UART1 interface */
-static struct omap_hwmod_ocp_if omap2_l4_core__uart1 = {
- .master = &omap2420_l4_core_hwmod,
- .slave = &omap2420_uart1_hwmod,
- .clk = "uart1_ick",
- .addr = omap2xxx_uart1_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 CORE -> UART2 interface */
-static struct omap_hwmod_ocp_if omap2_l4_core__uart2 = {
- .master = &omap2420_l4_core_hwmod,
- .slave = &omap2420_uart2_hwmod,
- .clk = "uart2_ick",
- .addr = omap2xxx_uart2_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 PER -> UART3 interface */
-static struct omap_hwmod_ocp_if omap2_l4_core__uart3 = {
- .master = &omap2420_l4_core_hwmod,
- .slave = &omap2420_uart3_hwmod,
- .clk = "uart3_ick",
- .addr = omap2xxx_uart3_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 CORE -> I2C1 interface */
-static struct omap_hwmod_ocp_if omap2420_l4_core__i2c1 = {
- .master = &omap2420_l4_core_hwmod,
- .slave = &omap2420_i2c1_hwmod,
- .clk = "i2c1_ick",
- .addr = omap2_i2c1_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 CORE -> I2C2 interface */
-static struct omap_hwmod_ocp_if omap2420_l4_core__i2c2 = {
- .master = &omap2420_l4_core_hwmod,
- .slave = &omap2420_i2c2_hwmod,
- .clk = "i2c2_ick",
- .addr = omap2_i2c2_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* Slave interfaces on the L4_CORE interconnect */
-static struct omap_hwmod_ocp_if *omap2420_l4_core_slaves[] = {
- &omap2420_l3_main__l4_core,
-};
-
-/* Master interfaces on the L4_CORE interconnect */
-static struct omap_hwmod_ocp_if *omap2420_l4_core_masters[] = {
- &omap2420_l4_core__l4_wkup,
- &omap2_l4_core__uart1,
- &omap2_l4_core__uart2,
- &omap2_l4_core__uart3,
- &omap2420_l4_core__i2c1,
- &omap2420_l4_core__i2c2
-};
-
-/* L4 CORE */
-static struct omap_hwmod omap2420_l4_core_hwmod = {
- .name = "l4_core",
- .class = &l4_hwmod_class,
- .masters = omap2420_l4_core_masters,
- .masters_cnt = ARRAY_SIZE(omap2420_l4_core_masters),
- .slaves = omap2420_l4_core_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_l4_core_slaves),
- .flags = HWMOD_NO_IDLEST,
-};
-
-/* Slave interfaces on the L4_WKUP interconnect */
-static struct omap_hwmod_ocp_if *omap2420_l4_wkup_slaves[] = {
- &omap2420_l4_core__l4_wkup,
-};
-
-/* Master interfaces on the L4_WKUP interconnect */
-static struct omap_hwmod_ocp_if *omap2420_l4_wkup_masters[] = {
-};
-
-/* L4 WKUP */
-static struct omap_hwmod omap2420_l4_wkup_hwmod = {
- .name = "l4_wkup",
- .class = &l4_hwmod_class,
- .masters = omap2420_l4_wkup_masters,
- .masters_cnt = ARRAY_SIZE(omap2420_l4_wkup_masters),
- .slaves = omap2420_l4_wkup_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_l4_wkup_slaves),
- .flags = HWMOD_NO_IDLEST,
-};
-
-/* Master interfaces on the MPU device */
-static struct omap_hwmod_ocp_if *omap2420_mpu_masters[] = {
- &omap2420_mpu__l3_main,
-};
-
-/* MPU */
-static struct omap_hwmod omap2420_mpu_hwmod = {
- .name = "mpu",
- .class = &mpu_hwmod_class,
- .main_clk = "mpu_ck",
- .masters = omap2420_mpu_masters,
- .masters_cnt = ARRAY_SIZE(omap2420_mpu_masters),
-};
-
/*
- * IVA1 interface data
+ * IP blocks
*/
-/* IVA <- L3 interface */
-static struct omap_hwmod_ocp_if omap2420_l3__iva = {
- .master = &omap2420_l3_main_hwmod,
- .slave = &omap2420_iva_hwmod,
- .clk = "iva1_ifck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
+/* IVA1 (IVA1) */
+static struct omap_hwmod_class iva1_hwmod_class = {
+ .name = "iva1",
};
-static struct omap_hwmod_ocp_if *omap2420_iva_masters[] = {
- &omap2420_l3__iva,
+static struct omap_hwmod_rst_info omap2420_iva_resets[] = {
+ { .name = "iva", .rst_shift = 8 },
};
-/*
- * IVA2 (IVA2)
- */
-
static struct omap_hwmod omap2420_iva_hwmod = {
.name = "iva",
- .class = &iva_hwmod_class,
- .masters = omap2420_iva_masters,
- .masters_cnt = ARRAY_SIZE(omap2420_iva_masters),
-};
-
-/* always-on timers dev attribute */
-static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
- .timer_capability = OMAP_TIMER_ALWON,
+ .class = &iva1_hwmod_class,
+ .clkdm_name = "iva1_clkdm",
+ .rst_lines = omap2420_iva_resets,
+ .rst_lines_cnt = ARRAY_SIZE(omap2420_iva_resets),
+ .main_clk = "iva1_ifck",
};
-/* pwm timers dev attribute */
-static struct omap_timer_capability_dev_attr capability_pwm_dev_attr = {
- .timer_capability = OMAP_TIMER_HAS_PWM,
-};
-
-/* timer1 */
-static struct omap_hwmod omap2420_timer1_hwmod;
-
-static struct omap_hwmod_addr_space omap2420_timer1_addrs[] = {
- {
- .pa_start = 0x48028000,
- .pa_end = 0x48028000 + SZ_1K - 1,
- .flags = ADDR_TYPE_RT
- },
- { }
+/* DSP */
+static struct omap_hwmod_class dsp_hwmod_class = {
+ .name = "dsp",
};
-/* l4_wkup -> timer1 */
-static struct omap_hwmod_ocp_if omap2420_l4_wkup__timer1 = {
- .master = &omap2420_l4_wkup_hwmod,
- .slave = &omap2420_timer1_hwmod,
- .clk = "gpt1_ick",
- .addr = omap2420_timer1_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
+static struct omap_hwmod_rst_info omap2420_dsp_resets[] = {
+ { .name = "logic", .rst_shift = 0 },
+ { .name = "mmu", .rst_shift = 1 },
};
-/* timer1 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer1_slaves[] = {
- &omap2420_l4_wkup__timer1,
+static struct omap_hwmod omap2420_dsp_hwmod = {
+ .name = "dsp",
+ .class = &dsp_hwmod_class,
+ .clkdm_name = "dsp_clkdm",
+ .rst_lines = omap2420_dsp_resets,
+ .rst_lines_cnt = ARRAY_SIZE(omap2420_dsp_resets),
+ .main_clk = "dsp_fck",
};
-/* timer1 hwmod */
-static struct omap_hwmod omap2420_timer1_hwmod = {
- .name = "timer1",
- .mpu_irqs = omap2_timer1_mpu_irqs,
- .main_clk = "gpt1_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT1_SHIFT,
- .module_offs = WKUP_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT1_SHIFT,
- },
- },
- .dev_attr = &capability_alwon_dev_attr,
- .slaves = omap2420_timer1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_timer1_slaves),
- .class = &omap2xxx_timer_hwmod_class,
+/* I2C common */
+static struct omap_hwmod_class_sysconfig i2c_sysc = {
+ .rev_offs = 0x00,
+ .sysc_offs = 0x20,
+ .syss_offs = 0x10,
+ .sysc_flags = (SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+ .sysc_fields = &omap_hwmod_sysc_type1,
};
-/* timer2 */
-static struct omap_hwmod omap2420_timer2_hwmod;
-
-/* l4_core -> timer2 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__timer2 = {
- .master = &omap2420_l4_core_hwmod,
- .slave = &omap2420_timer2_hwmod,
- .clk = "gpt2_ick",
- .addr = omap2xxx_timer2_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
+static struct omap_hwmod_class i2c_class = {
+ .name = "i2c",
+ .sysc = &i2c_sysc,
+ .rev = OMAP_I2C_IP_VERSION_1,
+ .reset = &omap_i2c_reset,
};
-/* timer2 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer2_slaves[] = {
- &omap2420_l4_core__timer2,
+static struct omap_i2c_dev_attr i2c_dev_attr = {
+ .flags = OMAP_I2C_FLAG_NO_FIFO |
+ OMAP_I2C_FLAG_SIMPLE_CLOCK |
+ OMAP_I2C_FLAG_16BIT_DATA_REG |
+ OMAP_I2C_FLAG_BUS_SHIFT_2,
};
-/* timer2 hwmod */
-static struct omap_hwmod omap2420_timer2_hwmod = {
- .name = "timer2",
- .mpu_irqs = omap2_timer2_mpu_irqs,
- .main_clk = "gpt2_fck",
+/* I2C1 */
+static struct omap_hwmod omap2420_i2c1_hwmod = {
+ .name = "i2c1",
+ .mpu_irqs = omap2_i2c1_mpu_irqs,
+ .sdma_reqs = omap2_i2c1_sdma_reqs,
+ .main_clk = "i2c1_fck",
.prcm = {
.omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT2_SHIFT,
.module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP2420_EN_I2C1_SHIFT,
.idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT2_SHIFT,
+ .idlest_idle_bit = OMAP2420_ST_I2C1_SHIFT,
},
},
- .dev_attr = &capability_alwon_dev_attr,
- .slaves = omap2420_timer2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_timer2_slaves),
- .class = &omap2xxx_timer_hwmod_class,
-};
-
-/* timer3 */
-static struct omap_hwmod omap2420_timer3_hwmod;
-
-/* l4_core -> timer3 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__timer3 = {
- .master = &omap2420_l4_core_hwmod,
- .slave = &omap2420_timer3_hwmod,
- .clk = "gpt3_ick",
- .addr = omap2xxx_timer3_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer3 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer3_slaves[] = {
- &omap2420_l4_core__timer3,
+ .class = &i2c_class,
+ .dev_attr = &i2c_dev_attr,
+ .flags = HWMOD_16BIT_REG,
};
-/* timer3 hwmod */
-static struct omap_hwmod omap2420_timer3_hwmod = {
- .name = "timer3",
- .mpu_irqs = omap2_timer3_mpu_irqs,
- .main_clk = "gpt3_fck",
+/* I2C2 */
+static struct omap_hwmod omap2420_i2c2_hwmod = {
+ .name = "i2c2",
+ .mpu_irqs = omap2_i2c2_mpu_irqs,
+ .sdma_reqs = omap2_i2c2_sdma_reqs,
+ .main_clk = "i2c2_fck",
.prcm = {
.omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT3_SHIFT,
.module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP2420_EN_I2C2_SHIFT,
.idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT3_SHIFT,
+ .idlest_idle_bit = OMAP2420_ST_I2C2_SHIFT,
},
},
- .dev_attr = &capability_alwon_dev_attr,
- .slaves = omap2420_timer3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_timer3_slaves),
- .class = &omap2xxx_timer_hwmod_class,
+ .class = &i2c_class,
+ .dev_attr = &i2c_dev_attr,
+ .flags = HWMOD_16BIT_REG,
};
-/* timer4 */
-static struct omap_hwmod omap2420_timer4_hwmod;
+/* dma attributes */
+static struct omap_dma_dev_attr dma_dev_attr = {
+ .dev_caps = RESERVE_CHANNEL | DMA_LINKED_LCH | GLOBAL_PRIORITY |
+ IS_CSSA_32 | IS_CDSA_32,
+ .lch_count = 32,
+};
-/* l4_core -> timer4 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__timer4 = {
- .master = &omap2420_l4_core_hwmod,
- .slave = &omap2420_timer4_hwmod,
- .clk = "gpt4_ick",
- .addr = omap2xxx_timer4_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
+static struct omap_hwmod omap2420_dma_system_hwmod = {
+ .name = "dma",
+ .class = &omap2xxx_dma_hwmod_class,
+ .mpu_irqs = omap2_dma_system_irqs,
+ .main_clk = "core_l3_ck",
+ .dev_attr = &dma_dev_attr,
+ .flags = HWMOD_NO_IDLEST,
};
-/* timer4 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer4_slaves[] = {
- &omap2420_l4_core__timer4,
+/* mailbox */
+static struct omap_hwmod_irq_info omap2420_mailbox_irqs[] = {
+ { .name = "dsp", .irq = 26 },
+ { .name = "iva", .irq = 34 },
+ { .irq = -1 }
};
-/* timer4 hwmod */
-static struct omap_hwmod omap2420_timer4_hwmod = {
- .name = "timer4",
- .mpu_irqs = omap2_timer4_mpu_irqs,
- .main_clk = "gpt4_fck",
+static struct omap_hwmod omap2420_mailbox_hwmod = {
+ .name = "mailbox",
+ .class = &omap2xxx_mailbox_hwmod_class,
+ .mpu_irqs = omap2420_mailbox_irqs,
+ .main_clk = "mailboxes_ick",
.prcm = {
.omap2 = {
.prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT4_SHIFT,
+ .module_bit = OMAP24XX_EN_MAILBOXES_SHIFT,
.module_offs = CORE_MOD,
.idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT4_SHIFT,
+ .idlest_idle_bit = OMAP24XX_ST_MAILBOXES_SHIFT,
},
},
- .dev_attr = &capability_alwon_dev_attr,
- .slaves = omap2420_timer4_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_timer4_slaves),
- .class = &omap2xxx_timer_hwmod_class,
};
-/* timer5 */
-static struct omap_hwmod omap2420_timer5_hwmod;
+/*
+ * 'mcbsp' class
+ * multi channel buffered serial port controller
+ */
-/* l4_core -> timer5 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__timer5 = {
- .master = &omap2420_l4_core_hwmod,
- .slave = &omap2420_timer5_hwmod,
- .clk = "gpt5_ick",
- .addr = omap2xxx_timer5_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
+static struct omap_hwmod_class omap2420_mcbsp_hwmod_class = {
+ .name = "mcbsp",
};
-/* timer5 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer5_slaves[] = {
- &omap2420_l4_core__timer5,
+/* mcbsp1 */
+static struct omap_hwmod_irq_info omap2420_mcbsp1_irqs[] = {
+ { .name = "tx", .irq = 59 },
+ { .name = "rx", .irq = 60 },
+ { .irq = -1 }
};
-/* timer5 hwmod */
-static struct omap_hwmod omap2420_timer5_hwmod = {
- .name = "timer5",
- .mpu_irqs = omap2_timer5_mpu_irqs,
- .main_clk = "gpt5_fck",
+static struct omap_hwmod omap2420_mcbsp1_hwmod = {
+ .name = "mcbsp1",
+ .class = &omap2420_mcbsp_hwmod_class,
+ .mpu_irqs = omap2420_mcbsp1_irqs,
+ .sdma_reqs = omap2_mcbsp1_sdma_reqs,
+ .main_clk = "mcbsp1_fck",
.prcm = {
.omap2 = {
.prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT5_SHIFT,
+ .module_bit = OMAP24XX_EN_MCBSP1_SHIFT,
.module_offs = CORE_MOD,
.idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT5_SHIFT,
+ .idlest_idle_bit = OMAP24XX_ST_MCBSP1_SHIFT,
},
},
- .dev_attr = &capability_alwon_dev_attr,
- .slaves = omap2420_timer5_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_timer5_slaves),
- .class = &omap2xxx_timer_hwmod_class,
};
-
-/* timer6 */
-static struct omap_hwmod omap2420_timer6_hwmod;
-
-/* l4_core -> timer6 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__timer6 = {
- .master = &omap2420_l4_core_hwmod,
- .slave = &omap2420_timer6_hwmod,
- .clk = "gpt6_ick",
- .addr = omap2xxx_timer6_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer6 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer6_slaves[] = {
- &omap2420_l4_core__timer6,
+/* mcbsp2 */
+static struct omap_hwmod_irq_info omap2420_mcbsp2_irqs[] = {
+ { .name = "tx", .irq = 62 },
+ { .name = "rx", .irq = 63 },
+ { .irq = -1 }
};
-/* timer6 hwmod */
-static struct omap_hwmod omap2420_timer6_hwmod = {
- .name = "timer6",
- .mpu_irqs = omap2_timer6_mpu_irqs,
- .main_clk = "gpt6_fck",
+static struct omap_hwmod omap2420_mcbsp2_hwmod = {
+ .name = "mcbsp2",
+ .class = &omap2420_mcbsp_hwmod_class,
+ .mpu_irqs = omap2420_mcbsp2_irqs,
+ .sdma_reqs = omap2_mcbsp2_sdma_reqs,
+ .main_clk = "mcbsp2_fck",
.prcm = {
.omap2 = {
.prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT6_SHIFT,
+ .module_bit = OMAP24XX_EN_MCBSP2_SHIFT,
.module_offs = CORE_MOD,
.idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT6_SHIFT,
+ .idlest_idle_bit = OMAP24XX_ST_MCBSP2_SHIFT,
},
},
- .dev_attr = &capability_alwon_dev_attr,
- .slaves = omap2420_timer6_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_timer6_slaves),
- .class = &omap2xxx_timer_hwmod_class,
};
-/* timer7 */
-static struct omap_hwmod omap2420_timer7_hwmod;
-
-/* l4_core -> timer7 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__timer7 = {
- .master = &omap2420_l4_core_hwmod,
- .slave = &omap2420_timer7_hwmod,
- .clk = "gpt7_ick",
- .addr = omap2xxx_timer7_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer7 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer7_slaves[] = {
- &omap2420_l4_core__timer7,
+static struct omap_hwmod_class_sysconfig omap2420_msdi_sysc = {
+ .rev_offs = 0x3c,
+ .sysc_offs = 0x64,
+ .syss_offs = 0x68,
+ .sysc_flags = (SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+ .sysc_fields = &omap_hwmod_sysc_type1,
};
-/* timer7 hwmod */
-static struct omap_hwmod omap2420_timer7_hwmod = {
- .name = "timer7",
- .mpu_irqs = omap2_timer7_mpu_irqs,
- .main_clk = "gpt7_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT7_SHIFT,
- .module_offs = CORE_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT7_SHIFT,
- },
- },
- .dev_attr = &capability_alwon_dev_attr,
- .slaves = omap2420_timer7_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_timer7_slaves),
- .class = &omap2xxx_timer_hwmod_class,
+static struct omap_hwmod_class omap2420_msdi_hwmod_class = {
+ .name = "msdi",
+ .sysc = &omap2420_msdi_sysc,
+ .reset = &omap_msdi_reset,
};
-/* timer8 */
-static struct omap_hwmod omap2420_timer8_hwmod;
-
-/* l4_core -> timer8 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__timer8 = {
- .master = &omap2420_l4_core_hwmod,
- .slave = &omap2420_timer8_hwmod,
- .clk = "gpt8_ick",
- .addr = omap2xxx_timer8_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
+/* msdi1 */
+static struct omap_hwmod_irq_info omap2420_msdi1_irqs[] = {
+ { .irq = 83 },
+ { .irq = -1 }
};
-/* timer8 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer8_slaves[] = {
- &omap2420_l4_core__timer8,
+static struct omap_hwmod_dma_info omap2420_msdi1_sdma_reqs[] = {
+ { .name = "tx", .dma_req = 61 }, /* OMAP24XX_DMA_MMC1_TX */
+ { .name = "rx", .dma_req = 62 }, /* OMAP24XX_DMA_MMC1_RX */
+ { .dma_req = -1 }
};
-/* timer8 hwmod */
-static struct omap_hwmod omap2420_timer8_hwmod = {
- .name = "timer8",
- .mpu_irqs = omap2_timer8_mpu_irqs,
- .main_clk = "gpt8_fck",
+static struct omap_hwmod omap2420_msdi1_hwmod = {
+ .name = "msdi1",
+ .class = &omap2420_msdi_hwmod_class,
+ .mpu_irqs = omap2420_msdi1_irqs,
+ .sdma_reqs = omap2420_msdi1_sdma_reqs,
+ .main_clk = "mmc_fck",
.prcm = {
.omap2 = {
.prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT8_SHIFT,
+ .module_bit = OMAP2420_EN_MMC_SHIFT,
.module_offs = CORE_MOD,
.idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT8_SHIFT,
+ .idlest_idle_bit = OMAP2420_ST_MMC_SHIFT,
},
},
- .dev_attr = &capability_alwon_dev_attr,
- .slaves = omap2420_timer8_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_timer8_slaves),
- .class = &omap2xxx_timer_hwmod_class,
-};
-
-/* timer9 */
-static struct omap_hwmod omap2420_timer9_hwmod;
-
-/* l4_core -> timer9 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__timer9 = {
- .master = &omap2420_l4_core_hwmod,
- .slave = &omap2420_timer9_hwmod,
- .clk = "gpt9_ick",
- .addr = omap2xxx_timer9_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer9 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer9_slaves[] = {
- &omap2420_l4_core__timer9,
+ .flags = HWMOD_16BIT_REG,
};
-/* timer9 hwmod */
-static struct omap_hwmod omap2420_timer9_hwmod = {
- .name = "timer9",
- .mpu_irqs = omap2_timer9_mpu_irqs,
- .main_clk = "gpt9_fck",
+/* HDQ1W/1-wire */
+static struct omap_hwmod omap2420_hdq1w_hwmod = {
+ .name = "hdq1w",
+ .mpu_irqs = omap2_hdq1w_mpu_irqs,
+ .main_clk = "hdq_fck",
.prcm = {
.omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT9_SHIFT,
.module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_HDQ_SHIFT,
.idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT9_SHIFT,
+ .idlest_idle_bit = OMAP24XX_ST_HDQ_SHIFT,
},
},
- .dev_attr = &capability_pwm_dev_attr,
- .slaves = omap2420_timer9_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_timer9_slaves),
- .class = &omap2xxx_timer_hwmod_class,
+ .class = &omap2_hdq1w_class,
};
-/* timer10 */
-static struct omap_hwmod omap2420_timer10_hwmod;
+/*
+ * interfaces
+ */
-/* l4_core -> timer10 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__timer10 = {
- .master = &omap2420_l4_core_hwmod,
- .slave = &omap2420_timer10_hwmod,
- .clk = "gpt10_ick",
- .addr = omap2_timer10_addrs,
+/* L4 CORE -> I2C1 interface */
+static struct omap_hwmod_ocp_if omap2420_l4_core__i2c1 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2420_i2c1_hwmod,
+ .clk = "i2c1_ick",
+ .addr = omap2_i2c1_addr_space,
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-/* timer10 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer10_slaves[] = {
- &omap2420_l4_core__timer10,
-};
-
-/* timer10 hwmod */
-static struct omap_hwmod omap2420_timer10_hwmod = {
- .name = "timer10",
- .mpu_irqs = omap2_timer10_mpu_irqs,
- .main_clk = "gpt10_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT10_SHIFT,
- .module_offs = CORE_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT10_SHIFT,
- },
- },
- .dev_attr = &capability_pwm_dev_attr,
- .slaves = omap2420_timer10_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_timer10_slaves),
- .class = &omap2xxx_timer_hwmod_class,
+/* L4 CORE -> I2C2 interface */
+static struct omap_hwmod_ocp_if omap2420_l4_core__i2c2 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2420_i2c2_hwmod,
+ .clk = "i2c2_ick",
+ .addr = omap2_i2c2_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
};
-/* timer11 */
-static struct omap_hwmod omap2420_timer11_hwmod;
-
-/* l4_core -> timer11 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__timer11 = {
- .master = &omap2420_l4_core_hwmod,
- .slave = &omap2420_timer11_hwmod,
- .clk = "gpt11_ick",
- .addr = omap2_timer11_addrs,
+/* IVA <- L3 interface */
+static struct omap_hwmod_ocp_if omap2420_l3__iva = {
+ .master = &omap2xxx_l3_main_hwmod,
+ .slave = &omap2420_iva_hwmod,
+ .clk = "core_l3_ck",
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-/* timer11 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer11_slaves[] = {
- &omap2420_l4_core__timer11,
+/* DSP <- L3 interface */
+static struct omap_hwmod_ocp_if omap2420_l3__dsp = {
+ .master = &omap2xxx_l3_main_hwmod,
+ .slave = &omap2420_dsp_hwmod,
+ .clk = "dsp_ick",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
};
-/* timer11 hwmod */
-static struct omap_hwmod omap2420_timer11_hwmod = {
- .name = "timer11",
- .mpu_irqs = omap2_timer11_mpu_irqs,
- .main_clk = "gpt11_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT11_SHIFT,
- .module_offs = CORE_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT11_SHIFT,
- },
+static struct omap_hwmod_addr_space omap2420_timer1_addrs[] = {
+ {
+ .pa_start = 0x48028000,
+ .pa_end = 0x48028000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
},
- .dev_attr = &capability_pwm_dev_attr,
- .slaves = omap2420_timer11_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_timer11_slaves),
- .class = &omap2xxx_timer_hwmod_class,
+ { }
};
-/* timer12 */
-static struct omap_hwmod omap2420_timer12_hwmod;
-
-/* l4_core -> timer12 */
-static struct omap_hwmod_ocp_if omap2420_l4_core__timer12 = {
- .master = &omap2420_l4_core_hwmod,
- .slave = &omap2420_timer12_hwmod,
- .clk = "gpt12_ick",
- .addr = omap2xxx_timer12_addrs,
+/* l4_wkup -> timer1 */
+static struct omap_hwmod_ocp_if omap2420_l4_wkup__timer1 = {
+ .master = &omap2xxx_l4_wkup_hwmod,
+ .slave = &omap2xxx_timer1_hwmod,
+ .clk = "gpt1_ick",
+ .addr = omap2420_timer1_addrs,
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-/* timer12 slave port */
-static struct omap_hwmod_ocp_if *omap2420_timer12_slaves[] = {
- &omap2420_l4_core__timer12,
-};
-
-/* timer12 hwmod */
-static struct omap_hwmod omap2420_timer12_hwmod = {
- .name = "timer12",
- .mpu_irqs = omap2xxx_timer12_mpu_irqs,
- .main_clk = "gpt12_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT12_SHIFT,
- .module_offs = CORE_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT12_SHIFT,
- },
- },
- .dev_attr = &capability_pwm_dev_attr,
- .slaves = omap2420_timer12_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_timer12_slaves),
- .class = &omap2xxx_timer_hwmod_class,
-};
-
/* l4_wkup -> wd_timer2 */
static struct omap_hwmod_addr_space omap2420_wd_timer2_addrs[] = {
{
@@ -744,363 +368,13 @@ static struct omap_hwmod_addr_space omap2420_wd_timer2_addrs[] = {
};
static struct omap_hwmod_ocp_if omap2420_l4_wkup__wd_timer2 = {
- .master = &omap2420_l4_wkup_hwmod,
- .slave = &omap2420_wd_timer2_hwmod,
+ .master = &omap2xxx_l4_wkup_hwmod,
+ .slave = &omap2xxx_wd_timer2_hwmod,
.clk = "mpu_wdt_ick",
.addr = omap2420_wd_timer2_addrs,
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-/* wd_timer2 */
-static struct omap_hwmod_ocp_if *omap2420_wd_timer2_slaves[] = {
- &omap2420_l4_wkup__wd_timer2,
-};
-
-static struct omap_hwmod omap2420_wd_timer2_hwmod = {
- .name = "wd_timer2",
- .class = &omap2xxx_wd_timer_hwmod_class,
- .main_clk = "mpu_wdt_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_MPU_WDT_SHIFT,
- .module_offs = WKUP_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_MPU_WDT_SHIFT,
- },
- },
- .slaves = omap2420_wd_timer2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_wd_timer2_slaves),
-};
-
-/* UART1 */
-
-static struct omap_hwmod_ocp_if *omap2420_uart1_slaves[] = {
- &omap2_l4_core__uart1,
-};
-
-static struct omap_hwmod omap2420_uart1_hwmod = {
- .name = "uart1",
- .mpu_irqs = omap2_uart1_mpu_irqs,
- .sdma_reqs = omap2_uart1_sdma_reqs,
- .main_clk = "uart1_fck",
- .prcm = {
- .omap2 = {
- .module_offs = CORE_MOD,
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_UART1_SHIFT,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_EN_UART1_SHIFT,
- },
- },
- .slaves = omap2420_uart1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_uart1_slaves),
- .class = &omap2_uart_class,
-};
-
-/* UART2 */
-
-static struct omap_hwmod_ocp_if *omap2420_uart2_slaves[] = {
- &omap2_l4_core__uart2,
-};
-
-static struct omap_hwmod omap2420_uart2_hwmod = {
- .name = "uart2",
- .mpu_irqs = omap2_uart2_mpu_irqs,
- .sdma_reqs = omap2_uart2_sdma_reqs,
- .main_clk = "uart2_fck",
- .prcm = {
- .omap2 = {
- .module_offs = CORE_MOD,
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_UART2_SHIFT,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_EN_UART2_SHIFT,
- },
- },
- .slaves = omap2420_uart2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_uart2_slaves),
- .class = &omap2_uart_class,
-};
-
-/* UART3 */
-
-static struct omap_hwmod_ocp_if *omap2420_uart3_slaves[] = {
- &omap2_l4_core__uart3,
-};
-
-static struct omap_hwmod omap2420_uart3_hwmod = {
- .name = "uart3",
- .mpu_irqs = omap2_uart3_mpu_irqs,
- .sdma_reqs = omap2_uart3_sdma_reqs,
- .main_clk = "uart3_fck",
- .prcm = {
- .omap2 = {
- .module_offs = CORE_MOD,
- .prcm_reg_id = 2,
- .module_bit = OMAP24XX_EN_UART3_SHIFT,
- .idlest_reg_id = 2,
- .idlest_idle_bit = OMAP24XX_EN_UART3_SHIFT,
- },
- },
- .slaves = omap2420_uart3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_uart3_slaves),
- .class = &omap2_uart_class,
-};
-
-/* dss */
-/* dss master ports */
-static struct omap_hwmod_ocp_if *omap2420_dss_masters[] = {
- &omap2420_dss__l3,
-};
-
-/* l4_core -> dss */
-static struct omap_hwmod_ocp_if omap2420_l4_core__dss = {
- .master = &omap2420_l4_core_hwmod,
- .slave = &omap2420_dss_core_hwmod,
- .clk = "dss_ick",
- .addr = omap2_dss_addrs,
- .fw = {
- .omap2 = {
- .l4_fw_region = OMAP2420_L4_CORE_FW_DSS_CORE_REGION,
- .flags = OMAP_FIREWALL_L4,
- }
- },
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dss slave ports */
-static struct omap_hwmod_ocp_if *omap2420_dss_slaves[] = {
- &omap2420_l4_core__dss,
-};
-
-static struct omap_hwmod_opt_clk dss_opt_clks[] = {
- /*
- * The DSS HW needs all DSS clocks enabled during reset. The dss_core
- * driver does not use these clocks.
- */
- { .role = "tv_clk", .clk = "dss_54m_fck" },
- { .role = "sys_clk", .clk = "dss2_fck" },
-};
-
-static struct omap_hwmod omap2420_dss_core_hwmod = {
- .name = "dss_core",
- .class = &omap2_dss_hwmod_class,
- .main_clk = "dss1_fck", /* instead of dss_fck */
- .sdma_reqs = omap2xxx_dss_sdma_chs,
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_DSS1_SHIFT,
- .module_offs = CORE_MOD,
- .idlest_reg_id = 1,
- .idlest_stdby_bit = OMAP24XX_ST_DSS_SHIFT,
- },
- },
- .opt_clks = dss_opt_clks,
- .opt_clks_cnt = ARRAY_SIZE(dss_opt_clks),
- .slaves = omap2420_dss_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_dss_slaves),
- .masters = omap2420_dss_masters,
- .masters_cnt = ARRAY_SIZE(omap2420_dss_masters),
- .flags = HWMOD_NO_IDLEST | HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-};
-
-/* l4_core -> dss_dispc */
-static struct omap_hwmod_ocp_if omap2420_l4_core__dss_dispc = {
- .master = &omap2420_l4_core_hwmod,
- .slave = &omap2420_dss_dispc_hwmod,
- .clk = "dss_ick",
- .addr = omap2_dss_dispc_addrs,
- .fw = {
- .omap2 = {
- .l4_fw_region = OMAP2420_L4_CORE_FW_DSS_DISPC_REGION,
- .flags = OMAP_FIREWALL_L4,
- }
- },
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dss_dispc slave ports */
-static struct omap_hwmod_ocp_if *omap2420_dss_dispc_slaves[] = {
- &omap2420_l4_core__dss_dispc,
-};
-
-static struct omap_hwmod omap2420_dss_dispc_hwmod = {
- .name = "dss_dispc",
- .class = &omap2_dispc_hwmod_class,
- .mpu_irqs = omap2_dispc_irqs,
- .main_clk = "dss1_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_DSS1_SHIFT,
- .module_offs = CORE_MOD,
- .idlest_reg_id = 1,
- .idlest_stdby_bit = OMAP24XX_ST_DSS_SHIFT,
- },
- },
- .slaves = omap2420_dss_dispc_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_dss_dispc_slaves),
- .flags = HWMOD_NO_IDLEST,
- .dev_attr = &omap2_3_dss_dispc_dev_attr
-};
-
-/* l4_core -> dss_rfbi */
-static struct omap_hwmod_ocp_if omap2420_l4_core__dss_rfbi = {
- .master = &omap2420_l4_core_hwmod,
- .slave = &omap2420_dss_rfbi_hwmod,
- .clk = "dss_ick",
- .addr = omap2_dss_rfbi_addrs,
- .fw = {
- .omap2 = {
- .l4_fw_region = OMAP2420_L4_CORE_FW_DSS_CORE_REGION,
- .flags = OMAP_FIREWALL_L4,
- }
- },
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dss_rfbi slave ports */
-static struct omap_hwmod_ocp_if *omap2420_dss_rfbi_slaves[] = {
- &omap2420_l4_core__dss_rfbi,
-};
-
-static struct omap_hwmod_opt_clk dss_rfbi_opt_clks[] = {
- { .role = "ick", .clk = "dss_ick" },
-};
-
-static struct omap_hwmod omap2420_dss_rfbi_hwmod = {
- .name = "dss_rfbi",
- .class = &omap2_rfbi_hwmod_class,
- .main_clk = "dss1_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_DSS1_SHIFT,
- .module_offs = CORE_MOD,
- },
- },
- .opt_clks = dss_rfbi_opt_clks,
- .opt_clks_cnt = ARRAY_SIZE(dss_rfbi_opt_clks),
- .slaves = omap2420_dss_rfbi_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_dss_rfbi_slaves),
- .flags = HWMOD_NO_IDLEST,
-};
-
-/* l4_core -> dss_venc */
-static struct omap_hwmod_ocp_if omap2420_l4_core__dss_venc = {
- .master = &omap2420_l4_core_hwmod,
- .slave = &omap2420_dss_venc_hwmod,
- .clk = "dss_ick",
- .addr = omap2_dss_venc_addrs,
- .fw = {
- .omap2 = {
- .l4_fw_region = OMAP2420_L4_CORE_FW_DSS_VENC_REGION,
- .flags = OMAP_FIREWALL_L4,
- }
- },
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dss_venc slave ports */
-static struct omap_hwmod_ocp_if *omap2420_dss_venc_slaves[] = {
- &omap2420_l4_core__dss_venc,
-};
-
-static struct omap_hwmod omap2420_dss_venc_hwmod = {
- .name = "dss_venc",
- .class = &omap2_venc_hwmod_class,
- .main_clk = "dss_54m_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_DSS1_SHIFT,
- .module_offs = CORE_MOD,
- },
- },
- .slaves = omap2420_dss_venc_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_dss_venc_slaves),
- .flags = HWMOD_NO_IDLEST,
-};
-
-/* I2C common */
-static struct omap_hwmod_class_sysconfig i2c_sysc = {
- .rev_offs = 0x00,
- .sysc_offs = 0x20,
- .syss_offs = 0x10,
- .sysc_flags = (SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
- .sysc_fields = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class i2c_class = {
- .name = "i2c",
- .sysc = &i2c_sysc,
- .rev = OMAP_I2C_IP_VERSION_1,
- .reset = &omap_i2c_reset,
-};
-
-static struct omap_i2c_dev_attr i2c_dev_attr = {
- .flags = OMAP_I2C_FLAG_NO_FIFO |
- OMAP_I2C_FLAG_SIMPLE_CLOCK |
- OMAP_I2C_FLAG_16BIT_DATA_REG |
- OMAP_I2C_FLAG_BUS_SHIFT_2,
-};
-
-/* I2C1 */
-
-static struct omap_hwmod_ocp_if *omap2420_i2c1_slaves[] = {
- &omap2420_l4_core__i2c1,
-};
-
-static struct omap_hwmod omap2420_i2c1_hwmod = {
- .name = "i2c1",
- .mpu_irqs = omap2_i2c1_mpu_irqs,
- .sdma_reqs = omap2_i2c1_sdma_reqs,
- .main_clk = "i2c1_fck",
- .prcm = {
- .omap2 = {
- .module_offs = CORE_MOD,
- .prcm_reg_id = 1,
- .module_bit = OMAP2420_EN_I2C1_SHIFT,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP2420_ST_I2C1_SHIFT,
- },
- },
- .slaves = omap2420_i2c1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_i2c1_slaves),
- .class = &i2c_class,
- .dev_attr = &i2c_dev_attr,
- .flags = HWMOD_16BIT_REG,
-};
-
-/* I2C2 */
-
-static struct omap_hwmod_ocp_if *omap2420_i2c2_slaves[] = {
- &omap2420_l4_core__i2c2,
-};
-
-static struct omap_hwmod omap2420_i2c2_hwmod = {
- .name = "i2c2",
- .mpu_irqs = omap2_i2c2_mpu_irqs,
- .sdma_reqs = omap2_i2c2_sdma_reqs,
- .main_clk = "i2c2_fck",
- .prcm = {
- .omap2 = {
- .module_offs = CORE_MOD,
- .prcm_reg_id = 1,
- .module_bit = OMAP2420_EN_I2C2_SHIFT,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP2420_ST_I2C2_SHIFT,
- },
- },
- .slaves = omap2420_i2c2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_i2c2_slaves),
- .class = &i2c_class,
- .dev_attr = &i2c_dev_attr,
- .flags = HWMOD_16BIT_REG,
-};
-
/* l4_wkup -> gpio1 */
static struct omap_hwmod_addr_space omap2420_gpio1_addr_space[] = {
{
@@ -1112,8 +386,8 @@ static struct omap_hwmod_addr_space omap2420_gpio1_addr_space[] = {
};
static struct omap_hwmod_ocp_if omap2420_l4_wkup__gpio1 = {
- .master = &omap2420_l4_wkup_hwmod,
- .slave = &omap2420_gpio1_hwmod,
+ .master = &omap2xxx_l4_wkup_hwmod,
+ .slave = &omap2xxx_gpio1_hwmod,
.clk = "gpios_ick",
.addr = omap2420_gpio1_addr_space,
.user = OCP_USER_MPU | OCP_USER_SDMA,
@@ -1130,8 +404,8 @@ static struct omap_hwmod_addr_space omap2420_gpio2_addr_space[] = {
};
static struct omap_hwmod_ocp_if omap2420_l4_wkup__gpio2 = {
- .master = &omap2420_l4_wkup_hwmod,
- .slave = &omap2420_gpio2_hwmod,
+ .master = &omap2xxx_l4_wkup_hwmod,
+ .slave = &omap2xxx_gpio2_hwmod,
.clk = "gpios_ick",
.addr = omap2420_gpio2_addr_space,
.user = OCP_USER_MPU | OCP_USER_SDMA,
@@ -1148,8 +422,8 @@ static struct omap_hwmod_addr_space omap2420_gpio3_addr_space[] = {
};
static struct omap_hwmod_ocp_if omap2420_l4_wkup__gpio3 = {
- .master = &omap2420_l4_wkup_hwmod,
- .slave = &omap2420_gpio3_hwmod,
+ .master = &omap2xxx_l4_wkup_hwmod,
+ .slave = &omap2xxx_gpio3_hwmod,
.clk = "gpios_ick",
.addr = omap2420_gpio3_addr_space,
.user = OCP_USER_MPU | OCP_USER_SDMA,
@@ -1166,408 +440,150 @@ static struct omap_hwmod_addr_space omap2420_gpio4_addr_space[] = {
};
static struct omap_hwmod_ocp_if omap2420_l4_wkup__gpio4 = {
- .master = &omap2420_l4_wkup_hwmod,
- .slave = &omap2420_gpio4_hwmod,
+ .master = &omap2xxx_l4_wkup_hwmod,
+ .slave = &omap2xxx_gpio4_hwmod,
.clk = "gpios_ick",
.addr = omap2420_gpio4_addr_space,
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-/* gpio dev_attr */
-static struct omap_gpio_dev_attr gpio_dev_attr = {
- .bank_width = 32,
- .dbck_flag = false,
-};
-
-/* gpio1 */
-static struct omap_hwmod_ocp_if *omap2420_gpio1_slaves[] = {
- &omap2420_l4_wkup__gpio1,
-};
-
-static struct omap_hwmod omap2420_gpio1_hwmod = {
- .name = "gpio1",
- .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
- .mpu_irqs = omap2_gpio1_irqs,
- .main_clk = "gpios_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPIOS_SHIFT,
- .module_offs = WKUP_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPIOS_SHIFT,
- },
- },
- .slaves = omap2420_gpio1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_gpio1_slaves),
- .class = &omap2xxx_gpio_hwmod_class,
- .dev_attr = &gpio_dev_attr,
-};
-
-/* gpio2 */
-static struct omap_hwmod_ocp_if *omap2420_gpio2_slaves[] = {
- &omap2420_l4_wkup__gpio2,
-};
-
-static struct omap_hwmod omap2420_gpio2_hwmod = {
- .name = "gpio2",
- .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
- .mpu_irqs = omap2_gpio2_irqs,
- .main_clk = "gpios_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPIOS_SHIFT,
- .module_offs = WKUP_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPIOS_SHIFT,
- },
- },
- .slaves = omap2420_gpio2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_gpio2_slaves),
- .class = &omap2xxx_gpio_hwmod_class,
- .dev_attr = &gpio_dev_attr,
-};
-
-/* gpio3 */
-static struct omap_hwmod_ocp_if *omap2420_gpio3_slaves[] = {
- &omap2420_l4_wkup__gpio3,
-};
-
-static struct omap_hwmod omap2420_gpio3_hwmod = {
- .name = "gpio3",
- .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
- .mpu_irqs = omap2_gpio3_irqs,
- .main_clk = "gpios_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPIOS_SHIFT,
- .module_offs = WKUP_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPIOS_SHIFT,
- },
- },
- .slaves = omap2420_gpio3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_gpio3_slaves),
- .class = &omap2xxx_gpio_hwmod_class,
- .dev_attr = &gpio_dev_attr,
-};
-
-/* gpio4 */
-static struct omap_hwmod_ocp_if *omap2420_gpio4_slaves[] = {
- &omap2420_l4_wkup__gpio4,
-};
-
-static struct omap_hwmod omap2420_gpio4_hwmod = {
- .name = "gpio4",
- .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
- .mpu_irqs = omap2_gpio4_irqs,
- .main_clk = "gpios_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPIOS_SHIFT,
- .module_offs = WKUP_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPIOS_SHIFT,
- },
- },
- .slaves = omap2420_gpio4_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_gpio4_slaves),
- .class = &omap2xxx_gpio_hwmod_class,
- .dev_attr = &gpio_dev_attr,
-};
-
-/* dma attributes */
-static struct omap_dma_dev_attr dma_dev_attr = {
- .dev_caps = RESERVE_CHANNEL | DMA_LINKED_LCH | GLOBAL_PRIORITY |
- IS_CSSA_32 | IS_CDSA_32,
- .lch_count = 32,
-};
-
/* dma_system -> L3 */
static struct omap_hwmod_ocp_if omap2420_dma_system__l3 = {
.master = &omap2420_dma_system_hwmod,
- .slave = &omap2420_l3_main_hwmod,
+ .slave = &omap2xxx_l3_main_hwmod,
.clk = "core_l3_ck",
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-/* dma_system master ports */
-static struct omap_hwmod_ocp_if *omap2420_dma_system_masters[] = {
- &omap2420_dma_system__l3,
-};
-
/* l4_core -> dma_system */
static struct omap_hwmod_ocp_if omap2420_l4_core__dma_system = {
- .master = &omap2420_l4_core_hwmod,
+ .master = &omap2xxx_l4_core_hwmod,
.slave = &omap2420_dma_system_hwmod,
.clk = "sdma_ick",
.addr = omap2_dma_system_addrs,
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-/* dma_system slave ports */
-static struct omap_hwmod_ocp_if *omap2420_dma_system_slaves[] = {
- &omap2420_l4_core__dma_system,
-};
-
-static struct omap_hwmod omap2420_dma_system_hwmod = {
- .name = "dma",
- .class = &omap2xxx_dma_hwmod_class,
- .mpu_irqs = omap2_dma_system_irqs,
- .main_clk = "core_l3_ck",
- .slaves = omap2420_dma_system_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_dma_system_slaves),
- .masters = omap2420_dma_system_masters,
- .masters_cnt = ARRAY_SIZE(omap2420_dma_system_masters),
- .dev_attr = &dma_dev_attr,
- .flags = HWMOD_NO_IDLEST,
-};
-
-/* mailbox */
-static struct omap_hwmod omap2420_mailbox_hwmod;
-static struct omap_hwmod_irq_info omap2420_mailbox_irqs[] = {
- { .name = "dsp", .irq = 26 },
- { .name = "iva", .irq = 34 },
- { .irq = -1 }
-};
-
/* l4_core -> mailbox */
static struct omap_hwmod_ocp_if omap2420_l4_core__mailbox = {
- .master = &omap2420_l4_core_hwmod,
+ .master = &omap2xxx_l4_core_hwmod,
.slave = &omap2420_mailbox_hwmod,
.addr = omap2_mailbox_addrs,
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-/* mailbox slave ports */
-static struct omap_hwmod_ocp_if *omap2420_mailbox_slaves[] = {
- &omap2420_l4_core__mailbox,
-};
-
-static struct omap_hwmod omap2420_mailbox_hwmod = {
- .name = "mailbox",
- .class = &omap2xxx_mailbox_hwmod_class,
- .mpu_irqs = omap2420_mailbox_irqs,
- .main_clk = "mailboxes_ick",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_MAILBOXES_SHIFT,
- .module_offs = CORE_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_MAILBOXES_SHIFT,
- },
- },
- .slaves = omap2420_mailbox_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_mailbox_slaves),
-};
-
-/* mcspi1 */
-static struct omap_hwmod_ocp_if *omap2420_mcspi1_slaves[] = {
- &omap2420_l4_core__mcspi1,
-};
-
-static struct omap2_mcspi_dev_attr omap_mcspi1_dev_attr = {
- .num_chipselect = 4,
-};
-
-static struct omap_hwmod omap2420_mcspi1_hwmod = {
- .name = "mcspi1_hwmod",
- .mpu_irqs = omap2_mcspi1_mpu_irqs,
- .sdma_reqs = omap2_mcspi1_sdma_reqs,
- .main_clk = "mcspi1_fck",
- .prcm = {
- .omap2 = {
- .module_offs = CORE_MOD,
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_MCSPI1_SHIFT,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_MCSPI1_SHIFT,
- },
- },
- .slaves = omap2420_mcspi1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_mcspi1_slaves),
- .class = &omap2xxx_mcspi_class,
- .dev_attr = &omap_mcspi1_dev_attr,
-};
-
-/* mcspi2 */
-static struct omap_hwmod_ocp_if *omap2420_mcspi2_slaves[] = {
- &omap2420_l4_core__mcspi2,
-};
-
-static struct omap2_mcspi_dev_attr omap_mcspi2_dev_attr = {
- .num_chipselect = 2,
-};
-
-static struct omap_hwmod omap2420_mcspi2_hwmod = {
- .name = "mcspi2_hwmod",
- .mpu_irqs = omap2_mcspi2_mpu_irqs,
- .sdma_reqs = omap2_mcspi2_sdma_reqs,
- .main_clk = "mcspi2_fck",
- .prcm = {
- .omap2 = {
- .module_offs = CORE_MOD,
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_MCSPI2_SHIFT,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_MCSPI2_SHIFT,
- },
- },
- .slaves = omap2420_mcspi2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_mcspi2_slaves),
- .class = &omap2xxx_mcspi_class,
- .dev_attr = &omap_mcspi2_dev_attr,
-};
-
-/*
- * 'mcbsp' class
- * multi channel buffered serial port controller
- */
-
-static struct omap_hwmod_class omap2420_mcbsp_hwmod_class = {
- .name = "mcbsp",
-};
-
-/* mcbsp1 */
-static struct omap_hwmod_irq_info omap2420_mcbsp1_irqs[] = {
- { .name = "tx", .irq = 59 },
- { .name = "rx", .irq = 60 },
- { .irq = -1 }
-};
-
/* l4_core -> mcbsp1 */
static struct omap_hwmod_ocp_if omap2420_l4_core__mcbsp1 = {
- .master = &omap2420_l4_core_hwmod,
+ .master = &omap2xxx_l4_core_hwmod,
.slave = &omap2420_mcbsp1_hwmod,
.clk = "mcbsp1_ick",
.addr = omap2_mcbsp1_addrs,
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-/* mcbsp1 slave ports */
-static struct omap_hwmod_ocp_if *omap2420_mcbsp1_slaves[] = {
- &omap2420_l4_core__mcbsp1,
-};
-
-static struct omap_hwmod omap2420_mcbsp1_hwmod = {
- .name = "mcbsp1",
- .class = &omap2420_mcbsp_hwmod_class,
- .mpu_irqs = omap2420_mcbsp1_irqs,
- .sdma_reqs = omap2_mcbsp1_sdma_reqs,
- .main_clk = "mcbsp1_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_MCBSP1_SHIFT,
- .module_offs = CORE_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_MCBSP1_SHIFT,
- },
- },
- .slaves = omap2420_mcbsp1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_mcbsp1_slaves),
-};
-
-/* mcbsp2 */
-static struct omap_hwmod_irq_info omap2420_mcbsp2_irqs[] = {
- { .name = "tx", .irq = 62 },
- { .name = "rx", .irq = 63 },
- { .irq = -1 }
-};
-
/* l4_core -> mcbsp2 */
static struct omap_hwmod_ocp_if omap2420_l4_core__mcbsp2 = {
- .master = &omap2420_l4_core_hwmod,
+ .master = &omap2xxx_l4_core_hwmod,
.slave = &omap2420_mcbsp2_hwmod,
.clk = "mcbsp2_ick",
.addr = omap2xxx_mcbsp2_addrs,
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-/* mcbsp2 slave ports */
-static struct omap_hwmod_ocp_if *omap2420_mcbsp2_slaves[] = {
- &omap2420_l4_core__mcbsp2,
-};
-
-static struct omap_hwmod omap2420_mcbsp2_hwmod = {
- .name = "mcbsp2",
- .class = &omap2420_mcbsp_hwmod_class,
- .mpu_irqs = omap2420_mcbsp2_irqs,
- .sdma_reqs = omap2_mcbsp2_sdma_reqs,
- .main_clk = "mcbsp2_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_MCBSP2_SHIFT,
- .module_offs = CORE_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_MCBSP2_SHIFT,
- },
+static struct omap_hwmod_addr_space omap2420_msdi1_addrs[] = {
+ {
+ .pa_start = 0x4809c000,
+ .pa_end = 0x4809c000 + SZ_128 - 1,
+ .flags = ADDR_TYPE_RT,
},
- .slaves = omap2420_mcbsp2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2420_mcbsp2_slaves),
+ { }
};
-static __initdata struct omap_hwmod *omap2420_hwmods[] = {
- &omap2420_l3_main_hwmod,
- &omap2420_l4_core_hwmod,
- &omap2420_l4_wkup_hwmod,
- &omap2420_mpu_hwmod,
- &omap2420_iva_hwmod,
-
- &omap2420_timer1_hwmod,
- &omap2420_timer2_hwmod,
- &omap2420_timer3_hwmod,
- &omap2420_timer4_hwmod,
- &omap2420_timer5_hwmod,
- &omap2420_timer6_hwmod,
- &omap2420_timer7_hwmod,
- &omap2420_timer8_hwmod,
- &omap2420_timer9_hwmod,
- &omap2420_timer10_hwmod,
- &omap2420_timer11_hwmod,
- &omap2420_timer12_hwmod,
-
- &omap2420_wd_timer2_hwmod,
- &omap2420_uart1_hwmod,
- &omap2420_uart2_hwmod,
- &omap2420_uart3_hwmod,
- /* dss class */
- &omap2420_dss_core_hwmod,
- &omap2420_dss_dispc_hwmod,
- &omap2420_dss_rfbi_hwmod,
- &omap2420_dss_venc_hwmod,
- /* i2c class */
- &omap2420_i2c1_hwmod,
- &omap2420_i2c2_hwmod,
+/* l4_core -> msdi1 */
+static struct omap_hwmod_ocp_if omap2420_l4_core__msdi1 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2420_msdi1_hwmod,
+ .clk = "mmc_ick",
+ .addr = omap2420_msdi1_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
- /* gpio class */
- &omap2420_gpio1_hwmod,
- &omap2420_gpio2_hwmod,
- &omap2420_gpio3_hwmod,
- &omap2420_gpio4_hwmod,
+/* l4_core -> hdq1w interface */
+static struct omap_hwmod_ocp_if omap2420_l4_core__hdq1w = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2420_hdq1w_hwmod,
+ .clk = "hdq_ick",
+ .addr = omap2_hdq1w_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+ .flags = OMAP_FIREWALL_L4 | OCPIF_SWSUP_IDLE,
+};
- /* dma_system class*/
- &omap2420_dma_system_hwmod,
- /* mailbox class */
- &omap2420_mailbox_hwmod,
+/* l4_wkup -> 32ksync_counter */
+static struct omap_hwmod_addr_space omap2420_counter_32k_addrs[] = {
+ {
+ .pa_start = 0x48004000,
+ .pa_end = 0x4800401f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
- /* mcbsp class */
- &omap2420_mcbsp1_hwmod,
- &omap2420_mcbsp2_hwmod,
+static struct omap_hwmod_ocp_if omap2420_l4_wkup__counter_32k = {
+ .master = &omap2xxx_l4_wkup_hwmod,
+ .slave = &omap2xxx_counter_32k_hwmod,
+ .clk = "sync_32k_ick",
+ .addr = omap2420_counter_32k_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
- /* mcspi class */
- &omap2420_mcspi1_hwmod,
- &omap2420_mcspi2_hwmod,
+static struct omap_hwmod_ocp_if *omap2420_hwmod_ocp_ifs[] __initdata = {
+ &omap2xxx_l3_main__l4_core,
+ &omap2xxx_mpu__l3_main,
+ &omap2xxx_dss__l3,
+ &omap2xxx_l4_core__mcspi1,
+ &omap2xxx_l4_core__mcspi2,
+ &omap2xxx_l4_core__l4_wkup,
+ &omap2_l4_core__uart1,
+ &omap2_l4_core__uart2,
+ &omap2_l4_core__uart3,
+ &omap2420_l4_core__i2c1,
+ &omap2420_l4_core__i2c2,
+ &omap2420_l3__iva,
+ &omap2420_l3__dsp,
+ &omap2420_l4_wkup__timer1,
+ &omap2xxx_l4_core__timer2,
+ &omap2xxx_l4_core__timer3,
+ &omap2xxx_l4_core__timer4,
+ &omap2xxx_l4_core__timer5,
+ &omap2xxx_l4_core__timer6,
+ &omap2xxx_l4_core__timer7,
+ &omap2xxx_l4_core__timer8,
+ &omap2xxx_l4_core__timer9,
+ &omap2xxx_l4_core__timer10,
+ &omap2xxx_l4_core__timer11,
+ &omap2xxx_l4_core__timer12,
+ &omap2420_l4_wkup__wd_timer2,
+ &omap2xxx_l4_core__dss,
+ &omap2xxx_l4_core__dss_dispc,
+ &omap2xxx_l4_core__dss_rfbi,
+ &omap2xxx_l4_core__dss_venc,
+ &omap2420_l4_wkup__gpio1,
+ &omap2420_l4_wkup__gpio2,
+ &omap2420_l4_wkup__gpio3,
+ &omap2420_l4_wkup__gpio4,
+ &omap2420_dma_system__l3,
+ &omap2420_l4_core__dma_system,
+ &omap2420_l4_core__mailbox,
+ &omap2420_l4_core__mcbsp1,
+ &omap2420_l4_core__mcbsp2,
+ &omap2420_l4_core__msdi1,
+ &omap2420_l4_core__hdq1w,
+ &omap2420_l4_wkup__counter_32k,
NULL,
};
int __init omap2420_hwmod_init(void)
{
- return omap_hwmod_register(omap2420_hwmods);
+ return omap_hwmod_register_links(omap2420_hwmod_ocp_ifs);
}
diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
index 04a3885f4475..4d7264981230 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
@@ -2,6 +2,7 @@
* omap_hwmod_2430_data.c - hardware modules present on the OMAP2430 chips
*
* Copyright (C) 2009-2011 Nokia Corporation
+ * Copyright (C) 2012 Texas Instruments, Inc.
* Paul Walmsley
*
* This program is free software; you can redistribute it and/or modify
@@ -33,1044 +34,29 @@
/*
* OMAP2430 hardware module integration data
*
- * ALl of the data in this section should be autogeneratable from the
+ * All of the data in this section should be autogeneratable from the
* TI hardware database or other technical documentation. Data that
* is driver-specific or driver-kernel integration-specific belongs
* elsewhere.
*/
-static struct omap_hwmod omap2430_mpu_hwmod;
-static struct omap_hwmod omap2430_iva_hwmod;
-static struct omap_hwmod omap2430_l3_main_hwmod;
-static struct omap_hwmod omap2430_l4_core_hwmod;
-static struct omap_hwmod omap2430_dss_core_hwmod;
-static struct omap_hwmod omap2430_dss_dispc_hwmod;
-static struct omap_hwmod omap2430_dss_rfbi_hwmod;
-static struct omap_hwmod omap2430_dss_venc_hwmod;
-static struct omap_hwmod omap2430_wd_timer2_hwmod;
-static struct omap_hwmod omap2430_gpio1_hwmod;
-static struct omap_hwmod omap2430_gpio2_hwmod;
-static struct omap_hwmod omap2430_gpio3_hwmod;
-static struct omap_hwmod omap2430_gpio4_hwmod;
-static struct omap_hwmod omap2430_gpio5_hwmod;
-static struct omap_hwmod omap2430_dma_system_hwmod;
-static struct omap_hwmod omap2430_mcbsp1_hwmod;
-static struct omap_hwmod omap2430_mcbsp2_hwmod;
-static struct omap_hwmod omap2430_mcbsp3_hwmod;
-static struct omap_hwmod omap2430_mcbsp4_hwmod;
-static struct omap_hwmod omap2430_mcbsp5_hwmod;
-static struct omap_hwmod omap2430_mcspi1_hwmod;
-static struct omap_hwmod omap2430_mcspi2_hwmod;
-static struct omap_hwmod omap2430_mcspi3_hwmod;
-static struct omap_hwmod omap2430_mmc1_hwmod;
-static struct omap_hwmod omap2430_mmc2_hwmod;
-
-/* L3 -> L4_CORE interface */
-static struct omap_hwmod_ocp_if omap2430_l3_main__l4_core = {
- .master = &omap2430_l3_main_hwmod,
- .slave = &omap2430_l4_core_hwmod,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* MPU -> L3 interface */
-static struct omap_hwmod_ocp_if omap2430_mpu__l3_main = {
- .master = &omap2430_mpu_hwmod,
- .slave = &omap2430_l3_main_hwmod,
- .user = OCP_USER_MPU,
-};
-
-/* Slave interfaces on the L3 interconnect */
-static struct omap_hwmod_ocp_if *omap2430_l3_main_slaves[] = {
- &omap2430_mpu__l3_main,
-};
-
-/* DSS -> l3 */
-static struct omap_hwmod_ocp_if omap2430_dss__l3 = {
- .master = &omap2430_dss_core_hwmod,
- .slave = &omap2430_l3_main_hwmod,
- .fw = {
- .omap2 = {
- .l3_perm_bit = OMAP2_L3_CORE_FW_CONNID_DSS,
- .flags = OMAP_FIREWALL_L3,
- }
- },
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* Master interfaces on the L3 interconnect */
-static struct omap_hwmod_ocp_if *omap2430_l3_main_masters[] = {
- &omap2430_l3_main__l4_core,
-};
-
-/* L3 */
-static struct omap_hwmod omap2430_l3_main_hwmod = {
- .name = "l3_main",
- .class = &l3_hwmod_class,
- .masters = omap2430_l3_main_masters,
- .masters_cnt = ARRAY_SIZE(omap2430_l3_main_masters),
- .slaves = omap2430_l3_main_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_l3_main_slaves),
- .flags = HWMOD_NO_IDLEST,
-};
-
-static struct omap_hwmod omap2430_l4_wkup_hwmod;
-static struct omap_hwmod omap2430_uart1_hwmod;
-static struct omap_hwmod omap2430_uart2_hwmod;
-static struct omap_hwmod omap2430_uart3_hwmod;
-static struct omap_hwmod omap2430_i2c1_hwmod;
-static struct omap_hwmod omap2430_i2c2_hwmod;
-
-static struct omap_hwmod omap2430_usbhsotg_hwmod;
-
-/* l3_core -> usbhsotg interface */
-static struct omap_hwmod_ocp_if omap2430_usbhsotg__l3 = {
- .master = &omap2430_usbhsotg_hwmod,
- .slave = &omap2430_l3_main_hwmod,
- .clk = "core_l3_ck",
- .user = OCP_USER_MPU,
-};
-
-/* L4 CORE -> I2C1 interface */
-static struct omap_hwmod_ocp_if omap2430_l4_core__i2c1 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_i2c1_hwmod,
- .clk = "i2c1_ick",
- .addr = omap2_i2c1_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 CORE -> I2C2 interface */
-static struct omap_hwmod_ocp_if omap2430_l4_core__i2c2 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_i2c2_hwmod,
- .clk = "i2c2_ick",
- .addr = omap2_i2c2_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4_CORE -> L4_WKUP interface */
-static struct omap_hwmod_ocp_if omap2430_l4_core__l4_wkup = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_l4_wkup_hwmod,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 CORE -> UART1 interface */
-static struct omap_hwmod_ocp_if omap2_l4_core__uart1 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_uart1_hwmod,
- .clk = "uart1_ick",
- .addr = omap2xxx_uart1_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 CORE -> UART2 interface */
-static struct omap_hwmod_ocp_if omap2_l4_core__uart2 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_uart2_hwmod,
- .clk = "uart2_ick",
- .addr = omap2xxx_uart2_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 PER -> UART3 interface */
-static struct omap_hwmod_ocp_if omap2_l4_core__uart3 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_uart3_hwmod,
- .clk = "uart3_ick",
- .addr = omap2xxx_uart3_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/*
-* usbhsotg interface data
-*/
-static struct omap_hwmod_addr_space omap2430_usbhsotg_addrs[] = {
- {
- .pa_start = OMAP243X_HS_BASE,
- .pa_end = OMAP243X_HS_BASE + SZ_4K - 1,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_core ->usbhsotg interface */
-static struct omap_hwmod_ocp_if omap2430_l4_core__usbhsotg = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_usbhsotg_hwmod,
- .clk = "usb_l4_ick",
- .addr = omap2430_usbhsotg_addrs,
- .user = OCP_USER_MPU,
-};
-
-static struct omap_hwmod_ocp_if *omap2430_usbhsotg_masters[] = {
- &omap2430_usbhsotg__l3,
-};
-
-static struct omap_hwmod_ocp_if *omap2430_usbhsotg_slaves[] = {
- &omap2430_l4_core__usbhsotg,
-};
-
-/* L4 CORE -> MMC1 interface */
-static struct omap_hwmod_ocp_if omap2430_l4_core__mmc1 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_mmc1_hwmod,
- .clk = "mmchs1_ick",
- .addr = omap2430_mmc1_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 CORE -> MMC2 interface */
-static struct omap_hwmod_ocp_if omap2430_l4_core__mmc2 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_mmc2_hwmod,
- .clk = "mmchs2_ick",
- .addr = omap2430_mmc2_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* Slave interfaces on the L4_CORE interconnect */
-static struct omap_hwmod_ocp_if *omap2430_l4_core_slaves[] = {
- &omap2430_l3_main__l4_core,
-};
-
-/* Master interfaces on the L4_CORE interconnect */
-static struct omap_hwmod_ocp_if *omap2430_l4_core_masters[] = {
- &omap2430_l4_core__l4_wkup,
- &omap2430_l4_core__mmc1,
- &omap2430_l4_core__mmc2,
-};
-
-/* L4 CORE */
-static struct omap_hwmod omap2430_l4_core_hwmod = {
- .name = "l4_core",
- .class = &l4_hwmod_class,
- .masters = omap2430_l4_core_masters,
- .masters_cnt = ARRAY_SIZE(omap2430_l4_core_masters),
- .slaves = omap2430_l4_core_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_l4_core_slaves),
- .flags = HWMOD_NO_IDLEST,
-};
-
-/* Slave interfaces on the L4_WKUP interconnect */
-static struct omap_hwmod_ocp_if *omap2430_l4_wkup_slaves[] = {
- &omap2430_l4_core__l4_wkup,
- &omap2_l4_core__uart1,
- &omap2_l4_core__uart2,
- &omap2_l4_core__uart3,
-};
-
-/* Master interfaces on the L4_WKUP interconnect */
-static struct omap_hwmod_ocp_if *omap2430_l4_wkup_masters[] = {
-};
-
-/* l4 core -> mcspi1 interface */
-static struct omap_hwmod_ocp_if omap2430_l4_core__mcspi1 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_mcspi1_hwmod,
- .clk = "mcspi1_ick",
- .addr = omap2_mcspi1_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4 core -> mcspi2 interface */
-static struct omap_hwmod_ocp_if omap2430_l4_core__mcspi2 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_mcspi2_hwmod,
- .clk = "mcspi2_ick",
- .addr = omap2_mcspi2_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4 core -> mcspi3 interface */
-static struct omap_hwmod_ocp_if omap2430_l4_core__mcspi3 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_mcspi3_hwmod,
- .clk = "mcspi3_ick",
- .addr = omap2430_mcspi3_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 WKUP */
-static struct omap_hwmod omap2430_l4_wkup_hwmod = {
- .name = "l4_wkup",
- .class = &l4_hwmod_class,
- .masters = omap2430_l4_wkup_masters,
- .masters_cnt = ARRAY_SIZE(omap2430_l4_wkup_masters),
- .slaves = omap2430_l4_wkup_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_l4_wkup_slaves),
- .flags = HWMOD_NO_IDLEST,
-};
-
-/* Master interfaces on the MPU device */
-static struct omap_hwmod_ocp_if *omap2430_mpu_masters[] = {
- &omap2430_mpu__l3_main,
-};
-
-/* MPU */
-static struct omap_hwmod omap2430_mpu_hwmod = {
- .name = "mpu",
- .class = &mpu_hwmod_class,
- .main_clk = "mpu_ck",
- .masters = omap2430_mpu_masters,
- .masters_cnt = ARRAY_SIZE(omap2430_mpu_masters),
-};
-
/*
- * IVA2_1 interface data
+ * IP blocks
*/
-/* IVA2 <- L3 interface */
-static struct omap_hwmod_ocp_if omap2430_l3__iva = {
- .master = &omap2430_l3_main_hwmod,
- .slave = &omap2430_iva_hwmod,
- .clk = "dsp_fck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-static struct omap_hwmod_ocp_if *omap2430_iva_masters[] = {
- &omap2430_l3__iva,
+/* IVA2 (IVA2) */
+static struct omap_hwmod_rst_info omap2430_iva_resets[] = {
+ { .name = "logic", .rst_shift = 0 },
+ { .name = "mmu", .rst_shift = 1 },
};
-/*
- * IVA2 (IVA2)
- */
-
static struct omap_hwmod omap2430_iva_hwmod = {
.name = "iva",
.class = &iva_hwmod_class,
- .masters = omap2430_iva_masters,
- .masters_cnt = ARRAY_SIZE(omap2430_iva_masters),
-};
-
-/* always-on timers dev attribute */
-static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
- .timer_capability = OMAP_TIMER_ALWON,
-};
-
-/* pwm timers dev attribute */
-static struct omap_timer_capability_dev_attr capability_pwm_dev_attr = {
- .timer_capability = OMAP_TIMER_HAS_PWM,
-};
-
-/* timer1 */
-static struct omap_hwmod omap2430_timer1_hwmod;
-
-static struct omap_hwmod_addr_space omap2430_timer1_addrs[] = {
- {
- .pa_start = 0x49018000,
- .pa_end = 0x49018000 + SZ_1K - 1,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_wkup -> timer1 */
-static struct omap_hwmod_ocp_if omap2430_l4_wkup__timer1 = {
- .master = &omap2430_l4_wkup_hwmod,
- .slave = &omap2430_timer1_hwmod,
- .clk = "gpt1_ick",
- .addr = omap2430_timer1_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer1 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer1_slaves[] = {
- &omap2430_l4_wkup__timer1,
-};
-
-/* timer1 hwmod */
-static struct omap_hwmod omap2430_timer1_hwmod = {
- .name = "timer1",
- .mpu_irqs = omap2_timer1_mpu_irqs,
- .main_clk = "gpt1_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT1_SHIFT,
- .module_offs = WKUP_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT1_SHIFT,
- },
- },
- .dev_attr = &capability_alwon_dev_attr,
- .slaves = omap2430_timer1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_timer1_slaves),
- .class = &omap2xxx_timer_hwmod_class,
-};
-
-/* timer2 */
-static struct omap_hwmod omap2430_timer2_hwmod;
-
-/* l4_core -> timer2 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__timer2 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_timer2_hwmod,
- .clk = "gpt2_ick",
- .addr = omap2xxx_timer2_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer2 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer2_slaves[] = {
- &omap2430_l4_core__timer2,
-};
-
-/* timer2 hwmod */
-static struct omap_hwmod omap2430_timer2_hwmod = {
- .name = "timer2",
- .mpu_irqs = omap2_timer2_mpu_irqs,
- .main_clk = "gpt2_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT2_SHIFT,
- .module_offs = CORE_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT2_SHIFT,
- },
- },
- .dev_attr = &capability_alwon_dev_attr,
- .slaves = omap2430_timer2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_timer2_slaves),
- .class = &omap2xxx_timer_hwmod_class,
-};
-
-/* timer3 */
-static struct omap_hwmod omap2430_timer3_hwmod;
-
-/* l4_core -> timer3 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__timer3 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_timer3_hwmod,
- .clk = "gpt3_ick",
- .addr = omap2xxx_timer3_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer3 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer3_slaves[] = {
- &omap2430_l4_core__timer3,
-};
-
-/* timer3 hwmod */
-static struct omap_hwmod omap2430_timer3_hwmod = {
- .name = "timer3",
- .mpu_irqs = omap2_timer3_mpu_irqs,
- .main_clk = "gpt3_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT3_SHIFT,
- .module_offs = CORE_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT3_SHIFT,
- },
- },
- .dev_attr = &capability_alwon_dev_attr,
- .slaves = omap2430_timer3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_timer3_slaves),
- .class = &omap2xxx_timer_hwmod_class,
-};
-
-/* timer4 */
-static struct omap_hwmod omap2430_timer4_hwmod;
-
-/* l4_core -> timer4 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__timer4 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_timer4_hwmod,
- .clk = "gpt4_ick",
- .addr = omap2xxx_timer4_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer4 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer4_slaves[] = {
- &omap2430_l4_core__timer4,
-};
-
-/* timer4 hwmod */
-static struct omap_hwmod omap2430_timer4_hwmod = {
- .name = "timer4",
- .mpu_irqs = omap2_timer4_mpu_irqs,
- .main_clk = "gpt4_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT4_SHIFT,
- .module_offs = CORE_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT4_SHIFT,
- },
- },
- .dev_attr = &capability_alwon_dev_attr,
- .slaves = omap2430_timer4_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_timer4_slaves),
- .class = &omap2xxx_timer_hwmod_class,
-};
-
-/* timer5 */
-static struct omap_hwmod omap2430_timer5_hwmod;
-
-/* l4_core -> timer5 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__timer5 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_timer5_hwmod,
- .clk = "gpt5_ick",
- .addr = omap2xxx_timer5_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer5 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer5_slaves[] = {
- &omap2430_l4_core__timer5,
-};
-
-/* timer5 hwmod */
-static struct omap_hwmod omap2430_timer5_hwmod = {
- .name = "timer5",
- .mpu_irqs = omap2_timer5_mpu_irqs,
- .main_clk = "gpt5_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT5_SHIFT,
- .module_offs = CORE_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT5_SHIFT,
- },
- },
- .dev_attr = &capability_alwon_dev_attr,
- .slaves = omap2430_timer5_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_timer5_slaves),
- .class = &omap2xxx_timer_hwmod_class,
-};
-
-/* timer6 */
-static struct omap_hwmod omap2430_timer6_hwmod;
-
-/* l4_core -> timer6 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__timer6 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_timer6_hwmod,
- .clk = "gpt6_ick",
- .addr = omap2xxx_timer6_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer6 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer6_slaves[] = {
- &omap2430_l4_core__timer6,
-};
-
-/* timer6 hwmod */
-static struct omap_hwmod omap2430_timer6_hwmod = {
- .name = "timer6",
- .mpu_irqs = omap2_timer6_mpu_irqs,
- .main_clk = "gpt6_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT6_SHIFT,
- .module_offs = CORE_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT6_SHIFT,
- },
- },
- .dev_attr = &capability_alwon_dev_attr,
- .slaves = omap2430_timer6_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_timer6_slaves),
- .class = &omap2xxx_timer_hwmod_class,
-};
-
-/* timer7 */
-static struct omap_hwmod omap2430_timer7_hwmod;
-
-/* l4_core -> timer7 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__timer7 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_timer7_hwmod,
- .clk = "gpt7_ick",
- .addr = omap2xxx_timer7_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer7 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer7_slaves[] = {
- &omap2430_l4_core__timer7,
-};
-
-/* timer7 hwmod */
-static struct omap_hwmod omap2430_timer7_hwmod = {
- .name = "timer7",
- .mpu_irqs = omap2_timer7_mpu_irqs,
- .main_clk = "gpt7_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT7_SHIFT,
- .module_offs = CORE_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT7_SHIFT,
- },
- },
- .dev_attr = &capability_alwon_dev_attr,
- .slaves = omap2430_timer7_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_timer7_slaves),
- .class = &omap2xxx_timer_hwmod_class,
-};
-
-/* timer8 */
-static struct omap_hwmod omap2430_timer8_hwmod;
-
-/* l4_core -> timer8 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__timer8 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_timer8_hwmod,
- .clk = "gpt8_ick",
- .addr = omap2xxx_timer8_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer8 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer8_slaves[] = {
- &omap2430_l4_core__timer8,
-};
-
-/* timer8 hwmod */
-static struct omap_hwmod omap2430_timer8_hwmod = {
- .name = "timer8",
- .mpu_irqs = omap2_timer8_mpu_irqs,
- .main_clk = "gpt8_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT8_SHIFT,
- .module_offs = CORE_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT8_SHIFT,
- },
- },
- .dev_attr = &capability_alwon_dev_attr,
- .slaves = omap2430_timer8_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_timer8_slaves),
- .class = &omap2xxx_timer_hwmod_class,
-};
-
-/* timer9 */
-static struct omap_hwmod omap2430_timer9_hwmod;
-
-/* l4_core -> timer9 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__timer9 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_timer9_hwmod,
- .clk = "gpt9_ick",
- .addr = omap2xxx_timer9_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer9 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer9_slaves[] = {
- &omap2430_l4_core__timer9,
-};
-
-/* timer9 hwmod */
-static struct omap_hwmod omap2430_timer9_hwmod = {
- .name = "timer9",
- .mpu_irqs = omap2_timer9_mpu_irqs,
- .main_clk = "gpt9_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT9_SHIFT,
- .module_offs = CORE_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT9_SHIFT,
- },
- },
- .dev_attr = &capability_pwm_dev_attr,
- .slaves = omap2430_timer9_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_timer9_slaves),
- .class = &omap2xxx_timer_hwmod_class,
-};
-
-/* timer10 */
-static struct omap_hwmod omap2430_timer10_hwmod;
-
-/* l4_core -> timer10 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__timer10 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_timer10_hwmod,
- .clk = "gpt10_ick",
- .addr = omap2_timer10_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer10 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer10_slaves[] = {
- &omap2430_l4_core__timer10,
-};
-
-/* timer10 hwmod */
-static struct omap_hwmod omap2430_timer10_hwmod = {
- .name = "timer10",
- .mpu_irqs = omap2_timer10_mpu_irqs,
- .main_clk = "gpt10_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT10_SHIFT,
- .module_offs = CORE_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT10_SHIFT,
- },
- },
- .dev_attr = &capability_pwm_dev_attr,
- .slaves = omap2430_timer10_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_timer10_slaves),
- .class = &omap2xxx_timer_hwmod_class,
-};
-
-/* timer11 */
-static struct omap_hwmod omap2430_timer11_hwmod;
-
-/* l4_core -> timer11 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__timer11 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_timer11_hwmod,
- .clk = "gpt11_ick",
- .addr = omap2_timer11_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer11 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer11_slaves[] = {
- &omap2430_l4_core__timer11,
-};
-
-/* timer11 hwmod */
-static struct omap_hwmod omap2430_timer11_hwmod = {
- .name = "timer11",
- .mpu_irqs = omap2_timer11_mpu_irqs,
- .main_clk = "gpt11_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT11_SHIFT,
- .module_offs = CORE_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT11_SHIFT,
- },
- },
- .dev_attr = &capability_pwm_dev_attr,
- .slaves = omap2430_timer11_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_timer11_slaves),
- .class = &omap2xxx_timer_hwmod_class,
-};
-
-/* timer12 */
-static struct omap_hwmod omap2430_timer12_hwmod;
-
-/* l4_core -> timer12 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__timer12 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_timer12_hwmod,
- .clk = "gpt12_ick",
- .addr = omap2xxx_timer12_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer12 slave port */
-static struct omap_hwmod_ocp_if *omap2430_timer12_slaves[] = {
- &omap2430_l4_core__timer12,
-};
-
-/* timer12 hwmod */
-static struct omap_hwmod omap2430_timer12_hwmod = {
- .name = "timer12",
- .mpu_irqs = omap2xxx_timer12_mpu_irqs,
- .main_clk = "gpt12_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPT12_SHIFT,
- .module_offs = CORE_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPT12_SHIFT,
- },
- },
- .dev_attr = &capability_pwm_dev_attr,
- .slaves = omap2430_timer12_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_timer12_slaves),
- .class = &omap2xxx_timer_hwmod_class,
-};
-
-/* l4_wkup -> wd_timer2 */
-static struct omap_hwmod_addr_space omap2430_wd_timer2_addrs[] = {
- {
- .pa_start = 0x49016000,
- .pa_end = 0x4901607f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-static struct omap_hwmod_ocp_if omap2430_l4_wkup__wd_timer2 = {
- .master = &omap2430_l4_wkup_hwmod,
- .slave = &omap2430_wd_timer2_hwmod,
- .clk = "mpu_wdt_ick",
- .addr = omap2430_wd_timer2_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* wd_timer2 */
-static struct omap_hwmod_ocp_if *omap2430_wd_timer2_slaves[] = {
- &omap2430_l4_wkup__wd_timer2,
-};
-
-static struct omap_hwmod omap2430_wd_timer2_hwmod = {
- .name = "wd_timer2",
- .class = &omap2xxx_wd_timer_hwmod_class,
- .main_clk = "mpu_wdt_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_MPU_WDT_SHIFT,
- .module_offs = WKUP_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_MPU_WDT_SHIFT,
- },
- },
- .slaves = omap2430_wd_timer2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_wd_timer2_slaves),
-};
-
-/* UART1 */
-
-static struct omap_hwmod_ocp_if *omap2430_uart1_slaves[] = {
- &omap2_l4_core__uart1,
-};
-
-static struct omap_hwmod omap2430_uart1_hwmod = {
- .name = "uart1",
- .mpu_irqs = omap2_uart1_mpu_irqs,
- .sdma_reqs = omap2_uart1_sdma_reqs,
- .main_clk = "uart1_fck",
- .prcm = {
- .omap2 = {
- .module_offs = CORE_MOD,
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_UART1_SHIFT,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_EN_UART1_SHIFT,
- },
- },
- .slaves = omap2430_uart1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_uart1_slaves),
- .class = &omap2_uart_class,
-};
-
-/* UART2 */
-
-static struct omap_hwmod_ocp_if *omap2430_uart2_slaves[] = {
- &omap2_l4_core__uart2,
-};
-
-static struct omap_hwmod omap2430_uart2_hwmod = {
- .name = "uart2",
- .mpu_irqs = omap2_uart2_mpu_irqs,
- .sdma_reqs = omap2_uart2_sdma_reqs,
- .main_clk = "uart2_fck",
- .prcm = {
- .omap2 = {
- .module_offs = CORE_MOD,
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_UART2_SHIFT,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_EN_UART2_SHIFT,
- },
- },
- .slaves = omap2430_uart2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_uart2_slaves),
- .class = &omap2_uart_class,
-};
-
-/* UART3 */
-
-static struct omap_hwmod_ocp_if *omap2430_uart3_slaves[] = {
- &omap2_l4_core__uart3,
-};
-
-static struct omap_hwmod omap2430_uart3_hwmod = {
- .name = "uart3",
- .mpu_irqs = omap2_uart3_mpu_irqs,
- .sdma_reqs = omap2_uart3_sdma_reqs,
- .main_clk = "uart3_fck",
- .prcm = {
- .omap2 = {
- .module_offs = CORE_MOD,
- .prcm_reg_id = 2,
- .module_bit = OMAP24XX_EN_UART3_SHIFT,
- .idlest_reg_id = 2,
- .idlest_idle_bit = OMAP24XX_EN_UART3_SHIFT,
- },
- },
- .slaves = omap2430_uart3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_uart3_slaves),
- .class = &omap2_uart_class,
-};
-
-/* dss */
-/* dss master ports */
-static struct omap_hwmod_ocp_if *omap2430_dss_masters[] = {
- &omap2430_dss__l3,
-};
-
-/* l4_core -> dss */
-static struct omap_hwmod_ocp_if omap2430_l4_core__dss = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_dss_core_hwmod,
- .clk = "dss_ick",
- .addr = omap2_dss_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dss slave ports */
-static struct omap_hwmod_ocp_if *omap2430_dss_slaves[] = {
- &omap2430_l4_core__dss,
-};
-
-static struct omap_hwmod_opt_clk dss_opt_clks[] = {
- /*
- * The DSS HW needs all DSS clocks enabled during reset. The dss_core
- * driver does not use these clocks.
- */
- { .role = "tv_clk", .clk = "dss_54m_fck" },
- { .role = "sys_clk", .clk = "dss2_fck" },
-};
-
-static struct omap_hwmod omap2430_dss_core_hwmod = {
- .name = "dss_core",
- .class = &omap2_dss_hwmod_class,
- .main_clk = "dss1_fck", /* instead of dss_fck */
- .sdma_reqs = omap2xxx_dss_sdma_chs,
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_DSS1_SHIFT,
- .module_offs = CORE_MOD,
- .idlest_reg_id = 1,
- .idlest_stdby_bit = OMAP24XX_ST_DSS_SHIFT,
- },
- },
- .opt_clks = dss_opt_clks,
- .opt_clks_cnt = ARRAY_SIZE(dss_opt_clks),
- .slaves = omap2430_dss_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_dss_slaves),
- .masters = omap2430_dss_masters,
- .masters_cnt = ARRAY_SIZE(omap2430_dss_masters),
- .flags = HWMOD_NO_IDLEST | HWMOD_CONTROL_OPT_CLKS_IN_RESET,
-};
-
-/* l4_core -> dss_dispc */
-static struct omap_hwmod_ocp_if omap2430_l4_core__dss_dispc = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_dss_dispc_hwmod,
- .clk = "dss_ick",
- .addr = omap2_dss_dispc_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dss_dispc slave ports */
-static struct omap_hwmod_ocp_if *omap2430_dss_dispc_slaves[] = {
- &omap2430_l4_core__dss_dispc,
-};
-
-static struct omap_hwmod omap2430_dss_dispc_hwmod = {
- .name = "dss_dispc",
- .class = &omap2_dispc_hwmod_class,
- .mpu_irqs = omap2_dispc_irqs,
- .main_clk = "dss1_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_DSS1_SHIFT,
- .module_offs = CORE_MOD,
- .idlest_reg_id = 1,
- .idlest_stdby_bit = OMAP24XX_ST_DSS_SHIFT,
- },
- },
- .slaves = omap2430_dss_dispc_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_dss_dispc_slaves),
- .flags = HWMOD_NO_IDLEST,
- .dev_attr = &omap2_3_dss_dispc_dev_attr
-};
-
-/* l4_core -> dss_rfbi */
-static struct omap_hwmod_ocp_if omap2430_l4_core__dss_rfbi = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_dss_rfbi_hwmod,
- .clk = "dss_ick",
- .addr = omap2_dss_rfbi_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dss_rfbi slave ports */
-static struct omap_hwmod_ocp_if *omap2430_dss_rfbi_slaves[] = {
- &omap2430_l4_core__dss_rfbi,
-};
-
-static struct omap_hwmod_opt_clk dss_rfbi_opt_clks[] = {
- { .role = "ick", .clk = "dss_ick" },
-};
-
-static struct omap_hwmod omap2430_dss_rfbi_hwmod = {
- .name = "dss_rfbi",
- .class = &omap2_rfbi_hwmod_class,
- .main_clk = "dss1_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_DSS1_SHIFT,
- .module_offs = CORE_MOD,
- },
- },
- .opt_clks = dss_rfbi_opt_clks,
- .opt_clks_cnt = ARRAY_SIZE(dss_rfbi_opt_clks),
- .slaves = omap2430_dss_rfbi_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_dss_rfbi_slaves),
- .flags = HWMOD_NO_IDLEST,
-};
-
-/* l4_core -> dss_venc */
-static struct omap_hwmod_ocp_if omap2430_l4_core__dss_venc = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_dss_venc_hwmod,
- .clk = "dss_ick",
- .addr = omap2_dss_venc_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dss_venc slave ports */
-static struct omap_hwmod_ocp_if *omap2430_dss_venc_slaves[] = {
- &omap2430_l4_core__dss_venc,
-};
-
-static struct omap_hwmod omap2430_dss_venc_hwmod = {
- .name = "dss_venc",
- .class = &omap2_venc_hwmod_class,
- .main_clk = "dss_54m_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_DSS1_SHIFT,
- .module_offs = CORE_MOD,
- },
- },
- .slaves = omap2430_dss_venc_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_dss_venc_slaves),
- .flags = HWMOD_NO_IDLEST,
+ .clkdm_name = "dsp_clkdm",
+ .rst_lines = omap2430_iva_resets,
+ .rst_lines_cnt = ARRAY_SIZE(omap2430_iva_resets),
+ .main_clk = "dsp_fck",
};
/* I2C common */
@@ -1098,11 +84,6 @@ static struct omap_i2c_dev_attr i2c_dev_attr = {
};
/* I2C1 */
-
-static struct omap_hwmod_ocp_if *omap2430_i2c1_slaves[] = {
- &omap2430_l4_core__i2c1,
-};
-
static struct omap_hwmod omap2430_i2c1_hwmod = {
.name = "i2c1",
.flags = HWMOD_16BIT_REG,
@@ -1126,18 +107,11 @@ static struct omap_hwmod omap2430_i2c1_hwmod = {
.idlest_idle_bit = OMAP2430_ST_I2CHS1_SHIFT,
},
},
- .slaves = omap2430_i2c1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_i2c1_slaves),
.class = &i2c_class,
.dev_attr = &i2c_dev_attr,
};
/* I2C2 */
-
-static struct omap_hwmod_ocp_if *omap2430_i2c2_slaves[] = {
- &omap2430_l4_core__i2c2,
-};
-
static struct omap_hwmod omap2430_i2c2_hwmod = {
.name = "i2c2",
.flags = HWMOD_16BIT_REG,
@@ -1153,218 +127,16 @@ static struct omap_hwmod omap2430_i2c2_hwmod = {
.idlest_idle_bit = OMAP2430_ST_I2CHS2_SHIFT,
},
},
- .slaves = omap2430_i2c2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_i2c2_slaves),
.class = &i2c_class,
.dev_attr = &i2c_dev_attr,
};
-/* l4_wkup -> gpio1 */
-static struct omap_hwmod_addr_space omap2430_gpio1_addr_space[] = {
- {
- .pa_start = 0x4900C000,
- .pa_end = 0x4900C1ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-static struct omap_hwmod_ocp_if omap2430_l4_wkup__gpio1 = {
- .master = &omap2430_l4_wkup_hwmod,
- .slave = &omap2430_gpio1_hwmod,
- .clk = "gpios_ick",
- .addr = omap2430_gpio1_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_wkup -> gpio2 */
-static struct omap_hwmod_addr_space omap2430_gpio2_addr_space[] = {
- {
- .pa_start = 0x4900E000,
- .pa_end = 0x4900E1ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-static struct omap_hwmod_ocp_if omap2430_l4_wkup__gpio2 = {
- .master = &omap2430_l4_wkup_hwmod,
- .slave = &omap2430_gpio2_hwmod,
- .clk = "gpios_ick",
- .addr = omap2430_gpio2_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_wkup -> gpio3 */
-static struct omap_hwmod_addr_space omap2430_gpio3_addr_space[] = {
- {
- .pa_start = 0x49010000,
- .pa_end = 0x490101ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-static struct omap_hwmod_ocp_if omap2430_l4_wkup__gpio3 = {
- .master = &omap2430_l4_wkup_hwmod,
- .slave = &omap2430_gpio3_hwmod,
- .clk = "gpios_ick",
- .addr = omap2430_gpio3_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_wkup -> gpio4 */
-static struct omap_hwmod_addr_space omap2430_gpio4_addr_space[] = {
- {
- .pa_start = 0x49012000,
- .pa_end = 0x490121ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-static struct omap_hwmod_ocp_if omap2430_l4_wkup__gpio4 = {
- .master = &omap2430_l4_wkup_hwmod,
- .slave = &omap2430_gpio4_hwmod,
- .clk = "gpios_ick",
- .addr = omap2430_gpio4_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_core -> gpio5 */
-static struct omap_hwmod_addr_space omap2430_gpio5_addr_space[] = {
- {
- .pa_start = 0x480B6000,
- .pa_end = 0x480B61ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-static struct omap_hwmod_ocp_if omap2430_l4_core__gpio5 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_gpio5_hwmod,
- .clk = "gpio5_ick",
- .addr = omap2430_gpio5_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* gpio dev_attr */
-static struct omap_gpio_dev_attr gpio_dev_attr = {
- .bank_width = 32,
- .dbck_flag = false,
-};
-
-/* gpio1 */
-static struct omap_hwmod_ocp_if *omap2430_gpio1_slaves[] = {
- &omap2430_l4_wkup__gpio1,
-};
-
-static struct omap_hwmod omap2430_gpio1_hwmod = {
- .name = "gpio1",
- .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
- .mpu_irqs = omap2_gpio1_irqs,
- .main_clk = "gpios_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPIOS_SHIFT,
- .module_offs = WKUP_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_EN_GPIOS_SHIFT,
- },
- },
- .slaves = omap2430_gpio1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_gpio1_slaves),
- .class = &omap2xxx_gpio_hwmod_class,
- .dev_attr = &gpio_dev_attr,
-};
-
-/* gpio2 */
-static struct omap_hwmod_ocp_if *omap2430_gpio2_slaves[] = {
- &omap2430_l4_wkup__gpio2,
-};
-
-static struct omap_hwmod omap2430_gpio2_hwmod = {
- .name = "gpio2",
- .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
- .mpu_irqs = omap2_gpio2_irqs,
- .main_clk = "gpios_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPIOS_SHIFT,
- .module_offs = WKUP_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPIOS_SHIFT,
- },
- },
- .slaves = omap2430_gpio2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_gpio2_slaves),
- .class = &omap2xxx_gpio_hwmod_class,
- .dev_attr = &gpio_dev_attr,
-};
-
-/* gpio3 */
-static struct omap_hwmod_ocp_if *omap2430_gpio3_slaves[] = {
- &omap2430_l4_wkup__gpio3,
-};
-
-static struct omap_hwmod omap2430_gpio3_hwmod = {
- .name = "gpio3",
- .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
- .mpu_irqs = omap2_gpio3_irqs,
- .main_clk = "gpios_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPIOS_SHIFT,
- .module_offs = WKUP_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPIOS_SHIFT,
- },
- },
- .slaves = omap2430_gpio3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_gpio3_slaves),
- .class = &omap2xxx_gpio_hwmod_class,
- .dev_attr = &gpio_dev_attr,
-};
-
-/* gpio4 */
-static struct omap_hwmod_ocp_if *omap2430_gpio4_slaves[] = {
- &omap2430_l4_wkup__gpio4,
-};
-
-static struct omap_hwmod omap2430_gpio4_hwmod = {
- .name = "gpio4",
- .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
- .mpu_irqs = omap2_gpio4_irqs,
- .main_clk = "gpios_fck",
- .prcm = {
- .omap2 = {
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_GPIOS_SHIFT,
- .module_offs = WKUP_MOD,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_GPIOS_SHIFT,
- },
- },
- .slaves = omap2430_gpio4_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_gpio4_slaves),
- .class = &omap2xxx_gpio_hwmod_class,
- .dev_attr = &gpio_dev_attr,
-};
-
/* gpio5 */
static struct omap_hwmod_irq_info omap243x_gpio5_irqs[] = {
{ .irq = 33 }, /* INT_24XX_GPIO_BANK5 */
{ .irq = -1 }
};
-static struct omap_hwmod_ocp_if *omap2430_gpio5_slaves[] = {
- &omap2430_l4_core__gpio5,
-};
-
static struct omap_hwmod omap2430_gpio5_hwmod = {
.name = "gpio5",
.flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
@@ -1379,10 +151,8 @@ static struct omap_hwmod omap2430_gpio5_hwmod = {
.idlest_idle_bit = OMAP2430_ST_GPIO5_SHIFT,
},
},
- .slaves = omap2430_gpio5_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_gpio5_slaves),
.class = &omap2xxx_gpio_hwmod_class,
- .dev_attr = &gpio_dev_attr,
+ .dev_attr = &omap2xxx_gpio_dev_attr,
};
/* dma attributes */
@@ -1392,66 +162,21 @@ static struct omap_dma_dev_attr dma_dev_attr = {
.lch_count = 32,
};
-/* dma_system -> L3 */
-static struct omap_hwmod_ocp_if omap2430_dma_system__l3 = {
- .master = &omap2430_dma_system_hwmod,
- .slave = &omap2430_l3_main_hwmod,
- .clk = "core_l3_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dma_system master ports */
-static struct omap_hwmod_ocp_if *omap2430_dma_system_masters[] = {
- &omap2430_dma_system__l3,
-};
-
-/* l4_core -> dma_system */
-static struct omap_hwmod_ocp_if omap2430_l4_core__dma_system = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_dma_system_hwmod,
- .clk = "sdma_ick",
- .addr = omap2_dma_system_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dma_system slave ports */
-static struct omap_hwmod_ocp_if *omap2430_dma_system_slaves[] = {
- &omap2430_l4_core__dma_system,
-};
-
static struct omap_hwmod omap2430_dma_system_hwmod = {
.name = "dma",
.class = &omap2xxx_dma_hwmod_class,
.mpu_irqs = omap2_dma_system_irqs,
.main_clk = "core_l3_ck",
- .slaves = omap2430_dma_system_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_dma_system_slaves),
- .masters = omap2430_dma_system_masters,
- .masters_cnt = ARRAY_SIZE(omap2430_dma_system_masters),
.dev_attr = &dma_dev_attr,
.flags = HWMOD_NO_IDLEST,
};
/* mailbox */
-static struct omap_hwmod omap2430_mailbox_hwmod;
static struct omap_hwmod_irq_info omap2430_mailbox_irqs[] = {
{ .irq = 26 },
{ .irq = -1 }
};
-/* l4_core -> mailbox */
-static struct omap_hwmod_ocp_if omap2430_l4_core__mailbox = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_mailbox_hwmod,
- .addr = omap2_mailbox_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mailbox slave ports */
-static struct omap_hwmod_ocp_if *omap2430_mailbox_slaves[] = {
- &omap2430_l4_core__mailbox,
-};
-
static struct omap_hwmod omap2430_mailbox_hwmod = {
.name = "mailbox",
.class = &omap2xxx_mailbox_hwmod_class,
@@ -1466,66 +191,6 @@ static struct omap_hwmod omap2430_mailbox_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_MAILBOXES_SHIFT,
},
},
- .slaves = omap2430_mailbox_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_mailbox_slaves),
-};
-
-/* mcspi1 */
-static struct omap_hwmod_ocp_if *omap2430_mcspi1_slaves[] = {
- &omap2430_l4_core__mcspi1,
-};
-
-static struct omap2_mcspi_dev_attr omap_mcspi1_dev_attr = {
- .num_chipselect = 4,
-};
-
-static struct omap_hwmod omap2430_mcspi1_hwmod = {
- .name = "mcspi1_hwmod",
- .mpu_irqs = omap2_mcspi1_mpu_irqs,
- .sdma_reqs = omap2_mcspi1_sdma_reqs,
- .main_clk = "mcspi1_fck",
- .prcm = {
- .omap2 = {
- .module_offs = CORE_MOD,
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_MCSPI1_SHIFT,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_MCSPI1_SHIFT,
- },
- },
- .slaves = omap2430_mcspi1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_mcspi1_slaves),
- .class = &omap2xxx_mcspi_class,
- .dev_attr = &omap_mcspi1_dev_attr,
-};
-
-/* mcspi2 */
-static struct omap_hwmod_ocp_if *omap2430_mcspi2_slaves[] = {
- &omap2430_l4_core__mcspi2,
-};
-
-static struct omap2_mcspi_dev_attr omap_mcspi2_dev_attr = {
- .num_chipselect = 2,
-};
-
-static struct omap_hwmod omap2430_mcspi2_hwmod = {
- .name = "mcspi2_hwmod",
- .mpu_irqs = omap2_mcspi2_mpu_irqs,
- .sdma_reqs = omap2_mcspi2_sdma_reqs,
- .main_clk = "mcspi2_fck",
- .prcm = {
- .omap2 = {
- .module_offs = CORE_MOD,
- .prcm_reg_id = 1,
- .module_bit = OMAP24XX_EN_MCSPI2_SHIFT,
- .idlest_reg_id = 1,
- .idlest_idle_bit = OMAP24XX_ST_MCSPI2_SHIFT,
- },
- },
- .slaves = omap2430_mcspi2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_mcspi2_slaves),
- .class = &omap2xxx_mcspi_class,
- .dev_attr = &omap_mcspi2_dev_attr,
};
/* mcspi3 */
@@ -1542,16 +207,12 @@ static struct omap_hwmod_dma_info omap2430_mcspi3_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_ocp_if *omap2430_mcspi3_slaves[] = {
- &omap2430_l4_core__mcspi3,
-};
-
static struct omap2_mcspi_dev_attr omap_mcspi3_dev_attr = {
.num_chipselect = 2,
};
static struct omap_hwmod omap2430_mcspi3_hwmod = {
- .name = "mcspi3_hwmod",
+ .name = "mcspi3",
.mpu_irqs = omap2430_mcspi3_mpu_irqs,
.sdma_reqs = omap2430_mcspi3_sdma_reqs,
.main_clk = "mcspi3_fck",
@@ -1564,15 +225,11 @@ static struct omap_hwmod omap2430_mcspi3_hwmod = {
.idlest_idle_bit = OMAP2430_ST_MCSPI3_SHIFT,
},
},
- .slaves = omap2430_mcspi3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_mcspi3_slaves),
.class = &omap2xxx_mcspi_class,
.dev_attr = &omap_mcspi3_dev_attr,
};
-/*
- * usbhsotg
- */
+/* usbhsotg */
static struct omap_hwmod_class_sysconfig omap2430_usbhsotg_sysc = {
.rev_offs = 0x0400,
.sysc_offs = 0x0404,
@@ -1611,10 +268,6 @@ static struct omap_hwmod omap2430_usbhsotg_hwmod = {
.idlest_idle_bit = OMAP2430_ST_USBHS_SHIFT,
},
},
- .masters = omap2430_usbhsotg_masters,
- .masters_cnt = ARRAY_SIZE(omap2430_usbhsotg_masters),
- .slaves = omap2430_usbhsotg_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_usbhsotg_slaves),
.class = &usbotg_class,
/*
* Erratum ID: i479 idle_req / idle_ack mechanism potentially
@@ -1652,20 +305,6 @@ static struct omap_hwmod_irq_info omap2430_mcbsp1_irqs[] = {
{ .irq = -1 }
};
-/* l4_core -> mcbsp1 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp1 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_mcbsp1_hwmod,
- .clk = "mcbsp1_ick",
- .addr = omap2_mcbsp1_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mcbsp1 slave ports */
-static struct omap_hwmod_ocp_if *omap2430_mcbsp1_slaves[] = {
- &omap2430_l4_core__mcbsp1,
-};
-
static struct omap_hwmod omap2430_mcbsp1_hwmod = {
.name = "mcbsp1",
.class = &omap2430_mcbsp_hwmod_class,
@@ -1681,8 +320,6 @@ static struct omap_hwmod omap2430_mcbsp1_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_MCBSP1_SHIFT,
},
},
- .slaves = omap2430_mcbsp1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_mcbsp1_slaves),
};
/* mcbsp2 */
@@ -1693,20 +330,6 @@ static struct omap_hwmod_irq_info omap2430_mcbsp2_irqs[] = {
{ .irq = -1 }
};
-/* l4_core -> mcbsp2 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp2 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_mcbsp2_hwmod,
- .clk = "mcbsp2_ick",
- .addr = omap2xxx_mcbsp2_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mcbsp2 slave ports */
-static struct omap_hwmod_ocp_if *omap2430_mcbsp2_slaves[] = {
- &omap2430_l4_core__mcbsp2,
-};
-
static struct omap_hwmod omap2430_mcbsp2_hwmod = {
.name = "mcbsp2",
.class = &omap2430_mcbsp_hwmod_class,
@@ -1722,8 +345,6 @@ static struct omap_hwmod omap2430_mcbsp2_hwmod = {
.idlest_idle_bit = OMAP24XX_ST_MCBSP2_SHIFT,
},
},
- .slaves = omap2430_mcbsp2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_mcbsp2_slaves),
};
/* mcbsp3 */
@@ -1734,30 +355,6 @@ static struct omap_hwmod_irq_info omap2430_mcbsp3_irqs[] = {
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap2430_mcbsp3_addrs[] = {
- {
- .name = "mpu",
- .pa_start = 0x4808C000,
- .pa_end = 0x4808C0ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_core -> mcbsp3 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp3 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_mcbsp3_hwmod,
- .clk = "mcbsp3_ick",
- .addr = omap2430_mcbsp3_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mcbsp3 slave ports */
-static struct omap_hwmod_ocp_if *omap2430_mcbsp3_slaves[] = {
- &omap2430_l4_core__mcbsp3,
-};
-
static struct omap_hwmod omap2430_mcbsp3_hwmod = {
.name = "mcbsp3",
.class = &omap2430_mcbsp_hwmod_class,
@@ -1773,8 +370,6 @@ static struct omap_hwmod omap2430_mcbsp3_hwmod = {
.idlest_idle_bit = OMAP2430_ST_MCBSP3_SHIFT,
},
},
- .slaves = omap2430_mcbsp3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_mcbsp3_slaves),
};
/* mcbsp4 */
@@ -1791,30 +386,6 @@ static struct omap_hwmod_dma_info omap2430_mcbsp4_sdma_chs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap2430_mcbsp4_addrs[] = {
- {
- .name = "mpu",
- .pa_start = 0x4808E000,
- .pa_end = 0x4808E0ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_core -> mcbsp4 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp4 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_mcbsp4_hwmod,
- .clk = "mcbsp4_ick",
- .addr = omap2430_mcbsp4_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mcbsp4 slave ports */
-static struct omap_hwmod_ocp_if *omap2430_mcbsp4_slaves[] = {
- &omap2430_l4_core__mcbsp4,
-};
-
static struct omap_hwmod omap2430_mcbsp4_hwmod = {
.name = "mcbsp4",
.class = &omap2430_mcbsp_hwmod_class,
@@ -1830,8 +401,6 @@ static struct omap_hwmod omap2430_mcbsp4_hwmod = {
.idlest_idle_bit = OMAP2430_ST_MCBSP4_SHIFT,
},
},
- .slaves = omap2430_mcbsp4_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_mcbsp4_slaves),
};
/* mcbsp5 */
@@ -1848,30 +417,6 @@ static struct omap_hwmod_dma_info omap2430_mcbsp5_sdma_chs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap2430_mcbsp5_addrs[] = {
- {
- .name = "mpu",
- .pa_start = 0x48096000,
- .pa_end = 0x480960ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_core -> mcbsp5 */
-static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp5 = {
- .master = &omap2430_l4_core_hwmod,
- .slave = &omap2430_mcbsp5_hwmod,
- .clk = "mcbsp5_ick",
- .addr = omap2430_mcbsp5_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mcbsp5 slave ports */
-static struct omap_hwmod_ocp_if *omap2430_mcbsp5_slaves[] = {
- &omap2430_l4_core__mcbsp5,
-};
-
static struct omap_hwmod omap2430_mcbsp5_hwmod = {
.name = "mcbsp5",
.class = &omap2430_mcbsp_hwmod_class,
@@ -1887,12 +432,9 @@ static struct omap_hwmod omap2430_mcbsp5_hwmod = {
.idlest_idle_bit = OMAP2430_ST_MCBSP5_SHIFT,
},
},
- .slaves = omap2430_mcbsp5_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_mcbsp5_slaves),
};
/* MMC/SD/SDIO common */
-
static struct omap_hwmod_class_sysconfig omap2430_mmc_sysc = {
.rev_offs = 0x1fc,
.sysc_offs = 0x10,
@@ -1910,7 +452,6 @@ static struct omap_hwmod_class omap2430_mmc_class = {
};
/* MMC/SD/SDIO1 */
-
static struct omap_hwmod_irq_info omap2430_mmc1_mpu_irqs[] = {
{ .irq = 83 },
{ .irq = -1 }
@@ -1926,10 +467,6 @@ static struct omap_hwmod_opt_clk omap2430_mmc1_opt_clks[] = {
{ .role = "dbck", .clk = "mmchsdb1_fck" },
};
-static struct omap_hwmod_ocp_if *omap2430_mmc1_slaves[] = {
- &omap2430_l4_core__mmc1,
-};
-
static struct omap_mmc_dev_attr mmc1_dev_attr = {
.flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
};
@@ -1952,13 +489,10 @@ static struct omap_hwmod omap2430_mmc1_hwmod = {
},
},
.dev_attr = &mmc1_dev_attr,
- .slaves = omap2430_mmc1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_mmc1_slaves),
.class = &omap2430_mmc_class,
};
/* MMC/SD/SDIO2 */
-
static struct omap_hwmod_irq_info omap2430_mmc2_mpu_irqs[] = {
{ .irq = 86 },
{ .irq = -1 }
@@ -1974,10 +508,6 @@ static struct omap_hwmod_opt_clk omap2430_mmc2_opt_clks[] = {
{ .role = "dbck", .clk = "mmchsdb2_fck" },
};
-static struct omap_hwmod_ocp_if *omap2430_mmc2_slaves[] = {
- &omap2430_l4_core__mmc2,
-};
-
static struct omap_hwmod omap2430_mmc2_hwmod = {
.name = "mmc2",
.flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
@@ -1995,78 +525,418 @@ static struct omap_hwmod omap2430_mmc2_hwmod = {
.idlest_idle_bit = OMAP2430_ST_MMCHS2_SHIFT,
},
},
- .slaves = omap2430_mmc2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap2430_mmc2_slaves),
.class = &omap2430_mmc_class,
};
-static __initdata struct omap_hwmod *omap2430_hwmods[] = {
- &omap2430_l3_main_hwmod,
- &omap2430_l4_core_hwmod,
- &omap2430_l4_wkup_hwmod,
- &omap2430_mpu_hwmod,
- &omap2430_iva_hwmod,
-
- &omap2430_timer1_hwmod,
- &omap2430_timer2_hwmod,
- &omap2430_timer3_hwmod,
- &omap2430_timer4_hwmod,
- &omap2430_timer5_hwmod,
- &omap2430_timer6_hwmod,
- &omap2430_timer7_hwmod,
- &omap2430_timer8_hwmod,
- &omap2430_timer9_hwmod,
- &omap2430_timer10_hwmod,
- &omap2430_timer11_hwmod,
- &omap2430_timer12_hwmod,
-
- &omap2430_wd_timer2_hwmod,
- &omap2430_uart1_hwmod,
- &omap2430_uart2_hwmod,
- &omap2430_uart3_hwmod,
- /* dss class */
- &omap2430_dss_core_hwmod,
- &omap2430_dss_dispc_hwmod,
- &omap2430_dss_rfbi_hwmod,
- &omap2430_dss_venc_hwmod,
- /* i2c class */
- &omap2430_i2c1_hwmod,
- &omap2430_i2c2_hwmod,
- &omap2430_mmc1_hwmod,
- &omap2430_mmc2_hwmod,
-
- /* gpio class */
- &omap2430_gpio1_hwmod,
- &omap2430_gpio2_hwmod,
- &omap2430_gpio3_hwmod,
- &omap2430_gpio4_hwmod,
- &omap2430_gpio5_hwmod,
-
- /* dma_system class*/
- &omap2430_dma_system_hwmod,
-
- /* mcbsp class */
- &omap2430_mcbsp1_hwmod,
- &omap2430_mcbsp2_hwmod,
- &omap2430_mcbsp3_hwmod,
- &omap2430_mcbsp4_hwmod,
- &omap2430_mcbsp5_hwmod,
-
- /* mailbox class */
- &omap2430_mailbox_hwmod,
-
- /* mcspi class */
- &omap2430_mcspi1_hwmod,
- &omap2430_mcspi2_hwmod,
- &omap2430_mcspi3_hwmod,
-
- /* usbotg class*/
- &omap2430_usbhsotg_hwmod,
+/* HDQ1W/1-wire */
+static struct omap_hwmod omap2430_hdq1w_hwmod = {
+ .name = "hdq1w",
+ .mpu_irqs = omap2_hdq1w_mpu_irqs,
+ .main_clk = "hdq_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_HDQ_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_HDQ_SHIFT,
+ },
+ },
+ .class = &omap2_hdq1w_class,
+};
+
+/*
+ * interfaces
+ */
+
+/* L3 -> L4_CORE interface */
+/* l3_core -> usbhsotg interface */
+static struct omap_hwmod_ocp_if omap2430_usbhsotg__l3 = {
+ .master = &omap2430_usbhsotg_hwmod,
+ .slave = &omap2xxx_l3_main_hwmod,
+ .clk = "core_l3_ck",
+ .user = OCP_USER_MPU,
+};
+
+/* L4 CORE -> I2C1 interface */
+static struct omap_hwmod_ocp_if omap2430_l4_core__i2c1 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2430_i2c1_hwmod,
+ .clk = "i2c1_ick",
+ .addr = omap2_i2c1_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> I2C2 interface */
+static struct omap_hwmod_ocp_if omap2430_l4_core__i2c2 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2430_i2c2_hwmod,
+ .clk = "i2c2_ick",
+ .addr = omap2_i2c2_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap2430_usbhsotg_addrs[] = {
+ {
+ .pa_start = OMAP243X_HS_BASE,
+ .pa_end = OMAP243X_HS_BASE + SZ_4K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_core ->usbhsotg interface */
+static struct omap_hwmod_ocp_if omap2430_l4_core__usbhsotg = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2430_usbhsotg_hwmod,
+ .clk = "usb_l4_ick",
+ .addr = omap2430_usbhsotg_addrs,
+ .user = OCP_USER_MPU,
+};
+/* L4 CORE -> MMC1 interface */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mmc1 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2430_mmc1_hwmod,
+ .clk = "mmchs1_ick",
+ .addr = omap2430_mmc1_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> MMC2 interface */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mmc2 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2430_mmc2_hwmod,
+ .clk = "mmchs2_ick",
+ .addr = omap2430_mmc2_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4 core -> mcspi3 interface */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mcspi3 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2430_mcspi3_hwmod,
+ .clk = "mcspi3_ick",
+ .addr = omap2430_mcspi3_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* IVA2 <- L3 interface */
+static struct omap_hwmod_ocp_if omap2430_l3__iva = {
+ .master = &omap2xxx_l3_main_hwmod,
+ .slave = &omap2430_iva_hwmod,
+ .clk = "core_l3_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap2430_timer1_addrs[] = {
+ {
+ .pa_start = 0x49018000,
+ .pa_end = 0x49018000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_wkup -> timer1 */
+static struct omap_hwmod_ocp_if omap2430_l4_wkup__timer1 = {
+ .master = &omap2xxx_l4_wkup_hwmod,
+ .slave = &omap2xxx_timer1_hwmod,
+ .clk = "gpt1_ick",
+ .addr = omap2430_timer1_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> wd_timer2 */
+static struct omap_hwmod_addr_space omap2430_wd_timer2_addrs[] = {
+ {
+ .pa_start = 0x49016000,
+ .pa_end = 0x4901607f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if omap2430_l4_wkup__wd_timer2 = {
+ .master = &omap2xxx_l4_wkup_hwmod,
+ .slave = &omap2xxx_wd_timer2_hwmod,
+ .clk = "mpu_wdt_ick",
+ .addr = omap2430_wd_timer2_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> gpio1 */
+static struct omap_hwmod_addr_space omap2430_gpio1_addr_space[] = {
+ {
+ .pa_start = 0x4900C000,
+ .pa_end = 0x4900C1ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if omap2430_l4_wkup__gpio1 = {
+ .master = &omap2xxx_l4_wkup_hwmod,
+ .slave = &omap2xxx_gpio1_hwmod,
+ .clk = "gpios_ick",
+ .addr = omap2430_gpio1_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> gpio2 */
+static struct omap_hwmod_addr_space omap2430_gpio2_addr_space[] = {
+ {
+ .pa_start = 0x4900E000,
+ .pa_end = 0x4900E1ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if omap2430_l4_wkup__gpio2 = {
+ .master = &omap2xxx_l4_wkup_hwmod,
+ .slave = &omap2xxx_gpio2_hwmod,
+ .clk = "gpios_ick",
+ .addr = omap2430_gpio2_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> gpio3 */
+static struct omap_hwmod_addr_space omap2430_gpio3_addr_space[] = {
+ {
+ .pa_start = 0x49010000,
+ .pa_end = 0x490101ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if omap2430_l4_wkup__gpio3 = {
+ .master = &omap2xxx_l4_wkup_hwmod,
+ .slave = &omap2xxx_gpio3_hwmod,
+ .clk = "gpios_ick",
+ .addr = omap2430_gpio3_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> gpio4 */
+static struct omap_hwmod_addr_space omap2430_gpio4_addr_space[] = {
+ {
+ .pa_start = 0x49012000,
+ .pa_end = 0x490121ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if omap2430_l4_wkup__gpio4 = {
+ .master = &omap2xxx_l4_wkup_hwmod,
+ .slave = &omap2xxx_gpio4_hwmod,
+ .clk = "gpios_ick",
+ .addr = omap2430_gpio4_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> gpio5 */
+static struct omap_hwmod_addr_space omap2430_gpio5_addr_space[] = {
+ {
+ .pa_start = 0x480B6000,
+ .pa_end = 0x480B61ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if omap2430_l4_core__gpio5 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2430_gpio5_hwmod,
+ .clk = "gpio5_ick",
+ .addr = omap2430_gpio5_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dma_system -> L3 */
+static struct omap_hwmod_ocp_if omap2430_dma_system__l3 = {
+ .master = &omap2430_dma_system_hwmod,
+ .slave = &omap2xxx_l3_main_hwmod,
+ .clk = "core_l3_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> dma_system */
+static struct omap_hwmod_ocp_if omap2430_l4_core__dma_system = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2430_dma_system_hwmod,
+ .clk = "sdma_ick",
+ .addr = omap2_dma_system_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> mailbox */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mailbox = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2430_mailbox_hwmod,
+ .addr = omap2_mailbox_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> mcbsp1 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp1 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2430_mcbsp1_hwmod,
+ .clk = "mcbsp1_ick",
+ .addr = omap2_mcbsp1_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> mcbsp2 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp2 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2430_mcbsp2_hwmod,
+ .clk = "mcbsp2_ick",
+ .addr = omap2xxx_mcbsp2_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap2430_mcbsp3_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x4808C000,
+ .pa_end = 0x4808C0ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_core -> mcbsp3 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp3 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2430_mcbsp3_hwmod,
+ .clk = "mcbsp3_ick",
+ .addr = omap2430_mcbsp3_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap2430_mcbsp4_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x4808E000,
+ .pa_end = 0x4808E0ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_core -> mcbsp4 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp4 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2430_mcbsp4_hwmod,
+ .clk = "mcbsp4_ick",
+ .addr = omap2430_mcbsp4_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap2430_mcbsp5_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x48096000,
+ .pa_end = 0x480960ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_core -> mcbsp5 */
+static struct omap_hwmod_ocp_if omap2430_l4_core__mcbsp5 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2430_mcbsp5_hwmod,
+ .clk = "mcbsp5_ick",
+ .addr = omap2430_mcbsp5_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> hdq1w */
+static struct omap_hwmod_ocp_if omap2430_l4_core__hdq1w = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2430_hdq1w_hwmod,
+ .clk = "hdq_ick",
+ .addr = omap2_hdq1w_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+ .flags = OMAP_FIREWALL_L4 | OCPIF_SWSUP_IDLE,
+};
+
+/* l4_wkup -> 32ksync_counter */
+static struct omap_hwmod_addr_space omap2430_counter_32k_addrs[] = {
+ {
+ .pa_start = 0x49020000,
+ .pa_end = 0x4902001f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if omap2430_l4_wkup__counter_32k = {
+ .master = &omap2xxx_l4_wkup_hwmod,
+ .slave = &omap2xxx_counter_32k_hwmod,
+ .clk = "sync_32k_ick",
+ .addr = omap2430_counter_32k_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_ocp_if *omap2430_hwmod_ocp_ifs[] __initdata = {
+ &omap2xxx_l3_main__l4_core,
+ &omap2xxx_mpu__l3_main,
+ &omap2xxx_dss__l3,
+ &omap2430_usbhsotg__l3,
+ &omap2430_l4_core__i2c1,
+ &omap2430_l4_core__i2c2,
+ &omap2xxx_l4_core__l4_wkup,
+ &omap2_l4_core__uart1,
+ &omap2_l4_core__uart2,
+ &omap2_l4_core__uart3,
+ &omap2430_l4_core__usbhsotg,
+ &omap2430_l4_core__mmc1,
+ &omap2430_l4_core__mmc2,
+ &omap2xxx_l4_core__mcspi1,
+ &omap2xxx_l4_core__mcspi2,
+ &omap2430_l4_core__mcspi3,
+ &omap2430_l3__iva,
+ &omap2430_l4_wkup__timer1,
+ &omap2xxx_l4_core__timer2,
+ &omap2xxx_l4_core__timer3,
+ &omap2xxx_l4_core__timer4,
+ &omap2xxx_l4_core__timer5,
+ &omap2xxx_l4_core__timer6,
+ &omap2xxx_l4_core__timer7,
+ &omap2xxx_l4_core__timer8,
+ &omap2xxx_l4_core__timer9,
+ &omap2xxx_l4_core__timer10,
+ &omap2xxx_l4_core__timer11,
+ &omap2xxx_l4_core__timer12,
+ &omap2430_l4_wkup__wd_timer2,
+ &omap2xxx_l4_core__dss,
+ &omap2xxx_l4_core__dss_dispc,
+ &omap2xxx_l4_core__dss_rfbi,
+ &omap2xxx_l4_core__dss_venc,
+ &omap2430_l4_wkup__gpio1,
+ &omap2430_l4_wkup__gpio2,
+ &omap2430_l4_wkup__gpio3,
+ &omap2430_l4_wkup__gpio4,
+ &omap2430_l4_core__gpio5,
+ &omap2430_dma_system__l3,
+ &omap2430_l4_core__dma_system,
+ &omap2430_l4_core__mailbox,
+ &omap2430_l4_core__mcbsp1,
+ &omap2430_l4_core__mcbsp2,
+ &omap2430_l4_core__mcbsp3,
+ &omap2430_l4_core__mcbsp4,
+ &omap2430_l4_core__mcbsp5,
+ &omap2430_l4_core__hdq1w,
+ &omap2430_l4_wkup__counter_32k,
NULL,
};
int __init omap2430_hwmod_init(void)
{
- return omap_hwmod_register(omap2430_hwmods);
+ return omap_hwmod_register_links(omap2430_hwmod_ocp_ifs);
}
diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_interconnect_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_interconnect_data.c
index 04637fabadd2..cbb4ef6544ad 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_interconnect_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_interconnect_data.c
@@ -171,3 +171,12 @@ struct omap_hwmod_addr_space omap2_mcbsp1_addrs[] = {
},
{ }
};
+
+struct omap_hwmod_addr_space omap2_hdq1w_addr_space[] = {
+ {
+ .pa_start = 0x480b2000,
+ .pa_end = 0x480b2fff,
+ .flags = ADDR_TYPE_RT,
+ },
+ { }
+};
diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c
index f08e442af397..102d76e9e9ea 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_3xxx_ipblock_data.c
@@ -2,6 +2,7 @@
* omap_hwmod_2xxx_3xxx_ipblock_data.c - common IP block data for OMAP2/3
*
* Copyright (C) 2011 Nokia Corporation
+ * Copyright (C) 2012 Texas Instruments, Inc.
* Paul Walmsley
*
* This program is free software; you can redistribute it and/or modify
@@ -12,6 +13,7 @@
#include <plat/serial.h>
#include <plat/dma.h>
#include <plat/common.h>
+#include <plat/hdq1w.h>
#include <mach/irqs.h>
@@ -302,3 +304,23 @@ struct omap_hwmod_irq_info omap2_mcspi2_mpu_irqs[] = {
{ .irq = -1 }
};
+struct omap_hwmod_class_sysconfig omap2_hdq1w_sysc = {
+ .rev_offs = 0x0,
+ .sysc_offs = 0x14,
+ .syss_offs = 0x18,
+ .sysc_flags = (SYSC_HAS_SOFTRESET | SYSC_HAS_AUTOIDLE |
+ SYSS_HAS_RESET_STATUS),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+struct omap_hwmod_class omap2_hdq1w_class = {
+ .name = "hdq1w",
+ .sysc = &omap2_hdq1w_sysc,
+ .reset = &omap_hdq1w_reset,
+};
+
+struct omap_hwmod_irq_info omap2_hdq1w_mpu_irqs[] = {
+ { .irq = 58, },
+ { .irq = -1 }
+};
+
diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_interconnect_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_interconnect_data.c
index 4f3547c2a49e..5178e40e84f9 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2xxx_interconnect_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_interconnect_data.c
@@ -15,10 +15,12 @@
#include <plat/omap_hwmod.h>
#include <plat/serial.h>
+#include <plat/l3_2xxx.h>
+#include <plat/l4_2xxx.h>
#include "omap_hwmod_common_data.h"
-struct omap_hwmod_addr_space omap2xxx_uart1_addr_space[] = {
+static struct omap_hwmod_addr_space omap2xxx_uart1_addr_space[] = {
{
.pa_start = OMAP2_UART1_BASE,
.pa_end = OMAP2_UART1_BASE + SZ_8K - 1,
@@ -27,7 +29,7 @@ struct omap_hwmod_addr_space omap2xxx_uart1_addr_space[] = {
{ }
};
-struct omap_hwmod_addr_space omap2xxx_uart2_addr_space[] = {
+static struct omap_hwmod_addr_space omap2xxx_uart2_addr_space[] = {
{
.pa_start = OMAP2_UART2_BASE,
.pa_end = OMAP2_UART2_BASE + SZ_1K - 1,
@@ -36,7 +38,7 @@ struct omap_hwmod_addr_space omap2xxx_uart2_addr_space[] = {
{ }
};
-struct omap_hwmod_addr_space omap2xxx_uart3_addr_space[] = {
+static struct omap_hwmod_addr_space omap2xxx_uart3_addr_space[] = {
{
.pa_start = OMAP2_UART3_BASE,
.pa_end = OMAP2_UART3_BASE + SZ_1K - 1,
@@ -45,7 +47,7 @@ struct omap_hwmod_addr_space omap2xxx_uart3_addr_space[] = {
{ }
};
-struct omap_hwmod_addr_space omap2xxx_timer2_addrs[] = {
+static struct omap_hwmod_addr_space omap2xxx_timer2_addrs[] = {
{
.pa_start = 0x4802a000,
.pa_end = 0x4802a000 + SZ_1K - 1,
@@ -54,7 +56,7 @@ struct omap_hwmod_addr_space omap2xxx_timer2_addrs[] = {
{ }
};
-struct omap_hwmod_addr_space omap2xxx_timer3_addrs[] = {
+static struct omap_hwmod_addr_space omap2xxx_timer3_addrs[] = {
{
.pa_start = 0x48078000,
.pa_end = 0x48078000 + SZ_1K - 1,
@@ -63,7 +65,7 @@ struct omap_hwmod_addr_space omap2xxx_timer3_addrs[] = {
{ }
};
-struct omap_hwmod_addr_space omap2xxx_timer4_addrs[] = {
+static struct omap_hwmod_addr_space omap2xxx_timer4_addrs[] = {
{
.pa_start = 0x4807a000,
.pa_end = 0x4807a000 + SZ_1K - 1,
@@ -72,7 +74,7 @@ struct omap_hwmod_addr_space omap2xxx_timer4_addrs[] = {
{ }
};
-struct omap_hwmod_addr_space omap2xxx_timer5_addrs[] = {
+static struct omap_hwmod_addr_space omap2xxx_timer5_addrs[] = {
{
.pa_start = 0x4807c000,
.pa_end = 0x4807c000 + SZ_1K - 1,
@@ -81,7 +83,7 @@ struct omap_hwmod_addr_space omap2xxx_timer5_addrs[] = {
{ }
};
-struct omap_hwmod_addr_space omap2xxx_timer6_addrs[] = {
+static struct omap_hwmod_addr_space omap2xxx_timer6_addrs[] = {
{
.pa_start = 0x4807e000,
.pa_end = 0x4807e000 + SZ_1K - 1,
@@ -90,7 +92,7 @@ struct omap_hwmod_addr_space omap2xxx_timer6_addrs[] = {
{ }
};
-struct omap_hwmod_addr_space omap2xxx_timer7_addrs[] = {
+static struct omap_hwmod_addr_space omap2xxx_timer7_addrs[] = {
{
.pa_start = 0x48080000,
.pa_end = 0x48080000 + SZ_1K - 1,
@@ -99,7 +101,7 @@ struct omap_hwmod_addr_space omap2xxx_timer7_addrs[] = {
{ }
};
-struct omap_hwmod_addr_space omap2xxx_timer8_addrs[] = {
+static struct omap_hwmod_addr_space omap2xxx_timer8_addrs[] = {
{
.pa_start = 0x48082000,
.pa_end = 0x48082000 + SZ_1K - 1,
@@ -108,7 +110,7 @@ struct omap_hwmod_addr_space omap2xxx_timer8_addrs[] = {
{ }
};
-struct omap_hwmod_addr_space omap2xxx_timer9_addrs[] = {
+static struct omap_hwmod_addr_space omap2xxx_timer9_addrs[] = {
{
.pa_start = 0x48084000,
.pa_end = 0x48084000 + SZ_1K - 1,
@@ -127,4 +129,246 @@ struct omap_hwmod_addr_space omap2xxx_mcbsp2_addrs[] = {
{ }
};
+/*
+ * Common interconnect data
+ */
+
+/* L3 -> L4_CORE interface */
+struct omap_hwmod_ocp_if omap2xxx_l3_main__l4_core = {
+ .master = &omap2xxx_l3_main_hwmod,
+ .slave = &omap2xxx_l4_core_hwmod,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* MPU -> L3 interface */
+struct omap_hwmod_ocp_if omap2xxx_mpu__l3_main = {
+ .master = &omap2xxx_mpu_hwmod,
+ .slave = &omap2xxx_l3_main_hwmod,
+ .user = OCP_USER_MPU,
+};
+
+/* DSS -> l3 */
+struct omap_hwmod_ocp_if omap2xxx_dss__l3 = {
+ .master = &omap2xxx_dss_core_hwmod,
+ .slave = &omap2xxx_l3_main_hwmod,
+ .fw = {
+ .omap2 = {
+ .l3_perm_bit = OMAP2_L3_CORE_FW_CONNID_DSS,
+ .flags = OMAP_FIREWALL_L3,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4_CORE -> L4_WKUP interface */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__l4_wkup = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2xxx_l4_wkup_hwmod,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> UART1 interface */
+struct omap_hwmod_ocp_if omap2_l4_core__uart1 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2xxx_uart1_hwmod,
+ .clk = "uart1_ick",
+ .addr = omap2xxx_uart1_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> UART2 interface */
+struct omap_hwmod_ocp_if omap2_l4_core__uart2 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2xxx_uart2_hwmod,
+ .clk = "uart2_ick",
+ .addr = omap2xxx_uart2_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 PER -> UART3 interface */
+struct omap_hwmod_ocp_if omap2_l4_core__uart3 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2xxx_uart3_hwmod,
+ .clk = "uart3_ick",
+ .addr = omap2xxx_uart3_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4 core -> mcspi1 interface */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__mcspi1 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2xxx_mcspi1_hwmod,
+ .clk = "mcspi1_ick",
+ .addr = omap2_mcspi1_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4 core -> mcspi2 interface */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__mcspi2 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2xxx_mcspi2_hwmod,
+ .clk = "mcspi2_ick",
+ .addr = omap2_mcspi2_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer2 */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__timer2 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2xxx_timer2_hwmod,
+ .clk = "gpt2_ick",
+ .addr = omap2xxx_timer2_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer3 */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__timer3 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2xxx_timer3_hwmod,
+ .clk = "gpt3_ick",
+ .addr = omap2xxx_timer3_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer4 */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__timer4 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2xxx_timer4_hwmod,
+ .clk = "gpt4_ick",
+ .addr = omap2xxx_timer4_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer5 */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__timer5 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2xxx_timer5_hwmod,
+ .clk = "gpt5_ick",
+ .addr = omap2xxx_timer5_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer6 */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__timer6 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2xxx_timer6_hwmod,
+ .clk = "gpt6_ick",
+ .addr = omap2xxx_timer6_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer7 */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__timer7 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2xxx_timer7_hwmod,
+ .clk = "gpt7_ick",
+ .addr = omap2xxx_timer7_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer8 */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__timer8 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2xxx_timer8_hwmod,
+ .clk = "gpt8_ick",
+ .addr = omap2xxx_timer8_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer9 */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__timer9 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2xxx_timer9_hwmod,
+ .clk = "gpt9_ick",
+ .addr = omap2xxx_timer9_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer10 */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__timer10 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2xxx_timer10_hwmod,
+ .clk = "gpt10_ick",
+ .addr = omap2_timer10_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer11 */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__timer11 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2xxx_timer11_hwmod,
+ .clk = "gpt11_ick",
+ .addr = omap2_timer11_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer12 */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__timer12 = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2xxx_timer12_hwmod,
+ .clk = "gpt12_ick",
+ .addr = omap2xxx_timer12_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> dss */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__dss = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2xxx_dss_core_hwmod,
+ .clk = "dss_ick",
+ .addr = omap2_dss_addrs,
+ .fw = {
+ .omap2 = {
+ .l4_fw_region = OMAP2420_L4_CORE_FW_DSS_CORE_REGION,
+ .flags = OMAP_FIREWALL_L4,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> dss_dispc */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__dss_dispc = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2xxx_dss_dispc_hwmod,
+ .clk = "dss_ick",
+ .addr = omap2_dss_dispc_addrs,
+ .fw = {
+ .omap2 = {
+ .l4_fw_region = OMAP2420_L4_CORE_FW_DSS_DISPC_REGION,
+ .flags = OMAP_FIREWALL_L4,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> dss_rfbi */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__dss_rfbi = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2xxx_dss_rfbi_hwmod,
+ .clk = "dss_ick",
+ .addr = omap2_dss_rfbi_addrs,
+ .fw = {
+ .omap2 = {
+ .l4_fw_region = OMAP2420_L4_CORE_FW_DSS_CORE_REGION,
+ .flags = OMAP_FIREWALL_L4,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> dss_venc */
+struct omap_hwmod_ocp_if omap2xxx_l4_core__dss_venc = {
+ .master = &omap2xxx_l4_core_hwmod,
+ .slave = &omap2xxx_dss_venc_hwmod,
+ .clk = "dss_ick",
+ .addr = omap2_dss_venc_addrs,
+ .fw = {
+ .omap2 = {
+ .l4_fw_region = OMAP2420_L4_CORE_FW_DSS_VENC_REGION,
+ .flags = OMAP_FIREWALL_L4,
+ }
+ },
+ .flags = OCPIF_SWSUP_IDLE,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
diff --git a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
index 2a6729741b06..83eafd96ecaa 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
@@ -10,6 +10,7 @@
*/
#include <plat/omap_hwmod.h>
#include <plat/serial.h>
+#include <plat/gpio.h>
#include <plat/dma.h>
#include <plat/dmtimer.h>
#include <plat/mcspi.h>
@@ -17,6 +18,8 @@
#include <mach/irqs.h>
#include "omap_hwmod_common_data.h"
+#include "cm-regbits-24xx.h"
+#include "prm-regbits-24xx.h"
#include "wd_timer.h"
struct omap_hwmod_irq_info omap2xxx_timer12_mpu_irqs[] = {
@@ -86,7 +89,8 @@ static struct omap_hwmod_class_sysconfig omap2xxx_wd_timer_sysc = {
struct omap_hwmod_class omap2xxx_wd_timer_hwmod_class = {
.name = "wd_timer",
.sysc = &omap2xxx_wd_timer_sysc,
- .pre_shutdown = &omap2_wd_timer_disable
+ .pre_shutdown = &omap2_wd_timer_disable,
+ .reset = &omap2_wd_timer_reset,
};
/*
@@ -170,3 +174,582 @@ struct omap_hwmod_class omap2xxx_mcspi_class = {
.sysc = &omap2xxx_mcspi_sysc,
.rev = OMAP2_MCSPI_REV,
};
+
+/*
+ * IP blocks
+ */
+
+/* L3 */
+struct omap_hwmod omap2xxx_l3_main_hwmod = {
+ .name = "l3_main",
+ .class = &l3_hwmod_class,
+ .flags = HWMOD_NO_IDLEST,
+};
+
+/* L4 CORE */
+struct omap_hwmod omap2xxx_l4_core_hwmod = {
+ .name = "l4_core",
+ .class = &l4_hwmod_class,
+ .flags = HWMOD_NO_IDLEST,
+};
+
+/* L4 WKUP */
+struct omap_hwmod omap2xxx_l4_wkup_hwmod = {
+ .name = "l4_wkup",
+ .class = &l4_hwmod_class,
+ .flags = HWMOD_NO_IDLEST,
+};
+
+/* MPU */
+struct omap_hwmod omap2xxx_mpu_hwmod = {
+ .name = "mpu",
+ .class = &mpu_hwmod_class,
+ .main_clk = "mpu_ck",
+};
+
+/* IVA2 */
+struct omap_hwmod omap2xxx_iva_hwmod = {
+ .name = "iva",
+ .class = &iva_hwmod_class,
+};
+
+/* always-on timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
+ .timer_capability = OMAP_TIMER_ALWON,
+};
+
+/* pwm timers dev attribute */
+static struct omap_timer_capability_dev_attr capability_pwm_dev_attr = {
+ .timer_capability = OMAP_TIMER_HAS_PWM,
+};
+
+/* timer1 */
+
+struct omap_hwmod omap2xxx_timer1_hwmod = {
+ .name = "timer1",
+ .mpu_irqs = omap2_timer1_mpu_irqs,
+ .main_clk = "gpt1_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT1_SHIFT,
+ .module_offs = WKUP_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT1_SHIFT,
+ },
+ },
+ .dev_attr = &capability_alwon_dev_attr,
+ .class = &omap2xxx_timer_hwmod_class,
+};
+
+/* timer2 */
+
+struct omap_hwmod omap2xxx_timer2_hwmod = {
+ .name = "timer2",
+ .mpu_irqs = omap2_timer2_mpu_irqs,
+ .main_clk = "gpt2_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT2_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT2_SHIFT,
+ },
+ },
+ .dev_attr = &capability_alwon_dev_attr,
+ .class = &omap2xxx_timer_hwmod_class,
+};
+
+/* timer3 */
+
+struct omap_hwmod omap2xxx_timer3_hwmod = {
+ .name = "timer3",
+ .mpu_irqs = omap2_timer3_mpu_irqs,
+ .main_clk = "gpt3_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT3_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT3_SHIFT,
+ },
+ },
+ .dev_attr = &capability_alwon_dev_attr,
+ .class = &omap2xxx_timer_hwmod_class,
+};
+
+/* timer4 */
+
+struct omap_hwmod omap2xxx_timer4_hwmod = {
+ .name = "timer4",
+ .mpu_irqs = omap2_timer4_mpu_irqs,
+ .main_clk = "gpt4_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT4_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT4_SHIFT,
+ },
+ },
+ .dev_attr = &capability_alwon_dev_attr,
+ .class = &omap2xxx_timer_hwmod_class,
+};
+
+/* timer5 */
+
+struct omap_hwmod omap2xxx_timer5_hwmod = {
+ .name = "timer5",
+ .mpu_irqs = omap2_timer5_mpu_irqs,
+ .main_clk = "gpt5_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT5_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT5_SHIFT,
+ },
+ },
+ .dev_attr = &capability_alwon_dev_attr,
+ .class = &omap2xxx_timer_hwmod_class,
+};
+
+/* timer6 */
+
+struct omap_hwmod omap2xxx_timer6_hwmod = {
+ .name = "timer6",
+ .mpu_irqs = omap2_timer6_mpu_irqs,
+ .main_clk = "gpt6_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT6_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT6_SHIFT,
+ },
+ },
+ .dev_attr = &capability_alwon_dev_attr,
+ .class = &omap2xxx_timer_hwmod_class,
+};
+
+/* timer7 */
+
+struct omap_hwmod omap2xxx_timer7_hwmod = {
+ .name = "timer7",
+ .mpu_irqs = omap2_timer7_mpu_irqs,
+ .main_clk = "gpt7_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT7_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT7_SHIFT,
+ },
+ },
+ .dev_attr = &capability_alwon_dev_attr,
+ .class = &omap2xxx_timer_hwmod_class,
+};
+
+/* timer8 */
+
+struct omap_hwmod omap2xxx_timer8_hwmod = {
+ .name = "timer8",
+ .mpu_irqs = omap2_timer8_mpu_irqs,
+ .main_clk = "gpt8_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT8_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT8_SHIFT,
+ },
+ },
+ .dev_attr = &capability_alwon_dev_attr,
+ .class = &omap2xxx_timer_hwmod_class,
+};
+
+/* timer9 */
+
+struct omap_hwmod omap2xxx_timer9_hwmod = {
+ .name = "timer9",
+ .mpu_irqs = omap2_timer9_mpu_irqs,
+ .main_clk = "gpt9_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT9_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT9_SHIFT,
+ },
+ },
+ .dev_attr = &capability_pwm_dev_attr,
+ .class = &omap2xxx_timer_hwmod_class,
+};
+
+/* timer10 */
+
+struct omap_hwmod omap2xxx_timer10_hwmod = {
+ .name = "timer10",
+ .mpu_irqs = omap2_timer10_mpu_irqs,
+ .main_clk = "gpt10_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT10_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT10_SHIFT,
+ },
+ },
+ .dev_attr = &capability_pwm_dev_attr,
+ .class = &omap2xxx_timer_hwmod_class,
+};
+
+/* timer11 */
+
+struct omap_hwmod omap2xxx_timer11_hwmod = {
+ .name = "timer11",
+ .mpu_irqs = omap2_timer11_mpu_irqs,
+ .main_clk = "gpt11_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT11_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT11_SHIFT,
+ },
+ },
+ .dev_attr = &capability_pwm_dev_attr,
+ .class = &omap2xxx_timer_hwmod_class,
+};
+
+/* timer12 */
+
+struct omap_hwmod omap2xxx_timer12_hwmod = {
+ .name = "timer12",
+ .mpu_irqs = omap2xxx_timer12_mpu_irqs,
+ .main_clk = "gpt12_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPT12_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPT12_SHIFT,
+ },
+ },
+ .dev_attr = &capability_pwm_dev_attr,
+ .class = &omap2xxx_timer_hwmod_class,
+};
+
+/* wd_timer2 */
+struct omap_hwmod omap2xxx_wd_timer2_hwmod = {
+ .name = "wd_timer2",
+ .class = &omap2xxx_wd_timer_hwmod_class,
+ .main_clk = "mpu_wdt_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_MPU_WDT_SHIFT,
+ .module_offs = WKUP_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_MPU_WDT_SHIFT,
+ },
+ },
+};
+
+/* UART1 */
+
+struct omap_hwmod omap2xxx_uart1_hwmod = {
+ .name = "uart1",
+ .mpu_irqs = omap2_uart1_mpu_irqs,
+ .sdma_reqs = omap2_uart1_sdma_reqs,
+ .main_clk = "uart1_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_UART1_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_EN_UART1_SHIFT,
+ },
+ },
+ .class = &omap2_uart_class,
+};
+
+/* UART2 */
+
+struct omap_hwmod omap2xxx_uart2_hwmod = {
+ .name = "uart2",
+ .mpu_irqs = omap2_uart2_mpu_irqs,
+ .sdma_reqs = omap2_uart2_sdma_reqs,
+ .main_clk = "uart2_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_UART2_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_EN_UART2_SHIFT,
+ },
+ },
+ .class = &omap2_uart_class,
+};
+
+/* UART3 */
+
+struct omap_hwmod omap2xxx_uart3_hwmod = {
+ .name = "uart3",
+ .mpu_irqs = omap2_uart3_mpu_irqs,
+ .sdma_reqs = omap2_uart3_sdma_reqs,
+ .main_clk = "uart3_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 2,
+ .module_bit = OMAP24XX_EN_UART3_SHIFT,
+ .idlest_reg_id = 2,
+ .idlest_idle_bit = OMAP24XX_EN_UART3_SHIFT,
+ },
+ },
+ .class = &omap2_uart_class,
+};
+
+/* dss */
+
+static struct omap_hwmod_opt_clk dss_opt_clks[] = {
+ /*
+ * The DSS HW needs all DSS clocks enabled during reset. The dss_core
+ * driver does not use these clocks.
+ */
+ { .role = "tv_clk", .clk = "dss_54m_fck" },
+ { .role = "sys_clk", .clk = "dss2_fck" },
+};
+
+struct omap_hwmod omap2xxx_dss_core_hwmod = {
+ .name = "dss_core",
+ .class = &omap2_dss_hwmod_class,
+ .main_clk = "dss1_fck", /* instead of dss_fck */
+ .sdma_reqs = omap2xxx_dss_sdma_chs,
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_DSS1_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_stdby_bit = OMAP24XX_ST_DSS_SHIFT,
+ },
+ },
+ .opt_clks = dss_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(dss_opt_clks),
+ .flags = HWMOD_NO_IDLEST | HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+};
+
+struct omap_hwmod omap2xxx_dss_dispc_hwmod = {
+ .name = "dss_dispc",
+ .class = &omap2_dispc_hwmod_class,
+ .mpu_irqs = omap2_dispc_irqs,
+ .main_clk = "dss1_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_DSS1_SHIFT,
+ .module_offs = CORE_MOD,
+ .idlest_reg_id = 1,
+ .idlest_stdby_bit = OMAP24XX_ST_DSS_SHIFT,
+ },
+ },
+ .flags = HWMOD_NO_IDLEST,
+ .dev_attr = &omap2_3_dss_dispc_dev_attr
+};
+
+static struct omap_hwmod_opt_clk dss_rfbi_opt_clks[] = {
+ { .role = "ick", .clk = "dss_ick" },
+};
+
+struct omap_hwmod omap2xxx_dss_rfbi_hwmod = {
+ .name = "dss_rfbi",
+ .class = &omap2_rfbi_hwmod_class,
+ .main_clk = "dss1_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_DSS1_SHIFT,
+ .module_offs = CORE_MOD,
+ },
+ },
+ .opt_clks = dss_rfbi_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(dss_rfbi_opt_clks),
+ .flags = HWMOD_NO_IDLEST,
+};
+
+struct omap_hwmod omap2xxx_dss_venc_hwmod = {
+ .name = "dss_venc",
+ .class = &omap2_venc_hwmod_class,
+ .main_clk = "dss_54m_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_DSS1_SHIFT,
+ .module_offs = CORE_MOD,
+ },
+ },
+ .flags = HWMOD_NO_IDLEST,
+};
+
+/* gpio dev_attr */
+struct omap_gpio_dev_attr omap2xxx_gpio_dev_attr = {
+ .bank_width = 32,
+ .dbck_flag = false,
+};
+
+/* gpio1 */
+struct omap_hwmod omap2xxx_gpio1_hwmod = {
+ .name = "gpio1",
+ .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+ .mpu_irqs = omap2_gpio1_irqs,
+ .main_clk = "gpios_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPIOS_SHIFT,
+ .module_offs = WKUP_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPIOS_SHIFT,
+ },
+ },
+ .class = &omap2xxx_gpio_hwmod_class,
+ .dev_attr = &omap2xxx_gpio_dev_attr,
+};
+
+/* gpio2 */
+struct omap_hwmod omap2xxx_gpio2_hwmod = {
+ .name = "gpio2",
+ .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+ .mpu_irqs = omap2_gpio2_irqs,
+ .main_clk = "gpios_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPIOS_SHIFT,
+ .module_offs = WKUP_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPIOS_SHIFT,
+ },
+ },
+ .class = &omap2xxx_gpio_hwmod_class,
+ .dev_attr = &omap2xxx_gpio_dev_attr,
+};
+
+/* gpio3 */
+struct omap_hwmod omap2xxx_gpio3_hwmod = {
+ .name = "gpio3",
+ .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+ .mpu_irqs = omap2_gpio3_irqs,
+ .main_clk = "gpios_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPIOS_SHIFT,
+ .module_offs = WKUP_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPIOS_SHIFT,
+ },
+ },
+ .class = &omap2xxx_gpio_hwmod_class,
+ .dev_attr = &omap2xxx_gpio_dev_attr,
+};
+
+/* gpio4 */
+struct omap_hwmod omap2xxx_gpio4_hwmod = {
+ .name = "gpio4",
+ .flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+ .mpu_irqs = omap2_gpio4_irqs,
+ .main_clk = "gpios_fck",
+ .prcm = {
+ .omap2 = {
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_GPIOS_SHIFT,
+ .module_offs = WKUP_MOD,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_GPIOS_SHIFT,
+ },
+ },
+ .class = &omap2xxx_gpio_hwmod_class,
+ .dev_attr = &omap2xxx_gpio_dev_attr,
+};
+
+/* mcspi1 */
+static struct omap2_mcspi_dev_attr omap_mcspi1_dev_attr = {
+ .num_chipselect = 4,
+};
+
+struct omap_hwmod omap2xxx_mcspi1_hwmod = {
+ .name = "mcspi1",
+ .mpu_irqs = omap2_mcspi1_mpu_irqs,
+ .sdma_reqs = omap2_mcspi1_sdma_reqs,
+ .main_clk = "mcspi1_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_MCSPI1_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_MCSPI1_SHIFT,
+ },
+ },
+ .class = &omap2xxx_mcspi_class,
+ .dev_attr = &omap_mcspi1_dev_attr,
+};
+
+/* mcspi2 */
+static struct omap2_mcspi_dev_attr omap_mcspi2_dev_attr = {
+ .num_chipselect = 2,
+};
+
+struct omap_hwmod omap2xxx_mcspi2_hwmod = {
+ .name = "mcspi2",
+ .mpu_irqs = omap2_mcspi2_mpu_irqs,
+ .sdma_reqs = omap2_mcspi2_sdma_reqs,
+ .main_clk = "mcspi2_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_EN_MCSPI2_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_MCSPI2_SHIFT,
+ },
+ },
+ .class = &omap2xxx_mcspi_class,
+ .dev_attr = &omap_mcspi2_dev_attr,
+};
+
+
+static struct omap_hwmod_class omap2xxx_counter_hwmod_class = {
+ .name = "counter",
+};
+
+struct omap_hwmod omap2xxx_counter_32k_hwmod = {
+ .name = "counter_32k",
+ .main_clk = "func_32k_ck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = WKUP_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP24XX_ST_32KSYNC_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP24XX_ST_32KSYNC_SHIFT,
+ },
+ },
+ .class = &omap2xxx_counter_hwmod_class,
+};
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index db86ce90c69f..fd48797fa95a 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -2,6 +2,7 @@
* omap_hwmod_3xxx_data.c - hardware modules present on the OMAP3xxx chips
*
* Copyright (C) 2009-2011 Nokia Corporation
+ * Copyright (C) 2012 Texas Instruments, Inc.
* Paul Walmsley
*
* This program is free software; you can redistribute it and/or modify
@@ -38,491 +39,56 @@
/*
* OMAP3xxx hardware module integration data
*
- * ALl of the data in this section should be autogeneratable from the
+ * All of the data in this section should be autogeneratable from the
* TI hardware database or other technical documentation. Data that
* is driver-specific or driver-kernel integration-specific belongs
* elsewhere.
*/
-static struct omap_hwmod omap3xxx_mpu_hwmod;
-static struct omap_hwmod omap3xxx_iva_hwmod;
-static struct omap_hwmod omap3xxx_l3_main_hwmod;
-static struct omap_hwmod omap3xxx_l4_core_hwmod;
-static struct omap_hwmod omap3xxx_l4_per_hwmod;
-static struct omap_hwmod omap3xxx_wd_timer2_hwmod;
-static struct omap_hwmod omap3430es1_dss_core_hwmod;
-static struct omap_hwmod omap3xxx_dss_core_hwmod;
-static struct omap_hwmod omap3xxx_dss_dispc_hwmod;
-static struct omap_hwmod omap3xxx_dss_dsi1_hwmod;
-static struct omap_hwmod omap3xxx_dss_rfbi_hwmod;
-static struct omap_hwmod omap3xxx_dss_venc_hwmod;
-static struct omap_hwmod omap3xxx_i2c1_hwmod;
-static struct omap_hwmod omap3xxx_i2c2_hwmod;
-static struct omap_hwmod omap3xxx_i2c3_hwmod;
-static struct omap_hwmod omap3xxx_gpio1_hwmod;
-static struct omap_hwmod omap3xxx_gpio2_hwmod;
-static struct omap_hwmod omap3xxx_gpio3_hwmod;
-static struct omap_hwmod omap3xxx_gpio4_hwmod;
-static struct omap_hwmod omap3xxx_gpio5_hwmod;
-static struct omap_hwmod omap3xxx_gpio6_hwmod;
-static struct omap_hwmod omap34xx_sr1_hwmod;
-static struct omap_hwmod omap34xx_sr2_hwmod;
-static struct omap_hwmod omap34xx_mcspi1;
-static struct omap_hwmod omap34xx_mcspi2;
-static struct omap_hwmod omap34xx_mcspi3;
-static struct omap_hwmod omap34xx_mcspi4;
-static struct omap_hwmod omap3xxx_mmc1_hwmod;
-static struct omap_hwmod omap3xxx_mmc2_hwmod;
-static struct omap_hwmod omap3xxx_mmc3_hwmod;
-static struct omap_hwmod am35xx_usbhsotg_hwmod;
-
-static struct omap_hwmod omap3xxx_dma_system_hwmod;
-
-static struct omap_hwmod omap3xxx_mcbsp1_hwmod;
-static struct omap_hwmod omap3xxx_mcbsp2_hwmod;
-static struct omap_hwmod omap3xxx_mcbsp3_hwmod;
-static struct omap_hwmod omap3xxx_mcbsp4_hwmod;
-static struct omap_hwmod omap3xxx_mcbsp5_hwmod;
-static struct omap_hwmod omap3xxx_mcbsp2_sidetone_hwmod;
-static struct omap_hwmod omap3xxx_mcbsp3_sidetone_hwmod;
-static struct omap_hwmod omap3xxx_usb_host_hs_hwmod;
-static struct omap_hwmod omap3xxx_usb_tll_hs_hwmod;
-
-/* L3 -> L4_CORE interface */
-static struct omap_hwmod_ocp_if omap3xxx_l3_main__l4_core = {
- .master = &omap3xxx_l3_main_hwmod,
- .slave = &omap3xxx_l4_core_hwmod,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L3 -> L4_PER interface */
-static struct omap_hwmod_ocp_if omap3xxx_l3_main__l4_per = {
- .master = &omap3xxx_l3_main_hwmod,
- .slave = &omap3xxx_l4_per_hwmod,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
+/*
+ * IP blocks
+ */
-/* L3 taret configuration and error log registers */
+/* L3 */
static struct omap_hwmod_irq_info omap3xxx_l3_main_irqs[] = {
{ .irq = INT_34XX_L3_DBG_IRQ },
{ .irq = INT_34XX_L3_APP_IRQ },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap3xxx_l3_main_addrs[] = {
- {
- .pa_start = 0x68000000,
- .pa_end = 0x6800ffff,
- .flags = ADDR_TYPE_RT,
- },
- { }
-};
-
-/* MPU -> L3 interface */
-static struct omap_hwmod_ocp_if omap3xxx_mpu__l3_main = {
- .master = &omap3xxx_mpu_hwmod,
- .slave = &omap3xxx_l3_main_hwmod,
- .addr = omap3xxx_l3_main_addrs,
- .user = OCP_USER_MPU,
-};
-
-/* Slave interfaces on the L3 interconnect */
-static struct omap_hwmod_ocp_if *omap3xxx_l3_main_slaves[] = {
- &omap3xxx_mpu__l3_main,
-};
-
-/* DSS -> l3 */
-static struct omap_hwmod_ocp_if omap3xxx_dss__l3 = {
- .master = &omap3xxx_dss_core_hwmod,
- .slave = &omap3xxx_l3_main_hwmod,
- .fw = {
- .omap2 = {
- .l3_perm_bit = OMAP3_L3_CORE_FW_INIT_ID_DSS,
- .flags = OMAP_FIREWALL_L3,
- }
- },
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* Master interfaces on the L3 interconnect */
-static struct omap_hwmod_ocp_if *omap3xxx_l3_main_masters[] = {
- &omap3xxx_l3_main__l4_core,
- &omap3xxx_l3_main__l4_per,
-};
-
-/* L3 */
static struct omap_hwmod omap3xxx_l3_main_hwmod = {
.name = "l3_main",
.class = &l3_hwmod_class,
.mpu_irqs = omap3xxx_l3_main_irqs,
- .masters = omap3xxx_l3_main_masters,
- .masters_cnt = ARRAY_SIZE(omap3xxx_l3_main_masters),
- .slaves = omap3xxx_l3_main_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_l3_main_slaves),
.flags = HWMOD_NO_IDLEST,
};
-static struct omap_hwmod omap3xxx_l4_wkup_hwmod;
-static struct omap_hwmod omap3xxx_uart1_hwmod;
-static struct omap_hwmod omap3xxx_uart2_hwmod;
-static struct omap_hwmod omap3xxx_uart3_hwmod;
-static struct omap_hwmod omap3xxx_uart4_hwmod;
-static struct omap_hwmod am35xx_uart4_hwmod;
-static struct omap_hwmod omap3xxx_usbhsotg_hwmod;
-
-/* l3_core -> usbhsotg interface */
-static struct omap_hwmod_ocp_if omap3xxx_usbhsotg__l3 = {
- .master = &omap3xxx_usbhsotg_hwmod,
- .slave = &omap3xxx_l3_main_hwmod,
- .clk = "core_l3_ick",
- .user = OCP_USER_MPU,
-};
-
-/* l3_core -> am35xx_usbhsotg interface */
-static struct omap_hwmod_ocp_if am35xx_usbhsotg__l3 = {
- .master = &am35xx_usbhsotg_hwmod,
- .slave = &omap3xxx_l3_main_hwmod,
- .clk = "core_l3_ick",
- .user = OCP_USER_MPU,
-};
-/* L4_CORE -> L4_WKUP interface */
-static struct omap_hwmod_ocp_if omap3xxx_l4_core__l4_wkup = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_l4_wkup_hwmod,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 CORE -> MMC1 interface */
-static struct omap_hwmod_ocp_if omap3xxx_l4_core__mmc1 = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_mmc1_hwmod,
- .clk = "mmchs1_ick",
- .addr = omap2430_mmc1_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
- .flags = OMAP_FIREWALL_L4
-};
-
-/* L4 CORE -> MMC2 interface */
-static struct omap_hwmod_ocp_if omap3xxx_l4_core__mmc2 = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_mmc2_hwmod,
- .clk = "mmchs2_ick",
- .addr = omap2430_mmc2_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
- .flags = OMAP_FIREWALL_L4
-};
-
-/* L4 CORE -> MMC3 interface */
-static struct omap_hwmod_addr_space omap3xxx_mmc3_addr_space[] = {
- {
- .pa_start = 0x480ad000,
- .pa_end = 0x480ad1ff,
- .flags = ADDR_TYPE_RT,
- },
- { }
-};
-
-static struct omap_hwmod_ocp_if omap3xxx_l4_core__mmc3 = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_mmc3_hwmod,
- .clk = "mmchs3_ick",
- .addr = omap3xxx_mmc3_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
- .flags = OMAP_FIREWALL_L4
-};
-
-/* L4 CORE -> UART1 interface */
-static struct omap_hwmod_addr_space omap3xxx_uart1_addr_space[] = {
- {
- .pa_start = OMAP3_UART1_BASE,
- .pa_end = OMAP3_UART1_BASE + SZ_8K - 1,
- .flags = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
- },
- { }
-};
-
-static struct omap_hwmod_ocp_if omap3_l4_core__uart1 = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_uart1_hwmod,
- .clk = "uart1_ick",
- .addr = omap3xxx_uart1_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 CORE -> UART2 interface */
-static struct omap_hwmod_addr_space omap3xxx_uart2_addr_space[] = {
- {
- .pa_start = OMAP3_UART2_BASE,
- .pa_end = OMAP3_UART2_BASE + SZ_1K - 1,
- .flags = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
- },
- { }
-};
-
-static struct omap_hwmod_ocp_if omap3_l4_core__uart2 = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_uart2_hwmod,
- .clk = "uart2_ick",
- .addr = omap3xxx_uart2_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 PER -> UART3 interface */
-static struct omap_hwmod_addr_space omap3xxx_uart3_addr_space[] = {
- {
- .pa_start = OMAP3_UART3_BASE,
- .pa_end = OMAP3_UART3_BASE + SZ_1K - 1,
- .flags = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
- },
- { }
-};
-
-static struct omap_hwmod_ocp_if omap3_l4_per__uart3 = {
- .master = &omap3xxx_l4_per_hwmod,
- .slave = &omap3xxx_uart3_hwmod,
- .clk = "uart3_ick",
- .addr = omap3xxx_uart3_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 PER -> UART4 interface */
-static struct omap_hwmod_addr_space omap3xxx_uart4_addr_space[] = {
- {
- .pa_start = OMAP3_UART4_BASE,
- .pa_end = OMAP3_UART4_BASE + SZ_1K - 1,
- .flags = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
- },
- { }
-};
-
-static struct omap_hwmod_ocp_if omap3_l4_per__uart4 = {
- .master = &omap3xxx_l4_per_hwmod,
- .slave = &omap3xxx_uart4_hwmod,
- .clk = "uart4_ick",
- .addr = omap3xxx_uart4_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* AM35xx: L4 CORE -> UART4 interface */
-static struct omap_hwmod_addr_space am35xx_uart4_addr_space[] = {
- {
- .pa_start = OMAP3_UART4_AM35XX_BASE,
- .pa_end = OMAP3_UART4_AM35XX_BASE + SZ_1K - 1,
- .flags = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
- },
-};
-
-static struct omap_hwmod_ocp_if am35xx_l4_core__uart4 = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &am35xx_uart4_hwmod,
- .clk = "uart4_ick",
- .addr = am35xx_uart4_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 CORE -> I2C1 interface */
-static struct omap_hwmod_ocp_if omap3_l4_core__i2c1 = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_i2c1_hwmod,
- .clk = "i2c1_ick",
- .addr = omap2_i2c1_addr_space,
- .fw = {
- .omap2 = {
- .l4_fw_region = OMAP3_L4_CORE_FW_I2C1_REGION,
- .l4_prot_group = 7,
- .flags = OMAP_FIREWALL_L4,
- }
- },
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 CORE -> I2C2 interface */
-static struct omap_hwmod_ocp_if omap3_l4_core__i2c2 = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_i2c2_hwmod,
- .clk = "i2c2_ick",
- .addr = omap2_i2c2_addr_space,
- .fw = {
- .omap2 = {
- .l4_fw_region = OMAP3_L4_CORE_FW_I2C2_REGION,
- .l4_prot_group = 7,
- .flags = OMAP_FIREWALL_L4,
- }
- },
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* L4 CORE -> I2C3 interface */
-static struct omap_hwmod_addr_space omap3xxx_i2c3_addr_space[] = {
- {
- .pa_start = 0x48060000,
- .pa_end = 0x48060000 + SZ_128 - 1,
- .flags = ADDR_TYPE_RT,
- },
- { }
-};
-
-static struct omap_hwmod_ocp_if omap3_l4_core__i2c3 = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_i2c3_hwmod,
- .clk = "i2c3_ick",
- .addr = omap3xxx_i2c3_addr_space,
- .fw = {
- .omap2 = {
- .l4_fw_region = OMAP3_L4_CORE_FW_I2C3_REGION,
- .l4_prot_group = 7,
- .flags = OMAP_FIREWALL_L4,
- }
- },
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-static struct omap_hwmod_irq_info omap3_smartreflex_mpu_irqs[] = {
- { .irq = 18},
- { .irq = -1 }
-};
-
-static struct omap_hwmod_irq_info omap3_smartreflex_core_irqs[] = {
- { .irq = 19},
- { .irq = -1 }
-};
-
-/* L4 CORE -> SR1 interface */
-static struct omap_hwmod_addr_space omap3_sr1_addr_space[] = {
- {
- .pa_start = OMAP34XX_SR1_BASE,
- .pa_end = OMAP34XX_SR1_BASE + SZ_1K - 1,
- .flags = ADDR_TYPE_RT,
- },
- { }
-};
-
-static struct omap_hwmod_ocp_if omap3_l4_core__sr1 = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap34xx_sr1_hwmod,
- .clk = "sr_l4_ick",
- .addr = omap3_sr1_addr_space,
- .user = OCP_USER_MPU,
-};
-
-/* L4 CORE -> SR1 interface */
-static struct omap_hwmod_addr_space omap3_sr2_addr_space[] = {
- {
- .pa_start = OMAP34XX_SR2_BASE,
- .pa_end = OMAP34XX_SR2_BASE + SZ_1K - 1,
- .flags = ADDR_TYPE_RT,
- },
- { }
-};
-
-static struct omap_hwmod_ocp_if omap3_l4_core__sr2 = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap34xx_sr2_hwmod,
- .clk = "sr_l4_ick",
- .addr = omap3_sr2_addr_space,
- .user = OCP_USER_MPU,
-};
-
-/*
-* usbhsotg interface data
-*/
-
-static struct omap_hwmod_addr_space omap3xxx_usbhsotg_addrs[] = {
- {
- .pa_start = OMAP34XX_HSUSB_OTG_BASE,
- .pa_end = OMAP34XX_HSUSB_OTG_BASE + SZ_4K - 1,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_core -> usbhsotg */
-static struct omap_hwmod_ocp_if omap3xxx_l4_core__usbhsotg = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_usbhsotg_hwmod,
- .clk = "l4_ick",
- .addr = omap3xxx_usbhsotg_addrs,
- .user = OCP_USER_MPU,
-};
-
-static struct omap_hwmod_ocp_if *omap3xxx_usbhsotg_masters[] = {
- &omap3xxx_usbhsotg__l3,
-};
-
-static struct omap_hwmod_ocp_if *omap3xxx_usbhsotg_slaves[] = {
- &omap3xxx_l4_core__usbhsotg,
-};
-
-static struct omap_hwmod_addr_space am35xx_usbhsotg_addrs[] = {
- {
- .pa_start = AM35XX_IPSS_USBOTGSS_BASE,
- .pa_end = AM35XX_IPSS_USBOTGSS_BASE + SZ_4K - 1,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_core -> usbhsotg */
-static struct omap_hwmod_ocp_if am35xx_l4_core__usbhsotg = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &am35xx_usbhsotg_hwmod,
- .clk = "l4_ick",
- .addr = am35xx_usbhsotg_addrs,
- .user = OCP_USER_MPU,
-};
-
-static struct omap_hwmod_ocp_if *am35xx_usbhsotg_masters[] = {
- &am35xx_usbhsotg__l3,
-};
-
-static struct omap_hwmod_ocp_if *am35xx_usbhsotg_slaves[] = {
- &am35xx_l4_core__usbhsotg,
-};
-/* Slave interfaces on the L4_CORE interconnect */
-static struct omap_hwmod_ocp_if *omap3xxx_l4_core_slaves[] = {
- &omap3xxx_l3_main__l4_core,
-};
-
/* L4 CORE */
static struct omap_hwmod omap3xxx_l4_core_hwmod = {
.name = "l4_core",
.class = &l4_hwmod_class,
- .slaves = omap3xxx_l4_core_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_l4_core_slaves),
.flags = HWMOD_NO_IDLEST,
};
-/* Slave interfaces on the L4_PER interconnect */
-static struct omap_hwmod_ocp_if *omap3xxx_l4_per_slaves[] = {
- &omap3xxx_l3_main__l4_per,
-};
-
/* L4 PER */
static struct omap_hwmod omap3xxx_l4_per_hwmod = {
.name = "l4_per",
.class = &l4_hwmod_class,
- .slaves = omap3xxx_l4_per_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_l4_per_slaves),
.flags = HWMOD_NO_IDLEST,
};
-/* Slave interfaces on the L4_WKUP interconnect */
-static struct omap_hwmod_ocp_if *omap3xxx_l4_wkup_slaves[] = {
- &omap3xxx_l4_core__l4_wkup,
-};
-
/* L4 WKUP */
static struct omap_hwmod omap3xxx_l4_wkup_hwmod = {
.name = "l4_wkup",
.class = &l4_hwmod_class,
- .slaves = omap3xxx_l4_wkup_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_l4_wkup_slaves),
.flags = HWMOD_NO_IDLEST,
};
-/* Master interfaces on the MPU device */
-static struct omap_hwmod_ocp_if *omap3xxx_mpu_masters[] = {
- &omap3xxx_mpu__l3_main,
+/* L4 SEC */
+static struct omap_hwmod omap3xxx_l4_sec_hwmod = {
+ .name = "l4_sec",
+ .class = &l4_hwmod_class,
+ .flags = HWMOD_NO_IDLEST,
};
/* MPU */
@@ -530,35 +96,22 @@ static struct omap_hwmod omap3xxx_mpu_hwmod = {
.name = "mpu",
.class = &mpu_hwmod_class,
.main_clk = "arm_fck",
- .masters = omap3xxx_mpu_masters,
- .masters_cnt = ARRAY_SIZE(omap3xxx_mpu_masters),
};
-/*
- * IVA2_2 interface data
- */
-
-/* IVA2 <- L3 interface */
-static struct omap_hwmod_ocp_if omap3xxx_l3__iva = {
- .master = &omap3xxx_l3_main_hwmod,
- .slave = &omap3xxx_iva_hwmod,
- .clk = "iva2_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
+/* IVA2 (IVA2) */
+static struct omap_hwmod_rst_info omap3xxx_iva_resets[] = {
+ { .name = "logic", .rst_shift = 0 },
+ { .name = "seq0", .rst_shift = 1 },
+ { .name = "seq1", .rst_shift = 2 },
};
-static struct omap_hwmod_ocp_if *omap3xxx_iva_masters[] = {
- &omap3xxx_l3__iva,
-};
-
-/*
- * IVA2 (IVA2)
- */
-
static struct omap_hwmod omap3xxx_iva_hwmod = {
.name = "iva",
.class = &iva_hwmod_class,
- .masters = omap3xxx_iva_masters,
- .masters_cnt = ARRAY_SIZE(omap3xxx_iva_masters),
+ .clkdm_name = "iva2_clkdm",
+ .rst_lines = omap3xxx_iva_resets,
+ .rst_lines_cnt = ARRAY_SIZE(omap3xxx_iva_resets),
+ .main_clk = "iva2_ck",
};
/* timer class */
@@ -597,46 +150,20 @@ static struct omap_hwmod_class omap3xxx_timer_hwmod_class = {
/* secure timers dev attribute */
static struct omap_timer_capability_dev_attr capability_secure_dev_attr = {
- .timer_capability = OMAP_TIMER_SECURE,
+ .timer_capability = OMAP_TIMER_SECURE,
};
/* always-on timers dev attribute */
static struct omap_timer_capability_dev_attr capability_alwon_dev_attr = {
- .timer_capability = OMAP_TIMER_ALWON,
+ .timer_capability = OMAP_TIMER_ALWON,
};
/* pwm timers dev attribute */
static struct omap_timer_capability_dev_attr capability_pwm_dev_attr = {
- .timer_capability = OMAP_TIMER_HAS_PWM,
+ .timer_capability = OMAP_TIMER_HAS_PWM,
};
/* timer1 */
-static struct omap_hwmod omap3xxx_timer1_hwmod;
-
-static struct omap_hwmod_addr_space omap3xxx_timer1_addrs[] = {
- {
- .pa_start = 0x48318000,
- .pa_end = 0x48318000 + SZ_1K - 1,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_wkup -> timer1 */
-static struct omap_hwmod_ocp_if omap3xxx_l4_wkup__timer1 = {
- .master = &omap3xxx_l4_wkup_hwmod,
- .slave = &omap3xxx_timer1_hwmod,
- .clk = "gpt1_ick",
- .addr = omap3xxx_timer1_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer1 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer1_slaves[] = {
- &omap3xxx_l4_wkup__timer1,
-};
-
-/* timer1 hwmod */
static struct omap_hwmod omap3xxx_timer1_hwmod = {
.name = "timer1",
.mpu_irqs = omap2_timer1_mpu_irqs,
@@ -651,38 +178,10 @@ static struct omap_hwmod omap3xxx_timer1_hwmod = {
},
},
.dev_attr = &capability_alwon_dev_attr,
- .slaves = omap3xxx_timer1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_timer1_slaves),
.class = &omap3xxx_timer_1ms_hwmod_class,
};
/* timer2 */
-static struct omap_hwmod omap3xxx_timer2_hwmod;
-
-static struct omap_hwmod_addr_space omap3xxx_timer2_addrs[] = {
- {
- .pa_start = 0x49032000,
- .pa_end = 0x49032000 + SZ_1K - 1,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> timer2 */
-static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer2 = {
- .master = &omap3xxx_l4_per_hwmod,
- .slave = &omap3xxx_timer2_hwmod,
- .clk = "gpt2_ick",
- .addr = omap3xxx_timer2_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer2 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer2_slaves[] = {
- &omap3xxx_l4_per__timer2,
-};
-
-/* timer2 hwmod */
static struct omap_hwmod omap3xxx_timer2_hwmod = {
.name = "timer2",
.mpu_irqs = omap2_timer2_mpu_irqs,
@@ -697,38 +196,10 @@ static struct omap_hwmod omap3xxx_timer2_hwmod = {
},
},
.dev_attr = &capability_alwon_dev_attr,
- .slaves = omap3xxx_timer2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_timer2_slaves),
.class = &omap3xxx_timer_1ms_hwmod_class,
};
/* timer3 */
-static struct omap_hwmod omap3xxx_timer3_hwmod;
-
-static struct omap_hwmod_addr_space omap3xxx_timer3_addrs[] = {
- {
- .pa_start = 0x49034000,
- .pa_end = 0x49034000 + SZ_1K - 1,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> timer3 */
-static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer3 = {
- .master = &omap3xxx_l4_per_hwmod,
- .slave = &omap3xxx_timer3_hwmod,
- .clk = "gpt3_ick",
- .addr = omap3xxx_timer3_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer3 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer3_slaves[] = {
- &omap3xxx_l4_per__timer3,
-};
-
-/* timer3 hwmod */
static struct omap_hwmod omap3xxx_timer3_hwmod = {
.name = "timer3",
.mpu_irqs = omap2_timer3_mpu_irqs,
@@ -743,38 +214,10 @@ static struct omap_hwmod omap3xxx_timer3_hwmod = {
},
},
.dev_attr = &capability_alwon_dev_attr,
- .slaves = omap3xxx_timer3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_timer3_slaves),
.class = &omap3xxx_timer_hwmod_class,
};
/* timer4 */
-static struct omap_hwmod omap3xxx_timer4_hwmod;
-
-static struct omap_hwmod_addr_space omap3xxx_timer4_addrs[] = {
- {
- .pa_start = 0x49036000,
- .pa_end = 0x49036000 + SZ_1K - 1,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> timer4 */
-static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer4 = {
- .master = &omap3xxx_l4_per_hwmod,
- .slave = &omap3xxx_timer4_hwmod,
- .clk = "gpt4_ick",
- .addr = omap3xxx_timer4_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer4 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer4_slaves[] = {
- &omap3xxx_l4_per__timer4,
-};
-
-/* timer4 hwmod */
static struct omap_hwmod omap3xxx_timer4_hwmod = {
.name = "timer4",
.mpu_irqs = omap2_timer4_mpu_irqs,
@@ -789,38 +232,10 @@ static struct omap_hwmod omap3xxx_timer4_hwmod = {
},
},
.dev_attr = &capability_alwon_dev_attr,
- .slaves = omap3xxx_timer4_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_timer4_slaves),
.class = &omap3xxx_timer_hwmod_class,
};
/* timer5 */
-static struct omap_hwmod omap3xxx_timer5_hwmod;
-
-static struct omap_hwmod_addr_space omap3xxx_timer5_addrs[] = {
- {
- .pa_start = 0x49038000,
- .pa_end = 0x49038000 + SZ_1K - 1,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> timer5 */
-static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer5 = {
- .master = &omap3xxx_l4_per_hwmod,
- .slave = &omap3xxx_timer5_hwmod,
- .clk = "gpt5_ick",
- .addr = omap3xxx_timer5_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer5 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer5_slaves[] = {
- &omap3xxx_l4_per__timer5,
-};
-
-/* timer5 hwmod */
static struct omap_hwmod omap3xxx_timer5_hwmod = {
.name = "timer5",
.mpu_irqs = omap2_timer5_mpu_irqs,
@@ -835,38 +250,10 @@ static struct omap_hwmod omap3xxx_timer5_hwmod = {
},
},
.dev_attr = &capability_alwon_dev_attr,
- .slaves = omap3xxx_timer5_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_timer5_slaves),
.class = &omap3xxx_timer_hwmod_class,
};
/* timer6 */
-static struct omap_hwmod omap3xxx_timer6_hwmod;
-
-static struct omap_hwmod_addr_space omap3xxx_timer6_addrs[] = {
- {
- .pa_start = 0x4903A000,
- .pa_end = 0x4903A000 + SZ_1K - 1,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> timer6 */
-static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer6 = {
- .master = &omap3xxx_l4_per_hwmod,
- .slave = &omap3xxx_timer6_hwmod,
- .clk = "gpt6_ick",
- .addr = omap3xxx_timer6_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer6 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer6_slaves[] = {
- &omap3xxx_l4_per__timer6,
-};
-
-/* timer6 hwmod */
static struct omap_hwmod omap3xxx_timer6_hwmod = {
.name = "timer6",
.mpu_irqs = omap2_timer6_mpu_irqs,
@@ -881,38 +268,10 @@ static struct omap_hwmod omap3xxx_timer6_hwmod = {
},
},
.dev_attr = &capability_alwon_dev_attr,
- .slaves = omap3xxx_timer6_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_timer6_slaves),
.class = &omap3xxx_timer_hwmod_class,
};
/* timer7 */
-static struct omap_hwmod omap3xxx_timer7_hwmod;
-
-static struct omap_hwmod_addr_space omap3xxx_timer7_addrs[] = {
- {
- .pa_start = 0x4903C000,
- .pa_end = 0x4903C000 + SZ_1K - 1,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> timer7 */
-static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer7 = {
- .master = &omap3xxx_l4_per_hwmod,
- .slave = &omap3xxx_timer7_hwmod,
- .clk = "gpt7_ick",
- .addr = omap3xxx_timer7_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer7 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer7_slaves[] = {
- &omap3xxx_l4_per__timer7,
-};
-
-/* timer7 hwmod */
static struct omap_hwmod omap3xxx_timer7_hwmod = {
.name = "timer7",
.mpu_irqs = omap2_timer7_mpu_irqs,
@@ -927,38 +286,10 @@ static struct omap_hwmod omap3xxx_timer7_hwmod = {
},
},
.dev_attr = &capability_alwon_dev_attr,
- .slaves = omap3xxx_timer7_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_timer7_slaves),
.class = &omap3xxx_timer_hwmod_class,
};
/* timer8 */
-static struct omap_hwmod omap3xxx_timer8_hwmod;
-
-static struct omap_hwmod_addr_space omap3xxx_timer8_addrs[] = {
- {
- .pa_start = 0x4903E000,
- .pa_end = 0x4903E000 + SZ_1K - 1,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> timer8 */
-static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer8 = {
- .master = &omap3xxx_l4_per_hwmod,
- .slave = &omap3xxx_timer8_hwmod,
- .clk = "gpt8_ick",
- .addr = omap3xxx_timer8_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer8 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer8_slaves[] = {
- &omap3xxx_l4_per__timer8,
-};
-
-/* timer8 hwmod */
static struct omap_hwmod omap3xxx_timer8_hwmod = {
.name = "timer8",
.mpu_irqs = omap2_timer8_mpu_irqs,
@@ -973,38 +304,10 @@ static struct omap_hwmod omap3xxx_timer8_hwmod = {
},
},
.dev_attr = &capability_pwm_dev_attr,
- .slaves = omap3xxx_timer8_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_timer8_slaves),
.class = &omap3xxx_timer_hwmod_class,
};
/* timer9 */
-static struct omap_hwmod omap3xxx_timer9_hwmod;
-
-static struct omap_hwmod_addr_space omap3xxx_timer9_addrs[] = {
- {
- .pa_start = 0x49040000,
- .pa_end = 0x49040000 + SZ_1K - 1,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> timer9 */
-static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer9 = {
- .master = &omap3xxx_l4_per_hwmod,
- .slave = &omap3xxx_timer9_hwmod,
- .clk = "gpt9_ick",
- .addr = omap3xxx_timer9_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer9 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer9_slaves[] = {
- &omap3xxx_l4_per__timer9,
-};
-
-/* timer9 hwmod */
static struct omap_hwmod omap3xxx_timer9_hwmod = {
.name = "timer9",
.mpu_irqs = omap2_timer9_mpu_irqs,
@@ -1019,29 +322,10 @@ static struct omap_hwmod omap3xxx_timer9_hwmod = {
},
},
.dev_attr = &capability_pwm_dev_attr,
- .slaves = omap3xxx_timer9_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_timer9_slaves),
.class = &omap3xxx_timer_hwmod_class,
};
/* timer10 */
-static struct omap_hwmod omap3xxx_timer10_hwmod;
-
-/* l4_core -> timer10 */
-static struct omap_hwmod_ocp_if omap3xxx_l4_core__timer10 = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_timer10_hwmod,
- .clk = "gpt10_ick",
- .addr = omap2_timer10_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer10 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer10_slaves[] = {
- &omap3xxx_l4_core__timer10,
-};
-
-/* timer10 hwmod */
static struct omap_hwmod omap3xxx_timer10_hwmod = {
.name = "timer10",
.mpu_irqs = omap2_timer10_mpu_irqs,
@@ -1056,29 +340,10 @@ static struct omap_hwmod omap3xxx_timer10_hwmod = {
},
},
.dev_attr = &capability_pwm_dev_attr,
- .slaves = omap3xxx_timer10_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_timer10_slaves),
.class = &omap3xxx_timer_1ms_hwmod_class,
};
/* timer11 */
-static struct omap_hwmod omap3xxx_timer11_hwmod;
-
-/* l4_core -> timer11 */
-static struct omap_hwmod_ocp_if omap3xxx_l4_core__timer11 = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_timer11_hwmod,
- .clk = "gpt11_ick",
- .addr = omap2_timer11_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer11 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer11_slaves[] = {
- &omap3xxx_l4_core__timer11,
-};
-
-/* timer11 hwmod */
static struct omap_hwmod omap3xxx_timer11_hwmod = {
.name = "timer11",
.mpu_irqs = omap2_timer11_mpu_irqs,
@@ -1093,42 +358,15 @@ static struct omap_hwmod omap3xxx_timer11_hwmod = {
},
},
.dev_attr = &capability_pwm_dev_attr,
- .slaves = omap3xxx_timer11_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_timer11_slaves),
.class = &omap3xxx_timer_hwmod_class,
};
-/* timer12*/
-static struct omap_hwmod omap3xxx_timer12_hwmod;
+/* timer12 */
static struct omap_hwmod_irq_info omap3xxx_timer12_mpu_irqs[] = {
{ .irq = 95, },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap3xxx_timer12_addrs[] = {
- {
- .pa_start = 0x48304000,
- .pa_end = 0x48304000 + SZ_1K - 1,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_core -> timer12 */
-static struct omap_hwmod_ocp_if omap3xxx_l4_core__timer12 = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_timer12_hwmod,
- .clk = "gpt12_ick",
- .addr = omap3xxx_timer12_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer12 slave port */
-static struct omap_hwmod_ocp_if *omap3xxx_timer12_slaves[] = {
- &omap3xxx_l4_core__timer12,
-};
-
-/* timer12 hwmod */
static struct omap_hwmod omap3xxx_timer12_hwmod = {
.name = "timer12",
.mpu_irqs = omap3xxx_timer12_mpu_irqs,
@@ -1143,29 +381,9 @@ static struct omap_hwmod omap3xxx_timer12_hwmod = {
},
},
.dev_attr = &capability_secure_dev_attr,
- .slaves = omap3xxx_timer12_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_timer12_slaves),
.class = &omap3xxx_timer_hwmod_class,
};
-/* l4_wkup -> wd_timer2 */
-static struct omap_hwmod_addr_space omap3xxx_wd_timer2_addrs[] = {
- {
- .pa_start = 0x48314000,
- .pa_end = 0x4831407f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-static struct omap_hwmod_ocp_if omap3xxx_l4_wkup__wd_timer2 = {
- .master = &omap3xxx_l4_wkup_hwmod,
- .slave = &omap3xxx_wd_timer2_hwmod,
- .clk = "wdt2_ick",
- .addr = omap3xxx_wd_timer2_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
/*
* 'wd_timer' class
* 32-bit watchdog upward counter that generates a pulse on the reset pin on
@@ -1200,12 +418,8 @@ static struct omap_hwmod_class_sysconfig i2c_sysc = {
static struct omap_hwmod_class omap3xxx_wd_timer_hwmod_class = {
.name = "wd_timer",
.sysc = &omap3xxx_wd_timer_sysc,
- .pre_shutdown = &omap2_wd_timer_disable
-};
-
-/* wd_timer2 */
-static struct omap_hwmod_ocp_if *omap3xxx_wd_timer2_slaves[] = {
- &omap3xxx_l4_wkup__wd_timer2,
+ .pre_shutdown = &omap2_wd_timer_disable,
+ .reset = &omap2_wd_timer_reset,
};
static struct omap_hwmod omap3xxx_wd_timer2_hwmod = {
@@ -1221,8 +435,6 @@ static struct omap_hwmod omap3xxx_wd_timer2_hwmod = {
.idlest_idle_bit = OMAP3430_ST_WDT2_SHIFT,
},
},
- .slaves = omap3xxx_wd_timer2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_wd_timer2_slaves),
/*
* XXX: Use software supervised mode, HW supervised smartidle seems to
* block CORE power domain idle transitions. Maybe a HW bug in wdt2?
@@ -1231,11 +443,6 @@ static struct omap_hwmod omap3xxx_wd_timer2_hwmod = {
};
/* UART1 */
-
-static struct omap_hwmod_ocp_if *omap3xxx_uart1_slaves[] = {
- &omap3_l4_core__uart1,
-};
-
static struct omap_hwmod omap3xxx_uart1_hwmod = {
.name = "uart1",
.mpu_irqs = omap2_uart1_mpu_irqs,
@@ -1250,17 +457,10 @@ static struct omap_hwmod omap3xxx_uart1_hwmod = {
.idlest_idle_bit = OMAP3430_EN_UART1_SHIFT,
},
},
- .slaves = omap3xxx_uart1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_uart1_slaves),
.class = &omap2_uart_class,
};
/* UART2 */
-
-static struct omap_hwmod_ocp_if *omap3xxx_uart2_slaves[] = {
- &omap3_l4_core__uart2,
-};
-
static struct omap_hwmod omap3xxx_uart2_hwmod = {
.name = "uart2",
.mpu_irqs = omap2_uart2_mpu_irqs,
@@ -1275,17 +475,10 @@ static struct omap_hwmod omap3xxx_uart2_hwmod = {
.idlest_idle_bit = OMAP3430_EN_UART2_SHIFT,
},
},
- .slaves = omap3xxx_uart2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_uart2_slaves),
.class = &omap2_uart_class,
};
/* UART3 */
-
-static struct omap_hwmod_ocp_if *omap3xxx_uart3_slaves[] = {
- &omap3_l4_per__uart3,
-};
-
static struct omap_hwmod omap3xxx_uart3_hwmod = {
.name = "uart3",
.mpu_irqs = omap2_uart3_mpu_irqs,
@@ -1300,13 +493,10 @@ static struct omap_hwmod omap3xxx_uart3_hwmod = {
.idlest_idle_bit = OMAP3430_EN_UART3_SHIFT,
},
},
- .slaves = omap3xxx_uart3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_uart3_slaves),
.class = &omap2_uart_class,
};
/* UART4 */
-
static struct omap_hwmod_irq_info uart4_mpu_irqs[] = {
{ .irq = INT_36XX_UART4_IRQ, },
{ .irq = -1 }
@@ -1318,11 +508,7 @@ static struct omap_hwmod_dma_info uart4_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_ocp_if *omap3xxx_uart4_slaves[] = {
- &omap3_l4_per__uart4,
-};
-
-static struct omap_hwmod omap3xxx_uart4_hwmod = {
+static struct omap_hwmod omap36xx_uart4_hwmod = {
.name = "uart4",
.mpu_irqs = uart4_mpu_irqs,
.sdma_reqs = uart4_sdma_reqs,
@@ -1336,8 +522,6 @@ static struct omap_hwmod omap3xxx_uart4_hwmod = {
.idlest_idle_bit = OMAP3630_EN_UART4_SHIFT,
},
},
- .slaves = omap3xxx_uart4_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_uart4_slaves),
.class = &omap2_uart_class,
};
@@ -1350,16 +534,12 @@ static struct omap_hwmod_dma_info am35xx_uart4_sdma_reqs[] = {
{ .name = "tx", .dma_req = AM35XX_DMA_UART4_TX, },
};
-static struct omap_hwmod_ocp_if *am35xx_uart4_slaves[] = {
- &am35xx_l4_core__uart4,
-};
-
static struct omap_hwmod am35xx_uart4_hwmod = {
- .name = "uart4",
- .mpu_irqs = am35xx_uart4_mpu_irqs,
- .sdma_reqs = am35xx_uart4_sdma_reqs,
- .main_clk = "uart4_fck",
- .prcm = {
+ .name = "uart4",
+ .mpu_irqs = am35xx_uart4_mpu_irqs,
+ .sdma_reqs = am35xx_uart4_sdma_reqs,
+ .main_clk = "uart4_fck",
+ .prcm = {
.omap2 = {
.module_offs = CORE_MOD,
.prcm_reg_id = 1,
@@ -1368,12 +548,9 @@ static struct omap_hwmod am35xx_uart4_hwmod = {
.idlest_idle_bit = OMAP3430_EN_UART4_SHIFT,
},
},
- .slaves = am35xx_uart4_slaves,
- .slaves_cnt = ARRAY_SIZE(am35xx_uart4_slaves),
- .class = &omap2_uart_class,
+ .class = &omap2_uart_class,
};
-
static struct omap_hwmod_class i2c_class = {
.name = "i2c",
.sysc = &i2c_sysc,
@@ -1388,51 +565,6 @@ static struct omap_hwmod_dma_info omap3xxx_dss_sdma_chs[] = {
};
/* dss */
-/* dss master ports */
-static struct omap_hwmod_ocp_if *omap3xxx_dss_masters[] = {
- &omap3xxx_dss__l3,
-};
-
-/* l4_core -> dss */
-static struct omap_hwmod_ocp_if omap3430es1_l4_core__dss = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3430es1_dss_core_hwmod,
- .clk = "dss_ick",
- .addr = omap2_dss_addrs,
- .fw = {
- .omap2 = {
- .l4_fw_region = OMAP3ES1_L4_CORE_FW_DSS_CORE_REGION,
- .l4_prot_group = OMAP3_L4_CORE_FW_DSS_PROT_GROUP,
- .flags = OMAP_FIREWALL_L4,
- }
- },
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-static struct omap_hwmod_ocp_if omap3xxx_l4_core__dss = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_dss_core_hwmod,
- .clk = "dss_ick",
- .addr = omap2_dss_addrs,
- .fw = {
- .omap2 = {
- .l4_fw_region = OMAP3_L4_CORE_FW_DSS_CORE_REGION,
- .l4_prot_group = OMAP3_L4_CORE_FW_DSS_PROT_GROUP,
- .flags = OMAP_FIREWALL_L4,
- }
- },
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dss slave ports */
-static struct omap_hwmod_ocp_if *omap3430es1_dss_slaves[] = {
- &omap3430es1_l4_core__dss,
-};
-
-static struct omap_hwmod_ocp_if *omap3xxx_dss_slaves[] = {
- &omap3xxx_l4_core__dss,
-};
-
static struct omap_hwmod_opt_clk dss_opt_clks[] = {
/*
* The DSS HW needs all DSS clocks enabled during reset. The dss_core
@@ -1460,10 +592,6 @@ static struct omap_hwmod omap3430es1_dss_core_hwmod = {
},
.opt_clks = dss_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_opt_clks),
- .slaves = omap3430es1_dss_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3430es1_dss_slaves),
- .masters = omap3xxx_dss_masters,
- .masters_cnt = ARRAY_SIZE(omap3xxx_dss_masters),
.flags = HWMOD_NO_IDLEST | HWMOD_CONTROL_OPT_CLKS_IN_RESET,
};
@@ -1485,10 +613,6 @@ static struct omap_hwmod omap3xxx_dss_core_hwmod = {
},
.opt_clks = dss_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_opt_clks),
- .slaves = omap3xxx_dss_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_dss_slaves),
- .masters = omap3xxx_dss_masters,
- .masters_cnt = ARRAY_SIZE(omap3xxx_dss_masters),
};
/*
@@ -1513,27 +637,6 @@ static struct omap_hwmod_class omap3_dispc_hwmod_class = {
.sysc = &omap3_dispc_sysc,
};
-/* l4_core -> dss_dispc */
-static struct omap_hwmod_ocp_if omap3xxx_l4_core__dss_dispc = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_dss_dispc_hwmod,
- .clk = "dss_ick",
- .addr = omap2_dss_dispc_addrs,
- .fw = {
- .omap2 = {
- .l4_fw_region = OMAP3_L4_CORE_FW_DSS_DISPC_REGION,
- .l4_prot_group = OMAP3_L4_CORE_FW_DSS_PROT_GROUP,
- .flags = OMAP_FIREWALL_L4,
- }
- },
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dss_dispc slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_dss_dispc_slaves[] = {
- &omap3xxx_l4_core__dss_dispc,
-};
-
static struct omap_hwmod omap3xxx_dss_dispc_hwmod = {
.name = "dss_dispc",
.class = &omap3_dispc_hwmod_class,
@@ -1546,8 +649,6 @@ static struct omap_hwmod omap3xxx_dss_dispc_hwmod = {
.module_offs = OMAP3430_DSS_MOD,
},
},
- .slaves = omap3xxx_dss_dispc_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_dss_dispc_slaves),
.flags = HWMOD_NO_IDLEST,
.dev_attr = &omap2_3_dss_dispc_dev_attr
};
@@ -1567,36 +668,6 @@ static struct omap_hwmod_irq_info omap3xxx_dsi1_irqs[] = {
};
/* dss_dsi1 */
-static struct omap_hwmod_addr_space omap3xxx_dss_dsi1_addrs[] = {
- {
- .pa_start = 0x4804FC00,
- .pa_end = 0x4804FFFF,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_core -> dss_dsi1 */
-static struct omap_hwmod_ocp_if omap3xxx_l4_core__dss_dsi1 = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_dss_dsi1_hwmod,
- .clk = "dss_ick",
- .addr = omap3xxx_dss_dsi1_addrs,
- .fw = {
- .omap2 = {
- .l4_fw_region = OMAP3_L4_CORE_FW_DSS_DSI_REGION,
- .l4_prot_group = OMAP3_L4_CORE_FW_DSS_PROT_GROUP,
- .flags = OMAP_FIREWALL_L4,
- }
- },
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dss_dsi1 slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_dss_dsi1_slaves[] = {
- &omap3xxx_l4_core__dss_dsi1,
-};
-
static struct omap_hwmod_opt_clk dss_dsi1_opt_clks[] = {
{ .role = "sys_clk", .clk = "dss2_alwon_fck" },
};
@@ -1615,32 +686,9 @@ static struct omap_hwmod omap3xxx_dss_dsi1_hwmod = {
},
.opt_clks = dss_dsi1_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_dsi1_opt_clks),
- .slaves = omap3xxx_dss_dsi1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_dss_dsi1_slaves),
.flags = HWMOD_NO_IDLEST,
};
-/* l4_core -> dss_rfbi */
-static struct omap_hwmod_ocp_if omap3xxx_l4_core__dss_rfbi = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_dss_rfbi_hwmod,
- .clk = "dss_ick",
- .addr = omap2_dss_rfbi_addrs,
- .fw = {
- .omap2 = {
- .l4_fw_region = OMAP3_L4_CORE_FW_DSS_RFBI_REGION,
- .l4_prot_group = OMAP3_L4_CORE_FW_DSS_PROT_GROUP ,
- .flags = OMAP_FIREWALL_L4,
- }
- },
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dss_rfbi slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_dss_rfbi_slaves[] = {
- &omap3xxx_l4_core__dss_rfbi,
-};
-
static struct omap_hwmod_opt_clk dss_rfbi_opt_clks[] = {
{ .role = "ick", .clk = "dss_ick" },
};
@@ -1658,32 +706,9 @@ static struct omap_hwmod omap3xxx_dss_rfbi_hwmod = {
},
.opt_clks = dss_rfbi_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_rfbi_opt_clks),
- .slaves = omap3xxx_dss_rfbi_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_dss_rfbi_slaves),
.flags = HWMOD_NO_IDLEST,
};
-/* l4_core -> dss_venc */
-static struct omap_hwmod_ocp_if omap3xxx_l4_core__dss_venc = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_dss_venc_hwmod,
- .clk = "dss_ick",
- .addr = omap2_dss_venc_addrs,
- .fw = {
- .omap2 = {
- .l4_fw_region = OMAP3_L4_CORE_FW_DSS_VENC_REGION,
- .l4_prot_group = OMAP3_L4_CORE_FW_DSS_PROT_GROUP,
- .flags = OMAP_FIREWALL_L4,
- }
- },
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dss_venc slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_dss_venc_slaves[] = {
- &omap3xxx_l4_core__dss_venc,
-};
-
static struct omap_hwmod_opt_clk dss_venc_opt_clks[] = {
/* required only on OMAP3430 */
{ .role = "tv_dac_clk", .clk = "dss_96m_fck" },
@@ -1702,13 +727,10 @@ static struct omap_hwmod omap3xxx_dss_venc_hwmod = {
},
.opt_clks = dss_venc_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_venc_opt_clks),
- .slaves = omap3xxx_dss_venc_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_dss_venc_slaves),
.flags = HWMOD_NO_IDLEST,
};
/* I2C1 */
-
static struct omap_i2c_dev_attr i2c1_dev_attr = {
.fifo_depth = 8, /* bytes */
.flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 |
@@ -1716,10 +738,6 @@ static struct omap_i2c_dev_attr i2c1_dev_attr = {
OMAP_I2C_FLAG_BUS_SHIFT_2,
};
-static struct omap_hwmod_ocp_if *omap3xxx_i2c1_slaves[] = {
- &omap3_l4_core__i2c1,
-};
-
static struct omap_hwmod omap3xxx_i2c1_hwmod = {
.name = "i2c1",
.flags = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
@@ -1735,14 +753,11 @@ static struct omap_hwmod omap3xxx_i2c1_hwmod = {
.idlest_idle_bit = OMAP3430_ST_I2C1_SHIFT,
},
},
- .slaves = omap3xxx_i2c1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_i2c1_slaves),
.class = &i2c_class,
.dev_attr = &i2c1_dev_attr,
};
/* I2C2 */
-
static struct omap_i2c_dev_attr i2c2_dev_attr = {
.fifo_depth = 8, /* bytes */
.flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 |
@@ -1750,10 +765,6 @@ static struct omap_i2c_dev_attr i2c2_dev_attr = {
OMAP_I2C_FLAG_BUS_SHIFT_2,
};
-static struct omap_hwmod_ocp_if *omap3xxx_i2c2_slaves[] = {
- &omap3_l4_core__i2c2,
-};
-
static struct omap_hwmod omap3xxx_i2c2_hwmod = {
.name = "i2c2",
.flags = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
@@ -1769,14 +780,11 @@ static struct omap_hwmod omap3xxx_i2c2_hwmod = {
.idlest_idle_bit = OMAP3430_ST_I2C2_SHIFT,
},
},
- .slaves = omap3xxx_i2c2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_i2c2_slaves),
.class = &i2c_class,
.dev_attr = &i2c2_dev_attr,
};
/* I2C3 */
-
static struct omap_i2c_dev_attr i2c3_dev_attr = {
.fifo_depth = 64, /* bytes */
.flags = OMAP_I2C_FLAG_APPLY_ERRATA_I207 |
@@ -1795,10 +803,6 @@ static struct omap_hwmod_dma_info i2c3_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_ocp_if *omap3xxx_i2c3_slaves[] = {
- &omap3_l4_core__i2c3,
-};
-
static struct omap_hwmod omap3xxx_i2c3_hwmod = {
.name = "i2c3",
.flags = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
@@ -1814,114 +818,10 @@ static struct omap_hwmod omap3xxx_i2c3_hwmod = {
.idlest_idle_bit = OMAP3430_ST_I2C3_SHIFT,
},
},
- .slaves = omap3xxx_i2c3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_i2c3_slaves),
.class = &i2c_class,
.dev_attr = &i2c3_dev_attr,
};
-/* l4_wkup -> gpio1 */
-static struct omap_hwmod_addr_space omap3xxx_gpio1_addrs[] = {
- {
- .pa_start = 0x48310000,
- .pa_end = 0x483101ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-static struct omap_hwmod_ocp_if omap3xxx_l4_wkup__gpio1 = {
- .master = &omap3xxx_l4_wkup_hwmod,
- .slave = &omap3xxx_gpio1_hwmod,
- .addr = omap3xxx_gpio1_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> gpio2 */
-static struct omap_hwmod_addr_space omap3xxx_gpio2_addrs[] = {
- {
- .pa_start = 0x49050000,
- .pa_end = 0x490501ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-static struct omap_hwmod_ocp_if omap3xxx_l4_per__gpio2 = {
- .master = &omap3xxx_l4_per_hwmod,
- .slave = &omap3xxx_gpio2_hwmod,
- .addr = omap3xxx_gpio2_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> gpio3 */
-static struct omap_hwmod_addr_space omap3xxx_gpio3_addrs[] = {
- {
- .pa_start = 0x49052000,
- .pa_end = 0x490521ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-static struct omap_hwmod_ocp_if omap3xxx_l4_per__gpio3 = {
- .master = &omap3xxx_l4_per_hwmod,
- .slave = &omap3xxx_gpio3_hwmod,
- .addr = omap3xxx_gpio3_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> gpio4 */
-static struct omap_hwmod_addr_space omap3xxx_gpio4_addrs[] = {
- {
- .pa_start = 0x49054000,
- .pa_end = 0x490541ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-static struct omap_hwmod_ocp_if omap3xxx_l4_per__gpio4 = {
- .master = &omap3xxx_l4_per_hwmod,
- .slave = &omap3xxx_gpio4_hwmod,
- .addr = omap3xxx_gpio4_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> gpio5 */
-static struct omap_hwmod_addr_space omap3xxx_gpio5_addrs[] = {
- {
- .pa_start = 0x49056000,
- .pa_end = 0x490561ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-static struct omap_hwmod_ocp_if omap3xxx_l4_per__gpio5 = {
- .master = &omap3xxx_l4_per_hwmod,
- .slave = &omap3xxx_gpio5_hwmod,
- .addr = omap3xxx_gpio5_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per -> gpio6 */
-static struct omap_hwmod_addr_space omap3xxx_gpio6_addrs[] = {
- {
- .pa_start = 0x49058000,
- .pa_end = 0x490581ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-static struct omap_hwmod_ocp_if omap3xxx_l4_per__gpio6 = {
- .master = &omap3xxx_l4_per_hwmod,
- .slave = &omap3xxx_gpio6_hwmod,
- .addr = omap3xxx_gpio6_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
/*
* 'gpio' class
* general purpose io module
@@ -1944,7 +844,7 @@ static struct omap_hwmod_class omap3xxx_gpio_hwmod_class = {
.rev = 1,
};
-/* gpio_dev_attr*/
+/* gpio_dev_attr */
static struct omap_gpio_dev_attr gpio_dev_attr = {
.bank_width = 32,
.dbck_flag = true,
@@ -1955,10 +855,6 @@ static struct omap_hwmod_opt_clk gpio1_opt_clks[] = {
{ .role = "dbclk", .clk = "gpio1_dbck", },
};
-static struct omap_hwmod_ocp_if *omap3xxx_gpio1_slaves[] = {
- &omap3xxx_l4_wkup__gpio1,
-};
-
static struct omap_hwmod omap3xxx_gpio1_hwmod = {
.name = "gpio1",
.flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
@@ -1975,8 +871,6 @@ static struct omap_hwmod omap3xxx_gpio1_hwmod = {
.idlest_idle_bit = OMAP3430_ST_GPIO1_SHIFT,
},
},
- .slaves = omap3xxx_gpio1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_gpio1_slaves),
.class = &omap3xxx_gpio_hwmod_class,
.dev_attr = &gpio_dev_attr,
};
@@ -1986,10 +880,6 @@ static struct omap_hwmod_opt_clk gpio2_opt_clks[] = {
{ .role = "dbclk", .clk = "gpio2_dbck", },
};
-static struct omap_hwmod_ocp_if *omap3xxx_gpio2_slaves[] = {
- &omap3xxx_l4_per__gpio2,
-};
-
static struct omap_hwmod omap3xxx_gpio2_hwmod = {
.name = "gpio2",
.flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
@@ -2006,8 +896,6 @@ static struct omap_hwmod omap3xxx_gpio2_hwmod = {
.idlest_idle_bit = OMAP3430_ST_GPIO2_SHIFT,
},
},
- .slaves = omap3xxx_gpio2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_gpio2_slaves),
.class = &omap3xxx_gpio_hwmod_class,
.dev_attr = &gpio_dev_attr,
};
@@ -2017,10 +905,6 @@ static struct omap_hwmod_opt_clk gpio3_opt_clks[] = {
{ .role = "dbclk", .clk = "gpio3_dbck", },
};
-static struct omap_hwmod_ocp_if *omap3xxx_gpio3_slaves[] = {
- &omap3xxx_l4_per__gpio3,
-};
-
static struct omap_hwmod omap3xxx_gpio3_hwmod = {
.name = "gpio3",
.flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
@@ -2037,8 +921,6 @@ static struct omap_hwmod omap3xxx_gpio3_hwmod = {
.idlest_idle_bit = OMAP3430_ST_GPIO3_SHIFT,
},
},
- .slaves = omap3xxx_gpio3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_gpio3_slaves),
.class = &omap3xxx_gpio_hwmod_class,
.dev_attr = &gpio_dev_attr,
};
@@ -2048,10 +930,6 @@ static struct omap_hwmod_opt_clk gpio4_opt_clks[] = {
{ .role = "dbclk", .clk = "gpio4_dbck", },
};
-static struct omap_hwmod_ocp_if *omap3xxx_gpio4_slaves[] = {
- &omap3xxx_l4_per__gpio4,
-};
-
static struct omap_hwmod omap3xxx_gpio4_hwmod = {
.name = "gpio4",
.flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
@@ -2068,8 +946,6 @@ static struct omap_hwmod omap3xxx_gpio4_hwmod = {
.idlest_idle_bit = OMAP3430_ST_GPIO4_SHIFT,
},
},
- .slaves = omap3xxx_gpio4_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_gpio4_slaves),
.class = &omap3xxx_gpio_hwmod_class,
.dev_attr = &gpio_dev_attr,
};
@@ -2084,10 +960,6 @@ static struct omap_hwmod_opt_clk gpio5_opt_clks[] = {
{ .role = "dbclk", .clk = "gpio5_dbck", },
};
-static struct omap_hwmod_ocp_if *omap3xxx_gpio5_slaves[] = {
- &omap3xxx_l4_per__gpio5,
-};
-
static struct omap_hwmod omap3xxx_gpio5_hwmod = {
.name = "gpio5",
.flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
@@ -2104,8 +976,6 @@ static struct omap_hwmod omap3xxx_gpio5_hwmod = {
.idlest_idle_bit = OMAP3430_ST_GPIO5_SHIFT,
},
},
- .slaves = omap3xxx_gpio5_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_gpio5_slaves),
.class = &omap3xxx_gpio_hwmod_class,
.dev_attr = &gpio_dev_attr,
};
@@ -2120,10 +990,6 @@ static struct omap_hwmod_opt_clk gpio6_opt_clks[] = {
{ .role = "dbclk", .clk = "gpio6_dbck", },
};
-static struct omap_hwmod_ocp_if *omap3xxx_gpio6_slaves[] = {
- &omap3xxx_l4_per__gpio6,
-};
-
static struct omap_hwmod omap3xxx_gpio6_hwmod = {
.name = "gpio6",
.flags = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
@@ -2140,20 +1006,10 @@ static struct omap_hwmod omap3xxx_gpio6_hwmod = {
.idlest_idle_bit = OMAP3430_ST_GPIO6_SHIFT,
},
},
- .slaves = omap3xxx_gpio6_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_gpio6_slaves),
.class = &omap3xxx_gpio_hwmod_class,
.dev_attr = &gpio_dev_attr,
};
-/* dma_system -> L3 */
-static struct omap_hwmod_ocp_if omap3xxx_dma_system__l3 = {
- .master = &omap3xxx_dma_system_hwmod,
- .slave = &omap3xxx_l3_main_hwmod,
- .clk = "core_l3_ick",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
/* dma attributes */
static struct omap_dma_dev_attr dma_dev_attr = {
.dev_caps = RESERVE_CHANNEL | DMA_LINKED_LCH | GLOBAL_PRIORITY |
@@ -2180,34 +1036,6 @@ static struct omap_hwmod_class omap3xxx_dma_hwmod_class = {
};
/* dma_system */
-static struct omap_hwmod_addr_space omap3xxx_dma_system_addrs[] = {
- {
- .pa_start = 0x48056000,
- .pa_end = 0x48056fff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* dma_system master ports */
-static struct omap_hwmod_ocp_if *omap3xxx_dma_system_masters[] = {
- &omap3xxx_dma_system__l3,
-};
-
-/* l4_cfg -> dma_system */
-static struct omap_hwmod_ocp_if omap3xxx_l4_core__dma_system = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_dma_system_hwmod,
- .clk = "core_l4_ick",
- .addr = omap3xxx_dma_system_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dma_system slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_dma_system_slaves[] = {
- &omap3xxx_l4_core__dma_system,
-};
-
static struct omap_hwmod omap3xxx_dma_system_hwmod = {
.name = "dma",
.class = &omap3xxx_dma_hwmod_class,
@@ -2222,10 +1050,6 @@ static struct omap_hwmod omap3xxx_dma_system_hwmod = {
.idlest_idle_bit = OMAP3430_ST_SDMA_SHIFT,
},
},
- .slaves = omap3xxx_dma_system_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_dma_system_slaves),
- .masters = omap3xxx_dma_system_masters,
- .masters_cnt = ARRAY_SIZE(omap3xxx_dma_system_masters),
.dev_attr = &dma_dev_attr,
.flags = HWMOD_NO_IDLEST,
};
@@ -2252,36 +1076,12 @@ static struct omap_hwmod_class omap3xxx_mcbsp_hwmod_class = {
/* mcbsp1 */
static struct omap_hwmod_irq_info omap3xxx_mcbsp1_irqs[] = {
- { .name = "irq", .irq = 16 },
+ { .name = "common", .irq = 16 },
{ .name = "tx", .irq = 59 },
{ .name = "rx", .irq = 60 },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap3xxx_mcbsp1_addrs[] = {
- {
- .name = "mpu",
- .pa_start = 0x48074000,
- .pa_end = 0x480740ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_core -> mcbsp1 */
-static struct omap_hwmod_ocp_if omap3xxx_l4_core__mcbsp1 = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_mcbsp1_hwmod,
- .clk = "mcbsp1_ick",
- .addr = omap3xxx_mcbsp1_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mcbsp1 slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_mcbsp1_slaves[] = {
- &omap3xxx_l4_core__mcbsp1,
-};
-
static struct omap_hwmod omap3xxx_mcbsp1_hwmod = {
.name = "mcbsp1",
.class = &omap3xxx_mcbsp_hwmod_class,
@@ -2297,42 +1097,16 @@ static struct omap_hwmod omap3xxx_mcbsp1_hwmod = {
.idlest_idle_bit = OMAP3430_ST_MCBSP1_SHIFT,
},
},
- .slaves = omap3xxx_mcbsp1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_mcbsp1_slaves),
};
/* mcbsp2 */
static struct omap_hwmod_irq_info omap3xxx_mcbsp2_irqs[] = {
- { .name = "irq", .irq = 17 },
+ { .name = "common", .irq = 17 },
{ .name = "tx", .irq = 62 },
{ .name = "rx", .irq = 63 },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap3xxx_mcbsp2_addrs[] = {
- {
- .name = "mpu",
- .pa_start = 0x49022000,
- .pa_end = 0x490220ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> mcbsp2 */
-static struct omap_hwmod_ocp_if omap3xxx_l4_per__mcbsp2 = {
- .master = &omap3xxx_l4_per_hwmod,
- .slave = &omap3xxx_mcbsp2_hwmod,
- .clk = "mcbsp2_ick",
- .addr = omap3xxx_mcbsp2_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mcbsp2 slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_mcbsp2_slaves[] = {
- &omap3xxx_l4_per__mcbsp2,
-};
-
static struct omap_mcbsp_dev_attr omap34xx_mcbsp2_dev_attr = {
.sidetone = "mcbsp2_sidetone",
};
@@ -2352,45 +1126,19 @@ static struct omap_hwmod omap3xxx_mcbsp2_hwmod = {
.idlest_idle_bit = OMAP3430_ST_MCBSP2_SHIFT,
},
},
- .slaves = omap3xxx_mcbsp2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_mcbsp2_slaves),
.dev_attr = &omap34xx_mcbsp2_dev_attr,
};
/* mcbsp3 */
static struct omap_hwmod_irq_info omap3xxx_mcbsp3_irqs[] = {
- { .name = "irq", .irq = 22 },
+ { .name = "common", .irq = 22 },
{ .name = "tx", .irq = 89 },
{ .name = "rx", .irq = 90 },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap3xxx_mcbsp3_addrs[] = {
- {
- .name = "mpu",
- .pa_start = 0x49024000,
- .pa_end = 0x490240ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> mcbsp3 */
-static struct omap_hwmod_ocp_if omap3xxx_l4_per__mcbsp3 = {
- .master = &omap3xxx_l4_per_hwmod,
- .slave = &omap3xxx_mcbsp3_hwmod,
- .clk = "mcbsp3_ick",
- .addr = omap3xxx_mcbsp3_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mcbsp3 slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_mcbsp3_slaves[] = {
- &omap3xxx_l4_per__mcbsp3,
-};
-
static struct omap_mcbsp_dev_attr omap34xx_mcbsp3_dev_attr = {
- .sidetone = "mcbsp3_sidetone",
+ .sidetone = "mcbsp3_sidetone",
};
static struct omap_hwmod omap3xxx_mcbsp3_hwmod = {
@@ -2408,14 +1156,12 @@ static struct omap_hwmod omap3xxx_mcbsp3_hwmod = {
.idlest_idle_bit = OMAP3430_ST_MCBSP3_SHIFT,
},
},
- .slaves = omap3xxx_mcbsp3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_mcbsp3_slaves),
.dev_attr = &omap34xx_mcbsp3_dev_attr,
};
/* mcbsp4 */
static struct omap_hwmod_irq_info omap3xxx_mcbsp4_irqs[] = {
- { .name = "irq", .irq = 23 },
+ { .name = "common", .irq = 23 },
{ .name = "tx", .irq = 54 },
{ .name = "rx", .irq = 55 },
{ .irq = -1 }
@@ -2427,30 +1173,6 @@ static struct omap_hwmod_dma_info omap3xxx_mcbsp4_sdma_chs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap3xxx_mcbsp4_addrs[] = {
- {
- .name = "mpu",
- .pa_start = 0x49026000,
- .pa_end = 0x490260ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> mcbsp4 */
-static struct omap_hwmod_ocp_if omap3xxx_l4_per__mcbsp4 = {
- .master = &omap3xxx_l4_per_hwmod,
- .slave = &omap3xxx_mcbsp4_hwmod,
- .clk = "mcbsp4_ick",
- .addr = omap3xxx_mcbsp4_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mcbsp4 slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_mcbsp4_slaves[] = {
- &omap3xxx_l4_per__mcbsp4,
-};
-
static struct omap_hwmod omap3xxx_mcbsp4_hwmod = {
.name = "mcbsp4",
.class = &omap3xxx_mcbsp_hwmod_class,
@@ -2466,13 +1188,11 @@ static struct omap_hwmod omap3xxx_mcbsp4_hwmod = {
.idlest_idle_bit = OMAP3430_ST_MCBSP4_SHIFT,
},
},
- .slaves = omap3xxx_mcbsp4_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_mcbsp4_slaves),
};
/* mcbsp5 */
static struct omap_hwmod_irq_info omap3xxx_mcbsp5_irqs[] = {
- { .name = "irq", .irq = 27 },
+ { .name = "common", .irq = 27 },
{ .name = "tx", .irq = 81 },
{ .name = "rx", .irq = 82 },
{ .irq = -1 }
@@ -2484,30 +1204,6 @@ static struct omap_hwmod_dma_info omap3xxx_mcbsp5_sdma_chs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap3xxx_mcbsp5_addrs[] = {
- {
- .name = "mpu",
- .pa_start = 0x48096000,
- .pa_end = 0x480960ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_core -> mcbsp5 */
-static struct omap_hwmod_ocp_if omap3xxx_l4_core__mcbsp5 = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_mcbsp5_hwmod,
- .clk = "mcbsp5_ick",
- .addr = omap3xxx_mcbsp5_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mcbsp5 slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_mcbsp5_slaves[] = {
- &omap3xxx_l4_core__mcbsp5,
-};
-
static struct omap_hwmod omap3xxx_mcbsp5_hwmod = {
.name = "mcbsp5",
.class = &omap3xxx_mcbsp_hwmod_class,
@@ -2523,11 +1219,9 @@ static struct omap_hwmod omap3xxx_mcbsp5_hwmod = {
.idlest_idle_bit = OMAP3430_ST_MCBSP5_SHIFT,
},
},
- .slaves = omap3xxx_mcbsp5_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_mcbsp5_slaves),
};
-/* 'mcbsp sidetone' class */
+/* 'mcbsp sidetone' class */
static struct omap_hwmod_class_sysconfig omap3xxx_mcbsp_sidetone_sysc = {
.sysc_offs = 0x0010,
.sysc_flags = SYSC_HAS_AUTOIDLE,
@@ -2545,30 +1239,6 @@ static struct omap_hwmod_irq_info omap3xxx_mcbsp2_sidetone_irqs[] = {
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap3xxx_mcbsp2_sidetone_addrs[] = {
- {
- .name = "sidetone",
- .pa_start = 0x49028000,
- .pa_end = 0x490280ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> mcbsp2_sidetone */
-static struct omap_hwmod_ocp_if omap3xxx_l4_per__mcbsp2_sidetone = {
- .master = &omap3xxx_l4_per_hwmod,
- .slave = &omap3xxx_mcbsp2_sidetone_hwmod,
- .clk = "mcbsp2_ick",
- .addr = omap3xxx_mcbsp2_sidetone_addrs,
- .user = OCP_USER_MPU,
-};
-
-/* mcbsp2_sidetone slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_mcbsp2_sidetone_slaves[] = {
- &omap3xxx_l4_per__mcbsp2_sidetone,
-};
-
static struct omap_hwmod omap3xxx_mcbsp2_sidetone_hwmod = {
.name = "mcbsp2_sidetone",
.class = &omap3xxx_mcbsp_sidetone_hwmod_class,
@@ -2583,8 +1253,6 @@ static struct omap_hwmod omap3xxx_mcbsp2_sidetone_hwmod = {
.idlest_idle_bit = OMAP3430_ST_MCBSP2_SHIFT,
},
},
- .slaves = omap3xxx_mcbsp2_sidetone_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_mcbsp2_sidetone_slaves),
};
/* mcbsp3_sidetone */
@@ -2593,30 +1261,6 @@ static struct omap_hwmod_irq_info omap3xxx_mcbsp3_sidetone_irqs[] = {
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap3xxx_mcbsp3_sidetone_addrs[] = {
- {
- .name = "sidetone",
- .pa_start = 0x4902A000,
- .pa_end = 0x4902A0ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> mcbsp3_sidetone */
-static struct omap_hwmod_ocp_if omap3xxx_l4_per__mcbsp3_sidetone = {
- .master = &omap3xxx_l4_per_hwmod,
- .slave = &omap3xxx_mcbsp3_sidetone_hwmod,
- .clk = "mcbsp3_ick",
- .addr = omap3xxx_mcbsp3_sidetone_addrs,
- .user = OCP_USER_MPU,
-};
-
-/* mcbsp3_sidetone slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_mcbsp3_sidetone_slaves[] = {
- &omap3xxx_l4_per__mcbsp3_sidetone,
-};
-
static struct omap_hwmod omap3xxx_mcbsp3_sidetone_hwmod = {
.name = "mcbsp3_sidetone",
.class = &omap3xxx_mcbsp_sidetone_hwmod_class,
@@ -2631,11 +1275,8 @@ static struct omap_hwmod omap3xxx_mcbsp3_sidetone_hwmod = {
.idlest_idle_bit = OMAP3430_ST_MCBSP3_SHIFT,
},
},
- .slaves = omap3xxx_mcbsp3_sidetone_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_mcbsp3_sidetone_slaves),
};
-
/* SR common */
static struct omap_hwmod_sysc_fields omap34xx_sr_sysc_fields = {
.clkact_shift = 20,
@@ -2656,7 +1297,7 @@ static struct omap_hwmod_class omap34xx_smartreflex_hwmod_class = {
static struct omap_hwmod_sysc_fields omap36xx_sr_sysc_fields = {
.sidle_shift = 24,
- .enwkup_shift = 26
+ .enwkup_shift = 26,
};
static struct omap_hwmod_class_sysconfig omap36xx_sr_sysc = {
@@ -2678,12 +1319,13 @@ static struct omap_smartreflex_dev_attr sr1_dev_attr = {
.sensor_voltdm_name = "mpu_iva",
};
-static struct omap_hwmod_ocp_if *omap3_sr1_slaves[] = {
- &omap3_l4_core__sr1,
+static struct omap_hwmod_irq_info omap3_smartreflex_mpu_irqs[] = {
+ { .irq = 18 },
+ { .irq = -1 }
};
static struct omap_hwmod omap34xx_sr1_hwmod = {
- .name = "sr1_hwmod",
+ .name = "sr1",
.class = &omap34xx_smartreflex_hwmod_class,
.main_clk = "sr1_fck",
.prcm = {
@@ -2695,15 +1337,13 @@ static struct omap_hwmod omap34xx_sr1_hwmod = {
.idlest_idle_bit = OMAP3430_EN_SR1_SHIFT,
},
},
- .slaves = omap3_sr1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3_sr1_slaves),
.dev_attr = &sr1_dev_attr,
.mpu_irqs = omap3_smartreflex_mpu_irqs,
.flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
static struct omap_hwmod omap36xx_sr1_hwmod = {
- .name = "sr1_hwmod",
+ .name = "sr1",
.class = &omap36xx_smartreflex_hwmod_class,
.main_clk = "sr1_fck",
.prcm = {
@@ -2715,8 +1355,6 @@ static struct omap_hwmod omap36xx_sr1_hwmod = {
.idlest_idle_bit = OMAP3430_EN_SR1_SHIFT,
},
},
- .slaves = omap3_sr1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3_sr1_slaves),
.dev_attr = &sr1_dev_attr,
.mpu_irqs = omap3_smartreflex_mpu_irqs,
};
@@ -2726,12 +1364,13 @@ static struct omap_smartreflex_dev_attr sr2_dev_attr = {
.sensor_voltdm_name = "core",
};
-static struct omap_hwmod_ocp_if *omap3_sr2_slaves[] = {
- &omap3_l4_core__sr2,
+static struct omap_hwmod_irq_info omap3_smartreflex_core_irqs[] = {
+ { .irq = 19 },
+ { .irq = -1 }
};
static struct omap_hwmod omap34xx_sr2_hwmod = {
- .name = "sr2_hwmod",
+ .name = "sr2",
.class = &omap34xx_smartreflex_hwmod_class,
.main_clk = "sr2_fck",
.prcm = {
@@ -2743,15 +1382,13 @@ static struct omap_hwmod omap34xx_sr2_hwmod = {
.idlest_idle_bit = OMAP3430_EN_SR2_SHIFT,
},
},
- .slaves = omap3_sr2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3_sr2_slaves),
.dev_attr = &sr2_dev_attr,
.mpu_irqs = omap3_smartreflex_core_irqs,
.flags = HWMOD_SET_DEFAULT_CLOCKACT,
};
static struct omap_hwmod omap36xx_sr2_hwmod = {
- .name = "sr2_hwmod",
+ .name = "sr2",
.class = &omap36xx_smartreflex_hwmod_class,
.main_clk = "sr2_fck",
.prcm = {
@@ -2763,8 +1400,6 @@ static struct omap_hwmod omap36xx_sr2_hwmod = {
.idlest_idle_bit = OMAP3430_EN_SR2_SHIFT,
},
},
- .slaves = omap3_sr2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3_sr2_slaves),
.dev_attr = &sr2_dev_attr,
.mpu_irqs = omap3_smartreflex_core_irqs,
};
@@ -2790,34 +1425,11 @@ static struct omap_hwmod_class omap3xxx_mailbox_hwmod_class = {
.sysc = &omap3xxx_mailbox_sysc,
};
-static struct omap_hwmod omap3xxx_mailbox_hwmod;
static struct omap_hwmod_irq_info omap3xxx_mailbox_irqs[] = {
{ .irq = 26 },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap3xxx_mailbox_addrs[] = {
- {
- .pa_start = 0x48094000,
- .pa_end = 0x480941ff,
- .flags = ADDR_TYPE_RT,
- },
- { }
-};
-
-/* l4_core -> mailbox */
-static struct omap_hwmod_ocp_if omap3xxx_l4_core__mailbox = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_mailbox_hwmod,
- .addr = omap3xxx_mailbox_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mailbox slave ports */
-static struct omap_hwmod_ocp_if *omap3xxx_mailbox_slaves[] = {
- &omap3xxx_l4_core__mailbox,
-};
-
static struct omap_hwmod omap3xxx_mailbox_hwmod = {
.name = "mailbox",
.class = &omap3xxx_mailbox_hwmod_class,
@@ -2832,53 +1444,6 @@ static struct omap_hwmod omap3xxx_mailbox_hwmod = {
.idlest_idle_bit = OMAP3430_ST_MAILBOXES_SHIFT,
},
},
- .slaves = omap3xxx_mailbox_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_mailbox_slaves),
-};
-
-/* l4 core -> mcspi1 interface */
-static struct omap_hwmod_ocp_if omap34xx_l4_core__mcspi1 = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap34xx_mcspi1,
- .clk = "mcspi1_ick",
- .addr = omap2_mcspi1_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4 core -> mcspi2 interface */
-static struct omap_hwmod_ocp_if omap34xx_l4_core__mcspi2 = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap34xx_mcspi2,
- .clk = "mcspi2_ick",
- .addr = omap2_mcspi2_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4 core -> mcspi3 interface */
-static struct omap_hwmod_ocp_if omap34xx_l4_core__mcspi3 = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap34xx_mcspi3,
- .clk = "mcspi3_ick",
- .addr = omap2430_mcspi3_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4 core -> mcspi4 interface */
-static struct omap_hwmod_addr_space omap34xx_mcspi4_addr_space[] = {
- {
- .pa_start = 0x480ba000,
- .pa_end = 0x480ba0ff,
- .flags = ADDR_TYPE_RT,
- },
- { }
-};
-
-static struct omap_hwmod_ocp_if omap34xx_l4_core__mcspi4 = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap34xx_mcspi4,
- .clk = "mcspi4_ick",
- .addr = omap34xx_mcspi4_addr_space,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
};
/*
@@ -2905,10 +1470,6 @@ static struct omap_hwmod_class omap34xx_mcspi_class = {
};
/* mcspi1 */
-static struct omap_hwmod_ocp_if *omap34xx_mcspi1_slaves[] = {
- &omap34xx_l4_core__mcspi1,
-};
-
static struct omap2_mcspi_dev_attr omap_mcspi1_dev_attr = {
.num_chipselect = 4,
};
@@ -2927,17 +1488,11 @@ static struct omap_hwmod omap34xx_mcspi1 = {
.idlest_idle_bit = OMAP3430_ST_MCSPI1_SHIFT,
},
},
- .slaves = omap34xx_mcspi1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap34xx_mcspi1_slaves),
.class = &omap34xx_mcspi_class,
.dev_attr = &omap_mcspi1_dev_attr,
};
/* mcspi2 */
-static struct omap_hwmod_ocp_if *omap34xx_mcspi2_slaves[] = {
- &omap34xx_l4_core__mcspi2,
-};
-
static struct omap2_mcspi_dev_attr omap_mcspi2_dev_attr = {
.num_chipselect = 2,
};
@@ -2956,8 +1511,6 @@ static struct omap_hwmod omap34xx_mcspi2 = {
.idlest_idle_bit = OMAP3430_ST_MCSPI2_SHIFT,
},
},
- .slaves = omap34xx_mcspi2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap34xx_mcspi2_slaves),
.class = &omap34xx_mcspi_class,
.dev_attr = &omap_mcspi2_dev_attr,
};
@@ -2976,10 +1529,6 @@ static struct omap_hwmod_dma_info omap34xx_mcspi3_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_ocp_if *omap34xx_mcspi3_slaves[] = {
- &omap34xx_l4_core__mcspi3,
-};
-
static struct omap2_mcspi_dev_attr omap_mcspi3_dev_attr = {
.num_chipselect = 2,
};
@@ -2998,13 +1547,11 @@ static struct omap_hwmod omap34xx_mcspi3 = {
.idlest_idle_bit = OMAP3430_ST_MCSPI3_SHIFT,
},
},
- .slaves = omap34xx_mcspi3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap34xx_mcspi3_slaves),
.class = &omap34xx_mcspi_class,
.dev_attr = &omap_mcspi3_dev_attr,
};
-/* SPI4 */
+/* mcspi4 */
static struct omap_hwmod_irq_info omap34xx_mcspi4_mpu_irqs[] = {
{ .name = "irq", .irq = INT_34XX_SPI4_IRQ }, /* 48 */
{ .irq = -1 }
@@ -3016,10 +1563,6 @@ static struct omap_hwmod_dma_info omap34xx_mcspi4_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_ocp_if *omap34xx_mcspi4_slaves[] = {
- &omap34xx_l4_core__mcspi4,
-};
-
static struct omap2_mcspi_dev_attr omap_mcspi4_dev_attr = {
.num_chipselect = 1,
};
@@ -3038,15 +1581,11 @@ static struct omap_hwmod omap34xx_mcspi4 = {
.idlest_idle_bit = OMAP3430_ST_MCSPI4_SHIFT,
},
},
- .slaves = omap34xx_mcspi4_slaves,
- .slaves_cnt = ARRAY_SIZE(omap34xx_mcspi4_slaves),
.class = &omap34xx_mcspi_class,
.dev_attr = &omap_mcspi4_dev_attr,
};
-/*
- * usbhsotg
- */
+/* usbhsotg */
static struct omap_hwmod_class_sysconfig omap3xxx_usbhsotg_sysc = {
.rev_offs = 0x0400,
.sysc_offs = 0x0404,
@@ -3063,6 +1602,7 @@ static struct omap_hwmod_class usbotg_class = {
.name = "usbotg",
.sysc = &omap3xxx_usbhsotg_sysc,
};
+
/* usb_otg_hs */
static struct omap_hwmod_irq_info omap3xxx_usbhsotg_mpu_irqs[] = {
@@ -3085,10 +1625,6 @@ static struct omap_hwmod omap3xxx_usbhsotg_hwmod = {
.idlest_stdby_bit = OMAP3430ES2_ST_HSOTGUSB_STDBY_SHIFT
},
},
- .masters = omap3xxx_usbhsotg_masters,
- .masters_cnt = ARRAY_SIZE(omap3xxx_usbhsotg_masters),
- .slaves = omap3xxx_usbhsotg_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_usbhsotg_slaves),
.class = &usbotg_class,
/*
@@ -3120,15 +1656,10 @@ static struct omap_hwmod am35xx_usbhsotg_hwmod = {
.omap2 = {
},
},
- .masters = am35xx_usbhsotg_masters,
- .masters_cnt = ARRAY_SIZE(am35xx_usbhsotg_masters),
- .slaves = am35xx_usbhsotg_slaves,
- .slaves_cnt = ARRAY_SIZE(am35xx_usbhsotg_slaves),
.class = &am35xx_usbotg_class,
};
/* MMC/SD/SDIO common */
-
static struct omap_hwmod_class_sysconfig omap34xx_mmc_sysc = {
.rev_offs = 0x1fc,
.sysc_offs = 0x10,
@@ -3162,10 +1693,6 @@ static struct omap_hwmod_opt_clk omap34xx_mmc1_opt_clks[] = {
{ .role = "dbck", .clk = "omap_32k_fck", },
};
-static struct omap_hwmod_ocp_if *omap3xxx_mmc1_slaves[] = {
- &omap3xxx_l4_core__mmc1,
-};
-
static struct omap_mmc_dev_attr mmc1_dev_attr = {
.flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
};
@@ -3193,8 +1720,6 @@ static struct omap_hwmod omap3xxx_pre_es3_mmc1_hwmod = {
},
},
.dev_attr = &mmc1_pre_es3_dev_attr,
- .slaves = omap3xxx_mmc1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_mmc1_slaves),
.class = &omap34xx_mmc_class,
};
@@ -3215,8 +1740,6 @@ static struct omap_hwmod omap3xxx_es3plus_mmc1_hwmod = {
},
},
.dev_attr = &mmc1_dev_attr,
- .slaves = omap3xxx_mmc1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_mmc1_slaves),
.class = &omap34xx_mmc_class,
};
@@ -3237,10 +1760,6 @@ static struct omap_hwmod_opt_clk omap34xx_mmc2_opt_clks[] = {
{ .role = "dbck", .clk = "omap_32k_fck", },
};
-static struct omap_hwmod_ocp_if *omap3xxx_mmc2_slaves[] = {
- &omap3xxx_l4_core__mmc2,
-};
-
/* See 35xx errata 2.1.1.128 in SPRZ278F */
static struct omap_mmc_dev_attr mmc2_pre_es3_dev_attr = {
.flags = OMAP_HSMMC_BROKEN_MULTIBLOCK_READ,
@@ -3263,8 +1782,6 @@ static struct omap_hwmod omap3xxx_pre_es3_mmc2_hwmod = {
},
},
.dev_attr = &mmc2_pre_es3_dev_attr,
- .slaves = omap3xxx_mmc2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_mmc2_slaves),
.class = &omap34xx_mmc_class,
};
@@ -3284,8 +1801,6 @@ static struct omap_hwmod omap3xxx_es3plus_mmc2_hwmod = {
.idlest_idle_bit = OMAP3430_ST_MMC2_SHIFT,
},
},
- .slaves = omap3xxx_mmc2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_mmc2_slaves),
.class = &omap34xx_mmc_class,
};
@@ -3306,10 +1821,6 @@ static struct omap_hwmod_opt_clk omap34xx_mmc3_opt_clks[] = {
{ .role = "dbck", .clk = "omap_32k_fck", },
};
-static struct omap_hwmod_ocp_if *omap3xxx_mmc3_slaves[] = {
- &omap3xxx_l4_core__mmc3,
-};
-
static struct omap_hwmod omap3xxx_mmc3_hwmod = {
.name = "mmc3",
.mpu_irqs = omap34xx_mmc3_mpu_irqs,
@@ -3325,8 +1836,6 @@ static struct omap_hwmod omap3xxx_mmc3_hwmod = {
.idlest_idle_bit = OMAP3430_ST_MMC3_SHIFT,
},
},
- .slaves = omap3xxx_mmc3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_mmc3_slaves),
.class = &omap34xx_mmc_class,
};
@@ -3334,12 +1843,6 @@ static struct omap_hwmod omap3xxx_mmc3_hwmod = {
* 'usb_host_hs' class
* high-speed multi-port usb host controller
*/
-static struct omap_hwmod_ocp_if omap3xxx_usb_host_hs__l3_main_2 = {
- .master = &omap3xxx_usb_host_hs_hwmod,
- .slave = &omap3xxx_l3_main_hwmod,
- .clk = "core_l3_ick",
- .user = OCP_USER_MPU,
-};
static struct omap_hwmod_class_sysconfig omap3xxx_usb_host_hs_sysc = {
.rev_offs = 0x0000,
@@ -3358,42 +1861,6 @@ static struct omap_hwmod_class omap3xxx_usb_host_hs_hwmod_class = {
.sysc = &omap3xxx_usb_host_hs_sysc,
};
-static struct omap_hwmod_ocp_if *omap3xxx_usb_host_hs_masters[] = {
- &omap3xxx_usb_host_hs__l3_main_2,
-};
-
-static struct omap_hwmod_addr_space omap3xxx_usb_host_hs_addrs[] = {
- {
- .name = "uhh",
- .pa_start = 0x48064000,
- .pa_end = 0x480643ff,
- .flags = ADDR_TYPE_RT
- },
- {
- .name = "ohci",
- .pa_start = 0x48064400,
- .pa_end = 0x480647ff,
- },
- {
- .name = "ehci",
- .pa_start = 0x48064800,
- .pa_end = 0x48064cff,
- },
- {}
-};
-
-static struct omap_hwmod_ocp_if omap3xxx_l4_core__usb_host_hs = {
- .master = &omap3xxx_l4_core_hwmod,
- .slave = &omap3xxx_usb_host_hs_hwmod,
- .clk = "usbhost_ick",
- .addr = omap3xxx_usb_host_hs_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-static struct omap_hwmod_ocp_if *omap3xxx_usb_host_hs_slaves[] = {
- &omap3xxx_l4_core__usb_host_hs,
-};
-
static struct omap_hwmod_opt_clk omap3xxx_usb_host_hs_opt_clks[] = {
{ .role = "ehci_logic_fck", .clk = "usbhost_120m_fck", },
};
@@ -3422,10 +1889,6 @@ static struct omap_hwmod omap3xxx_usb_host_hs_hwmod = {
},
.opt_clks = omap3xxx_usb_host_hs_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(omap3xxx_usb_host_hs_opt_clks),
- .slaves = omap3xxx_usb_host_hs_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_usb_host_hs_slaves),
- .masters = omap3xxx_usb_host_hs_masters,
- .masters_cnt = ARRAY_SIZE(omap3xxx_usb_host_hs_masters),
/*
* Errata: USBHOST Configured In Smart-Idle Can Lead To a Deadlock
@@ -3501,6 +1964,1134 @@ static struct omap_hwmod_irq_info omap3xxx_usb_tll_hs_irqs[] = {
{ .irq = -1 }
};
+static struct omap_hwmod omap3xxx_usb_tll_hs_hwmod = {
+ .name = "usb_tll_hs",
+ .class = &omap3xxx_usb_tll_hs_hwmod_class,
+ .clkdm_name = "l3_init_clkdm",
+ .mpu_irqs = omap3xxx_usb_tll_hs_irqs,
+ .main_clk = "usbtll_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 3,
+ .module_bit = OMAP3430ES2_EN_USBTLL_SHIFT,
+ .idlest_reg_id = 3,
+ .idlest_idle_bit = OMAP3430ES2_ST_USBTLL_SHIFT,
+ },
+ },
+};
+
+static struct omap_hwmod omap3xxx_hdq1w_hwmod = {
+ .name = "hdq1w",
+ .mpu_irqs = omap2_hdq1w_mpu_irqs,
+ .main_clk = "hdq_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = CORE_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_EN_HDQ_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_HDQ_SHIFT,
+ },
+ },
+ .class = &omap2_hdq1w_class,
+};
+
+/*
+ * '32K sync counter' class
+ * 32-bit ordinary counter, clocked by the falling edge of the 32 khz clock
+ */
+static struct omap_hwmod_class_sysconfig omap3xxx_counter_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0004,
+ .sysc_flags = SYSC_HAS_SIDLEMODE,
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap3xxx_counter_hwmod_class = {
+ .name = "counter",
+ .sysc = &omap3xxx_counter_sysc,
+};
+
+static struct omap_hwmod omap3xxx_counter_32k_hwmod = {
+ .name = "counter_32k",
+ .class = &omap3xxx_counter_hwmod_class,
+ .clkdm_name = "wkup_clkdm",
+ .flags = HWMOD_SWSUP_SIDLE,
+ .main_clk = "wkup_32k_fck",
+ .prcm = {
+ .omap2 = {
+ .module_offs = WKUP_MOD,
+ .prcm_reg_id = 1,
+ .module_bit = OMAP3430_ST_32KSYNC_SHIFT,
+ .idlest_reg_id = 1,
+ .idlest_idle_bit = OMAP3430_ST_32KSYNC_SHIFT,
+ },
+ },
+};
+
+/*
+ * interfaces
+ */
+
+/* L3 -> L4_CORE interface */
+static struct omap_hwmod_ocp_if omap3xxx_l3_main__l4_core = {
+ .master = &omap3xxx_l3_main_hwmod,
+ .slave = &omap3xxx_l4_core_hwmod,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L3 -> L4_PER interface */
+static struct omap_hwmod_ocp_if omap3xxx_l3_main__l4_per = {
+ .master = &omap3xxx_l3_main_hwmod,
+ .slave = &omap3xxx_l4_per_hwmod,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_l3_main_addrs[] = {
+ {
+ .pa_start = 0x68000000,
+ .pa_end = 0x6800ffff,
+ .flags = ADDR_TYPE_RT,
+ },
+ { }
+};
+
+/* MPU -> L3 interface */
+static struct omap_hwmod_ocp_if omap3xxx_mpu__l3_main = {
+ .master = &omap3xxx_mpu_hwmod,
+ .slave = &omap3xxx_l3_main_hwmod,
+ .addr = omap3xxx_l3_main_addrs,
+ .user = OCP_USER_MPU,
+};
+
+/* DSS -> l3 */
+static struct omap_hwmod_ocp_if omap3430es1_dss__l3 = {
+ .master = &omap3430es1_dss_core_hwmod,
+ .slave = &omap3xxx_l3_main_hwmod,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_dss__l3 = {
+ .master = &omap3xxx_dss_core_hwmod,
+ .slave = &omap3xxx_l3_main_hwmod,
+ .fw = {
+ .omap2 = {
+ .l3_perm_bit = OMAP3_L3_CORE_FW_INIT_ID_DSS,
+ .flags = OMAP_FIREWALL_L3,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_core -> usbhsotg interface */
+static struct omap_hwmod_ocp_if omap3xxx_usbhsotg__l3 = {
+ .master = &omap3xxx_usbhsotg_hwmod,
+ .slave = &omap3xxx_l3_main_hwmod,
+ .clk = "core_l3_ick",
+ .user = OCP_USER_MPU,
+};
+
+/* l3_core -> am35xx_usbhsotg interface */
+static struct omap_hwmod_ocp_if am35xx_usbhsotg__l3 = {
+ .master = &am35xx_usbhsotg_hwmod,
+ .slave = &omap3xxx_l3_main_hwmod,
+ .clk = "core_l3_ick",
+ .user = OCP_USER_MPU,
+};
+/* L4_CORE -> L4_WKUP interface */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__l4_wkup = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_l4_wkup_hwmod,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> MMC1 interface */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__pre_es3_mmc1 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_pre_es3_mmc1_hwmod,
+ .clk = "mmchs1_ick",
+ .addr = omap2430_mmc1_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+ .flags = OMAP_FIREWALL_L4
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__es3plus_mmc1 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_es3plus_mmc1_hwmod,
+ .clk = "mmchs1_ick",
+ .addr = omap2430_mmc1_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+ .flags = OMAP_FIREWALL_L4
+};
+
+/* L4 CORE -> MMC2 interface */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__pre_es3_mmc2 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_pre_es3_mmc2_hwmod,
+ .clk = "mmchs2_ick",
+ .addr = omap2430_mmc2_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+ .flags = OMAP_FIREWALL_L4
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__es3plus_mmc2 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_es3plus_mmc2_hwmod,
+ .clk = "mmchs2_ick",
+ .addr = omap2430_mmc2_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+ .flags = OMAP_FIREWALL_L4
+};
+
+/* L4 CORE -> MMC3 interface */
+static struct omap_hwmod_addr_space omap3xxx_mmc3_addr_space[] = {
+ {
+ .pa_start = 0x480ad000,
+ .pa_end = 0x480ad1ff,
+ .flags = ADDR_TYPE_RT,
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__mmc3 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_mmc3_hwmod,
+ .clk = "mmchs3_ick",
+ .addr = omap3xxx_mmc3_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+ .flags = OMAP_FIREWALL_L4
+};
+
+/* L4 CORE -> UART1 interface */
+static struct omap_hwmod_addr_space omap3xxx_uart1_addr_space[] = {
+ {
+ .pa_start = OMAP3_UART1_BASE,
+ .pa_end = OMAP3_UART1_BASE + SZ_8K - 1,
+ .flags = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if omap3_l4_core__uart1 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_uart1_hwmod,
+ .clk = "uart1_ick",
+ .addr = omap3xxx_uart1_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> UART2 interface */
+static struct omap_hwmod_addr_space omap3xxx_uart2_addr_space[] = {
+ {
+ .pa_start = OMAP3_UART2_BASE,
+ .pa_end = OMAP3_UART2_BASE + SZ_1K - 1,
+ .flags = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if omap3_l4_core__uart2 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_uart2_hwmod,
+ .clk = "uart2_ick",
+ .addr = omap3xxx_uart2_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 PER -> UART3 interface */
+static struct omap_hwmod_addr_space omap3xxx_uart3_addr_space[] = {
+ {
+ .pa_start = OMAP3_UART3_BASE,
+ .pa_end = OMAP3_UART3_BASE + SZ_1K - 1,
+ .flags = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if omap3_l4_per__uart3 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_uart3_hwmod,
+ .clk = "uart3_ick",
+ .addr = omap3xxx_uart3_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 PER -> UART4 interface */
+static struct omap_hwmod_addr_space omap36xx_uart4_addr_space[] = {
+ {
+ .pa_start = OMAP3_UART4_BASE,
+ .pa_end = OMAP3_UART4_BASE + SZ_1K - 1,
+ .flags = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if omap36xx_l4_per__uart4 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap36xx_uart4_hwmod,
+ .clk = "uart4_ick",
+ .addr = omap36xx_uart4_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* AM35xx: L4 CORE -> UART4 interface */
+static struct omap_hwmod_addr_space am35xx_uart4_addr_space[] = {
+ {
+ .pa_start = OMAP3_UART4_AM35XX_BASE,
+ .pa_end = OMAP3_UART4_AM35XX_BASE + SZ_1K - 1,
+ .flags = ADDR_MAP_ON_INIT | ADDR_TYPE_RT,
+ },
+};
+
+static struct omap_hwmod_ocp_if am35xx_l4_core__uart4 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &am35xx_uart4_hwmod,
+ .clk = "uart4_ick",
+ .addr = am35xx_uart4_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> I2C1 interface */
+static struct omap_hwmod_ocp_if omap3_l4_core__i2c1 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_i2c1_hwmod,
+ .clk = "i2c1_ick",
+ .addr = omap2_i2c1_addr_space,
+ .fw = {
+ .omap2 = {
+ .l4_fw_region = OMAP3_L4_CORE_FW_I2C1_REGION,
+ .l4_prot_group = 7,
+ .flags = OMAP_FIREWALL_L4,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> I2C2 interface */
+static struct omap_hwmod_ocp_if omap3_l4_core__i2c2 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_i2c2_hwmod,
+ .clk = "i2c2_ick",
+ .addr = omap2_i2c2_addr_space,
+ .fw = {
+ .omap2 = {
+ .l4_fw_region = OMAP3_L4_CORE_FW_I2C2_REGION,
+ .l4_prot_group = 7,
+ .flags = OMAP_FIREWALL_L4,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> I2C3 interface */
+static struct omap_hwmod_addr_space omap3xxx_i2c3_addr_space[] = {
+ {
+ .pa_start = 0x48060000,
+ .pa_end = 0x48060000 + SZ_128 - 1,
+ .flags = ADDR_TYPE_RT,
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if omap3_l4_core__i2c3 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_i2c3_hwmod,
+ .clk = "i2c3_ick",
+ .addr = omap3xxx_i2c3_addr_space,
+ .fw = {
+ .omap2 = {
+ .l4_fw_region = OMAP3_L4_CORE_FW_I2C3_REGION,
+ .l4_prot_group = 7,
+ .flags = OMAP_FIREWALL_L4,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* L4 CORE -> SR1 interface */
+static struct omap_hwmod_addr_space omap3_sr1_addr_space[] = {
+ {
+ .pa_start = OMAP34XX_SR1_BASE,
+ .pa_end = OMAP34XX_SR1_BASE + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT,
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if omap34xx_l4_core__sr1 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap34xx_sr1_hwmod,
+ .clk = "sr_l4_ick",
+ .addr = omap3_sr1_addr_space,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_ocp_if omap36xx_l4_core__sr1 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap36xx_sr1_hwmod,
+ .clk = "sr_l4_ick",
+ .addr = omap3_sr1_addr_space,
+ .user = OCP_USER_MPU,
+};
+
+/* L4 CORE -> SR1 interface */
+static struct omap_hwmod_addr_space omap3_sr2_addr_space[] = {
+ {
+ .pa_start = OMAP34XX_SR2_BASE,
+ .pa_end = OMAP34XX_SR2_BASE + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT,
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if omap34xx_l4_core__sr2 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap34xx_sr2_hwmod,
+ .clk = "sr_l4_ick",
+ .addr = omap3_sr2_addr_space,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_ocp_if omap36xx_l4_core__sr2 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap36xx_sr2_hwmod,
+ .clk = "sr_l4_ick",
+ .addr = omap3_sr2_addr_space,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_usbhsotg_addrs[] = {
+ {
+ .pa_start = OMAP34XX_HSUSB_OTG_BASE,
+ .pa_end = OMAP34XX_HSUSB_OTG_BASE + SZ_4K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_core -> usbhsotg */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__usbhsotg = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_usbhsotg_hwmod,
+ .clk = "l4_ick",
+ .addr = omap3xxx_usbhsotg_addrs,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space am35xx_usbhsotg_addrs[] = {
+ {
+ .pa_start = AM35XX_IPSS_USBOTGSS_BASE,
+ .pa_end = AM35XX_IPSS_USBOTGSS_BASE + SZ_4K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_core -> usbhsotg */
+static struct omap_hwmod_ocp_if am35xx_l4_core__usbhsotg = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &am35xx_usbhsotg_hwmod,
+ .clk = "l4_ick",
+ .addr = am35xx_usbhsotg_addrs,
+ .user = OCP_USER_MPU,
+};
+
+/* L4_WKUP -> L4_SEC interface */
+static struct omap_hwmod_ocp_if omap3xxx_l4_wkup__l4_sec = {
+ .master = &omap3xxx_l4_wkup_hwmod,
+ .slave = &omap3xxx_l4_sec_hwmod,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* IVA2 <- L3 interface */
+static struct omap_hwmod_ocp_if omap3xxx_l3__iva = {
+ .master = &omap3xxx_l3_main_hwmod,
+ .slave = &omap3xxx_iva_hwmod,
+ .clk = "core_l3_ick",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_timer1_addrs[] = {
+ {
+ .pa_start = 0x48318000,
+ .pa_end = 0x48318000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_wkup -> timer1 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_wkup__timer1 = {
+ .master = &omap3xxx_l4_wkup_hwmod,
+ .slave = &omap3xxx_timer1_hwmod,
+ .clk = "gpt1_ick",
+ .addr = omap3xxx_timer1_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_timer2_addrs[] = {
+ {
+ .pa_start = 0x49032000,
+ .pa_end = 0x49032000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> timer2 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer2 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_timer2_hwmod,
+ .clk = "gpt2_ick",
+ .addr = omap3xxx_timer2_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_timer3_addrs[] = {
+ {
+ .pa_start = 0x49034000,
+ .pa_end = 0x49034000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> timer3 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer3 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_timer3_hwmod,
+ .clk = "gpt3_ick",
+ .addr = omap3xxx_timer3_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_timer4_addrs[] = {
+ {
+ .pa_start = 0x49036000,
+ .pa_end = 0x49036000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> timer4 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer4 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_timer4_hwmod,
+ .clk = "gpt4_ick",
+ .addr = omap3xxx_timer4_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_timer5_addrs[] = {
+ {
+ .pa_start = 0x49038000,
+ .pa_end = 0x49038000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> timer5 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer5 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_timer5_hwmod,
+ .clk = "gpt5_ick",
+ .addr = omap3xxx_timer5_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_timer6_addrs[] = {
+ {
+ .pa_start = 0x4903A000,
+ .pa_end = 0x4903A000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> timer6 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer6 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_timer6_hwmod,
+ .clk = "gpt6_ick",
+ .addr = omap3xxx_timer6_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_timer7_addrs[] = {
+ {
+ .pa_start = 0x4903C000,
+ .pa_end = 0x4903C000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> timer7 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer7 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_timer7_hwmod,
+ .clk = "gpt7_ick",
+ .addr = omap3xxx_timer7_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_timer8_addrs[] = {
+ {
+ .pa_start = 0x4903E000,
+ .pa_end = 0x4903E000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> timer8 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer8 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_timer8_hwmod,
+ .clk = "gpt8_ick",
+ .addr = omap3xxx_timer8_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_timer9_addrs[] = {
+ {
+ .pa_start = 0x49040000,
+ .pa_end = 0x49040000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> timer9 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__timer9 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_timer9_hwmod,
+ .clk = "gpt9_ick",
+ .addr = omap3xxx_timer9_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer10 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__timer10 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_timer10_hwmod,
+ .clk = "gpt10_ick",
+ .addr = omap2_timer10_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> timer11 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__timer11 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_timer11_hwmod,
+ .clk = "gpt11_ick",
+ .addr = omap2_timer11_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_timer12_addrs[] = {
+ {
+ .pa_start = 0x48304000,
+ .pa_end = 0x48304000 + SZ_1K - 1,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_core -> timer12 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_sec__timer12 = {
+ .master = &omap3xxx_l4_sec_hwmod,
+ .slave = &omap3xxx_timer12_hwmod,
+ .clk = "gpt12_ick",
+ .addr = omap3xxx_timer12_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> wd_timer2 */
+static struct omap_hwmod_addr_space omap3xxx_wd_timer2_addrs[] = {
+ {
+ .pa_start = 0x48314000,
+ .pa_end = 0x4831407f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_l4_wkup__wd_timer2 = {
+ .master = &omap3xxx_l4_wkup_hwmod,
+ .slave = &omap3xxx_wd_timer2_hwmod,
+ .clk = "wdt2_ick",
+ .addr = omap3xxx_wd_timer2_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> dss */
+static struct omap_hwmod_ocp_if omap3430es1_l4_core__dss = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3430es1_dss_core_hwmod,
+ .clk = "dss_ick",
+ .addr = omap2_dss_addrs,
+ .fw = {
+ .omap2 = {
+ .l4_fw_region = OMAP3ES1_L4_CORE_FW_DSS_CORE_REGION,
+ .l4_prot_group = OMAP3_L4_CORE_FW_DSS_PROT_GROUP,
+ .flags = OMAP_FIREWALL_L4,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__dss = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_dss_core_hwmod,
+ .clk = "dss_ick",
+ .addr = omap2_dss_addrs,
+ .fw = {
+ .omap2 = {
+ .l4_fw_region = OMAP3_L4_CORE_FW_DSS_CORE_REGION,
+ .l4_prot_group = OMAP3_L4_CORE_FW_DSS_PROT_GROUP,
+ .flags = OMAP_FIREWALL_L4,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> dss_dispc */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__dss_dispc = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_dss_dispc_hwmod,
+ .clk = "dss_ick",
+ .addr = omap2_dss_dispc_addrs,
+ .fw = {
+ .omap2 = {
+ .l4_fw_region = OMAP3_L4_CORE_FW_DSS_DISPC_REGION,
+ .l4_prot_group = OMAP3_L4_CORE_FW_DSS_PROT_GROUP,
+ .flags = OMAP_FIREWALL_L4,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_dss_dsi1_addrs[] = {
+ {
+ .pa_start = 0x4804FC00,
+ .pa_end = 0x4804FFFF,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_core -> dss_dsi1 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__dss_dsi1 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_dss_dsi1_hwmod,
+ .clk = "dss_ick",
+ .addr = omap3xxx_dss_dsi1_addrs,
+ .fw = {
+ .omap2 = {
+ .l4_fw_region = OMAP3_L4_CORE_FW_DSS_DSI_REGION,
+ .l4_prot_group = OMAP3_L4_CORE_FW_DSS_PROT_GROUP,
+ .flags = OMAP_FIREWALL_L4,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> dss_rfbi */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__dss_rfbi = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_dss_rfbi_hwmod,
+ .clk = "dss_ick",
+ .addr = omap2_dss_rfbi_addrs,
+ .fw = {
+ .omap2 = {
+ .l4_fw_region = OMAP3_L4_CORE_FW_DSS_RFBI_REGION,
+ .l4_prot_group = OMAP3_L4_CORE_FW_DSS_PROT_GROUP ,
+ .flags = OMAP_FIREWALL_L4,
+ }
+ },
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_core -> dss_venc */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__dss_venc = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_dss_venc_hwmod,
+ .clk = "dss_ick",
+ .addr = omap2_dss_venc_addrs,
+ .fw = {
+ .omap2 = {
+ .l4_fw_region = OMAP3_L4_CORE_FW_DSS_VENC_REGION,
+ .l4_prot_group = OMAP3_L4_CORE_FW_DSS_PROT_GROUP,
+ .flags = OMAP_FIREWALL_L4,
+ }
+ },
+ .flags = OCPIF_SWSUP_IDLE,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> gpio1 */
+static struct omap_hwmod_addr_space omap3xxx_gpio1_addrs[] = {
+ {
+ .pa_start = 0x48310000,
+ .pa_end = 0x483101ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_l4_wkup__gpio1 = {
+ .master = &omap3xxx_l4_wkup_hwmod,
+ .slave = &omap3xxx_gpio1_hwmod,
+ .addr = omap3xxx_gpio1_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per -> gpio2 */
+static struct omap_hwmod_addr_space omap3xxx_gpio2_addrs[] = {
+ {
+ .pa_start = 0x49050000,
+ .pa_end = 0x490501ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__gpio2 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_gpio2_hwmod,
+ .addr = omap3xxx_gpio2_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per -> gpio3 */
+static struct omap_hwmod_addr_space omap3xxx_gpio3_addrs[] = {
+ {
+ .pa_start = 0x49052000,
+ .pa_end = 0x490521ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__gpio3 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_gpio3_hwmod,
+ .addr = omap3xxx_gpio3_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per -> gpio4 */
+static struct omap_hwmod_addr_space omap3xxx_gpio4_addrs[] = {
+ {
+ .pa_start = 0x49054000,
+ .pa_end = 0x490541ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__gpio4 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_gpio4_hwmod,
+ .addr = omap3xxx_gpio4_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per -> gpio5 */
+static struct omap_hwmod_addr_space omap3xxx_gpio5_addrs[] = {
+ {
+ .pa_start = 0x49056000,
+ .pa_end = 0x490561ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__gpio5 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_gpio5_hwmod,
+ .addr = omap3xxx_gpio5_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per -> gpio6 */
+static struct omap_hwmod_addr_space omap3xxx_gpio6_addrs[] = {
+ {
+ .pa_start = 0x49058000,
+ .pa_end = 0x490581ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__gpio6 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_gpio6_hwmod,
+ .addr = omap3xxx_gpio6_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dma_system -> L3 */
+static struct omap_hwmod_ocp_if omap3xxx_dma_system__l3 = {
+ .master = &omap3xxx_dma_system_hwmod,
+ .slave = &omap3xxx_l3_main_hwmod,
+ .clk = "core_l3_ick",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_dma_system_addrs[] = {
+ {
+ .pa_start = 0x48056000,
+ .pa_end = 0x48056fff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_cfg -> dma_system */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__dma_system = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_dma_system_hwmod,
+ .clk = "core_l4_ick",
+ .addr = omap3xxx_dma_system_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_mcbsp1_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x48074000,
+ .pa_end = 0x480740ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_core -> mcbsp1 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__mcbsp1 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_mcbsp1_hwmod,
+ .clk = "mcbsp1_ick",
+ .addr = omap3xxx_mcbsp1_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_mcbsp2_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x49022000,
+ .pa_end = 0x490220ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> mcbsp2 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__mcbsp2 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_mcbsp2_hwmod,
+ .clk = "mcbsp2_ick",
+ .addr = omap3xxx_mcbsp2_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_mcbsp3_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x49024000,
+ .pa_end = 0x490240ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> mcbsp3 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__mcbsp3 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_mcbsp3_hwmod,
+ .clk = "mcbsp3_ick",
+ .addr = omap3xxx_mcbsp3_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_mcbsp4_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x49026000,
+ .pa_end = 0x490260ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> mcbsp4 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__mcbsp4 = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_mcbsp4_hwmod,
+ .clk = "mcbsp4_ick",
+ .addr = omap3xxx_mcbsp4_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_mcbsp5_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x48096000,
+ .pa_end = 0x480960ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_core -> mcbsp5 */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__mcbsp5 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_mcbsp5_hwmod,
+ .clk = "mcbsp5_ick",
+ .addr = omap3xxx_mcbsp5_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_mcbsp2_sidetone_addrs[] = {
+ {
+ .name = "sidetone",
+ .pa_start = 0x49028000,
+ .pa_end = 0x490280ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> mcbsp2_sidetone */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__mcbsp2_sidetone = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_mcbsp2_sidetone_hwmod,
+ .clk = "mcbsp2_ick",
+ .addr = omap3xxx_mcbsp2_sidetone_addrs,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_mcbsp3_sidetone_addrs[] = {
+ {
+ .name = "sidetone",
+ .pa_start = 0x4902A000,
+ .pa_end = 0x4902A0ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> mcbsp3_sidetone */
+static struct omap_hwmod_ocp_if omap3xxx_l4_per__mcbsp3_sidetone = {
+ .master = &omap3xxx_l4_per_hwmod,
+ .slave = &omap3xxx_mcbsp3_sidetone_hwmod,
+ .clk = "mcbsp3_ick",
+ .addr = omap3xxx_mcbsp3_sidetone_addrs,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_mailbox_addrs[] = {
+ {
+ .pa_start = 0x48094000,
+ .pa_end = 0x480941ff,
+ .flags = ADDR_TYPE_RT,
+ },
+ { }
+};
+
+/* l4_core -> mailbox */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__mailbox = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_mailbox_hwmod,
+ .addr = omap3xxx_mailbox_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4 core -> mcspi1 interface */
+static struct omap_hwmod_ocp_if omap34xx_l4_core__mcspi1 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap34xx_mcspi1,
+ .clk = "mcspi1_ick",
+ .addr = omap2_mcspi1_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4 core -> mcspi2 interface */
+static struct omap_hwmod_ocp_if omap34xx_l4_core__mcspi2 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap34xx_mcspi2,
+ .clk = "mcspi2_ick",
+ .addr = omap2_mcspi2_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4 core -> mcspi3 interface */
+static struct omap_hwmod_ocp_if omap34xx_l4_core__mcspi3 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap34xx_mcspi3,
+ .clk = "mcspi3_ick",
+ .addr = omap2430_mcspi3_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4 core -> mcspi4 interface */
+static struct omap_hwmod_addr_space omap34xx_mcspi4_addr_space[] = {
+ {
+ .pa_start = 0x480ba000,
+ .pa_end = 0x480ba0ff,
+ .flags = ADDR_TYPE_RT,
+ },
+ { }
+};
+
+static struct omap_hwmod_ocp_if omap34xx_l4_core__mcspi4 = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap34xx_mcspi4,
+ .clk = "mcspi4_ick",
+ .addr = omap34xx_mcspi4_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_usb_host_hs__l3_main_2 = {
+ .master = &omap3xxx_usb_host_hs_hwmod,
+ .slave = &omap3xxx_l3_main_hwmod,
+ .clk = "core_l3_ick",
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap3xxx_usb_host_hs_addrs[] = {
+ {
+ .name = "uhh",
+ .pa_start = 0x48064000,
+ .pa_end = 0x480643ff,
+ .flags = ADDR_TYPE_RT
+ },
+ {
+ .name = "ohci",
+ .pa_start = 0x48064400,
+ .pa_end = 0x480647ff,
+ },
+ {
+ .name = "ehci",
+ .pa_start = 0x48064800,
+ .pa_end = 0x48064cff,
+ },
+ {}
+};
+
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__usb_host_hs = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_usb_host_hs_hwmod,
+ .clk = "usbhost_ick",
+ .addr = omap3xxx_usb_host_hs_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
static struct omap_hwmod_addr_space omap3xxx_usb_tll_hs_addrs[] = {
{
.name = "tll",
@@ -3519,183 +3110,187 @@ static struct omap_hwmod_ocp_if omap3xxx_l4_core__usb_tll_hs = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-static struct omap_hwmod_ocp_if *omap3xxx_usb_tll_hs_slaves[] = {
- &omap3xxx_l4_core__usb_tll_hs,
+/* l4_core -> hdq1w interface */
+static struct omap_hwmod_ocp_if omap3xxx_l4_core__hdq1w = {
+ .master = &omap3xxx_l4_core_hwmod,
+ .slave = &omap3xxx_hdq1w_hwmod,
+ .clk = "hdq_ick",
+ .addr = omap2_hdq1w_addr_space,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+ .flags = OMAP_FIREWALL_L4 | OCPIF_SWSUP_IDLE,
};
-static struct omap_hwmod omap3xxx_usb_tll_hs_hwmod = {
- .name = "usb_tll_hs",
- .class = &omap3xxx_usb_tll_hs_hwmod_class,
- .clkdm_name = "l3_init_clkdm",
- .mpu_irqs = omap3xxx_usb_tll_hs_irqs,
- .main_clk = "usbtll_fck",
- .prcm = {
- .omap2 = {
- .module_offs = CORE_MOD,
- .prcm_reg_id = 3,
- .module_bit = OMAP3430ES2_EN_USBTLL_SHIFT,
- .idlest_reg_id = 3,
- .idlest_idle_bit = OMAP3430ES2_ST_USBTLL_SHIFT,
- },
+/* l4_wkup -> 32ksync_counter */
+static struct omap_hwmod_addr_space omap3xxx_counter_32k_addrs[] = {
+ {
+ .pa_start = 0x48320000,
+ .pa_end = 0x4832001f,
+ .flags = ADDR_TYPE_RT
},
- .slaves = omap3xxx_usb_tll_hs_slaves,
- .slaves_cnt = ARRAY_SIZE(omap3xxx_usb_tll_hs_slaves),
-};
-
-static __initdata struct omap_hwmod *omap3xxx_hwmods[] = {
- &omap3xxx_l3_main_hwmod,
- &omap3xxx_l4_core_hwmod,
- &omap3xxx_l4_per_hwmod,
- &omap3xxx_l4_wkup_hwmod,
- &omap3xxx_mmc3_hwmod,
- &omap3xxx_mpu_hwmod,
-
- &omap3xxx_timer1_hwmod,
- &omap3xxx_timer2_hwmod,
- &omap3xxx_timer3_hwmod,
- &omap3xxx_timer4_hwmod,
- &omap3xxx_timer5_hwmod,
- &omap3xxx_timer6_hwmod,
- &omap3xxx_timer7_hwmod,
- &omap3xxx_timer8_hwmod,
- &omap3xxx_timer9_hwmod,
- &omap3xxx_timer10_hwmod,
- &omap3xxx_timer11_hwmod,
-
- &omap3xxx_wd_timer2_hwmod,
- &omap3xxx_uart1_hwmod,
- &omap3xxx_uart2_hwmod,
- &omap3xxx_uart3_hwmod,
-
- /* i2c class */
- &omap3xxx_i2c1_hwmod,
- &omap3xxx_i2c2_hwmod,
- &omap3xxx_i2c3_hwmod,
-
- /* gpio class */
- &omap3xxx_gpio1_hwmod,
- &omap3xxx_gpio2_hwmod,
- &omap3xxx_gpio3_hwmod,
- &omap3xxx_gpio4_hwmod,
- &omap3xxx_gpio5_hwmod,
- &omap3xxx_gpio6_hwmod,
-
- /* dma_system class*/
- &omap3xxx_dma_system_hwmod,
-
- /* mcbsp class */
- &omap3xxx_mcbsp1_hwmod,
- &omap3xxx_mcbsp2_hwmod,
- &omap3xxx_mcbsp3_hwmod,
- &omap3xxx_mcbsp4_hwmod,
- &omap3xxx_mcbsp5_hwmod,
- &omap3xxx_mcbsp2_sidetone_hwmod,
- &omap3xxx_mcbsp3_sidetone_hwmod,
-
-
- /* mcspi class */
- &omap34xx_mcspi1,
- &omap34xx_mcspi2,
- &omap34xx_mcspi3,
- &omap34xx_mcspi4,
+ { }
+};
+static struct omap_hwmod_ocp_if omap3xxx_l4_wkup__counter_32k = {
+ .master = &omap3xxx_l4_wkup_hwmod,
+ .slave = &omap3xxx_counter_32k_hwmod,
+ .clk = "omap_32ksync_ick",
+ .addr = omap3xxx_counter_32k_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_ocp_if *omap3xxx_hwmod_ocp_ifs[] __initdata = {
+ &omap3xxx_l3_main__l4_core,
+ &omap3xxx_l3_main__l4_per,
+ &omap3xxx_mpu__l3_main,
+ &omap3xxx_l4_core__l4_wkup,
+ &omap3xxx_l4_core__mmc3,
+ &omap3_l4_core__uart1,
+ &omap3_l4_core__uart2,
+ &omap3_l4_per__uart3,
+ &omap3_l4_core__i2c1,
+ &omap3_l4_core__i2c2,
+ &omap3_l4_core__i2c3,
+ &omap3xxx_l4_wkup__l4_sec,
+ &omap3xxx_l4_wkup__timer1,
+ &omap3xxx_l4_per__timer2,
+ &omap3xxx_l4_per__timer3,
+ &omap3xxx_l4_per__timer4,
+ &omap3xxx_l4_per__timer5,
+ &omap3xxx_l4_per__timer6,
+ &omap3xxx_l4_per__timer7,
+ &omap3xxx_l4_per__timer8,
+ &omap3xxx_l4_per__timer9,
+ &omap3xxx_l4_core__timer10,
+ &omap3xxx_l4_core__timer11,
+ &omap3xxx_l4_wkup__wd_timer2,
+ &omap3xxx_l4_wkup__gpio1,
+ &omap3xxx_l4_per__gpio2,
+ &omap3xxx_l4_per__gpio3,
+ &omap3xxx_l4_per__gpio4,
+ &omap3xxx_l4_per__gpio5,
+ &omap3xxx_l4_per__gpio6,
+ &omap3xxx_dma_system__l3,
+ &omap3xxx_l4_core__dma_system,
+ &omap3xxx_l4_core__mcbsp1,
+ &omap3xxx_l4_per__mcbsp2,
+ &omap3xxx_l4_per__mcbsp3,
+ &omap3xxx_l4_per__mcbsp4,
+ &omap3xxx_l4_core__mcbsp5,
+ &omap3xxx_l4_per__mcbsp2_sidetone,
+ &omap3xxx_l4_per__mcbsp3_sidetone,
+ &omap34xx_l4_core__mcspi1,
+ &omap34xx_l4_core__mcspi2,
+ &omap34xx_l4_core__mcspi3,
+ &omap34xx_l4_core__mcspi4,
+ &omap3xxx_l4_wkup__counter_32k,
NULL,
};
-/* GP-only hwmods */
-static __initdata struct omap_hwmod *omap3xxx_gp_hwmods[] = {
- &omap3xxx_timer12_hwmod,
+/* GP-only hwmod links */
+static struct omap_hwmod_ocp_if *omap3xxx_gp_hwmod_ocp_ifs[] __initdata = {
+ &omap3xxx_l4_sec__timer12,
NULL
};
-/* 3430ES1-only hwmods */
-static __initdata struct omap_hwmod *omap3430es1_hwmods[] = {
- &omap3430es1_dss_core_hwmod,
+/* 3430ES1-only hwmod links */
+static struct omap_hwmod_ocp_if *omap3430es1_hwmod_ocp_ifs[] __initdata = {
+ &omap3430es1_dss__l3,
+ &omap3430es1_l4_core__dss,
NULL
};
-/* 3430ES2+-only hwmods */
-static __initdata struct omap_hwmod *omap3430es2plus_hwmods[] = {
- &omap3xxx_dss_core_hwmod,
- &omap3xxx_usbhsotg_hwmod,
- &omap3xxx_usb_host_hs_hwmod,
- &omap3xxx_usb_tll_hs_hwmod,
+/* 3430ES2+-only hwmod links */
+static struct omap_hwmod_ocp_if *omap3430es2plus_hwmod_ocp_ifs[] __initdata = {
+ &omap3xxx_dss__l3,
+ &omap3xxx_l4_core__dss,
+ &omap3xxx_usbhsotg__l3,
+ &omap3xxx_l4_core__usbhsotg,
+ &omap3xxx_usb_host_hs__l3_main_2,
+ &omap3xxx_l4_core__usb_host_hs,
+ &omap3xxx_l4_core__usb_tll_hs,
NULL
};
-/* <= 3430ES3-only hwmods */
-static struct omap_hwmod *omap3430_pre_es3_hwmods[] __initdata = {
- &omap3xxx_pre_es3_mmc1_hwmod,
- &omap3xxx_pre_es3_mmc2_hwmod,
+/* <= 3430ES3-only hwmod links */
+static struct omap_hwmod_ocp_if *omap3430_pre_es3_hwmod_ocp_ifs[] __initdata = {
+ &omap3xxx_l4_core__pre_es3_mmc1,
+ &omap3xxx_l4_core__pre_es3_mmc2,
NULL
};
-/* 3430ES3+-only hwmods */
-static struct omap_hwmod *omap3430_es3plus_hwmods[] __initdata = {
- &omap3xxx_es3plus_mmc1_hwmod,
- &omap3xxx_es3plus_mmc2_hwmod,
+/* 3430ES3+-only hwmod links */
+static struct omap_hwmod_ocp_if *omap3430_es3plus_hwmod_ocp_ifs[] __initdata = {
+ &omap3xxx_l4_core__es3plus_mmc1,
+ &omap3xxx_l4_core__es3plus_mmc2,
NULL
};
-/* 34xx-only hwmods (all ES revisions) */
-static __initdata struct omap_hwmod *omap34xx_hwmods[] = {
- &omap3xxx_iva_hwmod,
- &omap34xx_sr1_hwmod,
- &omap34xx_sr2_hwmod,
- &omap3xxx_mailbox_hwmod,
+/* 34xx-only hwmod links (all ES revisions) */
+static struct omap_hwmod_ocp_if *omap34xx_hwmod_ocp_ifs[] __initdata = {
+ &omap3xxx_l3__iva,
+ &omap34xx_l4_core__sr1,
+ &omap34xx_l4_core__sr2,
+ &omap3xxx_l4_core__mailbox,
+ &omap3xxx_l4_core__hdq1w,
NULL
};
-/* 36xx-only hwmods (all ES revisions) */
-static __initdata struct omap_hwmod *omap36xx_hwmods[] = {
- &omap3xxx_iva_hwmod,
- &omap3xxx_uart4_hwmod,
- &omap3xxx_dss_core_hwmod,
- &omap36xx_sr1_hwmod,
- &omap36xx_sr2_hwmod,
- &omap3xxx_usbhsotg_hwmod,
- &omap3xxx_mailbox_hwmod,
- &omap3xxx_usb_host_hs_hwmod,
- &omap3xxx_usb_tll_hs_hwmod,
- &omap3xxx_es3plus_mmc1_hwmod,
- &omap3xxx_es3plus_mmc2_hwmod,
+/* 36xx-only hwmod links (all ES revisions) */
+static struct omap_hwmod_ocp_if *omap36xx_hwmod_ocp_ifs[] __initdata = {
+ &omap3xxx_l3__iva,
+ &omap36xx_l4_per__uart4,
+ &omap3xxx_dss__l3,
+ &omap3xxx_l4_core__dss,
+ &omap36xx_l4_core__sr1,
+ &omap36xx_l4_core__sr2,
+ &omap3xxx_usbhsotg__l3,
+ &omap3xxx_l4_core__usbhsotg,
+ &omap3xxx_l4_core__mailbox,
+ &omap3xxx_usb_host_hs__l3_main_2,
+ &omap3xxx_l4_core__usb_host_hs,
+ &omap3xxx_l4_core__usb_tll_hs,
+ &omap3xxx_l4_core__es3plus_mmc1,
+ &omap3xxx_l4_core__es3plus_mmc2,
+ &omap3xxx_l4_core__hdq1w,
NULL
};
-static __initdata struct omap_hwmod *am35xx_hwmods[] = {
- &omap3xxx_dss_core_hwmod, /* XXX ??? */
- &am35xx_usbhsotg_hwmod,
- &am35xx_uart4_hwmod,
- &omap3xxx_usb_host_hs_hwmod,
- &omap3xxx_usb_tll_hs_hwmod,
- &omap3xxx_es3plus_mmc1_hwmod,
- &omap3xxx_es3plus_mmc2_hwmod,
+static struct omap_hwmod_ocp_if *am35xx_hwmod_ocp_ifs[] __initdata = {
+ &omap3xxx_dss__l3,
+ &omap3xxx_l4_core__dss,
+ &am35xx_usbhsotg__l3,
+ &am35xx_l4_core__usbhsotg,
+ &am35xx_l4_core__uart4,
+ &omap3xxx_usb_host_hs__l3_main_2,
+ &omap3xxx_l4_core__usb_host_hs,
+ &omap3xxx_l4_core__usb_tll_hs,
+ &omap3xxx_l4_core__es3plus_mmc1,
+ &omap3xxx_l4_core__es3plus_mmc2,
NULL
};
-static __initdata struct omap_hwmod *omap3xxx_dss_hwmods[] = {
- /* dss class */
- &omap3xxx_dss_dispc_hwmod,
- &omap3xxx_dss_dsi1_hwmod,
- &omap3xxx_dss_rfbi_hwmod,
- &omap3xxx_dss_venc_hwmod,
+static struct omap_hwmod_ocp_if *omap3xxx_dss_hwmod_ocp_ifs[] __initdata = {
+ &omap3xxx_l4_core__dss_dispc,
+ &omap3xxx_l4_core__dss_dsi1,
+ &omap3xxx_l4_core__dss_rfbi,
+ &omap3xxx_l4_core__dss_venc,
NULL
};
int __init omap3xxx_hwmod_init(void)
{
int r;
- struct omap_hwmod **h = NULL;
+ struct omap_hwmod_ocp_if **h = NULL;
unsigned int rev;
- /* Register hwmods common to all OMAP3 */
- r = omap_hwmod_register(omap3xxx_hwmods);
+ /* Register hwmod links common to all OMAP3 */
+ r = omap_hwmod_register_links(omap3xxx_hwmod_ocp_ifs);
if (r < 0)
return r;
- /* Register GP-only hwmods. */
+ /* Register GP-only hwmod links. */
if (omap_type() == OMAP2_DEVICE_TYPE_GP) {
- r = omap_hwmod_register(omap3xxx_gp_hwmods);
+ r = omap_hwmod_register_links(omap3xxx_gp_hwmod_ocp_ifs);
if (r < 0)
return r;
}
@@ -3703,43 +3298,43 @@ int __init omap3xxx_hwmod_init(void)
rev = omap_rev();
/*
- * Register hwmods common to individual OMAP3 families, all
+ * Register hwmod links common to individual OMAP3 families, all
* silicon revisions (e.g., 34xx, or AM3505/3517, or 36xx)
* All possible revisions should be included in this conditional.
*/
if (rev == OMAP3430_REV_ES1_0 || rev == OMAP3430_REV_ES2_0 ||
rev == OMAP3430_REV_ES2_1 || rev == OMAP3430_REV_ES3_0 ||
rev == OMAP3430_REV_ES3_1 || rev == OMAP3430_REV_ES3_1_2) {
- h = omap34xx_hwmods;
+ h = omap34xx_hwmod_ocp_ifs;
} else if (rev == OMAP3517_REV_ES1_0 || rev == OMAP3517_REV_ES1_1) {
- h = am35xx_hwmods;
+ h = am35xx_hwmod_ocp_ifs;
} else if (rev == OMAP3630_REV_ES1_0 || rev == OMAP3630_REV_ES1_1 ||
rev == OMAP3630_REV_ES1_2) {
- h = omap36xx_hwmods;
+ h = omap36xx_hwmod_ocp_ifs;
} else {
WARN(1, "OMAP3 hwmod family init: unknown chip type\n");
return -EINVAL;
};
- r = omap_hwmod_register(h);
+ r = omap_hwmod_register_links(h);
if (r < 0)
return r;
/*
- * Register hwmods specific to certain ES levels of a
+ * Register hwmod links specific to certain ES levels of a
* particular family of silicon (e.g., 34xx ES1.0)
*/
h = NULL;
if (rev == OMAP3430_REV_ES1_0) {
- h = omap3430es1_hwmods;
+ h = omap3430es1_hwmod_ocp_ifs;
} else if (rev == OMAP3430_REV_ES2_0 || rev == OMAP3430_REV_ES2_1 ||
rev == OMAP3430_REV_ES3_0 || rev == OMAP3430_REV_ES3_1 ||
rev == OMAP3430_REV_ES3_1_2) {
- h = omap3430es2plus_hwmods;
+ h = omap3430es2plus_hwmod_ocp_ifs;
};
if (h) {
- r = omap_hwmod_register(h);
+ r = omap_hwmod_register_links(h);
if (r < 0)
return r;
}
@@ -3747,29 +3342,29 @@ int __init omap3xxx_hwmod_init(void)
h = NULL;
if (rev == OMAP3430_REV_ES1_0 || rev == OMAP3430_REV_ES2_0 ||
rev == OMAP3430_REV_ES2_1) {
- h = omap3430_pre_es3_hwmods;
+ h = omap3430_pre_es3_hwmod_ocp_ifs;
} else if (rev == OMAP3430_REV_ES3_0 || rev == OMAP3430_REV_ES3_1 ||
rev == OMAP3430_REV_ES3_1_2) {
- h = omap3430_es3plus_hwmods;
+ h = omap3430_es3plus_hwmod_ocp_ifs;
};
if (h)
- r = omap_hwmod_register(h);
+ r = omap_hwmod_register_links(h);
if (r < 0)
return r;
/*
* DSS code presumes that dss_core hwmod is handled first,
* _before_ any other DSS related hwmods so register common
- * DSS hwmods last to ensure that dss_core is already registered.
- * Otherwise some change things may happen, for ex. if dispc
- * is handled before dss_core and DSS is enabled in bootloader
- * DIPSC will be reset with outputs enabled which sometimes leads
- * to unrecoverable L3 error.
- * XXX The long-term fix to this is to ensure modules are set up
- * in dependency order in the hwmod core code.
+ * DSS hwmod links last to ensure that dss_core is already
+ * registered. Otherwise some change things may happen, for
+ * ex. if dispc is handled before dss_core and DSS is enabled
+ * in bootloader DISPC will be reset with outputs enabled
+ * which sometimes leads to unrecoverable L3 error. XXX The
+ * long-term fix to this is to ensure hwmods are set up in
+ * dependency order in the hwmod core code.
*/
- r = omap_hwmod_register(omap3xxx_dss_hwmods);
+ r = omap_hwmod_register_links(omap3xxx_dss_hwmod_ocp_ifs);
return r;
}
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index 6abc75753e42..950454a3fa31 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -1,7 +1,7 @@
/*
* Hardware modules present on the OMAP44xx chips
*
- * Copyright (C) 2009-2011 Texas Instruments, Inc.
+ * Copyright (C) 2009-2012 Texas Instruments, Inc.
* Copyright (C) 2009-2010 Nokia Corporation
*
* Paul Walmsley
@@ -44,41 +44,34 @@
#define OMAP44XX_IRQ_GIC_START 32
/* Base offset for all OMAP4 dma requests */
-#define OMAP44XX_DMA_REQ_START 1
-
-/* Backward references (IPs with Bus Master capability) */
-static struct omap_hwmod omap44xx_aess_hwmod;
-static struct omap_hwmod omap44xx_dma_system_hwmod;
-static struct omap_hwmod omap44xx_dmm_hwmod;
-static struct omap_hwmod omap44xx_dsp_hwmod;
-static struct omap_hwmod omap44xx_dss_hwmod;
-static struct omap_hwmod omap44xx_emif_fw_hwmod;
-static struct omap_hwmod omap44xx_hsi_hwmod;
-static struct omap_hwmod omap44xx_ipu_hwmod;
-static struct omap_hwmod omap44xx_iss_hwmod;
-static struct omap_hwmod omap44xx_iva_hwmod;
-static struct omap_hwmod omap44xx_l3_instr_hwmod;
-static struct omap_hwmod omap44xx_l3_main_1_hwmod;
-static struct omap_hwmod omap44xx_l3_main_2_hwmod;
-static struct omap_hwmod omap44xx_l3_main_3_hwmod;
-static struct omap_hwmod omap44xx_l4_abe_hwmod;
-static struct omap_hwmod omap44xx_l4_cfg_hwmod;
-static struct omap_hwmod omap44xx_l4_per_hwmod;
-static struct omap_hwmod omap44xx_l4_wkup_hwmod;
-static struct omap_hwmod omap44xx_mmc1_hwmod;
-static struct omap_hwmod omap44xx_mmc2_hwmod;
-static struct omap_hwmod omap44xx_mpu_hwmod;
-static struct omap_hwmod omap44xx_mpu_private_hwmod;
-static struct omap_hwmod omap44xx_usb_otg_hs_hwmod;
-static struct omap_hwmod omap44xx_usb_host_hs_hwmod;
-static struct omap_hwmod omap44xx_usb_tll_hs_hwmod;
+#define OMAP44XX_DMA_REQ_START 1
/*
- * Interconnects omap_hwmod structures
- * hwmods that compose the global OMAP interconnect
+ * IP blocks
*/
/*
+ * 'c2c_target_fw' class
+ * instance(s): c2c_target_fw
+ */
+static struct omap_hwmod_class omap44xx_c2c_target_fw_hwmod_class = {
+ .name = "c2c_target_fw",
+};
+
+/* c2c_target_fw */
+static struct omap_hwmod omap44xx_c2c_target_fw_hwmod = {
+ .name = "c2c_target_fw",
+ .class = &omap44xx_c2c_target_fw_hwmod_class,
+ .clkdm_name = "d2d_clkdm",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = OMAP4_CM_D2D_SAD2D_FW_CLKCTRL_OFFSET,
+ .context_offs = OMAP4_RM_D2D_SAD2D_FW_CONTEXT_OFFSET,
+ },
+ },
+};
+
+/*
* 'dmm' class
* instance(s): dmm
*/
@@ -92,51 +85,17 @@ static struct omap_hwmod_irq_info omap44xx_dmm_irqs[] = {
{ .irq = -1 }
};
-/* l3_main_1 -> dmm */
-static struct omap_hwmod_ocp_if omap44xx_l3_main_1__dmm = {
- .master = &omap44xx_l3_main_1_hwmod,
- .slave = &omap44xx_dmm_hwmod,
- .clk = "l3_div_ck",
- .user = OCP_USER_SDMA,
-};
-
-static struct omap_hwmod_addr_space omap44xx_dmm_addrs[] = {
- {
- .pa_start = 0x4e000000,
- .pa_end = 0x4e0007ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* mpu -> dmm */
-static struct omap_hwmod_ocp_if omap44xx_mpu__dmm = {
- .master = &omap44xx_mpu_hwmod,
- .slave = &omap44xx_dmm_hwmod,
- .clk = "l3_div_ck",
- .addr = omap44xx_dmm_addrs,
- .user = OCP_USER_MPU,
-};
-
-/* dmm slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_dmm_slaves[] = {
- &omap44xx_l3_main_1__dmm,
- &omap44xx_mpu__dmm,
-};
-
static struct omap_hwmod omap44xx_dmm_hwmod = {
.name = "dmm",
.class = &omap44xx_dmm_hwmod_class,
.clkdm_name = "l3_emif_clkdm",
+ .mpu_irqs = omap44xx_dmm_irqs,
.prcm = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_MEMIF_DMM_CLKCTRL_OFFSET,
.context_offs = OMAP4_RM_MEMIF_DMM_CONTEXT_OFFSET,
},
},
- .slaves = omap44xx_dmm_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_dmm_slaves),
- .mpu_irqs = omap44xx_dmm_irqs,
};
/*
@@ -148,38 +107,6 @@ static struct omap_hwmod_class omap44xx_emif_fw_hwmod_class = {
};
/* emif_fw */
-/* dmm -> emif_fw */
-static struct omap_hwmod_ocp_if omap44xx_dmm__emif_fw = {
- .master = &omap44xx_dmm_hwmod,
- .slave = &omap44xx_emif_fw_hwmod,
- .clk = "l3_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-static struct omap_hwmod_addr_space omap44xx_emif_fw_addrs[] = {
- {
- .pa_start = 0x4a20c000,
- .pa_end = 0x4a20c0ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_cfg -> emif_fw */
-static struct omap_hwmod_ocp_if omap44xx_l4_cfg__emif_fw = {
- .master = &omap44xx_l4_cfg_hwmod,
- .slave = &omap44xx_emif_fw_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_emif_fw_addrs,
- .user = OCP_USER_MPU,
-};
-
-/* emif_fw slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_emif_fw_slaves[] = {
- &omap44xx_dmm__emif_fw,
- &omap44xx_l4_cfg__emif_fw,
-};
-
static struct omap_hwmod omap44xx_emif_fw_hwmod = {
.name = "emif_fw",
.class = &omap44xx_emif_fw_hwmod_class,
@@ -190,8 +117,6 @@ static struct omap_hwmod omap44xx_emif_fw_hwmod = {
.context_offs = OMAP4_RM_MEMIF_EMIF_FW_CONTEXT_OFFSET,
},
},
- .slaves = omap44xx_emif_fw_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_emif_fw_slaves),
};
/*
@@ -203,28 +128,6 @@ static struct omap_hwmod_class omap44xx_l3_hwmod_class = {
};
/* l3_instr */
-/* iva -> l3_instr */
-static struct omap_hwmod_ocp_if omap44xx_iva__l3_instr = {
- .master = &omap44xx_iva_hwmod,
- .slave = &omap44xx_l3_instr_hwmod,
- .clk = "l3_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l3_main_3 -> l3_instr */
-static struct omap_hwmod_ocp_if omap44xx_l3_main_3__l3_instr = {
- .master = &omap44xx_l3_main_3_hwmod,
- .slave = &omap44xx_l3_instr_hwmod,
- .clk = "l3_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l3_instr slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_l3_instr_slaves[] = {
- &omap44xx_iva__l3_instr,
- &omap44xx_l3_main_3__l3_instr,
-};
-
static struct omap_hwmod omap44xx_l3_instr_hwmod = {
.name = "l3_instr",
.class = &omap44xx_l3_hwmod_class,
@@ -236,8 +139,6 @@ static struct omap_hwmod omap44xx_l3_instr_hwmod = {
.modulemode = MODULEMODE_HWCTRL,
},
},
- .slaves = omap44xx_l3_instr_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_l3_instr_slaves),
};
/* l3_main_1 */
@@ -247,83 +148,6 @@ static struct omap_hwmod_irq_info omap44xx_l3_main_1_irqs[] = {
{ .irq = -1 }
};
-/* dsp -> l3_main_1 */
-static struct omap_hwmod_ocp_if omap44xx_dsp__l3_main_1 = {
- .master = &omap44xx_dsp_hwmod,
- .slave = &omap44xx_l3_main_1_hwmod,
- .clk = "l3_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dss -> l3_main_1 */
-static struct omap_hwmod_ocp_if omap44xx_dss__l3_main_1 = {
- .master = &omap44xx_dss_hwmod,
- .slave = &omap44xx_l3_main_1_hwmod,
- .clk = "l3_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l3_main_2 -> l3_main_1 */
-static struct omap_hwmod_ocp_if omap44xx_l3_main_2__l3_main_1 = {
- .master = &omap44xx_l3_main_2_hwmod,
- .slave = &omap44xx_l3_main_1_hwmod,
- .clk = "l3_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_cfg -> l3_main_1 */
-static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_1 = {
- .master = &omap44xx_l4_cfg_hwmod,
- .slave = &omap44xx_l3_main_1_hwmod,
- .clk = "l4_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mmc1 -> l3_main_1 */
-static struct omap_hwmod_ocp_if omap44xx_mmc1__l3_main_1 = {
- .master = &omap44xx_mmc1_hwmod,
- .slave = &omap44xx_l3_main_1_hwmod,
- .clk = "l3_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mmc2 -> l3_main_1 */
-static struct omap_hwmod_ocp_if omap44xx_mmc2__l3_main_1 = {
- .master = &omap44xx_mmc2_hwmod,
- .slave = &omap44xx_l3_main_1_hwmod,
- .clk = "l3_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-static struct omap_hwmod_addr_space omap44xx_l3_main_1_addrs[] = {
- {
- .pa_start = 0x44000000,
- .pa_end = 0x44000fff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* mpu -> l3_main_1 */
-static struct omap_hwmod_ocp_if omap44xx_mpu__l3_main_1 = {
- .master = &omap44xx_mpu_hwmod,
- .slave = &omap44xx_l3_main_1_hwmod,
- .clk = "l3_div_ck",
- .addr = omap44xx_l3_main_1_addrs,
- .user = OCP_USER_MPU,
-};
-
-/* l3_main_1 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_l3_main_1_slaves[] = {
- &omap44xx_dsp__l3_main_1,
- &omap44xx_dss__l3_main_1,
- &omap44xx_l3_main_2__l3_main_1,
- &omap44xx_l4_cfg__l3_main_1,
- &omap44xx_mmc1__l3_main_1,
- &omap44xx_mmc2__l3_main_1,
- &omap44xx_mpu__l3_main_1,
-};
-
static struct omap_hwmod omap44xx_l3_main_1_hwmod = {
.name = "l3_main_1",
.class = &omap44xx_l3_hwmod_class,
@@ -335,97 +159,9 @@ static struct omap_hwmod omap44xx_l3_main_1_hwmod = {
.context_offs = OMAP4_RM_L3_1_L3_1_CONTEXT_OFFSET,
},
},
- .slaves = omap44xx_l3_main_1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_l3_main_1_slaves),
};
/* l3_main_2 */
-/* dma_system -> l3_main_2 */
-static struct omap_hwmod_ocp_if omap44xx_dma_system__l3_main_2 = {
- .master = &omap44xx_dma_system_hwmod,
- .slave = &omap44xx_l3_main_2_hwmod,
- .clk = "l3_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* hsi -> l3_main_2 */
-static struct omap_hwmod_ocp_if omap44xx_hsi__l3_main_2 = {
- .master = &omap44xx_hsi_hwmod,
- .slave = &omap44xx_l3_main_2_hwmod,
- .clk = "l3_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* ipu -> l3_main_2 */
-static struct omap_hwmod_ocp_if omap44xx_ipu__l3_main_2 = {
- .master = &omap44xx_ipu_hwmod,
- .slave = &omap44xx_l3_main_2_hwmod,
- .clk = "l3_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* iss -> l3_main_2 */
-static struct omap_hwmod_ocp_if omap44xx_iss__l3_main_2 = {
- .master = &omap44xx_iss_hwmod,
- .slave = &omap44xx_l3_main_2_hwmod,
- .clk = "l3_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* iva -> l3_main_2 */
-static struct omap_hwmod_ocp_if omap44xx_iva__l3_main_2 = {
- .master = &omap44xx_iva_hwmod,
- .slave = &omap44xx_l3_main_2_hwmod,
- .clk = "l3_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-static struct omap_hwmod_addr_space omap44xx_l3_main_2_addrs[] = {
- {
- .pa_start = 0x44800000,
- .pa_end = 0x44801fff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l3_main_1 -> l3_main_2 */
-static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l3_main_2 = {
- .master = &omap44xx_l3_main_1_hwmod,
- .slave = &omap44xx_l3_main_2_hwmod,
- .clk = "l3_div_ck",
- .addr = omap44xx_l3_main_2_addrs,
- .user = OCP_USER_MPU,
-};
-
-/* l4_cfg -> l3_main_2 */
-static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_2 = {
- .master = &omap44xx_l4_cfg_hwmod,
- .slave = &omap44xx_l3_main_2_hwmod,
- .clk = "l4_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* usb_otg_hs -> l3_main_2 */
-static struct omap_hwmod_ocp_if omap44xx_usb_otg_hs__l3_main_2 = {
- .master = &omap44xx_usb_otg_hs_hwmod,
- .slave = &omap44xx_l3_main_2_hwmod,
- .clk = "l3_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l3_main_2 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_l3_main_2_slaves[] = {
- &omap44xx_dma_system__l3_main_2,
- &omap44xx_hsi__l3_main_2,
- &omap44xx_ipu__l3_main_2,
- &omap44xx_iss__l3_main_2,
- &omap44xx_iva__l3_main_2,
- &omap44xx_l3_main_1__l3_main_2,
- &omap44xx_l4_cfg__l3_main_2,
- &omap44xx_usb_otg_hs__l3_main_2,
-};
-
static struct omap_hwmod omap44xx_l3_main_2_hwmod = {
.name = "l3_main_2",
.class = &omap44xx_l3_hwmod_class,
@@ -436,52 +172,9 @@ static struct omap_hwmod omap44xx_l3_main_2_hwmod = {
.context_offs = OMAP4_RM_L3_2_L3_2_CONTEXT_OFFSET,
},
},
- .slaves = omap44xx_l3_main_2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_l3_main_2_slaves),
};
/* l3_main_3 */
-static struct omap_hwmod_addr_space omap44xx_l3_main_3_addrs[] = {
- {
- .pa_start = 0x45000000,
- .pa_end = 0x45000fff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l3_main_1 -> l3_main_3 */
-static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l3_main_3 = {
- .master = &omap44xx_l3_main_1_hwmod,
- .slave = &omap44xx_l3_main_3_hwmod,
- .clk = "l3_div_ck",
- .addr = omap44xx_l3_main_3_addrs,
- .user = OCP_USER_MPU,
-};
-
-/* l3_main_2 -> l3_main_3 */
-static struct omap_hwmod_ocp_if omap44xx_l3_main_2__l3_main_3 = {
- .master = &omap44xx_l3_main_2_hwmod,
- .slave = &omap44xx_l3_main_3_hwmod,
- .clk = "l3_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_cfg -> l3_main_3 */
-static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_3 = {
- .master = &omap44xx_l4_cfg_hwmod,
- .slave = &omap44xx_l3_main_3_hwmod,
- .clk = "l4_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l3_main_3 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_l3_main_3_slaves[] = {
- &omap44xx_l3_main_1__l3_main_3,
- &omap44xx_l3_main_2__l3_main_3,
- &omap44xx_l4_cfg__l3_main_3,
-};
-
static struct omap_hwmod omap44xx_l3_main_3_hwmod = {
.name = "l3_main_3",
.class = &omap44xx_l3_hwmod_class,
@@ -493,8 +186,6 @@ static struct omap_hwmod omap44xx_l3_main_3_hwmod = {
.modulemode = MODULEMODE_HWCTRL,
},
},
- .slaves = omap44xx_l3_main_3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_l3_main_3_slaves),
};
/*
@@ -506,46 +197,6 @@ static struct omap_hwmod_class omap44xx_l4_hwmod_class = {
};
/* l4_abe */
-/* aess -> l4_abe */
-static struct omap_hwmod_ocp_if omap44xx_aess__l4_abe = {
- .master = &omap44xx_aess_hwmod,
- .slave = &omap44xx_l4_abe_hwmod,
- .clk = "ocp_abe_iclk",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dsp -> l4_abe */
-static struct omap_hwmod_ocp_if omap44xx_dsp__l4_abe = {
- .master = &omap44xx_dsp_hwmod,
- .slave = &omap44xx_l4_abe_hwmod,
- .clk = "ocp_abe_iclk",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l3_main_1 -> l4_abe */
-static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l4_abe = {
- .master = &omap44xx_l3_main_1_hwmod,
- .slave = &omap44xx_l4_abe_hwmod,
- .clk = "l3_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mpu -> l4_abe */
-static struct omap_hwmod_ocp_if omap44xx_mpu__l4_abe = {
- .master = &omap44xx_mpu_hwmod,
- .slave = &omap44xx_l4_abe_hwmod,
- .clk = "ocp_abe_iclk",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_abe slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_l4_abe_slaves[] = {
- &omap44xx_aess__l4_abe,
- &omap44xx_dsp__l4_abe,
- &omap44xx_l3_main_1__l4_abe,
- &omap44xx_mpu__l4_abe,
-};
-
static struct omap_hwmod omap44xx_l4_abe_hwmod = {
.name = "l4_abe",
.class = &omap44xx_l4_hwmod_class,
@@ -555,24 +206,9 @@ static struct omap_hwmod omap44xx_l4_abe_hwmod = {
.clkctrl_offs = OMAP4_CM1_ABE_L4ABE_CLKCTRL_OFFSET,
},
},
- .slaves = omap44xx_l4_abe_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_l4_abe_slaves),
};
/* l4_cfg */
-/* l3_main_1 -> l4_cfg */
-static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l4_cfg = {
- .master = &omap44xx_l3_main_1_hwmod,
- .slave = &omap44xx_l4_cfg_hwmod,
- .clk = "l3_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_cfg slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_l4_cfg_slaves[] = {
- &omap44xx_l3_main_1__l4_cfg,
-};
-
static struct omap_hwmod omap44xx_l4_cfg_hwmod = {
.name = "l4_cfg",
.class = &omap44xx_l4_hwmod_class,
@@ -583,24 +219,9 @@ static struct omap_hwmod omap44xx_l4_cfg_hwmod = {
.context_offs = OMAP4_RM_L4CFG_L4_CFG_CONTEXT_OFFSET,
},
},
- .slaves = omap44xx_l4_cfg_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_l4_cfg_slaves),
};
/* l4_per */
-/* l3_main_2 -> l4_per */
-static struct omap_hwmod_ocp_if omap44xx_l3_main_2__l4_per = {
- .master = &omap44xx_l3_main_2_hwmod,
- .slave = &omap44xx_l4_per_hwmod,
- .clk = "l3_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_per slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_l4_per_slaves[] = {
- &omap44xx_l3_main_2__l4_per,
-};
-
static struct omap_hwmod omap44xx_l4_per_hwmod = {
.name = "l4_per",
.class = &omap44xx_l4_hwmod_class,
@@ -611,24 +232,9 @@ static struct omap_hwmod omap44xx_l4_per_hwmod = {
.context_offs = OMAP4_RM_L4PER_L4_PER_CONTEXT_OFFSET,
},
},
- .slaves = omap44xx_l4_per_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_l4_per_slaves),
};
/* l4_wkup */
-/* l4_cfg -> l4_wkup */
-static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l4_wkup = {
- .master = &omap44xx_l4_cfg_hwmod,
- .slave = &omap44xx_l4_wkup_hwmod,
- .clk = "l4_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* l4_wkup slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_l4_wkup_slaves[] = {
- &omap44xx_l4_cfg__l4_wkup,
-};
-
static struct omap_hwmod omap44xx_l4_wkup_hwmod = {
.name = "l4_wkup",
.class = &omap44xx_l4_hwmod_class,
@@ -639,8 +245,6 @@ static struct omap_hwmod omap44xx_l4_wkup_hwmod = {
.context_offs = OMAP4_RM_WKUP_L4WKUP_CONTEXT_OFFSET,
},
},
- .slaves = omap44xx_l4_wkup_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_l4_wkup_slaves),
};
/*
@@ -652,25 +256,32 @@ static struct omap_hwmod_class omap44xx_mpu_bus_hwmod_class = {
};
/* mpu_private */
-/* mpu -> mpu_private */
-static struct omap_hwmod_ocp_if omap44xx_mpu__mpu_private = {
- .master = &omap44xx_mpu_hwmod,
- .slave = &omap44xx_mpu_private_hwmod,
- .clk = "l3_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mpu_private slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mpu_private_slaves[] = {
- &omap44xx_mpu__mpu_private,
-};
-
static struct omap_hwmod omap44xx_mpu_private_hwmod = {
.name = "mpu_private",
.class = &omap44xx_mpu_bus_hwmod_class,
.clkdm_name = "mpuss_clkdm",
- .slaves = omap44xx_mpu_private_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_mpu_private_slaves),
+};
+
+/*
+ * 'ocp_wp_noc' class
+ * instance(s): ocp_wp_noc
+ */
+static struct omap_hwmod_class omap44xx_ocp_wp_noc_hwmod_class = {
+ .name = "ocp_wp_noc",
+};
+
+/* ocp_wp_noc */
+static struct omap_hwmod omap44xx_ocp_wp_noc_hwmod = {
+ .name = "ocp_wp_noc",
+ .class = &omap44xx_ocp_wp_noc_hwmod_class,
+ .clkdm_name = "l3_instr_clkdm",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = OMAP4_CM_L3INSTR_OCP_WP1_CLKCTRL_OFFSET,
+ .context_offs = OMAP4_RM_L3INSTR_OCP_WP1_CONTEXT_OFFSET,
+ .modulemode = MODULEMODE_HWCTRL,
+ },
+ },
};
/*
@@ -681,41 +292,7 @@ static struct omap_hwmod omap44xx_mpu_private_hwmod = {
* - They still need to be validated with the driver
* properly adapted to omap_hwmod / omap_device
*
- * c2c
- * c2c_target_fw
- * cm_core
- * cm_core_aon
- * ctrl_module_core
- * ctrl_module_pad_core
- * ctrl_module_pad_wkup
- * ctrl_module_wkup
- * debugss
- * efuse_ctrl_cust
- * efuse_ctrl_std
- * elm
- * emif1
- * emif2
- * fdif
- * gpmc
- * gpu
- * hdq1w
- * mcasp
- * mpu_c0
- * mpu_c1
- * ocmc_ram
- * ocp2scp_usb_phy
- * ocp_wp_noc
- * prcm_mpu
- * prm
- * scrm
- * sl2if
- * slimbus1
- * slimbus2
- * usb_host_fs
- * usb_host_hs
- * usb_phy_cm
- * usb_tll_hs
- * usim
+ * usim
*/
/*
@@ -756,53 +333,6 @@ static struct omap_hwmod_dma_info omap44xx_aess_sdma_reqs[] = {
{ .dma_req = -1 }
};
-/* aess master ports */
-static struct omap_hwmod_ocp_if *omap44xx_aess_masters[] = {
- &omap44xx_aess__l4_abe,
-};
-
-static struct omap_hwmod_addr_space omap44xx_aess_addrs[] = {
- {
- .pa_start = 0x401f1000,
- .pa_end = 0x401f13ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_abe -> aess */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__aess = {
- .master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_aess_hwmod,
- .clk = "ocp_abe_iclk",
- .addr = omap44xx_aess_addrs,
- .user = OCP_USER_MPU,
-};
-
-static struct omap_hwmod_addr_space omap44xx_aess_dma_addrs[] = {
- {
- .pa_start = 0x490f1000,
- .pa_end = 0x490f13ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_abe -> aess (dma) */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__aess_dma = {
- .master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_aess_hwmod,
- .clk = "ocp_abe_iclk",
- .addr = omap44xx_aess_dma_addrs,
- .user = OCP_USER_SDMA,
-};
-
-/* aess slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_aess_slaves[] = {
- &omap44xx_l4_abe__aess,
- &omap44xx_l4_abe__aess_dma,
-};
-
static struct omap_hwmod omap44xx_aess_hwmod = {
.name = "aess",
.class = &omap44xx_aess_hwmod_class,
@@ -817,37 +347,41 @@ static struct omap_hwmod omap44xx_aess_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_aess_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_aess_slaves),
- .masters = omap44xx_aess_masters,
- .masters_cnt = ARRAY_SIZE(omap44xx_aess_masters),
};
/*
- * 'bandgap' class
- * bangap reference for ldo regulators
+ * 'c2c' class
+ * chip 2 chip interface used to plug the ape soc (omap) with an external modem
+ * soc
*/
-static struct omap_hwmod_class omap44xx_bandgap_hwmod_class = {
- .name = "bandgap",
+static struct omap_hwmod_class omap44xx_c2c_hwmod_class = {
+ .name = "c2c",
};
-/* bandgap */
-static struct omap_hwmod_opt_clk bandgap_opt_clks[] = {
- { .role = "fclk", .clk = "bandgap_fclk" },
+/* c2c */
+static struct omap_hwmod_irq_info omap44xx_c2c_irqs[] = {
+ { .irq = 88 + OMAP44XX_IRQ_GIC_START },
+ { .irq = -1 }
};
-static struct omap_hwmod omap44xx_bandgap_hwmod = {
- .name = "bandgap",
- .class = &omap44xx_bandgap_hwmod_class,
- .clkdm_name = "l4_wkup_clkdm",
+static struct omap_hwmod_dma_info omap44xx_c2c_sdma_reqs[] = {
+ { .dma_req = 68 + OMAP44XX_DMA_REQ_START },
+ { .dma_req = -1 }
+};
+
+static struct omap_hwmod omap44xx_c2c_hwmod = {
+ .name = "c2c",
+ .class = &omap44xx_c2c_hwmod_class,
+ .clkdm_name = "d2d_clkdm",
+ .mpu_irqs = omap44xx_c2c_irqs,
+ .sdma_reqs = omap44xx_c2c_sdma_reqs,
.prcm = {
.omap4 = {
- .clkctrl_offs = OMAP4_CM_WKUP_BANDGAP_CLKCTRL_OFFSET,
+ .clkctrl_offs = OMAP4_CM_D2D_SAD2D_CLKCTRL_OFFSET,
+ .context_offs = OMAP4_RM_D2D_SAD2D_CONTEXT_OFFSET,
},
},
- .opt_clks = bandgap_opt_clks,
- .opt_clks_cnt = ARRAY_SIZE(bandgap_opt_clks),
};
/*
@@ -870,30 +404,6 @@ static struct omap_hwmod_class omap44xx_counter_hwmod_class = {
};
/* counter_32k */
-static struct omap_hwmod omap44xx_counter_32k_hwmod;
-static struct omap_hwmod_addr_space omap44xx_counter_32k_addrs[] = {
- {
- .pa_start = 0x4a304000,
- .pa_end = 0x4a30401f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_wkup -> counter_32k */
-static struct omap_hwmod_ocp_if omap44xx_l4_wkup__counter_32k = {
- .master = &omap44xx_l4_wkup_hwmod,
- .slave = &omap44xx_counter_32k_hwmod,
- .clk = "l4_wkup_clk_mux_ck",
- .addr = omap44xx_counter_32k_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* counter_32k slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_counter_32k_slaves[] = {
- &omap44xx_l4_wkup__counter_32k,
-};
-
static struct omap_hwmod omap44xx_counter_32k_hwmod = {
.name = "counter_32k",
.class = &omap44xx_counter_hwmod_class,
@@ -906,8 +416,83 @@ static struct omap_hwmod omap44xx_counter_32k_hwmod = {
.context_offs = OMAP4_RM_WKUP_SYNCTIMER_CONTEXT_OFFSET,
},
},
- .slaves = omap44xx_counter_32k_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_counter_32k_slaves),
+};
+
+/*
+ * 'ctrl_module' class
+ * attila core control module + core pad control module + wkup pad control
+ * module + attila wkup control module
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_ctrl_module_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .sysc_flags = SYSC_HAS_SIDLEMODE,
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ SIDLE_SMART_WKUP),
+ .sysc_fields = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_ctrl_module_hwmod_class = {
+ .name = "ctrl_module",
+ .sysc = &omap44xx_ctrl_module_sysc,
+};
+
+/* ctrl_module_core */
+static struct omap_hwmod_irq_info omap44xx_ctrl_module_core_irqs[] = {
+ { .irq = 8 + OMAP44XX_IRQ_GIC_START },
+ { .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_ctrl_module_core_hwmod = {
+ .name = "ctrl_module_core",
+ .class = &omap44xx_ctrl_module_hwmod_class,
+ .clkdm_name = "l4_cfg_clkdm",
+ .mpu_irqs = omap44xx_ctrl_module_core_irqs,
+};
+
+/* ctrl_module_pad_core */
+static struct omap_hwmod omap44xx_ctrl_module_pad_core_hwmod = {
+ .name = "ctrl_module_pad_core",
+ .class = &omap44xx_ctrl_module_hwmod_class,
+ .clkdm_name = "l4_cfg_clkdm",
+};
+
+/* ctrl_module_wkup */
+static struct omap_hwmod omap44xx_ctrl_module_wkup_hwmod = {
+ .name = "ctrl_module_wkup",
+ .class = &omap44xx_ctrl_module_hwmod_class,
+ .clkdm_name = "l4_wkup_clkdm",
+};
+
+/* ctrl_module_pad_wkup */
+static struct omap_hwmod omap44xx_ctrl_module_pad_wkup_hwmod = {
+ .name = "ctrl_module_pad_wkup",
+ .class = &omap44xx_ctrl_module_hwmod_class,
+ .clkdm_name = "l4_wkup_clkdm",
+};
+
+/*
+ * 'debugss' class
+ * debug and emulation sub system
+ */
+
+static struct omap_hwmod_class omap44xx_debugss_hwmod_class = {
+ .name = "debugss",
+};
+
+/* debugss */
+static struct omap_hwmod omap44xx_debugss_hwmod = {
+ .name = "debugss",
+ .class = &omap44xx_debugss_hwmod_class,
+ .clkdm_name = "emu_sys_clkdm",
+ .main_clk = "trace_clk_div_ck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = OMAP4_CM_EMU_DEBUGSS_CLKCTRL_OFFSET,
+ .context_offs = OMAP4_RM_EMU_DEBUGSS_CONTEXT_OFFSET,
+ },
+ },
};
/*
@@ -950,34 +535,6 @@ static struct omap_hwmod_irq_info omap44xx_dma_system_irqs[] = {
{ .irq = -1 }
};
-/* dma_system master ports */
-static struct omap_hwmod_ocp_if *omap44xx_dma_system_masters[] = {
- &omap44xx_dma_system__l3_main_2,
-};
-
-static struct omap_hwmod_addr_space omap44xx_dma_system_addrs[] = {
- {
- .pa_start = 0x4a056000,
- .pa_end = 0x4a056fff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_cfg -> dma_system */
-static struct omap_hwmod_ocp_if omap44xx_l4_cfg__dma_system = {
- .master = &omap44xx_l4_cfg_hwmod,
- .slave = &omap44xx_dma_system_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_dma_system_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dma_system slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_dma_system_slaves[] = {
- &omap44xx_l4_cfg__dma_system,
-};
-
static struct omap_hwmod omap44xx_dma_system_hwmod = {
.name = "dma_system",
.class = &omap44xx_dma_hwmod_class,
@@ -991,10 +548,6 @@ static struct omap_hwmod omap44xx_dma_system_hwmod = {
},
},
.dev_attr = &dma_dev_attr,
- .slaves = omap44xx_dma_system_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_dma_system_slaves),
- .masters = omap44xx_dma_system_masters,
- .masters_cnt = ARRAY_SIZE(omap44xx_dma_system_masters),
};
/*
@@ -1018,7 +571,6 @@ static struct omap_hwmod_class omap44xx_dmic_hwmod_class = {
};
/* dmic */
-static struct omap_hwmod omap44xx_dmic_hwmod;
static struct omap_hwmod_irq_info omap44xx_dmic_irqs[] = {
{ .irq = 114 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
@@ -1029,50 +581,6 @@ static struct omap_hwmod_dma_info omap44xx_dmic_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_dmic_addrs[] = {
- {
- .name = "mpu",
- .pa_start = 0x4012e000,
- .pa_end = 0x4012e07f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_abe -> dmic */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__dmic = {
- .master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_dmic_hwmod,
- .clk = "ocp_abe_iclk",
- .addr = omap44xx_dmic_addrs,
- .user = OCP_USER_MPU,
-};
-
-static struct omap_hwmod_addr_space omap44xx_dmic_dma_addrs[] = {
- {
- .name = "dma",
- .pa_start = 0x4902e000,
- .pa_end = 0x4902e07f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_abe -> dmic (dma) */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__dmic_dma = {
- .master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_dmic_hwmod,
- .clk = "ocp_abe_iclk",
- .addr = omap44xx_dmic_dma_addrs,
- .user = OCP_USER_SDMA,
-};
-
-/* dmic slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_dmic_slaves[] = {
- &omap44xx_l4_abe__dmic,
- &omap44xx_l4_abe__dmic_dma,
-};
-
static struct omap_hwmod omap44xx_dmic_hwmod = {
.name = "dmic",
.class = &omap44xx_dmic_hwmod_class,
@@ -1087,8 +595,6 @@ static struct omap_hwmod omap44xx_dmic_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_dmic_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_dmic_slaves),
};
/*
@@ -1107,53 +613,8 @@ static struct omap_hwmod_irq_info omap44xx_dsp_irqs[] = {
};
static struct omap_hwmod_rst_info omap44xx_dsp_resets[] = {
- { .name = "mmu_cache", .rst_shift = 1 },
-};
-
-static struct omap_hwmod_rst_info omap44xx_dsp_c0_resets[] = {
{ .name = "dsp", .rst_shift = 0 },
-};
-
-/* dsp -> iva */
-static struct omap_hwmod_ocp_if omap44xx_dsp__iva = {
- .master = &omap44xx_dsp_hwmod,
- .slave = &omap44xx_iva_hwmod,
- .clk = "dpll_iva_m5x2_ck",
-};
-
-/* dsp master ports */
-static struct omap_hwmod_ocp_if *omap44xx_dsp_masters[] = {
- &omap44xx_dsp__l3_main_1,
- &omap44xx_dsp__l4_abe,
- &omap44xx_dsp__iva,
-};
-
-/* l4_cfg -> dsp */
-static struct omap_hwmod_ocp_if omap44xx_l4_cfg__dsp = {
- .master = &omap44xx_l4_cfg_hwmod,
- .slave = &omap44xx_dsp_hwmod,
- .clk = "l4_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* dsp slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_dsp_slaves[] = {
- &omap44xx_l4_cfg__dsp,
-};
-
-/* Pseudo hwmod for reset control purpose only */
-static struct omap_hwmod omap44xx_dsp_c0_hwmod = {
- .name = "dsp_c0",
- .class = &omap44xx_dsp_hwmod_class,
- .clkdm_name = "tesla_clkdm",
- .flags = HWMOD_INIT_NO_RESET,
- .rst_lines = omap44xx_dsp_c0_resets,
- .rst_lines_cnt = ARRAY_SIZE(omap44xx_dsp_c0_resets),
- .prcm = {
- .omap4 = {
- .rstctrl_offs = OMAP4_RM_TESLA_RSTCTRL_OFFSET,
- },
- },
+ { .name = "mmu_cache", .rst_shift = 1 },
};
static struct omap_hwmod omap44xx_dsp_hwmod = {
@@ -1172,10 +633,6 @@ static struct omap_hwmod omap44xx_dsp_hwmod = {
.modulemode = MODULEMODE_HWCTRL,
},
},
- .slaves = omap44xx_dsp_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_dsp_slaves),
- .masters = omap44xx_dsp_masters,
- .masters_cnt = ARRAY_SIZE(omap44xx_dsp_masters),
};
/*
@@ -1196,53 +653,6 @@ static struct omap_hwmod_class omap44xx_dss_hwmod_class = {
};
/* dss */
-/* dss master ports */
-static struct omap_hwmod_ocp_if *omap44xx_dss_masters[] = {
- &omap44xx_dss__l3_main_1,
-};
-
-static struct omap_hwmod_addr_space omap44xx_dss_dma_addrs[] = {
- {
- .pa_start = 0x58000000,
- .pa_end = 0x5800007f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l3_main_2 -> dss */
-static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss = {
- .master = &omap44xx_l3_main_2_hwmod,
- .slave = &omap44xx_dss_hwmod,
- .clk = "dss_fck",
- .addr = omap44xx_dss_dma_addrs,
- .user = OCP_USER_SDMA,
-};
-
-static struct omap_hwmod_addr_space omap44xx_dss_addrs[] = {
- {
- .pa_start = 0x48040000,
- .pa_end = 0x4804007f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> dss */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__dss = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_dss_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_dss_addrs,
- .user = OCP_USER_MPU,
-};
-
-/* dss slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_dss_slaves[] = {
- &omap44xx_l3_main_2__dss,
- &omap44xx_l4_per__dss,
-};
-
static struct omap_hwmod_opt_clk dss_opt_clks[] = {
{ .role = "sys_clk", .clk = "dss_sys_clk" },
{ .role = "tv_clk", .clk = "dss_tv_clk" },
@@ -1263,10 +673,6 @@ static struct omap_hwmod omap44xx_dss_hwmod = {
},
.opt_clks = dss_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_opt_clks),
- .slaves = omap44xx_dss_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_dss_slaves),
- .masters = omap44xx_dss_masters,
- .masters_cnt = ARRAY_SIZE(omap44xx_dss_masters),
};
/*
@@ -1293,7 +699,6 @@ static struct omap_hwmod_class omap44xx_dispc_hwmod_class = {
};
/* dss_dispc */
-static struct omap_hwmod omap44xx_dss_dispc_hwmod;
static struct omap_hwmod_irq_info omap44xx_dss_dispc_irqs[] = {
{ .irq = 25 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
@@ -1304,53 +709,11 @@ static struct omap_hwmod_dma_info omap44xx_dss_dispc_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_dss_dispc_dma_addrs[] = {
- {
- .pa_start = 0x58001000,
- .pa_end = 0x58001fff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l3_main_2 -> dss_dispc */
-static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dispc = {
- .master = &omap44xx_l3_main_2_hwmod,
- .slave = &omap44xx_dss_dispc_hwmod,
- .clk = "dss_fck",
- .addr = omap44xx_dss_dispc_dma_addrs,
- .user = OCP_USER_SDMA,
-};
-
-static struct omap_hwmod_addr_space omap44xx_dss_dispc_addrs[] = {
- {
- .pa_start = 0x48041000,
- .pa_end = 0x48041fff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
static struct omap_dss_dispc_dev_attr omap44xx_dss_dispc_dev_attr = {
.manager_count = 3,
.has_framedonetv_irq = 1
};
-/* l4_per -> dss_dispc */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__dss_dispc = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_dss_dispc_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_dss_dispc_addrs,
- .user = OCP_USER_MPU,
-};
-
-/* dss_dispc slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_dss_dispc_slaves[] = {
- &omap44xx_l3_main_2__dss_dispc,
- &omap44xx_l4_per__dss_dispc,
-};
-
static struct omap_hwmod omap44xx_dss_dispc_hwmod = {
.name = "dss_dispc",
.class = &omap44xx_dispc_hwmod_class,
@@ -1364,8 +727,6 @@ static struct omap_hwmod omap44xx_dss_dispc_hwmod = {
.context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
},
},
- .slaves = omap44xx_dss_dispc_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_dss_dispc_slaves),
.dev_attr = &omap44xx_dss_dispc_dev_attr
};
@@ -1391,7 +752,6 @@ static struct omap_hwmod_class omap44xx_dsi_hwmod_class = {
};
/* dss_dsi1 */
-static struct omap_hwmod omap44xx_dss_dsi1_hwmod;
static struct omap_hwmod_irq_info omap44xx_dss_dsi1_irqs[] = {
{ .irq = 53 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
@@ -1402,48 +762,6 @@ static struct omap_hwmod_dma_info omap44xx_dss_dsi1_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_dss_dsi1_dma_addrs[] = {
- {
- .pa_start = 0x58004000,
- .pa_end = 0x580041ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l3_main_2 -> dss_dsi1 */
-static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dsi1 = {
- .master = &omap44xx_l3_main_2_hwmod,
- .slave = &omap44xx_dss_dsi1_hwmod,
- .clk = "dss_fck",
- .addr = omap44xx_dss_dsi1_dma_addrs,
- .user = OCP_USER_SDMA,
-};
-
-static struct omap_hwmod_addr_space omap44xx_dss_dsi1_addrs[] = {
- {
- .pa_start = 0x48044000,
- .pa_end = 0x480441ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> dss_dsi1 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__dss_dsi1 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_dss_dsi1_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_dss_dsi1_addrs,
- .user = OCP_USER_MPU,
-};
-
-/* dss_dsi1 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_dss_dsi1_slaves[] = {
- &omap44xx_l3_main_2__dss_dsi1,
- &omap44xx_l4_per__dss_dsi1,
-};
-
static struct omap_hwmod_opt_clk dss_dsi1_opt_clks[] = {
{ .role = "sys_clk", .clk = "dss_sys_clk" },
};
@@ -1463,12 +781,9 @@ static struct omap_hwmod omap44xx_dss_dsi1_hwmod = {
},
.opt_clks = dss_dsi1_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_dsi1_opt_clks),
- .slaves = omap44xx_dss_dsi1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_dss_dsi1_slaves),
};
/* dss_dsi2 */
-static struct omap_hwmod omap44xx_dss_dsi2_hwmod;
static struct omap_hwmod_irq_info omap44xx_dss_dsi2_irqs[] = {
{ .irq = 84 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
@@ -1479,48 +794,6 @@ static struct omap_hwmod_dma_info omap44xx_dss_dsi2_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_dss_dsi2_dma_addrs[] = {
- {
- .pa_start = 0x58005000,
- .pa_end = 0x580051ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l3_main_2 -> dss_dsi2 */
-static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dsi2 = {
- .master = &omap44xx_l3_main_2_hwmod,
- .slave = &omap44xx_dss_dsi2_hwmod,
- .clk = "dss_fck",
- .addr = omap44xx_dss_dsi2_dma_addrs,
- .user = OCP_USER_SDMA,
-};
-
-static struct omap_hwmod_addr_space omap44xx_dss_dsi2_addrs[] = {
- {
- .pa_start = 0x48045000,
- .pa_end = 0x480451ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> dss_dsi2 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__dss_dsi2 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_dss_dsi2_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_dss_dsi2_addrs,
- .user = OCP_USER_MPU,
-};
-
-/* dss_dsi2 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_dss_dsi2_slaves[] = {
- &omap44xx_l3_main_2__dss_dsi2,
- &omap44xx_l4_per__dss_dsi2,
-};
-
static struct omap_hwmod_opt_clk dss_dsi2_opt_clks[] = {
{ .role = "sys_clk", .clk = "dss_sys_clk" },
};
@@ -1540,8 +813,6 @@ static struct omap_hwmod omap44xx_dss_dsi2_hwmod = {
},
.opt_clks = dss_dsi2_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_dsi2_opt_clks),
- .slaves = omap44xx_dss_dsi2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_dss_dsi2_slaves),
};
/*
@@ -1565,7 +836,6 @@ static struct omap_hwmod_class omap44xx_hdmi_hwmod_class = {
};
/* dss_hdmi */
-static struct omap_hwmod omap44xx_dss_hdmi_hwmod;
static struct omap_hwmod_irq_info omap44xx_dss_hdmi_irqs[] = {
{ .irq = 101 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
@@ -1576,48 +846,6 @@ static struct omap_hwmod_dma_info omap44xx_dss_hdmi_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_dss_hdmi_dma_addrs[] = {
- {
- .pa_start = 0x58006000,
- .pa_end = 0x58006fff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l3_main_2 -> dss_hdmi */
-static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_hdmi = {
- .master = &omap44xx_l3_main_2_hwmod,
- .slave = &omap44xx_dss_hdmi_hwmod,
- .clk = "dss_fck",
- .addr = omap44xx_dss_hdmi_dma_addrs,
- .user = OCP_USER_SDMA,
-};
-
-static struct omap_hwmod_addr_space omap44xx_dss_hdmi_addrs[] = {
- {
- .pa_start = 0x48046000,
- .pa_end = 0x48046fff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> dss_hdmi */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__dss_hdmi = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_dss_hdmi_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_dss_hdmi_addrs,
- .user = OCP_USER_MPU,
-};
-
-/* dss_hdmi slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_dss_hdmi_slaves[] = {
- &omap44xx_l3_main_2__dss_hdmi,
- &omap44xx_l4_per__dss_hdmi,
-};
-
static struct omap_hwmod_opt_clk dss_hdmi_opt_clks[] = {
{ .role = "sys_clk", .clk = "dss_sys_clk" },
};
@@ -1637,8 +865,6 @@ static struct omap_hwmod omap44xx_dss_hdmi_hwmod = {
},
.opt_clks = dss_hdmi_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_hdmi_opt_clks),
- .slaves = omap44xx_dss_hdmi_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_dss_hdmi_slaves),
};
/*
@@ -1662,54 +888,11 @@ static struct omap_hwmod_class omap44xx_rfbi_hwmod_class = {
};
/* dss_rfbi */
-static struct omap_hwmod omap44xx_dss_rfbi_hwmod;
static struct omap_hwmod_dma_info omap44xx_dss_rfbi_sdma_reqs[] = {
{ .dma_req = 13 + OMAP44XX_DMA_REQ_START },
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_dss_rfbi_dma_addrs[] = {
- {
- .pa_start = 0x58002000,
- .pa_end = 0x580020ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l3_main_2 -> dss_rfbi */
-static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_rfbi = {
- .master = &omap44xx_l3_main_2_hwmod,
- .slave = &omap44xx_dss_rfbi_hwmod,
- .clk = "dss_fck",
- .addr = omap44xx_dss_rfbi_dma_addrs,
- .user = OCP_USER_SDMA,
-};
-
-static struct omap_hwmod_addr_space omap44xx_dss_rfbi_addrs[] = {
- {
- .pa_start = 0x48042000,
- .pa_end = 0x480420ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> dss_rfbi */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__dss_rfbi = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_dss_rfbi_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_dss_rfbi_addrs,
- .user = OCP_USER_MPU,
-};
-
-/* dss_rfbi slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_dss_rfbi_slaves[] = {
- &omap44xx_l3_main_2__dss_rfbi,
- &omap44xx_l4_per__dss_rfbi,
-};
-
static struct omap_hwmod_opt_clk dss_rfbi_opt_clks[] = {
{ .role = "ick", .clk = "dss_fck" },
};
@@ -1728,8 +911,6 @@ static struct omap_hwmod omap44xx_dss_rfbi_hwmod = {
},
.opt_clks = dss_rfbi_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_rfbi_opt_clks),
- .slaves = omap44xx_dss_rfbi_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_dss_rfbi_slaves),
};
/*
@@ -1742,62 +923,165 @@ static struct omap_hwmod_class omap44xx_venc_hwmod_class = {
};
/* dss_venc */
-static struct omap_hwmod omap44xx_dss_venc_hwmod;
-static struct omap_hwmod_addr_space omap44xx_dss_venc_dma_addrs[] = {
- {
- .pa_start = 0x58003000,
- .pa_end = 0x580030ff,
- .flags = ADDR_TYPE_RT
+static struct omap_hwmod omap44xx_dss_venc_hwmod = {
+ .name = "dss_venc",
+ .class = &omap44xx_venc_hwmod_class,
+ .clkdm_name = "l3_dss_clkdm",
+ .main_clk = "dss_tv_clk",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
+ .context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
+ },
},
- { }
};
-/* l3_main_2 -> dss_venc */
-static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_venc = {
- .master = &omap44xx_l3_main_2_hwmod,
- .slave = &omap44xx_dss_venc_hwmod,
- .clk = "dss_fck",
- .addr = omap44xx_dss_venc_dma_addrs,
- .user = OCP_USER_SDMA,
+/*
+ * 'elm' class
+ * bch error location module
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_elm_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+ SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+ SYSS_HAS_RESET_STATUS),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
};
-static struct omap_hwmod_addr_space omap44xx_dss_venc_addrs[] = {
- {
- .pa_start = 0x48043000,
- .pa_end = 0x480430ff,
- .flags = ADDR_TYPE_RT
+static struct omap_hwmod_class omap44xx_elm_hwmod_class = {
+ .name = "elm",
+ .sysc = &omap44xx_elm_sysc,
+};
+
+/* elm */
+static struct omap_hwmod_irq_info omap44xx_elm_irqs[] = {
+ { .irq = 4 + OMAP44XX_IRQ_GIC_START },
+ { .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_elm_hwmod = {
+ .name = "elm",
+ .class = &omap44xx_elm_hwmod_class,
+ .clkdm_name = "l4_per_clkdm",
+ .mpu_irqs = omap44xx_elm_irqs,
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = OMAP4_CM_L4PER_ELM_CLKCTRL_OFFSET,
+ .context_offs = OMAP4_RM_L4PER_ELM_CONTEXT_OFFSET,
+ },
},
- { }
};
-/* l4_per -> dss_venc */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__dss_venc = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_dss_venc_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_dss_venc_addrs,
- .user = OCP_USER_MPU,
+/*
+ * 'emif' class
+ * external memory interface no1
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_emif_sysc = {
+ .rev_offs = 0x0000,
};
-/* dss_venc slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_dss_venc_slaves[] = {
- &omap44xx_l3_main_2__dss_venc,
- &omap44xx_l4_per__dss_venc,
+static struct omap_hwmod_class omap44xx_emif_hwmod_class = {
+ .name = "emif",
+ .sysc = &omap44xx_emif_sysc,
};
-static struct omap_hwmod omap44xx_dss_venc_hwmod = {
- .name = "dss_venc",
- .class = &omap44xx_venc_hwmod_class,
- .clkdm_name = "l3_dss_clkdm",
- .main_clk = "dss_tv_clk",
+/* emif1 */
+static struct omap_hwmod_irq_info omap44xx_emif1_irqs[] = {
+ { .irq = 110 + OMAP44XX_IRQ_GIC_START },
+ { .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_emif1_hwmod = {
+ .name = "emif1",
+ .class = &omap44xx_emif_hwmod_class,
+ .clkdm_name = "l3_emif_clkdm",
+ .flags = HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
+ .mpu_irqs = omap44xx_emif1_irqs,
+ .main_clk = "ddrphy_ck",
.prcm = {
.omap4 = {
- .clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
- .context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
+ .clkctrl_offs = OMAP4_CM_MEMIF_EMIF_1_CLKCTRL_OFFSET,
+ .context_offs = OMAP4_RM_MEMIF_EMIF_1_CONTEXT_OFFSET,
+ .modulemode = MODULEMODE_HWCTRL,
+ },
+ },
+};
+
+/* emif2 */
+static struct omap_hwmod_irq_info omap44xx_emif2_irqs[] = {
+ { .irq = 111 + OMAP44XX_IRQ_GIC_START },
+ { .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_emif2_hwmod = {
+ .name = "emif2",
+ .class = &omap44xx_emif_hwmod_class,
+ .clkdm_name = "l3_emif_clkdm",
+ .flags = HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
+ .mpu_irqs = omap44xx_emif2_irqs,
+ .main_clk = "ddrphy_ck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = OMAP4_CM_MEMIF_EMIF_2_CLKCTRL_OFFSET,
+ .context_offs = OMAP4_RM_MEMIF_EMIF_2_CONTEXT_OFFSET,
+ .modulemode = MODULEMODE_HWCTRL,
+ },
+ },
+};
+
+/*
+ * 'fdif' class
+ * face detection hw accelerator module
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_fdif_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ /*
+ * FDIF needs 100 OCP clk cycles delay after a softreset before
+ * accessing sysconfig again.
+ * The lowest frequency at the moment for L3 bus is 100 MHz, so
+ * 1usec delay is needed. Add an x2 margin to be safe (2 usecs).
+ *
+ * TODO: Indicate errata when available.
+ */
+ .srst_udelay = 2,
+ .sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_RESET_STATUS |
+ SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_fdif_hwmod_class = {
+ .name = "fdif",
+ .sysc = &omap44xx_fdif_sysc,
+};
+
+/* fdif */
+static struct omap_hwmod_irq_info omap44xx_fdif_irqs[] = {
+ { .irq = 69 + OMAP44XX_IRQ_GIC_START },
+ { .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_fdif_hwmod = {
+ .name = "fdif",
+ .class = &omap44xx_fdif_hwmod_class,
+ .clkdm_name = "iss_clkdm",
+ .mpu_irqs = omap44xx_fdif_irqs,
+ .main_clk = "fdif_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = OMAP4_CM_CAM_FDIF_CLKCTRL_OFFSET,
+ .context_offs = OMAP4_RM_CAM_FDIF_CONTEXT_OFFSET,
+ .modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_dss_venc_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_dss_venc_slaves),
};
/*
@@ -1830,35 +1114,11 @@ static struct omap_gpio_dev_attr gpio_dev_attr = {
};
/* gpio1 */
-static struct omap_hwmod omap44xx_gpio1_hwmod;
static struct omap_hwmod_irq_info omap44xx_gpio1_irqs[] = {
{ .irq = 29 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_gpio1_addrs[] = {
- {
- .pa_start = 0x4a310000,
- .pa_end = 0x4a3101ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_wkup -> gpio1 */
-static struct omap_hwmod_ocp_if omap44xx_l4_wkup__gpio1 = {
- .master = &omap44xx_l4_wkup_hwmod,
- .slave = &omap44xx_gpio1_hwmod,
- .clk = "l4_wkup_clk_mux_ck",
- .addr = omap44xx_gpio1_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* gpio1 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_gpio1_slaves[] = {
- &omap44xx_l4_wkup__gpio1,
-};
-
static struct omap_hwmod_opt_clk gpio1_opt_clks[] = {
{ .role = "dbclk", .clk = "gpio1_dbclk" },
};
@@ -1879,40 +1139,14 @@ static struct omap_hwmod omap44xx_gpio1_hwmod = {
.opt_clks = gpio1_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(gpio1_opt_clks),
.dev_attr = &gpio_dev_attr,
- .slaves = omap44xx_gpio1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_gpio1_slaves),
};
/* gpio2 */
-static struct omap_hwmod omap44xx_gpio2_hwmod;
static struct omap_hwmod_irq_info omap44xx_gpio2_irqs[] = {
{ .irq = 30 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_gpio2_addrs[] = {
- {
- .pa_start = 0x48055000,
- .pa_end = 0x480551ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> gpio2 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__gpio2 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_gpio2_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_gpio2_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* gpio2 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_gpio2_slaves[] = {
- &omap44xx_l4_per__gpio2,
-};
-
static struct omap_hwmod_opt_clk gpio2_opt_clks[] = {
{ .role = "dbclk", .clk = "gpio2_dbclk" },
};
@@ -1934,40 +1168,14 @@ static struct omap_hwmod omap44xx_gpio2_hwmod = {
.opt_clks = gpio2_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(gpio2_opt_clks),
.dev_attr = &gpio_dev_attr,
- .slaves = omap44xx_gpio2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_gpio2_slaves),
};
/* gpio3 */
-static struct omap_hwmod omap44xx_gpio3_hwmod;
static struct omap_hwmod_irq_info omap44xx_gpio3_irqs[] = {
{ .irq = 31 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_gpio3_addrs[] = {
- {
- .pa_start = 0x48057000,
- .pa_end = 0x480571ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> gpio3 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__gpio3 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_gpio3_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_gpio3_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* gpio3 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_gpio3_slaves[] = {
- &omap44xx_l4_per__gpio3,
-};
-
static struct omap_hwmod_opt_clk gpio3_opt_clks[] = {
{ .role = "dbclk", .clk = "gpio3_dbclk" },
};
@@ -1989,40 +1197,14 @@ static struct omap_hwmod omap44xx_gpio3_hwmod = {
.opt_clks = gpio3_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(gpio3_opt_clks),
.dev_attr = &gpio_dev_attr,
- .slaves = omap44xx_gpio3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_gpio3_slaves),
};
/* gpio4 */
-static struct omap_hwmod omap44xx_gpio4_hwmod;
static struct omap_hwmod_irq_info omap44xx_gpio4_irqs[] = {
{ .irq = 32 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_gpio4_addrs[] = {
- {
- .pa_start = 0x48059000,
- .pa_end = 0x480591ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> gpio4 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__gpio4 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_gpio4_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_gpio4_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* gpio4 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_gpio4_slaves[] = {
- &omap44xx_l4_per__gpio4,
-};
-
static struct omap_hwmod_opt_clk gpio4_opt_clks[] = {
{ .role = "dbclk", .clk = "gpio4_dbclk" },
};
@@ -2044,40 +1226,14 @@ static struct omap_hwmod omap44xx_gpio4_hwmod = {
.opt_clks = gpio4_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(gpio4_opt_clks),
.dev_attr = &gpio_dev_attr,
- .slaves = omap44xx_gpio4_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_gpio4_slaves),
};
/* gpio5 */
-static struct omap_hwmod omap44xx_gpio5_hwmod;
static struct omap_hwmod_irq_info omap44xx_gpio5_irqs[] = {
{ .irq = 33 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_gpio5_addrs[] = {
- {
- .pa_start = 0x4805b000,
- .pa_end = 0x4805b1ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> gpio5 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__gpio5 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_gpio5_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_gpio5_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* gpio5 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_gpio5_slaves[] = {
- &omap44xx_l4_per__gpio5,
-};
-
static struct omap_hwmod_opt_clk gpio5_opt_clks[] = {
{ .role = "dbclk", .clk = "gpio5_dbclk" },
};
@@ -2099,40 +1255,14 @@ static struct omap_hwmod omap44xx_gpio5_hwmod = {
.opt_clks = gpio5_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(gpio5_opt_clks),
.dev_attr = &gpio_dev_attr,
- .slaves = omap44xx_gpio5_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_gpio5_slaves),
};
/* gpio6 */
-static struct omap_hwmod omap44xx_gpio6_hwmod;
static struct omap_hwmod_irq_info omap44xx_gpio6_irqs[] = {
{ .irq = 34 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_gpio6_addrs[] = {
- {
- .pa_start = 0x4805d000,
- .pa_end = 0x4805d1ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> gpio6 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__gpio6 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_gpio6_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_gpio6_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* gpio6 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_gpio6_slaves[] = {
- &omap44xx_l4_per__gpio6,
-};
-
static struct omap_hwmod_opt_clk gpio6_opt_clks[] = {
{ .role = "dbclk", .clk = "gpio6_dbclk" },
};
@@ -2154,8 +1284,135 @@ static struct omap_hwmod omap44xx_gpio6_hwmod = {
.opt_clks = gpio6_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(gpio6_opt_clks),
.dev_attr = &gpio_dev_attr,
- .slaves = omap44xx_gpio6_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_gpio6_slaves),
+};
+
+/*
+ * 'gpmc' class
+ * general purpose memory controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_gpmc_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_AUTOIDLE | SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_gpmc_hwmod_class = {
+ .name = "gpmc",
+ .sysc = &omap44xx_gpmc_sysc,
+};
+
+/* gpmc */
+static struct omap_hwmod_irq_info omap44xx_gpmc_irqs[] = {
+ { .irq = 20 + OMAP44XX_IRQ_GIC_START },
+ { .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_gpmc_sdma_reqs[] = {
+ { .dma_req = 3 + OMAP44XX_DMA_REQ_START },
+ { .dma_req = -1 }
+};
+
+static struct omap_hwmod omap44xx_gpmc_hwmod = {
+ .name = "gpmc",
+ .class = &omap44xx_gpmc_hwmod_class,
+ .clkdm_name = "l3_2_clkdm",
+ .flags = HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
+ .mpu_irqs = omap44xx_gpmc_irqs,
+ .sdma_reqs = omap44xx_gpmc_sdma_reqs,
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = OMAP4_CM_L3_2_GPMC_CLKCTRL_OFFSET,
+ .context_offs = OMAP4_RM_L3_2_GPMC_CONTEXT_OFFSET,
+ .modulemode = MODULEMODE_HWCTRL,
+ },
+ },
+};
+
+/*
+ * 'gpu' class
+ * 2d/3d graphics accelerator
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_gpu_sysc = {
+ .rev_offs = 0x1fc00,
+ .sysc_offs = 0x1fc10,
+ .sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
+ MSTANDBY_SMART | MSTANDBY_SMART_WKUP),
+ .sysc_fields = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_gpu_hwmod_class = {
+ .name = "gpu",
+ .sysc = &omap44xx_gpu_sysc,
+};
+
+/* gpu */
+static struct omap_hwmod_irq_info omap44xx_gpu_irqs[] = {
+ { .irq = 21 + OMAP44XX_IRQ_GIC_START },
+ { .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_gpu_hwmod = {
+ .name = "gpu",
+ .class = &omap44xx_gpu_hwmod_class,
+ .clkdm_name = "l3_gfx_clkdm",
+ .mpu_irqs = omap44xx_gpu_irqs,
+ .main_clk = "gpu_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = OMAP4_CM_GFX_GFX_CLKCTRL_OFFSET,
+ .context_offs = OMAP4_RM_GFX_GFX_CONTEXT_OFFSET,
+ .modulemode = MODULEMODE_SWCTRL,
+ },
+ },
+};
+
+/*
+ * 'hdq1w' class
+ * hdq / 1-wire serial interface controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_hdq1w_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0014,
+ .syss_offs = 0x0018,
+ .sysc_flags = (SYSC_HAS_AUTOIDLE | SYSC_HAS_SOFTRESET |
+ SYSS_HAS_RESET_STATUS),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_hdq1w_hwmod_class = {
+ .name = "hdq1w",
+ .sysc = &omap44xx_hdq1w_sysc,
+};
+
+/* hdq1w */
+static struct omap_hwmod_irq_info omap44xx_hdq1w_irqs[] = {
+ { .irq = 58 + OMAP44XX_IRQ_GIC_START },
+ { .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_hdq1w_hwmod = {
+ .name = "hdq1w",
+ .class = &omap44xx_hdq1w_hwmod_class,
+ .clkdm_name = "l4_per_clkdm",
+ .flags = HWMOD_INIT_NO_RESET, /* XXX temporary */
+ .mpu_irqs = omap44xx_hdq1w_irqs,
+ .main_clk = "hdq1w_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = OMAP4_CM_L4PER_HDQ1W_CLKCTRL_OFFSET,
+ .context_offs = OMAP4_RM_L4PER_HDQ1W_CONTEXT_OFFSET,
+ .modulemode = MODULEMODE_SWCTRL,
+ },
+ },
};
/*
@@ -2190,34 +1447,6 @@ static struct omap_hwmod_irq_info omap44xx_hsi_irqs[] = {
{ .irq = -1 }
};
-/* hsi master ports */
-static struct omap_hwmod_ocp_if *omap44xx_hsi_masters[] = {
- &omap44xx_hsi__l3_main_2,
-};
-
-static struct omap_hwmod_addr_space omap44xx_hsi_addrs[] = {
- {
- .pa_start = 0x4a058000,
- .pa_end = 0x4a05bfff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_cfg -> hsi */
-static struct omap_hwmod_ocp_if omap44xx_l4_cfg__hsi = {
- .master = &omap44xx_l4_cfg_hwmod,
- .slave = &omap44xx_hsi_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_hsi_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* hsi slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_hsi_slaves[] = {
- &omap44xx_l4_cfg__hsi,
-};
-
static struct omap_hwmod omap44xx_hsi_hwmod = {
.name = "hsi",
.class = &omap44xx_hsi_hwmod_class,
@@ -2231,10 +1460,6 @@ static struct omap_hwmod omap44xx_hsi_hwmod = {
.modulemode = MODULEMODE_HWCTRL,
},
},
- .slaves = omap44xx_hsi_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_hsi_slaves),
- .masters = omap44xx_hsi_masters,
- .masters_cnt = ARRAY_SIZE(omap44xx_hsi_masters),
};
/*
@@ -2262,11 +1487,11 @@ static struct omap_hwmod_class omap44xx_i2c_hwmod_class = {
};
static struct omap_i2c_dev_attr i2c_dev_attr = {
- .flags = OMAP_I2C_FLAG_BUS_SHIFT_NONE,
+ .flags = OMAP_I2C_FLAG_BUS_SHIFT_NONE |
+ OMAP_I2C_FLAG_RESET_REGS_POSTIDLE,
};
/* i2c1 */
-static struct omap_hwmod omap44xx_i2c1_hwmod;
static struct omap_hwmod_irq_info omap44xx_i2c1_irqs[] = {
{ .irq = 56 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
@@ -2278,29 +1503,6 @@ static struct omap_hwmod_dma_info omap44xx_i2c1_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_i2c1_addrs[] = {
- {
- .pa_start = 0x48070000,
- .pa_end = 0x480700ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> i2c1 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__i2c1 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_i2c1_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_i2c1_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* i2c1 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_i2c1_slaves[] = {
- &omap44xx_l4_per__i2c1,
-};
-
static struct omap_hwmod omap44xx_i2c1_hwmod = {
.name = "i2c1",
.class = &omap44xx_i2c_hwmod_class,
@@ -2316,13 +1518,10 @@ static struct omap_hwmod omap44xx_i2c1_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_i2c1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_i2c1_slaves),
.dev_attr = &i2c_dev_attr,
};
/* i2c2 */
-static struct omap_hwmod omap44xx_i2c2_hwmod;
static struct omap_hwmod_irq_info omap44xx_i2c2_irqs[] = {
{ .irq = 57 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
@@ -2334,29 +1533,6 @@ static struct omap_hwmod_dma_info omap44xx_i2c2_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_i2c2_addrs[] = {
- {
- .pa_start = 0x48072000,
- .pa_end = 0x480720ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> i2c2 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__i2c2 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_i2c2_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_i2c2_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* i2c2 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_i2c2_slaves[] = {
- &omap44xx_l4_per__i2c2,
-};
-
static struct omap_hwmod omap44xx_i2c2_hwmod = {
.name = "i2c2",
.class = &omap44xx_i2c_hwmod_class,
@@ -2372,13 +1548,10 @@ static struct omap_hwmod omap44xx_i2c2_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_i2c2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_i2c2_slaves),
.dev_attr = &i2c_dev_attr,
};
/* i2c3 */
-static struct omap_hwmod omap44xx_i2c3_hwmod;
static struct omap_hwmod_irq_info omap44xx_i2c3_irqs[] = {
{ .irq = 61 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
@@ -2390,29 +1563,6 @@ static struct omap_hwmod_dma_info omap44xx_i2c3_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_i2c3_addrs[] = {
- {
- .pa_start = 0x48060000,
- .pa_end = 0x480600ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> i2c3 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__i2c3 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_i2c3_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_i2c3_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* i2c3 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_i2c3_slaves[] = {
- &omap44xx_l4_per__i2c3,
-};
-
static struct omap_hwmod omap44xx_i2c3_hwmod = {
.name = "i2c3",
.class = &omap44xx_i2c_hwmod_class,
@@ -2428,13 +1578,10 @@ static struct omap_hwmod omap44xx_i2c3_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_i2c3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_i2c3_slaves),
.dev_attr = &i2c_dev_attr,
};
/* i2c4 */
-static struct omap_hwmod omap44xx_i2c4_hwmod;
static struct omap_hwmod_irq_info omap44xx_i2c4_irqs[] = {
{ .irq = 62 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
@@ -2446,29 +1593,6 @@ static struct omap_hwmod_dma_info omap44xx_i2c4_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_i2c4_addrs[] = {
- {
- .pa_start = 0x48350000,
- .pa_end = 0x483500ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> i2c4 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__i2c4 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_i2c4_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_i2c4_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* i2c4 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_i2c4_slaves[] = {
- &omap44xx_l4_per__i2c4,
-};
-
static struct omap_hwmod omap44xx_i2c4_hwmod = {
.name = "i2c4",
.class = &omap44xx_i2c_hwmod_class,
@@ -2484,8 +1608,6 @@ static struct omap_hwmod omap44xx_i2c4_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_i2c4_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_i2c4_slaves),
.dev_attr = &i2c_dev_attr,
};
@@ -2504,66 +1626,12 @@ static struct omap_hwmod_irq_info omap44xx_ipu_irqs[] = {
{ .irq = -1 }
};
-static struct omap_hwmod_rst_info omap44xx_ipu_c0_resets[] = {
+static struct omap_hwmod_rst_info omap44xx_ipu_resets[] = {
{ .name = "cpu0", .rst_shift = 0 },
-};
-
-static struct omap_hwmod_rst_info omap44xx_ipu_c1_resets[] = {
{ .name = "cpu1", .rst_shift = 1 },
-};
-
-static struct omap_hwmod_rst_info omap44xx_ipu_resets[] = {
{ .name = "mmu_cache", .rst_shift = 2 },
};
-/* ipu master ports */
-static struct omap_hwmod_ocp_if *omap44xx_ipu_masters[] = {
- &omap44xx_ipu__l3_main_2,
-};
-
-/* l3_main_2 -> ipu */
-static struct omap_hwmod_ocp_if omap44xx_l3_main_2__ipu = {
- .master = &omap44xx_l3_main_2_hwmod,
- .slave = &omap44xx_ipu_hwmod,
- .clk = "l3_div_ck",
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* ipu slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_ipu_slaves[] = {
- &omap44xx_l3_main_2__ipu,
-};
-
-/* Pseudo hwmod for reset control purpose only */
-static struct omap_hwmod omap44xx_ipu_c0_hwmod = {
- .name = "ipu_c0",
- .class = &omap44xx_ipu_hwmod_class,
- .clkdm_name = "ducati_clkdm",
- .flags = HWMOD_INIT_NO_RESET,
- .rst_lines = omap44xx_ipu_c0_resets,
- .rst_lines_cnt = ARRAY_SIZE(omap44xx_ipu_c0_resets),
- .prcm = {
- .omap4 = {
- .rstctrl_offs = OMAP4_RM_DUCATI_RSTCTRL_OFFSET,
- },
- },
-};
-
-/* Pseudo hwmod for reset control purpose only */
-static struct omap_hwmod omap44xx_ipu_c1_hwmod = {
- .name = "ipu_c1",
- .class = &omap44xx_ipu_hwmod_class,
- .clkdm_name = "ducati_clkdm",
- .flags = HWMOD_INIT_NO_RESET,
- .rst_lines = omap44xx_ipu_c1_resets,
- .rst_lines_cnt = ARRAY_SIZE(omap44xx_ipu_c1_resets),
- .prcm = {
- .omap4 = {
- .rstctrl_offs = OMAP4_RM_DUCATI_RSTCTRL_OFFSET,
- },
- },
-};
-
static struct omap_hwmod omap44xx_ipu_hwmod = {
.name = "ipu",
.class = &omap44xx_ipu_hwmod_class,
@@ -2580,10 +1648,6 @@ static struct omap_hwmod omap44xx_ipu_hwmod = {
.modulemode = MODULEMODE_HWCTRL,
},
},
- .slaves = omap44xx_ipu_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_ipu_slaves),
- .masters = omap44xx_ipu_masters,
- .masters_cnt = ARRAY_SIZE(omap44xx_ipu_masters),
};
/*
@@ -2630,34 +1694,6 @@ static struct omap_hwmod_dma_info omap44xx_iss_sdma_reqs[] = {
{ .dma_req = -1 }
};
-/* iss master ports */
-static struct omap_hwmod_ocp_if *omap44xx_iss_masters[] = {
- &omap44xx_iss__l3_main_2,
-};
-
-static struct omap_hwmod_addr_space omap44xx_iss_addrs[] = {
- {
- .pa_start = 0x52000000,
- .pa_end = 0x520000ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l3_main_2 -> iss */
-static struct omap_hwmod_ocp_if omap44xx_l3_main_2__iss = {
- .master = &omap44xx_l3_main_2_hwmod,
- .slave = &omap44xx_iss_hwmod,
- .clk = "l3_div_ck",
- .addr = omap44xx_iss_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* iss slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_iss_slaves[] = {
- &omap44xx_l3_main_2__iss,
-};
-
static struct omap_hwmod_opt_clk iss_opt_clks[] = {
{ .role = "ctrlclk", .clk = "iss_ctrlclk" },
};
@@ -2678,10 +1714,6 @@ static struct omap_hwmod omap44xx_iss_hwmod = {
},
.opt_clks = iss_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(iss_opt_clks),
- .slaves = omap44xx_iss_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_iss_slaves),
- .masters = omap44xx_iss_masters,
- .masters_cnt = ARRAY_SIZE(omap44xx_iss_masters),
};
/*
@@ -2702,75 +1734,9 @@ static struct omap_hwmod_irq_info omap44xx_iva_irqs[] = {
};
static struct omap_hwmod_rst_info omap44xx_iva_resets[] = {
- { .name = "logic", .rst_shift = 2 },
-};
-
-static struct omap_hwmod_rst_info omap44xx_iva_seq0_resets[] = {
{ .name = "seq0", .rst_shift = 0 },
-};
-
-static struct omap_hwmod_rst_info omap44xx_iva_seq1_resets[] = {
{ .name = "seq1", .rst_shift = 1 },
-};
-
-/* iva master ports */
-static struct omap_hwmod_ocp_if *omap44xx_iva_masters[] = {
- &omap44xx_iva__l3_main_2,
- &omap44xx_iva__l3_instr,
-};
-
-static struct omap_hwmod_addr_space omap44xx_iva_addrs[] = {
- {
- .pa_start = 0x5a000000,
- .pa_end = 0x5a07ffff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l3_main_2 -> iva */
-static struct omap_hwmod_ocp_if omap44xx_l3_main_2__iva = {
- .master = &omap44xx_l3_main_2_hwmod,
- .slave = &omap44xx_iva_hwmod,
- .clk = "l3_div_ck",
- .addr = omap44xx_iva_addrs,
- .user = OCP_USER_MPU,
-};
-
-/* iva slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_iva_slaves[] = {
- &omap44xx_dsp__iva,
- &omap44xx_l3_main_2__iva,
-};
-
-/* Pseudo hwmod for reset control purpose only */
-static struct omap_hwmod omap44xx_iva_seq0_hwmod = {
- .name = "iva_seq0",
- .class = &omap44xx_iva_hwmod_class,
- .clkdm_name = "ivahd_clkdm",
- .flags = HWMOD_INIT_NO_RESET,
- .rst_lines = omap44xx_iva_seq0_resets,
- .rst_lines_cnt = ARRAY_SIZE(omap44xx_iva_seq0_resets),
- .prcm = {
- .omap4 = {
- .rstctrl_offs = OMAP4_RM_IVAHD_RSTCTRL_OFFSET,
- },
- },
-};
-
-/* Pseudo hwmod for reset control purpose only */
-static struct omap_hwmod omap44xx_iva_seq1_hwmod = {
- .name = "iva_seq1",
- .class = &omap44xx_iva_hwmod_class,
- .clkdm_name = "ivahd_clkdm",
- .flags = HWMOD_INIT_NO_RESET,
- .rst_lines = omap44xx_iva_seq1_resets,
- .rst_lines_cnt = ARRAY_SIZE(omap44xx_iva_seq1_resets),
- .prcm = {
- .omap4 = {
- .rstctrl_offs = OMAP4_RM_IVAHD_RSTCTRL_OFFSET,
- },
- },
+ { .name = "logic", .rst_shift = 2 },
};
static struct omap_hwmod omap44xx_iva_hwmod = {
@@ -2789,10 +1755,6 @@ static struct omap_hwmod omap44xx_iva_hwmod = {
.modulemode = MODULEMODE_HWCTRL,
},
},
- .slaves = omap44xx_iva_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_iva_slaves),
- .masters = omap44xx_iva_masters,
- .masters_cnt = ARRAY_SIZE(omap44xx_iva_masters),
};
/*
@@ -2818,35 +1780,11 @@ static struct omap_hwmod_class omap44xx_kbd_hwmod_class = {
};
/* kbd */
-static struct omap_hwmod omap44xx_kbd_hwmod;
static struct omap_hwmod_irq_info omap44xx_kbd_irqs[] = {
{ .irq = 120 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_kbd_addrs[] = {
- {
- .pa_start = 0x4a31c000,
- .pa_end = 0x4a31c07f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_wkup -> kbd */
-static struct omap_hwmod_ocp_if omap44xx_l4_wkup__kbd = {
- .master = &omap44xx_l4_wkup_hwmod,
- .slave = &omap44xx_kbd_hwmod,
- .clk = "l4_wkup_clk_mux_ck",
- .addr = omap44xx_kbd_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* kbd slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_kbd_slaves[] = {
- &omap44xx_l4_wkup__kbd,
-};
-
static struct omap_hwmod omap44xx_kbd_hwmod = {
.name = "kbd",
.class = &omap44xx_kbd_hwmod_class,
@@ -2860,8 +1798,6 @@ static struct omap_hwmod omap44xx_kbd_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_kbd_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_kbd_slaves),
};
/*
@@ -2885,35 +1821,11 @@ static struct omap_hwmod_class omap44xx_mailbox_hwmod_class = {
};
/* mailbox */
-static struct omap_hwmod omap44xx_mailbox_hwmod;
static struct omap_hwmod_irq_info omap44xx_mailbox_irqs[] = {
{ .irq = 26 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_mailbox_addrs[] = {
- {
- .pa_start = 0x4a0f4000,
- .pa_end = 0x4a0f41ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_cfg -> mailbox */
-static struct omap_hwmod_ocp_if omap44xx_l4_cfg__mailbox = {
- .master = &omap44xx_l4_cfg_hwmod,
- .slave = &omap44xx_mailbox_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_mailbox_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mailbox slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mailbox_slaves[] = {
- &omap44xx_l4_cfg__mailbox,
-};
-
static struct omap_hwmod omap44xx_mailbox_hwmod = {
.name = "mailbox",
.class = &omap44xx_mailbox_hwmod_class,
@@ -2925,8 +1837,58 @@ static struct omap_hwmod omap44xx_mailbox_hwmod = {
.context_offs = OMAP4_RM_L4CFG_MAILBOX_CONTEXT_OFFSET,
},
},
- .slaves = omap44xx_mailbox_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_mailbox_slaves),
+};
+
+/*
+ * 'mcasp' class
+ * multi-channel audio serial port controller
+ */
+
+/* The IP is not compliant to type1 / type2 scheme */
+static struct omap_hwmod_sysc_fields omap_hwmod_sysc_type_mcasp = {
+ .sidle_shift = 0,
+};
+
+static struct omap_hwmod_class_sysconfig omap44xx_mcasp_sysc = {
+ .sysc_offs = 0x0004,
+ .sysc_flags = SYSC_HAS_SIDLEMODE,
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ SIDLE_SMART_WKUP),
+ .sysc_fields = &omap_hwmod_sysc_type_mcasp,
+};
+
+static struct omap_hwmod_class omap44xx_mcasp_hwmod_class = {
+ .name = "mcasp",
+ .sysc = &omap44xx_mcasp_sysc,
+};
+
+/* mcasp */
+static struct omap_hwmod_irq_info omap44xx_mcasp_irqs[] = {
+ { .name = "arevt", .irq = 108 + OMAP44XX_IRQ_GIC_START },
+ { .name = "axevt", .irq = 109 + OMAP44XX_IRQ_GIC_START },
+ { .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_mcasp_sdma_reqs[] = {
+ { .name = "axevt", .dma_req = 7 + OMAP44XX_DMA_REQ_START },
+ { .name = "arevt", .dma_req = 10 + OMAP44XX_DMA_REQ_START },
+ { .dma_req = -1 }
+};
+
+static struct omap_hwmod omap44xx_mcasp_hwmod = {
+ .name = "mcasp",
+ .class = &omap44xx_mcasp_hwmod_class,
+ .clkdm_name = "abe_clkdm",
+ .mpu_irqs = omap44xx_mcasp_irqs,
+ .sdma_reqs = omap44xx_mcasp_sdma_reqs,
+ .main_clk = "mcasp_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = OMAP4_CM1_ABE_MCASP_CLKCTRL_OFFSET,
+ .context_offs = OMAP4_RM_ABE_MCASP_CONTEXT_OFFSET,
+ .modulemode = MODULEMODE_SWCTRL,
+ },
+ },
};
/*
@@ -2949,9 +1911,8 @@ static struct omap_hwmod_class omap44xx_mcbsp_hwmod_class = {
};
/* mcbsp1 */
-static struct omap_hwmod omap44xx_mcbsp1_hwmod;
static struct omap_hwmod_irq_info omap44xx_mcbsp1_irqs[] = {
- { .irq = 17 + OMAP44XX_IRQ_GIC_START },
+ { .name = "common", .irq = 17 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
@@ -2961,50 +1922,6 @@ static struct omap_hwmod_dma_info omap44xx_mcbsp1_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_mcbsp1_addrs[] = {
- {
- .name = "mpu",
- .pa_start = 0x40122000,
- .pa_end = 0x401220ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_abe -> mcbsp1 */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcbsp1 = {
- .master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_mcbsp1_hwmod,
- .clk = "ocp_abe_iclk",
- .addr = omap44xx_mcbsp1_addrs,
- .user = OCP_USER_MPU,
-};
-
-static struct omap_hwmod_addr_space omap44xx_mcbsp1_dma_addrs[] = {
- {
- .name = "dma",
- .pa_start = 0x49022000,
- .pa_end = 0x490220ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_abe -> mcbsp1 (dma) */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcbsp1_dma = {
- .master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_mcbsp1_hwmod,
- .clk = "ocp_abe_iclk",
- .addr = omap44xx_mcbsp1_dma_addrs,
- .user = OCP_USER_SDMA,
-};
-
-/* mcbsp1 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mcbsp1_slaves[] = {
- &omap44xx_l4_abe__mcbsp1,
- &omap44xx_l4_abe__mcbsp1_dma,
-};
-
static struct omap_hwmod_opt_clk mcbsp1_opt_clks[] = {
{ .role = "pad_fck", .clk = "pad_clks_ck" },
{ .role = "prcm_clk", .clk = "mcbsp1_sync_mux_ck" },
@@ -3024,16 +1941,13 @@ static struct omap_hwmod omap44xx_mcbsp1_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_mcbsp1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_mcbsp1_slaves),
.opt_clks = mcbsp1_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(mcbsp1_opt_clks),
};
/* mcbsp2 */
-static struct omap_hwmod omap44xx_mcbsp2_hwmod;
static struct omap_hwmod_irq_info omap44xx_mcbsp2_irqs[] = {
- { .irq = 22 + OMAP44XX_IRQ_GIC_START },
+ { .name = "common", .irq = 22 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
@@ -3043,50 +1957,6 @@ static struct omap_hwmod_dma_info omap44xx_mcbsp2_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_mcbsp2_addrs[] = {
- {
- .name = "mpu",
- .pa_start = 0x40124000,
- .pa_end = 0x401240ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_abe -> mcbsp2 */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcbsp2 = {
- .master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_mcbsp2_hwmod,
- .clk = "ocp_abe_iclk",
- .addr = omap44xx_mcbsp2_addrs,
- .user = OCP_USER_MPU,
-};
-
-static struct omap_hwmod_addr_space omap44xx_mcbsp2_dma_addrs[] = {
- {
- .name = "dma",
- .pa_start = 0x49024000,
- .pa_end = 0x490240ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_abe -> mcbsp2 (dma) */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcbsp2_dma = {
- .master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_mcbsp2_hwmod,
- .clk = "ocp_abe_iclk",
- .addr = omap44xx_mcbsp2_dma_addrs,
- .user = OCP_USER_SDMA,
-};
-
-/* mcbsp2 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mcbsp2_slaves[] = {
- &omap44xx_l4_abe__mcbsp2,
- &omap44xx_l4_abe__mcbsp2_dma,
-};
-
static struct omap_hwmod_opt_clk mcbsp2_opt_clks[] = {
{ .role = "pad_fck", .clk = "pad_clks_ck" },
{ .role = "prcm_clk", .clk = "mcbsp2_sync_mux_ck" },
@@ -3106,16 +1976,13 @@ static struct omap_hwmod omap44xx_mcbsp2_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_mcbsp2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_mcbsp2_slaves),
.opt_clks = mcbsp2_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(mcbsp2_opt_clks),
};
/* mcbsp3 */
-static struct omap_hwmod omap44xx_mcbsp3_hwmod;
static struct omap_hwmod_irq_info omap44xx_mcbsp3_irqs[] = {
- { .irq = 23 + OMAP44XX_IRQ_GIC_START },
+ { .name = "common", .irq = 23 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
@@ -3125,50 +1992,6 @@ static struct omap_hwmod_dma_info omap44xx_mcbsp3_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_mcbsp3_addrs[] = {
- {
- .name = "mpu",
- .pa_start = 0x40126000,
- .pa_end = 0x401260ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_abe -> mcbsp3 */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcbsp3 = {
- .master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_mcbsp3_hwmod,
- .clk = "ocp_abe_iclk",
- .addr = omap44xx_mcbsp3_addrs,
- .user = OCP_USER_MPU,
-};
-
-static struct omap_hwmod_addr_space omap44xx_mcbsp3_dma_addrs[] = {
- {
- .name = "dma",
- .pa_start = 0x49026000,
- .pa_end = 0x490260ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_abe -> mcbsp3 (dma) */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcbsp3_dma = {
- .master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_mcbsp3_hwmod,
- .clk = "ocp_abe_iclk",
- .addr = omap44xx_mcbsp3_dma_addrs,
- .user = OCP_USER_SDMA,
-};
-
-/* mcbsp3 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mcbsp3_slaves[] = {
- &omap44xx_l4_abe__mcbsp3,
- &omap44xx_l4_abe__mcbsp3_dma,
-};
-
static struct omap_hwmod_opt_clk mcbsp3_opt_clks[] = {
{ .role = "pad_fck", .clk = "pad_clks_ck" },
{ .role = "prcm_clk", .clk = "mcbsp3_sync_mux_ck" },
@@ -3188,16 +2011,13 @@ static struct omap_hwmod omap44xx_mcbsp3_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_mcbsp3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_mcbsp3_slaves),
.opt_clks = mcbsp3_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(mcbsp3_opt_clks),
};
/* mcbsp4 */
-static struct omap_hwmod omap44xx_mcbsp4_hwmod;
static struct omap_hwmod_irq_info omap44xx_mcbsp4_irqs[] = {
- { .irq = 16 + OMAP44XX_IRQ_GIC_START },
+ { .name = "common", .irq = 16 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
@@ -3207,29 +2027,6 @@ static struct omap_hwmod_dma_info omap44xx_mcbsp4_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_mcbsp4_addrs[] = {
- {
- .pa_start = 0x48096000,
- .pa_end = 0x480960ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> mcbsp4 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__mcbsp4 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_mcbsp4_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_mcbsp4_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mcbsp4 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mcbsp4_slaves[] = {
- &omap44xx_l4_per__mcbsp4,
-};
-
static struct omap_hwmod_opt_clk mcbsp4_opt_clks[] = {
{ .role = "pad_fck", .clk = "pad_clks_ck" },
{ .role = "prcm_clk", .clk = "mcbsp4_sync_mux_ck" },
@@ -3249,8 +2046,6 @@ static struct omap_hwmod omap44xx_mcbsp4_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_mcbsp4_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_mcbsp4_slaves),
.opt_clks = mcbsp4_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(mcbsp4_opt_clks),
};
@@ -3277,7 +2072,6 @@ static struct omap_hwmod_class omap44xx_mcpdm_hwmod_class = {
};
/* mcpdm */
-static struct omap_hwmod omap44xx_mcpdm_hwmod;
static struct omap_hwmod_irq_info omap44xx_mcpdm_irqs[] = {
{ .irq = 112 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
@@ -3289,48 +2083,6 @@ static struct omap_hwmod_dma_info omap44xx_mcpdm_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_mcpdm_addrs[] = {
- {
- .pa_start = 0x40132000,
- .pa_end = 0x4013207f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_abe -> mcpdm */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcpdm = {
- .master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_mcpdm_hwmod,
- .clk = "ocp_abe_iclk",
- .addr = omap44xx_mcpdm_addrs,
- .user = OCP_USER_MPU,
-};
-
-static struct omap_hwmod_addr_space omap44xx_mcpdm_dma_addrs[] = {
- {
- .pa_start = 0x49032000,
- .pa_end = 0x4903207f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_abe -> mcpdm (dma) */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcpdm_dma = {
- .master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_mcpdm_hwmod,
- .clk = "ocp_abe_iclk",
- .addr = omap44xx_mcpdm_dma_addrs,
- .user = OCP_USER_SDMA,
-};
-
-/* mcpdm slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mcpdm_slaves[] = {
- &omap44xx_l4_abe__mcpdm,
- &omap44xx_l4_abe__mcpdm_dma,
-};
-
static struct omap_hwmod omap44xx_mcpdm_hwmod = {
.name = "mcpdm",
.class = &omap44xx_mcpdm_hwmod_class,
@@ -3345,8 +2097,6 @@ static struct omap_hwmod omap44xx_mcpdm_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_mcpdm_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_mcpdm_slaves),
};
/*
@@ -3372,7 +2122,6 @@ static struct omap_hwmod_class omap44xx_mcspi_hwmod_class = {
};
/* mcspi1 */
-static struct omap_hwmod omap44xx_mcspi1_hwmod;
static struct omap_hwmod_irq_info omap44xx_mcspi1_irqs[] = {
{ .irq = 65 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
@@ -3390,29 +2139,6 @@ static struct omap_hwmod_dma_info omap44xx_mcspi1_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_mcspi1_addrs[] = {
- {
- .pa_start = 0x48098000,
- .pa_end = 0x480981ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> mcspi1 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__mcspi1 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_mcspi1_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_mcspi1_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mcspi1 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mcspi1_slaves[] = {
- &omap44xx_l4_per__mcspi1,
-};
-
/* mcspi1 dev_attr */
static struct omap2_mcspi_dev_attr mcspi1_dev_attr = {
.num_chipselect = 4,
@@ -3433,12 +2159,9 @@ static struct omap_hwmod omap44xx_mcspi1_hwmod = {
},
},
.dev_attr = &mcspi1_dev_attr,
- .slaves = omap44xx_mcspi1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_mcspi1_slaves),
};
/* mcspi2 */
-static struct omap_hwmod omap44xx_mcspi2_hwmod;
static struct omap_hwmod_irq_info omap44xx_mcspi2_irqs[] = {
{ .irq = 66 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
@@ -3452,29 +2175,6 @@ static struct omap_hwmod_dma_info omap44xx_mcspi2_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_mcspi2_addrs[] = {
- {
- .pa_start = 0x4809a000,
- .pa_end = 0x4809a1ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> mcspi2 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__mcspi2 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_mcspi2_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_mcspi2_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mcspi2 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mcspi2_slaves[] = {
- &omap44xx_l4_per__mcspi2,
-};
-
/* mcspi2 dev_attr */
static struct omap2_mcspi_dev_attr mcspi2_dev_attr = {
.num_chipselect = 2,
@@ -3495,12 +2195,9 @@ static struct omap_hwmod omap44xx_mcspi2_hwmod = {
},
},
.dev_attr = &mcspi2_dev_attr,
- .slaves = omap44xx_mcspi2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_mcspi2_slaves),
};
/* mcspi3 */
-static struct omap_hwmod omap44xx_mcspi3_hwmod;
static struct omap_hwmod_irq_info omap44xx_mcspi3_irqs[] = {
{ .irq = 91 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
@@ -3514,29 +2211,6 @@ static struct omap_hwmod_dma_info omap44xx_mcspi3_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_mcspi3_addrs[] = {
- {
- .pa_start = 0x480b8000,
- .pa_end = 0x480b81ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> mcspi3 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__mcspi3 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_mcspi3_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_mcspi3_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mcspi3 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mcspi3_slaves[] = {
- &omap44xx_l4_per__mcspi3,
-};
-
/* mcspi3 dev_attr */
static struct omap2_mcspi_dev_attr mcspi3_dev_attr = {
.num_chipselect = 2,
@@ -3557,12 +2231,9 @@ static struct omap_hwmod omap44xx_mcspi3_hwmod = {
},
},
.dev_attr = &mcspi3_dev_attr,
- .slaves = omap44xx_mcspi3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_mcspi3_slaves),
};
/* mcspi4 */
-static struct omap_hwmod omap44xx_mcspi4_hwmod;
static struct omap_hwmod_irq_info omap44xx_mcspi4_irqs[] = {
{ .irq = 48 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
@@ -3574,29 +2245,6 @@ static struct omap_hwmod_dma_info omap44xx_mcspi4_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_mcspi4_addrs[] = {
- {
- .pa_start = 0x480ba000,
- .pa_end = 0x480ba1ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> mcspi4 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__mcspi4 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_mcspi4_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_mcspi4_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mcspi4 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mcspi4_slaves[] = {
- &omap44xx_l4_per__mcspi4,
-};
-
/* mcspi4 dev_attr */
static struct omap2_mcspi_dev_attr mcspi4_dev_attr = {
.num_chipselect = 1,
@@ -3617,8 +2265,6 @@ static struct omap_hwmod omap44xx_mcspi4_hwmod = {
},
},
.dev_attr = &mcspi4_dev_attr,
- .slaves = omap44xx_mcspi4_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_mcspi4_slaves),
};
/*
@@ -3655,34 +2301,6 @@ static struct omap_hwmod_dma_info omap44xx_mmc1_sdma_reqs[] = {
{ .dma_req = -1 }
};
-/* mmc1 master ports */
-static struct omap_hwmod_ocp_if *omap44xx_mmc1_masters[] = {
- &omap44xx_mmc1__l3_main_1,
-};
-
-static struct omap_hwmod_addr_space omap44xx_mmc1_addrs[] = {
- {
- .pa_start = 0x4809c000,
- .pa_end = 0x4809c3ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> mmc1 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__mmc1 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_mmc1_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_mmc1_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mmc1 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mmc1_slaves[] = {
- &omap44xx_l4_per__mmc1,
-};
-
/* mmc1 dev_attr */
static struct omap_mmc_dev_attr mmc1_dev_attr = {
.flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
@@ -3703,10 +2321,6 @@ static struct omap_hwmod omap44xx_mmc1_hwmod = {
},
},
.dev_attr = &mmc1_dev_attr,
- .slaves = omap44xx_mmc1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_mmc1_slaves),
- .masters = omap44xx_mmc1_masters,
- .masters_cnt = ARRAY_SIZE(omap44xx_mmc1_masters),
};
/* mmc2 */
@@ -3721,34 +2335,6 @@ static struct omap_hwmod_dma_info omap44xx_mmc2_sdma_reqs[] = {
{ .dma_req = -1 }
};
-/* mmc2 master ports */
-static struct omap_hwmod_ocp_if *omap44xx_mmc2_masters[] = {
- &omap44xx_mmc2__l3_main_1,
-};
-
-static struct omap_hwmod_addr_space omap44xx_mmc2_addrs[] = {
- {
- .pa_start = 0x480b4000,
- .pa_end = 0x480b43ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> mmc2 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__mmc2 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_mmc2_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_mmc2_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mmc2 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mmc2_slaves[] = {
- &omap44xx_l4_per__mmc2,
-};
-
static struct omap_hwmod omap44xx_mmc2_hwmod = {
.name = "mmc2",
.class = &omap44xx_mmc_hwmod_class,
@@ -3763,14 +2349,9 @@ static struct omap_hwmod omap44xx_mmc2_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_mmc2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_mmc2_slaves),
- .masters = omap44xx_mmc2_masters,
- .masters_cnt = ARRAY_SIZE(omap44xx_mmc2_masters),
};
/* mmc3 */
-static struct omap_hwmod omap44xx_mmc3_hwmod;
static struct omap_hwmod_irq_info omap44xx_mmc3_irqs[] = {
{ .irq = 94 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
@@ -3782,29 +2363,6 @@ static struct omap_hwmod_dma_info omap44xx_mmc3_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_mmc3_addrs[] = {
- {
- .pa_start = 0x480ad000,
- .pa_end = 0x480ad3ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> mmc3 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__mmc3 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_mmc3_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_mmc3_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mmc3 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mmc3_slaves[] = {
- &omap44xx_l4_per__mmc3,
-};
-
static struct omap_hwmod omap44xx_mmc3_hwmod = {
.name = "mmc3",
.class = &omap44xx_mmc_hwmod_class,
@@ -3819,12 +2377,9 @@ static struct omap_hwmod omap44xx_mmc3_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_mmc3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_mmc3_slaves),
};
/* mmc4 */
-static struct omap_hwmod omap44xx_mmc4_hwmod;
static struct omap_hwmod_irq_info omap44xx_mmc4_irqs[] = {
{ .irq = 96 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
@@ -3836,35 +2391,11 @@ static struct omap_hwmod_dma_info omap44xx_mmc4_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_mmc4_addrs[] = {
- {
- .pa_start = 0x480d1000,
- .pa_end = 0x480d13ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> mmc4 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__mmc4 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_mmc4_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_mmc4_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mmc4 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mmc4_slaves[] = {
- &omap44xx_l4_per__mmc4,
-};
-
static struct omap_hwmod omap44xx_mmc4_hwmod = {
.name = "mmc4",
.class = &omap44xx_mmc_hwmod_class,
.clkdm_name = "l4_per_clkdm",
.mpu_irqs = omap44xx_mmc4_irqs,
-
.sdma_reqs = omap44xx_mmc4_sdma_reqs,
.main_clk = "mmc4_fck",
.prcm = {
@@ -3874,12 +2405,9 @@ static struct omap_hwmod omap44xx_mmc4_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_mmc4_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_mmc4_slaves),
};
/* mmc5 */
-static struct omap_hwmod omap44xx_mmc5_hwmod;
static struct omap_hwmod_irq_info omap44xx_mmc5_irqs[] = {
{ .irq = 59 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
@@ -3891,29 +2419,6 @@ static struct omap_hwmod_dma_info omap44xx_mmc5_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_mmc5_addrs[] = {
- {
- .pa_start = 0x480d5000,
- .pa_end = 0x480d53ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> mmc5 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__mmc5 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_mmc5_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_mmc5_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* mmc5 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_mmc5_slaves[] = {
- &omap44xx_l4_per__mmc5,
-};
-
static struct omap_hwmod omap44xx_mmc5_hwmod = {
.name = "mmc5",
.class = &omap44xx_mmc_hwmod_class,
@@ -3928,8 +2433,6 @@ static struct omap_hwmod omap44xx_mmc5_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_mmc5_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_mmc5_slaves),
};
/*
@@ -3949,13 +2452,6 @@ static struct omap_hwmod_irq_info omap44xx_mpu_irqs[] = {
{ .irq = -1 }
};
-/* mpu master ports */
-static struct omap_hwmod_ocp_if *omap44xx_mpu_masters[] = {
- &omap44xx_mpu__l3_main_1,
- &omap44xx_mpu__l4_abe,
- &omap44xx_mpu__dmm,
-};
-
static struct omap_hwmod omap44xx_mpu_hwmod = {
.name = "mpu",
.class = &omap44xx_mpu_hwmod_class,
@@ -3969,8 +2465,252 @@ static struct omap_hwmod omap44xx_mpu_hwmod = {
.context_offs = OMAP4_RM_MPU_MPU_CONTEXT_OFFSET,
},
},
- .masters = omap44xx_mpu_masters,
- .masters_cnt = ARRAY_SIZE(omap44xx_mpu_masters),
+};
+
+/*
+ * 'ocmc_ram' class
+ * top-level core on-chip ram
+ */
+
+static struct omap_hwmod_class omap44xx_ocmc_ram_hwmod_class = {
+ .name = "ocmc_ram",
+};
+
+/* ocmc_ram */
+static struct omap_hwmod omap44xx_ocmc_ram_hwmod = {
+ .name = "ocmc_ram",
+ .class = &omap44xx_ocmc_ram_hwmod_class,
+ .clkdm_name = "l3_2_clkdm",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = OMAP4_CM_L3_2_OCMC_RAM_CLKCTRL_OFFSET,
+ .context_offs = OMAP4_RM_L3_2_OCMC_RAM_CONTEXT_OFFSET,
+ },
+ },
+};
+
+/*
+ * 'ocp2scp' class
+ * bridge to transform ocp interface protocol to scp (serial control port)
+ * protocol
+ */
+
+static struct omap_hwmod_class omap44xx_ocp2scp_hwmod_class = {
+ .name = "ocp2scp",
+};
+
+/* ocp2scp_usb_phy */
+static struct omap_hwmod_opt_clk ocp2scp_usb_phy_opt_clks[] = {
+ { .role = "phy_48m", .clk = "ocp2scp_usb_phy_phy_48m" },
+};
+
+static struct omap_hwmod omap44xx_ocp2scp_usb_phy_hwmod = {
+ .name = "ocp2scp_usb_phy",
+ .class = &omap44xx_ocp2scp_hwmod_class,
+ .clkdm_name = "l3_init_clkdm",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = OMAP4_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL_OFFSET,
+ .context_offs = OMAP4_RM_L3INIT_USBPHYOCP2SCP_CONTEXT_OFFSET,
+ .modulemode = MODULEMODE_HWCTRL,
+ },
+ },
+ .opt_clks = ocp2scp_usb_phy_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(ocp2scp_usb_phy_opt_clks),
+};
+
+/*
+ * 'prcm' class
+ * power and reset manager (part of the prcm infrastructure) + clock manager 2
+ * + clock manager 1 (in always on power domain) + local prm in mpu
+ */
+
+static struct omap_hwmod_class omap44xx_prcm_hwmod_class = {
+ .name = "prcm",
+};
+
+/* prcm_mpu */
+static struct omap_hwmod omap44xx_prcm_mpu_hwmod = {
+ .name = "prcm_mpu",
+ .class = &omap44xx_prcm_hwmod_class,
+ .clkdm_name = "l4_wkup_clkdm",
+};
+
+/* cm_core_aon */
+static struct omap_hwmod omap44xx_cm_core_aon_hwmod = {
+ .name = "cm_core_aon",
+ .class = &omap44xx_prcm_hwmod_class,
+ .clkdm_name = "cm_clkdm",
+};
+
+/* cm_core */
+static struct omap_hwmod omap44xx_cm_core_hwmod = {
+ .name = "cm_core",
+ .class = &omap44xx_prcm_hwmod_class,
+ .clkdm_name = "cm_clkdm",
+};
+
+/* prm */
+static struct omap_hwmod_irq_info omap44xx_prm_irqs[] = {
+ { .irq = 11 + OMAP44XX_IRQ_GIC_START },
+ { .irq = -1 }
+};
+
+static struct omap_hwmod_rst_info omap44xx_prm_resets[] = {
+ { .name = "rst_global_warm_sw", .rst_shift = 0 },
+ { .name = "rst_global_cold_sw", .rst_shift = 1 },
+};
+
+static struct omap_hwmod omap44xx_prm_hwmod = {
+ .name = "prm",
+ .class = &omap44xx_prcm_hwmod_class,
+ .clkdm_name = "prm_clkdm",
+ .mpu_irqs = omap44xx_prm_irqs,
+ .rst_lines = omap44xx_prm_resets,
+ .rst_lines_cnt = ARRAY_SIZE(omap44xx_prm_resets),
+};
+
+/*
+ * 'scrm' class
+ * system clock and reset manager
+ */
+
+static struct omap_hwmod_class omap44xx_scrm_hwmod_class = {
+ .name = "scrm",
+};
+
+/* scrm */
+static struct omap_hwmod omap44xx_scrm_hwmod = {
+ .name = "scrm",
+ .class = &omap44xx_scrm_hwmod_class,
+ .clkdm_name = "l4_wkup_clkdm",
+};
+
+/*
+ * 'sl2if' class
+ * shared level 2 memory interface
+ */
+
+static struct omap_hwmod_class omap44xx_sl2if_hwmod_class = {
+ .name = "sl2if",
+};
+
+/* sl2if */
+static struct omap_hwmod omap44xx_sl2if_hwmod = {
+ .name = "sl2if",
+ .class = &omap44xx_sl2if_hwmod_class,
+ .clkdm_name = "ivahd_clkdm",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = OMAP4_CM_IVAHD_SL2_CLKCTRL_OFFSET,
+ .context_offs = OMAP4_RM_IVAHD_SL2_CONTEXT_OFFSET,
+ .modulemode = MODULEMODE_HWCTRL,
+ },
+ },
+};
+
+/*
+ * 'slimbus' class
+ * bidirectional, multi-drop, multi-channel two-line serial interface between
+ * the device and external components
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_slimbus_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .sysc_flags = (SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_SOFTRESET),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ SIDLE_SMART_WKUP),
+ .sysc_fields = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_slimbus_hwmod_class = {
+ .name = "slimbus",
+ .sysc = &omap44xx_slimbus_sysc,
+};
+
+/* slimbus1 */
+static struct omap_hwmod_irq_info omap44xx_slimbus1_irqs[] = {
+ { .irq = 97 + OMAP44XX_IRQ_GIC_START },
+ { .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_slimbus1_sdma_reqs[] = {
+ { .name = "tx0", .dma_req = 84 + OMAP44XX_DMA_REQ_START },
+ { .name = "tx1", .dma_req = 85 + OMAP44XX_DMA_REQ_START },
+ { .name = "tx2", .dma_req = 86 + OMAP44XX_DMA_REQ_START },
+ { .name = "tx3", .dma_req = 87 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx0", .dma_req = 88 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx1", .dma_req = 89 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx2", .dma_req = 90 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx3", .dma_req = 91 + OMAP44XX_DMA_REQ_START },
+ { .dma_req = -1 }
+};
+
+static struct omap_hwmod_opt_clk slimbus1_opt_clks[] = {
+ { .role = "fclk_1", .clk = "slimbus1_fclk_1" },
+ { .role = "fclk_0", .clk = "slimbus1_fclk_0" },
+ { .role = "fclk_2", .clk = "slimbus1_fclk_2" },
+ { .role = "slimbus_clk", .clk = "slimbus1_slimbus_clk" },
+};
+
+static struct omap_hwmod omap44xx_slimbus1_hwmod = {
+ .name = "slimbus1",
+ .class = &omap44xx_slimbus_hwmod_class,
+ .clkdm_name = "abe_clkdm",
+ .mpu_irqs = omap44xx_slimbus1_irqs,
+ .sdma_reqs = omap44xx_slimbus1_sdma_reqs,
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = OMAP4_CM1_ABE_SLIMBUS_CLKCTRL_OFFSET,
+ .context_offs = OMAP4_RM_ABE_SLIMBUS_CONTEXT_OFFSET,
+ .modulemode = MODULEMODE_SWCTRL,
+ },
+ },
+ .opt_clks = slimbus1_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(slimbus1_opt_clks),
+};
+
+/* slimbus2 */
+static struct omap_hwmod_irq_info omap44xx_slimbus2_irqs[] = {
+ { .irq = 98 + OMAP44XX_IRQ_GIC_START },
+ { .irq = -1 }
+};
+
+static struct omap_hwmod_dma_info omap44xx_slimbus2_sdma_reqs[] = {
+ { .name = "tx0", .dma_req = 92 + OMAP44XX_DMA_REQ_START },
+ { .name = "tx1", .dma_req = 93 + OMAP44XX_DMA_REQ_START },
+ { .name = "tx2", .dma_req = 94 + OMAP44XX_DMA_REQ_START },
+ { .name = "tx3", .dma_req = 95 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx0", .dma_req = 96 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx1", .dma_req = 97 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx2", .dma_req = 98 + OMAP44XX_DMA_REQ_START },
+ { .name = "rx3", .dma_req = 99 + OMAP44XX_DMA_REQ_START },
+ { .dma_req = -1 }
+};
+
+static struct omap_hwmod_opt_clk slimbus2_opt_clks[] = {
+ { .role = "fclk_1", .clk = "slimbus2_fclk_1" },
+ { .role = "fclk_0", .clk = "slimbus2_fclk_0" },
+ { .role = "slimbus_clk", .clk = "slimbus2_slimbus_clk" },
+};
+
+static struct omap_hwmod omap44xx_slimbus2_hwmod = {
+ .name = "slimbus2",
+ .class = &omap44xx_slimbus_hwmod_class,
+ .clkdm_name = "l4_per_clkdm",
+ .mpu_irqs = omap44xx_slimbus2_irqs,
+ .sdma_reqs = omap44xx_slimbus2_sdma_reqs,
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = OMAP4_CM_L4PER_SLIMBUS2_CLKCTRL_OFFSET,
+ .context_offs = OMAP4_RM_L4PER_SLIMBUS2_CONTEXT_OFFSET,
+ .modulemode = MODULEMODE_SWCTRL,
+ },
+ },
+ .opt_clks = slimbus2_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(slimbus2_opt_clks),
};
/*
@@ -4004,35 +2744,11 @@ static struct omap_smartreflex_dev_attr smartreflex_core_dev_attr = {
.sensor_voltdm_name = "core",
};
-static struct omap_hwmod omap44xx_smartreflex_core_hwmod;
static struct omap_hwmod_irq_info omap44xx_smartreflex_core_irqs[] = {
{ .irq = 19 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_smartreflex_core_addrs[] = {
- {
- .pa_start = 0x4a0dd000,
- .pa_end = 0x4a0dd03f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_cfg -> smartreflex_core */
-static struct omap_hwmod_ocp_if omap44xx_l4_cfg__smartreflex_core = {
- .master = &omap44xx_l4_cfg_hwmod,
- .slave = &omap44xx_smartreflex_core_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_smartreflex_core_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* smartreflex_core slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_smartreflex_core_slaves[] = {
- &omap44xx_l4_cfg__smartreflex_core,
-};
-
static struct omap_hwmod omap44xx_smartreflex_core_hwmod = {
.name = "smartreflex_core",
.class = &omap44xx_smartreflex_hwmod_class,
@@ -4047,8 +2763,6 @@ static struct omap_hwmod omap44xx_smartreflex_core_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_smartreflex_core_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_smartreflex_core_slaves),
.dev_attr = &smartreflex_core_dev_attr,
};
@@ -4057,35 +2771,11 @@ static struct omap_smartreflex_dev_attr smartreflex_iva_dev_attr = {
.sensor_voltdm_name = "iva",
};
-static struct omap_hwmod omap44xx_smartreflex_iva_hwmod;
static struct omap_hwmod_irq_info omap44xx_smartreflex_iva_irqs[] = {
{ .irq = 102 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_smartreflex_iva_addrs[] = {
- {
- .pa_start = 0x4a0db000,
- .pa_end = 0x4a0db03f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_cfg -> smartreflex_iva */
-static struct omap_hwmod_ocp_if omap44xx_l4_cfg__smartreflex_iva = {
- .master = &omap44xx_l4_cfg_hwmod,
- .slave = &omap44xx_smartreflex_iva_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_smartreflex_iva_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* smartreflex_iva slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_smartreflex_iva_slaves[] = {
- &omap44xx_l4_cfg__smartreflex_iva,
-};
-
static struct omap_hwmod omap44xx_smartreflex_iva_hwmod = {
.name = "smartreflex_iva",
.class = &omap44xx_smartreflex_hwmod_class,
@@ -4099,8 +2789,6 @@ static struct omap_hwmod omap44xx_smartreflex_iva_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_smartreflex_iva_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_smartreflex_iva_slaves),
.dev_attr = &smartreflex_iva_dev_attr,
};
@@ -4109,35 +2797,11 @@ static struct omap_smartreflex_dev_attr smartreflex_mpu_dev_attr = {
.sensor_voltdm_name = "mpu",
};
-static struct omap_hwmod omap44xx_smartreflex_mpu_hwmod;
static struct omap_hwmod_irq_info omap44xx_smartreflex_mpu_irqs[] = {
{ .irq = 18 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_smartreflex_mpu_addrs[] = {
- {
- .pa_start = 0x4a0d9000,
- .pa_end = 0x4a0d903f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_cfg -> smartreflex_mpu */
-static struct omap_hwmod_ocp_if omap44xx_l4_cfg__smartreflex_mpu = {
- .master = &omap44xx_l4_cfg_hwmod,
- .slave = &omap44xx_smartreflex_mpu_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_smartreflex_mpu_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* smartreflex_mpu slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_smartreflex_mpu_slaves[] = {
- &omap44xx_l4_cfg__smartreflex_mpu,
-};
-
static struct omap_hwmod omap44xx_smartreflex_mpu_hwmod = {
.name = "smartreflex_mpu",
.class = &omap44xx_smartreflex_hwmod_class,
@@ -4151,8 +2815,6 @@ static struct omap_hwmod omap44xx_smartreflex_mpu_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_smartreflex_mpu_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_smartreflex_mpu_slaves),
.dev_attr = &smartreflex_mpu_dev_attr,
};
@@ -4180,30 +2842,6 @@ static struct omap_hwmod_class omap44xx_spinlock_hwmod_class = {
};
/* spinlock */
-static struct omap_hwmod omap44xx_spinlock_hwmod;
-static struct omap_hwmod_addr_space omap44xx_spinlock_addrs[] = {
- {
- .pa_start = 0x4a0f6000,
- .pa_end = 0x4a0f6fff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_cfg -> spinlock */
-static struct omap_hwmod_ocp_if omap44xx_l4_cfg__spinlock = {
- .master = &omap44xx_l4_cfg_hwmod,
- .slave = &omap44xx_spinlock_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_spinlock_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* spinlock slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_spinlock_slaves[] = {
- &omap44xx_l4_cfg__spinlock,
-};
-
static struct omap_hwmod omap44xx_spinlock_hwmod = {
.name = "spinlock",
.class = &omap44xx_spinlock_hwmod_class,
@@ -4214,8 +2852,6 @@ static struct omap_hwmod omap44xx_spinlock_hwmod = {
.context_offs = OMAP4_RM_L4CFG_HW_SEM_CONTEXT_OFFSET,
},
},
- .slaves = omap44xx_spinlock_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_spinlock_slaves),
};
/*
@@ -4267,35 +2903,11 @@ static struct omap_timer_capability_dev_attr capability_pwm_dev_attr = {
};
/* timer1 */
-static struct omap_hwmod omap44xx_timer1_hwmod;
static struct omap_hwmod_irq_info omap44xx_timer1_irqs[] = {
{ .irq = 37 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_timer1_addrs[] = {
- {
- .pa_start = 0x4a318000,
- .pa_end = 0x4a31807f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_wkup -> timer1 */
-static struct omap_hwmod_ocp_if omap44xx_l4_wkup__timer1 = {
- .master = &omap44xx_l4_wkup_hwmod,
- .slave = &omap44xx_timer1_hwmod,
- .clk = "l4_wkup_clk_mux_ck",
- .addr = omap44xx_timer1_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer1 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_timer1_slaves[] = {
- &omap44xx_l4_wkup__timer1,
-};
-
static struct omap_hwmod omap44xx_timer1_hwmod = {
.name = "timer1",
.class = &omap44xx_timer_1ms_hwmod_class,
@@ -4310,40 +2922,14 @@ static struct omap_hwmod omap44xx_timer1_hwmod = {
},
},
.dev_attr = &capability_alwon_dev_attr,
- .slaves = omap44xx_timer1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_timer1_slaves),
};
/* timer2 */
-static struct omap_hwmod omap44xx_timer2_hwmod;
static struct omap_hwmod_irq_info omap44xx_timer2_irqs[] = {
{ .irq = 38 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_timer2_addrs[] = {
- {
- .pa_start = 0x48032000,
- .pa_end = 0x4803207f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> timer2 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__timer2 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_timer2_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_timer2_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer2 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_timer2_slaves[] = {
- &omap44xx_l4_per__timer2,
-};
-
static struct omap_hwmod omap44xx_timer2_hwmod = {
.name = "timer2",
.class = &omap44xx_timer_1ms_hwmod_class,
@@ -4358,40 +2944,14 @@ static struct omap_hwmod omap44xx_timer2_hwmod = {
},
},
.dev_attr = &capability_alwon_dev_attr,
- .slaves = omap44xx_timer2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_timer2_slaves),
};
/* timer3 */
-static struct omap_hwmod omap44xx_timer3_hwmod;
static struct omap_hwmod_irq_info omap44xx_timer3_irqs[] = {
{ .irq = 39 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_timer3_addrs[] = {
- {
- .pa_start = 0x48034000,
- .pa_end = 0x4803407f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> timer3 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__timer3 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_timer3_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_timer3_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer3 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_timer3_slaves[] = {
- &omap44xx_l4_per__timer3,
-};
-
static struct omap_hwmod omap44xx_timer3_hwmod = {
.name = "timer3",
.class = &omap44xx_timer_hwmod_class,
@@ -4406,40 +2966,14 @@ static struct omap_hwmod omap44xx_timer3_hwmod = {
},
},
.dev_attr = &capability_alwon_dev_attr,
- .slaves = omap44xx_timer3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_timer3_slaves),
};
/* timer4 */
-static struct omap_hwmod omap44xx_timer4_hwmod;
static struct omap_hwmod_irq_info omap44xx_timer4_irqs[] = {
{ .irq = 40 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_timer4_addrs[] = {
- {
- .pa_start = 0x48036000,
- .pa_end = 0x4803607f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> timer4 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__timer4 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_timer4_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_timer4_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer4 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_timer4_slaves[] = {
- &omap44xx_l4_per__timer4,
-};
-
static struct omap_hwmod omap44xx_timer4_hwmod = {
.name = "timer4",
.class = &omap44xx_timer_hwmod_class,
@@ -4454,59 +2988,14 @@ static struct omap_hwmod omap44xx_timer4_hwmod = {
},
},
.dev_attr = &capability_alwon_dev_attr,
- .slaves = omap44xx_timer4_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_timer4_slaves),
};
/* timer5 */
-static struct omap_hwmod omap44xx_timer5_hwmod;
static struct omap_hwmod_irq_info omap44xx_timer5_irqs[] = {
{ .irq = 41 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_timer5_addrs[] = {
- {
- .pa_start = 0x40138000,
- .pa_end = 0x4013807f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_abe -> timer5 */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer5 = {
- .master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_timer5_hwmod,
- .clk = "ocp_abe_iclk",
- .addr = omap44xx_timer5_addrs,
- .user = OCP_USER_MPU,
-};
-
-static struct omap_hwmod_addr_space omap44xx_timer5_dma_addrs[] = {
- {
- .pa_start = 0x49038000,
- .pa_end = 0x4903807f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_abe -> timer5 (dma) */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer5_dma = {
- .master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_timer5_hwmod,
- .clk = "ocp_abe_iclk",
- .addr = omap44xx_timer5_dma_addrs,
- .user = OCP_USER_SDMA,
-};
-
-/* timer5 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_timer5_slaves[] = {
- &omap44xx_l4_abe__timer5,
- &omap44xx_l4_abe__timer5_dma,
-};
-
static struct omap_hwmod omap44xx_timer5_hwmod = {
.name = "timer5",
.class = &omap44xx_timer_hwmod_class,
@@ -4521,59 +3010,14 @@ static struct omap_hwmod omap44xx_timer5_hwmod = {
},
},
.dev_attr = &capability_alwon_dev_attr,
- .slaves = omap44xx_timer5_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_timer5_slaves),
};
/* timer6 */
-static struct omap_hwmod omap44xx_timer6_hwmod;
static struct omap_hwmod_irq_info omap44xx_timer6_irqs[] = {
{ .irq = 42 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_timer6_addrs[] = {
- {
- .pa_start = 0x4013a000,
- .pa_end = 0x4013a07f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_abe -> timer6 */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer6 = {
- .master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_timer6_hwmod,
- .clk = "ocp_abe_iclk",
- .addr = omap44xx_timer6_addrs,
- .user = OCP_USER_MPU,
-};
-
-static struct omap_hwmod_addr_space omap44xx_timer6_dma_addrs[] = {
- {
- .pa_start = 0x4903a000,
- .pa_end = 0x4903a07f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_abe -> timer6 (dma) */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer6_dma = {
- .master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_timer6_hwmod,
- .clk = "ocp_abe_iclk",
- .addr = omap44xx_timer6_dma_addrs,
- .user = OCP_USER_SDMA,
-};
-
-/* timer6 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_timer6_slaves[] = {
- &omap44xx_l4_abe__timer6,
- &omap44xx_l4_abe__timer6_dma,
-};
-
static struct omap_hwmod omap44xx_timer6_hwmod = {
.name = "timer6",
.class = &omap44xx_timer_hwmod_class,
@@ -4589,59 +3033,14 @@ static struct omap_hwmod omap44xx_timer6_hwmod = {
},
},
.dev_attr = &capability_alwon_dev_attr,
- .slaves = omap44xx_timer6_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_timer6_slaves),
};
/* timer7 */
-static struct omap_hwmod omap44xx_timer7_hwmod;
static struct omap_hwmod_irq_info omap44xx_timer7_irqs[] = {
{ .irq = 43 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_timer7_addrs[] = {
- {
- .pa_start = 0x4013c000,
- .pa_end = 0x4013c07f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_abe -> timer7 */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer7 = {
- .master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_timer7_hwmod,
- .clk = "ocp_abe_iclk",
- .addr = omap44xx_timer7_addrs,
- .user = OCP_USER_MPU,
-};
-
-static struct omap_hwmod_addr_space omap44xx_timer7_dma_addrs[] = {
- {
- .pa_start = 0x4903c000,
- .pa_end = 0x4903c07f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_abe -> timer7 (dma) */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer7_dma = {
- .master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_timer7_hwmod,
- .clk = "ocp_abe_iclk",
- .addr = omap44xx_timer7_dma_addrs,
- .user = OCP_USER_SDMA,
-};
-
-/* timer7 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_timer7_slaves[] = {
- &omap44xx_l4_abe__timer7,
- &omap44xx_l4_abe__timer7_dma,
-};
-
static struct omap_hwmod omap44xx_timer7_hwmod = {
.name = "timer7",
.class = &omap44xx_timer_hwmod_class,
@@ -4656,59 +3055,14 @@ static struct omap_hwmod omap44xx_timer7_hwmod = {
},
},
.dev_attr = &capability_alwon_dev_attr,
- .slaves = omap44xx_timer7_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_timer7_slaves),
};
/* timer8 */
-static struct omap_hwmod omap44xx_timer8_hwmod;
static struct omap_hwmod_irq_info omap44xx_timer8_irqs[] = {
{ .irq = 44 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_timer8_addrs[] = {
- {
- .pa_start = 0x4013e000,
- .pa_end = 0x4013e07f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_abe -> timer8 */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer8 = {
- .master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_timer8_hwmod,
- .clk = "ocp_abe_iclk",
- .addr = omap44xx_timer8_addrs,
- .user = OCP_USER_MPU,
-};
-
-static struct omap_hwmod_addr_space omap44xx_timer8_dma_addrs[] = {
- {
- .pa_start = 0x4903e000,
- .pa_end = 0x4903e07f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_abe -> timer8 (dma) */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer8_dma = {
- .master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_timer8_hwmod,
- .clk = "ocp_abe_iclk",
- .addr = omap44xx_timer8_dma_addrs,
- .user = OCP_USER_SDMA,
-};
-
-/* timer8 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_timer8_slaves[] = {
- &omap44xx_l4_abe__timer8,
- &omap44xx_l4_abe__timer8_dma,
-};
-
static struct omap_hwmod omap44xx_timer8_hwmod = {
.name = "timer8",
.class = &omap44xx_timer_hwmod_class,
@@ -4723,40 +3077,14 @@ static struct omap_hwmod omap44xx_timer8_hwmod = {
},
},
.dev_attr = &capability_pwm_dev_attr,
- .slaves = omap44xx_timer8_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_timer8_slaves),
};
/* timer9 */
-static struct omap_hwmod omap44xx_timer9_hwmod;
static struct omap_hwmod_irq_info omap44xx_timer9_irqs[] = {
{ .irq = 45 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_timer9_addrs[] = {
- {
- .pa_start = 0x4803e000,
- .pa_end = 0x4803e07f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> timer9 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__timer9 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_timer9_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_timer9_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer9 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_timer9_slaves[] = {
- &omap44xx_l4_per__timer9,
-};
-
static struct omap_hwmod omap44xx_timer9_hwmod = {
.name = "timer9",
.class = &omap44xx_timer_hwmod_class,
@@ -4771,40 +3099,14 @@ static struct omap_hwmod omap44xx_timer9_hwmod = {
},
},
.dev_attr = &capability_pwm_dev_attr,
- .slaves = omap44xx_timer9_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_timer9_slaves),
};
/* timer10 */
-static struct omap_hwmod omap44xx_timer10_hwmod;
static struct omap_hwmod_irq_info omap44xx_timer10_irqs[] = {
{ .irq = 46 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_timer10_addrs[] = {
- {
- .pa_start = 0x48086000,
- .pa_end = 0x4808607f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> timer10 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__timer10 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_timer10_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_timer10_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer10 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_timer10_slaves[] = {
- &omap44xx_l4_per__timer10,
-};
-
static struct omap_hwmod omap44xx_timer10_hwmod = {
.name = "timer10",
.class = &omap44xx_timer_1ms_hwmod_class,
@@ -4819,40 +3121,14 @@ static struct omap_hwmod omap44xx_timer10_hwmod = {
},
},
.dev_attr = &capability_pwm_dev_attr,
- .slaves = omap44xx_timer10_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_timer10_slaves),
};
/* timer11 */
-static struct omap_hwmod omap44xx_timer11_hwmod;
static struct omap_hwmod_irq_info omap44xx_timer11_irqs[] = {
{ .irq = 47 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_timer11_addrs[] = {
- {
- .pa_start = 0x48088000,
- .pa_end = 0x4808807f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> timer11 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__timer11 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_timer11_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_timer11_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* timer11 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_timer11_slaves[] = {
- &omap44xx_l4_per__timer11,
-};
-
static struct omap_hwmod omap44xx_timer11_hwmod = {
.name = "timer11",
.class = &omap44xx_timer_hwmod_class,
@@ -4867,8 +3143,6 @@ static struct omap_hwmod omap44xx_timer11_hwmod = {
},
},
.dev_attr = &capability_pwm_dev_attr,
- .slaves = omap44xx_timer11_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_timer11_slaves),
};
/*
@@ -4894,7 +3168,6 @@ static struct omap_hwmod_class omap44xx_uart_hwmod_class = {
};
/* uart1 */
-static struct omap_hwmod omap44xx_uart1_hwmod;
static struct omap_hwmod_irq_info omap44xx_uart1_irqs[] = {
{ .irq = 72 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
@@ -4906,29 +3179,6 @@ static struct omap_hwmod_dma_info omap44xx_uart1_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_uart1_addrs[] = {
- {
- .pa_start = 0x4806a000,
- .pa_end = 0x4806a0ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> uart1 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__uart1 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_uart1_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_uart1_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* uart1 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_uart1_slaves[] = {
- &omap44xx_l4_per__uart1,
-};
-
static struct omap_hwmod omap44xx_uart1_hwmod = {
.name = "uart1",
.class = &omap44xx_uart_hwmod_class,
@@ -4943,12 +3193,9 @@ static struct omap_hwmod omap44xx_uart1_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_uart1_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_uart1_slaves),
};
/* uart2 */
-static struct omap_hwmod omap44xx_uart2_hwmod;
static struct omap_hwmod_irq_info omap44xx_uart2_irqs[] = {
{ .irq = 73 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
@@ -4960,29 +3207,6 @@ static struct omap_hwmod_dma_info omap44xx_uart2_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_uart2_addrs[] = {
- {
- .pa_start = 0x4806c000,
- .pa_end = 0x4806c0ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> uart2 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__uart2 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_uart2_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_uart2_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* uart2 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_uart2_slaves[] = {
- &omap44xx_l4_per__uart2,
-};
-
static struct omap_hwmod omap44xx_uart2_hwmod = {
.name = "uart2",
.class = &omap44xx_uart_hwmod_class,
@@ -4997,12 +3221,9 @@ static struct omap_hwmod omap44xx_uart2_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_uart2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_uart2_slaves),
};
/* uart3 */
-static struct omap_hwmod omap44xx_uart3_hwmod;
static struct omap_hwmod_irq_info omap44xx_uart3_irqs[] = {
{ .irq = 74 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
@@ -5014,29 +3235,6 @@ static struct omap_hwmod_dma_info omap44xx_uart3_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_uart3_addrs[] = {
- {
- .pa_start = 0x48020000,
- .pa_end = 0x480200ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> uart3 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__uart3 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_uart3_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_uart3_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* uart3 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_uart3_slaves[] = {
- &omap44xx_l4_per__uart3,
-};
-
static struct omap_hwmod omap44xx_uart3_hwmod = {
.name = "uart3",
.class = &omap44xx_uart_hwmod_class,
@@ -5052,12 +3250,9 @@ static struct omap_hwmod omap44xx_uart3_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_uart3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_uart3_slaves),
};
/* uart4 */
-static struct omap_hwmod omap44xx_uart4_hwmod;
static struct omap_hwmod_irq_info omap44xx_uart4_irqs[] = {
{ .irq = 70 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
@@ -5069,29 +3264,6 @@ static struct omap_hwmod_dma_info omap44xx_uart4_sdma_reqs[] = {
{ .dma_req = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_uart4_addrs[] = {
- {
- .pa_start = 0x4806e000,
- .pa_end = 0x4806e0ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_per -> uart4 */
-static struct omap_hwmod_ocp_if omap44xx_l4_per__uart4 = {
- .master = &omap44xx_l4_per_hwmod,
- .slave = &omap44xx_uart4_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_uart4_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* uart4 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_uart4_slaves[] = {
- &omap44xx_l4_per__uart4,
-};
-
static struct omap_hwmod omap44xx_uart4_hwmod = {
.name = "uart4",
.class = &omap44xx_uart_hwmod_class,
@@ -5106,8 +3278,147 @@ static struct omap_hwmod omap44xx_uart4_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_uart4_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_uart4_slaves),
+};
+
+/*
+ * 'usb_host_fs' class
+ * full-speed usb host controller
+ */
+
+/* The IP is not compliant to type1 / type2 scheme */
+static struct omap_hwmod_sysc_fields omap_hwmod_sysc_type_usb_host_fs = {
+ .midle_shift = 4,
+ .sidle_shift = 2,
+ .srst_shift = 1,
+};
+
+static struct omap_hwmod_class_sysconfig omap44xx_usb_host_fs_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0210,
+ .sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_SOFTRESET),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ SIDLE_SMART_WKUP),
+ .sysc_fields = &omap_hwmod_sysc_type_usb_host_fs,
+};
+
+static struct omap_hwmod_class omap44xx_usb_host_fs_hwmod_class = {
+ .name = "usb_host_fs",
+ .sysc = &omap44xx_usb_host_fs_sysc,
+};
+
+/* usb_host_fs */
+static struct omap_hwmod_irq_info omap44xx_usb_host_fs_irqs[] = {
+ { .name = "std", .irq = 89 + OMAP44XX_IRQ_GIC_START },
+ { .name = "smi", .irq = 90 + OMAP44XX_IRQ_GIC_START },
+ { .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_usb_host_fs_hwmod = {
+ .name = "usb_host_fs",
+ .class = &omap44xx_usb_host_fs_hwmod_class,
+ .clkdm_name = "l3_init_clkdm",
+ .mpu_irqs = omap44xx_usb_host_fs_irqs,
+ .main_clk = "usb_host_fs_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = OMAP4_CM_L3INIT_USB_HOST_FS_CLKCTRL_OFFSET,
+ .context_offs = OMAP4_RM_L3INIT_USB_HOST_FS_CONTEXT_OFFSET,
+ .modulemode = MODULEMODE_SWCTRL,
+ },
+ },
+};
+
+/*
+ * 'usb_host_hs' class
+ * high-speed multi-port usb host controller
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_usb_host_hs_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_SOFTRESET),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
+ MSTANDBY_SMART | MSTANDBY_SMART_WKUP),
+ .sysc_fields = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap44xx_usb_host_hs_hwmod_class = {
+ .name = "usb_host_hs",
+ .sysc = &omap44xx_usb_host_hs_sysc,
+};
+
+/* usb_host_hs */
+static struct omap_hwmod_irq_info omap44xx_usb_host_hs_irqs[] = {
+ { .name = "ohci-irq", .irq = 76 + OMAP44XX_IRQ_GIC_START },
+ { .name = "ehci-irq", .irq = 77 + OMAP44XX_IRQ_GIC_START },
+ { .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_usb_host_hs_hwmod = {
+ .name = "usb_host_hs",
+ .class = &omap44xx_usb_host_hs_hwmod_class,
+ .clkdm_name = "l3_init_clkdm",
+ .main_clk = "usb_host_hs_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_OFFSET,
+ .context_offs = OMAP4_RM_L3INIT_USB_HOST_CONTEXT_OFFSET,
+ .modulemode = MODULEMODE_SWCTRL,
+ },
+ },
+ .mpu_irqs = omap44xx_usb_host_hs_irqs,
+
+ /*
+ * Errata: USBHOST Configured In Smart-Idle Can Lead To a Deadlock
+ * id: i660
+ *
+ * Description:
+ * In the following configuration :
+ * - USBHOST module is set to smart-idle mode
+ * - PRCM asserts idle_req to the USBHOST module ( This typically
+ * happens when the system is going to a low power mode : all ports
+ * have been suspended, the master part of the USBHOST module has
+ * entered the standby state, and SW has cut the functional clocks)
+ * - an USBHOST interrupt occurs before the module is able to answer
+ * idle_ack, typically a remote wakeup IRQ.
+ * Then the USB HOST module will enter a deadlock situation where it
+ * is no more accessible nor functional.
+ *
+ * Workaround:
+ * Don't use smart idle; use only force idle, hence HWMOD_SWSUP_SIDLE
+ */
+
+ /*
+ * Errata: USB host EHCI may stall when entering smart-standby mode
+ * Id: i571
+ *
+ * Description:
+ * When the USBHOST module is set to smart-standby mode, and when it is
+ * ready to enter the standby state (i.e. all ports are suspended and
+ * all attached devices are in suspend mode), then it can wrongly assert
+ * the Mstandby signal too early while there are still some residual OCP
+ * transactions ongoing. If this condition occurs, the internal state
+ * machine may go to an undefined state and the USB link may be stuck
+ * upon the next resume.
+ *
+ * Workaround:
+ * Don't use smart standby; use only force standby,
+ * hence HWMOD_SWSUP_MSTANDBY
+ */
+
+ /*
+ * During system boot; If the hwmod framework resets the module
+ * the module will have smart idle settings; which can lead to deadlock
+ * (above Errata Id:i660); so, dont reset the module during boot;
+ * Use HWMOD_INIT_NO_RESET.
+ */
+
+ .flags = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY |
+ HWMOD_INIT_NO_RESET,
};
/*
@@ -5140,34 +3451,6 @@ static struct omap_hwmod_irq_info omap44xx_usb_otg_hs_irqs[] = {
{ .irq = -1 }
};
-/* usb_otg_hs master ports */
-static struct omap_hwmod_ocp_if *omap44xx_usb_otg_hs_masters[] = {
- &omap44xx_usb_otg_hs__l3_main_2,
-};
-
-static struct omap_hwmod_addr_space omap44xx_usb_otg_hs_addrs[] = {
- {
- .pa_start = 0x4a0ab000,
- .pa_end = 0x4a0ab003,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_cfg -> usb_otg_hs */
-static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usb_otg_hs = {
- .master = &omap44xx_l4_cfg_hwmod,
- .slave = &omap44xx_usb_otg_hs_hwmod,
- .clk = "l4_div_ck",
- .addr = omap44xx_usb_otg_hs_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* usb_otg_hs slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_usb_otg_hs_slaves[] = {
- &omap44xx_l4_cfg__usb_otg_hs,
-};
-
static struct omap_hwmod_opt_clk usb_otg_hs_opt_clks[] = {
{ .role = "xclk", .clk = "usb_otg_hs_xclk" },
};
@@ -5188,10 +3471,47 @@ static struct omap_hwmod omap44xx_usb_otg_hs_hwmod = {
},
.opt_clks = usb_otg_hs_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(usb_otg_hs_opt_clks),
- .slaves = omap44xx_usb_otg_hs_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_usb_otg_hs_slaves),
- .masters = omap44xx_usb_otg_hs_masters,
- .masters_cnt = ARRAY_SIZE(omap44xx_usb_otg_hs_masters),
+};
+
+/*
+ * 'usb_tll_hs' class
+ * usb_tll_hs module is the adapter on the usb_host_hs ports
+ */
+
+static struct omap_hwmod_class_sysconfig omap44xx_usb_tll_hs_sysc = {
+ .rev_offs = 0x0000,
+ .sysc_offs = 0x0010,
+ .syss_offs = 0x0014,
+ .sysc_flags = (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
+ SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
+ SYSC_HAS_AUTOIDLE),
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class omap44xx_usb_tll_hs_hwmod_class = {
+ .name = "usb_tll_hs",
+ .sysc = &omap44xx_usb_tll_hs_sysc,
+};
+
+static struct omap_hwmod_irq_info omap44xx_usb_tll_hs_irqs[] = {
+ { .name = "tll-irq", .irq = 78 + OMAP44XX_IRQ_GIC_START },
+ { .irq = -1 }
+};
+
+static struct omap_hwmod omap44xx_usb_tll_hs_hwmod = {
+ .name = "usb_tll_hs",
+ .class = &omap44xx_usb_tll_hs_hwmod_class,
+ .clkdm_name = "l3_init_clkdm",
+ .mpu_irqs = omap44xx_usb_tll_hs_irqs,
+ .main_clk = "usb_tll_hs_ick",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = OMAP4_CM_L3INIT_USB_TLL_CLKCTRL_OFFSET,
+ .context_offs = OMAP4_RM_L3INIT_USB_TLL_CONTEXT_OFFSET,
+ .modulemode = MODULEMODE_HWCTRL,
+ },
+ },
};
/*
@@ -5215,38 +3535,15 @@ static struct omap_hwmod_class omap44xx_wd_timer_hwmod_class = {
.name = "wd_timer",
.sysc = &omap44xx_wd_timer_sysc,
.pre_shutdown = &omap2_wd_timer_disable,
+ .reset = &omap2_wd_timer_reset,
};
/* wd_timer2 */
-static struct omap_hwmod omap44xx_wd_timer2_hwmod;
static struct omap_hwmod_irq_info omap44xx_wd_timer2_irqs[] = {
{ .irq = 80 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_wd_timer2_addrs[] = {
- {
- .pa_start = 0x4a314000,
- .pa_end = 0x4a31407f,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
-/* l4_wkup -> wd_timer2 */
-static struct omap_hwmod_ocp_if omap44xx_l4_wkup__wd_timer2 = {
- .master = &omap44xx_l4_wkup_hwmod,
- .slave = &omap44xx_wd_timer2_hwmod,
- .clk = "l4_wkup_clk_mux_ck",
- .addr = omap44xx_wd_timer2_addrs,
- .user = OCP_USER_MPU | OCP_USER_SDMA,
-};
-
-/* wd_timer2 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_wd_timer2_slaves[] = {
- &omap44xx_l4_wkup__wd_timer2,
-};
-
static struct omap_hwmod omap44xx_wd_timer2_hwmod = {
.name = "wd_timer2",
.class = &omap44xx_wd_timer_hwmod_class,
@@ -5260,106 +3557,2308 @@ static struct omap_hwmod omap44xx_wd_timer2_hwmod = {
.modulemode = MODULEMODE_SWCTRL,
},
},
- .slaves = omap44xx_wd_timer2_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_wd_timer2_slaves),
};
/* wd_timer3 */
-static struct omap_hwmod omap44xx_wd_timer3_hwmod;
static struct omap_hwmod_irq_info omap44xx_wd_timer3_irqs[] = {
{ .irq = 36 + OMAP44XX_IRQ_GIC_START },
{ .irq = -1 }
};
-static struct omap_hwmod_addr_space omap44xx_wd_timer3_addrs[] = {
+static struct omap_hwmod omap44xx_wd_timer3_hwmod = {
+ .name = "wd_timer3",
+ .class = &omap44xx_wd_timer_hwmod_class,
+ .clkdm_name = "abe_clkdm",
+ .mpu_irqs = omap44xx_wd_timer3_irqs,
+ .main_clk = "wd_timer3_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = OMAP4_CM1_ABE_WDT3_CLKCTRL_OFFSET,
+ .context_offs = OMAP4_RM_ABE_WDT3_CONTEXT_OFFSET,
+ .modulemode = MODULEMODE_SWCTRL,
+ },
+ },
+};
+
+
+/*
+ * interfaces
+ */
+
+static struct omap_hwmod_addr_space omap44xx_c2c_target_fw_addrs[] = {
{
- .pa_start = 0x40130000,
- .pa_end = 0x4013007f,
+ .pa_start = 0x4a204000,
+ .pa_end = 0x4a2040ff,
.flags = ADDR_TYPE_RT
},
{ }
};
-/* l4_abe -> wd_timer3 */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__wd_timer3 = {
+/* c2c -> c2c_target_fw */
+static struct omap_hwmod_ocp_if omap44xx_c2c__c2c_target_fw = {
+ .master = &omap44xx_c2c_hwmod,
+ .slave = &omap44xx_c2c_target_fw_hwmod,
+ .clk = "div_core_ck",
+ .addr = omap44xx_c2c_target_fw_addrs,
+ .user = OCP_USER_MPU,
+};
+
+/* l4_cfg -> c2c_target_fw */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__c2c_target_fw = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_c2c_target_fw_hwmod,
+ .clk = "l4_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_1 -> dmm */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_1__dmm = {
+ .master = &omap44xx_l3_main_1_hwmod,
+ .slave = &omap44xx_dmm_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dmm_addrs[] = {
+ {
+ .pa_start = 0x4e000000,
+ .pa_end = 0x4e0007ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* mpu -> dmm */
+static struct omap_hwmod_ocp_if omap44xx_mpu__dmm = {
+ .master = &omap44xx_mpu_hwmod,
+ .slave = &omap44xx_dmm_hwmod,
+ .clk = "l3_div_ck",
+ .addr = omap44xx_dmm_addrs,
+ .user = OCP_USER_MPU,
+};
+
+/* c2c -> emif_fw */
+static struct omap_hwmod_ocp_if omap44xx_c2c__emif_fw = {
+ .master = &omap44xx_c2c_hwmod,
+ .slave = &omap44xx_emif_fw_hwmod,
+ .clk = "div_core_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dmm -> emif_fw */
+static struct omap_hwmod_ocp_if omap44xx_dmm__emif_fw = {
+ .master = &omap44xx_dmm_hwmod,
+ .slave = &omap44xx_emif_fw_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_emif_fw_addrs[] = {
+ {
+ .pa_start = 0x4a20c000,
+ .pa_end = 0x4a20c0ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_cfg -> emif_fw */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__emif_fw = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_emif_fw_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_emif_fw_addrs,
+ .user = OCP_USER_MPU,
+};
+
+/* iva -> l3_instr */
+static struct omap_hwmod_ocp_if omap44xx_iva__l3_instr = {
+ .master = &omap44xx_iva_hwmod,
+ .slave = &omap44xx_l3_instr_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_3 -> l3_instr */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_3__l3_instr = {
+ .master = &omap44xx_l3_main_3_hwmod,
+ .slave = &omap44xx_l3_instr_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* ocp_wp_noc -> l3_instr */
+static struct omap_hwmod_ocp_if omap44xx_ocp_wp_noc__l3_instr = {
+ .master = &omap44xx_ocp_wp_noc_hwmod,
+ .slave = &omap44xx_l3_instr_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dsp -> l3_main_1 */
+static struct omap_hwmod_ocp_if omap44xx_dsp__l3_main_1 = {
+ .master = &omap44xx_dsp_hwmod,
+ .slave = &omap44xx_l3_main_1_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dss -> l3_main_1 */
+static struct omap_hwmod_ocp_if omap44xx_dss__l3_main_1 = {
+ .master = &omap44xx_dss_hwmod,
+ .slave = &omap44xx_l3_main_1_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_2 -> l3_main_1 */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__l3_main_1 = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_l3_main_1_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_cfg -> l3_main_1 */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_1 = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_l3_main_1_hwmod,
+ .clk = "l4_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mmc1 -> l3_main_1 */
+static struct omap_hwmod_ocp_if omap44xx_mmc1__l3_main_1 = {
+ .master = &omap44xx_mmc1_hwmod,
+ .slave = &omap44xx_l3_main_1_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mmc2 -> l3_main_1 */
+static struct omap_hwmod_ocp_if omap44xx_mmc2__l3_main_1 = {
+ .master = &omap44xx_mmc2_hwmod,
+ .slave = &omap44xx_l3_main_1_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_l3_main_1_addrs[] = {
+ {
+ .pa_start = 0x44000000,
+ .pa_end = 0x44000fff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* mpu -> l3_main_1 */
+static struct omap_hwmod_ocp_if omap44xx_mpu__l3_main_1 = {
+ .master = &omap44xx_mpu_hwmod,
+ .slave = &omap44xx_l3_main_1_hwmod,
+ .clk = "l3_div_ck",
+ .addr = omap44xx_l3_main_1_addrs,
+ .user = OCP_USER_MPU,
+};
+
+/* c2c_target_fw -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_c2c_target_fw__l3_main_2 = {
+ .master = &omap44xx_c2c_target_fw_hwmod,
+ .slave = &omap44xx_l3_main_2_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* debugss -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_debugss__l3_main_2 = {
+ .master = &omap44xx_debugss_hwmod,
+ .slave = &omap44xx_l3_main_2_hwmod,
+ .clk = "dbgclk_mux_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dma_system -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_dma_system__l3_main_2 = {
+ .master = &omap44xx_dma_system_hwmod,
+ .slave = &omap44xx_l3_main_2_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* fdif -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_fdif__l3_main_2 = {
+ .master = &omap44xx_fdif_hwmod,
+ .slave = &omap44xx_l3_main_2_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* gpu -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_gpu__l3_main_2 = {
+ .master = &omap44xx_gpu_hwmod,
+ .slave = &omap44xx_l3_main_2_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* hsi -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_hsi__l3_main_2 = {
+ .master = &omap44xx_hsi_hwmod,
+ .slave = &omap44xx_l3_main_2_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* ipu -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_ipu__l3_main_2 = {
+ .master = &omap44xx_ipu_hwmod,
+ .slave = &omap44xx_l3_main_2_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* iss -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_iss__l3_main_2 = {
+ .master = &omap44xx_iss_hwmod,
+ .slave = &omap44xx_l3_main_2_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* iva -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_iva__l3_main_2 = {
+ .master = &omap44xx_iva_hwmod,
+ .slave = &omap44xx_l3_main_2_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_l3_main_2_addrs[] = {
+ {
+ .pa_start = 0x44800000,
+ .pa_end = 0x44801fff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l3_main_1 -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l3_main_2 = {
+ .master = &omap44xx_l3_main_1_hwmod,
+ .slave = &omap44xx_l3_main_2_hwmod,
+ .clk = "l3_div_ck",
+ .addr = omap44xx_l3_main_2_addrs,
+ .user = OCP_USER_MPU,
+};
+
+/* l4_cfg -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_2 = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_l3_main_2_hwmod,
+ .clk = "l4_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* usb_host_fs -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_usb_host_fs__l3_main_2 = {
+ .master = &omap44xx_usb_host_fs_hwmod,
+ .slave = &omap44xx_l3_main_2_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* usb_host_hs -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_usb_host_hs__l3_main_2 = {
+ .master = &omap44xx_usb_host_hs_hwmod,
+ .slave = &omap44xx_l3_main_2_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* usb_otg_hs -> l3_main_2 */
+static struct omap_hwmod_ocp_if omap44xx_usb_otg_hs__l3_main_2 = {
+ .master = &omap44xx_usb_otg_hs_hwmod,
+ .slave = &omap44xx_l3_main_2_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_l3_main_3_addrs[] = {
+ {
+ .pa_start = 0x45000000,
+ .pa_end = 0x45000fff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l3_main_1 -> l3_main_3 */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l3_main_3 = {
+ .master = &omap44xx_l3_main_1_hwmod,
+ .slave = &omap44xx_l3_main_3_hwmod,
+ .clk = "l3_div_ck",
+ .addr = omap44xx_l3_main_3_addrs,
+ .user = OCP_USER_MPU,
+};
+
+/* l3_main_2 -> l3_main_3 */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__l3_main_3 = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_l3_main_3_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_cfg -> l3_main_3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l3_main_3 = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_l3_main_3_hwmod,
+ .clk = "l4_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* aess -> l4_abe */
+static struct omap_hwmod_ocp_if omap44xx_aess__l4_abe = {
+ .master = &omap44xx_aess_hwmod,
+ .slave = &omap44xx_l4_abe_hwmod,
+ .clk = "ocp_abe_iclk",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* dsp -> l4_abe */
+static struct omap_hwmod_ocp_if omap44xx_dsp__l4_abe = {
+ .master = &omap44xx_dsp_hwmod,
+ .slave = &omap44xx_l4_abe_hwmod,
+ .clk = "ocp_abe_iclk",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_1 -> l4_abe */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l4_abe = {
+ .master = &omap44xx_l3_main_1_hwmod,
+ .slave = &omap44xx_l4_abe_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mpu -> l4_abe */
+static struct omap_hwmod_ocp_if omap44xx_mpu__l4_abe = {
+ .master = &omap44xx_mpu_hwmod,
+ .slave = &omap44xx_l4_abe_hwmod,
+ .clk = "ocp_abe_iclk",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_1 -> l4_cfg */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_1__l4_cfg = {
+ .master = &omap44xx_l3_main_1_hwmod,
+ .slave = &omap44xx_l4_cfg_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_2 -> l4_per */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__l4_per = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_l4_per_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_cfg -> l4_wkup */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__l4_wkup = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_l4_wkup_hwmod,
+ .clk = "l4_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mpu -> mpu_private */
+static struct omap_hwmod_ocp_if omap44xx_mpu__mpu_private = {
+ .master = &omap44xx_mpu_hwmod,
+ .slave = &omap44xx_mpu_private_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_ocp_wp_noc_addrs[] = {
+ {
+ .pa_start = 0x4a102000,
+ .pa_end = 0x4a10207f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_cfg -> ocp_wp_noc */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__ocp_wp_noc = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_ocp_wp_noc_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_ocp_wp_noc_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_aess_addrs[] = {
+ {
+ .pa_start = 0x401f1000,
+ .pa_end = 0x401f13ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> aess */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__aess = {
.master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_wd_timer3_hwmod,
+ .slave = &omap44xx_aess_hwmod,
.clk = "ocp_abe_iclk",
- .addr = omap44xx_wd_timer3_addrs,
+ .addr = omap44xx_aess_addrs,
.user = OCP_USER_MPU,
};
-static struct omap_hwmod_addr_space omap44xx_wd_timer3_dma_addrs[] = {
+static struct omap_hwmod_addr_space omap44xx_aess_dma_addrs[] = {
{
- .pa_start = 0x49030000,
- .pa_end = 0x4903007f,
+ .pa_start = 0x490f1000,
+ .pa_end = 0x490f13ff,
.flags = ADDR_TYPE_RT
},
{ }
};
-/* l4_abe -> wd_timer3 (dma) */
-static struct omap_hwmod_ocp_if omap44xx_l4_abe__wd_timer3_dma = {
+/* l4_abe -> aess (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__aess_dma = {
.master = &omap44xx_l4_abe_hwmod,
- .slave = &omap44xx_wd_timer3_hwmod,
+ .slave = &omap44xx_aess_hwmod,
.clk = "ocp_abe_iclk",
- .addr = omap44xx_wd_timer3_dma_addrs,
+ .addr = omap44xx_aess_dma_addrs,
.user = OCP_USER_SDMA,
};
-/* wd_timer3 slave ports */
-static struct omap_hwmod_ocp_if *omap44xx_wd_timer3_slaves[] = {
- &omap44xx_l4_abe__wd_timer3,
- &omap44xx_l4_abe__wd_timer3_dma,
+/* l3_main_2 -> c2c */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__c2c = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_c2c_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
};
-static struct omap_hwmod omap44xx_wd_timer3_hwmod = {
- .name = "wd_timer3",
- .class = &omap44xx_wd_timer_hwmod_class,
- .clkdm_name = "abe_clkdm",
- .mpu_irqs = omap44xx_wd_timer3_irqs,
- .main_clk = "wd_timer3_fck",
- .prcm = {
- .omap4 = {
- .clkctrl_offs = OMAP4_CM1_ABE_WDT3_CLKCTRL_OFFSET,
- .context_offs = OMAP4_RM_ABE_WDT3_CONTEXT_OFFSET,
- .modulemode = MODULEMODE_SWCTRL,
- },
+static struct omap_hwmod_addr_space omap44xx_counter_32k_addrs[] = {
+ {
+ .pa_start = 0x4a304000,
+ .pa_end = 0x4a30401f,
+ .flags = ADDR_TYPE_RT
},
- .slaves = omap44xx_wd_timer3_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_wd_timer3_slaves),
+ { }
};
-/*
- * 'usb_host_hs' class
- * high-speed multi-port usb host controller
- */
-static struct omap_hwmod_ocp_if omap44xx_usb_host_hs__l3_main_2 = {
- .master = &omap44xx_usb_host_hs_hwmod,
- .slave = &omap44xx_l3_main_2_hwmod,
+/* l4_wkup -> counter_32k */
+static struct omap_hwmod_ocp_if omap44xx_l4_wkup__counter_32k = {
+ .master = &omap44xx_l4_wkup_hwmod,
+ .slave = &omap44xx_counter_32k_hwmod,
+ .clk = "l4_wkup_clk_mux_ck",
+ .addr = omap44xx_counter_32k_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_ctrl_module_core_addrs[] = {
+ {
+ .pa_start = 0x4a002000,
+ .pa_end = 0x4a0027ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_cfg -> ctrl_module_core */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__ctrl_module_core = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_ctrl_module_core_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_ctrl_module_core_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_ctrl_module_pad_core_addrs[] = {
+ {
+ .pa_start = 0x4a100000,
+ .pa_end = 0x4a1007ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_cfg -> ctrl_module_pad_core */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__ctrl_module_pad_core = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_ctrl_module_pad_core_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_ctrl_module_pad_core_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_ctrl_module_wkup_addrs[] = {
+ {
+ .pa_start = 0x4a30c000,
+ .pa_end = 0x4a30c7ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_wkup -> ctrl_module_wkup */
+static struct omap_hwmod_ocp_if omap44xx_l4_wkup__ctrl_module_wkup = {
+ .master = &omap44xx_l4_wkup_hwmod,
+ .slave = &omap44xx_ctrl_module_wkup_hwmod,
+ .clk = "l4_wkup_clk_mux_ck",
+ .addr = omap44xx_ctrl_module_wkup_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_ctrl_module_pad_wkup_addrs[] = {
+ {
+ .pa_start = 0x4a31e000,
+ .pa_end = 0x4a31e7ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_wkup -> ctrl_module_pad_wkup */
+static struct omap_hwmod_ocp_if omap44xx_l4_wkup__ctrl_module_pad_wkup = {
+ .master = &omap44xx_l4_wkup_hwmod,
+ .slave = &omap44xx_ctrl_module_pad_wkup_hwmod,
+ .clk = "l4_wkup_clk_mux_ck",
+ .addr = omap44xx_ctrl_module_pad_wkup_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_debugss_addrs[] = {
+ {
+ .pa_start = 0x54160000,
+ .pa_end = 0x54167fff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l3_instr -> debugss */
+static struct omap_hwmod_ocp_if omap44xx_l3_instr__debugss = {
+ .master = &omap44xx_l3_instr_hwmod,
+ .slave = &omap44xx_debugss_hwmod,
.clk = "l3_div_ck",
+ .addr = omap44xx_debugss_addrs,
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-static struct omap_hwmod_class_sysconfig omap44xx_usb_host_hs_sysc = {
- .rev_offs = 0x0000,
- .sysc_offs = 0x0010,
- .syss_offs = 0x0014,
- .sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE |
- SYSC_HAS_SOFTRESET),
- .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
- SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
- MSTANDBY_SMART | MSTANDBY_SMART_WKUP),
- .sysc_fields = &omap_hwmod_sysc_type2,
+static struct omap_hwmod_addr_space omap44xx_dma_system_addrs[] = {
+ {
+ .pa_start = 0x4a056000,
+ .pa_end = 0x4a056fff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
};
-static struct omap_hwmod_class omap44xx_usb_host_hs_hwmod_class = {
- .name = "usb_host_hs",
- .sysc = &omap44xx_usb_host_hs_sysc,
+/* l4_cfg -> dma_system */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__dma_system = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_dma_system_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_dma_system_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
};
-static struct omap_hwmod_ocp_if *omap44xx_usb_host_hs_masters[] = {
- &omap44xx_usb_host_hs__l3_main_2,
+static struct omap_hwmod_addr_space omap44xx_dmic_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x4012e000,
+ .pa_end = 0x4012e07f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> dmic */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__dmic = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_dmic_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_dmic_addrs,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dmic_dma_addrs[] = {
+ {
+ .name = "dma",
+ .pa_start = 0x4902e000,
+ .pa_end = 0x4902e07f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> dmic (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__dmic_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_dmic_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_dmic_dma_addrs,
+ .user = OCP_USER_SDMA,
+};
+
+/* dsp -> iva */
+static struct omap_hwmod_ocp_if omap44xx_dsp__iva = {
+ .master = &omap44xx_dsp_hwmod,
+ .slave = &omap44xx_iva_hwmod,
+ .clk = "dpll_iva_m5x2_ck",
+ .user = OCP_USER_DSP,
+};
+
+/* dsp -> sl2if */
+static struct omap_hwmod_ocp_if omap44xx_dsp__sl2if = {
+ .master = &omap44xx_dsp_hwmod,
+ .slave = &omap44xx_sl2if_hwmod,
+ .clk = "dpll_iva_m5x2_ck",
+ .user = OCP_USER_DSP,
+};
+
+/* l4_cfg -> dsp */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__dsp = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_dsp_hwmod,
+ .clk = "l4_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_dma_addrs[] = {
+ {
+ .pa_start = 0x58000000,
+ .pa_end = 0x5800007f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l3_main_2 -> dss */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_dss_hwmod,
+ .clk = "dss_fck",
+ .addr = omap44xx_dss_dma_addrs,
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_addrs[] = {
+ {
+ .pa_start = 0x48040000,
+ .pa_end = 0x4804007f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> dss */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__dss = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_dss_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_dss_addrs,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_dispc_dma_addrs[] = {
+ {
+ .pa_start = 0x58001000,
+ .pa_end = 0x58001fff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l3_main_2 -> dss_dispc */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dispc = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_dss_dispc_hwmod,
+ .clk = "dss_fck",
+ .addr = omap44xx_dss_dispc_dma_addrs,
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_dispc_addrs[] = {
+ {
+ .pa_start = 0x48041000,
+ .pa_end = 0x48041fff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> dss_dispc */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__dss_dispc = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_dss_dispc_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_dss_dispc_addrs,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_dsi1_dma_addrs[] = {
+ {
+ .pa_start = 0x58004000,
+ .pa_end = 0x580041ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l3_main_2 -> dss_dsi1 */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dsi1 = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_dss_dsi1_hwmod,
+ .clk = "dss_fck",
+ .addr = omap44xx_dss_dsi1_dma_addrs,
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_dsi1_addrs[] = {
+ {
+ .pa_start = 0x48044000,
+ .pa_end = 0x480441ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> dss_dsi1 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__dss_dsi1 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_dss_dsi1_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_dss_dsi1_addrs,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_dsi2_dma_addrs[] = {
+ {
+ .pa_start = 0x58005000,
+ .pa_end = 0x580051ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l3_main_2 -> dss_dsi2 */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dsi2 = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_dss_dsi2_hwmod,
+ .clk = "dss_fck",
+ .addr = omap44xx_dss_dsi2_dma_addrs,
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_dsi2_addrs[] = {
+ {
+ .pa_start = 0x48045000,
+ .pa_end = 0x480451ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> dss_dsi2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__dss_dsi2 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_dss_dsi2_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_dss_dsi2_addrs,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_hdmi_dma_addrs[] = {
+ {
+ .pa_start = 0x58006000,
+ .pa_end = 0x58006fff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l3_main_2 -> dss_hdmi */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_hdmi = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_dss_hdmi_hwmod,
+ .clk = "dss_fck",
+ .addr = omap44xx_dss_hdmi_dma_addrs,
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_hdmi_addrs[] = {
+ {
+ .pa_start = 0x48046000,
+ .pa_end = 0x48046fff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> dss_hdmi */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__dss_hdmi = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_dss_hdmi_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_dss_hdmi_addrs,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_rfbi_dma_addrs[] = {
+ {
+ .pa_start = 0x58002000,
+ .pa_end = 0x580020ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l3_main_2 -> dss_rfbi */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_rfbi = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_dss_rfbi_hwmod,
+ .clk = "dss_fck",
+ .addr = omap44xx_dss_rfbi_dma_addrs,
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_rfbi_addrs[] = {
+ {
+ .pa_start = 0x48042000,
+ .pa_end = 0x480420ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> dss_rfbi */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__dss_rfbi = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_dss_rfbi_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_dss_rfbi_addrs,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_venc_dma_addrs[] = {
+ {
+ .pa_start = 0x58003000,
+ .pa_end = 0x580030ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l3_main_2 -> dss_venc */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_venc = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_dss_venc_hwmod,
+ .clk = "dss_fck",
+ .addr = omap44xx_dss_venc_dma_addrs,
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_dss_venc_addrs[] = {
+ {
+ .pa_start = 0x48043000,
+ .pa_end = 0x480430ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> dss_venc */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__dss_venc = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_dss_venc_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_dss_venc_addrs,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_elm_addrs[] = {
+ {
+ .pa_start = 0x48078000,
+ .pa_end = 0x48078fff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> elm */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__elm = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_elm_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_elm_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_emif1_addrs[] = {
+ {
+ .pa_start = 0x4c000000,
+ .pa_end = 0x4c0000ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* emif_fw -> emif1 */
+static struct omap_hwmod_ocp_if omap44xx_emif_fw__emif1 = {
+ .master = &omap44xx_emif_fw_hwmod,
+ .slave = &omap44xx_emif1_hwmod,
+ .clk = "l3_div_ck",
+ .addr = omap44xx_emif1_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_emif2_addrs[] = {
+ {
+ .pa_start = 0x4d000000,
+ .pa_end = 0x4d0000ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* emif_fw -> emif2 */
+static struct omap_hwmod_ocp_if omap44xx_emif_fw__emif2 = {
+ .master = &omap44xx_emif_fw_hwmod,
+ .slave = &omap44xx_emif2_hwmod,
+ .clk = "l3_div_ck",
+ .addr = omap44xx_emif2_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_fdif_addrs[] = {
+ {
+ .pa_start = 0x4a10a000,
+ .pa_end = 0x4a10a1ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_cfg -> fdif */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__fdif = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_fdif_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_fdif_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_gpio1_addrs[] = {
+ {
+ .pa_start = 0x4a310000,
+ .pa_end = 0x4a3101ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_wkup -> gpio1 */
+static struct omap_hwmod_ocp_if omap44xx_l4_wkup__gpio1 = {
+ .master = &omap44xx_l4_wkup_hwmod,
+ .slave = &omap44xx_gpio1_hwmod,
+ .clk = "l4_wkup_clk_mux_ck",
+ .addr = omap44xx_gpio1_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_gpio2_addrs[] = {
+ {
+ .pa_start = 0x48055000,
+ .pa_end = 0x480551ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> gpio2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__gpio2 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_gpio2_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_gpio2_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_gpio3_addrs[] = {
+ {
+ .pa_start = 0x48057000,
+ .pa_end = 0x480571ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> gpio3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__gpio3 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_gpio3_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_gpio3_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_gpio4_addrs[] = {
+ {
+ .pa_start = 0x48059000,
+ .pa_end = 0x480591ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> gpio4 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__gpio4 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_gpio4_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_gpio4_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_gpio5_addrs[] = {
+ {
+ .pa_start = 0x4805b000,
+ .pa_end = 0x4805b1ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> gpio5 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__gpio5 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_gpio5_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_gpio5_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_gpio6_addrs[] = {
+ {
+ .pa_start = 0x4805d000,
+ .pa_end = 0x4805d1ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> gpio6 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__gpio6 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_gpio6_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_gpio6_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_gpmc_addrs[] = {
+ {
+ .pa_start = 0x50000000,
+ .pa_end = 0x500003ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l3_main_2 -> gpmc */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__gpmc = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_gpmc_hwmod,
+ .clk = "l3_div_ck",
+ .addr = omap44xx_gpmc_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_gpu_addrs[] = {
+ {
+ .pa_start = 0x56000000,
+ .pa_end = 0x5600ffff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l3_main_2 -> gpu */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__gpu = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_gpu_hwmod,
+ .clk = "l3_div_ck",
+ .addr = omap44xx_gpu_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_hdq1w_addrs[] = {
+ {
+ .pa_start = 0x480b2000,
+ .pa_end = 0x480b201f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> hdq1w */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__hdq1w = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_hdq1w_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_hdq1w_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_hsi_addrs[] = {
+ {
+ .pa_start = 0x4a058000,
+ .pa_end = 0x4a05bfff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_cfg -> hsi */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__hsi = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_hsi_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_hsi_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_i2c1_addrs[] = {
+ {
+ .pa_start = 0x48070000,
+ .pa_end = 0x480700ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> i2c1 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__i2c1 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_i2c1_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_i2c1_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_i2c2_addrs[] = {
+ {
+ .pa_start = 0x48072000,
+ .pa_end = 0x480720ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> i2c2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__i2c2 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_i2c2_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_i2c2_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_i2c3_addrs[] = {
+ {
+ .pa_start = 0x48060000,
+ .pa_end = 0x480600ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> i2c3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__i2c3 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_i2c3_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_i2c3_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_i2c4_addrs[] = {
+ {
+ .pa_start = 0x48350000,
+ .pa_end = 0x483500ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> i2c4 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__i2c4 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_i2c4_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_i2c4_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_2 -> ipu */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__ipu = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_ipu_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_iss_addrs[] = {
+ {
+ .pa_start = 0x52000000,
+ .pa_end = 0x520000ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l3_main_2 -> iss */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__iss = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_iss_hwmod,
+ .clk = "l3_div_ck",
+ .addr = omap44xx_iss_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* iva -> sl2if */
+static struct omap_hwmod_ocp_if omap44xx_iva__sl2if = {
+ .master = &omap44xx_iva_hwmod,
+ .slave = &omap44xx_sl2if_hwmod,
+ .clk = "dpll_iva_m5x2_ck",
+ .user = OCP_USER_IVA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_iva_addrs[] = {
+ {
+ .pa_start = 0x5a000000,
+ .pa_end = 0x5a07ffff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l3_main_2 -> iva */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__iva = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_iva_hwmod,
+ .clk = "l3_div_ck",
+ .addr = omap44xx_iva_addrs,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_kbd_addrs[] = {
+ {
+ .pa_start = 0x4a31c000,
+ .pa_end = 0x4a31c07f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_wkup -> kbd */
+static struct omap_hwmod_ocp_if omap44xx_l4_wkup__kbd = {
+ .master = &omap44xx_l4_wkup_hwmod,
+ .slave = &omap44xx_kbd_hwmod,
+ .clk = "l4_wkup_clk_mux_ck",
+ .addr = omap44xx_kbd_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mailbox_addrs[] = {
+ {
+ .pa_start = 0x4a0f4000,
+ .pa_end = 0x4a0f41ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_cfg -> mailbox */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__mailbox = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_mailbox_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_mailbox_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcasp_addrs[] = {
+ {
+ .pa_start = 0x40128000,
+ .pa_end = 0x401283ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> mcasp */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcasp = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_mcasp_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_mcasp_addrs,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcasp_dma_addrs[] = {
+ {
+ .pa_start = 0x49028000,
+ .pa_end = 0x490283ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> mcasp (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcasp_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_mcasp_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_mcasp_dma_addrs,
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcbsp1_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x40122000,
+ .pa_end = 0x401220ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> mcbsp1 */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcbsp1 = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_mcbsp1_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_mcbsp1_addrs,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcbsp1_dma_addrs[] = {
+ {
+ .name = "dma",
+ .pa_start = 0x49022000,
+ .pa_end = 0x490220ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> mcbsp1 (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcbsp1_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_mcbsp1_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_mcbsp1_dma_addrs,
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcbsp2_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x40124000,
+ .pa_end = 0x401240ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> mcbsp2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcbsp2 = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_mcbsp2_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_mcbsp2_addrs,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcbsp2_dma_addrs[] = {
+ {
+ .name = "dma",
+ .pa_start = 0x49024000,
+ .pa_end = 0x490240ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> mcbsp2 (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcbsp2_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_mcbsp2_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_mcbsp2_dma_addrs,
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcbsp3_addrs[] = {
+ {
+ .name = "mpu",
+ .pa_start = 0x40126000,
+ .pa_end = 0x401260ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> mcbsp3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcbsp3 = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_mcbsp3_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_mcbsp3_addrs,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcbsp3_dma_addrs[] = {
+ {
+ .name = "dma",
+ .pa_start = 0x49026000,
+ .pa_end = 0x490260ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> mcbsp3 (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcbsp3_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_mcbsp3_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_mcbsp3_dma_addrs,
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcbsp4_addrs[] = {
+ {
+ .pa_start = 0x48096000,
+ .pa_end = 0x480960ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> mcbsp4 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__mcbsp4 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_mcbsp4_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_mcbsp4_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcpdm_addrs[] = {
+ {
+ .pa_start = 0x40132000,
+ .pa_end = 0x4013207f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> mcpdm */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcpdm = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_mcpdm_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_mcpdm_addrs,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcpdm_dma_addrs[] = {
+ {
+ .pa_start = 0x49032000,
+ .pa_end = 0x4903207f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> mcpdm (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__mcpdm_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_mcpdm_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_mcpdm_dma_addrs,
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcspi1_addrs[] = {
+ {
+ .pa_start = 0x48098000,
+ .pa_end = 0x480981ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> mcspi1 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__mcspi1 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_mcspi1_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_mcspi1_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcspi2_addrs[] = {
+ {
+ .pa_start = 0x4809a000,
+ .pa_end = 0x4809a1ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> mcspi2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__mcspi2 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_mcspi2_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_mcspi2_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcspi3_addrs[] = {
+ {
+ .pa_start = 0x480b8000,
+ .pa_end = 0x480b81ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> mcspi3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__mcspi3 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_mcspi3_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_mcspi3_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mcspi4_addrs[] = {
+ {
+ .pa_start = 0x480ba000,
+ .pa_end = 0x480ba1ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> mcspi4 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__mcspi4 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_mcspi4_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_mcspi4_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mmc1_addrs[] = {
+ {
+ .pa_start = 0x4809c000,
+ .pa_end = 0x4809c3ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> mmc1 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__mmc1 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_mmc1_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_mmc1_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mmc2_addrs[] = {
+ {
+ .pa_start = 0x480b4000,
+ .pa_end = 0x480b43ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> mmc2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__mmc2 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_mmc2_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_mmc2_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mmc3_addrs[] = {
+ {
+ .pa_start = 0x480ad000,
+ .pa_end = 0x480ad3ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> mmc3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__mmc3 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_mmc3_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_mmc3_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mmc4_addrs[] = {
+ {
+ .pa_start = 0x480d1000,
+ .pa_end = 0x480d13ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> mmc4 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__mmc4 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_mmc4_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_mmc4_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_mmc5_addrs[] = {
+ {
+ .pa_start = 0x480d5000,
+ .pa_end = 0x480d53ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> mmc5 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__mmc5 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_mmc5_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_mmc5_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_2 -> ocmc_ram */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__ocmc_ram = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_ocmc_ram_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_cfg -> ocp2scp_usb_phy */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__ocp2scp_usb_phy = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_ocp2scp_usb_phy_hwmod,
+ .clk = "l4_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_prcm_mpu_addrs[] = {
+ {
+ .pa_start = 0x48243000,
+ .pa_end = 0x48243fff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* mpu_private -> prcm_mpu */
+static struct omap_hwmod_ocp_if omap44xx_mpu_private__prcm_mpu = {
+ .master = &omap44xx_mpu_private_hwmod,
+ .slave = &omap44xx_prcm_mpu_hwmod,
+ .clk = "l3_div_ck",
+ .addr = omap44xx_prcm_mpu_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_cm_core_aon_addrs[] = {
+ {
+ .pa_start = 0x4a004000,
+ .pa_end = 0x4a004fff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_wkup -> cm_core_aon */
+static struct omap_hwmod_ocp_if omap44xx_l4_wkup__cm_core_aon = {
+ .master = &omap44xx_l4_wkup_hwmod,
+ .slave = &omap44xx_cm_core_aon_hwmod,
+ .clk = "l4_wkup_clk_mux_ck",
+ .addr = omap44xx_cm_core_aon_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_cm_core_addrs[] = {
+ {
+ .pa_start = 0x4a008000,
+ .pa_end = 0x4a009fff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_cfg -> cm_core */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__cm_core = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_cm_core_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_cm_core_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_prm_addrs[] = {
+ {
+ .pa_start = 0x4a306000,
+ .pa_end = 0x4a307fff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_wkup -> prm */
+static struct omap_hwmod_ocp_if omap44xx_l4_wkup__prm = {
+ .master = &omap44xx_l4_wkup_hwmod,
+ .slave = &omap44xx_prm_hwmod,
+ .clk = "l4_wkup_clk_mux_ck",
+ .addr = omap44xx_prm_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_scrm_addrs[] = {
+ {
+ .pa_start = 0x4a30a000,
+ .pa_end = 0x4a30a7ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_wkup -> scrm */
+static struct omap_hwmod_ocp_if omap44xx_l4_wkup__scrm = {
+ .master = &omap44xx_l4_wkup_hwmod,
+ .slave = &omap44xx_scrm_hwmod,
+ .clk = "l4_wkup_clk_mux_ck",
+ .addr = omap44xx_scrm_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_2 -> sl2if */
+static struct omap_hwmod_ocp_if omap44xx_l3_main_2__sl2if = {
+ .master = &omap44xx_l3_main_2_hwmod,
+ .slave = &omap44xx_sl2if_hwmod,
+ .clk = "l3_div_ck",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_slimbus1_addrs[] = {
+ {
+ .pa_start = 0x4012c000,
+ .pa_end = 0x4012c3ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> slimbus1 */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__slimbus1 = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_slimbus1_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_slimbus1_addrs,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_slimbus1_dma_addrs[] = {
+ {
+ .pa_start = 0x4902c000,
+ .pa_end = 0x4902c3ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> slimbus1 (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__slimbus1_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_slimbus1_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_slimbus1_dma_addrs,
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_slimbus2_addrs[] = {
+ {
+ .pa_start = 0x48076000,
+ .pa_end = 0x480763ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> slimbus2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__slimbus2 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_slimbus2_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_slimbus2_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_smartreflex_core_addrs[] = {
+ {
+ .pa_start = 0x4a0dd000,
+ .pa_end = 0x4a0dd03f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_cfg -> smartreflex_core */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__smartreflex_core = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_smartreflex_core_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_smartreflex_core_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_smartreflex_iva_addrs[] = {
+ {
+ .pa_start = 0x4a0db000,
+ .pa_end = 0x4a0db03f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_cfg -> smartreflex_iva */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__smartreflex_iva = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_smartreflex_iva_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_smartreflex_iva_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_smartreflex_mpu_addrs[] = {
+ {
+ .pa_start = 0x4a0d9000,
+ .pa_end = 0x4a0d903f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_cfg -> smartreflex_mpu */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__smartreflex_mpu = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_smartreflex_mpu_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_smartreflex_mpu_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_spinlock_addrs[] = {
+ {
+ .pa_start = 0x4a0f6000,
+ .pa_end = 0x4a0f6fff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_cfg -> spinlock */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__spinlock = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_spinlock_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_spinlock_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer1_addrs[] = {
+ {
+ .pa_start = 0x4a318000,
+ .pa_end = 0x4a31807f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_wkup -> timer1 */
+static struct omap_hwmod_ocp_if omap44xx_l4_wkup__timer1 = {
+ .master = &omap44xx_l4_wkup_hwmod,
+ .slave = &omap44xx_timer1_hwmod,
+ .clk = "l4_wkup_clk_mux_ck",
+ .addr = omap44xx_timer1_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer2_addrs[] = {
+ {
+ .pa_start = 0x48032000,
+ .pa_end = 0x4803207f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> timer2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__timer2 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_timer2_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_timer2_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer3_addrs[] = {
+ {
+ .pa_start = 0x48034000,
+ .pa_end = 0x4803407f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> timer3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__timer3 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_timer3_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_timer3_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer4_addrs[] = {
+ {
+ .pa_start = 0x48036000,
+ .pa_end = 0x4803607f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> timer4 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__timer4 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_timer4_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_timer4_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer5_addrs[] = {
+ {
+ .pa_start = 0x40138000,
+ .pa_end = 0x4013807f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> timer5 */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer5 = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_timer5_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_timer5_addrs,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer5_dma_addrs[] = {
+ {
+ .pa_start = 0x49038000,
+ .pa_end = 0x4903807f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> timer5 (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer5_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_timer5_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_timer5_dma_addrs,
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer6_addrs[] = {
+ {
+ .pa_start = 0x4013a000,
+ .pa_end = 0x4013a07f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> timer6 */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer6 = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_timer6_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_timer6_addrs,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer6_dma_addrs[] = {
+ {
+ .pa_start = 0x4903a000,
+ .pa_end = 0x4903a07f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> timer6 (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer6_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_timer6_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_timer6_dma_addrs,
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer7_addrs[] = {
+ {
+ .pa_start = 0x4013c000,
+ .pa_end = 0x4013c07f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> timer7 */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer7 = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_timer7_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_timer7_addrs,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer7_dma_addrs[] = {
+ {
+ .pa_start = 0x4903c000,
+ .pa_end = 0x4903c07f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> timer7 (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer7_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_timer7_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_timer7_dma_addrs,
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer8_addrs[] = {
+ {
+ .pa_start = 0x4013e000,
+ .pa_end = 0x4013e07f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> timer8 */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer8 = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_timer8_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_timer8_addrs,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer8_dma_addrs[] = {
+ {
+ .pa_start = 0x4903e000,
+ .pa_end = 0x4903e07f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> timer8 (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__timer8_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_timer8_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_timer8_dma_addrs,
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer9_addrs[] = {
+ {
+ .pa_start = 0x4803e000,
+ .pa_end = 0x4803e07f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> timer9 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__timer9 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_timer9_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_timer9_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer10_addrs[] = {
+ {
+ .pa_start = 0x48086000,
+ .pa_end = 0x4808607f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> timer10 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__timer10 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_timer10_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_timer10_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_timer11_addrs[] = {
+ {
+ .pa_start = 0x48088000,
+ .pa_end = 0x4808807f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> timer11 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__timer11 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_timer11_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_timer11_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_uart1_addrs[] = {
+ {
+ .pa_start = 0x4806a000,
+ .pa_end = 0x4806a0ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> uart1 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__uart1 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_uart1_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_uart1_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_uart2_addrs[] = {
+ {
+ .pa_start = 0x4806c000,
+ .pa_end = 0x4806c0ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> uart2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__uart2 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_uart2_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_uart2_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_uart3_addrs[] = {
+ {
+ .pa_start = 0x48020000,
+ .pa_end = 0x480200ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> uart3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__uart3 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_uart3_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_uart3_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_uart4_addrs[] = {
+ {
+ .pa_start = 0x4806e000,
+ .pa_end = 0x4806e0ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_per -> uart4 */
+static struct omap_hwmod_ocp_if omap44xx_l4_per__uart4 = {
+ .master = &omap44xx_l4_per_hwmod,
+ .slave = &omap44xx_uart4_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_uart4_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_usb_host_fs_addrs[] = {
+ {
+ .pa_start = 0x4a0a9000,
+ .pa_end = 0x4a0a93ff,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_cfg -> usb_host_fs */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usb_host_fs = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_usb_host_fs_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_usb_host_fs_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
};
static struct omap_hwmod_addr_space omap44xx_usb_host_hs_addrs[] = {
@@ -5382,12 +5881,7 @@ static struct omap_hwmod_addr_space omap44xx_usb_host_hs_addrs[] = {
{}
};
-static struct omap_hwmod_irq_info omap44xx_usb_host_hs_irqs[] = {
- { .name = "ohci-irq", .irq = 76 + OMAP44XX_IRQ_GIC_START },
- { .name = "ehci-irq", .irq = 77 + OMAP44XX_IRQ_GIC_START },
- { .irq = -1 }
-};
-
+/* l4_cfg -> usb_host_hs */
static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usb_host_hs = {
.master = &omap44xx_l4_cfg_hwmod,
.slave = &omap44xx_usb_host_hs_hwmod,
@@ -5396,100 +5890,22 @@ static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usb_host_hs = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-static struct omap_hwmod_ocp_if *omap44xx_usb_host_hs_slaves[] = {
- &omap44xx_l4_cfg__usb_host_hs,
-};
-
-static struct omap_hwmod omap44xx_usb_host_hs_hwmod = {
- .name = "usb_host_hs",
- .class = &omap44xx_usb_host_hs_hwmod_class,
- .clkdm_name = "l3_init_clkdm",
- .main_clk = "usb_host_hs_fck",
- .prcm = {
- .omap4 = {
- .clkctrl_offs = OMAP4_CM_L3INIT_USB_HOST_CLKCTRL_OFFSET,
- .context_offs = OMAP4_RM_L3INIT_USB_HOST_CONTEXT_OFFSET,
- .modulemode = MODULEMODE_SWCTRL,
- },
+static struct omap_hwmod_addr_space omap44xx_usb_otg_hs_addrs[] = {
+ {
+ .pa_start = 0x4a0ab000,
+ .pa_end = 0x4a0ab003,
+ .flags = ADDR_TYPE_RT
},
- .mpu_irqs = omap44xx_usb_host_hs_irqs,
- .slaves = omap44xx_usb_host_hs_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_usb_host_hs_slaves),
- .masters = omap44xx_usb_host_hs_masters,
- .masters_cnt = ARRAY_SIZE(omap44xx_usb_host_hs_masters),
-
- /*
- * Errata: USBHOST Configured In Smart-Idle Can Lead To a Deadlock
- * id: i660
- *
- * Description:
- * In the following configuration :
- * - USBHOST module is set to smart-idle mode
- * - PRCM asserts idle_req to the USBHOST module ( This typically
- * happens when the system is going to a low power mode : all ports
- * have been suspended, the master part of the USBHOST module has
- * entered the standby state, and SW has cut the functional clocks)
- * - an USBHOST interrupt occurs before the module is able to answer
- * idle_ack, typically a remote wakeup IRQ.
- * Then the USB HOST module will enter a deadlock situation where it
- * is no more accessible nor functional.
- *
- * Workaround:
- * Don't use smart idle; use only force idle, hence HWMOD_SWSUP_SIDLE
- */
-
- /*
- * Errata: USB host EHCI may stall when entering smart-standby mode
- * Id: i571
- *
- * Description:
- * When the USBHOST module is set to smart-standby mode, and when it is
- * ready to enter the standby state (i.e. all ports are suspended and
- * all attached devices are in suspend mode), then it can wrongly assert
- * the Mstandby signal too early while there are still some residual OCP
- * transactions ongoing. If this condition occurs, the internal state
- * machine may go to an undefined state and the USB link may be stuck
- * upon the next resume.
- *
- * Workaround:
- * Don't use smart standby; use only force standby,
- * hence HWMOD_SWSUP_MSTANDBY
- */
-
- /*
- * During system boot; If the hwmod framework resets the module
- * the module will have smart idle settings; which can lead to deadlock
- * (above Errata Id:i660); so, dont reset the module during boot;
- * Use HWMOD_INIT_NO_RESET.
- */
-
- .flags = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY |
- HWMOD_INIT_NO_RESET,
-};
-
-/*
- * 'usb_tll_hs' class
- * usb_tll_hs module is the adapter on the usb_host_hs ports
- */
-static struct omap_hwmod_class_sysconfig omap44xx_usb_tll_hs_sysc = {
- .rev_offs = 0x0000,
- .sysc_offs = 0x0010,
- .syss_offs = 0x0014,
- .sysc_flags = (SYSC_HAS_CLOCKACTIVITY | SYSC_HAS_SIDLEMODE |
- SYSC_HAS_ENAWAKEUP | SYSC_HAS_SOFTRESET |
- SYSC_HAS_AUTOIDLE),
- .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
- .sysc_fields = &omap_hwmod_sysc_type1,
-};
-
-static struct omap_hwmod_class omap44xx_usb_tll_hs_hwmod_class = {
- .name = "usb_tll_hs",
- .sysc = &omap44xx_usb_tll_hs_sysc,
+ { }
};
-static struct omap_hwmod_irq_info omap44xx_usb_tll_hs_irqs[] = {
- { .name = "tll-irq", .irq = 78 + OMAP44XX_IRQ_GIC_START },
- { .irq = -1 }
+/* l4_cfg -> usb_otg_hs */
+static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usb_otg_hs = {
+ .master = &omap44xx_l4_cfg_hwmod,
+ .slave = &omap44xx_usb_otg_hs_hwmod,
+ .clk = "l4_div_ck",
+ .addr = omap44xx_usb_otg_hs_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
};
static struct omap_hwmod_addr_space omap44xx_usb_tll_hs_addrs[] = {
@@ -5502,6 +5918,7 @@ static struct omap_hwmod_addr_space omap44xx_usb_tll_hs_addrs[] = {
{}
};
+/* l4_cfg -> usb_tll_hs */
static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usb_tll_hs = {
.master = &omap44xx_l4_cfg_hwmod,
.slave = &omap44xx_usb_tll_hs_hwmod,
@@ -5510,181 +5927,223 @@ static struct omap_hwmod_ocp_if omap44xx_l4_cfg__usb_tll_hs = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-static struct omap_hwmod_ocp_if *omap44xx_usb_tll_hs_slaves[] = {
- &omap44xx_l4_cfg__usb_tll_hs,
+static struct omap_hwmod_addr_space omap44xx_wd_timer2_addrs[] = {
+ {
+ .pa_start = 0x4a314000,
+ .pa_end = 0x4a31407f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
};
-static struct omap_hwmod omap44xx_usb_tll_hs_hwmod = {
- .name = "usb_tll_hs",
- .class = &omap44xx_usb_tll_hs_hwmod_class,
- .clkdm_name = "l3_init_clkdm",
- .main_clk = "usb_tll_hs_ick",
- .prcm = {
- .omap4 = {
- .clkctrl_offs = OMAP4_CM_L3INIT_USB_TLL_CLKCTRL_OFFSET,
- .context_offs = OMAP4_RM_L3INIT_USB_TLL_CONTEXT_OFFSET,
- .modulemode = MODULEMODE_HWCTRL,
- },
+/* l4_wkup -> wd_timer2 */
+static struct omap_hwmod_ocp_if omap44xx_l4_wkup__wd_timer2 = {
+ .master = &omap44xx_l4_wkup_hwmod,
+ .slave = &omap44xx_wd_timer2_hwmod,
+ .clk = "l4_wkup_clk_mux_ck",
+ .addr = omap44xx_wd_timer2_addrs,
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space omap44xx_wd_timer3_addrs[] = {
+ {
+ .pa_start = 0x40130000,
+ .pa_end = 0x4013007f,
+ .flags = ADDR_TYPE_RT
},
- .mpu_irqs = omap44xx_usb_tll_hs_irqs,
- .slaves = omap44xx_usb_tll_hs_slaves,
- .slaves_cnt = ARRAY_SIZE(omap44xx_usb_tll_hs_slaves),
+ { }
};
-static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
-
- /* dmm class */
- &omap44xx_dmm_hwmod,
-
- /* emif_fw class */
- &omap44xx_emif_fw_hwmod,
-
- /* l3 class */
- &omap44xx_l3_instr_hwmod,
- &omap44xx_l3_main_1_hwmod,
- &omap44xx_l3_main_2_hwmod,
- &omap44xx_l3_main_3_hwmod,
-
- /* l4 class */
- &omap44xx_l4_abe_hwmod,
- &omap44xx_l4_cfg_hwmod,
- &omap44xx_l4_per_hwmod,
- &omap44xx_l4_wkup_hwmod,
-
- /* mpu_bus class */
- &omap44xx_mpu_private_hwmod,
-
- /* aess class */
-/* &omap44xx_aess_hwmod, */
-
- /* bandgap class */
- &omap44xx_bandgap_hwmod,
-
- /* counter class */
-/* &omap44xx_counter_32k_hwmod, */
-
- /* dma class */
- &omap44xx_dma_system_hwmod,
-
- /* dmic class */
- &omap44xx_dmic_hwmod,
-
- /* dsp class */
- &omap44xx_dsp_hwmod,
- &omap44xx_dsp_c0_hwmod,
-
- /* dss class */
- &omap44xx_dss_hwmod,
- &omap44xx_dss_dispc_hwmod,
- &omap44xx_dss_dsi1_hwmod,
- &omap44xx_dss_dsi2_hwmod,
- &omap44xx_dss_hdmi_hwmod,
- &omap44xx_dss_rfbi_hwmod,
- &omap44xx_dss_venc_hwmod,
-
- /* gpio class */
- &omap44xx_gpio1_hwmod,
- &omap44xx_gpio2_hwmod,
- &omap44xx_gpio3_hwmod,
- &omap44xx_gpio4_hwmod,
- &omap44xx_gpio5_hwmod,
- &omap44xx_gpio6_hwmod,
-
- /* hsi class */
-/* &omap44xx_hsi_hwmod, */
-
- /* i2c class */
- &omap44xx_i2c1_hwmod,
- &omap44xx_i2c2_hwmod,
- &omap44xx_i2c3_hwmod,
- &omap44xx_i2c4_hwmod,
-
- /* ipu class */
- &omap44xx_ipu_hwmod,
- &omap44xx_ipu_c0_hwmod,
- &omap44xx_ipu_c1_hwmod,
-
- /* iss class */
-/* &omap44xx_iss_hwmod, */
-
- /* iva class */
- &omap44xx_iva_hwmod,
- &omap44xx_iva_seq0_hwmod,
- &omap44xx_iva_seq1_hwmod,
-
- /* kbd class */
- &omap44xx_kbd_hwmod,
-
- /* mailbox class */
- &omap44xx_mailbox_hwmod,
-
- /* mcbsp class */
- &omap44xx_mcbsp1_hwmod,
- &omap44xx_mcbsp2_hwmod,
- &omap44xx_mcbsp3_hwmod,
- &omap44xx_mcbsp4_hwmod,
-
- /* mcpdm class */
- &omap44xx_mcpdm_hwmod,
-
- /* mcspi class */
- &omap44xx_mcspi1_hwmod,
- &omap44xx_mcspi2_hwmod,
- &omap44xx_mcspi3_hwmod,
- &omap44xx_mcspi4_hwmod,
-
- /* mmc class */
- &omap44xx_mmc1_hwmod,
- &omap44xx_mmc2_hwmod,
- &omap44xx_mmc3_hwmod,
- &omap44xx_mmc4_hwmod,
- &omap44xx_mmc5_hwmod,
-
- /* mpu class */
- &omap44xx_mpu_hwmod,
-
- /* smartreflex class */
- &omap44xx_smartreflex_core_hwmod,
- &omap44xx_smartreflex_iva_hwmod,
- &omap44xx_smartreflex_mpu_hwmod,
-
- /* spinlock class */
- &omap44xx_spinlock_hwmod,
-
- /* timer class */
- &omap44xx_timer1_hwmod,
- &omap44xx_timer2_hwmod,
- &omap44xx_timer3_hwmod,
- &omap44xx_timer4_hwmod,
- &omap44xx_timer5_hwmod,
- &omap44xx_timer6_hwmod,
- &omap44xx_timer7_hwmod,
- &omap44xx_timer8_hwmod,
- &omap44xx_timer9_hwmod,
- &omap44xx_timer10_hwmod,
- &omap44xx_timer11_hwmod,
-
- /* uart class */
- &omap44xx_uart1_hwmod,
- &omap44xx_uart2_hwmod,
- &omap44xx_uart3_hwmod,
- &omap44xx_uart4_hwmod,
-
- /* usb host class */
- &omap44xx_usb_host_hs_hwmod,
- &omap44xx_usb_tll_hs_hwmod,
-
- /* usb_otg_hs class */
- &omap44xx_usb_otg_hs_hwmod,
-
- /* wd_timer class */
- &omap44xx_wd_timer2_hwmod,
- &omap44xx_wd_timer3_hwmod,
+/* l4_abe -> wd_timer3 */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__wd_timer3 = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_wd_timer3_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_wd_timer3_addrs,
+ .user = OCP_USER_MPU,
+};
+
+static struct omap_hwmod_addr_space omap44xx_wd_timer3_dma_addrs[] = {
+ {
+ .pa_start = 0x49030000,
+ .pa_end = 0x4903007f,
+ .flags = ADDR_TYPE_RT
+ },
+ { }
+};
+
+/* l4_abe -> wd_timer3 (dma) */
+static struct omap_hwmod_ocp_if omap44xx_l4_abe__wd_timer3_dma = {
+ .master = &omap44xx_l4_abe_hwmod,
+ .slave = &omap44xx_wd_timer3_hwmod,
+ .clk = "ocp_abe_iclk",
+ .addr = omap44xx_wd_timer3_dma_addrs,
+ .user = OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_ocp_if *omap44xx_hwmod_ocp_ifs[] __initdata = {
+ &omap44xx_c2c__c2c_target_fw,
+ &omap44xx_l4_cfg__c2c_target_fw,
+ &omap44xx_l3_main_1__dmm,
+ &omap44xx_mpu__dmm,
+ &omap44xx_c2c__emif_fw,
+ &omap44xx_dmm__emif_fw,
+ &omap44xx_l4_cfg__emif_fw,
+ &omap44xx_iva__l3_instr,
+ &omap44xx_l3_main_3__l3_instr,
+ &omap44xx_ocp_wp_noc__l3_instr,
+ &omap44xx_dsp__l3_main_1,
+ &omap44xx_dss__l3_main_1,
+ &omap44xx_l3_main_2__l3_main_1,
+ &omap44xx_l4_cfg__l3_main_1,
+ &omap44xx_mmc1__l3_main_1,
+ &omap44xx_mmc2__l3_main_1,
+ &omap44xx_mpu__l3_main_1,
+ &omap44xx_c2c_target_fw__l3_main_2,
+ &omap44xx_debugss__l3_main_2,
+ &omap44xx_dma_system__l3_main_2,
+ &omap44xx_fdif__l3_main_2,
+ &omap44xx_gpu__l3_main_2,
+ &omap44xx_hsi__l3_main_2,
+ &omap44xx_ipu__l3_main_2,
+ &omap44xx_iss__l3_main_2,
+ &omap44xx_iva__l3_main_2,
+ &omap44xx_l3_main_1__l3_main_2,
+ &omap44xx_l4_cfg__l3_main_2,
+ &omap44xx_usb_host_fs__l3_main_2,
+ &omap44xx_usb_host_hs__l3_main_2,
+ &omap44xx_usb_otg_hs__l3_main_2,
+ &omap44xx_l3_main_1__l3_main_3,
+ &omap44xx_l3_main_2__l3_main_3,
+ &omap44xx_l4_cfg__l3_main_3,
+ &omap44xx_aess__l4_abe,
+ &omap44xx_dsp__l4_abe,
+ &omap44xx_l3_main_1__l4_abe,
+ &omap44xx_mpu__l4_abe,
+ &omap44xx_l3_main_1__l4_cfg,
+ &omap44xx_l3_main_2__l4_per,
+ &omap44xx_l4_cfg__l4_wkup,
+ &omap44xx_mpu__mpu_private,
+ &omap44xx_l4_cfg__ocp_wp_noc,
+ &omap44xx_l4_abe__aess,
+ &omap44xx_l4_abe__aess_dma,
+ &omap44xx_l3_main_2__c2c,
+ &omap44xx_l4_wkup__counter_32k,
+ &omap44xx_l4_cfg__ctrl_module_core,
+ &omap44xx_l4_cfg__ctrl_module_pad_core,
+ &omap44xx_l4_wkup__ctrl_module_wkup,
+ &omap44xx_l4_wkup__ctrl_module_pad_wkup,
+ &omap44xx_l3_instr__debugss,
+ &omap44xx_l4_cfg__dma_system,
+ &omap44xx_l4_abe__dmic,
+ &omap44xx_l4_abe__dmic_dma,
+ &omap44xx_dsp__iva,
+ &omap44xx_dsp__sl2if,
+ &omap44xx_l4_cfg__dsp,
+ &omap44xx_l3_main_2__dss,
+ &omap44xx_l4_per__dss,
+ &omap44xx_l3_main_2__dss_dispc,
+ &omap44xx_l4_per__dss_dispc,
+ &omap44xx_l3_main_2__dss_dsi1,
+ &omap44xx_l4_per__dss_dsi1,
+ &omap44xx_l3_main_2__dss_dsi2,
+ &omap44xx_l4_per__dss_dsi2,
+ &omap44xx_l3_main_2__dss_hdmi,
+ &omap44xx_l4_per__dss_hdmi,
+ &omap44xx_l3_main_2__dss_rfbi,
+ &omap44xx_l4_per__dss_rfbi,
+ &omap44xx_l3_main_2__dss_venc,
+ &omap44xx_l4_per__dss_venc,
+ &omap44xx_l4_per__elm,
+ &omap44xx_emif_fw__emif1,
+ &omap44xx_emif_fw__emif2,
+ &omap44xx_l4_cfg__fdif,
+ &omap44xx_l4_wkup__gpio1,
+ &omap44xx_l4_per__gpio2,
+ &omap44xx_l4_per__gpio3,
+ &omap44xx_l4_per__gpio4,
+ &omap44xx_l4_per__gpio5,
+ &omap44xx_l4_per__gpio6,
+ &omap44xx_l3_main_2__gpmc,
+ &omap44xx_l3_main_2__gpu,
+ &omap44xx_l4_per__hdq1w,
+ &omap44xx_l4_cfg__hsi,
+ &omap44xx_l4_per__i2c1,
+ &omap44xx_l4_per__i2c2,
+ &omap44xx_l4_per__i2c3,
+ &omap44xx_l4_per__i2c4,
+ &omap44xx_l3_main_2__ipu,
+ &omap44xx_l3_main_2__iss,
+ &omap44xx_iva__sl2if,
+ &omap44xx_l3_main_2__iva,
+ &omap44xx_l4_wkup__kbd,
+ &omap44xx_l4_cfg__mailbox,
+ &omap44xx_l4_abe__mcasp,
+ &omap44xx_l4_abe__mcasp_dma,
+ &omap44xx_l4_abe__mcbsp1,
+ &omap44xx_l4_abe__mcbsp1_dma,
+ &omap44xx_l4_abe__mcbsp2,
+ &omap44xx_l4_abe__mcbsp2_dma,
+ &omap44xx_l4_abe__mcbsp3,
+ &omap44xx_l4_abe__mcbsp3_dma,
+ &omap44xx_l4_per__mcbsp4,
+ &omap44xx_l4_abe__mcpdm,
+ &omap44xx_l4_abe__mcpdm_dma,
+ &omap44xx_l4_per__mcspi1,
+ &omap44xx_l4_per__mcspi2,
+ &omap44xx_l4_per__mcspi3,
+ &omap44xx_l4_per__mcspi4,
+ &omap44xx_l4_per__mmc1,
+ &omap44xx_l4_per__mmc2,
+ &omap44xx_l4_per__mmc3,
+ &omap44xx_l4_per__mmc4,
+ &omap44xx_l4_per__mmc5,
+ &omap44xx_l3_main_2__ocmc_ram,
+ &omap44xx_l4_cfg__ocp2scp_usb_phy,
+ &omap44xx_mpu_private__prcm_mpu,
+ &omap44xx_l4_wkup__cm_core_aon,
+ &omap44xx_l4_cfg__cm_core,
+ &omap44xx_l4_wkup__prm,
+ &omap44xx_l4_wkup__scrm,
+ &omap44xx_l3_main_2__sl2if,
+ &omap44xx_l4_abe__slimbus1,
+ &omap44xx_l4_abe__slimbus1_dma,
+ &omap44xx_l4_per__slimbus2,
+ &omap44xx_l4_cfg__smartreflex_core,
+ &omap44xx_l4_cfg__smartreflex_iva,
+ &omap44xx_l4_cfg__smartreflex_mpu,
+ &omap44xx_l4_cfg__spinlock,
+ &omap44xx_l4_wkup__timer1,
+ &omap44xx_l4_per__timer2,
+ &omap44xx_l4_per__timer3,
+ &omap44xx_l4_per__timer4,
+ &omap44xx_l4_abe__timer5,
+ &omap44xx_l4_abe__timer5_dma,
+ &omap44xx_l4_abe__timer6,
+ &omap44xx_l4_abe__timer6_dma,
+ &omap44xx_l4_abe__timer7,
+ &omap44xx_l4_abe__timer7_dma,
+ &omap44xx_l4_abe__timer8,
+ &omap44xx_l4_abe__timer8_dma,
+ &omap44xx_l4_per__timer9,
+ &omap44xx_l4_per__timer10,
+ &omap44xx_l4_per__timer11,
+ &omap44xx_l4_per__uart1,
+ &omap44xx_l4_per__uart2,
+ &omap44xx_l4_per__uart3,
+ &omap44xx_l4_per__uart4,
+ &omap44xx_l4_cfg__usb_host_fs,
+ &omap44xx_l4_cfg__usb_host_hs,
+ &omap44xx_l4_cfg__usb_otg_hs,
+ &omap44xx_l4_cfg__usb_tll_hs,
+ &omap44xx_l4_wkup__wd_timer2,
+ &omap44xx_l4_abe__wd_timer3,
+ &omap44xx_l4_abe__wd_timer3_dma,
NULL,
};
int __init omap44xx_hwmod_init(void)
{
- return omap_hwmod_register(omap44xx_hwmods);
+ return omap_hwmod_register_links(omap44xx_hwmod_ocp_ifs);
}
diff --git a/arch/arm/mach-omap2/omap_hwmod_common_data.h b/arch/arm/mach-omap2/omap_hwmod_common_data.h
index ad5d8f04c0b8..e7e8eeae95e5 100644
--- a/arch/arm/mach-omap2/omap_hwmod_common_data.h
+++ b/arch/arm/mach-omap2/omap_hwmod_common_data.h
@@ -19,18 +19,6 @@
#include "display.h"
/* Common address space across OMAP2xxx */
-extern struct omap_hwmod_addr_space omap2xxx_uart1_addr_space[];
-extern struct omap_hwmod_addr_space omap2xxx_uart2_addr_space[];
-extern struct omap_hwmod_addr_space omap2xxx_uart3_addr_space[];
-extern struct omap_hwmod_addr_space omap2xxx_timer2_addrs[];
-extern struct omap_hwmod_addr_space omap2xxx_timer3_addrs[];
-extern struct omap_hwmod_addr_space omap2xxx_timer4_addrs[];
-extern struct omap_hwmod_addr_space omap2xxx_timer5_addrs[];
-extern struct omap_hwmod_addr_space omap2xxx_timer6_addrs[];
-extern struct omap_hwmod_addr_space omap2xxx_timer7_addrs[];
-extern struct omap_hwmod_addr_space omap2xxx_timer8_addrs[];
-extern struct omap_hwmod_addr_space omap2xxx_timer9_addrs[];
-extern struct omap_hwmod_addr_space omap2xxx_timer12_addrs[];
extern struct omap_hwmod_addr_space omap2xxx_mcbsp2_addrs[];
/* Common address space across OMAP2xxx/3xxx */
@@ -50,10 +38,70 @@ extern struct omap_hwmod_addr_space omap2430_mcspi3_addr_space[];
extern struct omap_hwmod_addr_space omap2_dma_system_addrs[];
extern struct omap_hwmod_addr_space omap2_mailbox_addrs[];
extern struct omap_hwmod_addr_space omap2_mcbsp1_addrs[];
+extern struct omap_hwmod_addr_space omap2_hdq1w_addr_space[];
/* Common IP block data across OMAP2xxx */
extern struct omap_hwmod_irq_info omap2xxx_timer12_mpu_irqs[];
extern struct omap_hwmod_dma_info omap2xxx_dss_sdma_chs[];
+extern struct omap_gpio_dev_attr omap2xxx_gpio_dev_attr;
+extern struct omap_hwmod omap2xxx_l3_main_hwmod;
+extern struct omap_hwmod omap2xxx_l4_core_hwmod;
+extern struct omap_hwmod omap2xxx_l4_wkup_hwmod;
+extern struct omap_hwmod omap2xxx_mpu_hwmod;
+extern struct omap_hwmod omap2xxx_iva_hwmod;
+extern struct omap_hwmod omap2xxx_timer1_hwmod;
+extern struct omap_hwmod omap2xxx_timer2_hwmod;
+extern struct omap_hwmod omap2xxx_timer3_hwmod;
+extern struct omap_hwmod omap2xxx_timer4_hwmod;
+extern struct omap_hwmod omap2xxx_timer5_hwmod;
+extern struct omap_hwmod omap2xxx_timer6_hwmod;
+extern struct omap_hwmod omap2xxx_timer7_hwmod;
+extern struct omap_hwmod omap2xxx_timer8_hwmod;
+extern struct omap_hwmod omap2xxx_timer9_hwmod;
+extern struct omap_hwmod omap2xxx_timer10_hwmod;
+extern struct omap_hwmod omap2xxx_timer11_hwmod;
+extern struct omap_hwmod omap2xxx_timer12_hwmod;
+extern struct omap_hwmod omap2xxx_wd_timer2_hwmod;
+extern struct omap_hwmod omap2xxx_uart1_hwmod;
+extern struct omap_hwmod omap2xxx_uart2_hwmod;
+extern struct omap_hwmod omap2xxx_uart3_hwmod;
+extern struct omap_hwmod omap2xxx_dss_core_hwmod;
+extern struct omap_hwmod omap2xxx_dss_dispc_hwmod;
+extern struct omap_hwmod omap2xxx_dss_rfbi_hwmod;
+extern struct omap_hwmod omap2xxx_dss_venc_hwmod;
+extern struct omap_hwmod omap2xxx_gpio1_hwmod;
+extern struct omap_hwmod omap2xxx_gpio2_hwmod;
+extern struct omap_hwmod omap2xxx_gpio3_hwmod;
+extern struct omap_hwmod omap2xxx_gpio4_hwmod;
+extern struct omap_hwmod omap2xxx_mcspi1_hwmod;
+extern struct omap_hwmod omap2xxx_mcspi2_hwmod;
+extern struct omap_hwmod omap2xxx_counter_32k_hwmod;
+
+/* Common interface data across OMAP2xxx */
+extern struct omap_hwmod_ocp_if omap2xxx_l3_main__l4_core;
+extern struct omap_hwmod_ocp_if omap2xxx_mpu__l3_main;
+extern struct omap_hwmod_ocp_if omap2xxx_dss__l3;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__l4_wkup;
+extern struct omap_hwmod_ocp_if omap2_l4_core__uart1;
+extern struct omap_hwmod_ocp_if omap2_l4_core__uart2;
+extern struct omap_hwmod_ocp_if omap2_l4_core__uart3;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__mcspi1;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__mcspi2;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__timer2;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__timer3;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__timer4;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__timer5;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__timer6;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__timer7;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__timer8;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__timer9;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__timer10;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__timer11;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__timer12;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__dss;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__dss_dispc;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__dss_rfbi;
+extern struct omap_hwmod_ocp_if omap2xxx_l4_core__dss_venc;
/* Common IP block data */
extern struct omap_hwmod_dma_info omap2_uart1_sdma_reqs[];
@@ -94,6 +142,8 @@ extern struct omap_hwmod_irq_info omap2_gpio4_irqs[];
extern struct omap_hwmod_irq_info omap2_dma_system_irqs[];
extern struct omap_hwmod_irq_info omap2_mcspi1_mpu_irqs[];
extern struct omap_hwmod_irq_info omap2_mcspi2_mpu_irqs[];
+extern struct omap_hwmod_addr_space omap2xxx_timer12_addrs[];
+extern struct omap_hwmod_irq_info omap2_hdq1w_mpu_irqs[];
/* OMAP hwmod classes - forward declarations */
extern struct omap_hwmod_class l3_hwmod_class;
@@ -105,6 +155,8 @@ extern struct omap_hwmod_class omap2_dss_hwmod_class;
extern struct omap_hwmod_class omap2_dispc_hwmod_class;
extern struct omap_hwmod_class omap2_rfbi_hwmod_class;
extern struct omap_hwmod_class omap2_venc_hwmod_class;
+extern struct omap_hwmod_class_sysconfig omap2_hdq1w_sysc;
+extern struct omap_hwmod_class omap2_hdq1w_class;
extern struct omap_hwmod_class omap2xxx_timer_hwmod_class;
extern struct omap_hwmod_class omap2xxx_wd_timer_hwmod_class;
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 36fa90b6ece8..78564895e914 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -38,27 +38,6 @@ static inline int omap4_opp_init(void)
}
#endif
-/*
- * cpuidle mach specific parameters
- *
- * The board code can override the default C-states definition using
- * omap3_pm_init_cpuidle
- */
-struct cpuidle_params {
- u32 exit_latency; /* exit_latency = sleep + wake-up latencies */
- u32 target_residency;
- u8 valid; /* validates the C-state */
-};
-
-#if defined(CONFIG_PM) && defined(CONFIG_CPU_IDLE)
-extern void omap3_pm_init_cpuidle(struct cpuidle_params *cpuidle_board_params);
-#else
-static
-inline void omap3_pm_init_cpuidle(struct cpuidle_params *cpuidle_board_params)
-{
-}
-#endif
-
extern int omap3_pm_get_suspend_state(struct powerdomain *pwrdm);
extern int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state);
diff --git a/arch/arm/mach-omap2/pm24xx.c b/arch/arm/mach-omap2/pm24xx.c
index 95442b69ae27..facfffca9eac 100644
--- a/arch/arm/mach-omap2/pm24xx.c
+++ b/arch/arm/mach-omap2/pm24xx.c
@@ -171,8 +171,6 @@ static int omap2_allow_mpu_retention(void)
static void omap2_enter_mpu_retention(void)
{
- int only_idle = 0;
-
/* Putting MPU into the WFI state while a transfer is active
* seems to cause the I2C block to timeout. Why? Good question. */
if (omap2_i2c_active())
@@ -195,7 +193,6 @@ static void omap2_enter_mpu_retention(void)
omap2_prm_write_mod_reg(OMAP_LOGICRETSTATE_MASK, MPU_MOD,
OMAP2_PM_PWSTCTRL);
- only_idle = 1;
}
omap2_sram_idle();
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 703bd1099259..8b43aefba0ea 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -273,7 +273,7 @@ void omap_sram_idle(void)
int per_next_state = PWRDM_POWER_ON;
int core_next_state = PWRDM_POWER_ON;
int per_going_off;
- int core_prev_state, per_prev_state;
+ int core_prev_state;
u32 sdrc_pwr = 0;
mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
@@ -375,10 +375,8 @@ void omap_sram_idle(void)
pwrdm_post_transition();
/* PER */
- if (per_next_state < PWRDM_POWER_ON) {
- per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm);
+ if (per_next_state < PWRDM_POWER_ON)
omap2_gpio_resume_after_idle();
- }
/* Disable IO-PAD and IO-CHAIN wakeup */
if (omap3_has_io_wakeup() &&
@@ -702,7 +700,7 @@ static void __init pm_errata_configure(void)
static int __init omap3_pm_init(void)
{
struct power_state *pwrst, *tmp;
- struct clockdomain *neon_clkdm, *per_clkdm, *mpu_clkdm, *core_clkdm;
+ struct clockdomain *neon_clkdm, *mpu_clkdm;
int ret;
if (!cpu_is_omap34xx())
@@ -757,8 +755,6 @@ static int __init omap3_pm_init(void)
neon_clkdm = clkdm_lookup("neon_clkdm");
mpu_clkdm = clkdm_lookup("mpu_clkdm");
- per_clkdm = clkdm_lookup("per_clkdm");
- core_clkdm = clkdm_lookup("core_clkdm");
#ifdef CONFIG_SUSPEND
omap_pm_suspend = omap3_pm_suspend;
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 96ad3dbeac34..96114901b932 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -981,16 +981,6 @@ int pwrdm_state_switch(struct powerdomain *pwrdm)
return ret;
}
-int pwrdm_clkdm_state_switch(struct clockdomain *clkdm)
-{
- if (clkdm != NULL && clkdm->pwrdm.ptr != NULL) {
- pwrdm_wait_transition(clkdm->pwrdm.ptr);
- return pwrdm_state_switch(clkdm->pwrdm.ptr);
- }
-
- return -EINVAL;
-}
-
int pwrdm_pre_transition(void)
{
pwrdm_for_each(_pwrdm_pre_transition_cb, NULL);
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
index 0d72a8a8ce4d..8f88d65c46ea 100644
--- a/arch/arm/mach-omap2/powerdomain.h
+++ b/arch/arm/mach-omap2/powerdomain.h
@@ -213,7 +213,6 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm);
int pwrdm_wait_transition(struct powerdomain *pwrdm);
int pwrdm_state_switch(struct powerdomain *pwrdm);
-int pwrdm_clkdm_state_switch(struct clockdomain *clkdm);
int pwrdm_pre_transition(void);
int pwrdm_post_transition(void);
int pwrdm_set_lowpwrstchange(struct powerdomain *pwrdm);
diff --git a/arch/arm/mach-omap2/prcm-common.h b/arch/arm/mach-omap2/prcm-common.h
index 5aa5435e3ff1..6da3ba483ad1 100644
--- a/arch/arm/mach-omap2/prcm-common.h
+++ b/arch/arm/mach-omap2/prcm-common.h
@@ -177,6 +177,8 @@
/* PM_WKST_WKUP, CM_IDLEST_WKUP shared bits */
#define OMAP24XX_ST_GPIOS_SHIFT 2
#define OMAP24XX_ST_GPIOS_MASK (1 << 2)
+#define OMAP24XX_ST_32KSYNC_SHIFT 1
+#define OMAP24XX_ST_32KSYNC_MASK (1 << 1)
#define OMAP24XX_ST_GPT1_SHIFT 0
#define OMAP24XX_ST_GPT1_MASK (1 << 0)
@@ -307,6 +309,8 @@
#define OMAP3430_ST_SR1_MASK (1 << 6)
#define OMAP3430_ST_GPIO1_SHIFT 3
#define OMAP3430_ST_GPIO1_MASK (1 << 3)
+#define OMAP3430_ST_32KSYNC_SHIFT 2
+#define OMAP3430_ST_32KSYNC_MASK (1 << 2)
#define OMAP3430_ST_GPT12_SHIFT 1
#define OMAP3430_ST_GPT12_MASK (1 << 1)
#define OMAP3430_ST_GPT1_SHIFT 0
@@ -410,6 +414,19 @@
extern void __iomem *prm_base;
extern void __iomem *cm_base;
extern void __iomem *cm2_base;
+extern void __iomem *prcm_mpu_base;
+
+#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_OMAP5)
+extern void omap_prm_base_init(void);
+extern void omap_cm_base_init(void);
+#else
+static inline void omap_prm_base_init(void)
+{
+}
+static inline void omap_cm_base_init(void)
+{
+}
+#endif
/**
* struct omap_prcm_irq - describes a PRCM interrupt bit
diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c
index 626acfad7190..480f40a5ee42 100644
--- a/arch/arm/mach-omap2/prcm.c
+++ b/arch/arm/mach-omap2/prcm.c
@@ -42,6 +42,7 @@
void __iomem *prm_base;
void __iomem *cm_base;
void __iomem *cm2_base;
+void __iomem *prcm_mpu_base;
#define MAX_MODULE_ENABLE_WAIT 100000
@@ -155,4 +156,11 @@ void __init omap2_set_globals_prcm(struct omap_globals *omap2_globals)
cm_base = omap2_globals->cm;
if (omap2_globals->cm2)
cm2_base = omap2_globals->cm2;
+ if (omap2_globals->prcm_mpu)
+ prcm_mpu_base = omap2_globals->prcm_mpu;
+
+ if (cpu_is_omap44xx()) {
+ omap_prm_base_init();
+ omap_cm_base_init();
+ }
}
diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c
index d28f848897d6..dfe00ddb5c60 100644
--- a/arch/arm/mach-omap2/prm_common.c
+++ b/arch/arm/mach-omap2/prm_common.c
@@ -237,7 +237,7 @@ void omap_prcm_irq_complete(void)
*/
int omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup)
{
- int nr_regs = irq_setup->nr_regs;
+ int nr_regs;
u32 mask[OMAP_PRCM_MAX_NR_PENDING_REG];
int offset, i;
struct irq_chip_generic *gc;
@@ -246,6 +246,8 @@ int omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup)
if (!irq_setup)
return -EINVAL;
+ nr_regs = irq_setup->nr_regs;
+
if (prcm_irq_setup) {
pr_err("PRCM: already initialized; won't reinitialize\n");
return -EINVAL;
diff --git a/arch/arm/mach-omap2/prminst44xx.c b/arch/arm/mach-omap2/prminst44xx.c
index 9b3898a3ac9b..c12320c0ae95 100644
--- a/arch/arm/mach-omap2/prminst44xx.c
+++ b/arch/arm/mach-omap2/prminst44xx.c
@@ -18,20 +18,26 @@
#include "iomap.h"
#include "common.h"
+#include "prcm-common.h"
#include "prm44xx.h"
#include "prminst44xx.h"
#include "prm-regbits-44xx.h"
#include "prcm44xx.h"
#include "prcm_mpu44xx.h"
-static u32 _prm_bases[OMAP4_MAX_PRCM_PARTITIONS] = {
- [OMAP4430_INVALID_PRCM_PARTITION] = 0,
- [OMAP4430_PRM_PARTITION] = OMAP4430_PRM_BASE,
- [OMAP4430_CM1_PARTITION] = 0,
- [OMAP4430_CM2_PARTITION] = 0,
- [OMAP4430_SCRM_PARTITION] = 0,
- [OMAP4430_PRCM_MPU_PARTITION] = OMAP4430_PRCM_MPU_BASE,
-};
+static void __iomem *_prm_bases[OMAP4_MAX_PRCM_PARTITIONS];
+
+/**
+ * omap_prm_base_init - Populates the prm partitions
+ *
+ * Populates the base addresses of the _prm_bases
+ * array used for read/write of prm module registers.
+ */
+void omap_prm_base_init(void)
+{
+ _prm_bases[OMAP4430_PRM_PARTITION] = prm_base;
+ _prm_bases[OMAP4430_PRCM_MPU_PARTITION] = prcm_mpu_base;
+}
/* Read a register in a PRM instance */
u32 omap4_prminst_read_inst_reg(u8 part, s16 inst, u16 idx)
@@ -39,8 +45,7 @@ u32 omap4_prminst_read_inst_reg(u8 part, s16 inst, u16 idx)
BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS ||
part == OMAP4430_INVALID_PRCM_PARTITION ||
!_prm_bases[part]);
- return __raw_readl(OMAP2_L4_IO_ADDRESS(_prm_bases[part] + inst +
- idx));
+ return __raw_readl(_prm_bases[part] + inst + idx);
}
/* Write into a register in a PRM instance */
@@ -49,7 +54,7 @@ void omap4_prminst_write_inst_reg(u32 val, u8 part, s16 inst, u16 idx)
BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS ||
part == OMAP4430_INVALID_PRCM_PARTITION ||
!_prm_bases[part]);
- __raw_writel(val, OMAP2_L4_IO_ADDRESS(_prm_bases[part] + inst + idx));
+ __raw_writel(val, _prm_bases[part] + inst + idx);
}
/* Read-modify-write a register in PRM. Caller must lock */
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 9fc2f44188cb..292d4aaca068 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -133,7 +133,7 @@ static void omap_serial_fill_default_pads(struct omap_board_data *bdata)
static void omap_serial_fill_default_pads(struct omap_board_data *bdata) {}
#endif
-char *cmdline_find_option(char *str)
+static char *cmdline_find_option(char *str)
{
extern char *saved_command_line;
@@ -245,14 +245,6 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,
omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate;
omap_up.autosuspend_timeout = info->autosuspend_timeout;
- /* Enable the MDR1 Errata i202 for OMAP2430/3xxx/44xx */
- if (!cpu_is_omap2420() && !cpu_is_ti816x())
- omap_up.errata |= UART_ERRATA_i202_MDR1_ACCESS;
-
- /* Enable DMA Mode Force Idle Errata i291 for omap34xx/3630 */
- if (cpu_is_omap34xx() || cpu_is_omap3630())
- omap_up.errata |= UART_ERRATA_i291_DMA_FORCEIDLE;
-
pdata = &omap_up;
pdata_size = sizeof(struct omap_uart_port_info);
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index c512bac69ec5..1b7835865c83 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -145,8 +145,10 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
{
char name[10]; /* 10 = sizeof("gptXX_Xck0") */
struct omap_hwmod *oh;
+ struct resource irq_rsrc, mem_rsrc;
size_t size;
int res = 0;
+ int r;
sprintf(name, "timer%d", gptimer_id);
omap_hwmod_setup_one(name);
@@ -154,9 +156,16 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
if (!oh)
return -ENODEV;
- timer->irq = oh->mpu_irqs[0].irq;
- timer->phys_base = oh->slaves[0]->addr->pa_start;
- size = oh->slaves[0]->addr->pa_end - timer->phys_base;
+ r = omap_hwmod_get_resource_byname(oh, IORESOURCE_IRQ, NULL, &irq_rsrc);
+ if (r)
+ return -ENXIO;
+ timer->irq = irq_rsrc.start;
+
+ r = omap_hwmod_get_resource_byname(oh, IORESOURCE_MEM, NULL, &mem_rsrc);
+ if (r)
+ return -ENXIO;
+ timer->phys_base = mem_rsrc.start;
+ size = mem_rsrc.end - mem_rsrc.start;
/* Static mapping, never released */
timer->io_base = ioremap(timer->phys_base, size);
@@ -169,13 +178,6 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
if (IS_ERR(timer->fclk))
return -ENODEV;
- sprintf(name, "gpt%d_ick", gptimer_id);
- timer->iclk = clk_get(NULL, name);
- if (IS_ERR(timer->iclk)) {
- clk_put(timer->fclk);
- return -ENODEV;
- }
-
omap_hwmod_enable(oh);
sys_timer_reserved |= (1 << (gptimer_id - 1));
diff --git a/arch/arm/mach-omap2/twl-common.c b/arch/arm/mach-omap2/twl-common.c
index 7a7b89304c48..119d5a910f3a 100644
--- a/arch/arm/mach-omap2/twl-common.c
+++ b/arch/arm/mach-omap2/twl-common.c
@@ -31,6 +31,7 @@
#include "twl-common.h"
#include "pm.h"
+#include "voltage.h"
static struct i2c_board_info __initdata pmic_i2c_board_info = {
.addr = 0x48,
@@ -47,6 +48,18 @@ static struct i2c_board_info __initdata omap4_i2c1_board_info[] = {
},
};
+static int twl_set_voltage(void *data, int target_uV)
+{
+ struct voltagedomain *voltdm = (struct voltagedomain *)data;
+ return voltdm_scale(voltdm, target_uV);
+}
+
+static int twl_get_voltage(void *data)
+{
+ struct voltagedomain *voltdm = (struct voltagedomain *)data;
+ return voltdm_get_voltage(voltdm);
+}
+
void __init omap_pmic_init(int bus, u32 clkrate,
const char *pmic_type, int pmic_irq,
struct twl4030_platform_data *pmic_data)
@@ -153,6 +166,48 @@ static struct regulator_init_data omap3_vpll2_idata = {
.consumer_supplies = omap3_vpll2_supplies,
};
+static struct regulator_consumer_supply omap3_vdd1_supply[] = {
+ REGULATOR_SUPPLY("vcc", "mpu.0"),
+};
+
+static struct regulator_consumer_supply omap3_vdd2_supply[] = {
+ REGULATOR_SUPPLY("vcc", "l3_main.0"),
+};
+
+static struct regulator_init_data omap3_vdd1 = {
+ .constraints = {
+ .name = "vdd_mpu_iva",
+ .min_uV = 600000,
+ .max_uV = 1450000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(omap3_vdd1_supply),
+ .consumer_supplies = omap3_vdd1_supply,
+};
+
+static struct regulator_init_data omap3_vdd2 = {
+ .constraints = {
+ .name = "vdd_core",
+ .min_uV = 600000,
+ .max_uV = 1450000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(omap3_vdd2_supply),
+ .consumer_supplies = omap3_vdd2_supply,
+};
+
+static struct twl_regulator_driver_data omap3_vdd1_drvdata = {
+ .get_voltage = twl_get_voltage,
+ .set_voltage = twl_set_voltage,
+};
+
+static struct twl_regulator_driver_data omap3_vdd2_drvdata = {
+ .get_voltage = twl_get_voltage,
+ .set_voltage = twl_set_voltage,
+};
+
void __init omap3_pmic_get_config(struct twl4030_platform_data *pmic_data,
u32 pdata_flags, u32 regulators_flags)
{
@@ -160,6 +215,16 @@ void __init omap3_pmic_get_config(struct twl4030_platform_data *pmic_data,
pmic_data->irq_base = TWL4030_IRQ_BASE;
if (!pmic_data->irq_end)
pmic_data->irq_end = TWL4030_IRQ_END;
+ if (!pmic_data->vdd1) {
+ omap3_vdd1.driver_data = &omap3_vdd1_drvdata;
+ omap3_vdd1_drvdata.data = voltdm_lookup("mpu_iva");
+ pmic_data->vdd1 = &omap3_vdd1;
+ }
+ if (!pmic_data->vdd2) {
+ omap3_vdd2.driver_data = &omap3_vdd2_drvdata;
+ omap3_vdd2_drvdata.data = voltdm_lookup("core");
+ pmic_data->vdd2 = &omap3_vdd2;
+ }
/* Common platform data configurations */
if (pdata_flags & TWL_COMMON_PDATA_USB && !pmic_data->usb)
@@ -201,6 +266,7 @@ static struct regulator_init_data omap4_vdac_idata = {
.valid_ops_mask = REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
+ .supply_regulator = "V2V1",
};
static struct regulator_init_data omap4_vaux2_idata = {
@@ -291,6 +357,7 @@ static struct regulator_init_data omap4_vcxio_idata = {
},
.num_consumer_supplies = ARRAY_SIZE(omap4_vcxio_supply),
.consumer_supplies = omap4_vcxio_supply,
+ .supply_regulator = "V2V1",
};
static struct regulator_init_data omap4_vusb_idata = {
@@ -310,6 +377,105 @@ static struct regulator_init_data omap4_clk32kg_idata = {
},
};
+static struct regulator_consumer_supply omap4_vdd1_supply[] = {
+ REGULATOR_SUPPLY("vcc", "mpu.0"),
+};
+
+static struct regulator_consumer_supply omap4_vdd2_supply[] = {
+ REGULATOR_SUPPLY("vcc", "iva.0"),
+};
+
+static struct regulator_consumer_supply omap4_vdd3_supply[] = {
+ REGULATOR_SUPPLY("vcc", "l3_main.0"),
+};
+
+static struct regulator_init_data omap4_vdd1 = {
+ .constraints = {
+ .name = "vdd_mpu",
+ .min_uV = 500000,
+ .max_uV = 1500000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(omap4_vdd1_supply),
+ .consumer_supplies = omap4_vdd1_supply,
+};
+
+static struct regulator_init_data omap4_vdd2 = {
+ .constraints = {
+ .name = "vdd_iva",
+ .min_uV = 500000,
+ .max_uV = 1500000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(omap4_vdd2_supply),
+ .consumer_supplies = omap4_vdd2_supply,
+};
+
+static struct regulator_init_data omap4_vdd3 = {
+ .constraints = {
+ .name = "vdd_core",
+ .min_uV = 500000,
+ .max_uV = 1500000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(omap4_vdd3_supply),
+ .consumer_supplies = omap4_vdd3_supply,
+};
+
+
+static struct twl_regulator_driver_data omap4_vdd1_drvdata = {
+ .get_voltage = twl_get_voltage,
+ .set_voltage = twl_set_voltage,
+};
+
+static struct twl_regulator_driver_data omap4_vdd2_drvdata = {
+ .get_voltage = twl_get_voltage,
+ .set_voltage = twl_set_voltage,
+};
+
+static struct twl_regulator_driver_data omap4_vdd3_drvdata = {
+ .get_voltage = twl_get_voltage,
+ .set_voltage = twl_set_voltage,
+};
+
+static struct regulator_consumer_supply omap4_v1v8_supply[] = {
+ REGULATOR_SUPPLY("vio", "1-004b"),
+};
+
+static struct regulator_init_data omap4_v1v8_idata = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ .always_on = true,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(omap4_v1v8_supply),
+ .consumer_supplies = omap4_v1v8_supply,
+};
+
+static struct regulator_consumer_supply omap4_v2v1_supply[] = {
+ REGULATOR_SUPPLY("v2v1", "1-004b"),
+};
+
+static struct regulator_init_data omap4_v2v1_idata = {
+ .constraints = {
+ .min_uV = 2100000,
+ .max_uV = 2100000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(omap4_v2v1_supply),
+ .consumer_supplies = omap4_v2v1_supply,
+};
+
void __init omap4_pmic_get_config(struct twl4030_platform_data *pmic_data,
u32 pdata_flags, u32 regulators_flags)
{
@@ -318,6 +484,24 @@ void __init omap4_pmic_get_config(struct twl4030_platform_data *pmic_data,
if (!pmic_data->irq_end)
pmic_data->irq_end = TWL6030_IRQ_END;
+ if (!pmic_data->vdd1) {
+ omap4_vdd1.driver_data = &omap4_vdd1_drvdata;
+ omap4_vdd1_drvdata.data = voltdm_lookup("mpu");
+ pmic_data->vdd1 = &omap4_vdd1;
+ }
+
+ if (!pmic_data->vdd2) {
+ omap4_vdd2.driver_data = &omap4_vdd2_drvdata;
+ omap4_vdd2_drvdata.data = voltdm_lookup("iva");
+ pmic_data->vdd2 = &omap4_vdd2;
+ }
+
+ if (!pmic_data->vdd3) {
+ omap4_vdd3.driver_data = &omap4_vdd3_drvdata;
+ omap4_vdd3_drvdata.data = voltdm_lookup("core");
+ pmic_data->vdd3 = &omap4_vdd3;
+ }
+
/* Common platform data configurations */
if (pdata_flags & TWL_COMMON_PDATA_USB && !pmic_data->usb)
pmic_data->usb = &omap4_usb_pdata;
@@ -350,5 +534,11 @@ void __init omap4_pmic_get_config(struct twl4030_platform_data *pmic_data,
if (regulators_flags & TWL_COMMON_REGULATOR_CLK32KG &&
!pmic_data->clk32kg)
pmic_data->clk32kg = &omap4_clk32kg_idata;
+
+ if (regulators_flags & TWL_COMMON_REGULATOR_V1V8 && !pmic_data->v1v8)
+ pmic_data->v1v8 = &omap4_v1v8_idata;
+
+ if (regulators_flags & TWL_COMMON_REGULATOR_V2V1 && !pmic_data->v2v1)
+ pmic_data->v2v1 = &omap4_v2v1_idata;
}
#endif /* CONFIG_ARCH_OMAP4 */
diff --git a/arch/arm/mach-omap2/twl-common.h b/arch/arm/mach-omap2/twl-common.h
index 09627483a57f..8fe71cfd002c 100644
--- a/arch/arm/mach-omap2/twl-common.h
+++ b/arch/arm/mach-omap2/twl-common.h
@@ -22,6 +22,8 @@
#define TWL_COMMON_REGULATOR_VCXIO (1 << 8)
#define TWL_COMMON_REGULATOR_VUSB (1 << 9)
#define TWL_COMMON_REGULATOR_CLK32KG (1 << 10)
+#define TWL_COMMON_REGULATOR_V1V8 (1 << 11)
+#define TWL_COMMON_REGULATOR_V2V1 (1 << 12)
/* TWL4030 LDO regulators */
#define TWL_COMMON_REGULATOR_VPLL1 (1 << 4)
diff --git a/arch/arm/mach-omap2/usb-tusb6010.c b/arch/arm/mach-omap2/usb-tusb6010.c
index 994d8f591a1d..db84a46ce7fd 100644
--- a/arch/arm/mach-omap2/usb-tusb6010.c
+++ b/arch/arm/mach-omap2/usb-tusb6010.c
@@ -126,7 +126,7 @@ static int tusb_set_sync_mode(unsigned sysclk_ps, unsigned fclk_ps)
tmp = (t.sync_clk + fclk_ps - 1) / fclk_ps;
if (tmp > 4)
return -ERANGE;
- if (tmp <= 0)
+ if (tmp == 0)
tmp = 1;
t.page_burst_access = (fclk_ps * tmp) / 1000;
diff --git a/arch/arm/mach-omap2/vc3xxx_data.c b/arch/arm/mach-omap2/vc3xxx_data.c
index a5ec7f8f2ea8..5d8eaf31569c 100644
--- a/arch/arm/mach-omap2/vc3xxx_data.c
+++ b/arch/arm/mach-omap2/vc3xxx_data.c
@@ -46,6 +46,7 @@ static struct omap_vc_common omap3_vc_common = {
};
struct omap_vc_channel omap3_vc_mpu = {
+ .flags = OMAP_VC_CHANNEL_DEFAULT,
.common = &omap3_vc_common,
.smps_sa_reg = OMAP3_PRM_VC_SMPS_SA_OFFSET,
.smps_volra_reg = OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET,
diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
index 8a36342e60d2..4dc60e83e00d 100644
--- a/arch/arm/mach-omap2/voltage.c
+++ b/arch/arm/mach-omap2/voltage.c
@@ -73,7 +73,8 @@ unsigned long voltdm_get_voltage(struct voltagedomain *voltdm)
int voltdm_scale(struct voltagedomain *voltdm,
unsigned long target_volt)
{
- int ret;
+ int ret, i;
+ unsigned long volt = 0;
if (!voltdm || IS_ERR(voltdm)) {
pr_warning("%s: VDD specified does not exist!\n", __func__);
@@ -86,9 +87,23 @@ int voltdm_scale(struct voltagedomain *voltdm,
return -ENODATA;
}
- ret = voltdm->scale(voltdm, target_volt);
+ /* Adjust voltage to the exact voltage from the OPP table */
+ for (i = 0; voltdm->volt_data[i].volt_nominal != 0; i++) {
+ if (voltdm->volt_data[i].volt_nominal >= target_volt) {
+ volt = voltdm->volt_data[i].volt_nominal;
+ break;
+ }
+ }
+
+ if (!volt) {
+ pr_warning("%s: not scaling. OPP voltage for %lu, not found.\n",
+ __func__, target_volt);
+ return -EINVAL;
+ }
+
+ ret = voltdm->scale(voltdm, volt);
if (!ret)
- voltdm->nominal_volt = target_volt;
+ voltdm->nominal_volt = volt;
return ret;
}
diff --git a/arch/arm/mach-omap2/wd_timer.c b/arch/arm/mach-omap2/wd_timer.c
index 4067669d96c4..b2f1c67043a2 100644
--- a/arch/arm/mach-omap2/wd_timer.c
+++ b/arch/arm/mach-omap2/wd_timer.c
@@ -14,6 +14,7 @@
#include <plat/omap_hwmod.h>
#include "wd_timer.h"
+#include "common.h"
/*
* In order to avoid any assumptions from bootloader regarding WDT
@@ -25,6 +26,8 @@
#define OMAP_WDT_WPS 0x34
#define OMAP_WDT_SPR 0x48
+/* Maximum microseconds to wait for OMAP module to softreset */
+#define MAX_MODULE_SOFTRESET_WAIT 10000
int omap2_wd_timer_disable(struct omap_hwmod *oh)
{
@@ -54,3 +57,45 @@ int omap2_wd_timer_disable(struct omap_hwmod *oh)
return 0;
}
+/**
+ * omap2_wdtimer_reset - reset and disable the WDTIMER IP block
+ * @oh: struct omap_hwmod *
+ *
+ * After the WDTIMER IP blocks are reset on OMAP2/3, we must also take
+ * care to execute the special watchdog disable sequence. This is
+ * because the watchdog is re-armed upon OCP softreset. (On OMAP4,
+ * this behavior was apparently changed and the watchdog is no longer
+ * re-armed after an OCP soft-reset.) Returns -ETIMEDOUT if the reset
+ * did not complete, or 0 upon success.
+ *
+ * XXX Most of this code should be moved to the omap_hwmod.c layer
+ * during a normal merge window. omap_hwmod_softreset() should be
+ * renamed to omap_hwmod_set_ocp_softreset(), and omap_hwmod_softreset()
+ * should call the hwmod _ocp_softreset() code.
+ */
+int omap2_wd_timer_reset(struct omap_hwmod *oh)
+{
+ int c = 0;
+
+ /* Write to the SOFTRESET bit */
+ omap_hwmod_softreset(oh);
+
+ /* Poll on RESETDONE bit */
+ omap_test_timeout((omap_hwmod_read(oh,
+ oh->class->sysc->syss_offs)
+ & SYSS_RESETDONE_MASK),
+ MAX_MODULE_SOFTRESET_WAIT, c);
+
+ if (oh->class->sysc->srst_udelay)
+ udelay(oh->class->sysc->srst_udelay);
+
+ if (c == MAX_MODULE_SOFTRESET_WAIT)
+ pr_warning("%s: %s: softreset failed (waited %d usec)\n",
+ __func__, oh->name, MAX_MODULE_SOFTRESET_WAIT);
+ else
+ pr_debug("%s: %s: softreset in %d usec\n", __func__,
+ oh->name, c);
+
+ return (c == MAX_MODULE_SOFTRESET_WAIT) ? -ETIMEDOUT :
+ omap2_wd_timer_disable(oh);
+}
diff --git a/arch/arm/mach-omap2/wd_timer.h b/arch/arm/mach-omap2/wd_timer.h
index e0054a2d5505..f6bbba73b535 100644
--- a/arch/arm/mach-omap2/wd_timer.h
+++ b/arch/arm/mach-omap2/wd_timer.h
@@ -13,5 +13,6 @@
#include <plat/omap_hwmod.h>
extern int omap2_wd_timer_disable(struct omap_hwmod *oh);
+extern int omap2_wd_timer_reset(struct omap_hwmod *oh);
#endif
diff --git a/arch/arm/mach-orion5x/Kconfig b/arch/arm/mach-orion5x/Kconfig
index 6604fc6ca58a..0673f0c10432 100644
--- a/arch/arm/mach-orion5x/Kconfig
+++ b/arch/arm/mach-orion5x/Kconfig
@@ -86,7 +86,6 @@ config MACH_WRT350N_V2
config MACH_TS78XX
bool "Technologic Systems TS-78xx"
- select PM
help
Say 'Y' here if you want your kernel to support the
Technologic Systems TS-78xx platform.
diff --git a/arch/arm/mach-orion5x/addr-map.c b/arch/arm/mach-orion5x/addr-map.c
index 3638e5c12b7e..eaac83d1df6f 100644
--- a/arch/arm/mach-orion5x/addr-map.c
+++ b/arch/arm/mach-orion5x/addr-map.c
@@ -76,7 +76,7 @@ static int __init cpu_win_can_remap(const struct orion_addr_map_cfg *cfg,
/*
* Description of the windows needed by the platform code
*/
-static struct __initdata orion_addr_map_cfg addr_map_cfg = {
+static struct orion_addr_map_cfg addr_map_cfg __initdata = {
.num_wins = 8,
.cpu_win_can_remap = cpu_win_can_remap,
.bridge_virt_base = ORION5X_BRIDGE_VIRT_BASE,
diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c
index 24481666d2cd..e2e9db492d0c 100644
--- a/arch/arm/mach-orion5x/common.c
+++ b/arch/arm/mach-orion5x/common.c
@@ -205,7 +205,7 @@ int __init orion5x_find_tclk(void)
return 166666667;
}
-static void orion5x_timer_init(void)
+static void __init orion5x_timer_init(void)
{
orion5x_tclk = orion5x_find_tclk();
diff --git a/arch/arm/mach-orion5x/common.h b/arch/arm/mach-orion5x/common.h
index 2e6454c8d4ba..31bab92ce038 100644
--- a/arch/arm/mach-orion5x/common.h
+++ b/arch/arm/mach-orion5x/common.h
@@ -45,6 +45,7 @@ void orion5x_restart(char, const char *);
*/
struct pci_bus;
struct pci_sys_data;
+struct pci_dev;
void orion5x_pcie_id(u32 *dev, u32 *rev);
void orion5x_pci_disable(void);
diff --git a/arch/arm/mach-orion5x/dns323-setup.c b/arch/arm/mach-orion5x/dns323-setup.c
index 8c06ccac44c2..d470864b4e42 100644
--- a/arch/arm/mach-orion5x/dns323-setup.c
+++ b/arch/arm/mach-orion5x/dns323-setup.c
@@ -252,27 +252,6 @@ error_fail:
* GPIO LEDs (simple - doesn't use hardware blinking support)
*/
-#define ORION_BLINK_HALF_PERIOD 100 /* ms */
-
-static int dns323_gpio_blink_set(unsigned gpio, int state,
- unsigned long *delay_on, unsigned long *delay_off)
-{
-
- if (delay_on && delay_off && !*delay_on && !*delay_off)
- *delay_on = *delay_off = ORION_BLINK_HALF_PERIOD;
-
- switch(state) {
- case GPIO_LED_NO_BLINK_LOW:
- case GPIO_LED_NO_BLINK_HIGH:
- orion_gpio_set_blink(gpio, 0);
- gpio_set_value(gpio, state);
- break;
- case GPIO_LED_BLINK:
- orion_gpio_set_blink(gpio, 1);
- }
- return 0;
-}
-
static struct gpio_led dns323ab_leds[] = {
{
.name = "power:blue",
@@ -311,13 +290,13 @@ static struct gpio_led dns323c_leds[] = {
static struct gpio_led_platform_data dns323ab_led_data = {
.num_leds = ARRAY_SIZE(dns323ab_leds),
.leds = dns323ab_leds,
- .gpio_blink_set = dns323_gpio_blink_set,
+ .gpio_blink_set = orion_gpio_led_blink_set,
};
static struct gpio_led_platform_data dns323c_led_data = {
.num_leds = ARRAY_SIZE(dns323c_leds),
.leds = dns323c_leds,
- .gpio_blink_set = dns323_gpio_blink_set,
+ .gpio_blink_set = orion_gpio_led_blink_set,
};
static struct platform_device dns323_gpio_leds = {
diff --git a/arch/arm/mach-orion5x/ts78xx-fpga.h b/arch/arm/mach-orion5x/ts78xx-fpga.h
index 151e89e1e676..97c393d39ae2 100644
--- a/arch/arm/mach-orion5x/ts78xx-fpga.h
+++ b/arch/arm/mach-orion5x/ts78xx-fpga.h
@@ -28,9 +28,9 @@ struct fpga_device {
struct fpga_devices {
/* Technologic Systems */
- struct fpga_device ts_rtc;
- struct fpga_device ts_nand;
- struct fpga_device ts_rng;
+ struct fpga_device ts_rtc;
+ struct fpga_device ts_nand;
+ struct fpga_device ts_rng;
};
struct ts78xx_fpga_data {
diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c
index c96f37472eda..a74f3cf54cc5 100644
--- a/arch/arm/mach-orion5x/ts78xx-setup.c
+++ b/arch/arm/mach-orion5x/ts78xx-setup.c
@@ -8,6 +8,8 @@
* warranty of any kind, whether express or implied.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sysfs.h>
@@ -115,7 +117,7 @@ static struct platform_device ts78xx_ts_rtc_device = {
* I've used the method TS use in their rtc7800.c example for the detection
*
* TODO: track down a guinea pig without an RTC to see if we can work out a
- * better RTC detection routine
+ * better RTC detection routine
*/
static int ts78xx_ts_rtc_load(void)
{
@@ -141,10 +143,14 @@ static int ts78xx_ts_rtc_load(void)
} else
rc = platform_device_add(&ts78xx_ts_rtc_device);
+ if (rc)
+ pr_info("RTC could not be registered: %d\n",
+ rc);
return rc;
}
}
+ pr_info("RTC not found\n");
return -ENODEV;
};
@@ -292,11 +298,8 @@ static struct platform_nand_data ts78xx_ts_nand_data = {
},
};
-static struct resource ts78xx_ts_nand_resources = {
- .start = TS_NAND_DATA,
- .end = TS_NAND_DATA + 4,
- .flags = IORESOURCE_MEM,
-};
+static struct resource ts78xx_ts_nand_resources
+ = DEFINE_RES_MEM(TS_NAND_DATA, 4);
static struct platform_device ts78xx_ts_nand_device = {
.name = "gen_nand",
@@ -319,6 +322,8 @@ static int ts78xx_ts_nand_load(void)
} else
rc = platform_device_add(&ts78xx_ts_nand_device);
+ if (rc)
+ pr_info("NAND could not be registered: %d\n", rc);
return rc;
};
@@ -332,11 +337,8 @@ static void ts78xx_ts_nand_unload(void)
****************************************************************************/
#define TS_RNG_DATA (TS78XX_FPGA_REGS_PHYS_BASE | 0x044)
-static struct resource ts78xx_ts_rng_resource = {
- .flags = IORESOURCE_MEM,
- .start = TS_RNG_DATA,
- .end = TS_RNG_DATA + 4 - 1,
-};
+static struct resource ts78xx_ts_rng_resource
+ = DEFINE_RES_MEM(TS_RNG_DATA, 4);
static struct timeriomem_rng_data ts78xx_ts_rng_data = {
.period = 1000000, /* one second */
@@ -363,6 +365,8 @@ static int ts78xx_ts_rng_load(void)
} else
rc = platform_device_add(&ts78xx_ts_rng_device);
+ if (rc)
+ pr_info("RNG could not be registered: %d\n", rc);
return rc;
};
@@ -402,7 +406,7 @@ static void ts78xx_fpga_supports(void)
/* enable devices if magic matches */
switch ((ts78xx_fpga.id >> 8) & 0xffffff) {
case TS7800_FPGA_MAGIC:
- pr_warning("TS-7800 FPGA: unrecognized revision 0x%.2x\n",
+ pr_warning("unrecognised FPGA revision 0x%.2x\n",
ts78xx_fpga.id & 0xff);
ts78xx_fpga.supports.ts_rtc.present = 1;
ts78xx_fpga.supports.ts_nand.present = 1;
@@ -422,26 +426,20 @@ static int ts78xx_fpga_load_devices(void)
if (ts78xx_fpga.supports.ts_rtc.present == 1) {
tmp = ts78xx_ts_rtc_load();
- if (tmp) {
- pr_info("TS-78xx: RTC not registered\n");
+ if (tmp)
ts78xx_fpga.supports.ts_rtc.present = 0;
- }
ret |= tmp;
}
if (ts78xx_fpga.supports.ts_nand.present == 1) {
tmp = ts78xx_ts_nand_load();
- if (tmp) {
- pr_info("TS-78xx: NAND not registered\n");
+ if (tmp)
ts78xx_fpga.supports.ts_nand.present = 0;
- }
ret |= tmp;
}
if (ts78xx_fpga.supports.ts_rng.present == 1) {
tmp = ts78xx_ts_rng_load();
- if (tmp) {
- pr_info("TS-78xx: RNG not registered\n");
+ if (tmp)
ts78xx_fpga.supports.ts_rng.present = 0;
- }
ret |= tmp;
}
@@ -466,7 +464,7 @@ static int ts78xx_fpga_load(void)
{
ts78xx_fpga.id = readl(TS78XX_FPGA_REGS_VIRT_BASE);
- pr_info("TS-78xx FPGA: magic=0x%.6x, rev=0x%.2x\n",
+ pr_info("FPGA magic=0x%.6x, rev=0x%.2x\n",
(ts78xx_fpga.id >> 8) & 0xffffff,
ts78xx_fpga.id & 0xff);
@@ -494,7 +492,7 @@ static int ts78xx_fpga_unload(void)
* UrJTAG SVN since r1381 can be used to reprogram the FPGA
*/
if (ts78xx_fpga.id != fpga_id) {
- pr_err("TS-78xx FPGA: magic/rev mismatch\n"
+ pr_err("FPGA magic/rev mismatch\n"
"TS-78xx FPGA: was 0x%.6x/%.2x but now 0x%.6x/%.2x\n",
(ts78xx_fpga.id >> 8) & 0xffffff, ts78xx_fpga.id & 0xff,
(fpga_id >> 8) & 0xffffff, fpga_id & 0xff);
@@ -525,7 +523,7 @@ static ssize_t ts78xx_fpga_store(struct kobject *kobj,
int value, ret;
if (ts78xx_fpga.state < 0) {
- pr_err("TS-78xx FPGA: borked, you must powercycle asap\n");
+ pr_err("FPGA borked, you must powercycle ASAP\n");
return -EBUSY;
}
@@ -533,10 +531,8 @@ static ssize_t ts78xx_fpga_store(struct kobject *kobj,
value = 1;
else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0)
value = 0;
- else {
- pr_err("ts78xx_fpga_store: Invalid value\n");
+ else
return -EINVAL;
- }
if (ts78xx_fpga.state == value)
return n;
@@ -614,7 +610,7 @@ static void __init ts78xx_init(void)
/* FPGA init */
ts78xx_fpga_devices_zero_init();
ret = ts78xx_fpga_load();
- ret = sysfs_create_file(power_kobj, &ts78xx_fpga_attr.attr);
+ ret = sysfs_create_file(firmware_kobj, &ts78xx_fpga_attr.attr);
if (ret)
pr_err("sysfs_create_file failed: %d\n", ret);
}
diff --git a/arch/arm/mach-pnx4008/i2c.c b/arch/arm/mach-pnx4008/i2c.c
index 8103f9644e2d..550cfc2a1f2e 100644
--- a/arch/arm/mach-pnx4008/i2c.c
+++ b/arch/arm/mach-pnx4008/i2c.c
@@ -16,48 +16,62 @@
#include <linux/err.h>
#include <mach/platform.h>
#include <mach/irqs.h>
-#include <mach/i2c.h>
-static struct i2c_pnx_data i2c0_data = {
- .name = I2C_CHIP_NAME "0",
- .base = PNX4008_I2C1_BASE,
- .irq = I2C_1_INT,
+static struct resource i2c0_resources[] = {
+ {
+ .start = PNX4008_I2C1_BASE,
+ .end = PNX4008_I2C1_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = I2C_1_INT,
+ .end = I2C_1_INT,
+ .flags = IORESOURCE_IRQ,
+ },
};
-static struct i2c_pnx_data i2c1_data = {
- .name = I2C_CHIP_NAME "1",
- .base = PNX4008_I2C2_BASE,
- .irq = I2C_2_INT,
+static struct resource i2c1_resources[] = {
+ {
+ .start = PNX4008_I2C2_BASE,
+ .end = PNX4008_I2C2_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = I2C_2_INT,
+ .end = I2C_2_INT,
+ .flags = IORESOURCE_IRQ,
+ },
};
-static struct i2c_pnx_data i2c2_data = {
- .name = "USB-I2C",
- .base = (PNX4008_USB_CONFIG_BASE + 0x300),
- .irq = USB_I2C_INT,
+static struct resource i2c2_resources[] = {
+ {
+ .start = PNX4008_USB_CONFIG_BASE + 0x300,
+ .end = PNX4008_USB_CONFIG_BASE + 0x300 + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = USB_I2C_INT,
+ .end = USB_I2C_INT,
+ .flags = IORESOURCE_IRQ,
+ },
};
static struct platform_device i2c0_device = {
- .name = "pnx-i2c",
+ .name = "pnx-i2c.0",
.id = 0,
- .dev = {
- .platform_data = &i2c0_data,
- },
+ .resource = i2c0_resources,
+ .num_resources = ARRAY_SIZE(i2c0_resources),
};
static struct platform_device i2c1_device = {
- .name = "pnx-i2c",
+ .name = "pnx-i2c.1",
.id = 1,
- .dev = {
- .platform_data = &i2c1_data,
- },
+ .resource = i2c1_resources,
+ .num_resources = ARRAY_SIZE(i2c1_resources),
};
static struct platform_device i2c2_device = {
- .name = "pnx-i2c",
+ .name = "pnx-i2c.2",
.id = 2,
- .dev = {
- .platform_data = &i2c2_data,
- },
+ .resource = i2c2_resources,
+ .num_resources = ARRAY_SIZE(i2c2_resources),
};
static struct platform_device *devices[] __initdata = {
diff --git a/arch/arm/mach-pnx4008/include/mach/i2c.h b/arch/arm/mach-pnx4008/include/mach/i2c.h
deleted file mode 100644
index 259ac53abf40..000000000000
--- a/arch/arm/mach-pnx4008/include/mach/i2c.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * PNX4008-specific tweaks for I2C IP3204 block
- *
- * Author: Vitaly Wool <vwool@ru.mvista.com>
- *
- * 2005 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-
-#ifndef __ASM_ARCH_I2C_H__
-#define __ASM_ARCH_I2C_H__
-
-enum {
- mstatus_tdi = 0x00000001,
- mstatus_afi = 0x00000002,
- mstatus_nai = 0x00000004,
- mstatus_drmi = 0x00000008,
- mstatus_active = 0x00000020,
- mstatus_scl = 0x00000040,
- mstatus_sda = 0x00000080,
- mstatus_rff = 0x00000100,
- mstatus_rfe = 0x00000200,
- mstatus_tff = 0x00000400,
- mstatus_tfe = 0x00000800,
-};
-
-enum {
- mcntrl_tdie = 0x00000001,
- mcntrl_afie = 0x00000002,
- mcntrl_naie = 0x00000004,
- mcntrl_drmie = 0x00000008,
- mcntrl_daie = 0x00000020,
- mcntrl_rffie = 0x00000040,
- mcntrl_tffie = 0x00000080,
- mcntrl_reset = 0x00000100,
- mcntrl_cdbmode = 0x00000400,
-};
-
-enum {
- rw_bit = 1 << 0,
- start_bit = 1 << 8,
- stop_bit = 1 << 9,
-};
-
-#define I2C_REG_RX(a) ((a)->ioaddr) /* Rx FIFO reg (RO) */
-#define I2C_REG_TX(a) ((a)->ioaddr) /* Tx FIFO reg (WO) */
-#define I2C_REG_STS(a) ((a)->ioaddr + 0x04) /* Status reg (RO) */
-#define I2C_REG_CTL(a) ((a)->ioaddr + 0x08) /* Ctl reg */
-#define I2C_REG_CKL(a) ((a)->ioaddr + 0x0c) /* Clock divider low */
-#define I2C_REG_CKH(a) ((a)->ioaddr + 0x10) /* Clock divider high */
-#define I2C_REG_ADR(a) ((a)->ioaddr + 0x14) /* I2C address */
-#define I2C_REG_RFL(a) ((a)->ioaddr + 0x18) /* Rx FIFO level (RO) */
-#define I2C_REG_TFL(a) ((a)->ioaddr + 0x1c) /* Tx FIFO level (RO) */
-#define I2C_REG_RXB(a) ((a)->ioaddr + 0x20) /* Num of bytes Rx-ed (RO) */
-#define I2C_REG_TXB(a) ((a)->ioaddr + 0x24) /* Num of bytes Tx-ed (RO) */
-#define I2C_REG_TXS(a) ((a)->ioaddr + 0x28) /* Tx slave FIFO (RO) */
-#define I2C_REG_STFL(a) ((a)->ioaddr + 0x2c) /* Tx slave FIFO level (RO) */
-
-#define HCLK_MHZ 13
-#define I2C_CHIP_NAME "PNX4008-I2C"
-
-#endif /* __ASM_ARCH_I2C_H___ */
diff --git a/arch/arm/mach-pxa/balloon3.c b/arch/arm/mach-pxa/balloon3.c
index c35456f02acb..56e8cebeb7d5 100644
--- a/arch/arm/mach-pxa/balloon3.c
+++ b/arch/arm/mach-pxa/balloon3.c
@@ -732,9 +732,7 @@ static inline void balloon3_nand_init(void) {}
#if defined(CONFIG_REGULATOR_MAX1586) || \
defined(CONFIG_REGULATOR_MAX1586_MODULE)
static struct regulator_consumer_supply balloon3_max1587a_consumers[] = {
- {
- .supply = "vcc_core",
- }
+ REGULATOR_SUPPLY("vcc_core", NULL),
};
static struct regulator_init_data balloon3_max1587a_v3_info = {
diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c
index 313274016277..3e4e9fe2d462 100644
--- a/arch/arm/mach-pxa/cm-x300.c
+++ b/arch/arm/mach-pxa/cm-x300.c
@@ -713,9 +713,7 @@ struct da9030_battery_info cm_x300_battery_info = {
};
static struct regulator_consumer_supply buck2_consumers[] = {
- {
- .supply = "vcc_core",
- },
+ REGULATOR_SUPPLY("vcc_core", NULL),
};
static struct regulator_init_data buck2_data = {
diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c
index 16ec557b8e43..a3a4a38d4972 100644
--- a/arch/arm/mach-pxa/em-x270.c
+++ b/arch/arm/mach-pxa/em-x270.c
@@ -1085,10 +1085,7 @@ static void __init em_x270_userspace_consumers_init(void)
/* DA9030 related initializations */
#define REGULATOR_CONSUMER(_name, _dev_name, _supply) \
static struct regulator_consumer_supply _name##_consumers[] = { \
- { \
- .dev_name = _dev_name, \
- .supply = _supply, \
- }, \
+ REGULATOR_SUPPLY(_supply, _dev_name), \
}
REGULATOR_CONSUMER(ldo3, "reg-userspace-consumer.0", "vcc gps");
diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c
index b83b95a29503..d09da6a746b8 100644
--- a/arch/arm/mach-pxa/hx4700.c
+++ b/arch/arm/mach-pxa/hx4700.c
@@ -22,6 +22,7 @@
#include <linux/gpio.h>
#include <linux/gpio_keys.h>
#include <linux/input.h>
+#include <linux/input/navpoint.h>
#include <linux/lcd.h>
#include <linux/mfd/htc-egpio.h>
#include <linux/mfd/asic3.h>
@@ -102,6 +103,10 @@ static unsigned long hx4700_pin_config[] __initdata = {
GPIO44_BTUART_CTS,
GPIO45_BTUART_RTS_LPM_LOW,
+ /* STUART (IRDA) */
+ GPIO46_STUART_RXD,
+ GPIO47_STUART_TXD,
+
/* PWM 1 (Backlight) */
GPIO17_PWM1_OUT,
@@ -113,7 +118,7 @@ static unsigned long hx4700_pin_config[] __initdata = {
GPIO113_I2S_SYSCLK,
/* SSP 1 (NavPoint) */
- GPIO23_SSP1_SCLK,
+ GPIO23_SSP1_SCLK_IN,
GPIO24_SSP1_SFRM,
GPIO25_SSP1_TXD,
GPIO26_SSP1_RXD,
@@ -125,10 +130,13 @@ static unsigned long hx4700_pin_config[] __initdata = {
GPIO88_GPIO,
/* HX4700 specific input GPIOs */
- GPIO12_GPIO, /* ASIC3_IRQ */
+ GPIO12_GPIO | WAKEUP_ON_EDGE_RISE, /* ASIC3_IRQ */
GPIO13_GPIO, /* W3220_IRQ */
GPIO14_GPIO, /* nWLAN_IRQ */
+ /* HX4700 specific output GPIOs */
+ GPIO102_GPIO | MFP_LPM_DRIVE_LOW, /* SYNAPTICS_POWER_ON */
+
GPIO10_GPIO, /* GSM_IRQ */
GPIO13_GPIO, /* CPLD_IRQ */
GPIO107_GPIO, /* DS1WM_IRQ */
@@ -183,6 +191,23 @@ static struct platform_device gpio_keys = {
};
/*
+ * Synaptics NavPoint connected to SSP1
+ */
+
+static struct navpoint_platform_data navpoint_platform_data = {
+ .port = 1,
+ .gpio = GPIO102_HX4700_SYNAPTICS_POWER_ON,
+};
+
+static struct platform_device navpoint = {
+ .name = "navpoint",
+ .id = -1,
+ .dev = {
+ .platform_data = &navpoint_platform_data,
+ },
+};
+
+/*
* ASIC3
*/
@@ -227,7 +252,6 @@ static u16 asic3_gpio_config[] = {
ASIC3_GPIOC0_LED0, /* red */
ASIC3_GPIOC1_LED1, /* green */
ASIC3_GPIOC2_LED2, /* blue */
- ASIC3_GPIOC4_CF_nCD,
ASIC3_GPIOC5_nCIOW,
ASIC3_GPIOC6_nCIOR,
ASIC3_GPIOC7_nPCE_1,
@@ -241,6 +265,7 @@ static u16 asic3_gpio_config[] = {
ASIC3_GPIOC15_nPIOR,
/* GPIOD: input GPIOs, CF */
+ ASIC3_GPIOD4_CF_nCD,
ASIC3_GPIOD11_nCIOIS16,
ASIC3_GPIOD12_nCWAIT,
ASIC3_GPIOD15_nPIOW,
@@ -291,6 +316,7 @@ static struct asic3_platform_data asic3_platform_data = {
.gpio_config_num = ARRAY_SIZE(asic3_gpio_config),
.irq_base = IRQ_BOARD_START,
.gpio_base = HX4700_ASIC3_GPIO_BASE,
+ .clock_rate = 4000000,
.leds = asic3_leds,
};
@@ -680,12 +706,8 @@ static struct platform_device power_supply = {
*/
static struct regulator_consumer_supply bq24022_consumers[] = {
- {
- .supply = "vbus_draw",
- },
- {
- .supply = "ac_draw",
- },
+ REGULATOR_SUPPLY("vbus_draw", NULL),
+ REGULATOR_SUPPLY("ac_draw", NULL),
};
static struct regulator_init_data bq24022_init_data = {
@@ -764,9 +786,8 @@ static struct platform_device strataflash = {
* Maxim MAX1587A on PI2C
*/
-static struct regulator_consumer_supply max1587a_consumer = {
- .supply = "vcc_core",
-};
+static struct regulator_consumer_supply max1587a_consumer =
+ REGULATOR_SUPPLY("vcc_core", NULL);
static struct regulator_init_data max1587a_v3_info = {
.constraints = {
@@ -828,6 +849,7 @@ static struct platform_device audio = {
static struct platform_device *devices[] __initdata = {
&asic3,
&gpio_keys,
+ &navpoint,
&backlight,
&w3220,
&hx4700_lcd,
@@ -859,6 +881,7 @@ static void __init hx4700_init(void)
int ret;
pxa2xx_mfp_config(ARRAY_AND_SIZE(hx4700_pin_config));
+ gpio_set_wake(GPIO12_HX4700_ASIC3_IRQ, 1);
ret = gpio_request_array(ARRAY_AND_SIZE(global_gpios));
if (ret)
pr_err ("hx4700: Failed to request GPIOs.\n");
diff --git a/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h b/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h
index a65867209aa0..a611ad3153c7 100644
--- a/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h
+++ b/arch/arm/mach-pxa/include/mach/mfp-pxa27x.h
@@ -208,6 +208,7 @@
#define GPIO113_I2S_SYSCLK MFP_CFG_OUT(GPIO113, AF1, DRIVE_LOW)
/* SSP 1 */
+#define GPIO23_SSP1_SCLK_IN MFP_CFG_IN(GPIO23, AF2)
#define GPIO23_SSP1_SCLK MFP_CFG_OUT(GPIO23, AF2, DRIVE_LOW)
#define GPIO29_SSP1_SCLK MFP_CFG_IN(GPIO29, AF3)
#define GPIO27_SSP1_SYSCLK MFP_CFG_OUT(GPIO27, AF1, DRIVE_LOW)
diff --git a/arch/arm/mach-pxa/include/mach/mioa701.h b/arch/arm/mach-pxa/include/mach/mioa701.h
index 02868447b0b1..e57f5c724e8a 100644
--- a/arch/arm/mach-pxa/include/mach/mioa701.h
+++ b/arch/arm/mach-pxa/include/mach/mioa701.h
@@ -61,6 +61,9 @@
#define GPIO93_KEY_VOLUME_UP 93
#define GPIO94_KEY_VOLUME_DOWN 94
+/* Camera */
+#define GPIO56_MT9M111_nOE 56
+
extern struct input_dev *mioa701_evdev;
extern void mioa701_gpio_lpm_set(unsigned long mfp_pin);
diff --git a/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h b/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h
index d72791695b26..0260aaa2fc17 100644
--- a/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h
+++ b/arch/arm/mach-pxa/include/mach/pcm990_baseboard.h
@@ -31,7 +31,6 @@
#define PCM990_CTRL_INT_IRQ PXA_GPIO_TO_IRQ(PCM990_CTRL_INT_IRQ_GPIO)
#define PCM990_CTRL_INT_IRQ_EDGE IRQ_TYPE_EDGE_RISING
#define PCM990_CTRL_PHYS PXA_CS1_PHYS /* 16-Bit */
-#define PCM990_CTRL_BASE 0xea000000
#define PCM990_CTRL_SIZE (1*1024*1024)
#define PCM990_CTRL_PWR_IRQ_GPIO 14
@@ -69,13 +68,13 @@
#define PCM990_CTRL_MMC2DE 0x0004 /* R MMC2 Card detect */
#define PCM990_CTRL_MMC2WP 0x0008 /* R MMC2 Card write protect */
-#define PCM990_CTRL_REG6 0x000C /* Interrupt Clear REGISTER */
+#define PCM990_CTRL_INTSETCLR 0x000C /* Interrupt Clear REGISTER */
#define PCM990_CTRL_INTC0 0x0001 /* Clear Reg BT Detect */
#define PCM990_CTRL_INTC1 0x0002 /* Clear Reg FR RI */
#define PCM990_CTRL_INTC2 0x0004 /* Clear Reg MMC1 Detect */
#define PCM990_CTRL_INTC3 0x0008 /* Clear Reg PM_5V off */
-#define PCM990_CTRL_REG7 0x000E /* Interrupt Enable REGISTER */
+#define PCM990_CTRL_INTMSKENA 0x000E /* Interrupt Enable REGISTER */
#define PCM990_CTRL_ENAINT0 0x0001 /* Enable Int BT Detect */
#define PCM990_CTRL_ENAINT1 0x0002 /* Enable Int FR RI */
#define PCM990_CTRL_ENAINT2 0x0004 /* Enable Int MMC1 Detect */
@@ -102,32 +101,6 @@
#define PCM990_CTRL_ACPRES 0x0004 /* DC Present */
#define PCM990_CTRL_ACALARM 0x0008 /* Error Akku */
-#define PCM990_CTRL_P2V(x) ((x) - PCM990_CTRL_PHYS + PCM990_CTRL_BASE)
-#define PCM990_CTRL_V2P(x) ((x) - PCM990_CTRL_BASE + PCM990_CTRL_PHYS)
-
-#ifndef __ASSEMBLY__
-# define __PCM990_CTRL_REG(x) \
- (*((volatile unsigned char *)PCM990_CTRL_P2V(x)))
-#else
-# define __PCM990_CTRL_REG(x) PCM990_CTRL_P2V(x)
-#endif
-
-#define PCM990_INTMSKENA __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG7)
-#define PCM990_INTSETCLR __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG6)
-#define PCM990_CTRL0 __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG0)
-#define PCM990_CTRL1 __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG1)
-#define PCM990_CTRL2 __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG2)
-#define PCM990_CTRL3 __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG3)
-#define PCM990_CTRL4 __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG4)
-#define PCM990_CTRL5 __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG5)
-#define PCM990_CTRL6 __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG6)
-#define PCM990_CTRL7 __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG7)
-#define PCM990_CTRL8 __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG8)
-#define PCM990_CTRL9 __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG9)
-#define PCM990_CTRL10 __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG10)
-#define PCM990_CTRL11 __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG11)
-
-
/*
* IDE
*/
@@ -166,24 +139,6 @@
#define PCM990_IDE_PLD_P2V(x) ((x) - PCM990_IDE_PLD_PHYS + PCM990_IDE_PLD_BASE)
#define PCM990_IDE_PLD_V2P(x) ((x) - PCM990_IDE_PLD_BASE + PCM990_IDE_PLD_PHYS)
-#ifndef __ASSEMBLY__
-# define __PCM990_IDE_PLD_REG(x) \
- (*((volatile unsigned char *)PCM990_IDE_PLD_P2V(x)))
-#else
-# define __PCM990_IDE_PLD_REG(x) PCM990_IDE_PLD_P2V(x)
-#endif
-
-#define PCM990_IDE0 \
- __PCM990_IDE_PLD_REG(PCM990_IDE_PLD_PHYS + PCM990_IDE_PLD_REG0)
-#define PCM990_IDE1 \
- __PCM990_IDE_PLD_REG(PCM990_IDE_PLD_PHYS + PCM990_IDE_PLD_REG1)
-#define PCM990_IDE2 \
- __PCM990_IDE_PLD_REG(PCM990_IDE_PLD_PHYS + PCM990_IDE_PLD_REG2)
-#define PCM990_IDE3 \
- __PCM990_IDE_PLD_REG(PCM990_IDE_PLD_PHYS + PCM990_IDE_PLD_REG3)
-#define PCM990_IDE4 \
- __PCM990_IDE_PLD_REG(PCM990_IDE_PLD_PHYS + PCM990_IDE_PLD_REG4)
-
/*
* Compact Flash
*/
@@ -196,10 +151,6 @@
#define PCM990_CF_CD_EDGE IRQ_TYPE_EDGE_RISING
#define PCM990_CF_PLD_PHYS 0x30000000 /* 16 bit wide */
-#define PCM990_CF_PLD_BASE 0xef000000
-#define PCM990_CF_PLD_SIZE (1*1024*1024)
-#define PCM990_CF_PLD_P2V(x) ((x) - PCM990_CF_PLD_PHYS + PCM990_CF_PLD_BASE)
-#define PCM990_CF_PLD_V2P(x) ((x) - PCM990_CF_PLD_BASE + PCM990_CF_PLD_PHYS)
/* visible CPLD (U6) registers */
#define PCM990_CF_PLD_REG0 0x1000 /* OFFSET CF REGISTER 0 */
@@ -239,21 +190,6 @@
#define PCM990_CF_REG6_CD1 0x0001 /* R CF Card_Detect1 */
#define PCM990_CF_REG6_CD2 0x0002 /* R CF Card_Detect2 */
-#ifndef __ASSEMBLY__
-# define __PCM990_CF_PLD_REG(x) \
- (*((volatile unsigned char *)PCM990_CF_PLD_P2V(x)))
-#else
-# define __PCM990_CF_PLD_REG(x) PCM990_CF_PLD_P2V(x)
-#endif
-
-#define PCM990_CF0 __PCM990_CF_PLD_REG(PCM990_CF_PLD_PHYS + PCM990_CF_PLD_REG0)
-#define PCM990_CF1 __PCM990_CF_PLD_REG(PCM990_CF_PLD_PHYS + PCM990_CF_PLD_REG1)
-#define PCM990_CF2 __PCM990_CF_PLD_REG(PCM990_CF_PLD_PHYS + PCM990_CF_PLD_REG2)
-#define PCM990_CF3 __PCM990_CF_PLD_REG(PCM990_CF_PLD_PHYS + PCM990_CF_PLD_REG3)
-#define PCM990_CF4 __PCM990_CF_PLD_REG(PCM990_CF_PLD_PHYS + PCM990_CF_PLD_REG4)
-#define PCM990_CF5 __PCM990_CF_PLD_REG(PCM990_CF_PLD_PHYS + PCM990_CF_PLD_REG5)
-#define PCM990_CF6 __PCM990_CF_PLD_REG(PCM990_CF_PLD_PHYS + PCM990_CF_PLD_REG6)
-
/*
* Wolfson AC97 Touch
*/
diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c
index 8de0651d7efb..2db697cd2b4e 100644
--- a/arch/arm/mach-pxa/magician.c
+++ b/arch/arm/mach-pxa/magician.c
@@ -579,12 +579,8 @@ static struct platform_device power_supply = {
*/
static struct regulator_consumer_supply bq24022_consumers[] = {
- {
- .supply = "vbus_draw",
- },
- {
- .supply = "ac_draw",
- },
+ REGULATOR_SUPPLY("vbus_draw", NULL),
+ REGULATOR_SUPPLY("ac_draw", NULL),
};
static struct regulator_init_data bq24022_init_data = {
diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c
index 061d57009cee..bf99022b021f 100644
--- a/arch/arm/mach-pxa/mioa701.c
+++ b/arch/arm/mach-pxa/mioa701.c
@@ -103,6 +103,7 @@ static unsigned long mioa701_pin_config[] = {
GPIO82_CIF_DD_5,
GPIO84_CIF_FV,
GPIO85_CIF_LV,
+ MIO_CFG_OUT(GPIO56_MT9M111_nOE, AF0, DRIVE_LOW),
/* Bluetooth */
MIO_CFG_IN(GPIO14_BT_nACTIVITY, AF0),
@@ -581,9 +582,7 @@ static struct wm97xx_pdata mioa701_wm97xx_pdata = {
* Voltage regulation
*/
static struct regulator_consumer_supply max1586_consumers[] = {
- {
- .supply = "vcc_core",
- }
+ REGULATOR_SUPPLY("vcc_core", NULL),
};
static struct regulator_init_data max1586_v3_info = {
@@ -705,6 +704,7 @@ static struct gpio global_gpios[] = {
{ GPIO9_CHARGE_EN, GPIOF_OUT_INIT_HIGH, "Charger enable" },
{ GPIO18_POWEROFF, GPIOF_OUT_INIT_LOW, "Power Off" },
{ GPIO87_LCD_POWER, GPIOF_OUT_INIT_LOW, "LCD Power" },
+ { GPIO56_MT9M111_nOE, GPIOF_OUT_INIT_LOW, "Camera nOE" },
};
static void __init mioa701_machine_init(void)
diff --git a/arch/arm/mach-pxa/palm27x.c b/arch/arm/mach-pxa/palm27x.c
index fbc10d7b95d1..dad71cfa34c8 100644
--- a/arch/arm/mach-pxa/palm27x.c
+++ b/arch/arm/mach-pxa/palm27x.c
@@ -429,9 +429,7 @@ void __init palm27x_power_init(int ac, int usb)
#if defined(CONFIG_REGULATOR_MAX1586) || \
defined(CONFIG_REGULATOR_MAX1586_MODULE)
static struct regulator_consumer_supply palm27x_max1587a_consumers[] = {
- {
- .supply = "vcc_core",
- }
+ REGULATOR_SUPPLY("vcc_core", NULL),
};
static struct regulator_init_data palm27x_max1587a_v3_info = {
diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c
index abab4e2b122c..cb723e84bc27 100644
--- a/arch/arm/mach-pxa/pcm990-baseboard.c
+++ b/arch/arm/mach-pxa/pcm990-baseboard.c
@@ -65,6 +65,18 @@ static unsigned long pcm990_pin_config[] __initdata = {
GPIO31_AC97_SYNC,
};
+static void __iomem *pcm990_cpld_base;
+
+static u8 pcm990_cpld_readb(unsigned int reg)
+{
+ return readb(pcm990_cpld_base + reg);
+}
+
+static void pcm990_cpld_writeb(u8 value, unsigned int reg)
+{
+ writeb(value, pcm990_cpld_base + reg);
+}
+
/*
* pcm990_lcd_power - control power supply to the LCD
* @on: 0 = switch off, 1 = switch on
@@ -78,13 +90,13 @@ static void pcm990_lcd_power(int on, struct fb_var_screeninfo *var)
/* enable LCD-Latches
* power on LCD
*/
- __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG3) =
- PCM990_CTRL_LCDPWR + PCM990_CTRL_LCDON;
+ pcm990_cpld_writeb(PCM990_CTRL_LCDPWR + PCM990_CTRL_LCDON,
+ PCM990_CTRL_REG3);
} else {
/* disable LCD-Latches
* power off LCD
*/
- __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG3) = 0x00;
+ pcm990_cpld_writeb(0, PCM990_CTRL_REG3);
}
}
#endif
@@ -243,15 +255,26 @@ static unsigned long pcm990_irq_enabled;
static void pcm990_mask_ack_irq(struct irq_data *d)
{
int pcm990_irq = (d->irq - PCM027_IRQ(0));
- PCM990_INTMSKENA = (pcm990_irq_enabled &= ~(1 << pcm990_irq));
+
+ pcm990_irq_enabled &= ~(1 << pcm990_irq);
+
+ pcm990_cpld_writeb(pcm990_irq_enabled, PCM990_CTRL_INTMSKENA);
}
static void pcm990_unmask_irq(struct irq_data *d)
{
int pcm990_irq = (d->irq - PCM027_IRQ(0));
+ u8 val;
+
/* the irq can be acknowledged only if deasserted, so it's done here */
- PCM990_INTSETCLR |= 1 << pcm990_irq;
- PCM990_INTMSKENA = (pcm990_irq_enabled |= (1 << pcm990_irq));
+
+ pcm990_irq_enabled |= (1 << pcm990_irq);
+
+ val = pcm990_cpld_readb(PCM990_CTRL_INTSETCLR);
+ val |= 1 << pcm990_irq;
+ pcm990_cpld_writeb(val, PCM990_CTRL_INTSETCLR);
+
+ pcm990_cpld_writeb(pcm990_irq_enabled, PCM990_CTRL_INTMSKENA);
}
static struct irq_chip pcm990_irq_chip = {
@@ -261,7 +284,10 @@ static struct irq_chip pcm990_irq_chip = {
static void pcm990_irq_handler(unsigned int irq, struct irq_desc *desc)
{
- unsigned long pending = (~PCM990_INTSETCLR) & pcm990_irq_enabled;
+ unsigned long pending;
+
+ pending = ~pcm990_cpld_readb(PCM990_CTRL_INTSETCLR);
+ pending &= pcm990_irq_enabled;
do {
/* clear our parent IRQ */
@@ -270,7 +296,8 @@ static void pcm990_irq_handler(unsigned int irq, struct irq_desc *desc)
irq = PCM027_IRQ(0) + __ffs(pending);
generic_handle_irq(irq);
}
- pending = (~PCM990_INTSETCLR) & pcm990_irq_enabled;
+ pending = ~pcm990_cpld_readb(PCM990_CTRL_INTSETCLR);
+ pending &= pcm990_irq_enabled;
} while (pending);
}
@@ -285,8 +312,9 @@ static void __init pcm990_init_irq(void)
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
}
- PCM990_INTMSKENA = 0x00; /* disable all Interrupts */
- PCM990_INTSETCLR = 0xFF;
+ /* disable all Interrupts */
+ pcm990_cpld_writeb(0x0, PCM990_CTRL_INTMSKENA);
+ pcm990_cpld_writeb(0xff, PCM990_CTRL_INTSETCLR);
irq_set_chained_handler(PCM990_CTRL_INT_IRQ, pcm990_irq_handler);
irq_set_irq_type(PCM990_CTRL_INT_IRQ, PCM990_CTRL_INT_IRQ_EDGE);
@@ -309,13 +337,16 @@ static int pcm990_mci_init(struct device *dev, irq_handler_t mci_detect_int,
static void pcm990_mci_setpower(struct device *dev, unsigned int vdd)
{
struct pxamci_platform_data *p_d = dev->platform_data;
+ u8 val;
+
+ val = pcm990_cpld_readb(PCM990_CTRL_REG5);
if ((1 << vdd) & p_d->ocr_mask)
- __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG5) =
- PCM990_CTRL_MMC2PWR;
+ val |= PCM990_CTRL_MMC2PWR;
else
- __PCM990_CTRL_REG(PCM990_CTRL_PHYS + PCM990_CTRL_REG5) =
- ~PCM990_CTRL_MMC2PWR;
+ val &= ~PCM990_CTRL_MMC2PWR;
+
+ pcm990_cpld_writeb(PCM990_CTRL_MMC2PWR, PCM990_CTRL_REG5);
}
static void pcm990_mci_exit(struct device *dev, void *data)
@@ -481,23 +512,6 @@ static struct platform_device pcm990_camera[] = {
#endif /* CONFIG_VIDEO_PXA27x ||CONFIG_VIDEO_PXA27x_MODULE */
/*
- * enable generic access to the base board control CPLDs U6 and U7
- */
-static struct map_desc pcm990_io_desc[] __initdata = {
- {
- .virtual = PCM990_CTRL_BASE,
- .pfn = __phys_to_pfn(PCM990_CTRL_PHYS),
- .length = PCM990_CTRL_SIZE,
- .type = MT_DEVICE /* CPLD */
- }, {
- .virtual = PCM990_CF_PLD_BASE,
- .pfn = __phys_to_pfn(PCM990_CF_PLD_PHYS),
- .length = PCM990_CF_PLD_SIZE,
- .type = MT_DEVICE /* CPLD */
- }
-};
-
-/*
* system init for baseboard usage. Will be called by pcm027 init.
*
* Add platform devices present on this baseboard and init
@@ -507,8 +521,11 @@ void __init pcm990_baseboard_init(void)
{
pxa2xx_mfp_config(ARRAY_AND_SIZE(pcm990_pin_config));
- /* register CPLD access */
- iotable_init(ARRAY_AND_SIZE(pcm990_io_desc));
+ pcm990_cpld_base = ioremap(PCM990_CTRL_PHYS, PCM990_CTRL_SIZE);
+ if (!pcm990_cpld_base) {
+ pr_err("pcm990: failed to ioremap cpld\n");
+ return;
+ }
/* register CPLD's IRQ controller */
pcm990_init_irq();
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index df2ab0fb2ace..363d91b44ecb 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -877,9 +877,7 @@ static struct i2c_board_info spitz_i2c_devs[] = {
};
static struct regulator_consumer_supply isl6271a_consumers[] = {
- {
- .supply = "vcc_core",
- }
+ REGULATOR_SUPPLY("vcc_core", NULL),
};
static struct regulator_init_data isl6271a_info[] = {
diff --git a/arch/arm/mach-pxa/stargate2.c b/arch/arm/mach-pxa/stargate2.c
index 4cd645e29b64..30b1b0b3c7f7 100644
--- a/arch/arm/mach-pxa/stargate2.c
+++ b/arch/arm/mach-pxa/stargate2.c
@@ -151,10 +151,7 @@ static struct platform_device sht15 = {
};
static struct regulator_consumer_supply stargate2_sensor_3_con[] = {
- {
- .dev_name = "sht15",
- .supply = "vcc",
- },
+ REGULATOR_SUPPLY("vcc", "sht15"),
};
enum stargate2_ldos{
diff --git a/arch/arm/mach-pxa/vpac270.c b/arch/arm/mach-pxa/vpac270.c
index c57ab636ea9c..e1740acd15f1 100644
--- a/arch/arm/mach-pxa/vpac270.c
+++ b/arch/arm/mach-pxa/vpac270.c
@@ -640,9 +640,7 @@ static inline void vpac270_ide_init(void) {}
#if defined(CONFIG_REGULATOR_MAX1586) || \
defined(CONFIG_REGULATOR_MAX1586_MODULE)
static struct regulator_consumer_supply vpac270_max1587a_consumers[] = {
- {
- .supply = "vcc_core",
- }
+ REGULATOR_SUPPLY("vcc_core", NULL),
};
static struct regulator_init_data vpac270_max1587a_v3_info = {
diff --git a/arch/arm/mach-pxa/z2.c b/arch/arm/mach-pxa/z2.c
index fa8619970841..b9320cb8a11f 100644
--- a/arch/arm/mach-pxa/z2.c
+++ b/arch/arm/mach-pxa/z2.c
@@ -615,9 +615,7 @@ static inline void z2_spi_init(void) {}
#if defined(CONFIG_REGULATOR_TPS65023) || \
defined(CONFIG_REGULATOR_TPS65023_MODULE)
static struct regulator_consumer_supply z2_tps65021_consumers[] = {
- {
- .supply = "vcc_core",
- }
+ REGULATOR_SUPPLY("vcc_core", NULL),
};
static struct regulator_init_data z2_tps65021_info[] = {
diff --git a/arch/arm/mach-s3c24xx/bast-ide.c b/arch/arm/mach-s3c24xx/bast-ide.c
index 298ececfa366..ba02cf8d80a2 100644
--- a/arch/arm/mach-s3c24xx/bast-ide.c
+++ b/arch/arm/mach-s3c24xx/bast-ide.c
@@ -37,21 +37,9 @@ static struct pata_platform_info bast_ide_platdata = {
#define IDE_CS S3C2410_CS5
static struct resource bast_ide0_resource[] = {
- [0] = {
- .start = IDE_CS + BAST_PA_IDEPRI,
- .end = IDE_CS + BAST_PA_IDEPRI + (8 * 0x20) - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IDE_CS + BAST_PA_IDEPRIAUX + (6 * 0x20) ,
- .end = IDE_CS + BAST_PA_IDEPRIAUX + (7 * 0x20) - 1,
- .flags = IORESOURCE_MEM,
- },
- [2] = {
- .start = IRQ_IDE0,
- .end = IRQ_IDE0,
- .flags = IORESOURCE_IRQ,
- },
+ [0] = DEFINE_RES_MEM(IDE_CS + BAST_PA_IDEPRI, 8 * 0x20),
+ [1] = DEFINE_RES_MEM(IDE_CS + BAST_PA_IDEPRIAUX + (6 * 0x20), 0x20),
+ [2] = DEFINE_RES_IRQ(IRQ_IDE0),
};
static struct platform_device bast_device_ide0 = {
@@ -67,21 +55,9 @@ static struct platform_device bast_device_ide0 = {
};
static struct resource bast_ide1_resource[] = {
- [0] = {
- .start = IDE_CS + BAST_PA_IDESEC,
- .end = IDE_CS + BAST_PA_IDESEC + (8 * 0x20) - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IDE_CS + BAST_PA_IDESECAUX + (6 * 0x20),
- .end = IDE_CS + BAST_PA_IDESECAUX + (7 * 0x20) - 1,
- .flags = IORESOURCE_MEM,
- },
- [2] = {
- .start = IRQ_IDE1,
- .end = IRQ_IDE1,
- .flags = IORESOURCE_IRQ,
- },
+ [0] = DEFINE_RES_MEM(IDE_CS + BAST_PA_IDESEC, 8 * 0x20),
+ [1] = DEFINE_RES_MEM(IDE_CS + BAST_PA_IDESECAUX + (6 * 0x20), 0x20),
+ [2] = DEFINE_RES_IRQ(IRQ_IDE1),
};
static struct platform_device bast_device_ide1 = {
diff --git a/arch/arm/mach-s3c24xx/mach-amlm5900.c b/arch/arm/mach-s3c24xx/mach-amlm5900.c
index 4220cc60de3c..ea2c4b003d58 100644
--- a/arch/arm/mach-s3c24xx/mach-amlm5900.c
+++ b/arch/arm/mach-s3c24xx/mach-amlm5900.c
@@ -65,13 +65,8 @@
#include "common.h"
-static struct resource amlm5900_nor_resource = {
- .start = 0x00000000,
- .end = 0x01000000 - 1,
- .flags = IORESOURCE_MEM,
-};
-
-
+static struct resource amlm5900_nor_resource =
+ DEFINE_RES_MEM(0x00000000, SZ_16M);
static struct mtd_partition amlm5900_mtd_partitions[] = {
{
diff --git a/arch/arm/mach-s3c24xx/mach-anubis.c b/arch/arm/mach-s3c24xx/mach-anubis.c
index 60c72c54c21e..5a7d0c0010f7 100644
--- a/arch/arm/mach-s3c24xx/mach-anubis.c
+++ b/arch/arm/mach-s3c24xx/mach-anubis.c
@@ -235,19 +235,9 @@ static struct pata_platform_info anubis_ide_platdata = {
};
static struct resource anubis_ide0_resource[] = {
- {
- .start = S3C2410_CS3,
- .end = S3C2410_CS3 + (8*32) - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = S3C2410_CS3 + (1<<26) + (6*32),
- .end = S3C2410_CS3 + (1<<26) + (7*32) - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_IDE0,
- .end = IRQ_IDE0,
- .flags = IORESOURCE_IRQ,
- },
+ [0] = DEFINE_RES_MEM(S3C2410_CS3, 8 * 32),
+ [2] = DEFINE_RES_MEM(S3C2410_CS3 + (1 << 26) + (6 * 32), 32),
+ [3] = DEFINE_RES_IRQ(IRQ_IDE0),
};
static struct platform_device anubis_device_ide0 = {
@@ -262,19 +252,9 @@ static struct platform_device anubis_device_ide0 = {
};
static struct resource anubis_ide1_resource[] = {
- {
- .start = S3C2410_CS4,
- .end = S3C2410_CS4 + (8*32) - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = S3C2410_CS4 + (1<<26) + (6*32),
- .end = S3C2410_CS4 + (1<<26) + (7*32) - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_IDE0,
- .end = IRQ_IDE0,
- .flags = IORESOURCE_IRQ,
- },
+ [0] = DEFINE_RES_MEM(S3C2410_CS4, 8 * 32),
+ [1] = DEFINE_RES_MEM(S3C2410_CS4 + (1 << 26) + (6 * 32), 32),
+ [2] = DEFINE_RES_IRQ(IRQ_IDE0),
};
static struct platform_device anubis_device_ide1 = {
@@ -298,16 +278,8 @@ static struct ax_plat_data anubis_asix_platdata = {
};
static struct resource anubis_asix_resource[] = {
- [0] = {
- .start = S3C2410_CS5,
- .end = S3C2410_CS5 + (0x20 * 0x20) -1,
- .flags = IORESOURCE_MEM
- },
- [1] = {
- .start = IRQ_ASIX,
- .end = IRQ_ASIX,
- .flags = IORESOURCE_IRQ
- }
+ [0] = DEFINE_RES_MEM(S3C2410_CS5, 0x20 * 0x20),
+ [1] = DEFINE_RES_IRQ(IRQ_ASIX),
};
static struct platform_device anubis_device_asix = {
@@ -323,21 +295,9 @@ static struct platform_device anubis_device_asix = {
/* SM501 */
static struct resource anubis_sm501_resource[] = {
- [0] = {
- .start = S3C2410_CS2,
- .end = S3C2410_CS2 + SZ_8M,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = S3C2410_CS2 + SZ_64M - SZ_2M,
- .end = S3C2410_CS2 + SZ_64M - 1,
- .flags = IORESOURCE_MEM,
- },
- [2] = {
- .start = IRQ_EINT0,
- .end = IRQ_EINT0,
- .flags = IORESOURCE_IRQ,
- },
+ [0] = DEFINE_RES_MEM(S3C2410_CS2, SZ_8M),
+ [1] = DEFINE_RES_MEM(S3C2410_CS2 + SZ_64M - SZ_2M, SZ_2M),
+ [2] = DEFINE_RES_IRQ(IRQ_EINT0),
};
static struct sm501_initdata anubis_sm501_initdata = {
diff --git a/arch/arm/mach-s3c24xx/mach-at2440evb.c b/arch/arm/mach-s3c24xx/mach-at2440evb.c
index d7ae49c90118..7a05abf1270b 100644
--- a/arch/arm/mach-s3c24xx/mach-at2440evb.c
+++ b/arch/arm/mach-s3c24xx/mach-at2440evb.c
@@ -118,21 +118,10 @@ static struct s3c2410_platform_nand __initdata at2440evb_nand_info = {
/* DM9000AEP 10/100 ethernet controller */
static struct resource at2440evb_dm9k_resource[] = {
- [0] = {
- .start = S3C2410_CS3,
- .end = S3C2410_CS3 + 3,
- .flags = IORESOURCE_MEM
- },
- [1] = {
- .start = S3C2410_CS3 + 4,
- .end = S3C2410_CS3 + 7,
- .flags = IORESOURCE_MEM
- },
- [2] = {
- .start = IRQ_EINT7,
- .end = IRQ_EINT7,
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
- }
+ [0] = DEFINE_RES_MEM(S3C2410_CS3, 4),
+ [1] = DEFINE_RES_MEM(S3C2410_CS3 + 4, 4),
+ [2] = DEFINE_RES_NAMED(IRQ_EINT7, 1, NULL, IORESOURCE_IRQ \
+ | IORESOURCE_IRQ_HIGHEDGE),
};
static struct dm9000_plat_data at2440evb_dm9k_pdata = {
diff --git a/arch/arm/mach-s3c24xx/mach-bast.c b/arch/arm/mach-s3c24xx/mach-bast.c
index 53219c02eca0..1cf1720682d3 100644
--- a/arch/arm/mach-s3c24xx/mach-bast.c
+++ b/arch/arm/mach-s3c24xx/mach-bast.c
@@ -310,22 +310,10 @@ static struct s3c2410_platform_nand __initdata bast_nand_info = {
/* DM9000 */
static struct resource bast_dm9k_resource[] = {
- [0] = {
- .start = S3C2410_CS5 + BAST_PA_DM9000,
- .end = S3C2410_CS5 + BAST_PA_DM9000 + 3,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = S3C2410_CS5 + BAST_PA_DM9000 + 0x40,
- .end = S3C2410_CS5 + BAST_PA_DM9000 + 0x40 + 0x3f,
- .flags = IORESOURCE_MEM,
- },
- [2] = {
- .start = IRQ_DM9000,
- .end = IRQ_DM9000,
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
- }
-
+ [0] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_DM9000, 4),
+ [1] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_DM9000 + 0x40, 0x40),
+ [2] = DEFINE_RES_NAMED(IRQ_DM9000 , 1, NULL, IORESOURCE_IRQ \
+ | IORESOURCE_IRQ_HIGHLEVEL),
};
/* for the moment we limit ourselves to 16bit IO until some
@@ -400,21 +388,9 @@ static struct ax_plat_data bast_asix_platdata = {
};
static struct resource bast_asix_resource[] = {
- [0] = {
- .start = S3C2410_CS5 + BAST_PA_ASIXNET,
- .end = S3C2410_CS5 + BAST_PA_ASIXNET + (0x18 * 0x20) - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1f * 0x20),
- .end = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1f * 0x20),
- .flags = IORESOURCE_MEM,
- },
- [2] = {
- .start = IRQ_ASIX,
- .end = IRQ_ASIX,
- .flags = IORESOURCE_IRQ
- }
+ [0] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_ASIXNET, 0x18 * 0x20),
+ [1] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_ASIXNET + (0x1f * 0x20), 1),
+ [2] = DEFINE_RES_IRQ(IRQ_ASIX),
};
static struct platform_device bast_device_asix = {
@@ -430,11 +406,8 @@ static struct platform_device bast_device_asix = {
/* Asix AX88796 10/100 ethernet controller parallel port */
static struct resource bast_asixpp_resource[] = {
- [0] = {
- .start = S3C2410_CS5 + BAST_PA_ASIXNET + (0x18 * 0x20),
- .end = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1b * 0x20) - 1,
- .flags = IORESOURCE_MEM,
- }
+ [0] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_ASIXNET + (0x18 * 0x20), \
+ 0x30 * 0x20),
};
static struct platform_device bast_device_axpp = {
diff --git a/arch/arm/mach-s3c24xx/mach-gta02.c b/arch/arm/mach-s3c24xx/mach-gta02.c
index ba5d85394105..0f29f64a3eeb 100644
--- a/arch/arm/mach-s3c24xx/mach-gta02.c
+++ b/arch/arm/mach-s3c24xx/mach-gta02.c
@@ -387,11 +387,8 @@ static struct physmap_flash_data gta02_nor_flash_data = {
.width = 2,
};
-static struct resource gta02_nor_flash_resource = {
- .start = GTA02_FLASH_BASE,
- .end = GTA02_FLASH_BASE + GTA02_FLASH_SIZE - 1,
- .flags = IORESOURCE_MEM,
-};
+static struct resource gta02_nor_flash_resource =
+ DEFINE_RES_MEM(GTA02_FLASH_BASE, GTA02_FLASH_SIZE);
static struct platform_device gta02_nor_flash = {
.name = "physmap-flash",
diff --git a/arch/arm/mach-s3c24xx/mach-h1940.c b/arch/arm/mach-s3c24xx/mach-h1940.c
index 6b21ba107eab..bb8d008d5a5c 100644
--- a/arch/arm/mach-s3c24xx/mach-h1940.c
+++ b/arch/arm/mach-s3c24xx/mach-h1940.c
@@ -253,13 +253,8 @@ static struct pda_power_pdata power_supply_info = {
};
static struct resource power_supply_resources[] = {
- [0] = {
- .name = "ac",
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE |
- IORESOURCE_IRQ_HIGHEDGE,
- .start = IRQ_EINT2,
- .end = IRQ_EINT2,
- },
+ [0] = DEFINE_RES_NAMED(IRQ_EINT2, 1, "ac", IORESOURCE_IRQ \
+ | IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE),
};
static struct platform_device power_supply = {
diff --git a/arch/arm/mach-s3c24xx/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c
index 5d66fb218a41..f092b188ab70 100644
--- a/arch/arm/mach-s3c24xx/mach-mini2440.c
+++ b/arch/arm/mach-s3c24xx/mach-mini2440.c
@@ -292,21 +292,10 @@ static struct s3c2410_platform_nand mini2440_nand_info __initdata = {
/* DM9000AEP 10/100 ethernet controller */
static struct resource mini2440_dm9k_resource[] = {
- [0] = {
- .start = MACH_MINI2440_DM9K_BASE,
- .end = MACH_MINI2440_DM9K_BASE + 3,
- .flags = IORESOURCE_MEM
- },
- [1] = {
- .start = MACH_MINI2440_DM9K_BASE + 4,
- .end = MACH_MINI2440_DM9K_BASE + 7,
- .flags = IORESOURCE_MEM
- },
- [2] = {
- .start = IRQ_EINT7,
- .end = IRQ_EINT7,
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
- }
+ [0] = DEFINE_RES_MEM(MACH_MINI2440_DM9K_BASE, 4),
+ [1] = DEFINE_RES_MEM(MACH_MINI2440_DM9K_BASE + 4, 4),
+ [2] = DEFINE_RES_NAMED(IRQ_EINT7, 1, NULL, IORESOURCE_IRQ \
+ | IORESOURCE_IRQ_HIGHEDGE),
};
/*
diff --git a/arch/arm/mach-s3c24xx/mach-nexcoder.c b/arch/arm/mach-s3c24xx/mach-nexcoder.c
index 5198e3e1c5be..5c05ba1c330f 100644
--- a/arch/arm/mach-s3c24xx/mach-nexcoder.c
+++ b/arch/arm/mach-s3c24xx/mach-nexcoder.c
@@ -84,11 +84,7 @@ static struct s3c2410_uartcfg nexcoder_uartcfgs[] __initdata = {
/* NOR Flash on NexVision NexCoder 2440 board */
static struct resource nexcoder_nor_resource[] = {
- [0] = {
- .start = S3C2410_CS0,
- .end = S3C2410_CS0 + (8*1024*1024) - 1,
- .flags = IORESOURCE_MEM,
- }
+ [0] = DEFINE_RES_MEM(S3C2410_CS0, SZ_8M),
};
static struct map_info nexcoder_nor_map = {
diff --git a/arch/arm/mach-s3c24xx/mach-osiris.c b/arch/arm/mach-s3c24xx/mach-osiris.c
index c5daeb612a88..95d077255024 100644
--- a/arch/arm/mach-s3c24xx/mach-osiris.c
+++ b/arch/arm/mach-s3c24xx/mach-osiris.c
@@ -244,16 +244,8 @@ static struct s3c2410_platform_nand __initdata osiris_nand_info = {
/* PCMCIA control and configuration */
static struct resource osiris_pcmcia_resource[] = {
- [0] = {
- .start = 0x0f000000,
- .end = 0x0f100000,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = 0x0c000000,
- .end = 0x0c100000,
- .flags = IORESOURCE_MEM,
- }
+ [0] = DEFINE_RES_MEM(0x0f000000, SZ_1M),
+ [1] = DEFINE_RES_MEM(0x0c000000, SZ_1M),
};
static struct platform_device osiris_pcmcia = {
diff --git a/arch/arm/mach-s3c24xx/mach-otom.c b/arch/arm/mach-s3c24xx/mach-otom.c
index 5f1e0eeb38a9..bc4b6efb3b27 100644
--- a/arch/arm/mach-s3c24xx/mach-otom.c
+++ b/arch/arm/mach-s3c24xx/mach-otom.c
@@ -77,11 +77,7 @@ static struct s3c2410_uartcfg otom11_uartcfgs[] __initdata = {
/* NOR Flash on NexVision OTOM board */
static struct resource otom_nor_resource[] = {
- [0] = {
- .start = S3C2410_CS0,
- .end = S3C2410_CS0 + (4*1024*1024) - 1,
- .flags = IORESOURCE_MEM,
- }
+ [0] = DEFINE_RES_MEM(S3C2410_CS0, SZ_4M),
};
static struct platform_device otom_device_nor = {
diff --git a/arch/arm/mach-s3c24xx/mach-qt2410.c b/arch/arm/mach-s3c24xx/mach-qt2410.c
index 91c16d9d2459..b868dddcb836 100644
--- a/arch/arm/mach-s3c24xx/mach-qt2410.c
+++ b/arch/arm/mach-s3c24xx/mach-qt2410.c
@@ -180,16 +180,8 @@ static struct s3c2410fb_mach_info qt2410_fb_info __initdata = {
/* CS8900 */
static struct resource qt2410_cs89x0_resources[] = {
- [0] = {
- .start = 0x19000000,
- .end = 0x19000000 + 16,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_EINT9,
- .end = IRQ_EINT9,
- .flags = IORESOURCE_IRQ,
- },
+ [0] = DEFINE_RES_MEM(0x19000000, 17),
+ [1] = DEFINE_RES_IRQ(IRQ_EINT9),
};
static struct platform_device qt2410_cs89x0 = {
diff --git a/arch/arm/mach-s3c24xx/mach-rx1950.c b/arch/arm/mach-s3c24xx/mach-rx1950.c
index 200debb4c72d..a6762aae4727 100644
--- a/arch/arm/mach-s3c24xx/mach-rx1950.c
+++ b/arch/arm/mach-s3c24xx/mach-rx1950.c
@@ -152,13 +152,8 @@ static struct pda_power_pdata power_supply_info = {
};
static struct resource power_supply_resources[] = {
- [0] = {
- .name = "ac",
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE |
- IORESOURCE_IRQ_HIGHEDGE,
- .start = IRQ_EINT2,
- .end = IRQ_EINT2,
- },
+ [0] = DEFINE_RES_NAMED(IRQ_EINT2, 1, "ac", IORESOURCE_IRQ \
+ | IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE),
};
static struct platform_device power_supply = {
diff --git a/arch/arm/mach-s3c24xx/mach-tct_hammer.c b/arch/arm/mach-s3c24xx/mach-tct_hammer.c
index 1114666f0efb..fe990289ee7d 100644
--- a/arch/arm/mach-s3c24xx/mach-tct_hammer.c
+++ b/arch/arm/mach-s3c24xx/mach-tct_hammer.c
@@ -56,11 +56,8 @@
#include "common.h"
-static struct resource tct_hammer_nor_resource = {
- .start = 0x00000000,
- .end = 0x01000000 - 1,
- .flags = IORESOURCE_MEM,
-};
+static struct resource tct_hammer_nor_resource =
+ DEFINE_RES_MEM(0x00000000, SZ_16M);
static struct mtd_partition tct_hammer_mtd_partitions[] = {
{
diff --git a/arch/arm/mach-s3c24xx/mach-vr1000.c b/arch/arm/mach-s3c24xx/mach-vr1000.c
index 87608d45dac4..bd5f189f0424 100644
--- a/arch/arm/mach-s3c24xx/mach-vr1000.c
+++ b/arch/arm/mach-s3c24xx/mach-vr1000.c
@@ -187,40 +187,17 @@ static struct platform_device serial_device = {
/* DM9000 ethernet devices */
static struct resource vr1000_dm9k0_resource[] = {
- [0] = {
- .start = S3C2410_CS5 + VR1000_PA_DM9000,
- .end = S3C2410_CS5 + VR1000_PA_DM9000 + 3,
- .flags = IORESOURCE_MEM
- },
- [1] = {
- .start = S3C2410_CS5 + VR1000_PA_DM9000 + 0x40,
- .end = S3C2410_CS5 + VR1000_PA_DM9000 + 0x7f,
- .flags = IORESOURCE_MEM
- },
- [2] = {
- .start = IRQ_VR1000_DM9000A,
- .end = IRQ_VR1000_DM9000A,
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
- }
-
+ [0] = DEFINE_RES_MEM(S3C2410_CS5 + VR1000_PA_DM9000, 4),
+ [1] = DEFINE_RES_MEM(S3C2410_CS5 + VR1000_PA_DM9000 + 0x40, 0x40),
+ [2] = DEFINE_RES_NAMED(IRQ_VR1000_DM9000A, 1, NULL, IORESOURCE_IRQ \
+ | IORESOURCE_IRQ_HIGHLEVEL),
};
static struct resource vr1000_dm9k1_resource[] = {
- [0] = {
- .start = S3C2410_CS5 + VR1000_PA_DM9000 + 0x80,
- .end = S3C2410_CS5 + VR1000_PA_DM9000 + 0x83,
- .flags = IORESOURCE_MEM
- },
- [1] = {
- .start = S3C2410_CS5 + VR1000_PA_DM9000 + 0xC0,
- .end = S3C2410_CS5 + VR1000_PA_DM9000 + 0xFF,
- .flags = IORESOURCE_MEM
- },
- [2] = {
- .start = IRQ_VR1000_DM9000N,
- .end = IRQ_VR1000_DM9000N,
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
- }
+ [0] = DEFINE_RES_MEM(S3C2410_CS5 + VR1000_PA_DM9000 + 0x80, 4),
+ [1] = DEFINE_RES_MEM(S3C2410_CS5 + VR1000_PA_DM9000 + 0xC0, 0x40),
+ [2] = DEFINE_RES_NAMED(IRQ_VR1000_DM9000N, 1, NULL, IORESOURCE_IRQ \
+ | IORESOURCE_IRQ_HIGHLEVEL),
};
/* for the moment we limit ourselves to 16bit IO until some
diff --git a/arch/arm/mach-s3c24xx/simtec-nor.c b/arch/arm/mach-s3c24xx/simtec-nor.c
index b9d6d4f92c03..029744fcaacb 100644
--- a/arch/arm/mach-s3c24xx/simtec-nor.c
+++ b/arch/arm/mach-s3c24xx/simtec-nor.c
@@ -55,11 +55,7 @@ static struct physmap_flash_data simtec_nor_pdata = {
};
static struct resource simtec_nor_resource[] = {
- [0] = {
- .start = S3C2410_CS1 + 0x4000000,
- .end = S3C2410_CS1 + 0x4000000 + SZ_8M - 1,
- .flags = IORESOURCE_MEM,
- }
+ [0] = DEFINE_RES_MEM(S3C2410_CS1 + 0x4000000, SZ_8M),
};
static struct platform_device simtec_device_nor = {
diff --git a/arch/arm/mach-s3c64xx/Kconfig b/arch/arm/mach-s3c64xx/Kconfig
index 82c0915729ee..06ca1cd4cae2 100644
--- a/arch/arm/mach-s3c64xx/Kconfig
+++ b/arch/arm/mach-s3c64xx/Kconfig
@@ -210,7 +210,7 @@ config SMDK6410_WM1190_EV1
and audio daughtercard for the Samsung SMDK6410 reference
platform. Enabling this option will build support for this
module into the kernel. The presence of the module will be
- detected at runtime so the the resulting kernel can be used
+ detected at runtime so the resulting kernel can be used
with or without the 1190-EV1 fitted.
config SMDK6410_WM1192_EV1
@@ -226,7 +226,7 @@ config SMDK6410_WM1192_EV1
daughtercard for the Samsung SMDK6410 reference platform.
Enabling this option will build support for this module into
the kernel. The presence of the daughtercard will be
- detected at runtime so the the resulting kernel can be used
+ detected at runtime so the resulting kernel can be used
with or without the 1192-EV1 fitted.
config MACH_NCP
diff --git a/arch/arm/mach-s3c64xx/dev-audio.c b/arch/arm/mach-s3c64xx/dev-audio.c
index 93470b158a4e..124fd5d63006 100644
--- a/arch/arm/mach-s3c64xx/dev-audio.c
+++ b/arch/arm/mach-s3c64xx/dev-audio.c
@@ -57,21 +57,9 @@ static int s3c64xx_i2s_cfg_gpio(struct platform_device *pdev)
}
static struct resource s3c64xx_iis0_resource[] = {
- [0] = {
- .start = S3C64XX_PA_IIS0,
- .end = S3C64XX_PA_IIS0 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_I2S0_OUT,
- .end = DMACH_I2S0_OUT,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_I2S0_IN,
- .end = DMACH_I2S0_IN,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(S3C64XX_PA_IIS0, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_I2S0_OUT),
+ [2] = DEFINE_RES_DMA(DMACH_I2S0_IN),
};
static struct s3c_audio_pdata i2sv3_pdata = {
@@ -95,21 +83,9 @@ struct platform_device s3c64xx_device_iis0 = {
EXPORT_SYMBOL(s3c64xx_device_iis0);
static struct resource s3c64xx_iis1_resource[] = {
- [0] = {
- .start = S3C64XX_PA_IIS1,
- .end = S3C64XX_PA_IIS1 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_I2S1_OUT,
- .end = DMACH_I2S1_OUT,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_I2S1_IN,
- .end = DMACH_I2S1_IN,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(S3C64XX_PA_IIS1, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_I2S1_OUT),
+ [2] = DEFINE_RES_DMA(DMACH_I2S1_IN),
};
struct platform_device s3c64xx_device_iis1 = {
@@ -124,21 +100,9 @@ struct platform_device s3c64xx_device_iis1 = {
EXPORT_SYMBOL(s3c64xx_device_iis1);
static struct resource s3c64xx_iisv4_resource[] = {
- [0] = {
- .start = S3C64XX_PA_IISV4,
- .end = S3C64XX_PA_IISV4 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_HSI_I2SV40_TX,
- .end = DMACH_HSI_I2SV40_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_HSI_I2SV40_RX,
- .end = DMACH_HSI_I2SV40_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(S3C64XX_PA_IISV4, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_HSI_I2SV40_TX),
+ [2] = DEFINE_RES_DMA(DMACH_HSI_I2SV40_RX),
};
static struct s3c_audio_pdata i2sv4_pdata = {
@@ -187,21 +151,9 @@ static int s3c64xx_pcm_cfg_gpio(struct platform_device *pdev)
}
static struct resource s3c64xx_pcm0_resource[] = {
- [0] = {
- .start = S3C64XX_PA_PCM0,
- .end = S3C64XX_PA_PCM0 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_PCM0_TX,
- .end = DMACH_PCM0_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_PCM0_RX,
- .end = DMACH_PCM0_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(S3C64XX_PA_PCM0, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_PCM0_TX),
+ [2] = DEFINE_RES_DMA(DMACH_PCM0_RX),
};
static struct s3c_audio_pdata s3c_pcm0_pdata = {
@@ -220,21 +172,9 @@ struct platform_device s3c64xx_device_pcm0 = {
EXPORT_SYMBOL(s3c64xx_device_pcm0);
static struct resource s3c64xx_pcm1_resource[] = {
- [0] = {
- .start = S3C64XX_PA_PCM1,
- .end = S3C64XX_PA_PCM1 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_PCM1_TX,
- .end = DMACH_PCM1_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_PCM1_RX,
- .end = DMACH_PCM1_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(S3C64XX_PA_PCM1, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_PCM1_TX),
+ [2] = DEFINE_RES_DMA(DMACH_PCM1_RX),
};
static struct s3c_audio_pdata s3c_pcm1_pdata = {
@@ -265,31 +205,11 @@ static int s3c64xx_ac97_cfg_gpe(struct platform_device *pdev)
}
static struct resource s3c64xx_ac97_resource[] = {
- [0] = {
- .start = S3C64XX_PA_AC97,
- .end = S3C64XX_PA_AC97 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_AC97_PCMOUT,
- .end = DMACH_AC97_PCMOUT,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_AC97_PCMIN,
- .end = DMACH_AC97_PCMIN,
- .flags = IORESOURCE_DMA,
- },
- [3] = {
- .start = DMACH_AC97_MICIN,
- .end = DMACH_AC97_MICIN,
- .flags = IORESOURCE_DMA,
- },
- [4] = {
- .start = IRQ_AC97,
- .end = IRQ_AC97,
- .flags = IORESOURCE_IRQ,
- },
+ [0] = DEFINE_RES_MEM(S3C64XX_PA_AC97, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_AC97_PCMOUT),
+ [2] = DEFINE_RES_DMA(DMACH_AC97_PCMIN),
+ [3] = DEFINE_RES_DMA(DMACH_AC97_MICIN),
+ [4] = DEFINE_RES_IRQ(IRQ_AC97),
};
static struct s3c_audio_pdata s3c_ac97_pdata;
diff --git a/arch/arm/mach-s3c64xx/dev-uart.c b/arch/arm/mach-s3c64xx/dev-uart.c
index c681b99eda08..46e18d77ea93 100644
--- a/arch/arm/mach-s3c64xx/dev-uart.c
+++ b/arch/arm/mach-s3c64xx/dev-uart.c
@@ -31,55 +31,23 @@
/* 64xx uarts are closer together */
static struct resource s3c64xx_uart0_resource[] = {
- [0] = {
- .start = S3C_PA_UART0,
- .end = S3C_PA_UART0 + 0x100,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_UART0,
- .end = IRQ_UART0,
- .flags = IORESOURCE_IRQ,
- },
+ [0] = DEFINE_RES_MEM(S3C_PA_UART0, SZ_256),
+ [1] = DEFINE_RES_IRQ(IRQ_UART0),
};
static struct resource s3c64xx_uart1_resource[] = {
- [0] = {
- .start = S3C_PA_UART1,
- .end = S3C_PA_UART1 + 0x100,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_UART1,
- .end = IRQ_UART1,
- .flags = IORESOURCE_IRQ,
- },
+ [0] = DEFINE_RES_MEM(S3C_PA_UART1, SZ_256),
+ [1] = DEFINE_RES_IRQ(IRQ_UART1),
};
static struct resource s3c6xx_uart2_resource[] = {
- [0] = {
- .start = S3C_PA_UART2,
- .end = S3C_PA_UART2 + 0x100,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_UART2,
- .end = IRQ_UART2,
- .flags = IORESOURCE_IRQ,
- },
+ [0] = DEFINE_RES_MEM(S3C_PA_UART2, SZ_256),
+ [1] = DEFINE_RES_IRQ(IRQ_UART2),
};
static struct resource s3c64xx_uart3_resource[] = {
- [0] = {
- .start = S3C_PA_UART3,
- .end = S3C_PA_UART3 + 0x100,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_UART3,
- .end = IRQ_UART3,
- .flags = IORESOURCE_IRQ,
- },
+ [0] = DEFINE_RES_MEM(S3C_PA_UART3, SZ_256),
+ [1] = DEFINE_RES_IRQ(IRQ_UART3),
};
diff --git a/arch/arm/mach-s3c64xx/mach-anw6410.c b/arch/arm/mach-s3c64xx/mach-anw6410.c
index b86f2779e4e6..f252691fb209 100644
--- a/arch/arm/mach-s3c64xx/mach-anw6410.c
+++ b/arch/arm/mach-s3c64xx/mach-anw6410.c
@@ -165,21 +165,10 @@ static void __init anw6410_dm9000_enable(void)
}
static struct resource anw6410_dm9000_resource[] = {
- [0] = {
- .start = ANW6410_PA_DM9000,
- .end = ANW6410_PA_DM9000 + 3,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = ANW6410_PA_DM9000 + 4,
- .end = ANW6410_PA_DM9000 + 4 + 500,
- .flags = IORESOURCE_MEM,
- },
- [2] = {
- .start = IRQ_EINT(15),
- .end = IRQ_EINT(15),
- .flags = IORESOURCE_IRQ | IRQF_TRIGGER_HIGH,
- },
+ [0] = DEFINE_RES_MEM(ANW6410_PA_DM9000, 4),
+ [1] = DEFINE_RES_MEM(ANW6410_PA_DM9000 + 4, 501),
+ [2] = DEFINE_RES_NAMED(IRQ_EINT(15), 1, NULL, IORESOURCE_IRQ \
+ | IRQF_TRIGGER_HIGH),
};
static struct dm9000_plat_data anw6410_dm9000_pdata = {
diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c
index e20bf5835365..aa1137fb47e6 100644
--- a/arch/arm/mach-s3c64xx/mach-crag6410.c
+++ b/arch/arm/mach-s3c64xx/mach-crag6410.c
@@ -31,6 +31,7 @@
#include <linux/spi/spi.h>
#include <linux/i2c/pca953x.h>
+#include <linux/platform_data/s3c-hsotg.h>
#include <video/platform_lcd.h>
@@ -61,7 +62,6 @@
#include <plat/sdhci.h>
#include <plat/gpio-cfg.h>
#include <plat/s3c64xx-spi.h>
-#include <plat/udc-hs.h>
#include <plat/keypad.h>
#include <plat/clock.h>
@@ -232,21 +232,10 @@ static struct platform_device crag6410_gpio_keydev = {
};
static struct resource crag6410_dm9k_resource[] = {
- [0] = {
- .start = S3C64XX_PA_XM0CSN5,
- .end = S3C64XX_PA_XM0CSN5 + 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = S3C64XX_PA_XM0CSN5 + (1 << 8),
- .end = S3C64XX_PA_XM0CSN5 + (1 << 8) + 1,
- .flags = IORESOURCE_MEM,
- },
- [2] = {
- .start = S3C_EINT(17),
- .end = S3C_EINT(17),
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
- },
+ [0] = DEFINE_RES_MEM(S3C64XX_PA_XM0CSN5, 2),
+ [1] = DEFINE_RES_MEM(S3C64XX_PA_XM0CSN5 + (1 << 8), 2),
+ [2] = DEFINE_RES_NAMED(S3C_EINT(17), 1, NULL, IORESOURCE_IRQ \
+ | IORESOURCE_IRQ_HIGHLEVEL),
};
static struct dm9000_plat_data mini6410_dm9k_pdata = {
@@ -262,12 +251,7 @@ static struct platform_device crag6410_dm9k_device = {
};
static struct resource crag6410_mmgpio_resource[] = {
- [0] = {
- .name = "dat",
- .start = S3C64XX_PA_XM0CSN4 + 1,
- .end = S3C64XX_PA_XM0CSN4 + 1,
- .flags = IORESOURCE_MEM,
- },
+ [0] = DEFINE_RES_MEM_NAMED(S3C64XX_PA_XM0CSN4, 1, "dat"),
};
static struct platform_device crag6410_mmgpio = {
@@ -306,6 +290,24 @@ static struct regulator_consumer_supply wallvdd_consumers[] = {
REGULATOR_SUPPLY("SPKVDD2", "1-001a"),
REGULATOR_SUPPLY("SPKVDDL", "1-001a"),
REGULATOR_SUPPLY("SPKVDDR", "1-001a"),
+
+ REGULATOR_SUPPLY("DC1VDD", "0-0034"),
+ REGULATOR_SUPPLY("DC2VDD", "0-0034"),
+ REGULATOR_SUPPLY("DC3VDD", "0-0034"),
+ REGULATOR_SUPPLY("LDO1VDD", "0-0034"),
+ REGULATOR_SUPPLY("LDO2VDD", "0-0034"),
+ REGULATOR_SUPPLY("LDO4VDD", "0-0034"),
+ REGULATOR_SUPPLY("LDO5VDD", "0-0034"),
+ REGULATOR_SUPPLY("LDO6VDD", "0-0034"),
+ REGULATOR_SUPPLY("LDO7VDD", "0-0034"),
+ REGULATOR_SUPPLY("LDO8VDD", "0-0034"),
+ REGULATOR_SUPPLY("LDO9VDD", "0-0034"),
+ REGULATOR_SUPPLY("LDO10VDD", "0-0034"),
+ REGULATOR_SUPPLY("LDO11VDD", "0-0034"),
+
+ REGULATOR_SUPPLY("DC1VDD", "1-0034"),
+ REGULATOR_SUPPLY("DC2VDD", "1-0034"),
+ REGULATOR_SUPPLY("DC3VDD", "1-0034"),
};
static struct regulator_init_data wallvdd_data = {
diff --git a/arch/arm/mach-s3c64xx/mach-mini6410.c b/arch/arm/mach-s3c64xx/mach-mini6410.c
index c34c2ab22ead..b2166d4a5538 100644
--- a/arch/arm/mach-s3c64xx/mach-mini6410.c
+++ b/arch/arm/mach-s3c64xx/mach-mini6410.c
@@ -85,21 +85,10 @@ static struct s3c2410_uartcfg mini6410_uartcfgs[] __initdata = {
/* DM9000AEP 10/100 ethernet controller */
static struct resource mini6410_dm9k_resource[] = {
- [0] = {
- .start = S3C64XX_PA_XM0CSN1,
- .end = S3C64XX_PA_XM0CSN1 + 1,
- .flags = IORESOURCE_MEM
- },
- [1] = {
- .start = S3C64XX_PA_XM0CSN1 + 4,
- .end = S3C64XX_PA_XM0CSN1 + 5,
- .flags = IORESOURCE_MEM
- },
- [2] = {
- .start = S3C_EINT(7),
- .end = S3C_EINT(7),
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL
- }
+ [0] = DEFINE_RES_MEM(S3C64XX_PA_XM0CSN1, 2),
+ [1] = DEFINE_RES_MEM(S3C64XX_PA_XM0CSN1 + 4, 2),
+ [2] = DEFINE_RES_NAMED(S3C_EINT(7), 1, NULL, IORESOURCE_IRQ \
+ | IORESOURCE_IRQ_HIGHLEVEL),
};
static struct dm9000_plat_data mini6410_dm9k_pdata = {
diff --git a/arch/arm/mach-s3c64xx/mach-real6410.c b/arch/arm/mach-s3c64xx/mach-real6410.c
index be2a9a22ab74..5c08266cea21 100644
--- a/arch/arm/mach-s3c64xx/mach-real6410.c
+++ b/arch/arm/mach-s3c64xx/mach-real6410.c
@@ -86,21 +86,10 @@ static struct s3c2410_uartcfg real6410_uartcfgs[] __initdata = {
/* DM9000AEP 10/100 ethernet controller */
static struct resource real6410_dm9k_resource[] = {
- [0] = {
- .start = S3C64XX_PA_XM0CSN1,
- .end = S3C64XX_PA_XM0CSN1 + 1,
- .flags = IORESOURCE_MEM
- },
- [1] = {
- .start = S3C64XX_PA_XM0CSN1 + 4,
- .end = S3C64XX_PA_XM0CSN1 + 5,
- .flags = IORESOURCE_MEM
- },
- [2] = {
- .start = S3C_EINT(7),
- .end = S3C_EINT(7),
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL
- }
+ [0] = DEFINE_RES_MEM(S3C64XX_PA_XM0CSN1, 2),
+ [1] = DEFINE_RES_MEM(S3C64XX_PA_XM0CSN1 + 4, 2),
+ [2] = DEFINE_RES_NAMED(S3C_EINT(7), 1, NULL, IORESOURCE_IRQ \
+ | IORESOURCE_IRQ_HIGHLEVEL),
};
static struct dm9000_plat_data real6410_dm9k_pdata = {
diff --git a/arch/arm/mach-s3c64xx/mach-smartq.c b/arch/arm/mach-s3c64xx/mach-smartq.c
index ce745e19aa27..ceeb1de40376 100644
--- a/arch/arm/mach-s3c64xx/mach-smartq.c
+++ b/arch/arm/mach-s3c64xx/mach-smartq.c
@@ -18,6 +18,7 @@
#include <linux/serial_core.h>
#include <linux/spi/spi_gpio.h>
#include <linux/usb/gpio_vbus.h>
+#include <linux/platform_data/s3c-hsotg.h>
#include <asm/mach-types.h>
#include <asm/mach/map.h>
@@ -33,7 +34,6 @@
#include <plat/gpio-cfg.h>
#include <plat/hwmon.h>
#include <plat/regs-serial.h>
-#include <plat/udc-hs.h>
#include <plat/usb-control.h>
#include <plat/sdhci.h>
#include <plat/ts.h>
diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c
index d55bc96d9582..7da044f738ac 100644
--- a/arch/arm/mach-s3c64xx/mach-smdk6410.c
+++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c
@@ -30,6 +30,7 @@
#include <linux/regulator/fixed.h>
#include <linux/regulator/machine.h>
#include <linux/pwm_backlight.h>
+#include <linux/platform_data/s3c-hsotg.h>
#ifdef CONFIG_SMDK6410_WM1190_EV1
#include <linux/mfd/wm8350/core.h>
@@ -72,7 +73,6 @@
#include <plat/keypad.h>
#include <plat/backlight.h>
#include <plat/regs-fb-v4.h>
-#include <plat/udc-hs.h>
#include "common.h"
@@ -182,16 +182,9 @@ static struct s3c_fb_platdata smdk6410_lcd_pdata __initdata = {
*/
static struct resource smdk6410_smsc911x_resources[] = {
- [0] = {
- .start = S3C64XX_PA_XM0CSN1,
- .end = S3C64XX_PA_XM0CSN1 + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = S3C_EINT(10),
- .end = S3C_EINT(10),
- .flags = IORESOURCE_IRQ | IRQ_TYPE_LEVEL_LOW,
- },
+ [0] = DEFINE_RES_MEM(S3C64XX_PA_XM0CSN1, SZ_64K),
+ [1] = DEFINE_RES_NAMED(S3C_EINT(10), 1, NULL, IORESOURCE_IRQ \
+ | IRQ_TYPE_LEVEL_LOW),
};
static struct smsc911x_platform_config smdk6410_smsc911x_pdata = {
diff --git a/arch/arm/mach-s5p64x0/dev-audio.c b/arch/arm/mach-s5p64x0/dev-audio.c
index 35f1f226dabb..91113ddc51da 100644
--- a/arch/arm/mach-s5p64x0/dev-audio.c
+++ b/arch/arm/mach-s5p64x0/dev-audio.c
@@ -51,21 +51,9 @@ static struct s3c_audio_pdata s5p6440_i2s_pdata = {
};
static struct resource s5p64x0_i2s0_resource[] = {
- [0] = {
- .start = S5P64X0_PA_I2S,
- .end = S5P64X0_PA_I2S + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_I2S0_TX,
- .end = DMACH_I2S0_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_I2S0_RX,
- .end = DMACH_I2S0_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(S5P64X0_PA_I2S, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_I2S0_TX),
+ [2] = DEFINE_RES_DMA(DMACH_I2S0_RX),
};
struct platform_device s5p6440_device_iis = {
@@ -130,21 +118,9 @@ static struct s3c_audio_pdata s5p6450_i2s_pdata = {
};
static struct resource s5p6450_i2s1_resource[] = {
- [0] = {
- .start = S5P6450_PA_I2S1,
- .end = S5P6450_PA_I2S1 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_I2S1_TX,
- .end = DMACH_I2S1_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_I2S1_RX,
- .end = DMACH_I2S1_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(S5P6450_PA_I2S1, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_I2S1_TX),
+ [2] = DEFINE_RES_DMA(DMACH_I2S1_RX),
};
struct platform_device s5p6450_device_iis1 = {
@@ -158,21 +134,9 @@ struct platform_device s5p6450_device_iis1 = {
};
static struct resource s5p6450_i2s2_resource[] = {
- [0] = {
- .start = S5P6450_PA_I2S2,
- .end = S5P6450_PA_I2S2 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_I2S2_TX,
- .end = DMACH_I2S2_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_I2S2_RX,
- .end = DMACH_I2S2_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(S5P6450_PA_I2S2, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_I2S2_TX),
+ [2] = DEFINE_RES_DMA(DMACH_I2S2_RX),
};
struct platform_device s5p6450_device_iis2 = {
@@ -208,21 +172,9 @@ static struct s3c_audio_pdata s5p6440_pcm_pdata = {
};
static struct resource s5p6440_pcm0_resource[] = {
- [0] = {
- .start = S5P64X0_PA_PCM,
- .end = S5P64X0_PA_PCM + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_PCM0_TX,
- .end = DMACH_PCM0_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_PCM0_RX,
- .end = DMACH_PCM0_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(S5P64X0_PA_PCM, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_PCM0_TX),
+ [2] = DEFINE_RES_DMA(DMACH_PCM0_RX),
};
struct platform_device s5p6440_device_pcm = {
diff --git a/arch/arm/mach-s5pc100/dev-audio.c b/arch/arm/mach-s5pc100/dev-audio.c
index ab2d27172cbc..9d4bde3f1110 100644
--- a/arch/arm/mach-s5pc100/dev-audio.c
+++ b/arch/arm/mach-s5pc100/dev-audio.c
@@ -56,26 +56,10 @@ static struct s3c_audio_pdata i2sv5_pdata = {
};
static struct resource s5pc100_iis0_resource[] = {
- [0] = {
- .start = S5PC100_PA_I2S0,
- .end = S5PC100_PA_I2S0 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_I2S0_TX,
- .end = DMACH_I2S0_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_I2S0_RX,
- .end = DMACH_I2S0_RX,
- .flags = IORESOURCE_DMA,
- },
- [3] = {
- .start = DMACH_I2S0S_TX,
- .end = DMACH_I2S0S_TX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(S5PC100_PA_I2S0, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_I2S0_TX),
+ [2] = DEFINE_RES_DMA(DMACH_I2S0_RX),
+ [3] = DEFINE_RES_DMA(DMACH_I2S0S_TX),
};
struct platform_device s5pc100_device_iis0 = {
@@ -103,21 +87,9 @@ static struct s3c_audio_pdata i2sv3_pdata = {
};
static struct resource s5pc100_iis1_resource[] = {
- [0] = {
- .start = S5PC100_PA_I2S1,
- .end = S5PC100_PA_I2S1 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_I2S1_TX,
- .end = DMACH_I2S1_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_I2S1_RX,
- .end = DMACH_I2S1_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(S5PC100_PA_I2S1, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_I2S1_TX),
+ [2] = DEFINE_RES_DMA(DMACH_I2S1_RX),
};
struct platform_device s5pc100_device_iis1 = {
@@ -131,21 +103,9 @@ struct platform_device s5pc100_device_iis1 = {
};
static struct resource s5pc100_iis2_resource[] = {
- [0] = {
- .start = S5PC100_PA_I2S2,
- .end = S5PC100_PA_I2S2 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_I2S2_TX,
- .end = DMACH_I2S2_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_I2S2_RX,
- .end = DMACH_I2S2_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(S5PC100_PA_I2S2, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_I2S2_TX),
+ [2] = DEFINE_RES_DMA(DMACH_I2S2_RX),
};
struct platform_device s5pc100_device_iis2 = {
@@ -184,21 +144,9 @@ static struct s3c_audio_pdata s3c_pcm_pdata = {
};
static struct resource s5pc100_pcm0_resource[] = {
- [0] = {
- .start = S5PC100_PA_PCM0,
- .end = S5PC100_PA_PCM0 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_PCM0_TX,
- .end = DMACH_PCM0_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_PCM0_RX,
- .end = DMACH_PCM0_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(S5PC100_PA_PCM0, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_PCM0_TX),
+ [2] = DEFINE_RES_DMA(DMACH_PCM0_RX),
};
struct platform_device s5pc100_device_pcm0 = {
@@ -212,21 +160,9 @@ struct platform_device s5pc100_device_pcm0 = {
};
static struct resource s5pc100_pcm1_resource[] = {
- [0] = {
- .start = S5PC100_PA_PCM1,
- .end = S5PC100_PA_PCM1 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_PCM1_TX,
- .end = DMACH_PCM1_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_PCM1_RX,
- .end = DMACH_PCM1_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(S5PC100_PA_PCM1, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_PCM1_TX),
+ [2] = DEFINE_RES_DMA(DMACH_PCM1_RX),
};
struct platform_device s5pc100_device_pcm1 = {
@@ -247,31 +183,11 @@ static int s5pc100_ac97_cfg_gpio(struct platform_device *pdev)
}
static struct resource s5pc100_ac97_resource[] = {
- [0] = {
- .start = S5PC100_PA_AC97,
- .end = S5PC100_PA_AC97 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_AC97_PCMOUT,
- .end = DMACH_AC97_PCMOUT,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_AC97_PCMIN,
- .end = DMACH_AC97_PCMIN,
- .flags = IORESOURCE_DMA,
- },
- [3] = {
- .start = DMACH_AC97_MICIN,
- .end = DMACH_AC97_MICIN,
- .flags = IORESOURCE_DMA,
- },
- [4] = {
- .start = IRQ_AC97,
- .end = IRQ_AC97,
- .flags = IORESOURCE_IRQ,
- },
+ [0] = DEFINE_RES_MEM(S5PC100_PA_AC97, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_AC97_PCMOUT),
+ [2] = DEFINE_RES_DMA(DMACH_AC97_PCMIN),
+ [3] = DEFINE_RES_DMA(DMACH_AC97_MICIN),
+ [4] = DEFINE_RES_IRQ(IRQ_AC97),
};
static struct s3c_audio_pdata s3c_ac97_pdata = {
@@ -308,16 +224,8 @@ static int s5pc100_spdif_cfg_gpg3(struct platform_device *pdev)
}
static struct resource s5pc100_spdif_resource[] = {
- [0] = {
- .start = S5PC100_PA_SPDIF,
- .end = S5PC100_PA_SPDIF + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_SPDIF,
- .end = DMACH_SPDIF,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(S5PC100_PA_SPDIF, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_SPDIF),
};
static struct s3c_audio_pdata s5p_spdif_pdata = {
diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig
index 29594fc4fdf4..88e983b0c82e 100644
--- a/arch/arm/mach-s5pv210/Kconfig
+++ b/arch/arm/mach-s5pv210/Kconfig
@@ -85,6 +85,7 @@ config MACH_AQUILA
select S5P_DEV_ONENAND
select S5PV210_SETUP_FB_24BPP
select S5PV210_SETUP_SDHCI
+ select S5PV210_SETUP_USB_PHY
help
Machine support for the Samsung Aquila target based on S5PC110 SoC
diff --git a/arch/arm/mach-s5pv210/dev-audio.c b/arch/arm/mach-s5pv210/dev-audio.c
index 63f5d82004b5..8367749c3eec 100644
--- a/arch/arm/mach-s5pv210/dev-audio.c
+++ b/arch/arm/mach-s5pv210/dev-audio.c
@@ -59,26 +59,10 @@ static struct s3c_audio_pdata i2sv5_pdata = {
};
static struct resource s5pv210_iis0_resource[] = {
- [0] = {
- .start = S5PV210_PA_IIS0,
- .end = S5PV210_PA_IIS0 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_I2S0_TX,
- .end = DMACH_I2S0_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_I2S0_RX,
- .end = DMACH_I2S0_RX,
- .flags = IORESOURCE_DMA,
- },
- [3] = {
- .start = DMACH_I2S0S_TX,
- .end = DMACH_I2S0S_TX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(S5PV210_PA_IIS0, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_I2S0_TX),
+ [2] = DEFINE_RES_DMA(DMACH_I2S0_RX),
+ [3] = DEFINE_RES_DMA(DMACH_I2S0S_TX),
};
struct platform_device s5pv210_device_iis0 = {
@@ -106,21 +90,9 @@ static struct s3c_audio_pdata i2sv3_pdata = {
};
static struct resource s5pv210_iis1_resource[] = {
- [0] = {
- .start = S5PV210_PA_IIS1,
- .end = S5PV210_PA_IIS1 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_I2S1_TX,
- .end = DMACH_I2S1_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_I2S1_RX,
- .end = DMACH_I2S1_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(S5PV210_PA_IIS1, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_I2S1_TX),
+ [2] = DEFINE_RES_DMA(DMACH_I2S1_RX),
};
struct platform_device s5pv210_device_iis1 = {
@@ -134,21 +106,9 @@ struct platform_device s5pv210_device_iis1 = {
};
static struct resource s5pv210_iis2_resource[] = {
- [0] = {
- .start = S5PV210_PA_IIS2,
- .end = S5PV210_PA_IIS2 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_I2S2_TX,
- .end = DMACH_I2S2_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_I2S2_RX,
- .end = DMACH_I2S2_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(S5PV210_PA_IIS2, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_I2S2_TX),
+ [2] = DEFINE_RES_DMA(DMACH_I2S2_RX),
};
struct platform_device s5pv210_device_iis2 = {
@@ -188,21 +148,9 @@ static struct s3c_audio_pdata s3c_pcm_pdata = {
};
static struct resource s5pv210_pcm0_resource[] = {
- [0] = {
- .start = S5PV210_PA_PCM0,
- .end = S5PV210_PA_PCM0 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_PCM0_TX,
- .end = DMACH_PCM0_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_PCM0_RX,
- .end = DMACH_PCM0_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(S5PV210_PA_PCM0, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_PCM0_TX),
+ [2] = DEFINE_RES_DMA(DMACH_PCM0_RX),
};
struct platform_device s5pv210_device_pcm0 = {
@@ -216,21 +164,9 @@ struct platform_device s5pv210_device_pcm0 = {
};
static struct resource s5pv210_pcm1_resource[] = {
- [0] = {
- .start = S5PV210_PA_PCM1,
- .end = S5PV210_PA_PCM1 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_PCM1_TX,
- .end = DMACH_PCM1_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_PCM1_RX,
- .end = DMACH_PCM1_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(S5PV210_PA_PCM1, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_PCM1_TX),
+ [2] = DEFINE_RES_DMA(DMACH_PCM1_RX),
};
struct platform_device s5pv210_device_pcm1 = {
@@ -244,21 +180,9 @@ struct platform_device s5pv210_device_pcm1 = {
};
static struct resource s5pv210_pcm2_resource[] = {
- [0] = {
- .start = S5PV210_PA_PCM2,
- .end = S5PV210_PA_PCM2 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_PCM2_TX,
- .end = DMACH_PCM2_TX,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_PCM2_RX,
- .end = DMACH_PCM2_RX,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(S5PV210_PA_PCM2, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_PCM2_TX),
+ [2] = DEFINE_RES_DMA(DMACH_PCM2_RX),
};
struct platform_device s5pv210_device_pcm2 = {
@@ -279,31 +203,11 @@ static int s5pv210_ac97_cfg_gpio(struct platform_device *pdev)
}
static struct resource s5pv210_ac97_resource[] = {
- [0] = {
- .start = S5PV210_PA_AC97,
- .end = S5PV210_PA_AC97 + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_AC97_PCMOUT,
- .end = DMACH_AC97_PCMOUT,
- .flags = IORESOURCE_DMA,
- },
- [2] = {
- .start = DMACH_AC97_PCMIN,
- .end = DMACH_AC97_PCMIN,
- .flags = IORESOURCE_DMA,
- },
- [3] = {
- .start = DMACH_AC97_MICIN,
- .end = DMACH_AC97_MICIN,
- .flags = IORESOURCE_DMA,
- },
- [4] = {
- .start = IRQ_AC97,
- .end = IRQ_AC97,
- .flags = IORESOURCE_IRQ,
- },
+ [0] = DEFINE_RES_MEM(S5PV210_PA_AC97, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_AC97_PCMOUT),
+ [2] = DEFINE_RES_DMA(DMACH_AC97_PCMIN),
+ [3] = DEFINE_RES_DMA(DMACH_AC97_MICIN),
+ [4] = DEFINE_RES_IRQ(IRQ_AC97),
};
static struct s3c_audio_pdata s3c_ac97_pdata = {
@@ -334,16 +238,8 @@ static int s5pv210_spdif_cfg_gpio(struct platform_device *pdev)
}
static struct resource s5pv210_spdif_resource[] = {
- [0] = {
- .start = S5PV210_PA_SPDIF,
- .end = S5PV210_PA_SPDIF + 0x100 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = DMACH_SPDIF,
- .end = DMACH_SPDIF,
- .flags = IORESOURCE_DMA,
- },
+ [0] = DEFINE_RES_MEM(S5PV210_PA_SPDIF, SZ_256),
+ [1] = DEFINE_RES_DMA(DMACH_SPDIF),
};
static struct s3c_audio_pdata samsung_spdif_pdata = {
diff --git a/arch/arm/mach-s5pv210/mach-goni.c b/arch/arm/mach-s5pv210/mach-goni.c
index 32395664e879..f20a97c8e411 100644
--- a/arch/arm/mach-s5pv210/mach-goni.c
+++ b/arch/arm/mach-s5pv210/mach-goni.c
@@ -27,6 +27,7 @@
#include <linux/gpio.h>
#include <linux/mmc/host.h>
#include <linux/interrupt.h>
+#include <linux/platform_data/s3c-hsotg.h>
#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
@@ -278,6 +279,9 @@ static void __init goni_tsp_init(void)
i2c2_devs[0].irq = gpio_to_irq(gpio);
}
+/* USB OTG */
+static struct s3c_hsotg_plat goni_hsotg_pdata;
+
static void goni_camera_init(void)
{
s5pv210_fimc_setup_gpio(S5P_CAMPORT_A);
@@ -941,6 +945,8 @@ static void __init goni_machine_init(void)
s3c_set_platdata(&goni_fimc_md_platdata, sizeof(goni_fimc_md_platdata),
&s5p_device_fimc_md);
+ s3c_hsotg_set_platdata(&goni_hsotg_pdata);
+
goni_camera_init();
/* SPI */
diff --git a/arch/arm/mach-s5pv210/mach-smdkv210.c b/arch/arm/mach-s5pv210/mach-smdkv210.c
index 91d4ad8bcc73..fa1b61209fd9 100644
--- a/arch/arm/mach-s5pv210/mach-smdkv210.c
+++ b/arch/arm/mach-s5pv210/mach-smdkv210.c
@@ -119,21 +119,10 @@ static struct samsung_keypad_platdata smdkv210_keypad_data __initdata = {
};
static struct resource smdkv210_dm9000_resources[] = {
- [0] = {
- .start = S5PV210_PA_SROM_BANK5,
- .end = S5PV210_PA_SROM_BANK5,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = S5PV210_PA_SROM_BANK5 + 2,
- .end = S5PV210_PA_SROM_BANK5 + 2,
- .flags = IORESOURCE_MEM,
- },
- [2] = {
- .start = IRQ_EINT(9),
- .end = IRQ_EINT(9),
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
- },
+ [0] = DEFINE_RES_MEM(S5PV210_PA_SROM_BANK5, 1),
+ [1] = DEFINE_RES_MEM(S5PV210_PA_SROM_BANK5 + 2, 1),
+ [2] = DEFINE_RES_NAMED(IRQ_EINT(9), 1, NULL, IORESOURCE_IRQ \
+ | IORESOURCE_IRQ_HIGHLEVEL),
};
static struct dm9000_plat_data smdkv210_dm9000_platdata = {
diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index 34560cab45d9..f31383c32f9c 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -41,6 +41,12 @@ config ARCH_R8A7779
select ARM_GIC
select ARCH_WANT_OPTIONAL_GPIOLIB
+config ARCH_EMEV2
+ bool "Emma Mobile EV2"
+ select CPU_V7
+ select ARM_GIC
+ select ARCH_WANT_OPTIONAL_GPIOLIB
+
comment "SH-Mobile Board Type"
config MACH_G3EVM
@@ -58,6 +64,7 @@ config MACH_AP4EVB
depends on ARCH_SH7372
select ARCH_REQUIRE_GPIOLIB
select SH_LCD_MIPI_DSI
+ select SND_SOC_AK4642 if SND_SIMPLE_CARD
choice
prompt "AP4EVB LCD panel selection"
@@ -82,6 +89,7 @@ config MACH_MACKEREL
bool "mackerel board"
depends on ARCH_SH7372
select ARCH_REQUIRE_GPIOLIB
+ select SND_SOC_AK4642 if SND_SIMPLE_CARD
config MACH_KOTA2
bool "KOTA2 board"
@@ -93,11 +101,28 @@ config MACH_BONITO
select ARCH_REQUIRE_GPIOLIB
depends on ARCH_R8A7740
+config MACH_ARMADILLO800EVA
+ bool "Armadillo-800 EVA board"
+ depends on ARCH_R8A7740
+ select ARCH_REQUIRE_GPIOLIB
+ select USE_OF
+
config MACH_MARZEN
bool "MARZEN board"
depends on ARCH_R8A7779
select ARCH_REQUIRE_GPIOLIB
+config MACH_KZM9D
+ bool "KZM9D board"
+ depends on ARCH_EMEV2
+ select USE_OF
+
+config MACH_KZM9G
+ bool "KZM-A9-GT board"
+ depends on ARCH_SH73A0
+ select ARCH_REQUIRE_GPIOLIB
+ select USE_OF
+
comment "SH-Mobile System Configuration"
config CPU_HAS_INTEVT
@@ -110,7 +135,8 @@ config MEMORY_START
hex "Physical memory start address"
default "0x50000000" if MACH_G3EVM
default "0x40000000" if MACH_G4EVM || MACH_AP4EVB || MACH_AG5EVM || \
- MACH_MACKEREL || MACH_BONITO
+ MACH_MACKEREL || MACH_BONITO || \
+ MACH_ARMADILLO800EVA
default "0x41000000" if MACH_KOTA2
default "0x00000000"
---help---
@@ -122,7 +148,8 @@ config MEMORY_SIZE
hex "Physical memory size"
default "0x08000000" if MACH_G3EVM
default "0x08000000" if MACH_G4EVM
- default "0x20000000" if MACH_AG5EVM || MACH_BONITO
+ default "0x20000000" if MACH_AG5EVM || MACH_BONITO || \
+ MACH_ARMADILLO800EVA
default "0x1e000000" if MACH_KOTA2
default "0x10000000" if MACH_AP4EVB || MACH_MACKEREL
default "0x04000000"
diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile
index e7c2590b75d9..e6b177bc9410 100644
--- a/arch/arm/mach-shmobile/Makefile
+++ b/arch/arm/mach-shmobile/Makefile
@@ -12,12 +12,14 @@ obj-$(CONFIG_ARCH_SH7372) += setup-sh7372.o clock-sh7372.o intc-sh7372.o
obj-$(CONFIG_ARCH_SH73A0) += setup-sh73a0.o clock-sh73a0.o intc-sh73a0.o
obj-$(CONFIG_ARCH_R8A7740) += setup-r8a7740.o clock-r8a7740.o intc-r8a7740.o
obj-$(CONFIG_ARCH_R8A7779) += setup-r8a7779.o clock-r8a7779.o intc-r8a7779.o
+obj-$(CONFIG_ARCH_EMEV2) += setup-emev2.o clock-emev2.o
# SMP objects
smp-y := platsmp.o headsmp.o
smp-$(CONFIG_HOTPLUG_CPU) += hotplug.o
smp-$(CONFIG_ARCH_SH73A0) += smp-sh73a0.o
smp-$(CONFIG_ARCH_R8A7779) += smp-r8a7779.o
+smp-$(CONFIG_ARCH_EMEV2) += smp-emev2.o
# Pinmux setup
pfc-y :=
@@ -49,6 +51,9 @@ obj-$(CONFIG_MACH_MACKEREL) += board-mackerel.o
obj-$(CONFIG_MACH_KOTA2) += board-kota2.o
obj-$(CONFIG_MACH_BONITO) += board-bonito.o
obj-$(CONFIG_MACH_MARZEN) += board-marzen.o
+obj-$(CONFIG_MACH_ARMADILLO800EVA) += board-armadillo800eva.o
+obj-$(CONFIG_MACH_KZM9D) += board-kzm9d.o
+obj-$(CONFIG_MACH_KZM9G) += board-kzm9g.o
# Framework support
obj-$(CONFIG_SMP) += $(smp-y)
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c
index b56dde2732bb..b540b8eb20ca 100644
--- a/arch/arm/mach-shmobile/board-ap4evb.c
+++ b/arch/arm/mach-shmobile/board-ap4evb.c
@@ -50,6 +50,7 @@
#include <media/soc_camera.h>
#include <sound/sh_fsi.h>
+#include <sound/simple_card.h>
#include <video/sh_mobile_hdmi.h>
#include <video/sh_mobile_lcdc.h>
@@ -785,17 +786,25 @@ static struct platform_device fsi_device = {
},
};
-static struct fsi_ak4642_info fsi2_ak4643_info = {
+static struct asoc_simple_dai_init_info fsi2_ak4643_init_info = {
+ .fmt = SND_SOC_DAIFMT_LEFT_J,
+ .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM,
+ .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS,
+ .sysclk = 11289600,
+};
+
+static struct asoc_simple_card_info fsi2_ak4643_info = {
.name = "AK4643",
.card = "FSI2A-AK4643",
.cpu_dai = "fsia-dai",
.codec = "ak4642-codec.0-0013",
.platform = "sh_fsi2",
- .id = FSI_PORT_A,
+ .codec_dai = "ak4642-hifi",
+ .init = &fsi2_ak4643_init_info,
};
static struct platform_device fsi_ak4643_device = {
- .name = "fsi-ak4642-audio",
+ .name = "asoc-simple-card",
.dev = {
.platform_data = &fsi2_ak4643_info,
},
@@ -900,8 +909,26 @@ static struct platform_device lcdc1_device = {
},
};
+static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = {
+ .cpu_daifmt = SND_SOC_DAIFMT_CBM_CFM,
+};
+
+static struct asoc_simple_card_info fsi2_hdmi_info = {
+ .name = "HDMI",
+ .card = "FSI2B-HDMI",
+ .cpu_dai = "fsib-dai",
+ .codec = "sh-mobile-hdmi",
+ .platform = "sh_fsi2",
+ .codec_dai = "sh_mobile_hdmi-hifi",
+ .init = &fsi2_hdmi_init_info,
+};
+
static struct platform_device fsi_hdmi_device = {
- .name = "sh_fsi2_b_hdmi",
+ .name = "asoc-simple-card",
+ .id = 1,
+ .dev = {
+ .platform_data = &fsi2_hdmi_info,
+ },
};
static struct gpio_led ap4evb_leds[] = {
@@ -997,6 +1024,8 @@ static struct sh_mobile_ceu_companion csi2 = {
static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
.flags = SH_CEU_FLAG_USE_8BIT_BUS,
+ .max_width = 8188,
+ .max_height = 8188,
.csi2 = &csi2,
};
diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c
new file mode 100644
index 000000000000..9e37026ef9dd
--- /dev/null
+++ b/arch/arm/mach-shmobile/board-armadillo800eva.c
@@ -0,0 +1,784 @@
+/*
+ * armadillo 800 eva board support
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ * Copyright (C) 2012 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/sh_eth.h>
+#include <linux/videodev2.h>
+#include <linux/usb/renesas_usbhs.h>
+#include <linux/mfd/tmio.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sh_mmcif.h>
+#include <linux/mmc/sh_mobile_sdhi.h>
+#include <mach/common.h>
+#include <mach/irqs.h>
+#include <asm/page.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <mach/r8a7740.h>
+#include <video/sh_mobile_lcdc.h>
+
+/*
+ * CON1 Camera Module
+ * CON2 Extension Bus
+ * CON3 HDMI Output
+ * CON4 Composite Video Output
+ * CON5 H-UDI JTAG
+ * CON6 ARM JTAG
+ * CON7 SD1
+ * CON8 SD2
+ * CON9 RTC BackUp
+ * CON10 Monaural Mic Input
+ * CON11 Stereo Headphone Output
+ * CON12 Audio Line Output(L)
+ * CON13 Audio Line Output(R)
+ * CON14 AWL13 Module
+ * CON15 Extension
+ * CON16 LCD1
+ * CON17 LCD2
+ * CON19 Power Input
+ * CON20 USB1
+ * CON21 USB2
+ * CON22 Serial
+ * CON23 LAN
+ * CON24 USB3
+ * LED1 Camera LED(Yellow)
+ * LED2 Power LED (Green)
+ * ED3-LED6 User LED(Yellow)
+ * LED7 LAN link LED(Green)
+ * LED8 LAN activity LED(Yellow)
+ */
+
+/*
+ * DipSwitch
+ *
+ * SW1
+ *
+ * -12345678-+---------------+----------------------------
+ * 1 | boot | hermit
+ * 0 | boot | OS auto boot
+ * -12345678-+---------------+----------------------------
+ * 00 | boot device | eMMC
+ * 10 | boot device | SDHI0 (CON7)
+ * 01 | boot device | -
+ * 11 | boot device | Extension Buss (CS0)
+ * -12345678-+---------------+----------------------------
+ * 0 | Extension Bus | D8-D15 disable, eMMC enable
+ * 1 | Extension Bus | D8-D15 enable, eMMC disable
+ * -12345678-+---------------+----------------------------
+ * 0 | SDHI1 | COM8 disable, COM14 enable
+ * 1 | SDHI1 | COM8 enable, COM14 disable
+ * -12345678-+---------------+----------------------------
+ * 0 | USB0 | COM20 enable, COM24 disable
+ * 1 | USB0 | COM20 disable, COM24 enable
+ * -12345678-+---------------+----------------------------
+ * 00 | JTAG | SH-X2
+ * 10 | JTAG | ARM
+ * 01 | JTAG | -
+ * 11 | JTAG | Boundary Scan
+ *-----------+---------------+----------------------------
+ */
+
+/*
+ * USB function
+ *
+ * When you use USB Function,
+ * set SW1.6 ON, and connect cable to CN24.
+ *
+ * USBF needs workaround on R8A7740 chip.
+ * These are a little bit complex.
+ * see
+ * usbhsf_power_ctrl()
+ *
+ * CAUTION
+ *
+ * It uses autonomy mode for USB hotplug at this point
+ * (= usbhs_private.platform_callback.get_vbus is NULL),
+ * since we don't know what's happen on PM control
+ * on this workaround.
+ */
+#define USBCR1 0xe605810a
+#define USBH 0xC6700000
+#define USBH_USBCTR 0x10834
+
+struct usbhsf_private {
+ struct clk *phy;
+ struct clk *usb24;
+ struct clk *pci;
+ struct clk *func;
+ struct clk *host;
+ void __iomem *usbh_base;
+ struct renesas_usbhs_platform_info info;
+};
+
+#define usbhsf_get_priv(pdev) \
+ container_of(renesas_usbhs_get_info(pdev), \
+ struct usbhsf_private, info)
+
+static int usbhsf_get_id(struct platform_device *pdev)
+{
+ return USBHS_GADGET;
+}
+
+static void usbhsf_power_ctrl(struct platform_device *pdev,
+ void __iomem *base, int enable)
+{
+ struct usbhsf_private *priv = usbhsf_get_priv(pdev);
+
+ /*
+ * Work around for USB Function.
+ * It needs USB host clock, and settings
+ */
+ if (enable) {
+ /*
+ * enable all the related usb clocks
+ * for usb workaround
+ */
+ clk_enable(priv->usb24);
+ clk_enable(priv->pci);
+ clk_enable(priv->host);
+ clk_enable(priv->func);
+ clk_enable(priv->phy);
+
+ /*
+ * set USBCR1
+ *
+ * Port1 is driven by USB function,
+ * Port2 is driven by USB HOST
+ * One HOST (Port1 or Port2 is HOST)
+ * USB PLL input clock = 24MHz
+ */
+ __raw_writew(0xd750, USBCR1);
+ mdelay(1);
+
+ /*
+ * start USB Host
+ */
+ __raw_writel(0x0000000c, priv->usbh_base + USBH_USBCTR);
+ __raw_writel(0x00000008, priv->usbh_base + USBH_USBCTR);
+ mdelay(10);
+
+ /*
+ * USB PHY Power ON
+ */
+ __raw_writew(0xd770, USBCR1);
+ __raw_writew(0x4000, base + 0x102); /* USBF :: SUSPMODE */
+
+ } else {
+ __raw_writel(0x0000010f, priv->usbh_base + USBH_USBCTR);
+ __raw_writew(0xd7c0, USBCR1); /* GPIO */
+
+ clk_disable(priv->phy);
+ clk_disable(priv->func); /* usb work around */
+ clk_disable(priv->host); /* usb work around */
+ clk_disable(priv->pci); /* usb work around */
+ clk_disable(priv->usb24); /* usb work around */
+ }
+}
+
+static void usbhsf_hardware_exit(struct platform_device *pdev)
+{
+ struct usbhsf_private *priv = usbhsf_get_priv(pdev);
+
+ if (!IS_ERR(priv->phy))
+ clk_put(priv->phy);
+ if (!IS_ERR(priv->usb24))
+ clk_put(priv->usb24);
+ if (!IS_ERR(priv->pci))
+ clk_put(priv->pci);
+ if (!IS_ERR(priv->host))
+ clk_put(priv->host);
+ if (!IS_ERR(priv->func))
+ clk_put(priv->func);
+ if (priv->usbh_base)
+ iounmap(priv->usbh_base);
+
+ priv->phy = NULL;
+ priv->usb24 = NULL;
+ priv->pci = NULL;
+ priv->host = NULL;
+ priv->func = NULL;
+ priv->usbh_base = NULL;
+}
+
+static int usbhsf_hardware_init(struct platform_device *pdev)
+{
+ struct usbhsf_private *priv = usbhsf_get_priv(pdev);
+
+ priv->phy = clk_get(&pdev->dev, "phy");
+ priv->usb24 = clk_get(&pdev->dev, "usb24");
+ priv->pci = clk_get(&pdev->dev, "pci");
+ priv->func = clk_get(&pdev->dev, "func");
+ priv->host = clk_get(&pdev->dev, "host");
+ priv->usbh_base = ioremap_nocache(USBH, 0x20000);
+
+ if (IS_ERR(priv->phy) ||
+ IS_ERR(priv->usb24) ||
+ IS_ERR(priv->pci) ||
+ IS_ERR(priv->host) ||
+ IS_ERR(priv->func) ||
+ !priv->usbh_base) {
+ dev_err(&pdev->dev, "USB clock setting failed\n");
+ usbhsf_hardware_exit(pdev);
+ return -EIO;
+ }
+
+ /* usb24 use 1/1 of parent clock (= usb24s = 24MHz) */
+ clk_set_rate(priv->usb24,
+ clk_get_rate(clk_get_parent(priv->usb24)));
+
+ return 0;
+}
+
+static struct usbhsf_private usbhsf_private = {
+ .info = {
+ .platform_callback = {
+ .get_id = usbhsf_get_id,
+ .hardware_init = usbhsf_hardware_init,
+ .hardware_exit = usbhsf_hardware_exit,
+ .power_ctrl = usbhsf_power_ctrl,
+ },
+ .driver_param = {
+ .buswait_bwait = 5,
+ .detection_delay = 5,
+ },
+ }
+};
+
+static struct resource usbhsf_resources[] = {
+ {
+ .name = "USBHS",
+ .start = 0xe6890000,
+ .end = 0xe6890104 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = evt2irq(0x0A20),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device usbhsf_device = {
+ .name = "renesas_usbhs",
+ .dev = {
+ .platform_data = &usbhsf_private.info,
+ },
+ .id = -1,
+ .num_resources = ARRAY_SIZE(usbhsf_resources),
+ .resource = usbhsf_resources,
+};
+
+/* Ether */
+static struct sh_eth_plat_data sh_eth_platdata = {
+ .phy = 0x00, /* LAN8710A */
+ .edmac_endian = EDMAC_LITTLE_ENDIAN,
+ .register_type = SH_ETH_REG_GIGABIT,
+ .phy_interface = PHY_INTERFACE_MODE_MII,
+};
+
+static struct resource sh_eth_resources[] = {
+ {
+ .start = 0xe9a00000,
+ .end = 0xe9a00800 - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = 0xe9a01800,
+ .end = 0xe9a02000 - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = evt2irq(0x0500),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sh_eth_device = {
+ .name = "sh-eth",
+ .id = -1,
+ .dev = {
+ .platform_data = &sh_eth_platdata,
+ },
+ .resource = sh_eth_resources,
+ .num_resources = ARRAY_SIZE(sh_eth_resources),
+};
+
+/* LCDC */
+static struct fb_videomode lcdc0_mode = {
+ .name = "AMPIER/AM-800480",
+ .xres = 800,
+ .yres = 480,
+ .left_margin = 88,
+ .right_margin = 40,
+ .hsync_len = 128,
+ .upper_margin = 20,
+ .lower_margin = 5,
+ .vsync_len = 5,
+ .sync = 0,
+};
+
+static struct sh_mobile_lcdc_info lcdc0_info = {
+ .clock_source = LCDC_CLK_BUS,
+ .ch[0] = {
+ .chan = LCDC_CHAN_MAINLCD,
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .interface_type = RGB24,
+ .clock_divider = 5,
+ .flags = 0,
+ .lcd_modes = &lcdc0_mode,
+ .num_modes = 1,
+ .panel_cfg = {
+ .width = 111,
+ .height = 68,
+ },
+ },
+};
+
+static struct resource lcdc0_resources[] = {
+ [0] = {
+ .name = "LCD0",
+ .start = 0xfe940000,
+ .end = 0xfe943fff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = intcs_evt2irq(0x580),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device lcdc0_device = {
+ .name = "sh_mobile_lcdc_fb",
+ .num_resources = ARRAY_SIZE(lcdc0_resources),
+ .resource = lcdc0_resources,
+ .id = 0,
+ .dev = {
+ .platform_data = &lcdc0_info,
+ .coherent_dma_mask = ~0,
+ },
+};
+
+/* GPIO KEY */
+#define GPIO_KEY(c, g, d) { .code = c, .gpio = g, .desc = d, .active_low = 1 }
+
+static struct gpio_keys_button gpio_buttons[] = {
+ GPIO_KEY(KEY_POWER, GPIO_PORT99, "SW1"),
+ GPIO_KEY(KEY_BACK, GPIO_PORT100, "SW2"),
+ GPIO_KEY(KEY_MENU, GPIO_PORT97, "SW3"),
+ GPIO_KEY(KEY_HOME, GPIO_PORT98, "SW4"),
+};
+
+static struct gpio_keys_platform_data gpio_key_info = {
+ .buttons = gpio_buttons,
+ .nbuttons = ARRAY_SIZE(gpio_buttons),
+};
+
+static struct platform_device gpio_keys_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .dev = {
+ .platform_data = &gpio_key_info,
+ },
+};
+
+/* SDHI0 */
+/*
+ * FIXME
+ *
+ * It use polling mode here, since
+ * CD (= Card Detect) pin is not connected to SDHI0_CD.
+ * We can use IRQ31 as card detect irq,
+ * but it needs chattering removal operation
+ */
+#define IRQ31 evt2irq(0x33E0)
+static struct sh_mobile_sdhi_info sdhi0_info = {
+ .tmio_caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |\
+ MMC_CAP_NEEDS_POLL,
+ .tmio_ocr_mask = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34,
+ .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT,
+};
+
+static struct resource sdhi0_resources[] = {
+ {
+ .name = "SDHI0",
+ .start = 0xe6850000,
+ .end = 0xe6850100 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ /*
+ * no SH_MOBILE_SDHI_IRQ_CARD_DETECT here
+ */
+ {
+ .name = SH_MOBILE_SDHI_IRQ_SDCARD,
+ .start = evt2irq(0x0E20),
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = SH_MOBILE_SDHI_IRQ_SDIO,
+ .start = evt2irq(0x0E40),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sdhi0_device = {
+ .name = "sh_mobile_sdhi",
+ .id = 0,
+ .dev = {
+ .platform_data = &sdhi0_info,
+ },
+ .num_resources = ARRAY_SIZE(sdhi0_resources),
+ .resource = sdhi0_resources,
+};
+
+/* SDHI1 */
+static struct sh_mobile_sdhi_info sdhi1_info = {
+ .tmio_caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
+ .tmio_ocr_mask = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34,
+ .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT,
+};
+
+static struct resource sdhi1_resources[] = {
+ [0] = {
+ .name = "SDHI1",
+ .start = 0xe6860000,
+ .end = 0xe6860100 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = evt2irq(0x0E80),
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = evt2irq(0x0EA0),
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .start = evt2irq(0x0EC0),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sdhi1_device = {
+ .name = "sh_mobile_sdhi",
+ .id = 1,
+ .dev = {
+ .platform_data = &sdhi1_info,
+ },
+ .num_resources = ARRAY_SIZE(sdhi1_resources),
+ .resource = sdhi1_resources,
+};
+
+/* MMCIF */
+static struct sh_mmcif_plat_data sh_mmcif_plat = {
+ .sup_pclk = 0,
+ .ocr = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34,
+ .caps = MMC_CAP_4_BIT_DATA |
+ MMC_CAP_8_BIT_DATA |
+ MMC_CAP_NONREMOVABLE,
+};
+
+static struct resource sh_mmcif_resources[] = {
+ [0] = {
+ .name = "MMCIF",
+ .start = 0xe6bd0000,
+ .end = 0xe6bd0100 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ /* MMC ERR */
+ .start = evt2irq(0x1AC0),
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ /* MMC NOR */
+ .start = evt2irq(0x1AE0),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sh_mmcif_device = {
+ .name = "sh_mmcif",
+ .id = -1,
+ .dev = {
+ .platform_data = &sh_mmcif_plat,
+ },
+ .num_resources = ARRAY_SIZE(sh_mmcif_resources),
+ .resource = sh_mmcif_resources,
+};
+
+/* I2C */
+static struct i2c_board_info i2c0_devices[] = {
+ {
+ I2C_BOARD_INFO("st1232-ts", 0x55),
+ .irq = evt2irq(0x0340),
+ },
+};
+
+/*
+ * board devices
+ */
+static struct platform_device *eva_devices[] __initdata = {
+ &lcdc0_device,
+ &gpio_keys_device,
+ &sh_eth_device,
+ &sdhi0_device,
+ &sh_mmcif_device,
+};
+
+static void __init eva_clock_init(void)
+{
+ struct clk *system = clk_get(NULL, "system_clk");
+ struct clk *xtal1 = clk_get(NULL, "extal1");
+ struct clk *usb24s = clk_get(NULL, "usb24s");
+
+ if (IS_ERR(system) ||
+ IS_ERR(xtal1) ||
+ IS_ERR(usb24s)) {
+ pr_err("armadillo800eva board clock init failed\n");
+ goto clock_error;
+ }
+
+ /* armadillo 800 eva extal1 is 24MHz */
+ clk_set_rate(xtal1, 24000000);
+
+ /* usb24s use extal1 (= system) clock (= 24MHz) */
+ clk_set_parent(usb24s, system);
+
+clock_error:
+ if (!IS_ERR(system))
+ clk_put(system);
+ if (!IS_ERR(xtal1))
+ clk_put(xtal1);
+ if (!IS_ERR(usb24s))
+ clk_put(usb24s);
+}
+
+/*
+ * board init
+ */
+static void __init eva_init(void)
+{
+ eva_clock_init();
+
+ r8a7740_pinmux_init();
+
+ /* SCIFA1 */
+ gpio_request(GPIO_FN_SCIFA1_RXD, NULL);
+ gpio_request(GPIO_FN_SCIFA1_TXD, NULL);
+
+ /* LCDC0 */
+ gpio_request(GPIO_FN_LCDC0_SELECT, NULL);
+ gpio_request(GPIO_FN_LCD0_D0, NULL);
+ gpio_request(GPIO_FN_LCD0_D1, NULL);
+ gpio_request(GPIO_FN_LCD0_D2, NULL);
+ gpio_request(GPIO_FN_LCD0_D3, NULL);
+ gpio_request(GPIO_FN_LCD0_D4, NULL);
+ gpio_request(GPIO_FN_LCD0_D5, NULL);
+ gpio_request(GPIO_FN_LCD0_D6, NULL);
+ gpio_request(GPIO_FN_LCD0_D7, NULL);
+ gpio_request(GPIO_FN_LCD0_D8, NULL);
+ gpio_request(GPIO_FN_LCD0_D9, NULL);
+ gpio_request(GPIO_FN_LCD0_D10, NULL);
+ gpio_request(GPIO_FN_LCD0_D11, NULL);
+ gpio_request(GPIO_FN_LCD0_D12, NULL);
+ gpio_request(GPIO_FN_LCD0_D13, NULL);
+ gpio_request(GPIO_FN_LCD0_D14, NULL);
+ gpio_request(GPIO_FN_LCD0_D15, NULL);
+ gpio_request(GPIO_FN_LCD0_D16, NULL);
+ gpio_request(GPIO_FN_LCD0_D17, NULL);
+ gpio_request(GPIO_FN_LCD0_D18_PORT40, NULL);
+ gpio_request(GPIO_FN_LCD0_D19_PORT4, NULL);
+ gpio_request(GPIO_FN_LCD0_D20_PORT3, NULL);
+ gpio_request(GPIO_FN_LCD0_D21_PORT2, NULL);
+ gpio_request(GPIO_FN_LCD0_D22_PORT0, NULL);
+ gpio_request(GPIO_FN_LCD0_D23_PORT1, NULL);
+ gpio_request(GPIO_FN_LCD0_DCK, NULL);
+ gpio_request(GPIO_FN_LCD0_VSYN, NULL);
+ gpio_request(GPIO_FN_LCD0_HSYN, NULL);
+ gpio_request(GPIO_FN_LCD0_DISP, NULL);
+ gpio_request(GPIO_FN_LCD0_LCLK_PORT165, NULL);
+
+ gpio_request(GPIO_PORT61, NULL); /* LCDDON */
+ gpio_direction_output(GPIO_PORT61, 1);
+
+ gpio_request(GPIO_PORT202, NULL); /* LCD0_LED_CONT */
+ gpio_direction_output(GPIO_PORT202, 0);
+
+ /* Touchscreen */
+ gpio_request(GPIO_FN_IRQ10, NULL); /* TP_INT */
+ gpio_request(GPIO_PORT166, NULL); /* TP_RST_B */
+ gpio_direction_output(GPIO_PORT166, 1);
+
+ /* GETHER */
+ gpio_request(GPIO_FN_ET_CRS, NULL);
+ gpio_request(GPIO_FN_ET_MDC, NULL);
+ gpio_request(GPIO_FN_ET_MDIO, NULL);
+ gpio_request(GPIO_FN_ET_TX_ER, NULL);
+ gpio_request(GPIO_FN_ET_RX_ER, NULL);
+ gpio_request(GPIO_FN_ET_ERXD0, NULL);
+ gpio_request(GPIO_FN_ET_ERXD1, NULL);
+ gpio_request(GPIO_FN_ET_ERXD2, NULL);
+ gpio_request(GPIO_FN_ET_ERXD3, NULL);
+ gpio_request(GPIO_FN_ET_TX_CLK, NULL);
+ gpio_request(GPIO_FN_ET_TX_EN, NULL);
+ gpio_request(GPIO_FN_ET_ETXD0, NULL);
+ gpio_request(GPIO_FN_ET_ETXD1, NULL);
+ gpio_request(GPIO_FN_ET_ETXD2, NULL);
+ gpio_request(GPIO_FN_ET_ETXD3, NULL);
+ gpio_request(GPIO_FN_ET_PHY_INT, NULL);
+ gpio_request(GPIO_FN_ET_COL, NULL);
+ gpio_request(GPIO_FN_ET_RX_DV, NULL);
+ gpio_request(GPIO_FN_ET_RX_CLK, NULL);
+
+ gpio_request(GPIO_PORT18, NULL); /* PHY_RST */
+ gpio_direction_output(GPIO_PORT18, 1);
+
+ /* USB */
+ gpio_request(GPIO_PORT159, NULL); /* USB_DEVICE_MODE */
+ gpio_direction_input(GPIO_PORT159);
+
+ if (gpio_get_value(GPIO_PORT159)) {
+ /* USB Host */
+ } else {
+ /* USB Func */
+ gpio_request(GPIO_FN_VBUS, NULL);
+ platform_device_register(&usbhsf_device);
+ }
+
+ /* SDHI0 */
+ gpio_request(GPIO_FN_SDHI0_CMD, NULL);
+ gpio_request(GPIO_FN_SDHI0_CLK, NULL);
+ gpio_request(GPIO_FN_SDHI0_D0, NULL);
+ gpio_request(GPIO_FN_SDHI0_D1, NULL);
+ gpio_request(GPIO_FN_SDHI0_D2, NULL);
+ gpio_request(GPIO_FN_SDHI0_D3, NULL);
+ gpio_request(GPIO_FN_SDHI0_WP, NULL);
+
+ gpio_request(GPIO_PORT17, NULL); /* SDHI0_18/33_B */
+ gpio_request(GPIO_PORT74, NULL); /* SDHI0_PON */
+ gpio_request(GPIO_PORT75, NULL); /* SDSLOT1_PON */
+ gpio_direction_output(GPIO_PORT17, 0);
+ gpio_direction_output(GPIO_PORT74, 1);
+ gpio_direction_output(GPIO_PORT75, 1);
+
+ /* we can use GPIO_FN_IRQ31_PORT167 here for SDHI0 CD irq */
+
+ /*
+ * MMCIF
+ *
+ * Here doesn't care SW1.4 status,
+ * since CON2 is not mounted.
+ */
+ gpio_request(GPIO_FN_MMC1_CLK_PORT103, NULL);
+ gpio_request(GPIO_FN_MMC1_CMD_PORT104, NULL);
+ gpio_request(GPIO_FN_MMC1_D0_PORT149, NULL);
+ gpio_request(GPIO_FN_MMC1_D1_PORT148, NULL);
+ gpio_request(GPIO_FN_MMC1_D2_PORT147, NULL);
+ gpio_request(GPIO_FN_MMC1_D3_PORT146, NULL);
+ gpio_request(GPIO_FN_MMC1_D4_PORT145, NULL);
+ gpio_request(GPIO_FN_MMC1_D5_PORT144, NULL);
+ gpio_request(GPIO_FN_MMC1_D6_PORT143, NULL);
+ gpio_request(GPIO_FN_MMC1_D7_PORT142, NULL);
+
+ /*
+ * CAUTION
+ *
+ * DBGMD/LCDC0/FSIA MUX
+ * DBGMD_SELECT_B should be set after setting PFC Function.
+ */
+ gpio_request(GPIO_PORT176, NULL);
+ gpio_direction_output(GPIO_PORT176, 1);
+
+ /*
+ * We can switch CON8/CON14 by SW1.5,
+ * but it needs after DBGMD_SELECT_B
+ */
+ gpio_request(GPIO_PORT6, NULL);
+ gpio_direction_input(GPIO_PORT6);
+ if (gpio_get_value(GPIO_PORT6)) {
+ /* CON14 enable */
+ } else {
+ /* CON8 (SDHI1) enable */
+ gpio_request(GPIO_FN_SDHI1_CLK, NULL);
+ gpio_request(GPIO_FN_SDHI1_CMD, NULL);
+ gpio_request(GPIO_FN_SDHI1_D0, NULL);
+ gpio_request(GPIO_FN_SDHI1_D1, NULL);
+ gpio_request(GPIO_FN_SDHI1_D2, NULL);
+ gpio_request(GPIO_FN_SDHI1_D3, NULL);
+ gpio_request(GPIO_FN_SDHI1_CD, NULL);
+ gpio_request(GPIO_FN_SDHI1_WP, NULL);
+
+ gpio_request(GPIO_PORT16, NULL); /* SDSLOT2_PON */
+ gpio_direction_output(GPIO_PORT16, 1);
+
+ platform_device_register(&sdhi1_device);
+ }
+
+
+#ifdef CONFIG_CACHE_L2X0
+ /* Early BRESP enable, Shared attribute override enable, 32K*8way */
+ l2x0_init(__io(0xf0002000), 0x40440000, 0x82000fff);
+#endif
+
+ i2c_register_board_info(0, i2c0_devices, ARRAY_SIZE(i2c0_devices));
+
+ r8a7740_add_standard_devices();
+
+ platform_add_devices(eva_devices,
+ ARRAY_SIZE(eva_devices));
+}
+
+static void __init eva_earlytimer_init(void)
+{
+ r8a7740_clock_init(MD_CK0 | MD_CK2);
+ shmobile_earlytimer_init();
+}
+
+static void __init eva_add_early_devices(void)
+{
+ r8a7740_add_early_devices();
+
+ /* override timer setup with board-specific code */
+ shmobile_timer.init = eva_earlytimer_init;
+}
+
+static const char *eva_boards_compat_dt[] __initdata = {
+ "renesas,armadillo800eva",
+ NULL,
+};
+
+DT_MACHINE_START(ARMADILLO800EVA_DT, "armadillo800eva")
+ .map_io = r8a7740_map_io,
+ .init_early = eva_add_early_devices,
+ .init_irq = r8a7740_init_irq,
+ .handle_irq = shmobile_handle_irq_intc,
+ .init_machine = eva_init,
+ .timer = &shmobile_timer,
+ .dt_compat = eva_boards_compat_dt,
+MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-bonito.c b/arch/arm/mach-shmobile/board-bonito.c
index 81fd95f7f52a..63ab7062bee3 100644
--- a/arch/arm/mach-shmobile/board-bonito.c
+++ b/arch/arm/mach-shmobile/board-bonito.c
@@ -486,7 +486,7 @@ static void __init bonito_earlytimer_init(void)
shmobile_earlytimer_init();
}
-void __init bonito_add_early_devices(void)
+static void __init bonito_add_early_devices(void)
{
r8a7740_add_early_devices();
diff --git a/arch/arm/mach-shmobile/board-kzm9d.c b/arch/arm/mach-shmobile/board-kzm9d.c
new file mode 100644
index 000000000000..7bc5e7d39f9b
--- /dev/null
+++ b/arch/arm/mach-shmobile/board-kzm9d.c
@@ -0,0 +1,85 @@
+/*
+ * kzm9d board support
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ * Copyright (C) 2012 Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/smsc911x.h>
+#include <mach/common.h>
+#include <mach/emev2.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/hardware/gic.h>
+
+/* Ether */
+static struct resource smsc911x_resources[] = {
+ [0] = {
+ .start = 0x20000000,
+ .end = 0x2000ffff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = EMEV2_GPIO_IRQ(1),
+ .flags = IORESOURCE_IRQ | IRQF_TRIGGER_HIGH,
+ },
+};
+
+static struct smsc911x_platform_config smsc911x_platdata = {
+ .flags = SMSC911X_USE_32BIT,
+ .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL,
+ .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH,
+};
+
+static struct platform_device smsc91x_device = {
+ .name = "smsc911x",
+ .id = 0,
+ .dev = {
+ .platform_data = &smsc911x_platdata,
+ },
+ .num_resources = ARRAY_SIZE(smsc911x_resources),
+ .resource = smsc911x_resources,
+};
+
+static struct platform_device *kzm9d_devices[] __initdata = {
+ &smsc91x_device,
+};
+
+void __init kzm9d_add_standard_devices(void)
+{
+ emev2_add_standard_devices();
+
+ platform_add_devices(kzm9d_devices, ARRAY_SIZE(kzm9d_devices));
+}
+
+static const char *kzm9d_boards_compat_dt[] __initdata = {
+ "renesas,kzm9d",
+ NULL,
+};
+
+DT_MACHINE_START(KZM9D_DT, "kzm9d")
+ .map_io = emev2_map_io,
+ .init_early = emev2_add_early_devices,
+ .nr_irqs = NR_IRQS_LEGACY,
+ .init_irq = emev2_init_irq,
+ .handle_irq = gic_handle_irq,
+ .init_machine = kzm9d_add_standard_devices,
+ .timer = &shmobile_timer,
+ .dt_compat = kzm9d_boards_compat_dt,
+MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c
new file mode 100644
index 000000000000..d8e33b682832
--- /dev/null
+++ b/arch/arm/mach-shmobile/board-kzm9g.c
@@ -0,0 +1,460 @@
+/*
+ * KZM-A9-GT board support
+ *
+ * Copyright (C) 2012 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
+#include <linux/i2c/pcf857x.h>
+#include <linux/input.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sh_mmcif.h>
+#include <linux/mmc/sh_mobile_sdhi.h>
+#include <linux/mfd/tmio.h>
+#include <linux/platform_device.h>
+#include <linux/smsc911x.h>
+#include <linux/usb/r8a66597.h>
+#include <linux/videodev2.h>
+#include <mach/irqs.h>
+#include <mach/sh73a0.h>
+#include <mach/common.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <asm/hardware/gic.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <video/sh_mobile_lcdc.h>
+
+/*
+ * external GPIO
+ */
+#define GPIO_PCF8575_BASE (GPIO_NR)
+#define GPIO_PCF8575_PORT10 (GPIO_NR + 8)
+#define GPIO_PCF8575_PORT11 (GPIO_NR + 9)
+#define GPIO_PCF8575_PORT12 (GPIO_NR + 10)
+#define GPIO_PCF8575_PORT13 (GPIO_NR + 11)
+#define GPIO_PCF8575_PORT14 (GPIO_NR + 12)
+#define GPIO_PCF8575_PORT15 (GPIO_NR + 13)
+#define GPIO_PCF8575_PORT16 (GPIO_NR + 14)
+
+/* SMSC 9221 */
+static struct resource smsc9221_resources[] = {
+ [0] = {
+ .start = 0x10000000, /* CS4 */
+ .end = 0x100000ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = intcs_evt2irq(0x260), /* IRQ3 */
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct smsc911x_platform_config smsc9221_platdata = {
+ .flags = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS,
+ .phy_interface = PHY_INTERFACE_MODE_MII,
+ .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+ .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL,
+};
+
+static struct platform_device smsc_device = {
+ .name = "smsc911x",
+ .dev = {
+ .platform_data = &smsc9221_platdata,
+ },
+ .resource = smsc9221_resources,
+ .num_resources = ARRAY_SIZE(smsc9221_resources),
+};
+
+/* USB external chip */
+static struct r8a66597_platdata usb_host_data = {
+ .on_chip = 0,
+ .xtal = R8A66597_PLATDATA_XTAL_48MHZ,
+};
+
+static struct resource usb_resources[] = {
+ [0] = {
+ .start = 0x10010000,
+ .end = 0x1001ffff - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = intcs_evt2irq(0x220), /* IRQ1 */
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device usb_host_device = {
+ .name = "r8a66597_hcd",
+ .dev = {
+ .platform_data = &usb_host_data,
+ .dma_mask = NULL,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(usb_resources),
+ .resource = usb_resources,
+};
+
+/* LCDC */
+static struct fb_videomode kzm_lcdc_mode = {
+ .name = "WVGA Panel",
+ .xres = 800,
+ .yres = 480,
+ .left_margin = 220,
+ .right_margin = 110,
+ .hsync_len = 70,
+ .upper_margin = 20,
+ .lower_margin = 5,
+ .vsync_len = 5,
+ .sync = 0,
+};
+
+static struct sh_mobile_lcdc_info lcdc_info = {
+ .clock_source = LCDC_CLK_BUS,
+ .ch[0] = {
+ .chan = LCDC_CHAN_MAINLCD,
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .interface_type = RGB24,
+ .lcd_modes = &kzm_lcdc_mode,
+ .num_modes = 1,
+ .clock_divider = 5,
+ .flags = 0,
+ .panel_cfg = {
+ .width = 152,
+ .height = 91,
+ },
+ }
+};
+
+static struct resource lcdc_resources[] = {
+ [0] = {
+ .name = "LCDC",
+ .start = 0xfe940000,
+ .end = 0xfe943fff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = intcs_evt2irq(0x580),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device lcdc_device = {
+ .name = "sh_mobile_lcdc_fb",
+ .num_resources = ARRAY_SIZE(lcdc_resources),
+ .resource = lcdc_resources,
+ .dev = {
+ .platform_data = &lcdc_info,
+ .coherent_dma_mask = ~0,
+ },
+};
+
+/* MMCIF */
+static struct resource sh_mmcif_resources[] = {
+ [0] = {
+ .name = "MMCIF",
+ .start = 0xe6bd0000,
+ .end = 0xe6bd00ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = gic_spi(141),
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = gic_spi(140),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct sh_mmcif_plat_data sh_mmcif_platdata = {
+ .ocr = MMC_VDD_165_195,
+ .caps = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE,
+};
+
+static struct platform_device mmc_device = {
+ .name = "sh_mmcif",
+ .dev = {
+ .dma_mask = NULL,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &sh_mmcif_platdata,
+ },
+ .num_resources = ARRAY_SIZE(sh_mmcif_resources),
+ .resource = sh_mmcif_resources,
+};
+
+/* SDHI */
+static struct sh_mobile_sdhi_info sdhi0_info = {
+ .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT,
+ .tmio_caps = MMC_CAP_SD_HIGHSPEED,
+ .tmio_ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
+};
+
+static struct resource sdhi0_resources[] = {
+ [0] = {
+ .name = "SDHI0",
+ .start = 0xee100000,
+ .end = 0xee1000ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = SH_MOBILE_SDHI_IRQ_CARD_DETECT,
+ .start = gic_spi(83),
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .name = SH_MOBILE_SDHI_IRQ_SDCARD,
+ .start = gic_spi(84),
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .name = SH_MOBILE_SDHI_IRQ_SDIO,
+ .start = gic_spi(85),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sdhi0_device = {
+ .name = "sh_mobile_sdhi",
+ .num_resources = ARRAY_SIZE(sdhi0_resources),
+ .resource = sdhi0_resources,
+ .dev = {
+ .platform_data = &sdhi0_info,
+ },
+};
+
+/* KEY */
+#define GPIO_KEY(c, g, d) { .code = c, .gpio = g, .desc = d, .active_low = 1 }
+
+static struct gpio_keys_button gpio_buttons[] = {
+ GPIO_KEY(KEY_BACK, GPIO_PCF8575_PORT10, "SW3"),
+ GPIO_KEY(KEY_RIGHT, GPIO_PCF8575_PORT11, "SW2-R"),
+ GPIO_KEY(KEY_LEFT, GPIO_PCF8575_PORT12, "SW2-L"),
+ GPIO_KEY(KEY_ENTER, GPIO_PCF8575_PORT13, "SW2-P"),
+ GPIO_KEY(KEY_UP, GPIO_PCF8575_PORT14, "SW2-U"),
+ GPIO_KEY(KEY_DOWN, GPIO_PCF8575_PORT15, "SW2-D"),
+ GPIO_KEY(KEY_HOME, GPIO_PCF8575_PORT16, "SW1"),
+};
+
+static struct gpio_keys_platform_data gpio_key_info = {
+ .buttons = gpio_buttons,
+ .nbuttons = ARRAY_SIZE(gpio_buttons),
+ .poll_interval = 250, /* poling at this point */
+};
+
+static struct platform_device gpio_keys_device = {
+ /* gpio-pcf857x.c driver doesn't support gpio_to_irq() */
+ .name = "gpio-keys-polled",
+ .dev = {
+ .platform_data = &gpio_key_info,
+ },
+};
+
+/* I2C */
+static struct pcf857x_platform_data pcf8575_pdata = {
+ .gpio_base = GPIO_PCF8575_BASE,
+};
+
+static struct i2c_board_info i2c1_devices[] = {
+ {
+ I2C_BOARD_INFO("st1232-ts", 0x55),
+ .irq = intcs_evt2irq(0x300), /* IRQ8 */
+ },
+};
+
+static struct i2c_board_info i2c3_devices[] = {
+ {
+ I2C_BOARD_INFO("pcf8575", 0x20),
+ .platform_data = &pcf8575_pdata,
+ },
+};
+
+static struct platform_device *kzm_devices[] __initdata = {
+ &smsc_device,
+ &usb_host_device,
+ &lcdc_device,
+ &mmc_device,
+ &sdhi0_device,
+ &gpio_keys_device,
+};
+
+/*
+ * FIXME
+ *
+ * This is quick hack for enabling LCDC backlight
+ */
+static int __init as3711_enable_lcdc_backlight(void)
+{
+ struct i2c_adapter *a = i2c_get_adapter(0);
+ struct i2c_msg msg;
+ int i, ret;
+ __u8 magic[] = {
+ 0x40, 0x2a,
+ 0x43, 0x3c,
+ 0x44, 0x3c,
+ 0x45, 0x3c,
+ 0x54, 0x03,
+ 0x51, 0x00,
+ 0x51, 0x01,
+ 0xff, 0x00, /* wait */
+ 0x43, 0xf0,
+ 0x44, 0xf0,
+ 0x45, 0xf0,
+ };
+
+ if (!machine_is_kzm9g())
+ return 0;
+
+ if (!a)
+ return 0;
+
+ msg.addr = 0x40;
+ msg.len = 2;
+ msg.flags = 0;
+
+ for (i = 0; i < ARRAY_SIZE(magic); i += 2) {
+ msg.buf = magic + i;
+
+ if (0xff == msg.buf[0]) {
+ udelay(500);
+ continue;
+ }
+
+ ret = i2c_transfer(a, &msg, 1);
+ if (ret < 0) {
+ pr_err("i2c transfer fail\n");
+ break;
+ }
+ }
+
+ return 0;
+}
+device_initcall(as3711_enable_lcdc_backlight);
+
+static void __init kzm_init(void)
+{
+ sh73a0_pinmux_init();
+
+ /* enable SCIFA4 */
+ gpio_request(GPIO_FN_SCIFA4_TXD, NULL);
+ gpio_request(GPIO_FN_SCIFA4_RXD, NULL);
+ gpio_request(GPIO_FN_SCIFA4_RTS_, NULL);
+ gpio_request(GPIO_FN_SCIFA4_CTS_, NULL);
+
+ /* CS4 for SMSC/USB */
+ gpio_request(GPIO_FN_CS4_, NULL); /* CS4 */
+
+ /* SMSC */
+ gpio_request(GPIO_PORT224, NULL); /* IRQ3 */
+ gpio_direction_input(GPIO_PORT224);
+
+ /* LCDC */
+ gpio_request(GPIO_FN_LCDD23, NULL);
+ gpio_request(GPIO_FN_LCDD22, NULL);
+ gpio_request(GPIO_FN_LCDD21, NULL);
+ gpio_request(GPIO_FN_LCDD20, NULL);
+ gpio_request(GPIO_FN_LCDD19, NULL);
+ gpio_request(GPIO_FN_LCDD18, NULL);
+ gpio_request(GPIO_FN_LCDD17, NULL);
+ gpio_request(GPIO_FN_LCDD16, NULL);
+ gpio_request(GPIO_FN_LCDD15, NULL);
+ gpio_request(GPIO_FN_LCDD14, NULL);
+ gpio_request(GPIO_FN_LCDD13, NULL);
+ gpio_request(GPIO_FN_LCDD12, NULL);
+ gpio_request(GPIO_FN_LCDD11, NULL);
+ gpio_request(GPIO_FN_LCDD10, NULL);
+ gpio_request(GPIO_FN_LCDD9, NULL);
+ gpio_request(GPIO_FN_LCDD8, NULL);
+ gpio_request(GPIO_FN_LCDD7, NULL);
+ gpio_request(GPIO_FN_LCDD6, NULL);
+ gpio_request(GPIO_FN_LCDD5, NULL);
+ gpio_request(GPIO_FN_LCDD4, NULL);
+ gpio_request(GPIO_FN_LCDD3, NULL);
+ gpio_request(GPIO_FN_LCDD2, NULL);
+ gpio_request(GPIO_FN_LCDD1, NULL);
+ gpio_request(GPIO_FN_LCDD0, NULL);
+ gpio_request(GPIO_FN_LCDDISP, NULL);
+ gpio_request(GPIO_FN_LCDDCK, NULL);
+
+ gpio_request(GPIO_PORT222, NULL); /* LCDCDON */
+ gpio_request(GPIO_PORT226, NULL); /* SC */
+ gpio_direction_output(GPIO_PORT222, 1);
+ gpio_direction_output(GPIO_PORT226, 1);
+
+ /* Touchscreen */
+ gpio_request(GPIO_PORT223, NULL); /* IRQ8 */
+ gpio_direction_input(GPIO_PORT223);
+
+ /* enable MMCIF */
+ gpio_request(GPIO_FN_MMCCLK0, NULL);
+ gpio_request(GPIO_FN_MMCCMD0_PU, NULL);
+ gpio_request(GPIO_FN_MMCD0_0_PU, NULL);
+ gpio_request(GPIO_FN_MMCD0_1_PU, NULL);
+ gpio_request(GPIO_FN_MMCD0_2_PU, NULL);
+ gpio_request(GPIO_FN_MMCD0_3_PU, NULL);
+ gpio_request(GPIO_FN_MMCD0_4_PU, NULL);
+ gpio_request(GPIO_FN_MMCD0_5_PU, NULL);
+ gpio_request(GPIO_FN_MMCD0_6_PU, NULL);
+ gpio_request(GPIO_FN_MMCD0_7_PU, NULL);
+
+ /* enable SD */
+ gpio_request(GPIO_FN_SDHIWP0, NULL);
+ gpio_request(GPIO_FN_SDHICD0, NULL);
+ gpio_request(GPIO_FN_SDHICMD0, NULL);
+ gpio_request(GPIO_FN_SDHICLK0, NULL);
+ gpio_request(GPIO_FN_SDHID0_3, NULL);
+ gpio_request(GPIO_FN_SDHID0_2, NULL);
+ gpio_request(GPIO_FN_SDHID0_1, NULL);
+ gpio_request(GPIO_FN_SDHID0_0, NULL);
+ gpio_request(GPIO_FN_SDHI0_VCCQ_MC0_ON, NULL);
+ gpio_request(GPIO_PORT15, NULL);
+ gpio_direction_output(GPIO_PORT15, 1); /* power */
+
+ /* I2C 3 */
+ gpio_request(GPIO_FN_PORT27_I2C_SCL3, NULL);
+ gpio_request(GPIO_FN_PORT28_I2C_SDA3, NULL);
+
+#ifdef CONFIG_CACHE_L2X0
+ /* Early BRESP enable, Shared attribute override enable, 64K*8way */
+ l2x0_init(IOMEM(0xf0100000), 0x40460000, 0x82000fff);
+#endif
+
+ i2c_register_board_info(1, i2c1_devices, ARRAY_SIZE(i2c1_devices));
+ i2c_register_board_info(3, i2c3_devices, ARRAY_SIZE(i2c3_devices));
+
+ sh73a0_add_standard_devices();
+ platform_add_devices(kzm_devices, ARRAY_SIZE(kzm_devices));
+}
+
+static const char *kzm9g_boards_compat_dt[] __initdata = {
+ "renesas,kzm9g",
+ NULL,
+};
+
+DT_MACHINE_START(KZM9G_DT, "kzm9g")
+ .map_io = sh73a0_map_io,
+ .init_early = sh73a0_add_early_devices,
+ .nr_irqs = NR_IRQS_LEGACY,
+ .init_irq = sh73a0_init_irq,
+ .handle_irq = gic_handle_irq,
+ .init_machine = kzm_init,
+ .timer = &shmobile_timer,
+ .dt_compat = kzm9g_boards_compat_dt,
+MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index 8c6202bb6aeb..50c67b22d087 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -53,6 +53,7 @@
#include <media/soc_camera.h>
#include <media/soc_camera_platform.h>
#include <sound/sh_fsi.h>
+#include <sound/simple_card.h>
#include <mach/common.h>
#include <mach/irqs.h>
@@ -502,8 +503,26 @@ static struct platform_device hdmi_lcdc_device = {
},
};
+static struct asoc_simple_dai_init_info fsi2_hdmi_init_info = {
+ .cpu_daifmt = SND_SOC_DAIFMT_CBM_CFM,
+};
+
+static struct asoc_simple_card_info fsi2_hdmi_info = {
+ .name = "HDMI",
+ .card = "FSI2B-HDMI",
+ .cpu_dai = "fsib-dai",
+ .codec = "sh-mobile-hdmi",
+ .platform = "sh_fsi2",
+ .codec_dai = "sh_mobile_hdmi-hifi",
+ .init = &fsi2_hdmi_init_info,
+};
+
static struct platform_device fsi_hdmi_device = {
- .name = "sh_fsi2_b_hdmi",
+ .name = "asoc-simple-card",
+ .id = 1,
+ .dev = {
+ .platform_data = &fsi2_hdmi_info,
+ },
};
static void __init hdmi_init_pm_clock(void)
@@ -908,6 +927,8 @@ fsi_set_rate_end:
static struct sh_fsi_platform_info fsi_info = {
.port_a = {
.flags = SH_FSI_BRS_INV,
+ .tx_id = SHDMA_SLAVE_FSIA_TX,
+ .rx_id = SHDMA_SLAVE_FSIA_RX,
},
.port_b = {
.flags = SH_FSI_BRS_INV |
@@ -920,9 +941,11 @@ static struct sh_fsi_platform_info fsi_info = {
static struct resource fsi_resources[] = {
[0] = {
+ /* we need 0xFE1F0000 to access DMA
+ * instead of 0xFE3C0000 */
.name = "FSI",
- .start = 0xFE3C0000,
- .end = 0xFE3C0400 - 1,
+ .start = 0xFE1F0000,
+ .end = 0xFE1F0400 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -941,17 +964,25 @@ static struct platform_device fsi_device = {
},
};
-static struct fsi_ak4642_info fsi2_ak4643_info = {
+static struct asoc_simple_dai_init_info fsi2_ak4643_init_info = {
+ .fmt = SND_SOC_DAIFMT_LEFT_J,
+ .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM,
+ .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS,
+ .sysclk = 11289600,
+};
+
+static struct asoc_simple_card_info fsi2_ak4643_info = {
.name = "AK4643",
.card = "FSI2A-AK4643",
.cpu_dai = "fsia-dai",
.codec = "ak4642-codec.0-0013",
.platform = "sh_fsi2",
- .id = FSI_PORT_A,
+ .codec_dai = "ak4642-hifi",
+ .init = &fsi2_ak4643_init_info,
};
static struct platform_device fsi_ak4643_device = {
- .name = "fsi-ak4642-audio",
+ .name = "asoc-simple-card",
.dev = {
.platform_data = &fsi2_ak4643_info,
},
@@ -1248,6 +1279,8 @@ static void mackerel_camera_del(struct soc_camera_device *icd)
static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
.flags = SH_CEU_FLAG_USE_8BIT_BUS,
+ .max_width = 8188,
+ .max_height = 8188,
};
static struct resource ceu_resources[] = {
diff --git a/arch/arm/mach-shmobile/clock-emev2.c b/arch/arm/mach-shmobile/clock-emev2.c
new file mode 100644
index 000000000000..4710f1847bb7
--- /dev/null
+++ b/arch/arm/mach-shmobile/clock-emev2.c
@@ -0,0 +1,249 @@
+/*
+ * Emma Mobile EV2 clock framework support
+ *
+ * Copyright (C) 2012 Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/sh_clk.h>
+#include <linux/clkdev.h>
+#include <mach/common.h>
+
+#define EMEV2_SMU_BASE 0xe0110000
+
+/* EMEV2 SMU registers */
+#define USIAU0_RSTCTRL 0x094
+#define USIBU1_RSTCTRL 0x0ac
+#define USIBU2_RSTCTRL 0x0b0
+#define USIBU3_RSTCTRL 0x0b4
+#define STI_RSTCTRL 0x124
+#define USIAU0GCLKCTRL 0x4a0
+#define USIBU1GCLKCTRL 0x4b8
+#define USIBU2GCLKCTRL 0x4bc
+#define USIBU3GCLKCTRL 0x04c0
+#define STIGCLKCTRL 0x528
+#define USIAU0SCLKDIV 0x61c
+#define USIB2SCLKDIV 0x65c
+#define USIB3SCLKDIV 0x660
+#define STI_CLKSEL 0x688
+#define SMU_GENERAL_REG0 0x7c0
+
+/* not pretty, but hey */
+static void __iomem *smu_base;
+
+static void emev2_smu_write(unsigned long value, int offs)
+{
+ BUG_ON(!smu_base || (offs >= PAGE_SIZE));
+ iowrite32(value, smu_base + offs);
+}
+
+void emev2_set_boot_vector(unsigned long value)
+{
+ emev2_smu_write(value, SMU_GENERAL_REG0);
+}
+
+static struct clk_mapping smu_mapping = {
+ .phys = EMEV2_SMU_BASE,
+ .len = PAGE_SIZE,
+};
+
+/* Fixed 32 KHz root clock from C32K pin */
+static struct clk c32k_clk = {
+ .rate = 32768,
+ .mapping = &smu_mapping,
+};
+
+/* PLL3 multiplies C32K with 7000 */
+static unsigned long pll3_recalc(struct clk *clk)
+{
+ return clk->parent->rate * 7000;
+}
+
+static struct sh_clk_ops pll3_clk_ops = {
+ .recalc = pll3_recalc,
+};
+
+static struct clk pll3_clk = {
+ .ops = &pll3_clk_ops,
+ .parent = &c32k_clk,
+};
+
+static struct clk *main_clks[] = {
+ &c32k_clk,
+ &pll3_clk,
+};
+
+enum { SCLKDIV_USIAU0, SCLKDIV_USIBU2, SCLKDIV_USIBU1, SCLKDIV_USIBU3,
+ SCLKDIV_NR };
+
+#define SCLKDIV(_reg, _shift) \
+{ \
+ .parent = &pll3_clk, \
+ .enable_reg = IOMEM(EMEV2_SMU_BASE + (_reg)), \
+ .enable_bit = _shift, \
+}
+
+static struct clk sclkdiv_clks[SCLKDIV_NR] = {
+ [SCLKDIV_USIAU0] = SCLKDIV(USIAU0SCLKDIV, 0),
+ [SCLKDIV_USIBU2] = SCLKDIV(USIB2SCLKDIV, 16),
+ [SCLKDIV_USIBU1] = SCLKDIV(USIB2SCLKDIV, 0),
+ [SCLKDIV_USIBU3] = SCLKDIV(USIB3SCLKDIV, 0),
+};
+
+enum { GCLK_USIAU0_SCLK, GCLK_USIBU1_SCLK, GCLK_USIBU2_SCLK, GCLK_USIBU3_SCLK,
+ GCLK_STI_SCLK,
+ GCLK_NR };
+
+#define GCLK_SCLK(_parent, _reg) \
+{ \
+ .parent = _parent, \
+ .enable_reg = IOMEM(EMEV2_SMU_BASE + (_reg)), \
+ .enable_bit = 1, /* SCLK_GCC */ \
+}
+
+static struct clk gclk_clks[GCLK_NR] = {
+ [GCLK_USIAU0_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIAU0],
+ USIAU0GCLKCTRL),
+ [GCLK_USIBU1_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU1],
+ USIBU1GCLKCTRL),
+ [GCLK_USIBU2_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU2],
+ USIBU2GCLKCTRL),
+ [GCLK_USIBU3_SCLK] = GCLK_SCLK(&sclkdiv_clks[SCLKDIV_USIBU3],
+ USIBU3GCLKCTRL),
+ [GCLK_STI_SCLK] = GCLK_SCLK(&c32k_clk, STIGCLKCTRL),
+};
+
+static int emev2_gclk_enable(struct clk *clk)
+{
+ iowrite32(ioread32(clk->mapped_reg) | (1 << clk->enable_bit),
+ clk->mapped_reg);
+ return 0;
+}
+
+static void emev2_gclk_disable(struct clk *clk)
+{
+ iowrite32(ioread32(clk->mapped_reg) & ~(1 << clk->enable_bit),
+ clk->mapped_reg);
+}
+
+static struct sh_clk_ops emev2_gclk_clk_ops = {
+ .enable = emev2_gclk_enable,
+ .disable = emev2_gclk_disable,
+ .recalc = followparent_recalc,
+};
+
+static int __init emev2_gclk_register(struct clk *clks, int nr)
+{
+ struct clk *clkp;
+ int ret = 0;
+ int k;
+
+ for (k = 0; !ret && (k < nr); k++) {
+ clkp = clks + k;
+ clkp->ops = &emev2_gclk_clk_ops;
+ ret |= clk_register(clkp);
+ }
+
+ return ret;
+}
+
+static unsigned long emev2_sclkdiv_recalc(struct clk *clk)
+{
+ unsigned int sclk_div;
+
+ sclk_div = (ioread32(clk->mapped_reg) >> clk->enable_bit) & 0xff;
+
+ return clk->parent->rate / (sclk_div + 1);
+}
+
+static struct sh_clk_ops emev2_sclkdiv_clk_ops = {
+ .recalc = emev2_sclkdiv_recalc,
+};
+
+static int __init emev2_sclkdiv_register(struct clk *clks, int nr)
+{
+ struct clk *clkp;
+ int ret = 0;
+ int k;
+
+ for (k = 0; !ret && (k < nr); k++) {
+ clkp = clks + k;
+ clkp->ops = &emev2_sclkdiv_clk_ops;
+ ret |= clk_register(clkp);
+ }
+
+ return ret;
+}
+
+static struct clk_lookup lookups[] = {
+ CLKDEV_DEV_ID("serial8250-em.0", &gclk_clks[GCLK_USIAU0_SCLK]),
+ CLKDEV_DEV_ID("e1020000.uart", &gclk_clks[GCLK_USIAU0_SCLK]),
+ CLKDEV_DEV_ID("serial8250-em.1", &gclk_clks[GCLK_USIBU1_SCLK]),
+ CLKDEV_DEV_ID("e1030000.uart", &gclk_clks[GCLK_USIBU1_SCLK]),
+ CLKDEV_DEV_ID("serial8250-em.2", &gclk_clks[GCLK_USIBU2_SCLK]),
+ CLKDEV_DEV_ID("e1040000.uart", &gclk_clks[GCLK_USIBU2_SCLK]),
+ CLKDEV_DEV_ID("serial8250-em.3", &gclk_clks[GCLK_USIBU3_SCLK]),
+ CLKDEV_DEV_ID("e1050000.uart", &gclk_clks[GCLK_USIBU3_SCLK]),
+ CLKDEV_DEV_ID("em_sti.0", &gclk_clks[GCLK_STI_SCLK]),
+ CLKDEV_DEV_ID("e0180000.sti", &gclk_clks[GCLK_STI_SCLK]),
+};
+
+void __init emev2_clock_init(void)
+{
+ int k, ret = 0;
+ static int is_setup;
+
+ /* yuck, this is ugly as hell, but the non-smp case of clocks
+ * code is now designed to rely on ioremap() instead of static
+ * entity maps. in the case of smp we need access to the SMU
+ * register earlier than ioremap() is actually working without
+ * any static maps. to enable SMP in ugly but with dynamic
+ * mappings we have to call emev2_clock_init() from different
+ * places depending on UP and SMP...
+ */
+ if (is_setup++)
+ return;
+
+ smu_base = ioremap(EMEV2_SMU_BASE, PAGE_SIZE);
+ BUG_ON(!smu_base);
+
+ /* setup STI timer to run on 37.768 kHz and deassert reset */
+ emev2_smu_write(0, STI_CLKSEL);
+ emev2_smu_write(1, STI_RSTCTRL);
+
+ /* deassert reset for UART0->UART3 */
+ emev2_smu_write(2, USIAU0_RSTCTRL);
+ emev2_smu_write(2, USIBU1_RSTCTRL);
+ emev2_smu_write(2, USIBU2_RSTCTRL);
+ emev2_smu_write(2, USIBU3_RSTCTRL);
+
+ for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
+ ret = clk_register(main_clks[k]);
+
+ if (!ret)
+ ret = emev2_sclkdiv_register(sclkdiv_clks, SCLKDIV_NR);
+
+ if (!ret)
+ ret = emev2_gclk_register(gclk_clks, GCLK_NR);
+
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+
+ if (!ret)
+ shmobile_clk_init();
+ else
+ panic("failed to setup emev2 clocks\n");
+}
diff --git a/arch/arm/mach-shmobile/clock-r8a7740.c b/arch/arm/mach-shmobile/clock-r8a7740.c
index 99c4d743a99c..26eea5f21054 100644
--- a/arch/arm/mach-shmobile/clock-r8a7740.c
+++ b/arch/arm/mach-shmobile/clock-r8a7740.c
@@ -47,6 +47,7 @@
#define PLLC01CR 0xe6150028
#define SUBCKCR 0xe6150080
+#define USBCKCR 0xe615008c
#define MSTPSR0 0xe6150030
#define MSTPSR1 0xe6150038
@@ -181,6 +182,95 @@ static struct clk pllc1_div2_clk = {
.parent = &pllc1_clk,
};
+/* USB clock */
+static struct clk *usb24s_parents[] = {
+ [0] = &system_clk,
+ [1] = &extal2_clk
+};
+
+static int usb24s_enable(struct clk *clk)
+{
+ __raw_writel(__raw_readl(USBCKCR) & ~(1 << 8), USBCKCR);
+
+ return 0;
+}
+
+static void usb24s_disable(struct clk *clk)
+{
+ __raw_writel(__raw_readl(USBCKCR) | (1 << 8), USBCKCR);
+}
+
+static int usb24s_set_parent(struct clk *clk, struct clk *parent)
+{
+ int i, ret;
+ u32 val;
+
+ if (!clk->parent_table || !clk->parent_num)
+ return -EINVAL;
+
+ /* Search the parent */
+ for (i = 0; i < clk->parent_num; i++)
+ if (clk->parent_table[i] == parent)
+ break;
+
+ if (i == clk->parent_num)
+ return -ENODEV;
+
+ ret = clk_reparent(clk, parent);
+ if (ret < 0)
+ return ret;
+
+ val = __raw_readl(USBCKCR);
+ val &= ~(1 << 7);
+ val |= i << 7;
+ __raw_writel(val, USBCKCR);
+
+ return 0;
+}
+
+static struct sh_clk_ops usb24s_clk_ops = {
+ .recalc = followparent_recalc,
+ .enable = usb24s_enable,
+ .disable = usb24s_disable,
+ .set_parent = usb24s_set_parent,
+};
+
+static struct clk usb24s_clk = {
+ .ops = &usb24s_clk_ops,
+ .parent_table = usb24s_parents,
+ .parent_num = ARRAY_SIZE(usb24s_parents),
+ .parent = &system_clk,
+};
+
+static unsigned long usb24_recalc(struct clk *clk)
+{
+ return clk->parent->rate /
+ ((__raw_readl(USBCKCR) & (1 << 6)) ? 1 : 2);
+};
+
+static int usb24_set_rate(struct clk *clk, unsigned long rate)
+{
+ u32 val;
+
+ /* closer to which ? parent->rate or parent->rate/2 */
+ val = __raw_readl(USBCKCR);
+ val &= ~(1 << 6);
+ val |= (rate > (clk->parent->rate / 4) * 3) << 6;
+ __raw_writel(val, USBCKCR);
+
+ return 0;
+}
+
+static struct sh_clk_ops usb24_clk_ops = {
+ .recalc = usb24_recalc,
+ .set_rate = usb24_set_rate,
+};
+
+static struct clk usb24_clk = {
+ .ops = &usb24_clk_ops,
+ .parent = &usb24s_clk,
+};
+
struct clk *main_clks[] = {
&extalr_clk,
&extal1_clk,
@@ -196,6 +286,8 @@ struct clk *main_clks[] = {
&pllc0_clk,
&pllc1_clk,
&pllc1_div2_clk,
+ &usb24s_clk,
+ &usb24_clk,
};
static void div4_kick(struct clk *clk)
@@ -223,7 +315,7 @@ static struct clk_div4_table div4_table = {
enum {
DIV4_I, DIV4_ZG, DIV4_B, DIV4_M1, DIV4_HP,
- DIV4_HPP, DIV4_S, DIV4_ZB, DIV4_M3, DIV4_CP,
+ DIV4_HPP, DIV4_USBP, DIV4_S, DIV4_ZB, DIV4_M3, DIV4_CP,
DIV4_NR
};
@@ -234,6 +326,7 @@ struct clk div4_clks[DIV4_NR] = {
[DIV4_M1] = SH_CLK_DIV4(&pllc1_clk, FRQCRA, 4, 0x6fff, CLK_ENABLE_ON_INIT),
[DIV4_HP] = SH_CLK_DIV4(&pllc1_clk, FRQCRB, 4, 0x6fff, 0),
[DIV4_HPP] = SH_CLK_DIV4(&pllc1_clk, FRQCRC, 20, 0x6fff, 0),
+ [DIV4_USBP] = SH_CLK_DIV4(&pllc1_clk, FRQCRC, 16, 0x6fff, 0),
[DIV4_S] = SH_CLK_DIV4(&pllc1_clk, FRQCRC, 12, 0x6fff, 0),
[DIV4_ZB] = SH_CLK_DIV4(&pllc1_clk, FRQCRC, 8, 0x6fff, 0),
[DIV4_M3] = SH_CLK_DIV4(&pllc1_clk, FRQCRC, 4, 0x6fff, 0),
@@ -257,7 +350,11 @@ enum {
MSTP222,
MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
- MSTP329, MSTP323,
+ MSTP329, MSTP328, MSTP323, MSTP320,
+ MSTP314, MSTP313, MSTP312,
+ MSTP309,
+
+ MSTP416, MSTP415, MSTP407, MSTP406,
MSTP_NR
};
@@ -280,7 +377,18 @@ static struct clk mstp_clks[MSTP_NR] = {
[MSTP200] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */
[MSTP329] = SH_CLK_MSTP32(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */
+ [MSTP328] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR3, 28, 0), /* FSI */
[MSTP323] = SH_CLK_MSTP32(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */
+ [MSTP320] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR3, 20, 0), /* USBF */
+ [MSTP314] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR3, 14, 0), /* SDHI0 */
+ [MSTP313] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR3, 13, 0), /* SDHI1 */
+ [MSTP312] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR3, 12, 0), /* MMC */
+ [MSTP309] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR3, 9, 0), /* GEther */
+
+ [MSTP416] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR4, 16, 0), /* USBHOST */
+ [MSTP415] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR4, 15, 0), /* SDHI2 */
+ [MSTP407] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR4, 7, 0), /* USB-Func */
+ [MSTP406] = SH_CLK_MSTP32(&div4_clks[DIV4_HP], SMSTPCR4, 6, 0), /* USB Phy */
};
static struct clk_lookup lookups[] = {
@@ -299,6 +407,7 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("pllc0_clk", &pllc0_clk),
CLKDEV_CON_ID("pllc1_clk", &pllc1_clk),
CLKDEV_CON_ID("pllc1_div2_clk", &pllc1_div2_clk),
+ CLKDEV_CON_ID("usb24s", &usb24s_clk),
/* DIV4 clocks */
CLKDEV_CON_ID("i_clk", &div4_clks[DIV4_I]),
@@ -334,7 +443,22 @@ static struct clk_lookup lookups[] = {
CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP230]),
CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]),
+ CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]),
CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]),
+ CLKDEV_DEV_ID("renesas_usbhs", &mstp_clks[MSTP320]),
+ CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]),
+ CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]),
+ CLKDEV_DEV_ID("sh_mmcif", &mstp_clks[MSTP312]),
+ CLKDEV_DEV_ID("sh-eth", &mstp_clks[MSTP309]),
+
+ CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP415]),
+
+ /* ICK */
+ CLKDEV_ICK_ID("host", "renesas_usbhs", &mstp_clks[MSTP416]),
+ CLKDEV_ICK_ID("func", "renesas_usbhs", &mstp_clks[MSTP407]),
+ CLKDEV_ICK_ID("phy", "renesas_usbhs", &mstp_clks[MSTP406]),
+ CLKDEV_ICK_ID("pci", "renesas_usbhs", &div4_clks[DIV4_USBP]),
+ CLKDEV_ICK_ID("usb24", "renesas_usbhs", &usb24_clk),
};
void __init r8a7740_clock_init(u8 md_ck)
diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h
index c85e6ecda606..ff5f12fd742f 100644
--- a/arch/arm/mach-shmobile/include/mach/common.h
+++ b/arch/arm/mach-shmobile/include/mach/common.h
@@ -3,6 +3,8 @@
extern void shmobile_earlytimer_init(void);
extern struct sys_timer shmobile_timer;
+extern void shmobile_setup_delay(unsigned int max_cpu_core_mhz,
+ unsigned int mult, unsigned int div);
struct twd_local_timer;
extern void shmobile_setup_console(void);
extern void shmobile_secondary_vector(void);
diff --git a/arch/arm/mach-shmobile/include/mach/emev2.h b/arch/arm/mach-shmobile/include/mach/emev2.h
new file mode 100644
index 000000000000..e6b0c1bf4b7e
--- /dev/null
+++ b/arch/arm/mach-shmobile/include/mach/emev2.h
@@ -0,0 +1,19 @@
+#ifndef __ASM_EMEV2_H__
+#define __ASM_EMEV2_H__
+
+extern void emev2_map_io(void);
+extern void emev2_init_irq(void);
+extern void emev2_add_early_devices(void);
+extern void emev2_add_standard_devices(void);
+extern void emev2_clock_init(void);
+extern void emev2_set_boot_vector(unsigned long value);
+extern unsigned int emev2_get_core_count(void);
+extern int emev2_platform_cpu_kill(unsigned int cpu);
+extern void emev2_secondary_init(unsigned int cpu);
+extern int emev2_boot_secondary(unsigned int cpu);
+extern void emev2_smp_prepare_cpus(void);
+
+#define EMEV2_GPIO_BASE 200
+#define EMEV2_GPIO_IRQ(n) (EMEV2_GPIO_BASE + (n))
+
+#endif /* __ASM_EMEV2_H__ */
diff --git a/arch/arm/mach-shmobile/include/mach/intc.h b/arch/arm/mach-shmobile/include/mach/intc.h
index 8b22258c8caa..a5603c76cfe0 100644
--- a/arch/arm/mach-shmobile/include/mach/intc.h
+++ b/arch/arm/mach-shmobile/include/mach/intc.h
@@ -142,6 +142,50 @@ static struct intc_desc p ## _desc __initdata = { \
p ## _sense_registers, p ## _ack_registers) \
}
+#define INTC_IRQ_PINS_16H(p, base, vect, str) \
+ \
+static struct resource p ## _resources[] __initdata = { \
+ [0] = { \
+ .start = base, \
+ .end = base + 0x64, \
+ .flags = IORESOURCE_MEM, \
+ }, \
+}; \
+ \
+enum { \
+ p ## _UNUSED = 0, \
+ INTC_IRQ_PINS_ENUM_16H(p), \
+}; \
+ \
+static struct intc_vect p ## _vectors[] __initdata = { \
+ INTC_IRQ_PINS_VECT_16H(p, vect), \
+}; \
+ \
+static struct intc_mask_reg p ## _mask_registers[] __initdata = { \
+ INTC_IRQ_PINS_MASK_16H(p, base), \
+}; \
+ \
+static struct intc_prio_reg p ## _prio_registers[] __initdata = { \
+ INTC_IRQ_PINS_PRIO_16H(p, base), \
+}; \
+ \
+static struct intc_sense_reg p ## _sense_registers[] __initdata = { \
+ INTC_IRQ_PINS_SENSE_16H(p, base), \
+}; \
+ \
+static struct intc_mask_reg p ## _ack_registers[] __initdata = { \
+ INTC_IRQ_PINS_ACK_16H(p, base), \
+}; \
+ \
+static struct intc_desc p ## _desc __initdata = { \
+ .name = str, \
+ .resource = p ## _resources, \
+ .num_resources = ARRAY_SIZE(p ## _resources), \
+ .hw = INTC_HW_DESC(p ## _vectors, NULL, \
+ p ## _mask_registers, p ## _prio_registers, \
+ p ## _sense_registers, p ## _ack_registers) \
+}
+
#define INTC_IRQ_PINS_32(p, base, vect, str) \
\
static struct resource p ## _resources[] __initdata = { \
diff --git a/arch/arm/mach-shmobile/include/mach/irqs.h b/arch/arm/mach-shmobile/include/mach/irqs.h
index 4e686cc201fc..06a5da3c3050 100644
--- a/arch/arm/mach-shmobile/include/mach/irqs.h
+++ b/arch/arm/mach-shmobile/include/mach/irqs.h
@@ -7,7 +7,7 @@
#define gic_spi(nr) ((nr) + 32)
/* INTCS */
-#define INTCS_VECT_BASE 0x2200
+#define INTCS_VECT_BASE 0x3400
#define INTCS_VECT(n, vect) INTC_VECT((n), INTCS_VECT_BASE + (vect))
#define intcs_evt2irq(evt) evt2irq(INTCS_VECT_BASE + (evt))
diff --git a/arch/arm/mach-shmobile/include/mach/sh7372.h b/arch/arm/mach-shmobile/include/mach/sh7372.h
index 8254ab86f6cd..915d0093da08 100644
--- a/arch/arm/mach-shmobile/include/mach/sh7372.h
+++ b/arch/arm/mach-shmobile/include/mach/sh7372.h
@@ -457,6 +457,8 @@ enum {
SHDMA_SLAVE_SDHI1_TX,
SHDMA_SLAVE_SDHI2_RX,
SHDMA_SLAVE_SDHI2_TX,
+ SHDMA_SLAVE_FSIA_RX,
+ SHDMA_SLAVE_FSIA_TX,
SHDMA_SLAVE_MMCIF_RX,
SHDMA_SLAVE_MMCIF_TX,
SHDMA_SLAVE_USB0_TX,
diff --git a/arch/arm/mach-shmobile/include/mach/sh73a0.h b/arch/arm/mach-shmobile/include/mach/sh73a0.h
index cad57578ceed..398e2c10913b 100644
--- a/arch/arm/mach-shmobile/include/mach/sh73a0.h
+++ b/arch/arm/mach-shmobile/include/mach/sh73a0.h
@@ -482,6 +482,9 @@ enum {
GPIO_FN_FSIAILR_PU,
GPIO_FN_FSIAIBT_PU,
GPIO_FN_FSIAISLD_PU,
+
+ /* end of GPIO */
+ GPIO_NR,
};
/* DMA slave IDs */
@@ -515,8 +518,36 @@ enum {
SHDMA_SLAVE_MMCIF_RX,
};
-/* PINT interrupts are located at Linux IRQ 800 and up */
-#define SH73A0_PINT0_IRQ(irq) ((irq) + 800)
-#define SH73A0_PINT1_IRQ(irq) ((irq) + 832)
+/*
+ * SH73A0 IRQ LOCATION TABLE
+ *
+ * 416 -----------------------------------------
+ * IRQ0-IRQ15
+ * 431 -----------------------------------------
+ * ...
+ * 448 -----------------------------------------
+ * sh73a0-intcs
+ * sh73a0-intca-irq-pins
+ * 680 -----------------------------------------
+ * ...
+ * 700 -----------------------------------------
+ * sh73a0-pint0
+ * 731 -----------------------------------------
+ * 732 -----------------------------------------
+ * sh73a0-pint1
+ * 739 -----------------------------------------
+ * ...
+ * 800 -----------------------------------------
+ * IRQ16-IRQ31
+ * 815 -----------------------------------------
+ * ...
+ * 928 -----------------------------------------
+ * sh73a0-intca-irq-pins
+ * 943 -----------------------------------------
+ */
+
+/* PINT interrupts are located at Linux IRQ 700 and up */
+#define SH73A0_PINT0_IRQ(irq) ((irq) + 700)
+#define SH73A0_PINT1_IRQ(irq) ((irq) + 732)
#endif /* __ASM_SH73A0_H__ */
diff --git a/arch/arm/mach-shmobile/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c
index 6447e0af52d4..2587a22842f2 100644
--- a/arch/arm/mach-shmobile/intc-sh7372.c
+++ b/arch/arm/mach-shmobile/intc-sh7372.c
@@ -19,6 +19,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/module.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/sh_intc.h>
@@ -305,14 +306,16 @@ static DECLARE_INTC_DESC(intca_desc, "sh7372-intca",
intca_mask_registers, intca_prio_registers,
NULL);
-INTC_IRQ_PINS_32(intca_irq_pins, 0xe6900000,
- INTC_VECT, "sh7372-intca-irq-pins");
+INTC_IRQ_PINS_16(intca_irq_pins_lo, 0xe6900000,
+ INTC_VECT, "sh7372-intca-irq-lo");
+
+INTC_IRQ_PINS_16H(intca_irq_pins_hi, 0xe6900000,
+ INTC_VECT, "sh7372-intca-irq-hi");
+
enum {
UNUSED_INTCS = 0,
ENABLED_INTCS,
- INTCS,
-
/* interrupt sources INTCS */
/* IRQ0S - IRQ31S */
@@ -426,8 +429,6 @@ static struct intc_vect intcs_vectors[] = {
INTCS_VECT(CPORTS2R, 0x1a20),
/* CEC */
INTCS_VECT(JPU6E, 0x1a80),
-
- INTC_VECT(INTCS, 0xf80),
};
static struct intc_group intcs_groups[] __initdata = {
@@ -490,9 +491,6 @@ static struct intc_mask_reg intcs_mask_registers[] = {
{ 0xffd5019c, 0xffd501dc, 8, /* IMR7SA3 / IMCR7SA3 */
{ MFIS2_INTCS, CPORTS2R, 0, 0,
JPU6E, 0, 0, 0 } },
- { 0xffd20104, 0, 16, /* INTAMASK */
- { 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, INTCS } },
};
/* Priority is needed for INTCA to receive the INTCS interrupt */
@@ -557,18 +555,30 @@ static void __iomem *intcs_ffd5;
void __init sh7372_init_irq(void)
{
void __iomem *intevtsa;
+ int n;
intcs_ffd2 = ioremap_nocache(0xffd20000, PAGE_SIZE);
intevtsa = intcs_ffd2 + 0x100;
intcs_ffd5 = ioremap_nocache(0xffd50000, PAGE_SIZE);
register_intc_controller(&intca_desc);
- register_intc_controller(&intca_irq_pins_desc);
+ register_intc_controller(&intca_irq_pins_lo_desc);
+ register_intc_controller(&intca_irq_pins_hi_desc);
register_intc_controller(&intcs_desc);
+ /* setup dummy cascade chip for INTCS */
+ n = evt2irq(0xf80);
+ irq_alloc_desc_at(n, numa_node_id());
+ irq_set_chip_and_handler_name(n, &dummy_irq_chip,
+ handle_level_irq, "level");
+ set_irq_flags(n, IRQF_VALID); /* yuck */
+
/* demux using INTEVTSA */
- irq_set_handler_data(evt2irq(0xf80), (void *)intevtsa);
- irq_set_chained_handler(evt2irq(0xf80), intcs_demux);
+ irq_set_handler_data(n, (void *)intevtsa);
+ irq_set_chained_handler(n, intcs_demux);
+
+ /* unmask INTCS in INTAMASK */
+ iowrite16(0, intcs_ffd2 + 0x104);
}
static unsigned short ffd2[0x200];
diff --git a/arch/arm/mach-shmobile/pfc-r8a7740.c b/arch/arm/mach-shmobile/pfc-r8a7740.c
index a4fff6950b03..670fe1869dbc 100644
--- a/arch/arm/mach-shmobile/pfc-r8a7740.c
+++ b/arch/arm/mach-shmobile/pfc-r8a7740.c
@@ -22,6 +22,7 @@
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <mach/r8a7740.h>
+#include <mach/irqs.h>
#define CPU_ALL_PORT(fn, pfx, sfx) \
PORT_10(fn, pfx, sfx), PORT_90(fn, pfx, sfx), \
@@ -2527,6 +2528,41 @@ static struct pinmux_data_reg pinmux_data_regs[] = {
{ },
};
+static struct pinmux_irq pinmux_irqs[] = {
+ PINMUX_IRQ(evt2irq(0x0200), PORT2_FN0, PORT13_FN0), /* IRQ0A */
+ PINMUX_IRQ(evt2irq(0x0220), PORT20_FN0), /* IRQ1A */
+ PINMUX_IRQ(evt2irq(0x0240), PORT11_FN0, PORT12_FN0), /* IRQ2A */
+ PINMUX_IRQ(evt2irq(0x0260), PORT10_FN0, PORT14_FN0), /* IRQ3A */
+ PINMUX_IRQ(evt2irq(0x0280), PORT15_FN0, PORT172_FN0), /* IRQ4A */
+ PINMUX_IRQ(evt2irq(0x02A0), PORT0_FN0, PORT1_FN0), /* IRQ5A */
+ PINMUX_IRQ(evt2irq(0x02C0), PORT121_FN0, PORT173_FN0), /* IRQ6A */
+ PINMUX_IRQ(evt2irq(0x02E0), PORT120_FN0, PORT209_FN0), /* IRQ7A */
+ PINMUX_IRQ(evt2irq(0x0300), PORT119_FN0), /* IRQ8A */
+ PINMUX_IRQ(evt2irq(0x0320), PORT118_FN0, PORT210_FN0), /* IRQ9A */
+ PINMUX_IRQ(evt2irq(0x0340), PORT19_FN0), /* IRQ10A */
+ PINMUX_IRQ(evt2irq(0x0360), PORT104_FN0), /* IRQ11A */
+ PINMUX_IRQ(evt2irq(0x0380), PORT42_FN0, PORT97_FN0), /* IRQ12A */
+ PINMUX_IRQ(evt2irq(0x03A0), PORT64_FN0, PORT98_FN0), /* IRQ13A */
+ PINMUX_IRQ(evt2irq(0x03C0), PORT63_FN0, PORT99_FN0), /* IRQ14A */
+ PINMUX_IRQ(evt2irq(0x03E0), PORT62_FN0, PORT100_FN0), /* IRQ15A */
+ PINMUX_IRQ(evt2irq(0x3200), PORT68_FN0, PORT211_FN0), /* IRQ16A */
+ PINMUX_IRQ(evt2irq(0x3220), PORT69_FN0), /* IRQ17A */
+ PINMUX_IRQ(evt2irq(0x3240), PORT70_FN0), /* IRQ18A */
+ PINMUX_IRQ(evt2irq(0x3260), PORT71_FN0), /* IRQ19A */
+ PINMUX_IRQ(evt2irq(0x3280), PORT67_FN0), /* IRQ20A */
+ PINMUX_IRQ(evt2irq(0x32A0), PORT202_FN0), /* IRQ21A */
+ PINMUX_IRQ(evt2irq(0x32C0), PORT95_FN0), /* IRQ22A */
+ PINMUX_IRQ(evt2irq(0x32E0), PORT96_FN0), /* IRQ23A */
+ PINMUX_IRQ(evt2irq(0x3300), PORT180_FN0), /* IRQ24A */
+ PINMUX_IRQ(evt2irq(0x3320), PORT38_FN0), /* IRQ25A */
+ PINMUX_IRQ(evt2irq(0x3340), PORT58_FN0, PORT81_FN0), /* IRQ26A */
+ PINMUX_IRQ(evt2irq(0x3360), PORT57_FN0, PORT168_FN0), /* IRQ27A */
+ PINMUX_IRQ(evt2irq(0x3380), PORT56_FN0, PORT169_FN0), /* IRQ28A */
+ PINMUX_IRQ(evt2irq(0x33A0), PORT50_FN0, PORT170_FN0), /* IRQ29A */
+ PINMUX_IRQ(evt2irq(0x33C0), PORT49_FN0, PORT171_FN0), /* IRQ30A */
+ PINMUX_IRQ(evt2irq(0x33E0), PORT41_FN0, PORT167_FN0), /* IRQ31A */
+};
+
static struct pinmux_info r8a7740_pinmux_info = {
.name = "r8a7740_pfc",
.reserved_id = PINMUX_RESERVED,
@@ -2554,6 +2590,9 @@ static struct pinmux_info r8a7740_pinmux_info = {
.gpio_data = pinmux_data,
.gpio_data_size = ARRAY_SIZE(pinmux_data),
+
+ .gpio_irq = pinmux_irqs,
+ .gpio_irq_size = ARRAY_SIZE(pinmux_irqs),
};
void r8a7740_pinmux_init(void)
diff --git a/arch/arm/mach-shmobile/pfc-sh73a0.c b/arch/arm/mach-shmobile/pfc-sh73a0.c
index e05634ce2e0d..4a547b803268 100644
--- a/arch/arm/mach-shmobile/pfc-sh73a0.c
+++ b/arch/arm/mach-shmobile/pfc-sh73a0.c
@@ -829,14 +829,14 @@ static pinmux_enum_t pinmux_data[] = {
PINMUX_DATA(PORT27_I2C_SCL2_MARK, PORT27_FN2, MSEL2CR_MSEL17_0,
MSEL2CR_MSEL16_1), \
PINMUX_DATA(PORT27_I2C_SCL3_MARK, PORT27_FN3, MSEL2CR_MSEL19_0,
- MSEL2CR_MSEL18_0), \
+ MSEL2CR_MSEL18_1), \
PINMUX_DATA(MFG0_OUT1_MARK, PORT27_FN4), \
PINMUX_DATA(PORT27_IROUT_MARK, PORT27_FN7),
PINMUX_DATA(XDVFS2_MARK, PORT28_FN1), \
PINMUX_DATA(PORT28_I2C_SDA2_MARK, PORT28_FN2, MSEL2CR_MSEL17_0,
MSEL2CR_MSEL16_1), \
PINMUX_DATA(PORT28_I2C_SDA3_MARK, PORT28_FN3, MSEL2CR_MSEL19_0,
- MSEL2CR_MSEL18_0), \
+ MSEL2CR_MSEL18_1), \
PINMUX_DATA(PORT28_TPU1TO1_MARK, PORT28_FN7),
PINMUX_DATA(SIM_RST_MARK, PORT29_FN1), \
PINMUX_DATA(PORT29_TPU1TO1_MARK, PORT29_FN4),
diff --git a/arch/arm/mach-shmobile/platsmp.c b/arch/arm/mach-shmobile/platsmp.c
index 45fa3924c6a1..bacdd667e3b1 100644
--- a/arch/arm/mach-shmobile/platsmp.c
+++ b/arch/arm/mach-shmobile/platsmp.c
@@ -16,12 +16,16 @@
#include <linux/device.h>
#include <linux/smp.h>
#include <linux/io.h>
+#include <linux/of.h>
#include <asm/hardware/gic.h>
#include <asm/mach-types.h>
#include <mach/common.h>
+#include <mach/emev2.h>
-#define is_sh73a0() (machine_is_ag5evm() || machine_is_kota2())
+#define is_sh73a0() (machine_is_ag5evm() || machine_is_kota2() || \
+ of_machine_is_compatible("renesas,sh73a0"))
#define is_r8a7779() machine_is_marzen()
+#define is_emev2() of_machine_is_compatible("renesas,emev2")
static unsigned int __init shmobile_smp_get_core_count(void)
{
@@ -31,6 +35,9 @@ static unsigned int __init shmobile_smp_get_core_count(void)
if (is_r8a7779())
return r8a7779_get_core_count();
+ if (is_emev2())
+ return emev2_get_core_count();
+
return 1;
}
@@ -41,6 +48,9 @@ static void __init shmobile_smp_prepare_cpus(void)
if (is_r8a7779())
r8a7779_smp_prepare_cpus();
+
+ if (is_emev2())
+ emev2_smp_prepare_cpus();
}
int shmobile_platform_cpu_kill(unsigned int cpu)
@@ -48,6 +58,9 @@ int shmobile_platform_cpu_kill(unsigned int cpu)
if (is_r8a7779())
return r8a7779_platform_cpu_kill(cpu);
+ if (is_emev2())
+ return emev2_platform_cpu_kill(cpu);
+
return 1;
}
@@ -60,6 +73,9 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
if (is_r8a7779())
r8a7779_secondary_init(cpu);
+
+ if (is_emev2())
+ emev2_secondary_init(cpu);
}
int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
@@ -70,6 +86,9 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
if (is_r8a7779())
return r8a7779_boot_secondary(cpu);
+ if (is_emev2())
+ return emev2_boot_secondary(cpu);
+
return -ENOSYS;
}
diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c
new file mode 100644
index 000000000000..dae9aa68bb09
--- /dev/null
+++ b/arch/arm/mach-shmobile/setup-emev2.c
@@ -0,0 +1,452 @@
+/*
+ * Emma Mobile EV2 processor support
+ *
+ * Copyright (C) 2012 Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/gpio-em.h>
+#include <linux/of_platform.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/io.h>
+#include <linux/of_irq.h>
+#include <mach/hardware.h>
+#include <mach/common.h>
+#include <mach/emev2.h>
+#include <mach/irqs.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+#include <asm/hardware/gic.h>
+
+static struct map_desc emev2_io_desc[] __initdata = {
+#ifdef CONFIG_SMP
+ /* 128K entity map for 0xe0100000 (SMU) */
+ {
+ .virtual = 0xe0100000,
+ .pfn = __phys_to_pfn(0xe0100000),
+ .length = SZ_128K,
+ .type = MT_DEVICE
+ },
+ /* 2M mapping for SCU + L2 controller */
+ {
+ .virtual = 0xf0000000,
+ .pfn = __phys_to_pfn(0x1e000000),
+ .length = SZ_2M,
+ .type = MT_DEVICE
+ },
+#endif
+};
+
+void __init emev2_map_io(void)
+{
+ iotable_init(emev2_io_desc, ARRAY_SIZE(emev2_io_desc));
+}
+
+/* UART */
+static struct resource uart0_resources[] = {
+ [0] = {
+ .start = 0xe1020000,
+ .end = 0xe1020037,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 40,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device uart0_device = {
+ .name = "serial8250-em",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(uart0_resources),
+ .resource = uart0_resources,
+};
+
+static struct resource uart1_resources[] = {
+ [0] = {
+ .start = 0xe1030000,
+ .end = 0xe1030037,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 41,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device uart1_device = {
+ .name = "serial8250-em",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(uart1_resources),
+ .resource = uart1_resources,
+};
+
+static struct resource uart2_resources[] = {
+ [0] = {
+ .start = 0xe1040000,
+ .end = 0xe1040037,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 42,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device uart2_device = {
+ .name = "serial8250-em",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(uart2_resources),
+ .resource = uart2_resources,
+};
+
+static struct resource uart3_resources[] = {
+ [0] = {
+ .start = 0xe1050000,
+ .end = 0xe1050037,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 43,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device uart3_device = {
+ .name = "serial8250-em",
+ .id = 3,
+ .num_resources = ARRAY_SIZE(uart3_resources),
+ .resource = uart3_resources,
+};
+
+/* STI */
+static struct resource sti_resources[] = {
+ [0] = {
+ .name = "STI",
+ .start = 0xe0180000,
+ .end = 0xe0180053,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 157,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sti_device = {
+ .name = "em_sti",
+ .id = 0,
+ .resource = sti_resources,
+ .num_resources = ARRAY_SIZE(sti_resources),
+};
+
+
+/* GIO */
+static struct gpio_em_config gio0_config = {
+ .gpio_base = 0,
+ .irq_base = EMEV2_GPIO_IRQ(0),
+ .number_of_pins = 32,
+};
+
+static struct resource gio0_resources[] = {
+ [0] = {
+ .name = "GIO_000",
+ .start = 0xe0050000,
+ .end = 0xe005002b,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "GIO_000",
+ .start = 0xe0050040,
+ .end = 0xe005005f,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .start = 99,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .start = 100,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device gio0_device = {
+ .name = "em_gio",
+ .id = 0,
+ .resource = gio0_resources,
+ .num_resources = ARRAY_SIZE(gio0_resources),
+ .dev = {
+ .platform_data = &gio0_config,
+ },
+};
+
+static struct gpio_em_config gio1_config = {
+ .gpio_base = 32,
+ .irq_base = EMEV2_GPIO_IRQ(32),
+ .number_of_pins = 32,
+};
+
+static struct resource gio1_resources[] = {
+ [0] = {
+ .name = "GIO_032",
+ .start = 0xe0050080,
+ .end = 0xe00500ab,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "GIO_032",
+ .start = 0xe00500c0,
+ .end = 0xe00500df,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .start = 101,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .start = 102,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device gio1_device = {
+ .name = "em_gio",
+ .id = 1,
+ .resource = gio1_resources,
+ .num_resources = ARRAY_SIZE(gio1_resources),
+ .dev = {
+ .platform_data = &gio1_config,
+ },
+};
+
+static struct gpio_em_config gio2_config = {
+ .gpio_base = 64,
+ .irq_base = EMEV2_GPIO_IRQ(64),
+ .number_of_pins = 32,
+};
+
+static struct resource gio2_resources[] = {
+ [0] = {
+ .name = "GIO_064",
+ .start = 0xe0050100,
+ .end = 0xe005012b,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "GIO_064",
+ .start = 0xe0050140,
+ .end = 0xe005015f,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .start = 103,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .start = 104,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device gio2_device = {
+ .name = "em_gio",
+ .id = 2,
+ .resource = gio2_resources,
+ .num_resources = ARRAY_SIZE(gio2_resources),
+ .dev = {
+ .platform_data = &gio2_config,
+ },
+};
+
+static struct gpio_em_config gio3_config = {
+ .gpio_base = 96,
+ .irq_base = EMEV2_GPIO_IRQ(96),
+ .number_of_pins = 32,
+};
+
+static struct resource gio3_resources[] = {
+ [0] = {
+ .name = "GIO_096",
+ .start = 0xe0050100,
+ .end = 0xe005012b,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "GIO_096",
+ .start = 0xe0050140,
+ .end = 0xe005015f,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .start = 105,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .start = 106,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device gio3_device = {
+ .name = "em_gio",
+ .id = 3,
+ .resource = gio3_resources,
+ .num_resources = ARRAY_SIZE(gio3_resources),
+ .dev = {
+ .platform_data = &gio3_config,
+ },
+};
+
+static struct gpio_em_config gio4_config = {
+ .gpio_base = 128,
+ .irq_base = EMEV2_GPIO_IRQ(128),
+ .number_of_pins = 31,
+};
+
+static struct resource gio4_resources[] = {
+ [0] = {
+ .name = "GIO_128",
+ .start = 0xe0050200,
+ .end = 0xe005022b,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "GIO_128",
+ .start = 0xe0050240,
+ .end = 0xe005025f,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .start = 107,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .start = 108,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device gio4_device = {
+ .name = "em_gio",
+ .id = 4,
+ .resource = gio4_resources,
+ .num_resources = ARRAY_SIZE(gio4_resources),
+ .dev = {
+ .platform_data = &gio4_config,
+ },
+};
+
+static struct platform_device *emev2_early_devices[] __initdata = {
+ &uart0_device,
+ &uart1_device,
+ &uart2_device,
+ &uart3_device,
+};
+
+static struct platform_device *emev2_late_devices[] __initdata = {
+ &sti_device,
+ &gio0_device,
+ &gio1_device,
+ &gio2_device,
+ &gio3_device,
+ &gio4_device,
+};
+
+void __init emev2_add_standard_devices(void)
+{
+ emev2_clock_init();
+
+ platform_add_devices(emev2_early_devices,
+ ARRAY_SIZE(emev2_early_devices));
+
+ platform_add_devices(emev2_late_devices,
+ ARRAY_SIZE(emev2_late_devices));
+}
+
+void __init emev2_init_delay(void)
+{
+ shmobile_setup_delay(533, 1, 3); /* Cortex-A9 @ 533MHz */
+}
+
+void __init emev2_add_early_devices(void)
+{
+ emev2_init_delay();
+
+ early_platform_add_devices(emev2_early_devices,
+ ARRAY_SIZE(emev2_early_devices));
+
+ /* setup early console here as well */
+ shmobile_setup_console();
+}
+
+void __init emev2_init_irq(void)
+{
+ void __iomem *gic_dist_base;
+ void __iomem *gic_cpu_base;
+
+ /* Static mappings, never released */
+ gic_dist_base = ioremap(0xe0028000, PAGE_SIZE);
+ gic_cpu_base = ioremap(0xe0020000, PAGE_SIZE);
+ BUG_ON(!gic_dist_base || !gic_cpu_base);
+
+ /* Use GIC to handle interrupts */
+ gic_init(0, 29, gic_dist_base, gic_cpu_base);
+}
+
+#ifdef CONFIG_USE_OF
+static const struct of_dev_auxdata emev2_auxdata_lookup[] __initconst = {
+ { }
+};
+
+void __init emev2_add_standard_devices_dt(void)
+{
+ of_platform_populate(NULL, of_default_bus_match_table,
+ emev2_auxdata_lookup, NULL);
+}
+
+static const struct of_device_id emev2_dt_irq_match[] = {
+ { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
+ {},
+};
+
+static const char *emev2_boards_compat_dt[] __initdata = {
+ "renesas,emev2",
+ NULL,
+};
+
+void __init emev2_init_irq_dt(void)
+{
+ of_irq_init(emev2_dt_irq_match);
+}
+
+DT_MACHINE_START(EMEV2_DT, "Generic Emma Mobile EV2 (Flattened Device Tree)")
+ .init_early = emev2_init_delay,
+ .nr_irqs = NR_IRQS_LEGACY,
+ .init_irq = emev2_init_irq_dt,
+ .handle_irq = gic_handle_irq,
+ .init_machine = emev2_add_standard_devices_dt,
+ .timer = &shmobile_timer,
+ .dt_compat = emev2_boards_compat_dt,
+MACHINE_END
+
+#endif /* CONFIG_USE_OF */
diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c
index 14edb5cffa7f..ec4eb49c1693 100644
--- a/arch/arm/mach-shmobile/setup-r8a7740.c
+++ b/arch/arm/mach-shmobile/setup-r8a7740.c
@@ -18,6 +18,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/delay.h>
+#include <linux/dma-mapping.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
@@ -60,6 +61,12 @@ static struct map_desc r8a7740_io_desc[] __initdata = {
void __init r8a7740_map_io(void)
{
iotable_init(r8a7740_io_desc, ARRAY_SIZE(r8a7740_io_desc));
+
+ /*
+ * DMA memory at 0xff200000 - 0xffdfffff. The default 2MB size isn't
+ * enough to allocate the frame buffer memory.
+ */
+ init_consistent_dma_size(12 << 20);
}
/* SCIFA0 */
@@ -350,19 +357,19 @@ static void r8a7740_i2c_workaround(struct platform_device *pdev)
i2c_write(reg, ICSTART, i2c_read(reg, ICSTART) | 0x10);
i2c_read(reg, ICSTART); /* dummy read */
- mdelay(100);
+ udelay(10);
i2c_write(reg, ICCR, 0x01);
- i2c_read(reg, ICCR);
i2c_write(reg, ICSTART, 0x00);
- i2c_read(reg, ICSTART);
+
+ udelay(10);
i2c_write(reg, ICCR, 0x10);
- mdelay(100);
+ udelay(10);
i2c_write(reg, ICCR, 0x00);
- mdelay(100);
+ udelay(10);
i2c_write(reg, ICCR, 0x10);
- mdelay(100);
+ udelay(10);
iounmap(reg);
}
diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c
index 2fe8f83ca124..6a4bd582c028 100644
--- a/arch/arm/mach-shmobile/setup-sh7372.c
+++ b/arch/arm/mach-shmobile/setup-sh7372.c
@@ -22,6 +22,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
+#include <linux/of_platform.h>
#include <linux/uio_driver.h>
#include <linux/delay.h>
#include <linux/input.h>
@@ -461,6 +462,16 @@ static const struct sh_dmae_slave_config sh7372_dmae_slaves[] = {
.chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT),
.mid_rid = 0xce,
}, {
+ .slave_id = SHDMA_SLAVE_FSIA_TX,
+ .addr = 0xfe1f0024,
+ .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT),
+ .mid_rid = 0xb1,
+ }, {
+ .slave_id = SHDMA_SLAVE_FSIA_RX,
+ .addr = 0xfe1f0020,
+ .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT),
+ .mid_rid = 0xb2,
+ }, {
.slave_id = SHDMA_SLAVE_MMCIF_TX,
.addr = 0xe6bd0034,
.chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_32BIT),
@@ -1092,3 +1103,50 @@ void __init sh7372_add_early_devices(void)
/* override timer setup with soc-specific code */
shmobile_timer.init = sh7372_earlytimer_init;
}
+
+#ifdef CONFIG_USE_OF
+
+void __init sh7372_add_early_devices_dt(void)
+{
+ shmobile_setup_delay(800, 1, 3); /* Cortex-A8 @ 800MHz */
+
+ early_platform_add_devices(sh7372_early_devices,
+ ARRAY_SIZE(sh7372_early_devices));
+
+ /* setup early console here as well */
+ shmobile_setup_console();
+}
+
+static const struct of_dev_auxdata sh7372_auxdata_lookup[] __initconst = {
+ { }
+};
+
+void __init sh7372_add_standard_devices_dt(void)
+{
+ /* clocks are setup late during boot in the case of DT */
+ sh7372_clock_init();
+
+ platform_add_devices(sh7372_early_devices,
+ ARRAY_SIZE(sh7372_early_devices));
+
+ of_platform_populate(NULL, of_default_bus_match_table,
+ sh7372_auxdata_lookup, NULL);
+}
+
+static const char *sh7372_boards_compat_dt[] __initdata = {
+ "renesas,sh7372",
+ NULL,
+};
+
+DT_MACHINE_START(SH7372_DT, "Generic SH7372 (Flattened Device Tree)")
+ .map_io = sh7372_map_io,
+ .init_early = sh7372_add_early_devices_dt,
+ .nr_irqs = NR_IRQS_LEGACY,
+ .init_irq = sh7372_init_irq,
+ .handle_irq = shmobile_handle_irq_intc,
+ .init_machine = sh7372_add_standard_devices_dt,
+ .timer = &shmobile_timer,
+ .dt_compat = sh7372_boards_compat_dt,
+MACHINE_END
+
+#endif /* CONFIG_USE_OF */
diff --git a/arch/arm/mach-shmobile/smp-emev2.c b/arch/arm/mach-shmobile/smp-emev2.c
new file mode 100644
index 000000000000..6a35c4a31e6c
--- /dev/null
+++ b/arch/arm/mach-shmobile/smp-emev2.c
@@ -0,0 +1,97 @@
+/*
+ * SMP support for Emma Mobile EV2
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ * Copyright (C) 2012 Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <mach/common.h>
+#include <mach/emev2.h>
+#include <asm/smp_plat.h>
+#include <asm/smp_scu.h>
+#include <asm/hardware/gic.h>
+#include <asm/cacheflush.h>
+
+#define EMEV2_SCU_BASE 0x1e000000
+
+static DEFINE_SPINLOCK(scu_lock);
+static void __iomem *scu_base;
+
+static void modify_scu_cpu_psr(unsigned long set, unsigned long clr)
+{
+ unsigned long tmp;
+
+ /* we assume this code is running on a different cpu
+ * than the one that is changing coherency setting */
+ spin_lock(&scu_lock);
+ tmp = readl(scu_base + 8);
+ tmp &= ~clr;
+ tmp |= set;
+ writel(tmp, scu_base + 8);
+ spin_unlock(&scu_lock);
+
+}
+
+unsigned int __init emev2_get_core_count(void)
+{
+ if (!scu_base) {
+ scu_base = ioremap(EMEV2_SCU_BASE, PAGE_SIZE);
+ emev2_clock_init(); /* need ioremapped SMU */
+ }
+
+ WARN_ON_ONCE(!scu_base);
+
+ return scu_base ? scu_get_core_count(scu_base) : 1;
+}
+
+int emev2_platform_cpu_kill(unsigned int cpu)
+{
+ return 0; /* not supported yet */
+}
+
+void __cpuinit emev2_secondary_init(unsigned int cpu)
+{
+ gic_secondary_init(0);
+}
+
+int __cpuinit emev2_boot_secondary(unsigned int cpu)
+{
+ cpu = cpu_logical_map(cpu);
+
+ /* enable cache coherency */
+ modify_scu_cpu_psr(0, 3 << (cpu * 8));
+
+ /* Tell ROM loader about our vector (in headsmp.S) */
+ emev2_set_boot_vector(__pa(shmobile_secondary_vector));
+
+ gic_raise_softirq(cpumask_of(cpu), 1);
+ return 0;
+}
+
+void __init emev2_smp_prepare_cpus(void)
+{
+ int cpu = cpu_logical_map(0);
+
+ scu_enable(scu_base);
+
+ /* enable cache coherency on CPU0 */
+ modify_scu_cpu_psr(0, 3 << (cpu * 8));
+}
diff --git a/arch/arm/mach-shmobile/timer.c b/arch/arm/mach-shmobile/timer.c
index 8b79e7917a23..a68919727e24 100644
--- a/arch/arm/mach-shmobile/timer.c
+++ b/arch/arm/mach-shmobile/timer.c
@@ -19,9 +19,27 @@
*
*/
#include <linux/platform_device.h>
+#include <linux/delay.h>
#include <asm/mach/time.h>
#include <asm/smp_twd.h>
+void __init shmobile_setup_delay(unsigned int max_cpu_core_mhz,
+ unsigned int mult, unsigned int div)
+{
+ /* calculate a worst-case loops-per-jiffy value
+ * based on maximum cpu core mhz setting and the
+ * __delay() implementation in arch/arm/lib/delay.S
+ *
+ * this will result in a longer delay than expected
+ * when the cpu core runs on lower frequencies.
+ */
+
+ unsigned int value = (1000000 * mult) / (HZ * div);
+
+ if (!preset_lpj)
+ preset_lpj = max_cpu_core_mhz * value;
+}
+
static void __init shmobile_late_time_init(void)
{
/*
diff --git a/arch/arm/mach-spear3xx/Kconfig b/arch/arm/mach-spear3xx/Kconfig
index 2cee6b0de371..8bd37291fa4f 100644
--- a/arch/arm/mach-spear3xx/Kconfig
+++ b/arch/arm/mach-spear3xx/Kconfig
@@ -5,39 +5,22 @@
if ARCH_SPEAR3XX
menu "SPEAr3xx Implementations"
-config BOARD_SPEAR300_EVB
- bool "SPEAr300 Evaluation Board"
- select MACH_SPEAR300
- help
- Supports ST SPEAr300 Evaluation Board
-
-config BOARD_SPEAR310_EVB
- bool "SPEAr310 Evaluation Board"
- select MACH_SPEAR310
- help
- Supports ST SPEAr310 Evaluation Board
-
-config BOARD_SPEAR320_EVB
- bool "SPEAr320 Evaluation Board"
- select MACH_SPEAR320
- help
- Supports ST SPEAr320 Evaluation Board
-
-endmenu
-
config MACH_SPEAR300
- bool "SPEAr300"
+ bool "SPEAr300 Machine support with Device Tree"
+ select PINCTRL_SPEAR300
help
- Supports ST SPEAr300 Machine
+ Supports ST SPEAr300 machine configured via the device-tree
config MACH_SPEAR310
- bool "SPEAr310"
+ bool "SPEAr310 Machine support with Device Tree"
+ select PINCTRL_SPEAR310
help
- Supports ST SPEAr310 Machine
+ Supports ST SPEAr310 machine configured via the device-tree
config MACH_SPEAR320
- bool "SPEAr320"
+ bool "SPEAr320 Machine support with Device Tree"
+ select PINCTRL_SPEAR320
help
- Supports ST SPEAr320 Machine
-
+ Supports ST SPEAr320 machine configured via the device-tree
+endmenu
endif #ARCH_SPEAR3XX
diff --git a/arch/arm/mach-spear3xx/Makefile b/arch/arm/mach-spear3xx/Makefile
index b24862489704..17b5d83cf2d5 100644
--- a/arch/arm/mach-spear3xx/Makefile
+++ b/arch/arm/mach-spear3xx/Makefile
@@ -3,24 +3,13 @@
#
# common files
-obj-y += spear3xx.o clock.o
+obj-$(CONFIG_ARCH_SPEAR3XX) += spear3xx.o clock.o
# spear300 specific files
obj-$(CONFIG_MACH_SPEAR300) += spear300.o
-# spear300 boards files
-obj-$(CONFIG_BOARD_SPEAR300_EVB) += spear300_evb.o
-
-
# spear310 specific files
obj-$(CONFIG_MACH_SPEAR310) += spear310.o
-# spear310 boards files
-obj-$(CONFIG_BOARD_SPEAR310_EVB) += spear310_evb.o
-
-
# spear320 specific files
obj-$(CONFIG_MACH_SPEAR320) += spear320.o
-
-# spear320 boards files
-obj-$(CONFIG_BOARD_SPEAR320_EVB) += spear320_evb.o
diff --git a/arch/arm/mach-spear3xx/Makefile.boot b/arch/arm/mach-spear3xx/Makefile.boot
index 4674a4c221db..d93e2177e6ec 100644
--- a/arch/arm/mach-spear3xx/Makefile.boot
+++ b/arch/arm/mach-spear3xx/Makefile.boot
@@ -1,3 +1,7 @@
zreladdr-y += 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
+
+dtb-$(CONFIG_MACH_SPEAR300) += spear300-evb.dtb
+dtb-$(CONFIG_MACH_SPEAR310) += spear310-evb.dtb
+dtb-$(CONFIG_MACH_SPEAR320) += spear320-evb.dtb
diff --git a/arch/arm/mach-spear3xx/clock.c b/arch/arm/mach-spear3xx/clock.c
index 6c4841f55223..cd6c11099083 100644
--- a/arch/arm/mach-spear3xx/clock.c
+++ b/arch/arm/mach-spear3xx/clock.c
@@ -11,12 +11,112 @@
* warranty of any kind, whether express or implied.
*/
+#include <linux/clkdev.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/of_platform.h>
#include <asm/mach-types.h>
#include <plat/clock.h>
#include <mach/misc_regs.h>
+#include <mach/spear.h>
+
+#define PLL1_CTR (MISC_BASE + 0x008)
+#define PLL1_FRQ (MISC_BASE + 0x00C)
+#define PLL1_MOD (MISC_BASE + 0x010)
+#define PLL2_CTR (MISC_BASE + 0x014)
+/* PLL_CTR register masks */
+#define PLL_ENABLE 2
+#define PLL_MODE_SHIFT 4
+#define PLL_MODE_MASK 0x3
+#define PLL_MODE_NORMAL 0
+#define PLL_MODE_FRACTION 1
+#define PLL_MODE_DITH_DSB 2
+#define PLL_MODE_DITH_SSB 3
+
+#define PLL2_FRQ (MISC_BASE + 0x018)
+/* PLL FRQ register masks */
+#define PLL_DIV_N_SHIFT 0
+#define PLL_DIV_N_MASK 0xFF
+#define PLL_DIV_P_SHIFT 8
+#define PLL_DIV_P_MASK 0x7
+#define PLL_NORM_FDBK_M_SHIFT 24
+#define PLL_NORM_FDBK_M_MASK 0xFF
+#define PLL_DITH_FDBK_M_SHIFT 16
+#define PLL_DITH_FDBK_M_MASK 0xFFFF
+
+#define PLL2_MOD (MISC_BASE + 0x01C)
+#define PLL_CLK_CFG (MISC_BASE + 0x020)
+#define CORE_CLK_CFG (MISC_BASE + 0x024)
+/* CORE CLK CFG register masks */
+#define PLL_HCLK_RATIO_SHIFT 10
+#define PLL_HCLK_RATIO_MASK 0x3
+#define HCLK_PCLK_RATIO_SHIFT 8
+#define HCLK_PCLK_RATIO_MASK 0x3
+
+#define PERIP_CLK_CFG (MISC_BASE + 0x028)
+/* PERIP_CLK_CFG register masks */
+#define UART_CLK_SHIFT 4
+#define UART_CLK_MASK 0x1
+#define FIRDA_CLK_SHIFT 5
+#define FIRDA_CLK_MASK 0x3
+#define GPT0_CLK_SHIFT 8
+#define GPT1_CLK_SHIFT 11
+#define GPT2_CLK_SHIFT 12
+#define GPT_CLK_MASK 0x1
+#define AUX_CLK_PLL3_VAL 0
+#define AUX_CLK_PLL1_VAL 1
+
+#define PERIP1_CLK_ENB (MISC_BASE + 0x02C)
+/* PERIP1_CLK_ENB register masks */
+#define UART_CLK_ENB 3
+#define SSP_CLK_ENB 5
+#define I2C_CLK_ENB 7
+#define JPEG_CLK_ENB 8
+#define FIRDA_CLK_ENB 10
+#define GPT1_CLK_ENB 11
+#define GPT2_CLK_ENB 12
+#define ADC_CLK_ENB 15
+#define RTC_CLK_ENB 17
+#define GPIO_CLK_ENB 18
+#define DMA_CLK_ENB 19
+#define SMI_CLK_ENB 21
+#define GMAC_CLK_ENB 23
+#define USBD_CLK_ENB 24
+#define USBH_CLK_ENB 25
+#define C3_CLK_ENB 31
+
+#define RAS_CLK_ENB (MISC_BASE + 0x034)
+
+#define PRSC1_CLK_CFG (MISC_BASE + 0x044)
+#define PRSC2_CLK_CFG (MISC_BASE + 0x048)
+#define PRSC3_CLK_CFG (MISC_BASE + 0x04C)
+/* gpt synthesizer register masks */
+#define GPT_MSCALE_SHIFT 0
+#define GPT_MSCALE_MASK 0xFFF
+#define GPT_NSCALE_SHIFT 12
+#define GPT_NSCALE_MASK 0xF
+
+#define AMEM_CLK_CFG (MISC_BASE + 0x050)
+#define EXPI_CLK_CFG (MISC_BASE + 0x054)
+#define CLCD_CLK_SYNT (MISC_BASE + 0x05C)
+#define FIRDA_CLK_SYNT (MISC_BASE + 0x060)
+#define UART_CLK_SYNT (MISC_BASE + 0x064)
+#define GMAC_CLK_SYNT (MISC_BASE + 0x068)
+#define RAS1_CLK_SYNT (MISC_BASE + 0x06C)
+#define RAS2_CLK_SYNT (MISC_BASE + 0x070)
+#define RAS3_CLK_SYNT (MISC_BASE + 0x074)
+#define RAS4_CLK_SYNT (MISC_BASE + 0x078)
+/* aux clk synthesiser register masks for irda to ras4 */
+#define AUX_SYNT_ENB 31
+#define AUX_EQ_SEL_SHIFT 30
+#define AUX_EQ_SEL_MASK 1
+#define AUX_EQ1_SEL 0
+#define AUX_EQ2_SEL 1
+#define AUX_XSCALE_SHIFT 16
+#define AUX_XSCALE_MASK 0xFFF
+#define AUX_YSCALE_SHIFT 0
+#define AUX_YSCALE_MASK 0xFFF
/* root clks */
/* 32 KHz oscillator clock */
@@ -411,6 +511,21 @@ static struct clk usbd_clk = {
.recalc = &follow_parent,
};
+/* clock derived from usbh clk */
+/* usbh0 clock */
+static struct clk usbh0_clk = {
+ .flags = ALWAYS_ENABLED,
+ .pclk = &usbh_clk,
+ .recalc = &follow_parent,
+};
+
+/* usbh1 clock */
+static struct clk usbh1_clk = {
+ .flags = ALWAYS_ENABLED,
+ .pclk = &usbh_clk,
+ .recalc = &follow_parent,
+};
+
/* clock derived from ahb clk */
/* apb masks structure */
static struct bus_clk_masks apb_masks = {
@@ -652,109 +767,126 @@ static struct clk pwm_clk = {
/* array of all spear 3xx clock lookups */
static struct clk_lookup spear_clk_lookups[] = {
- { .con_id = "apb_pclk", .clk = &dummy_apb_pclk},
+ CLKDEV_INIT(NULL, "apb_pclk", &dummy_apb_pclk),
/* root clks */
- { .con_id = "osc_32k_clk", .clk = &osc_32k_clk},
- { .con_id = "osc_24m_clk", .clk = &osc_24m_clk},
+ CLKDEV_INIT(NULL, "osc_32k_clk", &osc_32k_clk),
+ CLKDEV_INIT(NULL, "osc_24m_clk", &osc_24m_clk),
/* clock derived from 32 KHz osc clk */
- { .dev_id = "rtc-spear", .clk = &rtc_clk},
+ CLKDEV_INIT("fc900000.rtc", NULL, &rtc_clk),
/* clock derived from 24 MHz osc clk */
- { .con_id = "pll1_clk", .clk = &pll1_clk},
- { .con_id = "pll3_48m_clk", .clk = &pll3_48m_clk},
- { .dev_id = "wdt", .clk = &wdt_clk},
+ CLKDEV_INIT(NULL, "pll1_clk", &pll1_clk),
+ CLKDEV_INIT(NULL, "pll3_48m_clk", &pll3_48m_clk),
+ CLKDEV_INIT("fc880000.wdt", NULL, &wdt_clk),
/* clock derived from pll1 clk */
- { .con_id = "cpu_clk", .clk = &cpu_clk},
- { .con_id = "ahb_clk", .clk = &ahb_clk},
- { .con_id = "uart_synth_clk", .clk = &uart_synth_clk},
- { .con_id = "firda_synth_clk", .clk = &firda_synth_clk},
- { .con_id = "gpt0_synth_clk", .clk = &gpt0_synth_clk},
- { .con_id = "gpt1_synth_clk", .clk = &gpt1_synth_clk},
- { .con_id = "gpt2_synth_clk", .clk = &gpt2_synth_clk},
- { .dev_id = "uart", .clk = &uart_clk},
- { .dev_id = "firda", .clk = &firda_clk},
- { .dev_id = "gpt0", .clk = &gpt0_clk},
- { .dev_id = "gpt1", .clk = &gpt1_clk},
- { .dev_id = "gpt2", .clk = &gpt2_clk},
+ CLKDEV_INIT(NULL, "cpu_clk", &cpu_clk),
+ CLKDEV_INIT(NULL, "ahb_clk", &ahb_clk),
+ CLKDEV_INIT(NULL, "uart_synth_clk", &uart_synth_clk),
+ CLKDEV_INIT(NULL, "firda_synth_clk", &firda_synth_clk),
+ CLKDEV_INIT(NULL, "gpt0_synth_clk", &gpt0_synth_clk),
+ CLKDEV_INIT(NULL, "gpt1_synth_clk", &gpt1_synth_clk),
+ CLKDEV_INIT(NULL, "gpt2_synth_clk", &gpt2_synth_clk),
+ CLKDEV_INIT("d0000000.serial", NULL, &uart_clk),
+ CLKDEV_INIT("firda", NULL, &firda_clk),
+ CLKDEV_INIT("gpt0", NULL, &gpt0_clk),
+ CLKDEV_INIT("gpt1", NULL, &gpt1_clk),
+ CLKDEV_INIT("gpt2", NULL, &gpt2_clk),
/* clock derived from pll3 clk */
- { .dev_id = "designware_udc", .clk = &usbd_clk},
- { .con_id = "usbh_clk", .clk = &usbh_clk},
+ CLKDEV_INIT("designware_udc", NULL, &usbd_clk),
+ CLKDEV_INIT(NULL, "usbh_clk", &usbh_clk),
+ /* clock derived from usbh clk */
+ CLKDEV_INIT(NULL, "usbh.0_clk", &usbh0_clk),
+ CLKDEV_INIT(NULL, "usbh.1_clk", &usbh1_clk),
/* clock derived from ahb clk */
- { .con_id = "apb_clk", .clk = &apb_clk},
- { .dev_id = "i2c_designware.0", .clk = &i2c_clk},
- { .dev_id = "dma", .clk = &dma_clk},
- { .dev_id = "jpeg", .clk = &jpeg_clk},
- { .dev_id = "gmac", .clk = &gmac_clk},
- { .dev_id = "smi", .clk = &smi_clk},
- { .dev_id = "c3", .clk = &c3_clk},
+ CLKDEV_INIT(NULL, "apb_clk", &apb_clk),
+ CLKDEV_INIT("d0180000.i2c", NULL, &i2c_clk),
+ CLKDEV_INIT("fc400000.dma", NULL, &dma_clk),
+ CLKDEV_INIT("jpeg", NULL, &jpeg_clk),
+ CLKDEV_INIT("e0800000.eth", NULL, &gmac_clk),
+ CLKDEV_INIT("fc000000.flash", NULL, &smi_clk),
+ CLKDEV_INIT("c3", NULL, &c3_clk),
/* clock derived from apb clk */
- { .dev_id = "adc", .clk = &adc_clk},
- { .dev_id = "ssp-pl022.0", .clk = &ssp0_clk},
- { .dev_id = "gpio", .clk = &gpio_clk},
+ CLKDEV_INIT("adc", NULL, &adc_clk),
+ CLKDEV_INIT("d0100000.spi", NULL, &ssp0_clk),
+ CLKDEV_INIT("fc980000.gpio", NULL, &gpio_clk),
};
/* array of all spear 300 clock lookups */
#ifdef CONFIG_MACH_SPEAR300
static struct clk_lookup spear300_clk_lookups[] = {
- { .dev_id = "clcd", .clk = &clcd_clk},
- { .con_id = "fsmc", .clk = &fsmc_clk},
- { .dev_id = "gpio1", .clk = &gpio1_clk},
- { .dev_id = "keyboard", .clk = &kbd_clk},
- { .dev_id = "sdhci", .clk = &sdhci_clk},
+ CLKDEV_INIT("60000000.clcd", NULL, &clcd_clk),
+ CLKDEV_INIT("94000000.flash", NULL, &fsmc_clk),
+ CLKDEV_INIT("a9000000.gpio", NULL, &gpio1_clk),
+ CLKDEV_INIT("a0000000.kbd", NULL, &kbd_clk),
+ CLKDEV_INIT("70000000.sdhci", NULL, &sdhci_clk),
};
+
+void __init spear300_clk_init(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(spear_clk_lookups); i++)
+ clk_register(&spear_clk_lookups[i]);
+
+ for (i = 0; i < ARRAY_SIZE(spear300_clk_lookups); i++)
+ clk_register(&spear300_clk_lookups[i]);
+
+ clk_init();
+}
#endif
/* array of all spear 310 clock lookups */
#ifdef CONFIG_MACH_SPEAR310
static struct clk_lookup spear310_clk_lookups[] = {
- { .con_id = "fsmc", .clk = &fsmc_clk},
- { .con_id = "emi", .clk = &emi_clk},
- { .dev_id = "uart1", .clk = &uart1_clk},
- { .dev_id = "uart2", .clk = &uart2_clk},
- { .dev_id = "uart3", .clk = &uart3_clk},
- { .dev_id = "uart4", .clk = &uart4_clk},
- { .dev_id = "uart5", .clk = &uart5_clk},
+ CLKDEV_INIT("44000000.flash", NULL, &fsmc_clk),
+ CLKDEV_INIT(NULL, "emi", &emi_clk),
+ CLKDEV_INIT("b2000000.serial", NULL, &uart1_clk),
+ CLKDEV_INIT("b2080000.serial", NULL, &uart2_clk),
+ CLKDEV_INIT("b2100000.serial", NULL, &uart3_clk),
+ CLKDEV_INIT("b2180000.serial", NULL, &uart4_clk),
+ CLKDEV_INIT("b2200000.serial", NULL, &uart5_clk),
};
+
+void __init spear310_clk_init(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(spear_clk_lookups); i++)
+ clk_register(&spear_clk_lookups[i]);
+
+ for (i = 0; i < ARRAY_SIZE(spear310_clk_lookups); i++)
+ clk_register(&spear310_clk_lookups[i]);
+
+ clk_init();
+}
#endif
/* array of all spear 320 clock lookups */
#ifdef CONFIG_MACH_SPEAR320
static struct clk_lookup spear320_clk_lookups[] = {
- { .dev_id = "clcd", .clk = &clcd_clk},
- { .con_id = "fsmc", .clk = &fsmc_clk},
- { .dev_id = "i2c_designware.1", .clk = &i2c1_clk},
- { .con_id = "emi", .clk = &emi_clk},
- { .dev_id = "pwm", .clk = &pwm_clk},
- { .dev_id = "sdhci", .clk = &sdhci_clk},
- { .dev_id = "c_can_platform.0", .clk = &can0_clk},
- { .dev_id = "c_can_platform.1", .clk = &can1_clk},
- { .dev_id = "ssp-pl022.1", .clk = &ssp1_clk},
- { .dev_id = "ssp-pl022.2", .clk = &ssp2_clk},
- { .dev_id = "uart1", .clk = &uart1_clk},
- { .dev_id = "uart2", .clk = &uart2_clk},
-};
-#endif
-
-void __init spear3xx_clk_init(void)
+ CLKDEV_INIT("90000000.clcd", NULL, &clcd_clk),
+ CLKDEV_INIT("4c000000.flash", NULL, &fsmc_clk),
+ CLKDEV_INIT("a7000000.i2c", NULL, &i2c1_clk),
+ CLKDEV_INIT(NULL, "emi", &emi_clk),
+ CLKDEV_INIT("pwm", NULL, &pwm_clk),
+ CLKDEV_INIT("70000000.sdhci", NULL, &sdhci_clk),
+ CLKDEV_INIT("c_can_platform.0", NULL, &can0_clk),
+ CLKDEV_INIT("c_can_platform.1", NULL, &can1_clk),
+ CLKDEV_INIT("a5000000.spi", NULL, &ssp1_clk),
+ CLKDEV_INIT("a6000000.spi", NULL, &ssp2_clk),
+ CLKDEV_INIT("a3000000.serial", NULL, &uart1_clk),
+ CLKDEV_INIT("a4000000.serial", NULL, &uart2_clk),
+};
+
+void __init spear320_clk_init(void)
{
- int i, cnt;
- struct clk_lookup *lookups;
-
- if (machine_is_spear300()) {
- cnt = ARRAY_SIZE(spear300_clk_lookups);
- lookups = spear300_clk_lookups;
- } else if (machine_is_spear310()) {
- cnt = ARRAY_SIZE(spear310_clk_lookups);
- lookups = spear310_clk_lookups;
- } else {
- cnt = ARRAY_SIZE(spear320_clk_lookups);
- lookups = spear320_clk_lookups;
- }
+ int i;
for (i = 0; i < ARRAY_SIZE(spear_clk_lookups); i++)
clk_register(&spear_clk_lookups[i]);
- for (i = 0; i < cnt; i++)
- clk_register(&lookups[i]);
+ for (i = 0; i < ARRAY_SIZE(spear320_clk_lookups); i++)
+ clk_register(&spear320_clk_lookups[i]);
clk_init();
}
+#endif
diff --git a/arch/arm/mach-spear3xx/include/mach/generic.h b/arch/arm/mach-spear3xx/include/mach/generic.h
index 14276e5a98d2..bdb304551caf 100644
--- a/arch/arm/mach-spear3xx/include/mach/generic.h
+++ b/arch/arm/mach-spear3xx/include/mach/generic.h
@@ -14,188 +14,40 @@
#ifndef __MACH_GENERIC_H
#define __MACH_GENERIC_H
+#include <linux/amba/pl08x.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/amba/bus.h>
#include <asm/mach/time.h>
#include <asm/mach/map.h>
-#include <plat/padmux.h>
-
-/* spear3xx declarations */
-/*
- * Each GPT has 2 timer channels
- * Following GPT channels will be used as clock source and clockevent
- */
-#define SPEAR_GPT0_BASE SPEAR3XX_ML1_TMR_BASE
-#define SPEAR_GPT0_CHAN0_IRQ SPEAR3XX_IRQ_CPU_GPT1_1
-#define SPEAR_GPT0_CHAN1_IRQ SPEAR3XX_IRQ_CPU_GPT1_2
/* Add spear3xx family device structure declarations here */
-extern struct amba_device spear3xx_gpio_device;
-extern struct amba_device spear3xx_uart_device;
extern struct sys_timer spear3xx_timer;
+extern struct pl022_ssp_controller pl022_plat_data;
+extern struct pl08x_platform_data pl080_plat_data;
/* Add spear3xx family function declarations here */
-void __init spear3xx_clk_init(void);
-void __init spear_setup_timer(void);
+void __init spear_setup_timer(resource_size_t base, int irq);
void __init spear3xx_map_io(void);
-void __init spear3xx_init_irq(void);
-void __init spear3xx_init(void);
+void __init spear3xx_dt_init_irq(void);
void spear_restart(char, const char *);
-/* pad mux declarations */
-#define PMX_FIRDA_MASK (1 << 14)
-#define PMX_I2C_MASK (1 << 13)
-#define PMX_SSP_CS_MASK (1 << 12)
-#define PMX_SSP_MASK (1 << 11)
-#define PMX_MII_MASK (1 << 10)
-#define PMX_GPIO_PIN0_MASK (1 << 9)
-#define PMX_GPIO_PIN1_MASK (1 << 8)
-#define PMX_GPIO_PIN2_MASK (1 << 7)
-#define PMX_GPIO_PIN3_MASK (1 << 6)
-#define PMX_GPIO_PIN4_MASK (1 << 5)
-#define PMX_GPIO_PIN5_MASK (1 << 4)
-#define PMX_UART0_MODEM_MASK (1 << 3)
-#define PMX_UART0_MASK (1 << 2)
-#define PMX_TIMER_3_4_MASK (1 << 1)
-#define PMX_TIMER_1_2_MASK (1 << 0)
-
-/* pad mux devices */
-extern struct pmx_dev spear3xx_pmx_firda;
-extern struct pmx_dev spear3xx_pmx_i2c;
-extern struct pmx_dev spear3xx_pmx_ssp_cs;
-extern struct pmx_dev spear3xx_pmx_ssp;
-extern struct pmx_dev spear3xx_pmx_mii;
-extern struct pmx_dev spear3xx_pmx_gpio_pin0;
-extern struct pmx_dev spear3xx_pmx_gpio_pin1;
-extern struct pmx_dev spear3xx_pmx_gpio_pin2;
-extern struct pmx_dev spear3xx_pmx_gpio_pin3;
-extern struct pmx_dev spear3xx_pmx_gpio_pin4;
-extern struct pmx_dev spear3xx_pmx_gpio_pin5;
-extern struct pmx_dev spear3xx_pmx_uart0_modem;
-extern struct pmx_dev spear3xx_pmx_uart0;
-extern struct pmx_dev spear3xx_pmx_timer_3_4;
-extern struct pmx_dev spear3xx_pmx_timer_1_2;
-
-#if defined(CONFIG_MACH_SPEAR310) || defined(CONFIG_MACH_SPEAR320)
-/* padmux plgpio devices */
-extern struct pmx_dev spear3xx_pmx_plgpio_0_1;
-extern struct pmx_dev spear3xx_pmx_plgpio_2_3;
-extern struct pmx_dev spear3xx_pmx_plgpio_4_5;
-extern struct pmx_dev spear3xx_pmx_plgpio_6_9;
-extern struct pmx_dev spear3xx_pmx_plgpio_10_27;
-extern struct pmx_dev spear3xx_pmx_plgpio_28;
-extern struct pmx_dev spear3xx_pmx_plgpio_29;
-extern struct pmx_dev spear3xx_pmx_plgpio_30;
-extern struct pmx_dev spear3xx_pmx_plgpio_31;
-extern struct pmx_dev spear3xx_pmx_plgpio_32;
-extern struct pmx_dev spear3xx_pmx_plgpio_33;
-extern struct pmx_dev spear3xx_pmx_plgpio_34_36;
-extern struct pmx_dev spear3xx_pmx_plgpio_37_42;
-extern struct pmx_dev spear3xx_pmx_plgpio_43_44_47_48;
-extern struct pmx_dev spear3xx_pmx_plgpio_45_46_49_50;
-#endif
-
/* spear300 declarations */
#ifdef CONFIG_MACH_SPEAR300
-/* Add spear300 machine device structure declarations here */
-extern struct amba_device spear300_gpio1_device;
-
-/* pad mux modes */
-extern struct pmx_mode spear300_nand_mode;
-extern struct pmx_mode spear300_nor_mode;
-extern struct pmx_mode spear300_photo_frame_mode;
-extern struct pmx_mode spear300_lend_ip_phone_mode;
-extern struct pmx_mode spear300_hend_ip_phone_mode;
-extern struct pmx_mode spear300_lend_wifi_phone_mode;
-extern struct pmx_mode spear300_hend_wifi_phone_mode;
-extern struct pmx_mode spear300_ata_pabx_wi2s_mode;
-extern struct pmx_mode spear300_ata_pabx_i2s_mode;
-extern struct pmx_mode spear300_caml_lcdw_mode;
-extern struct pmx_mode spear300_camu_lcd_mode;
-extern struct pmx_mode spear300_camu_wlcd_mode;
-extern struct pmx_mode spear300_caml_lcd_mode;
-
-/* pad mux devices */
-extern struct pmx_dev spear300_pmx_fsmc_2_chips;
-extern struct pmx_dev spear300_pmx_fsmc_4_chips;
-extern struct pmx_dev spear300_pmx_keyboard;
-extern struct pmx_dev spear300_pmx_clcd;
-extern struct pmx_dev spear300_pmx_telecom_gpio;
-extern struct pmx_dev spear300_pmx_telecom_tdm;
-extern struct pmx_dev spear300_pmx_telecom_spi_cs_i2c_clk;
-extern struct pmx_dev spear300_pmx_telecom_camera;
-extern struct pmx_dev spear300_pmx_telecom_dac;
-extern struct pmx_dev spear300_pmx_telecom_i2s;
-extern struct pmx_dev spear300_pmx_telecom_boot_pins;
-extern struct pmx_dev spear300_pmx_telecom_sdhci_4bit;
-extern struct pmx_dev spear300_pmx_telecom_sdhci_8bit;
-extern struct pmx_dev spear300_pmx_gpio1;
-
-/* Add spear300 machine function declarations here */
-void __init spear300_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs,
- u8 pmx_dev_count);
+void __init spear300_clk_init(void);
#endif /* CONFIG_MACH_SPEAR300 */
/* spear310 declarations */
#ifdef CONFIG_MACH_SPEAR310
-/* Add spear310 machine device structure declarations here */
-
-/* pad mux devices */
-extern struct pmx_dev spear310_pmx_emi_cs_0_1_4_5;
-extern struct pmx_dev spear310_pmx_emi_cs_2_3;
-extern struct pmx_dev spear310_pmx_uart1;
-extern struct pmx_dev spear310_pmx_uart2;
-extern struct pmx_dev spear310_pmx_uart3_4_5;
-extern struct pmx_dev spear310_pmx_fsmc;
-extern struct pmx_dev spear310_pmx_rs485_0_1;
-extern struct pmx_dev spear310_pmx_tdm0;
-
-/* Add spear310 machine function declarations here */
-void __init spear310_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs,
- u8 pmx_dev_count);
+void __init spear310_clk_init(void);
#endif /* CONFIG_MACH_SPEAR310 */
/* spear320 declarations */
#ifdef CONFIG_MACH_SPEAR320
-/* Add spear320 machine device structure declarations here */
-
-/* pad mux modes */
-extern struct pmx_mode spear320_auto_net_smii_mode;
-extern struct pmx_mode spear320_auto_net_mii_mode;
-extern struct pmx_mode spear320_auto_exp_mode;
-extern struct pmx_mode spear320_small_printers_mode;
-
-/* pad mux devices */
-extern struct pmx_dev spear320_pmx_clcd;
-extern struct pmx_dev spear320_pmx_emi;
-extern struct pmx_dev spear320_pmx_fsmc;
-extern struct pmx_dev spear320_pmx_spp;
-extern struct pmx_dev spear320_pmx_sdhci;
-extern struct pmx_dev spear320_pmx_i2s;
-extern struct pmx_dev spear320_pmx_uart1;
-extern struct pmx_dev spear320_pmx_uart1_modem;
-extern struct pmx_dev spear320_pmx_uart2;
-extern struct pmx_dev spear320_pmx_touchscreen;
-extern struct pmx_dev spear320_pmx_can;
-extern struct pmx_dev spear320_pmx_sdhci_led;
-extern struct pmx_dev spear320_pmx_pwm0;
-extern struct pmx_dev spear320_pmx_pwm1;
-extern struct pmx_dev spear320_pmx_pwm2;
-extern struct pmx_dev spear320_pmx_pwm3;
-extern struct pmx_dev spear320_pmx_ssp1;
-extern struct pmx_dev spear320_pmx_ssp2;
-extern struct pmx_dev spear320_pmx_mii1;
-extern struct pmx_dev spear320_pmx_smii0;
-extern struct pmx_dev spear320_pmx_smii1;
-extern struct pmx_dev spear320_pmx_i2c1;
-
-/* Add spear320 machine function declarations here */
-void __init spear320_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs,
- u8 pmx_dev_count);
+void __init spear320_clk_init(void);
#endif /* CONFIG_MACH_SPEAR320 */
diff --git a/arch/arm/mach-spear3xx/include/mach/hardware.h b/arch/arm/mach-spear3xx/include/mach/hardware.h
index 4660c0d8ec0d..40a8c178f10d 100644
--- a/arch/arm/mach-spear3xx/include/mach/hardware.h
+++ b/arch/arm/mach-spear3xx/include/mach/hardware.h
@@ -1,23 +1 @@
-/*
- * arch/arm/mach-spear3xx/include/mach/hardware.h
- *
- * Hardware definitions for SPEAr3xx machine family
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __MACH_HARDWARE_H
-#define __MACH_HARDWARE_H
-
-#include <plat/hardware.h>
-#include <mach/spear.h>
-
-/* Vitual to physical translation of statically mapped space */
-#define IO_ADDRESS(x) (x | 0xF0000000)
-
-#endif /* __MACH_HARDWARE_H */
+/* empty */
diff --git a/arch/arm/mach-spear3xx/include/mach/irqs.h b/arch/arm/mach-spear3xx/include/mach/irqs.h
index 6e265442808e..319620a1afb4 100644
--- a/arch/arm/mach-spear3xx/include/mach/irqs.h
+++ b/arch/arm/mach-spear3xx/include/mach/irqs.h
@@ -14,141 +14,15 @@
#ifndef __MACH_IRQS_H
#define __MACH_IRQS_H
-/* SPEAr3xx IRQ definitions */
-#define SPEAR3XX_IRQ_HW_ACCEL_MOD_0 0
+/* FIXME: probe all these from DT */
#define SPEAR3XX_IRQ_INTRCOMM_RAS_ARM 1
#define SPEAR3XX_IRQ_CPU_GPT1_1 2
-#define SPEAR3XX_IRQ_CPU_GPT1_2 3
-#define SPEAR3XX_IRQ_BASIC_GPT1_1 4
-#define SPEAR3XX_IRQ_BASIC_GPT1_2 5
-#define SPEAR3XX_IRQ_BASIC_GPT2_1 6
-#define SPEAR3XX_IRQ_BASIC_GPT2_2 7
-#define SPEAR3XX_IRQ_BASIC_DMA 8
-#define SPEAR3XX_IRQ_BASIC_SMI 9
-#define SPEAR3XX_IRQ_BASIC_RTC 10
-#define SPEAR3XX_IRQ_BASIC_GPIO 11
-#define SPEAR3XX_IRQ_BASIC_WDT 12
-#define SPEAR3XX_IRQ_DDR_CONTROLLER 13
-#define SPEAR3XX_IRQ_SYS_ERROR 14
-#define SPEAR3XX_IRQ_WAKEUP_RCV 15
-#define SPEAR3XX_IRQ_JPEG 16
-#define SPEAR3XX_IRQ_IRDA 17
-#define SPEAR3XX_IRQ_ADC 18
-#define SPEAR3XX_IRQ_UART 19
-#define SPEAR3XX_IRQ_SSP 20
-#define SPEAR3XX_IRQ_I2C 21
-#define SPEAR3XX_IRQ_MAC_1 22
-#define SPEAR3XX_IRQ_MAC_2 23
-#define SPEAR3XX_IRQ_USB_DEV 24
-#define SPEAR3XX_IRQ_USB_H_OHCI_0 25
-#define SPEAR3XX_IRQ_USB_H_EHCI_0 26
-#define SPEAR3XX_IRQ_USB_H_EHCI_1 SPEAR3XX_IRQ_USB_H_EHCI_0
-#define SPEAR3XX_IRQ_USB_H_OHCI_1 27
#define SPEAR3XX_IRQ_GEN_RAS_1 28
#define SPEAR3XX_IRQ_GEN_RAS_2 29
#define SPEAR3XX_IRQ_GEN_RAS_3 30
-#define SPEAR3XX_IRQ_HW_ACCEL_MOD_1 31
#define SPEAR3XX_IRQ_VIC_END 32
-
#define SPEAR3XX_VIRQ_START SPEAR3XX_IRQ_VIC_END
-/* SPEAr300 Virtual irq definitions */
-/* IRQs sharing IRQ_GEN_RAS_1 */
-#define SPEAR300_VIRQ_IT_PERS_S (SPEAR3XX_VIRQ_START + 0)
-#define SPEAR300_VIRQ_IT_CHANGE_S (SPEAR3XX_VIRQ_START + 1)
-#define SPEAR300_VIRQ_I2S (SPEAR3XX_VIRQ_START + 2)
-#define SPEAR300_VIRQ_TDM (SPEAR3XX_VIRQ_START + 3)
-#define SPEAR300_VIRQ_CAMERA_L (SPEAR3XX_VIRQ_START + 4)
-#define SPEAR300_VIRQ_CAMERA_F (SPEAR3XX_VIRQ_START + 5)
-#define SPEAR300_VIRQ_CAMERA_V (SPEAR3XX_VIRQ_START + 6)
-#define SPEAR300_VIRQ_KEYBOARD (SPEAR3XX_VIRQ_START + 7)
-#define SPEAR300_VIRQ_GPIO1 (SPEAR3XX_VIRQ_START + 8)
-
-/* IRQs sharing IRQ_GEN_RAS_3 */
-#define SPEAR300_IRQ_CLCD SPEAR3XX_IRQ_GEN_RAS_3
-
-/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */
-#define SPEAR300_IRQ_SDHCI SPEAR3XX_IRQ_INTRCOMM_RAS_ARM
-
-/* SPEAr310 Virtual irq definitions */
-/* IRQs sharing IRQ_GEN_RAS_1 */
-#define SPEAR310_VIRQ_SMII0 (SPEAR3XX_VIRQ_START + 0)
-#define SPEAR310_VIRQ_SMII1 (SPEAR3XX_VIRQ_START + 1)
-#define SPEAR310_VIRQ_SMII2 (SPEAR3XX_VIRQ_START + 2)
-#define SPEAR310_VIRQ_SMII3 (SPEAR3XX_VIRQ_START + 3)
-#define SPEAR310_VIRQ_WAKEUP_SMII0 (SPEAR3XX_VIRQ_START + 4)
-#define SPEAR310_VIRQ_WAKEUP_SMII1 (SPEAR3XX_VIRQ_START + 5)
-#define SPEAR310_VIRQ_WAKEUP_SMII2 (SPEAR3XX_VIRQ_START + 6)
-#define SPEAR310_VIRQ_WAKEUP_SMII3 (SPEAR3XX_VIRQ_START + 7)
-
-/* IRQs sharing IRQ_GEN_RAS_2 */
-#define SPEAR310_VIRQ_UART1 (SPEAR3XX_VIRQ_START + 8)
-#define SPEAR310_VIRQ_UART2 (SPEAR3XX_VIRQ_START + 9)
-#define SPEAR310_VIRQ_UART3 (SPEAR3XX_VIRQ_START + 10)
-#define SPEAR310_VIRQ_UART4 (SPEAR3XX_VIRQ_START + 11)
-#define SPEAR310_VIRQ_UART5 (SPEAR3XX_VIRQ_START + 12)
-
-/* IRQs sharing IRQ_GEN_RAS_3 */
-#define SPEAR310_VIRQ_EMI (SPEAR3XX_VIRQ_START + 13)
-#define SPEAR310_VIRQ_PLGPIO (SPEAR3XX_VIRQ_START + 14)
-
-/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */
-#define SPEAR310_VIRQ_TDM_HDLC (SPEAR3XX_VIRQ_START + 15)
-#define SPEAR310_VIRQ_RS485_0 (SPEAR3XX_VIRQ_START + 16)
-#define SPEAR310_VIRQ_RS485_1 (SPEAR3XX_VIRQ_START + 17)
-
-/* SPEAr320 Virtual irq definitions */
-/* IRQs sharing IRQ_GEN_RAS_1 */
-#define SPEAR320_VIRQ_EMI (SPEAR3XX_VIRQ_START + 0)
-#define SPEAR320_VIRQ_CLCD (SPEAR3XX_VIRQ_START + 1)
-#define SPEAR320_VIRQ_SPP (SPEAR3XX_VIRQ_START + 2)
-
-/* IRQs sharing IRQ_GEN_RAS_2 */
-#define SPEAR320_IRQ_SDHCI SPEAR3XX_IRQ_GEN_RAS_2
-
-/* IRQs sharing IRQ_GEN_RAS_3 */
-#define SPEAR320_VIRQ_PLGPIO (SPEAR3XX_VIRQ_START + 3)
-#define SPEAR320_VIRQ_I2S_PLAY (SPEAR3XX_VIRQ_START + 4)
-#define SPEAR320_VIRQ_I2S_REC (SPEAR3XX_VIRQ_START + 5)
-
-/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */
-#define SPEAR320_VIRQ_CANU (SPEAR3XX_VIRQ_START + 6)
-#define SPEAR320_VIRQ_CANL (SPEAR3XX_VIRQ_START + 7)
-#define SPEAR320_VIRQ_UART1 (SPEAR3XX_VIRQ_START + 8)
-#define SPEAR320_VIRQ_UART2 (SPEAR3XX_VIRQ_START + 9)
-#define SPEAR320_VIRQ_SSP1 (SPEAR3XX_VIRQ_START + 10)
-#define SPEAR320_VIRQ_SSP2 (SPEAR3XX_VIRQ_START + 11)
-#define SPEAR320_VIRQ_SMII0 (SPEAR3XX_VIRQ_START + 12)
-#define SPEAR320_VIRQ_MII1_SMII1 (SPEAR3XX_VIRQ_START + 13)
-#define SPEAR320_VIRQ_WAKEUP_SMII0 (SPEAR3XX_VIRQ_START + 14)
-#define SPEAR320_VIRQ_WAKEUP_MII1_SMII1 (SPEAR3XX_VIRQ_START + 15)
-#define SPEAR320_VIRQ_I2C1 (SPEAR3XX_VIRQ_START + 16)
-
-/*
- * GPIO pins virtual irqs
- * Use the lowest number for the GPIO virtual IRQs base on which subarchs
- * we have compiled in
- */
-#if defined(CONFIG_MACH_SPEAR310)
-#define SPEAR3XX_GPIO_INT_BASE (SPEAR3XX_VIRQ_START + 18)
-#elif defined(CONFIG_MACH_SPEAR320)
-#define SPEAR3XX_GPIO_INT_BASE (SPEAR3XX_VIRQ_START + 17)
-#else
-#define SPEAR3XX_GPIO_INT_BASE (SPEAR3XX_VIRQ_START + 9)
-#endif
-
-#define SPEAR300_GPIO1_INT_BASE (SPEAR3XX_GPIO_INT_BASE + 8)
-#define SPEAR3XX_PLGPIO_COUNT 102
-
-#if defined(CONFIG_MACH_SPEAR310) || defined(CONFIG_MACH_SPEAR320)
-#define SPEAR3XX_PLGPIO_INT_BASE (SPEAR3XX_GPIO_INT_BASE + 8)
-#define SPEAR3XX_GPIO_INT_END (SPEAR3XX_PLGPIO_INT_BASE + \
- SPEAR3XX_PLGPIO_COUNT)
-#else
-#define SPEAR3XX_GPIO_INT_END (SPEAR300_GPIO1_INT_BASE + 8)
-#endif
-
-#define SPEAR3XX_VIRQ_END SPEAR3XX_GPIO_INT_END
-#define NR_IRQS SPEAR3XX_VIRQ_END
+#define NR_IRQS 160
#endif /* __MACH_IRQS_H */
diff --git a/arch/arm/mach-spear3xx/include/mach/misc_regs.h b/arch/arm/mach-spear3xx/include/mach/misc_regs.h
index 5bd8cd8d4852..e0ab72e61507 100644
--- a/arch/arm/mach-spear3xx/include/mach/misc_regs.h
+++ b/arch/arm/mach-spear3xx/include/mach/misc_regs.h
@@ -14,151 +14,7 @@
#ifndef __MACH_MISC_REGS_H
#define __MACH_MISC_REGS_H
-#include <mach/hardware.h>
-
#define MISC_BASE IOMEM(VA_SPEAR3XX_ICM3_MISC_REG_BASE)
-
-#define SOC_CFG_CTR (MISC_BASE + 0x000)
-#define DIAG_CFG_CTR (MISC_BASE + 0x004)
-#define PLL1_CTR (MISC_BASE + 0x008)
-#define PLL1_FRQ (MISC_BASE + 0x00C)
-#define PLL1_MOD (MISC_BASE + 0x010)
-#define PLL2_CTR (MISC_BASE + 0x014)
-/* PLL_CTR register masks */
-#define PLL_ENABLE 2
-#define PLL_MODE_SHIFT 4
-#define PLL_MODE_MASK 0x3
-#define PLL_MODE_NORMAL 0
-#define PLL_MODE_FRACTION 1
-#define PLL_MODE_DITH_DSB 2
-#define PLL_MODE_DITH_SSB 3
-
-#define PLL2_FRQ (MISC_BASE + 0x018)
-/* PLL FRQ register masks */
-#define PLL_DIV_N_SHIFT 0
-#define PLL_DIV_N_MASK 0xFF
-#define PLL_DIV_P_SHIFT 8
-#define PLL_DIV_P_MASK 0x7
-#define PLL_NORM_FDBK_M_SHIFT 24
-#define PLL_NORM_FDBK_M_MASK 0xFF
-#define PLL_DITH_FDBK_M_SHIFT 16
-#define PLL_DITH_FDBK_M_MASK 0xFFFF
-
-#define PLL2_MOD (MISC_BASE + 0x01C)
-#define PLL_CLK_CFG (MISC_BASE + 0x020)
-#define CORE_CLK_CFG (MISC_BASE + 0x024)
-/* CORE CLK CFG register masks */
-#define PLL_HCLK_RATIO_SHIFT 10
-#define PLL_HCLK_RATIO_MASK 0x3
-#define HCLK_PCLK_RATIO_SHIFT 8
-#define HCLK_PCLK_RATIO_MASK 0x3
-
-#define PERIP_CLK_CFG (MISC_BASE + 0x028)
-/* PERIP_CLK_CFG register masks */
-#define UART_CLK_SHIFT 4
-#define UART_CLK_MASK 0x1
-#define FIRDA_CLK_SHIFT 5
-#define FIRDA_CLK_MASK 0x3
-#define GPT0_CLK_SHIFT 8
-#define GPT1_CLK_SHIFT 11
-#define GPT2_CLK_SHIFT 12
-#define GPT_CLK_MASK 0x1
-#define AUX_CLK_PLL3_VAL 0
-#define AUX_CLK_PLL1_VAL 1
-
-#define PERIP1_CLK_ENB (MISC_BASE + 0x02C)
-/* PERIP1_CLK_ENB register masks */
-#define UART_CLK_ENB 3
-#define SSP_CLK_ENB 5
-#define I2C_CLK_ENB 7
-#define JPEG_CLK_ENB 8
-#define FIRDA_CLK_ENB 10
-#define GPT1_CLK_ENB 11
-#define GPT2_CLK_ENB 12
-#define ADC_CLK_ENB 15
-#define RTC_CLK_ENB 17
-#define GPIO_CLK_ENB 18
-#define DMA_CLK_ENB 19
-#define SMI_CLK_ENB 21
-#define GMAC_CLK_ENB 23
-#define USBD_CLK_ENB 24
-#define USBH_CLK_ENB 25
-#define C3_CLK_ENB 31
-
-#define SOC_CORE_ID (MISC_BASE + 0x030)
-#define RAS_CLK_ENB (MISC_BASE + 0x034)
-#define PERIP1_SOF_RST (MISC_BASE + 0x038)
-/* PERIP1_SOF_RST register masks */
-#define JPEG_SOF_RST 8
-
-#define SOC_USER_ID (MISC_BASE + 0x03C)
-#define RAS_SOF_RST (MISC_BASE + 0x040)
-#define PRSC1_CLK_CFG (MISC_BASE + 0x044)
-#define PRSC2_CLK_CFG (MISC_BASE + 0x048)
-#define PRSC3_CLK_CFG (MISC_BASE + 0x04C)
-/* gpt synthesizer register masks */
-#define GPT_MSCALE_SHIFT 0
-#define GPT_MSCALE_MASK 0xFFF
-#define GPT_NSCALE_SHIFT 12
-#define GPT_NSCALE_MASK 0xF
-
-#define AMEM_CLK_CFG (MISC_BASE + 0x050)
-#define EXPI_CLK_CFG (MISC_BASE + 0x054)
-#define CLCD_CLK_SYNT (MISC_BASE + 0x05C)
-#define FIRDA_CLK_SYNT (MISC_BASE + 0x060)
-#define UART_CLK_SYNT (MISC_BASE + 0x064)
-#define GMAC_CLK_SYNT (MISC_BASE + 0x068)
-#define RAS1_CLK_SYNT (MISC_BASE + 0x06C)
-#define RAS2_CLK_SYNT (MISC_BASE + 0x070)
-#define RAS3_CLK_SYNT (MISC_BASE + 0x074)
-#define RAS4_CLK_SYNT (MISC_BASE + 0x078)
-/* aux clk synthesiser register masks for irda to ras4 */
-#define AUX_SYNT_ENB 31
-#define AUX_EQ_SEL_SHIFT 30
-#define AUX_EQ_SEL_MASK 1
-#define AUX_EQ1_SEL 0
-#define AUX_EQ2_SEL 1
-#define AUX_XSCALE_SHIFT 16
-#define AUX_XSCALE_MASK 0xFFF
-#define AUX_YSCALE_SHIFT 0
-#define AUX_YSCALE_MASK 0xFFF
-
-#define ICM1_ARB_CFG (MISC_BASE + 0x07C)
-#define ICM2_ARB_CFG (MISC_BASE + 0x080)
-#define ICM3_ARB_CFG (MISC_BASE + 0x084)
-#define ICM4_ARB_CFG (MISC_BASE + 0x088)
-#define ICM5_ARB_CFG (MISC_BASE + 0x08C)
-#define ICM6_ARB_CFG (MISC_BASE + 0x090)
-#define ICM7_ARB_CFG (MISC_BASE + 0x094)
-#define ICM8_ARB_CFG (MISC_BASE + 0x098)
-#define ICM9_ARB_CFG (MISC_BASE + 0x09C)
#define DMA_CHN_CFG (MISC_BASE + 0x0A0)
-#define USB2_PHY_CFG (MISC_BASE + 0x0A4)
-#define GMAC_CFG_CTR (MISC_BASE + 0x0A8)
-#define EXPI_CFG_CTR (MISC_BASE + 0x0AC)
-#define PRC1_LOCK_CTR (MISC_BASE + 0x0C0)
-#define PRC2_LOCK_CTR (MISC_BASE + 0x0C4)
-#define PRC3_LOCK_CTR (MISC_BASE + 0x0C8)
-#define PRC4_LOCK_CTR (MISC_BASE + 0x0CC)
-#define PRC1_IRQ_CTR (MISC_BASE + 0x0D0)
-#define PRC2_IRQ_CTR (MISC_BASE + 0x0D4)
-#define PRC3_IRQ_CTR (MISC_BASE + 0x0D8)
-#define PRC4_IRQ_CTR (MISC_BASE + 0x0DC)
-#define PWRDOWN_CFG_CTR (MISC_BASE + 0x0E0)
-#define COMPSSTL_1V8_CFG (MISC_BASE + 0x0E4)
-#define COMPSSTL_2V5_CFG (MISC_BASE + 0x0E8)
-#define COMPCOR_3V3_CFG (MISC_BASE + 0x0EC)
-#define SSTLPAD_CFG_CTR (MISC_BASE + 0x0F0)
-#define BIST1_CFG_CTR (MISC_BASE + 0x0F4)
-#define BIST2_CFG_CTR (MISC_BASE + 0x0F8)
-#define BIST3_CFG_CTR (MISC_BASE + 0x0FC)
-#define BIST4_CFG_CTR (MISC_BASE + 0x100)
-#define BIST5_CFG_CTR (MISC_BASE + 0x104)
-#define BIST1_STS_RES (MISC_BASE + 0x108)
-#define BIST2_STS_RES (MISC_BASE + 0x10C)
-#define BIST3_STS_RES (MISC_BASE + 0x110)
-#define BIST4_STS_RES (MISC_BASE + 0x114)
-#define BIST5_STS_RES (MISC_BASE + 0x118)
-#define SYSERR_CFG_CTR (MISC_BASE + 0x11C)
#endif /* __MACH_MISC_REGS_H */
diff --git a/arch/arm/mach-spear3xx/include/mach/spear.h b/arch/arm/mach-spear3xx/include/mach/spear.h
index 63fd98356919..6d4dadc67633 100644
--- a/arch/arm/mach-spear3xx/include/mach/spear.h
+++ b/arch/arm/mach-spear3xx/include/mach/spear.h
@@ -15,60 +15,27 @@
#define __MACH_SPEAR3XX_H
#include <asm/memory.h>
-#include <mach/spear300.h>
-#include <mach/spear310.h>
-#include <mach/spear320.h>
-
-#define SPEAR3XX_ML_SDRAM_BASE UL(0x00000000)
-
-#define SPEAR3XX_ICM9_BASE UL(0xC0000000)
/* ICM1 - Low speed connection */
#define SPEAR3XX_ICM1_2_BASE UL(0xD0000000)
+#define VA_SPEAR3XX_ICM1_2_BASE UL(0xFD000000)
#define SPEAR3XX_ICM1_UART_BASE UL(0xD0000000)
-#define VA_SPEAR3XX_ICM1_UART_BASE IO_ADDRESS(SPEAR3XX_ICM1_UART_BASE)
-#define SPEAR3XX_ICM1_ADC_BASE UL(0xD0080000)
+#define VA_SPEAR3XX_ICM1_UART_BASE (VA_SPEAR3XX_ICM1_2_BASE | SPEAR3XX_ICM1_UART_BASE)
#define SPEAR3XX_ICM1_SSP_BASE UL(0xD0100000)
-#define SPEAR3XX_ICM1_I2C_BASE UL(0xD0180000)
-#define SPEAR3XX_ICM1_JPEG_BASE UL(0xD0800000)
-#define SPEAR3XX_ICM1_IRDA_BASE UL(0xD1000000)
-#define SPEAR3XX_ICM1_SRAM_BASE UL(0xD2800000)
-
-/* ICM2 - Application Subsystem */
-#define SPEAR3XX_ICM2_HWACCEL0_BASE UL(0xD8800000)
-#define SPEAR3XX_ICM2_HWACCEL1_BASE UL(0xD9000000)
-
-/* ICM4 - High Speed Connection */
-#define SPEAR3XX_ICM4_BASE UL(0xE0000000)
-#define SPEAR3XX_ICM4_MII_BASE UL(0xE0800000)
-#define SPEAR3XX_ICM4_USBD_FIFO_BASE UL(0xE1000000)
-#define SPEAR3XX_ICM4_USBD_CSR_BASE UL(0xE1100000)
-#define SPEAR3XX_ICM4_USBD_PLDT_BASE UL(0xE1200000)
-#define SPEAR3XX_ICM4_USB_EHCI0_1_BASE UL(0xE1800000)
-#define SPEAR3XX_ICM4_USB_OHCI0_BASE UL(0xE1900000)
-#define SPEAR3XX_ICM4_USB_OHCI1_BASE UL(0xE2100000)
-#define SPEAR3XX_ICM4_USB_ARB_BASE UL(0xE2800000)
/* ML1 - Multi Layer CPU Subsystem */
#define SPEAR3XX_ICM3_ML1_2_BASE UL(0xF0000000)
-#define SPEAR3XX_ML1_TMR_BASE UL(0xF0000000)
-#define SPEAR3XX_ML1_VIC_BASE UL(0xF1100000)
-#define VA_SPEAR3XX_ML1_VIC_BASE IO_ADDRESS(SPEAR3XX_ML1_VIC_BASE)
+#define VA_SPEAR6XX_ML_CPU_BASE UL(0xF0000000)
+#define SPEAR3XX_CPU_TMR_BASE UL(0xF0000000)
/* ICM3 - Basic Subsystem */
-#define SPEAR3XX_ICM3_SMEM_BASE UL(0xF8000000)
#define SPEAR3XX_ICM3_SMI_CTRL_BASE UL(0xFC000000)
+#define VA_SPEAR3XX_ICM3_SMI_CTRL_BASE UL(0xFC000000)
#define SPEAR3XX_ICM3_DMA_BASE UL(0xFC400000)
-#define SPEAR3XX_ICM3_SDRAM_CTRL_BASE UL(0xFC600000)
-#define SPEAR3XX_ICM3_TMR0_BASE UL(0xFC800000)
-#define SPEAR3XX_ICM3_WDT_BASE UL(0xFC880000)
-#define SPEAR3XX_ICM3_RTC_BASE UL(0xFC900000)
-#define SPEAR3XX_ICM3_GPIO_BASE UL(0xFC980000)
#define SPEAR3XX_ICM3_SYS_CTRL_BASE UL(0xFCA00000)
-#define VA_SPEAR3XX_ICM3_SYS_CTRL_BASE IO_ADDRESS(SPEAR3XX_ICM3_SYS_CTRL_BASE)
+#define VA_SPEAR3XX_ICM3_SYS_CTRL_BASE (VA_SPEAR3XX_ICM3_SMI_CTRL_BASE | SPEAR3XX_ICM3_SYS_CTRL_BASE)
#define SPEAR3XX_ICM3_MISC_REG_BASE UL(0xFCA80000)
-#define VA_SPEAR3XX_ICM3_MISC_REG_BASE IO_ADDRESS(SPEAR3XX_ICM3_MISC_REG_BASE)
-#define SPEAR3XX_ICM3_TMR1_BASE UL(0xFCB00000)
+#define VA_SPEAR3XX_ICM3_MISC_REG_BASE (VA_SPEAR3XX_ICM3_SMI_CTRL_BASE | SPEAR3XX_ICM3_MISC_REG_BASE)
/* Debug uart for linux, will be used for debug and uncompress messages */
#define SPEAR_DBG_UART_BASE SPEAR3XX_ICM1_UART_BASE
diff --git a/arch/arm/mach-spear3xx/include/mach/spear300.h b/arch/arm/mach-spear3xx/include/mach/spear300.h
deleted file mode 100644
index 3b6ea0729040..000000000000
--- a/arch/arm/mach-spear3xx/include/mach/spear300.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * arch/arm/mach-spear3xx/include/mach/spear300.h
- *
- * SPEAr300 Machine specific definition
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifdef CONFIG_MACH_SPEAR300
-
-#ifndef __MACH_SPEAR300_H
-#define __MACH_SPEAR300_H
-
-/* Base address of various IPs */
-#define SPEAR300_TELECOM_BASE UL(0x50000000)
-
-/* Interrupt registers offsets and masks */
-#define SPEAR300_INT_ENB_MASK_REG 0x54
-#define SPEAR300_INT_STS_MASK_REG 0x58
-#define SPEAR300_IT_PERS_S_IRQ_MASK (1 << 0)
-#define SPEAR300_IT_CHANGE_S_IRQ_MASK (1 << 1)
-#define SPEAR300_I2S_IRQ_MASK (1 << 2)
-#define SPEAR300_TDM_IRQ_MASK (1 << 3)
-#define SPEAR300_CAMERA_L_IRQ_MASK (1 << 4)
-#define SPEAR300_CAMERA_F_IRQ_MASK (1 << 5)
-#define SPEAR300_CAMERA_V_IRQ_MASK (1 << 6)
-#define SPEAR300_KEYBOARD_IRQ_MASK (1 << 7)
-#define SPEAR300_GPIO1_IRQ_MASK (1 << 8)
-
-#define SPEAR300_SHIRQ_RAS1_MASK 0x1FF
-
-#define SPEAR300_CLCD_BASE UL(0x60000000)
-#define SPEAR300_SDHCI_BASE UL(0x70000000)
-#define SPEAR300_NAND_0_BASE UL(0x80000000)
-#define SPEAR300_NAND_1_BASE UL(0x84000000)
-#define SPEAR300_NAND_2_BASE UL(0x88000000)
-#define SPEAR300_NAND_3_BASE UL(0x8c000000)
-#define SPEAR300_NOR_0_BASE UL(0x90000000)
-#define SPEAR300_NOR_1_BASE UL(0x91000000)
-#define SPEAR300_NOR_2_BASE UL(0x92000000)
-#define SPEAR300_NOR_3_BASE UL(0x93000000)
-#define SPEAR300_FSMC_BASE UL(0x94000000)
-#define SPEAR300_SOC_CONFIG_BASE UL(0x99000000)
-#define SPEAR300_KEYBOARD_BASE UL(0xA0000000)
-#define SPEAR300_GPIO_BASE UL(0xA9000000)
-
-#endif /* __MACH_SPEAR300_H */
-
-#endif /* CONFIG_MACH_SPEAR300 */
diff --git a/arch/arm/mach-spear3xx/include/mach/spear310.h b/arch/arm/mach-spear3xx/include/mach/spear310.h
deleted file mode 100644
index 1567d0da725f..000000000000
--- a/arch/arm/mach-spear3xx/include/mach/spear310.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * arch/arm/mach-spear3xx/include/mach/spear310.h
- *
- * SPEAr310 Machine specific definition
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifdef CONFIG_MACH_SPEAR310
-
-#ifndef __MACH_SPEAR310_H
-#define __MACH_SPEAR310_H
-
-#define SPEAR310_NAND_BASE UL(0x40000000)
-#define SPEAR310_FSMC_BASE UL(0x44000000)
-#define SPEAR310_UART1_BASE UL(0xB2000000)
-#define SPEAR310_UART2_BASE UL(0xB2080000)
-#define SPEAR310_UART3_BASE UL(0xB2100000)
-#define SPEAR310_UART4_BASE UL(0xB2180000)
-#define SPEAR310_UART5_BASE UL(0xB2200000)
-#define SPEAR310_HDLC_BASE UL(0xB2800000)
-#define SPEAR310_RS485_0_BASE UL(0xB3000000)
-#define SPEAR310_RS485_1_BASE UL(0xB3800000)
-#define SPEAR310_SOC_CONFIG_BASE UL(0xB4000000)
-
-/* Interrupt registers offsets and masks */
-#define SPEAR310_INT_STS_MASK_REG 0x04
-#define SPEAR310_SMII0_IRQ_MASK (1 << 0)
-#define SPEAR310_SMII1_IRQ_MASK (1 << 1)
-#define SPEAR310_SMII2_IRQ_MASK (1 << 2)
-#define SPEAR310_SMII3_IRQ_MASK (1 << 3)
-#define SPEAR310_WAKEUP_SMII0_IRQ_MASK (1 << 4)
-#define SPEAR310_WAKEUP_SMII1_IRQ_MASK (1 << 5)
-#define SPEAR310_WAKEUP_SMII2_IRQ_MASK (1 << 6)
-#define SPEAR310_WAKEUP_SMII3_IRQ_MASK (1 << 7)
-#define SPEAR310_UART1_IRQ_MASK (1 << 8)
-#define SPEAR310_UART2_IRQ_MASK (1 << 9)
-#define SPEAR310_UART3_IRQ_MASK (1 << 10)
-#define SPEAR310_UART4_IRQ_MASK (1 << 11)
-#define SPEAR310_UART5_IRQ_MASK (1 << 12)
-#define SPEAR310_EMI_IRQ_MASK (1 << 13)
-#define SPEAR310_TDM_HDLC_IRQ_MASK (1 << 14)
-#define SPEAR310_RS485_0_IRQ_MASK (1 << 15)
-#define SPEAR310_RS485_1_IRQ_MASK (1 << 16)
-
-#define SPEAR310_SHIRQ_RAS1_MASK 0x000FF
-#define SPEAR310_SHIRQ_RAS2_MASK 0x01F00
-#define SPEAR310_SHIRQ_RAS3_MASK 0x02000
-#define SPEAR310_SHIRQ_INTRCOMM_RAS_MASK 0x1C000
-
-#endif /* __MACH_SPEAR310_H */
-
-#endif /* CONFIG_MACH_SPEAR310 */
diff --git a/arch/arm/mach-spear3xx/include/mach/spear320.h b/arch/arm/mach-spear3xx/include/mach/spear320.h
deleted file mode 100644
index 8cfa83fa1296..000000000000
--- a/arch/arm/mach-spear3xx/include/mach/spear320.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * arch/arm/mach-spear3xx/include/mach/spear320.h
- *
- * SPEAr320 Machine specific definition
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifdef CONFIG_MACH_SPEAR320
-
-#ifndef __MACH_SPEAR320_H
-#define __MACH_SPEAR320_H
-
-#define SPEAR320_EMI_CTRL_BASE UL(0x40000000)
-#define SPEAR320_FSMC_BASE UL(0x4C000000)
-#define SPEAR320_NAND_BASE UL(0x50000000)
-#define SPEAR320_I2S_BASE UL(0x60000000)
-#define SPEAR320_SDHCI_BASE UL(0x70000000)
-#define SPEAR320_CLCD_BASE UL(0x90000000)
-#define SPEAR320_PAR_PORT_BASE UL(0xA0000000)
-#define SPEAR320_CAN0_BASE UL(0xA1000000)
-#define SPEAR320_CAN1_BASE UL(0xA2000000)
-#define SPEAR320_UART1_BASE UL(0xA3000000)
-#define SPEAR320_UART2_BASE UL(0xA4000000)
-#define SPEAR320_SSP0_BASE UL(0xA5000000)
-#define SPEAR320_SSP1_BASE UL(0xA6000000)
-#define SPEAR320_I2C_BASE UL(0xA7000000)
-#define SPEAR320_PWM_BASE UL(0xA8000000)
-#define SPEAR320_SMII0_BASE UL(0xAA000000)
-#define SPEAR320_SMII1_BASE UL(0xAB000000)
-#define SPEAR320_SOC_CONFIG_BASE UL(0xB3000000)
-
-/* Interrupt registers offsets and masks */
-#define SPEAR320_INT_STS_MASK_REG 0x04
-#define SPEAR320_INT_CLR_MASK_REG 0x04
-#define SPEAR320_INT_ENB_MASK_REG 0x08
-#define SPEAR320_GPIO_IRQ_MASK (1 << 0)
-#define SPEAR320_I2S_PLAY_IRQ_MASK (1 << 1)
-#define SPEAR320_I2S_REC_IRQ_MASK (1 << 2)
-#define SPEAR320_EMI_IRQ_MASK (1 << 7)
-#define SPEAR320_CLCD_IRQ_MASK (1 << 8)
-#define SPEAR320_SPP_IRQ_MASK (1 << 9)
-#define SPEAR320_SDHCI_IRQ_MASK (1 << 10)
-#define SPEAR320_CAN_U_IRQ_MASK (1 << 11)
-#define SPEAR320_CAN_L_IRQ_MASK (1 << 12)
-#define SPEAR320_UART1_IRQ_MASK (1 << 13)
-#define SPEAR320_UART2_IRQ_MASK (1 << 14)
-#define SPEAR320_SSP1_IRQ_MASK (1 << 15)
-#define SPEAR320_SSP2_IRQ_MASK (1 << 16)
-#define SPEAR320_SMII0_IRQ_MASK (1 << 17)
-#define SPEAR320_MII1_SMII1_IRQ_MASK (1 << 18)
-#define SPEAR320_WAKEUP_SMII0_IRQ_MASK (1 << 19)
-#define SPEAR320_WAKEUP_MII1_SMII1_IRQ_MASK (1 << 20)
-#define SPEAR320_I2C1_IRQ_MASK (1 << 21)
-
-#define SPEAR320_SHIRQ_RAS1_MASK 0x000380
-#define SPEAR320_SHIRQ_RAS3_MASK 0x000007
-#define SPEAR320_SHIRQ_INTRCOMM_RAS_MASK 0x3FF800
-
-#endif /* __MACH_SPEAR320_H */
-
-#endif /* CONFIG_MACH_SPEAR320 */
diff --git a/arch/arm/mach-spear3xx/spear300.c b/arch/arm/mach-spear3xx/spear300.c
index f7db66812abb..f75fe25a620c 100644
--- a/arch/arm/mach-spear3xx/spear300.c
+++ b/arch/arm/mach-spear3xx/spear300.c
@@ -3,372 +3,62 @@
*
* SPEAr300 machine source file
*
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
+ * Copyright (C) 2009-2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
-#include <linux/types.h>
-#include <linux/amba/pl061.h>
-#include <linux/ptrace.h>
-#include <asm/irq.h>
+#define pr_fmt(fmt) "SPEAr300: " fmt
+
+#include <linux/amba/pl08x.h>
+#include <linux/of_platform.h>
+#include <asm/hardware/vic.h>
+#include <asm/mach/arch.h>
#include <plat/shirq.h>
#include <mach/generic.h>
-#include <mach/hardware.h>
-
-/* pad multiplexing support */
-/* muxing registers */
-#define PAD_MUX_CONFIG_REG 0x00
-#define MODE_CONFIG_REG 0x04
-
-/* modes */
-#define NAND_MODE (1 << 0)
-#define NOR_MODE (1 << 1)
-#define PHOTO_FRAME_MODE (1 << 2)
-#define LEND_IP_PHONE_MODE (1 << 3)
-#define HEND_IP_PHONE_MODE (1 << 4)
-#define LEND_WIFI_PHONE_MODE (1 << 5)
-#define HEND_WIFI_PHONE_MODE (1 << 6)
-#define ATA_PABX_WI2S_MODE (1 << 7)
-#define ATA_PABX_I2S_MODE (1 << 8)
-#define CAML_LCDW_MODE (1 << 9)
-#define CAMU_LCD_MODE (1 << 10)
-#define CAMU_WLCD_MODE (1 << 11)
-#define CAML_LCD_MODE (1 << 12)
-#define ALL_MODES 0x1FFF
-
-struct pmx_mode spear300_nand_mode = {
- .id = NAND_MODE,
- .name = "nand mode",
- .mask = 0x00,
-};
-
-struct pmx_mode spear300_nor_mode = {
- .id = NOR_MODE,
- .name = "nor mode",
- .mask = 0x01,
-};
-
-struct pmx_mode spear300_photo_frame_mode = {
- .id = PHOTO_FRAME_MODE,
- .name = "photo frame mode",
- .mask = 0x02,
-};
-
-struct pmx_mode spear300_lend_ip_phone_mode = {
- .id = LEND_IP_PHONE_MODE,
- .name = "lend ip phone mode",
- .mask = 0x03,
-};
-
-struct pmx_mode spear300_hend_ip_phone_mode = {
- .id = HEND_IP_PHONE_MODE,
- .name = "hend ip phone mode",
- .mask = 0x04,
-};
-
-struct pmx_mode spear300_lend_wifi_phone_mode = {
- .id = LEND_WIFI_PHONE_MODE,
- .name = "lend wifi phone mode",
- .mask = 0x05,
-};
-
-struct pmx_mode spear300_hend_wifi_phone_mode = {
- .id = HEND_WIFI_PHONE_MODE,
- .name = "hend wifi phone mode",
- .mask = 0x06,
-};
-
-struct pmx_mode spear300_ata_pabx_wi2s_mode = {
- .id = ATA_PABX_WI2S_MODE,
- .name = "ata pabx wi2s mode",
- .mask = 0x07,
-};
-
-struct pmx_mode spear300_ata_pabx_i2s_mode = {
- .id = ATA_PABX_I2S_MODE,
- .name = "ata pabx i2s mode",
- .mask = 0x08,
-};
-
-struct pmx_mode spear300_caml_lcdw_mode = {
- .id = CAML_LCDW_MODE,
- .name = "caml lcdw mode",
- .mask = 0x0C,
-};
-
-struct pmx_mode spear300_camu_lcd_mode = {
- .id = CAMU_LCD_MODE,
- .name = "camu lcd mode",
- .mask = 0x0D,
-};
-
-struct pmx_mode spear300_camu_wlcd_mode = {
- .id = CAMU_WLCD_MODE,
- .name = "camu wlcd mode",
- .mask = 0x0E,
-};
-
-struct pmx_mode spear300_caml_lcd_mode = {
- .id = CAML_LCD_MODE,
- .name = "caml lcd mode",
- .mask = 0x0F,
-};
-
-/* devices */
-static struct pmx_dev_mode pmx_fsmc_2_chips_modes[] = {
- {
- .ids = NAND_MODE | NOR_MODE | PHOTO_FRAME_MODE |
- ATA_PABX_WI2S_MODE | ATA_PABX_I2S_MODE,
- .mask = PMX_FIRDA_MASK,
- },
-};
-
-struct pmx_dev spear300_pmx_fsmc_2_chips = {
- .name = "fsmc_2_chips",
- .modes = pmx_fsmc_2_chips_modes,
- .mode_count = ARRAY_SIZE(pmx_fsmc_2_chips_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_fsmc_4_chips_modes[] = {
- {
- .ids = NAND_MODE | NOR_MODE | PHOTO_FRAME_MODE |
- ATA_PABX_WI2S_MODE | ATA_PABX_I2S_MODE,
- .mask = PMX_FIRDA_MASK | PMX_UART0_MASK,
- },
-};
-
-struct pmx_dev spear300_pmx_fsmc_4_chips = {
- .name = "fsmc_4_chips",
- .modes = pmx_fsmc_4_chips_modes,
- .mode_count = ARRAY_SIZE(pmx_fsmc_4_chips_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_keyboard_modes[] = {
- {
- .ids = LEND_IP_PHONE_MODE | HEND_IP_PHONE_MODE |
- LEND_WIFI_PHONE_MODE | HEND_WIFI_PHONE_MODE |
- CAML_LCDW_MODE | CAMU_LCD_MODE | CAMU_WLCD_MODE |
- CAML_LCD_MODE,
- .mask = 0x0,
- },
-};
-
-struct pmx_dev spear300_pmx_keyboard = {
- .name = "keyboard",
- .modes = pmx_keyboard_modes,
- .mode_count = ARRAY_SIZE(pmx_keyboard_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_clcd_modes[] = {
- {
- .ids = PHOTO_FRAME_MODE,
- .mask = PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK ,
- }, {
- .ids = HEND_IP_PHONE_MODE | HEND_WIFI_PHONE_MODE |
- CAMU_LCD_MODE | CAML_LCD_MODE,
- .mask = PMX_TIMER_3_4_MASK,
- },
-};
-
-struct pmx_dev spear300_pmx_clcd = {
- .name = "clcd",
- .modes = pmx_clcd_modes,
- .mode_count = ARRAY_SIZE(pmx_clcd_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_telecom_gpio_modes[] = {
- {
- .ids = PHOTO_FRAME_MODE | CAMU_LCD_MODE | CAML_LCD_MODE,
- .mask = PMX_MII_MASK,
- }, {
- .ids = LEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE,
- .mask = PMX_MII_MASK | PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK,
- }, {
- .ids = ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_WLCD_MODE,
- .mask = PMX_MII_MASK | PMX_TIMER_3_4_MASK,
- }, {
- .ids = HEND_IP_PHONE_MODE | HEND_WIFI_PHONE_MODE,
- .mask = PMX_MII_MASK | PMX_TIMER_1_2_MASK,
- }, {
- .ids = ATA_PABX_WI2S_MODE,
- .mask = PMX_MII_MASK | PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK
- | PMX_UART0_MODEM_MASK,
- },
-};
-
-struct pmx_dev spear300_pmx_telecom_gpio = {
- .name = "telecom_gpio",
- .modes = pmx_telecom_gpio_modes,
- .mode_count = ARRAY_SIZE(pmx_telecom_gpio_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_telecom_tdm_modes[] = {
- {
- .ids = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE |
- HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE
- | HEND_WIFI_PHONE_MODE | ATA_PABX_WI2S_MODE
- | ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE
- | CAMU_WLCD_MODE | CAML_LCD_MODE,
- .mask = PMX_UART0_MODEM_MASK | PMX_SSP_CS_MASK,
- },
-};
-
-struct pmx_dev spear300_pmx_telecom_tdm = {
- .name = "telecom_tdm",
- .modes = pmx_telecom_tdm_modes,
- .mode_count = ARRAY_SIZE(pmx_telecom_tdm_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_telecom_spi_cs_i2c_clk_modes[] = {
- {
- .ids = LEND_IP_PHONE_MODE | HEND_IP_PHONE_MODE |
- LEND_WIFI_PHONE_MODE | HEND_WIFI_PHONE_MODE
- | ATA_PABX_WI2S_MODE | ATA_PABX_I2S_MODE |
- CAML_LCDW_MODE | CAML_LCD_MODE,
- .mask = PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK,
- },
-};
-
-struct pmx_dev spear300_pmx_telecom_spi_cs_i2c_clk = {
- .name = "telecom_spi_cs_i2c_clk",
- .modes = pmx_telecom_spi_cs_i2c_clk_modes,
- .mode_count = ARRAY_SIZE(pmx_telecom_spi_cs_i2c_clk_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_telecom_camera_modes[] = {
- {
- .ids = CAML_LCDW_MODE | CAML_LCD_MODE,
- .mask = PMX_MII_MASK,
- }, {
- .ids = CAMU_LCD_MODE | CAMU_WLCD_MODE,
- .mask = PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK | PMX_MII_MASK,
- },
-};
-
-struct pmx_dev spear300_pmx_telecom_camera = {
- .name = "telecom_camera",
- .modes = pmx_telecom_camera_modes,
- .mode_count = ARRAY_SIZE(pmx_telecom_camera_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_telecom_dac_modes[] = {
- {
- .ids = ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE
- | CAMU_WLCD_MODE | CAML_LCD_MODE,
- .mask = PMX_TIMER_1_2_MASK,
- },
-};
-
-struct pmx_dev spear300_pmx_telecom_dac = {
- .name = "telecom_dac",
- .modes = pmx_telecom_dac_modes,
- .mode_count = ARRAY_SIZE(pmx_telecom_dac_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_telecom_i2s_modes[] = {
- {
- .ids = LEND_IP_PHONE_MODE | HEND_IP_PHONE_MODE
- | LEND_WIFI_PHONE_MODE | HEND_WIFI_PHONE_MODE |
- ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE
- | CAMU_WLCD_MODE | CAML_LCD_MODE,
- .mask = PMX_UART0_MODEM_MASK,
- },
-};
-
-struct pmx_dev spear300_pmx_telecom_i2s = {
- .name = "telecom_i2s",
- .modes = pmx_telecom_i2s_modes,
- .mode_count = ARRAY_SIZE(pmx_telecom_i2s_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_telecom_boot_pins_modes[] = {
- {
- .ids = NAND_MODE | NOR_MODE,
- .mask = PMX_UART0_MODEM_MASK | PMX_TIMER_1_2_MASK |
- PMX_TIMER_3_4_MASK,
- },
-};
-
-struct pmx_dev spear300_pmx_telecom_boot_pins = {
- .name = "telecom_boot_pins",
- .modes = pmx_telecom_boot_pins_modes,
- .mode_count = ARRAY_SIZE(pmx_telecom_boot_pins_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_telecom_sdhci_4bit_modes[] = {
- {
- .ids = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE |
- HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE |
- HEND_WIFI_PHONE_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE |
- CAMU_WLCD_MODE | CAML_LCD_MODE | ATA_PABX_WI2S_MODE |
- ATA_PABX_I2S_MODE,
- .mask = PMX_GPIO_PIN0_MASK | PMX_GPIO_PIN1_MASK |
- PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK |
- PMX_GPIO_PIN4_MASK | PMX_GPIO_PIN5_MASK,
- },
-};
-
-struct pmx_dev spear300_pmx_telecom_sdhci_4bit = {
- .name = "telecom_sdhci_4bit",
- .modes = pmx_telecom_sdhci_4bit_modes,
- .mode_count = ARRAY_SIZE(pmx_telecom_sdhci_4bit_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_telecom_sdhci_8bit_modes[] = {
- {
- .ids = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE |
- HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE |
- HEND_WIFI_PHONE_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE |
- CAMU_WLCD_MODE | CAML_LCD_MODE,
- .mask = PMX_GPIO_PIN0_MASK | PMX_GPIO_PIN1_MASK |
- PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK |
- PMX_GPIO_PIN4_MASK | PMX_GPIO_PIN5_MASK | PMX_MII_MASK,
- },
-};
-
-struct pmx_dev spear300_pmx_telecom_sdhci_8bit = {
- .name = "telecom_sdhci_8bit",
- .modes = pmx_telecom_sdhci_8bit_modes,
- .mode_count = ARRAY_SIZE(pmx_telecom_sdhci_8bit_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_gpio1_modes[] = {
- {
- .ids = PHOTO_FRAME_MODE,
- .mask = PMX_UART0_MODEM_MASK | PMX_TIMER_1_2_MASK |
- PMX_TIMER_3_4_MASK,
- },
-};
-
-struct pmx_dev spear300_pmx_gpio1 = {
- .name = "arm gpio1",
- .modes = pmx_gpio1_modes,
- .mode_count = ARRAY_SIZE(pmx_gpio1_modes),
- .enb_on_reset = 1,
-};
-
-/* pmx driver structure */
-static struct pmx_driver pmx_driver = {
- .mode_reg = {.offset = MODE_CONFIG_REG, .mask = 0x0000000f},
- .mux_reg = {.offset = PAD_MUX_CONFIG_REG, .mask = 0x00007fff},
-};
+#include <mach/spear.h>
+
+/* Base address of various IPs */
+#define SPEAR300_TELECOM_BASE UL(0x50000000)
+
+/* Interrupt registers offsets and masks */
+#define SPEAR300_INT_ENB_MASK_REG 0x54
+#define SPEAR300_INT_STS_MASK_REG 0x58
+#define SPEAR300_IT_PERS_S_IRQ_MASK (1 << 0)
+#define SPEAR300_IT_CHANGE_S_IRQ_MASK (1 << 1)
+#define SPEAR300_I2S_IRQ_MASK (1 << 2)
+#define SPEAR300_TDM_IRQ_MASK (1 << 3)
+#define SPEAR300_CAMERA_L_IRQ_MASK (1 << 4)
+#define SPEAR300_CAMERA_F_IRQ_MASK (1 << 5)
+#define SPEAR300_CAMERA_V_IRQ_MASK (1 << 6)
+#define SPEAR300_KEYBOARD_IRQ_MASK (1 << 7)
+#define SPEAR300_GPIO1_IRQ_MASK (1 << 8)
+
+#define SPEAR300_SHIRQ_RAS1_MASK 0x1FF
+
+#define SPEAR300_SOC_CONFIG_BASE UL(0x99000000)
+
+
+/* SPEAr300 Virtual irq definitions */
+/* IRQs sharing IRQ_GEN_RAS_1 */
+#define SPEAR300_VIRQ_IT_PERS_S (SPEAR3XX_VIRQ_START + 0)
+#define SPEAR300_VIRQ_IT_CHANGE_S (SPEAR3XX_VIRQ_START + 1)
+#define SPEAR300_VIRQ_I2S (SPEAR3XX_VIRQ_START + 2)
+#define SPEAR300_VIRQ_TDM (SPEAR3XX_VIRQ_START + 3)
+#define SPEAR300_VIRQ_CAMERA_L (SPEAR3XX_VIRQ_START + 4)
+#define SPEAR300_VIRQ_CAMERA_F (SPEAR3XX_VIRQ_START + 5)
+#define SPEAR300_VIRQ_CAMERA_V (SPEAR3XX_VIRQ_START + 6)
+#define SPEAR300_VIRQ_KEYBOARD (SPEAR3XX_VIRQ_START + 7)
+#define SPEAR300_VIRQ_GPIO1 (SPEAR3XX_VIRQ_START + 8)
+
+/* IRQs sharing IRQ_GEN_RAS_3 */
+#define SPEAR300_IRQ_CLCD SPEAR3XX_IRQ_GEN_RAS_3
+
+/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */
+#define SPEAR300_IRQ_SDHCI SPEAR3XX_IRQ_INTRCOMM_RAS_ARM
/* spear3xx shared irq */
static struct shirq_dev_config shirq_ras1_config[] = {
@@ -423,45 +113,239 @@ static struct spear_shirq shirq_ras1 = {
},
};
-/* Add spear300 specific devices here */
-/* arm gpio1 device registration */
-static struct pl061_platform_data gpio1_plat_data = {
- .gpio_base = 8,
- .irq_base = SPEAR300_GPIO1_INT_BASE,
+/* DMAC platform data's slave info */
+struct pl08x_channel_data spear300_dma_info[] = {
+ {
+ .bus_id = "uart0_rx",
+ .min_signal = 2,
+ .max_signal = 2,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart0_tx",
+ .min_signal = 3,
+ .max_signal = 3,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ssp0_rx",
+ .min_signal = 8,
+ .max_signal = 8,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ssp0_tx",
+ .min_signal = 9,
+ .max_signal = 9,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "i2c_rx",
+ .min_signal = 10,
+ .max_signal = 10,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "i2c_tx",
+ .min_signal = 11,
+ .max_signal = 11,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "irda",
+ .min_signal = 12,
+ .max_signal = 12,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "adc",
+ .min_signal = 13,
+ .max_signal = 13,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "to_jpeg",
+ .min_signal = 14,
+ .max_signal = 14,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "from_jpeg",
+ .min_signal = 15,
+ .max_signal = 15,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras0_rx",
+ .min_signal = 0,
+ .max_signal = 0,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras0_tx",
+ .min_signal = 1,
+ .max_signal = 1,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras1_rx",
+ .min_signal = 2,
+ .max_signal = 2,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras1_tx",
+ .min_signal = 3,
+ .max_signal = 3,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras2_rx",
+ .min_signal = 4,
+ .max_signal = 4,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras2_tx",
+ .min_signal = 5,
+ .max_signal = 5,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras3_rx",
+ .min_signal = 6,
+ .max_signal = 6,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras3_tx",
+ .min_signal = 7,
+ .max_signal = 7,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras4_rx",
+ .min_signal = 8,
+ .max_signal = 8,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras4_tx",
+ .min_signal = 9,
+ .max_signal = 9,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras5_rx",
+ .min_signal = 10,
+ .max_signal = 10,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras5_tx",
+ .min_signal = 11,
+ .max_signal = 11,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras6_rx",
+ .min_signal = 12,
+ .max_signal = 12,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras6_tx",
+ .min_signal = 13,
+ .max_signal = 13,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras7_rx",
+ .min_signal = 14,
+ .max_signal = 14,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras7_tx",
+ .min_signal = 15,
+ .max_signal = 15,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ },
};
-AMBA_APB_DEVICE(spear300_gpio1, "gpio1", 0, SPEAR300_GPIO_BASE,
- {SPEAR300_VIRQ_GPIO1}, &gpio1_plat_data);
+/* Add SPEAr300 auxdata to pass platform data */
+static struct of_dev_auxdata spear300_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("arm,pl022", SPEAR3XX_ICM1_SSP_BASE, NULL,
+ &pl022_plat_data),
+ OF_DEV_AUXDATA("arm,pl080", SPEAR3XX_ICM3_DMA_BASE, NULL,
+ &pl080_plat_data),
+ {}
+};
-/* spear300 routines */
-void __init spear300_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs,
- u8 pmx_dev_count)
+static void __init spear300_dt_init(void)
{
- int ret = 0;
+ int ret;
+
+ pl080_plat_data.slave_channels = spear300_dma_info;
+ pl080_plat_data.num_slave_channels = ARRAY_SIZE(spear300_dma_info);
- /* call spear3xx family common init function */
- spear3xx_init();
+ of_platform_populate(NULL, of_default_bus_match_table,
+ spear300_auxdata_lookup, NULL);
/* shared irq registration */
shirq_ras1.regs.base = ioremap(SPEAR300_TELECOM_BASE, SZ_4K);
if (shirq_ras1.regs.base) {
ret = spear_shirq_register(&shirq_ras1);
if (ret)
- printk(KERN_ERR "Error registering Shared IRQ\n");
+ pr_err("Error registering Shared IRQ\n");
}
+}
- /* pmx initialization */
- pmx_driver.mode = pmx_mode;
- pmx_driver.devs = pmx_devs;
- pmx_driver.devs_count = pmx_dev_count;
+static const char * const spear300_dt_board_compat[] = {
+ "st,spear300",
+ "st,spear300-evb",
+ NULL,
+};
- pmx_driver.base = ioremap(SPEAR300_SOC_CONFIG_BASE, SZ_4K);
- if (pmx_driver.base) {
- ret = pmx_register(&pmx_driver);
- if (ret)
- printk(KERN_ERR "padmux: registration failed. err no"
- ": %d\n", ret);
- /* Free Mapping, device selection already done */
- iounmap(pmx_driver.base);
- }
+static void __init spear300_map_io(void)
+{
+ spear3xx_map_io();
+ spear300_clk_init();
}
+
+DT_MACHINE_START(SPEAR300_DT, "ST SPEAr300 SoC with Flattened Device Tree")
+ .map_io = spear300_map_io,
+ .init_irq = spear3xx_dt_init_irq,
+ .handle_irq = vic_handle_irq,
+ .timer = &spear3xx_timer,
+ .init_machine = spear300_dt_init,
+ .restart = spear_restart,
+ .dt_compat = spear300_dt_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-spear3xx/spear300_evb.c b/arch/arm/mach-spear3xx/spear300_evb.c
deleted file mode 100644
index 3462ab9d6122..000000000000
--- a/arch/arm/mach-spear3xx/spear300_evb.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * arch/arm/mach-spear3xx/spear300_evb.c
- *
- * SPEAr300 evaluation board source file
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <asm/hardware/vic.h>
-#include <asm/mach/arch.h>
-#include <asm/mach-types.h>
-#include <mach/generic.h>
-#include <mach/hardware.h>
-
-/* padmux devices to enable */
-static struct pmx_dev *pmx_devs[] = {
- /* spear3xx specific devices */
- &spear3xx_pmx_i2c,
- &spear3xx_pmx_ssp_cs,
- &spear3xx_pmx_ssp,
- &spear3xx_pmx_mii,
- &spear3xx_pmx_uart0,
-
- /* spear300 specific devices */
- &spear300_pmx_fsmc_2_chips,
- &spear300_pmx_clcd,
- &spear300_pmx_telecom_sdhci_4bit,
- &spear300_pmx_gpio1,
-};
-
-static struct amba_device *amba_devs[] __initdata = {
- /* spear3xx specific devices */
- &spear3xx_gpio_device,
- &spear3xx_uart_device,
-
- /* spear300 specific devices */
- &spear300_gpio1_device,
-};
-
-static struct platform_device *plat_devs[] __initdata = {
- /* spear3xx specific devices */
-
- /* spear300 specific devices */
-};
-
-static void __init spear300_evb_init(void)
-{
- unsigned int i;
-
- /* call spear300 machine init function */
- spear300_init(&spear300_photo_frame_mode, pmx_devs,
- ARRAY_SIZE(pmx_devs));
-
- /* Add Platform Devices */
- platform_add_devices(plat_devs, ARRAY_SIZE(plat_devs));
-
- /* Add Amba Devices */
- for (i = 0; i < ARRAY_SIZE(amba_devs); i++)
- amba_device_register(amba_devs[i], &iomem_resource);
-}
-
-MACHINE_START(SPEAR300, "ST-SPEAR300-EVB")
- .atag_offset = 0x100,
- .map_io = spear3xx_map_io,
- .init_irq = spear3xx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &spear3xx_timer,
- .init_machine = spear300_evb_init,
- .restart = spear_restart,
-MACHINE_END
diff --git a/arch/arm/mach-spear3xx/spear310.c b/arch/arm/mach-spear3xx/spear310.c
index febaa6fcfb6a..f0842a58dc02 100644
--- a/arch/arm/mach-spear3xx/spear310.c
+++ b/arch/arm/mach-spear3xx/spear310.c
@@ -3,141 +3,84 @@
*
* SPEAr310 machine source file
*
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
+ * Copyright (C) 2009-2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
-#include <linux/ptrace.h>
-#include <asm/irq.h>
+#define pr_fmt(fmt) "SPEAr310: " fmt
+
+#include <linux/amba/pl08x.h>
+#include <linux/amba/serial.h>
+#include <linux/of_platform.h>
+#include <asm/hardware/vic.h>
+#include <asm/mach/arch.h>
#include <plat/shirq.h>
#include <mach/generic.h>
-#include <mach/hardware.h>
-
-/* pad multiplexing support */
-/* muxing registers */
-#define PAD_MUX_CONFIG_REG 0x08
-
-/* devices */
-static struct pmx_dev_mode pmx_emi_cs_0_1_4_5_modes[] = {
- {
- .ids = 0x00,
- .mask = PMX_TIMER_3_4_MASK,
- },
-};
-
-struct pmx_dev spear310_pmx_emi_cs_0_1_4_5 = {
- .name = "emi_cs_0_1_4_5",
- .modes = pmx_emi_cs_0_1_4_5_modes,
- .mode_count = ARRAY_SIZE(pmx_emi_cs_0_1_4_5_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_emi_cs_2_3_modes[] = {
- {
- .ids = 0x00,
- .mask = PMX_TIMER_1_2_MASK,
- },
-};
-
-struct pmx_dev spear310_pmx_emi_cs_2_3 = {
- .name = "emi_cs_2_3",
- .modes = pmx_emi_cs_2_3_modes,
- .mode_count = ARRAY_SIZE(pmx_emi_cs_2_3_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_uart1_modes[] = {
- {
- .ids = 0x00,
- .mask = PMX_FIRDA_MASK,
- },
-};
-
-struct pmx_dev spear310_pmx_uart1 = {
- .name = "uart1",
- .modes = pmx_uart1_modes,
- .mode_count = ARRAY_SIZE(pmx_uart1_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_uart2_modes[] = {
- {
- .ids = 0x00,
- .mask = PMX_TIMER_1_2_MASK,
- },
-};
-
-struct pmx_dev spear310_pmx_uart2 = {
- .name = "uart2",
- .modes = pmx_uart2_modes,
- .mode_count = ARRAY_SIZE(pmx_uart2_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_uart3_4_5_modes[] = {
- {
- .ids = 0x00,
- .mask = PMX_UART0_MODEM_MASK,
- },
-};
-
-struct pmx_dev spear310_pmx_uart3_4_5 = {
- .name = "uart3_4_5",
- .modes = pmx_uart3_4_5_modes,
- .mode_count = ARRAY_SIZE(pmx_uart3_4_5_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_fsmc_modes[] = {
- {
- .ids = 0x00,
- .mask = PMX_SSP_CS_MASK,
- },
-};
-
-struct pmx_dev spear310_pmx_fsmc = {
- .name = "fsmc",
- .modes = pmx_fsmc_modes,
- .mode_count = ARRAY_SIZE(pmx_fsmc_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_rs485_0_1_modes[] = {
- {
- .ids = 0x00,
- .mask = PMX_MII_MASK,
- },
-};
-
-struct pmx_dev spear310_pmx_rs485_0_1 = {
- .name = "rs485_0_1",
- .modes = pmx_rs485_0_1_modes,
- .mode_count = ARRAY_SIZE(pmx_rs485_0_1_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_tdm0_modes[] = {
- {
- .ids = 0x00,
- .mask = PMX_MII_MASK,
- },
-};
-
-struct pmx_dev spear310_pmx_tdm0 = {
- .name = "tdm0",
- .modes = pmx_tdm0_modes,
- .mode_count = ARRAY_SIZE(pmx_tdm0_modes),
- .enb_on_reset = 1,
-};
+#include <mach/spear.h>
+
+#define SPEAR310_UART1_BASE UL(0xB2000000)
+#define SPEAR310_UART2_BASE UL(0xB2080000)
+#define SPEAR310_UART3_BASE UL(0xB2100000)
+#define SPEAR310_UART4_BASE UL(0xB2180000)
+#define SPEAR310_UART5_BASE UL(0xB2200000)
+#define SPEAR310_SOC_CONFIG_BASE UL(0xB4000000)
+
+/* Interrupt registers offsets and masks */
+#define SPEAR310_INT_STS_MASK_REG 0x04
+#define SPEAR310_SMII0_IRQ_MASK (1 << 0)
+#define SPEAR310_SMII1_IRQ_MASK (1 << 1)
+#define SPEAR310_SMII2_IRQ_MASK (1 << 2)
+#define SPEAR310_SMII3_IRQ_MASK (1 << 3)
+#define SPEAR310_WAKEUP_SMII0_IRQ_MASK (1 << 4)
+#define SPEAR310_WAKEUP_SMII1_IRQ_MASK (1 << 5)
+#define SPEAR310_WAKEUP_SMII2_IRQ_MASK (1 << 6)
+#define SPEAR310_WAKEUP_SMII3_IRQ_MASK (1 << 7)
+#define SPEAR310_UART1_IRQ_MASK (1 << 8)
+#define SPEAR310_UART2_IRQ_MASK (1 << 9)
+#define SPEAR310_UART3_IRQ_MASK (1 << 10)
+#define SPEAR310_UART4_IRQ_MASK (1 << 11)
+#define SPEAR310_UART5_IRQ_MASK (1 << 12)
+#define SPEAR310_EMI_IRQ_MASK (1 << 13)
+#define SPEAR310_TDM_HDLC_IRQ_MASK (1 << 14)
+#define SPEAR310_RS485_0_IRQ_MASK (1 << 15)
+#define SPEAR310_RS485_1_IRQ_MASK (1 << 16)
+
+#define SPEAR310_SHIRQ_RAS1_MASK 0x000FF
+#define SPEAR310_SHIRQ_RAS2_MASK 0x01F00
+#define SPEAR310_SHIRQ_RAS3_MASK 0x02000
+#define SPEAR310_SHIRQ_INTRCOMM_RAS_MASK 0x1C000
+
+/* SPEAr310 Virtual irq definitions */
+/* IRQs sharing IRQ_GEN_RAS_1 */
+#define SPEAR310_VIRQ_SMII0 (SPEAR3XX_VIRQ_START + 0)
+#define SPEAR310_VIRQ_SMII1 (SPEAR3XX_VIRQ_START + 1)
+#define SPEAR310_VIRQ_SMII2 (SPEAR3XX_VIRQ_START + 2)
+#define SPEAR310_VIRQ_SMII3 (SPEAR3XX_VIRQ_START + 3)
+#define SPEAR310_VIRQ_WAKEUP_SMII0 (SPEAR3XX_VIRQ_START + 4)
+#define SPEAR310_VIRQ_WAKEUP_SMII1 (SPEAR3XX_VIRQ_START + 5)
+#define SPEAR310_VIRQ_WAKEUP_SMII2 (SPEAR3XX_VIRQ_START + 6)
+#define SPEAR310_VIRQ_WAKEUP_SMII3 (SPEAR3XX_VIRQ_START + 7)
+
+/* IRQs sharing IRQ_GEN_RAS_2 */
+#define SPEAR310_VIRQ_UART1 (SPEAR3XX_VIRQ_START + 8)
+#define SPEAR310_VIRQ_UART2 (SPEAR3XX_VIRQ_START + 9)
+#define SPEAR310_VIRQ_UART3 (SPEAR3XX_VIRQ_START + 10)
+#define SPEAR310_VIRQ_UART4 (SPEAR3XX_VIRQ_START + 11)
+#define SPEAR310_VIRQ_UART5 (SPEAR3XX_VIRQ_START + 12)
+
+/* IRQs sharing IRQ_GEN_RAS_3 */
+#define SPEAR310_VIRQ_EMI (SPEAR3XX_VIRQ_START + 13)
+#define SPEAR310_VIRQ_PLGPIO (SPEAR3XX_VIRQ_START + 14)
+
+/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */
+#define SPEAR310_VIRQ_TDM_HDLC (SPEAR3XX_VIRQ_START + 15)
+#define SPEAR310_VIRQ_RS485_0 (SPEAR3XX_VIRQ_START + 16)
+#define SPEAR310_VIRQ_RS485_1 (SPEAR3XX_VIRQ_START + 17)
-/* pmx driver structure */
-static struct pmx_driver pmx_driver = {
- .mux_reg = {.offset = PAD_MUX_CONFIG_REG, .mask = 0x00007fff},
-};
/* spear3xx shared irq */
static struct shirq_dev_config shirq_ras1_config[] = {
@@ -255,17 +198,247 @@ static struct spear_shirq shirq_intrcomm_ras = {
},
};
-/* Add spear310 specific devices here */
+/* DMAC platform data's slave info */
+struct pl08x_channel_data spear310_dma_info[] = {
+ {
+ .bus_id = "uart0_rx",
+ .min_signal = 2,
+ .max_signal = 2,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart0_tx",
+ .min_signal = 3,
+ .max_signal = 3,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ssp0_rx",
+ .min_signal = 8,
+ .max_signal = 8,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ssp0_tx",
+ .min_signal = 9,
+ .max_signal = 9,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "i2c_rx",
+ .min_signal = 10,
+ .max_signal = 10,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "i2c_tx",
+ .min_signal = 11,
+ .max_signal = 11,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "irda",
+ .min_signal = 12,
+ .max_signal = 12,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "adc",
+ .min_signal = 13,
+ .max_signal = 13,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "to_jpeg",
+ .min_signal = 14,
+ .max_signal = 14,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "from_jpeg",
+ .min_signal = 15,
+ .max_signal = 15,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart1_rx",
+ .min_signal = 0,
+ .max_signal = 0,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart1_tx",
+ .min_signal = 1,
+ .max_signal = 1,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart2_rx",
+ .min_signal = 2,
+ .max_signal = 2,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart2_tx",
+ .min_signal = 3,
+ .max_signal = 3,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart3_rx",
+ .min_signal = 4,
+ .max_signal = 4,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart3_tx",
+ .min_signal = 5,
+ .max_signal = 5,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart4_rx",
+ .min_signal = 6,
+ .max_signal = 6,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart4_tx",
+ .min_signal = 7,
+ .max_signal = 7,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart5_rx",
+ .min_signal = 8,
+ .max_signal = 8,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart5_tx",
+ .min_signal = 9,
+ .max_signal = 9,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras5_rx",
+ .min_signal = 10,
+ .max_signal = 10,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras5_tx",
+ .min_signal = 11,
+ .max_signal = 11,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras6_rx",
+ .min_signal = 12,
+ .max_signal = 12,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras6_tx",
+ .min_signal = 13,
+ .max_signal = 13,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras7_rx",
+ .min_signal = 14,
+ .max_signal = 14,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras7_tx",
+ .min_signal = 15,
+ .max_signal = 15,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ },
+};
-/* spear310 routines */
-void __init spear310_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs,
- u8 pmx_dev_count)
+/* uart devices plat data */
+static struct amba_pl011_data spear310_uart_data[] = {
+ {
+ .dma_filter = pl08x_filter_id,
+ .dma_tx_param = "uart1_tx",
+ .dma_rx_param = "uart1_rx",
+ }, {
+ .dma_filter = pl08x_filter_id,
+ .dma_tx_param = "uart2_tx",
+ .dma_rx_param = "uart2_rx",
+ }, {
+ .dma_filter = pl08x_filter_id,
+ .dma_tx_param = "uart3_tx",
+ .dma_rx_param = "uart3_rx",
+ }, {
+ .dma_filter = pl08x_filter_id,
+ .dma_tx_param = "uart4_tx",
+ .dma_rx_param = "uart4_rx",
+ }, {
+ .dma_filter = pl08x_filter_id,
+ .dma_tx_param = "uart5_tx",
+ .dma_rx_param = "uart5_rx",
+ },
+};
+
+/* Add SPEAr310 auxdata to pass platform data */
+static struct of_dev_auxdata spear310_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("arm,pl022", SPEAR3XX_ICM1_SSP_BASE, NULL,
+ &pl022_plat_data),
+ OF_DEV_AUXDATA("arm,pl080", SPEAR3XX_ICM3_DMA_BASE, NULL,
+ &pl080_plat_data),
+ OF_DEV_AUXDATA("arm,pl011", SPEAR310_UART1_BASE, NULL,
+ &spear310_uart_data[0]),
+ OF_DEV_AUXDATA("arm,pl011", SPEAR310_UART2_BASE, NULL,
+ &spear310_uart_data[1]),
+ OF_DEV_AUXDATA("arm,pl011", SPEAR310_UART3_BASE, NULL,
+ &spear310_uart_data[2]),
+ OF_DEV_AUXDATA("arm,pl011", SPEAR310_UART4_BASE, NULL,
+ &spear310_uart_data[3]),
+ OF_DEV_AUXDATA("arm,pl011", SPEAR310_UART5_BASE, NULL,
+ &spear310_uart_data[4]),
+ {}
+};
+
+static void __init spear310_dt_init(void)
{
void __iomem *base;
- int ret = 0;
+ int ret;
- /* call spear3xx family common init function */
- spear3xx_init();
+ pl080_plat_data.slave_channels = spear310_dma_info;
+ pl080_plat_data.num_slave_channels = ARRAY_SIZE(spear310_dma_info);
+
+ of_platform_populate(NULL, of_default_bus_match_table,
+ spear310_auxdata_lookup, NULL);
/* shared irq registration */
base = ioremap(SPEAR310_SOC_CONFIG_BASE, SZ_4K);
@@ -274,35 +447,46 @@ void __init spear310_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs,
shirq_ras1.regs.base = base;
ret = spear_shirq_register(&shirq_ras1);
if (ret)
- printk(KERN_ERR "Error registering Shared IRQ 1\n");
+ pr_err("Error registering Shared IRQ 1\n");
/* shirq 2 */
shirq_ras2.regs.base = base;
ret = spear_shirq_register(&shirq_ras2);
if (ret)
- printk(KERN_ERR "Error registering Shared IRQ 2\n");
+ pr_err("Error registering Shared IRQ 2\n");
/* shirq 3 */
shirq_ras3.regs.base = base;
ret = spear_shirq_register(&shirq_ras3);
if (ret)
- printk(KERN_ERR "Error registering Shared IRQ 3\n");
+ pr_err("Error registering Shared IRQ 3\n");
/* shirq 4 */
shirq_intrcomm_ras.regs.base = base;
ret = spear_shirq_register(&shirq_intrcomm_ras);
if (ret)
- printk(KERN_ERR "Error registering Shared IRQ 4\n");
+ pr_err("Error registering Shared IRQ 4\n");
}
+}
- /* pmx initialization */
- pmx_driver.base = base;
- pmx_driver.mode = pmx_mode;
- pmx_driver.devs = pmx_devs;
- pmx_driver.devs_count = pmx_dev_count;
+static const char * const spear310_dt_board_compat[] = {
+ "st,spear310",
+ "st,spear310-evb",
+ NULL,
+};
- ret = pmx_register(&pmx_driver);
- if (ret)
- printk(KERN_ERR "padmux: registration failed. err no: %d\n",
- ret);
+static void __init spear310_map_io(void)
+{
+ spear3xx_map_io();
+ spear310_clk_init();
}
+
+DT_MACHINE_START(SPEAR310_DT, "ST SPEAr310 SoC with Flattened Device Tree")
+ .map_io = spear310_map_io,
+ .init_irq = spear3xx_dt_init_irq,
+ .handle_irq = vic_handle_irq,
+ .timer = &spear3xx_timer,
+ .init_machine = spear310_dt_init,
+ .restart = spear_restart,
+ .dt_compat = spear310_dt_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-spear3xx/spear310_evb.c b/arch/arm/mach-spear3xx/spear310_evb.c
deleted file mode 100644
index f92c4993f65a..000000000000
--- a/arch/arm/mach-spear3xx/spear310_evb.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * arch/arm/mach-spear3xx/spear310_evb.c
- *
- * SPEAr310 evaluation board source file
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <asm/hardware/vic.h>
-#include <asm/mach/arch.h>
-#include <asm/mach-types.h>
-#include <mach/generic.h>
-#include <mach/hardware.h>
-
-/* padmux devices to enable */
-static struct pmx_dev *pmx_devs[] = {
- /* spear3xx specific devices */
- &spear3xx_pmx_i2c,
- &spear3xx_pmx_ssp,
- &spear3xx_pmx_gpio_pin0,
- &spear3xx_pmx_gpio_pin1,
- &spear3xx_pmx_gpio_pin2,
- &spear3xx_pmx_gpio_pin3,
- &spear3xx_pmx_gpio_pin4,
- &spear3xx_pmx_gpio_pin5,
- &spear3xx_pmx_uart0,
-
- /* spear310 specific devices */
- &spear310_pmx_emi_cs_0_1_4_5,
- &spear310_pmx_emi_cs_2_3,
- &spear310_pmx_uart1,
- &spear310_pmx_uart2,
- &spear310_pmx_uart3_4_5,
- &spear310_pmx_fsmc,
- &spear310_pmx_rs485_0_1,
- &spear310_pmx_tdm0,
-};
-
-static struct amba_device *amba_devs[] __initdata = {
- /* spear3xx specific devices */
- &spear3xx_gpio_device,
- &spear3xx_uart_device,
-
- /* spear310 specific devices */
-};
-
-static struct platform_device *plat_devs[] __initdata = {
- /* spear3xx specific devices */
-
- /* spear310 specific devices */
-};
-
-static void __init spear310_evb_init(void)
-{
- unsigned int i;
-
- /* call spear310 machine init function */
- spear310_init(NULL, pmx_devs, ARRAY_SIZE(pmx_devs));
-
- /* Add Platform Devices */
- platform_add_devices(plat_devs, ARRAY_SIZE(plat_devs));
-
- /* Add Amba Devices */
- for (i = 0; i < ARRAY_SIZE(amba_devs); i++)
- amba_device_register(amba_devs[i], &iomem_resource);
-}
-
-MACHINE_START(SPEAR310, "ST-SPEAR310-EVB")
- .atag_offset = 0x100,
- .map_io = spear3xx_map_io,
- .init_irq = spear3xx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &spear3xx_timer,
- .init_machine = spear310_evb_init,
- .restart = spear_restart,
-MACHINE_END
diff --git a/arch/arm/mach-spear3xx/spear320.c b/arch/arm/mach-spear3xx/spear320.c
index deaaf199612c..e8caeef50a5c 100644
--- a/arch/arm/mach-spear3xx/spear320.c
+++ b/arch/arm/mach-spear3xx/spear320.c
@@ -3,386 +3,85 @@
*
* SPEAr320 machine source file
*
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
+ * Copyright (C) 2009-2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
-#include <linux/ptrace.h>
-#include <asm/irq.h>
+#define pr_fmt(fmt) "SPEAr320: " fmt
+
+#include <linux/amba/pl022.h>
+#include <linux/amba/pl08x.h>
+#include <linux/amba/serial.h>
+#include <linux/of_platform.h>
+#include <asm/hardware/vic.h>
+#include <asm/mach/arch.h>
#include <plat/shirq.h>
#include <mach/generic.h>
-#include <mach/hardware.h>
-
-/* pad multiplexing support */
-/* muxing registers */
-#define PAD_MUX_CONFIG_REG 0x0C
-#define MODE_CONFIG_REG 0x10
-
-/* modes */
-#define AUTO_NET_SMII_MODE (1 << 0)
-#define AUTO_NET_MII_MODE (1 << 1)
-#define AUTO_EXP_MODE (1 << 2)
-#define SMALL_PRINTERS_MODE (1 << 3)
-#define ALL_MODES 0xF
-
-struct pmx_mode spear320_auto_net_smii_mode = {
- .id = AUTO_NET_SMII_MODE,
- .name = "Automation Networking SMII Mode",
- .mask = 0x00,
-};
-
-struct pmx_mode spear320_auto_net_mii_mode = {
- .id = AUTO_NET_MII_MODE,
- .name = "Automation Networking MII Mode",
- .mask = 0x01,
-};
-
-struct pmx_mode spear320_auto_exp_mode = {
- .id = AUTO_EXP_MODE,
- .name = "Automation Expanded Mode",
- .mask = 0x02,
-};
-
-struct pmx_mode spear320_small_printers_mode = {
- .id = SMALL_PRINTERS_MODE,
- .name = "Small Printers Mode",
- .mask = 0x03,
-};
-
-/* devices */
-static struct pmx_dev_mode pmx_clcd_modes[] = {
- {
- .ids = AUTO_NET_SMII_MODE,
- .mask = 0x0,
- },
-};
-
-struct pmx_dev spear320_pmx_clcd = {
- .name = "clcd",
- .modes = pmx_clcd_modes,
- .mode_count = ARRAY_SIZE(pmx_clcd_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_emi_modes[] = {
- {
- .ids = AUTO_EXP_MODE,
- .mask = PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK,
- },
-};
-
-struct pmx_dev spear320_pmx_emi = {
- .name = "emi",
- .modes = pmx_emi_modes,
- .mode_count = ARRAY_SIZE(pmx_emi_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_fsmc_modes[] = {
- {
- .ids = ALL_MODES,
- .mask = 0x0,
- },
-};
-
-struct pmx_dev spear320_pmx_fsmc = {
- .name = "fsmc",
- .modes = pmx_fsmc_modes,
- .mode_count = ARRAY_SIZE(pmx_fsmc_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_spp_modes[] = {
- {
- .ids = SMALL_PRINTERS_MODE,
- .mask = 0x0,
- },
-};
-
-struct pmx_dev spear320_pmx_spp = {
- .name = "spp",
- .modes = pmx_spp_modes,
- .mode_count = ARRAY_SIZE(pmx_spp_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_sdhci_modes[] = {
- {
- .ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE |
- SMALL_PRINTERS_MODE,
- .mask = PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK,
- },
-};
-
-struct pmx_dev spear320_pmx_sdhci = {
- .name = "sdhci",
- .modes = pmx_sdhci_modes,
- .mode_count = ARRAY_SIZE(pmx_sdhci_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_i2s_modes[] = {
- {
- .ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE,
- .mask = PMX_UART0_MODEM_MASK,
- },
-};
-
-struct pmx_dev spear320_pmx_i2s = {
- .name = "i2s",
- .modes = pmx_i2s_modes,
- .mode_count = ARRAY_SIZE(pmx_i2s_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_uart1_modes[] = {
- {
- .ids = ALL_MODES,
- .mask = PMX_GPIO_PIN0_MASK | PMX_GPIO_PIN1_MASK,
- },
-};
-
-struct pmx_dev spear320_pmx_uart1 = {
- .name = "uart1",
- .modes = pmx_uart1_modes,
- .mode_count = ARRAY_SIZE(pmx_uart1_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_uart1_modem_modes[] = {
- {
- .ids = AUTO_EXP_MODE,
- .mask = PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK |
- PMX_SSP_CS_MASK,
- }, {
- .ids = SMALL_PRINTERS_MODE,
- .mask = PMX_GPIO_PIN3_MASK | PMX_GPIO_PIN4_MASK |
- PMX_GPIO_PIN5_MASK | PMX_SSP_CS_MASK,
- },
-};
-
-struct pmx_dev spear320_pmx_uart1_modem = {
- .name = "uart1_modem",
- .modes = pmx_uart1_modem_modes,
- .mode_count = ARRAY_SIZE(pmx_uart1_modem_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_uart2_modes[] = {
- {
- .ids = ALL_MODES,
- .mask = PMX_FIRDA_MASK,
- },
-};
-
-struct pmx_dev spear320_pmx_uart2 = {
- .name = "uart2",
- .modes = pmx_uart2_modes,
- .mode_count = ARRAY_SIZE(pmx_uart2_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_touchscreen_modes[] = {
- {
- .ids = AUTO_NET_SMII_MODE,
- .mask = PMX_SSP_CS_MASK,
- },
-};
-
-struct pmx_dev spear320_pmx_touchscreen = {
- .name = "touchscreen",
- .modes = pmx_touchscreen_modes,
- .mode_count = ARRAY_SIZE(pmx_touchscreen_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_can_modes[] = {
- {
- .ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | AUTO_EXP_MODE,
- .mask = PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK |
- PMX_GPIO_PIN4_MASK | PMX_GPIO_PIN5_MASK,
- },
-};
-
-struct pmx_dev spear320_pmx_can = {
- .name = "can",
- .modes = pmx_can_modes,
- .mode_count = ARRAY_SIZE(pmx_can_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_sdhci_led_modes[] = {
- {
- .ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE,
- .mask = PMX_SSP_CS_MASK,
- },
-};
-
-struct pmx_dev spear320_pmx_sdhci_led = {
- .name = "sdhci_led",
- .modes = pmx_sdhci_led_modes,
- .mode_count = ARRAY_SIZE(pmx_sdhci_led_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_pwm0_modes[] = {
- {
- .ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE,
- .mask = PMX_UART0_MODEM_MASK,
- }, {
- .ids = AUTO_EXP_MODE | SMALL_PRINTERS_MODE,
- .mask = PMX_MII_MASK,
- },
-};
-
-struct pmx_dev spear320_pmx_pwm0 = {
- .name = "pwm0",
- .modes = pmx_pwm0_modes,
- .mode_count = ARRAY_SIZE(pmx_pwm0_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_pwm1_modes[] = {
- {
- .ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE,
- .mask = PMX_UART0_MODEM_MASK,
- }, {
- .ids = AUTO_EXP_MODE | SMALL_PRINTERS_MODE,
- .mask = PMX_MII_MASK,
- },
-};
-
-struct pmx_dev spear320_pmx_pwm1 = {
- .name = "pwm1",
- .modes = pmx_pwm1_modes,
- .mode_count = ARRAY_SIZE(pmx_pwm1_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_pwm2_modes[] = {
- {
- .ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE,
- .mask = PMX_SSP_CS_MASK,
- }, {
- .ids = AUTO_EXP_MODE | SMALL_PRINTERS_MODE,
- .mask = PMX_MII_MASK,
- },
-};
-
-struct pmx_dev spear320_pmx_pwm2 = {
- .name = "pwm2",
- .modes = pmx_pwm2_modes,
- .mode_count = ARRAY_SIZE(pmx_pwm2_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_pwm3_modes[] = {
- {
- .ids = AUTO_EXP_MODE | SMALL_PRINTERS_MODE | AUTO_NET_SMII_MODE,
- .mask = PMX_MII_MASK,
- },
-};
-
-struct pmx_dev spear320_pmx_pwm3 = {
- .name = "pwm3",
- .modes = pmx_pwm3_modes,
- .mode_count = ARRAY_SIZE(pmx_pwm3_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_ssp1_modes[] = {
- {
- .ids = SMALL_PRINTERS_MODE | AUTO_NET_SMII_MODE,
- .mask = PMX_MII_MASK,
- },
-};
-
-struct pmx_dev spear320_pmx_ssp1 = {
- .name = "ssp1",
- .modes = pmx_ssp1_modes,
- .mode_count = ARRAY_SIZE(pmx_ssp1_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_ssp2_modes[] = {
- {
- .ids = AUTO_NET_SMII_MODE,
- .mask = PMX_MII_MASK,
- },
-};
-
-struct pmx_dev spear320_pmx_ssp2 = {
- .name = "ssp2",
- .modes = pmx_ssp2_modes,
- .mode_count = ARRAY_SIZE(pmx_ssp2_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_mii1_modes[] = {
- {
- .ids = AUTO_NET_MII_MODE,
- .mask = 0x0,
- },
-};
-
-struct pmx_dev spear320_pmx_mii1 = {
- .name = "mii1",
- .modes = pmx_mii1_modes,
- .mode_count = ARRAY_SIZE(pmx_mii1_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_smii0_modes[] = {
- {
- .ids = AUTO_NET_SMII_MODE | AUTO_EXP_MODE | SMALL_PRINTERS_MODE,
- .mask = PMX_MII_MASK,
- },
-};
-
-struct pmx_dev spear320_pmx_smii0 = {
- .name = "smii0",
- .modes = pmx_smii0_modes,
- .mode_count = ARRAY_SIZE(pmx_smii0_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_smii1_modes[] = {
- {
- .ids = AUTO_NET_SMII_MODE | SMALL_PRINTERS_MODE,
- .mask = PMX_MII_MASK,
- },
-};
-
-struct pmx_dev spear320_pmx_smii1 = {
- .name = "smii1",
- .modes = pmx_smii1_modes,
- .mode_count = ARRAY_SIZE(pmx_smii1_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_i2c1_modes[] = {
- {
- .ids = AUTO_EXP_MODE,
- .mask = 0x0,
- },
-};
-
-struct pmx_dev spear320_pmx_i2c1 = {
- .name = "i2c1",
- .modes = pmx_i2c1_modes,
- .mode_count = ARRAY_SIZE(pmx_i2c1_modes),
- .enb_on_reset = 1,
-};
-
-/* pmx driver structure */
-static struct pmx_driver pmx_driver = {
- .mode_reg = {.offset = MODE_CONFIG_REG, .mask = 0x00000007},
- .mux_reg = {.offset = PAD_MUX_CONFIG_REG, .mask = 0x00007fff},
-};
+#include <mach/spear.h>
+
+#define SPEAR320_UART1_BASE UL(0xA3000000)
+#define SPEAR320_UART2_BASE UL(0xA4000000)
+#define SPEAR320_SSP0_BASE UL(0xA5000000)
+#define SPEAR320_SSP1_BASE UL(0xA6000000)
+#define SPEAR320_SOC_CONFIG_BASE UL(0xB3000000)
+
+/* Interrupt registers offsets and masks */
+#define SPEAR320_INT_STS_MASK_REG 0x04
+#define SPEAR320_INT_CLR_MASK_REG 0x04
+#define SPEAR320_INT_ENB_MASK_REG 0x08
+#define SPEAR320_GPIO_IRQ_MASK (1 << 0)
+#define SPEAR320_I2S_PLAY_IRQ_MASK (1 << 1)
+#define SPEAR320_I2S_REC_IRQ_MASK (1 << 2)
+#define SPEAR320_EMI_IRQ_MASK (1 << 7)
+#define SPEAR320_CLCD_IRQ_MASK (1 << 8)
+#define SPEAR320_SPP_IRQ_MASK (1 << 9)
+#define SPEAR320_SDHCI_IRQ_MASK (1 << 10)
+#define SPEAR320_CAN_U_IRQ_MASK (1 << 11)
+#define SPEAR320_CAN_L_IRQ_MASK (1 << 12)
+#define SPEAR320_UART1_IRQ_MASK (1 << 13)
+#define SPEAR320_UART2_IRQ_MASK (1 << 14)
+#define SPEAR320_SSP1_IRQ_MASK (1 << 15)
+#define SPEAR320_SSP2_IRQ_MASK (1 << 16)
+#define SPEAR320_SMII0_IRQ_MASK (1 << 17)
+#define SPEAR320_MII1_SMII1_IRQ_MASK (1 << 18)
+#define SPEAR320_WAKEUP_SMII0_IRQ_MASK (1 << 19)
+#define SPEAR320_WAKEUP_MII1_SMII1_IRQ_MASK (1 << 20)
+#define SPEAR320_I2C1_IRQ_MASK (1 << 21)
+
+#define SPEAR320_SHIRQ_RAS1_MASK 0x000380
+#define SPEAR320_SHIRQ_RAS3_MASK 0x000007
+#define SPEAR320_SHIRQ_INTRCOMM_RAS_MASK 0x3FF800
+
+/* SPEAr320 Virtual irq definitions */
+/* IRQs sharing IRQ_GEN_RAS_1 */
+#define SPEAR320_VIRQ_EMI (SPEAR3XX_VIRQ_START + 0)
+#define SPEAR320_VIRQ_CLCD (SPEAR3XX_VIRQ_START + 1)
+#define SPEAR320_VIRQ_SPP (SPEAR3XX_VIRQ_START + 2)
+
+/* IRQs sharing IRQ_GEN_RAS_2 */
+#define SPEAR320_IRQ_SDHCI SPEAR3XX_IRQ_GEN_RAS_2
+
+/* IRQs sharing IRQ_GEN_RAS_3 */
+#define SPEAR320_VIRQ_PLGPIO (SPEAR3XX_VIRQ_START + 3)
+#define SPEAR320_VIRQ_I2S_PLAY (SPEAR3XX_VIRQ_START + 4)
+#define SPEAR320_VIRQ_I2S_REC (SPEAR3XX_VIRQ_START + 5)
+
+/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */
+#define SPEAR320_VIRQ_CANU (SPEAR3XX_VIRQ_START + 6)
+#define SPEAR320_VIRQ_CANL (SPEAR3XX_VIRQ_START + 7)
+#define SPEAR320_VIRQ_UART1 (SPEAR3XX_VIRQ_START + 8)
+#define SPEAR320_VIRQ_UART2 (SPEAR3XX_VIRQ_START + 9)
+#define SPEAR320_VIRQ_SSP1 (SPEAR3XX_VIRQ_START + 10)
+#define SPEAR320_VIRQ_SSP2 (SPEAR3XX_VIRQ_START + 11)
+#define SPEAR320_VIRQ_SMII0 (SPEAR3XX_VIRQ_START + 12)
+#define SPEAR320_VIRQ_MII1_SMII1 (SPEAR3XX_VIRQ_START + 13)
+#define SPEAR320_VIRQ_WAKEUP_SMII0 (SPEAR3XX_VIRQ_START + 14)
+#define SPEAR320_VIRQ_WAKEUP_MII1_SMII1 (SPEAR3XX_VIRQ_START + 15)
+#define SPEAR320_VIRQ_I2C1 (SPEAR3XX_VIRQ_START + 16)
/* spear3xx shared irq */
static struct shirq_dev_config shirq_ras1_config[] = {
@@ -508,17 +207,250 @@ static struct spear_shirq shirq_intrcomm_ras = {
},
};
-/* Add spear320 specific devices here */
+/* DMAC platform data's slave info */
+struct pl08x_channel_data spear320_dma_info[] = {
+ {
+ .bus_id = "uart0_rx",
+ .min_signal = 2,
+ .max_signal = 2,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart0_tx",
+ .min_signal = 3,
+ .max_signal = 3,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ssp0_rx",
+ .min_signal = 8,
+ .max_signal = 8,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ssp0_tx",
+ .min_signal = 9,
+ .max_signal = 9,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "i2c0_rx",
+ .min_signal = 10,
+ .max_signal = 10,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "i2c0_tx",
+ .min_signal = 11,
+ .max_signal = 11,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "irda",
+ .min_signal = 12,
+ .max_signal = 12,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "adc",
+ .min_signal = 13,
+ .max_signal = 13,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "to_jpeg",
+ .min_signal = 14,
+ .max_signal = 14,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "from_jpeg",
+ .min_signal = 15,
+ .max_signal = 15,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ssp1_rx",
+ .min_signal = 0,
+ .max_signal = 0,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ssp1_tx",
+ .min_signal = 1,
+ .max_signal = 1,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ssp2_rx",
+ .min_signal = 2,
+ .max_signal = 2,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ssp2_tx",
+ .min_signal = 3,
+ .max_signal = 3,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "uart1_rx",
+ .min_signal = 4,
+ .max_signal = 4,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "uart1_tx",
+ .min_signal = 5,
+ .max_signal = 5,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "uart2_rx",
+ .min_signal = 6,
+ .max_signal = 6,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "uart2_tx",
+ .min_signal = 7,
+ .max_signal = 7,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "i2c1_rx",
+ .min_signal = 8,
+ .max_signal = 8,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "i2c1_tx",
+ .min_signal = 9,
+ .max_signal = 9,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "i2c2_rx",
+ .min_signal = 10,
+ .max_signal = 10,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "i2c2_tx",
+ .min_signal = 11,
+ .max_signal = 11,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "i2s_rx",
+ .min_signal = 12,
+ .max_signal = 12,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "i2s_tx",
+ .min_signal = 13,
+ .max_signal = 13,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "rs485_rx",
+ .min_signal = 14,
+ .max_signal = 14,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "rs485_tx",
+ .min_signal = 15,
+ .max_signal = 15,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ },
+};
+
+static struct pl022_ssp_controller spear320_ssp_data[] = {
+ {
+ .bus_id = 1,
+ .enable_dma = 1,
+ .dma_filter = pl08x_filter_id,
+ .dma_tx_param = "ssp1_tx",
+ .dma_rx_param = "ssp1_rx",
+ .num_chipselect = 2,
+ }, {
+ .bus_id = 2,
+ .enable_dma = 1,
+ .dma_filter = pl08x_filter_id,
+ .dma_tx_param = "ssp2_tx",
+ .dma_rx_param = "ssp2_rx",
+ .num_chipselect = 2,
+ }
+};
+
+static struct amba_pl011_data spear320_uart_data[] = {
+ {
+ .dma_filter = pl08x_filter_id,
+ .dma_tx_param = "uart1_tx",
+ .dma_rx_param = "uart1_rx",
+ }, {
+ .dma_filter = pl08x_filter_id,
+ .dma_tx_param = "uart2_tx",
+ .dma_rx_param = "uart2_rx",
+ },
+};
-/* spear320 routines */
-void __init spear320_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs,
- u8 pmx_dev_count)
+/* Add SPEAr310 auxdata to pass platform data */
+static struct of_dev_auxdata spear320_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("arm,pl022", SPEAR3XX_ICM1_SSP_BASE, NULL,
+ &pl022_plat_data),
+ OF_DEV_AUXDATA("arm,pl080", SPEAR3XX_ICM3_DMA_BASE, NULL,
+ &pl080_plat_data),
+ OF_DEV_AUXDATA("arm,pl022", SPEAR320_SSP0_BASE, NULL,
+ &spear320_ssp_data[0]),
+ OF_DEV_AUXDATA("arm,pl022", SPEAR320_SSP1_BASE, NULL,
+ &spear320_ssp_data[1]),
+ OF_DEV_AUXDATA("arm,pl011", SPEAR320_UART1_BASE, NULL,
+ &spear320_uart_data[0]),
+ OF_DEV_AUXDATA("arm,pl011", SPEAR320_UART2_BASE, NULL,
+ &spear320_uart_data[1]),
+ {}
+};
+
+static void __init spear320_dt_init(void)
{
void __iomem *base;
- int ret = 0;
+ int ret;
+
+ pl080_plat_data.slave_channels = spear320_dma_info;
+ pl080_plat_data.num_slave_channels = ARRAY_SIZE(spear320_dma_info);
- /* call spear3xx family common init function */
- spear3xx_init();
+ of_platform_populate(NULL, of_default_bus_match_table,
+ spear320_auxdata_lookup, NULL);
/* shared irq registration */
base = ioremap(SPEAR320_SOC_CONFIG_BASE, SZ_4K);
@@ -527,29 +459,40 @@ void __init spear320_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs,
shirq_ras1.regs.base = base;
ret = spear_shirq_register(&shirq_ras1);
if (ret)
- printk(KERN_ERR "Error registering Shared IRQ 1\n");
+ pr_err("Error registering Shared IRQ 1\n");
/* shirq 3 */
shirq_ras3.regs.base = base;
ret = spear_shirq_register(&shirq_ras3);
if (ret)
- printk(KERN_ERR "Error registering Shared IRQ 3\n");
+ pr_err("Error registering Shared IRQ 3\n");
/* shirq 4 */
shirq_intrcomm_ras.regs.base = base;
ret = spear_shirq_register(&shirq_intrcomm_ras);
if (ret)
- printk(KERN_ERR "Error registering Shared IRQ 4\n");
+ pr_err("Error registering Shared IRQ 4\n");
}
+}
- /* pmx initialization */
- pmx_driver.base = base;
- pmx_driver.mode = pmx_mode;
- pmx_driver.devs = pmx_devs;
- pmx_driver.devs_count = pmx_dev_count;
+static const char * const spear320_dt_board_compat[] = {
+ "st,spear320",
+ "st,spear320-evb",
+ NULL,
+};
- ret = pmx_register(&pmx_driver);
- if (ret)
- printk(KERN_ERR "padmux: registration failed. err no: %d\n",
- ret);
+static void __init spear320_map_io(void)
+{
+ spear3xx_map_io();
+ spear320_clk_init();
}
+
+DT_MACHINE_START(SPEAR320_DT, "ST SPEAr320 SoC with Flattened Device Tree")
+ .map_io = spear320_map_io,
+ .init_irq = spear3xx_dt_init_irq,
+ .handle_irq = vic_handle_irq,
+ .timer = &spear3xx_timer,
+ .init_machine = spear320_dt_init,
+ .restart = spear_restart,
+ .dt_compat = spear320_dt_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-spear3xx/spear320_evb.c b/arch/arm/mach-spear3xx/spear320_evb.c
deleted file mode 100644
index 105334ab7021..000000000000
--- a/arch/arm/mach-spear3xx/spear320_evb.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * arch/arm/mach-spear3xx/spear320_evb.c
- *
- * SPEAr320 evaluation board source file
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <asm/hardware/vic.h>
-#include <asm/mach/arch.h>
-#include <asm/mach-types.h>
-#include <mach/generic.h>
-#include <mach/hardware.h>
-
-/* padmux devices to enable */
-static struct pmx_dev *pmx_devs[] = {
- /* spear3xx specific devices */
- &spear3xx_pmx_i2c,
- &spear3xx_pmx_ssp,
- &spear3xx_pmx_mii,
- &spear3xx_pmx_uart0,
-
- /* spear320 specific devices */
- &spear320_pmx_fsmc,
- &spear320_pmx_sdhci,
- &spear320_pmx_i2s,
- &spear320_pmx_uart1,
- &spear320_pmx_uart2,
- &spear320_pmx_can,
- &spear320_pmx_pwm0,
- &spear320_pmx_pwm1,
- &spear320_pmx_pwm2,
- &spear320_pmx_mii1,
-};
-
-static struct amba_device *amba_devs[] __initdata = {
- /* spear3xx specific devices */
- &spear3xx_gpio_device,
- &spear3xx_uart_device,
-
- /* spear320 specific devices */
-};
-
-static struct platform_device *plat_devs[] __initdata = {
- /* spear3xx specific devices */
-
- /* spear320 specific devices */
-};
-
-static void __init spear320_evb_init(void)
-{
- unsigned int i;
-
- /* call spear320 machine init function */
- spear320_init(&spear320_auto_net_mii_mode, pmx_devs,
- ARRAY_SIZE(pmx_devs));
-
- /* Add Platform Devices */
- platform_add_devices(plat_devs, ARRAY_SIZE(plat_devs));
-
- /* Add Amba Devices */
- for (i = 0; i < ARRAY_SIZE(amba_devs); i++)
- amba_device_register(amba_devs[i], &iomem_resource);
-}
-
-MACHINE_START(SPEAR320, "ST-SPEAR320-EVB")
- .atag_offset = 0x100,
- .map_io = spear3xx_map_io,
- .init_irq = spear3xx_init_irq,
- .handle_irq = vic_handle_irq,
- .timer = &spear3xx_timer,
- .init_machine = spear320_evb_init,
- .restart = spear_restart,
-MACHINE_END
diff --git a/arch/arm/mach-spear3xx/spear3xx.c b/arch/arm/mach-spear3xx/spear3xx.c
index b1733c37f209..826ac20ef1e7 100644
--- a/arch/arm/mach-spear3xx/spear3xx.c
+++ b/arch/arm/mach-spear3xx/spear3xx.c
@@ -3,71 +3,78 @@
*
* SPEAr3XX machines common source file
*
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
+ * Copyright (C) 2009-2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
-#include <linux/types.h>
-#include <linux/amba/pl061.h>
-#include <linux/ptrace.h>
+#define pr_fmt(fmt) "SPEAr3xx: " fmt
+
+#include <linux/amba/pl022.h>
+#include <linux/amba/pl08x.h>
+#include <linux/of_irq.h>
#include <linux/io.h>
+#include <asm/hardware/pl080.h>
#include <asm/hardware/vic.h>
-#include <asm/irq.h>
-#include <asm/mach/arch.h>
+#include <plat/pl080.h>
#include <mach/generic.h>
-#include <mach/hardware.h>
-
-/* Add spear3xx machines common devices here */
-/* gpio device registration */
-static struct pl061_platform_data gpio_plat_data = {
- .gpio_base = 0,
- .irq_base = SPEAR3XX_GPIO_INT_BASE,
+#include <mach/spear.h>
+
+/* ssp device registration */
+struct pl022_ssp_controller pl022_plat_data = {
+ .bus_id = 0,
+ .enable_dma = 1,
+ .dma_filter = pl08x_filter_id,
+ .dma_tx_param = "ssp0_tx",
+ .dma_rx_param = "ssp0_rx",
+ /*
+ * This is number of spi devices that can be connected to spi. There are
+ * two type of chipselects on which slave devices can work. One is chip
+ * select provided by spi masters other is controlled through external
+ * gpio's. We can't use chipselect provided from spi master (because as
+ * soon as FIFO becomes empty, CS is disabled and transfer ends). So
+ * this number now depends on number of gpios available for spi. each
+ * slave on each master requires a separate gpio pin.
+ */
+ .num_chipselect = 2,
+};
+
+/* dmac device registration */
+struct pl08x_platform_data pl080_plat_data = {
+ .memcpy_channel = {
+ .bus_id = "memcpy",
+ .cctl = (PL080_BSIZE_16 << PL080_CONTROL_SB_SIZE_SHIFT | \
+ PL080_BSIZE_16 << PL080_CONTROL_DB_SIZE_SHIFT | \
+ PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT | \
+ PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT | \
+ PL080_CONTROL_PROT_BUFF | PL080_CONTROL_PROT_CACHE | \
+ PL080_CONTROL_PROT_SYS),
+ },
+ .lli_buses = PL08X_AHB1,
+ .mem_buses = PL08X_AHB1,
+ .get_signal = pl080_get_signal,
+ .put_signal = pl080_put_signal,
};
-AMBA_APB_DEVICE(spear3xx_gpio, "gpio", 0, SPEAR3XX_ICM3_GPIO_BASE,
- {SPEAR3XX_IRQ_BASIC_GPIO}, &gpio_plat_data);
-
-/* uart device registration */
-AMBA_APB_DEVICE(spear3xx_uart, "uart", 0, SPEAR3XX_ICM1_UART_BASE,
- {SPEAR3XX_IRQ_UART}, NULL);
-
-/* Do spear3xx familiy common initialization part here */
-void __init spear3xx_init(void)
-{
- /* nothing to do for now */
-}
-
-/* This will initialize vic */
-void __init spear3xx_init_irq(void)
-{
- vic_init((void __iomem *)VA_SPEAR3XX_ML1_VIC_BASE, 0, ~0, 0);
-}
-
-/* Following will create static virtual/physical mappings */
+/*
+ * Following will create 16MB static virtual/physical mappings
+ * PHYSICAL VIRTUAL
+ * 0xD0000000 0xFD000000
+ * 0xFC000000 0xFC000000
+ */
struct map_desc spear3xx_io_desc[] __initdata = {
{
- .virtual = VA_SPEAR3XX_ICM1_UART_BASE,
- .pfn = __phys_to_pfn(SPEAR3XX_ICM1_UART_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE
- }, {
- .virtual = VA_SPEAR3XX_ML1_VIC_BASE,
- .pfn = __phys_to_pfn(SPEAR3XX_ML1_VIC_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE
- }, {
- .virtual = VA_SPEAR3XX_ICM3_SYS_CTRL_BASE,
- .pfn = __phys_to_pfn(SPEAR3XX_ICM3_SYS_CTRL_BASE),
- .length = SZ_4K,
+ .virtual = VA_SPEAR3XX_ICM1_2_BASE,
+ .pfn = __phys_to_pfn(SPEAR3XX_ICM1_2_BASE),
+ .length = SZ_16M,
.type = MT_DEVICE
}, {
- .virtual = VA_SPEAR3XX_ICM3_MISC_REG_BASE,
- .pfn = __phys_to_pfn(SPEAR3XX_ICM3_MISC_REG_BASE),
- .length = SZ_4K,
+ .virtual = VA_SPEAR3XX_ICM3_SMI_CTRL_BASE,
+ .pfn = __phys_to_pfn(SPEAR3XX_ICM3_SMI_CTRL_BASE),
+ .length = SZ_16M,
.type = MT_DEVICE
},
};
@@ -76,436 +83,8 @@ struct map_desc spear3xx_io_desc[] __initdata = {
void __init spear3xx_map_io(void)
{
iotable_init(spear3xx_io_desc, ARRAY_SIZE(spear3xx_io_desc));
-
- /* This will initialize clock framework */
- spear3xx_clk_init();
}
-/* pad multiplexing support */
-/* devices */
-static struct pmx_dev_mode pmx_firda_modes[] = {
- {
- .ids = 0xffffffff,
- .mask = PMX_FIRDA_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_firda = {
- .name = "firda",
- .modes = pmx_firda_modes,
- .mode_count = ARRAY_SIZE(pmx_firda_modes),
- .enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_i2c_modes[] = {
- {
- .ids = 0xffffffff,
- .mask = PMX_I2C_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_i2c = {
- .name = "i2c",
- .modes = pmx_i2c_modes,
- .mode_count = ARRAY_SIZE(pmx_i2c_modes),
- .enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_ssp_cs_modes[] = {
- {
- .ids = 0xffffffff,
- .mask = PMX_SSP_CS_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_ssp_cs = {
- .name = "ssp_chip_selects",
- .modes = pmx_ssp_cs_modes,
- .mode_count = ARRAY_SIZE(pmx_ssp_cs_modes),
- .enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_ssp_modes[] = {
- {
- .ids = 0xffffffff,
- .mask = PMX_SSP_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_ssp = {
- .name = "ssp",
- .modes = pmx_ssp_modes,
- .mode_count = ARRAY_SIZE(pmx_ssp_modes),
- .enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_mii_modes[] = {
- {
- .ids = 0xffffffff,
- .mask = PMX_MII_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_mii = {
- .name = "mii",
- .modes = pmx_mii_modes,
- .mode_count = ARRAY_SIZE(pmx_mii_modes),
- .enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_gpio_pin0_modes[] = {
- {
- .ids = 0xffffffff,
- .mask = PMX_GPIO_PIN0_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_gpio_pin0 = {
- .name = "gpio_pin0",
- .modes = pmx_gpio_pin0_modes,
- .mode_count = ARRAY_SIZE(pmx_gpio_pin0_modes),
- .enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_gpio_pin1_modes[] = {
- {
- .ids = 0xffffffff,
- .mask = PMX_GPIO_PIN1_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_gpio_pin1 = {
- .name = "gpio_pin1",
- .modes = pmx_gpio_pin1_modes,
- .mode_count = ARRAY_SIZE(pmx_gpio_pin1_modes),
- .enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_gpio_pin2_modes[] = {
- {
- .ids = 0xffffffff,
- .mask = PMX_GPIO_PIN2_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_gpio_pin2 = {
- .name = "gpio_pin2",
- .modes = pmx_gpio_pin2_modes,
- .mode_count = ARRAY_SIZE(pmx_gpio_pin2_modes),
- .enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_gpio_pin3_modes[] = {
- {
- .ids = 0xffffffff,
- .mask = PMX_GPIO_PIN3_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_gpio_pin3 = {
- .name = "gpio_pin3",
- .modes = pmx_gpio_pin3_modes,
- .mode_count = ARRAY_SIZE(pmx_gpio_pin3_modes),
- .enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_gpio_pin4_modes[] = {
- {
- .ids = 0xffffffff,
- .mask = PMX_GPIO_PIN4_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_gpio_pin4 = {
- .name = "gpio_pin4",
- .modes = pmx_gpio_pin4_modes,
- .mode_count = ARRAY_SIZE(pmx_gpio_pin4_modes),
- .enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_gpio_pin5_modes[] = {
- {
- .ids = 0xffffffff,
- .mask = PMX_GPIO_PIN5_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_gpio_pin5 = {
- .name = "gpio_pin5",
- .modes = pmx_gpio_pin5_modes,
- .mode_count = ARRAY_SIZE(pmx_gpio_pin5_modes),
- .enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_uart0_modem_modes[] = {
- {
- .ids = 0xffffffff,
- .mask = PMX_UART0_MODEM_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_uart0_modem = {
- .name = "uart0_modem",
- .modes = pmx_uart0_modem_modes,
- .mode_count = ARRAY_SIZE(pmx_uart0_modem_modes),
- .enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_uart0_modes[] = {
- {
- .ids = 0xffffffff,
- .mask = PMX_UART0_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_uart0 = {
- .name = "uart0",
- .modes = pmx_uart0_modes,
- .mode_count = ARRAY_SIZE(pmx_uart0_modes),
- .enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_timer_3_4_modes[] = {
- {
- .ids = 0xffffffff,
- .mask = PMX_TIMER_3_4_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_timer_3_4 = {
- .name = "timer_3_4",
- .modes = pmx_timer_3_4_modes,
- .mode_count = ARRAY_SIZE(pmx_timer_3_4_modes),
- .enb_on_reset = 0,
-};
-
-static struct pmx_dev_mode pmx_timer_1_2_modes[] = {
- {
- .ids = 0xffffffff,
- .mask = PMX_TIMER_1_2_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_timer_1_2 = {
- .name = "timer_1_2",
- .modes = pmx_timer_1_2_modes,
- .mode_count = ARRAY_SIZE(pmx_timer_1_2_modes),
- .enb_on_reset = 0,
-};
-
-#if defined(CONFIG_MACH_SPEAR310) || defined(CONFIG_MACH_SPEAR320)
-/* plgpios devices */
-static struct pmx_dev_mode pmx_plgpio_0_1_modes[] = {
- {
- .ids = 0x00,
- .mask = PMX_FIRDA_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_0_1 = {
- .name = "plgpio 0 and 1",
- .modes = pmx_plgpio_0_1_modes,
- .mode_count = ARRAY_SIZE(pmx_plgpio_0_1_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_2_3_modes[] = {
- {
- .ids = 0x00,
- .mask = PMX_UART0_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_2_3 = {
- .name = "plgpio 2 and 3",
- .modes = pmx_plgpio_2_3_modes,
- .mode_count = ARRAY_SIZE(pmx_plgpio_2_3_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_4_5_modes[] = {
- {
- .ids = 0x00,
- .mask = PMX_I2C_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_4_5 = {
- .name = "plgpio 4 and 5",
- .modes = pmx_plgpio_4_5_modes,
- .mode_count = ARRAY_SIZE(pmx_plgpio_4_5_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_6_9_modes[] = {
- {
- .ids = 0x00,
- .mask = PMX_SSP_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_6_9 = {
- .name = "plgpio 6 to 9",
- .modes = pmx_plgpio_6_9_modes,
- .mode_count = ARRAY_SIZE(pmx_plgpio_6_9_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_10_27_modes[] = {
- {
- .ids = 0x00,
- .mask = PMX_MII_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_10_27 = {
- .name = "plgpio 10 to 27",
- .modes = pmx_plgpio_10_27_modes,
- .mode_count = ARRAY_SIZE(pmx_plgpio_10_27_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_28_modes[] = {
- {
- .ids = 0x00,
- .mask = PMX_GPIO_PIN0_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_28 = {
- .name = "plgpio 28",
- .modes = pmx_plgpio_28_modes,
- .mode_count = ARRAY_SIZE(pmx_plgpio_28_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_29_modes[] = {
- {
- .ids = 0x00,
- .mask = PMX_GPIO_PIN1_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_29 = {
- .name = "plgpio 29",
- .modes = pmx_plgpio_29_modes,
- .mode_count = ARRAY_SIZE(pmx_plgpio_29_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_30_modes[] = {
- {
- .ids = 0x00,
- .mask = PMX_GPIO_PIN2_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_30 = {
- .name = "plgpio 30",
- .modes = pmx_plgpio_30_modes,
- .mode_count = ARRAY_SIZE(pmx_plgpio_30_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_31_modes[] = {
- {
- .ids = 0x00,
- .mask = PMX_GPIO_PIN3_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_31 = {
- .name = "plgpio 31",
- .modes = pmx_plgpio_31_modes,
- .mode_count = ARRAY_SIZE(pmx_plgpio_31_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_32_modes[] = {
- {
- .ids = 0x00,
- .mask = PMX_GPIO_PIN4_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_32 = {
- .name = "plgpio 32",
- .modes = pmx_plgpio_32_modes,
- .mode_count = ARRAY_SIZE(pmx_plgpio_32_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_33_modes[] = {
- {
- .ids = 0x00,
- .mask = PMX_GPIO_PIN5_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_33 = {
- .name = "plgpio 33",
- .modes = pmx_plgpio_33_modes,
- .mode_count = ARRAY_SIZE(pmx_plgpio_33_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_34_36_modes[] = {
- {
- .ids = 0x00,
- .mask = PMX_SSP_CS_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_34_36 = {
- .name = "plgpio 34 to 36",
- .modes = pmx_plgpio_34_36_modes,
- .mode_count = ARRAY_SIZE(pmx_plgpio_34_36_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_37_42_modes[] = {
- {
- .ids = 0x00,
- .mask = PMX_UART0_MODEM_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_37_42 = {
- .name = "plgpio 37 to 42",
- .modes = pmx_plgpio_37_42_modes,
- .mode_count = ARRAY_SIZE(pmx_plgpio_37_42_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_43_44_47_48_modes[] = {
- {
- .ids = 0x00,
- .mask = PMX_TIMER_1_2_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_43_44_47_48 = {
- .name = "plgpio 43, 44, 47 and 48",
- .modes = pmx_plgpio_43_44_47_48_modes,
- .mode_count = ARRAY_SIZE(pmx_plgpio_43_44_47_48_modes),
- .enb_on_reset = 1,
-};
-
-static struct pmx_dev_mode pmx_plgpio_45_46_49_50_modes[] = {
- {
- .ids = 0x00,
- .mask = PMX_TIMER_3_4_MASK,
- },
-};
-
-struct pmx_dev spear3xx_pmx_plgpio_45_46_49_50 = {
- .name = "plgpio 45, 46, 49 and 50",
- .modes = pmx_plgpio_45_46_49_50_modes,
- .mode_count = ARRAY_SIZE(pmx_plgpio_45_46_49_50_modes),
- .enb_on_reset = 1,
-};
-#endif /* CONFIG_MACH_SPEAR310 || CONFIG_MACH_SPEAR320 */
-
static void __init spear3xx_timer_init(void)
{
char pclk_name[] = "pll3_48m_clk";
@@ -530,9 +109,19 @@ static void __init spear3xx_timer_init(void)
clk_put(gpt_clk);
clk_put(pclk);
- spear_setup_timer();
+ spear_setup_timer(SPEAR3XX_CPU_TMR_BASE, SPEAR3XX_IRQ_CPU_GPT1_1);
}
struct sys_timer spear3xx_timer = {
.init = spear3xx_timer_init,
};
+
+static const struct of_device_id vic_of_match[] __initconst = {
+ { .compatible = "arm,pl190-vic", .data = vic_of_init, },
+ { /* Sentinel */ }
+};
+
+void __init spear3xx_dt_init_irq(void)
+{
+ of_irq_init(vic_of_match);
+}
diff --git a/arch/arm/mach-spear6xx/Kconfig b/arch/arm/mach-spear6xx/Kconfig
index fbe298bd1d92..339f397dea70 100644
--- a/arch/arm/mach-spear6xx/Kconfig
+++ b/arch/arm/mach-spear6xx/Kconfig
@@ -2,21 +2,9 @@
# SPEAr6XX Machine configuration file
#
-if ARCH_SPEAR6XX
-
-menu "SPEAr6xx Implementations"
-config BOARD_SPEAR600_DT
- bool "SPEAr600 generic board configured via device-tree"
- select MACH_SPEAR600
+config MACH_SPEAR600
+ def_bool y
+ depends on ARCH_SPEAR6XX
select USE_OF
help
Supports ST SPEAr600 boards configured via the device-tree
-
-endmenu
-
-config MACH_SPEAR600
- bool "SPEAr600"
- help
- Supports ST SPEAr600 Machine
-
-endif #ARCH_SPEAR6XX
diff --git a/arch/arm/mach-spear6xx/Makefile.boot b/arch/arm/mach-spear6xx/Makefile.boot
index 4674a4c221db..af493da37ab6 100644
--- a/arch/arm/mach-spear6xx/Makefile.boot
+++ b/arch/arm/mach-spear6xx/Makefile.boot
@@ -1,3 +1,5 @@
zreladdr-y += 0x00008000
params_phys-y := 0x00000100
initrd_phys-y := 0x00800000
+
+dtb-$(CONFIG_BOARD_SPEAR600_DT) += spear600-evb.dtb
diff --git a/arch/arm/mach-spear6xx/clock.c b/arch/arm/mach-spear6xx/clock.c
index a86499a8a15f..bef77d43db87 100644
--- a/arch/arm/mach-spear6xx/clock.c
+++ b/arch/arm/mach-spear6xx/clock.c
@@ -16,6 +16,112 @@
#include <linux/kernel.h>
#include <plat/clock.h>
#include <mach/misc_regs.h>
+#include <mach/spear.h>
+
+#define PLL1_CTR (MISC_BASE + 0x008)
+#define PLL1_FRQ (MISC_BASE + 0x00C)
+#define PLL1_MOD (MISC_BASE + 0x010)
+#define PLL2_CTR (MISC_BASE + 0x014)
+/* PLL_CTR register masks */
+#define PLL_ENABLE 2
+#define PLL_MODE_SHIFT 4
+#define PLL_MODE_MASK 0x3
+#define PLL_MODE_NORMAL 0
+#define PLL_MODE_FRACTION 1
+#define PLL_MODE_DITH_DSB 2
+#define PLL_MODE_DITH_SSB 3
+
+#define PLL2_FRQ (MISC_BASE + 0x018)
+/* PLL FRQ register masks */
+#define PLL_DIV_N_SHIFT 0
+#define PLL_DIV_N_MASK 0xFF
+#define PLL_DIV_P_SHIFT 8
+#define PLL_DIV_P_MASK 0x7
+#define PLL_NORM_FDBK_M_SHIFT 24
+#define PLL_NORM_FDBK_M_MASK 0xFF
+#define PLL_DITH_FDBK_M_SHIFT 16
+#define PLL_DITH_FDBK_M_MASK 0xFFFF
+
+#define PLL2_MOD (MISC_BASE + 0x01C)
+#define PLL_CLK_CFG (MISC_BASE + 0x020)
+#define CORE_CLK_CFG (MISC_BASE + 0x024)
+/* CORE CLK CFG register masks */
+#define PLL_HCLK_RATIO_SHIFT 10
+#define PLL_HCLK_RATIO_MASK 0x3
+#define HCLK_PCLK_RATIO_SHIFT 8
+#define HCLK_PCLK_RATIO_MASK 0x3
+
+#define PERIP_CLK_CFG (MISC_BASE + 0x028)
+/* PERIP_CLK_CFG register masks */
+#define CLCD_CLK_SHIFT 2
+#define CLCD_CLK_MASK 0x3
+#define UART_CLK_SHIFT 4
+#define UART_CLK_MASK 0x1
+#define FIRDA_CLK_SHIFT 5
+#define FIRDA_CLK_MASK 0x3
+#define GPT0_CLK_SHIFT 8
+#define GPT1_CLK_SHIFT 10
+#define GPT2_CLK_SHIFT 11
+#define GPT3_CLK_SHIFT 12
+#define GPT_CLK_MASK 0x1
+#define AUX_CLK_PLL3_VAL 0
+#define AUX_CLK_PLL1_VAL 1
+
+#define PERIP1_CLK_ENB (MISC_BASE + 0x02C)
+/* PERIP1_CLK_ENB register masks */
+#define UART0_CLK_ENB 3
+#define UART1_CLK_ENB 4
+#define SSP0_CLK_ENB 5
+#define SSP1_CLK_ENB 6
+#define I2C_CLK_ENB 7
+#define JPEG_CLK_ENB 8
+#define FSMC_CLK_ENB 9
+#define FIRDA_CLK_ENB 10
+#define GPT2_CLK_ENB 11
+#define GPT3_CLK_ENB 12
+#define GPIO2_CLK_ENB 13
+#define SSP2_CLK_ENB 14
+#define ADC_CLK_ENB 15
+#define GPT1_CLK_ENB 11
+#define RTC_CLK_ENB 17
+#define GPIO1_CLK_ENB 18
+#define DMA_CLK_ENB 19
+#define SMI_CLK_ENB 21
+#define CLCD_CLK_ENB 22
+#define GMAC_CLK_ENB 23
+#define USBD_CLK_ENB 24
+#define USBH0_CLK_ENB 25
+#define USBH1_CLK_ENB 26
+
+#define PRSC1_CLK_CFG (MISC_BASE + 0x044)
+#define PRSC2_CLK_CFG (MISC_BASE + 0x048)
+#define PRSC3_CLK_CFG (MISC_BASE + 0x04C)
+/* gpt synthesizer register masks */
+#define GPT_MSCALE_SHIFT 0
+#define GPT_MSCALE_MASK 0xFFF
+#define GPT_NSCALE_SHIFT 12
+#define GPT_NSCALE_MASK 0xF
+
+#define AMEM_CLK_CFG (MISC_BASE + 0x050)
+#define EXPI_CLK_CFG (MISC_BASE + 0x054)
+#define CLCD_CLK_SYNT (MISC_BASE + 0x05C)
+#define FIRDA_CLK_SYNT (MISC_BASE + 0x060)
+#define UART_CLK_SYNT (MISC_BASE + 0x064)
+#define GMAC_CLK_SYNT (MISC_BASE + 0x068)
+#define RAS1_CLK_SYNT (MISC_BASE + 0x06C)
+#define RAS2_CLK_SYNT (MISC_BASE + 0x070)
+#define RAS3_CLK_SYNT (MISC_BASE + 0x074)
+#define RAS4_CLK_SYNT (MISC_BASE + 0x078)
+/* aux clk synthesiser register masks for irda to ras4 */
+#define AUX_SYNT_ENB 31
+#define AUX_EQ_SEL_SHIFT 30
+#define AUX_EQ_SEL_MASK 1
+#define AUX_EQ1_SEL 0
+#define AUX_EQ2_SEL 1
+#define AUX_XSCALE_SHIFT 16
+#define AUX_XSCALE_MASK 0xFFF
+#define AUX_YSCALE_SHIFT 0
+#define AUX_YSCALE_MASK 0xFFF
/* root clks */
/* 32 KHz oscillator clock */
@@ -623,53 +729,53 @@ static struct clk dummy_apb_pclk;
/* array of all spear 6xx clock lookups */
static struct clk_lookup spear_clk_lookups[] = {
- { .con_id = "apb_pclk", .clk = &dummy_apb_pclk},
+ CLKDEV_INIT(NULL, "apb_pclk", &dummy_apb_pclk),
/* root clks */
- { .con_id = "osc_32k_clk", .clk = &osc_32k_clk},
- { .con_id = "osc_30m_clk", .clk = &osc_30m_clk},
+ CLKDEV_INIT(NULL, "osc_32k_clk", &osc_32k_clk),
+ CLKDEV_INIT(NULL, "osc_30m_clk", &osc_30m_clk),
/* clock derived from 32 KHz os clk */
- { .dev_id = "rtc-spear", .clk = &rtc_clk},
+ CLKDEV_INIT("rtc-spear", NULL, &rtc_clk),
/* clock derived from 30 MHz os clk */
- { .con_id = "pll1_clk", .clk = &pll1_clk},
- { .con_id = "pll3_48m_clk", .clk = &pll3_48m_clk},
- { .dev_id = "wdt", .clk = &wdt_clk},
+ CLKDEV_INIT(NULL, "pll1_clk", &pll1_clk),
+ CLKDEV_INIT(NULL, "pll3_48m_clk", &pll3_48m_clk),
+ CLKDEV_INIT("wdt", NULL, &wdt_clk),
/* clock derived from pll1 clk */
- { .con_id = "cpu_clk", .clk = &cpu_clk},
- { .con_id = "ahb_clk", .clk = &ahb_clk},
- { .con_id = "uart_synth_clk", .clk = &uart_synth_clk},
- { .con_id = "firda_synth_clk", .clk = &firda_synth_clk},
- { .con_id = "clcd_synth_clk", .clk = &clcd_synth_clk},
- { .con_id = "gpt0_synth_clk", .clk = &gpt0_synth_clk},
- { .con_id = "gpt2_synth_clk", .clk = &gpt2_synth_clk},
- { .con_id = "gpt3_synth_clk", .clk = &gpt3_synth_clk},
- { .dev_id = "d0000000.serial", .clk = &uart0_clk},
- { .dev_id = "d0080000.serial", .clk = &uart1_clk},
- { .dev_id = "firda", .clk = &firda_clk},
- { .dev_id = "clcd", .clk = &clcd_clk},
- { .dev_id = "gpt0", .clk = &gpt0_clk},
- { .dev_id = "gpt1", .clk = &gpt1_clk},
- { .dev_id = "gpt2", .clk = &gpt2_clk},
- { .dev_id = "gpt3", .clk = &gpt3_clk},
+ CLKDEV_INIT(NULL, "cpu_clk", &cpu_clk),
+ CLKDEV_INIT(NULL, "ahb_clk", &ahb_clk),
+ CLKDEV_INIT(NULL, "uart_synth_clk", &uart_synth_clk),
+ CLKDEV_INIT(NULL, "firda_synth_clk", &firda_synth_clk),
+ CLKDEV_INIT(NULL, "clcd_synth_clk", &clcd_synth_clk),
+ CLKDEV_INIT(NULL, "gpt0_synth_clk", &gpt0_synth_clk),
+ CLKDEV_INIT(NULL, "gpt2_synth_clk", &gpt2_synth_clk),
+ CLKDEV_INIT(NULL, "gpt3_synth_clk", &gpt3_synth_clk),
+ CLKDEV_INIT("d0000000.serial", NULL, &uart0_clk),
+ CLKDEV_INIT("d0080000.serial", NULL, &uart1_clk),
+ CLKDEV_INIT("firda", NULL, &firda_clk),
+ CLKDEV_INIT("clcd", NULL, &clcd_clk),
+ CLKDEV_INIT("gpt0", NULL, &gpt0_clk),
+ CLKDEV_INIT("gpt1", NULL, &gpt1_clk),
+ CLKDEV_INIT("gpt2", NULL, &gpt2_clk),
+ CLKDEV_INIT("gpt3", NULL, &gpt3_clk),
/* clock derived from pll3 clk */
- { .dev_id = "designware_udc", .clk = &usbd_clk},
- { .con_id = "usbh.0_clk", .clk = &usbh0_clk},
- { .con_id = "usbh.1_clk", .clk = &usbh1_clk},
+ CLKDEV_INIT("designware_udc", NULL, &usbd_clk),
+ CLKDEV_INIT(NULL, "usbh.0_clk", &usbh0_clk),
+ CLKDEV_INIT(NULL, "usbh.1_clk", &usbh1_clk),
/* clock derived from ahb clk */
- { .con_id = "apb_clk", .clk = &apb_clk},
- { .dev_id = "d0200000.i2c", .clk = &i2c_clk},
- { .dev_id = "dma", .clk = &dma_clk},
- { .dev_id = "jpeg", .clk = &jpeg_clk},
- { .dev_id = "gmac", .clk = &gmac_clk},
- { .dev_id = "smi", .clk = &smi_clk},
- { .dev_id = "fsmc-nand", .clk = &fsmc_clk},
+ CLKDEV_INIT(NULL, "apb_clk", &apb_clk),
+ CLKDEV_INIT("d0200000.i2c", NULL, &i2c_clk),
+ CLKDEV_INIT("fc400000.dma", NULL, &dma_clk),
+ CLKDEV_INIT("jpeg", NULL, &jpeg_clk),
+ CLKDEV_INIT("gmac", NULL, &gmac_clk),
+ CLKDEV_INIT("fc000000.flash", NULL, &smi_clk),
+ CLKDEV_INIT("d1800000.flash", NULL, &fsmc_clk),
/* clock derived from apb clk */
- { .dev_id = "adc", .clk = &adc_clk},
- { .dev_id = "ssp-pl022.0", .clk = &ssp0_clk},
- { .dev_id = "ssp-pl022.1", .clk = &ssp1_clk},
- { .dev_id = "ssp-pl022.2", .clk = &ssp2_clk},
- { .dev_id = "f0100000.gpio", .clk = &gpio0_clk},
- { .dev_id = "fc980000.gpio", .clk = &gpio1_clk},
- { .dev_id = "d8100000.gpio", .clk = &gpio2_clk},
+ CLKDEV_INIT("adc", NULL, &adc_clk),
+ CLKDEV_INIT("ssp-pl022.0", NULL, &ssp0_clk),
+ CLKDEV_INIT("ssp-pl022.1", NULL, &ssp1_clk),
+ CLKDEV_INIT("ssp-pl022.2", NULL, &ssp2_clk),
+ CLKDEV_INIT("f0100000.gpio", NULL, &gpio0_clk),
+ CLKDEV_INIT("fc980000.gpio", NULL, &gpio1_clk),
+ CLKDEV_INIT("d8100000.gpio", NULL, &gpio2_clk),
};
void __init spear6xx_clk_init(void)
diff --git a/arch/arm/mach-spear6xx/include/mach/generic.h b/arch/arm/mach-spear6xx/include/mach/generic.h
index 116b99301cf5..7167fd331d86 100644
--- a/arch/arm/mach-spear6xx/include/mach/generic.h
+++ b/arch/arm/mach-spear6xx/include/mach/generic.h
@@ -15,34 +15,9 @@
#define __MACH_GENERIC_H
#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/amba/bus.h>
-#include <asm/mach/time.h>
-#include <asm/mach/map.h>
-
-/*
- * Each GPT has 2 timer channels
- * Following GPT channels will be used as clock source and clockevent
- */
-#define SPEAR_GPT0_BASE SPEAR6XX_CPU_TMR_BASE
-#define SPEAR_GPT0_CHAN0_IRQ IRQ_CPU_GPT1_1
-#define SPEAR_GPT0_CHAN1_IRQ IRQ_CPU_GPT1_2
-
-/* Add spear6xx family device structure declarations here */
-extern struct amba_device gpio_device[];
-extern struct amba_device uart_device[];
-extern struct sys_timer spear6xx_timer;
-
-/* Add spear6xx family function declarations here */
-void __init spear_setup_timer(void);
-void __init spear6xx_map_io(void);
-void __init spear6xx_init_irq(void);
-void __init spear6xx_init(void);
-void __init spear600_init(void);
-void __init spear6xx_clk_init(void);
+void __init spear_setup_timer(resource_size_t base, int irq);
void spear_restart(char, const char *);
-
-/* Add spear600 machine device structure declarations here */
+void __init spear6xx_clk_init(void);
#endif /* __MACH_GENERIC_H */
diff --git a/arch/arm/mach-spear6xx/include/mach/hardware.h b/arch/arm/mach-spear6xx/include/mach/hardware.h
index 0b3f96ae2848..40a8c178f10d 100644
--- a/arch/arm/mach-spear6xx/include/mach/hardware.h
+++ b/arch/arm/mach-spear6xx/include/mach/hardware.h
@@ -1,23 +1 @@
-/*
- * arch/arm/mach-spear6xx/include/mach/hardware.h
- *
- * Hardware definitions for SPEAr6xx machine family
- *
- * Copyright (C) 2009 ST Microelectronics
- * Rajeev Kumar<rajeev-dlh.kumar@st.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __MACH_HARDWARE_H
-#define __MACH_HARDWARE_H
-
-#include <plat/hardware.h>
-#include <mach/spear.h>
-
-/* Vitual to physical translation of statically mapped space */
-#define IO_ADDRESS(x) (x | 0xF0000000)
-
-#endif /* __MACH_HARDWARE_H */
+/* empty */
diff --git a/arch/arm/mach-spear6xx/include/mach/irqs.h b/arch/arm/mach-spear6xx/include/mach/irqs.h
index 8f214b03d75d..2b735389e74b 100644
--- a/arch/arm/mach-spear6xx/include/mach/irqs.h
+++ b/arch/arm/mach-spear6xx/include/mach/irqs.h
@@ -16,82 +16,13 @@
/* IRQ definitions */
/* VIC 1 */
-#define IRQ_INTRCOMM_SW_IRQ 0
-#define IRQ_INTRCOMM_CPU_1 1
-#define IRQ_INTRCOMM_CPU_2 2
-#define IRQ_INTRCOMM_RAS2A11_1 3
-#define IRQ_INTRCOMM_RAS2A11_2 4
-#define IRQ_INTRCOMM_RAS2A12_1 5
-#define IRQ_INTRCOMM_RAS2A12_2 6
-#define IRQ_GEN_RAS_0 7
-#define IRQ_GEN_RAS_1 8
-#define IRQ_GEN_RAS_2 9
-#define IRQ_GEN_RAS_3 10
-#define IRQ_GEN_RAS_4 11
-#define IRQ_GEN_RAS_5 12
-#define IRQ_GEN_RAS_6 13
-#define IRQ_GEN_RAS_7 14
-#define IRQ_GEN_RAS_8 15
+/* FIXME: probe this from DT */
#define IRQ_CPU_GPT1_1 16
-#define IRQ_CPU_GPT1_2 17
-#define IRQ_LOCAL_GPIO 18
-#define IRQ_PLL_UNLOCK 19
-#define IRQ_JPEG 20
-#define IRQ_FSMC 21
-#define IRQ_IRDA 22
-#define IRQ_RESERVED 23
-#define IRQ_UART_0 24
-#define IRQ_UART_1 25
-#define IRQ_SSP_1 26
-#define IRQ_SSP_2 27
-#define IRQ_I2C 28
-#define IRQ_GEN_RAS_9 29
-#define IRQ_GEN_RAS_10 30
-#define IRQ_GEN_RAS_11 31
-
-/* VIC 2 */
-#define IRQ_APPL_GPT1_1 32
-#define IRQ_APPL_GPT1_2 33
-#define IRQ_APPL_GPT2_1 34
-#define IRQ_APPL_GPT2_2 35
-#define IRQ_APPL_GPIO 36
-#define IRQ_APPL_SSP 37
-#define IRQ_APPL_ADC 38
-#define IRQ_APPL_RESERVED 39
-#define IRQ_AHB_EXP_MASTER 40
-#define IRQ_DDR_CONTROLLER 41
-#define IRQ_BASIC_DMA 42
-#define IRQ_BASIC_RESERVED1 43
-#define IRQ_BASIC_SMI 44
-#define IRQ_BASIC_CLCD 45
-#define IRQ_EXP_AHB_1 46
-#define IRQ_EXP_AHB_2 47
-#define IRQ_BASIC_GPT1_1 48
-#define IRQ_BASIC_GPT1_2 49
-#define IRQ_BASIC_RTC 50
-#define IRQ_BASIC_GPIO 51
-#define IRQ_BASIC_WDT 52
-#define IRQ_BASIC_RESERVED 53
-#define IRQ_AHB_EXP_SLAVE 54
-#define IRQ_GMAC_1 55
-#define IRQ_GMAC_2 56
-#define IRQ_USB_DEV 57
-#define IRQ_USB_H_OHCI_0 58
-#define IRQ_USB_H_EHCI_0 59
-#define IRQ_USB_H_OHCI_1 60
-#define IRQ_USB_H_EHCI_1 61
-#define IRQ_EXP_AHB_3 62
-#define IRQ_EXP_AHB_4 63
#define IRQ_VIC_END 64
/* GPIO pins virtual irqs */
-#define SPEAR_GPIO_INT_BASE IRQ_VIC_END
-#define SPEAR_GPIO0_INT_BASE SPEAR_GPIO_INT_BASE
-#define SPEAR_GPIO1_INT_BASE (SPEAR_GPIO0_INT_BASE + 8)
-#define SPEAR_GPIO2_INT_BASE (SPEAR_GPIO1_INT_BASE + 8)
-#define SPEAR_GPIO_INT_END (SPEAR_GPIO2_INT_BASE + 8)
-#define VIRTUAL_IRQS (SPEAR_GPIO_INT_END - IRQ_VIC_END)
-#define NR_IRQS (IRQ_VIC_END + VIRTUAL_IRQS)
+#define VIRTUAL_IRQS 24
+#define NR_IRQS (IRQ_VIC_END + VIRTUAL_IRQS)
#endif /* __MACH_IRQS_H */
diff --git a/arch/arm/mach-spear6xx/include/mach/misc_regs.h b/arch/arm/mach-spear6xx/include/mach/misc_regs.h
index 68c20a007b0d..2b9aaa6cdd11 100644
--- a/arch/arm/mach-spear6xx/include/mach/misc_regs.h
+++ b/arch/arm/mach-spear6xx/include/mach/misc_regs.h
@@ -14,161 +14,7 @@
#ifndef __MACH_MISC_REGS_H
#define __MACH_MISC_REGS_H
-#include <mach/hardware.h>
-
#define MISC_BASE IOMEM(VA_SPEAR6XX_ICM3_MISC_REG_BASE)
-
-#define SOC_CFG_CTR (MISC_BASE + 0x000)
-#define DIAG_CFG_CTR (MISC_BASE + 0x004)
-#define PLL1_CTR (MISC_BASE + 0x008)
-#define PLL1_FRQ (MISC_BASE + 0x00C)
-#define PLL1_MOD (MISC_BASE + 0x010)
-#define PLL2_CTR (MISC_BASE + 0x014)
-/* PLL_CTR register masks */
-#define PLL_ENABLE 2
-#define PLL_MODE_SHIFT 4
-#define PLL_MODE_MASK 0x3
-#define PLL_MODE_NORMAL 0
-#define PLL_MODE_FRACTION 1
-#define PLL_MODE_DITH_DSB 2
-#define PLL_MODE_DITH_SSB 3
-
-#define PLL2_FRQ (MISC_BASE + 0x018)
-/* PLL FRQ register masks */
-#define PLL_DIV_N_SHIFT 0
-#define PLL_DIV_N_MASK 0xFF
-#define PLL_DIV_P_SHIFT 8
-#define PLL_DIV_P_MASK 0x7
-#define PLL_NORM_FDBK_M_SHIFT 24
-#define PLL_NORM_FDBK_M_MASK 0xFF
-#define PLL_DITH_FDBK_M_SHIFT 16
-#define PLL_DITH_FDBK_M_MASK 0xFFFF
-
-#define PLL2_MOD (MISC_BASE + 0x01C)
-#define PLL_CLK_CFG (MISC_BASE + 0x020)
-#define CORE_CLK_CFG (MISC_BASE + 0x024)
-/* CORE CLK CFG register masks */
-#define PLL_HCLK_RATIO_SHIFT 10
-#define PLL_HCLK_RATIO_MASK 0x3
-#define HCLK_PCLK_RATIO_SHIFT 8
-#define HCLK_PCLK_RATIO_MASK 0x3
-
-#define PERIP_CLK_CFG (MISC_BASE + 0x028)
-/* PERIP_CLK_CFG register masks */
-#define CLCD_CLK_SHIFT 2
-#define CLCD_CLK_MASK 0x3
-#define UART_CLK_SHIFT 4
-#define UART_CLK_MASK 0x1
-#define FIRDA_CLK_SHIFT 5
-#define FIRDA_CLK_MASK 0x3
-#define GPT0_CLK_SHIFT 8
-#define GPT1_CLK_SHIFT 10
-#define GPT2_CLK_SHIFT 11
-#define GPT3_CLK_SHIFT 12
-#define GPT_CLK_MASK 0x1
-#define AUX_CLK_PLL3_VAL 0
-#define AUX_CLK_PLL1_VAL 1
-
-#define PERIP1_CLK_ENB (MISC_BASE + 0x02C)
-/* PERIP1_CLK_ENB register masks */
-#define UART0_CLK_ENB 3
-#define UART1_CLK_ENB 4
-#define SSP0_CLK_ENB 5
-#define SSP1_CLK_ENB 6
-#define I2C_CLK_ENB 7
-#define JPEG_CLK_ENB 8
-#define FSMC_CLK_ENB 9
-#define FIRDA_CLK_ENB 10
-#define GPT2_CLK_ENB 11
-#define GPT3_CLK_ENB 12
-#define GPIO2_CLK_ENB 13
-#define SSP2_CLK_ENB 14
-#define ADC_CLK_ENB 15
-#define GPT1_CLK_ENB 11
-#define RTC_CLK_ENB 17
-#define GPIO1_CLK_ENB 18
-#define DMA_CLK_ENB 19
-#define SMI_CLK_ENB 21
-#define CLCD_CLK_ENB 22
-#define GMAC_CLK_ENB 23
-#define USBD_CLK_ENB 24
-#define USBH0_CLK_ENB 25
-#define USBH1_CLK_ENB 26
-
-#define SOC_CORE_ID (MISC_BASE + 0x030)
-#define RAS_CLK_ENB (MISC_BASE + 0x034)
-#define PERIP1_SOF_RST (MISC_BASE + 0x038)
-/* PERIP1_SOF_RST register masks */
-#define JPEG_SOF_RST 8
-
-#define SOC_USER_ID (MISC_BASE + 0x03C)
-#define RAS_SOF_RST (MISC_BASE + 0x040)
-#define PRSC1_CLK_CFG (MISC_BASE + 0x044)
-#define PRSC2_CLK_CFG (MISC_BASE + 0x048)
-#define PRSC3_CLK_CFG (MISC_BASE + 0x04C)
-/* gpt synthesizer register masks */
-#define GPT_MSCALE_SHIFT 0
-#define GPT_MSCALE_MASK 0xFFF
-#define GPT_NSCALE_SHIFT 12
-#define GPT_NSCALE_MASK 0xF
-
-#define AMEM_CLK_CFG (MISC_BASE + 0x050)
-#define EXPI_CLK_CFG (MISC_BASE + 0x054)
-#define CLCD_CLK_SYNT (MISC_BASE + 0x05C)
-#define FIRDA_CLK_SYNT (MISC_BASE + 0x060)
-#define UART_CLK_SYNT (MISC_BASE + 0x064)
-#define GMAC_CLK_SYNT (MISC_BASE + 0x068)
-#define RAS1_CLK_SYNT (MISC_BASE + 0x06C)
-#define RAS2_CLK_SYNT (MISC_BASE + 0x070)
-#define RAS3_CLK_SYNT (MISC_BASE + 0x074)
-#define RAS4_CLK_SYNT (MISC_BASE + 0x078)
-/* aux clk synthesiser register masks for irda to ras4 */
-#define AUX_SYNT_ENB 31
-#define AUX_EQ_SEL_SHIFT 30
-#define AUX_EQ_SEL_MASK 1
-#define AUX_EQ1_SEL 0
-#define AUX_EQ2_SEL 1
-#define AUX_XSCALE_SHIFT 16
-#define AUX_XSCALE_MASK 0xFFF
-#define AUX_YSCALE_SHIFT 0
-#define AUX_YSCALE_MASK 0xFFF
-
-#define ICM1_ARB_CFG (MISC_BASE + 0x07C)
-#define ICM2_ARB_CFG (MISC_BASE + 0x080)
-#define ICM3_ARB_CFG (MISC_BASE + 0x084)
-#define ICM4_ARB_CFG (MISC_BASE + 0x088)
-#define ICM5_ARB_CFG (MISC_BASE + 0x08C)
-#define ICM6_ARB_CFG (MISC_BASE + 0x090)
-#define ICM7_ARB_CFG (MISC_BASE + 0x094)
-#define ICM8_ARB_CFG (MISC_BASE + 0x098)
-#define ICM9_ARB_CFG (MISC_BASE + 0x09C)
#define DMA_CHN_CFG (MISC_BASE + 0x0A0)
-#define USB2_PHY_CFG (MISC_BASE + 0x0A4)
-#define GMAC_CFG_CTR (MISC_BASE + 0x0A8)
-#define EXPI_CFG_CTR (MISC_BASE + 0x0AC)
-#define PRC1_LOCK_CTR (MISC_BASE + 0x0C0)
-#define PRC2_LOCK_CTR (MISC_BASE + 0x0C4)
-#define PRC3_LOCK_CTR (MISC_BASE + 0x0C8)
-#define PRC4_LOCK_CTR (MISC_BASE + 0x0CC)
-#define PRC1_IRQ_CTR (MISC_BASE + 0x0D0)
-#define PRC2_IRQ_CTR (MISC_BASE + 0x0D4)
-#define PRC3_IRQ_CTR (MISC_BASE + 0x0D8)
-#define PRC4_IRQ_CTR (MISC_BASE + 0x0DC)
-#define PWRDOWN_CFG_CTR (MISC_BASE + 0x0E0)
-#define COMPSSTL_1V8_CFG (MISC_BASE + 0x0E4)
-#define COMPSSTL_2V5_CFG (MISC_BASE + 0x0E8)
-#define COMPCOR_3V3_CFG (MISC_BASE + 0x0EC)
-#define SSTLPAD_CFG_CTR (MISC_BASE + 0x0F0)
-#define BIST1_CFG_CTR (MISC_BASE + 0x0F4)
-#define BIST2_CFG_CTR (MISC_BASE + 0x0F8)
-#define BIST3_CFG_CTR (MISC_BASE + 0x0FC)
-#define BIST4_CFG_CTR (MISC_BASE + 0x100)
-#define BIST5_CFG_CTR (MISC_BASE + 0x104)
-#define BIST1_STS_RES (MISC_BASE + 0x108)
-#define BIST2_STS_RES (MISC_BASE + 0x10C)
-#define BIST3_STS_RES (MISC_BASE + 0x110)
-#define BIST4_STS_RES (MISC_BASE + 0x114)
-#define BIST5_STS_RES (MISC_BASE + 0x118)
-#define SYSERR_CFG_CTR (MISC_BASE + 0x11C)
#endif /* __MACH_MISC_REGS_H */
diff --git a/arch/arm/mach-spear6xx/include/mach/spear.h b/arch/arm/mach-spear6xx/include/mach/spear.h
index 7fd621532def..d278ed047a53 100644
--- a/arch/arm/mach-spear6xx/include/mach/spear.h
+++ b/arch/arm/mach-spear6xx/include/mach/spear.h
@@ -15,69 +15,26 @@
#define __MACH_SPEAR6XX_H
#include <asm/memory.h>
-#include <mach/spear600.h>
-#define SPEAR6XX_ML_SDRAM_BASE UL(0x00000000)
/* ICM1 - Low speed connection */
#define SPEAR6XX_ICM1_BASE UL(0xD0000000)
-
+#define VA_SPEAR6XX_ICM1_BASE UL(0xFD000000)
#define SPEAR6XX_ICM1_UART0_BASE UL(0xD0000000)
-#define VA_SPEAR6XX_ICM1_UART0_BASE IO_ADDRESS(SPEAR6XX_ICM1_UART0_BASE)
-
-#define SPEAR6XX_ICM1_UART1_BASE UL(0xD0080000)
-#define SPEAR6XX_ICM1_SSP0_BASE UL(0xD0100000)
-#define SPEAR6XX_ICM1_SSP1_BASE UL(0xD0180000)
-#define SPEAR6XX_ICM1_I2C_BASE UL(0xD0200000)
-#define SPEAR6XX_ICM1_JPEG_BASE UL(0xD0800000)
-#define SPEAR6XX_ICM1_IRDA_BASE UL(0xD1000000)
-#define SPEAR6XX_ICM1_FSMC_BASE UL(0xD1800000)
-#define SPEAR6XX_ICM1_NAND_BASE UL(0xD2000000)
-#define SPEAR6XX_ICM1_SRAM_BASE UL(0xD2800000)
-
-/* ICM2 - Application Subsystem */
-#define SPEAR6XX_ICM2_BASE UL(0xD8000000)
-#define SPEAR6XX_ICM2_TMR0_BASE UL(0xD8000000)
-#define SPEAR6XX_ICM2_TMR1_BASE UL(0xD8080000)
-#define SPEAR6XX_ICM2_GPIO_BASE UL(0xD8100000)
-#define SPEAR6XX_ICM2_SSP2_BASE UL(0xD8180000)
-#define SPEAR6XX_ICM2_ADC_BASE UL(0xD8200000)
+#define VA_SPEAR6XX_ICM1_UART0_BASE (VA_SPEAR6XX_ICM1_2_BASE | SPEAR6XX_ICM1_UART0_BASE)
/* ML-1, 2 - Multi Layer CPU Subsystem */
#define SPEAR6XX_ML_CPU_BASE UL(0xF0000000)
+#define VA_SPEAR6XX_ML_CPU_BASE UL(0xF0000000)
#define SPEAR6XX_CPU_TMR_BASE UL(0xF0000000)
-#define SPEAR6XX_CPU_GPIO_BASE UL(0xF0100000)
-#define SPEAR6XX_CPU_VIC_SEC_BASE UL(0xF1000000)
-#define VA_SPEAR6XX_CPU_VIC_SEC_BASE IO_ADDRESS(SPEAR6XX_CPU_VIC_SEC_BASE)
-#define SPEAR6XX_CPU_VIC_PRI_BASE UL(0xF1100000)
-#define VA_SPEAR6XX_CPU_VIC_PRI_BASE IO_ADDRESS(SPEAR6XX_CPU_VIC_PRI_BASE)
/* ICM3 - Basic Subsystem */
-#define SPEAR6XX_ICM3_BASE UL(0xF8000000)
-#define SPEAR6XX_ICM3_SMEM_BASE UL(0xF8000000)
#define SPEAR6XX_ICM3_SMI_CTRL_BASE UL(0xFC000000)
-#define SPEAR6XX_ICM3_CLCD_BASE UL(0xFC200000)
+#define VA_SPEAR6XX_ICM3_SMI_CTRL_BASE UL(0xFC000000)
#define SPEAR6XX_ICM3_DMA_BASE UL(0xFC400000)
-#define SPEAR6XX_ICM3_SDRAM_CTRL_BASE UL(0xFC600000)
-#define SPEAR6XX_ICM3_TMR_BASE UL(0xFC800000)
-#define SPEAR6XX_ICM3_WDT_BASE UL(0xFC880000)
-#define SPEAR6XX_ICM3_RTC_BASE UL(0xFC900000)
-#define SPEAR6XX_ICM3_GPIO_BASE UL(0xFC980000)
#define SPEAR6XX_ICM3_SYS_CTRL_BASE UL(0xFCA00000)
-#define VA_SPEAR6XX_ICM3_SYS_CTRL_BASE IO_ADDRESS(SPEAR6XX_ICM3_SYS_CTRL_BASE)
+#define VA_SPEAR6XX_ICM3_SYS_CTRL_BASE (VA_SPEAR6XX_ICM3_SMI_CTRL_BASE | SPEAR6XX_ICM3_SYS_CTRL_BASE)
#define SPEAR6XX_ICM3_MISC_REG_BASE UL(0xFCA80000)
-#define VA_SPEAR6XX_ICM3_MISC_REG_BASE IO_ADDRESS(SPEAR6XX_ICM3_MISC_REG_BASE)
-
-/* ICM4 - High Speed Connection */
-#define SPEAR6XX_ICM4_BASE UL(0xE0000000)
-#define SPEAR6XX_ICM4_GMAC_BASE UL(0xE0800000)
-#define SPEAR6XX_ICM4_USBD_FIFO_BASE UL(0xE1000000)
-#define SPEAR6XX_ICM4_USBD_CSR_BASE UL(0xE1100000)
-#define SPEAR6XX_ICM4_USBD_PLDT_BASE UL(0xE1200000)
-#define SPEAR6XX_ICM4_USB_EHCI0_BASE UL(0xE1800000)
-#define SPEAR6XX_ICM4_USB_OHCI0_BASE UL(0xE1900000)
-#define SPEAR6XX_ICM4_USB_EHCI1_BASE UL(0xE2000000)
-#define SPEAR6XX_ICM4_USB_OHCI1_BASE UL(0xE2100000)
-#define SPEAR6XX_ICM4_USB_ARB_BASE UL(0xE2800000)
+#define VA_SPEAR6XX_ICM3_MISC_REG_BASE (VA_SPEAR6XX_ICM3_SMI_CTRL_BASE | SPEAR6XX_ICM3_MISC_REG_BASE)
/* Debug uart for linux, will be used for debug and uncompress messages */
#define SPEAR_DBG_UART_BASE SPEAR6XX_ICM1_UART0_BASE
diff --git a/arch/arm/mach-spear6xx/include/mach/spear600.h b/arch/arm/mach-spear6xx/include/mach/spear600.h
deleted file mode 100644
index c068cc50b0fb..000000000000
--- a/arch/arm/mach-spear6xx/include/mach/spear600.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * arch/arm/mach-spear66xx/include/mach/spear600.h
- *
- * SPEAr600 Machine specific definition
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifdef CONFIG_MACH_SPEAR600
-
-#ifndef __MACH_SPEAR600_H
-#define __MACH_SPEAR600_H
-
-#endif /* __MACH_SPEAR600_H */
-
-#endif /* CONFIG_MACH_SPEAR600 */
diff --git a/arch/arm/mach-spear6xx/spear6xx.c b/arch/arm/mach-spear6xx/spear6xx.c
index 2ed8b14c82c8..de194dbb8371 100644
--- a/arch/arm/mach-spear6xx/spear6xx.c
+++ b/arch/arm/mach-spear6xx/spear6xx.c
@@ -13,41 +13,404 @@
* warranty of any kind, whether express or implied.
*/
+#include <linux/amba/pl08x.h>
+#include <linux/clk.h>
+#include <linux/err.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include <asm/hardware/pl080.h>
#include <asm/hardware/vic.h>
#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/mach/map.h>
+#include <plat/pl080.h>
#include <mach/generic.h>
-#include <mach/hardware.h>
+#include <mach/spear.h>
-/* Following will create static virtual/physical mappings */
-static struct map_desc spear6xx_io_desc[] __initdata = {
+/* dmac device registration */
+static struct pl08x_channel_data spear600_dma_info[] = {
{
- .virtual = VA_SPEAR6XX_ICM1_UART0_BASE,
- .pfn = __phys_to_pfn(SPEAR6XX_ICM1_UART0_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE
+ .bus_id = "ssp1_rx",
+ .min_signal = 0,
+ .max_signal = 0,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
}, {
- .virtual = VA_SPEAR6XX_CPU_VIC_PRI_BASE,
- .pfn = __phys_to_pfn(SPEAR6XX_CPU_VIC_PRI_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE
+ .bus_id = "ssp1_tx",
+ .min_signal = 1,
+ .max_signal = 1,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
}, {
- .virtual = VA_SPEAR6XX_CPU_VIC_SEC_BASE,
- .pfn = __phys_to_pfn(SPEAR6XX_CPU_VIC_SEC_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE
+ .bus_id = "uart0_rx",
+ .min_signal = 2,
+ .max_signal = 2,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart0_tx",
+ .min_signal = 3,
+ .max_signal = 3,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart1_rx",
+ .min_signal = 4,
+ .max_signal = 4,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "uart1_tx",
+ .min_signal = 5,
+ .max_signal = 5,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ssp2_rx",
+ .min_signal = 6,
+ .max_signal = 6,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ssp2_tx",
+ .min_signal = 7,
+ .max_signal = 7,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ssp0_rx",
+ .min_signal = 8,
+ .max_signal = 8,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ssp0_tx",
+ .min_signal = 9,
+ .max_signal = 9,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "i2c_rx",
+ .min_signal = 10,
+ .max_signal = 10,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "i2c_tx",
+ .min_signal = 11,
+ .max_signal = 11,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "irda",
+ .min_signal = 12,
+ .max_signal = 12,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "adc",
+ .min_signal = 13,
+ .max_signal = 13,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "to_jpeg",
+ .min_signal = 14,
+ .max_signal = 14,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "from_jpeg",
+ .min_signal = 15,
+ .max_signal = 15,
+ .muxval = 0,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras0_rx",
+ .min_signal = 0,
+ .max_signal = 0,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras0_tx",
+ .min_signal = 1,
+ .max_signal = 1,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras1_rx",
+ .min_signal = 2,
+ .max_signal = 2,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras1_tx",
+ .min_signal = 3,
+ .max_signal = 3,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras2_rx",
+ .min_signal = 4,
+ .max_signal = 4,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras2_tx",
+ .min_signal = 5,
+ .max_signal = 5,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras3_rx",
+ .min_signal = 6,
+ .max_signal = 6,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras3_tx",
+ .min_signal = 7,
+ .max_signal = 7,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras4_rx",
+ .min_signal = 8,
+ .max_signal = 8,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras4_tx",
+ .min_signal = 9,
+ .max_signal = 9,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras5_rx",
+ .min_signal = 10,
+ .max_signal = 10,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras5_tx",
+ .min_signal = 11,
+ .max_signal = 11,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras6_rx",
+ .min_signal = 12,
+ .max_signal = 12,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras6_tx",
+ .min_signal = 13,
+ .max_signal = 13,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
}, {
- .virtual = VA_SPEAR6XX_ICM3_SYS_CTRL_BASE,
- .pfn = __phys_to_pfn(SPEAR6XX_ICM3_SYS_CTRL_BASE),
- .length = SZ_4K,
+ .bus_id = "ras7_rx",
+ .min_signal = 14,
+ .max_signal = 14,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ras7_tx",
+ .min_signal = 15,
+ .max_signal = 15,
+ .muxval = 1,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB1,
+ }, {
+ .bus_id = "ext0_rx",
+ .min_signal = 0,
+ .max_signal = 0,
+ .muxval = 2,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext0_tx",
+ .min_signal = 1,
+ .max_signal = 1,
+ .muxval = 2,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext1_rx",
+ .min_signal = 2,
+ .max_signal = 2,
+ .muxval = 2,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext1_tx",
+ .min_signal = 3,
+ .max_signal = 3,
+ .muxval = 2,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext2_rx",
+ .min_signal = 4,
+ .max_signal = 4,
+ .muxval = 2,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext2_tx",
+ .min_signal = 5,
+ .max_signal = 5,
+ .muxval = 2,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext3_rx",
+ .min_signal = 6,
+ .max_signal = 6,
+ .muxval = 2,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext3_tx",
+ .min_signal = 7,
+ .max_signal = 7,
+ .muxval = 2,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext4_rx",
+ .min_signal = 8,
+ .max_signal = 8,
+ .muxval = 2,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext4_tx",
+ .min_signal = 9,
+ .max_signal = 9,
+ .muxval = 2,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext5_rx",
+ .min_signal = 10,
+ .max_signal = 10,
+ .muxval = 2,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext5_tx",
+ .min_signal = 11,
+ .max_signal = 11,
+ .muxval = 2,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext6_rx",
+ .min_signal = 12,
+ .max_signal = 12,
+ .muxval = 2,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext6_tx",
+ .min_signal = 13,
+ .max_signal = 13,
+ .muxval = 2,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext7_rx",
+ .min_signal = 14,
+ .max_signal = 14,
+ .muxval = 2,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ }, {
+ .bus_id = "ext7_tx",
+ .min_signal = 15,
+ .max_signal = 15,
+ .muxval = 2,
+ .cctl = 0,
+ .periph_buses = PL08X_AHB2,
+ },
+};
+
+struct pl08x_platform_data pl080_plat_data = {
+ .memcpy_channel = {
+ .bus_id = "memcpy",
+ .cctl = (PL080_BSIZE_16 << PL080_CONTROL_SB_SIZE_SHIFT | \
+ PL080_BSIZE_16 << PL080_CONTROL_DB_SIZE_SHIFT | \
+ PL080_WIDTH_32BIT << PL080_CONTROL_SWIDTH_SHIFT | \
+ PL080_WIDTH_32BIT << PL080_CONTROL_DWIDTH_SHIFT | \
+ PL080_CONTROL_PROT_BUFF | PL080_CONTROL_PROT_CACHE | \
+ PL080_CONTROL_PROT_SYS),
+ },
+ .lli_buses = PL08X_AHB1,
+ .mem_buses = PL08X_AHB1,
+ .get_signal = pl080_get_signal,
+ .put_signal = pl080_put_signal,
+ .slave_channels = spear600_dma_info,
+ .num_slave_channels = ARRAY_SIZE(spear600_dma_info),
+};
+
+/*
+ * Following will create 16MB static virtual/physical mappings
+ * PHYSICAL VIRTUAL
+ * 0xF0000000 0xF0000000
+ * 0xF1000000 0xF1000000
+ * 0xD0000000 0xFD000000
+ * 0xFC000000 0xFC000000
+ */
+struct map_desc spear6xx_io_desc[] __initdata = {
+ {
+ .virtual = VA_SPEAR6XX_ML_CPU_BASE,
+ .pfn = __phys_to_pfn(SPEAR6XX_ML_CPU_BASE),
+ .length = 2 * SZ_16M,
+ .type = MT_DEVICE
+ }, {
+ .virtual = VA_SPEAR6XX_ICM1_BASE,
+ .pfn = __phys_to_pfn(SPEAR6XX_ICM1_BASE),
+ .length = SZ_16M,
.type = MT_DEVICE
}, {
- .virtual = VA_SPEAR6XX_ICM3_MISC_REG_BASE,
- .pfn = __phys_to_pfn(SPEAR6XX_ICM3_MISC_REG_BASE),
- .length = SZ_4K,
+ .virtual = VA_SPEAR6XX_ICM3_SMI_CTRL_BASE,
+ .pfn = __phys_to_pfn(SPEAR6XX_ICM3_SMI_CTRL_BASE),
+ .length = SZ_16M,
.type = MT_DEVICE
},
};
@@ -85,16 +448,24 @@ static void __init spear6xx_timer_init(void)
clk_put(gpt_clk);
clk_put(pclk);
- spear_setup_timer();
+ spear_setup_timer(SPEAR6XX_CPU_TMR_BASE, IRQ_CPU_GPT1_1);
}
struct sys_timer spear6xx_timer = {
.init = spear6xx_timer_init,
};
+/* Add auxdata to pass platform data */
+struct of_dev_auxdata spear6xx_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("arm,pl080", SPEAR6XX_ICM3_DMA_BASE, NULL,
+ &pl080_plat_data),
+ {}
+};
+
static void __init spear600_dt_init(void)
{
- of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+ of_platform_populate(NULL, of_default_bus_match_table,
+ spear6xx_auxdata_lookup, NULL);
}
static const char *spear600_dt_board_compat[] = {
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index d87d968115ec..2eb4445ddb14 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -5,7 +5,6 @@ obj-y += io.o
obj-y += irq.o
obj-y += clock.o
obj-y += timer.o
-obj-y += pinmux.o
obj-y += fuse.o
obj-y += pmc.o
obj-y += flowctrl.o
@@ -14,8 +13,6 @@ obj-$(CONFIG_CPU_IDLE) += sleep.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += powergate.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_clocks.o
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra2_emc.o
-obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += pinmux-tegra20-tables.o
-obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += pinmux-tegra30-tables.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += board-dt-tegra30.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30_clocks.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
diff --git a/arch/arm/mach-tegra/board-dt-tegra20.c b/arch/arm/mach-tegra/board-dt-tegra20.c
index 0952494f481a..fac3eb1af17e 100644
--- a/arch/arm/mach-tegra/board-dt-tegra20.c
+++ b/arch/arm/mach-tegra/board-dt-tegra20.c
@@ -37,7 +37,6 @@
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
#include <asm/setup.h>
-#include <asm/hardware/gic.h>
#include <mach/iomap.h>
#include <mach/irqs.h>
@@ -47,15 +46,7 @@
#include "clock.h"
#include "devices.h"
-void harmony_pinmux_init(void);
-void paz00_pinmux_init(void);
-void seaboard_pinmux_init(void);
-void trimslice_pinmux_init(void);
-void ventana_pinmux_init(void);
-
struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
- OF_DEV_AUXDATA("nvidia,tegra20-pinmux", TEGRA_APB_MISC_BASE + 0x14, "tegra-pinmux", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-gpio", TEGRA_GPIO_BASE, "tegra-gpio", NULL),
OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC1_BASE, "sdhci-tegra.0", NULL),
OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC2_BASE, "sdhci-tegra.1", NULL),
OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC3_BASE, "sdhci-tegra.2", NULL),
@@ -64,9 +55,9 @@ struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C2_BASE, "tegra-i2c.1", NULL),
OF_DEV_AUXDATA("nvidia,tegra20-i2c", TEGRA_I2C3_BASE, "tegra-i2c.2", NULL),
OF_DEV_AUXDATA("nvidia,tegra20-i2c-dvc", TEGRA_DVC_BASE, "tegra-i2c.3", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra-i2s.0", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S2_BASE, "tegra-i2s.1", NULL),
- OF_DEV_AUXDATA("nvidia,tegra20-das", TEGRA_APB_MISC_DAS_BASE, "tegra-das", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S1_BASE, "tegra20-i2s.0", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra20-i2s", TEGRA_I2S2_BASE, "tegra20-i2s.1", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra20-das", TEGRA_APB_MISC_DAS_BASE, "tegra20-das", NULL),
OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB_BASE, "tegra-ehci.0",
&tegra_ehci1_pdata),
OF_DEV_AUXDATA("nvidia,tegra20-ehci", TEGRA_USB2_BASE, "tegra-ehci.1",
@@ -95,33 +86,10 @@ static struct of_device_id tegra_dt_match_table[] __initdata = {
{}
};
-static struct {
- char *machine;
- void (*init)(void);
-} pinmux_configs[] = {
- { "compulab,trimslice", trimslice_pinmux_init },
- { "nvidia,harmony", harmony_pinmux_init },
- { "compal,paz00", paz00_pinmux_init },
- { "nvidia,seaboard", seaboard_pinmux_init },
- { "nvidia,ventana", ventana_pinmux_init },
-};
-
static void __init tegra_dt_init(void)
{
- int i;
-
tegra_clk_init_from_table(tegra_dt_clk_init_table);
- for (i = 0; i < ARRAY_SIZE(pinmux_configs); i++) {
- if (of_machine_is_compatible(pinmux_configs[i].machine)) {
- pinmux_configs[i].init();
- break;
- }
- }
-
- WARN(i == ARRAY_SIZE(pinmux_configs),
- "Unknown platform! Pinmuxing not initialized\n");
-
/*
* Finished with the static registrations now; fill in the missing
* devices
diff --git a/arch/arm/mach-tegra/board-harmony-pinmux.c b/arch/arm/mach-tegra/board-harmony-pinmux.c
index 1af85bccc0f1..83d420fbc58c 100644
--- a/arch/arm/mach-tegra/board-harmony-pinmux.c
+++ b/arch/arm/mach-tegra/board-harmony-pinmux.c
@@ -2,6 +2,7 @@
* arch/arm/mach-tegra/board-harmony-pinmux.c
*
* Copyright (C) 2010 Google, Inc.
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -15,153 +16,138 @@
*/
#include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <linux/of.h>
-#include <mach/pinmux.h>
-#include <mach/pinmux-tegra20.h>
-
-#include "gpio-names.h"
#include "board-harmony.h"
#include "board-pinmux.h"
-static struct tegra_pingroup_config harmony_pinmux[] = {
- {TEGRA_PINGROUP_ATA, TEGRA_MUX_IDE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_ATB, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_ATC, TEGRA_MUX_NAND, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_ATD, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_ATE, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_CDEV1, TEGRA_MUX_PLLA_OUT, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_CDEV2, TEGRA_MUX_PLLP_OUT4, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_CRTP, TEGRA_MUX_CRT, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_CSUS, TEGRA_MUX_VI_SENSOR_CLK, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DAP1, TEGRA_MUX_DAP1, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_DAP2, TEGRA_MUX_DAP2, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DAP3, TEGRA_MUX_DAP3, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DAP4, TEGRA_MUX_DAP4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DDC, TEGRA_MUX_I2C2, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_DTA, TEGRA_MUX_SDIO2, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_DTB, TEGRA_MUX_RSVD1, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_DTC, TEGRA_MUX_RSVD1, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DTD, TEGRA_MUX_SDIO2, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_DTE, TEGRA_MUX_RSVD1, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DTF, TEGRA_MUX_I2C3, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_GMA, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GMB, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GMC, TEGRA_MUX_UARTD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GMD, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GME, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GPU, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_GPU7, TEGRA_MUX_RTCK, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GPV, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_HDINT, TEGRA_MUX_HDMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_I2CP, TEGRA_MUX_I2C, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_IRRX, TEGRA_MUX_UARTA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_IRTX, TEGRA_MUX_UARTA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_KBCA, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_KBCB, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_KBCC, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_KBCD, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_KBCE, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_KBCF, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LCSN, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LD0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD10, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD11, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD12, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD13, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD14, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD15, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD16, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD17, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD3, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD4, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD5, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD6, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD7, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD8, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD9, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LDC, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LDI, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LHP0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LHP1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LHP2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LHS, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LM0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LM1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LPP, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LPW0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LPW1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LPW2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LSC0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LSC1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LSCK, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LSDA, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LSDI, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LSPI, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LVP0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LVP1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LVS, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_OWC, TEGRA_MUX_RSVD2, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_PMC, TEGRA_MUX_PWR_ON, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_PTA, TEGRA_MUX_HDMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_RM, TEGRA_MUX_I2C, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SDB, TEGRA_MUX_PWM, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SDC, TEGRA_MUX_PWM, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SDD, TEGRA_MUX_PWM, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SDIO1, TEGRA_MUX_SDIO1, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SLXA, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SLXC, TEGRA_MUX_SPDIF, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SLXD, TEGRA_MUX_SPDIF, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SLXK, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SPDI, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPDO, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIA, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SPIB, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SPIC, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPID, TEGRA_MUX_SPI1, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIE, TEGRA_MUX_SPI1, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIF, TEGRA_MUX_SPI1, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIG, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIH, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_UAA, TEGRA_MUX_ULPI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_UAB, TEGRA_MUX_ULPI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_UAC, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_UAD, TEGRA_MUX_IRDA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_UCA, TEGRA_MUX_UARTC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_UCB, TEGRA_MUX_UARTC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_UDA, TEGRA_MUX_ULPI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_CK32, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_DDRC, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_PMCA, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_PMCB, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_PMCC, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_PMCD, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_PMCE, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_XM2C, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_XM2D, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
-};
-
-static struct tegra_gpio_table gpio_table[] = {
- { .gpio = TEGRA_GPIO_SD2_CD, .enable = true },
- { .gpio = TEGRA_GPIO_SD2_WP, .enable = true },
- { .gpio = TEGRA_GPIO_SD2_POWER, .enable = true },
- { .gpio = TEGRA_GPIO_SD4_CD, .enable = true },
- { .gpio = TEGRA_GPIO_SD4_WP, .enable = true },
- { .gpio = TEGRA_GPIO_SD4_POWER, .enable = true },
- { .gpio = TEGRA_GPIO_CDC_IRQ, .enable = true },
- { .gpio = TEGRA_GPIO_HP_DET, .enable = true },
- { .gpio = TEGRA_GPIO_INT_MIC_EN, .enable = true },
- { .gpio = TEGRA_GPIO_EXT_MIC_EN, .enable = true },
+static struct pinctrl_map harmony_map[] = {
+ TEGRA_MAP_MUXCONF("ata", "ide", none, driven),
+ TEGRA_MAP_MUXCONF("atb", "sdio4", none, driven),
+ TEGRA_MAP_MUXCONF("atc", "nand", none, driven),
+ TEGRA_MAP_MUXCONF("atd", "gmi", none, driven),
+ TEGRA_MAP_MUXCONF("ate", "gmi", none, driven),
+ TEGRA_MAP_MUXCONF("cdev1", "plla_out", none, driven),
+ TEGRA_MAP_MUXCONF("cdev2", "pllp_out4", down, tristate),
+ TEGRA_MAP_MUXCONF("crtp", "crt", none, tristate),
+ TEGRA_MAP_MUXCONF("csus", "vi_sensor_clk", down, tristate),
+ TEGRA_MAP_MUXCONF("dap1", "dap1", none, driven),
+ TEGRA_MAP_MUXCONF("dap2", "dap2", none, tristate),
+ TEGRA_MAP_MUXCONF("dap3", "dap3", none, tristate),
+ TEGRA_MAP_MUXCONF("dap4", "dap4", none, tristate),
+ TEGRA_MAP_MUXCONF("ddc", "i2c2", up, driven),
+ TEGRA_MAP_MUXCONF("dta", "sdio2", up, driven),
+ TEGRA_MAP_MUXCONF("dtb", "rsvd1", none, driven),
+ TEGRA_MAP_MUXCONF("dtc", "rsvd1", none, tristate),
+ TEGRA_MAP_MUXCONF("dtd", "sdio2", up, driven),
+ TEGRA_MAP_MUXCONF("dte", "rsvd1", none, tristate),
+ TEGRA_MAP_MUXCONF("dtf", "i2c3", none, tristate),
+ TEGRA_MAP_MUXCONF("gma", "sdio4", none, driven),
+ TEGRA_MAP_MUXCONF("gmb", "gmi", none, driven),
+ TEGRA_MAP_MUXCONF("gmc", "uartd", none, driven),
+ TEGRA_MAP_MUXCONF("gmd", "gmi", none, driven),
+ TEGRA_MAP_MUXCONF("gme", "sdio4", none, driven),
+ TEGRA_MAP_MUXCONF("gpu", "gmi", none, tristate),
+ TEGRA_MAP_MUXCONF("gpu7", "rtck", none, driven),
+ TEGRA_MAP_MUXCONF("gpv", "pcie", none, driven),
+ TEGRA_MAP_MUXCONF("hdint", "hdmi", na, tristate),
+ TEGRA_MAP_MUXCONF("i2cp", "i2cp", none, driven),
+ TEGRA_MAP_MUXCONF("irrx", "uarta", up, tristate),
+ TEGRA_MAP_MUXCONF("irtx", "uarta", up, tristate),
+ TEGRA_MAP_MUXCONF("kbca", "kbc", up, driven),
+ TEGRA_MAP_MUXCONF("kbcb", "kbc", up, driven),
+ TEGRA_MAP_MUXCONF("kbcc", "kbc", up, driven),
+ TEGRA_MAP_MUXCONF("kbcd", "kbc", up, driven),
+ TEGRA_MAP_MUXCONF("kbce", "kbc", up, driven),
+ TEGRA_MAP_MUXCONF("kbcf", "kbc", up, driven),
+ TEGRA_MAP_MUXCONF("lcsn", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("ld0", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld1", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld10", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld11", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld12", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld13", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld14", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld15", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld16", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld17", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld2", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld3", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld4", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld5", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld6", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld7", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld8", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld9", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ldc", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("ldi", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lhp0", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lhp1", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lhp2", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lhs", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lm0", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lm1", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lpp", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lpw0", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lpw1", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lpw2", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lsc0", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lsc1", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lsck", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lsda", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lsdi", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lspi", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lvp0", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lvp1", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lvs", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("owc", "rsvd2", na, tristate),
+ TEGRA_MAP_MUXCONF("pmc", "pwr_on", na, driven),
+ TEGRA_MAP_MUXCONF("pta", "hdmi", none, driven),
+ TEGRA_MAP_MUXCONF("rm", "i2c1", none, driven),
+ TEGRA_MAP_MUXCONF("sdb", "pwm", na, tristate),
+ TEGRA_MAP_MUXCONF("sdc", "pwm", up, driven),
+ TEGRA_MAP_MUXCONF("sdd", "pwm", up, tristate),
+ TEGRA_MAP_MUXCONF("sdio1", "sdio1", none, tristate),
+ TEGRA_MAP_MUXCONF("slxa", "pcie", none, driven),
+ TEGRA_MAP_MUXCONF("slxc", "spdif", none, tristate),
+ TEGRA_MAP_MUXCONF("slxd", "spdif", none, tristate),
+ TEGRA_MAP_MUXCONF("slxk", "pcie", none, driven),
+ TEGRA_MAP_MUXCONF("spdi", "rsvd2", none, tristate),
+ TEGRA_MAP_MUXCONF("spdo", "rsvd2", none, tristate),
+ TEGRA_MAP_MUXCONF("spia", "gmi", none, driven),
+ TEGRA_MAP_MUXCONF("spib", "gmi", none, driven),
+ TEGRA_MAP_MUXCONF("spic", "gmi", up, tristate),
+ TEGRA_MAP_MUXCONF("spid", "spi1", down, tristate),
+ TEGRA_MAP_MUXCONF("spie", "spi1", up, tristate),
+ TEGRA_MAP_MUXCONF("spif", "spi1", down, tristate),
+ TEGRA_MAP_MUXCONF("spig", "spi2_alt", none, tristate),
+ TEGRA_MAP_MUXCONF("spih", "spi2_alt", up, tristate),
+ TEGRA_MAP_MUXCONF("uaa", "ulpi", up, tristate),
+ TEGRA_MAP_MUXCONF("uab", "ulpi", up, tristate),
+ TEGRA_MAP_MUXCONF("uac", "rsvd2", none, tristate),
+ TEGRA_MAP_MUXCONF("uad", "irda", up, tristate),
+ TEGRA_MAP_MUXCONF("uca", "uartc", up, tristate),
+ TEGRA_MAP_MUXCONF("ucb", "uartc", up, tristate),
+ TEGRA_MAP_MUXCONF("uda", "ulpi", none, tristate),
+ TEGRA_MAP_CONF("ck32", none, na),
+ TEGRA_MAP_CONF("ddrc", none, na),
+ TEGRA_MAP_CONF("pmca", none, na),
+ TEGRA_MAP_CONF("pmcb", none, na),
+ TEGRA_MAP_CONF("pmcc", none, na),
+ TEGRA_MAP_CONF("pmcd", none, na),
+ TEGRA_MAP_CONF("pmce", none, na),
+ TEGRA_MAP_CONF("xm2c", none, na),
+ TEGRA_MAP_CONF("xm2d", none, na),
+ TEGRA_MAP_CONF("ls", up, na),
+ TEGRA_MAP_CONF("lc", up, na),
+ TEGRA_MAP_CONF("ld17_0", down, na),
+ TEGRA_MAP_CONF("ld19_18", down, na),
+ TEGRA_MAP_CONF("ld21_20", down, na),
+ TEGRA_MAP_CONF("ld23_22", down, na),
};
static struct tegra_board_pinmux_conf conf = {
- .pgs = harmony_pinmux,
- .pg_count = ARRAY_SIZE(harmony_pinmux),
- .gpios = gpio_table,
- .gpio_count = ARRAY_SIZE(gpio_table),
+ .maps = harmony_map,
+ .map_count = ARRAY_SIZE(harmony_map),
};
void harmony_pinmux_init(void)
diff --git a/arch/arm/mach-tegra/board-harmony.c b/arch/arm/mach-tegra/board-harmony.c
index c00aadb01e09..b906b3b6077b 100644
--- a/arch/arm/mach-tegra/board-harmony.c
+++ b/arch/arm/mach-tegra/board-harmony.c
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
+#include <linux/of_serial.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/pda_power.h>
@@ -52,6 +53,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
.irq = INT_UARTD,
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
.type = PORT_TEGRA,
+ .handle_break = tegra_serial_handle_break,
.iotype = UPIO_MEM,
.regshift = 2,
.uartclk = 216000000,
@@ -122,7 +124,6 @@ static struct platform_device *harmony_devices[] __initdata = {
&tegra_ehci3_device,
&tegra_i2s_device1,
&tegra_das_device,
- &tegra_pcm_device,
&harmony_audio_device,
};
diff --git a/arch/arm/mach-tegra/board-paz00-pinmux.c b/arch/arm/mach-tegra/board-paz00-pinmux.c
index c775572dcea4..6f1111b48e7c 100644
--- a/arch/arm/mach-tegra/board-paz00-pinmux.c
+++ b/arch/arm/mach-tegra/board-paz00-pinmux.c
@@ -2,6 +2,7 @@
* arch/arm/mach-tegra/board-paz00-pinmux.c
*
* Copyright (C) 2010 Marc Dietrich <marvin24@gmx.de>
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -15,150 +16,138 @@
*/
#include <linux/kernel.h>
-#include <linux/gpio.h>
-#include <linux/of.h>
-#include <mach/pinmux.h>
-#include <mach/pinmux-tegra20.h>
-
-#include "gpio-names.h"
#include "board-paz00.h"
#include "board-pinmux.h"
-static struct tegra_pingroup_config paz00_pinmux[] = {
- {TEGRA_PINGROUP_ATA, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_ATB, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_ATC, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_ATD, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_ATE, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_CDEV1, TEGRA_MUX_PLLA_OUT, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_CDEV2, TEGRA_MUX_PLLP_OUT4, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_CRTP, TEGRA_MUX_CRT, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_CSUS, TEGRA_MUX_PLLC_OUT1, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DAP1, TEGRA_MUX_DAP1, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_DAP2, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_DAP3, TEGRA_MUX_DAP3, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DAP4, TEGRA_MUX_DAP4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DDC, TEGRA_MUX_I2C2, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_DTA, TEGRA_MUX_RSVD1, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DTB, TEGRA_MUX_RSVD1, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DTC, TEGRA_MUX_RSVD1, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DTD, TEGRA_MUX_RSVD1, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DTE, TEGRA_MUX_RSVD1, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DTF, TEGRA_MUX_I2C3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GMA, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GMB, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GMC, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GMD, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GME, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GPU, TEGRA_MUX_PWM, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GPU7, TEGRA_MUX_RTCK, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GPV, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_HDINT, TEGRA_MUX_HDMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_I2CP, TEGRA_MUX_I2C, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_IRRX, TEGRA_MUX_UARTA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_IRTX, TEGRA_MUX_UARTA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_KBCA, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_KBCB, TEGRA_MUX_SDIO2, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_KBCC, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_KBCD, TEGRA_MUX_SDIO2, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_KBCE, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_KBCF, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LCSN, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LD0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD10, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD11, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD12, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD13, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD14, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD15, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD16, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD17, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD3, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD4, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD5, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD6, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD7, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD8, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD9, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LDC, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LDI, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LHP0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LHP1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LHP2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LHS, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LM0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LM1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LPP, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LPW0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LPW1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LPW2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LSC0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LSC1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LSCK, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LSDA, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LSDI, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LSPI, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LVP0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LVP1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LVS, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_OWC, TEGRA_MUX_OWR, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_PMC, TEGRA_MUX_PWR_ON, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_PTA, TEGRA_MUX_HDMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_RM, TEGRA_MUX_I2C, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SDB, TEGRA_MUX_PWM, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SDC, TEGRA_MUX_TWC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SDD, TEGRA_MUX_PWM, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SDIO1, TEGRA_MUX_SDIO1, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SLXA, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SLXC, TEGRA_MUX_SPI4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SLXD, TEGRA_MUX_SPI4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SLXK, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SPDI, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPDO, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SPIA, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIB, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIC, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SPID, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIE, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIF, TEGRA_MUX_RSVD4, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIG, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SPIH, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_UAA, TEGRA_MUX_ULPI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_UAB, TEGRA_MUX_ULPI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_UAC, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_UAD, TEGRA_MUX_SPDIF, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_UCA, TEGRA_MUX_UARTC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_UCB, TEGRA_MUX_UARTC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_UDA, TEGRA_MUX_ULPI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_CK32, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_DDRC, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_PMCA, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_PMCB, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_PMCC, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_PMCD, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_PMCE, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_XM2C, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_XM2D, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
-};
-
-static struct tegra_gpio_table gpio_table[] = {
- { .gpio = TEGRA_GPIO_SD1_CD, .enable = true },
- { .gpio = TEGRA_GPIO_SD1_WP, .enable = true },
- { .gpio = TEGRA_GPIO_SD1_POWER, .enable = true },
- { .gpio = TEGRA_ULPI_RST, .enable = true },
- { .gpio = TEGRA_WIFI_PWRN, .enable = true },
- { .gpio = TEGRA_WIFI_RST, .enable = true },
- { .gpio = TEGRA_WIFI_LED, .enable = true },
+static struct pinctrl_map paz00_map[] = {
+ TEGRA_MAP_MUXCONF("ata", "gmi", none, driven),
+ TEGRA_MAP_MUXCONF("atb", "sdio4", none, driven),
+ TEGRA_MAP_MUXCONF("atc", "gmi", none, driven),
+ TEGRA_MAP_MUXCONF("atd", "gmi", none, driven),
+ TEGRA_MAP_MUXCONF("ate", "gmi", none, driven),
+ TEGRA_MAP_MUXCONF("cdev1", "plla_out", none, driven),
+ TEGRA_MAP_MUXCONF("cdev2", "pllp_out4", down, driven),
+ TEGRA_MAP_MUXCONF("crtp", "crt", none, tristate),
+ TEGRA_MAP_MUXCONF("csus", "pllc_out1", down, tristate),
+ TEGRA_MAP_MUXCONF("dap1", "dap1", none, driven),
+ TEGRA_MAP_MUXCONF("dap2", "gmi", none, driven),
+ TEGRA_MAP_MUXCONF("dap3", "dap3", none, tristate),
+ TEGRA_MAP_MUXCONF("dap4", "dap4", none, tristate),
+ TEGRA_MAP_MUXCONF("ddc", "i2c2", up, driven),
+ TEGRA_MAP_MUXCONF("dta", "rsvd1", up, tristate),
+ TEGRA_MAP_MUXCONF("dtb", "rsvd1", none, tristate),
+ TEGRA_MAP_MUXCONF("dtc", "rsvd1", none, tristate),
+ TEGRA_MAP_MUXCONF("dtd", "rsvd1", up, tristate),
+ TEGRA_MAP_MUXCONF("dte", "rsvd1", none, tristate),
+ TEGRA_MAP_MUXCONF("dtf", "i2c3", none, driven),
+ TEGRA_MAP_MUXCONF("gma", "sdio4", none, driven),
+ TEGRA_MAP_MUXCONF("gmb", "gmi", none, driven),
+ TEGRA_MAP_MUXCONF("gmc", "gmi", none, driven),
+ TEGRA_MAP_MUXCONF("gmd", "gmi", none, driven),
+ TEGRA_MAP_MUXCONF("gme", "sdio4", none, driven),
+ TEGRA_MAP_MUXCONF("gpu", "pwm", none, driven),
+ TEGRA_MAP_MUXCONF("gpu7", "rtck", none, driven),
+ TEGRA_MAP_MUXCONF("gpv", "pcie", none, driven),
+ TEGRA_MAP_MUXCONF("hdint", "hdmi", na, driven),
+ TEGRA_MAP_MUXCONF("i2cp", "i2cp", none, driven),
+ TEGRA_MAP_MUXCONF("irrx", "uarta", up, driven),
+ TEGRA_MAP_MUXCONF("irtx", "uarta", up, driven),
+ TEGRA_MAP_MUXCONF("kbca", "kbc", up, driven),
+ TEGRA_MAP_MUXCONF("kbcb", "sdio2", up, driven),
+ TEGRA_MAP_MUXCONF("kbcc", "kbc", up, driven),
+ TEGRA_MAP_MUXCONF("kbcd", "sdio2", up, driven),
+ TEGRA_MAP_MUXCONF("kbce", "kbc", up, driven),
+ TEGRA_MAP_MUXCONF("kbcf", "kbc", up, driven),
+ TEGRA_MAP_MUXCONF("lcsn", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("ld0", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld1", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld10", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld11", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld12", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld13", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld14", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld15", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld16", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld17", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld2", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld3", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld4", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld5", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld6", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld7", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld8", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld9", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ldc", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ldi", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lhp0", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lhp1", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lhp2", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lhs", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lm0", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lm1", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lpp", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lpw0", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lpw1", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lpw2", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lsc0", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lsc1", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lsck", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lsda", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lsdi", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lspi", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lvp0", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lvp1", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lvs", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("owc", "owr", up, tristate),
+ TEGRA_MAP_MUXCONF("pmc", "pwr_on", na, driven),
+ TEGRA_MAP_MUXCONF("pta", "hdmi", none, driven),
+ TEGRA_MAP_MUXCONF("rm", "i2c1", none, driven),
+ TEGRA_MAP_MUXCONF("sdb", "pwm", na, tristate),
+ TEGRA_MAP_MUXCONF("sdc", "twc", up, tristate),
+ TEGRA_MAP_MUXCONF("sdd", "pwm", up, tristate),
+ TEGRA_MAP_MUXCONF("sdio1", "sdio1", none, driven),
+ TEGRA_MAP_MUXCONF("slxa", "pcie", none, tristate),
+ TEGRA_MAP_MUXCONF("slxc", "spi4", none, tristate),
+ TEGRA_MAP_MUXCONF("slxd", "spi4", none, tristate),
+ TEGRA_MAP_MUXCONF("slxk", "pcie", none, driven),
+ TEGRA_MAP_MUXCONF("spdi", "rsvd2", none, tristate),
+ TEGRA_MAP_MUXCONF("spdo", "rsvd2", none, driven),
+ TEGRA_MAP_MUXCONF("spia", "gmi", down, tristate),
+ TEGRA_MAP_MUXCONF("spib", "gmi", down, tristate),
+ TEGRA_MAP_MUXCONF("spic", "gmi", up, driven),
+ TEGRA_MAP_MUXCONF("spid", "gmi", down, tristate),
+ TEGRA_MAP_MUXCONF("spie", "gmi", up, tristate),
+ TEGRA_MAP_MUXCONF("spif", "rsvd4", down, tristate),
+ TEGRA_MAP_MUXCONF("spig", "spi2_alt", up, driven),
+ TEGRA_MAP_MUXCONF("spih", "spi2_alt", up, tristate),
+ TEGRA_MAP_MUXCONF("uaa", "ulpi", up, driven),
+ TEGRA_MAP_MUXCONF("uab", "ulpi", up, driven),
+ TEGRA_MAP_MUXCONF("uac", "rsvd4", none, driven),
+ TEGRA_MAP_MUXCONF("uad", "spdif", up, tristate),
+ TEGRA_MAP_MUXCONF("uca", "uartc", up, tristate),
+ TEGRA_MAP_MUXCONF("ucb", "uartc", up, tristate),
+ TEGRA_MAP_MUXCONF("uda", "ulpi", none, driven),
+ TEGRA_MAP_CONF("ck32", none, na),
+ TEGRA_MAP_CONF("ddrc", none, na),
+ TEGRA_MAP_CONF("pmca", none, na),
+ TEGRA_MAP_CONF("pmcb", none, na),
+ TEGRA_MAP_CONF("pmcc", none, na),
+ TEGRA_MAP_CONF("pmcd", none, na),
+ TEGRA_MAP_CONF("pmce", none, na),
+ TEGRA_MAP_CONF("xm2c", none, na),
+ TEGRA_MAP_CONF("xm2d", none, na),
+ TEGRA_MAP_CONF("ls", up, na),
+ TEGRA_MAP_CONF("lc", up, na),
+ TEGRA_MAP_CONF("ld17_0", down, na),
+ TEGRA_MAP_CONF("ld19_18", down, na),
+ TEGRA_MAP_CONF("ld21_20", down, na),
+ TEGRA_MAP_CONF("ld23_22", down, na),
};
static struct tegra_board_pinmux_conf conf = {
- .pgs = paz00_pinmux,
- .pg_count = ARRAY_SIZE(paz00_pinmux),
- .gpios = gpio_table,
- .gpio_count = ARRAY_SIZE(gpio_table),
+ .maps = paz00_map,
+ .map_count = ARRAY_SIZE(paz00_map),
};
void paz00_pinmux_init(void)
diff --git a/arch/arm/mach-tegra/board-paz00.c b/arch/arm/mach-tegra/board-paz00.c
index 330afdfa2475..d0735c70d688 100644
--- a/arch/arm/mach-tegra/board-paz00.c
+++ b/arch/arm/mach-tegra/board-paz00.c
@@ -21,6 +21,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
+#include <linux/of_serial.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/gpio_keys.h>
@@ -55,6 +56,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
.irq = INT_UARTA,
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
.type = PORT_TEGRA,
+ .handle_break = tegra_serial_handle_break,
.iotype = UPIO_MEM,
.regshift = 2,
.uartclk = 216000000,
@@ -65,6 +67,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
.irq = INT_UARTC,
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
.type = PORT_TEGRA,
+ .handle_break = tegra_serial_handle_break,
.iotype = UPIO_MEM,
.regshift = 2,
.uartclk = 216000000,
diff --git a/arch/arm/mach-tegra/board-pinmux.c b/arch/arm/mach-tegra/board-pinmux.c
index adc3efe979b3..a5574c71b931 100644
--- a/arch/arm/mach-tegra/board-pinmux.c
+++ b/arch/arm/mach-tegra/board-pinmux.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2011,2012, NVIDIA CORPORATION. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -15,75 +15,59 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/notifier.h>
-#include <linux/of.h>
#include <linux/string.h>
-#include <mach/gpio-tegra.h>
-#include <mach/pinmux.h>
-
#include "board-pinmux.h"
#include "devices.h"
-struct tegra_board_pinmux_conf *confs[2];
-
-static void tegra_board_pinmux_setup_gpios(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(confs); i++) {
- if (!confs[i])
- continue;
-
- tegra_gpio_config(confs[i]->gpios, confs[i]->gpio_count);
- }
-}
-
-static void tegra_board_pinmux_setup_pinmux(void)
-{
- int i;
+unsigned long tegra_pincfg_pullnone_driven[2] = {
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_PULL, TEGRA_PINCONFIG_PULL_NONE),
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_TRISTATE, TEGRA_PINCONFIG_DRIVEN),
+};
- for (i = 0; i < ARRAY_SIZE(confs); i++) {
- if (!confs[i])
- continue;
+unsigned long tegra_pincfg_pullnone_tristate[2] = {
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_PULL, TEGRA_PINCONFIG_PULL_NONE),
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_TRISTATE, TEGRA_PINCONFIG_TRISTATE),
+};
- tegra_pinmux_config_table(confs[i]->pgs, confs[i]->pg_count);
+unsigned long tegra_pincfg_pullnone_na[1] = {
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_PULL, TEGRA_PINCONFIG_PULL_NONE),
+};
- if (confs[i]->drives)
- tegra_drive_pinmux_config_table(confs[i]->drives,
- confs[i]->drive_count);
- }
-}
+unsigned long tegra_pincfg_pullup_driven[2] = {
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_PULL, TEGRA_PINCONFIG_PULL_UP),
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_TRISTATE, TEGRA_PINCONFIG_DRIVEN),
+};
-static int tegra_board_pinmux_bus_notify(struct notifier_block *nb,
- unsigned long event, void *vdev)
-{
- static bool had_gpio;
- static bool had_pinmux;
+unsigned long tegra_pincfg_pullup_tristate[2] = {
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_PULL, TEGRA_PINCONFIG_PULL_UP),
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_TRISTATE, TEGRA_PINCONFIG_TRISTATE),
+};
- struct device *dev = vdev;
- const char *devname;
+unsigned long tegra_pincfg_pullup_na[1] = {
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_PULL, TEGRA_PINCONFIG_PULL_UP),
+};
- if (event != BUS_NOTIFY_BOUND_DRIVER)
- return NOTIFY_DONE;
+unsigned long tegra_pincfg_pulldown_driven[2] = {
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_PULL, TEGRA_PINCONFIG_PULL_DOWN),
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_TRISTATE, TEGRA_PINCONFIG_DRIVEN),
+};
- devname = dev_name(dev);
+unsigned long tegra_pincfg_pulldown_tristate[2] = {
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_PULL, TEGRA_PINCONFIG_PULL_DOWN),
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_TRISTATE, TEGRA_PINCONFIG_TRISTATE),
+};
- if (!had_gpio && !strcmp(devname, GPIO_DEV)) {
- tegra_board_pinmux_setup_gpios();
- had_gpio = true;
- } else if (!had_pinmux && !strcmp(devname, PINMUX_DEV)) {
- tegra_board_pinmux_setup_pinmux();
- had_pinmux = true;
- }
+unsigned long tegra_pincfg_pulldown_na[1] = {
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_PULL, TEGRA_PINCONFIG_PULL_DOWN),
+};
- if (had_gpio && had_pinmux)
- return NOTIFY_STOP_MASK;
- else
- return NOTIFY_DONE;
-}
+unsigned long tegra_pincfg_pullna_driven[1] = {
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_TRISTATE, TEGRA_PINCONFIG_DRIVEN),
+};
-static struct notifier_block nb = {
- .notifier_call = tegra_board_pinmux_bus_notify,
+unsigned long tegra_pincfg_pullna_tristate[1] = {
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_TRISTATE, TEGRA_PINCONFIG_TRISTATE),
};
static struct platform_device *devices[] = {
@@ -94,11 +78,10 @@ static struct platform_device *devices[] = {
void tegra_board_pinmux_init(struct tegra_board_pinmux_conf *conf_a,
struct tegra_board_pinmux_conf *conf_b)
{
- confs[0] = conf_a;
- confs[1] = conf_b;
-
- bus_register_notifier(&platform_bus_type, &nb);
+ if (conf_a)
+ pinctrl_register_mappings(conf_a->maps, conf_a->map_count);
+ if (conf_b)
+ pinctrl_register_mappings(conf_b->maps, conf_b->map_count);
- if (!of_machine_is_compatible("nvidia,tegra20"))
- platform_add_devices(devices, ARRAY_SIZE(devices));
+ platform_add_devices(devices, ARRAY_SIZE(devices));
}
diff --git a/arch/arm/mach-tegra/board-pinmux.h b/arch/arm/mach-tegra/board-pinmux.h
index 4aac73546f54..c5f3f3381e86 100644
--- a/arch/arm/mach-tegra/board-pinmux.h
+++ b/arch/arm/mach-tegra/board-pinmux.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2011,2012, NVIDIA CORPORATION. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -15,21 +15,37 @@
#ifndef __MACH_TEGRA_BOARD_PINMUX_H
#define __MACH_TEGRA_BOARD_PINMUX_H
-#define GPIO_DEV "tegra-gpio"
-#define PINMUX_DEV "tegra-pinmux"
+#include <linux/pinctrl/machine.h>
-struct tegra_pingroup_config;
-struct tegra_gpio_table;
+#include <mach/pinconf-tegra.h>
-struct tegra_board_pinmux_conf {
- struct tegra_pingroup_config *pgs;
- int pg_count;
+#define PINMUX_DEV "tegra20-pinctrl"
+
+#define TEGRA_MAP_MUX(_group_, _function_) \
+ PIN_MAP_MUX_GROUP_HOG_DEFAULT(PINMUX_DEV, _group_, _function_)
+
+#define TEGRA_MAP_CONF(_group_, _pull_, _drive_) \
+ PIN_MAP_CONFIGS_GROUP_HOG_DEFAULT(PINMUX_DEV, _group_, tegra_pincfg_pull##_pull_##_##_drive_)
- struct tegra_drive_pingroup_config *drives;
- int drive_count;
+#define TEGRA_MAP_MUXCONF(_group_, _function_, _pull_, _drive_) \
+ TEGRA_MAP_MUX(_group_, _function_), \
+ TEGRA_MAP_CONF(_group_, _pull_, _drive_)
- struct tegra_gpio_table *gpios;
- int gpio_count;
+extern unsigned long tegra_pincfg_pullnone_driven[2];
+extern unsigned long tegra_pincfg_pullnone_tristate[2];
+extern unsigned long tegra_pincfg_pullnone_na[1];
+extern unsigned long tegra_pincfg_pullup_driven[2];
+extern unsigned long tegra_pincfg_pullup_tristate[2];
+extern unsigned long tegra_pincfg_pullup_na[1];
+extern unsigned long tegra_pincfg_pulldown_driven[2];
+extern unsigned long tegra_pincfg_pulldown_tristate[2];
+extern unsigned long tegra_pincfg_pulldown_na[1];
+extern unsigned long tegra_pincfg_pullna_driven[1];
+extern unsigned long tegra_pincfg_pullna_tristate[1];
+
+struct tegra_board_pinmux_conf {
+ struct pinctrl_map *maps;
+ int map_count;
};
void tegra_board_pinmux_init(struct tegra_board_pinmux_conf *conf_a,
diff --git a/arch/arm/mach-tegra/board-seaboard-pinmux.c b/arch/arm/mach-tegra/board-seaboard-pinmux.c
index 55e7e43a14ad..11fc8a568c64 100644
--- a/arch/arm/mach-tegra/board-seaboard-pinmux.c
+++ b/arch/arm/mach-tegra/board-seaboard-pinmux.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010,2011 NVIDIA Corporation
+ * Copyright (C) 2010-2012 NVIDIA Corporation
* Copyright (C) 2011 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
@@ -14,216 +14,176 @@
*/
#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/of.h>
-#include <mach/pinmux.h>
-#include <mach/pinmux-tegra20.h>
-
-#include "gpio-names.h"
-#include "board-pinmux.h"
#include "board-seaboard.h"
+#include "board-pinmux.h"
-#define DEFAULT_DRIVE(_name) \
- { \
- .pingroup = TEGRA_DRIVE_PINGROUP_##_name, \
- .hsm = TEGRA_HSM_DISABLE, \
- .schmitt = TEGRA_SCHMITT_ENABLE, \
- .drive = TEGRA_DRIVE_DIV_1, \
- .pull_down = TEGRA_PULL_31, \
- .pull_up = TEGRA_PULL_31, \
- .slew_rising = TEGRA_SLEW_SLOWEST, \
- .slew_falling = TEGRA_SLEW_SLOWEST, \
- }
-
-static struct tegra_drive_pingroup_config seaboard_drive_pinmux[] = {
- DEFAULT_DRIVE(SDIO1),
-};
-
-static struct tegra_pingroup_config common_pinmux[] = {
- {TEGRA_PINGROUP_ATA, TEGRA_MUX_IDE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_ATB, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_ATC, TEGRA_MUX_NAND, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_ATD, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_ATE, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_CDEV1, TEGRA_MUX_PLLA_OUT, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_CDEV2, TEGRA_MUX_PLLP_OUT4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_CRTP, TEGRA_MUX_CRT, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_CSUS, TEGRA_MUX_VI_SENSOR_CLK, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DAP1, TEGRA_MUX_DAP1, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_DAP2, TEGRA_MUX_DAP2, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_DAP3, TEGRA_MUX_DAP3, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DAP4, TEGRA_MUX_DAP4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_DTA, TEGRA_MUX_VI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_DTB, TEGRA_MUX_VI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_DTC, TEGRA_MUX_VI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_DTD, TEGRA_MUX_VI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_DTE, TEGRA_MUX_VI, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DTF, TEGRA_MUX_I2C3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GMA, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GMB, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_GMC, TEGRA_MUX_UARTD, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GME, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GPU, TEGRA_MUX_PWM, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GPU7, TEGRA_MUX_RTCK, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GPV, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_HDINT, TEGRA_MUX_HDMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_I2CP, TEGRA_MUX_I2C, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_IRRX, TEGRA_MUX_UARTB, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_IRTX, TEGRA_MUX_UARTB, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_KBCA, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_KBCB, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_KBCC, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_KBCD, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_KBCE, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_KBCF, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LCSN, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LD0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD10, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD11, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD12, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD13, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD14, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD15, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD16, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD17, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD3, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD4, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD5, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD6, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD7, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD8, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD9, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LDC, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LDI, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LHP0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LHP1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LHP2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LHS, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LM0, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LM1, TEGRA_MUX_CRT, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LPP, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LPW1, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LSC0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LSDI, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LSPI, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LVP0, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LVP1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LVS, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_OWC, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_PMC, TEGRA_MUX_PWR_ON, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_RM, TEGRA_MUX_I2C, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SDB, TEGRA_MUX_SDIO3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SDC, TEGRA_MUX_SDIO3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SDD, TEGRA_MUX_SDIO3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SDIO1, TEGRA_MUX_SDIO1, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SLXA, TEGRA_MUX_PCIE, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SLXD, TEGRA_MUX_SPDIF, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SPDI, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SPDO, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SPIB, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPID, TEGRA_MUX_SPI1, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIE, TEGRA_MUX_SPI1, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIF, TEGRA_MUX_SPI1, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIH, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_UAA, TEGRA_MUX_ULPI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_UAB, TEGRA_MUX_ULPI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_UAC, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_UAD, TEGRA_MUX_IRDA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_UCA, TEGRA_MUX_UARTC, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_UCB, TEGRA_MUX_UARTC, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_UDA, TEGRA_MUX_ULPI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_CK32, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_DDRC, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_PMCA, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_PMCB, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_PMCC, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_PMCD, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_PMCE, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_XM2C, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_XM2D, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
-};
-
-static struct tegra_pingroup_config seaboard_pinmux[] = {
- {TEGRA_PINGROUP_DDC, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_GMD, TEGRA_MUX_SFLASH, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LPW0, TEGRA_MUX_HDMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LPW2, TEGRA_MUX_HDMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LSC1, TEGRA_MUX_HDMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LSCK, TEGRA_MUX_HDMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LSDA, TEGRA_MUX_HDMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_PTA, TEGRA_MUX_HDMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SLXC, TEGRA_MUX_SPDIF, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SLXK, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SPIA, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIC, TEGRA_MUX_GMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SPIG, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
-};
-
-static struct tegra_pingroup_config ventana_pinmux[] = {
- {TEGRA_PINGROUP_DDC, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GMD, TEGRA_MUX_SFLASH, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LPW0, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LPW2, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LSC1, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LSCK, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LSDA, TEGRA_MUX_RSVD4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_PTA, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SLXC, TEGRA_MUX_SDIO3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SLXK, TEGRA_MUX_SDIO3, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SPIA, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIC, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIG, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
+static unsigned long seaboard_pincfg_drive_sdio1[] = {
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_HIGH_SPEED_MODE, 0),
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_SCHMITT, 0),
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_LOW_POWER_MODE, 3),
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_DRIVE_DOWN_STRENGTH, 31),
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_DRIVE_UP_STRENGTH, 31),
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_SLEW_RATE_FALLING, 3),
+ TEGRA_PINCONF_PACK(TEGRA_PINCONF_PARAM_SLEW_RATE_RISING, 3),
};
-static struct tegra_gpio_table common_gpio_table[] = {
- { .gpio = TEGRA_GPIO_SD2_CD, .enable = true },
- { .gpio = TEGRA_GPIO_SD2_WP, .enable = true },
- { .gpio = TEGRA_GPIO_SD2_POWER, .enable = true },
- { .gpio = TEGRA_GPIO_CDC_IRQ, .enable = true },
+static struct pinctrl_map common_map[] = {
+ TEGRA_MAP_MUXCONF("ata", "ide", none, driven),
+ TEGRA_MAP_MUXCONF("atb", "sdio4", none, driven),
+ TEGRA_MAP_MUXCONF("atc", "nand", none, driven),
+ TEGRA_MAP_MUXCONF("atd", "gmi", none, driven),
+ TEGRA_MAP_MUXCONF("ate", "gmi", none, tristate),
+ TEGRA_MAP_MUXCONF("cdev1", "plla_out", none, driven),
+ TEGRA_MAP_MUXCONF("cdev2", "pllp_out4", none, driven),
+ TEGRA_MAP_MUXCONF("crtp", "crt", up, tristate),
+ TEGRA_MAP_MUXCONF("csus", "vi_sensor_clk", none, tristate),
+ TEGRA_MAP_MUXCONF("dap1", "dap1", none, driven),
+ TEGRA_MAP_MUXCONF("dap2", "dap2", none, driven),
+ TEGRA_MAP_MUXCONF("dap3", "dap3", none, tristate),
+ TEGRA_MAP_MUXCONF("dap4", "dap4", none, driven),
+ TEGRA_MAP_MUXCONF("dta", "vi", down, driven),
+ TEGRA_MAP_MUXCONF("dtb", "vi", down, driven),
+ TEGRA_MAP_MUXCONF("dtc", "vi", down, driven),
+ TEGRA_MAP_MUXCONF("dtd", "vi", down, driven),
+ TEGRA_MAP_MUXCONF("dte", "vi", down, tristate),
+ TEGRA_MAP_MUXCONF("dtf", "i2c3", none, driven),
+ TEGRA_MAP_MUXCONF("gma", "sdio4", none, driven),
+ TEGRA_MAP_MUXCONF("gmb", "gmi", up, tristate),
+ TEGRA_MAP_MUXCONF("gmc", "uartd", none, driven),
+ TEGRA_MAP_MUXCONF("gme", "sdio4", none, driven),
+ TEGRA_MAP_MUXCONF("gpu", "pwm", none, driven),
+ TEGRA_MAP_MUXCONF("gpu7", "rtck", none, driven),
+ TEGRA_MAP_MUXCONF("gpv", "pcie", none, tristate),
+ TEGRA_MAP_MUXCONF("hdint", "hdmi", na, tristate),
+ TEGRA_MAP_MUXCONF("i2cp", "i2cp", none, driven),
+ TEGRA_MAP_MUXCONF("irrx", "uartb", none, driven),
+ TEGRA_MAP_MUXCONF("irtx", "uartb", none, driven),
+ TEGRA_MAP_MUXCONF("kbca", "kbc", up, driven),
+ TEGRA_MAP_MUXCONF("kbcb", "kbc", up, driven),
+ TEGRA_MAP_MUXCONF("kbcc", "kbc", up, driven),
+ TEGRA_MAP_MUXCONF("kbcd", "kbc", up, driven),
+ TEGRA_MAP_MUXCONF("kbce", "kbc", up, driven),
+ TEGRA_MAP_MUXCONF("kbcf", "kbc", up, driven),
+ TEGRA_MAP_MUXCONF("lcsn", "rsvd4", na, tristate),
+ TEGRA_MAP_MUXCONF("ld0", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld1", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld10", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld11", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld12", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld13", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld14", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld15", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld16", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld17", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld2", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld3", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld4", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld5", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld6", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld7", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld8", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld9", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ldc", "rsvd4", na, tristate),
+ TEGRA_MAP_MUXCONF("ldi", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lhp0", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lhp1", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lhp2", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lhs", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lm0", "rsvd4", na, driven),
+ TEGRA_MAP_MUXCONF("lm1", "crt", na, tristate),
+ TEGRA_MAP_MUXCONF("lpp", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lpw1", "rsvd4", na, tristate),
+ TEGRA_MAP_MUXCONF("lsc0", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lsdi", "rsvd4", na, tristate),
+ TEGRA_MAP_MUXCONF("lspi", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lvp0", "rsvd4", na, tristate),
+ TEGRA_MAP_MUXCONF("lvp1", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lvs", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("owc", "rsvd2", none, tristate),
+ TEGRA_MAP_MUXCONF("pmc", "pwr_on", na, driven),
+ TEGRA_MAP_MUXCONF("pta", "hdmi", none, driven),
+ TEGRA_MAP_MUXCONF("rm", "i2c1", none, driven),
+ TEGRA_MAP_MUXCONF("sdb", "sdio3", na, driven),
+ TEGRA_MAP_MUXCONF("sdc", "sdio3", none, driven),
+ TEGRA_MAP_MUXCONF("sdd", "sdio3", none, driven),
+ TEGRA_MAP_MUXCONF("sdio1", "sdio1", up, driven),
+ TEGRA_MAP_MUXCONF("slxa", "pcie", up, tristate),
+ TEGRA_MAP_MUXCONF("slxd", "spdif", none, driven),
+ TEGRA_MAP_MUXCONF("slxk", "pcie", none, driven),
+ TEGRA_MAP_MUXCONF("spdi", "rsvd2", none, driven),
+ TEGRA_MAP_MUXCONF("spdo", "rsvd2", none, driven),
+ TEGRA_MAP_MUXCONF("spib", "gmi", none, tristate),
+ TEGRA_MAP_MUXCONF("spid", "spi1", none, tristate),
+ TEGRA_MAP_MUXCONF("spie", "spi1", none, tristate),
+ TEGRA_MAP_MUXCONF("spif", "spi1", down, tristate),
+ TEGRA_MAP_MUXCONF("spih", "spi2_alt", up, tristate),
+ TEGRA_MAP_MUXCONF("uaa", "ulpi", up, driven),
+ TEGRA_MAP_MUXCONF("uab", "ulpi", up, driven),
+ TEGRA_MAP_MUXCONF("uac", "rsvd2", none, driven),
+ TEGRA_MAP_MUXCONF("uad", "irda", none, driven),
+ TEGRA_MAP_MUXCONF("uca", "uartc", none, driven),
+ TEGRA_MAP_MUXCONF("ucb", "uartc", none, driven),
+ TEGRA_MAP_MUXCONF("uda", "ulpi", none, driven),
+ TEGRA_MAP_CONF("ck32", none, na),
+ TEGRA_MAP_CONF("ddrc", none, na),
+ TEGRA_MAP_CONF("pmca", none, na),
+ TEGRA_MAP_CONF("pmcb", none, na),
+ TEGRA_MAP_CONF("pmcc", none, na),
+ TEGRA_MAP_CONF("pmcd", none, na),
+ TEGRA_MAP_CONF("pmce", none, na),
+ TEGRA_MAP_CONF("xm2c", none, na),
+ TEGRA_MAP_CONF("xm2d", none, na),
+ TEGRA_MAP_CONF("ls", up, na),
+ TEGRA_MAP_CONF("lc", up, na),
+ TEGRA_MAP_CONF("ld17_0", down, na),
+ TEGRA_MAP_CONF("ld19_18", down, na),
+ TEGRA_MAP_CONF("ld21_20", down, na),
+ TEGRA_MAP_CONF("ld23_22", down, na),
};
-static struct tegra_gpio_table seaboard_gpio_table[] = {
- { .gpio = TEGRA_GPIO_LIDSWITCH, .enable = true },
- { .gpio = TEGRA_GPIO_POWERKEY, .enable = true },
- { .gpio = TEGRA_GPIO_HP_DET, .enable = true },
- { .gpio = TEGRA_GPIO_ISL29018_IRQ, .enable = true },
- { .gpio = TEGRA_GPIO_USB1, .enable = true },
+static struct pinctrl_map seaboard_map[] = {
+ TEGRA_MAP_MUXCONF("ddc", "rsvd2", none, tristate),
+ TEGRA_MAP_MUXCONF("gmd", "sflash", none, driven),
+ TEGRA_MAP_MUXCONF("lpw0", "hdmi", na, driven),
+ TEGRA_MAP_MUXCONF("lpw2", "hdmi", na, driven),
+ TEGRA_MAP_MUXCONF("lsc1", "hdmi", na, tristate),
+ TEGRA_MAP_MUXCONF("lsck", "hdmi", na, tristate),
+ TEGRA_MAP_MUXCONF("lsda", "hdmi", na, tristate),
+ TEGRA_MAP_MUXCONF("slxc", "spdif", none, tristate),
+ TEGRA_MAP_MUXCONF("spia", "gmi", up, tristate),
+ TEGRA_MAP_MUXCONF("spic", "gmi", up, driven),
+ TEGRA_MAP_MUXCONF("spig", "spi2_alt", up, tristate),
+ PIN_MAP_CONFIGS_GROUP_HOG_DEFAULT(PINMUX_DEV, "drive_sdio1", seaboard_pincfg_drive_sdio1),
};
-static struct tegra_gpio_table ventana_gpio_table[] = {
- /* hp_det */
- { .gpio = TEGRA_GPIO_PW2, .enable = true },
- /* int_mic_en */
- { .gpio = TEGRA_GPIO_PX0, .enable = true },
- /* ext_mic_en */
- { .gpio = TEGRA_GPIO_PX1, .enable = true },
+static struct pinctrl_map ventana_map[] = {
+ TEGRA_MAP_MUXCONF("ddc", "rsvd2", none, driven),
+ TEGRA_MAP_MUXCONF("gmd", "sflash", none, tristate),
+ TEGRA_MAP_MUXCONF("lpw0", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lpw2", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lsc1", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lsck", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lsda", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("slxc", "sdio3", none, driven),
+ TEGRA_MAP_MUXCONF("spia", "gmi", none, tristate),
+ TEGRA_MAP_MUXCONF("spic", "gmi", none, tristate),
+ TEGRA_MAP_MUXCONF("spig", "spi2_alt", none, tristate),
};
static struct tegra_board_pinmux_conf common_conf = {
- .pgs = common_pinmux,
- .pg_count = ARRAY_SIZE(common_pinmux),
- .gpios = common_gpio_table,
- .gpio_count = ARRAY_SIZE(common_gpio_table),
+ .maps = common_map,
+ .map_count = ARRAY_SIZE(common_map),
};
static struct tegra_board_pinmux_conf seaboard_conf = {
- .pgs = seaboard_pinmux,
- .pg_count = ARRAY_SIZE(seaboard_pinmux),
- .drives = seaboard_drive_pinmux,
- .drive_count = ARRAY_SIZE(seaboard_drive_pinmux),
- .gpios = seaboard_gpio_table,
- .gpio_count = ARRAY_SIZE(seaboard_gpio_table),
+ .maps = seaboard_map,
+ .map_count = ARRAY_SIZE(seaboard_map),
};
static struct tegra_board_pinmux_conf ventana_conf = {
- .pgs = ventana_pinmux,
- .pg_count = ARRAY_SIZE(ventana_pinmux),
- .gpios = ventana_gpio_table,
- .gpio_count = ARRAY_SIZE(ventana_gpio_table),
+ .maps = ventana_map,
+ .map_count = ARRAY_SIZE(ventana_map),
};
void seaboard_pinmux_init(void)
diff --git a/arch/arm/mach-tegra/board-seaboard.c b/arch/arm/mach-tegra/board-seaboard.c
index d669847f0485..79064c7a7907 100644
--- a/arch/arm/mach-tegra/board-seaboard.c
+++ b/arch/arm/mach-tegra/board-seaboard.c
@@ -18,12 +18,14 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
+#include <linux/of_serial.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/gpio_keys.h>
+#include <linux/platform_data/tegra_usb.h>
#include <sound/wm8903.h>
@@ -47,6 +49,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
/* Memory and IRQ filled in before registration */
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
.type = PORT_TEGRA,
+ .handle_break = tegra_serial_handle_break,
.iotype = UPIO_MEM,
.regshift = 2,
.uartclk = 216000000,
@@ -153,7 +156,6 @@ static struct platform_device *seaboard_devices[] __initdata = {
&seaboard_gpio_keys_device,
&tegra_i2s_device1,
&tegra_das_device,
- &tegra_pcm_device,
&seaboard_audio_device,
};
@@ -186,20 +188,10 @@ static struct i2c_board_info __initdata wm8903_device = {
static int seaboard_ehci_init(void)
{
- int gpio_status;
+ struct tegra_ehci_platform_data *pdata;
- gpio_status = gpio_request(TEGRA_GPIO_USB1, "VBUS_USB1");
- if (gpio_status < 0) {
- pr_err("VBUS_USB1 request GPIO FAILED\n");
- WARN_ON(1);
- }
-
- gpio_status = gpio_direction_output(TEGRA_GPIO_USB1, 1);
- if (gpio_status < 0) {
- pr_err("VBUS_USB1 request GPIO DIRECTION FAILED\n");
- WARN_ON(1);
- }
- gpio_set_value(TEGRA_GPIO_USB1, 1);
+ pdata = tegra_ehci1_device.dev.platform_data;
+ pdata->vbus_gpio = TEGRA_GPIO_USB1;
platform_device_register(&tegra_ehci1_device);
platform_device_register(&tegra_ehci3_device);
@@ -209,9 +201,6 @@ static int seaboard_ehci_init(void)
static void __init seaboard_i2c_init(void)
{
- gpio_request(TEGRA_GPIO_ISL29018_IRQ, "isl29018");
- gpio_direction_input(TEGRA_GPIO_ISL29018_IRQ);
-
isl29018_device.irq = gpio_to_irq(TEGRA_GPIO_ISL29018_IRQ);
i2c_register_board_info(0, &isl29018_device, 1);
@@ -261,7 +250,6 @@ static void __init tegra_kaen_init(void)
debug_uart_platform_data[0].irq = INT_UARTB;
seaboard_audio_pdata.gpio_hp_mute = TEGRA_GPIO_KAEN_HP_MUTE;
- tegra_gpio_enable(TEGRA_GPIO_KAEN_HP_MUTE);
seaboard_common_init();
diff --git a/arch/arm/mach-tegra/board-trimslice-pinmux.c b/arch/arm/mach-tegra/board-trimslice-pinmux.c
index a21a2be57cb6..7b39511c0d4d 100644
--- a/arch/arm/mach-tegra/board-trimslice-pinmux.c
+++ b/arch/arm/mach-tegra/board-trimslice-pinmux.c
@@ -2,6 +2,7 @@
* arch/arm/mach-tegra/board-trimslice-pinmux.c
*
* Copyright (C) 2011 CompuLab, Ltd.
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -13,150 +14,139 @@
* GNU General Public License for more details.
*
*/
-#include <linux/gpio.h>
#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/of.h>
-#include <mach/pinmux.h>
-#include <mach/pinmux-tegra20.h>
-
-#include "gpio-names.h"
-#include "board-pinmux.h"
#include "board-trimslice.h"
+#include "board-pinmux.h"
-static struct tegra_pingroup_config trimslice_pinmux[] = {
- {TEGRA_PINGROUP_ATA, TEGRA_MUX_IDE, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_ATB, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_ATC, TEGRA_MUX_NAND, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_ATD, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_ATE, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_CDEV1, TEGRA_MUX_PLLA_OUT, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_CDEV2, TEGRA_MUX_PLLP_OUT4, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_CRTP, TEGRA_MUX_CRT, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_CSUS, TEGRA_MUX_VI_SENSOR_CLK, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DAP1, TEGRA_MUX_DAP1, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_DAP2, TEGRA_MUX_DAP2, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DAP3, TEGRA_MUX_DAP3, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DAP4, TEGRA_MUX_DAP4, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DDC, TEGRA_MUX_I2C2, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_DTA, TEGRA_MUX_VI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DTB, TEGRA_MUX_VI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DTC, TEGRA_MUX_VI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DTD, TEGRA_MUX_VI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DTE, TEGRA_MUX_VI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_DTF, TEGRA_MUX_I2C3, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GMA, TEGRA_MUX_SDIO4, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GMB, TEGRA_MUX_NAND, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_GMC, TEGRA_MUX_SFLASH, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GMD, TEGRA_MUX_SFLASH, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GME, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_GPU, TEGRA_MUX_UARTA, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GPU7, TEGRA_MUX_RTCK, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_GPV, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_HDINT, TEGRA_MUX_HDMI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_I2CP, TEGRA_MUX_I2C, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_IRRX, TEGRA_MUX_UARTB, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_IRTX, TEGRA_MUX_UARTB, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_KBCA, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_KBCB, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_KBCC, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_KBCD, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_KBCE, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_KBCF, TEGRA_MUX_KBC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LCSN, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LD0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD3, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD4, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD5, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD6, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD7, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD8, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD9, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD10, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD11, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD12, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD13, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD14, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD15, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD16, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LD17, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LDC, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LDI, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LHP0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LHP1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LHP2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LHS, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LM0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LM1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LPP, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LPW0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LPW1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LPW2, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LSC0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LSC1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LSCK, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LSDA, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LSDI, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LSPI, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LVP0, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_LVP1, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_LVS, TEGRA_MUX_DISPLAYA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_OWC, TEGRA_MUX_RSVD2, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_PMC, TEGRA_MUX_PWR_ON, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_PTA, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_RM, TEGRA_MUX_I2C, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SDB, TEGRA_MUX_PWM, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SDC, TEGRA_MUX_PWM, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SDD, TEGRA_MUX_PWM, TEGRA_PUPD_PULL_UP, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SDIO1, TEGRA_MUX_SDIO1, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SLXA, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SLXC, TEGRA_MUX_SDIO3, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SLXD, TEGRA_MUX_SDIO3, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SLXK, TEGRA_MUX_PCIE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_SPDI, TEGRA_MUX_SPDIF, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPDO, TEGRA_MUX_SPDIF, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIA, TEGRA_MUX_SPI2, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIB, TEGRA_MUX_SPI2, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIC, TEGRA_MUX_SPI2, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPID, TEGRA_MUX_SPI1, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIE, TEGRA_MUX_SPI1, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIF, TEGRA_MUX_SPI1, TEGRA_PUPD_PULL_DOWN, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIG, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_SPIH, TEGRA_MUX_SPI2_ALT, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_UAA, TEGRA_MUX_ULPI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_UAB, TEGRA_MUX_ULPI, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_UAC, TEGRA_MUX_RSVD2, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_UAD, TEGRA_MUX_IRDA, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_UCA, TEGRA_MUX_UARTC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_UCB, TEGRA_MUX_UARTC, TEGRA_PUPD_PULL_UP, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_UDA, TEGRA_MUX_ULPI, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
- {TEGRA_PINGROUP_CK32, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_DDRC, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_PMCA, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_PMCB, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_PMCC, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_PMCD, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_PMCE, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_XM2C, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
- {TEGRA_PINGROUP_XM2D, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
-};
-
-static struct tegra_gpio_table gpio_table[] = {
- { .gpio = TRIMSLICE_GPIO_SD4_CD, .enable = true }, /* mmc4 cd */
- { .gpio = TRIMSLICE_GPIO_SD4_WP, .enable = true }, /* mmc4 wp */
-
- { .gpio = TRIMSLICE_GPIO_USB1_MODE, .enable = true }, /* USB1 mode */
- { .gpio = TRIMSLICE_GPIO_USB2_RST, .enable = true }, /* USB2 PHY rst */
+static struct pinctrl_map trimslice_map[] = {
+ TEGRA_MAP_MUXCONF("ata", "ide", none, tristate),
+ TEGRA_MAP_MUXCONF("atb", "sdio4", none, driven),
+ TEGRA_MAP_MUXCONF("atc", "nand", none, tristate),
+ TEGRA_MAP_MUXCONF("atd", "gmi", none, tristate),
+ TEGRA_MAP_MUXCONF("ate", "gmi", none, tristate),
+ TEGRA_MAP_MUXCONF("cdev1", "plla_out", none, driven),
+ TEGRA_MAP_MUXCONF("cdev2", "pllp_out4", down, tristate),
+ TEGRA_MAP_MUXCONF("crtp", "crt", none, tristate),
+ TEGRA_MAP_MUXCONF("csus", "vi_sensor_clk", down, tristate),
+ TEGRA_MAP_MUXCONF("dap1", "dap1", none, driven),
+ TEGRA_MAP_MUXCONF("dap2", "dap2", none, tristate),
+ TEGRA_MAP_MUXCONF("dap3", "dap3", none, tristate),
+ TEGRA_MAP_MUXCONF("dap4", "dap4", none, tristate),
+ TEGRA_MAP_MUXCONF("ddc", "i2c2", up, driven),
+ TEGRA_MAP_MUXCONF("dta", "vi", none, tristate),
+ TEGRA_MAP_MUXCONF("dtb", "vi", none, tristate),
+ TEGRA_MAP_MUXCONF("dtc", "vi", none, tristate),
+ TEGRA_MAP_MUXCONF("dtd", "vi", none, tristate),
+ TEGRA_MAP_MUXCONF("dte", "vi", none, tristate),
+ TEGRA_MAP_MUXCONF("dtf", "i2c3", up, driven),
+ TEGRA_MAP_MUXCONF("gma", "sdio4", none, driven),
+ TEGRA_MAP_MUXCONF("gmb", "nand", none, tristate),
+ TEGRA_MAP_MUXCONF("gmc", "sflash", none, driven),
+ TEGRA_MAP_MUXCONF("gmd", "sflash", none, driven),
+ TEGRA_MAP_MUXCONF("gme", "gmi", none, tristate),
+ TEGRA_MAP_MUXCONF("gpu", "uarta", none, driven),
+ TEGRA_MAP_MUXCONF("gpu7", "rtck", none, driven),
+ TEGRA_MAP_MUXCONF("gpv", "pcie", none, driven),
+ TEGRA_MAP_MUXCONF("hdint", "hdmi", na, tristate),
+ TEGRA_MAP_MUXCONF("i2cp", "i2cp", none, tristate),
+ TEGRA_MAP_MUXCONF("irrx", "uartb", up, tristate),
+ TEGRA_MAP_MUXCONF("irtx", "uartb", up, tristate),
+ TEGRA_MAP_MUXCONF("kbca", "kbc", up, tristate),
+ TEGRA_MAP_MUXCONF("kbcb", "kbc", up, tristate),
+ TEGRA_MAP_MUXCONF("kbcc", "kbc", up, tristate),
+ TEGRA_MAP_MUXCONF("kbcd", "kbc", up, tristate),
+ TEGRA_MAP_MUXCONF("kbce", "kbc", up, tristate),
+ TEGRA_MAP_MUXCONF("kbcf", "kbc", up, tristate),
+ TEGRA_MAP_MUXCONF("lcsn", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("ld0", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld1", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld10", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld11", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld12", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld13", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld14", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld15", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld16", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld17", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld2", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld3", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld4", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld5", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld6", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld7", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld8", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ld9", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("ldc", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("ldi", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lhp0", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lhp1", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lhp2", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lhs", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lm0", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lm1", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lpp", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lpw0", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lpw1", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lpw2", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lsc0", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lsc1", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lsck", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lsda", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lsdi", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lspi", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lvp0", "displaya", na, tristate),
+ TEGRA_MAP_MUXCONF("lvp1", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("lvs", "displaya", na, driven),
+ TEGRA_MAP_MUXCONF("owc", "rsvd2", up, tristate),
+ TEGRA_MAP_MUXCONF("pmc", "pwr_on", na, tristate),
+ TEGRA_MAP_MUXCONF("pta", "gmi", none, tristate),
+ TEGRA_MAP_MUXCONF("rm", "i2c1", up, driven),
+ TEGRA_MAP_MUXCONF("sdb", "pwm", na, driven),
+ TEGRA_MAP_MUXCONF("sdc", "pwm", up, driven),
+ TEGRA_MAP_MUXCONF("sdd", "pwm", up, driven),
+ TEGRA_MAP_MUXCONF("sdio1", "sdio1", none, driven),
+ TEGRA_MAP_MUXCONF("slxa", "pcie", none, driven),
+ TEGRA_MAP_MUXCONF("slxc", "sdio3", none, tristate),
+ TEGRA_MAP_MUXCONF("slxd", "sdio3", none, tristate),
+ TEGRA_MAP_MUXCONF("slxk", "pcie", none, driven),
+ TEGRA_MAP_MUXCONF("spdi", "spdif", none, tristate),
+ TEGRA_MAP_MUXCONF("spdo", "spdif", none, tristate),
+ TEGRA_MAP_MUXCONF("spia", "spi2", down, tristate),
+ TEGRA_MAP_MUXCONF("spib", "spi2", down, tristate),
+ TEGRA_MAP_MUXCONF("spic", "spi2", up, tristate),
+ TEGRA_MAP_MUXCONF("spid", "spi1", down, tristate),
+ TEGRA_MAP_MUXCONF("spie", "spi1", up, tristate),
+ TEGRA_MAP_MUXCONF("spif", "spi1", down, tristate),
+ TEGRA_MAP_MUXCONF("spig", "spi2_alt", up, tristate),
+ TEGRA_MAP_MUXCONF("spih", "spi2_alt", up, tristate),
+ TEGRA_MAP_MUXCONF("uaa", "ulpi", up, tristate),
+ TEGRA_MAP_MUXCONF("uab", "ulpi", up, tristate),
+ TEGRA_MAP_MUXCONF("uac", "rsvd2", none, driven),
+ TEGRA_MAP_MUXCONF("uad", "irda", up, tristate),
+ TEGRA_MAP_MUXCONF("uca", "uartc", up, tristate),
+ TEGRA_MAP_MUXCONF("ucb", "uartc", up, tristate),
+ TEGRA_MAP_MUXCONF("uda", "ulpi", none, tristate),
+ TEGRA_MAP_CONF("ck32", none, na),
+ TEGRA_MAP_CONF("ddrc", none, na),
+ TEGRA_MAP_CONF("pmca", none, na),
+ TEGRA_MAP_CONF("pmcb", none, na),
+ TEGRA_MAP_CONF("pmcc", none, na),
+ TEGRA_MAP_CONF("pmcd", none, na),
+ TEGRA_MAP_CONF("pmce", none, na),
+ TEGRA_MAP_CONF("xm2c", none, na),
+ TEGRA_MAP_CONF("xm2d", none, na),
+ TEGRA_MAP_CONF("ls", up, na),
+ TEGRA_MAP_CONF("lc", up, na),
+ TEGRA_MAP_CONF("ld17_0", down, na),
+ TEGRA_MAP_CONF("ld19_18", down, na),
+ TEGRA_MAP_CONF("ld21_20", down, na),
+ TEGRA_MAP_CONF("ld23_22", down, na),
};
static struct tegra_board_pinmux_conf conf = {
- .pgs = trimslice_pinmux,
- .pg_count = ARRAY_SIZE(trimslice_pinmux),
- .gpios = gpio_table,
- .gpio_count = ARRAY_SIZE(gpio_table),
+ .maps = trimslice_map,
+ .map_count = ARRAY_SIZE(trimslice_map),
};
void trimslice_pinmux_init(void)
diff --git a/arch/arm/mach-tegra/board-trimslice.c b/arch/arm/mach-tegra/board-trimslice.c
index cd52820a3e37..bc59b379c6fe 100644
--- a/arch/arm/mach-tegra/board-trimslice.c
+++ b/arch/arm/mach-tegra/board-trimslice.c
@@ -22,9 +22,11 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
+#include <linux/of_serial.h>
#include <linux/io.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
+#include <linux/platform_data/tegra_usb.h>
#include <asm/hardware/gic.h>
#include <asm/mach-types.h>
@@ -48,6 +50,7 @@ static struct plat_serial8250_port debug_uart_platform_data[] = {
.irq = INT_UARTA,
.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
.type = PORT_TEGRA,
+ .handle_break = tegra_serial_handle_break,
.iotype = UPIO_MEM,
.regshift = 2,
.uartclk = 216000000,
@@ -86,7 +89,6 @@ static struct platform_device *trimslice_devices[] __initdata = {
&tegra_sdhci_device4,
&tegra_i2s_device1,
&tegra_das_device,
- &tegra_pcm_device,
&trimslice_audio_device,
};
@@ -111,19 +113,13 @@ static void trimslice_i2c_init(void)
static void trimslice_usb_init(void)
{
- int err;
+ struct tegra_ehci_platform_data *pdata;
- platform_device_register(&tegra_ehci3_device);
+ pdata = tegra_ehci1_device.dev.platform_data;
+ pdata->vbus_gpio = TRIMSLICE_GPIO_USB1_MODE;
+ platform_device_register(&tegra_ehci3_device);
platform_device_register(&tegra_ehci2_device);
-
- err = gpio_request_one(TRIMSLICE_GPIO_USB1_MODE, GPIOF_OUT_INIT_HIGH,
- "usb1mode");
- if (err) {
- pr_err("TrimSlice: failed to obtain USB1 mode gpio: %d\n", err);
- return;
- }
-
platform_device_register(&tegra_ehci1_device);
}
diff --git a/arch/arm/mach-tegra/devices.c b/arch/arm/mach-tegra/devices.c
index 5f6b867e20b4..2d8dfa2faf8f 100644
--- a/arch/arm/mach-tegra/devices.c
+++ b/arch/arm/mach-tegra/devices.c
@@ -110,7 +110,7 @@ static struct resource pinmux_resource[] = {
};
struct platform_device tegra_pinmux_device = {
- .name = "tegra-pinmux",
+ .name = "tegra20-pinctrl",
.id = -1,
.resource = pinmux_resource,
.num_resources = ARRAY_SIZE(pinmux_resource),
@@ -448,17 +448,20 @@ static struct tegra_ulpi_config tegra_ehci2_ulpi_phy_config = {
struct tegra_ehci_platform_data tegra_ehci1_pdata = {
.operating_mode = TEGRA_USB_OTG,
.power_down_on_bus_suspend = 1,
+ .vbus_gpio = -1,
};
struct tegra_ehci_platform_data tegra_ehci2_pdata = {
.phy_config = &tegra_ehci2_ulpi_phy_config,
.operating_mode = TEGRA_USB_HOST,
.power_down_on_bus_suspend = 1,
+ .vbus_gpio = -1,
};
struct tegra_ehci_platform_data tegra_ehci3_pdata = {
.operating_mode = TEGRA_USB_HOST,
.power_down_on_bus_suspend = 1,
+ .vbus_gpio = -1,
};
static u64 tegra_ehci_dmamask = DMA_BIT_MASK(32);
@@ -671,14 +674,14 @@ static struct resource i2s_resource2[] = {
};
struct platform_device tegra_i2s_device1 = {
- .name = "tegra-i2s",
+ .name = "tegra20-i2s",
.id = 0,
.resource = i2s_resource1,
.num_resources = ARRAY_SIZE(i2s_resource1),
};
struct platform_device tegra_i2s_device2 = {
- .name = "tegra-i2s",
+ .name = "tegra20-i2s",
.id = 1,
.resource = i2s_resource2,
.num_resources = ARRAY_SIZE(i2s_resource2),
@@ -693,13 +696,8 @@ static struct resource tegra_das_resources[] = {
};
struct platform_device tegra_das_device = {
- .name = "tegra-das",
+ .name = "tegra20-das",
.id = -1,
.num_resources = ARRAY_SIZE(tegra_das_resources),
.resource = tegra_das_resources,
};
-
-struct platform_device tegra_pcm_device = {
- .name = "tegra-pcm-audio",
- .id = -1,
-};
diff --git a/arch/arm/mach-tegra/devices.h b/arch/arm/mach-tegra/devices.h
index ec455679b219..138c642e59f4 100644
--- a/arch/arm/mach-tegra/devices.h
+++ b/arch/arm/mach-tegra/devices.h
@@ -52,6 +52,5 @@ extern struct platform_device tegra_pmu_device;
extern struct platform_device tegra_i2s_device1;
extern struct platform_device tegra_i2s_device2;
extern struct platform_device tegra_das_device;
-extern struct platform_device tegra_pcm_device;
#endif
diff --git a/arch/arm/mach-tegra/include/mach/dma.h b/arch/arm/mach-tegra/include/mach/dma.h
index 3c9339058bec..9077092812c0 100644
--- a/arch/arm/mach-tegra/include/mach/dma.h
+++ b/arch/arm/mach-tegra/include/mach/dma.h
@@ -51,8 +51,6 @@
#define TEGRA_DMA_REQ_SEL_OWR 25
#define TEGRA_DMA_REQ_SEL_INVALID 31
-#if defined(CONFIG_TEGRA_SYSTEM_DMA)
-
struct tegra_dma_req;
struct tegra_dma_channel;
@@ -151,5 +149,3 @@ void tegra_dma_free_channel(struct tegra_dma_channel *ch);
int __init tegra_dma_init(void);
#endif
-
-#endif
diff --git a/arch/arm/mach-tegra/include/mach/gpio-tegra.h b/arch/arm/mach-tegra/include/mach/gpio-tegra.h
index 6140820555e1..a978b3cc3a8d 100644
--- a/arch/arm/mach-tegra/include/mach/gpio-tegra.h
+++ b/arch/arm/mach-tegra/include/mach/gpio-tegra.h
@@ -25,13 +25,4 @@
#define TEGRA_NR_GPIOS INT_GPIO_NR
-struct tegra_gpio_table {
- int gpio; /* GPIO number */
- bool enable; /* Enable for GPIO at init? */
-};
-
-void tegra_gpio_config(struct tegra_gpio_table *table, int num);
-void tegra_gpio_enable(int gpio);
-void tegra_gpio_disable(int gpio);
-
#endif
diff --git a/arch/arm/mach-tegra/include/mach/pinmux-tegra20.h b/arch/arm/mach-tegra/include/mach/pinmux-tegra20.h
deleted file mode 100644
index 6a40c1dbab17..000000000000
--- a/arch/arm/mach-tegra/include/mach/pinmux-tegra20.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * linux/arch/arm/mach-tegra/include/mach/pinmux-tegra20.h
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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 __MACH_TEGRA_PINMUX_TEGRA20_H
-#define __MACH_TEGRA_PINMUX_TEGRA20_H
-
-enum tegra_pingroup {
- TEGRA_PINGROUP_ATA = 0,
- TEGRA_PINGROUP_ATB,
- TEGRA_PINGROUP_ATC,
- TEGRA_PINGROUP_ATD,
- TEGRA_PINGROUP_ATE,
- TEGRA_PINGROUP_CDEV1,
- TEGRA_PINGROUP_CDEV2,
- TEGRA_PINGROUP_CRTP,
- TEGRA_PINGROUP_CSUS,
- TEGRA_PINGROUP_DAP1,
- TEGRA_PINGROUP_DAP2,
- TEGRA_PINGROUP_DAP3,
- TEGRA_PINGROUP_DAP4,
- TEGRA_PINGROUP_DDC,
- TEGRA_PINGROUP_DTA,
- TEGRA_PINGROUP_DTB,
- TEGRA_PINGROUP_DTC,
- TEGRA_PINGROUP_DTD,
- TEGRA_PINGROUP_DTE,
- TEGRA_PINGROUP_DTF,
- TEGRA_PINGROUP_GMA,
- TEGRA_PINGROUP_GMB,
- TEGRA_PINGROUP_GMC,
- TEGRA_PINGROUP_GMD,
- TEGRA_PINGROUP_GME,
- TEGRA_PINGROUP_GPU,
- TEGRA_PINGROUP_GPU7,
- TEGRA_PINGROUP_GPV,
- TEGRA_PINGROUP_HDINT,
- TEGRA_PINGROUP_I2CP,
- TEGRA_PINGROUP_IRRX,
- TEGRA_PINGROUP_IRTX,
- TEGRA_PINGROUP_KBCA,
- TEGRA_PINGROUP_KBCB,
- TEGRA_PINGROUP_KBCC,
- TEGRA_PINGROUP_KBCD,
- TEGRA_PINGROUP_KBCE,
- TEGRA_PINGROUP_KBCF,
- TEGRA_PINGROUP_LCSN,
- TEGRA_PINGROUP_LD0,
- TEGRA_PINGROUP_LD1,
- TEGRA_PINGROUP_LD10,
- TEGRA_PINGROUP_LD11,
- TEGRA_PINGROUP_LD12,
- TEGRA_PINGROUP_LD13,
- TEGRA_PINGROUP_LD14,
- TEGRA_PINGROUP_LD15,
- TEGRA_PINGROUP_LD16,
- TEGRA_PINGROUP_LD17,
- TEGRA_PINGROUP_LD2,
- TEGRA_PINGROUP_LD3,
- TEGRA_PINGROUP_LD4,
- TEGRA_PINGROUP_LD5,
- TEGRA_PINGROUP_LD6,
- TEGRA_PINGROUP_LD7,
- TEGRA_PINGROUP_LD8,
- TEGRA_PINGROUP_LD9,
- TEGRA_PINGROUP_LDC,
- TEGRA_PINGROUP_LDI,
- TEGRA_PINGROUP_LHP0,
- TEGRA_PINGROUP_LHP1,
- TEGRA_PINGROUP_LHP2,
- TEGRA_PINGROUP_LHS,
- TEGRA_PINGROUP_LM0,
- TEGRA_PINGROUP_LM1,
- TEGRA_PINGROUP_LPP,
- TEGRA_PINGROUP_LPW0,
- TEGRA_PINGROUP_LPW1,
- TEGRA_PINGROUP_LPW2,
- TEGRA_PINGROUP_LSC0,
- TEGRA_PINGROUP_LSC1,
- TEGRA_PINGROUP_LSCK,
- TEGRA_PINGROUP_LSDA,
- TEGRA_PINGROUP_LSDI,
- TEGRA_PINGROUP_LSPI,
- TEGRA_PINGROUP_LVP0,
- TEGRA_PINGROUP_LVP1,
- TEGRA_PINGROUP_LVS,
- TEGRA_PINGROUP_OWC,
- TEGRA_PINGROUP_PMC,
- TEGRA_PINGROUP_PTA,
- TEGRA_PINGROUP_RM,
- TEGRA_PINGROUP_SDB,
- TEGRA_PINGROUP_SDC,
- TEGRA_PINGROUP_SDD,
- TEGRA_PINGROUP_SDIO1,
- TEGRA_PINGROUP_SLXA,
- TEGRA_PINGROUP_SLXC,
- TEGRA_PINGROUP_SLXD,
- TEGRA_PINGROUP_SLXK,
- TEGRA_PINGROUP_SPDI,
- TEGRA_PINGROUP_SPDO,
- TEGRA_PINGROUP_SPIA,
- TEGRA_PINGROUP_SPIB,
- TEGRA_PINGROUP_SPIC,
- TEGRA_PINGROUP_SPID,
- TEGRA_PINGROUP_SPIE,
- TEGRA_PINGROUP_SPIF,
- TEGRA_PINGROUP_SPIG,
- TEGRA_PINGROUP_SPIH,
- TEGRA_PINGROUP_UAA,
- TEGRA_PINGROUP_UAB,
- TEGRA_PINGROUP_UAC,
- TEGRA_PINGROUP_UAD,
- TEGRA_PINGROUP_UCA,
- TEGRA_PINGROUP_UCB,
- TEGRA_PINGROUP_UDA,
- /* these pin groups only have pullup and pull down control */
- TEGRA_PINGROUP_CK32,
- TEGRA_PINGROUP_DDRC,
- TEGRA_PINGROUP_PMCA,
- TEGRA_PINGROUP_PMCB,
- TEGRA_PINGROUP_PMCC,
- TEGRA_PINGROUP_PMCD,
- TEGRA_PINGROUP_PMCE,
- TEGRA_PINGROUP_XM2C,
- TEGRA_PINGROUP_XM2D,
- TEGRA_MAX_PINGROUP,
-};
-
-enum tegra_drive_pingroup {
- TEGRA_DRIVE_PINGROUP_AO1 = 0,
- TEGRA_DRIVE_PINGROUP_AO2,
- TEGRA_DRIVE_PINGROUP_AT1,
- TEGRA_DRIVE_PINGROUP_AT2,
- TEGRA_DRIVE_PINGROUP_CDEV1,
- TEGRA_DRIVE_PINGROUP_CDEV2,
- TEGRA_DRIVE_PINGROUP_CSUS,
- TEGRA_DRIVE_PINGROUP_DAP1,
- TEGRA_DRIVE_PINGROUP_DAP2,
- TEGRA_DRIVE_PINGROUP_DAP3,
- TEGRA_DRIVE_PINGROUP_DAP4,
- TEGRA_DRIVE_PINGROUP_DBG,
- TEGRA_DRIVE_PINGROUP_LCD1,
- TEGRA_DRIVE_PINGROUP_LCD2,
- TEGRA_DRIVE_PINGROUP_SDMMC2,
- TEGRA_DRIVE_PINGROUP_SDMMC3,
- TEGRA_DRIVE_PINGROUP_SPI,
- TEGRA_DRIVE_PINGROUP_UAA,
- TEGRA_DRIVE_PINGROUP_UAB,
- TEGRA_DRIVE_PINGROUP_UART2,
- TEGRA_DRIVE_PINGROUP_UART3,
- TEGRA_DRIVE_PINGROUP_VI1,
- TEGRA_DRIVE_PINGROUP_VI2,
- TEGRA_DRIVE_PINGROUP_XM2A,
- TEGRA_DRIVE_PINGROUP_XM2C,
- TEGRA_DRIVE_PINGROUP_XM2D,
- TEGRA_DRIVE_PINGROUP_XM2CLK,
- TEGRA_DRIVE_PINGROUP_MEMCOMP,
- TEGRA_DRIVE_PINGROUP_SDIO1,
- TEGRA_DRIVE_PINGROUP_CRT,
- TEGRA_DRIVE_PINGROUP_DDC,
- TEGRA_DRIVE_PINGROUP_GMA,
- TEGRA_DRIVE_PINGROUP_GMB,
- TEGRA_DRIVE_PINGROUP_GMC,
- TEGRA_DRIVE_PINGROUP_GMD,
- TEGRA_DRIVE_PINGROUP_GME,
- TEGRA_DRIVE_PINGROUP_OWR,
- TEGRA_DRIVE_PINGROUP_UAD,
- TEGRA_MAX_DRIVE_PINGROUP,
-};
-
-#endif
-
diff --git a/arch/arm/mach-tegra/include/mach/pinmux-tegra30.h b/arch/arm/mach-tegra/include/mach/pinmux-tegra30.h
deleted file mode 100644
index c1aee3eb2df1..000000000000
--- a/arch/arm/mach-tegra/include/mach/pinmux-tegra30.h
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * linux/arch/arm/mach-tegra/include/mach/pinmux-tegra30.h
- *
- * Copyright (C) 2010 Google, Inc.
- * Copyright (C) 2010,2011 Nvidia, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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 __MACH_TEGRA_PINMUX_TEGRA30_H
-#define __MACH_TEGRA_PINMUX_TEGRA30_H
-
-enum tegra_pingroup {
- TEGRA_PINGROUP_ULPI_DATA0 = 0,
- TEGRA_PINGROUP_ULPI_DATA1,
- TEGRA_PINGROUP_ULPI_DATA2,
- TEGRA_PINGROUP_ULPI_DATA3,
- TEGRA_PINGROUP_ULPI_DATA4,
- TEGRA_PINGROUP_ULPI_DATA5,
- TEGRA_PINGROUP_ULPI_DATA6,
- TEGRA_PINGROUP_ULPI_DATA7,
- TEGRA_PINGROUP_ULPI_CLK,
- TEGRA_PINGROUP_ULPI_DIR,
- TEGRA_PINGROUP_ULPI_NXT,
- TEGRA_PINGROUP_ULPI_STP,
- TEGRA_PINGROUP_DAP3_FS,
- TEGRA_PINGROUP_DAP3_DIN,
- TEGRA_PINGROUP_DAP3_DOUT,
- TEGRA_PINGROUP_DAP3_SCLK,
- TEGRA_PINGROUP_GPIO_PV0,
- TEGRA_PINGROUP_GPIO_PV1,
- TEGRA_PINGROUP_SDMMC1_CLK,
- TEGRA_PINGROUP_SDMMC1_CMD,
- TEGRA_PINGROUP_SDMMC1_DAT3,
- TEGRA_PINGROUP_SDMMC1_DAT2,
- TEGRA_PINGROUP_SDMMC1_DAT1,
- TEGRA_PINGROUP_SDMMC1_DAT0,
- TEGRA_PINGROUP_GPIO_PV2,
- TEGRA_PINGROUP_GPIO_PV3,
- TEGRA_PINGROUP_CLK2_OUT,
- TEGRA_PINGROUP_CLK2_REQ,
- TEGRA_PINGROUP_LCD_PWR1,
- TEGRA_PINGROUP_LCD_PWR2,
- TEGRA_PINGROUP_LCD_SDIN,
- TEGRA_PINGROUP_LCD_SDOUT,
- TEGRA_PINGROUP_LCD_WR_N,
- TEGRA_PINGROUP_LCD_CS0_N,
- TEGRA_PINGROUP_LCD_DC0,
- TEGRA_PINGROUP_LCD_SCK,
- TEGRA_PINGROUP_LCD_PWR0,
- TEGRA_PINGROUP_LCD_PCLK,
- TEGRA_PINGROUP_LCD_DE,
- TEGRA_PINGROUP_LCD_HSYNC,
- TEGRA_PINGROUP_LCD_VSYNC,
- TEGRA_PINGROUP_LCD_D0,
- TEGRA_PINGROUP_LCD_D1,
- TEGRA_PINGROUP_LCD_D2,
- TEGRA_PINGROUP_LCD_D3,
- TEGRA_PINGROUP_LCD_D4,
- TEGRA_PINGROUP_LCD_D5,
- TEGRA_PINGROUP_LCD_D6,
- TEGRA_PINGROUP_LCD_D7,
- TEGRA_PINGROUP_LCD_D8,
- TEGRA_PINGROUP_LCD_D9,
- TEGRA_PINGROUP_LCD_D10,
- TEGRA_PINGROUP_LCD_D11,
- TEGRA_PINGROUP_LCD_D12,
- TEGRA_PINGROUP_LCD_D13,
- TEGRA_PINGROUP_LCD_D14,
- TEGRA_PINGROUP_LCD_D15,
- TEGRA_PINGROUP_LCD_D16,
- TEGRA_PINGROUP_LCD_D17,
- TEGRA_PINGROUP_LCD_D18,
- TEGRA_PINGROUP_LCD_D19,
- TEGRA_PINGROUP_LCD_D20,
- TEGRA_PINGROUP_LCD_D21,
- TEGRA_PINGROUP_LCD_D22,
- TEGRA_PINGROUP_LCD_D23,
- TEGRA_PINGROUP_LCD_CS1_N,
- TEGRA_PINGROUP_LCD_M1,
- TEGRA_PINGROUP_LCD_DC1,
- TEGRA_PINGROUP_HDMI_INT,
- TEGRA_PINGROUP_DDC_SCL,
- TEGRA_PINGROUP_DDC_SDA,
- TEGRA_PINGROUP_CRT_HSYNC,
- TEGRA_PINGROUP_CRT_VSYNC,
- TEGRA_PINGROUP_VI_D0,
- TEGRA_PINGROUP_VI_D1,
- TEGRA_PINGROUP_VI_D2,
- TEGRA_PINGROUP_VI_D3,
- TEGRA_PINGROUP_VI_D4,
- TEGRA_PINGROUP_VI_D5,
- TEGRA_PINGROUP_VI_D6,
- TEGRA_PINGROUP_VI_D7,
- TEGRA_PINGROUP_VI_D8,
- TEGRA_PINGROUP_VI_D9,
- TEGRA_PINGROUP_VI_D10,
- TEGRA_PINGROUP_VI_D11,
- TEGRA_PINGROUP_VI_PCLK,
- TEGRA_PINGROUP_VI_MCLK,
- TEGRA_PINGROUP_VI_VSYNC,
- TEGRA_PINGROUP_VI_HSYNC,
- TEGRA_PINGROUP_UART2_RXD,
- TEGRA_PINGROUP_UART2_TXD,
- TEGRA_PINGROUP_UART2_RTS_N,
- TEGRA_PINGROUP_UART2_CTS_N,
- TEGRA_PINGROUP_UART3_TXD,
- TEGRA_PINGROUP_UART3_RXD,
- TEGRA_PINGROUP_UART3_CTS_N,
- TEGRA_PINGROUP_UART3_RTS_N,
- TEGRA_PINGROUP_GPIO_PU0,
- TEGRA_PINGROUP_GPIO_PU1,
- TEGRA_PINGROUP_GPIO_PU2,
- TEGRA_PINGROUP_GPIO_PU3,
- TEGRA_PINGROUP_GPIO_PU4,
- TEGRA_PINGROUP_GPIO_PU5,
- TEGRA_PINGROUP_GPIO_PU6,
- TEGRA_PINGROUP_GEN1_I2C_SDA,
- TEGRA_PINGROUP_GEN1_I2C_SCL,
- TEGRA_PINGROUP_DAP4_FS,
- TEGRA_PINGROUP_DAP4_DIN,
- TEGRA_PINGROUP_DAP4_DOUT,
- TEGRA_PINGROUP_DAP4_SCLK,
- TEGRA_PINGROUP_CLK3_OUT,
- TEGRA_PINGROUP_CLK3_REQ,
- TEGRA_PINGROUP_GMI_WP_N,
- TEGRA_PINGROUP_GMI_IORDY,
- TEGRA_PINGROUP_GMI_WAIT,
- TEGRA_PINGROUP_GMI_ADV_N,
- TEGRA_PINGROUP_GMI_CLK,
- TEGRA_PINGROUP_GMI_CS0_N,
- TEGRA_PINGROUP_GMI_CS1_N,
- TEGRA_PINGROUP_GMI_CS2_N,
- TEGRA_PINGROUP_GMI_CS3_N,
- TEGRA_PINGROUP_GMI_CS4_N,
- TEGRA_PINGROUP_GMI_CS6_N,
- TEGRA_PINGROUP_GMI_CS7_N,
- TEGRA_PINGROUP_GMI_AD0,
- TEGRA_PINGROUP_GMI_AD1,
- TEGRA_PINGROUP_GMI_AD2,
- TEGRA_PINGROUP_GMI_AD3,
- TEGRA_PINGROUP_GMI_AD4,
- TEGRA_PINGROUP_GMI_AD5,
- TEGRA_PINGROUP_GMI_AD6,
- TEGRA_PINGROUP_GMI_AD7,
- TEGRA_PINGROUP_GMI_AD8,
- TEGRA_PINGROUP_GMI_AD9,
- TEGRA_PINGROUP_GMI_AD10,
- TEGRA_PINGROUP_GMI_AD11,
- TEGRA_PINGROUP_GMI_AD12,
- TEGRA_PINGROUP_GMI_AD13,
- TEGRA_PINGROUP_GMI_AD14,
- TEGRA_PINGROUP_GMI_AD15,
- TEGRA_PINGROUP_GMI_A16,
- TEGRA_PINGROUP_GMI_A17,
- TEGRA_PINGROUP_GMI_A18,
- TEGRA_PINGROUP_GMI_A19,
- TEGRA_PINGROUP_GMI_WR_N,
- TEGRA_PINGROUP_GMI_OE_N,
- TEGRA_PINGROUP_GMI_DQS,
- TEGRA_PINGROUP_GMI_RST_N,
- TEGRA_PINGROUP_GEN2_I2C_SCL,
- TEGRA_PINGROUP_GEN2_I2C_SDA,
- TEGRA_PINGROUP_SDMMC4_CLK,
- TEGRA_PINGROUP_SDMMC4_CMD,
- TEGRA_PINGROUP_SDMMC4_DAT0,
- TEGRA_PINGROUP_SDMMC4_DAT1,
- TEGRA_PINGROUP_SDMMC4_DAT2,
- TEGRA_PINGROUP_SDMMC4_DAT3,
- TEGRA_PINGROUP_SDMMC4_DAT4,
- TEGRA_PINGROUP_SDMMC4_DAT5,
- TEGRA_PINGROUP_SDMMC4_DAT6,
- TEGRA_PINGROUP_SDMMC4_DAT7,
- TEGRA_PINGROUP_SDMMC4_RST_N,
- TEGRA_PINGROUP_CAM_MCLK,
- TEGRA_PINGROUP_GPIO_PCC1,
- TEGRA_PINGROUP_GPIO_PBB0,
- TEGRA_PINGROUP_CAM_I2C_SCL,
- TEGRA_PINGROUP_CAM_I2C_SDA,
- TEGRA_PINGROUP_GPIO_PBB3,
- TEGRA_PINGROUP_GPIO_PBB4,
- TEGRA_PINGROUP_GPIO_PBB5,
- TEGRA_PINGROUP_GPIO_PBB6,
- TEGRA_PINGROUP_GPIO_PBB7,
- TEGRA_PINGROUP_GPIO_PCC2,
- TEGRA_PINGROUP_JTAG_RTCK,
- TEGRA_PINGROUP_PWR_I2C_SCL,
- TEGRA_PINGROUP_PWR_I2C_SDA,
- TEGRA_PINGROUP_KB_ROW0,
- TEGRA_PINGROUP_KB_ROW1,
- TEGRA_PINGROUP_KB_ROW2,
- TEGRA_PINGROUP_KB_ROW3,
- TEGRA_PINGROUP_KB_ROW4,
- TEGRA_PINGROUP_KB_ROW5,
- TEGRA_PINGROUP_KB_ROW6,
- TEGRA_PINGROUP_KB_ROW7,
- TEGRA_PINGROUP_KB_ROW8,
- TEGRA_PINGROUP_KB_ROW9,
- TEGRA_PINGROUP_KB_ROW10,
- TEGRA_PINGROUP_KB_ROW11,
- TEGRA_PINGROUP_KB_ROW12,
- TEGRA_PINGROUP_KB_ROW13,
- TEGRA_PINGROUP_KB_ROW14,
- TEGRA_PINGROUP_KB_ROW15,
- TEGRA_PINGROUP_KB_COL0,
- TEGRA_PINGROUP_KB_COL1,
- TEGRA_PINGROUP_KB_COL2,
- TEGRA_PINGROUP_KB_COL3,
- TEGRA_PINGROUP_KB_COL4,
- TEGRA_PINGROUP_KB_COL5,
- TEGRA_PINGROUP_KB_COL6,
- TEGRA_PINGROUP_KB_COL7,
- TEGRA_PINGROUP_CLK_32K_OUT,
- TEGRA_PINGROUP_SYS_CLK_REQ,
- TEGRA_PINGROUP_CORE_PWR_REQ,
- TEGRA_PINGROUP_CPU_PWR_REQ,
- TEGRA_PINGROUP_PWR_INT_N,
- TEGRA_PINGROUP_CLK_32K_IN,
- TEGRA_PINGROUP_OWR,
- TEGRA_PINGROUP_DAP1_FS,
- TEGRA_PINGROUP_DAP1_DIN,
- TEGRA_PINGROUP_DAP1_DOUT,
- TEGRA_PINGROUP_DAP1_SCLK,
- TEGRA_PINGROUP_CLK1_REQ,
- TEGRA_PINGROUP_CLK1_OUT,
- TEGRA_PINGROUP_SPDIF_IN,
- TEGRA_PINGROUP_SPDIF_OUT,
- TEGRA_PINGROUP_DAP2_FS,
- TEGRA_PINGROUP_DAP2_DIN,
- TEGRA_PINGROUP_DAP2_DOUT,
- TEGRA_PINGROUP_DAP2_SCLK,
- TEGRA_PINGROUP_SPI2_MOSI,
- TEGRA_PINGROUP_SPI2_MISO,
- TEGRA_PINGROUP_SPI2_CS0_N,
- TEGRA_PINGROUP_SPI2_SCK,
- TEGRA_PINGROUP_SPI1_MOSI,
- TEGRA_PINGROUP_SPI1_SCK,
- TEGRA_PINGROUP_SPI1_CS0_N,
- TEGRA_PINGROUP_SPI1_MISO,
- TEGRA_PINGROUP_SPI2_CS1_N,
- TEGRA_PINGROUP_SPI2_CS2_N,
- TEGRA_PINGROUP_SDMMC3_CLK,
- TEGRA_PINGROUP_SDMMC3_CMD,
- TEGRA_PINGROUP_SDMMC3_DAT0,
- TEGRA_PINGROUP_SDMMC3_DAT1,
- TEGRA_PINGROUP_SDMMC3_DAT2,
- TEGRA_PINGROUP_SDMMC3_DAT3,
- TEGRA_PINGROUP_SDMMC3_DAT4,
- TEGRA_PINGROUP_SDMMC3_DAT5,
- TEGRA_PINGROUP_SDMMC3_DAT6,
- TEGRA_PINGROUP_SDMMC3_DAT7,
- TEGRA_PINGROUP_PEX_L0_PRSNT_N,
- TEGRA_PINGROUP_PEX_L0_RST_N,
- TEGRA_PINGROUP_PEX_L0_CLKREQ_N,
- TEGRA_PINGROUP_PEX_WAKE_N,
- TEGRA_PINGROUP_PEX_L1_PRSNT_N,
- TEGRA_PINGROUP_PEX_L1_RST_N,
- TEGRA_PINGROUP_PEX_L1_CLKREQ_N,
- TEGRA_PINGROUP_PEX_L2_PRSNT_N,
- TEGRA_PINGROUP_PEX_L2_RST_N,
- TEGRA_PINGROUP_PEX_L2_CLKREQ_N,
- TEGRA_PINGROUP_HDMI_CEC,
- TEGRA_MAX_PINGROUP,
-};
-
-enum tegra_drive_pingroup {
- TEGRA_DRIVE_PINGROUP_AO1 = 0,
- TEGRA_DRIVE_PINGROUP_AO2,
- TEGRA_DRIVE_PINGROUP_AT1,
- TEGRA_DRIVE_PINGROUP_AT2,
- TEGRA_DRIVE_PINGROUP_AT3,
- TEGRA_DRIVE_PINGROUP_AT4,
- TEGRA_DRIVE_PINGROUP_AT5,
- TEGRA_DRIVE_PINGROUP_CDEV1,
- TEGRA_DRIVE_PINGROUP_CDEV2,
- TEGRA_DRIVE_PINGROUP_CSUS,
- TEGRA_DRIVE_PINGROUP_DAP1,
- TEGRA_DRIVE_PINGROUP_DAP2,
- TEGRA_DRIVE_PINGROUP_DAP3,
- TEGRA_DRIVE_PINGROUP_DAP4,
- TEGRA_DRIVE_PINGROUP_DBG,
- TEGRA_DRIVE_PINGROUP_LCD1,
- TEGRA_DRIVE_PINGROUP_LCD2,
- TEGRA_DRIVE_PINGROUP_SDIO2,
- TEGRA_DRIVE_PINGROUP_SDIO3,
- TEGRA_DRIVE_PINGROUP_SPI,
- TEGRA_DRIVE_PINGROUP_UAA,
- TEGRA_DRIVE_PINGROUP_UAB,
- TEGRA_DRIVE_PINGROUP_UART2,
- TEGRA_DRIVE_PINGROUP_UART3,
- TEGRA_DRIVE_PINGROUP_VI1,
- TEGRA_DRIVE_PINGROUP_SDIO1,
- TEGRA_DRIVE_PINGROUP_CRT,
- TEGRA_DRIVE_PINGROUP_DDC,
- TEGRA_DRIVE_PINGROUP_GMA,
- TEGRA_DRIVE_PINGROUP_GMB,
- TEGRA_DRIVE_PINGROUP_GMC,
- TEGRA_DRIVE_PINGROUP_GMD,
- TEGRA_DRIVE_PINGROUP_GME,
- TEGRA_DRIVE_PINGROUP_GMF,
- TEGRA_DRIVE_PINGROUP_GMG,
- TEGRA_DRIVE_PINGROUP_GMH,
- TEGRA_DRIVE_PINGROUP_OWR,
- TEGRA_DRIVE_PINGROUP_UAD,
- TEGRA_DRIVE_PINGROUP_GPV,
- TEGRA_DRIVE_PINGROUP_DEV3,
- TEGRA_DRIVE_PINGROUP_CEC,
- TEGRA_MAX_DRIVE_PINGROUP,
-};
-
-#endif
-
diff --git a/arch/arm/mach-tegra/include/mach/pinmux.h b/arch/arm/mach-tegra/include/mach/pinmux.h
deleted file mode 100644
index 055f1792c8ff..000000000000
--- a/arch/arm/mach-tegra/include/mach/pinmux.h
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * linux/arch/arm/mach-tegra/include/mach/pinmux.h
- *
- * Copyright (C) 2010 Google, Inc.
- * Copyright (C) 2010,2011 Nvidia, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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 __MACH_TEGRA_PINMUX_H
-#define __MACH_TEGRA_PINMUX_H
-
-enum tegra_mux_func {
- TEGRA_MUX_RSVD = 0x8000,
- TEGRA_MUX_RSVD1 = 0x8000,
- TEGRA_MUX_RSVD2 = 0x8001,
- TEGRA_MUX_RSVD3 = 0x8002,
- TEGRA_MUX_RSVD4 = 0x8003,
- TEGRA_MUX_INVALID = 0x4000,
- TEGRA_MUX_NONE = -1,
- TEGRA_MUX_AHB_CLK,
- TEGRA_MUX_APB_CLK,
- TEGRA_MUX_AUDIO_SYNC,
- TEGRA_MUX_CRT,
- TEGRA_MUX_DAP1,
- TEGRA_MUX_DAP2,
- TEGRA_MUX_DAP3,
- TEGRA_MUX_DAP4,
- TEGRA_MUX_DAP5,
- TEGRA_MUX_DISPLAYA,
- TEGRA_MUX_DISPLAYB,
- TEGRA_MUX_EMC_TEST0_DLL,
- TEGRA_MUX_EMC_TEST1_DLL,
- TEGRA_MUX_GMI,
- TEGRA_MUX_GMI_INT,
- TEGRA_MUX_HDMI,
- TEGRA_MUX_I2C,
- TEGRA_MUX_I2C2,
- TEGRA_MUX_I2C3,
- TEGRA_MUX_IDE,
- TEGRA_MUX_IRDA,
- TEGRA_MUX_KBC,
- TEGRA_MUX_MIO,
- TEGRA_MUX_MIPI_HS,
- TEGRA_MUX_NAND,
- TEGRA_MUX_OSC,
- TEGRA_MUX_OWR,
- TEGRA_MUX_PCIE,
- TEGRA_MUX_PLLA_OUT,
- TEGRA_MUX_PLLC_OUT1,
- TEGRA_MUX_PLLM_OUT1,
- TEGRA_MUX_PLLP_OUT2,
- TEGRA_MUX_PLLP_OUT3,
- TEGRA_MUX_PLLP_OUT4,
- TEGRA_MUX_PWM,
- TEGRA_MUX_PWR_INTR,
- TEGRA_MUX_PWR_ON,
- TEGRA_MUX_RTCK,
- TEGRA_MUX_SDIO1,
- TEGRA_MUX_SDIO2,
- TEGRA_MUX_SDIO3,
- TEGRA_MUX_SDIO4,
- TEGRA_MUX_SFLASH,
- TEGRA_MUX_SPDIF,
- TEGRA_MUX_SPI1,
- TEGRA_MUX_SPI2,
- TEGRA_MUX_SPI2_ALT,
- TEGRA_MUX_SPI3,
- TEGRA_MUX_SPI4,
- TEGRA_MUX_TRACE,
- TEGRA_MUX_TWC,
- TEGRA_MUX_UARTA,
- TEGRA_MUX_UARTB,
- TEGRA_MUX_UARTC,
- TEGRA_MUX_UARTD,
- TEGRA_MUX_UARTE,
- TEGRA_MUX_ULPI,
- TEGRA_MUX_VI,
- TEGRA_MUX_VI_SENSOR_CLK,
- TEGRA_MUX_XIO,
- TEGRA_MUX_BLINK,
- TEGRA_MUX_CEC,
- TEGRA_MUX_CLK12,
- TEGRA_MUX_DAP,
- TEGRA_MUX_DAPSDMMC2,
- TEGRA_MUX_DDR,
- TEGRA_MUX_DEV3,
- TEGRA_MUX_DTV,
- TEGRA_MUX_VI_ALT1,
- TEGRA_MUX_VI_ALT2,
- TEGRA_MUX_VI_ALT3,
- TEGRA_MUX_EMC_DLL,
- TEGRA_MUX_EXTPERIPH1,
- TEGRA_MUX_EXTPERIPH2,
- TEGRA_MUX_EXTPERIPH3,
- TEGRA_MUX_GMI_ALT,
- TEGRA_MUX_HDA,
- TEGRA_MUX_HSI,
- TEGRA_MUX_I2C4,
- TEGRA_MUX_I2C5,
- TEGRA_MUX_I2CPWR,
- TEGRA_MUX_I2S0,
- TEGRA_MUX_I2S1,
- TEGRA_MUX_I2S2,
- TEGRA_MUX_I2S3,
- TEGRA_MUX_I2S4,
- TEGRA_MUX_NAND_ALT,
- TEGRA_MUX_POPSDIO4,
- TEGRA_MUX_POPSDMMC4,
- TEGRA_MUX_PWM0,
- TEGRA_MUX_PWM1,
- TEGRA_MUX_PWM2,
- TEGRA_MUX_PWM3,
- TEGRA_MUX_SATA,
- TEGRA_MUX_SPI5,
- TEGRA_MUX_SPI6,
- TEGRA_MUX_SYSCLK,
- TEGRA_MUX_VGP1,
- TEGRA_MUX_VGP2,
- TEGRA_MUX_VGP3,
- TEGRA_MUX_VGP4,
- TEGRA_MUX_VGP5,
- TEGRA_MUX_VGP6,
- TEGRA_MUX_SAFE,
- TEGRA_MAX_MUX,
-};
-
-enum tegra_pullupdown {
- TEGRA_PUPD_NORMAL = 0,
- TEGRA_PUPD_PULL_DOWN,
- TEGRA_PUPD_PULL_UP,
-};
-
-enum tegra_tristate {
- TEGRA_TRI_NORMAL = 0,
- TEGRA_TRI_TRISTATE = 1,
-};
-
-enum tegra_pin_io {
- TEGRA_PIN_OUTPUT = 0,
- TEGRA_PIN_INPUT = 1,
-};
-
-enum tegra_vddio {
- TEGRA_VDDIO_BB = 0,
- TEGRA_VDDIO_LCD,
- TEGRA_VDDIO_VI,
- TEGRA_VDDIO_UART,
- TEGRA_VDDIO_DDR,
- TEGRA_VDDIO_NAND,
- TEGRA_VDDIO_SYS,
- TEGRA_VDDIO_AUDIO,
- TEGRA_VDDIO_SD,
- TEGRA_VDDIO_CAM,
- TEGRA_VDDIO_GMI,
- TEGRA_VDDIO_PEXCTL,
- TEGRA_VDDIO_SDMMC1,
- TEGRA_VDDIO_SDMMC3,
- TEGRA_VDDIO_SDMMC4,
-};
-
-struct tegra_pingroup_config {
- int pingroup;
- enum tegra_mux_func func;
- enum tegra_pullupdown pupd;
- enum tegra_tristate tristate;
-};
-
-enum tegra_slew {
- TEGRA_SLEW_FASTEST = 0,
- TEGRA_SLEW_FAST,
- TEGRA_SLEW_SLOW,
- TEGRA_SLEW_SLOWEST,
- TEGRA_MAX_SLEW,
-};
-
-enum tegra_pull_strength {
- TEGRA_PULL_0 = 0,
- TEGRA_PULL_1,
- TEGRA_PULL_2,
- TEGRA_PULL_3,
- TEGRA_PULL_4,
- TEGRA_PULL_5,
- TEGRA_PULL_6,
- TEGRA_PULL_7,
- TEGRA_PULL_8,
- TEGRA_PULL_9,
- TEGRA_PULL_10,
- TEGRA_PULL_11,
- TEGRA_PULL_12,
- TEGRA_PULL_13,
- TEGRA_PULL_14,
- TEGRA_PULL_15,
- TEGRA_PULL_16,
- TEGRA_PULL_17,
- TEGRA_PULL_18,
- TEGRA_PULL_19,
- TEGRA_PULL_20,
- TEGRA_PULL_21,
- TEGRA_PULL_22,
- TEGRA_PULL_23,
- TEGRA_PULL_24,
- TEGRA_PULL_25,
- TEGRA_PULL_26,
- TEGRA_PULL_27,
- TEGRA_PULL_28,
- TEGRA_PULL_29,
- TEGRA_PULL_30,
- TEGRA_PULL_31,
- TEGRA_MAX_PULL,
-};
-
-enum tegra_drive {
- TEGRA_DRIVE_DIV_8 = 0,
- TEGRA_DRIVE_DIV_4,
- TEGRA_DRIVE_DIV_2,
- TEGRA_DRIVE_DIV_1,
- TEGRA_MAX_DRIVE,
-};
-
-enum tegra_hsm {
- TEGRA_HSM_DISABLE = 0,
- TEGRA_HSM_ENABLE,
-};
-
-enum tegra_schmitt {
- TEGRA_SCHMITT_DISABLE = 0,
- TEGRA_SCHMITT_ENABLE,
-};
-
-struct tegra_drive_pingroup_config {
- int pingroup;
- enum tegra_hsm hsm;
- enum tegra_schmitt schmitt;
- enum tegra_drive drive;
- enum tegra_pull_strength pull_down;
- enum tegra_pull_strength pull_up;
- enum tegra_slew slew_rising;
- enum tegra_slew slew_falling;
-};
-
-struct tegra_drive_pingroup_desc {
- const char *name;
- s16 reg_bank;
- s16 reg;
-};
-
-struct tegra_pingroup_desc {
- const char *name;
- int funcs[4];
- int func_safe;
- int vddio;
- enum tegra_pin_io io_default;
- s16 tri_bank; /* Register bank the tri_reg exists within */
- s16 mux_bank; /* Register bank the mux_reg exists within */
- s16 pupd_bank; /* Register bank the pupd_reg exists within */
- s16 tri_reg; /* offset into the TRISTATE_REG_* register bank */
- s16 mux_reg; /* offset into the PIN_MUX_CTL_* register bank */
- s16 pupd_reg; /* offset into the PULL_UPDOWN_REG_* register bank */
- s8 tri_bit; /* offset into the TRISTATE_REG_* register bit */
- s8 mux_bit; /* offset into the PIN_MUX_CTL_* register bit */
- s8 pupd_bit; /* offset into the PULL_UPDOWN_REG_* register bit */
- s8 lock_bit; /* offset of the LOCK bit into mux register bit */
- s8 od_bit; /* offset of the OD bit into mux register bit */
- s8 ioreset_bit; /* offset of the IO_RESET bit into mux register bit */
-};
-
-typedef void (*pinmux_init) (const struct tegra_pingroup_desc **pg,
- int *pg_max, const struct tegra_drive_pingroup_desc **pgdrive,
- int *pgdrive_max);
-
-void tegra20_pinmux_init(const struct tegra_pingroup_desc **pg, int *pg_max,
- const struct tegra_drive_pingroup_desc **pgdrive, int *pgdrive_max);
-
-void tegra30_pinmux_init(const struct tegra_pingroup_desc **pg, int *pg_max,
- const struct tegra_drive_pingroup_desc **pgdrive, int *pgdrive_max);
-
-int tegra_pinmux_set_tristate(int pg, enum tegra_tristate tristate);
-int tegra_pinmux_set_pullupdown(int pg, enum tegra_pullupdown pupd);
-
-void tegra_pinmux_config_table(const struct tegra_pingroup_config *config,
- int len);
-
-void tegra_drive_pinmux_config_table(struct tegra_drive_pingroup_config *config,
- int len);
-void tegra_pinmux_set_safe_pinmux_table(const struct tegra_pingroup_config *config,
- int len);
-void tegra_pinmux_config_pinmux_table(const struct tegra_pingroup_config *config,
- int len);
-void tegra_pinmux_config_tristate_table(const struct tegra_pingroup_config *config,
- int len, enum tegra_tristate tristate);
-void tegra_pinmux_config_pullupdown_table(const struct tegra_pingroup_config *config,
- int len, enum tegra_pullupdown pupd);
-#endif
diff --git a/arch/arm/mach-tegra/pinmux-tegra20-tables.c b/arch/arm/mach-tegra/pinmux-tegra20-tables.c
deleted file mode 100644
index 734add1280b7..000000000000
--- a/arch/arm/mach-tegra/pinmux-tegra20-tables.c
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * linux/arch/arm/mach-tegra/pinmux-tegra20-tables.c
- *
- * Common pinmux configurations for Tegra20 SoCs
- *
- * Copyright (C) 2010 NVIDIA Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
-#include <linux/init.h>
-#include <linux/string.h>
-
-#include <mach/iomap.h>
-#include <mach/pinmux.h>
-#include <mach/pinmux-tegra20.h>
-#include <mach/suspend.h>
-
-#define TRISTATE_REG_A 0x14
-#define PIN_MUX_CTL_REG_A 0x80
-#define PULLUPDOWN_REG_A 0xa0
-#define PINGROUP_REG_A 0x868
-
-#define DRIVE_PINGROUP(pg_name, r) \
- [TEGRA_DRIVE_PINGROUP_ ## pg_name] = { \
- .name = #pg_name, \
- .reg_bank = 3, \
- .reg = ((r) - PINGROUP_REG_A) \
- }
-
-static const struct tegra_drive_pingroup_desc tegra_soc_drive_pingroups[TEGRA_MAX_DRIVE_PINGROUP] = {
- DRIVE_PINGROUP(AO1, 0x868),
- DRIVE_PINGROUP(AO2, 0x86c),
- DRIVE_PINGROUP(AT1, 0x870),
- DRIVE_PINGROUP(AT2, 0x874),
- DRIVE_PINGROUP(CDEV1, 0x878),
- DRIVE_PINGROUP(CDEV2, 0x87c),
- DRIVE_PINGROUP(CSUS, 0x880),
- DRIVE_PINGROUP(DAP1, 0x884),
- DRIVE_PINGROUP(DAP2, 0x888),
- DRIVE_PINGROUP(DAP3, 0x88c),
- DRIVE_PINGROUP(DAP4, 0x890),
- DRIVE_PINGROUP(DBG, 0x894),
- DRIVE_PINGROUP(LCD1, 0x898),
- DRIVE_PINGROUP(LCD2, 0x89c),
- DRIVE_PINGROUP(SDMMC2, 0x8a0),
- DRIVE_PINGROUP(SDMMC3, 0x8a4),
- DRIVE_PINGROUP(SPI, 0x8a8),
- DRIVE_PINGROUP(UAA, 0x8ac),
- DRIVE_PINGROUP(UAB, 0x8b0),
- DRIVE_PINGROUP(UART2, 0x8b4),
- DRIVE_PINGROUP(UART3, 0x8b8),
- DRIVE_PINGROUP(VI1, 0x8bc),
- DRIVE_PINGROUP(VI2, 0x8c0),
- DRIVE_PINGROUP(XM2A, 0x8c4),
- DRIVE_PINGROUP(XM2C, 0x8c8),
- DRIVE_PINGROUP(XM2D, 0x8cc),
- DRIVE_PINGROUP(XM2CLK, 0x8d0),
- DRIVE_PINGROUP(MEMCOMP, 0x8d4),
- DRIVE_PINGROUP(SDIO1, 0x8e0),
- DRIVE_PINGROUP(CRT, 0x8ec),
- DRIVE_PINGROUP(DDC, 0x8f0),
- DRIVE_PINGROUP(GMA, 0x8f4),
- DRIVE_PINGROUP(GMB, 0x8f8),
- DRIVE_PINGROUP(GMC, 0x8fc),
- DRIVE_PINGROUP(GMD, 0x900),
- DRIVE_PINGROUP(GME, 0x904),
- DRIVE_PINGROUP(OWR, 0x908),
- DRIVE_PINGROUP(UAD, 0x90c),
-};
-
-#define PINGROUP(pg_name, vdd, f0, f1, f2, f3, f_safe, \
- tri_r, tri_b, mux_r, mux_b, pupd_r, pupd_b) \
- [TEGRA_PINGROUP_ ## pg_name] = { \
- .name = #pg_name, \
- .vddio = TEGRA_VDDIO_ ## vdd, \
- .funcs = { \
- TEGRA_MUX_ ## f0, \
- TEGRA_MUX_ ## f1, \
- TEGRA_MUX_ ## f2, \
- TEGRA_MUX_ ## f3, \
- }, \
- .func_safe = TEGRA_MUX_ ## f_safe, \
- .tri_bank = 0, \
- .tri_reg = ((tri_r) - TRISTATE_REG_A), \
- .tri_bit = tri_b, \
- .mux_bank = 1, \
- .mux_reg = ((mux_r) - PIN_MUX_CTL_REG_A), \
- .mux_bit = mux_b, \
- .pupd_bank = 2, \
- .pupd_reg = ((pupd_r) - PULLUPDOWN_REG_A), \
- .pupd_bit = pupd_b, \
- .lock_bit = -1, \
- .od_bit = -1, \
- .ioreset_bit = -1, \
- .io_default = -1, \
- }
-
-static const struct tegra_pingroup_desc tegra_soc_pingroups[TEGRA_MAX_PINGROUP] = {
- PINGROUP(ATA, NAND, IDE, NAND, GMI, RSVD, IDE, 0x14, 0, 0x80, 24, 0xA0, 0),
- PINGROUP(ATB, NAND, IDE, NAND, GMI, SDIO4, IDE, 0x14, 1, 0x80, 16, 0xA0, 2),
- PINGROUP(ATC, NAND, IDE, NAND, GMI, SDIO4, IDE, 0x14, 2, 0x80, 22, 0xA0, 4),
- PINGROUP(ATD, NAND, IDE, NAND, GMI, SDIO4, IDE, 0x14, 3, 0x80, 20, 0xA0, 6),
- PINGROUP(ATE, NAND, IDE, NAND, GMI, RSVD, IDE, 0x18, 25, 0x80, 12, 0xA0, 8),
- PINGROUP(CDEV1, AUDIO, OSC, PLLA_OUT, PLLM_OUT1, AUDIO_SYNC, OSC, 0x14, 4, 0x88, 2, 0xA8, 0),
- PINGROUP(CDEV2, AUDIO, OSC, AHB_CLK, APB_CLK, PLLP_OUT4, OSC, 0x14, 5, 0x88, 4, 0xA8, 2),
- PINGROUP(CRTP, LCD, CRT, RSVD, RSVD, RSVD, RSVD, 0x20, 14, 0x98, 20, 0xA4, 24),
- PINGROUP(CSUS, VI, PLLC_OUT1, PLLP_OUT2, PLLP_OUT3, VI_SENSOR_CLK, PLLC_OUT1, 0x14, 6, 0x88, 6, 0xAC, 24),
- PINGROUP(DAP1, AUDIO, DAP1, RSVD, GMI, SDIO2, DAP1, 0x14, 7, 0x88, 20, 0xA0, 10),
- PINGROUP(DAP2, AUDIO, DAP2, TWC, RSVD, GMI, DAP2, 0x14, 8, 0x88, 22, 0xA0, 12),
- PINGROUP(DAP3, BB, DAP3, RSVD, RSVD, RSVD, DAP3, 0x14, 9, 0x88, 24, 0xA0, 14),
- PINGROUP(DAP4, UART, DAP4, RSVD, GMI, RSVD, DAP4, 0x14, 10, 0x88, 26, 0xA0, 16),
- PINGROUP(DDC, LCD, I2C2, RSVD, RSVD, RSVD, RSVD4, 0x18, 31, 0x88, 0, 0xB0, 28),
- PINGROUP(DTA, VI, RSVD, SDIO2, VI, RSVD, RSVD4, 0x14, 11, 0x84, 20, 0xA0, 18),
- PINGROUP(DTB, VI, RSVD, RSVD, VI, SPI1, RSVD1, 0x14, 12, 0x84, 22, 0xA0, 20),
- PINGROUP(DTC, VI, RSVD, RSVD, VI, RSVD, RSVD1, 0x14, 13, 0x84, 26, 0xA0, 22),
- PINGROUP(DTD, VI, RSVD, SDIO2, VI, RSVD, RSVD1, 0x14, 14, 0x84, 28, 0xA0, 24),
- PINGROUP(DTE, VI, RSVD, RSVD, VI, SPI1, RSVD1, 0x14, 15, 0x84, 30, 0xA0, 26),
- PINGROUP(DTF, VI, I2C3, RSVD, VI, RSVD, RSVD4, 0x20, 12, 0x98, 30, 0xA0, 28),
- PINGROUP(GMA, NAND, UARTE, SPI3, GMI, SDIO4, SPI3, 0x14, 28, 0x84, 0, 0xB0, 20),
- PINGROUP(GMB, NAND, IDE, NAND, GMI, GMI_INT, GMI, 0x18, 29, 0x88, 28, 0xB0, 22),
- PINGROUP(GMC, NAND, UARTD, SPI4, GMI, SFLASH, SPI4, 0x14, 29, 0x84, 2, 0xB0, 24),
- PINGROUP(GMD, NAND, RSVD, NAND, GMI, SFLASH, GMI, 0x18, 30, 0x88, 30, 0xB0, 26),
- PINGROUP(GME, NAND, RSVD, DAP5, GMI, SDIO4, GMI, 0x18, 0, 0x8C, 0, 0xA8, 24),
- PINGROUP(GPU, UART, PWM, UARTA, GMI, RSVD, RSVD4, 0x14, 16, 0x8C, 4, 0xA4, 20),
- PINGROUP(GPU7, SYS, RTCK, RSVD, RSVD, RSVD, RTCK, 0x20, 11, 0x98, 28, 0xA4, 6),
- PINGROUP(GPV, SD, PCIE, RSVD, RSVD, RSVD, PCIE, 0x14, 17, 0x8C, 2, 0xA0, 30),
- PINGROUP(HDINT, LCD, HDMI, RSVD, RSVD, RSVD, HDMI, 0x1C, 23, 0x84, 4, 0xAC, 22),
- PINGROUP(I2CP, SYS, I2C, RSVD, RSVD, RSVD, RSVD4, 0x14, 18, 0x88, 8, 0xA4, 2),
- PINGROUP(IRRX, UART, UARTA, UARTB, GMI, SPI4, UARTB, 0x14, 20, 0x88, 18, 0xA8, 22),
- PINGROUP(IRTX, UART, UARTA, UARTB, GMI, SPI4, UARTB, 0x14, 19, 0x88, 16, 0xA8, 20),
- PINGROUP(KBCA, SYS, KBC, NAND, SDIO2, EMC_TEST0_DLL, KBC, 0x14, 22, 0x88, 10, 0xA4, 8),
- PINGROUP(KBCB, SYS, KBC, NAND, SDIO2, MIO, KBC, 0x14, 21, 0x88, 12, 0xA4, 10),
- PINGROUP(KBCC, SYS, KBC, NAND, TRACE, EMC_TEST1_DLL, KBC, 0x18, 26, 0x88, 14, 0xA4, 12),
- PINGROUP(KBCD, SYS, KBC, NAND, SDIO2, MIO, KBC, 0x20, 10, 0x98, 26, 0xA4, 14),
- PINGROUP(KBCE, SYS, KBC, NAND, OWR, RSVD, KBC, 0x14, 26, 0x80, 28, 0xB0, 2),
- PINGROUP(KBCF, SYS, KBC, NAND, TRACE, MIO, KBC, 0x14, 27, 0x80, 26, 0xB0, 0),
- PINGROUP(LCSN, LCD, DISPLAYA, DISPLAYB, SPI3, RSVD, RSVD4, 0x1C, 31, 0x90, 12, 0xAC, 20),
- PINGROUP(LD0, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 0, 0x94, 0, 0xAC, 12),
- PINGROUP(LD1, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 1, 0x94, 2, 0xAC, 12),
- PINGROUP(LD10, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 10, 0x94, 20, 0xAC, 12),
- PINGROUP(LD11, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 11, 0x94, 22, 0xAC, 12),
- PINGROUP(LD12, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 12, 0x94, 24, 0xAC, 12),
- PINGROUP(LD13, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 13, 0x94, 26, 0xAC, 12),
- PINGROUP(LD14, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 14, 0x94, 28, 0xAC, 12),
- PINGROUP(LD15, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 15, 0x94, 30, 0xAC, 12),
- PINGROUP(LD16, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 16, 0x98, 0, 0xAC, 12),
- PINGROUP(LD17, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x1C, 17, 0x98, 2, 0xAC, 12),
- PINGROUP(LD2, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 2, 0x94, 4, 0xAC, 12),
- PINGROUP(LD3, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 3, 0x94, 6, 0xAC, 12),
- PINGROUP(LD4, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 4, 0x94, 8, 0xAC, 12),
- PINGROUP(LD5, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 5, 0x94, 10, 0xAC, 12),
- PINGROUP(LD6, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 6, 0x94, 12, 0xAC, 12),
- PINGROUP(LD7, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 7, 0x94, 14, 0xAC, 12),
- PINGROUP(LD8, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 8, 0x94, 16, 0xAC, 12),
- PINGROUP(LD9, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 9, 0x94, 18, 0xAC, 12),
- PINGROUP(LDC, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x1C, 30, 0x90, 14, 0xAC, 20),
- PINGROUP(LDI, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x20, 6, 0x98, 16, 0xAC, 18),
- PINGROUP(LHP0, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x1C, 18, 0x98, 10, 0xAC, 16),
- PINGROUP(LHP1, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x1C, 19, 0x98, 4, 0xAC, 14),
- PINGROUP(LHP2, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x1C, 20, 0x98, 6, 0xAC, 14),
- PINGROUP(LHS, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x20, 7, 0x90, 22, 0xAC, 22),
- PINGROUP(LM0, LCD, DISPLAYA, DISPLAYB, SPI3, RSVD, RSVD4, 0x1C, 24, 0x90, 26, 0xAC, 22),
- PINGROUP(LM1, LCD, DISPLAYA, DISPLAYB, RSVD, CRT, RSVD3, 0x1C, 25, 0x90, 28, 0xAC, 22),
- PINGROUP(LPP, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x20, 8, 0x98, 14, 0xAC, 18),
- PINGROUP(LPW0, LCD, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYA, 0x20, 3, 0x90, 0, 0xAC, 20),
- PINGROUP(LPW1, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x20, 4, 0x90, 2, 0xAC, 20),
- PINGROUP(LPW2, LCD, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYA, 0x20, 5, 0x90, 4, 0xAC, 20),
- PINGROUP(LSC0, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 27, 0x90, 18, 0xAC, 22),
- PINGROUP(LSC1, LCD, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYA, 0x1C, 28, 0x90, 20, 0xAC, 20),
- PINGROUP(LSCK, LCD, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYA, 0x1C, 29, 0x90, 16, 0xAC, 20),
- PINGROUP(LSDA, LCD, DISPLAYA, DISPLAYB, SPI3, HDMI, DISPLAYA, 0x20, 1, 0x90, 8, 0xAC, 20),
- PINGROUP(LSDI, LCD, DISPLAYA, DISPLAYB, SPI3, RSVD, DISPLAYA, 0x20, 2, 0x90, 6, 0xAC, 20),
- PINGROUP(LSPI, LCD, DISPLAYA, DISPLAYB, XIO, HDMI, DISPLAYA, 0x20, 0, 0x90, 10, 0xAC, 22),
- PINGROUP(LVP0, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x1C, 21, 0x90, 30, 0xAC, 22),
- PINGROUP(LVP1, LCD, DISPLAYA, DISPLAYB, RSVD, RSVD, RSVD4, 0x1C, 22, 0x98, 8, 0xAC, 16),
- PINGROUP(LVS, LCD, DISPLAYA, DISPLAYB, XIO, RSVD, RSVD4, 0x1C, 26, 0x90, 24, 0xAC, 22),
- PINGROUP(OWC, SYS, OWR, RSVD, RSVD, RSVD, OWR, 0x14, 31, 0x84, 8, 0xB0, 30),
- PINGROUP(PMC, SYS, PWR_ON, PWR_INTR, RSVD, RSVD, PWR_ON, 0x14, 23, 0x98, 18, -1, -1),
- PINGROUP(PTA, NAND, I2C2, HDMI, GMI, RSVD, RSVD4, 0x14, 24, 0x98, 22, 0xA4, 4),
- PINGROUP(RM, UART, I2C, RSVD, RSVD, RSVD, RSVD4, 0x14, 25, 0x80, 14, 0xA4, 0),
- PINGROUP(SDB, SD, UARTA, PWM, SDIO3, SPI2, PWM, 0x20, 15, 0x8C, 10, -1, -1),
- PINGROUP(SDC, SD, PWM, TWC, SDIO3, SPI3, TWC, 0x18, 1, 0x8C, 12, 0xAC, 28),
- PINGROUP(SDD, SD, UARTA, PWM, SDIO3, SPI3, PWM, 0x18, 2, 0x8C, 14, 0xAC, 30),
- PINGROUP(SDIO1, BB, SDIO1, RSVD, UARTE, UARTA, RSVD2, 0x14, 30, 0x80, 30, 0xB0, 18),
- PINGROUP(SLXA, SD, PCIE, SPI4, SDIO3, SPI2, PCIE, 0x18, 3, 0x84, 6, 0xA4, 22),
- PINGROUP(SLXC, SD, SPDIF, SPI4, SDIO3, SPI2, SPI4, 0x18, 5, 0x84, 10, 0xA4, 26),
- PINGROUP(SLXD, SD, SPDIF, SPI4, SDIO3, SPI2, SPI4, 0x18, 6, 0x84, 12, 0xA4, 28),
- PINGROUP(SLXK, SD, PCIE, SPI4, SDIO3, SPI2, PCIE, 0x18, 7, 0x84, 14, 0xA4, 30),
- PINGROUP(SPDI, AUDIO, SPDIF, RSVD, I2C, SDIO2, RSVD2, 0x18, 8, 0x8C, 8, 0xA4, 16),
- PINGROUP(SPDO, AUDIO, SPDIF, RSVD, I2C, SDIO2, RSVD2, 0x18, 9, 0x8C, 6, 0xA4, 18),
- PINGROUP(SPIA, AUDIO, SPI1, SPI2, SPI3, GMI, GMI, 0x18, 10, 0x8C, 30, 0xA8, 4),
- PINGROUP(SPIB, AUDIO, SPI1, SPI2, SPI3, GMI, GMI, 0x18, 11, 0x8C, 28, 0xA8, 6),
- PINGROUP(SPIC, AUDIO, SPI1, SPI2, SPI3, GMI, GMI, 0x18, 12, 0x8C, 26, 0xA8, 8),
- PINGROUP(SPID, AUDIO, SPI2, SPI1, SPI2_ALT, GMI, GMI, 0x18, 13, 0x8C, 24, 0xA8, 10),
- PINGROUP(SPIE, AUDIO, SPI2, SPI1, SPI2_ALT, GMI, GMI, 0x18, 14, 0x8C, 22, 0xA8, 12),
- PINGROUP(SPIF, AUDIO, SPI3, SPI1, SPI2, RSVD, RSVD4, 0x18, 15, 0x8C, 20, 0xA8, 14),
- PINGROUP(SPIG, AUDIO, SPI3, SPI2, SPI2_ALT, I2C, SPI2_ALT, 0x18, 16, 0x8C, 18, 0xA8, 16),
- PINGROUP(SPIH, AUDIO, SPI3, SPI2, SPI2_ALT, I2C, SPI2_ALT, 0x18, 17, 0x8C, 16, 0xA8, 18),
- PINGROUP(UAA, BB, SPI3, MIPI_HS, UARTA, ULPI, MIPI_HS, 0x18, 18, 0x80, 0, 0xAC, 0),
- PINGROUP(UAB, BB, SPI2, MIPI_HS, UARTA, ULPI, MIPI_HS, 0x18, 19, 0x80, 2, 0xAC, 2),
- PINGROUP(UAC, BB, OWR, RSVD, RSVD, RSVD, RSVD4, 0x18, 20, 0x80, 4, 0xAC, 4),
- PINGROUP(UAD, UART, IRDA, SPDIF, UARTA, SPI4, SPDIF, 0x18, 21, 0x80, 6, 0xAC, 6),
- PINGROUP(UCA, UART, UARTC, RSVD, GMI, RSVD, RSVD4, 0x18, 22, 0x84, 16, 0xAC, 8),
- PINGROUP(UCB, UART, UARTC, PWM, GMI, RSVD, RSVD4, 0x18, 23, 0x84, 18, 0xAC, 10),
- PINGROUP(UDA, BB, SPI1, RSVD, UARTD, ULPI, RSVD2, 0x20, 13, 0x80, 8, 0xB0, 16),
- /* these pin groups only have pullup and pull down control */
- PINGROUP(CK32, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, -1, -1, -1, -1, 0xB0, 14),
- PINGROUP(DDRC, DDR, RSVD, RSVD, RSVD, RSVD, RSVD, -1, -1, -1, -1, 0xAC, 26),
- PINGROUP(PMCA, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, -1, -1, -1, -1, 0xB0, 4),
- PINGROUP(PMCB, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, -1, -1, -1, -1, 0xB0, 6),
- PINGROUP(PMCC, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, -1, -1, -1, -1, 0xB0, 8),
- PINGROUP(PMCD, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, -1, -1, -1, -1, 0xB0, 10),
- PINGROUP(PMCE, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, -1, -1, -1, -1, 0xB0, 12),
- PINGROUP(XM2C, DDR, RSVD, RSVD, RSVD, RSVD, RSVD, -1, -1, -1, -1, 0xA8, 30),
- PINGROUP(XM2D, DDR, RSVD, RSVD, RSVD, RSVD, RSVD, -1, -1, -1, -1, 0xA8, 28),
-};
-
-void __devinit tegra20_pinmux_init(const struct tegra_pingroup_desc **pg,
- int *pg_max, const struct tegra_drive_pingroup_desc **pgdrive,
- int *pgdrive_max)
-{
- *pg = tegra_soc_pingroups;
- *pg_max = TEGRA_MAX_PINGROUP;
- *pgdrive = tegra_soc_drive_pingroups;
- *pgdrive_max = TEGRA_MAX_DRIVE_PINGROUP;
-}
-
diff --git a/arch/arm/mach-tegra/pinmux-tegra30-tables.c b/arch/arm/mach-tegra/pinmux-tegra30-tables.c
deleted file mode 100644
index 14fc0e4c1c44..000000000000
--- a/arch/arm/mach-tegra/pinmux-tegra30-tables.c
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * linux/arch/arm/mach-tegra/pinmux-tegra30-tables.c
- *
- * Common pinmux configurations for Tegra30 SoCs
- *
- * Copyright (C) 2010,2011 NVIDIA Corporation
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
-#include <linux/init.h>
-#include <linux/string.h>
-
-#include <mach/iomap.h>
-#include <mach/pinmux.h>
-#include <mach/pinmux-tegra30.h>
-#include <mach/suspend.h>
-
-#define PINGROUP_REG_A 0x868
-#define MUXCTL_REG_A 0x3000
-
-#define DRIVE_PINGROUP(pg_name, r) \
- [TEGRA_DRIVE_PINGROUP_ ## pg_name] = { \
- .name = #pg_name, \
- .reg_bank = 0, \
- .reg = ((r) - PINGROUP_REG_A) \
- }
-
-static const struct tegra_drive_pingroup_desc tegra_soc_drive_pingroups[TEGRA_MAX_DRIVE_PINGROUP] = {
- DRIVE_PINGROUP(AO1, 0x868),
- DRIVE_PINGROUP(AO2, 0x86c),
- DRIVE_PINGROUP(AT1, 0x870),
- DRIVE_PINGROUP(AT2, 0x874),
- DRIVE_PINGROUP(AT3, 0x878),
- DRIVE_PINGROUP(AT4, 0x87c),
- DRIVE_PINGROUP(AT5, 0x880),
- DRIVE_PINGROUP(CDEV1, 0x884),
- DRIVE_PINGROUP(CDEV2, 0x888),
- DRIVE_PINGROUP(CSUS, 0x88c),
- DRIVE_PINGROUP(DAP1, 0x890),
- DRIVE_PINGROUP(DAP2, 0x894),
- DRIVE_PINGROUP(DAP3, 0x898),
- DRIVE_PINGROUP(DAP4, 0x89c),
- DRIVE_PINGROUP(DBG, 0x8a0),
- DRIVE_PINGROUP(LCD1, 0x8a4),
- DRIVE_PINGROUP(LCD2, 0x8a8),
- DRIVE_PINGROUP(SDIO2, 0x8ac),
- DRIVE_PINGROUP(SDIO3, 0x8b0),
- DRIVE_PINGROUP(SPI, 0x8b4),
- DRIVE_PINGROUP(UAA, 0x8b8),
- DRIVE_PINGROUP(UAB, 0x8bc),
- DRIVE_PINGROUP(UART2, 0x8c0),
- DRIVE_PINGROUP(UART3, 0x8c4),
- DRIVE_PINGROUP(VI1, 0x8c8),
- DRIVE_PINGROUP(SDIO1, 0x8ec),
- DRIVE_PINGROUP(CRT, 0x8f8),
- DRIVE_PINGROUP(DDC, 0x8fc),
- DRIVE_PINGROUP(GMA, 0x900),
- DRIVE_PINGROUP(GMB, 0x904),
- DRIVE_PINGROUP(GMC, 0x908),
- DRIVE_PINGROUP(GMD, 0x90c),
- DRIVE_PINGROUP(GME, 0x910),
- DRIVE_PINGROUP(GMF, 0x914),
- DRIVE_PINGROUP(GMG, 0x918),
- DRIVE_PINGROUP(GMH, 0x91c),
- DRIVE_PINGROUP(OWR, 0x920),
- DRIVE_PINGROUP(UAD, 0x924),
- DRIVE_PINGROUP(GPV, 0x928),
- DRIVE_PINGROUP(DEV3, 0x92c),
- DRIVE_PINGROUP(CEC, 0x938),
-};
-
-#define PINGROUP(pg_name, vdd, f0, f1, f2, f3, fs, iod, reg) \
- [TEGRA_PINGROUP_ ## pg_name] = { \
- .name = #pg_name, \
- .vddio = TEGRA_VDDIO_ ## vdd, \
- .funcs = { \
- TEGRA_MUX_ ## f0, \
- TEGRA_MUX_ ## f1, \
- TEGRA_MUX_ ## f2, \
- TEGRA_MUX_ ## f3, \
- }, \
- .func_safe = TEGRA_MUX_ ## fs, \
- .tri_bank = 1, \
- .tri_reg = ((reg) - MUXCTL_REG_A), \
- .tri_bit = 4, \
- .mux_bank = 1, \
- .mux_reg = ((reg) - MUXCTL_REG_A), \
- .mux_bit = 0, \
- .pupd_bank = 1, \
- .pupd_reg = ((reg) - MUXCTL_REG_A), \
- .pupd_bit = 2, \
- .io_default = TEGRA_PIN_ ## iod, \
- .od_bit = 6, \
- .lock_bit = 7, \
- .ioreset_bit = 8, \
- }
-
-static const struct tegra_pingroup_desc tegra_soc_pingroups[TEGRA_MAX_PINGROUP] = {
- /* NAME VDD f0 f1 f2 f3 fSafe io reg */
- PINGROUP(ULPI_DATA0, BB, SPI3, HSI, UARTA, ULPI, RSVD, INPUT, 0x3000),
- PINGROUP(ULPI_DATA1, BB, SPI3, HSI, UARTA, ULPI, RSVD, INPUT, 0x3004),
- PINGROUP(ULPI_DATA2, BB, SPI3, HSI, UARTA, ULPI, RSVD, INPUT, 0x3008),
- PINGROUP(ULPI_DATA3, BB, SPI3, HSI, UARTA, ULPI, RSVD, INPUT, 0x300c),
- PINGROUP(ULPI_DATA4, BB, SPI2, HSI, UARTA, ULPI, RSVD, INPUT, 0x3010),
- PINGROUP(ULPI_DATA5, BB, SPI2, HSI, UARTA, ULPI, RSVD, INPUT, 0x3014),
- PINGROUP(ULPI_DATA6, BB, SPI2, HSI, UARTA, ULPI, RSVD, INPUT, 0x3018),
- PINGROUP(ULPI_DATA7, BB, SPI2, HSI, UARTA, ULPI, RSVD, INPUT, 0x301c),
- PINGROUP(ULPI_CLK, BB, SPI1, RSVD, UARTD, ULPI, RSVD, INPUT, 0x3020),
- PINGROUP(ULPI_DIR, BB, SPI1, RSVD, UARTD, ULPI, RSVD, INPUT, 0x3024),
- PINGROUP(ULPI_NXT, BB, SPI1, RSVD, UARTD, ULPI, RSVD, INPUT, 0x3028),
- PINGROUP(ULPI_STP, BB, SPI1, RSVD, UARTD, ULPI, RSVD, INPUT, 0x302c),
- PINGROUP(DAP3_FS, BB, I2S2, RSVD1, DISPLAYA, DISPLAYB, RSVD, INPUT, 0x3030),
- PINGROUP(DAP3_DIN, BB, I2S2, RSVD1, DISPLAYA, DISPLAYB, RSVD, INPUT, 0x3034),
- PINGROUP(DAP3_DOUT, BB, I2S2, RSVD1, DISPLAYA, DISPLAYB, RSVD, INPUT, 0x3038),
- PINGROUP(DAP3_SCLK, BB, I2S2, RSVD1, DISPLAYA, DISPLAYB, RSVD, INPUT, 0x303c),
- PINGROUP(GPIO_PV0, BB, RSVD, RSVD, RSVD, RSVD, RSVD, INPUT, 0x3040),
- PINGROUP(GPIO_PV1, BB, RSVD, RSVD, RSVD, RSVD, RSVD, INPUT, 0x3044),
- PINGROUP(SDMMC1_CLK, SDMMC1, SDIO1, RSVD1, RSVD2, INVALID, RSVD, INPUT, 0x3048),
- PINGROUP(SDMMC1_CMD, SDMMC1, SDIO1, RSVD1, RSVD2, INVALID, RSVD, INPUT, 0x304c),
- PINGROUP(SDMMC1_DAT3, SDMMC1, SDIO1, RSVD1, UARTE, INVALID, RSVD, INPUT, 0x3050),
- PINGROUP(SDMMC1_DAT2, SDMMC1, SDIO1, RSVD1, UARTE, INVALID, RSVD, INPUT, 0x3054),
- PINGROUP(SDMMC1_DAT1, SDMMC1, SDIO1, RSVD1, UARTE, INVALID, RSVD, INPUT, 0x3058),
- PINGROUP(SDMMC1_DAT0, SDMMC1, SDIO1, RSVD1, UARTE, INVALID, RSVD, INPUT, 0x305c),
- PINGROUP(GPIO_PV2, SDMMC1, OWR, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x3060),
- PINGROUP(GPIO_PV3, SDMMC1, INVALID, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x3064),
- PINGROUP(CLK2_OUT, SDMMC1, EXTPERIPH2, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x3068),
- PINGROUP(CLK2_REQ, SDMMC1, DAP, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x306c),
- PINGROUP(LCD_PWR1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x3070),
- PINGROUP(LCD_PWR2, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, RSVD, OUTPUT, 0x3074),
- PINGROUP(LCD_SDIN, LCD, DISPLAYA, DISPLAYB, SPI5, RSVD, RSVD, OUTPUT, 0x3078),
- PINGROUP(LCD_SDOUT, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, RSVD, OUTPUT, 0x307c),
- PINGROUP(LCD_WR_N, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, RSVD, OUTPUT, 0x3080),
- PINGROUP(LCD_CS0_N, LCD, DISPLAYA, DISPLAYB, SPI5, RSVD, RSVD, OUTPUT, 0x3084),
- PINGROUP(LCD_DC0, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x3088),
- PINGROUP(LCD_SCK, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, RSVD, OUTPUT, 0x308c),
- PINGROUP(LCD_PWR0, LCD, DISPLAYA, DISPLAYB, SPI5, INVALID, RSVD, OUTPUT, 0x3090),
- PINGROUP(LCD_PCLK, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x3094),
- PINGROUP(LCD_DE, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x3098),
- PINGROUP(LCD_HSYNC, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x309c),
- PINGROUP(LCD_VSYNC, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30a0),
- PINGROUP(LCD_D0, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30a4),
- PINGROUP(LCD_D1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30a8),
- PINGROUP(LCD_D2, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30ac),
- PINGROUP(LCD_D3, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30b0),
- PINGROUP(LCD_D4, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30b4),
- PINGROUP(LCD_D5, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30b8),
- PINGROUP(LCD_D6, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30bc),
- PINGROUP(LCD_D7, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30c0),
- PINGROUP(LCD_D8, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30c4),
- PINGROUP(LCD_D9, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30c8),
- PINGROUP(LCD_D10, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30cc),
- PINGROUP(LCD_D11, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30d0),
- PINGROUP(LCD_D12, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30d4),
- PINGROUP(LCD_D13, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30d8),
- PINGROUP(LCD_D14, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30dc),
- PINGROUP(LCD_D15, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30e0),
- PINGROUP(LCD_D16, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30e4),
- PINGROUP(LCD_D17, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30e8),
- PINGROUP(LCD_D18, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30ec),
- PINGROUP(LCD_D19, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30f0),
- PINGROUP(LCD_D20, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30f4),
- PINGROUP(LCD_D21, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30f8),
- PINGROUP(LCD_D22, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x30fc),
- PINGROUP(LCD_D23, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x3100),
- PINGROUP(LCD_CS1_N, LCD, DISPLAYA, DISPLAYB, SPI5, RSVD2, RSVD, OUTPUT, 0x3104),
- PINGROUP(LCD_M1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x3108),
- PINGROUP(LCD_DC1, LCD, DISPLAYA, DISPLAYB, RSVD1, RSVD2, RSVD, OUTPUT, 0x310c),
- PINGROUP(HDMI_INT, LCD, RSVD, RSVD, RSVD, RSVD, RSVD, INPUT, 0x3110),
- PINGROUP(DDC_SCL, LCD, I2C4, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x3114),
- PINGROUP(DDC_SDA, LCD, I2C4, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x3118),
- PINGROUP(CRT_HSYNC, LCD, CRT, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x311c),
- PINGROUP(CRT_VSYNC, LCD, CRT, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x3120),
- PINGROUP(VI_D0, VI, INVALID, RSVD1, VI, RSVD2, RSVD, INPUT, 0x3124),
- PINGROUP(VI_D1, VI, INVALID, SDIO2, VI, RSVD1, RSVD, INPUT, 0x3128),
- PINGROUP(VI_D2, VI, INVALID, SDIO2, VI, RSVD1, RSVD, INPUT, 0x312c),
- PINGROUP(VI_D3, VI, INVALID, SDIO2, VI, RSVD1, RSVD, INPUT, 0x3130),
- PINGROUP(VI_D4, VI, INVALID, SDIO2, VI, RSVD1, RSVD, INPUT, 0x3134),
- PINGROUP(VI_D5, VI, INVALID, SDIO2, VI, RSVD1, RSVD, INPUT, 0x3138),
- PINGROUP(VI_D6, VI, INVALID, SDIO2, VI, RSVD1, RSVD, INPUT, 0x313c),
- PINGROUP(VI_D7, VI, INVALID, SDIO2, VI, RSVD1, RSVD, INPUT, 0x3140),
- PINGROUP(VI_D8, VI, INVALID, SDIO2, VI, RSVD1, RSVD, INPUT, 0x3144),
- PINGROUP(VI_D9, VI, INVALID, SDIO2, VI, RSVD1, RSVD, INPUT, 0x3148),
- PINGROUP(VI_D10, VI, INVALID, RSVD1, VI, RSVD2, RSVD, INPUT, 0x314c),
- PINGROUP(VI_D11, VI, INVALID, RSVD1, VI, RSVD2, RSVD, INPUT, 0x3150),
- PINGROUP(VI_PCLK, VI, RSVD1, SDIO2, VI, RSVD2, RSVD, INPUT, 0x3154),
- PINGROUP(VI_MCLK, VI, VI, INVALID, INVALID, INVALID, RSVD, INPUT, 0x3158),
- PINGROUP(VI_VSYNC, VI, INVALID, RSVD1, VI, RSVD2, RSVD, INPUT, 0x315c),
- PINGROUP(VI_HSYNC, VI, INVALID, RSVD1, VI, RSVD2, RSVD, INPUT, 0x3160),
- PINGROUP(UART2_RXD, UART, IRDA, SPDIF, UARTA, SPI4, RSVD, INPUT, 0x3164),
- PINGROUP(UART2_TXD, UART, IRDA, SPDIF, UARTA, SPI4, RSVD, INPUT, 0x3168),
- PINGROUP(UART2_RTS_N, UART, UARTA, UARTB, GMI, SPI4, RSVD, INPUT, 0x316c),
- PINGROUP(UART2_CTS_N, UART, UARTA, UARTB, GMI, SPI4, RSVD, INPUT, 0x3170),
- PINGROUP(UART3_TXD, UART, UARTC, RSVD1, GMI, RSVD2, RSVD, INPUT, 0x3174),
- PINGROUP(UART3_RXD, UART, UARTC, RSVD1, GMI, RSVD2, RSVD, INPUT, 0x3178),
- PINGROUP(UART3_CTS_N, UART, UARTC, RSVD1, GMI, RSVD2, RSVD, INPUT, 0x317c),
- PINGROUP(UART3_RTS_N, UART, UARTC, PWM0, GMI, RSVD2, RSVD, INPUT, 0x3180),
- PINGROUP(GPIO_PU0, UART, OWR, UARTA, GMI, RSVD1, RSVD, INPUT, 0x3184),
- PINGROUP(GPIO_PU1, UART, RSVD1, UARTA, GMI, RSVD2, RSVD, INPUT, 0x3188),
- PINGROUP(GPIO_PU2, UART, RSVD1, UARTA, GMI, RSVD2, RSVD, INPUT, 0x318c),
- PINGROUP(GPIO_PU3, UART, PWM0, UARTA, GMI, RSVD1, RSVD, INPUT, 0x3190),
- PINGROUP(GPIO_PU4, UART, PWM1, UARTA, GMI, RSVD1, RSVD, INPUT, 0x3194),
- PINGROUP(GPIO_PU5, UART, PWM2, UARTA, GMI, RSVD1, RSVD, INPUT, 0x3198),
- PINGROUP(GPIO_PU6, UART, PWM3, UARTA, GMI, RSVD1, RSVD, INPUT, 0x319c),
- PINGROUP(GEN1_I2C_SDA, UART, I2C, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x31a0),
- PINGROUP(GEN1_I2C_SCL, UART, I2C, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x31a4),
- PINGROUP(DAP4_FS, UART, I2S3, RSVD1, GMI, RSVD2, RSVD, INPUT, 0x31a8),
- PINGROUP(DAP4_DIN, UART, I2S3, RSVD1, GMI, RSVD2, RSVD, INPUT, 0x31ac),
- PINGROUP(DAP4_DOUT, UART, I2S3, RSVD1, GMI, RSVD2, RSVD, INPUT, 0x31b0),
- PINGROUP(DAP4_SCLK, UART, I2S3, RSVD1, GMI, RSVD2, RSVD, INPUT, 0x31b4),
- PINGROUP(CLK3_OUT, UART, EXTPERIPH3, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x31b8),
- PINGROUP(CLK3_REQ, UART, DEV3, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x31bc),
- PINGROUP(GMI_WP_N, GMI, RSVD1, NAND, GMI, GMI_ALT, RSVD, INPUT, 0x31c0),
- PINGROUP(GMI_IORDY, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31c4),
- PINGROUP(GMI_WAIT, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31c8),
- PINGROUP(GMI_ADV_N, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31cc),
- PINGROUP(GMI_CLK, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31d0),
- PINGROUP(GMI_CS0_N, GMI, RSVD1, NAND, GMI, INVALID, RSVD, INPUT, 0x31d4),
- PINGROUP(GMI_CS1_N, GMI, RSVD1, NAND, GMI, DTV, RSVD, INPUT, 0x31d8),
- PINGROUP(GMI_CS2_N, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31dc),
- PINGROUP(GMI_CS3_N, GMI, RSVD1, NAND, GMI, GMI_ALT, RSVD, INPUT, 0x31e0),
- PINGROUP(GMI_CS4_N, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31e4),
- PINGROUP(GMI_CS6_N, GMI, NAND, NAND_ALT, GMI, SATA, RSVD, INPUT, 0x31e8),
- PINGROUP(GMI_CS7_N, GMI, NAND, NAND_ALT, GMI, GMI_ALT, RSVD, INPUT, 0x31ec),
- PINGROUP(GMI_AD0, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31f0),
- PINGROUP(GMI_AD1, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31f4),
- PINGROUP(GMI_AD2, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31f8),
- PINGROUP(GMI_AD3, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x31fc),
- PINGROUP(GMI_AD4, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x3200),
- PINGROUP(GMI_AD5, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x3204),
- PINGROUP(GMI_AD6, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x3208),
- PINGROUP(GMI_AD7, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x320c),
- PINGROUP(GMI_AD8, GMI, PWM0, NAND, GMI, RSVD2, RSVD, INPUT, 0x3210),
- PINGROUP(GMI_AD9, GMI, PWM1, NAND, GMI, RSVD2, RSVD, INPUT, 0x3214),
- PINGROUP(GMI_AD10, GMI, PWM2, NAND, GMI, RSVD2, RSVD, INPUT, 0x3218),
- PINGROUP(GMI_AD11, GMI, PWM3, NAND, GMI, RSVD2, RSVD, INPUT, 0x321c),
- PINGROUP(GMI_AD12, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x3220),
- PINGROUP(GMI_AD13, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x3224),
- PINGROUP(GMI_AD14, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x3228),
- PINGROUP(GMI_AD15, GMI, RSVD1, NAND, GMI, RSVD2, RSVD, INPUT, 0x322c),
- PINGROUP(GMI_A16, GMI, UARTD, SPI4, GMI, GMI_ALT, RSVD, INPUT, 0x3230),
- PINGROUP(GMI_A17, GMI, UARTD, SPI4, GMI, INVALID, RSVD, INPUT, 0x3234),
- PINGROUP(GMI_A18, GMI, UARTD, SPI4, GMI, INVALID, RSVD, INPUT, 0x3238),
- PINGROUP(GMI_A19, GMI, UARTD, SPI4, GMI, RSVD3, RSVD, INPUT, 0x323c),
- PINGROUP(GMI_WR_N, GMI, RSVD1, NAND, GMI, RSVD3, RSVD, INPUT, 0x3240),
- PINGROUP(GMI_OE_N, GMI, RSVD1, NAND, GMI, RSVD3, RSVD, INPUT, 0x3244),
- PINGROUP(GMI_DQS, GMI, RSVD1, NAND, GMI, RSVD3, RSVD, INPUT, 0x3248),
- PINGROUP(GMI_RST_N, GMI, NAND, NAND_ALT, GMI, RSVD3, RSVD, INPUT, 0x324c),
- PINGROUP(GEN2_I2C_SCL, GMI, I2C2, INVALID, GMI, RSVD3, RSVD, INPUT, 0x3250),
- PINGROUP(GEN2_I2C_SDA, GMI, I2C2, INVALID, GMI, RSVD3, RSVD, INPUT, 0x3254),
- PINGROUP(SDMMC4_CLK, SDMMC4, INVALID, NAND, GMI, SDIO4, RSVD, INPUT, 0x3258),
- PINGROUP(SDMMC4_CMD, SDMMC4, I2C3, NAND, GMI, SDIO4, RSVD, INPUT, 0x325c),
- PINGROUP(SDMMC4_DAT0, SDMMC4, UARTE, SPI3, GMI, SDIO4, RSVD, INPUT, 0x3260),
- PINGROUP(SDMMC4_DAT1, SDMMC4, UARTE, SPI3, GMI, SDIO4, RSVD, INPUT, 0x3264),
- PINGROUP(SDMMC4_DAT2, SDMMC4, UARTE, SPI3, GMI, SDIO4, RSVD, INPUT, 0x3268),
- PINGROUP(SDMMC4_DAT3, SDMMC4, UARTE, SPI3, GMI, SDIO4, RSVD, INPUT, 0x326c),
- PINGROUP(SDMMC4_DAT4, SDMMC4, I2C3, I2S4, GMI, SDIO4, RSVD, INPUT, 0x3270),
- PINGROUP(SDMMC4_DAT5, SDMMC4, VGP3, I2S4, GMI, SDIO4, RSVD, INPUT, 0x3274),
- PINGROUP(SDMMC4_DAT6, SDMMC4, VGP4, I2S4, GMI, SDIO4, RSVD, INPUT, 0x3278),
- PINGROUP(SDMMC4_DAT7, SDMMC4, VGP5, I2S4, GMI, SDIO4, RSVD, INPUT, 0x327c),
- PINGROUP(SDMMC4_RST_N, SDMMC4, VGP6, RSVD1, RSVD2, POPSDMMC4, RSVD, INPUT, 0x3280),
- PINGROUP(CAM_MCLK, CAM, VI, INVALID, VI_ALT2, POPSDMMC4, RSVD, INPUT, 0x3284),
- PINGROUP(GPIO_PCC1, CAM, I2S4, RSVD1, RSVD2, POPSDMMC4, RSVD, INPUT, 0x3288),
- PINGROUP(GPIO_PBB0, CAM, I2S4, RSVD1, RSVD2, POPSDMMC4, RSVD, INPUT, 0x328c),
- PINGROUP(CAM_I2C_SCL, CAM, INVALID, I2C3, RSVD2, POPSDMMC4, RSVD, INPUT, 0x3290),
- PINGROUP(CAM_I2C_SDA, CAM, INVALID, I2C3, RSVD2, POPSDMMC4, RSVD, INPUT, 0x3294),
- PINGROUP(GPIO_PBB3, CAM, VGP3, DISPLAYA, DISPLAYB, POPSDMMC4, RSVD, INPUT, 0x3298),
- PINGROUP(GPIO_PBB4, CAM, VGP4, DISPLAYA, DISPLAYB, POPSDMMC4, RSVD, INPUT, 0x329c),
- PINGROUP(GPIO_PBB5, CAM, VGP5, DISPLAYA, DISPLAYB, POPSDMMC4, RSVD, INPUT, 0x32a0),
- PINGROUP(GPIO_PBB6, CAM, VGP6, DISPLAYA, DISPLAYB, POPSDMMC4, RSVD, INPUT, 0x32a4),
- PINGROUP(GPIO_PBB7, CAM, I2S4, RSVD1, RSVD2, POPSDMMC4, RSVD, INPUT, 0x32a8),
- PINGROUP(GPIO_PCC2, CAM, I2S4, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x32ac),
- PINGROUP(JTAG_RTCK, SYS, RTCK, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x32b0),
- PINGROUP(PWR_I2C_SCL, SYS, I2CPWR, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x32b4),
- PINGROUP(PWR_I2C_SDA, SYS, I2CPWR, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x32b8),
- PINGROUP(KB_ROW0, SYS, KBC, INVALID, RSVD2, RSVD3, RSVD, INPUT, 0x32bc),
- PINGROUP(KB_ROW1, SYS, KBC, INVALID, RSVD2, RSVD3, RSVD, INPUT, 0x32c0),
- PINGROUP(KB_ROW2, SYS, KBC, INVALID, RSVD2, RSVD3, RSVD, INPUT, 0x32c4),
- PINGROUP(KB_ROW3, SYS, KBC, INVALID, RSVD2, INVALID, RSVD, INPUT, 0x32c8),
- PINGROUP(KB_ROW4, SYS, KBC, INVALID, TRACE, RSVD3, RSVD, INPUT, 0x32cc),
- PINGROUP(KB_ROW5, SYS, KBC, INVALID, TRACE, OWR, RSVD, INPUT, 0x32d0),
- PINGROUP(KB_ROW6, SYS, KBC, INVALID, SDIO2, INVALID, RSVD, INPUT, 0x32d4),
- PINGROUP(KB_ROW7, SYS, KBC, INVALID, SDIO2, INVALID, RSVD, INPUT, 0x32d8),
- PINGROUP(KB_ROW8, SYS, KBC, INVALID, SDIO2, INVALID, RSVD, INPUT, 0x32dc),
- PINGROUP(KB_ROW9, SYS, KBC, INVALID, SDIO2, INVALID, RSVD, INPUT, 0x32e0),
- PINGROUP(KB_ROW10, SYS, KBC, INVALID, SDIO2, INVALID, RSVD, INPUT, 0x32e4),
- PINGROUP(KB_ROW11, SYS, KBC, INVALID, SDIO2, INVALID, RSVD, INPUT, 0x32e8),
- PINGROUP(KB_ROW12, SYS, KBC, INVALID, SDIO2, INVALID, RSVD, INPUT, 0x32ec),
- PINGROUP(KB_ROW13, SYS, KBC, INVALID, SDIO2, INVALID, RSVD, INPUT, 0x32f0),
- PINGROUP(KB_ROW14, SYS, KBC, INVALID, SDIO2, INVALID, RSVD, INPUT, 0x32f4),
- PINGROUP(KB_ROW15, SYS, KBC, INVALID, SDIO2, INVALID, RSVD, INPUT, 0x32f8),
- PINGROUP(KB_COL0, SYS, KBC, INVALID, TRACE, INVALID, RSVD, INPUT, 0x32fc),
- PINGROUP(KB_COL1, SYS, KBC, INVALID, TRACE, INVALID, RSVD, INPUT, 0x3300),
- PINGROUP(KB_COL2, SYS, KBC, INVALID, TRACE, RSVD, RSVD, INPUT, 0x3304),
- PINGROUP(KB_COL3, SYS, KBC, INVALID, TRACE, RSVD, RSVD, INPUT, 0x3308),
- PINGROUP(KB_COL4, SYS, KBC, INVALID, TRACE, RSVD, RSVD, INPUT, 0x330c),
- PINGROUP(KB_COL5, SYS, KBC, INVALID, TRACE, RSVD, RSVD, INPUT, 0x3310),
- PINGROUP(KB_COL6, SYS, KBC, INVALID, TRACE, INVALID, RSVD, INPUT, 0x3314),
- PINGROUP(KB_COL7, SYS, KBC, INVALID, TRACE, INVALID, RSVD, INPUT, 0x3318),
- PINGROUP(CLK_32K_OUT, SYS, BLINK, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x331c),
- PINGROUP(SYS_CLK_REQ, SYS, SYSCLK, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x3320),
- PINGROUP(CORE_PWR_REQ, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, INPUT, 0x3324),
- PINGROUP(CPU_PWR_REQ, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, INPUT, 0x3328),
- PINGROUP(PWR_INT_N, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, INPUT, 0x332c),
- PINGROUP(CLK_32K_IN, SYS, RSVD, RSVD, RSVD, RSVD, RSVD, INPUT, 0x3330),
- PINGROUP(OWR, SYS, OWR, RSVD, RSVD, RSVD, RSVD, INPUT, 0x3334),
- PINGROUP(DAP1_FS, AUDIO, I2S0, HDA, GMI, SDIO2, RSVD, INPUT, 0x3338),
- PINGROUP(DAP1_DIN, AUDIO, I2S0, HDA, GMI, SDIO2, RSVD, INPUT, 0x333c),
- PINGROUP(DAP1_DOUT, AUDIO, I2S0, HDA, GMI, SDIO2, RSVD, INPUT, 0x3340),
- PINGROUP(DAP1_SCLK, AUDIO, I2S0, HDA, GMI, SDIO2, RSVD, INPUT, 0x3344),
- PINGROUP(CLK1_REQ, AUDIO, DAP, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x3348),
- PINGROUP(CLK1_OUT, AUDIO, EXTPERIPH1, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x334c),
- PINGROUP(SPDIF_IN, AUDIO, SPDIF, HDA, INVALID, DAPSDMMC2, RSVD, INPUT, 0x3350),
- PINGROUP(SPDIF_OUT, AUDIO, SPDIF, RSVD1, INVALID, DAPSDMMC2, RSVD, INPUT, 0x3354),
- PINGROUP(DAP2_FS, AUDIO, I2S1, HDA, RSVD2, GMI, RSVD, INPUT, 0x3358),
- PINGROUP(DAP2_DIN, AUDIO, I2S1, HDA, RSVD2, GMI, RSVD, INPUT, 0x335c),
- PINGROUP(DAP2_DOUT, AUDIO, I2S1, HDA, RSVD2, GMI, RSVD, INPUT, 0x3360),
- PINGROUP(DAP2_SCLK, AUDIO, I2S1, HDA, RSVD2, GMI, RSVD, INPUT, 0x3364),
- PINGROUP(SPI2_MOSI, AUDIO, SPI6, SPI2, INVALID, GMI, RSVD, INPUT, 0x3368),
- PINGROUP(SPI2_MISO, AUDIO, SPI6, SPI2, INVALID, GMI, RSVD, INPUT, 0x336c),
- PINGROUP(SPI2_CS0_N, AUDIO, SPI6, SPI2, INVALID, GMI, RSVD, INPUT, 0x3370),
- PINGROUP(SPI2_SCK, AUDIO, SPI6, SPI2, INVALID, GMI, RSVD, INPUT, 0x3374),
- PINGROUP(SPI1_MOSI, AUDIO, SPI2, SPI1, INVALID, GMI, RSVD, INPUT, 0x3378),
- PINGROUP(SPI1_SCK, AUDIO, SPI2, SPI1, INVALID, GMI, RSVD, INPUT, 0x337c),
- PINGROUP(SPI1_CS0_N, AUDIO, SPI2, SPI1, INVALID, GMI, RSVD, INPUT, 0x3380),
- PINGROUP(SPI1_MISO, AUDIO, INVALID, SPI1, INVALID, RSVD3, RSVD, INPUT, 0x3384),
- PINGROUP(SPI2_CS1_N, AUDIO, INVALID, SPI2, INVALID, INVALID, RSVD, INPUT, 0x3388),
- PINGROUP(SPI2_CS2_N, AUDIO, INVALID, SPI2, INVALID, INVALID, RSVD, INPUT, 0x338c),
- PINGROUP(SDMMC3_CLK, SDMMC3, UARTA, PWM2, SDIO3, INVALID, RSVD, INPUT, 0x3390),
- PINGROUP(SDMMC3_CMD, SDMMC3, UARTA, PWM3, SDIO3, INVALID, RSVD, INPUT, 0x3394),
- PINGROUP(SDMMC3_DAT0, SDMMC3, RSVD, RSVD1, SDIO3, INVALID, RSVD, INPUT, 0x3398),
- PINGROUP(SDMMC3_DAT1, SDMMC3, RSVD, RSVD1, SDIO3, INVALID, RSVD, INPUT, 0x339c),
- PINGROUP(SDMMC3_DAT2, SDMMC3, RSVD, PWM1, SDIO3, INVALID, RSVD, INPUT, 0x33a0),
- PINGROUP(SDMMC3_DAT3, SDMMC3, RSVD, PWM0, SDIO3, INVALID, RSVD, INPUT, 0x33a4),
- PINGROUP(SDMMC3_DAT4, SDMMC3, PWM1, INVALID, SDIO3, INVALID, RSVD, INPUT, 0x33a8),
- PINGROUP(SDMMC3_DAT5, SDMMC3, PWM0, INVALID, SDIO3, INVALID, RSVD, INPUT, 0x33ac),
- PINGROUP(SDMMC3_DAT6, SDMMC3, SPDIF, INVALID, SDIO3, INVALID, RSVD, INPUT, 0x33b0),
- PINGROUP(SDMMC3_DAT7, SDMMC3, SPDIF, INVALID, SDIO3, INVALID, RSVD, INPUT, 0x33b4),
- PINGROUP(PEX_L0_PRSNT_N, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33b8),
- PINGROUP(PEX_L0_RST_N, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33bc),
- PINGROUP(PEX_L0_CLKREQ_N, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33c0),
- PINGROUP(PEX_WAKE_N, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33c4),
- PINGROUP(PEX_L1_PRSNT_N, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33c8),
- PINGROUP(PEX_L1_RST_N, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33cc),
- PINGROUP(PEX_L1_CLKREQ_N, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33d0),
- PINGROUP(PEX_L2_PRSNT_N, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33d4),
- PINGROUP(PEX_L2_RST_N, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33d8),
- PINGROUP(PEX_L2_CLKREQ_N, PEXCTL, PCIE, HDA, RSVD2, RSVD3, RSVD, INPUT, 0x33dc),
- PINGROUP(HDMI_CEC, SYS, CEC, RSVD1, RSVD2, RSVD3, RSVD, INPUT, 0x33e0),
-};
-
-void __devinit tegra30_pinmux_init(const struct tegra_pingroup_desc **pg,
- int *pg_max, const struct tegra_drive_pingroup_desc **pgdrive,
- int *pgdrive_max)
-{
- *pg = tegra_soc_pingroups;
- *pg_max = TEGRA_MAX_PINGROUP;
- *pgdrive = tegra_soc_drive_pingroups;
- *pgdrive_max = TEGRA_MAX_DRIVE_PINGROUP;
-}
-
diff --git a/arch/arm/mach-tegra/pinmux.c b/arch/arm/mach-tegra/pinmux.c
deleted file mode 100644
index ac35d2b76850..000000000000
--- a/arch/arm/mach-tegra/pinmux.c
+++ /dev/null
@@ -1,987 +0,0 @@
-/*
- * linux/arch/arm/mach-tegra/pinmux.c
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/of_device.h>
-
-#include <mach/iomap.h>
-#include <mach/pinmux.h>
-
-#define HSM_EN(reg) (((reg) >> 2) & 0x1)
-#define SCHMT_EN(reg) (((reg) >> 3) & 0x1)
-#define LPMD(reg) (((reg) >> 4) & 0x3)
-#define DRVDN(reg) (((reg) >> 12) & 0x1f)
-#define DRVUP(reg) (((reg) >> 20) & 0x1f)
-#define SLWR(reg) (((reg) >> 28) & 0x3)
-#define SLWF(reg) (((reg) >> 30) & 0x3)
-
-static const struct tegra_pingroup_desc *pingroups;
-static const struct tegra_drive_pingroup_desc *drive_pingroups;
-static int pingroup_max;
-static int drive_max;
-
-static char *tegra_mux_names[TEGRA_MAX_MUX] = {
- [TEGRA_MUX_AHB_CLK] = "AHB_CLK",
- [TEGRA_MUX_APB_CLK] = "APB_CLK",
- [TEGRA_MUX_AUDIO_SYNC] = "AUDIO_SYNC",
- [TEGRA_MUX_CRT] = "CRT",
- [TEGRA_MUX_DAP1] = "DAP1",
- [TEGRA_MUX_DAP2] = "DAP2",
- [TEGRA_MUX_DAP3] = "DAP3",
- [TEGRA_MUX_DAP4] = "DAP4",
- [TEGRA_MUX_DAP5] = "DAP5",
- [TEGRA_MUX_DISPLAYA] = "DISPLAYA",
- [TEGRA_MUX_DISPLAYB] = "DISPLAYB",
- [TEGRA_MUX_EMC_TEST0_DLL] = "EMC_TEST0_DLL",
- [TEGRA_MUX_EMC_TEST1_DLL] = "EMC_TEST1_DLL",
- [TEGRA_MUX_GMI] = "GMI",
- [TEGRA_MUX_GMI_INT] = "GMI_INT",
- [TEGRA_MUX_HDMI] = "HDMI",
- [TEGRA_MUX_I2C] = "I2C",
- [TEGRA_MUX_I2C2] = "I2C2",
- [TEGRA_MUX_I2C3] = "I2C3",
- [TEGRA_MUX_IDE] = "IDE",
- [TEGRA_MUX_IRDA] = "IRDA",
- [TEGRA_MUX_KBC] = "KBC",
- [TEGRA_MUX_MIO] = "MIO",
- [TEGRA_MUX_MIPI_HS] = "MIPI_HS",
- [TEGRA_MUX_NAND] = "NAND",
- [TEGRA_MUX_OSC] = "OSC",
- [TEGRA_MUX_OWR] = "OWR",
- [TEGRA_MUX_PCIE] = "PCIE",
- [TEGRA_MUX_PLLA_OUT] = "PLLA_OUT",
- [TEGRA_MUX_PLLC_OUT1] = "PLLC_OUT1",
- [TEGRA_MUX_PLLM_OUT1] = "PLLM_OUT1",
- [TEGRA_MUX_PLLP_OUT2] = "PLLP_OUT2",
- [TEGRA_MUX_PLLP_OUT3] = "PLLP_OUT3",
- [TEGRA_MUX_PLLP_OUT4] = "PLLP_OUT4",
- [TEGRA_MUX_PWM] = "PWM",
- [TEGRA_MUX_PWR_INTR] = "PWR_INTR",
- [TEGRA_MUX_PWR_ON] = "PWR_ON",
- [TEGRA_MUX_RTCK] = "RTCK",
- [TEGRA_MUX_SDIO1] = "SDIO1",
- [TEGRA_MUX_SDIO2] = "SDIO2",
- [TEGRA_MUX_SDIO3] = "SDIO3",
- [TEGRA_MUX_SDIO4] = "SDIO4",
- [TEGRA_MUX_SFLASH] = "SFLASH",
- [TEGRA_MUX_SPDIF] = "SPDIF",
- [TEGRA_MUX_SPI1] = "SPI1",
- [TEGRA_MUX_SPI2] = "SPI2",
- [TEGRA_MUX_SPI2_ALT] = "SPI2_ALT",
- [TEGRA_MUX_SPI3] = "SPI3",
- [TEGRA_MUX_SPI4] = "SPI4",
- [TEGRA_MUX_TRACE] = "TRACE",
- [TEGRA_MUX_TWC] = "TWC",
- [TEGRA_MUX_UARTA] = "UARTA",
- [TEGRA_MUX_UARTB] = "UARTB",
- [TEGRA_MUX_UARTC] = "UARTC",
- [TEGRA_MUX_UARTD] = "UARTD",
- [TEGRA_MUX_UARTE] = "UARTE",
- [TEGRA_MUX_ULPI] = "ULPI",
- [TEGRA_MUX_VI] = "VI",
- [TEGRA_MUX_VI_SENSOR_CLK] = "VI_SENSOR_CLK",
- [TEGRA_MUX_XIO] = "XIO",
- [TEGRA_MUX_BLINK] = "BLINK",
- [TEGRA_MUX_CEC] = "CEC",
- [TEGRA_MUX_CLK12] = "CLK12",
- [TEGRA_MUX_DAP] = "DAP",
- [TEGRA_MUX_DAPSDMMC2] = "DAPSDMMC2",
- [TEGRA_MUX_DDR] = "DDR",
- [TEGRA_MUX_DEV3] = "DEV3",
- [TEGRA_MUX_DTV] = "DTV",
- [TEGRA_MUX_VI_ALT1] = "VI_ALT1",
- [TEGRA_MUX_VI_ALT2] = "VI_ALT2",
- [TEGRA_MUX_VI_ALT3] = "VI_ALT3",
- [TEGRA_MUX_EMC_DLL] = "EMC_DLL",
- [TEGRA_MUX_EXTPERIPH1] = "EXTPERIPH1",
- [TEGRA_MUX_EXTPERIPH2] = "EXTPERIPH2",
- [TEGRA_MUX_EXTPERIPH3] = "EXTPERIPH3",
- [TEGRA_MUX_GMI_ALT] = "GMI_ALT",
- [TEGRA_MUX_HDA] = "HDA",
- [TEGRA_MUX_HSI] = "HSI",
- [TEGRA_MUX_I2C4] = "I2C4",
- [TEGRA_MUX_I2C5] = "I2C5",
- [TEGRA_MUX_I2CPWR] = "I2CPWR",
- [TEGRA_MUX_I2S0] = "I2S0",
- [TEGRA_MUX_I2S1] = "I2S1",
- [TEGRA_MUX_I2S2] = "I2S2",
- [TEGRA_MUX_I2S3] = "I2S3",
- [TEGRA_MUX_I2S4] = "I2S4",
- [TEGRA_MUX_NAND_ALT] = "NAND_ALT",
- [TEGRA_MUX_POPSDIO4] = "POPSDIO4",
- [TEGRA_MUX_POPSDMMC4] = "POPSDMMC4",
- [TEGRA_MUX_PWM0] = "PWM0",
- [TEGRA_MUX_PWM1] = "PWM2",
- [TEGRA_MUX_PWM2] = "PWM2",
- [TEGRA_MUX_PWM3] = "PWM3",
- [TEGRA_MUX_SATA] = "SATA",
- [TEGRA_MUX_SPI5] = "SPI5",
- [TEGRA_MUX_SPI6] = "SPI6",
- [TEGRA_MUX_SYSCLK] = "SYSCLK",
- [TEGRA_MUX_VGP1] = "VGP1",
- [TEGRA_MUX_VGP2] = "VGP2",
- [TEGRA_MUX_VGP3] = "VGP3",
- [TEGRA_MUX_VGP4] = "VGP4",
- [TEGRA_MUX_VGP5] = "VGP5",
- [TEGRA_MUX_VGP6] = "VGP6",
- [TEGRA_MUX_SAFE] = "<safe>",
-};
-
-static const char *tegra_drive_names[TEGRA_MAX_DRIVE] = {
- [TEGRA_DRIVE_DIV_8] = "DIV_8",
- [TEGRA_DRIVE_DIV_4] = "DIV_4",
- [TEGRA_DRIVE_DIV_2] = "DIV_2",
- [TEGRA_DRIVE_DIV_1] = "DIV_1",
-};
-
-static const char *tegra_slew_names[TEGRA_MAX_SLEW] = {
- [TEGRA_SLEW_FASTEST] = "FASTEST",
- [TEGRA_SLEW_FAST] = "FAST",
- [TEGRA_SLEW_SLOW] = "SLOW",
- [TEGRA_SLEW_SLOWEST] = "SLOWEST",
-};
-
-static DEFINE_SPINLOCK(mux_lock);
-
-static const char *pingroup_name(int pg)
-{
- if (pg < 0 || pg >= pingroup_max)
- return "<UNKNOWN>";
-
- return pingroups[pg].name;
-}
-
-static const char *func_name(enum tegra_mux_func func)
-{
- if (func == TEGRA_MUX_RSVD1)
- return "RSVD1";
-
- if (func == TEGRA_MUX_RSVD2)
- return "RSVD2";
-
- if (func == TEGRA_MUX_RSVD3)
- return "RSVD3";
-
- if (func == TEGRA_MUX_RSVD4)
- return "RSVD4";
-
- if (func == TEGRA_MUX_NONE)
- return "NONE";
-
- if (func < 0 || func >= TEGRA_MAX_MUX)
- return "<UNKNOWN>";
-
- return tegra_mux_names[func];
-}
-
-
-static const char *tri_name(unsigned long val)
-{
- return val ? "TRISTATE" : "NORMAL";
-}
-
-static const char *pupd_name(unsigned long val)
-{
- switch (val) {
- case 0:
- return "NORMAL";
-
- case 1:
- return "PULL_DOWN";
-
- case 2:
- return "PULL_UP";
-
- default:
- return "RSVD";
- }
-}
-
-static int nbanks;
-static void __iomem **regs;
-
-static inline u32 pg_readl(u32 bank, u32 reg)
-{
- return readl(regs[bank] + reg);
-}
-
-static inline void pg_writel(u32 val, u32 bank, u32 reg)
-{
- writel(val, regs[bank] + reg);
-}
-
-static int tegra_pinmux_set_func(const struct tegra_pingroup_config *config)
-{
- int mux = -1;
- int i;
- unsigned long reg;
- unsigned long flags;
- int pg = config->pingroup;
- enum tegra_mux_func func = config->func;
-
- if (pg < 0 || pg >= pingroup_max)
- return -ERANGE;
-
- if (pingroups[pg].mux_reg < 0)
- return -EINVAL;
-
- if (func < 0)
- return -ERANGE;
-
- if (func == TEGRA_MUX_SAFE)
- func = pingroups[pg].func_safe;
-
- if (func & TEGRA_MUX_RSVD) {
- mux = func & 0x3;
- } else {
- for (i = 0; i < 4; i++) {
- if (pingroups[pg].funcs[i] == func) {
- mux = i;
- break;
- }
- }
- }
-
- if (mux < 0)
- return -EINVAL;
-
- spin_lock_irqsave(&mux_lock, flags);
-
- reg = pg_readl(pingroups[pg].mux_bank, pingroups[pg].mux_reg);
- reg &= ~(0x3 << pingroups[pg].mux_bit);
- reg |= mux << pingroups[pg].mux_bit;
- pg_writel(reg, pingroups[pg].mux_bank, pingroups[pg].mux_reg);
-
- spin_unlock_irqrestore(&mux_lock, flags);
-
- return 0;
-}
-
-int tegra_pinmux_set_tristate(int pg, enum tegra_tristate tristate)
-{
- unsigned long reg;
- unsigned long flags;
-
- if (pg < 0 || pg >= pingroup_max)
- return -ERANGE;
-
- if (pingroups[pg].tri_reg < 0)
- return -EINVAL;
-
- spin_lock_irqsave(&mux_lock, flags);
-
- reg = pg_readl(pingroups[pg].tri_bank, pingroups[pg].tri_reg);
- reg &= ~(0x1 << pingroups[pg].tri_bit);
- if (tristate)
- reg |= 1 << pingroups[pg].tri_bit;
- pg_writel(reg, pingroups[pg].tri_bank, pingroups[pg].tri_reg);
-
- spin_unlock_irqrestore(&mux_lock, flags);
-
- return 0;
-}
-
-int tegra_pinmux_set_pullupdown(int pg, enum tegra_pullupdown pupd)
-{
- unsigned long reg;
- unsigned long flags;
-
- if (pg < 0 || pg >= pingroup_max)
- return -ERANGE;
-
- if (pingroups[pg].pupd_reg < 0)
- return -EINVAL;
-
- if (pupd != TEGRA_PUPD_NORMAL &&
- pupd != TEGRA_PUPD_PULL_DOWN &&
- pupd != TEGRA_PUPD_PULL_UP)
- return -EINVAL;
-
-
- spin_lock_irqsave(&mux_lock, flags);
-
- reg = pg_readl(pingroups[pg].pupd_bank, pingroups[pg].pupd_reg);
- reg &= ~(0x3 << pingroups[pg].pupd_bit);
- reg |= pupd << pingroups[pg].pupd_bit;
- pg_writel(reg, pingroups[pg].pupd_bank, pingroups[pg].pupd_reg);
-
- spin_unlock_irqrestore(&mux_lock, flags);
-
- return 0;
-}
-
-static void tegra_pinmux_config_pingroup(const struct tegra_pingroup_config *config)
-{
- int pingroup = config->pingroup;
- enum tegra_mux_func func = config->func;
- enum tegra_pullupdown pupd = config->pupd;
- enum tegra_tristate tristate = config->tristate;
- int err;
-
- if (pingroups[pingroup].mux_reg >= 0) {
- err = tegra_pinmux_set_func(config);
- if (err < 0)
- pr_err("pinmux: can't set pingroup %s func to %s: %d\n",
- pingroup_name(pingroup), func_name(func), err);
- }
-
- if (pingroups[pingroup].pupd_reg >= 0) {
- err = tegra_pinmux_set_pullupdown(pingroup, pupd);
- if (err < 0)
- pr_err("pinmux: can't set pingroup %s pullupdown to %s: %d\n",
- pingroup_name(pingroup), pupd_name(pupd), err);
- }
-
- if (pingroups[pingroup].tri_reg >= 0) {
- err = tegra_pinmux_set_tristate(pingroup, tristate);
- if (err < 0)
- pr_err("pinmux: can't set pingroup %s tristate to %s: %d\n",
- pingroup_name(pingroup), tri_name(func), err);
- }
-}
-
-void tegra_pinmux_config_table(const struct tegra_pingroup_config *config, int len)
-{
- int i;
-
- for (i = 0; i < len; i++)
- tegra_pinmux_config_pingroup(&config[i]);
-}
-
-static const char *drive_pinmux_name(int pg)
-{
- if (pg < 0 || pg >= drive_max)
- return "<UNKNOWN>";
-
- return drive_pingroups[pg].name;
-}
-
-static const char *enable_name(unsigned long val)
-{
- return val ? "ENABLE" : "DISABLE";
-}
-
-static const char *drive_name(unsigned long val)
-{
- if (val >= TEGRA_MAX_DRIVE)
- return "<UNKNOWN>";
-
- return tegra_drive_names[val];
-}
-
-static const char *slew_name(unsigned long val)
-{
- if (val >= TEGRA_MAX_SLEW)
- return "<UNKNOWN>";
-
- return tegra_slew_names[val];
-}
-
-static int tegra_drive_pinmux_set_hsm(int pg, enum tegra_hsm hsm)
-{
- unsigned long flags;
- u32 reg;
- if (pg < 0 || pg >= drive_max)
- return -ERANGE;
-
- if (hsm != TEGRA_HSM_ENABLE && hsm != TEGRA_HSM_DISABLE)
- return -EINVAL;
-
- spin_lock_irqsave(&mux_lock, flags);
-
- reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
- if (hsm == TEGRA_HSM_ENABLE)
- reg |= (1 << 2);
- else
- reg &= ~(1 << 2);
- pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
-
- spin_unlock_irqrestore(&mux_lock, flags);
-
- return 0;
-}
-
-static int tegra_drive_pinmux_set_schmitt(int pg, enum tegra_schmitt schmitt)
-{
- unsigned long flags;
- u32 reg;
- if (pg < 0 || pg >= drive_max)
- return -ERANGE;
-
- if (schmitt != TEGRA_SCHMITT_ENABLE && schmitt != TEGRA_SCHMITT_DISABLE)
- return -EINVAL;
-
- spin_lock_irqsave(&mux_lock, flags);
-
- reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
- if (schmitt == TEGRA_SCHMITT_ENABLE)
- reg |= (1 << 3);
- else
- reg &= ~(1 << 3);
- pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
-
- spin_unlock_irqrestore(&mux_lock, flags);
-
- return 0;
-}
-
-static int tegra_drive_pinmux_set_drive(int pg, enum tegra_drive drive)
-{
- unsigned long flags;
- u32 reg;
- if (pg < 0 || pg >= drive_max)
- return -ERANGE;
-
- if (drive < 0 || drive >= TEGRA_MAX_DRIVE)
- return -EINVAL;
-
- spin_lock_irqsave(&mux_lock, flags);
-
- reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
- reg &= ~(0x3 << 4);
- reg |= drive << 4;
- pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
-
- spin_unlock_irqrestore(&mux_lock, flags);
-
- return 0;
-}
-
-static int tegra_drive_pinmux_set_pull_down(int pg,
- enum tegra_pull_strength pull_down)
-{
- unsigned long flags;
- u32 reg;
- if (pg < 0 || pg >= drive_max)
- return -ERANGE;
-
- if (pull_down < 0 || pull_down >= TEGRA_MAX_PULL)
- return -EINVAL;
-
- spin_lock_irqsave(&mux_lock, flags);
-
- reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
- reg &= ~(0x1f << 12);
- reg |= pull_down << 12;
- pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
-
- spin_unlock_irqrestore(&mux_lock, flags);
-
- return 0;
-}
-
-static int tegra_drive_pinmux_set_pull_up(int pg,
- enum tegra_pull_strength pull_up)
-{
- unsigned long flags;
- u32 reg;
- if (pg < 0 || pg >= drive_max)
- return -ERANGE;
-
- if (pull_up < 0 || pull_up >= TEGRA_MAX_PULL)
- return -EINVAL;
-
- spin_lock_irqsave(&mux_lock, flags);
-
- reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
- reg &= ~(0x1f << 12);
- reg |= pull_up << 12;
- pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
-
- spin_unlock_irqrestore(&mux_lock, flags);
-
- return 0;
-}
-
-static int tegra_drive_pinmux_set_slew_rising(int pg,
- enum tegra_slew slew_rising)
-{
- unsigned long flags;
- u32 reg;
- if (pg < 0 || pg >= drive_max)
- return -ERANGE;
-
- if (slew_rising < 0 || slew_rising >= TEGRA_MAX_SLEW)
- return -EINVAL;
-
- spin_lock_irqsave(&mux_lock, flags);
-
- reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
- reg &= ~(0x3 << 28);
- reg |= slew_rising << 28;
- pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
-
- spin_unlock_irqrestore(&mux_lock, flags);
-
- return 0;
-}
-
-static int tegra_drive_pinmux_set_slew_falling(int pg,
- enum tegra_slew slew_falling)
-{
- unsigned long flags;
- u32 reg;
- if (pg < 0 || pg >= drive_max)
- return -ERANGE;
-
- if (slew_falling < 0 || slew_falling >= TEGRA_MAX_SLEW)
- return -EINVAL;
-
- spin_lock_irqsave(&mux_lock, flags);
-
- reg = pg_readl(drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
- reg &= ~(0x3 << 30);
- reg |= slew_falling << 30;
- pg_writel(reg, drive_pingroups[pg].reg_bank, drive_pingroups[pg].reg);
-
- spin_unlock_irqrestore(&mux_lock, flags);
-
- return 0;
-}
-
-static void tegra_drive_pinmux_config_pingroup(int pingroup,
- enum tegra_hsm hsm,
- enum tegra_schmitt schmitt,
- enum tegra_drive drive,
- enum tegra_pull_strength pull_down,
- enum tegra_pull_strength pull_up,
- enum tegra_slew slew_rising,
- enum tegra_slew slew_falling)
-{
- int err;
-
- err = tegra_drive_pinmux_set_hsm(pingroup, hsm);
- if (err < 0)
- pr_err("pinmux: can't set pingroup %s hsm to %s: %d\n",
- drive_pinmux_name(pingroup),
- enable_name(hsm), err);
-
- err = tegra_drive_pinmux_set_schmitt(pingroup, schmitt);
- if (err < 0)
- pr_err("pinmux: can't set pingroup %s schmitt to %s: %d\n",
- drive_pinmux_name(pingroup),
- enable_name(schmitt), err);
-
- err = tegra_drive_pinmux_set_drive(pingroup, drive);
- if (err < 0)
- pr_err("pinmux: can't set pingroup %s drive to %s: %d\n",
- drive_pinmux_name(pingroup),
- drive_name(drive), err);
-
- err = tegra_drive_pinmux_set_pull_down(pingroup, pull_down);
- if (err < 0)
- pr_err("pinmux: can't set pingroup %s pull down to %d: %d\n",
- drive_pinmux_name(pingroup),
- pull_down, err);
-
- err = tegra_drive_pinmux_set_pull_up(pingroup, pull_up);
- if (err < 0)
- pr_err("pinmux: can't set pingroup %s pull up to %d: %d\n",
- drive_pinmux_name(pingroup),
- pull_up, err);
-
- err = tegra_drive_pinmux_set_slew_rising(pingroup, slew_rising);
- if (err < 0)
- pr_err("pinmux: can't set pingroup %s rising slew to %s: %d\n",
- drive_pinmux_name(pingroup),
- slew_name(slew_rising), err);
-
- err = tegra_drive_pinmux_set_slew_falling(pingroup, slew_falling);
- if (err < 0)
- pr_err("pinmux: can't set pingroup %s falling slew to %s: %d\n",
- drive_pinmux_name(pingroup),
- slew_name(slew_falling), err);
-}
-
-void tegra_drive_pinmux_config_table(struct tegra_drive_pingroup_config *config,
- int len)
-{
- int i;
-
- for (i = 0; i < len; i++)
- tegra_drive_pinmux_config_pingroup(config[i].pingroup,
- config[i].hsm,
- config[i].schmitt,
- config[i].drive,
- config[i].pull_down,
- config[i].pull_up,
- config[i].slew_rising,
- config[i].slew_falling);
-}
-
-void tegra_pinmux_set_safe_pinmux_table(const struct tegra_pingroup_config *config,
- int len)
-{
- int i;
- struct tegra_pingroup_config c;
-
- for (i = 0; i < len; i++) {
- int err;
- c = config[i];
- if (c.pingroup < 0 || c.pingroup >= pingroup_max) {
- WARN_ON(1);
- continue;
- }
- c.func = pingroups[c.pingroup].func_safe;
- err = tegra_pinmux_set_func(&c);
- if (err < 0)
- pr_err("%s: tegra_pinmux_set_func returned %d setting "
- "%s to %s\n", __func__, err,
- pingroup_name(c.pingroup), func_name(c.func));
- }
-}
-
-void tegra_pinmux_config_pinmux_table(const struct tegra_pingroup_config *config,
- int len)
-{
- int i;
-
- for (i = 0; i < len; i++) {
- int err;
- if (config[i].pingroup < 0 ||
- config[i].pingroup >= pingroup_max) {
- WARN_ON(1);
- continue;
- }
- err = tegra_pinmux_set_func(&config[i]);
- if (err < 0)
- pr_err("%s: tegra_pinmux_set_func returned %d setting "
- "%s to %s\n", __func__, err,
- pingroup_name(config[i].pingroup),
- func_name(config[i].func));
- }
-}
-
-void tegra_pinmux_config_tristate_table(const struct tegra_pingroup_config *config,
- int len, enum tegra_tristate tristate)
-{
- int i;
- int err;
- int pingroup;
-
- for (i = 0; i < len; i++) {
- pingroup = config[i].pingroup;
- if (pingroups[pingroup].tri_reg >= 0) {
- err = tegra_pinmux_set_tristate(pingroup, tristate);
- if (err < 0)
- pr_err("pinmux: can't set pingroup %s tristate"
- " to %s: %d\n", pingroup_name(pingroup),
- tri_name(tristate), err);
- }
- }
-}
-
-void tegra_pinmux_config_pullupdown_table(const struct tegra_pingroup_config *config,
- int len, enum tegra_pullupdown pupd)
-{
- int i;
- int err;
- int pingroup;
-
- for (i = 0; i < len; i++) {
- pingroup = config[i].pingroup;
- if (pingroups[pingroup].pupd_reg >= 0) {
- err = tegra_pinmux_set_pullupdown(pingroup, pupd);
- if (err < 0)
- pr_err("pinmux: can't set pingroup %s pullupdown"
- " to %s: %d\n", pingroup_name(pingroup),
- pupd_name(pupd), err);
- }
- }
-}
-
-static struct of_device_id tegra_pinmux_of_match[] __devinitdata = {
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- { .compatible = "nvidia,tegra20-pinmux", tegra20_pinmux_init },
-#endif
-#ifdef CONFIG_ARCH_TEGRA_3x_SOC
- { .compatible = "nvidia,tegra30-pinmux", tegra30_pinmux_init },
-#endif
- { },
-};
-
-static int __devinit tegra_pinmux_probe(struct platform_device *pdev)
-{
- struct resource *res;
- int i;
- int config_bad = 0;
- const struct of_device_id *match;
-
- match = of_match_device(tegra_pinmux_of_match, &pdev->dev);
-
- if (match)
- ((pinmux_init)(match->data))(&pingroups, &pingroup_max,
- &drive_pingroups, &drive_max);
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- else
- /* no device tree available, so we must be on tegra20 */
- tegra20_pinmux_init(&pingroups, &pingroup_max,
- &drive_pingroups, &drive_max);
-#else
- pr_warn("non Tegra20 platform requires pinmux devicetree node\n");
-#endif
-
- for (i = 0; ; i++) {
- res = platform_get_resource(pdev, IORESOURCE_MEM, i);
- if (!res)
- break;
- }
- nbanks = i;
-
- for (i = 0; i < pingroup_max; i++) {
- if (pingroups[i].tri_bank >= nbanks) {
- dev_err(&pdev->dev, "pingroup %d: bad tri_bank\n", i);
- config_bad = 1;
- }
-
- if (pingroups[i].mux_bank >= nbanks) {
- dev_err(&pdev->dev, "pingroup %d: bad mux_bank\n", i);
- config_bad = 1;
- }
-
- if (pingroups[i].pupd_bank >= nbanks) {
- dev_err(&pdev->dev, "pingroup %d: bad pupd_bank\n", i);
- config_bad = 1;
- }
- }
-
- for (i = 0; i < drive_max; i++) {
- if (drive_pingroups[i].reg_bank >= nbanks) {
- dev_err(&pdev->dev,
- "drive pingroup %d: bad reg_bank\n", i);
- config_bad = 1;
- }
- }
-
- if (config_bad)
- return -ENODEV;
-
- regs = devm_kzalloc(&pdev->dev, nbanks * sizeof(*regs), GFP_KERNEL);
- if (!regs) {
- dev_err(&pdev->dev, "Can't alloc regs pointer\n");
- return -ENODEV;
- }
-
- for (i = 0; i < nbanks; i++) {
- res = platform_get_resource(pdev, IORESOURCE_MEM, i);
- if (!res) {
- dev_err(&pdev->dev, "Missing MEM resource\n");
- return -ENODEV;
- }
-
- if (!devm_request_mem_region(&pdev->dev, res->start,
- resource_size(res),
- dev_name(&pdev->dev))) {
- dev_err(&pdev->dev,
- "Couldn't request MEM resource %d\n", i);
- return -ENODEV;
- }
-
- regs[i] = devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
- if (!regs) {
- dev_err(&pdev->dev, "Couldn't ioremap regs %d\n", i);
- return -ENODEV;
- }
- }
-
- return 0;
-}
-
-static struct platform_driver tegra_pinmux_driver = {
- .driver = {
- .name = "tegra-pinmux",
- .owner = THIS_MODULE,
- .of_match_table = tegra_pinmux_of_match,
- },
- .probe = tegra_pinmux_probe,
-};
-
-static int __init tegra_pinmux_init(void)
-{
- return platform_driver_register(&tegra_pinmux_driver);
-}
-postcore_initcall(tegra_pinmux_init);
-
-#ifdef CONFIG_DEBUG_FS
-
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-
-static void dbg_pad_field(struct seq_file *s, int len)
-{
- seq_putc(s, ',');
-
- while (len-- > -1)
- seq_putc(s, ' ');
-}
-
-static int dbg_pinmux_show(struct seq_file *s, void *unused)
-{
- int i;
- int len;
-
- for (i = 0; i < pingroup_max; i++) {
- unsigned long reg;
- unsigned long tri;
- unsigned long mux;
- unsigned long pupd;
-
- seq_printf(s, "\t{TEGRA_PINGROUP_%s", pingroups[i].name);
- len = strlen(pingroups[i].name);
- dbg_pad_field(s, 5 - len);
-
- if (pingroups[i].mux_reg < 0) {
- seq_printf(s, "TEGRA_MUX_NONE");
- len = strlen("NONE");
- } else {
- reg = pg_readl(pingroups[i].mux_bank,
- pingroups[i].mux_reg);
- mux = (reg >> pingroups[i].mux_bit) & 0x3;
- if (pingroups[i].funcs[mux] == TEGRA_MUX_RSVD) {
- seq_printf(s, "TEGRA_MUX_RSVD%1lu", mux+1);
- len = 5;
- } else {
- seq_printf(s, "TEGRA_MUX_%s",
- tegra_mux_names[pingroups[i].funcs[mux]]);
- len = strlen(tegra_mux_names[pingroups[i].funcs[mux]]);
- }
- }
- dbg_pad_field(s, 13-len);
-
- if (pingroups[i].pupd_reg < 0) {
- seq_printf(s, "TEGRA_PUPD_NORMAL");
- len = strlen("NORMAL");
- } else {
- reg = pg_readl(pingroups[i].pupd_bank,
- pingroups[i].pupd_reg);
- pupd = (reg >> pingroups[i].pupd_bit) & 0x3;
- seq_printf(s, "TEGRA_PUPD_%s", pupd_name(pupd));
- len = strlen(pupd_name(pupd));
- }
- dbg_pad_field(s, 9 - len);
-
- if (pingroups[i].tri_reg < 0) {
- seq_printf(s, "TEGRA_TRI_NORMAL");
- } else {
- reg = pg_readl(pingroups[i].tri_bank,
- pingroups[i].tri_reg);
- tri = (reg >> pingroups[i].tri_bit) & 0x1;
-
- seq_printf(s, "TEGRA_TRI_%s", tri_name(tri));
- }
- seq_printf(s, "},\n");
- }
- return 0;
-}
-
-static int dbg_pinmux_open(struct inode *inode, struct file *file)
-{
- return single_open(file, dbg_pinmux_show, &inode->i_private);
-}
-
-static const struct file_operations debug_fops = {
- .open = dbg_pinmux_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int dbg_drive_pinmux_show(struct seq_file *s, void *unused)
-{
- int i;
- int len;
-
- for (i = 0; i < drive_max; i++) {
- u32 reg;
-
- seq_printf(s, "\t{TEGRA_DRIVE_PINGROUP_%s",
- drive_pingroups[i].name);
- len = strlen(drive_pingroups[i].name);
- dbg_pad_field(s, 7 - len);
-
-
- reg = pg_readl(drive_pingroups[i].reg_bank,
- drive_pingroups[i].reg);
- if (HSM_EN(reg)) {
- seq_printf(s, "TEGRA_HSM_ENABLE");
- len = 16;
- } else {
- seq_printf(s, "TEGRA_HSM_DISABLE");
- len = 17;
- }
- dbg_pad_field(s, 17 - len);
-
- if (SCHMT_EN(reg)) {
- seq_printf(s, "TEGRA_SCHMITT_ENABLE");
- len = 21;
- } else {
- seq_printf(s, "TEGRA_SCHMITT_DISABLE");
- len = 22;
- }
- dbg_pad_field(s, 22 - len);
-
- seq_printf(s, "TEGRA_DRIVE_%s", drive_name(LPMD(reg)));
- len = strlen(drive_name(LPMD(reg)));
- dbg_pad_field(s, 5 - len);
-
- seq_printf(s, "TEGRA_PULL_%d", DRVDN(reg));
- len = DRVDN(reg) < 10 ? 1 : 2;
- dbg_pad_field(s, 2 - len);
-
- seq_printf(s, "TEGRA_PULL_%d", DRVUP(reg));
- len = DRVUP(reg) < 10 ? 1 : 2;
- dbg_pad_field(s, 2 - len);
-
- seq_printf(s, "TEGRA_SLEW_%s", slew_name(SLWR(reg)));
- len = strlen(slew_name(SLWR(reg)));
- dbg_pad_field(s, 7 - len);
-
- seq_printf(s, "TEGRA_SLEW_%s", slew_name(SLWF(reg)));
-
- seq_printf(s, "},\n");
- }
- return 0;
-}
-
-static int dbg_drive_pinmux_open(struct inode *inode, struct file *file)
-{
- return single_open(file, dbg_drive_pinmux_show, &inode->i_private);
-}
-
-static const struct file_operations debug_drive_fops = {
- .open = dbg_drive_pinmux_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int __init tegra_pinmux_debuginit(void)
-{
- (void) debugfs_create_file("tegra_pinmux", S_IRUGO,
- NULL, NULL, &debug_fops);
- (void) debugfs_create_file("tegra_pinmux_drive", S_IRUGO,
- NULL, NULL, &debug_drive_fops);
- return 0;
-}
-late_initcall(tegra_pinmux_debuginit);
-#endif
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 592a4eeb5328..bae09b859891 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -1764,6 +1764,12 @@ static struct clk_pll_freq_table tegra_pll_x_freq_table[] = {
{ 19200000, 760000000, 950, 24, 1, 8},
{ 26000000, 760000000, 760, 26, 1, 12},
+ /* 750 MHz */
+ { 12000000, 750000000, 750, 12, 1, 12},
+ { 13000000, 750000000, 750, 13, 1, 12},
+ { 19200000, 750000000, 625, 16, 1, 8},
+ { 26000000, 750000000, 750, 26, 1, 12},
+
/* 608 MHz */
{ 12000000, 608000000, 608, 12, 1, 12},
{ 13000000, 608000000, 608, 13, 1, 12},
@@ -2142,8 +2148,8 @@ static struct clk tegra_list_clks[] = {
PERIPH_CLK("apbdma", "tegra-dma", NULL, 34, 0, 108000000, mux_pclk, 0),
PERIPH_CLK("rtc", "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET),
PERIPH_CLK("timer", "timer", NULL, 5, 0, 26000000, mux_clk_m, 0),
- PERIPH_CLK("i2s1", "tegra-i2s.0", NULL, 11, 0x100, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
- PERIPH_CLK("i2s2", "tegra-i2s.1", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
+ PERIPH_CLK("i2s1", "tegra20-i2s.0", NULL, 11, 0x100, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
+ PERIPH_CLK("i2s2", "tegra20-i2s.1", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
PERIPH_CLK("spdif_out", "spdif_out", NULL, 10, 0x108, 100000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71),
PERIPH_CLK("spdif_in", "spdif_in", NULL, 10, 0x10c, 100000000, mux_pllp_pllc_pllm, MUX | DIV_U71),
PERIPH_CLK("pwm", "pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_audio_clkm_clk32, MUX | DIV_U71),
diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c
index c5b2ac04e2a0..d71d2fed6721 100644
--- a/arch/arm/mach-tegra/usb_phy.c
+++ b/arch/arm/mach-tegra/usb_phy.c
@@ -711,7 +711,6 @@ struct tegra_usb_phy *tegra_usb_phy_open(int instance, void __iomem *regs,
err = -ENXIO;
goto err1;
}
- tegra_gpio_enable(ulpi_config->reset_gpio);
gpio_request(ulpi_config->reset_gpio, "ulpi_phy_reset_b");
gpio_direction_output(ulpi_config->reset_gpio, 0);
phy->ulpi = otg_ulpi_create(&ulpi_viewport_access_ops, 0);
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index ef7099eea0f2..53d3d46dec12 100644
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -9,10 +9,8 @@ config UX500_SOC_COMMON
select ARM_ERRATA_754322
select ARM_ERRATA_764369
select CACHE_L2X0
-
-config UX500_SOC_DB5500
- bool
- select MFD_DB5500_PRCMU
+ select PINCTRL
+ select PINCTRL_NOMADIK
config UX500_SOC_DB8500
bool
@@ -20,6 +18,7 @@ config UX500_SOC_DB8500
select REGULATOR
select REGULATOR_DB8500_PRCMU
select CPU_FREQ_TABLE if CPU_FREQ
+ select PINCTRL_DB8500
menu "Ux500 target platform (boards)"
@@ -45,15 +44,8 @@ config MACH_SNOWBALL
help
Include support for the snowball development platform.
-config MACH_U5500
- bool "U5500 Development platform"
- select UX500_SOC_DB5500
- help
- Include support for the U5500 development platform.
-
config UX500_AUTO_PLATFORM
def_bool y
- depends on !MACH_U5500
select MACH_MOP500
help
At least one platform needs to be selected in order to build
@@ -74,18 +66,4 @@ config UX500_DEBUG_UART
Choose the UART on which kernel low-level debug messages should be
output.
-config U5500_MODEM_IRQ
- bool "Modem IRQ support"
- depends on UX500_SOC_DB5500
- default y
- help
- Add support for handling IRQ:s from modem side
-
-config U5500_MBOX
- bool "Mailbox support"
- depends on U5500_MODEM_IRQ
- default y
- help
- Add support for U5500 mailbox communication with modem side
-
endif
diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile
index 465b9ec9510a..026086ff9e6c 100644
--- a/arch/arm/mach-ux500/Makefile
+++ b/arch/arm/mach-ux500/Makefile
@@ -4,17 +4,14 @@
obj-y := clock.o cpu.o devices.o devices-common.o \
id.o usb.o timer.o
+obj-$(CONFIG_CPU_IDLE) += cpuidle.o
obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o
-obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o dma-db5500.o
obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o
obj-$(CONFIG_MACH_MOP500) += board-mop500.o board-mop500-sdi.o \
board-mop500-regulators.o \
board-mop500-uib.o board-mop500-stuib.o \
board-mop500-u8500uib.o \
- board-mop500-pins.o
-obj-$(CONFIG_MACH_U5500) += board-u5500.o board-u5500-sdi.o
+ board-mop500-pins.o \
+ board-mop500-msp.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
-obj-$(CONFIG_U5500_MODEM_IRQ) += modem-irq-db5500.o
-obj-$(CONFIG_U5500_MBOX) += mbox-db5500.o
-
diff --git a/arch/arm/mach-ux500/board-mop500-msp.c b/arch/arm/mach-ux500/board-mop500-msp.c
new file mode 100644
index 000000000000..996048038743
--- /dev/null
+++ b/arch/arm/mach-ux500/board-mop500-msp.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
+
+#include <plat/gpio-nomadik.h>
+#include <plat/pincfg.h>
+#include <plat/ste_dma40.h>
+
+#include <mach/devices.h>
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/msp.h>
+
+#include "ste-dma40-db8500.h"
+#include "board-mop500.h"
+#include "devices-db8500.h"
+#include "pins-db8500.h"
+
+/* MSP1/3 Tx/Rx usage protection */
+static DEFINE_SPINLOCK(msp_rxtx_lock);
+
+/* Reference Count */
+static int msp_rxtx_ref;
+
+/* Pin modes */
+struct pinctrl *msp1_p;
+struct pinctrl_state *msp1_def;
+struct pinctrl_state *msp1_sleep;
+
+int msp13_i2s_init(void)
+{
+ int retval = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&msp_rxtx_lock, flags);
+ if (msp_rxtx_ref == 0 && !(IS_ERR(msp1_p) || IS_ERR(msp1_def))) {
+ retval = pinctrl_select_state(msp1_p, msp1_def);
+ if (retval)
+ pr_err("could not set MSP1 defstate\n");
+ }
+ if (!retval)
+ msp_rxtx_ref++;
+ spin_unlock_irqrestore(&msp_rxtx_lock, flags);
+
+ return retval;
+}
+
+int msp13_i2s_exit(void)
+{
+ int retval = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&msp_rxtx_lock, flags);
+ WARN_ON(!msp_rxtx_ref);
+ msp_rxtx_ref--;
+ if (msp_rxtx_ref == 0 && !(IS_ERR(msp1_p) || IS_ERR(msp1_sleep))) {
+ retval = pinctrl_select_state(msp1_p, msp1_sleep);
+ if (retval)
+ pr_err("could not set MSP1 sleepstate\n");
+ }
+ spin_unlock_irqrestore(&msp_rxtx_lock, flags);
+
+ return retval;
+}
+
+static struct stedma40_chan_cfg msp0_dma_rx = {
+ .high_priority = true,
+ .dir = STEDMA40_PERIPH_TO_MEM,
+
+ .src_dev_type = DB8500_DMA_DEV31_MSP0_RX_SLIM0_CH0_RX,
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+
+ .src_info.psize = STEDMA40_PSIZE_LOG_4,
+ .dst_info.psize = STEDMA40_PSIZE_LOG_4,
+
+ /* data_width is set during configuration */
+};
+
+static struct stedma40_chan_cfg msp0_dma_tx = {
+ .high_priority = true,
+ .dir = STEDMA40_MEM_TO_PERIPH,
+
+ .src_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .dst_dev_type = DB8500_DMA_DEV31_MSP0_TX_SLIM0_CH0_TX,
+
+ .src_info.psize = STEDMA40_PSIZE_LOG_4,
+ .dst_info.psize = STEDMA40_PSIZE_LOG_4,
+
+ /* data_width is set during configuration */
+};
+
+static struct msp_i2s_platform_data msp0_platform_data = {
+ .id = MSP_I2S_0,
+ .msp_i2s_dma_rx = &msp0_dma_rx,
+ .msp_i2s_dma_tx = &msp0_dma_tx,
+};
+
+static struct stedma40_chan_cfg msp1_dma_rx = {
+ .high_priority = true,
+ .dir = STEDMA40_PERIPH_TO_MEM,
+
+ .src_dev_type = DB8500_DMA_DEV30_MSP3_RX,
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+
+ .src_info.psize = STEDMA40_PSIZE_LOG_4,
+ .dst_info.psize = STEDMA40_PSIZE_LOG_4,
+
+ /* data_width is set during configuration */
+};
+
+static struct stedma40_chan_cfg msp1_dma_tx = {
+ .high_priority = true,
+ .dir = STEDMA40_MEM_TO_PERIPH,
+
+ .src_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .dst_dev_type = DB8500_DMA_DEV30_MSP1_TX,
+
+ .src_info.psize = STEDMA40_PSIZE_LOG_4,
+ .dst_info.psize = STEDMA40_PSIZE_LOG_4,
+
+ /* data_width is set during configuration */
+};
+
+static struct msp_i2s_platform_data msp1_platform_data = {
+ .id = MSP_I2S_1,
+ .msp_i2s_dma_rx = NULL,
+ .msp_i2s_dma_tx = &msp1_dma_tx,
+ .msp_i2s_init = msp13_i2s_init,
+ .msp_i2s_exit = msp13_i2s_exit,
+};
+
+static struct stedma40_chan_cfg msp2_dma_rx = {
+ .high_priority = true,
+ .dir = STEDMA40_PERIPH_TO_MEM,
+
+ .src_dev_type = DB8500_DMA_DEV14_MSP2_RX,
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+
+ /* MSP2 DMA doesn't work with PSIZE == 4 on DB8500v2 */
+ .src_info.psize = STEDMA40_PSIZE_LOG_1,
+ .dst_info.psize = STEDMA40_PSIZE_LOG_1,
+
+ /* data_width is set during configuration */
+};
+
+static struct stedma40_chan_cfg msp2_dma_tx = {
+ .high_priority = true,
+ .dir = STEDMA40_MEM_TO_PERIPH,
+
+ .src_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .dst_dev_type = DB8500_DMA_DEV14_MSP2_TX,
+
+ .src_info.psize = STEDMA40_PSIZE_LOG_4,
+ .dst_info.psize = STEDMA40_PSIZE_LOG_4,
+
+ .use_fixed_channel = true,
+ .phy_channel = 1,
+
+ /* data_width is set during configuration */
+};
+
+static struct platform_device *db8500_add_msp_i2s(struct device *parent,
+ int id,
+ resource_size_t base, int irq,
+ struct msp_i2s_platform_data *pdata)
+{
+ struct platform_device *pdev;
+ struct resource res[] = {
+ DEFINE_RES_MEM(base, SZ_4K),
+ DEFINE_RES_IRQ(irq),
+ };
+
+ pr_info("Register platform-device 'ux500-msp-i2s', id %d, irq %d\n",
+ id, irq);
+ pdev = platform_device_register_resndata(parent, "ux500-msp-i2s", id,
+ res, ARRAY_SIZE(res),
+ pdata, sizeof(*pdata));
+ if (!pdev) {
+ pr_err("Failed to register platform-device 'ux500-msp-i2s.%d'!\n",
+ id);
+ return NULL;
+ }
+
+ return pdev;
+}
+
+/* Platform device for ASoC U8500 machine */
+static struct platform_device snd_soc_u8500 = {
+ .name = "snd-soc-u8500",
+ .id = 0,
+ .dev = {
+ .platform_data = NULL,
+ },
+};
+
+/* Platform device for Ux500-PCM */
+static struct platform_device ux500_pcm = {
+ .name = "ux500-pcm",
+ .id = 0,
+ .dev = {
+ .platform_data = NULL,
+ },
+};
+
+static struct msp_i2s_platform_data msp2_platform_data = {
+ .id = MSP_I2S_2,
+ .msp_i2s_dma_rx = &msp2_dma_rx,
+ .msp_i2s_dma_tx = &msp2_dma_tx,
+};
+
+static struct msp_i2s_platform_data msp3_platform_data = {
+ .id = MSP_I2S_3,
+ .msp_i2s_dma_rx = &msp1_dma_rx,
+ .msp_i2s_dma_tx = NULL,
+ .msp_i2s_init = msp13_i2s_init,
+ .msp_i2s_exit = msp13_i2s_exit,
+};
+
+int mop500_msp_init(struct device *parent)
+{
+ struct platform_device *msp1;
+
+ pr_info("%s: Register platform-device 'snd-soc-u8500'.\n", __func__);
+ platform_device_register(&snd_soc_u8500);
+
+ pr_info("Initialize MSP I2S-devices.\n");
+ db8500_add_msp_i2s(parent, 0, U8500_MSP0_BASE, IRQ_DB8500_MSP0,
+ &msp0_platform_data);
+ msp1 = db8500_add_msp_i2s(parent, 1, U8500_MSP1_BASE, IRQ_DB8500_MSP1,
+ &msp1_platform_data);
+ db8500_add_msp_i2s(parent, 2, U8500_MSP2_BASE, IRQ_DB8500_MSP2,
+ &msp2_platform_data);
+ db8500_add_msp_i2s(parent, 3, U8500_MSP3_BASE, IRQ_DB8500_MSP1,
+ &msp3_platform_data);
+
+ /* Get the pinctrl handle for MSP1 */
+ if (msp1) {
+ msp1_p = pinctrl_get(&msp1->dev);
+ if (IS_ERR(msp1_p))
+ dev_err(&msp1->dev, "could not get MSP1 pinctrl\n");
+ else {
+ msp1_def = pinctrl_lookup_state(msp1_p,
+ PINCTRL_STATE_DEFAULT);
+ if (IS_ERR(msp1_def)) {
+ dev_err(&msp1->dev,
+ "could not get MSP1 defstate\n");
+ }
+ msp1_sleep = pinctrl_lookup_state(msp1_p,
+ PINCTRL_STATE_SLEEP);
+ if (IS_ERR(msp1_sleep))
+ dev_err(&msp1->dev,
+ "could not get MSP1 idlestate\n");
+ }
+ }
+
+ pr_info("%s: Register platform-device 'ux500-pcm'\n", __func__);
+ platform_device_register(&ux500_pcm);
+
+ return 0;
+}
diff --git a/arch/arm/mach-ux500/board-mop500-msp.h b/arch/arm/mach-ux500/board-mop500-msp.h
new file mode 100644
index 000000000000..6fcfb5e2cc94
--- /dev/null
+++ b/arch/arm/mach-ux500/board-mop500-msp.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ * for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * 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.
+ */
+
+void mop500_msp_init(struct device *parent);
diff --git a/arch/arm/mach-ux500/board-mop500-pins.c b/arch/arm/mach-ux500/board-mop500-pins.c
index f5413dca532c..32fd99204464 100644
--- a/arch/arm/mach-ux500/board-mop500-pins.c
+++ b/arch/arm/mach-ux500/board-mop500-pins.c
@@ -7,299 +7,508 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/bug.h>
+#include <linux/string.h>
+#include <linux/pinctrl/machine.h>
#include <asm/mach-types.h>
#include <plat/pincfg.h>
#include <plat/gpio-nomadik.h>
+
#include <mach/hardware.h>
#include "pins-db8500.h"
+#include "board-mop500.h"
-static pin_cfg_t mop500_pins_common[] = {
- /* I2C */
- GPIO147_I2C0_SCL,
- GPIO148_I2C0_SDA,
- GPIO16_I2C1_SCL,
- GPIO17_I2C1_SDA,
- GPIO10_I2C2_SDA,
- GPIO11_I2C2_SCL,
- GPIO229_I2C3_SDA,
- GPIO230_I2C3_SCL,
-
- /* MSP0 */
- GPIO12_MSP0_TXD,
- GPIO13_MSP0_TFS,
- GPIO14_MSP0_TCK,
- GPIO15_MSP0_RXD,
-
- /* MSP2: HDMI */
- GPIO193_MSP2_TXD,
- GPIO194_MSP2_TCK,
- GPIO195_MSP2_TFS,
- GPIO196_MSP2_RXD | PIN_OUTPUT_LOW,
-
- /* Touch screen INTERFACE */
- GPIO84_GPIO | PIN_INPUT_PULLUP, /* TOUCH_INT1 */
-
- /* STMPE1601/tc35893 keypad IRQ */
- GPIO218_GPIO | PIN_INPUT_PULLUP,
-
- /* MMC0 (MicroSD card) */
- GPIO18_MC0_CMDDIR | PIN_OUTPUT_HIGH,
- GPIO19_MC0_DAT0DIR | PIN_OUTPUT_HIGH,
- GPIO20_MC0_DAT2DIR | PIN_OUTPUT_HIGH,
-
- GPIO22_MC0_FBCLK | PIN_INPUT_NOPULL,
- GPIO23_MC0_CLK | PIN_OUTPUT_LOW,
- GPIO24_MC0_CMD | PIN_INPUT_PULLUP,
- GPIO25_MC0_DAT0 | PIN_INPUT_PULLUP,
- GPIO26_MC0_DAT1 | PIN_INPUT_PULLUP,
- GPIO27_MC0_DAT2 | PIN_INPUT_PULLUP,
- GPIO28_MC0_DAT3 | PIN_INPUT_PULLUP,
-
- /* SDI1 (SDIO) */
- GPIO208_MC1_CLK | PIN_OUTPUT_LOW,
- GPIO209_MC1_FBCLK | PIN_INPUT_NOPULL,
- GPIO210_MC1_CMD | PIN_INPUT_PULLUP,
- GPIO211_MC1_DAT0 | PIN_INPUT_PULLUP,
- GPIO212_MC1_DAT1 | PIN_INPUT_PULLUP,
- GPIO213_MC1_DAT2 | PIN_INPUT_PULLUP,
- GPIO214_MC1_DAT3 | PIN_INPUT_PULLUP,
-
- /* MMC2 (On-board DATA INTERFACE eMMC) */
- GPIO128_MC2_CLK | PIN_OUTPUT_LOW,
- GPIO129_MC2_CMD | PIN_INPUT_PULLUP,
- GPIO130_MC2_FBCLK | PIN_INPUT_NOPULL,
- GPIO131_MC2_DAT0 | PIN_INPUT_PULLUP,
- GPIO132_MC2_DAT1 | PIN_INPUT_PULLUP,
- GPIO133_MC2_DAT2 | PIN_INPUT_PULLUP,
- GPIO134_MC2_DAT3 | PIN_INPUT_PULLUP,
- GPIO135_MC2_DAT4 | PIN_INPUT_PULLUP,
- GPIO136_MC2_DAT5 | PIN_INPUT_PULLUP,
- GPIO137_MC2_DAT6 | PIN_INPUT_PULLUP,
- GPIO138_MC2_DAT7 | PIN_INPUT_PULLUP,
-
- /* MMC4 (On-board STORAGE INTERFACE eMMC) */
- GPIO197_MC4_DAT3 | PIN_INPUT_PULLUP,
- GPIO198_MC4_DAT2 | PIN_INPUT_PULLUP,
- GPIO199_MC4_DAT1 | PIN_INPUT_PULLUP,
- GPIO200_MC4_DAT0 | PIN_INPUT_PULLUP,
- GPIO201_MC4_CMD | PIN_INPUT_PULLUP,
- GPIO202_MC4_FBCLK | PIN_INPUT_NOPULL,
- GPIO203_MC4_CLK | PIN_OUTPUT_LOW,
- GPIO204_MC4_DAT7 | PIN_INPUT_PULLUP,
- GPIO205_MC4_DAT6 | PIN_INPUT_PULLUP,
- GPIO206_MC4_DAT5 | PIN_INPUT_PULLUP,
- GPIO207_MC4_DAT4 | PIN_INPUT_PULLUP,
-
- /* SKE keypad */
- GPIO153_KP_I7,
- GPIO154_KP_I6,
- GPIO155_KP_I5,
- GPIO156_KP_I4,
- GPIO157_KP_O7,
- GPIO158_KP_O6,
- GPIO159_KP_O5,
- GPIO160_KP_O4,
- GPIO161_KP_I3,
- GPIO162_KP_I2,
- GPIO163_KP_I1,
- GPIO164_KP_I0,
- GPIO165_KP_O3,
- GPIO166_KP_O2,
- GPIO167_KP_O1,
- GPIO168_KP_O0,
+enum custom_pin_cfg_t {
+ PINS_FOR_DEFAULT,
+ PINS_FOR_U9500,
+};
- /* UART */
- /* uart-0 pins gpio configuration should be
- * kept intact to prevent glitch in tx line
- * when tty dev is opened. Later these pins
+static enum custom_pin_cfg_t pinsfor;
+
+/* These simply sets bias for pins */
+#define BIAS(a,b) static unsigned long a[] = { b }
+
+BIAS(pd, PIN_PULL_DOWN);
+BIAS(slpm_gpio_nopull, PIN_SLPM_GPIO|PIN_SLPM_INPUT_NOPULL);
+BIAS(in_nopull, PIN_INPUT_NOPULL);
+BIAS(in_nopull_sleep_nowkup, PIN_INPUT_NOPULL|PIN_SLPM_WAKEUP_DISABLE);
+BIAS(in_pu, PIN_INPUT_PULLUP);
+BIAS(in_pd, PIN_INPUT_PULLDOWN);
+BIAS(in_pd_slpm_in_pu, PIN_INPUT_PULLDOWN|PIN_SLPM_INPUT_PULLUP);
+BIAS(in_pu_slpm_out_lo, PIN_INPUT_PULLUP|PIN_SLPM_OUTPUT_LOW);
+BIAS(out_hi, PIN_OUTPUT_HIGH);
+BIAS(out_lo, PIN_OUTPUT_LOW);
+BIAS(out_lo_sleep_nowkup, PIN_OUTPUT_LOW|PIN_SLPM_WAKEUP_DISABLE);
+/* These also force them into GPIO mode */
+BIAS(gpio_in_pu, PIN_INPUT_PULLUP|PIN_GPIOMODE_ENABLED);
+BIAS(gpio_in_pd, PIN_INPUT_PULLDOWN|PIN_GPIOMODE_ENABLED);
+BIAS(gpio_in_pu_slpm_gpio_nopull, PIN_INPUT_PULLUP|PIN_GPIOMODE_ENABLED|PIN_SLPM_GPIO|PIN_SLPM_INPUT_NOPULL);
+BIAS(gpio_in_pd_slpm_gpio_nopull, PIN_INPUT_PULLDOWN|PIN_GPIOMODE_ENABLED|PIN_SLPM_GPIO|PIN_SLPM_INPUT_NOPULL);
+BIAS(gpio_out_hi, PIN_OUTPUT_HIGH|PIN_GPIOMODE_ENABLED);
+BIAS(gpio_out_lo, PIN_OUTPUT_LOW|PIN_GPIOMODE_ENABLED);
+/* Sleep modes */
+BIAS(sleep_in_wkup_pdis, PIN_SLPM_DIR_INPUT|PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_DISABLED);
+BIAS(sleep_in_nopull_wkup, PIN_INPUT_NOPULL|PIN_SLPM_WAKEUP_ENABLE);
+BIAS(sleep_out_hi_wkup_pdis, PIN_SLPM_OUTPUT_HIGH|PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_DISABLED);
+BIAS(sleep_out_lo_wkup, PIN_OUTPUT_LOW|PIN_SLPM_WAKEUP_ENABLE);
+BIAS(sleep_out_wkup_pdis, PIN_SLPM_DIR_OUTPUT|PIN_SLPM_WAKEUP_ENABLE|PIN_SLPM_PDIS_DISABLED);
+
+/* We use these to define hog settings that are always done on boot */
+#define DB8500_MUX_HOG(group,func) \
+ PIN_MAP_MUX_GROUP_HOG_DEFAULT("pinctrl-db8500", group, func)
+#define DB8500_PIN_HOG(pin,conf) \
+ PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-db8500", pin, conf)
+
+/* These are default states associated with device and changed runtime */
+#define DB8500_MUX(group,func,dev) \
+ PIN_MAP_MUX_GROUP_DEFAULT(dev, "pinctrl-db8500", group, func)
+#define DB8500_PIN(pin,conf,dev) \
+ PIN_MAP_CONFIGS_PIN_DEFAULT(dev, "pinctrl-db8500", pin, conf)
+
+#define DB8500_PIN_SLEEP(pin,conf,dev) \
+ PIN_MAP_CONFIGS_PIN(dev, PINCTRL_STATE_SLEEP, "pinctrl-db8500", \
+ pin, conf)
+
+/* Pin control settings */
+static struct pinctrl_map __initdata mop500_family_pinmap[] = {
+ /*
+ * uMSP0, mux in 4 pins, regular placement of RX/TX
+ * explicitly set the pins to no pull
+ */
+ DB8500_MUX_HOG("msp0txrx_a_1", "msp0"),
+ DB8500_MUX_HOG("msp0tfstck_a_1", "msp0"),
+ DB8500_PIN_HOG("GPIO12_AC4", in_nopull), /* TXD */
+ DB8500_PIN_HOG("GPIO15_AC3", in_nopull), /* RXD */
+ DB8500_PIN_HOG("GPIO13_AF3", in_nopull), /* TFS */
+ DB8500_PIN_HOG("GPIO14_AE3", in_nopull), /* TCK */
+ /* MSP2 for HDMI, pull down TXD, TCK, TFS */
+ DB8500_MUX_HOG("msp2_a_1", "msp2"),
+ DB8500_PIN_HOG("GPIO193_AH27", in_pd), /* TXD */
+ DB8500_PIN_HOG("GPIO194_AF27", in_pd), /* TCK */
+ DB8500_PIN_HOG("GPIO195_AG28", in_pd), /* TFS */
+ DB8500_PIN_HOG("GPIO196_AG26", out_lo), /* RXD */
+ /*
+ * LCD, set TE0 (using LCD VSI0) and D14 (touch screen interrupt) to
+ * pull-up
+ * TODO: is this really correct? Snowball doesn't have a LCD.
+ */
+ DB8500_MUX_HOG("lcdvsi0_a_1", "lcd"),
+ DB8500_PIN_HOG("GPIO68_E1", in_pu),
+ DB8500_PIN_HOG("GPIO84_C2", gpio_in_pu),
+ /*
+ * STMPE1601/tc35893 keypad IRQ GPIO 218
+ * TODO: set for snowball and HREF really??
+ */
+ DB8500_PIN_HOG("GPIO218_AH11", gpio_in_pu),
+ /*
+ * UART0, we do not mux in u0 here.
+ * uart-0 pins gpio configuration should be kept intact to prevent
+ * a glitch in tx line when the tty dev is opened. Later these pins
* are configured to uart mop500_pins_uart0
- *
- * It will be replaced with uart configuration
- * once the issue is solved.
*/
- GPIO0_GPIO | PIN_INPUT_PULLUP,
- GPIO1_GPIO | PIN_OUTPUT_HIGH,
- GPIO2_GPIO | PIN_INPUT_PULLUP,
- GPIO3_GPIO | PIN_OUTPUT_HIGH,
-
- GPIO29_U2_RXD | PIN_INPUT_PULLUP,
- GPIO30_U2_TXD | PIN_OUTPUT_HIGH,
- GPIO31_U2_CTSn | PIN_INPUT_PULLUP,
- GPIO32_U2_RTSn | PIN_OUTPUT_HIGH,
-
- /* Display & HDMI HW sync */
- GPIO68_LCD_VSI0 | PIN_INPUT_PULLUP,
- GPIO69_LCD_VSI1 | PIN_INPUT_PULLUP,
+ DB8500_PIN_HOG("GPIO0_AJ5", in_pu), /* CTS */
+ DB8500_PIN_HOG("GPIO1_AJ3", out_hi), /* RTS */
+ DB8500_PIN_HOG("GPIO2_AH4", in_pu), /* RXD */
+ DB8500_PIN_HOG("GPIO3_AH3", out_hi), /* TXD */
+ /*
+ * Mux in UART2 on altfunction C and set pull-ups.
+ * TODO: is this used on U8500 variants and Snowball really?
+ * The setting on GPIO31 conflicts with magnetometer use on hrefv60
+ */
+ DB8500_MUX_HOG("u2rxtx_c_1", "u2"),
+ DB8500_MUX_HOG("u2ctsrts_c_1", "u2"),
+ DB8500_PIN_HOG("GPIO29_W2", in_pu), /* RXD */
+ DB8500_PIN_HOG("GPIO30_W3", out_hi), /* TXD */
+ DB8500_PIN_HOG("GPIO31_V3", in_pu), /* CTS */
+ DB8500_PIN_HOG("GPIO32_V2", out_hi), /* RTS */
+ /*
+ * The following pin sets were known as "runtime pins" before being
+ * converted to the pinctrl model. Here we model them as "default"
+ * states.
+ */
+ /* Mux in UART0 after initialization */
+ DB8500_MUX("u0_a_1", "u0", "uart0"),
+ DB8500_PIN("GPIO0_AJ5", in_pu, "uart0"), /* CTS */
+ DB8500_PIN("GPIO1_AJ3", out_hi, "uart0"), /* RTS */
+ DB8500_PIN("GPIO2_AH4", in_pu, "uart0"), /* RXD */
+ DB8500_PIN("GPIO3_AH3", out_hi, "uart0"), /* TXD */
+ /* UART0 sleep state */
+ DB8500_PIN_SLEEP("GPIO0_AJ5", sleep_in_wkup_pdis, "uart0"),
+ DB8500_PIN_SLEEP("GPIO1_AJ3", sleep_out_hi_wkup_pdis, "uart0"),
+ DB8500_PIN_SLEEP("GPIO2_AH4", sleep_in_wkup_pdis, "uart0"),
+ DB8500_PIN_SLEEP("GPIO3_AH3", sleep_out_wkup_pdis, "uart0"),
+ /* MSP1 for ALSA codec */
+ DB8500_MUX("msp1txrx_a_1", "msp1", "ux500-msp-i2s.1"),
+ DB8500_MUX("msp1_a_1", "msp1", "ux500-msp-i2s.1"),
+ DB8500_PIN("GPIO33_AF2", out_lo_sleep_nowkup, "ux500-msp-i2s.1"),
+ DB8500_PIN("GPIO34_AE1", in_nopull_sleep_nowkup, "ux500-msp-i2s.1"),
+ DB8500_PIN("GPIO35_AE2", in_nopull_sleep_nowkup, "ux500-msp-i2s.1"),
+ DB8500_PIN("GPIO36_AG2", in_nopull_sleep_nowkup, "ux500-msp-i2s.1"),
+ /* MSP1 sleep state */
+ DB8500_PIN_SLEEP("GPIO33_AF2", sleep_out_lo_wkup, "ux500-msp-i2s.1"),
+ DB8500_PIN_SLEEP("GPIO34_AE1", sleep_in_nopull_wkup, "ux500-msp-i2s.1"),
+ DB8500_PIN_SLEEP("GPIO35_AE2", sleep_in_nopull_wkup, "ux500-msp-i2s.1"),
+ DB8500_PIN_SLEEP("GPIO36_AG2", sleep_in_nopull_wkup, "ux500-msp-i2s.1"),
+ /* Mux in LCD data lines 8 thru 11 and LCDA CLK for MCDE TVOUT */
+ DB8500_MUX("lcd_d8_d11_a_1", "lcd", "mcde-tvout"),
+ DB8500_MUX("lcdaclk_b_1", "lcda", "mcde-tvout"),
+ /* Mux in LCD VSI1 and pull it up for MCDE HDMI output */
+ DB8500_MUX("lcdvsi1_a_1", "lcd", "av8100-hdmi"),
+ /* Mux in I2C blocks, put pins into GPIO in sleepmode no pull-up */
+ DB8500_MUX("i2c0_a_1", "i2c0", "nmk-i2c.0"),
+ DB8500_PIN("GPIO147_C15", slpm_gpio_nopull, "nmk-i2c.0"),
+ DB8500_PIN("GPIO148_B16", slpm_gpio_nopull, "nmk-i2c.0"),
+ DB8500_MUX("i2c1_b_2", "i2c1", "nmk-i2c.1"),
+ DB8500_PIN("GPIO16_AD3", slpm_gpio_nopull, "nmk-i2c.1"),
+ DB8500_PIN("GPIO17_AD4", slpm_gpio_nopull, "nmk-i2c.1"),
+ DB8500_MUX("i2c2_b_2", "i2c2", "nmk-i2c.2"),
+ DB8500_PIN("GPIO10_AF5", slpm_gpio_nopull, "nmk-i2c.2"),
+ DB8500_PIN("GPIO11_AG4", slpm_gpio_nopull, "nmk-i2c.2"),
+ DB8500_MUX("i2c3_c_2", "i2c3", "nmk-i2c.3"),
+ DB8500_PIN("GPIO229_AG7", slpm_gpio_nopull, "nmk-i2c.3"),
+ DB8500_PIN("GPIO230_AF7", slpm_gpio_nopull, "nmk-i2c.3"),
+ /* Mux in SDI0 (here called MC0) used for removable MMC/SD/SDIO cards */
+ DB8500_MUX("mc0_a_1", "mc0", "sdi0"),
+ DB8500_PIN("GPIO18_AC2", out_hi, "sdi0"), /* CMDDIR */
+ DB8500_PIN("GPIO19_AC1", out_hi, "sdi0"), /* DAT0DIR */
+ DB8500_PIN("GPIO20_AB4", out_hi, "sdi0"), /* DAT2DIR */
+ DB8500_PIN("GPIO22_AA3", in_nopull, "sdi0"), /* FBCLK */
+ DB8500_PIN("GPIO23_AA4", out_lo, "sdi0"), /* CLK */
+ DB8500_PIN("GPIO24_AB2", in_pu, "sdi0"), /* CMD */
+ DB8500_PIN("GPIO25_Y4", in_pu, "sdi0"), /* DAT0 */
+ DB8500_PIN("GPIO26_Y2", in_pu, "sdi0"), /* DAT1 */
+ DB8500_PIN("GPIO27_AA2", in_pu, "sdi0"), /* DAT2 */
+ DB8500_PIN("GPIO28_AA1", in_pu, "sdi0"), /* DAT3 */
+ /* Mux in SDI1 (here called MC1) used for SDIO for CW1200 WLAN */
+ DB8500_MUX("mc1_a_1", "mc1", "sdi1"),
+ DB8500_PIN("GPIO208_AH16", out_lo, "sdi1"), /* CLK */
+ DB8500_PIN("GPIO209_AG15", in_nopull, "sdi1"), /* FBCLK */
+ DB8500_PIN("GPIO210_AJ15", in_pu, "sdi1"), /* CMD */
+ DB8500_PIN("GPIO211_AG14", in_pu, "sdi1"), /* DAT0 */
+ DB8500_PIN("GPIO212_AF13", in_pu, "sdi1"), /* DAT1 */
+ DB8500_PIN("GPIO213_AG13", in_pu, "sdi1"), /* DAT2 */
+ DB8500_PIN("GPIO214_AH15", in_pu, "sdi1"), /* DAT3 */
+ /* Mux in SDI2 (here called MC2) used for for PoP eMMC */
+ DB8500_MUX("mc2_a_1", "mc2", "sdi2"),
+ DB8500_PIN("GPIO128_A5", out_lo, "sdi2"), /* CLK */
+ DB8500_PIN("GPIO129_B4", in_pu, "sdi2"), /* CMD */
+ DB8500_PIN("GPIO130_C8", in_nopull, "sdi2"), /* FBCLK */
+ DB8500_PIN("GPIO131_A12", in_pu, "sdi2"), /* DAT0 */
+ DB8500_PIN("GPIO132_C10", in_pu, "sdi2"), /* DAT1 */
+ DB8500_PIN("GPIO133_B10", in_pu, "sdi2"), /* DAT2 */
+ DB8500_PIN("GPIO134_B9", in_pu, "sdi2"), /* DAT3 */
+ DB8500_PIN("GPIO135_A9", in_pu, "sdi2"), /* DAT4 */
+ DB8500_PIN("GPIO136_C7", in_pu, "sdi2"), /* DAT5 */
+ DB8500_PIN("GPIO137_A7", in_pu, "sdi2"), /* DAT6 */
+ DB8500_PIN("GPIO138_C5", in_pu, "sdi2"), /* DAT7 */
+ /* Mux in SDI4 (here called MC4) used for for PCB-mounted eMMC */
+ DB8500_MUX("mc4_a_1", "mc4", "sdi4"),
+ DB8500_PIN("GPIO197_AH24", in_pu, "sdi4"), /* DAT3 */
+ DB8500_PIN("GPIO198_AG25", in_pu, "sdi4"), /* DAT2 */
+ DB8500_PIN("GPIO199_AH23", in_pu, "sdi4"), /* DAT1 */
+ DB8500_PIN("GPIO200_AH26", in_pu, "sdi4"), /* DAT0 */
+ DB8500_PIN("GPIO201_AF24", in_pu, "sdi4"), /* CMD */
+ DB8500_PIN("GPIO202_AF25", in_nopull, "sdi4"), /* FBCLK */
+ DB8500_PIN("GPIO203_AE23", out_lo, "sdi4"), /* CLK */
+ DB8500_PIN("GPIO204_AF23", in_pu, "sdi4"), /* DAT7 */
+ DB8500_PIN("GPIO205_AG23", in_pu, "sdi4"), /* DAT6 */
+ DB8500_PIN("GPIO206_AG24", in_pu, "sdi4"), /* DAT5 */
+ DB8500_PIN("GPIO207_AJ23", in_pu, "sdi4"), /* DAT4 */
+ /* Mux in USB pins, drive STP high */
+ DB8500_MUX("usb_a_1", "usb", "musb-ux500.0"),
+ DB8500_PIN("GPIO257_AE29", out_hi, "musb-ux500.0"), /* STP */
+ /* Mux in SPI2 pins on the "other C1" altfunction */
+ DB8500_MUX("spi2_oc1_1", "spi2", "spi2"),
+ DB8500_PIN("GPIO216_AG12", gpio_out_hi, "spi2"), /* FRM */
+ DB8500_PIN("GPIO218_AH11", in_pd, "spi2"), /* RXD */
+ DB8500_PIN("GPIO215_AH13", out_lo, "spi2"), /* TXD */
+ DB8500_PIN("GPIO217_AH12", out_lo, "spi2"), /* CLK */
};
-static pin_cfg_t mop500_pins_default[] = {
- /* SSP0 */
- GPIO143_SSP0_CLK,
- GPIO144_SSP0_FRM,
- GPIO145_SSP0_RXD | PIN_PULL_DOWN,
- GPIO146_SSP0_TXD,
-
-
- GPIO217_GPIO | PIN_INPUT_PULLUP, /* TC35892 IRQ */
-
- /* SDI0 (MicroSD card) */
- GPIO21_MC0_DAT31DIR | PIN_OUTPUT_HIGH,
-
- /* UART */
- GPIO4_U1_RXD | PIN_INPUT_PULLUP,
- GPIO5_U1_TXD | PIN_OUTPUT_HIGH,
- GPIO6_U1_CTSn | PIN_INPUT_PULLUP,
- GPIO7_U1_RTSn | PIN_OUTPUT_HIGH,
+/*
+ * These are specifically for the MOP500 and HREFP (pre-v60) version of the
+ * board, which utilized a TC35892 GPIO expander instead of using a lot of
+ * on-chip pins as the HREFv60 and later does.
+ */
+static struct pinctrl_map __initdata mop500_pinmap[] = {
+ /* Mux in SSP0, pull down RXD pin */
+ DB8500_MUX_HOG("ssp0_a_1", "ssp0"),
+ DB8500_PIN_HOG("GPIO145_C13", pd),
+ /*
+ * XENON Flashgun on image processor GPIO (controlled from image
+ * processor firmware), mux in these image processor GPIO lines 0
+ * (XENON_FLASH_ID) and 1 (XENON_READY) on altfunction C and pull up
+ * the pins.
+ */
+ DB8500_MUX_HOG("ipgpio0_c_1", "ipgpio"),
+ DB8500_MUX_HOG("ipgpio1_c_1", "ipgpio"),
+ DB8500_PIN_HOG("GPIO6_AF6", in_pu),
+ DB8500_PIN_HOG("GPIO7_AG5", in_pu),
+ /* TC35892 IRQ, pull up the line, let the driver mux in the pin */
+ DB8500_PIN_HOG("GPIO217_AH12", gpio_in_pu),
+ /* Mux in UART1 and set the pull-ups */
+ DB8500_MUX_HOG("u1rxtx_a_1", "u1"),
+ DB8500_MUX_HOG("u1ctsrts_a_1", "u1"),
+ DB8500_PIN_HOG("GPIO4_AH6", in_pu), /* RXD */
+ DB8500_PIN_HOG("GPIO5_AG6", out_hi), /* TXD */
+ DB8500_PIN_HOG("GPIO6_AF6", in_pu), /* CTS */
+ DB8500_PIN_HOG("GPIO7_AG5", out_hi), /* RTS */
+ /*
+ * Runtime stuff: make it possible to mux in the SKE keypad
+ * and bias the pins
+ */
+ DB8500_MUX("kp_a_2", "kp", "ske"),
+ DB8500_PIN("GPIO153_B17", in_pd_slpm_in_pu, "ske"), /* I7 */
+ DB8500_PIN("GPIO154_C16", in_pd_slpm_in_pu, "ske"), /* I6 */
+ DB8500_PIN("GPIO155_C19", in_pd_slpm_in_pu, "ske"), /* I5 */
+ DB8500_PIN("GPIO156_C17", in_pd_slpm_in_pu, "ske"), /* I4 */
+ DB8500_PIN("GPIO161_D21", in_pd_slpm_in_pu, "ske"), /* I3 */
+ DB8500_PIN("GPIO162_D20", in_pd_slpm_in_pu, "ske"), /* I2 */
+ DB8500_PIN("GPIO163_C20", in_pd_slpm_in_pu, "ske"), /* I1 */
+ DB8500_PIN("GPIO164_B21", in_pd_slpm_in_pu, "ske"), /* I0 */
+ DB8500_PIN("GPIO157_A18", in_pu_slpm_out_lo, "ske"), /* O7 */
+ DB8500_PIN("GPIO158_C18", in_pu_slpm_out_lo, "ske"), /* O6 */
+ DB8500_PIN("GPIO159_B19", in_pu_slpm_out_lo, "ske"), /* O5 */
+ DB8500_PIN("GPIO160_B20", in_pu_slpm_out_lo, "ske"), /* O4 */
+ DB8500_PIN("GPIO165_C21", in_pu_slpm_out_lo, "ske"), /* O3 */
+ DB8500_PIN("GPIO166_A22", in_pu_slpm_out_lo, "ske"), /* O2 */
+ DB8500_PIN("GPIO167_B24", in_pu_slpm_out_lo, "ske"), /* O1 */
+ DB8500_PIN("GPIO168_C22", in_pu_slpm_out_lo, "ske"), /* O0 */
+ /* Mux in and drive the SDI0 DAT31DIR line high at runtime */
+ DB8500_MUX("mc0dat31dir_a_1", "mc0", "sdi0"),
+ DB8500_PIN("GPIO21_AB3", out_hi, "sdi0"),
};
-static pin_cfg_t hrefv60_pins[] = {
- /* WLAN */
- GPIO4_GPIO | PIN_INPUT_PULLUP,/* WLAN_IRQ */
- GPIO85_GPIO | PIN_OUTPUT_LOW,/* WLAN_ENA */
-
- /* XENON Flashgun INTERFACE */
- GPIO6_IP_GPIO0 | PIN_INPUT_PULLUP,/* XENON_FLASH_ID */
- GPIO7_IP_GPIO1 | PIN_INPUT_PULLUP,/* XENON_READY */
- GPIO170_GPIO | PIN_OUTPUT_LOW, /* XENON_CHARGE */
-
- /* Assistant LED INTERFACE */
- GPIO21_GPIO | PIN_OUTPUT_LOW, /* XENON_EN1 */
- GPIO64_IP_GPIO4 | PIN_OUTPUT_LOW, /* XENON_EN2 */
-
- /* Magnetometer */
- GPIO31_GPIO | PIN_INPUT_PULLUP, /* magnetometer_INT */
- GPIO32_GPIO | PIN_INPUT_PULLDOWN, /* Magnetometer DRDY */
-
- /* Display Interface */
- GPIO65_GPIO | PIN_OUTPUT_LOW, /* DISP1 RST */
- GPIO66_GPIO | PIN_OUTPUT_LOW, /* DISP2 RST */
-
- /* Touch screen INTERFACE */
- GPIO143_GPIO | PIN_OUTPUT_LOW,/*TOUCH_RST1 */
-
- /* Touch screen INTERFACE 2 */
- GPIO67_GPIO | PIN_INPUT_PULLUP, /* TOUCH_INT2 */
- GPIO146_GPIO | PIN_OUTPUT_LOW,/*TOUCH_RST2 */
-
- /* ETM_PTM_TRACE INTERFACE */
- GPIO70_GPIO | PIN_OUTPUT_LOW,/* ETM_PTM_DATA23 */
- GPIO71_GPIO | PIN_OUTPUT_LOW,/* ETM_PTM_DATA22 */
- GPIO72_GPIO | PIN_OUTPUT_LOW,/* ETM_PTM_DATA21 */
- GPIO73_GPIO | PIN_OUTPUT_LOW,/* ETM_PTM_DATA20 */
- GPIO74_GPIO | PIN_OUTPUT_LOW,/* ETM_PTM_DATA19 */
-
- /* NAHJ INTERFACE */
- GPIO76_GPIO | PIN_OUTPUT_LOW,/* NAHJ_CTRL */
- GPIO216_GPIO | PIN_OUTPUT_HIGH,/* NAHJ_CTRL_INV */
-
- /* NFC INTERFACE */
- GPIO77_GPIO | PIN_OUTPUT_LOW, /* NFC_ENA */
- GPIO144_GPIO | PIN_INPUT_PULLDOWN, /* NFC_IRQ */
- GPIO142_GPIO | PIN_OUTPUT_LOW, /* NFC_RESET */
-
- /* Keyboard MATRIX INTERFACE */
- GPIO90_MC5_CMD | PIN_OUTPUT_LOW, /* KP_O_1 */
- GPIO87_MC5_DAT1 | PIN_OUTPUT_LOW, /* KP_O_2 */
- GPIO86_MC5_DAT0 | PIN_OUTPUT_LOW, /* KP_O_3 */
- GPIO96_KP_O6 | PIN_OUTPUT_LOW, /* KP_O_6 */
- GPIO94_KP_O7 | PIN_OUTPUT_LOW, /* KP_O_7 */
- GPIO93_MC5_DAT4 | PIN_INPUT_PULLUP, /* KP_I_0 */
- GPIO89_MC5_DAT3 | PIN_INPUT_PULLUP, /* KP_I_2 */
- GPIO88_MC5_DAT2 | PIN_INPUT_PULLUP, /* KP_I_3 */
- GPIO91_GPIO | PIN_INPUT_PULLUP, /* FORCE_SENSING_INT */
- GPIO92_GPIO | PIN_OUTPUT_LOW, /* FORCE_SENSING_RST */
- GPIO97_GPIO | PIN_OUTPUT_LOW, /* FORCE_SENSING_WU */
-
- /* DiPro Sensor Interface */
- GPIO139_GPIO | PIN_INPUT_PULLUP, /* DIPRO_INT */
-
- /* HAL SWITCH INTERFACE */
- GPIO145_GPIO | PIN_INPUT_PULLDOWN,/* HAL_SW */
-
- /* Audio Amplifier Interface */
- GPIO149_GPIO | PIN_OUTPUT_LOW, /* VAUDIO_HF_EN */
-
- /* GBF INTERFACE */
- GPIO171_GPIO | PIN_OUTPUT_LOW, /* GBF_ENA_RESET */
-
- /* MSP : HDTV INTERFACE */
- GPIO192_GPIO | PIN_INPUT_PULLDOWN,
-
- /* ACCELEROMETER_INTERFACE */
- GPIO82_GPIO | PIN_INPUT_PULLUP, /* ACC_INT1 */
- GPIO83_GPIO | PIN_INPUT_PULLUP, /* ACC_INT2 */
-
- /* Proximity Sensor */
- GPIO217_GPIO | PIN_INPUT_PULLUP,
-
-
+/*
+ * The HREFv60 series of platforms is using available pins on the DB8500
+ * insteaf of the Toshiba I2C GPIO expander, reusing some pins like the SSP0
+ * and SSP1 ports (previously connected to the AB8500) as generic GPIO lines.
+ */
+static struct pinctrl_map __initdata hrefv60_pinmap[] = {
+ /* Drive WLAN_ENA low */
+ DB8500_PIN_HOG("GPIO85_D5", gpio_out_lo), /* WLAN_ENA */
+ /*
+ * XENON Flashgun on image processor GPIO (controlled from image
+ * processor firmware), mux in these image processor GPIO lines 0
+ * (XENON_FLASH_ID), 1 (XENON_READY) and there is an assistant
+ * LED on IP GPIO 4 (XENON_EN2) on altfunction C, that need bias
+ * from GPIO21 so pull up 0, 1 and drive 4 and GPIO21 low as output.
+ */
+ DB8500_MUX_HOG("ipgpio0_c_1", "ipgpio"),
+ DB8500_MUX_HOG("ipgpio1_c_1", "ipgpio"),
+ DB8500_MUX_HOG("ipgpio4_c_1", "ipgpio"),
+ DB8500_PIN_HOG("GPIO6_AF6", in_pu), /* XENON_FLASH_ID */
+ DB8500_PIN_HOG("GPIO7_AG5", in_pu), /* XENON_READY */
+ DB8500_PIN_HOG("GPIO21_AB3", gpio_out_lo), /* XENON_EN1 */
+ DB8500_PIN_HOG("GPIO64_F3", out_lo), /* XENON_EN2 */
+ /* Magnetometer uses GPIO 31 and 32, pull these up/down respectively */
+ DB8500_PIN_HOG("GPIO31_V3", gpio_in_pu), /* EN1 */
+ DB8500_PIN_HOG("GPIO32_V2", gpio_in_pd), /* DRDY */
+ /*
+ * Display Interface 1 uses GPIO 65 for RST (reset).
+ * Display Interface 2 uses GPIO 66 for RST (reset).
+ * Drive DISP1 reset high (not reset), driver DISP2 reset low (reset)
+ */
+ DB8500_PIN_HOG("GPIO65_F1", gpio_out_hi), /* DISP1 NO RST */
+ DB8500_PIN_HOG("GPIO66_G3", gpio_out_lo), /* DISP2 RST */
+ /*
+ * Touch screen uses GPIO 143 for RST1, GPIO 146 for RST2 and
+ * GPIO 67 for interrupts. Pull-up the IRQ line and drive both
+ * reset signals low.
+ */
+ DB8500_PIN_HOG("GPIO143_D12", gpio_out_lo), /* TOUCH_RST1 */
+ DB8500_PIN_HOG("GPIO67_G2", gpio_in_pu), /* TOUCH_INT2 */
+ DB8500_PIN_HOG("GPIO146_D13", gpio_out_lo), /* TOUCH_RST2 */
+ /*
+ * Drive D19-D23 for the ETM PTM trace interface low,
+ * (presumably pins are unconnected therefore grounded here,
+ * the "other alt C1" setting enables these pins)
+ */
+ DB8500_PIN_HOG("GPIO70_G5", gpio_out_lo),
+ DB8500_PIN_HOG("GPIO71_G4", gpio_out_lo),
+ DB8500_PIN_HOG("GPIO72_H4", gpio_out_lo),
+ DB8500_PIN_HOG("GPIO73_H3", gpio_out_lo),
+ DB8500_PIN_HOG("GPIO74_J3", gpio_out_lo),
+ /* NAHJ CTRL on GPIO 76 to low, CTRL_INV on GPIO216 to high */
+ DB8500_PIN_HOG("GPIO76_J2", gpio_out_lo), /* CTRL */
+ DB8500_PIN_HOG("GPIO216_AG12", gpio_out_hi), /* CTRL_INV */
+ /* NFC ENA and RESET to low, pulldown IRQ line */
+ DB8500_PIN_HOG("GPIO77_H1", gpio_out_lo), /* NFC_ENA */
+ DB8500_PIN_HOG("GPIO144_B13", gpio_in_pd), /* NFC_IRQ */
+ DB8500_PIN_HOG("GPIO142_C11", gpio_out_lo), /* NFC_RESET */
+ /*
+ * SKE keyboard partly on alt A and partly on "Other alt C1"
+ * Driver KP_O1,2,3,6,7 low and pull up KP_I 0,2,3 for three
+ * rows of 6 keys, then pull up force sensing interrup and
+ * drive reset and force sensing WU low.
+ */
+ DB8500_MUX_HOG("kp_a_1", "kp"),
+ DB8500_MUX_HOG("kp_oc1_1", "kp"),
+ DB8500_PIN_HOG("GPIO90_A3", out_lo), /* KP_O1 */
+ DB8500_PIN_HOG("GPIO87_B3", out_lo), /* KP_O2 */
+ DB8500_PIN_HOG("GPIO86_C6", out_lo), /* KP_O3 */
+ DB8500_PIN_HOG("GPIO96_D8", out_lo), /* KP_O6 */
+ DB8500_PIN_HOG("GPIO94_D7", out_lo), /* KP_O7 */
+ DB8500_PIN_HOG("GPIO93_B7", in_pu), /* KP_I0 */
+ DB8500_PIN_HOG("GPIO89_E6", in_pu), /* KP_I2 */
+ DB8500_PIN_HOG("GPIO88_C4", in_pu), /* KP_I3 */
+ DB8500_PIN_HOG("GPIO91_B6", gpio_in_pu), /* FORCE_SENSING_INT */
+ DB8500_PIN_HOG("GPIO92_D6", gpio_out_lo), /* FORCE_SENSING_RST */
+ DB8500_PIN_HOG("GPIO97_D9", gpio_out_lo), /* FORCE_SENSING_WU */
+ /* DiPro Sensor interrupt */
+ DB8500_PIN_HOG("GPIO139_C9", gpio_in_pu), /* DIPRO_INT */
+ /* Audio Amplifier HF enable */
+ DB8500_PIN_HOG("GPIO149_B14", gpio_out_hi), /* VAUDIO_HF_EN, enable MAX8968 */
+ /* GBF interface, pull low to reset state */
+ DB8500_PIN_HOG("GPIO171_D23", gpio_out_lo), /* GBF_ENA_RESET */
+ /* MSP : HDTV INTERFACE GPIO line */
+ DB8500_PIN_HOG("GPIO192_AJ27", gpio_in_pd),
+ /* Accelerometer interrupt lines */
+ DB8500_PIN_HOG("GPIO82_C1", gpio_in_pu), /* ACC_INT1 */
+ DB8500_PIN_HOG("GPIO83_D3", gpio_in_pu), /* ACC_INT2 */
+ /* SD card detect GPIO pin */
+ DB8500_PIN_HOG("GPIO95_E8", gpio_in_pu),
+ /*
+ * Runtime stuff
+ * Pull up/down of some sensor GPIO pins, for proximity, HAL sensor
+ * etc.
+ */
+ DB8500_PIN("GPIO217_AH12", gpio_in_pu_slpm_gpio_nopull, "gpio-keys.0"),
+ DB8500_PIN("GPIO145_C13", gpio_in_pd_slpm_gpio_nopull, "gpio-keys.0"),
+ DB8500_PIN("GPIO139_C9", gpio_in_pu_slpm_gpio_nopull, "gpio-keys.0"),
+ /*
+ * Make it possible to mux in the SKE keypad and bias the pins
+ * FIXME: what's the point with this on HREFv60? KP/SKE is already
+ * muxed in at another place! Enabling this will bork.
+ */
+ DB8500_MUX("kp_a_2", "kp", "ske"),
+ DB8500_PIN("GPIO153_B17", in_pd_slpm_in_pu, "ske"), /* I7 */
+ DB8500_PIN("GPIO154_C16", in_pd_slpm_in_pu, "ske"), /* I6 */
+ DB8500_PIN("GPIO155_C19", in_pd_slpm_in_pu, "ske"), /* I5 */
+ DB8500_PIN("GPIO156_C17", in_pd_slpm_in_pu, "ske"), /* I4 */
+ DB8500_PIN("GPIO161_D21", in_pd_slpm_in_pu, "ske"), /* I3 */
+ DB8500_PIN("GPIO162_D20", in_pd_slpm_in_pu, "ske"), /* I2 */
+ DB8500_PIN("GPIO163_C20", in_pd_slpm_in_pu, "ske"), /* I1 */
+ DB8500_PIN("GPIO164_B21", in_pd_slpm_in_pu, "ske"), /* I0 */
+ DB8500_PIN("GPIO157_A18", in_pu_slpm_out_lo, "ske"), /* O7 */
+ DB8500_PIN("GPIO158_C18", in_pu_slpm_out_lo, "ske"), /* O6 */
+ DB8500_PIN("GPIO159_B19", in_pu_slpm_out_lo, "ske"), /* O5 */
+ DB8500_PIN("GPIO160_B20", in_pu_slpm_out_lo, "ske"), /* O4 */
+ DB8500_PIN("GPIO165_C21", in_pu_slpm_out_lo, "ske"), /* O3 */
+ DB8500_PIN("GPIO166_A22", in_pu_slpm_out_lo, "ske"), /* O2 */
+ DB8500_PIN("GPIO167_B24", in_pu_slpm_out_lo, "ske"), /* O1 */
+ DB8500_PIN("GPIO168_C22", in_pu_slpm_out_lo, "ske"), /* O0 */
};
-static pin_cfg_t snowball_pins[] = {
- /* SSP0, to AB8500 */
- GPIO143_SSP0_CLK,
- GPIO144_SSP0_FRM,
- GPIO145_SSP0_RXD | PIN_PULL_DOWN,
- GPIO146_SSP0_TXD,
+static struct pinctrl_map __initdata u9500_pinmap[] = {
+ /* Mux in UART1 (just RX/TX) and set the pull-ups */
+ DB8500_MUX_HOG("u1rxtx_a_1", "u1"),
+ DB8500_PIN_HOG("GPIO4_AH6", in_pu),
+ DB8500_PIN_HOG("GPIO5_AG6", out_hi),
+ /* WLAN_IRQ line */
+ DB8500_PIN_HOG("GPIO144_B13", gpio_in_pu),
+ /* HSI */
+ DB8500_MUX_HOG("hsir_a_1", "hsi"),
+ DB8500_MUX_HOG("hsit_a_1", "hsi"),
+ DB8500_PIN_HOG("GPIO219_AG10", in_pd), /* RX FLA0 */
+ DB8500_PIN_HOG("GPIO220_AH10", in_pd), /* RX DAT0 */
+ DB8500_PIN_HOG("GPIO221_AJ11", out_lo), /* RX RDY0 */
+ DB8500_PIN_HOG("GPIO222_AJ9", out_lo), /* TX FLA0 */
+ DB8500_PIN_HOG("GPIO223_AH9", out_lo), /* TX DAT0 */
+ DB8500_PIN_HOG("GPIO224_AG9", in_pd), /* TX RDY0 */
+ DB8500_PIN_HOG("GPIO225_AG8", in_pd), /* CAWAKE0 */
+ DB8500_PIN_HOG("GPIO226_AF8", out_hi), /* ACWAKE0 */
+};
- /* MMC0: MicroSD card */
- GPIO21_MC0_DAT31DIR | PIN_OUTPUT_HIGH,
+static struct pinctrl_map __initdata u8500_pinmap[] = {
+ DB8500_PIN_HOG("GPIO226_AF8", gpio_out_lo), /* WLAN_PMU_EN */
+ DB8500_PIN_HOG("GPIO4_AH6", gpio_in_pu), /* WLAN_IRQ */
+};
- /* MMC2: LAN */
- GPIO86_SM_ADQ0,
- GPIO87_SM_ADQ1,
- GPIO88_SM_ADQ2,
- GPIO89_SM_ADQ3,
- GPIO90_SM_ADQ4,
- GPIO91_SM_ADQ5,
- GPIO92_SM_ADQ6,
- GPIO93_SM_ADQ7,
+static struct pinctrl_map __initdata snowball_pinmap[] = {
+ /* Mux in SSP0 connected to AB8500, pull down RXD pin */
+ DB8500_MUX_HOG("ssp0_a_1", "ssp0"),
+ DB8500_PIN_HOG("GPIO145_C13", pd),
+ /* Always drive the MC0 DAT31DIR line high on these boards */
+ DB8500_PIN_HOG("GPIO21_AB3", out_hi),
+ /* Mux in "SM" which is used for the SMSC911x Ethernet adapter */
+ DB8500_MUX_HOG("sm_b_1", "sm"),
+ /* Drive RSTn_LAN high */
+ DB8500_PIN_HOG("GPIO141_C12", gpio_out_hi),
+ /* Accelerometer/Magnetometer */
+ DB8500_PIN_HOG("GPIO163_C20", gpio_in_pu), /* ACCEL_IRQ1 */
+ DB8500_PIN_HOG("GPIO164_B21", gpio_in_pu), /* ACCEL_IRQ2 */
+ DB8500_PIN_HOG("GPIO165_C21", gpio_in_pu), /* MAG_DRDY */
+ /* WLAN/GBF */
+ DB8500_PIN_HOG("GPIO161_D21", gpio_out_lo), /* WLAN_PMU_EN */
+ DB8500_PIN_HOG("GPIO171_D23", gpio_out_hi), /* GBF_ENA */
+ DB8500_PIN_HOG("GPIO215_AH13", gpio_out_lo), /* WLAN_ENA */
+ DB8500_PIN_HOG("GPIO216_AG12", gpio_in_pu), /* WLAN_IRQ */
+};
- GPIO94_SM_ADVn,
- GPIO95_SM_CS0n,
- GPIO96_SM_OEn,
- GPIO97_SM_WEn,
+/*
+ * passing "pinsfor=" in kernel cmdline allows for custom
+ * configuration of GPIOs on u8500 derived boards.
+ */
+static int __init early_pinsfor(char *p)
+{
+ pinsfor = PINS_FOR_DEFAULT;
- GPIO128_SM_CKO,
- GPIO130_SM_FBCLK,
- GPIO131_SM_ADQ8,
- GPIO132_SM_ADQ9,
- GPIO133_SM_ADQ10,
- GPIO134_SM_ADQ11,
- GPIO135_SM_ADQ12,
- GPIO136_SM_ADQ13,
- GPIO137_SM_ADQ14,
- GPIO138_SM_ADQ15,
+ if (strcmp(p, "u9500-21") == 0)
+ pinsfor = PINS_FOR_U9500;
- /* RSTn_LAN */
- GPIO141_GPIO | PIN_OUTPUT_HIGH,
-};
+ return 0;
+}
+early_param("pinsfor", early_pinsfor);
-void __init mop500_pins_init(void)
+int pins_for_u9500(void)
{
- nmk_config_pins(mop500_pins_common,
- ARRAY_SIZE(mop500_pins_common));
+ if (pinsfor == PINS_FOR_U9500)
+ return 1;
- nmk_config_pins(mop500_pins_default,
- ARRAY_SIZE(mop500_pins_default));
+ return 0;
}
-void __init snowball_pins_init(void)
+static void __init mop500_href_family_pinmaps_init(void)
{
- nmk_config_pins(mop500_pins_common,
- ARRAY_SIZE(mop500_pins_common));
+ switch (pinsfor) {
+ case PINS_FOR_U9500:
+ pinctrl_register_mappings(u9500_pinmap,
+ ARRAY_SIZE(u9500_pinmap));
+ break;
+ case PINS_FOR_DEFAULT:
+ pinctrl_register_mappings(u8500_pinmap,
+ ARRAY_SIZE(u8500_pinmap));
+ default:
+ break;
+ }
+}
- nmk_config_pins(snowball_pins,
- ARRAY_SIZE(snowball_pins));
+void __init mop500_pinmaps_init(void)
+{
+ pinctrl_register_mappings(mop500_family_pinmap,
+ ARRAY_SIZE(mop500_family_pinmap));
+ pinctrl_register_mappings(mop500_pinmap,
+ ARRAY_SIZE(mop500_pinmap));
+ mop500_href_family_pinmaps_init();
}
-void __init hrefv60_pins_init(void)
+void __init snowball_pinmaps_init(void)
{
- nmk_config_pins(mop500_pins_common,
- ARRAY_SIZE(mop500_pins_common));
+ pinctrl_register_mappings(mop500_family_pinmap,
+ ARRAY_SIZE(mop500_family_pinmap));
+ pinctrl_register_mappings(snowball_pinmap,
+ ARRAY_SIZE(snowball_pinmap));
+ pinctrl_register_mappings(u8500_pinmap,
+ ARRAY_SIZE(u8500_pinmap));
+}
- nmk_config_pins(hrefv60_pins,
- ARRAY_SIZE(hrefv60_pins));
+void __init hrefv60_pinmaps_init(void)
+{
+ pinctrl_register_mappings(mop500_family_pinmap,
+ ARRAY_SIZE(mop500_family_pinmap));
+ pinctrl_register_mappings(hrefv60_pinmap,
+ ARRAY_SIZE(hrefv60_pinmap));
+ mop500_href_family_pinmaps_init();
}
diff --git a/arch/arm/mach-ux500/board-mop500-uib.c b/arch/arm/mach-ux500/board-mop500-uib.c
index 5af36aa56c08..b29a788f498c 100644
--- a/arch/arm/mach-ux500/board-mop500-uib.c
+++ b/arch/arm/mach-ux500/board-mop500-uib.c
@@ -102,7 +102,7 @@ static int __init mop500_uib_init(void)
struct i2c_adapter *i2c0;
int ret;
- if (!cpu_is_u8500())
+ if (!cpu_is_u8500_family())
return -ENODEV;
if (uib) {
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
index 77d03c1fbd04..f943687acaf0 100644
--- a/arch/arm/mach-ux500/board-mop500.c
+++ b/arch/arm/mach-ux500/board-mop500.c
@@ -1,3 +1,4 @@
+
/*
* Copyright (C) 2008-2009 ST-Ericsson
*
@@ -29,30 +30,30 @@
#include <linux/smsc911x.h>
#include <linux/gpio_keys.h>
#include <linux/delay.h>
-
#include <linux/of.h>
#include <linux/of_platform.h>
-
#include <linux/leds.h>
+#include <linux/pinctrl/consumer.h>
+
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/hardware/gic.h>
#include <plat/i2c.h>
#include <plat/ste_dma40.h>
-#include <plat/pincfg.h>
#include <plat/gpio-nomadik.h>
#include <mach/hardware.h>
#include <mach/setup.h>
#include <mach/devices.h>
#include <mach/irqs.h>
+#include <mach/crypto-ux500.h>
-#include "pins-db8500.h"
#include "ste-dma40-db8500.h"
#include "devices-db8500.h"
#include "board-mop500.h"
#include "board-mop500-regulators.h"
+#include "board-mop500-msp.h"
static struct gpio_led snowball_led_array[] = {
{
@@ -417,6 +418,45 @@ static void mop500_prox_deactivate(struct device *dev)
regulator_put(prox_regulator);
}
+static struct cryp_platform_data u8500_cryp1_platform_data = {
+ .mem_to_engine = {
+ .dir = STEDMA40_MEM_TO_PERIPH,
+ .src_dev_type = STEDMA40_DEV_SRC_MEMORY,
+ .dst_dev_type = DB8500_DMA_DEV48_CAC1_TX,
+ .src_info.data_width = STEDMA40_WORD_WIDTH,
+ .dst_info.data_width = STEDMA40_WORD_WIDTH,
+ .mode = STEDMA40_MODE_LOGICAL,
+ .src_info.psize = STEDMA40_PSIZE_LOG_4,
+ .dst_info.psize = STEDMA40_PSIZE_LOG_4,
+ },
+ .engine_to_mem = {
+ .dir = STEDMA40_PERIPH_TO_MEM,
+ .src_dev_type = DB8500_DMA_DEV48_CAC1_RX,
+ .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
+ .src_info.data_width = STEDMA40_WORD_WIDTH,
+ .dst_info.data_width = STEDMA40_WORD_WIDTH,
+ .mode = STEDMA40_MODE_LOGICAL,
+ .src_info.psize = STEDMA40_PSIZE_LOG_4,
+ .dst_info.psize = STEDMA40_PSIZE_LOG_4,
+ }
+};
+
+static struct stedma40_chan_cfg u8500_hash_dma_cfg_tx = {
+ .dir = STEDMA40_MEM_TO_PERIPH,
+ .src_dev_type = STEDMA40_DEV_SRC_MEMORY,
+ .dst_dev_type = DB8500_DMA_DEV50_HAC1_TX,
+ .src_info.data_width = STEDMA40_WORD_WIDTH,
+ .dst_info.data_width = STEDMA40_WORD_WIDTH,
+ .mode = STEDMA40_MODE_LOGICAL,
+ .src_info.psize = STEDMA40_PSIZE_LOG_16,
+ .dst_info.psize = STEDMA40_PSIZE_LOG_16,
+};
+
+static struct hash_platform_data u8500_hash1_platform_data = {
+ .mem_to_engine = &u8500_hash_dma_cfg_tx,
+ .dma_filter = stedma40_filter,
+};
+
/* add any platform devices here - TODO */
static struct platform_device *mop500_platform_devs[] __initdata = {
&mop500_gpio_keys_device,
@@ -520,14 +560,6 @@ static struct stedma40_chan_cfg uart2_dma_cfg_tx = {
};
#endif
-
-static pin_cfg_t mop500_pins_uart0[] = {
- GPIO0_U0_CTSn | PIN_INPUT_PULLUP,
- GPIO1_U0_RTSn | PIN_OUTPUT_HIGH,
- GPIO2_U0_RXD | PIN_INPUT_PULLUP,
- GPIO3_U0_TXD | PIN_OUTPUT_HIGH,
-};
-
#define PRCC_K_SOFTRST_SET 0x18
#define PRCC_K_SOFTRST_CLEAR 0x1C
static void ux500_uart0_reset(void)
@@ -548,24 +580,33 @@ static void ux500_uart0_reset(void)
udelay(1);
}
+/* This needs to be referenced by callbacks */
+struct pinctrl *u0_p;
+struct pinctrl_state *u0_def;
+struct pinctrl_state *u0_sleep;
+
static void ux500_uart0_init(void)
{
int ret;
- ret = nmk_config_pins(mop500_pins_uart0,
- ARRAY_SIZE(mop500_pins_uart0));
- if (ret < 0)
- pr_err("pl011: uart pins_enable failed\n");
+ if (IS_ERR(u0_p) || IS_ERR(u0_def))
+ return;
+
+ ret = pinctrl_select_state(u0_p, u0_def);
+ if (ret)
+ pr_err("could not set UART0 defstate\n");
}
static void ux500_uart0_exit(void)
{
int ret;
- ret = nmk_config_pins_sleep(mop500_pins_uart0,
- ARRAY_SIZE(mop500_pins_uart0));
- if (ret < 0)
- pr_err("pl011: uart pins_disable failed\n");
+ if (IS_ERR(u0_p) || IS_ERR(u0_sleep))
+ return;
+
+ ret = pinctrl_select_state(u0_p, u0_sleep);
+ if (ret)
+ pr_err("could not set UART0 idlestate\n");
}
static struct amba_pl011_data uart0_plat = {
@@ -597,15 +638,41 @@ static struct amba_pl011_data uart2_plat = {
static void __init mop500_uart_init(struct device *parent)
{
- db8500_add_uart0(parent, &uart0_plat);
+ struct amba_device *uart0_device;
+
+ uart0_device = db8500_add_uart0(parent, &uart0_plat);
+ if (uart0_device) {
+ u0_p = pinctrl_get(&uart0_device->dev);
+ if (IS_ERR(u0_p))
+ dev_err(&uart0_device->dev,
+ "could not get UART0 pinctrl\n");
+ else {
+ u0_def = pinctrl_lookup_state(u0_p,
+ PINCTRL_STATE_DEFAULT);
+ if (IS_ERR(u0_def)) {
+ dev_err(&uart0_device->dev,
+ "could not get UART0 defstate\n");
+ }
+ u0_sleep = pinctrl_lookup_state(u0_p,
+ PINCTRL_STATE_SLEEP);
+ if (IS_ERR(u0_sleep))
+ dev_err(&uart0_device->dev,
+ "could not get UART0 idlestate\n");
+ }
+ }
db8500_add_uart1(parent, &uart1_plat);
db8500_add_uart2(parent, &uart2_plat);
}
+static void __init u8500_cryp1_hash1_init(struct device *parent)
+{
+ db8500_add_cryp1(parent, &u8500_cryp1_platform_data);
+ db8500_add_hash1(parent, &u8500_hash1_platform_data);
+}
+
static struct platform_device *snowball_platform_devs[] __initdata = {
&snowball_led_dev,
&snowball_key_dev,
- &snowball_sbnet_dev,
&ab8500_device,
};
@@ -617,10 +684,9 @@ static void __init mop500_init_machine(void)
mop500_gpio_keys[0].gpio = GPIO_PROX_SENSOR;
+ mop500_pinmaps_init();
parent = u8500_init_devices();
- mop500_pins_init();
-
/* FIXME: parent of ab8500 should be prcmu */
for (i = 0; i < ARRAY_SIZE(mop500_platform_devs); i++)
mop500_platform_devs[i]->dev.parent = parent;
@@ -631,8 +697,11 @@ static void __init mop500_init_machine(void)
mop500_i2c_init(parent);
mop500_sdi_init(parent);
mop500_spi_init(parent);
+ mop500_msp_init(parent);
mop500_uart_init(parent);
+ u8500_cryp1_hash1_init(parent);
+
i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs);
@@ -646,13 +715,11 @@ static void __init mop500_init_machine(void)
static void __init snowball_init_machine(void)
{
struct device *parent = NULL;
- int i2c0_devs;
int i;
+ snowball_pinmaps_init();
parent = u8500_init_devices();
- snowball_pins_init();
-
for (i = 0; i < ARRAY_SIZE(snowball_platform_devs); i++)
snowball_platform_devs[i]->dev.parent = parent;
@@ -662,13 +729,9 @@ static void __init snowball_init_machine(void)
mop500_i2c_init(parent);
snowball_sdi_init(parent);
mop500_spi_init(parent);
+ mop500_msp_init(parent);
mop500_uart_init(parent);
- i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
- i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs);
- i2c_register_board_info(2, mop500_i2c2_devices,
- ARRAY_SIZE(mop500_i2c2_devices));
-
/* This board has full regulator constraints */
regulator_has_full_constraints();
}
@@ -686,10 +749,9 @@ static void __init hrefv60_init_machine(void)
*/
mop500_gpio_keys[0].gpio = HREFV60_PROX_SENSE_GPIO;
+ hrefv60_pinmaps_init();
parent = u8500_init_devices();
- hrefv60_pins_init();
-
for (i = 0; i < ARRAY_SIZE(mop500_platform_devs); i++)
mop500_platform_devs[i]->dev.parent = parent;
@@ -699,6 +761,7 @@ static void __init hrefv60_init_machine(void)
mop500_i2c_init(parent);
hrefv60_sdi_init(parent);
mop500_spi_init(parent);
+ mop500_msp_init(parent);
mop500_uart_init(parent);
i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
@@ -746,16 +809,29 @@ MACHINE_END
#ifdef CONFIG_MACH_UX500_DT
struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = {
+ /* Requires DMA and call-back bindings. */
OF_DEV_AUXDATA("arm,pl011", 0x80120000, "uart0", &uart0_plat),
OF_DEV_AUXDATA("arm,pl011", 0x80121000, "uart1", &uart1_plat),
OF_DEV_AUXDATA("arm,pl011", 0x80007000, "uart2", &uart2_plat),
+ /* Requires DMA bindings. */
OF_DEV_AUXDATA("arm,pl022", 0x80002000, "ssp0", &ssp0_plat),
+ /* Requires clock name bindings. */
+ OF_DEV_AUXDATA("st,nomadik-gpio", 0x8012e000, "gpio.0", NULL),
+ OF_DEV_AUXDATA("st,nomadik-gpio", 0x8012e080, "gpio.1", NULL),
+ OF_DEV_AUXDATA("st,nomadik-gpio", 0x8000e000, "gpio.2", NULL),
+ OF_DEV_AUXDATA("st,nomadik-gpio", 0x8000e080, "gpio.3", NULL),
+ OF_DEV_AUXDATA("st,nomadik-gpio", 0x8000e100, "gpio.4", NULL),
+ OF_DEV_AUXDATA("st,nomadik-gpio", 0x8000e180, "gpio.5", NULL),
+ OF_DEV_AUXDATA("st,nomadik-gpio", 0x8011e000, "gpio.6", NULL),
+ OF_DEV_AUXDATA("st,nomadik-gpio", 0x8011e080, "gpio.7", NULL),
+ OF_DEV_AUXDATA("st,nomadik-gpio", 0xa03fe000, "gpio.8", NULL),
{},
};
-static const struct of_device_id u8500_soc_node[] = {
+static const struct of_device_id u8500_local_bus_nodes[] = {
/* only create devices below soc node */
{ .compatible = "stericsson,db8500", },
+ { .compatible = "simple-bus"},
{ },
};
@@ -765,8 +841,15 @@ static void __init u8500_init_machine(void)
int i2c0_devs;
int i;
+ /* Pinmaps must be in place before devices register */
+ if (of_machine_is_compatible("st-ericsson,mop500"))
+ mop500_pinmaps_init();
+ else if (of_machine_is_compatible("calaosystems,snowball-a9500"))
+ snowball_pinmaps_init();
+ else if (of_machine_is_compatible("st-ericsson,hrefv60+"))
+ hrefv60_pinmaps_init();
+
parent = u8500_init_devices();
- i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
for (i = 0; i < ARRAY_SIZE(mop500_platform_devs); i++)
mop500_platform_devs[i]->dev.parent = parent;
@@ -774,18 +857,22 @@ static void __init u8500_init_machine(void)
snowball_platform_devs[i]->dev.parent = parent;
/* automatically probe child nodes of db8500 device */
- of_platform_populate(NULL, u8500_soc_node, u8500_auxdata_lookup, parent);
+ of_platform_populate(NULL, u8500_local_bus_nodes, u8500_auxdata_lookup, parent);
if (of_machine_is_compatible("st-ericsson,mop500")) {
mop500_gpio_keys[0].gpio = GPIO_PROX_SENSOR;
- mop500_pins_init();
platform_add_devices(mop500_platform_devs,
ARRAY_SIZE(mop500_platform_devs));
mop500_sdi_init(parent);
+
+ i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
+ i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs);
+ i2c_register_board_info(2, mop500_i2c2_devices,
+ ARRAY_SIZE(mop500_i2c2_devices));
+
} else if (of_machine_is_compatible("calaosystems,snowball-a9500")) {
- snowball_pins_init();
platform_add_devices(snowball_platform_devs,
ARRAY_SIZE(snowball_platform_devs));
@@ -797,19 +884,20 @@ static void __init u8500_init_machine(void)
* instead.
*/
mop500_gpio_keys[0].gpio = HREFV60_PROX_SENSE_GPIO;
- i2c0_devs -= NUM_PRE_V60_I2C0_DEVICES;
- hrefv60_pins_init();
platform_add_devices(mop500_platform_devs,
ARRAY_SIZE(mop500_platform_devs));
hrefv60_sdi_init(parent);
+
+ i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
+ i2c0_devs -= NUM_PRE_V60_I2C0_DEVICES;
+
+ i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs);
+ i2c_register_board_info(2, mop500_i2c2_devices,
+ ARRAY_SIZE(mop500_i2c2_devices));
}
mop500_i2c_init(parent);
- i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs);
- i2c_register_board_info(2, mop500_i2c2_devices,
- ARRAY_SIZE(mop500_i2c2_devices));
-
/* This board has full regulator constraints */
regulator_has_full_constraints();
}
diff --git a/arch/arm/mach-ux500/board-mop500.h b/arch/arm/mach-ux500/board-mop500.h
index fdcfa8721bb4..bc44c07c71a9 100644
--- a/arch/arm/mach-ux500/board-mop500.h
+++ b/arch/arm/mach-ux500/board-mop500.h
@@ -7,6 +7,9 @@
#ifndef __BOARD_MOP500_H
#define __BOARD_MOP500_H
+/* For NOMADIK_NR_GPIO */
+#include <mach/irqs.h>
+
/* Snowball specific GPIO assignments, this board has no GPIO expander */
#define SNOWBALL_ACCEL_INT1_GPIO 163
#define SNOWBALL_ACCEL_INT2_GPIO 164
@@ -73,6 +76,7 @@
#define SNOWBALL_PME_ETH_GPIO MOP500_AB8500_PIN_GPIO(24) /* SYSCLKREQ7/GPIO24 */
#define SNOWBALL_EN_3V3_ETH_GPIO MOP500_AB8500_PIN_GPIO(26) /* GPIO26 */
+struct device;
struct i2c_board_info;
extern void mop500_sdi_init(struct device *parent);
@@ -81,9 +85,9 @@ extern void hrefv60_sdi_init(struct device *parent);
extern void mop500_sdi_tc35892_init(struct device *parent);
void __init mop500_u8500uib_init(void);
void __init mop500_stuib_init(void);
-void __init mop500_pins_init(void);
-void __init hrefv60_pins_init(void);
-void __init snowball_pins_init(void);
+void __init mop500_pinmaps_init(void);
+void __init snowball_pinmaps_init(void);
+void __init hrefv60_pinmaps_init(void);
void mop500_uib_i2c_add(int busnum, struct i2c_board_info *info,
unsigned n);
diff --git a/arch/arm/mach-ux500/board-u5500-sdi.c b/arch/arm/mach-ux500/board-u5500-sdi.c
deleted file mode 100644
index 836112eedde7..000000000000
--- a/arch/arm/mach-ux500/board-u5500-sdi.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Hanumath Prasad <ulf.hansson@stericsson.com>
- * License terms: GNU General Public License (GPL) version 2
- */
-
-#include <linux/amba/mmci.h>
-#include <linux/mmc/host.h>
-
-#include <plat/pincfg.h>
-#include <plat/gpio-nomadik.h>
-#include <mach/db5500-regs.h>
-#include <plat/ste_dma40.h>
-
-#include "pins-db5500.h"
-#include "devices-db5500.h"
-#include "ste-dma40-db5500.h"
-
-static pin_cfg_t u5500_sdi_pins[] = {
- /* SDI0 (POP eMMC) */
- GPIO5_MC0_DAT0 | PIN_DIR_INPUT | PIN_PULL_UP,
- GPIO6_MC0_DAT1 | PIN_DIR_INPUT | PIN_PULL_UP,
- GPIO7_MC0_DAT2 | PIN_DIR_INPUT | PIN_PULL_UP,
- GPIO8_MC0_DAT3 | PIN_DIR_INPUT | PIN_PULL_UP,
- GPIO9_MC0_DAT4 | PIN_DIR_INPUT | PIN_PULL_UP,
- GPIO10_MC0_DAT5 | PIN_DIR_INPUT | PIN_PULL_UP,
- GPIO11_MC0_DAT6 | PIN_DIR_INPUT | PIN_PULL_UP,
- GPIO12_MC0_DAT7 | PIN_DIR_INPUT | PIN_PULL_UP,
- GPIO13_MC0_CMD | PIN_DIR_INPUT | PIN_PULL_UP,
- GPIO14_MC0_CLK | PIN_DIR_OUTPUT | PIN_VAL_LOW,
-};
-
-#ifdef CONFIG_STE_DMA40
-struct stedma40_chan_cfg u5500_sdi0_dma_cfg_rx = {
- .mode = STEDMA40_MODE_LOGICAL,
- .dir = STEDMA40_PERIPH_TO_MEM,
- .src_dev_type = DB5500_DMA_DEV24_SDMMC0_RX,
- .dst_dev_type = STEDMA40_DEV_DST_MEMORY,
- .src_info.data_width = STEDMA40_WORD_WIDTH,
- .dst_info.data_width = STEDMA40_WORD_WIDTH,
-};
-
-static struct stedma40_chan_cfg u5500_sdi0_dma_cfg_tx = {
- .mode = STEDMA40_MODE_LOGICAL,
- .dir = STEDMA40_MEM_TO_PERIPH,
- .src_dev_type = STEDMA40_DEV_SRC_MEMORY,
- .dst_dev_type = DB5500_DMA_DEV24_SDMMC0_TX,
- .src_info.data_width = STEDMA40_WORD_WIDTH,
- .dst_info.data_width = STEDMA40_WORD_WIDTH,
-};
-#endif
-
-static struct mmci_platform_data u5500_sdi0_data = {
- .ocr_mask = MMC_VDD_165_195,
- .f_max = 50000000,
- .capabilities = MMC_CAP_4_BIT_DATA |
- MMC_CAP_8_BIT_DATA |
- MMC_CAP_MMC_HIGHSPEED,
- .gpio_cd = -1,
- .gpio_wp = -1,
-#ifdef CONFIG_STE_DMA40
- .dma_filter = stedma40_filter,
- .dma_rx_param = &u5500_sdi0_dma_cfg_rx,
- .dma_tx_param = &u5500_sdi0_dma_cfg_tx,
-#endif
-};
-
-void __init u5500_sdi_init(struct device *parent)
-{
- nmk_config_pins(u5500_sdi_pins, ARRAY_SIZE(u5500_sdi_pins));
-
- db5500_add_sdi0(parent, &u5500_sdi0_data);
-}
diff --git a/arch/arm/mach-ux500/board-u5500.c b/arch/arm/mach-ux500/board-u5500.c
deleted file mode 100644
index 0ff4be72a809..000000000000
--- a/arch/arm/mach-ux500/board-u5500.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- */
-
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/amba/bus.h>
-#include <linux/irq.h>
-#include <linux/i2c.h>
-#include <linux/mfd/abx500/ab5500.h>
-
-#include <asm/hardware/gic.h>
-#include <asm/mach/arch.h>
-#include <asm/mach-types.h>
-
-#include <plat/pincfg.h>
-#include <plat/i2c.h>
-#include <plat/gpio-nomadik.h>
-
-#include <mach/hardware.h>
-#include <mach/devices.h>
-#include <mach/setup.h>
-
-#include "pins-db5500.h"
-#include "devices-db5500.h"
-#include <linux/led-lm3530.h>
-
-/*
- * GPIO
- */
-
-static pin_cfg_t u5500_pins[] = {
- /* I2C */
- GPIO218_I2C2_SCL | PIN_INPUT_PULLUP,
- GPIO219_I2C2_SDA | PIN_INPUT_PULLUP,
-
- /* DISPLAY_ENABLE */
- GPIO226_GPIO | PIN_OUTPUT_LOW,
-
- /* Backlight Enbale */
- GPIO224_GPIO | PIN_OUTPUT_HIGH,
-};
-/*
- * I2C
- */
-
-#define U5500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, _sm) \
-static struct nmk_i2c_controller u5500_i2c##id##_data = { \
- /* \
- * slave data setup time, which is \
- * 250 ns,100ns,10ns which is 14,6,2 \
- * respectively for a 48 Mhz \
- * i2c clock \
- */ \
- .slsu = _slsu, \
- /* Tx FIFO threshold */ \
- .tft = _tft, \
- /* Rx FIFO threshold */ \
- .rft = _rft, \
- /* std. mode operation */ \
- .clk_freq = clk, \
- .sm = _sm, \
-}
-/*
- * The board uses TODO <3> i2c controllers, initialize all of
- * them with slave data setup time of 250 ns,
- * Tx & Rx FIFO threshold values as 1 and standard
- * mode of operation
- */
-
-U5500_I2C_CONTROLLER(2, 0xe, 1, 1, 400000, I2C_FREQ_MODE_FAST);
-
-static struct lm3530_platform_data u5500_als_platform_data = {
- .mode = LM3530_BL_MODE_MANUAL,
- .als_input_mode = LM3530_INPUT_ALS1,
- .max_current = LM3530_FS_CURR_26mA,
- .pwm_pol_hi = true,
- .als_avrg_time = LM3530_ALS_AVRG_TIME_512ms,
- .brt_ramp_law = 1, /* Linear */
- .brt_ramp_fall = LM3530_RAMP_TIME_8s,
- .brt_ramp_rise = LM3530_RAMP_TIME_8s,
- .als1_resistor_sel = LM3530_ALS_IMPD_13_53kOhm,
- .als2_resistor_sel = LM3530_ALS_IMPD_Z,
- .als_vmin = 730, /* mV */
- .als_vmax = 1020, /* mV */
- .brt_val = 0x7F, /* Max brightness */
-};
-
-static struct i2c_board_info __initdata u5500_i2c2_devices[] = {
- {
- /* Backlight */
- I2C_BOARD_INFO("lm3530-led", 0x36),
- .platform_data = &u5500_als_platform_data,
- },
-};
-
-static void __init u5500_i2c_init(struct device *parent)
-{
- db5500_add_i2c2(parent, &u5500_i2c2_data);
- i2c_register_board_info(2, ARRAY_AND_SIZE(u5500_i2c2_devices));
-}
-
-static struct ab5500_platform_data ab5500_plf_data = {
- .irq = {
- .base = 0,
- .count = 0,
- },
- .init_settings = NULL,
- .init_settings_sz = 0,
- .pm_power_off = false,
-};
-
-static struct platform_device ab5500_device = {
- .name = "ab5500-core",
- .id = 0,
- .dev = {
- .platform_data = &ab5500_plf_data,
- },
- .num_resources = 0,
-};
-
-static struct platform_device *u5500_platform_devices[] __initdata = {
- &ab5500_device,
-};
-
-static void __init u5500_uart_init(struct device *parent)
-{
- db5500_add_uart0(parent, NULL);
- db5500_add_uart1(parent, NULL);
- db5500_add_uart2(parent, NULL);
-}
-
-static void __init u5500_init_machine(void)
-{
- struct device *parent = NULL;
- int i;
-
- parent = u5500_init_devices();
- nmk_config_pins(u5500_pins, ARRAY_SIZE(u5500_pins));
-
- u5500_i2c_init(parent);
- u5500_sdi_init(parent);
- u5500_uart_init(parent);
-
- for (i = 0; i < ARRAY_SIZE(u5500_platform_devices); i++)
- u5500_platform_devices[i]->dev.parent = parent;
-
- platform_add_devices(u5500_platform_devices,
- ARRAY_SIZE(u5500_platform_devices));
-}
-
-MACHINE_START(U5500, "ST-Ericsson U5500 Platform")
- .atag_offset = 0x100,
- .map_io = u5500_map_io,
- .init_irq = ux500_init_irq,
- .timer = &ux500_timer,
- .handle_irq = gic_handle_irq,
- .init_machine = u5500_init_machine,
-MACHINE_END
diff --git a/arch/arm/mach-ux500/cache-l2x0.c b/arch/arm/mach-ux500/cache-l2x0.c
index 77a75ed0df67..dc12394295d5 100644
--- a/arch/arm/mach-ux500/cache-l2x0.c
+++ b/arch/arm/mach-ux500/cache-l2x0.c
@@ -36,9 +36,9 @@ static int __init ux500_l2x0_unlock(void)
static int __init ux500_l2x0_init(void)
{
- if (cpu_is_u5500())
- l2x0_base = __io_address(U5500_L2CC_BASE);
- else if (cpu_is_u8500())
+ u32 aux_val = 0x3e000000;
+
+ if (cpu_is_u8500_family())
l2x0_base = __io_address(U8500_L2CC_BASE);
else
ux500_unknown_soc();
@@ -46,11 +46,19 @@ static int __init ux500_l2x0_init(void)
/* Unlock before init */
ux500_l2x0_unlock();
+ /* DB9540's L2 has 128KB way size */
+ if (cpu_is_u9540())
+ /* 128KB way size */
+ aux_val |= (0x4 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT);
+ else
+ /* 64KB way size */
+ aux_val |= (0x3 << L2X0_AUX_CTRL_WAY_SIZE_SHIFT);
+
/* 64KB way size, 8 way associativity, force WA */
if (of_have_populated_dt())
- l2x0_of_init(0x3e060000, 0xc0000fff);
+ l2x0_of_init(aux_val, 0xc0000fff);
else
- l2x0_init(l2x0_base, 0x3e060000, 0xc0000fff);
+ l2x0_init(l2x0_base, aux_val, 0xc0000fff);
/*
* We can't disable l2 as we are in non secure mode, currently
diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c
index ec35f0aa5665..1762c4728f1e 100644
--- a/arch/arm/mach-ux500/clock.c
+++ b/arch/arm/mach-ux500/clock.c
@@ -149,9 +149,7 @@ static unsigned long clk_mtu_get_rate(struct clk *clk)
unsigned long mturate;
unsigned long retclk;
- if (cpu_is_u5500())
- addr = __io_address(U5500_PRCMU_BASE);
- else if (cpu_is_u8500())
+ if (cpu_is_u8500_family())
addr = __io_address(U8500_PRCMU_BASE);
else
ux500_unknown_soc();
@@ -336,6 +334,7 @@ static DEFINE_PRCMU_CLK(uiccclk, 0x4, 1, UICCCLK); /* v1 */
*/
/* Peripheral Cluster #1 */
+static DEFINE_PRCC_CLK(1, msp3, 11, 10, &clk_msp1clk);
static DEFINE_PRCC_CLK(1, i2c4, 10, 9, &clk_i2cclk);
static DEFINE_PRCC_CLK(1, gpio0, 9, -1, NULL);
static DEFINE_PRCC_CLK(1, slimbus0, 8, 8, &clk_slimclk);
@@ -382,14 +381,15 @@ static DEFINE_PRCC_CLK(5, usb, 0, 0, NULL);
/* Peripheral Cluster #6 */
/* MTU ID in data */
-static DEFINE_PRCC_CLK_CUSTOM(6, mtu1, 8, -1, NULL, clk_mtu_get_rate, 1);
-static DEFINE_PRCC_CLK_CUSTOM(6, mtu0, 7, -1, NULL, clk_mtu_get_rate, 0);
-static DEFINE_PRCC_CLK(6, cfgreg, 6, 6, NULL);
-static DEFINE_PRCC_CLK(6, hash1, 5, -1, NULL);
-static DEFINE_PRCC_CLK(6, unipro, 4, 1, &clk_uniproclk);
-static DEFINE_PRCC_CLK(6, pka, 3, -1, NULL);
-static DEFINE_PRCC_CLK(6, hash0, 2, -1, NULL);
-static DEFINE_PRCC_CLK(6, cryp0, 1, -1, NULL);
+static DEFINE_PRCC_CLK_CUSTOM(6, mtu1, 9, -1, NULL, clk_mtu_get_rate, 1);
+static DEFINE_PRCC_CLK_CUSTOM(6, mtu0, 8, -1, NULL, clk_mtu_get_rate, 0);
+static DEFINE_PRCC_CLK(6, cfgreg, 7, 7, NULL);
+static DEFINE_PRCC_CLK(6, hash1, 6, -1, NULL);
+static DEFINE_PRCC_CLK(6, unipro, 5, 1, &clk_uniproclk);
+static DEFINE_PRCC_CLK(6, pka, 4, -1, NULL);
+static DEFINE_PRCC_CLK(6, hash0, 3, -1, NULL);
+static DEFINE_PRCC_CLK(6, cryp0, 2, -1, NULL);
+static DEFINE_PRCC_CLK(6, cryp1, 1, -1, NULL);
static DEFINE_PRCC_CLK(6, rng, 0, 0, &clk_rngclk);
static struct clk clk_dummy_apb_pclk = {
@@ -405,7 +405,7 @@ static struct clk_lookup u8500_clks[] = {
CLK(slimbus0, "slimbus0", NULL),
CLK(i2c2, "nmk-i2c.2", NULL),
CLK(sdi0, "sdi0", NULL),
- CLK(msp0, "msp0", NULL),
+ CLK(msp0, "ux500-msp-i2s.0", NULL),
CLK(i2c1, "nmk-i2c.1", NULL),
CLK(uart1, "uart1", NULL),
CLK(uart0, "uart0", NULL),
@@ -431,6 +431,7 @@ static struct clk_lookup u8500_clks[] = {
CLK(pka, "pka", NULL),
CLK(hash0, "hash0", NULL),
CLK(cryp0, "cryp0", NULL),
+ CLK(cryp1, "cryp1", NULL),
/* PRCMU level clock gating */
@@ -455,7 +456,8 @@ static struct clk_lookup u8500_clks[] = {
/* Peripheral Cluster #1 */
CLK(i2c4, "nmk-i2c.4", NULL),
CLK(spi3, "spi3", NULL),
- CLK(msp1, "msp1", NULL),
+ CLK(msp1, "ux500-msp-i2s.1", NULL),
+ CLK(msp3, "ux500-msp-i2s.3", NULL),
/* Peripheral Cluster #2 */
CLK(gpio1, "gpio.6", NULL),
@@ -465,7 +467,7 @@ static struct clk_lookup u8500_clks[] = {
CLK(spi0, "spi0", NULL),
CLK(sdi3, "sdi3", NULL),
CLK(sdi1, "sdi1", NULL),
- CLK(msp2, "msp2", NULL),
+ CLK(msp2, "ux500-msp-i2s.2", NULL),
CLK(sdi4, "sdi4", NULL),
CLK(pwl, "pwl", NULL),
CLK(spi1, "spi1", NULL),
@@ -705,14 +707,6 @@ late_initcall(clk_init_smp_twd_cpufreq);
int __init clk_init(void)
{
- if (cpu_is_u5500()) {
- /* Clock tree for U5500 not implemented yet */
- clk_prcc_ops.enable = clk_prcc_ops.disable = NULL;
- clk_prcmu_ops.enable = clk_prcmu_ops.disable = NULL;
- clk_uartclk.rate = 36360000;
- clk_sdmmcclk.rate = 99900000;
- }
-
clkdev_add_table(u8500_clks, ARRAY_SIZE(u8500_clks));
clkdev_add(&clk_smp_twd_lookup);
diff --git a/arch/arm/mach-ux500/cpu-db5500.c b/arch/arm/mach-ux500/cpu-db5500.c
deleted file mode 100644
index bca47f32082f..000000000000
--- a/arch/arm/mach-ux500/cpu-db5500.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- */
-
-#include <linux/platform_device.h>
-#include <linux/amba/bus.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-
-#include <asm/mach/map.h>
-#include <asm/pmu.h>
-
-#include <plat/gpio-nomadik.h>
-
-#include <mach/hardware.h>
-#include <mach/devices.h>
-#include <mach/setup.h>
-#include <mach/irqs.h>
-#include <mach/usb.h>
-
-#include "devices-db5500.h"
-#include "ste-dma40-db5500.h"
-
-static struct map_desc u5500_uart_io_desc[] __initdata = {
- __IO_DEV_DESC(U5500_UART0_BASE, SZ_4K),
- __IO_DEV_DESC(U5500_UART2_BASE, SZ_4K),
-};
-
-static struct map_desc u5500_io_desc[] __initdata = {
- /* SCU base also covers GIC CPU BASE and TWD with its 4K page */
- __IO_DEV_DESC(U5500_SCU_BASE, SZ_4K),
- __IO_DEV_DESC(U5500_GIC_DIST_BASE, SZ_4K),
- __IO_DEV_DESC(U5500_L2CC_BASE, SZ_4K),
- __IO_DEV_DESC(U5500_MTU0_BASE, SZ_4K),
- __IO_DEV_DESC(U5500_BACKUPRAM0_BASE, SZ_8K),
-
- __IO_DEV_DESC(U5500_GPIO0_BASE, SZ_4K),
- __IO_DEV_DESC(U5500_GPIO1_BASE, SZ_4K),
- __IO_DEV_DESC(U5500_GPIO2_BASE, SZ_4K),
- __IO_DEV_DESC(U5500_GPIO3_BASE, SZ_4K),
- __IO_DEV_DESC(U5500_GPIO4_BASE, SZ_4K),
- __IO_DEV_DESC(U5500_PRCMU_BASE, SZ_4K),
- __IO_DEV_DESC(U5500_PRCMU_TCDM_BASE, SZ_4K),
-};
-
-static struct resource mbox0_resources[] = {
- {
- .name = "mbox_peer",
- .start = U5500_MBOX0_PEER_START,
- .end = U5500_MBOX0_PEER_END,
- .flags = IORESOURCE_MEM,
- },
- {
- .name = "mbox_local",
- .start = U5500_MBOX0_LOCAL_START,
- .end = U5500_MBOX0_LOCAL_END,
- .flags = IORESOURCE_MEM,
- },
- {
- .name = "mbox_irq",
- .start = MBOX_PAIR0_VIRT_IRQ,
- .end = MBOX_PAIR0_VIRT_IRQ,
- .flags = IORESOURCE_IRQ,
- }
-};
-
-static struct resource mbox1_resources[] = {
- {
- .name = "mbox_peer",
- .start = U5500_MBOX1_PEER_START,
- .end = U5500_MBOX1_PEER_END,
- .flags = IORESOURCE_MEM,
- },
- {
- .name = "mbox_local",
- .start = U5500_MBOX1_LOCAL_START,
- .end = U5500_MBOX1_LOCAL_END,
- .flags = IORESOURCE_MEM,
- },
- {
- .name = "mbox_irq",
- .start = MBOX_PAIR1_VIRT_IRQ,
- .end = MBOX_PAIR1_VIRT_IRQ,
- .flags = IORESOURCE_IRQ,
- }
-};
-
-static struct resource mbox2_resources[] = {
- {
- .name = "mbox_peer",
- .start = U5500_MBOX2_PEER_START,
- .end = U5500_MBOX2_PEER_END,
- .flags = IORESOURCE_MEM,
- },
- {
- .name = "mbox_local",
- .start = U5500_MBOX2_LOCAL_START,
- .end = U5500_MBOX2_LOCAL_END,
- .flags = IORESOURCE_MEM,
- },
- {
- .name = "mbox_irq",
- .start = MBOX_PAIR2_VIRT_IRQ,
- .end = MBOX_PAIR2_VIRT_IRQ,
- .flags = IORESOURCE_IRQ,
- }
-};
-
-static struct platform_device mbox0_device = {
- .id = 0,
- .name = "mbox",
- .resource = mbox0_resources,
- .num_resources = ARRAY_SIZE(mbox0_resources),
-};
-
-static struct platform_device mbox1_device = {
- .id = 1,
- .name = "mbox",
- .resource = mbox1_resources,
- .num_resources = ARRAY_SIZE(mbox1_resources),
-};
-
-static struct platform_device mbox2_device = {
- .id = 2,
- .name = "mbox",
- .resource = mbox2_resources,
- .num_resources = ARRAY_SIZE(mbox2_resources),
-};
-
-static struct platform_device *db5500_platform_devs[] __initdata = {
- &mbox0_device,
- &mbox1_device,
- &mbox2_device,
-};
-
-static resource_size_t __initdata db5500_gpio_base[] = {
- U5500_GPIOBANK0_BASE,
- U5500_GPIOBANK1_BASE,
- U5500_GPIOBANK2_BASE,
- U5500_GPIOBANK3_BASE,
- U5500_GPIOBANK4_BASE,
- U5500_GPIOBANK5_BASE,
- U5500_GPIOBANK6_BASE,
- U5500_GPIOBANK7_BASE,
-};
-
-static void __init db5500_add_gpios(struct device *parent)
-{
- struct nmk_gpio_platform_data pdata = {
- /* No custom data yet */
- };
-
- dbx500_add_gpios(parent, ARRAY_AND_SIZE(db5500_gpio_base),
- IRQ_DB5500_GPIO0, &pdata);
-}
-
-void __init u5500_map_io(void)
-{
- /*
- * Map the UARTs early so that the DEBUG_LL stuff continues to work.
- */
- iotable_init(u5500_uart_io_desc, ARRAY_SIZE(u5500_uart_io_desc));
-
- ux500_map_io();
-
- iotable_init(u5500_io_desc, ARRAY_SIZE(u5500_io_desc));
-
- _PRCMU_BASE = __io_address(U5500_PRCMU_BASE);
-}
-
-static void __init db5500_pmu_init(void)
-{
- struct resource res[] = {
- [0] = {
- .start = IRQ_DB5500_PMU0,
- .end = IRQ_DB5500_PMU0,
- .flags = IORESOURCE_IRQ,
- },
- [1] = {
- .start = IRQ_DB5500_PMU1,
- .end = IRQ_DB5500_PMU1,
- .flags = IORESOURCE_IRQ,
- },
- };
-
- platform_device_register_simple("arm-pmu", ARM_PMU_DEVICE_CPU,
- res, ARRAY_SIZE(res));
-}
-
-static int usb_db5500_rx_dma_cfg[] = {
- DB5500_DMA_DEV4_USB_OTG_IEP_1_9,
- DB5500_DMA_DEV5_USB_OTG_IEP_2_10,
- DB5500_DMA_DEV6_USB_OTG_IEP_3_11,
- DB5500_DMA_DEV20_USB_OTG_IEP_4_12,
- DB5500_DMA_DEV21_USB_OTG_IEP_5_13,
- DB5500_DMA_DEV22_USB_OTG_IEP_6_14,
- DB5500_DMA_DEV23_USB_OTG_IEP_7_15,
- DB5500_DMA_DEV38_USB_OTG_IEP_8
-};
-
-static int usb_db5500_tx_dma_cfg[] = {
- DB5500_DMA_DEV4_USB_OTG_OEP_1_9,
- DB5500_DMA_DEV5_USB_OTG_OEP_2_10,
- DB5500_DMA_DEV6_USB_OTG_OEP_3_11,
- DB5500_DMA_DEV20_USB_OTG_OEP_4_12,
- DB5500_DMA_DEV21_USB_OTG_OEP_5_13,
- DB5500_DMA_DEV22_USB_OTG_OEP_6_14,
- DB5500_DMA_DEV23_USB_OTG_OEP_7_15,
- DB5500_DMA_DEV38_USB_OTG_OEP_8
-};
-
-static const char *db5500_read_soc_id(void)
-{
- return kasprintf(GFP_KERNEL, "u5500 currently unsupported\n");
-}
-
-static struct device * __init db5500_soc_device_init(void)
-{
- const char *soc_id = db5500_read_soc_id();
-
- return ux500_soc_device_init(soc_id);
-}
-
-struct device * __init u5500_init_devices(void)
-{
- struct device *parent;
- int i;
-
- parent = db5500_soc_device_init();
-
- db5500_add_gpios(parent);
- db5500_pmu_init();
- db5500_dma_init(parent);
- db5500_add_rtc(parent);
- db5500_add_usb(parent, usb_db5500_rx_dma_cfg, usb_db5500_tx_dma_cfg);
-
- for (i = 0; i < ARRAY_SIZE(db5500_platform_devs); i++)
- db5500_platform_devs[i]->dev.parent = parent;
-
- platform_add_devices(db5500_platform_devs,
- ARRAY_SIZE(db5500_platform_devs));
-
- return parent;
-}
diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c
index 9bd8163896cf..16169c4bf6ca 100644
--- a/arch/arm/mach-ux500/cpu-db8500.c
+++ b/arch/arm/mach-ux500/cpu-db8500.c
@@ -34,8 +34,8 @@ static struct map_desc u8500_uart_io_desc[] __initdata = {
__IO_DEV_DESC(U8500_UART0_BASE, SZ_4K),
__IO_DEV_DESC(U8500_UART2_BASE, SZ_4K),
};
-
-static struct map_desc u8500_io_desc[] __initdata = {
+/* U8500 and U9540 common io_desc */
+static struct map_desc u8500_common_io_desc[] __initdata = {
/* SCU base also covers GIC CPU BASE and TWD with its 4K page */
__IO_DEV_DESC(U8500_SCU_BASE, SZ_4K),
__IO_DEV_DESC(U8500_GIC_DIST_BASE, SZ_4K),
@@ -49,12 +49,23 @@ static struct map_desc u8500_io_desc[] __initdata = {
__IO_DEV_DESC(U8500_CLKRST5_BASE, SZ_4K),
__IO_DEV_DESC(U8500_CLKRST6_BASE, SZ_4K),
- __IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K),
__IO_DEV_DESC(U8500_GPIO0_BASE, SZ_4K),
__IO_DEV_DESC(U8500_GPIO1_BASE, SZ_4K),
__IO_DEV_DESC(U8500_GPIO2_BASE, SZ_4K),
__IO_DEV_DESC(U8500_GPIO3_BASE, SZ_4K),
+};
+
+/* U8500 IO map specific description */
+static struct map_desc u8500_io_desc[] __initdata = {
+ __IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K),
__IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K),
+
+};
+
+/* U9540 IO map specific description */
+static struct map_desc u9540_io_desc[] __initdata = {
+ __IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K + SZ_8K),
+ __IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K + SZ_8K),
};
void __init u8500_map_io(void)
@@ -66,7 +77,12 @@ void __init u8500_map_io(void)
ux500_map_io();
- iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc));
+ iotable_init(u8500_common_io_desc, ARRAY_SIZE(u8500_common_io_desc));
+
+ if (cpu_is_u9540())
+ iotable_init(u9540_io_desc, ARRAY_SIZE(u9540_io_desc));
+ else
+ iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc));
_PRCMU_BASE = __io_address(U8500_PRCMU_BASE);
}
@@ -121,6 +137,12 @@ static struct platform_device *platform_devs[] __initdata = {
&db8500_prcmu_device,
};
+static struct platform_device *of_platform_devs[] __initdata = {
+ &u8500_dma40_device,
+ &db8500_pmu_device,
+ &db8500_prcmu_device,
+};
+
static resource_size_t __initdata db8500_gpio_base[] = {
U8500_GPIOBANK0_BASE,
U8500_GPIOBANK1_BASE,
@@ -141,6 +163,7 @@ static void __init db8500_add_gpios(struct device *parent)
dbx500_add_gpios(parent, ARRAY_AND_SIZE(db8500_gpio_base),
IRQ_DB8500_GPIO0, &pdata);
+ dbx500_add_pinctrl(parent, "pinctrl-db8500");
}
static int usb_db8500_rx_dma_cfg[] = {
@@ -199,10 +222,16 @@ struct device * __init u8500_init_devices(void)
platform_device_register_data(parent,
"cpufreq-u8500", -1, NULL, 0);
- for (i = 0; i < ARRAY_SIZE(platform_devs); i++)
- platform_devs[i]->dev.parent = parent;
+ for (i = 0; i < ARRAY_SIZE(of_platform_devs); i++)
+ of_platform_devs[i]->dev.parent = parent;
- platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
+ /*
+ * Devices to be DT:ed:
+ * u8500_dma40_device = todo
+ * db8500_pmu_device = todo
+ * db8500_prcmu_device = todo
+ */
+ platform_add_devices(of_platform_devs, ARRAY_SIZE(of_platform_devs));
return parent;
}
diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c
index d11f3892a27d..a29a0e3adcf9 100644
--- a/arch/arm/mach-ux500/cpu.c
+++ b/arch/arm/mach-ux500/cpu.c
@@ -10,7 +10,6 @@
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/mfd/db8500-prcmu.h>
-#include <linux/mfd/db5500-prcmu.h>
#include <linux/clksrc-dbx500-prcmu.h>
#include <linux/sys_soc.h>
#include <linux/err.h>
@@ -30,6 +29,18 @@
void __iomem *_PRCMU_BASE;
+/*
+ * FIXME: Should we set up the GPIO domain here?
+ *
+ * The problem is that we cannot put the interrupt resources into the platform
+ * device until the irqdomain has been added. Right now, we set the GIC interrupt
+ * domain from init_irq(), then load the gpio driver from
+ * core_initcall(nmk_gpio_init) and add the platform devices from
+ * arch_initcall(customize_machine).
+ *
+ * This feels fragile because it depends on the gpio device getting probed
+ * _before_ any device uses the gpio interrupts.
+*/
static const struct of_device_id ux500_dt_irq_match[] = {
{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
{},
@@ -40,10 +51,7 @@ void __init ux500_init_irq(void)
void __iomem *dist_base;
void __iomem *cpu_base;
- if (cpu_is_u5500()) {
- dist_base = __io_address(U5500_GIC_DIST_BASE);
- cpu_base = __io_address(U5500_GIC_CPU_BASE);
- } else if (cpu_is_u8500()) {
+ if (cpu_is_u8500_family()) {
dist_base = __io_address(U8500_GIC_DIST_BASE);
cpu_base = __io_address(U8500_GIC_CPU_BASE);
} else
@@ -60,9 +68,7 @@ void __init ux500_init_irq(void)
* Init clocks here so that they are available for system timer
* initialization.
*/
- if (cpu_is_u5500())
- db5500_prcmu_early_init();
- if (cpu_is_u8500())
+ if (cpu_is_u8500_family())
db8500_prcmu_early_init();
clk_init();
}
diff --git a/arch/arm/mach-ux500/cpuidle.c b/arch/arm/mach-ux500/cpuidle.c
new file mode 100644
index 000000000000..b54884bd2549
--- /dev/null
+++ b/arch/arm/mach-ux500/cpuidle.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2012 Linaro : Daniel Lezcano <daniel.lezcano@linaro.org> (IBM)
+ *
+ * Based on the work of Rickard Andersson <rickard.andersson@stericsson.com>
+ * and Jonas Aaberg <jonas.aberg@stericsson.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/module.h>
+#include <linux/cpuidle.h>
+#include <linux/clockchips.h>
+#include <linux/spinlock.h>
+#include <linux/atomic.h>
+#include <linux/smp.h>
+#include <linux/mfd/dbx500-prcmu.h>
+
+#include <asm/cpuidle.h>
+#include <asm/proc-fns.h>
+
+static atomic_t master = ATOMIC_INIT(0);
+static DEFINE_SPINLOCK(master_lock);
+static DEFINE_PER_CPU(struct cpuidle_device, ux500_cpuidle_device);
+
+static inline int ux500_enter_idle(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
+{
+ int this_cpu = smp_processor_id();
+ bool recouple = false;
+
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &this_cpu);
+
+ if (atomic_inc_return(&master) == num_online_cpus()) {
+
+ /* With this lock, we prevent the other cpu to exit and enter
+ * this function again and become the master */
+ if (!spin_trylock(&master_lock))
+ goto wfi;
+
+ /* decouple the gic from the A9 cores */
+ if (prcmu_gic_decouple())
+ goto out;
+
+ /* If an error occur, we will have to recouple the gic
+ * manually */
+ recouple = true;
+
+ /* At this state, as the gic is decoupled, if the other
+ * cpu is in WFI, we have the guarantee it won't be wake
+ * up, so we can safely go to retention */
+ if (!prcmu_is_cpu_in_wfi(this_cpu ? 0 : 1))
+ goto out;
+
+ /* The prcmu will be in charge of watching the interrupts
+ * and wake up the cpus */
+ if (prcmu_copy_gic_settings())
+ goto out;
+
+ /* Check in the meantime an interrupt did
+ * not occur on the gic ... */
+ if (prcmu_gic_pending_irq())
+ goto out;
+
+ /* ... and the prcmu */
+ if (prcmu_pending_irq())
+ goto out;
+
+ /* Go to the retention state, the prcmu will wait for the
+ * cpu to go WFI and this is what happens after exiting this
+ * 'master' critical section */
+ if (prcmu_set_power_state(PRCMU_AP_IDLE, true, true))
+ goto out;
+
+ /* When we switch to retention, the prcmu is in charge
+ * of recoupling the gic automatically */
+ recouple = false;
+
+ spin_unlock(&master_lock);
+ }
+wfi:
+ cpu_do_idle();
+out:
+ atomic_dec(&master);
+
+ if (recouple) {
+ prcmu_gic_recouple();
+ spin_unlock(&master_lock);
+ }
+
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &this_cpu);
+
+ return index;
+}
+
+static struct cpuidle_driver ux500_idle_driver = {
+ .name = "ux500_idle",
+ .owner = THIS_MODULE,
+ .en_core_tk_irqen = 1,
+ .states = {
+ ARM_CPUIDLE_WFI_STATE,
+ {
+ .enter = ux500_enter_idle,
+ .exit_latency = 70,
+ .target_residency = 260,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .name = "ApIdle",
+ .desc = "ARM Retention",
+ },
+ },
+ .safe_state_index = 0,
+ .state_count = 2,
+};
+
+/*
+ * For each cpu, setup the broadcast timer because we will
+ * need to migrate the timers for the states >= ApIdle.
+ */
+static void ux500_setup_broadcast_timer(void *arg)
+{
+ int cpu = smp_processor_id();
+ clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &cpu);
+}
+
+int __init ux500_idle_init(void)
+{
+ int ret, cpu;
+ struct cpuidle_device *device;
+
+ /* Configure wake up reasons */
+ prcmu_enable_wakeups(PRCMU_WAKEUP(ARM) | PRCMU_WAKEUP(RTC) |
+ PRCMU_WAKEUP(ABB));
+
+ /*
+ * Configure the timer broadcast for each cpu, that must
+ * be done from the cpu context, so we use a smp cross
+ * call with 'on_each_cpu'.
+ */
+ on_each_cpu(ux500_setup_broadcast_timer, NULL, 1);
+
+ ret = cpuidle_register_driver(&ux500_idle_driver);
+ if (ret) {
+ printk(KERN_ERR "failed to register ux500 idle driver\n");
+ return ret;
+ }
+
+ for_each_online_cpu(cpu) {
+ device = &per_cpu(ux500_cpuidle_device, cpu);
+ device->cpu = cpu;
+ ret = cpuidle_register_device(device);
+ if (ret) {
+ printk(KERN_ERR "Failed to register cpuidle "
+ "device for cpu%d\n", cpu);
+ goto out_unregister;
+ }
+ }
+out:
+ return ret;
+
+out_unregister:
+ for_each_online_cpu(cpu) {
+ device = &per_cpu(ux500_cpuidle_device, cpu);
+ cpuidle_unregister_device(device);
+ }
+
+ cpuidle_unregister_driver(&ux500_idle_driver);
+ goto out;
+}
+
+device_initcall(ux500_idle_init);
diff --git a/arch/arm/mach-ux500/devices-common.h b/arch/arm/mach-ux500/devices-common.h
index f75bcb2ab13b..6e4706560266 100644
--- a/arch/arm/mach-ux500/devices-common.h
+++ b/arch/arm/mach-ux500/devices-common.h
@@ -13,6 +13,7 @@
#include <linux/sys_soc.h>
#include <linux/amba/bus.h>
#include <plat/i2c.h>
+#include <mach/crypto-ux500.h>
struct spi_master_cntlr;
@@ -85,9 +86,70 @@ dbx500_add_rtc(struct device *parent, resource_size_t base, int irq)
0, NULL, 0);
}
+struct cryp_platform_data;
+
+static inline struct platform_device *
+dbx500_add_cryp1(struct device *parent, int id, resource_size_t base, int irq,
+ struct cryp_platform_data *pdata)
+{
+ struct resource res[] = {
+ DEFINE_RES_MEM(base, SZ_4K),
+ DEFINE_RES_IRQ(irq),
+ };
+
+ struct platform_device_info pdevinfo = {
+ .parent = parent,
+ .name = "cryp1",
+ .id = id,
+ .res = res,
+ .num_res = ARRAY_SIZE(res),
+ .data = pdata,
+ .size_data = sizeof(*pdata),
+ .dma_mask = DMA_BIT_MASK(32),
+ };
+
+ return platform_device_register_full(&pdevinfo);
+}
+
+struct hash_platform_data;
+
+static inline struct platform_device *
+dbx500_add_hash1(struct device *parent, int id, resource_size_t base,
+ struct hash_platform_data *pdata)
+{
+ struct resource res[] = {
+ DEFINE_RES_MEM(base, SZ_4K),
+ };
+
+ struct platform_device_info pdevinfo = {
+ .parent = parent,
+ .name = "hash1",
+ .id = id,
+ .res = res,
+ .num_res = ARRAY_SIZE(res),
+ .data = pdata,
+ .size_data = sizeof(*pdata),
+ .dma_mask = DMA_BIT_MASK(32),
+ };
+
+ return platform_device_register_full(&pdevinfo);
+}
+
struct nmk_gpio_platform_data;
void dbx500_add_gpios(struct device *parent, resource_size_t *base, int num,
int irq, struct nmk_gpio_platform_data *pdata);
+static inline void
+dbx500_add_pinctrl(struct device *parent, const char *name)
+{
+ struct platform_device_info pdevinfo = {
+ .parent = parent,
+ .name = name,
+ .id = -1,
+ };
+
+ platform_device_register_full(&pdevinfo);
+}
+
#endif
diff --git a/arch/arm/mach-ux500/devices-db5500.h b/arch/arm/mach-ux500/devices-db5500.h
deleted file mode 100644
index e70955502c35..000000000000
--- a/arch/arm/mach-ux500/devices-db5500.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
- * License terms: GNU General Public License (GPL), version 2.
- */
-
-#ifndef __DEVICES_DB5500_H
-#define __DEVICES_DB5500_H
-
-#include "devices-common.h"
-
-#define db5500_add_i2c1(parent, pdata) \
- dbx500_add_i2c(parent, 1, U5500_I2C1_BASE, IRQ_DB5500_I2C1, pdata)
-#define db5500_add_i2c2(parent, pdata) \
- dbx500_add_i2c(parent, 2, U5500_I2C2_BASE, IRQ_DB5500_I2C2, pdata)
-#define db5500_add_i2c3(parent, pdata) \
- dbx500_add_i2c(parent, 3, U5500_I2C3_BASE, IRQ_DB5500_I2C3, pdata)
-
-#define db5500_add_msp0_spi(parent, pdata) \
- dbx500_add_msp_spi(parent, "msp0", U5500_MSP0_BASE, \
- IRQ_DB5500_MSP0, pdata)
-#define db5500_add_msp1_spi(parent, pdata) \
- dbx500_add_msp_spi(parent, "msp1", U5500_MSP1_BASE, \
- IRQ_DB5500_MSP1, pdata)
-#define db5500_add_msp2_spi(parent, pdata) \
- dbx500_add_msp_spi(parent, "msp2", U5500_MSP2_BASE, \
- IRQ_DB5500_MSP2, pdata)
-
-#define db5500_add_msp0_spi(parent, pdata) \
- dbx500_add_msp_spi(parent, "msp0", U5500_MSP0_BASE, \
- IRQ_DB5500_MSP0, pdata)
-#define db5500_add_msp1_spi(parent, pdata) \
- dbx500_add_msp_spi(parent, "msp1", U5500_MSP1_BASE, \
- IRQ_DB5500_MSP1, pdata)
-#define db5500_add_msp2_spi(parent, pdata) \
- dbx500_add_msp_spi(parent, "msp2", U5500_MSP2_BASE, \
- IRQ_DB5500_MSP2, pdata)
-
-#define db5500_add_rtc(parent) \
- dbx500_add_rtc(parent, U5500_RTC_BASE, IRQ_DB5500_RTC);
-
-#define db5500_add_usb(parent, rx_cfg, tx_cfg) \
- ux500_add_usb(parent, U5500_USBOTG_BASE, \
- IRQ_DB5500_USBOTG, rx_cfg, tx_cfg)
-
-#define db5500_add_sdi0(parent, pdata) \
- dbx500_add_sdi(parent, "sdi0", U5500_SDI0_BASE, \
- IRQ_DB5500_SDMMC0, pdata, \
- 0x10480180)
-#define db5500_add_sdi1(parent, pdata) \
- dbx500_add_sdi(parent, "sdi1", U5500_SDI1_BASE, \
- IRQ_DB5500_SDMMC1, pdata, \
- 0x10480180)
-#define db5500_add_sdi2(parent, pdata) \
- dbx500_add_sdi(parent, "sdi2", U5500_SDI2_BASE, \
- IRQ_DB5500_SDMMC2, pdata \
- 0x10480180)
-#define db5500_add_sdi3(parent, pdata) \
- dbx500_add_sdi(parent, "sdi3", U5500_SDI3_BASE, \
- IRQ_DB5500_SDMMC3, pdata \
- 0x10480180)
-#define db5500_add_sdi4(parent, pdata) \
- dbx500_add_sdi(parent, "sdi4", U5500_SDI4_BASE, \
- IRQ_DB5500_SDMMC4, pdata \
- 0x10480180)
-
-/* This one has a bad peripheral ID in the U5500 silicon */
-#define db5500_add_spi0(parent, pdata) \
- dbx500_add_spi(parent, "spi0", U5500_SPI0_BASE, \
- IRQ_DB5500_SPI0, pdata, \
- 0x10080023)
-#define db5500_add_spi1(parent, pdata) \
- dbx500_add_spi(parent, "spi1", U5500_SPI1_BASE, \
- IRQ_DB5500_SPI1, pdata, \
- 0x10080023)
-#define db5500_add_spi2(parent, pdata) \
- dbx500_add_spi(parent, "spi2", U5500_SPI2_BASE, \
- IRQ_DB5500_SPI2, pdata \
- 0x10080023)
-#define db5500_add_spi3(parent, pdata) \
- dbx500_add_spi(parent, "spi3", U5500_SPI3_BASE, \
- IRQ_DB5500_SPI3, pdata \
- 0x10080023)
-
-#define db5500_add_uart0(parent, plat) \
- dbx500_add_uart(parent, "uart0", U5500_UART0_BASE, \
- IRQ_DB5500_UART0, plat)
-#define db5500_add_uart1(parent, plat) \
- dbx500_add_uart(parent, "uart1", U5500_UART1_BASE, \
- IRQ_DB5500_UART1, plat)
-#define db5500_add_uart2(parent, plat) \
- dbx500_add_uart(parent, "uart2", U5500_UART2_BASE, \
- IRQ_DB5500_UART2, plat)
-#define db5500_add_uart3(parent, plat) \
- dbx500_add_uart(parent, "uart3", U5500_UART3_BASE, \
- IRQ_DB5500_UART3, plat)
-
-#endif
diff --git a/arch/arm/mach-ux500/devices-db8500.c b/arch/arm/mach-ux500/devices-db8500.c
index 6e66d3777ed5..91754a8a0d49 100644
--- a/arch/arm/mach-ux500/devices-db8500.c
+++ b/arch/arm/mach-ux500/devices-db8500.c
@@ -104,6 +104,8 @@ static const dma_addr_t dma40_tx_map[DB8500_DMA_NR_DEV] = {
[DB8500_DMA_DEV14_MSP2_TX] = U8500_MSP2_BASE + MSP_TX_RX_REG_OFFSET,
[DB8500_DMA_DEV30_MSP1_TX] = U8500_MSP1_BASE + MSP_TX_RX_REG_OFFSET,
[DB8500_DMA_DEV31_MSP0_TX_SLIM0_CH0_TX] = U8500_MSP0_BASE + MSP_TX_RX_REG_OFFSET,
+ [DB8500_DMA_DEV48_CAC1_TX] = U8500_CRYP1_BASE + CRYP1_TX_REG_OFFSET,
+ [DB8500_DMA_DEV50_HAC1_TX] = U8500_HASH1_BASE + HASH1_TX_REG_OFFSET,
};
/* Mapping between source event lines and physical device address */
@@ -139,6 +141,7 @@ static const dma_addr_t dma40_rx_map[DB8500_DMA_NR_DEV] = {
[DB8500_DMA_DEV14_MSP2_RX] = U8500_MSP2_BASE + MSP_TX_RX_REG_OFFSET,
[DB8500_DMA_DEV30_MSP3_RX] = U8500_MSP3_BASE + MSP_TX_RX_REG_OFFSET,
[DB8500_DMA_DEV31_MSP0_RX_SLIM0_CH0_RX] = U8500_MSP0_BASE + MSP_TX_RX_REG_OFFSET,
+ [DB8500_DMA_DEV48_CAC1_RX] = U8500_CRYP1_BASE + CRYP1_RX_REG_OFFSET,
};
/* Reserved event lines for memcpy only */
diff --git a/arch/arm/mach-ux500/devices-db8500.h b/arch/arm/mach-ux500/devices-db8500.h
index 6fc7eb24d9a0..3c8010f4fb3f 100644
--- a/arch/arm/mach-ux500/devices-db8500.h
+++ b/arch/arm/mach-ux500/devices-db8500.h
@@ -34,7 +34,6 @@ db8500_add_ssp(struct device *parent, const char *name, resource_size_t base,
return amba_ahb_device_add(parent, name, base, SZ_4K, irq, 0, pdata, 0);
}
-
#define db8500_add_i2c0(parent, pdata) \
dbx500_add_i2c(parent, 0, U8500_I2C0_BASE, IRQ_DB8500_I2C0, pdata)
#define db8500_add_i2c1(parent, pdata) \
@@ -46,15 +45,6 @@ db8500_add_ssp(struct device *parent, const char *name, resource_size_t base,
#define db8500_add_i2c4(parent, pdata) \
dbx500_add_i2c(parent, 4, U8500_I2C4_BASE, IRQ_DB8500_I2C4, pdata)
-#define db8500_add_msp0_i2s(parent, pdata) \
- dbx500_add_msp_i2s(parent, 0, U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata)
-#define db8500_add_msp1_i2s(parent, pdata) \
- dbx500_add_msp_i2s(parent, 1, U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata)
-#define db8500_add_msp2_i2s(parent, pdata) \
- dbx500_add_msp_i2s(parent, 2, U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata)
-#define db8500_add_msp3_i2s(parent, pdata) \
- dbx500_add_msp_i2s(parent, 3, U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata)
-
#define db8500_add_msp0_spi(parent, pdata) \
dbx500_add_msp_spi(parent, "msp0", U8500_MSP0_BASE, \
IRQ_DB8500_MSP0, pdata)
@@ -124,4 +114,8 @@ db8500_add_ssp(struct device *parent, const char *name, resource_size_t base,
dbx500_add_uart(parent, "uart2", U8500_UART2_BASE, \
IRQ_DB8500_UART2, pdata)
+#define db8500_add_cryp1(parent, pdata) \
+ dbx500_add_cryp1(parent, -1, U8500_CRYP1_BASE, IRQ_DB8500_CRYP1, pdata)
+#define db8500_add_hash1(parent, pdata) \
+ dbx500_add_hash1(parent, -1, U8500_HASH1_BASE, pdata)
#endif
diff --git a/arch/arm/mach-ux500/dma-db5500.c b/arch/arm/mach-ux500/dma-db5500.c
deleted file mode 100644
index 41e9470fa0e6..000000000000
--- a/arch/arm/mach-ux500/dma-db5500.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Per Forlin <per.forlin@stericsson.com> for ST-Ericsson
- * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
- * Author: Rabin Vincent <rabinv.vincent@stericsson.com> for ST-Ericsson
- *
- * License terms: GNU General Public License (GPL), version 2
- */
-
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-
-#include <plat/ste_dma40.h>
-#include <mach/setup.h>
-#include <mach/hardware.h>
-
-#include "ste-dma40-db5500.h"
-
-static struct resource dma40_resources[] = {
- [0] = {
- .start = U5500_DMA_BASE,
- .end = U5500_DMA_BASE + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
- .name = "base",
- },
- [1] = {
- .start = U5500_DMA_LCPA_BASE,
- .end = U5500_DMA_LCPA_BASE + 2 * SZ_1K - 1,
- .flags = IORESOURCE_MEM,
- .name = "lcpa",
- },
- [2] = {
- .start = IRQ_DB5500_DMA,
- .end = IRQ_DB5500_DMA,
- .flags = IORESOURCE_IRQ
- }
-};
-
-/* Default configuration for physical memcpy */
-static struct stedma40_chan_cfg dma40_memcpy_conf_phy = {
- .mode = STEDMA40_MODE_PHYSICAL,
- .dir = STEDMA40_MEM_TO_MEM,
-
- .src_info.data_width = STEDMA40_BYTE_WIDTH,
- .src_info.psize = STEDMA40_PSIZE_PHY_1,
- .src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
-
- .dst_info.data_width = STEDMA40_BYTE_WIDTH,
- .dst_info.psize = STEDMA40_PSIZE_PHY_1,
- .dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
-};
-
-/* Default configuration for logical memcpy */
-static struct stedma40_chan_cfg dma40_memcpy_conf_log = {
- .dir = STEDMA40_MEM_TO_MEM,
-
- .src_info.data_width = STEDMA40_BYTE_WIDTH,
- .src_info.psize = STEDMA40_PSIZE_LOG_1,
- .src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
-
- .dst_info.data_width = STEDMA40_BYTE_WIDTH,
- .dst_info.psize = STEDMA40_PSIZE_LOG_1,
- .dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
-};
-
-/*
- * Mapping between soruce event lines and physical device address This was
- * created assuming that the event line is tied to a device and therefore the
- * address is constant, however this is not true for at least USB, and the
- * values are just placeholders for USB. This table is preserved and used for
- * now.
- */
-static const dma_addr_t dma40_rx_map[DB5500_DMA_NR_DEV] = {
- [DB5500_DMA_DEV24_SDMMC0_RX] = -1,
- [DB5500_DMA_DEV38_USB_OTG_IEP_8] = -1,
- [DB5500_DMA_DEV23_USB_OTG_IEP_7_15] = -1,
- [DB5500_DMA_DEV22_USB_OTG_IEP_6_14] = -1,
- [DB5500_DMA_DEV21_USB_OTG_IEP_5_13] = -1,
- [DB5500_DMA_DEV20_USB_OTG_IEP_4_12] = -1,
- [DB5500_DMA_DEV6_USB_OTG_IEP_3_11] = -1,
- [DB5500_DMA_DEV5_USB_OTG_IEP_2_10] = -1,
- [DB5500_DMA_DEV4_USB_OTG_IEP_1_9] = -1,
-};
-
-/* Mapping between destination event lines and physical device address */
-static const dma_addr_t dma40_tx_map[DB5500_DMA_NR_DEV] = {
- [DB5500_DMA_DEV24_SDMMC0_TX] = -1,
- [DB5500_DMA_DEV38_USB_OTG_OEP_8] = -1,
- [DB5500_DMA_DEV23_USB_OTG_OEP_7_15] = -1,
- [DB5500_DMA_DEV22_USB_OTG_OEP_6_14] = -1,
- [DB5500_DMA_DEV21_USB_OTG_OEP_5_13] = -1,
- [DB5500_DMA_DEV20_USB_OTG_OEP_4_12] = -1,
- [DB5500_DMA_DEV6_USB_OTG_OEP_3_11] = -1,
- [DB5500_DMA_DEV5_USB_OTG_OEP_2_10] = -1,
- [DB5500_DMA_DEV4_USB_OTG_OEP_1_9] = -1,
-};
-
-static int dma40_memcpy_event[] = {
- DB5500_DMA_MEMCPY_TX_1,
- DB5500_DMA_MEMCPY_TX_2,
- DB5500_DMA_MEMCPY_TX_3,
- DB5500_DMA_MEMCPY_TX_4,
- DB5500_DMA_MEMCPY_TX_5,
-};
-
-static struct stedma40_platform_data dma40_plat_data = {
- .dev_len = ARRAY_SIZE(dma40_rx_map),
- .dev_rx = dma40_rx_map,
- .dev_tx = dma40_tx_map,
- .memcpy = dma40_memcpy_event,
- .memcpy_len = ARRAY_SIZE(dma40_memcpy_event),
- .memcpy_conf_phy = &dma40_memcpy_conf_phy,
- .memcpy_conf_log = &dma40_memcpy_conf_log,
- .disabled_channels = {-1},
-};
-
-static struct platform_device dma40_device = {
- .dev = {
- .platform_data = &dma40_plat_data,
- },
- .name = "dma40",
- .id = 0,
- .num_resources = ARRAY_SIZE(dma40_resources),
- .resource = dma40_resources
-};
-
-void __init db5500_dma_init(struct device *parent)
-{
- int ret;
-
- dma40_device.dev.parent = parent;
- ret = platform_device_register(&dma40_device);
- if (ret)
- dev_err(&dma40_device.dev, "unable to register device: %d\n", ret);
-
-}
diff --git a/arch/arm/mach-ux500/id.c b/arch/arm/mach-ux500/id.c
index 15a0f63b2e2b..d1579920139f 100644
--- a/arch/arm/mach-ux500/id.c
+++ b/arch/arm/mach-ux500/id.c
@@ -23,7 +23,7 @@ static unsigned int ux500_read_asicid(phys_addr_t addr)
{
phys_addr_t base = addr & ~0xfff;
struct map_desc desc = {
- .virtual = IO_ADDRESS(base),
+ .virtual = UX500_VIRT_ROM,
.pfn = __phys_to_pfn(base),
.length = SZ_16K,
.type = MT_DEVICE,
@@ -35,7 +35,7 @@ static unsigned int ux500_read_asicid(phys_addr_t addr)
local_flush_tlb_all();
flush_cache_all();
- return readl(__io_address(addr));
+ return readl(IOMEM(UX500_VIRT_ROM + (addr & 0xfff)));
}
static void ux500_print_soc_info(unsigned int asicid)
@@ -67,6 +67,7 @@ static unsigned int partnumber(unsigned int asicid)
* DB8500v2 0x412fc091 0x9001DBF4 0x008500B0
* DB8520v2.2 0x412fc091 0x9001DBF4 0x008500B2
* DB5500v1 0x412fc091 0x9001FFF4 0x005500A0
+ * DB9540 0x413fc090 0xFFFFDBF4 0x009540xx
*/
void __init ux500_map_io(void)
@@ -91,6 +92,10 @@ void __init ux500_map_io(void)
/* DB5500v1 */
addr = 0x9001FFF4;
break;
+
+ case 0x413fc090: /* DB9540 */
+ addr = 0xFFFFDBF4;
+ break;
}
if (addr)
diff --git a/arch/arm/mach-ux500/include/mach/crypto-ux500.h b/arch/arm/mach-ux500/include/mach/crypto-ux500.h
new file mode 100644
index 000000000000..5b2d0817e26a
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/crypto-ux500.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ *
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#ifndef _CRYPTO_UX500_H
+#define _CRYPTO_UX500_H
+#include <linux/dmaengine.h>
+#include <plat/ste_dma40.h>
+
+struct hash_platform_data {
+ void *mem_to_engine;
+ bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
+};
+
+struct cryp_platform_data {
+ struct stedma40_chan_cfg mem_to_engine;
+ struct stedma40_chan_cfg engine_to_mem;
+};
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/db5500-regs.h b/arch/arm/mach-ux500/include/mach/db5500-regs.h
deleted file mode 100644
index 8e714bcb099f..000000000000
--- a/arch/arm/mach-ux500/include/mach/db5500-regs.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License terms: GNU General Public License (GPL) version 2
- */
-
-#ifndef __MACH_DB5500_REGS_H
-#define __MACH_DB5500_REGS_H
-
-#define U5500_PER1_BASE 0xA0020000
-#define U5500_PER2_BASE 0xA0010000
-#define U5500_PER3_BASE 0x80140000
-#define U5500_PER4_BASE 0x80150000
-#define U5500_PER5_BASE 0x80100000
-#define U5500_PER6_BASE 0x80120000
-
-#define U5500_GIC_DIST_BASE 0xA0411000
-#define U5500_GIC_CPU_BASE 0xA0410100
-#define U5500_DMA_BASE 0x90030000
-#define U5500_STM_BASE 0x90020000
-#define U5500_STM_REG_BASE (U5500_STM_BASE + 0xF000)
-#define U5500_MCDE_BASE 0xA0400000
-#define U5500_MODEM_BASE 0xB0000000
-#define U5500_L2CC_BASE 0xA0412000
-#define U5500_SCU_BASE 0xA0410000
-#define U5500_DSI1_BASE 0xA0401000
-#define U5500_DSI2_BASE 0xA0402000
-#define U5500_SIA_BASE 0xA0100000
-#define U5500_SVA_BASE 0x80200000
-#define U5500_HSEM_BASE 0xA0000000
-#define U5500_NAND0_BASE 0x60000000
-#define U5500_NAND1_BASE 0x70000000
-#define U5500_TWD_BASE 0xa0410600
-#define U5500_ICN_BASE 0xA0040000
-#define U5500_B2R2_BASE 0xa0200000
-#define U5500_BOOT_ROM_BASE 0x90000000
-
-#define U5500_FSMC_BASE (U5500_PER1_BASE + 0x0000)
-#define U5500_SDI0_BASE (U5500_PER1_BASE + 0x1000)
-#define U5500_SDI2_BASE (U5500_PER1_BASE + 0x2000)
-#define U5500_UART0_BASE (U5500_PER1_BASE + 0x3000)
-#define U5500_I2C1_BASE (U5500_PER1_BASE + 0x4000)
-#define U5500_MSP0_BASE (U5500_PER1_BASE + 0x5000)
-#define U5500_GPIO0_BASE (U5500_PER1_BASE + 0xE000)
-#define U5500_CLKRST1_BASE (U5500_PER1_BASE + 0xF000)
-
-#define U5500_USBOTG_BASE (U5500_PER2_BASE + 0x0000)
-#define U5500_GPIO1_BASE (U5500_PER2_BASE + 0xE000)
-#define U5500_CLKRST2_BASE (U5500_PER2_BASE + 0xF000)
-
-#define U5500_KEYPAD_BASE (U5500_PER3_BASE + 0x0000)
-#define U5500_PWM_BASE (U5500_PER3_BASE + 0x1000)
-#define U5500_GPIO3_BASE (U5500_PER3_BASE + 0xE000)
-#define U5500_CLKRST3_BASE (U5500_PER3_BASE + 0xF000)
-
-#define U5500_BACKUPRAM0_BASE (U5500_PER4_BASE + 0x0000)
-#define U5500_BACKUPRAM1_BASE (U5500_PER4_BASE + 0x1000)
-#define U5500_RTT0_BASE (U5500_PER4_BASE + 0x2000)
-#define U5500_RTT1_BASE (U5500_PER4_BASE + 0x3000)
-#define U5500_RTC_BASE (U5500_PER4_BASE + 0x4000)
-#define U5500_SCR_BASE (U5500_PER4_BASE + 0x5000)
-#define U5500_DMC_BASE (U5500_PER4_BASE + 0x6000)
-#define U5500_PRCMU_BASE (U5500_PER4_BASE + 0x7000)
-#define U5500_PRCMU_TIMER_3_BASE (U5500_PER4_BASE + 0x07338)
-#define U5500_PRCMU_TIMER_4_BASE (U5500_PER4_BASE + 0x07450)
-#define U5500_MSP1_BASE (U5500_PER4_BASE + 0x9000)
-#define U5500_GPIO2_BASE (U5500_PER4_BASE + 0xA000)
-#define U5500_MTIMER_BASE (U5500_PER4_BASE + 0xC000)
-#define U5500_CDETECT_BASE (U5500_PER4_BASE + 0xF000)
-#define U5500_PRCMU_TCDM_BASE (U5500_PER4_BASE + 0x18000)
-#define U5500_PRCMU_TCPM_BASE (U5500_PER4_BASE + 0x10000)
-#define U5500_TPIU_BASE (U5500_PER4_BASE + 0x50000)
-
-#define U5500_SPI0_BASE (U5500_PER5_BASE + 0x0000)
-#define U5500_SPI1_BASE (U5500_PER5_BASE + 0x1000)
-#define U5500_SPI2_BASE (U5500_PER5_BASE + 0x2000)
-#define U5500_SPI3_BASE (U5500_PER5_BASE + 0x3000)
-#define U5500_UART1_BASE (U5500_PER5_BASE + 0x4000)
-#define U5500_UART2_BASE (U5500_PER5_BASE + 0x5000)
-#define U5500_UART3_BASE (U5500_PER5_BASE + 0x6000)
-#define U5500_SDI1_BASE (U5500_PER5_BASE + 0x7000)
-#define U5500_SDI3_BASE (U5500_PER5_BASE + 0x8000)
-#define U5500_SDI4_BASE (U5500_PER5_BASE + 0x9000)
-#define U5500_I2C2_BASE (U5500_PER5_BASE + 0xA000)
-#define U5500_I2C3_BASE (U5500_PER5_BASE + 0xB000)
-#define U5500_MSP2_BASE (U5500_PER5_BASE + 0xC000)
-#define U5500_IRDA_BASE (U5500_PER5_BASE + 0xD000)
-#define U5500_IRRC_BASE (U5500_PER5_BASE + 0x10000)
-#define U5500_GPIO4_BASE (U5500_PER5_BASE + 0x1E000)
-#define U5500_CLKRST5_BASE (U5500_PER5_BASE + 0x1F000)
-
-#define U5500_RNG_BASE (U5500_PER6_BASE + 0x0000)
-#define U5500_HASH0_BASE (U5500_PER6_BASE + 0x1000)
-#define U5500_HASH1_BASE (U5500_PER6_BASE + 0x2000)
-#define U5500_PKA_BASE (U5500_PER6_BASE + 0x4000)
-#define U5500_PKAM_BASE (U5500_PER6_BASE + 0x5100)
-#define U5500_MTU0_BASE (U5500_PER6_BASE + 0x6000)
-#define U5500_MTU1_BASE (U5500_PER6_BASE + 0x7000)
-#define U5500_CR_BASE (U5500_PER6_BASE + 0x8000)
-#define U5500_CRYP0_BASE (U5500_PER6_BASE + 0xA000)
-#define U5500_CRYP1_BASE (U5500_PER6_BASE + 0xB000)
-#define U5500_CLKRST6_BASE (U5500_PER6_BASE + 0xF000)
-
-#define U5500_GPIOBANK0_BASE U5500_GPIO0_BASE
-#define U5500_GPIOBANK1_BASE (U5500_GPIO0_BASE + 0x80)
-#define U5500_GPIOBANK2_BASE U5500_GPIO1_BASE
-#define U5500_GPIOBANK3_BASE U5500_GPIO2_BASE
-#define U5500_GPIOBANK4_BASE U5500_GPIO3_BASE
-#define U5500_GPIOBANK5_BASE U5500_GPIO4_BASE
-#define U5500_GPIOBANK6_BASE (U5500_GPIO4_BASE + 0x80)
-#define U5500_GPIOBANK7_BASE (U5500_GPIO4_BASE + 0x100)
-
-#define U5500_MBOX_BASE (U5500_MODEM_BASE + 0xFFD1000)
-#define U5500_MBOX0_PEER_START (U5500_MBOX_BASE + 0x40)
-#define U5500_MBOX0_PEER_END (U5500_MBOX_BASE + 0x5F)
-#define U5500_MBOX0_LOCAL_START (U5500_MBOX_BASE + 0x60)
-#define U5500_MBOX0_LOCAL_END (U5500_MBOX_BASE + 0x7F)
-#define U5500_MBOX1_PEER_START (U5500_MBOX_BASE + 0x80)
-#define U5500_MBOX1_PEER_END (U5500_MBOX_BASE + 0x9F)
-#define U5500_MBOX1_LOCAL_START (U5500_MBOX_BASE + 0xA0)
-#define U5500_MBOX1_LOCAL_END (U5500_MBOX_BASE + 0xBF)
-#define U5500_MBOX2_PEER_START (U5500_MBOX_BASE + 0x00)
-#define U5500_MBOX2_PEER_END (U5500_MBOX_BASE + 0x1F)
-#define U5500_MBOX2_LOCAL_START (U5500_MBOX_BASE + 0x20)
-#define U5500_MBOX2_LOCAL_END (U5500_MBOX_BASE + 0x3F)
-
-#define U5500_ACCCON_BASE_SEC (0xBFFF0000)
-#define U5500_ACCCON_BASE (0xBFFF1000)
-#define U5500_ACCCON_CPUVEC_RESET_ADDR_OFFSET (0x00000020)
-#define U5500_ACCCON_ACC_CPU_CTRL_OFFSET (0x000000BC)
-#define U5500_INTCON_MBOX1_INT_RESET_ADDR (0xBFFD31A4)
-
-#define U5500_ESRAM_BASE 0x40000000
-#define U5500_ESRAM_DMA_LCPA_OFFSET 0x10000
-#define U5500_DMA_LCPA_BASE (U5500_ESRAM_BASE + U5500_ESRAM_DMA_LCPA_OFFSET)
-
-#define U5500_MCDE_SIZE 0x1000
-#define U5500_DSI_LINK_SIZE 0x1000
-#define U5500_DSI_LINK_COUNT 0x2
-#define U5500_DSI_LINK1_BASE (U5500_MCDE_BASE + U5500_MCDE_SIZE)
-#define U5500_DSI_LINK2_BASE (U5500_DSI_LINK1_BASE + U5500_DSI_LINK_SIZE)
-
-#endif
diff --git a/arch/arm/mach-ux500/include/mach/db8500-regs.h b/arch/arm/mach-ux500/include/mach/db8500-regs.h
index 9ec20b96d8f2..1530d493879d 100644
--- a/arch/arm/mach-ux500/include/mach/db8500-regs.h
+++ b/arch/arm/mach-ux500/include/mach/db8500-regs.h
@@ -41,6 +41,10 @@
/* ASIC ID is at 0xbf4 offset within this region */
#define U8500_ASIC_ID_BASE 0x9001D000
+#define U9540_BOOT_ROM_BASE 0xFFFE0000
+/* ASIC ID is at 0xbf4 offset within this region */
+#define U9540_ASIC_ID_BASE 0xFFFFD000
+
#define U8500_PER6_BASE 0xa03c0000
#define U8500_PER7_BASE 0xa03d0000
#define U8500_PER5_BASE 0xa03e0000
@@ -96,7 +100,9 @@
#define U8500_SCR_BASE (U8500_PER4_BASE + 0x05000)
#define U8500_DMC_BASE (U8500_PER4_BASE + 0x06000)
#define U8500_PRCMU_BASE (U8500_PER4_BASE + 0x07000)
+#define U9540_DMC1_BASE (U8500_PER4_BASE + 0x0A000)
#define U8500_PRCMU_TCDM_BASE (U8500_PER4_BASE + 0x68000)
+#define U9540_PRCMU_TCDM_BASE (U8500_PER4_BASE + 0x6A000)
#define U8500_PRCMU_TCPM_BASE (U8500_PER4_BASE + 0x60000)
#define U8500_PRCMU_TIMER_3_BASE (U8500_PER4_BASE + 0x07338)
#define U8500_PRCMU_TIMER_4_BASE (U8500_PER4_BASE + 0x07450)
diff --git a/arch/arm/mach-ux500/include/mach/debug-macro.S b/arch/arm/mach-ux500/include/mach/debug-macro.S
index 8d74d927d4e2..67035223334a 100644
--- a/arch/arm/mach-ux500/include/mach/debug-macro.S
+++ b/arch/arm/mach-ux500/include/mach/debug-macro.S
@@ -20,10 +20,6 @@
* built, so that there's some hint during the build that something is wrong.
*/
-#ifdef CONFIG_UX500_SOC_DB5500
-#define __UX500_UART(n) U5500_UART##n##_BASE
-#endif
-
#ifdef CONFIG_UX500_SOC_DB8500
#define __UX500_UART(n) U8500_UART##n##_BASE
#endif
diff --git a/arch/arm/mach-ux500/include/mach/devices.h b/arch/arm/mach-ux500/include/mach/devices.h
index 5f6cb71fc62d..cbc6f1e4104d 100644
--- a/arch/arm/mach-ux500/include/mach/devices.h
+++ b/arch/arm/mach-ux500/include/mach/devices.h
@@ -10,11 +10,13 @@
struct platform_device;
struct amba_device;
-extern struct platform_device u5500_gpio_devs[];
extern struct platform_device u8500_gpio_devs[];
extern struct amba_device ux500_pl031_device;
+extern struct platform_device ux500_hash1_device;
+extern struct platform_device ux500_cryp1_device;
+
extern struct platform_device u8500_dma40_device;
extern struct platform_device ux500_ske_keypad_device;
diff --git a/arch/arm/mach-ux500/include/mach/hardware.h b/arch/arm/mach-ux500/include/mach/hardware.h
index f84698936d36..28d16e744bfd 100644
--- a/arch/arm/mach-ux500/include/mach/hardware.h
+++ b/arch/arm/mach-ux500/include/mach/hardware.h
@@ -17,6 +17,8 @@
*/
#define U8500_IO_VIRTUAL 0xf0000000
#define U8500_IO_PHYSICAL 0xa0000000
+/* This is where we map in the ROM to check ASIC IDs */
+#define UX500_VIRT_ROM 0xf0000000
/* This macro is used in assembly, so no cast */
#define IO_ADDRESS(x) \
@@ -24,13 +26,16 @@
/* typesafe io address */
#define __io_address(n) IOMEM(IO_ADDRESS(n))
+
/* Used by some plat-nomadik code */
#define io_p2v(n) __io_address(n)
#include <mach/db8500-regs.h>
-#include <mach/db5500-regs.h>
#define MSP_TX_RX_REG_OFFSET 0
+#define CRYP1_RX_REG_OFFSET 0x10
+#define CRYP1_TX_REG_OFFSET 0x8
+#define HASH1_TX_REG_OFFSET 0x4
#ifndef __ASSEMBLY__
diff --git a/arch/arm/mach-ux500/include/mach/id.h b/arch/arm/mach-ux500/include/mach/id.h
index 833d6a6edc9b..c6e2db9e9e51 100644
--- a/arch/arm/mach-ux500/include/mach/id.h
+++ b/arch/arm/mach-ux500/include/mach/id.h
@@ -41,6 +41,16 @@ static inline bool __attribute_const__ cpu_is_u8500(void)
return dbx500_partnumber() == 0x8500;
}
+static inline bool __attribute_const__ cpu_is_u9540(void)
+{
+ return dbx500_partnumber() == 0x9540;
+}
+
+static inline bool cpu_is_u8500_family(void)
+{
+ return cpu_is_u8500() || cpu_is_u9540();
+}
+
static inline bool __attribute_const__ cpu_is_u5500(void)
{
return dbx500_partnumber() == 0x5500;
@@ -111,7 +121,12 @@ static inline bool cpu_is_u8500v21(void)
static inline bool cpu_is_u8500v20_or_later(void)
{
- return cpu_is_u8500() && !cpu_is_u8500v10() && !cpu_is_u8500v11();
+ /*
+ * U9540 has so much in common with U8500 that is is considered a
+ * U8500 variant.
+ */
+ return cpu_is_u9540() ||
+ (cpu_is_u8500() && !cpu_is_u8500v10() && !cpu_is_u8500v11());
}
static inline bool ux500_is_svp(void)
diff --git a/arch/arm/mach-ux500/include/mach/irqs-board-u5500.h b/arch/arm/mach-ux500/include/mach/irqs-board-u5500.h
deleted file mode 100644
index 29d972c7717b..000000000000
--- a/arch/arm/mach-ux500/include/mach/irqs-board-u5500.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License terms: GNU General Public License (GPL) version 2
- */
-
-#ifndef __MACH_IRQS_BOARD_U5500_H
-#define __MACH_IRQS_BOARD_U5500_H
-
-#define AB5500_NR_IRQS 5
-#define IRQ_AB5500_BASE IRQ_BOARD_START
-#define IRQ_AB5500_END (IRQ_AB5500_BASE + AB5500_NR_IRQS)
-
-#define U5500_IRQ_END IRQ_AB5500_END
-
-#if IRQ_BOARD_END < U5500_IRQ_END
-#undef IRQ_BOARD_END
-#define IRQ_BOARD_END U5500_IRQ_END
-#endif
-
-#endif
diff --git a/arch/arm/mach-ux500/include/mach/irqs-db5500.h b/arch/arm/mach-ux500/include/mach/irqs-db5500.h
deleted file mode 100644
index 77239776a6f2..000000000000
--- a/arch/arm/mach-ux500/include/mach/irqs-db5500.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Rabin Vincent <rabin.vincent@stericsson.com>
- * License terms: GNU General Public License (GPL) version 2
- */
-
-#ifndef __MACH_IRQS_DB5500_H
-#define __MACH_IRQS_DB5500_H
-
-#define IRQ_DB5500_MTU0 (IRQ_SHPI_START + 4)
-#define IRQ_DB5500_SPI2 (IRQ_SHPI_START + 6)
-#define IRQ_DB5500_PMU0 (IRQ_SHPI_START + 7)
-#define IRQ_DB5500_SPI0 (IRQ_SHPI_START + 8)
-#define IRQ_DB5500_RTT (IRQ_SHPI_START + 9)
-#define IRQ_DB5500_PKA (IRQ_SHPI_START + 10)
-#define IRQ_DB5500_UART0 (IRQ_SHPI_START + 11)
-#define IRQ_DB5500_I2C3 (IRQ_SHPI_START + 12)
-#define IRQ_DB5500_L2CC (IRQ_SHPI_START + 13)
-#define IRQ_DB5500_MSP0 (IRQ_SHPI_START + 14)
-#define IRQ_DB5500_CRYP1 (IRQ_SHPI_START + 15)
-#define IRQ_DB5500_PMU1 (IRQ_SHPI_START + 16)
-#define IRQ_DB5500_MTU1 (IRQ_SHPI_START + 17)
-#define IRQ_DB5500_RTC (IRQ_SHPI_START + 18)
-#define IRQ_DB5500_UART1 (IRQ_SHPI_START + 19)
-#define IRQ_DB5500_USB_WAKEUP (IRQ_SHPI_START + 20)
-#define IRQ_DB5500_I2C0 (IRQ_SHPI_START + 21)
-#define IRQ_DB5500_I2C1 (IRQ_SHPI_START + 22)
-#define IRQ_DB5500_USBOTG (IRQ_SHPI_START + 23)
-#define IRQ_DB5500_DMA_SECURE (IRQ_SHPI_START + 24)
-#define IRQ_DB5500_DMA (IRQ_SHPI_START + 25)
-#define IRQ_DB5500_UART2 (IRQ_SHPI_START + 26)
-#define IRQ_DB5500_ICN_PMU1 (IRQ_SHPI_START + 27)
-#define IRQ_DB5500_ICN_PMU2 (IRQ_SHPI_START + 28)
-#define IRQ_DB5500_UART3 (IRQ_SHPI_START + 29)
-#define IRQ_DB5500_SPI3 (IRQ_SHPI_START + 30)
-#define IRQ_DB5500_SDMMC4 (IRQ_SHPI_START + 31)
-#define IRQ_DB5500_IRRC (IRQ_SHPI_START + 33)
-#define IRQ_DB5500_IRDA_FT (IRQ_SHPI_START + 34)
-#define IRQ_DB5500_IRDA_SD (IRQ_SHPI_START + 35)
-#define IRQ_DB5500_IRDA_FI (IRQ_SHPI_START + 36)
-#define IRQ_DB5500_IRDA_FD (IRQ_SHPI_START + 37)
-#define IRQ_DB5500_FSMC_CODEREADY (IRQ_SHPI_START + 38)
-#define IRQ_DB5500_FSMC_NANDWAIT (IRQ_SHPI_START + 39)
-#define IRQ_DB5500_AB5500 (IRQ_SHPI_START + 40)
-#define IRQ_DB5500_SDMMC2 (IRQ_SHPI_START + 41)
-#define IRQ_DB5500_SIA (IRQ_SHPI_START + 42)
-#define IRQ_DB5500_SIA2 (IRQ_SHPI_START + 43)
-#define IRQ_DB5500_HVA (IRQ_SHPI_START + 44)
-#define IRQ_DB5500_HVA2 (IRQ_SHPI_START + 45)
-#define IRQ_DB5500_PRCMU0 (IRQ_SHPI_START + 46)
-#define IRQ_DB5500_PRCMU1 (IRQ_SHPI_START + 47)
-#define IRQ_DB5500_DISP (IRQ_SHPI_START + 48)
-#define IRQ_DB5500_SDMMC1 (IRQ_SHPI_START + 50)
-#define IRQ_DB5500_MSP1 (IRQ_SHPI_START + 52)
-#define IRQ_DB5500_KBD (IRQ_SHPI_START + 53)
-#define IRQ_DB5500_I2C2 (IRQ_SHPI_START + 55)
-#define IRQ_DB5500_B2R2 (IRQ_SHPI_START + 56)
-#define IRQ_DB5500_CRYP0 (IRQ_SHPI_START + 57)
-#define IRQ_DB5500_SDMMC3 (IRQ_SHPI_START + 59)
-#define IRQ_DB5500_SDMMC0 (IRQ_SHPI_START + 60)
-#define IRQ_DB5500_HSEM (IRQ_SHPI_START + 61)
-#define IRQ_DB5500_SBAG (IRQ_SHPI_START + 63)
-#define IRQ_DB5500_MODEM (IRQ_SHPI_START + 65)
-#define IRQ_DB5500_SPI1 (IRQ_SHPI_START + 96)
-#define IRQ_DB5500_MSP2 (IRQ_SHPI_START + 98)
-#define IRQ_DB5500_SRPTIMER (IRQ_SHPI_START + 101)
-#define IRQ_DB5500_CTI0 (IRQ_SHPI_START + 108)
-#define IRQ_DB5500_CTI1 (IRQ_SHPI_START + 109)
-#define IRQ_DB5500_ICN_ERR (IRQ_SHPI_START + 110)
-#define IRQ_DB5500_MALI_PPMMU (IRQ_SHPI_START + 112)
-#define IRQ_DB5500_MALI_PP (IRQ_SHPI_START + 113)
-#define IRQ_DB5500_MALI_GPMMU (IRQ_SHPI_START + 114)
-#define IRQ_DB5500_MALI_GP (IRQ_SHPI_START + 115)
-#define IRQ_DB5500_MALI (IRQ_SHPI_START + 116)
-#define IRQ_DB5500_PRCMU_SEM (IRQ_SHPI_START + 118)
-#define IRQ_DB5500_GPIO0 (IRQ_SHPI_START + 119)
-#define IRQ_DB5500_GPIO1 (IRQ_SHPI_START + 120)
-#define IRQ_DB5500_GPIO2 (IRQ_SHPI_START + 121)
-#define IRQ_DB5500_GPIO3 (IRQ_SHPI_START + 122)
-#define IRQ_DB5500_GPIO4 (IRQ_SHPI_START + 123)
-#define IRQ_DB5500_GPIO5 (IRQ_SHPI_START + 124)
-#define IRQ_DB5500_GPIO6 (IRQ_SHPI_START + 125)
-#define IRQ_DB5500_GPIO7 (IRQ_SHPI_START + 126)
-
-#ifdef CONFIG_UX500_SOC_DB5500
-
-/*
- * After the GPIO ones we reserve a range of IRQ:s in which virtual
- * IRQ:s representing modem IRQ:s can be allocated
- */
-#define IRQ_MODEM_EVENTS_BASE IRQ_SOC_START
-#define IRQ_MODEM_EVENTS_NBR 72
-#define IRQ_MODEM_EVENTS_END (IRQ_MODEM_EVENTS_BASE + IRQ_MODEM_EVENTS_NBR)
-
-/* List of virtual IRQ:s that are allocated from the range above */
-#define MBOX_PAIR0_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 43)
-#define MBOX_PAIR1_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 45)
-#define MBOX_PAIR2_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 41)
-
-/*
- * We may have several SoCs, but only one will run at a
- * time, so the one with most IRQs will bump this ahead,
- * but the IRQ_SOC_START remains the same for either SoC.
- */
-#if IRQ_SOC_END < IRQ_MODEM_EVENTS_END
-#undef IRQ_SOC_END
-#define IRQ_SOC_END IRQ_MODEM_EVENTS_END
-#endif
-
-#endif /* CONFIG_UX500_SOC_DB5500 */
-
-#endif
diff --git a/arch/arm/mach-ux500/include/mach/irqs.h b/arch/arm/mach-ux500/include/mach/irqs.h
index c23a6b5f0c4e..e8928548b6a3 100644
--- a/arch/arm/mach-ux500/include/mach/irqs.h
+++ b/arch/arm/mach-ux500/include/mach/irqs.h
@@ -24,7 +24,7 @@
*/
#define IRQ_MTU0 (IRQ_SHPI_START + 4)
-#define DBX500_NR_INTERNAL_IRQS 160
+#define DBX500_NR_INTERNAL_IRQS 166
/* After chip-specific IRQ numbers we have the GPIO ones */
#define NOMADIK_NR_GPIO 288
@@ -36,7 +36,6 @@
/* This will be overridden by SoC-specific irq headers */
#define IRQ_SOC_END IRQ_SOC_START
-#include <mach/irqs-db5500.h>
#include <mach/irqs-db8500.h>
#define IRQ_BOARD_START IRQ_SOC_END
@@ -47,10 +46,6 @@
#include <mach/irqs-board-mop500.h>
#endif
-#ifdef CONFIG_MACH_U5500
-#include <mach/irqs-board-u5500.h>
-#endif
-
#define NR_IRQS IRQ_BOARD_END
#endif /* ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-ux500/include/mach/mbox-db5500.h b/arch/arm/mach-ux500/include/mach/mbox-db5500.h
deleted file mode 100644
index 7f9da4d2fbda..000000000000
--- a/arch/arm/mach-ux500/include/mach/mbox-db5500.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for ST-Ericsson.
- * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson.
- * License terms: GNU General Public License (GPL), version 2.
- */
-
-#ifndef __INC_STE_MBOX_H
-#define __INC_STE_MBOX_H
-
-#define MBOX_BUF_SIZE 16
-#define MBOX_NAME_SIZE 8
-
-/**
- * mbox_recv_cb_t - Definition of the mailbox callback.
- * @mbox_msg: The mailbox message.
- * @priv: The clients private data as specified in the call to mbox_setup.
- *
- * This function will be called upon reception of new mailbox messages.
- */
-typedef void mbox_recv_cb_t (u32 mbox_msg, void *priv);
-
-/**
- * struct mbox - Mailbox instance struct
- * @list: Linked list head.
- * @pdev: Pointer to device struct.
- * @cb: Callback function. Will be called
- * when new data is received.
- * @client_data: Clients private data. Will be sent back
- * in the callback function.
- * @virtbase_peer: Virtual address for outgoing mailbox.
- * @virtbase_local: Virtual address for incoming mailbox.
- * @buffer: Then internal queue for outgoing messages.
- * @name: Name of this mailbox.
- * @buffer_available: Completion variable to achieve "blocking send".
- * This variable will be signaled when there is
- * internal buffer space available.
- * @client_blocked: To keep track if any client is currently
- * blocked.
- * @lock: Spinlock to protect this mailbox instance.
- * @write_index: Index in internal buffer to write to.
- * @read_index: Index in internal buffer to read from.
- * @allocated: Indicates whether this particular mailbox
- * id has been allocated by someone.
- */
-struct mbox {
- struct list_head list;
- struct platform_device *pdev;
- mbox_recv_cb_t *cb;
- void *client_data;
- void __iomem *virtbase_peer;
- void __iomem *virtbase_local;
- u32 buffer[MBOX_BUF_SIZE];
- char name[MBOX_NAME_SIZE];
- struct completion buffer_available;
- u8 client_blocked;
- spinlock_t lock;
- u8 write_index;
- u8 read_index;
- bool allocated;
-};
-
-/**
- * mbox_setup - Set up a mailbox and return its instance.
- * @mbox_id: The ID number of the mailbox. 0 or 1 for modem CPU,
- * 2 for modem DSP.
- * @mbox_cb: Pointer to the callback function to be called when a new message
- * is received.
- * @priv: Client user data which will be returned in the callback.
- *
- * Returns a mailbox instance to be specified in subsequent calls to mbox_send.
- */
-struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv);
-
-/**
- * mbox_send - Send a mailbox message.
- * @mbox: Mailbox instance (returned by mbox_setup)
- * @mbox_msg: The mailbox message to send.
- * @block: Specifies whether this call will block until send is possible,
- * or return an error if the mailbox buffer is full.
- *
- * Returns 0 on success or a negative error code on error. -ENOMEM indicates
- * that the internal buffer is full and you have to try again later (or
- * specify "block" in order to block until send is possible).
- */
-int mbox_send(struct mbox *mbox, u32 mbox_msg, bool block);
-
-#endif /*INC_STE_MBOX_H*/
diff --git a/arch/arm/mach-ux500/include/mach/msp.h b/arch/arm/mach-ux500/include/mach/msp.h
new file mode 100644
index 000000000000..798be19129ef
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/msp.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef __MSP_H
+#define __MSP_H
+
+#include <plat/ste_dma40.h>
+
+enum msp_i2s_id {
+ MSP_I2S_0 = 0,
+ MSP_I2S_1,
+ MSP_I2S_2,
+ MSP_I2S_3,
+};
+
+/* Platform data structure for a MSP I2S-device */
+struct msp_i2s_platform_data {
+ enum msp_i2s_id id;
+ struct stedma40_chan_cfg *msp_i2s_dma_rx;
+ struct stedma40_chan_cfg *msp_i2s_dma_tx;
+ int (*msp_i2s_init) (void);
+ int (*msp_i2s_exit) (void);
+};
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/setup.h b/arch/arm/mach-ux500/include/mach/setup.h
index 3dc00ffa7bfa..4e369f1645ec 100644
--- a/arch/arm/mach-ux500/include/mach/setup.h
+++ b/arch/arm/mach-ux500/include/mach/setup.h
@@ -15,18 +15,12 @@
#include <linux/init.h>
void __init ux500_map_io(void);
-extern void __init u5500_map_io(void);
extern void __init u8500_map_io(void);
-extern struct device * __init u5500_init_devices(void);
extern struct device * __init u8500_init_devices(void);
extern void __init ux500_init_irq(void);
-extern void __init u5500_sdi_init(struct device *parent);
-
-extern void __init db5500_dma_init(struct device *parent);
-
extern struct device *ux500_soc_device_init(const char *soc_id);
struct amba_device;
diff --git a/arch/arm/mach-ux500/include/mach/uncompress.h b/arch/arm/mach-ux500/include/mach/uncompress.h
index 6fb3c4b0105d..34775baadaea 100644
--- a/arch/arm/mach-ux500/include/mach/uncompress.h
+++ b/arch/arm/mach-ux500/include/mach/uncompress.h
@@ -50,11 +50,8 @@ static void flush(void)
static inline void arch_decomp_setup(void)
{
- /* Check in run time if we run on an U8500 or U5500 */
- if (machine_is_u5500())
- ux500_uart_base = U5500_UART0_BASE;
- else
- ux500_uart_base = U8500_UART2_BASE;
+ /* Use machine_is_foo() macro if you need to switch base someday */
+ ux500_uart_base = U8500_UART2_BASE;
}
#define arch_decomp_wdog() /* nothing to do here */
diff --git a/arch/arm/mach-ux500/mbox-db5500.c b/arch/arm/mach-ux500/mbox-db5500.c
deleted file mode 100644
index 0127490218cd..000000000000
--- a/arch/arm/mach-ux500/mbox-db5500.c
+++ /dev/null
@@ -1,565 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for ST-Ericsson.
- * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson.
- * License terms: GNU General Public License (GPL), version 2.
- */
-
-/*
- * Mailbox nomenclature:
- *
- * APE MODEM
- * mbox pairX
- * ..........................
- * . .
- * . peer .
- * . send ---- .
- * . --> | | .
- * . | | .
- * . ---- .
- * . .
- * . local .
- * . rec ---- .
- * . | | <-- .
- * . | | .
- * . ---- .
- * .........................
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/platform_device.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/completion.h>
-#include <mach/mbox-db5500.h>
-
-#define MBOX_NAME "mbox"
-
-#define MBOX_FIFO_DATA 0x000
-#define MBOX_FIFO_ADD 0x004
-#define MBOX_FIFO_REMOVE 0x008
-#define MBOX_FIFO_THRES_FREE 0x00C
-#define MBOX_FIFO_THRES_OCCUP 0x010
-#define MBOX_FIFO_STATUS 0x014
-
-#define MBOX_DISABLE_IRQ 0x4
-#define MBOX_ENABLE_IRQ 0x0
-#define MBOX_LATCH 1
-
-/* Global list of all mailboxes */
-static struct list_head mboxs = LIST_HEAD_INIT(mboxs);
-
-static struct mbox *get_mbox_with_id(u8 id)
-{
- u8 i;
- struct list_head *pos = &mboxs;
- for (i = 0; i <= id; i++)
- pos = pos->next;
-
- return (struct mbox *) list_entry(pos, struct mbox, list);
-}
-
-int mbox_send(struct mbox *mbox, u32 mbox_msg, bool block)
-{
- int res = 0;
-
- spin_lock(&mbox->lock);
-
- dev_dbg(&(mbox->pdev->dev),
- "About to buffer 0x%X to mailbox 0x%X."
- " ri = %d, wi = %d\n",
- mbox_msg, (u32)mbox, mbox->read_index,
- mbox->write_index);
-
- /* Check if write buffer is full */
- while (((mbox->write_index + 1) % MBOX_BUF_SIZE) == mbox->read_index) {
- if (!block) {
- dev_dbg(&(mbox->pdev->dev),
- "Buffer full in non-blocking call! "
- "Returning -ENOMEM!\n");
- res = -ENOMEM;
- goto exit;
- }
- spin_unlock(&mbox->lock);
- dev_dbg(&(mbox->pdev->dev),
- "Buffer full in blocking call! Sleeping...\n");
- mbox->client_blocked = 1;
- wait_for_completion(&mbox->buffer_available);
- dev_dbg(&(mbox->pdev->dev),
- "Blocking send was woken up! Trying again...\n");
- spin_lock(&mbox->lock);
- }
-
- mbox->buffer[mbox->write_index] = mbox_msg;
- mbox->write_index = (mbox->write_index + 1) % MBOX_BUF_SIZE;
-
- /*
- * Indicate that we want an IRQ as soon as there is a slot
- * in the FIFO
- */
- writel(MBOX_ENABLE_IRQ, mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
-
-exit:
- spin_unlock(&mbox->lock);
- return res;
-}
-EXPORT_SYMBOL(mbox_send);
-
-#if defined(CONFIG_DEBUG_FS)
-/*
- * Expected input: <value> <nbr sends>
- * Example: "echo 0xdeadbeef 4 > mbox-node" sends 0xdeadbeef 4 times
- */
-static ssize_t mbox_write_fifo(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t count)
-{
- unsigned long mbox_mess;
- unsigned long nbr_sends;
- unsigned long i;
- char int_buf[16];
- char *token;
- char *val;
-
- struct mbox *mbox = (struct mbox *) dev->platform_data;
-
- strncpy((char *) &int_buf, buf, sizeof(int_buf));
- token = (char *) &int_buf;
-
- /* Parse message */
- val = strsep(&token, " ");
- if ((val == NULL) || (strict_strtoul(val, 16, &mbox_mess) != 0))
- mbox_mess = 0xDEADBEEF;
-
- val = strsep(&token, " ");
- if ((val == NULL) || (strict_strtoul(val, 10, &nbr_sends) != 0))
- nbr_sends = 1;
-
- dev_dbg(dev, "Will write 0x%lX %ld times using data struct at 0x%X\n",
- mbox_mess, nbr_sends, (u32) mbox);
-
- for (i = 0; i < nbr_sends; i++)
- mbox_send(mbox, mbox_mess, true);
-
- return count;
-}
-
-static ssize_t mbox_read_fifo(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- int mbox_value;
- struct mbox *mbox = (struct mbox *) dev->platform_data;
-
- if ((readl(mbox->virtbase_local + MBOX_FIFO_STATUS) & 0x7) <= 0)
- return sprintf(buf, "Mailbox is empty\n");
-
- mbox_value = readl(mbox->virtbase_local + MBOX_FIFO_DATA);
- writel(MBOX_LATCH, (mbox->virtbase_local + MBOX_FIFO_REMOVE));
-
- return sprintf(buf, "0x%X\n", mbox_value);
-}
-
-static DEVICE_ATTR(fifo, S_IWUSR | S_IRUGO, mbox_read_fifo, mbox_write_fifo);
-
-static int mbox_show(struct seq_file *s, void *data)
-{
- struct list_head *pos;
- u8 mbox_index = 0;
-
- list_for_each(pos, &mboxs) {
- struct mbox *m =
- (struct mbox *) list_entry(pos, struct mbox, list);
- if (m == NULL) {
- seq_printf(s,
- "Unable to retrieve mailbox %d\n",
- mbox_index);
- continue;
- }
-
- spin_lock(&m->lock);
- if ((m->virtbase_peer == NULL) || (m->virtbase_local == NULL)) {
- seq_printf(s, "MAILBOX %d not setup or corrupt\n",
- mbox_index);
- spin_unlock(&m->lock);
- continue;
- }
-
- seq_printf(s,
- "===========================\n"
- " MAILBOX %d\n"
- " PEER MAILBOX DUMP\n"
- "---------------------------\n"
- "FIFO: 0x%X (%d)\n"
- "Free Threshold: 0x%.2X (%d)\n"
- "Occupied Threshold: 0x%.2X (%d)\n"
- "Status: 0x%.2X (%d)\n"
- " Free spaces (ot): %d (%d)\n"
- " Occup spaces (ot): %d (%d)\n"
- "===========================\n"
- " LOCAL MAILBOX DUMP\n"
- "---------------------------\n"
- "FIFO: 0x%.X (%d)\n"
- "Free Threshold: 0x%.2X (%d)\n"
- "Occupied Threshold: 0x%.2X (%d)\n"
- "Status: 0x%.2X (%d)\n"
- " Free spaces (ot): %d (%d)\n"
- " Occup spaces (ot): %d (%d)\n"
- "===========================\n"
- "write_index: %d\n"
- "read_index : %d\n"
- "===========================\n"
- "\n",
- mbox_index,
- readl(m->virtbase_peer + MBOX_FIFO_DATA),
- readl(m->virtbase_peer + MBOX_FIFO_DATA),
- readl(m->virtbase_peer + MBOX_FIFO_THRES_FREE),
- readl(m->virtbase_peer + MBOX_FIFO_THRES_FREE),
- readl(m->virtbase_peer + MBOX_FIFO_THRES_OCCUP),
- readl(m->virtbase_peer + MBOX_FIFO_THRES_OCCUP),
- readl(m->virtbase_peer + MBOX_FIFO_STATUS),
- readl(m->virtbase_peer + MBOX_FIFO_STATUS),
- (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 4) & 0x7,
- (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 7) & 0x1,
- (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 0) & 0x7,
- (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 3) & 0x1,
- readl(m->virtbase_local + MBOX_FIFO_DATA),
- readl(m->virtbase_local + MBOX_FIFO_DATA),
- readl(m->virtbase_local + MBOX_FIFO_THRES_FREE),
- readl(m->virtbase_local + MBOX_FIFO_THRES_FREE),
- readl(m->virtbase_local + MBOX_FIFO_THRES_OCCUP),
- readl(m->virtbase_local + MBOX_FIFO_THRES_OCCUP),
- readl(m->virtbase_local + MBOX_FIFO_STATUS),
- readl(m->virtbase_local + MBOX_FIFO_STATUS),
- (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 4) & 0x7,
- (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 7) & 0x1,
- (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 0) & 0x7,
- (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 3) & 0x1,
- m->write_index, m->read_index);
- mbox_index++;
- spin_unlock(&m->lock);
- }
-
- return 0;
-}
-
-static int mbox_open(struct inode *inode, struct file *file)
-{
- return single_open(file, mbox_show, NULL);
-}
-
-static const struct file_operations mbox_operations = {
- .owner = THIS_MODULE,
- .open = mbox_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-#endif
-
-static irqreturn_t mbox_irq(int irq, void *arg)
-{
- u32 mbox_value;
- int nbr_occup;
- int nbr_free;
- struct mbox *mbox = (struct mbox *) arg;
-
- spin_lock(&mbox->lock);
-
- dev_dbg(&(mbox->pdev->dev),
- "mbox IRQ [%d] received. ri = %d, wi = %d\n",
- irq, mbox->read_index, mbox->write_index);
-
- /*
- * Check if we have any outgoing messages, and if there is space for
- * them in the FIFO.
- */
- if (mbox->read_index != mbox->write_index) {
- /*
- * Check by reading FREE for LOCAL since that indicates
- * OCCUP for PEER
- */
- nbr_free = (readl(mbox->virtbase_local + MBOX_FIFO_STATUS)
- >> 4) & 0x7;
- dev_dbg(&(mbox->pdev->dev),
- "Status indicates %d empty spaces in the FIFO!\n",
- nbr_free);
-
- while ((nbr_free > 0) &&
- (mbox->read_index != mbox->write_index)) {
- /* Write the message and latch it into the FIFO */
- writel(mbox->buffer[mbox->read_index],
- (mbox->virtbase_peer + MBOX_FIFO_DATA));
- writel(MBOX_LATCH,
- (mbox->virtbase_peer + MBOX_FIFO_ADD));
- dev_dbg(&(mbox->pdev->dev),
- "Wrote message 0x%X to addr 0x%X\n",
- mbox->buffer[mbox->read_index],
- (u32) (mbox->virtbase_peer + MBOX_FIFO_DATA));
-
- nbr_free--;
- mbox->read_index =
- (mbox->read_index + 1) % MBOX_BUF_SIZE;
- }
-
- /*
- * Check if we still want IRQ:s when there is free
- * space to send
- */
- if (mbox->read_index != mbox->write_index) {
- dev_dbg(&(mbox->pdev->dev),
- "Still have messages to send, but FIFO full. "
- "Request IRQ again!\n");
- writel(MBOX_ENABLE_IRQ,
- mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
- } else {
- dev_dbg(&(mbox->pdev->dev),
- "No more messages to send. "
- "Do not request IRQ again!\n");
- writel(MBOX_DISABLE_IRQ,
- mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
- }
-
- /*
- * Check if we can signal any blocked clients that it is OK to
- * start buffering again
- */
- if (mbox->client_blocked &&
- (((mbox->write_index + 1) % MBOX_BUF_SIZE)
- != mbox->read_index)) {
- dev_dbg(&(mbox->pdev->dev),
- "Waking up blocked client\n");
- complete(&mbox->buffer_available);
- mbox->client_blocked = 0;
- }
- }
-
- /* Check if we have any incoming messages */
- nbr_occup = readl(mbox->virtbase_local + MBOX_FIFO_STATUS) & 0x7;
- if (nbr_occup == 0)
- goto exit;
-
- if (mbox->cb == NULL) {
- dev_dbg(&(mbox->pdev->dev), "No receive callback registered, "
- "leaving %d incoming messages in fifo!\n", nbr_occup);
- goto exit;
- }
-
- /* Read and acknowledge the message */
- mbox_value = readl(mbox->virtbase_local + MBOX_FIFO_DATA);
- writel(MBOX_LATCH, (mbox->virtbase_local + MBOX_FIFO_REMOVE));
-
- /* Notify consumer of new mailbox message */
- dev_dbg(&(mbox->pdev->dev), "Calling callback for message 0x%X!\n",
- mbox_value);
- mbox->cb(mbox_value, mbox->client_data);
-
-exit:
- dev_dbg(&(mbox->pdev->dev), "Exit mbox IRQ. ri = %d, wi = %d\n",
- mbox->read_index, mbox->write_index);
- spin_unlock(&mbox->lock);
-
- return IRQ_HANDLED;
-}
-
-/* Setup is executed once for each mbox pair */
-struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv)
-{
- struct resource *resource;
- int irq;
- int res;
- struct mbox *mbox;
-
- mbox = get_mbox_with_id(mbox_id);
- if (mbox == NULL) {
- dev_err(&(mbox->pdev->dev), "Incorrect mailbox id: %d!\n",
- mbox_id);
- goto exit;
- }
-
- /*
- * Check if mailbox has been allocated to someone else,
- * otherwise allocate it
- */
- if (mbox->allocated) {
- dev_err(&(mbox->pdev->dev), "Mailbox number %d is busy!\n",
- mbox_id);
- mbox = NULL;
- goto exit;
- }
- mbox->allocated = true;
-
- dev_dbg(&(mbox->pdev->dev), "Initiating mailbox number %d: 0x%X...\n",
- mbox_id, (u32)mbox);
-
- mbox->client_data = priv;
- mbox->cb = mbox_cb;
-
- /* Get addr for peer mailbox and ioremap it */
- resource = platform_get_resource_byname(mbox->pdev,
- IORESOURCE_MEM,
- "mbox_peer");
- if (resource == NULL) {
- dev_err(&(mbox->pdev->dev),
- "Unable to retrieve mbox peer resource\n");
- mbox = NULL;
- goto exit;
- }
- dev_dbg(&(mbox->pdev->dev),
- "Resource name: %s start: 0x%X, end: 0x%X\n",
- resource->name, resource->start, resource->end);
- mbox->virtbase_peer = ioremap(resource->start, resource_size(resource));
- if (!mbox->virtbase_peer) {
- dev_err(&(mbox->pdev->dev), "Unable to ioremap peer mbox\n");
- mbox = NULL;
- goto exit;
- }
- dev_dbg(&(mbox->pdev->dev),
- "ioremapped peer physical: (0x%X-0x%X) to virtual: 0x%X\n",
- resource->start, resource->end, (u32) mbox->virtbase_peer);
-
- /* Get addr for local mailbox and ioremap it */
- resource = platform_get_resource_byname(mbox->pdev,
- IORESOURCE_MEM,
- "mbox_local");
- if (resource == NULL) {
- dev_err(&(mbox->pdev->dev),
- "Unable to retrieve mbox local resource\n");
- mbox = NULL;
- goto exit;
- }
- dev_dbg(&(mbox->pdev->dev),
- "Resource name: %s start: 0x%X, end: 0x%X\n",
- resource->name, resource->start, resource->end);
- mbox->virtbase_local = ioremap(resource->start, resource_size(resource));
- if (!mbox->virtbase_local) {
- dev_err(&(mbox->pdev->dev), "Unable to ioremap local mbox\n");
- mbox = NULL;
- goto exit;
- }
- dev_dbg(&(mbox->pdev->dev),
- "ioremapped local physical: (0x%X-0x%X) to virtual: 0x%X\n",
- resource->start, resource->end, (u32) mbox->virtbase_peer);
-
- init_completion(&mbox->buffer_available);
- mbox->client_blocked = 0;
-
- /* Get IRQ for mailbox and allocate it */
- irq = platform_get_irq_byname(mbox->pdev, "mbox_irq");
- if (irq < 0) {
- dev_err(&(mbox->pdev->dev),
- "Unable to retrieve mbox irq resource\n");
- mbox = NULL;
- goto exit;
- }
-
- dev_dbg(&(mbox->pdev->dev), "Allocating irq %d...\n", irq);
- res = request_irq(irq, mbox_irq, 0, mbox->name, (void *) mbox);
- if (res < 0) {
- dev_err(&(mbox->pdev->dev),
- "Unable to allocate mbox irq %d\n", irq);
- mbox = NULL;
- goto exit;
- }
-
- /* Set up mailbox to not launch IRQ on free space in mailbox */
- writel(MBOX_DISABLE_IRQ, mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
-
- /*
- * Set up mailbox to launch IRQ on new message if we have
- * a callback set. If not, do not raise IRQ, but keep message
- * in FIFO for manual retrieval
- */
- if (mbox_cb != NULL)
- writel(MBOX_ENABLE_IRQ,
- mbox->virtbase_local + MBOX_FIFO_THRES_OCCUP);
- else
- writel(MBOX_DISABLE_IRQ,
- mbox->virtbase_local + MBOX_FIFO_THRES_OCCUP);
-
-#if defined(CONFIG_DEBUG_FS)
- res = device_create_file(&(mbox->pdev->dev), &dev_attr_fifo);
- if (res != 0)
- dev_warn(&(mbox->pdev->dev),
- "Unable to create mbox sysfs entry");
-
- (void) debugfs_create_file("mbox", S_IFREG | S_IRUGO, NULL,
- NULL, &mbox_operations);
-#endif
-
- dev_info(&(mbox->pdev->dev),
- "Mailbox driver with index %d initiated!\n", mbox_id);
-
-exit:
- return mbox;
-}
-EXPORT_SYMBOL(mbox_setup);
-
-
-int __init mbox_probe(struct platform_device *pdev)
-{
- struct mbox local_mbox;
- struct mbox *mbox;
- int res = 0;
- dev_dbg(&(pdev->dev), "Probing mailbox (pdev = 0x%X)...\n", (u32) pdev);
-
- memset(&local_mbox, 0x0, sizeof(struct mbox));
-
- /* Associate our mbox data with the platform device */
- res = platform_device_add_data(pdev,
- (void *) &local_mbox,
- sizeof(struct mbox));
- if (res != 0) {
- dev_err(&(pdev->dev),
- "Unable to allocate driver platform data!\n");
- goto exit;
- }
-
- mbox = (struct mbox *) pdev->dev.platform_data;
- mbox->pdev = pdev;
- mbox->write_index = 0;
- mbox->read_index = 0;
-
- INIT_LIST_HEAD(&(mbox->list));
- list_add_tail(&(mbox->list), &mboxs);
-
- sprintf(mbox->name, "%s", MBOX_NAME);
- spin_lock_init(&mbox->lock);
-
- dev_info(&(pdev->dev), "Mailbox driver loaded\n");
-
-exit:
- return res;
-}
-
-static struct platform_driver mbox_driver = {
- .driver = {
- .name = MBOX_NAME,
- .owner = THIS_MODULE,
- },
-};
-
-static int __init mbox_init(void)
-{
- return platform_driver_probe(&mbox_driver, mbox_probe);
-}
-
-module_init(mbox_init);
-
-void __exit mbox_exit(void)
-{
- platform_driver_unregister(&mbox_driver);
-}
-
-module_exit(mbox_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("MBOX driver");
diff --git a/arch/arm/mach-ux500/modem-irq-db5500.c b/arch/arm/mach-ux500/modem-irq-db5500.c
deleted file mode 100644
index 6b86416c94c9..000000000000
--- a/arch/arm/mach-ux500/modem-irq-db5500.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for ST-Ericsson.
- * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson.
- * License terms: GNU General Public License (GPL), version 2.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-
-#include <mach/id.h>
-
-#define MODEM_INTCON_BASE_ADDR 0xBFFD3000
-#define MODEM_INTCON_SIZE 0xFFF
-
-#define DEST_IRQ41_OFFSET 0x2A4
-#define DEST_IRQ43_OFFSET 0x2AC
-#define DEST_IRQ45_OFFSET 0x2B4
-
-#define PRIO_IRQ41_OFFSET 0x6A4
-#define PRIO_IRQ43_OFFSET 0x6AC
-#define PRIO_IRQ45_OFFSET 0x6B4
-
-#define ALLOW_IRQ_OFFSET 0x104
-
-#define MODEM_INTCON_CPU_NBR 0x1
-#define MODEM_INTCON_PRIO_HIGH 0x0
-
-#define MODEM_INTCON_ALLOW_IRQ41 0x0200
-#define MODEM_INTCON_ALLOW_IRQ43 0x0800
-#define MODEM_INTCON_ALLOW_IRQ45 0x2000
-
-#define MODEM_IRQ_REG_OFFSET 0x4
-
-struct modem_irq {
- void __iomem *modem_intcon_base;
-};
-
-
-static void setup_modem_intcon(void __iomem *modem_intcon_base)
-{
- /* IC_DESTINATION_BASE_ARRAY - Which CPU to receive the IRQ */
- writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ41_OFFSET);
- writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ43_OFFSET);
- writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ45_OFFSET);
-
- /* IC_PRIORITY_BASE_ARRAY - IRQ priority in modem IRQ controller */
- writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ41_OFFSET);
- writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ43_OFFSET);
- writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ45_OFFSET);
-
- /* IC_ALLOW_ARRAY - IRQ enable */
- writel(MODEM_INTCON_ALLOW_IRQ41 |
- MODEM_INTCON_ALLOW_IRQ43 |
- MODEM_INTCON_ALLOW_IRQ45,
- modem_intcon_base + ALLOW_IRQ_OFFSET);
-}
-
-static irqreturn_t modem_cpu_irq_handler(int irq, void *data)
-{
- int real_irq;
- int virt_irq;
- struct modem_irq *mi = (struct modem_irq *)data;
-
- /* Read modem side IRQ number from modem IRQ controller */
- real_irq = readl(mi->modem_intcon_base + MODEM_IRQ_REG_OFFSET) & 0xFF;
- virt_irq = IRQ_MODEM_EVENTS_BASE + real_irq;
-
- pr_debug("modem_irq: Worker read addr 0x%X and got value 0x%X "
- "which will be 0x%X (%d) which translates to "
- "virtual IRQ 0x%X (%d)!\n",
- (u32)mi->modem_intcon_base + MODEM_IRQ_REG_OFFSET,
- real_irq,
- real_irq & 0xFF,
- real_irq & 0xFF,
- virt_irq,
- virt_irq);
-
- if (virt_irq != 0)
- generic_handle_irq(virt_irq);
-
- pr_debug("modem_irq: Done handling virtual IRQ %d!\n", virt_irq);
-
- return IRQ_HANDLED;
-}
-
-static void create_virtual_irq(int irq, struct irq_chip *modem_irq_chip)
-{
- irq_set_chip_and_handler(irq, modem_irq_chip, handle_simple_irq);
- set_irq_flags(irq, IRQF_VALID);
-
- pr_debug("modem_irq: Created virtual IRQ %d\n", irq);
-}
-
-static int modem_irq_init(void)
-{
- int err;
- static struct irq_chip modem_irq_chip;
- struct modem_irq *mi;
-
- if (!cpu_is_u5500())
- return -ENODEV;
-
- pr_info("modem_irq: Set up IRQ handler for incoming modem IRQ %d\n",
- IRQ_DB5500_MODEM);
-
- mi = kmalloc(sizeof(struct modem_irq), GFP_KERNEL);
- if (!mi) {
- pr_err("modem_irq: Could not allocate device\n");
- return -ENOMEM;
- }
-
- mi->modem_intcon_base =
- ioremap(MODEM_INTCON_BASE_ADDR, MODEM_INTCON_SIZE);
- pr_debug("modem_irq: ioremapped modem_intcon_base from "
- "phy 0x%x to virt 0x%x\n", MODEM_INTCON_BASE_ADDR,
- (u32)mi->modem_intcon_base);
-
- setup_modem_intcon(mi->modem_intcon_base);
-
- modem_irq_chip = dummy_irq_chip;
- modem_irq_chip.name = "modem_irq";
-
- /* Create the virtual IRQ:s needed */
- create_virtual_irq(MBOX_PAIR0_VIRT_IRQ, &modem_irq_chip);
- create_virtual_irq(MBOX_PAIR1_VIRT_IRQ, &modem_irq_chip);
- create_virtual_irq(MBOX_PAIR2_VIRT_IRQ, &modem_irq_chip);
-
- err = request_threaded_irq(IRQ_DB5500_MODEM, NULL,
- modem_cpu_irq_handler, IRQF_ONESHOT,
- "modem_irq", mi);
- if (err)
- pr_err("modem_irq: Could not register IRQ %d\n",
- IRQ_DB5500_MODEM);
-
- return 0;
-}
-
-arch_initcall(modem_irq_init);
diff --git a/arch/arm/mach-ux500/pins-db5500.h b/arch/arm/mach-ux500/pins-db5500.h
deleted file mode 100644
index bf50c21fe69d..000000000000
--- a/arch/arm/mach-ux500/pins-db5500.h
+++ /dev/null
@@ -1,620 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License terms: GNU General Public License, version 2
- * Author: Rabin Vincent <rabin.vincent@stericsson.com>
- */
-
-#ifndef __MACH_DB5500_PINS_H
-#define __MACH_DB5500_PINS_H
-
-#define GPIO0_GPIO PIN_CFG(0, GPIO)
-#define GPIO0_SM_CS3n PIN_CFG(0, ALT_A)
-
-#define GPIO1_GPIO PIN_CFG(1, GPIO)
-#define GPIO1_SM_A3 PIN_CFG(1, ALT_A)
-
-#define GPIO2_GPIO PIN_CFG(2, GPIO)
-#define GPIO2_SM_A4 PIN_CFG(2, ALT_A)
-#define GPIO2_SM_AVD PIN_CFG(2, ALT_B)
-
-#define GPIO3_GPIO PIN_CFG(3, GPIO)
-#define GPIO3_I2C1_SCL PIN_CFG(3, ALT_A)
-
-#define GPIO4_GPIO PIN_CFG(4, GPIO)
-#define GPIO4_I2C1_SDA PIN_CFG(4, ALT_A)
-
-#define GPIO5_GPIO PIN_CFG(5, GPIO)
-#define GPIO5_MC0_DAT0 PIN_CFG(5, ALT_A)
-#define GPIO5_SM_ADQ8 PIN_CFG(5, ALT_B)
-
-#define GPIO6_GPIO PIN_CFG(6, GPIO)
-#define GPIO6_MC0_DAT1 PIN_CFG(6, ALT_A)
-#define GPIO6_SM_ADQ0 PIN_CFG(6, ALT_B)
-
-#define GPIO7_GPIO PIN_CFG(7, GPIO)
-#define GPIO7_MC0_DAT2 PIN_CFG(7, ALT_A)
-#define GPIO7_SM_ADQ9 PIN_CFG(7, ALT_B)
-
-#define GPIO8_GPIO PIN_CFG(8, GPIO)
-#define GPIO8_MC0_DAT3 PIN_CFG(8, ALT_A)
-#define GPIO8_SM_ADQ1 PIN_CFG(8, ALT_B)
-
-#define GPIO9_GPIO PIN_CFG(9, GPIO)
-#define GPIO9_MC0_DAT4 PIN_CFG(9, ALT_A)
-#define GPIO9_SM_ADQ10 PIN_CFG(9, ALT_B)
-
-#define GPIO10_GPIO PIN_CFG(10, GPIO)
-#define GPIO10_MC0_DAT5 PIN_CFG(10, ALT_A)
-#define GPIO10_SM_ADQ2 PIN_CFG(10, ALT_B)
-
-#define GPIO11_GPIO PIN_CFG(11, GPIO)
-#define GPIO11_MC0_DAT6 PIN_CFG(11, ALT_A)
-#define GPIO11_SM_ADQ11 PIN_CFG(11, ALT_B)
-
-#define GPIO12_GPIO PIN_CFG(12, GPIO)
-#define GPIO12_MC0_DAT7 PIN_CFG(12, ALT_A)
-#define GPIO12_SM_ADQ3 PIN_CFG(12, ALT_B)
-
-#define GPIO13_GPIO PIN_CFG(13, GPIO)
-#define GPIO13_MC0_CMD PIN_CFG(13, ALT_A)
-#define GPIO13_SM_BUSY0n PIN_CFG(13, ALT_B)
-#define GPIO13_SM_WAIT0n PIN_CFG(13, ALT_C)
-
-#define GPIO14_GPIO PIN_CFG(14, GPIO)
-#define GPIO14_MC0_CLK PIN_CFG(14, ALT_A)
-#define GPIO14_SM_CS1n PIN_CFG(14, ALT_B)
-#define GPIO14_SM_CKO PIN_CFG(14, ALT_C)
-
-#define GPIO15_GPIO PIN_CFG(15, GPIO)
-#define GPIO15_SM_A5 PIN_CFG(15, ALT_A)
-#define GPIO15_SM_CLE PIN_CFG(15, ALT_B)
-
-#define GPIO16_GPIO PIN_CFG(16, GPIO)
-#define GPIO16_MC2_CMD PIN_CFG(16, ALT_A)
-#define GPIO16_SM_OEn PIN_CFG(16, ALT_B)
-
-#define GPIO17_GPIO PIN_CFG(17, GPIO)
-#define GPIO17_MC2_CLK PIN_CFG(17, ALT_A)
-#define GPIO17_SM_WEn PIN_CFG(17, ALT_B)
-
-#define GPIO18_GPIO PIN_CFG(18, GPIO)
-#define GPIO18_SM_A6 PIN_CFG(18, ALT_A)
-#define GPIO18_SM_ALE PIN_CFG(18, ALT_B)
-#define GPIO18_SM_AVDn PIN_CFG(18, ALT_C)
-
-#define GPIO19_GPIO PIN_CFG(19, GPIO)
-#define GPIO19_MC2_DAT1 PIN_CFG(19, ALT_A)
-#define GPIO19_SM_ADQ4 PIN_CFG(19, ALT_B)
-
-#define GPIO20_GPIO PIN_CFG(20, GPIO)
-#define GPIO20_MC2_DAT3 PIN_CFG(20, ALT_A)
-#define GPIO20_SM_ADQ5 PIN_CFG(20, ALT_B)
-
-#define GPIO21_GPIO PIN_CFG(21, GPIO)
-#define GPIO21_MC2_DAT5 PIN_CFG(21, ALT_A)
-#define GPIO21_SM_ADQ6 PIN_CFG(21, ALT_B)
-
-#define GPIO22_GPIO PIN_CFG(22, GPIO)
-#define GPIO22_MC2_DAT7 PIN_CFG(22, ALT_A)
-#define GPIO22_SM_ADQ7 PIN_CFG(22, ALT_B)
-
-#define GPIO23_GPIO PIN_CFG(23, GPIO)
-#define GPIO23_MC2_DAT0 PIN_CFG(23, ALT_A)
-#define GPIO23_SM_ADQ12 PIN_CFG(23, ALT_B)
-#define GPIO23_MC0_DAT1 PIN_CFG(23, ALT_C)
-
-#define GPIO24_GPIO PIN_CFG(24, GPIO)
-#define GPIO24_MC2_DAT2 PIN_CFG(24, ALT_A)
-#define GPIO24_SM_ADQ13 PIN_CFG(24, ALT_B)
-#define GPIO24_MC0_DAT3 PIN_CFG(24, ALT_C)
-
-#define GPIO25_GPIO PIN_CFG(25, GPIO)
-#define GPIO25_MC2_DAT4 PIN_CFG(25, ALT_A)
-#define GPIO25_SM_ADQ14 PIN_CFG(25, ALT_B)
-#define GPIO25_MC0_CMD PIN_CFG(25, ALT_C)
-
-#define GPIO26_GPIO PIN_CFG(26, GPIO)
-#define GPIO26_MC2_DAT6 PIN_CFG(26, ALT_A)
-#define GPIO26_SM_ADQ15 PIN_CFG(26, ALT_B)
-
-#define GPIO27_GPIO PIN_CFG(27, GPIO)
-#define GPIO27_SM_CS0n PIN_CFG(27, ALT_A)
-#define GPIO27_SM_PS0n PIN_CFG(27, ALT_B)
-
-#define GPIO28_GPIO PIN_CFG(28, GPIO)
-#define GPIO28_U0_TXD PIN_CFG(28, ALT_A)
-#define GPIO28_SM_A0 PIN_CFG(28, ALT_B)
-
-#define GPIO29_GPIO PIN_CFG(29, GPIO)
-#define GPIO29_U0_RXD PIN_CFG(29, ALT_A)
-#define GPIO29_SM_A1 PIN_CFG(29, ALT_B)
-#define GPIO29_PWM_0 PIN_CFG(29, ALT_C)
-
-#define GPIO30_GPIO PIN_CFG(30, GPIO)
-#define GPIO30_MC0_DAT5 PIN_CFG(30, ALT_A)
-#define GPIO30_SM_A2 PIN_CFG(30, ALT_B)
-#define GPIO30_PWM_1 PIN_CFG(30, ALT_C)
-
-#define GPIO31_GPIO PIN_CFG(31, GPIO)
-#define GPIO31_MC0_DAT7 PIN_CFG(31, ALT_A)
-#define GPIO31_SM_CS2n PIN_CFG(31, ALT_B)
-#define GPIO31_PWM_2 PIN_CFG(31, ALT_C)
-
-#define GPIO32_GPIO PIN_CFG(32, GPIO)
-#define GPIO32_MSP0_TCK PIN_CFG(32, ALT_A)
-#define GPIO32_ACCI2S0_SCK PIN_CFG(32, ALT_B)
-
-#define GPIO33_GPIO PIN_CFG(33, GPIO)
-#define GPIO33_MSP0_TFS PIN_CFG(33, ALT_A)
-#define GPIO33_ACCI2S0_WS PIN_CFG(33, ALT_B)
-
-#define GPIO34_GPIO PIN_CFG(34, GPIO)
-#define GPIO34_MSP0_TXD PIN_CFG(34, ALT_A)
-#define GPIO34_ACCI2S0_DLD PIN_CFG(34, ALT_B)
-
-#define GPIO35_GPIO PIN_CFG(35, GPIO)
-#define GPIO35_MSP0_RXD PIN_CFG(35, ALT_A)
-#define GPIO35_ACCI2S0_ULD PIN_CFG(35, ALT_B)
-
-#define GPIO64_GPIO PIN_CFG(64, GPIO)
-#define GPIO64_USB_DAT0 PIN_CFG(64, ALT_A)
-#define GPIO64_U0_TXD PIN_CFG(64, ALT_B)
-
-#define GPIO65_GPIO PIN_CFG(65, GPIO)
-#define GPIO65_USB_DAT1 PIN_CFG(65, ALT_A)
-#define GPIO65_U0_RXD PIN_CFG(65, ALT_B)
-
-#define GPIO66_GPIO PIN_CFG(66, GPIO)
-#define GPIO66_USB_DAT2 PIN_CFG(66, ALT_A)
-
-#define GPIO67_GPIO PIN_CFG(67, GPIO)
-#define GPIO67_USB_DAT3 PIN_CFG(67, ALT_A)
-
-#define GPIO68_GPIO PIN_CFG(68, GPIO)
-#define GPIO68_USB_DAT4 PIN_CFG(68, ALT_A)
-
-#define GPIO69_GPIO PIN_CFG(69, GPIO)
-#define GPIO69_USB_DAT5 PIN_CFG(69, ALT_A)
-
-#define GPIO70_GPIO PIN_CFG(70, GPIO)
-#define GPIO70_USB_DAT6 PIN_CFG(70, ALT_A)
-
-#define GPIO71_GPIO PIN_CFG(71, GPIO)
-#define GPIO71_USB_DAT7 PIN_CFG(71, ALT_A)
-
-#define GPIO72_GPIO PIN_CFG(72, GPIO)
-#define GPIO72_USB_STP PIN_CFG(72, ALT_A)
-
-#define GPIO73_GPIO PIN_CFG(73, GPIO)
-#define GPIO73_USB_DIR PIN_CFG(73, ALT_A)
-
-#define GPIO74_GPIO PIN_CFG(74, GPIO)
-#define GPIO74_USB_NXT PIN_CFG(74, ALT_A)
-
-#define GPIO75_GPIO PIN_CFG(75, GPIO)
-#define GPIO75_USB_XCLK PIN_CFG(75, ALT_A)
-
-#define GPIO76_GPIO PIN_CFG(76, GPIO)
-
-#define GPIO77_GPIO PIN_CFG(77, GPIO)
-#define GPIO77_ACCTX_ON PIN_CFG(77, ALT_A)
-
-#define GPIO78_GPIO PIN_CFG(78, GPIO)
-#define GPIO78_IRQn PIN_CFG(78, ALT_A)
-
-#define GPIO79_GPIO PIN_CFG(79, GPIO)
-#define GPIO79_ACCSIM_Clk PIN_CFG(79, ALT_A)
-
-#define GPIO80_GPIO PIN_CFG(80, GPIO)
-#define GPIO80_ACCSIM_Da PIN_CFG(80, ALT_A)
-
-#define GPIO81_GPIO PIN_CFG(81, GPIO)
-#define GPIO81_ACCSIM_Reset PIN_CFG(81, ALT_A)
-
-#define GPIO82_GPIO PIN_CFG(82, GPIO)
-#define GPIO82_ACCSIM_DDir PIN_CFG(82, ALT_A)
-
-#define GPIO96_GPIO PIN_CFG(96, GPIO)
-#define GPIO96_MSP1_TCK PIN_CFG(96, ALT_A)
-#define GPIO96_PRCMU_DEBUG3 PIN_CFG(96, ALT_B)
-#define GPIO96_PRCMU_DEBUG7 PIN_CFG(96, ALT_C)
-
-#define GPIO97_GPIO PIN_CFG(97, GPIO)
-#define GPIO97_MSP1_TFS PIN_CFG(97, ALT_A)
-#define GPIO97_PRCMU_DEBUG2 PIN_CFG(97, ALT_B)
-#define GPIO97_PRCMU_DEBUG6 PIN_CFG(97, ALT_C)
-
-#define GPIO98_GPIO PIN_CFG(98, GPIO)
-#define GPIO98_MSP1_TXD PIN_CFG(98, ALT_A)
-#define GPIO98_PRCMU_DEBUG1 PIN_CFG(98, ALT_B)
-#define GPIO98_PRCMU_DEBUG5 PIN_CFG(98, ALT_C)
-
-#define GPIO99_GPIO PIN_CFG(99, GPIO)
-#define GPIO99_MSP1_RXD PIN_CFG(99, ALT_A)
-#define GPIO99_PRCMU_DEBUG0 PIN_CFG(99, ALT_B)
-#define GPIO99_PRCMU_DEBUG4 PIN_CFG(99, ALT_C)
-
-#define GPIO100_GPIO PIN_CFG(100, GPIO)
-#define GPIO100_I2C0_SCL PIN_CFG(100, ALT_A)
-
-#define GPIO101_GPIO PIN_CFG(101, GPIO)
-#define GPIO101_I2C0_SDA PIN_CFG(101, ALT_A)
-
-#define GPIO128_GPIO PIN_CFG(128, GPIO)
-#define GPIO128_KP_I0 PIN_CFG(128, ALT_A)
-#define GPIO128_BUSMON_D0 PIN_CFG(128, ALT_B)
-
-#define GPIO129_GPIO PIN_CFG(129, GPIO)
-#define GPIO129_KP_O0 PIN_CFG(129, ALT_A)
-#define GPIO129_BUSMON_D1 PIN_CFG(129, ALT_B)
-
-#define GPIO130_GPIO PIN_CFG(130, GPIO)
-#define GPIO130_KP_I1 PIN_CFG(130, ALT_A)
-#define GPIO130_BUSMON_D2 PIN_CFG(130, ALT_B)
-
-#define GPIO131_GPIO PIN_CFG(131, GPIO)
-#define GPIO131_KP_O1 PIN_CFG(131, ALT_A)
-#define GPIO131_BUSMON_D3 PIN_CFG(131, ALT_B)
-
-#define GPIO132_GPIO PIN_CFG(132, GPIO)
-#define GPIO132_KP_I2 PIN_CFG(132, ALT_A)
-#define GPIO132_ETM_D15 PIN_CFG(132, ALT_B)
-#define GPIO132_STMAPE_CLK PIN_CFG(132, ALT_C)
-
-#define GPIO133_GPIO PIN_CFG(133, GPIO)
-#define GPIO133_KP_O2 PIN_CFG(133, ALT_A)
-#define GPIO133_ETM_D14 PIN_CFG(133, ALT_B)
-#define GPIO133_U0_RXD PIN_CFG(133, ALT_C)
-
-#define GPIO134_GPIO PIN_CFG(134, GPIO)
-#define GPIO134_KP_I3 PIN_CFG(134, ALT_A)
-#define GPIO134_ETM_D13 PIN_CFG(134, ALT_B)
-#define GPIO134_STMAPE_DAT0 PIN_CFG(134, ALT_C)
-
-#define GPIO135_GPIO PIN_CFG(135, GPIO)
-#define GPIO135_KP_O3 PIN_CFG(135, ALT_A)
-#define GPIO135_ETM_D12 PIN_CFG(135, ALT_B)
-#define GPIO135_STMAPE_DAT1 PIN_CFG(135, ALT_C)
-
-#define GPIO136_GPIO PIN_CFG(136, GPIO)
-#define GPIO136_KP_I4 PIN_CFG(136, ALT_A)
-#define GPIO136_ETM_D11 PIN_CFG(136, ALT_B)
-#define GPIO136_STMAPE_DAT2 PIN_CFG(136, ALT_C)
-
-#define GPIO137_GPIO PIN_CFG(137, GPIO)
-#define GPIO137_KP_O4 PIN_CFG(137, ALT_A)
-#define GPIO137_ETM_D10 PIN_CFG(137, ALT_B)
-#define GPIO137_STMAPE_DAT3 PIN_CFG(137, ALT_C)
-
-#define GPIO138_GPIO PIN_CFG(138, GPIO)
-#define GPIO138_KP_I5 PIN_CFG(138, ALT_A)
-#define GPIO138_ETM_D9 PIN_CFG(138, ALT_B)
-#define GPIO138_U0_TXD PIN_CFG(138, ALT_C)
-
-#define GPIO139_GPIO PIN_CFG(139, GPIO)
-#define GPIO139_KP_O5 PIN_CFG(139, ALT_A)
-#define GPIO139_ETM_D8 PIN_CFG(139, ALT_B)
-#define GPIO139_BUSMON_D11 PIN_CFG(139, ALT_C)
-
-#define GPIO140_GPIO PIN_CFG(140, GPIO)
-#define GPIO140_KP_I6 PIN_CFG(140, ALT_A)
-#define GPIO140_ETM_D7 PIN_CFG(140, ALT_B)
-#define GPIO140_STMAPE_CLK PIN_CFG(140, ALT_C)
-
-#define GPIO141_GPIO PIN_CFG(141, GPIO)
-#define GPIO141_KP_O6 PIN_CFG(141, ALT_A)
-#define GPIO141_ETM_D6 PIN_CFG(141, ALT_B)
-#define GPIO141_U0_RXD PIN_CFG(141, ALT_C)
-
-#define GPIO142_GPIO PIN_CFG(142, GPIO)
-#define GPIO142_KP_I7 PIN_CFG(142, ALT_A)
-#define GPIO142_ETM_D5 PIN_CFG(142, ALT_B)
-#define GPIO142_STMAPE_DAT0 PIN_CFG(142, ALT_C)
-
-#define GPIO143_GPIO PIN_CFG(143, GPIO)
-#define GPIO143_KP_O7 PIN_CFG(143, ALT_A)
-#define GPIO143_ETM_D4 PIN_CFG(143, ALT_B)
-#define GPIO143_STMAPE_DAT1 PIN_CFG(143, ALT_C)
-
-#define GPIO144_GPIO PIN_CFG(144, GPIO)
-#define GPIO144_I2C3_SCL PIN_CFG(144, ALT_A)
-#define GPIO144_ETM_D3 PIN_CFG(144, ALT_B)
-#define GPIO144_STMAPE_DAT2 PIN_CFG(144, ALT_C)
-
-#define GPIO145_GPIO PIN_CFG(145, GPIO)
-#define GPIO145_I2C3_SDA PIN_CFG(145, ALT_A)
-#define GPIO145_ETM_D2 PIN_CFG(145, ALT_B)
-#define GPIO145_STMAPE_DAT3 PIN_CFG(145, ALT_C)
-
-#define GPIO146_GPIO PIN_CFG(146, GPIO)
-#define GPIO146_PWM_0 PIN_CFG(146, ALT_A)
-#define GPIO146_ETM_D1 PIN_CFG(146, ALT_B)
-
-#define GPIO147_GPIO PIN_CFG(147, GPIO)
-#define GPIO147_PWM_1 PIN_CFG(147, ALT_A)
-#define GPIO147_ETM_D0 PIN_CFG(147, ALT_B)
-
-#define GPIO148_GPIO PIN_CFG(148, GPIO)
-#define GPIO148_PWM_2 PIN_CFG(148, ALT_A)
-#define GPIO148_ETM_CLK PIN_CFG(148, ALT_B)
-
-#define GPIO160_GPIO PIN_CFG(160, GPIO)
-#define GPIO160_CLKOUT_REQn PIN_CFG(160, ALT_A)
-
-#define GPIO161_GPIO PIN_CFG(161, GPIO)
-#define GPIO161_CLKOUT_0 PIN_CFG(161, ALT_A)
-
-#define GPIO162_GPIO PIN_CFG(162, GPIO)
-#define GPIO162_CLKOUT_1 PIN_CFG(162, ALT_A)
-
-#define GPIO163_GPIO PIN_CFG(163, GPIO)
-
-#define GPIO164_GPIO PIN_CFG(164, GPIO)
-#define GPIO164_GPS_START PIN_CFG(164, ALT_A)
-
-#define GPIO165_GPIO PIN_CFG(165, GPIO)
-#define GPIO165_SPI1_CS2n PIN_CFG(165, ALT_A)
-#define GPIO165_U3_RXD PIN_CFG(165, ALT_B)
-#define GPIO165_BUSMON_D20 PIN_CFG(165, ALT_C)
-
-#define GPIO166_GPIO PIN_CFG(166, GPIO)
-#define GPIO166_SPI1_CS1n PIN_CFG(166, ALT_A)
-#define GPIO166_U3_TXD PIN_CFG(166, ALT_B)
-#define GPIO166_BUSMON_D21 PIN_CFG(166, ALT_C)
-
-#define GPIO167_GPIO PIN_CFG(167, GPIO)
-#define GPIO167_SPI1_CS0n PIN_CFG(167, ALT_A)
-#define GPIO167_U3_RTSn PIN_CFG(167, ALT_B)
-#define GPIO167_BUSMON_D22 PIN_CFG(167, ALT_C)
-
-#define GPIO168_GPIO PIN_CFG(168, GPIO)
-#define GPIO168_SPI1_RXD PIN_CFG(168, ALT_A)
-#define GPIO168_U3_CTSn PIN_CFG(168, ALT_B)
-#define GPIO168_BUSMON_D23 PIN_CFG(168, ALT_C)
-
-#define GPIO169_GPIO PIN_CFG(169, GPIO)
-#define GPIO169_SPI1_TXD PIN_CFG(169, ALT_A)
-#define GPIO169_DDR_RC PIN_CFG(169, ALT_B)
-#define GPIO169_BUSMON_D24 PIN_CFG(169, ALT_C)
-
-#define GPIO170_GPIO PIN_CFG(170, GPIO)
-#define GPIO170_SPI1_CLK PIN_CFG(170, ALT_A)
-
-#define GPIO171_GPIO PIN_CFG(171, GPIO)
-#define GPIO171_MC3_DAT0 PIN_CFG(171, ALT_A)
-#define GPIO171_SPI3_RXD PIN_CFG(171, ALT_B)
-#define GPIO171_BUSMON_D25 PIN_CFG(171, ALT_C)
-
-#define GPIO172_GPIO PIN_CFG(172, GPIO)
-#define GPIO172_MC3_DAT1 PIN_CFG(172, ALT_A)
-#define GPIO172_SPI3_CS1n PIN_CFG(172, ALT_B)
-#define GPIO172_BUSMON_D26 PIN_CFG(172, ALT_C)
-
-#define GPIO173_GPIO PIN_CFG(173, GPIO)
-#define GPIO173_MC3_DAT2 PIN_CFG(173, ALT_A)
-#define GPIO173_SPI3_CS2n PIN_CFG(173, ALT_B)
-#define GPIO173_BUSMON_D27 PIN_CFG(173, ALT_C)
-
-#define GPIO174_GPIO PIN_CFG(174, GPIO)
-#define GPIO174_MC3_DAT3 PIN_CFG(174, ALT_A)
-#define GPIO174_SPI3_CS0n PIN_CFG(174, ALT_B)
-#define GPIO174_BUSMON_D28 PIN_CFG(174, ALT_C)
-
-#define GPIO175_GPIO PIN_CFG(175, GPIO)
-#define GPIO175_MC3_CMD PIN_CFG(175, ALT_A)
-#define GPIO175_SPI3_TXD PIN_CFG(175, ALT_B)
-#define GPIO175_BUSMON_D29 PIN_CFG(175, ALT_C)
-
-#define GPIO176_GPIO PIN_CFG(176, GPIO)
-#define GPIO176_MC3_CLK PIN_CFG(176, ALT_A)
-#define GPIO176_SPI3_CLK PIN_CFG(176, ALT_B)
-
-#define GPIO177_GPIO PIN_CFG(177, GPIO)
-#define GPIO177_U2_RXD PIN_CFG(177, ALT_A)
-#define GPIO177_I2C3_SCL PIN_CFG(177, ALT_B)
-#define GPIO177_BUSMON_D30 PIN_CFG(177, ALT_C)
-
-#define GPIO178_GPIO PIN_CFG(178, GPIO)
-#define GPIO178_U2_TXD PIN_CFG(178, ALT_A)
-#define GPIO178_I2C3_SDA PIN_CFG(178, ALT_B)
-#define GPIO178_BUSMON_D31 PIN_CFG(178, ALT_C)
-
-#define GPIO179_GPIO PIN_CFG(179, GPIO)
-#define GPIO179_U2_CTSn PIN_CFG(179, ALT_A)
-#define GPIO179_U3_RXD PIN_CFG(179, ALT_B)
-#define GPIO179_BUSMON_D32 PIN_CFG(179, ALT_C)
-
-#define GPIO180_GPIO PIN_CFG(180, GPIO)
-#define GPIO180_U2_RTSn PIN_CFG(180, ALT_A)
-#define GPIO180_U3_TXD PIN_CFG(180, ALT_B)
-#define GPIO180_BUSMON_D33 PIN_CFG(180, ALT_C)
-
-#define GPIO185_GPIO PIN_CFG(185, GPIO)
-#define GPIO185_SPI3_CS2n PIN_CFG(185, ALT_A)
-#define GPIO185_MC4_DAT0 PIN_CFG(185, ALT_B)
-
-#define GPIO186_GPIO PIN_CFG(186, GPIO)
-#define GPIO186_SPI3_CS1n PIN_CFG(186, ALT_A)
-#define GPIO186_MC4_DAT1 PIN_CFG(186, ALT_B)
-
-#define GPIO187_GPIO PIN_CFG(187, GPIO)
-#define GPIO187_SPI3_CS0n PIN_CFG(187, ALT_A)
-#define GPIO187_MC4_DAT2 PIN_CFG(187, ALT_B)
-
-#define GPIO188_GPIO PIN_CFG(188, GPIO)
-#define GPIO188_SPI3_RXD PIN_CFG(188, ALT_A)
-#define GPIO188_MC4_DAT3 PIN_CFG(188, ALT_B)
-
-#define GPIO189_GPIO PIN_CFG(189, GPIO)
-#define GPIO189_SPI3_TXD PIN_CFG(189, ALT_A)
-#define GPIO189_MC4_CMD PIN_CFG(189, ALT_B)
-
-#define GPIO190_GPIO PIN_CFG(190, GPIO)
-#define GPIO190_SPI3_CLK PIN_CFG(190, ALT_A)
-#define GPIO190_MC4_CLK PIN_CFG(190, ALT_B)
-
-#define GPIO191_GPIO PIN_CFG(191, GPIO)
-#define GPIO191_MC1_DAT0 PIN_CFG(191, ALT_A)
-#define GPIO191_MC4_DAT4 PIN_CFG(191, ALT_B)
-#define GPIO191_STMAPE_DAT0 PIN_CFG(191, ALT_C)
-
-#define GPIO192_GPIO PIN_CFG(192, GPIO)
-#define GPIO192_MC1_DAT1 PIN_CFG(192, ALT_A)
-#define GPIO192_MC4_DAT5 PIN_CFG(192, ALT_B)
-#define GPIO192_STMAPE_DAT1 PIN_CFG(192, ALT_C)
-
-#define GPIO193_GPIO PIN_CFG(193, GPIO)
-#define GPIO193_MC1_DAT2 PIN_CFG(193, ALT_A)
-#define GPIO193_MC4_DAT6 PIN_CFG(193, ALT_B)
-#define GPIO193_STMAPE_DAT2 PIN_CFG(193, ALT_C)
-
-#define GPIO194_GPIO PIN_CFG(194, GPIO)
-#define GPIO194_MC1_DAT3 PIN_CFG(194, ALT_A)
-#define GPIO194_MC4_DAT7 PIN_CFG(194, ALT_B)
-#define GPIO194_STMAPE_DAT3 PIN_CFG(194, ALT_C)
-
-#define GPIO195_GPIO PIN_CFG(195, GPIO)
-#define GPIO195_MC1_CLK PIN_CFG(195, ALT_A)
-#define GPIO195_STMAPE_CLK PIN_CFG(195, ALT_B)
-#define GPIO195_BUSMON_CLK PIN_CFG(195, ALT_C)
-
-#define GPIO196_GPIO PIN_CFG(196, GPIO)
-#define GPIO196_MC1_CMD PIN_CFG(196, ALT_A)
-#define GPIO196_U0_RXD PIN_CFG(196, ALT_B)
-#define GPIO196_BUSMON_D38 PIN_CFG(196, ALT_C)
-
-#define GPIO197_GPIO PIN_CFG(197, GPIO)
-#define GPIO197_MC1_CMDDIR PIN_CFG(197, ALT_A)
-#define GPIO197_BUSMON_D39 PIN_CFG(197, ALT_B)
-
-#define GPIO198_GPIO PIN_CFG(198, GPIO)
-#define GPIO198_MC1_FBCLK PIN_CFG(198, ALT_A)
-
-#define GPIO199_GPIO PIN_CFG(199, GPIO)
-#define GPIO199_MC1_DAT0DIR PIN_CFG(199, ALT_A)
-#define GPIO199_BUSMON_D40 PIN_CFG(199, ALT_B)
-
-#define GPIO200_GPIO PIN_CFG(200, GPIO)
-#define GPIO200_U1_TXD PIN_CFG(200, ALT_A)
-#define GPIO200_ACCU0_RTSn PIN_CFG(200, ALT_B)
-
-#define GPIO201_GPIO PIN_CFG(201, GPIO)
-#define GPIO201_U1_RXD PIN_CFG(201, ALT_A)
-#define GPIO201_ACCU0_CTSn PIN_CFG(201, ALT_B)
-
-#define GPIO202_GPIO PIN_CFG(202, GPIO)
-#define GPIO202_U1_CTSn PIN_CFG(202, ALT_A)
-#define GPIO202_ACCU0_RXD PIN_CFG(202, ALT_B)
-
-#define GPIO203_GPIO PIN_CFG(203, GPIO)
-#define GPIO203_U1_RTSn PIN_CFG(203, ALT_A)
-#define GPIO203_ACCU0_TXD PIN_CFG(203, ALT_B)
-
-#define GPIO204_GPIO PIN_CFG(204, GPIO)
-#define GPIO204_SPI0_CS2n PIN_CFG(204, ALT_A)
-#define GPIO204_ACCGPIO_000 PIN_CFG(204, ALT_B)
-#define GPIO204_LCD_VSI1 PIN_CFG(204, ALT_C)
-
-#define GPIO205_GPIO PIN_CFG(205, GPIO)
-#define GPIO205_SPI0_CS1n PIN_CFG(205, ALT_A)
-#define GPIO205_ACCGPIO_001 PIN_CFG(205, ALT_B)
-#define GPIO205_LCD_D3 PIN_CFG(205, ALT_C)
-
-#define GPIO206_GPIO PIN_CFG(206, GPIO)
-#define GPIO206_SPI0_CS0n PIN_CFG(206, ALT_A)
-#define GPIO206_ACCGPIO_002 PIN_CFG(206, ALT_B)
-#define GPIO206_LCD_D2 PIN_CFG(206, ALT_C)
-
-#define GPIO207_GPIO PIN_CFG(207, GPIO)
-#define GPIO207_SPI0_RXD PIN_CFG(207, ALT_A)
-#define GPIO207_ACCGPIO_003 PIN_CFG(207, ALT_B)
-#define GPIO207_LCD_D1 PIN_CFG(207, ALT_C)
-
-#define GPIO208_GPIO PIN_CFG(208, GPIO)
-#define GPIO208_SPI0_TXD PIN_CFG(208, ALT_A)
-#define GPIO208_ACCGPIO_004 PIN_CFG(208, ALT_B)
-#define GPIO208_LCD_D0 PIN_CFG(208, ALT_C)
-
-#define GPIO209_GPIO PIN_CFG(209, GPIO)
-#define GPIO209_SPI0_CLK PIN_CFG(209, ALT_A)
-#define GPIO209_ACCGPIO_005 PIN_CFG(209, ALT_B)
-#define GPIO209_LCD_CLK PIN_CFG(209, ALT_C)
-
-#define GPIO210_GPIO PIN_CFG(210, GPIO)
-#define GPIO210_LCD_VSO PIN_CFG(210, ALT_A)
-#define GPIO210_PRCMU_PWRCTRL1 PIN_CFG(210, ALT_B)
-
-#define GPIO211_GPIO PIN_CFG(211, GPIO)
-#define GPIO211_LCD_VSI0 PIN_CFG(211, ALT_A)
-#define GPIO211_PRCMU_PWRCTRL2 PIN_CFG(211, ALT_B)
-
-#define GPIO212_GPIO PIN_CFG(212, GPIO)
-#define GPIO212_SPI2_CS2n PIN_CFG(212, ALT_A)
-#define GPIO212_LCD_HSO PIN_CFG(212, ALT_B)
-
-#define GPIO213_GPIO PIN_CFG(213, GPIO)
-#define GPIO213_SPI2_CS1n PIN_CFG(213, ALT_A)
-#define GPIO213_LCD_DE PIN_CFG(213, ALT_B)
-#define GPIO213_BUSMON_D16 PIN_CFG(213, ALT_C)
-
-#define GPIO214_GPIO PIN_CFG(214, GPIO)
-#define GPIO214_SPI2_CS0n PIN_CFG(214, ALT_A)
-#define GPIO214_LCD_D7 PIN_CFG(214, ALT_B)
-#define GPIO214_BUSMON_D17 PIN_CFG(214, ALT_C)
-
-#define GPIO215_GPIO PIN_CFG(215, GPIO)
-#define GPIO215_SPI2_RXD PIN_CFG(215, ALT_A)
-#define GPIO215_LCD_D6 PIN_CFG(215, ALT_B)
-#define GPIO215_BUSMON_D18 PIN_CFG(215, ALT_C)
-
-#define GPIO216_GPIO PIN_CFG(216, GPIO)
-#define GPIO216_SPI2_CLK PIN_CFG(216, ALT_A)
-#define GPIO216_LCD_D5 PIN_CFG(216, ALT_B)
-
-#define GPIO217_GPIO PIN_CFG(217, GPIO)
-#define GPIO217_SPI2_TXD PIN_CFG(217, ALT_A)
-#define GPIO217_LCD_D4 PIN_CFG(217, ALT_B)
-#define GPIO217_BUSMON_D19 PIN_CFG(217, ALT_C)
-
-#define GPIO218_GPIO PIN_CFG(218, GPIO)
-#define GPIO218_I2C2_SCL PIN_CFG(218, ALT_A)
-#define GPIO218_LCD_VSO PIN_CFG(218, ALT_B)
-
-#define GPIO219_GPIO PIN_CFG(219, GPIO)
-#define GPIO219_I2C2_SDA PIN_CFG(219, ALT_A)
-#define GPIO219_LCD_D3 PIN_CFG(219, ALT_B)
-
-#define GPIO220_GPIO PIN_CFG(220, GPIO)
-#define GPIO220_MSP2_TCK PIN_CFG(220, ALT_A)
-#define GPIO220_LCD_D2 PIN_CFG(220, ALT_B)
-
-#define GPIO221_GPIO PIN_CFG(221, GPIO)
-#define GPIO221_MSP2_TFS PIN_CFG(221, ALT_A)
-#define GPIO221_LCD_D1 PIN_CFG(221, ALT_B)
-
-#define GPIO222_GPIO PIN_CFG(222, GPIO)
-#define GPIO222_MSP2_TXD PIN_CFG(222, ALT_A)
-#define GPIO222_LCD_D0 PIN_CFG(222, ALT_B)
-
-#define GPIO223_GPIO PIN_CFG(223, GPIO)
-#define GPIO223_MSP2_RXD PIN_CFG(223, ALT_A)
-#define GPIO223_LCD_CLK PIN_CFG(223, ALT_B)
-
-#define GPIO224_GPIO PIN_CFG(224, GPIO)
-#define GPIO224_PRCMU_PWRCTRL0 PIN_CFG(224, ALT_A)
-#define GPIO224_LCD_VSI1 PIN_CFG(224, ALT_B)
-
-#define GPIO225_GPIO PIN_CFG(225, GPIO)
-#define GPIO225_PRCMU_PWRCTRL1 PIN_CFG(225, ALT_A)
-#define GPIO225_IRDA_RXD PIN_CFG(225, ALT_B)
-
-#define GPIO226_GPIO PIN_CFG(226, GPIO)
-#define GPIO226_PRCMU_PWRCTRL2 PIN_CFG(226, ALT_A)
-#define GPIO226_IRRC_DAT PIN_CFG(226, ALT_B)
-
-#define GPIO227_GPIO PIN_CFG(227, GPIO)
-#define GPIO227_IRRC_DAT PIN_CFG(227, ALT_A)
-#define GPIO227_IRDA_TXD PIN_CFG(227, ALT_B)
-
-#endif
diff --git a/arch/arm/mach-ux500/pins-db8500.h b/arch/arm/mach-ux500/pins-db8500.h
index 8b1d1a7a679e..062c7acf4576 100644
--- a/arch/arm/mach-ux500/pins-db8500.h
+++ b/arch/arm/mach-ux500/pins-db8500.h
@@ -35,40 +35,40 @@
#define GPIO4_GPIO PIN_CFG(4, GPIO)
#define GPIO4_U1_RXD PIN_CFG(4, ALT_A)
-#define GPIO4_I2C4_SCL PIN_CFG_INPUT(4, ALT_B, PULLUP)
+#define GPIO4_I2C4_SCL PIN_CFG(4, ALT_B)
#define GPIO4_IP_TRSTn PIN_CFG(4, ALT_C)
#define GPIO5_GPIO PIN_CFG(5, GPIO)
#define GPIO5_U1_TXD PIN_CFG(5, ALT_A)
-#define GPIO5_I2C4_SDA PIN_CFG_INPUT(5, ALT_B, PULLUP)
+#define GPIO5_I2C4_SDA PIN_CFG(5, ALT_B)
#define GPIO5_IP_GPIO6 PIN_CFG(5, ALT_C)
#define GPIO6_GPIO PIN_CFG(6, GPIO)
#define GPIO6_U1_CTSn PIN_CFG(6, ALT_A)
-#define GPIO6_I2C1_SCL PIN_CFG_INPUT(6, ALT_B, PULLUP)
+#define GPIO6_I2C1_SCL PIN_CFG(6, ALT_B)
#define GPIO6_IP_GPIO0 PIN_CFG(6, ALT_C)
#define GPIO7_GPIO PIN_CFG(7, GPIO)
#define GPIO7_U1_RTSn PIN_CFG(7, ALT_A)
-#define GPIO7_I2C1_SDA PIN_CFG_INPUT(7, ALT_B, PULLUP)
+#define GPIO7_I2C1_SDA PIN_CFG(7, ALT_B)
#define GPIO7_IP_GPIO1 PIN_CFG(7, ALT_C)
#define GPIO8_GPIO PIN_CFG(8, GPIO)
-#define GPIO8_IPI2C_SDA PIN_CFG_INPUT(8, ALT_A, PULLUP)
-#define GPIO8_I2C2_SDA PIN_CFG_INPUT(8, ALT_B, PULLUP)
+#define GPIO8_IPI2C_SDA PIN_CFG(8, ALT_A)
+#define GPIO8_I2C2_SDA PIN_CFG(8, ALT_B)
#define GPIO9_GPIO PIN_CFG(9, GPIO)
-#define GPIO9_IPI2C_SCL PIN_CFG_INPUT(9, ALT_A, PULLUP)
-#define GPIO9_I2C2_SCL PIN_CFG_INPUT(9, ALT_B, PULLUP)
+#define GPIO9_IPI2C_SCL PIN_CFG(9, ALT_A)
+#define GPIO9_I2C2_SCL PIN_CFG(9, ALT_B)
#define GPIO10_GPIO PIN_CFG(10, GPIO)
-#define GPIO10_IPI2C_SDA PIN_CFG_INPUT(10, ALT_A, PULLUP)
-#define GPIO10_I2C2_SDA PIN_CFG_INPUT(10, ALT_B, PULLUP)
+#define GPIO10_IPI2C_SDA PIN_CFG(10, ALT_A)
+#define GPIO10_I2C2_SDA PIN_CFG(10, ALT_B)
#define GPIO10_IP_GPIO3 PIN_CFG(10, ALT_C)
#define GPIO11_GPIO PIN_CFG(11, GPIO)
-#define GPIO11_IPI2C_SCL PIN_CFG_INPUT(11, ALT_A, PULLUP)
-#define GPIO11_I2C2_SCL PIN_CFG_INPUT(11, ALT_B, PULLUP)
+#define GPIO11_IPI2C_SCL PIN_CFG(11, ALT_A)
+#define GPIO11_I2C2_SCL PIN_CFG(11, ALT_B)
#define GPIO11_IP_GPIO2 PIN_CFG(11, ALT_C)
#define GPIO12_GPIO PIN_CFG(12, GPIO)
@@ -87,12 +87,12 @@
#define GPIO16_GPIO PIN_CFG(16, GPIO)
#define GPIO16_MSP0_RFS PIN_CFG(16, ALT_A)
-#define GPIO16_I2C1_SCL PIN_CFG_INPUT(16, ALT_B, PULLUP)
+#define GPIO16_I2C1_SCL PIN_CFG(16, ALT_B)
#define GPIO16_SLIM0_DAT PIN_CFG(16, ALT_C)
#define GPIO17_GPIO PIN_CFG(17, GPIO)
#define GPIO17_MSP0_RCK PIN_CFG(17, ALT_A)
-#define GPIO17_I2C1_SDA PIN_CFG_INPUT(17, ALT_B, PULLUP)
+#define GPIO17_I2C1_SDA PIN_CFG(17, ALT_B)
#define GPIO17_SLIM0_CLK PIN_CFG(17, ALT_C)
#define GPIO18_GPIO PIN_CFG(18, GPIO)
@@ -434,10 +434,10 @@
#define GPIO146_SSP0_TXD PIN_CFG(146, ALT_A)
#define GPIO147_GPIO PIN_CFG(147, GPIO)
-#define GPIO147_I2C0_SCL PIN_CFG_INPUT(147, ALT_A, PULLUP)
+#define GPIO147_I2C0_SCL PIN_CFG(147, ALT_A)
#define GPIO148_GPIO PIN_CFG(148, GPIO)
-#define GPIO148_I2C0_SDA PIN_CFG_INPUT(148, ALT_A, PULLUP)
+#define GPIO148_I2C0_SDA PIN_CFG(148, ALT_A)
#define GPIO149_GPIO PIN_CFG(149, GPIO)
#define GPIO149_IP_GPIO0 PIN_CFG(149, ALT_A)
@@ -459,82 +459,82 @@
#define GPIO152_KP_O9 PIN_CFG(152, ALT_C)
#define GPIO153_GPIO PIN_CFG(153, GPIO)
-#define GPIO153_KP_I7 PIN_CFG_INPUT(153, ALT_A, PULLDOWN)
+#define GPIO153_KP_I7 PIN_CFG(153, ALT_A)
#define GPIO153_LCD_D24 PIN_CFG(153, ALT_B)
#define GPIO153_U2_RXD PIN_CFG(153, ALT_C)
#define GPIO154_GPIO PIN_CFG(154, GPIO)
-#define GPIO154_KP_I6 PIN_CFG_INPUT(154, ALT_A, PULLDOWN)
+#define GPIO154_KP_I6 PIN_CFG(154, ALT_A)
#define GPIO154_LCD_D25 PIN_CFG(154, ALT_B)
#define GPIO154_U2_TXD PIN_CFG(154, ALT_C)
#define GPIO155_GPIO PIN_CFG(155, GPIO)
-#define GPIO155_KP_I5 PIN_CFG_INPUT(155, ALT_A, PULLDOWN)
+#define GPIO155_KP_I5 PIN_CFG(155, ALT_A)
#define GPIO155_LCD_D26 PIN_CFG(155, ALT_B)
#define GPIO155_STMAPE_CLK PIN_CFG(155, ALT_C)
#define GPIO156_GPIO PIN_CFG(156, GPIO)
-#define GPIO156_KP_I4 PIN_CFG_INPUT(156, ALT_A, PULLDOWN)
+#define GPIO156_KP_I4 PIN_CFG(156, ALT_A)
#define GPIO156_LCD_D27 PIN_CFG(156, ALT_B)
#define GPIO156_STMAPE_DAT3 PIN_CFG(156, ALT_C)
#define GPIO157_GPIO PIN_CFG(157, GPIO)
-#define GPIO157_KP_O7 PIN_CFG_INPUT(157, ALT_A, PULLUP)
+#define GPIO157_KP_O7 PIN_CFG(157, ALT_A)
#define GPIO157_LCD_D28 PIN_CFG(157, ALT_B)
#define GPIO157_STMAPE_DAT2 PIN_CFG(157, ALT_C)
#define GPIO158_GPIO PIN_CFG(158, GPIO)
-#define GPIO158_KP_O6 PIN_CFG_INPUT(158, ALT_A, PULLUP)
+#define GPIO158_KP_O6 PIN_CFG(158, ALT_A)
#define GPIO158_LCD_D29 PIN_CFG(158, ALT_B)
#define GPIO158_STMAPE_DAT1 PIN_CFG(158, ALT_C)
#define GPIO159_GPIO PIN_CFG(159, GPIO)
-#define GPIO159_KP_O5 PIN_CFG_INPUT(159, ALT_A, PULLUP)
+#define GPIO159_KP_O5 PIN_CFG(159, ALT_A)
#define GPIO159_LCD_D30 PIN_CFG(159, ALT_B)
#define GPIO159_STMAPE_DAT0 PIN_CFG(159, ALT_C)
#define GPIO160_GPIO PIN_CFG(160, GPIO)
-#define GPIO160_KP_O4 PIN_CFG_INPUT(160, ALT_A, PULLUP)
+#define GPIO160_KP_O4 PIN_CFG(160, ALT_A)
#define GPIO160_LCD_D31 PIN_CFG(160, ALT_B)
#define GPIO160_NONE PIN_CFG(160, ALT_C)
#define GPIO161_GPIO PIN_CFG(161, GPIO)
-#define GPIO161_KP_I3 PIN_CFG_INPUT(161, ALT_A, PULLDOWN)
+#define GPIO161_KP_I3 PIN_CFG(161, ALT_A)
#define GPIO161_LCD_D32 PIN_CFG(161, ALT_B)
#define GPIO161_UARTMOD_RXD PIN_CFG(161, ALT_C)
#define GPIO162_GPIO PIN_CFG(162, GPIO)
-#define GPIO162_KP_I2 PIN_CFG_INPUT(162, ALT_A, PULLDOWN)
+#define GPIO162_KP_I2 PIN_CFG(162, ALT_A)
#define GPIO162_LCD_D33 PIN_CFG(162, ALT_B)
#define GPIO162_UARTMOD_TXD PIN_CFG(162, ALT_C)
#define GPIO163_GPIO PIN_CFG(163, GPIO)
-#define GPIO163_KP_I1 PIN_CFG_INPUT(163, ALT_A, PULLDOWN)
+#define GPIO163_KP_I1 PIN_CFG(163, ALT_A)
#define GPIO163_LCD_D34 PIN_CFG(163, ALT_B)
#define GPIO163_STMMOD_CLK PIN_CFG(163, ALT_C)
#define GPIO164_GPIO PIN_CFG(164, GPIO)
-#define GPIO164_KP_I0 PIN_CFG_INPUT(164, ALT_A, PULLUP)
+#define GPIO164_KP_I0 PIN_CFG(164, ALT_A)
#define GPIO164_LCD_D35 PIN_CFG(164, ALT_B)
#define GPIO164_STMMOD_DAT3 PIN_CFG(164, ALT_C)
#define GPIO165_GPIO PIN_CFG(165, GPIO)
-#define GPIO165_KP_O3 PIN_CFG_INPUT(165, ALT_A, PULLUP)
+#define GPIO165_KP_O3 PIN_CFG(165, ALT_A)
#define GPIO165_LCD_D36 PIN_CFG(165, ALT_B)
#define GPIO165_STMMOD_DAT2 PIN_CFG(165, ALT_C)
#define GPIO166_GPIO PIN_CFG(166, GPIO)
-#define GPIO166_KP_O2 PIN_CFG_INPUT(166, ALT_A, PULLUP)
+#define GPIO166_KP_O2 PIN_CFG(166, ALT_A)
#define GPIO166_LCD_D37 PIN_CFG(166, ALT_B)
#define GPIO166_STMMOD_DAT1 PIN_CFG(166, ALT_C)
#define GPIO167_GPIO PIN_CFG(167, GPIO)
-#define GPIO167_KP_O1 PIN_CFG_INPUT(167, ALT_A, PULLUP)
+#define GPIO167_KP_O1 PIN_CFG(167, ALT_A)
#define GPIO167_LCD_D38 PIN_CFG(167, ALT_B)
#define GPIO167_STMMOD_DAT0 PIN_CFG(167, ALT_C)
#define GPIO168_GPIO PIN_CFG(168, GPIO)
-#define GPIO168_KP_O0 PIN_CFG_INPUT(168, ALT_A, PULLUP)
+#define GPIO168_KP_O0 PIN_CFG(168, ALT_A)
#define GPIO168_LCD_D39 PIN_CFG(168, ALT_B)
#define GPIO168_NONE PIN_CFG(168, ALT_C)
@@ -637,7 +637,7 @@
#define GPIO216_GPIO PIN_CFG(216, GPIO)
#define GPIO216_MC1_DAT2DIR PIN_CFG(216, ALT_A)
#define GPIO216_MC3_CMDDIR PIN_CFG(216, ALT_B)
-#define GPIO216_I2C3_SDA PIN_CFG_INPUT(216, ALT_C, PULLUP)
+#define GPIO216_I2C3_SDA PIN_CFG(216, ALT_C)
#define GPIO216_SPI2_FRM PIN_CFG(216, ALT_C)
#define GPIO217_GPIO PIN_CFG(217, GPIO)
@@ -649,7 +649,7 @@
#define GPIO218_GPIO PIN_CFG(218, GPIO)
#define GPIO218_MC1_DAT31DIR PIN_CFG(218, ALT_A)
#define GPIO218_MC3_DAT0DIR PIN_CFG(218, ALT_B)
-#define GPIO218_I2C3_SCL PIN_CFG_INPUT(218, ALT_C, PULLUP)
+#define GPIO218_I2C3_SCL PIN_CFG(218, ALT_C)
#define GPIO218_SPI2_RXD PIN_CFG(218, ALT_C)
#define GPIO219_GPIO PIN_CFG(219, GPIO)
@@ -698,12 +698,12 @@
#define GPIO229_GPIO PIN_CFG(229, GPIO)
#define GPIO229_CLKOUT1 PIN_CFG(229, ALT_A)
#define GPIO229_PWL PIN_CFG(229, ALT_B)
-#define GPIO229_I2C3_SDA PIN_CFG_INPUT(229, ALT_C, PULLUP)
+#define GPIO229_I2C3_SDA PIN_CFG(229, ALT_C)
#define GPIO230_GPIO PIN_CFG(230, GPIO)
#define GPIO230_CLKOUT2 PIN_CFG(230, ALT_A)
#define GPIO230_PWL PIN_CFG(230, ALT_B)
-#define GPIO230_I2C3_SCL PIN_CFG_INPUT(230, ALT_C, PULLUP)
+#define GPIO230_I2C3_SCL PIN_CFG(230, ALT_C)
#define GPIO256_GPIO PIN_CFG(256, GPIO)
#define GPIO256_USB_NXT PIN_CFG(256, ALT_A)
diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c
index eff5842f6232..da1d5ad5bd45 100644
--- a/arch/arm/mach-ux500/platsmp.c
+++ b/arch/arm/mach-ux500/platsmp.c
@@ -48,9 +48,7 @@ static void write_pen_release(int val)
static void __iomem *scu_base_addr(void)
{
- if (cpu_is_u5500())
- return __io_address(U5500_SCU_BASE);
- else if (cpu_is_u8500())
+ if (cpu_is_u8500_family())
return __io_address(U8500_SCU_BASE);
else
ux500_unknown_soc();
@@ -120,9 +118,7 @@ static void __init wakeup_secondary(void)
{
void __iomem *backupram;
- if (cpu_is_u5500())
- backupram = __io_address(U5500_BACKUPRAM0_BASE);
- else if (cpu_is_u8500())
+ if (cpu_is_u8500_family())
backupram = __io_address(U8500_BACKUPRAM0_BASE);
else
ux500_unknown_soc();
diff --git a/arch/arm/mach-ux500/ste-dma40-db5500.h b/arch/arm/mach-ux500/ste-dma40-db5500.h
deleted file mode 100644
index cb2110c32858..000000000000
--- a/arch/arm/mach-ux500/ste-dma40-db5500.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- *
- * DB5500-SoC-specific configuration for DMA40
- */
-
-#ifndef STE_DMA40_DB5500_H
-#define STE_DMA40_DB5500_H
-
-#define DB5500_DMA_NR_DEV 64
-
-enum dma_src_dev_type {
- DB5500_DMA_DEV0_SPI0_RX = 0,
- DB5500_DMA_DEV1_SPI1_RX = 1,
- DB5500_DMA_DEV2_SPI2_RX = 2,
- DB5500_DMA_DEV3_SPI3_RX = 3,
- DB5500_DMA_DEV4_USB_OTG_IEP_1_9 = 4,
- DB5500_DMA_DEV5_USB_OTG_IEP_2_10 = 5,
- DB5500_DMA_DEV6_USB_OTG_IEP_3_11 = 6,
- DB5500_DMA_DEV7_IRDA_RFS = 7,
- DB5500_DMA_DEV8_IRDA_FIFO_RX = 8,
- DB5500_DMA_DEV9_MSP0_RX = 9,
- DB5500_DMA_DEV10_MSP1_RX = 10,
- DB5500_DMA_DEV11_MSP2_RX = 11,
- DB5500_DMA_DEV12_UART0_RX = 12,
- DB5500_DMA_DEV13_UART1_RX = 13,
- DB5500_DMA_DEV14_UART2_RX = 14,
- DB5500_DMA_DEV15_UART3_RX = 15,
- DB5500_DMA_DEV16_USB_OTG_IEP_8 = 16,
- DB5500_DMA_DEV17_USB_OTG_IEP_1_9 = 17,
- DB5500_DMA_DEV18_USB_OTG_IEP_2_10 = 18,
- DB5500_DMA_DEV19_USB_OTG_IEP_3_11 = 19,
- DB5500_DMA_DEV20_USB_OTG_IEP_4_12 = 20,
- DB5500_DMA_DEV21_USB_OTG_IEP_5_13 = 21,
- DB5500_DMA_DEV22_USB_OTG_IEP_6_14 = 22,
- DB5500_DMA_DEV23_USB_OTG_IEP_7_15 = 23,
- DB5500_DMA_DEV24_SDMMC0_RX = 24,
- DB5500_DMA_DEV25_SDMMC1_RX = 25,
- DB5500_DMA_DEV26_SDMMC2_RX = 26,
- DB5500_DMA_DEV27_SDMMC3_RX = 27,
- DB5500_DMA_DEV28_SDMMC4_RX = 28,
- /* 29 - 32 not used */
- DB5500_DMA_DEV33_SDMMC0_RX = 33,
- DB5500_DMA_DEV34_SDMMC1_RX = 34,
- DB5500_DMA_DEV35_SDMMC2_RX = 35,
- DB5500_DMA_DEV36_SDMMC3_RX = 36,
- DB5500_DMA_DEV37_SDMMC4_RX = 37,
- DB5500_DMA_DEV38_USB_OTG_IEP_8 = 38,
- DB5500_DMA_DEV39_USB_OTG_IEP_1_9 = 39,
- DB5500_DMA_DEV40_USB_OTG_IEP_2_10 = 40,
- DB5500_DMA_DEV41_USB_OTG_IEP_3_11 = 41,
- DB5500_DMA_DEV42_USB_OTG_IEP_4_12 = 42,
- DB5500_DMA_DEV43_USB_OTG_IEP_5_13 = 43,
- DB5500_DMA_DEV44_USB_OTG_IEP_6_14 = 44,
- DB5500_DMA_DEV45_USB_OTG_IEP_7_15 = 45,
- /* 46 not used */
- DB5500_DMA_DEV47_MCDE_RX = 47,
- DB5500_DMA_DEV48_CRYPTO1_RX = 48,
- /* 49, 50 not used */
- DB5500_DMA_DEV49_I2C1_RX = 51,
- DB5500_DMA_DEV50_I2C3_RX = 52,
- DB5500_DMA_DEV51_I2C2_RX = 53,
- /* 54 - 60 not used */
- DB5500_DMA_DEV61_CRYPTO0_RX = 61,
- /* 62, 63 not used */
-};
-
-enum dma_dest_dev_type {
- DB5500_DMA_DEV0_SPI0_TX = 0,
- DB5500_DMA_DEV1_SPI1_TX = 1,
- DB5500_DMA_DEV2_SPI2_TX = 2,
- DB5500_DMA_DEV3_SPI3_TX = 3,
- DB5500_DMA_DEV4_USB_OTG_OEP_1_9 = 4,
- DB5500_DMA_DEV5_USB_OTG_OEP_2_10 = 5,
- DB5500_DMA_DEV6_USB_OTG_OEP_3_11 = 6,
- DB5500_DMA_DEV7_IRRC_TX = 7,
- DB5500_DMA_DEV8_IRDA_FIFO_TX = 8,
- DB5500_DMA_DEV9_MSP0_TX = 9,
- DB5500_DMA_DEV10_MSP1_TX = 10,
- DB5500_DMA_DEV11_MSP2_TX = 11,
- DB5500_DMA_DEV12_UART0_TX = 12,
- DB5500_DMA_DEV13_UART1_TX = 13,
- DB5500_DMA_DEV14_UART2_TX = 14,
- DB5500_DMA_DEV15_UART3_TX = 15,
- DB5500_DMA_DEV16_USB_OTG_OEP_8 = 16,
- DB5500_DMA_DEV17_USB_OTG_OEP_1_9 = 17,
- DB5500_DMA_DEV18_USB_OTG_OEP_2_10 = 18,
- DB5500_DMA_DEV19_USB_OTG_OEP_3_11 = 19,
- DB5500_DMA_DEV20_USB_OTG_OEP_4_12 = 20,
- DB5500_DMA_DEV21_USB_OTG_OEP_5_13 = 21,
- DB5500_DMA_DEV22_USB_OTG_OEP_6_14 = 22,
- DB5500_DMA_DEV23_USB_OTG_OEP_7_15 = 23,
- DB5500_DMA_DEV24_SDMMC0_TX = 24,
- DB5500_DMA_DEV25_SDMMC1_TX = 25,
- DB5500_DMA_DEV26_SDMMC2_TX = 26,
- DB5500_DMA_DEV27_SDMMC3_TX = 27,
- DB5500_DMA_DEV28_SDMMC4_TX = 28,
- /* 29 - 31 not used */
- DB5500_DMA_DEV32_FSMC_TX = 32,
- DB5500_DMA_DEV33_SDMMC0_TX = 33,
- DB5500_DMA_DEV34_SDMMC1_TX = 34,
- DB5500_DMA_DEV35_SDMMC2_TX = 35,
- DB5500_DMA_DEV36_SDMMC3_TX = 36,
- DB5500_DMA_DEV37_SDMMC4_TX = 37,
- DB5500_DMA_DEV38_USB_OTG_OEP_8 = 38,
- DB5500_DMA_DEV39_USB_OTG_OEP_1_9 = 39,
- DB5500_DMA_DEV40_USB_OTG_OEP_2_10 = 40,
- DB5500_DMA_DEV41_USB_OTG_OEP_3_11 = 41,
- DB5500_DMA_DEV42_USB_OTG_OEP_4_12 = 42,
- DB5500_DMA_DEV43_USB_OTG_OEP_5_13 = 43,
- DB5500_DMA_DEV44_USB_OTG_OEP_6_14 = 44,
- DB5500_DMA_DEV45_USB_OTG_OEP_7_15 = 45,
- /* 46 not used */
- DB5500_DMA_DEV47_STM_TX = 47,
- DB5500_DMA_DEV48_CRYPTO1_TX = 48,
- DB5500_DMA_DEV49_CRYPTO1_TX_HASH1_TX = 49,
- DB5500_DMA_DEV50_HASH1_TX = 50,
- DB5500_DMA_DEV51_I2C1_TX = 51,
- DB5500_DMA_DEV52_I2C3_TX = 52,
- DB5500_DMA_DEV53_I2C2_TX = 53,
- /* 54, 55 not used */
- DB5500_DMA_MEMCPY_TX_1 = 56,
- DB5500_DMA_MEMCPY_TX_2 = 57,
- DB5500_DMA_MEMCPY_TX_3 = 58,
- DB5500_DMA_MEMCPY_TX_4 = 59,
- DB5500_DMA_MEMCPY_TX_5 = 60,
- DB5500_DMA_DEV61_CRYPTO0_TX = 61,
- DB5500_DMA_DEV62_CRYPTO0_TX_HASH0_TX = 62,
- DB5500_DMA_DEV63_HASH0_TX = 63,
-};
-
-#endif
diff --git a/arch/arm/mach-ux500/timer.c b/arch/arm/mach-ux500/timer.c
index d37df98b5c32..741e71feca78 100644
--- a/arch/arm/mach-ux500/timer.c
+++ b/arch/arm/mach-ux500/timer.c
@@ -8,6 +8,7 @@
#include <linux/errno.h>
#include <linux/clksrc-dbx500-prcmu.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <asm/smp_twd.h>
@@ -18,8 +19,6 @@
#include <mach/irqs.h>
#ifdef CONFIG_HAVE_ARM_TWD
-static DEFINE_TWD_LOCAL_TIMER(u5500_twd_local_timer,
- U5500_TWD_BASE, IRQ_LOCALTIMER);
static DEFINE_TWD_LOCAL_TIMER(u8500_twd_local_timer,
U8500_TWD_BASE, IRQ_LOCALTIMER);
@@ -28,8 +27,8 @@ static void __init ux500_twd_init(void)
struct twd_local_timer *twd_local_timer;
int err;
- twd_local_timer = cpu_is_u5500() ? &u5500_twd_local_timer :
- &u8500_twd_local_timer;
+ /* Use this to switch local timer base if changed in new ASICs */
+ twd_local_timer = &u8500_twd_local_timer;
if (of_have_populated_dt())
twd_local_timer_of_register();
@@ -43,21 +42,41 @@ static void __init ux500_twd_init(void)
#define ux500_twd_init() do { } while(0)
#endif
+const static struct of_device_id prcmu_timer_of_match[] __initconst = {
+ { .compatible = "stericsson,db8500-prcmu-timer-4", },
+ { },
+};
+
static void __init ux500_timer_init(void)
{
void __iomem *mtu_timer_base;
void __iomem *prcmu_timer_base;
+ void __iomem *tmp_base;
+ struct device_node *np;
- if (cpu_is_u5500()) {
- mtu_timer_base = __io_address(U5500_MTU0_BASE);
- prcmu_timer_base = __io_address(U5500_PRCMU_TIMER_3_BASE);
- } else if (cpu_is_u8500()) {
+ if (cpu_is_u8500_family()) {
mtu_timer_base = __io_address(U8500_MTU0_BASE);
prcmu_timer_base = __io_address(U8500_PRCMU_TIMER_4_BASE);
} else {
ux500_unknown_soc();
}
+ /* TODO: Once MTU has been DT:ed place code above into else. */
+ if (of_have_populated_dt()) {
+ np = of_find_matching_node(NULL, prcmu_timer_of_match);
+ if (!np)
+ goto dt_fail;
+
+ tmp_base = of_iomap(np, 0);
+ if (!tmp_base)
+ goto dt_fail;
+
+ prcmu_timer_base = tmp_base;
+ }
+
+dt_fail:
+ /* Doing it the old fashioned way. */
+
/*
* Here we register the timerblocks active in the system.
* Localtimers (twd) is started when both cpu is up and running.
@@ -70,7 +89,7 @@ static void __init ux500_timer_init(void)
* depending on delay which is not yet calibrated. RTC-RTT is in the
* always-on powerdomain and is used as clockevent instead of twd when
* sleeping.
- * The PRCMU timer 4(3 for DB5500) register a clocksource and
+ * The PRCMU timer 4 register a clocksource and
* sched_clock with higher rating then MTU since is always-on.
*
*/
diff --git a/arch/arm/mm/cache-tauros2.c b/arch/arm/mm/cache-tauros2.c
index 1fbca05fe906..23a7643e9a87 100644
--- a/arch/arm/mm/cache-tauros2.c
+++ b/arch/arm/mm/cache-tauros2.c
@@ -108,6 +108,26 @@ static void tauros2_flush_range(unsigned long start, unsigned long end)
dsb();
}
+
+static void tauros2_disable(void)
+{
+ __asm__ __volatile__ (
+ "mcr p15, 1, %0, c7, c11, 0 @L2 Cache Clean All\n\t"
+ "mrc p15, 0, %0, c1, c0, 0\n\t"
+ "bic %0, %0, #(1 << 26)\n\t"
+ "mcr p15, 0, %0, c1, c0, 0 @Disable L2 Cache\n\t"
+ : : "r" (0x0));
+}
+
+static void tauros2_resume(void)
+{
+ __asm__ __volatile__ (
+ "mcr p15, 1, %0, c7, c7, 0 @L2 Cache Invalidate All\n\t"
+ "mrc p15, 0, %0, c1, c0, 0\n\t"
+ "orr %0, %0, #(1 << 26)\n\t"
+ "mcr p15, 0, %0, c1, c0, 0 @Enable L2 Cache\n\t"
+ : : "r" (0x0));
+}
#endif
static inline u32 __init read_extra_features(void)
@@ -194,6 +214,8 @@ void __init tauros2_init(void)
outer_cache.inv_range = tauros2_inv_range;
outer_cache.clean_range = tauros2_clean_range;
outer_cache.flush_range = tauros2_flush_range;
+ outer_cache.disable = tauros2_disable;
+ outer_cache.resume = tauros2_resume;
}
#endif
@@ -219,6 +241,8 @@ void __init tauros2_init(void)
outer_cache.inv_range = tauros2_inv_range;
outer_cache.clean_range = tauros2_clean_range;
outer_cache.flush_range = tauros2_flush_range;
+ outer_cache.disable = tauros2_disable;
+ outer_cache.resume = tauros2_resume;
}
#endif
diff --git a/arch/arm/mm/proc-mohawk.S b/arch/arm/mm/proc-mohawk.S
index b0475468c711..fbb2124a547d 100644
--- a/arch/arm/mm/proc-mohawk.S
+++ b/arch/arm/mm/proc-mohawk.S
@@ -345,6 +345,41 @@ ENTRY(cpu_mohawk_set_pte_ext)
mcr p15, 0, r0, c7, c10, 4 @ drain WB
mov pc, lr
+.globl cpu_mohawk_suspend_size
+.equ cpu_mohawk_suspend_size, 4 * 6
+#ifdef CONFIG_PM_SLEEP
+ENTRY(cpu_mohawk_do_suspend)
+ stmfd sp!, {r4 - r9, lr}
+ mrc p14, 0, r4, c6, c0, 0 @ clock configuration, for turbo mode
+ mrc p15, 0, r5, c15, c1, 0 @ CP access reg
+ mrc p15, 0, r6, c13, c0, 0 @ PID
+ mrc p15, 0, r7, c3, c0, 0 @ domain ID
+ mrc p15, 0, r8, c1, c0, 1 @ auxiliary control reg
+ mrc p15, 0, r9, c1, c0, 0 @ control reg
+ bic r4, r4, #2 @ clear frequency change bit
+ stmia r0, {r4 - r9} @ store cp regs
+ ldmia sp!, {r4 - r9, pc}
+ENDPROC(cpu_mohawk_do_suspend)
+
+ENTRY(cpu_mohawk_do_resume)
+ ldmia r0, {r4 - r9} @ load cp regs
+ mov ip, #0
+ mcr p15, 0, ip, c7, c7, 0 @ invalidate I & D caches, BTB
+ mcr p15, 0, ip, c7, c10, 4 @ drain write (&fill) buffer
+ mcr p15, 0, ip, c7, c5, 4 @ flush prefetch buffer
+ mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
+ mcr p14, 0, r4, c6, c0, 0 @ clock configuration, turbo mode.
+ mcr p15, 0, r5, c15, c1, 0 @ CP access reg
+ mcr p15, 0, r6, c13, c0, 0 @ PID
+ mcr p15, 0, r7, c3, c0, 0 @ domain ID
+ orr r1, r1, #0x18 @ cache the page table in L2
+ mcr p15, 0, r1, c2, c0, 0 @ translation table base addr
+ mcr p15, 0, r8, c1, c0, 1 @ auxiliary control reg
+ mov r0, r9 @ control register
+ b cpu_resume_mmu
+ENDPROC(cpu_mohawk_do_resume)
+#endif
+
__CPUINIT
.type __mohawk_setup, #function
diff --git a/arch/arm/nwfpe/fpmodule.c b/arch/arm/nwfpe/fpmodule.c
index cb7658e8acc5..4e729f055a81 100644
--- a/arch/arm/nwfpe/fpmodule.c
+++ b/arch/arm/nwfpe/fpmodule.c
@@ -147,7 +147,7 @@ void float_raise(signed char flags)
#ifdef CONFIG_DEBUG_USER
if (flags & debug)
printk(KERN_DEBUG
- "NWFPE: %s[%d] takes exception %08x at %p from %08lx\n",
+ "NWFPE: %s[%d] takes exception %08x at %pf from %08lx\n",
current->comm, current->pid, flags,
__builtin_return_address(0), GET_USERREG()->ARM_pc);
#endif
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx51.h b/arch/arm/plat-mxc/include/mach/iomux-mx51.h
index c7f5169a6a54..36c8989d9de6 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mx51.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx51.h
@@ -256,13 +256,13 @@
#define MX51_PAD_NANDF_RB1__GPIO3_9 IOMUX_PAD(0x4fc, 0x120, 3, __NA_, 0, MX51_GPIO_PAD_CTRL)
#define MX51_PAD_NANDF_RB1__NANDF_RB1 IOMUX_PAD(0x4fc, 0x120, 0, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_NANDF_RB1__PATA_IORDY IOMUX_PAD(0x4fc, 0x120, 1, __NA_, 0, NO_PAD_CTRL)
-#define MX51_PAD_NANDF_RB1__SD4_CMD IOMUX_PAD(0x4fc, 0x120, 5, __NA_, 0, MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_NANDF_RB1__SD4_CMD IOMUX_PAD(0x4fc, 0x120, 0x15, __NA_, 0, MX51_SDHCI_PAD_CTRL)
#define MX51_PAD_NANDF_RB2__DISP2_WAIT IOMUX_PAD(0x500, 0x124, 5, 0x9a8, 0, NO_PAD_CTRL)
#define MX51_PAD_NANDF_RB2__ECSPI2_SCLK IOMUX_PAD(0x500, 0x124, 2, __NA_, 0, MX51_ECSPI_PAD_CTRL)
#define MX51_PAD_NANDF_RB2__FEC_COL IOMUX_PAD(0x500, 0x124, 1, 0x94c, 0, MX51_PAD_CTRL_2)
#define MX51_PAD_NANDF_RB2__GPIO3_10 IOMUX_PAD(0x500, 0x124, 3, __NA_, 0, MX51_GPIO_PAD_CTRL)
#define MX51_PAD_NANDF_RB2__NANDF_RB2 IOMUX_PAD(0x500, 0x124, 0, __NA_, 0, NO_PAD_CTRL)
-#define MX51_PAD_NANDF_RB2__USBH3_H3_DP IOMUX_PAD(0x500, 0x124, 7, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_RB2__USBH3_H3_DP IOMUX_PAD(0x500, 0x124, 0x17, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_NANDF_RB2__USBH3_NXT IOMUX_PAD(0x500, 0x124, 6, 0xa20, 0, NO_PAD_CTRL)
#define MX51_PAD_NANDF_RB3__DISP1_WAIT IOMUX_PAD(0x504, 0x128, 5, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_NANDF_RB3__ECSPI2_MISO IOMUX_PAD(0x504, 0x128, 2, __NA_, 0, MX51_ECSPI_PAD_CTRL)
@@ -270,7 +270,7 @@
#define MX51_PAD_NANDF_RB3__GPIO3_11 IOMUX_PAD(0x504, 0x128, 3, __NA_, 0, MX51_GPIO_PAD_CTRL)
#define MX51_PAD_NANDF_RB3__NANDF_RB3 IOMUX_PAD(0x504, 0x128, 0, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_NANDF_RB3__USBH3_CLK IOMUX_PAD(0x504, 0x128, 6, 0x9f8, 0, NO_PAD_CTRL)
-#define MX51_PAD_NANDF_RB3__USBH3_H3_DM IOMUX_PAD(0x504, 0x128, 7, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_RB3__USBH3_H3_DM IOMUX_PAD(0x504, 0x128, 0x17, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_GPIO_NAND__GPIO_NAND IOMUX_PAD(0x514, 0x12c, 0, 0x998, 0, MX51_GPIO_PAD_CTRL)
#define MX51_PAD_GPIO_NAND__PATA_INTRQ IOMUX_PAD(0x514, 0x12c, 1, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_NANDF_CS0__GPIO3_16 IOMUX_PAD(0x518, 0x130, 3, __NA_, 0, MX51_GPIO_PAD_CTRL)
@@ -283,13 +283,13 @@
#define MX51_PAD_NANDF_CS2__NANDF_CS2 IOMUX_PAD(0x520, 0x138, 0, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_NANDF_CS2__PATA_CS_0 IOMUX_PAD(0x520, 0x138, 1, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_NANDF_CS2__SD4_CLK IOMUX_PAD(0x520, 0x138, 5, __NA_, 0, MX51_SDHCI_PAD_CTRL | PAD_CTL_HYS)
-#define MX51_PAD_NANDF_CS2__USBH3_H1_DP IOMUX_PAD(0x520, 0x138, 7, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS2__USBH3_H1_DP IOMUX_PAD(0x520, 0x138, 0x17, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_NANDF_CS3__FEC_MDC IOMUX_PAD(0x524, 0x13c, 2, __NA_, 0, MX51_PAD_CTRL_5)
#define MX51_PAD_NANDF_CS3__GPIO3_19 IOMUX_PAD(0x524, 0x13c, 3, __NA_, 0, MX51_GPIO_PAD_CTRL)
#define MX51_PAD_NANDF_CS3__NANDF_CS3 IOMUX_PAD(0x524, 0x13c, 0, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_NANDF_CS3__PATA_CS_1 IOMUX_PAD(0x524, 0x13c, 1, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_NANDF_CS3__SD4_DAT0 IOMUX_PAD(0x524, 0x13c, 5, __NA_, 0, MX51_SDHCI_PAD_CTRL)
-#define MX51_PAD_NANDF_CS3__USBH3_H1_DM IOMUX_PAD(0x524, 0x13c, 7, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS3__USBH3_H1_DM IOMUX_PAD(0x524, 0x13c, 0x17, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_NANDF_CS4__FEC_TDATA1 IOMUX_PAD(0x528, 0x140, 2, __NA_, 0, MX51_PAD_CTRL_5)
#define MX51_PAD_NANDF_CS4__GPIO3_20 IOMUX_PAD(0x528, 0x140, 3, __NA_, 0, MX51_GPIO_PAD_CTRL)
#define MX51_PAD_NANDF_CS4__NANDF_CS4 IOMUX_PAD(0x528, 0x140, 0, __NA_, 0, NO_PAD_CTRL)
@@ -316,7 +316,7 @@
#define MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK IOMUX_PAD(0x538, 0x150, 1, 0x974, 0, MX51_PAD_CTRL_4)
#define MX51_PAD_NANDF_RDY_INT__GPIO3_24 IOMUX_PAD(0x538, 0x150, 3, __NA_, 0, MX51_GPIO_PAD_CTRL)
#define MX51_PAD_NANDF_RDY_INT__NANDF_RDY_INT IOMUX_PAD(0x538, 0x150, 0, 0x938, 0, NO_PAD_CTRL)
-#define MX51_PAD_NANDF_RDY_INT__SD3_CMD IOMUX_PAD(0x538, 0x150, 5, __NA_, 0, MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_NANDF_RDY_INT__SD3_CMD IOMUX_PAD(0x538, 0x150, 0x15, __NA_, 0, MX51_SDHCI_PAD_CTRL)
#define MX51_PAD_NANDF_D15__ECSPI2_MOSI IOMUX_PAD(0x53c, 0x154, 2, __NA_, 0, MX51_ECSPI_PAD_CTRL)
#define MX51_PAD_NANDF_D15__GPIO3_25 IOMUX_PAD(0x53c, 0x154, 3, __NA_, 0, MX51_GPIO_PAD_CTRL)
#define MX51_PAD_NANDF_D15__NANDF_D15 IOMUX_PAD(0x53c, 0x154, 0, __NA_, 0, NO_PAD_CTRL)
@@ -672,23 +672,23 @@
#define MX51_PAD_DISP2_DAT5__DISP2_DAT5 IOMUX_PAD(0x770, 0x368, 0, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_DISP2_DAT6__DISP2_DAT6 IOMUX_PAD(0x774, 0x36c, 0, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_DISP2_DAT6__FEC_TDATA1 IOMUX_PAD(0x774, 0x36c, 2, __NA_, 0, MX51_PAD_CTRL_5)
-#define MX51_PAD_DISP2_DAT6__GPIO1_19 IOMUX_PAD(0x774, 0x36c, 5, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT6__GPIO1_19 IOMUX_PAD(0x774, 0x36c, 5, __NA_, 0, MX51_GPIO_PAD_CTRL)
#define MX51_PAD_DISP2_DAT6__KEY_ROW4 IOMUX_PAD(0x774, 0x36c, 4, 0x9d0, 1, NO_PAD_CTRL)
#define MX51_PAD_DISP2_DAT6__USBH3_STP IOMUX_PAD(0x774, 0x36c, 3, 0xa24, 1, NO_PAD_CTRL)
#define MX51_PAD_DISP2_DAT7__DISP2_DAT7 IOMUX_PAD(0x778, 0x370, 0, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_DISP2_DAT7__FEC_TDATA2 IOMUX_PAD(0x778, 0x370, 2, __NA_, 0, MX51_PAD_CTRL_5)
-#define MX51_PAD_DISP2_DAT7__GPIO1_29 IOMUX_PAD(0x778, 0x370, 5, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT7__GPIO1_29 IOMUX_PAD(0x778, 0x370, 5, __NA_, 0, MX51_GPIO_PAD_CTRL)
#define MX51_PAD_DISP2_DAT7__KEY_ROW5 IOMUX_PAD(0x778, 0x370, 4, 0x9d4, 1, NO_PAD_CTRL)
#define MX51_PAD_DISP2_DAT7__USBH3_NXT IOMUX_PAD(0x778, 0x370, 3, 0xa20, 1, NO_PAD_CTRL)
#define MX51_PAD_DISP2_DAT8__DISP2_DAT8 IOMUX_PAD(0x77c, 0x374, 0, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_DISP2_DAT8__FEC_TDATA3 IOMUX_PAD(0x77c, 0x374, 2, __NA_, 0, MX51_PAD_CTRL_5)
-#define MX51_PAD_DISP2_DAT8__GPIO1_30 IOMUX_PAD(0x77c, 0x374, 5, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT8__GPIO1_30 IOMUX_PAD(0x77c, 0x374, 5, __NA_, 0, MX51_GPIO_PAD_CTRL)
#define MX51_PAD_DISP2_DAT8__KEY_ROW6 IOMUX_PAD(0x77c, 0x374, 4, 0x9d8, 1, NO_PAD_CTRL)
#define MX51_PAD_DISP2_DAT8__USBH3_DATA0 IOMUX_PAD(0x77c, 0x374, 3, 0x9fc, 1, NO_PAD_CTRL)
#define MX51_PAD_DISP2_DAT9__AUD6_RXC IOMUX_PAD(0x780, 0x378, 4, 0x8f4, 1, NO_PAD_CTRL)
#define MX51_PAD_DISP2_DAT9__DISP2_DAT9 IOMUX_PAD(0x780, 0x378, 0, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_DISP2_DAT9__FEC_TX_EN IOMUX_PAD(0x780, 0x378, 2, __NA_, 0, MX51_PAD_CTRL_5)
-#define MX51_PAD_DISP2_DAT9__GPIO1_31 IOMUX_PAD(0x780, 0x378, 5, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT9__GPIO1_31 IOMUX_PAD(0x780, 0x378, 5, __NA_, 0, MX51_GPIO_PAD_CTRL)
#define MX51_PAD_DISP2_DAT9__USBH3_DATA1 IOMUX_PAD(0x780, 0x378, 3, 0xa00, 1, NO_PAD_CTRL)
#define MX51_PAD_DISP2_DAT10__DISP2_DAT10 IOMUX_PAD(0x784, 0x37c, 0, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_DISP2_DAT10__DISP2_SER_CS IOMUX_PAD(0x784, 0x37c, 5, __NA_, 0, NO_PAD_CTRL)
@@ -698,7 +698,7 @@
#define MX51_PAD_DISP2_DAT11__AUD6_TXD IOMUX_PAD(0x788, 0x380, 4, 0x8f0, 1, NO_PAD_CTRL)
#define MX51_PAD_DISP2_DAT11__DISP2_DAT11 IOMUX_PAD(0x788, 0x380, 0, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_DISP2_DAT11__FEC_RX_CLK IOMUX_PAD(0x788, 0x380, 2, 0x968, 1, NO_PAD_CTRL)
-#define MX51_PAD_DISP2_DAT11__GPIO1_10 IOMUX_PAD(0x788, 0x380, 7, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_DISP2_DAT11__GPIO1_10 IOMUX_PAD(0x788, 0x380, 7, __NA_, 0, MX51_GPIO_PAD_CTRL)
#define MX51_PAD_DISP2_DAT11__USBH3_DATA3 IOMUX_PAD(0x788, 0x380, 3, 0xa08, 1, NO_PAD_CTRL)
#define MX51_PAD_DISP2_DAT12__AUD6_RXD IOMUX_PAD(0x78c, 0x384, 4, 0x8ec, 1, NO_PAD_CTRL)
#define MX51_PAD_DISP2_DAT12__DISP2_DAT12 IOMUX_PAD(0x78c, 0x384, 0, __NA_, 0, NO_PAD_CTRL)
@@ -746,16 +746,16 @@
#define MX51_PAD_SD1_DATA3__CSPI_SS1 IOMUX_PAD(0x7b0, 0x3a8, 2, 0x920, 1, MX51_ECSPI_PAD_CTRL)
#define MX51_PAD_SD1_DATA3__SD1_DATA3 IOMUX_PAD(0x7b0, 0x3a8, 0x10, __NA_, 0, MX51_SDHCI_PAD_CTRL)
#define MX51_PAD_GPIO1_0__CSPI_SS2 IOMUX_PAD(0x7b4, 0x3ac, 2, 0x924, 0, MX51_ECSPI_PAD_CTRL)
-#define MX51_PAD_GPIO1_0__GPIO1_0 IOMUX_PAD(0x7b4, 0x3ac, 1, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_0__GPIO1_0 IOMUX_PAD(0x7b4, 0x3ac, 1, __NA_, 0, MX51_GPIO_PAD_CTRL)
#define MX51_PAD_GPIO1_0__SD1_CD IOMUX_PAD(0x7b4, 0x3ac, 0, __NA_, 0, MX51_ESDHC_PAD_CTRL)
#define MX51_PAD_GPIO1_1__CSPI_MISO IOMUX_PAD(0x7b8, 0x3b0, 2, 0x918, 2, MX51_ECSPI_PAD_CTRL)
-#define MX51_PAD_GPIO1_1__GPIO1_1 IOMUX_PAD(0x7b8, 0x3b0, 1, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_1__GPIO1_1 IOMUX_PAD(0x7b8, 0x3b0, 1, __NA_, 0, MX51_GPIO_PAD_CTRL)
#define MX51_PAD_GPIO1_1__SD1_WP IOMUX_PAD(0x7b8, 0x3b0, 0, __NA_, 0, MX51_ESDHC_PAD_CTRL)
#define MX51_PAD_EIM_DA12__EIM_DA12 IOMUX_PAD(__NA_, 0x04c, 0, 0x000, 0, NO_PAD_CTRL)
#define MX51_PAD_EIM_DA13__EIM_DA13 IOMUX_PAD(__NA_, 0x050, 0, 0x000, 0, NO_PAD_CTRL)
#define MX51_PAD_EIM_DA14__EIM_DA14 IOMUX_PAD(__NA_, 0x054, 0, 0x000, 0, NO_PAD_CTRL)
#define MX51_PAD_EIM_DA15__EIM_DA15 IOMUX_PAD(__NA_, 0x058, 0, 0x000, 0, NO_PAD_CTRL)
-#define MX51_PAD_SD2_CMD__CSPI_MOSI IOMUX_PAD(__NA_, 0x3b4, 2, 0x91c, 3, MX51_ECSPI_PAD_CTRL)
+#define MX51_PAD_SD2_CMD__CSPI_MOSI IOMUX_PAD(0x7bc, 0x3b4, 2, 0x91c, 3, MX51_ECSPI_PAD_CTRL)
#define MX51_PAD_SD2_CMD__I2C1_SCL IOMUX_PAD(0x7bc, 0x3b4, 0x11, 0x9b0, 2, MX51_I2C_PAD_CTRL)
#define MX51_PAD_SD2_CMD__SD2_CMD IOMUX_PAD(0x7bc, 0x3b4, 0x10, __NA_, 0, MX51_SDHCI_PAD_CTRL)
#define MX51_PAD_SD2_CLK__CSPI_SCLK IOMUX_PAD(0x7c0, 0x3b8, 2, 0x914, 3, MX51_ECSPI_PAD_CTRL)
@@ -766,19 +766,19 @@
#define MX51_PAD_SD2_DATA0__SD2_DATA0 IOMUX_PAD(0x7c4, 0x3bc, 0x10, __NA_, 0, MX51_SDHCI_PAD_CTRL)
#define MX51_PAD_SD2_DATA1__SD1_DAT5 IOMUX_PAD(0x7c8, 0x3c0, 1, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_SD2_DATA1__SD2_DATA1 IOMUX_PAD(0x7c8, 0x3c0, 0x10, __NA_, 0, MX51_SDHCI_PAD_CTRL)
-#define MX51_PAD_SD2_DATA1__USBH3_H2_DP IOMUX_PAD(0x7c8, 0x3c0, 2, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_SD2_DATA1__USBH3_H2_DP IOMUX_PAD(0x7c8, 0x3c0, 0x12, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_SD2_DATA2__SD1_DAT6 IOMUX_PAD(0x7cc, 0x3c4, 1, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_SD2_DATA2__SD2_DATA2 IOMUX_PAD(0x7cc, 0x3c4, 0x10, __NA_, 0, MX51_SDHCI_PAD_CTRL)
-#define MX51_PAD_SD2_DATA2__USBH3_H2_DM IOMUX_PAD(0x7cc, 0x3c4, 2, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_SD2_DATA2__USBH3_H2_DM IOMUX_PAD(0x7cc, 0x3c4, 0x12, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_SD2_DATA3__CSPI_SS2 IOMUX_PAD(0x7d0, 0x3c8, 2, 0x924, 1, MX51_ECSPI_PAD_CTRL)
#define MX51_PAD_SD2_DATA3__SD1_DAT7 IOMUX_PAD(0x7d0, 0x3c8, 1, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_SD2_DATA3__SD2_DATA3 IOMUX_PAD(0x7d0, 0x3c8, 0x10, __NA_, 0, MX51_SDHCI_PAD_CTRL)
#define MX51_PAD_GPIO1_2__CCM_OUT_2 IOMUX_PAD(0x7d4, 0x3cc, 5, __NA_, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO1_2__GPIO1_2 IOMUX_PAD(0x7d4, 0x3cc, 0, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_2__GPIO1_2 IOMUX_PAD(0x7d4, 0x3cc, 0, __NA_, 0, MX51_GPIO_PAD_CTRL)
#define MX51_PAD_GPIO1_2__I2C2_SCL IOMUX_PAD(0x7d4, 0x3cc, 0x12, 0x9b8, 3, MX51_I2C_PAD_CTRL)
#define MX51_PAD_GPIO1_2__PLL1_BYP IOMUX_PAD(0x7d4, 0x3cc, 7, 0x90c, 1, NO_PAD_CTRL)
#define MX51_PAD_GPIO1_2__PWM1_PWMO IOMUX_PAD(0x7d4, 0x3cc, 1, __NA_, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO1_3__GPIO1_3 IOMUX_PAD(0x7d8, 0x3d0, 0, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_3__GPIO1_3 IOMUX_PAD(0x7d8, 0x3d0, 0, __NA_, 0, MX51_GPIO_PAD_CTRL)
#define MX51_PAD_GPIO1_3__I2C2_SDA IOMUX_PAD(0x7d8, 0x3d0, 0x12, 0x9bc, 3, MX51_I2C_PAD_CTRL)
#define MX51_PAD_GPIO1_3__PLL2_BYP IOMUX_PAD(0x7d8, 0x3d0, 7, 0x910, 1, NO_PAD_CTRL)
#define MX51_PAD_GPIO1_3__PWM2_PWMO IOMUX_PAD(0x7d8, 0x3d0, 1, __NA_, 0, NO_PAD_CTRL)
@@ -786,27 +786,27 @@
#define MX51_PAD_PMIC_INT_REQ__PMIC_PMU_IRQ_B IOMUX_PAD(0x7fc, 0x3d4, 1, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_GPIO1_4__DISP2_EXT_CLK IOMUX_PAD(0x804, 0x3d8, 4, 0x908, 1, NO_PAD_CTRL)
#define MX51_PAD_GPIO1_4__EIM_RDY IOMUX_PAD(0x804, 0x3d8, 3, 0x938, 1, NO_PAD_CTRL)
-#define MX51_PAD_GPIO1_4__GPIO1_4 IOMUX_PAD(0x804, 0x3d8, 0, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_4__GPIO1_4 IOMUX_PAD(0x804, 0x3d8, 0, __NA_, 0, MX51_GPIO_PAD_CTRL)
#define MX51_PAD_GPIO1_4__WDOG1_WDOG_B IOMUX_PAD(0x804, 0x3d8, 2, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_GPIO1_5__CSI2_MCLK IOMUX_PAD(0x808, 0x3dc, 6, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_GPIO1_5__DISP2_PIN16 IOMUX_PAD(0x808, 0x3dc, 3, __NA_, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO1_5__GPIO1_5 IOMUX_PAD(0x808, 0x3dc, 0, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_5__GPIO1_5 IOMUX_PAD(0x808, 0x3dc, 0, __NA_, 0, MX51_GPIO_PAD_CTRL)
#define MX51_PAD_GPIO1_5__WDOG2_WDOG_B IOMUX_PAD(0x808, 0x3dc, 2, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_GPIO1_6__DISP2_PIN17 IOMUX_PAD(0x80c, 0x3e0, 4, __NA_, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO1_6__GPIO1_6 IOMUX_PAD(0x80c, 0x3e0, 0, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_6__GPIO1_6 IOMUX_PAD(0x80c, 0x3e0, 0, __NA_, 0, MX51_GPIO_PAD_CTRL)
#define MX51_PAD_GPIO1_6__REF_EN_B IOMUX_PAD(0x80c, 0x3e0, 3, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_GPIO1_7__CCM_OUT_0 IOMUX_PAD(0x810, 0x3e4, 3, __NA_, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO1_7__GPIO1_7 IOMUX_PAD(0x810, 0x3e4, 0, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_7__GPIO1_7 IOMUX_PAD(0x810, 0x3e4, 0, __NA_, 0, MX51_GPIO_PAD_CTRL)
#define MX51_PAD_GPIO1_7__SD2_WP IOMUX_PAD(0x810, 0x3e4, 6, __NA_, 0, MX51_ESDHC_PAD_CTRL)
#define MX51_PAD_GPIO1_7__SPDIF_OUT1 IOMUX_PAD(0x810, 0x3e4, 2, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_GPIO1_8__CSI2_DATA_EN IOMUX_PAD(0x814, 0x3e8, 2, 0x99c, 2, NO_PAD_CTRL)
-#define MX51_PAD_GPIO1_8__GPIO1_8 IOMUX_PAD(0x814, 0x3e8, 0, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_8__GPIO1_8 IOMUX_PAD(0x814, 0x3e8, 0, __NA_, 0, MX51_GPIO_PAD_CTRL)
#define MX51_PAD_GPIO1_8__SD2_CD IOMUX_PAD(0x814, 0x3e8, 6, __NA_, 0, MX51_ESDHC_PAD_CTRL)
#define MX51_PAD_GPIO1_8__USBH3_PWR IOMUX_PAD(0x814, 0x3e8, 1, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_GPIO1_9__CCM_OUT_1 IOMUX_PAD(0x818, 0x3ec, 3, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_GPIO1_9__DISP2_D1_CS IOMUX_PAD(0x818, 0x3ec, 2, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_GPIO1_9__DISP2_SER_CS IOMUX_PAD(0x818, 0x3ec, 7, __NA_, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO1_9__GPIO1_9 IOMUX_PAD(0x818, 0x3ec, 0, __NA_, 0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO1_9__GPIO1_9 IOMUX_PAD(0x818, 0x3ec, 0, __NA_, 0, MX51_GPIO_PAD_CTRL)
#define MX51_PAD_GPIO1_9__SD2_LCTL IOMUX_PAD(0x818, 0x3ec, 6, __NA_, 0, NO_PAD_CTRL)
#define MX51_PAD_GPIO1_9__USBH3_OC IOMUX_PAD(0x818, 0x3ec, 1, __NA_, 0, NO_PAD_CTRL)
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx53.h b/arch/arm/plat-mxc/include/mach/iomux-mx53.h
index 527f8fe3e31b..9761e003bde2 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mx53.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx53.h
@@ -573,7 +573,7 @@
#define MX53_PAD_EIM_D28__UART2_CTS IOMUX_PAD(0x494, 0x14C, 2, __NA_, 0, MX53_UART_PAD_CTRL)
#define MX53_PAD_EIM_D28__IPU_DISPB0_SER_DIO IOMUX_PAD(0x494, 0x14C, 3, 0x82C, 1, NO_PAD_CTRL)
#define MX53_PAD_EIM_D28__CSPI_MOSI IOMUX_PAD(0x494, 0x14C, 4, 0x788, 1, NO_PAD_CTRL)
-#define MX53_PAD_EIM_D28__I2C1_SDA IOMUX_PAD(0x494, 0x14C, 5 | IOMUX_CONFIG_SION, 0x818, 1, PAD_CTRL_I2C)
+#define MX53_PAD_EIM_D28__I2C1_SDA IOMUX_PAD(0x494, 0x14C, 5 | IOMUX_CONFIG_SION, 0x818, 1, NO_PAD_CTRL)
#define MX53_PAD_EIM_D28__IPU_EXT_TRIG IOMUX_PAD(0x494, 0x14C, 6, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_EIM_D28__IPU_DI0_PIN13 IOMUX_PAD(0x494, 0x14C, 7, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_EIM_D29__EMI_WEIM_D_29 IOMUX_PAD(0x498, 0x150, 0, __NA_, 0, NO_PAD_CTRL)
@@ -1187,7 +1187,7 @@
#define MX53_PAD_GPIO_8__ESAI1_TX5_RX0 IOMUX_PAD(0x6C8, 0x338, 0, 0x7F8, 1, NO_PAD_CTRL)
#define MX53_PAD_GPIO_8__GPIO1_8 IOMUX_PAD(0x6C8, 0x338, 1, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_GPIO_8__EPIT2_EPITO IOMUX_PAD(0x6C8, 0x338, 2, __NA_, 0, NO_PAD_CTRL)
-#define MX53_PAD_GPIO_8__CAN1_RXCAN IOMUX_PAD(0x6C8, 0x338, 3, 0x760, 3, NO_PAD_CTRL)
+#define MX53_PAD_GPIO_8__CAN1_RXCAN IOMUX_PAD(0x6C8, 0x338, 3, 0x760, 2, NO_PAD_CTRL)
#define MX53_PAD_GPIO_8__UART2_RXD_MUX IOMUX_PAD(0x6C8, 0x338, 4, 0x880, 5, MX53_UART_PAD_CTRL)
#define MX53_PAD_GPIO_8__FIRI_TXD IOMUX_PAD(0x6C8, 0x338, 5, __NA_, 0, NO_PAD_CTRL)
#define MX53_PAD_GPIO_8__SPDIF_SRCLK IOMUX_PAD(0x6C8, 0x338, 6, __NA_, 0, NO_PAD_CTRL)
diff --git a/arch/arm/plat-mxc/include/mach/mx2_cam.h b/arch/arm/plat-mxc/include/mach/mx2_cam.h
index 3c080a32dbf5..7ded6f1f74bc 100644
--- a/arch/arm/plat-mxc/include/mach/mx2_cam.h
+++ b/arch/arm/plat-mxc/include/mach/mx2_cam.h
@@ -23,7 +23,6 @@
#ifndef __MACH_MX2_CAM_H_
#define __MACH_MX2_CAM_H_
-#define MX2_CAMERA_SWAP16 (1 << 0)
#define MX2_CAMERA_EXT_VSYNC (1 << 1)
#define MX2_CAMERA_CCIR (1 << 2)
#define MX2_CAMERA_CCIR_INTERLACE (1 << 3)
@@ -31,7 +30,6 @@
#define MX2_CAMERA_GATED_CLOCK (1 << 5)
#define MX2_CAMERA_INV_DATA (1 << 6)
#define MX2_CAMERA_PCLK_SAMPLE_RISING (1 << 7)
-#define MX2_CAMERA_PACK_DIR_MSB (1 << 8)
/**
* struct mx2_camera_platform_data - optional platform data for mx2_camera
diff --git a/arch/arm/plat-nomadik/include/plat/gpio-nomadik.h b/arch/arm/plat-nomadik/include/plat/gpio-nomadik.h
index 9605bf227df9..826de74bfdd1 100644
--- a/arch/arm/plat-nomadik/include/plat/gpio-nomadik.h
+++ b/arch/arm/plat-nomadik/include/plat/gpio-nomadik.h
@@ -29,6 +29,7 @@
#define NMK_GPIO_SLPC 0x1c
#define NMK_GPIO_AFSLA 0x20
#define NMK_GPIO_AFSLB 0x24
+#define NMK_GPIO_LOWEMI 0x28
#define NMK_GPIO_RIMSC 0x40
#define NMK_GPIO_FIMSC 0x44
@@ -61,7 +62,14 @@ enum nmk_gpio_slpm {
extern int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode);
extern int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull);
+#ifdef CONFIG_PINCTRL_NOMADIK
extern int nmk_gpio_set_mode(int gpio, int gpio_mode);
+#else
+static inline int nmk_gpio_set_mode(int gpio, int gpio_mode)
+{
+ return -ENODEV;
+}
+#endif
extern int nmk_gpio_get_mode(int gpio);
extern void nmk_gpio_wakeups_suspend(void);
diff --git a/arch/arm/plat-nomadik/include/plat/pincfg.h b/arch/arm/plat-nomadik/include/plat/pincfg.h
index 22cb97d2d8ad..9c949c7c98a7 100644
--- a/arch/arm/plat-nomadik/include/plat/pincfg.h
+++ b/arch/arm/plat-nomadik/include/plat/pincfg.h
@@ -24,6 +24,7 @@
* bit 16..18 - SLPM pull up/down state
* bit 19..20 - SLPM direction
* bit 21..22 - SLPM Value (if output)
+ * bit 23..25 - PDIS value (if input)
*
* to facilitate the definition, the following macros are provided
*
@@ -67,6 +68,10 @@ typedef unsigned long pin_cfg_t;
/* These two replace the above in DB8500v2+ */
#define PIN_SLPM_WAKEUP_ENABLE (NMK_GPIO_SLPM_WAKEUP_ENABLE << PIN_SLPM_SHIFT)
#define PIN_SLPM_WAKEUP_DISABLE (NMK_GPIO_SLPM_WAKEUP_DISABLE << PIN_SLPM_SHIFT)
+#define PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP PIN_SLPM_WAKEUP_DISABLE
+
+#define PIN_SLPM_GPIO PIN_SLPM_WAKEUP_ENABLE /* In SLPM, pin is a gpio */
+#define PIN_SLPM_ALTFUNC PIN_SLPM_WAKEUP_DISABLE /* In SLPM, pin is altfunc */
#define PIN_DIR_SHIFT 14
#define PIN_DIR_MASK (0x1 << PIN_DIR_SHIFT)
@@ -105,6 +110,33 @@ typedef unsigned long pin_cfg_t;
#define PIN_SLPM_VAL_LOW ((1 + 0) << PIN_SLPM_VAL_SHIFT)
#define PIN_SLPM_VAL_HIGH ((1 + 1) << PIN_SLPM_VAL_SHIFT)
+#define PIN_SLPM_PDIS_SHIFT 23
+#define PIN_SLPM_PDIS_MASK (0x3 << PIN_SLPM_PDIS_SHIFT)
+#define PIN_SLPM_PDIS(x) \
+ (((x) & PIN_SLPM_PDIS_MASK) >> PIN_SLPM_PDIS_SHIFT)
+#define PIN_SLPM_PDIS_NO_CHANGE (0 << PIN_SLPM_PDIS_SHIFT)
+#define PIN_SLPM_PDIS_DISABLED (1 << PIN_SLPM_PDIS_SHIFT)
+#define PIN_SLPM_PDIS_ENABLED (2 << PIN_SLPM_PDIS_SHIFT)
+
+#define PIN_LOWEMI_SHIFT 25
+#define PIN_LOWEMI_MASK (0x1 << PIN_LOWEMI_SHIFT)
+#define PIN_LOWEMI(x) (((x) & PIN_LOWEMI_MASK) >> PIN_LOWEMI_SHIFT)
+#define PIN_LOWEMI_DISABLED (0 << PIN_LOWEMI_SHIFT)
+#define PIN_LOWEMI_ENABLED (1 << PIN_LOWEMI_SHIFT)
+
+#define PIN_GPIOMODE_SHIFT 26
+#define PIN_GPIOMODE_MASK (0x1 << PIN_GPIOMODE_SHIFT)
+#define PIN_GPIOMODE(x) (((x) & PIN_GPIOMODE_MASK) >> PIN_GPIOMODE_SHIFT)
+#define PIN_GPIOMODE_DISABLED (0 << PIN_GPIOMODE_SHIFT)
+#define PIN_GPIOMODE_ENABLED (1 << PIN_GPIOMODE_SHIFT)
+
+#define PIN_SLEEPMODE_SHIFT 27
+#define PIN_SLEEPMODE_MASK (0x1 << PIN_SLEEPMODE_SHIFT)
+#define PIN_SLEEPMODE(x) (((x) & PIN_SLEEPMODE_MASK) >> PIN_SLEEPMODE_SHIFT)
+#define PIN_SLEEPMODE_DISABLED (0 << PIN_SLEEPMODE_SHIFT)
+#define PIN_SLEEPMODE_ENABLED (1 << PIN_SLEEPMODE_SHIFT)
+
+
/* Shortcuts. Use these instead of separate DIR, PULL, and VAL. */
#define PIN_INPUT_PULLDOWN (PIN_DIR_INPUT | PIN_PULL_DOWN)
#define PIN_INPUT_PULLUP (PIN_DIR_INPUT | PIN_PULL_UP)
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index c0fe2757b695..ed8605f01155 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -9,9 +9,6 @@ obj-m :=
obj-n :=
obj- :=
-# OCPI interconnect support for 1710, 1610 and 5912
-obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
-
# omap_device support (OMAP2+ only at the moment)
obj-$(CONFIG_ARCH_OMAP2) += omap_device.o
obj-$(CONFIG_ARCH_OMAP3) += omap_device.o
diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c
index f1e46ea6b81d..0a9b9a970113 100644
--- a/arch/arm/plat-omap/common.c
+++ b/arch/arm/plat-omap/common.c
@@ -20,6 +20,7 @@
#include <plat/board.h>
#include <plat/vram.h>
#include <plat/dsp.h>
+#include <plat/dma.h>
#include <plat/omap-secure.h>
diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c
index 60278f47c0bd..09b07d252892 100644
--- a/arch/arm/plat-omap/devices.c
+++ b/arch/arm/plat-omap/devices.c
@@ -167,8 +167,8 @@ void __init omap_dsp_reserve_sdram_memblock(void)
paddr = arm_memblock_steal(size, SZ_1M);
if (!paddr) {
- pr_err("%s: failed to reserve %x bytes\n",
- __func__, size);
+ pr_err("%s: failed to reserve %llx bytes\n",
+ __func__, (unsigned long long)size);
return;
}
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index c58d896cd5c3..987e6101267d 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -41,6 +41,15 @@
#include <plat/tc.h>
+/*
+ * MAX_LOGICAL_DMA_CH_COUNT: the maximum number of logical DMA
+ * channels that an instance of the SDMA IP block can support. Used
+ * to size arrays. (The actual maximum on a particular SoC may be less
+ * than this -- for example, OMAP1 SDMA instances only support 17 logical
+ * DMA channels.)
+ */
+#define MAX_LOGICAL_DMA_CH_COUNT 32
+
#undef DEBUG
#ifndef CONFIG_ARCH_OMAP1
@@ -883,7 +892,7 @@ void omap_start_dma(int lch)
if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
int next_lch, cur_lch;
- char dma_chan_link_map[dma_lch_count];
+ char dma_chan_link_map[MAX_LOGICAL_DMA_CH_COUNT];
dma_chan_link_map[lch] = 1;
/* Set the link register of the first channel */
@@ -981,7 +990,7 @@ void omap_stop_dma(int lch)
if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
int next_lch, cur_lch = lch;
- char dma_chan_link_map[dma_lch_count];
+ char dma_chan_link_map[MAX_LOGICAL_DMA_CH_COUNT];
memset(dma_chan_link_map, 0, sizeof(dma_chan_link_map));
do {
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 652139c0339e..c4ed35e89fbd 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -349,11 +349,12 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_start);
int omap_dm_timer_stop(struct omap_dm_timer *timer)
{
unsigned long rate = 0;
- struct dmtimer_platform_data *pdata = timer->pdev->dev.platform_data;
+ struct dmtimer_platform_data *pdata;
if (unlikely(!timer))
return -EINVAL;
+ pdata = timer->pdev->dev.platform_data;
if (!pdata->needs_manual_reset)
rate = clk_get_rate(timer->fclk);
diff --git a/arch/arm/plat-omap/include/plat/board.h b/arch/arm/plat-omap/include/plat/board.h
index d5eb4c87db9d..4814c5b65306 100644
--- a/arch/arm/plat-omap/include/plat/board.h
+++ b/arch/arm/plat-omap/include/plat/board.h
@@ -91,6 +91,8 @@ struct omap_usb_config {
u32 (*usb0_init)(unsigned nwires, unsigned is_device);
u32 (*usb1_init)(unsigned nwires);
u32 (*usb2_init)(unsigned nwires, unsigned alt_pingroup);
+
+ int (*ocpi_enable)(void);
};
struct omap_lcd_config {
diff --git a/arch/arm/plat-omap/include/plat/clkdev_omap.h b/arch/arm/plat-omap/include/plat/clkdev_omap.h
index b299b8d201c8..d0ed8c443a63 100644
--- a/arch/arm/plat-omap/include/plat/clkdev_omap.h
+++ b/arch/arm/plat-omap/include/plat/clkdev_omap.h
@@ -34,8 +34,7 @@ struct omap_clk {
#define CK_243X (1 << 5) /* 243x, 253x */
#define CK_3430ES1 (1 << 6) /* 34xxES1 only */
#define CK_3430ES2PLUS (1 << 7) /* 34xxES2, ES3, non-Sitara 35xx only */
-#define CK_3505 (1 << 8)
-#define CK_3517 (1 << 9)
+#define CK_AM35XX (1 << 9) /* Sitara AM35xx */
#define CK_36XX (1 << 10) /* 36xx/37xx-specific clocks */
#define CK_443X (1 << 11)
#define CK_TI816X (1 << 12)
@@ -44,7 +43,6 @@ struct omap_clk {
#define CK_34XX (CK_3430ES1 | CK_3430ES2PLUS)
-#define CK_AM35XX (CK_3505 | CK_3517) /* all Sitara AM35xx */
#define CK_3XXX (CK_34XX | CK_AM35XX | CK_36XX)
diff --git a/arch/arm/plat-omap/include/plat/common.h b/arch/arm/plat-omap/include/plat/common.h
index b4d7ec3fbfbe..a557b8484e6c 100644
--- a/arch/arm/plat-omap/include/plat/common.h
+++ b/arch/arm/plat-omap/include/plat/common.h
@@ -32,6 +32,8 @@
extern int __init omap_init_clocksource_32k(void);
+extern void __init omap_check_revision(void);
+
extern void omap_reserve(void);
extern int omap_dss_reset(struct omap_hwmod *);
diff --git a/arch/arm/plat-omap/include/plat/cpu.h b/arch/arm/plat-omap/include/plat/cpu.h
index dc6a86bf2172..4bdf14ec6747 100644
--- a/arch/arm/plat-omap/include/plat/cpu.h
+++ b/arch/arm/plat-omap/include/plat/cpu.h
@@ -445,6 +445,7 @@ IS_OMAP_TYPE(3517, 0x3517)
#define OMAP446X_CLASS 0x44600044
#define OMAP4460_REV_ES1_0 (OMAP446X_CLASS | (0x10 << 8))
+#define OMAP4460_REV_ES1_1 (OMAP446X_CLASS | (0x11 << 8))
#define OMAP447X_CLASS 0x44700044
#define OMAP4470_REV_ES1_0 (OMAP447X_CLASS | (0x10 << 8))
diff --git a/arch/arm/plat-omap/include/plat/dma.h b/arch/arm/plat-omap/include/plat/dma.h
index dc562a5c0a8a..42afb4c45517 100644
--- a/arch/arm/plat-omap/include/plat/dma.h
+++ b/arch/arm/plat-omap/include/plat/dma.h
@@ -442,6 +442,7 @@ struct omap_system_dma_plat_info {
u32 (*dma_read)(int reg, int lch);
};
+extern void __init omap_init_consistent_dma_size(void);
extern void omap_set_dma_priority(int lch, int dst_port, int priority);
extern int omap_request_dma(int dev_id, const char *dev_name,
void (*callback)(int lch, u16 ch_status, void *data),
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h
index 9418f00b6c38..bdf871a84d62 100644
--- a/arch/arm/plat-omap/include/plat/dmtimer.h
+++ b/arch/arm/plat-omap/include/plat/dmtimer.h
@@ -259,7 +259,7 @@ struct omap_dm_timer {
unsigned long phys_base;
int id;
int irq;
- struct clk *iclk, *fclk;
+ struct clk *fclk;
void __iomem *io_base;
void __iomem *sys_stat; /* TISTAT timer status */
@@ -316,12 +316,12 @@ static inline void __omap_dm_timer_init_regs(struct omap_dm_timer *timer)
OMAP_TIMER_V1_SYS_STAT_OFFSET;
timer->irq_stat = timer->io_base + OMAP_TIMER_V1_STAT_OFFSET;
timer->irq_ena = timer->io_base + OMAP_TIMER_V1_INT_EN_OFFSET;
- timer->irq_dis = 0;
+ timer->irq_dis = NULL;
timer->pend = timer->io_base + _OMAP_TIMER_WRITE_PEND_OFFSET;
timer->func_base = timer->io_base;
} else {
timer->revision = 2;
- timer->sys_stat = 0;
+ timer->sys_stat = NULL;
timer->irq_stat = timer->io_base + OMAP_TIMER_V2_IRQSTATUS;
timer->irq_ena = timer->io_base + OMAP_TIMER_V2_IRQENABLE_SET;
timer->irq_dis = timer->io_base + OMAP_TIMER_V2_IRQENABLE_CLR;
diff --git a/arch/arm/plat-omap/include/plat/gpio.h b/arch/arm/plat-omap/include/plat/gpio.h
index 2f6e9924a814..50fb7cc000ea 100644
--- a/arch/arm/plat-omap/include/plat/gpio.h
+++ b/arch/arm/plat-omap/include/plat/gpio.h
@@ -172,6 +172,8 @@ struct omap_gpio_reg_offs {
u16 clr_dataout;
u16 irqstatus;
u16 irqstatus2;
+ u16 irqstatus_raw0;
+ u16 irqstatus_raw1;
u16 irqenable;
u16 irqenable2;
u16 set_irqenable;
@@ -193,7 +195,6 @@ struct omap_gpio_reg_offs {
};
struct omap_gpio_platform_data {
- u16 virtual_irq_start;
int bank_type;
int bank_width; /* GPIO bank width */
int bank_stride; /* Only needed for omap1 MPUIO */
diff --git a/arch/arm/plat-omap/include/plat/hdq1w.h b/arch/arm/plat-omap/include/plat/hdq1w.h
new file mode 100644
index 000000000000..0c1efc846d8d
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/hdq1w.h
@@ -0,0 +1,36 @@
+/*
+ * Shared macros and function prototypes for the HDQ1W/1-wire IP block
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ * Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#ifndef ARCH_ARM_MACH_OMAP2_HDQ1W_H
+#define ARCH_ARM_MACH_OMAP2_HDQ1W_H
+
+#include <plat/omap_hwmod.h>
+
+/*
+ * XXX A future cleanup patch should modify
+ * drivers/w1/masters/omap_hdq.c to use these macros
+ */
+#define HDQ_CTRL_STATUS_OFFSET 0x0c
+#define HDQ_CTRL_STATUS_CLOCKENABLE_SHIFT 5
+
+
+extern int omap_hdq1w_reset(struct omap_hwmod *oh);
+
+#endif
diff --git a/arch/arm/plat-omap/include/plat/mmc.h b/arch/arm/plat-omap/include/plat/mmc.h
index 7a38750c0079..3e7ae0f0215f 100644
--- a/arch/arm/plat-omap/include/plat/mmc.h
+++ b/arch/arm/plat-omap/include/plat/mmc.h
@@ -16,6 +16,7 @@
#include <linux/mmc/host.h>
#include <plat/board.h>
+#include <plat/omap_hwmod.h>
#define OMAP15XX_NR_MMC 1
#define OMAP16XX_NR_MMC 2
@@ -195,4 +196,7 @@ static inline int omap_mmc_add(const char *name, int id, unsigned long base,
}
#endif
+
+extern int omap_msdi_reset(struct omap_hwmod *oh);
+
#endif
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
index 9ff444469f3d..1a52725ffcf2 100644
--- a/arch/arm/plat-omap/include/plat/omap-serial.h
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -65,7 +65,6 @@ struct omap_uart_port_info {
bool dma_enabled; /* To specify DMA Mode */
unsigned int uartclk; /* UART clock rate */
upf_t flags; /* UPF_* flags */
- u32 errata;
unsigned int dma_rx_buf_size;
unsigned int dma_rx_timeout;
unsigned int autosuspend_timeout;
diff --git a/arch/arm/plat-omap/include/plat/omap_hwmod.h b/arch/arm/plat-omap/include/plat/omap_hwmod.h
index 3f26db4ee8e6..c835b7194ff5 100644
--- a/arch/arm/plat-omap/include/plat/omap_hwmod.h
+++ b/arch/arm/plat-omap/include/plat/omap_hwmod.h
@@ -213,11 +213,17 @@ struct omap_hwmod_addr_space {
*/
#define OCP_USER_MPU (1 << 0)
#define OCP_USER_SDMA (1 << 1)
+#define OCP_USER_DSP (1 << 2)
+#define OCP_USER_IVA (1 << 3)
/* omap_hwmod_ocp_if.flags bits */
#define OCPIF_SWSUP_IDLE (1 << 0)
#define OCPIF_CAN_BURST (1 << 1)
+/* omap_hwmod_ocp_if._int_flags possibilities */
+#define _OCPIF_INT_FLAGS_REGISTERED (1 << 0)
+
+
/**
* struct omap_hwmod_ocp_if - OCP interface data
* @master: struct omap_hwmod that initiates OCP transactions on this link
@@ -229,6 +235,7 @@ struct omap_hwmod_addr_space {
* @width: OCP data width
* @user: initiators using this interface (see OCP_USER_* macros above)
* @flags: OCP interface flags (see OCPIF_* macros above)
+ * @_int_flags: internal flags (see _OCPIF_INT_FLAGS* macros above)
*
* It may also be useful to add a tag_cnt field for OCP2.x devices.
*
@@ -247,6 +254,7 @@ struct omap_hwmod_ocp_if {
u8 width;
u8 user;
u8 flags;
+ u8 _int_flags;
};
@@ -327,9 +335,9 @@ struct omap_hwmod_sysc_fields {
* then this field has to be populated with the correct offset structure.
*/
struct omap_hwmod_class_sysconfig {
- u16 rev_offs;
- u16 sysc_offs;
- u16 syss_offs;
+ u32 rev_offs;
+ u32 sysc_offs;
+ u32 syss_offs;
u16 sysc_flags;
struct omap_hwmod_sysc_fields *sysc_fields;
u8 srst_udelay;
@@ -476,6 +484,16 @@ struct omap_hwmod_class {
};
/**
+ * struct omap_hwmod_link - internal structure linking hwmods with ocp_ifs
+ * @ocp_if: OCP interface structure record pointer
+ * @node: list_head pointing to next struct omap_hwmod_link in a list
+ */
+struct omap_hwmod_link {
+ struct omap_hwmod_ocp_if *ocp_if;
+ struct list_head node;
+};
+
+/**
* struct omap_hwmod - integration data for OMAP hardware "modules" (IP blocks)
* @name: name of the hwmod
* @class: struct omap_hwmod_class * to the class of this hwmod
@@ -487,12 +505,10 @@ struct omap_hwmod_class {
* @_clk: pointer to the main struct clk (filled in at runtime)
* @opt_clks: other device clocks that drivers can request (0..*)
* @voltdm: pointer to voltage domain (filled in at runtime)
- * @masters: ptr to array of OCP ifs that this hwmod can initiate on
- * @slaves: ptr to array of OCP ifs that this hwmod can respond on
* @dev_attr: arbitrary device attributes that can be passed to the driver
* @_sysc_cache: internal-use hwmod flags
* @_mpu_rt_va: cached register target start address (internal use)
- * @_mpu_port_index: cached MPU register target slave ID (internal use)
+ * @_mpu_port: cached MPU register target slave (internal use)
* @opt_clks_cnt: number of @opt_clks
* @master_cnt: number of @master entries
* @slaves_cnt: number of @slave entries
@@ -511,6 +527,8 @@ struct omap_hwmod_class {
*
* Parameter names beginning with an underscore are managed internally by
* the omap_hwmod code and should not be set during initialization.
+ *
+ * @masters and @slaves are now deprecated.
*/
struct omap_hwmod {
const char *name;
@@ -529,15 +547,15 @@ struct omap_hwmod {
struct omap_hwmod_opt_clk *opt_clks;
char *clkdm_name;
struct clockdomain *clkdm;
- struct omap_hwmod_ocp_if **masters; /* connect to *_IA */
- struct omap_hwmod_ocp_if **slaves; /* connect to *_TA */
+ struct list_head master_ports; /* connect to *_IA */
+ struct list_head slave_ports; /* connect to *_TA */
void *dev_attr;
u32 _sysc_cache;
void __iomem *_mpu_rt_va;
spinlock_t _lock;
struct list_head node;
+ struct omap_hwmod_ocp_if *_mpu_port;
u16 flags;
- u8 _mpu_port_index;
u8 response_lat;
u8 rst_lines_cnt;
u8 opt_clks_cnt;
@@ -549,7 +567,6 @@ struct omap_hwmod {
u8 _postsetup_state;
};
-int omap_hwmod_register(struct omap_hwmod **ohs);
struct omap_hwmod *omap_hwmod_lookup(const char *name);
int omap_hwmod_for_each(int (*fn)(struct omap_hwmod *oh, void *data),
void *data);
@@ -581,6 +598,8 @@ int omap_hwmod_softreset(struct omap_hwmod *oh);
int omap_hwmod_count_resources(struct omap_hwmod *oh);
int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res);
+int omap_hwmod_get_resource_byname(struct omap_hwmod *oh, unsigned int type,
+ const char *name, struct resource *res);
struct powerdomain *omap_hwmod_get_pwrdm(struct omap_hwmod *oh);
void __iomem *omap_hwmod_get_mpu_rt_va(struct omap_hwmod *oh);
@@ -619,4 +638,6 @@ extern int omap2430_hwmod_init(void);
extern int omap3xxx_hwmod_init(void);
extern int omap44xx_hwmod_init(void);
+extern int __init omap_hwmod_register_links(struct omap_hwmod_ocp_if **ois);
+
#endif
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
index d50cbc6385bd..c490240bb82c 100644
--- a/arch/arm/plat-omap/omap_device.c
+++ b/arch/arm/plat-omap/omap_device.c
@@ -475,13 +475,11 @@ static int omap_device_count_resources(struct omap_device *od)
static int omap_device_fill_resources(struct omap_device *od,
struct resource *res)
{
- int c = 0;
int i, r;
for (i = 0; i < od->hwmods_cnt; i++) {
r = omap_hwmod_fill_resources(od->hwmods[i], res);
res += r;
- c += r;
}
return 0;
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
index f9a8c5341ee9..477363c163ec 100644
--- a/arch/arm/plat-omap/sram.c
+++ b/arch/arm/plat-omap/sram.c
@@ -196,8 +196,8 @@ static void __init omap_map_sram(void)
* Looks like we need to preserve some bootloader code at the
* beginning of SRAM for jumping to flash for reboot to work...
*/
- memset((void *)omap_sram_base + SRAM_BOOTLOADER_SZ, 0,
- omap_sram_size - SRAM_BOOTLOADER_SZ);
+ memset_io(omap_sram_base + SRAM_BOOTLOADER_SZ, 0,
+ omap_sram_size - SRAM_BOOTLOADER_SZ);
}
/*
diff --git a/arch/arm/plat-omap/usb.c b/arch/arm/plat-omap/usb.c
index d2bbfd1cb0b5..daa0327381b5 100644
--- a/arch/arm/plat-omap/usb.c
+++ b/arch/arm/plat-omap/usb.c
@@ -31,15 +31,12 @@
#include <mach/hardware.h>
-#include "../mach-omap2/common.h"
-
#ifdef CONFIG_ARCH_OMAP_OTG
void __init
omap_otg_init(struct omap_usb_config *config)
{
u32 syscon;
- int status;
int alt_pingroup = 0;
/* NOTE: no bus or clock setup (yet?) */
@@ -104,6 +101,7 @@ omap_otg_init(struct omap_usb_config *config)
#ifdef CONFIG_USB_GADGET_OMAP
if (config->otg || config->register_dev) {
struct platform_device *udc_device = config->udc_device;
+ int status;
syscon &= ~DEV_IDLE_EN;
udc_device->dev.platform_data = config;
@@ -116,6 +114,7 @@ omap_otg_init(struct omap_usb_config *config)
#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
if (config->otg || config->register_host) {
struct platform_device *ohci_device = config->ohci_device;
+ int status;
syscon &= ~HST_IDLE_EN;
ohci_device->dev.platform_data = config;
@@ -128,6 +127,7 @@ omap_otg_init(struct omap_usb_config *config)
#ifdef CONFIG_USB_OTG
if (config->otg) {
struct platform_device *otg_device = config->otg_device;
+ int status;
syscon &= ~OTG_IDLE_EN;
otg_device->dev.platform_data = config;
@@ -138,8 +138,6 @@ omap_otg_init(struct omap_usb_config *config)
#endif
pr_debug("OTG_SYSCON_1 = %08x\n", omap_readl(OTG_SYSCON_1));
omap_writel(syscon, OTG_SYSCON_1);
-
- status = 0;
}
#else
diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c
index 10d160888133..af95af257301 100644
--- a/arch/arm/plat-orion/gpio.c
+++ b/arch/arm/plat-orion/gpio.c
@@ -16,6 +16,7 @@
#include <linux/bitops.h>
#include <linux/io.h>
#include <linux/gpio.h>
+#include <linux/leds.h>
/*
* GPIO unit register offsets.
@@ -289,12 +290,34 @@ void orion_gpio_set_blink(unsigned pin, int blink)
return;
spin_lock_irqsave(&ochip->lock, flags);
- __set_level(ochip, pin, 0);
- __set_blinking(ochip, pin, blink);
+ __set_level(ochip, pin & 31, 0);
+ __set_blinking(ochip, pin & 31, blink);
spin_unlock_irqrestore(&ochip->lock, flags);
}
EXPORT_SYMBOL(orion_gpio_set_blink);
+#define ORION_BLINK_HALF_PERIOD 100 /* ms */
+
+int orion_gpio_led_blink_set(unsigned gpio, int state,
+ unsigned long *delay_on, unsigned long *delay_off)
+{
+
+ if (delay_on && delay_off && !*delay_on && !*delay_off)
+ *delay_on = *delay_off = ORION_BLINK_HALF_PERIOD;
+
+ switch (state) {
+ case GPIO_LED_NO_BLINK_LOW:
+ case GPIO_LED_NO_BLINK_HIGH:
+ orion_gpio_set_blink(gpio, 0);
+ gpio_set_value(gpio, state);
+ break;
+ case GPIO_LED_BLINK:
+ orion_gpio_set_blink(gpio, 1);
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(orion_gpio_led_blink_set);
+
/*****************************************************************************
* Orion GPIO IRQ
diff --git a/arch/arm/plat-orion/include/plat/gpio.h b/arch/arm/plat-orion/include/plat/gpio.h
index 3abf30428bee..bec0c98ce41f 100644
--- a/arch/arm/plat-orion/include/plat/gpio.h
+++ b/arch/arm/plat-orion/include/plat/gpio.h
@@ -19,6 +19,8 @@
*/
void orion_gpio_set_unused(unsigned pin);
void orion_gpio_set_blink(unsigned pin, int blink);
+int orion_gpio_led_blink_set(unsigned gpio, int state,
+ unsigned long *delay_on, unsigned long *delay_off);
#define GPIO_INPUT_OK (1 << 0)
#define GPIO_OUTPUT_OK (1 << 1)
diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
index 8b928f9bc1c3..1d214cb9d770 100644
--- a/arch/arm/plat-samsung/devs.c
+++ b/arch/arm/plat-samsung/devs.c
@@ -30,6 +30,7 @@
#include <linux/mmc/host.h>
#include <linux/ioport.h>
#include <linux/platform_data/s3c-hsudc.h>
+#include <linux/platform_data/s3c-hsotg.h>
#include <asm/irq.h>
#include <asm/pmu.h>
@@ -57,7 +58,6 @@
#include <plat/sdhci.h>
#include <plat/ts.h>
#include <plat/udc.h>
-#include <plat/udc-hs.h>
#include <plat/usb-control.h>
#include <plat/usb-phy.h>
#include <plat/regs-iic.h>
@@ -272,16 +272,8 @@ struct platform_device s5p_device_fimc3 = {
#ifdef CONFIG_S5P_DEV_G2D
static struct resource s5p_g2d_resource[] = {
- [0] = {
- .start = S5P_PA_G2D,
- .end = S5P_PA_G2D + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_2D,
- .end = IRQ_2D,
- .flags = IORESOURCE_IRQ,
- },
+ [0] = DEFINE_RES_MEM(S5P_PA_G2D, SZ_4K),
+ [1] = DEFINE_RES_IRQ(IRQ_2D),
};
struct platform_device s5p_device_g2d = {
@@ -370,7 +362,6 @@ struct s3c_sdhci_platdata s3c_hsmmc0_def_platdata = {
.max_width = 4,
.host_caps = (MMC_CAP_4_BIT_DATA |
MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
- .clk_type = S3C_SDHCI_CLK_DIV_INTERNAL,
};
struct platform_device s3c_device_hsmmc0 = {
@@ -401,7 +392,6 @@ struct s3c_sdhci_platdata s3c_hsmmc1_def_platdata = {
.max_width = 4,
.host_caps = (MMC_CAP_4_BIT_DATA |
MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
- .clk_type = S3C_SDHCI_CLK_DIV_INTERNAL,
};
struct platform_device s3c_device_hsmmc1 = {
@@ -434,7 +424,6 @@ struct s3c_sdhci_platdata s3c_hsmmc2_def_platdata = {
.max_width = 4,
.host_caps = (MMC_CAP_4_BIT_DATA |
MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
- .clk_type = S3C_SDHCI_CLK_DIV_INTERNAL,
};
struct platform_device s3c_device_hsmmc2 = {
@@ -465,7 +454,6 @@ struct s3c_sdhci_platdata s3c_hsmmc3_def_platdata = {
.max_width = 4,
.host_caps = (MMC_CAP_4_BIT_DATA |
MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED),
- .clk_type = S3C_SDHCI_CLK_DIV_INTERNAL,
};
struct platform_device s3c_device_hsmmc3 = {
diff --git a/arch/arm/plat-samsung/include/plat/regs-usb-hsotg.h b/arch/arm/plat-samsung/include/plat/regs-usb-hsotg.h
deleted file mode 100644
index dc90f5ede88f..000000000000
--- a/arch/arm/plat-samsung/include/plat/regs-usb-hsotg.h
+++ /dev/null
@@ -1,379 +0,0 @@
-/* arch/arm/plat-s3c/include/plat/regs-usb-hsotg.h
- *
- * Copyright 2008 Openmoko, Inc.
- * Copyright 2008 Simtec Electronics
- * http://armlinux.simtec.co.uk/
- * Ben Dooks <ben@simtec.co.uk>
- *
- * S3C - USB2.0 Highspeed/OtG device block registers
- *
- * 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 __PLAT_S3C64XX_REGS_USB_HSOTG_H
-#define __PLAT_S3C64XX_REGS_USB_HSOTG_H __FILE__
-
-#define S3C_HSOTG_REG(x) (x)
-
-#define S3C_GOTGCTL S3C_HSOTG_REG(0x000)
-#define S3C_GOTGCTL_BSESVLD (1 << 19)
-#define S3C_GOTGCTL_ASESVLD (1 << 18)
-#define S3C_GOTGCTL_DBNC_SHORT (1 << 17)
-#define S3C_GOTGCTL_CONID_B (1 << 16)
-#define S3C_GOTGCTL_DEVHNPEN (1 << 11)
-#define S3C_GOTGCTL_HSSETHNPEN (1 << 10)
-#define S3C_GOTGCTL_HNPREQ (1 << 9)
-#define S3C_GOTGCTL_HSTNEGSCS (1 << 8)
-#define S3C_GOTGCTL_SESREQ (1 << 1)
-#define S3C_GOTGCTL_SESREQSCS (1 << 0)
-
-#define S3C_GOTGINT S3C_HSOTG_REG(0x004)
-#define S3C_GOTGINT_DbnceDone (1 << 19)
-#define S3C_GOTGINT_ADevTOUTChg (1 << 18)
-#define S3C_GOTGINT_HstNegDet (1 << 17)
-#define S3C_GOTGINT_HstnegSucStsChng (1 << 9)
-#define S3C_GOTGINT_SesReqSucStsChng (1 << 8)
-#define S3C_GOTGINT_SesEndDet (1 << 2)
-
-#define S3C_GAHBCFG S3C_HSOTG_REG(0x008)
-#define S3C_GAHBCFG_PTxFEmpLvl (1 << 8)
-#define S3C_GAHBCFG_NPTxFEmpLvl (1 << 7)
-#define S3C_GAHBCFG_DMAEn (1 << 5)
-#define S3C_GAHBCFG_HBstLen_MASK (0xf << 1)
-#define S3C_GAHBCFG_HBstLen_SHIFT (1)
-#define S3C_GAHBCFG_HBstLen_Single (0x0 << 1)
-#define S3C_GAHBCFG_HBstLen_Incr (0x1 << 1)
-#define S3C_GAHBCFG_HBstLen_Incr4 (0x3 << 1)
-#define S3C_GAHBCFG_HBstLen_Incr8 (0x5 << 1)
-#define S3C_GAHBCFG_HBstLen_Incr16 (0x7 << 1)
-#define S3C_GAHBCFG_GlblIntrEn (1 << 0)
-
-#define S3C_GUSBCFG S3C_HSOTG_REG(0x00C)
-#define S3C_GUSBCFG_PHYLPClkSel (1 << 15)
-#define S3C_GUSBCFG_HNPCap (1 << 9)
-#define S3C_GUSBCFG_SRPCap (1 << 8)
-#define S3C_GUSBCFG_PHYIf16 (1 << 3)
-#define S3C_GUSBCFG_TOutCal_MASK (0x7 << 0)
-#define S3C_GUSBCFG_TOutCal_SHIFT (0)
-#define S3C_GUSBCFG_TOutCal_LIMIT (0x7)
-#define S3C_GUSBCFG_TOutCal(_x) ((_x) << 0)
-
-#define S3C_GRSTCTL S3C_HSOTG_REG(0x010)
-
-#define S3C_GRSTCTL_AHBIdle (1 << 31)
-#define S3C_GRSTCTL_DMAReq (1 << 30)
-#define S3C_GRSTCTL_TxFNum_MASK (0x1f << 6)
-#define S3C_GRSTCTL_TxFNum_SHIFT (6)
-#define S3C_GRSTCTL_TxFNum_LIMIT (0x1f)
-#define S3C_GRSTCTL_TxFNum(_x) ((_x) << 6)
-#define S3C_GRSTCTL_TxFFlsh (1 << 5)
-#define S3C_GRSTCTL_RxFFlsh (1 << 4)
-#define S3C_GRSTCTL_INTknQFlsh (1 << 3)
-#define S3C_GRSTCTL_FrmCntrRst (1 << 2)
-#define S3C_GRSTCTL_HSftRst (1 << 1)
-#define S3C_GRSTCTL_CSftRst (1 << 0)
-
-#define S3C_GINTSTS S3C_HSOTG_REG(0x014)
-#define S3C_GINTMSK S3C_HSOTG_REG(0x018)
-
-#define S3C_GINTSTS_WkUpInt (1 << 31)
-#define S3C_GINTSTS_SessReqInt (1 << 30)
-#define S3C_GINTSTS_DisconnInt (1 << 29)
-#define S3C_GINTSTS_ConIDStsChng (1 << 28)
-#define S3C_GINTSTS_PTxFEmp (1 << 26)
-#define S3C_GINTSTS_HChInt (1 << 25)
-#define S3C_GINTSTS_PrtInt (1 << 24)
-#define S3C_GINTSTS_FetSusp (1 << 22)
-#define S3C_GINTSTS_incompIP (1 << 21)
-#define S3C_GINTSTS_IncomplSOIN (1 << 20)
-#define S3C_GINTSTS_OEPInt (1 << 19)
-#define S3C_GINTSTS_IEPInt (1 << 18)
-#define S3C_GINTSTS_EPMis (1 << 17)
-#define S3C_GINTSTS_EOPF (1 << 15)
-#define S3C_GINTSTS_ISOutDrop (1 << 14)
-#define S3C_GINTSTS_EnumDone (1 << 13)
-#define S3C_GINTSTS_USBRst (1 << 12)
-#define S3C_GINTSTS_USBSusp (1 << 11)
-#define S3C_GINTSTS_ErlySusp (1 << 10)
-#define S3C_GINTSTS_GOUTNakEff (1 << 7)
-#define S3C_GINTSTS_GINNakEff (1 << 6)
-#define S3C_GINTSTS_NPTxFEmp (1 << 5)
-#define S3C_GINTSTS_RxFLvl (1 << 4)
-#define S3C_GINTSTS_SOF (1 << 3)
-#define S3C_GINTSTS_OTGInt (1 << 2)
-#define S3C_GINTSTS_ModeMis (1 << 1)
-#define S3C_GINTSTS_CurMod_Host (1 << 0)
-
-#define S3C_GRXSTSR S3C_HSOTG_REG(0x01C)
-#define S3C_GRXSTSP S3C_HSOTG_REG(0x020)
-
-#define S3C_GRXSTS_FN_MASK (0x7f << 25)
-#define S3C_GRXSTS_FN_SHIFT (25)
-
-#define S3C_GRXSTS_PktSts_MASK (0xf << 17)
-#define S3C_GRXSTS_PktSts_SHIFT (17)
-#define S3C_GRXSTS_PktSts_GlobalOutNAK (0x1 << 17)
-#define S3C_GRXSTS_PktSts_OutRX (0x2 << 17)
-#define S3C_GRXSTS_PktSts_OutDone (0x3 << 17)
-#define S3C_GRXSTS_PktSts_SetupDone (0x4 << 17)
-#define S3C_GRXSTS_PktSts_SetupRX (0x6 << 17)
-
-#define S3C_GRXSTS_DPID_MASK (0x3 << 15)
-#define S3C_GRXSTS_DPID_SHIFT (15)
-#define S3C_GRXSTS_ByteCnt_MASK (0x7ff << 4)
-#define S3C_GRXSTS_ByteCnt_SHIFT (4)
-#define S3C_GRXSTS_EPNum_MASK (0xf << 0)
-#define S3C_GRXSTS_EPNum_SHIFT (0)
-
-#define S3C_GRXFSIZ S3C_HSOTG_REG(0x024)
-
-#define S3C_GNPTXFSIZ S3C_HSOTG_REG(0x028)
-
-#define S3C_GNPTXFSIZ_NPTxFDep_MASK (0xffff << 16)
-#define S3C_GNPTXFSIZ_NPTxFDep_SHIFT (16)
-#define S3C_GNPTXFSIZ_NPTxFDep_LIMIT (0xffff)
-#define S3C_GNPTXFSIZ_NPTxFDep(_x) ((_x) << 16)
-#define S3C_GNPTXFSIZ_NPTxFStAddr_MASK (0xffff << 0)
-#define S3C_GNPTXFSIZ_NPTxFStAddr_SHIFT (0)
-#define S3C_GNPTXFSIZ_NPTxFStAddr_LIMIT (0xffff)
-#define S3C_GNPTXFSIZ_NPTxFStAddr(_x) ((_x) << 0)
-
-#define S3C_GNPTXSTS S3C_HSOTG_REG(0x02C)
-
-#define S3C_GNPTXSTS_NPtxQTop_MASK (0x7f << 24)
-#define S3C_GNPTXSTS_NPtxQTop_SHIFT (24)
-
-#define S3C_GNPTXSTS_NPTxQSpcAvail_MASK (0xff << 16)
-#define S3C_GNPTXSTS_NPTxQSpcAvail_SHIFT (16)
-#define S3C_GNPTXSTS_NPTxQSpcAvail_GET(_v) (((_v) >> 16) & 0xff)
-
-#define S3C_GNPTXSTS_NPTxFSpcAvail_MASK (0xffff << 0)
-#define S3C_GNPTXSTS_NPTxFSpcAvail_SHIFT (0)
-#define S3C_GNPTXSTS_NPTxFSpcAvail_GET(_v) (((_v) >> 0) & 0xffff)
-
-
-#define S3C_HPTXFSIZ S3C_HSOTG_REG(0x100)
-
-#define S3C_DPTXFSIZn(_a) S3C_HSOTG_REG(0x104 + (((_a) - 1) * 4))
-
-#define S3C_DPTXFSIZn_DPTxFSize_MASK (0xffff << 16)
-#define S3C_DPTXFSIZn_DPTxFSize_SHIFT (16)
-#define S3C_DPTXFSIZn_DPTxFSize_GET(_v) (((_v) >> 16) & 0xffff)
-#define S3C_DPTXFSIZn_DPTxFSize_LIMIT (0xffff)
-#define S3C_DPTXFSIZn_DPTxFSize(_x) ((_x) << 16)
-
-#define S3C_DPTXFSIZn_DPTxFStAddr_MASK (0xffff << 0)
-#define S3C_DPTXFSIZn_DPTxFStAddr_SHIFT (0)
-
-/* Device mode registers */
-#define S3C_DCFG S3C_HSOTG_REG(0x800)
-
-#define S3C_DCFG_EPMisCnt_MASK (0x1f << 18)
-#define S3C_DCFG_EPMisCnt_SHIFT (18)
-#define S3C_DCFG_EPMisCnt_LIMIT (0x1f)
-#define S3C_DCFG_EPMisCnt(_x) ((_x) << 18)
-
-#define S3C_DCFG_PerFrInt_MASK (0x3 << 11)
-#define S3C_DCFG_PerFrInt_SHIFT (11)
-#define S3C_DCFG_PerFrInt_LIMIT (0x3)
-#define S3C_DCFG_PerFrInt(_x) ((_x) << 11)
-
-#define S3C_DCFG_DevAddr_MASK (0x7f << 4)
-#define S3C_DCFG_DevAddr_SHIFT (4)
-#define S3C_DCFG_DevAddr_LIMIT (0x7f)
-#define S3C_DCFG_DevAddr(_x) ((_x) << 4)
-
-#define S3C_DCFG_NZStsOUTHShk (1 << 2)
-
-#define S3C_DCFG_DevSpd_MASK (0x3 << 0)
-#define S3C_DCFG_DevSpd_SHIFT (0)
-#define S3C_DCFG_DevSpd_HS (0x0 << 0)
-#define S3C_DCFG_DevSpd_FS (0x1 << 0)
-#define S3C_DCFG_DevSpd_LS (0x2 << 0)
-#define S3C_DCFG_DevSpd_FS48 (0x3 << 0)
-
-#define S3C_DCTL S3C_HSOTG_REG(0x804)
-
-#define S3C_DCTL_PWROnPrgDone (1 << 11)
-#define S3C_DCTL_CGOUTNak (1 << 10)
-#define S3C_DCTL_SGOUTNak (1 << 9)
-#define S3C_DCTL_CGNPInNAK (1 << 8)
-#define S3C_DCTL_SGNPInNAK (1 << 7)
-#define S3C_DCTL_TstCtl_MASK (0x7 << 4)
-#define S3C_DCTL_TstCtl_SHIFT (4)
-#define S3C_DCTL_GOUTNakSts (1 << 3)
-#define S3C_DCTL_GNPINNakSts (1 << 2)
-#define S3C_DCTL_SftDiscon (1 << 1)
-#define S3C_DCTL_RmtWkUpSig (1 << 0)
-
-#define S3C_DSTS S3C_HSOTG_REG(0x808)
-
-#define S3C_DSTS_SOFFN_MASK (0x3fff << 8)
-#define S3C_DSTS_SOFFN_SHIFT (8)
-#define S3C_DSTS_SOFFN_LIMIT (0x3fff)
-#define S3C_DSTS_SOFFN(_x) ((_x) << 8)
-#define S3C_DSTS_ErraticErr (1 << 3)
-#define S3C_DSTS_EnumSpd_MASK (0x3 << 1)
-#define S3C_DSTS_EnumSpd_SHIFT (1)
-#define S3C_DSTS_EnumSpd_HS (0x0 << 1)
-#define S3C_DSTS_EnumSpd_FS (0x1 << 1)
-#define S3C_DSTS_EnumSpd_LS (0x2 << 1)
-#define S3C_DSTS_EnumSpd_FS48 (0x3 << 1)
-
-#define S3C_DSTS_SuspSts (1 << 0)
-
-#define S3C_DIEPMSK S3C_HSOTG_REG(0x810)
-
-#define S3C_DIEPMSK_TxFIFOEmpty (1 << 7)
-#define S3C_DIEPMSK_INEPNakEffMsk (1 << 6)
-#define S3C_DIEPMSK_INTknEPMisMsk (1 << 5)
-#define S3C_DIEPMSK_INTknTXFEmpMsk (1 << 4)
-#define S3C_DIEPMSK_TimeOUTMsk (1 << 3)
-#define S3C_DIEPMSK_AHBErrMsk (1 << 2)
-#define S3C_DIEPMSK_EPDisbldMsk (1 << 1)
-#define S3C_DIEPMSK_XferComplMsk (1 << 0)
-
-#define S3C_DOEPMSK S3C_HSOTG_REG(0x814)
-
-#define S3C_DOEPMSK_Back2BackSetup (1 << 6)
-#define S3C_DOEPMSK_OUTTknEPdisMsk (1 << 4)
-#define S3C_DOEPMSK_SetupMsk (1 << 3)
-#define S3C_DOEPMSK_AHBErrMsk (1 << 2)
-#define S3C_DOEPMSK_EPDisbldMsk (1 << 1)
-#define S3C_DOEPMSK_XferComplMsk (1 << 0)
-
-#define S3C_DAINT S3C_HSOTG_REG(0x818)
-#define S3C_DAINTMSK S3C_HSOTG_REG(0x81C)
-
-#define S3C_DAINT_OutEP_SHIFT (16)
-#define S3C_DAINT_OutEP(x) (1 << ((x) + 16))
-#define S3C_DAINT_InEP(x) (1 << (x))
-
-#define S3C_DTKNQR1 S3C_HSOTG_REG(0x820)
-#define S3C_DTKNQR2 S3C_HSOTG_REG(0x824)
-#define S3C_DTKNQR3 S3C_HSOTG_REG(0x830)
-#define S3C_DTKNQR4 S3C_HSOTG_REG(0x834)
-
-#define S3C_DVBUSDIS S3C_HSOTG_REG(0x828)
-#define S3C_DVBUSPULSE S3C_HSOTG_REG(0x82C)
-
-#define S3C_DIEPCTL0 S3C_HSOTG_REG(0x900)
-#define S3C_DOEPCTL0 S3C_HSOTG_REG(0xB00)
-#define S3C_DIEPCTL(_a) S3C_HSOTG_REG(0x900 + ((_a) * 0x20))
-#define S3C_DOEPCTL(_a) S3C_HSOTG_REG(0xB00 + ((_a) * 0x20))
-
-/* EP0 specialness:
- * bits[29..28] - reserved (no SetD0PID, SetD1PID)
- * bits[25..22] - should always be zero, this isn't a periodic endpoint
- * bits[10..0] - MPS setting differenct for EP0
-*/
-#define S3C_D0EPCTL_MPS_MASK (0x3 << 0)
-#define S3C_D0EPCTL_MPS_SHIFT (0)
-#define S3C_D0EPCTL_MPS_64 (0x0 << 0)
-#define S3C_D0EPCTL_MPS_32 (0x1 << 0)
-#define S3C_D0EPCTL_MPS_16 (0x2 << 0)
-#define S3C_D0EPCTL_MPS_8 (0x3 << 0)
-
-#define S3C_DxEPCTL_EPEna (1 << 31)
-#define S3C_DxEPCTL_EPDis (1 << 30)
-#define S3C_DxEPCTL_SetD1PID (1 << 29)
-#define S3C_DxEPCTL_SetOddFr (1 << 29)
-#define S3C_DxEPCTL_SetD0PID (1 << 28)
-#define S3C_DxEPCTL_SetEvenFr (1 << 28)
-#define S3C_DxEPCTL_SNAK (1 << 27)
-#define S3C_DxEPCTL_CNAK (1 << 26)
-#define S3C_DxEPCTL_TxFNum_MASK (0xf << 22)
-#define S3C_DxEPCTL_TxFNum_SHIFT (22)
-#define S3C_DxEPCTL_TxFNum_LIMIT (0xf)
-#define S3C_DxEPCTL_TxFNum(_x) ((_x) << 22)
-
-#define S3C_DxEPCTL_Stall (1 << 21)
-#define S3C_DxEPCTL_Snp (1 << 20)
-#define S3C_DxEPCTL_EPType_MASK (0x3 << 18)
-#define S3C_DxEPCTL_EPType_SHIFT (18)
-#define S3C_DxEPCTL_EPType_Control (0x0 << 18)
-#define S3C_DxEPCTL_EPType_Iso (0x1 << 18)
-#define S3C_DxEPCTL_EPType_Bulk (0x2 << 18)
-#define S3C_DxEPCTL_EPType_Intterupt (0x3 << 18)
-
-#define S3C_DxEPCTL_NAKsts (1 << 17)
-#define S3C_DxEPCTL_DPID (1 << 16)
-#define S3C_DxEPCTL_EOFrNum (1 << 16)
-#define S3C_DxEPCTL_USBActEp (1 << 15)
-#define S3C_DxEPCTL_NextEp_MASK (0xf << 11)
-#define S3C_DxEPCTL_NextEp_SHIFT (11)
-#define S3C_DxEPCTL_NextEp_LIMIT (0xf)
-#define S3C_DxEPCTL_NextEp(_x) ((_x) << 11)
-
-#define S3C_DxEPCTL_MPS_MASK (0x7ff << 0)
-#define S3C_DxEPCTL_MPS_SHIFT (0)
-#define S3C_DxEPCTL_MPS_LIMIT (0x7ff)
-#define S3C_DxEPCTL_MPS(_x) ((_x) << 0)
-
-#define S3C_DIEPINT(_a) S3C_HSOTG_REG(0x908 + ((_a) * 0x20))
-#define S3C_DOEPINT(_a) S3C_HSOTG_REG(0xB08 + ((_a) * 0x20))
-
-#define S3C_DxEPINT_INEPNakEff (1 << 6)
-#define S3C_DxEPINT_Back2BackSetup (1 << 6)
-#define S3C_DxEPINT_INTknEPMis (1 << 5)
-#define S3C_DxEPINT_INTknTXFEmp (1 << 4)
-#define S3C_DxEPINT_OUTTknEPdis (1 << 4)
-#define S3C_DxEPINT_Timeout (1 << 3)
-#define S3C_DxEPINT_Setup (1 << 3)
-#define S3C_DxEPINT_AHBErr (1 << 2)
-#define S3C_DxEPINT_EPDisbld (1 << 1)
-#define S3C_DxEPINT_XferCompl (1 << 0)
-
-#define S3C_DIEPTSIZ0 S3C_HSOTG_REG(0x910)
-
-#define S3C_DIEPTSIZ0_PktCnt_MASK (0x3 << 19)
-#define S3C_DIEPTSIZ0_PktCnt_SHIFT (19)
-#define S3C_DIEPTSIZ0_PktCnt_LIMIT (0x3)
-#define S3C_DIEPTSIZ0_PktCnt(_x) ((_x) << 19)
-
-#define S3C_DIEPTSIZ0_XferSize_MASK (0x7f << 0)
-#define S3C_DIEPTSIZ0_XferSize_SHIFT (0)
-#define S3C_DIEPTSIZ0_XferSize_LIMIT (0x7f)
-#define S3C_DIEPTSIZ0_XferSize(_x) ((_x) << 0)
-
-
-#define DOEPTSIZ0 S3C_HSOTG_REG(0xB10)
-#define S3C_DOEPTSIZ0_SUPCnt_MASK (0x3 << 29)
-#define S3C_DOEPTSIZ0_SUPCnt_SHIFT (29)
-#define S3C_DOEPTSIZ0_SUPCnt_LIMIT (0x3)
-#define S3C_DOEPTSIZ0_SUPCnt(_x) ((_x) << 29)
-
-#define S3C_DOEPTSIZ0_PktCnt (1 << 19)
-#define S3C_DOEPTSIZ0_XferSize_MASK (0x7f << 0)
-#define S3C_DOEPTSIZ0_XferSize_SHIFT (0)
-
-#define S3C_DIEPTSIZ(_a) S3C_HSOTG_REG(0x910 + ((_a) * 0x20))
-#define S3C_DOEPTSIZ(_a) S3C_HSOTG_REG(0xB10 + ((_a) * 0x20))
-
-#define S3C_DxEPTSIZ_MC_MASK (0x3 << 29)
-#define S3C_DxEPTSIZ_MC_SHIFT (29)
-#define S3C_DxEPTSIZ_MC_LIMIT (0x3)
-#define S3C_DxEPTSIZ_MC(_x) ((_x) << 29)
-
-#define S3C_DxEPTSIZ_PktCnt_MASK (0x3ff << 19)
-#define S3C_DxEPTSIZ_PktCnt_SHIFT (19)
-#define S3C_DxEPTSIZ_PktCnt_GET(_v) (((_v) >> 19) & 0x3ff)
-#define S3C_DxEPTSIZ_PktCnt_LIMIT (0x3ff)
-#define S3C_DxEPTSIZ_PktCnt(_x) ((_x) << 19)
-
-#define S3C_DxEPTSIZ_XferSize_MASK (0x7ffff << 0)
-#define S3C_DxEPTSIZ_XferSize_SHIFT (0)
-#define S3C_DxEPTSIZ_XferSize_GET(_v) (((_v) >> 0) & 0x7ffff)
-#define S3C_DxEPTSIZ_XferSize_LIMIT (0x7ffff)
-#define S3C_DxEPTSIZ_XferSize(_x) ((_x) << 0)
-
-
-#define S3C_DIEPDMA(_a) S3C_HSOTG_REG(0x914 + ((_a) * 0x20))
-#define S3C_DOEPDMA(_a) S3C_HSOTG_REG(0xB14 + ((_a) * 0x20))
-#define S3C_DTXFSTS(_a) S3C_HSOTG_REG(0x918 + ((_a) * 0x20))
-
-#define S3C_EPFIFO(_a) S3C_HSOTG_REG(0x1000 + ((_a) * 0x1000))
-
-#endif /* __PLAT_S3C64XX_REGS_USB_HSOTG_H */
diff --git a/arch/arm/plat-samsung/include/plat/sdhci.h b/arch/arm/plat-samsung/include/plat/sdhci.h
index e834c5ef437c..151cc9195cf6 100644
--- a/arch/arm/plat-samsung/include/plat/sdhci.h
+++ b/arch/arm/plat-samsung/include/plat/sdhci.h
@@ -33,18 +33,12 @@ enum cd_types {
S3C_SDHCI_CD_PERMANENT, /* no CD line, card permanently wired to host */
};
-enum clk_types {
- S3C_SDHCI_CLK_DIV_INTERNAL, /* use mmc internal clock divider */
- S3C_SDHCI_CLK_DIV_EXTERNAL, /* use external clock divider */
-};
-
/**
* struct s3c_sdhci_platdata() - Platform device data for Samsung SDHCI
* @max_width: The maximum number of data bits supported.
* @host_caps: Standard MMC host capabilities bit field.
* @host_caps2: The second standard MMC host capabilities bit field.
* @cd_type: Type of Card Detection method (see cd_types enum above)
- * @clk_type: Type of clock divider method (see clk_types enum above)
* @ext_cd_init: Initialize external card detect subsystem. Called on
* sdhci-s3c driver probe when cd_type == S3C_SDHCI_CD_EXTERNAL.
* notify_func argument is a callback to the sdhci-s3c driver
@@ -69,7 +63,6 @@ struct s3c_sdhci_platdata {
unsigned int host_caps2;
unsigned int pm_caps;
enum cd_types cd_type;
- enum clk_types clk_type;
int ext_cd_gpio;
bool ext_cd_gpio_invert;
diff --git a/arch/arm/plat-samsung/platformdata.c b/arch/arm/plat-samsung/platformdata.c
index fa78aa710ed1..b430e9946287 100644
--- a/arch/arm/plat-samsung/platformdata.c
+++ b/arch/arm/plat-samsung/platformdata.c
@@ -57,6 +57,4 @@ void s3c_sdhci_set_platdata(struct s3c_sdhci_platdata *pd,
set->host_caps2 |= pd->host_caps2;
if (pd->pm_caps)
set->pm_caps |= pd->pm_caps;
- if (pd->clk_type)
- set->clk_type = pd->clk_type;
}
diff --git a/arch/arm/plat-spear/Kconfig b/arch/arm/plat-spear/Kconfig
index 1bb3dbce8810..387655b5ce05 100644
--- a/arch/arm/plat-spear/Kconfig
+++ b/arch/arm/plat-spear/Kconfig
@@ -9,9 +9,11 @@ choice
default ARCH_SPEAR3XX
config ARCH_SPEAR3XX
- bool "SPEAr3XX"
+ bool "ST SPEAr3xx with Device Tree"
select ARM_VIC
select CPU_ARM926T
+ select USE_OF
+ select PINCTRL
help
Supports for ARM's SPEAR3XX family
diff --git a/arch/arm/plat-spear/Makefile b/arch/arm/plat-spear/Makefile
index e0f2e5b9530c..7744802c83e7 100644
--- a/arch/arm/plat-spear/Makefile
+++ b/arch/arm/plat-spear/Makefile
@@ -3,6 +3,6 @@
#
# Common support
-obj-y := clock.o restart.o time.o
+obj-y := clock.o restart.o time.o pl080.o
-obj-$(CONFIG_ARCH_SPEAR3XX) += shirq.o padmux.o
+obj-$(CONFIG_ARCH_SPEAR3XX) += shirq.o
diff --git a/arch/arm/plat-spear/include/plat/debug-macro.S b/arch/arm/plat-spear/include/plat/debug-macro.S
index 02b160a1ec9b..ab3de721c5db 100644
--- a/arch/arm/plat-spear/include/plat/debug-macro.S
+++ b/arch/arm/plat-spear/include/plat/debug-macro.S
@@ -12,7 +12,7 @@
*/
#include <linux/amba/serial.h>
-#include <mach/hardware.h>
+#include <mach/spear.h>
.macro addruart, rp, rv, tmp
mov \rp, #SPEAR_DBG_UART_BASE @ Physical base
diff --git a/arch/arm/plat-spear/include/plat/hardware.h b/arch/arm/plat-spear/include/plat/hardware.h
deleted file mode 100644
index 70187d763e26..000000000000
--- a/arch/arm/plat-spear/include/plat/hardware.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * arch/arm/plat-spear/include/plat/hardware.h
- *
- * Hardware definitions for SPEAr
- *
- * Copyright (C) 2010 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __PLAT_HARDWARE_H
-#define __PLAT_HARDWARE_H
-
-#endif /* __PLAT_HARDWARE_H */
diff --git a/arch/arm/plat-spear/include/plat/padmux.h b/arch/arm/plat-spear/include/plat/padmux.h
deleted file mode 100644
index 877f3adcf610..000000000000
--- a/arch/arm/plat-spear/include/plat/padmux.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * arch/arm/plat-spear/include/plat/padmux.h
- *
- * SPEAr platform specific gpio pads muxing file
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __PLAT_PADMUX_H
-#define __PLAT_PADMUX_H
-
-#include <linux/types.h>
-
-/*
- * struct pmx_reg: configuration structure for mode reg and mux reg
- *
- * offset: offset of mode reg
- * mask: mask of mode reg
- */
-struct pmx_reg {
- u32 offset;
- u32 mask;
-};
-
-/*
- * struct pmx_dev_mode: configuration structure every group of modes of a device
- *
- * ids: all modes for this configuration
- * mask: mask for supported mode
- */
-struct pmx_dev_mode {
- u32 ids;
- u32 mask;
-};
-
-/*
- * struct pmx_mode: mode definition structure
- *
- * name: mode name
- * mask: mode mask
- */
-struct pmx_mode {
- char *name;
- u32 id;
- u32 mask;
-};
-
-/*
- * struct pmx_dev: device definition structure
- *
- * name: device name
- * modes: device configuration array for different modes supported
- * mode_count: size of modes array
- * is_active: is peripheral active/enabled
- * enb_on_reset: if 1, mask bits to be cleared in reg otherwise to be set in reg
- */
-struct pmx_dev {
- char *name;
- struct pmx_dev_mode *modes;
- u8 mode_count;
- bool is_active;
- bool enb_on_reset;
-};
-
-/*
- * struct pmx_driver: driver definition structure
- *
- * mode: mode to be set
- * devs: array of pointer to pmx devices
- * devs_count: ARRAY_SIZE of devs
- * base: base address of soc config registers
- * mode_reg: structure of mode config register
- * mux_reg: structure of device mux config register
- */
-struct pmx_driver {
- struct pmx_mode *mode;
- struct pmx_dev **devs;
- u8 devs_count;
- u32 *base;
- struct pmx_reg mode_reg;
- struct pmx_reg mux_reg;
-};
-
-/* pmx functions */
-int pmx_register(struct pmx_driver *driver);
-
-#endif /* __PLAT_PADMUX_H */
diff --git a/arch/arm/plat-spear/include/plat/pl080.h b/arch/arm/plat-spear/include/plat/pl080.h
new file mode 100644
index 000000000000..e14a3e4932f9
--- /dev/null
+++ b/arch/arm/plat-spear/include/plat/pl080.h
@@ -0,0 +1,21 @@
+/*
+ * arch/arm/plat-spear/include/plat/pl080.h
+ *
+ * DMAC pl080 definitions for SPEAr platform
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __PLAT_PL080_H
+#define __PLAT_PL080_H
+
+struct pl08x_dma_chan;
+int pl080_get_signal(struct pl08x_dma_chan *ch);
+void pl080_put_signal(struct pl08x_dma_chan *ch);
+
+#endif /* __PLAT_PL080_H */
diff --git a/arch/arm/plat-spear/include/plat/uncompress.h b/arch/arm/plat-spear/include/plat/uncompress.h
index 1bf84527aee4..6dd455bafdfd 100644
--- a/arch/arm/plat-spear/include/plat/uncompress.h
+++ b/arch/arm/plat-spear/include/plat/uncompress.h
@@ -13,7 +13,7 @@
#include <linux/io.h>
#include <linux/amba/serial.h>
-#include <mach/hardware.h>
+#include <mach/spear.h>
#ifndef __PLAT_UNCOMPRESS_H
#define __PLAT_UNCOMPRESS_H
diff --git a/arch/arm/plat-spear/padmux.c b/arch/arm/plat-spear/padmux.c
deleted file mode 100644
index 555eec6dc1cb..000000000000
--- a/arch/arm/plat-spear/padmux.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * arch/arm/plat-spear/include/plat/padmux.c
- *
- * SPEAr platform specific gpio pads muxing source file
- *
- * Copyright (C) 2009 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <plat/padmux.h>
-
-/*
- * struct pmx: pmx definition structure
- *
- * base: base address of configuration registers
- * mode_reg: mode configurations
- * mux_reg: muxing configurations
- * active_mode: pointer to current active mode
- */
-struct pmx {
- u32 base;
- struct pmx_reg mode_reg;
- struct pmx_reg mux_reg;
- struct pmx_mode *active_mode;
-};
-
-static struct pmx *pmx;
-
-/**
- * pmx_mode_set - Enables an multiplexing mode
- * @mode - pointer to pmx mode
- *
- * It will set mode of operation in hardware.
- * Returns -ve on Err otherwise 0
- */
-static int pmx_mode_set(struct pmx_mode *mode)
-{
- u32 val;
-
- if (!mode->name)
- return -EFAULT;
-
- pmx->active_mode = mode;
-
- val = readl(pmx->base + pmx->mode_reg.offset);
- val &= ~pmx->mode_reg.mask;
- val |= mode->mask & pmx->mode_reg.mask;
- writel(val, pmx->base + pmx->mode_reg.offset);
-
- return 0;
-}
-
-/**
- * pmx_devs_enable - Enables list of devices
- * @devs - pointer to pmx device array
- * @count - number of devices to enable
- *
- * It will enable pads for all required peripherals once and only once.
- * If peripheral is not supported by current mode then request is rejected.
- * Conflicts between peripherals are not handled and peripherals will be
- * enabled in the order they are present in pmx_dev array.
- * In case of conflicts last peripheral enabled will be present.
- * Returns -ve on Err otherwise 0
- */
-static int pmx_devs_enable(struct pmx_dev **devs, u8 count)
-{
- u32 val, i, mask;
-
- if (!count)
- return -EINVAL;
-
- val = readl(pmx->base + pmx->mux_reg.offset);
- for (i = 0; i < count; i++) {
- u8 j = 0;
-
- if (!devs[i]->name || !devs[i]->modes) {
- printk(KERN_ERR "padmux: dev name or modes is null\n");
- continue;
- }
- /* check if peripheral exists in active mode */
- if (pmx->active_mode) {
- bool found = false;
- for (j = 0; j < devs[i]->mode_count; j++) {
- if (devs[i]->modes[j].ids &
- pmx->active_mode->id) {
- found = true;
- break;
- }
- }
- if (found == false) {
- printk(KERN_ERR "%s device not available in %s"\
- "mode\n", devs[i]->name,
- pmx->active_mode->name);
- continue;
- }
- }
-
- /* enable peripheral */
- mask = devs[i]->modes[j].mask & pmx->mux_reg.mask;
- if (devs[i]->enb_on_reset)
- val &= ~mask;
- else
- val |= mask;
-
- devs[i]->is_active = true;
- }
- writel(val, pmx->base + pmx->mux_reg.offset);
- kfree(pmx);
-
- /* this will ensure that multiplexing can't be changed now */
- pmx = (struct pmx *)-1;
-
- return 0;
-}
-
-/**
- * pmx_register - registers a platform requesting pad mux feature
- * @driver - pointer to driver structure containing driver specific parameters
- *
- * Also this must be called only once. This will allocate memory for pmx
- * structure, will call pmx_mode_set, will call pmx_devs_enable.
- * Returns -ve on Err otherwise 0
- */
-int pmx_register(struct pmx_driver *driver)
-{
- int ret = 0;
-
- if (pmx)
- return -EPERM;
- if (!driver->base || !driver->devs)
- return -EFAULT;
-
- pmx = kzalloc(sizeof(*pmx), GFP_KERNEL);
- if (!pmx)
- return -ENOMEM;
-
- pmx->base = (u32)driver->base;
- pmx->mode_reg.offset = driver->mode_reg.offset;
- pmx->mode_reg.mask = driver->mode_reg.mask;
- pmx->mux_reg.offset = driver->mux_reg.offset;
- pmx->mux_reg.mask = driver->mux_reg.mask;
-
- /* choose mode to enable */
- if (driver->mode) {
- ret = pmx_mode_set(driver->mode);
- if (ret)
- goto pmx_fail;
- }
- ret = pmx_devs_enable(driver->devs, driver->devs_count);
- if (ret)
- goto pmx_fail;
-
- return 0;
-
-pmx_fail:
- return ret;
-}
diff --git a/arch/arm/plat-spear/pl080.c b/arch/arm/plat-spear/pl080.c
new file mode 100644
index 000000000000..a56a067717c1
--- /dev/null
+++ b/arch/arm/plat-spear/pl080.c
@@ -0,0 +1,80 @@
+/*
+ * arch/arm/plat-spear/pl080.c
+ *
+ * DMAC pl080 definitions for SPEAr platform
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/amba/pl08x.h>
+#include <linux/amba/bus.h>
+#include <linux/bug.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/spinlock_types.h>
+#include <mach/spear.h>
+#include <mach/misc_regs.h>
+
+static spinlock_t lock = __SPIN_LOCK_UNLOCKED(x);
+
+struct {
+ unsigned char busy;
+ unsigned char val;
+} signals[16] = {{0, 0}, };
+
+int pl080_get_signal(struct pl08x_dma_chan *ch)
+{
+ const struct pl08x_channel_data *cd = ch->cd;
+ unsigned int signal = cd->min_signal, val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&lock, flags);
+
+ /* Return if signal is already acquired by somebody else */
+ if (signals[signal].busy &&
+ (signals[signal].val != cd->muxval)) {
+ spin_unlock_irqrestore(&lock, flags);
+ return -EBUSY;
+ }
+
+ /* If acquiring for the first time, configure it */
+ if (!signals[signal].busy) {
+ val = readl(DMA_CHN_CFG);
+
+ /*
+ * Each request line has two bits in DMA_CHN_CFG register. To
+ * goto the bits of current request line, do left shift of
+ * value by 2 * signal number.
+ */
+ val &= ~(0x3 << (signal * 2));
+ val |= cd->muxval << (signal * 2);
+ writel(val, DMA_CHN_CFG);
+ }
+
+ signals[signal].busy++;
+ signals[signal].val = cd->muxval;
+ spin_unlock_irqrestore(&lock, flags);
+
+ return signal;
+}
+
+void pl080_put_signal(struct pl08x_dma_chan *ch)
+{
+ const struct pl08x_channel_data *cd = ch->cd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&lock, flags);
+
+ /* if signal is not used */
+ if (!signals[cd->min_signal].busy)
+ BUG();
+
+ signals[cd->min_signal].busy--;
+
+ spin_unlock_irqrestore(&lock, flags);
+}
diff --git a/arch/arm/plat-spear/restart.c b/arch/arm/plat-spear/restart.c
index 16f203e78d89..4471a232713a 100644
--- a/arch/arm/plat-spear/restart.c
+++ b/arch/arm/plat-spear/restart.c
@@ -13,7 +13,7 @@
#include <linux/io.h>
#include <asm/system_misc.h>
#include <asm/hardware/sp810.h>
-#include <mach/hardware.h>
+#include <mach/spear.h>
#include <mach/generic.h>
void spear_restart(char mode, const char *cmd)
diff --git a/arch/arm/plat-spear/time.c b/arch/arm/plat-spear/time.c
index abb5bdecd509..a3164d1647fd 100644
--- a/arch/arm/plat-spear/time.c
+++ b/arch/arm/plat-spear/time.c
@@ -15,14 +15,13 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/time.h>
#include <linux/irq.h>
#include <asm/mach/time.h>
#include <mach/generic.h>
-#include <mach/hardware.h>
-#include <mach/irqs.h>
/*
* We would use TIMER0 and TIMER1 as clockevent and clocksource.
@@ -175,7 +174,7 @@ static struct irqaction spear_timer_irq = {
.handler = spear_timer_interrupt
};
-static void __init spear_clockevent_init(void)
+static void __init spear_clockevent_init(int irq)
{
u32 tick_rate;
@@ -195,19 +194,19 @@ static void __init spear_clockevent_init(void)
clockevents_register_device(&clkevt);
- setup_irq(SPEAR_GPT0_CHAN0_IRQ, &spear_timer_irq);
+ setup_irq(irq, &spear_timer_irq);
}
-void __init spear_setup_timer(void)
+void __init spear_setup_timer(resource_size_t base, int irq)
{
int ret;
- if (!request_mem_region(SPEAR_GPT0_BASE, SZ_1K, "gpt0")) {
+ if (!request_mem_region(base, SZ_1K, "gpt0")) {
pr_err("%s:cannot get IO addr\n", __func__);
return;
}
- gpt_base = (void __iomem *)ioremap(SPEAR_GPT0_BASE, SZ_1K);
+ gpt_base = ioremap(base, SZ_1K);
if (!gpt_base) {
pr_err("%s:ioremap failed for gpt\n", __func__);
goto err_mem;
@@ -225,7 +224,7 @@ void __init spear_setup_timer(void)
goto err_clk;
}
- spear_clockevent_init();
+ spear_clockevent_init(irq);
spear_clocksource_init();
return;
@@ -235,5 +234,5 @@ err_clk:
err_iomap:
iounmap(gpt_base);
err_mem:
- release_mem_region(SPEAR_GPT0_BASE, SZ_1K);
+ release_mem_region(base, SZ_1K);
}
diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig
index 3dea7231f637..71d38c76726c 100644
--- a/arch/avr32/Kconfig
+++ b/arch/avr32/Kconfig
@@ -11,7 +11,9 @@ config AVR32
select GENERIC_ATOMIC64
select HARDIRQS_SW_RESEND
select GENERIC_IRQ_SHOW
+ select ARCH_HAVE_CUSTOM_GPIO_H
select ARCH_HAVE_NMI_SAFE_CMPXCHG
+ select GENERIC_CLOCKEVENTS
help
AVR32 is a high-performance 32-bit RISC microprocessor core,
designed for cost-sensitive embedded applications, with particular
@@ -35,9 +37,6 @@ config TRACE_IRQFLAGS_SUPPORT
config RWSEM_GENERIC_SPINLOCK
def_bool y
-config GENERIC_CLOCKEVENTS
- def_bool y
-
config RWSEM_XCHGADD_ALGORITHM
def_bool n
@@ -63,8 +62,6 @@ source "kernel/Kconfig.freezer"
menu "System Type and features"
-source "kernel/time/Kconfig"
-
config SUBARCH_AVR32B
bool
config MMU
diff --git a/arch/avr32/include/asm/processor.h b/arch/avr32/include/asm/processor.h
index 108502bc6770..87d8baccc60e 100644
--- a/arch/avr32/include/asm/processor.h
+++ b/arch/avr32/include/asm/processor.h
@@ -145,9 +145,6 @@ extern void release_thread(struct task_struct *);
/* Create a kernel thread without removing it from tasklists */
extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk) do { } while(0)
-
/* Return saved PC of a blocked thread */
#define thread_saved_pc(tsk) ((tsk)->thread.cpu_context.pc)
diff --git a/arch/avr32/include/asm/signal.h b/arch/avr32/include/asm/signal.h
index 8790dfc10d5b..ae56849fdb2b 100644
--- a/arch/avr32/include/asm/signal.h
+++ b/arch/avr32/include/asm/signal.h
@@ -115,13 +115,6 @@ typedef unsigned long sigset_t;
#include <asm-generic/signal-defs.h>
#ifdef __KERNEL__
-struct old_sigaction {
- __sighandler_t sa_handler;
- old_sigset_t sa_mask;
- unsigned long sa_flags;
- __sigrestore_t sa_restorer;
-};
-
struct sigaction {
__sighandler_t sa_handler;
unsigned long sa_flags;
diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c
index 64f886fac2ef..ae386c304bee 100644
--- a/arch/avr32/kernel/signal.c
+++ b/arch/avr32/kernel/signal.c
@@ -77,6 +77,9 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
struct rt_sigframe __user *frame;
sigset_t set;
+ /* Always make any pending restarted system calls return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
frame = (struct rt_sigframe __user *)regs->sp;
pr_debug("SIG return: frame = %p\n", frame);
@@ -87,10 +90,7 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
@@ -238,22 +238,16 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
*/
ret |= !valid_user_regs(regs);
- /*
- * Block the signal if we were unsuccessful.
- */
- if (ret != 0 || !(ka->sa.sa_flags & SA_NODEFER)) {
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked, &current->blocked,
- &ka->sa.sa_mask);
- sigaddset(&current->blocked, sig);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
- }
-
- if (ret == 0)
+ if (ret != 0) {
+ force_sigsegv(sig, current);
return;
+ }
- force_sigsegv(sig, current);
+ /*
+ * Block the signal if we were successful.
+ */
+ block_sigmask(ka, sig);
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
}
/*
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index 7f3c589cc024..fef96f47876c 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -31,6 +31,7 @@ config BLACKFIN
select HAVE_KERNEL_LZO if RAMKERNEL
select HAVE_OPROFILE
select HAVE_PERF_EVENTS
+ select ARCH_HAVE_CUSTOM_GPIO_H
select ARCH_WANT_OPTIONAL_GPIOLIB
select HAVE_GENERIC_HARDIRQS
select GENERIC_ATOMIC64
@@ -38,6 +39,7 @@ config BLACKFIN
select IRQ_PER_CPU if SMP
select HAVE_NMI_WATCHDOG if NMI_WATCHDOG
select GENERIC_SMP_IDLE_THREAD
+ select ARCH_USES_GETTIMEOFFSET if !GENERIC_CLOCKEVENTS
config GENERIC_CSUM
def_bool y
@@ -642,9 +644,10 @@ comment "Kernel Timer/Scheduler"
source kernel/Kconfig.hz
-config GENERIC_CLOCKEVENTS
+config SET_GENERIC_CLOCKEVENTS
bool "Generic clock events"
default y
+ select GENERIC_CLOCKEVENTS
menu "Clock event device"
depends on GENERIC_CLOCKEVENTS
@@ -678,12 +681,6 @@ config GPTMR0_CLOCKSOURCE
depends on !TICKSOURCE_GPTMR0
endmenu
-config ARCH_USES_GETTIMEOFFSET
- depends on !GENERIC_CLOCKEVENTS
- def_bool y
-
-source kernel/time/Kconfig
-
comment "Misc"
choice
@@ -1309,7 +1306,7 @@ config PM_BFIN_WAKE_GP
(all processors, except ADSP-BF549). This option sets
the general-purpose wake-up enable (GPWE) control bit to enable
wake-up upon detection of an active low signal on the /GPW (PH7) pin.
- On ADSP-BF549 this option enables the the same functionality on the
+ On ADSP-BF549 this option enables the same functionality on the
/MRXON pin also PH7.
config PM_BFIN_WAKE_PA15
diff --git a/arch/blackfin/include/asm/processor.h b/arch/blackfin/include/asm/processor.h
index 8af7772e84cc..4ef7cfe43ceb 100644
--- a/arch/blackfin/include/asm/processor.h
+++ b/arch/blackfin/include/asm/processor.h
@@ -75,8 +75,6 @@ static inline void release_thread(struct task_struct *dead_task)
{
}
-#define prepare_to_copy(tsk) do { } while (0)
-
extern int kernel_thread(int (*fn) (void *), void *arg, unsigned long flags);
/*
diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c
index d536f35d1f43..e5bbc1a5edc2 100644
--- a/arch/blackfin/kernel/signal.c
+++ b/arch/blackfin/kernel/signal.c
@@ -99,10 +99,7 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused)
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
if (rt_restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
goto badframe;
@@ -213,9 +210,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t * info,
return 0;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
return -EFAULT;
}
@@ -266,15 +261,9 @@ handle_signal(int sig, siginfo_t *info, struct k_sigaction *ka,
/* set up the stack frame */
ret = setup_rt_frame(sig, ka, info, oldset, regs);
- if (ret == 0) {
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked, &current->blocked,
- &ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(&current->blocked, sig);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
- }
+ if (ret == 0)
+ block_sigmask(ka, sig);
+
return ret;
}
diff --git a/arch/c6x/Kconfig b/arch/c6x/Kconfig
index 1f15b88b537f..052f81a76239 100644
--- a/arch/c6x/Kconfig
+++ b/arch/c6x/Kconfig
@@ -15,6 +15,7 @@ config C6X
select IRQ_DOMAIN
select OF
select OF_EARLY_FLATTREE
+ select GENERIC_CLOCKEVENTS
config MMU
def_bool n
@@ -31,12 +32,6 @@ config GENERIC_CALIBRATE_DELAY
config GENERIC_HWEIGHT
def_bool y
-config GENERIC_CLOCKEVENTS
- def_bool y
-
-config GENERIC_CLOCKEVENTS_BROADCAST
- bool
-
config GENERIC_BUG
def_bool y
@@ -125,7 +120,6 @@ source "mm/Kconfig"
source "kernel/Kconfig.preempt"
source "kernel/Kconfig.hz"
-source "kernel/time/Kconfig"
endmenu
diff --git a/arch/c6x/include/asm/processor.h b/arch/c6x/include/asm/processor.h
index 3ff7fab956ba..c50af7ef1c96 100644
--- a/arch/c6x/include/asm/processor.h
+++ b/arch/c6x/include/asm/processor.h
@@ -92,9 +92,6 @@ static inline void release_thread(struct task_struct *dead_task)
{
}
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk) do { } while (0)
-
extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
#define copy_segments(tsk, mm) do { } while (0)
diff --git a/arch/c6x/kernel/signal.c b/arch/c6x/kernel/signal.c
index 3b5a05099989..cf37478c1169 100644
--- a/arch/c6x/kernel/signal.c
+++ b/arch/c6x/kernel/signal.c
@@ -69,6 +69,9 @@ asmlinkage int do_rt_sigreturn(struct pt_regs *regs)
struct rt_sigframe __user *frame;
sigset_t set;
+ /* Always make any pending restarted system calls return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
/*
* Since we stacked the signal on a dword boundary,
* 'sp' should be dword aligned here. If it's
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig
index 2995035812ec..22d34d64cc81 100644
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -13,12 +13,6 @@ config RWSEM_GENERIC_SPINLOCK
config RWSEM_XCHGADD_ALGORITHM
bool
-config GENERIC_CMOS_UPDATE
- def_bool y
-
-config ARCH_USES_GETTIMEOFFSET
- def_bool n
-
config ARCH_HAS_ILOG2_U32
bool
default n
@@ -50,6 +44,7 @@ config CRIS
select GENERIC_IRQ_SHOW
select GENERIC_IOMAP
select GENERIC_SMP_IDLE_THREAD if ETRAX_ARCH_V32
+ select GENERIC_CMOS_UPDATE
config HZ
int
diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c
index 289c584ba499..e16f8f297f61 100644
--- a/arch/cris/arch-v10/kernel/signal.c
+++ b/arch/cris/arch-v10/kernel/signal.c
@@ -48,19 +48,11 @@ void do_signal(int canrestart, struct pt_regs *regs);
* dummy arguments to be able to reach the regs argument. (Note that this
* arrangement relies on old_sigset_t occupying one register.)
*/
-int sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof,
- long srp, struct pt_regs *regs)
+int sys_sigsuspend(old_sigset_t mask)
{
- mask &= _BLOCKABLE;
- spin_lock_irq(&current->sighand->siglock);
- current->saved_sigmask = current->blocked;
- siginitset(&current->blocked, mask);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
+ sigset_t blocked;
+ siginitset(&blocked, mask);
+ return sigsuspend(&blocked);
}
int sys_sigaction(int sig, const struct old_sigaction __user *act,
@@ -73,10 +65,10 @@ int sys_sigaction(int sig, const struct old_sigaction __user *act,
old_sigset_t mask;
if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
+ __get_user(mask, &act->sa_mask))
return -EFAULT;
- __get_user(new_ka.sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
siginitset(&new_ka.sa.sa_mask, mask);
}
@@ -85,10 +77,10 @@ int sys_sigaction(int sig, const struct old_sigaction __user *act,
if (!ret && oact) {
if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
__put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
return -EFAULT;
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
}
return ret;
@@ -185,10 +177,7 @@ asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof,
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->sc))
goto badframe;
@@ -224,10 +213,7 @@ asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13,
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
@@ -469,15 +455,9 @@ static inline int handle_signal(int canrestart, unsigned long sig,
else
ret = setup_frame(sig, ka, oldset, regs);
- if (ret == 0) {
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked, &current->blocked,
- &ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(&current->blocked, sig);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
- }
+ if (ret == 0)
+ block_sigmask(ka, sig);
+
return ret;
}
diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c
index ce4ab1a5552c..b338d8fc0c12 100644
--- a/arch/cris/arch-v32/kernel/signal.c
+++ b/arch/cris/arch-v32/kernel/signal.c
@@ -59,19 +59,11 @@ void keep_debug_flags(unsigned long oldccs, unsigned long oldspc,
* dummy arguments to be able to reach the regs argument.
*/
int
-sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof,
- long srp, struct pt_regs *regs)
+sys_sigsuspend(old_sigset_t mask)
{
- mask &= _BLOCKABLE;
- spin_lock_irq(&current->sighand->siglock);
- current->saved_sigmask = current->blocked;
- siginitset(&current->blocked, mask);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
+ sigset_t blocked;
+ siginitset(&blocked, mask);
+ return sigsuspend(&blocked);
}
int
@@ -87,11 +79,11 @@ sys_sigaction(int signal, const struct old_sigaction *act,
if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(newk.sa.sa_handler, &act->sa_handler) ||
- __get_user(newk.sa.sa_restorer, &act->sa_restorer))
+ __get_user(newk.sa.sa_restorer, &act->sa_restorer) ||
+ __get_user(newk.sa.sa_flags, &act->sa_flags) ||
+ __get_user(mask, &act->sa_mask))
return -EFAULT;
- __get_user(newk.sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
siginitset(&newk.sa.sa_mask, mask);
}
@@ -100,11 +92,11 @@ sys_sigaction(int signal, const struct old_sigaction *act,
if (!retval && oact) {
if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
__put_user(oldk.sa.sa_handler, &oact->sa_handler) ||
- __put_user(oldk.sa.sa_restorer, &oact->sa_restorer))
+ __put_user(oldk.sa.sa_restorer, &oact->sa_restorer) ||
+ __put_user(oldk.sa.sa_flags, &oact->sa_flags) ||
+ __put_user(oldk.sa.sa_mask.sig[0], &oact->sa_mask))
return -EFAULT;
- __put_user(oldk.sa.sa_flags, &oact->sa_flags);
- __put_user(oldk.sa.sa_mask.sig[0], &oact->sa_mask);
}
return retval;
@@ -176,12 +168,7 @@ sys_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp,
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
-
- current->blocked = set;
-
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->sc))
goto badframe;
@@ -222,12 +209,7 @@ sys_rt_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp,
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
-
- current->blocked = set;
-
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
@@ -363,10 +345,7 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
return 0;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
-
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
return -EFAULT;
}
@@ -450,10 +429,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
return 0;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
-
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
return -EFAULT;
}
@@ -512,18 +488,8 @@ handle_signal(int canrestart, unsigned long sig,
else
ret = setup_frame(sig, ka, oldset, regs);
- if (ka->sa.sa_flags & SA_ONESHOT)
- ka->sa.sa_handler = SIG_DFL;
-
- if (ret == 0) {
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked, &current->blocked,
- &ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(&current->blocked, sig);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
- }
+ if (ret == 0)
+ block_sigmask(ka, sig);
return ret;
}
diff --git a/arch/cris/include/asm/processor.h b/arch/cris/include/asm/processor.h
index 8dc56ef08712..ef4e1bc3efc8 100644
--- a/arch/cris/include/asm/processor.h
+++ b/arch/cris/include/asm/processor.h
@@ -49,10 +49,6 @@ struct task_struct;
#define task_pt_regs(task) user_regs(task_thread_info(task))
#define current_regs() task_pt_regs(current)
-static inline void prepare_to_copy(struct task_struct *tsk)
-{
-}
-
extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
unsigned long get_wchan(struct task_struct *p);
diff --git a/arch/frv/include/asm/processor.h b/arch/frv/include/asm/processor.h
index 9b1a92b73f60..dccb9d162318 100644
--- a/arch/frv/include/asm/processor.h
+++ b/arch/frv/include/asm/processor.h
@@ -54,7 +54,6 @@ extern struct cpuinfo_frv __nongprelbss boot_cpu_data;
* Bus types
*/
#define EISA_bus 0
-#define MCA_bus 0
struct thread_struct {
struct pt_regs *frame; /* [GR28] exception frame ptr for this thread */
@@ -103,8 +102,6 @@ do { \
__frame->sp = (_usp); \
} while(0)
-extern void prepare_to_copy(struct task_struct *tsk);
-
/* Free all resources held by a thread. */
static inline void release_thread(struct task_struct *dead_task)
{
diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c
index ed09e9e2c653..ff95f50efea5 100644
--- a/arch/frv/kernel/process.c
+++ b/arch/frv/kernel/process.c
@@ -165,17 +165,6 @@ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
return do_fork(clone_flags, newsp, __frame, 0, parent_tidptr, child_tidptr);
} /* end sys_clone() */
-/*****************************************************************************/
-/*
- * This gets called before we allocate a new thread and copy
- * the current task into it.
- */
-void prepare_to_copy(struct task_struct *tsk)
-{
- //unlazy_fpu(tsk);
-} /* end prepare_to_copy() */
-
-/*****************************************************************************/
/*
* set up the kernel stack and exception frames for a new process
*/
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c
index bab01298b58e..8cf5dca01758 100644
--- a/arch/frv/kernel/signal.c
+++ b/arch/frv/kernel/signal.c
@@ -40,17 +40,9 @@ struct fdpic_func_descriptor {
*/
asmlinkage int sys_sigsuspend(int history0, int history1, old_sigset_t mask)
{
- mask &= _BLOCKABLE;
- spin_lock_irq(&current->sighand->siglock);
- current->saved_sigmask = current->blocked;
- siginitset(&current->blocked, mask);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
+ sigset_t blocked;
+ siginitset(&blocked, mask);
+ return sigsuspend(&blocked);
}
asmlinkage int sys_sigaction(int sig,
@@ -64,10 +56,10 @@ asmlinkage int sys_sigaction(int sig,
old_sigset_t mask;
if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
+ __get_user(mask, &act->sa_mask))
return -EFAULT;
- __get_user(new_ka.sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
siginitset(&new_ka.sa.sa_mask, mask);
}
@@ -76,10 +68,10 @@ asmlinkage int sys_sigaction(int sig,
if (!ret && oact) {
if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
__put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
return -EFAULT;
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
}
return ret;
@@ -158,10 +150,7 @@ asmlinkage int sys_sigreturn(void)
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(&frame->sc, &gr8))
goto badframe;
@@ -184,10 +173,7 @@ asmlinkage int sys_rt_sigreturn(void)
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(&frame->uc.uc_mcontext, &gr8))
goto badframe;
@@ -474,15 +460,8 @@ static int handle_signal(unsigned long sig, siginfo_t *info,
else
ret = setup_frame(sig, ka, oldset);
- if (ret == 0) {
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked, &current->blocked,
- &ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(&current->blocked, sig);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
- }
+ if (ret == 0)
+ block_sigmask(ka, sig);
return ret;
diff --git a/arch/h8300/Kconfig.cpu b/arch/h8300/Kconfig.cpu
index 15c22286ae79..321f3922728b 100644
--- a/arch/h8300/Kconfig.cpu
+++ b/arch/h8300/Kconfig.cpu
@@ -1,7 +1,5 @@
menu "Processor type and features"
-source "kernel/time/Kconfig"
-
choice
prompt "H8/300 platform"
default H8300H_GENERIC
diff --git a/arch/h8300/include/asm/processor.h b/arch/h8300/include/asm/processor.h
index 61fabf1788c6..4c9f6f87b617 100644
--- a/arch/h8300/include/asm/processor.h
+++ b/arch/h8300/include/asm/processor.h
@@ -109,8 +109,6 @@ static inline void release_thread(struct task_struct *dead_task)
extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-#define prepare_to_copy(tsk) do { } while (0)
-
/*
* Free current thread data structures etc..
*/
diff --git a/arch/h8300/include/asm/unistd.h b/arch/h8300/include/asm/unistd.h
index 2c3f8e60b1e0..718511303b4e 100644
--- a/arch/h8300/include/asm/unistd.h
+++ b/arch/h8300/include/asm/unistd.h
@@ -356,6 +356,7 @@
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK
#define __ARCH_WANT_SYS_RT_SIGACTION
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
/*
* "Conditional" syscalls
diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c
index af842c369d24..d4b0555d2904 100644
--- a/arch/h8300/kernel/signal.c
+++ b/arch/h8300/kernel/signal.c
@@ -49,60 +49,15 @@
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
-
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
-asmlinkage int do_sigsuspend(struct pt_regs *regs)
-{
- old_sigset_t mask = regs->er3;
- sigset_t saveset;
-
- mask &= _BLOCKABLE;
- spin_lock_irq(&current->sighand->siglock);
- saveset = current->blocked;
- siginitset(&current->blocked, mask);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-
- regs->er0 = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (do_signal(regs, &saveset))
- return -EINTR;
- }
-}
-
asmlinkage int
-do_rt_sigsuspend(struct pt_regs *regs)
+sys_sigsuspend(int unused1, int unused2, old_sigset_t mask)
{
- sigset_t *unewset = (sigset_t *)regs->er1;
- size_t sigsetsize = (size_t)regs->er2;
- sigset_t saveset, newset;
-
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(sigset_t))
- return -EINVAL;
-
- if (copy_from_user(&newset, unewset, sizeof(newset)))
- return -EFAULT;
- sigdelsetmask(&newset, ~_BLOCKABLE);
-
- spin_lock_irq(&current->sighand->siglock);
- saveset = current->blocked;
- current->blocked = newset;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-
- regs->er0 = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (do_signal(regs, &saveset))
- return -EINTR;
- }
+ sigset_t blocked;
+ siginitset(&blocked, mask);
+ return sigsuspend(&blocked);
}
asmlinkage int
@@ -116,10 +71,10 @@ sys_sigaction(int sig, const struct old_sigaction *act,
old_sigset_t mask;
if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
+ __get_user(mask, &act->sa_mask))
return -EFAULT;
- __get_user(new_ka.sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
siginitset(&new_ka.sa.sa_mask, mask);
}
@@ -128,10 +83,10 @@ sys_sigaction(int sig, const struct old_sigaction *act,
if (!ret && oact) {
if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
__put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
return -EFAULT;
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
}
return ret;
@@ -232,10 +187,7 @@ asmlinkage int do_sigreturn(unsigned long __unused,...)
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->sc, &er0))
goto badframe;
@@ -260,10 +212,7 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused,...)
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_unlock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_lock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &er0))
goto badframe;
@@ -314,7 +263,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
return (void *)((usp - frame_size) & -8UL);
}
-static void setup_frame (int sig, struct k_sigaction *ka,
+static int setup_frame (int sig, struct k_sigaction *ka,
sigset_t *set, struct pt_regs *regs)
{
struct sigframe *frame;
@@ -375,13 +324,14 @@ static void setup_frame (int sig, struct k_sigaction *ka,
regs->er1 = (unsigned long)&(frame->sc);
regs->er5 = current->mm->start_data; /* GOT base */
- return;
+ return 0;
give_sigsegv:
force_sigsegv(sig, current);
+ return -EFAULT;
}
-static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
+static int setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs *regs)
{
struct rt_sigframe *frame;
@@ -450,10 +400,11 @@ static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
regs->er2 = (unsigned long)&frame->uc;
regs->er5 = current->mm->start_data; /* GOT base */
- return;
+ return 0;
give_sigsegv:
force_sigsegv(sig, current);
+ return -EFAULT;
}
/*
@@ -463,6 +414,7 @@ static void
handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
sigset_t *oldset, struct pt_regs * regs)
{
+ int ret;
/* are we from a system call? */
if (regs->orig_er0 >= 0) {
switch (regs->er0) {
@@ -485,16 +437,14 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
/* set up the stack frame */
if (ka->sa.sa_flags & SA_SIGINFO)
- setup_rt_frame(sig, ka, info, oldset, regs);
+ ret = setup_rt_frame(sig, ka, info, oldset, regs);
else
- setup_frame(sig, ka, oldset, regs);
-
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(&current->blocked,sig);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ ret = setup_frame(sig, ka, oldset, regs);
+
+ if (!ret) {
+ block_sigmask(ka, sig);
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ }
}
/*
@@ -502,11 +452,12 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
*/
-asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset)
+statis void do_signal(struct pt_regs *regs)
{
siginfo_t info;
int signr;
struct k_sigaction ka;
+ sigset_t *oldset;
/*
* We want the common case to go fast, which
@@ -515,21 +466,23 @@ asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset)
* if so.
*/
if ((regs->ccr & 0x10))
- return 1;
+ return;
if (try_to_freeze())
goto no_signal;
current->thread.esp0 = (unsigned long) regs;
- if (!oldset)
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = &current->saved_sigmask;
+ else
oldset = &current->blocked;
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) {
/* Whee! Actually deliver the signal. */
handle_signal(signr, &info, &ka, oldset, regs);
- return 1;
+ return;
}
no_signal:
/* Did we come from a system call? */
@@ -546,13 +499,16 @@ asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset)
regs->pc -= 2;
}
}
- return 0;
+
+ /* If there's no signal to deliver, we just restore the saved mask. */
+ if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK))
+ set_current_blocked(&current->saved_sigmask);
}
asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags)
{
- if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
- do_signal(regs, NULL);
+ if (thread_info_flags & _TIF_SIGPENDING)
+ do_signal(regs);
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
diff --git a/arch/h8300/kernel/syscalls.S b/arch/h8300/kernel/syscalls.S
index 4be2ea2fbe26..9d77e715a2ed 100644
--- a/arch/h8300/kernel/syscalls.S
+++ b/arch/h8300/kernel/syscalls.S
@@ -343,12 +343,6 @@ SYMBOL_NAME_LABEL(sys_call_table)
SYMBOL_NAME_LABEL(sys_clone)
call_sp h8300_clone
-SYMBOL_NAME_LABEL(sys_sigsuspend)
- call_sp do_sigsuspend
-
-SYMBOL_NAME_LABEL(sys_rt_sigsuspend)
- call_sp do_rt_sigsuspend
-
SYMBOL_NAME_LABEL(sys_sigreturn)
call_sp do_sigreturn
diff --git a/arch/hexagon/Kconfig b/arch/hexagon/Kconfig
index 22615dd02219..b2fdfb700f50 100644
--- a/arch/hexagon/Kconfig
+++ b/arch/hexagon/Kconfig
@@ -13,8 +13,8 @@ config HEXAGON
# select ARCH_REQUIRE_GPIOLIB
# select HAVE_CLK
# select IRQ_PER_CPU
- select HAVE_IRQ_WORK
# select GENERIC_PENDING_IRQ if SMP
+ select HAVE_IRQ_WORK
select GENERIC_ATOMIC64
select HAVE_PERF_EVENTS
select HAVE_GENERIC_HARDIRQS
@@ -26,7 +26,10 @@ config HEXAGON
select NO_IOPORT
select GENERIC_IOMAP
select GENERIC_SMP_IDLE_THREAD
- # mostly generic routines, with some accelerated ones
+ select STACKTRACE_SUPPORT
+ select KTIME_SCALAR
+ select GENERIC_CLOCKEVENTS
+ select GENERIC_CLOCKEVENTS_BROADCAST
---help---
Qualcomm Hexagon is a processor architecture designed for high
performance and low power across a wide variety of applications.
@@ -55,9 +58,6 @@ config PCI
config EARLY_PRINTK
def_bool y
-config KTIME_SCALAR
- def_bool y
-
config MMU
def_bool y
@@ -73,15 +73,6 @@ config GENERIC_CSUM
config GENERIC_IRQ_PROBE
def_bool y
-#config ZONE_DMA
-# bool
-# default y
-
-config HAS_DMA
- bool
- select HAVE_DMA_ATTRS
- default y
-
config NEED_SG_DMA_LENGTH
def_bool y
@@ -97,15 +88,6 @@ config GENERIC_FIND_NEXT_BIT
config GENERIC_HWEIGHT
def_bool y
-config GENERIC_TIME
- def_bool y
-
-config GENERIC_CLOCKEVENTS
- def_bool y
-
-config GENERIC_CLOCKEVENTS_BROADCAST
- def_bool y
-
config STACKTRACE_SUPPORT
def_bool y
select STACKTRACE
@@ -114,14 +96,11 @@ config GENERIC_BUG
def_bool y
depends on BUG
-config BUG
- def_bool y
-
menu "Machine selection"
choice
prompt "System type"
- default HEXAGON_ARCH_V2
+ default HEXAGON_COMET
config HEXAGON_COMET
bool "Comet Board"
@@ -191,11 +170,9 @@ endchoice
source "mm/Kconfig"
source "kernel/Kconfig.hz"
-source "kernel/time/Kconfig"
config GENERIC_GPIO
- bool "Generic GPIO support"
- default n
+ def_bool n
endmenu
diff --git a/arch/hexagon/Makefile b/arch/hexagon/Makefile
index e27d030846ae..d00d900b2566 100644
--- a/arch/hexagon/Makefile
+++ b/arch/hexagon/Makefile
@@ -50,8 +50,3 @@ head-y := arch/hexagon/kernel/head.o
core-y += arch/hexagon/kernel/ \
arch/hexagon/mm/ \
arch/hexagon/lib/
-
-# arch/hexagon/platform/common/
-#
-#core-$(CONFIG_HEXAGON_COMET) += arch/hexagon/platform/comet/
-#machine-$(CONFIG_HEXAGON_COMET) := comet
diff --git a/arch/hexagon/include/asm/processor.h b/arch/hexagon/include/asm/processor.h
index 20c5ddabbd8b..e8ea459002a4 100644
--- a/arch/hexagon/include/asm/processor.h
+++ b/arch/hexagon/include/asm/processor.h
@@ -59,13 +59,6 @@ struct thread_struct {
#define cpu_relax() __vmyield()
/*
- * "Unlazying all lazy status" occurs here.
- */
-static inline void prepare_to_copy(struct task_struct *tsk)
-{
-}
-
-/*
* Decides where the kernel will search for a free chunk of vm space during
* mmaps.
* See also arch_get_unmapped_area.
diff --git a/arch/hexagon/include/asm/spinlock_types.h b/arch/hexagon/include/asm/spinlock_types.h
index 5e937af1c4ad..99b5a7575c21 100644
--- a/arch/hexagon/include/asm/spinlock_types.h
+++ b/arch/hexagon/include/asm/spinlock_types.h
@@ -21,8 +21,6 @@
#ifndef _ASM_SPINLOCK_TYPES_H
#define _ASM_SPINLOCK_TYPES_H
-#include <linux/version.h>
-
#ifndef __LINUX_SPINLOCK_TYPES_H
# error "please don't include this file directly"
#endif
diff --git a/arch/hexagon/kernel/dma.c b/arch/hexagon/kernel/dma.c
index 0f2367cc5493..2b48751aa5f7 100644
--- a/arch/hexagon/kernel/dma.c
+++ b/arch/hexagon/kernel/dma.c
@@ -54,7 +54,7 @@ static struct gen_pool *coherent_pool;
/* Allocates from a pool of uncached memory that was reserved at boot time */
-void *hexagon_dma_alloc_coherent(struct device *dev, size_t size,
+static void *hexagon_dma_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_addr, gfp_t flag,
struct dma_attrs *attrs)
{
diff --git a/arch/hexagon/kernel/signal.c b/arch/hexagon/kernel/signal.c
index ecbab3457606..434866eb0f1c 100644
--- a/arch/hexagon/kernel/signal.c
+++ b/arch/hexagon/kernel/signal.c
@@ -272,6 +272,7 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
+ tracehook_notify_resume(regs);
if (current->replacement_session_keyring)
key_replace_session_keyring();
}
@@ -293,6 +294,9 @@ asmlinkage int sys_rt_sigreturn(void)
struct rt_sigframe __user *frame;
sigset_t blocked;
+ /* Always make any pending restarted system calls return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
frame = (struct rt_sigframe __user *)pt_psp(regs);
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
diff --git a/arch/hexagon/kernel/time.c b/arch/hexagon/kernel/time.c
index 5d9b33b67935..36ba64185711 100644
--- a/arch/hexagon/kernel/time.c
+++ b/arch/hexagon/kernel/time.c
@@ -201,12 +201,10 @@ void __init time_init_deferred(void)
resource = rtos_timer_device.resource;
/* ioremap here means this has to run later, after paging init */
- rtos_timer = ioremap(resource->start, resource->end
- - resource->start + 1);
+ rtos_timer = ioremap(resource->start, resource_size(resource));
if (!rtos_timer) {
- release_mem_region(resource->start, resource->end
- - resource->start + 1);
+ release_mem_region(resource->start, resource_size(resource));
}
clocksource_register_khz(&hexagon_clocksource, pcycle_freq_mhz * 1000);
diff --git a/arch/hexagon/mm/vm_fault.c b/arch/hexagon/mm/vm_fault.c
index c10b76ff9d65..06695cc4fe58 100644
--- a/arch/hexagon/mm/vm_fault.c
+++ b/arch/hexagon/mm/vm_fault.c
@@ -53,6 +53,8 @@ void do_page_fault(unsigned long address, long cause, struct pt_regs *regs)
int si_code = SEGV_MAPERR;
int fault;
const struct exception_table_entry *fixup;
+ unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
+ (cause > 0 ? FAULT_FLAG_WRITE : 0);
/*
* If we're in an interrupt or have no user context,
@@ -63,6 +65,7 @@ void do_page_fault(unsigned long address, long cause, struct pt_regs *regs)
local_irq_enable();
+retry:
down_read(&mm->mmap_sem);
vma = find_vma(mm, address);
if (!vma)
@@ -96,14 +99,23 @@ good_area:
break;
}
- fault = handle_mm_fault(mm, vma, address, (cause > 0));
+ fault = handle_mm_fault(mm, vma, address, flags);
+
+ if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
+ return;
/* The most common case -- we are done. */
if (likely(!(fault & VM_FAULT_ERROR))) {
- if (fault & VM_FAULT_MAJOR)
- current->maj_flt++;
- else
- current->min_flt++;
+ if (flags & FAULT_FLAG_ALLOW_RETRY) {
+ if (fault & VM_FAULT_MAJOR)
+ current->maj_flt++;
+ else
+ current->min_flt++;
+ if (fault & VM_FAULT_RETRY) {
+ flags &= ~FAULT_FLAG_ALLOW_RETRY;
+ goto retry;
+ }
+ }
up_read(&mm->mmap_sem);
return;
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index ba667b60f32d..8186ec5ea151 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -37,6 +37,8 @@ config IA64
select ARCH_INIT_TASK
select ARCH_TASK_STRUCT_ALLOCATOR
select ARCH_THREAD_INFO_ALLOCATOR
+ select ARCH_CLOCKSOURCE_DATA
+ select GENERIC_TIME_VSYSCALL
default y
help
The Itanium Processor Family is Intel's 64-bit successor to
@@ -92,10 +94,6 @@ config GENERIC_CALIBRATE_DELAY
bool
default y
-config GENERIC_TIME_VSYSCALL
- bool
- default y
-
config HAVE_SETUP_PER_CPU_AREA
def_bool y
@@ -110,9 +108,6 @@ config EFI
bool
default y
-config ARCH_CLOCKSOURCE_DATA
- def_bool y
-
config SCHED_OMIT_FRAME_POINTER
bool
default y
diff --git a/arch/ia64/include/asm/Kbuild b/arch/ia64/include/asm/Kbuild
index 241d1c53ba69..d4eb9383f5f6 100644
--- a/arch/ia64/include/asm/Kbuild
+++ b/arch/ia64/include/asm/Kbuild
@@ -1,6 +1,7 @@
include include/asm-generic/Kbuild.asm
header-y += break.h
+header-y += cmpxchg.h
header-y += fpu.h
header-y += gcc_intrin.h
header-y += ia64regs.h
diff --git a/arch/ia64/include/asm/gpio.h b/arch/ia64/include/asm/gpio.h
index 590a20debc4e..b3799d88ffcf 100644
--- a/arch/ia64/include/asm/gpio.h
+++ b/arch/ia64/include/asm/gpio.h
@@ -1,55 +1,4 @@
-/*
- * Generic GPIO API implementation for IA-64.
- *
- * A stright copy of that for PowerPC which was:
- *
- * Copyright (c) 2007-2008 MontaVista Software, Inc.
- *
- * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef _ASM_IA64_GPIO_H
-#define _ASM_IA64_GPIO_H
-
-#include <linux/errno.h>
-#include <asm-generic/gpio.h>
-
-#ifdef CONFIG_GPIOLIB
-
-/*
- * We don't (yet) implement inlined/rapid versions for on-chip gpios.
- * Just call gpiolib.
- */
-static inline int gpio_get_value(unsigned int gpio)
-{
- return __gpio_get_value(gpio);
-}
-
-static inline void gpio_set_value(unsigned int gpio, int value)
-{
- __gpio_set_value(gpio, value);
-}
-
-static inline int gpio_cansleep(unsigned int gpio)
-{
- return __gpio_cansleep(gpio);
-}
-
-static inline int gpio_to_irq(unsigned int gpio)
-{
- return __gpio_to_irq(gpio);
-}
-
-static inline int irq_to_gpio(unsigned int irq)
-{
- return -EINVAL;
-}
-
-#endif /* CONFIG_GPIOLIB */
-
-#endif /* _ASM_IA64_GPIO_H */
+#ifndef __LINUX_GPIO_H
+#warning Include linux/gpio.h instead of asm/gpio.h
+#include <linux/gpio.h>
+#endif
diff --git a/arch/ia64/include/asm/processor.h b/arch/ia64/include/asm/processor.h
index f92f67aba618..832dd3789e9d 100644
--- a/arch/ia64/include/asm/processor.h
+++ b/arch/ia64/include/asm/processor.h
@@ -34,8 +34,7 @@
* each (assuming 8KB page size), for a total of 8TB of user virtual
* address space.
*/
-#define TASK_SIZE_OF(tsk) ((tsk)->thread.task_size)
-#define TASK_SIZE TASK_SIZE_OF(current)
+#define TASK_SIZE DEFAULT_TASK_SIZE
/*
* This decides where the kernel will search for a free chunk of vm
@@ -280,7 +279,6 @@ struct thread_struct {
__u8 pad[3];
__u64 ksp; /* kernel stack pointer */
__u64 map_base; /* base address for get_unmapped_area() */
- __u64 task_size; /* limit for task size */
__u64 rbs_bot; /* the base address for the RBS */
int last_fph_cpu; /* CPU that may hold the contents of f32-f127 */
@@ -303,7 +301,6 @@ struct thread_struct {
.ksp = 0, \
.map_base = DEFAULT_MAP_BASE, \
.rbs_bot = STACK_TOP - DEFAULT_USER_STACK_SIZE, \
- .task_size = DEFAULT_TASK_SIZE, \
.last_fph_cpu = -1, \
INIT_THREAD_PM \
.dbr = {0, }, \
@@ -343,9 +340,6 @@ struct task_struct;
*/
#define release_thread(dead_task)
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk) do { } while (0)
-
/*
* This is the mechanism for creating a new kernel thread.
*
diff --git a/arch/ia64/include/asm/topology.h b/arch/ia64/include/asm/topology.h
index 09f646753d1a..a2496e449b75 100644
--- a/arch/ia64/include/asm/topology.h
+++ b/arch/ia64/include/asm/topology.h
@@ -70,31 +70,6 @@ void build_cpu_to_node_map(void);
.nr_balance_failed = 0, \
}
-/* sched_domains SD_NODE_INIT for IA64 NUMA machines */
-#define SD_NODE_INIT (struct sched_domain) { \
- .parent = NULL, \
- .child = NULL, \
- .groups = NULL, \
- .min_interval = 8, \
- .max_interval = 8*(min(num_online_cpus(), 32U)), \
- .busy_factor = 64, \
- .imbalance_pct = 125, \
- .cache_nice_tries = 2, \
- .busy_idx = 3, \
- .idle_idx = 2, \
- .newidle_idx = 0, \
- .wake_idx = 0, \
- .forkexec_idx = 0, \
- .flags = SD_LOAD_BALANCE \
- | SD_BALANCE_NEWIDLE \
- | SD_BALANCE_EXEC \
- | SD_BALANCE_FORK \
- | SD_SERIALIZE, \
- .last_balance = jiffies, \
- .balance_interval = 64, \
- .nr_balance_failed = 0, \
-}
-
#endif /* CONFIG_NUMA */
#ifdef CONFIG_SMP
diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S
index cc26edac0ec6..e662f178b990 100644
--- a/arch/ia64/kernel/fsys.S
+++ b/arch/ia64/kernel/fsys.S
@@ -372,175 +372,6 @@ ENTRY(fsys_clock_gettime)
END(fsys_clock_gettime)
/*
- * long fsys_rt_sigprocmask (int how, sigset_t *set, sigset_t *oset, size_t sigsetsize).
- */
-#if _NSIG_WORDS != 1
-# error Sorry, fsys_rt_sigprocmask() needs to be updated for _NSIG_WORDS != 1.
-#endif
-ENTRY(fsys_rt_sigprocmask)
- .prologue
- .altrp b6
- .body
-
- add r2=IA64_TASK_BLOCKED_OFFSET,r16
- add r9=TI_FLAGS+IA64_TASK_SIZE,r16
- cmp4.ltu p6,p0=SIG_SETMASK,r32
-
- cmp.ne p15,p0=r0,r34 // oset != NULL?
- tnat.nz p8,p0=r34
- add r31=IA64_TASK_SIGHAND_OFFSET,r16
- ;;
- ld8 r3=[r2] // read/prefetch current->blocked
- ld4 r9=[r9]
- tnat.nz.or p6,p0=r35
-
- cmp.ne.or p6,p0=_NSIG_WORDS*8,r35
- tnat.nz.or p6,p0=r32
-(p6) br.spnt.few .fail_einval // fail with EINVAL
- ;;
-#ifdef CONFIG_SMP
- ld8 r31=[r31] // r31 <- current->sighand
-#endif
- and r9=TIF_ALLWORK_MASK,r9
- tnat.nz.or p8,p0=r33
- ;;
- cmp.ne p7,p0=0,r9
- cmp.eq p6,p0=r0,r33 // set == NULL?
- add r31=IA64_SIGHAND_SIGLOCK_OFFSET,r31 // r31 <- current->sighand->siglock
-(p8) br.spnt.few .fail_efault // fail with EFAULT
-(p7) br.spnt.many fsys_fallback_syscall // got pending kernel work...
-(p6) br.dpnt.many .store_mask // -> short-circuit to just reading the signal mask
-
- /* Argh, we actually have to do some work and _update_ the signal mask: */
-
-EX(.fail_efault, probe.r.fault r33, 3) // verify user has read-access to *set
-EX(.fail_efault, ld8 r14=[r33]) // r14 <- *set
- mov r17=(1 << (SIGKILL - 1)) | (1 << (SIGSTOP - 1))
- ;;
-
- RSM_PSR_I(p0, r18, r19) // mask interrupt delivery
- andcm r14=r14,r17 // filter out SIGKILL & SIGSTOP
- mov r8=EINVAL // default to EINVAL
-
-#ifdef CONFIG_SMP
- // __ticket_spin_trylock(r31)
- ld4 r17=[r31]
- ;;
- mov.m ar.ccv=r17
- extr.u r9=r17,17,15
- adds r19=1,r17
- extr.u r18=r17,0,15
- ;;
- cmp.eq p6,p7=r9,r18
- ;;
-(p6) cmpxchg4.acq r9=[r31],r19,ar.ccv
-(p6) dep.z r20=r19,1,15 // next serving ticket for unlock
-(p7) br.cond.spnt.many .lock_contention
- ;;
- cmp4.eq p0,p7=r9,r17
- adds r31=2,r31
-(p7) br.cond.spnt.many .lock_contention
- ld8 r3=[r2] // re-read current->blocked now that we hold the lock
- ;;
-#else
- ld8 r3=[r2] // re-read current->blocked now that we hold the lock
-#endif
- add r18=IA64_TASK_PENDING_OFFSET+IA64_SIGPENDING_SIGNAL_OFFSET,r16
- add r19=IA64_TASK_SIGNAL_OFFSET,r16
- cmp4.eq p6,p0=SIG_BLOCK,r32
- ;;
- ld8 r19=[r19] // r19 <- current->signal
- cmp4.eq p7,p0=SIG_UNBLOCK,r32
- cmp4.eq p8,p0=SIG_SETMASK,r32
- ;;
- ld8 r18=[r18] // r18 <- current->pending.signal
- .pred.rel.mutex p6,p7,p8
-(p6) or r14=r3,r14 // SIG_BLOCK
-(p7) andcm r14=r3,r14 // SIG_UNBLOCK
-
-(p8) mov r14=r14 // SIG_SETMASK
-(p6) mov r8=0 // clear error code
- // recalc_sigpending()
- add r17=IA64_SIGNAL_GROUP_STOP_COUNT_OFFSET,r19
-
- add r19=IA64_SIGNAL_SHARED_PENDING_OFFSET+IA64_SIGPENDING_SIGNAL_OFFSET,r19
- ;;
- ld4 r17=[r17] // r17 <- current->signal->group_stop_count
-(p7) mov r8=0 // clear error code
-
- ld8 r19=[r19] // r19 <- current->signal->shared_pending
- ;;
- cmp4.gt p6,p7=r17,r0 // p6/p7 <- (current->signal->group_stop_count > 0)?
-(p8) mov r8=0 // clear error code
-
- or r18=r18,r19 // r18 <- current->pending | current->signal->shared_pending
- ;;
- // r18 <- (current->pending | current->signal->shared_pending) & ~current->blocked:
- andcm r18=r18,r14
- add r9=TI_FLAGS+IA64_TASK_SIZE,r16
- ;;
-
-(p7) cmp.ne.or.andcm p6,p7=r18,r0 // p6/p7 <- signal pending
- mov r19=0 // i must not leak kernel bits...
-(p6) br.cond.dpnt.many .sig_pending
- ;;
-
-1: ld4 r17=[r9] // r17 <- current->thread_info->flags
- ;;
- mov ar.ccv=r17
- and r18=~_TIF_SIGPENDING,r17 // r18 <- r17 & ~(1 << TIF_SIGPENDING)
- ;;
-
- st8 [r2]=r14 // update current->blocked with new mask
- cmpxchg4.acq r8=[r9],r18,ar.ccv // current->thread_info->flags <- r18
- ;;
- cmp.ne p6,p0=r17,r8 // update failed?
-(p6) br.cond.spnt.few 1b // yes -> retry
-
-#ifdef CONFIG_SMP
- // __ticket_spin_unlock(r31)
- st2.rel [r31]=r20
- mov r20=0 // i must not leak kernel bits...
-#endif
- SSM_PSR_I(p0, p9, r31)
- ;;
-
- srlz.d // ensure psr.i is set again
- mov r18=0 // i must not leak kernel bits...
-
-.store_mask:
-EX(.fail_efault, (p15) probe.w.fault r34, 3) // verify user has write-access to *oset
-EX(.fail_efault, (p15) st8 [r34]=r3)
- mov r2=0 // i must not leak kernel bits...
- mov r3=0 // i must not leak kernel bits...
- mov r8=0 // return 0
- mov r9=0 // i must not leak kernel bits...
- mov r14=0 // i must not leak kernel bits...
- mov r17=0 // i must not leak kernel bits...
- mov r31=0 // i must not leak kernel bits...
- FSYS_RETURN
-
-.sig_pending:
-#ifdef CONFIG_SMP
- // __ticket_spin_unlock(r31)
- st2.rel [r31]=r20 // release the lock
-#endif
- SSM_PSR_I(p0, p9, r17)
- ;;
- srlz.d
- br.sptk.many fsys_fallback_syscall // with signal pending, do the heavy-weight syscall
-
-#ifdef CONFIG_SMP
-.lock_contention:
- /* Rather than spinning here, fall back on doing a heavy-weight syscall. */
- SSM_PSR_I(p0, p9, r17)
- ;;
- srlz.d
- br.sptk.many fsys_fallback_syscall
-#endif
-END(fsys_rt_sigprocmask)
-
-/*
* fsys_getcpu doesn't use the third parameter in this implementation. It reads
* current_thread_info()->cpu and corresponding node in cpu_to_node_map.
*/
@@ -559,11 +390,15 @@ ENTRY(fsys_getcpu)
;;
tnat.nz p7,p0 = r33 // I guard against NaT argument
(p7) br.cond.spnt.few .fail_einval // B
+ ;;
+ cmp.ne p6,p0=r32,r0
+ cmp.ne p7,p0=r33,r0
+ ;;
#ifdef CONFIG_NUMA
movl r17=cpu_to_node_map
;;
-EX(.fail_efault, probe.w.fault r32, 3) // M This takes 5 cycles
-EX(.fail_efault, probe.w.fault r33, 3) // M This takes 5 cycles
+EX(.fail_efault, (p6) probe.w.fault r32, 3) // M This takes 5 cycles
+EX(.fail_efault, (p7) probe.w.fault r33, 3) // M This takes 5 cycles
shladd r18=r3,1,r17
;;
ld2 r20=[r18] // r20 = cpu_to_node_map[cpu]
@@ -573,20 +408,20 @@ EX(.fail_efault, probe.w.fault r33, 3) // M This takes 5 cycles
(p8) br.spnt.many fsys_fallback_syscall
;;
;;
-EX(.fail_efault, st4 [r32] = r3)
-EX(.fail_efault, st2 [r33] = r20)
+EX(.fail_efault, (p6) st4 [r32] = r3)
+EX(.fail_efault, (p7) st2 [r33] = r20)
mov r8=0
;;
#else
-EX(.fail_efault, probe.w.fault r32, 3) // M This takes 5 cycles
-EX(.fail_efault, probe.w.fault r33, 3) // M This takes 5 cycles
+EX(.fail_efault, (p6) probe.w.fault r32, 3) // M This takes 5 cycles
+EX(.fail_efault, (p7) probe.w.fault r33, 3) // M This takes 5 cycles
and r2 = TIF_ALLWORK_MASK,r2
;;
cmp.ne p8,p0=0,r2
(p8) br.spnt.many fsys_fallback_syscall
;;
-EX(.fail_efault, st4 [r32] = r3)
-EX(.fail_efault, st2 [r33] = r0)
+EX(.fail_efault, (p6) st4 [r32] = r3)
+EX(.fail_efault, (p7) st2 [r33] = r0)
mov r8=0
;;
#endif
@@ -916,7 +751,7 @@ paravirt_fsyscall_table:
data8 0 // sigaltstack
data8 0 // rt_sigaction
data8 0 // rt_sigpending
- data8 fsys_rt_sigprocmask // rt_sigprocmask
+ data8 0 // rt_sigprocmask
data8 0 // rt_sigqueueinfo // 1180
data8 0 // rt_sigreturn
data8 0 // rt_sigsuspend
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
index 7bdafc8788bd..7523501d3bc0 100644
--- a/arch/ia64/kernel/signal.c
+++ b/arch/ia64/kernel/signal.c
@@ -201,13 +201,7 @@ ia64_rt_sigreturn (struct sigscratch *scr)
goto give_sigsegv;
sigdelsetmask(&set, ~_BLOCKABLE);
-
- spin_lock_irq(&current->sighand->siglock);
- {
- current->blocked = set;
- recalc_sigpending();
- }
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(sc, scr))
goto give_sigsegv;
@@ -427,12 +421,7 @@ handle_signal (unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigse
if (!setup_frame(sig, ka, info, oldset, scr))
return 0;
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(&current->blocked, sig);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ block_sigmask(ka, sig);
/*
* Let tracing know that we've done the handler setup.
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
index ef80a6546ff2..b638d5bfa14d 100644
--- a/arch/m32r/Kconfig
+++ b/arch/m32r/Kconfig
@@ -11,6 +11,7 @@ config M32R
select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW
select GENERIC_ATOMIC64
+ select ARCH_USES_GETTIMEOFFSET
config SBUS
bool
@@ -33,9 +34,6 @@ config HZ
int
default 100
-config ARCH_USES_GETTIMEOFFSET
- def_bool y
-
source "init/Kconfig"
source "kernel/Kconfig.freezer"
diff --git a/arch/m32r/include/asm/processor.h b/arch/m32r/include/asm/processor.h
index e1f46d757460..da17253b5735 100644
--- a/arch/m32r/include/asm/processor.h
+++ b/arch/m32r/include/asm/processor.h
@@ -118,8 +118,6 @@ struct mm_struct;
/* Free all resources held by a thread. */
extern void release_thread(struct task_struct *);
-#define prepare_to_copy(tsk) do { } while (0)
-
/*
* create a kernel thread without removing it from tasklists
*/
diff --git a/arch/m32r/include/asm/signal.h b/arch/m32r/include/asm/signal.h
index b2eeb0de1c8d..ea5f95e4079e 100644
--- a/arch/m32r/include/asm/signal.h
+++ b/arch/m32r/include/asm/signal.h
@@ -110,13 +110,6 @@ typedef unsigned long sigset_t;
#include <asm-generic/signal-defs.h>
#ifdef __KERNEL__
-struct old_sigaction {
- __sighandler_t sa_handler;
- old_sigset_t sa_mask;
- unsigned long sa_flags;
- __sigrestore_t sa_restorer;
-};
-
struct sigaction {
__sighandler_t sa_handler;
unsigned long sa_flags;
diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c
index a08697f0886d..f54d96993ea1 100644
--- a/arch/m32r/kernel/signal.c
+++ b/arch/m32r/kernel/signal.c
@@ -112,10 +112,7 @@ sys_rt_sigreturn(unsigned long r0, unsigned long r1,
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &result))
goto badframe;
@@ -300,12 +297,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
if (setup_rt_frame(sig, ka, info, oldset, regs))
return -EFAULT;
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(&current->blocked,sig);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ block_sigmask(ka, sig);
return 0;
}
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index d318c606c888..cac5b6be572a 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -8,6 +8,7 @@ config M68K
select ARCH_HAVE_NMI_SAFE_CMPXCHG if RMW_INSNS
select GENERIC_CPU_DEVICES
select FPU if MMU
+ select ARCH_USES_GETTIMEOFFSET if MMU && !COLDFIRE
config RWSEM_GENERIC_SPINLOCK
bool
@@ -22,9 +23,6 @@ config ARCH_HAS_ILOG2_U32
config ARCH_HAS_ILOG2_U64
bool
-config GENERIC_CLOCKEVENTS
- bool
-
config GENERIC_GPIO
bool
@@ -43,9 +41,6 @@ config TIME_LOW_RES
bool
default y
-config ARCH_USES_GETTIMEOFFSET
- def_bool MMU && !COLDFIRE
-
config NO_IOPORT
def_bool y
@@ -111,10 +106,6 @@ if COLDFIRE
source "kernel/Kconfig.preempt"
endif
-if !MMU || COLDFIRE
-source "kernel/time/Kconfig"
-endif
-
source "mm/Kconfig"
endmenu
diff --git a/arch/m68k/Kconfig.cpu b/arch/m68k/Kconfig.cpu
index 8a9c767125a4..2b53254ad994 100644
--- a/arch/m68k/Kconfig.cpu
+++ b/arch/m68k/Kconfig.cpu
@@ -7,7 +7,7 @@ choice
help
The Freescale (was Motorola) M68K family of processors implements
the full 68000 processor instruction set.
- The Freescale ColdFire family of processors is a modern derivitive
+ The Freescale ColdFire family of processors is a modern derivative
of the 68000 processor family. They are mainly targeted at embedded
applications, and are all System-On-Chip (SOC) devices, as opposed
to stand alone CPUs. They implement a subset of the original 68000
@@ -24,6 +24,7 @@ config COLDFIRE
bool "Coldfire CPU family support"
select GENERIC_GPIO
select ARCH_REQUIRE_GPIOLIB
+ select ARCH_HAVE_CUSTOM_GPIO_H
select CPU_HAS_NO_BITFIELDS
select CPU_HAS_NO_MULDIV64
select GENERIC_CSUM
diff --git a/arch/m68k/include/asm/processor.h b/arch/m68k/include/asm/processor.h
index 46460fa15d5c..f17c42aff7ff 100644
--- a/arch/m68k/include/asm/processor.h
+++ b/arch/m68k/include/asm/processor.h
@@ -153,9 +153,6 @@ static inline void release_thread(struct task_struct *dead_task)
{
}
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk) do { } while (0)
-
extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
/*
diff --git a/arch/m68k/include/asm/thread_info.h b/arch/m68k/include/asm/thread_info.h
index e8665e6f9464..126131f94a2c 100644
--- a/arch/m68k/include/asm/thread_info.h
+++ b/arch/m68k/include/asm/thread_info.h
@@ -71,6 +71,7 @@ static inline struct thread_info *current_thread_info(void)
* bits 0-7 are tested at every exception exit
* bits 8-15 are also tested at syscall exit
*/
+#define TIF_NOTIFY_RESUME 5 /* callback before returning to user */
#define TIF_SIGPENDING 6 /* signal pending */
#define TIF_NEED_RESCHED 7 /* rescheduling necessary */
#define TIF_DELAYED_TRACE 14 /* single step a syscall */
diff --git a/arch/m68k/kernel/entry_mm.S b/arch/m68k/kernel/entry_mm.S
index 675a854966a6..f29e73ca9dbb 100644
--- a/arch/m68k/kernel/entry_mm.S
+++ b/arch/m68k/kernel/entry_mm.S
@@ -148,7 +148,7 @@ syscall_exit_work:
jcs do_trace_exit
jmi do_delayed_trace
lslw #8,%d0
- jmi do_signal_return
+ jne do_signal_return
pea resume_userspace
jra schedule
@@ -172,7 +172,7 @@ exit_work:
| save top of frame
movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0)
lslb #1,%d0
- jmi do_signal_return
+ jne do_signal_return
pea resume_userspace
jra schedule
@@ -182,7 +182,7 @@ do_signal_return:
subql #4,%sp | dummy return address
SAVE_SWITCH_STACK
pea %sp@(SWITCH_STACK_SIZE)
- bsrl do_signal
+ bsrl do_notify_resume
addql #4,%sp
RESTORE_SWITCH_STACK
addql #4,%sp
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c
index 1747c7030a33..d9f3d1900eed 100644
--- a/arch/m68k/kernel/signal.c
+++ b/arch/m68k/kernel/signal.c
@@ -43,6 +43,7 @@
#include <linux/tty.h>
#include <linux/binfmts.h>
#include <linux/module.h>
+#include <linux/tracehook.h>
#include <asm/setup.h>
#include <asm/uaccess.h>
@@ -230,18 +231,9 @@ static inline void push_cache(unsigned long vaddr)
asmlinkage int
sys_sigsuspend(int unused0, int unused1, old_sigset_t mask)
{
- mask &= _BLOCKABLE;
- spin_lock_irq(&current->sighand->siglock);
- current->saved_sigmask = current->blocked;
- siginitset(&current->blocked, mask);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_restore_sigmask();
-
- return -ERESTARTNOHAND;
+ sigset_t blocked;
+ siginitset(&blocked, mask);
+ return sigsuspend(&blocked);
}
asmlinkage int
@@ -804,8 +796,7 @@ asmlinkage int do_sigreturn(unsigned long __unused)
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- current->blocked = set;
- recalc_sigpending();
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->sc, frame + 1))
goto badframe;
@@ -830,8 +821,7 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused)
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- current->blocked = set;
- recalc_sigpending();
+ set_current_blocked(&set);
if (rt_restore_ucontext(regs, sw, &frame->uc))
goto badframe;
@@ -1150,10 +1140,7 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
if (err)
return;
- sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(&current->blocked,sig);
- recalc_sigpending();
+ block_sigmask(ka, sig);
if (test_thread_flag(TIF_DELAYED_TRACE)) {
regs->sr &= ~0x8000;
@@ -1168,7 +1155,7 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
*/
-asmlinkage void do_signal(struct pt_regs *regs)
+static void do_signal(struct pt_regs *regs)
{
siginfo_t info;
struct k_sigaction ka;
@@ -1200,3 +1187,15 @@ asmlinkage void do_signal(struct pt_regs *regs)
sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
}
}
+
+void do_notify_resume(struct pt_regs *regs)
+{
+ if (test_thread_flag(TIF_SIGPENDING))
+ do_signal(regs);
+
+ if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) {
+ tracehook_notify_resume(regs);
+ if (current->replacement_session_keyring)
+ key_replace_session_keyring();
+ }
+}
diff --git a/arch/m68k/platform/68328/entry.S b/arch/m68k/platform/68328/entry.S
index 5c39b80ed7de..7f91c2fde509 100644
--- a/arch/m68k/platform/68328/entry.S
+++ b/arch/m68k/platform/68328/entry.S
@@ -119,7 +119,7 @@ Lsignal_return:
subql #4,%sp /* dummy return address*/
SAVE_SWITCH_STACK
pea %sp@(SWITCH_STACK_SIZE)
- bsrw do_signal
+ bsrw do_notify_resume
addql #4,%sp
RESTORE_SWITCH_STACK
addql #4,%sp
diff --git a/arch/m68k/platform/68360/entry.S b/arch/m68k/platform/68360/entry.S
index aa47d1d49929..904fd9a4af4e 100644
--- a/arch/m68k/platform/68360/entry.S
+++ b/arch/m68k/platform/68360/entry.S
@@ -115,7 +115,7 @@ Lsignal_return:
subql #4,%sp /* dummy return address*/
SAVE_SWITCH_STACK
pea %sp@(SWITCH_STACK_SIZE)
- bsrw do_signal
+ bsrw do_notify_resume
addql #4,%sp
RESTORE_SWITCH_STACK
addql #4,%sp
diff --git a/arch/m68k/platform/coldfire/entry.S b/arch/m68k/platform/coldfire/entry.S
index 281e38c2b6c7..881ab8e379d4 100644
--- a/arch/m68k/platform/coldfire/entry.S
+++ b/arch/m68k/platform/coldfire/entry.S
@@ -152,7 +152,7 @@ Lsignal_return:
subql #4,%sp /* dummy return address */
SAVE_SWITCH_STACK
pea %sp@(SWITCH_STACK_SIZE)
- jsr do_signal
+ jsr do_notify_resume
addql #4,%sp
RESTORE_SWITCH_STACK
addql #4,%sp
diff --git a/arch/m68k/platform/coldfire/m532x.c b/arch/m68k/platform/coldfire/m532x.c
index 8e9476d59a65..5394223639f8 100644
--- a/arch/m68k/platform/coldfire/m532x.c
+++ b/arch/m68k/platform/coldfire/m532x.c
@@ -7,7 +7,7 @@
* Copyright (C) 2000, Lineo (www.lineo.com)
* Yaroslav Vinogradov yaroslav.vinogradov@freescale.com
* Copyright Freescale Semiconductor, Inc 2006
- * Copyright (c) 2006, emlix, Sebastian Hess <sh@emlix.com>
+ * Copyright (c) 2006, emlix, Sebastian Hess <shess@hessware.de>
*
* 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
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index ac22dc7f4cab..83460468998d 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -22,6 +22,7 @@ config MICROBLAZE
select GENERIC_PCI_IOMAP
select GENERIC_CPU_DEVICES
select GENERIC_ATOMIC64
+ select GENERIC_CLOCKEVENTS
config SWAP
def_bool n
@@ -50,12 +51,6 @@ config GENERIC_HWEIGHT
config GENERIC_CALIBRATE_DELAY
def_bool y
-config GENERIC_TIME_VSYSCALL
- def_bool n
-
-config GENERIC_CLOCKEVENTS
- def_bool y
-
config GENERIC_GPIO
def_bool y
@@ -79,8 +74,6 @@ source "arch/microblaze/platform/Kconfig.platform"
menu "Processor type and features"
-source "kernel/time/Kconfig"
-
source "kernel/Kconfig.preempt"
source "kernel/Kconfig.hz"
diff --git a/arch/microblaze/include/asm/gpio.h b/arch/microblaze/include/asm/gpio.h
index 2b2c18be71c6..b3799d88ffcf 100644
--- a/arch/microblaze/include/asm/gpio.h
+++ b/arch/microblaze/include/asm/gpio.h
@@ -1,53 +1,4 @@
-/*
- * Generic GPIO API implementation for PowerPC.
- *
- * Copyright (c) 2007-2008 MontaVista Software, Inc.
- *
- * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef _ASM_MICROBLAZE_GPIO_H
-#define _ASM_MICROBLAZE_GPIO_H
-
-#include <linux/errno.h>
-#include <asm-generic/gpio.h>
-
-#ifdef CONFIG_GPIOLIB
-
-/*
- * We don't (yet) implement inlined/rapid versions for on-chip gpios.
- * Just call gpiolib.
- */
-static inline int gpio_get_value(unsigned int gpio)
-{
- return __gpio_get_value(gpio);
-}
-
-static inline void gpio_set_value(unsigned int gpio, int value)
-{
- __gpio_set_value(gpio, value);
-}
-
-static inline int gpio_cansleep(unsigned int gpio)
-{
- return __gpio_cansleep(gpio);
-}
-
-static inline int gpio_to_irq(unsigned int gpio)
-{
- return __gpio_to_irq(gpio);
-}
-
-static inline int irq_to_gpio(unsigned int irq)
-{
- return -EINVAL;
-}
-
-#endif /* CONFIG_GPIOLIB */
-
-#endif /* _ASM_MICROBLAZE_GPIO_H */
+#ifndef __LINUX_GPIO_H
+#warning Include linux/gpio.h instead of asm/gpio.h
+#include <linux/gpio.h>
+#endif
diff --git a/arch/microblaze/include/asm/processor.h b/arch/microblaze/include/asm/processor.h
index bffb54527299..af2bb9652392 100644
--- a/arch/microblaze/include/asm/processor.h
+++ b/arch/microblaze/include/asm/processor.h
@@ -23,7 +23,6 @@ extern const struct seq_operations cpuinfo_op;
# define cpu_relax() barrier()
# define cpu_sleep() do {} while (0)
-# define prepare_to_copy(tsk) do {} while (0)
#define task_pt_regs(tsk) \
(((struct pt_regs *)(THREAD_SIZE + task_stack_page(tsk))) - 1)
diff --git a/arch/microblaze/kernel/entry-nommu.S b/arch/microblaze/kernel/entry-nommu.S
index 34b526f59b43..75c3ea1f48a1 100644
--- a/arch/microblaze/kernel/entry-nommu.S
+++ b/arch/microblaze/kernel/entry-nommu.S
@@ -132,11 +132,10 @@ ret_from_intr:
beqi r11, 1f
bralid r15, schedule
nop
-1: andi r11, r19, _TIF_SIGPENDING
+1: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
beqid r11, no_intr_resched
addk r5, r1, r0
- addk r7, r0, r0
- bralid r15, do_signal
+ bralid r15, do_notify_resume
addk r6, r0, r0
no_intr_resched:
@@ -292,8 +291,8 @@ ENTRY(_user_exception)
/*
* Debug traps are like a system call, but entered via brki r14, 0x60
- * All we need to do is send the SIGTRAP signal to current, ptrace and do_signal
- * will handle the rest
+ * All we need to do is send the SIGTRAP signal to current, ptrace and
+ * do_notify_resume will handle the rest
*/
ENTRY(_debug_exception)
swi r1, r0, PER_CPU(ENTRY_SP) /* save the current sp */
@@ -482,12 +481,11 @@ work_pending:
beqi r11, 1f
bralid r15, schedule
nop
-1: andi r11, r19, _TIF_SIGPENDING
+1: andi r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
beqi r11, no_work_pending
addk r5, r1, r0
- addik r7, r0, 1
- bralid r15, do_signal
- addk r6, r0, r0
+ bralid r15, do_notify_resume
+ addik r6, r0, 1
bri no_work_pending
ENTRY(ret_to_user)
@@ -569,10 +567,6 @@ sys_rt_sigreturn_wrapper:
brid sys_rt_sigreturn
addk r5, r1, r0
-sys_rt_sigsuspend_wrapper:
- brid sys_rt_sigsuspend
- addk r7, r1, r0
-
/* Interrupt vector table */
.section .init.ivt, "ax"
.org 0x0
diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S
index 66e34a3bfe1b..daff9e5e4a1f 100644
--- a/arch/microblaze/kernel/entry.S
+++ b/arch/microblaze/kernel/entry.S
@@ -430,13 +430,12 @@ C_ENTRY(ret_from_trap):
5: /* get thread info from current task*/
lwi r11, CURRENT_TASK, TS_THREAD_INFO;
lwi r11, r11, TI_FLAGS; /* get flags in thread info */
- andi r11, r11, _TIF_SIGPENDING;
+ andi r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
beqi r11, 1f; /* Signals to handle, handle them */
addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */
- addi r7, r0, 1; /* Arg 3: int in_syscall */
- bralid r15, do_signal; /* Handle any signals */
- add r6, r0, r0; /* Arg 2: sigset_t *oldset */
+ bralid r15, do_notify_resume; /* Handle any signals */
+ addi r6, r0, 1; /* Arg 2: int in_syscall */
/* Finally, return to user state. */
1: set_bip; /* Ints masked for state restore */
@@ -622,7 +621,7 @@ C_ENTRY(ret_from_exc):
/* Maybe handle a signal */
5: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
lwi r11, r11, TI_FLAGS; /* get flags in thread info */
- andi r11, r11, _TIF_SIGPENDING;
+ andi r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
beqi r11, 1f; /* Signals to handle, handle them */
/*
@@ -635,11 +634,10 @@ C_ENTRY(ret_from_exc):
* traps), but signal handlers may want to examine or change the
* complete register state. Here we save anything not saved by
* the normal entry sequence, so that it may be safely restored
- * (in a possibly modified form) after do_signal returns. */
+ * (in a possibly modified form) after do_notify_resume returns. */
addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */
- addi r7, r0, 0; /* Arg 3: int in_syscall */
- bralid r15, do_signal; /* Handle any signals */
- add r6, r0, r0; /* Arg 2: sigset_t *oldset */
+ bralid r15, do_notify_resume; /* Handle any signals */
+ addi r6, r0, 0; /* Arg 2: int in_syscall */
/* Finally, return to user state. */
1: set_bip; /* Ints masked for state restore */
@@ -732,13 +730,12 @@ ret_from_irq:
/* Maybe handle a signal */
5: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* MS: get thread info */
lwi r11, r11, TI_FLAGS; /* get flags in thread info */
- andi r11, r11, _TIF_SIGPENDING;
+ andi r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
beqid r11, no_intr_resched
/* Handle a signal return; Pending signals should be in r18. */
- addi r7, r0, 0; /* Arg 3: int in_syscall */
addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */
- bralid r15, do_signal; /* Handle any signals */
- add r6, r0, r0; /* Arg 2: sigset_t *oldset */
+ bralid r15, do_notify_resume; /* Handle any signals */
+ addi r6, r0, 0; /* Arg 2: int in_syscall */
/* Finally, return to user state. */
no_intr_resched:
@@ -869,13 +866,12 @@ dbtrap_call: /* Return point for kernel/user entry + 8 because of rtsd r15, 8 */
/* Maybe handle a signal */
5: lwi r11, CURRENT_TASK, TS_THREAD_INFO; /* get thread info */
lwi r11, r11, TI_FLAGS; /* get flags in thread info */
- andi r11, r11, _TIF_SIGPENDING;
+ andi r11, r11, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME;
beqi r11, 1f; /* Signals to handle, handle them */
addik r5, r1, 0; /* Arg 1: struct pt_regs *regs */
- addi r7, r0, 0; /* Arg 3: int in_syscall */
- bralid r15, do_signal; /* Handle any signals */
- add r6, r0, r0; /* Arg 2: sigset_t *oldset */
+ bralid r15, do_notify_resume; /* Handle any signals */
+ addi r6, r0, 0; /* Arg 2: int in_syscall */
/* Finally, return to user state. */
1: swi CURRENT_TASK, r0, PER_CPU(CURRENT_SAVE); /* save current */
diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c
index 599671168980..7f4c7bef1642 100644
--- a/arch/microblaze/kernel/signal.c
+++ b/arch/microblaze/kernel/signal.c
@@ -31,6 +31,7 @@
#include <linux/personality.h>
#include <linux/percpu.h>
#include <linux/linkage.h>
+#include <linux/tracehook.h>
#include <asm/entry.h>
#include <asm/ucontext.h>
#include <linux/uaccess.h>
@@ -42,8 +43,6 @@
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_sycall);
-
asmlinkage long
sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
struct pt_regs *regs)
@@ -98,6 +97,9 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
sigset_t set;
int rval;
+ /* Always make any pending restarted system calls return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
@@ -105,10 +107,7 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &rval))
goto badframe;
@@ -169,7 +168,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
return (void __user *)((sp - frame_size) & -8UL);
}
-static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
@@ -267,12 +266,11 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
current->comm, current->pid, frame, regs->pc);
#endif
- return;
+ return 0;
give_sigsegv:
- if (sig == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(sig, current);
+ return -EFAULT;
}
/* Handle restarting system calls */
@@ -316,24 +314,20 @@ static int
handle_signal(unsigned long sig, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
{
+ int ret;
+
/* Set up the stack frame */
if (ka->sa.sa_flags & SA_SIGINFO)
- setup_rt_frame(sig, ka, info, oldset, regs);
+ ret = setup_rt_frame(sig, ka, info, oldset, regs);
else
- setup_rt_frame(sig, ka, NULL, oldset, regs);
-
- if (ka->sa.sa_flags & SA_ONESHOT)
- ka->sa.sa_handler = SIG_DFL;
-
- if (!(ka->sa.sa_flags & SA_NODEFER)) {
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked,
- &current->blocked, &ka->sa.sa_mask);
- sigaddset(&current->blocked, sig);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
- }
- return 1;
+ ret = setup_rt_frame(sig, ka, NULL, oldset, regs);
+
+ if (ret)
+ return ret;
+
+ block_sigmask(ka, sig);
+
+ return 0;
}
/*
@@ -345,24 +339,17 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
* the kernel can handle, and then we build all the user-level signal handling
* stack-frames in one go after that.
*/
-int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall)
+static void do_signal(struct pt_regs *regs, int in_syscall)
{
siginfo_t info;
int signr;
struct k_sigaction ka;
+ sigset_t *oldset;
#ifdef DEBUG_SIG
- printk(KERN_INFO "do signal: %p %p %d\n", regs, oldset, in_syscall);
+ printk(KERN_INFO "do signal: %p %d\n", regs, in_syscall);
printk(KERN_INFO "do signal2: %lx %lx %ld [%lx]\n", regs->pc, regs->r1,
regs->r12, current_thread_info()->flags);
#endif
- /*
- * We want the common case to go fast, which
- * is why we may in certain cases get here from
- * kernel mode. Just return without doing anything
- * if so.
- */
- if (kernel_mode(regs))
- return 1;
if (current_thread_info()->status & TS_RESTORE_SIGMASK)
oldset = &current->saved_sigmask;
@@ -374,7 +361,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall)
/* Whee! Actually deliver the signal. */
if (in_syscall)
handle_restart(regs, &ka, 1);
- if (handle_signal(signr, &ka, &info, oldset, regs)) {
+ if (!handle_signal(signr, &ka, &info, oldset, regs)) {
/*
* A signal was successfully delivered; the saved
* sigmask will have been stored in the signal frame,
@@ -384,7 +371,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall)
current_thread_info()->status &=
~TS_RESTORE_SIGMASK;
}
- return 1;
+ return;
}
if (in_syscall)
@@ -398,7 +385,25 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall)
current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
}
+}
- /* Did we come from a system call? */
- return 0;
+void do_notify_resume(struct pt_regs *regs, int in_syscall)
+{
+ /*
+ * We want the common case to go fast, which
+ * is why we may in certain cases get here from
+ * kernel mode. Just return without doing anything
+ * if so.
+ */
+ if (kernel_mode(regs))
+ return;
+
+ if (test_thread_flag(TIF_SIGPENDING))
+ do_signal(regs, in_syscall);
+
+ if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) {
+ tracehook_notify_resume(regs);
+ if (current->replacement_session_keyring)
+ key_replace_session_keyring();
+ }
}
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 186fc8cf9ee0..77050671eeef 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -8,6 +8,7 @@ config MIPS
select HAVE_PERF_EVENTS
select PERF_USE_VMALLOC
select HAVE_ARCH_KGDB
+ select ARCH_HAVE_CUSTOM_GPIO_H
select HAVE_FUNCTION_TRACER
select HAVE_FUNCTION_TRACE_MCOUNT_TEST
select HAVE_DYNAMIC_FTRACE
@@ -30,6 +31,9 @@ config MIPS
select HAVE_MEMBLOCK_NODE_MAP
select ARCH_DISCARD_MEMBLOCK
select GENERIC_SMP_IDLE_THREAD
+ select BUILDTIME_EXTABLE_SORT
+ select GENERIC_CLOCKEVENTS
+ select GENERIC_CMOS_UPDATE
menu "Machine selection"
@@ -857,14 +861,6 @@ config GENERIC_CALIBRATE_DELAY
bool
default y
-config GENERIC_CLOCKEVENTS
- bool
- default y
-
-config GENERIC_CMOS_UPDATE
- bool
- default y
-
config SCHED_OMIT_FRAME_POINTER
bool
default y
@@ -1002,12 +998,12 @@ config HOLES_IN_ZONE
bool
#
-# Endianess selection. Sufficiently obscure so many users don't know what to
+# Endianness selection. Sufficiently obscure so many users don't know what to
# answer,so we try hard to limit the available choices. Also the use of a
# choice statement should be more obvious to the user.
#
choice
- prompt "Endianess selection"
+ prompt "Endianness selection"
help
Some MIPS machines can be configured for either little or big endian
byte order. These modes require different kernels and a different
@@ -2051,9 +2047,6 @@ config CPU_HAS_SYNC
depends on !CPU_R3000
default y
-config GENERIC_CLOCKEVENTS_BROADCAST
- bool
-
#
# CPU non-features
#
@@ -2215,8 +2208,6 @@ config NR_CPUS
performance should round up your number of processors to the next
power of two.
-source "kernel/time/Kconfig"
-
#
# Timer Interrupt Frequency Configuration
#
diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug
index 83ed00a5644a..5a43aa0798ca 100644
--- a/arch/mips/Kconfig.debug
+++ b/arch/mips/Kconfig.debug
@@ -57,7 +57,7 @@ config CMDLINE
options.
config CMDLINE_OVERRIDE
- bool "Built-in command line overrides firware arguments"
+ bool "Built-in command line overrides firmware arguments"
default n
depends on CMDLINE_BOOL
help
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index 19780aa91708..95bf4d7bac21 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -90,6 +90,7 @@ static int bcm47xx_get_sprom_ssb(struct ssb_bus *bus, struct ssb_sprom *out)
char prefix[10];
if (bus->bustype == SSB_BUSTYPE_PCI) {
+ memset(out, 0, sizeof(struct ssb_sprom));
snprintf(prefix, sizeof(prefix), "pci/%u/%u/",
bus->host_pci->bus->number + 1,
PCI_SLOT(bus->host_pci->devfn));
@@ -109,15 +110,9 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus,
/* Fill boardinfo structure */
memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo));
- if (nvram_getenv("boardvendor", buf, sizeof(buf)) >= 0)
- iv->boardinfo.vendor = (u16)simple_strtoul(buf, NULL, 0);
- else
- iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM;
- if (nvram_getenv("boardtype", buf, sizeof(buf)) >= 0)
- iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0);
- if (nvram_getenv("boardrev", buf, sizeof(buf)) >= 0)
- iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0);
+ bcm47xx_fill_ssb_boardinfo(&iv->boardinfo, NULL);
+ memset(&iv->sprom, 0, sizeof(struct ssb_sprom));
bcm47xx_fill_sprom(&iv->sprom, NULL);
if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0)
@@ -166,12 +161,14 @@ static int bcm47xx_get_sprom_bcma(struct bcma_bus *bus, struct ssb_sprom *out)
switch (bus->hosttype) {
case BCMA_HOSTTYPE_PCI:
+ memset(out, 0, sizeof(struct ssb_sprom));
snprintf(prefix, sizeof(prefix), "pci/%u/%u/",
bus->host_pci->bus->number + 1,
PCI_SLOT(bus->host_pci->devfn));
bcm47xx_fill_sprom(out, prefix);
return 0;
case BCMA_HOSTTYPE_SOC:
+ memset(out, 0, sizeof(struct ssb_sprom));
bcm47xx_fill_sprom_ethernet(out, NULL);
core = bcma_find_core(bus, BCMA_CORE_80211);
if (core) {
@@ -197,6 +194,8 @@ static void __init bcm47xx_register_bcma(void)
err = bcma_host_soc_register(&bcm47xx_bus.bcma);
if (err)
panic("Failed to initialize BCMA bus (err %d)", err);
+
+ bcm47xx_fill_bcma_boardinfo(&bcm47xx_bus.bcma.bus.boardinfo, NULL);
}
#endif
diff --git a/arch/mips/bcm47xx/sprom.c b/arch/mips/bcm47xx/sprom.c
index 5c8dcd2a8a93..d3a889745e20 100644
--- a/arch/mips/bcm47xx/sprom.c
+++ b/arch/mips/bcm47xx/sprom.c
@@ -165,6 +165,8 @@ static void bcm47xx_fill_sprom_r1234589(struct ssb_sprom *sprom,
const char *prefix)
{
nvram_read_u16(prefix, NULL, "boardrev", &sprom->board_rev, 0);
+ if (!sprom->board_rev)
+ nvram_read_u16(NULL, NULL, "boardrev", &sprom->board_rev, 0);
nvram_read_u16(prefix, NULL, "boardnum", &sprom->board_num, 0);
nvram_read_u8(prefix, NULL, "ledbh0", &sprom->gpio0, 0xff);
nvram_read_u8(prefix, NULL, "ledbh1", &sprom->gpio1, 0xff);
@@ -555,8 +557,6 @@ void bcm47xx_fill_sprom_ethernet(struct ssb_sprom *sprom, const char *prefix)
void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix)
{
- memset(sprom, 0, sizeof(struct ssb_sprom));
-
bcm47xx_fill_sprom_ethernet(sprom, prefix);
nvram_read_u8(prefix, NULL, "sromrev", &sprom->revision, 0);
@@ -618,3 +618,27 @@ void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix)
bcm47xx_fill_sprom_r1(sprom, prefix);
}
}
+
+#ifdef CONFIG_BCM47XX_SSB
+void bcm47xx_fill_ssb_boardinfo(struct ssb_boardinfo *boardinfo,
+ const char *prefix)
+{
+ nvram_read_u16(prefix, NULL, "boardvendor", &boardinfo->vendor, 0);
+ if (!boardinfo->vendor)
+ boardinfo->vendor = SSB_BOARDVENDOR_BCM;
+
+ nvram_read_u16(prefix, NULL, "boardtype", &boardinfo->type, 0);
+}
+#endif
+
+#ifdef CONFIG_BCM47XX_BCMA
+void bcm47xx_fill_bcma_boardinfo(struct bcma_boardinfo *boardinfo,
+ const char *prefix)
+{
+ nvram_read_u16(prefix, NULL, "boardvendor", &boardinfo->vendor, 0);
+ if (!boardinfo->vendor)
+ boardinfo->vendor = SSB_BOARDVENDOR_BCM;
+
+ nvram_read_u16(prefix, NULL, "boardtype", &boardinfo->type, 0);
+}
+#endif
diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
index 5ecaf47b34d2..26fdaf40b930 100644
--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
+++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
@@ -47,4 +47,13 @@ extern enum bcm47xx_bus_type bcm47xx_bus_type;
void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix);
void bcm47xx_fill_sprom_ethernet(struct ssb_sprom *sprom, const char *prefix);
+#ifdef CONFIG_BCM47XX_SSB
+void bcm47xx_fill_ssb_boardinfo(struct ssb_boardinfo *boardinfo,
+ const char *prefix);
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+void bcm47xx_fill_bcma_boardinfo(struct bcma_boardinfo *boardinfo,
+ const char *prefix);
+#endif
+
#endif /* __ASM_BCM47XX_H */
diff --git a/arch/mips/include/asm/mach-ip27/topology.h b/arch/mips/include/asm/mach-ip27/topology.h
index 1b1a7d1632b9..b2cf641f206f 100644
--- a/arch/mips/include/asm/mach-ip27/topology.h
+++ b/arch/mips/include/asm/mach-ip27/topology.h
@@ -36,23 +36,6 @@ extern unsigned char __node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES];
#define node_distance(from, to) (__node_distances[(from)][(to)])
-/* sched_domains SD_NODE_INIT for SGI IP27 machines */
-#define SD_NODE_INIT (struct sched_domain) { \
- .parent = NULL, \
- .child = NULL, \
- .groups = NULL, \
- .min_interval = 8, \
- .max_interval = 32, \
- .busy_factor = 32, \
- .imbalance_pct = 125, \
- .cache_nice_tries = 1, \
- .flags = SD_LOAD_BALANCE | \
- SD_BALANCE_EXEC, \
- .last_balance = jiffies, \
- .balance_interval = 1, \
- .nr_balance_failed = 0, \
-}
-
#include <asm-generic/topology.h>
#endif /* _ASM_MACH_TOPOLOGY_H */
diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h
index 20e9dcf42b27..5e33fabe354d 100644
--- a/arch/mips/include/asm/processor.h
+++ b/arch/mips/include/asm/processor.h
@@ -310,9 +310,6 @@ struct task_struct;
/* Free all resources held by a thread. */
#define release_thread(thread) do { } while(0)
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk) do { } while (0)
-
extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
extern unsigned long thread_saved_pc(struct task_struct *tsk);
diff --git a/arch/mips/kernel/mips-mt.c b/arch/mips/kernel/mips-mt.c
index 7f3376b1c219..6ded9bd1489c 100644
--- a/arch/mips/kernel/mips-mt.c
+++ b/arch/mips/kernel/mips-mt.c
@@ -209,7 +209,7 @@ void mips_mt_set_cpuoptions(void)
unsigned int nconfig7 = oconfig7;
if (mt_opt_norps) {
- printk("\"norps\" option deprectated: use \"rpsctl=\"\n");
+ printk("\"norps\" option deprecated: use \"rpsctl=\"\n");
}
if (mt_opt_rpsctl >= 0) {
printk("34K return prediction stack override set to %d.\n",
diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c
index 811084f4e422..ab73fa2fb9b5 100644
--- a/arch/mips/kernel/perf_event_mipsxx.c
+++ b/arch/mips/kernel/perf_event_mipsxx.c
@@ -1325,7 +1325,7 @@ static int mipsxx_pmu_handle_shared_irq(void)
regs = get_irq_regs();
- perf_sample_data_init(&data, 0);
+ perf_sample_data_init(&data, 0, 0);
switch (counters) {
#define HANDLE_COUNTER(n) \
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index d5a338a1739c..17f6ee30ad0d 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -255,15 +255,7 @@ asmlinkage int sys_sigsuspend(nabi_no_regargs struct pt_regs regs)
uset = (sigset_t __user *) regs.regs[4];
if (copy_from_user(&newset, uset, sizeof(sigset_t)))
return -EFAULT;
- sigdelsetmask(&newset, ~_BLOCKABLE);
-
- current->saved_sigmask = current->blocked;
- set_current_blocked(&newset);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
+ return sigsuspend(&newset);
}
#endif
@@ -281,15 +273,7 @@ asmlinkage int sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
unewset = (sigset_t __user *) regs.regs[4];
if (copy_from_user(&newset, unewset, sizeof(newset)))
return -EFAULT;
- sigdelsetmask(&newset, ~_BLOCKABLE);
-
- current->saved_sigmask = current->blocked;
- set_current_blocked(&newset);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
+ return sigsuspend(&newset);
}
#ifdef CONFIG_TRAD_SIGNALS
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index ac3b8d89aae5..b4fe2eacbd5d 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -288,15 +288,7 @@ asmlinkage int sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
uset = (compat_sigset_t __user *) regs.regs[4];
if (get_sigset(&newset, uset))
return -EFAULT;
- sigdelsetmask(&newset, ~_BLOCKABLE);
-
- current->saved_sigmask = current->blocked;
- set_current_blocked(&newset);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
+ return sigsuspend(&newset);
}
asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
@@ -313,15 +305,7 @@ asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
uset = (compat_sigset_t __user *) regs.regs[4];
if (get_sigset(&newset, uset))
return -EFAULT;
- sigdelsetmask(&newset, ~_BLOCKABLE);
-
- current->saved_sigmask = current->blocked;
- set_current_blocked(&newset);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
+ return sigsuspend(&newset);
}
SYSCALL_DEFINE3(32_sigaction, long, sig, const struct sigaction32 __user *, act,
diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c
index 86eb4b04631c..63ffac9af7c5 100644
--- a/arch/mips/kernel/signal_n32.c
+++ b/arch/mips/kernel/signal_n32.c
@@ -91,15 +91,7 @@ asmlinkage int sysn32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
if (copy_from_user(&uset, unewset, sizeof(uset)))
return -EFAULT;
sigset_from_compat(&newset, &uset);
- sigdelsetmask(&newset, ~_BLOCKABLE);
-
- current->saved_sigmask = current->blocked;
- set_current_blocked(&newset);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
+ return sigsuspend(&newset);
}
asmlinkage void sysn32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
diff --git a/arch/mips/lantiq/xway/gpio.c b/arch/mips/lantiq/xway/gpio.c
index d2fa98f3c78d..c429a5bc080f 100644
--- a/arch/mips/lantiq/xway/gpio.c
+++ b/arch/mips/lantiq/xway/gpio.c
@@ -188,7 +188,7 @@ int __init ltq_gpio_init(void)
int ret = platform_driver_register(&ltq_gpio_driver);
if (ret)
- pr_info("ltq_gpio : Error registering platfom driver!");
+ pr_info("ltq_gpio : Error registering platform driver!");
return ret;
}
diff --git a/arch/mips/lantiq/xway/gpio_ebu.c b/arch/mips/lantiq/xway/gpio_ebu.c
index b91c7f17f10f..aae17170472f 100644
--- a/arch/mips/lantiq/xway/gpio_ebu.c
+++ b/arch/mips/lantiq/xway/gpio_ebu.c
@@ -119,7 +119,7 @@ static int __init ltq_ebu_init(void)
int ret = platform_driver_register(&ltq_ebu_driver);
if (ret)
- pr_info("ltq_ebu : Error registering platfom driver!");
+ pr_info("ltq_ebu : Error registering platform driver!");
return ret;
}
diff --git a/arch/mips/lantiq/xway/gpio_stp.c b/arch/mips/lantiq/xway/gpio_stp.c
index ff9991cddeaa..fd07d87adaa9 100644
--- a/arch/mips/lantiq/xway/gpio_stp.c
+++ b/arch/mips/lantiq/xway/gpio_stp.c
@@ -150,7 +150,7 @@ int __init ltq_stp_init(void)
int ret = platform_driver_register(&ltq_stp_driver);
if (ret)
- pr_info("ltq_stp: error registering platfom driver");
+ pr_info("ltq_stp: error registering platform driver");
return ret;
}
diff --git a/arch/mips/sni/pcimt.c b/arch/mips/sni/pcimt.c
index ed3b3d317358..cdb1417fba59 100644
--- a/arch/mips/sni/pcimt.c
+++ b/arch/mips/sni/pcimt.c
@@ -29,7 +29,7 @@ static void __init sni_pcimt_sc_init(void)
scsiz = cacheconf & 7;
if (scsiz == 0) {
- printk("Second level cache is deactived.\n");
+ printk("Second level cache is deactivated.\n");
return;
}
if (scsiz >= 6) {
diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig
index 3aa3de017159..687f9b4a2ed6 100644
--- a/arch/mn10300/Kconfig
+++ b/arch/mn10300/Kconfig
@@ -6,6 +6,7 @@ config MN10300
select HAVE_ARCH_TRACEHOOK
select HAVE_ARCH_KGDB
select HAVE_NMI_WATCHDOG if MN10300_WD_TIMER
+ select GENERIC_CLOCKEVENTS
config AM33_2
def_bool n
@@ -42,15 +43,9 @@ config RWSEM_XCHGADD_ALGORITHM
config GENERIC_CALIBRATE_DELAY
def_bool y
-config GENERIC_CMOS_UPDATE
- def_bool n
-
config GENERIC_HWEIGHT
def_bool y
-config GENERIC_CLOCKEVENTS
- def_bool y
-
config GENERIC_BUG
def_bool y
@@ -231,7 +226,6 @@ config MN10300_USING_JTAG
single-stepping, which are taken over completely by the JTAG unit.
source "kernel/Kconfig.hz"
-source "kernel/time/Kconfig"
config MN10300_RTC
bool "Using MN10300 RTC"
diff --git a/arch/mn10300/include/asm/processor.h b/arch/mn10300/include/asm/processor.h
index f7b3c9ab2cb5..247928c9f549 100644
--- a/arch/mn10300/include/asm/processor.h
+++ b/arch/mn10300/include/asm/processor.h
@@ -139,9 +139,6 @@ static inline void start_thread(struct pt_regs *regs,
/* Free all resources held by a thread. */
extern void release_thread(struct task_struct *);
-/* Prepare to copy thread state - unlazy all lazy status */
-extern void prepare_to_copy(struct task_struct *tsk);
-
/*
* create a kernel thread without removing it from tasklists
*/
diff --git a/arch/mn10300/kernel/process.c b/arch/mn10300/kernel/process.c
index 14707f25153b..7dab0cd36466 100644
--- a/arch/mn10300/kernel/process.c
+++ b/arch/mn10300/kernel/process.c
@@ -208,12 +208,14 @@ void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
}
/*
- * this gets called before we allocate a new thread and copy the current task
- * into it so that we can store lazy state into memory
+ * this gets called so that we can store lazy state into memory and copy the
+ * current task into the new thread.
*/
-void prepare_to_copy(struct task_struct *tsk)
+int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
{
- unlazy_fpu(tsk);
+ unlazy_fpu(src);
+ *dst = *src;
+ return 0;
}
/*
diff --git a/arch/mn10300/kernel/signal.c b/arch/mn10300/kernel/signal.c
index 690f4e9507d7..890cf91767cc 100644
--- a/arch/mn10300/kernel/signal.c
+++ b/arch/mn10300/kernel/signal.c
@@ -38,17 +38,9 @@
*/
asmlinkage long sys_sigsuspend(int history0, int history1, old_sigset_t mask)
{
- mask &= _BLOCKABLE;
- spin_lock_irq(&current->sighand->siglock);
- current->saved_sigmask = current->blocked;
- siginitset(&current->blocked, mask);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
+ sigset_t blocked;
+ siginitset(&blocked, mask);
+ return sigsuspend(&blocked);
}
/*
@@ -172,10 +164,7 @@ asmlinkage long sys_sigreturn(void)
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(current_frame(), &frame->sc, &d0))
goto badframe;
@@ -203,10 +192,7 @@ asmlinkage long sys_rt_sigreturn(void)
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(current_frame(), &frame->uc.uc_mcontext, &d0))
goto badframe;
@@ -476,15 +462,8 @@ static int handle_signal(int sig,
else
ret = setup_frame(sig, ka, oldset, regs);
- if (ret == 0) {
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked, &current->blocked,
- &ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(&current->blocked, sig);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
- }
+ if (ret == 0)
+ block_sigmask(ka, sig);
return ret;
}
diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig
index 7589051e79e0..4932247d078a 100644
--- a/arch/openrisc/Kconfig
+++ b/arch/openrisc/Kconfig
@@ -18,6 +18,7 @@ config OPENRISC
select GENERIC_IOMAP
select GENERIC_CPU_DEVICES
select GENERIC_ATOMIC64
+ select GENERIC_CLOCKEVENTS
config MMU
def_bool y
@@ -47,9 +48,6 @@ config NO_IOPORT
config GENERIC_GPIO
def_bool y
-config GENERIC_CLOCKEVENTS
- def_bool y
-
config TRACE_IRQFLAGS_SUPPORT
def_bool y
@@ -109,7 +107,6 @@ config OPENRISC_HAVE_INST_DIV
endmenu
-source "kernel/time/Kconfig"
source kernel/Kconfig.hz
source kernel/Kconfig.preempt
source "mm/Kconfig"
@@ -142,7 +139,7 @@ config DEBUG_STACKOVERFLOW
bool "Check for kernel stack overflow"
default y
help
- Make extra checks for space avaliable on stack in some
+ Make extra checks for space available on stack in some
critical functions. This will cause kernel to run a bit slower,
but will catch most of kernel stack overruns and exit gracefuly.
diff --git a/arch/openrisc/include/asm/gpio.h b/arch/openrisc/include/asm/gpio.h
index 0b0d174f47cd..b3799d88ffcf 100644
--- a/arch/openrisc/include/asm/gpio.h
+++ b/arch/openrisc/include/asm/gpio.h
@@ -1,65 +1,4 @@
-/*
- * OpenRISC Linux
- *
- * Linux architectural port borrowing liberally from similar works of
- * others. All original copyrights apply as per the original source
- * declaration.
- *
- * OpenRISC implementation:
- * Copyright (C) 2003 Matjaz Breskvar <phoenix@bsemi.com>
- * Copyright (C) 2010-2011 Jonas Bonn <jonas@southpole.se>
- * et al.
- *
- * 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.
- */
-
-#ifndef __ASM_OPENRISC_GPIO_H
-#define __ASM_OPENRISC_GPIO_H
-
-#include <linux/errno.h>
-#include <asm-generic/gpio.h>
-
-#ifdef CONFIG_GPIOLIB
-
-/*
- * OpenRISC (or1k) does not have on-chip GPIO's so there is not really
- * any standardized implementation that makes sense here. If passing
- * through gpiolib becomes a bottleneck then it may make sense, on a
- * case-by-case basis, to implement these inlined/rapid versions.
- *
- * Just call gpiolib.
- */
-static inline int gpio_get_value(unsigned int gpio)
-{
- return __gpio_get_value(gpio);
-}
-
-static inline void gpio_set_value(unsigned int gpio, int value)
-{
- __gpio_set_value(gpio, value);
-}
-
-static inline int gpio_cansleep(unsigned int gpio)
-{
- return __gpio_cansleep(gpio);
-}
-
-/*
- * Not implemented, yet.
- */
-static inline int gpio_to_irq(unsigned int gpio)
-{
- return -ENOSYS;
-}
-
-static inline int irq_to_gpio(unsigned int irq)
-{
- return -EINVAL;
-}
-
-#endif /* CONFIG_GPIOLIB */
-
-#endif /* __ASM_OPENRISC_GPIO_H */
+#ifndef __LINUX_GPIO_H
+#warning Include linux/gpio.h instead of asm/gpio.h
+#include <linux/gpio.h>
+#endif
diff --git a/arch/openrisc/include/asm/processor.h b/arch/openrisc/include/asm/processor.h
index f7516fa78b58..30462f1fe959 100644
--- a/arch/openrisc/include/asm/processor.h
+++ b/arch/openrisc/include/asm/processor.h
@@ -72,10 +72,6 @@ struct thread_struct {
#define task_pt_regs(task) user_regs(task_thread_info(task))
#define current_regs() user_regs(current_thread_info())
-extern inline void prepare_to_copy(struct task_struct *tsk)
-{
-}
-
#define INIT_SP (sizeof(init_stack) + (unsigned long) &init_stack)
#define INIT_THREAD { }
diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c
index 0dc8543acb4f..c71eb6c79897 100644
--- a/arch/parisc/hpux/fs.c
+++ b/arch/parisc/hpux/fs.c
@@ -159,8 +159,8 @@ static int cp_hpux_stat(struct kstat *stat, struct hpux_stat64 __user *statbuf)
tmp.st_ino = stat->ino;
tmp.st_mode = stat->mode;
tmp.st_nlink = stat->nlink;
- tmp.st_uid = stat->uid;
- tmp.st_gid = stat->gid;
+ tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid);
+ tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid);
tmp.st_rdev = new_encode_dev(stat->rdev);
tmp.st_size = stat->size;
tmp.st_atime = stat->atime.tv_sec;
diff --git a/arch/parisc/include/asm/kbdleds.h b/arch/parisc/include/asm/kbdleds.h
new file mode 100644
index 000000000000..2e2e75a83c28
--- /dev/null
+++ b/arch/parisc/include/asm/kbdleds.h
@@ -0,0 +1,19 @@
+#ifndef _ASM_PARISC_KBDLEDS_H
+#define _ASM_PARISC_KBDLEDS_H
+
+/*
+ * On HIL keyboards of PARISC machines there is no NumLock key and
+ * everyone expects the keypad to be used for numbers. That's why
+ * we can safely turn on the NUMLOCK bit.
+ */
+
+static inline int kbd_defleds(void)
+{
+#if defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD)
+ return 1 << VC_NUMLOCK;
+#else
+ return 0;
+#endif
+}
+
+#endif /* _ASM_PARISC_KBDLEDS_H */
diff --git a/arch/parisc/include/asm/processor.h b/arch/parisc/include/asm/processor.h
index acdf4cad6125..0e8b7b8ce8a2 100644
--- a/arch/parisc/include/asm/processor.h
+++ b/arch/parisc/include/asm/processor.h
@@ -328,9 +328,6 @@ struct mm_struct;
extern void release_thread(struct task_struct *);
extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk) do { } while (0)
-
extern void map_hpux_gateway_page(struct task_struct *tsk, struct mm_struct *mm);
extern unsigned long get_wchan(struct task_struct *p);
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index 12c1ed33dc18..4b9cb0d546d1 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -109,6 +109,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
sigframe_size = PARISC_RT_SIGFRAME_SIZE32;
#endif
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
/* Unwind the user stack to get the rt_sigframe structure. */
frame = (struct rt_sigframe __user *)
@@ -131,10 +132,7 @@ sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
}
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
/* Good thing we saved the old gr[30], eh? */
#ifdef CONFIG_64BIT
@@ -454,12 +452,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall))
return 0;
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(&current->blocked,sig);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ block_sigmask(ka, sig);
tracehook_signal_handler(sig, info, ka, regs,
test_thread_flag(TIF_SINGLESTEP) ||
@@ -474,8 +467,6 @@ syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
/* Check the return code */
switch (regs->gr[28]) {
case -ERESTART_RESTARTBLOCK:
- current_thread_info()->restart_block.fn =
- do_no_restart_syscall;
case -ERESTARTNOHAND:
DBG(1,"ERESTARTNOHAND: returning -EINTR\n");
regs->gr[28] = -EINTR;
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 8a01098eaaca..00b9874e2240 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -27,15 +27,6 @@ config MMU
bool
default y
-config GENERIC_CMOS_UPDATE
- def_bool y
-
-config GENERIC_TIME_VSYSCALL
- def_bool y
-
-config GENERIC_CLOCKEVENTS
- def_bool y
-
config HAVE_SETUP_PER_CPU_AREA
def_bool PPC64
@@ -141,6 +132,9 @@ config PPC
select HAVE_ARCH_JUMP_LABEL
select ARCH_HAVE_NMI_SAFE_CMPXCHG
select GENERIC_SMP_IDLE_THREAD
+ select GENERIC_CMOS_UPDATE
+ select GENERIC_TIME_VSYSCALL
+ select GENERIC_CLOCKEVENTS
config EARLY_PRINTK
bool
@@ -281,7 +275,6 @@ config HIGHMEM
bool "High memory support"
depends on PPC32
-source kernel/time/Kconfig
source kernel/Kconfig.hz
source kernel/Kconfig.preempt
source "fs/Kconfig.binfmt"
@@ -350,7 +343,7 @@ config ARCH_ENABLE_MEMORY_HOTREMOVE
config KEXEC
bool "kexec system call (EXPERIMENTAL)"
- depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP && !PPC_47x)) && EXPERIMENTAL
+ depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP)) && EXPERIMENTAL
help
kexec is a system call that implements the ability to shutdown your
current kernel, and to start another kernel. It is like a reboot
@@ -367,7 +360,7 @@ config KEXEC
config CRASH_DUMP
bool "Build a kdump crash kernel"
- depends on PPC64 || 6xx || FSL_BOOKE || (44x && !SMP && !PPC_47x)
+ depends on PPC64 || 6xx || FSL_BOOKE || (44x && !SMP)
select RELOCATABLE if PPC64 || 44x
select DYNAMIC_MEMSTART if FSL_BOOKE
help
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index 6524c6e21896..950d1f7a5a39 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -69,6 +69,16 @@ LDFLAGS_vmlinux := $(LDFLAGS_vmlinux-y)
CFLAGS-$(CONFIG_PPC64) := -mminimal-toc -mtraceback=no -mcall-aixdesc
CFLAGS-$(CONFIG_PPC32) := -ffixed-r2 -mmultiple
+
+CFLAGS-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mtune=power7,-mtune=power4)
+CFLAGS-$(CONFIG_CELL_CPU) += $(call cc-option,-mcpu=cell)
+CFLAGS-$(CONFIG_POWER4_CPU) += $(call cc-option,-mcpu=power4)
+CFLAGS-$(CONFIG_POWER5_CPU) += $(call cc-option,-mcpu=power5)
+CFLAGS-$(CONFIG_POWER6_CPU) += $(call cc-option,-mcpu=power6)
+CFLAGS-$(CONFIG_POWER7_CPU) += $(call cc-option,-mcpu=power7)
+
+CFLAGS-$(CONFIG_TUNE_CELL) += $(call cc-option,-mtune=cell)
+
KBUILD_CPPFLAGS += -Iarch/$(ARCH)
KBUILD_AFLAGS += -Iarch/$(ARCH)
KBUILD_CFLAGS += -msoft-float -pipe -Iarch/$(ARCH) $(CFLAGS-y)
@@ -76,32 +86,11 @@ CPP = $(CC) -E $(KBUILD_CFLAGS)
CHECKFLAGS += -m$(CONFIG_WORD_SIZE) -D__powerpc__ -D__powerpc$(CONFIG_WORD_SIZE)__
-ifeq ($(CONFIG_PPC64),y)
-GCC_BROKEN_VEC := $(call cc-ifversion, -lt, 0400, y)
-
-ifeq ($(CONFIG_POWER4_ONLY),y)
-ifeq ($(CONFIG_ALTIVEC),y)
-ifeq ($(GCC_BROKEN_VEC),y)
- KBUILD_CFLAGS += $(call cc-option,-mcpu=970)
-else
- KBUILD_CFLAGS += $(call cc-option,-mcpu=power4)
-endif
-else
- KBUILD_CFLAGS += $(call cc-option,-mcpu=power4)
-endif
-else
- KBUILD_CFLAGS += $(call cc-option,-mtune=power4)
-endif
-endif
-
KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o
-ifeq ($(CONFIG_TUNE_CELL),y)
- KBUILD_CFLAGS += $(call cc-option,-mtune=cell)
-endif
-
-# No AltiVec instruction when building kernel
+# No AltiVec or VSX instructions when building kernel
KBUILD_CFLAGS += $(call cc-option,-mno-altivec)
+KBUILD_CFLAGS += $(call cc-option,-mno-vsx)
# No SPE instruction when building kernel
# (We use all available options to help semi-broken compilers)
@@ -160,6 +149,7 @@ core-$(CONFIG_KVM) += arch/powerpc/kvm/
core-$(CONFIG_PERF_EVENTS) += arch/powerpc/perf/
drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/
+drivers-$(CONFIG_CRYPTO_DEV_NX) += drivers/crypto/nx/
# Default to zImage, override when needed
all: zImage
@@ -234,10 +224,11 @@ archprepare: checkbin
# Use the file '.tmp_gas_check' for binutils tests, as gas won't output
# to stdout and these checks are run even on install targets.
TOUT := .tmp_gas_check
-# Ensure this is binutils 2.12.1 (or 2.12.90.0.7) or later for altivec
-# instructions.
-# gcc-3.4 and binutils-2.14 are a fatal combination.
+# Check gcc and binutils versions:
+# - gcc-3.4 and binutils-2.14 are a fatal combination
+# - Require gcc 4.0 or above on 64-bit
+# - gcc-4.2.0 has issues compiling modules on 64-bit
checkbin:
@if test "$(call cc-version)" = "0304" ; then \
if ! /bin/echo mftb 5 | $(AS) -v -mppc -many -o $(TOUT) >/dev/null 2>&1 ; then \
@@ -247,6 +238,12 @@ checkbin:
false; \
fi ; \
fi
+ @if test "$(call cc-version)" -lt "0400" \
+ && test "x${CONFIG_PPC64}" = "xy" ; then \
+ echo -n "Sorry, GCC v4.0 or above is required to build " ; \
+ echo "the 64-bit powerpc kernel." ; \
+ false ; \
+ fi
@if test "$(call cc-fullversion)" = "040200" \
&& test "x${CONFIG_MODULES}${CONFIG_PPC64}" = "xyy" ; then \
echo -n '*** GCC-4.2.0 cannot compile the 64-bit powerpc ' ; \
diff --git a/arch/powerpc/boot/dts/bluestone.dts b/arch/powerpc/boot/dts/bluestone.dts
index 7bda373f10ef..9d4917aebe6b 100644
--- a/arch/powerpc/boot/dts/bluestone.dts
+++ b/arch/powerpc/boot/dts/bluestone.dts
@@ -373,5 +373,30 @@
0x0 0x0 0x0 0x3 &UIC3 0xe 0x4 /* swizzled int C */
0x0 0x0 0x0 0x4 &UIC3 0xf 0x4 /* swizzled int D */>;
};
+
+ MSI: ppc4xx-msi@C10000000 {
+ compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";
+ reg = < 0xC 0x10000000 0x100
+ 0xC 0x10000000 0x100>;
+ sdr-base = <0x36C>;
+ msi-data = <0x00004440>;
+ msi-mask = <0x0000ffe0>;
+ interrupts =<0 1 2 3 4 5 6 7>;
+ interrupt-parent = <&MSI>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ msi-available-ranges = <0x0 0x100>;
+ interrupt-map = <
+ 0 &UIC3 0x18 1
+ 1 &UIC3 0x19 1
+ 2 &UIC3 0x1A 1
+ 3 &UIC3 0x1B 1
+ 4 &UIC3 0x1C 1
+ 5 &UIC3 0x1D 1
+ 6 &UIC3 0x1E 1
+ 7 &UIC3 0x1F 1
+ >;
+ };
};
};
diff --git a/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig b/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
index 0db9ba0423ff..c09598b31de1 100644
--- a/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
+++ b/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
@@ -100,6 +100,7 @@ CONFIG_SND_MIXER_OSS=y
CONFIG_SND_PCM_OSS=y
# CONFIG_SND_SUPPORT_OLD_API is not set
CONFIG_SND_SOC=y
+CONFIG_SND_POWERPC_SOC=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_CMOS=y
CONFIG_EXT2_FS=y
diff --git a/arch/powerpc/configs/chroma_defconfig b/arch/powerpc/configs/chroma_defconfig
index f104ccde6b53..b1f9597fe312 100644
--- a/arch/powerpc/configs/chroma_defconfig
+++ b/arch/powerpc/configs/chroma_defconfig
@@ -32,7 +32,7 @@ CONFIG_RD_LZMA=y
CONFIG_INITRAMFS_COMPRESSION_GZIP=y
CONFIG_KALLSYMS_ALL=y
CONFIG_EMBEDDED=y
-CONFIG_PERF_COUNTERS=y
+CONFIG_PERF_EVENTS=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_KPROBES=y
diff --git a/arch/powerpc/configs/g5_defconfig b/arch/powerpc/configs/g5_defconfig
index 1196c34163b7..07b7f2af2dca 100644
--- a/arch/powerpc/configs/g5_defconfig
+++ b/arch/powerpc/configs/g5_defconfig
@@ -1,5 +1,4 @@
CONFIG_PPC64=y
-CONFIG_POWER4_ONLY=y
CONFIG_ALTIVEC=y
CONFIG_SMP=y
CONFIG_NR_CPUS=4
diff --git a/arch/powerpc/configs/gamecube_defconfig b/arch/powerpc/configs/gamecube_defconfig
index e74d3a483705..9ef2cc13e1b4 100644
--- a/arch/powerpc/configs/gamecube_defconfig
+++ b/arch/powerpc/configs/gamecube_defconfig
@@ -8,7 +8,7 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_EXPERT=y
# CONFIG_ELF_CORE is not set
-CONFIG_PERF_COUNTERS=y
+CONFIG_PERF_EVENTS=y
# CONFIG_VM_EVENT_COUNTERS is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/powerpc/configs/maple_defconfig b/arch/powerpc/configs/maple_defconfig
index 2244d370f24d..02ac96b679b8 100644
--- a/arch/powerpc/configs/maple_defconfig
+++ b/arch/powerpc/configs/maple_defconfig
@@ -1,5 +1,4 @@
CONFIG_PPC64=y
-CONFIG_POWER4_ONLY=y
CONFIG_SMP=y
CONFIG_NR_CPUS=4
CONFIG_EXPERIMENTAL=y
diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig
index d6b6df5e8743..62bb723c5b54 100644
--- a/arch/powerpc/configs/mpc85xx_defconfig
+++ b/arch/powerpc/configs/mpc85xx_defconfig
@@ -141,6 +141,7 @@ CONFIG_SND_INTEL8X0=y
# CONFIG_SND_PPC is not set
# CONFIG_SND_USB is not set
CONFIG_SND_SOC=y
+CONFIG_SND_POWERPC_SOC=y
CONFIG_HID_A4TECH=y
CONFIG_HID_APPLE=y
CONFIG_HID_BELKIN=y
diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig
index 5b0e2926becd..d1828427ae55 100644
--- a/arch/powerpc/configs/mpc85xx_smp_defconfig
+++ b/arch/powerpc/configs/mpc85xx_smp_defconfig
@@ -143,6 +143,7 @@ CONFIG_SND_INTEL8X0=y
# CONFIG_SND_PPC is not set
# CONFIG_SND_USB is not set
CONFIG_SND_SOC=y
+CONFIG_SND_POWERPC_SOC=y
CONFIG_HID_A4TECH=y
CONFIG_HID_APPLE=y
CONFIG_HID_BELKIN=y
diff --git a/arch/powerpc/configs/pasemi_defconfig b/arch/powerpc/configs/pasemi_defconfig
index f4deb0b78cf0..840a2c2d0430 100644
--- a/arch/powerpc/configs/pasemi_defconfig
+++ b/arch/powerpc/configs/pasemi_defconfig
@@ -1,5 +1,4 @@
CONFIG_PPC64=y
-CONFIG_POWER4_ONLY=y
CONFIG_ALTIVEC=y
# CONFIG_VIRT_CPU_ACCOUNTING is not set
CONFIG_SMP=y
diff --git a/arch/powerpc/configs/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig
index ded867871e97..c2f4b4a86ece 100644
--- a/arch/powerpc/configs/ps3_defconfig
+++ b/arch/powerpc/configs/ps3_defconfig
@@ -6,7 +6,6 @@ CONFIG_NR_CPUS=2
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
-CONFIG_SPARSE_IRQ=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_EMBEDDED=y
@@ -25,7 +24,6 @@ CONFIG_PS3_DISK=y
CONFIG_PS3_ROM=y
CONFIG_PS3_FLASH=y
CONFIG_PS3_VRAM=m
-CONFIG_PS3_LPM=m
# CONFIG_PPC_OF_BOOT_TRAMPOLINE is not set
CONFIG_HIGH_RES_TIMERS=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
@@ -53,8 +51,6 @@ CONFIG_IP_PNP_DHCP=y
# CONFIG_INET_DIAG is not set
CONFIG_IPV6=y
CONFIG_BT=m
-CONFIG_BT_L2CAP=y
-CONFIG_BT_SCO=y
CONFIG_BT_RFCOMM=m
CONFIG_BT_RFCOMM_TTY=y
CONFIG_BT_BNEP=m
@@ -63,7 +59,6 @@ CONFIG_BT_BNEP_PROTO_FILTER=y
CONFIG_BT_HIDP=m
CONFIG_BT_HCIBTUSB=m
CONFIG_CFG80211=m
-# CONFIG_WIRELESS_EXT_SYSFS is not set
CONFIG_MAC80211=m
CONFIG_MAC80211_RC_PID=y
# CONFIG_MAC80211_RC_MINSTREL is not set
@@ -181,7 +176,6 @@ CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_WRITECOUNT=y
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_DEBUG_LIST=y
-CONFIG_SYSCTL_SYSCALL_CHECK=y
# CONFIG_FTRACE is not set
CONFIG_DEBUG_STACKOVERFLOW=y
CONFIG_CRYPTO_CCM=m
diff --git a/arch/powerpc/configs/wii_defconfig b/arch/powerpc/configs/wii_defconfig
index 175295fbf4f3..1e2b7d062aa4 100644
--- a/arch/powerpc/configs/wii_defconfig
+++ b/arch/powerpc/configs/wii_defconfig
@@ -9,7 +9,7 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_EXPERT=y
# CONFIG_ELF_CORE is not set
-CONFIG_PERF_COUNTERS=y
+CONFIG_PERF_EVENTS=y
# CONFIG_VM_EVENT_COUNTERS is not set
CONFIG_SLAB=y
CONFIG_MODULES=y
diff --git a/arch/powerpc/include/asm/asm-compat.h b/arch/powerpc/include/asm/asm-compat.h
index decad950f11a..5d7fbe1950f9 100644
--- a/arch/powerpc/include/asm/asm-compat.h
+++ b/arch/powerpc/include/asm/asm-compat.h
@@ -29,18 +29,9 @@
#define PPC_LLARX(t, a, b, eh) PPC_LDARX(t, a, b, eh)
#define PPC_STLCX stringify_in_c(stdcx.)
#define PPC_CNTLZL stringify_in_c(cntlzd)
+#define PPC_MTOCRF(FXM, RS) MTOCRF((FXM), (RS))
#define PPC_LR_STKOFF 16
#define PPC_MIN_STKFRM 112
-
-/* Move to CR, single-entry optimized version. Only available
- * on POWER4 and later.
- */
-#ifdef CONFIG_POWER4_ONLY
-#define PPC_MTOCRF stringify_in_c(mtocrf)
-#else
-#define PPC_MTOCRF stringify_in_c(mtcrf)
-#endif
-
#else /* 32-bit */
/* operations for longs and pointers */
diff --git a/arch/powerpc/include/asm/cputhreads.h b/arch/powerpc/include/asm/cputhreads.h
index ce516e5eb0d3..ac3eedb9b74a 100644
--- a/arch/powerpc/include/asm/cputhreads.h
+++ b/arch/powerpc/include/asm/cputhreads.h
@@ -9,7 +9,7 @@
* Note: This implementation is limited to a power of 2 number of
* threads per core and the same number for each core in the system
* (though it would work if some processors had less threads as long
- * as the CPU numbers are still allocated, just not brought offline).
+ * as the CPU numbers are still allocated, just not brought online).
*
* However, the API allows for a different implementation in the future
* if needed, as long as you only use the functions and not the variables
diff --git a/arch/powerpc/include/asm/gpio.h b/arch/powerpc/include/asm/gpio.h
index 38762edb5e58..b3799d88ffcf 100644
--- a/arch/powerpc/include/asm/gpio.h
+++ b/arch/powerpc/include/asm/gpio.h
@@ -1,53 +1,4 @@
-/*
- * Generic GPIO API implementation for PowerPC.
- *
- * Copyright (c) 2007-2008 MontaVista Software, Inc.
- *
- * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __ASM_POWERPC_GPIO_H
-#define __ASM_POWERPC_GPIO_H
-
-#include <linux/errno.h>
-#include <asm-generic/gpio.h>
-
-#ifdef CONFIG_GPIOLIB
-
-/*
- * We don't (yet) implement inlined/rapid versions for on-chip gpios.
- * Just call gpiolib.
- */
-static inline int gpio_get_value(unsigned int gpio)
-{
- return __gpio_get_value(gpio);
-}
-
-static inline void gpio_set_value(unsigned int gpio, int value)
-{
- __gpio_set_value(gpio, value);
-}
-
-static inline int gpio_cansleep(unsigned int gpio)
-{
- return __gpio_cansleep(gpio);
-}
-
-static inline int gpio_to_irq(unsigned int gpio)
-{
- return __gpio_to_irq(gpio);
-}
-
-static inline int irq_to_gpio(unsigned int irq)
-{
- return -EINVAL;
-}
-
-#endif /* CONFIG_GPIOLIB */
-
-#endif /* __ASM_POWERPC_GPIO_H */
+#ifndef __LINUX_GPIO_H
+#warning Include linux/gpio.h instead of asm/gpio.h
+#include <linux/gpio.h>
+#endif
diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
index 1c324ff55ea8..612252388190 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -77,8 +77,27 @@
#define H_MR_CONDITION -43
#define H_NOT_ENOUGH_RESOURCES -44
#define H_R_STATE -45
-#define H_RESCINDEND -46
-#define H_MULTI_THREADS_ACTIVE -9005
+#define H_RESCINDED -46
+#define H_P2 -55
+#define H_P3 -56
+#define H_P4 -57
+#define H_P5 -58
+#define H_P6 -59
+#define H_P7 -60
+#define H_P8 -61
+#define H_P9 -62
+#define H_TOO_BIG -64
+#define H_OVERLAP -68
+#define H_INTERRUPT -69
+#define H_BAD_DATA -70
+#define H_NOT_ACTIVE -71
+#define H_SG_LIST -72
+#define H_OP_MODE -73
+#define H_COP_HW -74
+#define H_UNSUPPORTED_FLAG_START -256
+#define H_UNSUPPORTED_FLAG_END -511
+#define H_MULTI_THREADS_ACTIVE -9005
+#define H_OUTSTANDING_COP_OPS -9006
/* Long Busy is a condition that can be returned by the firmware
@@ -240,6 +259,8 @@
#define H_GET_MPP 0x2D4
#define H_HOME_NODE_ASSOCIATIVITY 0x2EC
#define H_BEST_ENERGY 0x2F4
+#define H_RANDOM 0x300
+#define H_COP 0x304
#define H_GET_MPP_X 0x314
#define MAX_HCALL_OPCODE H_GET_MPP_X
diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h
index a76254af0aaa..531fe0c3108f 100644
--- a/arch/powerpc/include/asm/lppaca.h
+++ b/arch/powerpc/include/asm/lppaca.h
@@ -20,18 +20,16 @@
#define _ASM_POWERPC_LPPACA_H
#ifdef __KERNEL__
-/* These definitions relate to hypervisors that only exist when using
+/*
+ * These definitions relate to hypervisors that only exist when using
* a server type processor
*/
#ifdef CONFIG_PPC_BOOK3S
-//=============================================================================
-//
-// This control block contains the data that is shared between the
-// hypervisor (PLIC) and the OS.
-//
-//
-//----------------------------------------------------------------------------
+/*
+ * This control block contains the data that is shared between the
+ * hypervisor and the OS.
+ */
#include <linux/cache.h>
#include <linux/threads.h>
#include <asm/types.h>
@@ -43,123 +41,65 @@
*/
#define NR_LPPACAS 1
-
-/* The Hypervisor barfs if the lppaca crosses a page boundary. A 1k
- * alignment is sufficient to prevent this */
+/*
+ * The Hypervisor barfs if the lppaca crosses a page boundary. A 1k
+ * alignment is sufficient to prevent this
+ */
struct lppaca {
-//=============================================================================
-// CACHE_LINE_1 0x0000 - 0x007F Contains read-only data
-// NOTE: The xDynXyz fields are fields that will be dynamically changed by
-// PLIC when preparing to bring a processor online or when dispatching a
-// virtual processor!
-//=============================================================================
- u32 desc; // Eye catcher 0xD397D781 x00-x03
- u16 size; // Size of this struct x04-x05
- u16 reserved1; // Reserved x06-x07
- u16 reserved2:14; // Reserved x08-x09
- u8 shared_proc:1; // Shared processor indicator ...
- u8 secondary_thread:1; // Secondary thread indicator ...
- volatile u8 dyn_proc_status:8; // Dynamic Status of this proc x0A-x0A
- u8 secondary_thread_count; // Secondary thread count x0B-x0B
- volatile u16 dyn_hv_phys_proc_index;// Dynamic HV Physical Proc Index0C-x0D
- volatile u16 dyn_hv_log_proc_index;// Dynamic HV Logical Proc Indexx0E-x0F
- u32 decr_val; // Value for Decr programming x10-x13
- u32 pmc_val; // Value for PMC regs x14-x17
- volatile u32 dyn_hw_node_id; // Dynamic Hardware Node id x18-x1B
- volatile u32 dyn_hw_proc_id; // Dynamic Hardware Proc Id x1C-x1F
- volatile u32 dyn_pir; // Dynamic ProcIdReg value x20-x23
- u32 dsei_data; // DSEI data x24-x27
- u64 sprg3; // SPRG3 value x28-x2F
- u8 reserved3[40]; // Reserved x30-x57
- volatile u8 vphn_assoc_counts[8]; // Virtual processor home node
- // associativity change counters x58-x5F
- u8 reserved4[32]; // Reserved x60-x7F
-
-//=============================================================================
-// CACHE_LINE_2 0x0080 - 0x00FF Contains local read-write data
-//=============================================================================
- // This Dword contains a byte for each type of interrupt that can occur.
- // The IPI is a count while the others are just a binary 1 or 0.
- union {
- u64 any_int;
- struct {
- u16 reserved; // Reserved - cleared by #mpasmbl
- u8 xirr_int; // Indicates xXirrValue is valid or Immed IO
- u8 ipi_cnt; // IPI Count
- u8 decr_int; // DECR interrupt occurred
- u8 pdc_int; // PDC interrupt occurred
- u8 quantum_int; // Interrupt quantum reached
- u8 old_plic_deferred_ext_int; // Old PLIC has a deferred XIRR pending
- } fields;
- } int_dword;
-
- // Whenever any fields in this Dword are set then PLIC will defer the
- // processing of external interrupts. Note that PLIC will store the
- // XIRR directly into the xXirrValue field so that another XIRR will
- // not be presented until this one clears. The layout of the low
- // 4-bytes of this Dword is up to SLIC - PLIC just checks whether the
- // entire Dword is zero or not. A non-zero value in the low order
- // 2-bytes will result in SLIC being granted the highest thread
- // priority upon return. A 0 will return to SLIC as medium priority.
- u64 plic_defer_ints_area; // Entire Dword
-
- // Used to pass the real SRR0/1 from PLIC to SLIC as well as to
- // pass the target SRR0/1 from SLIC to PLIC on a SetAsrAndRfid.
- u64 saved_srr0; // Saved SRR0 x10-x17
- u64 saved_srr1; // Saved SRR1 x18-x1F
-
- // Used to pass parms from the OS to PLIC for SetAsrAndRfid
- u64 saved_gpr3; // Saved GPR3 x20-x27
- u64 saved_gpr4; // Saved GPR4 x28-x2F
- union {
- u64 saved_gpr5; /* Saved GPR5 x30-x37 */
- struct {
- u8 cede_latency_hint; /* x30 */
- u8 reserved[7]; /* x31-x36 */
- } fields;
- } gpr5_dword;
-
-
- u8 dtl_enable_mask; // Dispatch Trace Log mask x38-x38
- u8 donate_dedicated_cpu; // Donate dedicated CPU cycles x39-x39
- u8 fpregs_in_use; // FP regs in use x3A-x3A
- u8 pmcregs_in_use; // PMC regs in use x3B-x3B
- volatile u32 saved_decr; // Saved Decr Value x3C-x3F
- volatile u64 emulated_time_base;// Emulated TB for this thread x40-x47
- volatile u64 cur_plic_latency; // Unaccounted PLIC latency x48-x4F
- u64 tot_plic_latency; // Accumulated PLIC latency x50-x57
- u64 wait_state_cycles; // Wait cycles for this proc x58-x5F
- u64 end_of_quantum; // TB at end of quantum x60-x67
- u64 pdc_saved_sprg1; // Saved SPRG1 for PMC int x68-x6F
- u64 pdc_saved_srr0; // Saved SRR0 for PMC int x70-x77
- volatile u32 virtual_decr; // Virtual DECR for shared procsx78-x7B
- u16 slb_count; // # of SLBs to maintain x7C-x7D
- u8 idle; // Indicate OS is idle x7E
- u8 vmxregs_in_use; // VMX registers in use x7F
-
-
-//=============================================================================
-// CACHE_LINE_3 0x0100 - 0x017F: This line is shared with other processors
-//=============================================================================
- // This is the yield_count. An "odd" value (low bit on) means that
- // the processor is yielded (either because of an OS yield or a PLIC
- // preempt). An even value implies that the processor is currently
- // executing.
- // NOTE: This value will ALWAYS be zero for dedicated processors and
- // will NEVER be zero for shared processors (ie, initialized to a 1).
- volatile u32 yield_count; // PLIC increments each dispatchx00-x03
- volatile u32 dispersion_count; // dispatch changed phys cpu x04-x07
- volatile u64 cmo_faults; // CMO page fault count x08-x0F
- volatile u64 cmo_fault_time; // CMO page fault time x10-x17
- u8 reserved7[104]; // Reserved x18-x7F
-
-//=============================================================================
-// CACHE_LINE_4-5 0x0180 - 0x027F Contains PMC interrupt data
-//=============================================================================
- u32 page_ins; // CMO Hint - # page ins by OS x00-x03
- u8 reserved8[148]; // Reserved x04-x97
- volatile u64 dtl_idx; // Dispatch Trace Log head idx x98-x9F
- u8 reserved9[96]; // Reserved xA0-xFF
+ /* cacheline 1 contains read-only data */
+
+ u32 desc; /* Eye catcher 0xD397D781 */
+ u16 size; /* Size of this struct */
+ u16 reserved1;
+ u16 reserved2:14;
+ u8 shared_proc:1; /* Shared processor indicator */
+ u8 secondary_thread:1; /* Secondary thread indicator */
+ u8 reserved3[14];
+ volatile u32 dyn_hw_node_id; /* Dynamic hardware node id */
+ volatile u32 dyn_hw_proc_id; /* Dynamic hardware proc id */
+ u8 reserved4[56];
+ volatile u8 vphn_assoc_counts[8]; /* Virtual processor home node */
+ /* associativity change counters */
+ u8 reserved5[32];
+
+ /* cacheline 2 contains local read-write data */
+
+ u8 reserved6[48];
+ u8 cede_latency_hint;
+ u8 reserved7[7];
+ u8 dtl_enable_mask; /* Dispatch Trace Log mask */
+ u8 donate_dedicated_cpu; /* Donate dedicated CPU cycles */
+ u8 fpregs_in_use;
+ u8 pmcregs_in_use;
+ u8 reserved8[28];
+ u64 wait_state_cycles; /* Wait cycles for this proc */
+ u8 reserved9[28];
+ u16 slb_count; /* # of SLBs to maintain */
+ u8 idle; /* Indicate OS is idle */
+ u8 vmxregs_in_use;
+
+ /* cacheline 3 is shared with other processors */
+
+ /*
+ * This is the yield_count. An "odd" value (low bit on) means that
+ * the processor is yielded (either because of an OS yield or a
+ * hypervisor preempt). An even value implies that the processor is
+ * currently executing.
+ * NOTE: This value will ALWAYS be zero for dedicated processors and
+ * will NEVER be zero for shared processors (ie, initialized to a 1).
+ */
+ volatile u32 yield_count;
+ volatile u32 dispersion_count; /* dispatch changed physical cpu */
+ volatile u64 cmo_faults; /* CMO page fault count */
+ volatile u64 cmo_fault_time; /* CMO page fault time */
+ u8 reserved10[104];
+
+ /* cacheline 4-5 */
+
+ u32 page_ins; /* CMO Hint - # page ins by OS */
+ u8 reserved11[148];
+ volatile u64 dtl_idx; /* Dispatch Trace Log head index */
+ u8 reserved12[96];
} __attribute__((__aligned__(0x400)));
extern struct lppaca lppaca[];
@@ -172,13 +112,13 @@ extern struct lppaca lppaca[];
* ESID is stored in the lower 64bits, then the VSID.
*/
struct slb_shadow {
- u32 persistent; // Number of persistent SLBs x00-x03
- u32 buffer_length; // Total shadow buffer length x04-x07
- u64 reserved; // Alignment x08-x0f
+ u32 persistent; /* Number of persistent SLBs */
+ u32 buffer_length; /* Total shadow buffer length */
+ u64 reserved;
struct {
u64 esid;
u64 vsid;
- } save_area[SLB_NUM_BOLTED]; // x10-x40
+ } save_area[SLB_NUM_BOLTED];
} ____cacheline_aligned;
extern struct slb_shadow slb_shadow[];
diff --git a/arch/powerpc/include/asm/lv1call.h b/arch/powerpc/include/asm/lv1call.h
index 233f9ecae761..f5117674bf92 100644
--- a/arch/powerpc/include/asm/lv1call.h
+++ b/arch/powerpc/include/asm/lv1call.h
@@ -265,8 +265,8 @@ LV1_CALL(get_spe_irq_outlet, 2, 1, 78 )
LV1_CALL(set_spe_privilege_state_area_1_register, 3, 0, 79 )
LV1_CALL(create_repository_node, 6, 0, 90 )
LV1_CALL(read_repository_node, 5, 2, 91 )
-LV1_CALL(modify_repository_node_value, 6, 0, 92 )
-LV1_CALL(remove_repository_node, 4, 0, 93 )
+LV1_CALL(write_repository_node, 6, 0, 92 )
+LV1_CALL(delete_repository_node, 4, 0, 93 )
LV1_CALL(read_htab_entries, 2, 5, 95 )
LV1_CALL(set_dabr, 2, 0, 96 )
LV1_CALL(get_total_execution_time, 2, 1, 103 )
diff --git a/arch/powerpc/include/asm/pSeries_reconfig.h b/arch/powerpc/include/asm/pSeries_reconfig.h
index 23cd6cc30bcf..c07edfe98b98 100644
--- a/arch/powerpc/include/asm/pSeries_reconfig.h
+++ b/arch/powerpc/include/asm/pSeries_reconfig.h
@@ -13,6 +13,18 @@
#define PSERIES_RECONFIG_REMOVE 0x0002
#define PSERIES_DRCONF_MEM_ADD 0x0003
#define PSERIES_DRCONF_MEM_REMOVE 0x0004
+#define PSERIES_UPDATE_PROPERTY 0x0005
+
+/**
+ * pSeries_reconfig_notify - Notifier value structure for OFDT property updates
+ *
+ * @node: Device tree node which owns the property being updated
+ * @property: Updated property
+ */
+struct pSeries_reconfig_prop_update {
+ struct device_node *node;
+ struct property *property;
+};
#ifdef CONFIG_PPC_PSERIES
extern int pSeries_reconfig_notifier_register(struct notifier_block *);
diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
index 50f73aa2ba21..15444204a3a1 100644
--- a/arch/powerpc/include/asm/ppc_asm.h
+++ b/arch/powerpc/include/asm/ppc_asm.h
@@ -369,7 +369,15 @@ BEGIN_FTR_SECTION \
END_FTR_SECTION_IFCLR(CPU_FTR_601)
#endif
-
+#ifdef CONFIG_PPC64
+#define MTOCRF(FXM, RS) \
+ BEGIN_FTR_SECTION_NESTED(848); \
+ mtcrf (FXM), (RS); \
+ FTR_SECTION_ELSE_NESTED(848); \
+ mtocrf (FXM), (RS); \
+ ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_NOEXECUTE, 848)
+#endif
+
/*
* This instruction is not implemented on the PPC 603 or 601; however, on
* the 403GCX and 405GP tlbia IS defined and tlbie is not.
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 48a26d379222..55e85631c42e 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -74,9 +74,6 @@ struct task_struct;
void start_thread(struct pt_regs *regs, unsigned long fdptr, unsigned long sp);
void release_thread(struct task_struct *);
-/* Prepare to copy thread state - unlazy all lazy status */
-extern void prepare_to_copy(struct task_struct *tsk);
-
/* Create a new kernel thread. */
extern long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h
index 84cc7840cd18..9c21ed42aba6 100644
--- a/arch/powerpc/include/asm/ptrace.h
+++ b/arch/powerpc/include/asm/ptrace.h
@@ -354,12 +354,6 @@ static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
#define PTRACE_GETREGS64 22
#define PTRACE_SETREGS64 23
-/* (old) PTRACE requests with inverted arguments */
-#define PPC_PTRACE_GETREGS 0x99 /* Get GPRs 0 - 31 */
-#define PPC_PTRACE_SETREGS 0x98 /* Set GPRs 0 - 31 */
-#define PPC_PTRACE_GETFPREGS 0x97 /* Get FPRs 0 - 31 */
-#define PPC_PTRACE_SETFPREGS 0x96 /* Set FPRs 0 - 31 */
-
/* Calls to trace a 64bit program from a 32bit program */
#define PPC_PTRACE_PEEKTEXT_3264 0x95
#define PPC_PTRACE_PEEKDATA_3264 0x94
diff --git a/arch/powerpc/include/asm/switch_to.h b/arch/powerpc/include/asm/switch_to.h
index caf82d0a00de..1a6320290d26 100644
--- a/arch/powerpc/include/asm/switch_to.h
+++ b/arch/powerpc/include/asm/switch_to.h
@@ -21,7 +21,6 @@ extern void disable_kernel_fp(void);
extern void enable_kernel_fp(void);
extern void flush_fp_to_thread(struct task_struct *);
extern void enable_kernel_altivec(void);
-extern void giveup_altivec(struct task_struct *);
extern void load_up_altivec(struct task_struct *);
extern int emulate_altivec(struct pt_regs *);
extern void __giveup_vsx(struct task_struct *);
@@ -40,10 +39,15 @@ static inline void discard_lazy_cpu_state(void)
#ifdef CONFIG_ALTIVEC
extern void flush_altivec_to_thread(struct task_struct *);
+extern void giveup_altivec(struct task_struct *);
+extern void giveup_altivec_notask(void);
#else
static inline void flush_altivec_to_thread(struct task_struct *t)
{
}
+static inline void giveup_altivec(struct task_struct *t)
+{
+}
#endif
#ifdef CONFIG_VSX
diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h
index 1a1bb00f061a..a556ccc16b58 100644
--- a/arch/powerpc/include/asm/thread_info.h
+++ b/arch/powerpc/include/asm/thread_info.h
@@ -113,7 +113,6 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_NOERROR (1<<TIF_NOERROR)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
#define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT)
-#define _TIF_RUNLATCH (1<<TIF_RUNLATCH)
#define _TIF_SYSCALL_T_OR_A (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
_TIF_SECCOMP | _TIF_SYSCALL_TRACEPOINT)
diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h
index c97185885c6d..852ed1b384f6 100644
--- a/arch/powerpc/include/asm/topology.h
+++ b/arch/powerpc/include/asm/topology.h
@@ -18,12 +18,6 @@ struct device_node;
*/
#define RECLAIM_DISTANCE 10
-/*
- * Avoid creating an extra level of balancing (SD_ALLNODES) on the largest
- * POWER7 boxes which have a maximum of 32 nodes.
- */
-#define SD_NODES_PER_DOMAIN 32
-
#include <asm/mmzone.h>
static inline int cpu_to_node(int cpu)
@@ -51,36 +45,6 @@ static inline int pcibus_to_node(struct pci_bus *bus)
cpu_all_mask : \
cpumask_of_node(pcibus_to_node(bus)))
-/* sched_domains SD_NODE_INIT for PPC64 machines */
-#define SD_NODE_INIT (struct sched_domain) { \
- .min_interval = 8, \
- .max_interval = 32, \
- .busy_factor = 32, \
- .imbalance_pct = 125, \
- .cache_nice_tries = 1, \
- .busy_idx = 3, \
- .idle_idx = 1, \
- .newidle_idx = 0, \
- .wake_idx = 0, \
- .forkexec_idx = 0, \
- \
- .flags = 1*SD_LOAD_BALANCE \
- | 0*SD_BALANCE_NEWIDLE \
- | 1*SD_BALANCE_EXEC \
- | 1*SD_BALANCE_FORK \
- | 0*SD_BALANCE_WAKE \
- | 1*SD_WAKE_AFFINE \
- | 0*SD_PREFER_LOCAL \
- | 0*SD_SHARE_CPUPOWER \
- | 0*SD_POWERSAVINGS_BALANCE \
- | 0*SD_SHARE_PKG_RESOURCES \
- | 1*SD_SERIALIZE \
- | 0*SD_PREFER_SIBLING \
- , \
- .last_balance = jiffies, \
- .balance_interval = 1, \
-}
-
extern int __node_distance(int, int);
#define node_distance(a, b) __node_distance(a, b)
diff --git a/arch/powerpc/include/asm/vio.h b/arch/powerpc/include/asm/vio.h
index 6bfd5ffe1d4f..b19adf751dd9 100644
--- a/arch/powerpc/include/asm/vio.h
+++ b/arch/powerpc/include/asm/vio.h
@@ -46,6 +46,48 @@
struct iommu_table;
+/*
+ * Platform Facilities Option (PFO)-specific data
+ */
+
+/* Starting unit address for PFO devices on the VIO BUS */
+#define VIO_BASE_PFO_UA 0x50000000
+
+/**
+ * vio_pfo_op - PFO operation parameters
+ *
+ * @flags: h_call subfunctions and modifiers
+ * @in: Input data block logical real address
+ * @inlen: If non-negative, the length of the input data block. If negative,
+ * the length of the input data descriptor list in bytes.
+ * @out: Output data block logical real address
+ * @outlen: If non-negative, the length of the input data block. If negative,
+ * the length of the input data descriptor list in bytes.
+ * @csbcpb: Logical real address of the 4k naturally-aligned storage block
+ * containing the CSB & optional FC field specific CPB
+ * @timeout: # of milliseconds to retry h_call, 0 for no timeout.
+ * @hcall_err: pointer to return the h_call return value, else NULL
+ */
+struct vio_pfo_op {
+ u64 flags;
+ s64 in;
+ s64 inlen;
+ s64 out;
+ s64 outlen;
+ u64 csbcpb;
+ void *done;
+ unsigned long handle;
+ unsigned int timeout;
+ long hcall_err;
+};
+
+/* End PFO specific data */
+
+enum vio_dev_family {
+ VDEVICE, /* The OF node is a child of /vdevice */
+ PFO, /* The OF node is a child of /ibm,platform-facilities */
+};
+
/**
* vio_dev - This structure is used to describe virtual I/O devices.
*
@@ -58,6 +100,7 @@ struct vio_dev {
const char *name;
const char *type;
uint32_t unit_address;
+ uint32_t resource_id;
unsigned int irq;
struct {
size_t desired;
@@ -65,6 +108,7 @@ struct vio_dev {
size_t allocated;
atomic_t allocs_failed;
} cmo;
+ enum vio_dev_family family;
struct device dev;
};
@@ -95,6 +139,8 @@ extern void vio_cmo_set_dev_desired(struct vio_dev *viodev, size_t desired);
extern void __devinit vio_unregister_device(struct vio_dev *dev);
+extern int vio_h_cop_sync(struct vio_dev *vdev, struct vio_pfo_op *op);
+
struct device_node;
extern struct vio_dev *vio_register_device_node(
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 34b8afe94a50..4554dc2fe857 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -188,10 +188,6 @@ int main(void)
DEFINE(SLBSHADOW_STACKESID,
offsetof(struct slb_shadow, save_area[SLB_NUM_BOLTED - 1].esid));
DEFINE(SLBSHADOW_SAVEAREA, offsetof(struct slb_shadow, save_area));
- DEFINE(LPPACASRR0, offsetof(struct lppaca, saved_srr0));
- DEFINE(LPPACASRR1, offsetof(struct lppaca, saved_srr1));
- DEFINE(LPPACAANYINT, offsetof(struct lppaca, int_dword.any_int));
- DEFINE(LPPACADECRINT, offsetof(struct lppaca, int_dword.fields.decr_int));
DEFINE(LPPACA_PMCINUSE, offsetof(struct lppaca, pmcregs_in_use));
DEFINE(LPPACA_DTLIDX, offsetof(struct lppaca, dtl_idx));
DEFINE(LPPACA_YIELDCOUNT, offsetof(struct lppaca, yield_count));
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index ef2074c3e906..ed1718feb9d9 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -63,15 +63,9 @@ system_call_common:
std r0,GPR0(r1)
std r10,GPR1(r1)
ACCOUNT_CPU_USER_ENTRY(r10, r11)
- /*
- * This "crclr so" clears CR0.SO, which is the error indication on
- * return from this system call. There must be no cmp instruction
- * between it and the "mfcr r9" below, otherwise if XER.SO is set,
- * CR0.SO will get set, causing all system calls to appear to fail.
- */
- crclr so
std r2,GPR2(r1)
std r3,GPR3(r1)
+ mfcr r2
std r4,GPR4(r1)
std r5,GPR5(r1)
std r6,GPR6(r1)
@@ -82,18 +76,20 @@ system_call_common:
std r11,GPR10(r1)
std r11,GPR11(r1)
std r11,GPR12(r1)
+ std r11,_XER(r1)
+ std r11,_CTR(r1)
std r9,GPR13(r1)
- mfcr r9
mflr r10
+ /*
+ * This clears CR0.SO (bit 28), which is the error indication on
+ * return from this system call.
+ */
+ rldimi r2,r11,28,(63-28)
li r11,0xc01
- std r9,_CCR(r1)
std r10,_LINK(r1)
std r11,_TRAP(r1)
- mfxer r9
- mfctr r10
- std r9,_XER(r1)
- std r10,_CTR(r1)
std r3,ORIG_GPR3(r1)
+ std r2,_CCR(r1)
ld r2,PACATOC(r13)
addi r9,r1,STACK_FRAME_OVERHEAD
ld r11,exception_marker@toc(r2)
@@ -154,7 +150,7 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
ld r10,TI_FLAGS(r11)
andi. r11,r10,_TIF_SYSCALL_T_OR_A
bne- syscall_dotrace
-syscall_dotrace_cont:
+.Lsyscall_dotrace_cont:
cmpldi 0,r0,NR_syscalls
bge- syscall_enosys
@@ -211,7 +207,7 @@ syscall_exit:
cmpld r3,r11
ld r5,_CCR(r1)
bge- syscall_error
-syscall_error_cont:
+.Lsyscall_error_cont:
ld r7,_NIP(r1)
BEGIN_FTR_SECTION
stdcx. r0,0,r1 /* to clear the reservation */
@@ -246,7 +242,7 @@ syscall_error:
oris r5,r5,0x1000 /* Set SO bit in CR */
neg r3,r3
std r5,_CCR(r1)
- b syscall_error_cont
+ b .Lsyscall_error_cont
/* Traced system call support */
syscall_dotrace:
@@ -268,7 +264,7 @@ syscall_dotrace:
addi r9,r1,STACK_FRAME_OVERHEAD
clrrdi r10,r1,THREAD_SHIFT
ld r10,TI_FLAGS(r10)
- b syscall_dotrace_cont
+ b .Lsyscall_dotrace_cont
syscall_enosys:
li r3,-ENOSYS
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 8f880bc77c56..f7bed44ee165 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -94,12 +94,10 @@ machine_check_pSeries_1:
data_access_pSeries:
HMT_MEDIUM
SET_SCRATCH0(r13)
-#ifndef CONFIG_POWER4_ONLY
BEGIN_FTR_SECTION
b data_access_check_stab
data_access_not_stab:
END_MMU_FTR_SECTION_IFCLR(MMU_FTR_SLB)
-#endif
EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common, EXC_STD,
KVMTEST, 0x300)
@@ -301,7 +299,6 @@ machine_check_fwnmi:
EXC_STD, KVMTEST, 0x200)
KVM_HANDLER_SKIP(PACA_EXMC, EXC_STD, 0x200)
-#ifndef CONFIG_POWER4_ONLY
/* moved from 0x300 */
data_access_check_stab:
GET_PACA(r13)
@@ -328,7 +325,6 @@ do_stab_bolted_pSeries:
GET_SCRATCH0(r10)
std r10,PACA_EXSLB+EX_R13(r13)
EXCEPTION_PROLOG_PSERIES_1(.do_stab_bolted, EXC_STD)
-#endif /* CONFIG_POWER4_ONLY */
KVM_HANDLER_SKIP(PACA_EXGEN, EXC_STD, 0x300)
KVM_HANDLER_SKIP(PACA_EXSLB, EXC_STD, 0x380)
diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S
index 7dd2981bcc50..22d608e8bb7d 100644
--- a/arch/powerpc/kernel/head_44x.S
+++ b/arch/powerpc/kernel/head_44x.S
@@ -778,14 +778,6 @@ _GLOBAL(__fixup_440A_mcheck)
blr
/*
- * extern void giveup_altivec(struct task_struct *prev)
- *
- * The 44x core does not have an AltiVec unit.
- */
-_GLOBAL(giveup_altivec)
- blr
-
-/*
* extern void giveup_fpu(struct task_struct *prev)
*
* The 44x core does not have an FPU.
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index 28e62598d0e8..de80e0f9a2bd 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -874,14 +874,6 @@ _GLOBAL(__setup_e500mc_ivors)
sync
blr
-/*
- * extern void giveup_altivec(struct task_struct *prev)
- *
- * The e500 core does not have an AltiVec unit.
- */
-_GLOBAL(giveup_altivec)
- blr
-
#ifdef CONFIG_SPE
/*
* extern void giveup_spe(struct task_struct *prev)
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 641da9e868ce..7835a5e1ea5f 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -587,7 +587,7 @@ int irq_choose_cpu(const struct cpumask *mask)
{
int cpuid;
- if (cpumask_equal(mask, cpu_all_mask)) {
+ if (cpumask_equal(mask, cpu_online_mask)) {
static int irq_rover;
static DEFINE_RAW_SPINLOCK(irq_rover_lock);
unsigned long flags;
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 7cd07b42ca1a..386d57f66f28 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -738,8 +738,23 @@ relocate_new_kernel:
mr r5, r31
li r0, 0
-#elif defined(CONFIG_44x) && !defined(CONFIG_PPC_47x)
+#elif defined(CONFIG_44x)
+ /* Save our parameters */
+ mr r29, r3
+ mr r30, r4
+ mr r31, r5
+
+#ifdef CONFIG_PPC_47x
+ /* Check for 47x cores */
+ mfspr r3,SPRN_PVR
+ srwi r3,r3,16
+ cmplwi cr0,r3,PVR_476@h
+ beq setup_map_47x
+ cmplwi cr0,r3,PVR_476_ISS@h
+ beq setup_map_47x
+#endif /* CONFIG_PPC_47x */
+
/*
* Code for setting up 1:1 mapping for PPC440x for KEXEC
*
@@ -753,16 +768,15 @@ relocate_new_kernel:
* 5) Invalidate the tmp mapping.
*
* - Based on the kexec support code for FSL BookE
- * - Doesn't support 47x yet.
*
*/
- /* Save our parameters */
- mr r29, r3
- mr r30, r4
- mr r31, r5
- /* Load our MSR_IS and TID to MMUCR for TLB search */
- mfspr r3,SPRN_PID
+ /*
+ * Load the PID with kernel PID (0).
+ * Also load our MSR_IS and TID to MMUCR for TLB search.
+ */
+ li r3, 0
+ mtspr SPRN_PID, r3
mfmsr r4
andi. r4,r4,MSR_IS@l
beq wmmucr
@@ -900,6 +914,179 @@ next_tlb:
li r3, 0
tlbwe r3, r24, PPC44x_TLB_PAGEID
sync
+ b ppc44x_map_done
+
+#ifdef CONFIG_PPC_47x
+
+ /* 1:1 mapping for 47x */
+
+setup_map_47x:
+
+ /*
+ * Load the kernel pid (0) to PID and also to MMUCR[TID].
+ * Also set the MSR IS->MMUCR STS
+ */
+ li r3, 0
+ mtspr SPRN_PID, r3 /* Set PID */
+ mfmsr r4 /* Get MSR */
+ andi. r4, r4, MSR_IS@l /* TS=1? */
+ beq 1f /* If not, leave STS=0 */
+ oris r3, r3, PPC47x_MMUCR_STS@h /* Set STS=1 */
+1: mtspr SPRN_MMUCR, r3 /* Put MMUCR */
+ sync
+
+ /* Find the entry we are running from */
+ bl 2f
+2: mflr r23
+ tlbsx r23, 0, r23
+ tlbre r24, r23, 0 /* TLB Word 0 */
+ tlbre r25, r23, 1 /* TLB Word 1 */
+ tlbre r26, r23, 2 /* TLB Word 2 */
+
+
+ /*
+ * Invalidates all the tlb entries by writing to 256 RPNs(r4)
+ * of 4k page size in all 4 ways (0-3 in r3).
+ * This would invalidate the entire UTLB including the one we are
+ * running from. However the shadow TLB entries would help us
+ * to continue the execution, until we flush them (rfi/isync).
+ */
+ addis r3, 0, 0x8000 /* specify the way */
+ addi r4, 0, 0 /* TLB Word0 = (EPN=0, VALID = 0) */
+ addi r5, 0, 0
+ b clear_utlb_entry
+
+ /* Align the loop to speed things up. from head_44x.S */
+ .align 6
+
+clear_utlb_entry:
+
+ tlbwe r4, r3, 0
+ tlbwe r5, r3, 1
+ tlbwe r5, r3, 2
+ addis r3, r3, 0x2000 /* Increment the way */
+ cmpwi r3, 0
+ bne clear_utlb_entry
+ addis r3, 0, 0x8000
+ addis r4, r4, 0x100 /* Increment the EPN */
+ cmpwi r4, 0
+ bne clear_utlb_entry
+
+ /* Create the entries in the other address space */
+ mfmsr r5
+ rlwinm r7, r5, 27, 31, 31 /* Get the TS (Bit 26) from MSR */
+ xori r7, r7, 1 /* r7 = !TS */
+
+ insrwi r24, r7, 1, 21 /* Change the TS in the saved TLB word 0 */
+
+ /*
+ * write out the TLB entries for the tmp mapping
+ * Use way '0' so that we could easily invalidate it later.
+ */
+ lis r3, 0x8000 /* Way '0' */
+
+ tlbwe r24, r3, 0
+ tlbwe r25, r3, 1
+ tlbwe r26, r3, 2
+
+ /* Update the msr to the new TS */
+ insrwi r5, r7, 1, 26
+
+ bl 1f
+1: mflr r6
+ addi r6, r6, (2f-1b)
+
+ mtspr SPRN_SRR0, r6
+ mtspr SPRN_SRR1, r5
+ rfi
+
+ /*
+ * Now we are in the tmp address space.
+ * Create a 1:1 mapping for 0-2GiB in the original TS.
+ */
+2:
+ li r3, 0
+ li r4, 0 /* TLB Word 0 */
+ li r5, 0 /* TLB Word 1 */
+ li r6, 0
+ ori r6, r6, PPC47x_TLB2_S_RWX /* TLB word 2 */
+
+ li r8, 0 /* PageIndex */
+
+ xori r7, r7, 1 /* revert back to original TS */
+
+write_utlb:
+ rotlwi r5, r8, 28 /* RPN = PageIndex * 256M */
+ /* ERPN = 0 as we don't use memory above 2G */
+
+ mr r4, r5 /* EPN = RPN */
+ ori r4, r4, (PPC47x_TLB0_VALID | PPC47x_TLB0_256M)
+ insrwi r4, r7, 1, 21 /* Insert the TS to Word 0 */
+
+ tlbwe r4, r3, 0 /* Write out the entries */
+ tlbwe r5, r3, 1
+ tlbwe r6, r3, 2
+ addi r8, r8, 1
+ cmpwi r8, 8 /* Have we completed ? */
+ bne write_utlb
+
+ /* make sure we complete the TLB write up */
+ isync
+
+ /*
+ * Prepare to jump to the 1:1 mapping.
+ * 1) Extract page size of the tmp mapping
+ * DSIZ = TLB_Word0[22:27]
+ * 2) Calculate the physical address of the address
+ * to jump to.
+ */
+ rlwinm r10, r24, 0, 22, 27
+
+ cmpwi r10, PPC47x_TLB0_4K
+ bne 0f
+ li r10, 0x1000 /* r10 = 4k */
+ bl 1f
+
+0:
+ /* Defaults to 256M */
+ lis r10, 0x1000
+
+ bl 1f
+1: mflr r4
+ addi r4, r4, (2f-1b) /* virtual address of 2f */
+
+ subi r11, r10, 1 /* offsetmask = Pagesize - 1 */
+ not r10, r11 /* Pagemask = ~(offsetmask) */
+
+ and r5, r25, r10 /* Physical page */
+ and r6, r4, r11 /* offset within the current page */
+
+ or r5, r5, r6 /* Physical address for 2f */
+
+ /* Switch the TS in MSR to the original one */
+ mfmsr r8
+ insrwi r8, r7, 1, 26
+
+ mtspr SPRN_SRR1, r8
+ mtspr SPRN_SRR0, r5
+ rfi
+
+2:
+ /* Invalidate the tmp mapping */
+ lis r3, 0x8000 /* Way '0' */
+
+ clrrwi r24, r24, 12 /* Clear the valid bit */
+ tlbwe r24, r3, 0
+ tlbwe r25, r3, 1
+ tlbwe r26, r3, 2
+
+ /* Make sure we complete the TLB write and flush the shadow TLB */
+ isync
+
+#endif
+
+ppc44x_map_done:
+
/* Restore the parameters */
mr r3, r29
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index 0bb1f98613ba..fbe1a12dc7f1 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -36,10 +36,7 @@ struct lppaca lppaca[] = {
[0 ... (NR_LPPACAS-1)] = {
.desc = 0xd397d781, /* "LpPa" */
.size = sizeof(struct lppaca),
- .dyn_proc_status = 2,
- .decr_val = 0x00ff0000,
.fpregs_in_use = 1,
- .end_of_quantum = 0xfffffffffffffffful,
.slb_count = 64,
.vmxregs_in_use = 0,
.page_ins = 0,
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index aa05935b6947..710f400476de 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -124,7 +124,7 @@ void enable_kernel_altivec(void)
if (current->thread.regs && (current->thread.regs->msr & MSR_VEC))
giveup_altivec(current);
else
- giveup_altivec(NULL); /* just enable AltiVec for kernel - force */
+ giveup_altivec_notask();
#else
giveup_altivec(last_task_used_altivec);
#endif /* CONFIG_SMP */
@@ -711,18 +711,21 @@ release_thread(struct task_struct *t)
}
/*
- * This gets called before we allocate a new thread and copy
- * the current task into it.
+ * this gets called so that we can store coprocessor state into memory and
+ * copy the current task into the new thread.
*/
-void prepare_to_copy(struct task_struct *tsk)
+int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
{
- flush_fp_to_thread(current);
- flush_altivec_to_thread(current);
- flush_vsx_to_thread(current);
- flush_spe_to_thread(current);
+ flush_fp_to_thread(src);
+ flush_altivec_to_thread(src);
+ flush_vsx_to_thread(src);
+ flush_spe_to_thread(src);
#ifdef CONFIG_HAVE_HW_BREAKPOINT
- flush_ptrace_hw_breakpoint(tsk);
+ flush_ptrace_hw_breakpoint(src);
#endif /* CONFIG_HAVE_HW_BREAKPOINT */
+
+ *dst = *src;
+ return 0;
}
/*
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index 99860273211b..1b488e5305c5 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -680,6 +680,9 @@ static void __init early_cmdline_parse(void)
#define OV3_VMX 0x40 /* VMX/Altivec */
#define OV3_DFP 0x20 /* decimal FP */
+/* Option vector 4: IBM PAPR implementation */
+#define OV4_MIN_ENT_CAP 0x01 /* minimum VP entitled capacity */
+
/* Option vector 5: PAPR/OF options supported */
#define OV5_LPAR 0x80 /* logical partitioning supported */
#define OV5_SPLPAR 0x40 /* shared-processor LPAR supported */
@@ -701,6 +704,8 @@ static void __init early_cmdline_parse(void)
#define OV5_XCMO 0x00
#endif
#define OV5_TYPE1_AFFINITY 0x80 /* Type 1 NUMA affinity */
+#define OV5_PFO_HW_RNG 0x80 /* PFO Random Number Generator */
+#define OV5_PFO_HW_ENCR 0x20 /* PFO Encryption Accelerator */
/* Option Vector 6: IBM PAPR hints */
#define OV6_LINUX 0x02 /* Linux is our OS */
@@ -744,11 +749,12 @@ static unsigned char ibm_architecture_vec[] = {
OV3_FP | OV3_VMX | OV3_DFP,
/* option vector 4: IBM PAPR implementation */
- 2 - 2, /* length */
+ 3 - 2, /* length */
0, /* don't halt */
+ OV4_MIN_ENT_CAP, /* minimum VP entitled capacity */
/* option vector 5: PAPR/OF options */
- 13 - 2, /* length */
+ 18 - 2, /* length */
0, /* don't ignore, don't halt */
OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY |
OV5_DONATE_DEDICATE_CPU | OV5_MSI,
@@ -762,8 +768,13 @@ static unsigned char ibm_architecture_vec[] = {
* must match by the macro below. Update the definition if
* the structure layout changes.
*/
-#define IBM_ARCH_VEC_NRCORES_OFFSET 100
+#define IBM_ARCH_VEC_NRCORES_OFFSET 101
W(NR_CPUS), /* number of cores supported */
+ 0,
+ 0,
+ 0,
+ 0,
+ OV5_PFO_HW_RNG | OV5_PFO_HW_ENCR,
/* option vector 6: IBM PAPR hints */
4 - 2, /* length */
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index dd5e214cdf21..c10fc28b9092 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -1432,40 +1432,6 @@ static long ppc_del_hwdebug(struct task_struct *child, long addr, long data)
#endif
}
-/*
- * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls,
- * we mark them as obsolete now, they will be removed in a future version
- */
-static long arch_ptrace_old(struct task_struct *child, long request,
- unsigned long addr, unsigned long data)
-{
- void __user *datavp = (void __user *) data;
-
- switch (request) {
- case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
- return copy_regset_to_user(child, &user_ppc_native_view,
- REGSET_GPR, 0, 32 * sizeof(long),
- datavp);
-
- case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
- return copy_regset_from_user(child, &user_ppc_native_view,
- REGSET_GPR, 0, 32 * sizeof(long),
- datavp);
-
- case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */
- return copy_regset_to_user(child, &user_ppc_native_view,
- REGSET_FPR, 0, 32 * sizeof(double),
- datavp);
-
- case PPC_PTRACE_SETFPREGS: /* Set FPRs 0 - 31. */
- return copy_regset_from_user(child, &user_ppc_native_view,
- REGSET_FPR, 0, 32 * sizeof(double),
- datavp);
- }
-
- return -EPERM;
-}
-
long arch_ptrace(struct task_struct *child, long request,
unsigned long addr, unsigned long data)
{
@@ -1687,14 +1653,6 @@ long arch_ptrace(struct task_struct *child, long request,
datavp);
#endif
- /* Old reverse args ptrace callss */
- case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
- case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
- case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */
- case PPC_PTRACE_SETFPREGS: /* Get FPRs 0 - 31. */
- ret = arch_ptrace_old(child, request, addr, data);
- break;
-
default:
ret = ptrace_request(child, request, addr, data);
break;
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c
index 469349d14a97..8c21658719d9 100644
--- a/arch/powerpc/kernel/ptrace32.c
+++ b/arch/powerpc/kernel/ptrace32.c
@@ -39,30 +39,6 @@
* in exit.c or in signal.c.
*/
-/*
- * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls,
- * we mark them as obsolete now, they will be removed in a future version
- */
-static long compat_ptrace_old(struct task_struct *child, long request,
- long addr, long data)
-{
- switch (request) {
- case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
- return copy_regset_to_user(child,
- task_user_regset_view(current), 0,
- 0, 32 * sizeof(compat_long_t),
- compat_ptr(data));
-
- case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
- return copy_regset_from_user(child,
- task_user_regset_view(current), 0,
- 0, 32 * sizeof(compat_long_t),
- compat_ptr(data));
- }
-
- return -EPERM;
-}
-
/* Macros to workout the correct index for the FPR in the thread struct */
#define FPRNUMBER(i) (((i) - PT_FPR0) >> 1)
#define FPRHALF(i) (((i) - PT_FPR0) & 1)
@@ -308,8 +284,6 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
case PTRACE_SETVSRREGS:
case PTRACE_GETREGS64:
case PTRACE_SETREGS64:
- case PPC_PTRACE_GETFPREGS:
- case PPC_PTRACE_SETFPREGS:
case PTRACE_KILL:
case PTRACE_SINGLESTEP:
case PTRACE_DETACH:
@@ -322,12 +296,6 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
ret = arch_ptrace(child, request, addr, data);
break;
- /* Old reverse args ptrace callss */
- case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
- case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
- ret = compat_ptrace_old(child, request, addr, data);
- break;
-
default:
ret = compat_ptrace_request(child, request, addr, data);
break;
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 45eb998557f8..61f6aff25edc 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -204,10 +204,10 @@ static inline int get_old_sigaction(struct k_sigaction *new_ka,
if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(new_ka->sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka->sa.sa_restorer, &act->sa_restorer))
+ __get_user(new_ka->sa.sa_restorer, &act->sa_restorer) ||
+ __get_user(new_ka->sa.sa_flags, &act->sa_flags) ||
+ __get_user(mask, &act->sa_mask))
return -EFAULT;
- __get_user(new_ka->sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
siginitset(&new_ka->sa.sa_mask, mask);
return 0;
}
@@ -244,17 +244,8 @@ static inline int restore_general_regs(struct pt_regs *regs,
long sys_sigsuspend(old_sigset_t mask)
{
sigset_t blocked;
-
- current->saved_sigmask = current->blocked;
-
- mask &= _BLOCKABLE;
siginitset(&blocked, mask);
- set_current_blocked(&blocked);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_restore_sigmask();
- return -ERESTARTNOHAND;
+ return sigsuspend(&blocked);
}
long sys_sigaction(int sig, struct old_sigaction __user *act,
diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S
index 4d5a3edff49e..e830289d2e48 100644
--- a/arch/powerpc/kernel/vector.S
+++ b/arch/powerpc/kernel/vector.S
@@ -89,6 +89,16 @@ _GLOBAL(load_up_altivec)
/* restore registers and return */
blr
+_GLOBAL(giveup_altivec_notask)
+ mfmsr r3
+ andis. r4,r3,MSR_VEC@h
+ bnelr /* Already enabled? */
+ oris r3,r3,MSR_VEC@h
+ SYNC
+ MTMSRD(r3) /* enable use of VMX now */
+ isync
+ blr
+
/*
* giveup_altivec(tsk)
* Disable VMX for the task given as the argument,
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index a3a99901c8ec..cb87301ccd55 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -14,7 +14,9 @@
* 2 of the License, or (at your option) any later version.
*/
+#include <linux/cpu.h>
#include <linux/types.h>
+#include <linux/delay.h>
#include <linux/stat.h>
#include <linux/device.h>
#include <linux/init.h>
@@ -709,13 +711,26 @@ static int vio_cmo_bus_probe(struct vio_dev *viodev)
struct vio_driver *viodrv = to_vio_driver(dev->driver);
unsigned long flags;
size_t size;
+ bool dma_capable = false;
+
+ /* A device requires entitlement if it has a DMA window property */
+ switch (viodev->family) {
+ case VDEVICE:
+ if (of_get_property(viodev->dev.of_node,
+ "ibm,my-dma-window", NULL))
+ dma_capable = true;
+ break;
+ case PFO:
+ dma_capable = false;
+ break;
+ default:
+ dev_warn(dev, "unknown device family: %d\n", viodev->family);
+ BUG();
+ break;
+ }
- /*
- * Check to see that device has a DMA window and configure
- * entitlement for the device.
- */
- if (of_get_property(viodev->dev.of_node,
- "ibm,my-dma-window", NULL)) {
+ /* Configure entitlement for the device. */
+ if (dma_capable) {
/* Check that the driver is CMO enabled and get desired DMA */
if (!viodrv->get_desired_dma) {
dev_err(dev, "%s: device driver does not support CMO\n",
@@ -1050,6 +1065,94 @@ static void vio_cmo_sysfs_init(void) { }
EXPORT_SYMBOL(vio_cmo_entitlement_update);
EXPORT_SYMBOL(vio_cmo_set_dev_desired);
+
+/*
+ * Platform Facilities Option (PFO) support
+ */
+
+/**
+ * vio_h_cop_sync - Perform a synchronous PFO co-processor operation
+ *
+ * @vdev - Pointer to a struct vio_dev for device
+ * @op - Pointer to a struct vio_pfo_op for the operation parameters
+ *
+ * Calls the hypervisor to synchronously perform the PFO operation
+ * described in @op. In the case of a busy response from the hypervisor,
+ * the operation will be re-submitted indefinitely unless a non-zero timeout
+ * is specified or an error occurs. The timeout places a limit on when to
+ * stop re-submitting a operation, the total time can be exceeded if an
+ * operation is in progress.
+ *
+ * If op->hcall_ret is not NULL, this will be set to the return from the
+ * last h_cop_op call or it will be 0 if an error not involving the h_call
+ * was encountered.
+ *
+ * Returns:
+ * 0 on success,
+ * -EINVAL if the h_call fails due to an invalid parameter,
+ * -E2BIG if the h_call can not be performed synchronously,
+ * -EBUSY if a timeout is specified and has elapsed,
+ * -EACCES if the memory area for data/status has been rescinded, or
+ * -EPERM if a hardware fault has been indicated
+ */
+int vio_h_cop_sync(struct vio_dev *vdev, struct vio_pfo_op *op)
+{
+ struct device *dev = &vdev->dev;
+ unsigned long deadline = 0;
+ long hret = 0;
+ int ret = 0;
+
+ if (op->timeout)
+ deadline = jiffies + msecs_to_jiffies(op->timeout);
+
+ while (true) {
+ hret = plpar_hcall_norets(H_COP, op->flags,
+ vdev->resource_id,
+ op->in, op->inlen, op->out,
+ op->outlen, op->csbcpb);
+
+ if (hret == H_SUCCESS ||
+ (hret != H_NOT_ENOUGH_RESOURCES &&
+ hret != H_BUSY && hret != H_RESOURCE) ||
+ (op->timeout && time_after(deadline, jiffies)))
+ break;
+
+ dev_dbg(dev, "%s: hcall ret(%ld), retrying.\n", __func__, hret);
+ }
+
+ switch (hret) {
+ case H_SUCCESS:
+ ret = 0;
+ break;
+ case H_OP_MODE:
+ case H_TOO_BIG:
+ ret = -E2BIG;
+ break;
+ case H_RESCINDED:
+ ret = -EACCES;
+ break;
+ case H_HARDWARE:
+ ret = -EPERM;
+ break;
+ case H_NOT_ENOUGH_RESOURCES:
+ case H_RESOURCE:
+ case H_BUSY:
+ ret = -EBUSY;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret)
+ dev_dbg(dev, "%s: Sync h_cop_op failure (ret:%d) (hret:%ld)\n",
+ __func__, ret, hret);
+
+ op->hcall_err = hret;
+ return ret;
+}
+EXPORT_SYMBOL(vio_h_cop_sync);
+
static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)
{
const unsigned char *dma_window;
@@ -1211,35 +1314,87 @@ static void __devinit vio_dev_release(struct device *dev)
struct vio_dev *vio_register_device_node(struct device_node *of_node)
{
struct vio_dev *viodev;
+ struct device_node *parent_node;
const unsigned int *unit_address;
+ const unsigned int *pfo_resid = NULL;
+ enum vio_dev_family family;
+ const char *of_node_name = of_node->name ? of_node->name : "<unknown>";
- /* we need the 'device_type' property, in order to match with drivers */
- if (of_node->type == NULL) {
- printk(KERN_WARNING "%s: node %s missing 'device_type'\n",
- __func__,
- of_node->name ? of_node->name : "<unknown>");
+ /*
+ * Determine if this node is a under the /vdevice node or under the
+ * /ibm,platform-facilities node. This decides the device's family.
+ */
+ parent_node = of_get_parent(of_node);
+ if (parent_node) {
+ if (!strcmp(parent_node->full_name, "/ibm,platform-facilities"))
+ family = PFO;
+ else if (!strcmp(parent_node->full_name, "/vdevice"))
+ family = VDEVICE;
+ else {
+ pr_warn("%s: parent(%s) of %s not recognized.\n",
+ __func__,
+ parent_node->full_name,
+ of_node_name);
+ of_node_put(parent_node);
+ return NULL;
+ }
+ of_node_put(parent_node);
+ } else {
+ pr_warn("%s: could not determine the parent of node %s.\n",
+ __func__, of_node_name);
return NULL;
}
- unit_address = of_get_property(of_node, "reg", NULL);
- if (unit_address == NULL) {
- printk(KERN_WARNING "%s: node %s missing 'reg'\n",
- __func__,
- of_node->name ? of_node->name : "<unknown>");
- return NULL;
+ if (family == PFO) {
+ if (of_get_property(of_node, "interrupt-controller", NULL)) {
+ pr_debug("%s: Skipping the interrupt controller %s.\n",
+ __func__, of_node_name);
+ return NULL;
+ }
}
/* allocate a vio_dev for this node */
viodev = kzalloc(sizeof(struct vio_dev), GFP_KERNEL);
- if (viodev == NULL)
+ if (viodev == NULL) {
+ pr_warn("%s: allocation failure for VIO device.\n", __func__);
return NULL;
+ }
- viodev->irq = irq_of_parse_and_map(of_node, 0);
+ /* we need the 'device_type' property, in order to match with drivers */
+ viodev->family = family;
+ if (viodev->family == VDEVICE) {
+ if (of_node->type != NULL)
+ viodev->type = of_node->type;
+ else {
+ pr_warn("%s: node %s is missing the 'device_type' "
+ "property.\n", __func__, of_node_name);
+ goto out;
+ }
+
+ unit_address = of_get_property(of_node, "reg", NULL);
+ if (unit_address == NULL) {
+ pr_warn("%s: node %s missing 'reg'\n",
+ __func__, of_node_name);
+ goto out;
+ }
+ dev_set_name(&viodev->dev, "%x", *unit_address);
+ viodev->irq = irq_of_parse_and_map(of_node, 0);
+ viodev->unit_address = *unit_address;
+ } else {
+ /* PFO devices need their resource_id for submitting COP_OPs
+ * This is an optional field for devices, but is required when
+ * performing synchronous ops */
+ pfo_resid = of_get_property(of_node, "ibm,resource-id", NULL);
+ if (pfo_resid != NULL)
+ viodev->resource_id = *pfo_resid;
+
+ unit_address = NULL;
+ dev_set_name(&viodev->dev, "%s", of_node_name);
+ viodev->type = of_node_name;
+ viodev->irq = 0;
+ }
- dev_set_name(&viodev->dev, "%x", *unit_address);
viodev->name = of_node->name;
- viodev->type = of_node->type;
- viodev->unit_address = *unit_address;
viodev->dev.of_node = of_node_get(of_node);
if (firmware_has_feature(FW_FEATURE_CMO))
@@ -1267,16 +1422,51 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node)
}
return viodev;
+
+out: /* Use this exit point for any return prior to device_register */
+ kfree(viodev);
+
+ return NULL;
}
EXPORT_SYMBOL(vio_register_device_node);
+/*
+ * vio_bus_scan_for_devices - Scan OF and register each child device
+ * @root_name - OF node name for the root of the subtree to search.
+ * This must be non-NULL
+ *
+ * Starting from the root node provide, register the device node for
+ * each child beneath the root.
+ */
+static void vio_bus_scan_register_devices(char *root_name)
+{
+ struct device_node *node_root, *node_child;
+
+ if (!root_name)
+ return;
+
+ node_root = of_find_node_by_name(NULL, root_name);
+ if (node_root) {
+
+ /*
+ * Create struct vio_devices for each virtual device in
+ * the device tree. Drivers will associate with them later.
+ */
+ node_child = of_get_next_child(node_root, NULL);
+ while (node_child) {
+ vio_register_device_node(node_child);
+ node_child = of_get_next_child(node_root, node_child);
+ }
+ of_node_put(node_root);
+ }
+}
+
/**
* vio_bus_init: - Initialize the virtual IO bus
*/
static int __init vio_bus_init(void)
{
int err;
- struct device_node *node_vroot;
if (firmware_has_feature(FW_FEATURE_CMO))
vio_cmo_sysfs_init();
@@ -1301,19 +1491,8 @@ static int __init vio_bus_init(void)
if (firmware_has_feature(FW_FEATURE_CMO))
vio_cmo_bus_init();
- node_vroot = of_find_node_by_name(NULL, "vdevice");
- if (node_vroot) {
- struct device_node *of_node;
-
- /*
- * Create struct vio_devices for each virtual device in
- * the device tree. Drivers will associate with them later.
- */
- for (of_node = node_vroot->child; of_node != NULL;
- of_node = of_node->sibling)
- vio_register_device_node(of_node);
- of_node_put(node_vroot);
- }
+ vio_bus_scan_register_devices("vdevice");
+ vio_bus_scan_register_devices("ibm,platform-facilities");
return 0;
}
@@ -1436,12 +1615,28 @@ struct vio_dev *vio_find_node(struct device_node *vnode)
{
const uint32_t *unit_address;
char kobj_name[20];
+ struct device_node *vnode_parent;
+ const char *dev_type;
+
+ vnode_parent = of_get_parent(vnode);
+ if (!vnode_parent)
+ return NULL;
+
+ dev_type = of_get_property(vnode_parent, "device_type", NULL);
+ of_node_put(vnode_parent);
+ if (!dev_type)
+ return NULL;
/* construct the kobject name from the device node */
- unit_address = of_get_property(vnode, "reg", NULL);
- if (!unit_address)
+ if (!strcmp(dev_type, "vdevice")) {
+ unit_address = of_get_property(vnode, "reg", NULL);
+ if (!unit_address)
+ return NULL;
+ snprintf(kobj_name, sizeof(kobj_name), "%x", *unit_address);
+ } else if (!strcmp(dev_type, "ibm,platform-facilities"))
+ snprintf(kobj_name, sizeof(kobj_name), "%s", vnode->name);
+ else
return NULL;
- snprintf(kobj_name, sizeof(kobj_name), "%x", *unit_address);
return vio_find_name(kobj_name);
}
diff --git a/arch/powerpc/lib/copyuser_64.S b/arch/powerpc/lib/copyuser_64.S
index 773d38f90aaa..d73a59014900 100644
--- a/arch/powerpc/lib/copyuser_64.S
+++ b/arch/powerpc/lib/copyuser_64.S
@@ -30,7 +30,7 @@ _GLOBAL(__copy_tofrom_user_base)
dcbt 0,r4
beq .Lcopy_page_4K
andi. r6,r6,7
- PPC_MTOCRF 0x01,r5
+ PPC_MTOCRF(0x01,r5)
blt cr1,.Lshort_copy
/* Below we want to nop out the bne if we're on a CPU that has the
* CPU_FTR_UNALIGNED_LD_STD bit set and the CPU_FTR_CP_USE_DCBTZ bit
@@ -186,7 +186,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
blr
.Ldst_unaligned:
- PPC_MTOCRF 0x01,r6 /* put #bytes to 8B bdry into cr7 */
+ PPC_MTOCRF(0x01,r6) /* put #bytes to 8B bdry into cr7 */
subf r5,r6,r5
li r7,0
cmpldi cr1,r5,16
@@ -201,7 +201,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
2: bf cr7*4+1,3f
37: lwzx r0,r7,r4
83: stwx r0,r7,r3
-3: PPC_MTOCRF 0x01,r5
+3: PPC_MTOCRF(0x01,r5)
add r4,r6,r4
add r3,r6,r3
b .Ldst_aligned
diff --git a/arch/powerpc/lib/mem_64.S b/arch/powerpc/lib/mem_64.S
index 11ce045e21fd..f4fcb0bc6563 100644
--- a/arch/powerpc/lib/mem_64.S
+++ b/arch/powerpc/lib/mem_64.S
@@ -19,7 +19,7 @@ _GLOBAL(memset)
rlwimi r4,r4,16,0,15
cmplw cr1,r5,r0 /* do we get that far? */
rldimi r4,r4,32,0
- PPC_MTOCRF 1,r0
+ PPC_MTOCRF(1,r0)
mr r6,r3
blt cr1,8f
beq+ 3f /* if already 8-byte aligned */
@@ -49,7 +49,7 @@ _GLOBAL(memset)
bdnz 4b
5: srwi. r0,r5,3
clrlwi r5,r5,29
- PPC_MTOCRF 1,r0
+ PPC_MTOCRF(1,r0)
beq 8f
bf 29,6f
std r4,0(r6)
@@ -65,7 +65,7 @@ _GLOBAL(memset)
std r4,0(r6)
addi r6,r6,8
8: cmpwi r5,0
- PPC_MTOCRF 1,r5
+ PPC_MTOCRF(1,r5)
beqlr+
bf 29,9f
stw r4,0(r6)
diff --git a/arch/powerpc/lib/memcpy_64.S b/arch/powerpc/lib/memcpy_64.S
index e178922b2c21..82fea3963e15 100644
--- a/arch/powerpc/lib/memcpy_64.S
+++ b/arch/powerpc/lib/memcpy_64.S
@@ -12,7 +12,7 @@
.align 7
_GLOBAL(memcpy)
std r3,48(r1) /* save destination pointer for return value */
- PPC_MTOCRF 0x01,r5
+ PPC_MTOCRF(0x01,r5)
cmpldi cr1,r5,16
neg r6,r3 # LS 3 bits = # bytes to 8-byte dest bdry
andi. r6,r6,7
@@ -154,7 +154,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
blr
.Ldst_unaligned:
- PPC_MTOCRF 0x01,r6 # put #bytes to 8B bdry into cr7
+ PPC_MTOCRF(0x01,r6) # put #bytes to 8B bdry into cr7
subf r5,r6,r5
li r7,0
cmpldi cr1,r5,16
@@ -169,7 +169,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
2: bf cr7*4+1,3f
lwzx r0,r7,r4
stwx r0,r7,r3
-3: PPC_MTOCRF 0x01,r5
+3: PPC_MTOCRF(0x01,r5)
add r4,r6,r4
add r3,r6,r3
b .Ldst_aligned
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index fb05b123218f..1a6de0a7d8eb 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -271,7 +271,8 @@ int alloc_bootmem_huge_page(struct hstate *hstate)
unsigned long gpage_npages[MMU_PAGE_COUNT];
-static int __init do_gpage_early_setup(char *param, char *val)
+static int __init do_gpage_early_setup(char *param, char *val,
+ const char *unused)
{
static phys_addr_t size;
unsigned long npages;
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index 02aee03e713c..8f84bcba18da 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -1299,8 +1299,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
if (record) {
struct perf_sample_data data;
- perf_sample_data_init(&data, ~0ULL);
- data.period = event->hw.last_period;
+ perf_sample_data_init(&data, ~0ULL, event->hw.last_period);
if (event->attr.sample_type & PERF_SAMPLE_ADDR)
perf_get_data_addr(regs, &data.addr);
diff --git a/arch/powerpc/perf/core-fsl-emb.c b/arch/powerpc/perf/core-fsl-emb.c
index 0a6d2a9d569c..106c53354675 100644
--- a/arch/powerpc/perf/core-fsl-emb.c
+++ b/arch/powerpc/perf/core-fsl-emb.c
@@ -613,8 +613,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
if (record) {
struct perf_sample_data data;
- perf_sample_data_init(&data, 0);
- data.period = event->hw.last_period;
+ perf_sample_data_init(&data, 0, event->hw.last_period);
if (perf_event_overflow(event, &data, regs))
fsl_emb_pmu_stop(event, 0);
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index 2e4e64abfab4..8abf6fb8f410 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -23,6 +23,8 @@ config BLUESTONE
default n
select PPC44x_SIMPLE
select APM821xx
+ select PCI_MSI
+ select PPC4xx_MSI
select PPC4xx_PCI_EXPRESS
select IBM_EMAC_RGMII
help
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 425db18580a2..61c9550819a2 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -78,6 +78,36 @@ config PPC_BOOK3E_64
endchoice
+choice
+ prompt "CPU selection"
+ depends on PPC64
+ default GENERIC_CPU
+ help
+ This will create a kernel which is optimised for a particular CPU.
+ The resulting kernel may not run on other CPUs, so use this with care.
+
+ If unsure, select Generic.
+
+config GENERIC_CPU
+ bool "Generic"
+
+config CELL_CPU
+ bool "Cell Broadband Engine"
+
+config POWER4_CPU
+ bool "POWER4"
+
+config POWER5_CPU
+ bool "POWER5"
+
+config POWER6_CPU
+ bool "POWER6"
+
+config POWER7_CPU
+ bool "POWER7"
+
+endchoice
+
config PPC_BOOK3S
def_bool y
depends on PPC_BOOK3S_32 || PPC_BOOK3S_64
@@ -86,15 +116,6 @@ config PPC_BOOK3E
def_bool y
depends on PPC_BOOK3E_64
-config POWER4_ONLY
- bool "Optimize for POWER4"
- depends on PPC64 && PPC_BOOK3S
- default n
- ---help---
- Cause the compiler to optimize for POWER4/POWER5/PPC970 processors.
- The resulting binary will not work on POWER3 or RS64 processors
- when compiled with binutils 2.15 or later.
-
config 6xx
def_bool y
depends on PPC32 && PPC_BOOK3S
@@ -258,7 +279,7 @@ config PPC_ICSWX_PID
default y
---help---
The PID register in server is used explicitly for ICSWX. In
- embedded systems PID managment is done by the system.
+ embedded systems PID management is done by the system.
config PPC_ICSWX_USE_SIGILL
bool "Should a bad CT cause a SIGILL?"
@@ -266,7 +287,7 @@ config PPC_ICSWX_USE_SIGILL
default n
---help---
Should a bad CT used for "non-record form ICSWX" cause an
- illegal intruction signal or should it be silent as
+ illegal instruction signal or should it be silent as
architected.
If in doubt, say N here.
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c
index 03685a329d7d..fc536f2971c0 100644
--- a/arch/powerpc/platforms/powermac/low_i2c.c
+++ b/arch/powerpc/platforms/powermac/low_i2c.c
@@ -1503,6 +1503,7 @@ static int __init pmac_i2c_create_platform_devices(void)
if (bus->platform_dev == NULL)
return -ENOMEM;
bus->platform_dev->dev.platform_data = bus;
+ bus->platform_dev->dev.of_node = bus->busnode;
platform_device_add(bus->platform_dev);
}
diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig
index 476d9d9b2405..46b7f0232523 100644
--- a/arch/powerpc/platforms/ps3/Kconfig
+++ b/arch/powerpc/platforms/ps3/Kconfig
@@ -7,7 +7,6 @@ config PPC_PS3
select USB_OHCI_BIG_ENDIAN_MMIO
select USB_ARCH_HAS_EHCI
select USB_EHCI_BIG_ENDIAN_MMIO
- select MEMORY_HOTPLUG
select PPC_PCI_CHOICE
help
This option enables support for the Sony PS3 game console
@@ -74,7 +73,7 @@ config PS3_PS3AV
help
Include support for the PS3 AV Settings driver.
- This support is required for graphics and sound. In
+ This support is required for PS3 graphics and sound. In
general, all users will say Y or M.
config PS3_SYS_MANAGER
@@ -85,9 +84,22 @@ config PS3_SYS_MANAGER
help
Include support for the PS3 System Manager.
- This support is required for system control. In
+ This support is required for PS3 system control. In
general, all users will say Y or M.
+config PS3_REPOSITORY_WRITE
+ bool "PS3 Repository write support" if PS3_ADVANCED
+ depends on PPC_PS3
+ default n
+ help
+ Enables support for writing to the PS3 System Repository.
+
+ This support is intended for bootloaders that need to store data
+ in the repository for later boot stages.
+
+ If in doubt, say N here and reduce the size of the kernel by a
+ small amount.
+
config PS3_STORAGE
depends on PPC_PS3
tristate
@@ -122,7 +134,7 @@ config PS3_FLASH
This support is required to access the PS3 FLASH ROM, which
contains the boot loader and some boot options.
- In general, all users will say Y or M.
+ In general, PS3 OtherOS users will say Y or M.
As this driver needs a fixed buffer of 256 KiB of memory, it can
be disabled on the kernel command line using "ps3flash=off", to
@@ -156,7 +168,7 @@ config PS3GELIC_UDBG
via the Ethernet port (UDP port number 18194).
This driver uses a trivial implementation and is independent
- from the main network driver.
+ from the main PS3 gelic network driver.
If in doubt, say N here.
diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c
index de2aea421707..0c9f643d9e2a 100644
--- a/arch/powerpc/platforms/ps3/mm.c
+++ b/arch/powerpc/platforms/ps3/mm.c
@@ -20,7 +20,6 @@
#include <linux/kernel.h>
#include <linux/export.h>
-#include <linux/memory_hotplug.h>
#include <linux/memblock.h>
#include <linux/slab.h>
@@ -79,12 +78,14 @@ enum {
* @base: base address
* @size: size in bytes
* @offset: difference between base and rm.size
+ * @destroy: flag if region should be destroyed upon shutdown
*/
struct mem_region {
u64 base;
u64 size;
unsigned long offset;
+ int destroy;
};
/**
@@ -96,7 +97,7 @@ struct mem_region {
* The HV virtual address space (vas) allows for hotplug memory regions.
* Memory regions can be created and destroyed in the vas at runtime.
* @rm: real mode (bootmem) region
- * @r1: hotplug memory region(s)
+ * @r1: highmem region(s)
*
* ps3 addresses
* virt_addr: a cpu 'translated' effective address
@@ -222,10 +223,6 @@ void ps3_mm_vas_destroy(void)
}
}
-/*============================================================================*/
-/* memory hotplug routines */
-/*============================================================================*/
-
/**
* ps3_mm_region_create - create a memory region in the vas
* @r: pointer to a struct mem_region to accept initialized values
@@ -262,6 +259,7 @@ static int ps3_mm_region_create(struct mem_region *r, unsigned long size)
goto zero_region;
}
+ r->destroy = 1;
r->offset = r->base - map.rm.size;
return result;
@@ -279,7 +277,14 @@ static void ps3_mm_region_destroy(struct mem_region *r)
{
int result;
+ if (!r->destroy) {
+ pr_info("%s:%d: Not destroying high region: %llxh %llxh\n",
+ __func__, __LINE__, r->base, r->size);
+ return;
+ }
+
DBG("%s:%d: r->base = %llxh\n", __func__, __LINE__, r->base);
+
if (r->base) {
result = lv1_release_memory(r->base);
BUG_ON(result);
@@ -288,50 +293,36 @@ static void ps3_mm_region_destroy(struct mem_region *r)
}
}
-/**
- * ps3_mm_add_memory - hot add memory
- */
-
-static int __init ps3_mm_add_memory(void)
+static int ps3_mm_get_repository_highmem(struct mem_region *r)
{
int result;
- unsigned long start_addr;
- unsigned long start_pfn;
- unsigned long nr_pages;
-
- if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
- return -ENODEV;
- BUG_ON(!mem_init_done);
+ /* Assume a single highmem region. */
- start_addr = map.rm.size;
- start_pfn = start_addr >> PAGE_SHIFT;
- nr_pages = (map.r1.size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ result = ps3_repository_read_highmem_info(0, &r->base, &r->size);
- DBG("%s:%d: start_addr %lxh, start_pfn %lxh, nr_pages %lxh\n",
- __func__, __LINE__, start_addr, start_pfn, nr_pages);
-
- result = add_memory(0, start_addr, map.r1.size);
+ if (result)
+ goto zero_region;
- if (result) {
- pr_err("%s:%d: add_memory failed: (%d)\n",
- __func__, __LINE__, result);
- return result;
+ if (!r->base || !r->size) {
+ result = -1;
+ goto zero_region;
}
- memblock_add(start_addr, map.r1.size);
+ r->offset = r->base - map.rm.size;
- result = online_pages(start_pfn, nr_pages);
+ DBG("%s:%d: Found high region in repository: %llxh %llxh\n",
+ __func__, __LINE__, r->base, r->size);
- if (result)
- pr_err("%s:%d: online_pages failed: (%d)\n",
- __func__, __LINE__, result);
+ return 0;
+zero_region:
+ DBG("%s:%d: No high region in repository.\n", __func__, __LINE__);
+
+ r->size = r->base = r->offset = 0;
return result;
}
-device_initcall(ps3_mm_add_memory);
-
/*============================================================================*/
/* dma routines */
/*============================================================================*/
@@ -1217,13 +1208,23 @@ void __init ps3_mm_init(void)
BUG_ON(map.rm.base);
BUG_ON(!map.rm.size);
+ /* Check if we got the highmem region from an earlier boot step */
- /* arrange to do this in ps3_mm_add_memory */
- ps3_mm_region_create(&map.r1, map.total - map.rm.size);
+ if (ps3_mm_get_repository_highmem(&map.r1))
+ ps3_mm_region_create(&map.r1, map.total - map.rm.size);
/* correct map.total for the real total amount of memory we use */
map.total = map.rm.size + map.r1.size;
+ if (!map.r1.size) {
+ DBG("%s:%d: No highmem region found\n", __func__, __LINE__);
+ } else {
+ DBG("%s:%d: Adding highmem region: %llxh %llxh\n",
+ __func__, __LINE__, map.rm.size,
+ map.total - map.rm.size);
+ memblock_add(map.rm.size, map.total - map.rm.size);
+ }
+
DBG(" <- %s:%d\n", __func__, __LINE__);
}
diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h
index 1a633ed0fe98..d71329a8e325 100644
--- a/arch/powerpc/platforms/ps3/platform.h
+++ b/arch/powerpc/platforms/ps3/platform.h
@@ -188,6 +188,22 @@ int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size);
int ps3_repository_read_region_total(u64 *region_total);
int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size,
u64 *region_total);
+int ps3_repository_read_highmem_region_count(unsigned int *region_count);
+int ps3_repository_read_highmem_base(unsigned int region_index,
+ u64 *highmem_base);
+int ps3_repository_read_highmem_size(unsigned int region_index,
+ u64 *highmem_size);
+int ps3_repository_read_highmem_info(unsigned int region_index,
+ u64 *highmem_base, u64 *highmem_size);
+
+int ps3_repository_write_highmem_region_count(unsigned int region_count);
+int ps3_repository_write_highmem_base(unsigned int region_index,
+ u64 highmem_base);
+int ps3_repository_write_highmem_size(unsigned int region_index,
+ u64 highmem_size);
+int ps3_repository_write_highmem_info(unsigned int region_index,
+ u64 highmem_base, u64 highmem_size);
+int ps3_repository_delete_highmem_info(unsigned int region_index);
/* repository pme info */
diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c
index 7bdfea336f5e..9b47ba7a5de7 100644
--- a/arch/powerpc/platforms/ps3/repository.c
+++ b/arch/powerpc/platforms/ps3/repository.c
@@ -779,6 +779,72 @@ int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size, u64 *region_total)
}
/**
+ * ps3_repository_read_highmem_region_count - Read the number of highmem regions
+ *
+ * Bootloaders must arrange the repository nodes such that regions are indexed
+ * with a region_index from 0 to region_count-1.
+ */
+
+int ps3_repository_read_highmem_region_count(unsigned int *region_count)
+{
+ int result;
+ u64 v1 = 0;
+
+ result = read_node(PS3_LPAR_ID_CURRENT,
+ make_first_field("highmem", 0),
+ make_field("region", 0),
+ make_field("count", 0),
+ 0,
+ &v1, NULL);
+ *region_count = v1;
+ return result;
+}
+
+
+int ps3_repository_read_highmem_base(unsigned int region_index,
+ u64 *highmem_base)
+{
+ return read_node(PS3_LPAR_ID_CURRENT,
+ make_first_field("highmem", 0),
+ make_field("region", region_index),
+ make_field("base", 0),
+ 0,
+ highmem_base, NULL);
+}
+
+int ps3_repository_read_highmem_size(unsigned int region_index,
+ u64 *highmem_size)
+{
+ return read_node(PS3_LPAR_ID_CURRENT,
+ make_first_field("highmem", 0),
+ make_field("region", region_index),
+ make_field("size", 0),
+ 0,
+ highmem_size, NULL);
+}
+
+/**
+ * ps3_repository_read_highmem_info - Read high memory region info
+ * @region_index: Region index, {0,..,region_count-1}.
+ * @highmem_base: High memory base address.
+ * @highmem_size: High memory size.
+ *
+ * Bootloaders that preallocate highmem regions must place the
+ * region info into the repository at these well known nodes.
+ */
+
+int ps3_repository_read_highmem_info(unsigned int region_index,
+ u64 *highmem_base, u64 *highmem_size)
+{
+ int result;
+
+ *highmem_base = 0;
+ result = ps3_repository_read_highmem_base(region_index, highmem_base);
+ return result ? result
+ : ps3_repository_read_highmem_size(region_index, highmem_size);
+}
+
+/**
* ps3_repository_read_num_spu_reserved - Number of physical spus reserved.
* @num_spu: Number of physical spus.
*/
@@ -1002,6 +1068,138 @@ int ps3_repository_read_lpm_privileges(unsigned int be_index, u64 *lpar,
lpar, rights);
}
+#if defined(CONFIG_PS3_REPOSITORY_WRITE)
+
+static int create_node(u64 n1, u64 n2, u64 n3, u64 n4, u64 v1, u64 v2)
+{
+ int result;
+
+ dump_node(0, n1, n2, n3, n4, v1, v2);
+
+ result = lv1_create_repository_node(n1, n2, n3, n4, v1, v2);
+
+ if (result) {
+ pr_devel("%s:%d: lv1_create_repository_node failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+static int delete_node(u64 n1, u64 n2, u64 n3, u64 n4)
+{
+ int result;
+
+ dump_node(0, n1, n2, n3, n4, 0, 0);
+
+ result = lv1_delete_repository_node(n1, n2, n3, n4);
+
+ if (result) {
+ pr_devel("%s:%d: lv1_delete_repository_node failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+static int write_node(u64 n1, u64 n2, u64 n3, u64 n4, u64 v1, u64 v2)
+{
+ int result;
+
+ result = create_node(n1, n2, n3, n4, v1, v2);
+
+ if (!result)
+ return 0;
+
+ result = lv1_write_repository_node(n1, n2, n3, n4, v1, v2);
+
+ if (result) {
+ pr_devel("%s:%d: lv1_write_repository_node failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+int ps3_repository_write_highmem_region_count(unsigned int region_count)
+{
+ int result;
+ u64 v1 = (u64)region_count;
+
+ result = write_node(
+ make_first_field("highmem", 0),
+ make_field("region", 0),
+ make_field("count", 0),
+ 0,
+ v1, 0);
+ return result;
+}
+
+int ps3_repository_write_highmem_base(unsigned int region_index,
+ u64 highmem_base)
+{
+ return write_node(
+ make_first_field("highmem", 0),
+ make_field("region", region_index),
+ make_field("base", 0),
+ 0,
+ highmem_base, 0);
+}
+
+int ps3_repository_write_highmem_size(unsigned int region_index,
+ u64 highmem_size)
+{
+ return write_node(
+ make_first_field("highmem", 0),
+ make_field("region", region_index),
+ make_field("size", 0),
+ 0,
+ highmem_size, 0);
+}
+
+int ps3_repository_write_highmem_info(unsigned int region_index,
+ u64 highmem_base, u64 highmem_size)
+{
+ int result;
+
+ result = ps3_repository_write_highmem_base(region_index, highmem_base);
+ return result ? result
+ : ps3_repository_write_highmem_size(region_index, highmem_size);
+}
+
+static int ps3_repository_delete_highmem_base(unsigned int region_index)
+{
+ return delete_node(
+ make_first_field("highmem", 0),
+ make_field("region", region_index),
+ make_field("base", 0),
+ 0);
+}
+
+static int ps3_repository_delete_highmem_size(unsigned int region_index)
+{
+ return delete_node(
+ make_first_field("highmem", 0),
+ make_field("region", region_index),
+ make_field("size", 0),
+ 0);
+}
+
+int ps3_repository_delete_highmem_info(unsigned int region_index)
+{
+ int result;
+
+ result = ps3_repository_delete_highmem_base(region_index);
+ result += ps3_repository_delete_highmem_size(region_index);
+
+ return result ? -1 : 0;
+}
+
+#endif /* defined(CONFIG_PS3_WRITE_REPOSITORY) */
+
#if defined(DEBUG)
int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo)
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index 178a5f300bc9..837cf49357ed 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -67,7 +67,7 @@ config IO_EVENT_IRQ
This option will only enable the IO event platform code. You
will still need to enable or compile the actual drivers
- that use this infrastruture to handle IO event interrupts.
+ that use this infrastructure to handle IO event interrupts.
Say Y if you are unsure.
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index a75e37dc41aa..ecd394cf34e6 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -489,7 +489,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
* a stack trace will help the device-driver authors figure
* out what happened. So print that out.
*/
- dump_stack();
+ WARN(1, "EEH: failure detected\n");
return 1;
dn_unlock:
diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h
index 342797fc0f9c..13e8cc43adf7 100644
--- a/arch/powerpc/platforms/pseries/plpar_wrappers.h
+++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h
@@ -22,12 +22,12 @@ static inline long poll_pending(void)
static inline u8 get_cede_latency_hint(void)
{
- return get_lppaca()->gpr5_dword.fields.cede_latency_hint;
+ return get_lppaca()->cede_latency_hint;
}
static inline void set_cede_latency_hint(u8 latency_hint)
{
- get_lppaca()->gpr5_dword.fields.cede_latency_hint = latency_hint;
+ get_lppaca()->cede_latency_hint = latency_hint;
}
static inline long cede_processor(void)
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c
index 168651acdd83..7b3bf76ef834 100644
--- a/arch/powerpc/platforms/pseries/reconfig.c
+++ b/arch/powerpc/platforms/pseries/reconfig.c
@@ -103,11 +103,13 @@ int pSeries_reconfig_notifier_register(struct notifier_block *nb)
{
return blocking_notifier_chain_register(&pSeries_reconfig_chain, nb);
}
+EXPORT_SYMBOL_GPL(pSeries_reconfig_notifier_register);
void pSeries_reconfig_notifier_unregister(struct notifier_block *nb)
{
blocking_notifier_chain_unregister(&pSeries_reconfig_chain, nb);
}
+EXPORT_SYMBOL_GPL(pSeries_reconfig_notifier_unregister);
int pSeries_reconfig_notify(unsigned long action, void *p)
{
@@ -426,6 +428,7 @@ static int do_remove_property(char *buf, size_t bufsize)
static int do_update_property(char *buf, size_t bufsize)
{
struct device_node *np;
+ struct pSeries_reconfig_prop_update upd_value;
unsigned char *value;
char *name, *end, *next_prop;
int rc, length;
@@ -454,6 +457,10 @@ static int do_update_property(char *buf, size_t bufsize)
return -ENODEV;
}
+ upd_value.node = np;
+ upd_value.property = newprop;
+ pSeries_reconfig_notify(PSERIES_UPDATE_PROPERTY, &upd_value);
+
rc = prom_update_property(np, newprop, oldprop);
if (rc)
return rc;
diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c b/arch/powerpc/sysdev/ppc4xx_msi.c
index 1c2d7af17bbe..82c6702dcbab 100644
--- a/arch/powerpc/sysdev/ppc4xx_msi.c
+++ b/arch/powerpc/sysdev/ppc4xx_msi.c
@@ -28,10 +28,11 @@
#include <linux/of_platform.h>
#include <linux/interrupt.h>
#include <linux/export.h>
+#include <linux/kernel.h>
#include <asm/prom.h>
#include <asm/hw_irq.h>
#include <asm/ppc-pci.h>
-#include <boot/dcr.h>
+#include <asm/dcr.h>
#include <asm/dcr-regs.h>
#include <asm/msi_bitmap.h>
@@ -43,13 +44,14 @@
#define PEIH_FLUSH0 0x30
#define PEIH_FLUSH1 0x38
#define PEIH_CNTRST 0x48
-#define NR_MSI_IRQS 4
+
+static int msi_irqs;
struct ppc4xx_msi {
u32 msi_addr_lo;
u32 msi_addr_hi;
void __iomem *msi_regs;
- int msi_virqs[NR_MSI_IRQS];
+ int *msi_virqs;
struct msi_bitmap bitmap;
struct device_node *msi_dev;
};
@@ -61,7 +63,7 @@ static int ppc4xx_msi_init_allocator(struct platform_device *dev,
{
int err;
- err = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS,
+ err = msi_bitmap_alloc(&msi_data->bitmap, msi_irqs,
dev->dev.of_node);
if (err)
return err;
@@ -83,6 +85,11 @@ static int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
struct msi_desc *entry;
struct ppc4xx_msi *msi_data = &ppc4xx_msi;
+ msi_data->msi_virqs = kmalloc((msi_irqs) * sizeof(int),
+ GFP_KERNEL);
+ if (!msi_data->msi_virqs)
+ return -ENOMEM;
+
list_for_each_entry(entry, &dev->msi_list, list) {
int_no = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
if (int_no >= 0)
@@ -150,12 +157,11 @@ static int ppc4xx_setup_pcieh_hw(struct platform_device *dev,
if (!sdr_addr)
return -1;
- SDR0_WRITE(sdr_addr, (u64)res.start >> 32); /*HIGH addr */
- SDR0_WRITE(sdr_addr + 1, res.start & 0xFFFFFFFF); /* Low addr */
-
+ mtdcri(SDR0, *sdr_addr, upper_32_bits(res.start)); /*HIGH addr */
+ mtdcri(SDR0, *sdr_addr + 1, lower_32_bits(res.start)); /* Low addr */
msi->msi_dev = of_find_node_by_name(NULL, "ppc4xx-msi");
- if (msi->msi_dev)
+ if (!msi->msi_dev)
return -ENODEV;
msi->msi_regs = of_iomap(msi->msi_dev, 0);
@@ -167,9 +173,12 @@ static int ppc4xx_setup_pcieh_hw(struct platform_device *dev,
(u32) (msi->msi_regs + PEIH_TERMADH), (u32) (msi->msi_regs));
msi_virt = dma_alloc_coherent(&dev->dev, 64, &msi_phys, GFP_KERNEL);
- msi->msi_addr_hi = 0x0;
- msi->msi_addr_lo = (u32) msi_phys;
- dev_dbg(&dev->dev, "PCIE-MSI: msi address 0x%x\n", msi->msi_addr_lo);
+ if (!msi_virt)
+ return -ENOMEM;
+ msi->msi_addr_hi = upper_32_bits(msi_phys);
+ msi->msi_addr_lo = lower_32_bits(msi_phys & 0xffffffff);
+ dev_dbg(&dev->dev, "PCIE-MSI: msi address high 0x%x, low 0x%x\n",
+ msi->msi_addr_hi, msi->msi_addr_lo);
/* Progam the Interrupt handler Termination addr registers */
out_be32(msi->msi_regs + PEIH_TERMADH, msi->msi_addr_hi);
@@ -185,6 +194,8 @@ static int ppc4xx_setup_pcieh_hw(struct platform_device *dev,
out_be32(msi->msi_regs + PEIH_MSIED, *msi_data);
out_be32(msi->msi_regs + PEIH_MSIMK, *msi_mask);
+ dma_free_coherent(&dev->dev, 64, msi_virt, msi_phys);
+
return 0;
}
@@ -194,7 +205,7 @@ static int ppc4xx_of_msi_remove(struct platform_device *dev)
int i;
int virq;
- for (i = 0; i < NR_MSI_IRQS; i++) {
+ for (i = 0; i < msi_irqs; i++) {
virq = msi->msi_virqs[i];
if (virq != NO_IRQ)
irq_dispose_mapping(virq);
@@ -215,8 +226,6 @@ static int __devinit ppc4xx_msi_probe(struct platform_device *dev)
struct resource res;
int err = 0;
- msi = &ppc4xx_msi;/*keep the msi data for further use*/
-
dev_dbg(&dev->dev, "PCIE-MSI: Setting up MSI support...\n");
msi = kzalloc(sizeof(struct ppc4xx_msi), GFP_KERNEL);
@@ -234,6 +243,10 @@ static int __devinit ppc4xx_msi_probe(struct platform_device *dev)
goto error_out;
}
+ msi_irqs = of_irq_count(dev->dev.of_node);
+ if (!msi_irqs)
+ return -ENODEV;
+
if (ppc4xx_setup_pcieh_hw(dev, res, msi))
goto error_out;
@@ -242,6 +255,7 @@ static int __devinit ppc4xx_msi_probe(struct platform_device *dev)
dev_err(&dev->dev, "Error allocating MSI bitmap\n");
goto error_out;
}
+ ppc4xx_msi = *msi;
ppc_md.setup_msi_irqs = ppc4xx_setup_msi_irqs;
ppc_md.teardown_msi_irqs = ppc4xx_teardown_msi_irqs;
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index e16390c0bca8..b403c533432c 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -28,12 +28,6 @@ config ARCH_HAS_ILOG2_U64
config GENERIC_HWEIGHT
def_bool y
-config GENERIC_TIME_VSYSCALL
- def_bool y
-
-config GENERIC_CLOCKEVENTS
- def_bool y
-
config GENERIC_BUG
def_bool y if BUG
@@ -123,6 +117,9 @@ config S390
select ARCH_INLINE_WRITE_UNLOCK_IRQ
select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE
select GENERIC_SMP_IDLE_THREAD
+ select GENERIC_TIME_VSYSCALL
+ select GENERIC_CLOCKEVENTS
+ select KTIME_SCALAR if 32BIT
config SCHED_OMIT_FRAME_POINTER
def_bool y
@@ -135,8 +132,6 @@ menu "Base setup"
comment "Processor type and features"
-source "kernel/time/Kconfig"
-
config 64BIT
def_bool y
prompt "64 bit kernel"
@@ -147,9 +142,6 @@ config 64BIT
config 32BIT
def_bool y if !64BIT
-config KTIME_SCALAR
- def_bool 32BIT
-
config SMP
def_bool y
prompt "Symmetric multi-processing support"
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index d499b30ea487..6cbf31311673 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -141,9 +141,6 @@ struct seq_file;
extern void release_thread(struct task_struct *);
extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk) do { } while (0)
-
/*
* Return saved PC of a blocked thread.
*/
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index ab64bdbab2ae..65426525d9f2 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -173,11 +173,14 @@ asmlinkage long sys32_setfsgid16(u16 gid)
static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info)
{
+ struct user_namespace *user_ns = current_user_ns();
int i;
u16 group;
+ kgid_t kgid;
for (i = 0; i < group_info->ngroups; i++) {
- group = (u16)GROUP_AT(group_info, i);
+ kgid = GROUP_AT(group_info, i);
+ group = (u16)from_kgid_munged(user_ns, kgid);
if (put_user(group, grouplist+i))
return -EFAULT;
}
@@ -187,13 +190,20 @@ static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info
static int groups16_from_user(struct group_info *group_info, u16 __user *grouplist)
{
+ struct user_namespace *user_ns = current_user_ns();
int i;
u16 group;
+ kgid_t kgid;
for (i = 0; i < group_info->ngroups; i++) {
if (get_user(group, grouplist+i))
return -EFAULT;
- GROUP_AT(group_info, i) = (gid_t)group;
+
+ kgid = make_kgid(user_ns, (gid_t)group);
+ if (!gid_valid(kgid))
+ return -EINVAL;
+
+ GROUP_AT(group_info, i) = kgid;
}
return 0;
@@ -537,8 +547,8 @@ static int cp_stat64(struct stat64_emu31 __user *ubuf, struct kstat *stat)
tmp.__st_ino = (u32)stat->ino;
tmp.st_mode = stat->mode;
tmp.st_nlink = (unsigned int)stat->nlink;
- tmp.st_uid = stat->uid;
- tmp.st_gid = stat->gid;
+ tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid);
+ tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid);
tmp.st_rdev = huge_encode_dev(stat->rdev);
tmp.st_size = stat->size;
tmp.st_blksize = (u32)stat->blksize;
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index 8a4e2b760d56..f626232e216c 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -59,15 +59,8 @@ typedef struct
SYSCALL_DEFINE3(sigsuspend, int, history0, int, history1, old_sigset_t, mask)
{
sigset_t blocked;
-
- current->saved_sigmask = current->blocked;
- mask &= _BLOCKABLE;
siginitset(&blocked, mask);
- set_current_blocked(&blocked);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule();
- set_restore_sigmask();
- return -ERESTARTNOHAND;
+ return sigsuspend(&blocked);
}
SYSCALL_DEFINE3(sigaction, int, sig, const struct old_sigaction __user *, act,
diff --git a/arch/score/Kconfig b/arch/score/Kconfig
index 4b285779ac05..ba0f412920be 100644
--- a/arch/score/Kconfig
+++ b/arch/score/Kconfig
@@ -9,6 +9,7 @@ config SCORE
select HAVE_MEMBLOCK_NODE_MAP
select ARCH_DISCARD_MEMBLOCK
select GENERIC_CPU_DEVICES
+ select GENERIC_CLOCKEVENTS
choice
prompt "System type"
@@ -51,9 +52,6 @@ config GENERIC_HWEIGHT
config GENERIC_CALIBRATE_DELAY
def_bool y
-config GENERIC_CLOCKEVENTS
- def_bool y
-
menu "Kernel type"
config 32BIT
@@ -68,7 +66,6 @@ config MEMORY_START
hex
default 0xa0000000
-source "kernel/time/Kconfig"
source "kernel/Kconfig.hz"
source "kernel/Kconfig.preempt"
diff --git a/arch/score/include/asm/processor.h b/arch/score/include/asm/processor.h
index 7e22f216d771..ab3aceb54209 100644
--- a/arch/score/include/asm/processor.h
+++ b/arch/score/include/asm/processor.h
@@ -26,7 +26,6 @@ extern unsigned long get_wchan(struct task_struct *p);
#define cpu_relax() barrier()
#define release_thread(thread) do {} while (0)
-#define prepare_to_copy(tsk) do {} while (0)
/*
* User space process size: 2GB. This is hardcoded into a few places,
diff --git a/arch/score/kernel/signal.c b/arch/score/kernel/signal.c
index aa57440e4973..d4a49011c48a 100644
--- a/arch/score/kernel/signal.c
+++ b/arch/score/kernel/signal.c
@@ -28,6 +28,7 @@
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/uaccess.h>
+#include <linux/tracehook.h>
#include <asm/cacheflush.h>
#include <asm/syscalls.h>
@@ -152,6 +153,9 @@ score_rt_sigreturn(struct pt_regs *regs)
stack_t st;
int sig;
+ /* Always make any pending restarted system calls return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
frame = (struct rt_sigframe __user *) regs->regs[0];
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
@@ -159,10 +163,7 @@ score_rt_sigreturn(struct pt_regs *regs)
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
sig = restore_sigcontext(regs, &frame->rs_uc.uc_mcontext);
if (sig < 0)
@@ -236,9 +237,7 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
return 0;
give_sigsegv:
- if (signr == SIGSEGV)
- ka->sa.sa_handler = SIG_DFL;
- force_sig(SIGSEGV, current);
+ force_sigsegv(signr, current);
return -EFAULT;
}
@@ -272,12 +271,8 @@ static int handle_signal(unsigned long sig, siginfo_t *info,
*/
ret = setup_rt_frame(ka, regs, sig, oldset, info);
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(&current->blocked, sig);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ if (ret == 0)
+ block_sigmask(ka, sig);
return ret;
}
@@ -356,6 +351,12 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
__u32 thread_info_flags)
{
/* deal with pending signal delivery */
- if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+ if (thread_info_flags & _TIF_SIGPENDING)
do_signal(regs);
+ if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+ clear_thread_flag(TIF_NOTIFY_RESUME);
+ tracehook_notify_resume(regs);
+ if (current->replacement_session_keyring)
+ key_replace_session_keyring();
+ }
}
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 04a8cb4700af..99bcd0ee838d 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -13,6 +13,7 @@ config SUPERH
select HAVE_DMA_ATTRS
select HAVE_IRQ_WORK
select HAVE_PERF_EVENTS
+ select ARCH_HAVE_CUSTOM_GPIO_H
select ARCH_HAVE_NMI_SAFE_CMPXCHG if (GUSA_RB || CPU_SH4A)
select PERF_USE_VMALLOC
select HAVE_KERNEL_GZIP
@@ -29,6 +30,8 @@ config SUPERH
select GENERIC_ATOMIC64
select GENERIC_IRQ_SHOW
select GENERIC_SMP_IDLE_THREAD
+ select GENERIC_CLOCKEVENTS
+ select GENERIC_CMOS_UPDATE if SH_SH03 || SH_DREAMCAST
help
The SuperH is a RISC processor targeted for use in embedded systems
and consumer electronics; it was also used in the Sega Dreamcast
@@ -87,16 +90,6 @@ config GENERIC_GPIO
config GENERIC_CALIBRATE_DELAY
bool
-config GENERIC_CLOCKEVENTS
- def_bool y
-
-config GENERIC_CLOCKEVENTS_BROADCAST
- bool
-
-config GENERIC_CMOS_UPDATE
- def_bool y
- depends on SH_SH03 || SH_DREAMCAST
-
config GENERIC_LOCKBREAK
def_bool y
depends on SMP && PREEMPT
@@ -155,7 +148,8 @@ config ARCH_HAS_DEFAULT_IDLE
config NO_IOPORT
def_bool !PCI
- depends on !SH_CAYMAN && !SH_SH4202_MICRODEV && !SH_SHMIN
+ depends on !SH_CAYMAN && !SH_SH4202_MICRODEV && !SH_SHMIN && \
+ !SH_HP6XX && !SH_SOLUTION_ENGINE
config IO_TRAPPED
bool
@@ -286,6 +280,20 @@ config CPU_SUBTYPE_SH7263
select SYS_SUPPORTS_CMT
select SYS_SUPPORTS_MTU2
+config CPU_SUBTYPE_SH7264
+ bool "Support SH7264 processor"
+ select CPU_SH2A
+ select CPU_HAS_FPU
+ select SYS_SUPPORTS_CMT
+ select SYS_SUPPORTS_MTU2
+
+config CPU_SUBTYPE_SH7269
+ bool "Support SH7269 processor"
+ select CPU_SH2A
+ select CPU_HAS_FPU
+ select SYS_SUPPORTS_CMT
+ select SYS_SUPPORTS_MTU2
+
config CPU_SUBTYPE_MXG
bool "Support MX-G processor"
select CPU_SH2A
@@ -425,6 +433,16 @@ config CPU_SUBTYPE_SH7724
help
Select SH7724 if you have an SH-MobileR2R CPU.
+config CPU_SUBTYPE_SH7734
+ bool "Support SH7734 processor"
+ select CPU_SH4A
+ select CPU_SHX2
+ select ARCH_WANT_OPTIONAL_GPIOLIB
+ select USB_ARCH_HAS_OHCI
+ select USB_ARCH_HAS_EHCI
+ help
+ Select SH7734 if you have a SH4A SH7734 CPU.
+
config CPU_SUBTYPE_SH7757
bool "Support SH7757 processor"
select CPU_SH4A
@@ -582,9 +600,9 @@ config SH_CLK_CPG
config SH_CLK_CPG_LEGACY
depends on SH_CLK_CPG
def_bool y if !CPU_SUBTYPE_SH7785 && !ARCH_SHMOBILE && \
- !CPU_SHX3 && !CPU_SUBTYPE_SH7757
-
-source "kernel/time/Kconfig"
+ !CPU_SHX3 && !CPU_SUBTYPE_SH7757 && \
+ !CPU_SUBTYPE_SH7734 && !CPU_SUBTYPE_SH7264 && \
+ !CPU_SUBTYPE_SH7269
endmenu
@@ -683,6 +701,20 @@ config SECCOMP
If unsure, say N.
+config CC_STACKPROTECTOR
+ bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)"
+ depends on SUPERH32 && EXPERIMENTAL
+ help
+ This option turns on the -fstack-protector GCC feature. This
+ feature puts, at the beginning of functions, a canary value on
+ the stack just before the return address, and validates
+ the value just before actually returning. Stack based buffer
+ overflows (that need to overwrite this return address) now also
+ overwrite the canary, which gets detected and the attack is then
+ neutralized via a kernel panic.
+
+ This feature requires gcc version 4.2 or above.
+
config SMP
bool "Symmetric multi-processing support"
depends on SYS_SUPPORTS_SMP
diff --git a/arch/sh/Kconfig.cpu b/arch/sh/Kconfig.cpu
index ddf096c7d8bf..770ff2d5b94d 100644
--- a/arch/sh/Kconfig.cpu
+++ b/arch/sh/Kconfig.cpu
@@ -1,7 +1,7 @@
menu "Processor features"
choice
- prompt "Endianess selection"
+ prompt "Endianness selection"
default CPU_LITTLE_ENDIAN
help
Some SuperH machines can be configured for either little or big
diff --git a/arch/sh/Makefile b/arch/sh/Makefile
index e14a676a0c7d..46edf070da1c 100644
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -199,6 +199,10 @@ ifeq ($(CONFIG_DWARF_UNWINDER),y)
KBUILD_CFLAGS += -fasynchronous-unwind-tables
endif
+ifeq ($(CONFIG_CC_STACKPROTECTOR),y)
+ KBUILD_CFLAGS += -fstack-protector
+endif
+
libs-$(CONFIG_SUPERH32) := arch/sh/lib/ $(libs-y)
libs-$(CONFIG_SUPERH64) := arch/sh/lib64/ $(libs-y)
diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig
index d893411022d5..1f56b35d3248 100644
--- a/arch/sh/boards/Kconfig
+++ b/arch/sh/boards/Kconfig
@@ -54,6 +54,7 @@ config SH_7724_SOLUTION_ENGINE
select SOLUTION_ENGINE
depends on CPU_SUBTYPE_SH7724
select ARCH_REQUIRE_GPIOLIB
+ select SND_SOC_AK4642 if SND_SIMPLE_CARD
help
Select 7724 SolutionEngine if configuring for a Hitachi SH7724
evaluation board.
@@ -133,7 +134,8 @@ config SH_RTS7751R2D
config SH_RSK
bool "Renesas Starter Kit"
- depends on CPU_SUBTYPE_SH7201 || CPU_SUBTYPE_SH7203
+ depends on CPU_SUBTYPE_SH7201 || CPU_SUBTYPE_SH7203 || \
+ CPU_SUBTYPE_SH7264 || CPU_SUBTYPE_SH7269
help
Select this option if configuring for any of the RSK+ MCU
evaluation platforms.
@@ -223,6 +225,7 @@ config SH_ECOVEC
bool "EcoVec"
depends on CPU_SUBTYPE_SH7724
select ARCH_REQUIRE_GPIOLIB
+ select SND_SOC_DA7210 if SND_SIMPLE_CARD
help
Renesas "R0P7724LC0011/21RL (EcoVec)" support.
@@ -338,8 +341,6 @@ config SH_APSH4AD0A
help
Select AP-SH4AD-0A if configuring for an ALPHAPROJECT AP-SH4AD-0A.
-endmenu
-
source "arch/sh/boards/mach-r2d/Kconfig"
source "arch/sh/boards/mach-highlander/Kconfig"
source "arch/sh/boards/mach-sdk7780/Kconfig"
@@ -359,3 +360,5 @@ config SH_MAGIC_PANEL_R2_VERSION
endmenu
endif
+
+endmenu
diff --git a/arch/sh/boards/board-edosk7705.c b/arch/sh/boards/board-edosk7705.c
index 541d8a281035..5e24c17bbdad 100644
--- a/arch/sh/boards/board-edosk7705.c
+++ b/arch/sh/boards/board-edosk7705.c
@@ -13,6 +13,7 @@
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/smc91x.h>
+#include <linux/sh_intc.h>
#include <asm/machvec.h>
#include <asm/sizes.h>
@@ -20,7 +21,7 @@
#define SMC_IO_OFFSET 0x300
#define SMC_IOADDR (SMC_IOBASE + SMC_IO_OFFSET)
-#define ETHERNET_IRQ 0x09
+#define ETHERNET_IRQ evt2irq(0x320)
static void __init sh_edosk7705_init_irq(void)
{
@@ -73,6 +74,5 @@ device_initcall(init_edosk7705_devices);
*/
static struct sh_machine_vector mv_edosk7705 __initmv = {
.mv_name = "EDOSK7705",
- .mv_nr_irqs = 80,
.mv_init_irq = sh_edosk7705_init_irq,
};
diff --git a/arch/sh/boards/board-edosk7760.c b/arch/sh/boards/board-edosk7760.c
index e9656a2cc4cc..bab5b9513904 100644
--- a/arch/sh/boards/board-edosk7760.c
+++ b/arch/sh/boards/board-edosk7760.c
@@ -23,6 +23,7 @@
#include <linux/platform_device.h>
#include <linux/smc91x.h>
#include <linux/interrupt.h>
+#include <linux/sh_intc.h>
#include <linux/i2c.h>
#include <linux/mtd/physmap.h>
#include <asm/machvec.h>
@@ -40,8 +41,6 @@
#define SMC_IO_OFFSET 0x300
#define SMC_IOADDR (SMC_IOBASE + SMC_IO_OFFSET)
-#define ETHERNET_IRQ 5
-
/* NOR flash */
static struct mtd_partition edosk7760_nor_flash_partitions[] = {
{
@@ -99,8 +98,8 @@ static struct resource sh7760_i2c1_res[] = {
.end = SH7760_I2C1_MMIOEND,
.flags = IORESOURCE_MEM,
},{
- .start = SH7760_I2C1_IRQ,
- .end = SH7760_I2C1_IRQ,
+ .start = evt2irq(0x9e0),
+ .end = evt2irq(0x9e0),
.flags = IORESOURCE_IRQ,
},
};
@@ -122,8 +121,8 @@ static struct resource sh7760_i2c0_res[] = {
.end = SH7760_I2C0_MMIOEND,
.flags = IORESOURCE_MEM,
}, {
- .start = SH7760_I2C0_IRQ,
- .end = SH7760_I2C0_IRQ,
+ .start = evt2irq(0x9c0),
+ .end = evt2irq(0x9c0),
.flags = IORESOURCE_IRQ,
},
};
@@ -150,8 +149,8 @@ static struct resource smc91x_res[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = ETHERNET_IRQ,
- .end = ETHERNET_IRQ,
+ .start = evt2irq(0x2a0),
+ .end = evt2irq(0x2a0),
.flags = IORESOURCE_IRQ ,
}
};
@@ -189,5 +188,4 @@ device_initcall(init_edosk7760_devices);
*/
struct sh_machine_vector mv_edosk7760 __initmv = {
.mv_name = "EDOSK7760",
- .mv_nr_irqs = 128,
};
diff --git a/arch/sh/boards/board-espt.c b/arch/sh/boards/board-espt.c
index b3ae9d38cbc0..6cba0a7068bc 100644
--- a/arch/sh/boards/board-espt.c
+++ b/arch/sh/boards/board-espt.c
@@ -14,6 +14,7 @@
#include <linux/mtd/physmap.h>
#include <linux/io.h>
#include <linux/sh_eth.h>
+#include <linux/sh_intc.h>
#include <asm/machvec.h>
#include <asm/sizes.h>
@@ -71,7 +72,7 @@ static struct resource sh_eth_resources[] = {
.flags = IORESOURCE_MEM,
}, {
- .start = 57, /* irq number */
+ .start = evt2irq(0x920), /* irq number */
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/sh/boards/board-magicpanelr2.c b/arch/sh/boards/board-magicpanelr2.c
index b2ca1d9948fb..90568f9de3a4 100644
--- a/arch/sh/boards/board-magicpanelr2.c
+++ b/arch/sh/boards/board-magicpanelr2.c
@@ -19,6 +19,7 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
#include <linux/mtd/map.h>
+#include <linux/sh_intc.h>
#include <mach/magicpanelr2.h>
#include <asm/heartbeat.h>
#include <cpu/sh7720.h>
@@ -245,8 +246,8 @@ static struct resource smsc911x_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 35,
- .end = 35,
+ .start = evt2irq(0x660),
+ .end = evt2irq(0x660),
.flags = IORESOURCE_IRQ,
},
};
@@ -358,17 +359,17 @@ static void __init init_mpr2_IRQ(void)
{
plat_irq_setup_pins(IRQ_MODE_IRQ); /* install handlers for IRQ0-5 */
- irq_set_irq_type(32, IRQ_TYPE_LEVEL_LOW); /* IRQ0 CAN1 */
- irq_set_irq_type(33, IRQ_TYPE_LEVEL_LOW); /* IRQ1 CAN2 */
- irq_set_irq_type(34, IRQ_TYPE_LEVEL_LOW); /* IRQ2 CAN3 */
- irq_set_irq_type(35, IRQ_TYPE_LEVEL_LOW); /* IRQ3 SMSC9115 */
- irq_set_irq_type(36, IRQ_TYPE_EDGE_RISING); /* IRQ4 touchscreen */
- irq_set_irq_type(37, IRQ_TYPE_EDGE_FALLING); /* IRQ5 touchscreen */
-
- intc_set_priority(32, 13); /* IRQ0 CAN1 */
- intc_set_priority(33, 13); /* IRQ0 CAN2 */
- intc_set_priority(34, 13); /* IRQ0 CAN3 */
- intc_set_priority(35, 6); /* IRQ3 SMSC9115 */
+ irq_set_irq_type(evt2irq(0x600), IRQ_TYPE_LEVEL_LOW); /* IRQ0 CAN1 */
+ irq_set_irq_type(evt2irq(0x620), IRQ_TYPE_LEVEL_LOW); /* IRQ1 CAN2 */
+ irq_set_irq_type(evt2irq(0x640), IRQ_TYPE_LEVEL_LOW); /* IRQ2 CAN3 */
+ irq_set_irq_type(evt2irq(0x660), IRQ_TYPE_LEVEL_LOW); /* IRQ3 SMSC9115 */
+ irq_set_irq_type(evt2irq(0x680), IRQ_TYPE_EDGE_RISING); /* IRQ4 touchscreen */
+ irq_set_irq_type(evt2irq(0x6a0), IRQ_TYPE_EDGE_FALLING); /* IRQ5 touchscreen */
+
+ intc_set_priority(evt2irq(0x600), 13); /* IRQ0 CAN1 */
+ intc_set_priority(evt2irq(0x620), 13); /* IRQ0 CAN2 */
+ intc_set_priority(evt2irq(0x640), 13); /* IRQ0 CAN3 */
+ intc_set_priority(evt2irq(0x660), 6); /* IRQ3 SMSC9115 */
}
/*
diff --git a/arch/sh/boards/board-polaris.c b/arch/sh/boards/board-polaris.c
index 594866356c24..37d03c097ae9 100644
--- a/arch/sh/boards/board-polaris.c
+++ b/arch/sh/boards/board-polaris.c
@@ -141,6 +141,5 @@ static void __init init_polaris_irq(void)
static struct sh_machine_vector mv_polaris __initmv = {
.mv_name = "Polaris",
- .mv_nr_irqs = 61,
.mv_init_irq = init_polaris_irq,
};
diff --git a/arch/sh/boards/board-secureedge5410.c b/arch/sh/boards/board-secureedge5410.c
index 03820c3c93d4..98b36205aa7b 100644
--- a/arch/sh/boards/board-secureedge5410.c
+++ b/arch/sh/boards/board-secureedge5410.c
@@ -71,6 +71,5 @@ static void __init init_snapgear_IRQ(void)
*/
static struct sh_machine_vector mv_snapgear __initmv = {
.mv_name = "SnapGear SecureEdge5410",
- .mv_nr_irqs = 72,
.mv_init_irq = init_snapgear_IRQ,
};
diff --git a/arch/sh/boards/board-sh7757lcr.c b/arch/sh/boards/board-sh7757lcr.c
index 24b1ee410daa..5087f8bb4cff 100644
--- a/arch/sh/boards/board-sh7757lcr.c
+++ b/arch/sh/boards/board-sh7757lcr.c
@@ -19,6 +19,7 @@
#include <linux/mmc/sh_mmcif.h>
#include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/sh_eth.h>
+#include <linux/sh_intc.h>
#include <linux/usb/renesas_usbhs.h>
#include <cpu/sh7757.h>
#include <asm/heartbeat.h>
@@ -65,8 +66,8 @@ static struct resource sh_eth0_resources[] = {
.end = 0xfef001ff,
.flags = IORESOURCE_MEM,
}, {
- .start = 84,
- .end = 84,
+ .start = evt2irq(0xc80),
+ .end = evt2irq(0xc80),
.flags = IORESOURCE_IRQ,
},
};
@@ -94,8 +95,8 @@ static struct resource sh_eth1_resources[] = {
.end = 0xfef009ff,
.flags = IORESOURCE_MEM,
}, {
- .start = 84,
- .end = 84,
+ .start = evt2irq(0xc80),
+ .end = evt2irq(0xc80),
.flags = IORESOURCE_IRQ,
},
};
@@ -139,8 +140,8 @@ static struct resource sh_eth_giga0_resources[] = {
.end = 0xfee01fff,
.flags = IORESOURCE_MEM,
}, {
- .start = 315,
- .end = 315,
+ .start = evt2irq(0x2960),
+ .end = evt2irq(0x2960),
.flags = IORESOURCE_IRQ,
},
};
@@ -174,8 +175,8 @@ static struct resource sh_eth_giga1_resources[] = {
.end = 0xfee01fff,
.flags = IORESOURCE_MEM,
}, {
- .start = 316,
- .end = 316,
+ .start = evt2irq(0x2980),
+ .end = evt2irq(0x2980),
.flags = IORESOURCE_IRQ,
},
};
@@ -206,11 +207,11 @@ static struct resource sh_mmcif_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 211,
+ .start = evt2irq(0x1c60),
.flags = IORESOURCE_IRQ,
},
[2] = {
- .start = 212,
+ .start = evt2irq(0x1c80),
.flags = IORESOURCE_IRQ,
},
};
@@ -248,7 +249,7 @@ static struct resource sdhi_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 20,
+ .start = evt2irq(0x480),
.flags = IORESOURCE_IRQ,
},
};
@@ -284,8 +285,8 @@ static struct resource usb0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 50,
- .end = 50,
+ .start = evt2irq(0x840),
+ .end = evt2irq(0x840),
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/sh/boards/board-sh7785lcr.c b/arch/sh/boards/board-sh7785lcr.c
index d0d6221d7c2e..2c4771ee84cd 100644
--- a/arch/sh/boards/board-sh7785lcr.c
+++ b/arch/sh/boards/board-sh7785lcr.c
@@ -20,6 +20,7 @@
#include <linux/i2c-pca-platform.h>
#include <linux/i2c-algo-pca.h>
#include <linux/usb/r8a66597.h>
+#include <linux/sh_intc.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/clk.h>
@@ -105,8 +106,8 @@ static struct resource r8a66597_usb_host_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 2,
- .end = 2,
+ .start = evt2irq(0x240),
+ .end = evt2irq(0x240),
.flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
},
};
@@ -135,7 +136,7 @@ static struct resource sm501_resources[] = {
.flags = IORESOURCE_MEM,
},
[2] = {
- .start = 10,
+ .start = evt2irq(0x340),
.flags = IORESOURCE_IRQ,
},
};
@@ -223,8 +224,8 @@ static struct resource i2c_proto_resources[] = {
.flags = IORESOURCE_MEM | IORESOURCE_MEM_8BIT,
},
[1] = {
- .start = 12,
- .end = 12,
+ .start = evt2irq(0x380),
+ .end = evt2irq(0x380),
.flags = IORESOURCE_IRQ,
},
};
@@ -236,8 +237,8 @@ static struct resource i2c_resources[] = {
.flags = IORESOURCE_MEM | IORESOURCE_MEM_8BIT,
},
[1] = {
- .start = 12,
- .end = 12,
+ .start = evt2irq(0x380),
+ .end = evt2irq(0x380),
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/sh/boards/board-urquell.c b/arch/sh/boards/board-urquell.c
index 24e3316c5c17..b52abcc5259a 100644
--- a/arch/sh/boards/board-urquell.c
+++ b/arch/sh/boards/board-urquell.c
@@ -20,6 +20,7 @@
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/clk.h>
+#include <linux/sh_intc.h>
#include <mach/urquell.h>
#include <cpu/sh7786.h>
#include <asm/heartbeat.h>
@@ -78,7 +79,7 @@ static struct resource smc91x_eth_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 11,
+ .start = evt2irq(0x360),
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c
index 8cf02e343333..f33ebf447073 100644
--- a/arch/sh/boards/mach-ap325rxa/setup.c
+++ b/arch/sh/boards/mach-ap325rxa/setup.c
@@ -23,6 +23,7 @@
#include <linux/smsc911x.h>
#include <linux/gpio.h>
#include <linux/videodev2.h>
+#include <linux/sh_intc.h>
#include <media/ov772x.h>
#include <media/soc_camera.h>
#include <media/soc_camera_platform.h>
@@ -47,8 +48,8 @@ static struct resource smsc9118_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 35,
- .end = 35,
+ .start = evt2irq(0x660),
+ .end = evt2irq(0x660),
.flags = IORESOURCE_IRQ,
}
};
@@ -166,7 +167,7 @@ static int ap320_wvga_set_brightness(int brightness)
__raw_writew(0, FPGA_BKLREG);
gpio_set_value(GPIO_PTS3, 1);
}
-
+
return 0;
}
@@ -236,7 +237,7 @@ static struct resource lcdc_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 28,
+ .start = evt2irq(0x580),
.flags = IORESOURCE_IRQ,
},
};
@@ -404,7 +405,7 @@ static struct resource ceu_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 52,
+ .start = evt2irq(0x880),
.flags = IORESOURCE_IRQ,
},
[2] = {
@@ -430,7 +431,7 @@ static struct resource sdhi0_cn3_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 100,
+ .start = evt2irq(0xe80),
.flags = IORESOURCE_IRQ,
},
};
@@ -457,7 +458,7 @@ static struct resource sdhi1_cn7_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 23,
+ .start = evt2irq(0x4e0),
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/sh/boards/mach-cayman/setup.c b/arch/sh/boards/mach-cayman/setup.c
index e89e8e122a26..340fd40b381d 100644
--- a/arch/sh/boards/mach-cayman/setup.c
+++ b/arch/sh/boards/mach-cayman/setup.c
@@ -181,7 +181,6 @@ extern void init_cayman_irq(void);
static struct sh_machine_vector mv_cayman __initmv = {
.mv_name = "Hitachi Cayman",
- .mv_nr_irqs = 64,
.mv_ioport_map = cayman_ioport_map,
.mv_init_irq = init_cayman_irq,
};
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index d12fe9ddf3da..4158d70c0dea 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -29,9 +29,11 @@
#include <linux/input.h>
#include <linux/input/sh_keysc.h>
#include <linux/sh_eth.h>
+#include <linux/sh_intc.h>
#include <linux/videodev2.h>
#include <video/sh_mobile_lcdc.h>
#include <sound/sh_fsi.h>
+#include <sound/simple_card.h>
#include <media/sh_mobile_ceu.h>
#include <media/soc_camera.h>
#include <media/tw9910.h>
@@ -137,7 +139,7 @@ static struct resource sh_eth_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 91,
+ .start = evt2irq(0xd60),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
},
};
@@ -178,8 +180,8 @@ static struct resource usb0_host_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 65,
- .end = 65,
+ .start = evt2irq(0xa20),
+ .end = evt2irq(0xa20),
.flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
},
};
@@ -214,8 +216,8 @@ static struct resource usb1_common_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 66,
- .end = 66,
+ .start = evt2irq(0xa40),
+ .end = evt2irq(0xa40),
.flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
},
};
@@ -261,8 +263,8 @@ static struct resource usbhs_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 66,
- .end = 66,
+ .start = evt2irq(0xa40),
+ .end = evt2irq(0xa40),
.flags = IORESOURCE_IRQ,
},
};
@@ -348,7 +350,7 @@ static struct resource lcdc_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 106,
+ .start = evt2irq(0xf40),
.flags = IORESOURCE_IRQ,
},
};
@@ -375,7 +377,7 @@ static struct resource ceu0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 52,
+ .start = evt2irq(0x880),
.flags = IORESOURCE_IRQ,
},
[2] = {
@@ -406,7 +408,7 @@ static struct resource ceu1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 63,
+ .start = evt2irq(0x9e0),
.flags = IORESOURCE_IRQ,
},
[2] = {
@@ -437,7 +439,7 @@ static struct i2c_board_info i2c1_devices[] = {
},
{
I2C_BOARD_INFO("lis3lv02d", 0x1c),
- .irq = 33,
+ .irq = evt2irq(0x620),
}
};
@@ -463,7 +465,7 @@ static struct resource keysc_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 79,
+ .start = evt2irq(0xbe0),
.flags = IORESOURCE_IRQ,
},
};
@@ -479,7 +481,8 @@ static struct platform_device keysc_device = {
};
/* TouchScreen */
-#define IRQ0 32
+#define IRQ0 evt2irq(0x600)
+
static int ts_get_pendown_state(void)
{
int val = 0;
@@ -544,7 +547,7 @@ static struct resource sdhi0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 100,
+ .start = evt2irq(0xe80),
.flags = IORESOURCE_IRQ,
},
};
@@ -588,7 +591,7 @@ static struct resource sdhi1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 23,
+ .start = evt2irq(0x4e0),
.flags = IORESOURCE_IRQ,
},
};
@@ -653,7 +656,7 @@ static struct resource msiof0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 84,
+ .start = evt2irq(0xc80),
.flags = IORESOURCE_IRQ,
},
};
@@ -794,7 +797,7 @@ static struct resource fsi_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 108,
+ .start = evt2irq(0xf80),
.flags = IORESOURCE_IRQ,
},
};
@@ -809,6 +812,30 @@ static struct platform_device fsi_device = {
},
};
+static struct asoc_simple_dai_init_info fsi_da7210_init_info = {
+ .fmt = SND_SOC_DAIFMT_I2S,
+ .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM,
+ .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS,
+};
+
+static struct asoc_simple_card_info fsi_da7210_info = {
+ .name = "DA7210",
+ .card = "FSIB-DA7210",
+ .cpu_dai = "fsib-dai",
+ .codec = "da7210.0-001a",
+ .platform = "sh_fsi.0",
+ .codec_dai = "da7210-hifi",
+ .init = &fsi_da7210_init_info,
+};
+
+static struct platform_device fsi_da7210_device = {
+ .name = "asoc-simple-card",
+ .dev = {
+ .platform_data = &fsi_da7210_info,
+ },
+};
+
+
/* IrDA */
static struct resource irda_resources[] = {
[0] = {
@@ -818,7 +845,7 @@ static struct resource irda_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 20,
+ .start = evt2irq(0x480),
.flags = IORESOURCE_IRQ,
},
};
@@ -855,7 +882,7 @@ static struct resource sh_vou_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 55,
+ .start = evt2irq(0x8e0),
.flags = IORESOURCE_IRQ,
},
};
@@ -891,12 +918,12 @@ static struct resource sh_mmcif_resources[] = {
},
[1] = {
/* MMC2I */
- .start = 29,
+ .start = evt2irq(0x5a0),
.flags = IORESOURCE_IRQ,
},
[2] = {
/* MMC3I */
- .start = 30,
+ .start = evt2irq(0x5c0),
.flags = IORESOURCE_IRQ,
},
};
@@ -945,6 +972,7 @@ static struct platform_device *ecovec_devices[] __initdata = {
&camera_devices[1],
&camera_devices[2],
&fsi_device,
+ &fsi_da7210_device,
&irda_device,
&vou_device,
#if defined(CONFIG_MMC_SH_MMCIF) || defined(CONFIG_MMC_SH_MMCIF_MODULE)
diff --git a/arch/sh/boards/mach-hp6xx/setup.c b/arch/sh/boards/mach-hp6xx/setup.c
index 8c9add5f4cfa..05797b33f68e 100644
--- a/arch/sh/boards/mach-hp6xx/setup.c
+++ b/arch/sh/boards/mach-hp6xx/setup.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/irq.h>
+#include <linux/sh_intc.h>
#include <sound/sh_dac_audio.h>
#include <asm/hd64461.h>
#include <asm/io.h>
@@ -35,7 +36,7 @@ static struct resource cf_ide_resources[] = {
.flags = IORESOURCE_MEM,
},
[2] = {
- .start = 77,
+ .start = evt2irq(0xba0),
.flags = IORESOURCE_IRQ,
},
};
@@ -168,8 +169,6 @@ device_initcall(hp6xx_devices_setup);
static struct sh_machine_vector mv_hp6xx __initmv = {
.mv_name = "hp6xx",
.mv_setup = hp6xx_setup,
- /* IRQ's : CPU(64) + CCHIP(16) + FREE_TO_USE(6) */
- .mv_nr_irqs = HD64461_IRQBASE + HD64461_IRQ_NUM + 6,
/* Enable IRQ0 -> IRQ3 in IRQ_MODE */
.mv_init_irq = hp6xx_init_irq,
};
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c
index d04a55d3b877..158c9176e42a 100644
--- a/arch/sh/boards/mach-kfr2r09/setup.c
+++ b/arch/sh/boards/mach-kfr2r09/setup.c
@@ -23,6 +23,7 @@
#include <linux/i2c.h>
#include <linux/usb/r8a66597.h>
#include <linux/videodev2.h>
+#include <linux/sh_intc.h>
#include <media/rj54n1cb0c.h>
#include <media/soc_camera.h>
#include <media/sh_mobile_ceu.h>
@@ -110,7 +111,7 @@ static struct resource kfr2r09_sh_keysc_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 79,
+ .start = evt2irq(0xbe0),
.flags = IORESOURCE_IRQ,
},
};
@@ -175,7 +176,7 @@ static struct resource kfr2r09_sh_lcdc_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 106,
+ .start = evt2irq(0xf40),
.flags = IORESOURCE_IRQ,
},
};
@@ -200,8 +201,8 @@ static struct resource kfr2r09_usb0_gadget_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 65,
- .end = 65,
+ .start = evtirq(0xa20),
+ .end = evtirq(0xa20),
.flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
},
};
@@ -230,8 +231,8 @@ static struct resource kfr2r09_ceu_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 52,
- .end = 52,
+ .start = evt2irq(0x880),
+ .end = evt2irq(0x880),
.flags = IORESOURCE_IRQ,
},
[2] = {
@@ -348,7 +349,7 @@ static struct resource kfr2r09_sh_sdhi0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 100,
+ .start = evt2irq(0xe80),
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/sh/boards/mach-lboxre2/setup.c b/arch/sh/boards/mach-lboxre2/setup.c
index 79b4e0d77b71..6660622aa457 100644
--- a/arch/sh/boards/mach-lboxre2/setup.c
+++ b/arch/sh/boards/mach-lboxre2/setup.c
@@ -79,6 +79,5 @@ device_initcall(lboxre2_devices_setup);
*/
static struct sh_machine_vector mv_lboxre2 __initmv = {
.mv_name = "L-BOX RE2",
- .mv_nr_irqs = 72,
.mv_init_irq = init_lboxre2_IRQ,
};
diff --git a/arch/sh/boards/mach-microdev/setup.c b/arch/sh/boards/mach-microdev/setup.c
index d8a747291e03..6c66ee4d842b 100644
--- a/arch/sh/boards/mach-microdev/setup.c
+++ b/arch/sh/boards/mach-microdev/setup.c
@@ -194,7 +194,6 @@ device_initcall(microdev_devices_setup);
*/
static struct sh_machine_vector mv_sh4202_microdev __initmv = {
.mv_name = "SH4-202 MicroDev",
- .mv_nr_irqs = 72,
.mv_ioport_map = microdev_ioport_map,
.mv_init_irq = init_microdev_irq,
};
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c
index ff6f69c6906e..34cd0c5ff2e1 100644
--- a/arch/sh/boards/mach-migor/setup.c
+++ b/arch/sh/boards/mach-migor/setup.c
@@ -22,6 +22,7 @@
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/videodev2.h>
+#include <linux/sh_intc.h>
#include <video/sh_mobile_lcdc.h>
#include <media/sh_mobile_ceu.h>
#include <media/ov772x.h>
@@ -54,7 +55,7 @@ static struct resource smc91x_eth_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 32, /* IRQ0 */
+ .start = evt2irq(0x600), /* IRQ0 */
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
},
};
@@ -88,7 +89,7 @@ static struct resource sh_keysc_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 79,
+ .start = evt2irq(0xbe0),
.flags = IORESOURCE_IRQ,
},
};
@@ -285,7 +286,7 @@ static struct resource migor_lcdc_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 28,
+ .start = evt2irq(0x580),
.flags = IORESOURCE_IRQ,
},
};
@@ -368,7 +369,7 @@ static struct resource migor_ceu_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 52,
+ .start = evt2irq(0x880),
.flags = IORESOURCE_IRQ,
},
[2] = {
@@ -394,7 +395,7 @@ static struct resource sdhi_cn9_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 100,
+ .start = evt2irq(0xe80),
.flags = IORESOURCE_IRQ,
},
};
@@ -420,7 +421,7 @@ static struct i2c_board_info migor_i2c_devices[] = {
},
{
I2C_BOARD_INFO("migor_ts", 0x51),
- .irq = 38, /* IRQ6 */
+ .irq = evt2irq(0x6c0), /* IRQ6 */
},
{
I2C_BOARD_INFO("wm8978", 0x1a),
diff --git a/arch/sh/boards/mach-rsk/Kconfig b/arch/sh/boards/mach-rsk/Kconfig
index aeff3b042205..458a11ffd022 100644
--- a/arch/sh/boards/mach-rsk/Kconfig
+++ b/arch/sh/boards/mach-rsk/Kconfig
@@ -13,6 +13,16 @@ config SH_RSK7203
select ARCH_REQUIRE_GPIOLIB
depends on CPU_SUBTYPE_SH7203
+config SH_RSK7264
+ bool "RSK2+SH7264"
+ select ARCH_REQUIRE_GPIOLIB
+ depends on CPU_SUBTYPE_SH7264
+
+config SH_RSK7269
+ bool "RSK2+SH7269"
+ select ARCH_REQUIRE_GPIOLIB
+ depends on CPU_SUBTYPE_SH7269
+
endchoice
endif
diff --git a/arch/sh/boards/mach-rsk/Makefile b/arch/sh/boards/mach-rsk/Makefile
index 498da75ce38b..6a4e1b538a62 100644
--- a/arch/sh/boards/mach-rsk/Makefile
+++ b/arch/sh/boards/mach-rsk/Makefile
@@ -1,2 +1,4 @@
obj-y := setup.o
obj-$(CONFIG_SH_RSK7203) += devices-rsk7203.o
+obj-$(CONFIG_SH_RSK7264) += devices-rsk7264.o
+obj-$(CONFIG_SH_RSK7269) += devices-rsk7269.o
diff --git a/arch/sh/boards/mach-rsk/devices-rsk7264.c b/arch/sh/boards/mach-rsk/devices-rsk7264.c
new file mode 100644
index 000000000000..7251e37a842f
--- /dev/null
+++ b/arch/sh/boards/mach-rsk/devices-rsk7264.c
@@ -0,0 +1,58 @@
+/*
+ * RSK+SH7264 Support.
+ *
+ * Copyright (C) 2012 Renesas Electronics Europe
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/smsc911x.h>
+#include <asm/machvec.h>
+#include <asm/io.h>
+
+static struct smsc911x_platform_config smsc911x_config = {
+ .phy_interface = PHY_INTERFACE_MODE_MII,
+ .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+ .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+ .flags = SMSC911X_USE_16BIT | SMSC911X_SWAP_FIFO,
+};
+
+static struct resource smsc911x_resources[] = {
+ [0] = {
+ .start = 0x28000000,
+ .end = 0x280000ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 65,
+ .end = 65,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device smsc911x_device = {
+ .name = "smsc911x",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(smsc911x_resources),
+ .resource = smsc911x_resources,
+ .dev = {
+ .platform_data = &smsc911x_config,
+ },
+};
+
+static struct platform_device *rsk7264_devices[] __initdata = {
+ &smsc911x_device,
+};
+
+static int __init rsk7264_devices_setup(void)
+{
+ return platform_add_devices(rsk7264_devices,
+ ARRAY_SIZE(rsk7264_devices));
+}
+device_initcall(rsk7264_devices_setup);
diff --git a/arch/sh/boards/mach-rsk/devices-rsk7269.c b/arch/sh/boards/mach-rsk/devices-rsk7269.c
new file mode 100644
index 000000000000..4a544591d6f0
--- /dev/null
+++ b/arch/sh/boards/mach-rsk/devices-rsk7269.c
@@ -0,0 +1,60 @@
+/*
+ * RSK+SH7269 Support
+ *
+ * Copyright (C) 2012 Renesas Electronics Europe Ltd
+ * Copyright (C) 2012 Phil Edworthy
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/smsc911x.h>
+#include <linux/gpio.h>
+#include <asm/machvec.h>
+#include <asm/io.h>
+
+static struct smsc911x_platform_config smsc911x_config = {
+ .phy_interface = PHY_INTERFACE_MODE_MII,
+ .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+ .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL,
+ .flags = SMSC911X_USE_16BIT | SMSC911X_SWAP_FIFO,
+};
+
+static struct resource smsc911x_resources[] = {
+ [0] = {
+ .start = 0x24000000,
+ .end = 0x240000ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 85,
+ .end = 85,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device smsc911x_device = {
+ .name = "smsc911x",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(smsc911x_resources),
+ .resource = smsc911x_resources,
+ .dev = {
+ .platform_data = &smsc911x_config,
+ },
+};
+
+static struct platform_device *rsk7269_devices[] __initdata = {
+ &smsc911x_device,
+};
+
+static int __init rsk7269_devices_setup(void)
+{
+ return platform_add_devices(rsk7269_devices,
+ ARRAY_SIZE(rsk7269_devices));
+}
+device_initcall(rsk7269_devices_setup);
diff --git a/arch/sh/boards/mach-sdk7780/setup.c b/arch/sh/boards/mach-sdk7780/setup.c
index 4da38db4b5fe..2241659c3299 100644
--- a/arch/sh/boards/mach-sdk7780/setup.c
+++ b/arch/sh/boards/mach-sdk7780/setup.c
@@ -94,7 +94,6 @@ static void __init sdk7780_setup(char **cmdline_p)
static struct sh_machine_vector mv_se7780 __initmv = {
.mv_name = "Renesas SDK7780-R3" ,
.mv_setup = sdk7780_setup,
- .mv_nr_irqs = 111,
.mv_init_irq = init_sdk7780_IRQ,
};
diff --git a/arch/sh/boards/mach-se/7206/setup.c b/arch/sh/boards/mach-se/7206/setup.c
index 8ab8330e3fd1..68883ec95682 100644
--- a/arch/sh/boards/mach-se/7206/setup.c
+++ b/arch/sh/boards/mach-se/7206/setup.c
@@ -90,7 +90,6 @@ static int se7206_mode_pins(void)
static struct sh_machine_vector mv_se __initmv = {
.mv_name = "SolutionEngine",
- .mv_nr_irqs = 256,
.mv_init_irq = init_se7206_IRQ,
.mv_mode_pins = se7206_mode_pins,
};
diff --git a/arch/sh/boards/mach-se/770x/setup.c b/arch/sh/boards/mach-se/770x/setup.c
index 31330c65c0ce..9759d6ba7ffb 100644
--- a/arch/sh/boards/mach-se/770x/setup.c
+++ b/arch/sh/boards/mach-se/770x/setup.c
@@ -184,16 +184,5 @@ device_initcall(se_devices_setup);
static struct sh_machine_vector mv_se __initmv = {
.mv_name = "SolutionEngine",
.mv_setup = smsc_setup,
-#if defined(CONFIG_CPU_SH4)
- .mv_nr_irqs = 48,
-#elif defined(CONFIG_CPU_SUBTYPE_SH7708)
- .mv_nr_irqs = 32,
-#elif defined(CONFIG_CPU_SUBTYPE_SH7709)
- .mv_nr_irqs = 61,
-#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
- .mv_nr_irqs = 86,
-#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
- .mv_nr_irqs = 104,
-#endif
.mv_init_irq = init_se_IRQ,
};
diff --git a/arch/sh/boards/mach-se/7721/setup.c b/arch/sh/boards/mach-se/7721/setup.c
index 7416ad7ee53a..a0b3dba34ebf 100644
--- a/arch/sh/boards/mach-se/7721/setup.c
+++ b/arch/sh/boards/mach-se/7721/setup.c
@@ -92,6 +92,5 @@ static void __init se7721_setup(char **cmdline_p)
struct sh_machine_vector mv_se7721 __initmv = {
.mv_name = "Solution Engine 7721",
.mv_setup = se7721_setup,
- .mv_nr_irqs = 109,
.mv_init_irq = init_se7721_IRQ,
};
diff --git a/arch/sh/boards/mach-se/7722/setup.c b/arch/sh/boards/mach-se/7722/setup.c
index e1963fecd761..8f7f0550cfde 100644
--- a/arch/sh/boards/mach-se/7722/setup.c
+++ b/arch/sh/boards/mach-se/7722/setup.c
@@ -16,6 +16,7 @@
#include <linux/input.h>
#include <linux/input/sh_keysc.h>
#include <linux/smc91x.h>
+#include <linux/sh_intc.h>
#include <mach-se/mach/se7722.h>
#include <mach-se/mach/mrshpc.h>
#include <asm/machvec.h>
@@ -114,7 +115,7 @@ static struct resource sh_keysc_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 79,
+ .start = evt2irq(0xbe0),
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c
index c540b16547c3..ffbf5bc7366b 100644
--- a/arch/sh/boards/mach-se/7724/setup.c
+++ b/arch/sh/boards/mach-se/7724/setup.c
@@ -24,10 +24,12 @@
#include <linux/input/sh_keysc.h>
#include <linux/usb/r8a66597.h>
#include <linux/sh_eth.h>
+#include <linux/sh_intc.h>
#include <linux/videodev2.h>
#include <video/sh_mobile_lcdc.h>
#include <media/sh_mobile_ceu.h>
#include <sound/sh_fsi.h>
+#include <sound/simple_card.h>
#include <asm/io.h>
#include <asm/heartbeat.h>
#include <asm/clock.h>
@@ -197,7 +199,7 @@ static struct resource lcdc_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 106,
+ .start = evt2irq(0xf40),
.flags = IORESOURCE_IRQ,
},
};
@@ -224,7 +226,7 @@ static struct resource ceu0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 52,
+ .start = evt2irq(0x880),
.flags = IORESOURCE_IRQ,
},
[2] = {
@@ -255,7 +257,7 @@ static struct resource ceu1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 63,
+ .start = evt2irq(0x9e0),
.flags = IORESOURCE_IRQ,
},
[2] = {
@@ -289,7 +291,7 @@ static struct resource fsi_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 108,
+ .start = evt2irq(0xf80),
.flags = IORESOURCE_IRQ,
},
};
@@ -304,17 +306,25 @@ static struct platform_device fsi_device = {
},
};
-static struct fsi_ak4642_info fsi_ak4642_info = {
+static struct asoc_simple_dai_init_info fsi2_ak4642_init_info = {
+ .fmt = SND_SOC_DAIFMT_LEFT_J,
+ .codec_daifmt = SND_SOC_DAIFMT_CBM_CFM,
+ .cpu_daifmt = SND_SOC_DAIFMT_CBS_CFS,
+ .sysclk = 11289600,
+};
+
+static struct asoc_simple_card_info fsi_ak4642_info = {
.name = "AK4642",
.card = "FSIA-AK4642",
.cpu_dai = "fsia-dai",
.codec = "ak4642-codec.0-0012",
.platform = "sh_fsi.0",
- .id = FSI_PORT_A,
+ .codec_dai = "ak4642-hifi",
+ .init = &fsi2_ak4642_init_info,
};
static struct platform_device fsi_ak4642_device = {
- .name = "fsi-ak4642-audio",
+ .name = "asoc-simple-card",
.dev = {
.platform_data = &fsi_ak4642_info,
},
@@ -343,7 +353,7 @@ static struct resource keysc_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 79,
+ .start = evt2irq(0xbe0),
.flags = IORESOURCE_IRQ,
},
};
@@ -366,7 +376,7 @@ static struct resource sh_eth_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 91,
+ .start = evt2irq(0xd60),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
},
};
@@ -397,8 +407,8 @@ static struct resource sh7724_usb0_host_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 65,
- .end = 65,
+ .start = evt2irq(0xa20),
+ .end = evt2irq(0xa20),
.flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
},
};
@@ -426,8 +436,8 @@ static struct resource sh7724_usb1_gadget_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 66,
- .end = 66,
+ .start = evt2irq(0xa40),
+ .end = evt2irq(0xa40),
.flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
},
};
@@ -452,7 +462,7 @@ static struct resource sdhi0_cn7_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 100,
+ .start = evt2irq(0xe80),
.flags = IORESOURCE_IRQ,
},
};
@@ -481,7 +491,7 @@ static struct resource sdhi1_cn8_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 23,
+ .start = evt2irq(0x4e0),
.flags = IORESOURCE_IRQ,
},
};
@@ -511,7 +521,7 @@ static struct resource irda_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 20,
+ .start = evt2irq(0x480),
.flags = IORESOURCE_IRQ,
},
};
@@ -549,7 +559,7 @@ static struct resource sh_vou_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 55,
+ .start = evt2irq(0x8e0),
.flags = IORESOURCE_IRQ,
},
};
@@ -595,6 +605,7 @@ static struct i2c_board_info i2c0_devices[] = {
#define EEPROM_DATA 0xBA20600C
#define EEPROM_STAT 0xBA206010
#define EEPROM_STRT 0xBA206014
+
static int __init sh_eth_is_eeprom_ready(void)
{
int t = 10000;
@@ -651,7 +662,6 @@ extern char ms7724se_sdram_enter_end;
extern char ms7724se_sdram_leave_start;
extern char ms7724se_sdram_leave_end;
-
static int __init arch_setup(void)
{
/* enable I2C device */
@@ -928,5 +938,4 @@ device_initcall(devices_setup);
static struct sh_machine_vector mv_ms7724se __initmv = {
.mv_name = "ms7724se",
.mv_init_irq = init_se7724_IRQ,
- .mv_nr_irqs = SE7724_FPGA_IRQ_BASE + SE7724_FPGA_IRQ_NR,
};
diff --git a/arch/sh/boards/mach-se/7751/setup.c b/arch/sh/boards/mach-se/7751/setup.c
index 4ed60c5e221f..820f4e7ba0d2 100644
--- a/arch/sh/boards/mach-se/7751/setup.c
+++ b/arch/sh/boards/mach-se/7751/setup.c
@@ -55,6 +55,5 @@ device_initcall(se7751_devices_setup);
*/
static struct sh_machine_vector mv_7751se __initmv = {
.mv_name = "7751 SolutionEngine",
- .mv_nr_irqs = 72,
.mv_init_irq = init_7751se_IRQ,
};
diff --git a/arch/sh/boards/mach-se/7780/setup.c b/arch/sh/boards/mach-se/7780/setup.c
index 6f7c207138e1..ae5a1d84fdf8 100644
--- a/arch/sh/boards/mach-se/7780/setup.c
+++ b/arch/sh/boards/mach-se/7780/setup.c
@@ -110,6 +110,5 @@ static void __init se7780_setup(char **cmdline_p)
static struct sh_machine_vector mv_se7780 __initmv = {
.mv_name = "Solution Engine 7780" ,
.mv_setup = se7780_setup ,
- .mv_nr_irqs = 111 ,
.mv_init_irq = init_se7780_IRQ,
};
diff --git a/arch/sh/boards/mach-se/board-se7619.c b/arch/sh/boards/mach-se/board-se7619.c
index 82b6d4a5dc02..958bcd7aacc5 100644
--- a/arch/sh/boards/mach-se/board-se7619.c
+++ b/arch/sh/boards/mach-se/board-se7619.c
@@ -22,6 +22,5 @@ static int se7619_mode_pins(void)
static struct sh_machine_vector mv_se __initmv = {
.mv_name = "SolutionEngine",
- .mv_nr_irqs = 108,
.mv_mode_pins = se7619_mode_pins,
};
diff --git a/arch/sh/boards/mach-sh03/setup.c b/arch/sh/boards/mach-sh03/setup.c
index d4f79b2a6514..f582dab59343 100644
--- a/arch/sh/boards/mach-sh03/setup.c
+++ b/arch/sh/boards/mach-sh03/setup.c
@@ -101,6 +101,5 @@ device_initcall(sh03_devices_setup);
static struct sh_machine_vector mv_sh03 __initmv = {
.mv_name = "Interface (CTP/PCI-SH03)",
.mv_setup = sh03_setup,
- .mv_nr_irqs = 48,
.mv_init_irq = init_sh03_IRQ,
};
diff --git a/arch/sh/boards/mach-sh7763rdp/setup.c b/arch/sh/boards/mach-sh7763rdp/setup.c
index dd036f1661db..b7c75298dfb5 100644
--- a/arch/sh/boards/mach-sh7763rdp/setup.c
+++ b/arch/sh/boards/mach-sh7763rdp/setup.c
@@ -18,6 +18,7 @@
#include <linux/fb.h>
#include <linux/io.h>
#include <linux/sh_eth.h>
+#include <linux/sh_intc.h>
#include <mach/sh7763rdp.h>
#include <asm/sh7760fb.h>
@@ -67,7 +68,7 @@ static struct platform_device sh7763rdp_nor_flash_device = {
* SH-Ether
*
* SH Ether of SH7763 has multi IRQ handling.
- * (57,58,59 -> 57)
+ * (0x920,0x940,0x960 -> 0x920)
*/
static struct resource sh_eth_resources[] = {
{
@@ -79,7 +80,7 @@ static struct resource sh_eth_resources[] = {
.end = 0xFEE01FFF,
.flags = IORESOURCE_MEM,
}, {
- .start = 57, /* irq number */
+ .start = evt2irq(0x920), /* irq number */
.flags = IORESOURCE_IRQ,
},
};
@@ -213,6 +214,5 @@ static void __init sh7763rdp_setup(char **cmdline_p)
static struct sh_machine_vector mv_sh7763rdp __initmv = {
.mv_name = "sh7763drp",
.mv_setup = sh7763rdp_setup,
- .mv_nr_irqs = 112,
.mv_init_irq = init_sh7763rdp_IRQ,
};
diff --git a/arch/sh/configs/rsk7264_defconfig b/arch/sh/configs/rsk7264_defconfig
new file mode 100644
index 000000000000..1600426224c2
--- /dev/null
+++ b/arch/sh/configs/rsk7264_defconfig
@@ -0,0 +1,80 @@
+CONFIG_LOCALVERSION="uClinux RSK2+SH7264"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_IKCONFIG=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_NAMESPACES=y
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PERF_COUNTERS=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_SLAB=y
+CONFIG_MMAP_ALLOW_UNINITIALIZED=y
+CONFIG_PROFILING=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_CPU_SUBTYPE_SH7264=y
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_SH_RSK=y
+# CONFIG_SH_TIMER_MTU2 is not set
+CONFIG_BINFMT_FLAT=y
+CONFIG_NET=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=4
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_NETDEVICES=y
+CONFIG_SMSC911X=y
+CONFIG_SMSC_PHY=y
+CONFIG_INPUT_FF_MEMLESS=y
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=8
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_HWMON is not set
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_R8A66597_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DEBUG=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_VFAT_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_ENABLE_MUST_CHECK is not set
+# CONFIG_FTRACE is not set
diff --git a/arch/sh/configs/rsk7269_defconfig b/arch/sh/configs/rsk7269_defconfig
new file mode 100644
index 000000000000..9f062b5837d7
--- /dev/null
+++ b/arch/sh/configs/rsk7269_defconfig
@@ -0,0 +1,65 @@
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_SLAB=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_CPU_SUBTYPE_SH7269=y
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x02000000
+CONFIG_FLATMEM_MANUAL=y
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_SH_RSK=y
+# CONFIG_SH_TIMER_MTU2 is not set
+CONFIG_SH_PCLK_FREQ=66700000
+CONFIG_BINFMT_FLAT=y
+CONFIG_NET=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_FW_LOADER is not set
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_NETDEVICES=y
+CONFIG_SMSC911X=y
+CONFIG_SMSC_PHY=y
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=8
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+# CONFIG_HWMON is not set
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_R8A66597_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DEBUG=y
+CONFIG_USB_LIBUSUAL=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_VFAT_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_FTRACE is not set
diff --git a/arch/sh/configs/sh7785lcr_32bit_defconfig b/arch/sh/configs/sh7785lcr_32bit_defconfig
index 7b9c696ac5e0..9bdcf72ec06a 100644
--- a/arch/sh/configs/sh7785lcr_32bit_defconfig
+++ b/arch/sh/configs/sh7785lcr_32bit_defconfig
@@ -5,7 +5,7 @@ CONFIG_BSD_PROCESS_ACCT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=16
-CONFIG_PERF_COUNTERS=y
+CONFIG_PERF_EVENTS=y
# CONFIG_COMPAT_BRK is not set
CONFIG_SLAB=y
CONFIG_PROFILING=y
diff --git a/arch/sh/drivers/dma/Kconfig b/arch/sh/drivers/dma/Kconfig
index 4d58eb0973d4..cfd5b90a8628 100644
--- a/arch/sh/drivers/dma/Kconfig
+++ b/arch/sh/drivers/dma/Kconfig
@@ -40,23 +40,6 @@ config NR_ONCHIP_DMA_CHANNELS
DMAC supports. This will be 4 for SH7750/SH7751/Sh7750S/SH7091 and 8 for the
SH7750R/SH7751R/SH7760, 12 for the SH7723/SH7780/SH7785/SH7724, default is 6.
-config NR_DMA_CHANNELS_BOOL
- depends on SH_DMA
- bool "Override default number of maximum DMA channels"
- help
- This allows you to forcibly update the maximum number of supported
- DMA channels for a given board. If this is unset, this will default
- to the number of channels that the on-chip DMAC has.
-
-config NR_DMA_CHANNELS
- int "Maximum number of DMA channels"
- depends on SH_DMA && NR_DMA_CHANNELS_BOOL
- default NR_ONCHIP_DMA_CHANNELS
- help
- This allows you to specify the maximum number of DMA channels to
- support. Setting this to a higher value allows for cascading DMACs
- with additional channels.
-
config SH_DMABRG
bool "SH7760 DMABRG support"
depends on CPU_SUBTYPE_SH7760
diff --git a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c
index a60da6dd4d17..4c171f13b0e8 100644
--- a/arch/sh/drivers/dma/dma-sh.c
+++ b/arch/sh/drivers/dma/dma-sh.c
@@ -14,35 +14,72 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/io.h>
#include <mach-dreamcast/mach/dma.h>
#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/dma-sh.h>
+#include <asm/dma-register.h>
+#include <cpu/dma-register.h>
+#include <cpu/dma.h>
-#if defined(DMAE1_IRQ)
-#define NR_DMAE 2
-#else
-#define NR_DMAE 1
+/*
+ * Define the default configuration for dual address memory-memory transfer.
+ * The 0x400 value represents auto-request, external->external.
+ */
+#define RS_DUAL (DM_INC | SM_INC | 0x400 | TS_INDEX2VAL(XMIT_SZ_32BIT))
+
+static unsigned long dma_find_base(unsigned int chan)
+{
+ unsigned long base = SH_DMAC_BASE0;
+
+#ifdef SH_DMAC_BASE1
+ if (chan >= 6)
+ base = SH_DMAC_BASE1;
#endif
-static const char *dmae_name[] = {
- "DMAC Address Error0", "DMAC Address Error1"
-};
+ return base;
+}
+
+static unsigned long dma_base_addr(unsigned int chan)
+{
+ unsigned long base = dma_find_base(chan);
+
+ /* Normalize offset calculation */
+ if (chan >= 9)
+ chan -= 6;
+ if (chan >= 4)
+ base += 0x10;
+
+ return base + (chan * 0x10);
+}
+#ifdef CONFIG_SH_DMA_IRQ_MULTI
static inline unsigned int get_dmte_irq(unsigned int chan)
{
- unsigned int irq = 0;
- if (chan < ARRAY_SIZE(dmte_irq_map))
- irq = dmte_irq_map[chan];
-
-#if defined(CONFIG_SH_DMA_IRQ_MULTI)
- if (irq > DMTE6_IRQ)
- return DMTE6_IRQ;
- return DMTE0_IRQ;
+ return chan >= 6 ? DMTE6_IRQ : DMTE0_IRQ;
+}
#else
- return irq;
+
+static unsigned int dmte_irq_map[] = {
+ DMTE0_IRQ, DMTE0_IRQ + 1, DMTE0_IRQ + 2, DMTE0_IRQ + 3,
+
+#ifdef DMTE4_IRQ
+ DMTE4_IRQ, DMTE4_IRQ + 1,
+#endif
+
+#ifdef DMTE6_IRQ
+ DMTE6_IRQ, DMTE6_IRQ + 1,
+#endif
+
+#ifdef DMTE8_IRQ
+ DMTE8_IRQ, DMTE9_IRQ, DMTE10_IRQ, DMTE11_IRQ,
#endif
+};
+
+static inline unsigned int get_dmte_irq(unsigned int chan)
+{
+ return dmte_irq_map[chan];
}
+#endif
/*
* We determine the correct shift size based off of the CHCR transmit size
@@ -53,9 +90,10 @@ static inline unsigned int get_dmte_irq(unsigned int chan)
* iterations to complete the transfer.
*/
static unsigned int ts_shift[] = TS_SHIFT;
+
static inline unsigned int calc_xmit_shift(struct dma_channel *chan)
{
- u32 chcr = __raw_readl(dma_base_addr[chan->chan] + CHCR);
+ u32 chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR);
int cnt = ((chcr & CHCR_TS_LOW_MASK) >> CHCR_TS_LOW_SHIFT) |
((chcr & CHCR_TS_HIGH_MASK) >> CHCR_TS_HIGH_SHIFT);
@@ -73,13 +111,13 @@ static irqreturn_t dma_tei(int irq, void *dev_id)
struct dma_channel *chan = dev_id;
u32 chcr;
- chcr = __raw_readl(dma_base_addr[chan->chan] + CHCR);
+ chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR);
if (!(chcr & CHCR_TE))
return IRQ_NONE;
chcr &= ~(CHCR_IE | CHCR_DE);
- __raw_writel(chcr, (dma_base_addr[chan->chan] + CHCR));
+ __raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR));
wake_up(&chan->wait_queue);
@@ -91,13 +129,8 @@ static int sh_dmac_request_dma(struct dma_channel *chan)
if (unlikely(!(chan->flags & DMA_TEI_CAPABLE)))
return 0;
- return request_irq(get_dmte_irq(chan->chan), dma_tei,
-#if defined(CONFIG_SH_DMA_IRQ_MULTI)
- IRQF_SHARED,
-#else
- 0,
-#endif
- chan->dev_id, chan);
+ return request_irq(get_dmte_irq(chan->chan), dma_tei, IRQF_SHARED,
+ chan->dev_id, chan);
}
static void sh_dmac_free_dma(struct dma_channel *chan)
@@ -118,7 +151,7 @@ sh_dmac_configure_channel(struct dma_channel *chan, unsigned long chcr)
chan->flags &= ~DMA_TEI_CAPABLE;
}
- __raw_writel(chcr, (dma_base_addr[chan->chan] + CHCR));
+ __raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR));
chan->flags |= DMA_CONFIGURED;
return 0;
@@ -129,13 +162,13 @@ static void sh_dmac_enable_dma(struct dma_channel *chan)
int irq;
u32 chcr;
- chcr = __raw_readl(dma_base_addr[chan->chan] + CHCR);
+ chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR);
chcr |= CHCR_DE;
if (chan->flags & DMA_TEI_CAPABLE)
chcr |= CHCR_IE;
- __raw_writel(chcr, (dma_base_addr[chan->chan] + CHCR));
+ __raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR));
if (chan->flags & DMA_TEI_CAPABLE) {
irq = get_dmte_irq(chan->chan);
@@ -153,9 +186,9 @@ static void sh_dmac_disable_dma(struct dma_channel *chan)
disable_irq(irq);
}
- chcr = __raw_readl(dma_base_addr[chan->chan] + CHCR);
+ chcr = __raw_readl(dma_base_addr(chan->chan) + CHCR);
chcr &= ~(CHCR_DE | CHCR_TE | CHCR_IE);
- __raw_writel(chcr, (dma_base_addr[chan->chan] + CHCR));
+ __raw_writel(chcr, (dma_base_addr(chan->chan) + CHCR));
}
static int sh_dmac_xfer_dma(struct dma_channel *chan)
@@ -186,13 +219,13 @@ static int sh_dmac_xfer_dma(struct dma_channel *chan)
*/
if (chan->sar || (mach_is_dreamcast() &&
chan->chan == PVR2_CASCADE_CHAN))
- __raw_writel(chan->sar, (dma_base_addr[chan->chan]+SAR));
+ __raw_writel(chan->sar, (dma_base_addr(chan->chan) + SAR));
if (chan->dar || (mach_is_dreamcast() &&
chan->chan == PVR2_CASCADE_CHAN))
- __raw_writel(chan->dar, (dma_base_addr[chan->chan] + DAR));
+ __raw_writel(chan->dar, (dma_base_addr(chan->chan) + DAR));
__raw_writel(chan->count >> calc_xmit_shift(chan),
- (dma_base_addr[chan->chan] + TCR));
+ (dma_base_addr(chan->chan) + TCR));
sh_dmac_enable_dma(chan);
@@ -201,13 +234,32 @@ static int sh_dmac_xfer_dma(struct dma_channel *chan)
static int sh_dmac_get_dma_residue(struct dma_channel *chan)
{
- if (!(__raw_readl(dma_base_addr[chan->chan] + CHCR) & CHCR_DE))
+ if (!(__raw_readl(dma_base_addr(chan->chan) + CHCR) & CHCR_DE))
return 0;
- return __raw_readl(dma_base_addr[chan->chan] + TCR)
+ return __raw_readl(dma_base_addr(chan->chan) + TCR)
<< calc_xmit_shift(chan);
}
+/*
+ * DMAOR handling
+ */
+#if defined(CONFIG_CPU_SUBTYPE_SH7723) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7724) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7785)
+#define NR_DMAOR 2
+#else
+#define NR_DMAOR 1
+#endif
+
+/*
+ * DMAOR bases are broken out amongst channel groups. DMAOR0 manages
+ * channels 0 - 5, DMAOR1 6 - 11 (optional).
+ */
+#define dmaor_read_reg(n) __raw_readw(dma_find_base((n)*6))
+#define dmaor_write_reg(n, data) __raw_writew(data, dma_find_base(n)*6)
+
static inline int dmaor_reset(int no)
{
unsigned long dmaor = dmaor_read_reg(no);
@@ -228,36 +280,86 @@ static inline int dmaor_reset(int no)
return 0;
}
-#if defined(CONFIG_CPU_SH4)
-static irqreturn_t dma_err(int irq, void *dummy)
-{
-#if defined(CONFIG_SH_DMA_IRQ_MULTI)
- int cnt = 0;
- switch (irq) {
-#if defined(DMTE6_IRQ) && defined(DMAE1_IRQ)
- case DMTE6_IRQ:
- cnt++;
+/*
+ * DMAE handling
+ */
+#ifdef CONFIG_CPU_SH4
+
+#if defined(DMAE1_IRQ)
+#define NR_DMAE 2
+#else
+#define NR_DMAE 1
#endif
- case DMTE0_IRQ:
- if (dmaor_read_reg(cnt) & (DMAOR_NMIF | DMAOR_AE)) {
- disable_irq(irq);
- /* DMA multi and error IRQ */
- return IRQ_HANDLED;
- }
- default:
- return IRQ_NONE;
- }
+
+static const char *dmae_name[] = {
+ "DMAC Address Error0",
+ "DMAC Address Error1"
+};
+
+#ifdef CONFIG_SH_DMA_IRQ_MULTI
+static inline unsigned int get_dma_error_irq(int n)
+{
+ return get_dmte_irq(n * 6);
+}
#else
- dmaor_reset(0);
-#if defined(CONFIG_CPU_SUBTYPE_SH7723) || \
- defined(CONFIG_CPU_SUBTYPE_SH7780) || \
- defined(CONFIG_CPU_SUBTYPE_SH7785)
- dmaor_reset(1);
+
+static unsigned int dmae_irq_map[] = {
+ DMAE0_IRQ,
+
+#ifdef DMAE1_IRQ
+ DMAE1_IRQ,
+#endif
+};
+
+static inline unsigned int get_dma_error_irq(int n)
+{
+ return dmae_irq_map[n];
+}
#endif
+
+static irqreturn_t dma_err(int irq, void *dummy)
+{
+ int i;
+
+ for (i = 0; i < NR_DMAOR; i++)
+ dmaor_reset(i);
+
disable_irq(irq);
return IRQ_HANDLED;
-#endif
+}
+
+static int dmae_irq_init(void)
+{
+ int n;
+
+ for (n = 0; n < NR_DMAE; n++) {
+ int i = request_irq(get_dma_error_irq(n), dma_err,
+ IRQF_SHARED, dmae_name[n], NULL);
+ if (unlikely(i < 0)) {
+ printk(KERN_ERR "%s request_irq fail\n", dmae_name[n]);
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+static void dmae_irq_free(void)
+{
+ int n;
+
+ for (n = 0; n < NR_DMAE; n++)
+ free_irq(get_dma_error_irq(n), NULL);
+}
+#else
+static inline int dmae_irq_init(void)
+{
+ return 0;
+}
+
+static void dmae_irq_free(void)
+{
}
#endif
@@ -276,72 +378,34 @@ static struct dma_info sh_dmac_info = {
.flags = DMAC_CHANNELS_TEI_CAPABLE,
};
-#ifdef CONFIG_CPU_SH4
-static unsigned int get_dma_error_irq(int n)
-{
-#if defined(CONFIG_SH_DMA_IRQ_MULTI)
- return (n == 0) ? get_dmte_irq(0) : get_dmte_irq(6);
-#else
- return (n == 0) ? DMAE0_IRQ :
-#if defined(DMAE1_IRQ)
- DMAE1_IRQ;
-#else
- -1;
-#endif
-#endif
-}
-#endif
-
static int __init sh_dmac_init(void)
{
struct dma_info *info = &sh_dmac_info;
- int i;
-
-#ifdef CONFIG_CPU_SH4
- int n;
+ int i, rc;
- for (n = 0; n < NR_DMAE; n++) {
- i = request_irq(get_dma_error_irq(n), dma_err,
-#if defined(CONFIG_SH_DMA_IRQ_MULTI)
- IRQF_SHARED,
-#else
- 0,
-#endif
- dmae_name[n], (void *)dmae_name[n]);
- if (unlikely(i < 0)) {
- printk(KERN_ERR "%s request_irq fail\n", dmae_name[n]);
- return i;
- }
- }
-#endif /* CONFIG_CPU_SH4 */
+ /*
+ * Initialize DMAE, for parts that support it.
+ */
+ rc = dmae_irq_init();
+ if (unlikely(rc != 0))
+ return rc;
/*
* Initialize DMAOR, and clean up any error flags that may have
* been set.
*/
- i = dmaor_reset(0);
- if (unlikely(i != 0))
- return i;
-#if defined(CONFIG_CPU_SUBTYPE_SH7723) || \
- defined(CONFIG_CPU_SUBTYPE_SH7780) || \
- defined(CONFIG_CPU_SUBTYPE_SH7785)
- i = dmaor_reset(1);
- if (unlikely(i != 0))
- return i;
-#endif
+ for (i = 0; i < NR_DMAOR; i++) {
+ rc = dmaor_reset(i);
+ if (unlikely(rc != 0))
+ return rc;
+ }
return register_dmac(info);
}
static void __exit sh_dmac_exit(void)
{
-#ifdef CONFIG_CPU_SH4
- int n;
-
- for (n = 0; n < NR_DMAE; n++) {
- free_irq(get_dma_error_irq(n), (void *)dmae_name[n]);
- }
-#endif /* CONFIG_CPU_SH4 */
+ dmae_irq_free();
unregister_dmac(&sh_dmac_info);
}
diff --git a/arch/sh/drivers/dma/dma-sysfs.c b/arch/sh/drivers/dma/dma-sysfs.c
index 67ee95603813..4b15feda54b0 100644
--- a/arch/sh/drivers/dma/dma-sysfs.c
+++ b/arch/sh/drivers/dma/dma-sysfs.c
@@ -29,7 +29,7 @@ static ssize_t dma_show_devices(struct device *dev,
ssize_t len = 0;
int i;
- for (i = 0; i < MAX_DMA_CHANNELS; i++) {
+ for (i = 0; i < 16; i++) {
struct dma_info *info = get_dma_info(i);
struct dma_channel *channel = get_dma_channel(i);
diff --git a/arch/sh/drivers/pci/fixups-landisk.c b/arch/sh/drivers/pci/fixups-landisk.c
index ecb1d1060638..db5b40a98e62 100644
--- a/arch/sh/drivers/pci/fixups-landisk.c
+++ b/arch/sh/drivers/pci/fixups-landisk.c
@@ -14,6 +14,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pci.h>
+#include <linux/sh_intc.h>
#include "pci-sh4.h"
#define PCIMCR_MRSET_OFF 0xBFFFFFFF
@@ -27,7 +28,7 @@ int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
* slot2: pin1-4 = irq7,8,5,6
* slot3: pin1-4 = irq8,5,6,7
*/
- int irq = ((slot + pin - 1) & 0x3) + 5;
+ int irq = ((slot + pin - 1) & 0x3) + evt2irq(0x2a0);
if ((slot | (pin - 1)) > 0x3) {
printk(KERN_WARNING "PCI: Bad IRQ mapping request for slot %d pin %c\n",
diff --git a/arch/sh/drivers/pci/fixups-r7780rp.c b/arch/sh/drivers/pci/fixups-r7780rp.c
index f9370dce0b70..57ed3f09d0c2 100644
--- a/arch/sh/drivers/pci/fixups-r7780rp.c
+++ b/arch/sh/drivers/pci/fixups-r7780rp.c
@@ -12,13 +12,10 @@
*/
#include <linux/pci.h>
#include <linux/io.h>
+#include <linux/sh_intc.h>
#include "pci-sh4.h"
-static char irq_tab[] __initdata = {
- 65, 66, 67, 68,
-};
-
int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
{
- return irq_tab[slot];
+ return evt2irq(0xa20) + slot;
}
diff --git a/arch/sh/drivers/pci/fixups-sdk7780.c b/arch/sh/drivers/pci/fixups-sdk7780.c
index 0b8472501b88..c0a015ae6ecf 100644
--- a/arch/sh/drivers/pci/fixups-sdk7780.c
+++ b/arch/sh/drivers/pci/fixups-sdk7780.c
@@ -13,18 +13,28 @@
*/
#include <linux/pci.h>
#include <linux/io.h>
+#include <linux/sh_intc.h>
#include "pci-sh4.h"
+#define IRQ_INTA evt2irq(0xa20)
+#define IRQ_INTB evt2irq(0xa40)
+#define IRQ_INTC evt2irq(0xa60)
+#define IRQ_INTD evt2irq(0xa80)
+
/* IDSEL [16][17][18][19][20][21][22][23][24][25][26][27][28][29][30][31] */
static char sdk7780_irq_tab[4][16] __initdata = {
/* INTA */
- { 65, 68, 67, 68, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+ { IRQ_INTA, IRQ_INTD, IRQ_INTC, IRQ_INTD, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1 },
/* INTB */
- { 66, 65, -1, 65, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+ { IRQ_INTB, IRQ_INTA, -1, IRQ_INTA, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1 },
/* INTC */
- { 67, 66, -1, 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+ { IRQ_INTC, IRQ_INTB, -1, IRQ_INTB, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1 },
/* INTD */
- { 68, 67, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
+ { IRQ_INTD, IRQ_INTC, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1 },
};
int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
diff --git a/arch/sh/drivers/pci/fixups-se7751.c b/arch/sh/drivers/pci/fixups-se7751.c
index 2ec146c3fa44..84a88ca92008 100644
--- a/arch/sh/drivers/pci/fixups-se7751.c
+++ b/arch/sh/drivers/pci/fixups-se7751.c
@@ -4,13 +4,14 @@
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/io.h>
+#include <linux/sh_intc.h>
#include "pci-sh4.h"
int __init pcibios_map_platform_irq(const struct pci_dev *, u8 slot, u8 pin)
{
switch (slot) {
- case 0: return 13;
- case 1: return 13; /* AMD Ethernet controller */
+ case 0: return evt2irq(0x3a0);
+ case 1: return evt2irq(0x3a0); /* AMD Ethernet controller */
case 2: return -1;
case 3: return -1;
case 4: return -1;
diff --git a/arch/sh/drivers/pci/fixups-sh03.c b/arch/sh/drivers/pci/fixups-sh03.c
index 1615e5906168..16207bef9f52 100644
--- a/arch/sh/drivers/pci/fixups-sh03.c
+++ b/arch/sh/drivers/pci/fixups-sh03.c
@@ -2,6 +2,7 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/pci.h>
+#include <linux/sh_intc.h>
int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
@@ -9,21 +10,21 @@ int __init pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin)
if (dev->bus->number == 0) {
switch (slot) {
- case 4: return 5; /* eth0 */
- case 8: return 5; /* eth1 */
- case 6: return 2; /* PCI bridge */
+ case 4: return evt2irq(0x2a0); /* eth0 */
+ case 8: return evt2irq(0x2a0); /* eth1 */
+ case 6: return evt2irq(0x240); /* PCI bridge */
default:
printk(KERN_ERR "PCI: Bad IRQ mapping request "
"for slot %d\n", slot);
- return 2;
+ return evt2irq(0x240);
}
} else {
switch (pin) {
- case 0: irq = 2; break;
- case 1: irq = 2; break;
- case 2: irq = 2; break;
- case 3: irq = 2; break;
- case 4: irq = 2; break;
+ case 0: irq = evt2irq(0x240); break;
+ case 1: irq = evt2irq(0x240); break;
+ case 2: irq = evt2irq(0x240); break;
+ case 3: irq = evt2irq(0x240); break;
+ case 4: irq = evt2irq(0x240); break;
default: irq = -1; break;
}
}
diff --git a/arch/sh/drivers/pci/fixups-snapgear.c b/arch/sh/drivers/pci/fixups-snapgear.c
index 4a093c648d12..6e33ba4cd076 100644
--- a/arch/sh/drivers/pci/fixups-snapgear.c
+++ b/arch/sh/drivers/pci/fixups-snapgear.c
@@ -16,6 +16,7 @@
#include <linux/types.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/sh_intc.h>
#include "pci-sh4.h"
int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
@@ -24,11 +25,11 @@ int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
switch (slot) {
case 8: /* the PCI bridge */ break;
- case 11: irq = 8; break; /* USB */
- case 12: irq = 11; break; /* PCMCIA */
- case 13: irq = 5; break; /* eth0 */
- case 14: irq = 8; break; /* eth1 */
- case 15: irq = 11; break; /* safenet (unused) */
+ case 11: irq = evt2irq(0x300); break; /* USB */
+ case 12: irq = evt2irq(0x360); break; /* PCMCIA */
+ case 13: irq = evt2irq(0x2a0); break; /* eth0 */
+ case 14: irq = evt2irq(0x300); break; /* eth1 */
+ case 15: irq = evt2irq(0x360); break; /* safenet (unused) */
}
printk("PCI: Mapping SnapGear IRQ for slot %d, pin %c to irq %d\n",
diff --git a/arch/sh/drivers/pci/pcie-sh7786.c b/arch/sh/drivers/pci/pcie-sh7786.c
index 4df27c4fbf99..c045142f7338 100644
--- a/arch/sh/drivers/pci/pcie-sh7786.c
+++ b/arch/sh/drivers/pci/pcie-sh7786.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/sh_clk.h>
+#include <linux/sh_intc.h>
#include "pcie-sh7786.h"
#include <asm/sizes.h>
@@ -468,7 +469,7 @@ static int __init pcie_init(struct sh7786_pcie_port *port)
int __init pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
{
- return 71;
+ return evt2irq(0xae0);
}
static int __init sh7786_pcie_core_init(void)
diff --git a/arch/sh/include/asm/dma-sh.h b/arch/sh/include/asm/dma-sh.h
deleted file mode 100644
index f3acb8e34c6b..000000000000
--- a/arch/sh/include/asm/dma-sh.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * arch/sh/include/asm/dma-sh.h
- *
- * Copyright (C) 2000 Takashi YOSHII
- * Copyright (C) 2003 Paul Mundt
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#ifndef __DMA_SH_H
-#define __DMA_SH_H
-
-#include <asm/dma-register.h>
-#include <cpu/dma-register.h>
-#include <cpu/dma.h>
-
-/* DMAOR contorl: The DMAOR access size is different by CPU.*/
-#if defined(CONFIG_CPU_SUBTYPE_SH7723) || \
- defined(CONFIG_CPU_SUBTYPE_SH7724) || \
- defined(CONFIG_CPU_SUBTYPE_SH7780) || \
- defined(CONFIG_CPU_SUBTYPE_SH7785)
-#define dmaor_read_reg(n) \
- (n ? __raw_readw(SH_DMAC_BASE1 + DMAOR) \
- : __raw_readw(SH_DMAC_BASE0 + DMAOR))
-#define dmaor_write_reg(n, data) \
- (n ? __raw_writew(data, SH_DMAC_BASE1 + DMAOR) \
- : __raw_writew(data, SH_DMAC_BASE0 + DMAOR))
-#else /* Other CPU */
-#define dmaor_read_reg(n) __raw_readw(SH_DMAC_BASE0 + DMAOR)
-#define dmaor_write_reg(n, data) __raw_writew(data, SH_DMAC_BASE0 + DMAOR)
-#endif
-
-static int dmte_irq_map[] __maybe_unused = {
-#if (MAX_DMA_CHANNELS >= 4)
- DMTE0_IRQ,
- DMTE0_IRQ + 1,
- DMTE0_IRQ + 2,
- DMTE0_IRQ + 3,
-#endif
-#if (MAX_DMA_CHANNELS >= 6)
- DMTE4_IRQ,
- DMTE4_IRQ + 1,
-#endif
-#if (MAX_DMA_CHANNELS >= 8)
- DMTE6_IRQ,
- DMTE6_IRQ + 1,
-#endif
-#if (MAX_DMA_CHANNELS >= 12)
- DMTE8_IRQ,
- DMTE9_IRQ,
- DMTE10_IRQ,
- DMTE11_IRQ,
-#endif
-};
-
-/*
- * Define the default configuration for dual address memory-memory transfer.
- * The 0x400 value represents auto-request, external->external.
- */
-#define RS_DUAL (DM_INC | SM_INC | 0x400 | TS_INDEX2VAL(XMIT_SZ_32BIT))
-
-/* DMA base address */
-static u32 dma_base_addr[] __maybe_unused = {
-#if (MAX_DMA_CHANNELS >= 4)
- SH_DMAC_BASE0 + 0x00, /* channel 0 */
- SH_DMAC_BASE0 + 0x10,
- SH_DMAC_BASE0 + 0x20,
- SH_DMAC_BASE0 + 0x30,
-#endif
-#if (MAX_DMA_CHANNELS >= 6)
- SH_DMAC_BASE0 + 0x50,
- SH_DMAC_BASE0 + 0x60,
-#endif
-#if (MAX_DMA_CHANNELS >= 8)
- SH_DMAC_BASE1 + 0x00,
- SH_DMAC_BASE1 + 0x10,
-#endif
-#if (MAX_DMA_CHANNELS >= 12)
- SH_DMAC_BASE1 + 0x20,
- SH_DMAC_BASE1 + 0x30,
- SH_DMAC_BASE1 + 0x50,
- SH_DMAC_BASE1 + 0x60, /* channel 11 */
-#endif
-};
-
-#endif /* __DMA_SH_H */
diff --git a/arch/sh/include/asm/dma.h b/arch/sh/include/asm/dma.h
index 6aa2080c0065..fb6e4f7b00a2 100644
--- a/arch/sh/include/asm/dma.h
+++ b/arch/sh/include/asm/dma.h
@@ -15,17 +15,8 @@
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/device.h>
-#include <cpu/dma.h>
#include <asm-generic/dma.h>
-#ifdef CONFIG_NR_DMA_CHANNELS
-# define MAX_DMA_CHANNELS (CONFIG_NR_DMA_CHANNELS)
-#elif defined(CONFIG_NR_ONCHIP_DMA_CHANNELS)
-# define MAX_DMA_CHANNELS (CONFIG_NR_ONCHIP_DMA_CHANNELS)
-#else
-# define MAX_DMA_CHANNELS 0
-#endif
-
/*
* Read and write modes can mean drastically different things depending on the
* channel configuration. Consult your DMAC documentation and module
diff --git a/arch/sh/include/asm/fixmap.h b/arch/sh/include/asm/fixmap.h
index bd7e79a12653..cbe0186b6794 100644
--- a/arch/sh/include/asm/fixmap.h
+++ b/arch/sh/include/asm/fixmap.h
@@ -96,7 +96,7 @@ extern void __clear_fixmap(enum fixed_addresses idx, pgprot_t flags);
#ifdef CONFIG_SUPERH32
#define FIXADDR_TOP (P4SEG - PAGE_SIZE)
#else
-#define FIXADDR_TOP (0xff000000 - PAGE_SIZE)
+#define FIXADDR_TOP ((unsigned long)(-PAGE_SIZE))
#endif
#define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT)
#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)
diff --git a/arch/sh/include/asm/i2c-sh7760.h b/arch/sh/include/asm/i2c-sh7760.h
index 24182116711f..69fee1239b03 100644
--- a/arch/sh/include/asm/i2c-sh7760.h
+++ b/arch/sh/include/asm/i2c-sh7760.h
@@ -9,11 +9,9 @@
#define SH7760_I2C0_MMIO 0xFE140000
#define SH7760_I2C0_MMIOEND 0xFE14003B
-#define SH7760_I2C0_IRQ 62
#define SH7760_I2C1_MMIO 0xFE150000
#define SH7760_I2C1_MMIOEND 0xFE15003B
-#define SH7760_I2C1_IRQ 63
struct sh7760_i2c_platdata {
unsigned int speed_khz;
diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h
index ec464a6b95fe..0cf60a628814 100644
--- a/arch/sh/include/asm/io.h
+++ b/arch/sh/include/asm/io.h
@@ -218,8 +218,13 @@ __BUILD_IOPORT_STRING(w, u16)
__BUILD_IOPORT_STRING(l, u32)
__BUILD_IOPORT_STRING(q, u64)
+#else /* !CONFIG_HAS_IOPORT */
+
+#include <asm/io_noioport.h>
+
#endif
+
#define IO_SPACE_LIMIT 0xffffffff
/* synco on SH-4A, otherwise a nop */
diff --git a/arch/sh/include/asm/io_noioport.h b/arch/sh/include/asm/io_noioport.h
new file mode 100644
index 000000000000..e136d28d1d2e
--- /dev/null
+++ b/arch/sh/include/asm/io_noioport.h
@@ -0,0 +1,41 @@
+#ifndef __ASM_SH_IO_NOIOPORT_H
+#define __ASM_SH_IO_NOIOPORT_H
+
+static inline u8 inb(unsigned long addr)
+{
+ BUG();
+ return -1;
+}
+
+static inline u16 inw(unsigned long addr)
+{
+ BUG();
+ return -1;
+}
+
+static inline u32 inl(unsigned long addr)
+{
+ BUG();
+ return -1;
+}
+
+#define outb(x, y) BUG()
+#define outw(x, y) BUG()
+#define outl(x, y) BUG()
+
+#define inb_p(addr) inb(addr)
+#define inw_p(addr) inw(addr)
+#define inl_p(addr) inl(addr)
+#define outb_p(x, addr) outb((x), (addr))
+#define outw_p(x, addr) outw((x), (addr))
+#define outl_p(x, addr) outl((x), (addr))
+
+#define insb(a, b, c) BUG()
+#define insw(a, b, c) BUG()
+#define insl(a, b, c) BUG()
+
+#define outsb(a, b, c) BUG()
+#define outsw(a, b, c) BUG()
+#define outsl(a, b, c) BUG()
+
+#endif /* __ASM_SH_IO_NOIOPORT_H */
diff --git a/arch/sh/include/asm/irq.h b/arch/sh/include/asm/irq.h
index 2a62017eb275..0e4f532e4737 100644
--- a/arch/sh/include/asm/irq.h
+++ b/arch/sh/include/asm/irq.h
@@ -5,12 +5,15 @@
#include <asm/machvec.h>
/*
- * A sane default based on a reasonable vector table size, platforms are
- * advised to cap this at the hard limit that they're interested in
- * through the machvec.
+ * Only legacy non-sparseirq platforms have to set a reasonably sane
+ * value here. sparseirq platforms allocate their irq_descs on the fly,
+ * so will expand automatically based on the number of registered IRQs.
*/
-#define NR_IRQS 512
-#define NR_IRQS_LEGACY 8 /* Legacy external IRQ0-7 */
+#ifdef CONFIG_SPARSE_IRQ
+# define NR_IRQS 8
+#else
+# define NR_IRQS 512
+#endif
/*
* This is a special IRQ number for indicating that no IRQ has been
diff --git a/arch/sh/include/asm/kdebug.h b/arch/sh/include/asm/kdebug.h
index 5f6d2e9ccb7c..a6201f10c273 100644
--- a/arch/sh/include/asm/kdebug.h
+++ b/arch/sh/include/asm/kdebug.h
@@ -10,4 +10,6 @@ enum die_val {
DIE_SSTEP,
};
+extern void printk_address(unsigned long address, int reliable);
+
#endif /* __ASM_SH_KDEBUG_H */
diff --git a/arch/sh/include/asm/kgdb.h b/arch/sh/include/asm/kgdb.h
index f3613952d1ae..9e7d2d1b03e0 100644
--- a/arch/sh/include/asm/kgdb.h
+++ b/arch/sh/include/asm/kgdb.h
@@ -4,18 +4,6 @@
#include <asm/cacheflush.h>
#include <asm/ptrace.h>
-/* Same as pt_regs but has vbr in place of syscall_nr */
-struct kgdb_regs {
- unsigned long regs[16];
- unsigned long pc;
- unsigned long pr;
- unsigned long sr;
- unsigned long gbr;
- unsigned long mach;
- unsigned long macl;
- unsigned long vbr;
-};
-
enum regnames {
GDB_R0, GDB_R1, GDB_R2, GDB_R3, GDB_R4, GDB_R5, GDB_R6, GDB_R7,
GDB_R8, GDB_R9, GDB_R10, GDB_R11, GDB_R12, GDB_R13, GDB_R14, GDB_R15,
@@ -23,17 +11,27 @@ enum regnames {
GDB_PC, GDB_PR, GDB_SR, GDB_GBR, GDB_MACH, GDB_MACL, GDB_VBR,
};
-#define NUMREGBYTES ((GDB_VBR + 1) * 4)
+#define _GP_REGS 16
+#define _EXTRA_REGS 7
+#define GDB_SIZEOF_REG sizeof(u32)
+
+#define DBG_MAX_REG_NUM (_GP_REGS + _EXTRA_REGS)
+#define NUMREGBYTES (DBG_MAX_REG_NUM * sizeof(GDB_SIZEOF_REG))
static inline void arch_kgdb_breakpoint(void)
{
__asm__ __volatile__ ("trapa #0x3c\n");
}
-#define BUFMAX 2048
-
-#define CACHE_FLUSH_IS_SAFE 1
#define BREAK_INSTR_SIZE 2
+#define BUFMAX 2048
+
+#ifdef CONFIG_SMP
+# define CACHE_FLUSH_IS_SAFE 0
+#else
+# define CACHE_FLUSH_IS_SAFE 1
+#endif
+
#define GDB_ADJUSTS_BREAK_OFFSET
#endif /* __ASM_SH_KGDB_H */
diff --git a/arch/sh/include/asm/machvec.h b/arch/sh/include/asm/machvec.h
index 57c5c3d0f39f..eb9c20d971dd 100644
--- a/arch/sh/include/asm/machvec.h
+++ b/arch/sh/include/asm/machvec.h
@@ -17,7 +17,6 @@
struct sh_machine_vector {
void (*mv_setup)(char **cmdline_p);
const char *mv_name;
- int mv_nr_irqs;
int (*mv_irq_demux)(int irq);
void (*mv_init_irq)(void);
diff --git a/arch/sh/include/asm/pgtable_64.h b/arch/sh/include/asm/pgtable_64.h
index 42cb9dd52161..dda8c82601b9 100644
--- a/arch/sh/include/asm/pgtable_64.h
+++ b/arch/sh/include/asm/pgtable_64.h
@@ -87,9 +87,6 @@ static __inline__ void set_pte(pte_t *pteptr, pte_t pteval)
#define pte_unmap(pte) do { } while (0)
#ifndef __ASSEMBLY__
-#define IOBASE_VADDR 0xff000000
-#define IOBASE_END 0xffffffff
-
/*
* PTEL coherent flags.
* See Chapter 17 ST50 CPU Core Volume 1, Architecture.
diff --git a/arch/sh/include/asm/processor.h b/arch/sh/include/asm/processor.h
index 6dbc1be28a0f..3d14aeaef57c 100644
--- a/arch/sh/include/asm/processor.h
+++ b/arch/sh/include/asm/processor.h
@@ -18,7 +18,8 @@ enum cpu_type {
CPU_SH7619,
/* SH-2A types */
- CPU_SH7201, CPU_SH7203, CPU_SH7206, CPU_SH7263, CPU_MXG,
+ CPU_SH7201, CPU_SH7203, CPU_SH7206, CPU_SH7263, CPU_SH7264, CPU_SH7269,
+ CPU_MXG,
/* SH-3 types */
CPU_SH7705, CPU_SH7706, CPU_SH7707,
@@ -32,7 +33,7 @@ enum cpu_type {
/* SH-4A types */
CPU_SH7763, CPU_SH7770, CPU_SH7780, CPU_SH7781, CPU_SH7785, CPU_SH7786,
- CPU_SH7723, CPU_SH7724, CPU_SH7757, CPU_SHX3,
+ CPU_SH7723, CPU_SH7724, CPU_SH7757, CPU_SH7734, CPU_SHX3,
/* SH4AL-DSP types */
CPU_SH7343, CPU_SH7722, CPU_SH7366, CPU_SH7372,
diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h
index 900f8d72ffe2..b6311fd2d066 100644
--- a/arch/sh/include/asm/processor_32.h
+++ b/arch/sh/include/asm/processor_32.h
@@ -126,9 +126,6 @@ extern void start_thread(struct pt_regs *regs, unsigned long new_pc, unsigned lo
/* Free all resources held by a thread. */
extern void release_thread(struct task_struct *);
-/* Prepare to copy thread state - unlazy all lazy status */
-void prepare_to_copy(struct task_struct *tsk);
-
/*
* create a kernel thread without removing it from tasklists
*/
diff --git a/arch/sh/include/asm/processor_64.h b/arch/sh/include/asm/processor_64.h
index e25c4c7d6b63..cd6029fb2c01 100644
--- a/arch/sh/include/asm/processor_64.h
+++ b/arch/sh/include/asm/processor_64.h
@@ -121,7 +121,6 @@ struct thread_struct {
NULL for a kernel thread. */
struct pt_regs *uregs;
- unsigned long trap_no, error_code;
unsigned long address;
/* Hardware debugging registers may come here */
@@ -138,8 +137,6 @@ struct thread_struct {
.pc = 0, \
.kregs = &fake_swapper_regs, \
.uregs = NULL, \
- .trap_no = 0, \
- .error_code = 0, \
.address = 0, \
.flags = 0, \
}
@@ -172,7 +169,6 @@ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
#define copy_segments(p, mm) do { } while (0)
#define release_segments(mm) do { } while (0)
#define forget_segments() do { } while (0)
-#define prepare_to_copy(tsk) do { } while (0)
/*
* FPU lazy state save handling.
*/
diff --git a/arch/sh/include/asm/stackprotector.h b/arch/sh/include/asm/stackprotector.h
new file mode 100644
index 000000000000..d9df3a76847c
--- /dev/null
+++ b/arch/sh/include/asm/stackprotector.h
@@ -0,0 +1,27 @@
+#ifndef __ASM_SH_STACKPROTECTOR_H
+#define __ASM_SH_STACKPROTECTOR_H
+
+#include <linux/random.h>
+#include <linux/version.h>
+
+extern unsigned long __stack_chk_guard;
+
+/*
+ * Initialize the stackprotector canary value.
+ *
+ * NOTE: this must only be called from functions that never return,
+ * and it must always be inlined.
+ */
+static __always_inline void boot_init_stack_canary(void)
+{
+ unsigned long canary;
+
+ /* Try to get a semi random initial value. */
+ get_random_bytes(&canary, sizeof(canary));
+ canary ^= LINUX_VERSION_CODE;
+
+ current->stack_canary = canary;
+ __stack_chk_guard = current->stack_canary;
+}
+
+#endif /* __ASM_SH_STACKPROTECTOR_H */
diff --git a/arch/sh/include/asm/syscalls_32.h b/arch/sh/include/asm/syscalls_32.h
index ae717e3c26d6..6c1fa559753c 100644
--- a/arch/sh/include/asm/syscalls_32.h
+++ b/arch/sh/include/asm/syscalls_32.h
@@ -23,9 +23,7 @@ asmlinkage int sys_execve(const char __user *ufilename,
const char __user *const __user *uargv,
const char __user *const __user *uenvp,
unsigned long r7, struct pt_regs __regs);
-asmlinkage int sys_sigsuspend(old_sigset_t mask, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs __regs);
+asmlinkage int sys_sigsuspend(old_sigset_t mask);
asmlinkage int sys_sigaction(int sig, const struct old_sigaction __user *act,
struct old_sigaction __user *oact);
asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
diff --git a/arch/sh/include/asm/thread_info.h b/arch/sh/include/asm/thread_info.h
index b6902061d4dc..0c04ffc4f12c 100644
--- a/arch/sh/include/asm/thread_info.h
+++ b/arch/sh/include/asm/thread_info.h
@@ -10,8 +10,18 @@
* - Incorporating suggestions made by Linus Torvalds and Dave Miller
*/
#ifdef __KERNEL__
+
#include <asm/page.h>
+/*
+ * Page fault error code bits
+ */
+#define FAULT_CODE_WRITE (1 << 0) /* write access */
+#define FAULT_CODE_INITIAL (1 << 1) /* initial page write */
+#define FAULT_CODE_ITLB (1 << 2) /* ITLB miss */
+#define FAULT_CODE_PROT (1 << 3) /* protection fault */
+#define FAULT_CODE_USER (1 << 4) /* user-mode access */
+
#ifndef __ASSEMBLY__
#include <asm/processor.h>
@@ -98,10 +108,13 @@ extern void init_thread_xstate(void);
#endif /* __ASSEMBLY__ */
/*
- * thread information flags
- * - these are process state flags that various assembly files may need to access
- * - pending work-to-be-done flags are in LSW
- * - other flags in MSW
+ * Thread information flags
+ *
+ * - Limited to 24 bits, upper byte used for fault code encoding.
+ *
+ * - _TIF_ALLWORK_MASK and _TIF_WORK_MASK need to fit within 2 bytes, or
+ * we blow the tst immediate size constraints and need to fix up
+ * arch/sh/kernel/entry-common.S.
*/
#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
#define TIF_SIGPENDING 1 /* signal pending */
@@ -124,12 +137,6 @@ extern void init_thread_xstate(void);
#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT)
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
-/*
- * _TIF_ALLWORK_MASK and _TIF_WORK_MASK need to fit within 2 bytes, or we
- * blow the tst immediate size constraints and need to fix up
- * arch/sh/kernel/entry-common.S.
- */
-
/* work to do in syscall trace */
#define _TIF_WORK_SYSCALL_MASK (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \
_TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
@@ -156,6 +163,7 @@ extern void init_thread_xstate(void);
#define TS_USEDFPU 0x0002 /* FPU used by this task this quantum */
#ifndef __ASSEMBLY__
+
#define HAVE_SET_RESTORE_SIGMASK 1
static inline void set_restore_sigmask(void)
{
@@ -163,6 +171,24 @@ static inline void set_restore_sigmask(void)
ti->status |= TS_RESTORE_SIGMASK;
set_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags);
}
+
+#define TI_FLAG_FAULT_CODE_SHIFT 24
+
+/*
+ * Additional thread flag encoding
+ */
+static inline void set_thread_fault_code(unsigned int val)
+{
+ struct thread_info *ti = current_thread_info();
+ ti->flags = (ti->flags & (~0 >> (32 - TI_FLAG_FAULT_CODE_SHIFT)))
+ | (val << TI_FLAG_FAULT_CODE_SHIFT);
+}
+
+static inline unsigned int get_thread_fault_code(void)
+{
+ struct thread_info *ti = current_thread_info();
+ return ti->flags >> TI_FLAG_FAULT_CODE_SHIFT;
+}
#endif /* !__ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/arch/sh/include/asm/topology.h b/arch/sh/include/asm/topology.h
index 88e734069fa6..b0a282d65f6a 100644
--- a/arch/sh/include/asm/topology.h
+++ b/arch/sh/include/asm/topology.h
@@ -3,31 +3,6 @@
#ifdef CONFIG_NUMA
-/* sched_domains SD_NODE_INIT for sh machines */
-#define SD_NODE_INIT (struct sched_domain) { \
- .parent = NULL, \
- .child = NULL, \
- .groups = NULL, \
- .min_interval = 8, \
- .max_interval = 32, \
- .busy_factor = 32, \
- .imbalance_pct = 125, \
- .cache_nice_tries = 2, \
- .busy_idx = 3, \
- .idle_idx = 2, \
- .newidle_idx = 0, \
- .wake_idx = 0, \
- .forkexec_idx = 0, \
- .flags = SD_LOAD_BALANCE \
- | SD_BALANCE_FORK \
- | SD_BALANCE_EXEC \
- | SD_BALANCE_NEWIDLE \
- | SD_SERIALIZE, \
- .last_balance = jiffies, \
- .balance_interval = 1, \
- .nr_balance_failed = 0, \
-}
-
#define cpu_to_node(cpu) ((void)(cpu),0)
#define parent_node(node) ((void)(node),0)
diff --git a/arch/sh/include/asm/traps_64.h b/arch/sh/include/asm/traps_64.h
index c52d7f9a06c1..ef5eff919449 100644
--- a/arch/sh/include/asm/traps_64.h
+++ b/arch/sh/include/asm/traps_64.h
@@ -10,8 +10,22 @@
#ifndef __ASM_SH_TRAPS_64_H
#define __ASM_SH_TRAPS_64_H
+#include <cpu/registers.h>
+
extern void phys_stext(void);
+#define lookup_exception_vector() \
+({ \
+ unsigned long _vec; \
+ \
+ __asm__ __volatile__ ( \
+ "getcon " __EXPEVT ", %0\n\t" \
+ : "=r" (_vec) \
+ ); \
+ \
+ _vec; \
+})
+
static inline void trigger_address_error(void)
{
phys_stext();
diff --git a/arch/sh/include/asm/unistd.h b/arch/sh/include/asm/unistd.h
index a42a5610a36a..e800a38c9f8d 100644
--- a/arch/sh/include/asm/unistd.h
+++ b/arch/sh/include/asm/unistd.h
@@ -1,13 +1,11 @@
#ifdef __KERNEL__
# ifdef CONFIG_SUPERH32
-
# include "unistd_32.h"
-# define __ARCH_WANT_SYS_RT_SIGSUSPEND
-
# else
# include "unistd_64.h"
# endif
+# define __ARCH_WANT_SYS_RT_SIGSUSPEND
# define __ARCH_WANT_IPC_PARSE_VERSION
# define __ARCH_WANT_OLD_READDIR
# define __ARCH_WANT_OLD_STAT
diff --git a/arch/sh/include/cpu-sh2/cpu/dma.h b/arch/sh/include/cpu-sh2/cpu/dma.h
deleted file mode 100644
index d66b43cdc637..000000000000
--- a/arch/sh/include/cpu-sh2/cpu/dma.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Definitions for the SH-2 DMAC.
- *
- * Copyright (C) 2003 Paul Mundt
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#ifndef __ASM_CPU_SH2_DMA_H
-#define __ASM_CPU_SH2_DMA_H
-
-#define SH_MAX_DMA_CHANNELS 2
-
-#define SAR ((unsigned long[]){ 0xffffff80, 0xffffff90 })
-#define DAR ((unsigned long[]){ 0xffffff84, 0xffffff94 })
-#define DMATCR ((unsigned long[]){ 0xffffff88, 0xffffff98 })
-#define CHCR ((unsigned long[]){ 0xfffffffc, 0xffffff9c })
-
-#define DMAOR 0xffffffb0
-
-#endif /* __ASM_CPU_SH2_DMA_H */
-
diff --git a/arch/sh/include/cpu-sh2a/cpu/dma.h b/arch/sh/include/cpu-sh2a/cpu/dma.h
deleted file mode 100644
index 27a13ef4fdfc..000000000000
--- a/arch/sh/include/cpu-sh2a/cpu/dma.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <cpu-sh2/cpu/dma.h>
diff --git a/arch/sh/include/cpu-sh2a/cpu/sh7264.h b/arch/sh/include/cpu-sh2a/cpu/sh7264.h
new file mode 100644
index 000000000000..4d1ef6d74bd6
--- /dev/null
+++ b/arch/sh/include/cpu-sh2a/cpu/sh7264.h
@@ -0,0 +1,176 @@
+#ifndef __ASM_SH7264_H__
+#define __ASM_SH7264_H__
+
+enum {
+ /* Port A */
+ GPIO_PA3, GPIO_PA2, GPIO_PA1, GPIO_PA0,
+
+ /* Port B */
+ GPIO_PB22, GPIO_PB21, GPIO_PB20,
+ GPIO_PB19, GPIO_PB18, GPIO_PB17, GPIO_PB16,
+ GPIO_PB15, GPIO_PB14, GPIO_PB13, GPIO_PB12,
+ GPIO_PB11, GPIO_PB10, GPIO_PB9, GPIO_PB8,
+ GPIO_PB7, GPIO_PB6, GPIO_PB5, GPIO_PB4,
+ GPIO_PB3, GPIO_PB2, GPIO_PB1,
+
+ /* Port C */
+ GPIO_PC10, GPIO_PC9, GPIO_PC8,
+ GPIO_PC7, GPIO_PC6, GPIO_PC5, GPIO_PC4,
+ GPIO_PC3, GPIO_PC2, GPIO_PC1, GPIO_PC0,
+
+ /* Port D */
+ GPIO_PD15, GPIO_PD14, GPIO_PD13, GPIO_PD12,
+ GPIO_PD11, GPIO_PD10, GPIO_PD9, GPIO_PD8,
+ GPIO_PD7, GPIO_PD6, GPIO_PD5, GPIO_PD4,
+ GPIO_PD3, GPIO_PD2, GPIO_PD1, GPIO_PD0,
+
+ /* Port E */
+ GPIO_PE5, GPIO_PE4,
+ GPIO_PE3, GPIO_PE2, GPIO_PE1, GPIO_PE0,
+
+ /* Port F */
+ GPIO_PF12,
+ GPIO_PF11, GPIO_PF10, GPIO_PF9, GPIO_PF8,
+ GPIO_PF7, GPIO_PF6, GPIO_PF5, GPIO_PF4,
+ GPIO_PF3, GPIO_PF2, GPIO_PF1, GPIO_PF0,
+
+ /* Port G */
+ GPIO_PG24,
+ GPIO_PG23, GPIO_PG22, GPIO_PG21, GPIO_PG20,
+ GPIO_PG19, GPIO_PG18, GPIO_PG17, GPIO_PG16,
+ GPIO_PG15, GPIO_PG14, GPIO_PG13, GPIO_PG12,
+ GPIO_PG11, GPIO_PG10, GPIO_PG9, GPIO_PG8,
+ GPIO_PG7, GPIO_PG6, GPIO_PG5, GPIO_PG4,
+ GPIO_PG3, GPIO_PG2, GPIO_PG1, GPIO_PG0,
+
+ /* Port H */
+ GPIO_PH7, GPIO_PH6, GPIO_PH5, GPIO_PH4,
+ GPIO_PH3, GPIO_PH2, GPIO_PH1, GPIO_PH0,
+
+ /* Port I - not on device */
+
+ /* Port J */
+ GPIO_PJ11, GPIO_PJ10, GPIO_PJ9, GPIO_PJ8,
+ GPIO_PJ7, GPIO_PJ6, GPIO_PJ5, GPIO_PJ4,
+ GPIO_PJ3, GPIO_PJ2, GPIO_PJ1, GPIO_PJ0,
+
+ /* Port K */
+ GPIO_PK11, GPIO_PK10, GPIO_PK9, GPIO_PK8,
+ GPIO_PK7, GPIO_PK6, GPIO_PK5, GPIO_PK4,
+ GPIO_PK3, GPIO_PK2, GPIO_PK1, GPIO_PK0,
+
+ /* INTC: IRQ and PINT on PB/PD/PE */
+ GPIO_FN_PINT7_PG, GPIO_FN_PINT6_PG, GPIO_FN_PINT5_PG, GPIO_FN_PINT4_PG,
+ GPIO_FN_PINT3_PG, GPIO_FN_PINT2_PG, GPIO_FN_PINT1_PG,
+
+ GPIO_FN_IRQ7_PC, GPIO_FN_IRQ6_PC, GPIO_FN_IRQ5_PC, GPIO_FN_IRQ4_PC,
+ GPIO_FN_IRQ3_PG, GPIO_FN_IRQ2_PG, GPIO_FN_IRQ1_PJ, GPIO_FN_IRQ0_PJ,
+ GPIO_FN_IRQ3_PE, GPIO_FN_IRQ2_PE, GPIO_FN_IRQ1_PE, GPIO_FN_IRQ0_PE,
+
+ /* WDT */
+ GPIO_FN_WDTOVF,
+
+ /* CAN */
+ GPIO_FN_CTX1, GPIO_FN_CRX1, GPIO_FN_CTX0, GPIO_FN_CTX0_CTX1,
+ GPIO_FN_CRX0, GPIO_FN_CRX0_CRX1,
+
+ /* DMAC */
+ GPIO_FN_TEND0, GPIO_FN_DACK0, GPIO_FN_DREQ0,
+ GPIO_FN_TEND1, GPIO_FN_DACK1, GPIO_FN_DREQ1,
+
+ /* ADC */
+ GPIO_FN_ADTRG,
+
+ /* BSC */
+
+ GPIO_FN_A25, GPIO_FN_A24,
+ GPIO_FN_A23, GPIO_FN_A22, GPIO_FN_A21, GPIO_FN_A20,
+ GPIO_FN_A19, GPIO_FN_A18, GPIO_FN_A17, GPIO_FN_A16,
+ GPIO_FN_A15, GPIO_FN_A14, GPIO_FN_A13, GPIO_FN_A12,
+ GPIO_FN_A11, GPIO_FN_A10, GPIO_FN_A9, GPIO_FN_A8,
+ GPIO_FN_A7, GPIO_FN_A6, GPIO_FN_A5, GPIO_FN_A4,
+ GPIO_FN_A3, GPIO_FN_A2, GPIO_FN_A1, GPIO_FN_A0,
+ GPIO_FN_D15, GPIO_FN_D14, GPIO_FN_D13, GPIO_FN_D12,
+ GPIO_FN_D11, GPIO_FN_D10, GPIO_FN_D9, GPIO_FN_D8,
+ GPIO_FN_D7, GPIO_FN_D6, GPIO_FN_D5, GPIO_FN_D4,
+ GPIO_FN_D3, GPIO_FN_D2, GPIO_FN_D1, GPIO_FN_D0,
+
+ GPIO_FN_BS,
+ GPIO_FN_CS4, GPIO_FN_CS3, GPIO_FN_CS2, GPIO_FN_CS1, GPIO_FN_CS0,
+ GPIO_FN_CS6CE1B, GPIO_FN_CS5CE1A,
+ GPIO_FN_CE2A, GPIO_FN_CE2B,
+ GPIO_FN_RD, GPIO_FN_RDWR,
+ GPIO_FN_ICIOWRAH, GPIO_FN_ICIORD,
+ GPIO_FN_WE1DQMUWE, GPIO_FN_WE0DQML,
+ GPIO_FN_RAS, GPIO_FN_CAS, GPIO_FN_CKE,
+ GPIO_FN_WAIT, GPIO_FN_BREQ, GPIO_FN_BACK,
+ GPIO_FN_IOIS16,
+
+ /* TMU */
+ GPIO_FN_TIOC4D, GPIO_FN_TIOC4C, GPIO_FN_TIOC4B, GPIO_FN_TIOC4A,
+ GPIO_FN_TIOC3D, GPIO_FN_TIOC3C, GPIO_FN_TIOC3B, GPIO_FN_TIOC3A,
+ GPIO_FN_TIOC2B, GPIO_FN_TIOC1B, GPIO_FN_TIOC2A, GPIO_FN_TIOC1A,
+ GPIO_FN_TIOC0D, GPIO_FN_TIOC0C, GPIO_FN_TIOC0B, GPIO_FN_TIOC0A,
+ GPIO_FN_TCLKD, GPIO_FN_TCLKC, GPIO_FN_TCLKB, GPIO_FN_TCLKA,
+
+ /* SSU */
+ GPIO_FN_SCS0_PD, GPIO_FN_SSO0_PD, GPIO_FN_SSI0_PD, GPIO_FN_SSCK0_PD,
+ GPIO_FN_SCS0_PF, GPIO_FN_SSO0_PF, GPIO_FN_SSI0_PF, GPIO_FN_SSCK0_PF,
+ GPIO_FN_SCS1_PD, GPIO_FN_SSO1_PD, GPIO_FN_SSI1_PD, GPIO_FN_SSCK1_PD,
+ GPIO_FN_SCS1_PF, GPIO_FN_SSO1_PF, GPIO_FN_SSI1_PF, GPIO_FN_SSCK1_PF,
+
+ /* SCIF */
+ GPIO_FN_SCK0, GPIO_FN_SCK1, GPIO_FN_SCK2, GPIO_FN_SCK3,
+ GPIO_FN_RXD0, GPIO_FN_RXD1, GPIO_FN_RXD2, GPIO_FN_RXD3,
+ GPIO_FN_TXD0, GPIO_FN_TXD1, GPIO_FN_TXD2, GPIO_FN_TXD3,
+ GPIO_FN_RXD4, GPIO_FN_RXD5, GPIO_FN_RXD6, GPIO_FN_RXD7,
+ GPIO_FN_TXD4, GPIO_FN_TXD5, GPIO_FN_TXD6, GPIO_FN_TXD7,
+ GPIO_FN_RTS1, GPIO_FN_RTS3, GPIO_FN_CTS1, GPIO_FN_CTS3,
+
+ /* RSPI */
+ GPIO_FN_RSPCK0, GPIO_FN_MOSI0,
+ GPIO_FN_MISO0_PF12, GPIO_FN_MISO1,
+ GPIO_FN_SSL00,
+ GPIO_FN_RSPCK1, GPIO_FN_MOSI1,
+ GPIO_FN_MISO1_PG19, GPIO_FN_SSL10,
+
+ /* IIC3 */
+ GPIO_FN_SCL0, GPIO_FN_SCL1, GPIO_FN_SCL2,
+ GPIO_FN_SDA2, GPIO_FN_SDA1, GPIO_FN_SDA0,
+
+ /* SSI */
+ GPIO_FN_SSISCK0, GPIO_FN_SSIWS0, GPIO_FN_SSITXD0, GPIO_FN_SSIRXD0,
+ GPIO_FN_SSIWS1, GPIO_FN_SSIWS2, GPIO_FN_SSIWS3,
+ GPIO_FN_SSISCK1, GPIO_FN_SSISCK2, GPIO_FN_SSISCK3,
+ GPIO_FN_SSIDATA1, GPIO_FN_SSIDATA2, GPIO_FN_SSIDATA3,
+ GPIO_FN_AUDIO_CLK,
+
+ /* SIOF */
+ GPIO_FN_SIOFTXD, GPIO_FN_SIOFRXD, GPIO_FN_SIOFSYNC, GPIO_FN_SIOFSCK,
+
+ /* SPDIF */
+ GPIO_FN_SPDIF_IN,
+ GPIO_FN_SPDIF_OUT,
+
+ /* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
+ GPIO_FN_FCE,
+ GPIO_FN_FRB,
+
+ /* VDC3 */
+ GPIO_FN_DV_CLK, GPIO_FN_DV_VSYNC, GPIO_FN_DV_HSYNC,
+ GPIO_FN_DV_DATA7, GPIO_FN_DV_DATA6, GPIO_FN_DV_DATA5, GPIO_FN_DV_DATA4,
+ GPIO_FN_DV_DATA3, GPIO_FN_DV_DATA2, GPIO_FN_DV_DATA1, GPIO_FN_DV_DATA0,
+ GPIO_FN_LCD_CLK, GPIO_FN_LCD_EXTCLK,
+ GPIO_FN_LCD_VSYNC, GPIO_FN_LCD_HSYNC, GPIO_FN_LCD_DE,
+ GPIO_FN_LCD_DATA15, GPIO_FN_LCD_DATA14,
+ GPIO_FN_LCD_DATA13, GPIO_FN_LCD_DATA12,
+ GPIO_FN_LCD_DATA11, GPIO_FN_LCD_DATA10,
+ GPIO_FN_LCD_DATA9, GPIO_FN_LCD_DATA8,
+ GPIO_FN_LCD_DATA7, GPIO_FN_LCD_DATA6,
+ GPIO_FN_LCD_DATA5, GPIO_FN_LCD_DATA4,
+ GPIO_FN_LCD_DATA3, GPIO_FN_LCD_DATA2,
+ GPIO_FN_LCD_DATA1, GPIO_FN_LCD_DATA0,
+ GPIO_FN_LCD_M_DISP,
+};
+
+#endif /* __ASM_SH7264_H__ */
diff --git a/arch/sh/include/cpu-sh2a/cpu/sh7269.h b/arch/sh/include/cpu-sh2a/cpu/sh7269.h
new file mode 100644
index 000000000000..48d14498e774
--- /dev/null
+++ b/arch/sh/include/cpu-sh2a/cpu/sh7269.h
@@ -0,0 +1,201 @@
+#ifndef __ASM_SH7269_H__
+#define __ASM_SH7269_H__
+
+enum {
+ /* Port A */
+ GPIO_PA1, GPIO_PA0,
+
+ /* Port B */
+ GPIO_PB22, GPIO_PB21, GPIO_PB20,
+ GPIO_PB19, GPIO_PB18, GPIO_PB17, GPIO_PB16,
+ GPIO_PB15, GPIO_PB14, GPIO_PB13, GPIO_PB12,
+ GPIO_PB11, GPIO_PB10, GPIO_PB9, GPIO_PB8,
+ GPIO_PB7, GPIO_PB6, GPIO_PB5, GPIO_PB4,
+ GPIO_PB3, GPIO_PB2, GPIO_PB1,
+
+ /* Port C */
+ GPIO_PC8,
+ GPIO_PC7, GPIO_PC6, GPIO_PC5, GPIO_PC4,
+ GPIO_PC3, GPIO_PC2, GPIO_PC1, GPIO_PC0,
+
+ /* Port D */
+ GPIO_PD15, GPIO_PD14, GPIO_PD13, GPIO_PD12,
+ GPIO_PD11, GPIO_PD10, GPIO_PD9, GPIO_PD8,
+ GPIO_PD7, GPIO_PD6, GPIO_PD5, GPIO_PD4,
+ GPIO_PD3, GPIO_PD2, GPIO_PD1, GPIO_PD0,
+
+ /* Port E */
+ GPIO_PE7, GPIO_PE6, GPIO_PE5, GPIO_PE4,
+ GPIO_PE3, GPIO_PE2, GPIO_PE1, GPIO_PE0,
+
+ /* Port F */
+ GPIO_PF23, GPIO_PF22, GPIO_PF21, GPIO_PF20,
+ GPIO_PF19, GPIO_PF18, GPIO_PF17, GPIO_PF16,
+ GPIO_PF15, GPIO_PF14, GPIO_PF13, GPIO_PF12,
+ GPIO_PF11, GPIO_PF10, GPIO_PF9, GPIO_PF8,
+ GPIO_PF7, GPIO_PF6, GPIO_PF5, GPIO_PF4,
+ GPIO_PF3, GPIO_PF2, GPIO_PF1, GPIO_PF0,
+
+ /* Port G */
+ GPIO_PG27, GPIO_PG26, GPIO_PG25, GPIO_PG24,
+ GPIO_PG23, GPIO_PG22, GPIO_PG21, GPIO_PG20,
+ GPIO_PG19, GPIO_PG18, GPIO_PG17, GPIO_PG16,
+ GPIO_PG15, GPIO_PG14, GPIO_PG13, GPIO_PG12,
+ GPIO_PG11, GPIO_PG10, GPIO_PG9, GPIO_PG8,
+ GPIO_PG7, GPIO_PG6, GPIO_PG5, GPIO_PG4,
+ GPIO_PG3, GPIO_PG2, GPIO_PG1, GPIO_PG0,
+
+ /* Port H */
+ GPIO_PH7, GPIO_PH6, GPIO_PH5, GPIO_PH4,
+ GPIO_PH3, GPIO_PH2, GPIO_PH1, GPIO_PH0,
+
+ /* Port I - not on device */
+
+ /* Port J */
+ GPIO_PJ31, GPIO_PJ30, GPIO_PJ29, GPIO_PJ28,
+ GPIO_PJ27, GPIO_PJ26, GPIO_PJ25, GPIO_PJ24,
+ GPIO_PJ23, GPIO_PJ22, GPIO_PJ21, GPIO_PJ20,
+ GPIO_PJ19, GPIO_PJ18, GPIO_PJ17, GPIO_PJ16,
+ GPIO_PJ15, GPIO_PJ14, GPIO_PJ13, GPIO_PJ12,
+ GPIO_PJ11, GPIO_PJ10, GPIO_PJ9, GPIO_PJ8,
+ GPIO_PJ7, GPIO_PJ6, GPIO_PJ5, GPIO_PJ4,
+ GPIO_PJ3, GPIO_PJ2, GPIO_PJ1, GPIO_PJ0,
+
+ /* INTC: IRQ and PINT */
+ GPIO_FN_IRQ7_PG, GPIO_FN_IRQ6_PG, GPIO_FN_IRQ5_PG, GPIO_FN_IRQ4_PG,
+ GPIO_FN_IRQ3_PG, GPIO_FN_IRQ2_PG, GPIO_FN_IRQ1_PG, GPIO_FN_IRQ0_PG,
+ GPIO_FN_IRQ7_PF, GPIO_FN_IRQ6_PF, GPIO_FN_IRQ5_PF, GPIO_FN_IRQ4_PF,
+ GPIO_FN_IRQ3_PJ, GPIO_FN_IRQ2_PJ, GPIO_FN_IRQ1_PJ, GPIO_FN_IRQ0_PJ,
+ GPIO_FN_IRQ1_PC, GPIO_FN_IRQ0_PC,
+
+ GPIO_FN_PINT7_PG, GPIO_FN_PINT6_PG, GPIO_FN_PINT5_PG, GPIO_FN_PINT4_PG,
+ GPIO_FN_PINT3_PG, GPIO_FN_PINT2_PG, GPIO_FN_PINT1_PG, GPIO_FN_PINT0_PG,
+ GPIO_FN_PINT7_PH, GPIO_FN_PINT6_PH, GPIO_FN_PINT5_PH, GPIO_FN_PINT4_PH,
+ GPIO_FN_PINT3_PH, GPIO_FN_PINT2_PH, GPIO_FN_PINT1_PH, GPIO_FN_PINT0_PH,
+ GPIO_FN_PINT7_PJ, GPIO_FN_PINT6_PJ, GPIO_FN_PINT5_PJ, GPIO_FN_PINT4_PJ,
+ GPIO_FN_PINT3_PJ, GPIO_FN_PINT2_PJ, GPIO_FN_PINT1_PJ, GPIO_FN_PINT0_PJ,
+
+ /* WDT */
+ GPIO_FN_WDTOVF,
+
+ /* CAN */
+ GPIO_FN_CTX1, GPIO_FN_CRX1, GPIO_FN_CTX0, GPIO_FN_CTX0_CTX1,
+ GPIO_FN_CRX0, GPIO_FN_CRX0_CRX1, GPIO_FN_CRX0_CRX1_CRX2,
+
+ /* DMAC */
+ GPIO_FN_TEND0, GPIO_FN_DACK0, GPIO_FN_DREQ0,
+ GPIO_FN_TEND1, GPIO_FN_DACK1, GPIO_FN_DREQ1,
+
+ /* ADC */
+ GPIO_FN_ADTRG,
+
+ /* BSC */
+ GPIO_FN_A25, GPIO_FN_A24,
+ GPIO_FN_A23, GPIO_FN_A22, GPIO_FN_A21, GPIO_FN_A20,
+ GPIO_FN_A19, GPIO_FN_A18, GPIO_FN_A17, GPIO_FN_A16,
+ GPIO_FN_A15, GPIO_FN_A14, GPIO_FN_A13, GPIO_FN_A12,
+ GPIO_FN_A11, GPIO_FN_A10, GPIO_FN_A9, GPIO_FN_A8,
+ GPIO_FN_A7, GPIO_FN_A6, GPIO_FN_A5, GPIO_FN_A4,
+ GPIO_FN_A3, GPIO_FN_A2, GPIO_FN_A1, GPIO_FN_A0,
+ GPIO_FN_D15, GPIO_FN_D14, GPIO_FN_D13, GPIO_FN_D12,
+ GPIO_FN_D11, GPIO_FN_D10, GPIO_FN_D9, GPIO_FN_D8,
+ GPIO_FN_D7, GPIO_FN_D6, GPIO_FN_D5, GPIO_FN_D4,
+ GPIO_FN_D3, GPIO_FN_D2, GPIO_FN_D1, GPIO_FN_D0,
+
+ GPIO_FN_BS,
+ GPIO_FN_CS4, GPIO_FN_CS3, GPIO_FN_CS2, GPIO_FN_CS1, GPIO_FN_CS0,
+ GPIO_FN_CS5CE1A,
+ GPIO_FN_CE2A, GPIO_FN_CE2B,
+ GPIO_FN_RD, GPIO_FN_RDWR,
+ GPIO_FN_WE3ICIOWRAHDQMUU, GPIO_FN_WE2ICIORDDQMUL,
+ GPIO_FN_WE1DQMUWE, GPIO_FN_WE0DQML,
+ GPIO_FN_RAS, GPIO_FN_CAS, GPIO_FN_CKE,
+ GPIO_FN_WAIT, GPIO_FN_BREQ, GPIO_FN_BACK,
+ GPIO_FN_IOIS16,
+
+ /* TMU */
+ GPIO_FN_TIOC4D, GPIO_FN_TIOC4C, GPIO_FN_TIOC4B, GPIO_FN_TIOC4A,
+ GPIO_FN_TIOC3D, GPIO_FN_TIOC3C, GPIO_FN_TIOC3B, GPIO_FN_TIOC3A,
+ GPIO_FN_TIOC2B, GPIO_FN_TIOC1B, GPIO_FN_TIOC2A, GPIO_FN_TIOC1A,
+ GPIO_FN_TIOC0D, GPIO_FN_TIOC0C, GPIO_FN_TIOC0B, GPIO_FN_TIOC0A,
+ GPIO_FN_TCLKD, GPIO_FN_TCLKC, GPIO_FN_TCLKB, GPIO_FN_TCLKA,
+
+ /* SSU */
+ GPIO_FN_SCS0_PD, GPIO_FN_SSO0_PD, GPIO_FN_SSI0_PD, GPIO_FN_SSCK0_PD,
+ GPIO_FN_SCS0_PF, GPIO_FN_SSO0_PF, GPIO_FN_SSI0_PF, GPIO_FN_SSCK0_PF,
+ GPIO_FN_SCS1_PD, GPIO_FN_SSO1_PD, GPIO_FN_SSI1_PD, GPIO_FN_SSCK1_PD,
+ GPIO_FN_SCS1_PF, GPIO_FN_SSO1_PF, GPIO_FN_SSI1_PF, GPIO_FN_SSCK1_PF,
+
+ /* SCIF */
+ GPIO_FN_SCK0, GPIO_FN_RXD0, GPIO_FN_TXD0,
+ GPIO_FN_SCK1, GPIO_FN_RXD1, GPIO_FN_TXD1, GPIO_FN_RTS1, GPIO_FN_CTS1,
+ GPIO_FN_SCK2, GPIO_FN_RXD2, GPIO_FN_TXD2,
+ GPIO_FN_SCK3, GPIO_FN_RXD3, GPIO_FN_TXD3,
+ GPIO_FN_SCK4, GPIO_FN_RXD4, GPIO_FN_TXD4,
+ GPIO_FN_SCK5, GPIO_FN_RXD5, GPIO_FN_TXD5, GPIO_FN_RTS5, GPIO_FN_CTS5,
+ GPIO_FN_SCK6, GPIO_FN_RXD6, GPIO_FN_TXD6,
+ GPIO_FN_SCK7, GPIO_FN_RXD7, GPIO_FN_TXD7, GPIO_FN_RTS7, GPIO_FN_CTS7,
+
+ /* RSPI */
+ GPIO_FN_MISO0_PJ19, GPIO_FN_MISO0_PB20,
+ GPIO_FN_MOSI0_PJ18, GPIO_FN_MOSI0_PB19,
+ GPIO_FN_SSL00_PJ17, GPIO_FN_SSL00_PB18,
+ GPIO_FN_RSPCK0_PJ16, GPIO_FN_RSPCK0_PB17,
+ GPIO_FN_RSPCK1, GPIO_FN_MOSI1,
+ GPIO_FN_MISO1, GPIO_FN_SSL10,
+
+ /* IIC3 */
+ GPIO_FN_SCL0, GPIO_FN_SCL1, GPIO_FN_SCL2,
+ GPIO_FN_SDA2, GPIO_FN_SDA1, GPIO_FN_SDA0,
+
+ /* SSI */
+ GPIO_FN_SSISCK0, GPIO_FN_SSIWS0, GPIO_FN_SSITXD0, GPIO_FN_SSIRXD0,
+ GPIO_FN_SSIWS1, GPIO_FN_SSIWS2, GPIO_FN_SSIWS3,
+ GPIO_FN_SSISCK1, GPIO_FN_SSISCK2, GPIO_FN_SSISCK3,
+ GPIO_FN_SSIDATA1, GPIO_FN_SSIDATA2, GPIO_FN_SSIDATA3,
+ GPIO_FN_AUDIO_CLK,
+ GPIO_FN_AUDIO_XOUT,
+
+ /* SIOF */
+ GPIO_FN_SIOFTXD, GPIO_FN_SIOFRXD, GPIO_FN_SIOFSYNC, GPIO_FN_SIOFSCK,
+
+ /* SPDIF */
+ GPIO_FN_SPDIF_IN,
+ GPIO_FN_SPDIF_OUT,
+
+ /* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
+ GPIO_FN_FCE,
+ GPIO_FN_FRB,
+
+ /* VDC */
+ GPIO_FN_DV_CLK, GPIO_FN_DV_VSYNC, GPIO_FN_DV_HSYNC,
+ GPIO_FN_DV_DATA23, GPIO_FN_DV_DATA22,
+ GPIO_FN_DV_DATA21, GPIO_FN_DV_DATA20,
+ GPIO_FN_DV_DATA19, GPIO_FN_DV_DATA18,
+ GPIO_FN_DV_DATA17, GPIO_FN_DV_DATA16,
+ GPIO_FN_DV_DATA15, GPIO_FN_DV_DATA14,
+ GPIO_FN_DV_DATA13, GPIO_FN_DV_DATA12,
+ GPIO_FN_DV_DATA11, GPIO_FN_DV_DATA10,
+ GPIO_FN_DV_DATA9, GPIO_FN_DV_DATA8,
+ GPIO_FN_DV_DATA7, GPIO_FN_DV_DATA6,
+ GPIO_FN_DV_DATA5, GPIO_FN_DV_DATA4,
+ GPIO_FN_DV_DATA3, GPIO_FN_DV_DATA2,
+ GPIO_FN_DV_DATA1, GPIO_FN_DV_DATA0,
+ GPIO_FN_LCD_CLK, GPIO_FN_LCD_EXTCLK,
+ GPIO_FN_LCD_VSYNC, GPIO_FN_LCD_HSYNC, GPIO_FN_LCD_DE,
+ GPIO_FN_LCD_DATA23, GPIO_FN_LCD_DATA22,
+ GPIO_FN_LCD_DATA21, GPIO_FN_LCD_DATA20,
+ GPIO_FN_LCD_DATA19, GPIO_FN_LCD_DATA18,
+ GPIO_FN_LCD_DATA17, GPIO_FN_LCD_DATA16,
+ GPIO_FN_LCD_DATA15, GPIO_FN_LCD_DATA14,
+ GPIO_FN_LCD_DATA13, GPIO_FN_LCD_DATA12,
+ GPIO_FN_LCD_DATA11, GPIO_FN_LCD_DATA10,
+ GPIO_FN_LCD_DATA9, GPIO_FN_LCD_DATA8,
+ GPIO_FN_LCD_DATA7, GPIO_FN_LCD_DATA6,
+ GPIO_FN_LCD_DATA5, GPIO_FN_LCD_DATA4,
+ GPIO_FN_LCD_DATA3, GPIO_FN_LCD_DATA2,
+ GPIO_FN_LCD_DATA1, GPIO_FN_LCD_DATA0,
+ GPIO_FN_LCD_M_DISP,
+};
+
+#endif /* __ASM_SH7269_H__ */
diff --git a/arch/sh/include/cpu-sh3/cpu/dma.h b/arch/sh/include/cpu-sh3/cpu/dma.h
index 24e28b91c9d5..bccb4144a5e3 100644
--- a/arch/sh/include/cpu-sh3/cpu/dma.h
+++ b/arch/sh/include/cpu-sh3/cpu/dma.h
@@ -1,6 +1,8 @@
#ifndef __ASM_CPU_SH3_DMA_H
#define __ASM_CPU_SH3_DMA_H
+#include <linux/sh_intc.h>
+
#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
defined(CONFIG_CPU_SUBTYPE_SH7721) || \
defined(CONFIG_CPU_SUBTYPE_SH7710) || \
@@ -10,14 +12,7 @@
#define SH_DMAC_BASE0 0xa4000020
#endif
-#define DMTE0_IRQ 48
-#define DMTE4_IRQ 76
-
-/* Definitions for the SuperH DMAC */
-#define TM_BURST 0x00000020
-#define TS_8 0x00000000
-#define TS_16 0x00000008
-#define TS_32 0x00000010
-#define TS_128 0x00000018
+#define DMTE0_IRQ evt2irq(0x800)
+#define DMTE4_IRQ evt2irq(0xb80)
#endif /* __ASM_CPU_SH3_DMA_H */
diff --git a/arch/sh/include/cpu-sh4/cpu/dma-sh4a.h b/arch/sh/include/cpu-sh4/cpu/dma-sh4a.h
deleted file mode 100644
index 9647e681fd27..000000000000
--- a/arch/sh/include/cpu-sh4/cpu/dma-sh4a.h
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef __ASM_SH_CPU_SH4_DMA_SH7780_H
-#define __ASM_SH_CPU_SH4_DMA_SH7780_H
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7343) || \
- defined(CONFIG_CPU_SUBTYPE_SH7730)
-#define DMTE0_IRQ 48
-#define DMTE4_IRQ 76
-#define DMAE0_IRQ 78 /* DMA Error IRQ*/
-#define SH_DMAC_BASE0 0xFE008020
-#define SH_DMARS_BASE0 0xFE009000
-#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
-#define DMTE0_IRQ 48
-#define DMTE4_IRQ 76
-#define DMAE0_IRQ 78 /* DMA Error IRQ*/
-#define SH_DMAC_BASE0 0xFE008020
-#define SH_DMARS_BASE0 0xFE009000
-#elif defined(CONFIG_CPU_SUBTYPE_SH7763) || \
- defined(CONFIG_CPU_SUBTYPE_SH7764)
-#define DMTE0_IRQ 34
-#define DMTE4_IRQ 44
-#define DMAE0_IRQ 38
-#define SH_DMAC_BASE0 0xFF608020
-#define SH_DMARS_BASE0 0xFF609000
-#elif defined(CONFIG_CPU_SUBTYPE_SH7723)
-#define DMTE0_IRQ 48 /* DMAC0A*/
-#define DMTE4_IRQ 76 /* DMAC0B */
-#define DMTE6_IRQ 40
-#define DMTE8_IRQ 42 /* DMAC1A */
-#define DMTE9_IRQ 43
-#define DMTE10_IRQ 72 /* DMAC1B */
-#define DMTE11_IRQ 73
-#define DMAE0_IRQ 78 /* DMA Error IRQ*/
-#define DMAE1_IRQ 74 /* DMA Error IRQ*/
-#define SH_DMAC_BASE0 0xFE008020
-#define SH_DMAC_BASE1 0xFDC08020
-#define SH_DMARS_BASE0 0xFDC09000
-#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
-#define DMTE0_IRQ 48 /* DMAC0A*/
-#define DMTE4_IRQ 76 /* DMAC0B */
-#define DMTE6_IRQ 40
-#define DMTE8_IRQ 42 /* DMAC1A */
-#define DMTE9_IRQ 43
-#define DMTE10_IRQ 72 /* DMAC1B */
-#define DMTE11_IRQ 73
-#define DMAE0_IRQ 78 /* DMA Error IRQ*/
-#define DMAE1_IRQ 74 /* DMA Error IRQ*/
-#define SH_DMAC_BASE0 0xFE008020
-#define SH_DMAC_BASE1 0xFDC08020
-#define SH_DMARS_BASE0 0xFE009000
-#define SH_DMARS_BASE1 0xFDC09000
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
-#define DMTE0_IRQ 34
-#define DMTE4_IRQ 44
-#define DMTE6_IRQ 46
-#define DMTE8_IRQ 92
-#define DMTE9_IRQ 93
-#define DMTE10_IRQ 94
-#define DMTE11_IRQ 95
-#define DMAE0_IRQ 38 /* DMA Error IRQ */
-#define SH_DMAC_BASE0 0xFC808020
-#define SH_DMAC_BASE1 0xFC818020
-#define SH_DMARS_BASE0 0xFC809000
-#else /* SH7785 */
-#define DMTE0_IRQ 33
-#define DMTE4_IRQ 37
-#define DMTE6_IRQ 52
-#define DMTE8_IRQ 54
-#define DMTE9_IRQ 55
-#define DMTE10_IRQ 56
-#define DMTE11_IRQ 57
-#define DMAE0_IRQ 39 /* DMA Error IRQ0 */
-#define DMAE1_IRQ 58 /* DMA Error IRQ1 */
-#define SH_DMAC_BASE0 0xFC808020
-#define SH_DMAC_BASE1 0xFCC08020
-#define SH_DMARS_BASE0 0xFC809000
-#endif
-
-#define REQ_HE 0x000000C0
-#define REQ_H 0x00000080
-#define REQ_LE 0x00000040
-#define TM_BURST 0x00000020
-
-#endif /* __ASM_SH_CPU_SH4_DMA_SH7780_H */
diff --git a/arch/sh/include/cpu-sh4/cpu/dma.h b/arch/sh/include/cpu-sh4/cpu/dma.h
index ca747e93c2ed..a520eb219621 100644
--- a/arch/sh/include/cpu-sh4/cpu/dma.h
+++ b/arch/sh/include/cpu-sh4/cpu/dma.h
@@ -1,32 +1,17 @@
#ifndef __ASM_CPU_SH4_DMA_H
#define __ASM_CPU_SH4_DMA_H
-/* SH7751/7760/7780 DMA IRQ sources */
+#include <linux/sh_intc.h>
-#ifdef CONFIG_CPU_SH4A
-
-#include <cpu/dma-sh4a.h>
-
-#else /* CONFIG_CPU_SH4A */
/*
* SH7750/SH7751/SH7760
*/
-#define DMTE0_IRQ 34
-#define DMTE4_IRQ 44
-#define DMTE6_IRQ 46
-#define DMAE0_IRQ 38
+#define DMTE0_IRQ evt2irq(0x640)
+#define DMTE4_IRQ evt2irq(0x780)
+#define DMTE6_IRQ evt2irq(0x7c0)
+#define DMAE0_IRQ evt2irq(0x6c0)
#define SH_DMAC_BASE0 0xffa00000
#define SH_DMAC_BASE1 0xffa00070
-/* Definitions for the SuperH DMAC */
-#define TM_BURST 0x00000080
-#define TS_8 0x00000010
-#define TS_16 0x00000020
-#define TS_32 0x00000030
-#define TS_64 0x00000000
-
-#define DMAOR_COD 0x00000008
-
-#endif
#endif /* __ASM_CPU_SH4_DMA_H */
diff --git a/arch/sh/include/cpu-sh4/cpu/freq.h b/arch/sh/include/cpu-sh4/cpu/freq.h
index cffd25ed0240..1631fc238e6f 100644
--- a/arch/sh/include/cpu-sh4/cpu/freq.h
+++ b/arch/sh/include/cpu-sh4/cpu/freq.h
@@ -47,6 +47,11 @@
#define MSTPCR1 0xa4150034
#define MSTPCR2 0xa4150038
+#elif defined(CONFIG_CPU_SUBTYPE_SH7734)
+#define FRQCR0 0xffc80000
+#define FRQCR2 0xffc80008
+#define FRQMR1 0xffc80014
+#define FRQMR2 0xffc80018
#elif defined(CONFIG_CPU_SUBTYPE_SH7785)
#define FRQCR0 0xffc80000
#define FRQCR1 0xffc80004
diff --git a/arch/sh/include/cpu-sh4/cpu/sh7734.h b/arch/sh/include/cpu-sh4/cpu/sh7734.h
new file mode 100644
index 000000000000..2fb9a7b71b41
--- /dev/null
+++ b/arch/sh/include/cpu-sh4/cpu/sh7734.h
@@ -0,0 +1,306 @@
+#ifndef __ASM_SH7734_H__
+#define __ASM_SH7734_H__
+
+/* Pin Function Controller:
+ * GPIO_FN_xx - GPIO used to select pin function
+ * GPIO_GP_x_x - GPIO mapped to real I/O pin on CPU
+ */
+enum {
+ GPIO_GP_0_0, GPIO_GP_0_1, GPIO_GP_0_2, GPIO_GP_0_3,
+ GPIO_GP_0_4, GPIO_GP_0_5, GPIO_GP_0_6, GPIO_GP_0_7,
+ GPIO_GP_0_8, GPIO_GP_0_9, GPIO_GP_0_10, GPIO_GP_0_11,
+ GPIO_GP_0_12, GPIO_GP_0_13, GPIO_GP_0_14, GPIO_GP_0_15,
+ GPIO_GP_0_16, GPIO_GP_0_17, GPIO_GP_0_18, GPIO_GP_0_19,
+ GPIO_GP_0_20, GPIO_GP_0_21, GPIO_GP_0_22, GPIO_GP_0_23,
+ GPIO_GP_0_24, GPIO_GP_0_25, GPIO_GP_0_26, GPIO_GP_0_27,
+ GPIO_GP_0_28, GPIO_GP_0_29, GPIO_GP_0_30, GPIO_GP_0_31,
+
+ GPIO_GP_1_0, GPIO_GP_1_1, GPIO_GP_1_2, GPIO_GP_1_3,
+ GPIO_GP_1_4, GPIO_GP_1_5, GPIO_GP_1_6, GPIO_GP_1_7,
+ GPIO_GP_1_8, GPIO_GP_1_9, GPIO_GP_1_10, GPIO_GP_1_11,
+ GPIO_GP_1_12, GPIO_GP_1_13, GPIO_GP_1_14, GPIO_GP_1_15,
+ GPIO_GP_1_16, GPIO_GP_1_17, GPIO_GP_1_18, GPIO_GP_1_19,
+ GPIO_GP_1_20, GPIO_GP_1_21, GPIO_GP_1_22, GPIO_GP_1_23,
+ GPIO_GP_1_24, GPIO_GP_1_25, GPIO_GP_1_26, GPIO_GP_1_27,
+ GPIO_GP_1_28, GPIO_GP_1_29, GPIO_GP_1_30, GPIO_GP_1_31,
+
+ GPIO_GP_2_0, GPIO_GP_2_1, GPIO_GP_2_2, GPIO_GP_2_3,
+ GPIO_GP_2_4, GPIO_GP_2_5, GPIO_GP_2_6, GPIO_GP_2_7,
+ GPIO_GP_2_8, GPIO_GP_2_9, GPIO_GP_2_10, GPIO_GP_2_11,
+ GPIO_GP_2_12, GPIO_GP_2_13, GPIO_GP_2_14, GPIO_GP_2_15,
+ GPIO_GP_2_16, GPIO_GP_2_17, GPIO_GP_2_18, GPIO_GP_2_19,
+ GPIO_GP_2_20, GPIO_GP_2_21, GPIO_GP_2_22, GPIO_GP_2_23,
+ GPIO_GP_2_24, GPIO_GP_2_25, GPIO_GP_2_26, GPIO_GP_2_27,
+ GPIO_GP_2_28, GPIO_GP_2_29, GPIO_GP_2_30, GPIO_GP_2_31,
+
+ GPIO_GP_3_0, GPIO_GP_3_1, GPIO_GP_3_2, GPIO_GP_3_3,
+ GPIO_GP_3_4, GPIO_GP_3_5, GPIO_GP_3_6, GPIO_GP_3_7,
+ GPIO_GP_3_8, GPIO_GP_3_9, GPIO_GP_3_10, GPIO_GP_3_11,
+ GPIO_GP_3_12, GPIO_GP_3_13, GPIO_GP_3_14, GPIO_GP_3_15,
+ GPIO_GP_3_16, GPIO_GP_3_17, GPIO_GP_3_18, GPIO_GP_3_19,
+ GPIO_GP_3_20, GPIO_GP_3_21, GPIO_GP_3_22, GPIO_GP_3_23,
+ GPIO_GP_3_24, GPIO_GP_3_25, GPIO_GP_3_26, GPIO_GP_3_27,
+ GPIO_GP_3_28, GPIO_GP_3_29, GPIO_GP_3_30, GPIO_GP_3_31,
+
+ GPIO_GP_4_0, GPIO_GP_4_1, GPIO_GP_4_2, GPIO_GP_4_3,
+ GPIO_GP_4_4, GPIO_GP_4_5, GPIO_GP_4_6, GPIO_GP_4_7,
+ GPIO_GP_4_8, GPIO_GP_4_9, GPIO_GP_4_10, GPIO_GP_4_11,
+ GPIO_GP_4_12, GPIO_GP_4_13, GPIO_GP_4_14, GPIO_GP_4_15,
+ GPIO_GP_4_16, GPIO_GP_4_17, GPIO_GP_4_18, GPIO_GP_4_19,
+ GPIO_GP_4_20, GPIO_GP_4_21, GPIO_GP_4_22, GPIO_GP_4_23,
+ GPIO_GP_4_24, GPIO_GP_4_25, GPIO_GP_4_26, GPIO_GP_4_27,
+ GPIO_GP_4_28, GPIO_GP_4_29, GPIO_GP_4_30, GPIO_GP_4_31,
+
+ GPIO_GP_5_0, GPIO_GP_5_1, GPIO_GP_5_2, GPIO_GP_5_3,
+ GPIO_GP_5_4, GPIO_GP_5_5, GPIO_GP_5_6, GPIO_GP_5_7,
+ GPIO_GP_5_8, GPIO_GP_5_9, GPIO_GP_5_10, GPIO_GP_5_11,
+
+ GPIO_FN_CLKOUT, GPIO_FN_BS, GPIO_FN_CS0, GPIO_FN_EX_CS0, GPIO_FN_RD,
+ GPIO_FN_WE0, GPIO_FN_WE1,
+
+ GPIO_FN_SCL0, GPIO_FN_PENC0, GPIO_FN_USB_OVC0,
+
+ GPIO_FN_IRQ2_B, GPIO_FN_IRQ3_B,
+
+ /* IPSR0 */
+ GPIO_FN_A15, GPIO_FN_ST0_VCO_CLKIN, GPIO_FN_LCD_DATA15_A,
+ GPIO_FN_TIOC3D_C,
+ GPIO_FN_A14, GPIO_FN_LCD_DATA14_A, GPIO_FN_TIOC3C_C,
+ GPIO_FN_A13, GPIO_FN_LCD_DATA13_A, GPIO_FN_TIOC3B_C,
+ GPIO_FN_A12, GPIO_FN_LCD_DATA12_A, GPIO_FN_TIOC3A_C,
+ GPIO_FN_A11, GPIO_FN_ST0_D7, GPIO_FN_LCD_DATA11_A,
+ GPIO_FN_TIOC2B_C,
+ GPIO_FN_A10, GPIO_FN_ST0_D6, GPIO_FN_LCD_DATA10_A,
+ GPIO_FN_TIOC2A_C,
+ GPIO_FN_A9, GPIO_FN_ST0_D5, GPIO_FN_LCD_DATA9_A,
+ GPIO_FN_TIOC1B_C,
+ GPIO_FN_A8, GPIO_FN_ST0_D4, GPIO_FN_LCD_DATA8_A,
+ GPIO_FN_TIOC1A_C,
+ GPIO_FN_A7, GPIO_FN_ST0_D3, GPIO_FN_LCD_DATA7_A, GPIO_FN_TIOC0D_C,
+ GPIO_FN_A6, GPIO_FN_ST0_D2, GPIO_FN_LCD_DATA6_A, GPIO_FN_TIOC0C_C,
+ GPIO_FN_A5, GPIO_FN_ST0_D1, GPIO_FN_LCD_DATA5_A, GPIO_FN_TIOC0B_C,
+ GPIO_FN_A4, GPIO_FN_ST0_D0, GPIO_FN_LCD_DATA4_A, GPIO_FN_TIOC0A_C,
+ GPIO_FN_A3, GPIO_FN_ST0_VLD, GPIO_FN_LCD_DATA3_A, GPIO_FN_TCLKD_C,
+ GPIO_FN_A2, GPIO_FN_ST0_SYC, GPIO_FN_LCD_DATA2_A, GPIO_FN_TCLKC_C,
+ GPIO_FN_A1, GPIO_FN_ST0_REQ, GPIO_FN_LCD_DATA1_A, GPIO_FN_TCLKB_C,
+ GPIO_FN_A0, GPIO_FN_ST0_CLKIN, GPIO_FN_LCD_DATA0_A, GPIO_FN_TCLKA_C,
+
+ /* IPSR1 */
+ GPIO_FN_D3, GPIO_FN_SD0_DAT3_A, GPIO_FN_MMC_D3_A, GPIO_FN_ST1_D6,
+ GPIO_FN_FD3_A,
+ GPIO_FN_D2, GPIO_FN_SD0_DAT2_A, GPIO_FN_MMC_D2_A, GPIO_FN_ST1_D5,
+ GPIO_FN_FD2_A,
+ GPIO_FN_D1, GPIO_FN_SD0_DAT1_A, GPIO_FN_MMC_D1_A, GPIO_FN_ST1_D4,
+ GPIO_FN_FD1_A,
+ GPIO_FN_D0, GPIO_FN_SD0_DAT0_A, GPIO_FN_MMC_D0_A, GPIO_FN_ST1_D3,
+ GPIO_FN_FD0_A,
+ GPIO_FN_A25, GPIO_FN_TX2_D, GPIO_FN_ST1_D2,
+ GPIO_FN_A24, GPIO_FN_RX2_D, GPIO_FN_ST1_D1,
+ GPIO_FN_A23, GPIO_FN_ST1_D0, GPIO_FN_LCD_M_DISP_A,
+ GPIO_FN_A22, GPIO_FN_ST1_VLD, GPIO_FN_LCD_VEPWC_A,
+ GPIO_FN_A21, GPIO_FN_ST1_SYC, GPIO_FN_LCD_VCPWC_A,
+ GPIO_FN_A20, GPIO_FN_ST1_REQ, GPIO_FN_LCD_FLM_A,
+ GPIO_FN_A19, GPIO_FN_ST1_CLKIN, GPIO_FN_LCD_CLK_A, GPIO_FN_TIOC4D_C,
+ GPIO_FN_A18, GPIO_FN_ST1_PWM, GPIO_FN_LCD_CL2_A, GPIO_FN_TIOC4C_C,
+ GPIO_FN_A17, GPIO_FN_ST1_VCO_CLKIN, GPIO_FN_LCD_CL1_A, GPIO_FN_TIOC4B_C,
+ GPIO_FN_A16, GPIO_FN_ST0_PWM, GPIO_FN_LCD_DON_A, GPIO_FN_TIOC4A_C,
+
+ /* IPSR2 */
+ GPIO_FN_D14, GPIO_FN_TX2_B, GPIO_FN_FSE_A, GPIO_FN_ET0_TX_CLK_B,
+ GPIO_FN_D13, GPIO_FN_RX2_B, GPIO_FN_FRB_A, GPIO_FN_ET0_ETXD6_B,
+ GPIO_FN_D12, GPIO_FN_FWE_A, GPIO_FN_ET0_ETXD5_B,
+ GPIO_FN_D11, GPIO_FN_RSPI_MISO_A, GPIO_FN_QMI_QIO1_A,
+ GPIO_FN_FRE_A, GPIO_FN_ET0_ETXD3_B,
+ GPIO_FN_D10, GPIO_FN_RSPI_MOSI_A, GPIO_FN_QMO_QIO0_A,
+ GPIO_FN_FALE_A, GPIO_FN_ET0_ETXD2_B,
+ GPIO_FN_D9, GPIO_FN_SD0_CMD_A, GPIO_FN_MMC_CMD_A, GPIO_FN_QIO3_A,
+ GPIO_FN_FCLE_A, GPIO_FN_ET0_ETXD1_B,
+ GPIO_FN_D8, GPIO_FN_SD0_CLK_A, GPIO_FN_MMC_CLK_A, GPIO_FN_QIO2_A,
+ GPIO_FN_FCE_A, GPIO_FN_ET0_GTX_CLK_B,
+ GPIO_FN_D7, GPIO_FN_RSPI_SSL_A, GPIO_FN_MMC_D7_A, GPIO_FN_QSSL_A,
+ GPIO_FN_FD7_A,
+ GPIO_FN_D6, GPIO_FN_RSPI_RSPCK_A, GPIO_FN_MMC_D6_A, GPIO_FN_QSPCLK_A,
+ GPIO_FN_FD6_A,
+ GPIO_FN_D5, GPIO_FN_SD0_WP_A, GPIO_FN_MMC_D5_A, GPIO_FN_FD5_A,
+ GPIO_FN_D4, GPIO_FN_SD0_CD_A, GPIO_FN_MMC_D4_A, GPIO_FN_ST1_D7,
+ GPIO_FN_FD4_A,
+
+ /* IPSR3 */
+ GPIO_FN_DRACK0, GPIO_FN_SD1_DAT2_A, GPIO_FN_ATAG, GPIO_FN_TCLK1_A,
+ GPIO_FN_ET0_ETXD7,
+ GPIO_FN_EX_WAIT2, GPIO_FN_SD1_DAT1_A, GPIO_FN_DACK2, GPIO_FN_CAN1_RX_C,
+ GPIO_FN_ET0_MAGIC_C, GPIO_FN_ET0_ETXD6_A,
+ GPIO_FN_EX_WAIT1, GPIO_FN_SD1_DAT0_A, GPIO_FN_DREQ2, GPIO_FN_CAN1_TX_C,
+ GPIO_FN_ET0_LINK_C, GPIO_FN_ET0_ETXD5_A,
+ GPIO_FN_EX_WAIT0, GPIO_FN_TCLK1_B,
+ GPIO_FN_RD_WR, GPIO_FN_TCLK0,
+ GPIO_FN_EX_CS5, GPIO_FN_SD1_CMD_A, GPIO_FN_ATADIR, GPIO_FN_QSSL_B,
+ GPIO_FN_ET0_ETXD3_A,
+ GPIO_FN_EX_CS4, GPIO_FN_SD1_WP_A, GPIO_FN_ATAWR, GPIO_FN_QMI_QIO1_B,
+ GPIO_FN_ET0_ETXD2_A,
+ GPIO_FN_EX_CS3, GPIO_FN_SD1_CD_A, GPIO_FN_ATARD, GPIO_FN_QMO_QIO0_B,
+ GPIO_FN_ET0_ETXD1_A,
+ GPIO_FN_EX_CS2, GPIO_FN_TX3_B, GPIO_FN_ATACS1, GPIO_FN_QSPCLK_B,
+ GPIO_FN_ET0_GTX_CLK_A,
+ GPIO_FN_EX_CS1, GPIO_FN_RX3_B, GPIO_FN_ATACS0, GPIO_FN_QIO2_B,
+ GPIO_FN_ET0_ETXD0,
+ GPIO_FN_CS1_A26, GPIO_FN_QIO3_B,
+ GPIO_FN_D15, GPIO_FN_SCK2_B,
+
+ /* IPSR4 */
+ GPIO_FN_SCK2_A, GPIO_FN_VI0_G3,
+ GPIO_FN_RTS1_B, GPIO_FN_VI0_G2,
+ GPIO_FN_CTS1_B, GPIO_FN_VI0_DATA7_VI0_G1,
+ GPIO_FN_TX1_B, GPIO_FN_VI0_DATA6_VI0_G0, GPIO_FN_ET0_PHY_INT_A,
+ GPIO_FN_RX1_B, GPIO_FN_VI0_DATA5_VI0_B5, GPIO_FN_ET0_MAGIC_A,
+ GPIO_FN_SCK1_B, GPIO_FN_VI0_DATA4_VI0_B4, GPIO_FN_ET0_LINK_A,
+ GPIO_FN_RTS0_B, GPIO_FN_VI0_DATA3_VI0_B3, GPIO_FN_ET0_MDIO_A,
+ GPIO_FN_CTS0_B, GPIO_FN_VI0_DATA2_VI0_B2, GPIO_FN_RMII0_MDIO_A,
+ GPIO_FN_ET0_MDC,
+ GPIO_FN_HTX0_A, GPIO_FN_TX1_A, GPIO_FN_VI0_DATA1_VI0_B1,
+ GPIO_FN_RMII0_MDC_A, GPIO_FN_ET0_COL,
+ GPIO_FN_HRX0_A, GPIO_FN_RX1_A, GPIO_FN_VI0_DATA0_VI0_B0,
+ GPIO_FN_RMII0_CRS_DV_A, GPIO_FN_ET0_CRS,
+ GPIO_FN_HSCK0_A, GPIO_FN_SCK1_A, GPIO_FN_VI0_VSYNC,
+ GPIO_FN_RMII0_RX_ER_A, GPIO_FN_ET0_RX_ER,
+ GPIO_FN_HRTS0_A, GPIO_FN_RTS1_A, GPIO_FN_VI0_HSYNC,
+ GPIO_FN_RMII0_TXD_EN_A, GPIO_FN_ET0_RX_DV,
+ GPIO_FN_HCTS0_A, GPIO_FN_CTS1_A, GPIO_FN_VI0_FIELD,
+ GPIO_FN_RMII0_RXD1_A, GPIO_FN_ET0_ERXD7,
+
+ /* IPSR5 */
+ GPIO_FN_SD2_CLK_A, GPIO_FN_RX2_A, GPIO_FN_VI0_G4, GPIO_FN_ET0_RX_CLK_B,
+ GPIO_FN_SD2_CMD_A, GPIO_FN_TX2_A, GPIO_FN_VI0_G5, GPIO_FN_ET0_ERXD2_B,
+ GPIO_FN_SD2_DAT0_A, GPIO_FN_RX3_A, GPIO_FN_VI0_R0, GPIO_FN_ET0_ERXD3_B,
+ GPIO_FN_SD2_DAT1_A, GPIO_FN_TX3_A, GPIO_FN_VI0_R1, GPIO_FN_ET0_MDIO_B,
+ GPIO_FN_SD2_DAT2_A, GPIO_FN_RX4_A, GPIO_FN_VI0_R2, GPIO_FN_ET0_LINK_B,
+ GPIO_FN_SD2_DAT3_A, GPIO_FN_TX4_A, GPIO_FN_VI0_R3, GPIO_FN_ET0_MAGIC_B,
+ GPIO_FN_SD2_CD_A, GPIO_FN_RX5_A, GPIO_FN_VI0_R4, GPIO_FN_ET0_PHY_INT_B,
+ GPIO_FN_SD2_WP_A, GPIO_FN_TX5_A, GPIO_FN_VI0_R5,
+ GPIO_FN_REF125CK, GPIO_FN_ADTRG, GPIO_FN_RX5_C,
+ GPIO_FN_REF50CK, GPIO_FN_CTS1_E, GPIO_FN_HCTS0_D,
+
+ /* IPSR6 */
+ GPIO_FN_DU0_DR0, GPIO_FN_SCIF_CLK_B, GPIO_FN_HRX0_D, GPIO_FN_IETX_A,
+ GPIO_FN_TCLKA_A, GPIO_FN_HIFD00,
+ GPIO_FN_DU0_DR1, GPIO_FN_SCK0_B, GPIO_FN_HTX0_D, GPIO_FN_IERX_A,
+ GPIO_FN_TCLKB_A, GPIO_FN_HIFD01,
+ GPIO_FN_DU0_DR2, GPIO_FN_RX0_B, GPIO_FN_TCLKC_A, GPIO_FN_HIFD02,
+ GPIO_FN_DU0_DR3, GPIO_FN_TX0_B, GPIO_FN_TCLKD_A, GPIO_FN_HIFD03,
+ GPIO_FN_DU0_DR4, GPIO_FN_CTS0_C, GPIO_FN_TIOC0A_A, GPIO_FN_HIFD04,
+ GPIO_FN_DU0_DR5, GPIO_FN_RTS0_C, GPIO_FN_TIOC0B_A, GPIO_FN_HIFD05,
+ GPIO_FN_DU0_DR6, GPIO_FN_SCK1_C, GPIO_FN_TIOC0C_A, GPIO_FN_HIFD06,
+ GPIO_FN_DU0_DR7, GPIO_FN_RX1_C, GPIO_FN_TIOC0D_A, GPIO_FN_HIFD07,
+ GPIO_FN_DU0_DG0, GPIO_FN_TX1_C, GPIO_FN_HSCK0_D, GPIO_FN_IECLK_A,
+ GPIO_FN_TIOC1A_A, GPIO_FN_HIFD08,
+ GPIO_FN_DU0_DG1, GPIO_FN_CTS1_C, GPIO_FN_HRTS0_D, GPIO_FN_TIOC1B_A,
+ GPIO_FN_HIFD09,
+
+ /* IPSR7 */
+ GPIO_FN_DU0_DG2, GPIO_FN_RTS1_C, GPIO_FN_RMII0_MDC_B, GPIO_FN_TIOC2A_A,
+ GPIO_FN_HIFD10,
+ GPIO_FN_DU0_DG3, GPIO_FN_SCK2_C, GPIO_FN_RMII0_MDIO_B, GPIO_FN_TIOC2B_A,
+ GPIO_FN_HIFD11,
+ GPIO_FN_DU0_DG4, GPIO_FN_RX2_C, GPIO_FN_RMII0_CRS_DV_B,
+ GPIO_FN_TIOC3A_A, GPIO_FN_HIFD12,
+ GPIO_FN_DU0_DG5, GPIO_FN_TX2_C, GPIO_FN_RMII0_RX_ER_B,
+ GPIO_FN_TIOC3B_A, GPIO_FN_HIFD13,
+ GPIO_FN_DU0_DG6, GPIO_FN_RX3_C, GPIO_FN_RMII0_RXD0_B,
+ GPIO_FN_TIOC3C_A, GPIO_FN_HIFD14,
+ GPIO_FN_DU0_DG7, GPIO_FN_TX3_C, GPIO_FN_RMII0_RXD1_B,
+ GPIO_FN_TIOC3D_A, GPIO_FN_HIFD15,
+ GPIO_FN_DU0_DB0, GPIO_FN_RX4_C, GPIO_FN_RMII0_TXD_EN_B,
+ GPIO_FN_TIOC4A_A, GPIO_FN_HIFCS,
+ GPIO_FN_DU0_DB1, GPIO_FN_TX4_C, GPIO_FN_RMII0_TXD0_B,
+ GPIO_FN_TIOC4B_A, GPIO_FN_HIFRS,
+ GPIO_FN_DU0_DB2, GPIO_FN_RX5_B, GPIO_FN_RMII0_TXD1_B,
+ GPIO_FN_TIOC4C_A, GPIO_FN_HIFWR,
+ GPIO_FN_DU0_DB3, GPIO_FN_TX5_B, GPIO_FN_TIOC4D_A, GPIO_FN_HIFRD,
+ GPIO_FN_DU0_DB4, GPIO_FN_HIFINT,
+
+ /* IPSR8 */
+ GPIO_FN_DU0_DB5, GPIO_FN_HIFDREQ,
+ GPIO_FN_DU0_DB6, GPIO_FN_HIFRDY,
+ GPIO_FN_DU0_DB7, GPIO_FN_SSI_SCK0_B, GPIO_FN_HIFEBL_B,
+ GPIO_FN_DU0_DOTCLKIN, GPIO_FN_HSPI_CS0_C, GPIO_FN_SSI_WS0_B,
+ GPIO_FN_DU0_DOTCLKOUT, GPIO_FN_HSPI_CLK0_C, GPIO_FN_SSI_SDATA0_B,
+ GPIO_FN_DU0_EXHSYNC_DU0_HSYNC, GPIO_FN_HSPI_TX0_C, GPIO_FN_SSI_SCK1_B,
+ GPIO_FN_DU0_EXVSYNC_DU0_VSYNC, GPIO_FN_HSPI_RX0_C, GPIO_FN_SSI_WS1_B,
+ GPIO_FN_DU0_EXODDF_DU0_ODDF, GPIO_FN_CAN0_RX_B, GPIO_FN_HSCK0_B,
+ GPIO_FN_SSI_SDATA1_B,
+ GPIO_FN_DU0_DISP, GPIO_FN_CAN0_TX_B, GPIO_FN_HRX0_B,
+ GPIO_FN_AUDIO_CLKA_B,
+ GPIO_FN_DU0_CDE, GPIO_FN_HTX0_B, GPIO_FN_AUDIO_CLKB_B,
+ GPIO_FN_LCD_VCPWC_B,
+ GPIO_FN_IRQ0_A, GPIO_FN_HSPI_TX_B, GPIO_FN_RX3_E, GPIO_FN_ET0_ERXD0,
+ GPIO_FN_IRQ1_A, GPIO_FN_HSPI_RX_B, GPIO_FN_TX3_E, GPIO_FN_ET0_ERXD1,
+ GPIO_FN_IRQ2_A, GPIO_FN_CTS0_A, GPIO_FN_HCTS0_B, GPIO_FN_ET0_ERXD2_A,
+ GPIO_FN_IRQ3_A, GPIO_FN_RTS0_A, GPIO_FN_HRTS0_B, GPIO_FN_ET0_ERXD3_A,
+
+ /* IPSR9 */
+ GPIO_FN_VI1_CLK_A, GPIO_FN_FD0_B, GPIO_FN_LCD_DATA0_B,
+ GPIO_FN_VI1_0_A, GPIO_FN_FD1_B, GPIO_FN_LCD_DATA1_B,
+ GPIO_FN_VI1_1_A, GPIO_FN_FD2_B, GPIO_FN_LCD_DATA2_B,
+ GPIO_FN_VI1_2_A, GPIO_FN_FD3_B, GPIO_FN_LCD_DATA3_B,
+ GPIO_FN_VI1_3_A, GPIO_FN_FD4_B, GPIO_FN_LCD_DATA4_B,
+ GPIO_FN_VI1_4_A, GPIO_FN_FD5_B, GPIO_FN_LCD_DATA5_B,
+ GPIO_FN_VI1_5_A, GPIO_FN_FD6_B, GPIO_FN_LCD_DATA6_B,
+ GPIO_FN_VI1_6_A, GPIO_FN_FD7_B, GPIO_FN_LCD_DATA7_B,
+ GPIO_FN_VI1_7_A, GPIO_FN_FCE_B, GPIO_FN_LCD_DATA8_B,
+ GPIO_FN_SSI_SCK0_A, GPIO_FN_TIOC1A_B, GPIO_FN_LCD_DATA9_B,
+ GPIO_FN_SSI_WS0_A, GPIO_FN_TIOC1B_B, GPIO_FN_LCD_DATA10_B,
+ GPIO_FN_SSI_SDATA0_A, GPIO_FN_VI1_0_B, GPIO_FN_TIOC2A_B,
+ GPIO_FN_LCD_DATA11_B,
+ GPIO_FN_SSI_SCK1_A, GPIO_FN_VI1_1_B, GPIO_FN_TIOC2B_B,
+ GPIO_FN_LCD_DATA12_B,
+ GPIO_FN_SSI_WS1_A, GPIO_FN_VI1_2_B, GPIO_FN_LCD_DATA13_B,
+ GPIO_FN_SSI_SDATA1_A, GPIO_FN_VI1_3_B, GPIO_FN_LCD_DATA14_B,
+
+ /* IPSR10 */
+ GPIO_FN_SSI_SCK23, GPIO_FN_VI1_4_B, GPIO_FN_RX1_D, GPIO_FN_FCLE_B,
+ GPIO_FN_LCD_DATA15_B,
+ GPIO_FN_SSI_WS23, GPIO_FN_VI1_5_B, GPIO_FN_TX1_D, GPIO_FN_HSCK0_C,
+ GPIO_FN_FALE_B, GPIO_FN_LCD_DON_B,
+ GPIO_FN_SSI_SDATA2, GPIO_FN_VI1_6_B, GPIO_FN_HRX0_C, GPIO_FN_FRE_B,
+ GPIO_FN_LCD_CL1_B,
+ GPIO_FN_SSI_SDATA3, GPIO_FN_VI1_7_B, GPIO_FN_HTX0_C, GPIO_FN_FWE_B,
+ GPIO_FN_LCD_CL2_B,
+ GPIO_FN_AUDIO_CLKA_A, GPIO_FN_VI1_CLK_B, GPIO_FN_SCK1_D,
+ GPIO_FN_IECLK_B, GPIO_FN_LCD_FLM_B,
+ GPIO_FN_AUDIO_CLKB_A, GPIO_FN_LCD_CLK_B,
+ GPIO_FN_AUDIO_CLKC, GPIO_FN_SCK1_E, GPIO_FN_HCTS0_C, GPIO_FN_FRB_B,
+ GPIO_FN_LCD_VEPWC_B,
+ GPIO_FN_AUDIO_CLKOUT, GPIO_FN_TX1_E, GPIO_FN_HRTS0_C, GPIO_FN_FSE_B,
+ GPIO_FN_LCD_M_DISP_B,
+ GPIO_FN_CAN_CLK_A, GPIO_FN_RX4_D,
+ GPIO_FN_CAN0_TX_A, GPIO_FN_TX4_D, GPIO_FN_MLB_CLK,
+ GPIO_FN_CAN1_RX_A, GPIO_FN_IRQ1_B,
+ GPIO_FN_CAN0_RX_A, GPIO_FN_IRQ0_B, GPIO_FN_MLB_SIG,
+ GPIO_FN_CAN1_TX_A, GPIO_FN_TX5_C, GPIO_FN_MLB_DAT,
+
+ /* IPSR11 */
+ GPIO_FN_SCL1, GPIO_FN_SCIF_CLK_C,
+ GPIO_FN_SDA1, GPIO_FN_RX1_E,
+ GPIO_FN_SDA0, GPIO_FN_HIFEBL_A,
+ GPIO_FN_SDSELF, GPIO_FN_RTS1_E,
+ GPIO_FN_SCIF_CLK_A, GPIO_FN_HSPI_CLK_A, GPIO_FN_VI0_CLK,
+ GPIO_FN_RMII0_TXD0_A, GPIO_FN_ET0_ERXD4,
+ GPIO_FN_SCK0_A, GPIO_FN_HSPI_CS_A, GPIO_FN_VI0_CLKENB,
+ GPIO_FN_RMII0_TXD1_A, GPIO_FN_ET0_ERXD5,
+ GPIO_FN_RX0_A, GPIO_FN_HSPI_RX_A, GPIO_FN_RMII0_RXD0_A,
+ GPIO_FN_ET0_ERXD6,
+ GPIO_FN_TX0_A, GPIO_FN_HSPI_TX_A,
+ GPIO_FN_PENC1, GPIO_FN_TX3_D, GPIO_FN_CAN1_TX_B, GPIO_FN_TX5_D,
+ GPIO_FN_IETX_B,
+ GPIO_FN_USB_OVC1, GPIO_FN_RX3_D, GPIO_FN_CAN1_RX_B, GPIO_FN_RX5_D,
+ GPIO_FN_IERX_B,
+ GPIO_FN_DREQ0, GPIO_FN_SD1_CLK_A, GPIO_FN_ET0_TX_EN,
+ GPIO_FN_DACK0, GPIO_FN_SD1_DAT3_A, GPIO_FN_ET0_TX_ER,
+ GPIO_FN_DREQ1, GPIO_FN_HSPI_CLK_B, GPIO_FN_RX4_B, GPIO_FN_ET0_PHY_INT_C,
+ GPIO_FN_ET0_TX_CLK_A,
+ GPIO_FN_DACK1, GPIO_FN_HSPI_CS_B, GPIO_FN_TX4_B, GPIO_FN_ET0_RX_CLK_A,
+ GPIO_FN_PRESETOUT, GPIO_FN_ST_CLKOUT,
+
+};
+
+#endif /* __ASM_SH7734_H__ */
diff --git a/arch/sh/include/cpu-sh4a/cpu/dma.h b/arch/sh/include/cpu-sh4a/cpu/dma.h
new file mode 100644
index 000000000000..89afb650ce25
--- /dev/null
+++ b/arch/sh/include/cpu-sh4a/cpu/dma.h
@@ -0,0 +1,72 @@
+#ifndef __ASM_SH_CPU_SH4_DMA_SH7780_H
+#define __ASM_SH_CPU_SH4_DMA_SH7780_H
+
+#include <linux/sh_intc.h>
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7343) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7730)
+#define DMTE0_IRQ evt2irq(0x800)
+#define DMTE4_IRQ evt2irq(0xb80)
+#define DMAE0_IRQ evt2irq(0xbc0) /* DMA Error IRQ*/
+#define SH_DMAC_BASE0 0xFE008020
+#elif defined(CONFIG_CPU_SUBTYPE_SH7722)
+#define DMTE0_IRQ evt2irq(0x800)
+#define DMTE4_IRQ evt2irq(0xb80)
+#define DMAE0_IRQ evt2irq(0xbc0) /* DMA Error IRQ*/
+#define SH_DMAC_BASE0 0xFE008020
+#elif defined(CONFIG_CPU_SUBTYPE_SH7763) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7764)
+#define DMTE0_IRQ evt2irq(0x640)
+#define DMTE4_IRQ evt2irq(0x780)
+#define DMAE0_IRQ evt2irq(0x6c0)
+#define SH_DMAC_BASE0 0xFF608020
+#elif defined(CONFIG_CPU_SUBTYPE_SH7723)
+#define DMTE0_IRQ evt2irq(0x800) /* DMAC0A*/
+#define DMTE4_IRQ evt2irq(0xb80) /* DMAC0B */
+#define DMTE6_IRQ evt2irq(0x700)
+#define DMTE8_IRQ evt2irq(0x740) /* DMAC1A */
+#define DMTE9_IRQ evt2irq(0x760)
+#define DMTE10_IRQ evt2irq(0xb00) /* DMAC1B */
+#define DMTE11_IRQ evt2irq(0xb20)
+#define DMAE0_IRQ evt2irq(0xbc0) /* DMA Error IRQ*/
+#define DMAE1_IRQ evt2irq(0xb40) /* DMA Error IRQ*/
+#define SH_DMAC_BASE0 0xFE008020
+#define SH_DMAC_BASE1 0xFDC08020
+#elif defined(CONFIG_CPU_SUBTYPE_SH7724)
+#define DMTE0_IRQ evt2irq(0x800) /* DMAC0A*/
+#define DMTE4_IRQ evt2irq(0xb80) /* DMAC0B */
+#define DMTE6_IRQ evt2irq(0x700)
+#define DMTE8_IRQ evt2irq(0x740) /* DMAC1A */
+#define DMTE9_IRQ evt2irq(0x760)
+#define DMTE10_IRQ evt2irq(0xb00) /* DMAC1B */
+#define DMTE11_IRQ evt2irq(0xb20)
+#define DMAE0_IRQ evt2irq(0xbc0) /* DMA Error IRQ*/
+#define DMAE1_IRQ evt2irq(0xb40) /* DMA Error IRQ*/
+#define SH_DMAC_BASE0 0xFE008020
+#define SH_DMAC_BASE1 0xFDC08020
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+#define DMTE0_IRQ evt2irq(0x640)
+#define DMTE4_IRQ evt2irq(0x780)
+#define DMTE6_IRQ evt2irq(0x7c0)
+#define DMTE8_IRQ evt2irq(0xd80)
+#define DMTE9_IRQ evt2irq(0xda0)
+#define DMTE10_IRQ evt2irq(0xdc0)
+#define DMTE11_IRQ evt2irq(0xde0)
+#define DMAE0_IRQ evt2irq(0x6c0) /* DMA Error IRQ */
+#define SH_DMAC_BASE0 0xFC808020
+#define SH_DMAC_BASE1 0xFC818020
+#else /* SH7785 */
+#define DMTE0_IRQ evt2irq(0x620)
+#define DMTE4_IRQ evt2irq(0x6a0)
+#define DMTE6_IRQ evt2irq(0x880)
+#define DMTE8_IRQ evt2irq(0x8c0)
+#define DMTE9_IRQ evt2irq(0x8e0)
+#define DMTE10_IRQ evt2irq(0x900)
+#define DMTE11_IRQ evt2irq(0x920)
+#define DMAE0_IRQ evt2irq(0x6e0) /* DMA Error IRQ0 */
+#define DMAE1_IRQ evt2irq(0x940) /* DMA Error IRQ1 */
+#define SH_DMAC_BASE0 0xFC808020
+#define SH_DMAC_BASE1 0xFCC08020
+#endif
+
+#endif /* __ASM_SH_CPU_SH4_DMA_SH7780_H */
diff --git a/arch/sh/include/cpu-sh5/cpu/dma.h b/arch/sh/include/cpu-sh5/cpu/dma.h
deleted file mode 100644
index 7bf6bb3d35ed..000000000000
--- a/arch/sh/include/cpu-sh5/cpu/dma.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_SH_CPU_SH5_DMA_H
-#define __ASM_SH_CPU_SH5_DMA_H
-
-/* Nothing yet */
-
-#endif /* __ASM_SH_CPU_SH5_DMA_H */
diff --git a/arch/sh/include/mach-common/mach/hp6xx.h b/arch/sh/include/mach-common/mach/hp6xx.h
index bcc301ac12f4..6aaaf8596e6a 100644
--- a/arch/sh/include/mach-common/mach/hp6xx.h
+++ b/arch/sh/include/mach-common/mach/hp6xx.h
@@ -9,10 +9,11 @@
* for more details.
*
*/
+#include <linux/sh_intc.h>
-#define HP680_BTN_IRQ 32 /* IRQ0_IRQ */
-#define HP680_TS_IRQ 35 /* IRQ3_IRQ */
-#define HP680_HD64461_IRQ 36 /* IRQ4_IRQ */
+#define HP680_BTN_IRQ evt2irq(0x600) /* IRQ0_IRQ */
+#define HP680_TS_IRQ evt2irq(0x660) /* IRQ3_IRQ */
+#define HP680_HD64461_IRQ evt2irq(0x680) /* IRQ4_IRQ */
#define DAC_LCD_BRIGHTNESS 0
#define DAC_SPEAKER_VOLUME 1
diff --git a/arch/sh/include/mach-common/mach/lboxre2.h b/arch/sh/include/mach-common/mach/lboxre2.h
index e6d160504923..3a4dcc5c74ee 100644
--- a/arch/sh/include/mach-common/mach/lboxre2.h
+++ b/arch/sh/include/mach-common/mach/lboxre2.h
@@ -11,13 +11,14 @@
* for more details.
*
*/
+#include <linux/sh_intc.h>
-#define IRQ_CF1 9 /* CF1 */
-#define IRQ_CF0 10 /* CF0 */
-#define IRQ_INTD 11 /* INTD */
-#define IRQ_ETH1 12 /* Ether1 */
-#define IRQ_ETH0 13 /* Ether0 */
-#define IRQ_INTA 14 /* INTA */
+#define IRQ_CF1 evt2irq(0x320) /* CF1 */
+#define IRQ_CF0 evt2irq(0x340) /* CF0 */
+#define IRQ_INTD evt2irq(0x360) /* INTD */
+#define IRQ_ETH1 evt2irq(0x380) /* Ether1 */
+#define IRQ_ETH0 evt2irq(0x3a0) /* Ether0 */
+#define IRQ_INTA evt2irq(0x3c0) /* INTA */
void init_lboxre2_IRQ(void);
diff --git a/arch/sh/include/mach-common/mach/sdk7780.h b/arch/sh/include/mach-common/mach/sdk7780.h
index 697dc865f21b..ce64e02e9b50 100644
--- a/arch/sh/include/mach-common/mach/sdk7780.h
+++ b/arch/sh/include/mach-common/mach/sdk7780.h
@@ -11,6 +11,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
+#include <linux/sh_intc.h>
#include <asm/addrspace.h>
/* Box specific addresses. */
@@ -67,9 +68,9 @@
#define SDK7780_NR_IRL 15
/* IDE/ATA interrupt */
-#define IRQ_CFCARD 14
+#define IRQ_CFCARD evt2irq(0x3c0)
/* SMC interrupt */
-#define IRQ_ETHERNET 6
+#define IRQ_ETHERNET evt2irq(0x2c0)
/* arch/sh/boards/renesas/sdk7780/irq.c */
diff --git a/arch/sh/include/mach-common/mach/titan.h b/arch/sh/include/mach-common/mach/titan.h
index 4a674d27cbb8..fa3cd801cf2e 100644
--- a/arch/sh/include/mach-common/mach/titan.h
+++ b/arch/sh/include/mach-common/mach/titan.h
@@ -4,14 +4,16 @@
#ifndef _ASM_SH_TITAN_H
#define _ASM_SH_TITAN_H
+#include <linux/sh_intc.h>
+
#define __IO_PREFIX titan
#include <asm/io_generic.h>
/* IRQ assignments */
-#define TITAN_IRQ_WAN 2 /* eth0 (WAN) */
-#define TITAN_IRQ_LAN 5 /* eth1 (LAN) */
-#define TITAN_IRQ_MPCIA 8 /* mPCI A */
-#define TITAN_IRQ_MPCIB 11 /* mPCI B */
-#define TITAN_IRQ_USB 11 /* USB */
+#define TITAN_IRQ_WAN evt2irq(0x240) /* eth0 (WAN) */
+#define TITAN_IRQ_LAN evt2irq(0x2a0) /* eth1 (LAN) */
+#define TITAN_IRQ_MPCIA evt2irq(0x300) /* mPCI A */
+#define TITAN_IRQ_MPCIB evt2irq(0x360) /* mPCI B */
+#define TITAN_IRQ_USB evt2irq(0x360) /* USB */
#endif /* __ASM_SH_TITAN_H */
diff --git a/arch/sh/include/mach-dreamcast/mach/dma.h b/arch/sh/include/mach-dreamcast/mach/dma.h
index ddd68e788705..1dbfdf701c9d 100644
--- a/arch/sh/include/mach-dreamcast/mach/dma.h
+++ b/arch/sh/include/mach-dreamcast/mach/dma.h
@@ -11,9 +11,7 @@
#define __ASM_SH_DREAMCAST_DMA_H
/* Number of DMA channels */
-#define ONCHIP_NR_DMA_CHANNELS 4
#define G2_NR_DMA_CHANNELS 4
-#define PVR2_NR_DMA_CHANNELS 1
/* Channels for cascading */
#define PVR2_CASCADE_CHAN 2
diff --git a/arch/sh/include/mach-landisk/mach/iodata_landisk.h b/arch/sh/include/mach-landisk/mach/iodata_landisk.h
index f432773a9571..ceeea48cc7af 100644
--- a/arch/sh/include/mach-landisk/mach/iodata_landisk.h
+++ b/arch/sh/include/mach-landisk/mach/iodata_landisk.h
@@ -8,6 +8,7 @@
*
* IO-DATA LANDISK support
*/
+#include <linux/sh_intc.h>
/* Box specific addresses. */
@@ -25,15 +26,15 @@
#define PA_PIDE_OFFSET 0x40 /* CF IDE Offset */
#define PA_SIDE_OFFSET 0x40 /* HDD IDE Offset */
-#define IRQ_PCIINTA 5 /* PCI INTA IRQ */
-#define IRQ_PCIINTB 6 /* PCI INTB IRQ */
-#define IRQ_PCIINTC 7 /* PCI INTC IRQ */
-#define IRQ_PCIINTD 8 /* PCI INTD IRQ */
-#define IRQ_ATA 9 /* ATA IRQ */
-#define IRQ_FATA 10 /* FATA IRQ */
-#define IRQ_POWER 11 /* Power Switch IRQ */
-#define IRQ_BUTTON 12 /* USL-5P Button IRQ */
-#define IRQ_FAULT 13 /* USL-5P Fault IRQ */
+#define IRQ_PCIINTA evt2irq(0x2a0) /* PCI INTA IRQ */
+#define IRQ_PCIINTB evt2irq(0x2c0) /* PCI INTB IRQ */
+#define IRQ_PCIINTC evt2irq(0x2e0) /* PCI INTC IRQ */
+#define IRQ_PCIINTD evt2irq(0x300) /* PCI INTD IRQ */
+#define IRQ_ATA evt2irq(0x320) /* ATA IRQ */
+#define IRQ_FATA evt2irq(0x340) /* FATA IRQ */
+#define IRQ_POWER evt2irq(0x360) /* Power Switch IRQ */
+#define IRQ_BUTTON evt2irq(0x380) /* USL-5P Button IRQ */
+#define IRQ_FAULT evt2irq(0x3a0) /* USL-5P Fault IRQ */
void init_landisk_IRQ(void);
diff --git a/arch/sh/include/mach-se/mach/se.h b/arch/sh/include/mach-se/mach/se.h
index 14be91c5a2f0..8a6d44b4987b 100644
--- a/arch/sh/include/mach-se/mach/se.h
+++ b/arch/sh/include/mach-se/mach/se.h
@@ -8,6 +8,7 @@
*
* Hitachi SolutionEngine support
*/
+#include <linux/sh_intc.h>
/* Box specific addresses. */
@@ -82,16 +83,16 @@
#define INTC_IPRD 0xa4000018UL
#define INTC_IPRE 0xa400001aUL
-#define IRQ0_IRQ 32
-#define IRQ1_IRQ 33
+#define IRQ0_IRQ evt2irq(0x600)
+#define IRQ1_IRQ evt2irq(0x620)
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7705)
-#define IRQ_STNIC 12
-#define IRQ_CFCARD 14
+#define IRQ_STNIC evt2irq(0x380)
+#define IRQ_CFCARD evt2irq(0x3c0)
#else
-#define IRQ_STNIC 10
-#define IRQ_CFCARD 7
+#define IRQ_STNIC evt2irq(0x340)
+#define IRQ_CFCARD evt2irq(0x2e0)
#endif
/* SH Ether support (SH7710/SH7712) */
@@ -105,9 +106,9 @@
# define PHY_ID 0x01
#endif
/* Ether IRQ */
-#define SH_ETH0_IRQ 80
-#define SH_ETH1_IRQ 81
-#define SH_TSU_IRQ 82
+#define SH_ETH0_IRQ evt2irq(0xc00)
+#define SH_ETH1_IRQ evt2irq(0xc20)
+#define SH_TSU_IRQ evt2irq(0xc40)
void init_se_IRQ(void);
diff --git a/arch/sh/include/mach-se/mach/se7343.h b/arch/sh/include/mach-se/mach/se7343.h
index 8d8170d6cc43..50b5d575dff0 100644
--- a/arch/sh/include/mach-se/mach/se7343.h
+++ b/arch/sh/include/mach-se/mach/se7343.h
@@ -8,6 +8,7 @@
*
* SH-Mobile SolutionEngine 7343 support
*/
+#include <linux/sh_intc.h>
/* Box specific addresses. */
@@ -118,10 +119,10 @@
#define FPGA_IN 0xb1400000
#define FPGA_OUT 0xb1400002
-#define IRQ0_IRQ 32
-#define IRQ1_IRQ 33
-#define IRQ4_IRQ 36
-#define IRQ5_IRQ 37
+#define IRQ0_IRQ evt2irq(0x600)
+#define IRQ1_IRQ evt2irq(0x620)
+#define IRQ4_IRQ evt2irq(0x680)
+#define IRQ5_IRQ evt2irq(0x6a0)
#define SE7343_FPGA_IRQ_MRSHPC0 0
#define SE7343_FPGA_IRQ_MRSHPC1 1
diff --git a/arch/sh/include/mach-se/mach/se7721.h b/arch/sh/include/mach-se/mach/se7721.h
index b957f6041193..eabd0538de44 100644
--- a/arch/sh/include/mach-se/mach/se7721.h
+++ b/arch/sh/include/mach-se/mach/se7721.h
@@ -11,6 +11,8 @@
#ifndef __ASM_SH_SE7721_H
#define __ASM_SH_SE7721_H
+
+#include <linux/sh_intc.h>
#include <asm/addrspace.h>
/* Box specific addresses. */
@@ -49,9 +51,9 @@
#define MRSHPC_PCIC_INFO (PA_MRSHPC + 30)
#define PA_LED 0xB6800000 /* 8bit LED */
-#define PA_FPGA 0xB7000000 /* FPGA base address */
+#define PA_FPGA 0xB7000000 /* FPGA base address */
-#define MRSHPC_IRQ0 10
+#define MRSHPC_IRQ0 evt2irq(0x340)
#define FPGA_ILSR1 (PA_FPGA + 0x02)
#define FPGA_ILSR2 (PA_FPGA + 0x03)
diff --git a/arch/sh/include/mach-se/mach/se7722.h b/arch/sh/include/mach-se/mach/se7722.h
index 16505bfb8a9e..201081ebdbce 100644
--- a/arch/sh/include/mach-se/mach/se7722.h
+++ b/arch/sh/include/mach-se/mach/se7722.h
@@ -13,6 +13,7 @@
* for more details.
*
*/
+#include <linux/sh_intc.h>
#include <asm/addrspace.h>
/* Box specific addresses. */
@@ -31,7 +32,7 @@
#define PA_PERIPHERAL 0xB0000000
-#define PA_PCIC PA_PERIPHERAL /* MR-SHPC-01 PCMCIA */
+#define PA_PCIC PA_PERIPHERAL /* MR-SHPC-01 PCMCIA */
#define PA_MRSHPC (PA_PERIPHERAL + 0x003fffe0) /* MR-SHPC-01 PCMCIA controller */
#define PA_MRSHPC_MW1 (PA_PERIPHERAL + 0x00400000) /* MR-SHPC-01 memory window base */
#define PA_MRSHPC_MW2 (PA_PERIPHERAL + 0x00500000) /* MR-SHPC-01 attribute window base */
@@ -51,7 +52,7 @@
#define MRSHPC_PCIC_INFO (PA_MRSHPC + 30)
#define PA_LED (PA_PERIPHERAL + 0x00800000) /* 8bit LED */
-#define PA_FPGA (PA_PERIPHERAL + 0x01800000) /* FPGA base address */
+#define PA_FPGA (PA_PERIPHERAL + 0x01800000) /* FPGA base address */
#define PA_LAN (PA_AREA6_IO + 0) /* SMC LAN91C111 */
/* GPIO */
@@ -77,8 +78,8 @@
#define PORT_HIZCRC 0xA405015CUL
/* IRQ */
-#define IRQ0_IRQ 32
-#define IRQ1_IRQ 33
+#define IRQ0_IRQ evt2irq(0x600)
+#define IRQ1_IRQ evt2irq(0x620)
#define IRQ01_MODE 0xb1800000
#define IRQ01_STS 0xb1800004
diff --git a/arch/sh/include/mach-se/mach/se7724.h b/arch/sh/include/mach-se/mach/se7724.h
index 29514a39d0f5..be842dd1ca02 100644
--- a/arch/sh/include/mach-se/mach/se7724.h
+++ b/arch/sh/include/mach-se/mach/se7724.h
@@ -18,6 +18,7 @@
* for more details.
*
*/
+#include <linux/sh_intc.h>
#include <asm/addrspace.h>
/* SH Eth */
@@ -35,9 +36,9 @@
#define IRQ2_MR (0xba200028)
/* IRQ */
-#define IRQ0_IRQ 32
-#define IRQ1_IRQ 33
-#define IRQ2_IRQ 34
+#define IRQ0_IRQ evt2irq(0x600)
+#define IRQ1_IRQ evt2irq(0x620)
+#define IRQ2_IRQ evt2irq(0x640)
/* Bits in IRQ012 registers */
#define SE7724_FPGA_IRQ_BASE 220
diff --git a/arch/sh/include/mach-se/mach/se7751.h b/arch/sh/include/mach-se/mach/se7751.h
index b36792ac5d66..271871793d59 100644
--- a/arch/sh/include/mach-se/mach/se7751.h
+++ b/arch/sh/include/mach-se/mach/se7751.h
@@ -11,6 +11,7 @@
* Modified for 7751 Solution Engine by
* Ian da Silva and Jeremy Siegel, 2001.
*/
+#include <linux/sh_intc.h>
/* Box specific addresses. */
@@ -63,7 +64,7 @@
#define BCR_ILCRF (PA_BCR + 10)
#define BCR_ILCRG (PA_BCR + 12)
-#define IRQ_79C973 13
+#define IRQ_79C973 evt2irq(0x3a0)
void init_7751se_IRQ(void);
diff --git a/arch/sh/include/mach-se/mach/se7780.h b/arch/sh/include/mach-se/mach/se7780.h
index 40e9b41458cd..bde357cf81bd 100644
--- a/arch/sh/include/mach-se/mach/se7780.h
+++ b/arch/sh/include/mach-se/mach/se7780.h
@@ -12,6 +12,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
+#include <linux/sh_intc.h>
#include <asm/addrspace.h>
/* Box specific addresses. */
@@ -80,13 +81,13 @@
#define IRQPOS_PCCPW (0 * 4)
/* IDE interrupt */
-#define IRQ_IDE0 67 /* iVDR */
+#define IRQ_IDE0 evt2irq(0xa60) /* iVDR */
/* SMC interrupt */
-#define SMC_IRQ 8
+#define SMC_IRQ evt2irq(0x300)
/* SM501 interrupt */
-#define SM501_IRQ 0
+#define SM501_IRQ evt2irq(0x200)
/* interrupt pin */
#define IRQPIN_EXTINT1 0 /* IRQ0 pin */
diff --git a/arch/sh/kernel/cpu/proc.c b/arch/sh/kernel/cpu/proc.c
index f47be8727b3b..9e6624c9108b 100644
--- a/arch/sh/kernel/cpu/proc.c
+++ b/arch/sh/kernel/cpu/proc.c
@@ -7,6 +7,7 @@
static const char *cpu_name[] = {
[CPU_SH7201] = "SH7201",
[CPU_SH7203] = "SH7203", [CPU_SH7263] = "SH7263",
+ [CPU_SH7264] = "SH7264", [CPU_SH7269] = "SH7269",
[CPU_SH7206] = "SH7206", [CPU_SH7619] = "SH7619",
[CPU_SH7705] = "SH7705", [CPU_SH7706] = "SH7706",
[CPU_SH7707] = "SH7707", [CPU_SH7708] = "SH7708",
@@ -25,7 +26,8 @@ static const char *cpu_name[] = {
[CPU_SH5_101] = "SH5-101", [CPU_SH5_103] = "SH5-103",
[CPU_MXG] = "MX-G", [CPU_SH7723] = "SH7723",
[CPU_SH7366] = "SH7366", [CPU_SH7724] = "SH7724",
- [CPU_SH7372] = "SH7372", [CPU_SH_NONE] = "Unknown"
+ [CPU_SH7372] = "SH7372", [CPU_SH7734] = "SH7734",
+ [CPU_SH_NONE] = "Unknown"
};
const char *get_cpu_subtype(struct sh_cpuinfo *c)
diff --git a/arch/sh/kernel/cpu/sh2/setup-sh7619.c b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
index 0f8befccf9fa..e0b740c831c7 100644
--- a/arch/sh/kernel/cpu/sh2/setup-sh7619.c
+++ b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
@@ -65,7 +65,7 @@ static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 88, 88, 88, 88 },
+ .irqs = SCIx_IRQ_MUXED(88),
};
static struct platform_device scif0_device = {
@@ -82,7 +82,7 @@ static struct plat_sci_port scif1_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 92, 92, 92, 92 },
+ .irqs = SCIx_IRQ_MUXED(92),
};
static struct platform_device scif1_device = {
@@ -99,7 +99,7 @@ static struct plat_sci_port scif2_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 96, 96, 96, 96 },
+ .irqs = SCIx_IRQ_MUXED(96),
};
static struct platform_device scif2_device = {
diff --git a/arch/sh/kernel/cpu/sh2a/Makefile b/arch/sh/kernel/cpu/sh2a/Makefile
index 45f85c77ef75..7fdc102d0dd6 100644
--- a/arch/sh/kernel/cpu/sh2a/Makefile
+++ b/arch/sh/kernel/cpu/sh2a/Makefile
@@ -11,10 +11,14 @@ obj-$(CONFIG_SH_FPU) += fpu.o
obj-$(CONFIG_CPU_SUBTYPE_SH7201) += setup-sh7201.o clock-sh7201.o
obj-$(CONFIG_CPU_SUBTYPE_SH7203) += setup-sh7203.o clock-sh7203.o
obj-$(CONFIG_CPU_SUBTYPE_SH7263) += setup-sh7203.o clock-sh7203.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7264) += setup-sh7264.o clock-sh7264.o
obj-$(CONFIG_CPU_SUBTYPE_SH7206) += setup-sh7206.o clock-sh7206.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7269) += setup-sh7269.o clock-sh7269.o
obj-$(CONFIG_CPU_SUBTYPE_MXG) += setup-mxg.o clock-sh7206.o
# Pinmux setup
pinmux-$(CONFIG_CPU_SUBTYPE_SH7203) := pinmux-sh7203.o
+pinmux-$(CONFIG_CPU_SUBTYPE_SH7264) := pinmux-sh7264.o
+pinmux-$(CONFIG_CPU_SUBTYPE_SH7269) := pinmux-sh7269.o
obj-$(CONFIG_GENERIC_GPIO) += $(pinmux-y)
diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7264.c b/arch/sh/kernel/cpu/sh2a/clock-sh7264.c
new file mode 100644
index 000000000000..fdf585c95289
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/clock-sh7264.c
@@ -0,0 +1,153 @@
+/*
+ * arch/sh/kernel/cpu/sh2a/clock-sh7264.c
+ *
+ * SH7264 clock framework support
+ *
+ * Copyright (C) 2012 Phil Edworthy
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/clkdev.h>
+#include <asm/clock.h>
+
+/* SH7264 registers */
+#define FRQCR 0xfffe0010
+#define STBCR3 0xfffe0408
+#define STBCR4 0xfffe040c
+#define STBCR5 0xfffe0410
+#define STBCR6 0xfffe0414
+#define STBCR7 0xfffe0418
+#define STBCR8 0xfffe041c
+
+static const unsigned int pll1rate[] = {8, 12};
+
+static unsigned int pll1_div;
+
+/* Fixed 32 KHz root clock for RTC */
+static struct clk r_clk = {
+ .rate = 32768,
+};
+
+/*
+ * Default rate for the root input clock, reset this with clk_set_rate()
+ * from the platform code.
+ */
+static struct clk extal_clk = {
+ .rate = 18000000,
+};
+
+static unsigned long pll_recalc(struct clk *clk)
+{
+ unsigned long rate = clk->parent->rate / pll1_div;
+ return rate * pll1rate[(__raw_readw(FRQCR) >> 8) & 1];
+}
+
+static struct sh_clk_ops pll_clk_ops = {
+ .recalc = pll_recalc,
+};
+
+static struct clk pll_clk = {
+ .ops = &pll_clk_ops,
+ .parent = &extal_clk,
+ .flags = CLK_ENABLE_ON_INIT,
+};
+
+struct clk *main_clks[] = {
+ &r_clk,
+ &extal_clk,
+ &pll_clk,
+};
+
+static int div2[] = { 1, 2, 3, 4, 6, 8, 12 };
+
+static struct clk_div_mult_table div4_div_mult_table = {
+ .divisors = div2,
+ .nr_divisors = ARRAY_SIZE(div2),
+};
+
+static struct clk_div4_table div4_table = {
+ .div_mult_table = &div4_div_mult_table,
+};
+
+enum { DIV4_I, DIV4_P,
+ DIV4_NR };
+
+#define DIV4(_reg, _bit, _mask, _flags) \
+ SH_CLK_DIV4(&pll_clk, _reg, _bit, _mask, _flags)
+
+/* The mask field specifies the div2 entries that are valid */
+struct clk div4_clks[DIV4_NR] = {
+ [DIV4_I] = DIV4(FRQCR, 4, 0x7, CLK_ENABLE_REG_16BIT
+ | CLK_ENABLE_ON_INIT),
+ [DIV4_P] = DIV4(FRQCR, 0, 0x78, CLK_ENABLE_REG_16BIT),
+};
+
+enum { MSTP77, MSTP74, MSTP72,
+ MSTP60,
+ MSTP35, MSTP34, MSTP33, MSTP32, MSTP30,
+ MSTP_NR };
+
+static struct clk mstp_clks[MSTP_NR] = {
+ [MSTP77] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR7, 7, 0), /* SCIF */
+ [MSTP74] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR7, 4, 0), /* VDC */
+ [MSTP72] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR7, 2, 0), /* CMT */
+ [MSTP60] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR6, 0, 0), /* USB */
+ [MSTP35] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR3, 6, 0), /* MTU2 */
+ [MSTP34] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR3, 4, 0), /* SDHI0 */
+ [MSTP33] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR3, 3, 0), /* SDHI1 */
+ [MSTP32] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR3, 2, 0), /* ADC */
+ [MSTP30] = SH_CLK_MSTP8(&r_clk, STBCR3, 0, 0), /* RTC */
+};
+
+static struct clk_lookup lookups[] = {
+ /* main clocks */
+ CLKDEV_CON_ID("rclk", &r_clk),
+ CLKDEV_CON_ID("extal", &extal_clk),
+ CLKDEV_CON_ID("pll_clk", &pll_clk),
+
+ /* DIV4 clocks */
+ CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
+ CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
+
+ /* MSTP clocks */
+ CLKDEV_CON_ID("sci_ick", &mstp_clks[MSTP77]),
+ CLKDEV_CON_ID("vdc3", &mstp_clks[MSTP74]),
+ CLKDEV_CON_ID("cmt_fck", &mstp_clks[MSTP72]),
+ CLKDEV_CON_ID("usb0", &mstp_clks[MSTP60]),
+ CLKDEV_CON_ID("mtu2_fck", &mstp_clks[MSTP35]),
+ CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP34]),
+ CLKDEV_CON_ID("sdhi1", &mstp_clks[MSTP33]),
+ CLKDEV_CON_ID("adc0", &mstp_clks[MSTP32]),
+ CLKDEV_CON_ID("rtc0", &mstp_clks[MSTP30]),
+};
+
+int __init arch_clk_init(void)
+{
+ int k, ret = 0;
+
+ if (test_mode_pin(MODE_PIN0)) {
+ if (test_mode_pin(MODE_PIN1))
+ pll1_div = 3;
+ else
+ pll1_div = 4;
+ } else
+ pll1_div = 1;
+
+ for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
+ ret = clk_register(main_clks[k]);
+
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+
+ if (!ret)
+ ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
+
+ if (!ret)
+ ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
+
+ return ret;
+}
diff --git a/arch/sh/kernel/cpu/sh2a/clock-sh7269.c b/arch/sh/kernel/cpu/sh2a/clock-sh7269.c
new file mode 100644
index 000000000000..6b787620de99
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/clock-sh7269.c
@@ -0,0 +1,184 @@
+/*
+ * arch/sh/kernel/cpu/sh2a/clock-sh7269.c
+ *
+ * SH7269 clock framework support
+ *
+ * Copyright (C) 2012 Phil Edworthy
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/clkdev.h>
+#include <asm/clock.h>
+
+/* SH7269 registers */
+#define FRQCR 0xfffe0010
+#define STBCR3 0xfffe0408
+#define STBCR4 0xfffe040c
+#define STBCR5 0xfffe0410
+#define STBCR6 0xfffe0414
+#define STBCR7 0xfffe0418
+
+#define PLL_RATE 20
+
+/* Fixed 32 KHz root clock for RTC */
+static struct clk r_clk = {
+ .rate = 32768,
+};
+
+/*
+ * Default rate for the root input clock, reset this with clk_set_rate()
+ * from the platform code.
+ */
+static struct clk extal_clk = {
+ .rate = 13340000,
+};
+
+static unsigned long pll_recalc(struct clk *clk)
+{
+ return clk->parent->rate * PLL_RATE;
+}
+
+static struct sh_clk_ops pll_clk_ops = {
+ .recalc = pll_recalc,
+};
+
+static struct clk pll_clk = {
+ .ops = &pll_clk_ops,
+ .parent = &extal_clk,
+ .flags = CLK_ENABLE_ON_INIT,
+};
+
+static unsigned long peripheral0_recalc(struct clk *clk)
+{
+ return clk->parent->rate / 8;
+}
+
+static struct sh_clk_ops peripheral0_clk_ops = {
+ .recalc = peripheral0_recalc,
+};
+
+static struct clk peripheral0_clk = {
+ .ops = &peripheral0_clk_ops,
+ .parent = &pll_clk,
+ .flags = CLK_ENABLE_ON_INIT,
+};
+
+static unsigned long peripheral1_recalc(struct clk *clk)
+{
+ return clk->parent->rate / 4;
+}
+
+static struct sh_clk_ops peripheral1_clk_ops = {
+ .recalc = peripheral1_recalc,
+};
+
+static struct clk peripheral1_clk = {
+ .ops = &peripheral1_clk_ops,
+ .parent = &pll_clk,
+ .flags = CLK_ENABLE_ON_INIT,
+};
+
+struct clk *main_clks[] = {
+ &r_clk,
+ &extal_clk,
+ &pll_clk,
+ &peripheral0_clk,
+ &peripheral1_clk,
+};
+
+static int div2[] = { 1, 2, 0, 4 };
+
+static struct clk_div_mult_table div4_div_mult_table = {
+ .divisors = div2,
+ .nr_divisors = ARRAY_SIZE(div2),
+};
+
+static struct clk_div4_table div4_table = {
+ .div_mult_table = &div4_div_mult_table,
+};
+
+enum { DIV4_I, DIV4_B,
+ DIV4_NR };
+
+#define DIV4(_reg, _bit, _mask, _flags) \
+ SH_CLK_DIV4(&pll_clk, _reg, _bit, _mask, _flags)
+
+/* The mask field specifies the div2 entries that are valid */
+struct clk div4_clks[DIV4_NR] = {
+ [DIV4_I] = DIV4(FRQCR, 8, 0xB, CLK_ENABLE_REG_16BIT
+ | CLK_ENABLE_ON_INIT),
+ [DIV4_B] = DIV4(FRQCR, 4, 0xA, CLK_ENABLE_REG_16BIT
+ | CLK_ENABLE_ON_INIT),
+};
+
+enum { MSTP72,
+ MSTP60,
+ MSTP47, MSTP46, MSTP45, MSTP44, MSTP43, MSTP42, MSTP41, MSTP40,
+ MSTP35, MSTP32, MSTP30,
+ MSTP_NR };
+
+static struct clk mstp_clks[MSTP_NR] = {
+ [MSTP72] = SH_CLK_MSTP8(&peripheral0_clk, STBCR7, 2, 0), /* CMT */
+ [MSTP60] = SH_CLK_MSTP8(&peripheral1_clk, STBCR6, 0, 0), /* USB */
+ [MSTP47] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 7, 0), /* SCIF0 */
+ [MSTP46] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 6, 0), /* SCIF1 */
+ [MSTP45] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 5, 0), /* SCIF2 */
+ [MSTP44] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 4, 0), /* SCIF3 */
+ [MSTP43] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 3, 0), /* SCIF4 */
+ [MSTP42] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 2, 0), /* SCIF5 */
+ [MSTP41] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 1, 0), /* SCIF6 */
+ [MSTP40] = SH_CLK_MSTP8(&peripheral1_clk, STBCR4, 0, 0), /* SCIF7 */
+ [MSTP35] = SH_CLK_MSTP8(&peripheral0_clk, STBCR3, 5, 0), /* MTU2 */
+ [MSTP32] = SH_CLK_MSTP8(&peripheral1_clk, STBCR3, 2, 0), /* ADC */
+ [MSTP30] = SH_CLK_MSTP8(&r_clk, STBCR3, 0, 0), /* RTC */
+};
+
+static struct clk_lookup lookups[] = {
+ /* main clocks */
+ CLKDEV_CON_ID("rclk", &r_clk),
+ CLKDEV_CON_ID("extal", &extal_clk),
+ CLKDEV_CON_ID("pll_clk", &pll_clk),
+ CLKDEV_CON_ID("peripheral_clk", &peripheral1_clk),
+
+ /* DIV4 clocks */
+ CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
+ CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
+
+ /* MSTP clocks */
+ CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP47]),
+ CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP46]),
+ CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP45]),
+ CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP44]),
+ CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP43]),
+ CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP42]),
+ CLKDEV_ICK_ID("sci_fck", "sh-sci.6", &mstp_clks[MSTP41]),
+ CLKDEV_ICK_ID("sci_fck", "sh-sci.7", &mstp_clks[MSTP40]),
+ CLKDEV_CON_ID("cmt_fck", &mstp_clks[MSTP72]),
+ CLKDEV_CON_ID("usb0", &mstp_clks[MSTP60]),
+ CLKDEV_CON_ID("mtu2_fck", &mstp_clks[MSTP35]),
+ CLKDEV_CON_ID("adc0", &mstp_clks[MSTP32]),
+ CLKDEV_CON_ID("rtc0", &mstp_clks[MSTP30]),
+};
+
+int __init arch_clk_init(void)
+{
+ int k, ret = 0;
+
+ for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
+ ret = clk_register(main_clks[k]);
+
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+
+ if (!ret)
+ ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
+
+ if (!ret)
+ ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
+
+ return ret;
+}
diff --git a/arch/sh/kernel/cpu/sh2a/pinmux-sh7264.c b/arch/sh/kernel/cpu/sh2a/pinmux-sh7264.c
new file mode 100644
index 000000000000..b055b55d6f27
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/pinmux-sh7264.c
@@ -0,0 +1,2136 @@
+/*
+ * SH7264 Pinmux
+ *
+ * Copyright (C) 2012 Renesas Electronics Europe Ltd
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <cpu/sh7264.h>
+
+enum {
+ PINMUX_RESERVED = 0,
+
+ PINMUX_DATA_BEGIN,
+ /* Port A */
+ PA3_DATA, PA2_DATA, PA1_DATA, PA0_DATA,
+ /* Port B */
+ PB22_DATA, PB21_DATA, PB20_DATA,
+ PB19_DATA, PB18_DATA, PB17_DATA, PB16_DATA,
+ PB15_DATA, PB14_DATA, PB13_DATA, PB12_DATA,
+ PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
+ PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+ PB3_DATA, PB2_DATA, PB1_DATA,
+ /* Port C */
+ PC10_DATA, PC9_DATA, PC8_DATA,
+ PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+ PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
+ /* Port D */
+ PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
+ PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
+ PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+ PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA,
+ /* Port E */
+ PE5_DATA, PE4_DATA,
+ PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
+ /* Port F */
+ PF12_DATA,
+ PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
+ PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+ PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA,
+ /* Port G */
+ PG24_DATA,
+ PG23_DATA, PG22_DATA, PG21_DATA, PG20_DATA,
+ PG19_DATA, PG18_DATA, PG17_DATA, PG16_DATA,
+ PG15_DATA, PG14_DATA, PG13_DATA, PG12_DATA,
+ PG11_DATA, PG10_DATA, PG9_DATA, PG8_DATA,
+ PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+ PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
+ /* Port H */
+ /* NOTE - Port H does not have a Data Register, but PH Data is
+ connected to PH Port Register */
+ PH7_DATA, PH6_DATA, PH5_DATA, PH4_DATA,
+ PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA,
+ /* Port I - not on device */
+ /* Port J */
+ PJ12_DATA,
+ PJ11_DATA, PJ10_DATA, PJ9_DATA, PJ8_DATA,
+ PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
+ PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA,
+ /* Port K */
+ PK12_DATA,
+ PK11_DATA, PK10_DATA, PK9_DATA, PK8_DATA,
+ PK7_DATA, PK6_DATA, PK5_DATA, PK4_DATA,
+ PK3_DATA, PK2_DATA, PK1_DATA, PK0_DATA,
+ PINMUX_DATA_END,
+
+ PINMUX_INPUT_BEGIN,
+ FORCE_IN,
+ /* Port A */
+ PA3_IN, PA2_IN, PA1_IN, PA0_IN,
+ /* Port B */
+ PB22_IN, PB21_IN, PB20_IN,
+ PB19_IN, PB18_IN, PB17_IN, PB16_IN,
+ PB15_IN, PB14_IN, PB13_IN, PB12_IN,
+ PB11_IN, PB10_IN, PB9_IN, PB8_IN,
+ PB7_IN, PB6_IN, PB5_IN, PB4_IN,
+ PB3_IN, PB2_IN, PB1_IN,
+ /* Port C */
+ PC10_IN, PC9_IN, PC8_IN,
+ PC7_IN, PC6_IN, PC5_IN, PC4_IN,
+ PC3_IN, PC2_IN, PC1_IN, PC0_IN,
+ /* Port D */
+ PD15_IN, PD14_IN, PD13_IN, PD12_IN,
+ PD11_IN, PD10_IN, PD9_IN, PD8_IN,
+ PD7_IN, PD6_IN, PD5_IN, PD4_IN,
+ PD3_IN, PD2_IN, PD1_IN, PD0_IN,
+ /* Port E */
+ PE5_IN, PE4_IN,
+ PE3_IN, PE2_IN, PE1_IN, PE0_IN,
+ /* Port F */
+ PF12_IN,
+ PF11_IN, PF10_IN, PF9_IN, PF8_IN,
+ PF7_IN, PF6_IN, PF5_IN, PF4_IN,
+ PF3_IN, PF2_IN, PF1_IN, PF0_IN,
+ /* Port G */
+ PG24_IN,
+ PG23_IN, PG22_IN, PG21_IN, PG20_IN,
+ PG19_IN, PG18_IN, PG17_IN, PG16_IN,
+ PG15_IN, PG14_IN, PG13_IN, PG12_IN,
+ PG11_IN, PG10_IN, PG9_IN, PG8_IN,
+ PG7_IN, PG6_IN, PG5_IN, PG4_IN,
+ PG3_IN, PG2_IN, PG1_IN, PG0_IN,
+ /* Port H - Port H does not have a Data Register */
+ /* Port I - not on device */
+ /* Port J */
+ PJ12_IN,
+ PJ11_IN, PJ10_IN, PJ9_IN, PJ8_IN,
+ PJ7_IN, PJ6_IN, PJ5_IN, PJ4_IN,
+ PJ3_IN, PJ2_IN, PJ1_IN, PJ0_IN,
+ /* Port K */
+ PK12_IN,
+ PK11_IN, PK10_IN, PK9_IN, PK8_IN,
+ PK7_IN, PK6_IN, PK5_IN, PK4_IN,
+ PK3_IN, PK2_IN, PK1_IN, PK0_IN,
+ PINMUX_INPUT_END,
+
+ PINMUX_OUTPUT_BEGIN,
+ FORCE_OUT,
+ /* Port A */
+ PA3_OUT, PA2_OUT, PA1_OUT, PA0_OUT,
+ /* Port B */
+ PB22_OUT, PB21_OUT, PB20_OUT,
+ PB19_OUT, PB18_OUT, PB17_OUT, PB16_OUT,
+ PB15_OUT, PB14_OUT, PB13_OUT, PB12_OUT,
+ PB11_OUT, PB10_OUT, PB9_OUT, PB8_OUT,
+ PB7_OUT, PB6_OUT, PB5_OUT, PB4_OUT,
+ PB3_OUT, PB2_OUT, PB1_OUT,
+ /* Port C */
+ PC10_OUT, PC9_OUT, PC8_OUT,
+ PC7_OUT, PC6_OUT, PC5_OUT, PC4_OUT,
+ PC3_OUT, PC2_OUT, PC1_OUT, PC0_OUT,
+ /* Port D */
+ PD15_OUT, PD14_OUT, PD13_OUT, PD12_OUT,
+ PD11_OUT, PD10_OUT, PD9_OUT, PD8_OUT,
+ PD7_OUT, PD6_OUT, PD5_OUT, PD4_OUT,
+ PD3_OUT, PD2_OUT, PD1_OUT, PD0_OUT,
+ /* Port E */
+ PE5_OUT, PE4_OUT,
+ PE3_OUT, PE2_OUT, PE1_OUT, PE0_OUT,
+ /* Port F */
+ PF12_OUT,
+ PF11_OUT, PF10_OUT, PF9_OUT, PF8_OUT,
+ PF7_OUT, PF6_OUT, PF5_OUT, PF4_OUT,
+ PF3_OUT, PF2_OUT, PF1_OUT, PF0_OUT,
+ /* Port G */
+ PG24_OUT,
+ PG23_OUT, PG22_OUT, PG21_OUT, PG20_OUT,
+ PG19_OUT, PG18_OUT, PG17_OUT, PG16_OUT,
+ PG15_OUT, PG14_OUT, PG13_OUT, PG12_OUT,
+ PG11_OUT, PG10_OUT, PG9_OUT, PG8_OUT,
+ PG7_OUT, PG6_OUT, PG5_OUT, PG4_OUT,
+ PG3_OUT, PG2_OUT, PG1_OUT, PG0_OUT,
+ /* Port H - Port H does not have a Data Register */
+ /* Port I - not on device */
+ /* Port J */
+ PJ12_OUT,
+ PJ11_OUT, PJ10_OUT, PJ9_OUT, PJ8_OUT,
+ PJ7_OUT, PJ6_OUT, PJ5_OUT, PJ4_OUT,
+ PJ3_OUT, PJ2_OUT, PJ1_OUT, PJ0_OUT,
+ /* Port K */
+ PK12_OUT,
+ PK11_OUT, PK10_OUT, PK9_OUT, PK8_OUT,
+ PK7_OUT, PK6_OUT, PK5_OUT, PK4_OUT,
+ PK3_OUT, PK2_OUT, PK1_OUT, PK0_OUT,
+ PINMUX_OUTPUT_END,
+
+ PINMUX_FUNCTION_BEGIN,
+ /* Port A */
+ PA3_IOR_IN, PA3_IOR_OUT,
+ PA2_IOR_IN, PA2_IOR_OUT,
+ PA1_IOR_IN, PA1_IOR_OUT,
+ PA0_IOR_IN, PA0_IOR_OUT,
+
+ /* Port B */
+ PB11_IOR_IN, PB11_IOR_OUT,
+ PB10_IOR_IN, PB10_IOR_OUT,
+ PB9_IOR_IN, PB9_IOR_OUT,
+ PB8_IOR_IN, PB8_IOR_OUT,
+
+ PB22MD_00, PB22MD_01, PB22MD_10,
+ PB21MD_0, PB21MD_1,
+ PB20MD_0, PB20MD_1,
+ PB19MD_00, PB19MD_01, PB19MD_10, PB19MD_11,
+ PB18MD_00, PB18MD_01, PB18MD_10, PB18MD_11,
+ PB17MD_00, PB17MD_01, PB17MD_10, PB17MD_11,
+ PB16MD_00, PB16MD_01, PB16MD_10, PB16MD_11,
+ PB15MD_00, PB15MD_01, PB15MD_10, PB15MD_11,
+ PB14MD_00, PB14MD_01, PB14MD_10, PB14MD_11,
+ PB13MD_00, PB13MD_01, PB13MD_10, PB13MD_11,
+ PB12MD_00, PB12MD_01, PB12MD_10, PB12MD_11,
+ PB11MD_00, PB11MD_01, PB11MD_10, PB11MD_11,
+ PB10MD_00, PB10MD_01, PB10MD_10, PB10MD_11,
+ PB9MD_00, PB9MD_01, PB9MD_10, PB9MD_11,
+ PB8MD_00, PB8MD_01, PB8MD_10, PB8MD_11,
+ PB7MD_00, PB7MD_01, PB7MD_10, PB7MD_11,
+ PB6MD_00, PB6MD_01, PB6MD_10, PB6MD_11,
+ PB5MD_00, PB5MD_01, PB5MD_10, PB5MD_11,
+ PB4MD_00, PB4MD_01, PB4MD_10, PB4MD_11,
+ PB3MD_0, PB3MD_1,
+ PB2MD_0, PB2MD_1,
+ PB1MD_0, PB1MD_1,
+
+ /* Port C */
+ PC14_IOR_IN, PC14_IOR_OUT,
+ PC13_IOR_IN, PC13_IOR_OUT,
+ PC12_IOR_IN, PC12_IOR_OUT,
+ PC11_IOR_IN, PC11_IOR_OUT,
+ PC10_IOR_IN, PC10_IOR_OUT,
+ PC9_IOR_IN, PC9_IOR_OUT,
+ PC8_IOR_IN, PC8_IOR_OUT,
+ PC7_IOR_IN, PC7_IOR_OUT,
+ PC6_IOR_IN, PC6_IOR_OUT,
+ PC5_IOR_IN, PC5_IOR_OUT,
+ PC4_IOR_IN, PC4_IOR_OUT,
+ PC3_IOR_IN, PC3_IOR_OUT,
+ PC2_IOR_IN, PC2_IOR_OUT,
+ PC1_IOR_IN, PC1_IOR_OUT,
+ PC0_IOR_IN, PC0_IOR_OUT,
+
+ PC10MD_0, PC10MD_1,
+ PC9MD_0, PC9MD_1,
+ PC8MD_00, PC8MD_01, PC8MD_10, PC8MD_11,
+ PC7MD_00, PC7MD_01, PC7MD_10, PC7MD_11,
+ PC6MD_00, PC6MD_01, PC6MD_10, PC6MD_11,
+ PC5MD_00, PC5MD_01, PC5MD_10, PC5MD_11,
+ PC4MD_0, PC4MD_1,
+ PC3MD_0, PC3MD_1,
+ PC2MD_0, PC2MD_1,
+ PC1MD_0, PC1MD_1,
+ PC0MD_0, PC0MD_1,
+
+ /* Port D */
+ PD15_IOR_IN, PD15_IOR_OUT,
+ PD14_IOR_IN, PD14_IOR_OUT,
+ PD13_IOR_IN, PD13_IOR_OUT,
+ PD12_IOR_IN, PD12_IOR_OUT,
+ PD11_IOR_IN, PD11_IOR_OUT,
+ PD10_IOR_IN, PD10_IOR_OUT,
+ PD9_IOR_IN, PD9_IOR_OUT,
+ PD8_IOR_IN, PD8_IOR_OUT,
+ PD7_IOR_IN, PD7_IOR_OUT,
+ PD6_IOR_IN, PD6_IOR_OUT,
+ PD5_IOR_IN, PD5_IOR_OUT,
+ PD4_IOR_IN, PD4_IOR_OUT,
+ PD3_IOR_IN, PD3_IOR_OUT,
+ PD2_IOR_IN, PD2_IOR_OUT,
+ PD1_IOR_IN, PD1_IOR_OUT,
+ PD0_IOR_IN, PD0_IOR_OUT,
+
+ PD15MD_00, PD15MD_01, PD15MD_10, PD15MD_11,
+ PD14MD_00, PD14MD_01, PD14MD_10, PD14MD_11,
+ PD13MD_00, PD13MD_01, PD13MD_10, PD13MD_11,
+ PD12MD_00, PD12MD_01, PD12MD_10, PD12MD_11,
+ PD11MD_00, PD11MD_01, PD11MD_10, PD11MD_11,
+ PD10MD_00, PD10MD_01, PD10MD_10, PD10MD_11,
+ PD9MD_00, PD9MD_01, PD9MD_10, PD9MD_11,
+ PD8MD_00, PD8MD_01, PD8MD_10, PD8MD_11,
+ PD7MD_00, PD7MD_01, PD7MD_10, PD7MD_11,
+ PD6MD_00, PD6MD_01, PD6MD_10, PD6MD_11,
+ PD5MD_00, PD5MD_01, PD5MD_10, PD5MD_11,
+ PD4MD_00, PD4MD_01, PD4MD_10, PD4MD_11,
+ PD3MD_00, PD3MD_01, PD3MD_10, PD3MD_11,
+ PD2MD_00, PD2MD_01, PD2MD_10, PD2MD_11,
+ PD1MD_00, PD1MD_01, PD1MD_10, PD1MD_11,
+ PD0MD_00, PD0MD_01, PD0MD_10, PD0MD_11,
+
+ /* Port E */
+ PE5_IOR_IN, PE5_IOR_OUT,
+ PE4_IOR_IN, PE4_IOR_OUT,
+ PE3_IOR_IN, PE3_IOR_OUT,
+ PE2_IOR_IN, PE2_IOR_OUT,
+ PE1_IOR_IN, PE1_IOR_OUT,
+ PE0_IOR_IN, PE0_IOR_OUT,
+
+ PE5MD_00, PE5MD_01, PE5MD_10, PE5MD_11,
+ PE4MD_00, PE4MD_01, PE4MD_10, PE4MD_11,
+ PE3MD_00, PE3MD_01, PE3MD_10, PE3MD_11,
+ PE2MD_00, PE2MD_01, PE2MD_10, PE2MD_11,
+ PE1MD_000, PE1MD_001, PE1MD_010, PE1MD_011,
+ PE1MD_100, PE1MD_101, PE1MD_110, PE1MD_111,
+ PE0MD_00, PE0MD_01, PE0MD_10, PE0MD_11,
+
+ /* Port F */
+ PF12_IOR_IN, PF12_IOR_OUT,
+ PF11_IOR_IN, PF11_IOR_OUT,
+ PF10_IOR_IN, PF10_IOR_OUT,
+ PF9_IOR_IN, PF9_IOR_OUT,
+ PF8_IOR_IN, PF8_IOR_OUT,
+ PF7_IOR_IN, PF7_IOR_OUT,
+ PF6_IOR_IN, PF6_IOR_OUT,
+ PF5_IOR_IN, PF5_IOR_OUT,
+ PF4_IOR_IN, PF4_IOR_OUT,
+ PF3_IOR_IN, PF3_IOR_OUT,
+ PF2_IOR_IN, PF2_IOR_OUT,
+ PF1_IOR_IN, PF1_IOR_OUT,
+ PF0_IOR_IN, PF0_IOR_OUT,
+
+ PF12MD_000, PF12MD_001, PF12MD_010, PF12MD_011,
+ PF12MD_100, PF12MD_101, PF12MD_110, PF12MD_111,
+ PF11MD_000, PF11MD_001, PF11MD_010, PF11MD_011,
+ PF11MD_100, PF11MD_101, PF11MD_110, PF11MD_111,
+ PF10MD_000, PF10MD_001, PF10MD_010, PF10MD_011,
+ PF10MD_100, PF10MD_101, PF10MD_110, PF10MD_111,
+ PF9MD_000, PF9MD_001, PF9MD_010, PF9MD_011,
+ PF9MD_100, PF9MD_101, PF9MD_110, PF9MD_111,
+ PF8MD_00, PF8MD_01, PF8MD_10, PF8MD_11,
+ PF7MD_000, PF7MD_001, PF7MD_010, PF7MD_011,
+ PF7MD_100, PF7MD_101, PF7MD_110, PF7MD_111,
+ PF6MD_000, PF6MD_001, PF6MD_010, PF6MD_011,
+ PF6MD_100, PF6MD_101, PF6MD_110, PF6MD_111,
+ PF5MD_000, PF5MD_001, PF5MD_010, PF5MD_011,
+ PF5MD_100, PF5MD_101, PF5MD_110, PF5MD_111,
+ PF4MD_000, PF4MD_001, PF4MD_010, PF4MD_011,
+ PF4MD_100, PF4MD_101, PF4MD_110, PF4MD_111,
+ PF3MD_000, PF3MD_001, PF3MD_010, PF3MD_011,
+ PF3MD_100, PF3MD_101, PF3MD_110, PF3MD_111,
+ PF2MD_000, PF2MD_001, PF2MD_010, PF2MD_011,
+ PF2MD_100, PF2MD_101, PF2MD_110, PF2MD_111,
+ PF1MD_000, PF1MD_001, PF1MD_010, PF1MD_011,
+ PF1MD_100, PF1MD_101, PF1MD_110, PF1MD_111,
+ PF0MD_000, PF0MD_001, PF0MD_010, PF0MD_011,
+ PF0MD_100, PF0MD_101, PF0MD_110, PF0MD_111,
+
+ /* Port G */
+ PG24_IOR_IN, PG24_IOR_OUT,
+ PG23_IOR_IN, PG23_IOR_OUT,
+ PG22_IOR_IN, PG22_IOR_OUT,
+ PG21_IOR_IN, PG21_IOR_OUT,
+ PG20_IOR_IN, PG20_IOR_OUT,
+ PG19_IOR_IN, PG19_IOR_OUT,
+ PG18_IOR_IN, PG18_IOR_OUT,
+ PG17_IOR_IN, PG17_IOR_OUT,
+ PG16_IOR_IN, PG16_IOR_OUT,
+ PG15_IOR_IN, PG15_IOR_OUT,
+ PG14_IOR_IN, PG14_IOR_OUT,
+ PG13_IOR_IN, PG13_IOR_OUT,
+ PG12_IOR_IN, PG12_IOR_OUT,
+ PG11_IOR_IN, PG11_IOR_OUT,
+ PG10_IOR_IN, PG10_IOR_OUT,
+ PG9_IOR_IN, PG9_IOR_OUT,
+ PG8_IOR_IN, PG8_IOR_OUT,
+ PG7_IOR_IN, PG7_IOR_OUT,
+ PG6_IOR_IN, PG6_IOR_OUT,
+ PG5_IOR_IN, PG5_IOR_OUT,
+ PG4_IOR_IN, PG4_IOR_OUT,
+ PG3_IOR_IN, PG3_IOR_OUT,
+ PG2_IOR_IN, PG2_IOR_OUT,
+ PG1_IOR_IN, PG1_IOR_OUT,
+ PG0_IOR_IN, PG0_IOR_OUT,
+
+ PG24MD_00, PG24MD_01, PG24MD_10, PG24MD_11,
+ PG23MD_00, PG23MD_01, PG23MD_10, PG23MD_11,
+ PG22MD_00, PG22MD_01, PG22MD_10, PG22MD_11,
+ PG21MD_00, PG21MD_01, PG21MD_10, PG21MD_11,
+ PG20MD_000, PG20MD_001, PG20MD_010, PG20MD_011,
+ PG20MD_100, PG20MD_101, PG20MD_110, PG20MD_111,
+ PG19MD_000, PG19MD_001, PG19MD_010, PG19MD_011,
+ PG19MD_100, PG19MD_101, PG19MD_110, PG19MD_111,
+ PG18MD_000, PG18MD_001, PG18MD_010, PG18MD_011,
+ PG18MD_100, PG18MD_101, PG18MD_110, PG18MD_111,
+ PG17MD_000, PG17MD_001, PG17MD_010, PG17MD_011,
+ PG17MD_100, PG17MD_101, PG17MD_110, PG17MD_111,
+ PG16MD_000, PG16MD_001, PG16MD_010, PG16MD_011,
+ PG16MD_100, PG16MD_101, PG16MD_110, PG16MD_111,
+ PG15MD_000, PG15MD_001, PG15MD_010, PG15MD_011,
+ PG15MD_100, PG15MD_101, PG15MD_110, PG15MD_111,
+ PG14MD_000, PG14MD_001, PG14MD_010, PG14MD_011,
+ PG14MD_100, PG14MD_101, PG14MD_110, PG14MD_111,
+ PG13MD_000, PG13MD_001, PG13MD_010, PG13MD_011,
+ PG13MD_100, PG13MD_101, PG13MD_110, PG13MD_111,
+ PG12MD_000, PG12MD_001, PG12MD_010, PG12MD_011,
+ PG12MD_100, PG12MD_101, PG12MD_110, PG12MD_111,
+ PG11MD_000, PG11MD_001, PG11MD_010, PG11MD_011,
+ PG11MD_100, PG11MD_101, PG11MD_110, PG11MD_111,
+ PG10MD_000, PG10MD_001, PG10MD_010, PG10MD_011,
+ PG10MD_100, PG10MD_101, PG10MD_110, PG10MD_111,
+ PG9MD_000, PG9MD_001, PG9MD_010, PG9MD_011,
+ PG9MD_100, PG9MD_101, PG9MD_110, PG9MD_111,
+ PG8MD_000, PG8MD_001, PG8MD_010, PG8MD_011,
+ PG8MD_100, PG8MD_101, PG8MD_110, PG8MD_111,
+ PG7MD_00, PG7MD_01, PG7MD_10, PG7MD_11,
+ PG6MD_00, PG6MD_01, PG6MD_10, PG6MD_11,
+ PG5MD_00, PG5MD_01, PG5MD_10, PG5MD_11,
+ PG4MD_00, PG4MD_01, PG4MD_10, PG4MD_11,
+ PG3MD_00, PG3MD_01, PG3MD_10, PG3MD_11,
+ PG2MD_00, PG2MD_01, PG2MD_10, PG2MD_11,
+ PG1MD_00, PG1MD_01, PG1MD_10, PG1MD_11,
+ PG0MD_000, PG0MD_001, PG0MD_010, PG0MD_011,
+ PG0MD_100, PG0MD_101, PG0MD_110, PG0MD_111,
+
+ /* Port H */
+ PH7MD_0, PH7MD_1,
+ PH6MD_0, PH6MD_1,
+ PH5MD_0, PH5MD_1,
+ PH4MD_0, PH4MD_1,
+ PH3MD_0, PH3MD_1,
+ PH2MD_0, PH2MD_1,
+ PH1MD_0, PH1MD_1,
+ PH0MD_0, PH0MD_1,
+
+ /* Port I - not on device */
+
+ /* Port J */
+ PJ11_IOR_IN, PJ11_IOR_OUT,
+ PJ10_IOR_IN, PJ10_IOR_OUT,
+ PJ9_IOR_IN, PJ9_IOR_OUT,
+ PJ8_IOR_IN, PJ8_IOR_OUT,
+ PJ7_IOR_IN, PJ7_IOR_OUT,
+ PJ6_IOR_IN, PJ6_IOR_OUT,
+ PJ5_IOR_IN, PJ5_IOR_OUT,
+ PJ4_IOR_IN, PJ4_IOR_OUT,
+ PJ3_IOR_IN, PJ3_IOR_OUT,
+ PJ2_IOR_IN, PJ2_IOR_OUT,
+ PJ1_IOR_IN, PJ1_IOR_OUT,
+ PJ0_IOR_IN, PJ0_IOR_OUT,
+
+ PJ11MD_00, PJ11MD_01, PJ11MD_10, PJ11MD_11,
+ PJ10MD_00, PJ10MD_01, PJ10MD_10, PJ10MD_11,
+ PJ9MD_00, PJ9MD_01, PJ9MD_10, PJ9MD_11,
+ PJ8MD_00, PJ8MD_01, PJ8MD_10, PJ8MD_11,
+ PJ7MD_00, PJ7MD_01, PJ7MD_10, PJ7MD_11,
+ PJ6MD_00, PJ6MD_01, PJ6MD_10, PJ6MD_11,
+ PJ5MD_00, PJ5MD_01, PJ5MD_10, PJ5MD_11,
+ PJ4MD_00, PJ4MD_01, PJ4MD_10, PJ4MD_11,
+ PJ3MD_00, PJ3MD_01, PJ3MD_10, PJ3MD_11,
+ PJ2MD_000, PJ2MD_001, PJ2MD_010, PJ2MD_011,
+ PJ2MD_100, PJ2MD_101, PJ2MD_110, PJ2MD_111,
+ PJ1MD_000, PJ1MD_001, PJ1MD_010, PJ1MD_011,
+ PJ1MD_100, PJ1MD_101, PJ1MD_110, PJ1MD_111,
+ PJ0MD_000, PJ0MD_001, PJ0MD_010, PJ0MD_011,
+ PJ0MD_100, PJ0MD_101, PJ0MD_110, PJ0MD_111,
+
+ /* Port K */
+ PK11_IOR_IN, PK11_IOR_OUT,
+ PK10_IOR_IN, PK10_IOR_OUT,
+ PK9_IOR_IN, PK9_IOR_OUT,
+ PK8_IOR_IN, PK8_IOR_OUT,
+ PK7_IOR_IN, PK7_IOR_OUT,
+ PK6_IOR_IN, PK6_IOR_OUT,
+ PK5_IOR_IN, PK5_IOR_OUT,
+ PK4_IOR_IN, PK4_IOR_OUT,
+ PK3_IOR_IN, PK3_IOR_OUT,
+ PK2_IOR_IN, PK2_IOR_OUT,
+ PK1_IOR_IN, PK1_IOR_OUT,
+ PK0_IOR_IN, PK0_IOR_OUT,
+
+ PK11MD_00, PK11MD_01, PK11MD_10, PK11MD_11,
+ PK10MD_00, PK10MD_01, PK10MD_10, PK10MD_11,
+ PK9MD_00, PK9MD_01, PK9MD_10, PK9MD_11,
+ PK8MD_00, PK8MD_01, PK8MD_10, PK8MD_11,
+ PK7MD_00, PK7MD_01, PK7MD_10, PK7MD_11,
+ PK6MD_00, PK6MD_01, PK6MD_10, PK6MD_11,
+ PK5MD_00, PK5MD_01, PK5MD_10, PK5MD_11,
+ PK4MD_00, PK4MD_01, PK4MD_10, PK4MD_11,
+ PK3MD_00, PK3MD_01, PK3MD_10, PK3MD_11,
+ PK2MD_00, PK2MD_01, PK2MD_10, PK2MD_11,
+ PK1MD_00, PK1MD_01, PK1MD_10, PK1MD_11,
+ PK0MD_00, PK0MD_01, PK0MD_10, PK0MD_11,
+ PINMUX_FUNCTION_END,
+
+ PINMUX_MARK_BEGIN,
+ /* Port A */
+
+ /* Port B */
+
+ /* Port C */
+
+ /* Port D */
+
+ /* Port E */
+
+ /* Port F */
+
+ /* Port G */
+
+ /* Port H */
+ PHAN7_MARK, PHAN6_MARK, PHAN5_MARK, PHAN4_MARK,
+ PHAN3_MARK, PHAN2_MARK, PHAN1_MARK, PHAN0_MARK,
+
+ /* Port I - not on device */
+
+ /* Port J */
+
+ /* Port K */
+
+ IRQ7_PC_MARK, IRQ6_PC_MARK, IRQ5_PC_MARK, IRQ4_PC_MARK,
+ IRQ3_PG_MARK, IRQ2_PG_MARK, IRQ1_PJ_MARK, IRQ0_PJ_MARK,
+ IRQ3_PE_MARK, IRQ2_PE_MARK, IRQ1_PE_MARK, IRQ0_PE_MARK,
+
+ PINT7_PG_MARK, PINT6_PG_MARK, PINT5_PG_MARK, PINT4_PG_MARK,
+ PINT3_PG_MARK, PINT2_PG_MARK, PINT1_PG_MARK, PINT0_PG_MARK,
+
+ SD_CD_MARK, SD_D0_MARK, SD_D1_MARK, SD_D2_MARK, SD_D3_MARK,
+ SD_WP_MARK, SD_CLK_MARK, SD_CMD_MARK,
+ CRX0_MARK, CRX1_MARK,
+ CTX0_MARK, CTX1_MARK,
+
+ PWM1A_MARK, PWM1B_MARK, PWM1C_MARK, PWM1D_MARK,
+ PWM1E_MARK, PWM1F_MARK, PWM1G_MARK, PWM1H_MARK,
+ PWM2A_MARK, PWM2B_MARK, PWM2C_MARK, PWM2D_MARK,
+ PWM2E_MARK, PWM2F_MARK, PWM2G_MARK, PWM2H_MARK,
+ IERXD_MARK, IETXD_MARK,
+ CRX0CRX1_MARK,
+ WDTOVF_MARK,
+
+ CRX0X1_MARK,
+
+ /* DMAC */
+ TEND0_MARK, DACK0_MARK, DREQ0_MARK,
+ TEND1_MARK, DACK1_MARK, DREQ1_MARK,
+
+ /* ADC */
+ ADTRG_MARK,
+
+ /* BSC */
+ A25_MARK, A24_MARK,
+ A23_MARK, A22_MARK, A21_MARK, A20_MARK,
+ A19_MARK, A18_MARK, A17_MARK, A16_MARK,
+ A15_MARK, A14_MARK, A13_MARK, A12_MARK,
+ A11_MARK, A10_MARK, A9_MARK, A8_MARK,
+ A7_MARK, A6_MARK, A5_MARK, A4_MARK,
+ A3_MARK, A2_MARK, A1_MARK, A0_MARK,
+ D15_MARK, D14_MARK, D13_MARK, D12_MARK,
+ D11_MARK, D10_MARK, D9_MARK, D8_MARK,
+ D7_MARK, D6_MARK, D5_MARK, D4_MARK,
+ D3_MARK, D2_MARK, D1_MARK, D0_MARK,
+ BS_MARK,
+ CS4_MARK, CS3_MARK, CS2_MARK, CS1_MARK, CS0_MARK,
+ CS6CE1B_MARK, CS5CE1A_MARK,
+ CE2A_MARK, CE2B_MARK,
+ RD_MARK, RDWR_MARK,
+ ICIOWRAH_MARK,
+ ICIORD_MARK,
+ WE1DQMUWE_MARK,
+ WE0DQML_MARK,
+ RAS_MARK, CAS_MARK, CKE_MARK,
+ WAIT_MARK, BREQ_MARK, BACK_MARK, IOIS16_MARK,
+
+ /* TMU */
+ TIOC0A_MARK, TIOC0B_MARK, TIOC0C_MARK, TIOC0D_MARK,
+ TIOC1A_MARK, TIOC1B_MARK,
+ TIOC2A_MARK, TIOC2B_MARK,
+ TIOC3A_MARK, TIOC3B_MARK, TIOC3C_MARK, TIOC3D_MARK,
+ TIOC4A_MARK, TIOC4B_MARK, TIOC4C_MARK, TIOC4D_MARK,
+ TCLKA_MARK, TCLKB_MARK, TCLKC_MARK, TCLKD_MARK,
+
+ /* SCIF */
+ SCK0_MARK, SCK1_MARK, SCK2_MARK, SCK3_MARK,
+ RXD0_MARK, RXD1_MARK, RXD2_MARK, RXD3_MARK,
+ TXD0_MARK, TXD1_MARK, TXD2_MARK, TXD3_MARK,
+ RXD4_MARK, RXD5_MARK, RXD6_MARK, RXD7_MARK,
+ TXD4_MARK, TXD5_MARK, TXD6_MARK, TXD7_MARK,
+ RTS1_MARK, RTS3_MARK,
+ CTS1_MARK, CTS3_MARK,
+
+ /* RSPI */
+ RSPCK0_MARK, RSPCK1_MARK,
+ MOSI0_MARK, MOSI1_MARK,
+ MISO0_PF12_MARK, MISO1_MARK, MISO1_PG19_MARK,
+ SSL00_MARK, SSL10_MARK,
+
+ /* IIC3 */
+ SCL0_MARK, SCL1_MARK, SCL2_MARK,
+ SDA0_MARK, SDA1_MARK, SDA2_MARK,
+
+ /* SSI */
+ SSISCK0_MARK,
+ SSIWS0_MARK,
+ SSITXD0_MARK,
+ SSIRXD0_MARK,
+ SSIWS1_MARK, SSIWS2_MARK, SSIWS3_MARK,
+ SSISCK1_MARK, SSISCK2_MARK, SSISCK3_MARK,
+ SSIDATA1_MARK, SSIDATA2_MARK, SSIDATA3_MARK,
+ AUDIO_CLK_MARK,
+
+ /* SIOF */ /* NOTE Shares AUDIO_CLK with SSI */
+ SIOFTXD_MARK, SIOFRXD_MARK, SIOFSYNC_MARK, SIOFSCK_MARK,
+
+ /* SPDIF */ /* NOTE Shares AUDIO_CLK with SSI */
+ SPDIF_IN_MARK, SPDIF_OUT_MARK,
+
+ /* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
+ FCE_MARK,
+ FRB_MARK,
+
+ /* VDC3 */
+ DV_CLK_MARK,
+ DV_VSYNC_MARK, DV_HSYNC_MARK,
+ DV_DATA7_MARK, DV_DATA6_MARK, DV_DATA5_MARK, DV_DATA4_MARK,
+ DV_DATA3_MARK, DV_DATA2_MARK, DV_DATA1_MARK, DV_DATA0_MARK,
+ LCD_CLK_MARK, LCD_EXTCLK_MARK,
+ LCD_VSYNC_MARK, LCD_HSYNC_MARK, LCD_DE_MARK,
+ LCD_DATA15_MARK, LCD_DATA14_MARK, LCD_DATA13_MARK, LCD_DATA12_MARK,
+ LCD_DATA11_MARK, LCD_DATA10_MARK, LCD_DATA9_MARK, LCD_DATA8_MARK,
+ LCD_DATA7_MARK, LCD_DATA6_MARK, LCD_DATA5_MARK, LCD_DATA4_MARK,
+ LCD_DATA3_MARK, LCD_DATA2_MARK, LCD_DATA1_MARK, LCD_DATA0_MARK,
+ LCD_M_DISP_MARK,
+ PINMUX_MARK_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+
+ /* Port A */
+ PINMUX_DATA(PA3_DATA, PA3_IN),
+ PINMUX_DATA(PA2_DATA, PA2_IN),
+ PINMUX_DATA(PA1_DATA, PA1_IN),
+ PINMUX_DATA(PA0_DATA, PA0_IN),
+
+ /* Port B */
+ PINMUX_DATA(PB22_DATA, PB22MD_00, PB22_IN, PB22_OUT),
+ PINMUX_DATA(A22_MARK, PB22MD_01),
+ PINMUX_DATA(CS4_MARK, PB22MD_10),
+
+ PINMUX_DATA(PB21_DATA, PB21MD_0, PB21_IN, PB21_OUT),
+ PINMUX_DATA(A21_MARK, PB21MD_1),
+ PINMUX_DATA(A20_MARK, PB20MD_1),
+ PINMUX_DATA(A19_MARK, PB19MD_01),
+ PINMUX_DATA(A18_MARK, PB18MD_01),
+ PINMUX_DATA(A17_MARK, PB17MD_01),
+ PINMUX_DATA(A16_MARK, PB16MD_01),
+ PINMUX_DATA(A15_MARK, PB15MD_01),
+ PINMUX_DATA(A14_MARK, PB14MD_01),
+ PINMUX_DATA(A13_MARK, PB13MD_01),
+ PINMUX_DATA(A12_MARK, PB12MD_01),
+ PINMUX_DATA(A11_MARK, PB11MD_01),
+ PINMUX_DATA(A10_MARK, PB10MD_01),
+ PINMUX_DATA(A9_MARK, PB9MD_01),
+ PINMUX_DATA(A8_MARK, PB8MD_01),
+ PINMUX_DATA(A7_MARK, PB7MD_01),
+ PINMUX_DATA(A6_MARK, PB6MD_01),
+ PINMUX_DATA(A5_MARK, PB5MD_01),
+ PINMUX_DATA(A4_MARK, PB4MD_01),
+ PINMUX_DATA(A3_MARK, PB3MD_1),
+ PINMUX_DATA(A2_MARK, PB2MD_1),
+ PINMUX_DATA(A1_MARK, PB1MD_1),
+
+ /* Port C */
+ PINMUX_DATA(PC10_DATA, PC10MD_0),
+ PINMUX_DATA(TIOC2B_MARK, PC1MD_1),
+ PINMUX_DATA(PC9_DATA, PC9MD_0),
+ PINMUX_DATA(TIOC2A_MARK, PC9MD_1),
+ PINMUX_DATA(PC8_DATA, PC8MD_00),
+ PINMUX_DATA(CS3_MARK, PC8MD_01),
+ PINMUX_DATA(TIOC4D_MARK, PC8MD_10),
+ PINMUX_DATA(IRQ7_PC_MARK, PC8MD_11),
+ PINMUX_DATA(PC7_DATA, PC7MD_00),
+ PINMUX_DATA(CKE_MARK, PC7MD_01),
+ PINMUX_DATA(TIOC4C_MARK, PC7MD_10),
+ PINMUX_DATA(IRQ6_PC_MARK, PC7MD_11),
+ PINMUX_DATA(PC6_DATA, PC6MD_00),
+ PINMUX_DATA(CAS_MARK, PC6MD_01),
+ PINMUX_DATA(TIOC4B_MARK, PC6MD_10),
+ PINMUX_DATA(IRQ5_PC_MARK, PC6MD_11),
+ PINMUX_DATA(PC5_DATA, PC5MD_00),
+ PINMUX_DATA(RAS_MARK, PC5MD_01),
+ PINMUX_DATA(TIOC4A_MARK, PC5MD_10),
+ PINMUX_DATA(IRQ4_PC_MARK, PC5MD_11),
+ PINMUX_DATA(PC4_DATA, PC4MD_0),
+ PINMUX_DATA(WE1DQMUWE_MARK, PC4MD_1),
+ PINMUX_DATA(PC3_DATA, PC3MD_0),
+ PINMUX_DATA(WE0DQML_MARK, PC3MD_1),
+ PINMUX_DATA(PC2_DATA, PC2MD_0),
+ PINMUX_DATA(RDWR_MARK, PC2MD_1),
+ PINMUX_DATA(PC1_DATA, PC1MD_0),
+ PINMUX_DATA(RD_MARK, PC1MD_1),
+ PINMUX_DATA(PC0_DATA, PC0MD_0),
+ PINMUX_DATA(CS0_MARK, PC0MD_1),
+
+ /* Port D */
+ PINMUX_DATA(D15_MARK, PD15MD_01),
+ PINMUX_DATA(D14_MARK, PD14MD_01),
+ PINMUX_DATA(D13_MARK, PD13MD_01),
+ PINMUX_DATA(D12_MARK, PD12MD_01),
+ PINMUX_DATA(D11_MARK, PD11MD_01),
+ PINMUX_DATA(D10_MARK, PD10MD_01),
+ PINMUX_DATA(D9_MARK, PD9MD_01),
+ PINMUX_DATA(D8_MARK, PD8MD_01),
+ PINMUX_DATA(D7_MARK, PD7MD_01),
+ PINMUX_DATA(D6_MARK, PD6MD_01),
+ PINMUX_DATA(D5_MARK, PD5MD_01),
+ PINMUX_DATA(D4_MARK, PD4MD_01),
+ PINMUX_DATA(D3_MARK, PD3MD_01),
+ PINMUX_DATA(D2_MARK, PD2MD_01),
+ PINMUX_DATA(D1_MARK, PD1MD_01),
+ PINMUX_DATA(D0_MARK, PD0MD_01),
+
+ /* Port E */
+ PINMUX_DATA(PE5_DATA, PE5MD_00),
+ PINMUX_DATA(SDA2_MARK, PE5MD_01),
+ PINMUX_DATA(DV_HSYNC_MARK, PE5MD_11),
+
+ PINMUX_DATA(PE4_DATA, PE4MD_00),
+ PINMUX_DATA(SCL2_MARK, PE4MD_01),
+ PINMUX_DATA(DV_VSYNC_MARK, PE4MD_11),
+
+ PINMUX_DATA(PE3_DATA, PE3MD_00),
+ PINMUX_DATA(SDA1_MARK, PE3MD_01),
+ PINMUX_DATA(IRQ3_PE_MARK, PE3MD_11),
+
+ PINMUX_DATA(PE2_DATA, PE2MD_00),
+ PINMUX_DATA(SCL1_MARK, PE2MD_01),
+ PINMUX_DATA(IRQ2_PE_MARK, PE2MD_11),
+
+ PINMUX_DATA(PE1_DATA, PE1MD_000),
+ PINMUX_DATA(SDA0_MARK, PE1MD_001),
+ PINMUX_DATA(IOIS16_MARK, PE1MD_010),
+ PINMUX_DATA(IRQ1_PE_MARK, PE1MD_011),
+ PINMUX_DATA(TCLKA_MARK, PE1MD_100),
+ PINMUX_DATA(ADTRG_MARK, PE1MD_101),
+
+ PINMUX_DATA(PE0_DATA, PE0MD_00),
+ PINMUX_DATA(SCL0_MARK, PE0MD_01),
+ PINMUX_DATA(AUDIO_CLK_MARK, PE0MD_10),
+ PINMUX_DATA(IRQ0_PE_MARK, PE0MD_11),
+
+ /* Port F */
+ PINMUX_DATA(PF12_DATA, PF12MD_000),
+ PINMUX_DATA(BS_MARK, PF12MD_001),
+ PINMUX_DATA(MISO0_PF12_MARK, PF12MD_011),
+ PINMUX_DATA(TIOC3D_MARK, PF12MD_100),
+ PINMUX_DATA(SPDIF_OUT_MARK, PF12MD_101),
+
+ PINMUX_DATA(PF11_DATA, PF11MD_000),
+ PINMUX_DATA(A25_MARK, PF11MD_001),
+ PINMUX_DATA(SSIDATA3_MARK, PF11MD_010),
+ PINMUX_DATA(MOSI0_MARK, PF11MD_011),
+ PINMUX_DATA(TIOC3C_MARK, PF11MD_100),
+ PINMUX_DATA(SPDIF_IN_MARK, PF11MD_101),
+
+ PINMUX_DATA(PF10_DATA, PF10MD_000),
+ PINMUX_DATA(A24_MARK, PF10MD_001),
+ PINMUX_DATA(SSIWS3_MARK, PF10MD_010),
+ PINMUX_DATA(SSL00_MARK, PF10MD_011),
+ PINMUX_DATA(TIOC3B_MARK, PF10MD_100),
+ PINMUX_DATA(FCE_MARK, PF10MD_101),
+
+ PINMUX_DATA(PF9_DATA, PF9MD_000),
+ PINMUX_DATA(A23_MARK, PF9MD_001),
+ PINMUX_DATA(SSISCK3_MARK, PF9MD_010),
+ PINMUX_DATA(RSPCK0_MARK, PF9MD_011),
+ PINMUX_DATA(TIOC3A_MARK, PF9MD_100),
+ PINMUX_DATA(FRB_MARK, PF9MD_101),
+
+ PINMUX_DATA(PF8_DATA, PF8MD_00),
+ PINMUX_DATA(CE2B_MARK, PF8MD_01),
+ PINMUX_DATA(SSIDATA3_MARK, PF8MD_10),
+ PINMUX_DATA(DV_CLK_MARK, PF8MD_11),
+
+ PINMUX_DATA(PF7_DATA, PF7MD_000),
+ PINMUX_DATA(CE2A_MARK, PF7MD_001),
+ PINMUX_DATA(SSIWS3_MARK, PF7MD_010),
+ PINMUX_DATA(DV_DATA7_MARK, PF7MD_011),
+ PINMUX_DATA(TCLKD_MARK, PF7MD_100),
+
+ PINMUX_DATA(PF6_DATA, PF6MD_000),
+ PINMUX_DATA(CS6CE1B_MARK, PF6MD_001),
+ PINMUX_DATA(SSISCK3_MARK, PF6MD_010),
+ PINMUX_DATA(DV_DATA6_MARK, PF6MD_011),
+ PINMUX_DATA(TCLKB_MARK, PF6MD_100),
+
+ PINMUX_DATA(PF5_DATA, PF5MD_000),
+ PINMUX_DATA(CS5CE1A_MARK, PF5MD_001),
+ PINMUX_DATA(SSIDATA2_MARK, PF5MD_010),
+ PINMUX_DATA(DV_DATA5_MARK, PF5MD_011),
+ PINMUX_DATA(TCLKC_MARK, PF5MD_100),
+
+ PINMUX_DATA(PF4_DATA, PF4MD_000),
+ PINMUX_DATA(ICIOWRAH_MARK, PF4MD_001),
+ PINMUX_DATA(SSIWS2_MARK, PF4MD_010),
+ PINMUX_DATA(DV_DATA4_MARK, PF4MD_011),
+ PINMUX_DATA(TXD3_MARK, PF4MD_100),
+
+ PINMUX_DATA(PF3_DATA, PF3MD_000),
+ PINMUX_DATA(ICIORD_MARK, PF3MD_001),
+ PINMUX_DATA(SSISCK2_MARK, PF3MD_010),
+ PINMUX_DATA(DV_DATA3_MARK, PF3MD_011),
+ PINMUX_DATA(RXD3_MARK, PF3MD_100),
+
+ PINMUX_DATA(PF2_DATA, PF2MD_000),
+ PINMUX_DATA(BACK_MARK, PF2MD_001),
+ PINMUX_DATA(SSIDATA1_MARK, PF2MD_010),
+ PINMUX_DATA(DV_DATA2_MARK, PF2MD_011),
+ PINMUX_DATA(TXD2_MARK, PF2MD_100),
+ PINMUX_DATA(DACK0_MARK, PF2MD_101),
+
+ PINMUX_DATA(PF1_DATA, PF1MD_000),
+ PINMUX_DATA(BREQ_MARK, PF1MD_001),
+ PINMUX_DATA(SSIWS1_MARK, PF1MD_010),
+ PINMUX_DATA(DV_DATA1_MARK, PF1MD_011),
+ PINMUX_DATA(RXD2_MARK, PF1MD_100),
+ PINMUX_DATA(DREQ0_MARK, PF1MD_101),
+
+ PINMUX_DATA(PF0_DATA, PF0MD_000),
+ PINMUX_DATA(WAIT_MARK, PF0MD_001),
+ PINMUX_DATA(SSISCK1_MARK, PF0MD_010),
+ PINMUX_DATA(DV_DATA0_MARK, PF0MD_011),
+ PINMUX_DATA(SCK2_MARK, PF0MD_100),
+ PINMUX_DATA(TEND0_MARK, PF0MD_101),
+
+ /* Port G */
+ PINMUX_DATA(PG24_DATA, PG24MD_00),
+ PINMUX_DATA(MOSI0_MARK, PG24MD_01),
+ PINMUX_DATA(TIOC0D_MARK, PG24MD_10),
+
+ PINMUX_DATA(PG23_DATA, PG23MD_00),
+ PINMUX_DATA(MOSI1_MARK, PG23MD_01),
+ PINMUX_DATA(TIOC0C_MARK, PG23MD_10),
+
+ PINMUX_DATA(PG22_DATA, PG22MD_00),
+ PINMUX_DATA(SSL10_MARK, PG22MD_01),
+ PINMUX_DATA(TIOC0B_MARK, PG22MD_10),
+
+ PINMUX_DATA(PG21_DATA, PG21MD_00),
+ PINMUX_DATA(RSPCK1_MARK, PG21MD_01),
+ PINMUX_DATA(TIOC0A_MARK, PG21MD_10),
+
+ PINMUX_DATA(PG20_DATA, PG20MD_000),
+ PINMUX_DATA(LCD_EXTCLK_MARK, PG20MD_001),
+ PINMUX_DATA(MISO1_MARK, PG20MD_011),
+ PINMUX_DATA(TXD7_MARK, PG20MD_100),
+
+ PINMUX_DATA(PG19_DATA, PG19MD_000),
+ PINMUX_DATA(LCD_CLK_MARK, PG19MD_001),
+ PINMUX_DATA(TIOC2B_MARK, PG19MD_010),
+ PINMUX_DATA(MISO1_PG19_MARK, PG19MD_011),
+ PINMUX_DATA(RXD7_MARK, PG19MD_100),
+
+ PINMUX_DATA(PG18_DATA, PG18MD_000),
+ PINMUX_DATA(LCD_DE_MARK, PG18MD_001),
+ PINMUX_DATA(TIOC2A_MARK, PG18MD_010),
+ PINMUX_DATA(SSL10_MARK, PG18MD_011),
+ PINMUX_DATA(TXD6_MARK, PG18MD_100),
+
+ PINMUX_DATA(PG17_DATA, PG17MD_000),
+ PINMUX_DATA(LCD_HSYNC_MARK, PG17MD_001),
+ PINMUX_DATA(TIOC1B_MARK, PG17MD_010),
+ PINMUX_DATA(RSPCK1_MARK, PG17MD_011),
+ PINMUX_DATA(RXD6_MARK, PG17MD_100),
+
+ PINMUX_DATA(PG16_DATA, PG16MD_000),
+ PINMUX_DATA(LCD_VSYNC_MARK, PG16MD_001),
+ PINMUX_DATA(TIOC1A_MARK, PG16MD_010),
+ PINMUX_DATA(TXD3_MARK, PG16MD_011),
+ PINMUX_DATA(CTS1_MARK, PG16MD_100),
+
+ PINMUX_DATA(PG15_DATA, PG15MD_000),
+ PINMUX_DATA(LCD_DATA15_MARK, PG15MD_001),
+ PINMUX_DATA(TIOC0D_MARK, PG15MD_010),
+ PINMUX_DATA(RXD3_MARK, PG15MD_011),
+ PINMUX_DATA(RTS1_MARK, PG15MD_100),
+
+ PINMUX_DATA(PG14_DATA, PG14MD_000),
+ PINMUX_DATA(LCD_DATA14_MARK, PG14MD_001),
+ PINMUX_DATA(TIOC0C_MARK, PG14MD_010),
+ PINMUX_DATA(SCK1_MARK, PG14MD_100),
+
+ PINMUX_DATA(PG13_DATA, PG13MD_000),
+ PINMUX_DATA(LCD_DATA13_MARK, PG13MD_001),
+ PINMUX_DATA(TIOC0B_MARK, PG13MD_010),
+ PINMUX_DATA(TXD1_MARK, PG13MD_100),
+
+ PINMUX_DATA(PG12_DATA, PG12MD_000),
+ PINMUX_DATA(LCD_DATA12_MARK, PG12MD_001),
+ PINMUX_DATA(TIOC0A_MARK, PG12MD_010),
+ PINMUX_DATA(RXD1_MARK, PG12MD_100),
+
+ PINMUX_DATA(PG11_DATA, PG11MD_000),
+ PINMUX_DATA(LCD_DATA11_MARK, PG11MD_001),
+ PINMUX_DATA(SSITXD0_MARK, PG11MD_010),
+ PINMUX_DATA(IRQ3_PG_MARK, PG11MD_011),
+ PINMUX_DATA(TXD5_MARK, PG11MD_100),
+ PINMUX_DATA(SIOFTXD_MARK, PG11MD_101),
+
+ PINMUX_DATA(PG10_DATA, PG10MD_000),
+ PINMUX_DATA(LCD_DATA10_MARK, PG10MD_001),
+ PINMUX_DATA(SSIRXD0_MARK, PG10MD_010),
+ PINMUX_DATA(IRQ2_PG_MARK, PG10MD_011),
+ PINMUX_DATA(RXD5_MARK, PG10MD_100),
+ PINMUX_DATA(SIOFRXD_MARK, PG10MD_101),
+
+ PINMUX_DATA(PG9_DATA, PG9MD_000),
+ PINMUX_DATA(LCD_DATA9_MARK, PG9MD_001),
+ PINMUX_DATA(SSIWS0_MARK, PG9MD_010),
+ PINMUX_DATA(TXD4_MARK, PG9MD_100),
+ PINMUX_DATA(SIOFSYNC_MARK, PG9MD_101),
+
+ PINMUX_DATA(PG8_DATA, PG8MD_000),
+ PINMUX_DATA(LCD_DATA8_MARK, PG8MD_001),
+ PINMUX_DATA(SSISCK0_MARK, PG8MD_010),
+ PINMUX_DATA(RXD4_MARK, PG8MD_100),
+ PINMUX_DATA(SIOFSCK_MARK, PG8MD_101),
+
+ PINMUX_DATA(PG7_DATA, PG7MD_00),
+ PINMUX_DATA(LCD_DATA7_MARK, PG7MD_01),
+ PINMUX_DATA(SD_CD_MARK, PG7MD_10),
+ PINMUX_DATA(PINT7_PG_MARK, PG7MD_11),
+
+ PINMUX_DATA(PG6_DATA, PG7MD_00),
+ PINMUX_DATA(LCD_DATA6_MARK, PG7MD_01),
+ PINMUX_DATA(SD_WP_MARK, PG7MD_10),
+ PINMUX_DATA(PINT6_PG_MARK, PG7MD_11),
+
+ PINMUX_DATA(PG5_DATA, PG5MD_00),
+ PINMUX_DATA(LCD_DATA5_MARK, PG5MD_01),
+ PINMUX_DATA(SD_D1_MARK, PG5MD_10),
+ PINMUX_DATA(PINT5_PG_MARK, PG5MD_11),
+
+ PINMUX_DATA(PG4_DATA, PG4MD_00),
+ PINMUX_DATA(LCD_DATA4_MARK, PG4MD_01),
+ PINMUX_DATA(SD_D0_MARK, PG4MD_10),
+ PINMUX_DATA(PINT4_PG_MARK, PG4MD_11),
+
+ PINMUX_DATA(PG3_DATA, PG3MD_00),
+ PINMUX_DATA(LCD_DATA3_MARK, PG3MD_01),
+ PINMUX_DATA(SD_CLK_MARK, PG3MD_10),
+ PINMUX_DATA(PINT3_PG_MARK, PG3MD_11),
+
+ PINMUX_DATA(PG2_DATA, PG2MD_00),
+ PINMUX_DATA(LCD_DATA2_MARK, PG2MD_01),
+ PINMUX_DATA(SD_CMD_MARK, PG2MD_10),
+ PINMUX_DATA(PINT2_PG_MARK, PG2MD_11),
+
+ PINMUX_DATA(PG1_DATA, PG1MD_00),
+ PINMUX_DATA(LCD_DATA1_MARK, PG1MD_01),
+ PINMUX_DATA(SD_D3_MARK, PG1MD_10),
+ PINMUX_DATA(PINT1_PG_MARK, PG1MD_11),
+
+ PINMUX_DATA(PG0_DATA, PG0MD_000),
+ PINMUX_DATA(LCD_DATA0_MARK, PG0MD_001),
+ PINMUX_DATA(SD_D2_MARK, PG0MD_010),
+ PINMUX_DATA(PINT0_PG_MARK, PG0MD_011),
+ PINMUX_DATA(WDTOVF_MARK, PG0MD_100),
+
+ /* Port H */
+ PINMUX_DATA(PH7_DATA, PH7MD_0),
+ PINMUX_DATA(PHAN7_MARK, PH7MD_1),
+
+ PINMUX_DATA(PH6_DATA, PH6MD_0),
+ PINMUX_DATA(PHAN6_MARK, PH6MD_1),
+
+ PINMUX_DATA(PH5_DATA, PH5MD_0),
+ PINMUX_DATA(PHAN5_MARK, PH5MD_1),
+
+ PINMUX_DATA(PH4_DATA, PH4MD_0),
+ PINMUX_DATA(PHAN4_MARK, PH4MD_1),
+
+ PINMUX_DATA(PH3_DATA, PH3MD_0),
+ PINMUX_DATA(PHAN3_MARK, PH3MD_1),
+
+ PINMUX_DATA(PH2_DATA, PH2MD_0),
+ PINMUX_DATA(PHAN2_MARK, PH2MD_1),
+
+ PINMUX_DATA(PH1_DATA, PH1MD_0),
+ PINMUX_DATA(PHAN1_MARK, PH1MD_1),
+
+ PINMUX_DATA(PH0_DATA, PH0MD_0),
+ PINMUX_DATA(PHAN0_MARK, PH0MD_1),
+
+ /* Port I - not on device */
+
+ /* Port J */
+ PINMUX_DATA(PJ11_DATA, PJ11MD_00),
+ PINMUX_DATA(PWM2H_MARK, PJ11MD_01),
+ PINMUX_DATA(DACK1_MARK, PJ11MD_10),
+
+ PINMUX_DATA(PJ10_DATA, PJ10MD_00),
+ PINMUX_DATA(PWM2G_MARK, PJ10MD_01),
+ PINMUX_DATA(DREQ1_MARK, PJ10MD_10),
+
+ PINMUX_DATA(PJ9_DATA, PJ9MD_00),
+ PINMUX_DATA(PWM2F_MARK, PJ9MD_01),
+ PINMUX_DATA(TEND1_MARK, PJ9MD_10),
+
+ PINMUX_DATA(PJ8_DATA, PJ8MD_00),
+ PINMUX_DATA(PWM2E_MARK, PJ8MD_01),
+ PINMUX_DATA(RTS3_MARK, PJ8MD_10),
+
+ PINMUX_DATA(PJ7_DATA, PJ7MD_00),
+ PINMUX_DATA(TIOC1B_MARK, PJ7MD_01),
+ PINMUX_DATA(CTS3_MARK, PJ7MD_10),
+
+ PINMUX_DATA(PJ6_DATA, PJ6MD_00),
+ PINMUX_DATA(TIOC1A_MARK, PJ6MD_01),
+ PINMUX_DATA(SCK3_MARK, PJ6MD_10),
+
+ PINMUX_DATA(PJ5_DATA, PJ5MD_00),
+ PINMUX_DATA(IERXD_MARK, PJ5MD_01),
+ PINMUX_DATA(TXD3_MARK, PJ5MD_10),
+
+ PINMUX_DATA(PJ4_DATA, PJ4MD_00),
+ PINMUX_DATA(IETXD_MARK, PJ4MD_01),
+ PINMUX_DATA(RXD3_MARK, PJ4MD_10),
+
+ PINMUX_DATA(PJ3_DATA, PJ3MD_00),
+ PINMUX_DATA(CRX1_MARK, PJ3MD_01),
+ PINMUX_DATA(CRX0X1_MARK, PJ3MD_10),
+ PINMUX_DATA(IRQ1_PJ_MARK, PJ3MD_11),
+
+ PINMUX_DATA(PJ2_DATA, PJ2MD_000),
+ PINMUX_DATA(CTX1_MARK, PJ2MD_001),
+ PINMUX_DATA(CRX0CRX1_MARK, PJ2MD_010),
+ PINMUX_DATA(CS2_MARK, PJ2MD_011),
+ PINMUX_DATA(SCK0_MARK, PJ2MD_100),
+ PINMUX_DATA(LCD_M_DISP_MARK, PJ2MD_101),
+
+ PINMUX_DATA(PJ1_DATA, PJ1MD_000),
+ PINMUX_DATA(CRX0_MARK, PJ1MD_001),
+ PINMUX_DATA(IERXD_MARK, PJ1MD_010),
+ PINMUX_DATA(IRQ0_PJ_MARK, PJ1MD_011),
+ PINMUX_DATA(RXD0_MARK, PJ1MD_100),
+
+ PINMUX_DATA(PJ0_DATA, PJ0MD_000),
+ PINMUX_DATA(CTX0_MARK, PJ0MD_001),
+ PINMUX_DATA(IERXD_MARK, PJ0MD_010),
+ PINMUX_DATA(CS1_MARK, PJ0MD_011),
+ PINMUX_DATA(TXD0_MARK, PJ0MD_100),
+ PINMUX_DATA(A0_MARK, PJ0MD_101),
+
+ /* Port K */
+ PINMUX_DATA(PK11_DATA, PK11MD_00),
+ PINMUX_DATA(PWM2D_MARK, PK11MD_01),
+ PINMUX_DATA(SSITXD0_MARK, PK11MD_10),
+
+ PINMUX_DATA(PK10_DATA, PK10MD_00),
+ PINMUX_DATA(PWM2C_MARK, PK10MD_01),
+ PINMUX_DATA(SSIRXD0_MARK, PK10MD_10),
+
+ PINMUX_DATA(PK9_DATA, PK9MD_00),
+ PINMUX_DATA(PWM2B_MARK, PK9MD_01),
+ PINMUX_DATA(SSIWS0_MARK, PK9MD_10),
+
+ PINMUX_DATA(PK8_DATA, PK8MD_00),
+ PINMUX_DATA(PWM2A_MARK, PK8MD_01),
+ PINMUX_DATA(SSISCK0_MARK, PK8MD_10),
+
+ PINMUX_DATA(PK7_DATA, PK7MD_00),
+ PINMUX_DATA(PWM1H_MARK, PK7MD_01),
+ PINMUX_DATA(SD_CD_MARK, PK7MD_10),
+
+ PINMUX_DATA(PK6_DATA, PK6MD_00),
+ PINMUX_DATA(PWM1G_MARK, PK6MD_01),
+ PINMUX_DATA(SD_WP_MARK, PK6MD_10),
+
+ PINMUX_DATA(PK5_DATA, PK5MD_00),
+ PINMUX_DATA(PWM1F_MARK, PK5MD_01),
+ PINMUX_DATA(SD_D1_MARK, PK5MD_10),
+
+ PINMUX_DATA(PK4_DATA, PK4MD_00),
+ PINMUX_DATA(PWM1E_MARK, PK4MD_01),
+ PINMUX_DATA(SD_D0_MARK, PK4MD_10),
+
+ PINMUX_DATA(PK3_DATA, PK3MD_00),
+ PINMUX_DATA(PWM1D_MARK, PK3MD_01),
+ PINMUX_DATA(SD_CLK_MARK, PK3MD_10),
+
+ PINMUX_DATA(PK2_DATA, PK2MD_00),
+ PINMUX_DATA(PWM1C_MARK, PK2MD_01),
+ PINMUX_DATA(SD_CMD_MARK, PK2MD_10),
+
+ PINMUX_DATA(PK1_DATA, PK1MD_00),
+ PINMUX_DATA(PWM1B_MARK, PK1MD_01),
+ PINMUX_DATA(SD_D3_MARK, PK1MD_10),
+
+ PINMUX_DATA(PK0_DATA, PK0MD_00),
+ PINMUX_DATA(PWM1A_MARK, PK0MD_01),
+ PINMUX_DATA(SD_D2_MARK, PK0MD_10),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+
+ /* Port A */
+ PINMUX_GPIO(GPIO_PA3, PA3_DATA),
+ PINMUX_GPIO(GPIO_PA2, PA2_DATA),
+ PINMUX_GPIO(GPIO_PA1, PA1_DATA),
+ PINMUX_GPIO(GPIO_PA0, PA0_DATA),
+
+ /* Port B */
+ PINMUX_GPIO(GPIO_PB22, PB22_DATA),
+ PINMUX_GPIO(GPIO_PB21, PB21_DATA),
+ PINMUX_GPIO(GPIO_PB20, PB20_DATA),
+ PINMUX_GPIO(GPIO_PB19, PB19_DATA),
+ PINMUX_GPIO(GPIO_PB18, PB18_DATA),
+ PINMUX_GPIO(GPIO_PB17, PB17_DATA),
+ PINMUX_GPIO(GPIO_PB16, PB16_DATA),
+ PINMUX_GPIO(GPIO_PB15, PB15_DATA),
+ PINMUX_GPIO(GPIO_PB14, PB14_DATA),
+ PINMUX_GPIO(GPIO_PB13, PB13_DATA),
+ PINMUX_GPIO(GPIO_PB12, PB12_DATA),
+ PINMUX_GPIO(GPIO_PB11, PB11_DATA),
+ PINMUX_GPIO(GPIO_PB10, PB10_DATA),
+ PINMUX_GPIO(GPIO_PB9, PB9_DATA),
+ PINMUX_GPIO(GPIO_PB8, PB8_DATA),
+ PINMUX_GPIO(GPIO_PB7, PB7_DATA),
+ PINMUX_GPIO(GPIO_PB6, PB6_DATA),
+ PINMUX_GPIO(GPIO_PB5, PB5_DATA),
+ PINMUX_GPIO(GPIO_PB4, PB4_DATA),
+ PINMUX_GPIO(GPIO_PB3, PB3_DATA),
+ PINMUX_GPIO(GPIO_PB2, PB2_DATA),
+ PINMUX_GPIO(GPIO_PB1, PB1_DATA),
+
+ /* Port C */
+ PINMUX_GPIO(GPIO_PC10, PC10_DATA),
+ PINMUX_GPIO(GPIO_PC9, PC9_DATA),
+ PINMUX_GPIO(GPIO_PC8, PC8_DATA),
+ PINMUX_GPIO(GPIO_PC7, PC7_DATA),
+ PINMUX_GPIO(GPIO_PC6, PC6_DATA),
+ PINMUX_GPIO(GPIO_PC5, PC5_DATA),
+ PINMUX_GPIO(GPIO_PC4, PC4_DATA),
+ PINMUX_GPIO(GPIO_PC3, PC3_DATA),
+ PINMUX_GPIO(GPIO_PC2, PC2_DATA),
+ PINMUX_GPIO(GPIO_PC1, PC1_DATA),
+ PINMUX_GPIO(GPIO_PC0, PC0_DATA),
+
+ /* Port D */
+ PINMUX_GPIO(GPIO_PD15, PD15_DATA),
+ PINMUX_GPIO(GPIO_PD14, PD14_DATA),
+ PINMUX_GPIO(GPIO_PD13, PD13_DATA),
+ PINMUX_GPIO(GPIO_PD12, PD12_DATA),
+ PINMUX_GPIO(GPIO_PD11, PD11_DATA),
+ PINMUX_GPIO(GPIO_PD10, PD10_DATA),
+ PINMUX_GPIO(GPIO_PD9, PD9_DATA),
+ PINMUX_GPIO(GPIO_PD8, PD8_DATA),
+ PINMUX_GPIO(GPIO_PD7, PD7_DATA),
+ PINMUX_GPIO(GPIO_PD6, PD6_DATA),
+ PINMUX_GPIO(GPIO_PD5, PD5_DATA),
+ PINMUX_GPIO(GPIO_PD4, PD4_DATA),
+ PINMUX_GPIO(GPIO_PD3, PD3_DATA),
+ PINMUX_GPIO(GPIO_PD2, PD2_DATA),
+ PINMUX_GPIO(GPIO_PD1, PD1_DATA),
+ PINMUX_GPIO(GPIO_PD0, PD0_DATA),
+
+ /* Port E */
+ PINMUX_GPIO(GPIO_PE5, PE5_DATA),
+ PINMUX_GPIO(GPIO_PE4, PE4_DATA),
+ PINMUX_GPIO(GPIO_PE3, PE3_DATA),
+ PINMUX_GPIO(GPIO_PE2, PE2_DATA),
+ PINMUX_GPIO(GPIO_PE1, PE1_DATA),
+ PINMUX_GPIO(GPIO_PE0, PE0_DATA),
+
+ /* Port F */
+ PINMUX_GPIO(GPIO_PF12, PF12_DATA),
+ PINMUX_GPIO(GPIO_PF11, PF11_DATA),
+ PINMUX_GPIO(GPIO_PF10, PF10_DATA),
+ PINMUX_GPIO(GPIO_PF9, PF9_DATA),
+ PINMUX_GPIO(GPIO_PF8, PF8_DATA),
+ PINMUX_GPIO(GPIO_PF7, PF7_DATA),
+ PINMUX_GPIO(GPIO_PF6, PF6_DATA),
+ PINMUX_GPIO(GPIO_PF5, PF5_DATA),
+ PINMUX_GPIO(GPIO_PF4, PF4_DATA),
+ PINMUX_GPIO(GPIO_PF3, PF3_DATA),
+ PINMUX_GPIO(GPIO_PF2, PF2_DATA),
+ PINMUX_GPIO(GPIO_PF1, PF1_DATA),
+ PINMUX_GPIO(GPIO_PF0, PF0_DATA),
+
+ /* Port G */
+ PINMUX_GPIO(GPIO_PG24, PG24_DATA),
+ PINMUX_GPIO(GPIO_PG23, PG23_DATA),
+ PINMUX_GPIO(GPIO_PG22, PG22_DATA),
+ PINMUX_GPIO(GPIO_PG21, PG21_DATA),
+ PINMUX_GPIO(GPIO_PG20, PG20_DATA),
+ PINMUX_GPIO(GPIO_PG19, PG19_DATA),
+ PINMUX_GPIO(GPIO_PG18, PG18_DATA),
+ PINMUX_GPIO(GPIO_PG17, PG17_DATA),
+ PINMUX_GPIO(GPIO_PG16, PG16_DATA),
+ PINMUX_GPIO(GPIO_PG15, PG15_DATA),
+ PINMUX_GPIO(GPIO_PG14, PG14_DATA),
+ PINMUX_GPIO(GPIO_PG13, PG13_DATA),
+ PINMUX_GPIO(GPIO_PG12, PG12_DATA),
+ PINMUX_GPIO(GPIO_PG11, PG11_DATA),
+ PINMUX_GPIO(GPIO_PG10, PG10_DATA),
+ PINMUX_GPIO(GPIO_PG9, PG9_DATA),
+ PINMUX_GPIO(GPIO_PG8, PG8_DATA),
+ PINMUX_GPIO(GPIO_PG7, PG7_DATA),
+ PINMUX_GPIO(GPIO_PG6, PG6_DATA),
+ PINMUX_GPIO(GPIO_PG5, PG5_DATA),
+ PINMUX_GPIO(GPIO_PG4, PG4_DATA),
+ PINMUX_GPIO(GPIO_PG3, PG3_DATA),
+ PINMUX_GPIO(GPIO_PG2, PG2_DATA),
+ PINMUX_GPIO(GPIO_PG1, PG1_DATA),
+ PINMUX_GPIO(GPIO_PG0, PG0_DATA),
+
+ /* Port H - Port H does not have a Data Register */
+
+ /* Port I - not on device */
+
+ /* Port J */
+ PINMUX_GPIO(GPIO_PJ11, PJ11_DATA),
+ PINMUX_GPIO(GPIO_PJ10, PJ10_DATA),
+ PINMUX_GPIO(GPIO_PJ9, PJ9_DATA),
+ PINMUX_GPIO(GPIO_PJ8, PJ8_DATA),
+ PINMUX_GPIO(GPIO_PJ7, PJ7_DATA),
+ PINMUX_GPIO(GPIO_PJ6, PJ6_DATA),
+ PINMUX_GPIO(GPIO_PJ5, PJ5_DATA),
+ PINMUX_GPIO(GPIO_PJ4, PJ4_DATA),
+ PINMUX_GPIO(GPIO_PJ3, PJ3_DATA),
+ PINMUX_GPIO(GPIO_PJ2, PJ2_DATA),
+ PINMUX_GPIO(GPIO_PJ1, PJ1_DATA),
+ PINMUX_GPIO(GPIO_PJ0, PJ0_DATA),
+
+ /* Port K */
+ PINMUX_GPIO(GPIO_PK11, PK11_DATA),
+ PINMUX_GPIO(GPIO_PK10, PK10_DATA),
+ PINMUX_GPIO(GPIO_PK9, PK9_DATA),
+ PINMUX_GPIO(GPIO_PK8, PK8_DATA),
+ PINMUX_GPIO(GPIO_PK7, PK7_DATA),
+ PINMUX_GPIO(GPIO_PK6, PK6_DATA),
+ PINMUX_GPIO(GPIO_PK5, PK5_DATA),
+ PINMUX_GPIO(GPIO_PK4, PK4_DATA),
+ PINMUX_GPIO(GPIO_PK3, PK3_DATA),
+ PINMUX_GPIO(GPIO_PK2, PK2_DATA),
+ PINMUX_GPIO(GPIO_PK1, PK1_DATA),
+ PINMUX_GPIO(GPIO_PK0, PK0_DATA),
+
+ /* INTC */
+ PINMUX_GPIO(GPIO_FN_PINT7_PG, PINT7_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT6_PG, PINT6_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT5_PG, PINT5_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT4_PG, PINT4_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT3_PG, PINT3_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT2_PG, PINT2_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT1_PG, PINT1_PG_MARK),
+
+ PINMUX_GPIO(GPIO_FN_IRQ7_PC, IRQ7_PC_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ6_PC, IRQ6_PC_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ5_PC, IRQ5_PC_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ4_PC, IRQ4_PC_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ3_PG, IRQ3_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ2_PG, IRQ2_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ1_PJ, IRQ1_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ0_PJ, IRQ0_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ3_PE, IRQ3_PE_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ2_PE, IRQ2_PE_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ1_PE, IRQ1_PE_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ0_PE, IRQ0_PE_MARK),
+
+ /* WDT */
+ PINMUX_GPIO(GPIO_FN_WDTOVF, WDTOVF_MARK),
+
+ /* CAN */
+ PINMUX_GPIO(GPIO_FN_CTX1, CTX1_MARK),
+ PINMUX_GPIO(GPIO_FN_CRX1, CRX1_MARK),
+ PINMUX_GPIO(GPIO_FN_CTX0, CTX0_MARK),
+ PINMUX_GPIO(GPIO_FN_CRX0, CRX0_MARK),
+ PINMUX_GPIO(GPIO_FN_CRX0_CRX1, CRX0CRX1_MARK),
+
+ /* DMAC */
+ PINMUX_GPIO(GPIO_FN_TEND0, TEND0_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
+ PINMUX_GPIO(GPIO_FN_TEND1, TEND1_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
+
+ /* ADC */
+ PINMUX_GPIO(GPIO_FN_ADTRG, ADTRG_MARK),
+
+ /* BSCh */
+ PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
+ PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
+ PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
+ PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
+ PINMUX_GPIO(GPIO_FN_A21, A21_MARK),
+ PINMUX_GPIO(GPIO_FN_A20, A20_MARK),
+ PINMUX_GPIO(GPIO_FN_A19, A19_MARK),
+ PINMUX_GPIO(GPIO_FN_A18, A18_MARK),
+ PINMUX_GPIO(GPIO_FN_A17, A17_MARK),
+ PINMUX_GPIO(GPIO_FN_A16, A16_MARK),
+ PINMUX_GPIO(GPIO_FN_A15, A15_MARK),
+ PINMUX_GPIO(GPIO_FN_A14, A14_MARK),
+ PINMUX_GPIO(GPIO_FN_A13, A13_MARK),
+ PINMUX_GPIO(GPIO_FN_A12, A12_MARK),
+ PINMUX_GPIO(GPIO_FN_A11, A11_MARK),
+ PINMUX_GPIO(GPIO_FN_A10, A10_MARK),
+ PINMUX_GPIO(GPIO_FN_A9, A9_MARK),
+ PINMUX_GPIO(GPIO_FN_A8, A8_MARK),
+ PINMUX_GPIO(GPIO_FN_A7, A7_MARK),
+ PINMUX_GPIO(GPIO_FN_A6, A6_MARK),
+ PINMUX_GPIO(GPIO_FN_A5, A5_MARK),
+ PINMUX_GPIO(GPIO_FN_A4, A4_MARK),
+ PINMUX_GPIO(GPIO_FN_A3, A3_MARK),
+ PINMUX_GPIO(GPIO_FN_A2, A2_MARK),
+ PINMUX_GPIO(GPIO_FN_A1, A1_MARK),
+ PINMUX_GPIO(GPIO_FN_A0, A0_MARK),
+
+ PINMUX_GPIO(GPIO_FN_D15, D15_MARK),
+ PINMUX_GPIO(GPIO_FN_D14, D14_MARK),
+ PINMUX_GPIO(GPIO_FN_D13, D13_MARK),
+ PINMUX_GPIO(GPIO_FN_D12, D12_MARK),
+ PINMUX_GPIO(GPIO_FN_D11, D11_MARK),
+ PINMUX_GPIO(GPIO_FN_D10, D10_MARK),
+ PINMUX_GPIO(GPIO_FN_D9, D9_MARK),
+ PINMUX_GPIO(GPIO_FN_D8, D8_MARK),
+ PINMUX_GPIO(GPIO_FN_D7, D7_MARK),
+ PINMUX_GPIO(GPIO_FN_D6, D6_MARK),
+ PINMUX_GPIO(GPIO_FN_D5, D5_MARK),
+ PINMUX_GPIO(GPIO_FN_D4, D4_MARK),
+ PINMUX_GPIO(GPIO_FN_D3, D3_MARK),
+ PINMUX_GPIO(GPIO_FN_D2, D2_MARK),
+ PINMUX_GPIO(GPIO_FN_D1, D1_MARK),
+ PINMUX_GPIO(GPIO_FN_D0, D0_MARK),
+
+ PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
+ PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
+ PINMUX_GPIO(GPIO_FN_CS3, CS3_MARK),
+ PINMUX_GPIO(GPIO_FN_CS2, CS2_MARK),
+ PINMUX_GPIO(GPIO_FN_CS1, CS1_MARK),
+ PINMUX_GPIO(GPIO_FN_CS0, CS0_MARK),
+ PINMUX_GPIO(GPIO_FN_CS6CE1B, CS6CE1B_MARK),
+ PINMUX_GPIO(GPIO_FN_CS5CE1A, CS5CE1A_MARK),
+ PINMUX_GPIO(GPIO_FN_CE2A, CE2A_MARK),
+ PINMUX_GPIO(GPIO_FN_CE2B, CE2B_MARK),
+ PINMUX_GPIO(GPIO_FN_RD, RD_MARK),
+ PINMUX_GPIO(GPIO_FN_RDWR, RDWR_MARK),
+ PINMUX_GPIO(GPIO_FN_ICIOWRAH, ICIOWRAH_MARK),
+ PINMUX_GPIO(GPIO_FN_ICIORD, ICIORD_MARK),
+ PINMUX_GPIO(GPIO_FN_WE1DQMUWE, WE1DQMUWE_MARK),
+ PINMUX_GPIO(GPIO_FN_WE0DQML, WE0DQML_MARK),
+ PINMUX_GPIO(GPIO_FN_RAS, RAS_MARK),
+ PINMUX_GPIO(GPIO_FN_CAS, CAS_MARK),
+ PINMUX_GPIO(GPIO_FN_CKE, CKE_MARK),
+ PINMUX_GPIO(GPIO_FN_WAIT, WAIT_MARK),
+ PINMUX_GPIO(GPIO_FN_BREQ, BREQ_MARK),
+ PINMUX_GPIO(GPIO_FN_BACK, BACK_MARK),
+ PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
+
+ /* TMU */
+ PINMUX_GPIO(GPIO_FN_TIOC4D, TIOC4D_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC4C, TIOC4C_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC4B, TIOC4B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC4A, TIOC4A_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC3D, TIOC3D_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC3C, TIOC3C_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC3B, TIOC3B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC3A, TIOC3A_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC2B, TIOC2B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC1B, TIOC1B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC2A, TIOC2A_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC1A, TIOC1A_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC0D, TIOC0D_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC0C, TIOC0C_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC0B, TIOC0B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC0A, TIOC0A_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKD, TCLKD_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKC, TCLKC_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKB, TCLKB_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKA, TCLKA_MARK),
+
+ /* SCIF */
+ PINMUX_GPIO(GPIO_FN_TXD0, TXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD0, RXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK0, SCK0_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD1, TXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD1, RXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK1, SCK1_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
+ PINMUX_GPIO(GPIO_FN_RTS3, RTS3_MARK),
+ PINMUX_GPIO(GPIO_FN_CTS3, CTS3_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD3, TXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD4, TXD4_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD4, RXD4_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD5, TXD5_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD5, RXD5_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD6, TXD6_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD6, RXD6_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD7, TXD7_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD7, RXD7_MARK),
+ PINMUX_GPIO(GPIO_FN_RTS1, RTS1_MARK),
+ PINMUX_GPIO(GPIO_FN_CTS1, CTS1_MARK),
+
+ /* RSPI */
+ PINMUX_GPIO(GPIO_FN_RSPCK0, RSPCK0_MARK),
+ PINMUX_GPIO(GPIO_FN_MOSI0, MOSI0_MARK),
+ PINMUX_GPIO(GPIO_FN_MISO0_PF12, MISO0_PF12_MARK),
+ PINMUX_GPIO(GPIO_FN_MISO1, MISO1_MARK),
+ PINMUX_GPIO(GPIO_FN_SSL00, SSL00_MARK),
+ PINMUX_GPIO(GPIO_FN_RSPCK1, RSPCK1_MARK),
+ PINMUX_GPIO(GPIO_FN_MOSI1, MOSI1_MARK),
+ PINMUX_GPIO(GPIO_FN_MISO1_PG19, MISO1_PG19_MARK),
+ PINMUX_GPIO(GPIO_FN_SSL10, SSL10_MARK),
+
+ /* IIC3 */
+ PINMUX_GPIO(GPIO_FN_SCL0, SCL0_MARK),
+ PINMUX_GPIO(GPIO_FN_SCL1, SCL1_MARK),
+ PINMUX_GPIO(GPIO_FN_SCL2, SCL2_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA0, SDA0_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA1, SDA1_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA2, SDA2_MARK),
+
+ /* SSI */
+ PINMUX_GPIO(GPIO_FN_SSISCK0, SSISCK0_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIWS0, SSIWS0_MARK),
+ PINMUX_GPIO(GPIO_FN_SSITXD0, SSITXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIRXD0, SSIRXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIWS1, SSIWS1_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIWS2, SSIWS2_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIWS3, SSIWS3_MARK),
+ PINMUX_GPIO(GPIO_FN_SSISCK1, SSISCK1_MARK),
+ PINMUX_GPIO(GPIO_FN_SSISCK2, SSISCK2_MARK),
+ PINMUX_GPIO(GPIO_FN_SSISCK3, SSISCK3_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIDATA1, SSIDATA1_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIDATA2, SSIDATA2_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIDATA3, SSIDATA3_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDIO_CLK, AUDIO_CLK_MARK),
+
+ /* SIOF */ /* NOTE Shares AUDIO_CLK with SSI */
+ PINMUX_GPIO(GPIO_FN_SIOFTXD, SIOFTXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOFRXD, SIOFRXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOFSYNC, SIOFSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOFSCK, SIOFSCK_MARK),
+
+ /* SPDIF */ /* NOTE Shares AUDIO_CLK with SSI */
+ PINMUX_GPIO(GPIO_FN_SPDIF_IN, SPDIF_IN_MARK),
+ PINMUX_GPIO(GPIO_FN_SPDIF_OUT, SPDIF_OUT_MARK),
+
+ /* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
+ PINMUX_GPIO(GPIO_FN_FCE, FCE_MARK),
+ PINMUX_GPIO(GPIO_FN_FRB, FRB_MARK),
+
+ /* VDC3 */
+ PINMUX_GPIO(GPIO_FN_DV_CLK, DV_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_VSYNC, DV_VSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_HSYNC, DV_HSYNC_MARK),
+
+ PINMUX_GPIO(GPIO_FN_DV_DATA7, DV_DATA7_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA6, DV_DATA6_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA5, DV_DATA5_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA4, DV_DATA4_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA3, DV_DATA3_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA2, DV_DATA2_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA1, DV_DATA1_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA0, DV_DATA0_MARK),
+
+ PINMUX_GPIO(GPIO_FN_LCD_CLK, LCD_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_EXTCLK, LCD_EXTCLK_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_VSYNC, LCD_VSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_HSYNC, LCD_HSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DE, LCD_DE_MARK),
+
+ PINMUX_GPIO(GPIO_FN_LCD_DATA15, LCD_DATA15_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA14, LCD_DATA14_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA13, LCD_DATA13_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA12, LCD_DATA12_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA11, LCD_DATA11_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA10, LCD_DATA10_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA9, LCD_DATA9_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA8, LCD_DATA8_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA7, LCD_DATA7_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA6, LCD_DATA6_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA5, LCD_DATA5_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA4, LCD_DATA4_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA3, LCD_DATA3_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA2, LCD_DATA2_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA1, LCD_DATA1_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA0, LCD_DATA0_MARK),
+
+ PINMUX_GPIO(GPIO_FN_LCD_M_DISP, LCD_M_DISP_MARK),
+};
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+ { PINMUX_CFG_REG("PAIOR0", 0xfffe3812, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PA3_IN, PA3_OUT,
+ PA2_IN, PA2_OUT,
+ PA1_IN, PA1_OUT,
+ PA0_IN, PA0_OUT }
+ },
+
+ { PINMUX_CFG_REG("PBCR5", 0xfffe3824, 16, 4) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PB22MD_00, PB22MD_01, PB22MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PB21MD_0, PB21MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB20MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+
+ },
+ { PINMUX_CFG_REG("PBCR4", 0xfffe3826, 16, 4) {
+ 0, PB19MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB18MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB17MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB16MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PBCR3", 0xfffe3828, 16, 4) {
+ 0, PB15MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB14MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB13MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB12MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PBCR2", 0xfffe382a, 16, 4) {
+ 0, PB11MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB10MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB9MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB8MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PBCR1", 0xfffe382c, 16, 4) {
+ 0, PB7MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB6MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB5MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB4MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PBCR0", 0xfffe382e, 16, 4) {
+ 0, PB3MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB2MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB1MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PBIOR1", 0xfffe3830, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ PB22_IN, PB22_OUT,
+ PB21_IN, PB21_OUT,
+ PB20_IN, PB20_OUT,
+ PB19_IN, PB19_OUT,
+ PB18_IN, PB18_OUT,
+ PB17_IN, PB17_OUT,
+ PB16_IN, PB16_OUT }
+ },
+
+ { PINMUX_CFG_REG("PBIOR0", 0xfffe3832, 16, 1) {
+ PB15_IN, PB15_OUT,
+ PB14_IN, PB14_OUT,
+ PB13_IN, PB13_OUT,
+ PB12_IN, PB12_OUT,
+ PB11_IN, PB11_OUT,
+ PB10_IN, PB10_OUT,
+ PB9_IN, PB9_OUT,
+ PB8_IN, PB8_OUT,
+ PB7_IN, PB7_OUT,
+ PB6_IN, PB6_OUT,
+ PB5_IN, PB5_OUT,
+ PB4_IN, PB4_OUT,
+ PB3_IN, PB3_OUT,
+ PB2_IN, PB2_OUT,
+ PB1_IN, PB1_OUT,
+ 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PCCR2", 0xfffe384a, 16, 4) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PC10MD_0, PC10MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PC9MD_0, PC9MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PC8MD_00, PC8MD_01, PC8MD_10, PC8MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PCCR1", 0xfffe384c, 16, 4) {
+ PC7MD_00, PC7MD_01, PC7MD_10, PC7MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PC6MD_00, PC6MD_01, PC6MD_10, PC6MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PC5MD_00, PC5MD_01, PC5MD_10, PC5MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PC4MD_0, PC4MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PCCR0", 0xfffe384e, 16, 4) {
+ PC3MD_0, PC3MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PC2MD_0, PC2MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PC1MD_0, PC1MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PC0MD_0, PC0MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PCIOR0", 0xfffe3852, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ PC10_IN, PC10_OUT,
+ PC9_IN, PC9_OUT,
+ PC8_IN, PC8_OUT,
+ PC7_IN, PC7_OUT,
+ PC6_IN, PC6_OUT,
+ PC5_IN, PC5_OUT,
+ PC4_IN, PC4_OUT,
+ PC3_IN, PC3_OUT,
+ PC2_IN, PC2_OUT,
+ PC1_IN, PC1_OUT,
+ PC0_IN, PC0_OUT
+ }
+ },
+
+ { PINMUX_CFG_REG("PDCR3", 0xfffe3868, 16, 4) {
+ 0, PD15MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD14MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD13MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD12MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PDCR2", 0xfffe386a, 16, 4) {
+ 0, PD11MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD10MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD9MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD8MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PDCR1", 0xfffe386c, 16, 4) {
+ 0, PD7MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD6MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD5MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD4MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PDCR0", 0xfffe386e, 16, 4) {
+ 0, PD3MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD2MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD1MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PD0MD_01, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PDIOR0", 0xfffe3872, 16, 1) {
+ PD15_IN, PD15_OUT,
+ PD14_IN, PD14_OUT,
+ PD13_IN, PD13_OUT,
+ PD12_IN, PD12_OUT,
+ PD11_IN, PD11_OUT,
+ PD10_IN, PD10_OUT,
+ PD9_IN, PD9_OUT,
+ PD8_IN, PD8_OUT,
+ PD7_IN, PD7_OUT,
+ PD6_IN, PD6_OUT,
+ PD5_IN, PD5_OUT,
+ PD4_IN, PD4_OUT,
+ PD3_IN, PD3_OUT,
+ PD2_IN, PD2_OUT,
+ PD1_IN, PD1_OUT,
+ PD0_IN, PD0_OUT }
+ },
+
+ { PINMUX_CFG_REG("PECR1", 0xfffe388c, 16, 4) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PE5MD_00, PE5MD_01, 0, PE5MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PE4MD_00, PE4MD_01, 0, PE4MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PECR0", 0xfffe388e, 16, 4) {
+ PE3MD_00, PE3MD_01, 0, PE3MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PE2MD_00, PE2MD_01, 0, PE2MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PE1MD_000, PE1MD_001, PE1MD_010, PE1MD_011,
+ PE1MD_100, PE1MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PE0MD_00, PE0MD_01, PE0MD_10, PE0MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PEIOR0", 0xfffe3892, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ PE5_IN, PE5_OUT,
+ PE4_IN, PE4_OUT,
+ PE3_IN, PE3_OUT,
+ PE2_IN, PE2_OUT,
+ PE1_IN, PE1_OUT,
+ PE0_IN, PE0_OUT }
+ },
+
+ { PINMUX_CFG_REG("PFCR3", 0xfffe38a8, 16, 4) {
+ PF12MD_000, PF12MD_001, 0, PF12MD_011,
+ PF12MD_100, PF12MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PFCR2", 0xfffe38aa, 16, 4) {
+ PF11MD_000, PF11MD_001, PF11MD_010, PF11MD_011,
+ PF11MD_100, PF11MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PF10MD_000, PF10MD_001, PF10MD_010, PF10MD_011,
+ PF10MD_100, PF10MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PF9MD_000, PF9MD_001, PF9MD_010, PF9MD_011,
+ PF9MD_100, PF9MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PF8MD_00, PF8MD_01, PF8MD_10, PF8MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PFCR1", 0xfffe38ac, 16, 4) {
+ PF7MD_000, PF7MD_001, PF7MD_010, PF7MD_011,
+ PF7MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PF6MD_000, PF6MD_001, PF6MD_010, PF6MD_011,
+ PF6MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PF5MD_000, PF5MD_001, PF5MD_010, PF5MD_011,
+ PF5MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PF4MD_000, PF4MD_001, PF4MD_010, PF4MD_011,
+ PF4MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PFCR0", 0xfffe38ae, 16, 4) {
+ PF3MD_000, PF3MD_001, PF3MD_010, PF3MD_011,
+ PF3MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PF2MD_000, PF2MD_001, PF2MD_010, PF2MD_011,
+ PF2MD_100, PF2MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PF1MD_000, PF1MD_001, PF1MD_010, PF1MD_011,
+ PF1MD_100, PF1MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+ }
+ },
+
+ { PINMUX_CFG_REG("PFIOR0", 0xfffe38b2, 16, 1) {
+ 0, 0, 0, 0, 0, 0,
+ PF12_IN, PF12_OUT,
+ PF11_IN, PF11_OUT,
+ PF10_IN, PF10_OUT,
+ PF9_IN, PF9_OUT,
+ PF8_IN, PF8_OUT,
+ PF7_IN, PF7_OUT,
+ PF6_IN, PF6_OUT,
+ PF5_IN, PF5_OUT,
+ PF4_IN, PF4_OUT,
+ PF3_IN, PF3_OUT,
+ PF2_IN, PF2_OUT,
+ PF1_IN, PF1_OUT,
+ PF0_IN, PF0_OUT }
+ },
+
+ { PINMUX_CFG_REG("PGCR7", 0xfffe38c0, 16, 4) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG0MD_000, PG0MD_001, PG0MD_010, PG0MD_011,
+ PG0MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PGCR6", 0xfffe38c2, 16, 4) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG24MD_00, PG24MD_01, PG24MD_10, PG24MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PGCR5", 0xfffe38c4, 16, 4) {
+ PG23MD_00, PG23MD_01, PG23MD_10, PG23MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG22MD_00, PG22MD_01, PG22MD_10, PG22MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG21MD_00, PG21MD_01, PG21MD_10, PG21MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG20MD_000, PG20MD_001, PG20MD_010, PG20MD_011,
+ PG20MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PGCR4", 0xfffe38c6, 16, 4) {
+ PG19MD_000, PG19MD_001, PG19MD_010, PG19MD_011,
+ PG19MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG18MD_000, PG18MD_001, PG18MD_010, PG18MD_011,
+ PG18MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG17MD_000, PG17MD_001, PG17MD_010, PG17MD_011,
+ PG17MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG16MD_000, PG16MD_001, PG16MD_010, PG16MD_011,
+ PG16MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PGCR3", 0xfffe38c8, 16, 4) {
+ PG15MD_000, PG15MD_001, PG15MD_010, PG15MD_011,
+ PG15MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG14MD_000, PG14MD_001, PG14MD_010, 0,
+ PG14MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG13MD_000, PG13MD_001, PG13MD_010, 0,
+ PG13MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG12MD_000, PG12MD_001, PG12MD_010, 0,
+ PG12MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PGCR2", 0xfffe38ca, 16, 4) {
+ PG11MD_000, PG11MD_001, PG11MD_010, PG11MD_011,
+ PG11MD_100, PG11MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG10MD_000, PG10MD_001, PG10MD_010, PG10MD_011,
+ PG10MD_100, PG10MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG9MD_000, PG9MD_001, PG9MD_010, PG9MD_011,
+ PG9MD_100, PG9MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG8MD_000, PG8MD_001, PG8MD_010, PG8MD_011,
+ PG8MD_100, PG8MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PGCR1", 0xfffe38cc, 16, 4) {
+ PG7MD_00, PG7MD_01, PG7MD_10, PG7MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG6MD_00, PG6MD_01, PG6MD_10, PG6MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG5MD_00, PG5MD_01, PG5MD_10, PG5MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG4MD_00, PG4MD_01, PG4MD_10, PG4MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PGCR0", 0xfffe38ce, 16, 4) {
+ PG3MD_00, PG3MD_01, PG3MD_10, PG3MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG2MD_00, PG2MD_01, PG2MD_10, PG2MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG1MD_00, PG1MD_01, PG1MD_10, PG1MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PGIOR1", 0xfffe38d0, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ PG24_IN, PG24_OUT,
+ PG23_IN, PG23_OUT,
+ PG22_IN, PG22_OUT,
+ PG21_IN, PG21_OUT,
+ PG20_IN, PG20_OUT,
+ PG19_IN, PG19_OUT,
+ PG18_IN, PG18_OUT,
+ PG17_IN, PG17_OUT,
+ PG16_IN, PG16_OUT }
+ },
+
+ { PINMUX_CFG_REG("PGIOR0", 0xfffe38d2, 16, 1) {
+ PG15_IN, PG15_OUT,
+ PG14_IN, PG14_OUT,
+ PG13_IN, PG13_OUT,
+ PG12_IN, PG12_OUT,
+ PG11_IN, PG11_OUT,
+ PG10_IN, PG10_OUT,
+ PG9_IN, PG9_OUT,
+ PG8_IN, PG8_OUT,
+ PG7_IN, PG7_OUT,
+ PG6_IN, PG6_OUT,
+ PG5_IN, PG5_OUT,
+ PG4_IN, PG4_OUT,
+ PG3_IN, PG3_OUT,
+ PG2_IN, PG2_OUT,
+ PG1_IN, PG1_OUT,
+ PG0_IN, PG0_OUT
+ }
+ },
+
+ { PINMUX_CFG_REG("PHCR1", 0xfffe38ec, 16, 4) {
+ PH7MD_0, PH7MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PH6MD_0, PH6MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PH5MD_0, PH5MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PH4MD_0, PH4MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PHCR0", 0xfffe38ee, 16, 4) {
+ PH3MD_0, PH3MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PH2MD_0, PH2MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PH1MD_0, PH1MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PH0MD_0, PH0MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PJCR2", 0xfffe390a, 16, 4) {
+ PJ11MD_00, PJ11MD_01, PJ11MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PJ10MD_00, PJ10MD_01, PJ10MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PJ9MD_00, PJ9MD_01, PJ9MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PJ8MD_00, PJ8MD_01, PJ8MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PJCR1", 0xfffe390c, 16, 4) {
+ PJ7MD_00, PJ7MD_01, PJ7MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PJ6MD_00, PJ6MD_01, PJ6MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PJ5MD_00, PJ5MD_01, PJ5MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PJ4MD_00, PJ4MD_01, PJ4MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PJCR0", 0xfffe390e, 16, 4) {
+ PJ3MD_00, PJ3MD_01, PJ3MD_10, PJ3MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PJ2MD_000, PJ2MD_001, PJ2MD_010, PJ2MD_011,
+ PJ2MD_100, PJ2MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PJ1MD_000, PJ1MD_001, PJ1MD_010, PJ1MD_011,
+ PJ1MD_100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PJ0MD_000, PJ0MD_001, PJ0MD_010, PJ0MD_011,
+ PJ0MD_100, PJ0MD_101, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, }
+ },
+ { PINMUX_CFG_REG("PJIOR0", 0xfffe3912, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PJ11_IN, PJ11_OUT,
+ PJ10_IN, PJ10_OUT,
+ PJ9_IN, PJ9_OUT,
+ PJ8_IN, PJ8_OUT,
+ PJ7_IN, PJ7_OUT,
+ PJ6_IN, PJ6_OUT,
+ PJ5_IN, PJ5_OUT,
+ PJ4_IN, PJ4_OUT,
+ PJ3_IN, PJ3_OUT,
+ PJ2_IN, PJ2_OUT,
+ PJ1_IN, PJ1_OUT,
+ PJ0_IN, PJ0_OUT }
+ },
+
+ { PINMUX_CFG_REG("PKCR2", 0xfffe392a, 16, 4) {
+ PK11MD_00, PK11MD_01, PK11MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PK10MD_00, PK10MD_01, PK10MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PK9MD_00, PK9MD_01, PK9MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PK8MD_00, PK8MD_01, PK8MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PKCR1", 0xfffe392c, 16, 4) {
+ PK7MD_00, PK7MD_01, PK7MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PK6MD_00, PK6MD_01, PK6MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PK5MD_00, PK5MD_01, PK5MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PK4MD_00, PK4MD_01, PK4MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PKCR0", 0xfffe392e, 16, 4) {
+ PK3MD_00, PK3MD_01, PK3MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PK2MD_00, PK2MD_01, PK2MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PK1MD_00, PK1MD_01, PK1MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PK0MD_00, PK0MD_01, PK0MD_10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PKIOR0", 0xfffe3932, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PJ11_IN, PJ11_OUT,
+ PJ10_IN, PJ10_OUT,
+ PJ9_IN, PJ9_OUT,
+ PJ8_IN, PJ8_OUT,
+ PJ7_IN, PJ7_OUT,
+ PJ6_IN, PJ6_OUT,
+ PJ5_IN, PJ5_OUT,
+ PJ4_IN, PJ4_OUT,
+ PJ3_IN, PJ3_OUT,
+ PJ2_IN, PJ2_OUT,
+ PJ1_IN, PJ1_OUT,
+ PJ0_IN, PJ0_OUT }
+ },
+ {}
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+ { PINMUX_DATA_REG("PADR1", 0xfffe3814, 16) {
+ 0, 0, 0, 0, 0, 0, 0, PA3_DATA,
+ 0, 0, 0, 0, 0, 0, 0, PA2_DATA }
+ },
+
+ { PINMUX_DATA_REG("PADR0", 0xfffe3816, 16) {
+ 0, 0, 0, 0, 0, 0, 0, PA1_DATA,
+ 0, 0, 0, 0, 0, 0, 0, PA0_DATA }
+ },
+
+ { PINMUX_DATA_REG("PBDR1", 0xfffe3834, 16) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB22_DATA, PB21_DATA, PB20_DATA,
+ PB19_DATA, PB18_DATA, PB17_DATA, PB16_DATA }
+ },
+
+ { PINMUX_DATA_REG("PBDR0", 0xfffe3836, 16) {
+ PB15_DATA, PB14_DATA, PB13_DATA, PB12_DATA,
+ PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
+ PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+ PB3_DATA, PB2_DATA, PB1_DATA, 0 }
+ },
+
+ { PINMUX_DATA_REG("PCDR0", 0xfffe3856, 16) {
+ 0, 0, 0, 0,
+ 0, PC10_DATA, PC9_DATA, PC8_DATA,
+ PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+ PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA }
+ },
+
+ { PINMUX_DATA_REG("PDDR0", 0xfffe3876, 16) {
+ PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
+ PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
+ PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+ PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA }
+ },
+
+ { PINMUX_DATA_REG("PEDR0", 0xfffe3896, 16) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, PE5_DATA, PE4_DATA,
+ PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA }
+ },
+
+ { PINMUX_DATA_REG("PFDR0", 0xfffe38b6, 16) {
+ 0, 0, 0, PF12_DATA,
+ PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
+ PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+ PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA }
+ },
+
+ { PINMUX_DATA_REG("PGDR1", 0xfffe38d4, 16) {
+ 0, 0, 0, 0, 0, 0, 0, PG24_DATA,
+ PG23_DATA, PG22_DATA, PG21_DATA, PG20_DATA,
+ PG19_DATA, PG18_DATA, PG17_DATA, PG16_DATA }
+ },
+
+ { PINMUX_DATA_REG("PGDR0", 0xfffe38d6, 16) {
+ PG15_DATA, PG14_DATA, PG13_DATA, PG12_DATA,
+ PG11_DATA, PG10_DATA, PG9_DATA, PG8_DATA,
+ PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+ PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA }
+ },
+ { PINMUX_DATA_REG("PJDR0", 0xfffe3916, 16) {
+ 0, 0, 0, PJ12_DATA,
+ PJ11_DATA, PJ10_DATA, PJ9_DATA, PJ8_DATA,
+ PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
+ PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA }
+ },
+ { PINMUX_DATA_REG("PKDR0", 0xfffe3936, 16) {
+ 0, 0, 0, PK12_DATA,
+ PK11_DATA, PK10_DATA, PK9_DATA, PK8_DATA,
+ PK7_DATA, PK6_DATA, PK5_DATA, PK4_DATA,
+ PK3_DATA, PK2_DATA, PK1_DATA, PK0_DATA }
+ },
+ { }
+};
+
+static struct pinmux_info sh7264_pinmux_info = {
+ .name = "sh7264_pfc",
+ .reserved_id = PINMUX_RESERVED,
+ .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+ .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END, FORCE_IN },
+ .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END, FORCE_OUT },
+ .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+ .first_gpio = GPIO_PA3,
+ .last_gpio = GPIO_FN_LCD_M_DISP,
+
+ .gpios = pinmux_gpios,
+ .cfg_regs = pinmux_config_regs,
+ .data_regs = pinmux_data_regs,
+
+ .gpio_data = pinmux_data,
+ .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
+
+static int __init plat_pinmux_setup(void)
+{
+ return register_pinmux(&sh7264_pinmux_info);
+}
+arch_initcall(plat_pinmux_setup);
diff --git a/arch/sh/kernel/cpu/sh2a/pinmux-sh7269.c b/arch/sh/kernel/cpu/sh2a/pinmux-sh7269.c
new file mode 100644
index 000000000000..f25127c46eca
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/pinmux-sh7269.c
@@ -0,0 +1,2800 @@
+/*
+ * SH7269 Pinmux
+ *
+ * Copyright (C) 2012 Renesas Electronics Europe Ltd
+ * Copyright (C) 2012 Phil Edworthy
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <cpu/sh7269.h>
+
+enum {
+ PINMUX_RESERVED = 0,
+
+ PINMUX_DATA_BEGIN,
+ /* Port A */
+ PA1_DATA, PA0_DATA,
+ /* Port B */
+ PB22_DATA, PB21_DATA, PB20_DATA,
+ PB19_DATA, PB18_DATA, PB17_DATA, PB16_DATA,
+ PB15_DATA, PB14_DATA, PB13_DATA, PB12_DATA,
+ PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
+ PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+ PB3_DATA, PB2_DATA, PB1_DATA,
+ /* Port C */
+ PC8_DATA,
+ PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+ PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA,
+ /* Port D */
+ PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
+ PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
+ PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+ PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA,
+ /* Port E */
+ PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
+ PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA,
+ /* Port F */
+ PF23_DATA, PF22_DATA, PF21_DATA, PF20_DATA,
+ PF19_DATA, PF18_DATA, PF17_DATA, PF16_DATA,
+ PF15_DATA, PF14_DATA, PF13_DATA, PF12_DATA,
+ PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
+ PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+ PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA,
+ /* Port G */
+ PG27_DATA, PG26_DATA, PG25_DATA, PG24_DATA,
+ PG23_DATA, PG22_DATA, PG21_DATA, PG20_DATA,
+ PG19_DATA, PG18_DATA, PG17_DATA, PG16_DATA,
+ PG15_DATA, PG14_DATA, PG13_DATA, PG12_DATA,
+ PG11_DATA, PG10_DATA, PG9_DATA, PG8_DATA,
+ PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+ PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA,
+ /* Port H */
+ /* NOTE - Port H does not have a Data Register, but PH Data is
+ connected to PH Port Register */
+ PH7_DATA, PH6_DATA, PH5_DATA, PH4_DATA,
+ PH3_DATA, PH2_DATA, PH1_DATA, PH0_DATA,
+ /* Port I - not on device */
+ /* Port J */
+ PJ31_DATA, PJ30_DATA, PJ29_DATA, PJ28_DATA,
+ PJ27_DATA, PJ26_DATA, PJ25_DATA, PJ24_DATA,
+ PJ23_DATA, PJ22_DATA, PJ21_DATA, PJ20_DATA,
+ PJ19_DATA, PJ18_DATA, PJ17_DATA, PJ16_DATA,
+ PJ15_DATA, PJ14_DATA, PJ13_DATA, PJ12_DATA,
+ PJ11_DATA, PJ10_DATA, PJ9_DATA, PJ8_DATA,
+ PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
+ PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA,
+ PINMUX_DATA_END,
+
+ PINMUX_INPUT_BEGIN,
+ FORCE_IN,
+ /* Port A */
+ PA1_IN, PA0_IN,
+ /* Port B */
+ PB22_IN, PB21_IN, PB20_IN,
+ PB19_IN, PB18_IN, PB17_IN, PB16_IN,
+ PB15_IN, PB14_IN, PB13_IN, PB12_IN,
+ PB11_IN, PB10_IN, PB9_IN, PB8_IN,
+ PB7_IN, PB6_IN, PB5_IN, PB4_IN,
+ PB3_IN, PB2_IN, PB1_IN,
+ /* Port C */
+ PC8_IN,
+ PC7_IN, PC6_IN, PC5_IN, PC4_IN,
+ PC3_IN, PC2_IN, PC1_IN, PC0_IN,
+ /* Port D */
+ PD15_IN, PD14_IN, PD13_IN, PD12_IN,
+ PD11_IN, PD10_IN, PD9_IN, PD8_IN,
+ PD7_IN, PD6_IN, PD5_IN, PD4_IN,
+ PD3_IN, PD2_IN, PD1_IN, PD0_IN,
+ /* Port E */
+ PE7_IN, PE6_IN, PE5_IN, PE4_IN,
+ PE3_IN, PE2_IN, PE1_IN, PE0_IN,
+ /* Port F */
+ PF23_IN, PF22_IN, PF21_IN, PF20_IN,
+ PF19_IN, PF18_IN, PF17_IN, PF16_IN,
+ PF15_IN, PF14_IN, PF13_IN, PF12_IN,
+ PF11_IN, PF10_IN, PF9_IN, PF8_IN,
+ PF7_IN, PF6_IN, PF5_IN, PF4_IN,
+ PF3_IN, PF2_IN, PF1_IN, PF0_IN,
+ /* Port G */
+ PG27_IN, PG26_IN, PG25_IN, PG24_IN,
+ PG23_IN, PG22_IN, PG21_IN, PG20_IN,
+ PG19_IN, PG18_IN, PG17_IN, PG16_IN,
+ PG15_IN, PG14_IN, PG13_IN, PG12_IN,
+ PG11_IN, PG10_IN, PG9_IN, PG8_IN,
+ PG7_IN, PG6_IN, PG5_IN, PG4_IN,
+ PG3_IN, PG2_IN, PG1_IN, PG0_IN,
+ /* Port H - Port H does not have a Data Register */
+ /* Port I - not on device */
+ /* Port J */
+ PJ31_IN, PJ30_IN, PJ29_IN, PJ28_IN,
+ PJ27_IN, PJ26_IN, PJ25_IN, PJ24_IN,
+ PJ23_IN, PJ22_IN, PJ21_IN, PJ20_IN,
+ PJ19_IN, PJ18_IN, PJ17_IN, PJ16_IN,
+ PJ15_IN, PJ14_IN, PJ13_IN, PJ12_IN,
+ PJ11_IN, PJ10_IN, PJ9_IN, PJ8_IN,
+ PJ7_IN, PJ6_IN, PJ5_IN, PJ4_IN,
+ PJ3_IN, PJ2_IN, PJ1_IN, PJ0_IN,
+ PINMUX_INPUT_END,
+
+ PINMUX_OUTPUT_BEGIN,
+ FORCE_OUT,
+ /* Port A */
+ PA1_OUT, PA0_OUT,
+ /* Port B */
+ PB22_OUT, PB21_OUT, PB20_OUT,
+ PB19_OUT, PB18_OUT, PB17_OUT, PB16_OUT,
+ PB15_OUT, PB14_OUT, PB13_OUT, PB12_OUT,
+ PB11_OUT, PB10_OUT, PB9_OUT, PB8_OUT,
+ PB7_OUT, PB6_OUT, PB5_OUT, PB4_OUT,
+ PB3_OUT, PB2_OUT, PB1_OUT,
+ /* Port C */
+ PC8_OUT,
+ PC7_OUT, PC6_OUT, PC5_OUT, PC4_OUT,
+ PC3_OUT, PC2_OUT, PC1_OUT, PC0_OUT,
+ /* Port D */
+ PD15_OUT, PD14_OUT, PD13_OUT, PD12_OUT,
+ PD11_OUT, PD10_OUT, PD9_OUT, PD8_OUT,
+ PD7_OUT, PD6_OUT, PD5_OUT, PD4_OUT,
+ PD3_OUT, PD2_OUT, PD1_OUT, PD0_OUT,
+ /* Port E */
+ PE7_OUT, PE6_OUT, PE5_OUT, PE4_OUT,
+ PE3_OUT, PE2_OUT, PE1_OUT, PE0_OUT,
+ /* Port F */
+ PF23_OUT, PF22_OUT, PF21_OUT, PF20_OUT,
+ PF19_OUT, PF18_OUT, PF17_OUT, PF16_OUT,
+ PF15_OUT, PF14_OUT, PF13_OUT, PF12_OUT,
+ PF11_OUT, PF10_OUT, PF9_OUT, PF8_OUT,
+ PF7_OUT, PF6_OUT, PF5_OUT, PF4_OUT,
+ PF3_OUT, PF2_OUT, PF1_OUT, PF0_OUT,
+ /* Port G */
+ PG27_OUT, PG26_OUT, PG25_OUT, PG24_OUT,
+ PG23_OUT, PG22_OUT, PG21_OUT, PG20_OUT,
+ PG19_OUT, PG18_OUT, PG17_OUT, PG16_OUT,
+ PG15_OUT, PG14_OUT, PG13_OUT, PG12_OUT,
+ PG11_OUT, PG10_OUT, PG9_OUT, PG8_OUT,
+ PG7_OUT, PG6_OUT, PG5_OUT, PG4_OUT,
+ PG3_OUT, PG2_OUT, PG1_OUT, PG0_OUT,
+ /* Port H - Port H does not have a Data Register */
+ /* Port I - not on device */
+ /* Port J */
+ PJ31_OUT, PJ30_OUT, PJ29_OUT, PJ28_OUT,
+ PJ27_OUT, PJ26_OUT, PJ25_OUT, PJ24_OUT,
+ PJ23_OUT, PJ22_OUT, PJ21_OUT, PJ20_OUT,
+ PJ19_OUT, PJ18_OUT, PJ17_OUT, PJ16_OUT,
+ PJ15_OUT, PJ14_OUT, PJ13_OUT, PJ12_OUT,
+ PJ11_OUT, PJ10_OUT, PJ9_OUT, PJ8_OUT,
+ PJ7_OUT, PJ6_OUT, PJ5_OUT, PJ4_OUT,
+ PJ3_OUT, PJ2_OUT, PJ1_OUT, PJ0_OUT,
+ PINMUX_OUTPUT_END,
+
+ PINMUX_FUNCTION_BEGIN,
+ /* Port A */
+ PA1_IOR_IN, PA1_IOR_OUT,
+ PA0_IOR_IN, PA0_IOR_OUT,
+
+ /* Port B */
+ PB22_IOR_IN, PB22_IOR_OUT,
+ PB21_IOR_IN, PB21_IOR_OUT,
+ PB20_IOR_IN, PB20_IOR_OUT,
+ PB19_IOR_IN, PB19_IOR_OUT,
+ PB18_IOR_IN, PB18_IOR_OUT,
+ PB17_IOR_IN, PB17_IOR_OUT,
+ PB16_IOR_IN, PB16_IOR_OUT,
+
+ PB15_IOR_IN, PB15_IOR_OUT,
+ PB14_IOR_IN, PB14_IOR_OUT,
+ PB13_IOR_IN, PB13_IOR_OUT,
+ PB12_IOR_IN, PB12_IOR_OUT,
+ PB11_IOR_IN, PB11_IOR_OUT,
+ PB10_IOR_IN, PB10_IOR_OUT,
+ PB9_IOR_IN, PB9_IOR_OUT,
+ PB8_IOR_IN, PB8_IOR_OUT,
+
+ PB7_IOR_IN, PB7_IOR_OUT,
+ PB6_IOR_IN, PB6_IOR_OUT,
+ PB5_IOR_IN, PB5_IOR_OUT,
+ PB4_IOR_IN, PB4_IOR_OUT,
+ PB3_IOR_IN, PB3_IOR_OUT,
+ PB2_IOR_IN, PB2_IOR_OUT,
+ PB1_IOR_IN, PB1_IOR_OUT,
+ PB0_IOR_IN, PB0_IOR_OUT,
+
+ PB22MD_000, PB22MD_001, PB22MD_010, PB22MD_011,
+ PB22MD_100, PB22MD_101, PB22MD_110, PB22MD_111,
+ PB21MD_00, PB21MD_01, PB21MD_10, PB21MD_11,
+ PB20MD_000, PB20MD_001, PB20MD_010, PB20MD_011,
+ PB20MD_100, PB20MD_101, PB20MD_110, PB20MD_111,
+ PB19MD_000, PB19MD_001, PB19MD_010, PB19MD_011,
+ PB19MD_100, PB19MD_101, PB19MD_110, PB19MD_111,
+ PB18MD_000, PB18MD_001, PB18MD_010, PB18MD_011,
+ PB18MD_100, PB18MD_101, PB18MD_110, PB18MD_111,
+ PB17MD_000, PB17MD_001, PB17MD_010, PB17MD_011,
+ PB17MD_100, PB17MD_101, PB17MD_110, PB17MD_111,
+ PB16MD_000, PB16MD_001, PB16MD_010, PB16MD_011,
+ PB16MD_100, PB16MD_101, PB16MD_110, PB16MD_111,
+ PB15MD_000, PB15MD_001, PB15MD_010, PB15MD_011,
+ PB15MD_100, PB15MD_101, PB15MD_110, PB15MD_111,
+ PB14MD_000, PB14MD_001, PB14MD_010, PB14MD_011,
+ PB14MD_100, PB14MD_101, PB14MD_110, PB14MD_111,
+ PB13MD_000, PB13MD_001, PB13MD_010, PB13MD_011,
+ PB13MD_100, PB13MD_101, PB13MD_110, PB13MD_111,
+ PB12MD_00, PB12MD_01, PB12MD_10, PB12MD_11,
+
+ PB11MD_00, PB11MD_01, PB11MD_10, PB11MD_11,
+ PB10MD_00, PB10MD_01, PB10MD_10, PB10MD_11,
+ PB9MD_00, PB9MD_01, PB9MD_10, PB9MD_11,
+ PB8MD_00, PB8MD_01, PB8MD_10, PB8MD_11,
+
+ PB7MD_00, PB7MD_01, PB7MD_10, PB7MD_11,
+ PB6MD_00, PB6MD_01, PB6MD_10, PB6MD_11,
+ PB5MD_00, PB5MD_01, PB5MD_10, PB5MD_11,
+ PB4MD_00, PB4MD_01, PB4MD_10, PB4MD_11,
+
+ PB3MD_00, PB3MD_01, PB3MD_10, PB3MD_11,
+ PB2MD_00, PB2MD_01, PB2MD_10, PB2MD_11,
+ PB1MD_00, PB1MD_01, PB1MD_10, PB1MD_11,
+
+ /* Port C */
+ PC8_IOR_IN, PC8_IOR_OUT,
+ PC7_IOR_IN, PC7_IOR_OUT,
+ PC6_IOR_IN, PC6_IOR_OUT,
+ PC5_IOR_IN, PC5_IOR_OUT,
+ PC4_IOR_IN, PC4_IOR_OUT,
+ PC3_IOR_IN, PC3_IOR_OUT,
+ PC2_IOR_IN, PC2_IOR_OUT,
+ PC1_IOR_IN, PC1_IOR_OUT,
+ PC0_IOR_IN, PC0_IOR_OUT,
+
+ PC8MD_000, PC8MD_001, PC8MD_010, PC8MD_011,
+ PC8MD_100, PC8MD_101, PC8MD_110, PC8MD_111,
+ PC7MD_000, PC7MD_001, PC7MD_010, PC7MD_011,
+ PC7MD_100, PC7MD_101, PC7MD_110, PC7MD_111,
+ PC6MD_000, PC6MD_001, PC6MD_010, PC6MD_011,
+ PC6MD_100, PC6MD_101, PC6MD_110, PC6MD_111,
+ PC5MD_000, PC5MD_001, PC5MD_010, PC5MD_011,
+ PC5MD_100, PC5MD_101, PC5MD_110, PC5MD_111,
+ PC4MD_00, PC4MD_01, PC4MD_10, PC4MD_11,
+
+ PC3MD_00, PC3MD_01, PC3MD_10, PC3MD_11,
+ PC2MD_00, PC2MD_01, PC2MD_10, PC2MD_11,
+ PC1MD_0, PC1MD_1,
+ PC0MD_0, PC0MD_1,
+
+ /* Port D */
+ PD15_IOR_IN, PD15_IOR_OUT,
+ PD14_IOR_IN, PD14_IOR_OUT,
+ PD13_IOR_IN, PD13_IOR_OUT,
+ PD12_IOR_IN, PD12_IOR_OUT,
+ PD11_IOR_IN, PD11_IOR_OUT,
+ PD10_IOR_IN, PD10_IOR_OUT,
+ PD9_IOR_IN, PD9_IOR_OUT,
+ PD8_IOR_IN, PD8_IOR_OUT,
+ PD7_IOR_IN, PD7_IOR_OUT,
+ PD6_IOR_IN, PD6_IOR_OUT,
+ PD5_IOR_IN, PD5_IOR_OUT,
+ PD4_IOR_IN, PD4_IOR_OUT,
+ PD3_IOR_IN, PD3_IOR_OUT,
+ PD2_IOR_IN, PD2_IOR_OUT,
+ PD1_IOR_IN, PD1_IOR_OUT,
+ PD0_IOR_IN, PD0_IOR_OUT,
+
+ PD15MD_00, PD15MD_01, PD15MD_10, PD15MD_11,
+ PD14MD_00, PD14MD_01, PD14MD_10, PD14MD_11,
+ PD13MD_00, PD13MD_01, PD13MD_10, PD13MD_11,
+ PD12MD_00, PD12MD_01, PD12MD_10, PD12MD_11,
+
+ PD11MD_00, PD11MD_01, PD11MD_10, PD11MD_11,
+ PD10MD_00, PD10MD_01, PD10MD_10, PD10MD_11,
+ PD9MD_00, PD9MD_01, PD9MD_10, PD9MD_11,
+ PD8MD_00, PD8MD_01, PD8MD_10, PD8MD_11,
+
+ PD7MD_00, PD7MD_01, PD7MD_10, PD7MD_11,
+ PD6MD_00, PD6MD_01, PD6MD_10, PD6MD_11,
+ PD5MD_00, PD5MD_01, PD5MD_10, PD5MD_11,
+ PD4MD_00, PD4MD_01, PD4MD_10, PD4MD_11,
+
+ PD3MD_00, PD3MD_01, PD3MD_10, PD3MD_11,
+ PD2MD_00, PD2MD_01, PD2MD_10, PD2MD_11,
+ PD1MD_00, PD1MD_01, PD1MD_10, PD1MD_11,
+ PD0MD_00, PD0MD_01, PD0MD_10, PD0MD_11,
+
+ /* Port E */
+ PE7_IOR_IN, PE7_IOR_OUT,
+ PE6_IOR_IN, PE6_IOR_OUT,
+ PE5_IOR_IN, PE5_IOR_OUT,
+ PE4_IOR_IN, PE4_IOR_OUT,
+ PE3_IOR_IN, PE3_IOR_OUT,
+ PE2_IOR_IN, PE2_IOR_OUT,
+ PE1_IOR_IN, PE1_IOR_OUT,
+ PE0_IOR_IN, PE0_IOR_OUT,
+
+ PE7MD_00, PE7MD_01, PE7MD_10, PE7MD_11,
+ PE6MD_00, PE6MD_01, PE6MD_10, PE6MD_11,
+ PE5MD_00, PE5MD_01, PE5MD_10, PE5MD_11,
+ PE4MD_00, PE4MD_01, PE4MD_10, PE4MD_11,
+
+ PE3MD_000, PE3MD_001, PE3MD_010, PE3MD_011,
+ PE3MD_100, PE3MD_101, PE3MD_110, PE3MD_111,
+ PE2MD_000, PE2MD_001, PE2MD_010, PE2MD_011,
+ PE2MD_100, PE2MD_101, PE2MD_110, PE2MD_111,
+ PE1MD_000, PE1MD_001, PE1MD_010, PE1MD_011,
+ PE1MD_100, PE1MD_101, PE1MD_110, PE1MD_111,
+ PE0MD_00, PE0MD_01, PE0MD_10, PE0MD_11,
+
+ /* Port F */
+ PF23_IOR_IN, PF23_IOR_OUT,
+ PF22_IOR_IN, PF22_IOR_OUT,
+ PF21_IOR_IN, PF21_IOR_OUT,
+ PF20_IOR_IN, PF20_IOR_OUT,
+ PF19_IOR_IN, PF19_IOR_OUT,
+ PF18_IOR_IN, PF18_IOR_OUT,
+ PF17_IOR_IN, PF17_IOR_OUT,
+ PF16_IOR_IN, PF16_IOR_OUT,
+ PF15_IOR_IN, PF15_IOR_OUT,
+ PF14_IOR_IN, PF14_IOR_OUT,
+ PF13_IOR_IN, PF13_IOR_OUT,
+ PF12_IOR_IN, PF12_IOR_OUT,
+ PF11_IOR_IN, PF11_IOR_OUT,
+ PF10_IOR_IN, PF10_IOR_OUT,
+ PF9_IOR_IN, PF9_IOR_OUT,
+ PF8_IOR_IN, PF8_IOR_OUT,
+ PF7_IOR_IN, PF7_IOR_OUT,
+ PF6_IOR_IN, PF6_IOR_OUT,
+ PF5_IOR_IN, PF5_IOR_OUT,
+ PF4_IOR_IN, PF4_IOR_OUT,
+ PF3_IOR_IN, PF3_IOR_OUT,
+ PF2_IOR_IN, PF2_IOR_OUT,
+ PF1_IOR_IN, PF1_IOR_OUT,
+ PF0_IOR_IN, PF0_IOR_OUT,
+
+ PF23MD_000, PF23MD_001, PF23MD_010, PF23MD_011,
+ PF23MD_100, PF23MD_101, PF23MD_110, PF23MD_111,
+ PF22MD_000, PF22MD_001, PF22MD_010, PF22MD_011,
+ PF22MD_100, PF22MD_101, PF22MD_110, PF22MD_111,
+ PF21MD_000, PF21MD_001, PF21MD_010, PF21MD_011,
+ PF21MD_100, PF21MD_101, PF21MD_110, PF21MD_111,
+ PF20MD_000, PF20MD_001, PF20MD_010, PF20MD_011,
+ PF20MD_100, PF20MD_101, PF20MD_110, PF20MD_111,
+
+ PF19MD_000, PF19MD_001, PF19MD_010, PF19MD_011,
+ PF19MD_100, PF19MD_101, PF19MD_110, PF19MD_111,
+ PF18MD_000, PF18MD_001, PF18MD_010, PF18MD_011,
+ PF18MD_100, PF18MD_101, PF18MD_110, PF18MD_111,
+ PF17MD_000, PF17MD_001, PF17MD_010, PF17MD_011,
+ PF17MD_100, PF17MD_101, PF17MD_110, PF17MD_111,
+ PF16MD_000, PF16MD_001, PF16MD_010, PF16MD_011,
+ PF16MD_100, PF16MD_101, PF16MD_110, PF16MD_111,
+
+ PF15MD_000, PF15MD_001, PF15MD_010, PF15MD_011,
+ PF15MD_100, PF15MD_101, PF15MD_110, PF15MD_111,
+ PF14MD_000, PF14MD_001, PF14MD_010, PF14MD_011,
+ PF14MD_100, PF14MD_101, PF14MD_110, PF14MD_111,
+ PF13MD_000, PF13MD_001, PF13MD_010, PF13MD_011,
+ PF13MD_100, PF13MD_101, PF13MD_110, PF13MD_111,
+ PF12MD_000, PF12MD_001, PF12MD_010, PF12MD_011,
+ PF12MD_100, PF12MD_101, PF12MD_110, PF12MD_111,
+
+ PF11MD_000, PF11MD_001, PF11MD_010, PF11MD_011,
+ PF11MD_100, PF11MD_101, PF11MD_110, PF11MD_111,
+ PF10MD_000, PF10MD_001, PF10MD_010, PF10MD_011,
+ PF10MD_100, PF10MD_101, PF10MD_110, PF10MD_111,
+ PF9MD_000, PF9MD_001, PF9MD_010, PF9MD_011,
+ PF9MD_100, PF9MD_101, PF9MD_110, PF9MD_111,
+ PF8MD_000, PF8MD_001, PF8MD_010, PF8MD_011,
+ PF8MD_100, PF8MD_101, PF8MD_110, PF8MD_111,
+
+ PF7MD_000, PF7MD_001, PF7MD_010, PF7MD_011,
+ PF7MD_100, PF7MD_101, PF7MD_110, PF7MD_111,
+ PF6MD_000, PF6MD_001, PF6MD_010, PF6MD_011,
+ PF6MD_100, PF6MD_101, PF6MD_110, PF6MD_111,
+ PF5MD_000, PF5MD_001, PF5MD_010, PF5MD_011,
+ PF5MD_100, PF5MD_101, PF5MD_110, PF5MD_111,
+ PF4MD_000, PF4MD_001, PF4MD_010, PF4MD_011,
+ PF4MD_100, PF4MD_101, PF4MD_110, PF4MD_111,
+
+ PF3MD_000, PF3MD_001, PF3MD_010, PF3MD_011,
+ PF3MD_100, PF3MD_101, PF3MD_110, PF3MD_111,
+ PF2MD_000, PF2MD_001, PF2MD_010, PF2MD_011,
+ PF2MD_100, PF2MD_101, PF2MD_110, PF2MD_111,
+ PF1MD_000, PF1MD_001, PF1MD_010, PF1MD_011,
+ PF1MD_100, PF1MD_101, PF1MD_110, PF1MD_111,
+ PF0MD_000, PF0MD_001, PF0MD_010, PF0MD_011,
+ PF0MD_100, PF0MD_101, PF0MD_110, PF0MD_111,
+
+ /* Port G */
+ PG27_IOR_IN, PG27_IOR_OUT,
+ PG26_IOR_IN, PG26_IOR_OUT,
+ PG25_IOR_IN, PG25_IOR_OUT,
+ PG24_IOR_IN, PG24_IOR_OUT,
+ PG23_IOR_IN, PG23_IOR_OUT,
+ PG22_IOR_IN, PG22_IOR_OUT,
+ PG21_IOR_IN, PG21_IOR_OUT,
+ PG20_IOR_IN, PG20_IOR_OUT,
+ PG19_IOR_IN, PG19_IOR_OUT,
+ PG18_IOR_IN, PG18_IOR_OUT,
+ PG17_IOR_IN, PG17_IOR_OUT,
+ PG16_IOR_IN, PG16_IOR_OUT,
+ PG15_IOR_IN, PG15_IOR_OUT,
+ PG14_IOR_IN, PG14_IOR_OUT,
+ PG13_IOR_IN, PG13_IOR_OUT,
+ PG12_IOR_IN, PG12_IOR_OUT,
+ PG11_IOR_IN, PG11_IOR_OUT,
+ PG10_IOR_IN, PG10_IOR_OUT,
+ PG9_IOR_IN, PG9_IOR_OUT,
+ PG8_IOR_IN, PG8_IOR_OUT,
+ PG7_IOR_IN, PG7_IOR_OUT,
+ PG6_IOR_IN, PG6_IOR_OUT,
+ PG5_IOR_IN, PG5_IOR_OUT,
+ PG4_IOR_IN, PG4_IOR_OUT,
+ PG3_IOR_IN, PG3_IOR_OUT,
+ PG2_IOR_IN, PG2_IOR_OUT,
+ PG1_IOR_IN, PG1_IOR_OUT,
+ PG0_IOR_IN, PG0_IOR_OUT,
+
+ PG27MD_00, PG27MD_01, PG27MD_10, PG27MD_11,
+ PG26MD_00, PG26MD_01, PG26MD_10, PG26MD_11,
+ PG25MD_00, PG25MD_01, PG25MD_10, PG25MD_11,
+ PG24MD_00, PG24MD_01, PG24MD_10, PG24MD_11,
+
+ PG23MD_000, PG23MD_001, PG23MD_010, PG23MD_011,
+ PG23MD_100, PG23MD_101, PG23MD_110, PG23MD_111,
+ PG22MD_000, PG22MD_001, PG22MD_010, PG22MD_011,
+ PG22MD_100, PG22MD_101, PG22MD_110, PG22MD_111,
+ PG21MD_000, PG21MD_001, PG21MD_010, PG21MD_011,
+ PG21MD_100, PG21MD_101, PG21MD_110, PG21MD_111,
+ PG20MD_000, PG20MD_001, PG20MD_010, PG20MD_011,
+ PG20MD_100, PG20MD_101, PG20MD_110, PG20MD_111,
+
+ PG19MD_000, PG19MD_001, PG19MD_010, PG19MD_011,
+ PG19MD_100, PG19MD_101, PG19MD_110, PG19MD_111,
+ PG18MD_000, PG18MD_001, PG18MD_010, PG18MD_011,
+ PG18MD_100, PG18MD_101, PG18MD_110, PG18MD_111,
+ PG17MD_00, PG17MD_01, PG17MD_10, PG17MD_11,
+ PG16MD_00, PG16MD_01, PG16MD_10, PG16MD_11,
+
+ PG15MD_00, PG15MD_01, PG15MD_10, PG15MD_11,
+ PG14MD_00, PG14MD_01, PG14MD_10, PG14MD_11,
+ PG13MD_00, PG13MD_01, PG13MD_10, PG13MD_11,
+ PG12MD_00, PG12MD_01, PG12MD_10, PG12MD_11,
+
+ PG11MD_000, PG11MD_001, PG11MD_010, PG11MD_011,
+ PG11MD_100, PG11MD_101, PG11MD_110, PG11MD_111,
+ PG10MD_000, PG10MD_001, PG10MD_010, PG10MD_011,
+ PG10MD_100, PG10MD_101, PG10MD_110, PG10MD_111,
+ PG9MD_000, PG9MD_001, PG9MD_010, PG9MD_011,
+ PG9MD_100, PG9MD_101, PG9MD_110, PG9MD_111,
+ PG8MD_000, PG8MD_001, PG8MD_010, PG8MD_011,
+ PG8MD_100, PG8MD_101, PG8MD_110, PG8MD_111,
+
+ PG7MD_000, PG7MD_001, PG7MD_010, PG7MD_011,
+ PG7MD_100, PG7MD_101, PG7MD_110, PG7MD_111,
+ PG6MD_000, PG6MD_001, PG6MD_010, PG6MD_011,
+ PG6MD_100, PG6MD_101, PG6MD_110, PG6MD_111,
+ PG5MD_000, PG5MD_001, PG5MD_010, PG5MD_011,
+ PG5MD_100, PG5MD_101, PG5MD_110, PG5MD_111,
+ PG4MD_000, PG4MD_001, PG4MD_010, PG4MD_011,
+ PG4MD_100, PG4MD_101, PG4MD_110, PG4MD_111,
+
+ PG3MD_000, PG3MD_001, PG3MD_010, PG3MD_011,
+ PG3MD_100, PG3MD_101, PG3MD_110, PG3MD_111,
+ PG2MD_000, PG2MD_001, PG2MD_010, PG2MD_011,
+ PG2MD_100, PG2MD_101, PG2MD_110, PG2MD_111,
+ PG1MD_000, PG1MD_001, PG1MD_010, PG1MD_011,
+ PG1MD_100, PG1MD_101, PG1MD_110, PG1MD_111,
+ PG0MD_000, PG0MD_001, PG0MD_010, PG0MD_011,
+ PG0MD_100, PG0MD_101, PG0MD_110, PG0MD_111,
+
+ /* Port H */
+ PH7MD_00, PH7MD_01, PH7MD_10, PH7MD_11,
+ PH6MD_00, PH6MD_01, PH6MD_10, PH6MD_11,
+ PH5MD_00, PH5MD_01, PH5MD_10, PH5MD_11,
+ PH4MD_00, PH4MD_01, PH4MD_10, PH4MD_11,
+
+ PH3MD_00, PH3MD_01, PH3MD_10, PH3MD_11,
+ PH2MD_00, PH2MD_01, PH2MD_10, PH2MD_11,
+ PH1MD_00, PH1MD_01, PH1MD_10, PH1MD_11,
+ PH0MD_00, PH0MD_01, PH0MD_10, PH0MD_11,
+
+ /* Port I - not on device */
+
+ /* Port J */
+ PJ31_IOR_IN, PJ31_IOR_OUT,
+ PJ30_IOR_IN, PJ30_IOR_OUT,
+ PJ29_IOR_IN, PJ29_IOR_OUT,
+ PJ28_IOR_IN, PJ28_IOR_OUT,
+ PJ27_IOR_IN, PJ27_IOR_OUT,
+ PJ26_IOR_IN, PJ26_IOR_OUT,
+ PJ25_IOR_IN, PJ25_IOR_OUT,
+ PJ24_IOR_IN, PJ24_IOR_OUT,
+ PJ23_IOR_IN, PJ23_IOR_OUT,
+ PJ22_IOR_IN, PJ22_IOR_OUT,
+ PJ21_IOR_IN, PJ21_IOR_OUT,
+ PJ20_IOR_IN, PJ20_IOR_OUT,
+ PJ19_IOR_IN, PJ19_IOR_OUT,
+ PJ18_IOR_IN, PJ18_IOR_OUT,
+ PJ17_IOR_IN, PJ17_IOR_OUT,
+ PJ16_IOR_IN, PJ16_IOR_OUT,
+ PJ15_IOR_IN, PJ15_IOR_OUT,
+ PJ14_IOR_IN, PJ14_IOR_OUT,
+ PJ13_IOR_IN, PJ13_IOR_OUT,
+ PJ12_IOR_IN, PJ12_IOR_OUT,
+ PJ11_IOR_IN, PJ11_IOR_OUT,
+ PJ10_IOR_IN, PJ10_IOR_OUT,
+ PJ9_IOR_IN, PJ9_IOR_OUT,
+ PJ8_IOR_IN, PJ8_IOR_OUT,
+ PJ7_IOR_IN, PJ7_IOR_OUT,
+ PJ6_IOR_IN, PJ6_IOR_OUT,
+ PJ5_IOR_IN, PJ5_IOR_OUT,
+ PJ4_IOR_IN, PJ4_IOR_OUT,
+ PJ3_IOR_IN, PJ3_IOR_OUT,
+ PJ2_IOR_IN, PJ2_IOR_OUT,
+ PJ1_IOR_IN, PJ1_IOR_OUT,
+ PJ0_IOR_IN, PJ0_IOR_OUT,
+
+ PJ31MD_0, PJ31MD_1,
+ PJ30MD_000, PJ30MD_001, PJ30MD_010, PJ30MD_011,
+ PJ30MD_100, PJ30MD_101, PJ30MD_110, PJ30MD_111,
+ PJ29MD_000, PJ29MD_001, PJ29MD_010, PJ29MD_011,
+ PJ29MD_100, PJ29MD_101, PJ29MD_110, PJ29MD_111,
+ PJ28MD_000, PJ28MD_001, PJ28MD_010, PJ28MD_011,
+ PJ28MD_100, PJ28MD_101, PJ28MD_110, PJ28MD_111,
+
+ PJ27MD_000, PJ27MD_001, PJ27MD_010, PJ27MD_011,
+ PJ27MD_100, PJ27MD_101, PJ27MD_110, PJ27MD_111,
+ PJ26MD_000, PJ26MD_001, PJ26MD_010, PJ26MD_011,
+ PJ26MD_100, PJ26MD_101, PJ26MD_110, PJ26MD_111,
+ PJ25MD_000, PJ25MD_001, PJ25MD_010, PJ25MD_011,
+ PJ25MD_100, PJ25MD_101, PJ25MD_110, PJ25MD_111,
+ PJ24MD_000, PJ24MD_001, PJ24MD_010, PJ24MD_011,
+ PJ24MD_100, PJ24MD_101, PJ24MD_110, PJ24MD_111,
+
+ PJ23MD_000, PJ23MD_001, PJ23MD_010, PJ23MD_011,
+ PJ23MD_100, PJ23MD_101, PJ23MD_110, PJ23MD_111,
+ PJ22MD_000, PJ22MD_001, PJ22MD_010, PJ22MD_011,
+ PJ22MD_100, PJ22MD_101, PJ22MD_110, PJ22MD_111,
+ PJ21MD_000, PJ21MD_001, PJ21MD_010, PJ21MD_011,
+ PJ21MD_100, PJ21MD_101, PJ21MD_110, PJ21MD_111,
+ PJ20MD_000, PJ20MD_001, PJ20MD_010, PJ20MD_011,
+ PJ20MD_100, PJ20MD_101, PJ20MD_110, PJ20MD_111,
+
+ PJ19MD_000, PJ19MD_001, PJ19MD_010, PJ19MD_011,
+ PJ19MD_100, PJ19MD_101, PJ19MD_110, PJ19MD_111,
+ PJ18MD_000, PJ18MD_001, PJ18MD_010, PJ18MD_011,
+ PJ18MD_100, PJ18MD_101, PJ18MD_110, PJ18MD_111,
+ PJ17MD_000, PJ17MD_001, PJ17MD_010, PJ17MD_011,
+ PJ17MD_100, PJ17MD_101, PJ17MD_110, PJ17MD_111,
+ PJ16MD_000, PJ16MD_001, PJ16MD_010, PJ16MD_011,
+ PJ16MD_100, PJ16MD_101, PJ16MD_110, PJ16MD_111,
+
+ PJ15MD_000, PJ15MD_001, PJ15MD_010, PJ15MD_011,
+ PJ15MD_100, PJ15MD_101, PJ15MD_110, PJ15MD_111,
+ PJ14MD_000, PJ14MD_001, PJ14MD_010, PJ14MD_011,
+ PJ14MD_100, PJ14MD_101, PJ14MD_110, PJ14MD_111,
+ PJ13MD_000, PJ13MD_001, PJ13MD_010, PJ13MD_011,
+ PJ13MD_100, PJ13MD_101, PJ13MD_110, PJ13MD_111,
+ PJ12MD_000, PJ12MD_001, PJ12MD_010, PJ12MD_011,
+ PJ12MD_100, PJ12MD_101, PJ12MD_110, PJ12MD_111,
+
+ PJ11MD_000, PJ11MD_001, PJ11MD_010, PJ11MD_011,
+ PJ11MD_100, PJ11MD_101, PJ11MD_110, PJ11MD_111,
+ PJ10MD_000, PJ10MD_001, PJ10MD_010, PJ10MD_011,
+ PJ10MD_100, PJ10MD_101, PJ10MD_110, PJ10MD_111,
+ PJ9MD_000, PJ9MD_001, PJ9MD_010, PJ9MD_011,
+ PJ9MD_100, PJ9MD_101, PJ9MD_110, PJ9MD_111,
+ PJ8MD_000, PJ8MD_001, PJ8MD_010, PJ8MD_011,
+ PJ8MD_100, PJ8MD_101, PJ8MD_110, PJ8MD_111,
+
+ PJ7MD_000, PJ7MD_001, PJ7MD_010, PJ7MD_011,
+ PJ7MD_100, PJ7MD_101, PJ7MD_110, PJ7MD_111,
+ PJ6MD_000, PJ6MD_001, PJ6MD_010, PJ6MD_011,
+ PJ6MD_100, PJ6MD_101, PJ6MD_110, PJ6MD_111,
+ PJ5MD_000, PJ5MD_001, PJ5MD_010, PJ5MD_011,
+ PJ5MD_100, PJ5MD_101, PJ5MD_110, PJ5MD_111,
+ PJ4MD_000, PJ4MD_001, PJ4MD_010, PJ4MD_011,
+ PJ4MD_100, PJ4MD_101, PJ4MD_110, PJ4MD_111,
+
+ PJ3MD_000, PJ3MD_001, PJ3MD_010, PJ3MD_011,
+ PJ3MD_100, PJ3MD_101, PJ3MD_110, PJ3MD_111,
+ PJ2MD_000, PJ2MD_001, PJ2MD_010, PJ2MD_011,
+ PJ2MD_100, PJ2MD_101, PJ2MD_110, PJ2MD_111,
+ PJ1MD_000, PJ1MD_001, PJ1MD_010, PJ1MD_011,
+ PJ1MD_100, PJ1MD_101, PJ1MD_110, PJ1MD_111,
+ PJ0MD_000, PJ0MD_001, PJ0MD_010, PJ0MD_011,
+ PJ0MD_100, PJ0MD_101, PJ0MD_110, PJ0MD_111,
+
+ PINMUX_FUNCTION_END,
+
+ PINMUX_MARK_BEGIN,
+ /* Port H */
+ PHAN7_MARK, PHAN6_MARK, PHAN5_MARK, PHAN4_MARK,
+ PHAN3_MARK, PHAN2_MARK, PHAN1_MARK, PHAN0_MARK,
+
+ /* IRQs */
+ IRQ7_PG_MARK, IRQ6_PG_MARK, IRQ5_PG_MARK, IRQ4_PG_MARK,
+ IRQ3_PG_MARK, IRQ2_PG_MARK, IRQ1_PG_MARK, IRQ0_PG_MARK,
+ IRQ7_PF_MARK, IRQ6_PF_MARK, IRQ5_PF_MARK, IRQ4_PF_MARK,
+ IRQ3_PJ_MARK, IRQ2_PJ_MARK, IRQ1_PJ_MARK, IRQ0_PJ_MARK,
+ IRQ1_PC_MARK, IRQ0_PC_MARK,
+
+ PINT7_PG_MARK, PINT6_PG_MARK, PINT5_PG_MARK, PINT4_PG_MARK,
+ PINT3_PG_MARK, PINT2_PG_MARK, PINT1_PG_MARK, PINT0_PG_MARK,
+ PINT7_PH_MARK, PINT6_PH_MARK, PINT5_PH_MARK, PINT4_PH_MARK,
+ PINT3_PH_MARK, PINT2_PH_MARK, PINT1_PH_MARK, PINT0_PH_MARK,
+ PINT7_PJ_MARK, PINT6_PJ_MARK, PINT5_PJ_MARK, PINT4_PJ_MARK,
+ PINT3_PJ_MARK, PINT2_PJ_MARK, PINT1_PJ_MARK, PINT0_PJ_MARK,
+
+ /* SD */
+ SD_D0_MARK, SD_D1_MARK, SD_D2_MARK, SD_D3_MARK,
+ SD_WP_MARK, SD_CLK_MARK, SD_CMD_MARK, SD_CD_MARK,
+
+ /* MMC */
+ MMC_D0_MARK, MMC_D1_MARK, MMC_D2_MARK, MMC_D3_MARK,
+ MMC_D4_MARK, MMC_D5_MARK, MMC_D6_MARK, MMC_D7_MARK,
+ MMC_CLK_MARK, MMC_CMD_MARK, MMC_CD_MARK,
+
+ /* PWM */
+ PWM1A_MARK, PWM1B_MARK, PWM1C_MARK, PWM1D_MARK,
+ PWM1E_MARK, PWM1F_MARK, PWM1G_MARK, PWM1H_MARK,
+ PWM2A_MARK, PWM2B_MARK, PWM2C_MARK, PWM2D_MARK,
+ PWM2E_MARK, PWM2F_MARK, PWM2G_MARK, PWM2H_MARK,
+
+ /* IEBus */
+ IERXD_MARK, IETXD_MARK,
+
+ /* WDT */
+ WDTOVF_MARK,
+
+ /* DMAC */
+ TEND0_MARK, DACK0_MARK, DREQ0_MARK,
+ TEND1_MARK, DACK1_MARK, DREQ1_MARK,
+
+ /* ADC */
+ ADTRG_MARK,
+
+ /* BSC */
+ A25_MARK, A24_MARK,
+ A23_MARK, A22_MARK, A21_MARK, A20_MARK,
+ A19_MARK, A18_MARK, A17_MARK, A16_MARK,
+ A15_MARK, A14_MARK, A13_MARK, A12_MARK,
+ A11_MARK, A10_MARK, A9_MARK, A8_MARK,
+ A7_MARK, A6_MARK, A5_MARK, A4_MARK,
+ A3_MARK, A2_MARK, A1_MARK, A0_MARK,
+ D31_MARK, D30_MARK, D29_MARK, D28_MARK,
+ D27_MARK, D26_MARK, D25_MARK, D24_MARK,
+ D23_MARK, D22_MARK, D21_MARK, D20_MARK,
+ D19_MARK, D18_MARK, D17_MARK, D16_MARK,
+ D15_MARK, D14_MARK, D13_MARK, D12_MARK,
+ D11_MARK, D10_MARK, D9_MARK, D8_MARK,
+ D7_MARK, D6_MARK, D5_MARK, D4_MARK,
+ D3_MARK, D2_MARK, D1_MARK, D0_MARK,
+ BS_MARK,
+ CS4_MARK, CS3_MARK, CS2_MARK, CS1_MARK, CS0_MARK,
+ CS5CE1A_MARK,
+ CE2A_MARK, CE2B_MARK,
+ RD_MARK, RDWR_MARK,
+ WE3ICIOWRAHDQMUU_MARK,
+ WE2ICIORDDQMUL_MARK,
+ WE1DQMUWE_MARK,
+ WE0DQML_MARK,
+ RAS_MARK, CAS_MARK, CKE_MARK,
+ WAIT_MARK, BREQ_MARK, BACK_MARK, IOIS16_MARK,
+
+ /* TMU */
+ TIOC0A_MARK, TIOC0B_MARK, TIOC0C_MARK, TIOC0D_MARK,
+ TIOC1A_MARK, TIOC1B_MARK,
+ TIOC2A_MARK, TIOC2B_MARK,
+ TIOC3A_MARK, TIOC3B_MARK, TIOC3C_MARK, TIOC3D_MARK,
+ TIOC4A_MARK, TIOC4B_MARK, TIOC4C_MARK, TIOC4D_MARK,
+ TCLKA_MARK, TCLKB_MARK, TCLKC_MARK, TCLKD_MARK,
+
+ /* SCIF */
+ SCK0_MARK, RXD0_MARK, TXD0_MARK,
+ SCK1_MARK, RXD1_MARK, TXD1_MARK, RTS1_MARK, CTS1_MARK,
+ SCK2_MARK, RXD2_MARK, TXD2_MARK,
+ SCK3_MARK, RXD3_MARK, TXD3_MARK,
+ SCK4_MARK, RXD4_MARK, TXD4_MARK,
+ SCK5_MARK, RXD5_MARK, TXD5_MARK, RTS5_MARK, CTS5_MARK,
+ SCK6_MARK, RXD6_MARK, TXD6_MARK,
+ SCK7_MARK, RXD7_MARK, TXD7_MARK, RTS7_MARK, CTS7_MARK,
+
+ /* RSPI */
+ MISO0_PB20_MARK, MOSI0_PB19_MARK, SSL00_PB18_MARK, RSPCK0_PB17_MARK,
+ MISO0_PJ19_MARK, MOSI0_PJ18_MARK, SSL00_PJ17_MARK, RSPCK0_PJ16_MARK,
+ MISO1_MARK, MOSI1_MARK, SSL10_MARK, RSPCK1_MARK,
+
+ /* IIC3 */
+ SCL0_MARK, SDA0_MARK,
+ SCL1_MARK, SDA1_MARK,
+ SCL2_MARK, SDA2_MARK,
+ SCL3_MARK, SDA3_MARK,
+
+ /* SSI */
+ SSISCK0_MARK, SSIWS0_MARK, SSITXD0_MARK, SSIRXD0_MARK,
+ SSISCK1_MARK, SSIWS1_MARK, SSIDATA1_MARK,
+ SSISCK2_MARK, SSIWS2_MARK, SSIDATA2_MARK,
+ SSISCK3_MARK, SSIWS3_MARK, SSIDATA3_MARK,
+ SSISCK4_MARK, SSIWS4_MARK, SSIDATA4_MARK,
+ SSISCK5_MARK, SSIWS5_MARK, SSIDATA5_MARK,
+ AUDIO_CLK_MARK,
+ AUDIO_XOUT_MARK,
+
+ /* SIOF */ /* NOTE Shares AUDIO_CLK with SSI */
+ SIOFTXD_MARK, SIOFRXD_MARK, SIOFSYNC_MARK, SIOFSCK_MARK,
+
+ /* SPDIF */ /* NOTE Shares AUDIO_CLK with SSI */
+ SPDIF_IN_MARK, SPDIF_OUT_MARK,
+ SPDIF_IN_PJ24_MARK, SPDIF_OUT_PJ25_MARK,
+
+ /* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
+ FCE_MARK,
+ FRB_MARK,
+
+ /* CAN */
+ CRX0_MARK, CTX0_MARK,
+ CRX1_MARK, CTX1_MARK,
+ CRX2_MARK, CTX2_MARK,
+ CRX0CRX1_MARK,
+ CRX0CRX1CRX2_MARK,
+ CTX0CTX1CTX2_MARK,
+ CRX1_PJ22_MARK, CTX1_PJ23_MARK,
+ CRX2_PJ20_MARK, CTX2_PJ21_MARK,
+ CRX0CRX1_PJ22_MARK,
+ CRX0CRX1CRX2_PJ20_MARK,
+
+ /* VDC */
+ DV_CLK_MARK,
+ DV_VSYNC_MARK, DV_HSYNC_MARK,
+ DV_DATA23_MARK, DV_DATA22_MARK, DV_DATA21_MARK, DV_DATA20_MARK,
+ DV_DATA19_MARK, DV_DATA18_MARK, DV_DATA17_MARK, DV_DATA16_MARK,
+ DV_DATA15_MARK, DV_DATA14_MARK, DV_DATA13_MARK, DV_DATA12_MARK,
+ DV_DATA11_MARK, DV_DATA10_MARK, DV_DATA9_MARK, DV_DATA8_MARK,
+ DV_DATA7_MARK, DV_DATA6_MARK, DV_DATA5_MARK, DV_DATA4_MARK,
+ DV_DATA3_MARK, DV_DATA2_MARK, DV_DATA1_MARK, DV_DATA0_MARK,
+ LCD_CLK_MARK, LCD_EXTCLK_MARK,
+ LCD_VSYNC_MARK, LCD_HSYNC_MARK, LCD_DE_MARK,
+ LCD_DATA23_MARK, LCD_DATA22_MARK, LCD_DATA21_MARK, LCD_DATA20_MARK,
+ LCD_DATA19_MARK, LCD_DATA18_MARK, LCD_DATA17_MARK, LCD_DATA16_MARK,
+ LCD_DATA15_MARK, LCD_DATA14_MARK, LCD_DATA13_MARK, LCD_DATA12_MARK,
+ LCD_DATA11_MARK, LCD_DATA10_MARK, LCD_DATA9_MARK, LCD_DATA8_MARK,
+ LCD_DATA7_MARK, LCD_DATA6_MARK, LCD_DATA5_MARK, LCD_DATA4_MARK,
+ LCD_DATA3_MARK, LCD_DATA2_MARK, LCD_DATA1_MARK, LCD_DATA0_MARK,
+ LCD_TCON6_MARK, LCD_TCON5_MARK, LCD_TCON4_MARK,
+ LCD_TCON3_MARK, LCD_TCON2_MARK, LCD_TCON1_MARK, LCD_TCON0_MARK,
+ LCD_M_DISP_MARK,
+ PINMUX_MARK_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+
+ /* Port A */
+ PINMUX_DATA(PA1_DATA, PA1_IN),
+ PINMUX_DATA(PA0_DATA, PA0_IN),
+
+ /* Port B */
+ PINMUX_DATA(PB22_DATA, PB22MD_000, PB22_IN, PB22_OUT),
+ PINMUX_DATA(A22_MARK, PB22MD_001),
+ PINMUX_DATA(CTX2_MARK, PB22MD_010),
+ PINMUX_DATA(IETXD_MARK, PB22MD_011),
+ PINMUX_DATA(CS4_MARK, PB22MD_100),
+
+ PINMUX_DATA(PB21_DATA, PB21MD_00, PB21_IN, PB21_OUT),
+ PINMUX_DATA(A21_MARK, PB21MD_01),
+ PINMUX_DATA(CRX2_MARK, PB21MD_10),
+ PINMUX_DATA(IERXD_MARK, PB21MD_11),
+
+ PINMUX_DATA(A20_MARK, PB20MD_001),
+ PINMUX_DATA(A19_MARK, PB19MD_001),
+ PINMUX_DATA(A18_MARK, PB18MD_001),
+ PINMUX_DATA(A17_MARK, PB17MD_001),
+ PINMUX_DATA(A16_MARK, PB16MD_001),
+ PINMUX_DATA(A15_MARK, PB15MD_001),
+ PINMUX_DATA(A14_MARK, PB14MD_001),
+ PINMUX_DATA(A13_MARK, PB13MD_001),
+ PINMUX_DATA(A12_MARK, PB12MD_01),
+ PINMUX_DATA(A11_MARK, PB11MD_01),
+ PINMUX_DATA(A10_MARK, PB10MD_01),
+ PINMUX_DATA(A9_MARK, PB9MD_01),
+ PINMUX_DATA(A8_MARK, PB8MD_01),
+ PINMUX_DATA(A7_MARK, PB7MD_01),
+ PINMUX_DATA(A6_MARK, PB6MD_01),
+ PINMUX_DATA(A5_MARK, PB5MD_01),
+ PINMUX_DATA(A4_MARK, PB4MD_01),
+ PINMUX_DATA(A3_MARK, PB3MD_01),
+ PINMUX_DATA(A2_MARK, PB2MD_01),
+ PINMUX_DATA(A1_MARK, PB1MD_01),
+
+ /* Port C */
+ PINMUX_DATA(PC8_DATA, PC8MD_000),
+ PINMUX_DATA(CS3_MARK, PC8MD_001),
+ PINMUX_DATA(TXD7_MARK, PC8MD_010),
+ PINMUX_DATA(CTX1_MARK, PC8MD_011),
+
+ PINMUX_DATA(PC7_DATA, PC7MD_000),
+ PINMUX_DATA(CKE_MARK, PC7MD_001),
+ PINMUX_DATA(RXD7_MARK, PC7MD_010),
+ PINMUX_DATA(CRX1_MARK, PC7MD_011),
+ PINMUX_DATA(CRX0CRX1_MARK, PC7MD_100),
+ PINMUX_DATA(IRQ1_PC_MARK, PC7MD_101),
+
+ PINMUX_DATA(PC6_DATA, PC6MD_000),
+ PINMUX_DATA(CAS_MARK, PC6MD_001),
+ PINMUX_DATA(SCK7_MARK, PC6MD_010),
+ PINMUX_DATA(CTX0_MARK, PC6MD_011),
+
+ PINMUX_DATA(PC5_DATA, PC5MD_000),
+ PINMUX_DATA(RAS_MARK, PC5MD_001),
+ PINMUX_DATA(CRX0_MARK, PC5MD_011),
+ PINMUX_DATA(CTX0CTX1CTX2_MARK, PC5MD_100),
+ PINMUX_DATA(IRQ0_PC_MARK, PC5MD_101),
+
+ PINMUX_DATA(PC4_DATA, PC4MD_00),
+ PINMUX_DATA(WE1DQMUWE_MARK, PC4MD_01),
+ PINMUX_DATA(TXD6_MARK, PC4MD_10),
+
+ PINMUX_DATA(PC3_DATA, PC3MD_00),
+ PINMUX_DATA(WE0DQML_MARK, PC3MD_01),
+ PINMUX_DATA(RXD6_MARK, PC3MD_10),
+
+ PINMUX_DATA(PC2_DATA, PC2MD_00),
+ PINMUX_DATA(RDWR_MARK, PC2MD_01),
+ PINMUX_DATA(SCK5_MARK, PC2MD_10),
+
+ PINMUX_DATA(PC1_DATA, PC1MD_0),
+ PINMUX_DATA(RD_MARK, PC1MD_1),
+
+ PINMUX_DATA(PC0_DATA, PC0MD_0),
+ PINMUX_DATA(CS0_MARK, PC0MD_1),
+
+ /* Port D */
+ PINMUX_DATA(D15_MARK, PD15MD_01),
+ PINMUX_DATA(D14_MARK, PD14MD_01),
+
+ PINMUX_DATA(PD13_DATA, PD13MD_00),
+ PINMUX_DATA(D13_MARK, PD13MD_01),
+ PINMUX_DATA(PWM2F_MARK, PD13MD_10),
+
+ PINMUX_DATA(PD12_DATA, PD12MD_00),
+ PINMUX_DATA(D12_MARK, PD12MD_01),
+ PINMUX_DATA(PWM2E_MARK, PD12MD_10),
+
+ PINMUX_DATA(D11_MARK, PD11MD_01),
+ PINMUX_DATA(D10_MARK, PD10MD_01),
+ PINMUX_DATA(D9_MARK, PD9MD_01),
+ PINMUX_DATA(D8_MARK, PD8MD_01),
+ PINMUX_DATA(D7_MARK, PD7MD_01),
+ PINMUX_DATA(D6_MARK, PD6MD_01),
+ PINMUX_DATA(D5_MARK, PD5MD_01),
+ PINMUX_DATA(D4_MARK, PD4MD_01),
+ PINMUX_DATA(D3_MARK, PD3MD_01),
+ PINMUX_DATA(D2_MARK, PD2MD_01),
+ PINMUX_DATA(D1_MARK, PD1MD_01),
+ PINMUX_DATA(D0_MARK, PD0MD_01),
+
+ /* Port E */
+ PINMUX_DATA(PE7_DATA, PE7MD_00),
+ PINMUX_DATA(SDA3_MARK, PE7MD_01),
+ PINMUX_DATA(RXD7_MARK, PE7MD_10),
+
+ PINMUX_DATA(PE6_DATA, PE6MD_00),
+ PINMUX_DATA(SCL3_MARK, PE6MD_01),
+ PINMUX_DATA(RXD6_MARK, PE6MD_10),
+
+ PINMUX_DATA(PE5_DATA, PE5MD_00),
+ PINMUX_DATA(SDA2_MARK, PE5MD_01),
+ PINMUX_DATA(RXD5_MARK, PE5MD_10),
+ PINMUX_DATA(DV_HSYNC_MARK, PE5MD_11),
+
+ PINMUX_DATA(PE4_DATA, PE4MD_00),
+ PINMUX_DATA(SCL2_MARK, PE4MD_01),
+ PINMUX_DATA(DV_VSYNC_MARK, PE4MD_11),
+
+ PINMUX_DATA(PE3_DATA, PE3MD_000),
+ PINMUX_DATA(SDA1_MARK, PE3MD_001),
+ PINMUX_DATA(TCLKD_MARK, PE3MD_010),
+ PINMUX_DATA(ADTRG_MARK, PE3MD_011),
+ PINMUX_DATA(DV_HSYNC_MARK, PE3MD_100),
+
+ PINMUX_DATA(PE2_DATA, PE2MD_000),
+ PINMUX_DATA(SCL1_MARK, PE2MD_001),
+ PINMUX_DATA(TCLKD_MARK, PE2MD_010),
+ PINMUX_DATA(IOIS16_MARK, PE2MD_011),
+ PINMUX_DATA(DV_VSYNC_MARK, PE2MD_100),
+
+ PINMUX_DATA(PE1_DATA, PE1MD_000),
+ PINMUX_DATA(SDA0_MARK, PE1MD_001),
+ PINMUX_DATA(TCLKB_MARK, PE1MD_010),
+ PINMUX_DATA(AUDIO_CLK_MARK, PE1MD_010),
+ PINMUX_DATA(DV_CLK_MARK, PE1MD_100),
+
+ PINMUX_DATA(PE0_DATA, PE0MD_00),
+ PINMUX_DATA(SCL0_MARK, PE0MD_01),
+ PINMUX_DATA(TCLKA_MARK, PE0MD_10),
+ PINMUX_DATA(LCD_EXTCLK_MARK, PE0MD_11),
+
+ /* Port F */
+ PINMUX_DATA(PF23_DATA, PF23MD_000),
+ PINMUX_DATA(SD_D2_MARK, PF23MD_001),
+ PINMUX_DATA(TXD3_MARK, PF23MD_100),
+ PINMUX_DATA(MMC_D2_MARK, PF23MD_101),
+
+ PINMUX_DATA(PF22_DATA, PF22MD_000),
+ PINMUX_DATA(SD_D3_MARK, PF22MD_001),
+ PINMUX_DATA(RXD3_MARK, PF22MD_100),
+ PINMUX_DATA(MMC_D3_MARK, PF22MD_101),
+
+ PINMUX_DATA(PF21_DATA, PF21MD_000),
+ PINMUX_DATA(SD_CMD_MARK, PF21MD_001),
+ PINMUX_DATA(SCK3_MARK, PF21MD_100),
+ PINMUX_DATA(MMC_CMD_MARK, PF21MD_101),
+
+ PINMUX_DATA(PF20_DATA, PF20MD_000),
+ PINMUX_DATA(SD_CLK_MARK, PF20MD_001),
+ PINMUX_DATA(SSIDATA3_MARK, PF20MD_010),
+ PINMUX_DATA(MMC_CLK_MARK, PF20MD_101),
+
+ PINMUX_DATA(PF19_DATA, PF19MD_000),
+ PINMUX_DATA(SD_D0_MARK, PF19MD_001),
+ PINMUX_DATA(SSIWS3_MARK, PF19MD_010),
+ PINMUX_DATA(IRQ7_PF_MARK, PF19MD_100),
+ PINMUX_DATA(MMC_D0_MARK, PF19MD_101),
+
+ PINMUX_DATA(PF18_DATA, PF18MD_000),
+ PINMUX_DATA(SD_D1_MARK, PF18MD_001),
+ PINMUX_DATA(SSISCK3_MARK, PF18MD_010),
+ PINMUX_DATA(IRQ6_PF_MARK, PF18MD_100),
+ PINMUX_DATA(MMC_D1_MARK, PF18MD_101),
+
+ PINMUX_DATA(PF17_DATA, PF17MD_000),
+ PINMUX_DATA(SD_WP_MARK, PF17MD_001),
+ PINMUX_DATA(FRB_MARK, PF17MD_011),
+ PINMUX_DATA(IRQ5_PF_MARK, PF17MD_100),
+
+ PINMUX_DATA(PF16_DATA, PF16MD_000),
+ PINMUX_DATA(SD_CD_MARK, PF16MD_001),
+ PINMUX_DATA(FCE_MARK, PF16MD_011),
+ PINMUX_DATA(IRQ4_PF_MARK, PF16MD_100),
+ PINMUX_DATA(MMC_CD_MARK, PF16MD_101),
+
+ PINMUX_DATA(PF15_DATA, PF15MD_000),
+ PINMUX_DATA(A0_MARK, PF15MD_001),
+ PINMUX_DATA(SSIDATA2_MARK, PF15MD_010),
+ PINMUX_DATA(WDTOVF_MARK, PF15MD_011),
+ PINMUX_DATA(TXD2_MARK, PF15MD_100),
+
+ PINMUX_DATA(PF14_DATA, PF14MD_000),
+ PINMUX_DATA(A25_MARK, PF14MD_001),
+ PINMUX_DATA(SSIWS2_MARK, PF14MD_010),
+ PINMUX_DATA(RXD2_MARK, PF14MD_100),
+
+ PINMUX_DATA(PF13_DATA, PF13MD_000),
+ PINMUX_DATA(A24_MARK, PF13MD_001),
+ PINMUX_DATA(SSISCK2_MARK, PF13MD_010),
+ PINMUX_DATA(SCK2_MARK, PF13MD_100),
+
+ PINMUX_DATA(PF12_DATA, PF12MD_000),
+ PINMUX_DATA(SSIDATA1_MARK, PF12MD_010),
+ PINMUX_DATA(DV_DATA12_MARK, PF12MD_011),
+ PINMUX_DATA(TXD1_MARK, PF12MD_100),
+ PINMUX_DATA(MMC_D7_MARK, PF12MD_101),
+
+ PINMUX_DATA(PF11_DATA, PF11MD_000),
+ PINMUX_DATA(SSIWS1_MARK, PF11MD_010),
+ PINMUX_DATA(DV_DATA2_MARK, PF11MD_011),
+ PINMUX_DATA(RXD1_MARK, PF11MD_100),
+ PINMUX_DATA(MMC_D6_MARK, PF11MD_101),
+
+ PINMUX_DATA(PF10_DATA, PF10MD_000),
+ PINMUX_DATA(CS1_MARK, PF10MD_001),
+ PINMUX_DATA(SSISCK1_MARK, PF10MD_010),
+ PINMUX_DATA(DV_DATA1_MARK, PF10MD_011),
+ PINMUX_DATA(SCK1_MARK, PF10MD_100),
+ PINMUX_DATA(MMC_D5_MARK, PF10MD_101),
+
+ PINMUX_DATA(PF9_DATA, PF9MD_000),
+ PINMUX_DATA(BS_MARK, PF9MD_001),
+ PINMUX_DATA(DV_DATA0_MARK, PF9MD_011),
+ PINMUX_DATA(SCK0_MARK, PF9MD_100),
+ PINMUX_DATA(MMC_D4_MARK, PF9MD_101),
+ PINMUX_DATA(RTS1_MARK, PF9MD_110),
+
+ PINMUX_DATA(PF8_DATA, PF8MD_000),
+ PINMUX_DATA(A23_MARK, PF8MD_001),
+ PINMUX_DATA(TXD0_MARK, PF8MD_100),
+
+ PINMUX_DATA(PF7_DATA, PF7MD_000),
+ PINMUX_DATA(SSIRXD0_MARK, PF7MD_010),
+ PINMUX_DATA(RXD0_MARK, PF7MD_100),
+ PINMUX_DATA(CTS1_MARK, PF7MD_110),
+
+ PINMUX_DATA(PF6_DATA, PF6MD_000),
+ PINMUX_DATA(CE2A_MARK, PF6MD_001),
+ PINMUX_DATA(SSITXD0_MARK, PF6MD_010),
+
+ PINMUX_DATA(PF5_DATA, PF5MD_000),
+ PINMUX_DATA(SSIWS0_MARK, PF5MD_010),
+
+ PINMUX_DATA(PF4_DATA, PF4MD_000),
+ PINMUX_DATA(CS5CE1A_MARK, PF4MD_001),
+ PINMUX_DATA(SSISCK0_MARK, PF4MD_010),
+
+ PINMUX_DATA(PF3_DATA, PF3MD_000),
+ PINMUX_DATA(CS2_MARK, PF3MD_001),
+ PINMUX_DATA(MISO1_MARK, PF3MD_011),
+ PINMUX_DATA(TIOC4D_MARK, PF3MD_100),
+
+ PINMUX_DATA(PF2_DATA, PF2MD_000),
+ PINMUX_DATA(WAIT_MARK, PF2MD_001),
+ PINMUX_DATA(MOSI1_MARK, PF2MD_011),
+ PINMUX_DATA(TIOC4C_MARK, PF2MD_100),
+ PINMUX_DATA(TEND0_MARK, PF2MD_101),
+
+ PINMUX_DATA(PF1_DATA, PF1MD_000),
+ PINMUX_DATA(BACK_MARK, PF1MD_001),
+ PINMUX_DATA(TIOC4B_MARK, PF1MD_100),
+ PINMUX_DATA(DACK0_MARK, PF1MD_101),
+
+ PINMUX_DATA(PF0_DATA, PF0MD_000),
+ PINMUX_DATA(BREQ_MARK, PF0MD_001),
+ PINMUX_DATA(RSPCK1_MARK, PF0MD_011),
+ PINMUX_DATA(TIOC4A_MARK, PF0MD_100),
+ PINMUX_DATA(DREQ0_MARK, PF0MD_101),
+
+ /* Port G */
+ PINMUX_DATA(PG27_DATA, PG27MD_00),
+ PINMUX_DATA(LCD_TCON2_MARK, PG27MD_10),
+ PINMUX_DATA(LCD_EXTCLK_MARK, PG27MD_11),
+
+ PINMUX_DATA(PG26_DATA, PG26MD_00),
+ PINMUX_DATA(LCD_TCON1_MARK, PG26MD_10),
+
+ PINMUX_DATA(PG25_DATA, PG25MD_00),
+ PINMUX_DATA(LCD_TCON0_MARK, PG25MD_10),
+
+ PINMUX_DATA(PG24_DATA, PG24MD_00),
+ PINMUX_DATA(LCD_CLK_MARK, PG24MD_10),
+
+ PINMUX_DATA(PG23_DATA, PG23MD_000),
+ PINMUX_DATA(LCD_DATA23_MARK, PG23MD_010),
+ PINMUX_DATA(LCD_TCON6_MARK, PG23MD_011),
+ PINMUX_DATA(TXD5_MARK, PG23MD_100),
+
+ PINMUX_DATA(PG22_DATA, PG22MD_000),
+ PINMUX_DATA(LCD_DATA22_MARK, PG22MD_010),
+ PINMUX_DATA(LCD_TCON5_MARK, PG22MD_011),
+ PINMUX_DATA(RXD5_MARK, PG22MD_100),
+
+ PINMUX_DATA(PG21_DATA, PG21MD_000),
+ PINMUX_DATA(DV_DATA7_MARK, PG21MD_001),
+ PINMUX_DATA(LCD_DATA21_MARK, PG21MD_010),
+ PINMUX_DATA(LCD_TCON4_MARK, PG21MD_011),
+ PINMUX_DATA(TXD4_MARK, PG21MD_100),
+
+ PINMUX_DATA(PG20_DATA, PG20MD_000),
+ PINMUX_DATA(DV_DATA6_MARK, PG20MD_001),
+ PINMUX_DATA(LCD_DATA20_MARK, PG21MD_010),
+ PINMUX_DATA(LCD_TCON3_MARK, PG20MD_011),
+ PINMUX_DATA(RXD4_MARK, PG20MD_100),
+
+ PINMUX_DATA(PG19_DATA, PG19MD_000),
+ PINMUX_DATA(DV_DATA5_MARK, PG19MD_001),
+ PINMUX_DATA(LCD_DATA19_MARK, PG19MD_010),
+ PINMUX_DATA(SPDIF_OUT_MARK, PG19MD_011),
+ PINMUX_DATA(SCK5_MARK, PG19MD_100),
+
+ PINMUX_DATA(PG18_DATA, PG18MD_000),
+ PINMUX_DATA(DV_DATA4_MARK, PG18MD_001),
+ PINMUX_DATA(LCD_DATA18_MARK, PG18MD_010),
+ PINMUX_DATA(SPDIF_IN_MARK, PG18MD_011),
+ PINMUX_DATA(SCK4_MARK, PG18MD_100),
+
+// TODO hardware manual has PG17 3 bits wide in reg picture and 2 bits in description
+// we're going with 2 bits
+ PINMUX_DATA(PG17_DATA, PG17MD_00),
+ PINMUX_DATA(WE3ICIOWRAHDQMUU_MARK, PG17MD_01),
+ PINMUX_DATA(LCD_DATA17_MARK, PG17MD_10),
+
+// TODO hardware manual has PG16 3 bits wide in reg picture and 2 bits in description
+// we're going with 2 bits
+ PINMUX_DATA(PG16_DATA, PG16MD_00),
+ PINMUX_DATA(WE2ICIORDDQMUL_MARK, PG16MD_01),
+ PINMUX_DATA(LCD_DATA16_MARK, PG16MD_10),
+
+ PINMUX_DATA(PG15_DATA, PG15MD_00),
+ PINMUX_DATA(D31_MARK, PG15MD_01),
+ PINMUX_DATA(LCD_DATA15_MARK, PG15MD_10),
+ PINMUX_DATA(PINT7_PG_MARK, PG15MD_11),
+
+ PINMUX_DATA(PG14_DATA, PG14MD_00),
+ PINMUX_DATA(D30_MARK, PG14MD_01),
+ PINMUX_DATA(LCD_DATA14_MARK, PG14MD_10),
+ PINMUX_DATA(PINT6_PG_MARK, PG14MD_11),
+
+ PINMUX_DATA(PG13_DATA, PG13MD_00),
+ PINMUX_DATA(D29_MARK, PG13MD_01),
+ PINMUX_DATA(LCD_DATA13_MARK, PG13MD_10),
+ PINMUX_DATA(PINT5_PG_MARK, PG13MD_11),
+
+ PINMUX_DATA(PG12_DATA, PG12MD_00),
+ PINMUX_DATA(D28_MARK, PG12MD_01),
+ PINMUX_DATA(LCD_DATA12_MARK, PG12MD_10),
+ PINMUX_DATA(PINT4_PG_MARK, PG12MD_11),
+
+ PINMUX_DATA(PG11_DATA, PG11MD_000),
+ PINMUX_DATA(D27_MARK, PG11MD_001),
+ PINMUX_DATA(LCD_DATA11_MARK, PG11MD_010),
+ PINMUX_DATA(PINT3_PG_MARK, PG11MD_011),
+ PINMUX_DATA(TIOC3D_MARK, PG11MD_100),
+
+ PINMUX_DATA(PG10_DATA, PG10MD_000),
+ PINMUX_DATA(D26_MARK, PG10MD_001),
+ PINMUX_DATA(LCD_DATA10_MARK, PG10MD_010),
+ PINMUX_DATA(PINT2_PG_MARK, PG10MD_011),
+ PINMUX_DATA(TIOC3C_MARK, PG10MD_100),
+
+ PINMUX_DATA(PG9_DATA, PG9MD_000),
+ PINMUX_DATA(D25_MARK, PG9MD_001),
+ PINMUX_DATA(LCD_DATA9_MARK, PG9MD_010),
+ PINMUX_DATA(PINT1_PG_MARK, PG9MD_011),
+ PINMUX_DATA(TIOC3B_MARK, PG9MD_100),
+
+ PINMUX_DATA(PG8_DATA, PG8MD_000),
+ PINMUX_DATA(D24_MARK, PG8MD_001),
+ PINMUX_DATA(LCD_DATA8_MARK, PG8MD_010),
+ PINMUX_DATA(PINT0_PG_MARK, PG8MD_011),
+ PINMUX_DATA(TIOC3A_MARK, PG8MD_100),
+
+ PINMUX_DATA(PG7_DATA, PG7MD_000),
+ PINMUX_DATA(D23_MARK, PG7MD_001),
+ PINMUX_DATA(LCD_DATA7_MARK, PG7MD_010),
+ PINMUX_DATA(IRQ7_PG_MARK, PG7MD_011),
+ PINMUX_DATA(TIOC2B_MARK, PG7MD_100),
+
+ PINMUX_DATA(PG6_DATA, PG6MD_000),
+ PINMUX_DATA(D22_MARK, PG6MD_001),
+ PINMUX_DATA(LCD_DATA6_MARK, PG6MD_010),
+ PINMUX_DATA(IRQ6_PG_MARK, PG6MD_011),
+ PINMUX_DATA(TIOC2A_MARK, PG6MD_100),
+
+ PINMUX_DATA(PG5_DATA, PG5MD_000),
+ PINMUX_DATA(D21_MARK, PG5MD_001),
+ PINMUX_DATA(LCD_DATA5_MARK, PG5MD_010),
+ PINMUX_DATA(IRQ5_PG_MARK, PG5MD_011),
+ PINMUX_DATA(TIOC1B_MARK, PG5MD_100),
+
+ PINMUX_DATA(PG4_DATA, PG4MD_000),
+ PINMUX_DATA(D20_MARK, PG4MD_001),
+ PINMUX_DATA(LCD_DATA4_MARK, PG4MD_010),
+ PINMUX_DATA(IRQ4_PG_MARK, PG4MD_011),
+ PINMUX_DATA(TIOC1A_MARK, PG4MD_100),
+
+ PINMUX_DATA(PG3_DATA, PG3MD_000),
+ PINMUX_DATA(D19_MARK, PG3MD_001),
+ PINMUX_DATA(LCD_DATA3_MARK, PG3MD_010),
+ PINMUX_DATA(IRQ3_PG_MARK, PG3MD_011),
+ PINMUX_DATA(TIOC0D_MARK, PG3MD_100),
+
+ PINMUX_DATA(PG2_DATA, PG2MD_000),
+ PINMUX_DATA(D18_MARK, PG2MD_001),
+ PINMUX_DATA(LCD_DATA2_MARK, PG2MD_010),
+ PINMUX_DATA(IRQ2_PG_MARK, PG2MD_011),
+ PINMUX_DATA(TIOC0C_MARK, PG2MD_100),
+
+ PINMUX_DATA(PG1_DATA, PG1MD_000),
+ PINMUX_DATA(D17_MARK, PG1MD_001),
+ PINMUX_DATA(LCD_DATA1_MARK, PG1MD_010),
+ PINMUX_DATA(IRQ1_PG_MARK, PG1MD_011),
+ PINMUX_DATA(TIOC0B_MARK, PG1MD_100),
+
+ PINMUX_DATA(PG0_DATA, PG0MD_000),
+ PINMUX_DATA(D16_MARK, PG0MD_001),
+ PINMUX_DATA(LCD_DATA0_MARK, PG0MD_010),
+ PINMUX_DATA(IRQ0_PG_MARK, PG0MD_011),
+ PINMUX_DATA(TIOC0A_MARK, PG0MD_100),
+
+ /* Port H */
+ PINMUX_DATA(PH7_DATA, PH7MD_00),
+ PINMUX_DATA(PHAN7_MARK, PH7MD_01),
+ PINMUX_DATA(PINT7_PH_MARK, PH7MD_10),
+
+ PINMUX_DATA(PH6_DATA, PH6MD_00),
+ PINMUX_DATA(PHAN6_MARK, PH6MD_01),
+ PINMUX_DATA(PINT6_PH_MARK, PH6MD_10),
+
+ PINMUX_DATA(PH5_DATA, PH5MD_00),
+ PINMUX_DATA(PHAN5_MARK, PH5MD_01),
+ PINMUX_DATA(PINT5_PH_MARK, PH5MD_10),
+ PINMUX_DATA(LCD_EXTCLK_MARK, PH5MD_11),
+
+ PINMUX_DATA(PH4_DATA, PH4MD_00),
+ PINMUX_DATA(PHAN4_MARK, PH4MD_01),
+ PINMUX_DATA(PINT4_PH_MARK, PH4MD_10),
+
+ PINMUX_DATA(PH3_DATA, PH3MD_00),
+ PINMUX_DATA(PHAN3_MARK, PH3MD_01),
+ PINMUX_DATA(PINT3_PH_MARK, PH3MD_10),
+
+ PINMUX_DATA(PH2_DATA, PH2MD_00),
+ PINMUX_DATA(PHAN2_MARK, PH2MD_01),
+ PINMUX_DATA(PINT2_PH_MARK, PH2MD_10),
+
+ PINMUX_DATA(PH1_DATA, PH1MD_00),
+ PINMUX_DATA(PHAN1_MARK, PH1MD_01),
+ PINMUX_DATA(PINT1_PH_MARK, PH1MD_10),
+
+ PINMUX_DATA(PH0_DATA, PH0MD_00),
+ PINMUX_DATA(PHAN0_MARK, PH0MD_01),
+ PINMUX_DATA(PINT0_PH_MARK, PH0MD_10),
+
+ /* Port I - not on device */
+
+ /* Port J */
+ PINMUX_DATA(PJ31_DATA, PJ31MD_0),
+ PINMUX_DATA(DV_CLK_MARK, PJ31MD_1),
+
+ PINMUX_DATA(PJ30_DATA, PJ30MD_000),
+ PINMUX_DATA(SSIDATA5_MARK, PJ30MD_010),
+ PINMUX_DATA(TIOC2B_MARK, PJ30MD_100),
+ PINMUX_DATA(IETXD_MARK, PJ30MD_101),
+
+ PINMUX_DATA(PJ29_DATA, PJ29MD_000),
+ PINMUX_DATA(SSIWS5_MARK, PJ29MD_010),
+ PINMUX_DATA(TIOC2A_MARK, PJ29MD_100),
+ PINMUX_DATA(IERXD_MARK, PJ29MD_101),
+
+ PINMUX_DATA(PJ28_DATA, PJ28MD_000),
+ PINMUX_DATA(SSISCK5_MARK, PJ28MD_010),
+ PINMUX_DATA(TIOC1B_MARK, PJ28MD_100),
+ PINMUX_DATA(RTS7_MARK, PJ28MD_101),
+
+ PINMUX_DATA(PJ27_DATA, PJ27MD_000),
+ PINMUX_DATA(TIOC1A_MARK, PJ27MD_100),
+ PINMUX_DATA(CTS7_MARK, PJ27MD_101),
+
+ PINMUX_DATA(PJ26_DATA, PJ26MD_000),
+ PINMUX_DATA(SSIDATA4_MARK, PJ26MD_010),
+ PINMUX_DATA(LCD_TCON5_MARK, PJ26MD_011),
+ PINMUX_DATA(TXD7_MARK, PJ26MD_101),
+
+ PINMUX_DATA(PJ25_DATA, PJ25MD_000),
+ PINMUX_DATA(SSIWS4_MARK, PJ25MD_010),
+ PINMUX_DATA(LCD_TCON4_MARK, PJ25MD_011),
+ PINMUX_DATA(SPDIF_OUT_MARK, PJ25MD_100),
+ PINMUX_DATA(RXD7_MARK, PJ25MD_101),
+
+ PINMUX_DATA(PJ24_DATA, PJ24MD_000),
+ PINMUX_DATA(SSISCK4_MARK, PJ24MD_010),
+ PINMUX_DATA(LCD_TCON3_MARK, PJ24MD_011),
+ PINMUX_DATA(SPDIF_IN_MARK, PJ24MD_100),
+ PINMUX_DATA(SCK7_MARK, PJ24MD_101),
+
+ PINMUX_DATA(PJ23_DATA, PJ23MD_000),
+ PINMUX_DATA(DV_DATA23_MARK, PJ23MD_001),
+ PINMUX_DATA(LCD_DATA23_MARK, PJ23MD_010),
+ PINMUX_DATA(LCD_TCON6_MARK, PJ23MD_011),
+ PINMUX_DATA(IRQ3_PJ_MARK, PJ23MD_100),
+ PINMUX_DATA(CTX1_MARK, PJ23MD_101),
+
+ PINMUX_DATA(PJ22_DATA, PJ22MD_000),
+ PINMUX_DATA(DV_DATA22_MARK, PJ22MD_001),
+ PINMUX_DATA(LCD_DATA22_MARK, PJ22MD_010),
+ PINMUX_DATA(LCD_TCON5_MARK, PJ22MD_011),
+ PINMUX_DATA(IRQ2_PJ_MARK, PJ22MD_100),
+ PINMUX_DATA(CRX1_MARK, PJ22MD_101),
+ PINMUX_DATA(CRX0CRX1_MARK, PJ22MD_110),
+
+ PINMUX_DATA(PJ21_DATA, PJ21MD_000),
+ PINMUX_DATA(DV_DATA21_MARK, PJ21MD_001),
+ PINMUX_DATA(LCD_DATA21_MARK, PJ21MD_010),
+ PINMUX_DATA(LCD_TCON4_MARK, PJ21MD_011),
+ PINMUX_DATA(IRQ1_PJ_MARK, PJ21MD_100),
+ PINMUX_DATA(CTX2_MARK, PJ21MD_101),
+
+ PINMUX_DATA(PJ20_DATA, PJ20MD_000),
+ PINMUX_DATA(DV_DATA20_MARK, PJ20MD_001),
+ PINMUX_DATA(LCD_DATA20_MARK, PJ20MD_010),
+ PINMUX_DATA(LCD_TCON3_MARK, PJ20MD_011),
+ PINMUX_DATA(IRQ0_PJ_MARK, PJ20MD_100),
+ PINMUX_DATA(CRX2_MARK, PJ20MD_101),
+ PINMUX_DATA(CRX0CRX1CRX2_PJ20_MARK, PJ20MD_110),
+
+ PINMUX_DATA(PJ19_DATA, PJ19MD_000),
+ PINMUX_DATA(DV_DATA19_MARK, PJ19MD_001),
+ PINMUX_DATA(LCD_DATA19_MARK, PJ19MD_010),
+ PINMUX_DATA(MISO0_PJ19_MARK, PJ19MD_011),
+ PINMUX_DATA(TIOC0D_MARK, PJ19MD_100),
+ PINMUX_DATA(SIOFRXD_MARK, PJ19MD_101),
+ PINMUX_DATA(AUDIO_XOUT_MARK, PJ19MD_110),
+
+ PINMUX_DATA(PJ18_DATA, PJ18MD_000),
+ PINMUX_DATA(DV_DATA18_MARK, PJ18MD_001),
+ PINMUX_DATA(LCD_DATA18_MARK, PJ18MD_010),
+ PINMUX_DATA(MOSI0_PJ18_MARK, PJ18MD_011),
+ PINMUX_DATA(TIOC0C_MARK, PJ18MD_100),
+ PINMUX_DATA(SIOFTXD_MARK, PJ18MD_101),
+
+ PINMUX_DATA(PJ17_DATA, PJ17MD_000),
+ PINMUX_DATA(DV_DATA17_MARK, PJ17MD_001),
+ PINMUX_DATA(LCD_DATA17_MARK, PJ17MD_010),
+ PINMUX_DATA(SSL00_PJ17_MARK, PJ17MD_011),
+ PINMUX_DATA(TIOC0B_MARK, PJ17MD_100),
+ PINMUX_DATA(SIOFSYNC_MARK, PJ17MD_101),
+
+ PINMUX_DATA(PJ16_DATA, PJ16MD_000),
+ PINMUX_DATA(DV_DATA16_MARK, PJ16MD_001),
+ PINMUX_DATA(LCD_DATA16_MARK, PJ16MD_010),
+ PINMUX_DATA(RSPCK0_PJ16_MARK, PJ16MD_011),
+ PINMUX_DATA(TIOC0A_MARK, PJ16MD_100),
+ PINMUX_DATA(SIOFSCK_MARK, PJ16MD_101),
+
+ PINMUX_DATA(PJ15_DATA, PJ15MD_000),
+ PINMUX_DATA(DV_DATA15_MARK, PJ15MD_001),
+ PINMUX_DATA(LCD_DATA15_MARK, PJ15MD_010),
+ PINMUX_DATA(PINT7_PJ_MARK, PJ15MD_011),
+ PINMUX_DATA(PWM2H_MARK, PJ15MD_100),
+ PINMUX_DATA(TXD7_MARK, PJ15MD_101),
+
+ PINMUX_DATA(PJ14_DATA, PJ14MD_000),
+ PINMUX_DATA(DV_DATA14_MARK, PJ14MD_001),
+ PINMUX_DATA(LCD_DATA14_MARK, PJ14MD_010),
+ PINMUX_DATA(PINT6_PJ_MARK, PJ14MD_011),
+ PINMUX_DATA(PWM2G_MARK, PJ14MD_100),
+ PINMUX_DATA(TXD6_MARK, PJ14MD_101),
+
+ PINMUX_DATA(PJ13_DATA, PJ13MD_000),
+ PINMUX_DATA(DV_DATA13_MARK, PJ13MD_001),
+ PINMUX_DATA(LCD_DATA13_MARK, PJ13MD_010),
+ PINMUX_DATA(PINT5_PJ_MARK, PJ13MD_011),
+ PINMUX_DATA(PWM2F_MARK, PJ13MD_100),
+ PINMUX_DATA(TXD5_MARK, PJ13MD_101),
+
+ PINMUX_DATA(PJ12_DATA, PJ12MD_000),
+ PINMUX_DATA(DV_DATA12_MARK, PJ12MD_001),
+ PINMUX_DATA(LCD_DATA12_MARK, PJ12MD_010),
+ PINMUX_DATA(PINT4_PJ_MARK, PJ12MD_011),
+ PINMUX_DATA(PWM2E_MARK, PJ12MD_100),
+ PINMUX_DATA(SCK7_MARK, PJ12MD_101),
+
+ PINMUX_DATA(PJ11_DATA, PJ11MD_000),
+ PINMUX_DATA(DV_DATA11_MARK, PJ11MD_001),
+ PINMUX_DATA(LCD_DATA11_MARK, PJ11MD_010),
+ PINMUX_DATA(PINT3_PJ_MARK, PJ11MD_011),
+ PINMUX_DATA(PWM2D_MARK, PJ11MD_100),
+ PINMUX_DATA(SCK6_MARK, PJ11MD_101),
+
+ PINMUX_DATA(PJ10_DATA, PJ10MD_000),
+ PINMUX_DATA(DV_DATA10_MARK, PJ10MD_001),
+ PINMUX_DATA(LCD_DATA10_MARK, PJ10MD_010),
+ PINMUX_DATA(PINT2_PJ_MARK, PJ10MD_011),
+ PINMUX_DATA(PWM2C_MARK, PJ10MD_100),
+ PINMUX_DATA(SCK5_MARK, PJ10MD_101),
+
+ PINMUX_DATA(PJ9_DATA, PJ9MD_000),
+ PINMUX_DATA(DV_DATA9_MARK, PJ9MD_001),
+ PINMUX_DATA(LCD_DATA9_MARK, PJ9MD_010),
+ PINMUX_DATA(PINT1_PJ_MARK, PJ9MD_011),
+ PINMUX_DATA(PWM2B_MARK, PJ9MD_100),
+ PINMUX_DATA(RTS5_MARK, PJ9MD_101),
+
+ PINMUX_DATA(PJ8_DATA, PJ8MD_000),
+ PINMUX_DATA(DV_DATA8_MARK, PJ8MD_001),
+ PINMUX_DATA(LCD_DATA8_MARK, PJ8MD_010),
+ PINMUX_DATA(PINT0_PJ_MARK, PJ8MD_011),
+ PINMUX_DATA(PWM2A_MARK, PJ8MD_100),
+ PINMUX_DATA(CTS5_MARK, PJ8MD_101),
+
+ PINMUX_DATA(PJ7_DATA, PJ7MD_000),
+ PINMUX_DATA(DV_DATA7_MARK, PJ7MD_001),
+ PINMUX_DATA(LCD_DATA7_MARK, PJ7MD_010),
+ PINMUX_DATA(SD_D2_MARK, PJ7MD_011),
+ PINMUX_DATA(PWM1H_MARK, PJ7MD_100),
+
+ PINMUX_DATA(PJ6_DATA, PJ6MD_000),
+ PINMUX_DATA(DV_DATA6_MARK, PJ6MD_001),
+ PINMUX_DATA(LCD_DATA6_MARK, PJ6MD_010),
+ PINMUX_DATA(SD_D3_MARK, PJ6MD_011),
+ PINMUX_DATA(PWM1G_MARK, PJ6MD_100),
+
+ PINMUX_DATA(PJ5_DATA, PJ5MD_000),
+ PINMUX_DATA(DV_DATA5_MARK, PJ5MD_001),
+ PINMUX_DATA(LCD_DATA5_MARK, PJ5MD_010),
+ PINMUX_DATA(SD_CMD_MARK, PJ5MD_011),
+ PINMUX_DATA(PWM1F_MARK, PJ5MD_100),
+
+ PINMUX_DATA(PJ4_DATA, PJ4MD_000),
+ PINMUX_DATA(DV_DATA4_MARK, PJ4MD_001),
+ PINMUX_DATA(LCD_DATA4_MARK, PJ4MD_010),
+ PINMUX_DATA(SD_CLK_MARK, PJ4MD_011),
+ PINMUX_DATA(PWM1E_MARK, PJ4MD_100),
+
+ PINMUX_DATA(PJ3_DATA, PJ3MD_000),
+ PINMUX_DATA(DV_DATA3_MARK, PJ3MD_001),
+ PINMUX_DATA(LCD_DATA3_MARK, PJ3MD_010),
+ PINMUX_DATA(SD_D0_MARK, PJ3MD_011),
+ PINMUX_DATA(PWM1D_MARK, PJ3MD_100),
+
+ PINMUX_DATA(PJ2_DATA, PJ2MD_000),
+ PINMUX_DATA(DV_DATA2_MARK, PJ2MD_001),
+ PINMUX_DATA(LCD_DATA2_MARK, PJ2MD_010),
+ PINMUX_DATA(SD_D1_MARK, PJ2MD_011),
+ PINMUX_DATA(PWM1C_MARK, PJ2MD_100),
+
+ PINMUX_DATA(PJ1_DATA, PJ1MD_000),
+ PINMUX_DATA(DV_DATA1_MARK, PJ1MD_001),
+ PINMUX_DATA(LCD_DATA1_MARK, PJ1MD_010),
+ PINMUX_DATA(SD_WP_MARK, PJ1MD_011),
+ PINMUX_DATA(PWM1B_MARK, PJ1MD_100),
+
+ PINMUX_DATA(PJ0_DATA, PJ0MD_000),
+ PINMUX_DATA(DV_DATA0_MARK, PJ0MD_001),
+ PINMUX_DATA(LCD_DATA0_MARK, PJ0MD_010),
+ PINMUX_DATA(SD_CD_MARK, PJ0MD_011),
+ PINMUX_DATA(PWM1A_MARK, PJ0MD_100),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+ /* Port A */
+ PINMUX_GPIO(GPIO_PA1, PA1_DATA),
+ PINMUX_GPIO(GPIO_PA0, PA0_DATA),
+
+ /* Port B */
+ PINMUX_GPIO(GPIO_PB22, PB22_DATA),
+ PINMUX_GPIO(GPIO_PB21, PB21_DATA),
+ PINMUX_GPIO(GPIO_PB20, PB20_DATA),
+ PINMUX_GPIO(GPIO_PB19, PB19_DATA),
+ PINMUX_GPIO(GPIO_PB18, PB18_DATA),
+ PINMUX_GPIO(GPIO_PB17, PB17_DATA),
+ PINMUX_GPIO(GPIO_PB16, PB16_DATA),
+ PINMUX_GPIO(GPIO_PB15, PB15_DATA),
+ PINMUX_GPIO(GPIO_PB14, PB14_DATA),
+ PINMUX_GPIO(GPIO_PB13, PB13_DATA),
+ PINMUX_GPIO(GPIO_PB12, PB12_DATA),
+ PINMUX_GPIO(GPIO_PB11, PB11_DATA),
+ PINMUX_GPIO(GPIO_PB10, PB10_DATA),
+ PINMUX_GPIO(GPIO_PB9, PB9_DATA),
+ PINMUX_GPIO(GPIO_PB8, PB8_DATA),
+ PINMUX_GPIO(GPIO_PB7, PB7_DATA),
+ PINMUX_GPIO(GPIO_PB6, PB6_DATA),
+ PINMUX_GPIO(GPIO_PB5, PB5_DATA),
+ PINMUX_GPIO(GPIO_PB4, PB4_DATA),
+ PINMUX_GPIO(GPIO_PB3, PB3_DATA),
+ PINMUX_GPIO(GPIO_PB2, PB2_DATA),
+ PINMUX_GPIO(GPIO_PB1, PB1_DATA),
+
+ /* Port C */
+ PINMUX_GPIO(GPIO_PC8, PC8_DATA),
+ PINMUX_GPIO(GPIO_PC7, PC7_DATA),
+ PINMUX_GPIO(GPIO_PC6, PC6_DATA),
+ PINMUX_GPIO(GPIO_PC5, PC5_DATA),
+ PINMUX_GPIO(GPIO_PC4, PC4_DATA),
+ PINMUX_GPIO(GPIO_PC3, PC3_DATA),
+ PINMUX_GPIO(GPIO_PC2, PC2_DATA),
+ PINMUX_GPIO(GPIO_PC1, PC1_DATA),
+ PINMUX_GPIO(GPIO_PC0, PC0_DATA),
+
+ /* Port D */
+ PINMUX_GPIO(GPIO_PD15, PD15_DATA),
+ PINMUX_GPIO(GPIO_PD14, PD14_DATA),
+ PINMUX_GPIO(GPIO_PD13, PD13_DATA),
+ PINMUX_GPIO(GPIO_PD12, PD12_DATA),
+ PINMUX_GPIO(GPIO_PD11, PD11_DATA),
+ PINMUX_GPIO(GPIO_PD10, PD10_DATA),
+ PINMUX_GPIO(GPIO_PD9, PD9_DATA),
+ PINMUX_GPIO(GPIO_PD8, PD8_DATA),
+ PINMUX_GPIO(GPIO_PD7, PD7_DATA),
+ PINMUX_GPIO(GPIO_PD6, PD6_DATA),
+ PINMUX_GPIO(GPIO_PD5, PD5_DATA),
+ PINMUX_GPIO(GPIO_PD4, PD4_DATA),
+ PINMUX_GPIO(GPIO_PD3, PD3_DATA),
+ PINMUX_GPIO(GPIO_PD2, PD2_DATA),
+ PINMUX_GPIO(GPIO_PD1, PD1_DATA),
+ PINMUX_GPIO(GPIO_PD0, PD0_DATA),
+
+ /* Port E */
+ PINMUX_GPIO(GPIO_PE7, PE7_DATA),
+ PINMUX_GPIO(GPIO_PE6, PE6_DATA),
+ PINMUX_GPIO(GPIO_PE5, PE5_DATA),
+ PINMUX_GPIO(GPIO_PE4, PE4_DATA),
+ PINMUX_GPIO(GPIO_PE3, PE3_DATA),
+ PINMUX_GPIO(GPIO_PE2, PE2_DATA),
+ PINMUX_GPIO(GPIO_PE1, PE1_DATA),
+ PINMUX_GPIO(GPIO_PE0, PE0_DATA),
+
+ /* Port F */
+ PINMUX_GPIO(GPIO_PF23, PF23_DATA),
+ PINMUX_GPIO(GPIO_PF22, PF22_DATA),
+ PINMUX_GPIO(GPIO_PF21, PF21_DATA),
+ PINMUX_GPIO(GPIO_PF20, PF20_DATA),
+ PINMUX_GPIO(GPIO_PF19, PF19_DATA),
+ PINMUX_GPIO(GPIO_PF18, PF18_DATA),
+ PINMUX_GPIO(GPIO_PF17, PF17_DATA),
+ PINMUX_GPIO(GPIO_PF16, PF16_DATA),
+ PINMUX_GPIO(GPIO_PF15, PF15_DATA),
+ PINMUX_GPIO(GPIO_PF14, PF14_DATA),
+ PINMUX_GPIO(GPIO_PF13, PF13_DATA),
+ PINMUX_GPIO(GPIO_PF12, PF12_DATA),
+ PINMUX_GPIO(GPIO_PF11, PF11_DATA),
+ PINMUX_GPIO(GPIO_PF10, PF10_DATA),
+ PINMUX_GPIO(GPIO_PF9, PF9_DATA),
+ PINMUX_GPIO(GPIO_PF8, PF8_DATA),
+ PINMUX_GPIO(GPIO_PF7, PF7_DATA),
+ PINMUX_GPIO(GPIO_PF6, PF6_DATA),
+ PINMUX_GPIO(GPIO_PF5, PF5_DATA),
+ PINMUX_GPIO(GPIO_PF4, PF4_DATA),
+ PINMUX_GPIO(GPIO_PF3, PF3_DATA),
+ PINMUX_GPIO(GPIO_PF2, PF2_DATA),
+ PINMUX_GPIO(GPIO_PF1, PF1_DATA),
+ PINMUX_GPIO(GPIO_PF0, PF0_DATA),
+
+ /* Port G */
+ PINMUX_GPIO(GPIO_PG27, PG27_DATA),
+ PINMUX_GPIO(GPIO_PG26, PG26_DATA),
+ PINMUX_GPIO(GPIO_PG25, PG25_DATA),
+ PINMUX_GPIO(GPIO_PG24, PG24_DATA),
+ PINMUX_GPIO(GPIO_PG23, PG23_DATA),
+ PINMUX_GPIO(GPIO_PG22, PG22_DATA),
+ PINMUX_GPIO(GPIO_PG21, PG21_DATA),
+ PINMUX_GPIO(GPIO_PG20, PG20_DATA),
+ PINMUX_GPIO(GPIO_PG19, PG19_DATA),
+ PINMUX_GPIO(GPIO_PG18, PG18_DATA),
+ PINMUX_GPIO(GPIO_PG17, PG17_DATA),
+ PINMUX_GPIO(GPIO_PG16, PG16_DATA),
+ PINMUX_GPIO(GPIO_PG15, PG15_DATA),
+ PINMUX_GPIO(GPIO_PG14, PG14_DATA),
+ PINMUX_GPIO(GPIO_PG13, PG13_DATA),
+ PINMUX_GPIO(GPIO_PG12, PG12_DATA),
+ PINMUX_GPIO(GPIO_PG11, PG11_DATA),
+ PINMUX_GPIO(GPIO_PG10, PG10_DATA),
+ PINMUX_GPIO(GPIO_PG9, PG9_DATA),
+ PINMUX_GPIO(GPIO_PG8, PG8_DATA),
+ PINMUX_GPIO(GPIO_PG7, PG7_DATA),
+ PINMUX_GPIO(GPIO_PG6, PG6_DATA),
+ PINMUX_GPIO(GPIO_PG5, PG5_DATA),
+ PINMUX_GPIO(GPIO_PG4, PG4_DATA),
+ PINMUX_GPIO(GPIO_PG3, PG3_DATA),
+ PINMUX_GPIO(GPIO_PG2, PG2_DATA),
+ PINMUX_GPIO(GPIO_PG1, PG1_DATA),
+ PINMUX_GPIO(GPIO_PG0, PG0_DATA),
+
+ /* Port H - Port H does not have a Data Register */
+
+ /* Port I - not on device */
+
+ /* Port J */
+ PINMUX_GPIO(GPIO_PJ31, PJ31_DATA),
+ PINMUX_GPIO(GPIO_PJ30, PJ30_DATA),
+ PINMUX_GPIO(GPIO_PJ29, PJ29_DATA),
+ PINMUX_GPIO(GPIO_PJ28, PJ28_DATA),
+ PINMUX_GPIO(GPIO_PJ27, PJ27_DATA),
+ PINMUX_GPIO(GPIO_PJ26, PJ26_DATA),
+ PINMUX_GPIO(GPIO_PJ25, PJ25_DATA),
+ PINMUX_GPIO(GPIO_PJ24, PJ24_DATA),
+ PINMUX_GPIO(GPIO_PJ23, PJ23_DATA),
+ PINMUX_GPIO(GPIO_PJ22, PJ22_DATA),
+ PINMUX_GPIO(GPIO_PJ21, PJ21_DATA),
+ PINMUX_GPIO(GPIO_PJ20, PJ20_DATA),
+ PINMUX_GPIO(GPIO_PJ19, PJ19_DATA),
+ PINMUX_GPIO(GPIO_PJ18, PJ18_DATA),
+ PINMUX_GPIO(GPIO_PJ17, PJ17_DATA),
+ PINMUX_GPIO(GPIO_PJ16, PJ16_DATA),
+ PINMUX_GPIO(GPIO_PJ15, PJ15_DATA),
+ PINMUX_GPIO(GPIO_PJ14, PJ14_DATA),
+ PINMUX_GPIO(GPIO_PJ13, PJ13_DATA),
+ PINMUX_GPIO(GPIO_PJ12, PJ12_DATA),
+ PINMUX_GPIO(GPIO_PJ11, PJ11_DATA),
+ PINMUX_GPIO(GPIO_PJ10, PJ10_DATA),
+ PINMUX_GPIO(GPIO_PJ9, PJ9_DATA),
+ PINMUX_GPIO(GPIO_PJ8, PJ8_DATA),
+ PINMUX_GPIO(GPIO_PJ7, PJ7_DATA),
+ PINMUX_GPIO(GPIO_PJ6, PJ6_DATA),
+ PINMUX_GPIO(GPIO_PJ5, PJ5_DATA),
+ PINMUX_GPIO(GPIO_PJ4, PJ4_DATA),
+ PINMUX_GPIO(GPIO_PJ3, PJ3_DATA),
+ PINMUX_GPIO(GPIO_PJ2, PJ2_DATA),
+ PINMUX_GPIO(GPIO_PJ1, PJ1_DATA),
+ PINMUX_GPIO(GPIO_PJ0, PJ0_DATA),
+
+ /* INTC */
+ PINMUX_GPIO(GPIO_FN_IRQ7_PG, IRQ7_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ6_PG, IRQ6_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ5_PG, IRQ5_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ4_PG, IRQ4_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ3_PG, IRQ3_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ2_PG, IRQ2_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ1_PG, IRQ1_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ0_PG, IRQ0_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ7_PF, IRQ7_PF_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ6_PF, IRQ6_PF_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ5_PF, IRQ5_PF_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ4_PF, IRQ4_PF_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ3_PJ, IRQ3_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ2_PJ, IRQ2_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ1_PJ, IRQ1_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ0_PJ, IRQ0_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ1_PC, IRQ1_PC_MARK),
+ PINMUX_GPIO(GPIO_FN_IRQ0_PC, IRQ0_PC_MARK),
+
+ PINMUX_GPIO(GPIO_FN_PINT7_PG, PINT7_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT6_PG, PINT6_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT5_PG, PINT5_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT4_PG, PINT4_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT3_PG, PINT3_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT2_PG, PINT2_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT1_PG, PINT1_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT0_PG, PINT0_PG_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT7_PH, PINT7_PH_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT6_PH, PINT6_PH_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT5_PH, PINT5_PH_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT4_PH, PINT4_PH_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT3_PH, PINT3_PH_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT2_PH, PINT2_PH_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT1_PH, PINT1_PH_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT0_PH, PINT0_PH_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT7_PJ, PINT7_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT6_PJ, PINT6_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT5_PJ, PINT5_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT4_PJ, PINT4_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT3_PJ, PINT3_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT2_PJ, PINT2_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT1_PJ, PINT1_PJ_MARK),
+ PINMUX_GPIO(GPIO_FN_PINT0_PJ, PINT0_PJ_MARK),
+
+ /* WDT */
+ PINMUX_GPIO(GPIO_FN_WDTOVF, WDTOVF_MARK),
+
+ /* CAN */
+ PINMUX_GPIO(GPIO_FN_CTX1, CTX1_MARK),
+ PINMUX_GPIO(GPIO_FN_CRX1, CRX1_MARK),
+ PINMUX_GPIO(GPIO_FN_CTX0, CTX0_MARK),
+ PINMUX_GPIO(GPIO_FN_CRX0, CRX0_MARK),
+ PINMUX_GPIO(GPIO_FN_CRX0_CRX1, CRX0CRX1_MARK),
+ PINMUX_GPIO(GPIO_FN_CRX0_CRX1_CRX2, CRX0CRX1CRX2_MARK),
+
+ /* DMAC */
+ PINMUX_GPIO(GPIO_FN_TEND0, TEND0_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK0, DACK0_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ0, DREQ0_MARK),
+ PINMUX_GPIO(GPIO_FN_TEND1, TEND1_MARK),
+ PINMUX_GPIO(GPIO_FN_DACK1, DACK1_MARK),
+ PINMUX_GPIO(GPIO_FN_DREQ1, DREQ1_MARK),
+
+ /* ADC */
+ PINMUX_GPIO(GPIO_FN_ADTRG, ADTRG_MARK),
+
+ /* BSCh */
+ PINMUX_GPIO(GPIO_FN_A25, A25_MARK),
+ PINMUX_GPIO(GPIO_FN_A24, A24_MARK),
+ PINMUX_GPIO(GPIO_FN_A23, A23_MARK),
+ PINMUX_GPIO(GPIO_FN_A22, A22_MARK),
+ PINMUX_GPIO(GPIO_FN_A21, A21_MARK),
+ PINMUX_GPIO(GPIO_FN_A20, A20_MARK),
+ PINMUX_GPIO(GPIO_FN_A19, A19_MARK),
+ PINMUX_GPIO(GPIO_FN_A18, A18_MARK),
+ PINMUX_GPIO(GPIO_FN_A17, A17_MARK),
+ PINMUX_GPIO(GPIO_FN_A16, A16_MARK),
+ PINMUX_GPIO(GPIO_FN_A15, A15_MARK),
+ PINMUX_GPIO(GPIO_FN_A14, A14_MARK),
+ PINMUX_GPIO(GPIO_FN_A13, A13_MARK),
+ PINMUX_GPIO(GPIO_FN_A12, A12_MARK),
+ PINMUX_GPIO(GPIO_FN_A11, A11_MARK),
+ PINMUX_GPIO(GPIO_FN_A10, A10_MARK),
+ PINMUX_GPIO(GPIO_FN_A9, A9_MARK),
+ PINMUX_GPIO(GPIO_FN_A8, A8_MARK),
+ PINMUX_GPIO(GPIO_FN_A7, A7_MARK),
+ PINMUX_GPIO(GPIO_FN_A6, A6_MARK),
+ PINMUX_GPIO(GPIO_FN_A5, A5_MARK),
+ PINMUX_GPIO(GPIO_FN_A4, A4_MARK),
+ PINMUX_GPIO(GPIO_FN_A3, A3_MARK),
+ PINMUX_GPIO(GPIO_FN_A2, A2_MARK),
+ PINMUX_GPIO(GPIO_FN_A1, A1_MARK),
+ PINMUX_GPIO(GPIO_FN_A0, A0_MARK),
+
+ PINMUX_GPIO(GPIO_FN_D15, D15_MARK),
+ PINMUX_GPIO(GPIO_FN_D14, D14_MARK),
+ PINMUX_GPIO(GPIO_FN_D13, D13_MARK),
+ PINMUX_GPIO(GPIO_FN_D12, D12_MARK),
+ PINMUX_GPIO(GPIO_FN_D11, D11_MARK),
+ PINMUX_GPIO(GPIO_FN_D10, D10_MARK),
+ PINMUX_GPIO(GPIO_FN_D9, D9_MARK),
+ PINMUX_GPIO(GPIO_FN_D8, D8_MARK),
+ PINMUX_GPIO(GPIO_FN_D7, D7_MARK),
+ PINMUX_GPIO(GPIO_FN_D6, D6_MARK),
+ PINMUX_GPIO(GPIO_FN_D5, D5_MARK),
+ PINMUX_GPIO(GPIO_FN_D4, D4_MARK),
+ PINMUX_GPIO(GPIO_FN_D3, D3_MARK),
+ PINMUX_GPIO(GPIO_FN_D2, D2_MARK),
+ PINMUX_GPIO(GPIO_FN_D1, D1_MARK),
+ PINMUX_GPIO(GPIO_FN_D0, D0_MARK),
+
+ PINMUX_GPIO(GPIO_FN_BS, BS_MARK),
+ PINMUX_GPIO(GPIO_FN_CS4, CS4_MARK),
+ PINMUX_GPIO(GPIO_FN_CS3, CS3_MARK),
+ PINMUX_GPIO(GPIO_FN_CS2, CS2_MARK),
+ PINMUX_GPIO(GPIO_FN_CS1, CS1_MARK),
+ PINMUX_GPIO(GPIO_FN_CS0, CS0_MARK),
+ PINMUX_GPIO(GPIO_FN_CS5CE1A, CS5CE1A_MARK),
+ PINMUX_GPIO(GPIO_FN_CE2A, CE2A_MARK),
+ PINMUX_GPIO(GPIO_FN_CE2B, CE2B_MARK),
+ PINMUX_GPIO(GPIO_FN_RD, RD_MARK),
+ PINMUX_GPIO(GPIO_FN_RDWR, RDWR_MARK),
+ PINMUX_GPIO(GPIO_FN_WE3ICIOWRAHDQMUU, WE3ICIOWRAHDQMUU_MARK),
+ PINMUX_GPIO(GPIO_FN_WE2ICIORDDQMUL, WE2ICIORDDQMUL_MARK),
+ PINMUX_GPIO(GPIO_FN_WE1DQMUWE, WE1DQMUWE_MARK),
+ PINMUX_GPIO(GPIO_FN_WE0DQML, WE0DQML_MARK),
+ PINMUX_GPIO(GPIO_FN_RAS, RAS_MARK),
+ PINMUX_GPIO(GPIO_FN_CAS, CAS_MARK),
+ PINMUX_GPIO(GPIO_FN_CKE, CKE_MARK),
+ PINMUX_GPIO(GPIO_FN_WAIT, WAIT_MARK),
+ PINMUX_GPIO(GPIO_FN_BREQ, BREQ_MARK),
+ PINMUX_GPIO(GPIO_FN_BACK, BACK_MARK),
+ PINMUX_GPIO(GPIO_FN_IOIS16, IOIS16_MARK),
+
+ /* TMU */
+ PINMUX_GPIO(GPIO_FN_TIOC4D, TIOC4D_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC4C, TIOC4C_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC4B, TIOC4B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC4A, TIOC4A_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC3D, TIOC3D_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC3C, TIOC3C_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC3B, TIOC3B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC3A, TIOC3A_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC2B, TIOC2B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC1B, TIOC1B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC2A, TIOC2A_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC1A, TIOC1A_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC0D, TIOC0D_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC0C, TIOC0C_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC0B, TIOC0B_MARK),
+ PINMUX_GPIO(GPIO_FN_TIOC0A, TIOC0A_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKD, TCLKD_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKC, TCLKC_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKB, TCLKB_MARK),
+ PINMUX_GPIO(GPIO_FN_TCLKA, TCLKA_MARK),
+
+ /* SCIF */
+ PINMUX_GPIO(GPIO_FN_SCK0, SCK0_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD0, TXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD0, RXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK1, SCK1_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD1, TXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD1, RXD1_MARK),
+ PINMUX_GPIO(GPIO_FN_RTS1, RTS1_MARK),
+ PINMUX_GPIO(GPIO_FN_CTS1, CTS1_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK2, SCK2_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD2, TXD2_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD2, RXD2_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK3, SCK3_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD3, TXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD3, RXD3_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK4, SCK4_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD4, TXD4_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD4, RXD4_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK5, SCK5_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD5, TXD5_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD5, RXD5_MARK),
+ PINMUX_GPIO(GPIO_FN_RTS5, RTS5_MARK),
+ PINMUX_GPIO(GPIO_FN_CTS5, CTS5_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK6, SCK6_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD6, TXD6_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD6, RXD6_MARK),
+ PINMUX_GPIO(GPIO_FN_SCK7, SCK7_MARK),
+ PINMUX_GPIO(GPIO_FN_TXD7, TXD7_MARK),
+ PINMUX_GPIO(GPIO_FN_RXD7, RXD7_MARK),
+ PINMUX_GPIO(GPIO_FN_RTS7, RTS7_MARK),
+ PINMUX_GPIO(GPIO_FN_CTS7, CTS7_MARK),
+
+ /* RSPI */
+ PINMUX_GPIO(GPIO_FN_RSPCK0_PJ16, RSPCK0_PJ16_MARK),
+ PINMUX_GPIO(GPIO_FN_SSL00_PJ17, SSL00_PJ17_MARK),
+ PINMUX_GPIO(GPIO_FN_MOSI0_PJ18, MOSI0_PJ18_MARK),
+ PINMUX_GPIO(GPIO_FN_MISO0_PJ19, MISO0_PJ19_MARK),
+ PINMUX_GPIO(GPIO_FN_RSPCK0_PB17, RSPCK0_PB17_MARK),
+ PINMUX_GPIO(GPIO_FN_SSL00_PB18, SSL00_PB18_MARK),
+ PINMUX_GPIO(GPIO_FN_MOSI0_PB19, MOSI0_PB19_MARK),
+ PINMUX_GPIO(GPIO_FN_MISO0_PB20, MISO0_PB20_MARK),
+ PINMUX_GPIO(GPIO_FN_RSPCK1, RSPCK1_MARK),
+ PINMUX_GPIO(GPIO_FN_MOSI1, MOSI1_MARK),
+ PINMUX_GPIO(GPIO_FN_MISO1, MISO1_MARK),
+ PINMUX_GPIO(GPIO_FN_SSL10, SSL10_MARK),
+
+ /* IIC3 */
+ PINMUX_GPIO(GPIO_FN_SCL0, SCL0_MARK),
+ PINMUX_GPIO(GPIO_FN_SCL1, SCL1_MARK),
+ PINMUX_GPIO(GPIO_FN_SCL2, SCL2_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA0, SDA0_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA1, SDA1_MARK),
+ PINMUX_GPIO(GPIO_FN_SDA2, SDA2_MARK),
+
+ /* SSI */
+ PINMUX_GPIO(GPIO_FN_SSISCK0, SSISCK0_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIWS0, SSIWS0_MARK),
+ PINMUX_GPIO(GPIO_FN_SSITXD0, SSITXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIRXD0, SSIRXD0_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIWS1, SSIWS1_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIWS2, SSIWS2_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIWS3, SSIWS3_MARK),
+ PINMUX_GPIO(GPIO_FN_SSISCK1, SSISCK1_MARK),
+ PINMUX_GPIO(GPIO_FN_SSISCK2, SSISCK2_MARK),
+ PINMUX_GPIO(GPIO_FN_SSISCK3, SSISCK3_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIDATA1, SSIDATA1_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIDATA2, SSIDATA2_MARK),
+ PINMUX_GPIO(GPIO_FN_SSIDATA3, SSIDATA3_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDIO_CLK, AUDIO_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_AUDIO_XOUT, AUDIO_XOUT_MARK),
+
+ /* SIOF */ /* NOTE Shares AUDIO_CLK with SSI */
+ PINMUX_GPIO(GPIO_FN_SIOFTXD, SIOFTXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOFRXD, SIOFRXD_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOFSYNC, SIOFSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_SIOFSCK, SIOFSCK_MARK),
+
+ /* SPDIF */ /* NOTE Shares AUDIO_CLK with SSI */
+ PINMUX_GPIO(GPIO_FN_SPDIF_IN, SPDIF_IN_MARK),
+ PINMUX_GPIO(GPIO_FN_SPDIF_OUT, SPDIF_OUT_MARK),
+
+ /* NANDFMC */ /* NOTE Controller is not available in boot mode 0 */
+ PINMUX_GPIO(GPIO_FN_FCE, FCE_MARK),
+ PINMUX_GPIO(GPIO_FN_FRB, FRB_MARK),
+
+ /* VDC3 */
+ PINMUX_GPIO(GPIO_FN_DV_CLK, DV_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_VSYNC, DV_VSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_HSYNC, DV_HSYNC_MARK),
+
+ PINMUX_GPIO(GPIO_FN_DV_DATA23, DV_DATA23_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA22, DV_DATA22_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA21, DV_DATA21_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA20, DV_DATA20_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA19, DV_DATA19_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA18, DV_DATA18_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA17, DV_DATA17_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA16, DV_DATA16_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA15, DV_DATA15_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA14, DV_DATA14_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA13, DV_DATA13_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA12, DV_DATA12_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA11, DV_DATA11_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA10, DV_DATA10_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA9, DV_DATA9_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA8, DV_DATA8_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA7, DV_DATA7_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA6, DV_DATA6_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA5, DV_DATA5_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA4, DV_DATA4_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA3, DV_DATA3_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA2, DV_DATA2_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA1, DV_DATA1_MARK),
+ PINMUX_GPIO(GPIO_FN_DV_DATA0, DV_DATA0_MARK),
+
+ PINMUX_GPIO(GPIO_FN_LCD_CLK, LCD_CLK_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_EXTCLK, LCD_EXTCLK_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_VSYNC, LCD_VSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_HSYNC, LCD_HSYNC_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DE, LCD_DE_MARK),
+
+ PINMUX_GPIO(GPIO_FN_LCD_DATA23, LCD_DATA23_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA22, LCD_DATA22_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA21, LCD_DATA21_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA20, LCD_DATA20_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA19, LCD_DATA19_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA18, LCD_DATA18_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA17, LCD_DATA17_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA16, LCD_DATA16_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA15, LCD_DATA15_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA14, LCD_DATA14_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA13, LCD_DATA13_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA12, LCD_DATA12_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA11, LCD_DATA11_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA10, LCD_DATA10_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA9, LCD_DATA9_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA8, LCD_DATA8_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA7, LCD_DATA7_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA6, LCD_DATA6_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA5, LCD_DATA5_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA4, LCD_DATA4_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA3, LCD_DATA3_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA2, LCD_DATA2_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA1, LCD_DATA1_MARK),
+ PINMUX_GPIO(GPIO_FN_LCD_DATA0, LCD_DATA0_MARK),
+
+ PINMUX_GPIO(GPIO_FN_LCD_M_DISP, LCD_M_DISP_MARK),
+};
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+ /* "name" addr register_size Field_Width */
+
+ /* where Field_Width is 1 for single mode registers or 4 for upto 16
+ mode registers and modes are described in assending order [0..16] */
+
+ { PINMUX_CFG_REG("PAIOR0", 0xfffe3812, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, PA1_IN, PA1_OUT,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, PA0_IN, PA0_OUT }
+ },
+ { PINMUX_CFG_REG("PBCR5", 0xfffe3824, 16, 4) {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB22MD_000, PB22MD_001, PB22MD_010, PB22MD_011,
+ PB22MD_100, PB22MD_101, PB22MD_110, PB22MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB21MD_00, PB21MD_01, PB21MD_10, PB21MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB20MD_000, PB20MD_001, PB20MD_010, PB20MD_011,
+ PB20MD_100, PB20MD_101, PB20MD_110, PB20MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PBCR4", 0xfffe3826, 16, 4) {
+ PB19MD_000, PB19MD_001, PB19MD_010, PB19MD_011,
+ PB19MD_100, PB19MD_101, PB19MD_110, PB19MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB18MD_000, PB18MD_001, PB18MD_010, PB18MD_011,
+ PB18MD_100, PB18MD_101, PB18MD_110, PB18MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB17MD_000, PB17MD_001, PB17MD_010, PB17MD_011,
+ PB17MD_100, PB17MD_101, PB17MD_110, PB17MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB16MD_000, PB16MD_001, PB16MD_010, PB16MD_011,
+ PB16MD_100, PB16MD_101, PB16MD_110, PB16MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PBCR3", 0xfffe3828, 16, 4) {
+ PB15MD_000, PB15MD_001, PB15MD_010, PB15MD_011,
+ PB15MD_100, PB15MD_101, PB15MD_110, PB15MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB14MD_000, PB14MD_001, PB14MD_010, PB14MD_011,
+ PB14MD_100, PB14MD_101, PB14MD_110, PB14MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB13MD_000, PB13MD_001, PB13MD_010, PB13MD_011,
+ PB13MD_100, PB13MD_101, PB13MD_110, PB13MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB12MD_00, PB12MD_01, PB12MD_10, PB12MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PBCR2", 0xfffe382a, 16, 4) {
+ PB11MD_00, PB11MD_01, PB11MD_10, PB11MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB10MD_00, PB10MD_01, PB10MD_10, PB10MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB9MD_00, PB9MD_01, PB9MD_10, PB9MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB8MD_00, PB8MD_01, PB8MD_10, PB8MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PBCR1", 0xfffe382c, 16, 4) {
+ PB7MD_00, PB7MD_01, PB7MD_10, PB7MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB6MD_00, PB6MD_01, PB6MD_10, PB6MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB5MD_00, PB5MD_01, PB5MD_10, PB5MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB4MD_00, PB4MD_01, PB4MD_10, PB4MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PBCR0", 0xfffe382e, 16, 4) {
+ PB3MD_00, PB3MD_01, PB3MD_10, PB3MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB2MD_00, PB2MD_01, PB2MD_10, PB2MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PB1MD_00, PB1MD_01, PB1MD_10, PB1MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PBIOR1", 0xfffe3830, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,
+ PB22_IN, PB22_OUT,
+ PB21_IN, PB21_OUT,
+ PB20_IN, PB20_OUT,
+ PB19_IN, PB19_OUT,
+ PB18_IN, PB18_OUT,
+ PB17_IN, PB17_OUT,
+ PB16_IN, PB16_OUT }
+ },
+ { PINMUX_CFG_REG("PBIOR0", 0xfffe3832, 16, 1) {
+ PB15_IN, PB15_OUT,
+ PB14_IN, PB14_OUT,
+ PB13_IN, PB13_OUT,
+ PB12_IN, PB12_OUT,
+ PB11_IN, PB11_OUT,
+ PB10_IN, PB10_OUT,
+ PB9_IN, PB9_OUT,
+ PB8_IN, PB8_OUT,
+ PB7_IN, PB7_OUT,
+ PB6_IN, PB6_OUT,
+ PB5_IN, PB5_OUT,
+ PB4_IN, PB4_OUT,
+ PB3_IN, PB3_OUT,
+ PB2_IN, PB2_OUT,
+ PB1_IN, PB1_OUT,
+ 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PCCR2", 0xfffe384a, 16, 4) {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC8MD_000, PC8MD_001, PC8MD_010, PC8MD_011,
+ PC8MD_100, PC8MD_101, PC8MD_110, PC8MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PCCR1", 0xfffe384c, 16, 4) {
+ PC7MD_000, PC7MD_001, PC7MD_010, PC7MD_011,
+ PC7MD_100, PC7MD_101, PC7MD_110, PC7MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC6MD_000, PC6MD_001, PC6MD_010, PC6MD_011,
+ PC6MD_100, PC6MD_101, PC6MD_110, PC6MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC5MD_000, PC5MD_001, PC5MD_010, PC5MD_011,
+ PC5MD_100, PC5MD_101, PC5MD_110, PC5MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC4MD_00, PC4MD_01, PC4MD_10, PC4MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PCCR0", 0xfffe384e, 16, 4) {
+ PC3MD_00, PC3MD_01, PC3MD_10, PC3MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC2MD_00, PC2MD_01, PC2MD_10, PC2MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC1MD_0, PC1MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PC0MD_0, PC0MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PCIOR0", 0xfffe3852, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ PC8_IN, PC8_OUT,
+ PC7_IN, PC7_OUT,
+ PC6_IN, PC6_OUT,
+ PC5_IN, PC5_OUT,
+ PC4_IN, PC4_OUT,
+ PC3_IN, PC3_OUT,
+ PC2_IN, PC2_OUT,
+ PC1_IN, PC1_OUT,
+ PC0_IN, PC0_OUT }
+ },
+
+ { PINMUX_CFG_REG("PDCR3", 0xfffe3868, 16, 4) {
+ PD15MD_00, PD15MD_01, PD15MD_10, PD15MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD14MD_00, PD14MD_01, PD14MD_10, PD14MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD13MD_00, PD13MD_01, PD13MD_10, PD13MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD12MD_00, PD12MD_01, PD12MD_10, PD12MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PDCR2", 0xfffe386a, 16, 4) {
+ PD11MD_00, PD11MD_01, PD11MD_10, PD11MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD10MD_00, PD10MD_01, PD10MD_10, PD10MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD9MD_00, PD9MD_01, PD9MD_10, PD9MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD8MD_00, PD8MD_01, PD8MD_10, PD8MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PDCR1", 0xfffe386c, 16, 4) {
+ PD7MD_00, PD7MD_01, PD7MD_10, PD7MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD6MD_00, PD6MD_01, PD6MD_10, PD6MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD5MD_00, PD5MD_01, PD5MD_10, PD5MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD4MD_00, PD4MD_01, PD4MD_10, PD4MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PDCR0", 0xfffe386e, 16, 4) {
+ PD3MD_00, PD3MD_01, PD3MD_10, PD3MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD2MD_00, PD2MD_01, PD2MD_10, PD2MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD1MD_00, PD1MD_01, PD1MD_10, PD1MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PD0MD_00, PD0MD_01, PD0MD_10, PD0MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PDIOR0", 0xfffe3872, 16, 1) {
+ PD15_IN, PD15_OUT,
+ PD14_IN, PD14_OUT,
+ PD13_IN, PD13_OUT,
+ PD12_IN, PD12_OUT,
+ PD11_IN, PD11_OUT,
+ PD10_IN, PD10_OUT,
+ PD9_IN, PD9_OUT,
+ PD8_IN, PD8_OUT,
+ PD7_IN, PD7_OUT,
+ PD6_IN, PD6_OUT,
+ PD5_IN, PD5_OUT,
+ PD4_IN, PD4_OUT,
+ PD3_IN, PD3_OUT,
+ PD2_IN, PD2_OUT,
+ PD1_IN, PD1_OUT,
+ PD0_IN, PD0_OUT }
+ },
+
+ { PINMUX_CFG_REG("PECR1", 0xfffe388c, 16, 4) {
+ PE7MD_00, PE7MD_01, PE7MD_10, PE7MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE6MD_00, PE6MD_01, PE6MD_10, PE6MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE5MD_00, PE5MD_01, PE5MD_10, PE5MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE4MD_00, PE4MD_01, PE4MD_10, PE4MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PECR0", 0xfffe388e, 16, 4) {
+ PE3MD_000, PE3MD_001, PE3MD_010, PE3MD_011,
+ PE3MD_100, PE3MD_101, PE3MD_110, PE3MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE2MD_000, PE2MD_001, PE2MD_010, PE2MD_011,
+ PE2MD_100, PE2MD_101, PE2MD_110, PE2MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE1MD_000, PE1MD_001, PE1MD_010, PE1MD_011,
+ PE1MD_100, PE1MD_101, PE1MD_110, PE1MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PE0MD_00, PE0MD_01, PE0MD_10, PE0MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PEIOR0", 0xfffe3892, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PE7_IN, PE7_OUT,
+ PE6_IN, PE6_OUT,
+ PE5_IN, PE5_OUT,
+ PE4_IN, PE4_OUT,
+ PE3_IN, PE3_OUT,
+ PE2_IN, PE2_OUT,
+ PE1_IN, PE1_OUT,
+ PE0_IN, PE0_OUT }
+ },
+
+ { PINMUX_CFG_REG("PFCR6", 0xfffe38a2, 16, 4) {
+ PF23MD_000, PF23MD_001, PF23MD_010, PF23MD_011,
+ PF23MD_100, PF23MD_101, PF23MD_110, PF23MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF22MD_000, PF22MD_001, PF22MD_010, PF22MD_011,
+ PF22MD_100, PF22MD_101, PF22MD_110, PF22MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF21MD_000, PF21MD_001, PF21MD_010, PF21MD_011,
+ PF21MD_100, PF21MD_101, PF21MD_110, PF21MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF20MD_000, PF20MD_001, PF20MD_010, PF20MD_011,
+ PF20MD_100, PF20MD_101, PF20MD_110, PF20MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PFCR5", 0xfffe38a4, 16, 4) {
+ PF19MD_000, PF19MD_001, PF19MD_010, PF19MD_011,
+ PF19MD_100, PF19MD_101, PF19MD_110, PF19MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF18MD_000, PF18MD_001, PF18MD_010, PF18MD_011,
+ PF18MD_100, PF18MD_101, PF18MD_110, PF18MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF17MD_000, PF17MD_001, PF17MD_010, PF17MD_011,
+ PF17MD_100, PF17MD_101, PF17MD_110, PF17MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF16MD_000, PF16MD_001, PF16MD_010, PF16MD_011,
+ PF16MD_100, PF16MD_101, PF16MD_110, PF16MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PFCR4", 0xfffe38a6, 16, 4) {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF15MD_000, PF15MD_001, PF15MD_010, PF15MD_011,
+ PF15MD_100, PF15MD_101, PF15MD_110, PF15MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PFCR3", 0xfffe38a8, 16, 4) {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF14MD_000, PF14MD_001, PF14MD_010, PF14MD_011,
+ PF14MD_100, PF14MD_101, PF14MD_110, PF14MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF13MD_000, PF13MD_001, PF13MD_010, PF13MD_011,
+ PF13MD_100, PF13MD_101, PF13MD_110, PF13MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF12MD_000, PF12MD_001, PF12MD_010, PF12MD_011,
+ PF12MD_100, PF12MD_101, PF12MD_110, PF12MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PFCR2", 0xfffe38aa, 16, 4) {
+ PF11MD_000, PF11MD_001, PF11MD_010, PF11MD_011,
+ PF11MD_100, PF11MD_101, PF11MD_110, PF11MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF10MD_000, PF10MD_001, PF10MD_010, PF10MD_011,
+ PF10MD_100, PF10MD_101, PF10MD_110, PF10MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF9MD_000, PF9MD_001, PF9MD_010, PF9MD_011,
+ PF9MD_100, PF9MD_101, PF9MD_110, PF9MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF8MD_000, PF8MD_001, PF8MD_010, PF8MD_011,
+ PF8MD_100, PF8MD_101, PF8MD_110, PF8MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PFCR1", 0xfffe38ac, 16, 4) {
+ PF7MD_000, PF7MD_001, PF7MD_010, PF7MD_011,
+ PF7MD_100, PF7MD_101, PF7MD_110, PF7MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF6MD_000, PF6MD_001, PF6MD_010, PF6MD_011,
+ PF6MD_100, PF6MD_101, PF6MD_110, PF6MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF5MD_000, PF5MD_001, PF5MD_010, PF5MD_011,
+ PF5MD_100, PF5MD_101, PF5MD_110, PF5MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF4MD_000, PF4MD_001, PF4MD_010, PF4MD_011,
+ PF4MD_100, PF4MD_101, PF4MD_110, PF4MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PFCR0", 0xfffe38ae, 16, 4) {
+ PF3MD_000, PF3MD_001, PF3MD_010, PF3MD_011,
+ PF3MD_100, PF3MD_101, PF3MD_110, PF3MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF2MD_000, PF2MD_001, PF2MD_010, PF2MD_011,
+ PF2MD_100, PF2MD_101, PF2MD_110, PF2MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF1MD_000, PF1MD_001, PF1MD_010, PF1MD_011,
+ PF1MD_100, PF1MD_101, PF1MD_110, PF1MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PF0MD_000, PF0MD_001, PF0MD_010, PF0MD_011,
+ PF0MD_100, PF0MD_101, PF0MD_110, PF0MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PFIOR1", 0xfffe38b0, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PF23_IN, PF23_OUT,
+ PF22_IN, PF22_OUT,
+ PF21_IN, PF21_OUT,
+ PF20_IN, PF20_OUT,
+ PF19_IN, PF19_OUT,
+ PF18_IN, PF18_OUT,
+ PF17_IN, PF17_OUT,
+ PF16_IN, PF16_OUT }
+ },
+ { PINMUX_CFG_REG("PFIOR0", 0xfffe38b2, 16, 1) {
+ PF15_IN, PF15_OUT,
+ PF14_IN, PF14_OUT,
+ PF13_IN, PF13_OUT,
+ PF12_IN, PF12_OUT,
+ PF11_IN, PF11_OUT,
+ PF10_IN, PF10_OUT,
+ PF9_IN, PF9_OUT,
+ PF8_IN, PF8_OUT,
+ PF7_IN, PF7_OUT,
+ PF6_IN, PF6_OUT,
+ PF5_IN, PF5_OUT,
+ PF4_IN, PF4_OUT,
+ PF3_IN, PF3_OUT,
+ PF2_IN, PF2_OUT,
+ PF1_IN, PF1_OUT,
+ PF0_IN, PF0_OUT }
+ },
+
+ { PINMUX_CFG_REG("PGCR6", 0xfffe38c2, 16, 4) {
+ PG27MD_00, PG27MD_01, PG27MD_10, PG27MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG26MD_00, PG26MD_01, PG26MD_10, PG26MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG25MD_00, PG25MD_01, PG25MD_10, PG25MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG24MD_00, PG24MD_01, PG24MD_10, PG24MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PGCR5", 0xfffe38c4, 16, 4) {
+ PG23MD_000, PG23MD_001, PG23MD_010, PG23MD_011,
+ PG23MD_100, PG23MD_101, PG23MD_110, PG23MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG22MD_000, PG22MD_001, PG22MD_010, PG22MD_011,
+ PG22MD_100, PG22MD_101, PG22MD_110, PG22MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG21MD_000, PG21MD_001, PG21MD_010, PG21MD_011,
+ PG21MD_100, PG21MD_101, PG21MD_110, PG21MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG20MD_000, PG20MD_001, PG20MD_010, PG20MD_011,
+ PG20MD_100, PG20MD_101, PG20MD_110, PG20MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PGCR4", 0xfffe38c6, 16, 4) {
+ PG19MD_000, PG19MD_001, PG19MD_010, PG19MD_011,
+ PG19MD_100, PG19MD_101, PG19MD_110, PG19MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG18MD_000, PG18MD_001, PG18MD_010, PG18MD_011,
+ PG18MD_100, PG18MD_101, PG18MD_110, PG18MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG17MD_00, PG17MD_01, PG17MD_10, PG17MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG16MD_00, PG16MD_01, PG16MD_10, PG16MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PGCR3", 0xfffe38c8, 16, 4) {
+ PG15MD_00, PG15MD_01, PG15MD_10, PG15MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG14MD_00, PG14MD_01, PG14MD_10, PG14MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG13MD_00, PG13MD_01, PG13MD_10, PG13MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG12MD_00, PG12MD_01, PG12MD_10, PG12MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PGCR2", 0xfffe38ca, 16, 4) {
+ PG11MD_000, PG11MD_001, PG11MD_010, PG11MD_011,
+ PG11MD_100, PG11MD_101, PG11MD_110, PG11MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG10MD_000, PG10MD_001, PG10MD_010, PG10MD_011,
+ PG10MD_100, PG10MD_101, PG10MD_110, PG10MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG9MD_000, PG9MD_001, PG9MD_010, PG9MD_011,
+ PG9MD_100, PG9MD_101, PG9MD_110, PG9MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG8MD_000, PG8MD_001, PG8MD_010, PG8MD_011,
+ PG8MD_100, PG8MD_101, PG8MD_110, PG8MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PGCR1", 0xfffe38cc, 16, 4) {
+ PG7MD_000, PG7MD_001, PG7MD_010, PG7MD_011,
+ PG7MD_100, PG7MD_101, PG7MD_110, PG7MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG6MD_000, PG6MD_001, PG6MD_010, PG6MD_011,
+ PG6MD_100, PG6MD_101, PG6MD_110, PG6MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG5MD_000, PG5MD_001, PG5MD_010, PG5MD_011,
+ PG5MD_100, PG5MD_101, PG5MD_110, PG5MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG4MD_000, PG4MD_001, PG4MD_010, PG4MD_011,
+ PG4MD_100, PG4MD_101, PG4MD_110, PG4MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PGCR0", 0xfffe38ce, 16, 4) {
+ PG3MD_000, PG3MD_001, PG3MD_010, PG3MD_011,
+ PG3MD_100, PG3MD_101, PG3MD_110, PG3MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG2MD_000, PG2MD_001, PG2MD_010, PG2MD_011,
+ PG2MD_100, PG2MD_101, PG2MD_110, PG2MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG1MD_000, PG1MD_001, PG1MD_010, PG1MD_011,
+ PG1MD_100, PG1MD_101, PG1MD_110, PG1MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PG0MD_000, PG0MD_001, PG0MD_010, PG0MD_011,
+ PG0MD_100, PG0MD_101, PG0MD_110, PG0MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PGIOR1", 0xfffe38d0, 16, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PG27_IN, PG27_OUT,
+ PG26_IN, PG26_OUT,
+ PG25_IN, PG25_OUT,
+ PG24_IN, PG24_OUT,
+ PG23_IN, PG23_OUT,
+ PG22_IN, PG22_OUT,
+ PG21_IN, PG21_OUT,
+ PG20_IN, PG20_OUT,
+ PG19_IN, PG19_OUT,
+ PG18_IN, PG18_OUT,
+ PG17_IN, PG17_OUT,
+ PG16_IN, PG16_OUT }
+ },
+ { PINMUX_CFG_REG("PGIOR0", 0xfffe38d2, 16, 1) {
+ PG15_IN, PG15_OUT,
+ PG14_IN, PG14_OUT,
+ PG13_IN, PG13_OUT,
+ PG12_IN, PG12_OUT,
+ PG11_IN, PG11_OUT,
+ PG10_IN, PG10_OUT,
+ PG9_IN, PG9_OUT,
+ PG8_IN, PG8_OUT,
+ PG7_IN, PG7_OUT,
+ PG6_IN, PG6_OUT,
+ PG5_IN, PG5_OUT,
+ PG4_IN, PG4_OUT,
+ PG3_IN, PG3_OUT,
+ PG2_IN, PG2_OUT,
+ PG1_IN, PG1_OUT,
+ PG0_IN, PG0_OUT }
+ },
+
+ { PINMUX_CFG_REG("PHCR1", 0xfffe38ec, 16, 4) {
+ PH7MD_00, PH7MD_01, PH7MD_10, PH7MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PH6MD_00, PH6MD_01, PH6MD_10, PH6MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PH5MD_00, PH5MD_01, PH5MD_10, PH5MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PH4MD_00, PH4MD_01, PH4MD_10, PH4MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PHCR0", 0xfffe38ee, 16, 4) {
+ PH3MD_00, PH3MD_01, PH3MD_10, PH3MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PH2MD_00, PH2MD_01, PH2MD_10, PH2MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PH1MD_00, PH1MD_01, PH1MD_10, PH1MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PH0MD_00, PH0MD_01, PH0MD_10, PH0MD_11, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PJCR7", 0xfffe3900, 16, 4) {
+ PJ31MD_0, PJ31MD_1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ30MD_000, PJ30MD_001, PJ30MD_010, PJ30MD_011,
+ PJ30MD_100, PJ30MD_101, PJ30MD_110, PJ30MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ29MD_000, PJ29MD_001, PJ29MD_010, PJ29MD_011,
+ PJ29MD_100, PJ29MD_101, PJ29MD_110, PJ29MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ28MD_000, PJ28MD_001, PJ28MD_010, PJ28MD_011,
+ PJ28MD_100, PJ28MD_101, PJ28MD_110, PJ28MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PJCR6", 0xfffe3902, 16, 4) {
+ PJ27MD_000, PJ27MD_001, PJ27MD_010, PJ27MD_011,
+ PJ27MD_100, PJ27MD_101, PJ27MD_110, PJ27MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ26MD_000, PJ26MD_001, PJ26MD_010, PJ26MD_011,
+ PJ26MD_100, PJ26MD_101, PJ26MD_110, PJ26MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ25MD_000, PJ25MD_001, PJ25MD_010, PJ25MD_011,
+ PJ25MD_100, PJ25MD_101, PJ25MD_110, PJ25MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ24MD_000, PJ24MD_001, PJ24MD_010, PJ24MD_011,
+ PJ24MD_100, PJ24MD_101, PJ24MD_110, PJ24MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PJCR5", 0xfffe3904, 16, 4) {
+ PJ23MD_000, PJ23MD_001, PJ23MD_010, PJ23MD_011,
+ PJ23MD_100, PJ23MD_101, PJ23MD_110, PJ23MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ22MD_000, PJ22MD_001, PJ22MD_010, PJ22MD_011,
+ PJ22MD_100, PJ22MD_101, PJ22MD_110, PJ22MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ21MD_000, PJ21MD_001, PJ21MD_010, PJ21MD_011,
+ PJ21MD_100, PJ21MD_101, PJ21MD_110, PJ21MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ20MD_000, PJ20MD_001, PJ20MD_010, PJ20MD_011,
+ PJ20MD_100, PJ20MD_101, PJ20MD_110, PJ20MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PJCR4", 0xfffe3906, 16, 4) {
+ PJ19MD_000, PJ19MD_001, PJ19MD_010, PJ19MD_011,
+ PJ19MD_100, PJ19MD_101, PJ19MD_110, PJ19MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ18MD_000, PJ18MD_001, PJ18MD_010, PJ18MD_011,
+ PJ18MD_100, PJ18MD_101, PJ18MD_110, PJ18MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ17MD_000, PJ17MD_001, PJ17MD_010, PJ17MD_011,
+ PJ17MD_100, PJ17MD_101, PJ17MD_110, PJ17MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ16MD_000, PJ16MD_001, PJ16MD_010, PJ16MD_011,
+ PJ16MD_100, PJ16MD_101, PJ16MD_110, PJ16MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PJCR3", 0xfffe3908, 16, 4) {
+ PJ15MD_000, PJ15MD_001, PJ15MD_010, PJ15MD_011,
+ PJ15MD_100, PJ15MD_101, PJ15MD_110, PJ15MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ14MD_000, PJ14MD_001, PJ14MD_010, PJ14MD_011,
+ PJ14MD_100, PJ14MD_101, PJ14MD_110, PJ14MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ13MD_000, PJ13MD_001, PJ13MD_010, PJ13MD_011,
+ PJ13MD_100, PJ13MD_101, PJ13MD_110, PJ13MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ12MD_000, PJ12MD_001, PJ12MD_010, PJ12MD_011,
+ PJ12MD_100, PJ12MD_101, PJ12MD_110, PJ12MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PJCR2", 0xfffe390a, 16, 4) {
+ PJ11MD_000, PJ11MD_001, PJ11MD_010, PJ11MD_011,
+ PJ11MD_100, PJ11MD_101, PJ11MD_110, PJ11MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ10MD_000, PJ10MD_001, PJ10MD_010, PJ10MD_011,
+ PJ10MD_100, PJ10MD_101, PJ10MD_110, PJ10MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ9MD_000, PJ9MD_001, PJ9MD_010, PJ9MD_011,
+ PJ9MD_100, PJ9MD_101, PJ9MD_110, PJ9MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ8MD_000, PJ8MD_001, PJ8MD_010, PJ8MD_011,
+ PJ8MD_100, PJ8MD_101, PJ8MD_110, PJ8MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PJCR1", 0xfffe390c, 16, 4) {
+ PJ7MD_000, PJ7MD_001, PJ7MD_010, PJ7MD_011,
+ PJ7MD_100, PJ7MD_101, PJ7MD_110, PJ7MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ6MD_000, PJ6MD_001, PJ6MD_010, PJ6MD_011,
+ PJ6MD_100, PJ6MD_101, PJ6MD_110, PJ6MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ5MD_000, PJ5MD_001, PJ5MD_010, PJ5MD_011,
+ PJ5MD_100, PJ5MD_101, PJ5MD_110, PJ5MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ4MD_000, PJ4MD_001, PJ4MD_010, PJ4MD_011,
+ PJ4MD_100, PJ4MD_101, PJ4MD_110, PJ4MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG("PJCR0", 0xfffe390e, 16, 4) {
+ PJ3MD_000, PJ3MD_001, PJ3MD_010, PJ3MD_011,
+ PJ3MD_100, PJ3MD_101, PJ3MD_110, PJ3MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ2MD_000, PJ2MD_001, PJ2MD_010, PJ2MD_011,
+ PJ2MD_100, PJ2MD_101, PJ2MD_110, PJ2MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ1MD_000, PJ1MD_001, PJ1MD_010, PJ1MD_011,
+ PJ1MD_100, PJ1MD_101, PJ1MD_110, PJ1MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+
+ PJ0MD_000, PJ0MD_001, PJ0MD_010, PJ0MD_011,
+ PJ0MD_100, PJ0MD_101, PJ0MD_110, PJ0MD_111,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
+ },
+
+ { PINMUX_CFG_REG("PJIOR1", 0xfffe3910, 16, 1) {
+ PJ31_IN, PJ31_OUT,
+ PJ30_IN, PJ30_OUT,
+ PJ29_IN, PJ29_OUT,
+ PJ28_IN, PJ28_OUT,
+ PJ27_IN, PJ27_OUT,
+ PJ26_IN, PJ26_OUT,
+ PJ25_IN, PJ25_OUT,
+ PJ24_IN, PJ24_OUT,
+ PJ23_IN, PJ23_OUT,
+ PJ22_IN, PJ22_OUT,
+ PJ21_IN, PJ21_OUT,
+ PJ20_IN, PJ20_OUT,
+ PJ19_IN, PJ19_OUT,
+ PJ18_IN, PJ18_OUT,
+ PJ17_IN, PJ17_OUT,
+ PJ16_IN, PJ16_OUT }
+ },
+ { PINMUX_CFG_REG("PJIOR0", 0xfffe3912, 16, 1) {
+ PJ15_IN, PJ15_OUT,
+ PJ14_IN, PJ14_OUT,
+ PJ13_IN, PJ13_OUT,
+ PJ12_IN, PJ12_OUT,
+ PJ11_IN, PJ11_OUT,
+ PJ10_IN, PJ10_OUT,
+ PJ9_IN, PJ9_OUT,
+ PJ8_IN, PJ8_OUT,
+ PJ7_IN, PJ7_OUT,
+ PJ6_IN, PJ6_OUT,
+ PJ5_IN, PJ5_OUT,
+ PJ4_IN, PJ4_OUT,
+ PJ3_IN, PJ3_OUT,
+ PJ2_IN, PJ2_OUT,
+ PJ1_IN, PJ1_OUT,
+ PJ0_IN, PJ0_OUT }
+ },
+
+ {}
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+ { PINMUX_DATA_REG("PADR0", 0xfffe3816, 16) {
+ 0, 0, 0, 0, 0, 0, 0, PA1_DATA,
+ 0, 0, 0, 0, 0, 0, 0, PA0_DATA }
+ },
+
+ { PINMUX_DATA_REG("PBDR1", 0xfffe3834, 16) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, PB22_DATA, PB21_DATA, PB20_DATA,
+ PB19_DATA, PB18_DATA, PB17_DATA, PB16_DATA }
+ },
+ { PINMUX_DATA_REG("PBDR0", 0xfffe3836, 16) {
+ PB15_DATA, PB14_DATA, PB13_DATA, PB12_DATA,
+ PB11_DATA, PB10_DATA, PB9_DATA, PB8_DATA,
+ PB7_DATA, PB6_DATA, PB5_DATA, PB4_DATA,
+ PB3_DATA, PB2_DATA, PB1_DATA, 0 }
+ },
+
+ { PINMUX_DATA_REG("PCDR0", 0xfffe3856, 16) {
+ 0, 0, 0, 0,
+ 0, 0, 0, PC8_DATA,
+ PC7_DATA, PC6_DATA, PC5_DATA, PC4_DATA,
+ PC3_DATA, PC2_DATA, PC1_DATA, PC0_DATA }
+ },
+
+ { PINMUX_DATA_REG("PDDR0", 0xfffe3876, 16) {
+ PD15_DATA, PD14_DATA, PD13_DATA, PD12_DATA,
+ PD11_DATA, PD10_DATA, PD9_DATA, PD8_DATA,
+ PD7_DATA, PD6_DATA, PD5_DATA, PD4_DATA,
+ PD3_DATA, PD2_DATA, PD1_DATA, PD0_DATA }
+ },
+
+ { PINMUX_DATA_REG("PEDR0", 0xfffe3896, 16) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PE7_DATA, PE6_DATA, PE5_DATA, PE4_DATA,
+ PE3_DATA, PE2_DATA, PE1_DATA, PE0_DATA }
+ },
+
+ { PINMUX_DATA_REG("PFDR1", 0xfffe38b4, 16) {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ PF23_DATA, PF22_DATA, PF21_DATA, PF20_DATA,
+ PF19_DATA, PF18_DATA, PF17_DATA, PF16_DATA }
+ },
+ { PINMUX_DATA_REG("PFDR0", 0xfffe38b6, 16) {
+ PF15_DATA, PF14_DATA, PF13_DATA, PF12_DATA,
+ PF11_DATA, PF10_DATA, PF9_DATA, PF8_DATA,
+ PF7_DATA, PF6_DATA, PF5_DATA, PF4_DATA,
+ PF3_DATA, PF2_DATA, PF1_DATA, PF0_DATA }
+ },
+
+ { PINMUX_DATA_REG("PGDR1", 0xfffe38d4, 16) {
+ 0, 0, 0, 0,
+ PG27_DATA, PG26_DATA, PG25_DATA, PG24_DATA,
+ PG23_DATA, PG22_DATA, PG21_DATA, PG20_DATA,
+ PG19_DATA, PG18_DATA, PG17_DATA, PG16_DATA }
+ },
+ { PINMUX_DATA_REG("PGDR0", 0xfffe38d6, 16) {
+ PG15_DATA, PG14_DATA, PG13_DATA, PG12_DATA,
+ PG11_DATA, PG10_DATA, PG9_DATA, PG8_DATA,
+ PG7_DATA, PG6_DATA, PG5_DATA, PG4_DATA,
+ PG3_DATA, PG2_DATA, PG1_DATA, PG0_DATA }
+ },
+
+ { PINMUX_DATA_REG("PJDR1", 0xfffe3914, 16) {
+ PJ31_DATA, PJ30_DATA, PJ29_DATA, PJ28_DATA,
+ PJ27_DATA, PJ26_DATA, PJ25_DATA, PJ24_DATA,
+ PJ23_DATA, PJ22_DATA, PJ21_DATA, PJ20_DATA,
+ PJ19_DATA, PJ18_DATA, PJ17_DATA, PJ16_DATA }
+ },
+ { PINMUX_DATA_REG("PJDR0", 0xfffe3916, 16) {
+ PJ15_DATA, PJ14_DATA, PJ13_DATA, PJ12_DATA,
+ PJ11_DATA, PJ10_DATA, PJ9_DATA, PJ8_DATA,
+ PJ7_DATA, PJ6_DATA, PJ5_DATA, PJ4_DATA,
+ PJ3_DATA, PJ2_DATA, PJ1_DATA, PJ0_DATA }
+ },
+
+ { }
+};
+
+static struct pinmux_info sh7269_pinmux_info = {
+ .name = "sh7269_pfc",
+ .reserved_id = PINMUX_RESERVED,
+ .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+ .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END, FORCE_IN },
+ .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END, FORCE_OUT },
+ .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+ .first_gpio = GPIO_PA1,
+ .last_gpio = GPIO_FN_LCD_M_DISP,
+
+ .gpios = pinmux_gpios,
+ .cfg_regs = pinmux_config_regs,
+ .data_regs = pinmux_data_regs,
+
+ .gpio_data = pinmux_data,
+ .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
+
+static int __init plat_pinmux_setup(void)
+{
+ return register_pinmux(&sh7269_pinmux_info);
+}
+arch_initcall(plat_pinmux_setup);
diff --git a/arch/sh/kernel/cpu/sh2a/probe.c b/arch/sh/kernel/cpu/sh2a/probe.c
index 48e97a2a0c8d..5170b6aa4129 100644
--- a/arch/sh/kernel/cpu/sh2a/probe.c
+++ b/arch/sh/kernel/cpu/sh2a/probe.c
@@ -29,6 +29,12 @@ void __cpuinit cpu_probe(void)
#elif defined(CONFIG_CPU_SUBTYPE_SH7263)
boot_cpu_data.type = CPU_SH7263;
boot_cpu_data.flags |= CPU_HAS_FPU;
+#elif defined(CONFIG_CPU_SUBTYPE_SH7264)
+ boot_cpu_data.type = CPU_SH7264;
+ boot_cpu_data.flags |= CPU_HAS_FPU;
+#elif defined(CONFIG_CPU_SUBTYPE_SH7269)
+ boot_cpu_data.type = CPU_SH7269;
+ boot_cpu_data.flags |= CPU_HAS_FPU;
#elif defined(CONFIG_CPU_SUBTYPE_SH7206)
boot_cpu_data.type = CPU_SH7206;
boot_cpu_data.flags |= CPU_HAS_DSP;
diff --git a/arch/sh/kernel/cpu/sh2a/setup-mxg.c b/arch/sh/kernel/cpu/sh2a/setup-mxg.c
index 949bf2bac28c..f7f1cf2af302 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-mxg.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-mxg.c
@@ -204,7 +204,7 @@ static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 220, 220, 220, 220 },
+ .irqs = SCIx_IRQ_MUXED(220),
};
static struct platform_device scif0_device = {
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7201.c b/arch/sh/kernel/cpu/sh2a/setup-sh7201.c
index 9df558dcdb86..7b84785b8962 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7201.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7201.c
@@ -183,7 +183,7 @@ static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 180, 180, 180, 180 }
+ .irqs = SCIx_IRQ_MUXED(180),
};
static struct platform_device scif0_device = {
@@ -200,7 +200,7 @@ static struct plat_sci_port scif1_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 184, 184, 184, 184 }
+ .irqs = SCIx_IRQ_MUXED(184),
};
static struct platform_device scif1_device = {
@@ -217,7 +217,7 @@ static struct plat_sci_port scif2_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 188, 188, 188, 188 }
+ .irqs = SCIx_IRQ_MUXED(188),
};
static struct platform_device scif2_device = {
@@ -234,7 +234,7 @@ static struct plat_sci_port scif3_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 192, 192, 192, 192 }
+ .irqs = SCIx_IRQ_MUXED(192),
};
static struct platform_device scif3_device = {
@@ -251,7 +251,7 @@ static struct plat_sci_port scif4_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 196, 196, 196, 196 }
+ .irqs = SCIx_IRQ_MUXED(196),
};
static struct platform_device scif4_device = {
@@ -268,7 +268,7 @@ static struct plat_sci_port scif5_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 200, 200, 200, 200 }
+ .irqs = SCIx_IRQ_MUXED(200),
};
static struct platform_device scif5_device = {
@@ -285,7 +285,7 @@ static struct plat_sci_port scif6_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 204, 204, 204, 204 }
+ .irqs = SCIx_IRQ_MUXED(204),
};
static struct platform_device scif6_device = {
@@ -302,7 +302,7 @@ static struct plat_sci_port scif7_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 208, 208, 208, 208 }
+ .irqs = SCIx_IRQ_MUXED(208),
};
static struct platform_device scif7_device = {
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7203.c b/arch/sh/kernel/cpu/sh2a/setup-sh7203.c
index 0bd744f9a3b7..bfc33f6a28c3 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7203.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7203.c
@@ -180,7 +180,7 @@ static struct plat_sci_port scif0_platform_data = {
SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 192, 192, 192, 192 },
+ .irqs = SCIx_IRQ_MUXED(192),
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
@@ -199,7 +199,7 @@ static struct plat_sci_port scif1_platform_data = {
SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 196, 196, 196, 196 },
+ .irqs = SCIx_IRQ_MUXED(196),
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
@@ -218,7 +218,7 @@ static struct plat_sci_port scif2_platform_data = {
SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 200, 200, 200, 200 },
+ .irqs = SCIx_IRQ_MUXED(200),
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
@@ -237,7 +237,7 @@ static struct plat_sci_port scif3_platform_data = {
SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 204, 204, 204, 204 },
+ .irqs = SCIx_IRQ_MUXED(204),
.regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
};
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
index 5d14f849aea3..a5010741de85 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
@@ -139,7 +139,7 @@ static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 240, 240, 240, 240 },
+ .irqs = SCIx_IRQ_MUXED(240),
};
static struct platform_device scif0_device = {
@@ -156,7 +156,7 @@ static struct plat_sci_port scif1_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 244, 244, 244, 244 },
+ .irqs = SCIx_IRQ_MUXED(244),
};
static struct platform_device scif1_device = {
@@ -173,7 +173,7 @@ static struct plat_sci_port scif2_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 248, 248, 248, 248 },
+ .irqs = SCIx_IRQ_MUXED(248),
};
static struct platform_device scif2_device = {
@@ -190,7 +190,7 @@ static struct plat_sci_port scif3_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 252, 252, 252, 252 },
+ .irqs = SCIx_IRQ_MUXED(252),
};
static struct platform_device scif3_device = {
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7264.c b/arch/sh/kernel/cpu/sh2a/setup-sh7264.c
new file mode 100644
index 000000000000..ce5c1b5aebfa
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7264.c
@@ -0,0 +1,606 @@
+/*
+ * SH7264 Setup
+ *
+ * Copyright (C) 2012 Renesas Electronics Europe Ltd
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/serial_sci.h>
+#include <linux/usb/r8a66597.h>
+#include <linux/sh_timer.h>
+#include <linux/io.h>
+
+enum {
+ UNUSED = 0,
+
+ /* interrupt sources */
+ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+ PINT0, PINT1, PINT2, PINT3, PINT4, PINT5, PINT6, PINT7,
+
+ DMAC0, DMAC1, DMAC2, DMAC3, DMAC4, DMAC5, DMAC6, DMAC7,
+ DMAC8, DMAC9, DMAC10, DMAC11, DMAC12, DMAC13, DMAC14, DMAC15,
+ USB, VDC3, CMT0, CMT1, BSC, WDT,
+ MTU0_ABCD, MTU0_VEF, MTU1_AB, MTU1_VU, MTU2_AB, MTU2_VU,
+ MTU3_ABCD, MTU3_TCI3V, MTU4_ABCD, MTU4_TCI4V,
+ PWMT1, PWMT2, ADC_ADI,
+ SSIF0, SSII1, SSII2, SSII3,
+ RSPDIF,
+ IIC30, IIC31, IIC32, IIC33,
+ SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI,
+ SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI,
+ SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI,
+ SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI,
+ SCIF4_BRI, SCIF4_ERI, SCIF4_RXI, SCIF4_TXI,
+ SCIF5_BRI, SCIF5_ERI, SCIF5_RXI, SCIF5_TXI,
+ SCIF6_BRI, SCIF6_ERI, SCIF6_RXI, SCIF6_TXI,
+ SCIF7_BRI, SCIF7_ERI, SCIF7_RXI, SCIF7_TXI,
+ SIO_FIFO, RSPIC0, RSPIC1,
+ RCAN0, RCAN1, IEBC, CD_ROMD,
+ NFMC, SDHI, RTC,
+ SRCC0, SRCC1, DCOMU, OFFI, IFEI,
+
+ /* interrupt groups */
+ PINT, SCIF0, SCIF1, SCIF2, SCIF3, SCIF4, SCIF5, SCIF6, SCIF7,
+};
+
+static struct intc_vect vectors[] __initdata = {
+ INTC_IRQ(IRQ0, 64), INTC_IRQ(IRQ1, 65),
+ INTC_IRQ(IRQ2, 66), INTC_IRQ(IRQ3, 67),
+ INTC_IRQ(IRQ4, 68), INTC_IRQ(IRQ5, 69),
+ INTC_IRQ(IRQ6, 70), INTC_IRQ(IRQ7, 71),
+
+ INTC_IRQ(PINT0, 80), INTC_IRQ(PINT1, 81),
+ INTC_IRQ(PINT2, 82), INTC_IRQ(PINT3, 83),
+ INTC_IRQ(PINT4, 84), INTC_IRQ(PINT5, 85),
+ INTC_IRQ(PINT6, 86), INTC_IRQ(PINT7, 87),
+
+ INTC_IRQ(DMAC0, 108), INTC_IRQ(DMAC0, 109),
+ INTC_IRQ(DMAC1, 112), INTC_IRQ(DMAC1, 113),
+ INTC_IRQ(DMAC2, 116), INTC_IRQ(DMAC2, 117),
+ INTC_IRQ(DMAC3, 120), INTC_IRQ(DMAC3, 121),
+ INTC_IRQ(DMAC4, 124), INTC_IRQ(DMAC4, 125),
+ INTC_IRQ(DMAC5, 128), INTC_IRQ(DMAC5, 129),
+ INTC_IRQ(DMAC6, 132), INTC_IRQ(DMAC6, 133),
+ INTC_IRQ(DMAC7, 136), INTC_IRQ(DMAC7, 137),
+ INTC_IRQ(DMAC8, 140), INTC_IRQ(DMAC8, 141),
+ INTC_IRQ(DMAC9, 144), INTC_IRQ(DMAC9, 145),
+ INTC_IRQ(DMAC10, 148), INTC_IRQ(DMAC10, 149),
+ INTC_IRQ(DMAC11, 152), INTC_IRQ(DMAC11, 153),
+ INTC_IRQ(DMAC12, 156), INTC_IRQ(DMAC12, 157),
+ INTC_IRQ(DMAC13, 160), INTC_IRQ(DMAC13, 161),
+ INTC_IRQ(DMAC14, 164), INTC_IRQ(DMAC14, 165),
+ INTC_IRQ(DMAC15, 168), INTC_IRQ(DMAC15, 169),
+
+ INTC_IRQ(USB, 170),
+ INTC_IRQ(VDC3, 171), INTC_IRQ(VDC3, 172),
+ INTC_IRQ(VDC3, 173), INTC_IRQ(VDC3, 174),
+ INTC_IRQ(CMT0, 175), INTC_IRQ(CMT1, 176),
+ INTC_IRQ(BSC, 177), INTC_IRQ(WDT, 178),
+
+ INTC_IRQ(MTU0_ABCD, 179), INTC_IRQ(MTU0_ABCD, 180),
+ INTC_IRQ(MTU0_ABCD, 181), INTC_IRQ(MTU0_ABCD, 182),
+ INTC_IRQ(MTU0_VEF, 183),
+ INTC_IRQ(MTU0_VEF, 184), INTC_IRQ(MTU0_VEF, 185),
+ INTC_IRQ(MTU1_AB, 186), INTC_IRQ(MTU1_AB, 187),
+ INTC_IRQ(MTU1_VU, 188), INTC_IRQ(MTU1_VU, 189),
+ INTC_IRQ(MTU2_AB, 190), INTC_IRQ(MTU2_AB, 191),
+ INTC_IRQ(MTU2_VU, 192), INTC_IRQ(MTU2_VU, 193),
+ INTC_IRQ(MTU3_ABCD, 194), INTC_IRQ(MTU3_ABCD, 195),
+ INTC_IRQ(MTU3_ABCD, 196), INTC_IRQ(MTU3_ABCD, 197),
+ INTC_IRQ(MTU3_TCI3V, 198),
+ INTC_IRQ(MTU4_ABCD, 199), INTC_IRQ(MTU4_ABCD, 200),
+ INTC_IRQ(MTU4_ABCD, 201), INTC_IRQ(MTU4_ABCD, 202),
+ INTC_IRQ(MTU4_TCI4V, 203),
+
+ INTC_IRQ(PWMT1, 204), INTC_IRQ(PWMT2, 205),
+
+ INTC_IRQ(ADC_ADI, 206),
+
+ INTC_IRQ(SSIF0, 207), INTC_IRQ(SSIF0, 208),
+ INTC_IRQ(SSIF0, 209),
+ INTC_IRQ(SSII1, 210), INTC_IRQ(SSII1, 211),
+ INTC_IRQ(SSII2, 212), INTC_IRQ(SSII2, 213),
+ INTC_IRQ(SSII3, 214), INTC_IRQ(SSII3, 215),
+
+ INTC_IRQ(RSPDIF, 216),
+
+ INTC_IRQ(IIC30, 217), INTC_IRQ(IIC30, 218),
+ INTC_IRQ(IIC30, 219), INTC_IRQ(IIC30, 220),
+ INTC_IRQ(IIC30, 221),
+ INTC_IRQ(IIC31, 222), INTC_IRQ(IIC31, 223),
+ INTC_IRQ(IIC31, 224), INTC_IRQ(IIC31, 225),
+ INTC_IRQ(IIC31, 226),
+ INTC_IRQ(IIC32, 227), INTC_IRQ(IIC32, 228),
+ INTC_IRQ(IIC32, 229), INTC_IRQ(IIC32, 230),
+ INTC_IRQ(IIC32, 231),
+
+ INTC_IRQ(SCIF0_BRI, 232), INTC_IRQ(SCIF0_ERI, 233),
+ INTC_IRQ(SCIF0_RXI, 234), INTC_IRQ(SCIF0_TXI, 235),
+ INTC_IRQ(SCIF1_BRI, 236), INTC_IRQ(SCIF1_ERI, 237),
+ INTC_IRQ(SCIF1_RXI, 238), INTC_IRQ(SCIF1_TXI, 239),
+ INTC_IRQ(SCIF2_BRI, 240), INTC_IRQ(SCIF2_ERI, 241),
+ INTC_IRQ(SCIF2_RXI, 242), INTC_IRQ(SCIF2_TXI, 243),
+ INTC_IRQ(SCIF3_BRI, 244), INTC_IRQ(SCIF3_ERI, 245),
+ INTC_IRQ(SCIF3_RXI, 246), INTC_IRQ(SCIF3_TXI, 247),
+ INTC_IRQ(SCIF4_BRI, 248), INTC_IRQ(SCIF4_ERI, 249),
+ INTC_IRQ(SCIF4_RXI, 250), INTC_IRQ(SCIF4_TXI, 251),
+ INTC_IRQ(SCIF5_BRI, 252), INTC_IRQ(SCIF5_ERI, 253),
+ INTC_IRQ(SCIF5_RXI, 254), INTC_IRQ(SCIF5_TXI, 255),
+ INTC_IRQ(SCIF6_BRI, 256), INTC_IRQ(SCIF6_ERI, 257),
+ INTC_IRQ(SCIF6_RXI, 258), INTC_IRQ(SCIF6_TXI, 259),
+ INTC_IRQ(SCIF7_BRI, 260), INTC_IRQ(SCIF7_ERI, 261),
+ INTC_IRQ(SCIF7_RXI, 262), INTC_IRQ(SCIF7_TXI, 263),
+
+ INTC_IRQ(SIO_FIFO, 264),
+
+ INTC_IRQ(RSPIC0, 265), INTC_IRQ(RSPIC0, 266),
+ INTC_IRQ(RSPIC0, 267),
+ INTC_IRQ(RSPIC1, 268), INTC_IRQ(RSPIC1, 269),
+ INTC_IRQ(RSPIC1, 270),
+
+ INTC_IRQ(RCAN0, 271), INTC_IRQ(RCAN0, 272),
+ INTC_IRQ(RCAN0, 273), INTC_IRQ(RCAN0, 274),
+ INTC_IRQ(RCAN0, 275),
+ INTC_IRQ(RCAN1, 276), INTC_IRQ(RCAN1, 277),
+ INTC_IRQ(RCAN1, 278), INTC_IRQ(RCAN1, 279),
+ INTC_IRQ(RCAN1, 280),
+
+ INTC_IRQ(IEBC, 281),
+
+ INTC_IRQ(CD_ROMD, 282), INTC_IRQ(CD_ROMD, 283),
+ INTC_IRQ(CD_ROMD, 284), INTC_IRQ(CD_ROMD, 285),
+ INTC_IRQ(CD_ROMD, 286), INTC_IRQ(CD_ROMD, 287),
+
+ INTC_IRQ(NFMC, 288), INTC_IRQ(NFMC, 289),
+ INTC_IRQ(NFMC, 290), INTC_IRQ(NFMC, 291),
+
+ INTC_IRQ(SDHI, 292), INTC_IRQ(SDHI, 293),
+ INTC_IRQ(SDHI, 294),
+
+ INTC_IRQ(RTC, 296), INTC_IRQ(RTC, 297),
+ INTC_IRQ(RTC, 298),
+
+ INTC_IRQ(SRCC0, 299), INTC_IRQ(SRCC0, 300),
+ INTC_IRQ(SRCC0, 301), INTC_IRQ(SRCC0, 302),
+ INTC_IRQ(SRCC0, 303),
+ INTC_IRQ(SRCC1, 304), INTC_IRQ(SRCC1, 305),
+ INTC_IRQ(SRCC1, 306), INTC_IRQ(SRCC1, 307),
+ INTC_IRQ(SRCC1, 308),
+
+ INTC_IRQ(DCOMU, 310), INTC_IRQ(DCOMU, 311),
+ INTC_IRQ(DCOMU, 312),
+};
+
+static struct intc_group groups[] __initdata = {
+ INTC_GROUP(PINT, PINT0, PINT1, PINT2, PINT3,
+ PINT4, PINT5, PINT6, PINT7),
+ INTC_GROUP(SCIF0, SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI),
+ INTC_GROUP(SCIF1, SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI),
+ INTC_GROUP(SCIF2, SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI),
+ INTC_GROUP(SCIF3, SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI),
+ INTC_GROUP(SCIF4, SCIF4_BRI, SCIF4_ERI, SCIF4_RXI, SCIF4_TXI),
+ INTC_GROUP(SCIF5, SCIF5_BRI, SCIF5_ERI, SCIF5_RXI, SCIF5_TXI),
+ INTC_GROUP(SCIF6, SCIF6_BRI, SCIF6_ERI, SCIF6_RXI, SCIF6_TXI),
+ INTC_GROUP(SCIF7, SCIF7_BRI, SCIF7_ERI, SCIF7_RXI, SCIF7_TXI),
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+ { 0xfffe0818, 0, 16, 4, /* IPR01 */ { IRQ0, IRQ1, IRQ2, IRQ3 } },
+ { 0xfffe081a, 0, 16, 4, /* IPR02 */ { IRQ4, IRQ5, IRQ6, IRQ7 } },
+ { 0xfffe0820, 0, 16, 4, /* IPR05 */ { PINT, 0, 0, 0 } },
+ { 0xfffe0c00, 0, 16, 4, /* IPR06 */ { DMAC0, DMAC1, DMAC2, DMAC3 } },
+ { 0xfffe0c02, 0, 16, 4, /* IPR07 */ { DMAC4, DMAC5, DMAC6, DMAC7 } },
+ { 0xfffe0c04, 0, 16, 4, /* IPR08 */ { DMAC8, DMAC9,
+ DMAC10, DMAC11 } },
+ { 0xfffe0c06, 0, 16, 4, /* IPR09 */ { DMAC12, DMAC13,
+ DMAC14, DMAC15 } },
+ { 0xfffe0c08, 0, 16, 4, /* IPR10 */ { USB, VDC3, CMT0, CMT1 } },
+ { 0xfffe0c0a, 0, 16, 4, /* IPR11 */ { BSC, WDT, MTU0_ABCD, MTU0_VEF } },
+ { 0xfffe0c0c, 0, 16, 4, /* IPR12 */ { MTU1_AB, MTU1_VU,
+ MTU2_AB, MTU2_VU } },
+ { 0xfffe0c0e, 0, 16, 4, /* IPR13 */ { MTU3_ABCD, MTU3_TCI3V,
+ MTU4_ABCD, MTU4_TCI4V } },
+ { 0xfffe0c10, 0, 16, 4, /* IPR14 */ { PWMT1, PWMT2, ADC_ADI, 0 } },
+ { 0xfffe0c12, 0, 16, 4, /* IPR15 */ { SSIF0, SSII1, SSII2, SSII3 } },
+ { 0xfffe0c14, 0, 16, 4, /* IPR16 */ { RSPDIF, IIC30, IIC31, IIC32 } },
+ { 0xfffe0c16, 0, 16, 4, /* IPR17 */ { SCIF0, SCIF1, SCIF2, SCIF3 } },
+ { 0xfffe0c18, 0, 16, 4, /* IPR18 */ { SCIF4, SCIF5, SCIF6, SCIF7 } },
+ { 0xfffe0c1a, 0, 16, 4, /* IPR19 */ { SIO_FIFO, 0, RSPIC0, RSPIC1, } },
+ { 0xfffe0c1c, 0, 16, 4, /* IPR20 */ { RCAN0, RCAN1, IEBC, CD_ROMD } },
+ { 0xfffe0c1e, 0, 16, 4, /* IPR21 */ { NFMC, SDHI, RTC, 0 } },
+ { 0xfffe0c20, 0, 16, 4, /* IPR22 */ { SRCC0, SRCC1, 0, DCOMU } },
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+ { 0xfffe0808, 0, 16, /* PINTER */
+ { 0, 0, 0, 0, 0, 0, 0, 0,
+ PINT7, PINT6, PINT5, PINT4, PINT3, PINT2, PINT1, PINT0 } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7264", vectors, groups,
+ mask_registers, prio_registers, NULL);
+
+static struct plat_sci_port scif0_platform_data = {
+ .mapbase = 0xfffe8000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+ SCSCR_REIE | SCSCR_TOIE,
+ .scbrr_algo_id = SCBRR_ALGO_2,
+ .type = PORT_SCIF,
+ .irqs = { 233, 234, 235, 232 },
+ .regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif0_device = {
+ .name = "sh-sci",
+ .id = 0,
+ .dev = {
+ .platform_data = &scif0_platform_data,
+ },
+};
+
+static struct plat_sci_port scif1_platform_data = {
+ .mapbase = 0xfffe8800,
+ .flags = UPF_BOOT_AUTOCONF,
+ .scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+ SCSCR_REIE | SCSCR_TOIE,
+ .scbrr_algo_id = SCBRR_ALGO_2,
+ .type = PORT_SCIF,
+ .irqs = { 237, 238, 239, 236 },
+ .regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif1_device = {
+ .name = "sh-sci",
+ .id = 1,
+ .dev = {
+ .platform_data = &scif1_platform_data,
+ },
+};
+
+static struct plat_sci_port scif2_platform_data = {
+ .mapbase = 0xfffe9000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+ SCSCR_REIE | SCSCR_TOIE,
+ .scbrr_algo_id = SCBRR_ALGO_2,
+ .type = PORT_SCIF,
+ .irqs = { 241, 242, 243, 240 },
+ .regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif2_device = {
+ .name = "sh-sci",
+ .id = 2,
+ .dev = {
+ .platform_data = &scif2_platform_data,
+ },
+};
+
+static struct plat_sci_port scif3_platform_data = {
+ .mapbase = 0xfffe9800,
+ .flags = UPF_BOOT_AUTOCONF,
+ .scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+ SCSCR_REIE | SCSCR_TOIE,
+ .scbrr_algo_id = SCBRR_ALGO_2,
+ .type = PORT_SCIF,
+ .irqs = { 245, 246, 247, 244 },
+ .regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif3_device = {
+ .name = "sh-sci",
+ .id = 3,
+ .dev = {
+ .platform_data = &scif3_platform_data,
+ },
+};
+
+static struct plat_sci_port scif4_platform_data = {
+ .mapbase = 0xfffea000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+ SCSCR_REIE | SCSCR_TOIE,
+ .scbrr_algo_id = SCBRR_ALGO_2,
+ .type = PORT_SCIF,
+ .irqs = { 249, 250, 251, 248 },
+ .regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif4_device = {
+ .name = "sh-sci",
+ .id = 4,
+ .dev = {
+ .platform_data = &scif4_platform_data,
+ },
+};
+
+static struct plat_sci_port scif5_platform_data = {
+ .mapbase = 0xfffea800,
+ .flags = UPF_BOOT_AUTOCONF,
+ .scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+ SCSCR_REIE | SCSCR_TOIE,
+ .scbrr_algo_id = SCBRR_ALGO_2,
+ .type = PORT_SCIF,
+ .irqs = { 253, 254, 255, 252 },
+ .regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif5_device = {
+ .name = "sh-sci",
+ .id = 5,
+ .dev = {
+ .platform_data = &scif5_platform_data,
+ },
+};
+
+static struct plat_sci_port scif6_platform_data = {
+ .mapbase = 0xfffeb000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+ SCSCR_REIE | SCSCR_TOIE,
+ .scbrr_algo_id = SCBRR_ALGO_2,
+ .type = PORT_SCIF,
+ .irqs = { 257, 258, 259, 256 },
+ .regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif6_device = {
+ .name = "sh-sci",
+ .id = 6,
+ .dev = {
+ .platform_data = &scif6_platform_data,
+ },
+};
+
+static struct plat_sci_port scif7_platform_data = {
+ .mapbase = 0xfffeb800,
+ .flags = UPF_BOOT_AUTOCONF,
+ .scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+ SCSCR_REIE | SCSCR_TOIE,
+ .scbrr_algo_id = SCBRR_ALGO_2,
+ .type = PORT_SCIF,
+ .irqs = { 261, 262, 263, 260 },
+ .regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif7_device = {
+ .name = "sh-sci",
+ .id = 7,
+ .dev = {
+ .platform_data = &scif7_platform_data,
+ },
+};
+
+static struct sh_timer_config cmt0_platform_data = {
+ .channel_offset = 0x02,
+ .timer_bit = 0,
+ .clockevent_rating = 125,
+ .clocksource_rating = 0, /* disabled due to code generation issues */
+};
+
+static struct resource cmt0_resources[] = {
+ [0] = {
+ .name = "CMT0",
+ .start = 0xfffec002,
+ .end = 0xfffec007,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 175,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device cmt0_device = {
+ .name = "sh_cmt",
+ .id = 0,
+ .dev = {
+ .platform_data = &cmt0_platform_data,
+ },
+ .resource = cmt0_resources,
+ .num_resources = ARRAY_SIZE(cmt0_resources),
+};
+
+static struct sh_timer_config cmt1_platform_data = {
+ .name = "CMT1",
+ .channel_offset = 0x08,
+ .timer_bit = 1,
+ .clockevent_rating = 125,
+ .clocksource_rating = 0, /* disabled due to code generation issues */
+};
+
+static struct resource cmt1_resources[] = {
+ [0] = {
+ .name = "CMT1",
+ .start = 0xfffec008,
+ .end = 0xfffec00d,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 176,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device cmt1_device = {
+ .name = "sh_cmt",
+ .id = 1,
+ .dev = {
+ .platform_data = &cmt1_platform_data,
+ },
+ .resource = cmt1_resources,
+ .num_resources = ARRAY_SIZE(cmt1_resources),
+};
+
+static struct sh_timer_config mtu2_0_platform_data = {
+ .name = "MTU2_0",
+ .channel_offset = -0x80,
+ .timer_bit = 0,
+ .clockevent_rating = 200,
+};
+
+static struct resource mtu2_0_resources[] = {
+ [0] = {
+ .name = "MTU2_0",
+ .start = 0xfffe4300,
+ .end = 0xfffe4326,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 179,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device mtu2_0_device = {
+ .name = "sh_mtu2",
+ .id = 0,
+ .dev = {
+ .platform_data = &mtu2_0_platform_data,
+ },
+ .resource = mtu2_0_resources,
+ .num_resources = ARRAY_SIZE(mtu2_0_resources),
+};
+
+static struct sh_timer_config mtu2_1_platform_data = {
+ .name = "MTU2_1",
+ .channel_offset = -0x100,
+ .timer_bit = 1,
+ .clockevent_rating = 200,
+};
+
+static struct resource mtu2_1_resources[] = {
+ [0] = {
+ .name = "MTU2_1",
+ .start = 0xfffe4380,
+ .end = 0xfffe4390,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 186,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device mtu2_1_device = {
+ .name = "sh_mtu2",
+ .id = 1,
+ .dev = {
+ .platform_data = &mtu2_1_platform_data,
+ },
+ .resource = mtu2_1_resources,
+ .num_resources = ARRAY_SIZE(mtu2_1_resources),
+};
+
+static struct resource rtc_resources[] = {
+ [0] = {
+ .start = 0xfffe6000,
+ .end = 0xfffe6000 + 0x30 - 1,
+ .flags = IORESOURCE_IO,
+ },
+ [1] = {
+ /* Shared Period/Carry/Alarm IRQ */
+ .start = 296,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device rtc_device = {
+ .name = "sh-rtc",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(rtc_resources),
+ .resource = rtc_resources,
+};
+
+/* USB Host */
+static void usb_port_power(int port, int power)
+{
+ __raw_writew(0x200 , 0xffffc0c2) ; /* Initialise UACS25 */
+}
+
+static struct r8a66597_platdata r8a66597_data = {
+ .on_chip = 1,
+ .endian = 1,
+ .port_power = usb_port_power,
+};
+
+static struct resource r8a66597_usb_host_resources[] = {
+ [0] = {
+ .start = 0xffffc000,
+ .end = 0xffffc0e4,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 170,
+ .end = 170,
+ .flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
+ },
+};
+
+static struct platform_device r8a66597_usb_host_device = {
+ .name = "r8a66597_hcd",
+ .id = 0,
+ .dev = {
+ .dma_mask = NULL, /* not use dma */
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &r8a66597_data,
+ },
+ .num_resources = ARRAY_SIZE(r8a66597_usb_host_resources),
+ .resource = r8a66597_usb_host_resources,
+};
+
+static struct platform_device *sh7264_devices[] __initdata = {
+ &scif0_device,
+ &scif1_device,
+ &scif2_device,
+ &scif3_device,
+ &scif4_device,
+ &scif5_device,
+ &scif6_device,
+ &scif7_device,
+ &cmt0_device,
+ &cmt1_device,
+ &mtu2_0_device,
+ &mtu2_1_device,
+ &rtc_device,
+ &r8a66597_usb_host_device,
+};
+
+static int __init sh7264_devices_setup(void)
+{
+ return platform_add_devices(sh7264_devices,
+ ARRAY_SIZE(sh7264_devices));
+}
+arch_initcall(sh7264_devices_setup);
+
+void __init plat_irq_setup(void)
+{
+ register_intc_controller(&intc_desc);
+}
+
+static struct platform_device *sh7264_early_devices[] __initdata = {
+ &scif0_device,
+ &scif1_device,
+ &scif2_device,
+ &scif3_device,
+ &scif4_device,
+ &scif5_device,
+ &scif6_device,
+ &scif7_device,
+ &cmt0_device,
+ &cmt1_device,
+ &mtu2_0_device,
+ &mtu2_1_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+ early_platform_add_devices(sh7264_early_devices,
+ ARRAY_SIZE(sh7264_early_devices));
+}
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7269.c b/arch/sh/kernel/cpu/sh2a/setup-sh7269.c
new file mode 100644
index 000000000000..e82ae9d8d3bc
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7269.c
@@ -0,0 +1,615 @@
+/*
+ * SH7269 Setup
+ *
+ * Copyright (C) 2012 Renesas Electronics Europe Ltd
+ * Copyright (C) 2012 Phil Edworthy
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/serial_sci.h>
+#include <linux/usb/r8a66597.h>
+#include <linux/sh_timer.h>
+#include <linux/io.h>
+
+enum {
+ UNUSED = 0,
+
+ /* interrupt sources */
+ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+ PINT0, PINT1, PINT2, PINT3, PINT4, PINT5, PINT6, PINT7,
+
+ DMAC0, DMAC1, DMAC2, DMAC3, DMAC4, DMAC5, DMAC6, DMAC7,
+ DMAC8, DMAC9, DMAC10, DMAC11, DMAC12, DMAC13, DMAC14, DMAC15,
+ USB, VDC4, CMT0, CMT1, BSC, WDT,
+ MTU0_ABCD, MTU0_VEF, MTU1_AB, MTU1_VU, MTU2_AB, MTU2_VU,
+ MTU3_ABCD, MTU3_TCI3V, MTU4_ABCD, MTU4_TCI4V,
+ PWMT1, PWMT2, ADC_ADI,
+ SSIF0, SSII1, SSII2, SSII3, SSII4, SSII5,
+ RSPDIF,
+ IIC30, IIC31, IIC32, IIC33,
+ SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI,
+ SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI,
+ SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI,
+ SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI,
+ SCIF4_BRI, SCIF4_ERI, SCIF4_RXI, SCIF4_TXI,
+ SCIF5_BRI, SCIF5_ERI, SCIF5_RXI, SCIF5_TXI,
+ SCIF6_BRI, SCIF6_ERI, SCIF6_RXI, SCIF6_TXI,
+ SCIF7_BRI, SCIF7_ERI, SCIF7_RXI, SCIF7_TXI,
+ RCAN0, RCAN1, RCAN2,
+ RSPIC0, RSPIC1,
+ IEBC, CD_ROMD,
+ NFMC,
+ SDHI0, SDHI1,
+ RTC,
+ SRCC0, SRCC1, SRCC2,
+
+ /* interrupt groups */
+ PINT, SCIF0, SCIF1, SCIF2, SCIF3, SCIF4, SCIF5, SCIF6, SCIF7,
+};
+
+static struct intc_vect vectors[] __initdata = {
+ INTC_IRQ(IRQ0, 64), INTC_IRQ(IRQ1, 65),
+ INTC_IRQ(IRQ2, 66), INTC_IRQ(IRQ3, 67),
+ INTC_IRQ(IRQ4, 68), INTC_IRQ(IRQ5, 69),
+ INTC_IRQ(IRQ6, 70), INTC_IRQ(IRQ7, 71),
+
+ INTC_IRQ(PINT0, 80), INTC_IRQ(PINT1, 81),
+ INTC_IRQ(PINT2, 82), INTC_IRQ(PINT3, 83),
+ INTC_IRQ(PINT4, 84), INTC_IRQ(PINT5, 85),
+ INTC_IRQ(PINT6, 86), INTC_IRQ(PINT7, 87),
+
+ INTC_IRQ(DMAC0, 108), INTC_IRQ(DMAC0, 109),
+ INTC_IRQ(DMAC1, 112), INTC_IRQ(DMAC1, 113),
+ INTC_IRQ(DMAC2, 116), INTC_IRQ(DMAC2, 117),
+ INTC_IRQ(DMAC3, 120), INTC_IRQ(DMAC3, 121),
+ INTC_IRQ(DMAC4, 124), INTC_IRQ(DMAC4, 125),
+ INTC_IRQ(DMAC5, 128), INTC_IRQ(DMAC5, 129),
+ INTC_IRQ(DMAC6, 132), INTC_IRQ(DMAC6, 133),
+ INTC_IRQ(DMAC7, 136), INTC_IRQ(DMAC7, 137),
+ INTC_IRQ(DMAC8, 140), INTC_IRQ(DMAC8, 141),
+ INTC_IRQ(DMAC9, 144), INTC_IRQ(DMAC9, 145),
+ INTC_IRQ(DMAC10, 148), INTC_IRQ(DMAC10, 149),
+ INTC_IRQ(DMAC11, 152), INTC_IRQ(DMAC11, 153),
+ INTC_IRQ(DMAC12, 156), INTC_IRQ(DMAC12, 157),
+ INTC_IRQ(DMAC13, 160), INTC_IRQ(DMAC13, 161),
+ INTC_IRQ(DMAC14, 164), INTC_IRQ(DMAC14, 165),
+ INTC_IRQ(DMAC15, 168), INTC_IRQ(DMAC15, 169),
+
+ INTC_IRQ(USB, 170),
+
+ INTC_IRQ(VDC4, 171), INTC_IRQ(VDC4, 172),
+ INTC_IRQ(VDC4, 173), INTC_IRQ(VDC4, 174),
+ INTC_IRQ(VDC4, 175), INTC_IRQ(VDC4, 176),
+ INTC_IRQ(VDC4, 177), INTC_IRQ(VDC4, 177),
+
+ INTC_IRQ(CMT0, 188), INTC_IRQ(CMT1, 189),
+
+ INTC_IRQ(BSC, 190), INTC_IRQ(WDT, 191),
+
+ INTC_IRQ(MTU0_ABCD, 192), INTC_IRQ(MTU0_ABCD, 193),
+ INTC_IRQ(MTU0_ABCD, 194), INTC_IRQ(MTU0_ABCD, 195),
+ INTC_IRQ(MTU0_VEF, 196), INTC_IRQ(MTU0_VEF, 197),
+ INTC_IRQ(MTU0_VEF, 198),
+ INTC_IRQ(MTU1_AB, 199), INTC_IRQ(MTU1_AB, 200),
+ INTC_IRQ(MTU1_VU, 201), INTC_IRQ(MTU1_VU, 202),
+ INTC_IRQ(MTU2_AB, 203), INTC_IRQ(MTU2_AB, 204),
+ INTC_IRQ(MTU2_VU, 205), INTC_IRQ(MTU2_VU, 206),
+ INTC_IRQ(MTU3_ABCD, 207), INTC_IRQ(MTU3_ABCD, 208),
+ INTC_IRQ(MTU3_ABCD, 209), INTC_IRQ(MTU3_ABCD, 210),
+ INTC_IRQ(MTU3_TCI3V, 211),
+ INTC_IRQ(MTU4_ABCD, 212), INTC_IRQ(MTU4_ABCD, 213),
+ INTC_IRQ(MTU4_ABCD, 214), INTC_IRQ(MTU4_ABCD, 215),
+ INTC_IRQ(MTU4_TCI4V, 216),
+
+ INTC_IRQ(PWMT1, 217), INTC_IRQ(PWMT2, 218),
+
+ INTC_IRQ(ADC_ADI, 223),
+
+ INTC_IRQ(SSIF0, 224), INTC_IRQ(SSIF0, 225),
+ INTC_IRQ(SSIF0, 226),
+ INTC_IRQ(SSII1, 227), INTC_IRQ(SSII1, 228),
+ INTC_IRQ(SSII2, 229), INTC_IRQ(SSII2, 230),
+ INTC_IRQ(SSII3, 231), INTC_IRQ(SSII3, 232),
+ INTC_IRQ(SSII4, 233), INTC_IRQ(SSII4, 234),
+ INTC_IRQ(SSII5, 235), INTC_IRQ(SSII5, 236),
+
+ INTC_IRQ(RSPDIF, 237),
+
+ INTC_IRQ(IIC30, 238), INTC_IRQ(IIC30, 239),
+ INTC_IRQ(IIC30, 240), INTC_IRQ(IIC30, 241),
+ INTC_IRQ(IIC30, 242),
+ INTC_IRQ(IIC31, 243), INTC_IRQ(IIC31, 244),
+ INTC_IRQ(IIC31, 245), INTC_IRQ(IIC31, 246),
+ INTC_IRQ(IIC31, 247),
+ INTC_IRQ(IIC32, 248), INTC_IRQ(IIC32, 249),
+ INTC_IRQ(IIC32, 250), INTC_IRQ(IIC32, 251),
+ INTC_IRQ(IIC32, 252),
+ INTC_IRQ(IIC33, 253), INTC_IRQ(IIC33, 254),
+ INTC_IRQ(IIC33, 255), INTC_IRQ(IIC33, 256),
+ INTC_IRQ(IIC33, 257),
+
+ INTC_IRQ(SCIF0_BRI, 258), INTC_IRQ(SCIF0_ERI, 259),
+ INTC_IRQ(SCIF0_RXI, 260), INTC_IRQ(SCIF0_TXI, 261),
+ INTC_IRQ(SCIF1_BRI, 262), INTC_IRQ(SCIF1_ERI, 263),
+ INTC_IRQ(SCIF1_RXI, 264), INTC_IRQ(SCIF1_TXI, 265),
+ INTC_IRQ(SCIF2_BRI, 266), INTC_IRQ(SCIF2_ERI, 267),
+ INTC_IRQ(SCIF2_RXI, 268), INTC_IRQ(SCIF2_TXI, 269),
+ INTC_IRQ(SCIF3_BRI, 270), INTC_IRQ(SCIF3_ERI, 271),
+ INTC_IRQ(SCIF3_RXI, 272), INTC_IRQ(SCIF3_TXI, 273),
+ INTC_IRQ(SCIF4_BRI, 274), INTC_IRQ(SCIF4_ERI, 275),
+ INTC_IRQ(SCIF4_RXI, 276), INTC_IRQ(SCIF4_TXI, 277),
+ INTC_IRQ(SCIF5_BRI, 278), INTC_IRQ(SCIF5_ERI, 279),
+ INTC_IRQ(SCIF5_RXI, 280), INTC_IRQ(SCIF5_TXI, 281),
+ INTC_IRQ(SCIF6_BRI, 282), INTC_IRQ(SCIF6_ERI, 283),
+ INTC_IRQ(SCIF6_RXI, 284), INTC_IRQ(SCIF6_TXI, 285),
+ INTC_IRQ(SCIF7_BRI, 286), INTC_IRQ(SCIF7_ERI, 287),
+ INTC_IRQ(SCIF7_RXI, 288), INTC_IRQ(SCIF7_TXI, 289),
+
+ INTC_IRQ(RCAN0, 291), INTC_IRQ(RCAN0, 292),
+ INTC_IRQ(RCAN0, 293), INTC_IRQ(RCAN0, 294),
+ INTC_IRQ(RCAN0, 295),
+ INTC_IRQ(RCAN1, 296), INTC_IRQ(RCAN1, 297),
+ INTC_IRQ(RCAN1, 298), INTC_IRQ(RCAN1, 299),
+ INTC_IRQ(RCAN1, 300),
+ INTC_IRQ(RCAN2, 301), INTC_IRQ(RCAN2, 302),
+ INTC_IRQ(RCAN2, 303), INTC_IRQ(RCAN2, 304),
+ INTC_IRQ(RCAN2, 305),
+
+ INTC_IRQ(RSPIC0, 306), INTC_IRQ(RSPIC0, 307),
+ INTC_IRQ(RSPIC0, 308),
+ INTC_IRQ(RSPIC1, 309), INTC_IRQ(RSPIC1, 310),
+ INTC_IRQ(RSPIC1, 311),
+
+ INTC_IRQ(IEBC, 318),
+
+ INTC_IRQ(CD_ROMD, 319), INTC_IRQ(CD_ROMD, 320),
+ INTC_IRQ(CD_ROMD, 321), INTC_IRQ(CD_ROMD, 322),
+ INTC_IRQ(CD_ROMD, 323), INTC_IRQ(CD_ROMD, 324),
+
+ INTC_IRQ(NFMC, 325), INTC_IRQ(NFMC, 326),
+ INTC_IRQ(NFMC, 327), INTC_IRQ(NFMC, 328),
+
+ INTC_IRQ(SDHI0, 332), INTC_IRQ(SDHI0, 333),
+ INTC_IRQ(SDHI0, 334),
+ INTC_IRQ(SDHI1, 335), INTC_IRQ(SDHI1, 336),
+ INTC_IRQ(SDHI1, 337),
+
+ INTC_IRQ(RTC, 338), INTC_IRQ(RTC, 339),
+ INTC_IRQ(RTC, 340),
+
+ INTC_IRQ(SRCC0, 341), INTC_IRQ(SRCC0, 342),
+ INTC_IRQ(SRCC0, 343), INTC_IRQ(SRCC0, 344),
+ INTC_IRQ(SRCC0, 345),
+ INTC_IRQ(SRCC1, 346), INTC_IRQ(SRCC1, 347),
+ INTC_IRQ(SRCC1, 348), INTC_IRQ(SRCC1, 349),
+ INTC_IRQ(SRCC1, 350),
+ INTC_IRQ(SRCC2, 351), INTC_IRQ(SRCC2, 352),
+ INTC_IRQ(SRCC2, 353), INTC_IRQ(SRCC2, 354),
+ INTC_IRQ(SRCC2, 355),
+};
+
+static struct intc_group groups[] __initdata = {
+ INTC_GROUP(PINT, PINT0, PINT1, PINT2, PINT3,
+ PINT4, PINT5, PINT6, PINT7),
+ INTC_GROUP(SCIF0, SCIF0_BRI, SCIF0_ERI, SCIF0_RXI, SCIF0_TXI),
+ INTC_GROUP(SCIF1, SCIF1_BRI, SCIF1_ERI, SCIF1_RXI, SCIF1_TXI),
+ INTC_GROUP(SCIF2, SCIF2_BRI, SCIF2_ERI, SCIF2_RXI, SCIF2_TXI),
+ INTC_GROUP(SCIF3, SCIF3_BRI, SCIF3_ERI, SCIF3_RXI, SCIF3_TXI),
+ INTC_GROUP(SCIF4, SCIF4_BRI, SCIF4_ERI, SCIF4_RXI, SCIF4_TXI),
+ INTC_GROUP(SCIF5, SCIF5_BRI, SCIF5_ERI, SCIF5_RXI, SCIF5_TXI),
+ INTC_GROUP(SCIF6, SCIF6_BRI, SCIF6_ERI, SCIF6_RXI, SCIF6_TXI),
+ INTC_GROUP(SCIF7, SCIF7_BRI, SCIF7_ERI, SCIF7_RXI, SCIF7_TXI),
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+ { 0xfffe0818, 0, 16, 4, /* IPR01 */ { IRQ0, IRQ1, IRQ2, IRQ3 } },
+ { 0xfffe081a, 0, 16, 4, /* IPR02 */ { IRQ4, IRQ5, IRQ6, IRQ7 } },
+ { 0xfffe0820, 0, 16, 4, /* IPR05 */ { PINT, 0, 0, 0 } },
+ { 0xfffe0c00, 0, 16, 4, /* IPR06 */ { DMAC0, DMAC1, DMAC2, DMAC3 } },
+ { 0xfffe0c02, 0, 16, 4, /* IPR07 */ { DMAC4, DMAC5, DMAC6, DMAC7 } },
+ { 0xfffe0c04, 0, 16, 4, /* IPR08 */ { DMAC8, DMAC9,
+ DMAC10, DMAC11 } },
+ { 0xfffe0c06, 0, 16, 4, /* IPR09 */ { DMAC12, DMAC13,
+ DMAC14, DMAC15 } },
+ { 0xfffe0c08, 0, 16, 4, /* IPR10 */ { USB, VDC4, VDC4, VDC4 } },
+ { 0xfffe0c0a, 0, 16, 4, /* IPR11 */ { 0, 0, 0, 0 } },
+ { 0xfffe0c0c, 0, 16, 4, /* IPR12 */ { CMT0, CMT1, BSC, WDT } },
+ { 0xfffe0c0e, 0, 16, 4, /* IPR13 */ { MTU0_ABCD, MTU0_VEF,
+ MTU1_AB, MTU1_VU } },
+ { 0xfffe0c10, 0, 16, 4, /* IPR14 */ { MTU2_AB, MTU2_VU,
+ MTU3_ABCD, MTU3_TCI3V } },
+ { 0xfffe0c12, 0, 16, 4, /* IPR15 */ { MTU4_ABCD, MTU4_TCI4V,
+ PWMT1, PWMT2 } },
+ { 0xfffe0c14, 0, 16, 4, /* IPR16 */ { 0, 0, 0, 0 } },
+ { 0xfffe0c16, 0, 16, 4, /* IPR17 */ { ADC_ADI, SSIF0, SSII1, SSII2 } },
+ { 0xfffe0c18, 0, 16, 4, /* IPR18 */ { SSII3, SSII4, SSII5, RSPDIF} },
+ { 0xfffe0c1a, 0, 16, 4, /* IPR19 */ { IIC30, IIC31, IIC32, IIC33 } },
+ { 0xfffe0c1c, 0, 16, 4, /* IPR20 */ { SCIF0, SCIF1, SCIF2, SCIF3 } },
+ { 0xfffe0c1e, 0, 16, 4, /* IPR21 */ { SCIF4, SCIF5, SCIF6, SCIF7 } },
+ { 0xfffe0c20, 0, 16, 4, /* IPR22 */ { 0, RCAN0, RCAN1, RCAN2 } },
+ { 0xfffe0c22, 0, 16, 4, /* IPR23 */ { RSPIC0, RSPIC1, 0, 0 } },
+ { 0xfffe0c24, 0, 16, 4, /* IPR24 */ { IEBC, CD_ROMD, NFMC, 0 } },
+ { 0xfffe0c26, 0, 16, 4, /* IPR25 */ { SDHI0, SDHI1, RTC, 0 } },
+ { 0xfffe0c28, 0, 16, 4, /* IPR26 */ { SRCC0, SRCC1, SRCC2, 0 } },
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+ { 0xfffe0808, 0, 16, /* PINTER */
+ { 0, 0, 0, 0, 0, 0, 0, 0,
+ PINT7, PINT6, PINT5, PINT4, PINT3, PINT2, PINT1, PINT0 } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7269", vectors, groups,
+ mask_registers, prio_registers, NULL);
+
+static struct plat_sci_port scif0_platform_data = {
+ .mapbase = 0xe8007000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+ SCSCR_REIE | SCSCR_TOIE,
+ .scbrr_algo_id = SCBRR_ALGO_2,
+ .type = PORT_SCIF,
+ .irqs = { 259, 260, 261, 258 },
+ .regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif0_device = {
+ .name = "sh-sci",
+ .id = 0,
+ .dev = {
+ .platform_data = &scif0_platform_data,
+ },
+};
+
+static struct plat_sci_port scif1_platform_data = {
+ .mapbase = 0xe8007800,
+ .flags = UPF_BOOT_AUTOCONF,
+ .scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+ SCSCR_REIE | SCSCR_TOIE,
+ .scbrr_algo_id = SCBRR_ALGO_2,
+ .type = PORT_SCIF,
+ .irqs = { 263, 264, 265, 262 },
+ .regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif1_device = {
+ .name = "sh-sci",
+ .id = 1,
+ .dev = {
+ .platform_data = &scif1_platform_data,
+ },
+};
+
+static struct plat_sci_port scif2_platform_data = {
+ .mapbase = 0xe8008000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+ SCSCR_REIE | SCSCR_TOIE,
+ .scbrr_algo_id = SCBRR_ALGO_2,
+ .type = PORT_SCIF,
+ .irqs = { 267, 268, 269, 266 },
+ .regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif2_device = {
+ .name = "sh-sci",
+ .id = 2,
+ .dev = {
+ .platform_data = &scif2_platform_data,
+ },
+};
+
+static struct plat_sci_port scif3_platform_data = {
+ .mapbase = 0xe8008800,
+ .flags = UPF_BOOT_AUTOCONF,
+ .scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+ SCSCR_REIE | SCSCR_TOIE,
+ .scbrr_algo_id = SCBRR_ALGO_2,
+ .type = PORT_SCIF,
+ .irqs = { 271, 272, 273, 270 },
+ .regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif3_device = {
+ .name = "sh-sci",
+ .id = 3,
+ .dev = {
+ .platform_data = &scif3_platform_data,
+ },
+};
+
+static struct plat_sci_port scif4_platform_data = {
+ .mapbase = 0xe8009000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+ SCSCR_REIE | SCSCR_TOIE,
+ .scbrr_algo_id = SCBRR_ALGO_2,
+ .type = PORT_SCIF,
+ .irqs = { 275, 276, 277, 274 },
+ .regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif4_device = {
+ .name = "sh-sci",
+ .id = 4,
+ .dev = {
+ .platform_data = &scif4_platform_data,
+ },
+};
+
+static struct plat_sci_port scif5_platform_data = {
+ .mapbase = 0xe8009800,
+ .flags = UPF_BOOT_AUTOCONF,
+ .scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+ SCSCR_REIE | SCSCR_TOIE,
+ .scbrr_algo_id = SCBRR_ALGO_2,
+ .type = PORT_SCIF,
+ .irqs = { 279, 280, 281, 278 },
+ .regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif5_device = {
+ .name = "sh-sci",
+ .id = 5,
+ .dev = {
+ .platform_data = &scif5_platform_data,
+ },
+};
+
+static struct plat_sci_port scif6_platform_data = {
+ .mapbase = 0xe800a000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+ SCSCR_REIE | SCSCR_TOIE,
+ .scbrr_algo_id = SCBRR_ALGO_2,
+ .type = PORT_SCIF,
+ .irqs = { 283, 284, 285, 282 },
+ .regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif6_device = {
+ .name = "sh-sci",
+ .id = 6,
+ .dev = {
+ .platform_data = &scif6_platform_data,
+ },
+};
+
+static struct plat_sci_port scif7_platform_data = {
+ .mapbase = 0xe800a800,
+ .flags = UPF_BOOT_AUTOCONF,
+ .scscr = SCSCR_RIE | SCSCR_TIE | SCSCR_RE | SCSCR_TE |
+ SCSCR_REIE | SCSCR_TOIE,
+ .scbrr_algo_id = SCBRR_ALGO_2,
+ .type = PORT_SCIF,
+ .irqs = { 287, 288, 289, 286 },
+ .regtype = SCIx_SH2_SCIF_FIFODATA_REGTYPE,
+};
+
+static struct platform_device scif7_device = {
+ .name = "sh-sci",
+ .id = 7,
+ .dev = {
+ .platform_data = &scif7_platform_data,
+ },
+};
+
+static struct sh_timer_config cmt0_platform_data = {
+ .channel_offset = 0x02,
+ .timer_bit = 0,
+ .clockevent_rating = 125,
+ .clocksource_rating = 0, /* disabled due to code generation issues */
+};
+
+static struct resource cmt0_resources[] = {
+ [0] = {
+ .start = 0xfffec002,
+ .end = 0xfffec007,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 188,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device cmt0_device = {
+ .name = "sh_cmt",
+ .id = 0,
+ .dev = {
+ .platform_data = &cmt0_platform_data,
+ },
+ .resource = cmt0_resources,
+ .num_resources = ARRAY_SIZE(cmt0_resources),
+};
+
+static struct sh_timer_config cmt1_platform_data = {
+ .channel_offset = 0x08,
+ .timer_bit = 1,
+ .clockevent_rating = 125,
+ .clocksource_rating = 0, /* disabled due to code generation issues */
+};
+
+static struct resource cmt1_resources[] = {
+ [0] = {
+ .start = 0xfffec008,
+ .end = 0xfffec00d,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 189,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device cmt1_device = {
+ .name = "sh_cmt",
+ .id = 1,
+ .dev = {
+ .platform_data = &cmt1_platform_data,
+ },
+ .resource = cmt1_resources,
+ .num_resources = ARRAY_SIZE(cmt1_resources),
+};
+
+static struct sh_timer_config mtu2_0_platform_data = {
+ .channel_offset = -0x80,
+ .timer_bit = 0,
+ .clockevent_rating = 200,
+};
+
+static struct resource mtu2_0_resources[] = {
+ [0] = {
+ .start = 0xfffe4300,
+ .end = 0xfffe4326,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 192,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device mtu2_0_device = {
+ .name = "sh_mtu2",
+ .id = 0,
+ .dev = {
+ .platform_data = &mtu2_0_platform_data,
+ },
+ .resource = mtu2_0_resources,
+ .num_resources = ARRAY_SIZE(mtu2_0_resources),
+};
+
+static struct sh_timer_config mtu2_1_platform_data = {
+ .channel_offset = -0x100,
+ .timer_bit = 1,
+ .clockevent_rating = 200,
+};
+
+static struct resource mtu2_1_resources[] = {
+ [0] = {
+ .start = 0xfffe4380,
+ .end = 0xfffe4390,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 203,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device mtu2_1_device = {
+ .name = "sh_mtu2",
+ .id = 1,
+ .dev = {
+ .platform_data = &mtu2_1_platform_data,
+ },
+ .resource = mtu2_1_resources,
+ .num_resources = ARRAY_SIZE(mtu2_1_resources),
+};
+
+static struct resource rtc_resources[] = {
+ [0] = {
+ .start = 0xfffe6000,
+ .end = 0xfffe6000 + 0x30 - 1,
+ .flags = IORESOURCE_IO,
+ },
+ [1] = {
+ /* Shared Period/Carry/Alarm IRQ */
+ .start = 338,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device rtc_device = {
+ .name = "sh-rtc",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(rtc_resources),
+ .resource = rtc_resources,
+};
+
+/* USB Host */
+static struct r8a66597_platdata r8a66597_data = {
+ .on_chip = 1,
+ .endian = 1,
+};
+
+static struct resource r8a66597_usb_host_resources[] = {
+ [0] = {
+ .start = 0xe8010000,
+ .end = 0xe80100e4,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 170,
+ .end = 170,
+ .flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
+ },
+};
+
+static struct platform_device r8a66597_usb_host_device = {
+ .name = "r8a66597_hcd",
+ .id = 0,
+ .dev = {
+ .dma_mask = NULL, /* not use dma */
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &r8a66597_data,
+ },
+ .num_resources = ARRAY_SIZE(r8a66597_usb_host_resources),
+ .resource = r8a66597_usb_host_resources,
+};
+
+static struct platform_device *sh7269_devices[] __initdata = {
+ &scif0_device,
+ &scif1_device,
+ &scif2_device,
+ &scif3_device,
+ &scif4_device,
+ &scif5_device,
+ &scif6_device,
+ &scif7_device,
+ &cmt0_device,
+ &cmt1_device,
+ &mtu2_0_device,
+ &mtu2_1_device,
+ &rtc_device,
+ &r8a66597_usb_host_device,
+};
+
+static int __init sh7269_devices_setup(void)
+{
+ return platform_add_devices(sh7269_devices,
+ ARRAY_SIZE(sh7269_devices));
+}
+arch_initcall(sh7269_devices_setup);
+
+void __init plat_irq_setup(void)
+{
+ register_intc_controller(&intc_desc);
+}
+
+static struct platform_device *sh7269_early_devices[] __initdata = {
+ &scif0_device,
+ &scif1_device,
+ &scif2_device,
+ &scif3_device,
+ &scif4_device,
+ &scif5_device,
+ &scif6_device,
+ &scif7_device,
+ &cmt0_device,
+ &cmt1_device,
+ &mtu2_0_device,
+ &mtu2_1_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+ early_platform_add_devices(sh7269_early_devices,
+ ARRAY_SIZE(sh7269_early_devices));
+}
diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S
index f6a389c996cb..262db6ec067b 100644
--- a/arch/sh/kernel/cpu/sh3/entry.S
+++ b/arch/sh/kernel/cpu/sh3/entry.S
@@ -2,7 +2,7 @@
* arch/sh/kernel/cpu/sh3/entry.S
*
* Copyright (C) 1999, 2000, 2002 Niibe Yutaka
- * Copyright (C) 2003 - 2006 Paul Mundt
+ * Copyright (C) 2003 - 2012 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -17,6 +17,7 @@
#include <cpu/mmu_context.h>
#include <asm/page.h>
#include <asm/cache.h>
+#include <asm/thread_info.h>
! NOTE:
! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
@@ -114,22 +115,22 @@ ENTRY(tlb_miss_load)
.align 2
ENTRY(tlb_miss_store)
bra call_handle_tlbmiss
- mov #1, r5
+ mov #FAULT_CODE_WRITE, r5
.align 2
ENTRY(initial_page_write)
bra call_handle_tlbmiss
- mov #2, r5
+ mov #FAULT_CODE_INITIAL, r5
.align 2
ENTRY(tlb_protection_violation_load)
bra call_do_page_fault
- mov #0, r5
+ mov #FAULT_CODE_PROT, r5
.align 2
ENTRY(tlb_protection_violation_store)
bra call_do_page_fault
- mov #1, r5
+ mov #(FAULT_CODE_PROT | FAULT_CODE_WRITE), r5
call_handle_tlbmiss:
mov.l 1f, r0
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7705.c b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
index 2309618c015d..03e4c96f2b11 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7705.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
@@ -14,6 +14,7 @@
#include <linux/serial.h>
#include <linux/serial_sci.h>
#include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
#include <asm/rtc.h>
#include <cpu/serial.h>
@@ -75,7 +76,7 @@ static struct plat_sci_port scif0_platform_data = {
SCSCR_RE | SCSCR_CKE1 | SCSCR_CKE0,
.scbrr_algo_id = SCBRR_ALGO_4,
.type = PORT_SCIF,
- .irqs = { 56, 56, 56 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x900)),
.ops = &sh770x_sci_port_ops,
.regtype = SCIx_SH7705_SCIF_REGTYPE,
};
@@ -94,7 +95,7 @@ static struct plat_sci_port scif1_platform_data = {
.scscr = SCSCR_TIE | SCSCR_RIE | SCSCR_TE | SCSCR_RE,
.scbrr_algo_id = SCBRR_ALGO_4,
.type = PORT_SCIF,
- .irqs = { 52, 52, 52 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x880)),
.ops = &sh770x_sci_port_ops,
.regtype = SCIx_SH7705_SCIF_REGTYPE,
};
@@ -114,7 +115,7 @@ static struct resource rtc_resources[] = {
.flags = IORESOURCE_IO,
},
[1] = {
- .start = 20,
+ .start = evt2irq(0x480),
.flags = IORESOURCE_IRQ,
},
};
@@ -146,7 +147,7 @@ static struct resource tmu0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 16,
+ .start = evt2irq(0x400),
.flags = IORESOURCE_IRQ,
},
};
@@ -174,7 +175,7 @@ static struct resource tmu1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 17,
+ .start = evt2irq(0x420),
.flags = IORESOURCE_IRQ,
},
};
@@ -201,7 +202,7 @@ static struct resource tmu2_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 18,
+ .start = evt2irq(0x440),
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh770x.c b/arch/sh/kernel/cpu/sh3/setup-sh770x.c
index 3f3d5fe5892d..ba26cd9ce69b 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh770x.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh770x.c
@@ -19,6 +19,7 @@
#include <linux/serial.h>
#include <linux/serial_sci.h>
#include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
#include <cpu/serial.h>
enum {
@@ -95,7 +96,7 @@ static struct resource rtc_resources[] = {
.flags = IORESOURCE_IO,
},
[1] = {
- .start = 20,
+ .start = evt2irq(0x480),
.flags = IORESOURCE_IRQ,
},
};
@@ -114,7 +115,7 @@ static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_TE | SCSCR_RE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCI,
- .irqs = { 23, 23, 23, 0 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x4e0)),
.ops = &sh770x_sci_port_ops,
.regshift = 1,
};
@@ -135,7 +136,7 @@ static struct plat_sci_port scif1_platform_data = {
.scscr = SCSCR_TE | SCSCR_RE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 56, 56, 56, 56 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x900)),
.ops = &sh770x_sci_port_ops,
.regtype = SCIx_SH3_SCIF_REGTYPE,
};
@@ -157,7 +158,7 @@ static struct plat_sci_port scif2_platform_data = {
.scscr = SCSCR_TE | SCSCR_RE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_IRDA,
- .irqs = { 52, 52, 52, 52 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x880)),
.ops = &sh770x_sci_port_ops,
.regshift = 1,
};
@@ -184,7 +185,7 @@ static struct resource tmu0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 16,
+ .start = evt2irq(0x400),
.flags = IORESOURCE_IRQ,
},
};
@@ -212,7 +213,7 @@ static struct resource tmu1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 17,
+ .start = evt2irq(0x420),
.flags = IORESOURCE_IRQ,
},
};
@@ -239,7 +240,7 @@ static struct resource tmu2_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 18,
+ .start = evt2irq(0x440),
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7710.c b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
index 78f6b01d42c3..93c9c5e24a7a 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7710.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
@@ -14,6 +14,7 @@
#include <linux/serial.h>
#include <linux/serial_sci.h>
#include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
#include <asm/rtc.h>
enum {
@@ -77,7 +78,7 @@ static struct resource rtc_resources[] = {
.flags = IORESOURCE_IO,
},
[1] = {
- .start = 20,
+ .start = evt2irq(0x480),
.flags = IORESOURCE_IRQ,
},
};
@@ -103,7 +104,7 @@ static struct plat_sci_port scif0_platform_data = {
SCSCR_CKE1 | SCSCR_CKE0,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 52, 52, 52, 52 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x880)),
};
static struct platform_device scif0_device = {
@@ -121,7 +122,7 @@ static struct plat_sci_port scif1_platform_data = {
SCSCR_CKE1 | SCSCR_CKE0,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 56, 56, 56, 56 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x900)),
};
static struct platform_device scif1_device = {
@@ -145,7 +146,7 @@ static struct resource tmu0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 16,
+ .start = evt2irq(0x400),
.flags = IORESOURCE_IRQ,
},
};
@@ -173,7 +174,7 @@ static struct resource tmu1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 17,
+ .start = evt2irq(0x420),
.flags = IORESOURCE_IRQ,
},
};
@@ -200,7 +201,7 @@ static struct resource tmu2_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 18,
+ .start = evt2irq(0x440),
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7720.c b/arch/sh/kernel/cpu/sh3/setup-sh7720.c
index 94920345c14d..0c2f1b2c2e19 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7720.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7720.c
@@ -19,6 +19,7 @@
#include <linux/io.h>
#include <linux/serial_sci.h>
#include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
#include <asm/rtc.h>
#include <cpu/serial.h>
@@ -30,7 +31,7 @@ static struct resource rtc_resources[] = {
},
[1] = {
/* Shared Period/Carry/Alarm IRQ */
- .start = 20,
+ .start = evt2irq(0x480),
.flags = IORESOURCE_IRQ,
},
};
@@ -55,7 +56,7 @@ static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE,
.scbrr_algo_id = SCBRR_ALGO_4,
.type = PORT_SCIF,
- .irqs = { 80, 80, 80, 80 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xc00)),
.ops = &sh7720_sci_port_ops,
.regtype = SCIx_SH7705_SCIF_REGTYPE,
};
@@ -74,7 +75,7 @@ static struct plat_sci_port scif1_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE,
.scbrr_algo_id = SCBRR_ALGO_4,
.type = PORT_SCIF,
- .irqs = { 81, 81, 81, 81 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xc20)),
.ops = &sh7720_sci_port_ops,
.regtype = SCIx_SH7705_SCIF_REGTYPE,
};
@@ -94,13 +95,14 @@ static struct resource usb_ohci_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 67,
- .end = 67,
+ .start = evt2irq(0xa60),
+ .end = evt2irq(0xa60),
.flags = IORESOURCE_IRQ,
},
};
static u64 usb_ohci_dma_mask = 0xffffffffUL;
+
static struct platform_device usb_ohci_device = {
.name = "sh_ohci",
.id = -1,
@@ -121,8 +123,8 @@ static struct resource usbf_resources[] = {
},
[1] = {
.name = "sh_udc",
- .start = 65,
- .end = 65,
+ .start = evt2irq(0xa20),
+ .end = evt2irq(0xa20),
.flags = IORESOURCE_IRQ,
},
};
@@ -152,7 +154,7 @@ static struct resource cmt0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 104,
+ .start = evt2irq(0xf00),
.flags = IORESOURCE_IRQ,
},
};
@@ -179,7 +181,7 @@ static struct resource cmt1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 104,
+ .start = evt2irq(0xf00),
.flags = IORESOURCE_IRQ,
},
};
@@ -206,7 +208,7 @@ static struct resource cmt2_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 104,
+ .start = evt2irq(0xf00),
.flags = IORESOURCE_IRQ,
},
};
@@ -233,7 +235,7 @@ static struct resource cmt3_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 104,
+ .start = evt2irq(0xf00),
.flags = IORESOURCE_IRQ,
},
};
@@ -260,7 +262,7 @@ static struct resource cmt4_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 104,
+ .start = evt2irq(0xf00),
.flags = IORESOURCE_IRQ,
},
};
@@ -288,7 +290,7 @@ static struct resource tmu0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 16,
+ .start = evt2irq(0x400),
.flags = IORESOURCE_IRQ,
},
};
@@ -316,7 +318,7 @@ static struct resource tmu1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 17,
+ .start = evt2irq(0x420),
.flags = IORESOURCE_IRQ,
},
};
@@ -343,7 +345,7 @@ static struct resource tmu2_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 18,
+ .start = evt2irq(0x440),
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c
index 971cf0fce4f5..0fbbd50bc8ad 100644
--- a/arch/sh/kernel/cpu/sh4/probe.c
+++ b/arch/sh/kernel/cpu/sh4/probe.c
@@ -158,6 +158,9 @@ void __cpuinit cpu_probe(void)
case 0x40: /* yon-ten-go */
boot_cpu_data.type = CPU_SH7372;
break;
+ case 0xE0: /* 0x4E0 */
+ boot_cpu_data.type = CPU_SH7734; /* SH7733/SH7734 */
+ break;
}
break;
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh4-202.c b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
index 5b2833159b7d..2a5320aa73bb 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
@@ -13,6 +13,7 @@
#include <linux/serial.h>
#include <linux/serial_sci.h>
#include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
#include <linux/io.h>
static struct plat_sci_port scif0_platform_data = {
@@ -21,7 +22,10 @@ static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 40, 41, 43, 42 },
+ .irqs = { evt2irq(0x700),
+ evt2irq(0x720),
+ evt2irq(0x760),
+ evt2irq(0x740) },
};
static struct platform_device scif0_device = {
@@ -45,7 +49,7 @@ static struct resource tmu0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 16,
+ .start = evt2irq(0x400),
.flags = IORESOURCE_IRQ,
},
};
@@ -73,7 +77,7 @@ static struct resource tmu1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 17,
+ .start = evt2irq(0x420),
.flags = IORESOURCE_IRQ,
},
};
@@ -100,7 +104,7 @@ static struct resource tmu2_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 18,
+ .start = evt2irq(0x440),
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
index 98cc0c794c76..04a45512596f 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7750.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
@@ -13,6 +13,7 @@
#include <linux/serial.h>
#include <linux/io.h>
#include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
#include <linux/serial_sci.h>
#include <generated/machtypes.h>
@@ -24,7 +25,7 @@ static struct resource rtc_resources[] = {
},
[1] = {
/* Shared Period/Carry/Alarm IRQ */
- .start = 20,
+ .start = evt2irq(0x480),
.flags = IORESOURCE_IRQ,
},
};
@@ -43,7 +44,7 @@ static struct plat_sci_port sci_platform_data = {
.scscr = SCSCR_TE | SCSCR_RE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCI,
- .irqs = { 23, 23, 23, 0 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x4e0)),
.regshift = 2,
};
@@ -61,7 +62,7 @@ static struct plat_sci_port scif_platform_data = {
.scscr = SCSCR_TE | SCSCR_RE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 40, 40, 40, 40 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x700)),
};
static struct platform_device scif_device = {
@@ -85,7 +86,7 @@ static struct resource tmu0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 16,
+ .start = evt2irq(0x400),
.flags = IORESOURCE_IRQ,
},
};
@@ -113,7 +114,7 @@ static struct resource tmu1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 17,
+ .start = evt2irq(0x420),
.flags = IORESOURCE_IRQ,
},
};
@@ -140,7 +141,7 @@ static struct resource tmu2_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 18,
+ .start = evt2irq(0x440),
.flags = IORESOURCE_IRQ,
},
};
@@ -172,7 +173,7 @@ static struct resource tmu3_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 72,
+ .start = evt2irq(0xb00),
.flags = IORESOURCE_IRQ,
},
};
@@ -199,7 +200,7 @@ static struct resource tmu4_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 76,
+ .start = evt2irq(0xb80),
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7760.c b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
index c0b4c774700e..98e075ada44e 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7760.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
@@ -11,6 +11,7 @@
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
#include <linux/serial_sci.h>
#include <linux/io.h>
@@ -132,7 +133,10 @@ static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 52, 53, 55, 54 },
+ .irqs = { evt2irq(0x880),
+ evt2irq(0x8a0),
+ evt2irq(0x8e0),
+ evt2irq(0x8c0) },
.regtype = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
};
@@ -150,7 +154,10 @@ static struct plat_sci_port scif1_platform_data = {
.type = PORT_SCIF,
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
- .irqs = { 72, 73, 75, 74 },
+ .irqs = { evt2irq(0xb00),
+ evt2irq(0xb20),
+ evt2irq(0xb60),
+ evt2irq(0xb40) },
.regtype = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
};
@@ -168,7 +175,10 @@ static struct plat_sci_port scif2_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 76, 77, 79, 78 },
+ .irqs = { evt2irq(0xb80),
+ evt2irq(0xba0),
+ evt2irq(0xbe0),
+ evt2irq(0xbc0) },
.regtype = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
};
@@ -186,7 +196,9 @@ static struct plat_sci_port scif3_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCI,
- .irqs = { 80, 81, 82, 0 },
+ .irqs = { evt2irq(0xc00),
+ evt2irq(0xc20),
+ evt2irq(0xc40), },
.regshift = 2,
};
@@ -211,7 +223,7 @@ static struct resource tmu0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 16,
+ .start = evt2irq(0x400),
.flags = IORESOURCE_IRQ,
},
};
@@ -239,7 +251,7 @@ static struct resource tmu1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 17,
+ .start = evt2irq(0x420),
.flags = IORESOURCE_IRQ,
},
};
@@ -266,7 +278,7 @@ static struct resource tmu2_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 18,
+ .start = evt2irq(0x440),
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile
index 0b22d108f4c5..8fc6ec2be2fa 100644
--- a/arch/sh/kernel/cpu/sh4a/Makefile
+++ b/arch/sh/kernel/cpu/sh4a/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o
obj-$(CONFIG_CPU_SUBTYPE_SH7722) += setup-sh7722.o serial-sh7722.o
obj-$(CONFIG_CPU_SUBTYPE_SH7723) += setup-sh7723.o
obj-$(CONFIG_CPU_SUBTYPE_SH7724) += setup-sh7724.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7734) += setup-sh7734.o
obj-$(CONFIG_CPU_SUBTYPE_SH7366) += setup-sh7366.o
obj-$(CONFIG_CPU_SUBTYPE_SHX3) += setup-shx3.o intc-shx3.o
@@ -30,6 +31,7 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o
clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o
clock-$(CONFIG_CPU_SUBTYPE_SH7723) := clock-sh7723.o
clock-$(CONFIG_CPU_SUBTYPE_SH7724) := clock-sh7724.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7734) := clock-sh7734.o
clock-$(CONFIG_CPU_SUBTYPE_SH7366) := clock-sh7366.o
clock-$(CONFIG_CPU_SUBTYPE_SHX3) := clock-shx3.o
@@ -37,6 +39,7 @@ clock-$(CONFIG_CPU_SUBTYPE_SHX3) := clock-shx3.o
pinmux-$(CONFIG_CPU_SUBTYPE_SH7722) := pinmux-sh7722.o
pinmux-$(CONFIG_CPU_SUBTYPE_SH7723) := pinmux-sh7723.o
pinmux-$(CONFIG_CPU_SUBTYPE_SH7724) := pinmux-sh7724.o
+pinmux-$(CONFIG_CPU_SUBTYPE_SH7734) := pinmux-sh7734.o
pinmux-$(CONFIG_CPU_SUBTYPE_SH7757) := pinmux-sh7757.o
pinmux-$(CONFIG_CPU_SUBTYPE_SH7785) := pinmux-sh7785.o
pinmux-$(CONFIG_CPU_SUBTYPE_SH7786) := pinmux-sh7786.o
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7734.c b/arch/sh/kernel/cpu/sh4a/clock-sh7734.c
new file mode 100644
index 000000000000..1697642c1f73
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7734.c
@@ -0,0 +1,266 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/clock-sh7734.c
+ *
+ * Clock framework for SH7734
+ *
+ * Copyright (C) 2011, 2012 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
+ * Copyright (C) 2011, 2012 Renesas Solutions Corp.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/clkdev.h>
+#include <linux/delay.h>
+#include <asm/clock.h>
+#include <asm/freq.h>
+
+static struct clk extal_clk = {
+ .rate = 33333333,
+};
+
+#define MODEMR (0xFFCC0020)
+#define MODEMR_MASK (0x6)
+#define MODEMR_533MHZ (0x2)
+
+static unsigned long pll_recalc(struct clk *clk)
+{
+ int mode = 12;
+ u32 r = __raw_readl(MODEMR);
+
+ if ((r & MODEMR_MASK) & MODEMR_533MHZ)
+ mode = 16;
+
+ return clk->parent->rate * mode;
+}
+
+static struct sh_clk_ops pll_clk_ops = {
+ .recalc = pll_recalc,
+};
+
+static struct clk pll_clk = {
+ .ops = &pll_clk_ops,
+ .parent = &extal_clk,
+ .flags = CLK_ENABLE_ON_INIT,
+};
+
+static struct clk *main_clks[] = {
+ &extal_clk,
+ &pll_clk,
+};
+
+static int multipliers[] = { 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+static int divisors[] = { 1, 3, 2, 3, 4, 6, 8, 9, 12, 16, 18, 24 };
+
+static struct clk_div_mult_table div4_div_mult_table = {
+ .divisors = divisors,
+ .nr_divisors = ARRAY_SIZE(divisors),
+ .multipliers = multipliers,
+ .nr_multipliers = ARRAY_SIZE(multipliers),
+};
+
+static struct clk_div4_table div4_table = {
+ .div_mult_table = &div4_div_mult_table,
+};
+
+enum { DIV4_I, DIV4_S, DIV4_B, DIV4_M, DIV4_S1, DIV4_P, DIV4_NR };
+
+#define DIV4(_reg, _bit, _mask, _flags) \
+ SH_CLK_DIV4(&pll_clk, _reg, _bit, _mask, _flags)
+
+struct clk div4_clks[DIV4_NR] = {
+ [DIV4_I] = DIV4(FRQMR1, 28, 0x0003, CLK_ENABLE_ON_INIT),
+ [DIV4_S] = DIV4(FRQMR1, 20, 0x000C, CLK_ENABLE_ON_INIT),
+ [DIV4_B] = DIV4(FRQMR1, 16, 0x0140, CLK_ENABLE_ON_INIT),
+ [DIV4_M] = DIV4(FRQMR1, 12, 0x0004, CLK_ENABLE_ON_INIT),
+ [DIV4_S1] = DIV4(FRQMR1, 4, 0x0030, CLK_ENABLE_ON_INIT),
+ [DIV4_P] = DIV4(FRQMR1, 0, 0x0140, CLK_ENABLE_ON_INIT),
+};
+
+#define MSTPCR0 0xFFC80030
+#define MSTPCR1 0xFFC80034
+#define MSTPCR3 0xFFC8003C
+
+enum {
+ MSTP030, MSTP029, /* IIC */
+ MSTP026, MSTP025, MSTP024, /* SCIF */
+ MSTP023,
+ MSTP022, MSTP021,
+ MSTP019, /* HSCIF */
+ MSTP016, MSTP015, MSTP014, /* TMU / TIMER */
+ MSTP012, MSTP011, MSTP010, MSTP009, MSTP008, /* SSI */
+ MSTP007, /* HSPI */
+ MSTP115, /* ADMAC */
+ MSTP114, /* GETHER */
+ MSTP111, /* DMAC */
+ MSTP109, /* VIDEOIN1 */
+ MSTP108, /* VIDEOIN0 */
+ MSTP107, /* RGPVBG */
+ MSTP106, /* 2DG */
+ MSTP103, /* VIEW */
+ MSTP100, /* USB */
+ MSTP331, /* MMC */
+ MSTP330, /* MIMLB */
+ MSTP323, /* SDHI0 */
+ MSTP322, /* SDHI1 */
+ MSTP321, /* SDHI2 */
+ MSTP320, /* RQSPI */
+ MSTP319, /* SRC0 */
+ MSTP318, /* SRC1 */
+ MSTP317, /* RSPI */
+ MSTP316, /* RCAN0 */
+ MSTP315, /* RCAN1 */
+ MSTP314, /* FLTCL */
+ MSTP313, /* ADC */
+ MSTP312, /* MTU */
+ MSTP304, /* IE-BUS */
+ MSTP303, /* RTC */
+ MSTP302, /* HIF */
+ MSTP301, /* STIF0 */
+ MSTP300, /* STIF1 */
+ MSTP_NR };
+
+static struct clk mstp_clks[MSTP_NR] = {
+ /* MSTPCR0 */
+ [MSTP030] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 30, 0),
+ [MSTP029] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 29, 0),
+ [MSTP026] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 26, 0),
+ [MSTP025] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 25, 0),
+ [MSTP024] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 24, 0),
+ [MSTP023] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 23, 0),
+ [MSTP022] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 22, 0),
+ [MSTP021] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 21, 0),
+ [MSTP019] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 19, 0),
+ [MSTP016] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 16, 0),
+ [MSTP015] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 15, 0),
+ [MSTP014] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 14, 0),
+ [MSTP012] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 12, 0),
+ [MSTP011] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 11, 0),
+ [MSTP010] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 10, 0),
+ [MSTP009] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 9, 0),
+ [MSTP008] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 8, 0),
+ [MSTP007] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR0, 7, 0),
+
+ /* MSTPCR1 */
+ [MSTP115] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 15, 0),
+ [MSTP114] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 14, 0),
+ [MSTP111] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 11, 0),
+ [MSTP109] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 9, 0),
+ [MSTP108] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 8, 0),
+ [MSTP107] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 7, 0),
+ [MSTP106] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 6, 0),
+ [MSTP103] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 3, 0),
+ [MSTP100] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR1, 0, 0),
+
+ /* MSTPCR3 */
+ [MSTP331] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 31, 0),
+ [MSTP330] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 30, 0),
+ [MSTP323] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 23, 0),
+ [MSTP322] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 22, 0),
+ [MSTP321] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 21, 0),
+ [MSTP320] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 20, 0),
+ [MSTP319] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 19, 0),
+ [MSTP318] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 18, 0),
+ [MSTP317] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 17, 0),
+ [MSTP316] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 16, 0),
+ [MSTP315] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 15, 0),
+ [MSTP314] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 14, 0),
+ [MSTP313] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 13, 0),
+ [MSTP312] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 12, 0),
+ [MSTP304] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 4, 0),
+ [MSTP303] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 3, 0),
+ [MSTP302] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 2, 0),
+ [MSTP301] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 1, 0),
+ [MSTP300] = SH_CLK_MSTP32(&div4_clks[DIV4_P], MSTPCR3, 0, 0),
+};
+
+static struct clk_lookup lookups[] = {
+ /* main clocks */
+ CLKDEV_CON_ID("extal", &extal_clk),
+ CLKDEV_CON_ID("pll_clk", &pll_clk),
+
+ /* clocks */
+ CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
+ CLKDEV_CON_ID("shyway_clk", &div4_clks[DIV4_S]),
+ CLKDEV_CON_ID("ddr_clk", &div4_clks[DIV4_M]),
+ CLKDEV_CON_ID("bus_clk", &div4_clks[DIV4_B]),
+ CLKDEV_CON_ID("shyway_clk1", &div4_clks[DIV4_S1]),
+ CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
+
+ /* MSTP32 clocks */
+ CLKDEV_DEV_ID("i2c-sh7734.0", &mstp_clks[MSTP030]),
+ CLKDEV_DEV_ID("i2c-sh7734.1", &mstp_clks[MSTP029]),
+ CLKDEV_ICK_ID("sci_fck", "sh-sci.0", &mstp_clks[MSTP026]),
+ CLKDEV_ICK_ID("sci_fck", "sh-sci.1", &mstp_clks[MSTP025]),
+ CLKDEV_ICK_ID("sci_fck", "sh-sci.2", &mstp_clks[MSTP024]),
+ CLKDEV_ICK_ID("sci_fck", "sh-sci.3", &mstp_clks[MSTP023]),
+ CLKDEV_ICK_ID("sci_fck", "sh-sci.4", &mstp_clks[MSTP022]),
+ CLKDEV_ICK_ID("sci_fck", "sh-sci.5", &mstp_clks[MSTP021]),
+ CLKDEV_CON_ID("hscif", &mstp_clks[MSTP019]),
+ CLKDEV_ICK_ID("tmu_fck", "sh_tmu.0", &mstp_clks[MSTP016]),
+ CLKDEV_ICK_ID("tmu_fck", "sh_tmu.1", &mstp_clks[MSTP016]),
+ CLKDEV_ICK_ID("tmu_fck", "sh_tmu.2", &mstp_clks[MSTP016]),
+ CLKDEV_ICK_ID("tmu_fck", "sh_tmu.3", &mstp_clks[MSTP015]),
+ CLKDEV_ICK_ID("tmu_fck", "sh_tmu.4", &mstp_clks[MSTP015]),
+ CLKDEV_ICK_ID("tmu_fck", "sh_tmu.5", &mstp_clks[MSTP015]),
+ CLKDEV_ICK_ID("tmu_fck", "sh_tmu.6", &mstp_clks[MSTP014]),
+ CLKDEV_ICK_ID("tmu_fck", "sh_tmu.7", &mstp_clks[MSTP014]),
+ CLKDEV_ICK_ID("tmu_fck", "sh_tmu.8", &mstp_clks[MSTP014]),
+ CLKDEV_CON_ID("ssi0", &mstp_clks[MSTP012]),
+ CLKDEV_CON_ID("ssi1", &mstp_clks[MSTP011]),
+ CLKDEV_CON_ID("ssi2", &mstp_clks[MSTP010]),
+ CLKDEV_CON_ID("ssi3", &mstp_clks[MSTP009]),
+ CLKDEV_CON_ID("sss", &mstp_clks[MSTP008]),
+ CLKDEV_CON_ID("hspi", &mstp_clks[MSTP007]),
+ CLKDEV_CON_ID("usb_fck", &mstp_clks[MSTP100]),
+ CLKDEV_CON_ID("videoin0", &mstp_clks[MSTP109]),
+ CLKDEV_CON_ID("videoin1", &mstp_clks[MSTP108]),
+ CLKDEV_CON_ID("rgpvg", &mstp_clks[MSTP107]),
+ CLKDEV_CON_ID("2dg", &mstp_clks[MSTP106]),
+ CLKDEV_CON_ID("view", &mstp_clks[MSTP103]),
+
+ CLKDEV_CON_ID("mmc0", &mstp_clks[MSTP331]),
+ CLKDEV_CON_ID("mimlb0", &mstp_clks[MSTP330]),
+ CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP323]),
+ CLKDEV_CON_ID("sdhi1", &mstp_clks[MSTP322]),
+ CLKDEV_CON_ID("sdhi2", &mstp_clks[MSTP321]),
+ CLKDEV_CON_ID("rqspi0", &mstp_clks[MSTP320]),
+ CLKDEV_CON_ID("src0", &mstp_clks[MSTP319]),
+ CLKDEV_CON_ID("src1", &mstp_clks[MSTP318]),
+ CLKDEV_CON_ID("rsp0", &mstp_clks[MSTP317]),
+ CLKDEV_CON_ID("rcan0", &mstp_clks[MSTP316]),
+ CLKDEV_CON_ID("rcan1", &mstp_clks[MSTP315]),
+ CLKDEV_CON_ID("fltcl0", &mstp_clks[MSTP314]),
+ CLKDEV_CON_ID("adc0", &mstp_clks[MSTP313]),
+ CLKDEV_CON_ID("mtu0", &mstp_clks[MSTP312]),
+ CLKDEV_CON_ID("iebus0", &mstp_clks[MSTP304]),
+ CLKDEV_DEV_ID("sh-eth.0", &mstp_clks[MSTP114]),
+ CLKDEV_CON_ID("rtc0", &mstp_clks[MSTP303]),
+ CLKDEV_CON_ID("hif0", &mstp_clks[MSTP302]),
+ CLKDEV_CON_ID("stif0", &mstp_clks[MSTP301]),
+ CLKDEV_CON_ID("stif1", &mstp_clks[MSTP300]),
+};
+
+int __init arch_clk_init(void)
+{
+ int i, ret = 0;
+
+ for (i = 0; i < ARRAY_SIZE(main_clks); i++)
+ ret |= clk_register(main_clks[i]);
+
+ for (i = 0; i < ARRAY_SIZE(lookups); i++)
+ clkdev_add(&lookups[i]);
+
+ if (!ret)
+ ret = sh_clk_div4_register(div4_clks, ARRAY_SIZE(div4_clks),
+ &div4_table);
+
+ if (!ret)
+ ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
+
+ return ret;
+}
diff --git a/arch/sh/kernel/cpu/sh4a/pinmux-sh7734.c b/arch/sh/kernel/cpu/sh4a/pinmux-sh7734.c
new file mode 100644
index 000000000000..eed3b9d19d38
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/pinmux-sh7734.c
@@ -0,0 +1,2497 @@
+/*
+ * SH7734 processor support - PFC hardware block
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ * Copyright (C) 2012 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/ioport.h>
+#include <cpu/sh7734.h>
+
+#define CPU_32_PORT(fn, pfx, sfx) \
+ PORT_10(fn, pfx, sfx), PORT_10(fn, pfx##1, sfx), \
+ PORT_10(fn, pfx##2, sfx), PORT_1(fn, pfx##30, sfx), \
+ PORT_1(fn, pfx##31, sfx)
+
+#define CPU_32_PORT5(fn, pfx, sfx) \
+ PORT_1(fn, pfx##0, sfx), PORT_1(fn, pfx##1, sfx), \
+ PORT_1(fn, pfx##2, sfx), PORT_1(fn, pfx##3, sfx), \
+ PORT_1(fn, pfx##4, sfx), PORT_1(fn, pfx##5, sfx), \
+ PORT_1(fn, pfx##6, sfx), PORT_1(fn, pfx##7, sfx), \
+ PORT_1(fn, pfx##8, sfx), PORT_1(fn, pfx##9, sfx), \
+ PORT_1(fn, pfx##10, sfx), PORT_1(fn, pfx##11, sfx)
+
+/* GPSR0 - GPSR5 */
+#define CPU_ALL_PORT(fn, pfx, sfx) \
+ CPU_32_PORT(fn, pfx##_0_, sfx), \
+ CPU_32_PORT(fn, pfx##_1_, sfx), \
+ CPU_32_PORT(fn, pfx##_2_, sfx), \
+ CPU_32_PORT(fn, pfx##_3_, sfx), \
+ CPU_32_PORT(fn, pfx##_4_, sfx), \
+ CPU_32_PORT5(fn, pfx##_5_, sfx)
+
+#define _GP_GPIO(pfx, sfx) PINMUX_GPIO(GPIO_GP##pfx, GP##pfx##_DATA)
+#define _GP_DATA(pfx, sfx) PINMUX_DATA(GP##pfx##_DATA, GP##pfx##_FN, \
+ GP##pfx##_IN, GP##pfx##_OUT)
+
+#define _GP_INOUTSEL(pfx, sfx) GP##pfx##_IN, GP##pfx##_OUT
+#define _GP_INDT(pfx, sfx) GP##pfx##_DATA
+
+#define GP_ALL(str) CPU_ALL_PORT(_PORT_ALL, GP, str)
+#define PINMUX_GPIO_GP_ALL() CPU_ALL_PORT(_GP_GPIO, , unused)
+#define PINMUX_DATA_GP_ALL() CPU_ALL_PORT(_GP_DATA, , unused)
+
+#define PORT_10_REV(fn, pfx, sfx) \
+ PORT_1(fn, pfx##9, sfx), PORT_1(fn, pfx##8, sfx), \
+ PORT_1(fn, pfx##7, sfx), PORT_1(fn, pfx##6, sfx), \
+ PORT_1(fn, pfx##5, sfx), PORT_1(fn, pfx##4, sfx), \
+ PORT_1(fn, pfx##3, sfx), PORT_1(fn, pfx##2, sfx), \
+ PORT_1(fn, pfx##1, sfx), PORT_1(fn, pfx##0, sfx)
+
+#define CPU_32_PORT_REV(fn, pfx, sfx) \
+ PORT_1(fn, pfx##31, sfx), PORT_1(fn, pfx##30, sfx), \
+ PORT_10_REV(fn, pfx##2, sfx), PORT_10_REV(fn, pfx##1, sfx), \
+ PORT_10_REV(fn, pfx, sfx)
+
+#define GP_INOUTSEL(bank) CPU_32_PORT_REV(_GP_INOUTSEL, _##bank##_, unused)
+#define GP_INDT(bank) CPU_32_PORT_REV(_GP_INDT, _##bank##_, unused)
+
+#define PINMUX_IPSR_DATA(ipsr, fn) PINMUX_DATA(fn##_MARK, FN_##ipsr, FN_##fn)
+#define PINMUX_IPSR_MODSEL_DATA(ipsr, fn, ms) PINMUX_DATA(fn##_MARK, FN_##ms, \
+ FN_##ipsr, FN_##fn)
+
+enum {
+ PINMUX_RESERVED = 0,
+
+ PINMUX_DATA_BEGIN,
+ GP_ALL(DATA), /* GP_0_0_DATA -> GP_5_11_DATA */
+ PINMUX_DATA_END,
+
+ PINMUX_INPUT_BEGIN,
+ GP_ALL(IN), /* GP_0_0_IN -> GP_5_11_IN */
+ PINMUX_INPUT_END,
+
+ PINMUX_OUTPUT_BEGIN,
+ GP_ALL(OUT), /* GP_0_0_OUT -> GP_5_11_OUT */
+ PINMUX_OUTPUT_END,
+
+ PINMUX_FUNCTION_BEGIN,
+ GP_ALL(FN), /* GP_0_0_FN -> GP_5_11_FN */
+
+ /* GPSR0 */
+ FN_IP1_9_8, FN_IP1_11_10, FN_IP1_13_12, FN_IP1_15_14,
+ FN_IP0_7_6, FN_IP0_9_8, FN_IP0_11_10, FN_IP0_13_12,
+ FN_IP0_15_14, FN_IP0_17_16, FN_IP0_19_18, FN_IP0_21_20,
+ FN_IP0_23_22, FN_IP0_25_24, FN_IP0_27_26, FN_IP0_29_28,
+ FN_IP0_31_30, FN_IP1_1_0, FN_IP1_3_2, FN_IP1_5_4,
+ FN_IP1_7_6, FN_IP11_28, FN_IP0_1_0, FN_IP0_3_2,
+ FN_IP0_5_4, FN_IP1_17_16, FN_IP1_19_18, FN_IP1_22_20,
+ FN_IP1_25_23, FN_IP1_28_26, FN_IP1_31_29, FN_IP2_2_0,
+
+ /* GPSR1 */
+ FN_IP3_20, FN_IP3_29_27, FN_IP11_20_19, FN_IP11_22_21,
+ FN_IP2_16_14, FN_IP2_19_17, FN_IP2_22_20, FN_IP2_24_23,
+ FN_IP2_27_25, FN_IP2_30_28, FN_IP3_1_0, FN_CLKOUT,
+ FN_BS, FN_CS0, FN_IP3_2, FN_EX_CS0,
+ FN_IP3_5_3, FN_IP3_8_6, FN_IP3_11_9, FN_IP3_14_12,
+ FN_IP3_17_15, FN_RD, FN_IP3_19_18, FN_WE0,
+ FN_WE1, FN_IP2_4_3, FN_IP3_23_21, FN_IP3_26_24,
+ FN_IP2_7_5, FN_IP2_10_8, FN_IP2_13_11, FN_IP11_25_23,
+
+ /* GPSR2 */
+ FN_IP11_6_4, FN_IP11_9_7, FN_IP11_11_10, FN_IP4_2_0,
+ FN_IP8_29_28, FN_IP11_27_26, FN_IP8_22_20, FN_IP8_25_23,
+ FN_IP11_12, FN_IP8_27_26, FN_IP4_5_3, FN_IP4_8_6,
+ FN_IP4_11_9, FN_IP4_14_12, FN_IP4_17_15, FN_IP4_19_18,
+ FN_IP4_21_20, FN_IP4_23_22, FN_IP4_25_24, FN_IP4_27_26,
+ FN_IP4_29_28, FN_IP4_31_30, FN_IP5_2_0, FN_IP5_5_3,
+ FN_IP5_8_6, FN_IP5_11_9, FN_IP5_14_12, FN_IP5_17_15,
+ FN_IP5_20_18, FN_IP5_22_21, FN_IP5_24_23, FN_IP5_26_25,
+
+ /* GPSR3 */
+ FN_IP6_2_0, FN_IP6_5_3, FN_IP6_7_6, FN_IP6_9_8,
+ FN_IP6_11_10, FN_IP6_13_12, FN_IP6_15_14, FN_IP6_17_16,
+ FN_IP6_20_18, FN_IP6_23_21, FN_IP7_2_0, FN_IP7_5_3,
+ FN_IP7_8_6, FN_IP7_11_9, FN_IP7_14_12, FN_IP7_17_15,
+ FN_IP7_20_18, FN_IP7_23_21, FN_IP7_26_24, FN_IP7_28_27,
+ FN_IP7_30_29, FN_IP8_1_0, FN_IP8_3_2, FN_IP8_5_4,
+ FN_IP8_7_6, FN_IP8_9_8, FN_IP8_11_10, FN_IP8_13_12,
+ FN_IP8_15_14, FN_IP8_17_16, FN_IP8_19_18, FN_IP9_1_0,
+
+ /* GPSR4 */
+ FN_IP9_19_18, FN_IP9_21_20, FN_IP9_23_22, FN_IP9_25_24,
+ FN_IP9_11_10, FN_IP9_13_12, FN_IP9_15_14, FN_IP9_17_16,
+ FN_IP9_3_2, FN_IP9_5_4, FN_IP9_7_6, FN_IP9_9_8,
+ FN_IP9_27_26, FN_IP9_29_28, FN_IP10_2_0, FN_IP10_5_3,
+ FN_IP10_8_6, FN_IP10_11_9, FN_IP10_14_12, FN_IP10_15,
+ FN_IP10_18_16, FN_IP10_21_19, FN_IP11_0, FN_IP11_1,
+ FN_SCL0, FN_IP11_2, FN_PENC0, FN_IP11_15_13, /* Need check*/
+ FN_USB_OVC0, FN_IP11_18_16,
+ FN_IP10_22, FN_IP10_24_23,
+
+ /* GPSR5 */
+ FN_IP10_25, FN_IP11_3, FN_IRQ2_B, FN_IRQ3_B,
+ FN_IP10_27_26, /* 10 */
+ FN_IP10_29_28, /* 11 */
+
+ /* IPSR0 */
+ FN_A15, FN_ST0_VCO_CLKIN, FN_LCD_DATA15_A, FN_TIOC3D_C,
+ FN_A14, FN_LCD_DATA14_A, FN_TIOC3C_C,
+ FN_A13, FN_LCD_DATA13_A, FN_TIOC3B_C,
+ FN_A12, FN_LCD_DATA12_A, FN_TIOC3A_C,
+ FN_A11, FN_ST0_D7, FN_LCD_DATA11_A, FN_TIOC2B_C,
+ FN_A10, FN_ST0_D6, FN_LCD_DATA10_A, FN_TIOC2A_C,
+ FN_A9, FN_ST0_D5, FN_LCD_DATA9_A, FN_TIOC1B_C,
+ FN_A8, FN_ST0_D4, FN_LCD_DATA8_A, FN_TIOC1A_C,
+ FN_A7, FN_ST0_D3, FN_LCD_DATA7_A, FN_TIOC0D_C,
+ FN_A6, FN_ST0_D2, FN_LCD_DATA6_A, FN_TIOC0C_C,
+ FN_A5, FN_ST0_D1, FN_LCD_DATA5_A, FN_TIOC0B_C,
+ FN_A4, FN_ST0_D0, FN_LCD_DATA4_A, FN_TIOC0A_C,
+ FN_A3, FN_ST0_VLD, FN_LCD_DATA3_A, FN_TCLKD_C,
+ FN_A2, FN_ST0_SYC, FN_LCD_DATA2_A, FN_TCLKC_C,
+ FN_A1, FN_ST0_REQ, FN_LCD_DATA1_A, FN_TCLKB_C,
+ FN_A0, FN_ST0_CLKIN, FN_LCD_DATA0_A, FN_TCLKA_C,
+
+ /* IPSR1 */
+ FN_D3, FN_SD0_DAT3_A, FN_MMC_D3_A, FN_ST1_D6, FN_FD3_A,
+ FN_D2, FN_SD0_DAT2_A, FN_MMC_D2_A, FN_ST1_D5, FN_FD2_A,
+ FN_D1, FN_SD0_DAT1_A, FN_MMC_D1_A, FN_ST1_D4, FN_FD1_A,
+ FN_D0, FN_SD0_DAT0_A, FN_MMC_D0_A, FN_ST1_D3, FN_FD0_A,
+ FN_A25, FN_TX2_D, FN_ST1_D2,
+ FN_A24, FN_RX2_D, FN_ST1_D1,
+ FN_A23, FN_ST1_D0, FN_LCD_M_DISP_A,
+ FN_A22, FN_ST1_VLD, FN_LCD_VEPWC_A,
+ FN_A21, FN_ST1_SYC, FN_LCD_VCPWC_A,
+ FN_A20, FN_ST1_REQ, FN_LCD_FLM_A,
+ FN_A19, FN_ST1_CLKIN, FN_LCD_CLK_A, FN_TIOC4D_C,
+ FN_A18, FN_ST1_PWM, FN_LCD_CL2_A, FN_TIOC4C_C,
+ FN_A17, FN_ST1_VCO_CLKIN, FN_LCD_CL1_A, FN_TIOC4B_C,
+ FN_A16, FN_ST0_PWM, FN_LCD_DON_A, FN_TIOC4A_C,
+
+ /* IPSR2 */
+ FN_D14, FN_TX2_B, FN_FSE_A, FN_ET0_TX_CLK_B,
+ FN_D13, FN_RX2_B, FN_FRB_A, FN_ET0_ETXD6_B,
+ FN_D12, FN_FWE_A, FN_ET0_ETXD5_B,
+ FN_D11, FN_RSPI_MISO_A, FN_QMI_QIO1_A, FN_FRE_A,
+ FN_ET0_ETXD3_B,
+ FN_D10, FN_RSPI_MOSI_A, FN_QMO_QIO0_A, FN_FALE_A,
+ FN_ET0_ETXD2_B,
+ FN_D9, FN_SD0_CMD_A, FN_MMC_CMD_A, FN_QIO3_A, FN_FCLE_A,
+ FN_ET0_ETXD1_B,
+ FN_D8, FN_SD0_CLK_A, FN_MMC_CLK_A, FN_QIO2_A, FN_FCE_A,
+ FN_ET0_GTX_CLK_B,
+ FN_D7, FN_RSPI_SSL_A, FN_MMC_D7_A, FN_QSSL_A, FN_FD7_A,
+ FN_D6, FN_RSPI_RSPCK_A, FN_MMC_D6_A, FN_QSPCLK_A, FN_FD6_A,
+ FN_D5, FN_SD0_WP_A, FN_MMC_D5_A, FN_FD5_A,
+ FN_D4, FN_SD0_CD_A, FN_MMC_D4_A, FN_ST1_D7, FN_FD4_A,
+
+ /* IPSR3 */
+ FN_DRACK0, FN_SD1_DAT2_A, FN_ATAG, FN_TCLK1_A, FN_ET0_ETXD7,
+ FN_EX_WAIT2, FN_SD1_DAT1_A, FN_DACK2, FN_CAN1_RX_C,
+ FN_ET0_MAGIC_C, FN_ET0_ETXD6_A,
+ FN_EX_WAIT1, FN_SD1_DAT0_A, FN_DREQ2, FN_CAN1_TX_C,
+ FN_ET0_LINK_C, FN_ET0_ETXD5_A,
+ FN_EX_WAIT0, FN_TCLK1_B,
+ FN_RD_WR, FN_TCLK0, FN_CAN_CLK_B, FN_ET0_ETXD4,
+ FN_EX_CS5, FN_SD1_CMD_A, FN_ATADIR, FN_QSSL_B, FN_ET0_ETXD3_A,
+ FN_EX_CS4, FN_SD1_WP_A, FN_ATAWR, FN_QMI_QIO1_B, FN_ET0_ETXD2_A,
+ FN_EX_CS3, FN_SD1_CD_A, FN_ATARD, FN_QMO_QIO0_B, FN_ET0_ETXD1_A,
+ FN_EX_CS2, FN_TX3_B, FN_ATACS1, FN_QSPCLK_B, FN_ET0_GTX_CLK_A,
+ FN_EX_CS1, FN_RX3_B, FN_ATACS0, FN_QIO2_B, FN_ET0_ETXD0,
+ FN_CS1_A26, FN_QIO3_B,
+ FN_D15, FN_SCK2_B,
+
+ /* IPSR4 */
+ FN_SCK2_A, FN_VI0_G3,
+ FN_RTS1_B, FN_VI0_G2,
+ FN_CTS1_B, FN_VI0_DATA7_VI0_G1,
+ FN_TX1_B, FN_VI0_DATA6_VI0_G0, FN_ET0_PHY_INT_A,
+ FN_RX1_B, FN_VI0_DATA5_VI0_B5, FN_ET0_MAGIC_A,
+ FN_SCK1_B, FN_VI0_DATA4_VI0_B4, FN_ET0_LINK_A,
+ FN_RTS0_B, FN_VI0_DATA3_VI0_B3, FN_ET0_MDIO_A,
+ FN_CTS0_B, FN_VI0_DATA2_VI0_B2, FN_RMII0_MDIO_A, FN_ET0_MDC,
+ FN_HTX0_A, FN_TX1_A, FN_VI0_DATA1_VI0_B1, FN_RMII0_MDC_A, FN_ET0_COL,
+ FN_HRX0_A, FN_RX1_A, FN_VI0_DATA0_VI0_B0, FN_RMII0_CRS_DV_A, FN_ET0_CRS,
+ FN_HSCK0_A, FN_SCK1_A, FN_VI0_VSYNC, FN_RMII0_RX_ER_A, FN_ET0_RX_ER,
+ FN_HRTS0_A, FN_RTS1_A, FN_VI0_HSYNC, FN_RMII0_TXD_EN_A, FN_ET0_RX_DV,
+ FN_HCTS0_A, FN_CTS1_A, FN_VI0_FIELD, FN_RMII0_RXD1_A, FN_ET0_ERXD7,
+
+ /* IPSR5 */
+ FN_SD2_CLK_A, FN_RX2_A, FN_VI0_G4, FN_ET0_RX_CLK_B,
+ FN_SD2_CMD_A, FN_TX2_A, FN_VI0_G5, FN_ET0_ERXD2_B,
+ FN_SD2_DAT0_A, FN_RX3_A, FN_VI0_R0, FN_ET0_ERXD3_B,
+ FN_SD2_DAT1_A, FN_TX3_A, FN_VI0_R1, FN_ET0_MDIO_B,
+ FN_SD2_DAT2_A, FN_RX4_A, FN_VI0_R2, FN_ET0_LINK_B,
+ FN_SD2_DAT3_A, FN_TX4_A, FN_VI0_R3, FN_ET0_MAGIC_B,
+ FN_SD2_CD_A, FN_RX5_A, FN_VI0_R4, FN_ET0_PHY_INT_B,
+ FN_SD2_WP_A, FN_TX5_A, FN_VI0_R5,
+ FN_REF125CK, FN_ADTRG, FN_RX5_C,
+ FN_REF50CK, FN_CTS1_E, FN_HCTS0_D,
+
+ /* IPSR6 */
+ FN_DU0_DR0, FN_SCIF_CLK_B, FN_HRX0_D, FN_IETX_A, FN_TCLKA_A, FN_HIFD00,
+ FN_DU0_DR1, FN_SCK0_B, FN_HTX0_D, FN_IERX_A, FN_TCLKB_A, FN_HIFD01,
+ FN_DU0_DR2, FN_RX0_B, FN_TCLKC_A, FN_HIFD02,
+ FN_DU0_DR3, FN_TX0_B, FN_TCLKD_A, FN_HIFD03,
+ FN_DU0_DR4, FN_CTS0_C, FN_TIOC0A_A, FN_HIFD04,
+ FN_DU0_DR5, FN_RTS0_C, FN_TIOC0B_A, FN_HIFD05,
+ FN_DU0_DR6, FN_SCK1_C, FN_TIOC0C_A, FN_HIFD06,
+ FN_DU0_DR7, FN_RX1_C, FN_TIOC0D_A, FN_HIFD07,
+ FN_DU0_DG0, FN_TX1_C, FN_HSCK0_D, FN_IECLK_A, FN_TIOC1A_A, FN_HIFD08,
+ FN_DU0_DG1, FN_CTS1_C, FN_HRTS0_D, FN_TIOC1B_A, FN_HIFD09,
+
+ /* IPSR7 */
+ FN_DU0_DG2, FN_RTS1_C, FN_RMII0_MDC_B, FN_TIOC2A_A, FN_HIFD10,
+ FN_DU0_DG3, FN_SCK2_C, FN_RMII0_MDIO_B, FN_TIOC2B_A, FN_HIFD11,
+ FN_DU0_DG4, FN_RX2_C, FN_RMII0_CRS_DV_B, FN_TIOC3A_A, FN_HIFD12,
+ FN_DU0_DG5, FN_TX2_C, FN_RMII0_RX_ER_B, FN_TIOC3B_A, FN_HIFD13,
+ FN_DU0_DG6, FN_RX3_C, FN_RMII0_RXD0_B, FN_TIOC3C_A, FN_HIFD14,
+ FN_DU0_DG7, FN_TX3_C, FN_RMII0_RXD1_B, FN_TIOC3D_A, FN_HIFD15,
+ FN_DU0_DB0, FN_RX4_C, FN_RMII0_TXD_EN_B, FN_TIOC4A_A, FN_HIFCS,
+ FN_DU0_DB1, FN_TX4_C, FN_RMII0_TXD0_B, FN_TIOC4B_A, FN_HIFRS,
+ FN_DU0_DB2, FN_RX5_B, FN_RMII0_TXD1_B, FN_TIOC4C_A, FN_HIFWR,
+ FN_DU0_DB3, FN_TX5_B, FN_TIOC4D_A, FN_HIFRD,
+ FN_DU0_DB4, FN_HIFINT,
+
+ /* IPSR8 */
+ FN_DU0_DB5, FN_HIFDREQ,
+ FN_DU0_DB6, FN_HIFRDY,
+ FN_DU0_DB7, FN_SSI_SCK0_B, FN_HIFEBL_B,
+ FN_DU0_DOTCLKIN, FN_HSPI_CS0_C, FN_SSI_WS0_B,
+ FN_DU0_DOTCLKOUT, FN_HSPI_CLK0_C, FN_SSI_SDATA0_B,
+ FN_DU0_EXHSYNC_DU0_HSYNC, FN_HSPI_TX0_C, FN_SSI_SCK1_B,
+ FN_DU0_EXVSYNC_DU0_VSYNC, FN_HSPI_RX0_C, FN_SSI_WS1_B,
+ FN_DU0_EXODDF_DU0_ODDF, FN_CAN0_RX_B, FN_HSCK0_B, FN_SSI_SDATA1_B,
+ FN_DU0_DISP, FN_CAN0_TX_B, FN_HRX0_B, FN_AUDIO_CLKA_B,
+ FN_DU0_CDE, FN_HTX0_B, FN_AUDIO_CLKB_B, FN_LCD_VCPWC_B,
+ FN_IRQ0_A, FN_HSPI_TX_B, FN_RX3_E, FN_ET0_ERXD0,
+ FN_IRQ1_A, FN_HSPI_RX_B, FN_TX3_E, FN_ET0_ERXD1,
+ FN_IRQ2_A, FN_CTS0_A, FN_HCTS0_B, FN_ET0_ERXD2_A,
+ FN_IRQ3_A, FN_RTS0_A, FN_HRTS0_B, FN_ET0_ERXD3_A,
+
+ /* IPSR9 */
+ FN_VI1_CLK_A, FN_FD0_B, FN_LCD_DATA0_B,
+ FN_VI1_0_A, FN_FD1_B, FN_LCD_DATA1_B,
+ FN_VI1_1_A, FN_FD2_B, FN_LCD_DATA2_B,
+ FN_VI1_2_A, FN_FD3_B, FN_LCD_DATA3_B,
+ FN_VI1_3_A, FN_FD4_B, FN_LCD_DATA4_B,
+ FN_VI1_4_A, FN_FD5_B, FN_LCD_DATA5_B,
+ FN_VI1_5_A, FN_FD6_B, FN_LCD_DATA6_B,
+ FN_VI1_6_A, FN_FD7_B, FN_LCD_DATA7_B,
+ FN_VI1_7_A, FN_FCE_B, FN_LCD_DATA8_B,
+ FN_SSI_SCK0_A, FN_TIOC1A_B, FN_LCD_DATA9_B,
+ FN_SSI_WS0_A, FN_TIOC1B_B, FN_LCD_DATA10_B,
+ FN_SSI_SDATA0_A, FN_VI1_0_B, FN_TIOC2A_B, FN_LCD_DATA11_B,
+ FN_SSI_SCK1_A, FN_VI1_1_B, FN_TIOC2B_B, FN_LCD_DATA12_B,
+ FN_SSI_WS1_A, FN_VI1_2_B, FN_LCD_DATA13_B,
+ FN_SSI_SDATA1_A, FN_VI1_3_B, FN_LCD_DATA14_B,
+
+ /* IPSR10 */
+ FN_SSI_SCK23, FN_VI1_4_B, FN_RX1_D, FN_FCLE_B, FN_LCD_DATA15_B,
+ FN_SSI_WS23, FN_VI1_5_B, FN_TX1_D, FN_HSCK0_C, FN_FALE_B, FN_LCD_DON_B,
+ FN_SSI_SDATA2, FN_VI1_6_B, FN_HRX0_C, FN_FRE_B, FN_LCD_CL1_B,
+ FN_SSI_SDATA3, FN_VI1_7_B, FN_HTX0_C, FN_FWE_B, FN_LCD_CL2_B,
+ FN_AUDIO_CLKA_A, FN_VI1_CLK_B, FN_SCK1_D, FN_IECLK_B, FN_LCD_FLM_B,
+ FN_AUDIO_CLKB_A, FN_LCD_CLK_B,
+ FN_AUDIO_CLKC, FN_SCK1_E, FN_HCTS0_C, FN_FRB_B, FN_LCD_VEPWC_B,
+ FN_AUDIO_CLKOUT, FN_TX1_E, FN_HRTS0_C, FN_FSE_B, FN_LCD_M_DISP_B,
+ FN_CAN_CLK_A, FN_RX4_D,
+ FN_CAN0_TX_A, FN_TX4_D, FN_MLB_CLK,
+ FN_CAN1_RX_A, FN_IRQ1_B,
+ FN_CAN0_RX_A, FN_IRQ0_B, FN_MLB_SIG,
+ FN_CAN1_TX_A, FN_TX5_C, FN_MLB_DAT,
+
+ /* IPSR11 */
+ FN_SCL1, FN_SCIF_CLK_C,
+ FN_SDA1, FN_RX1_E,
+ FN_SDA0, FN_HIFEBL_A,
+ FN_SDSELF, FN_RTS1_E,
+ FN_SCIF_CLK_A, FN_HSPI_CLK_A, FN_VI0_CLK, FN_RMII0_TXD0_A, FN_ET0_ERXD4,
+ FN_SCK0_A, FN_HSPI_CS_A, FN_VI0_CLKENB, FN_RMII0_TXD1_A, FN_ET0_ERXD5,
+ FN_RX0_A, FN_HSPI_RX_A, FN_RMII0_RXD0_A, FN_ET0_ERXD6,
+ FN_TX0_A, FN_HSPI_TX_A,
+ FN_PENC1, FN_TX3_D, FN_CAN1_TX_B, FN_TX5_D, FN_IETX_B,
+ FN_USB_OVC1, FN_RX3_D, FN_CAN1_RX_B, FN_RX5_D, FN_IERX_B,
+ FN_DREQ0, FN_SD1_CLK_A, FN_ET0_TX_EN,
+ FN_DACK0, FN_SD1_DAT3_A, FN_ET0_TX_ER,
+ FN_DREQ1, FN_HSPI_CLK_B, FN_RX4_B, FN_ET0_PHY_INT_C, FN_ET0_TX_CLK_A,
+ FN_DACK1, FN_HSPI_CS_B, FN_TX4_B, FN_ET0_RX_CLK_A,
+ FN_PRESETOUT, FN_ST_CLKOUT,
+
+ /* MOD_SEL1 */
+ FN_SEL_IEBUS_0, FN_SEL_IEBUS_1,
+ FN_SEL_RQSPI_0, FN_SEL_RQSPI_1,
+ FN_SEL_VIN1_0, FN_SEL_VIN1_1,
+ FN_SEL_HIF_0, FN_SEL_HIF_1,
+ FN_SEL_RSPI_0, FN_SEL_RSPI_1,
+ FN_SEL_LCDC_0, FN_SEL_LCDC_1,
+ FN_SEL_ET0_CTL_0, FN_SEL_ET0_CTL_1, FN_SEL_ET0_CTL_2,
+ FN_SEL_ET0_0, FN_SEL_ET0_1,
+ FN_SEL_RMII_0, FN_SEL_RMII_1,
+ FN_SEL_TMU_0, FN_SEL_TMU_1,
+ FN_SEL_HSPI_0, FN_SEL_HSPI_1, FN_SEL_HSPI_2,
+ FN_SEL_HSCIF_0, FN_SEL_HSCIF_1, FN_SEL_HSCIF_2, FN_SEL_HSCIF_3,
+ FN_SEL_RCAN_CLK_0, FN_SEL_RCAN_CLK_1,
+ FN_SEL_RCAN1_0, FN_SEL_RCAN1_1, FN_SEL_RCAN1_2,
+ FN_SEL_RCAN0_0, FN_SEL_RCAN0_1,
+ FN_SEL_SDHI2_0, FN_SEL_SDHI2_1,
+ FN_SEL_SDHI1_0, FN_SEL_SDHI1_1,
+ FN_SEL_SDHI0_0, FN_SEL_SDHI0_1,
+ FN_SEL_SSI1_0, FN_SEL_SSI1_1,
+ FN_SEL_SSI0_0, FN_SEL_SSI0_1,
+ FN_SEL_AUDIO_CLKB_0, FN_SEL_AUDIO_CLKB_1,
+ FN_SEL_AUDIO_CLKA_0, FN_SEL_AUDIO_CLKA_1,
+ FN_SEL_FLCTL_0, FN_SEL_FLCTL_1,
+ FN_SEL_MMC_0, FN_SEL_MMC_1,
+ FN_SEL_INTC_0, FN_SEL_INTC_1,
+
+ /* MOD_SEL2 */
+ FN_SEL_MTU2_CLK_0, FN_SEL_MTU2_CLK_1,
+ FN_SEL_MTU2_CH4_0, FN_SEL_MTU2_CH4_1,
+ FN_SEL_MTU2_CH3_0, FN_SEL_MTU2_CH3_1,
+ FN_SEL_MTU2_CH2_0, FN_SEL_MTU2_CH2_1, FN_SEL_MTU2_CH2_2,
+ FN_SEL_MTU2_CH1_0, FN_SEL_MTU2_CH1_1, FN_SEL_MTU2_CH1_2,
+ FN_SEL_MTU2_CH0_0, FN_SEL_MTU2_CH0_1,
+ FN_SEL_SCIF5_0, FN_SEL_SCIF5_1,
+ FN_SEL_SCIF5_2, FN_SEL_SCIF5_3,
+ FN_SEL_SCIF4_0, FN_SEL_SCIF4_1,
+ FN_SEL_SCIF4_2, FN_SEL_SCIF4_3,
+ FN_SEL_SCIF3_0, FN_SEL_SCIF3_1, FN_SEL_SCIF3_2,
+ FN_SEL_SCIF3_3, FN_SEL_SCIF3_4,
+ FN_SEL_SCIF2_0, FN_SEL_SCIF2_1, FN_SEL_SCIF2_2,
+ FN_SEL_SCIF2_3,
+ FN_SEL_SCIF1_0, FN_SEL_SCIF1_1, FN_SEL_SCIF1_2,
+ FN_SEL_SCIF1_3, FN_SEL_SCIF1_4,
+ FN_SEL_SCIF0_0, FN_SEL_SCIF0_1, FN_SEL_SCIF0_2,
+ FN_SEL_SCIF_CLK_0, FN_SEL_SCIF_CLK_1, FN_SEL_SCIF_CLK_2,
+
+ PINMUX_FUNCTION_END,
+
+ PINMUX_MARK_BEGIN,
+
+ CLKOUT_MARK, BS_MARK, CS0_MARK, EX_CS0_MARK, RD_MARK,
+ WE0_MARK, WE1_MARK,
+
+ SCL0_MARK, PENC0_MARK, USB_OVC0_MARK,
+
+ IRQ2_B_MARK, IRQ3_B_MARK,
+
+ /* IPSR0 */
+ A15_MARK, ST0_VCO_CLKIN_MARK, LCD_DATA15_A_MARK, TIOC3D_C_MARK,
+ A14_MARK, LCD_DATA14_A_MARK, TIOC3C_C_MARK,
+ A13_MARK, LCD_DATA13_A_MARK, TIOC3B_C_MARK,
+ A12_MARK, LCD_DATA12_A_MARK, TIOC3A_C_MARK,
+ A11_MARK, ST0_D7_MARK, LCD_DATA11_A_MARK, TIOC2B_C_MARK,
+ A10_MARK, ST0_D6_MARK, LCD_DATA10_A_MARK, TIOC2A_C_MARK,
+ A9_MARK, ST0_D5_MARK, LCD_DATA9_A_MARK, TIOC1B_C_MARK,
+ A8_MARK, ST0_D4_MARK, LCD_DATA8_A_MARK, TIOC1A_C_MARK,
+ A7_MARK, ST0_D3_MARK, LCD_DATA7_A_MARK, TIOC0D_C_MARK,
+ A6_MARK, ST0_D2_MARK, LCD_DATA6_A_MARK, TIOC0C_C_MARK,
+ A5_MARK, ST0_D1_MARK, LCD_DATA5_A_MARK, TIOC0B_C_MARK,
+ A4_MARK, ST0_D0_MARK, LCD_DATA4_A_MARK, TIOC0A_C_MARK,
+ A3_MARK, ST0_VLD_MARK, LCD_DATA3_A_MARK, TCLKD_C_MARK,
+ A2_MARK, ST0_SYC_MARK, LCD_DATA2_A_MARK, TCLKC_C_MARK,
+ A1_MARK, ST0_REQ_MARK, LCD_DATA1_A_MARK, TCLKB_C_MARK,
+ A0_MARK, ST0_CLKIN_MARK, LCD_DATA0_A_MARK, TCLKA_C_MARK,
+
+ /* IPSR1 */
+ D3_MARK, SD0_DAT3_A_MARK, MMC_D3_A_MARK, ST1_D6_MARK, FD3_A_MARK,
+ D2_MARK, SD0_DAT2_A_MARK, MMC_D2_A_MARK, ST1_D5_MARK, FD2_A_MARK,
+ D1_MARK, SD0_DAT1_A_MARK, MMC_D1_A_MARK, ST1_D4_MARK, FD1_A_MARK,
+ D0_MARK, SD0_DAT0_A_MARK, MMC_D0_A_MARK, ST1_D3_MARK, FD0_A_MARK,
+ A25_MARK, TX2_D_MARK, ST1_D2_MARK,
+ A24_MARK, RX2_D_MARK, ST1_D1_MARK,
+ A23_MARK, ST1_D0_MARK, LCD_M_DISP_A_MARK,
+ A22_MARK, ST1_VLD_MARK, LCD_VEPWC_A_MARK,
+ A21_MARK, ST1_SYC_MARK, LCD_VCPWC_A_MARK,
+ A20_MARK, ST1_REQ_MARK, LCD_FLM_A_MARK,
+ A19_MARK, ST1_CLKIN_MARK, LCD_CLK_A_MARK, TIOC4D_C_MARK,
+ A18_MARK, ST1_PWM_MARK, LCD_CL2_A_MARK, TIOC4C_C_MARK,
+ A17_MARK, ST1_VCO_CLKIN_MARK, LCD_CL1_A_MARK, TIOC4B_C_MARK,
+ A16_MARK, ST0_PWM_MARK, LCD_DON_A_MARK, TIOC4A_C_MARK,
+
+ /* IPSR2 */
+ D14_MARK, TX2_B_MARK, FSE_A_MARK, ET0_TX_CLK_B_MARK,
+ D13_MARK, RX2_B_MARK, FRB_A_MARK, ET0_ETXD6_B_MARK,
+ D12_MARK, FWE_A_MARK, ET0_ETXD5_B_MARK,
+ D11_MARK, RSPI_MISO_A_MARK, QMI_QIO1_A_MARK, FRE_A_MARK,
+ ET0_ETXD3_B_MARK,
+ D10_MARK, RSPI_MOSI_A_MARK, QMO_QIO0_A_MARK, FALE_A_MARK,
+ ET0_ETXD2_B_MARK,
+ D9_MARK, SD0_CMD_A_MARK, MMC_CMD_A_MARK, QIO3_A_MARK,
+ FCLE_A_MARK, ET0_ETXD1_B_MARK,
+ D8_MARK, SD0_CLK_A_MARK, MMC_CLK_A_MARK, QIO2_A_MARK,
+ FCE_A_MARK, ET0_GTX_CLK_B_MARK,
+ D7_MARK, RSPI_SSL_A_MARK, MMC_D7_A_MARK, QSSL_A_MARK,
+ FD7_A_MARK,
+ D6_MARK, RSPI_RSPCK_A_MARK, MMC_D6_A_MARK, QSPCLK_A_MARK,
+ FD6_A_MARK,
+ D5_MARK, SD0_WP_A_MARK, MMC_D5_A_MARK, FD5_A_MARK,
+ D4_MARK, SD0_CD_A_MARK, MMC_D4_A_MARK, ST1_D7_MARK,
+ FD4_A_MARK,
+
+ /* IPSR3 */
+ DRACK0_MARK, SD1_DAT2_A_MARK, ATAG_MARK, TCLK1_A_MARK, ET0_ETXD7_MARK,
+ EX_WAIT2_MARK, SD1_DAT1_A_MARK, DACK2_MARK, CAN1_RX_C_MARK,
+ ET0_MAGIC_C_MARK, ET0_ETXD6_A_MARK,
+ EX_WAIT1_MARK, SD1_DAT0_A_MARK, DREQ2_MARK, CAN1_TX_C_MARK,
+ ET0_LINK_C_MARK, ET0_ETXD5_A_MARK,
+ EX_WAIT0_MARK, TCLK1_B_MARK,
+ RD_WR_MARK, TCLK0_MARK, CAN_CLK_B_MARK, ET0_ETXD4_MARK,
+ EX_CS5_MARK, SD1_CMD_A_MARK, ATADIR_MARK, QSSL_B_MARK,
+ ET0_ETXD3_A_MARK,
+ EX_CS4_MARK, SD1_WP_A_MARK, ATAWR_MARK, QMI_QIO1_B_MARK,
+ ET0_ETXD2_A_MARK,
+ EX_CS3_MARK, SD1_CD_A_MARK, ATARD_MARK, QMO_QIO0_B_MARK,
+ ET0_ETXD1_A_MARK,
+ EX_CS2_MARK, TX3_B_MARK, ATACS1_MARK, QSPCLK_B_MARK,
+ ET0_GTX_CLK_A_MARK,
+ EX_CS1_MARK, RX3_B_MARK, ATACS0_MARK, QIO2_B_MARK,
+ ET0_ETXD0_MARK,
+ CS1_A26_MARK, QIO3_B_MARK,
+ D15_MARK, SCK2_B_MARK,
+
+ /* IPSR4 */
+ SCK2_A_MARK, VI0_G3_MARK,
+ RTS1_B_MARK, VI0_G2_MARK,
+ CTS1_B_MARK, VI0_DATA7_VI0_G1_MARK,
+ TX1_B_MARK, VI0_DATA6_VI0_G0_MARK, ET0_PHY_INT_A_MARK,
+ RX1_B_MARK, VI0_DATA5_VI0_B5_MARK, ET0_MAGIC_A_MARK,
+ SCK1_B_MARK, VI0_DATA4_VI0_B4_MARK, ET0_LINK_A_MARK,
+ RTS0_B_MARK, VI0_DATA3_VI0_B3_MARK, ET0_MDIO_A_MARK,
+ CTS0_B_MARK, VI0_DATA2_VI0_B2_MARK, RMII0_MDIO_A_MARK,
+ ET0_MDC_MARK,
+ HTX0_A_MARK, TX1_A_MARK, VI0_DATA1_VI0_B1_MARK,
+ RMII0_MDC_A_MARK, ET0_COL_MARK,
+ HRX0_A_MARK, RX1_A_MARK, VI0_DATA0_VI0_B0_MARK,
+ RMII0_CRS_DV_A_MARK, ET0_CRS_MARK,
+ HSCK0_A_MARK, SCK1_A_MARK, VI0_VSYNC_MARK,
+ RMII0_RX_ER_A_MARK, ET0_RX_ER_MARK,
+ HRTS0_A_MARK, RTS1_A_MARK, VI0_HSYNC_MARK,
+ RMII0_TXD_EN_A_MARK, ET0_RX_DV_MARK,
+ HCTS0_A_MARK, CTS1_A_MARK, VI0_FIELD_MARK,
+ RMII0_RXD1_A_MARK, ET0_ERXD7_MARK,
+
+ /* IPSR5 */
+ SD2_CLK_A_MARK, RX2_A_MARK, VI0_G4_MARK, ET0_RX_CLK_B_MARK,
+ SD2_CMD_A_MARK, TX2_A_MARK, VI0_G5_MARK, ET0_ERXD2_B_MARK,
+ SD2_DAT0_A_MARK, RX3_A_MARK, VI0_R0_MARK, ET0_ERXD3_B_MARK,
+ SD2_DAT1_A_MARK, TX3_A_MARK, VI0_R1_MARK, ET0_MDIO_B_MARK,
+ SD2_DAT2_A_MARK, RX4_A_MARK, VI0_R2_MARK, ET0_LINK_B_MARK,
+ SD2_DAT3_A_MARK, TX4_A_MARK, VI0_R3_MARK, ET0_MAGIC_B_MARK,
+ SD2_CD_A_MARK, RX5_A_MARK, VI0_R4_MARK, ET0_PHY_INT_B_MARK,
+ SD2_WP_A_MARK, TX5_A_MARK, VI0_R5_MARK,
+ REF125CK_MARK, ADTRG_MARK, RX5_C_MARK,
+ REF50CK_MARK, CTS1_E_MARK, HCTS0_D_MARK,
+
+ /* IPSR6 */
+ DU0_DR0_MARK, SCIF_CLK_B_MARK, HRX0_D_MARK, IETX_A_MARK,
+ TCLKA_A_MARK, HIFD00_MARK,
+ DU0_DR1_MARK, SCK0_B_MARK, HTX0_D_MARK, IERX_A_MARK,
+ TCLKB_A_MARK, HIFD01_MARK,
+ DU0_DR2_MARK, RX0_B_MARK, TCLKC_A_MARK, HIFD02_MARK,
+ DU0_DR3_MARK, TX0_B_MARK, TCLKD_A_MARK, HIFD03_MARK,
+ DU0_DR4_MARK, CTS0_C_MARK, TIOC0A_A_MARK, HIFD04_MARK,
+ DU0_DR5_MARK, RTS0_C_MARK, TIOC0B_A_MARK, HIFD05_MARK,
+ DU0_DR6_MARK, SCK1_C_MARK, TIOC0C_A_MARK, HIFD06_MARK,
+ DU0_DR7_MARK, RX1_C_MARK, TIOC0D_A_MARK, HIFD07_MARK,
+ DU0_DG0_MARK, TX1_C_MARK, HSCK0_D_MARK, IECLK_A_MARK,
+ TIOC1A_A_MARK, HIFD08_MARK,
+ DU0_DG1_MARK, CTS1_C_MARK, HRTS0_D_MARK, TIOC1B_A_MARK,
+ HIFD09_MARK,
+
+ /* IPSR7 */
+ DU0_DG2_MARK, RTS1_C_MARK, RMII0_MDC_B_MARK, TIOC2A_A_MARK,
+ HIFD10_MARK,
+ DU0_DG3_MARK, SCK2_C_MARK, RMII0_MDIO_B_MARK, TIOC2B_A_MARK,
+ HIFD11_MARK,
+ DU0_DG4_MARK, RX2_C_MARK, RMII0_CRS_DV_B_MARK, TIOC3A_A_MARK,
+ HIFD12_MARK,
+ DU0_DG5_MARK, TX2_C_MARK, RMII0_RX_ER_B_MARK, TIOC3B_A_MARK,
+ HIFD13_MARK,
+ DU0_DG6_MARK, RX3_C_MARK, RMII0_RXD0_B_MARK, TIOC3C_A_MARK,
+ HIFD14_MARK,
+ DU0_DG7_MARK, TX3_C_MARK, RMII0_RXD1_B_MARK, TIOC3D_A_MARK,
+ HIFD15_MARK,
+ DU0_DB0_MARK, RX4_C_MARK, RMII0_TXD_EN_B_MARK, TIOC4A_A_MARK,
+ HIFCS_MARK,
+ DU0_DB1_MARK, TX4_C_MARK, RMII0_TXD0_B_MARK, TIOC4B_A_MARK,
+ HIFRS_MARK,
+ DU0_DB2_MARK, RX5_B_MARK, RMII0_TXD1_B_MARK, TIOC4C_A_MARK,
+ HIFWR_MARK,
+ DU0_DB3_MARK, TX5_B_MARK, TIOC4D_A_MARK, HIFRD_MARK,
+ DU0_DB4_MARK, HIFINT_MARK,
+
+ /* IPSR8 */
+ DU0_DB5_MARK, HIFDREQ_MARK,
+ DU0_DB6_MARK, HIFRDY_MARK,
+ DU0_DB7_MARK, SSI_SCK0_B_MARK, HIFEBL_B_MARK,
+ DU0_DOTCLKIN_MARK, HSPI_CS0_C_MARK, SSI_WS0_B_MARK,
+ DU0_DOTCLKOUT_MARK, HSPI_CLK0_C_MARK, SSI_SDATA0_B_MARK,
+ DU0_EXHSYNC_DU0_HSYNC_MARK, HSPI_TX0_C_MARK, SSI_SCK1_B_MARK,
+ DU0_EXVSYNC_DU0_VSYNC_MARK, HSPI_RX0_C_MARK, SSI_WS1_B_MARK,
+ DU0_EXODDF_DU0_ODDF_MARK, CAN0_RX_B_MARK, HSCK0_B_MARK,
+ SSI_SDATA1_B_MARK,
+ DU0_DISP_MARK, CAN0_TX_B_MARK, HRX0_B_MARK, AUDIO_CLKA_B_MARK,
+ DU0_CDE_MARK, HTX0_B_MARK, AUDIO_CLKB_B_MARK, LCD_VCPWC_B_MARK,
+ IRQ0_A_MARK, HSPI_TX_B_MARK, RX3_E_MARK, ET0_ERXD0_MARK,
+ IRQ1_A_MARK, HSPI_RX_B_MARK, TX3_E_MARK, ET0_ERXD1_MARK,
+ IRQ2_A_MARK, CTS0_A_MARK, HCTS0_B_MARK, ET0_ERXD2_A_MARK,
+ IRQ3_A_MARK, RTS0_A_MARK, HRTS0_B_MARK, ET0_ERXD3_A_MARK,
+
+ /* IPSR9 */
+ VI1_CLK_A_MARK, FD0_B_MARK, LCD_DATA0_B_MARK,
+ VI1_0_A_MARK, FD1_B_MARK, LCD_DATA1_B_MARK,
+ VI1_1_A_MARK, FD2_B_MARK, LCD_DATA2_B_MARK,
+ VI1_2_A_MARK, FD3_B_MARK, LCD_DATA3_B_MARK,
+ VI1_3_A_MARK, FD4_B_MARK, LCD_DATA4_B_MARK,
+ VI1_4_A_MARK, FD5_B_MARK, LCD_DATA5_B_MARK,
+ VI1_5_A_MARK, FD6_B_MARK, LCD_DATA6_B_MARK,
+ VI1_6_A_MARK, FD7_B_MARK, LCD_DATA7_B_MARK,
+ VI1_7_A_MARK, FCE_B_MARK, LCD_DATA8_B_MARK,
+ SSI_SCK0_A_MARK, TIOC1A_B_MARK, LCD_DATA9_B_MARK,
+ SSI_WS0_A_MARK, TIOC1B_B_MARK, LCD_DATA10_B_MARK,
+ SSI_SDATA0_A_MARK, VI1_0_B_MARK, TIOC2A_B_MARK, LCD_DATA11_B_MARK,
+ SSI_SCK1_A_MARK, VI1_1_B_MARK, TIOC2B_B_MARK, LCD_DATA12_B_MARK,
+ SSI_WS1_A_MARK, VI1_2_B_MARK, LCD_DATA13_B_MARK,
+ SSI_SDATA1_A_MARK, VI1_3_B_MARK, LCD_DATA14_B_MARK,
+
+ /* IPSR10 */
+ SSI_SCK23_MARK, VI1_4_B_MARK, RX1_D_MARK, FCLE_B_MARK,
+ LCD_DATA15_B_MARK,
+ SSI_WS23_MARK, VI1_5_B_MARK, TX1_D_MARK, HSCK0_C_MARK,
+ FALE_B_MARK, LCD_DON_B_MARK,
+ SSI_SDATA2_MARK, VI1_6_B_MARK, HRX0_C_MARK, FRE_B_MARK,
+ LCD_CL1_B_MARK,
+ SSI_SDATA3_MARK, VI1_7_B_MARK, HTX0_C_MARK, FWE_B_MARK,
+ LCD_CL2_B_MARK,
+ AUDIO_CLKA_A_MARK, VI1_CLK_B_MARK, SCK1_D_MARK, IECLK_B_MARK,
+ LCD_FLM_B_MARK,
+ AUDIO_CLKB_A_MARK, LCD_CLK_B_MARK,
+ AUDIO_CLKC_MARK, SCK1_E_MARK, HCTS0_C_MARK, FRB_B_MARK,
+ LCD_VEPWC_B_MARK,
+ AUDIO_CLKOUT_MARK, TX1_E_MARK, HRTS0_C_MARK, FSE_B_MARK,
+ LCD_M_DISP_B_MARK,
+ CAN_CLK_A_MARK, RX4_D_MARK,
+ CAN0_TX_A_MARK, TX4_D_MARK, MLB_CLK_MARK,
+ CAN1_RX_A_MARK, IRQ1_B_MARK,
+ CAN0_RX_A_MARK, IRQ0_B_MARK, MLB_SIG_MARK,
+ CAN1_TX_A_MARK, TX5_C_MARK, MLB_DAT_MARK,
+
+ /* IPSR11 */
+ SCL1_MARK, SCIF_CLK_C_MARK,
+ SDA1_MARK, RX1_E_MARK,
+ SDA0_MARK, HIFEBL_A_MARK,
+ SDSELF_MARK, RTS1_E_MARK,
+ SCIF_CLK_A_MARK, HSPI_CLK_A_MARK, VI0_CLK_MARK, RMII0_TXD0_A_MARK,
+ ET0_ERXD4_MARK,
+ SCK0_A_MARK, HSPI_CS_A_MARK, VI0_CLKENB_MARK, RMII0_TXD1_A_MARK,
+ ET0_ERXD5_MARK,
+ RX0_A_MARK, HSPI_RX_A_MARK, RMII0_RXD0_A_MARK, ET0_ERXD6_MARK,
+ TX0_A_MARK, HSPI_TX_A_MARK,
+ PENC1_MARK, TX3_D_MARK, CAN1_TX_B_MARK, TX5_D_MARK,
+ IETX_B_MARK,
+ USB_OVC1_MARK, RX3_D_MARK, CAN1_RX_B_MARK, RX5_D_MARK,
+ IERX_B_MARK,
+ DREQ0_MARK, SD1_CLK_A_MARK, ET0_TX_EN_MARK,
+ DACK0_MARK, SD1_DAT3_A_MARK, ET0_TX_ER_MARK,
+ DREQ1_MARK, HSPI_CLK_B_MARK, RX4_B_MARK, ET0_PHY_INT_C_MARK,
+ ET0_TX_CLK_A_MARK,
+ DACK1_MARK, HSPI_CS_B_MARK, TX4_B_MARK, ET0_RX_CLK_A_MARK,
+ PRESETOUT_MARK, ST_CLKOUT_MARK,
+
+ PINMUX_MARK_END,
+};
+
+static pinmux_enum_t pinmux_data[] = {
+ PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */
+
+ PINMUX_DATA(CLKOUT_MARK, FN_CLKOUT),
+ PINMUX_DATA(BS_MARK, FN_BS), PINMUX_DATA(CS0_MARK, FN_CS0),
+ PINMUX_DATA(EX_CS0_MARK, FN_EX_CS0),
+ PINMUX_DATA(RD_MARK, FN_RD), PINMUX_DATA(WE0_MARK, FN_WE0),
+ PINMUX_DATA(WE1_MARK, FN_WE1),
+ PINMUX_DATA(SCL0_MARK, FN_SCL0), PINMUX_DATA(PENC0_MARK, FN_PENC0),
+ PINMUX_DATA(USB_OVC0_MARK, FN_USB_OVC0),
+ PINMUX_DATA(IRQ2_B_MARK, FN_IRQ2_B),
+ PINMUX_DATA(IRQ3_B_MARK, FN_IRQ3_B),
+
+ /* IPSR0 */
+ PINMUX_IPSR_DATA(IP0_1_0, A0),
+ PINMUX_IPSR_DATA(IP0_1_0, ST0_CLKIN),
+ PINMUX_IPSR_MODSEL_DATA(IP0_1_0, LCD_DATA0_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_1_0, TCLKA_C, SEL_MTU2_CLK_1),
+
+ PINMUX_IPSR_DATA(IP0_3_2, A1),
+ PINMUX_IPSR_DATA(IP0_3_2, ST0_REQ),
+ PINMUX_IPSR_MODSEL_DATA(IP0_3_2, LCD_DATA1_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_3_2, TCLKB_C, SEL_MTU2_CLK_1),
+
+ PINMUX_IPSR_DATA(IP0_5_4, A2),
+ PINMUX_IPSR_DATA(IP0_5_4, ST0_SYC),
+ PINMUX_IPSR_MODSEL_DATA(IP0_5_4, LCD_DATA2_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_5_4, TCLKC_C, SEL_MTU2_CLK_1),
+
+ PINMUX_IPSR_DATA(IP0_7_6, A3),
+ PINMUX_IPSR_DATA(IP0_7_6, ST0_VLD),
+ PINMUX_IPSR_MODSEL_DATA(IP0_7_6, LCD_DATA3_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_7_6, TCLKD_C, SEL_MTU2_CLK_1),
+
+ PINMUX_IPSR_DATA(IP0_9_8, A4),
+ PINMUX_IPSR_DATA(IP0_9_8, ST0_D0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_9_8, LCD_DATA4_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_9_8, TIOC0A_C, SEL_MTU2_CH0_1),
+
+ PINMUX_IPSR_DATA(IP0_11_10, A5),
+ PINMUX_IPSR_DATA(IP0_11_10, ST0_D1),
+ PINMUX_IPSR_MODSEL_DATA(IP0_11_10, LCD_DATA5_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_11_10, TIOC0B_C, SEL_MTU2_CH0_1),
+
+ PINMUX_IPSR_DATA(IP0_13_12, A6),
+ PINMUX_IPSR_DATA(IP0_13_12, ST0_D2),
+ PINMUX_IPSR_MODSEL_DATA(IP0_13_12, LCD_DATA6_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_13_12, TIOC0C_C, SEL_MTU2_CH0_1),
+
+ PINMUX_IPSR_DATA(IP0_15_14, A7),
+ PINMUX_IPSR_DATA(IP0_15_14, ST0_D3),
+ PINMUX_IPSR_MODSEL_DATA(IP0_15_14, LCD_DATA7_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_15_14, TIOC0D_C, SEL_MTU2_CH0_1),
+
+ PINMUX_IPSR_DATA(IP0_17_16, A8),
+ PINMUX_IPSR_DATA(IP0_17_16, ST0_D4),
+ PINMUX_IPSR_MODSEL_DATA(IP0_17_16, LCD_DATA8_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_17_16, TIOC1A_C, SEL_MTU2_CH1_2),
+
+ PINMUX_IPSR_DATA(IP0_19_18, A9),
+ PINMUX_IPSR_DATA(IP0_19_18, ST0_D5),
+ PINMUX_IPSR_MODSEL_DATA(IP0_19_18, LCD_DATA9_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_19_18, TIOC1B_C, SEL_MTU2_CH1_2),
+
+ PINMUX_IPSR_DATA(IP0_21_20, A10),
+ PINMUX_IPSR_DATA(IP0_21_20, ST0_D6),
+ PINMUX_IPSR_MODSEL_DATA(IP0_21_20, LCD_DATA10_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_21_20, TIOC2A_C, SEL_MTU2_CH2_2),
+
+ PINMUX_IPSR_DATA(IP0_23_22, A11),
+ PINMUX_IPSR_DATA(IP0_23_22, ST0_D7),
+ PINMUX_IPSR_MODSEL_DATA(IP0_23_22, LCD_DATA11_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_23_22, TIOC2B_C, SEL_MTU2_CH2_2),
+
+ PINMUX_IPSR_DATA(IP0_25_24, A12),
+ PINMUX_IPSR_MODSEL_DATA(IP0_25_24, LCD_DATA12_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_25_24, TIOC3A_C, SEL_MTU2_CH3_1),
+
+ PINMUX_IPSR_DATA(IP0_27_26, A13),
+ PINMUX_IPSR_MODSEL_DATA(IP0_27_26, LCD_DATA13_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_27_26, TIOC3B_C, SEL_MTU2_CH3_1),
+
+ PINMUX_IPSR_DATA(IP0_29_28, A14),
+ PINMUX_IPSR_MODSEL_DATA(IP0_29_28, LCD_DATA14_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_29_28, TIOC3C_C, SEL_MTU2_CH3_1),
+
+ PINMUX_IPSR_DATA(IP0_31_30, A15),
+ PINMUX_IPSR_DATA(IP0_31_30, ST0_VCO_CLKIN),
+ PINMUX_IPSR_MODSEL_DATA(IP0_31_30, LCD_DATA15_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP0_31_30, TIOC3D_C, SEL_MTU2_CH3_1),
+
+
+ /* IPSR1 */
+ PINMUX_IPSR_DATA(IP1_1_0, A16),
+ PINMUX_IPSR_DATA(IP1_1_0, ST0_PWM),
+ PINMUX_IPSR_MODSEL_DATA(IP1_1_0, LCD_DON_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP1_1_0, TIOC4A_C, SEL_MTU2_CH4_1),
+
+ PINMUX_IPSR_DATA(IP1_3_2, A17),
+ PINMUX_IPSR_DATA(IP1_3_2, ST1_VCO_CLKIN),
+ PINMUX_IPSR_MODSEL_DATA(IP1_3_2, LCD_CL1_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP1_3_2, TIOC4B_C, SEL_MTU2_CH4_1),
+
+ PINMUX_IPSR_DATA(IP1_5_4, A18),
+ PINMUX_IPSR_DATA(IP1_5_4, ST1_PWM),
+ PINMUX_IPSR_MODSEL_DATA(IP1_5_4, LCD_CL2_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP1_5_4, TIOC4C_C, SEL_MTU2_CH4_1),
+
+ PINMUX_IPSR_DATA(IP1_7_6, A19),
+ PINMUX_IPSR_DATA(IP1_7_6, ST1_CLKIN),
+ PINMUX_IPSR_MODSEL_DATA(IP1_7_6, LCD_CLK_A, SEL_LCDC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP1_7_6, TIOC4D_C, SEL_MTU2_CH4_1),
+
+ PINMUX_IPSR_DATA(IP1_9_8, A20),
+ PINMUX_IPSR_DATA(IP1_9_8, ST1_REQ),
+ PINMUX_IPSR_MODSEL_DATA(IP1_9_8, LCD_FLM_A, SEL_LCDC_0),
+
+ PINMUX_IPSR_DATA(IP1_11_10, A21),
+ PINMUX_IPSR_DATA(IP1_11_10, ST1_SYC),
+ PINMUX_IPSR_MODSEL_DATA(IP1_11_10, LCD_VCPWC_A, SEL_LCDC_0),
+
+ PINMUX_IPSR_DATA(IP1_13_12, A22),
+ PINMUX_IPSR_DATA(IP1_13_12, ST1_VLD),
+ PINMUX_IPSR_MODSEL_DATA(IP1_13_12, LCD_VEPWC_A, SEL_LCDC_0),
+
+ PINMUX_IPSR_DATA(IP1_15_14, A23),
+ PINMUX_IPSR_DATA(IP1_15_14, ST1_D0),
+ PINMUX_IPSR_MODSEL_DATA(IP1_15_14, LCD_M_DISP_A, SEL_LCDC_0),
+
+ PINMUX_IPSR_DATA(IP1_17_16, A24),
+ PINMUX_IPSR_MODSEL_DATA(IP1_17_16, RX2_D, SEL_SCIF2_3),
+ PINMUX_IPSR_DATA(IP1_17_16, ST1_D1),
+
+ PINMUX_IPSR_DATA(IP1_19_18, A25),
+ PINMUX_IPSR_MODSEL_DATA(IP1_17_16, RX2_D, SEL_SCIF2_3),
+ PINMUX_IPSR_DATA(IP1_17_16, ST1_D2),
+
+ PINMUX_IPSR_DATA(IP1_22_20, D0),
+ PINMUX_IPSR_MODSEL_DATA(IP1_22_20, SD0_DAT0_A, SEL_SDHI0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP1_22_20, MMC_D0_A, SEL_MMC_0),
+ PINMUX_IPSR_DATA(IP1_22_20, ST1_D3),
+ PINMUX_IPSR_MODSEL_DATA(IP1_22_20, FD0_A, SEL_FLCTL_0),
+
+ PINMUX_IPSR_DATA(IP1_25_23, D1),
+ PINMUX_IPSR_MODSEL_DATA(IP1_25_23, SD0_DAT0_A, SEL_SDHI0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP1_25_23, MMC_D1_A, SEL_MMC_0),
+ PINMUX_IPSR_DATA(IP1_25_23, ST1_D4),
+ PINMUX_IPSR_MODSEL_DATA(IP1_25_23, FD1_A, SEL_FLCTL_0),
+
+ PINMUX_IPSR_DATA(IP1_28_26, D2),
+ PINMUX_IPSR_MODSEL_DATA(IP1_28_26, SD0_DAT0_A, SEL_SDHI0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP1_28_26, MMC_D2_A, SEL_MMC_0),
+ PINMUX_IPSR_DATA(IP1_28_26, ST1_D5),
+ PINMUX_IPSR_MODSEL_DATA(IP1_28_26, FD2_A, SEL_FLCTL_0),
+
+ PINMUX_IPSR_DATA(IP1_31_29, D3),
+ PINMUX_IPSR_MODSEL_DATA(IP1_31_29, SD0_DAT0_A, SEL_SDHI0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP1_31_29, MMC_D3_A, SEL_MMC_0),
+ PINMUX_IPSR_DATA(IP1_31_29, ST1_D6),
+ PINMUX_IPSR_MODSEL_DATA(IP1_31_29, FD3_A, SEL_FLCTL_0),
+
+ /* IPSR2 */
+ PINMUX_IPSR_DATA(IP2_2_0, D4),
+ PINMUX_IPSR_MODSEL_DATA(IP2_2_0, SD0_CD_A, SEL_SDHI0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_2_0, MMC_D4_A, SEL_MMC_0),
+ PINMUX_IPSR_DATA(IP2_2_0, ST1_D7),
+ PINMUX_IPSR_MODSEL_DATA(IP2_2_0, FD4_A, SEL_FLCTL_0),
+
+ PINMUX_IPSR_DATA(IP2_4_3, D5),
+ PINMUX_IPSR_MODSEL_DATA(IP2_4_3, SD0_WP_A, SEL_SDHI0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_4_3, MMC_D5_A, SEL_MMC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_4_3, FD5_A, SEL_FLCTL_0),
+
+ PINMUX_IPSR_DATA(IP2_7_5, D6),
+ PINMUX_IPSR_MODSEL_DATA(IP2_7_5, RSPI_RSPCK_A, SEL_RSPI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_7_5, MMC_D6_A, SEL_MMC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_7_5, QSPCLK_A, SEL_RQSPI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_7_5, FD6_A, SEL_FLCTL_0),
+
+ PINMUX_IPSR_DATA(IP2_10_8, D7),
+ PINMUX_IPSR_MODSEL_DATA(IP2_10_8, RSPI_SSL_A, SEL_RSPI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_10_8, MMC_D7_A, SEL_MMC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_10_8, QSSL_A, SEL_RQSPI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_10_8, FD7_A, SEL_FLCTL_0),
+
+ PINMUX_IPSR_DATA(IP2_13_11, D8),
+ PINMUX_IPSR_MODSEL_DATA(IP2_13_11, SD0_CLK_A, SEL_SDHI0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_13_11, MMC_CLK_A, SEL_MMC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_13_11, QIO2_A, SEL_RQSPI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_13_11, FCE_A, SEL_FLCTL_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_13_11, ET0_GTX_CLK_B, SEL_ET0_1),
+
+ PINMUX_IPSR_DATA(IP2_16_14, D9),
+ PINMUX_IPSR_MODSEL_DATA(IP2_16_14, SD0_CMD_A, SEL_SDHI0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_16_14, MMC_CMD_A, SEL_MMC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_16_14, QIO3_A, SEL_RQSPI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_16_14, FCLE_A, SEL_FLCTL_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_16_14, ET0_ETXD1_B, SEL_ET0_1),
+
+ PINMUX_IPSR_DATA(IP2_19_17, D10),
+ PINMUX_IPSR_MODSEL_DATA(IP2_19_17, RSPI_MOSI_A, SEL_RSPI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_19_17, QMO_QIO0_A, SEL_RQSPI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_19_17, FALE_A, SEL_FLCTL_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_19_17, ET0_ETXD2_B, SEL_ET0_1),
+
+ PINMUX_IPSR_DATA(IP2_22_20, D11),
+ PINMUX_IPSR_MODSEL_DATA(IP2_22_20, RSPI_MISO_A, SEL_RSPI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_22_20, QMI_QIO1_A, SEL_RQSPI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_22_20, FRE_A, SEL_FLCTL_0),
+
+ PINMUX_IPSR_DATA(IP2_24_23, D12),
+ PINMUX_IPSR_MODSEL_DATA(IP2_24_23, FWE_A, SEL_FLCTL_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_24_23, ET0_ETXD5_B, SEL_ET0_1),
+
+ PINMUX_IPSR_DATA(IP2_27_25, D13),
+ PINMUX_IPSR_MODSEL_DATA(IP2_27_25, RX2_B, SEL_SCIF2_1),
+ PINMUX_IPSR_MODSEL_DATA(IP2_27_25, FRB_A, SEL_FLCTL_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_27_25, ET0_ETXD6_B, SEL_ET0_1),
+
+ PINMUX_IPSR_DATA(IP2_30_28, D14),
+ PINMUX_IPSR_MODSEL_DATA(IP2_30_28, TX2_B, SEL_SCIF2_1),
+ PINMUX_IPSR_MODSEL_DATA(IP2_30_28, FSE_A, SEL_FLCTL_0),
+ PINMUX_IPSR_MODSEL_DATA(IP2_30_28, ET0_TX_CLK_B, SEL_ET0_1),
+
+ /* IPSR3 */
+ PINMUX_IPSR_DATA(IP3_1_0, D15),
+ PINMUX_IPSR_MODSEL_DATA(IP3_1_0, SCK2_B, SEL_SCIF2_1),
+
+ PINMUX_IPSR_DATA(IP3_2, CS1_A26),
+ PINMUX_IPSR_MODSEL_DATA(IP3_2, QIO3_B, SEL_RQSPI_1),
+
+ PINMUX_IPSR_DATA(IP3_5_3, EX_CS1),
+ PINMUX_IPSR_MODSEL_DATA(IP3_5_3, RX3_B, SEL_SCIF2_1),
+ PINMUX_IPSR_DATA(IP3_5_3, ATACS0),
+ PINMUX_IPSR_MODSEL_DATA(IP3_5_3, QIO2_B, SEL_RQSPI_1),
+ PINMUX_IPSR_DATA(IP3_5_3, ET0_ETXD0),
+
+ PINMUX_IPSR_DATA(IP3_8_6, EX_CS2),
+ PINMUX_IPSR_MODSEL_DATA(IP3_8_6, TX3_B, SEL_SCIF3_1),
+ PINMUX_IPSR_DATA(IP3_8_6, ATACS1),
+ PINMUX_IPSR_MODSEL_DATA(IP3_8_6, QSPCLK_B, SEL_RQSPI_1),
+ PINMUX_IPSR_MODSEL_DATA(IP3_8_6, ET0_GTX_CLK_A, SEL_ET0_0),
+
+ PINMUX_IPSR_DATA(IP3_11_9, EX_CS3),
+ PINMUX_IPSR_MODSEL_DATA(IP3_11_9, SD1_CD_A, SEL_SDHI1_0),
+ PINMUX_IPSR_DATA(IP3_11_9, ATARD),
+ PINMUX_IPSR_MODSEL_DATA(IP3_11_9, QMO_QIO0_B, SEL_RQSPI_1),
+ PINMUX_IPSR_MODSEL_DATA(IP3_11_9, ET0_ETXD1_A, SEL_ET0_0),
+
+ PINMUX_IPSR_DATA(IP3_14_12, EX_CS4),
+ PINMUX_IPSR_MODSEL_DATA(IP3_14_12, SD1_WP_A, SEL_SDHI1_0),
+ PINMUX_IPSR_DATA(IP3_14_12, ATAWR),
+ PINMUX_IPSR_MODSEL_DATA(IP3_14_12, QMI_QIO1_B, SEL_RQSPI_1),
+ PINMUX_IPSR_MODSEL_DATA(IP3_14_12, ET0_ETXD2_A, SEL_ET0_0),
+
+ PINMUX_IPSR_DATA(IP3_17_15, EX_CS5),
+ PINMUX_IPSR_MODSEL_DATA(IP3_17_15, SD1_CMD_A, SEL_SDHI1_0),
+ PINMUX_IPSR_DATA(IP3_17_15, ATADIR),
+ PINMUX_IPSR_MODSEL_DATA(IP3_17_15, QSSL_B, SEL_RQSPI_1),
+ PINMUX_IPSR_MODSEL_DATA(IP3_17_15, ET0_ETXD3_A, SEL_ET0_0),
+
+ PINMUX_IPSR_DATA(IP3_19_18, RD_WR),
+ PINMUX_IPSR_DATA(IP3_19_18, TCLK0),
+ PINMUX_IPSR_MODSEL_DATA(IP3_19_18, CAN_CLK_B, SEL_RCAN_CLK_1),
+ PINMUX_IPSR_DATA(IP3_19_18, ET0_ETXD4),
+
+ PINMUX_IPSR_DATA(IP3_20, EX_WAIT0),
+ PINMUX_IPSR_MODSEL_DATA(IP3_20, TCLK1_B, SEL_TMU_1),
+
+ PINMUX_IPSR_DATA(IP3_23_21, EX_WAIT1),
+ PINMUX_IPSR_MODSEL_DATA(IP3_23_21, SD1_DAT0_A, SEL_SDHI1_0),
+ PINMUX_IPSR_DATA(IP3_23_21, DREQ2),
+ PINMUX_IPSR_MODSEL_DATA(IP3_23_21, CAN1_TX_C, SEL_RCAN1_2),
+ PINMUX_IPSR_MODSEL_DATA(IP3_23_21, ET0_LINK_C, SEL_ET0_CTL_2),
+ PINMUX_IPSR_MODSEL_DATA(IP3_23_21, ET0_ETXD5_A, SEL_ET0_0),
+
+ PINMUX_IPSR_DATA(IP3_26_24, EX_WAIT2),
+ PINMUX_IPSR_MODSEL_DATA(IP3_26_24, SD1_DAT1_A, SEL_SDHI1_0),
+ PINMUX_IPSR_DATA(IP3_26_24, DACK2),
+ PINMUX_IPSR_MODSEL_DATA(IP3_26_24, CAN1_RX_C, SEL_RCAN1_2),
+ PINMUX_IPSR_MODSEL_DATA(IP3_26_24, ET0_MAGIC_C, SEL_ET0_CTL_2),
+ PINMUX_IPSR_MODSEL_DATA(IP3_26_24, ET0_ETXD6_A, SEL_ET0_0),
+
+ PINMUX_IPSR_DATA(IP3_29_27, DRACK0),
+ PINMUX_IPSR_MODSEL_DATA(IP3_29_27, SD1_DAT2_A, SEL_SDHI1_0),
+ PINMUX_IPSR_DATA(IP3_29_27, ATAG),
+ PINMUX_IPSR_MODSEL_DATA(IP3_29_27, TCLK1_A, SEL_TMU_0),
+ PINMUX_IPSR_DATA(IP3_29_27, ET0_ETXD7),
+
+ /* IPSR4 */
+ PINMUX_IPSR_MODSEL_DATA(IP4_2_0, HCTS0_A, SEL_HSCIF_0),
+ PINMUX_IPSR_MODSEL_DATA(IP4_2_0, CTS1_A, SEL_SCIF1_0),
+ PINMUX_IPSR_DATA(IP4_2_0, VI0_FIELD),
+ PINMUX_IPSR_MODSEL_DATA(IP4_2_0, RMII0_RXD1_A, SEL_RMII_0),
+ PINMUX_IPSR_DATA(IP4_2_0, ET0_ERXD7),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_5_3, HRTS0_A, SEL_HSCIF_0),
+ PINMUX_IPSR_MODSEL_DATA(IP4_5_3, RTS1_A, SEL_SCIF1_0),
+ PINMUX_IPSR_DATA(IP4_5_3, VI0_HSYNC),
+ PINMUX_IPSR_MODSEL_DATA(IP4_5_3, RMII0_TXD_EN_A, SEL_RMII_0),
+ PINMUX_IPSR_DATA(IP4_5_3, ET0_RX_DV),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_8_6, HSCK0_A, SEL_HSCIF_0),
+ PINMUX_IPSR_MODSEL_DATA(IP4_8_6, SCK1_A, SEL_SCIF1_0),
+ PINMUX_IPSR_DATA(IP4_8_6, VI0_VSYNC),
+ PINMUX_IPSR_MODSEL_DATA(IP4_8_6, RMII0_RX_ER_A, SEL_RMII_0),
+ PINMUX_IPSR_DATA(IP4_8_6, ET0_RX_ER),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_11_9, HRX0_A, SEL_HSCIF_0),
+ PINMUX_IPSR_MODSEL_DATA(IP4_11_9, RX1_A, SEL_SCIF1_0),
+ PINMUX_IPSR_DATA(IP4_11_9, VI0_DATA0_VI0_B0),
+ PINMUX_IPSR_MODSEL_DATA(IP4_11_9, RMII0_CRS_DV_A, SEL_RMII_0),
+ PINMUX_IPSR_DATA(IP4_11_9, ET0_CRS),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_14_12, HTX0_A, SEL_HSCIF_0),
+ PINMUX_IPSR_MODSEL_DATA(IP4_14_12, TX1_A, SEL_SCIF1_0),
+ PINMUX_IPSR_DATA(IP4_14_12, VI0_DATA1_VI0_B1),
+ PINMUX_IPSR_MODSEL_DATA(IP4_14_12, RMII0_MDC_A, SEL_RMII_0),
+ PINMUX_IPSR_DATA(IP4_14_12, ET0_COL),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_17_15, CTS0_B, SEL_SCIF0_1),
+ PINMUX_IPSR_DATA(IP4_17_15, VI0_DATA2_VI0_B2),
+ PINMUX_IPSR_MODSEL_DATA(IP4_17_15, RMII0_MDIO_A, SEL_RMII_0),
+ PINMUX_IPSR_DATA(IP4_17_15, ET0_MDC),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_19_18, RTS0_B, SEL_SCIF0_1),
+ PINMUX_IPSR_DATA(IP4_19_18, VI0_DATA3_VI0_B3),
+ PINMUX_IPSR_MODSEL_DATA(IP4_19_18, ET0_MDIO_A, SEL_ET0_0),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_21_20, SCK1_B, SEL_SCIF1_1),
+ PINMUX_IPSR_DATA(IP4_21_20, VI0_DATA4_VI0_B4),
+ PINMUX_IPSR_MODSEL_DATA(IP4_21_20, ET0_LINK_A, SEL_ET0_CTL_0),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_23_22, RX1_B, SEL_SCIF1_1),
+ PINMUX_IPSR_DATA(IP4_23_22, VI0_DATA5_VI0_B5),
+ PINMUX_IPSR_MODSEL_DATA(IP4_23_22, ET0_MAGIC_A, SEL_ET0_CTL_0),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_25_24, TX1_B, SEL_SCIF1_1),
+ PINMUX_IPSR_DATA(IP4_25_24, VI0_DATA6_VI0_G0),
+ PINMUX_IPSR_MODSEL_DATA(IP4_25_24, ET0_PHY_INT_A, SEL_ET0_CTL_0),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_27_26, CTS1_B, SEL_SCIF1_1),
+ PINMUX_IPSR_DATA(IP4_27_26, VI0_DATA7_VI0_G1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_29_28, RTS1_B, SEL_SCIF1_1),
+ PINMUX_IPSR_DATA(IP4_29_28, VI0_G2),
+
+ PINMUX_IPSR_MODSEL_DATA(IP4_31_30, SCK2_A, SEL_SCIF2_0),
+ PINMUX_IPSR_DATA(IP4_31_30, VI0_G3),
+
+ /* IPSR5 */
+ PINMUX_IPSR_MODSEL_DATA(IP5_2_0, SD2_CLK_A, SEL_SDHI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP5_2_0, RX2_A, SEL_SCIF2_0),
+ PINMUX_IPSR_DATA(IP5_2_0, VI0_G4),
+ PINMUX_IPSR_MODSEL_DATA(IP5_2_0, ET0_RX_CLK_B, SEL_ET0_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP5_5_3, SD2_CMD_A, SEL_SDHI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP5_5_3, TX2_A, SEL_SCIF2_0),
+ PINMUX_IPSR_DATA(IP5_5_3, VI0_G5),
+ PINMUX_IPSR_MODSEL_DATA(IP5_5_3, ET0_ERXD2_B, SEL_ET0_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP5_8_6, SD2_DAT0_A, SEL_SDHI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP5_8_6, RX3_A, SEL_SCIF3_0),
+ PINMUX_IPSR_DATA(IP4_8_6, VI0_R0),
+ PINMUX_IPSR_MODSEL_DATA(IP4_8_6, ET0_ERXD2_B, SEL_ET0_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP5_11_9, SD2_DAT1_A, SEL_SDHI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP5_11_9, TX3_A, SEL_SCIF3_0),
+ PINMUX_IPSR_DATA(IP5_11_9, VI0_R1),
+ PINMUX_IPSR_MODSEL_DATA(IP5_11_9, ET0_MDIO_B, SEL_ET0_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP5_14_12, SD2_DAT2_A, SEL_SDHI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP5_14_12, RX4_A, SEL_SCIF4_0),
+ PINMUX_IPSR_DATA(IP5_14_12, VI0_R2),
+ PINMUX_IPSR_MODSEL_DATA(IP5_14_12, ET0_LINK_B, SEL_ET0_CTL_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP5_17_15, SD2_DAT3_A, SEL_SDHI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP5_17_15, TX4_A, SEL_SCIF4_0),
+ PINMUX_IPSR_DATA(IP5_17_15, VI0_R3),
+ PINMUX_IPSR_MODSEL_DATA(IP5_17_15, ET0_MAGIC_B, SEL_ET0_CTL_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP5_20_18, SD2_CD_A, SEL_SDHI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP5_20_18, RX5_A, SEL_SCIF5_0),
+ PINMUX_IPSR_DATA(IP5_20_18, VI0_R4),
+ PINMUX_IPSR_MODSEL_DATA(IP5_20_18, ET0_PHY_INT_B, SEL_ET0_CTL_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP5_22_21, SD2_WP_A, SEL_SDHI2_0),
+ PINMUX_IPSR_MODSEL_DATA(IP5_22_21, TX5_A, SEL_SCIF5_0),
+ PINMUX_IPSR_DATA(IP5_22_21, VI0_R5),
+
+ PINMUX_IPSR_DATA(IP5_24_23, REF125CK),
+ PINMUX_IPSR_DATA(IP5_24_23, ADTRG),
+ PINMUX_IPSR_MODSEL_DATA(IP5_24_23, RX5_C, SEL_SCIF5_2),
+ PINMUX_IPSR_DATA(IP5_26_25, REF50CK),
+ PINMUX_IPSR_MODSEL_DATA(IP5_26_25, CTS1_E, SEL_SCIF1_3),
+ PINMUX_IPSR_MODSEL_DATA(IP5_26_25, HCTS0_D, SEL_HSCIF_3),
+
+ /* IPSR6 */
+ PINMUX_IPSR_DATA(IP6_2_0, DU0_DR0),
+ PINMUX_IPSR_MODSEL_DATA(IP6_2_0, SCIF_CLK_B, SEL_SCIF_CLK_1),
+ PINMUX_IPSR_MODSEL_DATA(IP6_2_0, HRX0_D, SEL_HSCIF_3),
+ PINMUX_IPSR_MODSEL_DATA(IP6_2_0, IETX_A, SEL_IEBUS_0),
+ PINMUX_IPSR_MODSEL_DATA(IP6_2_0, TCLKA_A, SEL_MTU2_CLK_0),
+ PINMUX_IPSR_DATA(IP6_2_0, HIFD00),
+
+ PINMUX_IPSR_DATA(IP6_5_3, DU0_DR1),
+ PINMUX_IPSR_MODSEL_DATA(IP6_5_3, SCK0_B, SEL_SCIF0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP6_5_3, HTX0_D, SEL_HSCIF_3),
+ PINMUX_IPSR_MODSEL_DATA(IP6_5_3, IERX_A, SEL_IEBUS_0),
+ PINMUX_IPSR_MODSEL_DATA(IP6_5_3, TCLKB_A, SEL_MTU2_CLK_0),
+ PINMUX_IPSR_DATA(IP6_5_3, HIFD01),
+
+ PINMUX_IPSR_DATA(IP6_7_6, DU0_DR2),
+ PINMUX_IPSR_MODSEL_DATA(IP6_7_6, RX0_B, SEL_SCIF0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP6_7_6, TCLKC_A, SEL_MTU2_CLK_0),
+ PINMUX_IPSR_DATA(IP6_7_6, HIFD02),
+
+ PINMUX_IPSR_DATA(IP6_9_8, DU0_DR3),
+ PINMUX_IPSR_MODSEL_DATA(IP6_9_8, TX0_B, SEL_SCIF0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP6_9_8, TCLKD_A, SEL_MTU2_CLK_0),
+ PINMUX_IPSR_DATA(IP6_9_8, HIFD03),
+
+ PINMUX_IPSR_DATA(IP6_11_10, DU0_DR4),
+ PINMUX_IPSR_MODSEL_DATA(IP6_11_10, CTS0_C, SEL_SCIF0_2),
+ PINMUX_IPSR_MODSEL_DATA(IP6_11_10, TIOC0A_A, SEL_MTU2_CH0_0),
+ PINMUX_IPSR_DATA(IP6_11_10, HIFD04),
+
+ PINMUX_IPSR_DATA(IP6_13_12, DU0_DR5),
+ PINMUX_IPSR_MODSEL_DATA(IP6_13_12, RTS0_C, SEL_SCIF0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP6_13_12, TIOC0B_A, SEL_MTU2_CH0_0),
+ PINMUX_IPSR_DATA(IP6_13_12, HIFD05),
+
+ PINMUX_IPSR_DATA(IP6_15_14, DU0_DR6),
+ PINMUX_IPSR_MODSEL_DATA(IP6_15_14, SCK1_C, SEL_SCIF1_2),
+ PINMUX_IPSR_MODSEL_DATA(IP6_15_14, TIOC0C_A, SEL_MTU2_CH0_0),
+ PINMUX_IPSR_DATA(IP6_15_14, HIFD06),
+
+ PINMUX_IPSR_DATA(IP6_17_16, DU0_DR7),
+ PINMUX_IPSR_MODSEL_DATA(IP6_17_16, RX1_C, SEL_SCIF1_2),
+ PINMUX_IPSR_MODSEL_DATA(IP6_17_16, TIOC0D_A, SEL_MTU2_CH0_0),
+ PINMUX_IPSR_DATA(IP6_17_16, HIFD07),
+
+ PINMUX_IPSR_DATA(IP6_20_18, DU0_DG0),
+ PINMUX_IPSR_MODSEL_DATA(IP6_20_18, TX1_C, SEL_SCIF1_2),
+ PINMUX_IPSR_MODSEL_DATA(IP6_20_18, HSCK0_D, SEL_HSCIF_3),
+ PINMUX_IPSR_MODSEL_DATA(IP6_20_18, IECLK_A, SEL_IEBUS_0),
+ PINMUX_IPSR_MODSEL_DATA(IP6_20_18, TIOC1A_A, SEL_MTU2_CH1_0),
+ PINMUX_IPSR_DATA(IP6_20_18, HIFD08),
+
+ PINMUX_IPSR_DATA(IP6_23_21, DU0_DG1),
+ PINMUX_IPSR_MODSEL_DATA(IP6_23_21, CTS1_C, SEL_SCIF1_2),
+ PINMUX_IPSR_MODSEL_DATA(IP6_23_21, HRTS0_D, SEL_HSCIF_3),
+ PINMUX_IPSR_MODSEL_DATA(IP6_23_21, TIOC1B_A, SEL_MTU2_CH1_0),
+ PINMUX_IPSR_DATA(IP6_23_21, HIFD09),
+
+ /* IPSR7 */
+ PINMUX_IPSR_DATA(IP7_2_0, DU0_DG2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_2_0, RTS1_C, SEL_SCIF1_2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_2_0, RMII0_MDC_B, SEL_RMII_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_2_0, TIOC2A_A, SEL_MTU2_CH2_0),
+ PINMUX_IPSR_DATA(IP7_2_0, HIFD10),
+
+ PINMUX_IPSR_DATA(IP7_5_3, DU0_DG3),
+ PINMUX_IPSR_MODSEL_DATA(IP7_5_3, SCK2_C, SEL_SCIF2_2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_5_3, RMII0_MDIO_B, SEL_RMII_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_5_3, TIOC2B_A, SEL_MTU2_CH2_0),
+ PINMUX_IPSR_DATA(IP7_5_3, HIFD11),
+
+ PINMUX_IPSR_DATA(IP7_8_6, DU0_DG4),
+ PINMUX_IPSR_MODSEL_DATA(IP7_8_6, RX2_C, SEL_SCIF2_2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_8_6, RMII0_CRS_DV_B, SEL_RMII_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_8_6, TIOC3A_A, SEL_MTU2_CH3_0),
+ PINMUX_IPSR_DATA(IP7_8_6, HIFD12),
+
+ PINMUX_IPSR_DATA(IP7_11_9, DU0_DG5),
+ PINMUX_IPSR_MODSEL_DATA(IP7_11_9, TX2_C, SEL_SCIF2_2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_11_9, RMII0_RX_ER_B, SEL_RMII_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_11_9, TIOC3B_A, SEL_MTU2_CH3_0),
+ PINMUX_IPSR_DATA(IP7_11_9, HIFD13),
+
+ PINMUX_IPSR_DATA(IP7_14_12, DU0_DG6),
+ PINMUX_IPSR_MODSEL_DATA(IP7_14_12, RX3_C, SEL_SCIF3_2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_14_12, RMII0_RXD0_B, SEL_RMII_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_14_12, TIOC3C_A, SEL_MTU2_CH3_0),
+ PINMUX_IPSR_DATA(IP7_14_12, HIFD14),
+
+ PINMUX_IPSR_DATA(IP7_17_15, DU0_DG7),
+ PINMUX_IPSR_MODSEL_DATA(IP7_17_15, TX3_C, SEL_SCIF3_2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_17_15, RMII0_RXD1_B, SEL_RMII_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_17_15, TIOC3D_A, SEL_MTU2_CH3_0),
+ PINMUX_IPSR_DATA(IP7_17_15, HIFD15),
+
+ PINMUX_IPSR_DATA(IP7_20_18, DU0_DB0),
+ PINMUX_IPSR_MODSEL_DATA(IP7_20_18, RX4_C, SEL_SCIF4_2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_20_18, RMII0_TXD_EN_B, SEL_RMII_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_20_18, TIOC4A_A, SEL_MTU2_CH4_0),
+ PINMUX_IPSR_DATA(IP7_20_18, HIFCS),
+
+ PINMUX_IPSR_DATA(IP7_23_21, DU0_DB1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_23_21, TX4_C, SEL_SCIF4_2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_23_21, RMII0_TXD0_B, SEL_RMII_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_23_21, TIOC4B_A, SEL_MTU2_CH4_0),
+ PINMUX_IPSR_DATA(IP7_23_21, HIFWR),
+
+ PINMUX_IPSR_DATA(IP7_26_24, DU0_DB2),
+ PINMUX_IPSR_MODSEL_DATA(IP7_26_24, RX5_B, SEL_SCIF5_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_26_24, RMII0_TXD1_B, SEL_RMII_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_26_24, TIOC4C_A, SEL_MTU2_CH4_0),
+
+ PINMUX_IPSR_DATA(IP7_28_27, DU0_DB3),
+ PINMUX_IPSR_MODSEL_DATA(IP7_28_27, TX5_B, SEL_SCIF5_1),
+ PINMUX_IPSR_MODSEL_DATA(IP7_28_27, TIOC4D_A, SEL_MTU2_CH4_0),
+ PINMUX_IPSR_DATA(IP7_28_27, HIFRD),
+
+ PINMUX_IPSR_DATA(IP7_30_29, DU0_DB4),
+ PINMUX_IPSR_DATA(IP7_30_29, HIFINT),
+
+ /* IPSR8 */
+ PINMUX_IPSR_DATA(IP8_1_0, DU0_DB5),
+ PINMUX_IPSR_DATA(IP8_1_0, HIFDREQ),
+
+ PINMUX_IPSR_DATA(IP8_3_2, DU0_DB6),
+ PINMUX_IPSR_DATA(IP8_3_2, HIFRDY),
+
+ PINMUX_IPSR_DATA(IP8_5_4, DU0_DB7),
+ PINMUX_IPSR_MODSEL_DATA(IP8_5_4, SSI_SCK0_B, SEL_SSI0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_5_4, HIFEBL_B, SEL_HIF_1),
+
+ PINMUX_IPSR_DATA(IP8_7_6, DU0_DOTCLKIN),
+ PINMUX_IPSR_MODSEL_DATA(IP8_7_6, HSPI_CS0_C, SEL_HSPI_2),
+ PINMUX_IPSR_MODSEL_DATA(IP8_7_6, SSI_WS0_B, SEL_SSI0_1),
+
+ PINMUX_IPSR_DATA(IP8_9_8, DU0_DOTCLKOUT),
+ PINMUX_IPSR_MODSEL_DATA(IP8_9_8, HSPI_CLK0_C, SEL_HSPI_2),
+ PINMUX_IPSR_MODSEL_DATA(IP8_9_8, SSI_SDATA0_B, SEL_SSI0_1),
+
+ PINMUX_IPSR_DATA(IP8_11_10, DU0_EXHSYNC_DU0_HSYNC),
+ PINMUX_IPSR_MODSEL_DATA(IP8_11_10, HSPI_TX0_C, SEL_HSPI_2),
+ PINMUX_IPSR_MODSEL_DATA(IP8_11_10, SSI_SCK1_B, SEL_SSI1_1),
+
+ PINMUX_IPSR_DATA(IP8_13_12, DU0_EXVSYNC_DU0_VSYNC),
+ PINMUX_IPSR_MODSEL_DATA(IP8_13_12, HSPI_RX0_C, SEL_HSPI_2),
+ PINMUX_IPSR_MODSEL_DATA(IP8_13_12, SSI_WS1_B, SEL_SSI1_1),
+
+ PINMUX_IPSR_DATA(IP8_15_14, DU0_EXODDF_DU0_ODDF),
+ PINMUX_IPSR_MODSEL_DATA(IP8_15_14, CAN0_RX_B, SEL_RCAN0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_15_14, HSCK0_B, SEL_HSCIF_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_15_14, SSI_SDATA1_B, SEL_SSI1_1),
+
+ PINMUX_IPSR_DATA(IP8_17_16, DU0_DISP),
+ PINMUX_IPSR_MODSEL_DATA(IP8_17_16, CAN0_TX_B, SEL_RCAN0_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_17_16, HRX0_B, SEL_HSCIF_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_17_16, AUDIO_CLKA_B, SEL_AUDIO_CLKA_1),
+
+ PINMUX_IPSR_DATA(IP8_19_18, DU0_CDE),
+ PINMUX_IPSR_MODSEL_DATA(IP8_19_18, HTX0_B, SEL_HSCIF_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_19_18, AUDIO_CLKB_B, SEL_AUDIO_CLKB_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_19_18, LCD_VCPWC_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP8_22_20, IRQ0_A, SEL_INTC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP8_22_20, HSPI_TX_B, SEL_HSPI_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_22_20, RX3_E, SEL_SCIF3_4),
+ PINMUX_IPSR_DATA(IP8_22_20, ET0_ERXD0),
+
+ PINMUX_IPSR_MODSEL_DATA(IP8_25_23, IRQ1_A, SEL_INTC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP8_25_23, HSPI_RX_B, SEL_HSPI_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_25_23, TX3_E, SEL_SCIF3_4),
+ PINMUX_IPSR_DATA(IP8_25_23, ET0_ERXD1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP8_27_26, IRQ2_A, SEL_INTC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP8_27_26, CTS0_A, SEL_SCIF0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP8_27_26, HCTS0_B, SEL_HSCIF_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_27_26, ET0_ERXD2_A, SEL_ET0_0),
+
+ PINMUX_IPSR_MODSEL_DATA(IP8_29_28, IRQ3_A, SEL_INTC_0),
+ PINMUX_IPSR_MODSEL_DATA(IP8_29_28, RTS0_A, SEL_SCIF0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP8_29_28, HRTS0_B, SEL_HSCIF_1),
+ PINMUX_IPSR_MODSEL_DATA(IP8_29_28, ET0_ERXD3_A, SEL_ET0_0),
+
+ /* IPSR9 */
+ PINMUX_IPSR_MODSEL_DATA(IP9_1_0, VI1_CLK_A, SEL_VIN1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_1_0, FD0_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_1_0, LCD_DATA0_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_3_2, VI1_0_A, SEL_VIN1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_3_2, FD1_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_3_2, LCD_DATA1_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_5_4, VI1_1_A, SEL_VIN1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_5_4, FD2_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_5_4, LCD_DATA2_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_7_6, VI1_2_A, SEL_VIN1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_7_6, FD3_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_7_6, LCD_DATA3_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_9_8, VI1_3_A, SEL_VIN1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_9_8, FD4_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_9_8, LCD_DATA4_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_11_10, VI1_4_A, SEL_VIN1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_11_10, FD5_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_11_10, LCD_DATA5_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_13_12, VI1_5_A, SEL_VIN1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_13_12, FD6_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_13_12, LCD_DATA6_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_15_14, VI1_6_A, SEL_VIN1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_15_14, FD7_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_15_14, LCD_DATA7_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_17_16, VI1_7_A, SEL_VIN1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_17_16, FCE_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_17_16, LCD_DATA8_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_19_18, SSI_SCK0_A, SEL_SSI0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_19_18, TIOC1A_B, SEL_MTU2_CH1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_19_18, LCD_DATA9_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_21_20, SSI_WS0_A, SEL_SSI0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_21_20, TIOC1B_B, SEL_MTU2_CH1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_21_20, LCD_DATA10_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_23_22, SSI_SDATA0_A, SEL_SSI0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_23_22, VI1_0_B, SEL_VIN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_23_22, TIOC2A_B, SEL_MTU2_CH2_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_23_22, LCD_DATA11_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_25_24, SSI_SCK1_A, SEL_SSI1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_25_24, VI1_1_B, SEL_VIN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_25_24, TIOC2B_B, SEL_MTU2_CH2_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_25_24, LCD_DATA12_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_27_26, SSI_WS1_A, SEL_SSI1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_27_26, VI1_2_B, SEL_VIN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_27_26, LCD_DATA13_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP9_29_28, SSI_SDATA1_A, SEL_SSI1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP9_29_28, VI1_3_B, SEL_VIN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP9_29_28, LCD_DATA14_B, SEL_LCDC_1),
+
+ /* IPSE10 */
+ PINMUX_IPSR_DATA(IP10_2_0, SSI_SCK23),
+ PINMUX_IPSR_MODSEL_DATA(IP10_2_0, VI1_4_B, SEL_VIN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_2_0, RX1_D, SEL_SCIF1_3),
+ PINMUX_IPSR_MODSEL_DATA(IP10_2_0, FCLE_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_2_0, LCD_DATA15_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_DATA(IP10_5_3, SSI_WS23),
+ PINMUX_IPSR_MODSEL_DATA(IP10_5_3, VI1_5_B, SEL_VIN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_5_3, TX1_D, SEL_SCIF1_3),
+ PINMUX_IPSR_MODSEL_DATA(IP10_5_3, HSCK0_C, SEL_HSCIF_2),
+ PINMUX_IPSR_MODSEL_DATA(IP10_5_3, FALE_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_5_3, LCD_DON_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_DATA(IP10_8_6, SSI_SDATA2),
+ PINMUX_IPSR_MODSEL_DATA(IP10_8_6, VI1_6_B, SEL_VIN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_8_6, HRX0_C, SEL_HSCIF_2),
+ PINMUX_IPSR_MODSEL_DATA(IP10_8_6, FRE_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_8_6, LCD_CL1_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_DATA(IP10_11_9, SSI_SDATA3),
+ PINMUX_IPSR_MODSEL_DATA(IP10_11_9, VI1_7_B, SEL_VIN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_11_9, HTX0_C, SEL_HSCIF_2),
+ PINMUX_IPSR_MODSEL_DATA(IP10_11_9, FWE_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_11_9, LCD_CL2_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP10_14_12, AUDIO_CLKA_A, SEL_AUDIO_CLKA_0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_14_12, VI1_CLK_B, SEL_VIN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_14_12, SCK1_D, SEL_SCIF1_3),
+ PINMUX_IPSR_MODSEL_DATA(IP10_14_12, IECLK_B, SEL_IEBUS_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_14_12, LCD_FLM_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP10_15, AUDIO_CLKB_A, SEL_AUDIO_CLKB_0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_15, LCD_CLK_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_DATA(IP10_18_16, AUDIO_CLKC),
+ PINMUX_IPSR_MODSEL_DATA(IP10_18_16, SCK1_E, SEL_SCIF1_4),
+ PINMUX_IPSR_MODSEL_DATA(IP10_18_16, HCTS0_C, SEL_HSCIF_2),
+ PINMUX_IPSR_MODSEL_DATA(IP10_18_16, FRB_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_18_16, LCD_VEPWC_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_DATA(IP10_21_19, AUDIO_CLKOUT),
+ PINMUX_IPSR_MODSEL_DATA(IP10_21_19, TX1_E, SEL_SCIF1_4),
+ PINMUX_IPSR_MODSEL_DATA(IP10_21_19, HRTS0_C, SEL_HSCIF_2),
+ PINMUX_IPSR_MODSEL_DATA(IP10_21_19, FSE_B, SEL_FLCTL_1),
+ PINMUX_IPSR_MODSEL_DATA(IP10_21_19, LCD_M_DISP_B, SEL_LCDC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP10_22, CAN_CLK_A, SEL_RCAN_CLK_0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_22, RX4_D, SEL_SCIF4_3),
+
+ PINMUX_IPSR_MODSEL_DATA(IP10_24_23, CAN0_TX_A, SEL_RCAN0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_24_23, TX4_D, SEL_SCIF4_3),
+ PINMUX_IPSR_DATA(IP10_24_23, MLB_CLK),
+
+ PINMUX_IPSR_MODSEL_DATA(IP10_25, CAN1_RX_A, SEL_RCAN1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_25, IRQ1_B, SEL_INTC_1),
+
+ PINMUX_IPSR_MODSEL_DATA(IP10_27_26, CAN0_RX_A, SEL_RCAN0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_27_26, IRQ0_B, SEL_INTC_1),
+ PINMUX_IPSR_DATA(IP10_27_26, MLB_SIG),
+
+ PINMUX_IPSR_MODSEL_DATA(IP10_29_28, CAN1_TX_A, SEL_RCAN1_0),
+ PINMUX_IPSR_MODSEL_DATA(IP10_29_28, TX5_C, SEL_SCIF1_2),
+ PINMUX_IPSR_DATA(IP10_29_28, MLB_DAT),
+
+ /* IPSR11 */
+ PINMUX_IPSR_DATA(IP11_0, SCL1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_0, SCIF_CLK_C, SEL_SCIF_CLK_2),
+
+ PINMUX_IPSR_DATA(IP11_1, SDA1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_0, RX1_E, SEL_SCIF1_4),
+
+ PINMUX_IPSR_DATA(IP11_2, SDA0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_2, HIFEBL_A, SEL_HIF_0),
+
+ PINMUX_IPSR_DATA(IP11_3, SDSELF),
+ PINMUX_IPSR_MODSEL_DATA(IP11_3, RTS1_E, SEL_SCIF1_3),
+
+ PINMUX_IPSR_MODSEL_DATA(IP11_6_4, SCIF_CLK_A, SEL_SCIF_CLK_0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_6_4, HSPI_CLK_A, SEL_HSPI_0),
+ PINMUX_IPSR_DATA(IP11_6_4, VI0_CLK),
+ PINMUX_IPSR_MODSEL_DATA(IP11_6_4, RMII0_TXD0_A, SEL_RMII_0),
+ PINMUX_IPSR_DATA(IP11_6_4, ET0_ERXD4),
+
+ PINMUX_IPSR_MODSEL_DATA(IP11_9_7, SCK0_A, SEL_SCIF0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_9_7, HSPI_CS_A, SEL_HSPI_0),
+ PINMUX_IPSR_DATA(IP11_9_7, VI0_CLKENB),
+ PINMUX_IPSR_MODSEL_DATA(IP11_9_7, RMII0_TXD1_A, SEL_RMII_0),
+ PINMUX_IPSR_DATA(IP11_9_7, ET0_ERXD5),
+
+ PINMUX_IPSR_MODSEL_DATA(IP11_11_10, RX0_A, SEL_SCIF0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_11_10, HSPI_RX_A, SEL_HSPI_0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_11_10, RMII0_RXD0_A, SEL_RMII_0),
+ PINMUX_IPSR_DATA(IP11_11_10, ET0_ERXD6),
+
+ PINMUX_IPSR_MODSEL_DATA(IP11_12, TX0_A, SEL_SCIF0_0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_12, HSPI_TX_A, SEL_HSPI_0),
+
+ PINMUX_IPSR_DATA(IP11_15_13, PENC1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_15_13, TX3_D, SEL_SCIF3_3),
+ PINMUX_IPSR_MODSEL_DATA(IP11_15_13, CAN1_TX_B, SEL_RCAN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_15_13, TX5_D, SEL_SCIF5_3),
+ PINMUX_IPSR_MODSEL_DATA(IP11_15_13, IETX_B, SEL_IEBUS_1),
+
+ PINMUX_IPSR_DATA(IP11_18_16, USB_OVC1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_18_16, RX3_D, SEL_SCIF3_3),
+ PINMUX_IPSR_MODSEL_DATA(IP11_18_16, CAN1_RX_B, SEL_RCAN1_1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_18_16, RX5_D, SEL_SCIF5_3),
+ PINMUX_IPSR_MODSEL_DATA(IP11_18_16, IERX_B, SEL_IEBUS_1),
+
+ PINMUX_IPSR_DATA(IP11_20_19, DREQ0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_20_19, SD1_CLK_A, SEL_SDHI1_0),
+ PINMUX_IPSR_DATA(IP11_20_19, ET0_TX_EN),
+
+ PINMUX_IPSR_DATA(IP11_22_21, DACK0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_22_21, SD1_DAT3_A, SEL_SDHI1_0),
+ PINMUX_IPSR_DATA(IP11_22_21, ET0_TX_ER),
+
+ PINMUX_IPSR_DATA(IP11_25_23, DREQ1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_25_23, HSPI_CLK_B, SEL_HSPI_1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_25_23, RX4_B, SEL_SCIF4_1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_25_23, ET0_PHY_INT_C, SEL_ET0_CTL_0),
+ PINMUX_IPSR_MODSEL_DATA(IP11_25_23, ET0_TX_CLK_A, SEL_ET0_0),
+
+ PINMUX_IPSR_DATA(IP11_27_26, DACK1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_27_26, HSPI_CS_B, SEL_HSPI_1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_27_26, TX4_B, SEL_SCIF3_1),
+ PINMUX_IPSR_MODSEL_DATA(IP11_27_26, ET0_RX_CLK_A, SEL_ET0_0),
+
+ PINMUX_IPSR_DATA(IP11_28, PRESETOUT),
+ PINMUX_IPSR_DATA(IP11_28, ST_CLKOUT),
+};
+
+static struct pinmux_gpio pinmux_gpios[] = {
+ PINMUX_GPIO_GP_ALL(),
+
+ GPIO_FN(CLKOUT), GPIO_FN(BS), GPIO_FN(CS0), GPIO_FN(EX_CS0),
+ GPIO_FN(RD), GPIO_FN(WE0), GPIO_FN(WE1),
+ GPIO_FN(SCL0), GPIO_FN(PENC0), GPIO_FN(USB_OVC0),
+ GPIO_FN(IRQ2_B), GPIO_FN(IRQ3_B),
+
+ /* IPSR0 */
+ GPIO_FN(A0), GPIO_FN(ST0_CLKIN), GPIO_FN(LCD_DATA0_A),
+ GPIO_FN(TCLKA_C),
+ GPIO_FN(A1), GPIO_FN(ST0_REQ), GPIO_FN(LCD_DATA1_A),
+ GPIO_FN(TCLKB_C),
+ GPIO_FN(A2), GPIO_FN(ST0_SYC), GPIO_FN(LCD_DATA2_A),
+ GPIO_FN(TCLKC_C),
+ GPIO_FN(A3), GPIO_FN(ST0_VLD), GPIO_FN(LCD_DATA3_A),
+ GPIO_FN(TCLKD_C),
+ GPIO_FN(A4), GPIO_FN(ST0_D0), GPIO_FN(LCD_DATA4_A),
+ GPIO_FN(TIOC0A_C),
+ GPIO_FN(A5), GPIO_FN(ST0_D1), GPIO_FN(LCD_DATA5_A),
+ GPIO_FN(TIOC0B_C),
+ GPIO_FN(A6), GPIO_FN(ST0_D2), GPIO_FN(LCD_DATA6_A),
+ GPIO_FN(TIOC0C_C),
+ GPIO_FN(A7), GPIO_FN(ST0_D3), GPIO_FN(LCD_DATA7_A),
+ GPIO_FN(TIOC0D_C),
+ GPIO_FN(A8), GPIO_FN(ST0_D4), GPIO_FN(LCD_DATA8_A),
+ GPIO_FN(TIOC1A_C),
+ GPIO_FN(A9), GPIO_FN(ST0_D5), GPIO_FN(LCD_DATA9_A),
+ GPIO_FN(TIOC1B_C),
+ GPIO_FN(A10), GPIO_FN(ST0_D6), GPIO_FN(LCD_DATA10_A),
+ GPIO_FN(TIOC2A_C),
+ GPIO_FN(A11), GPIO_FN(ST0_D7), GPIO_FN(LCD_DATA11_A),
+ GPIO_FN(TIOC2B_C),
+ GPIO_FN(A12), GPIO_FN(LCD_DATA12_A), GPIO_FN(TIOC3A_C),
+ GPIO_FN(A13), GPIO_FN(LCD_DATA13_A), GPIO_FN(TIOC3B_C),
+ GPIO_FN(A14), GPIO_FN(LCD_DATA14_A), GPIO_FN(TIOC3C_C),
+ GPIO_FN(A15), GPIO_FN(ST0_VCO_CLKIN), GPIO_FN(LCD_DATA15_A),
+ GPIO_FN(TIOC3D_C),
+
+ /* IPSR1 */
+ GPIO_FN(A16), GPIO_FN(ST0_PWM), GPIO_FN(LCD_DON_A),
+ GPIO_FN(TIOC4A_C),
+ GPIO_FN(A17), GPIO_FN(ST1_VCO_CLKIN), GPIO_FN(LCD_CL1_A),
+ GPIO_FN(TIOC4B_C),
+ GPIO_FN(A18), GPIO_FN(ST1_PWM), GPIO_FN(LCD_CL2_A),
+ GPIO_FN(TIOC4C_C),
+ GPIO_FN(A19), GPIO_FN(ST1_CLKIN), GPIO_FN(LCD_CLK_A),
+ GPIO_FN(TIOC4D_C),
+ GPIO_FN(A20), GPIO_FN(ST1_REQ), GPIO_FN(LCD_FLM_A),
+ GPIO_FN(A21), GPIO_FN(ST1_SYC), GPIO_FN(LCD_VCPWC_A),
+ GPIO_FN(A22), GPIO_FN(ST1_VLD), GPIO_FN(LCD_VEPWC_A),
+ GPIO_FN(A23), GPIO_FN(ST1_D0), GPIO_FN(LCD_M_DISP_A),
+ GPIO_FN(A24), GPIO_FN(RX2_D), GPIO_FN(ST1_D1),
+ GPIO_FN(A25), GPIO_FN(TX2_D), GPIO_FN(ST1_D2),
+ GPIO_FN(D0), GPIO_FN(SD0_DAT0_A), GPIO_FN(MMC_D0_A),
+ GPIO_FN(ST1_D3), GPIO_FN(FD0_A),
+ GPIO_FN(D1), GPIO_FN(SD0_DAT1_A), GPIO_FN(MMC_D1_A),
+ GPIO_FN(ST1_D4), GPIO_FN(FD1_A),
+ GPIO_FN(D2), GPIO_FN(SD0_DAT2_A), GPIO_FN(MMC_D2_A),
+ GPIO_FN(ST1_D5), GPIO_FN(FD2_A),
+ GPIO_FN(D3), GPIO_FN(SD0_DAT3_A), GPIO_FN(MMC_D3_A),
+ GPIO_FN(ST1_D6), GPIO_FN(FD3_A),
+
+ /* IPSR2 */
+ GPIO_FN(D4), GPIO_FN(SD0_CD_A), GPIO_FN(MMC_D4_A), GPIO_FN(ST1_D7),
+ GPIO_FN(FD4_A),
+ GPIO_FN(D5), GPIO_FN(SD0_WP_A), GPIO_FN(MMC_D5_A), GPIO_FN(FD5_A),
+ GPIO_FN(D6), GPIO_FN(RSPI_RSPCK_A), GPIO_FN(MMC_D6_A),
+ GPIO_FN(QSPCLK_A),
+ GPIO_FN(FD6_A),
+ GPIO_FN(D7), GPIO_FN(RSPI_SSL_A), GPIO_FN(MMC_D7_A), GPIO_FN(QSSL_A),
+ GPIO_FN(FD7_A),
+ GPIO_FN(D8), GPIO_FN(SD0_CLK_A), GPIO_FN(MMC_CLK_A), GPIO_FN(QIO2_A),
+ GPIO_FN(FCE_A), GPIO_FN(ET0_GTX_CLK_B),
+ GPIO_FN(D9), GPIO_FN(SD0_CMD_A), GPIO_FN(MMC_CMD_A), GPIO_FN(QIO3_A),
+ GPIO_FN(FCLE_A), GPIO_FN(ET0_ETXD1_B),
+ GPIO_FN(D10), GPIO_FN(RSPI_MOSI_A), GPIO_FN(QMO_QIO0_A),
+ GPIO_FN(FALE_A), GPIO_FN(ET0_ETXD2_B),
+ GPIO_FN(D11), GPIO_FN(RSPI_MISO_A), GPIO_FN(QMI_QIO1_A), GPIO_FN(FRE_A),
+ GPIO_FN(ET0_ETXD3_B),
+ GPIO_FN(D12), GPIO_FN(FWE_A), GPIO_FN(ET0_ETXD5_B),
+ GPIO_FN(D13), GPIO_FN(RX2_B), GPIO_FN(FRB_A), GPIO_FN(ET0_ETXD6_B),
+ GPIO_FN(D14), GPIO_FN(TX2_B), GPIO_FN(FSE_A), GPIO_FN(ET0_TX_CLK_B),
+
+ /* IPSR3 */
+ GPIO_FN(D15), GPIO_FN(SCK2_B),
+ GPIO_FN(CS1_A26), GPIO_FN(QIO3_B),
+ GPIO_FN(EX_CS1), GPIO_FN(RX3_B), GPIO_FN(ATACS0), GPIO_FN(QIO2_B),
+ GPIO_FN(ET0_ETXD0),
+ GPIO_FN(EX_CS2), GPIO_FN(TX3_B), GPIO_FN(ATACS1), GPIO_FN(QSPCLK_B),
+ GPIO_FN(ET0_GTX_CLK_A),
+ GPIO_FN(EX_CS3), GPIO_FN(SD1_CD_A), GPIO_FN(ATARD), GPIO_FN(QMO_QIO0_B),
+ GPIO_FN(ET0_ETXD1_A),
+ GPIO_FN(EX_CS4), GPIO_FN(SD1_WP_A), GPIO_FN(ATAWR), GPIO_FN(QMI_QIO1_B),
+ GPIO_FN(ET0_ETXD2_A),
+ GPIO_FN(EX_CS5), GPIO_FN(SD1_CMD_A), GPIO_FN(ATADIR), GPIO_FN(QSSL_B),
+ GPIO_FN(ET0_ETXD3_A),
+ GPIO_FN(RD_WR), GPIO_FN(TCLK1_B),
+ GPIO_FN(EX_WAIT0), GPIO_FN(TCLK1_B),
+ GPIO_FN(EX_WAIT1), GPIO_FN(SD1_DAT0_A), GPIO_FN(DREQ2),
+ GPIO_FN(CAN1_TX_C), GPIO_FN(ET0_LINK_C), GPIO_FN(ET0_ETXD5_A),
+ GPIO_FN(EX_WAIT2), GPIO_FN(SD1_DAT1_A), GPIO_FN(DACK2),
+ GPIO_FN(CAN1_RX_C), GPIO_FN(ET0_MAGIC_C), GPIO_FN(ET0_ETXD6_A),
+ GPIO_FN(DRACK0), GPIO_FN(SD1_DAT2_A), GPIO_FN(ATAG), GPIO_FN(TCLK1_A),
+ GPIO_FN(ET0_ETXD7),
+
+ /* IPSR4 */
+ GPIO_FN(HCTS0_A), GPIO_FN(CTS1_A), GPIO_FN(VI0_FIELD),
+ GPIO_FN(RMII0_RXD1_A), GPIO_FN(ET0_ERXD7),
+ GPIO_FN(HRTS0_A), GPIO_FN(RTS1_A), GPIO_FN(VI0_HSYNC),
+ GPIO_FN(RMII0_TXD_EN_A), GPIO_FN(ET0_RX_DV),
+ GPIO_FN(HSCK0_A), GPIO_FN(SCK1_A), GPIO_FN(VI0_VSYNC),
+ GPIO_FN(RMII0_RX_ER_A), GPIO_FN(ET0_RX_ER),
+ GPIO_FN(HRX0_A), GPIO_FN(RX1_A), GPIO_FN(VI0_DATA0_VI0_B0),
+ GPIO_FN(RMII0_CRS_DV_A), GPIO_FN(ET0_CRS),
+ GPIO_FN(HTX0_A), GPIO_FN(TX1_A), GPIO_FN(VI0_DATA1_VI0_B1),
+ GPIO_FN(RMII0_MDC_A), GPIO_FN(ET0_COL),
+ GPIO_FN(CTS0_B), GPIO_FN(VI0_DATA2_VI0_B2), GPIO_FN(RMII0_MDIO_A),
+ GPIO_FN(ET0_MDC),
+ GPIO_FN(RTS0_B), GPIO_FN(VI0_DATA3_VI0_B3), GPIO_FN(ET0_MDIO_A),
+ GPIO_FN(SCK1_B), GPIO_FN(VI0_DATA4_VI0_B4), GPIO_FN(ET0_LINK_A),
+ GPIO_FN(RX1_B), GPIO_FN(VI0_DATA5_VI0_B5), GPIO_FN(ET0_MAGIC_A),
+ GPIO_FN(TX1_B), GPIO_FN(VI0_DATA6_VI0_G0), GPIO_FN(ET0_PHY_INT_A),
+ GPIO_FN(CTS1_B), GPIO_FN(VI0_DATA7_VI0_G1),
+ GPIO_FN(RTS1_B), GPIO_FN(VI0_G2),
+ GPIO_FN(SCK2_A), GPIO_FN(VI0_G3),
+
+ /* IPSR5 */
+ GPIO_FN(REF50CK), GPIO_FN(CTS1_E), GPIO_FN(HCTS0_D),
+ GPIO_FN(REF125CK), GPIO_FN(ADTRG), GPIO_FN(RX5_C),
+ GPIO_FN(SD2_WP_A), GPIO_FN(TX5_A), GPIO_FN(VI0_R5),
+ GPIO_FN(SD2_CD_A), GPIO_FN(RX5_A), GPIO_FN(VI0_R4),
+ GPIO_FN(ET0_PHY_INT_B),
+ GPIO_FN(SD2_DAT3_A), GPIO_FN(TX4_A), GPIO_FN(VI0_R3),
+ GPIO_FN(ET0_MAGIC_B),
+ GPIO_FN(SD2_DAT2_A), GPIO_FN(RX4_A), GPIO_FN(VI0_R2),
+ GPIO_FN(ET0_LINK_B),
+ GPIO_FN(SD2_DAT1_A), GPIO_FN(TX3_A), GPIO_FN(VI0_R1),
+ GPIO_FN(ET0_MDIO_B),
+ GPIO_FN(SD2_DAT0_A), GPIO_FN(RX3_A), GPIO_FN(VI0_R0),
+ GPIO_FN(ET0_ERXD3_B),
+ GPIO_FN(SD2_CMD_A), GPIO_FN(TX2_A), GPIO_FN(VI0_G5),
+ GPIO_FN(ET0_ERXD2_B),
+ GPIO_FN(SD2_CLK_A), GPIO_FN(RX2_A), GPIO_FN(VI0_G4),
+ GPIO_FN(ET0_RX_CLK_B),
+
+ /* IPSR6 */
+ GPIO_FN(DU0_DG1), GPIO_FN(CTS1_C), GPIO_FN(HRTS0_D),
+ GPIO_FN(TIOC1B_A), GPIO_FN(HIFD09),
+ GPIO_FN(DU0_DG0), GPIO_FN(TX1_C), GPIO_FN(HSCK0_D),
+ GPIO_FN(IECLK_A), GPIO_FN(TIOC1A_A), GPIO_FN(HIFD08),
+ GPIO_FN(DU0_DR7), GPIO_FN(RX1_C), GPIO_FN(TIOC0D_A),
+ GPIO_FN(HIFD07),
+ GPIO_FN(DU0_DR6), GPIO_FN(SCK1_C), GPIO_FN(TIOC0C_A),
+ GPIO_FN(HIFD06),
+ GPIO_FN(DU0_DR5), GPIO_FN(RTS0_C), GPIO_FN(TIOC0B_A),
+ GPIO_FN(HIFD05),
+ GPIO_FN(DU0_DR4), GPIO_FN(CTS0_C), GPIO_FN(TIOC0A_A),
+ GPIO_FN(HIFD04),
+ GPIO_FN(DU0_DR3), GPIO_FN(TX0_B), GPIO_FN(TCLKD_A), GPIO_FN(HIFD03),
+ GPIO_FN(DU0_DR2), GPIO_FN(RX0_B), GPIO_FN(TCLKC_A), GPIO_FN(HIFD02),
+ GPIO_FN(DU0_DR1), GPIO_FN(SCK0_B), GPIO_FN(HTX0_D),
+ GPIO_FN(IERX_A), GPIO_FN(TCLKB_A), GPIO_FN(HIFD01),
+ GPIO_FN(DU0_DR0), GPIO_FN(SCIF_CLK_B), GPIO_FN(HRX0_D),
+ GPIO_FN(IETX_A), GPIO_FN(TCLKA_A), GPIO_FN(HIFD00),
+
+ /* IPSR7 */
+ GPIO_FN(DU0_DB4), GPIO_FN(HIFINT),
+ GPIO_FN(DU0_DB3), GPIO_FN(TX5_B), GPIO_FN(TIOC4D_A), GPIO_FN(HIFRD),
+ GPIO_FN(DU0_DB2), GPIO_FN(RX5_B), GPIO_FN(RMII0_TXD1_B),
+ GPIO_FN(TIOC4C_A), GPIO_FN(HIFWR),
+ GPIO_FN(DU0_DB1), GPIO_FN(TX4_C), GPIO_FN(RMII0_TXD0_B),
+ GPIO_FN(TIOC4B_A), GPIO_FN(HIFRS),
+ GPIO_FN(DU0_DB0), GPIO_FN(RX4_C), GPIO_FN(RMII0_TXD_EN_B),
+ GPIO_FN(TIOC4A_A), GPIO_FN(HIFCS),
+ GPIO_FN(DU0_DG7), GPIO_FN(TX3_C), GPIO_FN(RMII0_RXD1_B),
+ GPIO_FN(TIOC3D_A), GPIO_FN(HIFD15),
+ GPIO_FN(DU0_DG6), GPIO_FN(RX3_C), GPIO_FN(RMII0_RXD0_B),
+ GPIO_FN(TIOC3C_A), GPIO_FN(HIFD14),
+ GPIO_FN(DU0_DG5), GPIO_FN(TX2_C), GPIO_FN(RMII0_RX_ER_B),
+ GPIO_FN(TIOC3B_A), GPIO_FN(HIFD13),
+ GPIO_FN(DU0_DG4), GPIO_FN(RX2_C), GPIO_FN(RMII0_CRS_DV_B),
+ GPIO_FN(TIOC3A_A), GPIO_FN(HIFD12),
+ GPIO_FN(DU0_DG3), GPIO_FN(SCK2_C), GPIO_FN(RMII0_MDIO_B),
+ GPIO_FN(TIOC2B_A), GPIO_FN(HIFD11),
+ GPIO_FN(DU0_DG2), GPIO_FN(RTS1_C), GPIO_FN(RMII0_MDC_B),
+ GPIO_FN(TIOC2A_A), GPIO_FN(HIFD10),
+
+ /* IPSR8 */
+ GPIO_FN(IRQ3_A), GPIO_FN(RTS0_A), GPIO_FN(HRTS0_B),
+ GPIO_FN(ET0_ERXD3_A),
+ GPIO_FN(IRQ2_A), GPIO_FN(CTS0_A), GPIO_FN(HCTS0_B),
+ GPIO_FN(ET0_ERXD2_A),
+ GPIO_FN(IRQ1_A), GPIO_FN(HSPI_RX_B), GPIO_FN(TX3_E),
+ GPIO_FN(ET0_ERXD1),
+ GPIO_FN(IRQ0_A), GPIO_FN(HSPI_TX_B), GPIO_FN(RX3_E),
+ GPIO_FN(ET0_ERXD0),
+ GPIO_FN(DU0_CDE), GPIO_FN(HTX0_B), GPIO_FN(AUDIO_CLKB_B),
+ GPIO_FN(LCD_VCPWC_B),
+ GPIO_FN(DU0_DISP), GPIO_FN(CAN0_TX_B), GPIO_FN(HRX0_B),
+ GPIO_FN(AUDIO_CLKA_B),
+ GPIO_FN(DU0_EXODDF_DU0_ODDF), GPIO_FN(CAN0_RX_B), GPIO_FN(HSCK0_B),
+ GPIO_FN(SSI_SDATA1_B),
+ GPIO_FN(DU0_EXVSYNC_DU0_VSYNC), GPIO_FN(HSPI_RX0_C),
+ GPIO_FN(SSI_WS1_B),
+ GPIO_FN(DU0_EXHSYNC_DU0_HSYNC), GPIO_FN(HSPI_TX0_C),
+ GPIO_FN(SSI_SCK1_B),
+ GPIO_FN(DU0_DOTCLKOUT), GPIO_FN(HSPI_CLK0_C),
+ GPIO_FN(SSI_SDATA0_B),
+ GPIO_FN(DU0_DOTCLKIN), GPIO_FN(HSPI_CS0_C),
+ GPIO_FN(SSI_WS0_B),
+ GPIO_FN(DU0_DB7), GPIO_FN(SSI_SCK0_B), GPIO_FN(HIFEBL_B),
+ GPIO_FN(DU0_DB6), GPIO_FN(HIFRDY),
+ GPIO_FN(DU0_DB5), GPIO_FN(HIFDREQ),
+
+ /* IPSR9 */
+ GPIO_FN(SSI_SDATA1_A), GPIO_FN(VI1_3_B), GPIO_FN(LCD_DATA14_B),
+ GPIO_FN(SSI_WS1_A), GPIO_FN(VI1_2_B), GPIO_FN(LCD_DATA13_B),
+ GPIO_FN(SSI_SCK1_A), GPIO_FN(VI1_1_B), GPIO_FN(TIOC2B_B),
+ GPIO_FN(LCD_DATA12_B),
+ GPIO_FN(SSI_SDATA0_A), GPIO_FN(VI1_0_B), GPIO_FN(TIOC2A_B),
+ GPIO_FN(LCD_DATA11_B),
+ GPIO_FN(SSI_WS0_A), GPIO_FN(TIOC1B_B), GPIO_FN(LCD_DATA10_B),
+ GPIO_FN(SSI_SCK0_A), GPIO_FN(TIOC1A_B), GPIO_FN(LCD_DATA9_B),
+ GPIO_FN(VI1_7_A), GPIO_FN(FCE_B), GPIO_FN(LCD_DATA8_B),
+ GPIO_FN(VI1_6_A), GPIO_FN(FD7_B), GPIO_FN(LCD_DATA7_B),
+ GPIO_FN(VI1_5_A), GPIO_FN(FD6_B), GPIO_FN(LCD_DATA6_B),
+ GPIO_FN(VI1_4_A), GPIO_FN(FD5_B), GPIO_FN(LCD_DATA5_B),
+ GPIO_FN(VI1_3_A), GPIO_FN(FD4_B), GPIO_FN(LCD_DATA4_B),
+ GPIO_FN(VI1_2_A), GPIO_FN(FD3_B), GPIO_FN(LCD_DATA3_B),
+ GPIO_FN(VI1_1_A), GPIO_FN(FD2_B), GPIO_FN(LCD_DATA2_B),
+ GPIO_FN(VI1_0_A), GPIO_FN(FD1_B), GPIO_FN(LCD_DATA1_B),
+ GPIO_FN(VI1_CLK_A), GPIO_FN(FD0_B), GPIO_FN(LCD_DATA0_B),
+
+ /* IPSR10 */
+ GPIO_FN(CAN1_TX_A), GPIO_FN(TX5_C), GPIO_FN(MLB_DAT),
+ GPIO_FN(CAN0_RX_A), GPIO_FN(IRQ0_B), GPIO_FN(MLB_SIG),
+ GPIO_FN(CAN1_RX_A), GPIO_FN(IRQ1_B),
+ GPIO_FN(CAN0_TX_A), GPIO_FN(TX4_D), GPIO_FN(MLB_CLK),
+ GPIO_FN(CAN_CLK_A), GPIO_FN(RX4_D),
+ GPIO_FN(AUDIO_CLKOUT), GPIO_FN(TX1_E), GPIO_FN(HRTS0_C),
+ GPIO_FN(FSE_B), GPIO_FN(LCD_M_DISP_B),
+ GPIO_FN(AUDIO_CLKC), GPIO_FN(SCK1_E), GPIO_FN(HCTS0_C),
+ GPIO_FN(FRB_B), GPIO_FN(LCD_VEPWC_B),
+ GPIO_FN(AUDIO_CLKB_A), GPIO_FN(LCD_CLK_B),
+ GPIO_FN(AUDIO_CLKA_A), GPIO_FN(VI1_CLK_B), GPIO_FN(SCK1_D),
+ GPIO_FN(IECLK_B), GPIO_FN(LCD_FLM_B),
+ GPIO_FN(SSI_SDATA3), GPIO_FN(VI1_7_B), GPIO_FN(HTX0_C),
+ GPIO_FN(FWE_B), GPIO_FN(LCD_CL2_B),
+ GPIO_FN(SSI_SDATA2), GPIO_FN(VI1_6_B), GPIO_FN(HRX0_C),
+ GPIO_FN(FRE_B), GPIO_FN(LCD_CL1_B),
+ GPIO_FN(SSI_WS23), GPIO_FN(VI1_5_B), GPIO_FN(TX1_D),
+ GPIO_FN(HSCK0_C), GPIO_FN(FALE_B), GPIO_FN(LCD_DON_B),
+ GPIO_FN(SSI_SCK23), GPIO_FN(VI1_4_B), GPIO_FN(RX1_D),
+ GPIO_FN(FCLE_B), GPIO_FN(LCD_DATA15_B),
+
+ /* IPSR11 */
+ GPIO_FN(PRESETOUT), GPIO_FN(ST_CLKOUT),
+ GPIO_FN(DACK1), GPIO_FN(HSPI_CS_B), GPIO_FN(TX4_B),
+ GPIO_FN(ET0_RX_CLK_A),
+ GPIO_FN(DREQ1), GPIO_FN(HSPI_CLK_B), GPIO_FN(RX4_B),
+ GPIO_FN(ET0_PHY_INT_C), GPIO_FN(ET0_TX_CLK_A),
+ GPIO_FN(DACK0), GPIO_FN(SD1_DAT3_A), GPIO_FN(ET0_TX_ER),
+ GPIO_FN(DREQ0), GPIO_FN(SD1_CLK_A), GPIO_FN(ET0_TX_EN),
+ GPIO_FN(USB_OVC1), GPIO_FN(RX3_D), GPIO_FN(CAN1_RX_B),
+ GPIO_FN(RX5_D), GPIO_FN(IERX_B),
+ GPIO_FN(PENC1), GPIO_FN(TX3_D), GPIO_FN(CAN1_TX_B),
+ GPIO_FN(TX5_D), GPIO_FN(IETX_B),
+ GPIO_FN(TX0_A), GPIO_FN(HSPI_TX_A),
+ GPIO_FN(RX0_A), GPIO_FN(HSPI_RX_A), GPIO_FN(RMII0_RXD0_A),
+ GPIO_FN(ET0_ERXD6),
+ GPIO_FN(SCK0_A), GPIO_FN(HSPI_CS_A), GPIO_FN(VI0_CLKENB),
+ GPIO_FN(RMII0_TXD1_A), GPIO_FN(ET0_ERXD5),
+ GPIO_FN(SCIF_CLK_A), GPIO_FN(HSPI_CLK_A), GPIO_FN(VI0_CLK),
+ GPIO_FN(RMII0_TXD0_A), GPIO_FN(ET0_ERXD4),
+ GPIO_FN(SDSELF), GPIO_FN(RTS1_E),
+ GPIO_FN(SDA0), GPIO_FN(HIFEBL_A),
+ GPIO_FN(SDA1), GPIO_FN(RX1_E),
+ GPIO_FN(SCL1), GPIO_FN(SCIF_CLK_C),
+};
+
+static struct pinmux_cfg_reg pinmux_config_regs[] = {
+ { PINMUX_CFG_REG("GPSR0", 0xFFFC0004, 32, 1) {
+ GP_0_31_FN, FN_IP2_2_0,
+ GP_0_30_FN, FN_IP1_31_29,
+ GP_0_29_FN, FN_IP1_28_26,
+ GP_0_28_FN, FN_IP1_25_23,
+ GP_0_27_FN, FN_IP1_22_20,
+ GP_0_26_FN, FN_IP1_19_18,
+ GP_0_25_FN, FN_IP1_17_16,
+ GP_0_24_FN, FN_IP0_5_4,
+ GP_0_23_FN, FN_IP0_3_2,
+ GP_0_22_FN, FN_IP0_1_0,
+ GP_0_21_FN, FN_IP11_28,
+ GP_0_20_FN, FN_IP1_7_6,
+ GP_0_19_FN, FN_IP1_5_4,
+ GP_0_18_FN, FN_IP1_3_2,
+ GP_0_17_FN, FN_IP1_1_0,
+ GP_0_16_FN, FN_IP0_31_30,
+ GP_0_15_FN, FN_IP0_29_28,
+ GP_0_14_FN, FN_IP0_27_26,
+ GP_0_13_FN, FN_IP0_25_24,
+ GP_0_12_FN, FN_IP0_23_22,
+ GP_0_11_FN, FN_IP0_21_20,
+ GP_0_10_FN, FN_IP0_19_18,
+ GP_0_9_FN, FN_IP0_17_16,
+ GP_0_8_FN, FN_IP0_15_14,
+ GP_0_7_FN, FN_IP0_13_12,
+ GP_0_6_FN, FN_IP0_11_10,
+ GP_0_5_FN, FN_IP0_9_8,
+ GP_0_4_FN, FN_IP0_7_6,
+ GP_0_3_FN, FN_IP1_15_14,
+ GP_0_2_FN, FN_IP1_13_12,
+ GP_0_1_FN, FN_IP1_11_10,
+ GP_0_0_FN, FN_IP1_9_8 }
+ },
+ { PINMUX_CFG_REG("GPSR1", 0xFFFC0008, 32, 1) {
+ GP_1_31_FN, FN_IP11_25_23,
+ GP_1_30_FN, FN_IP2_13_11,
+ GP_1_29_FN, FN_IP2_10_8,
+ GP_1_28_FN, FN_IP2_7_5,
+ GP_1_27_FN, FN_IP3_26_24,
+ GP_1_26_FN, FN_IP3_23_21,
+ GP_1_25_FN, FN_IP2_4_3,
+ GP_1_24_FN, FN_WE1,
+ GP_1_23_FN, FN_WE0,
+ GP_1_22_FN, FN_IP3_19_18,
+ GP_1_21_FN, FN_RD,
+ GP_1_20_FN, FN_IP3_17_15,
+ GP_1_19_FN, FN_IP3_14_12,
+ GP_1_18_FN, FN_IP3_11_9,
+ GP_1_17_FN, FN_IP3_8_6,
+ GP_1_16_FN, FN_IP3_5_3,
+ GP_1_15_FN, FN_EX_CS0,
+ GP_1_14_FN, FN_IP3_2,
+ GP_1_13_FN, FN_CS0,
+ GP_1_12_FN, FN_BS,
+ GP_1_11_FN, FN_CLKOUT,
+ GP_1_10_FN, FN_IP3_1_0,
+ GP_1_9_FN, FN_IP2_30_28,
+ GP_1_8_FN, FN_IP2_27_25,
+ GP_1_7_FN, FN_IP2_24_23,
+ GP_1_6_FN, FN_IP2_22_20,
+ GP_1_5_FN, FN_IP2_19_17,
+ GP_1_4_FN, FN_IP2_16_14,
+ GP_1_3_FN, FN_IP11_22_21,
+ GP_1_2_FN, FN_IP11_20_19,
+ GP_1_1_FN, FN_IP3_29_27,
+ GP_1_0_FN, FN_IP3_20 }
+ },
+ { PINMUX_CFG_REG("GPSR2", 0xFFFC000C, 32, 1) {
+ GP_2_31_FN, FN_IP4_31_30,
+ GP_2_30_FN, FN_IP5_2_0,
+ GP_2_29_FN, FN_IP5_5_3,
+ GP_2_28_FN, FN_IP5_8_6,
+ GP_2_27_FN, FN_IP5_11_9,
+ GP_2_26_FN, FN_IP5_14_12,
+ GP_2_25_FN, FN_IP5_17_15,
+ GP_2_24_FN, FN_IP5_20_18,
+ GP_2_23_FN, FN_IP5_22_21,
+ GP_2_22_FN, FN_IP5_24_23,
+ GP_2_21_FN, FN_IP5_26_25,
+ GP_2_20_FN, FN_IP4_29_28,
+ GP_2_19_FN, FN_IP4_27_26,
+ GP_2_18_FN, FN_IP4_25_24,
+ GP_2_17_FN, FN_IP4_23_22,
+ GP_2_16_FN, FN_IP4_21_20,
+ GP_2_15_FN, FN_IP4_19_18,
+ GP_2_14_FN, FN_IP4_17_15,
+ GP_2_13_FN, FN_IP4_14_12,
+ GP_2_12_FN, FN_IP4_11_9,
+ GP_2_11_FN, FN_IP4_8_6,
+ GP_2_10_FN, FN_IP4_5_3,
+ GP_2_9_FN, FN_IP8_27_26,
+ GP_2_8_FN, FN_IP11_12,
+ GP_2_7_FN, FN_IP8_25_23,
+ GP_2_6_FN, FN_IP8_22_20,
+ GP_2_5_FN, FN_IP11_27_26,
+ GP_2_4_FN, FN_IP8_29_28,
+ GP_2_3_FN, FN_IP4_2_0,
+ GP_2_2_FN, FN_IP11_11_10,
+ GP_2_1_FN, FN_IP11_9_7,
+ GP_2_0_FN, FN_IP11_6_4 }
+ },
+ { PINMUX_CFG_REG("GPSR3", 0xFFFC0010, 32, 1) {
+ GP_3_31_FN, FN_IP9_1_0,
+ GP_3_30_FN, FN_IP8_19_18,
+ GP_3_29_FN, FN_IP8_17_16,
+ GP_3_28_FN, FN_IP8_15_14,
+ GP_3_27_FN, FN_IP8_13_12,
+ GP_3_26_FN, FN_IP8_11_10,
+ GP_3_25_FN, FN_IP8_9_8,
+ GP_3_24_FN, FN_IP8_7_6,
+ GP_3_23_FN, FN_IP8_5_4,
+ GP_3_22_FN, FN_IP8_3_2,
+ GP_3_21_FN, FN_IP8_1_0,
+ GP_3_20_FN, FN_IP7_30_29,
+ GP_3_19_FN, FN_IP7_28_27,
+ GP_3_18_FN, FN_IP7_26_24,
+ GP_3_17_FN, FN_IP7_23_21,
+ GP_3_16_FN, FN_IP7_20_18,
+ GP_3_15_FN, FN_IP7_17_15,
+ GP_3_14_FN, FN_IP7_14_12,
+ GP_3_13_FN, FN_IP7_11_9,
+ GP_3_12_FN, FN_IP7_8_6,
+ GP_3_11_FN, FN_IP7_5_3,
+ GP_3_10_FN, FN_IP7_2_0,
+ GP_3_9_FN, FN_IP6_23_21,
+ GP_3_8_FN, FN_IP6_20_18,
+ GP_3_7_FN, FN_IP6_17_16,
+ GP_3_6_FN, FN_IP6_15_14,
+ GP_3_5_FN, FN_IP6_13_12,
+ GP_3_4_FN, FN_IP6_11_10,
+ GP_3_3_FN, FN_IP6_9_8,
+ GP_3_2_FN, FN_IP6_7_6,
+ GP_3_1_FN, FN_IP6_5_3,
+ GP_3_0_FN, FN_IP6_2_0 }
+ },
+
+ { PINMUX_CFG_REG("GPSR4", 0xFFFC0014, 32, 1) {
+ GP_4_31_FN, FN_IP10_24_23,
+ GP_4_30_FN, FN_IP10_22,
+ GP_4_29_FN, FN_IP11_18_16,
+ GP_4_28_FN, FN_USB_OVC0,
+ GP_4_27_FN, FN_IP11_15_13,
+ GP_4_26_FN, FN_PENC0,
+ GP_4_25_FN, FN_IP11_2,
+ GP_4_24_FN, FN_SCL0,
+ GP_4_23_FN, FN_IP11_1,
+ GP_4_22_FN, FN_IP11_0,
+ GP_4_21_FN, FN_IP10_21_19,
+ GP_4_20_FN, FN_IP10_18_16,
+ GP_4_19_FN, FN_IP10_15,
+ GP_4_18_FN, FN_IP10_14_12,
+ GP_4_17_FN, FN_IP10_11_9,
+ GP_4_16_FN, FN_IP10_8_6,
+ GP_4_15_FN, FN_IP10_5_3,
+ GP_4_14_FN, FN_IP10_2_0,
+ GP_4_13_FN, FN_IP9_29_28,
+ GP_4_12_FN, FN_IP9_27_26,
+ GP_4_11_FN, FN_IP9_9_8,
+ GP_4_10_FN, FN_IP9_7_6,
+ GP_4_9_FN, FN_IP9_5_4,
+ GP_4_8_FN, FN_IP9_3_2,
+ GP_4_7_FN, FN_IP9_17_16,
+ GP_4_6_FN, FN_IP9_15_14,
+ GP_4_5_FN, FN_IP9_13_12,
+ GP_4_4_FN, FN_IP9_11_10,
+ GP_4_3_FN, FN_IP9_25_24,
+ GP_4_2_FN, FN_IP9_23_22,
+ GP_4_1_FN, FN_IP9_21_20,
+ GP_4_0_FN, FN_IP9_19_18 }
+ },
+ { PINMUX_CFG_REG("GPSR5", 0xFFFC0018, 32, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 31 - 28 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 27 - 24 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 23 - 20 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 19 - 16 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 15 - 12 */
+ GP_5_11_FN, FN_IP10_29_28,
+ GP_5_10_FN, FN_IP10_27_26,
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 9 - 6 */
+ 0, 0, 0, 0, /* 5, 4 */
+ GP_5_3_FN, FN_IRQ3_B,
+ GP_5_2_FN, FN_IRQ2_B,
+ GP_5_1_FN, FN_IP11_3,
+ GP_5_0_FN, FN_IP10_25 }
+ },
+
+ { PINMUX_CFG_REG_VAR("IPSR0", 0xFFFC001C, 32,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2) {
+ /* IP0_31_30 [2] */
+ FN_A15, FN_ST0_VCO_CLKIN, FN_LCD_DATA15_A,
+ FN_TIOC3D_C,
+ /* IP0_29_28 [2] */
+ FN_A14, FN_LCD_DATA14_A, FN_TIOC3C_C, 0,
+ /* IP0_27_26 [2] */
+ FN_A13, FN_LCD_DATA13_A, FN_TIOC3B_C, 0,
+ /* IP0_25_24 [2] */
+ FN_A12, FN_LCD_DATA12_A, FN_TIOC3A_C, 0,
+ /* IP0_23_22 [2] */
+ FN_A11, FN_ST0_D7, FN_LCD_DATA11_A, FN_TIOC2B_C,
+ /* IP0_21_20 [2] */
+ FN_A10, FN_ST0_D6, FN_LCD_DATA10_A, FN_TIOC2A_C,
+ /* IP0_19_18 [2] */
+ FN_A9, FN_ST0_D5, FN_LCD_DATA9_A, FN_TIOC1B_C,
+ /* IP0_17_16 [2] */
+ FN_A8, FN_ST0_D4, FN_LCD_DATA8_A, FN_TIOC1A_C,
+ /* IP0_15_14 [2] */
+ FN_A7, FN_ST0_D3, FN_LCD_DATA7_A, FN_TIOC0D_C,
+ /* IP0_13_12 [2] */
+ FN_A6, FN_ST0_D2, FN_LCD_DATA6_A, FN_TIOC0C_C,
+ /* IP0_11_10 [2] */
+ FN_A5, FN_ST0_D1, FN_LCD_DATA5_A, FN_TIOC0B_C,
+ /* IP0_9_8 [2] */
+ FN_A4, FN_ST0_D0, FN_LCD_DATA4_A, FN_TIOC0A_C,
+ /* IP0_7_6 [2] */
+ FN_A3, FN_ST0_VLD, FN_LCD_DATA3_A, FN_TCLKD_C,
+ /* IP0_5_4 [2] */
+ FN_A2, FN_ST0_SYC, FN_LCD_DATA2_A, FN_TCLKC_C,
+ /* IP0_3_2 [2] */
+ FN_A1, FN_ST0_REQ, FN_LCD_DATA1_A, FN_TCLKB_C,
+ /* IP0_1_0 [2] */
+ FN_A0, FN_ST0_CLKIN, FN_LCD_DATA0_A, FN_TCLKA_C }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR1", 0xFFFC0020, 32,
+ 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) {
+ /* IP1_31_29 [3] */
+ FN_D3, FN_SD0_DAT3_A, FN_MMC_D3_A, FN_ST1_D6,
+ FN_FD3_A, 0, 0, 0,
+ /* IP1_28_26 [3] */
+ FN_D2, FN_SD0_DAT2_A, FN_MMC_D2_A, FN_ST1_D5,
+ FN_FD2_A, 0, 0, 0,
+ /* IP1_25_23 [3] */
+ FN_D1, FN_SD0_DAT1_A, FN_MMC_D1_A, FN_ST1_D4,
+ FN_FD1_A, 0, 0, 0,
+ /* IP1_22_20 [3] */
+ FN_D0, FN_SD0_DAT0_A, FN_MMC_D0_A, FN_ST1_D3,
+ FN_FD0_A, 0, 0, 0,
+ /* IP1_19_18 [2] */
+ FN_A25, FN_TX2_D, FN_ST1_D2, 0,
+ /* IP1_17_16 [2] */
+ FN_A24, FN_RX2_D, FN_ST1_D1, 0,
+ /* IP1_15_14 [2] */
+ FN_A23, FN_ST1_D0, FN_LCD_M_DISP_A, 0,
+ /* IP1_13_12 [2] */
+ FN_A22, FN_ST1_VLD, FN_LCD_VEPWC_A, 0,
+ /* IP1_11_10 [2] */
+ FN_A21, FN_ST1_SYC, FN_LCD_VCPWC_A, 0,
+ /* IP1_9_8 [2] */
+ FN_A20, FN_ST1_REQ, FN_LCD_FLM_A, 0,
+ /* IP1_7_6 [2] */
+ FN_A19, FN_ST1_CLKIN, FN_LCD_CLK_A, FN_TIOC4D_C,
+ /* IP1_5_4 [2] */
+ FN_A18, FN_ST1_PWM, FN_LCD_CL2_A, FN_TIOC4C_C,
+ /* IP1_3_2 [2] */
+ FN_A17, FN_ST1_VCO_CLKIN, FN_LCD_CL1_A, FN_TIOC4B_C,
+ /* IP1_1_0 [2] */
+ FN_A16, FN_ST0_PWM, FN_LCD_DON_A, FN_TIOC4A_C }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR2", 0xFFFC0024, 32,
+ 1, 3, 3, 2, 3, 3, 3, 3, 3, 3, 2, 3) {
+ /* IP2_31 [1] */
+ 0, 0,
+ /* IP2_30_28 [3] */
+ FN_D14, FN_TX2_B, 0, FN_FSE_A,
+ FN_ET0_TX_CLK_B, 0, 0, 0,
+ /* IP2_27_25 [3] */
+ FN_D13, FN_RX2_B, 0, FN_FRB_A,
+ FN_ET0_ETXD6_B, 0, 0, 0,
+ /* IP2_24_23 [2] */
+ FN_D12, 0, FN_FWE_A, FN_ET0_ETXD5_B,
+ /* IP2_22_20 [3] */
+ FN_D11, FN_RSPI_MISO_A, 0, FN_QMI_QIO1_A,
+ FN_FRE_A, FN_ET0_ETXD3_B, 0, 0,
+ /* IP2_19_17 [3] */
+ FN_D10, FN_RSPI_MOSI_A, 0, FN_QMO_QIO0_A,
+ FN_FALE_A, FN_ET0_ETXD2_B, 0, 0,
+ /* IP2_16_14 [3] */
+ FN_D9, FN_SD0_CMD_A, FN_MMC_CMD_A, FN_QIO3_A,
+ FN_FCLE_A, FN_ET0_ETXD1_B, 0, 0,
+ /* IP2_13_11 [3] */
+ FN_D8, FN_SD0_CLK_A, FN_MMC_CLK_A, FN_QIO2_A,
+ FN_FCE_A, FN_ET0_GTX_CLK_B, 0, 0,
+ /* IP2_10_8 [3] */
+ FN_D7, FN_RSPI_SSL_A, FN_MMC_D7_A, FN_QSSL_A,
+ FN_FD7_A, 0, 0, 0,
+ /* IP2_7_5 [3] */
+ FN_D6, FN_RSPI_RSPCK_A, FN_MMC_D6_A, FN_QSPCLK_A,
+ FN_FD6_A, 0, 0, 0,
+ /* IP2_4_3 [2] */
+ FN_D5, FN_SD0_WP_A, FN_MMC_D5_A, FN_FD5_A,
+ /* IP2_2_0 [3] */
+ FN_D4, FN_SD0_CD_A, FN_MMC_D4_A, FN_ST1_D7,
+ FN_FD4_A, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR3", 0xFFFC0028, 32,
+ 2, 3, 3, 3, 1, 2, 3, 3, 3, 3, 3, 1, 2) {
+ /* IP3_31_30 [2] */
+ 0, 0, 0, 0,
+ /* IP3_29_27 [3] */
+ FN_DRACK0, FN_SD1_DAT2_A, FN_ATAG, FN_TCLK1_A,
+ FN_ET0_ETXD7, 0, 0, 0,
+ /* IP3_26_24 [3] */
+ FN_EX_WAIT2, FN_SD1_DAT1_A, FN_DACK2, FN_CAN1_RX_C,
+ FN_ET0_MAGIC_C, FN_ET0_ETXD6_A, 0, 0,
+ /* IP3_23_21 [3] */
+ FN_EX_WAIT1, FN_SD1_DAT0_A, FN_DREQ2, FN_CAN1_TX_C,
+ FN_ET0_LINK_C, FN_ET0_ETXD5_A, 0, 0,
+ /* IP3_20 [1] */
+ FN_EX_WAIT0, FN_TCLK1_B,
+ /* IP3_19_18 [2] */
+ FN_RD_WR, FN_TCLK1_B, 0, 0,
+ /* IP3_17_15 [3] */
+ FN_EX_CS5, FN_SD1_CMD_A, FN_ATADIR, FN_QSSL_B,
+ FN_ET0_ETXD3_A, 0, 0, 0,
+ /* IP3_14_12 [3] */
+ FN_EX_CS4, FN_SD1_WP_A, FN_ATAWR, FN_QMI_QIO1_B,
+ FN_ET0_ETXD2_A, 0, 0, 0,
+ /* IP3_11_9 [3] */
+ FN_EX_CS3, FN_SD1_CD_A, FN_ATARD, FN_QMO_QIO0_B,
+ FN_ET0_ETXD1_A, 0, 0, 0,
+ /* IP3_8_6 [3] */
+ FN_EX_CS2, FN_TX3_B, FN_ATACS1, FN_QSPCLK_B,
+ FN_ET0_GTX_CLK_A, 0, 0, 0,
+ /* IP3_5_3 [3] */
+ FN_EX_CS1, FN_RX3_B, FN_ATACS0, FN_QIO2_B,
+ FN_ET0_ETXD0, 0, 0, 0,
+ /* IP3_2 [1] */
+ FN_CS1_A26, FN_QIO3_B,
+ /* IP3_1_0 [2] */
+ FN_D15, FN_SCK2_B, 0, 0 }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR4", 0xFFFC002C, 32,
+ 2, 2, 2, 2, 2, 2 , 2, 3, 3, 3, 3, 3, 3) {
+ /* IP4_31_30 [2] */
+ 0, FN_SCK2_A, FN_VI0_G3, 0,
+ /* IP4_29_28 [2] */
+ 0, FN_RTS1_B, FN_VI0_G2, 0,
+ /* IP4_27_26 [2] */
+ 0, FN_CTS1_B, FN_VI0_DATA7_VI0_G1, 0,
+ /* IP4_25_24 [2] */
+ 0, FN_TX1_B, FN_VI0_DATA6_VI0_G0, FN_ET0_PHY_INT_A,
+ /* IP4_23_22 [2] */
+ 0, FN_RX1_B, FN_VI0_DATA5_VI0_B5, FN_ET0_MAGIC_A,
+ /* IP4_21_20 [2] */
+ 0, FN_SCK1_B, FN_VI0_DATA4_VI0_B4, FN_ET0_LINK_A,
+ /* IP4_19_18 [2] */
+ 0, FN_RTS0_B, FN_VI0_DATA3_VI0_B3, FN_ET0_MDIO_A,
+ /* IP4_17_15 [3] */
+ 0, FN_CTS0_B, FN_VI0_DATA2_VI0_B2, FN_RMII0_MDIO_A,
+ FN_ET0_MDC, 0, 0, 0,
+ /* IP4_14_12 [3] */
+ FN_HTX0_A, FN_TX1_A, FN_VI0_DATA1_VI0_B1, FN_RMII0_MDC_A,
+ FN_ET0_COL, 0, 0, 0,
+ /* IP4_11_9 [3] */
+ FN_HRX0_A, FN_RX1_A, FN_VI0_DATA0_VI0_B0, FN_RMII0_CRS_DV_A,
+ FN_ET0_CRS, 0, 0, 0,
+ /* IP4_8_6 [3] */
+ FN_HSCK0_A, FN_SCK1_A, FN_VI0_VSYNC, FN_RMII0_RX_ER_A,
+ FN_ET0_RX_ER, 0, 0, 0,
+ /* IP4_5_3 [3] */
+ FN_HRTS0_A, FN_RTS1_A, FN_VI0_HSYNC, FN_RMII0_TXD_EN_A,
+ FN_ET0_RX_DV, 0, 0, 0,
+ /* IP4_2_0 [3] */
+ FN_HCTS0_A, FN_CTS1_A, FN_VI0_FIELD, FN_RMII0_RXD1_A,
+ FN_ET0_ERXD7, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR5", 0xFFFC0030, 32,
+ 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3) {
+ /* IP5_31 [1] */
+ 0, 0,
+ /* IP5_30 [1] */
+ 0, 0,
+ /* IP5_29 [1] */
+ 0, 0,
+ /* IP5_28 [1] */
+ 0, 0,
+ /* IP5_27 [1] */
+ 0, 0,
+ /* IP5_26_25 [2] */
+ FN_REF50CK, FN_CTS1_E, FN_HCTS0_D, 0,
+ /* IP5_24_23 [2] */
+ FN_REF125CK, FN_ADTRG, FN_RX5_C, 0,
+ /* IP5_22_21 [2] */
+ FN_SD2_WP_A, FN_TX5_A, FN_VI0_R5, 0,
+ /* IP5_20_18 [3] */
+ FN_SD2_CD_A, FN_RX5_A, FN_VI0_R4, 0,
+ 0, 0, 0, FN_ET0_PHY_INT_B,
+ /* IP5_17_15 [3] */
+ FN_SD2_DAT3_A, FN_TX4_A, FN_VI0_R3, 0,
+ 0, 0, 0, FN_ET0_MAGIC_B,
+ /* IP5_14_12 [3] */
+ FN_SD2_DAT2_A, FN_RX4_A, FN_VI0_R2, 0,
+ 0, 0, 0, FN_ET0_LINK_B,
+ /* IP5_11_9 [3] */
+ FN_SD2_DAT1_A, FN_TX3_A, FN_VI0_R1, 0,
+ 0, 0, 0, FN_ET0_MDIO_B,
+ /* IP5_8_6 [3] */
+ FN_SD2_DAT0_A, FN_RX3_A, FN_VI0_R0, 0,
+ 0, 0, 0, FN_ET0_ERXD3_B,
+ /* IP5_5_3 [3] */
+ FN_SD2_CMD_A, FN_TX2_A, FN_VI0_G5, 0,
+ 0, 0, 0, FN_ET0_ERXD2_B,
+ /* IP5_2_0 [3] */
+ FN_SD2_CLK_A, FN_RX2_A, FN_VI0_G4, 0,
+ FN_ET0_RX_CLK_B, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR6", 0xFFFC0034, 32,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 3, 3, 2, 2, 2, 2, 2, 2, 3, 3) {
+ /* IP5_31 [1] */
+ 0, 0,
+ /* IP6_30 [1] */
+ 0, 0,
+ /* IP6_29 [1] */
+ 0, 0,
+ /* IP6_28 [1] */
+ 0, 0,
+ /* IP6_27 [1] */
+ 0, 0,
+ /* IP6_26 [1] */
+ 0, 0,
+ /* IP6_25 [1] */
+ 0, 0,
+ /* IP6_24 [1] */
+ 0, 0,
+ /* IP6_23_21 [3] */
+ FN_DU0_DG1, FN_CTS1_C, FN_HRTS0_D, FN_TIOC1B_A,
+ FN_HIFD09, 0, 0, 0,
+ /* IP6_20_18 [3] */
+ FN_DU0_DG0, FN_TX1_C, FN_HSCK0_D, FN_IECLK_A,
+ FN_TIOC1A_A, FN_HIFD08, 0, 0,
+ /* IP6_17_16 [2] */
+ FN_DU0_DR7, FN_RX1_C, FN_TIOC0D_A, FN_HIFD07,
+ /* IP6_15_14 [2] */
+ FN_DU0_DR6, FN_SCK1_C, FN_TIOC0C_A, FN_HIFD06,
+ /* IP6_13_12 [2] */
+ FN_DU0_DR5, FN_RTS0_C, FN_TIOC0B_A, FN_HIFD05,
+ /* IP6_11_10 [2] */
+ FN_DU0_DR4, FN_CTS0_C, FN_TIOC0A_A, FN_HIFD04,
+ /* IP6_9_8 [2] */
+ FN_DU0_DR3, FN_TX0_B, FN_TCLKD_A, FN_HIFD03,
+ /* IP6_7_6 [2] */
+ FN_DU0_DR2, FN_RX0_B, FN_TCLKC_A, FN_HIFD02,
+ /* IP6_5_3 [3] */
+ FN_DU0_DR1, FN_SCK0_B, FN_HTX0_D, FN_IERX_A,
+ FN_TCLKB_A, FN_HIFD01, 0, 0,
+ /* IP6_2_0 [3] */
+ FN_DU0_DR0, FN_SCIF_CLK_B, FN_HRX0_D, FN_IETX_A,
+ FN_TCLKA_A, FN_HIFD00, 0, 0 }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR7", 0xFFFC0038, 32,
+ 1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3) {
+ /* IP7_31 [1] */
+ 0, 0,
+ /* IP7_30_29 [2] */
+ FN_DU0_DB4, 0, FN_HIFINT, 0,
+ /* IP7_28_27 [2] */
+ FN_DU0_DB3, FN_TX5_B, FN_TIOC4D_A, FN_HIFRD,
+ /* IP7_26_24 [3] */
+ FN_DU0_DB2, FN_RX5_B, FN_RMII0_TXD1_B, FN_TIOC4C_A,
+ FN_HIFWR, 0, 0, 0,
+ /* IP7_23_21 [3] */
+ FN_DU0_DB1, FN_TX4_C, FN_RMII0_TXD0_B, FN_TIOC4B_A,
+ FN_HIFRS, 0, 0, 0,
+ /* IP7_20_18 [3] */
+ FN_DU0_DB0, FN_RX4_C, FN_RMII0_TXD_EN_B, FN_TIOC4A_A,
+ FN_HIFCS, 0, 0, 0,
+ /* IP7_17_15 [3] */
+ FN_DU0_DG7, FN_TX3_C, FN_RMII0_RXD1_B, FN_TIOC3D_A,
+ FN_HIFD15, 0, 0, 0,
+ /* IP7_14_12 [3] */
+ FN_DU0_DG6, FN_RX3_C, FN_RMII0_RXD0_B, FN_TIOC3C_A,
+ FN_HIFD14, 0, 0, 0,
+ /* IP7_11_9 [3] */
+ FN_DU0_DG5, FN_TX2_C, FN_RMII0_RX_ER_B, FN_TIOC3B_A,
+ FN_HIFD13, 0, 0, 0,
+ /* IP7_8_6 [3] */
+ FN_DU0_DG4, FN_RX2_C, FN_RMII0_CRS_DV_B, FN_TIOC3A_A,
+ FN_HIFD12, 0, 0, 0,
+ /* IP7_5_3 [3] */
+ FN_DU0_DG3, FN_SCK2_C, FN_RMII0_MDIO_B, FN_TIOC2B_A,
+ FN_HIFD11, 0, 0, 0,
+ /* IP7_2_0 [3] */
+ FN_DU0_DG2, FN_RTS1_C, FN_RMII0_MDC_B, FN_TIOC2A_A,
+ FN_HIFD10, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR8", 0xFFFC003C, 32,
+ 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) {
+ /* IP9_31_30 [2] */
+ 0, 0, 0, 0,
+ /* IP8_29_28 [2] */
+ FN_IRQ3_A, FN_RTS0_A, FN_HRTS0_B, FN_ET0_ERXD3_A,
+ /* IP8_27_26 [2] */
+ FN_IRQ2_A, FN_CTS0_A, FN_HCTS0_B, FN_ET0_ERXD2_A,
+ /* IP8_25_23 [3] */
+ FN_IRQ1_A, 0, FN_HSPI_RX_B, FN_TX3_E,
+ FN_ET0_ERXD1, 0, 0, 0,
+ /* IP8_22_20 [3] */
+ FN_IRQ0_A, 0, FN_HSPI_TX_B, FN_RX3_E,
+ FN_ET0_ERXD0, 0, 0, 0,
+ /* IP8_19_18 [2] */
+ FN_DU0_CDE, FN_HTX0_B, FN_AUDIO_CLKB_B, FN_LCD_VCPWC_B,
+ /* IP8_17_16 [2] */
+ FN_DU0_DISP, FN_CAN0_TX_B, FN_HRX0_B, FN_AUDIO_CLKA_B,
+ /* IP8_15_14 [2] */
+ FN_DU0_EXODDF_DU0_ODDF, FN_CAN0_RX_B, FN_HSCK0_B,
+ FN_SSI_SDATA1_B,
+ /* IP8_13_12 [2] */
+ FN_DU0_EXVSYNC_DU0_VSYNC, 0, FN_HSPI_RX0_C, FN_SSI_WS1_B,
+ /* IP8_11_10 [2] */
+ FN_DU0_EXHSYNC_DU0_HSYNC, 0, FN_HSPI_TX0_C, FN_SSI_SCK1_B,
+ /* IP8_9_8 [2] */
+ FN_DU0_DOTCLKOUT, 0, FN_HSPI_CLK0_C, FN_SSI_SDATA0_B,
+ /* IP8_7_6 [2] */
+ FN_DU0_DOTCLKIN, 0, FN_HSPI_CS0_C, FN_SSI_WS0_B,
+ /* IP8_5_4 [2] */
+ FN_DU0_DB7, 0, FN_SSI_SCK0_B, FN_HIFEBL_B,
+ /* IP8_3_2 [2] */
+ FN_DU0_DB6, 0, FN_HIFRDY, 0,
+ /* IP8_1_0 [2] */
+ FN_DU0_DB5, 0, FN_HIFDREQ, 0 }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR9", 0xFFFC0040, 32,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2) {
+ /* IP9_31_30 [2] */
+ 0, 0, 0, 0,
+ /* IP9_29_28 [2] */
+ FN_SSI_SDATA1_A, FN_VI1_3_B, FN_LCD_DATA14_B, 0,
+ /* IP9_27_26 [2] */
+ FN_SSI_WS1_A, FN_VI1_2_B, FN_LCD_DATA13_B, 0,
+ /* IP9_25_24 [2] */
+ FN_SSI_SCK1_A, FN_VI1_1_B, FN_TIOC2B_B, FN_LCD_DATA12_B,
+ /* IP9_23_22 [2] */
+ FN_SSI_SDATA0_A, FN_VI1_0_B, FN_TIOC2A_B, FN_LCD_DATA11_B,
+ /* IP9_21_20 [2] */
+ FN_SSI_WS0_A, FN_TIOC1B_B, FN_LCD_DATA10_B, 0,
+ /* IP9_19_18 [2] */
+ FN_SSI_SCK0_A, FN_TIOC1A_B, FN_LCD_DATA9_B, 0,
+ /* IP9_17_16 [2] */
+ FN_VI1_7_A, FN_FCE_B, FN_LCD_DATA8_B, 0,
+ /* IP9_15_14 [2] */
+ FN_VI1_6_A, 0, FN_FD7_B, FN_LCD_DATA7_B,
+ /* IP9_13_12 [2] */
+ FN_VI1_5_A, 0, FN_FD6_B, FN_LCD_DATA6_B,
+ /* IP9_11_10 [2] */
+ FN_VI1_4_A, 0, FN_FD5_B, FN_LCD_DATA5_B,
+ /* IP9_9_8 [2] */
+ FN_VI1_3_A, 0, FN_FD4_B, FN_LCD_DATA4_B,
+ /* IP9_7_6 [2] */
+ FN_VI1_2_A, 0, FN_FD3_B, FN_LCD_DATA3_B,
+ /* IP9_5_4 [2] */
+ FN_VI1_1_A, 0, FN_FD2_B, FN_LCD_DATA2_B,
+ /* IP9_3_2 [2] */
+ FN_VI1_0_A, 0, FN_FD1_B, FN_LCD_DATA1_B,
+ /* IP9_1_0 [2] */
+ FN_VI1_CLK_A, 0, FN_FD0_B, FN_LCD_DATA0_B }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR10", 0xFFFC0044, 32,
+ 2, 2, 2, 1, 2, 1, 3,
+ 3, 1, 3, 3, 3, 3, 3) {
+ /* IP9_31_30 [2] */
+ 0, 0, 0, 0,
+ /* IP10_29_28 [2] */
+ FN_CAN1_TX_A, FN_TX5_C, FN_MLB_DAT, 0,
+ /* IP10_27_26 [2] */
+ FN_CAN0_RX_A, FN_IRQ0_B, FN_MLB_SIG, 0,
+ /* IP10_25 [1] */
+ FN_CAN1_RX_A, FN_IRQ1_B,
+ /* IP10_24_23 [2] */
+ FN_CAN0_TX_A, FN_TX4_D, FN_MLB_CLK, 0,
+ /* IP10_22 [1] */
+ FN_CAN_CLK_A, FN_RX4_D,
+ /* IP10_21_19 [3] */
+ FN_AUDIO_CLKOUT, FN_TX1_E, FN_HRTS0_C, FN_FSE_B,
+ FN_LCD_M_DISP_B, 0, 0, 0,
+ /* IP10_18_16 [3] */
+ FN_AUDIO_CLKC, FN_SCK1_E, FN_HCTS0_C, FN_FRB_B,
+ FN_LCD_VEPWC_B, 0, 0, 0,
+ /* IP10_15 [1] */
+ FN_AUDIO_CLKB_A, FN_LCD_CLK_B,
+ /* IP10_14_12 [3] */
+ FN_AUDIO_CLKA_A, FN_VI1_CLK_B, FN_SCK1_D, FN_IECLK_B,
+ FN_LCD_FLM_B, 0, 0, 0,
+ /* IP10_11_9 [3] */
+ FN_SSI_SDATA3, FN_VI1_7_B, FN_HTX0_C, FN_FWE_B,
+ FN_LCD_CL2_B, 0, 0, 0,
+ /* IP10_8_6 [3] */
+ FN_SSI_SDATA2, FN_VI1_6_B, FN_HRX0_C, FN_FRE_B,
+ FN_LCD_CL1_B, 0, 0, 0,
+ /* IP10_5_3 [3] */
+ FN_SSI_WS23, FN_VI1_5_B, FN_TX1_D, FN_HSCK0_C, FN_FALE_B,
+ FN_LCD_DON_B, 0, 0, 0,
+ /* IP10_2_0 [3] */
+ FN_SSI_SCK23, FN_VI1_4_B, FN_RX1_D, FN_FCLE_B,
+ FN_LCD_DATA15_B, 0, 0, 0 }
+ },
+ { PINMUX_CFG_REG_VAR("IPSR11", 0xFFFC0048, 32,
+ 3, 1, 2, 2, 2, 3, 3, 1, 2, 3, 3, 1, 1, 1, 1) {
+ /* IP11_31_29 [3] */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* IP11_28 [1] */
+ FN_PRESETOUT, FN_ST_CLKOUT,
+ /* IP11_27_26 [2] */
+ FN_DACK1, FN_HSPI_CS_B, FN_TX4_B, FN_ET0_RX_CLK_A,
+ /* IP11_25_23 [3] */
+ FN_DREQ1, FN_HSPI_CLK_B, FN_RX4_B, FN_ET0_PHY_INT_C,
+ FN_ET0_TX_CLK_A, 0, 0, 0,
+ /* IP11_22_21 [2] */
+ FN_DACK0, FN_SD1_DAT3_A, FN_ET0_TX_ER, 0,
+ /* IP11_20_19 [2] */
+ FN_DREQ0, FN_SD1_CLK_A, FN_ET0_TX_EN, 0,
+ /* IP11_18_16 [3] */
+ FN_USB_OVC1, FN_RX3_D, FN_CAN1_RX_B, FN_RX5_D,
+ FN_IERX_B, 0, 0, 0,
+ /* IP11_15_13 [3] */
+ FN_PENC1, FN_TX3_D, FN_CAN1_TX_B, FN_TX5_D,
+ FN_IETX_B, 0, 0, 0,
+ /* IP11_12 [1] */
+ FN_TX0_A, FN_HSPI_TX_A,
+ /* IP11_11_10 [2] */
+ FN_RX0_A, FN_HSPI_RX_A, FN_RMII0_RXD0_A, FN_ET0_ERXD6,
+ /* IP11_9_7 [3] */
+ FN_SCK0_A, FN_HSPI_CS_A, FN_VI0_CLKENB, FN_RMII0_TXD1_A,
+ FN_ET0_ERXD5, 0, 0, 0,
+ /* IP11_6_4 [3] */
+ FN_SCIF_CLK_A, FN_HSPI_CLK_A, FN_VI0_CLK, FN_RMII0_TXD0_A,
+ FN_ET0_ERXD4, 0, 0, 0,
+ /* IP11_3 [1] */
+ FN_SDSELF, FN_RTS1_E,
+ /* IP11_2 [1] */
+ FN_SDA0, FN_HIFEBL_A,
+ /* IP11_1 [1] */
+ FN_SDA1, FN_RX1_E,
+ /* IP11_0 [1] */
+ FN_SCL1, FN_SCIF_CLK_C }
+ },
+ { PINMUX_CFG_REG_VAR("MOD_SEL1", 0xFFFC004C, 32,
+ 3, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 2,
+ 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) {
+ /* SEL1_31_29 [3] */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* SEL1_28 [1] */
+ FN_SEL_IEBUS_0, FN_SEL_IEBUS_1,
+ /* SEL1_27 [1] */
+ FN_SEL_RQSPI_0, FN_SEL_RQSPI_1,
+ /* SEL1_26 [1] */
+ FN_SEL_VIN1_0, FN_SEL_VIN1_1,
+ /* SEL1_25 [1] */
+ FN_SEL_HIF_0, FN_SEL_HIF_1,
+ /* SEL1_24 [1] */
+ FN_SEL_RSPI_0, FN_SEL_RSPI_1,
+ /* SEL1_23 [1] */
+ FN_SEL_LCDC_0, FN_SEL_LCDC_1,
+ /* SEL1_22_21 [2] */
+ FN_SEL_ET0_CTL_0, FN_SEL_ET0_CTL_1, FN_SEL_ET0_CTL_2, 0,
+ /* SEL1_20 [1] */
+ FN_SEL_ET0_0, FN_SEL_ET0_1,
+ /* SEL1_19 [1] */
+ FN_SEL_RMII_0, FN_SEL_RMII_1,
+ /* SEL1_18 [1] */
+ FN_SEL_TMU_0, FN_SEL_TMU_1,
+ /* SEL1_17_16 [2] */
+ FN_SEL_HSPI_0, FN_SEL_HSPI_1, FN_SEL_HSPI_2, 0,
+ /* SEL1_15_14 [2] */
+ FN_SEL_HSCIF_0, FN_SEL_HSCIF_1, FN_SEL_HSCIF_2, FN_SEL_HSCIF_3,
+ /* SEL1_13 [1] */
+ FN_SEL_RCAN_CLK_0, FN_SEL_RCAN_CLK_1,
+ /* SEL1_12_11 [2] */
+ FN_SEL_RCAN1_0, FN_SEL_RCAN1_1, FN_SEL_RCAN1_2, 0,
+ /* SEL1_10 [1] */
+ FN_SEL_RCAN0_0, FN_SEL_RCAN0_1,
+ /* SEL1_9 [1] */
+ FN_SEL_SDHI2_0, FN_SEL_SDHI2_1,
+ /* SEL1_8 [1] */
+ FN_SEL_SDHI1_0, FN_SEL_SDHI1_1,
+ /* SEL1_7 [1] */
+ FN_SEL_SDHI0_0, FN_SEL_SDHI0_1,
+ /* SEL1_6 [1] */
+ FN_SEL_SSI1_0, FN_SEL_SSI1_1,
+ /* SEL1_5 [1] */
+ FN_SEL_SSI0_0, FN_SEL_SSI0_1,
+ /* SEL1_4 [1] */
+ FN_SEL_AUDIO_CLKB_0, FN_SEL_AUDIO_CLKB_1,
+ /* SEL1_3 [1] */
+ FN_SEL_AUDIO_CLKA_0, FN_SEL_AUDIO_CLKA_1,
+ /* SEL1_2 [1] */
+ FN_SEL_FLCTL_0, FN_SEL_FLCTL_1,
+ /* SEL1_1 [1] */
+ FN_SEL_MMC_0, FN_SEL_MMC_1,
+ /* SEL1_0 [1] */
+ FN_SEL_INTC_0, FN_SEL_INTC_1 }
+ },
+ { PINMUX_CFG_REG_VAR("MOD_SEL2", 0xFFFC0050, 32,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 2, 2, 1, 2, 2, 3, 2, 3, 2, 2) {
+ /* SEL2_31 [1] */
+ 0, 0,
+ /* SEL2_30 [1] */
+ 0, 0,
+ /* SEL2_29 [1] */
+ 0, 0,
+ /* SEL2_28 [1] */
+ 0, 0,
+ /* SEL2_27 [1] */
+ 0, 0,
+ /* SEL2_26 [1] */
+ 0, 0,
+ /* SEL2_25 [1] */
+ 0, 0,
+ /* SEL2_24 [1] */
+ 0, 0,
+ /* SEL2_23 [1] */
+ FN_SEL_MTU2_CLK_0, FN_SEL_MTU2_CLK_1,
+ /* SEL2_22 [1] */
+ FN_SEL_MTU2_CH4_0, FN_SEL_MTU2_CH4_1,
+ /* SEL2_21 [1] */
+ FN_SEL_MTU2_CH3_0, FN_SEL_MTU2_CH3_1,
+ /* SEL2_20_19 [2] */
+ FN_SEL_MTU2_CH2_0, FN_SEL_MTU2_CH2_1, FN_SEL_MTU2_CH2_2, 0,
+ /* SEL2_18_17 [2] */
+ FN_SEL_MTU2_CH1_0, FN_SEL_MTU2_CH1_1, FN_SEL_MTU2_CH1_2, 0,
+ /* SEL2_16 [1] */
+ FN_SEL_MTU2_CH0_0, FN_SEL_MTU2_CH0_1,
+ /* SEL2_15_14 [2] */
+ FN_SEL_SCIF5_0, FN_SEL_SCIF5_1, FN_SEL_SCIF5_2, FN_SEL_SCIF5_3,
+ /* SEL2_13_12 [2] */
+ FN_SEL_SCIF4_0, FN_SEL_SCIF4_1, FN_SEL_SCIF4_2, FN_SEL_SCIF4_3,
+ /* SEL2_11_9 [3] */
+ FN_SEL_SCIF3_0, FN_SEL_SCIF3_1, FN_SEL_SCIF3_2, FN_SEL_SCIF3_3,
+ FN_SEL_SCIF3_4, 0, 0, 0,
+ /* SEL2_8_7 [2] */
+ FN_SEL_SCIF2_0, FN_SEL_SCIF2_1, FN_SEL_SCIF2_2, FN_SEL_SCIF2_3,
+ /* SEL2_6_4 [3] */
+ FN_SEL_SCIF1_0, FN_SEL_SCIF1_1, FN_SEL_SCIF1_2, FN_SEL_SCIF1_3,
+ FN_SEL_SCIF1_4, 0, 0, 0,
+ /* SEL2_3_2 [2] */
+ FN_SEL_SCIF0_0, FN_SEL_SCIF0_1, FN_SEL_SCIF0_2, 0,
+ /* SEL2_1_0 [2] */
+ FN_SEL_SCIF_CLK_0, FN_SEL_SCIF_CLK_1, FN_SEL_SCIF_CLK_2, 0 }
+ },
+ /* GPIO 0 - 5*/
+ { PINMUX_CFG_REG("INOUTSEL0", 0xFFC40004, 32, 1) { GP_INOUTSEL(0) } },
+ { PINMUX_CFG_REG("INOUTSEL1", 0xFFC41004, 32, 1) { GP_INOUTSEL(1) } },
+ { PINMUX_CFG_REG("INOUTSEL2", 0xFFC42004, 32, 1) { GP_INOUTSEL(2) } },
+ { PINMUX_CFG_REG("INOUTSEL3", 0xFFC43004, 32, 1) { GP_INOUTSEL(3) } },
+ { PINMUX_CFG_REG("INOUTSEL4", 0xFFC44004, 32, 1) { GP_INOUTSEL(4) } },
+ { PINMUX_CFG_REG("INOUTSEL5", 0xffc45004, 32, 1) {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 31 - 24 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 23 - 16 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 15 - 12 */
+ GP_5_11_IN, GP_5_11_OUT,
+ GP_5_10_IN, GP_5_10_OUT,
+ GP_5_9_IN, GP_5_9_OUT,
+ GP_5_8_IN, GP_5_8_OUT,
+ GP_5_7_IN, GP_5_7_OUT,
+ GP_5_6_IN, GP_5_6_OUT,
+ GP_5_5_IN, GP_5_5_OUT,
+ GP_5_4_IN, GP_5_4_OUT,
+ GP_5_3_IN, GP_5_3_OUT,
+ GP_5_2_IN, GP_5_2_OUT,
+ GP_5_1_IN, GP_5_1_OUT,
+ GP_5_0_IN, GP_5_0_OUT }
+ },
+ { },
+};
+
+static struct pinmux_data_reg pinmux_data_regs[] = {
+ /* GPIO 0 - 5*/
+ { PINMUX_DATA_REG("INDT0", 0xFFC4000C, 32) { GP_INDT(0) } },
+ { PINMUX_DATA_REG("INDT1", 0xFFC4100C, 32) { GP_INDT(1) } },
+ { PINMUX_DATA_REG("INDT2", 0xFFC4200C, 32) { GP_INDT(2) } },
+ { PINMUX_DATA_REG("INDT3", 0xFFC4300C, 32) { GP_INDT(3) } },
+ { PINMUX_DATA_REG("INDT4", 0xFFC4400C, 32) { GP_INDT(4) } },
+ { PINMUX_DATA_REG("INDT5", 0xFFC4500C, 32) {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ GP_5_11_DATA, GP_5_10_DATA, GP_5_9_DATA, GP_5_8_DATA,
+ GP_5_7_DATA, GP_5_6_DATA, GP_5_5_DATA, GP_5_4_DATA,
+ GP_5_3_DATA, GP_5_2_DATA, GP_5_1_DATA, GP_5_0_DATA }
+ },
+ { },
+};
+
+static struct resource sh7734_pfc_resources[] = {
+ [0] = { /* PFC */
+ .start = 0xFFFC0000,
+ .end = 0xFFFC011C,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = { /* GPIO */
+ .start = 0xFFC40000,
+ .end = 0xFFC4502B,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct pinmux_info sh7734_pinmux_info = {
+ .name = "sh7734_pfc",
+
+ .resource = sh7734_pfc_resources,
+ .num_resources = ARRAY_SIZE(sh7734_pfc_resources),
+
+ .unlock_reg = 0xFFFC0000,
+
+ .reserved_id = PINMUX_RESERVED,
+ .data = { PINMUX_DATA_BEGIN, PINMUX_DATA_END },
+ .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
+ .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
+ .mark = { PINMUX_MARK_BEGIN, PINMUX_MARK_END },
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+ .first_gpio = GPIO_GP_0_0,
+ .last_gpio = GPIO_FN_ST_CLKOUT,
+
+ .gpios = pinmux_gpios,
+ .cfg_regs = pinmux_config_regs,
+ .data_regs = pinmux_data_regs,
+
+ .gpio_data = pinmux_data,
+ .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
+
+static int __init plat_pinmux_setup(void)
+{
+ return register_pinmux(&sh7734_pinmux_info);
+}
+arch_initcall(plat_pinmux_setup);
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
index 1b8848317e9c..b91ea8300a3e 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7343.c
@@ -13,6 +13,7 @@
#include <linux/serial_sci.h>
#include <linux/uio_driver.h>
#include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
#include <asm/clock.h>
/* Serial */
@@ -22,7 +23,7 @@ static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 80, 80, 80, 80 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xc00)),
};
static struct platform_device scif0_device = {
@@ -39,7 +40,7 @@ static struct plat_sci_port scif1_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 81, 81, 81, 81 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xc20)),
};
static struct platform_device scif1_device = {
@@ -56,7 +57,7 @@ static struct plat_sci_port scif2_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 82, 82, 82, 82 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xc40)),
};
static struct platform_device scif2_device = {
@@ -73,7 +74,7 @@ static struct plat_sci_port scif3_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 83, 83, 83, 83 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xc60)),
};
static struct platform_device scif3_device = {
@@ -92,8 +93,8 @@ static struct resource iic0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 96,
- .end = 99,
+ .start = evt2irq(0xe00),
+ .end = evt2irq(0xe60),
.flags = IORESOURCE_IRQ,
},
};
@@ -113,8 +114,8 @@ static struct resource iic1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 44,
- .end = 47,
+ .start = evt2irq(0x780),
+ .end = evt2irq(0x7e0),
.flags = IORESOURCE_IRQ,
},
};
@@ -129,7 +130,7 @@ static struct platform_device iic1_device = {
static struct uio_info vpu_platform_data = {
.name = "VPU4",
.version = "0",
- .irq = 60,
+ .irq = evt2irq(0x980),
};
static struct resource vpu_resources[] = {
@@ -157,7 +158,7 @@ static struct platform_device vpu_device = {
static struct uio_info veu_platform_data = {
.name = "VEU",
.version = "0",
- .irq = 54,
+ .irq = evt2irq(0x8c0),
};
static struct resource veu_resources[] = {
@@ -185,7 +186,7 @@ static struct platform_device veu_device = {
static struct uio_info jpu_platform_data = {
.name = "JPU",
.version = "0",
- .irq = 27,
+ .irq = evt2irq(0x560),
};
static struct resource jpu_resources[] = {
@@ -224,7 +225,7 @@ static struct resource cmt_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 104,
+ .start = evt2irq(0xf00),
.flags = IORESOURCE_IRQ,
},
};
@@ -252,7 +253,7 @@ static struct resource tmu0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 16,
+ .start = evt2irq(0x400),
.flags = IORESOURCE_IRQ,
},
};
@@ -280,7 +281,7 @@ static struct resource tmu1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 17,
+ .start = evt2irq(0x420),
.flags = IORESOURCE_IRQ,
},
};
@@ -307,7 +308,7 @@ static struct resource tmu2_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 18,
+ .start = evt2irq(0x440),
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
index 87773869a2f3..0bd09d51419f 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c
@@ -15,6 +15,7 @@
#include <linux/serial_sci.h>
#include <linux/uio_driver.h>
#include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
#include <linux/usb/r8a66597.h>
#include <asm/clock.h>
@@ -25,7 +26,7 @@ static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 80, 80, 80, 80 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xc00)),
};
static struct platform_device scif0_device = {
@@ -44,8 +45,8 @@ static struct resource iic_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 96,
- .end = 99,
+ .start = evt2irq(0xe00),
+ .end = evt2irq(0xe60),
.flags = IORESOURCE_IRQ,
},
};
@@ -68,8 +69,8 @@ static struct resource usb_host_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 65,
- .end = 65,
+ .start = evt2irq(0xa20),
+ .end = evt2irq(0xa20),
.flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
},
};
@@ -89,7 +90,7 @@ static struct platform_device usb_host_device = {
static struct uio_info vpu_platform_data = {
.name = "VPU5",
.version = "0",
- .irq = 60,
+ .irq = evt2irq(0x980),
};
static struct resource vpu_resources[] = {
@@ -117,7 +118,7 @@ static struct platform_device vpu_device = {
static struct uio_info veu0_platform_data = {
.name = "VEU",
.version = "0",
- .irq = 54,
+ .irq = evt2irq(0x8c0),
};
static struct resource veu0_resources[] = {
@@ -145,7 +146,7 @@ static struct platform_device veu0_device = {
static struct uio_info veu1_platform_data = {
.name = "VEU",
.version = "0",
- .irq = 27,
+ .irq = evt2irq(0x560),
};
static struct resource veu1_resources[] = {
@@ -184,7 +185,7 @@ static struct resource cmt_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 104,
+ .start = evt2irq(0xf00),
.flags = IORESOURCE_IRQ,
},
};
@@ -240,7 +241,7 @@ static struct resource tmu1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 17,
+ .start = evt2irq(0x420),
.flags = IORESOURCE_IRQ,
},
};
@@ -267,7 +268,7 @@ static struct resource tmu2_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 18,
+ .start = evt2irq(0x440),
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
index 8420d4bc8bfc..0f5a21907da6 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
@@ -13,6 +13,7 @@
#include <linux/serial.h>
#include <linux/serial_sci.h>
#include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
#include <linux/uio_driver.h>
#include <linux/usb/m66592.h>
@@ -147,20 +148,20 @@ static struct resource sh7722_dmae_resources[] = {
},
{
.name = "error_irq",
- .start = 78,
- .end = 78,
+ .start = evt2irq(0xbc0),
+ .end = evt2irq(0xbc0),
.flags = IORESOURCE_IRQ,
},
{
/* IRQ for channels 0-3 */
- .start = 48,
- .end = 51,
+ .start = evt2irq(0x800),
+ .end = evt2irq(0x860),
.flags = IORESOURCE_IRQ,
},
{
/* IRQ for channels 4-5 */
- .start = 76,
- .end = 77,
+ .start = evt2irq(0xb80),
+ .end = evt2irq(0xba0),
.flags = IORESOURCE_IRQ,
},
};
@@ -182,7 +183,7 @@ static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 80, 80, 80, 80 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xc00)),
.ops = &sh7722_sci_port_ops,
.regtype = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
};
@@ -201,7 +202,7 @@ static struct plat_sci_port scif1_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 81, 81, 81, 81 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xc20)),
.ops = &sh7722_sci_port_ops,
.regtype = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
};
@@ -220,7 +221,7 @@ static struct plat_sci_port scif2_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 82, 82, 82, 82 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xc40)),
.ops = &sh7722_sci_port_ops,
.regtype = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
};
@@ -241,17 +242,17 @@ static struct resource rtc_resources[] = {
},
[1] = {
/* Period IRQ */
- .start = 45,
+ .start = evt2irq(0x7a0),
.flags = IORESOURCE_IRQ,
},
[2] = {
/* Carry IRQ */
- .start = 46,
+ .start = evt2irq(0x7c0),
.flags = IORESOURCE_IRQ,
},
[3] = {
/* Alarm IRQ */
- .start = 44,
+ .start = evt2irq(0x780),
.flags = IORESOURCE_IRQ,
},
};
@@ -275,8 +276,8 @@ static struct resource usbf_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 65,
- .end = 65,
+ .start = evt2irq(0xa20),
+ .end = evt2irq(0xa20),
.flags = IORESOURCE_IRQ,
},
};
@@ -301,8 +302,8 @@ static struct resource iic_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 96,
- .end = 99,
+ .start = evt2irq(0xe00),
+ .end = evt2irq(0xe60),
.flags = IORESOURCE_IRQ,
},
};
@@ -317,7 +318,7 @@ static struct platform_device iic_device = {
static struct uio_info vpu_platform_data = {
.name = "VPU4",
.version = "0",
- .irq = 60,
+ .irq = evt2irq(0x980),
};
static struct resource vpu_resources[] = {
@@ -345,7 +346,7 @@ static struct platform_device vpu_device = {
static struct uio_info veu_platform_data = {
.name = "VEU",
.version = "0",
- .irq = 54,
+ .irq = evt2irq(0x8c0),
};
static struct resource veu_resources[] = {
@@ -373,7 +374,7 @@ static struct platform_device veu_device = {
static struct uio_info jpu_platform_data = {
.name = "JPU",
.version = "0",
- .irq = 27,
+ .irq = evt2irq(0x560),
};
static struct resource jpu_resources[] = {
@@ -412,7 +413,7 @@ static struct resource cmt_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 104,
+ .start = evt2irq(0xf00),
.flags = IORESOURCE_IRQ,
},
};
@@ -440,7 +441,7 @@ static struct resource tmu0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 16,
+ .start = evt2irq(0x400),
.flags = IORESOURCE_IRQ,
},
};
@@ -468,7 +469,7 @@ static struct resource tmu1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 17,
+ .start = evt2irq(0x420),
.flags = IORESOURCE_IRQ,
},
};
@@ -525,7 +526,7 @@ static struct resource siu_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 108,
+ .start = evt2irq(0xf80),
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
index a188c9ea4393..28d6fd835fe0 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c
@@ -15,6 +15,7 @@
#include <linux/uio_driver.h>
#include <linux/usb/r8a66597.h>
#include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
#include <linux/io.h>
#include <asm/clock.h>
#include <asm/mmzone.h>
@@ -28,7 +29,7 @@ static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 80, 80, 80, 80 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xc00)),
.regtype = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
};
@@ -47,7 +48,7 @@ static struct plat_sci_port scif1_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 81, 81, 81, 81 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xc20)),
.regtype = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
};
@@ -66,7 +67,7 @@ static struct plat_sci_port scif2_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 82, 82, 82, 82 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xc40)),
.regtype = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
};
@@ -85,7 +86,7 @@ static struct plat_sci_port scif3_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_3,
.type = PORT_SCIFA,
- .irqs = { 56, 56, 56, 56 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x900)),
};
static struct platform_device scif3_device = {
@@ -103,7 +104,7 @@ static struct plat_sci_port scif4_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_3,
.type = PORT_SCIFA,
- .irqs = { 88, 88, 88, 88 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xd00)),
};
static struct platform_device scif4_device = {
@@ -121,7 +122,7 @@ static struct plat_sci_port scif5_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_3,
.type = PORT_SCIFA,
- .irqs = { 109, 109, 109, 109 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xfa0)),
};
static struct platform_device scif5_device = {
@@ -135,7 +136,7 @@ static struct platform_device scif5_device = {
static struct uio_info vpu_platform_data = {
.name = "VPU5",
.version = "0",
- .irq = 60,
+ .irq = evt2irq(0x980),
};
static struct resource vpu_resources[] = {
@@ -163,7 +164,7 @@ static struct platform_device vpu_device = {
static struct uio_info veu0_platform_data = {
.name = "VEU2H",
.version = "0",
- .irq = 54,
+ .irq = evt2irq(0x8c0),
};
static struct resource veu0_resources[] = {
@@ -191,7 +192,7 @@ static struct platform_device veu0_device = {
static struct uio_info veu1_platform_data = {
.name = "VEU2H",
.version = "0",
- .irq = 27,
+ .irq = evt2irq(0x560),
};
static struct resource veu1_resources[] = {
@@ -230,7 +231,7 @@ static struct resource cmt_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 104,
+ .start = evt2irq(0xf00),
.flags = IORESOURCE_IRQ,
},
};
@@ -258,7 +259,7 @@ static struct resource tmu0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 16,
+ .start = evt2irq(0x400),
.flags = IORESOURCE_IRQ,
},
};
@@ -286,7 +287,7 @@ static struct resource tmu1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 17,
+ .start = evt2irq(0x420),
.flags = IORESOURCE_IRQ,
},
};
@@ -313,7 +314,7 @@ static struct resource tmu2_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 18,
+ .start = evt2irq(0x440),
.flags = IORESOURCE_IRQ,
},
};
@@ -340,7 +341,7 @@ static struct resource tmu3_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 57,
+ .start = evt2irq(0x920),
.flags = IORESOURCE_IRQ,
},
};
@@ -367,7 +368,7 @@ static struct resource tmu4_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 58,
+ .start = evt2irq(0x940),
.flags = IORESOURCE_IRQ,
},
};
@@ -394,7 +395,7 @@ static struct resource tmu5_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 57,
+ .start = evt2irq(0x920),
.flags = IORESOURCE_IRQ,
},
};
@@ -417,17 +418,17 @@ static struct resource rtc_resources[] = {
},
[1] = {
/* Period IRQ */
- .start = 69,
+ .start = evt2irq(0xaa0),
.flags = IORESOURCE_IRQ,
},
[2] = {
/* Carry IRQ */
- .start = 70,
+ .start = evt2irq(0xac0),
.flags = IORESOURCE_IRQ,
},
[3] = {
/* Alarm IRQ */
- .start = 68,
+ .start = evt2irq(0xa80),
.flags = IORESOURCE_IRQ,
},
};
@@ -450,8 +451,8 @@ static struct resource sh7723_usb_host_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 65,
- .end = 65,
+ .start = evt2irq(0xa20),
+ .end = evt2irq(0xa20),
.flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW,
},
};
@@ -476,8 +477,8 @@ static struct resource iic_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 96,
- .end = 99,
+ .start = evt2irq(0xe00),
+ .end = evt2irq(0xe60),
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
index 4c671cfe68aa..26b74c2f9496 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c
@@ -20,6 +20,7 @@
#include <linux/uio_driver.h>
#include <linux/sh_dma.h>
#include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
#include <linux/io.h>
#include <linux/notifier.h>
@@ -215,20 +216,20 @@ static struct resource sh7724_dmae0_resources[] = {
},
{
.name = "error_irq",
- .start = 78,
- .end = 78,
+ .start = evt2irq(0xbc0),
+ .end = evt2irq(0xbc0),
.flags = IORESOURCE_IRQ,
},
{
/* IRQ for channels 0-3 */
- .start = 48,
- .end = 51,
+ .start = evt2irq(0x800),
+ .end = evt2irq(0x860),
.flags = IORESOURCE_IRQ,
},
{
/* IRQ for channels 4-5 */
- .start = 76,
- .end = 77,
+ .start = evt2irq(0xb80),
+ .end = evt2irq(0xba0),
.flags = IORESOURCE_IRQ,
},
};
@@ -249,20 +250,20 @@ static struct resource sh7724_dmae1_resources[] = {
},
{
.name = "error_irq",
- .start = 74,
- .end = 74,
+ .start = evt2irq(0xb40),
+ .end = evt2irq(0xb40),
.flags = IORESOURCE_IRQ,
},
{
/* IRQ for channels 0-3 */
- .start = 40,
- .end = 43,
+ .start = evt2irq(0x700),
+ .end = evt2irq(0x760),
.flags = IORESOURCE_IRQ,
},
{
/* IRQ for channels 4-5 */
- .start = 72,
- .end = 73,
+ .start = evt2irq(0xb00),
+ .end = evt2irq(0xb20),
.flags = IORESOURCE_IRQ,
},
};
@@ -295,7 +296,7 @@ static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 80, 80, 80, 80 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xc00)),
.regtype = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
};
@@ -314,7 +315,7 @@ static struct plat_sci_port scif1_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 81, 81, 81, 81 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xc20)),
.regtype = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
};
@@ -333,7 +334,7 @@ static struct plat_sci_port scif2_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 82, 82, 82, 82 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xc40)),
.regtype = SCIx_SH4_SCIF_NO_SCSPTR_REGTYPE,
};
@@ -352,7 +353,7 @@ static struct plat_sci_port scif3_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE,
.scbrr_algo_id = SCBRR_ALGO_3,
.type = PORT_SCIFA,
- .irqs = { 56, 56, 56, 56 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x900)),
};
static struct platform_device scif3_device = {
@@ -370,7 +371,7 @@ static struct plat_sci_port scif4_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE,
.scbrr_algo_id = SCBRR_ALGO_3,
.type = PORT_SCIFA,
- .irqs = { 88, 88, 88, 88 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xd00)),
};
static struct platform_device scif4_device = {
@@ -388,7 +389,7 @@ static struct plat_sci_port scif5_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE,
.scbrr_algo_id = SCBRR_ALGO_3,
.type = PORT_SCIFA,
- .irqs = { 109, 109, 109, 109 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xfa0)),
};
static struct platform_device scif5_device = {
@@ -408,17 +409,17 @@ static struct resource rtc_resources[] = {
},
[1] = {
/* Period IRQ */
- .start = 69,
+ .start = evt2irq(0xaa0),
.flags = IORESOURCE_IRQ,
},
[2] = {
/* Carry IRQ */
- .start = 70,
+ .start = evt2irq(0xac0),
.flags = IORESOURCE_IRQ,
},
[3] = {
/* Alarm IRQ */
- .start = 68,
+ .start = evt2irq(0xa80),
.flags = IORESOURCE_IRQ,
},
};
@@ -439,8 +440,8 @@ static struct resource iic0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 96,
- .end = 99,
+ .start = evt2irq(0xe00),
+ .end = evt2irq(0xe60),
.flags = IORESOURCE_IRQ,
},
};
@@ -461,8 +462,8 @@ static struct resource iic1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 92,
- .end = 95,
+ .start = evt2irq(0xd80),
+ .end = evt2irq(0xde0),
.flags = IORESOURCE_IRQ,
},
};
@@ -478,7 +479,7 @@ static struct platform_device iic1_device = {
static struct uio_info vpu_platform_data = {
.name = "VPU5F",
.version = "0",
- .irq = 60,
+ .irq = evt2irq(0x980),
};
static struct resource vpu_resources[] = {
@@ -507,7 +508,7 @@ static struct platform_device vpu_device = {
static struct uio_info veu0_platform_data = {
.name = "VEU3F0",
.version = "0",
- .irq = 83,
+ .irq = evt2irq(0xc60),
};
static struct resource veu0_resources[] = {
@@ -536,7 +537,7 @@ static struct platform_device veu0_device = {
static struct uio_info veu1_platform_data = {
.name = "VEU3F1",
.version = "0",
- .irq = 54,
+ .irq = evt2irq(0x8c0),
};
static struct resource veu1_resources[] = {
@@ -633,7 +634,7 @@ static struct resource cmt_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 104,
+ .start = evt2irq(0xf00),
.flags = IORESOURCE_IRQ,
},
};
@@ -661,7 +662,7 @@ static struct resource tmu0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 16,
+ .start = evt2irq(0x400),
.flags = IORESOURCE_IRQ,
},
};
@@ -689,7 +690,7 @@ static struct resource tmu1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 17,
+ .start = evt2irq(0x420),
.flags = IORESOURCE_IRQ,
},
};
@@ -716,7 +717,7 @@ static struct resource tmu2_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 18,
+ .start = evt2irq(0x440),
.flags = IORESOURCE_IRQ,
},
};
@@ -744,7 +745,7 @@ static struct resource tmu3_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 57,
+ .start = evt2irq(0x920),
.flags = IORESOURCE_IRQ,
},
};
@@ -771,7 +772,7 @@ static struct resource tmu4_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 58,
+ .start = evt2irq(0x940),
.flags = IORESOURCE_IRQ,
},
};
@@ -798,7 +799,7 @@ static struct resource tmu5_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 57,
+ .start = evt2irq(0x920),
.flags = IORESOURCE_IRQ,
},
};
@@ -817,7 +818,7 @@ static struct platform_device tmu5_device = {
static struct uio_info jpu_platform_data = {
.name = "JPU",
.version = "0",
- .irq = 27,
+ .irq = evt2irq(0x560),
};
static struct resource jpu_resources[] = {
@@ -846,7 +847,7 @@ static struct platform_device jpu_device = {
static struct uio_info spu0_platform_data = {
.name = "SPU2DSP0",
.version = "0",
- .irq = 86,
+ .irq = evt2irq(0xcc0),
};
static struct resource spu0_resources[] = {
@@ -875,7 +876,7 @@ static struct platform_device spu0_device = {
static struct uio_info spu1_platform_data = {
.name = "SPU2DSP1",
.version = "0",
- .irq = 87,
+ .irq = evt2irq(0xce0),
};
static struct resource spu1_resources[] = {
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7734.c b/arch/sh/kernel/cpu/sh4a/setup-sh7734.c
new file mode 100644
index 000000000000..f799971d453c
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7734.c
@@ -0,0 +1,800 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/setup-sh7734.c
+
+ * SH7734 Setup
+ *
+ * Copyright (C) 2011,2012 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
+ * Copyright (C) 2011,2012 Renesas Solutions Corp.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/serial_sci.h>
+#include <linux/sh_timer.h>
+#include <linux/io.h>
+#include <asm/clock.h>
+#include <asm/irq.h>
+#include <cpu/sh7734.h>
+
+/* SCIF */
+static struct plat_sci_port scif0_platform_data = {
+ .mapbase = 0xFFE40000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
+ .scbrr_algo_id = SCBRR_ALGO_2,
+ .type = PORT_SCIF,
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x8C0)),
+ .regtype = SCIx_SH4_SCIF_REGTYPE,
+};
+
+static struct platform_device scif0_device = {
+ .name = "sh-sci",
+ .id = 0,
+ .dev = {
+ .platform_data = &scif0_platform_data,
+ },
+};
+
+static struct plat_sci_port scif1_platform_data = {
+ .mapbase = 0xFFE41000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
+ .scbrr_algo_id = SCBRR_ALGO_2,
+ .type = PORT_SCIF,
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x8E0)),
+ .regtype = SCIx_SH4_SCIF_REGTYPE,
+};
+
+static struct platform_device scif1_device = {
+ .name = "sh-sci",
+ .id = 1,
+ .dev = {
+ .platform_data = &scif1_platform_data,
+ },
+};
+
+static struct plat_sci_port scif2_platform_data = {
+ .mapbase = 0xFFE42000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
+ .scbrr_algo_id = SCBRR_ALGO_2,
+ .type = PORT_SCIF,
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x900)),
+ .regtype = SCIx_SH4_SCIF_REGTYPE,
+};
+
+static struct platform_device scif2_device = {
+ .name = "sh-sci",
+ .id = 2,
+ .dev = {
+ .platform_data = &scif2_platform_data,
+ },
+};
+
+static struct plat_sci_port scif3_platform_data = {
+ .mapbase = 0xFFE43000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
+ .scbrr_algo_id = SCBRR_ALGO_2,
+ .type = PORT_SCIF,
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x920)),
+ .regtype = SCIx_SH4_SCIF_REGTYPE,
+};
+
+static struct platform_device scif3_device = {
+ .name = "sh-sci",
+ .id = 3,
+ .dev = {
+ .platform_data = &scif3_platform_data,
+ },
+};
+
+static struct plat_sci_port scif4_platform_data = {
+ .mapbase = 0xFFE44000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
+ .scbrr_algo_id = SCBRR_ALGO_2,
+ .type = PORT_SCIF,
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x940)),
+ .regtype = SCIx_SH4_SCIF_REGTYPE,
+};
+
+static struct platform_device scif4_device = {
+ .name = "sh-sci",
+ .id = 4,
+ .dev = {
+ .platform_data = &scif4_platform_data,
+ },
+};
+
+static struct plat_sci_port scif5_platform_data = {
+ .mapbase = 0xFFE43000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
+ .scbrr_algo_id = SCBRR_ALGO_2,
+ .type = PORT_SCIF,
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x960)),
+ .regtype = SCIx_SH4_SCIF_REGTYPE,
+};
+
+static struct platform_device scif5_device = {
+ .name = "sh-sci",
+ .id = 5,
+ .dev = {
+ .platform_data = &scif5_platform_data,
+ },
+};
+
+/* RTC */
+static struct resource rtc_resources[] = {
+ [0] = {
+ .name = "rtc",
+ .start = 0xFFFC5000,
+ .end = 0xFFFC5000 + 0x26 - 1,
+ .flags = IORESOURCE_IO,
+ },
+ [1] = {
+ .start = evt2irq(0xC00),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device rtc_device = {
+ .name = "sh-rtc",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(rtc_resources),
+ .resource = rtc_resources,
+};
+
+/* I2C 0 */
+static struct resource i2c0_resources[] = {
+ [0] = {
+ .name = "IIC0",
+ .start = 0xFFC70000,
+ .end = 0xFFC7000A - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = evt2irq(0x860),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device i2c0_device = {
+ .name = "i2c-sh7734",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(i2c0_resources),
+ .resource = i2c0_resources,
+};
+
+/* TMU */
+static struct sh_timer_config tmu0_platform_data = {
+ .channel_offset = 0x04,
+ .timer_bit = 0,
+ .clockevent_rating = 200,
+};
+
+static struct resource tmu0_resources[] = {
+ [0] = {
+ .start = 0xFFD80008,
+ .end = 0xFFD80014 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = evt2irq(0x400),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device tmu0_device = {
+ .name = "sh_tmu",
+ .id = 0,
+ .dev = {
+ .platform_data = &tmu0_platform_data,
+ },
+ .resource = tmu0_resources,
+ .num_resources = ARRAY_SIZE(tmu0_resources),
+};
+
+static struct sh_timer_config tmu1_platform_data = {
+ .channel_offset = 0x10,
+ .timer_bit = 1,
+ .clocksource_rating = 200,
+};
+
+static struct resource tmu1_resources[] = {
+ [0] = {
+ .start = 0xFFD80014,
+ .end = 0xFFD80020 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = evt2irq(0x420),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device tmu1_device = {
+ .name = "sh_tmu",
+ .id = 1,
+ .dev = {
+ .platform_data = &tmu1_platform_data,
+ },
+ .resource = tmu1_resources,
+ .num_resources = ARRAY_SIZE(tmu1_resources),
+};
+
+static struct sh_timer_config tmu2_platform_data = {
+ .channel_offset = 0x1c,
+ .timer_bit = 2,
+};
+
+static struct resource tmu2_resources[] = {
+ [0] = {
+ .start = 0xFFD80020,
+ .end = 0xFFD80030 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = evt2irq(0x440),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device tmu2_device = {
+ .name = "sh_tmu",
+ .id = 2,
+ .dev = {
+ .platform_data = &tmu2_platform_data,
+ },
+ .resource = tmu2_resources,
+ .num_resources = ARRAY_SIZE(tmu2_resources),
+};
+
+
+static struct sh_timer_config tmu3_platform_data = {
+ .channel_offset = 0x04,
+ .timer_bit = 0,
+};
+
+static struct resource tmu3_resources[] = {
+ [0] = {
+ .start = 0xFFD81008,
+ .end = 0xFFD81014 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = evt2irq(0x480),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device tmu3_device = {
+ .name = "sh_tmu",
+ .id = 3,
+ .dev = {
+ .platform_data = &tmu3_platform_data,
+ },
+ .resource = tmu3_resources,
+ .num_resources = ARRAY_SIZE(tmu3_resources),
+};
+
+static struct sh_timer_config tmu4_platform_data = {
+ .channel_offset = 0x10,
+ .timer_bit = 1,
+};
+
+static struct resource tmu4_resources[] = {
+ [0] = {
+ .start = 0xFFD81014,
+ .end = 0xFFD81020 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = evt2irq(0x4A0),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device tmu4_device = {
+ .name = "sh_tmu",
+ .id = 4,
+ .dev = {
+ .platform_data = &tmu4_platform_data,
+ },
+ .resource = tmu4_resources,
+ .num_resources = ARRAY_SIZE(tmu4_resources),
+};
+
+static struct sh_timer_config tmu5_platform_data = {
+ .channel_offset = 0x1c,
+ .timer_bit = 2,
+};
+
+static struct resource tmu5_resources[] = {
+ [0] = {
+ .start = 0xFFD81020,
+ .end = 0xFFD81030 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = evt2irq(0x4C0),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device tmu5_device = {
+ .name = "sh_tmu",
+ .id = 5,
+ .dev = {
+ .platform_data = &tmu5_platform_data,
+ },
+ .resource = tmu5_resources,
+ .num_resources = ARRAY_SIZE(tmu5_resources),
+};
+
+static struct sh_timer_config tmu6_platform_data = {
+ .channel_offset = 0x4,
+ .timer_bit = 0,
+};
+
+static struct resource tmu6_resources[] = {
+ [0] = {
+ .start = 0xFFD82008,
+ .end = 0xFFD82014 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = evt2irq(0x500),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device tmu6_device = {
+ .name = "sh_tmu",
+ .id = 6,
+ .dev = {
+ .platform_data = &tmu6_platform_data,
+ },
+ .resource = tmu6_resources,
+ .num_resources = ARRAY_SIZE(tmu6_resources),
+};
+
+static struct sh_timer_config tmu7_platform_data = {
+ .channel_offset = 0x10,
+ .timer_bit = 1,
+};
+
+static struct resource tmu7_resources[] = {
+ [0] = {
+ .start = 0xFFD82014,
+ .end = 0xFFD82020 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = evt2irq(0x520),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device tmu7_device = {
+ .name = "sh_tmu",
+ .id = 7,
+ .dev = {
+ .platform_data = &tmu7_platform_data,
+ },
+ .resource = tmu7_resources,
+ .num_resources = ARRAY_SIZE(tmu7_resources),
+};
+
+static struct sh_timer_config tmu8_platform_data = {
+ .channel_offset = 0x1c,
+ .timer_bit = 2,
+};
+
+static struct resource tmu8_resources[] = {
+ [0] = {
+ .start = 0xFFD82020,
+ .end = 0xFFD82030 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = evt2irq(0x540),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device tmu8_device = {
+ .name = "sh_tmu",
+ .id = 8,
+ .dev = {
+ .platform_data = &tmu8_platform_data,
+ },
+ .resource = tmu8_resources,
+ .num_resources = ARRAY_SIZE(tmu8_resources),
+};
+
+static struct platform_device *sh7734_devices[] __initdata = {
+ &scif0_device,
+ &scif1_device,
+ &scif2_device,
+ &scif3_device,
+ &scif4_device,
+ &scif5_device,
+ &tmu0_device,
+ &tmu1_device,
+ &tmu2_device,
+ &tmu3_device,
+ &tmu4_device,
+ &tmu5_device,
+ &tmu6_device,
+ &tmu7_device,
+ &tmu8_device,
+ &rtc_device,
+};
+
+static struct platform_device *sh7734_early_devices[] __initdata = {
+ &scif0_device,
+ &scif1_device,
+ &scif2_device,
+ &scif3_device,
+ &scif4_device,
+ &scif5_device,
+ &tmu0_device,
+ &tmu1_device,
+ &tmu2_device,
+ &tmu3_device,
+ &tmu4_device,
+ &tmu5_device,
+ &tmu6_device,
+ &tmu7_device,
+ &tmu8_device,
+};
+
+void __init plat_early_device_setup(void)
+{
+ early_platform_add_devices(sh7734_early_devices,
+ ARRAY_SIZE(sh7734_early_devices));
+}
+
+#define GROUP 0
+enum {
+ UNUSED = 0,
+
+ /* interrupt sources */
+
+ IRL0_LLLL, IRL0_LLLH, IRL0_LLHL, IRL0_LLHH,
+ IRL0_LHLL, IRL0_LHLH, IRL0_LHHL, IRL0_LHHH,
+ IRL0_HLLL, IRL0_HLLH, IRL0_HLHL, IRL0_HLHH,
+ IRL0_HHLL, IRL0_HHLH, IRL0_HHHL,
+
+ IRQ0, IRQ1, IRQ2, IRQ3,
+ DU,
+ TMU00, TMU10, TMU20, TMU21,
+ TMU30, TMU40, TMU50, TMU51,
+ TMU60, TMU70, TMU80,
+ RESET_WDT,
+ USB,
+ HUDI,
+ SHDMAC,
+ SSI0, SSI1, SSI2, SSI3,
+ VIN0,
+ RGPVG,
+ _2DG,
+ MMC,
+ HSPI,
+ LBSCATA,
+ I2C0,
+ RCAN0,
+ MIMLB,
+ SCIF0, SCIF1, SCIF2, SCIF3, SCIF4, SCIF5,
+ LBSCDMAC0, LBSCDMAC1, LBSCDMAC2,
+ RCAN1,
+ SDHI0, SDHI1,
+ IEBUS,
+ HPBDMAC0_3, HPBDMAC4_10, HPBDMAC11_18, HPBDMAC19_22, HPBDMAC23_25_27_28,
+ RTC,
+ VIN1,
+ LCDC,
+ SRC0, SRC1,
+ GETHER,
+ SDHI2,
+ GPIO0_3, GPIO4_5,
+ STIF0, STIF1,
+ ADMAC,
+ HIF,
+ FLCTL,
+ ADC,
+ MTU2,
+ RSPI,
+ QSPI,
+ HSCIF,
+ VEU3F_VE3,
+
+ /* Group */
+ /* Mask */
+ STIF_M,
+ GPIO_M,
+ HPBDMAC_M,
+ LBSCDMAC_M,
+ RCAN_M,
+ SRC_M,
+ SCIF_M,
+ LCDC_M,
+ _2DG_M,
+ VIN_M,
+ TMU_3_M,
+ TMU_0_M,
+
+ /* Priority */
+ RCAN_P,
+ LBSCDMAC_P,
+
+ /* Common */
+ SDHI,
+ SSI,
+ SPI,
+};
+
+static struct intc_vect vectors[] __initdata = {
+ INTC_VECT(DU, 0x3E0),
+ INTC_VECT(TMU00, 0x400),
+ INTC_VECT(TMU10, 0x420),
+ INTC_VECT(TMU20, 0x440),
+ INTC_VECT(TMU30, 0x480),
+ INTC_VECT(TMU40, 0x4A0),
+ INTC_VECT(TMU50, 0x4C0),
+ INTC_VECT(TMU51, 0x4E0),
+ INTC_VECT(TMU60, 0x500),
+ INTC_VECT(TMU70, 0x520),
+ INTC_VECT(TMU80, 0x540),
+ INTC_VECT(RESET_WDT, 0x560),
+ INTC_VECT(USB, 0x580),
+ INTC_VECT(HUDI, 0x600),
+ INTC_VECT(SHDMAC, 0x620),
+ INTC_VECT(SSI0, 0x6C0),
+ INTC_VECT(SSI1, 0x6E0),
+ INTC_VECT(SSI2, 0x700),
+ INTC_VECT(SSI3, 0x720),
+ INTC_VECT(VIN0, 0x740),
+ INTC_VECT(RGPVG, 0x760),
+ INTC_VECT(_2DG, 0x780),
+ INTC_VECT(MMC, 0x7A0),
+ INTC_VECT(HSPI, 0x7E0),
+ INTC_VECT(LBSCATA, 0x840),
+ INTC_VECT(I2C0, 0x860),
+ INTC_VECT(RCAN0, 0x880),
+ INTC_VECT(SCIF0, 0x8A0),
+ INTC_VECT(SCIF1, 0x8C0),
+ INTC_VECT(SCIF2, 0x900),
+ INTC_VECT(SCIF3, 0x920),
+ INTC_VECT(SCIF4, 0x940),
+ INTC_VECT(SCIF5, 0x960),
+ INTC_VECT(LBSCDMAC0, 0x9E0),
+ INTC_VECT(LBSCDMAC1, 0xA00),
+ INTC_VECT(LBSCDMAC2, 0xA20),
+ INTC_VECT(RCAN1, 0xA60),
+ INTC_VECT(SDHI0, 0xAE0),
+ INTC_VECT(SDHI1, 0xB00),
+ INTC_VECT(IEBUS, 0xB20),
+ INTC_VECT(HPBDMAC0_3, 0xB60),
+ INTC_VECT(HPBDMAC4_10, 0xB80),
+ INTC_VECT(HPBDMAC11_18, 0xBA0),
+ INTC_VECT(HPBDMAC19_22, 0xBC0),
+ INTC_VECT(HPBDMAC23_25_27_28, 0xBE0),
+ INTC_VECT(RTC, 0xC00),
+ INTC_VECT(VIN1, 0xC20),
+ INTC_VECT(LCDC, 0xC40),
+ INTC_VECT(SRC0, 0xC60),
+ INTC_VECT(SRC1, 0xC80),
+ INTC_VECT(GETHER, 0xCA0),
+ INTC_VECT(SDHI2, 0xCC0),
+ INTC_VECT(GPIO0_3, 0xCE0),
+ INTC_VECT(GPIO4_5, 0xD00),
+ INTC_VECT(STIF0, 0xD20),
+ INTC_VECT(STIF1, 0xD40),
+ INTC_VECT(ADMAC, 0xDA0),
+ INTC_VECT(HIF, 0xDC0),
+ INTC_VECT(FLCTL, 0xDE0),
+ INTC_VECT(ADC, 0xE00),
+ INTC_VECT(MTU2, 0xE20),
+ INTC_VECT(RSPI, 0xE40),
+ INTC_VECT(QSPI, 0xE60),
+ INTC_VECT(HSCIF, 0xFC0),
+ INTC_VECT(VEU3F_VE3, 0xF40),
+};
+
+static struct intc_group groups[] __initdata = {
+ /* Common */
+ INTC_GROUP(SDHI, SDHI0, SDHI1, SDHI2),
+ INTC_GROUP(SPI, HSPI, RSPI, QSPI),
+ INTC_GROUP(SSI, SSI0, SSI1, SSI2, SSI3),
+
+ /* Mask group */
+ INTC_GROUP(STIF_M, STIF0, STIF1), /* 22 */
+ INTC_GROUP(GPIO_M, GPIO0_3, GPIO4_5), /* 21 */
+ INTC_GROUP(HPBDMAC_M, HPBDMAC0_3, HPBDMAC4_10, HPBDMAC11_18,
+ HPBDMAC19_22, HPBDMAC23_25_27_28), /* 19 */
+ INTC_GROUP(LBSCDMAC_M, LBSCDMAC0, LBSCDMAC1, LBSCDMAC2), /* 18 */
+ INTC_GROUP(RCAN_M, RCAN0, RCAN1, IEBUS), /* 17 */
+ INTC_GROUP(SRC_M, SRC0, SRC1), /* 16 */
+ INTC_GROUP(SCIF_M, SCIF0, SCIF1, SCIF2, SCIF3, SCIF4, SCIF5,
+ HSCIF), /* 14 */
+ INTC_GROUP(LCDC_M, LCDC, MIMLB), /* 13 */
+ INTC_GROUP(_2DG_M, _2DG, RGPVG), /* 12 */
+ INTC_GROUP(VIN_M, VIN0, VIN1), /* 10 */
+ INTC_GROUP(TMU_3_M, TMU30, TMU40, TMU50, TMU51,
+ TMU60, TMU60, TMU70, TMU80), /* 2 */
+ INTC_GROUP(TMU_0_M, TMU00, TMU10, TMU20, TMU21), /* 1 */
+
+ /* Priority group*/
+ INTC_GROUP(RCAN_P, RCAN0, RCAN1), /* INT2PRI5 */
+ INTC_GROUP(LBSCDMAC_P, LBSCDMAC0, LBSCDMAC1), /* INT2PRI5 */
+};
+
+static struct intc_mask_reg mask_registers[] __initdata = {
+ { 0xFF804040, 0xFF804044, 32, /* INT2MSKRG / INT2MSKCR */
+ { 0,
+ VEU3F_VE3,
+ SDHI, /* SDHI 0-2 */
+ ADMAC,
+ FLCTL,
+ RESET_WDT,
+ HIF,
+ ADC,
+ MTU2,
+ STIF_M, /* STIF 0,1 */
+ GPIO_M, /* GPIO 0-5*/
+ GETHER,
+ HPBDMAC_M, /* HPBDMAC 0_3 - 23_25_27_28 */
+ LBSCDMAC_M, /* LBSCDMAC 0 - 2 */
+ RCAN_M, /* RCAN, IEBUS */
+ SRC_M, /* SRC 0,1 */
+ LBSCATA,
+ SCIF_M, /* SCIF 0-5, HSCIF */
+ LCDC_M, /* LCDC, MIMLB */
+ _2DG_M, /* 2DG, RGPVG */
+ SPI, /* HSPI, RSPI, QSPI */
+ VIN_M, /* VIN0, 1 */
+ SSI, /* SSI 0-3 */
+ USB,
+ SHDMAC,
+ HUDI,
+ MMC,
+ RTC,
+ I2C0, /* I2C */ /* I2C 0, 1*/
+ TMU_3_M, /* TMU30 - TMU80 */
+ TMU_0_M, /* TMU00 - TMU21 */
+ DU } },
+};
+
+static struct intc_prio_reg prio_registers[] __initdata = {
+ { 0xFF804000, 0, 32, 8, /* INT2PRI0 */
+ { DU, TMU00, TMU10, TMU20 } },
+ { 0xFF804004, 0, 32, 8, /* INT2PRI1 */
+ { TMU30, TMU60, RTC, SDHI } },
+ { 0xFF804008, 0, 32, 8, /* INT2PRI2 */
+ { HUDI, SHDMAC, USB, SSI } },
+ { 0xFF80400C, 0, 32, 8, /* INT2PRI3 */
+ { VIN0, SPI, _2DG, LBSCATA } },
+ { 0xFF804010, 0, 32, 8, /* INT2PRI4 */
+ { SCIF0, SCIF3, HSCIF, LCDC } },
+ { 0xFF804014, 0, 32, 8, /* INT2PRI5 */
+ { RCAN_P, LBSCDMAC_P, LBSCDMAC2, MMC } },
+ { 0xFF804018, 0, 32, 8, /* INT2PRI6 */
+ { HPBDMAC0_3, HPBDMAC4_10, HPBDMAC11_18, HPBDMAC19_22 } },
+ { 0xFF80401C, 0, 32, 8, /* INT2PRI7 */
+ { HPBDMAC23_25_27_28, I2C0, SRC0, SRC1 } },
+ { 0xFF804020, 0, 32, 8, /* INT2PRI8 */
+ { 0 /* ADIF */, VIN1, RESET_WDT, HIF } },
+ { 0xFF804024, 0, 32, 8, /* INT2PRI9 */
+ { ADMAC, FLCTL, GPIO0_3, GPIO4_5 } },
+ { 0xFF804028, 0, 32, 8, /* INT2PRI10 */
+ { STIF0, STIF1, VEU3F_VE3, GETHER } },
+ { 0xFF80402C, 0, 32, 8, /* INT2PRI11 */
+ { MTU2, RGPVG, MIMLB, IEBUS } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7734", vectors, groups,
+ mask_registers, prio_registers, NULL);
+
+/* Support for external interrupt pins in IRQ mode */
+
+static struct intc_vect irq3210_vectors[] __initdata = {
+ INTC_VECT(IRQ0, 0x240), INTC_VECT(IRQ1, 0x280),
+ INTC_VECT(IRQ2, 0x2C0), INTC_VECT(IRQ3, 0x300),
+};
+
+static struct intc_sense_reg irq3210_sense_registers[] __initdata = {
+ { 0xFF80201C, 32, 2, /* ICR1 */
+ { IRQ0, IRQ1, IRQ2, IRQ3, } },
+};
+
+static struct intc_mask_reg irq3210_ack_registers[] __initdata = {
+ { 0xFF802024, 0, 32, /* INTREQ */
+ { IRQ0, IRQ1, IRQ2, IRQ3, } },
+};
+
+static struct intc_mask_reg irq3210_mask_registers[] __initdata = {
+ { 0xFF802044, 0xFF802064, 32, /* INTMSK0 / INTMSKCLR0 */
+ { IRQ0, IRQ1, IRQ2, IRQ3, } },
+};
+
+static struct intc_prio_reg irq3210_prio_registers[] __initdata = {
+ { 0xFF802010, 0, 32, 4, /* INTPRI */
+ { IRQ0, IRQ1, IRQ2, IRQ3, } },
+};
+
+static DECLARE_INTC_DESC_ACK(intc_desc_irq3210, "sh7734-irq3210",
+ irq3210_vectors, NULL,
+ irq3210_mask_registers, irq3210_prio_registers,
+ irq3210_sense_registers, irq3210_ack_registers);
+
+/* External interrupt pins in IRL mode */
+
+static struct intc_vect vectors_irl3210[] __initdata = {
+ INTC_VECT(IRL0_LLLL, 0x200), INTC_VECT(IRL0_LLLH, 0x220),
+ INTC_VECT(IRL0_LLHL, 0x240), INTC_VECT(IRL0_LLHH, 0x260),
+ INTC_VECT(IRL0_LHLL, 0x280), INTC_VECT(IRL0_LHLH, 0x2a0),
+ INTC_VECT(IRL0_LHHL, 0x2c0), INTC_VECT(IRL0_LHHH, 0x2e0),
+ INTC_VECT(IRL0_HLLL, 0x300), INTC_VECT(IRL0_HLLH, 0x320),
+ INTC_VECT(IRL0_HLHL, 0x340), INTC_VECT(IRL0_HLHH, 0x360),
+ INTC_VECT(IRL0_HHLL, 0x380), INTC_VECT(IRL0_HHLH, 0x3a0),
+ INTC_VECT(IRL0_HHHL, 0x3c0),
+};
+
+static DECLARE_INTC_DESC(intc_desc_irl3210, "sh7734-irl3210",
+ vectors_irl3210, NULL, mask_registers, NULL, NULL);
+
+#define INTC_ICR0 0xFF802000
+#define INTC_INTMSK0 0xFF802044
+#define INTC_INTMSK1 0xFF802048
+#define INTC_INTMSKCLR0 0xFF802064
+#define INTC_INTMSKCLR1 0xFF802068
+
+void __init plat_irq_setup(void)
+{
+ /* disable IRQ3-0 */
+ __raw_writel(0xF0000000, INTC_INTMSK0);
+
+ /* disable IRL3-0 */
+ __raw_writel(0x80000000, INTC_INTMSK1);
+
+ /* select IRL mode for IRL3-0 */
+ __raw_writel(__raw_readl(INTC_ICR0) & ~0x00800000, INTC_ICR0);
+
+ /* disable holding function, ie enable "SH-4 Mode (LVLMODE)" */
+ __raw_writel(__raw_readl(INTC_ICR0) | 0x00200000, INTC_ICR0);
+
+ register_intc_controller(&intc_desc);
+}
+
+void __init plat_irq_setup_pins(int mode)
+{
+ switch (mode) {
+ case IRQ_MODE_IRQ3210:
+ /* select IRQ mode for IRL3-0 */
+ __raw_writel(__raw_readl(INTC_ICR0) | 0x00800000, INTC_ICR0);
+ register_intc_controller(&intc_desc_irq3210);
+ break;
+ case IRQ_MODE_IRL3210:
+ /* enable IRL0-3 but don't provide any masking */
+ __raw_writel(0x80000000, INTC_INTMSKCLR1);
+ __raw_writel(0xf0000000, INTC_INTMSKCLR0);
+ break;
+ case IRQ_MODE_IRL3210_MASK:
+ /* enable IRL0-3 and mask using cpu intc controller */
+ __raw_writel(0x80000000, INTC_INTMSKCLR0);
+ register_intc_controller(&intc_desc_irl3210);
+ break;
+ default:
+ BUG();
+ }
+}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
index c8836cffa216..a7708425afa9 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
@@ -18,7 +18,7 @@
#include <linux/dma-mapping.h>
#include <linux/sh_timer.h>
#include <linux/sh_dma.h>
-
+#include <linux/sh_intc.h>
#include <cpu/dma-register.h>
#include <cpu/sh7757.h>
@@ -28,7 +28,7 @@ static struct plat_sci_port scif2_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 40, 40, 40, 40 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x700)),
};
static struct platform_device scif2_device = {
@@ -45,7 +45,7 @@ static struct plat_sci_port scif3_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 76, 76, 76, 76 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xb80)),
};
static struct platform_device scif3_device = {
@@ -62,7 +62,7 @@ static struct plat_sci_port scif4_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 104, 104, 104, 104 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xF00)),
};
static struct platform_device scif4_device = {
@@ -86,7 +86,7 @@ static struct resource tmu0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 28,
+ .start = evt2irq(0x580),
.flags = IORESOURCE_IRQ,
},
};
@@ -114,7 +114,7 @@ static struct resource tmu1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 29,
+ .start = evt2irq(0x5a0),
.flags = IORESOURCE_IRQ,
},
};
@@ -136,7 +136,7 @@ static struct resource spi0_resources[] = {
.flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
},
[1] = {
- .start = 86,
+ .start = evt2irq(0xcc0),
.flags = IORESOURCE_IRQ,
},
};
@@ -466,8 +466,8 @@ static struct resource sh7757_dmae0_resources[] = {
},
{
.name = "error_irq",
- .start = 34,
- .end = 34,
+ .start = evt2irq(0x640),
+ .end = evt2irq(0x640),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
},
};
@@ -488,56 +488,56 @@ static struct resource sh7757_dmae1_resources[] = {
},
{
.name = "error_irq",
- .start = 34,
- .end = 34,
+ .start = evt2irq(0x640),
+ .end = evt2irq(0x640),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
},
{
/* IRQ for channels 4 */
- .start = 46,
- .end = 46,
+ .start = evt2irq(0x7c0),
+ .end = evt2irq(0x7c0),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
},
{
/* IRQ for channels 5 */
- .start = 46,
- .end = 46,
+ .start = evt2irq(0x7c0),
+ .end = evt2irq(0x7c0),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
},
{
/* IRQ for channels 6 */
- .start = 88,
- .end = 88,
+ .start = evt2irq(0xd00),
+ .end = evt2irq(0xd00),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
},
{
/* IRQ for channels 7 */
- .start = 88,
- .end = 88,
+ .start = evt2irq(0xd00),
+ .end = evt2irq(0xd00),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
},
{
/* IRQ for channels 8 */
- .start = 88,
- .end = 88,
+ .start = evt2irq(0xd00),
+ .end = evt2irq(0xd00),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
},
{
/* IRQ for channels 9 */
- .start = 88,
- .end = 88,
+ .start = evt2irq(0xd00),
+ .end = evt2irq(0xd00),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
},
{
/* IRQ for channels 10 */
- .start = 88,
- .end = 88,
+ .start = evt2irq(0xd00),
+ .end = evt2irq(0xd00),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
},
{
/* IRQ for channels 11 */
- .start = 88,
- .end = 88,
+ .start = evt2irq(0xd00),
+ .end = evt2irq(0xd00),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
},
};
@@ -558,20 +558,20 @@ static struct resource sh7757_dmae2_resources[] = {
},
{
.name = "error_irq",
- .start = 323,
- .end = 323,
+ .start = evt2irq(0x2a60),
+ .end = evt2irq(0x2a60),
.flags = IORESOURCE_IRQ,
},
{
/* IRQ for channels 12 to 16 */
- .start = 272,
- .end = 276,
+ .start = evt2irq(0x2400),
+ .end = evt2irq(0x2480),
.flags = IORESOURCE_IRQ,
},
{
/* IRQ for channel 17 */
- .start = 279,
- .end = 279,
+ .start = evt2irq(0x24e0),
+ .end = evt2irq(0x24e0),
.flags = IORESOURCE_IRQ,
},
};
@@ -592,20 +592,20 @@ static struct resource sh7757_dmae3_resources[] = {
},
{
.name = "error_irq",
- .start = 324,
- .end = 324,
+ .start = evt2irq(0x2a80),
+ .end = evt2irq(0x2a80),
.flags = IORESOURCE_IRQ,
},
{
/* IRQ for channels 18 to 22 */
- .start = 280,
- .end = 284,
+ .start = evt2irq(0x2500),
+ .end = evt2irq(0x2580),
.flags = IORESOURCE_IRQ,
},
{
/* IRQ for channel 23 */
- .start = 288,
- .end = 288,
+ .start = evt2irq(0x2600),
+ .end = evt2irq(0x2600),
.flags = IORESOURCE_IRQ,
},
};
@@ -668,7 +668,7 @@ static struct resource spi1_resources[] = {
.flags = IORESOURCE_MEM | IORESOURCE_MEM_8BIT,
},
{
- .start = 54,
+ .start = evt2irq(0x8c0),
.flags = IORESOURCE_IRQ,
},
};
@@ -687,7 +687,7 @@ static struct resource rspi_resources[] = {
.flags = IORESOURCE_MEM,
},
{
- .start = 220,
+ .start = evt2irq(0x1d80),
.flags = IORESOURCE_IRQ,
},
};
@@ -706,8 +706,8 @@ static struct resource usb_ehci_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 57,
- .end = 57,
+ .start = evt2irq(0x920),
+ .end = evt2irq(0x920),
.flags = IORESOURCE_IRQ,
},
};
@@ -730,8 +730,8 @@ static struct resource usb_ohci_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 57,
- .end = 57,
+ .start = evt2irq(0x920),
+ .end = evt2irq(0x920),
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7763.c b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c
index 00113515f233..bd0a8fbe610f 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7763.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7763.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
#include <linux/io.h>
#include <linux/serial_sci.h>
@@ -22,7 +23,7 @@ static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 40, 40, 40, 40 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x700)),
.regtype = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
};
@@ -40,7 +41,7 @@ static struct plat_sci_port scif1_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 76, 76, 76, 76 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xb80)),
.regtype = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
};
@@ -58,7 +59,7 @@ static struct plat_sci_port scif2_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 104, 104, 104, 104 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xf00)),
.regtype = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
};
@@ -78,7 +79,7 @@ static struct resource rtc_resources[] = {
},
[1] = {
/* Shared Period/Carry/Alarm IRQ */
- .start = 20,
+ .start = evt2irq(0x480),
.flags = IORESOURCE_IRQ,
},
};
@@ -97,13 +98,14 @@ static struct resource usb_ohci_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 83,
- .end = 83,
+ .start = evt2irq(0xc60),
+ .end = evt2irq(0xc60),
.flags = IORESOURCE_IRQ,
},
};
static u64 usb_ohci_dma_mask = 0xffffffffUL;
+
static struct platform_device usb_ohci_device = {
.name = "sh_ohci",
.id = -1,
@@ -122,8 +124,8 @@ static struct resource usbf_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 84,
- .end = 84,
+ .start = evt2irq(0xc80),
+ .end = evt2irq(0xc80),
.flags = IORESOURCE_IRQ,
},
};
@@ -152,7 +154,7 @@ static struct resource tmu0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 28,
+ .start = evt2irq(0x580),
.flags = IORESOURCE_IRQ,
},
};
@@ -180,7 +182,7 @@ static struct resource tmu1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 29,
+ .start = evt2irq(0x5a0),
.flags = IORESOURCE_IRQ,
},
};
@@ -207,7 +209,7 @@ static struct resource tmu2_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 30,
+ .start = evt2irq(0x5c0),
.flags = IORESOURCE_IRQ,
},
};
@@ -234,7 +236,7 @@ static struct resource tmu3_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 96,
+ .start = evt2irq(0xe00),
.flags = IORESOURCE_IRQ,
},
};
@@ -261,7 +263,7 @@ static struct resource tmu4_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 97,
+ .start = evt2irq(0xe20),
.flags = IORESOURCE_IRQ,
},
};
@@ -288,7 +290,7 @@ static struct resource tmu5_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 98,
+ .start = evt2irq(0xe40),
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7770.c b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c
index 2c6aa22cf5f6..256ea7a45164 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7770.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7770.c
@@ -12,6 +12,7 @@
#include <linux/serial.h>
#include <linux/serial_sci.h>
#include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
#include <linux/io.h>
static struct plat_sci_port scif0_platform_data = {
@@ -20,7 +21,7 @@ static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 61, 61, 61, 61 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x9a0)),
};
static struct platform_device scif0_device = {
@@ -37,7 +38,7 @@ static struct plat_sci_port scif1_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 62, 62, 62, 62 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x9c0)),
};
static struct platform_device scif1_device = {
@@ -54,7 +55,7 @@ static struct plat_sci_port scif2_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 63, 63, 63, 63 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x9e0)),
};
static struct platform_device scif2_device = {
@@ -71,7 +72,7 @@ static struct plat_sci_port scif3_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 64, 64, 64, 64 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xa00)),
};
static struct platform_device scif3_device = {
@@ -88,7 +89,7 @@ static struct plat_sci_port scif4_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 65, 65, 65, 65 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xa20)),
};
static struct platform_device scif4_device = {
@@ -105,7 +106,7 @@ static struct plat_sci_port scif5_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 66, 66, 66, 66 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xa40)),
};
static struct platform_device scif5_device = {
@@ -122,7 +123,7 @@ static struct plat_sci_port scif6_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 67, 67, 67, 67 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xa60)),
};
static struct platform_device scif6_device = {
@@ -139,7 +140,7 @@ static struct plat_sci_port scif7_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 68, 68, 68, 68 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xa80)),
};
static struct platform_device scif7_device = {
@@ -156,7 +157,7 @@ static struct plat_sci_port scif8_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 69, 69, 69, 69 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xaa0)),
};
static struct platform_device scif8_device = {
@@ -173,7 +174,7 @@ static struct plat_sci_port scif9_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_TOIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 70, 70, 70, 70 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xac0)),
};
static struct platform_device scif9_device = {
@@ -197,7 +198,7 @@ static struct resource tmu0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 16,
+ .start = evt2irq(0x400),
.flags = IORESOURCE_IRQ,
},
};
@@ -225,7 +226,7 @@ static struct resource tmu1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 17,
+ .start = evt2irq(0x420),
.flags = IORESOURCE_IRQ,
},
};
@@ -252,7 +253,7 @@ static struct resource tmu2_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 18,
+ .start = evt2irq(0x440),
.flags = IORESOURCE_IRQ,
},
};
@@ -279,7 +280,7 @@ static struct resource tmu3_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 19,
+ .start = evt2irq(0x460),
.flags = IORESOURCE_IRQ,
},
};
@@ -306,7 +307,7 @@ static struct resource tmu4_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 20,
+ .start = evt2irq(0x480),
.flags = IORESOURCE_IRQ,
},
};
@@ -333,7 +334,7 @@ static struct resource tmu5_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 21,
+ .start = evt2irq(0x4a0),
.flags = IORESOURCE_IRQ,
},
};
@@ -360,7 +361,7 @@ static struct resource tmu6_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 22,
+ .start = evt2irq(0x4c0),
.flags = IORESOURCE_IRQ,
},
};
@@ -387,7 +388,7 @@ static struct resource tmu7_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 23,
+ .start = evt2irq(0x4e0),
.flags = IORESOURCE_IRQ,
},
};
@@ -414,7 +415,7 @@ static struct resource tmu8_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 24,
+ .start = evt2irq(0x500),
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
index d431b0052d0c..de45b704687a 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
@@ -14,6 +14,7 @@
#include <linux/serial_sci.h>
#include <linux/sh_dma.h>
#include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
#include <cpu/dma-register.h>
static struct plat_sci_port scif0_platform_data = {
@@ -22,7 +23,7 @@ static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_1,
.type = PORT_SCIF,
- .irqs = { 40, 40, 40, 40 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x700)),
.regtype = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
};
@@ -40,7 +41,7 @@ static struct plat_sci_port scif1_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_1,
.type = PORT_SCIF,
- .irqs = { 76, 76, 76, 76 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0xb80)),
.regtype = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
};
@@ -65,7 +66,7 @@ static struct resource tmu0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 28,
+ .start = evt2irq(0x580),
.flags = IORESOURCE_IRQ,
},
};
@@ -93,7 +94,7 @@ static struct resource tmu1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 29,
+ .start = evt2irq(0x5a0),
.flags = IORESOURCE_IRQ,
},
};
@@ -120,7 +121,7 @@ static struct resource tmu2_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 30,
+ .start = evt2irq(0x5c0),
.flags = IORESOURCE_IRQ,
},
};
@@ -147,7 +148,7 @@ static struct resource tmu3_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 96,
+ .start = evt2irq(0xe00),
.flags = IORESOURCE_IRQ,
},
};
@@ -174,7 +175,7 @@ static struct resource tmu4_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 97,
+ .start = evt2irq(0xe20),
.flags = IORESOURCE_IRQ,
},
};
@@ -201,7 +202,7 @@ static struct resource tmu5_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 98,
+ .start = evt2irq(0xe40),
.flags = IORESOURCE_IRQ,
},
};
@@ -224,7 +225,7 @@ static struct resource rtc_resources[] = {
},
[1] = {
/* Shared Period/Carry/Alarm IRQ */
- .start = 20,
+ .start = evt2irq(0x480),
.flags = IORESOURCE_IRQ,
},
};
@@ -321,10 +322,13 @@ static struct resource sh7780_dmae0_resources[] = {
.flags = IORESOURCE_MEM,
},
{
- /* Real DMA error IRQ is 38, and channel IRQs are 34-37, 44-45 */
+ /*
+ * Real DMA error vector is 0x6c0, and channel
+ * vectors are 0x640-0x6a0, 0x780-0x7a0
+ */
.name = "error_irq",
- .start = 34,
- .end = 34,
+ .start = evt2irq(0x640),
+ .end = evt2irq(0x640),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
},
};
@@ -338,10 +342,13 @@ static struct resource sh7780_dmae1_resources[] = {
},
/* DMAC1 has no DMARS */
{
- /* Real DMA error IRQ is 38, and channel IRQs are 46-47, 92-95 */
+ /*
+ * Real DMA error vector is 0x6c0, and channel
+ * vectors are 0x7c0-0x7e0, 0xd80-0xde0
+ */
.name = "error_irq",
- .start = 46,
- .end = 46,
+ .start = evt2irq(0x7c0),
+ .end = evt2irq(0x7c0),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
},
};
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
index 81588ef15a6c..0968ecb962e6 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
@@ -15,6 +15,7 @@
#include <linux/mm.h>
#include <linux/sh_dma.h>
#include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
#include <asm/mmzone.h>
#include <cpu/dma-register.h>
@@ -24,7 +25,7 @@ static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_1,
.type = PORT_SCIF,
- .irqs = { 40, 40, 40, 40 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x700)),
.regtype = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
};
@@ -42,7 +43,7 @@ static struct plat_sci_port scif1_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_1,
.type = PORT_SCIF,
- .irqs = { 44, 44, 44, 44 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x780)),
.regtype = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
};
@@ -60,7 +61,7 @@ static struct plat_sci_port scif2_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_1,
.type = PORT_SCIF,
- .irqs = { 60, 60, 60, 60 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x980)),
.regtype = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
};
@@ -78,7 +79,7 @@ static struct plat_sci_port scif3_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_1,
.type = PORT_SCIF,
- .irqs = { 61, 61, 61, 61 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x9a0)),
.regtype = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
};
@@ -96,7 +97,7 @@ static struct plat_sci_port scif4_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_1,
.type = PORT_SCIF,
- .irqs = { 62, 62, 62, 62 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x9c0)),
.regtype = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
};
@@ -114,7 +115,7 @@ static struct plat_sci_port scif5_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_1,
.type = PORT_SCIF,
- .irqs = { 63, 63, 63, 63 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x9e0)),
.regtype = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
};
@@ -139,7 +140,7 @@ static struct resource tmu0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 28,
+ .start = evt2irq(0x580),
.flags = IORESOURCE_IRQ,
},
};
@@ -167,7 +168,7 @@ static struct resource tmu1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 29,
+ .start = evt2irq(0x5a0),
.flags = IORESOURCE_IRQ,
},
};
@@ -194,7 +195,7 @@ static struct resource tmu2_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 30,
+ .start = evt2irq(0x5c0),
.flags = IORESOURCE_IRQ,
},
};
@@ -221,7 +222,7 @@ static struct resource tmu3_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 96,
+ .start = evt2irq(0xe00),
.flags = IORESOURCE_IRQ,
},
};
@@ -248,7 +249,7 @@ static struct resource tmu4_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 97,
+ .start = evt2irq(0xe20),
.flags = IORESOURCE_IRQ,
},
};
@@ -275,7 +276,7 @@ static struct resource tmu5_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 98,
+ .start = evt2irq(0xe40),
.flags = IORESOURCE_IRQ,
},
};
@@ -375,10 +376,13 @@ static struct resource sh7785_dmae0_resources[] = {
.flags = IORESOURCE_MEM,
},
{
- /* Real DMA error IRQ is 39, and channel IRQs are 33-38 */
+ /*
+ * Real DMA error vector is 0x6e0, and channel
+ * vectors are 0x620-0x6c0
+ */
.name = "error_irq",
- .start = 33,
- .end = 33,
+ .start = evt2irq(0x620),
+ .end = evt2irq(0x620),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
},
};
@@ -392,10 +396,13 @@ static struct resource sh7785_dmae1_resources[] = {
},
/* DMAC1 has no DMARS */
{
- /* Real DMA error IRQ is 58, and channel IRQs are 52-57 */
+ /*
+ * Real DMA error vector is 0x940, and channel
+ * vectors are 0x880-0x920
+ */
.name = "error_irq",
- .start = 52,
- .end = 52,
+ .start = evt2irq(0x880),
+ .end = evt2irq(0x880),
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE,
},
};
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
index 599022d73b28..2e6952f87848 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7786.c
@@ -32,7 +32,10 @@ static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_1,
.type = PORT_SCIF,
- .irqs = { 40, 41, 43, 42 },
+ .irqs = { evt2irq(0x700),
+ evt2irq(0x720),
+ evt2irq(0x760),
+ evt2irq(0x740) },
.regtype = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
};
@@ -53,7 +56,7 @@ static struct plat_sci_port scif1_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_1,
.type = PORT_SCIF,
- .irqs = { 44, 44, 44, 44 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x780)),
.regtype = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
};
@@ -71,7 +74,7 @@ static struct plat_sci_port scif2_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_1,
.type = PORT_SCIF,
- .irqs = { 50, 50, 50, 50 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x840)),
.regtype = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
};
@@ -89,7 +92,7 @@ static struct plat_sci_port scif3_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_1,
.type = PORT_SCIF,
- .irqs = { 51, 51, 51, 51 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x860)),
.regtype = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
};
@@ -107,7 +110,7 @@ static struct plat_sci_port scif4_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_1,
.type = PORT_SCIF,
- .irqs = { 52, 52, 52, 52 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x880)),
.regtype = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
};
@@ -125,7 +128,7 @@ static struct plat_sci_port scif5_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE | SCSCR_CKE1,
.scbrr_algo_id = SCBRR_ALGO_1,
.type = PORT_SCIF,
- .irqs = { 53, 53, 53, 53 },
+ .irqs = SCIx_IRQ_MUXED(evt2irq(0x8a0)),
.regtype = SCIx_SH4_SCIF_FIFODATA_REGTYPE,
};
@@ -150,7 +153,7 @@ static struct resource tmu0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 16,
+ .start = evt2irq(0x400),
.flags = IORESOURCE_IRQ,
},
};
@@ -178,7 +181,7 @@ static struct resource tmu1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 17,
+ .start = evt2irq(0x420),
.flags = IORESOURCE_IRQ,
},
};
@@ -205,7 +208,7 @@ static struct resource tmu2_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 18,
+ .start = evt2irq(0x440),
.flags = IORESOURCE_IRQ,
},
};
@@ -232,7 +235,7 @@ static struct resource tmu3_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 20,
+ .start = evt2irq(0x480),
.flags = IORESOURCE_IRQ,
},
};
@@ -259,7 +262,7 @@ static struct resource tmu4_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 21,
+ .start = evt2irq(0x4a0),
.flags = IORESOURCE_IRQ,
},
};
@@ -286,7 +289,7 @@ static struct resource tmu5_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 22,
+ .start = evt2irq(0x4c0),
.flags = IORESOURCE_IRQ,
},
};
@@ -313,7 +316,7 @@ static struct resource tmu6_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 45,
+ .start = evt2irq(0x7a0),
.flags = IORESOURCE_IRQ,
},
};
@@ -340,7 +343,7 @@ static struct resource tmu7_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 45,
+ .start = evt2irq(0x7a0),
.flags = IORESOURCE_IRQ,
},
};
@@ -367,7 +370,7 @@ static struct resource tmu8_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 45,
+ .start = evt2irq(0x7a0),
.flags = IORESOURCE_IRQ,
},
};
@@ -394,7 +397,7 @@ static struct resource tmu9_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 46,
+ .start = evt2irq(0x7c0),
.flags = IORESOURCE_IRQ,
},
};
@@ -421,7 +424,7 @@ static struct resource tmu10_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 46,
+ .start = evt2irq(0x7c0),
.flags = IORESOURCE_IRQ,
},
};
@@ -448,7 +451,7 @@ static struct resource tmu11_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 46,
+ .start = evt2irq(0x7c0),
.flags = IORESOURCE_IRQ,
},
};
@@ -550,8 +553,8 @@ static struct resource usb_ehci_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 77,
- .end = 77,
+ .start = evt2irq(0xba0),
+ .end = evt2irq(0xba0),
.flags = IORESOURCE_IRQ,
},
};
@@ -574,8 +577,8 @@ static struct resource usb_ohci_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 77,
- .end = 77,
+ .start = evt2irq(0xba0),
+ .end = evt2irq(0xba0),
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
index bb208806dc1a..688f7ed1bab1 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
@@ -14,6 +14,7 @@
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/sh_timer.h>
+#include <linux/sh_intc.h>
#include <cpu/shx3.h>
#include <asm/mmzone.h>
@@ -32,7 +33,10 @@ static struct plat_sci_port scif0_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 40, 41, 43, 42 },
+ .irqs = { evt2irq(0x700),
+ evt2irq(0x720),
+ evt2irq(0x760),
+ evt2irq(0x740) },
};
static struct platform_device scif0_device = {
@@ -49,7 +53,10 @@ static struct plat_sci_port scif1_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 44, 45, 47, 46 },
+ .irqs = { evt2irq(0x780),
+ evt2irq(0x7a0),
+ evt2irq(0x7e0),
+ evt2irq(0x7c0) },
};
static struct platform_device scif1_device = {
@@ -66,7 +73,10 @@ static struct plat_sci_port scif2_platform_data = {
.scscr = SCSCR_RE | SCSCR_TE | SCSCR_REIE,
.scbrr_algo_id = SCBRR_ALGO_2,
.type = PORT_SCIF,
- .irqs = { 52, 53, 55, 54 },
+ .irqs = { evt2irq(0x880),
+ evt2irq(0x8a0),
+ evt2irq(0x8e0),
+ evt2irq(0x8c0) },
};
static struct platform_device scif2_device = {
@@ -90,7 +100,7 @@ static struct resource tmu0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 16,
+ .start = evt2irq(0x400),
.flags = IORESOURCE_IRQ,
},
};
@@ -118,7 +128,7 @@ static struct resource tmu1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 17,
+ .start = evt2irq(0x420),
.flags = IORESOURCE_IRQ,
},
};
@@ -145,7 +155,7 @@ static struct resource tmu2_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 18,
+ .start = evt2irq(0x440),
.flags = IORESOURCE_IRQ,
},
};
@@ -172,7 +182,7 @@ static struct resource tmu3_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 19,
+ .start = evt2irq(0x460),
.flags = IORESOURCE_IRQ,
},
};
@@ -199,7 +209,7 @@ static struct resource tmu4_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 20,
+ .start = evt2irq(0x480),
.flags = IORESOURCE_IRQ,
},
};
@@ -226,7 +236,7 @@ static struct resource tmu5_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 21,
+ .start = evt2irq(0x4a0),
.flags = IORESOURCE_IRQ,
},
};
@@ -484,9 +494,6 @@ void __init plat_irq_setup_pins(int mode)
void __init plat_irq_setup(void)
{
- reserve_intc_vectors(vectors_irq, ARRAY_SIZE(vectors_irq));
- reserve_intc_vectors(vectors_irl, ARRAY_SIZE(vectors_irl));
-
register_intc_controller(&intc_desc);
}
diff --git a/arch/sh/kernel/cpu/sh5/entry.S b/arch/sh/kernel/cpu/sh5/entry.S
index 6b80295dd7a4..ff1f0e6e9bec 100644
--- a/arch/sh/kernel/cpu/sh5/entry.S
+++ b/arch/sh/kernel/cpu/sh5/entry.S
@@ -335,7 +335,7 @@ tlb_miss:
/* If the fast path handler fixed the fault, just drop through quickly
to the restore code right away to return to the excepting context.
*/
- beqi/u r2, 0, tr1
+ bnei/u r2, 0, tr1
fast_tlb_miss_restore:
ld.q SP, SAVED_TR0, r2
@@ -1079,9 +1079,8 @@ restore_all:
*
* Kernel TLB fault handlers will get a slightly different interface.
* (r2) struct pt_regs *, original register's frame pointer
- * (r3) writeaccess, whether it's a store fault as opposed to load fault
- * (r4) execaccess, whether it's a ITLB fault as opposed to DTLB fault
- * (r5) Effective Address of fault
+ * (r3) page fault error code (see asm/thread_info.h)
+ * (r4) Effective Address of fault
* (LINK) return address
* (SP) = r2
*
@@ -1092,26 +1091,25 @@ restore_all:
tlb_miss_load:
or SP, ZERO, r2
or ZERO, ZERO, r3 /* Read */
- or ZERO, ZERO, r4 /* Data */
- getcon TEA, r5
+ getcon TEA, r4
pta call_do_page_fault, tr0
beq ZERO, ZERO, tr0
tlb_miss_store:
or SP, ZERO, r2
- movi 1, r3 /* Write */
- or ZERO, ZERO, r4 /* Data */
- getcon TEA, r5
+ movi FAULT_CODE_WRITE, r3 /* Write */
+ getcon TEA, r4
pta call_do_page_fault, tr0
beq ZERO, ZERO, tr0
itlb_miss_or_IRQ:
pta its_IRQ, tr0
beqi/u r4, EVENT_INTERRUPT, tr0
+
+ /* ITLB miss */
or SP, ZERO, r2
- or ZERO, ZERO, r3 /* Read */
- movi 1, r4 /* Text */
- getcon TEA, r5
+ movi FAULT_CODE_ITLB, r3
+ getcon TEA, r4
/* Fall through */
call_do_page_fault:
diff --git a/arch/sh/kernel/cpu/sh5/fpu.c b/arch/sh/kernel/cpu/sh5/fpu.c
index 4b3bb35e99f3..9f8713aa7184 100644
--- a/arch/sh/kernel/cpu/sh5/fpu.c
+++ b/arch/sh/kernel/cpu/sh5/fpu.c
@@ -107,8 +107,5 @@ asmlinkage void do_fpu_error(unsigned long ex, struct pt_regs *regs)
regs->pc += 4;
- tsk->thread.trap_no = 11;
- tsk->thread.error_code = 0;
-
force_sig(SIGFPE, tsk);
}
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index a3ee91971129..dadce735f746 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -234,8 +234,10 @@ void __init init_IRQ(void)
#ifdef CONFIG_SPARSE_IRQ
int __init arch_probe_nr_irqs(void)
{
- nr_irqs = sh_mv.mv_nr_irqs;
- return NR_IRQS_LEGACY;
+ /*
+ * No pre-allocated IRQs.
+ */
+ return 0;
}
#endif
diff --git a/arch/sh/kernel/kgdb.c b/arch/sh/kernel/kgdb.c
index b117781bfea2..38b313909ac9 100644
--- a/arch/sh/kernel/kgdb.c
+++ b/arch/sh/kernel/kgdb.c
@@ -1,7 +1,7 @@
/*
* SuperH KGDB support
*
- * Copyright (C) 2008 - 2009 Paul Mundt
+ * Copyright (C) 2008 - 2012 Paul Mundt
*
* Single stepping taken from the old stub by Henry Bell and Jeremy Siegel.
*
@@ -164,42 +164,89 @@ static void undo_single_step(struct pt_regs *linux_regs)
stepped_opcode = 0;
}
-void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
-{
- int i;
+struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
+ { "r0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[0]) },
+ { "r1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[1]) },
+ { "r2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[2]) },
+ { "r3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[3]) },
+ { "r4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[4]) },
+ { "r5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[5]) },
+ { "r6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[6]) },
+ { "r7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[7]) },
+ { "r8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[8]) },
+ { "r9", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[9]) },
+ { "r10", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[10]) },
+ { "r11", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[11]) },
+ { "r12", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[12]) },
+ { "r13", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[13]) },
+ { "r14", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[14]) },
+ { "r15", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[15]) },
+ { "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, pc) },
+ { "pr", GDB_SIZEOF_REG, offsetof(struct pt_regs, pr) },
+ { "sr", GDB_SIZEOF_REG, offsetof(struct pt_regs, sr) },
+ { "gbr", GDB_SIZEOF_REG, offsetof(struct pt_regs, gbr) },
+ { "mach", GDB_SIZEOF_REG, offsetof(struct pt_regs, mach) },
+ { "macl", GDB_SIZEOF_REG, offsetof(struct pt_regs, macl) },
+ { "vbr", GDB_SIZEOF_REG, -1 },
+};
- for (i = 0; i < 16; i++)
- gdb_regs[GDB_R0 + i] = regs->regs[i];
+int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
+{
+ if (regno < 0 || regno >= DBG_MAX_REG_NUM)
+ return -EINVAL;
- gdb_regs[GDB_PC] = regs->pc;
- gdb_regs[GDB_PR] = regs->pr;
- gdb_regs[GDB_SR] = regs->sr;
- gdb_regs[GDB_GBR] = regs->gbr;
- gdb_regs[GDB_MACH] = regs->mach;
- gdb_regs[GDB_MACL] = regs->macl;
+ if (dbg_reg_def[regno].offset != -1)
+ memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
+ dbg_reg_def[regno].size);
- __asm__ __volatile__ ("stc vbr, %0" : "=r" (gdb_regs[GDB_VBR]));
+ return 0;
}
-void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
{
- int i;
+ if (regno >= DBG_MAX_REG_NUM || regno < 0)
+ return NULL;
- for (i = 0; i < 16; i++)
- regs->regs[GDB_R0 + i] = gdb_regs[GDB_R0 + i];
+ if (dbg_reg_def[regno].size != -1)
+ memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
+ dbg_reg_def[regno].size);
+
+ switch (regno) {
+ case GDB_VBR:
+ __asm__ __volatile__ ("stc vbr, %0" : "=r" (mem));
+ break;
+ }
- regs->pc = gdb_regs[GDB_PC];
- regs->pr = gdb_regs[GDB_PR];
- regs->sr = gdb_regs[GDB_SR];
- regs->gbr = gdb_regs[GDB_GBR];
- regs->mach = gdb_regs[GDB_MACH];
- regs->macl = gdb_regs[GDB_MACL];
+ return dbg_reg_def[regno].name;
}
void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
{
+ struct pt_regs *thread_regs = task_pt_regs(p);
+ int reg;
+
+ /* Initialize to zero */
+ for (reg = 0; reg < DBG_MAX_REG_NUM; reg++)
+ gdb_regs[reg] = 0;
+
+ /*
+ * Copy out GP regs 8 to 14.
+ *
+ * switch_to() relies on SR.RB toggling, so regs 0->7 are banked
+ * and need privileged instructions to get to. The r15 value we
+ * fetch from the thread info directly.
+ */
+ for (reg = GDB_R8; reg < GDB_R15; reg++)
+ gdb_regs[reg] = thread_regs->regs[reg];
+
gdb_regs[GDB_R15] = p->thread.sp;
gdb_regs[GDB_PC] = p->thread.pc;
+
+ /*
+ * Additional registers we have context for
+ */
+ gdb_regs[GDB_PR] = thread_regs->pr;
+ gdb_regs[GDB_GBR] = thread_regs->gbr;
}
int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
@@ -264,6 +311,18 @@ BUILD_TRAP_HANDLER(singlestep)
local_irq_restore(flags);
}
+static void kgdb_call_nmi_hook(void *ignored)
+{
+ kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
+}
+
+void kgdb_roundup_cpus(unsigned long flags)
+{
+ local_irq_enable();
+ smp_call_function(kgdb_call_nmi_hook, NULL, 0);
+ local_irq_disable();
+}
+
static int __kgdb_notify(struct die_args *args, unsigned long cmd)
{
int ret;
diff --git a/arch/sh/kernel/machvec.c b/arch/sh/kernel/machvec.c
index 3d722e49db08..ec05f491c347 100644
--- a/arch/sh/kernel/machvec.c
+++ b/arch/sh/kernel/machvec.c
@@ -121,7 +121,4 @@ void __init sh_mv_setup(void)
mv_set(irq_demux);
mv_set(mode_pins);
mv_set(mem_init);
-
- if (!sh_mv.mv_nr_irqs)
- sh_mv.mv_nr_irqs = NR_IRQS;
}
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
index f2621abdf01d..9b7a459a4613 100644
--- a/arch/sh/kernel/process.c
+++ b/arch/sh/kernel/process.c
@@ -2,12 +2,26 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sched.h>
+#include <linux/export.h>
+#include <linux/stackprotector.h>
struct kmem_cache *task_xstate_cachep = NULL;
unsigned int xstate_size;
+#ifdef CONFIG_CC_STACKPROTECTOR
+unsigned long __stack_chk_guard __read_mostly;
+EXPORT_SYMBOL(__stack_chk_guard);
+#endif
+
+/*
+ * this gets called so that we can store lazy state into memory and copy the
+ * current task into the new thread.
+ */
int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
{
+#ifdef CONFIG_SUPERH32
+ unlazy_fpu(src, task_pt_regs(src));
+#endif
*dst = *src;
if (src->thread.xstate) {
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c
index 94273aaf78c1..59521e8a164d 100644
--- a/arch/sh/kernel/process_32.c
+++ b/arch/sh/kernel/process_32.c
@@ -22,6 +22,7 @@
#include <linux/ftrace.h>
#include <linux/hw_breakpoint.h>
#include <linux/prefetch.h>
+#include <linux/stackprotector.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
#include <asm/fpu.h>
@@ -155,15 +156,6 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
}
EXPORT_SYMBOL(dump_fpu);
-/*
- * This gets called before we allocate a new thread and copy
- * the current task into it.
- */
-void prepare_to_copy(struct task_struct *tsk)
-{
- unlazy_fpu(tsk, task_pt_regs(tsk));
-}
-
asmlinkage void ret_from_fork(void);
int copy_thread(unsigned long clone_flags, unsigned long usp,
@@ -220,6 +212,10 @@ __switch_to(struct task_struct *prev, struct task_struct *next)
{
struct thread_struct *next_t = &next->thread;
+#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
+ __stack_chk_guard = next->stack_canary;
+#endif
+
unlazy_fpu(prev, task_pt_regs(prev));
/* we're going to use this soon, after a few expensive things */
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c
index 5901fba3176e..cb4172c8af7d 100644
--- a/arch/sh/kernel/signal_32.c
+++ b/arch/sh/kernel/signal_32.c
@@ -53,23 +53,11 @@ struct fdpic_func_descriptor {
* Atomically swap in the new signal mask, and wait for a signal.
*/
asmlinkage int
-sys_sigsuspend(old_sigset_t mask,
- unsigned long r5, unsigned long r6, unsigned long r7,
- struct pt_regs __regs)
+sys_sigsuspend(old_sigset_t mask)
{
sigset_t blocked;
-
- current->saved_sigmask = current->blocked;
-
- mask &= _BLOCKABLE;
siginitset(&blocked, mask);
- set_current_blocked(&blocked);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_restore_sigmask();
-
- return -ERESTARTNOHAND;
+ return sigsuspend(&blocked);
}
asmlinkage int
@@ -83,10 +71,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
old_sigset_t mask;
if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
+ __get_user(mask, &act->sa_mask))
return -EFAULT;
- __get_user(new_ka.sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
siginitset(&new_ka.sa.sa_mask, mask);
}
@@ -95,10 +83,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
if (!ret && oact) {
if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
__put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
return -EFAULT;
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
}
return ret;
@@ -162,12 +150,11 @@ static inline int save_sigcontext_fpu(struct sigcontext __user *sc,
if (!(boot_cpu_data.flags & CPU_HAS_FPU))
return 0;
- if (!used_math()) {
- __put_user(0, &sc->sc_ownedfp);
- return 0;
- }
+ if (!used_math())
+ return __put_user(0, &sc->sc_ownedfp);
- __put_user(1, &sc->sc_ownedfp);
+ if (__put_user(1, &sc->sc_ownedfp))
+ return -EFAULT;
/* This will cause a "finit" to be triggered by the next
attempted FPU operation by the 'current' process.
@@ -207,7 +194,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *r0_p
regs->sr |= SR_FD; /* Release FPU */
clear_fpu(tsk, regs);
clear_used_math();
- __get_user (owned_fp, &sc->sc_ownedfp);
+ err |= __get_user (owned_fp, &sc->sc_ownedfp);
if (owned_fp)
err |= restore_sigcontext_fpu(sc);
}
@@ -398,11 +385,14 @@ static int setup_frame(int sig, struct k_sigaction *ka,
struct fdpic_func_descriptor __user *funcptr =
(struct fdpic_func_descriptor __user *)ka->sa.sa_handler;
- __get_user(regs->pc, &funcptr->text);
- __get_user(regs->regs[12], &funcptr->GOT);
+ err |= __get_user(regs->pc, &funcptr->text);
+ err |= __get_user(regs->regs[12], &funcptr->GOT);
} else
regs->pc = (unsigned long)ka->sa.sa_handler;
+ if (err)
+ goto give_sigsegv;
+
set_fs(USER_DS);
pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
@@ -482,11 +472,14 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
struct fdpic_func_descriptor __user *funcptr =
(struct fdpic_func_descriptor __user *)ka->sa.sa_handler;
- __get_user(regs->pc, &funcptr->text);
- __get_user(regs->regs[12], &funcptr->GOT);
+ err |= __get_user(regs->pc, &funcptr->text);
+ err |= __get_user(regs->regs[12], &funcptr->GOT);
} else
regs->pc = (unsigned long)ka->sa.sa_handler;
+ if (err)
+ goto give_sigsegv;
+
set_fs(USER_DS);
pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c
index 3c9a6f7dcdce..b589a354c069 100644
--- a/arch/sh/kernel/signal_64.c
+++ b/arch/sh/kernel/signal_64.c
@@ -83,11 +83,12 @@ handle_syscall_restart(struct pt_regs *regs, struct sigaction *sa)
* the kernel can handle, and then we build all the user-level signal handling
* stack-frames in one go after that.
*/
-static int do_signal(struct pt_regs *regs, sigset_t *oldset)
+static void do_signal(struct pt_regs *regs)
{
siginfo_t info;
int signr;
struct k_sigaction ka;
+ sigset_t *oldset;
/*
* We want the common case to go fast, which
@@ -96,11 +97,11 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset)
* if so.
*/
if (!user_mode(regs))
- return 1;
+ return;
if (current_thread_info()->status & TS_RESTORE_SIGMASK)
oldset = &current->saved_sigmask;
- else if (!oldset)
+ else
oldset = &current->blocked;
signr = get_signal_to_deliver(&info, &ka, regs, 0);
@@ -118,7 +119,7 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset)
tracehook_signal_handler(signr, &info, &ka, regs,
test_thread_flag(TIF_SINGLESTEP));
- return 1;
+ return;
}
}
@@ -147,71 +148,18 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset)
sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
}
- return 0;
+ return;
}
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
asmlinkage int
-sys_sigsuspend(old_sigset_t mask,
- unsigned long r3, unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs * regs)
+sys_sigsuspend(old_sigset_t mask)
{
- sigset_t saveset, blocked;
-
- saveset = current->blocked;
-
- mask &= _BLOCKABLE;
+ sigset_t blocked;
siginitset(&blocked, mask);
- set_current_blocked(&blocked);
-
- REF_REG_RET = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_restore_sigmask();
- regs->pc += 4; /* because sys_sigreturn decrements the pc */
- if (do_signal(regs, &saveset)) {
- /* pc now points at signal handler. Need to decrement
- it because entry.S will increment it. */
- regs->pc -= 4;
- return -EINTR;
- }
- }
-}
-
-asmlinkage int
-sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize,
- unsigned long r4, unsigned long r5, unsigned long r6,
- unsigned long r7,
- struct pt_regs * regs)
-{
- sigset_t saveset, newset;
-
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(sigset_t))
- return -EINVAL;
-
- if (copy_from_user(&newset, unewset, sizeof(newset)))
- return -EFAULT;
- sigdelsetmask(&newset, ~_BLOCKABLE);
- saveset = current->blocked;
- set_current_blocked(&newset);
-
- REF_REG_RET = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- regs->pc += 4; /* because sys_sigreturn decrements the pc */
- if (do_signal(regs, &saveset)) {
- /* pc now points at signal handler. Need to decrement
- it because entry.S will increment it. */
- regs->pc -= 4;
- return -EINTR;
- }
- }
+ return sigsuspend(&blocked);
}
asmlinkage int
@@ -225,10 +173,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
old_sigset_t mask;
if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
+ __get_user(mask, &act->sa_mask))
return -EFAULT;
- __get_user(new_ka.sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
siginitset(&new_ka.sa.sa_mask, mask);
}
@@ -237,10 +185,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
if (!ret && oact) {
if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
__put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
return -EFAULT;
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
}
return ret;
@@ -732,7 +680,7 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
{
if (thread_info_flags & _TIF_SIGPENDING)
- do_signal(regs, 0);
+ do_signal(regs);
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
diff --git a/arch/sh/kernel/traps_64.c b/arch/sh/kernel/traps_64.c
index 6c0486094e48..8dae93ed8aff 100644
--- a/arch/sh/kernel/traps_64.c
+++ b/arch/sh/kernel/traps_64.c
@@ -283,8 +283,6 @@ static void do_unhandled_exception(int trapnr, int signr, char *str, char *fn_na
unsigned long error_code, struct pt_regs *regs, struct task_struct *tsk)
{
show_excp_regs(fn_name, trapnr, signr, regs);
- tsk->thread.error_code = error_code;
- tsk->thread.trap_no = trapnr;
if (user_mode(regs))
force_sig(signr, tsk);
diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile
index 2228c8cee4d6..cee6b9999d86 100644
--- a/arch/sh/mm/Makefile
+++ b/arch/sh/mm/Makefile
@@ -15,8 +15,8 @@ cacheops-$(CONFIG_CPU_SHX3) += cache-shx3.o
obj-y += $(cacheops-y)
mmu-y := nommu.o extable_32.o
-mmu-$(CONFIG_MMU) := extable_$(BITS).o fault_$(BITS).o gup.o \
- ioremap.o kmap.o pgtable.o tlbflush_$(BITS).o
+mmu-$(CONFIG_MMU) := extable_$(BITS).o fault.o gup.o ioremap.o kmap.o \
+ pgtable.o tlbex_$(BITS).o tlbflush_$(BITS).o
obj-y += $(mmu-y)
@@ -44,7 +44,7 @@ obj-$(CONFIG_HAVE_SRAM_POOL) += sram.o
GCOV_PROFILE_pmb.o := n
-# Special flags for fault_64.o. This puts restrictions on the number of
+# Special flags for tlbex_64.o. This puts restrictions on the number of
# caller-save registers that the compiler can target when building this file.
# This is required because the code is called from a context in entry.S where
# very few registers have been saved in the exception handler (for speed
@@ -59,7 +59,7 @@ GCOV_PROFILE_pmb.o := n
# The resources not listed below are callee save, i.e. the compiler is free to
# use any of them and will spill them to the stack itself.
-CFLAGS_fault_64.o += -ffixed-r7 \
+CFLAGS_tlbex_64.o += -ffixed-r7 \
-ffixed-r8 -ffixed-r9 -ffixed-r10 -ffixed-r11 -ffixed-r12 \
-ffixed-r13 -ffixed-r14 -ffixed-r16 -ffixed-r17 -ffixed-r19 \
-ffixed-r20 -ffixed-r21 -ffixed-r22 -ffixed-r23 \
diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c
new file mode 100644
index 000000000000..1fc25d85e515
--- /dev/null
+++ b/arch/sh/mm/fault.c
@@ -0,0 +1,514 @@
+/*
+ * Page fault handler for SH with an MMU.
+ *
+ * Copyright (C) 1999 Niibe Yutaka
+ * Copyright (C) 2003 - 2012 Paul Mundt
+ *
+ * Based on linux/arch/i386/mm/fault.c:
+ * Copyright (C) 1995 Linus Torvalds
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/hardirq.h>
+#include <linux/kprobes.h>
+#include <linux/perf_event.h>
+#include <linux/kdebug.h>
+#include <asm/io_trapped.h>
+#include <asm/mmu_context.h>
+#include <asm/tlbflush.h>
+#include <asm/traps.h>
+
+static inline int notify_page_fault(struct pt_regs *regs, int trap)
+{
+ int ret = 0;
+
+ if (kprobes_built_in() && !user_mode(regs)) {
+ preempt_disable();
+ if (kprobe_running() && kprobe_fault_handler(regs, trap))
+ ret = 1;
+ preempt_enable();
+ }
+
+ return ret;
+}
+
+static void
+force_sig_info_fault(int si_signo, int si_code, unsigned long address,
+ struct task_struct *tsk)
+{
+ siginfo_t info;
+
+ info.si_signo = si_signo;
+ info.si_errno = 0;
+ info.si_code = si_code;
+ info.si_addr = (void __user *)address;
+
+ force_sig_info(si_signo, &info, tsk);
+}
+
+/*
+ * This is useful to dump out the page tables associated with
+ * 'addr' in mm 'mm'.
+ */
+static void show_pte(struct mm_struct *mm, unsigned long addr)
+{
+ pgd_t *pgd;
+
+ if (mm)
+ pgd = mm->pgd;
+ else
+ pgd = get_TTB();
+
+ printk(KERN_ALERT "pgd = %p\n", pgd);
+ pgd += pgd_index(addr);
+ printk(KERN_ALERT "[%08lx] *pgd=%0*Lx", addr,
+ (u32)(sizeof(*pgd) * 2), (u64)pgd_val(*pgd));
+
+ do {
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ if (pgd_none(*pgd))
+ break;
+
+ if (pgd_bad(*pgd)) {
+ printk("(bad)");
+ break;
+ }
+
+ pud = pud_offset(pgd, addr);
+ if (PTRS_PER_PUD != 1)
+ printk(", *pud=%0*Lx", (u32)(sizeof(*pud) * 2),
+ (u64)pud_val(*pud));
+
+ if (pud_none(*pud))
+ break;
+
+ if (pud_bad(*pud)) {
+ printk("(bad)");
+ break;
+ }
+
+ pmd = pmd_offset(pud, addr);
+ if (PTRS_PER_PMD != 1)
+ printk(", *pmd=%0*Lx", (u32)(sizeof(*pmd) * 2),
+ (u64)pmd_val(*pmd));
+
+ if (pmd_none(*pmd))
+ break;
+
+ if (pmd_bad(*pmd)) {
+ printk("(bad)");
+ break;
+ }
+
+ /* We must not map this if we have highmem enabled */
+ if (PageHighMem(pfn_to_page(pmd_val(*pmd) >> PAGE_SHIFT)))
+ break;
+
+ pte = pte_offset_kernel(pmd, addr);
+ printk(", *pte=%0*Lx", (u32)(sizeof(*pte) * 2),
+ (u64)pte_val(*pte));
+ } while (0);
+
+ printk("\n");
+}
+
+static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
+{
+ unsigned index = pgd_index(address);
+ pgd_t *pgd_k;
+ pud_t *pud, *pud_k;
+ pmd_t *pmd, *pmd_k;
+
+ pgd += index;
+ pgd_k = init_mm.pgd + index;
+
+ if (!pgd_present(*pgd_k))
+ return NULL;
+
+ pud = pud_offset(pgd, address);
+ pud_k = pud_offset(pgd_k, address);
+ if (!pud_present(*pud_k))
+ return NULL;
+
+ if (!pud_present(*pud))
+ set_pud(pud, *pud_k);
+
+ pmd = pmd_offset(pud, address);
+ pmd_k = pmd_offset(pud_k, address);
+ if (!pmd_present(*pmd_k))
+ return NULL;
+
+ if (!pmd_present(*pmd))
+ set_pmd(pmd, *pmd_k);
+ else {
+ /*
+ * The page tables are fully synchronised so there must
+ * be another reason for the fault. Return NULL here to
+ * signal that we have not taken care of the fault.
+ */
+ BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k));
+ return NULL;
+ }
+
+ return pmd_k;
+}
+
+#ifdef CONFIG_SH_STORE_QUEUES
+#define __FAULT_ADDR_LIMIT P3_ADDR_MAX
+#else
+#define __FAULT_ADDR_LIMIT VMALLOC_END
+#endif
+
+/*
+ * Handle a fault on the vmalloc or module mapping area
+ */
+static noinline int vmalloc_fault(unsigned long address)
+{
+ pgd_t *pgd_k;
+ pmd_t *pmd_k;
+ pte_t *pte_k;
+
+ /* Make sure we are in vmalloc/module/P3 area: */
+ if (!(address >= VMALLOC_START && address < __FAULT_ADDR_LIMIT))
+ return -1;
+
+ /*
+ * Synchronize this task's top level page-table
+ * with the 'reference' page table.
+ *
+ * Do _not_ use "current" here. We might be inside
+ * an interrupt in the middle of a task switch..
+ */
+ pgd_k = get_TTB();
+ pmd_k = vmalloc_sync_one(pgd_k, address);
+ if (!pmd_k)
+ return -1;
+
+ pte_k = pte_offset_kernel(pmd_k, address);
+ if (!pte_present(*pte_k))
+ return -1;
+
+ return 0;
+}
+
+static void
+show_fault_oops(struct pt_regs *regs, unsigned long address)
+{
+ if (!oops_may_print())
+ return;
+
+ printk(KERN_ALERT "BUG: unable to handle kernel ");
+ if (address < PAGE_SIZE)
+ printk(KERN_CONT "NULL pointer dereference");
+ else
+ printk(KERN_CONT "paging request");
+
+ printk(KERN_CONT " at %08lx\n", address);
+ printk(KERN_ALERT "PC:");
+ printk_address(regs->pc, 1);
+
+ show_pte(NULL, address);
+}
+
+static noinline void
+no_context(struct pt_regs *regs, unsigned long error_code,
+ unsigned long address)
+{
+ /* Are we prepared to handle this kernel fault? */
+ if (fixup_exception(regs))
+ return;
+
+ if (handle_trapped_io(regs, address))
+ return;
+
+ /*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+ bust_spinlocks(1);
+
+ show_fault_oops(regs, address);
+
+ die("Oops", regs, error_code);
+ bust_spinlocks(0);
+ do_exit(SIGKILL);
+}
+
+static void
+__bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
+ unsigned long address, int si_code)
+{
+ struct task_struct *tsk = current;
+
+ /* User mode accesses just cause a SIGSEGV */
+ if (user_mode(regs)) {
+ /*
+ * It's possible to have interrupts off here:
+ */
+ local_irq_enable();
+
+ force_sig_info_fault(SIGSEGV, si_code, address, tsk);
+
+ return;
+ }
+
+ no_context(regs, error_code, address);
+}
+
+static noinline void
+bad_area_nosemaphore(struct pt_regs *regs, unsigned long error_code,
+ unsigned long address)
+{
+ __bad_area_nosemaphore(regs, error_code, address, SEGV_MAPERR);
+}
+
+static void
+__bad_area(struct pt_regs *regs, unsigned long error_code,
+ unsigned long address, int si_code)
+{
+ struct mm_struct *mm = current->mm;
+
+ /*
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
+ */
+ up_read(&mm->mmap_sem);
+
+ __bad_area_nosemaphore(regs, error_code, address, si_code);
+}
+
+static noinline void
+bad_area(struct pt_regs *regs, unsigned long error_code, unsigned long address)
+{
+ __bad_area(regs, error_code, address, SEGV_MAPERR);
+}
+
+static noinline void
+bad_area_access_error(struct pt_regs *regs, unsigned long error_code,
+ unsigned long address)
+{
+ __bad_area(regs, error_code, address, SEGV_ACCERR);
+}
+
+static void out_of_memory(void)
+{
+ /*
+ * We ran out of memory, call the OOM killer, and return the userspace
+ * (which will retry the fault, or kill us if we got oom-killed):
+ */
+ up_read(&current->mm->mmap_sem);
+
+ pagefault_out_of_memory();
+}
+
+static void
+do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address)
+{
+ struct task_struct *tsk = current;
+ struct mm_struct *mm = tsk->mm;
+
+ up_read(&mm->mmap_sem);
+
+ /* Kernel mode? Handle exceptions or die: */
+ if (!user_mode(regs))
+ no_context(regs, error_code, address);
+
+ force_sig_info_fault(SIGBUS, BUS_ADRERR, address, tsk);
+}
+
+static noinline int
+mm_fault_error(struct pt_regs *regs, unsigned long error_code,
+ unsigned long address, unsigned int fault)
+{
+ /*
+ * Pagefault was interrupted by SIGKILL. We have no reason to
+ * continue pagefault.
+ */
+ if (fatal_signal_pending(current)) {
+ if (!(fault & VM_FAULT_RETRY))
+ up_read(&current->mm->mmap_sem);
+ if (!user_mode(regs))
+ no_context(regs, error_code, address);
+ return 1;
+ }
+
+ if (!(fault & VM_FAULT_ERROR))
+ return 0;
+
+ if (fault & VM_FAULT_OOM) {
+ /* Kernel mode? Handle exceptions or die: */
+ if (!user_mode(regs)) {
+ up_read(&current->mm->mmap_sem);
+ no_context(regs, error_code, address);
+ return 1;
+ }
+
+ out_of_memory();
+ } else {
+ if (fault & VM_FAULT_SIGBUS)
+ do_sigbus(regs, error_code, address);
+ else
+ BUG();
+ }
+
+ return 1;
+}
+
+static inline int access_error(int error_code, struct vm_area_struct *vma)
+{
+ if (error_code & FAULT_CODE_WRITE) {
+ /* write, present and write, not present: */
+ if (unlikely(!(vma->vm_flags & VM_WRITE)))
+ return 1;
+ return 0;
+ }
+
+ /* ITLB miss on NX page */
+ if (unlikely((error_code & FAULT_CODE_ITLB) &&
+ !(vma->vm_flags & VM_EXEC)))
+ return 1;
+
+ /* read, not present: */
+ if (unlikely(!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))))
+ return 1;
+
+ return 0;
+}
+
+static int fault_in_kernel_space(unsigned long address)
+{
+ return address >= TASK_SIZE;
+}
+
+/*
+ * This routine handles page faults. It determines the address,
+ * and the problem, and then passes it off to one of the appropriate
+ * routines.
+ */
+asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
+ unsigned long error_code,
+ unsigned long address)
+{
+ unsigned long vec;
+ struct task_struct *tsk;
+ struct mm_struct *mm;
+ struct vm_area_struct * vma;
+ int fault;
+ int write = error_code & FAULT_CODE_WRITE;
+ unsigned int flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
+ (write ? FAULT_FLAG_WRITE : 0));
+
+ tsk = current;
+ mm = tsk->mm;
+ vec = lookup_exception_vector();
+
+ /*
+ * We fault-in kernel-space virtual memory on-demand. The
+ * 'reference' page table is init_mm.pgd.
+ *
+ * NOTE! We MUST NOT take any locks for this case. We may
+ * be in an interrupt or a critical region, and should
+ * only copy the information from the master page table,
+ * nothing more.
+ */
+ if (unlikely(fault_in_kernel_space(address))) {
+ if (vmalloc_fault(address) >= 0)
+ return;
+ if (notify_page_fault(regs, vec))
+ return;
+
+ bad_area_nosemaphore(regs, error_code, address);
+ return;
+ }
+
+ if (unlikely(notify_page_fault(regs, vec)))
+ return;
+
+ /* Only enable interrupts if they were on before the fault */
+ if ((regs->sr & SR_IMASK) != SR_IMASK)
+ local_irq_enable();
+
+ perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
+
+ /*
+ * If we're in an interrupt, have no user context or are running
+ * in an atomic region then we must not take the fault:
+ */
+ if (unlikely(in_atomic() || !mm)) {
+ bad_area_nosemaphore(regs, error_code, address);
+ return;
+ }
+
+retry:
+ down_read(&mm->mmap_sem);
+
+ vma = find_vma(mm, address);
+ if (unlikely(!vma)) {
+ bad_area(regs, error_code, address);
+ return;
+ }
+ if (likely(vma->vm_start <= address))
+ goto good_area;
+ if (unlikely(!(vma->vm_flags & VM_GROWSDOWN))) {
+ bad_area(regs, error_code, address);
+ return;
+ }
+ if (unlikely(expand_stack(vma, address))) {
+ bad_area(regs, error_code, address);
+ return;
+ }
+
+ /*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+good_area:
+ if (unlikely(access_error(error_code, vma))) {
+ bad_area_access_error(regs, error_code, address);
+ return;
+ }
+
+ set_thread_fault_code(error_code);
+
+ /*
+ * If for any reason at all we couldn't handle the fault,
+ * make sure we exit gracefully rather than endlessly redo
+ * the fault.
+ */
+ fault = handle_mm_fault(mm, vma, address, flags);
+
+ if (unlikely(fault & (VM_FAULT_RETRY | VM_FAULT_ERROR)))
+ if (mm_fault_error(regs, error_code, address, fault))
+ return;
+
+ if (flags & FAULT_FLAG_ALLOW_RETRY) {
+ if (fault & VM_FAULT_MAJOR) {
+ tsk->maj_flt++;
+ perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
+ regs, address);
+ } else {
+ tsk->min_flt++;
+ perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
+ regs, address);
+ }
+ if (fault & VM_FAULT_RETRY) {
+ flags &= ~FAULT_FLAG_ALLOW_RETRY;
+
+ /*
+ * No need to up_read(&mm->mmap_sem) as we would
+ * have already released it in __lock_page_or_retry
+ * in mm/filemap.c.
+ */
+ goto retry;
+ }
+ }
+
+ up_read(&mm->mmap_sem);
+}
diff --git a/arch/sh/mm/fault_32.c b/arch/sh/mm/fault_32.c
deleted file mode 100644
index e99b104d967a..000000000000
--- a/arch/sh/mm/fault_32.c
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * Page fault handler for SH with an MMU.
- *
- * Copyright (C) 1999 Niibe Yutaka
- * Copyright (C) 2003 - 2009 Paul Mundt
- *
- * Based on linux/arch/i386/mm/fault.c:
- * Copyright (C) 1995 Linus Torvalds
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/hardirq.h>
-#include <linux/kprobes.h>
-#include <linux/perf_event.h>
-#include <asm/io_trapped.h>
-#include <asm/mmu_context.h>
-#include <asm/tlbflush.h>
-#include <asm/traps.h>
-
-static inline int notify_page_fault(struct pt_regs *regs, int trap)
-{
- int ret = 0;
-
- if (kprobes_built_in() && !user_mode(regs)) {
- preempt_disable();
- if (kprobe_running() && kprobe_fault_handler(regs, trap))
- ret = 1;
- preempt_enable();
- }
-
- return ret;
-}
-
-static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
-{
- unsigned index = pgd_index(address);
- pgd_t *pgd_k;
- pud_t *pud, *pud_k;
- pmd_t *pmd, *pmd_k;
-
- pgd += index;
- pgd_k = init_mm.pgd + index;
-
- if (!pgd_present(*pgd_k))
- return NULL;
-
- pud = pud_offset(pgd, address);
- pud_k = pud_offset(pgd_k, address);
- if (!pud_present(*pud_k))
- return NULL;
-
- if (!pud_present(*pud))
- set_pud(pud, *pud_k);
-
- pmd = pmd_offset(pud, address);
- pmd_k = pmd_offset(pud_k, address);
- if (!pmd_present(*pmd_k))
- return NULL;
-
- if (!pmd_present(*pmd))
- set_pmd(pmd, *pmd_k);
- else {
- /*
- * The page tables are fully synchronised so there must
- * be another reason for the fault. Return NULL here to
- * signal that we have not taken care of the fault.
- */
- BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k));
- return NULL;
- }
-
- return pmd_k;
-}
-
-/*
- * Handle a fault on the vmalloc or module mapping area
- */
-static noinline int vmalloc_fault(unsigned long address)
-{
- pgd_t *pgd_k;
- pmd_t *pmd_k;
- pte_t *pte_k;
-
- /* Make sure we are in vmalloc/module/P3 area: */
- if (!(address >= P3SEG && address < P3_ADDR_MAX))
- return -1;
-
- /*
- * Synchronize this task's top level page-table
- * with the 'reference' page table.
- *
- * Do _not_ use "current" here. We might be inside
- * an interrupt in the middle of a task switch..
- */
- pgd_k = get_TTB();
- pmd_k = vmalloc_sync_one(pgd_k, address);
- if (!pmd_k)
- return -1;
-
- pte_k = pte_offset_kernel(pmd_k, address);
- if (!pte_present(*pte_k))
- return -1;
-
- return 0;
-}
-
-static int fault_in_kernel_space(unsigned long address)
-{
- return address >= TASK_SIZE;
-}
-
-/*
- * This routine handles page faults. It determines the address,
- * and the problem, and then passes it off to one of the appropriate
- * routines.
- */
-asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
- unsigned long writeaccess,
- unsigned long address)
-{
- unsigned long vec;
- struct task_struct *tsk;
- struct mm_struct *mm;
- struct vm_area_struct * vma;
- int si_code;
- int fault;
- siginfo_t info;
-
- tsk = current;
- mm = tsk->mm;
- si_code = SEGV_MAPERR;
- vec = lookup_exception_vector();
-
- /*
- * We fault-in kernel-space virtual memory on-demand. The
- * 'reference' page table is init_mm.pgd.
- *
- * NOTE! We MUST NOT take any locks for this case. We may
- * be in an interrupt or a critical region, and should
- * only copy the information from the master page table,
- * nothing more.
- */
- if (unlikely(fault_in_kernel_space(address))) {
- if (vmalloc_fault(address) >= 0)
- return;
- if (notify_page_fault(regs, vec))
- return;
-
- goto bad_area_nosemaphore;
- }
-
- if (unlikely(notify_page_fault(regs, vec)))
- return;
-
- /* Only enable interrupts if they were on before the fault */
- if ((regs->sr & SR_IMASK) != SR_IMASK)
- local_irq_enable();
-
- perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
-
- /*
- * If we're in an interrupt, have no user context or are running
- * in an atomic region then we must not take the fault:
- */
- if (in_atomic() || !mm)
- goto no_context;
-
- down_read(&mm->mmap_sem);
-
- vma = find_vma(mm, address);
- if (!vma)
- goto bad_area;
- if (vma->vm_start <= address)
- goto good_area;
- if (!(vma->vm_flags & VM_GROWSDOWN))
- goto bad_area;
- if (expand_stack(vma, address))
- goto bad_area;
-
- /*
- * Ok, we have a good vm_area for this memory access, so
- * we can handle it..
- */
-good_area:
- si_code = SEGV_ACCERR;
- if (writeaccess) {
- if (!(vma->vm_flags & VM_WRITE))
- goto bad_area;
- } else {
- if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
- goto bad_area;
- }
-
- /*
- * If for any reason at all we couldn't handle the fault,
- * make sure we exit gracefully rather than endlessly redo
- * the fault.
- */
- fault = handle_mm_fault(mm, vma, address, writeaccess ? FAULT_FLAG_WRITE : 0);
- if (unlikely(fault & VM_FAULT_ERROR)) {
- if (fault & VM_FAULT_OOM)
- goto out_of_memory;
- else if (fault & VM_FAULT_SIGBUS)
- goto do_sigbus;
- BUG();
- }
- if (fault & VM_FAULT_MAJOR) {
- tsk->maj_flt++;
- perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
- regs, address);
- } else {
- tsk->min_flt++;
- perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
- regs, address);
- }
-
- up_read(&mm->mmap_sem);
- return;
-
- /*
- * Something tried to access memory that isn't in our memory map..
- * Fix it, but check if it's kernel or user first..
- */
-bad_area:
- up_read(&mm->mmap_sem);
-
-bad_area_nosemaphore:
- if (user_mode(regs)) {
- info.si_signo = SIGSEGV;
- info.si_errno = 0;
- info.si_code = si_code;
- info.si_addr = (void *) address;
- force_sig_info(SIGSEGV, &info, tsk);
- return;
- }
-
-no_context:
- /* Are we prepared to handle this kernel fault? */
- if (fixup_exception(regs))
- return;
-
- if (handle_trapped_io(regs, address))
- return;
-/*
- * Oops. The kernel tried to access some bad page. We'll have to
- * terminate things with extreme prejudice.
- *
- */
-
- bust_spinlocks(1);
-
- if (oops_may_print()) {
- unsigned long page;
-
- if (address < PAGE_SIZE)
- printk(KERN_ALERT "Unable to handle kernel NULL "
- "pointer dereference");
- else
- printk(KERN_ALERT "Unable to handle kernel paging "
- "request");
- printk(" at virtual address %08lx\n", address);
- printk(KERN_ALERT "pc = %08lx\n", regs->pc);
- page = (unsigned long)get_TTB();
- if (page) {
- page = ((__typeof__(page) *)page)[address >> PGDIR_SHIFT];
- printk(KERN_ALERT "*pde = %08lx\n", page);
- if (page & _PAGE_PRESENT) {
- page &= PAGE_MASK;
- address &= 0x003ff000;
- page = ((__typeof__(page) *)
- __va(page))[address >>
- PAGE_SHIFT];
- printk(KERN_ALERT "*pte = %08lx\n", page);
- }
- }
- }
-
- die("Oops", regs, writeaccess);
- bust_spinlocks(0);
- do_exit(SIGKILL);
-
-/*
- * We ran out of memory, or some other thing happened to us that made
- * us unable to handle the page fault gracefully.
- */
-out_of_memory:
- up_read(&mm->mmap_sem);
- if (!user_mode(regs))
- goto no_context;
- pagefault_out_of_memory();
- return;
-
-do_sigbus:
- up_read(&mm->mmap_sem);
-
- /*
- * Send a sigbus, regardless of whether we were in kernel
- * or user mode.
- */
- info.si_signo = SIGBUS;
- info.si_errno = 0;
- info.si_code = BUS_ADRERR;
- info.si_addr = (void *)address;
- force_sig_info(SIGBUS, &info, tsk);
-
- /* Kernel mode? Handle exceptions or die */
- if (!user_mode(regs))
- goto no_context;
-}
-
-/*
- * Called with interrupts disabled.
- */
-asmlinkage int __kprobes
-handle_tlbmiss(struct pt_regs *regs, unsigned long writeaccess,
- unsigned long address)
-{
- pgd_t *pgd;
- pud_t *pud;
- pmd_t *pmd;
- pte_t *pte;
- pte_t entry;
-
- /*
- * We don't take page faults for P1, P2, and parts of P4, these
- * are always mapped, whether it be due to legacy behaviour in
- * 29-bit mode, or due to PMB configuration in 32-bit mode.
- */
- if (address >= P3SEG && address < P3_ADDR_MAX) {
- pgd = pgd_offset_k(address);
- } else {
- if (unlikely(address >= TASK_SIZE || !current->mm))
- return 1;
-
- pgd = pgd_offset(current->mm, address);
- }
-
- pud = pud_offset(pgd, address);
- if (pud_none_or_clear_bad(pud))
- return 1;
- pmd = pmd_offset(pud, address);
- if (pmd_none_or_clear_bad(pmd))
- return 1;
- pte = pte_offset_kernel(pmd, address);
- entry = *pte;
- if (unlikely(pte_none(entry) || pte_not_present(entry)))
- return 1;
- if (unlikely(writeaccess && !pte_write(entry)))
- return 1;
-
- if (writeaccess)
- entry = pte_mkdirty(entry);
- entry = pte_mkyoung(entry);
-
- set_pte(pte, entry);
-
-#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SMP)
- /*
- * SH-4 does not set MMUCR.RC to the corresponding TLB entry in
- * the case of an initial page write exception, so we need to
- * flush it in order to avoid potential TLB entry duplication.
- */
- if (writeaccess == 2)
- local_flush_tlb_one(get_asid(), address & PAGE_MASK);
-#endif
-
- update_mmu_cache(NULL, address, pte);
-
- return 0;
-}
diff --git a/arch/sh/mm/fault_64.c b/arch/sh/mm/fault_64.c
deleted file mode 100644
index 44a341029e7b..000000000000
--- a/arch/sh/mm/fault_64.c
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * The SH64 TLB miss.
- *
- * Original code from fault.c
- * Copyright (C) 2000, 2001 Paolo Alberelli
- *
- * Fast PTE->TLB refill path
- * Copyright (C) 2003 Richard.Curnow@superh.com
- *
- * IMPORTANT NOTES :
- * The do_fast_page_fault function is called from a context in entry.S
- * where very few registers have been saved. In particular, the code in
- * this file must be compiled not to use ANY caller-save registers that
- * are not part of the restricted save set. Also, it means that code in
- * this file must not make calls to functions elsewhere in the kernel, or
- * else the excepting context will see corruption in its caller-save
- * registers. Plus, the entry.S save area is non-reentrant, so this code
- * has to run with SR.BL==1, i.e. no interrupts taken inside it and panic
- * on any exception.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/mman.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/interrupt.h>
-#include <asm/tlb.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
-#include <asm/mmu_context.h>
-#include <cpu/registers.h>
-
-/* Callable from fault.c, so not static */
-inline void __do_tlb_refill(unsigned long address,
- unsigned long long is_text_not_data, pte_t *pte)
-{
- unsigned long long ptel;
- unsigned long long pteh=0;
- struct tlb_info *tlbp;
- unsigned long long next;
-
- /* Get PTEL first */
- ptel = pte_val(*pte);
-
- /*
- * Set PTEH register
- */
- pteh = neff_sign_extend(address & MMU_VPN_MASK);
-
- /* Set the ASID. */
- pteh |= get_asid() << PTEH_ASID_SHIFT;
- pteh |= PTEH_VALID;
-
- /* Set PTEL register, set_pte has performed the sign extension */
- ptel &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
-
- tlbp = is_text_not_data ? &(cpu_data->itlb) : &(cpu_data->dtlb);
- next = tlbp->next;
- __flush_tlb_slot(next);
- asm volatile ("putcfg %0,1,%2\n\n\t"
- "putcfg %0,0,%1\n"
- : : "r" (next), "r" (pteh), "r" (ptel) );
-
- next += TLB_STEP;
- if (next > tlbp->last) next = tlbp->first;
- tlbp->next = next;
-
-}
-
-static int handle_vmalloc_fault(struct mm_struct *mm,
- unsigned long protection_flags,
- unsigned long long textaccess,
- unsigned long address)
-{
- pgd_t *dir;
- pud_t *pud;
- pmd_t *pmd;
- static pte_t *pte;
- pte_t entry;
-
- dir = pgd_offset_k(address);
-
- pud = pud_offset(dir, address);
- if (pud_none_or_clear_bad(pud))
- return 0;
-
- pmd = pmd_offset(pud, address);
- if (pmd_none_or_clear_bad(pmd))
- return 0;
-
- pte = pte_offset_kernel(pmd, address);
- entry = *pte;
-
- if (pte_none(entry) || !pte_present(entry))
- return 0;
- if ((pte_val(entry) & protection_flags) != protection_flags)
- return 0;
-
- __do_tlb_refill(address, textaccess, pte);
-
- return 1;
-}
-
-static int handle_tlbmiss(struct mm_struct *mm,
- unsigned long long protection_flags,
- unsigned long long textaccess,
- unsigned long address)
-{
- pgd_t *dir;
- pud_t *pud;
- pmd_t *pmd;
- pte_t *pte;
- pte_t entry;
-
- /* NB. The PGD currently only contains a single entry - there is no
- page table tree stored for the top half of the address space since
- virtual pages in that region should never be mapped in user mode.
- (In kernel mode, the only things in that region are the 512Mb super
- page (locked in), and vmalloc (modules) + I/O device pages (handled
- by handle_vmalloc_fault), so no PGD for the upper half is required
- by kernel mode either).
-
- See how mm->pgd is allocated and initialised in pgd_alloc to see why
- the next test is necessary. - RPC */
- if (address >= (unsigned long) TASK_SIZE)
- /* upper half - never has page table entries. */
- return 0;
-
- dir = pgd_offset(mm, address);
- if (pgd_none(*dir) || !pgd_present(*dir))
- return 0;
- if (!pgd_present(*dir))
- return 0;
-
- pud = pud_offset(dir, address);
- if (pud_none(*pud) || !pud_present(*pud))
- return 0;
-
- pmd = pmd_offset(pud, address);
- if (pmd_none(*pmd) || !pmd_present(*pmd))
- return 0;
-
- pte = pte_offset_kernel(pmd, address);
- entry = *pte;
-
- if (pte_none(entry) || !pte_present(entry))
- return 0;
-
- /*
- * If the page doesn't have sufficient protection bits set to
- * service the kind of fault being handled, there's not much
- * point doing the TLB refill. Punt the fault to the general
- * handler.
- */
- if ((pte_val(entry) & protection_flags) != protection_flags)
- return 0;
-
- __do_tlb_refill(address, textaccess, pte);
-
- return 1;
-}
-
-/*
- * Put all this information into one structure so that everything is just
- * arithmetic relative to a single base address. This reduces the number
- * of movi/shori pairs needed just to load addresses of static data.
- */
-struct expevt_lookup {
- unsigned short protection_flags[8];
- unsigned char is_text_access[8];
- unsigned char is_write_access[8];
-};
-
-#define PRU (1<<9)
-#define PRW (1<<8)
-#define PRX (1<<7)
-#define PRR (1<<6)
-
-#define DIRTY (_PAGE_DIRTY | _PAGE_ACCESSED)
-#define YOUNG (_PAGE_ACCESSED)
-
-/* Sized as 8 rather than 4 to allow checking the PTE's PRU bit against whether
- the fault happened in user mode or privileged mode. */
-static struct expevt_lookup expevt_lookup_table = {
- .protection_flags = {PRX, PRX, 0, 0, PRR, PRR, PRW, PRW},
- .is_text_access = {1, 1, 0, 0, 0, 0, 0, 0}
-};
-
-/*
- This routine handles page faults that can be serviced just by refilling a
- TLB entry from an existing page table entry. (This case represents a very
- large majority of page faults.) Return 1 if the fault was successfully
- handled. Return 0 if the fault could not be handled. (This leads into the
- general fault handling in fault.c which deals with mapping file-backed
- pages, stack growth, segmentation faults, swapping etc etc)
- */
-asmlinkage int do_fast_page_fault(unsigned long long ssr_md,
- unsigned long long expevt,
- unsigned long address)
-{
- struct task_struct *tsk;
- struct mm_struct *mm;
- unsigned long long textaccess;
- unsigned long long protection_flags;
- unsigned long long index;
- unsigned long long expevt4;
-
- /* The next few lines implement a way of hashing EXPEVT into a
- * small array index which can be used to lookup parameters
- * specific to the type of TLBMISS being handled.
- *
- * Note:
- * ITLBMISS has EXPEVT==0xa40
- * RTLBMISS has EXPEVT==0x040
- * WTLBMISS has EXPEVT==0x060
- */
- expevt4 = (expevt >> 4);
- /* TODO : xor ssr_md into this expression too. Then we can check
- * that PRU is set when it needs to be. */
- index = expevt4 ^ (expevt4 >> 5);
- index &= 7;
- protection_flags = expevt_lookup_table.protection_flags[index];
- textaccess = expevt_lookup_table.is_text_access[index];
-
- /* SIM
- * Note this is now called with interrupts still disabled
- * This is to cope with being called for a missing IO port
- * address with interrupts disabled. This should be fixed as
- * soon as we have a better 'fast path' miss handler.
- *
- * Plus take care how you try and debug this stuff.
- * For example, writing debug data to a port which you
- * have just faulted on is not going to work.
- */
-
- tsk = current;
- mm = tsk->mm;
-
- if ((address >= VMALLOC_START && address < VMALLOC_END) ||
- (address >= IOBASE_VADDR && address < IOBASE_END)) {
- if (ssr_md)
- /*
- * Process-contexts can never have this address
- * range mapped
- */
- if (handle_vmalloc_fault(mm, protection_flags,
- textaccess, address))
- return 1;
- } else if (!in_interrupt() && mm) {
- if (handle_tlbmiss(mm, protection_flags, textaccess, address))
- return 1;
- }
-
- return 0;
-}
diff --git a/arch/sh/mm/tlb-sh5.c b/arch/sh/mm/tlb-sh5.c
index f27dbe1c1599..3aea25dc431a 100644
--- a/arch/sh/mm/tlb-sh5.c
+++ b/arch/sh/mm/tlb-sh5.c
@@ -182,3 +182,43 @@ void tlb_unwire_entry(void)
local_irq_restore(flags);
}
+
+void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte)
+{
+ unsigned long long ptel;
+ unsigned long long pteh=0;
+ struct tlb_info *tlbp;
+ unsigned long long next;
+ unsigned int fault_code = get_thread_fault_code();
+
+ /* Get PTEL first */
+ ptel = pte.pte_low;
+
+ /*
+ * Set PTEH register
+ */
+ pteh = neff_sign_extend(address & MMU_VPN_MASK);
+
+ /* Set the ASID. */
+ pteh |= get_asid() << PTEH_ASID_SHIFT;
+ pteh |= PTEH_VALID;
+
+ /* Set PTEL register, set_pte has performed the sign extension */
+ ptel &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
+
+ if (fault_code & FAULT_CODE_ITLB)
+ tlbp = &cpu_data->itlb;
+ else
+ tlbp = &cpu_data->dtlb;
+
+ next = tlbp->next;
+ __flush_tlb_slot(next);
+ asm volatile ("putcfg %0,1,%2\n\n\t"
+ "putcfg %0,0,%1\n"
+ : : "r" (next), "r" (pteh), "r" (ptel) );
+
+ next += TLB_STEP;
+ if (next > tlbp->last)
+ next = tlbp->first;
+ tlbp->next = next;
+}
diff --git a/arch/sh/mm/tlbex_32.c b/arch/sh/mm/tlbex_32.c
new file mode 100644
index 000000000000..382262dc0c4b
--- /dev/null
+++ b/arch/sh/mm/tlbex_32.c
@@ -0,0 +1,78 @@
+/*
+ * TLB miss handler for SH with an MMU.
+ *
+ * Copyright (C) 1999 Niibe Yutaka
+ * Copyright (C) 2003 - 2012 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/kprobes.h>
+#include <linux/kdebug.h>
+#include <asm/mmu_context.h>
+#include <asm/thread_info.h>
+
+/*
+ * Called with interrupts disabled.
+ */
+asmlinkage int __kprobes
+handle_tlbmiss(struct pt_regs *regs, unsigned long error_code,
+ unsigned long address)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ pte_t entry;
+
+ /*
+ * We don't take page faults for P1, P2, and parts of P4, these
+ * are always mapped, whether it be due to legacy behaviour in
+ * 29-bit mode, or due to PMB configuration in 32-bit mode.
+ */
+ if (address >= P3SEG && address < P3_ADDR_MAX) {
+ pgd = pgd_offset_k(address);
+ } else {
+ if (unlikely(address >= TASK_SIZE || !current->mm))
+ return 1;
+
+ pgd = pgd_offset(current->mm, address);
+ }
+
+ pud = pud_offset(pgd, address);
+ if (pud_none_or_clear_bad(pud))
+ return 1;
+ pmd = pmd_offset(pud, address);
+ if (pmd_none_or_clear_bad(pmd))
+ return 1;
+ pte = pte_offset_kernel(pmd, address);
+ entry = *pte;
+ if (unlikely(pte_none(entry) || pte_not_present(entry)))
+ return 1;
+ if (unlikely(error_code && !pte_write(entry)))
+ return 1;
+
+ if (error_code)
+ entry = pte_mkdirty(entry);
+ entry = pte_mkyoung(entry);
+
+ set_pte(pte, entry);
+
+#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SMP)
+ /*
+ * SH-4 does not set MMUCR.RC to the corresponding TLB entry in
+ * the case of an initial page write exception, so we need to
+ * flush it in order to avoid potential TLB entry duplication.
+ */
+ if (error_code == FAULT_CODE_INITIAL)
+ local_flush_tlb_one(get_asid(), address & PAGE_MASK);
+#endif
+
+ set_thread_fault_code(error_code);
+ update_mmu_cache(NULL, address, pte);
+
+ return 0;
+}
diff --git a/arch/sh/mm/tlbex_64.c b/arch/sh/mm/tlbex_64.c
new file mode 100644
index 000000000000..8557548fc53e
--- /dev/null
+++ b/arch/sh/mm/tlbex_64.c
@@ -0,0 +1,166 @@
+/*
+ * The SH64 TLB miss.
+ *
+ * Original code from fault.c
+ * Copyright (C) 2000, 2001 Paolo Alberelli
+ *
+ * Fast PTE->TLB refill path
+ * Copyright (C) 2003 Richard.Curnow@superh.com
+ *
+ * IMPORTANT NOTES :
+ * The do_fast_page_fault function is called from a context in entry.S
+ * where very few registers have been saved. In particular, the code in
+ * this file must be compiled not to use ANY caller-save registers that
+ * are not part of the restricted save set. Also, it means that code in
+ * this file must not make calls to functions elsewhere in the kernel, or
+ * else the excepting context will see corruption in its caller-save
+ * registers. Plus, the entry.S save area is non-reentrant, so this code
+ * has to run with SR.BL==1, i.e. no interrupts taken inside it and panic
+ * on any exception.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/kprobes.h>
+#include <asm/tlb.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/pgalloc.h>
+#include <asm/mmu_context.h>
+
+static int handle_tlbmiss(unsigned long long protection_flags,
+ unsigned long address)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ pte_t entry;
+
+ if (is_vmalloc_addr((void *)address)) {
+ pgd = pgd_offset_k(address);
+ } else {
+ if (unlikely(address >= TASK_SIZE || !current->mm))
+ return 1;
+
+ pgd = pgd_offset(current->mm, address);
+ }
+
+ pud = pud_offset(pgd, address);
+ if (pud_none(*pud) || !pud_present(*pud))
+ return 1;
+
+ pmd = pmd_offset(pud, address);
+ if (pmd_none(*pmd) || !pmd_present(*pmd))
+ return 1;
+
+ pte = pte_offset_kernel(pmd, address);
+ entry = *pte;
+ if (pte_none(entry) || !pte_present(entry))
+ return 1;
+
+ /*
+ * If the page doesn't have sufficient protection bits set to
+ * service the kind of fault being handled, there's not much
+ * point doing the TLB refill. Punt the fault to the general
+ * handler.
+ */
+ if ((pte_val(entry) & protection_flags) != protection_flags)
+ return 1;
+
+ update_mmu_cache(NULL, address, pte);
+
+ return 0;
+}
+
+/*
+ * Put all this information into one structure so that everything is just
+ * arithmetic relative to a single base address. This reduces the number
+ * of movi/shori pairs needed just to load addresses of static data.
+ */
+struct expevt_lookup {
+ unsigned short protection_flags[8];
+ unsigned char is_text_access[8];
+ unsigned char is_write_access[8];
+};
+
+#define PRU (1<<9)
+#define PRW (1<<8)
+#define PRX (1<<7)
+#define PRR (1<<6)
+
+/* Sized as 8 rather than 4 to allow checking the PTE's PRU bit against whether
+ the fault happened in user mode or privileged mode. */
+static struct expevt_lookup expevt_lookup_table = {
+ .protection_flags = {PRX, PRX, 0, 0, PRR, PRR, PRW, PRW},
+ .is_text_access = {1, 1, 0, 0, 0, 0, 0, 0}
+};
+
+static inline unsigned int
+expevt_to_fault_code(unsigned long expevt)
+{
+ if (expevt == 0xa40)
+ return FAULT_CODE_ITLB;
+ else if (expevt == 0x060)
+ return FAULT_CODE_WRITE;
+
+ return 0;
+}
+
+/*
+ This routine handles page faults that can be serviced just by refilling a
+ TLB entry from an existing page table entry. (This case represents a very
+ large majority of page faults.) Return 1 if the fault was successfully
+ handled. Return 0 if the fault could not be handled. (This leads into the
+ general fault handling in fault.c which deals with mapping file-backed
+ pages, stack growth, segmentation faults, swapping etc etc)
+ */
+asmlinkage int __kprobes
+do_fast_page_fault(unsigned long long ssr_md, unsigned long long expevt,
+ unsigned long address)
+{
+ unsigned long long protection_flags;
+ unsigned long long index;
+ unsigned long long expevt4;
+ unsigned int fault_code;
+
+ /* The next few lines implement a way of hashing EXPEVT into a
+ * small array index which can be used to lookup parameters
+ * specific to the type of TLBMISS being handled.
+ *
+ * Note:
+ * ITLBMISS has EXPEVT==0xa40
+ * RTLBMISS has EXPEVT==0x040
+ * WTLBMISS has EXPEVT==0x060
+ */
+ expevt4 = (expevt >> 4);
+ /* TODO : xor ssr_md into this expression too. Then we can check
+ * that PRU is set when it needs to be. */
+ index = expevt4 ^ (expevt4 >> 5);
+ index &= 7;
+
+ fault_code = expevt_to_fault_code(expevt);
+
+ protection_flags = expevt_lookup_table.protection_flags[index];
+
+ if (expevt_lookup_table.is_text_access[index])
+ fault_code |= FAULT_CODE_ITLB;
+ if (!ssr_md)
+ fault_code |= FAULT_CODE_USER;
+
+ set_thread_fault_code(fault_code);
+
+ return handle_tlbmiss(protection_flags, address);
+}
diff --git a/arch/sh/mm/tlbflush_64.c b/arch/sh/mm/tlbflush_64.c
index 11c5a18f10ed..f33fdd2558e8 100644
--- a/arch/sh/mm/tlbflush_64.c
+++ b/arch/sh/mm/tlbflush_64.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2000, 2001 Paolo Alberelli
* Copyright (C) 2003 Richard Curnow (/proc/tlb, bug fixes)
- * Copyright (C) 2003 - 2009 Paul Mundt
+ * Copyright (C) 2003 - 2012 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -28,294 +28,6 @@
#include <asm/pgalloc.h>
#include <asm/mmu_context.h>
-extern void die(const char *,struct pt_regs *,long);
-
-#define PFLAG(val,flag) (( (val) & (flag) ) ? #flag : "" )
-#define PPROT(flag) PFLAG(pgprot_val(prot),flag)
-
-static inline void print_prots(pgprot_t prot)
-{
- printk("prot is 0x%016llx\n",pgprot_val(prot));
-
- printk("%s %s %s %s %s\n",PPROT(_PAGE_SHARED),PPROT(_PAGE_READ),
- PPROT(_PAGE_EXECUTE),PPROT(_PAGE_WRITE),PPROT(_PAGE_USER));
-}
-
-static inline void print_vma(struct vm_area_struct *vma)
-{
- printk("vma start 0x%08lx\n", vma->vm_start);
- printk("vma end 0x%08lx\n", vma->vm_end);
-
- print_prots(vma->vm_page_prot);
- printk("vm_flags 0x%08lx\n", vma->vm_flags);
-}
-
-static inline void print_task(struct task_struct *tsk)
-{
- printk("Task pid %d\n", task_pid_nr(tsk));
-}
-
-static pte_t *lookup_pte(struct mm_struct *mm, unsigned long address)
-{
- pgd_t *dir;
- pud_t *pud;
- pmd_t *pmd;
- pte_t *pte;
- pte_t entry;
-
- dir = pgd_offset(mm, address);
- if (pgd_none(*dir))
- return NULL;
-
- pud = pud_offset(dir, address);
- if (pud_none(*pud))
- return NULL;
-
- pmd = pmd_offset(pud, address);
- if (pmd_none(*pmd))
- return NULL;
-
- pte = pte_offset_kernel(pmd, address);
- entry = *pte;
- if (pte_none(entry) || !pte_present(entry))
- return NULL;
-
- return pte;
-}
-
-/*
- * This routine handles page faults. It determines the address,
- * and the problem, and then passes it off to one of the appropriate
- * routines.
- */
-asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
- unsigned long textaccess, unsigned long address)
-{
- struct task_struct *tsk;
- struct mm_struct *mm;
- struct vm_area_struct * vma;
- const struct exception_table_entry *fixup;
- pte_t *pte;
- int fault;
-
- /* SIM
- * Note this is now called with interrupts still disabled
- * This is to cope with being called for a missing IO port
- * address with interrupts disabled. This should be fixed as
- * soon as we have a better 'fast path' miss handler.
- *
- * Plus take care how you try and debug this stuff.
- * For example, writing debug data to a port which you
- * have just faulted on is not going to work.
- */
-
- tsk = current;
- mm = tsk->mm;
-
- /* Not an IO address, so reenable interrupts */
- local_irq_enable();
-
- perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
-
- /*
- * If we're in an interrupt or have no user
- * context, we must not take the fault..
- */
- if (in_atomic() || !mm)
- goto no_context;
-
- /* TLB misses upon some cache flushes get done under cli() */
- down_read(&mm->mmap_sem);
-
- vma = find_vma(mm, address);
-
- if (!vma) {
-#ifdef DEBUG_FAULT
- print_task(tsk);
- printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n",
- __func__, __LINE__,
- address,regs->pc,textaccess,writeaccess);
- show_regs(regs);
-#endif
- goto bad_area;
- }
- if (vma->vm_start <= address) {
- goto good_area;
- }
-
- if (!(vma->vm_flags & VM_GROWSDOWN)) {
-#ifdef DEBUG_FAULT
- print_task(tsk);
- printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n",
- __func__, __LINE__,
- address,regs->pc,textaccess,writeaccess);
- show_regs(regs);
-
- print_vma(vma);
-#endif
- goto bad_area;
- }
- if (expand_stack(vma, address)) {
-#ifdef DEBUG_FAULT
- print_task(tsk);
- printk("%s:%d fault, address is 0x%08x PC %016Lx textaccess %d writeaccess %d\n",
- __func__, __LINE__,
- address,regs->pc,textaccess,writeaccess);
- show_regs(regs);
-#endif
- goto bad_area;
- }
-/*
- * Ok, we have a good vm_area for this memory access, so
- * we can handle it..
- */
-good_area:
- if (textaccess) {
- if (!(vma->vm_flags & VM_EXEC))
- goto bad_area;
- } else {
- if (writeaccess) {
- if (!(vma->vm_flags & VM_WRITE))
- goto bad_area;
- } else {
- if (!(vma->vm_flags & VM_READ))
- goto bad_area;
- }
- }
-
- /*
- * If for any reason at all we couldn't handle the fault,
- * make sure we exit gracefully rather than endlessly redo
- * the fault.
- */
- fault = handle_mm_fault(mm, vma, address, writeaccess ? FAULT_FLAG_WRITE : 0);
- if (unlikely(fault & VM_FAULT_ERROR)) {
- if (fault & VM_FAULT_OOM)
- goto out_of_memory;
- else if (fault & VM_FAULT_SIGBUS)
- goto do_sigbus;
- BUG();
- }
-
- if (fault & VM_FAULT_MAJOR) {
- tsk->maj_flt++;
- perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1,
- regs, address);
- } else {
- tsk->min_flt++;
- perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1,
- regs, address);
- }
-
- /* If we get here, the page fault has been handled. Do the TLB refill
- now from the newly-setup PTE, to avoid having to fault again right
- away on the same instruction. */
- pte = lookup_pte (mm, address);
- if (!pte) {
- /* From empirical evidence, we can get here, due to
- !pte_present(pte). (e.g. if a swap-in occurs, and the page
- is swapped back out again before the process that wanted it
- gets rescheduled?) */
- goto no_pte;
- }
-
- __do_tlb_refill(address, textaccess, pte);
-
-no_pte:
-
- up_read(&mm->mmap_sem);
- return;
-
-/*
- * Something tried to access memory that isn't in our memory map..
- * Fix it, but check if it's kernel or user first..
- */
-bad_area:
-#ifdef DEBUG_FAULT
- printk("fault:bad area\n");
-#endif
- up_read(&mm->mmap_sem);
-
- if (user_mode(regs)) {
- static int count=0;
- siginfo_t info;
- if (count < 4) {
- /* This is really to help debug faults when starting
- * usermode, so only need a few */
- count++;
- printk("user mode bad_area address=%08lx pid=%d (%s) pc=%08lx\n",
- address, task_pid_nr(current), current->comm,
- (unsigned long) regs->pc);
-#if 0
- show_regs(regs);
-#endif
- }
- if (is_global_init(tsk)) {
- panic("INIT had user mode bad_area\n");
- }
- tsk->thread.address = address;
- tsk->thread.error_code = writeaccess;
- info.si_signo = SIGSEGV;
- info.si_errno = 0;
- info.si_addr = (void *) address;
- force_sig_info(SIGSEGV, &info, tsk);
- return;
- }
-
-no_context:
-#ifdef DEBUG_FAULT
- printk("fault:No context\n");
-#endif
- /* Are we prepared to handle this kernel fault? */
- fixup = search_exception_tables(regs->pc);
- if (fixup) {
- regs->pc = fixup->fixup;
- return;
- }
-
-/*
- * Oops. The kernel tried to access some bad page. We'll have to
- * terminate things with extreme prejudice.
- *
- */
- if (address < PAGE_SIZE)
- printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
- else
- printk(KERN_ALERT "Unable to handle kernel paging request");
- printk(" at virtual address %08lx\n", address);
- printk(KERN_ALERT "pc = %08Lx%08Lx\n", regs->pc >> 32, regs->pc & 0xffffffff);
- die("Oops", regs, writeaccess);
- do_exit(SIGKILL);
-
-/*
- * We ran out of memory, or some other thing happened to us that made
- * us unable to handle the page fault gracefully.
- */
-out_of_memory:
- up_read(&mm->mmap_sem);
- if (!user_mode(regs))
- goto no_context;
- pagefault_out_of_memory();
- return;
-
-do_sigbus:
- printk("fault:Do sigbus\n");
- up_read(&mm->mmap_sem);
-
- /*
- * Send a sigbus, regardless of whether we were in kernel
- * or user mode.
- */
- tsk->thread.address = address;
- tsk->thread.error_code = writeaccess;
- tsk->thread.trap_no = 14;
- force_sig(SIGBUS, tsk);
-
- /* Kernel mode? Handle exceptions or die */
- if (!user_mode(regs))
- goto no_context;
-}
-
void local_flush_tlb_one(unsigned long asid, unsigned long page)
{
unsigned long long match, pteh=0, lpage;
@@ -458,7 +170,3 @@ void __flush_tlb_global(void)
{
flush_tlb_all();
}
-
-void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte)
-{
-}
diff --git a/arch/sh/tools/mach-types b/arch/sh/tools/mach-types
index 6dd56c4d0054..569977e52c91 100644
--- a/arch/sh/tools/mach-types
+++ b/arch/sh/tools/mach-types
@@ -51,6 +51,8 @@ SDK7780 SH_SDK7780
MIGOR SH_MIGOR
RSK7201 SH_RSK7201
RSK7203 SH_RSK7203
+RSK7264 SH_RSK7264
+RSK7269 SH_RSK7269
AP325RXA SH_AP325RXA
SH2007 SH_SH2007
SH7757LCR SH_SH7757LCR
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 22474233205b..15e9e05740da 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -32,12 +32,15 @@ config SPARC
select HAVE_NMI_WATCHDOG if SPARC64
select HAVE_BPF_JIT
select GENERIC_SMP_IDLE_THREAD
+ select GENERIC_CMOS_UPDATE
+ select GENERIC_CLOCKEVENTS
select GENERIC_STRNCPY_FROM_USER
config SPARC32
def_bool !64BIT
select GENERIC_ATOMIC64
select CLZ_TAB
+ select ARCH_USES_GETTIMEOFFSET
config SPARC64
def_bool 64BIT
@@ -77,13 +80,6 @@ config BITS
default 32 if SPARC32
default 64 if SPARC64
-config GENERIC_CMOS_UPDATE
- bool
- default y
-
-config GENERIC_CLOCKEVENTS
- def_bool y
-
config IOMMU_HELPER
bool
default y if SPARC64
@@ -274,8 +270,6 @@ config HOTPLUG_CPU
can be controlled through /sys/devices/system/cpu/cpu#.
Say N if you want to disable CPU hotplug.
-source "kernel/time/Kconfig"
-
if SPARC64
source "drivers/cpufreq/Kconfig"
diff --git a/arch/sparc/configs/sparc64_defconfig b/arch/sparc/configs/sparc64_defconfig
index 3c1e85807403..9d8521b8c854 100644
--- a/arch/sparc/configs/sparc64_defconfig
+++ b/arch/sparc/configs/sparc64_defconfig
@@ -5,7 +5,7 @@ CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_LOG_BUF_SHIFT=18
CONFIG_BLK_DEV_INITRD=y
-CONFIG_PERF_COUNTERS=y
+CONFIG_PERF_EVENTS=y
# CONFIG_COMPAT_BRK is not set
CONFIG_SLAB=y
CONFIG_PROFILING=y
diff --git a/arch/sparc/include/asm/gpio.h b/arch/sparc/include/asm/gpio.h
index a0e3ac0af599..b3799d88ffcf 100644
--- a/arch/sparc/include/asm/gpio.h
+++ b/arch/sparc/include/asm/gpio.h
@@ -1,36 +1,4 @@
-#ifndef __ASM_SPARC_GPIO_H
-#define __ASM_SPARC_GPIO_H
-
-#include <linux/errno.h>
-#include <asm-generic/gpio.h>
-
-#ifdef CONFIG_GPIOLIB
-
-static inline int gpio_get_value(unsigned int gpio)
-{
- return __gpio_get_value(gpio);
-}
-
-static inline void gpio_set_value(unsigned int gpio, int value)
-{
- __gpio_set_value(gpio, value);
-}
-
-static inline int gpio_cansleep(unsigned int gpio)
-{
- return __gpio_cansleep(gpio);
-}
-
-static inline int gpio_to_irq(unsigned int gpio)
-{
- return -ENOSYS;
-}
-
-static inline int irq_to_gpio(unsigned int irq)
-{
- return -EINVAL;
-}
-
-#endif /* CONFIG_GPIOLIB */
-
-#endif /* __ASM_SPARC_GPIO_H */
+#ifndef __LINUX_GPIO_H
+#warning Include linux/gpio.h instead of asm/gpio.h
+#include <linux/gpio.h>
+#endif
diff --git a/arch/sparc/include/asm/processor_32.h b/arch/sparc/include/asm/processor_32.h
index 9cbd854fdfdd..f74ac9ee33a8 100644
--- a/arch/sparc/include/asm/processor_32.h
+++ b/arch/sparc/include/asm/processor_32.h
@@ -108,9 +108,6 @@ static inline void start_thread(struct pt_regs * regs, unsigned long pc,
#define release_thread(tsk) do { } while(0)
extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk) do { } while (0)
-
extern unsigned long get_wchan(struct task_struct *);
#define task_pt_regs(tsk) ((tsk)->thread.kregs)
diff --git a/arch/sparc/include/asm/processor_64.h b/arch/sparc/include/asm/processor_64.h
index 6ca7709971d2..4e5a483122a0 100644
--- a/arch/sparc/include/asm/processor_64.h
+++ b/arch/sparc/include/asm/processor_64.h
@@ -188,9 +188,6 @@ do { \
/* Free all resources held by a thread. */
#define release_thread(tsk) do { } while (0)
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk) do { } while (0)
-
extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
extern unsigned long get_wchan(struct task_struct *task);
diff --git a/arch/sparc/include/asm/topology_64.h b/arch/sparc/include/asm/topology_64.h
index 8b9c556d630b..1754390a426f 100644
--- a/arch/sparc/include/asm/topology_64.h
+++ b/arch/sparc/include/asm/topology_64.h
@@ -31,25 +31,6 @@ static inline int pcibus_to_node(struct pci_bus *pbus)
cpu_all_mask : \
cpumask_of_node(pcibus_to_node(bus)))
-#define SD_NODE_INIT (struct sched_domain) { \
- .min_interval = 8, \
- .max_interval = 32, \
- .busy_factor = 32, \
- .imbalance_pct = 125, \
- .cache_nice_tries = 2, \
- .busy_idx = 3, \
- .idle_idx = 2, \
- .newidle_idx = 0, \
- .wake_idx = 0, \
- .forkexec_idx = 0, \
- .flags = SD_LOAD_BALANCE \
- | SD_BALANCE_FORK \
- | SD_BALANCE_EXEC \
- | SD_SERIALIZE, \
- .last_balance = jiffies, \
- .balance_interval = 1, \
-}
-
#else /* CONFIG_NUMA */
#include <asm-generic/topology.h>
diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c
index 28559ce5eeb5..5713957dcb8a 100644
--- a/arch/sparc/kernel/perf_event.c
+++ b/arch/sparc/kernel/perf_event.c
@@ -1296,8 +1296,6 @@ static int __kprobes perf_event_nmi_handler(struct notifier_block *self,
regs = args->regs;
- perf_sample_data_init(&data, 0);
-
cpuc = &__get_cpu_var(cpu_hw_events);
/* If the PMU has the TOE IRQ enable bits, we need to do a
@@ -1321,7 +1319,7 @@ static int __kprobes perf_event_nmi_handler(struct notifier_block *self,
if (val & (1ULL << 31))
continue;
- data.period = event->hw.last_period;
+ perf_sample_data_init(&data, 0, hwc->last_period);
if (!sparc_perf_event_set_period(event, hwc, idx))
continue;
diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c
index 948700fb9036..bb1513e45f1a 100644
--- a/arch/sparc/kernel/signal32.c
+++ b/arch/sparc/kernel/signal32.c
@@ -215,8 +215,9 @@ void do_sigreturn32(struct pt_regs *regs)
(((unsigned long) sf) & 3))
goto segv;
- get_user(pc, &sf->info.si_regs.pc);
- __get_user(npc, &sf->info.si_regs.npc);
+ if (get_user(pc, &sf->info.si_regs.pc) ||
+ __get_user(npc, &sf->info.si_regs.npc))
+ goto segv;
if ((pc | npc) & 3)
goto segv;
@@ -305,8 +306,9 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
(((unsigned long) sf) & 3))
goto segv;
- get_user(pc, &sf->regs.pc);
- __get_user(npc, &sf->regs.npc);
+ if (get_user(pc, &sf->regs.pc) ||
+ __get_user(npc, &sf->regs.npc))
+ goto segv;
if ((pc | npc) & 3)
goto segv;
diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c
index ac8e66b50f07..2b7e849f7c65 100644
--- a/arch/sparc/kernel/signal_32.c
+++ b/arch/sparc/kernel/signal_32.c
@@ -64,18 +64,8 @@ struct rt_signal_frame {
static int _sigpause_common(old_sigset_t set)
{
sigset_t blocked;
-
- current->saved_sigmask = current->blocked;
-
- set &= _BLOCKABLE;
siginitset(&blocked, set);
- set_current_blocked(&blocked);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
-
- return -ERESTARTNOHAND;
+ return sigsuspend(&blocked);
}
asmlinkage int sys_sigsuspend(old_sigset_t set)
diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c
index 48b0f57b65f7..eafaab486b2d 100644
--- a/arch/sparc/kernel/signal_64.c
+++ b/arch/sparc/kernel/signal_64.c
@@ -242,19 +242,8 @@ struct rt_signal_frame {
static long _sigpause_common(old_sigset_t set)
{
sigset_t blocked;
-
- current->saved_sigmask = current->blocked;
-
- set &= _BLOCKABLE;
siginitset(&blocked, set);
- set_current_blocked(&blocked);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
-
- set_restore_sigmask();
-
- return -ERESTARTNOHAND;
+ return sigsuspend(&blocked);
}
asmlinkage long sys_sigpause(unsigned int set)
diff --git a/arch/sparc/kernel/sys_sparc32.c b/arch/sparc/kernel/sys_sparc32.c
index 29c478ffed91..f7392336961f 100644
--- a/arch/sparc/kernel/sys_sparc32.c
+++ b/arch/sparc/kernel/sys_sparc32.c
@@ -139,8 +139,8 @@ static int cp_compat_stat64(struct kstat *stat,
err |= put_user(stat->ino, &statbuf->st_ino);
err |= put_user(stat->mode, &statbuf->st_mode);
err |= put_user(stat->nlink, &statbuf->st_nlink);
- err |= put_user(stat->uid, &statbuf->st_uid);
- err |= put_user(stat->gid, &statbuf->st_gid);
+ err |= put_user(from_kuid_munged(current_user_ns(), stat->uid), &statbuf->st_uid);
+ err |= put_user(from_kgid_munged(current_user_ns(), stat->gid), &statbuf->st_gid);
err |= put_user(huge_encode_dev(stat->rdev), &statbuf->st_rdev);
err |= put_user(0, (unsigned long __user *) &statbuf->__pad3[0]);
err |= put_user(stat->size, &statbuf->st_size);
diff --git a/arch/sparc/kernel/sys_sparc_32.c b/arch/sparc/kernel/sys_sparc_32.c
index 627e89af1d71..0c9b31b22e07 100644
--- a/arch/sparc/kernel/sys_sparc_32.c
+++ b/arch/sparc/kernel/sys_sparc_32.c
@@ -184,10 +184,10 @@ sparc_sigaction (int sig, const struct old_sigaction __user *act,
if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
+ __get_user(mask, &act->sa_mask))
return -EFAULT;
- __get_user(new_ka.sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
siginitset(&new_ka.sa.sa_mask, mask);
new_ka.ka_restorer = NULL;
}
@@ -195,17 +195,12 @@ sparc_sigaction (int sig, const struct old_sigaction __user *act,
ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
if (!ret && oact) {
- /* In the clone() case we could copy half consistent
- * state to the user, however this could sleep and
- * deadlock us if we held the signal lock on SMP. So for
- * now I take the easy way out and do no locking.
- */
if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
__put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
return -EFAULT;
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
}
return ret;
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig
index 74239dd77e06..6ad6219fc47e 100644
--- a/arch/tile/Kconfig
+++ b/arch/tile/Kconfig
@@ -14,6 +14,7 @@ config TILE
select HAVE_SYSCALL_WRAPPERS if TILEGX
select SYS_HYPERVISOR
select ARCH_HAVE_NMI_SAFE_CMPXCHG
+ select GENERIC_CLOCKEVENTS
# FIXME: investigate whether we need/want these options.
# select HAVE_IOREMAP_PROT
@@ -47,9 +48,6 @@ config NEED_PER_CPU_PAGE_FIRST_CHUNK
config SYS_SUPPORTS_HUGETLBFS
def_bool y
-config GENERIC_CLOCKEVENTS
- def_bool y
-
# FIXME: tilegx can implement a more efficient rwsem.
config RWSEM_GENERIC_SPINLOCK
def_bool y
@@ -139,8 +137,6 @@ config NR_CPUS
smaller kernel memory footprint results from using a smaller
value on chips with fewer tiles.
-source "kernel/time/Kconfig"
-
source "kernel/Kconfig.hz"
config KEXEC
diff --git a/arch/tile/include/asm/processor.h b/arch/tile/include/asm/processor.h
index 34c1e01ffb5e..15cd8a4a06ce 100644
--- a/arch/tile/include/asm/processor.h
+++ b/arch/tile/include/asm/processor.h
@@ -210,9 +210,6 @@ static inline void release_thread(struct task_struct *dead_task)
/* Nothing for now */
}
-/* Prepare to copy thread state - unlazy all lazy status. */
-#define prepare_to_copy(tsk) do { } while (0)
-
extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
extern int do_work_pending(struct pt_regs *regs, u32 flags);
diff --git a/arch/tile/include/asm/topology.h b/arch/tile/include/asm/topology.h
index 6fdd0c860193..7a7ce390534f 100644
--- a/arch/tile/include/asm/topology.h
+++ b/arch/tile/include/asm/topology.h
@@ -78,32 +78,6 @@ static inline const struct cpumask *cpumask_of_node(int node)
.balance_interval = 32, \
}
-/* sched_domains SD_NODE_INIT for TILE architecture */
-#define SD_NODE_INIT (struct sched_domain) { \
- .min_interval = 16, \
- .max_interval = 512, \
- .busy_factor = 32, \
- .imbalance_pct = 125, \
- .cache_nice_tries = 1, \
- .busy_idx = 3, \
- .idle_idx = 1, \
- .newidle_idx = 2, \
- .wake_idx = 1, \
- .flags = 1*SD_LOAD_BALANCE \
- | 1*SD_BALANCE_NEWIDLE \
- | 1*SD_BALANCE_EXEC \
- | 1*SD_BALANCE_FORK \
- | 0*SD_BALANCE_WAKE \
- | 0*SD_WAKE_AFFINE \
- | 0*SD_PREFER_LOCAL \
- | 0*SD_SHARE_CPUPOWER \
- | 0*SD_SHARE_PKG_RESOURCES \
- | 1*SD_SERIALIZE \
- , \
- .last_balance = jiffies, \
- .balance_interval = 128, \
-}
-
/* By definition, we create nodes based on online memory. */
#define node_has_online_mem(nid) 1
diff --git a/arch/um/Kconfig.common b/arch/um/Kconfig.common
index 20a49ba93cb9..cb837c223922 100644
--- a/arch/um/Kconfig.common
+++ b/arch/um/Kconfig.common
@@ -10,6 +10,7 @@ config UML
select GENERIC_IRQ_SHOW
select GENERIC_CPU_DEVICES
select GENERIC_IO
+ select GENERIC_CLOCKEVENTS
config MMU
bool
@@ -52,15 +53,6 @@ config GENERIC_BUG
default y
depends on BUG
-config GENERIC_CLOCKEVENTS
- bool
- default y
-
-# Used in kernel/irq/manage.c and include/linux/irq.h
-config IRQ_RELEASE_METHOD
- bool
- default y
-
config HZ
int
default 100
diff --git a/arch/um/Kconfig.um b/arch/um/Kconfig.um
index 70fd690964e4..bf87f25eb2de 100644
--- a/arch/um/Kconfig.um
+++ b/arch/um/Kconfig.um
@@ -10,7 +10,6 @@ config STATIC_LINK
2.75G) for UML.
source "mm/Kconfig"
-source "kernel/time/Kconfig"
config LD_SCRIPT_STATIC
bool
diff --git a/arch/um/defconfig b/arch/um/defconfig
index fdc97e2c3d73..7823ab12e6a4 100644
--- a/arch/um/defconfig
+++ b/arch/um/defconfig
@@ -12,7 +12,6 @@ CONFIG_LOCKDEP_SUPPORT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_CLOCKEVENTS=y
-CONFIG_IRQ_RELEASE_METHOD=y
CONFIG_HZ=100
#
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index ca4c7ebfd0aa..45e248c2f43c 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -8,6 +8,7 @@
#include <linux/tty_flip.h>
#include "chan.h"
#include "os.h"
+#include "irq_kern.h"
#ifdef CONFIG_NOCONFIG_CHAN
static void *not_configged_init(char *str, int device,
@@ -213,9 +214,9 @@ void free_irqs(void)
chan = list_entry(ele, struct chan, free_list);
if (chan->input && chan->enabled)
- free_irq(chan->line->driver->read_irq, chan);
+ um_free_irq(chan->line->driver->read_irq, chan);
if (chan->output && chan->enabled)
- free_irq(chan->line->driver->write_irq, chan);
+ um_free_irq(chan->line->driver->write_irq, chan);
chan->enabled = 0;
}
}
@@ -234,9 +235,9 @@ static void close_one_chan(struct chan *chan, int delay_free_irq)
}
else {
if (chan->input && chan->enabled)
- free_irq(chan->line->driver->read_irq, chan);
+ um_free_irq(chan->line->driver->read_irq, chan);
if (chan->output && chan->enabled)
- free_irq(chan->line->driver->write_irq, chan);
+ um_free_irq(chan->line->driver->write_irq, chan);
chan->enabled = 0;
}
if (chan->ops->close != NULL)
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index 4ab0d9c0911c..acfd0e0fd0c9 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -699,7 +699,7 @@ struct winch {
static void __free_winch(struct work_struct *work)
{
struct winch *winch = container_of(work, struct winch, work);
- free_irq(WINCH_IRQ, winch);
+ um_free_irq(WINCH_IRQ, winch);
if (winch->pid != -1)
os_kill_process(winch->pid, 1);
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index 95f4416e6d9f..0d60c5685c26 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -195,7 +195,7 @@ static int uml_net_close(struct net_device *dev)
netif_stop_queue(dev);
- free_irq(dev->irq, dev);
+ um_free_irq(dev->irq, dev);
if (lp->close != NULL)
(*lp->close)(lp->fd, &lp->user);
lp->fd = -1;
@@ -835,7 +835,7 @@ static void close_devices(void)
spin_lock(&opened_lock);
list_for_each(ele, &opened) {
lp = list_entry(ele, struct uml_net_private, list);
- free_irq(lp->dev->irq, lp->dev);
+ um_free_irq(lp->dev->irq, lp->dev);
if ((lp->close != NULL) && (lp->fd >= 0))
(*lp->close)(lp->fd, &lp->user);
if (lp->remove != NULL)
diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c
index e31680e662a4..11866ffd45a9 100644
--- a/arch/um/drivers/port_kern.c
+++ b/arch/um/drivers/port_kern.c
@@ -254,7 +254,7 @@ int port_wait(void *data)
* connection. Then we loop here throwing out failed
* connections until a good one is found.
*/
- free_irq(TELNETD_IRQ, conn);
+ um_free_irq(TELNETD_IRQ, conn);
if (conn->fd >= 0)
break;
diff --git a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c
index 8bd130f0bda3..b68bbe269e01 100644
--- a/arch/um/drivers/xterm_kern.c
+++ b/arch/um/drivers/xterm_kern.c
@@ -65,7 +65,7 @@ int xterm_fd(int socket, int *pid_out)
* isn't set) this will hang... */
wait_for_completion(&data->ready);
- free_irq(XTERM_IRQ, data);
+ um_free_irq(XTERM_IRQ, data);
ret = data->new_fd;
*pid_out = data->pid;
diff --git a/arch/um/include/asm/pgtable.h b/arch/um/include/asm/pgtable.h
index 6a3f9845743e..5888f1b83477 100644
--- a/arch/um/include/asm/pgtable.h
+++ b/arch/um/include/asm/pgtable.h
@@ -273,6 +273,12 @@ static inline void set_pte(pte_t *pteptr, pte_t pteval)
}
#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+#define __HAVE_ARCH_PTE_SAME
+static inline int pte_same(pte_t pte_a, pte_t pte_b)
+{
+ return !((pte_val(pte_a) ^ pte_val(pte_b)) & ~_PAGE_NEWPAGE);
+}
+
/*
* Conversion functions: convert a page and protection to a page entry,
* and a page entry and page directory to the page they refer to.
@@ -348,11 +354,11 @@ extern pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr);
#define update_mmu_cache(vma,address,ptep) do ; while (0)
/* Encode and de-code a swap entry */
-#define __swp_type(x) (((x).val >> 4) & 0x3f)
+#define __swp_type(x) (((x).val >> 5) & 0x1f)
#define __swp_offset(x) ((x).val >> 11)
#define __swp_entry(type, offset) \
- ((swp_entry_t) { ((type) << 4) | ((offset) << 11) })
+ ((swp_entry_t) { ((type) << 5) | ((offset) << 11) })
#define __pte_to_swp_entry(pte) \
((swp_entry_t) { pte_val(pte_mkuptodate(pte)) })
#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
diff --git a/arch/um/include/asm/processor-generic.h b/arch/um/include/asm/processor-generic.h
index 7827394a5b6c..69f1c57a8d0d 100644
--- a/arch/um/include/asm/processor-generic.h
+++ b/arch/um/include/asm/processor-generic.h
@@ -74,11 +74,6 @@ static inline void release_thread(struct task_struct *task)
extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-static inline void prepare_to_copy(struct task_struct *tsk)
-{
-}
-
-
extern unsigned long thread_saved_pc(struct task_struct *t);
static inline void mm_copy_segments(struct mm_struct *from_mm,
diff --git a/arch/um/include/asm/thread_info.h b/arch/um/include/asm/thread_info.h
index 200c4ab1240c..c04e5ab68f56 100644
--- a/arch/um/include/asm/thread_info.h
+++ b/arch/um/include/asm/thread_info.h
@@ -71,6 +71,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_MEMDIE 5 /* is terminating due to OOM killer */
#define TIF_SYSCALL_AUDIT 6
#define TIF_RESTORE_SIGMASK 7
+#define TIF_NOTIFY_RESUME 8
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
@@ -78,6 +79,5 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
#define _TIF_MEMDIE (1 << TIF_MEMDIE)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
-#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
#endif
diff --git a/arch/um/include/shared/irq_kern.h b/arch/um/include/shared/irq_kern.h
index b05d22f3d84e..7a5bfa6291b8 100644
--- a/arch/um/include/shared/irq_kern.h
+++ b/arch/um/include/shared/irq_kern.h
@@ -13,6 +13,6 @@ extern int um_request_irq(unsigned int irq, int fd, int type,
irq_handler_t handler,
unsigned long irqflags, const char * devname,
void *dev_id);
-
+void um_free_irq(unsigned int irq, void *dev);
#endif
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
index 71b8c947e5ef..00506c3d5d6e 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -297,6 +297,13 @@ unsigned int do_IRQ(int irq, struct uml_pt_regs *regs)
return 1;
}
+void um_free_irq(unsigned int irq, void *dev)
+{
+ free_irq_by_irq_and_dev(irq, dev);
+ free_irq(irq, dev);
+}
+EXPORT_SYMBOL(um_free_irq);
+
int um_request_irq(unsigned int irq, int fd, int type,
irq_handler_t handler,
unsigned long irqflags, const char * devname,
@@ -327,7 +334,6 @@ static void dummy(struct irq_data *d)
/* This is used for everything else than the timer. */
static struct irq_chip normal_irq_type = {
.name = "SIGIO",
- .release = free_irq_by_irq_and_dev,
.irq_disable = dummy,
.irq_enable = dummy,
.irq_ack = dummy,
@@ -335,7 +341,6 @@ static struct irq_chip normal_irq_type = {
static struct irq_chip SIGVTALRM_irq_type = {
.name = "SIGVTALRM",
- .release = free_irq_by_irq_and_dev,
.irq_disable = dummy,
.irq_enable = dummy,
.irq_ack = dummy,
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index 2b73dedb44ca..3a2235e0abc3 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -18,6 +18,7 @@
#include <linux/seq_file.h>
#include <linux/tick.h>
#include <linux/threads.h>
+#include <linux/tracehook.h>
#include <asm/current.h>
#include <asm/pgtable.h>
#include <asm/mmu_context.h>
@@ -114,8 +115,13 @@ void interrupt_end(void)
{
if (need_resched())
schedule();
- if (test_tsk_thread_flag(current, TIF_SIGPENDING))
+ if (test_thread_flag(TIF_SIGPENDING))
do_signal();
+ if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) {
+ tracehook_notify_resume(&current->thread.regs);
+ if (current->replacement_session_keyring)
+ key_replace_session_keyring();
+ }
}
void exit_thread(void)
@@ -190,7 +196,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
if (current->thread.forking) {
memcpy(&p->thread.regs.regs, &regs->regs,
sizeof(p->thread.regs.regs));
- REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.gp, 0);
+ UPT_SET_SYSCALL_RETURN(&p->thread.regs.regs, 0);
if (sp != 0)
REGS_SP(p->thread.regs.regs.gp) = sp;
diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c
index fb12f4c5e649..292e706016c5 100644
--- a/arch/um/kernel/signal.c
+++ b/arch/um/kernel/signal.c
@@ -29,9 +29,6 @@ static int handle_signal(struct pt_regs *regs, unsigned long signr,
unsigned long sp;
int err;
- /* Always make any pending restarted system calls return -EINTR */
- current_thread_info()->restart_block.fn = do_no_restart_syscall;
-
/* Did we come from a system call? */
if (PT_REGS_SYSCALL_NR(regs) >= 0) {
/* If so, check system call restarting.. */
@@ -77,15 +74,14 @@ static int kern_do_signal(struct pt_regs *regs)
{
struct k_sigaction ka_copy;
siginfo_t info;
- sigset_t *oldset;
int sig, handled_sig = 0;
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
- oldset = &current->saved_sigmask;
- else
- oldset = &current->blocked;
-
while ((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0) {
+ sigset_t *oldset;
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = &current->saved_sigmask;
+ else
+ oldset = &current->blocked;
handled_sig = 1;
/* Whee! Actually deliver the signal. */
if (!handle_signal(regs, sig, &ka_copy, &info, oldset)) {
@@ -152,15 +148,8 @@ int do_signal(void)
long sys_sigsuspend(int history0, int history1, old_sigset_t mask)
{
sigset_t blocked;
-
- mask &= _BLOCKABLE;
siginitset(&blocked, mask);
- set_current_blocked(&blocked);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
- return -ERESTARTNOHAND;
+ return sigsuspend(&blocked);
}
long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c
index f5173e1ec3ac..05fbeb480e0b 100644
--- a/arch/um/kernel/skas/syscall.c
+++ b/arch/um/kernel/skas/syscall.c
@@ -34,7 +34,7 @@ void handle_syscall(struct uml_pt_regs *r)
result = -ENOSYS;
else result = EXECUTE_SYSCALL(syscall, regs);
- REGS_SET_SYSCALL_RETURN(r->gp, result);
+ UPT_SET_SYSCALL_RETURN(r, result);
syscall_trace(r, 1);
}
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
index 7f3d4d86431a..f819af951c19 100644
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -75,6 +75,7 @@ static int do_ops(struct host_vm_change *hvc, int end,
default:
printk(KERN_ERR "Unknown op type %d in do_ops\n",
op->type);
+ BUG();
break;
}
}
diff --git a/arch/um/os-Linux/skas/mem.c b/arch/um/os-Linux/skas/mem.c
index c0afff7af4bd..90b310d29179 100644
--- a/arch/um/os-Linux/skas/mem.c
+++ b/arch/um/os-Linux/skas/mem.c
@@ -48,10 +48,6 @@ __initcall(init_syscall_regs);
extern int proc_mm;
-int single_count = 0;
-int multi_count = 0;
-int multi_op_count = 0;
-
static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr)
{
int n, i;
@@ -64,8 +60,6 @@ static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr)
/* FIXME: Need to look up userspace_pid by cpu */
pid = userspace_pid[0];
- multi_count++;
-
n = ptrace_setregs(pid, syscall_regs);
if (n < 0) {
printk(UM_KERN_ERR "Registers - \n");
@@ -126,9 +120,6 @@ long run_syscall_stub(struct mm_id * mm_idp, int syscall,
{
unsigned long *stack = check_init_stack(mm_idp, *addr);
- if (done && *addr == NULL)
- single_count++;
-
*stack += sizeof(long);
stack += *stack / sizeof(long);
@@ -141,7 +132,6 @@ long run_syscall_stub(struct mm_id * mm_idp, int syscall,
*stack++ = args[5];
*stack++ = expected;
*stack = 0;
- multi_op_count++;
if (!done && ((((unsigned long) stack) & ~UM_KERN_PAGE_MASK) <
UM_KERN_PAGE_SIZE - 10 * sizeof(long))) {
diff --git a/arch/unicore32/Kconfig b/arch/unicore32/Kconfig
index eeb8054c7cd8..03c9ff808b5a 100644
--- a/arch/unicore32/Kconfig
+++ b/arch/unicore32/Kconfig
@@ -8,6 +8,7 @@ config UNICORE32
select HAVE_KERNEL_BZIP2
select HAVE_KERNEL_LZO
select HAVE_KERNEL_LZMA
+ select ARCH_HAVE_CUSTOM_GPIO_H
select GENERIC_FIND_FIRST_BIT
select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW
@@ -25,9 +26,6 @@ config HAVE_PWM
config GENERIC_GPIO
def_bool y
-config GENERIC_CLOCKEVENTS
- bool
-
config GENERIC_CSUM
def_bool y
@@ -146,8 +144,6 @@ endmenu
menu "Kernel Features"
-source "kernel/time/Kconfig"
-
source "kernel/Kconfig.preempt"
source "kernel/Kconfig.hz"
diff --git a/arch/unicore32/include/asm/processor.h b/arch/unicore32/include/asm/processor.h
index f0d780a51f9b..14382cb09657 100644
--- a/arch/unicore32/include/asm/processor.h
+++ b/arch/unicore32/include/asm/processor.h
@@ -68,9 +68,6 @@ struct task_struct;
/* Free all resources held by a thread. */
extern void release_thread(struct task_struct *);
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk) do { } while (0)
-
unsigned long get_wchan(struct task_struct *p);
#define cpu_relax() barrier()
diff --git a/arch/unicore32/kernel/signal.c b/arch/unicore32/kernel/signal.c
index 911b549a6df5..7754df6ef7d4 100644
--- a/arch/unicore32/kernel/signal.c
+++ b/arch/unicore32/kernel/signal.c
@@ -370,10 +370,7 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka,
/*
* Block the signal if we were successful.
*/
- sigorsets(&blocked, &tsk->blocked, &ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(&blocked, sig);
- set_current_blocked(&blocked);
+ block_sigmask(ka, sig);
return 0;
}
@@ -450,15 +447,12 @@ static void do_signal(struct pt_regs *regs, int syscall)
regs->UCreg_00 == -ERESTARTNOINTR) {
setup_syscall_restart(regs);
}
-
- /* If there's no signal to deliver, we just put the saved
- * sigmask back.
- */
- if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
- clear_thread_flag(TIF_RESTORE_SIGMASK);
- sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
- }
}
+ /* If there's no signal to deliver, we just put the saved
+ * sigmask back.
+ */
+ if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK))
+ set_current_blocked(&current->saved_sigmask);
}
asmlinkage void do_notify_resume(struct pt_regs *regs,
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 2787fbec7aed..66cc380bebf0 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -12,6 +12,7 @@ config X86_32
config X86_64
def_bool 64BIT
+ select X86_DEV_DMA_OPS
### Arch settings
config X86
@@ -40,7 +41,6 @@ config X86
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_FUNCTION_GRAPH_FP_TEST
select HAVE_FUNCTION_TRACE_MCOUNT_TEST
- select HAVE_FTRACE_NMI_ENTER if DYNAMIC_FTRACE
select HAVE_SYSCALL_TRACEPOINTS
select HAVE_KVM
select HAVE_ARCH_KGDB
@@ -84,9 +84,17 @@ config X86
select DCACHE_WORD_ACCESS
select GENERIC_SMP_IDLE_THREAD
select HAVE_ARCH_SECCOMP_FILTER
+ select BUILDTIME_EXTABLE_SORT
+ select GENERIC_CMOS_UPDATE
+ select CLOCKSOURCE_WATCHDOG
+ select GENERIC_CLOCKEVENTS
+ select ARCH_CLOCKSOURCE_DATA if X86_64
+ select GENERIC_CLOCKEVENTS_BROADCAST if X86_64 || (X86_32 && X86_LOCAL_APIC)
+ select GENERIC_TIME_VSYSCALL if X86_64
+ select KTIME_SCALAR if X86_32
config INSTRUCTION_DECODER
- def_bool (KPROBES || PERF_EVENTS)
+ def_bool (KPROBES || PERF_EVENTS || UPROBES)
config OUTPUT_FORMAT
string
@@ -98,23 +106,6 @@ config ARCH_DEFCONFIG
default "arch/x86/configs/i386_defconfig" if X86_32
default "arch/x86/configs/x86_64_defconfig" if X86_64
-config GENERIC_CMOS_UPDATE
- def_bool y
-
-config CLOCKSOURCE_WATCHDOG
- def_bool y
-
-config GENERIC_CLOCKEVENTS
- def_bool y
-
-config ARCH_CLOCKSOURCE_DATA
- def_bool y
- depends on X86_64
-
-config GENERIC_CLOCKEVENTS_BROADCAST
- def_bool y
- depends on X86_64 || (X86_32 && X86_LOCAL_APIC)
-
config LOCKDEP_SUPPORT
def_bool y
@@ -165,10 +156,6 @@ config RWSEM_XCHGADD_ALGORITHM
config GENERIC_CALIBRATE_DELAY
def_bool y
-config GENERIC_TIME_VSYSCALL
- bool
- default X86_64
-
config ARCH_HAS_CPU_RELAX
def_bool y
@@ -235,13 +222,13 @@ config ARCH_HWEIGHT_CFLAGS
default "-fcall-saved-ecx -fcall-saved-edx" if X86_32
default "-fcall-saved-rdi -fcall-saved-rsi -fcall-saved-rdx -fcall-saved-rcx -fcall-saved-r8 -fcall-saved-r9 -fcall-saved-r10 -fcall-saved-r11" if X86_64
-config KTIME_SCALAR
- def_bool X86_32
-
config ARCH_CPU_PROBE_RELEASE
def_bool y
depends on HOTPLUG_CPU
+config ARCH_SUPPORTS_UPROBES
+ def_bool y
+
source "init/Kconfig"
source "kernel/Kconfig.freezer"
@@ -257,8 +244,6 @@ config ZONE_DMA
If unsure, say Y.
-source "kernel/time/Kconfig"
-
config SMP
bool "Symmetric multi-processing support"
---help---
@@ -327,6 +312,7 @@ config X86_EXTENDED_PLATFORM
NUMAQ (IBM/Sequent)
RDC R-321x SoC
SGI 320/540 (Visual Workstation)
+ STA2X11-based (e.g. Northville)
Summit/EXA (IBM x440)
Unisys ES7000 IA32 series
Moorestown MID devices
@@ -373,6 +359,7 @@ config X86_VSMP
select PARAVIRT
depends on X86_64 && PCI
depends on X86_EXTENDED_PLATFORM
+ depends on SMP
---help---
Support for ScaleMP vSMP systems. Say 'Y' here if this kernel is
supposed to run on these EM64T-based machines. Only choose this option
@@ -459,10 +446,10 @@ config X86_32_NON_STANDARD
depends on X86_32 && SMP
depends on X86_EXTENDED_PLATFORM
---help---
- This option compiles in the NUMAQ, Summit, bigsmp, ES7000, default
- subarchitectures. It is intended for a generic binary kernel.
- if you select them all, kernel will probe it one by one. and will
- fallback to default.
+ This option compiles in the NUMAQ, Summit, bigsmp, ES7000,
+ STA2X11, default subarchitectures. It is intended for a generic
+ binary kernel. If you select them all, kernel will probe it
+ one by one and will fallback to default.
# Alphabetically sorted list of Non standard 32 bit platforms
@@ -502,6 +489,22 @@ config X86_VISWS
A kernel compiled for the Visual Workstation will run on general
PCs as well. See <file:Documentation/sgi-visws.txt> for details.
+config STA2X11
+ bool "STA2X11 Companion Chip Support"
+ depends on X86_32_NON_STANDARD && PCI
+ select X86_DEV_DMA_OPS
+ select X86_DMA_REMAP
+ select SWIOTLB
+ select MFD_STA2X11
+ select ARCH_REQUIRE_GPIOLIB
+ default n
+ ---help---
+ This adds support for boards based on the STA2X11 IO-Hub,
+ a.k.a. "ConneXt". The chip is used in place of the standard
+ PC chipset, so all "standard" peripherals are missing. If this
+ option is selected the kernel will still be able to boot on
+ standard PC machines.
+
config X86_SUMMIT
bool "Summit/EXA (IBM x440)"
depends on X86_32_NON_STANDARD
@@ -1238,10 +1241,6 @@ config NODES_SHIFT
Specify the maximum number of NUMA Nodes available on the target
system. Increases memory reserved to accommodate various tables.
-config HAVE_ARCH_BOOTMEM
- def_bool y
- depends on X86_32 && NUMA
-
config HAVE_ARCH_ALLOC_REMAP
def_bool y
depends on X86_32 && NUMA
@@ -2022,16 +2021,6 @@ config EISA
source "drivers/eisa/Kconfig"
-config MCA
- bool "MCA support"
- ---help---
- MicroChannel Architecture is found in some IBM PS/2 machines and
- laptops. It is a bus system similar to PCI or ISA. See
- <file:Documentation/mca.txt> (and especially the web page given
- there) before attempting to build an MCA bus kernel.
-
-source "drivers/mca/Kconfig"
-
config SCx200
tristate "NatSemi SCx200 support"
---help---
@@ -2214,6 +2203,14 @@ config HAVE_TEXT_POKE_SMP
bool
select STOP_MACHINE if SMP
+config X86_DEV_DMA_OPS
+ bool
+ depends on X86_64 || STA2X11
+
+config X86_DMA_REMAP
+ bool
+ depends on STA2X11
+
source "net/Kconfig"
source "drivers/Kconfig"
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index 277418ff8b52..1f2521434554 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -115,9 +115,10 @@ cfi-sections := $(call as-instr,.cfi_sections .debug_frame,-DCONFIG_AS_CFI_SECTI
# does binutils support specific instructions?
asinstr := $(call as-instr,fxsaveq (%rax),-DCONFIG_AS_FXSAVEQ=1)
+avx_instr := $(call as-instr,vxorps %ymm0$(comma)%ymm1$(comma)%ymm2,-DCONFIG_AS_AVX=1)
-KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr)
-KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr)
+KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr)
+KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr)
LDFLAGS := -m elf_$(UTS_MACHINE)
@@ -205,6 +206,7 @@ archclean:
$(Q)rm -rf $(objtree)/arch/i386
$(Q)rm -rf $(objtree)/arch/x86_64
$(Q)$(MAKE) $(clean)=$(boot)
+ $(Q)$(MAKE) $(clean)=arch/x86/tools
define archhelp
echo '* bzImage - Compressed kernel image (arch/x86/boot/bzImage)'
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index 0cdfc0d2315e..2c14e76bb4c7 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -904,11 +904,19 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table)
memset(boot_params, 0x0, 0x4000);
- /* Copy first two sectors to boot_params */
- memcpy(boot_params, image->image_base, 1024);
-
hdr = &boot_params->hdr;
+ /* Copy the second sector to boot_params */
+ memcpy(&hdr->jump, image->image_base + 512, 512);
+
+ /*
+ * Fill out some of the header fields ourselves because the
+ * EFI firmware loader doesn't load the first sector.
+ */
+ hdr->root_flags = 1;
+ hdr->vid_mode = 0xffff;
+ hdr->boot_flag = 0xAA55;
+
/*
* The EFI firmware loader could have placed the kernel image
* anywhere in memory, but the kernel has various restrictions
diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index f1bbeeb09148..8bbea6aa40d9 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -147,7 +147,7 @@ optional_header:
# Filled in by build.c
.long 0x0000 # AddressOfEntryPoint
- .long 0x0000 # BaseOfCode
+ .long 0x0200 # BaseOfCode
#ifdef CONFIG_X86_32
.long 0 # data
#endif
@@ -189,7 +189,7 @@ extra_header_fields:
.quad 0 # SizeOfHeapCommit
#endif
.long 0 # LoaderFlags
- .long 0x1 # NumberOfRvaAndSizes
+ .long 0x6 # NumberOfRvaAndSizes
.quad 0 # ExportTable
.quad 0 # ImportTable
@@ -217,18 +217,17 @@ section_table:
#
# The EFI application loader requires a relocation section
- # because EFI applications are relocatable and not having
- # this section seems to confuse it. But since we don't need
- # the loader to fixup any relocs for us just fill it with a
- # single dummy reloc.
+ # because EFI applications must be relocatable. But since
+ # we don't need the loader to fixup any relocs for us, we
+ # just create an empty (zero-length) .reloc section header.
#
.ascii ".reloc"
.byte 0
.byte 0
- .long reloc_end - reloc_start
- .long reloc_start
- .long reloc_end - reloc_start # SizeOfRawData
- .long reloc_start # PointerToRawData
+ .long 0
+ .long 0
+ .long 0 # SizeOfRawData
+ .long 0 # PointerToRawData
.long 0 # PointerToRelocations
.long 0 # PointerToLineNumbers
.word 0 # NumberOfRelocations
@@ -469,10 +468,3 @@ setup_corrupt:
.data
dummy: .long 0
-
- .section .reloc
-reloc_start:
- .long dummy - reloc_start
- .long 10
- .word 0
-reloc_end:
diff --git a/arch/x86/boot/main.c b/arch/x86/boot/main.c
index 40358c8905be..cf6083d444f4 100644
--- a/arch/x86/boot/main.c
+++ b/arch/x86/boot/main.c
@@ -57,14 +57,20 @@ static void copy_boot_params(void)
}
/*
- * Set the keyboard repeat rate to maximum. Unclear why this
+ * Query the keyboard lock status as given by the BIOS, and
+ * set the keyboard repeat rate to maximum. Unclear why the latter
* is done here; this might be possible to kill off as stale code.
*/
-static void keyboard_set_repeat(void)
+static void keyboard_init(void)
{
- struct biosregs ireg;
+ struct biosregs ireg, oreg;
initregs(&ireg);
- ireg.ax = 0x0305;
+
+ ireg.ah = 0x02; /* Get keyboard status */
+ intcall(0x16, &ireg, &oreg);
+ boot_params.kbd_status = oreg.al;
+
+ ireg.ax = 0x0305; /* Set keyboard repeat rate */
intcall(0x16, &ireg, NULL);
}
@@ -151,8 +157,8 @@ void main(void)
/* Detect memory layout */
detect_memory();
- /* Set keyboard repeat rate (why?) */
- keyboard_set_repeat();
+ /* Set keyboard repeat rate (why?) and query the lock flags */
+ keyboard_init();
/* Query MCA information */
query_mca();
diff --git a/arch/x86/boot/tools/build.c b/arch/x86/boot/tools/build.c
index 24443a332083..3f61f6e2b46f 100644
--- a/arch/x86/boot/tools/build.c
+++ b/arch/x86/boot/tools/build.c
@@ -198,12 +198,19 @@ int main(int argc, char ** argv)
pe_header = get_unaligned_le32(&buf[0x3c]);
- /* Size of code */
- put_unaligned_le32(file_sz, &buf[pe_header + 0x1c]);
-
/* Size of image */
put_unaligned_le32(file_sz, &buf[pe_header + 0x50]);
+ /*
+ * Subtract the size of the first section (512 bytes) which
+ * includes the header and .reloc section. The remaining size
+ * is that of the .text section.
+ */
+ file_sz -= 512;
+
+ /* Size of code */
+ put_unaligned_le32(file_sz, &buf[pe_header + 0x1c]);
+
#ifdef CONFIG_X86_32
/*
* Address of entry point.
@@ -216,8 +223,14 @@ int main(int argc, char ** argv)
/* .text size */
put_unaligned_le32(file_sz, &buf[pe_header + 0xb0]);
+ /* .text vma */
+ put_unaligned_le32(0x200, &buf[pe_header + 0xb4]);
+
/* .text size of initialised data */
put_unaligned_le32(file_sz, &buf[pe_header + 0xb8]);
+
+ /* .text file offset */
+ put_unaligned_le32(0x200, &buf[pe_header + 0xbc]);
#else
/*
* Address of entry point. startup_32 is at the beginning and
@@ -231,9 +244,14 @@ int main(int argc, char ** argv)
/* .text size */
put_unaligned_le32(file_sz, &buf[pe_header + 0xc0]);
+ /* .text vma */
+ put_unaligned_le32(0x200, &buf[pe_header + 0xc4]);
+
/* .text size of initialised data */
put_unaligned_le32(file_sz, &buf[pe_header + 0xc8]);
+ /* .text file offset */
+ put_unaligned_le32(0x200, &buf[pe_header + 0xcc]);
#endif /* CONFIG_X86_32 */
#endif /* CONFIG_EFI_STUB */
diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c
index c799352e24fc..ac7f5cd019e8 100644
--- a/arch/x86/crypto/aesni-intel_glue.c
+++ b/arch/x86/crypto/aesni-intel_glue.c
@@ -222,27 +222,6 @@ static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
}
}
-static struct crypto_alg aesni_alg = {
- .cra_name = "aes",
- .cra_driver_name = "aes-aesni",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1,
- .cra_alignmask = 0,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(aesni_alg.cra_list),
- .cra_u = {
- .cipher = {
- .cia_min_keysize = AES_MIN_KEY_SIZE,
- .cia_max_keysize = AES_MAX_KEY_SIZE,
- .cia_setkey = aes_set_key,
- .cia_encrypt = aes_encrypt,
- .cia_decrypt = aes_decrypt
- }
- }
-};
-
static void __aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
{
struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm));
@@ -257,27 +236,6 @@ static void __aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
aesni_dec(ctx, dst, src);
}
-static struct crypto_alg __aesni_alg = {
- .cra_name = "__aes-aesni",
- .cra_driver_name = "__driver-aes-aesni",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1,
- .cra_alignmask = 0,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(__aesni_alg.cra_list),
- .cra_u = {
- .cipher = {
- .cia_min_keysize = AES_MIN_KEY_SIZE,
- .cia_max_keysize = AES_MAX_KEY_SIZE,
- .cia_setkey = aes_set_key,
- .cia_encrypt = __aes_encrypt,
- .cia_decrypt = __aes_decrypt
- }
- }
-};
-
static int ecb_encrypt(struct blkcipher_desc *desc,
struct scatterlist *dst, struct scatterlist *src,
unsigned int nbytes)
@@ -326,28 +284,6 @@ static int ecb_decrypt(struct blkcipher_desc *desc,
return err;
}
-static struct crypto_alg blk_ecb_alg = {
- .cra_name = "__ecb-aes-aesni",
- .cra_driver_name = "__driver-ecb-aes-aesni",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1,
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(blk_ecb_alg.cra_list),
- .cra_u = {
- .blkcipher = {
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- .setkey = aes_set_key,
- .encrypt = ecb_encrypt,
- .decrypt = ecb_decrypt,
- },
- },
-};
-
static int cbc_encrypt(struct blkcipher_desc *desc,
struct scatterlist *dst, struct scatterlist *src,
unsigned int nbytes)
@@ -396,28 +332,6 @@ static int cbc_decrypt(struct blkcipher_desc *desc,
return err;
}
-static struct crypto_alg blk_cbc_alg = {
- .cra_name = "__cbc-aes-aesni",
- .cra_driver_name = "__driver-cbc-aes-aesni",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1,
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(blk_cbc_alg.cra_list),
- .cra_u = {
- .blkcipher = {
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- .setkey = aes_set_key,
- .encrypt = cbc_encrypt,
- .decrypt = cbc_decrypt,
- },
- },
-};
-
#ifdef CONFIG_X86_64
static void ctr_crypt_final(struct crypto_aes_ctx *ctx,
struct blkcipher_walk *walk)
@@ -461,29 +375,6 @@ static int ctr_crypt(struct blkcipher_desc *desc,
return err;
}
-
-static struct crypto_alg blk_ctr_alg = {
- .cra_name = "__ctr-aes-aesni",
- .cra_driver_name = "__driver-ctr-aes-aesni",
- .cra_priority = 0,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1,
- .cra_alignmask = 0,
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(blk_ctr_alg.cra_list),
- .cra_u = {
- .blkcipher = {
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- .ivsize = AES_BLOCK_SIZE,
- .setkey = aes_set_key,
- .encrypt = ctr_crypt,
- .decrypt = ctr_crypt,
- },
- },
-};
#endif
static int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key,
@@ -551,281 +442,65 @@ static void ablk_exit(struct crypto_tfm *tfm)
cryptd_free_ablkcipher(ctx->cryptd_tfm);
}
-static void ablk_init_common(struct crypto_tfm *tfm,
- struct cryptd_ablkcipher *cryptd_tfm)
+static int ablk_init_common(struct crypto_tfm *tfm, const char *drv_name)
{
struct async_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct cryptd_ablkcipher *cryptd_tfm;
+
+ cryptd_tfm = cryptd_alloc_ablkcipher(drv_name, 0, 0);
+ if (IS_ERR(cryptd_tfm))
+ return PTR_ERR(cryptd_tfm);
ctx->cryptd_tfm = cryptd_tfm;
tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) +
crypto_ablkcipher_reqsize(&cryptd_tfm->base);
+
+ return 0;
}
static int ablk_ecb_init(struct crypto_tfm *tfm)
{
- struct cryptd_ablkcipher *cryptd_tfm;
-
- cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ecb-aes-aesni", 0, 0);
- if (IS_ERR(cryptd_tfm))
- return PTR_ERR(cryptd_tfm);
- ablk_init_common(tfm, cryptd_tfm);
- return 0;
+ return ablk_init_common(tfm, "__driver-ecb-aes-aesni");
}
-static struct crypto_alg ablk_ecb_alg = {
- .cra_name = "ecb(aes)",
- .cra_driver_name = "ecb-aes-aesni",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_aes_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(ablk_ecb_alg.cra_list),
- .cra_init = ablk_ecb_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-};
-
static int ablk_cbc_init(struct crypto_tfm *tfm)
{
- struct cryptd_ablkcipher *cryptd_tfm;
-
- cryptd_tfm = cryptd_alloc_ablkcipher("__driver-cbc-aes-aesni", 0, 0);
- if (IS_ERR(cryptd_tfm))
- return PTR_ERR(cryptd_tfm);
- ablk_init_common(tfm, cryptd_tfm);
- return 0;
+ return ablk_init_common(tfm, "__driver-cbc-aes-aesni");
}
-static struct crypto_alg ablk_cbc_alg = {
- .cra_name = "cbc(aes)",
- .cra_driver_name = "cbc-aes-aesni",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_aes_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(ablk_cbc_alg.cra_list),
- .cra_init = ablk_cbc_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- .ivsize = AES_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-};
-
#ifdef CONFIG_X86_64
static int ablk_ctr_init(struct crypto_tfm *tfm)
{
- struct cryptd_ablkcipher *cryptd_tfm;
-
- cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ctr-aes-aesni", 0, 0);
- if (IS_ERR(cryptd_tfm))
- return PTR_ERR(cryptd_tfm);
- ablk_init_common(tfm, cryptd_tfm);
- return 0;
+ return ablk_init_common(tfm, "__driver-ctr-aes-aesni");
}
-static struct crypto_alg ablk_ctr_alg = {
- .cra_name = "ctr(aes)",
- .cra_driver_name = "ctr-aes-aesni",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct async_aes_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(ablk_ctr_alg.cra_list),
- .cra_init = ablk_ctr_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- .ivsize = AES_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_encrypt,
- .geniv = "chainiv",
- },
- },
-};
-
#ifdef HAS_CTR
static int ablk_rfc3686_ctr_init(struct crypto_tfm *tfm)
{
- struct cryptd_ablkcipher *cryptd_tfm;
-
- cryptd_tfm = cryptd_alloc_ablkcipher(
- "rfc3686(__driver-ctr-aes-aesni)", 0, 0);
- if (IS_ERR(cryptd_tfm))
- return PTR_ERR(cryptd_tfm);
- ablk_init_common(tfm, cryptd_tfm);
- return 0;
+ return ablk_init_common(tfm, "rfc3686(__driver-ctr-aes-aesni)");
}
-
-static struct crypto_alg ablk_rfc3686_ctr_alg = {
- .cra_name = "rfc3686(ctr(aes))",
- .cra_driver_name = "rfc3686-ctr-aes-aesni",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct async_aes_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(ablk_rfc3686_ctr_alg.cra_list),
- .cra_init = ablk_rfc3686_ctr_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = AES_MIN_KEY_SIZE+CTR_RFC3686_NONCE_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE+CTR_RFC3686_NONCE_SIZE,
- .ivsize = CTR_RFC3686_IV_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- .geniv = "seqiv",
- },
- },
-};
#endif
#endif
#ifdef HAS_LRW
static int ablk_lrw_init(struct crypto_tfm *tfm)
{
- struct cryptd_ablkcipher *cryptd_tfm;
-
- cryptd_tfm = cryptd_alloc_ablkcipher("fpu(lrw(__driver-aes-aesni))",
- 0, 0);
- if (IS_ERR(cryptd_tfm))
- return PTR_ERR(cryptd_tfm);
- ablk_init_common(tfm, cryptd_tfm);
- return 0;
+ return ablk_init_common(tfm, "fpu(lrw(__driver-aes-aesni))");
}
-
-static struct crypto_alg ablk_lrw_alg = {
- .cra_name = "lrw(aes)",
- .cra_driver_name = "lrw-aes-aesni",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_aes_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(ablk_lrw_alg.cra_list),
- .cra_init = ablk_lrw_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = AES_MIN_KEY_SIZE + AES_BLOCK_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE + AES_BLOCK_SIZE,
- .ivsize = AES_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-};
#endif
#ifdef HAS_PCBC
static int ablk_pcbc_init(struct crypto_tfm *tfm)
{
- struct cryptd_ablkcipher *cryptd_tfm;
-
- cryptd_tfm = cryptd_alloc_ablkcipher("fpu(pcbc(__driver-aes-aesni))",
- 0, 0);
- if (IS_ERR(cryptd_tfm))
- return PTR_ERR(cryptd_tfm);
- ablk_init_common(tfm, cryptd_tfm);
- return 0;
+ return ablk_init_common(tfm, "fpu(pcbc(__driver-aes-aesni))");
}
-
-static struct crypto_alg ablk_pcbc_alg = {
- .cra_name = "pcbc(aes)",
- .cra_driver_name = "pcbc-aes-aesni",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_aes_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(ablk_pcbc_alg.cra_list),
- .cra_init = ablk_pcbc_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = AES_MIN_KEY_SIZE,
- .max_keysize = AES_MAX_KEY_SIZE,
- .ivsize = AES_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-};
#endif
#ifdef HAS_XTS
static int ablk_xts_init(struct crypto_tfm *tfm)
{
- struct cryptd_ablkcipher *cryptd_tfm;
-
- cryptd_tfm = cryptd_alloc_ablkcipher("fpu(xts(__driver-aes-aesni))",
- 0, 0);
- if (IS_ERR(cryptd_tfm))
- return PTR_ERR(cryptd_tfm);
- ablk_init_common(tfm, cryptd_tfm);
- return 0;
+ return ablk_init_common(tfm, "fpu(xts(__driver-aes-aesni))");
}
-
-static struct crypto_alg ablk_xts_alg = {
- .cra_name = "xts(aes)",
- .cra_driver_name = "xts-aes-aesni",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
- .cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct async_aes_ctx),
- .cra_alignmask = 0,
- .cra_type = &crypto_ablkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(ablk_xts_alg.cra_list),
- .cra_init = ablk_xts_init,
- .cra_exit = ablk_exit,
- .cra_u = {
- .ablkcipher = {
- .min_keysize = 2 * AES_MIN_KEY_SIZE,
- .max_keysize = 2 * AES_MAX_KEY_SIZE,
- .ivsize = AES_BLOCK_SIZE,
- .setkey = ablk_set_key,
- .encrypt = ablk_encrypt,
- .decrypt = ablk_decrypt,
- },
- },
-};
#endif
#ifdef CONFIG_X86_64
@@ -1050,32 +725,6 @@ static int rfc4106_decrypt(struct aead_request *req)
}
}
-static struct crypto_alg rfc4106_alg = {
- .cra_name = "rfc4106(gcm(aes))",
- .cra_driver_name = "rfc4106-gcm-aesni",
- .cra_priority = 400,
- .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
- .cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct aesni_rfc4106_gcm_ctx) + AESNI_ALIGN,
- .cra_alignmask = 0,
- .cra_type = &crypto_nivaead_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(rfc4106_alg.cra_list),
- .cra_init = rfc4106_init,
- .cra_exit = rfc4106_exit,
- .cra_u = {
- .aead = {
- .setkey = rfc4106_set_key,
- .setauthsize = rfc4106_set_authsize,
- .encrypt = rfc4106_encrypt,
- .decrypt = rfc4106_decrypt,
- .geniv = "seqiv",
- .ivsize = 8,
- .maxauthsize = 16,
- },
- },
-};
-
static int __driver_rfc4106_encrypt(struct aead_request *req)
{
u8 one_entry_in_sg = 0;
@@ -1233,26 +882,316 @@ static int __driver_rfc4106_decrypt(struct aead_request *req)
}
return retval;
}
+#endif
-static struct crypto_alg __rfc4106_alg = {
+static struct crypto_alg aesni_algs[] = { {
+ .cra_name = "aes",
+ .cra_driver_name = "aes-aesni",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct crypto_aes_ctx) +
+ AESNI_ALIGN - 1,
+ .cra_alignmask = 0,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .cipher = {
+ .cia_min_keysize = AES_MIN_KEY_SIZE,
+ .cia_max_keysize = AES_MAX_KEY_SIZE,
+ .cia_setkey = aes_set_key,
+ .cia_encrypt = aes_encrypt,
+ .cia_decrypt = aes_decrypt
+ }
+ }
+}, {
+ .cra_name = "__aes-aesni",
+ .cra_driver_name = "__driver-aes-aesni",
+ .cra_priority = 0,
+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct crypto_aes_ctx) +
+ AESNI_ALIGN - 1,
+ .cra_alignmask = 0,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .cipher = {
+ .cia_min_keysize = AES_MIN_KEY_SIZE,
+ .cia_max_keysize = AES_MAX_KEY_SIZE,
+ .cia_setkey = aes_set_key,
+ .cia_encrypt = __aes_encrypt,
+ .cia_decrypt = __aes_decrypt
+ }
+ }
+}, {
+ .cra_name = "__ecb-aes-aesni",
+ .cra_driver_name = "__driver-ecb-aes-aesni",
+ .cra_priority = 0,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct crypto_aes_ctx) +
+ AESNI_ALIGN - 1,
+ .cra_alignmask = 0,
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .blkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = aes_set_key,
+ .encrypt = ecb_encrypt,
+ .decrypt = ecb_decrypt,
+ },
+ },
+}, {
+ .cra_name = "__cbc-aes-aesni",
+ .cra_driver_name = "__driver-cbc-aes-aesni",
+ .cra_priority = 0,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct crypto_aes_ctx) +
+ AESNI_ALIGN - 1,
+ .cra_alignmask = 0,
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .blkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = aes_set_key,
+ .encrypt = cbc_encrypt,
+ .decrypt = cbc_decrypt,
+ },
+ },
+}, {
+ .cra_name = "ecb(aes)",
+ .cra_driver_name = "ecb-aes-aesni",
+ .cra_priority = 400,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct async_aes_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = ablk_ecb_init,
+ .cra_exit = ablk_exit,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = ablk_set_key,
+ .encrypt = ablk_encrypt,
+ .decrypt = ablk_decrypt,
+ },
+ },
+}, {
+ .cra_name = "cbc(aes)",
+ .cra_driver_name = "cbc-aes-aesni",
+ .cra_priority = 400,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct async_aes_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = ablk_cbc_init,
+ .cra_exit = ablk_exit,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = ablk_set_key,
+ .encrypt = ablk_encrypt,
+ .decrypt = ablk_decrypt,
+ },
+ },
+#ifdef CONFIG_X86_64
+}, {
+ .cra_name = "__ctr-aes-aesni",
+ .cra_driver_name = "__driver-ctr-aes-aesni",
+ .cra_priority = 0,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct crypto_aes_ctx) +
+ AESNI_ALIGN - 1,
+ .cra_alignmask = 0,
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .blkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = aes_set_key,
+ .encrypt = ctr_crypt,
+ .decrypt = ctr_crypt,
+ },
+ },
+}, {
+ .cra_name = "ctr(aes)",
+ .cra_driver_name = "ctr-aes-aesni",
+ .cra_priority = 400,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct async_aes_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = ablk_ctr_init,
+ .cra_exit = ablk_exit,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = ablk_set_key,
+ .encrypt = ablk_encrypt,
+ .decrypt = ablk_encrypt,
+ .geniv = "chainiv",
+ },
+ },
+}, {
.cra_name = "__gcm-aes-aesni",
.cra_driver_name = "__driver-gcm-aes-aesni",
.cra_priority = 0,
.cra_flags = CRYPTO_ALG_TYPE_AEAD,
.cra_blocksize = 1,
- .cra_ctxsize = sizeof(struct aesni_rfc4106_gcm_ctx) + AESNI_ALIGN,
+ .cra_ctxsize = sizeof(struct aesni_rfc4106_gcm_ctx) +
+ AESNI_ALIGN,
.cra_alignmask = 0,
.cra_type = &crypto_aead_type,
.cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(__rfc4106_alg.cra_list),
.cra_u = {
.aead = {
.encrypt = __driver_rfc4106_encrypt,
.decrypt = __driver_rfc4106_decrypt,
},
},
-};
+}, {
+ .cra_name = "rfc4106(gcm(aes))",
+ .cra_driver_name = "rfc4106-gcm-aesni",
+ .cra_priority = 400,
+ .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct aesni_rfc4106_gcm_ctx) +
+ AESNI_ALIGN,
+ .cra_alignmask = 0,
+ .cra_type = &crypto_nivaead_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = rfc4106_init,
+ .cra_exit = rfc4106_exit,
+ .cra_u = {
+ .aead = {
+ .setkey = rfc4106_set_key,
+ .setauthsize = rfc4106_set_authsize,
+ .encrypt = rfc4106_encrypt,
+ .decrypt = rfc4106_decrypt,
+ .geniv = "seqiv",
+ .ivsize = 8,
+ .maxauthsize = 16,
+ },
+ },
+#ifdef HAS_CTR
+}, {
+ .cra_name = "rfc3686(ctr(aes))",
+ .cra_driver_name = "rfc3686-ctr-aes-aesni",
+ .cra_priority = 400,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct async_aes_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = ablk_rfc3686_ctr_init,
+ .cra_exit = ablk_exit,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE +
+ CTR_RFC3686_NONCE_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE +
+ CTR_RFC3686_NONCE_SIZE,
+ .ivsize = CTR_RFC3686_IV_SIZE,
+ .setkey = ablk_set_key,
+ .encrypt = ablk_encrypt,
+ .decrypt = ablk_decrypt,
+ .geniv = "seqiv",
+ },
+ },
+#endif
+#endif
+#ifdef HAS_LRW
+}, {
+ .cra_name = "lrw(aes)",
+ .cra_driver_name = "lrw-aes-aesni",
+ .cra_priority = 400,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct async_aes_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = ablk_lrw_init,
+ .cra_exit = ablk_exit,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE + AES_BLOCK_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE + AES_BLOCK_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = ablk_set_key,
+ .encrypt = ablk_encrypt,
+ .decrypt = ablk_decrypt,
+ },
+ },
+#endif
+#ifdef HAS_PCBC
+}, {
+ .cra_name = "pcbc(aes)",
+ .cra_driver_name = "pcbc-aes-aesni",
+ .cra_priority = 400,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct async_aes_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = ablk_pcbc_init,
+ .cra_exit = ablk_exit,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = ablk_set_key,
+ .encrypt = ablk_encrypt,
+ .decrypt = ablk_decrypt,
+ },
+ },
#endif
+#ifdef HAS_XTS
+}, {
+ .cra_name = "xts(aes)",
+ .cra_driver_name = "xts-aes-aesni",
+ .cra_priority = 400,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct async_aes_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = ablk_xts_init,
+ .cra_exit = ablk_exit,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = 2 * AES_MIN_KEY_SIZE,
+ .max_keysize = 2 * AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = ablk_set_key,
+ .encrypt = ablk_encrypt,
+ .decrypt = ablk_decrypt,
+ },
+ },
+#endif
+} };
static const struct x86_cpu_id aesni_cpu_id[] = {
@@ -1263,120 +1202,24 @@ MODULE_DEVICE_TABLE(x86cpu, aesni_cpu_id);
static int __init aesni_init(void)
{
- int err;
+ int err, i;
if (!x86_match_cpu(aesni_cpu_id))
return -ENODEV;
- if ((err = crypto_fpu_init()))
- goto fpu_err;
- if ((err = crypto_register_alg(&aesni_alg)))
- goto aes_err;
- if ((err = crypto_register_alg(&__aesni_alg)))
- goto __aes_err;
- if ((err = crypto_register_alg(&blk_ecb_alg)))
- goto blk_ecb_err;
- if ((err = crypto_register_alg(&blk_cbc_alg)))
- goto blk_cbc_err;
- if ((err = crypto_register_alg(&ablk_ecb_alg)))
- goto ablk_ecb_err;
- if ((err = crypto_register_alg(&ablk_cbc_alg)))
- goto ablk_cbc_err;
-#ifdef CONFIG_X86_64
- if ((err = crypto_register_alg(&blk_ctr_alg)))
- goto blk_ctr_err;
- if ((err = crypto_register_alg(&ablk_ctr_alg)))
- goto ablk_ctr_err;
- if ((err = crypto_register_alg(&__rfc4106_alg)))
- goto __aead_gcm_err;
- if ((err = crypto_register_alg(&rfc4106_alg)))
- goto aead_gcm_err;
-#ifdef HAS_CTR
- if ((err = crypto_register_alg(&ablk_rfc3686_ctr_alg)))
- goto ablk_rfc3686_ctr_err;
-#endif
-#endif
-#ifdef HAS_LRW
- if ((err = crypto_register_alg(&ablk_lrw_alg)))
- goto ablk_lrw_err;
-#endif
-#ifdef HAS_PCBC
- if ((err = crypto_register_alg(&ablk_pcbc_alg)))
- goto ablk_pcbc_err;
-#endif
-#ifdef HAS_XTS
- if ((err = crypto_register_alg(&ablk_xts_alg)))
- goto ablk_xts_err;
-#endif
- return err;
+ err = crypto_fpu_init();
+ if (err)
+ return err;
-#ifdef HAS_XTS
-ablk_xts_err:
-#endif
-#ifdef HAS_PCBC
- crypto_unregister_alg(&ablk_pcbc_alg);
-ablk_pcbc_err:
-#endif
-#ifdef HAS_LRW
- crypto_unregister_alg(&ablk_lrw_alg);
-ablk_lrw_err:
-#endif
-#ifdef CONFIG_X86_64
-#ifdef HAS_CTR
- crypto_unregister_alg(&ablk_rfc3686_ctr_alg);
-ablk_rfc3686_ctr_err:
-#endif
- crypto_unregister_alg(&rfc4106_alg);
-aead_gcm_err:
- crypto_unregister_alg(&__rfc4106_alg);
-__aead_gcm_err:
- crypto_unregister_alg(&ablk_ctr_alg);
-ablk_ctr_err:
- crypto_unregister_alg(&blk_ctr_alg);
-blk_ctr_err:
-#endif
- crypto_unregister_alg(&ablk_cbc_alg);
-ablk_cbc_err:
- crypto_unregister_alg(&ablk_ecb_alg);
-ablk_ecb_err:
- crypto_unregister_alg(&blk_cbc_alg);
-blk_cbc_err:
- crypto_unregister_alg(&blk_ecb_alg);
-blk_ecb_err:
- crypto_unregister_alg(&__aesni_alg);
-__aes_err:
- crypto_unregister_alg(&aesni_alg);
-aes_err:
-fpu_err:
- return err;
+ for (i = 0; i < ARRAY_SIZE(aesni_algs); i++)
+ INIT_LIST_HEAD(&aesni_algs[i].cra_list);
+
+ return crypto_register_algs(aesni_algs, ARRAY_SIZE(aesni_algs));
}
static void __exit aesni_exit(void)
{
-#ifdef HAS_XTS
- crypto_unregister_alg(&ablk_xts_alg);
-#endif
-#ifdef HAS_PCBC
- crypto_unregister_alg(&ablk_pcbc_alg);
-#endif
-#ifdef HAS_LRW
- crypto_unregister_alg(&ablk_lrw_alg);
-#endif
-#ifdef CONFIG_X86_64
-#ifdef HAS_CTR
- crypto_unregister_alg(&ablk_rfc3686_ctr_alg);
-#endif
- crypto_unregister_alg(&rfc4106_alg);
- crypto_unregister_alg(&__rfc4106_alg);
- crypto_unregister_alg(&ablk_ctr_alg);
- crypto_unregister_alg(&blk_ctr_alg);
-#endif
- crypto_unregister_alg(&ablk_cbc_alg);
- crypto_unregister_alg(&ablk_ecb_alg);
- crypto_unregister_alg(&blk_cbc_alg);
- crypto_unregister_alg(&blk_ecb_alg);
- crypto_unregister_alg(&__aesni_alg);
- crypto_unregister_alg(&aesni_alg);
+ crypto_unregister_algs(aesni_algs, ARRAY_SIZE(aesni_algs));
crypto_fpu_exit();
}
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
index 0b3f2354f6aa..98bd70faccc5 100644
--- a/arch/x86/ia32/ia32_signal.c
+++ b/arch/x86/ia32/ia32_signal.c
@@ -131,18 +131,8 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
asmlinkage long sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
{
sigset_t blocked;
-
- current->saved_sigmask = current->blocked;
-
- mask &= _BLOCKABLE;
siginitset(&blocked, mask);
- set_current_blocked(&blocked);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
-
- set_restore_sigmask();
- return -ERESTARTNOHAND;
+ return sigsuspend(&blocked);
}
asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index e3e734005e19..20e5f7ba0e6b 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -13,6 +13,7 @@
#include <asm/thread_info.h>
#include <asm/segment.h>
#include <asm/irqflags.h>
+#include <asm/asm.h>
#include <linux/linkage.h>
#include <linux/err.h>
@@ -146,9 +147,7 @@ ENTRY(ia32_sysenter_target)
/* no need to do an access_ok check here because rbp has been
32bit zero extended */
1: movl (%rbp),%ebp
- .section __ex_table,"a"
- .quad 1b,ia32_badarg
- .previous
+ _ASM_EXTABLE(1b,ia32_badarg)
orl $TS_COMPAT,TI_status+THREAD_INFO(%rsp,RIP-ARGOFFSET)
testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
CFI_REMEMBER_STATE
@@ -303,9 +302,7 @@ ENTRY(ia32_cstar_target)
32bit zero extended */
/* hardware stack frame is complete now */
1: movl (%r8),%r9d
- .section __ex_table,"a"
- .quad 1b,ia32_badarg
- .previous
+ _ASM_EXTABLE(1b,ia32_badarg)
orl $TS_COMPAT,TI_status+THREAD_INFO(%rsp,RIP-ARGOFFSET)
testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags+THREAD_INFO(%rsp,RIP-ARGOFFSET)
CFI_REMEMBER_STATE
diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c
index aec2202a596c..4540bece0946 100644
--- a/arch/x86/ia32/sys_ia32.c
+++ b/arch/x86/ia32/sys_ia32.c
@@ -71,8 +71,8 @@ static int cp_stat64(struct stat64 __user *ubuf, struct kstat *stat)
{
typeof(ubuf->st_uid) uid = 0;
typeof(ubuf->st_gid) gid = 0;
- SET_UID(uid, stat->uid);
- SET_GID(gid, stat->gid);
+ SET_UID(uid, from_kuid_munged(current_user_ns(), stat->uid));
+ SET_GID(gid, from_kgid_munged(current_user_ns(), stat->gid));
if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct stat64)) ||
__put_user(huge_encode_dev(stat->dev), &ubuf->st_dev) ||
__put_user(stat->ino, &ubuf->__st_ino) ||
@@ -287,11 +287,6 @@ asmlinkage long sys32_sigaction(int sig, struct old_sigaction32 __user *act,
return ret;
}
-asmlinkage long sys32_alarm(unsigned int seconds)
-{
- return alarm_setitimer(seconds);
-}
-
asmlinkage long sys32_waitpid(compat_pid_t pid, unsigned int *stat_addr,
int options)
{
@@ -300,11 +295,6 @@ asmlinkage long sys32_waitpid(compat_pid_t pid, unsigned int *stat_addr,
/* 32-bit timeval and related flotsam. */
-asmlinkage long sys32_sysfs(int option, u32 arg1, u32 arg2)
-{
- return sys_sysfs(option, arg1, arg2);
-}
-
asmlinkage long sys32_sched_rr_get_interval(compat_pid_t pid,
struct compat_timespec __user *interval)
{
@@ -375,19 +365,6 @@ asmlinkage long sys32_pwrite(unsigned int fd, const char __user *ubuf,
}
-asmlinkage long sys32_personality(unsigned long personality)
-{
- int ret;
-
- if (personality(current->personality) == PER_LINUX32 &&
- personality == PER_LINUX)
- personality = PER_LINUX32;
- ret = sys_personality(personality);
- if (ret == PER_LINUX32)
- ret = PER_LINUX;
- return ret;
-}
-
asmlinkage long sys32_sendfile(int out_fd, int in_fd,
compat_off_t __user *offset, s32 count)
{
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index d85410171260..eaff4790ed96 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -138,6 +138,11 @@ static inline void native_apic_msr_write(u32 reg, u32 v)
wrmsr(APIC_BASE_MSR + (reg >> 4), v, 0);
}
+static inline void native_apic_msr_eoi_write(u32 reg, u32 v)
+{
+ wrmsr(APIC_BASE_MSR + (APIC_EOI >> 4), APIC_EOI_ACK, 0);
+}
+
static inline u32 native_apic_msr_read(u32 reg)
{
u64 msr;
@@ -351,6 +356,14 @@ struct apic {
/* apic ops */
u32 (*read)(u32 reg);
void (*write)(u32 reg, u32 v);
+ /*
+ * ->eoi_write() has the same signature as ->write().
+ *
+ * Drivers can support both ->eoi_write() and ->write() by passing the same
+ * callback value. Kernel can override ->eoi_write() and fall back
+ * on write for EOI.
+ */
+ void (*eoi_write)(u32 reg, u32 v);
u64 (*icr_read)(void);
void (*icr_write)(u32 low, u32 high);
void (*wait_icr_idle)(void);
@@ -426,6 +439,11 @@ static inline void apic_write(u32 reg, u32 val)
apic->write(reg, val);
}
+static inline void apic_eoi(void)
+{
+ apic->eoi_write(APIC_EOI, APIC_EOI_ACK);
+}
+
static inline u64 apic_icr_read(void)
{
return apic->icr_read();
@@ -450,6 +468,7 @@ static inline u32 safe_apic_wait_icr_idle(void)
static inline u32 apic_read(u32 reg) { return 0; }
static inline void apic_write(u32 reg, u32 val) { }
+static inline void apic_eoi(void) { }
static inline u64 apic_icr_read(void) { return 0; }
static inline void apic_icr_write(u32 low, u32 high) { }
static inline void apic_wait_icr_idle(void) { }
@@ -463,9 +482,7 @@ static inline void ack_APIC_irq(void)
* ack_APIC_irq() actually gets compiled as a single instruction
* ... yummie.
*/
-
- /* Docs say use 0 for future compatibility */
- apic_write(APIC_EOI, 0);
+ apic_eoi();
}
static inline unsigned default_get_apic_id(unsigned long x)
diff --git a/arch/x86/include/asm/apicdef.h b/arch/x86/include/asm/apicdef.h
index 134bba00df09..c46bb99d5fb2 100644
--- a/arch/x86/include/asm/apicdef.h
+++ b/arch/x86/include/asm/apicdef.h
@@ -37,7 +37,7 @@
#define APIC_ARBPRI_MASK 0xFFu
#define APIC_PROCPRI 0xA0
#define APIC_EOI 0xB0
-#define APIC_EIO_ACK 0x0
+#define APIC_EOI_ACK 0x0 /* Docs say 0 for future compat. */
#define APIC_RRR 0xC0
#define APIC_LDR 0xD0
#define APIC_LDR_MASK (0xFFu << 24)
diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h
index 9412d6558c88..1c2d247f65ce 100644
--- a/arch/x86/include/asm/asm.h
+++ b/arch/x86/include/asm/asm.h
@@ -4,11 +4,9 @@
#ifdef __ASSEMBLY__
# define __ASM_FORM(x) x
# define __ASM_FORM_COMMA(x) x,
-# define __ASM_EX_SEC .section __ex_table, "a"
#else
# define __ASM_FORM(x) " " #x " "
# define __ASM_FORM_COMMA(x) " " #x ","
-# define __ASM_EX_SEC " .section __ex_table,\"a\"\n"
#endif
#ifdef CONFIG_X86_32
@@ -42,17 +40,33 @@
/* Exception table entry */
#ifdef __ASSEMBLY__
-# define _ASM_EXTABLE(from,to) \
- __ASM_EX_SEC ; \
- _ASM_ALIGN ; \
- _ASM_PTR from , to ; \
- .previous
+# define _ASM_EXTABLE(from,to) \
+ .pushsection "__ex_table","a" ; \
+ .balign 8 ; \
+ .long (from) - . ; \
+ .long (to) - . ; \
+ .popsection
+
+# define _ASM_EXTABLE_EX(from,to) \
+ .pushsection "__ex_table","a" ; \
+ .balign 8 ; \
+ .long (from) - . ; \
+ .long (to) - . + 0x7ffffff0 ; \
+ .popsection
#else
-# define _ASM_EXTABLE(from,to) \
- __ASM_EX_SEC \
- _ASM_ALIGN "\n" \
- _ASM_PTR #from "," #to "\n" \
- " .previous\n"
+# define _ASM_EXTABLE(from,to) \
+ " .pushsection \"__ex_table\",\"a\"\n" \
+ " .balign 8\n" \
+ " .long (" #from ") - .\n" \
+ " .long (" #to ") - .\n" \
+ " .popsection\n"
+
+# define _ASM_EXTABLE_EX(from,to) \
+ " .pushsection \"__ex_table\",\"a\"\n" \
+ " .balign 8\n" \
+ " .long (" #from ") - .\n" \
+ " .long (" #to ") - . + 0x7ffffff0\n" \
+ " .popsection\n"
#endif
#endif /* _ASM_X86_ASM_H */
diff --git a/arch/x86/include/asm/atomic64_32.h b/arch/x86/include/asm/atomic64_32.h
index 198119910da5..b154de75c90c 100644
--- a/arch/x86/include/asm/atomic64_32.h
+++ b/arch/x86/include/asm/atomic64_32.h
@@ -63,7 +63,7 @@ ATOMIC64_DECL(add_unless);
/**
* atomic64_cmpxchg - cmpxchg atomic64 variable
- * @p: pointer to type atomic64_t
+ * @v: pointer to type atomic64_t
* @o: expected value
* @n: new value
*
@@ -98,7 +98,7 @@ static inline long long atomic64_xchg(atomic64_t *v, long long n)
/**
* atomic64_set - set atomic64 variable
* @v: pointer to type atomic64_t
- * @n: value to assign
+ * @i: value to assign
*
* Atomically sets the value of @v to @n.
*/
@@ -200,7 +200,7 @@ static inline long long atomic64_sub(long long i, atomic64_t *v)
* atomic64_sub_and_test - subtract value from variable and test result
* @i: integer value to subtract
* @v: pointer to type atomic64_t
- *
+ *
* Atomically subtracts @i from @v and returns
* true if the result is zero, or false for all
* other cases.
@@ -224,9 +224,9 @@ static inline void atomic64_inc(atomic64_t *v)
/**
* atomic64_dec - decrement atomic64 variable
- * @ptr: pointer to type atomic64_t
+ * @v: pointer to type atomic64_t
*
- * Atomically decrements @ptr by 1.
+ * Atomically decrements @v by 1.
*/
static inline void atomic64_dec(atomic64_t *v)
{
diff --git a/arch/x86/include/asm/bootparam.h b/arch/x86/include/asm/bootparam.h
index 2f90c51cc49d..eb45aa6b1f27 100644
--- a/arch/x86/include/asm/bootparam.h
+++ b/arch/x86/include/asm/bootparam.h
@@ -112,7 +112,8 @@ struct boot_params {
__u8 e820_entries; /* 0x1e8 */
__u8 eddbuf_entries; /* 0x1e9 */
__u8 edd_mbr_sig_buf_entries; /* 0x1ea */
- __u8 _pad6[6]; /* 0x1eb */
+ __u8 kbd_status; /* 0x1eb */
+ __u8 _pad6[5]; /* 0x1ec */
struct setup_header hdr; /* setup header */ /* 0x1f1 */
__u8 _pad7[0x290-0x1f1-sizeof(struct setup_header)];
__u32 edd_mbr_sig_buffer[EDD_MBR_SIG_MAX]; /* 0x290 */
diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h
index d6805798d6fc..fedf32b73e65 100644
--- a/arch/x86/include/asm/compat.h
+++ b/arch/x86/include/asm/compat.h
@@ -229,7 +229,7 @@ static inline void __user *arch_compat_alloc_user_space(long len)
sp = task_pt_regs(current)->sp;
} else {
/* -128 for the x32 ABI redzone */
- sp = percpu_read(old_rsp) - 128;
+ sp = this_cpu_read(old_rsp) - 128;
}
return (void __user *)round_down(sp - len, 16);
diff --git a/arch/x86/include/asm/current.h b/arch/x86/include/asm/current.h
index 4d447b732d82..9476c04ee635 100644
--- a/arch/x86/include/asm/current.h
+++ b/arch/x86/include/asm/current.h
@@ -11,7 +11,7 @@ DECLARE_PER_CPU(struct task_struct *, current_task);
static __always_inline struct task_struct *get_current(void)
{
- return percpu_read_stable(current_task);
+ return this_cpu_read_stable(current_task);
}
#define current get_current()
diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h
index e95822d683f4..8bf1c06070d5 100644
--- a/arch/x86/include/asm/desc.h
+++ b/arch/x86/include/asm/desc.h
@@ -6,6 +6,7 @@
#include <asm/mmu.h>
#include <linux/smp.h>
+#include <linux/percpu.h>
static inline void fill_ldt(struct desc_struct *desc, const struct user_desc *info)
{
diff --git a/arch/x86/include/asm/device.h b/arch/x86/include/asm/device.h
index 63a2a03d7d51..93e1c55f14ab 100644
--- a/arch/x86/include/asm/device.h
+++ b/arch/x86/include/asm/device.h
@@ -5,8 +5,8 @@ struct dev_archdata {
#ifdef CONFIG_ACPI
void *acpi_handle;
#endif
-#ifdef CONFIG_X86_64
-struct dma_map_ops *dma_ops;
+#ifdef CONFIG_X86_DEV_DMA_OPS
+ struct dma_map_ops *dma_ops;
#endif
#if defined(CONFIG_INTEL_IOMMU) || defined(CONFIG_AMD_IOMMU)
void *iommu; /* hook for IOMMU specific extension */
diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h
index 4b4331d71935..61c0bd25845a 100644
--- a/arch/x86/include/asm/dma-mapping.h
+++ b/arch/x86/include/asm/dma-mapping.h
@@ -30,7 +30,7 @@ extern struct dma_map_ops *dma_ops;
static inline struct dma_map_ops *get_dma_ops(struct device *dev)
{
-#ifdef CONFIG_X86_32
+#ifndef CONFIG_X86_DEV_DMA_OPS
return dma_ops;
#else
if (unlikely(!dev) || !dev->archdata.dma_ops)
@@ -62,6 +62,12 @@ extern void *dma_generic_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_addr, gfp_t flag,
struct dma_attrs *attrs);
+#ifdef CONFIG_X86_DMA_REMAP /* Platform code defines bridge-specific code */
+extern bool dma_capable(struct device *dev, dma_addr_t addr, size_t size);
+extern dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr);
+extern phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr);
+#else
+
static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
{
if (!dev->dma_mask)
@@ -79,6 +85,7 @@ static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
{
return daddr;
}
+#endif /* CONFIG_X86_DMA_REMAP */
static inline void
dma_cache_sync(struct device *dev, void *vaddr, size_t size,
diff --git a/arch/x86/include/asm/fpu-internal.h b/arch/x86/include/asm/fpu-internal.h
index 4fa88154e4de..75f4c6d6a331 100644
--- a/arch/x86/include/asm/fpu-internal.h
+++ b/arch/x86/include/asm/fpu-internal.h
@@ -290,14 +290,14 @@ static inline int __thread_has_fpu(struct task_struct *tsk)
static inline void __thread_clear_has_fpu(struct task_struct *tsk)
{
tsk->thread.fpu.has_fpu = 0;
- percpu_write(fpu_owner_task, NULL);
+ this_cpu_write(fpu_owner_task, NULL);
}
/* Must be paired with a 'clts' before! */
static inline void __thread_set_has_fpu(struct task_struct *tsk)
{
tsk->thread.fpu.has_fpu = 1;
- percpu_write(fpu_owner_task, tsk);
+ this_cpu_write(fpu_owner_task, tsk);
}
/*
@@ -344,7 +344,7 @@ typedef struct { int preload; } fpu_switch_t;
*/
static inline int fpu_lazy_restore(struct task_struct *new, unsigned int cpu)
{
- return new == percpu_read_stable(fpu_owner_task) &&
+ return new == this_cpu_read_stable(fpu_owner_task) &&
cpu == new->thread.fpu.last_cpu;
}
diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h
index 268c783ab1c0..18d9005d9e4f 100644
--- a/arch/x86/include/asm/ftrace.h
+++ b/arch/x86/include/asm/ftrace.h
@@ -34,6 +34,7 @@
#ifndef __ASSEMBLY__
extern void mcount(void);
+extern int modifying_ftrace_code;
static inline unsigned long ftrace_call_adjust(unsigned long addr)
{
@@ -50,6 +51,8 @@ struct dyn_arch_ftrace {
/* No extra data needed for x86 */
};
+int ftrace_int3_handler(struct pt_regs *regs);
+
#endif /* CONFIG_DYNAMIC_FTRACE */
#endif /* __ASSEMBLY__ */
#endif /* CONFIG_FUNCTION_TRACER */
diff --git a/arch/x86/include/asm/gpio.h b/arch/x86/include/asm/gpio.h
index 91d915a65259..b3799d88ffcf 100644
--- a/arch/x86/include/asm/gpio.h
+++ b/arch/x86/include/asm/gpio.h
@@ -1,53 +1,4 @@
-/*
- * Generic GPIO API implementation for x86.
- *
- * Derived from the generic GPIO API for powerpc:
- *
- * Copyright (c) 2007-2008 MontaVista Software, Inc.
- *
- * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef _ASM_X86_GPIO_H
-#define _ASM_X86_GPIO_H
-
-#include <asm-generic/gpio.h>
-
-#ifdef CONFIG_GPIOLIB
-
-/*
- * Just call gpiolib.
- */
-static inline int gpio_get_value(unsigned int gpio)
-{
- return __gpio_get_value(gpio);
-}
-
-static inline void gpio_set_value(unsigned int gpio, int value)
-{
- __gpio_set_value(gpio, value);
-}
-
-static inline int gpio_cansleep(unsigned int gpio)
-{
- return __gpio_cansleep(gpio);
-}
-
-static inline int gpio_to_irq(unsigned int gpio)
-{
- return __gpio_to_irq(gpio);
-}
-
-static inline int irq_to_gpio(unsigned int irq)
-{
- return -EINVAL;
-}
-
-#endif /* CONFIG_GPIOLIB */
-
-#endif /* _ASM_X86_GPIO_H */
+#ifndef __LINUX_GPIO_H
+#warning Include linux/gpio.h instead of asm/gpio.h
+#include <linux/gpio.h>
+#endif
diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h
index 382f75d735f3..d3895dbf4ddb 100644
--- a/arch/x86/include/asm/hardirq.h
+++ b/arch/x86/include/asm/hardirq.h
@@ -35,14 +35,15 @@ DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
#define __ARCH_IRQ_STAT
-#define inc_irq_stat(member) percpu_inc(irq_stat.member)
+#define inc_irq_stat(member) this_cpu_inc(irq_stat.member)
-#define local_softirq_pending() percpu_read(irq_stat.__softirq_pending)
+#define local_softirq_pending() this_cpu_read(irq_stat.__softirq_pending)
#define __ARCH_SET_SOFTIRQ_PENDING
-#define set_softirq_pending(x) percpu_write(irq_stat.__softirq_pending, (x))
-#define or_softirq_pending(x) percpu_or(irq_stat.__softirq_pending, (x))
+#define set_softirq_pending(x) \
+ this_cpu_write(irq_stat.__softirq_pending, (x))
+#define or_softirq_pending(x) this_cpu_or(irq_stat.__softirq_pending, (x))
extern void ack_bad_irq(unsigned int irq);
diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h
index 2c4943de5150..73d8c5398ea9 100644
--- a/arch/x86/include/asm/io_apic.h
+++ b/arch/x86/include/asm/io_apic.h
@@ -5,7 +5,7 @@
#include <asm/mpspec.h>
#include <asm/apicdef.h>
#include <asm/irq_vectors.h>
-
+#include <asm/x86_init.h>
/*
* Intel IO-APIC support for SMP and UP systems.
*
@@ -21,15 +21,6 @@
#define IO_APIC_REDIR_LEVEL_TRIGGER (1 << 15)
#define IO_APIC_REDIR_MASKED (1 << 16)
-struct io_apic_ops {
- void (*init) (void);
- unsigned int (*read) (unsigned int apic, unsigned int reg);
- void (*write) (unsigned int apic, unsigned int reg, unsigned int value);
- void (*modify)(unsigned int apic, unsigned int reg, unsigned int value);
-};
-
-void __init set_io_apic_ops(const struct io_apic_ops *);
-
/*
* The structure of the IO-APIC:
*/
@@ -156,7 +147,6 @@ struct io_apic_irq_attr;
extern int io_apic_set_pci_routing(struct device *dev, int irq,
struct io_apic_irq_attr *irq_attr);
void setup_IO_APIC_irq_extra(u32 gsi);
-extern void ioapic_and_gsi_init(void);
extern void ioapic_insert_resources(void);
int io_apic_setup_irq_pin_once(unsigned int irq, int node, struct io_apic_irq_attr *attr);
@@ -185,12 +175,29 @@ extern void mp_save_irq(struct mpc_intsrc *m);
extern void disable_ioapic_support(void);
+extern void __init native_io_apic_init_mappings(void);
+extern unsigned int native_io_apic_read(unsigned int apic, unsigned int reg);
+extern void native_io_apic_write(unsigned int apic, unsigned int reg, unsigned int val);
+extern void native_io_apic_modify(unsigned int apic, unsigned int reg, unsigned int val);
+
+static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
+{
+ return x86_io_apic_ops.read(apic, reg);
+}
+
+static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
+{
+ x86_io_apic_ops.write(apic, reg, value);
+}
+static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
+{
+ x86_io_apic_ops.modify(apic, reg, value);
+}
#else /* !CONFIG_X86_IO_APIC */
#define io_apic_assign_pci_irqs 0
#define setup_ioapic_ids_from_mpc x86_init_noop
static const int timer_through_8259 = 0;
-static inline void ioapic_and_gsi_init(void) { }
static inline void ioapic_insert_resources(void) { }
#define gsi_top (NR_IRQS_LEGACY)
static inline int mp_find_ioapic(u32 gsi) { return 0; }
@@ -212,6 +219,10 @@ static inline int restore_ioapic_entries(void)
static inline void mp_save_irq(struct mpc_intsrc *m) { };
static inline void disable_ioapic_support(void) { }
+#define native_io_apic_init_mappings NULL
+#define native_io_apic_read NULL
+#define native_io_apic_write NULL
+#define native_io_apic_modify NULL
#endif
#endif /* _ASM_X86_IO_APIC_H */
diff --git a/arch/x86/include/asm/irq_regs.h b/arch/x86/include/asm/irq_regs.h
index 77843225b7ea..d82250b1debb 100644
--- a/arch/x86/include/asm/irq_regs.h
+++ b/arch/x86/include/asm/irq_regs.h
@@ -15,7 +15,7 @@ DECLARE_PER_CPU(struct pt_regs *, irq_regs);
static inline struct pt_regs *get_irq_regs(void)
{
- return percpu_read(irq_regs);
+ return this_cpu_read(irq_regs);
}
static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs)
@@ -23,7 +23,7 @@ static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs)
struct pt_regs *old_regs;
old_regs = get_irq_regs();
- percpu_write(irq_regs, new_regs);
+ this_cpu_write(irq_regs, new_regs);
return old_regs;
}
diff --git a/arch/x86/include/asm/kbdleds.h b/arch/x86/include/asm/kbdleds.h
new file mode 100644
index 000000000000..f27ac5ff597d
--- /dev/null
+++ b/arch/x86/include/asm/kbdleds.h
@@ -0,0 +1,17 @@
+#ifndef _ASM_X86_KBDLEDS_H
+#define _ASM_X86_KBDLEDS_H
+
+/*
+ * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
+ * This seems a good reason to start with NumLock off. That's why on X86 we
+ * ask the bios for the correct state.
+ */
+
+#include <asm/setup.h>
+
+static inline int kbd_defleds(void)
+{
+ return boot_params.kbd_status & 0x20 ? (1 << VC_NUMLOCK) : 0;
+}
+
+#endif /* _ASM_X86_KBDLEDS_H */
diff --git a/arch/x86/include/asm/kdebug.h b/arch/x86/include/asm/kdebug.h
index d73f1571bde7..2c37aadcbc35 100644
--- a/arch/x86/include/asm/kdebug.h
+++ b/arch/x86/include/asm/kdebug.h
@@ -24,7 +24,6 @@ enum die_val {
extern void printk_address(unsigned long address, int reliable);
extern void die(const char *, struct pt_regs *,long);
extern int __must_check __die(const char *, struct pt_regs *, long);
-extern void show_registers(struct pt_regs *regs);
extern void show_trace(struct task_struct *t, struct pt_regs *regs,
unsigned long *sp, unsigned long bp);
extern void __show_regs(struct pt_regs *regs, int all);
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index e216ba066e79..e5b97be12d2a 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -27,6 +27,7 @@
#include <asm/desc.h>
#include <asm/mtrr.h>
#include <asm/msr-index.h>
+#include <asm/asm.h>
#define KVM_MAX_VCPUS 254
#define KVM_SOFT_MAX_VCPUS 160
@@ -921,9 +922,7 @@ extern bool kvm_rebooting;
__ASM_SIZE(push) " $666b \n\t" \
"call kvm_spurious_fault \n\t" \
".popsection \n\t" \
- ".pushsection __ex_table, \"a\" \n\t" \
- _ASM_PTR " 666b, 667b \n\t" \
- ".popsection"
+ _ASM_EXTABLE(666b, 667b)
#define __kvm_handle_fault_on_reboot(insn) \
____kvm_handle_fault_on_reboot(insn, "")
diff --git a/arch/x86/include/asm/mca.h b/arch/x86/include/asm/mca.h
deleted file mode 100644
index eedbb6cc1efb..000000000000
--- a/arch/x86/include/asm/mca.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8 -*- */
-
-/* Platform specific MCA defines */
-#ifndef _ASM_X86_MCA_H
-#define _ASM_X86_MCA_H
-
-/* Maximal number of MCA slots - actually, some machines have less, but
- * they all have sufficient number of POS registers to cover 8.
- */
-#define MCA_MAX_SLOT_NR 8
-
-/* Most machines have only one MCA bus. The only multiple bus machines
- * I know have at most two */
-#define MAX_MCA_BUSSES 2
-
-#define MCA_PRIMARY_BUS 0
-#define MCA_SECONDARY_BUS 1
-
-/* Dummy slot numbers on primary MCA for integrated functions */
-#define MCA_INTEGSCSI (MCA_MAX_SLOT_NR)
-#define MCA_INTEGVIDEO (MCA_MAX_SLOT_NR+1)
-#define MCA_MOTHERBOARD (MCA_MAX_SLOT_NR+2)
-
-/* Dummy POS values for integrated functions */
-#define MCA_DUMMY_POS_START 0x10000
-#define MCA_INTEGSCSI_POS (MCA_DUMMY_POS_START+1)
-#define MCA_INTEGVIDEO_POS (MCA_DUMMY_POS_START+2)
-#define MCA_MOTHERBOARD_POS (MCA_DUMMY_POS_START+3)
-
-/* MCA registers */
-
-#define MCA_MOTHERBOARD_SETUP_REG 0x94
-#define MCA_ADAPTER_SETUP_REG 0x96
-#define MCA_POS_REG(n) (0x100+(n))
-
-#define MCA_ENABLED 0x01 /* POS 2, set if adapter enabled */
-
-/* Max number of adapters, including both slots and various integrated
- * things.
- */
-#define MCA_NUMADAPTERS (MCA_MAX_SLOT_NR+3)
-
-#endif /* _ASM_X86_MCA_H */
diff --git a/arch/x86/include/asm/mca_dma.h b/arch/x86/include/asm/mca_dma.h
deleted file mode 100644
index 45271aef82dd..000000000000
--- a/arch/x86/include/asm/mca_dma.h
+++ /dev/null
@@ -1,201 +0,0 @@
-#ifndef _ASM_X86_MCA_DMA_H
-#define _ASM_X86_MCA_DMA_H
-
-#include <asm/io.h>
-#include <linux/ioport.h>
-
-/*
- * Microchannel specific DMA stuff. DMA on an MCA machine is fairly similar to
- * standard PC dma, but it certainly has its quirks. DMA register addresses
- * are in a different place and there are some added functions. Most of this
- * should be pretty obvious on inspection. Note that the user must divide
- * count by 2 when using 16-bit dma; that is not handled by these functions.
- *
- * Ramen Noodles are yummy.
- *
- * 1998 Tymm Twillman <tymm@computer.org>
- */
-
-/*
- * Registers that are used by the DMA controller; FN is the function register
- * (tell the controller what to do) and EXE is the execution register (how
- * to do it)
- */
-
-#define MCA_DMA_REG_FN 0x18
-#define MCA_DMA_REG_EXE 0x1A
-
-/*
- * Functions that the DMA controller can do
- */
-
-#define MCA_DMA_FN_SET_IO 0x00
-#define MCA_DMA_FN_SET_ADDR 0x20
-#define MCA_DMA_FN_GET_ADDR 0x30
-#define MCA_DMA_FN_SET_COUNT 0x40
-#define MCA_DMA_FN_GET_COUNT 0x50
-#define MCA_DMA_FN_GET_STATUS 0x60
-#define MCA_DMA_FN_SET_MODE 0x70
-#define MCA_DMA_FN_SET_ARBUS 0x80
-#define MCA_DMA_FN_MASK 0x90
-#define MCA_DMA_FN_RESET_MASK 0xA0
-#define MCA_DMA_FN_MASTER_CLEAR 0xD0
-
-/*
- * Modes (used by setting MCA_DMA_FN_MODE in the function register)
- *
- * Note that the MODE_READ is read from memory (write to device), and
- * MODE_WRITE is vice-versa.
- */
-
-#define MCA_DMA_MODE_XFER 0x04 /* read by default */
-#define MCA_DMA_MODE_READ 0x04 /* same as XFER */
-#define MCA_DMA_MODE_WRITE 0x08 /* OR with MODE_XFER to use */
-#define MCA_DMA_MODE_IO 0x01 /* DMA from IO register */
-#define MCA_DMA_MODE_16 0x40 /* 16 bit xfers */
-
-
-/**
- * mca_enable_dma - channel to enable DMA on
- * @dmanr: DMA channel
- *
- * Enable the MCA bus DMA on a channel. This can be called from
- * IRQ context.
- */
-
-static inline void mca_enable_dma(unsigned int dmanr)
-{
- outb(MCA_DMA_FN_RESET_MASK | dmanr, MCA_DMA_REG_FN);
-}
-
-/**
- * mca_disble_dma - channel to disable DMA on
- * @dmanr: DMA channel
- *
- * Enable the MCA bus DMA on a channel. This can be called from
- * IRQ context.
- */
-
-static inline void mca_disable_dma(unsigned int dmanr)
-{
- outb(MCA_DMA_FN_MASK | dmanr, MCA_DMA_REG_FN);
-}
-
-/**
- * mca_set_dma_addr - load a 24bit DMA address
- * @dmanr: DMA channel
- * @a: 24bit bus address
- *
- * Load the address register in the DMA controller. This has a 24bit
- * limitation (16Mb).
- */
-
-static inline void mca_set_dma_addr(unsigned int dmanr, unsigned int a)
-{
- outb(MCA_DMA_FN_SET_ADDR | dmanr, MCA_DMA_REG_FN);
- outb(a & 0xff, MCA_DMA_REG_EXE);
- outb((a >> 8) & 0xff, MCA_DMA_REG_EXE);
- outb((a >> 16) & 0xff, MCA_DMA_REG_EXE);
-}
-
-/**
- * mca_get_dma_addr - load a 24bit DMA address
- * @dmanr: DMA channel
- *
- * Read the address register in the DMA controller. This has a 24bit
- * limitation (16Mb). The return is a bus address.
- */
-
-static inline unsigned int mca_get_dma_addr(unsigned int dmanr)
-{
- unsigned int addr;
-
- outb(MCA_DMA_FN_GET_ADDR | dmanr, MCA_DMA_REG_FN);
- addr = inb(MCA_DMA_REG_EXE);
- addr |= inb(MCA_DMA_REG_EXE) << 8;
- addr |= inb(MCA_DMA_REG_EXE) << 16;
-
- return addr;
-}
-
-/**
- * mca_set_dma_count - load a 16bit transfer count
- * @dmanr: DMA channel
- * @count: count
- *
- * Set the DMA count for this channel. This can be up to 64Kbytes.
- * Setting a count of zero will not do what you expect.
- */
-
-static inline void mca_set_dma_count(unsigned int dmanr, unsigned int count)
-{
- count--; /* transfers one more than count -- correct for this */
-
- outb(MCA_DMA_FN_SET_COUNT | dmanr, MCA_DMA_REG_FN);
- outb(count & 0xff, MCA_DMA_REG_EXE);
- outb((count >> 8) & 0xff, MCA_DMA_REG_EXE);
-}
-
-/**
- * mca_get_dma_residue - get the remaining bytes to transfer
- * @dmanr: DMA channel
- *
- * This function returns the number of bytes left to transfer
- * on this DMA channel.
- */
-
-static inline unsigned int mca_get_dma_residue(unsigned int dmanr)
-{
- unsigned short count;
-
- outb(MCA_DMA_FN_GET_COUNT | dmanr, MCA_DMA_REG_FN);
- count = 1 + inb(MCA_DMA_REG_EXE);
- count += inb(MCA_DMA_REG_EXE) << 8;
-
- return count;
-}
-
-/**
- * mca_set_dma_io - set the port for an I/O transfer
- * @dmanr: DMA channel
- * @io_addr: an I/O port number
- *
- * Unlike the ISA bus DMA controllers the DMA on MCA bus can transfer
- * with an I/O port target.
- */
-
-static inline void mca_set_dma_io(unsigned int dmanr, unsigned int io_addr)
-{
- /*
- * DMA from a port address -- set the io address
- */
-
- outb(MCA_DMA_FN_SET_IO | dmanr, MCA_DMA_REG_FN);
- outb(io_addr & 0xff, MCA_DMA_REG_EXE);
- outb((io_addr >> 8) & 0xff, MCA_DMA_REG_EXE);
-}
-
-/**
- * mca_set_dma_mode - set the DMA mode
- * @dmanr: DMA channel
- * @mode: mode to set
- *
- * The DMA controller supports several modes. The mode values you can
- * set are-
- *
- * %MCA_DMA_MODE_READ when reading from the DMA device.
- *
- * %MCA_DMA_MODE_WRITE to writing to the DMA device.
- *
- * %MCA_DMA_MODE_IO to do DMA to or from an I/O port.
- *
- * %MCA_DMA_MODE_16 to do 16bit transfers.
- */
-
-static inline void mca_set_dma_mode(unsigned int dmanr, unsigned int mode)
-{
- outb(MCA_DMA_FN_SET_MODE | dmanr, MCA_DMA_REG_FN);
- outb(mode, MCA_DMA_REG_EXE);
-}
-
-#endif /* _ASM_X86_MCA_DMA_H */
diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h
index 69021528b43c..cdbf36776106 100644
--- a/arch/x86/include/asm/mmu_context.h
+++ b/arch/x86/include/asm/mmu_context.h
@@ -25,8 +25,8 @@ void destroy_context(struct mm_struct *mm);
static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
{
#ifdef CONFIG_SMP
- if (percpu_read(cpu_tlbstate.state) == TLBSTATE_OK)
- percpu_write(cpu_tlbstate.state, TLBSTATE_LAZY);
+ if (this_cpu_read(cpu_tlbstate.state) == TLBSTATE_OK)
+ this_cpu_write(cpu_tlbstate.state, TLBSTATE_LAZY);
#endif
}
@@ -37,8 +37,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
if (likely(prev != next)) {
#ifdef CONFIG_SMP
- percpu_write(cpu_tlbstate.state, TLBSTATE_OK);
- percpu_write(cpu_tlbstate.active_mm, next);
+ this_cpu_write(cpu_tlbstate.state, TLBSTATE_OK);
+ this_cpu_write(cpu_tlbstate.active_mm, next);
#endif
cpumask_set_cpu(cpu, mm_cpumask(next));
@@ -56,8 +56,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
}
#ifdef CONFIG_SMP
else {
- percpu_write(cpu_tlbstate.state, TLBSTATE_OK);
- BUG_ON(percpu_read(cpu_tlbstate.active_mm) != next);
+ this_cpu_write(cpu_tlbstate.state, TLBSTATE_OK);
+ BUG_ON(this_cpu_read(cpu_tlbstate.active_mm) != next);
if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next))) {
/* We were in lazy tlb mode and leave_mm disabled
diff --git a/arch/x86/include/asm/mmzone_32.h b/arch/x86/include/asm/mmzone_32.h
index 55728e121473..eb05fb3b02fb 100644
--- a/arch/x86/include/asm/mmzone_32.h
+++ b/arch/x86/include/asm/mmzone_32.h
@@ -61,10 +61,4 @@ static inline int pfn_valid(int pfn)
#endif /* CONFIG_DISCONTIGMEM */
-#ifdef CONFIG_NEED_MULTIPLE_NODES
-/* always use node 0 for bootmem on this numa platform */
-#define bootmem_arch_preferred_node(__bdata, size, align, goal, limit) \
- (NODE_DATA(0)->bdata)
-#endif /* CONFIG_NEED_MULTIPLE_NODES */
-
#endif /* _ASM_X86_MMZONE_32_H */
diff --git a/arch/x86/include/asm/mpspec.h b/arch/x86/include/asm/mpspec.h
index 9c7d95f6174b..3e2f42a4b872 100644
--- a/arch/x86/include/asm/mpspec.h
+++ b/arch/x86/include/asm/mpspec.h
@@ -40,7 +40,7 @@ extern int quad_local_to_mp_bus_id [NR_CPUS/4][4];
#endif /* CONFIG_X86_64 */
-#if defined(CONFIG_MCA) || defined(CONFIG_EISA)
+#ifdef CONFIG_EISA
extern int mp_bus_id_to_type[MAX_MP_BUSSES];
#endif
diff --git a/arch/x86/include/asm/mpspec_def.h b/arch/x86/include/asm/mpspec_def.h
index c0a955a9a087..b31f8c098271 100644
--- a/arch/x86/include/asm/mpspec_def.h
+++ b/arch/x86/include/asm/mpspec_def.h
@@ -84,7 +84,7 @@ struct mpc_bus {
#define BUSTYPE_EISA "EISA"
#define BUSTYPE_ISA "ISA"
#define BUSTYPE_INTERN "INTERN" /* Internal BUS */
-#define BUSTYPE_MCA "MCA"
+#define BUSTYPE_MCA "MCA" /* Obsolete */
#define BUSTYPE_VL "VL" /* Local bus */
#define BUSTYPE_PCI "PCI"
#define BUSTYPE_PCMCIA "PCMCIA"
@@ -169,6 +169,5 @@ enum mp_bustype {
MP_BUS_ISA = 1,
MP_BUS_EISA,
MP_BUS_PCI,
- MP_BUS_MCA,
};
#endif /* _ASM_X86_MPSPEC_DEF_H */
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index ccb805966f68..957ec87385af 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -134,6 +134,8 @@
#define MSR_AMD64_IBSFETCHCTL 0xc0011030
#define MSR_AMD64_IBSFETCHLINAD 0xc0011031
#define MSR_AMD64_IBSFETCHPHYSAD 0xc0011032
+#define MSR_AMD64_IBSFETCH_REG_COUNT 3
+#define MSR_AMD64_IBSFETCH_REG_MASK ((1UL<<MSR_AMD64_IBSFETCH_REG_COUNT)-1)
#define MSR_AMD64_IBSOPCTL 0xc0011033
#define MSR_AMD64_IBSOPRIP 0xc0011034
#define MSR_AMD64_IBSOPDATA 0xc0011035
@@ -141,8 +143,11 @@
#define MSR_AMD64_IBSOPDATA3 0xc0011037
#define MSR_AMD64_IBSDCLINAD 0xc0011038
#define MSR_AMD64_IBSDCPHYSAD 0xc0011039
+#define MSR_AMD64_IBSOP_REG_COUNT 7
+#define MSR_AMD64_IBSOP_REG_MASK ((1UL<<MSR_AMD64_IBSOP_REG_COUNT)-1)
#define MSR_AMD64_IBSCTL 0xc001103a
#define MSR_AMD64_IBSBRTARGET 0xc001103b
+#define MSR_AMD64_IBS_REG_COUNT_MAX 8 /* includes MSR_AMD64_IBSBRTARGET */
/* Fam 15h MSRs */
#define MSR_F15H_PERF_CTL 0xc0010200
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index 95203d40ffdd..084ef95274cd 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -169,14 +169,7 @@ static inline int wrmsr_safe(unsigned msr, unsigned low, unsigned high)
return native_write_msr_safe(msr, low, high);
}
-/*
- * rdmsr with exception handling.
- *
- * Please note that the exception handling works only after we've
- * switched to the "smart" #GP handler in trap_init() which knows about
- * exception tables - using this macro earlier than that causes machine
- * hangs on boxes which do not implement the @msr in the first argument.
- */
+/* rdmsr with exception handling */
#define rdmsr_safe(msr, p1, p2) \
({ \
int __err; \
diff --git a/arch/x86/include/asm/nops.h b/arch/x86/include/asm/nops.h
index 405b4032a60b..aff2b3356101 100644
--- a/arch/x86/include/asm/nops.h
+++ b/arch/x86/include/asm/nops.h
@@ -87,7 +87,11 @@
#define P6_NOP8 0x0f,0x1f,0x84,0x00,0,0,0,0
#define P6_NOP5_ATOMIC P6_NOP5
+#ifdef __ASSEMBLY__
+#define _ASM_MK_NOP(x) .byte x
+#else
#define _ASM_MK_NOP(x) ".byte " __stringify(x) "\n"
+#endif
#if defined(CONFIG_MK7)
#define ASM_NOP1 _ASM_MK_NOP(K7_NOP1)
diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index aa0f91308367..6cbbabf52707 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -1023,10 +1023,8 @@ extern void default_banner(void);
call PARA_INDIRECT(pv_cpu_ops+PV_CPU_swapgs) \
)
-#define GET_CR2_INTO_RCX \
- call PARA_INDIRECT(pv_mmu_ops+PV_MMU_read_cr2); \
- movq %rax, %rcx; \
- xorq %rax, %rax;
+#define GET_CR2_INTO_RAX \
+ call PARA_INDIRECT(pv_mmu_ops+PV_MMU_read_cr2)
#define PARAVIRT_ADJUST_EXCEPTION_FRAME \
PARA_SITE(PARA_PATCH(pv_irq_ops, PV_IRQ_adjust_exception_frame), \
diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h
index 7a11910a63c4..d9b8e3f7f42a 100644
--- a/arch/x86/include/asm/percpu.h
+++ b/arch/x86/include/asm/percpu.h
@@ -46,7 +46,7 @@
#ifdef CONFIG_SMP
#define __percpu_prefix "%%"__stringify(__percpu_seg)":"
-#define __my_cpu_offset percpu_read(this_cpu_off)
+#define __my_cpu_offset this_cpu_read(this_cpu_off)
/*
* Compared to the generic __my_cpu_offset version, the following
@@ -351,23 +351,15 @@ do { \
})
/*
- * percpu_read() makes gcc load the percpu variable every time it is
- * accessed while percpu_read_stable() allows the value to be cached.
- * percpu_read_stable() is more efficient and can be used if its value
+ * this_cpu_read() makes gcc load the percpu variable every time it is
+ * accessed while this_cpu_read_stable() allows the value to be cached.
+ * this_cpu_read_stable() is more efficient and can be used if its value
* is guaranteed to be valid across cpus. The current users include
* get_current() and get_thread_info() both of which are actually
* per-thread variables implemented as per-cpu variables and thus
* stable for the duration of the respective task.
*/
-#define percpu_read(var) percpu_from_op("mov", var, "m" (var))
-#define percpu_read_stable(var) percpu_from_op("mov", var, "p" (&(var)))
-#define percpu_write(var, val) percpu_to_op("mov", var, val)
-#define percpu_add(var, val) percpu_add_op(var, val)
-#define percpu_sub(var, val) percpu_add_op(var, -(val))
-#define percpu_and(var, val) percpu_to_op("and", var, val)
-#define percpu_or(var, val) percpu_to_op("or", var, val)
-#define percpu_xor(var, val) percpu_to_op("xor", var, val)
-#define percpu_inc(var) percpu_unary_op("inc", var)
+#define this_cpu_read_stable(var) percpu_from_op("mov", var, "p" (&(var)))
#define __this_cpu_read_1(pcp) percpu_from_op("mov", (pcp), "m"(pcp))
#define __this_cpu_read_2(pcp) percpu_from_op("mov", (pcp), "m"(pcp))
@@ -512,7 +504,11 @@ static __always_inline int x86_this_cpu_constant_test_bit(unsigned int nr,
{
unsigned long __percpu *a = (unsigned long *)addr + nr / BITS_PER_LONG;
- return ((1UL << (nr % BITS_PER_LONG)) & percpu_read(*a)) != 0;
+#ifdef CONFIG_X86_64
+ return ((1UL << (nr % BITS_PER_LONG)) & __this_cpu_read_8(*a)) != 0;
+#else
+ return ((1UL << (nr % BITS_PER_LONG)) & __this_cpu_read_4(*a)) != 0;
+#endif
}
static inline int x86_this_cpu_variable_test_bit(int nr,
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h
index 2291895b1836..588f52ea810e 100644
--- a/arch/x86/include/asm/perf_event.h
+++ b/arch/x86/include/asm/perf_event.h
@@ -158,6 +158,7 @@ struct x86_pmu_capability {
#define IBS_CAPS_OPCNT (1U<<4)
#define IBS_CAPS_BRNTRGT (1U<<5)
#define IBS_CAPS_OPCNTEXT (1U<<6)
+#define IBS_CAPS_RIPINVALIDCHK (1U<<7)
#define IBS_CAPS_DEFAULT (IBS_CAPS_AVAIL \
| IBS_CAPS_FETCHSAM \
@@ -170,21 +171,28 @@ struct x86_pmu_capability {
#define IBSCTL_LVT_OFFSET_VALID (1ULL<<8)
#define IBSCTL_LVT_OFFSET_MASK 0x0F
-/* IbsFetchCtl bits/masks */
+/* ibs fetch bits/masks */
#define IBS_FETCH_RAND_EN (1ULL<<57)
#define IBS_FETCH_VAL (1ULL<<49)
#define IBS_FETCH_ENABLE (1ULL<<48)
#define IBS_FETCH_CNT 0xFFFF0000ULL
#define IBS_FETCH_MAX_CNT 0x0000FFFFULL
-/* IbsOpCtl bits */
+/* ibs op bits/masks */
+/* lower 4 bits of the current count are ignored: */
+#define IBS_OP_CUR_CNT (0xFFFF0ULL<<32)
#define IBS_OP_CNT_CTL (1ULL<<19)
#define IBS_OP_VAL (1ULL<<18)
#define IBS_OP_ENABLE (1ULL<<17)
#define IBS_OP_MAX_CNT 0x0000FFFFULL
#define IBS_OP_MAX_CNT_EXT 0x007FFFFFULL /* not a register bit mask */
+#define IBS_RIP_INVALID (1ULL<<38)
+#ifdef CONFIG_X86_LOCAL_APIC
extern u32 get_ibs_caps(void);
+#else
+static inline u32 get_ibs_caps(void) { return 0; }
+#endif
#ifdef CONFIG_PERF_EVENTS
extern void perf_events_lapic_init(void);
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index ccbb1ea99ccb..7745b257f035 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -579,9 +579,6 @@ extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
/* Free all resources held by a thread. */
extern void release_thread(struct task_struct *);
-/* Prepare to copy thread state - unlazy all lazy state */
-extern void prepare_to_copy(struct task_struct *tsk);
-
unsigned long get_wchan(struct task_struct *p);
/*
diff --git a/arch/x86/include/asm/segment.h b/arch/x86/include/asm/segment.h
index 165466233ab0..c48a95035a77 100644
--- a/arch/x86/include/asm/segment.h
+++ b/arch/x86/include/asm/segment.h
@@ -205,13 +205,15 @@
#define IDT_ENTRIES 256
#define NUM_EXCEPTION_VECTORS 32
+/* Bitmask of exception vectors which push an error code on the stack */
+#define EXCEPTION_ERRCODE_MASK 0x00027d00
#define GDT_SIZE (GDT_ENTRIES * 8)
#define GDT_ENTRY_TLS_ENTRIES 3
#define TLS_SIZE (GDT_ENTRY_TLS_ENTRIES * 8)
#ifdef __KERNEL__
#ifndef __ASSEMBLY__
-extern const char early_idt_handlers[NUM_EXCEPTION_VECTORS][10];
+extern const char early_idt_handlers[NUM_EXCEPTION_VECTORS][2+2+5];
/*
* Load a segment. Fall back on loading the zero
diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h
index f8cbc6f20e31..f48394513c37 100644
--- a/arch/x86/include/asm/smp.h
+++ b/arch/x86/include/asm/smp.h
@@ -191,11 +191,11 @@ extern unsigned disabled_cpus __cpuinitdata;
* from the initial startup. We map APIC_BASE very early in page_setup(),
* so this is correct in the x86 case.
*/
-#define raw_smp_processor_id() (percpu_read(cpu_number))
+#define raw_smp_processor_id() (this_cpu_read(cpu_number))
extern int safe_smp_processor_id(void);
#elif defined(CONFIG_X86_64_SMP)
-#define raw_smp_processor_id() (percpu_read(cpu_number))
+#define raw_smp_processor_id() (this_cpu_read(cpu_number))
#define stack_smp_processor_id() \
({ \
diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h
index 76bfa2cf301d..b315a33867f2 100644
--- a/arch/x86/include/asm/spinlock.h
+++ b/arch/x86/include/asm/spinlock.h
@@ -20,10 +20,8 @@
#ifdef CONFIG_X86_32
# define LOCK_PTR_REG "a"
-# define REG_PTR_MODE "k"
#else
# define LOCK_PTR_REG "D"
-# define REG_PTR_MODE "q"
#endif
#if defined(CONFIG_X86_32) && \
diff --git a/arch/x86/include/asm/stackprotector.h b/arch/x86/include/asm/stackprotector.h
index b5d9533d2c38..6a998598f172 100644
--- a/arch/x86/include/asm/stackprotector.h
+++ b/arch/x86/include/asm/stackprotector.h
@@ -75,9 +75,9 @@ static __always_inline void boot_init_stack_canary(void)
current->stack_canary = canary;
#ifdef CONFIG_X86_64
- percpu_write(irq_stack_union.stack_canary, canary);
+ this_cpu_write(irq_stack_union.stack_canary, canary);
#else
- percpu_write(stack_canary.canary, canary);
+ this_cpu_write(stack_canary.canary, canary);
#endif
}
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index 73cfe0d309c9..5c25de07cba8 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -85,6 +85,7 @@ struct thread_info {
#define TIF_SECCOMP 8 /* secure computing */
#define TIF_MCE_NOTIFY 10 /* notify userspace of an MCE */
#define TIF_USER_RETURN_NOTIFY 11 /* notify kernel of userspace return */
+#define TIF_UPROBE 12 /* breakpointed or singlestepping */
#define TIF_NOTSC 16 /* TSC is not accessible in userland */
#define TIF_IA32 17 /* IA32 compatibility process */
#define TIF_FORK 18 /* ret_from_fork */
@@ -109,6 +110,7 @@ struct thread_info {
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
#define _TIF_MCE_NOTIFY (1 << TIF_MCE_NOTIFY)
#define _TIF_USER_RETURN_NOTIFY (1 << TIF_USER_RETURN_NOTIFY)
+#define _TIF_UPROBE (1 << TIF_UPROBE)
#define _TIF_NOTSC (1 << TIF_NOTSC)
#define _TIF_IA32 (1 << TIF_IA32)
#define _TIF_FORK (1 << TIF_FORK)
@@ -204,7 +206,7 @@ DECLARE_PER_CPU(unsigned long, kernel_stack);
static inline struct thread_info *current_thread_info(void)
{
struct thread_info *ti;
- ti = (void *)(percpu_read_stable(kernel_stack) +
+ ti = (void *)(this_cpu_read_stable(kernel_stack) +
KERNEL_STACK_OFFSET - THREAD_SIZE);
return ti;
}
diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h
index c0e108e08079..36a1a2ab87d2 100644
--- a/arch/x86/include/asm/tlbflush.h
+++ b/arch/x86/include/asm/tlbflush.h
@@ -62,11 +62,7 @@ static inline void __flush_tlb_one(unsigned long addr)
__flush_tlb();
}
-#ifdef CONFIG_X86_32
-# define TLB_FLUSH_ALL 0xffffffff
-#else
-# define TLB_FLUSH_ALL -1ULL
-#endif
+#define TLB_FLUSH_ALL -1UL
/*
* TLB flushing:
@@ -156,8 +152,8 @@ DECLARE_PER_CPU_SHARED_ALIGNED(struct tlb_state, cpu_tlbstate);
static inline void reset_lazy_tlbstate(void)
{
- percpu_write(cpu_tlbstate.state, 0);
- percpu_write(cpu_tlbstate.active_mm, &init_mm);
+ this_cpu_write(cpu_tlbstate.state, 0);
+ this_cpu_write(cpu_tlbstate.active_mm, &init_mm);
}
#endif /* SMP */
diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h
index b9676ae37ada..095b21507b6a 100644
--- a/arch/x86/include/asm/topology.h
+++ b/arch/x86/include/asm/topology.h
@@ -92,44 +92,6 @@ extern void setup_node_to_cpumask_map(void);
#define pcibus_to_node(bus) __pcibus_to_node(bus)
-#ifdef CONFIG_X86_32
-# define SD_CACHE_NICE_TRIES 1
-# define SD_IDLE_IDX 1
-#else
-# define SD_CACHE_NICE_TRIES 2
-# define SD_IDLE_IDX 2
-#endif
-
-/* sched_domains SD_NODE_INIT for NUMA machines */
-#define SD_NODE_INIT (struct sched_domain) { \
- .min_interval = 8, \
- .max_interval = 32, \
- .busy_factor = 32, \
- .imbalance_pct = 125, \
- .cache_nice_tries = SD_CACHE_NICE_TRIES, \
- .busy_idx = 3, \
- .idle_idx = SD_IDLE_IDX, \
- .newidle_idx = 0, \
- .wake_idx = 0, \
- .forkexec_idx = 0, \
- \
- .flags = 1*SD_LOAD_BALANCE \
- | 1*SD_BALANCE_NEWIDLE \
- | 1*SD_BALANCE_EXEC \
- | 1*SD_BALANCE_FORK \
- | 0*SD_BALANCE_WAKE \
- | 1*SD_WAKE_AFFINE \
- | 0*SD_PREFER_LOCAL \
- | 0*SD_SHARE_CPUPOWER \
- | 0*SD_POWERSAVINGS_BALANCE \
- | 0*SD_SHARE_PKG_RESOURCES \
- | 1*SD_SERIALIZE \
- | 0*SD_PREFER_SIBLING \
- , \
- .last_balance = jiffies, \
- .balance_interval = 1, \
-}
-
extern int __node_distance(int, int);
#define node_distance(a, b) __node_distance(a, b)
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index e0544597cfe7..851fe0dc13bc 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -79,11 +79,12 @@
#define access_ok(type, addr, size) (likely(__range_not_ok(addr, size) == 0))
/*
- * The exception table consists of pairs of addresses: the first is the
- * address of an instruction that is allowed to fault, and the second is
- * the address at which the program should continue. No registers are
- * modified, so it is entirely up to the continuation code to figure out
- * what to do.
+ * The exception table consists of pairs of addresses relative to the
+ * exception table enty itself: the first is the address of an
+ * instruction that is allowed to fault, and the second is the address
+ * at which the program should continue. No registers are modified,
+ * so it is entirely up to the continuation code to figure out what to
+ * do.
*
* All the routines below use bits of fixup code that are out of line
* with the main instruction path. This means when everything is well,
@@ -92,10 +93,14 @@
*/
struct exception_table_entry {
- unsigned long insn, fixup;
+ int insn, fixup;
};
+/* This is not the generic standard exception_table_entry format */
+#define ARCH_HAS_SORT_EXTABLE
+#define ARCH_HAS_SEARCH_EXTABLE
extern int fixup_exception(struct pt_regs *regs);
+extern int early_fixup_exception(unsigned long *ip);
/*
* These are the main single-value transfer routines. They automatically
@@ -202,8 +207,8 @@ extern int __get_user_bad(void);
asm volatile("1: movl %%eax,0(%1)\n" \
"2: movl %%edx,4(%1)\n" \
"3:\n" \
- _ASM_EXTABLE(1b, 2b - 1b) \
- _ASM_EXTABLE(2b, 3b - 2b) \
+ _ASM_EXTABLE_EX(1b, 2b) \
+ _ASM_EXTABLE_EX(2b, 3b) \
: : "A" (x), "r" (addr))
#define __put_user_x8(x, ptr, __ret_pu) \
@@ -408,7 +413,7 @@ do { \
#define __get_user_asm_ex(x, addr, itype, rtype, ltype) \
asm volatile("1: mov"itype" %1,%"rtype"0\n" \
"2:\n" \
- _ASM_EXTABLE(1b, 2b - 1b) \
+ _ASM_EXTABLE_EX(1b, 2b) \
: ltype(x) : "m" (__m(addr)))
#define __put_user_nocheck(x, ptr, size) \
@@ -450,7 +455,7 @@ struct __large_struct { unsigned long buf[100]; };
#define __put_user_asm_ex(x, addr, itype, rtype, ltype) \
asm volatile("1: mov"itype" %"rtype"0,%1\n" \
"2:\n" \
- _ASM_EXTABLE(1b, 2b - 1b) \
+ _ASM_EXTABLE_EX(1b, 2b) \
: : ltype(x), "m" (__m(addr)))
/*
diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h
new file mode 100644
index 000000000000..1e9bed14f7ae
--- /dev/null
+++ b/arch/x86/include/asm/uprobes.h
@@ -0,0 +1,57 @@
+#ifndef _ASM_UPROBES_H
+#define _ASM_UPROBES_H
+/*
+ * User-space Probes (UProbes) for x86
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2008-2011
+ * Authors:
+ * Srikar Dronamraju
+ * Jim Keniston
+ */
+
+#include <linux/notifier.h>
+
+typedef u8 uprobe_opcode_t;
+
+#define MAX_UINSN_BYTES 16
+#define UPROBE_XOL_SLOT_BYTES 128 /* to keep it cache aligned */
+
+#define UPROBE_SWBP_INSN 0xcc
+#define UPROBE_SWBP_INSN_SIZE 1
+
+struct arch_uprobe {
+ u16 fixups;
+ u8 insn[MAX_UINSN_BYTES];
+#ifdef CONFIG_X86_64
+ unsigned long rip_rela_target_address;
+#endif
+};
+
+struct arch_uprobe_task {
+ unsigned long saved_trap_nr;
+#ifdef CONFIG_X86_64
+ unsigned long saved_scratch_register;
+#endif
+};
+
+extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm);
+extern int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs);
+extern int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs);
+extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk);
+extern int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data);
+extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, struct pt_regs *regs);
+#endif /* _ASM_UPROBES_H */
diff --git a/arch/x86/include/asm/vga.h b/arch/x86/include/asm/vga.h
index c4b9dc2f67c5..44282fbf7bf9 100644
--- a/arch/x86/include/asm/vga.h
+++ b/arch/x86/include/asm/vga.h
@@ -17,4 +17,10 @@
#define vga_readb(x) (*(x))
#define vga_writeb(x, y) (*(y) = (x))
+#ifdef CONFIG_FB_EFI
+#define __ARCH_HAS_VGA_DEFAULT_DEVICE
+extern struct pci_dev *vga_default_device(void);
+extern void vga_set_default_device(struct pci_dev *pdev);
+#endif
+
#endif /* _ASM_X86_VGA_H */
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
index 764b66a4cf89..c090af10ac7d 100644
--- a/arch/x86/include/asm/x86_init.h
+++ b/arch/x86/include/asm/x86_init.h
@@ -188,11 +188,18 @@ struct x86_msi_ops {
void (*restore_msi_irqs)(struct pci_dev *dev, int irq);
};
+struct x86_io_apic_ops {
+ void (*init) (void);
+ unsigned int (*read) (unsigned int apic, unsigned int reg);
+ void (*write) (unsigned int apic, unsigned int reg, unsigned int value);
+ void (*modify)(unsigned int apic, unsigned int reg, unsigned int value);
+};
+
extern struct x86_init_ops x86_init;
extern struct x86_cpuinit_ops x86_cpuinit;
extern struct x86_platform_ops x86_platform;
extern struct x86_msi_ops x86_msi;
-
+extern struct x86_io_apic_ops x86_io_apic_ops;
extern void x86_init_noop(void);
extern void x86_init_uint_noop(unsigned int unused);
diff --git a/arch/x86/include/asm/xor_32.h b/arch/x86/include/asm/xor_32.h
index 133b40a0f495..454570891bdc 100644
--- a/arch/x86/include/asm/xor_32.h
+++ b/arch/x86/include/asm/xor_32.h
@@ -861,6 +861,9 @@ static struct xor_block_template xor_block_pIII_sse = {
.do_5 = xor_sse_5,
};
+/* Also try the AVX routines */
+#include "xor_avx.h"
+
/* Also try the generic routines. */
#include <asm-generic/xor.h>
@@ -871,6 +874,7 @@ do { \
xor_speed(&xor_block_8regs_p); \
xor_speed(&xor_block_32regs); \
xor_speed(&xor_block_32regs_p); \
+ AVX_XOR_SPEED; \
if (cpu_has_xmm) \
xor_speed(&xor_block_pIII_sse); \
if (cpu_has_mmx) { \
@@ -883,6 +887,6 @@ do { \
We may also be able to load into the L1 only depending on how the cpu
deals with a load to a line that is being prefetched. */
#define XOR_SELECT_TEMPLATE(FASTEST) \
- (cpu_has_xmm ? &xor_block_pIII_sse : FASTEST)
+ AVX_SELECT(cpu_has_xmm ? &xor_block_pIII_sse : FASTEST)
#endif /* _ASM_X86_XOR_32_H */
diff --git a/arch/x86/include/asm/xor_64.h b/arch/x86/include/asm/xor_64.h
index 1549b5e261f6..b9b2323e90fe 100644
--- a/arch/x86/include/asm/xor_64.h
+++ b/arch/x86/include/asm/xor_64.h
@@ -347,15 +347,21 @@ static struct xor_block_template xor_block_sse = {
.do_5 = xor_sse_5,
};
+
+/* Also try the AVX routines */
+#include "xor_avx.h"
+
#undef XOR_TRY_TEMPLATES
#define XOR_TRY_TEMPLATES \
do { \
+ AVX_XOR_SPEED; \
xor_speed(&xor_block_sse); \
} while (0)
/* We force the use of the SSE xor block because it can write around L2.
We may also be able to load into the L1 only depending on how the cpu
deals with a load to a line that is being prefetched. */
-#define XOR_SELECT_TEMPLATE(FASTEST) (&xor_block_sse)
+#define XOR_SELECT_TEMPLATE(FASTEST) \
+ AVX_SELECT(&xor_block_sse)
#endif /* _ASM_X86_XOR_64_H */
diff --git a/arch/x86/include/asm/xor_avx.h b/arch/x86/include/asm/xor_avx.h
new file mode 100644
index 000000000000..2510d35f480e
--- /dev/null
+++ b/arch/x86/include/asm/xor_avx.h
@@ -0,0 +1,214 @@
+#ifndef _ASM_X86_XOR_AVX_H
+#define _ASM_X86_XOR_AVX_H
+
+/*
+ * Optimized RAID-5 checksumming functions for AVX
+ *
+ * Copyright (C) 2012 Intel Corporation
+ * Author: Jim Kukunas <james.t.kukunas@linux.intel.com>
+ *
+ * Based on Ingo Molnar and Zach Brown's respective MMX and SSE routines
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#ifdef CONFIG_AS_AVX
+
+#include <linux/compiler.h>
+#include <asm/i387.h>
+
+#define ALIGN32 __aligned(32)
+
+#define YMM_SAVED_REGS 4
+
+#define YMMS_SAVE \
+do { \
+ preempt_disable(); \
+ cr0 = read_cr0(); \
+ clts(); \
+ asm volatile("vmovaps %%ymm0, %0" : "=m" (ymm_save[0]) : : "memory"); \
+ asm volatile("vmovaps %%ymm1, %0" : "=m" (ymm_save[32]) : : "memory"); \
+ asm volatile("vmovaps %%ymm2, %0" : "=m" (ymm_save[64]) : : "memory"); \
+ asm volatile("vmovaps %%ymm3, %0" : "=m" (ymm_save[96]) : : "memory"); \
+} while (0);
+
+#define YMMS_RESTORE \
+do { \
+ asm volatile("sfence" : : : "memory"); \
+ asm volatile("vmovaps %0, %%ymm3" : : "m" (ymm_save[96])); \
+ asm volatile("vmovaps %0, %%ymm2" : : "m" (ymm_save[64])); \
+ asm volatile("vmovaps %0, %%ymm1" : : "m" (ymm_save[32])); \
+ asm volatile("vmovaps %0, %%ymm0" : : "m" (ymm_save[0])); \
+ write_cr0(cr0); \
+ preempt_enable(); \
+} while (0);
+
+#define BLOCK4(i) \
+ BLOCK(32 * i, 0) \
+ BLOCK(32 * (i + 1), 1) \
+ BLOCK(32 * (i + 2), 2) \
+ BLOCK(32 * (i + 3), 3)
+
+#define BLOCK16() \
+ BLOCK4(0) \
+ BLOCK4(4) \
+ BLOCK4(8) \
+ BLOCK4(12)
+
+static void xor_avx_2(unsigned long bytes, unsigned long *p0, unsigned long *p1)
+{
+ unsigned long cr0, lines = bytes >> 9;
+ char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
+
+ YMMS_SAVE
+
+ while (lines--) {
+#undef BLOCK
+#define BLOCK(i, reg) \
+do { \
+ asm volatile("vmovdqa %0, %%ymm" #reg : : "m" (p1[i / sizeof(*p1)])); \
+ asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
+ "m" (p0[i / sizeof(*p0)])); \
+ asm volatile("vmovdqa %%ymm" #reg ", %0" : \
+ "=m" (p0[i / sizeof(*p0)])); \
+} while (0);
+
+ BLOCK16()
+
+ p0 = (unsigned long *)((uintptr_t)p0 + 512);
+ p1 = (unsigned long *)((uintptr_t)p1 + 512);
+ }
+
+ YMMS_RESTORE
+}
+
+static void xor_avx_3(unsigned long bytes, unsigned long *p0, unsigned long *p1,
+ unsigned long *p2)
+{
+ unsigned long cr0, lines = bytes >> 9;
+ char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
+
+ YMMS_SAVE
+
+ while (lines--) {
+#undef BLOCK
+#define BLOCK(i, reg) \
+do { \
+ asm volatile("vmovdqa %0, %%ymm" #reg : : "m" (p2[i / sizeof(*p2)])); \
+ asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
+ "m" (p1[i / sizeof(*p1)])); \
+ asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
+ "m" (p0[i / sizeof(*p0)])); \
+ asm volatile("vmovdqa %%ymm" #reg ", %0" : \
+ "=m" (p0[i / sizeof(*p0)])); \
+} while (0);
+
+ BLOCK16()
+
+ p0 = (unsigned long *)((uintptr_t)p0 + 512);
+ p1 = (unsigned long *)((uintptr_t)p1 + 512);
+ p2 = (unsigned long *)((uintptr_t)p2 + 512);
+ }
+
+ YMMS_RESTORE
+}
+
+static void xor_avx_4(unsigned long bytes, unsigned long *p0, unsigned long *p1,
+ unsigned long *p2, unsigned long *p3)
+{
+ unsigned long cr0, lines = bytes >> 9;
+ char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
+
+ YMMS_SAVE
+
+ while (lines--) {
+#undef BLOCK
+#define BLOCK(i, reg) \
+do { \
+ asm volatile("vmovdqa %0, %%ymm" #reg : : "m" (p3[i / sizeof(*p3)])); \
+ asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
+ "m" (p2[i / sizeof(*p2)])); \
+ asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
+ "m" (p1[i / sizeof(*p1)])); \
+ asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
+ "m" (p0[i / sizeof(*p0)])); \
+ asm volatile("vmovdqa %%ymm" #reg ", %0" : \
+ "=m" (p0[i / sizeof(*p0)])); \
+} while (0);
+
+ BLOCK16();
+
+ p0 = (unsigned long *)((uintptr_t)p0 + 512);
+ p1 = (unsigned long *)((uintptr_t)p1 + 512);
+ p2 = (unsigned long *)((uintptr_t)p2 + 512);
+ p3 = (unsigned long *)((uintptr_t)p3 + 512);
+ }
+
+ YMMS_RESTORE
+}
+
+static void xor_avx_5(unsigned long bytes, unsigned long *p0, unsigned long *p1,
+ unsigned long *p2, unsigned long *p3, unsigned long *p4)
+{
+ unsigned long cr0, lines = bytes >> 9;
+ char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
+
+ YMMS_SAVE
+
+ while (lines--) {
+#undef BLOCK
+#define BLOCK(i, reg) \
+do { \
+ asm volatile("vmovdqa %0, %%ymm" #reg : : "m" (p4[i / sizeof(*p4)])); \
+ asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
+ "m" (p3[i / sizeof(*p3)])); \
+ asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
+ "m" (p2[i / sizeof(*p2)])); \
+ asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
+ "m" (p1[i / sizeof(*p1)])); \
+ asm volatile("vxorps %0, %%ymm" #reg ", %%ymm" #reg : : \
+ "m" (p0[i / sizeof(*p0)])); \
+ asm volatile("vmovdqa %%ymm" #reg ", %0" : \
+ "=m" (p0[i / sizeof(*p0)])); \
+} while (0);
+
+ BLOCK16()
+
+ p0 = (unsigned long *)((uintptr_t)p0 + 512);
+ p1 = (unsigned long *)((uintptr_t)p1 + 512);
+ p2 = (unsigned long *)((uintptr_t)p2 + 512);
+ p3 = (unsigned long *)((uintptr_t)p3 + 512);
+ p4 = (unsigned long *)((uintptr_t)p4 + 512);
+ }
+
+ YMMS_RESTORE
+}
+
+static struct xor_block_template xor_block_avx = {
+ .name = "avx",
+ .do_2 = xor_avx_2,
+ .do_3 = xor_avx_3,
+ .do_4 = xor_avx_4,
+ .do_5 = xor_avx_5,
+};
+
+#define AVX_XOR_SPEED \
+do { \
+ if (cpu_has_avx) \
+ xor_speed(&xor_block_avx); \
+} while (0)
+
+#define AVX_SELECT(FASTEST) \
+ (cpu_has_avx ? &xor_block_avx : FASTEST)
+
+#else
+
+#define AVX_XOR_SPEED {}
+
+#define AVX_SELECT(FASTEST) (FASTEST)
+
+#endif
+#endif
diff --git a/arch/x86/include/asm/xsave.h b/arch/x86/include/asm/xsave.h
index c6ce2452f10c..8a1b6f9b594a 100644
--- a/arch/x86/include/asm/xsave.h
+++ b/arch/x86/include/asm/xsave.h
@@ -80,10 +80,7 @@ static inline int xsave_user(struct xsave_struct __user *buf)
"3: movl $-1,%[err]\n"
" jmp 2b\n"
".previous\n"
- ".section __ex_table,\"a\"\n"
- _ASM_ALIGN "\n"
- _ASM_PTR "1b,3b\n"
- ".previous"
+ _ASM_EXTABLE(1b,3b)
: [err] "=r" (err)
: "D" (buf), "a" (-1), "d" (-1), "0" (0)
: "memory");
@@ -106,10 +103,7 @@ static inline int xrestore_user(struct xsave_struct __user *buf, u64 mask)
"3: movl $-1,%[err]\n"
" jmp 2b\n"
".previous\n"
- ".section __ex_table,\"a\"\n"
- _ASM_ALIGN "\n"
- _ASM_PTR "1b,3b\n"
- ".previous"
+ _ASM_EXTABLE(1b,3b)
: [err] "=r" (err)
: "D" (xstate), "a" (lmask), "d" (hmask), "0" (0)
: "memory"); /* memory required? */
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 56ebd1f98447..9bba5b79902b 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -49,7 +49,6 @@ obj-y += cpu/
obj-y += acpi/
obj-y += reboot.o
obj-$(CONFIG_X86_32) += reboot_32.o
-obj-$(CONFIG_MCA) += mca_32.o
obj-$(CONFIG_X86_MSR) += msr.o
obj-$(CONFIG_X86_CPUID) += cpuid.o
obj-$(CONFIG_PCI) += early-quirks.o
@@ -101,6 +100,7 @@ obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o
obj-$(CONFIG_SWIOTLB) += pci-swiotlb.o
obj-$(CONFIG_OF) += devicetree.o
+obj-$(CONFIG_UPROBES) += uprobes.o
###
# 64 bit specific files
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 7c439fe4941b..8afb69319815 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -990,7 +990,7 @@ void __init mp_config_acpi_legacy_irqs(void)
int i;
struct mpc_intsrc mp_irq;
-#if defined (CONFIG_MCA) || defined (CONFIG_EISA)
+#ifdef CONFIG_EISA
/*
* Fabricate the legacy ISA bus (bus #31).
*/
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 3722179a49db..39a222e094af 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1326,11 +1326,13 @@ void __cpuinit setup_local_APIC(void)
acked);
break;
}
- if (cpu_has_tsc) {
- rdtscll(ntsc);
- max_loops = (cpu_khz << 10) - (ntsc - tsc);
- } else
- max_loops--;
+ if (queued) {
+ if (cpu_has_tsc) {
+ rdtscll(ntsc);
+ max_loops = (cpu_khz << 10) - (ntsc - tsc);
+ } else
+ max_loops--;
+ }
} while (queued && max_loops > 0);
WARN_ON(max_loops <= 0);
diff --git a/arch/x86/kernel/apic/apic_flat_64.c b/arch/x86/kernel/apic/apic_flat_64.c
index 359b6899a36c..0e881c46e8c8 100644
--- a/arch/x86/kernel/apic/apic_flat_64.c
+++ b/arch/x86/kernel/apic/apic_flat_64.c
@@ -227,6 +227,7 @@ static struct apic apic_flat = {
.read = native_apic_mem_read,
.write = native_apic_mem_write,
+ .eoi_write = native_apic_mem_write,
.icr_read = native_apic_icr_read,
.icr_write = native_apic_icr_write,
.wait_icr_idle = native_apic_wait_icr_idle,
@@ -386,6 +387,7 @@ static struct apic apic_physflat = {
.read = native_apic_mem_read,
.write = native_apic_mem_write,
+ .eoi_write = native_apic_mem_write,
.icr_read = native_apic_icr_read,
.icr_write = native_apic_icr_write,
.wait_icr_idle = native_apic_wait_icr_idle,
diff --git a/arch/x86/kernel/apic/apic_noop.c b/arch/x86/kernel/apic/apic_noop.c
index 634ae6cdd5c9..a6e4c6e06c08 100644
--- a/arch/x86/kernel/apic/apic_noop.c
+++ b/arch/x86/kernel/apic/apic_noop.c
@@ -181,6 +181,7 @@ struct apic apic_noop = {
.read = noop_apic_read,
.write = noop_apic_write,
+ .eoi_write = noop_apic_write,
.icr_read = noop_apic_icr_read,
.icr_write = noop_apic_icr_write,
.wait_icr_idle = noop_apic_wait_icr_idle,
diff --git a/arch/x86/kernel/apic/apic_numachip.c b/arch/x86/kernel/apic/apic_numachip.c
index 23e75422e013..6ec6d5d297c3 100644
--- a/arch/x86/kernel/apic/apic_numachip.c
+++ b/arch/x86/kernel/apic/apic_numachip.c
@@ -295,6 +295,7 @@ static struct apic apic_numachip __refconst = {
.read = native_apic_mem_read,
.write = native_apic_mem_write,
+ .eoi_write = native_apic_mem_write,
.icr_read = native_apic_icr_read,
.icr_write = native_apic_icr_write,
.wait_icr_idle = native_apic_wait_icr_idle,
diff --git a/arch/x86/kernel/apic/bigsmp_32.c b/arch/x86/kernel/apic/bigsmp_32.c
index 0cdec7065aff..31fbdbfbf960 100644
--- a/arch/x86/kernel/apic/bigsmp_32.c
+++ b/arch/x86/kernel/apic/bigsmp_32.c
@@ -248,6 +248,7 @@ static struct apic apic_bigsmp = {
.read = native_apic_mem_read,
.write = native_apic_mem_write,
+ .eoi_write = native_apic_mem_write,
.icr_read = native_apic_icr_read,
.icr_write = native_apic_icr_write,
.wait_icr_idle = native_apic_wait_icr_idle,
diff --git a/arch/x86/kernel/apic/es7000_32.c b/arch/x86/kernel/apic/es7000_32.c
index e42d1d3b9134..db4ab1be3c79 100644
--- a/arch/x86/kernel/apic/es7000_32.c
+++ b/arch/x86/kernel/apic/es7000_32.c
@@ -678,6 +678,7 @@ static struct apic __refdata apic_es7000_cluster = {
.read = native_apic_mem_read,
.write = native_apic_mem_write,
+ .eoi_write = native_apic_mem_write,
.icr_read = native_apic_icr_read,
.icr_write = native_apic_icr_write,
.wait_icr_idle = native_apic_wait_icr_idle,
@@ -742,6 +743,7 @@ static struct apic __refdata apic_es7000 = {
.read = native_apic_mem_read,
.write = native_apic_mem_write,
+ .eoi_write = native_apic_mem_write,
.icr_read = native_apic_icr_read,
.icr_write = native_apic_icr_write,
.wait_icr_idle = native_apic_wait_icr_idle,
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index ef0648cd7084..ac96561d1a99 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -68,24 +68,6 @@
#define for_each_irq_pin(entry, head) \
for (entry = head; entry; entry = entry->next)
-static void __init __ioapic_init_mappings(void);
-
-static unsigned int __io_apic_read (unsigned int apic, unsigned int reg);
-static void __io_apic_write (unsigned int apic, unsigned int reg, unsigned int val);
-static void __io_apic_modify(unsigned int apic, unsigned int reg, unsigned int val);
-
-static struct io_apic_ops io_apic_ops = {
- .init = __ioapic_init_mappings,
- .read = __io_apic_read,
- .write = __io_apic_write,
- .modify = __io_apic_modify,
-};
-
-void __init set_io_apic_ops(const struct io_apic_ops *ops)
-{
- io_apic_ops = *ops;
-}
-
#ifdef CONFIG_IRQ_REMAP
static void irq_remap_modify_chip_defaults(struct irq_chip *chip);
static inline bool irq_remapped(struct irq_cfg *cfg)
@@ -158,7 +140,7 @@ int mp_irq_entries;
/* GSI interrupts */
static int nr_irqs_gsi = NR_IRQS_LEGACY;
-#if defined (CONFIG_MCA) || defined (CONFIG_EISA)
+#ifdef CONFIG_EISA
int mp_bus_id_to_type[MAX_MP_BUSSES];
#endif
@@ -329,21 +311,6 @@ static void free_irq_at(unsigned int at, struct irq_cfg *cfg)
irq_free_desc(at);
}
-static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
-{
- return io_apic_ops.read(apic, reg);
-}
-
-static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
-{
- io_apic_ops.write(apic, reg, value);
-}
-
-static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
-{
- io_apic_ops.modify(apic, reg, value);
-}
-
struct io_apic {
unsigned int index;
@@ -365,14 +332,14 @@ static inline void io_apic_eoi(unsigned int apic, unsigned int vector)
writel(vector, &io_apic->eoi);
}
-static unsigned int __io_apic_read(unsigned int apic, unsigned int reg)
+unsigned int native_io_apic_read(unsigned int apic, unsigned int reg)
{
struct io_apic __iomem *io_apic = io_apic_base(apic);
writel(reg, &io_apic->index);
return readl(&io_apic->data);
}
-static void __io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
+void native_io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
{
struct io_apic __iomem *io_apic = io_apic_base(apic);
@@ -386,7 +353,7 @@ static void __io_apic_write(unsigned int apic, unsigned int reg, unsigned int va
*
* Older SiS APIC requires we rewrite the index register
*/
-static void __io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
+void native_io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value)
{
struct io_apic __iomem *io_apic = io_apic_base(apic);
@@ -395,29 +362,6 @@ static void __io_apic_modify(unsigned int apic, unsigned int reg, unsigned int v
writel(value, &io_apic->data);
}
-static bool io_apic_level_ack_pending(struct irq_cfg *cfg)
-{
- struct irq_pin_list *entry;
- unsigned long flags;
-
- raw_spin_lock_irqsave(&ioapic_lock, flags);
- for_each_irq_pin(entry, cfg->irq_2_pin) {
- unsigned int reg;
- int pin;
-
- pin = entry->pin;
- reg = io_apic_read(entry->apic, 0x10 + pin*2);
- /* Is the remote IRR bit set? */
- if (reg & IO_APIC_REDIR_REMOTE_IRR) {
- raw_spin_unlock_irqrestore(&ioapic_lock, flags);
- return true;
- }
- }
- raw_spin_unlock_irqrestore(&ioapic_lock, flags);
-
- return false;
-}
-
union entry_union {
struct { u32 w1, w2; };
struct IO_APIC_route_entry entry;
@@ -891,7 +835,7 @@ static int __init find_isa_irq_apic(int irq, int type)
return -1;
}
-#if defined(CONFIG_EISA) || defined(CONFIG_MCA)
+#ifdef CONFIG_EISA
/*
* EISA Edge/Level control register, ELCR
*/
@@ -928,12 +872,6 @@ static int EISA_ELCR(unsigned int irq)
#define default_PCI_trigger(idx) (1)
#define default_PCI_polarity(idx) (1)
-/* MCA interrupts are always polarity zero level triggered,
- * when listed as conforming in the MP table. */
-
-#define default_MCA_trigger(idx) (1)
-#define default_MCA_polarity(idx) default_ISA_polarity(idx)
-
static int irq_polarity(int idx)
{
int bus = mp_irqs[idx].srcbus;
@@ -991,7 +929,7 @@ static int irq_trigger(int idx)
trigger = default_ISA_trigger(idx);
else
trigger = default_PCI_trigger(idx);
-#if defined(CONFIG_EISA) || defined(CONFIG_MCA)
+#ifdef CONFIG_EISA
switch (mp_bus_id_to_type[bus]) {
case MP_BUS_ISA: /* ISA pin */
{
@@ -1008,11 +946,6 @@ static int irq_trigger(int idx)
/* set before the switch */
break;
}
- case MP_BUS_MCA: /* MCA pin */
- {
- trigger = default_MCA_trigger(idx);
- break;
- }
default:
{
printk(KERN_WARNING "broken BIOS!!\n");
@@ -2439,6 +2372,29 @@ static void ack_apic_edge(struct irq_data *data)
atomic_t irq_mis_count;
#ifdef CONFIG_GENERIC_PENDING_IRQ
+static bool io_apic_level_ack_pending(struct irq_cfg *cfg)
+{
+ struct irq_pin_list *entry;
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&ioapic_lock, flags);
+ for_each_irq_pin(entry, cfg->irq_2_pin) {
+ unsigned int reg;
+ int pin;
+
+ pin = entry->pin;
+ reg = io_apic_read(entry->apic, 0x10 + pin*2);
+ /* Is the remote IRR bit set? */
+ if (reg & IO_APIC_REDIR_REMOTE_IRR) {
+ raw_spin_unlock_irqrestore(&ioapic_lock, flags);
+ return true;
+ }
+ }
+ raw_spin_unlock_irqrestore(&ioapic_lock, flags);
+
+ return false;
+}
+
static inline bool ioapic_irqd_mask(struct irq_data *data, struct irq_cfg *cfg)
{
/* If we are moving the irq we need to mask it */
@@ -3756,12 +3712,7 @@ static struct resource * __init ioapic_setup_resources(int nr_ioapics)
return res;
}
-void __init ioapic_and_gsi_init(void)
-{
- io_apic_ops.init();
-}
-
-static void __init __ioapic_init_mappings(void)
+void __init native_io_apic_init_mappings(void)
{
unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
struct resource *ioapic_res;
diff --git a/arch/x86/kernel/apic/numaq_32.c b/arch/x86/kernel/apic/numaq_32.c
index 00d2422ca7c9..f00a68cca37a 100644
--- a/arch/x86/kernel/apic/numaq_32.c
+++ b/arch/x86/kernel/apic/numaq_32.c
@@ -530,6 +530,7 @@ static struct apic __refdata apic_numaq = {
.read = native_apic_mem_read,
.write = native_apic_mem_write,
+ .eoi_write = native_apic_mem_write,
.icr_read = native_apic_icr_read,
.icr_write = native_apic_icr_write,
.wait_icr_idle = native_apic_wait_icr_idle,
diff --git a/arch/x86/kernel/apic/probe_32.c b/arch/x86/kernel/apic/probe_32.c
index ff2c1b9aac4d..1b291da09e60 100644
--- a/arch/x86/kernel/apic/probe_32.c
+++ b/arch/x86/kernel/apic/probe_32.c
@@ -142,6 +142,7 @@ static struct apic apic_default = {
.read = native_apic_mem_read,
.write = native_apic_mem_write,
+ .eoi_write = native_apic_mem_write,
.icr_read = native_apic_icr_read,
.icr_write = native_apic_icr_write,
.wait_icr_idle = native_apic_wait_icr_idle,
diff --git a/arch/x86/kernel/apic/summit_32.c b/arch/x86/kernel/apic/summit_32.c
index fea000b27f07..659897c00755 100644
--- a/arch/x86/kernel/apic/summit_32.c
+++ b/arch/x86/kernel/apic/summit_32.c
@@ -546,6 +546,7 @@ static struct apic apic_summit = {
.read = native_apic_mem_read,
.write = native_apic_mem_write,
+ .eoi_write = native_apic_mem_write,
.icr_read = native_apic_icr_read,
.icr_write = native_apic_icr_write,
.wait_icr_idle = native_apic_wait_icr_idle,
diff --git a/arch/x86/kernel/apic/x2apic_cluster.c b/arch/x86/kernel/apic/x2apic_cluster.c
index 48f3103b3c93..ff35cff0e1a7 100644
--- a/arch/x86/kernel/apic/x2apic_cluster.c
+++ b/arch/x86/kernel/apic/x2apic_cluster.c
@@ -260,6 +260,7 @@ static struct apic apic_x2apic_cluster = {
.read = native_apic_msr_read,
.write = native_apic_msr_write,
+ .eoi_write = native_apic_msr_eoi_write,
.icr_read = native_x2apic_icr_read,
.icr_write = native_x2apic_icr_write,
.wait_icr_idle = native_x2apic_wait_icr_idle,
diff --git a/arch/x86/kernel/apic/x2apic_phys.c b/arch/x86/kernel/apic/x2apic_phys.c
index 991e315f4227..c17e982db275 100644
--- a/arch/x86/kernel/apic/x2apic_phys.c
+++ b/arch/x86/kernel/apic/x2apic_phys.c
@@ -172,6 +172,7 @@ static struct apic apic_x2apic_phys = {
.read = native_apic_msr_read,
.write = native_apic_msr_write,
+ .eoi_write = native_apic_msr_eoi_write,
.icr_read = native_x2apic_icr_read,
.icr_write = native_x2apic_icr_write,
.wait_icr_idle = native_x2apic_wait_icr_idle,
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index 87bfa69e216e..c6d03f7a4401 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -404,6 +404,7 @@ static struct apic __refdata apic_x2apic_uv_x = {
.read = native_apic_msr_read,
.write = native_apic_msr_write,
+ .eoi_write = native_apic_msr_eoi_write,
.icr_read = native_x2apic_icr_read,
.icr_write = native_x2apic_icr_write,
.wait_icr_idle = native_x2apic_wait_icr_idle,
diff --git a/arch/x86/kernel/check.c b/arch/x86/kernel/check.c
index 5da1269e8ddc..e2dbcb7dabdd 100644
--- a/arch/x86/kernel/check.c
+++ b/arch/x86/kernel/check.c
@@ -27,21 +27,29 @@ static int num_scan_areas;
static __init int set_corruption_check(char *arg)
{
- char *end;
+ ssize_t ret;
+ unsigned long val;
- memory_corruption_check = simple_strtol(arg, &end, 10);
+ ret = kstrtoul(arg, 10, &val);
+ if (ret)
+ return ret;
- return (*end == 0) ? 0 : -EINVAL;
+ memory_corruption_check = val;
+ return 0;
}
early_param("memory_corruption_check", set_corruption_check);
static __init int set_corruption_check_period(char *arg)
{
- char *end;
+ ssize_t ret;
+ unsigned long val;
- corruption_check_period = simple_strtoul(arg, &end, 10);
+ ret = kstrtoul(arg, 10, &val);
+ if (ret)
+ return ret;
- return (*end == 0) ? 0 : -EINVAL;
+ corruption_check_period = val;
+ return 0;
}
early_param("memory_corruption_check_period", set_corruption_check_period);
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index cf79302198a6..82f29e70d058 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -1185,7 +1185,7 @@ void __cpuinit cpu_init(void)
oist = &per_cpu(orig_ist, cpu);
#ifdef CONFIG_NUMA
- if (cpu != 0 && percpu_read(numa_node) == 0 &&
+ if (cpu != 0 && this_cpu_read(numa_node) == 0 &&
early_cpu_to_node(cpu) != NUMA_NO_NODE)
set_numa_node(early_cpu_to_node(cpu));
#endif
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index b8f3653dddbc..9a7c90d80bc4 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -615,14 +615,14 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c)
new_l2 = this_leaf.size/1024;
num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;
index_msb = get_count_order(num_threads_sharing);
- l2_id = c->apicid >> index_msb;
+ l2_id = c->apicid & ~((1 << index_msb) - 1);
break;
case 3:
new_l3 = this_leaf.size/1024;
num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;
index_msb = get_count_order(
num_threads_sharing);
- l3_id = c->apicid >> index_msb;
+ l3_id = c->apicid & ~((1 << index_msb) - 1);
break;
default:
break;
diff --git a/arch/x86/kernel/cpu/match.c b/arch/x86/kernel/cpu/match.c
index 5502b289341b..36565373af87 100644
--- a/arch/x86/kernel/cpu/match.c
+++ b/arch/x86/kernel/cpu/match.c
@@ -23,7 +23,7 @@
* %X86_MODEL_ANY, %X86_FEATURE_ANY or 0 (except for vendor)
*
* Arrays used to match for this should also be declared using
- * MODULE_DEVICE_TABLE(x86_cpu, ...)
+ * MODULE_DEVICE_TABLE(x86cpu, ...)
*
* This always matches against the boot cpu, assuming models and features are
* consistent over all CPUs.
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 11c9166c3337..2afcbd253e1d 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -583,7 +583,7 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
struct mce m;
int i;
- percpu_inc(mce_poll_count);
+ this_cpu_inc(mce_poll_count);
mce_gather_info(&m, NULL);
@@ -1017,7 +1017,7 @@ void do_machine_check(struct pt_regs *regs, long error_code)
atomic_inc(&mce_entry);
- percpu_inc(mce_exception_count);
+ this_cpu_inc(mce_exception_count);
if (!banks)
goto out;
@@ -1431,6 +1431,43 @@ static int __cpuinit __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c)
*/
if (c->x86 == 6 && banks > 0)
mce_banks[0].ctl = 0;
+
+ /*
+ * Turn off MC4_MISC thresholding banks on those models since
+ * they're not supported there.
+ */
+ if (c->x86 == 0x15 &&
+ (c->x86_model >= 0x10 && c->x86_model <= 0x1f)) {
+ int i;
+ u64 val, hwcr;
+ bool need_toggle;
+ u32 msrs[] = {
+ 0x00000413, /* MC4_MISC0 */
+ 0xc0000408, /* MC4_MISC1 */
+ };
+
+ rdmsrl(MSR_K7_HWCR, hwcr);
+
+ /* McStatusWrEn has to be set */
+ need_toggle = !(hwcr & BIT(18));
+
+ if (need_toggle)
+ wrmsrl(MSR_K7_HWCR, hwcr | BIT(18));
+
+ for (i = 0; i < ARRAY_SIZE(msrs); i++) {
+ rdmsrl(msrs[i], val);
+
+ /* CntP bit set? */
+ if (val & BIT(62)) {
+ val &= ~BIT(62);
+ wrmsrl(msrs[i], val);
+ }
+ }
+
+ /* restore old settings */
+ if (need_toggle)
+ wrmsrl(MSR_K7_HWCR, hwcr);
+ }
}
if (c->x86_vendor == X86_VENDOR_INTEL) {
diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c
index 99b57179f912..f4873a64f46d 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_amd.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c
@@ -51,6 +51,7 @@ struct threshold_block {
unsigned int cpu;
u32 address;
u16 interrupt_enable;
+ bool interrupt_capable;
u16 threshold_limit;
struct kobject kobj;
struct list_head miscj;
@@ -83,6 +84,21 @@ struct thresh_restart {
u16 old_limit;
};
+static bool lvt_interrupt_supported(unsigned int bank, u32 msr_high_bits)
+{
+ /*
+ * bank 4 supports APIC LVT interrupts implicitly since forever.
+ */
+ if (bank == 4)
+ return true;
+
+ /*
+ * IntP: interrupt present; if this bit is set, the thresholding
+ * bank can generate APIC LVT interrupts
+ */
+ return msr_high_bits & BIT(28);
+}
+
static int lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi)
{
int msr = (hi & MASK_LVTOFF_HI) >> 20;
@@ -104,8 +120,10 @@ static int lvt_off_valid(struct threshold_block *b, int apic, u32 lo, u32 hi)
return 1;
};
-/* must be called with correct cpu affinity */
-/* Called via smp_call_function_single() */
+/*
+ * Called via smp_call_function_single(), must be called with correct
+ * cpu affinity.
+ */
static void threshold_restart_bank(void *_tr)
{
struct thresh_restart *tr = _tr;
@@ -128,6 +146,12 @@ static void threshold_restart_bank(void *_tr)
(new_count & THRESHOLD_MAX);
}
+ /* clear IntType */
+ hi &= ~MASK_INT_TYPE_HI;
+
+ if (!tr->b->interrupt_capable)
+ goto done;
+
if (tr->set_lvt_off) {
if (lvt_off_valid(tr->b, tr->lvt_off, lo, hi)) {
/* set new lvt offset */
@@ -136,9 +160,10 @@ static void threshold_restart_bank(void *_tr)
}
}
- tr->b->interrupt_enable ?
- (hi = (hi & ~MASK_INT_TYPE_HI) | INT_TYPE_APIC) :
- (hi &= ~MASK_INT_TYPE_HI);
+ if (tr->b->interrupt_enable)
+ hi |= INT_TYPE_APIC;
+
+ done:
hi |= MASK_COUNT_EN_HI;
wrmsr(tr->b->address, lo, hi);
@@ -202,14 +227,17 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
if (shared_bank[bank] && c->cpu_core_id)
break;
- offset = setup_APIC_mce(offset,
- (high & MASK_LVTOFF_HI) >> 20);
-
memset(&b, 0, sizeof(b));
- b.cpu = cpu;
- b.bank = bank;
- b.block = block;
- b.address = address;
+ b.cpu = cpu;
+ b.bank = bank;
+ b.block = block;
+ b.address = address;
+ b.interrupt_capable = lvt_interrupt_supported(bank, high);
+
+ if (b.interrupt_capable) {
+ int new = (high & MASK_LVTOFF_HI) >> 20;
+ offset = setup_APIC_mce(offset, new);
+ }
mce_threshold_block_init(&b, offset);
mce_threshold_vector = amd_threshold_interrupt;
@@ -309,6 +337,9 @@ store_interrupt_enable(struct threshold_block *b, const char *buf, size_t size)
struct thresh_restart tr;
unsigned long new;
+ if (!b->interrupt_capable)
+ return -EINVAL;
+
if (strict_strtoul(buf, 0, &new) < 0)
return -EINVAL;
@@ -390,10 +421,10 @@ RW_ATTR(threshold_limit);
RW_ATTR(error_count);
static struct attribute *default_attrs[] = {
- &interrupt_enable.attr,
&threshold_limit.attr,
&error_count.attr,
- NULL
+ NULL, /* possibly interrupt_enable if supported, see below */
+ NULL,
};
#define to_block(k) container_of(k, struct threshold_block, kobj)
@@ -467,8 +498,14 @@ static __cpuinit int allocate_threshold_blocks(unsigned int cpu,
b->cpu = cpu;
b->address = address;
b->interrupt_enable = 0;
+ b->interrupt_capable = lvt_interrupt_supported(bank, high);
b->threshold_limit = THRESHOLD_MAX;
+ if (b->interrupt_capable)
+ threshold_ktype.default_attrs[2] = &interrupt_enable.attr;
+ else
+ threshold_ktype.default_attrs[2] = NULL;
+
INIT_LIST_HEAD(&b->miscj);
if (per_cpu(threshold_banks, cpu)[bank]->blocks) {
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index bb8e03407e18..e049d6da0183 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -484,9 +484,6 @@ static int __x86_pmu_event_init(struct perf_event *event)
/* mark unused */
event->hw.extra_reg.idx = EXTRA_REG_NONE;
-
- /* mark not used */
- event->hw.extra_reg.idx = EXTRA_REG_NONE;
event->hw.branch_reg.idx = EXTRA_REG_NONE;
return x86_pmu.hw_config(event);
@@ -1186,8 +1183,6 @@ int x86_pmu_handle_irq(struct pt_regs *regs)
int idx, handled = 0;
u64 val;
- perf_sample_data_init(&data, 0);
-
cpuc = &__get_cpu_var(cpu_hw_events);
/*
@@ -1222,7 +1217,7 @@ int x86_pmu_handle_irq(struct pt_regs *regs)
* event overflow
*/
handled++;
- data.period = event->hw.last_period;
+ perf_sample_data_init(&data, 0, event->hw.last_period);
if (!x86_perf_event_set_period(event))
continue;
diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c
index 95e7fe1c5f0b..11a4eb9131d5 100644
--- a/arch/x86/kernel/cpu/perf_event_amd.c
+++ b/arch/x86/kernel/cpu/perf_event_amd.c
@@ -134,8 +134,13 @@ static u64 amd_pmu_event_map(int hw_event)
static int amd_pmu_hw_config(struct perf_event *event)
{
- int ret = x86_pmu_hw_config(event);
+ int ret;
+ /* pass precise event sampling to ibs: */
+ if (event->attr.precise_ip && get_ibs_caps())
+ return -ENOENT;
+
+ ret = x86_pmu_hw_config(event);
if (ret)
return ret;
@@ -205,10 +210,8 @@ static void amd_put_event_constraints(struct cpu_hw_events *cpuc,
* when we come here
*/
for (i = 0; i < x86_pmu.num_counters; i++) {
- if (nb->owners[i] == event) {
- cmpxchg(nb->owners+i, event, NULL);
+ if (cmpxchg(nb->owners + i, event, NULL) == event)
break;
- }
}
}
@@ -493,6 +496,7 @@ static __initconst const struct x86_pmu amd_pmu = {
* 0x023 DE PERF_CTL[2:0]
* 0x02D LS PERF_CTL[3]
* 0x02E LS PERF_CTL[3,0]
+ * 0x031 LS PERF_CTL[2:0] (**)
* 0x043 CU PERF_CTL[2:0]
* 0x045 CU PERF_CTL[2:0]
* 0x046 CU PERF_CTL[2:0]
@@ -506,10 +510,12 @@ static __initconst const struct x86_pmu amd_pmu = {
* 0x0DD LS PERF_CTL[5:0]
* 0x0DE LS PERF_CTL[5:0]
* 0x0DF LS PERF_CTL[5:0]
+ * 0x1C0 EX PERF_CTL[5:3]
* 0x1D6 EX PERF_CTL[5:0]
* 0x1D8 EX PERF_CTL[5:0]
*
- * (*) depending on the umask all FPU counters may be used
+ * (*) depending on the umask all FPU counters may be used
+ * (**) only one unitmask enabled at a time
*/
static struct event_constraint amd_f15_PMC0 = EVENT_CONSTRAINT(0, 0x01, 0);
@@ -559,6 +565,12 @@ amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, struct perf_event *ev
return &amd_f15_PMC3;
case 0x02E:
return &amd_f15_PMC30;
+ case 0x031:
+ if (hweight_long(hwc->config & ARCH_PERFMON_EVENTSEL_UMASK) <= 1)
+ return &amd_f15_PMC20;
+ return &emptyconstraint;
+ case 0x1C0:
+ return &amd_f15_PMC53;
default:
return &amd_f15_PMC50;
}
diff --git a/arch/x86/kernel/cpu/perf_event_amd_ibs.c b/arch/x86/kernel/cpu/perf_event_amd_ibs.c
index 3b8a2d30d14e..da9bcdcd9856 100644
--- a/arch/x86/kernel/cpu/perf_event_amd_ibs.c
+++ b/arch/x86/kernel/cpu/perf_event_amd_ibs.c
@@ -9,6 +9,7 @@
#include <linux/perf_event.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/ptrace.h>
#include <asm/apic.h>
@@ -16,36 +17,591 @@ static u32 ibs_caps;
#if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD)
-static struct pmu perf_ibs;
+#include <linux/kprobes.h>
+#include <linux/hardirq.h>
+
+#include <asm/nmi.h>
+
+#define IBS_FETCH_CONFIG_MASK (IBS_FETCH_RAND_EN | IBS_FETCH_MAX_CNT)
+#define IBS_OP_CONFIG_MASK IBS_OP_MAX_CNT
+
+enum ibs_states {
+ IBS_ENABLED = 0,
+ IBS_STARTED = 1,
+ IBS_STOPPING = 2,
+
+ IBS_MAX_STATES,
+};
+
+struct cpu_perf_ibs {
+ struct perf_event *event;
+ unsigned long state[BITS_TO_LONGS(IBS_MAX_STATES)];
+};
+
+struct perf_ibs {
+ struct pmu pmu;
+ unsigned int msr;
+ u64 config_mask;
+ u64 cnt_mask;
+ u64 enable_mask;
+ u64 valid_mask;
+ u64 max_period;
+ unsigned long offset_mask[1];
+ int offset_max;
+ struct cpu_perf_ibs __percpu *pcpu;
+ u64 (*get_count)(u64 config);
+};
+
+struct perf_ibs_data {
+ u32 size;
+ union {
+ u32 data[0]; /* data buffer starts here */
+ u32 caps;
+ };
+ u64 regs[MSR_AMD64_IBS_REG_COUNT_MAX];
+};
+
+static int
+perf_event_set_period(struct hw_perf_event *hwc, u64 min, u64 max, u64 *hw_period)
+{
+ s64 left = local64_read(&hwc->period_left);
+ s64 period = hwc->sample_period;
+ int overflow = 0;
+
+ /*
+ * If we are way outside a reasonable range then just skip forward:
+ */
+ if (unlikely(left <= -period)) {
+ left = period;
+ local64_set(&hwc->period_left, left);
+ hwc->last_period = period;
+ overflow = 1;
+ }
+
+ if (unlikely(left < (s64)min)) {
+ left += period;
+ local64_set(&hwc->period_left, left);
+ hwc->last_period = period;
+ overflow = 1;
+ }
+
+ /*
+ * If the hw period that triggers the sw overflow is too short
+ * we might hit the irq handler. This biases the results.
+ * Thus we shorten the next-to-last period and set the last
+ * period to the max period.
+ */
+ if (left > max) {
+ left -= max;
+ if (left > max)
+ left = max;
+ else if (left < min)
+ left = min;
+ }
+
+ *hw_period = (u64)left;
+
+ return overflow;
+}
+
+static int
+perf_event_try_update(struct perf_event *event, u64 new_raw_count, int width)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ int shift = 64 - width;
+ u64 prev_raw_count;
+ u64 delta;
+
+ /*
+ * Careful: an NMI might modify the previous event value.
+ *
+ * Our tactic to handle this is to first atomically read and
+ * exchange a new raw count - then add that new-prev delta
+ * count to the generic event atomically:
+ */
+ prev_raw_count = local64_read(&hwc->prev_count);
+ if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+ new_raw_count) != prev_raw_count)
+ return 0;
+
+ /*
+ * Now we have the new raw value and have updated the prev
+ * timestamp already. We can now calculate the elapsed delta
+ * (event-)time and add that to the generic event.
+ *
+ * Careful, not all hw sign-extends above the physical width
+ * of the count.
+ */
+ delta = (new_raw_count << shift) - (prev_raw_count << shift);
+ delta >>= shift;
+
+ local64_add(delta, &event->count);
+ local64_sub(delta, &hwc->period_left);
+
+ return 1;
+}
+
+static struct perf_ibs perf_ibs_fetch;
+static struct perf_ibs perf_ibs_op;
+
+static struct perf_ibs *get_ibs_pmu(int type)
+{
+ if (perf_ibs_fetch.pmu.type == type)
+ return &perf_ibs_fetch;
+ if (perf_ibs_op.pmu.type == type)
+ return &perf_ibs_op;
+ return NULL;
+}
+
+/*
+ * Use IBS for precise event sampling:
+ *
+ * perf record -a -e cpu-cycles:p ... # use ibs op counting cycle count
+ * perf record -a -e r076:p ... # same as -e cpu-cycles:p
+ * perf record -a -e r0C1:p ... # use ibs op counting micro-ops
+ *
+ * IbsOpCntCtl (bit 19) of IBS Execution Control Register (IbsOpCtl,
+ * MSRC001_1033) is used to select either cycle or micro-ops counting
+ * mode.
+ *
+ * The rip of IBS samples has skid 0. Thus, IBS supports precise
+ * levels 1 and 2 and the PERF_EFLAGS_EXACT is set. In rare cases the
+ * rip is invalid when IBS was not able to record the rip correctly.
+ * We clear PERF_EFLAGS_EXACT and take the rip from pt_regs then.
+ *
+ */
+static int perf_ibs_precise_event(struct perf_event *event, u64 *config)
+{
+ switch (event->attr.precise_ip) {
+ case 0:
+ return -ENOENT;
+ case 1:
+ case 2:
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ switch (event->attr.type) {
+ case PERF_TYPE_HARDWARE:
+ switch (event->attr.config) {
+ case PERF_COUNT_HW_CPU_CYCLES:
+ *config = 0;
+ return 0;
+ }
+ break;
+ case PERF_TYPE_RAW:
+ switch (event->attr.config) {
+ case 0x0076:
+ *config = 0;
+ return 0;
+ case 0x00C1:
+ *config = IBS_OP_CNT_CTL;
+ return 0;
+ }
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ return -EOPNOTSUPP;
+}
static int perf_ibs_init(struct perf_event *event)
{
- if (perf_ibs.type != event->attr.type)
+ struct hw_perf_event *hwc = &event->hw;
+ struct perf_ibs *perf_ibs;
+ u64 max_cnt, config;
+ int ret;
+
+ perf_ibs = get_ibs_pmu(event->attr.type);
+ if (perf_ibs) {
+ config = event->attr.config;
+ } else {
+ perf_ibs = &perf_ibs_op;
+ ret = perf_ibs_precise_event(event, &config);
+ if (ret)
+ return ret;
+ }
+
+ if (event->pmu != &perf_ibs->pmu)
return -ENOENT;
+
+ if (config & ~perf_ibs->config_mask)
+ return -EINVAL;
+
+ if (hwc->sample_period) {
+ if (config & perf_ibs->cnt_mask)
+ /* raw max_cnt may not be set */
+ return -EINVAL;
+ if (!event->attr.sample_freq && hwc->sample_period & 0x0f)
+ /*
+ * lower 4 bits can not be set in ibs max cnt,
+ * but allowing it in case we adjust the
+ * sample period to set a frequency.
+ */
+ return -EINVAL;
+ hwc->sample_period &= ~0x0FULL;
+ if (!hwc->sample_period)
+ hwc->sample_period = 0x10;
+ } else {
+ max_cnt = config & perf_ibs->cnt_mask;
+ config &= ~perf_ibs->cnt_mask;
+ event->attr.sample_period = max_cnt << 4;
+ hwc->sample_period = event->attr.sample_period;
+ }
+
+ if (!hwc->sample_period)
+ return -EINVAL;
+
+ /*
+ * If we modify hwc->sample_period, we also need to update
+ * hwc->last_period and hwc->period_left.
+ */
+ hwc->last_period = hwc->sample_period;
+ local64_set(&hwc->period_left, hwc->sample_period);
+
+ hwc->config_base = perf_ibs->msr;
+ hwc->config = config;
+
return 0;
}
+static int perf_ibs_set_period(struct perf_ibs *perf_ibs,
+ struct hw_perf_event *hwc, u64 *period)
+{
+ int overflow;
+
+ /* ignore lower 4 bits in min count: */
+ overflow = perf_event_set_period(hwc, 1<<4, perf_ibs->max_period, period);
+ local64_set(&hwc->prev_count, 0);
+
+ return overflow;
+}
+
+static u64 get_ibs_fetch_count(u64 config)
+{
+ return (config & IBS_FETCH_CNT) >> 12;
+}
+
+static u64 get_ibs_op_count(u64 config)
+{
+ u64 count = 0;
+
+ if (config & IBS_OP_VAL)
+ count += (config & IBS_OP_MAX_CNT) << 4; /* cnt rolled over */
+
+ if (ibs_caps & IBS_CAPS_RDWROPCNT)
+ count += (config & IBS_OP_CUR_CNT) >> 32;
+
+ return count;
+}
+
+static void
+perf_ibs_event_update(struct perf_ibs *perf_ibs, struct perf_event *event,
+ u64 *config)
+{
+ u64 count = perf_ibs->get_count(*config);
+
+ /*
+ * Set width to 64 since we do not overflow on max width but
+ * instead on max count. In perf_ibs_set_period() we clear
+ * prev count manually on overflow.
+ */
+ while (!perf_event_try_update(event, count, 64)) {
+ rdmsrl(event->hw.config_base, *config);
+ count = perf_ibs->get_count(*config);
+ }
+}
+
+static inline void perf_ibs_enable_event(struct perf_ibs *perf_ibs,
+ struct hw_perf_event *hwc, u64 config)
+{
+ wrmsrl(hwc->config_base, hwc->config | config | perf_ibs->enable_mask);
+}
+
+/*
+ * Erratum #420 Instruction-Based Sampling Engine May Generate
+ * Interrupt that Cannot Be Cleared:
+ *
+ * Must clear counter mask first, then clear the enable bit. See
+ * Revision Guide for AMD Family 10h Processors, Publication #41322.
+ */
+static inline void perf_ibs_disable_event(struct perf_ibs *perf_ibs,
+ struct hw_perf_event *hwc, u64 config)
+{
+ config &= ~perf_ibs->cnt_mask;
+ wrmsrl(hwc->config_base, config);
+ config &= ~perf_ibs->enable_mask;
+ wrmsrl(hwc->config_base, config);
+}
+
+/*
+ * We cannot restore the ibs pmu state, so we always needs to update
+ * the event while stopping it and then reset the state when starting
+ * again. Thus, ignoring PERF_EF_RELOAD and PERF_EF_UPDATE flags in
+ * perf_ibs_start()/perf_ibs_stop() and instead always do it.
+ */
+static void perf_ibs_start(struct perf_event *event, int flags)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ struct perf_ibs *perf_ibs = container_of(event->pmu, struct perf_ibs, pmu);
+ struct cpu_perf_ibs *pcpu = this_cpu_ptr(perf_ibs->pcpu);
+ u64 period;
+
+ if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
+ return;
+
+ WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
+ hwc->state = 0;
+
+ perf_ibs_set_period(perf_ibs, hwc, &period);
+ set_bit(IBS_STARTED, pcpu->state);
+ perf_ibs_enable_event(perf_ibs, hwc, period >> 4);
+
+ perf_event_update_userpage(event);
+}
+
+static void perf_ibs_stop(struct perf_event *event, int flags)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ struct perf_ibs *perf_ibs = container_of(event->pmu, struct perf_ibs, pmu);
+ struct cpu_perf_ibs *pcpu = this_cpu_ptr(perf_ibs->pcpu);
+ u64 config;
+ int stopping;
+
+ stopping = test_and_clear_bit(IBS_STARTED, pcpu->state);
+
+ if (!stopping && (hwc->state & PERF_HES_UPTODATE))
+ return;
+
+ rdmsrl(hwc->config_base, config);
+
+ if (stopping) {
+ set_bit(IBS_STOPPING, pcpu->state);
+ perf_ibs_disable_event(perf_ibs, hwc, config);
+ WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+ hwc->state |= PERF_HES_STOPPED;
+ }
+
+ if (hwc->state & PERF_HES_UPTODATE)
+ return;
+
+ /*
+ * Clear valid bit to not count rollovers on update, rollovers
+ * are only updated in the irq handler.
+ */
+ config &= ~perf_ibs->valid_mask;
+
+ perf_ibs_event_update(perf_ibs, event, &config);
+ hwc->state |= PERF_HES_UPTODATE;
+}
+
static int perf_ibs_add(struct perf_event *event, int flags)
{
+ struct perf_ibs *perf_ibs = container_of(event->pmu, struct perf_ibs, pmu);
+ struct cpu_perf_ibs *pcpu = this_cpu_ptr(perf_ibs->pcpu);
+
+ if (test_and_set_bit(IBS_ENABLED, pcpu->state))
+ return -ENOSPC;
+
+ event->hw.state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+
+ pcpu->event = event;
+
+ if (flags & PERF_EF_START)
+ perf_ibs_start(event, PERF_EF_RELOAD);
+
return 0;
}
static void perf_ibs_del(struct perf_event *event, int flags)
{
+ struct perf_ibs *perf_ibs = container_of(event->pmu, struct perf_ibs, pmu);
+ struct cpu_perf_ibs *pcpu = this_cpu_ptr(perf_ibs->pcpu);
+
+ if (!test_and_clear_bit(IBS_ENABLED, pcpu->state))
+ return;
+
+ perf_ibs_stop(event, PERF_EF_UPDATE);
+
+ pcpu->event = NULL;
+
+ perf_event_update_userpage(event);
}
-static struct pmu perf_ibs = {
- .event_init= perf_ibs_init,
- .add= perf_ibs_add,
- .del= perf_ibs_del,
+static void perf_ibs_read(struct perf_event *event) { }
+
+static struct perf_ibs perf_ibs_fetch = {
+ .pmu = {
+ .task_ctx_nr = perf_invalid_context,
+
+ .event_init = perf_ibs_init,
+ .add = perf_ibs_add,
+ .del = perf_ibs_del,
+ .start = perf_ibs_start,
+ .stop = perf_ibs_stop,
+ .read = perf_ibs_read,
+ },
+ .msr = MSR_AMD64_IBSFETCHCTL,
+ .config_mask = IBS_FETCH_CONFIG_MASK,
+ .cnt_mask = IBS_FETCH_MAX_CNT,
+ .enable_mask = IBS_FETCH_ENABLE,
+ .valid_mask = IBS_FETCH_VAL,
+ .max_period = IBS_FETCH_MAX_CNT << 4,
+ .offset_mask = { MSR_AMD64_IBSFETCH_REG_MASK },
+ .offset_max = MSR_AMD64_IBSFETCH_REG_COUNT,
+
+ .get_count = get_ibs_fetch_count,
};
+static struct perf_ibs perf_ibs_op = {
+ .pmu = {
+ .task_ctx_nr = perf_invalid_context,
+
+ .event_init = perf_ibs_init,
+ .add = perf_ibs_add,
+ .del = perf_ibs_del,
+ .start = perf_ibs_start,
+ .stop = perf_ibs_stop,
+ .read = perf_ibs_read,
+ },
+ .msr = MSR_AMD64_IBSOPCTL,
+ .config_mask = IBS_OP_CONFIG_MASK,
+ .cnt_mask = IBS_OP_MAX_CNT,
+ .enable_mask = IBS_OP_ENABLE,
+ .valid_mask = IBS_OP_VAL,
+ .max_period = IBS_OP_MAX_CNT << 4,
+ .offset_mask = { MSR_AMD64_IBSOP_REG_MASK },
+ .offset_max = MSR_AMD64_IBSOP_REG_COUNT,
+
+ .get_count = get_ibs_op_count,
+};
+
+static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs)
+{
+ struct cpu_perf_ibs *pcpu = this_cpu_ptr(perf_ibs->pcpu);
+ struct perf_event *event = pcpu->event;
+ struct hw_perf_event *hwc = &event->hw;
+ struct perf_sample_data data;
+ struct perf_raw_record raw;
+ struct pt_regs regs;
+ struct perf_ibs_data ibs_data;
+ int offset, size, check_rip, offset_max, throttle = 0;
+ unsigned int msr;
+ u64 *buf, *config, period;
+
+ if (!test_bit(IBS_STARTED, pcpu->state)) {
+ /*
+ * Catch spurious interrupts after stopping IBS: After
+ * disabling IBS there could be still incomming NMIs
+ * with samples that even have the valid bit cleared.
+ * Mark all this NMIs as handled.
+ */
+ return test_and_clear_bit(IBS_STOPPING, pcpu->state) ? 1 : 0;
+ }
+
+ msr = hwc->config_base;
+ buf = ibs_data.regs;
+ rdmsrl(msr, *buf);
+ if (!(*buf++ & perf_ibs->valid_mask))
+ return 0;
+
+ config = &ibs_data.regs[0];
+ perf_ibs_event_update(perf_ibs, event, config);
+ perf_sample_data_init(&data, 0, hwc->last_period);
+ if (!perf_ibs_set_period(perf_ibs, hwc, &period))
+ goto out; /* no sw counter overflow */
+
+ ibs_data.caps = ibs_caps;
+ size = 1;
+ offset = 1;
+ check_rip = (perf_ibs == &perf_ibs_op && (ibs_caps & IBS_CAPS_RIPINVALIDCHK));
+ if (event->attr.sample_type & PERF_SAMPLE_RAW)
+ offset_max = perf_ibs->offset_max;
+ else if (check_rip)
+ offset_max = 2;
+ else
+ offset_max = 1;
+ do {
+ rdmsrl(msr + offset, *buf++);
+ size++;
+ offset = find_next_bit(perf_ibs->offset_mask,
+ perf_ibs->offset_max,
+ offset + 1);
+ } while (offset < offset_max);
+ ibs_data.size = sizeof(u64) * size;
+
+ regs = *iregs;
+ if (check_rip && (ibs_data.regs[2] & IBS_RIP_INVALID)) {
+ regs.flags &= ~PERF_EFLAGS_EXACT;
+ } else {
+ instruction_pointer_set(&regs, ibs_data.regs[1]);
+ regs.flags |= PERF_EFLAGS_EXACT;
+ }
+
+ if (event->attr.sample_type & PERF_SAMPLE_RAW) {
+ raw.size = sizeof(u32) + ibs_data.size;
+ raw.data = ibs_data.data;
+ data.raw = &raw;
+ }
+
+ throttle = perf_event_overflow(event, &data, &regs);
+out:
+ if (throttle)
+ perf_ibs_disable_event(perf_ibs, hwc, *config);
+ else
+ perf_ibs_enable_event(perf_ibs, hwc, period >> 4);
+
+ perf_event_update_userpage(event);
+
+ return 1;
+}
+
+static int __kprobes
+perf_ibs_nmi_handler(unsigned int cmd, struct pt_regs *regs)
+{
+ int handled = 0;
+
+ handled += perf_ibs_handle_irq(&perf_ibs_fetch, regs);
+ handled += perf_ibs_handle_irq(&perf_ibs_op, regs);
+
+ if (handled)
+ inc_irq_stat(apic_perf_irqs);
+
+ return handled;
+}
+
+static __init int perf_ibs_pmu_init(struct perf_ibs *perf_ibs, char *name)
+{
+ struct cpu_perf_ibs __percpu *pcpu;
+ int ret;
+
+ pcpu = alloc_percpu(struct cpu_perf_ibs);
+ if (!pcpu)
+ return -ENOMEM;
+
+ perf_ibs->pcpu = pcpu;
+
+ ret = perf_pmu_register(&perf_ibs->pmu, name, -1);
+ if (ret) {
+ perf_ibs->pcpu = NULL;
+ free_percpu(pcpu);
+ }
+
+ return ret;
+}
+
static __init int perf_event_ibs_init(void)
{
if (!ibs_caps)
return -ENODEV; /* ibs not supported by the cpu */
- perf_pmu_register(&perf_ibs, "ibs", -1);
+ perf_ibs_pmu_init(&perf_ibs_fetch, "ibs_fetch");
+ if (ibs_caps & IBS_CAPS_OPCNT)
+ perf_ibs_op.config_mask |= IBS_OP_CNT_CTL;
+ perf_ibs_pmu_init(&perf_ibs_op, "ibs_op");
+ register_nmi_handler(NMI_LOCAL, perf_ibs_nmi_handler, 0, "perf_ibs");
printk(KERN_INFO "perf: AMD IBS detected (0x%08x)\n", ibs_caps);
return 0;
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
index 26b3e2fef104..166546ec6aef 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -1027,8 +1027,6 @@ static int intel_pmu_handle_irq(struct pt_regs *regs)
u64 status;
int handled;
- perf_sample_data_init(&data, 0);
-
cpuc = &__get_cpu_var(cpu_hw_events);
/*
@@ -1082,7 +1080,7 @@ again:
if (!intel_pmu_save_and_restart(event))
continue;
- data.period = event->hw.last_period;
+ perf_sample_data_init(&data, 0, event->hw.last_period);
if (has_branch_stack(event))
data.br_stack = &cpuc->lbr_stack;
diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c
index 7f64df19e7dd..5a3edc27f6e5 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_ds.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c
@@ -316,8 +316,7 @@ int intel_pmu_drain_bts_buffer(void)
ds->bts_index = ds->bts_buffer_base;
- perf_sample_data_init(&data, 0);
- data.period = event->hw.last_period;
+ perf_sample_data_init(&data, 0, event->hw.last_period);
regs.ip = 0;
/*
@@ -564,8 +563,7 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
if (!intel_pmu_save_and_restart(event))
return;
- perf_sample_data_init(&data, 0);
- data.period = event->hw.last_period;
+ perf_sample_data_init(&data, 0, event->hw.last_period);
/*
* We use the interrupt regs as a base because the PEBS record
diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c
index a2dfacfd7103..47124a73dd73 100644
--- a/arch/x86/kernel/cpu/perf_event_p4.c
+++ b/arch/x86/kernel/cpu/perf_event_p4.c
@@ -1005,8 +1005,6 @@ static int p4_pmu_handle_irq(struct pt_regs *regs)
int idx, handled = 0;
u64 val;
- perf_sample_data_init(&data, 0);
-
cpuc = &__get_cpu_var(cpu_hw_events);
for (idx = 0; idx < x86_pmu.num_counters; idx++) {
@@ -1034,10 +1032,12 @@ static int p4_pmu_handle_irq(struct pt_regs *regs)
handled += overflow;
/* event overflow for sure */
- data.period = event->hw.last_period;
+ perf_sample_data_init(&data, 0, hwc->last_period);
if (!x86_perf_event_set_period(event))
continue;
+
+
if (perf_event_overflow(event, &data, regs))
x86_pmu_stop(event, 0);
}
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index 1b81839b6c88..571246d81edf 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -271,7 +271,7 @@ int __kprobes __die(const char *str, struct pt_regs *regs, long err)
current->thread.trap_nr, SIGSEGV) == NOTIFY_STOP)
return 1;
- show_registers(regs);
+ show_regs(regs);
#ifdef CONFIG_X86_32
if (user_mode_vm(regs)) {
sp = regs->sp;
@@ -311,16 +311,33 @@ void die(const char *str, struct pt_regs *regs, long err)
static int __init kstack_setup(char *s)
{
+ ssize_t ret;
+ unsigned long val;
+
if (!s)
return -EINVAL;
- kstack_depth_to_print = simple_strtoul(s, NULL, 0);
+
+ ret = kstrtoul(s, 0, &val);
+ if (ret)
+ return ret;
+ kstack_depth_to_print = val;
return 0;
}
early_param("kstack", kstack_setup);
static int __init code_bytes_setup(char *s)
{
- code_bytes = simple_strtoul(s, NULL, 0);
+ ssize_t ret;
+ unsigned long val;
+
+ if (!s)
+ return -EINVAL;
+
+ ret = kstrtoul(s, 0, &val);
+ if (ret)
+ return ret;
+
+ code_bytes = val;
if (code_bytes > 8192)
code_bytes = 8192;
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c
index 88ec9129271d..e0b1d783daab 100644
--- a/arch/x86/kernel/dumpstack_32.c
+++ b/arch/x86/kernel/dumpstack_32.c
@@ -82,7 +82,7 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
}
-void show_registers(struct pt_regs *regs)
+void show_regs(struct pt_regs *regs)
{
int i;
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index 17107bd6e1f0..791b76122aa8 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -245,7 +245,7 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
show_trace_log_lvl(task, regs, sp, bp, log_lvl);
}
-void show_registers(struct pt_regs *regs)
+void show_regs(struct pt_regs *regs)
{
int i;
unsigned long sp;
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 7b784f4ef1e4..01ccf9b71473 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -56,6 +56,7 @@
#include <asm/irq_vectors.h>
#include <asm/cpufeature.h>
#include <asm/alternative-asm.h>
+#include <asm/asm.h>
/* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */
#include <linux/elf-em.h>
@@ -151,10 +152,8 @@
.pushsection .fixup, "ax"
99: movl $0, (%esp)
jmp 98b
-.section __ex_table, "a"
- .align 4
- .long 98b, 99b
.popsection
+ _ASM_EXTABLE(98b,99b)
.endm
.macro PTGS_TO_GS
@@ -164,10 +163,8 @@
.pushsection .fixup, "ax"
99: movl $0, PT_GS(%esp)
jmp 98b
-.section __ex_table, "a"
- .align 4
- .long 98b, 99b
.popsection
+ _ASM_EXTABLE(98b,99b)
.endm
.macro GS_TO_REG reg
@@ -249,12 +246,10 @@
jmp 2b
6: movl $0, (%esp)
jmp 3b
-.section __ex_table, "a"
- .align 4
- .long 1b, 4b
- .long 2b, 5b
- .long 3b, 6b
.popsection
+ _ASM_EXTABLE(1b,4b)
+ _ASM_EXTABLE(2b,5b)
+ _ASM_EXTABLE(3b,6b)
POP_GS_EX
.endm
@@ -415,10 +410,7 @@ sysenter_past_esp:
jae syscall_fault
1: movl (%ebp),%ebp
movl %ebp,PT_EBP(%esp)
-.section __ex_table,"a"
- .align 4
- .long 1b,syscall_fault
-.previous
+ _ASM_EXTABLE(1b,syscall_fault)
GET_THREAD_INFO(%ebp)
@@ -485,10 +477,8 @@ sysexit_audit:
.pushsection .fixup,"ax"
2: movl $0,PT_FS(%esp)
jmp 1b
-.section __ex_table,"a"
- .align 4
- .long 1b,2b
.popsection
+ _ASM_EXTABLE(1b,2b)
PTGS_TO_GS_EX
ENDPROC(ia32_sysenter_target)
@@ -543,10 +533,7 @@ ENTRY(iret_exc)
pushl $do_iret_error
jmp error_code
.previous
-.section __ex_table,"a"
- .align 4
- .long irq_return,iret_exc
-.previous
+ _ASM_EXTABLE(irq_return,iret_exc)
CFI_RESTORE_STATE
ldt_ss:
@@ -901,10 +888,7 @@ END(device_not_available)
#ifdef CONFIG_PARAVIRT
ENTRY(native_iret)
iret
-.section __ex_table,"a"
- .align 4
- .long native_iret, iret_exc
-.previous
+ _ASM_EXTABLE(native_iret, iret_exc)
END(native_iret)
ENTRY(native_irq_enable_sysexit)
@@ -1093,13 +1077,10 @@ ENTRY(xen_failsafe_callback)
movl %eax,16(%esp)
jmp 4b
.previous
-.section __ex_table,"a"
- .align 4
- .long 1b,6b
- .long 2b,7b
- .long 3b,8b
- .long 4b,9b
-.previous
+ _ASM_EXTABLE(1b,6b)
+ _ASM_EXTABLE(2b,7b)
+ _ASM_EXTABLE(3b,8b)
+ _ASM_EXTABLE(4b,9b)
ENDPROC(xen_failsafe_callback)
BUILD_INTERRUPT3(xen_hvm_callback_vector, XEN_HVM_EVTCHN_CALLBACK,
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index cdc79b5cfcd9..320852d02026 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -55,6 +55,7 @@
#include <asm/paravirt.h>
#include <asm/ftrace.h>
#include <asm/percpu.h>
+#include <asm/asm.h>
#include <linux/err.h>
/* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */
@@ -900,18 +901,12 @@ restore_args:
irq_return:
INTERRUPT_RETURN
-
- .section __ex_table, "a"
- .quad irq_return, bad_iret
- .previous
+ _ASM_EXTABLE(irq_return, bad_iret)
#ifdef CONFIG_PARAVIRT
ENTRY(native_iret)
iretq
-
- .section __ex_table,"a"
- .quad native_iret, bad_iret
- .previous
+ _ASM_EXTABLE(native_iret, bad_iret)
#endif
.section .fixup,"ax"
@@ -1181,10 +1176,7 @@ gs_change:
CFI_ENDPROC
END(native_load_gs_index)
- .section __ex_table,"a"
- .align 8
- .quad gs_change,bad_gs
- .previous
+ _ASM_EXTABLE(gs_change,bad_gs)
.section .fixup,"ax"
/* running with kernelgs */
bad_gs:
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index c9a281f272fd..32ff36596ab1 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -24,40 +24,21 @@
#include <trace/syscall.h>
#include <asm/cacheflush.h>
+#include <asm/kprobes.h>
#include <asm/ftrace.h>
#include <asm/nops.h>
-#include <asm/nmi.h>
-
#ifdef CONFIG_DYNAMIC_FTRACE
-/*
- * modifying_code is set to notify NMIs that they need to use
- * memory barriers when entering or exiting. But we don't want
- * to burden NMIs with unnecessary memory barriers when code
- * modification is not being done (which is most of the time).
- *
- * A mutex is already held when ftrace_arch_code_modify_prepare
- * and post_process are called. No locks need to be taken here.
- *
- * Stop machine will make sure currently running NMIs are done
- * and new NMIs will see the updated variable before we need
- * to worry about NMIs doing memory barriers.
- */
-static int modifying_code __read_mostly;
-static DEFINE_PER_CPU(int, save_modifying_code);
-
int ftrace_arch_code_modify_prepare(void)
{
set_kernel_text_rw();
set_all_modules_text_rw();
- modifying_code = 1;
return 0;
}
int ftrace_arch_code_modify_post_process(void)
{
- modifying_code = 0;
set_all_modules_text_ro();
set_kernel_text_ro();
return 0;
@@ -90,134 +71,6 @@ static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
return calc.code;
}
-/*
- * Modifying code must take extra care. On an SMP machine, if
- * the code being modified is also being executed on another CPU
- * that CPU will have undefined results and possibly take a GPF.
- * We use kstop_machine to stop other CPUS from exectuing code.
- * But this does not stop NMIs from happening. We still need
- * to protect against that. We separate out the modification of
- * the code to take care of this.
- *
- * Two buffers are added: An IP buffer and a "code" buffer.
- *
- * 1) Put the instruction pointer into the IP buffer
- * and the new code into the "code" buffer.
- * 2) Wait for any running NMIs to finish and set a flag that says
- * we are modifying code, it is done in an atomic operation.
- * 3) Write the code
- * 4) clear the flag.
- * 5) Wait for any running NMIs to finish.
- *
- * If an NMI is executed, the first thing it does is to call
- * "ftrace_nmi_enter". This will check if the flag is set to write
- * and if it is, it will write what is in the IP and "code" buffers.
- *
- * The trick is, it does not matter if everyone is writing the same
- * content to the code location. Also, if a CPU is executing code
- * it is OK to write to that code location if the contents being written
- * are the same as what exists.
- */
-
-#define MOD_CODE_WRITE_FLAG (1 << 31) /* set when NMI should do the write */
-static atomic_t nmi_running = ATOMIC_INIT(0);
-static int mod_code_status; /* holds return value of text write */
-static void *mod_code_ip; /* holds the IP to write to */
-static const void *mod_code_newcode; /* holds the text to write to the IP */
-
-static unsigned nmi_wait_count;
-static atomic_t nmi_update_count = ATOMIC_INIT(0);
-
-int ftrace_arch_read_dyn_info(char *buf, int size)
-{
- int r;
-
- r = snprintf(buf, size, "%u %u",
- nmi_wait_count,
- atomic_read(&nmi_update_count));
- return r;
-}
-
-static void clear_mod_flag(void)
-{
- int old = atomic_read(&nmi_running);
-
- for (;;) {
- int new = old & ~MOD_CODE_WRITE_FLAG;
-
- if (old == new)
- break;
-
- old = atomic_cmpxchg(&nmi_running, old, new);
- }
-}
-
-static void ftrace_mod_code(void)
-{
- /*
- * Yes, more than one CPU process can be writing to mod_code_status.
- * (and the code itself)
- * But if one were to fail, then they all should, and if one were
- * to succeed, then they all should.
- */
- mod_code_status = probe_kernel_write(mod_code_ip, mod_code_newcode,
- MCOUNT_INSN_SIZE);
-
- /* if we fail, then kill any new writers */
- if (mod_code_status)
- clear_mod_flag();
-}
-
-void ftrace_nmi_enter(void)
-{
- __this_cpu_write(save_modifying_code, modifying_code);
-
- if (!__this_cpu_read(save_modifying_code))
- return;
-
- if (atomic_inc_return(&nmi_running) & MOD_CODE_WRITE_FLAG) {
- smp_rmb();
- ftrace_mod_code();
- atomic_inc(&nmi_update_count);
- }
- /* Must have previous changes seen before executions */
- smp_mb();
-}
-
-void ftrace_nmi_exit(void)
-{
- if (!__this_cpu_read(save_modifying_code))
- return;
-
- /* Finish all executions before clearing nmi_running */
- smp_mb();
- atomic_dec(&nmi_running);
-}
-
-static void wait_for_nmi_and_set_mod_flag(void)
-{
- if (!atomic_cmpxchg(&nmi_running, 0, MOD_CODE_WRITE_FLAG))
- return;
-
- do {
- cpu_relax();
- } while (atomic_cmpxchg(&nmi_running, 0, MOD_CODE_WRITE_FLAG));
-
- nmi_wait_count++;
-}
-
-static void wait_for_nmi(void)
-{
- if (!atomic_read(&nmi_running))
- return;
-
- do {
- cpu_relax();
- } while (atomic_read(&nmi_running));
-
- nmi_wait_count++;
-}
-
static inline int
within(unsigned long addr, unsigned long start, unsigned long end)
{
@@ -238,26 +91,7 @@ do_ftrace_mod_code(unsigned long ip, const void *new_code)
if (within(ip, (unsigned long)_text, (unsigned long)_etext))
ip = (unsigned long)__va(__pa(ip));
- mod_code_ip = (void *)ip;
- mod_code_newcode = new_code;
-
- /* The buffers need to be visible before we let NMIs write them */
- smp_mb();
-
- wait_for_nmi_and_set_mod_flag();
-
- /* Make sure all running NMIs have finished before we write the code */
- smp_mb();
-
- ftrace_mod_code();
-
- /* Make sure the write happens before clearing the bit */
- smp_mb();
-
- clear_mod_flag();
- wait_for_nmi();
-
- return mod_code_status;
+ return probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE);
}
static const unsigned char *ftrace_nop_replace(void)
@@ -334,6 +168,336 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
return ret;
}
+int modifying_ftrace_code __read_mostly;
+
+/*
+ * A breakpoint was added to the code address we are about to
+ * modify, and this is the handle that will just skip over it.
+ * We are either changing a nop into a trace call, or a trace
+ * call to a nop. While the change is taking place, we treat
+ * it just like it was a nop.
+ */
+int ftrace_int3_handler(struct pt_regs *regs)
+{
+ if (WARN_ON_ONCE(!regs))
+ return 0;
+
+ if (!ftrace_location(regs->ip - 1))
+ return 0;
+
+ regs->ip += MCOUNT_INSN_SIZE - 1;
+
+ return 1;
+}
+
+static int ftrace_write(unsigned long ip, const char *val, int size)
+{
+ /*
+ * On x86_64, kernel text mappings are mapped read-only with
+ * CONFIG_DEBUG_RODATA. So we use the kernel identity mapping instead
+ * of the kernel text mapping to modify the kernel text.
+ *
+ * For 32bit kernels, these mappings are same and we can use
+ * kernel identity mapping to modify code.
+ */
+ if (within(ip, (unsigned long)_text, (unsigned long)_etext))
+ ip = (unsigned long)__va(__pa(ip));
+
+ return probe_kernel_write((void *)ip, val, size);
+}
+
+static int add_break(unsigned long ip, const char *old)
+{
+ unsigned char replaced[MCOUNT_INSN_SIZE];
+ unsigned char brk = BREAKPOINT_INSTRUCTION;
+
+ if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE))
+ return -EFAULT;
+
+ /* Make sure it is what we expect it to be */
+ if (memcmp(replaced, old, MCOUNT_INSN_SIZE) != 0)
+ return -EINVAL;
+
+ if (ftrace_write(ip, &brk, 1))
+ return -EPERM;
+
+ return 0;
+}
+
+static int add_brk_on_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+ unsigned const char *old;
+ unsigned long ip = rec->ip;
+
+ old = ftrace_call_replace(ip, addr);
+
+ return add_break(rec->ip, old);
+}
+
+
+static int add_brk_on_nop(struct dyn_ftrace *rec)
+{
+ unsigned const char *old;
+
+ old = ftrace_nop_replace();
+
+ return add_break(rec->ip, old);
+}
+
+static int add_breakpoints(struct dyn_ftrace *rec, int enable)
+{
+ unsigned long ftrace_addr;
+ int ret;
+
+ ret = ftrace_test_record(rec, enable);
+
+ ftrace_addr = (unsigned long)FTRACE_ADDR;
+
+ switch (ret) {
+ case FTRACE_UPDATE_IGNORE:
+ return 0;
+
+ case FTRACE_UPDATE_MAKE_CALL:
+ /* converting nop to call */
+ return add_brk_on_nop(rec);
+
+ case FTRACE_UPDATE_MAKE_NOP:
+ /* converting a call to a nop */
+ return add_brk_on_call(rec, ftrace_addr);
+ }
+ return 0;
+}
+
+/*
+ * On error, we need to remove breakpoints. This needs to
+ * be done caefully. If the address does not currently have a
+ * breakpoint, we know we are done. Otherwise, we look at the
+ * remaining 4 bytes of the instruction. If it matches a nop
+ * we replace the breakpoint with the nop. Otherwise we replace
+ * it with the call instruction.
+ */
+static int remove_breakpoint(struct dyn_ftrace *rec)
+{
+ unsigned char ins[MCOUNT_INSN_SIZE];
+ unsigned char brk = BREAKPOINT_INSTRUCTION;
+ const unsigned char *nop;
+ unsigned long ftrace_addr;
+ unsigned long ip = rec->ip;
+
+ /* If we fail the read, just give up */
+ if (probe_kernel_read(ins, (void *)ip, MCOUNT_INSN_SIZE))
+ return -EFAULT;
+
+ /* If this does not have a breakpoint, we are done */
+ if (ins[0] != brk)
+ return -1;
+
+ nop = ftrace_nop_replace();
+
+ /*
+ * If the last 4 bytes of the instruction do not match
+ * a nop, then we assume that this is a call to ftrace_addr.
+ */
+ if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) != 0) {
+ /*
+ * For extra paranoidism, we check if the breakpoint is on
+ * a call that would actually jump to the ftrace_addr.
+ * If not, don't touch the breakpoint, we make just create
+ * a disaster.
+ */
+ ftrace_addr = (unsigned long)FTRACE_ADDR;
+ nop = ftrace_call_replace(ip, ftrace_addr);
+
+ if (memcmp(&ins[1], &nop[1], MCOUNT_INSN_SIZE - 1) != 0)
+ return -EINVAL;
+ }
+
+ return probe_kernel_write((void *)ip, &nop[0], 1);
+}
+
+static int add_update_code(unsigned long ip, unsigned const char *new)
+{
+ /* skip breakpoint */
+ ip++;
+ new++;
+ if (ftrace_write(ip, new, MCOUNT_INSN_SIZE - 1))
+ return -EPERM;
+ return 0;
+}
+
+static int add_update_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+ unsigned long ip = rec->ip;
+ unsigned const char *new;
+
+ new = ftrace_call_replace(ip, addr);
+ return add_update_code(ip, new);
+}
+
+static int add_update_nop(struct dyn_ftrace *rec)
+{
+ unsigned long ip = rec->ip;
+ unsigned const char *new;
+
+ new = ftrace_nop_replace();
+ return add_update_code(ip, new);
+}
+
+static int add_update(struct dyn_ftrace *rec, int enable)
+{
+ unsigned long ftrace_addr;
+ int ret;
+
+ ret = ftrace_test_record(rec, enable);
+
+ ftrace_addr = (unsigned long)FTRACE_ADDR;
+
+ switch (ret) {
+ case FTRACE_UPDATE_IGNORE:
+ return 0;
+
+ case FTRACE_UPDATE_MAKE_CALL:
+ /* converting nop to call */
+ return add_update_call(rec, ftrace_addr);
+
+ case FTRACE_UPDATE_MAKE_NOP:
+ /* converting a call to a nop */
+ return add_update_nop(rec);
+ }
+
+ return 0;
+}
+
+static int finish_update_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+ unsigned long ip = rec->ip;
+ unsigned const char *new;
+
+ new = ftrace_call_replace(ip, addr);
+
+ if (ftrace_write(ip, new, 1))
+ return -EPERM;
+
+ return 0;
+}
+
+static int finish_update_nop(struct dyn_ftrace *rec)
+{
+ unsigned long ip = rec->ip;
+ unsigned const char *new;
+
+ new = ftrace_nop_replace();
+
+ if (ftrace_write(ip, new, 1))
+ return -EPERM;
+ return 0;
+}
+
+static int finish_update(struct dyn_ftrace *rec, int enable)
+{
+ unsigned long ftrace_addr;
+ int ret;
+
+ ret = ftrace_update_record(rec, enable);
+
+ ftrace_addr = (unsigned long)FTRACE_ADDR;
+
+ switch (ret) {
+ case FTRACE_UPDATE_IGNORE:
+ return 0;
+
+ case FTRACE_UPDATE_MAKE_CALL:
+ /* converting nop to call */
+ return finish_update_call(rec, ftrace_addr);
+
+ case FTRACE_UPDATE_MAKE_NOP:
+ /* converting a call to a nop */
+ return finish_update_nop(rec);
+ }
+
+ return 0;
+}
+
+static void do_sync_core(void *data)
+{
+ sync_core();
+}
+
+static void run_sync(void)
+{
+ int enable_irqs = irqs_disabled();
+
+ /* We may be called with interrupts disbled (on bootup). */
+ if (enable_irqs)
+ local_irq_enable();
+ on_each_cpu(do_sync_core, NULL, 1);
+ if (enable_irqs)
+ local_irq_disable();
+}
+
+void ftrace_replace_code(int enable)
+{
+ struct ftrace_rec_iter *iter;
+ struct dyn_ftrace *rec;
+ const char *report = "adding breakpoints";
+ int count = 0;
+ int ret;
+
+ for_ftrace_rec_iter(iter) {
+ rec = ftrace_rec_iter_record(iter);
+
+ ret = add_breakpoints(rec, enable);
+ if (ret)
+ goto remove_breakpoints;
+ count++;
+ }
+
+ run_sync();
+
+ report = "updating code";
+
+ for_ftrace_rec_iter(iter) {
+ rec = ftrace_rec_iter_record(iter);
+
+ ret = add_update(rec, enable);
+ if (ret)
+ goto remove_breakpoints;
+ }
+
+ run_sync();
+
+ report = "removing breakpoints";
+
+ for_ftrace_rec_iter(iter) {
+ rec = ftrace_rec_iter_record(iter);
+
+ ret = finish_update(rec, enable);
+ if (ret)
+ goto remove_breakpoints;
+ }
+
+ run_sync();
+
+ return;
+
+ remove_breakpoints:
+ ftrace_bug(ret, rec ? rec->ip : 0);
+ printk(KERN_WARNING "Failed on %s (%d):\n", report, count);
+ for_ftrace_rec_iter(iter) {
+ rec = ftrace_rec_iter_record(iter);
+ remove_breakpoint(rec);
+ }
+}
+
+void arch_ftrace_update_code(int command)
+{
+ modifying_ftrace_code++;
+
+ ftrace_modify_all_code(command);
+
+ modifying_ftrace_code--;
+}
+
int __init ftrace_dyn_arch_init(void *data)
{
/* The return code is retured via data */
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index ce0be7cd085e..463c9797ca6a 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -21,6 +21,7 @@
#include <asm/msr-index.h>
#include <asm/cpufeature.h>
#include <asm/percpu.h>
+#include <asm/nops.h>
/* Physical address */
#define pa(X) ((X) - __PAGE_OFFSET)
@@ -363,28 +364,23 @@ default_entry:
pushl $0
popfl
-#ifdef CONFIG_SMP
- cmpb $0, ready
- jnz checkCPUtype
-#endif /* CONFIG_SMP */
-
/*
* start system 32-bit setup. We need to re-do some of the things done
* in 16-bit mode for the "real" operations.
*/
- call setup_idt
-
-checkCPUtype:
-
- movl $-1,X86_CPUID # -1 for no CPUID initially
-
+ movl setup_once_ref,%eax
+ andl %eax,%eax
+ jz 1f # Did we do this already?
+ call *%eax
+1:
+
/* check if it is 486 or 386. */
/*
* XXX - this does a lot of unnecessary setup. Alignment checks don't
* apply at our cpl of 0 and the stack ought to be aligned already, and
* we don't need to preserve eflags.
*/
-
+ movl $-1,X86_CPUID # -1 for no CPUID initially
movb $3,X86 # at least 386
pushfl # push EFLAGS
popl %eax # get EFLAGS
@@ -450,21 +446,6 @@ is386: movl $2,%ecx # set MP
movl $(__KERNEL_PERCPU), %eax
movl %eax,%fs # set this cpu's percpu
-#ifdef CONFIG_CC_STACKPROTECTOR
- /*
- * The linker can't handle this by relocation. Manually set
- * base address in stack canary segment descriptor.
- */
- cmpb $0,ready
- jne 1f
- movl $gdt_page,%eax
- movl $stack_canary,%ecx
- movw %cx, 8 * GDT_ENTRY_STACK_CANARY + 2(%eax)
- shrl $16, %ecx
- movb %cl, 8 * GDT_ENTRY_STACK_CANARY + 4(%eax)
- movb %ch, 8 * GDT_ENTRY_STACK_CANARY + 7(%eax)
-1:
-#endif
movl $(__KERNEL_STACK_CANARY),%eax
movl %eax,%gs
@@ -473,7 +454,6 @@ is386: movl $2,%ecx # set MP
cld # gcc2 wants the direction flag cleared at all times
pushl $0 # fake return address for unwinder
- movb $1, ready
jmp *(initial_code)
/*
@@ -495,81 +475,122 @@ check_x87:
.byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */
ret
+
+#include "verify_cpu.S"
+
/*
- * setup_idt
+ * setup_once
*
- * sets up a idt with 256 entries pointing to
- * ignore_int, interrupt gates. It doesn't actually load
- * idt - that can be done only after paging has been enabled
- * and the kernel moved to PAGE_OFFSET. Interrupts
- * are enabled elsewhere, when we can be relatively
- * sure everything is ok.
+ * The setup work we only want to run on the BSP.
*
* Warning: %esi is live across this function.
*/
-setup_idt:
- lea ignore_int,%edx
- movl $(__KERNEL_CS << 16),%eax
- movw %dx,%ax /* selector = 0x0010 = cs */
- movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
+__INIT
+setup_once:
+ /*
+ * Set up a idt with 256 entries pointing to ignore_int,
+ * interrupt gates. It doesn't actually load idt - that needs
+ * to be done on each CPU. Interrupts are enabled elsewhere,
+ * when we can be relatively sure everything is ok.
+ */
- lea idt_table,%edi
- mov $256,%ecx
-rp_sidt:
+ movl $idt_table,%edi
+ movl $early_idt_handlers,%eax
+ movl $NUM_EXCEPTION_VECTORS,%ecx
+1:
movl %eax,(%edi)
- movl %edx,4(%edi)
+ movl %eax,4(%edi)
+ /* interrupt gate, dpl=0, present */
+ movl $(0x8E000000 + __KERNEL_CS),2(%edi)
+ addl $9,%eax
addl $8,%edi
- dec %ecx
- jne rp_sidt
+ loop 1b
-.macro set_early_handler handler,trapno
- lea \handler,%edx
+ movl $256 - NUM_EXCEPTION_VECTORS,%ecx
+ movl $ignore_int,%edx
movl $(__KERNEL_CS << 16),%eax
- movw %dx,%ax
+ movw %dx,%ax /* selector = 0x0010 = cs */
movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
- lea idt_table,%edi
- movl %eax,8*\trapno(%edi)
- movl %edx,8*\trapno+4(%edi)
-.endm
+2:
+ movl %eax,(%edi)
+ movl %edx,4(%edi)
+ addl $8,%edi
+ loop 2b
- set_early_handler handler=early_divide_err,trapno=0
- set_early_handler handler=early_illegal_opcode,trapno=6
- set_early_handler handler=early_protection_fault,trapno=13
- set_early_handler handler=early_page_fault,trapno=14
+#ifdef CONFIG_CC_STACKPROTECTOR
+ /*
+ * Configure the stack canary. The linker can't handle this by
+ * relocation. Manually set base address in stack canary
+ * segment descriptor.
+ */
+ movl $gdt_page,%eax
+ movl $stack_canary,%ecx
+ movw %cx, 8 * GDT_ENTRY_STACK_CANARY + 2(%eax)
+ shrl $16, %ecx
+ movb %cl, 8 * GDT_ENTRY_STACK_CANARY + 4(%eax)
+ movb %ch, 8 * GDT_ENTRY_STACK_CANARY + 7(%eax)
+#endif
+ andl $0,setup_once_ref /* Once is enough, thanks */
ret
-early_divide_err:
- xor %edx,%edx
- pushl $0 /* fake errcode */
- jmp early_fault
+ENTRY(early_idt_handlers)
+ # 36(%esp) %eflags
+ # 32(%esp) %cs
+ # 28(%esp) %eip
+ # 24(%rsp) error code
+ i = 0
+ .rept NUM_EXCEPTION_VECTORS
+ .if (EXCEPTION_ERRCODE_MASK >> i) & 1
+ ASM_NOP2
+ .else
+ pushl $0 # Dummy error code, to make stack frame uniform
+ .endif
+ pushl $i # 20(%esp) Vector number
+ jmp early_idt_handler
+ i = i + 1
+ .endr
+ENDPROC(early_idt_handlers)
+
+ /* This is global to keep gas from relaxing the jumps */
+ENTRY(early_idt_handler)
+ cld
+ cmpl $2,%ss:early_recursion_flag
+ je hlt_loop
+ incl %ss:early_recursion_flag
-early_illegal_opcode:
- movl $6,%edx
- pushl $0 /* fake errcode */
- jmp early_fault
+ push %eax # 16(%esp)
+ push %ecx # 12(%esp)
+ push %edx # 8(%esp)
+ push %ds # 4(%esp)
+ push %es # 0(%esp)
+ movl $(__KERNEL_DS),%eax
+ movl %eax,%ds
+ movl %eax,%es
-early_protection_fault:
- movl $13,%edx
- jmp early_fault
+ cmpl $(__KERNEL_CS),32(%esp)
+ jne 10f
-early_page_fault:
- movl $14,%edx
- jmp early_fault
+ leal 28(%esp),%eax # Pointer to %eip
+ call early_fixup_exception
+ andl %eax,%eax
+ jnz ex_entry /* found an exception entry */
-early_fault:
- cld
+10:
#ifdef CONFIG_PRINTK
- pusha
- movl $(__KERNEL_DS),%eax
- movl %eax,%ds
- movl %eax,%es
- cmpl $2,early_recursion_flag
- je hlt_loop
- incl early_recursion_flag
+ xorl %eax,%eax
+ movw %ax,2(%esp) /* clean up the segment values on some cpus */
+ movw %ax,6(%esp)
+ movw %ax,34(%esp)
+ leal 40(%esp),%eax
+ pushl %eax /* %esp before the exception */
+ pushl %ebx
+ pushl %ebp
+ pushl %esi
+ pushl %edi
movl %cr2,%eax
pushl %eax
- pushl %edx /* trapno */
+ pushl (20+6*4)(%esp) /* trapno */
pushl $fault_msg
call printk
#endif
@@ -578,6 +599,17 @@ hlt_loop:
hlt
jmp hlt_loop
+ex_entry:
+ pop %es
+ pop %ds
+ pop %edx
+ pop %ecx
+ pop %eax
+ addl $8,%esp /* drop vector number and error code */
+ decl %ss:early_recursion_flag
+ iret
+ENDPROC(early_idt_handler)
+
/* This is the default interrupt "handler" :-) */
ALIGN
ignore_int:
@@ -611,13 +643,18 @@ ignore_int:
popl %eax
#endif
iret
+ENDPROC(ignore_int)
+__INITDATA
+ .align 4
+early_recursion_flag:
+ .long 0
-#include "verify_cpu.S"
-
- __REFDATA
-.align 4
+__REFDATA
+ .align 4
ENTRY(initial_code)
.long i386_start_kernel
+ENTRY(setup_once_ref)
+ .long setup_once
/*
* BSS section
@@ -670,22 +707,19 @@ ENTRY(initial_page_table)
ENTRY(stack_start)
.long init_thread_union+THREAD_SIZE
-early_recursion_flag:
- .long 0
-
-ready: .byte 0
-
+__INITRODATA
int_msg:
.asciz "Unknown interrupt or fault at: %p %p %p\n"
fault_msg:
/* fault info: */
.ascii "BUG: Int %d: CR2 %p\n"
-/* pusha regs: */
- .ascii " EDI %p ESI %p EBP %p ESP %p\n"
- .ascii " EBX %p EDX %p ECX %p EAX %p\n"
+/* regs pushed in early_idt_handler: */
+ .ascii " EDI %p ESI %p EBP %p EBX %p\n"
+ .ascii " ESP %p ES %p DS %p\n"
+ .ascii " EDX %p ECX %p EAX %p\n"
/* fault frame: */
- .ascii " err %p EIP %p CS %p flg %p\n"
+ .ascii " vec %p err %p EIP %p CS %p flg %p\n"
.ascii "Stack: %p %p %p %p %p %p %p %p\n"
.ascii " %p %p %p %p %p %p %p %p\n"
.asciz " %p %p %p %p %p %p %p %p\n"
@@ -699,6 +733,7 @@ fault_msg:
* segment size, and 32-bit linear address value:
*/
+ .data
.globl boot_gdt_descr
.globl idt_descr
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index 40f4eb3766d1..7a40f2447321 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -19,12 +19,15 @@
#include <asm/cache.h>
#include <asm/processor-flags.h>
#include <asm/percpu.h>
+#include <asm/nops.h>
#ifdef CONFIG_PARAVIRT
#include <asm/asm-offsets.h>
#include <asm/paravirt.h>
+#define GET_CR2_INTO(reg) GET_CR2_INTO_RAX ; movq %rax, reg
#else
-#define GET_CR2_INTO_RCX movq %cr2, %rcx
+#define GET_CR2_INTO(reg) movq %cr2, reg
+#define INTERRUPT_RETURN iretq
#endif
/* we are not able to switch in one step to the final KERNEL ADDRESS SPACE
@@ -270,36 +273,56 @@ bad_address:
jmp bad_address
.section ".init.text","ax"
-#ifdef CONFIG_EARLY_PRINTK
.globl early_idt_handlers
early_idt_handlers:
+ # 104(%rsp) %rflags
+ # 96(%rsp) %cs
+ # 88(%rsp) %rip
+ # 80(%rsp) error code
i = 0
.rept NUM_EXCEPTION_VECTORS
- movl $i, %esi
+ .if (EXCEPTION_ERRCODE_MASK >> i) & 1
+ ASM_NOP2
+ .else
+ pushq $0 # Dummy error code, to make stack frame uniform
+ .endif
+ pushq $i # 72(%rsp) Vector number
jmp early_idt_handler
i = i + 1
.endr
-#endif
ENTRY(early_idt_handler)
-#ifdef CONFIG_EARLY_PRINTK
+ cld
+
cmpl $2,early_recursion_flag(%rip)
jz 1f
incl early_recursion_flag(%rip)
- GET_CR2_INTO_RCX
- movq %rcx,%r9
- xorl %r8d,%r8d # zero for error code
- movl %esi,%ecx # get vector number
- # Test %ecx against mask of vectors that push error code.
- cmpl $31,%ecx
- ja 0f
- movl $1,%eax
- salq %cl,%rax
- testl $0x27d00,%eax
- je 0f
- popq %r8 # get error code
-0: movq 0(%rsp),%rcx # get ip
- movq 8(%rsp),%rdx # get cs
+
+ pushq %rax # 64(%rsp)
+ pushq %rcx # 56(%rsp)
+ pushq %rdx # 48(%rsp)
+ pushq %rsi # 40(%rsp)
+ pushq %rdi # 32(%rsp)
+ pushq %r8 # 24(%rsp)
+ pushq %r9 # 16(%rsp)
+ pushq %r10 # 8(%rsp)
+ pushq %r11 # 0(%rsp)
+
+ cmpl $__KERNEL_CS,96(%rsp)
+ jne 10f
+
+ leaq 88(%rsp),%rdi # Pointer to %rip
+ call early_fixup_exception
+ andl %eax,%eax
+ jnz 20f # Found an exception entry
+
+10:
+#ifdef CONFIG_EARLY_PRINTK
+ GET_CR2_INTO(%r9) # can clobber any volatile register if pv
+ movl 80(%rsp),%r8d # error code
+ movl 72(%rsp),%esi # vector number
+ movl 96(%rsp),%edx # %cs
+ movq 88(%rsp),%rcx # %rip
xorl %eax,%eax
leaq early_idt_msg(%rip),%rdi
call early_printk
@@ -308,17 +331,32 @@ ENTRY(early_idt_handler)
call dump_stack
#ifdef CONFIG_KALLSYMS
leaq early_idt_ripmsg(%rip),%rdi
- movq 0(%rsp),%rsi # get rip again
+ movq 40(%rsp),%rsi # %rip again
call __print_symbol
#endif
#endif /* EARLY_PRINTK */
1: hlt
jmp 1b
-#ifdef CONFIG_EARLY_PRINTK
+20: # Exception table entry found
+ popq %r11
+ popq %r10
+ popq %r9
+ popq %r8
+ popq %rdi
+ popq %rsi
+ popq %rdx
+ popq %rcx
+ popq %rax
+ addq $16,%rsp # drop vector number and error code
+ decl early_recursion_flag(%rip)
+ INTERRUPT_RETURN
+
+ .balign 4
early_recursion_flag:
.long 0
+#ifdef CONFIG_EARLY_PRINTK
early_idt_msg:
.asciz "PANIC: early exception %02lx rip %lx:%lx error %lx cr2 %lx\n"
early_idt_ripmsg:
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index ad0de0c2714e..9cc7b4392f7c 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -94,13 +94,18 @@ static int hpet_verbose;
static int __init hpet_setup(char *str)
{
- if (str) {
+ while (str) {
+ char *next = strchr(str, ',');
+
+ if (next)
+ *next++ = 0;
if (!strncmp("disable", str, 7))
boot_hpet_disable = 1;
if (!strncmp("force", str, 5))
hpet_force_user = 1;
if (!strncmp("verbose", str, 7))
hpet_verbose = 1;
+ str = next;
}
return 1;
}
@@ -319,8 +324,6 @@ static void hpet_set_mode(enum clock_event_mode mode,
now = hpet_readl(HPET_COUNTER);
cmp = now + (unsigned int) delta;
cfg = hpet_readl(HPET_Tn_CFG(timer));
- /* Make sure we use edge triggered interrupts */
- cfg &= ~HPET_TN_LEVEL;
cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC |
HPET_TN_SETVAL | HPET_TN_32BIT;
hpet_writel(cfg, HPET_Tn_CFG(timer));
@@ -787,15 +790,16 @@ static int hpet_clocksource_register(void)
return 0;
}
+static u32 *hpet_boot_cfg;
+
/**
* hpet_enable - Try to setup the HPET timer. Returns 1 on success.
*/
int __init hpet_enable(void)
{
- unsigned long hpet_period;
- unsigned int id;
+ u32 hpet_period, cfg, id;
u64 freq;
- int i;
+ unsigned int i, last;
if (!is_hpet_capable())
return 0;
@@ -847,15 +851,45 @@ int __init hpet_enable(void)
id = hpet_readl(HPET_ID);
hpet_print_config();
+ last = (id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT;
+
#ifdef CONFIG_HPET_EMULATE_RTC
/*
* The legacy routing mode needs at least two channels, tick timer
* and the rtc emulation channel.
*/
- if (!(id & HPET_ID_NUMBER))
+ if (!last)
goto out_nohpet;
#endif
+ cfg = hpet_readl(HPET_CFG);
+ hpet_boot_cfg = kmalloc((last + 2) * sizeof(*hpet_boot_cfg),
+ GFP_KERNEL);
+ if (hpet_boot_cfg)
+ *hpet_boot_cfg = cfg;
+ else
+ pr_warn("HPET initial state will not be saved\n");
+ cfg &= ~(HPET_CFG_ENABLE | HPET_CFG_LEGACY);
+ hpet_writel(cfg, HPET_Tn_CFG(i));
+ if (cfg)
+ pr_warn("HPET: Unrecognized bits %#x set in global cfg\n",
+ cfg);
+
+ for (i = 0; i <= last; ++i) {
+ cfg = hpet_readl(HPET_Tn_CFG(i));
+ if (hpet_boot_cfg)
+ hpet_boot_cfg[i + 1] = cfg;
+ cfg &= ~(HPET_TN_ENABLE | HPET_TN_LEVEL | HPET_TN_FSB);
+ hpet_writel(cfg, HPET_Tn_CFG(i));
+ cfg &= ~(HPET_TN_PERIODIC | HPET_TN_PERIODIC_CAP
+ | HPET_TN_64BIT_CAP | HPET_TN_32BIT | HPET_TN_ROUTE
+ | HPET_TN_FSB | HPET_TN_FSB_CAP);
+ if (cfg)
+ pr_warn("HPET: Unrecognized bits %#x set in cfg#%u\n",
+ cfg, i);
+ }
+ hpet_print_config();
+
if (hpet_clocksource_register())
goto out_nohpet;
@@ -923,14 +957,28 @@ fs_initcall(hpet_late_init);
void hpet_disable(void)
{
if (is_hpet_capable() && hpet_virt_address) {
- unsigned int cfg = hpet_readl(HPET_CFG);
+ unsigned int cfg = hpet_readl(HPET_CFG), id, last;
- if (hpet_legacy_int_enabled) {
+ if (hpet_boot_cfg)
+ cfg = *hpet_boot_cfg;
+ else if (hpet_legacy_int_enabled) {
cfg &= ~HPET_CFG_LEGACY;
hpet_legacy_int_enabled = 0;
}
cfg &= ~HPET_CFG_ENABLE;
hpet_writel(cfg, HPET_CFG);
+
+ if (!hpet_boot_cfg)
+ return;
+
+ id = hpet_readl(HPET_ID);
+ last = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT);
+
+ for (id = 0; id <= last; ++id)
+ hpet_writel(hpet_boot_cfg[id + 1], HPET_Tn_CFG(id));
+
+ if (*hpet_boot_cfg & HPET_CFG_ENABLE)
+ hpet_writel(*hpet_boot_cfg, HPET_CFG);
}
}
diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index 2d6e6498c176..f250431fb505 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -88,7 +88,7 @@ void kernel_fpu_begin(void)
__thread_clear_has_fpu(me);
/* We do 'stts()' in kernel_fpu_end() */
} else {
- percpu_write(fpu_owner_task, NULL);
+ this_cpu_write(fpu_owner_task, NULL);
clts();
}
}
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c
index e213fc8408d2..e2f751efb7b1 100644
--- a/arch/x86/kernel/kprobes.c
+++ b/arch/x86/kernel/kprobes.c
@@ -1037,9 +1037,9 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
"current sp %p does not match saved sp %p\n",
stack_addr(regs), kcb->jprobe_saved_sp);
printk(KERN_ERR "Saved registers for jprobe %p\n", jp);
- show_registers(saved_regs);
+ show_regs(saved_regs);
printk(KERN_ERR "Current registers\n");
- show_registers(regs);
+ show_regs(regs);
BUG();
}
*regs = kcb->jprobe_saved_regs;
diff --git a/arch/x86/kernel/mca_32.c b/arch/x86/kernel/mca_32.c
deleted file mode 100644
index 7eb1e2b97827..000000000000
--- a/arch/x86/kernel/mca_32.c
+++ /dev/null
@@ -1,476 +0,0 @@
-/*
- * Written by Martin Kolinek, February 1996
- *
- * Changes:
- *
- * Chris Beauregard July 28th, 1996
- * - Fixed up integrated SCSI detection
- *
- * Chris Beauregard August 3rd, 1996
- * - Made mca_info local
- * - Made integrated registers accessible through standard function calls
- * - Added name field
- * - More sanity checking
- *
- * Chris Beauregard August 9th, 1996
- * - Rewrote /proc/mca
- *
- * Chris Beauregard January 7th, 1997
- * - Added basic NMI-processing
- * - Added more information to mca_info structure
- *
- * David Weinehall October 12th, 1998
- * - Made a lot of cleaning up in the source
- * - Added use of save_flags / restore_flags
- * - Added the 'driver_loaded' flag in MCA_adapter
- * - Added an alternative implemention of ZP Gu's mca_find_unused_adapter
- *
- * David Weinehall March 24th, 1999
- * - Fixed the output of 'Driver Installed' in /proc/mca/pos
- * - Made the Integrated Video & SCSI show up even if they have id 0000
- *
- * Alexander Viro November 9th, 1999
- * - Switched to regular procfs methods
- *
- * Alfred Arnold & David Weinehall August 23rd, 2000
- * - Added support for Planar POS-registers
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/mca.h>
-#include <linux/kprobes.h>
-#include <linux/slab.h>
-#include <asm/io.h>
-#include <linux/proc_fs.h>
-#include <linux/mman.h>
-#include <linux/mm.h>
-#include <linux/pagemap.h>
-#include <linux/ioport.h>
-#include <asm/uaccess.h>
-#include <linux/init.h>
-
-static unsigned char which_scsi;
-
-int MCA_bus;
-EXPORT_SYMBOL(MCA_bus);
-
-/*
- * Motherboard register spinlock. Untested on SMP at the moment, but
- * are there any MCA SMP boxes?
- *
- * Yes - Alan
- */
-static DEFINE_SPINLOCK(mca_lock);
-
-/* Build the status info for the adapter */
-
-static void mca_configure_adapter_status(struct mca_device *mca_dev)
-{
- mca_dev->status = MCA_ADAPTER_NONE;
-
- mca_dev->pos_id = mca_dev->pos[0]
- + (mca_dev->pos[1] << 8);
-
- if (!mca_dev->pos_id && mca_dev->slot < MCA_MAX_SLOT_NR) {
-
- /*
- * id = 0x0000 usually indicates hardware failure,
- * however, ZP Gu (zpg@castle.net> reports that his 9556
- * has 0x0000 as id and everything still works. There
- * also seem to be an adapter with id = 0x0000; the
- * NCR Parallel Bus Memory Card. Until this is confirmed,
- * however, this code will stay.
- */
-
- mca_dev->status = MCA_ADAPTER_ERROR;
-
- return;
- } else if (mca_dev->pos_id != 0xffff) {
-
- /*
- * 0xffff usually indicates that there's no adapter,
- * however, some integrated adapters may have 0xffff as
- * their id and still be valid. Examples are on-board
- * VGA of the 55sx, the integrated SCSI of the 56 & 57,
- * and possibly also the 95 ULTIMEDIA.
- */
-
- mca_dev->status = MCA_ADAPTER_NORMAL;
- }
-
- if ((mca_dev->pos_id == 0xffff ||
- mca_dev->pos_id == 0x0000) && mca_dev->slot >= MCA_MAX_SLOT_NR) {
- int j;
-
- for (j = 2; j < 8; j++) {
- if (mca_dev->pos[j] != 0xff) {
- mca_dev->status = MCA_ADAPTER_NORMAL;
- break;
- }
- }
- }
-
- if (!(mca_dev->pos[2] & MCA_ENABLED)) {
-
- /* enabled bit is in POS 2 */
-
- mca_dev->status = MCA_ADAPTER_DISABLED;
- }
-} /* mca_configure_adapter_status */
-
-/*--------------------------------------------------------------------*/
-
-static struct resource mca_standard_resources[] = {
- { .start = 0x60, .end = 0x60, .name = "system control port B (MCA)" },
- { .start = 0x90, .end = 0x90, .name = "arbitration (MCA)" },
- { .start = 0x91, .end = 0x91, .name = "card Select Feedback (MCA)" },
- { .start = 0x92, .end = 0x92, .name = "system Control port A (MCA)" },
- { .start = 0x94, .end = 0x94, .name = "system board setup (MCA)" },
- { .start = 0x96, .end = 0x97, .name = "POS (MCA)" },
- { .start = 0x100, .end = 0x107, .name = "POS (MCA)" }
-};
-
-#define MCA_STANDARD_RESOURCES ARRAY_SIZE(mca_standard_resources)
-
-/*
- * mca_read_and_store_pos - read the POS registers into a memory buffer
- * @pos: a char pointer to 8 bytes, contains the POS register value on
- * successful return
- *
- * Returns 1 if a card actually exists (i.e. the pos isn't
- * all 0xff) or 0 otherwise
- */
-static int mca_read_and_store_pos(unsigned char *pos)
-{
- int j;
- int found = 0;
-
- for (j = 0; j < 8; j++) {
- pos[j] = inb_p(MCA_POS_REG(j));
- if (pos[j] != 0xff) {
- /* 0xff all across means no device. 0x00 means
- * something's broken, but a device is
- * probably there. However, if you get 0x00
- * from a motherboard register it won't matter
- * what we find. For the record, on the
- * 57SLC, the integrated SCSI adapter has
- * 0xffff for the adapter ID, but nonzero for
- * other registers. */
-
- found = 1;
- }
- }
- return found;
-}
-
-static unsigned char mca_pc_read_pos(struct mca_device *mca_dev, int reg)
-{
- unsigned char byte;
- unsigned long flags;
-
- if (reg < 0 || reg >= 8)
- return 0;
-
- spin_lock_irqsave(&mca_lock, flags);
- if (mca_dev->pos_register) {
- /* Disable adapter setup, enable motherboard setup */
-
- outb_p(0, MCA_ADAPTER_SETUP_REG);
- outb_p(mca_dev->pos_register, MCA_MOTHERBOARD_SETUP_REG);
-
- byte = inb_p(MCA_POS_REG(reg));
- outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
- } else {
-
- /* Make sure motherboard setup is off */
-
- outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
-
- /* Read the appropriate register */
-
- outb_p(0x8|(mca_dev->slot & 0xf), MCA_ADAPTER_SETUP_REG);
- byte = inb_p(MCA_POS_REG(reg));
- outb_p(0, MCA_ADAPTER_SETUP_REG);
- }
- spin_unlock_irqrestore(&mca_lock, flags);
-
- mca_dev->pos[reg] = byte;
-
- return byte;
-}
-
-static void mca_pc_write_pos(struct mca_device *mca_dev, int reg,
- unsigned char byte)
-{
- unsigned long flags;
-
- if (reg < 0 || reg >= 8)
- return;
-
- spin_lock_irqsave(&mca_lock, flags);
-
- /* Make sure motherboard setup is off */
-
- outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
-
- /* Read in the appropriate register */
-
- outb_p(0x8|(mca_dev->slot&0xf), MCA_ADAPTER_SETUP_REG);
- outb_p(byte, MCA_POS_REG(reg));
- outb_p(0, MCA_ADAPTER_SETUP_REG);
-
- spin_unlock_irqrestore(&mca_lock, flags);
-
- /* Update the global register list, while we have the byte */
-
- mca_dev->pos[reg] = byte;
-
-}
-
-/* for the primary MCA bus, we have identity transforms */
-static int mca_dummy_transform_irq(struct mca_device *mca_dev, int irq)
-{
- return irq;
-}
-
-static int mca_dummy_transform_ioport(struct mca_device *mca_dev, int port)
-{
- return port;
-}
-
-static void *mca_dummy_transform_memory(struct mca_device *mca_dev, void *mem)
-{
- return mem;
-}
-
-
-static int __init mca_init(void)
-{
- unsigned int i, j;
- struct mca_device *mca_dev;
- unsigned char pos[8];
- short mca_builtin_scsi_ports[] = {0xf7, 0xfd, 0x00};
- struct mca_bus *bus;
-
- /*
- * WARNING: Be careful when making changes here. Putting an adapter
- * and the motherboard simultaneously into setup mode may result in
- * damage to chips (according to The Indispensable PC Hardware Book
- * by Hans-Peter Messmer). Also, we disable system interrupts (so
- * that we are not disturbed in the middle of this).
- */
-
- /* Make sure the MCA bus is present */
-
- if (mca_system_init()) {
- printk(KERN_ERR "MCA bus system initialisation failed\n");
- return -ENODEV;
- }
-
- if (!MCA_bus)
- return -ENODEV;
-
- printk(KERN_INFO "Micro Channel bus detected.\n");
-
- /* All MCA systems have at least a primary bus */
- bus = mca_attach_bus(MCA_PRIMARY_BUS);
- if (!bus)
- goto out_nomem;
- bus->default_dma_mask = 0xffffffffLL;
- bus->f.mca_write_pos = mca_pc_write_pos;
- bus->f.mca_read_pos = mca_pc_read_pos;
- bus->f.mca_transform_irq = mca_dummy_transform_irq;
- bus->f.mca_transform_ioport = mca_dummy_transform_ioport;
- bus->f.mca_transform_memory = mca_dummy_transform_memory;
-
- /* get the motherboard device */
- mca_dev = kzalloc(sizeof(struct mca_device), GFP_KERNEL);
- if (unlikely(!mca_dev))
- goto out_nomem;
-
- /*
- * We do not expect many MCA interrupts during initialization,
- * but let us be safe:
- */
- spin_lock_irq(&mca_lock);
-
- /* Make sure adapter setup is off */
-
- outb_p(0, MCA_ADAPTER_SETUP_REG);
-
- /* Read motherboard POS registers */
-
- mca_dev->pos_register = 0x7f;
- outb_p(mca_dev->pos_register, MCA_MOTHERBOARD_SETUP_REG);
- mca_dev->name[0] = 0;
- mca_read_and_store_pos(mca_dev->pos);
- mca_configure_adapter_status(mca_dev);
- /* fake POS and slot for a motherboard */
- mca_dev->pos_id = MCA_MOTHERBOARD_POS;
- mca_dev->slot = MCA_MOTHERBOARD;
- mca_register_device(MCA_PRIMARY_BUS, mca_dev);
-
- mca_dev = kzalloc(sizeof(struct mca_device), GFP_ATOMIC);
- if (unlikely(!mca_dev))
- goto out_unlock_nomem;
-
- /* Put motherboard into video setup mode, read integrated video
- * POS registers, and turn motherboard setup off.
- */
-
- mca_dev->pos_register = 0xdf;
- outb_p(mca_dev->pos_register, MCA_MOTHERBOARD_SETUP_REG);
- mca_dev->name[0] = 0;
- mca_read_and_store_pos(mca_dev->pos);
- mca_configure_adapter_status(mca_dev);
- /* fake POS and slot for the integrated video */
- mca_dev->pos_id = MCA_INTEGVIDEO_POS;
- mca_dev->slot = MCA_INTEGVIDEO;
- mca_register_device(MCA_PRIMARY_BUS, mca_dev);
-
- /*
- * Put motherboard into scsi setup mode, read integrated scsi
- * POS registers, and turn motherboard setup off.
- *
- * It seems there are two possible SCSI registers. Martin says that
- * for the 56,57, 0xf7 is the one, but fails on the 76.
- * Alfredo (apena@vnet.ibm.com) says
- * 0xfd works on his machine. We'll try both of them. I figure it's
- * a good bet that only one could be valid at a time. This could
- * screw up though if one is used for something else on the other
- * machine.
- */
-
- for (i = 0; (which_scsi = mca_builtin_scsi_ports[i]) != 0; i++) {
- outb_p(which_scsi, MCA_MOTHERBOARD_SETUP_REG);
- if (mca_read_and_store_pos(pos))
- break;
- }
- if (which_scsi) {
- /* found a scsi card */
- mca_dev = kzalloc(sizeof(struct mca_device), GFP_ATOMIC);
- if (unlikely(!mca_dev))
- goto out_unlock_nomem;
-
- for (j = 0; j < 8; j++)
- mca_dev->pos[j] = pos[j];
-
- mca_configure_adapter_status(mca_dev);
- /* fake POS and slot for integrated SCSI controller */
- mca_dev->pos_id = MCA_INTEGSCSI_POS;
- mca_dev->slot = MCA_INTEGSCSI;
- mca_dev->pos_register = which_scsi;
- mca_register_device(MCA_PRIMARY_BUS, mca_dev);
- }
-
- /* Turn off motherboard setup */
-
- outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
-
- /*
- * Now loop over MCA slots: put each adapter into setup mode, and
- * read its POS registers. Then put adapter setup off.
- */
-
- for (i = 0; i < MCA_MAX_SLOT_NR; i++) {
- outb_p(0x8|(i&0xf), MCA_ADAPTER_SETUP_REG);
- if (!mca_read_and_store_pos(pos))
- continue;
-
- mca_dev = kzalloc(sizeof(struct mca_device), GFP_ATOMIC);
- if (unlikely(!mca_dev))
- goto out_unlock_nomem;
-
- for (j = 0; j < 8; j++)
- mca_dev->pos[j] = pos[j];
-
- mca_dev->driver_loaded = 0;
- mca_dev->slot = i;
- mca_dev->pos_register = 0;
- mca_configure_adapter_status(mca_dev);
- mca_register_device(MCA_PRIMARY_BUS, mca_dev);
- }
- outb_p(0, MCA_ADAPTER_SETUP_REG);
-
- /* Enable interrupts and return memory start */
- spin_unlock_irq(&mca_lock);
-
- for (i = 0; i < MCA_STANDARD_RESOURCES; i++)
- request_resource(&ioport_resource, mca_standard_resources + i);
-
- mca_do_proc_init();
-
- return 0;
-
- out_unlock_nomem:
- spin_unlock_irq(&mca_lock);
- out_nomem:
- printk(KERN_EMERG "Failed memory allocation in MCA setup!\n");
- return -ENOMEM;
-}
-
-subsys_initcall(mca_init);
-
-/*--------------------------------------------------------------------*/
-
-static __kprobes void
-mca_handle_nmi_device(struct mca_device *mca_dev, int check_flag)
-{
- int slot = mca_dev->slot;
-
- if (slot == MCA_INTEGSCSI) {
- printk(KERN_CRIT "NMI: caused by MCA integrated SCSI adapter (%s)\n",
- mca_dev->name);
- } else if (slot == MCA_INTEGVIDEO) {
- printk(KERN_CRIT "NMI: caused by MCA integrated video adapter (%s)\n",
- mca_dev->name);
- } else if (slot == MCA_MOTHERBOARD) {
- printk(KERN_CRIT "NMI: caused by motherboard (%s)\n",
- mca_dev->name);
- }
-
- /* More info available in POS 6 and 7? */
-
- if (check_flag) {
- unsigned char pos6, pos7;
-
- pos6 = mca_device_read_pos(mca_dev, 6);
- pos7 = mca_device_read_pos(mca_dev, 7);
-
- printk(KERN_CRIT "NMI: POS 6 = 0x%x, POS 7 = 0x%x\n", pos6, pos7);
- }
-
-} /* mca_handle_nmi_slot */
-
-/*--------------------------------------------------------------------*/
-
-static int __kprobes mca_handle_nmi_callback(struct device *dev, void *data)
-{
- struct mca_device *mca_dev = to_mca_device(dev);
- unsigned char pos5;
-
- pos5 = mca_device_read_pos(mca_dev, 5);
-
- if (!(pos5 & 0x80)) {
- /*
- * Bit 7 of POS 5 is reset when this adapter has a hardware
- * error. Bit 7 it reset if there's error information
- * available in POS 6 and 7.
- */
- mca_handle_nmi_device(mca_dev, !(pos5 & 0x40));
- return 1;
- }
- return 0;
-}
-
-void __kprobes mca_handle_nmi(void)
-{
- /*
- * First try - scan the various adapters and see if a specific
- * adapter was responsible for the error.
- */
- bus_for_each_dev(&mca_bus_type, NULL, NULL, mca_handle_nmi_callback);
-}
diff --git a/arch/x86/kernel/microcode_core.c b/arch/x86/kernel/microcode_core.c
index c9bda6d6035c..fbdfc6917180 100644
--- a/arch/x86/kernel/microcode_core.c
+++ b/arch/x86/kernel/microcode_core.c
@@ -299,12 +299,11 @@ static ssize_t reload_store(struct device *dev,
{
unsigned long val;
int cpu = dev->id;
- int ret = 0;
- char *end;
+ ssize_t ret = 0;
- val = simple_strtoul(buf, &end, 0);
- if (end == buf)
- return -EINVAL;
+ ret = kstrtoul(buf, 0, &val);
+ if (ret)
+ return ret;
if (val == 1) {
get_online_cpus();
diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c
index ca470e4c92dc..b02d4dd6b8a3 100644
--- a/arch/x86/kernel/mpparse.c
+++ b/arch/x86/kernel/mpparse.c
@@ -97,7 +97,7 @@ static void __init MP_bus_info(struct mpc_bus *m)
set_bit(m->busid, mp_bus_not_pci);
if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA) - 1) == 0) {
-#if defined(CONFIG_EISA) || defined(CONFIG_MCA)
+#ifdef CONFIG_EISA
mp_bus_id_to_type[m->busid] = MP_BUS_ISA;
#endif
} else if (strncmp(str, BUSTYPE_PCI, sizeof(BUSTYPE_PCI) - 1) == 0) {
@@ -105,12 +105,10 @@ static void __init MP_bus_info(struct mpc_bus *m)
x86_init.mpparse.mpc_oem_pci_bus(m);
clear_bit(m->busid, mp_bus_not_pci);
-#if defined(CONFIG_EISA) || defined(CONFIG_MCA)
+#ifdef CONFIG_EISA
mp_bus_id_to_type[m->busid] = MP_BUS_PCI;
} else if (strncmp(str, BUSTYPE_EISA, sizeof(BUSTYPE_EISA) - 1) == 0) {
mp_bus_id_to_type[m->busid] = MP_BUS_EISA;
- } else if (strncmp(str, BUSTYPE_MCA, sizeof(BUSTYPE_MCA) - 1) == 0) {
- mp_bus_id_to_type[m->busid] = MP_BUS_MCA;
#endif
} else
printk(KERN_WARNING "Unknown bustype %s - ignoring\n", str);
@@ -368,9 +366,6 @@ static void __init construct_ioapic_table(int mpc_default_type)
case 3:
memcpy(bus.bustype, "EISA ", 6);
break;
- case 4:
- case 7:
- memcpy(bus.bustype, "MCA ", 6);
}
MP_bus_info(&bus);
if (mpc_default_type > 4) {
@@ -623,7 +618,7 @@ void __init default_find_smp_config(void)
return;
/*
* If it is an SMP machine we should know now, unless the
- * configuration is in an EISA/MCA bus machine with an
+ * configuration is in an EISA bus machine with an
* extended bios data area.
*
* there is a real-mode segmented pointer pointing to the
diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c
index 585be4bd71a5..90875279ef3d 100644
--- a/arch/x86/kernel/nmi.c
+++ b/arch/x86/kernel/nmi.c
@@ -19,8 +19,6 @@
#include <linux/slab.h>
#include <linux/export.h>
-#include <linux/mca.h>
-
#if defined(CONFIG_EDAC)
#include <linux/edac.h>
#endif
@@ -84,7 +82,7 @@ __setup("unknown_nmi_panic", setup_unknown_nmi_panic);
#define nmi_to_desc(type) (&nmi_desc[type])
-static int notrace __kprobes nmi_handle(unsigned int type, struct pt_regs *regs, bool b2b)
+static int __kprobes nmi_handle(unsigned int type, struct pt_regs *regs, bool b2b)
{
struct nmi_desc *desc = nmi_to_desc(type);
struct nmiaction *a;
@@ -166,7 +164,7 @@ void unregister_nmi_handler(unsigned int type, const char *name)
}
EXPORT_SYMBOL_GPL(unregister_nmi_handler);
-static notrace __kprobes void
+static __kprobes void
pci_serr_error(unsigned char reason, struct pt_regs *regs)
{
/* check to see if anyone registered against these types of errors */
@@ -197,7 +195,7 @@ pci_serr_error(unsigned char reason, struct pt_regs *regs)
outb(reason, NMI_REASON_PORT);
}
-static notrace __kprobes void
+static __kprobes void
io_check_error(unsigned char reason, struct pt_regs *regs)
{
unsigned long i;
@@ -209,7 +207,7 @@ io_check_error(unsigned char reason, struct pt_regs *regs)
pr_emerg(
"NMI: IOCK error (debug interrupt?) for reason %02x on CPU %d.\n",
reason, smp_processor_id());
- show_registers(regs);
+ show_regs(regs);
if (panic_on_io_nmi)
panic("NMI IOCK error: Not continuing");
@@ -228,7 +226,7 @@ io_check_error(unsigned char reason, struct pt_regs *regs)
outb(reason, NMI_REASON_PORT);
}
-static notrace __kprobes void
+static __kprobes void
unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
{
int handled;
@@ -247,16 +245,6 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
__this_cpu_add(nmi_stats.unknown, 1);
-#ifdef CONFIG_MCA
- /*
- * Might actually be able to figure out what the guilty party
- * is:
- */
- if (MCA_bus) {
- mca_handle_nmi();
- return;
- }
-#endif
pr_emerg("Uhhuh. NMI received for unknown reason %02x on CPU %d.\n",
reason, smp_processor_id());
@@ -270,7 +258,7 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
static DEFINE_PER_CPU(bool, swallow_nmi);
static DEFINE_PER_CPU(unsigned long, last_nmi_rip);
-static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
+static __kprobes void default_do_nmi(struct pt_regs *regs)
{
unsigned char reason = 0;
int handled;
diff --git a/arch/x86/kernel/nmi_selftest.c b/arch/x86/kernel/nmi_selftest.c
index 2c39dcd510fa..e31bf8d5c4d2 100644
--- a/arch/x86/kernel/nmi_selftest.c
+++ b/arch/x86/kernel/nmi_selftest.c
@@ -13,6 +13,7 @@
#include <linux/cpumask.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/percpu.h>
#include <asm/apic.h>
#include <asm/nmi.h>
@@ -117,15 +118,15 @@ static void __init dotest(void (*testcase_fn)(void), int expected)
unexpected_testcase_failures++;
if (nmi_fail == FAILURE)
- printk("FAILED |");
+ printk(KERN_CONT "FAILED |");
else if (nmi_fail == TIMEOUT)
- printk("TIMEOUT|");
+ printk(KERN_CONT "TIMEOUT|");
else
- printk("ERROR |");
+ printk(KERN_CONT "ERROR |");
dump_stack();
} else {
testcase_successes++;
- printk(" ok |");
+ printk(KERN_CONT " ok |");
}
testcase_total++;
@@ -150,10 +151,10 @@ void __init nmi_selftest(void)
print_testname("remote IPI");
dotest(remote_ipi, SUCCESS);
- printk("\n");
+ printk(KERN_CONT "\n");
print_testname("local IPI");
dotest(local_ipi, SUCCESS);
- printk("\n");
+ printk(KERN_CONT "\n");
cleanup_nmi_testsuite();
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index ab137605e694..9ce885996fd7 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -241,16 +241,16 @@ static DEFINE_PER_CPU(enum paravirt_lazy_mode, paravirt_lazy_mode) = PARAVIRT_LA
static inline void enter_lazy(enum paravirt_lazy_mode mode)
{
- BUG_ON(percpu_read(paravirt_lazy_mode) != PARAVIRT_LAZY_NONE);
+ BUG_ON(this_cpu_read(paravirt_lazy_mode) != PARAVIRT_LAZY_NONE);
- percpu_write(paravirt_lazy_mode, mode);
+ this_cpu_write(paravirt_lazy_mode, mode);
}
static void leave_lazy(enum paravirt_lazy_mode mode)
{
- BUG_ON(percpu_read(paravirt_lazy_mode) != mode);
+ BUG_ON(this_cpu_read(paravirt_lazy_mode) != mode);
- percpu_write(paravirt_lazy_mode, PARAVIRT_LAZY_NONE);
+ this_cpu_write(paravirt_lazy_mode, PARAVIRT_LAZY_NONE);
}
void paravirt_enter_lazy_mmu(void)
@@ -267,7 +267,7 @@ void paravirt_start_context_switch(struct task_struct *prev)
{
BUG_ON(preemptible());
- if (percpu_read(paravirt_lazy_mode) == PARAVIRT_LAZY_MMU) {
+ if (this_cpu_read(paravirt_lazy_mode) == PARAVIRT_LAZY_MMU) {
arch_leave_lazy_mmu_mode();
set_ti_thread_flag(task_thread_info(prev), TIF_LAZY_MMU_UPDATES);
}
@@ -289,7 +289,7 @@ enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
if (in_interrupt())
return PARAVIRT_LAZY_NONE;
- return percpu_read(paravirt_lazy_mode);
+ return this_cpu_read(paravirt_lazy_mode);
}
void arch_flush_lazy_mmu_mode(void)
diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c
index d0b2fb9ccbb1..b72838bae64a 100644
--- a/arch/x86/kernel/pci-calgary_64.c
+++ b/arch/x86/kernel/pci-calgary_64.c
@@ -1480,8 +1480,9 @@ cleanup:
static int __init calgary_parse_options(char *p)
{
unsigned int bridge;
+ unsigned long val;
size_t len;
- char* endp;
+ ssize_t ret;
while (*p) {
if (!strncmp(p, "64k", 3))
@@ -1512,10 +1513,11 @@ static int __init calgary_parse_options(char *p)
++p;
if (*p == '\0')
break;
- bridge = simple_strtoul(p, &endp, 0);
- if (p == endp)
+ ret = kstrtoul(p, 0, &val);
+ if (ret)
break;
+ bridge = val;
if (bridge < MAX_PHB_BUS_NUM) {
printk(KERN_INFO "Calgary: disabling "
"translation for PHB %#x\n", bridge);
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index e8173154800d..735279e54e59 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -56,10 +56,16 @@ EXPORT_SYMBOL_GPL(idle_notifier_unregister);
struct kmem_cache *task_xstate_cachep;
EXPORT_SYMBOL_GPL(task_xstate_cachep);
+/*
+ * this gets called so that we can store lazy state into memory and copy the
+ * current task into the new thread.
+ */
int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
{
int ret;
+ unlazy_fpu(src);
+
*dst = *src;
if (fpu_allocated(&src->thread.fpu)) {
memset(&dst->thread.fpu, 0, sizeof(dst->thread.fpu));
@@ -89,6 +95,16 @@ void arch_task_cache_init(void)
SLAB_PANIC | SLAB_NOTRACK, NULL);
}
+static inline void drop_fpu(struct task_struct *tsk)
+{
+ /*
+ * Forget coprocessor state..
+ */
+ tsk->fpu_counter = 0;
+ clear_fpu(tsk);
+ clear_used_math();
+}
+
/*
* Free current thread data structures etc..
*/
@@ -111,12 +127,8 @@ void exit_thread(void)
put_cpu();
kfree(bp);
}
-}
-void show_regs(struct pt_regs *regs)
-{
- show_registers(regs);
- show_trace(NULL, regs, (unsigned long *)kernel_stack_pointer(regs), 0);
+ drop_fpu(me);
}
void show_regs_common(void)
@@ -151,12 +163,7 @@ void flush_thread(void)
flush_ptrace_hw_breakpoint(tsk);
memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));
- /*
- * Forget coprocessor state..
- */
- tsk->fpu_counter = 0;
- clear_fpu(tsk);
- clear_used_math();
+ drop_fpu(tsk);
}
static void hard_disable_TSC(void)
@@ -385,7 +392,7 @@ static inline void play_dead(void)
#ifdef CONFIG_X86_64
void enter_idle(void)
{
- percpu_write(is_idle, 1);
+ this_cpu_write(is_idle, 1);
atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL);
}
@@ -582,9 +589,17 @@ int mwait_usable(const struct cpuinfo_x86 *c)
{
u32 eax, ebx, ecx, edx;
+ /* Use mwait if idle=mwait boot option is given */
if (boot_option_idle_override == IDLE_FORCE_MWAIT)
return 1;
+ /*
+ * Any idle= boot option other than idle=mwait means that we must not
+ * use mwait. Eg: idle=halt or idle=poll or idle=nomwait
+ */
+ if (boot_option_idle_override != IDLE_NO_OVERRIDE)
+ return 0;
+
if (c->cpuid_level < MWAIT_INFO)
return 0;
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index ae6847303e26..516fa186121b 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -126,15 +126,6 @@ void release_thread(struct task_struct *dead_task)
release_vm86_irqs(dead_task);
}
-/*
- * This gets called before we allocate a new thread and copy
- * the current task into it.
- */
-void prepare_to_copy(struct task_struct *tsk)
-{
- unlazy_fpu(tsk);
-}
-
int copy_thread(unsigned long clone_flags, unsigned long sp,
unsigned long unused,
struct task_struct *p, struct pt_regs *regs)
@@ -302,7 +293,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
switch_fpu_finish(next_p, fpu);
- percpu_write(current_task, next_p);
+ this_cpu_write(current_task, next_p);
return prev_p;
}
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 43d8b48b23e6..61cdf7fdf099 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -145,15 +145,6 @@ static inline u32 read_32bit_tls(struct task_struct *t, int tls)
return get_desc_base(&t->thread.tls_array[tls]);
}
-/*
- * This gets called before we allocate a new thread and copy
- * the current task into it.
- */
-void prepare_to_copy(struct task_struct *tsk)
-{
- unlazy_fpu(tsk);
-}
-
int copy_thread(unsigned long clone_flags, unsigned long sp,
unsigned long unused,
struct task_struct *p, struct pt_regs *regs)
@@ -237,7 +228,7 @@ start_thread_common(struct pt_regs *regs, unsigned long new_ip,
current->thread.usersp = new_sp;
regs->ip = new_ip;
regs->sp = new_sp;
- percpu_write(old_rsp, new_sp);
+ this_cpu_write(old_rsp, new_sp);
regs->cs = _cs;
regs->ss = _ss;
regs->flags = X86_EFLAGS_IF;
@@ -359,11 +350,11 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
/*
* Switch the PDA and FPU contexts.
*/
- prev->usersp = percpu_read(old_rsp);
- percpu_write(old_rsp, next->usersp);
- percpu_write(current_task, next_p);
+ prev->usersp = this_cpu_read(old_rsp);
+ this_cpu_write(old_rsp, next->usersp);
+ this_cpu_write(current_task, next_p);
- percpu_write(kernel_stack,
+ this_cpu_write(kernel_stack,
(unsigned long)task_stack_page(next_p) +
THREAD_SIZE - KERNEL_STACK_OFFSET);
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index d840e69a853c..77215c23fba1 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -39,7 +39,8 @@ static int reboot_mode;
enum reboot_type reboot_type = BOOT_ACPI;
int reboot_force;
-/* This variable is used privately to keep track of whether or not
+/*
+ * This variable is used privately to keep track of whether or not
* reboot_type is still set to its default value (i.e., reboot= hasn't
* been set on the command line). This is needed so that we can
* suppress DMI scanning for reboot quirks. Without it, it's
@@ -51,7 +52,8 @@ static int reboot_default = 1;
static int reboot_cpu = -1;
#endif
-/* This is set if we need to go through the 'emergency' path.
+/*
+ * This is set if we need to go through the 'emergency' path.
* When machine_emergency_restart() is called, we may be on
* an inconsistent state and won't be able to do a clean cleanup
*/
@@ -60,22 +62,24 @@ static int reboot_emergency;
/* This is set by the PCI code if either type 1 or type 2 PCI is detected */
bool port_cf9_safe = false;
-/* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci]
- warm Don't set the cold reboot flag
- cold Set the cold reboot flag
- bios Reboot by jumping through the BIOS (only for X86_32)
- smp Reboot by executing reset on BSP or other CPU (only for X86_32)
- triple Force a triple fault (init)
- kbd Use the keyboard controller. cold reset (default)
- acpi Use the RESET_REG in the FADT
- efi Use efi reset_system runtime service
- pci Use the so-called "PCI reset register", CF9
- force Avoid anything that could hang.
+/*
+ * reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci]
+ * warm Don't set the cold reboot flag
+ * cold Set the cold reboot flag
+ * bios Reboot by jumping through the BIOS (only for X86_32)
+ * smp Reboot by executing reset on BSP or other CPU (only for X86_32)
+ * triple Force a triple fault (init)
+ * kbd Use the keyboard controller. cold reset (default)
+ * acpi Use the RESET_REG in the FADT
+ * efi Use efi reset_system runtime service
+ * pci Use the so-called "PCI reset register", CF9
+ * force Avoid anything that could hang.
*/
static int __init reboot_setup(char *str)
{
for (;;) {
- /* Having anything passed on the command line via
+ /*
+ * Having anything passed on the command line via
* reboot= will cause us to disable DMI checking
* below.
*/
@@ -98,9 +102,11 @@ static int __init reboot_setup(char *str)
if (isdigit(*(str+2)))
reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
}
- /* we will leave sorting out the final value
- when we are ready to reboot, since we might not
- have detected BSP APIC ID or smp_num_cpu */
+ /*
+ * We will leave sorting out the final value
+ * when we are ready to reboot, since we might not
+ * have detected BSP APIC ID or smp_num_cpu
+ */
break;
#endif /* CONFIG_SMP */
@@ -150,6 +156,82 @@ static int __init set_bios_reboot(const struct dmi_system_id *d)
return 0;
}
+extern const unsigned char machine_real_restart_asm[];
+extern const u64 machine_real_restart_gdt[3];
+
+void machine_real_restart(unsigned int type)
+{
+ void *restart_va;
+ unsigned long restart_pa;
+ void (*restart_lowmem)(unsigned int);
+ u64 *lowmem_gdt;
+
+ local_irq_disable();
+
+ /*
+ * Write zero to CMOS register number 0x0f, which the BIOS POST
+ * routine will recognize as telling it to do a proper reboot. (Well
+ * that's what this book in front of me says -- it may only apply to
+ * the Phoenix BIOS though, it's not clear). At the same time,
+ * disable NMIs by setting the top bit in the CMOS address register,
+ * as we're about to do peculiar things to the CPU. I'm not sure if
+ * `outb_p' is needed instead of just `outb'. Use it to be on the
+ * safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.)
+ */
+ spin_lock(&rtc_lock);
+ CMOS_WRITE(0x00, 0x8f);
+ spin_unlock(&rtc_lock);
+
+ /*
+ * Switch back to the initial page table.
+ */
+ load_cr3(initial_page_table);
+
+ /*
+ * Write 0x1234 to absolute memory location 0x472. The BIOS reads
+ * this on booting to tell it to "Bypass memory test (also warm
+ * boot)". This seems like a fairly standard thing that gets set by
+ * REBOOT.COM programs, and the previous reset routine did this
+ * too. */
+ *((unsigned short *)0x472) = reboot_mode;
+
+ /* Patch the GDT in the low memory trampoline */
+ lowmem_gdt = TRAMPOLINE_SYM(machine_real_restart_gdt);
+
+ restart_va = TRAMPOLINE_SYM(machine_real_restart_asm);
+ restart_pa = virt_to_phys(restart_va);
+ restart_lowmem = (void (*)(unsigned int))restart_pa;
+
+ /* GDT[0]: GDT self-pointer */
+ lowmem_gdt[0] =
+ (u64)(sizeof(machine_real_restart_gdt) - 1) +
+ ((u64)virt_to_phys(lowmem_gdt) << 16);
+ /* GDT[1]: 64K real mode code segment */
+ lowmem_gdt[1] =
+ GDT_ENTRY(0x009b, restart_pa, 0xffff);
+
+ /* Jump to the identity-mapped low memory code */
+ restart_lowmem(type);
+}
+#ifdef CONFIG_APM_MODULE
+EXPORT_SYMBOL(machine_real_restart);
+#endif
+
+#endif /* CONFIG_X86_32 */
+
+/*
+ * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot
+ */
+static int __init set_pci_reboot(const struct dmi_system_id *d)
+{
+ if (reboot_type != BOOT_CF9) {
+ reboot_type = BOOT_CF9;
+ printk(KERN_INFO "%s series board detected. "
+ "Selecting PCI-method for reboots.\n", d->ident);
+ }
+ return 0;
+}
+
static int __init set_kbd_reboot(const struct dmi_system_id *d)
{
if (reboot_type != BOOT_KBD) {
@@ -159,7 +241,12 @@ static int __init set_kbd_reboot(const struct dmi_system_id *d)
return 0;
}
+/*
+ * This is a single dmi_table handling all reboot quirks. Note that
+ * REBOOT_BIOS is only available for 32bit
+ */
static struct dmi_system_id __initdata reboot_dmi_table[] = {
+#ifdef CONFIG_X86_32
{ /* Handle problems with rebooting on Dell E520's */
.callback = set_bios_reboot,
.ident = "Dell E520",
@@ -184,7 +271,7 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
},
},
- { /* Handle problems with rebooting on Dell Optiplex 745's SFF*/
+ { /* Handle problems with rebooting on Dell Optiplex 745's SFF */
.callback = set_bios_reboot,
.ident = "Dell OptiPlex 745",
.matches = {
@@ -192,7 +279,7 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
},
},
- { /* Handle problems with rebooting on Dell Optiplex 745's DFF*/
+ { /* Handle problems with rebooting on Dell Optiplex 745's DFF */
.callback = set_bios_reboot,
.ident = "Dell OptiPlex 745",
.matches = {
@@ -201,7 +288,7 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "0MM599"),
},
},
- { /* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */
+ { /* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */
.callback = set_bios_reboot,
.ident = "Dell OptiPlex 745",
.matches = {
@@ -210,7 +297,7 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "0KW626"),
},
},
- { /* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */
+ { /* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */
.callback = set_bios_reboot,
.ident = "Dell OptiPlex 330",
.matches = {
@@ -219,7 +306,7 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "0KP561"),
},
},
- { /* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */
+ { /* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */
.callback = set_bios_reboot,
.ident = "Dell OptiPlex 360",
.matches = {
@@ -228,7 +315,7 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "0T656F"),
},
},
- { /* Handle problems with rebooting on Dell OptiPlex 760 with 0G919G*/
+ { /* Handle problems with rebooting on Dell OptiPlex 760 with 0G919G */
.callback = set_bios_reboot,
.ident = "Dell OptiPlex 760",
.matches = {
@@ -301,7 +388,7 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "SBC-FITPC2"),
},
},
- { /* Handle problems with rebooting on ASUS P4S800 */
+ { /* Handle problems with rebooting on ASUS P4S800 */
.callback = set_bios_reboot,
.ident = "ASUS P4S800",
.matches = {
@@ -309,7 +396,9 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
DMI_MATCH(DMI_BOARD_NAME, "P4S800"),
},
},
- { /* Handle reboot issue on Acer Aspire one */
+#endif /* CONFIG_X86_32 */
+
+ { /* Handle reboot issue on Acer Aspire one */
.callback = set_kbd_reboot,
.ident = "Acer Aspire One A110",
.matches = {
@@ -317,96 +406,6 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"),
},
},
- { }
-};
-
-static int __init reboot_init(void)
-{
- /* Only do the DMI check if reboot_type hasn't been overridden
- * on the command line
- */
- if (reboot_default) {
- dmi_check_system(reboot_dmi_table);
- }
- return 0;
-}
-core_initcall(reboot_init);
-
-extern const unsigned char machine_real_restart_asm[];
-extern const u64 machine_real_restart_gdt[3];
-
-void machine_real_restart(unsigned int type)
-{
- void *restart_va;
- unsigned long restart_pa;
- void (*restart_lowmem)(unsigned int);
- u64 *lowmem_gdt;
-
- local_irq_disable();
-
- /* Write zero to CMOS register number 0x0f, which the BIOS POST
- routine will recognize as telling it to do a proper reboot. (Well
- that's what this book in front of me says -- it may only apply to
- the Phoenix BIOS though, it's not clear). At the same time,
- disable NMIs by setting the top bit in the CMOS address register,
- as we're about to do peculiar things to the CPU. I'm not sure if
- `outb_p' is needed instead of just `outb'. Use it to be on the
- safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.)
- */
- spin_lock(&rtc_lock);
- CMOS_WRITE(0x00, 0x8f);
- spin_unlock(&rtc_lock);
-
- /*
- * Switch back to the initial page table.
- */
- load_cr3(initial_page_table);
-
- /* Write 0x1234 to absolute memory location 0x472. The BIOS reads
- this on booting to tell it to "Bypass memory test (also warm
- boot)". This seems like a fairly standard thing that gets set by
- REBOOT.COM programs, and the previous reset routine did this
- too. */
- *((unsigned short *)0x472) = reboot_mode;
-
- /* Patch the GDT in the low memory trampoline */
- lowmem_gdt = TRAMPOLINE_SYM(machine_real_restart_gdt);
-
- restart_va = TRAMPOLINE_SYM(machine_real_restart_asm);
- restart_pa = virt_to_phys(restart_va);
- restart_lowmem = (void (*)(unsigned int))restart_pa;
-
- /* GDT[0]: GDT self-pointer */
- lowmem_gdt[0] =
- (u64)(sizeof(machine_real_restart_gdt) - 1) +
- ((u64)virt_to_phys(lowmem_gdt) << 16);
- /* GDT[1]: 64K real mode code segment */
- lowmem_gdt[1] =
- GDT_ENTRY(0x009b, restart_pa, 0xffff);
-
- /* Jump to the identity-mapped low memory code */
- restart_lowmem(type);
-}
-#ifdef CONFIG_APM_MODULE
-EXPORT_SYMBOL(machine_real_restart);
-#endif
-
-#endif /* CONFIG_X86_32 */
-
-/*
- * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot
- */
-static int __init set_pci_reboot(const struct dmi_system_id *d)
-{
- if (reboot_type != BOOT_CF9) {
- reboot_type = BOOT_CF9;
- printk(KERN_INFO "%s series board detected. "
- "Selecting PCI-method for reboots.\n", d->ident);
- }
- return 0;
-}
-
-static struct dmi_system_id __initdata pci_reboot_dmi_table[] = {
{ /* Handle problems with rebooting on Apple MacBook5 */
.callback = set_pci_reboot,
.ident = "Apple MacBook5",
@@ -474,17 +473,17 @@ static struct dmi_system_id __initdata pci_reboot_dmi_table[] = {
{ }
};
-static int __init pci_reboot_init(void)
+static int __init reboot_init(void)
{
- /* Only do the DMI check if reboot_type hasn't been overridden
+ /*
+ * Only do the DMI check if reboot_type hasn't been overridden
* on the command line
*/
- if (reboot_default) {
- dmi_check_system(pci_reboot_dmi_table);
- }
+ if (reboot_default)
+ dmi_check_system(reboot_dmi_table);
return 0;
}
-core_initcall(pci_reboot_init);
+core_initcall(reboot_init);
static inline void kb_wait(void)
{
@@ -502,14 +501,14 @@ static void vmxoff_nmi(int cpu, struct pt_regs *regs)
cpu_emergency_vmxoff();
}
-/* Use NMIs as IPIs to tell all CPUs to disable virtualization
- */
+/* Use NMIs as IPIs to tell all CPUs to disable virtualization */
static void emergency_vmx_disable_all(void)
{
/* Just make sure we won't change CPUs while doing this */
local_irq_disable();
- /* We need to disable VMX on all CPUs before rebooting, otherwise
+ /*
+ * We need to disable VMX on all CPUs before rebooting, otherwise
* we risk hanging up the machine, because the CPU ignore INIT
* signals when VMX is enabled.
*
@@ -528,8 +527,7 @@ static void emergency_vmx_disable_all(void)
* is still enabling VMX.
*/
if (cpu_has_vmx() && cpu_vmx_enabled()) {
- /* Disable VMX on this CPU.
- */
+ /* Disable VMX on this CPU. */
cpu_vmxoff();
/* Halt and disable VMX on the other CPUs */
@@ -574,12 +572,12 @@ static void native_machine_emergency_restart(void)
/* Could also try the reset bit in the Hammer NB */
switch (reboot_type) {
case BOOT_KBD:
- mach_reboot_fixups(); /* for board specific fixups */
+ mach_reboot_fixups(); /* For board specific fixups */
for (i = 0; i < 10; i++) {
kb_wait();
udelay(50);
- outb(0xfe, 0x64); /* pulse reset low */
+ outb(0xfe, 0x64); /* Pulse reset low */
udelay(50);
}
if (attempt == 0 && orig_reboot_type == BOOT_ACPI) {
@@ -621,7 +619,7 @@ static void native_machine_emergency_restart(void)
case BOOT_CF9:
port_cf9_safe = true;
- /* fall through */
+ /* Fall through */
case BOOT_CF9_COND:
if (port_cf9_safe) {
@@ -659,7 +657,8 @@ void native_machine_shutdown(void)
/* Make certain I only run on the appropriate processor */
set_cpus_allowed_ptr(current, cpumask_of(reboot_cpu_id));
- /* O.K Now that I'm on the appropriate processor,
+ /*
+ * O.K Now that I'm on the appropriate processor,
* stop all of the others.
*/
stop_other_cpus();
@@ -697,12 +696,11 @@ static void native_machine_restart(char *__unused)
static void native_machine_halt(void)
{
- /* stop other cpus and apics */
+ /* Stop other cpus and apics */
machine_shutdown();
tboot_shutdown(TB_SHUTDOWN_HALT);
- /* stop this cpu */
stop_this_cpu(NULL);
}
@@ -713,7 +711,7 @@ static void native_machine_power_off(void)
machine_shutdown();
pm_power_off();
}
- /* a fallback in case there is no PM info available */
+ /* A fallback in case there is no PM info available */
tboot_shutdown(TB_SHUTDOWN_HALT);
}
@@ -775,7 +773,8 @@ static int crash_nmi_callback(unsigned int val, struct pt_regs *regs)
cpu = raw_smp_processor_id();
- /* Don't do anything if this handler is invoked on crashing cpu.
+ /*
+ * Don't do anything if this handler is invoked on crashing cpu.
* Otherwise, system will completely hang. Crashing cpu can get
* an NMI if system was initially booted with nmi_watchdog parameter.
*/
@@ -799,7 +798,8 @@ static void smp_send_nmi_allbutself(void)
apic->send_IPI_allbutself(NMI_VECTOR);
}
-/* Halt all other CPUs, calling the specified function on each of them
+/*
+ * Halt all other CPUs, calling the specified function on each of them
*
* This function can be used to halt all other CPUs on crash
* or emergency reboot time. The function passed as parameter
@@ -810,7 +810,7 @@ void nmi_shootdown_cpus(nmi_shootdown_cb callback)
unsigned long msecs;
local_irq_disable();
- /* Make a note of crashing cpu. Will be used in NMI callback.*/
+ /* Make a note of crashing cpu. Will be used in NMI callback. */
crashing_cpu = safe_smp_processor_id();
shootdown_callback = callback;
@@ -819,8 +819,9 @@ void nmi_shootdown_cpus(nmi_shootdown_cb callback)
/* Would it be better to replace the trap vector here? */
if (register_nmi_handler(NMI_LOCAL, crash_nmi_callback,
NMI_FLAG_FIRST, "crash"))
- return; /* return what? */
- /* Ensure the new callback function is set before sending
+ return; /* Return what? */
+ /*
+ * Ensure the new callback function is set before sending
* out the NMI
*/
wmb();
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 1a2901562059..366c688d619e 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -34,7 +34,6 @@
#include <linux/memblock.h>
#include <linux/seq_file.h>
#include <linux/console.h>
-#include <linux/mca.h>
#include <linux/root_dev.h>
#include <linux/highmem.h>
#include <linux/module.h>
@@ -179,12 +178,6 @@ struct cpuinfo_x86 new_cpu_data __cpuinitdata = {0, 0, 0, 0, -1, 1, 0, 0, -1};
/* common cpu data for all cpus */
struct cpuinfo_x86 boot_cpu_data __read_mostly = {0, 0, 0, 0, -1, 1, 0, 0, -1};
EXPORT_SYMBOL(boot_cpu_data);
-static void set_mca_bus(int x)
-{
-#ifdef CONFIG_MCA
- MCA_bus = x;
-#endif
-}
unsigned int def_to_bigsmp;
@@ -393,10 +386,9 @@ static void __init reserve_initrd(void)
initrd_start = 0;
if (ramdisk_size >= (end_of_lowmem>>1)) {
- memblock_free(ramdisk_image, ramdisk_end - ramdisk_image);
- printk(KERN_ERR "initrd too large to handle, "
- "disabling initrd\n");
- return;
+ panic("initrd too large to handle, "
+ "disabling initrd (%lld needed, %lld available)\n",
+ ramdisk_size, end_of_lowmem>>1);
}
printk(KERN_INFO "RAMDISK: %08llx - %08llx\n", ramdisk_image,
@@ -717,7 +709,6 @@ void __init setup_arch(char **cmdline_p)
apm_info.bios = boot_params.apm_bios_info;
ist_info = boot_params.ist_info;
if (boot_params.sys_desc_table.length != 0) {
- set_mca_bus(boot_params.sys_desc_table.table[3] & 0x2);
machine_id = boot_params.sys_desc_table.table[0];
machine_submodel_id = boot_params.sys_desc_table.table[1];
BIOS_revision = boot_params.sys_desc_table.table[2];
@@ -1012,7 +1003,8 @@ void __init setup_arch(char **cmdline_p)
init_cpu_to_node();
init_apic_mappings();
- ioapic_and_gsi_init();
+ if (x86_io_apic_ops.init)
+ x86_io_apic_ops.init();
kvm_guest_init();
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index 115eac431483..965dfda0fd5e 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -18,6 +18,7 @@
#include <linux/personality.h>
#include <linux/uaccess.h>
#include <linux/user-return-notifier.h>
+#include <linux/uprobes.h>
#include <asm/processor.h>
#include <asm/ucontext.h>
@@ -478,18 +479,8 @@ asmlinkage int
sys_sigsuspend(int history0, int history1, old_sigset_t mask)
{
sigset_t blocked;
-
- current->saved_sigmask = current->blocked;
-
- mask &= _BLOCKABLE;
siginitset(&blocked, mask);
- set_current_blocked(&blocked);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
-
- set_restore_sigmask();
- return -ERESTARTNOHAND;
+ return sigsuspend(&blocked);
}
asmlinkage int
@@ -824,6 +815,11 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
mce_notify_process();
#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */
+ if (thread_info_flags & _TIF_UPROBE) {
+ clear_thread_flag(TIF_UPROBE);
+ uprobe_notify_resume(regs);
+ }
+
/* deal with pending signal delivery */
if (thread_info_flags & _TIF_SIGPENDING)
do_signal(regs);
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c
index 66c74f481cab..48d2b7ded422 100644
--- a/arch/x86/kernel/smp.c
+++ b/arch/x86/kernel/smp.c
@@ -109,6 +109,9 @@
* about nothing of note with C stepping upwards.
*/
+static atomic_t stopping_cpu = ATOMIC_INIT(-1);
+static bool smp_no_nmi_ipi = false;
+
/*
* this function sends a 'reschedule' IPI to another CPU.
* it goes straight through and wastes no time serializing
@@ -149,8 +152,6 @@ void native_send_call_func_ipi(const struct cpumask *mask)
free_cpumask_var(allbutself);
}
-static atomic_t stopping_cpu = ATOMIC_INIT(-1);
-
static int smp_stop_nmi_callback(unsigned int val, struct pt_regs *regs)
{
/* We are registered on stopping cpu too, avoid spurious NMI */
@@ -162,7 +163,19 @@ static int smp_stop_nmi_callback(unsigned int val, struct pt_regs *regs)
return NMI_HANDLED;
}
-static void native_nmi_stop_other_cpus(int wait)
+/*
+ * this function calls the 'stop' function on all other CPUs in the system.
+ */
+
+asmlinkage void smp_reboot_interrupt(void)
+{
+ ack_APIC_irq();
+ irq_enter();
+ stop_this_cpu(NULL);
+ irq_exit();
+}
+
+static void native_stop_other_cpus(int wait)
{
unsigned long flags;
unsigned long timeout;
@@ -174,20 +187,25 @@ static void native_nmi_stop_other_cpus(int wait)
* Use an own vector here because smp_call_function
* does lots of things not suitable in a panic situation.
*/
+
+ /*
+ * We start by using the REBOOT_VECTOR irq.
+ * The irq is treated as a sync point to allow critical
+ * regions of code on other cpus to release their spin locks
+ * and re-enable irqs. Jumping straight to an NMI might
+ * accidentally cause deadlocks with further shutdown/panic
+ * code. By syncing, we give the cpus up to one second to
+ * finish their work before we force them off with the NMI.
+ */
if (num_online_cpus() > 1) {
/* did someone beat us here? */
if (atomic_cmpxchg(&stopping_cpu, -1, safe_smp_processor_id()) != -1)
return;
- if (register_nmi_handler(NMI_LOCAL, smp_stop_nmi_callback,
- NMI_FLAG_FIRST, "smp_stop"))
- /* Note: we ignore failures here */
- return;
-
- /* sync above data before sending NMI */
+ /* sync above data before sending IRQ */
wmb();
- apic->send_IPI_allbutself(NMI_VECTOR);
+ apic->send_IPI_allbutself(REBOOT_VECTOR);
/*
* Don't wait longer than a second if the caller
@@ -197,63 +215,37 @@ static void native_nmi_stop_other_cpus(int wait)
while (num_online_cpus() > 1 && (wait || timeout--))
udelay(1);
}
+
+ /* if the REBOOT_VECTOR didn't work, try with the NMI */
+ if ((num_online_cpus() > 1) && (!smp_no_nmi_ipi)) {
+ if (register_nmi_handler(NMI_LOCAL, smp_stop_nmi_callback,
+ NMI_FLAG_FIRST, "smp_stop"))
+ /* Note: we ignore failures here */
+ /* Hope the REBOOT_IRQ is good enough */
+ goto finish;
- local_irq_save(flags);
- disable_local_APIC();
- local_irq_restore(flags);
-}
-
-/*
- * this function calls the 'stop' function on all other CPUs in the system.
- */
-
-asmlinkage void smp_reboot_interrupt(void)
-{
- ack_APIC_irq();
- irq_enter();
- stop_this_cpu(NULL);
- irq_exit();
-}
-
-static void native_irq_stop_other_cpus(int wait)
-{
- unsigned long flags;
- unsigned long timeout;
+ /* sync above data before sending IRQ */
+ wmb();
- if (reboot_force)
- return;
+ pr_emerg("Shutting down cpus with NMI\n");
- /*
- * Use an own vector here because smp_call_function
- * does lots of things not suitable in a panic situation.
- * On most systems we could also use an NMI here,
- * but there are a few systems around where NMI
- * is problematic so stay with an non NMI for now
- * (this implies we cannot stop CPUs spinning with irq off
- * currently)
- */
- if (num_online_cpus() > 1) {
- apic->send_IPI_allbutself(REBOOT_VECTOR);
+ apic->send_IPI_allbutself(NMI_VECTOR);
/*
- * Don't wait longer than a second if the caller
+ * Don't wait longer than a 10 ms if the caller
* didn't ask us to wait.
*/
- timeout = USEC_PER_SEC;
+ timeout = USEC_PER_MSEC * 10;
while (num_online_cpus() > 1 && (wait || timeout--))
udelay(1);
}
+finish:
local_irq_save(flags);
disable_local_APIC();
local_irq_restore(flags);
}
-static void native_smp_disable_nmi_ipi(void)
-{
- smp_ops.stop_other_cpus = native_irq_stop_other_cpus;
-}
-
/*
* Reschedule call back.
*/
@@ -287,8 +279,8 @@ void smp_call_function_single_interrupt(struct pt_regs *regs)
static int __init nonmi_ipi_setup(char *str)
{
- native_smp_disable_nmi_ipi();
- return 1;
+ smp_no_nmi_ipi = true;
+ return 1;
}
__setup("nonmi_ipi", nonmi_ipi_setup);
@@ -298,7 +290,7 @@ struct smp_ops smp_ops = {
.smp_prepare_cpus = native_smp_prepare_cpus,
.smp_cpus_done = native_smp_cpus_done,
- .stop_other_cpus = native_nmi_stop_other_cpus,
+ .stop_other_cpus = native_stop_other_cpus,
.smp_send_reschedule = native_smp_send_reschedule,
.cpu_up = native_cpu_up,
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 3acaf51dfddb..433529e29be4 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -299,59 +299,90 @@ void __cpuinit smp_store_cpu_info(int id)
identify_secondary_cpu(c);
}
-static void __cpuinit link_thread_siblings(int cpu1, int cpu2)
+static bool __cpuinit
+topology_sane(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o, const char *name)
{
- cpumask_set_cpu(cpu1, cpu_sibling_mask(cpu2));
- cpumask_set_cpu(cpu2, cpu_sibling_mask(cpu1));
- cpumask_set_cpu(cpu1, cpu_core_mask(cpu2));
- cpumask_set_cpu(cpu2, cpu_core_mask(cpu1));
- cpumask_set_cpu(cpu1, cpu_llc_shared_mask(cpu2));
- cpumask_set_cpu(cpu2, cpu_llc_shared_mask(cpu1));
+ int cpu1 = c->cpu_index, cpu2 = o->cpu_index;
+
+ return !WARN_ONCE(cpu_to_node(cpu1) != cpu_to_node(cpu2),
+ "sched: CPU #%d's %s-sibling CPU #%d is not on the same node! "
+ "[node: %d != %d]. Ignoring dependency.\n",
+ cpu1, name, cpu2, cpu_to_node(cpu1), cpu_to_node(cpu2));
}
+#define link_mask(_m, c1, c2) \
+do { \
+ cpumask_set_cpu((c1), cpu_##_m##_mask(c2)); \
+ cpumask_set_cpu((c2), cpu_##_m##_mask(c1)); \
+} while (0)
+
+static bool __cpuinit match_smt(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
+{
+ if (cpu_has(c, X86_FEATURE_TOPOEXT)) {
+ int cpu1 = c->cpu_index, cpu2 = o->cpu_index;
+
+ if (c->phys_proc_id == o->phys_proc_id &&
+ per_cpu(cpu_llc_id, cpu1) == per_cpu(cpu_llc_id, cpu2) &&
+ c->compute_unit_id == o->compute_unit_id)
+ return topology_sane(c, o, "smt");
+
+ } else if (c->phys_proc_id == o->phys_proc_id &&
+ c->cpu_core_id == o->cpu_core_id) {
+ return topology_sane(c, o, "smt");
+ }
+
+ return false;
+}
+
+static bool __cpuinit match_llc(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
+{
+ int cpu1 = c->cpu_index, cpu2 = o->cpu_index;
+
+ if (per_cpu(cpu_llc_id, cpu1) != BAD_APICID &&
+ per_cpu(cpu_llc_id, cpu1) == per_cpu(cpu_llc_id, cpu2))
+ return topology_sane(c, o, "llc");
+
+ return false;
+}
+
+static bool __cpuinit match_mc(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
+{
+ if (c->phys_proc_id == o->phys_proc_id)
+ return topology_sane(c, o, "mc");
+
+ return false;
+}
void __cpuinit set_cpu_sibling_map(int cpu)
{
- int i;
+ bool has_mc = boot_cpu_data.x86_max_cores > 1;
+ bool has_smt = smp_num_siblings > 1;
struct cpuinfo_x86 *c = &cpu_data(cpu);
+ struct cpuinfo_x86 *o;
+ int i;
cpumask_set_cpu(cpu, cpu_sibling_setup_mask);
- if (smp_num_siblings > 1) {
- for_each_cpu(i, cpu_sibling_setup_mask) {
- struct cpuinfo_x86 *o = &cpu_data(i);
-
- if (cpu_has(c, X86_FEATURE_TOPOEXT)) {
- if (c->phys_proc_id == o->phys_proc_id &&
- per_cpu(cpu_llc_id, cpu) == per_cpu(cpu_llc_id, i) &&
- c->compute_unit_id == o->compute_unit_id)
- link_thread_siblings(cpu, i);
- } else if (c->phys_proc_id == o->phys_proc_id &&
- c->cpu_core_id == o->cpu_core_id) {
- link_thread_siblings(cpu, i);
- }
- }
- } else {
+ if (!has_smt && !has_mc) {
cpumask_set_cpu(cpu, cpu_sibling_mask(cpu));
- }
-
- cpumask_set_cpu(cpu, cpu_llc_shared_mask(cpu));
-
- if (__this_cpu_read(cpu_info.x86_max_cores) == 1) {
- cpumask_copy(cpu_core_mask(cpu), cpu_sibling_mask(cpu));
+ cpumask_set_cpu(cpu, cpu_llc_shared_mask(cpu));
+ cpumask_set_cpu(cpu, cpu_core_mask(cpu));
c->booted_cores = 1;
return;
}
for_each_cpu(i, cpu_sibling_setup_mask) {
- if (per_cpu(cpu_llc_id, cpu) != BAD_APICID &&
- per_cpu(cpu_llc_id, cpu) == per_cpu(cpu_llc_id, i)) {
- cpumask_set_cpu(i, cpu_llc_shared_mask(cpu));
- cpumask_set_cpu(cpu, cpu_llc_shared_mask(i));
- }
- if (c->phys_proc_id == cpu_data(i).phys_proc_id) {
- cpumask_set_cpu(i, cpu_core_mask(cpu));
- cpumask_set_cpu(cpu, cpu_core_mask(i));
+ o = &cpu_data(i);
+
+ if ((i == cpu) || (has_smt && match_smt(c, o)))
+ link_mask(sibling, cpu, i);
+
+ if ((i == cpu) || (has_mc && match_llc(c, o)))
+ link_mask(llc_shared, cpu, i);
+
+ if ((i == cpu) || (has_mc && match_mc(c, o))) {
+ link_mask(core, cpu, i);
+
/*
* Does this new cpu bringup a new core?
*/
@@ -382,8 +413,7 @@ const struct cpumask *cpu_coregroup_mask(int cpu)
* For perf, we return last level cache shared map.
* And for power savings, we return cpu_core_map
*/
- if ((sched_mc_power_savings || sched_smt_power_savings) &&
- !(cpu_has(c, X86_FEATURE_AMD_DCM)))
+ if (!(cpu_has(c, X86_FEATURE_AMD_DCM)))
return cpu_core_mask(cpu);
else
return cpu_llc_shared_mask(cpu);
diff --git a/arch/x86/kernel/test_rodata.c b/arch/x86/kernel/test_rodata.c
index c29e235792af..b79133abda48 100644
--- a/arch/x86/kernel/test_rodata.c
+++ b/arch/x86/kernel/test_rodata.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <asm/cacheflush.h>
#include <asm/sections.h>
+#include <asm/asm.h>
int rodata_test(void)
{
@@ -42,14 +43,7 @@ int rodata_test(void)
".section .fixup,\"ax\"\n"
"2: jmp 1b\n"
".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 16\n"
-#ifdef CONFIG_X86_32
- " .long 0b,2b\n"
-#else
- " .quad 0b,2b\n"
-#endif
- ".previous"
+ _ASM_EXTABLE(0b,2b)
: [rslt] "=r" (result)
: [rodata_test] "r" (&rodata_test_data), [zero] "r" (0UL)
);
diff --git a/arch/x86/kernel/time.c b/arch/x86/kernel/time.c
index c6eba2b42673..24d3c91e9812 100644
--- a/arch/x86/kernel/time.c
+++ b/arch/x86/kernel/time.c
@@ -14,7 +14,6 @@
#include <linux/i8253.h>
#include <linux/time.h>
#include <linux/export.h>
-#include <linux/mca.h>
#include <asm/vsyscall.h>
#include <asm/x86_init.h>
@@ -58,11 +57,6 @@ EXPORT_SYMBOL(profile_pc);
static irqreturn_t timer_interrupt(int irq, void *dev_id)
{
global_clock_event->event_handler(global_clock_event);
-
- /* MCA bus quirk: Acknowledge irq0 by setting bit 7 in port 0x61 */
- if (MCA_bus)
- outb_p(inb_p(0x61)| 0x80, 0x61);
-
return IRQ_HANDLED;
}
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index ff9281f16029..ff08457a025d 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -37,10 +37,6 @@
#include <linux/eisa.h>
#endif
-#ifdef CONFIG_MCA
-#include <linux/mca.h>
-#endif
-
#if defined(CONFIG_EDAC)
#include <linux/edac.h>
#endif
@@ -50,6 +46,7 @@
#include <asm/processor.h>
#include <asm/debugreg.h>
#include <linux/atomic.h>
+#include <asm/ftrace.h>
#include <asm/traps.h>
#include <asm/desc.h>
#include <asm/i387.h>
@@ -303,8 +300,13 @@ gp_in_kernel:
}
/* May run on IST stack. */
-dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code)
+dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_code)
{
+#ifdef CONFIG_DYNAMIC_FTRACE
+ /* ftrace must be first, everything else may cause a recursive crash */
+ if (unlikely(modifying_ftrace_code) && ftrace_int3_handler(regs))
+ return;
+#endif
#ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
SIGTRAP) == NOTIFY_STOP)
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
new file mode 100644
index 000000000000..dc4e910a7d96
--- /dev/null
+++ b/arch/x86/kernel/uprobes.c
@@ -0,0 +1,674 @@
+/*
+ * User-space Probes (UProbes) for x86
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2008-2011
+ * Authors:
+ * Srikar Dronamraju
+ * Jim Keniston
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/uprobes.h>
+#include <linux/uaccess.h>
+
+#include <linux/kdebug.h>
+#include <asm/processor.h>
+#include <asm/insn.h>
+
+/* Post-execution fixups. */
+
+/* No fixup needed */
+#define UPROBE_FIX_NONE 0x0
+
+/* Adjust IP back to vicinity of actual insn */
+#define UPROBE_FIX_IP 0x1
+
+/* Adjust the return address of a call insn */
+#define UPROBE_FIX_CALL 0x2
+
+#define UPROBE_FIX_RIP_AX 0x8000
+#define UPROBE_FIX_RIP_CX 0x4000
+
+#define UPROBE_TRAP_NR UINT_MAX
+
+/* Adaptations for mhiramat x86 decoder v14. */
+#define OPCODE1(insn) ((insn)->opcode.bytes[0])
+#define OPCODE2(insn) ((insn)->opcode.bytes[1])
+#define OPCODE3(insn) ((insn)->opcode.bytes[2])
+#define MODRM_REG(insn) X86_MODRM_REG(insn->modrm.value)
+
+#define W(row, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, ba, bb, bc, bd, be, bf)\
+ (((b0##UL << 0x0)|(b1##UL << 0x1)|(b2##UL << 0x2)|(b3##UL << 0x3) | \
+ (b4##UL << 0x4)|(b5##UL << 0x5)|(b6##UL << 0x6)|(b7##UL << 0x7) | \
+ (b8##UL << 0x8)|(b9##UL << 0x9)|(ba##UL << 0xa)|(bb##UL << 0xb) | \
+ (bc##UL << 0xc)|(bd##UL << 0xd)|(be##UL << 0xe)|(bf##UL << 0xf)) \
+ << (row % 32))
+
+/*
+ * Good-instruction tables for 32-bit apps. This is non-const and volatile
+ * to keep gcc from statically optimizing it out, as variable_test_bit makes
+ * some versions of gcc to think only *(unsigned long*) is used.
+ */
+static volatile u32 good_insns_32[256 / 32] = {
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
+ /* ---------------------------------------------- */
+ W(0x00, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0) | /* 00 */
+ W(0x10, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0) , /* 10 */
+ W(0x20, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1) | /* 20 */
+ W(0x30, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1) , /* 30 */
+ W(0x40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 40 */
+ W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 50 */
+ W(0x60, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* 60 */
+ W(0x70, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 70 */
+ W(0x80, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 80 */
+ W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 90 */
+ W(0xa0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* a0 */
+ W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* b0 */
+ W(0xc0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0) | /* c0 */
+ W(0xd0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* d0 */
+ W(0xe0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* e0 */
+ W(0xf0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1) /* f0 */
+ /* ---------------------------------------------- */
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
+};
+
+/* Using this for both 64-bit and 32-bit apps */
+static volatile u32 good_2byte_insns[256 / 32] = {
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
+ /* ---------------------------------------------- */
+ W(0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1) | /* 00 */
+ W(0x10, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1) , /* 10 */
+ W(0x20, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1) | /* 20 */
+ W(0x30, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) , /* 30 */
+ W(0x40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 40 */
+ W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 50 */
+ W(0x60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 60 */
+ W(0x70, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1) , /* 70 */
+ W(0x80, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 80 */
+ W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 90 */
+ W(0xa0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1) | /* a0 */
+ W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1) , /* b0 */
+ W(0xc0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* c0 */
+ W(0xd0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* d0 */
+ W(0xe0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* e0 */
+ W(0xf0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) /* f0 */
+ /* ---------------------------------------------- */
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
+};
+
+#ifdef CONFIG_X86_64
+/* Good-instruction tables for 64-bit apps */
+static volatile u32 good_insns_64[256 / 32] = {
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
+ /* ---------------------------------------------- */
+ W(0x00, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) | /* 00 */
+ W(0x10, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) , /* 10 */
+ W(0x20, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) | /* 20 */
+ W(0x30, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0) , /* 30 */
+ W(0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | /* 40 */
+ W(0x50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 50 */
+ W(0x60, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* 60 */
+ W(0x70, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 70 */
+ W(0x80, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* 80 */
+ W(0x90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* 90 */
+ W(0xa0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) | /* a0 */
+ W(0xb0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* b0 */
+ W(0xc0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0) | /* c0 */
+ W(0xd0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1) , /* d0 */
+ W(0xe0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0) | /* e0 */
+ W(0xf0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1) /* f0 */
+ /* ---------------------------------------------- */
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
+};
+#endif
+#undef W
+
+/*
+ * opcodes we'll probably never support:
+ *
+ * 6c-6d, e4-e5, ec-ed - in
+ * 6e-6f, e6-e7, ee-ef - out
+ * cc, cd - int3, int
+ * cf - iret
+ * d6 - illegal instruction
+ * f1 - int1/icebp
+ * f4 - hlt
+ * fa, fb - cli, sti
+ * 0f - lar, lsl, syscall, clts, sysret, sysenter, sysexit, invd, wbinvd, ud2
+ *
+ * invalid opcodes in 64-bit mode:
+ *
+ * 06, 0e, 16, 1e, 27, 2f, 37, 3f, 60-62, 82, c4-c5, d4-d5
+ * 63 - we support this opcode in x86_64 but not in i386.
+ *
+ * opcodes we may need to refine support for:
+ *
+ * 0f - 2-byte instructions: For many of these instructions, the validity
+ * depends on the prefix and/or the reg field. On such instructions, we
+ * just consider the opcode combination valid if it corresponds to any
+ * valid instruction.
+ *
+ * 8f - Group 1 - only reg = 0 is OK
+ * c6-c7 - Group 11 - only reg = 0 is OK
+ * d9-df - fpu insns with some illegal encodings
+ * f2, f3 - repnz, repz prefixes. These are also the first byte for
+ * certain floating-point instructions, such as addsd.
+ *
+ * fe - Group 4 - only reg = 0 or 1 is OK
+ * ff - Group 5 - only reg = 0-6 is OK
+ *
+ * others -- Do we need to support these?
+ *
+ * 0f - (floating-point?) prefetch instructions
+ * 07, 17, 1f - pop es, pop ss, pop ds
+ * 26, 2e, 36, 3e - es:, cs:, ss:, ds: segment prefixes --
+ * but 64 and 65 (fs: and gs:) seem to be used, so we support them
+ * 67 - addr16 prefix
+ * ce - into
+ * f0 - lock prefix
+ */
+
+/*
+ * TODO:
+ * - Where necessary, examine the modrm byte and allow only valid instructions
+ * in the different Groups and fpu instructions.
+ */
+
+static bool is_prefix_bad(struct insn *insn)
+{
+ int i;
+
+ for (i = 0; i < insn->prefixes.nbytes; i++) {
+ switch (insn->prefixes.bytes[i]) {
+ case 0x26: /* INAT_PFX_ES */
+ case 0x2E: /* INAT_PFX_CS */
+ case 0x36: /* INAT_PFX_DS */
+ case 0x3E: /* INAT_PFX_SS */
+ case 0xF0: /* INAT_PFX_LOCK */
+ return true;
+ }
+ }
+ return false;
+}
+
+static int validate_insn_32bits(struct arch_uprobe *auprobe, struct insn *insn)
+{
+ insn_init(insn, auprobe->insn, false);
+
+ /* Skip good instruction prefixes; reject "bad" ones. */
+ insn_get_opcode(insn);
+ if (is_prefix_bad(insn))
+ return -ENOTSUPP;
+
+ if (test_bit(OPCODE1(insn), (unsigned long *)good_insns_32))
+ return 0;
+
+ if (insn->opcode.nbytes == 2) {
+ if (test_bit(OPCODE2(insn), (unsigned long *)good_2byte_insns))
+ return 0;
+ }
+
+ return -ENOTSUPP;
+}
+
+/*
+ * Figure out which fixups arch_uprobe_post_xol() will need to perform, and
+ * annotate arch_uprobe->fixups accordingly. To start with,
+ * arch_uprobe->fixups is either zero or it reflects rip-related fixups.
+ */
+static void prepare_fixups(struct arch_uprobe *auprobe, struct insn *insn)
+{
+ bool fix_ip = true, fix_call = false; /* defaults */
+ int reg;
+
+ insn_get_opcode(insn); /* should be a nop */
+
+ switch (OPCODE1(insn)) {
+ case 0xc3: /* ret/lret */
+ case 0xcb:
+ case 0xc2:
+ case 0xca:
+ /* ip is correct */
+ fix_ip = false;
+ break;
+ case 0xe8: /* call relative - Fix return addr */
+ fix_call = true;
+ break;
+ case 0x9a: /* call absolute - Fix return addr, not ip */
+ fix_call = true;
+ fix_ip = false;
+ break;
+ case 0xff:
+ insn_get_modrm(insn);
+ reg = MODRM_REG(insn);
+ if (reg == 2 || reg == 3) {
+ /* call or lcall, indirect */
+ /* Fix return addr; ip is correct. */
+ fix_call = true;
+ fix_ip = false;
+ } else if (reg == 4 || reg == 5) {
+ /* jmp or ljmp, indirect */
+ /* ip is correct. */
+ fix_ip = false;
+ }
+ break;
+ case 0xea: /* jmp absolute -- ip is correct */
+ fix_ip = false;
+ break;
+ default:
+ break;
+ }
+ if (fix_ip)
+ auprobe->fixups |= UPROBE_FIX_IP;
+ if (fix_call)
+ auprobe->fixups |= UPROBE_FIX_CALL;
+}
+
+#ifdef CONFIG_X86_64
+/*
+ * If arch_uprobe->insn doesn't use rip-relative addressing, return
+ * immediately. Otherwise, rewrite the instruction so that it accesses
+ * its memory operand indirectly through a scratch register. Set
+ * arch_uprobe->fixups and arch_uprobe->rip_rela_target_address
+ * accordingly. (The contents of the scratch register will be saved
+ * before we single-step the modified instruction, and restored
+ * afterward.)
+ *
+ * We do this because a rip-relative instruction can access only a
+ * relatively small area (+/- 2 GB from the instruction), and the XOL
+ * area typically lies beyond that area. At least for instructions
+ * that store to memory, we can't execute the original instruction
+ * and "fix things up" later, because the misdirected store could be
+ * disastrous.
+ *
+ * Some useful facts about rip-relative instructions:
+ *
+ * - There's always a modrm byte.
+ * - There's never a SIB byte.
+ * - The displacement is always 4 bytes.
+ */
+static void
+handle_riprel_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, struct insn *insn)
+{
+ u8 *cursor;
+ u8 reg;
+
+ if (mm->context.ia32_compat)
+ return;
+
+ auprobe->rip_rela_target_address = 0x0;
+ if (!insn_rip_relative(insn))
+ return;
+
+ /*
+ * insn_rip_relative() would have decoded rex_prefix, modrm.
+ * Clear REX.b bit (extension of MODRM.rm field):
+ * we want to encode rax/rcx, not r8/r9.
+ */
+ if (insn->rex_prefix.nbytes) {
+ cursor = auprobe->insn + insn_offset_rex_prefix(insn);
+ *cursor &= 0xfe; /* Clearing REX.B bit */
+ }
+
+ /*
+ * Point cursor at the modrm byte. The next 4 bytes are the
+ * displacement. Beyond the displacement, for some instructions,
+ * is the immediate operand.
+ */
+ cursor = auprobe->insn + insn_offset_modrm(insn);
+ insn_get_length(insn);
+
+ /*
+ * Convert from rip-relative addressing to indirect addressing
+ * via a scratch register. Change the r/m field from 0x5 (%rip)
+ * to 0x0 (%rax) or 0x1 (%rcx), and squeeze out the offset field.
+ */
+ reg = MODRM_REG(insn);
+ if (reg == 0) {
+ /*
+ * The register operand (if any) is either the A register
+ * (%rax, %eax, etc.) or (if the 0x4 bit is set in the
+ * REX prefix) %r8. In any case, we know the C register
+ * is NOT the register operand, so we use %rcx (register
+ * #1) for the scratch register.
+ */
+ auprobe->fixups = UPROBE_FIX_RIP_CX;
+ /* Change modrm from 00 000 101 to 00 000 001. */
+ *cursor = 0x1;
+ } else {
+ /* Use %rax (register #0) for the scratch register. */
+ auprobe->fixups = UPROBE_FIX_RIP_AX;
+ /* Change modrm from 00 xxx 101 to 00 xxx 000 */
+ *cursor = (reg << 3);
+ }
+
+ /* Target address = address of next instruction + (signed) offset */
+ auprobe->rip_rela_target_address = (long)insn->length + insn->displacement.value;
+
+ /* Displacement field is gone; slide immediate field (if any) over. */
+ if (insn->immediate.nbytes) {
+ cursor++;
+ memmove(cursor, cursor + insn->displacement.nbytes, insn->immediate.nbytes);
+ }
+ return;
+}
+
+static int validate_insn_64bits(struct arch_uprobe *auprobe, struct insn *insn)
+{
+ insn_init(insn, auprobe->insn, true);
+
+ /* Skip good instruction prefixes; reject "bad" ones. */
+ insn_get_opcode(insn);
+ if (is_prefix_bad(insn))
+ return -ENOTSUPP;
+
+ if (test_bit(OPCODE1(insn), (unsigned long *)good_insns_64))
+ return 0;
+
+ if (insn->opcode.nbytes == 2) {
+ if (test_bit(OPCODE2(insn), (unsigned long *)good_2byte_insns))
+ return 0;
+ }
+ return -ENOTSUPP;
+}
+
+static int validate_insn_bits(struct arch_uprobe *auprobe, struct mm_struct *mm, struct insn *insn)
+{
+ if (mm->context.ia32_compat)
+ return validate_insn_32bits(auprobe, insn);
+ return validate_insn_64bits(auprobe, insn);
+}
+#else /* 32-bit: */
+static void handle_riprel_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, struct insn *insn)
+{
+ /* No RIP-relative addressing on 32-bit */
+}
+
+static int validate_insn_bits(struct arch_uprobe *auprobe, struct mm_struct *mm, struct insn *insn)
+{
+ return validate_insn_32bits(auprobe, insn);
+}
+#endif /* CONFIG_X86_64 */
+
+/**
+ * arch_uprobe_analyze_insn - instruction analysis including validity and fixups.
+ * @mm: the probed address space.
+ * @arch_uprobe: the probepoint information.
+ * Return 0 on success or a -ve number on error.
+ */
+int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm)
+{
+ int ret;
+ struct insn insn;
+
+ auprobe->fixups = 0;
+ ret = validate_insn_bits(auprobe, mm, &insn);
+ if (ret != 0)
+ return ret;
+
+ handle_riprel_insn(auprobe, mm, &insn);
+ prepare_fixups(auprobe, &insn);
+
+ return 0;
+}
+
+#ifdef CONFIG_X86_64
+/*
+ * If we're emulating a rip-relative instruction, save the contents
+ * of the scratch register and store the target address in that register.
+ */
+static void
+pre_xol_rip_insn(struct arch_uprobe *auprobe, struct pt_regs *regs,
+ struct arch_uprobe_task *autask)
+{
+ if (auprobe->fixups & UPROBE_FIX_RIP_AX) {
+ autask->saved_scratch_register = regs->ax;
+ regs->ax = current->utask->vaddr;
+ regs->ax += auprobe->rip_rela_target_address;
+ } else if (auprobe->fixups & UPROBE_FIX_RIP_CX) {
+ autask->saved_scratch_register = regs->cx;
+ regs->cx = current->utask->vaddr;
+ regs->cx += auprobe->rip_rela_target_address;
+ }
+}
+#else
+static void
+pre_xol_rip_insn(struct arch_uprobe *auprobe, struct pt_regs *regs,
+ struct arch_uprobe_task *autask)
+{
+ /* No RIP-relative addressing on 32-bit */
+}
+#endif
+
+/*
+ * arch_uprobe_pre_xol - prepare to execute out of line.
+ * @auprobe: the probepoint information.
+ * @regs: reflects the saved user state of current task.
+ */
+int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+ struct arch_uprobe_task *autask;
+
+ autask = &current->utask->autask;
+ autask->saved_trap_nr = current->thread.trap_nr;
+ current->thread.trap_nr = UPROBE_TRAP_NR;
+ regs->ip = current->utask->xol_vaddr;
+ pre_xol_rip_insn(auprobe, regs, autask);
+
+ return 0;
+}
+
+/*
+ * This function is called by arch_uprobe_post_xol() to adjust the return
+ * address pushed by a call instruction executed out of line.
+ */
+static int adjust_ret_addr(unsigned long sp, long correction)
+{
+ int rasize, ncopied;
+ long ra = 0;
+
+ if (is_ia32_task())
+ rasize = 4;
+ else
+ rasize = 8;
+
+ ncopied = copy_from_user(&ra, (void __user *)sp, rasize);
+ if (unlikely(ncopied))
+ return -EFAULT;
+
+ ra += correction;
+ ncopied = copy_to_user((void __user *)sp, &ra, rasize);
+ if (unlikely(ncopied))
+ return -EFAULT;
+
+ return 0;
+}
+
+#ifdef CONFIG_X86_64
+static bool is_riprel_insn(struct arch_uprobe *auprobe)
+{
+ return ((auprobe->fixups & (UPROBE_FIX_RIP_AX | UPROBE_FIX_RIP_CX)) != 0);
+}
+
+static void
+handle_riprel_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs, long *correction)
+{
+ if (is_riprel_insn(auprobe)) {
+ struct arch_uprobe_task *autask;
+
+ autask = &current->utask->autask;
+ if (auprobe->fixups & UPROBE_FIX_RIP_AX)
+ regs->ax = autask->saved_scratch_register;
+ else
+ regs->cx = autask->saved_scratch_register;
+
+ /*
+ * The original instruction includes a displacement, and so
+ * is 4 bytes longer than what we've just single-stepped.
+ * Fall through to handle stuff like "jmpq *...(%rip)" and
+ * "callq *...(%rip)".
+ */
+ if (correction)
+ *correction += 4;
+ }
+}
+#else
+static void
+handle_riprel_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs, long *correction)
+{
+ /* No RIP-relative addressing on 32-bit */
+}
+#endif
+
+/*
+ * If xol insn itself traps and generates a signal(Say,
+ * SIGILL/SIGSEGV/etc), then detect the case where a singlestepped
+ * instruction jumps back to its own address. It is assumed that anything
+ * like do_page_fault/do_trap/etc sets thread.trap_nr != -1.
+ *
+ * arch_uprobe_pre_xol/arch_uprobe_post_xol save/restore thread.trap_nr,
+ * arch_uprobe_xol_was_trapped() simply checks that ->trap_nr is not equal to
+ * UPROBE_TRAP_NR == -1 set by arch_uprobe_pre_xol().
+ */
+bool arch_uprobe_xol_was_trapped(struct task_struct *t)
+{
+ if (t->thread.trap_nr != UPROBE_TRAP_NR)
+ return true;
+
+ return false;
+}
+
+/*
+ * Called after single-stepping. To avoid the SMP problems that can
+ * occur when we temporarily put back the original opcode to
+ * single-step, we single-stepped a copy of the instruction.
+ *
+ * This function prepares to resume execution after the single-step.
+ * We have to fix things up as follows:
+ *
+ * Typically, the new ip is relative to the copied instruction. We need
+ * to make it relative to the original instruction (FIX_IP). Exceptions
+ * are return instructions and absolute or indirect jump or call instructions.
+ *
+ * If the single-stepped instruction was a call, the return address that
+ * is atop the stack is the address following the copied instruction. We
+ * need to make it the address following the original instruction (FIX_CALL).
+ *
+ * If the original instruction was a rip-relative instruction such as
+ * "movl %edx,0xnnnn(%rip)", we have instead executed an equivalent
+ * instruction using a scratch register -- e.g., "movl %edx,(%rax)".
+ * We need to restore the contents of the scratch register and adjust
+ * the ip, keeping in mind that the instruction we executed is 4 bytes
+ * shorter than the original instruction (since we squeezed out the offset
+ * field). (FIX_RIP_AX or FIX_RIP_CX)
+ */
+int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+ struct uprobe_task *utask;
+ long correction;
+ int result = 0;
+
+ WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR);
+
+ utask = current->utask;
+ current->thread.trap_nr = utask->autask.saved_trap_nr;
+ correction = (long)(utask->vaddr - utask->xol_vaddr);
+ handle_riprel_post_xol(auprobe, regs, &correction);
+ if (auprobe->fixups & UPROBE_FIX_IP)
+ regs->ip += correction;
+
+ if (auprobe->fixups & UPROBE_FIX_CALL)
+ result = adjust_ret_addr(regs->sp, correction);
+
+ return result;
+}
+
+/* callback routine for handling exceptions. */
+int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data)
+{
+ struct die_args *args = data;
+ struct pt_regs *regs = args->regs;
+ int ret = NOTIFY_DONE;
+
+ /* We are only interested in userspace traps */
+ if (regs && !user_mode_vm(regs))
+ return NOTIFY_DONE;
+
+ switch (val) {
+ case DIE_INT3:
+ if (uprobe_pre_sstep_notifier(regs))
+ ret = NOTIFY_STOP;
+
+ break;
+
+ case DIE_DEBUG:
+ if (uprobe_post_sstep_notifier(regs))
+ ret = NOTIFY_STOP;
+
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * This function gets called when XOL instruction either gets trapped or
+ * the thread has a fatal signal, so reset the instruction pointer to its
+ * probed address.
+ */
+void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+ struct uprobe_task *utask = current->utask;
+
+ current->thread.trap_nr = utask->autask.saved_trap_nr;
+ handle_riprel_post_xol(auprobe, regs, NULL);
+ instruction_pointer_set(regs, utask->vaddr);
+}
+
+/*
+ * Skip these instructions as per the currently known x86 ISA.
+ * 0x66* { 0x90 | 0x0f 0x1f | 0x0f 0x19 | 0x87 0xc0 }
+ */
+bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
+{
+ int i;
+
+ for (i = 0; i < MAX_UINSN_BYTES; i++) {
+ if ((auprobe->insn[i] == 0x66))
+ continue;
+
+ if (auprobe->insn[i] == 0x90)
+ return true;
+
+ if (i == (MAX_UINSN_BYTES - 1))
+ break;
+
+ if ((auprobe->insn[i] == 0x0f) && (auprobe->insn[i+1] == 0x1f))
+ return true;
+
+ if ((auprobe->insn[i] == 0x0f) && (auprobe->insn[i+1] == 0x19))
+ return true;
+
+ if ((auprobe->insn[i] == 0x87) && (auprobe->insn[i+1] == 0xc0))
+ return true;
+
+ break;
+ }
+ return false;
+}
diff --git a/arch/x86/kernel/vsmp_64.c b/arch/x86/kernel/vsmp_64.c
index a1d804bcd483..8eeb55a551b4 100644
--- a/arch/x86/kernel/vsmp_64.c
+++ b/arch/x86/kernel/vsmp_64.c
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/pci_ids.h>
#include <linux/pci_regs.h>
+#include <linux/smp.h>
#include <asm/apic.h>
#include <asm/pci-direct.h>
@@ -22,6 +23,8 @@
#include <asm/paravirt.h>
#include <asm/setup.h>
+#define TOPOLOGY_REGISTER_OFFSET 0x10
+
#if defined CONFIG_PCI && defined CONFIG_PARAVIRT
/*
* Interrupt control on vSMPowered systems:
@@ -149,12 +152,49 @@ int is_vsmp_box(void)
return 0;
}
#endif
+
+static void __init vsmp_cap_cpus(void)
+{
+#if !defined(CONFIG_X86_VSMP) && defined(CONFIG_SMP)
+ void __iomem *address;
+ unsigned int cfg, topology, node_shift, maxcpus;
+
+ /*
+ * CONFIG_X86_VSMP is not configured, so limit the number CPUs to the
+ * ones present in the first board, unless explicitly overridden by
+ * setup_max_cpus
+ */
+ if (setup_max_cpus != NR_CPUS)
+ return;
+
+ /* Read the vSMP Foundation topology register */
+ cfg = read_pci_config(0, 0x1f, 0, PCI_BASE_ADDRESS_0);
+ address = early_ioremap(cfg + TOPOLOGY_REGISTER_OFFSET, 4);
+ if (WARN_ON(!address))
+ return;
+
+ topology = readl(address);
+ node_shift = (topology >> 16) & 0x7;
+ if (!node_shift)
+ /* The value 0 should be decoded as 8 */
+ node_shift = 8;
+ maxcpus = (topology & ((1 << node_shift) - 1)) + 1;
+
+ pr_info("vSMP CTL: Capping CPUs to %d (CONFIG_X86_VSMP is unset)\n",
+ maxcpus);
+ setup_max_cpus = maxcpus;
+ early_iounmap(address, 4);
+#endif
+}
+
void __init vsmp_init(void)
{
detect_vsmp_box();
if (!is_vsmp_box())
return;
+ vsmp_cap_cpus();
+
set_vsmp_pv_ops();
return;
}
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index 9cf71d0b2d37..35c5e543f550 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -18,6 +18,7 @@
#include <asm/e820.h>
#include <asm/time.h>
#include <asm/irq.h>
+#include <asm/io_apic.h>
#include <asm/pat.h>
#include <asm/tsc.h>
#include <asm/iommu.h>
@@ -119,3 +120,10 @@ struct x86_msi_ops x86_msi = {
.teardown_msi_irqs = default_teardown_msi_irqs,
.restore_msi_irqs = default_restore_msi_irqs,
};
+
+struct x86_io_apic_ops x86_io_apic_ops = {
+ .init = native_io_apic_init_mappings,
+ .read = native_io_apic_read,
+ .write = native_io_apic_write,
+ .modify = native_io_apic_modify,
+};
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c
index e62728e30b01..bd18149b2b0f 100644
--- a/arch/x86/kernel/xsave.c
+++ b/arch/x86/kernel/xsave.c
@@ -48,8 +48,6 @@ void __sanitize_i387_state(struct task_struct *tsk)
if (!fx)
return;
- BUG_ON(__thread_has_fpu(tsk));
-
xstate_bv = tsk->thread.fpu.state->xsave.xsave_hdr.xstate_bv;
/*
diff --git a/arch/x86/lib/checksum_32.S b/arch/x86/lib/checksum_32.S
index 78d16a554db0..2af5df3ade7c 100644
--- a/arch/x86/lib/checksum_32.S
+++ b/arch/x86/lib/checksum_32.S
@@ -28,6 +28,7 @@
#include <linux/linkage.h>
#include <asm/dwarf2.h>
#include <asm/errno.h>
+#include <asm/asm.h>
/*
* computes a partial checksum, e.g. for TCP/UDP fragments
@@ -282,15 +283,11 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst,
#define SRC(y...) \
9999: y; \
- .section __ex_table, "a"; \
- .long 9999b, 6001f ; \
- .previous
+ _ASM_EXTABLE(9999b, 6001f)
#define DST(y...) \
9999: y; \
- .section __ex_table, "a"; \
- .long 9999b, 6002f ; \
- .previous
+ _ASM_EXTABLE(9999b, 6002f)
#ifndef CONFIG_X86_USE_PPRO_CHECKSUM
diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S
index 024840266ba0..5b2995f4557a 100644
--- a/arch/x86/lib/copy_user_64.S
+++ b/arch/x86/lib/copy_user_64.S
@@ -16,6 +16,7 @@
#include <asm/thread_info.h>
#include <asm/cpufeature.h>
#include <asm/alternative-asm.h>
+#include <asm/asm.h>
/*
* By placing feature2 after feature1 in altinstructions section, we logically
@@ -63,11 +64,8 @@
jmp copy_user_handle_tail
.previous
- .section __ex_table,"a"
- .align 8
- .quad 100b,103b
- .quad 101b,103b
- .previous
+ _ASM_EXTABLE(100b,103b)
+ _ASM_EXTABLE(101b,103b)
#endif
.endm
@@ -191,29 +189,26 @@ ENTRY(copy_user_generic_unrolled)
60: jmp copy_user_handle_tail /* ecx is zerorest also */
.previous
- .section __ex_table,"a"
- .align 8
- .quad 1b,30b
- .quad 2b,30b
- .quad 3b,30b
- .quad 4b,30b
- .quad 5b,30b
- .quad 6b,30b
- .quad 7b,30b
- .quad 8b,30b
- .quad 9b,30b
- .quad 10b,30b
- .quad 11b,30b
- .quad 12b,30b
- .quad 13b,30b
- .quad 14b,30b
- .quad 15b,30b
- .quad 16b,30b
- .quad 18b,40b
- .quad 19b,40b
- .quad 21b,50b
- .quad 22b,50b
- .previous
+ _ASM_EXTABLE(1b,30b)
+ _ASM_EXTABLE(2b,30b)
+ _ASM_EXTABLE(3b,30b)
+ _ASM_EXTABLE(4b,30b)
+ _ASM_EXTABLE(5b,30b)
+ _ASM_EXTABLE(6b,30b)
+ _ASM_EXTABLE(7b,30b)
+ _ASM_EXTABLE(8b,30b)
+ _ASM_EXTABLE(9b,30b)
+ _ASM_EXTABLE(10b,30b)
+ _ASM_EXTABLE(11b,30b)
+ _ASM_EXTABLE(12b,30b)
+ _ASM_EXTABLE(13b,30b)
+ _ASM_EXTABLE(14b,30b)
+ _ASM_EXTABLE(15b,30b)
+ _ASM_EXTABLE(16b,30b)
+ _ASM_EXTABLE(18b,40b)
+ _ASM_EXTABLE(19b,40b)
+ _ASM_EXTABLE(21b,50b)
+ _ASM_EXTABLE(22b,50b)
CFI_ENDPROC
ENDPROC(copy_user_generic_unrolled)
@@ -259,11 +254,8 @@ ENTRY(copy_user_generic_string)
jmp copy_user_handle_tail
.previous
- .section __ex_table,"a"
- .align 8
- .quad 1b,11b
- .quad 3b,12b
- .previous
+ _ASM_EXTABLE(1b,11b)
+ _ASM_EXTABLE(3b,12b)
CFI_ENDPROC
ENDPROC(copy_user_generic_string)
@@ -294,9 +286,6 @@ ENTRY(copy_user_enhanced_fast_string)
jmp copy_user_handle_tail
.previous
- .section __ex_table,"a"
- .align 8
- .quad 1b,12b
- .previous
+ _ASM_EXTABLE(1b,12b)
CFI_ENDPROC
ENDPROC(copy_user_enhanced_fast_string)
diff --git a/arch/x86/lib/copy_user_nocache_64.S b/arch/x86/lib/copy_user_nocache_64.S
index cb0c112386fb..cacddc7163eb 100644
--- a/arch/x86/lib/copy_user_nocache_64.S
+++ b/arch/x86/lib/copy_user_nocache_64.S
@@ -14,6 +14,7 @@
#include <asm/current.h>
#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
+#include <asm/asm.h>
.macro ALIGN_DESTINATION
#ifdef FIX_ALIGNMENT
@@ -36,11 +37,8 @@
jmp copy_user_handle_tail
.previous
- .section __ex_table,"a"
- .align 8
- .quad 100b,103b
- .quad 101b,103b
- .previous
+ _ASM_EXTABLE(100b,103b)
+ _ASM_EXTABLE(101b,103b)
#endif
.endm
@@ -111,27 +109,25 @@ ENTRY(__copy_user_nocache)
jmp copy_user_handle_tail
.previous
- .section __ex_table,"a"
- .quad 1b,30b
- .quad 2b,30b
- .quad 3b,30b
- .quad 4b,30b
- .quad 5b,30b
- .quad 6b,30b
- .quad 7b,30b
- .quad 8b,30b
- .quad 9b,30b
- .quad 10b,30b
- .quad 11b,30b
- .quad 12b,30b
- .quad 13b,30b
- .quad 14b,30b
- .quad 15b,30b
- .quad 16b,30b
- .quad 18b,40b
- .quad 19b,40b
- .quad 21b,50b
- .quad 22b,50b
- .previous
+ _ASM_EXTABLE(1b,30b)
+ _ASM_EXTABLE(2b,30b)
+ _ASM_EXTABLE(3b,30b)
+ _ASM_EXTABLE(4b,30b)
+ _ASM_EXTABLE(5b,30b)
+ _ASM_EXTABLE(6b,30b)
+ _ASM_EXTABLE(7b,30b)
+ _ASM_EXTABLE(8b,30b)
+ _ASM_EXTABLE(9b,30b)
+ _ASM_EXTABLE(10b,30b)
+ _ASM_EXTABLE(11b,30b)
+ _ASM_EXTABLE(12b,30b)
+ _ASM_EXTABLE(13b,30b)
+ _ASM_EXTABLE(14b,30b)
+ _ASM_EXTABLE(15b,30b)
+ _ASM_EXTABLE(16b,30b)
+ _ASM_EXTABLE(18b,40b)
+ _ASM_EXTABLE(19b,40b)
+ _ASM_EXTABLE(21b,50b)
+ _ASM_EXTABLE(22b,50b)
CFI_ENDPROC
ENDPROC(__copy_user_nocache)
diff --git a/arch/x86/lib/csum-copy_64.S b/arch/x86/lib/csum-copy_64.S
index fb903b758da8..2419d5fefae3 100644
--- a/arch/x86/lib/csum-copy_64.S
+++ b/arch/x86/lib/csum-copy_64.S
@@ -8,6 +8,7 @@
#include <linux/linkage.h>
#include <asm/dwarf2.h>
#include <asm/errno.h>
+#include <asm/asm.h>
/*
* Checksum copy with exception handling.
@@ -31,26 +32,17 @@
.macro source
10:
- .section __ex_table, "a"
- .align 8
- .quad 10b, .Lbad_source
- .previous
+ _ASM_EXTABLE(10b, .Lbad_source)
.endm
.macro dest
20:
- .section __ex_table, "a"
- .align 8
- .quad 20b, .Lbad_dest
- .previous
+ _ASM_EXTABLE(20b, .Lbad_dest)
.endm
.macro ignore L=.Lignore
30:
- .section __ex_table, "a"
- .align 8
- .quad 30b, \L
- .previous
+ _ASM_EXTABLE(30b, \L)
.endm
diff --git a/arch/x86/lib/getuser.S b/arch/x86/lib/getuser.S
index 51f1504cddd9..b33b1fb1e6d4 100644
--- a/arch/x86/lib/getuser.S
+++ b/arch/x86/lib/getuser.S
@@ -95,10 +95,9 @@ bad_get_user:
CFI_ENDPROC
END(bad_get_user)
-.section __ex_table,"a"
- _ASM_PTR 1b,bad_get_user
- _ASM_PTR 2b,bad_get_user
- _ASM_PTR 3b,bad_get_user
+ _ASM_EXTABLE(1b,bad_get_user)
+ _ASM_EXTABLE(2b,bad_get_user)
+ _ASM_EXTABLE(3b,bad_get_user)
#ifdef CONFIG_X86_64
- _ASM_PTR 4b,bad_get_user
+ _ASM_EXTABLE(4b,bad_get_user)
#endif
diff --git a/arch/x86/lib/putuser.S b/arch/x86/lib/putuser.S
index 36b0d15ae6e9..7f951c8f76c4 100644
--- a/arch/x86/lib/putuser.S
+++ b/arch/x86/lib/putuser.S
@@ -86,12 +86,10 @@ bad_put_user:
EXIT
END(bad_put_user)
-.section __ex_table,"a"
- _ASM_PTR 1b,bad_put_user
- _ASM_PTR 2b,bad_put_user
- _ASM_PTR 3b,bad_put_user
- _ASM_PTR 4b,bad_put_user
+ _ASM_EXTABLE(1b,bad_put_user)
+ _ASM_EXTABLE(2b,bad_put_user)
+ _ASM_EXTABLE(3b,bad_put_user)
+ _ASM_EXTABLE(4b,bad_put_user)
#ifdef CONFIG_X86_32
- _ASM_PTR 5b,bad_put_user
+ _ASM_EXTABLE(5b,bad_put_user)
#endif
-.previous
diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c
index ef2a6a5d78e3..883b216c60b2 100644
--- a/arch/x86/lib/usercopy_32.c
+++ b/arch/x86/lib/usercopy_32.c
@@ -13,6 +13,7 @@
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <asm/mmx.h>
+#include <asm/asm.h>
#ifdef CONFIG_X86_INTEL_USERCOPY
/*
@@ -127,10 +128,7 @@ long strnlen_user(const char __user *s, long n)
"3: movb $1,%%al\n"
" jmp 1b\n"
".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 0b,2b\n"
- ".previous"
+ _ASM_EXTABLE(0b,2b)
:"=&r" (n), "=&D" (s), "=&a" (res), "=&c" (tmp)
:"0" (n), "1" (s), "2" (0), "3" (mask)
:"cc");
@@ -199,47 +197,44 @@ __copy_user_intel(void __user *to, const void *from, unsigned long size)
"101: lea 0(%%eax,%0,4),%0\n"
" jmp 100b\n"
".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 1b,100b\n"
- " .long 2b,100b\n"
- " .long 3b,100b\n"
- " .long 4b,100b\n"
- " .long 5b,100b\n"
- " .long 6b,100b\n"
- " .long 7b,100b\n"
- " .long 8b,100b\n"
- " .long 9b,100b\n"
- " .long 10b,100b\n"
- " .long 11b,100b\n"
- " .long 12b,100b\n"
- " .long 13b,100b\n"
- " .long 14b,100b\n"
- " .long 15b,100b\n"
- " .long 16b,100b\n"
- " .long 17b,100b\n"
- " .long 18b,100b\n"
- " .long 19b,100b\n"
- " .long 20b,100b\n"
- " .long 21b,100b\n"
- " .long 22b,100b\n"
- " .long 23b,100b\n"
- " .long 24b,100b\n"
- " .long 25b,100b\n"
- " .long 26b,100b\n"
- " .long 27b,100b\n"
- " .long 28b,100b\n"
- " .long 29b,100b\n"
- " .long 30b,100b\n"
- " .long 31b,100b\n"
- " .long 32b,100b\n"
- " .long 33b,100b\n"
- " .long 34b,100b\n"
- " .long 35b,100b\n"
- " .long 36b,100b\n"
- " .long 37b,100b\n"
- " .long 99b,101b\n"
- ".previous"
+ _ASM_EXTABLE(1b,100b)
+ _ASM_EXTABLE(2b,100b)
+ _ASM_EXTABLE(3b,100b)
+ _ASM_EXTABLE(4b,100b)
+ _ASM_EXTABLE(5b,100b)
+ _ASM_EXTABLE(6b,100b)
+ _ASM_EXTABLE(7b,100b)
+ _ASM_EXTABLE(8b,100b)
+ _ASM_EXTABLE(9b,100b)
+ _ASM_EXTABLE(10b,100b)
+ _ASM_EXTABLE(11b,100b)
+ _ASM_EXTABLE(12b,100b)
+ _ASM_EXTABLE(13b,100b)
+ _ASM_EXTABLE(14b,100b)
+ _ASM_EXTABLE(15b,100b)
+ _ASM_EXTABLE(16b,100b)
+ _ASM_EXTABLE(17b,100b)
+ _ASM_EXTABLE(18b,100b)
+ _ASM_EXTABLE(19b,100b)
+ _ASM_EXTABLE(20b,100b)
+ _ASM_EXTABLE(21b,100b)
+ _ASM_EXTABLE(22b,100b)
+ _ASM_EXTABLE(23b,100b)
+ _ASM_EXTABLE(24b,100b)
+ _ASM_EXTABLE(25b,100b)
+ _ASM_EXTABLE(26b,100b)
+ _ASM_EXTABLE(27b,100b)
+ _ASM_EXTABLE(28b,100b)
+ _ASM_EXTABLE(29b,100b)
+ _ASM_EXTABLE(30b,100b)
+ _ASM_EXTABLE(31b,100b)
+ _ASM_EXTABLE(32b,100b)
+ _ASM_EXTABLE(33b,100b)
+ _ASM_EXTABLE(34b,100b)
+ _ASM_EXTABLE(35b,100b)
+ _ASM_EXTABLE(36b,100b)
+ _ASM_EXTABLE(37b,100b)
+ _ASM_EXTABLE(99b,101b)
: "=&c"(size), "=&D" (d0), "=&S" (d1)
: "1"(to), "2"(from), "0"(size)
: "eax", "edx", "memory");
@@ -312,29 +307,26 @@ __copy_user_zeroing_intel(void *to, const void __user *from, unsigned long size)
" popl %0\n"
" jmp 8b\n"
".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 0b,16b\n"
- " .long 1b,16b\n"
- " .long 2b,16b\n"
- " .long 21b,16b\n"
- " .long 3b,16b\n"
- " .long 31b,16b\n"
- " .long 4b,16b\n"
- " .long 41b,16b\n"
- " .long 10b,16b\n"
- " .long 51b,16b\n"
- " .long 11b,16b\n"
- " .long 61b,16b\n"
- " .long 12b,16b\n"
- " .long 71b,16b\n"
- " .long 13b,16b\n"
- " .long 81b,16b\n"
- " .long 14b,16b\n"
- " .long 91b,16b\n"
- " .long 6b,9b\n"
- " .long 7b,16b\n"
- ".previous"
+ _ASM_EXTABLE(0b,16b)
+ _ASM_EXTABLE(1b,16b)
+ _ASM_EXTABLE(2b,16b)
+ _ASM_EXTABLE(21b,16b)
+ _ASM_EXTABLE(3b,16b)
+ _ASM_EXTABLE(31b,16b)
+ _ASM_EXTABLE(4b,16b)
+ _ASM_EXTABLE(41b,16b)
+ _ASM_EXTABLE(10b,16b)
+ _ASM_EXTABLE(51b,16b)
+ _ASM_EXTABLE(11b,16b)
+ _ASM_EXTABLE(61b,16b)
+ _ASM_EXTABLE(12b,16b)
+ _ASM_EXTABLE(71b,16b)
+ _ASM_EXTABLE(13b,16b)
+ _ASM_EXTABLE(81b,16b)
+ _ASM_EXTABLE(14b,16b)
+ _ASM_EXTABLE(91b,16b)
+ _ASM_EXTABLE(6b,9b)
+ _ASM_EXTABLE(7b,16b)
: "=&c"(size), "=&D" (d0), "=&S" (d1)
: "1"(to), "2"(from), "0"(size)
: "eax", "edx", "memory");
@@ -414,29 +406,26 @@ static unsigned long __copy_user_zeroing_intel_nocache(void *to,
" popl %0\n"
" jmp 8b\n"
".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 0b,16b\n"
- " .long 1b,16b\n"
- " .long 2b,16b\n"
- " .long 21b,16b\n"
- " .long 3b,16b\n"
- " .long 31b,16b\n"
- " .long 4b,16b\n"
- " .long 41b,16b\n"
- " .long 10b,16b\n"
- " .long 51b,16b\n"
- " .long 11b,16b\n"
- " .long 61b,16b\n"
- " .long 12b,16b\n"
- " .long 71b,16b\n"
- " .long 13b,16b\n"
- " .long 81b,16b\n"
- " .long 14b,16b\n"
- " .long 91b,16b\n"
- " .long 6b,9b\n"
- " .long 7b,16b\n"
- ".previous"
+ _ASM_EXTABLE(0b,16b)
+ _ASM_EXTABLE(1b,16b)
+ _ASM_EXTABLE(2b,16b)
+ _ASM_EXTABLE(21b,16b)
+ _ASM_EXTABLE(3b,16b)
+ _ASM_EXTABLE(31b,16b)
+ _ASM_EXTABLE(4b,16b)
+ _ASM_EXTABLE(41b,16b)
+ _ASM_EXTABLE(10b,16b)
+ _ASM_EXTABLE(51b,16b)
+ _ASM_EXTABLE(11b,16b)
+ _ASM_EXTABLE(61b,16b)
+ _ASM_EXTABLE(12b,16b)
+ _ASM_EXTABLE(71b,16b)
+ _ASM_EXTABLE(13b,16b)
+ _ASM_EXTABLE(81b,16b)
+ _ASM_EXTABLE(14b,16b)
+ _ASM_EXTABLE(91b,16b)
+ _ASM_EXTABLE(6b,9b)
+ _ASM_EXTABLE(7b,16b)
: "=&c"(size), "=&D" (d0), "=&S" (d1)
: "1"(to), "2"(from), "0"(size)
: "eax", "edx", "memory");
@@ -505,29 +494,26 @@ static unsigned long __copy_user_intel_nocache(void *to,
"9: lea 0(%%eax,%0,4),%0\n"
"16: jmp 8b\n"
".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 0b,16b\n"
- " .long 1b,16b\n"
- " .long 2b,16b\n"
- " .long 21b,16b\n"
- " .long 3b,16b\n"
- " .long 31b,16b\n"
- " .long 4b,16b\n"
- " .long 41b,16b\n"
- " .long 10b,16b\n"
- " .long 51b,16b\n"
- " .long 11b,16b\n"
- " .long 61b,16b\n"
- " .long 12b,16b\n"
- " .long 71b,16b\n"
- " .long 13b,16b\n"
- " .long 81b,16b\n"
- " .long 14b,16b\n"
- " .long 91b,16b\n"
- " .long 6b,9b\n"
- " .long 7b,16b\n"
- ".previous"
+ _ASM_EXTABLE(0b,16b)
+ _ASM_EXTABLE(1b,16b)
+ _ASM_EXTABLE(2b,16b)
+ _ASM_EXTABLE(21b,16b)
+ _ASM_EXTABLE(3b,16b)
+ _ASM_EXTABLE(31b,16b)
+ _ASM_EXTABLE(4b,16b)
+ _ASM_EXTABLE(41b,16b)
+ _ASM_EXTABLE(10b,16b)
+ _ASM_EXTABLE(51b,16b)
+ _ASM_EXTABLE(11b,16b)
+ _ASM_EXTABLE(61b,16b)
+ _ASM_EXTABLE(12b,16b)
+ _ASM_EXTABLE(71b,16b)
+ _ASM_EXTABLE(13b,16b)
+ _ASM_EXTABLE(81b,16b)
+ _ASM_EXTABLE(14b,16b)
+ _ASM_EXTABLE(91b,16b)
+ _ASM_EXTABLE(6b,9b)
+ _ASM_EXTABLE(7b,16b)
: "=&c"(size), "=&D" (d0), "=&S" (d1)
: "1"(to), "2"(from), "0"(size)
: "eax", "edx", "memory");
@@ -574,12 +560,9 @@ do { \
"3: lea 0(%3,%0,4),%0\n" \
" jmp 2b\n" \
".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 4b,5b\n" \
- " .long 0b,3b\n" \
- " .long 1b,2b\n" \
- ".previous" \
+ _ASM_EXTABLE(4b,5b) \
+ _ASM_EXTABLE(0b,3b) \
+ _ASM_EXTABLE(1b,2b) \
: "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) \
: "3"(size), "0"(size), "1"(to), "2"(from) \
: "memory"); \
@@ -616,12 +599,9 @@ do { \
" popl %0\n" \
" jmp 2b\n" \
".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 4b,5b\n" \
- " .long 0b,3b\n" \
- " .long 1b,6b\n" \
- ".previous" \
+ _ASM_EXTABLE(4b,5b) \
+ _ASM_EXTABLE(0b,3b) \
+ _ASM_EXTABLE(1b,6b) \
: "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) \
: "3"(size), "0"(size), "1"(to), "2"(from) \
: "memory"); \
diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
index 1fb85dbe390a..903ec1e9c326 100644
--- a/arch/x86/mm/extable.c
+++ b/arch/x86/mm/extable.c
@@ -1,11 +1,23 @@
#include <linux/module.h>
#include <linux/spinlock.h>
+#include <linux/sort.h>
#include <asm/uaccess.h>
+static inline unsigned long
+ex_insn_addr(const struct exception_table_entry *x)
+{
+ return (unsigned long)&x->insn + x->insn;
+}
+static inline unsigned long
+ex_fixup_addr(const struct exception_table_entry *x)
+{
+ return (unsigned long)&x->fixup + x->fixup;
+}
int fixup_exception(struct pt_regs *regs)
{
const struct exception_table_entry *fixup;
+ unsigned long new_ip;
#ifdef CONFIG_PNPBIOS
if (unlikely(SEGMENT_IS_PNP_CODE(regs->cs))) {
@@ -23,15 +35,135 @@ int fixup_exception(struct pt_regs *regs)
fixup = search_exception_tables(regs->ip);
if (fixup) {
- /* If fixup is less than 16, it means uaccess error */
- if (fixup->fixup < 16) {
+ new_ip = ex_fixup_addr(fixup);
+
+ if (fixup->fixup - fixup->insn >= 0x7ffffff0 - 4) {
+ /* Special hack for uaccess_err */
current_thread_info()->uaccess_err = 1;
- regs->ip += fixup->fixup;
- return 1;
+ new_ip -= 0x7ffffff0;
}
- regs->ip = fixup->fixup;
+ regs->ip = new_ip;
return 1;
}
return 0;
}
+
+/* Restricted version used during very early boot */
+int __init early_fixup_exception(unsigned long *ip)
+{
+ const struct exception_table_entry *fixup;
+ unsigned long new_ip;
+
+ fixup = search_exception_tables(*ip);
+ if (fixup) {
+ new_ip = ex_fixup_addr(fixup);
+
+ if (fixup->fixup - fixup->insn >= 0x7ffffff0 - 4) {
+ /* uaccess handling not supported during early boot */
+ return 0;
+ }
+
+ *ip = new_ip;
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Search one exception table for an entry corresponding to the
+ * given instruction address, and return the address of the entry,
+ * or NULL if none is found.
+ * We use a binary search, and thus we assume that the table is
+ * already sorted.
+ */
+const struct exception_table_entry *
+search_extable(const struct exception_table_entry *first,
+ const struct exception_table_entry *last,
+ unsigned long value)
+{
+ while (first <= last) {
+ const struct exception_table_entry *mid;
+ unsigned long addr;
+
+ mid = ((last - first) >> 1) + first;
+ addr = ex_insn_addr(mid);
+ if (addr < value)
+ first = mid + 1;
+ else if (addr > value)
+ last = mid - 1;
+ else
+ return mid;
+ }
+ return NULL;
+}
+
+/*
+ * The exception table needs to be sorted so that the binary
+ * search that we use to find entries in it works properly.
+ * This is used both for the kernel exception table and for
+ * the exception tables of modules that get loaded.
+ *
+ */
+static int cmp_ex(const void *a, const void *b)
+{
+ const struct exception_table_entry *x = a, *y = b;
+
+ /*
+ * This value will always end up fittin in an int, because on
+ * both i386 and x86-64 the kernel symbol-reachable address
+ * space is < 2 GiB.
+ *
+ * This compare is only valid after normalization.
+ */
+ return x->insn - y->insn;
+}
+
+void sort_extable(struct exception_table_entry *start,
+ struct exception_table_entry *finish)
+{
+ struct exception_table_entry *p;
+ int i;
+
+ /* Convert all entries to being relative to the start of the section */
+ i = 0;
+ for (p = start; p < finish; p++) {
+ p->insn += i;
+ i += 4;
+ p->fixup += i;
+ i += 4;
+ }
+
+ sort(start, finish - start, sizeof(struct exception_table_entry),
+ cmp_ex, NULL);
+
+ /* Denormalize all entries */
+ i = 0;
+ for (p = start; p < finish; p++) {
+ p->insn -= i;
+ i += 4;
+ p->fixup -= i;
+ i += 4;
+ }
+}
+
+#ifdef CONFIG_MODULES
+/*
+ * If the exception table is sorted, any referring to the module init
+ * will be at the beginning or the end.
+ */
+void trim_init_extable(struct module *m)
+{
+ /*trim the beginning*/
+ while (m->num_exentries &&
+ within_module_init(ex_insn_addr(&m->extable[0]), m)) {
+ m->extable++;
+ m->num_exentries--;
+ }
+ /*trim the end*/
+ while (m->num_exentries &&
+ within_module_init(ex_insn_addr(&m->extable[m->num_exentries-1]), m))
+ m->num_exentries--;
+}
+#endif /* CONFIG_MODULES */
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 3ecfd1aaf214..76dcd9d8e0bc 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -582,7 +582,7 @@ show_fault_oops(struct pt_regs *regs, unsigned long error_code,
pte_t *pte = lookup_address(address, &level);
if (pte && pte_present(*pte) && !pte_exec(*pte))
- printk(nx_warning, current_uid());
+ printk(nx_warning, from_kuid(&init_user_ns, current_uid()));
}
printk(KERN_ALERT "BUG: unable to handle kernel ");
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index 4f0cec7e4ffb..319b6f2fb8b9 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -29,8 +29,14 @@ int direct_gbpages
#endif
;
-static void __init find_early_table_space(unsigned long end, int use_pse,
- int use_gbpages)
+struct map_range {
+ unsigned long start;
+ unsigned long end;
+ unsigned page_size_mask;
+};
+
+static void __init find_early_table_space(struct map_range *mr, unsigned long end,
+ int use_pse, int use_gbpages)
{
unsigned long puds, pmds, ptes, tables, start = 0, good_end = end;
phys_addr_t base;
@@ -55,6 +61,9 @@ static void __init find_early_table_space(unsigned long end, int use_pse,
#ifdef CONFIG_X86_32
extra += PMD_SIZE;
#endif
+ /* The first 2/4M doesn't use large pages. */
+ extra += mr->end - mr->start;
+
ptes = (extra + PAGE_SIZE - 1) >> PAGE_SHIFT;
} else
ptes = (end + PAGE_SIZE - 1) >> PAGE_SHIFT;
@@ -84,12 +93,6 @@ void __init native_pagetable_reserve(u64 start, u64 end)
memblock_reserve(start, end - start);
}
-struct map_range {
- unsigned long start;
- unsigned long end;
- unsigned page_size_mask;
-};
-
#ifdef CONFIG_X86_32
#define NR_RANGE_MR 3
#else /* CONFIG_X86_64 */
@@ -261,7 +264,7 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
* nodes are discovered.
*/
if (!after_bootmem)
- find_early_table_space(end, use_pse, use_gbpages);
+ find_early_table_space(&mr[0], end, use_pse, use_gbpages);
for (i = 0; i < nr_range; i++)
ret = kernel_physical_mapping_init(mr[i].start, mr[i].end,
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index fc18be0f6f29..2b6b4a3c8beb 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -407,12 +407,12 @@ static unsigned long __meminit
phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
unsigned long page_size_mask, pgprot_t prot)
{
- unsigned long pages = 0;
+ unsigned long pages = 0, next;
unsigned long last_map_addr = end;
int i = pmd_index(address);
- for (; i < PTRS_PER_PMD; i++, address += PMD_SIZE) {
+ for (; i < PTRS_PER_PMD; i++, address = next) {
unsigned long pte_phys;
pmd_t *pmd = pmd_page + pmd_index(address);
pte_t *pte;
@@ -426,6 +426,8 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
break;
}
+ next = (address & PMD_MASK) + PMD_SIZE;
+
if (pmd_val(*pmd)) {
if (!pmd_large(*pmd)) {
spin_lock(&init_mm.page_table_lock);
@@ -449,7 +451,7 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
* attributes.
*/
if (page_size_mask & (1 << PG_LEVEL_2M)) {
- pages++;
+ last_map_addr = next;
continue;
}
new_prot = pte_pgprot(pte_clrhuge(*(pte_t *)pmd));
@@ -462,7 +464,7 @@ phys_pmd_init(pmd_t *pmd_page, unsigned long address, unsigned long end,
pfn_pte(address >> PAGE_SHIFT,
__pgprot(pgprot_val(prot) | _PAGE_PSE)));
spin_unlock(&init_mm.page_table_lock);
- last_map_addr = (address & PMD_MASK) + PMD_SIZE;
+ last_map_addr = next;
continue;
}
@@ -482,11 +484,11 @@ static unsigned long __meminit
phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,
unsigned long page_size_mask)
{
- unsigned long pages = 0;
+ unsigned long pages = 0, next;
unsigned long last_map_addr = end;
int i = pud_index(addr);
- for (; i < PTRS_PER_PUD; i++, addr = (addr & PUD_MASK) + PUD_SIZE) {
+ for (; i < PTRS_PER_PUD; i++, addr = next) {
unsigned long pmd_phys;
pud_t *pud = pud_page + pud_index(addr);
pmd_t *pmd;
@@ -495,8 +497,9 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,
if (addr >= end)
break;
- if (!after_bootmem &&
- !e820_any_mapped(addr, addr+PUD_SIZE, 0)) {
+ next = (addr & PUD_MASK) + PUD_SIZE;
+
+ if (!after_bootmem && !e820_any_mapped(addr, next, 0)) {
set_pud(pud, __pud(0));
continue;
}
@@ -523,7 +526,7 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,
* attributes.
*/
if (page_size_mask & (1 << PG_LEVEL_1G)) {
- pages++;
+ last_map_addr = next;
continue;
}
prot = pte_pgprot(pte_clrhuge(*(pte_t *)pud));
@@ -535,7 +538,7 @@ phys_pud_init(pud_t *pud_page, unsigned long addr, unsigned long end,
set_pte((pte_t *)pud,
pfn_pte(addr >> PAGE_SHIFT, PAGE_KERNEL_LARGE));
spin_unlock(&init_mm.page_table_lock);
- last_map_addr = (addr & PUD_MASK) + PUD_SIZE;
+ last_map_addr = next;
continue;
}
diff --git a/arch/x86/mm/numa_emulation.c b/arch/x86/mm/numa_emulation.c
index 53489ff6bf82..871dd8868170 100644
--- a/arch/x86/mm/numa_emulation.c
+++ b/arch/x86/mm/numa_emulation.c
@@ -339,9 +339,11 @@ void __init numa_emulation(struct numa_meminfo *numa_meminfo, int numa_dist_cnt)
} else {
unsigned long n;
- n = simple_strtoul(emu_cmdline, NULL, 0);
+ n = simple_strtoul(emu_cmdline, &emu_cmdline, 0);
ret = split_nodes_interleave(&ei, &pi, 0, max_addr, n);
}
+ if (*emu_cmdline == ':')
+ emu_cmdline++;
if (ret < 0)
goto no_emu;
@@ -418,7 +420,9 @@ void __init numa_emulation(struct numa_meminfo *numa_meminfo, int numa_dist_cnt)
int physj = emu_nid_to_phys[j];
int dist;
- if (physi >= numa_dist_cnt || physj >= numa_dist_cnt)
+ if (get_option(&emu_cmdline, &dist) == 2)
+ ;
+ else if (physi >= numa_dist_cnt || physj >= numa_dist_cnt)
dist = physi == physj ?
LOCAL_DISTANCE : REMOTE_DISTANCE;
else
diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c
index d6c0418c3e47..5e57e113b72c 100644
--- a/arch/x86/mm/tlb.c
+++ b/arch/x86/mm/tlb.c
@@ -61,11 +61,13 @@ static DEFINE_PER_CPU_READ_MOSTLY(int, tlb_vector_offset);
*/
void leave_mm(int cpu)
{
- if (percpu_read(cpu_tlbstate.state) == TLBSTATE_OK)
+ struct mm_struct *active_mm = this_cpu_read(cpu_tlbstate.active_mm);
+ if (this_cpu_read(cpu_tlbstate.state) == TLBSTATE_OK)
BUG();
- cpumask_clear_cpu(cpu,
- mm_cpumask(percpu_read(cpu_tlbstate.active_mm)));
- load_cr3(swapper_pg_dir);
+ if (cpumask_test_cpu(cpu, mm_cpumask(active_mm))) {
+ cpumask_clear_cpu(cpu, mm_cpumask(active_mm));
+ load_cr3(swapper_pg_dir);
+ }
}
EXPORT_SYMBOL_GPL(leave_mm);
@@ -152,8 +154,8 @@ void smp_invalidate_interrupt(struct pt_regs *regs)
* BUG();
*/
- if (f->flush_mm == percpu_read(cpu_tlbstate.active_mm)) {
- if (percpu_read(cpu_tlbstate.state) == TLBSTATE_OK) {
+ if (f->flush_mm == this_cpu_read(cpu_tlbstate.active_mm)) {
+ if (this_cpu_read(cpu_tlbstate.state) == TLBSTATE_OK) {
if (f->flush_va == TLB_FLUSH_ALL)
local_flush_tlb();
else
@@ -322,7 +324,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long va)
static void do_flush_tlb_all(void *info)
{
__flush_tlb_all();
- if (percpu_read(cpu_tlbstate.state) == TLBSTATE_LAZY)
+ if (this_cpu_read(cpu_tlbstate.state) == TLBSTATE_LAZY)
leave_mm(smp_processor_id());
}
diff --git a/arch/x86/pci/Makefile b/arch/x86/pci/Makefile
index e76e18c94a3c..3af5a1e79c9c 100644
--- a/arch/x86/pci/Makefile
+++ b/arch/x86/pci/Makefile
@@ -11,6 +11,8 @@ obj-$(CONFIG_X86_INTEL_CE) += ce4100.o
obj-$(CONFIG_ACPI) += acpi.o
obj-y += legacy.o irq.o
+obj-$(CONFIG_STA2X11) += sta2x11-fixup.o
+
obj-$(CONFIG_X86_VISWS) += visws.o
obj-$(CONFIG_X86_NUMAQ) += numaq_32.o
diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c
index d0e6e403b4f6..af8a224db216 100644
--- a/arch/x86/pci/fixup.c
+++ b/arch/x86/pci/fixup.c
@@ -6,6 +6,7 @@
#include <linux/dmi.h>
#include <linux/pci.h>
#include <linux/init.h>
+#include <linux/vgaarb.h>
#include <asm/pci_x86.h>
static void __devinit pci_fixup_i450nx(struct pci_dev *d)
@@ -348,6 +349,8 @@ static void __devinit pci_fixup_video(struct pci_dev *pdev)
if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
dev_printk(KERN_DEBUG, &pdev->dev, "Boot video device\n");
+ if (!vga_default_device())
+ vga_set_default_device(pdev);
}
}
DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
@@ -519,3 +522,20 @@ static void sb600_disable_hpet_bar(struct pci_dev *dev)
}
}
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATI, 0x4385, sb600_disable_hpet_bar);
+
+/*
+ * Twinhead H12Y needs us to block out a region otherwise we map devices
+ * there and any access kills the box.
+ *
+ * See: https://bugzilla.kernel.org/show_bug.cgi?id=10231
+ *
+ * Match off the LPC and svid/sdid (older kernels lose the bridge subvendor)
+ */
+static void __devinit twinhead_reserve_killing_zone(struct pci_dev *dev)
+{
+ if (dev->subsystem_vendor == 0x14FF && dev->subsystem_device == 0xA003) {
+ pr_info("Reserving memory on Twinhead H12Y\n");
+ request_mem_region(0xFFB00000, 0x100000, "twinhead");
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x27B9, twinhead_reserve_killing_zone);
diff --git a/arch/x86/pci/sta2x11-fixup.c b/arch/x86/pci/sta2x11-fixup.c
new file mode 100644
index 000000000000..9d8a509c9730
--- /dev/null
+++ b/arch/x86/pci/sta2x11-fixup.c
@@ -0,0 +1,366 @@
+/*
+ * arch/x86/pci/sta2x11-fixup.c
+ * glue code for lib/swiotlb.c and DMA translation between STA2x11
+ * AMBA memory mapping and the X86 memory mapping
+ *
+ * ST Microelectronics ConneXt (STA2X11/STA2X10)
+ *
+ * Copyright (c) 2010-2011 Wind River Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/export.h>
+#include <linux/list.h>
+
+#define STA2X11_SWIOTLB_SIZE (4*1024*1024)
+extern int swiotlb_late_init_with_default_size(size_t default_size);
+
+/*
+ * We build a list of bus numbers that are under the ConneXt. The
+ * main bridge hosts 4 busses, which are the 4 endpoints, in order.
+ */
+#define STA2X11_NR_EP 4 /* 0..3 included */
+#define STA2X11_NR_FUNCS 8 /* 0..7 included */
+#define STA2X11_AMBA_SIZE (512 << 20)
+
+struct sta2x11_ahb_regs { /* saved during suspend */
+ u32 base, pexlbase, pexhbase, crw;
+};
+
+struct sta2x11_mapping {
+ u32 amba_base;
+ int is_suspended;
+ struct sta2x11_ahb_regs regs[STA2X11_NR_FUNCS];
+};
+
+struct sta2x11_instance {
+ struct list_head list;
+ int bus0;
+ struct sta2x11_mapping map[STA2X11_NR_EP];
+};
+
+static LIST_HEAD(sta2x11_instance_list);
+
+/* At probe time, record new instances of this bridge (likely one only) */
+static void sta2x11_new_instance(struct pci_dev *pdev)
+{
+ struct sta2x11_instance *instance;
+
+ instance = kzalloc(sizeof(*instance), GFP_ATOMIC);
+ if (!instance)
+ return;
+ /* This has a subordinate bridge, with 4 more-subordinate ones */
+ instance->bus0 = pdev->subordinate->number + 1;
+
+ if (list_empty(&sta2x11_instance_list)) {
+ int size = STA2X11_SWIOTLB_SIZE;
+ /* First instance: register your own swiotlb area */
+ dev_info(&pdev->dev, "Using SWIOTLB (size %i)\n", size);
+ if (swiotlb_late_init_with_default_size(size))
+ dev_emerg(&pdev->dev, "init swiotlb failed\n");
+ }
+ list_add(&instance->list, &sta2x11_instance_list);
+}
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, 0xcc17, sta2x11_new_instance);
+
+/*
+ * Utility functions used in this file from below
+ */
+static struct sta2x11_instance *sta2x11_pdev_to_instance(struct pci_dev *pdev)
+{
+ struct sta2x11_instance *instance;
+ int ep;
+
+ list_for_each_entry(instance, &sta2x11_instance_list, list) {
+ ep = pdev->bus->number - instance->bus0;
+ if (ep >= 0 && ep < STA2X11_NR_EP)
+ return instance;
+ }
+ return NULL;
+}
+
+static int sta2x11_pdev_to_ep(struct pci_dev *pdev)
+{
+ struct sta2x11_instance *instance;
+
+ instance = sta2x11_pdev_to_instance(pdev);
+ if (!instance)
+ return -1;
+
+ return pdev->bus->number - instance->bus0;
+}
+
+static struct sta2x11_mapping *sta2x11_pdev_to_mapping(struct pci_dev *pdev)
+{
+ struct sta2x11_instance *instance;
+ int ep;
+
+ instance = sta2x11_pdev_to_instance(pdev);
+ if (!instance)
+ return NULL;
+ ep = sta2x11_pdev_to_ep(pdev);
+ return instance->map + ep;
+}
+
+/* This is exported, as some devices need to access the MFD registers */
+struct sta2x11_instance *sta2x11_get_instance(struct pci_dev *pdev)
+{
+ return sta2x11_pdev_to_instance(pdev);
+}
+EXPORT_SYMBOL(sta2x11_get_instance);
+
+
+/**
+ * p2a - Translate physical address to STA2x11 AMBA address,
+ * used for DMA transfers to STA2x11
+ * @p: Physical address
+ * @pdev: PCI device (must be hosted within the connext)
+ */
+static dma_addr_t p2a(dma_addr_t p, struct pci_dev *pdev)
+{
+ struct sta2x11_mapping *map;
+ dma_addr_t a;
+
+ map = sta2x11_pdev_to_mapping(pdev);
+ a = p + map->amba_base;
+ return a;
+}
+
+/**
+ * a2p - Translate STA2x11 AMBA address to physical address
+ * used for DMA transfers from STA2x11
+ * @a: STA2x11 AMBA address
+ * @pdev: PCI device (must be hosted within the connext)
+ */
+static dma_addr_t a2p(dma_addr_t a, struct pci_dev *pdev)
+{
+ struct sta2x11_mapping *map;
+ dma_addr_t p;
+
+ map = sta2x11_pdev_to_mapping(pdev);
+ p = a - map->amba_base;
+ return p;
+}
+
+/**
+ * sta2x11_swiotlb_alloc_coherent - Allocate swiotlb bounce buffers
+ * returns virtual address. This is the only "special" function here.
+ * @dev: PCI device
+ * @size: Size of the buffer
+ * @dma_handle: DMA address
+ * @flags: memory flags
+ */
+static void *sta2x11_swiotlb_alloc_coherent(struct device *dev,
+ size_t size,
+ dma_addr_t *dma_handle,
+ gfp_t flags,
+ struct dma_attrs *attrs)
+{
+ void *vaddr;
+
+ vaddr = dma_generic_alloc_coherent(dev, size, dma_handle, flags, attrs);
+ if (!vaddr)
+ vaddr = swiotlb_alloc_coherent(dev, size, dma_handle, flags);
+ *dma_handle = p2a(*dma_handle, to_pci_dev(dev));
+ return vaddr;
+}
+
+/* We have our own dma_ops: the same as swiotlb but from alloc (above) */
+static struct dma_map_ops sta2x11_dma_ops = {
+ .alloc = sta2x11_swiotlb_alloc_coherent,
+ .free = swiotlb_free_coherent,
+ .map_page = swiotlb_map_page,
+ .unmap_page = swiotlb_unmap_page,
+ .map_sg = swiotlb_map_sg_attrs,
+ .unmap_sg = swiotlb_unmap_sg_attrs,
+ .sync_single_for_cpu = swiotlb_sync_single_for_cpu,
+ .sync_single_for_device = swiotlb_sync_single_for_device,
+ .sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
+ .sync_sg_for_device = swiotlb_sync_sg_for_device,
+ .mapping_error = swiotlb_dma_mapping_error,
+ .dma_supported = NULL, /* FIXME: we should use this instead! */
+};
+
+/* At setup time, we use our own ops if the device is a ConneXt one */
+static void sta2x11_setup_pdev(struct pci_dev *pdev)
+{
+ struct sta2x11_instance *instance = sta2x11_pdev_to_instance(pdev);
+
+ if (!instance) /* either a sta2x11 bridge or another ST device */
+ return;
+ pci_set_consistent_dma_mask(pdev, STA2X11_AMBA_SIZE - 1);
+ pci_set_dma_mask(pdev, STA2X11_AMBA_SIZE - 1);
+ pdev->dev.archdata.dma_ops = &sta2x11_dma_ops;
+
+ /* We must enable all devices as master, for audio DMA to work */
+ pci_set_master(pdev);
+}
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, sta2x11_setup_pdev);
+
+/*
+ * The following three functions are exported (used in swiotlb: FIXME)
+ */
+/**
+ * dma_capable - Check if device can manage DMA transfers (FIXME: kill it)
+ * @dev: device for a PCI device
+ * @addr: DMA address
+ * @size: DMA size
+ */
+bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
+{
+ struct sta2x11_mapping *map;
+
+ if (dev->archdata.dma_ops != &sta2x11_dma_ops) {
+ if (!dev->dma_mask)
+ return false;
+ return addr + size - 1 <= *dev->dma_mask;
+ }
+
+ map = sta2x11_pdev_to_mapping(to_pci_dev(dev));
+
+ if (!map || (addr < map->amba_base))
+ return false;
+ if (addr + size >= map->amba_base + STA2X11_AMBA_SIZE) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * phys_to_dma - Return the DMA AMBA address used for this STA2x11 device
+ * @dev: device for a PCI device
+ * @paddr: Physical address
+ */
+dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
+{
+ if (dev->archdata.dma_ops != &sta2x11_dma_ops)
+ return paddr;
+ return p2a(paddr, to_pci_dev(dev));
+}
+
+/**
+ * dma_to_phys - Return the physical address used for this STA2x11 DMA address
+ * @dev: device for a PCI device
+ * @daddr: STA2x11 AMBA DMA address
+ */
+phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr)
+{
+ if (dev->archdata.dma_ops != &sta2x11_dma_ops)
+ return daddr;
+ return a2p(daddr, to_pci_dev(dev));
+}
+
+
+/*
+ * At boot we must set up the mappings for the pcie-to-amba bridge.
+ * It involves device access, and the same happens at suspend/resume time
+ */
+
+#define AHB_MAPB 0xCA4
+#define AHB_CRW(i) (AHB_MAPB + 0 + (i) * 0x10)
+#define AHB_CRW_SZMASK 0xfffffc00UL
+#define AHB_CRW_ENABLE (1 << 0)
+#define AHB_CRW_WTYPE_MEM (2 << 1)
+#define AHB_CRW_ROE (1UL << 3) /* Relax Order Ena */
+#define AHB_CRW_NSE (1UL << 4) /* No Snoop Enable */
+#define AHB_BASE(i) (AHB_MAPB + 4 + (i) * 0x10)
+#define AHB_PEXLBASE(i) (AHB_MAPB + 8 + (i) * 0x10)
+#define AHB_PEXHBASE(i) (AHB_MAPB + 12 + (i) * 0x10)
+
+/* At probe time, enable mapping for each endpoint, using the pdev */
+static void sta2x11_map_ep(struct pci_dev *pdev)
+{
+ struct sta2x11_mapping *map = sta2x11_pdev_to_mapping(pdev);
+ int i;
+
+ if (!map)
+ return;
+ pci_read_config_dword(pdev, AHB_BASE(0), &map->amba_base);
+
+ /* Configure AHB mapping */
+ pci_write_config_dword(pdev, AHB_PEXLBASE(0), 0);
+ pci_write_config_dword(pdev, AHB_PEXHBASE(0), 0);
+ pci_write_config_dword(pdev, AHB_CRW(0), STA2X11_AMBA_SIZE |
+ AHB_CRW_WTYPE_MEM | AHB_CRW_ENABLE);
+
+ /* Disable all the other windows */
+ for (i = 1; i < STA2X11_NR_FUNCS; i++)
+ pci_write_config_dword(pdev, AHB_CRW(i), 0);
+
+ dev_info(&pdev->dev,
+ "sta2x11: Map EP %i: AMBA address %#8x-%#8x\n",
+ sta2x11_pdev_to_ep(pdev), map->amba_base,
+ map->amba_base + STA2X11_AMBA_SIZE - 1);
+}
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, sta2x11_map_ep);
+
+#ifdef CONFIG_PM /* Some register values must be saved and restored */
+
+static void suspend_mapping(struct pci_dev *pdev)
+{
+ struct sta2x11_mapping *map = sta2x11_pdev_to_mapping(pdev);
+ int i;
+
+ if (!map)
+ return;
+
+ if (map->is_suspended)
+ return;
+ map->is_suspended = 1;
+
+ /* Save all window configs */
+ for (i = 0; i < STA2X11_NR_FUNCS; i++) {
+ struct sta2x11_ahb_regs *regs = map->regs + i;
+
+ pci_read_config_dword(pdev, AHB_BASE(i), &regs->base);
+ pci_read_config_dword(pdev, AHB_PEXLBASE(i), &regs->pexlbase);
+ pci_read_config_dword(pdev, AHB_PEXHBASE(i), &regs->pexhbase);
+ pci_read_config_dword(pdev, AHB_CRW(i), &regs->crw);
+ }
+}
+DECLARE_PCI_FIXUP_SUSPEND(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, suspend_mapping);
+
+static void resume_mapping(struct pci_dev *pdev)
+{
+ struct sta2x11_mapping *map = sta2x11_pdev_to_mapping(pdev);
+ int i;
+
+ if (!map)
+ return;
+
+
+ if (!map->is_suspended)
+ goto out;
+ map->is_suspended = 0;
+
+ /* Restore all window configs */
+ for (i = 0; i < STA2X11_NR_FUNCS; i++) {
+ struct sta2x11_ahb_regs *regs = map->regs + i;
+
+ pci_write_config_dword(pdev, AHB_BASE(i), regs->base);
+ pci_write_config_dword(pdev, AHB_PEXLBASE(i), regs->pexlbase);
+ pci_write_config_dword(pdev, AHB_PEXHBASE(i), regs->pexhbase);
+ pci_write_config_dword(pdev, AHB_CRW(i), regs->crw);
+ }
+out:
+ pci_set_master(pdev); /* Like at boot, enable master on all devices */
+}
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_STMICRO, PCI_ANY_ID, resume_mapping);
+
+#endif /* CONFIG_PM */
diff --git a/arch/x86/platform/olpc/olpc-xo1-sci.c b/arch/x86/platform/olpc/olpc-xo1-sci.c
index 1d4c783d7325..04b8c73659c5 100644
--- a/arch/x86/platform/olpc/olpc-xo1-sci.c
+++ b/arch/x86/platform/olpc/olpc-xo1-sci.c
@@ -18,6 +18,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
+#include <linux/pm_wakeup.h>
#include <linux/mfd/core.h>
#include <linux/power_supply.h>
#include <linux/suspend.h>
@@ -83,8 +84,12 @@ static void send_ebook_state(void)
return;
}
+ if (!!test_bit(SW_TABLET_MODE, ebook_switch_idev->sw) == state)
+ return; /* Nothing new to report. */
+
input_report_switch(ebook_switch_idev, SW_TABLET_MODE, state);
input_sync(ebook_switch_idev);
+ pm_wakeup_event(&ebook_switch_idev->dev, 0);
}
static void flip_lid_inverter(void)
@@ -123,8 +128,12 @@ static void detect_lid_state(void)
/* Report current lid switch state through input layer */
static void send_lid_state(void)
{
+ if (!!test_bit(SW_LID, lid_switch_idev->sw) == !lid_open)
+ return; /* Nothing new to report. */
+
input_report_switch(lid_switch_idev, SW_LID, !lid_open);
input_sync(lid_switch_idev);
+ pm_wakeup_event(&lid_switch_idev->dev, 0);
}
static ssize_t lid_wake_mode_show(struct device *dev,
@@ -213,11 +222,30 @@ static irqreturn_t xo1_sci_intr(int irq, void *dev_id)
dev_dbg(&pdev->dev, "sts %x gpe %x\n", sts, gpe);
- if (sts & CS5536_PWRBTN_FLAG && !(sts & CS5536_WAK_FLAG)) {
- input_report_key(power_button_idev, KEY_POWER, 1);
- input_sync(power_button_idev);
- input_report_key(power_button_idev, KEY_POWER, 0);
- input_sync(power_button_idev);
+ if (sts & CS5536_PWRBTN_FLAG) {
+ if (!(sts & CS5536_WAK_FLAG)) {
+ /* Only report power button input when it was pressed
+ * during regular operation (as opposed to when it
+ * was used to wake the system). */
+ input_report_key(power_button_idev, KEY_POWER, 1);
+ input_sync(power_button_idev);
+ input_report_key(power_button_idev, KEY_POWER, 0);
+ input_sync(power_button_idev);
+ }
+ /* Report the wakeup event in all cases. */
+ pm_wakeup_event(&power_button_idev->dev, 0);
+ }
+
+ if ((sts & (CS5536_RTC_FLAG | CS5536_WAK_FLAG)) ==
+ (CS5536_RTC_FLAG | CS5536_WAK_FLAG)) {
+ /* When the system is woken by the RTC alarm, report the
+ * event on the rtc device. */
+ struct device *rtc = bus_find_device_by_name(
+ &platform_bus_type, NULL, "rtc_cmos");
+ if (rtc) {
+ pm_wakeup_event(rtc, 0);
+ put_device(rtc);
+ }
}
if (gpe & CS5536_GPIOM7_PME_FLAG) { /* EC GPIO */
@@ -310,9 +338,10 @@ static int __devinit setup_sci_interrupt(struct platform_device *pdev)
outb(lo, CS5536_PIC_INT_SEL2);
}
- /* Enable SCI from power button, and clear pending interrupts */
+ /* Enable interesting SCI events, and clear pending interrupts */
sts = inl(acpi_base + CS5536_PM1_STS);
- outl((CS5536_PM_PWRBTN << 16) | 0xffff, acpi_base + CS5536_PM1_STS);
+ outl(((CS5536_PM_PWRBTN | CS5536_PM_RTC) << 16) | 0xffff,
+ acpi_base + CS5536_PM1_STS);
r = request_irq(sci_irq, xo1_sci_intr, 0, DRV_NAME, pdev);
if (r)
diff --git a/arch/x86/platform/visws/visws_quirks.c b/arch/x86/platform/visws/visws_quirks.c
index c7abf13a213f..94d8a39332ec 100644
--- a/arch/x86/platform/visws/visws_quirks.c
+++ b/arch/x86/platform/visws/visws_quirks.c
@@ -445,7 +445,7 @@ static void ack_cobalt_irq(struct irq_data *data)
spin_lock_irqsave(&cobalt_lock, flags);
disable_cobalt_irq(data);
- apic_write(APIC_EOI, APIC_EIO_ACK);
+ apic_write(APIC_EOI, APIC_EOI_ACK);
spin_unlock_irqrestore(&cobalt_lock, flags);
}
diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
index b43cfcd9bf40..b685296d4464 100644
--- a/arch/x86/tools/relocs.c
+++ b/arch/x86/tools/relocs.c
@@ -60,6 +60,18 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {
"__x86_cpu_dev_(start|end)|"
"(__parainstructions|__alt_instructions)(|_end)|"
"(__iommu_table|__apicdrivers|__smp_locks)(|_end)|"
+ "__(start|end)_pci_.*|"
+ "__(start|end)_builtin_fw|"
+ "__(start|stop)___ksymtab(|_gpl|_unused|_unused_gpl|_gpl_future)|"
+ "__(start|stop)___kcrctab(|_gpl|_unused|_unused_gpl|_gpl_future)|"
+ "__(start|stop)___param|"
+ "__(start|stop)___modver|"
+ "__(start|stop)___bug_table|"
+ "__tracedata_(start|end)|"
+ "__(start|stop)_notes|"
+ "__end_rodata|"
+ "__initramfs_start|"
+ "(jiffies|jiffies_64)|"
"_end)$"
};
diff --git a/arch/x86/um/asm/elf.h b/arch/x86/um/asm/elf.h
index f3b0633b69a1..0e07adc8cbe4 100644
--- a/arch/x86/um/asm/elf.h
+++ b/arch/x86/um/asm/elf.h
@@ -34,25 +34,25 @@
#define ELF_ARCH EM_386
#define ELF_PLAT_INIT(regs, load_addr) do { \
- PT_REGS_EBX(regs) = 0; \
- PT_REGS_ECX(regs) = 0; \
- PT_REGS_EDX(regs) = 0; \
- PT_REGS_ESI(regs) = 0; \
- PT_REGS_EDI(regs) = 0; \
- PT_REGS_EBP(regs) = 0; \
- PT_REGS_EAX(regs) = 0; \
+ PT_REGS_BX(regs) = 0; \
+ PT_REGS_CX(regs) = 0; \
+ PT_REGS_DX(regs) = 0; \
+ PT_REGS_SI(regs) = 0; \
+ PT_REGS_DI(regs) = 0; \
+ PT_REGS_BP(regs) = 0; \
+ PT_REGS_AX(regs) = 0; \
} while (0)
/* Shamelessly stolen from include/asm-i386/elf.h */
#define ELF_CORE_COPY_REGS(pr_reg, regs) do { \
- pr_reg[0] = PT_REGS_EBX(regs); \
- pr_reg[1] = PT_REGS_ECX(regs); \
- pr_reg[2] = PT_REGS_EDX(regs); \
- pr_reg[3] = PT_REGS_ESI(regs); \
- pr_reg[4] = PT_REGS_EDI(regs); \
- pr_reg[5] = PT_REGS_EBP(regs); \
- pr_reg[6] = PT_REGS_EAX(regs); \
+ pr_reg[0] = PT_REGS_BX(regs); \
+ pr_reg[1] = PT_REGS_CX(regs); \
+ pr_reg[2] = PT_REGS_DX(regs); \
+ pr_reg[3] = PT_REGS_SI(regs); \
+ pr_reg[4] = PT_REGS_DI(regs); \
+ pr_reg[5] = PT_REGS_BP(regs); \
+ pr_reg[6] = PT_REGS_AX(regs); \
pr_reg[7] = PT_REGS_DS(regs); \
pr_reg[8] = PT_REGS_ES(regs); \
/* fake once used fs and gs selectors? */ \
@@ -130,13 +130,13 @@ do { \
#define ELF_ARCH EM_X86_64
#define ELF_PLAT_INIT(regs, load_addr) do { \
- PT_REGS_RBX(regs) = 0; \
- PT_REGS_RCX(regs) = 0; \
- PT_REGS_RDX(regs) = 0; \
- PT_REGS_RSI(regs) = 0; \
- PT_REGS_RDI(regs) = 0; \
- PT_REGS_RBP(regs) = 0; \
- PT_REGS_RAX(regs) = 0; \
+ PT_REGS_BX(regs) = 0; \
+ PT_REGS_CX(regs) = 0; \
+ PT_REGS_DX(regs) = 0; \
+ PT_REGS_SI(regs) = 0; \
+ PT_REGS_DI(regs) = 0; \
+ PT_REGS_BP(regs) = 0; \
+ PT_REGS_AX(regs) = 0; \
PT_REGS_R8(regs) = 0; \
PT_REGS_R9(regs) = 0; \
PT_REGS_R10(regs) = 0; \
diff --git a/arch/x86/um/asm/ptrace.h b/arch/x86/um/asm/ptrace.h
index c8aca8c501b0..950dfb7b8417 100644
--- a/arch/x86/um/asm/ptrace.h
+++ b/arch/x86/um/asm/ptrace.h
@@ -1,5 +1,39 @@
+#ifndef __UM_X86_PTRACE_H
+#define __UM_X86_PTRACE_H
+
#ifdef CONFIG_X86_32
# include "ptrace_32.h"
#else
# include "ptrace_64.h"
#endif
+
+#define PT_REGS_AX(r) UPT_AX(&(r)->regs)
+#define PT_REGS_BX(r) UPT_BX(&(r)->regs)
+#define PT_REGS_CX(r) UPT_CX(&(r)->regs)
+#define PT_REGS_DX(r) UPT_DX(&(r)->regs)
+
+#define PT_REGS_SI(r) UPT_SI(&(r)->regs)
+#define PT_REGS_DI(r) UPT_DI(&(r)->regs)
+#define PT_REGS_BP(r) UPT_BP(&(r)->regs)
+#define PT_REGS_EFLAGS(r) UPT_EFLAGS(&(r)->regs)
+
+#define PT_REGS_CS(r) UPT_CS(&(r)->regs)
+#define PT_REGS_SS(r) UPT_SS(&(r)->regs)
+#define PT_REGS_DS(r) UPT_DS(&(r)->regs)
+#define PT_REGS_ES(r) UPT_ES(&(r)->regs)
+
+#define PT_REGS_ORIG_SYSCALL(r) PT_REGS_AX(r)
+#define PT_REGS_SYSCALL_RET(r) PT_REGS_AX(r)
+
+#define PT_FIX_EXEC_STACK(sp) do ; while(0)
+
+#define profile_pc(regs) PT_REGS_IP(regs)
+
+#define UPT_RESTART_SYSCALL(r) (UPT_IP(r) -= 2)
+#define UPT_SET_SYSCALL_RETURN(r, res) (UPT_AX(r) = (res))
+
+static inline long regs_return_value(struct uml_pt_regs *regs)
+{
+ return UPT_AX(regs);
+}
+#endif /* __UM_X86_PTRACE_H */
diff --git a/arch/x86/um/asm/ptrace_32.h b/arch/x86/um/asm/ptrace_32.h
index 5d2a59112537..2cf225351b65 100644
--- a/arch/x86/um/asm/ptrace_32.h
+++ b/arch/x86/um/asm/ptrace_32.h
@@ -11,29 +11,6 @@
#include "linux/compiler.h"
#include "asm/ptrace-generic.h"
-#define PT_REGS_EAX(r) UPT_EAX(&(r)->regs)
-#define PT_REGS_EBX(r) UPT_EBX(&(r)->regs)
-#define PT_REGS_ECX(r) UPT_ECX(&(r)->regs)
-#define PT_REGS_EDX(r) UPT_EDX(&(r)->regs)
-#define PT_REGS_ESI(r) UPT_ESI(&(r)->regs)
-#define PT_REGS_EDI(r) UPT_EDI(&(r)->regs)
-#define PT_REGS_EBP(r) UPT_EBP(&(r)->regs)
-
-#define PT_REGS_CS(r) UPT_CS(&(r)->regs)
-#define PT_REGS_SS(r) UPT_SS(&(r)->regs)
-#define PT_REGS_DS(r) UPT_DS(&(r)->regs)
-#define PT_REGS_ES(r) UPT_ES(&(r)->regs)
-#define PT_REGS_FS(r) UPT_FS(&(r)->regs)
-#define PT_REGS_GS(r) UPT_GS(&(r)->regs)
-
-#define PT_REGS_EFLAGS(r) UPT_EFLAGS(&(r)->regs)
-
-#define PT_REGS_ORIG_SYSCALL(r) PT_REGS_EAX(r)
-#define PT_REGS_SYSCALL_RET(r) PT_REGS_EAX(r)
-#define PT_FIX_EXEC_STACK(sp) do ; while(0)
-
-#define profile_pc(regs) PT_REGS_IP(regs)
-
#define user_mode(r) UPT_IS_USER(&(r)->regs)
/*
diff --git a/arch/x86/um/asm/ptrace_64.h b/arch/x86/um/asm/ptrace_64.h
index 706a0d80545c..ea7bff394320 100644
--- a/arch/x86/um/asm/ptrace_64.h
+++ b/arch/x86/um/asm/ptrace_64.h
@@ -15,13 +15,6 @@
#define HOST_AUDIT_ARCH AUDIT_ARCH_X86_64
-#define PT_REGS_RBX(r) UPT_RBX(&(r)->regs)
-#define PT_REGS_RCX(r) UPT_RCX(&(r)->regs)
-#define PT_REGS_RDX(r) UPT_RDX(&(r)->regs)
-#define PT_REGS_RSI(r) UPT_RSI(&(r)->regs)
-#define PT_REGS_RDI(r) UPT_RDI(&(r)->regs)
-#define PT_REGS_RBP(r) UPT_RBP(&(r)->regs)
-#define PT_REGS_RAX(r) UPT_RAX(&(r)->regs)
#define PT_REGS_R8(r) UPT_R8(&(r)->regs)
#define PT_REGS_R9(r) UPT_R9(&(r)->regs)
#define PT_REGS_R10(r) UPT_R10(&(r)->regs)
@@ -31,27 +24,8 @@
#define PT_REGS_R14(r) UPT_R14(&(r)->regs)
#define PT_REGS_R15(r) UPT_R15(&(r)->regs)
-#define PT_REGS_FS(r) UPT_FS(&(r)->regs)
-#define PT_REGS_GS(r) UPT_GS(&(r)->regs)
-#define PT_REGS_DS(r) UPT_DS(&(r)->regs)
-#define PT_REGS_ES(r) UPT_ES(&(r)->regs)
-#define PT_REGS_SS(r) UPT_SS(&(r)->regs)
-#define PT_REGS_CS(r) UPT_CS(&(r)->regs)
-
-#define PT_REGS_ORIG_RAX(r) UPT_ORIG_RAX(&(r)->regs)
-#define PT_REGS_RIP(r) UPT_IP(&(r)->regs)
-#define PT_REGS_SP(r) UPT_SP(&(r)->regs)
-
-#define PT_REGS_EFLAGS(r) UPT_EFLAGS(&(r)->regs)
-
/* XXX */
#define user_mode(r) UPT_IS_USER(&(r)->regs)
-#define PT_REGS_ORIG_SYSCALL(r) PT_REGS_RAX(r)
-#define PT_REGS_SYSCALL_RET(r) PT_REGS_RAX(r)
-
-#define PT_FIX_EXEC_STACK(sp) do ; while(0)
-
-#define profile_pc(regs) PT_REGS_IP(regs)
struct user_desc;
diff --git a/arch/x86/um/checksum_32.S b/arch/x86/um/checksum_32.S
index f058d2f82e18..8d0c420465cc 100644
--- a/arch/x86/um/checksum_32.S
+++ b/arch/x86/um/checksum_32.S
@@ -26,6 +26,7 @@
*/
#include <asm/errno.h>
+#include <asm/asm.h>
/*
* computes a partial checksum, e.g. for TCP/UDP fragments
@@ -232,15 +233,11 @@ unsigned int csum_partial_copy_generic (const char *src, char *dst,
#define SRC(y...) \
9999: y; \
- .section __ex_table, "a"; \
- .long 9999b, 6001f ; \
- .previous
+ _ASM_EXTABLE(9999b, 6001f)
#define DST(y...) \
9999: y; \
- .section __ex_table, "a"; \
- .long 9999b, 6002f ; \
- .previous
+ _ASM_EXTABLE(9999b, 6002f)
.align 4
diff --git a/arch/x86/um/shared/sysdep/ptrace.h b/arch/x86/um/shared/sysdep/ptrace.h
index 2bbe1ec2d96a..6ce2d76eb908 100644
--- a/arch/x86/um/shared/sysdep/ptrace.h
+++ b/arch/x86/um/shared/sysdep/ptrace.h
@@ -1,15 +1,74 @@
#ifndef __SYSDEP_X86_PTRACE_H
#define __SYSDEP_X86_PTRACE_H
+#include <generated/user_constants.h>
+#include "sysdep/faultinfo.h"
+
+#define MAX_REG_OFFSET (UM_FRAME_SIZE)
+#define MAX_REG_NR ((MAX_REG_OFFSET) / sizeof(unsigned long))
+
+#define REGS_IP(r) ((r)[HOST_IP])
+#define REGS_SP(r) ((r)[HOST_SP])
+#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS])
+#define REGS_AX(r) ((r)[HOST_AX])
+#define REGS_BX(r) ((r)[HOST_BX])
+#define REGS_CX(r) ((r)[HOST_CX])
+#define REGS_DX(r) ((r)[HOST_DX])
+#define REGS_SI(r) ((r)[HOST_SI])
+#define REGS_DI(r) ((r)[HOST_DI])
+#define REGS_BP(r) ((r)[HOST_BP])
+#define REGS_CS(r) ((r)[HOST_CS])
+#define REGS_SS(r) ((r)[HOST_SS])
+#define REGS_DS(r) ((r)[HOST_DS])
+#define REGS_ES(r) ((r)[HOST_ES])
+
+#define UPT_IP(r) REGS_IP((r)->gp)
+#define UPT_SP(r) REGS_SP((r)->gp)
+#define UPT_EFLAGS(r) REGS_EFLAGS((r)->gp)
+#define UPT_AX(r) REGS_AX((r)->gp)
+#define UPT_BX(r) REGS_BX((r)->gp)
+#define UPT_CX(r) REGS_CX((r)->gp)
+#define UPT_DX(r) REGS_DX((r)->gp)
+#define UPT_SI(r) REGS_SI((r)->gp)
+#define UPT_DI(r) REGS_DI((r)->gp)
+#define UPT_BP(r) REGS_BP((r)->gp)
+#define UPT_CS(r) REGS_CS((r)->gp)
+#define UPT_SS(r) REGS_SS((r)->gp)
+#define UPT_DS(r) REGS_DS((r)->gp)
+#define UPT_ES(r) REGS_ES((r)->gp)
+
#ifdef __i386__
#include "ptrace_32.h"
#else
#include "ptrace_64.h"
#endif
-static inline long regs_return_value(struct uml_pt_regs *regs)
-{
- return UPT_SYSCALL_RET(regs);
-}
+struct syscall_args {
+ unsigned long args[6];
+};
+
+#define SYSCALL_ARGS(r) ((struct syscall_args) \
+ { .args = { UPT_SYSCALL_ARG1(r), \
+ UPT_SYSCALL_ARG2(r), \
+ UPT_SYSCALL_ARG3(r), \
+ UPT_SYSCALL_ARG4(r), \
+ UPT_SYSCALL_ARG5(r), \
+ UPT_SYSCALL_ARG6(r) } } )
+
+struct uml_pt_regs {
+ unsigned long gp[MAX_REG_NR];
+ unsigned long fp[MAX_FP_NR];
+ struct faultinfo faultinfo;
+ long syscall;
+ int is_user;
+};
+
+#define EMPTY_UML_PT_REGS { }
+
+#define UPT_SYSCALL_NR(r) ((r)->syscall)
+#define UPT_FAULTINFO(r) (&(r)->faultinfo)
+#define UPT_IS_USER(r) ((r)->is_user)
+
+extern int user_context(unsigned long sp);
#endif /* __SYSDEP_X86_PTRACE_H */
diff --git a/arch/x86/um/shared/sysdep/ptrace_32.h b/arch/x86/um/shared/sysdep/ptrace_32.h
index befd1df32ed0..b94a108de1dc 100644
--- a/arch/x86/um/shared/sysdep/ptrace_32.h
+++ b/arch/x86/um/shared/sysdep/ptrace_32.h
@@ -6,11 +6,7 @@
#ifndef __SYSDEP_I386_PTRACE_H
#define __SYSDEP_I386_PTRACE_H
-#include <generated/user_constants.h>
-#include "sysdep/faultinfo.h"
-
-#define MAX_REG_NR (UM_FRAME_SIZE / sizeof(unsigned long))
-#define MAX_REG_OFFSET (UM_FRAME_SIZE)
+#define MAX_FP_NR HOST_FPX_SIZE
static inline void update_debugregs(int seq) {}
@@ -24,90 +20,16 @@ void set_using_sysemu(int value);
int get_using_sysemu(void);
extern int sysemu_supported;
-#define REGS_IP(r) ((r)[HOST_IP])
-#define REGS_SP(r) ((r)[HOST_SP])
-#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS])
-#define REGS_EAX(r) ((r)[HOST_AX])
-#define REGS_EBX(r) ((r)[HOST_BX])
-#define REGS_ECX(r) ((r)[HOST_CX])
-#define REGS_EDX(r) ((r)[HOST_DX])
-#define REGS_ESI(r) ((r)[HOST_SI])
-#define REGS_EDI(r) ((r)[HOST_DI])
-#define REGS_EBP(r) ((r)[HOST_BP])
-#define REGS_CS(r) ((r)[HOST_CS])
-#define REGS_SS(r) ((r)[HOST_SS])
-#define REGS_DS(r) ((r)[HOST_DS])
-#define REGS_ES(r) ((r)[HOST_ES])
-#define REGS_FS(r) ((r)[HOST_FS])
-#define REGS_GS(r) ((r)[HOST_GS])
-
-#define REGS_SET_SYSCALL_RETURN(r, res) REGS_EAX(r) = (res)
-
-#define IP_RESTART_SYSCALL(ip) ((ip) -= 2)
-#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r))
-
#ifndef PTRACE_SYSEMU_SINGLESTEP
#define PTRACE_SYSEMU_SINGLESTEP 32
#endif
-struct uml_pt_regs {
- unsigned long gp[MAX_REG_NR];
- unsigned long fp[HOST_FPX_SIZE];
- struct faultinfo faultinfo;
- long syscall;
- int is_user;
-};
-
-#define EMPTY_UML_PT_REGS { }
-
-#define UPT_IP(r) REGS_IP((r)->gp)
-#define UPT_SP(r) REGS_SP((r)->gp)
-#define UPT_EFLAGS(r) REGS_EFLAGS((r)->gp)
-#define UPT_EAX(r) REGS_EAX((r)->gp)
-#define UPT_EBX(r) REGS_EBX((r)->gp)
-#define UPT_ECX(r) REGS_ECX((r)->gp)
-#define UPT_EDX(r) REGS_EDX((r)->gp)
-#define UPT_ESI(r) REGS_ESI((r)->gp)
-#define UPT_EDI(r) REGS_EDI((r)->gp)
-#define UPT_EBP(r) REGS_EBP((r)->gp)
-#define UPT_ORIG_EAX(r) ((r)->syscall)
-#define UPT_CS(r) REGS_CS((r)->gp)
-#define UPT_SS(r) REGS_SS((r)->gp)
-#define UPT_DS(r) REGS_DS((r)->gp)
-#define UPT_ES(r) REGS_ES((r)->gp)
-#define UPT_FS(r) REGS_FS((r)->gp)
-#define UPT_GS(r) REGS_GS((r)->gp)
-
-#define UPT_SYSCALL_ARG1(r) UPT_EBX(r)
-#define UPT_SYSCALL_ARG2(r) UPT_ECX(r)
-#define UPT_SYSCALL_ARG3(r) UPT_EDX(r)
-#define UPT_SYSCALL_ARG4(r) UPT_ESI(r)
-#define UPT_SYSCALL_ARG5(r) UPT_EDI(r)
-#define UPT_SYSCALL_ARG6(r) UPT_EBP(r)
-
-extern int user_context(unsigned long sp);
-
-#define UPT_IS_USER(r) ((r)->is_user)
-
-struct syscall_args {
- unsigned long args[6];
-};
-
-#define SYSCALL_ARGS(r) ((struct syscall_args) \
- { .args = { UPT_SYSCALL_ARG1(r), \
- UPT_SYSCALL_ARG2(r), \
- UPT_SYSCALL_ARG3(r), \
- UPT_SYSCALL_ARG4(r), \
- UPT_SYSCALL_ARG5(r), \
- UPT_SYSCALL_ARG6(r) } } )
-
-#define UPT_RESTART_SYSCALL(r) REGS_RESTART_SYSCALL((r)->gp)
-
-#define UPT_ORIG_SYSCALL(r) UPT_EAX(r)
-#define UPT_SYSCALL_NR(r) UPT_ORIG_EAX(r)
-#define UPT_SYSCALL_RET(r) UPT_EAX(r)
-
-#define UPT_FAULTINFO(r) (&(r)->faultinfo)
+#define UPT_SYSCALL_ARG1(r) UPT_BX(r)
+#define UPT_SYSCALL_ARG2(r) UPT_CX(r)
+#define UPT_SYSCALL_ARG3(r) UPT_DX(r)
+#define UPT_SYSCALL_ARG4(r) UPT_SI(r)
+#define UPT_SYSCALL_ARG5(r) UPT_DI(r)
+#define UPT_SYSCALL_ARG6(r) UPT_BP(r)
extern void arch_init_registers(int pid);
diff --git a/arch/x86/um/shared/sysdep/ptrace_64.h b/arch/x86/um/shared/sysdep/ptrace_64.h
index 031edc53ac57..919789f1071e 100644
--- a/arch/x86/um/shared/sysdep/ptrace_64.h
+++ b/arch/x86/um/shared/sysdep/ptrace_64.h
@@ -8,22 +8,8 @@
#ifndef __SYSDEP_X86_64_PTRACE_H
#define __SYSDEP_X86_64_PTRACE_H
-#include <generated/user_constants.h>
-#include "sysdep/faultinfo.h"
+#define MAX_FP_NR HOST_FP_SIZE
-#define MAX_REG_OFFSET (UM_FRAME_SIZE)
-#define MAX_REG_NR ((MAX_REG_OFFSET) / sizeof(unsigned long))
-
-#define REGS_IP(r) ((r)[HOST_IP])
-#define REGS_SP(r) ((r)[HOST_SP])
-
-#define REGS_RBX(r) ((r)[HOST_BX])
-#define REGS_RCX(r) ((r)[HOST_CX])
-#define REGS_RDX(r) ((r)[HOST_DX])
-#define REGS_RSI(r) ((r)[HOST_SI])
-#define REGS_RDI(r) ((r)[HOST_DI])
-#define REGS_RBP(r) ((r)[HOST_BP])
-#define REGS_RAX(r) ((r)[HOST_AX])
#define REGS_R8(r) ((r)[HOST_R8])
#define REGS_R9(r) ((r)[HOST_R9])
#define REGS_R10(r) ((r)[HOST_R10])
@@ -32,9 +18,6 @@
#define REGS_R13(r) ((r)[HOST_R13])
#define REGS_R14(r) ((r)[HOST_R14])
#define REGS_R15(r) ((r)[HOST_R15])
-#define REGS_CS(r) ((r)[HOST_CS])
-#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS])
-#define REGS_SS(r) ((r)[HOST_SS])
#define HOST_FS_BASE 21
#define HOST_GS_BASE 22
@@ -58,45 +41,6 @@
#define GS (HOST_GS * sizeof(long))
#endif
-#define REGS_FS_BASE(r) ((r)[HOST_FS_BASE])
-#define REGS_GS_BASE(r) ((r)[HOST_GS_BASE])
-#define REGS_DS(r) ((r)[HOST_DS])
-#define REGS_ES(r) ((r)[HOST_ES])
-#define REGS_FS(r) ((r)[HOST_FS])
-#define REGS_GS(r) ((r)[HOST_GS])
-
-#define REGS_ORIG_RAX(r) ((r)[HOST_ORIG_AX])
-
-#define REGS_SET_SYSCALL_RETURN(r, res) REGS_RAX(r) = (res)
-
-#define IP_RESTART_SYSCALL(ip) ((ip) -= 2)
-#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r))
-
-#define REGS_FAULT_ADDR(r) ((r)->fault_addr)
-
-#define REGS_FAULT_WRITE(r) FAULT_WRITE((r)->fault_type)
-
-#define REGS_TRAP(r) ((r)->trap_type)
-
-#define REGS_ERR(r) ((r)->fault_type)
-
-struct uml_pt_regs {
- unsigned long gp[MAX_REG_NR];
- unsigned long fp[HOST_FP_SIZE];
- struct faultinfo faultinfo;
- long syscall;
- int is_user;
-};
-
-#define EMPTY_UML_PT_REGS { }
-
-#define UPT_RBX(r) REGS_RBX((r)->gp)
-#define UPT_RCX(r) REGS_RCX((r)->gp)
-#define UPT_RDX(r) REGS_RDX((r)->gp)
-#define UPT_RSI(r) REGS_RSI((r)->gp)
-#define UPT_RDI(r) REGS_RDI((r)->gp)
-#define UPT_RBP(r) REGS_RBP((r)->gp)
-#define UPT_RAX(r) REGS_RAX((r)->gp)
#define UPT_R8(r) REGS_R8((r)->gp)
#define UPT_R9(r) REGS_R9((r)->gp)
#define UPT_R10(r) REGS_R10((r)->gp)
@@ -105,51 +49,14 @@ struct uml_pt_regs {
#define UPT_R13(r) REGS_R13((r)->gp)
#define UPT_R14(r) REGS_R14((r)->gp)
#define UPT_R15(r) REGS_R15((r)->gp)
-#define UPT_CS(r) REGS_CS((r)->gp)
-#define UPT_FS_BASE(r) REGS_FS_BASE((r)->gp)
-#define UPT_FS(r) REGS_FS((r)->gp)
-#define UPT_GS_BASE(r) REGS_GS_BASE((r)->gp)
-#define UPT_GS(r) REGS_GS((r)->gp)
-#define UPT_DS(r) REGS_DS((r)->gp)
-#define UPT_ES(r) REGS_ES((r)->gp)
-#define UPT_CS(r) REGS_CS((r)->gp)
-#define UPT_SS(r) REGS_SS((r)->gp)
-#define UPT_ORIG_RAX(r) REGS_ORIG_RAX((r)->gp)
-
-#define UPT_IP(r) REGS_IP((r)->gp)
-#define UPT_SP(r) REGS_SP((r)->gp)
-
-#define UPT_EFLAGS(r) REGS_EFLAGS((r)->gp)
-#define UPT_SYSCALL_NR(r) ((r)->syscall)
-#define UPT_SYSCALL_RET(r) UPT_RAX(r)
-
-extern int user_context(unsigned long sp);
-#define UPT_IS_USER(r) ((r)->is_user)
-
-#define UPT_SYSCALL_ARG1(r) UPT_RDI(r)
-#define UPT_SYSCALL_ARG2(r) UPT_RSI(r)
-#define UPT_SYSCALL_ARG3(r) UPT_RDX(r)
+#define UPT_SYSCALL_ARG1(r) UPT_DI(r)
+#define UPT_SYSCALL_ARG2(r) UPT_SI(r)
+#define UPT_SYSCALL_ARG3(r) UPT_DX(r)
#define UPT_SYSCALL_ARG4(r) UPT_R10(r)
#define UPT_SYSCALL_ARG5(r) UPT_R8(r)
#define UPT_SYSCALL_ARG6(r) UPT_R9(r)
-struct syscall_args {
- unsigned long args[6];
-};
-
-#define SYSCALL_ARGS(r) ((struct syscall_args) \
- { .args = { UPT_SYSCALL_ARG1(r), \
- UPT_SYSCALL_ARG2(r), \
- UPT_SYSCALL_ARG3(r), \
- UPT_SYSCALL_ARG4(r), \
- UPT_SYSCALL_ARG5(r), \
- UPT_SYSCALL_ARG6(r) } } )
-
-#define UPT_RESTART_SYSCALL(r) REGS_RESTART_SYSCALL((r)->gp)
-
-#define UPT_FAULTINFO(r) (&(r)->faultinfo)
-
static inline void arch_init_registers(int pid)
{
}
diff --git a/arch/x86/um/signal.c b/arch/x86/um/signal.c
index 4883b9546016..bb0fb03b9f85 100644
--- a/arch/x86/um/signal.c
+++ b/arch/x86/um/signal.c
@@ -156,6 +156,9 @@ static int copy_sc_from_user(struct pt_regs *regs,
struct sigcontext sc;
int err, pid;
+ /* Always make any pending restarted system calls return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
err = copy_from_user(&sc, from, sizeof(sc));
if (err)
return err;
@@ -410,9 +413,9 @@ int setup_signal_stack_sc(unsigned long stack_top, int sig,
PT_REGS_SP(regs) = (unsigned long) frame;
PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler;
- PT_REGS_EAX(regs) = (unsigned long) sig;
- PT_REGS_EDX(regs) = (unsigned long) 0;
- PT_REGS_ECX(regs) = (unsigned long) 0;
+ PT_REGS_AX(regs) = (unsigned long) sig;
+ PT_REGS_DX(regs) = (unsigned long) 0;
+ PT_REGS_CX(regs) = (unsigned long) 0;
if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
ptrace_notify(SIGTRAP);
@@ -460,9 +463,9 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
PT_REGS_SP(regs) = (unsigned long) frame;
PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler;
- PT_REGS_EAX(regs) = (unsigned long) sig;
- PT_REGS_EDX(regs) = (unsigned long) &frame->info;
- PT_REGS_ECX(regs) = (unsigned long) &frame->uc;
+ PT_REGS_AX(regs) = (unsigned long) sig;
+ PT_REGS_DX(regs) = (unsigned long) &frame->info;
+ PT_REGS_CX(regs) = (unsigned long) &frame->uc;
if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED))
ptrace_notify(SIGTRAP);
@@ -541,8 +544,8 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
set->sig[0]);
err |= __put_user(&frame->fpstate, &frame->uc.uc_mcontext.fpstate);
if (sizeof(*set) == 16) {
- __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
- __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]);
+ err |= __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
+ err |= __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]);
}
else
err |= __copy_to_user(&frame->uc.uc_sigmask, set,
@@ -570,17 +573,17 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
}
PT_REGS_SP(regs) = (unsigned long) frame;
- PT_REGS_RDI(regs) = sig;
+ PT_REGS_DI(regs) = sig;
/* In case the signal handler was declared without prototypes */
- PT_REGS_RAX(regs) = 0;
+ PT_REGS_AX(regs) = 0;
/*
* This also works for non SA_SIGINFO handlers because they expect the
* next argument after the signal number on the stack.
*/
- PT_REGS_RSI(regs) = (unsigned long) &frame->info;
- PT_REGS_RDX(regs) = (unsigned long) &frame->uc;
- PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler;
+ PT_REGS_SI(regs) = (unsigned long) &frame->info;
+ PT_REGS_DX(regs) = (unsigned long) &frame->uc;
+ PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler;
out:
return err;
}
diff --git a/arch/x86/um/sys_call_table_64.c b/arch/x86/um/sys_call_table_64.c
index 9924776f4265..170bd926a69c 100644
--- a/arch/x86/um/sys_call_table_64.c
+++ b/arch/x86/um/sys_call_table_64.c
@@ -31,7 +31,6 @@
#define stub_fork sys_fork
#define stub_vfork sys_vfork
#define stub_execve sys_execve
-#define stub_rt_sigsuspend sys_rt_sigsuspend
#define stub_sigaltstack sys_sigaltstack
#define stub_rt_sigreturn sys_rt_sigreturn
diff --git a/arch/x86/um/syscalls_32.c b/arch/x86/um/syscalls_32.c
index 70ca357393b8..b853e8600b9d 100644
--- a/arch/x86/um/syscalls_32.c
+++ b/arch/x86/um/syscalls_32.c
@@ -44,10 +44,10 @@ long sys_sigaction(int sig, const struct old_sigaction __user *act,
old_sigset_t mask;
if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
__get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) ||
+ __get_user(new_ka.sa.sa_flags, &act->sa_flags) ||
+ __get_user(mask, &act->sa_mask))
return -EFAULT;
- __get_user(new_ka.sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
siginitset(&new_ka.sa.sa_mask, mask);
}
@@ -56,10 +56,10 @@ long sys_sigaction(int sig, const struct old_sigaction __user *act,
if (!ret && oact) {
if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
__put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) ||
+ __put_user(old_ka.sa.sa_flags, &oact->sa_flags) ||
+ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask))
return -EFAULT;
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
}
return ret;
diff --git a/arch/x86/um/sysrq_32.c b/arch/x86/um/sysrq_32.c
index 171b3e9dc867..2d5cc51e9bef 100644
--- a/arch/x86/um/sysrq_32.c
+++ b/arch/x86/um/sysrq_32.c
@@ -23,12 +23,10 @@ void show_regs(struct pt_regs *regs)
printk(" EFLAGS: %08lx\n %s\n", PT_REGS_EFLAGS(regs),
print_tainted());
printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
- PT_REGS_EAX(regs), PT_REGS_EBX(regs),
- PT_REGS_ECX(regs),
- PT_REGS_EDX(regs));
+ PT_REGS_AX(regs), PT_REGS_BX(regs),
+ PT_REGS_CX(regs), PT_REGS_DX(regs));
printk("ESI: %08lx EDI: %08lx EBP: %08lx",
- PT_REGS_ESI(regs), PT_REGS_EDI(regs),
- PT_REGS_EBP(regs));
+ PT_REGS_SI(regs), PT_REGS_DI(regs), PT_REGS_BP(regs));
printk(" DS: %04lx ES: %04lx\n",
0xffff & PT_REGS_DS(regs),
0xffff & PT_REGS_ES(regs));
diff --git a/arch/x86/um/sysrq_64.c b/arch/x86/um/sysrq_64.c
index e8913436d7dc..08258f179969 100644
--- a/arch/x86/um/sysrq_64.c
+++ b/arch/x86/um/sysrq_64.c
@@ -19,15 +19,15 @@ void __show_regs(struct pt_regs *regs)
printk(KERN_INFO "Pid: %d, comm: %.20s %s %s\n", task_pid_nr(current),
current->comm, print_tainted(), init_utsname()->release);
printk(KERN_INFO "RIP: %04lx:[<%016lx>]\n", PT_REGS_CS(regs) & 0xffff,
- PT_REGS_RIP(regs));
+ PT_REGS_IP(regs));
printk(KERN_INFO "RSP: %016lx EFLAGS: %08lx\n", PT_REGS_SP(regs),
PT_REGS_EFLAGS(regs));
printk(KERN_INFO "RAX: %016lx RBX: %016lx RCX: %016lx\n",
- PT_REGS_RAX(regs), PT_REGS_RBX(regs), PT_REGS_RCX(regs));
+ PT_REGS_AX(regs), PT_REGS_BX(regs), PT_REGS_CX(regs));
printk(KERN_INFO "RDX: %016lx RSI: %016lx RDI: %016lx\n",
- PT_REGS_RDX(regs), PT_REGS_RSI(regs), PT_REGS_RDI(regs));
+ PT_REGS_DX(regs), PT_REGS_SI(regs), PT_REGS_DI(regs));
printk(KERN_INFO "RBP: %016lx R08: %016lx R09: %016lx\n",
- PT_REGS_RBP(regs), PT_REGS_R8(regs), PT_REGS_R9(regs));
+ PT_REGS_BP(regs), PT_REGS_R8(regs), PT_REGS_R9(regs));
printk(KERN_INFO "R10: %016lx R11: %016lx R12: %016lx\n",
PT_REGS_R10(regs), PT_REGS_R11(regs), PT_REGS_R12(regs));
printk(KERN_INFO "R13: %016lx R14: %016lx R15: %016lx\n",
diff --git a/arch/x86/um/tls_32.c b/arch/x86/um/tls_32.c
index c6c7131e563b..baba84f8ecb8 100644
--- a/arch/x86/um/tls_32.c
+++ b/arch/x86/um/tls_32.c
@@ -219,7 +219,7 @@ int arch_copy_tls(struct task_struct *new)
int idx, ret = -EFAULT;
if (copy_from_user(&info,
- (void __user *) UPT_ESI(&new->thread.regs.regs),
+ (void __user *) UPT_SI(&new->thread.regs.regs),
sizeof(info)))
goto out;
diff --git a/arch/x86/video/fbdev.c b/arch/x86/video/fbdev.c
index c5ffb6ac8707..d5644bbe8cba 100644
--- a/arch/x86/video/fbdev.c
+++ b/arch/x86/video/fbdev.c
@@ -9,24 +9,34 @@
#include <linux/fb.h>
#include <linux/pci.h>
#include <linux/module.h>
+#include <linux/vgaarb.h>
int fb_is_primary_device(struct fb_info *info)
{
struct device *device = info->device;
struct pci_dev *pci_dev = NULL;
+ struct pci_dev *default_device = vga_default_device();
struct resource *res = NULL;
- int retval = 0;
if (device)
pci_dev = to_pci_dev(device);
- if (pci_dev)
- res = &pci_dev->resource[PCI_ROM_RESOURCE];
+ if (!pci_dev)
+ return 0;
+
+ if (default_device) {
+ if (pci_dev == default_device)
+ return 1;
+ else
+ return 0;
+ }
+
+ res = &pci_dev->resource[PCI_ROM_RESOURCE];
if (res && res->flags & IORESOURCE_ROM_SHADOW)
- retval = 1;
+ return 1;
- return retval;
+ return 0;
}
EXPORT_SYMBOL(fb_is_primary_device);
MODULE_LICENSE("GPL");
diff --git a/arch/x86/xen/Makefile b/arch/x86/xen/Makefile
index add2c2d729ce..96ab2c09cb68 100644
--- a/arch/x86/xen/Makefile
+++ b/arch/x86/xen/Makefile
@@ -20,5 +20,5 @@ obj-$(CONFIG_EVENT_TRACING) += trace.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o
obj-$(CONFIG_XEN_DEBUG_FS) += debugfs.o
-obj-$(CONFIG_XEN_DOM0) += vga.o
+obj-$(CONFIG_XEN_DOM0) += apic.o vga.o
obj-$(CONFIG_SWIOTLB_XEN) += pci-swiotlb-xen.o
diff --git a/arch/x86/xen/apic.c b/arch/x86/xen/apic.c
new file mode 100644
index 000000000000..ec57bd3818a4
--- /dev/null
+++ b/arch/x86/xen/apic.c
@@ -0,0 +1,33 @@
+#include <linux/init.h>
+
+#include <asm/x86_init.h>
+#include <asm/apic.h>
+#include <asm/xen/hypercall.h>
+
+#include <xen/xen.h>
+#include <xen/interface/physdev.h>
+
+unsigned int xen_io_apic_read(unsigned apic, unsigned reg)
+{
+ struct physdev_apic apic_op;
+ int ret;
+
+ apic_op.apic_physbase = mpc_ioapic_addr(apic);
+ apic_op.reg = reg;
+ ret = HYPERVISOR_physdev_op(PHYSDEVOP_apic_read, &apic_op);
+ if (!ret)
+ return apic_op.value;
+
+ /* fallback to return an emulated IO_APIC values */
+ if (reg == 0x1)
+ return 0x00170020;
+ else if (reg == 0x0)
+ return apic << 24;
+
+ return 0xfd;
+}
+
+void __init xen_init_apic(void)
+{
+ x86_io_apic_ops.read = xen_io_apic_read;
+}
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 95dccce8e979..c0f5facdb10c 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1396,6 +1396,8 @@ asmlinkage void __init xen_start_kernel(void)
xen_start_info->console.domU.mfn = 0;
xen_start_info->console.domU.evtchn = 0;
+ xen_init_apic();
+
/* Make sure ACS will be enabled */
pci_request_acs();
}
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 69f5857660ac..3506cd4f9a43 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -1864,7 +1864,6 @@ pgd_t * __init xen_setup_kernel_pagetable(pgd_t *pgd,
#endif /* CONFIG_X86_64 */
static unsigned char dummy_mapping[PAGE_SIZE] __page_aligned_bss;
-static unsigned char fake_ioapic_mapping[PAGE_SIZE] __page_aligned_bss;
static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
{
@@ -1905,7 +1904,7 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
* We just don't map the IO APIC - all access is via
* hypercalls. Keep the address in the pte for reference.
*/
- pte = pfn_pte(PFN_DOWN(__pa(fake_ioapic_mapping)), PAGE_KERNEL);
+ pte = pfn_pte(PFN_DOWN(__pa(dummy_mapping)), PAGE_KERNEL);
break;
#endif
@@ -2070,7 +2069,6 @@ void __init xen_init_mmu_ops(void)
pv_mmu_ops = xen_mmu_ops;
memset(dummy_mapping, 0xff, PAGE_SIZE);
- memset(fake_ioapic_mapping, 0xfd, PAGE_SIZE);
}
/* Protected by xen_reservation_lock. */
diff --git a/arch/x86/xen/xen-asm_32.S b/arch/x86/xen/xen-asm_32.S
index b040b0e518ca..f9643fc50de5 100644
--- a/arch/x86/xen/xen-asm_32.S
+++ b/arch/x86/xen/xen-asm_32.S
@@ -14,6 +14,7 @@
#include <asm/thread_info.h>
#include <asm/processor-flags.h>
#include <asm/segment.h>
+#include <asm/asm.h>
#include <xen/interface/xen.h>
@@ -137,10 +138,7 @@ iret_restore_end:
1: iret
xen_iret_end_crit:
-.section __ex_table, "a"
- .align 4
- .long 1b, iret_exc
-.previous
+ _ASM_EXTABLE(1b, iret_exc)
hyper_iret:
/* put this out of line since its very rarely used */
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index b095739ccd4c..45c0c0667bd9 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -92,11 +92,15 @@ struct dom0_vga_console_info;
#ifdef CONFIG_XEN_DOM0
void __init xen_init_vga(const struct dom0_vga_console_info *, size_t size);
+void __init xen_init_apic(void);
#else
static inline void __init xen_init_vga(const struct dom0_vga_console_info *info,
size_t size)
{
}
+static inline void __init xen_init_apic(void)
+{
+}
#endif
/* Declare an asm function, along with symbols needed to make it
diff --git a/arch/xtensa/include/asm/gpio.h b/arch/xtensa/include/asm/gpio.h
index a8c9fc46c790..b3799d88ffcf 100644
--- a/arch/xtensa/include/asm/gpio.h
+++ b/arch/xtensa/include/asm/gpio.h
@@ -1,56 +1,4 @@
-/*
- * Generic GPIO API implementation for xtensa.
- *
- * Stolen from x86, which is derived from the generic GPIO API for powerpc:
- *
- * Copyright (c) 2007-2008 MontaVista Software, Inc.
- *
- * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef _ASM_XTENSA_GPIO_H
-#define _ASM_XTENSA_GPIO_H
-
-#include <asm-generic/gpio.h>
-
-#ifdef CONFIG_GPIOLIB
-
-/*
- * Just call gpiolib.
- */
-static inline int gpio_get_value(unsigned int gpio)
-{
- return __gpio_get_value(gpio);
-}
-
-static inline void gpio_set_value(unsigned int gpio, int value)
-{
- __gpio_set_value(gpio, value);
-}
-
-static inline int gpio_cansleep(unsigned int gpio)
-{
- return __gpio_cansleep(gpio);
-}
-
-static inline int gpio_to_irq(unsigned int gpio)
-{
- return __gpio_to_irq(gpio);
-}
-
-/*
- * Not implemented, yet.
- */
-static inline int irq_to_gpio(unsigned int irq)
-{
- return -EINVAL;
-}
-
-#endif /* CONFIG_GPIOLIB */
-
-#endif /* _ASM_XTENSA_GPIO_H */
+#ifndef __LINUX_GPIO_H
+#warning Include linux/gpio.h instead of asm/gpio.h
+#include <linux/gpio.h>
+#endif
diff --git a/arch/xtensa/include/asm/processor.h b/arch/xtensa/include/asm/processor.h
index 3acb26e8dead..5c371d8d4528 100644
--- a/arch/xtensa/include/asm/processor.h
+++ b/arch/xtensa/include/asm/processor.h
@@ -168,9 +168,6 @@ struct mm_struct;
/* Free all resources held by a thread. */
#define release_thread(thread) do { } while(0)
-/* Prepare to copy thread state - unlazy all lazy status */
-extern void prepare_to_copy(struct task_struct*);
-
/* Create a kernel thread without removing it from tasklists */
extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
diff --git a/arch/xtensa/include/asm/signal.h b/arch/xtensa/include/asm/signal.h
index 633ba73bc4d2..7f201b9d4195 100644
--- a/arch/xtensa/include/asm/signal.h
+++ b/arch/xtensa/include/asm/signal.h
@@ -120,13 +120,6 @@ typedef void (*__sighandler_t)(int);
#define SIG_ERR ((__sighandler_t)-1) /* error return from signal */
#ifdef __KERNEL__
-struct old_sigaction {
- __sighandler_t sa_handler;
- old_sigset_t sa_mask;
- unsigned long sa_flags;
- void (*sa_restorer)(void);
-};
-
struct sigaction {
__sighandler_t sa_handler;
unsigned long sa_flags;
diff --git a/arch/xtensa/include/asm/syscall.h b/arch/xtensa/include/asm/syscall.h
index efcf33b92e4c..0b9f2e13c781 100644
--- a/arch/xtensa/include/asm/syscall.h
+++ b/arch/xtensa/include/asm/syscall.h
@@ -15,10 +15,6 @@ asmlinkage long xtensa_clone(unsigned long, unsigned long, struct pt_regs*);
asmlinkage long xtensa_ptrace(long, long, long, long);
asmlinkage long xtensa_sigreturn(struct pt_regs*);
asmlinkage long xtensa_rt_sigreturn(struct pt_regs*);
-asmlinkage long xtensa_sigsuspend(struct pt_regs*);
-asmlinkage long xtensa_rt_sigsuspend(struct pt_regs*);
-asmlinkage long xtensa_sigaction(int, const struct old_sigaction*,
- struct old_sigaction*);
asmlinkage long xtensa_sigaltstack(struct pt_regs *regs);
asmlinkage long sys_rt_sigaction(int,
const struct sigaction __user *,
diff --git a/arch/xtensa/include/asm/thread_info.h b/arch/xtensa/include/asm/thread_info.h
index 6abbedd09d85..81abfd5d01ac 100644
--- a/arch/xtensa/include/asm/thread_info.h
+++ b/arch/xtensa/include/asm/thread_info.h
@@ -131,6 +131,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_IRET 4 /* return with iret */
#define TIF_MEMDIE 5 /* is terminating due to OOM killer */
#define TIF_RESTORE_SIGMASK 6 /* restore signal mask in do_signal() */
+#define TIF_NOTIFY_RESUME 7 /* callback before returning to user */
#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
diff --git a/arch/xtensa/include/asm/unistd.h b/arch/xtensa/include/asm/unistd.h
index 798ee6d285a1..bc7e005faa60 100644
--- a/arch/xtensa/include/asm/unistd.h
+++ b/arch/xtensa/include/asm/unistd.h
@@ -507,7 +507,7 @@ __SYSCALL(229, sys_rt_sigtimedwait, 4)
#define __NR_rt_sigqueueinfo 230
__SYSCALL(230, sys_rt_sigqueueinfo, 3)
#define __NR_rt_sigsuspend 231
-__SYSCALL(231, xtensa_rt_sigsuspend, 2)
+__SYSCALL(231, sys_rt_sigsuspend, 2)
/* Message */
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
index 6223f3346b5c..7e6236073397 100644
--- a/arch/xtensa/kernel/entry.S
+++ b/arch/xtensa/kernel/entry.S
@@ -409,16 +409,16 @@ common_exception_return:
l32i a4, a2, TI_FLAGS
_bbsi.l a4, TIF_NEED_RESCHED, 3f
+ _bbsi.l a4, TIF_NOTIFY_RESUME, 2f
_bbci.l a4, TIF_SIGPENDING, 4f
- l32i a4, a1, PT_DEPC
+2: l32i a4, a1, PT_DEPC
bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 4f
/* Call do_signal() */
- movi a4, do_signal # int do_signal(struct pt_regs*, sigset_t*)
+ movi a4, do_notify_resume # int do_notify_resume(struct pt_regs*)
mov a6, a1
- movi a7, 0
callx4 a4
j 1b
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
index 6a2d6edf8f72..9b306e550e3f 100644
--- a/arch/xtensa/kernel/process.c
+++ b/arch/xtensa/kernel/process.c
@@ -140,13 +140,16 @@ void flush_thread(void)
}
/*
- * This is called before the thread is copied.
+ * this gets called so that we can store coprocessor state into memory and
+ * copy the current task into the new thread.
*/
-void prepare_to_copy(struct task_struct *tsk)
+int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
{
#if XTENSA_HAVE_COPROCESSORS
- coprocessor_flush_all(task_thread_info(tsk));
+ coprocessor_flush_all(task_thread_info(src));
#endif
+ *dst = *src;
+ return 0;
}
/*
diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c
index d78869a00b11..c5e4ec0598d2 100644
--- a/arch/xtensa/kernel/signal.c
+++ b/arch/xtensa/kernel/signal.c
@@ -20,6 +20,7 @@
#include <linux/ptrace.h>
#include <linux/personality.h>
#include <linux/freezer.h>
+#include <linux/tracehook.h>
#include <asm/ucontext.h>
#include <asm/uaccess.h>
@@ -31,8 +32,6 @@
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
-
extern struct task_struct *coproc_owners[];
struct rt_sigframe
@@ -248,6 +247,9 @@ asmlinkage long xtensa_rt_sigreturn(long a0, long a1, long a2, long a3,
sigset_t set;
int ret;
+ /* Always make any pending restarted system calls return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
if (regs->depc > 64)
panic("rt_sigreturn in double exception!\n");
@@ -426,37 +428,6 @@ give_sigsegv:
return -EFAULT;
}
-/*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-
-asmlinkage long xtensa_rt_sigsuspend(sigset_t __user *unewset,
- size_t sigsetsize,
- long a2, long a3, long a4, long a5,
- struct pt_regs *regs)
-{
- sigset_t saveset, newset;
-
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(sigset_t))
- return -EINVAL;
-
- if (copy_from_user(&newset, unewset, sizeof(newset)))
- return -EFAULT;
-
- sigdelsetmask(&newset, ~_BLOCKABLE);
- saveset = current->blocked;
- set_current_blocked(&newset);
-
- regs->areg[2] = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (do_signal(regs, &saveset))
- return -EINTR;
- }
-}
-
asmlinkage long xtensa_sigaltstack(const stack_t __user *uss,
stack_t __user *uoss,
long a2, long a3, long a4, long a5,
@@ -476,19 +447,19 @@ asmlinkage long xtensa_sigaltstack(const stack_t __user *uss,
* the kernel can handle, and then we build all the user-level signal handling
* stack-frames in one go after that.
*/
-int do_signal(struct pt_regs *regs, sigset_t *oldset)
+static void do_signal(struct pt_regs *regs)
{
siginfo_t info;
int signr;
struct k_sigaction ka;
-
- if (!user_mode(regs))
- return 0;
+ sigset_t oldset;
if (try_to_freeze())
goto no_signal;
- if (!oldset)
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = &current->saved_sigmask;
+ else
oldset = &current->blocked;
task_pt_regs(current)->icountlevel = 0;
@@ -532,13 +503,14 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
/* Set up the stack frame */
ret = setup_frame(signr, &ka, &info, oldset, regs);
if (ret)
- return ret;
+ return;
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
block_sigmask(&ka, signr);
if (current->ptrace & PT_SINGLESTEP)
task_pt_regs(current)->icountlevel = 1;
- return 1;
+ return;
}
no_signal:
@@ -558,8 +530,27 @@ no_signal:
break;
}
}
+
+ /* If there's no signal to deliver, we just restore the saved mask. */
+ if (test_and_clear_thread_flag(TIF_RESTORE_SIGMASK))
+ set_current_blocked(&current->saved_sigmask);
+
if (current->ptrace & PT_SINGLESTEP)
task_pt_regs(current)->icountlevel = 1;
- return 0;
+ return;
}
+void do_notify_resume(struct pt_regs *regs)
+{
+ if (!user_mode(regs))
+ return;
+
+ if (test_thread_flag(TIF_SIGPENDING))
+ do_signal(regs);
+
+ if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) {
+ tracehook_notify_resume(regs);
+ if (current->replacement_session_keyring)
+ key_replace_session_keyring();
+ }
+}
diff --git a/arch/xtensa/variants/s6000/dmac.c b/arch/xtensa/variants/s6000/dmac.c
index dc7f7c573518..340f5bb0b5ef 100644
--- a/arch/xtensa/variants/s6000/dmac.c
+++ b/arch/xtensa/variants/s6000/dmac.c
@@ -1,5 +1,5 @@
/*
- * Authors: Oskar Schirmer <os@emlix.com>
+ * Authors: Oskar Schirmer <oskar@scara.com>
* Daniel Gloeckner <dg@emlix.com>
* (c) 2008 emlix GmbH http://www.emlix.com
*
diff --git a/arch/xtensa/variants/s6000/gpio.c b/arch/xtensa/variants/s6000/gpio.c
index 7af0757e001b..b89541ba39ab 100644
--- a/arch/xtensa/variants/s6000/gpio.c
+++ b/arch/xtensa/variants/s6000/gpio.c
@@ -2,8 +2,8 @@
* s6000 gpio driver
*
* Copyright (c) 2009 emlix GmbH
- * Authors: Oskar Schirmer <os@emlix.com>
- * Johannes Weiner <jw@emlix.com>
+ * Authors: Oskar Schirmer <oskar@scara.com>
+ * Johannes Weiner <hannes@cmpxchg.org>
* Daniel Gloeckner <dg@emlix.com>
*/
#include <linux/bitops.h>
diff --git a/arch/xtensa/variants/s6000/include/variant/dmac.h b/arch/xtensa/variants/s6000/include/variant/dmac.h
index e81735b2a206..3f88d9fc6897 100644
--- a/arch/xtensa/variants/s6000/include/variant/dmac.h
+++ b/arch/xtensa/variants/s6000/include/variant/dmac.h
@@ -8,7 +8,7 @@
* Copyright (C) 2006 Tensilica Inc.
* Copyright (C) 2008 Emlix GmbH <info@emlix.com>
* Authors: Fabian Godehardt <fg@emlix.com>
- * Oskar Schirmer <os@emlix.com>
+ * Oskar Schirmer <oskar@scara.com>
* Daniel Gloeckner <dg@emlix.com>
*/
diff --git a/arch/xtensa/variants/s6000/irq.c b/arch/xtensa/variants/s6000/irq.c
index 6651e3285fcf..81a241e79075 100644
--- a/arch/xtensa/variants/s6000/irq.c
+++ b/arch/xtensa/variants/s6000/irq.c
@@ -2,8 +2,8 @@
* s6000 irq crossbar
*
* Copyright (c) 2009 emlix GmbH
- * Authors: Johannes Weiner <jw@emlix.com>
- * Oskar Schirmer <os@emlix.com>
+ * Authors: Johannes Weiner <hannes@cmpxchg.org>
+ * Oskar Schirmer <oskar@scara.com>
*/
#include <linux/io.h>
#include <asm/irq.h>
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index ea84a23d5e68..126c341955de 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -28,34 +28,12 @@ static LIST_HEAD(blkio_list);
struct blkio_cgroup blkio_root_cgroup = { .weight = 2*BLKIO_WEIGHT_DEFAULT };
EXPORT_SYMBOL_GPL(blkio_root_cgroup);
-static struct cgroup_subsys_state *blkiocg_create(struct cgroup *);
-static int blkiocg_can_attach(struct cgroup *, struct cgroup_taskset *);
-static void blkiocg_attach(struct cgroup *, struct cgroup_taskset *);
-static void blkiocg_destroy(struct cgroup *);
-static int blkiocg_populate(struct cgroup_subsys *, struct cgroup *);
-
/* for encoding cft->private value on file */
#define BLKIOFILE_PRIVATE(x, val) (((x) << 16) | (val))
/* What policy owns the file, proportional or throttle */
#define BLKIOFILE_POLICY(val) (((val) >> 16) & 0xffff)
#define BLKIOFILE_ATTR(val) ((val) & 0xffff)
-struct cgroup_subsys blkio_subsys = {
- .name = "blkio",
- .create = blkiocg_create,
- .can_attach = blkiocg_can_attach,
- .attach = blkiocg_attach,
- .destroy = blkiocg_destroy,
- .populate = blkiocg_populate,
-#ifdef CONFIG_BLK_CGROUP
- /* note: blkio_subsys_id is otherwise defined in blk-cgroup.h */
- .subsys_id = blkio_subsys_id,
-#endif
- .use_id = 1,
- .module = THIS_MODULE,
-};
-EXPORT_SYMBOL_GPL(blkio_subsys);
-
static inline void blkio_policy_insert_node(struct blkio_cgroup *blkcg,
struct blkio_policy_node *pn)
{
@@ -1537,14 +1515,9 @@ struct cftype blkio_files[] = {
.read_map = blkiocg_file_read_map,
},
#endif
+ { } /* terminate */
};
-static int blkiocg_populate(struct cgroup_subsys *subsys, struct cgroup *cgroup)
-{
- return cgroup_add_files(cgroup, subsys, blkio_files,
- ARRAY_SIZE(blkio_files));
-}
-
static void blkiocg_destroy(struct cgroup *cgroup)
{
struct blkio_cgroup *blkcg = cgroup_to_blkio_cgroup(cgroup);
@@ -1658,6 +1631,22 @@ static void blkiocg_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
}
}
+struct cgroup_subsys blkio_subsys = {
+ .name = "blkio",
+ .create = blkiocg_create,
+ .can_attach = blkiocg_can_attach,
+ .attach = blkiocg_attach,
+ .destroy = blkiocg_destroy,
+#ifdef CONFIG_BLK_CGROUP
+ /* note: blkio_subsys_id is otherwise defined in blk-cgroup.h */
+ .subsys_id = blkio_subsys_id,
+#endif
+ .base_cftypes = blkio_files,
+ .use_id = 1,
+ .module = THIS_MODULE,
+};
+EXPORT_SYMBOL_GPL(blkio_subsys);
+
void blkio_policy_register(struct blkio_policy_type *blkiop)
{
spin_lock(&blkio_list_lock);
diff --git a/crypto/xor.c b/crypto/xor.c
index b75182d8ab14..65c7b416b4a3 100644
--- a/crypto/xor.c
+++ b/crypto/xor.c
@@ -21,6 +21,7 @@
#include <linux/gfp.h>
#include <linux/raid/xor.h>
#include <linux/jiffies.h>
+#include <linux/preempt.h>
#include <asm/xor.h>
/* The xor routines to use. */
@@ -63,12 +64,14 @@ static void
do_xor_speed(struct xor_block_template *tmpl, void *b1, void *b2)
{
int speed;
- unsigned long now;
+ unsigned long now, j;
int i, count, max;
tmpl->next = template_list;
template_list = tmpl;
+ preempt_disable();
+
/*
* Count the number of XORs done during a whole jiffy, and use
* this to calculate the speed of checksumming. We use a 2-page
@@ -76,9 +79,11 @@ do_xor_speed(struct xor_block_template *tmpl, void *b1, void *b2)
*/
max = 0;
for (i = 0; i < 5; i++) {
- now = jiffies;
+ j = jiffies;
count = 0;
- while (jiffies == now) {
+ while ((now = jiffies) == j)
+ cpu_relax();
+ while (time_before(jiffies, now + 1)) {
mb(); /* prevent loop optimzation */
tmpl->do_2(BENCH_SIZE, b1, b2);
mb();
@@ -89,6 +94,8 @@ do_xor_speed(struct xor_block_template *tmpl, void *b1, void *b2)
max = count;
}
+ preempt_enable();
+
speed = max * (HZ * BENCH_SIZE / 1024);
tmpl->speed = speed;
@@ -129,9 +136,9 @@ calibrate_xor_blocks(void)
if (fastest) {
printk(KERN_INFO "xor: automatically using best "
- "checksumming function: %s\n",
- fastest->name);
+ "checksumming function:\n");
xor_speed(fastest);
+ goto out;
} else {
printk(KERN_INFO "xor: measuring software checksum speed\n");
XOR_TRY_TEMPLATES;
@@ -146,6 +153,7 @@ calibrate_xor_blocks(void)
#undef xor_speed
+ out:
free_pages((unsigned long)b1, 2);
active_template = fastest;
diff --git a/drivers/Kconfig b/drivers/Kconfig
index d236aef7e59f..bfc918633fd9 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -140,4 +140,12 @@ source "drivers/virt/Kconfig"
source "drivers/devfreq/Kconfig"
+source "drivers/extcon/Kconfig"
+
+source "drivers/memory/Kconfig"
+
+source "drivers/iio/Kconfig"
+
+source "drivers/vme/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 95952c82bf16..0ee98d50f975 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -92,7 +92,6 @@ obj-$(CONFIG_BT) += bluetooth/
obj-$(CONFIG_ACCESSIBILITY) += accessibility/
obj-$(CONFIG_ISDN) += isdn/
obj-$(CONFIG_EDAC) += edac/
-obj-$(CONFIG_MCA) += mca/
obj-$(CONFIG_EISA) += eisa/
obj-y += lguest/
obj-$(CONFIG_CPU_FREQ) += cpufreq/
@@ -134,3 +133,7 @@ obj-$(CONFIG_VIRT_DRIVERS) += virt/
obj-$(CONFIG_HYPERV) += hv/
obj-$(CONFIG_PM_DEVFREQ) += devfreq/
+obj-$(CONFIG_EXTCON) += extcon/
+obj-$(CONFIG_MEMORY) += memory/
+obj-$(CONFIG_IIO) += iio/
+obj-$(CONFIG_VME_BUS) += vme/
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 29a4a5c8ee00..1564e0927c21 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -69,6 +69,7 @@ static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type)
up_read(&bus_type_sem);
return ret;
}
+EXPORT_SYMBOL_GPL(register_acpi_bus_type);
static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle)
{
@@ -85,6 +86,7 @@ static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle)
up_read(&bus_type_sem);
return ret;
}
+EXPORT_SYMBOL_GPL(unregister_acpi_bus_type);
/* Get device's handler per its address under its parent */
struct acpi_find_child {
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 4a29763b8eb4..a12808259dfb 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -720,21 +720,21 @@ static int acpi_pci_link_add(struct acpi_device *device)
acpi_device_bid(device));
for (i = 0; i < link->irq.possible_count; i++) {
if (link->irq.active == link->irq.possible[i]) {
- printk(" *%d", link->irq.possible[i]);
+ printk(KERN_CONT " *%d", link->irq.possible[i]);
found = 1;
} else
- printk(" %d", link->irq.possible[i]);
+ printk(KERN_CONT " %d", link->irq.possible[i]);
}
- printk(")");
+ printk(KERN_CONT ")");
if (!found)
- printk(" *%d", link->irq.active);
+ printk(KERN_CONT " *%d", link->irq.active);
if (!link->device->status.enabled)
- printk(", disabled.");
+ printk(KERN_CONT ", disabled.");
- printk("\n");
+ printk(KERN_CONT "\n");
list_add_tail(&link->list, &acpi_link_list);
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index eb6fd233764b..06527c526618 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -887,7 +887,7 @@ int __init acpi_sleep_init(void)
status = acpi_get_sleep_type_data(i, &type_a, &type_b);
if (ACPI_SUCCESS(status)) {
sleep_states[i] = 1;
- printk(" S%d", i);
+ printk(KERN_CONT " S%d", i);
}
}
@@ -901,7 +901,7 @@ int __init acpi_sleep_init(void)
hibernation_set_ops(old_suspend_ordering ?
&acpi_hibernation_ops_old : &acpi_hibernation_ops);
sleep_states[ACPI_STATE_S4] = 1;
- printk(" S4");
+ printk(KERN_CONT " S4");
if (!nosigcheck) {
acpi_get_table(ACPI_SIG_FACS, 1,
(struct acpi_table_header **)&facs);
@@ -914,11 +914,11 @@ int __init acpi_sleep_init(void)
status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
if (ACPI_SUCCESS(status)) {
sleep_states[ACPI_STATE_S5] = 1;
- printk(" S5");
+ printk(KERN_CONT " S5");
pm_power_off_prepare = acpi_power_off_prepare;
pm_power_off = acpi_power_off;
}
- printk(")\n");
+ printk(KERN_CONT ")\n");
/*
* Register the tts_notifier to reboot notifier list so that the _TTS
* object can also be evaluated when the system enters S5.
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index b002a471c5d4..adbbc1c80a26 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -382,3 +382,33 @@ acpi_evaluate_reference(acpi_handle handle,
}
EXPORT_SYMBOL(acpi_evaluate_reference);
+
+acpi_status
+acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld *pld)
+{
+ acpi_status status;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *output;
+
+ status = acpi_evaluate_object(handle, "_PLD", NULL, &buffer);
+
+ if (ACPI_FAILURE(status))
+ return status;
+
+ output = buffer.pointer;
+
+ if (!output || output->type != ACPI_TYPE_PACKAGE
+ || !output->package.count
+ || output->package.elements[0].type != ACPI_TYPE_BUFFER
+ || output->package.elements[0].buffer.length > sizeof(*pld)) {
+ status = AE_TYPE;
+ goto out;
+ }
+
+ memcpy(pld, output->package.elements[0].buffer.pointer,
+ output->package.elements[0].buffer.length);
+out:
+ kfree(buffer.pointer);
+ return status;
+}
+EXPORT_SYMBOL(acpi_get_physical_device_location);
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 6bdedd7cca2c..2be8ef1d3093 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -416,6 +416,15 @@ config PATA_EFAR
If unsure, say N.
+config PATA_EP93XX
+ tristate "Cirrus Logic EP93xx PATA support"
+ depends on ARCH_EP93XX
+ help
+ This option enables support for the PATA controller in
+ the Cirrus Logic EP9312 and EP9315 ARM CPU.
+
+ If unsure, say N.
+
config PATA_HPT366
tristate "HPT 366/368 PATA support"
depends on PCI
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 6ece5b7231a3..a454a139b1d2 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_PATA_CS5535) += pata_cs5535.o
obj-$(CONFIG_PATA_CS5536) += pata_cs5536.o
obj-$(CONFIG_PATA_CYPRESS) += pata_cypress.o
obj-$(CONFIG_PATA_EFAR) += pata_efar.o
+obj-$(CONFIG_PATA_EP93XX) += pata_ep93xx.o
obj-$(CONFIG_PATA_HPT366) += pata_hpt366.o
obj-$(CONFIG_PATA_HPT37X) += pata_hpt37x.o
obj-$(CONFIG_PATA_HPT3X2N) += pata_hpt3x2n.o
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index 7df56ec31819..aae115600b74 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -177,7 +177,7 @@ static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id
if ((id->driver_data & ATA_GEN_CLASS_MATCH) && all_generic_ide == 0)
return -ENODEV;
- if (id->driver_data & ATA_GEN_INTEL_IDER)
+ if ((id->driver_data & ATA_GEN_INTEL_IDER) && !all_generic_ide)
if (!is_intel_ider(dev))
return -ENODEV;
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 7857e8fd0a3e..3c809bfbccf5 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -1554,6 +1554,39 @@ static bool piix_broken_system_poweroff(struct pci_dev *pdev)
return false;
}
+static int prefer_ms_hyperv = 1;
+module_param(prefer_ms_hyperv, int, 0);
+
+static void piix_ignore_devices_quirk(struct ata_host *host)
+{
+#if IS_ENABLED(CONFIG_HYPERV_STORAGE)
+ static const struct dmi_system_id ignore_hyperv[] = {
+ {
+ /* On Hyper-V hypervisors the disks are exposed on
+ * both the emulated SATA controller and on the
+ * paravirtualised drivers. The CD/DVD devices
+ * are only exposed on the emulated controller.
+ * Request we ignore ATA devices on this host.
+ */
+ .ident = "Hyper-V Virtual Machine",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR,
+ "Microsoft Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Virtual Machine"),
+ },
+ },
+ { } /* terminate list */
+ };
+ const struct dmi_system_id *dmi = dmi_first_match(ignore_hyperv);
+
+ if (dmi && prefer_ms_hyperv) {
+ host->flags |= ATA_HOST_IGNORE_ATA;
+ dev_info(host->dev, "%s detected, ATA device ignore set\n",
+ dmi->ident);
+ }
+#endif
+}
+
/**
* piix_init_one - Register PIIX ATA PCI device with kernel services
* @pdev: PCI device to register
@@ -1669,6 +1702,9 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
}
host->flags |= ATA_HOST_PARALLEL_SCAN;
+ /* Allow hosts to specify device types to ignore when scanning. */
+ piix_ignore_devices_quirk(host);
+
pci_set_master(pdev);
return ata_pci_sff_activate_host(host, ata_bmdma_interrupt, sht);
}
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 23763a1ec570..cece3a4d11ea 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -1973,6 +1973,12 @@ retry:
if (class == ATA_DEV_ATA) {
if (!ata_id_is_ata(id) && !ata_id_is_cfa(id))
goto err_out;
+ if (ap->host->flags & ATA_HOST_IGNORE_ATA &&
+ ata_id_is_ata(id)) {
+ ata_dev_dbg(dev,
+ "host indicates ignore ATA devices, ignored\n");
+ return -ENOENT;
+ }
} else {
if (ata_id_is_ata(id))
goto err_out;
@@ -4051,6 +4057,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "_NEC DV5800A", NULL, ATA_HORKAGE_NODMA },
{ "SAMSUNG CD-ROM SN-124", "N001", ATA_HORKAGE_NODMA },
{ "Seagate STT20000A", NULL, ATA_HORKAGE_NODMA },
+ { "2GB ATA Flash Disk", "ADMA428M", ATA_HORKAGE_NODMA },
/* Odd clown on sil3726/4726 PMPs */
{ "Config Disk", NULL, ATA_HORKAGE_DISABLE },
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index d1fbd59ead16..6d53cf9b3b6e 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -2047,6 +2047,26 @@ static unsigned int ata_eh_speed_down(struct ata_device *dev,
}
/**
+ * ata_eh_worth_retry - analyze error and decide whether to retry
+ * @qc: qc to possibly retry
+ *
+ * Look at the cause of the error and decide if a retry
+ * might be useful or not. We don't want to retry media errors
+ * because the drive itself has probably already taken 10-30 seconds
+ * doing its own internal retries before reporting the failure.
+ */
+static inline int ata_eh_worth_retry(struct ata_queued_cmd *qc)
+{
+ if (qc->flags & AC_ERR_MEDIA)
+ return 0; /* don't retry media errors */
+ if (qc->flags & ATA_QCFLAG_IO)
+ return 1; /* otherwise retry anything from fs stack */
+ if (qc->err_mask & AC_ERR_INVALID)
+ return 0; /* don't retry these */
+ return qc->err_mask != AC_ERR_DEV; /* retry if not dev error */
+}
+
+/**
* ata_eh_link_autopsy - analyze error and determine recovery action
* @link: host link to perform autopsy on
*
@@ -2120,9 +2140,7 @@ static void ata_eh_link_autopsy(struct ata_link *link)
qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER);
/* determine whether the command is worth retrying */
- if (qc->flags & ATA_QCFLAG_IO ||
- (!(qc->err_mask & AC_ERR_INVALID) &&
- qc->err_mask != AC_ERR_DEV))
+ if (ata_eh_worth_retry(qc))
qc->flags |= ATA_QCFLAG_RETRY;
/* accumulate error info */
diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c
new file mode 100644
index 000000000000..6ef2e3741f76
--- /dev/null
+++ b/drivers/ata/pata_ep93xx.c
@@ -0,0 +1,1044 @@
+/*
+ * EP93XX PATA controller driver.
+ *
+ * Copyright (c) 2012, Metasoft s.c.
+ * Rafal Prylowski <prylowski@metasoft.pl>
+ *
+ * Based on pata_scc.c, pata_icside.c and on earlier version of EP93XX
+ * PATA driver by Lennert Buytenhek and Alessandro Zummo.
+ * Read/Write timings, resource management and other improvements
+ * from driver by Joao Ramos and Bartlomiej Zolnierkiewicz.
+ * DMA engine support based on spi-ep93xx.c by Mika Westerberg.
+ *
+ * Original copyrights:
+ *
+ * Support for Cirrus Logic's EP93xx (EP9312, EP9315) CPUs
+ * PATA host controller driver.
+ *
+ * Copyright (c) 2009, Bartlomiej Zolnierkiewicz
+ *
+ * Heavily based on the ep93xx-ide.c driver:
+ *
+ * Copyright (c) 2009, Joao Ramos <joao.ramos@inov.pt>
+ * INESC Inovacao (INOV)
+ *
+ * EP93XX PATA controller driver.
+ * Copyright (C) 2007 Lennert Buytenhek <buytenh@wantstofly.org>
+ *
+ * An ATA driver for the Cirrus Logic EP93xx PATA controller.
+ *
+ * Based on an earlier version by Alessandro Zummo, which is:
+ * Copyright (C) 2006 Tower Technologies
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi_host.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/ktime.h>
+
+#include <mach/dma.h>
+#include <mach/platform.h>
+
+#define DRV_NAME "ep93xx-ide"
+#define DRV_VERSION "1.0"
+
+enum {
+ /* IDE Control Register */
+ IDECTRL = 0x00,
+ IDECTRL_CS0N = (1 << 0),
+ IDECTRL_CS1N = (1 << 1),
+ IDECTRL_DIORN = (1 << 5),
+ IDECTRL_DIOWN = (1 << 6),
+ IDECTRL_INTRQ = (1 << 9),
+ IDECTRL_IORDY = (1 << 10),
+ /*
+ * the device IDE register to be accessed is selected through
+ * IDECTRL register's specific bitfields 'DA', 'CS1N' and 'CS0N':
+ * b4 b3 b2 b1 b0
+ * A2 A1 A0 CS1N CS0N
+ * the values filled in this structure allows the value to be directly
+ * ORed to the IDECTRL register, hence giving directly the A[2:0] and
+ * CS1N/CS0N values for each IDE register.
+ * The values correspond to the transformation:
+ * ((real IDE address) << 2) | CS1N value << 1 | CS0N value
+ */
+ IDECTRL_ADDR_CMD = 0 + 2, /* CS1 */
+ IDECTRL_ADDR_DATA = (ATA_REG_DATA << 2) + 2,
+ IDECTRL_ADDR_ERROR = (ATA_REG_ERR << 2) + 2,
+ IDECTRL_ADDR_FEATURE = (ATA_REG_FEATURE << 2) + 2,
+ IDECTRL_ADDR_NSECT = (ATA_REG_NSECT << 2) + 2,
+ IDECTRL_ADDR_LBAL = (ATA_REG_LBAL << 2) + 2,
+ IDECTRL_ADDR_LBAM = (ATA_REG_LBAM << 2) + 2,
+ IDECTRL_ADDR_LBAH = (ATA_REG_LBAH << 2) + 2,
+ IDECTRL_ADDR_DEVICE = (ATA_REG_DEVICE << 2) + 2,
+ IDECTRL_ADDR_STATUS = (ATA_REG_STATUS << 2) + 2,
+ IDECTRL_ADDR_COMMAND = (ATA_REG_CMD << 2) + 2,
+ IDECTRL_ADDR_ALTSTATUS = (0x06 << 2) + 1, /* CS0 */
+ IDECTRL_ADDR_CTL = (0x06 << 2) + 1, /* CS0 */
+
+ /* IDE Configuration Register */
+ IDECFG = 0x04,
+ IDECFG_IDEEN = (1 << 0),
+ IDECFG_PIO = (1 << 1),
+ IDECFG_MDMA = (1 << 2),
+ IDECFG_UDMA = (1 << 3),
+ IDECFG_MODE_SHIFT = 4,
+ IDECFG_MODE_MASK = (0xf << 4),
+ IDECFG_WST_SHIFT = 8,
+ IDECFG_WST_MASK = (0x3 << 8),
+
+ /* MDMA Operation Register */
+ IDEMDMAOP = 0x08,
+
+ /* UDMA Operation Register */
+ IDEUDMAOP = 0x0c,
+ IDEUDMAOP_UEN = (1 << 0),
+ IDEUDMAOP_RWOP = (1 << 1),
+
+ /* PIO/MDMA/UDMA Data Registers */
+ IDEDATAOUT = 0x10,
+ IDEDATAIN = 0x14,
+ IDEMDMADATAOUT = 0x18,
+ IDEMDMADATAIN = 0x1c,
+ IDEUDMADATAOUT = 0x20,
+ IDEUDMADATAIN = 0x24,
+
+ /* UDMA Status Register */
+ IDEUDMASTS = 0x28,
+ IDEUDMASTS_DMAIDE = (1 << 16),
+ IDEUDMASTS_INTIDE = (1 << 17),
+ IDEUDMASTS_SBUSY = (1 << 18),
+ IDEUDMASTS_NDO = (1 << 24),
+ IDEUDMASTS_NDI = (1 << 25),
+ IDEUDMASTS_N4X = (1 << 26),
+
+ /* UDMA Debug Status Register */
+ IDEUDMADEBUG = 0x2c,
+};
+
+struct ep93xx_pata_data {
+ const struct platform_device *pdev;
+ void __iomem *ide_base;
+ struct ata_timing t;
+ bool iordy;
+
+ unsigned long udma_in_phys;
+ unsigned long udma_out_phys;
+
+ struct dma_chan *dma_rx_channel;
+ struct ep93xx_dma_data dma_rx_data;
+ struct dma_chan *dma_tx_channel;
+ struct ep93xx_dma_data dma_tx_data;
+};
+
+static void ep93xx_pata_clear_regs(void __iomem *base)
+{
+ writel(IDECTRL_CS0N | IDECTRL_CS1N | IDECTRL_DIORN |
+ IDECTRL_DIOWN, base + IDECTRL);
+
+ writel(0, base + IDECFG);
+ writel(0, base + IDEMDMAOP);
+ writel(0, base + IDEUDMAOP);
+ writel(0, base + IDEDATAOUT);
+ writel(0, base + IDEDATAIN);
+ writel(0, base + IDEMDMADATAOUT);
+ writel(0, base + IDEMDMADATAIN);
+ writel(0, base + IDEUDMADATAOUT);
+ writel(0, base + IDEUDMADATAIN);
+ writel(0, base + IDEUDMADEBUG);
+}
+
+static bool ep93xx_pata_check_iordy(void __iomem *base)
+{
+ return !!(readl(base + IDECTRL) & IDECTRL_IORDY);
+}
+
+/*
+ * According to EP93xx User's Guide, WST field of IDECFG specifies number
+ * of HCLK cycles to hold the data bus after a PIO write operation.
+ * It should be programmed to guarantee following delays:
+ *
+ * PIO Mode [ns]
+ * 0 30
+ * 1 20
+ * 2 15
+ * 3 10
+ * 4 5
+ *
+ * Maximum possible value for HCLK is 100MHz.
+ */
+static int ep93xx_pata_get_wst(int pio_mode)
+{
+ int val;
+
+ if (pio_mode == 0)
+ val = 3;
+ else if (pio_mode < 3)
+ val = 2;
+ else
+ val = 1;
+
+ return val << IDECFG_WST_SHIFT;
+}
+
+static void ep93xx_pata_enable_pio(void __iomem *base, int pio_mode)
+{
+ writel(IDECFG_IDEEN | IDECFG_PIO |
+ ep93xx_pata_get_wst(pio_mode) |
+ (pio_mode << IDECFG_MODE_SHIFT), base + IDECFG);
+}
+
+/*
+ * Based on delay loop found in mach-pxa/mp900.c.
+ *
+ * Single iteration should take 5 cpu cycles. This is 25ns assuming the
+ * fastest ep93xx cpu speed (200MHz) and is better optimized for PIO4 timings
+ * than eg. 20ns.
+ */
+static void ep93xx_pata_delay(unsigned long count)
+{
+ __asm__ volatile (
+ "0:\n"
+ "mov r0, r0\n"
+ "subs %0, %1, #1\n"
+ "bge 0b\n"
+ : "=r" (count)
+ : "0" (count)
+ );
+}
+
+static unsigned long ep93xx_pata_wait_for_iordy(void __iomem *base,
+ unsigned long t2)
+{
+ /*
+ * According to ATA specification, IORDY pin can be first sampled
+ * tA = 35ns after activation of DIOR-/DIOW-. Maximum IORDY pulse
+ * width is tB = 1250ns.
+ *
+ * We are already t2 delay loop iterations after activation of
+ * DIOR-/DIOW-, so we set timeout to (1250 + 35) / 25 - t2 additional
+ * delay loop iterations.
+ */
+ unsigned long start = (1250 + 35) / 25 - t2;
+ unsigned long counter = start;
+
+ while (!ep93xx_pata_check_iordy(base) && counter--)
+ ep93xx_pata_delay(1);
+ return start - counter;
+}
+
+/* common part at start of ep93xx_pata_read/write() */
+static void ep93xx_pata_rw_begin(void __iomem *base, unsigned long addr,
+ unsigned long t1)
+{
+ writel(IDECTRL_DIOWN | IDECTRL_DIORN | addr, base + IDECTRL);
+ ep93xx_pata_delay(t1);
+}
+
+/* common part at end of ep93xx_pata_read/write() */
+static void ep93xx_pata_rw_end(void __iomem *base, unsigned long addr,
+ bool iordy, unsigned long t0, unsigned long t2,
+ unsigned long t2i)
+{
+ ep93xx_pata_delay(t2);
+ /* lengthen t2 if needed */
+ if (iordy)
+ t2 += ep93xx_pata_wait_for_iordy(base, t2);
+ writel(IDECTRL_DIOWN | IDECTRL_DIORN | addr, base + IDECTRL);
+ if (t0 > t2 && t0 - t2 > t2i)
+ ep93xx_pata_delay(t0 - t2);
+ else
+ ep93xx_pata_delay(t2i);
+}
+
+static u16 ep93xx_pata_read(struct ep93xx_pata_data *drv_data,
+ unsigned long addr,
+ bool reg)
+{
+ void __iomem *base = drv_data->ide_base;
+ const struct ata_timing *t = &drv_data->t;
+ unsigned long t0 = reg ? t->cyc8b : t->cycle;
+ unsigned long t2 = reg ? t->act8b : t->active;
+ unsigned long t2i = reg ? t->rec8b : t->recover;
+
+ ep93xx_pata_rw_begin(base, addr, t->setup);
+ writel(IDECTRL_DIOWN | addr, base + IDECTRL);
+ /*
+ * The IDEDATAIN register is loaded from the DD pins at the positive
+ * edge of the DIORN signal. (EP93xx UG p27-14)
+ */
+ ep93xx_pata_rw_end(base, addr, drv_data->iordy, t0, t2, t2i);
+ return readl(base + IDEDATAIN);
+}
+
+/* IDE register read */
+static u16 ep93xx_pata_read_reg(struct ep93xx_pata_data *drv_data,
+ unsigned long addr)
+{
+ return ep93xx_pata_read(drv_data, addr, true);
+}
+
+/* PIO data read */
+static u16 ep93xx_pata_read_data(struct ep93xx_pata_data *drv_data,
+ unsigned long addr)
+{
+ return ep93xx_pata_read(drv_data, addr, false);
+}
+
+static void ep93xx_pata_write(struct ep93xx_pata_data *drv_data,
+ u16 value, unsigned long addr,
+ bool reg)
+{
+ void __iomem *base = drv_data->ide_base;
+ const struct ata_timing *t = &drv_data->t;
+ unsigned long t0 = reg ? t->cyc8b : t->cycle;
+ unsigned long t2 = reg ? t->act8b : t->active;
+ unsigned long t2i = reg ? t->rec8b : t->recover;
+
+ ep93xx_pata_rw_begin(base, addr, t->setup);
+ /*
+ * Value from IDEDATAOUT register is driven onto the DD pins when
+ * DIOWN is low. (EP93xx UG p27-13)
+ */
+ writel(value, base + IDEDATAOUT);
+ writel(IDECTRL_DIORN | addr, base + IDECTRL);
+ ep93xx_pata_rw_end(base, addr, drv_data->iordy, t0, t2, t2i);
+}
+
+/* IDE register write */
+static void ep93xx_pata_write_reg(struct ep93xx_pata_data *drv_data,
+ u16 value, unsigned long addr)
+{
+ ep93xx_pata_write(drv_data, value, addr, true);
+}
+
+/* PIO data write */
+static void ep93xx_pata_write_data(struct ep93xx_pata_data *drv_data,
+ u16 value, unsigned long addr)
+{
+ ep93xx_pata_write(drv_data, value, addr, false);
+}
+
+static void ep93xx_pata_set_piomode(struct ata_port *ap,
+ struct ata_device *adev)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+ struct ata_device *pair = ata_dev_pair(adev);
+ /*
+ * Calculate timings for the delay loop, assuming ep93xx cpu speed
+ * is 200MHz (maximum possible for ep93xx). If actual cpu speed is
+ * slower, we will wait a bit longer in each delay.
+ * Additional division of cpu speed by 5, because single iteration
+ * of our delay loop takes 5 cpu cycles (25ns).
+ */
+ unsigned long T = 1000000 / (200 / 5);
+
+ ata_timing_compute(adev, adev->pio_mode, &drv_data->t, T, 0);
+ if (pair && pair->pio_mode) {
+ struct ata_timing t;
+ ata_timing_compute(pair, pair->pio_mode, &t, T, 0);
+ ata_timing_merge(&t, &drv_data->t, &drv_data->t,
+ ATA_TIMING_SETUP | ATA_TIMING_8BIT);
+ }
+ drv_data->iordy = ata_pio_need_iordy(adev);
+
+ ep93xx_pata_enable_pio(drv_data->ide_base,
+ adev->pio_mode - XFER_PIO_0);
+}
+
+/* Note: original code is ata_sff_check_status */
+static u8 ep93xx_pata_check_status(struct ata_port *ap)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+ return ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_STATUS);
+}
+
+static u8 ep93xx_pata_check_altstatus(struct ata_port *ap)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+ return ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_ALTSTATUS);
+}
+
+/* Note: original code is ata_sff_tf_load */
+static void ep93xx_pata_tf_load(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+ unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+ if (tf->ctl != ap->last_ctl) {
+ ep93xx_pata_write_reg(drv_data, tf->ctl, IDECTRL_ADDR_CTL);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ }
+
+ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+ ep93xx_pata_write_reg(drv_data, tf->hob_feature,
+ IDECTRL_ADDR_FEATURE);
+ ep93xx_pata_write_reg(drv_data, tf->hob_nsect,
+ IDECTRL_ADDR_NSECT);
+ ep93xx_pata_write_reg(drv_data, tf->hob_lbal,
+ IDECTRL_ADDR_LBAL);
+ ep93xx_pata_write_reg(drv_data, tf->hob_lbam,
+ IDECTRL_ADDR_LBAM);
+ ep93xx_pata_write_reg(drv_data, tf->hob_lbah,
+ IDECTRL_ADDR_LBAH);
+ }
+
+ if (is_addr) {
+ ep93xx_pata_write_reg(drv_data, tf->feature,
+ IDECTRL_ADDR_FEATURE);
+ ep93xx_pata_write_reg(drv_data, tf->nsect, IDECTRL_ADDR_NSECT);
+ ep93xx_pata_write_reg(drv_data, tf->lbal, IDECTRL_ADDR_LBAL);
+ ep93xx_pata_write_reg(drv_data, tf->lbam, IDECTRL_ADDR_LBAM);
+ ep93xx_pata_write_reg(drv_data, tf->lbah, IDECTRL_ADDR_LBAH);
+ }
+
+ if (tf->flags & ATA_TFLAG_DEVICE)
+ ep93xx_pata_write_reg(drv_data, tf->device,
+ IDECTRL_ADDR_DEVICE);
+
+ ata_wait_idle(ap);
+}
+
+/* Note: original code is ata_sff_tf_read */
+static void ep93xx_pata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+ tf->command = ep93xx_pata_check_status(ap);
+ tf->feature = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_FEATURE);
+ tf->nsect = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_NSECT);
+ tf->lbal = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_LBAL);
+ tf->lbam = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_LBAM);
+ tf->lbah = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_LBAH);
+ tf->device = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_DEVICE);
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ ep93xx_pata_write_reg(drv_data, tf->ctl | ATA_HOB,
+ IDECTRL_ADDR_CTL);
+ tf->hob_feature = ep93xx_pata_read_reg(drv_data,
+ IDECTRL_ADDR_FEATURE);
+ tf->hob_nsect = ep93xx_pata_read_reg(drv_data,
+ IDECTRL_ADDR_NSECT);
+ tf->hob_lbal = ep93xx_pata_read_reg(drv_data,
+ IDECTRL_ADDR_LBAL);
+ tf->hob_lbam = ep93xx_pata_read_reg(drv_data,
+ IDECTRL_ADDR_LBAM);
+ tf->hob_lbah = ep93xx_pata_read_reg(drv_data,
+ IDECTRL_ADDR_LBAH);
+ ep93xx_pata_write_reg(drv_data, tf->ctl, IDECTRL_ADDR_CTL);
+ ap->last_ctl = tf->ctl;
+ }
+}
+
+/* Note: original code is ata_sff_exec_command */
+static void ep93xx_pata_exec_command(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+ ep93xx_pata_write_reg(drv_data, tf->command,
+ IDECTRL_ADDR_COMMAND);
+ ata_sff_pause(ap);
+}
+
+/* Note: original code is ata_sff_dev_select */
+static void ep93xx_pata_dev_select(struct ata_port *ap, unsigned int device)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+ u8 tmp = ATA_DEVICE_OBS;
+
+ if (device != 0)
+ tmp |= ATA_DEV1;
+
+ ep93xx_pata_write_reg(drv_data, tmp, IDECTRL_ADDR_DEVICE);
+ ata_sff_pause(ap); /* needed; also flushes, for mmio */
+}
+
+/* Note: original code is ata_sff_set_devctl */
+static void ep93xx_pata_set_devctl(struct ata_port *ap, u8 ctl)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+ ep93xx_pata_write_reg(drv_data, ctl, IDECTRL_ADDR_CTL);
+}
+
+/* Note: original code is ata_sff_data_xfer */
+static unsigned int ep93xx_pata_data_xfer(struct ata_device *adev,
+ unsigned char *buf,
+ unsigned int buflen, int rw)
+{
+ struct ata_port *ap = adev->link->ap;
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+ u16 *data = (u16 *)buf;
+ unsigned int words = buflen >> 1;
+
+ /* Transfer multiple of 2 bytes */
+ while (words--)
+ if (rw == READ)
+ *data++ = cpu_to_le16(
+ ep93xx_pata_read_data(
+ drv_data, IDECTRL_ADDR_DATA));
+ else
+ ep93xx_pata_write_data(drv_data, le16_to_cpu(*data++),
+ IDECTRL_ADDR_DATA);
+
+ /* Transfer trailing 1 byte, if any. */
+ if (unlikely(buflen & 0x01)) {
+ unsigned char pad[2] = { };
+
+ buf += buflen - 1;
+
+ if (rw == READ) {
+ *pad = cpu_to_le16(
+ ep93xx_pata_read_data(
+ drv_data, IDECTRL_ADDR_DATA));
+ *buf = pad[0];
+ } else {
+ pad[0] = *buf;
+ ep93xx_pata_write_data(drv_data, le16_to_cpu(*pad),
+ IDECTRL_ADDR_DATA);
+ }
+ words++;
+ }
+
+ return words << 1;
+}
+
+/* Note: original code is ata_devchk */
+static bool ep93xx_pata_device_is_present(struct ata_port *ap,
+ unsigned int device)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+ u8 nsect, lbal;
+
+ ap->ops->sff_dev_select(ap, device);
+
+ ep93xx_pata_write_reg(drv_data, 0x55, IDECTRL_ADDR_NSECT);
+ ep93xx_pata_write_reg(drv_data, 0xaa, IDECTRL_ADDR_LBAL);
+
+ ep93xx_pata_write_reg(drv_data, 0xaa, IDECTRL_ADDR_NSECT);
+ ep93xx_pata_write_reg(drv_data, 0x55, IDECTRL_ADDR_LBAL);
+
+ ep93xx_pata_write_reg(drv_data, 0x55, IDECTRL_ADDR_NSECT);
+ ep93xx_pata_write_reg(drv_data, 0xaa, IDECTRL_ADDR_LBAL);
+
+ nsect = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_NSECT);
+ lbal = ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_LBAL);
+
+ if ((nsect == 0x55) && (lbal == 0xaa))
+ return true;
+
+ return false;
+}
+
+/* Note: original code is ata_sff_wait_after_reset */
+static int ep93xx_pata_wait_after_reset(struct ata_link *link,
+ unsigned int devmask,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+ unsigned int dev0 = devmask & (1 << 0);
+ unsigned int dev1 = devmask & (1 << 1);
+ int rc, ret = 0;
+
+ ata_msleep(ap, ATA_WAIT_AFTER_RESET);
+
+ /* always check readiness of the master device */
+ rc = ata_sff_wait_ready(link, deadline);
+ /*
+ * -ENODEV means the odd clown forgot the D7 pulldown resistor
+ * and TF status is 0xff, bail out on it too.
+ */
+ if (rc)
+ return rc;
+
+ /*
+ * if device 1 was found in ata_devchk, wait for register
+ * access briefly, then wait for BSY to clear.
+ */
+ if (dev1) {
+ int i;
+
+ ap->ops->sff_dev_select(ap, 1);
+
+ /*
+ * Wait for register access. Some ATAPI devices fail
+ * to set nsect/lbal after reset, so don't waste too
+ * much time on it. We're gonna wait for !BSY anyway.
+ */
+ for (i = 0; i < 2; i++) {
+ u8 nsect, lbal;
+
+ nsect = ep93xx_pata_read_reg(drv_data,
+ IDECTRL_ADDR_NSECT);
+ lbal = ep93xx_pata_read_reg(drv_data,
+ IDECTRL_ADDR_LBAL);
+ if (nsect == 1 && lbal == 1)
+ break;
+ msleep(50); /* give drive a breather */
+ }
+
+ rc = ata_sff_wait_ready(link, deadline);
+ if (rc) {
+ if (rc != -ENODEV)
+ return rc;
+ ret = rc;
+ }
+ }
+ /* is all this really necessary? */
+ ap->ops->sff_dev_select(ap, 0);
+ if (dev1)
+ ap->ops->sff_dev_select(ap, 1);
+ if (dev0)
+ ap->ops->sff_dev_select(ap, 0);
+
+ return ret;
+}
+
+/* Note: original code is ata_bus_softreset */
+static int ep93xx_pata_bus_softreset(struct ata_port *ap, unsigned int devmask,
+ unsigned long deadline)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+ ep93xx_pata_write_reg(drv_data, ap->ctl, IDECTRL_ADDR_CTL);
+ udelay(20); /* FIXME: flush */
+ ep93xx_pata_write_reg(drv_data, ap->ctl | ATA_SRST, IDECTRL_ADDR_CTL);
+ udelay(20); /* FIXME: flush */
+ ep93xx_pata_write_reg(drv_data, ap->ctl, IDECTRL_ADDR_CTL);
+ ap->last_ctl = ap->ctl;
+
+ return ep93xx_pata_wait_after_reset(&ap->link, devmask, deadline);
+}
+
+static void ep93xx_pata_release_dma(struct ep93xx_pata_data *drv_data)
+{
+ if (drv_data->dma_rx_channel) {
+ dma_release_channel(drv_data->dma_rx_channel);
+ drv_data->dma_rx_channel = NULL;
+ }
+ if (drv_data->dma_tx_channel) {
+ dma_release_channel(drv_data->dma_tx_channel);
+ drv_data->dma_tx_channel = NULL;
+ }
+}
+
+static bool ep93xx_pata_dma_filter(struct dma_chan *chan, void *filter_param)
+{
+ if (ep93xx_dma_chan_is_m2p(chan))
+ return false;
+
+ chan->private = filter_param;
+ return true;
+}
+
+static void ep93xx_pata_dma_init(struct ep93xx_pata_data *drv_data)
+{
+ const struct platform_device *pdev = drv_data->pdev;
+ dma_cap_mask_t mask;
+ struct dma_slave_config conf;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ /*
+ * Request two channels for IDE. Another possibility would be
+ * to request only one channel, and reprogram it's direction at
+ * start of new transfer.
+ */
+ drv_data->dma_rx_data.port = EP93XX_DMA_IDE;
+ drv_data->dma_rx_data.direction = DMA_FROM_DEVICE;
+ drv_data->dma_rx_data.name = "ep93xx-pata-rx";
+ drv_data->dma_rx_channel = dma_request_channel(mask,
+ ep93xx_pata_dma_filter, &drv_data->dma_rx_data);
+ if (!drv_data->dma_rx_channel)
+ return;
+
+ drv_data->dma_tx_data.port = EP93XX_DMA_IDE;
+ drv_data->dma_tx_data.direction = DMA_TO_DEVICE;
+ drv_data->dma_tx_data.name = "ep93xx-pata-tx";
+ drv_data->dma_tx_channel = dma_request_channel(mask,
+ ep93xx_pata_dma_filter, &drv_data->dma_tx_data);
+ if (!drv_data->dma_tx_channel) {
+ dma_release_channel(drv_data->dma_rx_channel);
+ return;
+ }
+
+ /* Configure receive channel direction and source address */
+ memset(&conf, 0, sizeof(conf));
+ conf.direction = DMA_FROM_DEVICE;
+ conf.src_addr = drv_data->udma_in_phys;
+ conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ if (dmaengine_slave_config(drv_data->dma_rx_channel, &conf)) {
+ dev_err(&pdev->dev, "failed to configure rx dma channel\n");
+ ep93xx_pata_release_dma(drv_data);
+ return;
+ }
+
+ /* Configure transmit channel direction and destination address */
+ memset(&conf, 0, sizeof(conf));
+ conf.direction = DMA_TO_DEVICE;
+ conf.dst_addr = drv_data->udma_out_phys;
+ conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ if (dmaengine_slave_config(drv_data->dma_tx_channel, &conf)) {
+ dev_err(&pdev->dev, "failed to configure tx dma channel\n");
+ ep93xx_pata_release_dma(drv_data);
+ }
+}
+
+static void ep93xx_pata_dma_start(struct ata_queued_cmd *qc)
+{
+ struct dma_async_tx_descriptor *txd;
+ struct ep93xx_pata_data *drv_data = qc->ap->host->private_data;
+ void __iomem *base = drv_data->ide_base;
+ struct ata_device *adev = qc->dev;
+ u32 v = qc->dma_dir == DMA_TO_DEVICE ? IDEUDMAOP_RWOP : 0;
+ struct dma_chan *channel = qc->dma_dir == DMA_TO_DEVICE
+ ? drv_data->dma_tx_channel : drv_data->dma_rx_channel;
+
+ txd = channel->device->device_prep_slave_sg(channel, qc->sg,
+ qc->n_elem, qc->dma_dir, DMA_CTRL_ACK, NULL);
+ if (!txd) {
+ dev_err(qc->ap->dev, "failed to prepare slave for sg dma\n");
+ return;
+ }
+ txd->callback = NULL;
+ txd->callback_param = NULL;
+
+ if (dmaengine_submit(txd) < 0) {
+ dev_err(qc->ap->dev, "failed to submit dma transfer\n");
+ return;
+ }
+ dma_async_issue_pending(channel);
+
+ /*
+ * When enabling UDMA operation, IDEUDMAOP register needs to be
+ * programmed in three step sequence:
+ * 1) set or clear the RWOP bit,
+ * 2) perform dummy read of the register,
+ * 3) set the UEN bit.
+ */
+ writel(v, base + IDEUDMAOP);
+ readl(base + IDEUDMAOP);
+ writel(v | IDEUDMAOP_UEN, base + IDEUDMAOP);
+
+ writel(IDECFG_IDEEN | IDECFG_UDMA |
+ ((adev->xfer_mode - XFER_UDMA_0) << IDECFG_MODE_SHIFT),
+ base + IDECFG);
+}
+
+static void ep93xx_pata_dma_stop(struct ata_queued_cmd *qc)
+{
+ struct ep93xx_pata_data *drv_data = qc->ap->host->private_data;
+ void __iomem *base = drv_data->ide_base;
+
+ /* terminate all dma transfers, if not yet finished */
+ dmaengine_terminate_all(drv_data->dma_rx_channel);
+ dmaengine_terminate_all(drv_data->dma_tx_channel);
+
+ /*
+ * To properly stop IDE-DMA, IDEUDMAOP register must to be cleared
+ * and IDECTRL register must be set to default value.
+ */
+ writel(0, base + IDEUDMAOP);
+ writel(readl(base + IDECTRL) | IDECTRL_DIOWN | IDECTRL_DIORN |
+ IDECTRL_CS0N | IDECTRL_CS1N, base + IDECTRL);
+
+ ep93xx_pata_enable_pio(drv_data->ide_base,
+ qc->dev->pio_mode - XFER_PIO_0);
+
+ ata_sff_dma_pause(qc->ap);
+}
+
+static void ep93xx_pata_dma_setup(struct ata_queued_cmd *qc)
+{
+ qc->ap->ops->sff_exec_command(qc->ap, &qc->tf);
+}
+
+static u8 ep93xx_pata_dma_status(struct ata_port *ap)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+ u32 val = readl(drv_data->ide_base + IDEUDMASTS);
+
+ /*
+ * UDMA Status Register bits:
+ *
+ * DMAIDE - DMA request signal from UDMA state machine,
+ * INTIDE - INT line generated by UDMA because of errors in the
+ * state machine,
+ * SBUSY - UDMA state machine busy, not in idle state,
+ * NDO - error for data-out not completed,
+ * NDI - error for data-in not completed,
+ * N4X - error for data transferred not multiplies of four
+ * 32-bit words.
+ * (EP93xx UG p27-17)
+ */
+ if (val & IDEUDMASTS_NDO || val & IDEUDMASTS_NDI ||
+ val & IDEUDMASTS_N4X || val & IDEUDMASTS_INTIDE)
+ return ATA_DMA_ERR;
+
+ /* read INTRQ (INT[3]) pin input state */
+ if (readl(drv_data->ide_base + IDECTRL) & IDECTRL_INTRQ)
+ return ATA_DMA_INTR;
+
+ if (val & IDEUDMASTS_SBUSY || val & IDEUDMASTS_DMAIDE)
+ return ATA_DMA_ACTIVE;
+
+ return 0;
+}
+
+/* Note: original code is ata_sff_softreset */
+static int ep93xx_pata_softreset(struct ata_link *al, unsigned int *classes,
+ unsigned long deadline)
+{
+ struct ata_port *ap = al->ap;
+ unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
+ unsigned int devmask = 0;
+ int rc;
+ u8 err;
+
+ /* determine if device 0/1 are present */
+ if (ep93xx_pata_device_is_present(ap, 0))
+ devmask |= (1 << 0);
+ if (slave_possible && ep93xx_pata_device_is_present(ap, 1))
+ devmask |= (1 << 1);
+
+ /* select device 0 again */
+ ap->ops->sff_dev_select(al->ap, 0);
+
+ /* issue bus reset */
+ rc = ep93xx_pata_bus_softreset(ap, devmask, deadline);
+ /* if link is ocuppied, -ENODEV too is an error */
+ if (rc && (rc != -ENODEV || sata_scr_valid(al))) {
+ ata_link_printk(al, KERN_ERR, "SRST failed (errno=%d)\n",
+ rc);
+ return rc;
+ }
+
+ /* determine by signature whether we have ATA or ATAPI devices */
+ classes[0] = ata_sff_dev_classify(&al->device[0], devmask & (1 << 0),
+ &err);
+ if (slave_possible && err != 0x81)
+ classes[1] = ata_sff_dev_classify(&al->device[1],
+ devmask & (1 << 1), &err);
+
+ return 0;
+}
+
+/* Note: original code is ata_sff_drain_fifo */
+static void ep93xx_pata_drain_fifo(struct ata_queued_cmd *qc)
+{
+ int count;
+ struct ata_port *ap;
+ struct ep93xx_pata_data *drv_data;
+
+ /* We only need to flush incoming data when a command was running */
+ if (qc == NULL || qc->dma_dir == DMA_TO_DEVICE)
+ return;
+
+ ap = qc->ap;
+ drv_data = ap->host->private_data;
+ /* Drain up to 64K of data before we give up this recovery method */
+ for (count = 0; (ap->ops->sff_check_status(ap) & ATA_DRQ)
+ && count < 65536; count += 2)
+ ep93xx_pata_read_reg(drv_data, IDECTRL_ADDR_DATA);
+
+ /* Can become DEBUG later */
+ if (count)
+ ata_port_printk(ap, KERN_DEBUG,
+ "drained %d bytes to clear DRQ.\n", count);
+
+}
+
+static int ep93xx_pata_port_start(struct ata_port *ap)
+{
+ struct ep93xx_pata_data *drv_data = ap->host->private_data;
+
+ /*
+ * Set timings to safe values at startup (= number of ns from ATA
+ * specification), we'll switch to properly calculated values later.
+ */
+ drv_data->t = *ata_timing_find_mode(XFER_PIO_0);
+ return 0;
+}
+
+static struct scsi_host_template ep93xx_pata_sht = {
+ ATA_BASE_SHT(DRV_NAME),
+ /* ep93xx dma implementation limit */
+ .sg_tablesize = 32,
+ /* ep93xx dma can't transfer 65536 bytes at once */
+ .dma_boundary = 0x7fff,
+};
+
+static struct ata_port_operations ep93xx_pata_port_ops = {
+ .inherits = &ata_bmdma_port_ops,
+
+ .qc_prep = ata_noop_qc_prep,
+
+ .softreset = ep93xx_pata_softreset,
+ .hardreset = ATA_OP_NULL,
+
+ .sff_dev_select = ep93xx_pata_dev_select,
+ .sff_set_devctl = ep93xx_pata_set_devctl,
+ .sff_check_status = ep93xx_pata_check_status,
+ .sff_check_altstatus = ep93xx_pata_check_altstatus,
+ .sff_tf_load = ep93xx_pata_tf_load,
+ .sff_tf_read = ep93xx_pata_tf_read,
+ .sff_exec_command = ep93xx_pata_exec_command,
+ .sff_data_xfer = ep93xx_pata_data_xfer,
+ .sff_drain_fifo = ep93xx_pata_drain_fifo,
+ .sff_irq_clear = ATA_OP_NULL,
+
+ .set_piomode = ep93xx_pata_set_piomode,
+
+ .bmdma_setup = ep93xx_pata_dma_setup,
+ .bmdma_start = ep93xx_pata_dma_start,
+ .bmdma_stop = ep93xx_pata_dma_stop,
+ .bmdma_status = ep93xx_pata_dma_status,
+
+ .cable_detect = ata_cable_unknown,
+ .port_start = ep93xx_pata_port_start,
+};
+
+static int __devinit ep93xx_pata_probe(struct platform_device *pdev)
+{
+ struct ep93xx_pata_data *drv_data;
+ struct ata_host *host;
+ struct ata_port *ap;
+ unsigned int irq;
+ struct resource *mem_res;
+ void __iomem *ide_base;
+ int err;
+
+ err = ep93xx_ide_acquire_gpio(pdev);
+ if (err)
+ return err;
+
+ /* INT[3] (IRQ_EP93XX_EXT3) line connected as pull down */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ err = -ENXIO;
+ goto err_rel_gpio;
+ }
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem_res) {
+ err = -ENXIO;
+ goto err_rel_gpio;
+ }
+
+ ide_base = devm_request_and_ioremap(&pdev->dev, mem_res);
+ if (!ide_base) {
+ err = -ENXIO;
+ goto err_rel_gpio;
+ }
+
+ drv_data = devm_kzalloc(&pdev->dev, sizeof(*drv_data), GFP_KERNEL);
+ if (!drv_data) {
+ err = -ENXIO;
+ goto err_rel_gpio;
+ }
+
+ platform_set_drvdata(pdev, drv_data);
+ drv_data->pdev = pdev;
+ drv_data->ide_base = ide_base;
+ drv_data->udma_in_phys = mem_res->start + IDEUDMADATAIN;
+ drv_data->udma_out_phys = mem_res->start + IDEUDMADATAOUT;
+ ep93xx_pata_dma_init(drv_data);
+
+ /* allocate host */
+ host = ata_host_alloc(&pdev->dev, 1);
+ if (!host) {
+ err = -ENXIO;
+ goto err_rel_dma;
+ }
+
+ ep93xx_pata_clear_regs(ide_base);
+
+ host->private_data = drv_data;
+
+ ap = host->ports[0];
+ ap->dev = &pdev->dev;
+ ap->ops = &ep93xx_pata_port_ops;
+ ap->flags |= ATA_FLAG_SLAVE_POSS;
+ ap->pio_mask = ATA_PIO4;
+
+ /*
+ * Maximum UDMA modes:
+ * EP931x rev.E0 - UDMA2
+ * EP931x rev.E1 - UDMA3
+ * EP931x rev.E2 - UDMA4
+ *
+ * MWDMA support was removed from EP931x rev.E2,
+ * so this driver supports only UDMA modes.
+ */
+ if (drv_data->dma_rx_channel && drv_data->dma_tx_channel) {
+ int chip_rev = ep93xx_chip_revision();
+
+ if (chip_rev == EP93XX_CHIP_REV_E1)
+ ap->udma_mask = ATA_UDMA3;
+ else if (chip_rev == EP93XX_CHIP_REV_E2)
+ ap->udma_mask = ATA_UDMA4;
+ else
+ ap->udma_mask = ATA_UDMA2;
+ }
+
+ /* defaults, pio 0 */
+ ep93xx_pata_enable_pio(ide_base, 0);
+
+ dev_info(&pdev->dev, "version " DRV_VERSION "\n");
+
+ /* activate host */
+ err = ata_host_activate(host, irq, ata_bmdma_interrupt, 0,
+ &ep93xx_pata_sht);
+ if (err == 0)
+ return 0;
+
+err_rel_dma:
+ ep93xx_pata_release_dma(drv_data);
+err_rel_gpio:
+ ep93xx_ide_release_gpio(pdev);
+ return err;
+}
+
+static int __devexit ep93xx_pata_remove(struct platform_device *pdev)
+{
+ struct ata_host *host = platform_get_drvdata(pdev);
+ struct ep93xx_pata_data *drv_data = host->private_data;
+
+ ata_host_detach(host);
+ ep93xx_pata_release_dma(drv_data);
+ ep93xx_pata_clear_regs(drv_data->ide_base);
+ ep93xx_ide_release_gpio(pdev);
+ return 0;
+}
+
+static struct platform_driver ep93xx_pata_platform_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ep93xx_pata_probe,
+ .remove = __devexit_p(ep93xx_pata_remove),
+};
+
+module_platform_driver(ep93xx_pata_platform_driver);
+
+MODULE_AUTHOR("Alessandro Zummo, Lennert Buytenhek, Joao Ramos, "
+ "Bartlomiej Zolnierkiewicz, Rafal Prylowski");
+MODULE_DESCRIPTION("low-level driver for cirrus ep93xx IDE controller");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:pata_ep93xx");
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 26a06b801b5b..2bcef657a60c 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -21,8 +21,7 @@
#include "power/power.h"
/* /sys/devices/system */
-/* FIXME: make static after drivers/base/sys.c is deleted */
-struct kset *system_kset;
+static struct kset *system_kset;
#define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index e28ce9898af4..346be8b78b24 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -25,6 +25,7 @@
#include <linux/mutex.h>
#include <linux/async.h>
#include <linux/pm_runtime.h>
+#include <linux/netdevice.h>
#include "base.h"
#include "power/power.h"
@@ -65,7 +66,7 @@ static inline int device_is_not_partition(struct device *dev)
* @dev: struct device to get the name of
*
* Will return the device's driver's name if it is bound to a device. If
- * the device is not bound to a device, it will return the name of the bus
+ * the device is not bound to a driver, it will return the name of the bus
* it is attached to. If it is not attached to a bus either, an empty
* string will be returned.
*/
@@ -878,8 +879,8 @@ EXPORT_SYMBOL_GPL(dev_set_name);
* to NULL prevents an entry from being created. class->dev_kobj must
* be set (or cleared) before any devices are registered to the class
* otherwise device_create_sys_dev_entry() and
- * device_remove_sys_dev_entry() will disagree about the the presence
- * of the link.
+ * device_remove_sys_dev_entry() will disagree about the presence of
+ * the link.
*/
static struct kobject *device_to_dev_kobj(struct device *dev)
{
@@ -1843,15 +1844,60 @@ void device_shutdown(void)
*/
#ifdef CONFIG_PRINTK
-
int __dev_printk(const char *level, const struct device *dev,
struct va_format *vaf)
{
+ char dict[128];
+ size_t dictlen = 0;
+ const char *subsys;
+
if (!dev)
return printk("%s(NULL device *): %pV", level, vaf);
- return printk("%s%s %s: %pV",
- level, dev_driver_string(dev), dev_name(dev), vaf);
+ if (dev->class)
+ subsys = dev->class->name;
+ else if (dev->bus)
+ subsys = dev->bus->name;
+ else
+ goto skip;
+
+ dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
+ "SUBSYSTEM=%s", subsys);
+
+ /*
+ * Add device identifier DEVICE=:
+ * b12:8 block dev_t
+ * c127:3 char dev_t
+ * n8 netdev ifindex
+ * +sound:card0 subsystem:devname
+ */
+ if (MAJOR(dev->devt)) {
+ char c;
+
+ if (strcmp(subsys, "block") == 0)
+ c = 'b';
+ else
+ c = 'c';
+ dictlen++;
+ dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
+ "DEVICE=%c%u:%u",
+ c, MAJOR(dev->devt), MINOR(dev->devt));
+ } else if (strcmp(subsys, "net") == 0) {
+ struct net_device *net = to_net_dev(dev);
+
+ dictlen++;
+ dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
+ "DEVICE=n%u", net->ifindex);
+ } else {
+ dictlen++;
+ dictlen += snprintf(dict + dictlen, sizeof(dict) - dictlen,
+ "DEVICE=+%s:%s", subsys, dev_name(dev));
+ }
+skip:
+ return printk_emit(0, level[1] - '0',
+ dictlen ? dict : NULL, dictlen,
+ "%s %s: %pV",
+ dev_driver_string(dev), dev_name(dev), vaf);
}
EXPORT_SYMBOL(__dev_printk);
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index adf937bf4091..63452943abd1 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -330,8 +330,4 @@ void __init cpu_dev_init(void)
panic("Failed to register CPU subsystem");
cpu_dev_register_generic();
-
-#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
- sched_create_sysfs_power_savings_entries(cpu_subsys.dev_root);
-#endif
}
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index 524bf96c289f..2360adb7a58f 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -309,6 +309,10 @@ EXPORT_SYMBOL_GPL(devres_remove);
* which @match returns 1. If @match is NULL, it's considered to
* match all. If found, the resource is removed atomically and freed.
*
+ * Note that the release function for the resource will not be called,
+ * only the devres-allocated data will be freed. The caller becomes
+ * responsible for freeing any other data.
+ *
* RETURNS:
* 0 if devres is found and freed, -ENOENT if not found.
*/
@@ -326,6 +330,37 @@ int devres_destroy(struct device *dev, dr_release_t release,
}
EXPORT_SYMBOL_GPL(devres_destroy);
+
+/**
+ * devres_release - Find a device resource and destroy it, calling release
+ * @dev: Device to find resource from
+ * @release: Look for resources associated with this release function
+ * @match: Match function (optional)
+ * @match_data: Data for the match function
+ *
+ * Find the latest devres of @dev associated with @release and for
+ * which @match returns 1. If @match is NULL, it's considered to
+ * match all. If found, the resource is removed atomically, the
+ * release function called and the resource freed.
+ *
+ * RETURNS:
+ * 0 if devres is found and freed, -ENOENT if not found.
+ */
+int devres_release(struct device *dev, dr_release_t release,
+ dr_match_t match, void *match_data)
+{
+ void *res;
+
+ res = devres_remove(dev, release, match, match_data);
+ if (unlikely(!res))
+ return -ENOENT;
+
+ (*release)(dev, res);
+ devres_free(res);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(devres_release);
+
static int remove_nodes(struct device *dev,
struct list_head *first, struct list_head *end,
struct list_head *todo)
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
index 8493536ea55b..765c3a28077a 100644
--- a/drivers/base/devtmpfs.c
+++ b/drivers/base/devtmpfs.c
@@ -7,9 +7,9 @@
* devtmpfs, a tmpfs-based filesystem is created. Every driver-core
* device which requests a device node, will add a node in this
* filesystem.
- * By default, all devices are named after the the name of the
- * device, owned by root and have a default mode of 0600. Subsystems
- * can overwrite the default setting if needed.
+ * By default, all devices are named after the name of the device,
+ * owned by root and have a default mode of 0600. Subsystems can
+ * overwrite the default setting if needed.
*/
#include <linux/kernel.h>
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c
index 07cbbc6fddb4..05c64c11bad2 100644
--- a/drivers/base/dma-buf.c
+++ b/drivers/base/dma-buf.c
@@ -293,7 +293,7 @@ EXPORT_SYMBOL_GPL(dma_buf_unmap_attachment);
* cpu in the kernel context. Calls begin_cpu_access to allow exporter-specific
* preparations. Coherency is only guaranteed in the specified range for the
* specified access direction.
- * @dma_buf: [in] buffer to prepare cpu access for.
+ * @dmabuf: [in] buffer to prepare cpu access for.
* @start: [in] start of range for cpu access.
* @len: [in] length of range for cpu access.
* @direction: [in] length of range for cpu access.
@@ -320,7 +320,7 @@ EXPORT_SYMBOL_GPL(dma_buf_begin_cpu_access);
* cpu in the kernel context. Calls end_cpu_access to allow exporter-specific
* actions. Coherency is only guaranteed in the specified range for the
* specified access direction.
- * @dma_buf: [in] buffer to complete cpu access for.
+ * @dmabuf: [in] buffer to complete cpu access for.
* @start: [in] start of range for cpu access.
* @len: [in] length of range for cpu access.
* @direction: [in] length of range for cpu access.
@@ -340,7 +340,7 @@ EXPORT_SYMBOL_GPL(dma_buf_end_cpu_access);
/**
* dma_buf_kmap_atomic - Map a page of the buffer object into kernel address
* space. The same restrictions as for kmap_atomic and friends apply.
- * @dma_buf: [in] buffer to map page from.
+ * @dmabuf: [in] buffer to map page from.
* @page_num: [in] page in PAGE_SIZE units to map.
*
* This call must always succeed, any necessary preparations that might fail
@@ -356,7 +356,7 @@ EXPORT_SYMBOL_GPL(dma_buf_kmap_atomic);
/**
* dma_buf_kunmap_atomic - Unmap a page obtained by dma_buf_kmap_atomic.
- * @dma_buf: [in] buffer to unmap page from.
+ * @dmabuf: [in] buffer to unmap page from.
* @page_num: [in] page in PAGE_SIZE units to unmap.
* @vaddr: [in] kernel space pointer obtained from dma_buf_kmap_atomic.
*
@@ -375,7 +375,7 @@ EXPORT_SYMBOL_GPL(dma_buf_kunmap_atomic);
/**
* dma_buf_kmap - Map a page of the buffer object into kernel address space. The
* same restrictions as for kmap and friends apply.
- * @dma_buf: [in] buffer to map page from.
+ * @dmabuf: [in] buffer to map page from.
* @page_num: [in] page in PAGE_SIZE units to map.
*
* This call must always succeed, any necessary preparations that might fail
@@ -391,7 +391,7 @@ EXPORT_SYMBOL_GPL(dma_buf_kmap);
/**
* dma_buf_kunmap - Unmap a page obtained by dma_buf_kmap.
- * @dma_buf: [in] buffer to unmap page from.
+ * @dmabuf: [in] buffer to unmap page from.
* @page_num: [in] page in PAGE_SIZE units to unmap.
* @vaddr: [in] kernel space pointer obtained from dma_buf_kmap.
*
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 3ec3896c83a6..207c27ddf828 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -80,7 +80,7 @@ struct device *driver_find_device(struct device_driver *drv,
struct klist_iter i;
struct device *dev;
- if (!drv)
+ if (!drv || !drv->p)
return NULL;
klist_iter_init_node(&drv->p->klist_devices, &i,
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 73ce9fbe9839..83aa694a8efe 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -11,6 +11,7 @@
#include <linux/io.h>
#include <linux/pm_runtime.h>
#include <linux/pm_domain.h>
+#include <linux/pm_qos.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/sched.h>
@@ -38,11 +39,13 @@
ktime_t __start = ktime_get(); \
type __retval = GENPD_DEV_CALLBACK(genpd, type, callback, dev); \
s64 __elapsed = ktime_to_ns(ktime_sub(ktime_get(), __start)); \
- struct generic_pm_domain_data *__gpd_data = dev_gpd_data(dev); \
- if (__elapsed > __gpd_data->td.field) { \
- __gpd_data->td.field = __elapsed; \
+ struct gpd_timing_data *__td = &dev_gpd_data(dev)->td; \
+ if (!__retval && __elapsed > __td->field) { \
+ __td->field = __elapsed; \
dev_warn(dev, name " latency exceeded, new value %lld ns\n", \
__elapsed); \
+ genpd->max_off_time_changed = true; \
+ __td->constraint_changed = true; \
} \
__retval; \
})
@@ -211,6 +214,7 @@ int __pm_genpd_poweron(struct generic_pm_domain *genpd)
elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
if (elapsed_ns > genpd->power_on_latency_ns) {
genpd->power_on_latency_ns = elapsed_ns;
+ genpd->max_off_time_changed = true;
if (genpd->name)
pr_warning("%s: Power-on latency exceeded, "
"new value %lld ns\n", genpd->name,
@@ -247,6 +251,53 @@ int pm_genpd_poweron(struct generic_pm_domain *genpd)
#ifdef CONFIG_PM_RUNTIME
+static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
+ unsigned long val, void *ptr)
+{
+ struct generic_pm_domain_data *gpd_data;
+ struct device *dev;
+
+ gpd_data = container_of(nb, struct generic_pm_domain_data, nb);
+
+ mutex_lock(&gpd_data->lock);
+ dev = gpd_data->base.dev;
+ if (!dev) {
+ mutex_unlock(&gpd_data->lock);
+ return NOTIFY_DONE;
+ }
+ mutex_unlock(&gpd_data->lock);
+
+ for (;;) {
+ struct generic_pm_domain *genpd;
+ struct pm_domain_data *pdd;
+
+ spin_lock_irq(&dev->power.lock);
+
+ pdd = dev->power.subsys_data ?
+ dev->power.subsys_data->domain_data : NULL;
+ if (pdd) {
+ to_gpd_data(pdd)->td.constraint_changed = true;
+ genpd = dev_to_genpd(dev);
+ } else {
+ genpd = ERR_PTR(-ENODATA);
+ }
+
+ spin_unlock_irq(&dev->power.lock);
+
+ if (!IS_ERR(genpd)) {
+ mutex_lock(&genpd->lock);
+ genpd->max_off_time_changed = true;
+ mutex_unlock(&genpd->lock);
+ }
+
+ dev = dev->parent;
+ if (!dev || dev->power.ignore_children)
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
/**
* __pm_genpd_save_device - Save the pre-suspend state of a device.
* @pdd: Domain data of the device to save the state of.
@@ -435,6 +486,7 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
if (elapsed_ns > genpd->power_off_latency_ns) {
genpd->power_off_latency_ns = elapsed_ns;
+ genpd->max_off_time_changed = true;
if (genpd->name)
pr_warning("%s: Power-off latency exceeded, "
"new value %lld ns\n", genpd->name,
@@ -443,17 +495,6 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
}
genpd->status = GPD_STATE_POWER_OFF;
- genpd->power_off_time = ktime_get();
-
- /* Update PM QoS information for devices in the domain. */
- list_for_each_entry_reverse(pdd, &genpd->dev_list, list_node) {
- struct gpd_timing_data *td = &to_gpd_data(pdd)->td;
-
- pm_runtime_update_max_time_suspended(pdd->dev,
- td->start_latency_ns +
- td->restore_state_latency_ns +
- genpd->power_on_latency_ns);
- }
list_for_each_entry(link, &genpd->slave_links, slave_node) {
genpd_sd_counter_dec(link->master);
@@ -514,9 +555,6 @@ static int pm_genpd_runtime_suspend(struct device *dev)
if (ret)
return ret;
- pm_runtime_update_max_time_suspended(dev,
- dev_gpd_data(dev)->td.start_latency_ns);
-
/*
* If power.irq_safe is set, this routine will be run with interrupts
* off, so it can't use mutexes.
@@ -613,6 +651,12 @@ void pm_genpd_poweroff_unused(void)
#else
+static inline int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
+ unsigned long val, void *ptr)
+{
+ return NOTIFY_DONE;
+}
+
static inline void genpd_power_off_work_fn(struct work_struct *work) {}
#define pm_genpd_runtime_suspend NULL
@@ -1209,12 +1253,15 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
return -EINVAL;
- genpd_acquire_lock(genpd);
+ gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL);
+ if (!gpd_data)
+ return -ENOMEM;
- if (genpd->status == GPD_STATE_POWER_OFF) {
- ret = -EINVAL;
- goto out;
- }
+ mutex_init(&gpd_data->lock);
+ gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
+ dev_pm_qos_add_notifier(dev, &gpd_data->nb);
+
+ genpd_acquire_lock(genpd);
if (genpd->prepared_count > 0) {
ret = -EAGAIN;
@@ -1227,26 +1274,35 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
goto out;
}
- gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL);
- if (!gpd_data) {
- ret = -ENOMEM;
- goto out;
- }
-
genpd->device_count++;
+ genpd->max_off_time_changed = true;
- dev->pm_domain = &genpd->domain;
dev_pm_get_subsys_data(dev);
+
+ mutex_lock(&gpd_data->lock);
+ spin_lock_irq(&dev->power.lock);
+ dev->pm_domain = &genpd->domain;
dev->power.subsys_data->domain_data = &gpd_data->base;
gpd_data->base.dev = dev;
- gpd_data->need_restore = false;
list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
+ gpd_data->need_restore = genpd->status == GPD_STATE_POWER_OFF;
if (td)
gpd_data->td = *td;
+ gpd_data->td.constraint_changed = true;
+ gpd_data->td.effective_constraint_ns = -1;
+ spin_unlock_irq(&dev->power.lock);
+ mutex_unlock(&gpd_data->lock);
+
+ genpd_release_lock(genpd);
+
+ return 0;
+
out:
genpd_release_lock(genpd);
+ dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
+ kfree(gpd_data);
return ret;
}
@@ -1290,12 +1346,15 @@ int __pm_genpd_of_add_device(struct device_node *genpd_node, struct device *dev,
int pm_genpd_remove_device(struct generic_pm_domain *genpd,
struct device *dev)
{
+ struct generic_pm_domain_data *gpd_data;
struct pm_domain_data *pdd;
- int ret = -EINVAL;
+ int ret = 0;
dev_dbg(dev, "%s()\n", __func__);
- if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
+ if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev)
+ || IS_ERR_OR_NULL(dev->pm_domain)
+ || pd_to_genpd(dev->pm_domain) != genpd)
return -EINVAL;
genpd_acquire_lock(genpd);
@@ -1305,21 +1364,27 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
goto out;
}
- list_for_each_entry(pdd, &genpd->dev_list, list_node) {
- if (pdd->dev != dev)
- continue;
+ genpd->device_count--;
+ genpd->max_off_time_changed = true;
- list_del_init(&pdd->list_node);
- pdd->dev = NULL;
- dev_pm_put_subsys_data(dev);
- dev->pm_domain = NULL;
- kfree(to_gpd_data(pdd));
+ spin_lock_irq(&dev->power.lock);
+ dev->pm_domain = NULL;
+ pdd = dev->power.subsys_data->domain_data;
+ list_del_init(&pdd->list_node);
+ dev->power.subsys_data->domain_data = NULL;
+ spin_unlock_irq(&dev->power.lock);
- genpd->device_count--;
+ gpd_data = to_gpd_data(pdd);
+ mutex_lock(&gpd_data->lock);
+ pdd->dev = NULL;
+ mutex_unlock(&gpd_data->lock);
- ret = 0;
- break;
- }
+ genpd_release_lock(genpd);
+
+ dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
+ kfree(gpd_data);
+ dev_pm_put_subsys_data(dev);
+ return 0;
out:
genpd_release_lock(genpd);
@@ -1348,6 +1413,26 @@ void pm_genpd_dev_always_on(struct device *dev, bool val)
EXPORT_SYMBOL_GPL(pm_genpd_dev_always_on);
/**
+ * pm_genpd_dev_need_restore - Set/unset the device's "need restore" flag.
+ * @dev: Device to set/unset the flag for.
+ * @val: The new value of the device's "need restore" flag.
+ */
+void pm_genpd_dev_need_restore(struct device *dev, bool val)
+{
+ struct pm_subsys_data *psd;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->power.lock, flags);
+
+ psd = dev_to_psd(dev);
+ if (psd && psd->domain_data)
+ to_gpd_data(psd->domain_data)->need_restore = val;
+
+ spin_unlock_irqrestore(&dev->power.lock, flags);
+}
+EXPORT_SYMBOL_GPL(pm_genpd_dev_need_restore);
+
+/**
* pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
* @genpd: Master PM domain to add the subdomain to.
* @subdomain: Subdomain to be added.
@@ -1378,7 +1463,7 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
goto out;
}
- list_for_each_entry(link, &genpd->slave_links, slave_node) {
+ list_for_each_entry(link, &genpd->master_links, master_node) {
if (link->slave == subdomain && link->master == genpd) {
ret = -EINVAL;
goto out;
@@ -1690,6 +1775,7 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
genpd->resume_count = 0;
genpd->device_count = 0;
genpd->max_off_time_ns = -1;
+ genpd->max_off_time_changed = true;
genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend;
genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume;
genpd->domain.ops.runtime_idle = pm_generic_runtime_idle;
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
index 66a265bf5867..28dee3053f1f 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -14,6 +14,31 @@
#ifdef CONFIG_PM_RUNTIME
+static int dev_update_qos_constraint(struct device *dev, void *data)
+{
+ s64 *constraint_ns_p = data;
+ s32 constraint_ns = -1;
+
+ if (dev->power.subsys_data && dev->power.subsys_data->domain_data)
+ constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
+
+ if (constraint_ns < 0) {
+ constraint_ns = dev_pm_qos_read_value(dev);
+ constraint_ns *= NSEC_PER_USEC;
+ }
+ if (constraint_ns == 0)
+ return 0;
+
+ /*
+ * constraint_ns cannot be negative here, because the device has been
+ * suspended.
+ */
+ if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
+ *constraint_ns_p = constraint_ns;
+
+ return 0;
+}
+
/**
* default_stop_ok - Default PM domain governor routine for stopping devices.
* @dev: Device to check.
@@ -21,14 +46,52 @@
bool default_stop_ok(struct device *dev)
{
struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
+ unsigned long flags;
+ s64 constraint_ns;
dev_dbg(dev, "%s()\n", __func__);
- if (dev->power.max_time_suspended_ns < 0 || td->break_even_ns == 0)
- return true;
+ spin_lock_irqsave(&dev->power.lock, flags);
+
+ if (!td->constraint_changed) {
+ bool ret = td->cached_stop_ok;
- return td->stop_latency_ns + td->start_latency_ns < td->break_even_ns
- && td->break_even_ns < dev->power.max_time_suspended_ns;
+ spin_unlock_irqrestore(&dev->power.lock, flags);
+ return ret;
+ }
+ td->constraint_changed = false;
+ td->cached_stop_ok = false;
+ td->effective_constraint_ns = -1;
+ constraint_ns = __dev_pm_qos_read_value(dev);
+
+ spin_unlock_irqrestore(&dev->power.lock, flags);
+
+ if (constraint_ns < 0)
+ return false;
+
+ constraint_ns *= NSEC_PER_USEC;
+ /*
+ * We can walk the children without any additional locking, because
+ * they all have been suspended at this point and their
+ * effective_constraint_ns fields won't be modified in parallel with us.
+ */
+ if (!dev->power.ignore_children)
+ device_for_each_child(dev, &constraint_ns,
+ dev_update_qos_constraint);
+
+ if (constraint_ns > 0) {
+ constraint_ns -= td->start_latency_ns;
+ if (constraint_ns == 0)
+ return false;
+ }
+ td->effective_constraint_ns = constraint_ns;
+ td->cached_stop_ok = constraint_ns > td->stop_latency_ns ||
+ constraint_ns == 0;
+ /*
+ * The children have been suspended already, so we don't need to take
+ * their stop latencies into account here.
+ */
+ return td->cached_stop_ok;
}
/**
@@ -42,9 +105,27 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
struct generic_pm_domain *genpd = pd_to_genpd(pd);
struct gpd_link *link;
struct pm_domain_data *pdd;
- s64 min_dev_off_time_ns;
+ s64 min_off_time_ns;
s64 off_on_time_ns;
- ktime_t time_now = ktime_get();
+
+ if (genpd->max_off_time_changed) {
+ struct gpd_link *link;
+
+ /*
+ * We have to invalidate the cached results for the masters, so
+ * use the observation that default_power_down_ok() is not
+ * going to be called for any master until this instance
+ * returns.
+ */
+ list_for_each_entry(link, &genpd->slave_links, slave_node)
+ link->master->max_off_time_changed = true;
+
+ genpd->max_off_time_changed = false;
+ genpd->cached_power_down_ok = false;
+ genpd->max_off_time_ns = -1;
+ } else {
+ return genpd->cached_power_down_ok;
+ }
off_on_time_ns = genpd->power_off_latency_ns +
genpd->power_on_latency_ns;
@@ -61,6 +142,7 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
to_gpd_data(pdd)->td.save_state_latency_ns;
}
+ min_off_time_ns = -1;
/*
* Check if subdomains can be off for enough time.
*
@@ -73,8 +155,6 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
if (sd_max_off_ns < 0)
continue;
- sd_max_off_ns -= ktime_to_ns(ktime_sub(time_now,
- sd->power_off_time));
/*
* Check if the subdomain is allowed to be off long enough for
* the current domain to turn off and on (that's how much time
@@ -82,60 +162,64 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
*/
if (sd_max_off_ns <= off_on_time_ns)
return false;
+
+ if (min_off_time_ns > sd_max_off_ns || min_off_time_ns < 0)
+ min_off_time_ns = sd_max_off_ns;
}
/*
* Check if the devices in the domain can be off enough time.
*/
- min_dev_off_time_ns = -1;
list_for_each_entry(pdd, &genpd->dev_list, list_node) {
struct gpd_timing_data *td;
- struct device *dev = pdd->dev;
- s64 dev_off_time_ns;
+ s64 constraint_ns;
- if (!dev->driver || dev->power.max_time_suspended_ns < 0)
+ if (!pdd->dev->driver)
continue;
+ /*
+ * Check if the device is allowed to be off long enough for the
+ * domain to turn off and on (that's how much time it will
+ * have to wait worst case).
+ */
td = &to_gpd_data(pdd)->td;
- dev_off_time_ns = dev->power.max_time_suspended_ns -
- (td->start_latency_ns + td->restore_state_latency_ns +
- ktime_to_ns(ktime_sub(time_now,
- dev->power.suspend_time)));
- if (dev_off_time_ns <= off_on_time_ns)
- return false;
-
- if (min_dev_off_time_ns > dev_off_time_ns
- || min_dev_off_time_ns < 0)
- min_dev_off_time_ns = dev_off_time_ns;
- }
+ constraint_ns = td->effective_constraint_ns;
+ /* default_stop_ok() need not be called before us. */
+ if (constraint_ns < 0) {
+ constraint_ns = dev_pm_qos_read_value(pdd->dev);
+ constraint_ns *= NSEC_PER_USEC;
+ }
+ if (constraint_ns == 0)
+ continue;
- if (min_dev_off_time_ns < 0) {
/*
- * There are no latency constraints, so the domain can spend
- * arbitrary time in the "off" state.
+ * constraint_ns cannot be negative here, because the device has
+ * been suspended.
*/
- genpd->max_off_time_ns = -1;
- return true;
+ constraint_ns -= td->restore_state_latency_ns;
+ if (constraint_ns <= off_on_time_ns)
+ return false;
+
+ if (min_off_time_ns > constraint_ns || min_off_time_ns < 0)
+ min_off_time_ns = constraint_ns;
}
+ genpd->cached_power_down_ok = true;
+
/*
- * The difference between the computed minimum delta and the time needed
- * to turn the domain on is the maximum theoretical time this domain can
- * spend in the "off" state.
+ * If the computed minimum device off time is negative, there are no
+ * latency constraints, so the domain can spend arbitrary time in the
+ * "off" state.
*/
- min_dev_off_time_ns -= genpd->power_on_latency_ns;
+ if (min_off_time_ns < 0)
+ return true;
/*
- * If the difference between the computed minimum delta and the time
- * needed to turn the domain off and back on on is smaller than the
- * domain's power break even time, removing power from the domain is not
- * worth it.
+ * The difference between the computed minimum subdomain or device off
+ * time and the time needed to turn the domain on is the maximum
+ * theoretical time this domain can spend in the "off" state.
*/
- if (genpd->break_even_ns >
- min_dev_off_time_ns - genpd->power_off_latency_ns)
- return false;
-
- genpd->max_off_time_ns = min_dev_off_time_ns;
+ genpd->max_off_time_ns = min_off_time_ns - genpd->power_on_latency_ns;
return true;
}
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index b462c0e341cb..e0fb5b0435a3 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -889,6 +889,11 @@ static int dpm_suspend_noirq(pm_message_t state)
if (!list_empty(&dev->power.entry))
list_move(&dev->power.entry, &dpm_noirq_list);
put_device(dev);
+
+ if (pm_wakeup_pending()) {
+ error = -EBUSY;
+ break;
+ }
}
mutex_unlock(&dpm_list_mtx);
if (error)
@@ -962,6 +967,11 @@ static int dpm_suspend_late(pm_message_t state)
if (!list_empty(&dev->power.entry))
list_move(&dev->power.entry, &dpm_late_early_list);
put_device(dev);
+
+ if (pm_wakeup_pending()) {
+ error = -EBUSY;
+ break;
+ }
}
mutex_unlock(&dpm_list_mtx);
if (error)
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 71855570922d..fd849a2c4fa8 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -352,21 +352,26 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_remove_request);
*
* Will register the notifier into a notification chain that gets called
* upon changes to the target value for the device.
+ *
+ * If the device's constraints object doesn't exist when this routine is called,
+ * it will be created (or error code will be returned if that fails).
*/
int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier)
{
- int retval = 0;
+ int ret = 0;
mutex_lock(&dev_pm_qos_mtx);
- /* Silently return if the constraints object is not present. */
- if (dev->power.constraints)
- retval = blocking_notifier_chain_register(
- dev->power.constraints->notifiers,
- notifier);
+ if (!dev->power.constraints)
+ ret = dev->power.power_state.event != PM_EVENT_INVALID ?
+ dev_pm_qos_constraints_allocate(dev) : -ENODEV;
+
+ if (!ret)
+ ret = blocking_notifier_chain_register(
+ dev->power.constraints->notifiers, notifier);
mutex_unlock(&dev_pm_qos_mtx);
- return retval;
+ return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_qos_add_notifier);
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index bd0f3949bcf9..59894873a3b3 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -282,47 +282,6 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev)
return retval != -EACCES ? retval : -EIO;
}
-struct rpm_qos_data {
- ktime_t time_now;
- s64 constraint_ns;
-};
-
-/**
- * rpm_update_qos_constraint - Update a given PM QoS constraint data.
- * @dev: Device whose timing data to use.
- * @data: PM QoS constraint data to update.
- *
- * Use the suspend timing data of @dev to update PM QoS constraint data pointed
- * to by @data.
- */
-static int rpm_update_qos_constraint(struct device *dev, void *data)
-{
- struct rpm_qos_data *qos = data;
- unsigned long flags;
- s64 delta_ns;
- int ret = 0;
-
- spin_lock_irqsave(&dev->power.lock, flags);
-
- if (dev->power.max_time_suspended_ns < 0)
- goto out;
-
- delta_ns = dev->power.max_time_suspended_ns -
- ktime_to_ns(ktime_sub(qos->time_now, dev->power.suspend_time));
- if (delta_ns <= 0) {
- ret = -EBUSY;
- goto out;
- }
-
- if (qos->constraint_ns > delta_ns || qos->constraint_ns == 0)
- qos->constraint_ns = delta_ns;
-
- out:
- spin_unlock_irqrestore(&dev->power.lock, flags);
-
- return ret;
-}
-
/**
* rpm_suspend - Carry out runtime suspend of given device.
* @dev: Device to suspend.
@@ -349,7 +308,6 @@ static int rpm_suspend(struct device *dev, int rpmflags)
{
int (*callback)(struct device *);
struct device *parent = NULL;
- struct rpm_qos_data qos;
int retval;
trace_rpm_suspend(dev, rpmflags);
@@ -445,38 +403,14 @@ static int rpm_suspend(struct device *dev, int rpmflags)
goto out;
}
- qos.constraint_ns = __dev_pm_qos_read_value(dev);
- if (qos.constraint_ns < 0) {
- /* Negative constraint means "never suspend". */
+ if (__dev_pm_qos_read_value(dev) < 0) {
+ /* Negative PM QoS constraint means "never suspend". */
retval = -EPERM;
goto out;
}
- qos.constraint_ns *= NSEC_PER_USEC;
- qos.time_now = ktime_get();
__update_runtime_status(dev, RPM_SUSPENDING);
- if (!dev->power.ignore_children) {
- if (dev->power.irq_safe)
- spin_unlock(&dev->power.lock);
- else
- spin_unlock_irq(&dev->power.lock);
-
- retval = device_for_each_child(dev, &qos,
- rpm_update_qos_constraint);
-
- if (dev->power.irq_safe)
- spin_lock(&dev->power.lock);
- else
- spin_lock_irq(&dev->power.lock);
-
- if (retval)
- goto fail;
- }
-
- dev->power.suspend_time = qos.time_now;
- dev->power.max_time_suspended_ns = qos.constraint_ns ? : -1;
-
if (dev->pm_domain)
callback = dev->pm_domain->ops.runtime_suspend;
else if (dev->type && dev->type->pm)
@@ -529,8 +463,6 @@ static int rpm_suspend(struct device *dev, int rpmflags)
fail:
__update_runtime_status(dev, RPM_ACTIVE);
- dev->power.suspend_time = ktime_set(0, 0);
- dev->power.max_time_suspended_ns = -1;
dev->power.deferred_resume = false;
wake_up_all(&dev->power.wait_queue);
@@ -704,9 +636,6 @@ static int rpm_resume(struct device *dev, int rpmflags)
if (dev->power.no_callbacks)
goto no_callback; /* Assume success. */
- dev->power.suspend_time = ktime_set(0, 0);
- dev->power.max_time_suspended_ns = -1;
-
__update_runtime_status(dev, RPM_RESUMING);
if (dev->pm_domain)
@@ -1369,9 +1298,6 @@ void pm_runtime_init(struct device *dev)
setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn,
(unsigned long)dev);
- dev->power.suspend_time = ktime_set(0, 0);
- dev->power.max_time_suspended_ns = -1;
-
init_waitqueue_head(&dev->power.wait_queue);
}
@@ -1389,28 +1315,3 @@ void pm_runtime_remove(struct device *dev)
if (dev->power.irq_safe && dev->parent)
pm_runtime_put_sync(dev->parent);
}
-
-/**
- * pm_runtime_update_max_time_suspended - Update device's suspend time data.
- * @dev: Device to handle.
- * @delta_ns: Value to subtract from the device's max_time_suspended_ns field.
- *
- * Update the device's power.max_time_suspended_ns field by subtracting
- * @delta_ns from it. The resulting value of power.max_time_suspended_ns is
- * never negative.
- */
-void pm_runtime_update_max_time_suspended(struct device *dev, s64 delta_ns)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&dev->power.lock, flags);
-
- if (delta_ns > 0 && dev->power.max_time_suspended_ns > 0) {
- if (dev->power.max_time_suspended_ns > delta_ns)
- dev->power.max_time_suspended_ns -= delta_ns;
- else
- dev->power.max_time_suspended_ns = 0;
- }
-
- spin_unlock_irqrestore(&dev->power.lock, flags);
-}
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 95c12f6cb5b9..48be2ad4dd2c 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -314,22 +314,41 @@ static ssize_t wakeup_active_count_show(struct device *dev,
static DEVICE_ATTR(wakeup_active_count, 0444, wakeup_active_count_show, NULL);
-static ssize_t wakeup_hit_count_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t wakeup_abort_count_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ unsigned long count = 0;
+ bool enabled = false;
+
+ spin_lock_irq(&dev->power.lock);
+ if (dev->power.wakeup) {
+ count = dev->power.wakeup->wakeup_count;
+ enabled = true;
+ }
+ spin_unlock_irq(&dev->power.lock);
+ return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n");
+}
+
+static DEVICE_ATTR(wakeup_abort_count, 0444, wakeup_abort_count_show, NULL);
+
+static ssize_t wakeup_expire_count_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
unsigned long count = 0;
bool enabled = false;
spin_lock_irq(&dev->power.lock);
if (dev->power.wakeup) {
- count = dev->power.wakeup->hit_count;
+ count = dev->power.wakeup->expire_count;
enabled = true;
}
spin_unlock_irq(&dev->power.lock);
return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n");
}
-static DEVICE_ATTR(wakeup_hit_count, 0444, wakeup_hit_count_show, NULL);
+static DEVICE_ATTR(wakeup_expire_count, 0444, wakeup_expire_count_show, NULL);
static ssize_t wakeup_active_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -398,6 +417,27 @@ static ssize_t wakeup_last_time_show(struct device *dev,
}
static DEVICE_ATTR(wakeup_last_time_ms, 0444, wakeup_last_time_show, NULL);
+
+#ifdef CONFIG_PM_AUTOSLEEP
+static ssize_t wakeup_prevent_sleep_time_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ s64 msec = 0;
+ bool enabled = false;
+
+ spin_lock_irq(&dev->power.lock);
+ if (dev->power.wakeup) {
+ msec = ktime_to_ms(dev->power.wakeup->prevent_sleep_time);
+ enabled = true;
+ }
+ spin_unlock_irq(&dev->power.lock);
+ return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n");
+}
+
+static DEVICE_ATTR(wakeup_prevent_sleep_time_ms, 0444,
+ wakeup_prevent_sleep_time_show, NULL);
+#endif /* CONFIG_PM_AUTOSLEEP */
#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM_ADVANCED_DEBUG
@@ -486,11 +526,15 @@ static struct attribute *wakeup_attrs[] = {
&dev_attr_wakeup.attr,
&dev_attr_wakeup_count.attr,
&dev_attr_wakeup_active_count.attr,
- &dev_attr_wakeup_hit_count.attr,
+ &dev_attr_wakeup_abort_count.attr,
+ &dev_attr_wakeup_expire_count.attr,
&dev_attr_wakeup_active.attr,
&dev_attr_wakeup_total_time_ms.attr,
&dev_attr_wakeup_max_time_ms.attr,
&dev_attr_wakeup_last_time_ms.attr,
+#ifdef CONFIG_PM_AUTOSLEEP
+ &dev_attr_wakeup_prevent_sleep_time_ms.attr,
+#endif
#endif
NULL,
};
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index 2a3e581b8dcd..cbb463b3a750 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -14,16 +14,15 @@
#include <linux/suspend.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
+#include <trace/events/power.h>
#include "power.h"
-#define TIMEOUT 100
-
/*
* If set, the suspend/hibernate code will abort transitions to a sleep state
* if wakeup events are registered during or immediately before the transition.
*/
-bool events_check_enabled;
+bool events_check_enabled __read_mostly;
/*
* Combined counters of registered wakeup events and wakeup events in progress.
@@ -52,6 +51,8 @@ static void pm_wakeup_timer_fn(unsigned long data);
static LIST_HEAD(wakeup_sources);
+static DECLARE_WAIT_QUEUE_HEAD(wakeup_count_wait_queue);
+
/**
* wakeup_source_prepare - Prepare a new wakeup source for initialization.
* @ws: Wakeup source to prepare.
@@ -132,6 +133,7 @@ void wakeup_source_add(struct wakeup_source *ws)
spin_lock_init(&ws->lock);
setup_timer(&ws->timer, pm_wakeup_timer_fn, (unsigned long)ws);
ws->active = false;
+ ws->last_time = ktime_get();
spin_lock_irq(&events_lock);
list_add_rcu(&ws->entry, &wakeup_sources);
@@ -374,12 +376,33 @@ EXPORT_SYMBOL_GPL(device_set_wakeup_enable);
*/
static void wakeup_source_activate(struct wakeup_source *ws)
{
+ unsigned int cec;
+
ws->active = true;
ws->active_count++;
ws->last_time = ktime_get();
+ if (ws->autosleep_enabled)
+ ws->start_prevent_time = ws->last_time;
/* Increment the counter of events in progress. */
- atomic_inc(&combined_event_count);
+ cec = atomic_inc_return(&combined_event_count);
+
+ trace_wakeup_source_activate(ws->name, cec);
+}
+
+/**
+ * wakeup_source_report_event - Report wakeup event using the given source.
+ * @ws: Wakeup source to report the event for.
+ */
+static void wakeup_source_report_event(struct wakeup_source *ws)
+{
+ ws->event_count++;
+ /* This is racy, but the counter is approximate anyway. */
+ if (events_check_enabled)
+ ws->wakeup_count++;
+
+ if (!ws->active)
+ wakeup_source_activate(ws);
}
/**
@@ -397,10 +420,7 @@ void __pm_stay_awake(struct wakeup_source *ws)
spin_lock_irqsave(&ws->lock, flags);
- ws->event_count++;
- if (!ws->active)
- wakeup_source_activate(ws);
-
+ wakeup_source_report_event(ws);
del_timer(&ws->timer);
ws->timer_expires = 0;
@@ -432,6 +452,17 @@ void pm_stay_awake(struct device *dev)
}
EXPORT_SYMBOL_GPL(pm_stay_awake);
+#ifdef CONFIG_PM_AUTOSLEEP
+static void update_prevent_sleep_time(struct wakeup_source *ws, ktime_t now)
+{
+ ktime_t delta = ktime_sub(now, ws->start_prevent_time);
+ ws->prevent_sleep_time = ktime_add(ws->prevent_sleep_time, delta);
+}
+#else
+static inline void update_prevent_sleep_time(struct wakeup_source *ws,
+ ktime_t now) {}
+#endif
+
/**
* wakup_source_deactivate - Mark given wakeup source as inactive.
* @ws: Wakeup source to handle.
@@ -442,6 +473,7 @@ EXPORT_SYMBOL_GPL(pm_stay_awake);
*/
static void wakeup_source_deactivate(struct wakeup_source *ws)
{
+ unsigned int cnt, inpr, cec;
ktime_t duration;
ktime_t now;
@@ -468,14 +500,23 @@ static void wakeup_source_deactivate(struct wakeup_source *ws)
if (ktime_to_ns(duration) > ktime_to_ns(ws->max_time))
ws->max_time = duration;
+ ws->last_time = now;
del_timer(&ws->timer);
ws->timer_expires = 0;
+ if (ws->autosleep_enabled)
+ update_prevent_sleep_time(ws, now);
+
/*
* Increment the counter of registered wakeup events and decrement the
* couter of wakeup events in progress simultaneously.
*/
- atomic_add(MAX_IN_PROGRESS, &combined_event_count);
+ cec = atomic_add_return(MAX_IN_PROGRESS, &combined_event_count);
+ trace_wakeup_source_deactivate(ws->name, cec);
+
+ split_counters(&cnt, &inpr);
+ if (!inpr && waitqueue_active(&wakeup_count_wait_queue))
+ wake_up(&wakeup_count_wait_queue);
}
/**
@@ -536,8 +577,10 @@ static void pm_wakeup_timer_fn(unsigned long data)
spin_lock_irqsave(&ws->lock, flags);
if (ws->active && ws->timer_expires
- && time_after_eq(jiffies, ws->timer_expires))
+ && time_after_eq(jiffies, ws->timer_expires)) {
wakeup_source_deactivate(ws);
+ ws->expire_count++;
+ }
spin_unlock_irqrestore(&ws->lock, flags);
}
@@ -564,9 +607,7 @@ void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec)
spin_lock_irqsave(&ws->lock, flags);
- ws->event_count++;
- if (!ws->active)
- wakeup_source_activate(ws);
+ wakeup_source_report_event(ws);
if (!msec) {
wakeup_source_deactivate(ws);
@@ -609,24 +650,6 @@ void pm_wakeup_event(struct device *dev, unsigned int msec)
EXPORT_SYMBOL_GPL(pm_wakeup_event);
/**
- * pm_wakeup_update_hit_counts - Update hit counts of all active wakeup sources.
- */
-static void pm_wakeup_update_hit_counts(void)
-{
- unsigned long flags;
- struct wakeup_source *ws;
-
- rcu_read_lock();
- list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
- spin_lock_irqsave(&ws->lock, flags);
- if (ws->active)
- ws->hit_count++;
- spin_unlock_irqrestore(&ws->lock, flags);
- }
- rcu_read_unlock();
-}
-
-/**
* pm_wakeup_pending - Check if power transition in progress should be aborted.
*
* Compare the current number of registered wakeup events with its preserved
@@ -648,32 +671,38 @@ bool pm_wakeup_pending(void)
events_check_enabled = !ret;
}
spin_unlock_irqrestore(&events_lock, flags);
- if (ret)
- pm_wakeup_update_hit_counts();
return ret;
}
/**
* pm_get_wakeup_count - Read the number of registered wakeup events.
* @count: Address to store the value at.
+ * @block: Whether or not to block.
*
- * Store the number of registered wakeup events at the address in @count. Block
- * if the current number of wakeup events being processed is nonzero.
+ * Store the number of registered wakeup events at the address in @count. If
+ * @block is set, block until the current number of wakeup events being
+ * processed is zero.
*
- * Return 'false' if the wait for the number of wakeup events being processed to
- * drop down to zero has been interrupted by a signal (and the current number
- * of wakeup events being processed is still nonzero). Otherwise return 'true'.
+ * Return 'false' if the current number of wakeup events being processed is
+ * nonzero. Otherwise return 'true'.
*/
-bool pm_get_wakeup_count(unsigned int *count)
+bool pm_get_wakeup_count(unsigned int *count, bool block)
{
unsigned int cnt, inpr;
- for (;;) {
- split_counters(&cnt, &inpr);
- if (inpr == 0 || signal_pending(current))
- break;
- pm_wakeup_update_hit_counts();
- schedule_timeout_interruptible(msecs_to_jiffies(TIMEOUT));
+ if (block) {
+ DEFINE_WAIT(wait);
+
+ for (;;) {
+ prepare_to_wait(&wakeup_count_wait_queue, &wait,
+ TASK_INTERRUPTIBLE);
+ split_counters(&cnt, &inpr);
+ if (inpr == 0 || signal_pending(current))
+ break;
+
+ schedule();
+ }
+ finish_wait(&wakeup_count_wait_queue, &wait);
}
split_counters(&cnt, &inpr);
@@ -703,11 +732,37 @@ bool pm_save_wakeup_count(unsigned int count)
events_check_enabled = true;
}
spin_unlock_irq(&events_lock);
- if (!events_check_enabled)
- pm_wakeup_update_hit_counts();
return events_check_enabled;
}
+#ifdef CONFIG_PM_AUTOSLEEP
+/**
+ * pm_wakep_autosleep_enabled - Modify autosleep_enabled for all wakeup sources.
+ * @enabled: Whether to set or to clear the autosleep_enabled flags.
+ */
+void pm_wakep_autosleep_enabled(bool set)
+{
+ struct wakeup_source *ws;
+ ktime_t now = ktime_get();
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
+ spin_lock_irq(&ws->lock);
+ if (ws->autosleep_enabled != set) {
+ ws->autosleep_enabled = set;
+ if (ws->active) {
+ if (set)
+ ws->start_prevent_time = now;
+ else
+ update_prevent_sleep_time(ws, now);
+ }
+ }
+ spin_unlock_irq(&ws->lock);
+ }
+ rcu_read_unlock();
+}
+#endif /* CONFIG_PM_AUTOSLEEP */
+
static struct dentry *wakeup_sources_stats_dentry;
/**
@@ -723,27 +778,37 @@ static int print_wakeup_source_stats(struct seq_file *m,
ktime_t max_time;
unsigned long active_count;
ktime_t active_time;
+ ktime_t prevent_sleep_time;
int ret;
spin_lock_irqsave(&ws->lock, flags);
total_time = ws->total_time;
max_time = ws->max_time;
+ prevent_sleep_time = ws->prevent_sleep_time;
active_count = ws->active_count;
if (ws->active) {
- active_time = ktime_sub(ktime_get(), ws->last_time);
+ ktime_t now = ktime_get();
+
+ active_time = ktime_sub(now, ws->last_time);
total_time = ktime_add(total_time, active_time);
if (active_time.tv64 > max_time.tv64)
max_time = active_time;
+
+ if (ws->autosleep_enabled)
+ prevent_sleep_time = ktime_add(prevent_sleep_time,
+ ktime_sub(now, ws->start_prevent_time));
} else {
active_time = ktime_set(0, 0);
}
- ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t"
- "%lld\t\t%lld\t\t%lld\t\t%lld\n",
- ws->name, active_count, ws->event_count, ws->hit_count,
+ ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t%lu\t\t"
+ "%lld\t\t%lld\t\t%lld\t\t%lld\t\t%lld\n",
+ ws->name, active_count, ws->event_count,
+ ws->wakeup_count, ws->expire_count,
ktime_to_ms(active_time), ktime_to_ms(total_time),
- ktime_to_ms(max_time), ktime_to_ms(ws->last_time));
+ ktime_to_ms(max_time), ktime_to_ms(ws->last_time),
+ ktime_to_ms(prevent_sleep_time));
spin_unlock_irqrestore(&ws->lock, flags);
@@ -758,8 +823,9 @@ static int wakeup_sources_stats_show(struct seq_file *m, void *unused)
{
struct wakeup_source *ws;
- seq_puts(m, "name\t\tactive_count\tevent_count\thit_count\t"
- "active_since\ttotal_time\tmax_time\tlast_change\n");
+ seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t"
+ "expire_count\tactive_since\ttotal_time\tmax_time\t"
+ "last_change\tprevent_suspend_time\n");
rcu_read_lock();
list_for_each_entry_rcu(ws, &wakeup_sources, entry)
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig
index 9ef0a5326f17..6be390bd8bd1 100644
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -6,6 +6,7 @@ config REGMAP
default y if (REGMAP_I2C || REGMAP_SPI)
select LZO_COMPRESS
select LZO_DECOMPRESS
+ select IRQ_DOMAIN if REGMAP_IRQ
bool
config REGMAP_I2C
diff --git a/drivers/bcma/core.c b/drivers/bcma/core.c
index 893f6e0c759f..bc6e89212ad3 100644
--- a/drivers/bcma/core.c
+++ b/drivers/bcma/core.c
@@ -30,6 +30,7 @@ void bcma_core_disable(struct bcma_device *core, u32 flags)
udelay(10);
bcma_awrite32(core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET);
+ bcma_aread32(core, BCMA_RESET_CTL);
udelay(1);
}
EXPORT_SYMBOL_GPL(bcma_core_disable);
@@ -77,7 +78,7 @@ void bcma_core_set_clockmode(struct bcma_device *core,
pr_err("HT force timeout\n");
break;
case BCMA_CLKMODE_DYNAMIC:
- pr_warn("Dynamic clockmode not supported yet!\n");
+ bcma_set32(core, BCMA_CLKCTLST, ~BCMA_CLKCTLST_FORCEHT);
break;
}
}
diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c
index 4d38ae179b48..9a96f14c8f47 100644
--- a/drivers/bcma/driver_pci.c
+++ b/drivers/bcma/driver_pci.c
@@ -24,14 +24,12 @@ u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address)
return pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_DATA);
}
-#if 0
static void bcma_pcie_write(struct bcma_drv_pci *pc, u32 address, u32 data)
{
pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_ADDR, address);
pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_ADDR);
pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_DATA, data);
}
-#endif
static void bcma_pcie_mdio_set_phy(struct bcma_drv_pci *pc, u8 phy)
{
@@ -170,13 +168,50 @@ static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc)
tmp & ~BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN);
}
+static void bcma_core_pci_fixcfg(struct bcma_drv_pci *pc)
+{
+ struct bcma_device *core = pc->core;
+ u16 val16, core_index;
+ uint regoff;
+
+ regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_PI_OFFSET);
+ core_index = (u16)core->core_index;
+
+ val16 = pcicore_read16(pc, regoff);
+ if (((val16 & BCMA_CORE_PCI_SPROM_PI_MASK) >> BCMA_CORE_PCI_SPROM_PI_SHIFT)
+ != core_index) {
+ val16 = (core_index << BCMA_CORE_PCI_SPROM_PI_SHIFT) |
+ (val16 & ~BCMA_CORE_PCI_SPROM_PI_MASK);
+ pcicore_write16(pc, regoff, val16);
+ }
+}
+
+/* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */
+/* Needs to happen when coming out of 'standby'/'hibernate' */
+static void bcma_core_pci_config_fixup(struct bcma_drv_pci *pc)
+{
+ u16 val16;
+ uint regoff;
+
+ regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_MISC_CONFIG);
+
+ val16 = pcicore_read16(pc, regoff);
+
+ if (!(val16 & BCMA_CORE_PCI_SPROM_L23READY_EXIT_NOPERST)) {
+ val16 |= BCMA_CORE_PCI_SPROM_L23READY_EXIT_NOPERST;
+ pcicore_write16(pc, regoff, val16);
+ }
+}
+
/**************************************************
* Init.
**************************************************/
static void __devinit bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
{
+ bcma_core_pci_fixcfg(pc);
bcma_pcicore_serdes_workaround(pc);
+ bcma_core_pci_config_fixup(pc);
}
void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc)
@@ -224,3 +259,17 @@ out:
return err;
}
EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl);
+
+void bcma_core_pci_extend_L1timer(struct bcma_drv_pci *pc, bool extend)
+{
+ u32 w;
+
+ w = bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG);
+ if (extend)
+ w |= BCMA_CORE_PCI_ASPMTIMER_EXTEND;
+ else
+ w &= ~BCMA_CORE_PCI_ASPMTIMER_EXTEND;
+ bcma_pcie_write(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG, w);
+ bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG);
+}
+EXPORT_SYMBOL_GPL(bcma_core_pci_extend_L1timer);
diff --git a/drivers/bcma/driver_pci_host.c b/drivers/bcma/driver_pci_host.c
index d2097a11c3c7..b9a86edfec39 100644
--- a/drivers/bcma/driver_pci_host.c
+++ b/drivers/bcma/driver_pci_host.c
@@ -119,7 +119,7 @@ static int bcma_extpci_read_config(struct bcma_drv_pci *pc, unsigned int dev,
if (unlikely(!addr))
goto out;
err = -ENOMEM;
- mmio = ioremap_nocache(addr, len);
+ mmio = ioremap_nocache(addr, sizeof(val));
if (!mmio)
goto out;
@@ -171,7 +171,7 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev,
addr = pc->core->addr + BCMA_CORE_PCI_PCICFG0;
addr |= (func << 8);
addr |= (off & 0xfc);
- mmio = ioremap_nocache(addr, len);
+ mmio = ioremap_nocache(addr, sizeof(val));
if (!mmio)
goto out;
}
@@ -180,7 +180,7 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev,
if (unlikely(!addr))
goto out;
err = -ENOMEM;
- mmio = ioremap_nocache(addr, len);
+ mmio = ioremap_nocache(addr, sizeof(val));
if (!mmio)
goto out;
@@ -491,8 +491,8 @@ void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
/* Ok, ready to run, register it to the system.
* The following needs change, if we want to port hostmode
* to non-MIPS platform. */
- io_map_base = (unsigned long)ioremap_nocache(BCMA_SOC_PCI_MEM,
- 0x04000000);
+ io_map_base = (unsigned long)ioremap_nocache(pc_host->mem_resource.start,
+ resource_size(&pc_host->mem_resource));
pc_host->pci_controller.io_map_base = io_map_base;
set_io_port_base(pc_host->pci_controller.io_map_base);
/* Give some time to the PCI controller to configure itself with the new
diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c
index e3928d68802b..6c05cf470f96 100644
--- a/drivers/bcma/host_pci.c
+++ b/drivers/bcma/host_pci.c
@@ -201,6 +201,9 @@ static int __devinit bcma_host_pci_probe(struct pci_dev *dev,
bus->hosttype = BCMA_HOSTTYPE_PCI;
bus->ops = &bcma_host_pci_ops;
+ bus->boardinfo.vendor = bus->host_pci->subsystem_vendor;
+ bus->boardinfo.type = bus->host_pci->subsystem_device;
+
/* Register */
err = bcma_bus_register(bus);
if (err)
@@ -222,7 +225,7 @@ err_kfree_bus:
return err;
}
-static void bcma_host_pci_remove(struct pci_dev *dev)
+static void __devexit bcma_host_pci_remove(struct pci_dev *dev)
{
struct bcma_bus *bus = pci_get_drvdata(dev);
@@ -277,7 +280,7 @@ static struct pci_driver bcma_pci_bridge_driver = {
.name = "bcma-pci-bridge",
.id_table = bcma_pci_bridge_tbl,
.probe = bcma_host_pci_probe,
- .remove = bcma_host_pci_remove,
+ .remove = __devexit_p(bcma_host_pci_remove),
.driver.pm = BCMA_PM_OPS,
};
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index f94cccccfa56..5ed0718fc660 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -19,7 +19,14 @@ struct bcma_device_id_name {
u16 id;
const char *name;
};
-struct bcma_device_id_name bcma_device_names[] = {
+
+static const struct bcma_device_id_name bcma_arm_device_names[] = {
+ { BCMA_CORE_ARM_1176, "ARM 1176" },
+ { BCMA_CORE_ARM_7TDMI, "ARM 7TDMI" },
+ { BCMA_CORE_ARM_CM3, "ARM CM3" },
+};
+
+static const struct bcma_device_id_name bcma_bcm_device_names[] = {
{ BCMA_CORE_OOB_ROUTER, "OOB Router" },
{ BCMA_CORE_INVALID, "Invalid" },
{ BCMA_CORE_CHIPCOMMON, "ChipCommon" },
@@ -27,7 +34,6 @@ struct bcma_device_id_name bcma_device_names[] = {
{ BCMA_CORE_SRAM, "SRAM" },
{ BCMA_CORE_SDRAM, "SDRAM" },
{ BCMA_CORE_PCI, "PCI" },
- { BCMA_CORE_MIPS, "MIPS" },
{ BCMA_CORE_ETHERNET, "Fast Ethernet" },
{ BCMA_CORE_V90, "V90" },
{ BCMA_CORE_USB11_HOSTDEV, "USB 1.1 Hostdev" },
@@ -44,7 +50,6 @@ struct bcma_device_id_name bcma_device_names[] = {
{ BCMA_CORE_PHY_A, "PHY A" },
{ BCMA_CORE_PHY_B, "PHY B" },
{ BCMA_CORE_PHY_G, "PHY G" },
- { BCMA_CORE_MIPS_3302, "MIPS 3302" },
{ BCMA_CORE_USB11_HOST, "USB 1.1 Host" },
{ BCMA_CORE_USB11_DEV, "USB 1.1 Device" },
{ BCMA_CORE_USB20_HOST, "USB 2.0 Host" },
@@ -58,15 +63,11 @@ struct bcma_device_id_name bcma_device_names[] = {
{ BCMA_CORE_PHY_N, "PHY N" },
{ BCMA_CORE_SRAM_CTL, "SRAM Controller" },
{ BCMA_CORE_MINI_MACPHY, "Mini MACPHY" },
- { BCMA_CORE_ARM_1176, "ARM 1176" },
- { BCMA_CORE_ARM_7TDMI, "ARM 7TDMI" },
{ BCMA_CORE_PHY_LP, "PHY LP" },
{ BCMA_CORE_PMU, "PMU" },
{ BCMA_CORE_PHY_SSN, "PHY SSN" },
{ BCMA_CORE_SDIO_DEV, "SDIO Device" },
- { BCMA_CORE_ARM_CM3, "ARM CM3" },
{ BCMA_CORE_PHY_HT, "PHY HT" },
- { BCMA_CORE_MIPS_74K, "MIPS 74K" },
{ BCMA_CORE_MAC_GBIT, "GBit MAC" },
{ BCMA_CORE_DDR12_MEM_CTL, "DDR1/DDR2 Memory Controller" },
{ BCMA_CORE_PCIE_RC, "PCIe Root Complex" },
@@ -79,16 +80,41 @@ struct bcma_device_id_name bcma_device_names[] = {
{ BCMA_CORE_SHIM, "SHIM" },
{ BCMA_CORE_DEFAULT, "Default" },
};
-const char *bcma_device_name(struct bcma_device_id *id)
+
+static const struct bcma_device_id_name bcma_mips_device_names[] = {
+ { BCMA_CORE_MIPS, "MIPS" },
+ { BCMA_CORE_MIPS_3302, "MIPS 3302" },
+ { BCMA_CORE_MIPS_74K, "MIPS 74K" },
+};
+
+static const char *bcma_device_name(const struct bcma_device_id *id)
{
- int i;
+ const struct bcma_device_id_name *names;
+ int size, i;
+
+ /* search manufacturer specific names */
+ switch (id->manuf) {
+ case BCMA_MANUF_ARM:
+ names = bcma_arm_device_names;
+ size = ARRAY_SIZE(bcma_arm_device_names);
+ break;
+ case BCMA_MANUF_BCM:
+ names = bcma_bcm_device_names;
+ size = ARRAY_SIZE(bcma_bcm_device_names);
+ break;
+ case BCMA_MANUF_MIPS:
+ names = bcma_mips_device_names;
+ size = ARRAY_SIZE(bcma_mips_device_names);
+ break;
+ default:
+ return "UNKNOWN";
+ }
- if (id->manuf == BCMA_MANUF_BCM) {
- for (i = 0; i < ARRAY_SIZE(bcma_device_names); i++) {
- if (bcma_device_names[i].id == id->id)
- return bcma_device_names[i].name;
- }
+ for (i = 0; i < size; i++) {
+ if (names[i].id == id->id)
+ return names[i].name;
}
+
return "UNKNOWN";
}
@@ -297,6 +323,23 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
return -EILSEQ;
}
+ /* First Slave Address Descriptor should be port 0:
+ * the main register space for the core
+ */
+ tmp = bcma_erom_get_addr_desc(bus, eromptr, SCAN_ADDR_TYPE_SLAVE, 0);
+ if (tmp <= 0) {
+ /* Try again to see if it is a bridge */
+ tmp = bcma_erom_get_addr_desc(bus, eromptr,
+ SCAN_ADDR_TYPE_BRIDGE, 0);
+ if (tmp <= 0) {
+ return -EILSEQ;
+ } else {
+ pr_info("Bridge found\n");
+ return -ENXIO;
+ }
+ }
+ core->addr = tmp;
+
/* get & parse slave ports */
for (i = 0; i < ports[1]; i++) {
for (j = 0; ; j++) {
@@ -309,7 +352,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
break;
} else {
if (i == 0 && j == 0)
- core->addr = tmp;
+ core->addr1 = tmp;
}
}
}
diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c
index 3e2a6002aae6..c7f93359acb0 100644
--- a/drivers/bcma/sprom.c
+++ b/drivers/bcma/sprom.c
@@ -181,6 +181,22 @@ static int bcma_sprom_valid(const u16 *sprom)
#define SPEX(_field, _offset, _mask, _shift) \
bus->sprom._field = ((sprom[SPOFF(_offset)] & (_mask)) >> (_shift))
+#define SPEX32(_field, _offset, _mask, _shift) \
+ bus->sprom._field = ((((u32)sprom[SPOFF((_offset)+2)] << 16 | \
+ sprom[SPOFF(_offset)]) & (_mask)) >> (_shift))
+
+#define SPEX_ARRAY8(_field, _offset, _mask, _shift) \
+ do { \
+ SPEX(_field[0], _offset + 0, _mask, _shift); \
+ SPEX(_field[1], _offset + 2, _mask, _shift); \
+ SPEX(_field[2], _offset + 4, _mask, _shift); \
+ SPEX(_field[3], _offset + 6, _mask, _shift); \
+ SPEX(_field[4], _offset + 8, _mask, _shift); \
+ SPEX(_field[5], _offset + 10, _mask, _shift); \
+ SPEX(_field[6], _offset + 12, _mask, _shift); \
+ SPEX(_field[7], _offset + 14, _mask, _shift); \
+ } while (0)
+
static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
{
u16 v, o;
@@ -243,7 +259,8 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, ~0, 0);
SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, ~0, 0);
- SPEX(country_code, SSB_SPROM8_CCODE, ~0, 0);
+ SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
+ SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
/* Extract cores power info info */
for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
@@ -298,6 +315,136 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
SSB_SROM8_FEM_TR_ISO_SHIFT);
SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_ANTSWLUT,
SSB_SROM8_FEM_ANTSWLUT_SHIFT);
+
+ SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A,
+ SSB_SPROM8_ANTAVAIL_A_SHIFT);
+ SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG,
+ SSB_SPROM8_ANTAVAIL_BG_SHIFT);
+ SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0);
+ SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG,
+ SSB_SPROM8_ITSSI_BG_SHIFT);
+ SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0);
+ SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A,
+ SSB_SPROM8_ITSSI_A_SHIFT);
+ SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0);
+ SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK,
+ SSB_SPROM8_MAXP_AL_SHIFT);
+ SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0);
+ SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1,
+ SSB_SPROM8_GPIOA_P1_SHIFT);
+ SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0);
+ SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3,
+ SSB_SPROM8_GPIOB_P3_SHIFT);
+ SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0);
+ SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G,
+ SSB_SPROM8_TRI5G_SHIFT);
+ SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0);
+ SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH,
+ SSB_SPROM8_TRI5GH_SHIFT);
+ SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G,
+ SSB_SPROM8_RXPO2G_SHIFT);
+ SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G,
+ SSB_SPROM8_RXPO5G_SHIFT);
+ SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0);
+ SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G,
+ SSB_SPROM8_RSSISMC2G_SHIFT);
+ SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G,
+ SSB_SPROM8_RSSISAV2G_SHIFT);
+ SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G,
+ SSB_SPROM8_BXA2G_SHIFT);
+ SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0);
+ SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G,
+ SSB_SPROM8_RSSISMC5G_SHIFT);
+ SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G,
+ SSB_SPROM8_RSSISAV5G_SHIFT);
+ SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G,
+ SSB_SPROM8_BXA5G_SHIFT);
+
+ SPEX(pa0b0, SSB_SPROM8_PA0B0, ~0, 0);
+ SPEX(pa0b1, SSB_SPROM8_PA0B1, ~0, 0);
+ SPEX(pa0b2, SSB_SPROM8_PA0B2, ~0, 0);
+ SPEX(pa1b0, SSB_SPROM8_PA1B0, ~0, 0);
+ SPEX(pa1b1, SSB_SPROM8_PA1B1, ~0, 0);
+ SPEX(pa1b2, SSB_SPROM8_PA1B2, ~0, 0);
+ SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, ~0, 0);
+ SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, ~0, 0);
+ SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, ~0, 0);
+ SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, ~0, 0);
+ SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, ~0, 0);
+ SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, ~0, 0);
+ SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, ~0, 0);
+ SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, ~0, 0);
+ SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, ~0, 0);
+ SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, ~0, 0);
+ SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, ~0, 0);
+
+ /* Extract the antenna gain values. */
+ SPEX(antenna_gain.a0, SSB_SPROM8_AGAIN01,
+ SSB_SPROM8_AGAIN0, SSB_SPROM8_AGAIN0_SHIFT);
+ SPEX(antenna_gain.a1, SSB_SPROM8_AGAIN01,
+ SSB_SPROM8_AGAIN1, SSB_SPROM8_AGAIN1_SHIFT);
+ SPEX(antenna_gain.a2, SSB_SPROM8_AGAIN23,
+ SSB_SPROM8_AGAIN2, SSB_SPROM8_AGAIN2_SHIFT);
+ SPEX(antenna_gain.a3, SSB_SPROM8_AGAIN23,
+ SSB_SPROM8_AGAIN3, SSB_SPROM8_AGAIN3_SHIFT);
+
+ SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON,
+ SSB_SPROM8_LEDDC_ON_SHIFT);
+ SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF,
+ SSB_SPROM8_LEDDC_OFF_SHIFT);
+
+ SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN,
+ SSB_SPROM8_TXRXC_TXCHAIN_SHIFT);
+ SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN,
+ SSB_SPROM8_TXRXC_RXCHAIN_SHIFT);
+ SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH,
+ SSB_SPROM8_TXRXC_SWITCH_SHIFT);
+
+ SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0);
+
+ SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0);
+ SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0);
+ SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0);
+ SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0);
+
+ SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP,
+ SSB_SPROM8_RAWTS_RAWTEMP_SHIFT);
+ SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER,
+ SSB_SPROM8_RAWTS_MEASPOWER_SHIFT);
+ SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX,
+ SSB_SPROM8_OPT_CORRX_TEMP_SLOPE,
+ SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT);
+ SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX,
+ SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT);
+ SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX,
+ SSB_SPROM8_OPT_CORRX_TEMP_OPTION,
+ SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT);
+ SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP,
+ SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR,
+ SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT);
+ SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP,
+ SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP,
+ SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT);
+ SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL,
+ SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT);
+
+ SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0);
+ SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0);
+ SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0);
+ SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0);
+
+ SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH,
+ SSB_SPROM8_THERMAL_TRESH_SHIFT);
+ SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET,
+ SSB_SPROM8_THERMAL_OFFSET_SHIFT);
+ SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA,
+ SSB_SPROM8_TEMPDELTA_PHYCAL,
+ SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT);
+ SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD,
+ SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT);
+ SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA,
+ SSB_SPROM8_TEMPDELTA_HYSTERESIS,
+ SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT);
}
/*
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 57fd867553d7..ad591bd240ec 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -81,6 +81,9 @@ static struct usb_device_id ath3k_table[] = {
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE02C) },
+ /* Atheros AR5BBU22 with sflash firmware */
+ { USB_DEVICE(0x0489, 0xE03C) },
+
{ } /* Terminating entry */
};
@@ -99,6 +102,9 @@ static struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
+ /* Atheros AR5BBU22 with sflash firmware */
+ { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
+
{ } /* Terminating entry */
};
@@ -439,6 +445,7 @@ static struct usb_driver ath3k_driver = {
.probe = ath3k_probe,
.disconnect = ath3k_disconnect,
.id_table = ath3k_table,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(ath3k_driver);
diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c
index 1e742a50e2cd..37ae175162f3 100644
--- a/drivers/bluetooth/bcm203x.c
+++ b/drivers/bluetooth/bcm203x.c
@@ -279,6 +279,7 @@ static struct usb_driver bcm203x_driver = {
.probe = bcm203x_probe,
.disconnect = bcm203x_disconnect,
.id_table = bcm203x_table,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(bcm203x_driver);
diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c
index b8ac1c549a1c..32e825144fe9 100644
--- a/drivers/bluetooth/bfusb.c
+++ b/drivers/bluetooth/bfusb.c
@@ -749,6 +749,7 @@ static struct usb_driver bfusb_driver = {
.probe = bfusb_probe,
.disconnect = bfusb_disconnect,
.id_table = bfusb_table,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(bfusb_driver);
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
index d894340a7601..609861a53c28 100644
--- a/drivers/bluetooth/bpa10x.c
+++ b/drivers/bluetooth/bpa10x.c
@@ -508,6 +508,7 @@ static struct usb_driver bpa10x_driver = {
.probe = bpa10x_probe,
.disconnect = bpa10x_disconnect,
.id_table = bpa10x_table,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(bpa10x_driver);
diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h
index 90bda50dc446..94f2d65131c4 100644
--- a/drivers/bluetooth/btmrvl_drv.h
+++ b/drivers/bluetooth/btmrvl_drv.h
@@ -67,6 +67,7 @@ struct btmrvl_adapter {
u8 wakeup_tries;
wait_queue_head_t cmd_wait_q;
u8 cmd_complete;
+ bool is_suspended;
};
struct btmrvl_private {
@@ -139,8 +140,10 @@ void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb);
int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb);
int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd);
+int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv);
int btmrvl_enable_ps(struct btmrvl_private *priv);
int btmrvl_prepare_command(struct btmrvl_private *priv);
+int btmrvl_enable_hs(struct btmrvl_private *priv);
#ifdef CONFIG_DEBUG_FS
void btmrvl_debugfs_init(struct hci_dev *hdev);
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
index d1209adc882d..681ca9d18e12 100644
--- a/drivers/bluetooth/btmrvl_main.c
+++ b/drivers/bluetooth/btmrvl_main.c
@@ -200,6 +200,36 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd)
}
EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd);
+int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv)
+{
+ struct sk_buff *skb;
+ struct btmrvl_cmd *cmd;
+
+ skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
+ if (!skb) {
+ BT_ERR("No free skb");
+ return -ENOMEM;
+ }
+
+ cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));
+ cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF,
+ BT_CMD_HOST_SLEEP_CONFIG));
+ cmd->length = 2;
+ cmd->data[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8;
+ cmd->data[1] = (u8) (priv->btmrvl_dev.gpio_gap & 0x00ff);
+
+ bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
+
+ skb->dev = (void *) priv->btmrvl_dev.hcidev;
+ skb_queue_head(&priv->adapter->tx_queue, skb);
+
+ BT_DBG("Queue HSCFG Command, gpio=0x%x, gap=0x%x", cmd->data[0],
+ cmd->data[1]);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(btmrvl_send_hscfg_cmd);
+
int btmrvl_enable_ps(struct btmrvl_private *priv)
{
struct sk_buff *skb;
@@ -232,7 +262,7 @@ int btmrvl_enable_ps(struct btmrvl_private *priv)
}
EXPORT_SYMBOL_GPL(btmrvl_enable_ps);
-static int btmrvl_enable_hs(struct btmrvl_private *priv)
+int btmrvl_enable_hs(struct btmrvl_private *priv)
{
struct sk_buff *skb;
struct btmrvl_cmd *cmd;
@@ -268,35 +298,15 @@ static int btmrvl_enable_hs(struct btmrvl_private *priv)
return ret;
}
+EXPORT_SYMBOL_GPL(btmrvl_enable_hs);
int btmrvl_prepare_command(struct btmrvl_private *priv)
{
- struct sk_buff *skb = NULL;
- struct btmrvl_cmd *cmd;
int ret = 0;
if (priv->btmrvl_dev.hscfgcmd) {
priv->btmrvl_dev.hscfgcmd = 0;
-
- skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
- if (skb == NULL) {
- BT_ERR("No free skb");
- return -ENOMEM;
- }
-
- cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));
- cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_HOST_SLEEP_CONFIG));
- cmd->length = 2;
- cmd->data[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8;
- cmd->data[1] = (u8) (priv->btmrvl_dev.gpio_gap & 0x00ff);
-
- bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
-
- skb->dev = (void *) priv->btmrvl_dev.hcidev;
- skb_queue_head(&priv->adapter->tx_queue, skb);
-
- BT_DBG("Queue HSCFG Command, gpio=0x%x, gap=0x%x",
- cmd->data[0], cmd->data[1]);
+ btmrvl_send_hscfg_cmd(priv);
}
if (priv->btmrvl_dev.pscmd) {
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index 27b74b0d547b..a853244e7fd7 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -339,9 +339,7 @@ static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card)
done:
kfree(tmphlprbuf);
- if (fw_helper)
- release_firmware(fw_helper);
-
+ release_firmware(fw_helper);
return ret;
}
@@ -484,10 +482,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
done:
kfree(tmpfwbuf);
-
- if (fw_firmware)
- release_firmware(fw_firmware);
-
+ release_firmware(fw_firmware);
return ret;
}
@@ -1013,6 +1008,9 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
priv->btmrvl_dev.psmode = 1;
btmrvl_enable_ps(priv);
+ priv->btmrvl_dev.gpio_gap = 0xffff;
+ btmrvl_send_hscfg_cmd(priv);
+
return 0;
disable_host_int:
@@ -1048,11 +1046,111 @@ static void btmrvl_sdio_remove(struct sdio_func *func)
}
}
+static int btmrvl_sdio_suspend(struct device *dev)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ struct btmrvl_sdio_card *card;
+ struct btmrvl_private *priv;
+ mmc_pm_flag_t pm_flags;
+ struct hci_dev *hcidev;
+
+ if (func) {
+ pm_flags = sdio_get_host_pm_caps(func);
+ BT_DBG("%s: suspend: PM flags = 0x%x", sdio_func_id(func),
+ pm_flags);
+ if (!(pm_flags & MMC_PM_KEEP_POWER)) {
+ BT_ERR("%s: cannot remain alive while suspended",
+ sdio_func_id(func));
+ return -ENOSYS;
+ }
+ card = sdio_get_drvdata(func);
+ if (!card || !card->priv) {
+ BT_ERR("card or priv structure is not valid");
+ return 0;
+ }
+ } else {
+ BT_ERR("sdio_func is not specified");
+ return 0;
+ }
+
+ priv = card->priv;
+
+ if (priv->adapter->hs_state != HS_ACTIVATED) {
+ if (btmrvl_enable_hs(priv)) {
+ BT_ERR("HS not actived, suspend failed!");
+ return -EBUSY;
+ }
+ }
+ hcidev = priv->btmrvl_dev.hcidev;
+ BT_DBG("%s: SDIO suspend", hcidev->name);
+ hci_suspend_dev(hcidev);
+ skb_queue_purge(&priv->adapter->tx_queue);
+
+ priv->adapter->is_suspended = true;
+
+ /* We will keep the power when hs enabled successfully */
+ if (priv->adapter->hs_state == HS_ACTIVATED) {
+ BT_DBG("suspend with MMC_PM_KEEP_POWER");
+ return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+ } else {
+ BT_DBG("suspend without MMC_PM_KEEP_POWER");
+ return 0;
+ }
+}
+
+static int btmrvl_sdio_resume(struct device *dev)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ struct btmrvl_sdio_card *card;
+ struct btmrvl_private *priv;
+ mmc_pm_flag_t pm_flags;
+ struct hci_dev *hcidev;
+
+ if (func) {
+ pm_flags = sdio_get_host_pm_caps(func);
+ BT_DBG("%s: resume: PM flags = 0x%x", sdio_func_id(func),
+ pm_flags);
+ card = sdio_get_drvdata(func);
+ if (!card || !card->priv) {
+ BT_ERR("card or priv structure is not valid");
+ return 0;
+ }
+ } else {
+ BT_ERR("sdio_func is not specified");
+ return 0;
+ }
+ priv = card->priv;
+
+ if (!priv->adapter->is_suspended) {
+ BT_DBG("device already resumed");
+ return 0;
+ }
+
+ priv->adapter->is_suspended = false;
+ hcidev = priv->btmrvl_dev.hcidev;
+ BT_DBG("%s: SDIO resume", hcidev->name);
+ hci_resume_dev(hcidev);
+ priv->hw_wakeup_firmware(priv);
+ priv->adapter->hs_state = HS_DEACTIVATED;
+ BT_DBG("%s: HS DEACTIVATED in resume!", hcidev->name);
+
+ return 0;
+}
+
+static const struct dev_pm_ops btmrvl_sdio_pm_ops = {
+ .suspend = btmrvl_sdio_suspend,
+ .resume = btmrvl_sdio_resume,
+};
+
static struct sdio_driver bt_mrvl_sdio = {
.name = "btmrvl_sdio",
.id_table = btmrvl_sdio_ids,
.probe = btmrvl_sdio_probe,
.remove = btmrvl_sdio_remove,
+ .drv = {
+ .owner = THIS_MODULE,
+ .pm = &btmrvl_sdio_pm_ops,
+ }
};
static int __init btmrvl_sdio_init_module(void)
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 9217121362e1..c9463af8e564 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -143,6 +143,9 @@ static struct usb_device_id blacklist_table[] = {
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
+ /* Atheros AR5BBU12 with sflash firmware */
+ { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
+
/* Broadcom BCM2035 */
{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
@@ -855,6 +858,7 @@ static void btusb_work(struct work_struct *work)
{
struct btusb_data *data = container_of(work, struct btusb_data, work);
struct hci_dev *hdev = data->hdev;
+ int new_alts;
int err;
if (hdev->conn_hash.sco_num > 0) {
@@ -868,11 +872,19 @@ static void btusb_work(struct work_struct *work)
set_bit(BTUSB_DID_ISO_RESUME, &data->flags);
}
- if (data->isoc_altsetting != 2) {
+
+ if (hdev->voice_setting & 0x0020) {
+ static const int alts[3] = { 2, 4, 5 };
+ new_alts = alts[hdev->conn_hash.sco_num - 1];
+ } else {
+ new_alts = hdev->conn_hash.sco_num;
+ }
+
+ if (data->isoc_altsetting != new_alts) {
clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
usb_kill_anchored_urbs(&data->isoc_anchor);
- if (__set_isoc_interface(hdev, 2) < 0)
+ if (__set_isoc_interface(hdev, new_alts) < 0)
return;
}
@@ -1218,6 +1230,7 @@ static struct usb_driver btusb_driver = {
#endif
.id_table = btusb_table,
.supports_autosuspend = 1,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(btusb_driver);
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 98a8c05d4f23..e564579a6115 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -388,7 +388,7 @@ static int hci_uart_register_dev(struct hci_uart *hu)
hdev->close = hci_uart_close;
hdev->flush = hci_uart_flush;
hdev->send = hci_uart_send_frame;
- hdev->parent = hu->tty->dev;
+ SET_HCIDEV_DEV(hdev, hu->tty->dev);
if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags))
set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
index 158bfe507da7..3f72595a6017 100644
--- a/drivers/bluetooth/hci_vhci.c
+++ b/drivers/bluetooth/hci_vhci.c
@@ -252,8 +252,9 @@ static int vhci_open(struct inode *inode, struct file *file)
}
file->private_data = data;
+ nonseekable_open(inode, file);
- return nonseekable_open(inode, file);
+ return 0;
}
static int vhci_release(struct inode *inode, struct file *file)
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index ee946865d6cb..ea6f6325f9ba 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -585,14 +585,6 @@ config DEVPORT
source "drivers/s390/char/Kconfig"
-config RAMOOPS
- tristate "Log panic/oops to a RAM buffer"
- depends on HAS_IOMEM
- default n
- help
- This enables panic and oops messages to be logged to a circular
- buffer in RAM where it can be read back at some later point.
-
config MSM_SMD_PKT
bool "Enable device interface for some SMD packet ports"
default n
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 0dc5d7ce4864..d0b27a39f1d4 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -58,7 +58,6 @@ obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o
obj-$(CONFIG_TCG_TPM) += tpm/
obj-$(CONFIG_PS3_FLASH) += ps3flash.o
-obj-$(CONFIG_RAMOOPS) += ramoops.o
obj-$(CONFIG_JS_RTC) += js-rtc.o
js-rtc-y = rtc.o
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 17e05d1076b3..a0df182f6f7d 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -958,7 +958,7 @@ int agp_generic_create_gatt_table(struct agp_bridge_data *bridge)
if (set_memory_uc((unsigned long)table, 1 << page_order))
printk(KERN_WARNING "Could not set GATT table memory to UC!\n");
- bridge->gatt_table = (void *)table;
+ bridge->gatt_table = (u32 __iomem *)table;
#else
bridge->gatt_table = ioremap_nocache(virt_to_phys(table),
(PAGE_SIZE * (1 << page_order)));
@@ -1010,7 +1010,6 @@ int agp_generic_free_gatt_table(struct agp_bridge_data *bridge)
case LVL2_APER_SIZE:
/* The generic routines can't deal with 2 level gatt's */
return -EINVAL;
- break;
default:
page_order = 0;
break;
@@ -1077,7 +1076,6 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
case LVL2_APER_SIZE:
/* The generic routines can't deal with 2 level gatt's */
return -EINVAL;
- break;
default:
num_entries = 0;
break;
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 962e75dc4781..764f70c5e690 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -907,6 +907,11 @@ static struct pci_device_id agp_intel_pci_table[] = {
ID(PCI_DEVICE_ID_INTEL_IVYBRIDGE_HB),
ID(PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_HB),
ID(PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_HB),
+ ID(PCI_DEVICE_ID_INTEL_VALLEYVIEW_HB),
+ ID(PCI_DEVICE_ID_INTEL_HASWELL_HB),
+ ID(PCI_DEVICE_ID_INTEL_HASWELL_M_HB),
+ ID(PCI_DEVICE_ID_INTEL_HASWELL_S_HB),
+ ID(PCI_DEVICE_ID_INTEL_HASWELL_E_HB),
{ }
};
diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h
index 7ea18a5fe71c..c0091753a0d1 100644
--- a/drivers/char/agp/intel-agp.h
+++ b/drivers/char/agp/intel-agp.h
@@ -96,6 +96,7 @@
#define G4x_GMCH_SIZE_VT_2M (G4x_GMCH_SIZE_2M | G4x_GMCH_SIZE_VT_EN)
#define GFX_FLSH_CNTL 0x2170 /* 915+ */
+#define GFX_FLSH_CNTL_VLV 0x101008
#define I810_DRAM_CTL 0x3000
#define I810_DRAM_ROW_0 0x00000001
@@ -235,6 +236,19 @@
#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_HB 0x0158 /* Server */
#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT1_IG 0x015A
#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT2_IG 0x016A
+#define PCI_DEVICE_ID_INTEL_VALLEYVIEW_HB 0x0F00 /* VLV1 */
+#define PCI_DEVICE_ID_INTEL_VALLEYVIEW_IG 0x0F30
+#define PCI_DEVICE_ID_INTEL_HASWELL_HB 0x0400 /* Desktop */
+#define PCI_DEVICE_ID_INTEL_HASWELL_D_GT1_IG 0x0402
+#define PCI_DEVICE_ID_INTEL_HASWELL_D_GT2_IG 0x0412
+#define PCI_DEVICE_ID_INTEL_HASWELL_M_HB 0x0404 /* Mobile */
+#define PCI_DEVICE_ID_INTEL_HASWELL_M_GT1_IG 0x0406
+#define PCI_DEVICE_ID_INTEL_HASWELL_M_GT2_IG 0x0416
+#define PCI_DEVICE_ID_INTEL_HASWELL_S_HB 0x0408 /* Server */
+#define PCI_DEVICE_ID_INTEL_HASWELL_S_GT1_IG 0x040a
+#define PCI_DEVICE_ID_INTEL_HASWELL_S_GT2_IG 0x041a
+#define PCI_DEVICE_ID_INTEL_HASWELL_SDV 0x0c16 /* SDV */
+#define PCI_DEVICE_ID_INTEL_HASWELL_E_HB 0x0c04
int intel_gmch_probe(struct pci_dev *pdev,
struct agp_bridge_data *bridge);
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
index 7f025fb620de..1237e7575c3f 100644
--- a/drivers/char/agp/intel-gtt.c
+++ b/drivers/char/agp/intel-gtt.c
@@ -1179,6 +1179,20 @@ static void gen6_write_entry(dma_addr_t addr, unsigned int entry,
writel(addr | pte_flags, intel_private.gtt + entry);
}
+static void valleyview_write_entry(dma_addr_t addr, unsigned int entry,
+ unsigned int flags)
+{
+ u32 pte_flags;
+
+ pte_flags = GEN6_PTE_UNCACHED | I810_PTE_VALID;
+
+ /* gen6 has bit11-4 for physical addr bit39-32 */
+ addr |= (addr >> 28) & 0xff0;
+ writel(addr | pte_flags, intel_private.gtt + entry);
+
+ writel(1, intel_private.registers + GFX_FLSH_CNTL_VLV);
+}
+
static void gen6_cleanup(void)
{
}
@@ -1205,12 +1219,16 @@ static inline int needs_idle_maps(void)
static int i9xx_setup(void)
{
u32 reg_addr;
+ int size = KB(512);
pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &reg_addr);
reg_addr &= 0xfff80000;
- intel_private.registers = ioremap(reg_addr, 128 * 4096);
+ if (INTEL_GTT_GEN >= 7)
+ size = MB(2);
+
+ intel_private.registers = ioremap(reg_addr, size);
if (!intel_private.registers)
return -ENOMEM;
@@ -1354,6 +1372,15 @@ static const struct intel_gtt_driver sandybridge_gtt_driver = {
.check_flags = gen6_check_flags,
.chipset_flush = i9xx_chipset_flush,
};
+static const struct intel_gtt_driver valleyview_gtt_driver = {
+ .gen = 7,
+ .setup = i9xx_setup,
+ .cleanup = gen6_cleanup,
+ .write_entry = valleyview_write_entry,
+ .dma_mask_size = 40,
+ .check_flags = gen6_check_flags,
+ .chipset_flush = i9xx_chipset_flush,
+};
/* Table to describe Intel GMCH and AGP/PCIE GART drivers. At least one of
* driver and gmch_driver must be non-null, and find_gmch will determine
@@ -1460,6 +1487,22 @@ static const struct intel_gtt_driver_description {
"Ivybridge", &sandybridge_gtt_driver },
{ PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT2_IG,
"Ivybridge", &sandybridge_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_VALLEYVIEW_IG,
+ "ValleyView", &valleyview_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_HASWELL_D_GT1_IG,
+ "Haswell", &sandybridge_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_HASWELL_D_GT2_IG,
+ "Haswell", &sandybridge_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_HASWELL_M_GT1_IG,
+ "Haswell", &sandybridge_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_HASWELL_M_GT2_IG,
+ "Haswell", &sandybridge_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_HASWELL_S_GT1_IG,
+ "Haswell", &sandybridge_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_HASWELL_S_GT2_IG,
+ "Haswell", &sandybridge_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_HASWELL_SDV,
+ "Haswell", &sandybridge_gtt_driver },
{ 0, NULL, NULL }
};
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c
index ffa888cd1c88..192000377737 100644
--- a/drivers/char/agp/sgi-agp.c
+++ b/drivers/char/agp/sgi-agp.c
@@ -158,7 +158,6 @@ static int sgi_tioca_insert_memory(struct agp_memory *mem, off_t pg_start,
break;
case LVL2_APER_SIZE:
return -EINVAL;
- break;
default:
num_entries = 0;
break;
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 0689bf6b0183..f45dad39a18b 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -62,8 +62,8 @@ config HW_RANDOM_AMD
config HW_RANDOM_ATMEL
tristate "Atmel Random Number Generator support"
- depends on HW_RANDOM && ARCH_AT91SAM9G45
- default HW_RANDOM
+ depends on HW_RANDOM && HAVE_CLK
+ default (HW_RANDOM && ARCH_AT91)
---help---
This driver provides kernel-side support for the Random Number
Generator hardware found on Atmel AT91 devices.
@@ -250,3 +250,16 @@ config UML_RANDOM
(check your distro, or download from
http://sourceforge.net/projects/gkernel/). rngd periodically reads
/dev/hwrng and injects the entropy into /dev/random.
+
+config HW_RANDOM_PSERIES
+ tristate "pSeries HW Random Number Generator support"
+ depends on HW_RANDOM && PPC64 && IBMVIO
+ default HW_RANDOM
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on POWER7+ machines and above
+
+ To compile this driver as a module, choose M here: the
+ module will be called pseries-rng.
+
+ If unsure, say Y.
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index b2ff5265a996..d901dfa30321 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -22,3 +22,4 @@ obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o
obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o
obj-$(CONFIG_HW_RANDOM_PICOXCELL) += picoxcell-rng.o
obj-$(CONFIG_HW_RANDOM_PPC4XX) += ppc4xx-rng.o
+obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c
index a07a5caa599c..1412565c01af 100644
--- a/drivers/char/hw_random/omap-rng.c
+++ b/drivers/char/hw_random/omap-rng.c
@@ -115,22 +115,12 @@ static int __devinit omap_rng_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- ret = -ENOENT;
- goto err_region;
- }
-
- if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
- ret = -EBUSY;
- goto err_region;
- }
-
- dev_set_drvdata(&pdev->dev, res);
- rng_base = ioremap(res->start, resource_size(res));
+ rng_base = devm_request_and_ioremap(&pdev->dev, res);
if (!rng_base) {
ret = -ENOMEM;
goto err_ioremap;
}
+ dev_set_drvdata(&pdev->dev, res);
ret = hwrng_register(&omap_rng_ops);
if (ret)
@@ -145,11 +135,8 @@ static int __devinit omap_rng_probe(struct platform_device *pdev)
return 0;
err_register:
- iounmap(rng_base);
rng_base = NULL;
err_ioremap:
- release_mem_region(res->start, resource_size(res));
-err_region:
if (cpu_is_omap24xx()) {
clk_disable(rng_ick);
clk_put(rng_ick);
@@ -159,20 +146,15 @@ err_region:
static int __exit omap_rng_remove(struct platform_device *pdev)
{
- struct resource *res = dev_get_drvdata(&pdev->dev);
-
hwrng_unregister(&omap_rng_ops);
omap_rng_write_reg(RNG_MASK_REG, 0x0);
- iounmap(rng_base);
-
if (cpu_is_omap24xx()) {
clk_disable(rng_ick);
clk_put(rng_ick);
}
- release_mem_region(res->start, resource_size(res));
rng_base = NULL;
return 0;
diff --git a/drivers/char/hw_random/pseries-rng.c b/drivers/char/hw_random/pseries-rng.c
new file mode 100644
index 000000000000..5f1197929f0c
--- /dev/null
+++ b/drivers/char/hw_random/pseries-rng.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2010 Michael Neuling IBM Corporation
+ *
+ * Driver for the pseries hardware RNG for POWER7+ and above
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/hw_random.h>
+#include <asm/vio.h>
+
+#define MODULE_NAME "pseries-rng"
+
+static int pseries_rng_data_read(struct hwrng *rng, u32 *data)
+{
+ if (plpar_hcall(H_RANDOM, (unsigned long *)data) != H_SUCCESS) {
+ printk(KERN_ERR "pseries rng hcall error\n");
+ return 0;
+ }
+ return 8;
+}
+
+/**
+ * pseries_rng_get_desired_dma - Return desired DMA allocate for CMO operations
+ *
+ * This is a required function for a driver to operate in a CMO environment
+ * but this device does not make use of DMA allocations, return 0.
+ *
+ * Return value:
+ * Number of bytes of IO data the driver will need to perform well -> 0
+ */
+static unsigned long pseries_rng_get_desired_dma(struct vio_dev *vdev)
+{
+ return 0;
+};
+
+static struct hwrng pseries_rng = {
+ .name = MODULE_NAME,
+ .data_read = pseries_rng_data_read,
+};
+
+static int __init pseries_rng_probe(struct vio_dev *dev,
+ const struct vio_device_id *id)
+{
+ return hwrng_register(&pseries_rng);
+}
+
+static int __exit pseries_rng_remove(struct vio_dev *dev)
+{
+ hwrng_unregister(&pseries_rng);
+ return 0;
+}
+
+static struct vio_device_id pseries_rng_driver_ids[] = {
+ { "ibm,random-v1", "ibm,random"},
+ { "", "" }
+};
+MODULE_DEVICE_TABLE(vio, pseries_rng_driver_ids);
+
+static struct vio_driver pseries_rng_driver = {
+ .name = MODULE_NAME,
+ .probe = pseries_rng_probe,
+ .remove = pseries_rng_remove,
+ .get_desired_dma = pseries_rng_get_desired_dma,
+ .id_table = pseries_rng_driver_ids
+};
+
+static int __init rng_init(void)
+{
+ printk(KERN_INFO "Registering IBM pSeries RNG driver\n");
+ return vio_register_driver(&pseries_rng_driver);
+}
+
+module_init(rng_init);
+
+static void __exit rng_exit(void)
+{
+ vio_unregister_driver(&pseries_rng_driver);
+}
+module_exit(rng_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael Neuling <mikey@neuling.org>");
+MODULE_DESCRIPTION("H/W RNG driver for IBM pSeries processors");
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index d6e9d081c8b1..67c3371723cc 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -807,44 +807,6 @@ static const struct file_operations oldmem_fops = {
};
#endif
-static ssize_t kmsg_writev(struct kiocb *iocb, const struct iovec *iv,
- unsigned long count, loff_t pos)
-{
- char *line, *p;
- int i;
- ssize_t ret = -EFAULT;
- size_t len = iov_length(iv, count);
-
- line = kmalloc(len + 1, GFP_KERNEL);
- if (line == NULL)
- return -ENOMEM;
-
- /*
- * copy all vectors into a single string, to ensure we do
- * not interleave our log line with other printk calls
- */
- p = line;
- for (i = 0; i < count; i++) {
- if (copy_from_user(p, iv[i].iov_base, iv[i].iov_len))
- goto out;
- p += iv[i].iov_len;
- }
- p[0] = '\0';
-
- ret = printk("%s", line);
- /* printk can add a prefix */
- if (ret > len)
- ret = len;
-out:
- kfree(line);
- return ret;
-}
-
-static const struct file_operations kmsg_fops = {
- .aio_write = kmsg_writev,
- .llseek = noop_llseek,
-};
-
static const struct memdev {
const char *name;
umode_t mode;
@@ -863,7 +825,9 @@ static const struct memdev {
[7] = { "full", 0666, &full_fops, NULL },
[8] = { "random", 0666, &random_fops, NULL },
[9] = { "urandom", 0666, &urandom_fops, NULL },
- [11] = { "kmsg", 0, &kmsg_fops, NULL },
+#ifdef CONFIG_PRINTK
+ [11] = { "kmsg", 0644, &kmsg_fops, NULL },
+#endif
#ifdef CONFIG_CRASH_DUMP
[12] = { "oldmem", 0, &oldmem_fops, NULL },
#endif
diff --git a/drivers/char/ramoops.c b/drivers/char/ramoops.c
deleted file mode 100644
index 2a5e45d2a9f8..000000000000
--- a/drivers/char/ramoops.c
+++ /dev/null
@@ -1,250 +0,0 @@
-/*
- * RAM Oops/Panic logger
- *
- * Copyright (C) 2010 Marco Stornelli <marco.stornelli@gmail.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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/kmsg_dump.h>
-#include <linux/time.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/ramoops.h>
-
-#define RAMOOPS_KERNMSG_HDR "===="
-#define MIN_MEM_SIZE 4096UL
-
-static ulong record_size = MIN_MEM_SIZE;
-module_param(record_size, ulong, 0400);
-MODULE_PARM_DESC(record_size,
- "size of each dump done on oops/panic");
-
-static ulong mem_address;
-module_param(mem_address, ulong, 0400);
-MODULE_PARM_DESC(mem_address,
- "start of reserved RAM used to store oops/panic logs");
-
-static ulong mem_size;
-module_param(mem_size, ulong, 0400);
-MODULE_PARM_DESC(mem_size,
- "size of reserved RAM used to store oops/panic logs");
-
-static int dump_oops = 1;
-module_param(dump_oops, int, 0600);
-MODULE_PARM_DESC(dump_oops,
- "set to 1 to dump oopses, 0 to only dump panics (default 1)");
-
-static struct ramoops_context {
- struct kmsg_dumper dump;
- void *virt_addr;
- phys_addr_t phys_addr;
- unsigned long size;
- unsigned long record_size;
- int dump_oops;
- int count;
- int max_count;
-} oops_cxt;
-
-static struct platform_device *dummy;
-static struct ramoops_platform_data *dummy_data;
-
-static void ramoops_do_dump(struct kmsg_dumper *dumper,
- enum kmsg_dump_reason reason, const char *s1, unsigned long l1,
- const char *s2, unsigned long l2)
-{
- struct ramoops_context *cxt = container_of(dumper,
- struct ramoops_context, dump);
- unsigned long s1_start, s2_start;
- unsigned long l1_cpy, l2_cpy;
- int res, hdr_size;
- char *buf, *buf_orig;
- struct timeval timestamp;
-
- if (reason != KMSG_DUMP_OOPS &&
- reason != KMSG_DUMP_PANIC)
- return;
-
- /* Only dump oopses if dump_oops is set */
- if (reason == KMSG_DUMP_OOPS && !cxt->dump_oops)
- return;
-
- buf = cxt->virt_addr + (cxt->count * cxt->record_size);
- buf_orig = buf;
-
- memset(buf, '\0', cxt->record_size);
- res = sprintf(buf, "%s", RAMOOPS_KERNMSG_HDR);
- buf += res;
- do_gettimeofday(&timestamp);
- res = sprintf(buf, "%lu.%lu\n", (long)timestamp.tv_sec, (long)timestamp.tv_usec);
- buf += res;
-
- hdr_size = buf - buf_orig;
- l2_cpy = min(l2, cxt->record_size - hdr_size);
- l1_cpy = min(l1, cxt->record_size - hdr_size - l2_cpy);
-
- s2_start = l2 - l2_cpy;
- s1_start = l1 - l1_cpy;
-
- memcpy(buf, s1 + s1_start, l1_cpy);
- memcpy(buf + l1_cpy, s2 + s2_start, l2_cpy);
-
- cxt->count = (cxt->count + 1) % cxt->max_count;
-}
-
-static int __init ramoops_probe(struct platform_device *pdev)
-{
- struct ramoops_platform_data *pdata = pdev->dev.platform_data;
- struct ramoops_context *cxt = &oops_cxt;
- int err = -EINVAL;
-
- if (!pdata->mem_size || !pdata->record_size) {
- pr_err("The memory size and the record size must be "
- "non-zero\n");
- goto fail3;
- }
-
- pdata->mem_size = rounddown_pow_of_two(pdata->mem_size);
- pdata->record_size = rounddown_pow_of_two(pdata->record_size);
-
- /* Check for the minimum memory size */
- if (pdata->mem_size < MIN_MEM_SIZE &&
- pdata->record_size < MIN_MEM_SIZE) {
- pr_err("memory size too small, minium is %lu\n", MIN_MEM_SIZE);
- goto fail3;
- }
-
- if (pdata->mem_size < pdata->record_size) {
- pr_err("The memory size must be larger than the "
- "records size\n");
- goto fail3;
- }
-
- cxt->max_count = pdata->mem_size / pdata->record_size;
- cxt->count = 0;
- cxt->size = pdata->mem_size;
- cxt->phys_addr = pdata->mem_address;
- cxt->record_size = pdata->record_size;
- cxt->dump_oops = pdata->dump_oops;
-
- if (!request_mem_region(cxt->phys_addr, cxt->size, "ramoops")) {
- pr_err("request mem region failed\n");
- err = -EINVAL;
- goto fail3;
- }
-
- cxt->virt_addr = ioremap(cxt->phys_addr, cxt->size);
- if (!cxt->virt_addr) {
- pr_err("ioremap failed\n");
- goto fail2;
- }
-
- cxt->dump.dump = ramoops_do_dump;
- err = kmsg_dump_register(&cxt->dump);
- if (err) {
- pr_err("registering kmsg dumper failed\n");
- goto fail1;
- }
-
- /*
- * Update the module parameter variables as well so they are visible
- * through /sys/module/ramoops/parameters/
- */
- mem_size = pdata->mem_size;
- mem_address = pdata->mem_address;
- record_size = pdata->record_size;
- dump_oops = pdata->dump_oops;
-
- return 0;
-
-fail1:
- iounmap(cxt->virt_addr);
-fail2:
- release_mem_region(cxt->phys_addr, cxt->size);
-fail3:
- return err;
-}
-
-static int __exit ramoops_remove(struct platform_device *pdev)
-{
- struct ramoops_context *cxt = &oops_cxt;
-
- if (kmsg_dump_unregister(&cxt->dump) < 0)
- pr_warn("could not unregister kmsg_dumper\n");
-
- iounmap(cxt->virt_addr);
- release_mem_region(cxt->phys_addr, cxt->size);
- return 0;
-}
-
-static struct platform_driver ramoops_driver = {
- .remove = __exit_p(ramoops_remove),
- .driver = {
- .name = "ramoops",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init ramoops_init(void)
-{
- int ret;
- ret = platform_driver_probe(&ramoops_driver, ramoops_probe);
- if (ret == -ENODEV) {
- /*
- * If we didn't find a platform device, we use module parameters
- * building platform data on the fly.
- */
- pr_info("platform device not found, using module parameters\n");
- dummy_data = kzalloc(sizeof(struct ramoops_platform_data),
- GFP_KERNEL);
- if (!dummy_data)
- return -ENOMEM;
- dummy_data->mem_size = mem_size;
- dummy_data->mem_address = mem_address;
- dummy_data->record_size = record_size;
- dummy_data->dump_oops = dump_oops;
- dummy = platform_create_bundle(&ramoops_driver, ramoops_probe,
- NULL, 0, dummy_data,
- sizeof(struct ramoops_platform_data));
-
- if (IS_ERR(dummy))
- ret = PTR_ERR(dummy);
- else
- ret = 0;
- }
-
- return ret;
-}
-
-static void __exit ramoops_exit(void)
-{
- platform_driver_unregister(&ramoops_driver);
- kfree(dummy_data);
-}
-
-module_init(ramoops_init);
-module_exit(ramoops_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Marco Stornelli <marco.stornelli@gmail.com>");
-MODULE_DESCRIPTION("RAM Oops/Panic logger/driver");
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
index 31ba11ca75e1..2c5d15beea35 100644
--- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
@@ -167,6 +167,7 @@ static const struct config_registers v4_config_registers = {
.BOOTSTS = UNIMPLEMENTED,
.CTL_1 = UNIMPLEMENTED,
};
+
static const struct config_registers v5_config_registers = {
.CRC = 0,
.FAR = 1,
@@ -192,6 +193,31 @@ static const struct config_registers v5_config_registers = {
.CTL_1 = 19,
};
+static const struct config_registers v6_config_registers = {
+ .CRC = 0,
+ .FAR = 1,
+ .FDRI = 2,
+ .FDRO = 3,
+ .CMD = 4,
+ .CTL = 5,
+ .MASK = 6,
+ .STAT = 7,
+ .LOUT = 8,
+ .COR = 9,
+ .MFWR = 10,
+ .FLR = UNIMPLEMENTED,
+ .KEY = UNIMPLEMENTED,
+ .CBC = 11,
+ .IDCODE = 12,
+ .AXSS = 13,
+ .C0R_1 = 14,
+ .CSOB = 15,
+ .WBSTAR = 16,
+ .TIMER = 17,
+ .BOOTSTS = 22,
+ .CTL_1 = 24,
+};
+
/**
* hwicap_command_desync - Send a DESYNC command to the ICAP port.
* @drvdata: a pointer to the drvdata.
@@ -744,6 +770,8 @@ static int __devinit hwicap_of_probe(struct platform_device *op,
regs = &v4_config_registers;
} else if (!strcmp(family, "virtex5")) {
regs = &v5_config_registers;
+ } else if (!strcmp(family, "virtex6")) {
+ regs = &v6_config_registers;
}
}
return hwicap_setup(&op->dev, id ? *id : -1, &res, config,
@@ -785,6 +813,8 @@ static int __devinit hwicap_drv_probe(struct platform_device *pdev)
regs = &v4_config_registers;
} else if (!strcmp(family, "virtex5")) {
regs = &v5_config_registers;
+ } else if (!strcmp(family, "virtex6")) {
+ regs = &v6_config_registers;
}
}
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.h b/drivers/char/xilinx_hwicap/xilinx_hwicap.h
index 8cca11981c5f..d31ee23c9f13 100644
--- a/drivers/char/xilinx_hwicap/xilinx_hwicap.h
+++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.h
@@ -86,7 +86,7 @@ struct hwicap_driver_config {
};
/* Number of times to poll the done regsiter */
-#define XHI_MAX_RETRIES 10
+#define XHI_MAX_RETRIES 5000
/************ Constant Definitions *************/
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 5138927a416c..99c6b203e6cd 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -18,7 +18,7 @@ config DW_APB_TIMER
config CLKSRC_DBX500_PRCMU
bool "Clocksource PRCMU Timer"
- depends on UX500_SOC_DB5500 || UX500_SOC_DB8500
+ depends on UX500_SOC_DB8500
default y
help
Use the always on PRCMU Timer as clocksource
diff --git a/drivers/cpufreq/db8500-cpufreq.c b/drivers/cpufreq/db8500-cpufreq.c
index 0bf1b8910eeb..74b830b635a6 100644
--- a/drivers/cpufreq/db8500-cpufreq.c
+++ b/drivers/cpufreq/db8500-cpufreq.c
@@ -161,7 +161,7 @@ static struct cpufreq_driver db8500_cpufreq_driver = {
static int __init db8500_cpufreq_register(void)
{
- if (!cpu_is_u8500v20_or_later())
+ if (!cpu_is_u8500_family())
return -ENODEV;
pr_info("cpufreq for DB8500 started\n");
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 371f13cc38eb..1092a770482e 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -297,4 +297,32 @@ config CRYPTO_DEV_TEGRA_AES
To compile this driver as a module, choose M here: the module
will be called tegra-aes.
+config CRYPTO_DEV_NX
+ tristate "Support for Power7+ in-Nest cryptographic accleration"
+ depends on PPC64 && IBMVIO
+ select CRYPTO_AES
+ select CRYPTO_CBC
+ select CRYPTO_ECB
+ select CRYPTO_CCM
+ select CRYPTO_GCM
+ select CRYPTO_AUTHENC
+ select CRYPTO_XCBC
+ select CRYPTO_SHA256
+ select CRYPTO_SHA512
+ help
+ Support for Power7+ in-Nest cryptographic acceleration. This
+ module supports acceleration for AES and SHA2 algorithms. If you
+ choose 'M' here, this module will be called nx_crypto.
+
+config CRYPTO_DEV_UX500
+ tristate "Driver for ST-Ericsson UX500 crypto hardware acceleration"
+ depends on ARCH_U8500
+ select CRYPTO_ALGAPI
+ help
+ Driver for ST-Ericsson UX500 crypto engine.
+
+if CRYPTO_DEV_UX500
+ source "drivers/crypto/ux500/Kconfig"
+endif # if CRYPTO_DEV_UX500
+
endif # CRYPTO_HW
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index f3e64eadd7af..01390325d72d 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o
obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o
+obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/ \ No newline at end of file
diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
index 13f8e1a14988..802e85102c32 100644
--- a/drivers/crypto/amcc/crypto4xx_core.c
+++ b/drivers/crypto/amcc/crypto4xx_core.c
@@ -1244,9 +1244,9 @@ err_start_dev:
iounmap(core_dev->dev->ce_base);
err_iomap:
free_irq(core_dev->irq, dev);
+err_request_irq:
irq_dispose_mapping(core_dev->irq);
tasklet_kill(&core_dev->tasklet);
-err_request_irq:
crypto4xx_destroy_sdr(core_dev->dev);
err_build_sdr:
crypto4xx_destroy_gdr(core_dev->dev);
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index 534a36469d57..4eec389184d3 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -2267,8 +2267,11 @@ static void __exit caam_algapi_exit(void)
int i, err;
dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
- if (!dev_node)
- return;
+ if (!dev_node) {
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+ if (!dev_node)
+ return;
+ }
pdev = of_find_device_by_node(dev_node);
if (!pdev)
@@ -2350,8 +2353,11 @@ static int __init caam_algapi_init(void)
int i = 0, err = 0;
dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
- if (!dev_node)
- return -ENODEV;
+ if (!dev_node) {
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+ if (!dev_node)
+ return -ENODEV;
+ }
pdev = of_find_device_by_node(dev_node);
if (!pdev)
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index c5f61c55d923..77557ebcd337 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -98,6 +98,12 @@ static int caam_probe(struct platform_device *pdev)
rspec = 0;
for_each_compatible_node(np, NULL, "fsl,sec-v4.0-job-ring")
rspec++;
+ if (!rspec) {
+ /* for backward compatible with device trees */
+ for_each_compatible_node(np, NULL, "fsl,sec4.0-job-ring")
+ rspec++;
+ }
+
ctrlpriv->jrdev = kzalloc(sizeof(struct device *) * rspec, GFP_KERNEL);
if (ctrlpriv->jrdev == NULL) {
iounmap(&topregs->ctrl);
@@ -111,6 +117,13 @@ static int caam_probe(struct platform_device *pdev)
ctrlpriv->total_jobrs++;
ring++;
}
+ if (!ring) {
+ for_each_compatible_node(np, NULL, "fsl,sec4.0-job-ring") {
+ caam_jr_probe(pdev, np, ring);
+ ctrlpriv->total_jobrs++;
+ ring++;
+ }
+ }
/* Check to see if QI present. If so, enable */
ctrlpriv->qi_present = !!(rd_reg64(&topregs->ctrl.perfmon.comp_parms) &
@@ -226,6 +239,9 @@ static struct of_device_id caam_match[] = {
{
.compatible = "fsl,sec-v4.0",
},
+ {
+ .compatible = "fsl,sec4.0",
+ },
{},
};
MODULE_DEVICE_TABLE(of, caam_match);
diff --git a/drivers/crypto/nx/Makefile b/drivers/crypto/nx/Makefile
new file mode 100644
index 000000000000..411ce59c80d1
--- /dev/null
+++ b/drivers/crypto/nx/Makefile
@@ -0,0 +1,11 @@
+obj-$(CONFIG_CRYPTO_DEV_NX) += nx-crypto.o
+nx-crypto-objs := nx.o \
+ nx_debugfs.o \
+ nx-aes-cbc.o \
+ nx-aes-ecb.o \
+ nx-aes-gcm.o \
+ nx-aes-ccm.o \
+ nx-aes-ctr.o \
+ nx-aes-xcbc.o \
+ nx-sha256.o \
+ nx-sha512.o
diff --git a/drivers/crypto/nx/nx-aes-cbc.c b/drivers/crypto/nx/nx-aes-cbc.c
new file mode 100644
index 000000000000..69ed796ee327
--- /dev/null
+++ b/drivers/crypto/nx/nx-aes-cbc.c
@@ -0,0 +1,141 @@
+/**
+ * AES CBC routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines 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; version 2 only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int cbc_aes_nx_set_key(struct crypto_tfm *tfm,
+ const u8 *in_key,
+ unsigned int key_len)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+
+ nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+ switch (key_len) {
+ case AES_KEYSIZE_128:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+ break;
+ case AES_KEYSIZE_192:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_192);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_192];
+ break;
+ case AES_KEYSIZE_256:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_256);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_256];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ csbcpb->cpb.hdr.mode = NX_MODE_AES_CBC;
+ memcpy(csbcpb->cpb.aes_cbc.key, in_key, key_len);
+
+ return 0;
+}
+
+static int cbc_aes_nx_crypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int nbytes,
+ int enc)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_blkcipher_ctx(desc->tfm);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+ int rc;
+
+ if (nbytes > nx_ctx->ap->databytelen)
+ return -EINVAL;
+
+ if (enc)
+ NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
+ else
+ NX_CPB_FDM(csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
+
+ rc = nx_build_sg_lists(nx_ctx, desc, dst, src, nbytes,
+ csbcpb->cpb.aes_cbc.iv);
+ if (rc)
+ goto out;
+
+ if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->aes_ops));
+ atomic64_add(csbcpb->csb.processed_byte_count,
+ &(nx_ctx->stats->aes_bytes));
+out:
+ return rc;
+}
+
+static int cbc_aes_nx_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int nbytes)
+{
+ return cbc_aes_nx_crypt(desc, dst, src, nbytes, 1);
+}
+
+static int cbc_aes_nx_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int nbytes)
+{
+ return cbc_aes_nx_crypt(desc, dst, src, nbytes, 0);
+}
+
+struct crypto_alg nx_cbc_aes_alg = {
+ .cra_name = "cbc(aes)",
+ .cra_driver_name = "cbc-aes-nx",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(nx_cbc_aes_alg.cra_list),
+ .cra_init = nx_crypto_ctx_aes_cbc_init,
+ .cra_exit = nx_crypto_ctx_exit,
+ .cra_blkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = cbc_aes_nx_set_key,
+ .encrypt = cbc_aes_nx_encrypt,
+ .decrypt = cbc_aes_nx_decrypt,
+ }
+};
diff --git a/drivers/crypto/nx/nx-aes-ccm.c b/drivers/crypto/nx/nx-aes-ccm.c
new file mode 100644
index 000000000000..7aeac678b9c0
--- /dev/null
+++ b/drivers/crypto/nx/nx-aes-ccm.c
@@ -0,0 +1,468 @@
+/**
+ * AES CCM routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2012 International Business Machines 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; version 2 only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/aead.h>
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <crypto/scatterwalk.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int ccm_aes_nx_set_key(struct crypto_aead *tfm,
+ const u8 *in_key,
+ unsigned int key_len)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+ struct nx_csbcpb *csbcpb_aead = nx_ctx->csbcpb_aead;
+
+ nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+ switch (key_len) {
+ case AES_KEYSIZE_128:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+ NX_CPB_SET_KEY_SIZE(csbcpb_aead, NX_KS_AES_128);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ csbcpb->cpb.hdr.mode = NX_MODE_AES_CCM;
+ memcpy(csbcpb->cpb.aes_ccm.key, in_key, key_len);
+
+ csbcpb_aead->cpb.hdr.mode = NX_MODE_AES_CCA;
+ memcpy(csbcpb_aead->cpb.aes_cca.key, in_key, key_len);
+
+ return 0;
+
+}
+
+static int ccm4309_aes_nx_set_key(struct crypto_aead *tfm,
+ const u8 *in_key,
+ unsigned int key_len)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
+
+ if (key_len < 3)
+ return -EINVAL;
+
+ key_len -= 3;
+
+ memcpy(nx_ctx->priv.ccm.nonce, in_key + key_len, 3);
+
+ return ccm_aes_nx_set_key(tfm, in_key, key_len);
+}
+
+static int ccm_aes_nx_setauthsize(struct crypto_aead *tfm,
+ unsigned int authsize)
+{
+ switch (authsize) {
+ case 4:
+ case 6:
+ case 8:
+ case 10:
+ case 12:
+ case 14:
+ case 16:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ crypto_aead_crt(tfm)->authsize = authsize;
+
+ return 0;
+}
+
+static int ccm4309_aes_nx_setauthsize(struct crypto_aead *tfm,
+ unsigned int authsize)
+{
+ switch (authsize) {
+ case 8:
+ case 12:
+ case 16:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ crypto_aead_crt(tfm)->authsize = authsize;
+
+ return 0;
+}
+
+/* taken from crypto/ccm.c */
+static int set_msg_len(u8 *block, unsigned int msglen, int csize)
+{
+ __be32 data;
+
+ memset(block, 0, csize);
+ block += csize;
+
+ if (csize >= 4)
+ csize = 4;
+ else if (msglen > (unsigned int)(1 << (8 * csize)))
+ return -EOVERFLOW;
+
+ data = cpu_to_be32(msglen);
+ memcpy(block - csize, (u8 *)&data + 4 - csize, csize);
+
+ return 0;
+}
+
+/* taken from crypto/ccm.c */
+static inline int crypto_ccm_check_iv(const u8 *iv)
+{
+ /* 2 <= L <= 8, so 1 <= L' <= 7. */
+ if (1 > iv[0] || iv[0] > 7)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* based on code from crypto/ccm.c */
+static int generate_b0(u8 *iv, unsigned int assoclen, unsigned int authsize,
+ unsigned int cryptlen, u8 *b0)
+{
+ unsigned int l, lp, m = authsize;
+ int rc;
+
+ memcpy(b0, iv, 16);
+
+ lp = b0[0];
+ l = lp + 1;
+
+ /* set m, bits 3-5 */
+ *b0 |= (8 * ((m - 2) / 2));
+
+ /* set adata, bit 6, if associated data is used */
+ if (assoclen)
+ *b0 |= 64;
+
+ rc = set_msg_len(b0 + 16 - l, cryptlen, l);
+
+ return rc;
+}
+
+static int generate_pat(u8 *iv,
+ struct aead_request *req,
+ struct nx_crypto_ctx *nx_ctx,
+ unsigned int authsize,
+ unsigned int nbytes,
+ u8 *out)
+{
+ struct nx_sg *nx_insg = nx_ctx->in_sg;
+ struct nx_sg *nx_outsg = nx_ctx->out_sg;
+ unsigned int iauth_len = 0;
+ struct vio_pfo_op *op = NULL;
+ u8 tmp[16], *b1 = NULL, *b0 = NULL, *result = NULL;
+ int rc;
+
+ /* zero the ctr value */
+ memset(iv + 15 - iv[0], 0, iv[0] + 1);
+
+ if (!req->assoclen) {
+ b0 = nx_ctx->csbcpb->cpb.aes_ccm.in_pat_or_b0;
+ } else if (req->assoclen <= 14) {
+ /* if associated data is 14 bytes or less, we do 1 GCM
+ * operation on 2 AES blocks, B0 (stored in the csbcpb) and B1,
+ * which is fed in through the source buffers here */
+ b0 = nx_ctx->csbcpb->cpb.aes_ccm.in_pat_or_b0;
+ b1 = nx_ctx->priv.ccm.iauth_tag;
+ iauth_len = req->assoclen;
+
+ nx_insg = nx_build_sg_list(nx_insg, b1, 16, nx_ctx->ap->sglen);
+ nx_outsg = nx_build_sg_list(nx_outsg, tmp, 16,
+ nx_ctx->ap->sglen);
+
+ /* inlen should be negative, indicating to phyp that its a
+ * pointer to an sg list */
+ nx_ctx->op.inlen = (nx_ctx->in_sg - nx_insg) *
+ sizeof(struct nx_sg);
+ nx_ctx->op.outlen = (nx_ctx->out_sg - nx_outsg) *
+ sizeof(struct nx_sg);
+
+ NX_CPB_FDM(nx_ctx->csbcpb) |= NX_FDM_ENDE_ENCRYPT;
+ NX_CPB_FDM(nx_ctx->csbcpb) |= NX_FDM_INTERMEDIATE;
+
+ op = &nx_ctx->op;
+ result = nx_ctx->csbcpb->cpb.aes_ccm.out_pat_or_mac;
+ } else if (req->assoclen <= 65280) {
+ /* if associated data is less than (2^16 - 2^8), we construct
+ * B1 differently and feed in the associated data to a CCA
+ * operation */
+ b0 = nx_ctx->csbcpb_aead->cpb.aes_cca.b0;
+ b1 = nx_ctx->csbcpb_aead->cpb.aes_cca.b1;
+ iauth_len = 14;
+
+ /* remaining assoc data must have scatterlist built for it */
+ nx_insg = nx_walk_and_build(nx_insg, nx_ctx->ap->sglen,
+ req->assoc, iauth_len,
+ req->assoclen - iauth_len);
+ nx_ctx->op_aead.inlen = (nx_ctx->in_sg - nx_insg) *
+ sizeof(struct nx_sg);
+
+ op = &nx_ctx->op_aead;
+ result = nx_ctx->csbcpb_aead->cpb.aes_cca.out_pat_or_b0;
+ } else {
+ /* if associated data is less than (2^32), we construct B1
+ * differently yet again and feed in the associated data to a
+ * CCA operation */
+ pr_err("associated data len is %u bytes (returning -EINVAL)\n",
+ req->assoclen);
+ rc = -EINVAL;
+ }
+
+ rc = generate_b0(iv, req->assoclen, authsize, nbytes, b0);
+ if (rc)
+ goto done;
+
+ if (b1) {
+ memset(b1, 0, 16);
+ *(u16 *)b1 = (u16)req->assoclen;
+
+ scatterwalk_map_and_copy(b1 + 2, req->assoc, 0,
+ iauth_len, SCATTERWALK_FROM_SG);
+
+ rc = nx_hcall_sync(nx_ctx, op,
+ req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto done;
+
+ atomic_inc(&(nx_ctx->stats->aes_ops));
+ atomic64_add(req->assoclen, &(nx_ctx->stats->aes_bytes));
+
+ memcpy(out, result, AES_BLOCK_SIZE);
+ }
+done:
+ return rc;
+}
+
+static int ccm_nx_decrypt(struct aead_request *req,
+ struct blkcipher_desc *desc)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+ unsigned int nbytes = req->cryptlen;
+ unsigned int authsize = crypto_aead_authsize(crypto_aead_reqtfm(req));
+ struct nx_ccm_priv *priv = &nx_ctx->priv.ccm;
+ int rc = -1;
+
+ if (nbytes > nx_ctx->ap->databytelen)
+ return -EINVAL;
+
+ nbytes -= authsize;
+
+ /* copy out the auth tag to compare with later */
+ scatterwalk_map_and_copy(priv->oauth_tag,
+ req->src, nbytes, authsize,
+ SCATTERWALK_FROM_SG);
+
+ rc = generate_pat(desc->info, req, nx_ctx, authsize, nbytes,
+ csbcpb->cpb.aes_ccm.in_pat_or_b0);
+ if (rc)
+ goto out;
+
+ rc = nx_build_sg_lists(nx_ctx, desc, req->dst, req->src, nbytes,
+ csbcpb->cpb.aes_ccm.iv_or_ctr);
+ if (rc)
+ goto out;
+
+ NX_CPB_FDM(nx_ctx->csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
+ NX_CPB_FDM(nx_ctx->csbcpb) &= ~NX_FDM_INTERMEDIATE;
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->aes_ops));
+ atomic64_add(csbcpb->csb.processed_byte_count,
+ &(nx_ctx->stats->aes_bytes));
+
+ rc = memcmp(csbcpb->cpb.aes_ccm.out_pat_or_mac, priv->oauth_tag,
+ authsize) ? -EBADMSG : 0;
+out:
+ return rc;
+}
+
+static int ccm_nx_encrypt(struct aead_request *req,
+ struct blkcipher_desc *desc)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+ unsigned int nbytes = req->cryptlen;
+ unsigned int authsize = crypto_aead_authsize(crypto_aead_reqtfm(req));
+ int rc = -1;
+
+ if (nbytes > nx_ctx->ap->databytelen)
+ return -EINVAL;
+
+ rc = generate_pat(desc->info, req, nx_ctx, authsize, nbytes,
+ csbcpb->cpb.aes_ccm.in_pat_or_b0);
+ if (rc)
+ goto out;
+
+ rc = nx_build_sg_lists(nx_ctx, desc, req->dst, req->src, nbytes,
+ csbcpb->cpb.aes_ccm.iv_or_ctr);
+ if (rc)
+ goto out;
+
+ NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
+ NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->aes_ops));
+ atomic64_add(csbcpb->csb.processed_byte_count,
+ &(nx_ctx->stats->aes_bytes));
+
+ /* copy out the auth tag */
+ scatterwalk_map_and_copy(csbcpb->cpb.aes_ccm.out_pat_or_mac,
+ req->dst, nbytes, authsize,
+ SCATTERWALK_TO_SG);
+out:
+ return rc;
+}
+
+static int ccm4309_aes_nx_encrypt(struct aead_request *req)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+ struct blkcipher_desc desc;
+ u8 *iv = nx_ctx->priv.ccm.iv;
+
+ iv[0] = 3;
+ memcpy(iv + 1, nx_ctx->priv.ccm.nonce, 3);
+ memcpy(iv + 4, req->iv, 8);
+
+ desc.info = iv;
+ desc.tfm = (struct crypto_blkcipher *)req->base.tfm;
+
+ return ccm_nx_encrypt(req, &desc);
+}
+
+static int ccm_aes_nx_encrypt(struct aead_request *req)
+{
+ struct blkcipher_desc desc;
+ int rc;
+
+ desc.info = req->iv;
+ desc.tfm = (struct crypto_blkcipher *)req->base.tfm;
+
+ rc = crypto_ccm_check_iv(desc.info);
+ if (rc)
+ return rc;
+
+ return ccm_nx_encrypt(req, &desc);
+}
+
+static int ccm4309_aes_nx_decrypt(struct aead_request *req)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+ struct blkcipher_desc desc;
+ u8 *iv = nx_ctx->priv.ccm.iv;
+
+ iv[0] = 3;
+ memcpy(iv + 1, nx_ctx->priv.ccm.nonce, 3);
+ memcpy(iv + 4, req->iv, 8);
+
+ desc.info = iv;
+ desc.tfm = (struct crypto_blkcipher *)req->base.tfm;
+
+ return ccm_nx_decrypt(req, &desc);
+}
+
+static int ccm_aes_nx_decrypt(struct aead_request *req)
+{
+ struct blkcipher_desc desc;
+ int rc;
+
+ desc.info = req->iv;
+ desc.tfm = (struct crypto_blkcipher *)req->base.tfm;
+
+ rc = crypto_ccm_check_iv(desc.info);
+ if (rc)
+ return rc;
+
+ return ccm_nx_decrypt(req, &desc);
+}
+
+/* tell the block cipher walk routines that this is a stream cipher by
+ * setting cra_blocksize to 1. Even using blkcipher_walk_virt_block
+ * during encrypt/decrypt doesn't solve this problem, because it calls
+ * blkcipher_walk_done under the covers, which doesn't use walk->blocksize,
+ * but instead uses this tfm->blocksize. */
+struct crypto_alg nx_ccm_aes_alg = {
+ .cra_name = "ccm(aes)",
+ .cra_driver_name = "ccm-aes-nx",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_AEAD |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_type = &crypto_aead_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(nx_ccm_aes_alg.cra_list),
+ .cra_init = nx_crypto_ctx_aes_ccm_init,
+ .cra_exit = nx_crypto_ctx_exit,
+ .cra_aead = {
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = AES_BLOCK_SIZE,
+ .setkey = ccm_aes_nx_set_key,
+ .setauthsize = ccm_aes_nx_setauthsize,
+ .encrypt = ccm_aes_nx_encrypt,
+ .decrypt = ccm_aes_nx_decrypt,
+ }
+};
+
+struct crypto_alg nx_ccm4309_aes_alg = {
+ .cra_name = "rfc4309(ccm(aes))",
+ .cra_driver_name = "rfc4309-ccm-aes-nx",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_AEAD |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_type = &crypto_nivaead_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(nx_ccm4309_aes_alg.cra_list),
+ .cra_init = nx_crypto_ctx_aes_ccm_init,
+ .cra_exit = nx_crypto_ctx_exit,
+ .cra_aead = {
+ .ivsize = 8,
+ .maxauthsize = AES_BLOCK_SIZE,
+ .setkey = ccm4309_aes_nx_set_key,
+ .setauthsize = ccm4309_aes_nx_setauthsize,
+ .encrypt = ccm4309_aes_nx_encrypt,
+ .decrypt = ccm4309_aes_nx_decrypt,
+ .geniv = "seqiv",
+ }
+};
diff --git a/drivers/crypto/nx/nx-aes-ctr.c b/drivers/crypto/nx/nx-aes-ctr.c
new file mode 100644
index 000000000000..52d4eb05e8f7
--- /dev/null
+++ b/drivers/crypto/nx/nx-aes-ctr.c
@@ -0,0 +1,178 @@
+/**
+ * AES CTR routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines 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; version 2 only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/aes.h>
+#include <crypto/ctr.h>
+#include <crypto/algapi.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int ctr_aes_nx_set_key(struct crypto_tfm *tfm,
+ const u8 *in_key,
+ unsigned int key_len)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+
+ nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+ switch (key_len) {
+ case AES_KEYSIZE_128:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+ break;
+ case AES_KEYSIZE_192:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_192);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_192];
+ break;
+ case AES_KEYSIZE_256:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_256);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_256];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ csbcpb->cpb.hdr.mode = NX_MODE_AES_CTR;
+ memcpy(csbcpb->cpb.aes_ctr.key, in_key, key_len);
+
+ return 0;
+}
+
+static int ctr3686_aes_nx_set_key(struct crypto_tfm *tfm,
+ const u8 *in_key,
+ unsigned int key_len)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
+
+ if (key_len < CTR_RFC3686_NONCE_SIZE)
+ return -EINVAL;
+
+ memcpy(nx_ctx->priv.ctr.iv,
+ in_key + key_len - CTR_RFC3686_NONCE_SIZE,
+ CTR_RFC3686_NONCE_SIZE);
+
+ key_len -= CTR_RFC3686_NONCE_SIZE;
+
+ return ctr_aes_nx_set_key(tfm, in_key, key_len);
+}
+
+static int ctr_aes_nx_crypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_blkcipher_ctx(desc->tfm);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+ int rc;
+
+ if (nbytes > nx_ctx->ap->databytelen)
+ return -EINVAL;
+
+ rc = nx_build_sg_lists(nx_ctx, desc, dst, src, nbytes,
+ csbcpb->cpb.aes_ctr.iv);
+ if (rc)
+ goto out;
+
+ if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->aes_ops));
+ atomic64_add(csbcpb->csb.processed_byte_count,
+ &(nx_ctx->stats->aes_bytes));
+out:
+ return rc;
+}
+
+static int ctr3686_aes_nx_crypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_blkcipher_ctx(desc->tfm);
+ u8 *iv = nx_ctx->priv.ctr.iv;
+
+ memcpy(iv + CTR_RFC3686_NONCE_SIZE,
+ desc->info, CTR_RFC3686_IV_SIZE);
+ iv[15] = 1;
+
+ desc->info = nx_ctx->priv.ctr.iv;
+
+ return ctr_aes_nx_crypt(desc, dst, src, nbytes);
+}
+
+struct crypto_alg nx_ctr_aes_alg = {
+ .cra_name = "ctr(aes)",
+ .cra_driver_name = "ctr-aes-nx",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(nx_ctr_aes_alg.cra_list),
+ .cra_init = nx_crypto_ctx_aes_ctr_init,
+ .cra_exit = nx_crypto_ctx_exit,
+ .cra_blkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = ctr_aes_nx_set_key,
+ .encrypt = ctr_aes_nx_crypt,
+ .decrypt = ctr_aes_nx_crypt,
+ }
+};
+
+struct crypto_alg nx_ctr3686_aes_alg = {
+ .cra_name = "rfc3686(ctr(aes))",
+ .cra_driver_name = "rfc3686-ctr-aes-nx",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(nx_ctr3686_aes_alg.cra_list),
+ .cra_init = nx_crypto_ctx_aes_ctr_init,
+ .cra_exit = nx_crypto_ctx_exit,
+ .cra_blkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE + CTR_RFC3686_NONCE_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE + CTR_RFC3686_NONCE_SIZE,
+ .ivsize = CTR_RFC3686_IV_SIZE,
+ .geniv = "seqiv",
+ .setkey = ctr3686_aes_nx_set_key,
+ .encrypt = ctr3686_aes_nx_crypt,
+ .decrypt = ctr3686_aes_nx_crypt,
+ }
+};
diff --git a/drivers/crypto/nx/nx-aes-ecb.c b/drivers/crypto/nx/nx-aes-ecb.c
new file mode 100644
index 000000000000..7b77bc2d1df4
--- /dev/null
+++ b/drivers/crypto/nx/nx-aes-ecb.c
@@ -0,0 +1,139 @@
+/**
+ * AES ECB routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines 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; version 2 only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int ecb_aes_nx_set_key(struct crypto_tfm *tfm,
+ const u8 *in_key,
+ unsigned int key_len)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
+ struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+
+ nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+ switch (key_len) {
+ case AES_KEYSIZE_128:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+ break;
+ case AES_KEYSIZE_192:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_192);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_192];
+ break;
+ case AES_KEYSIZE_256:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_256);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_256];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ csbcpb->cpb.hdr.mode = NX_MODE_AES_ECB;
+ memcpy(csbcpb->cpb.aes_ecb.key, in_key, key_len);
+
+ return 0;
+}
+
+static int ecb_aes_nx_crypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int nbytes,
+ int enc)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_blkcipher_ctx(desc->tfm);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+ int rc;
+
+ if (nbytes > nx_ctx->ap->databytelen)
+ return -EINVAL;
+
+ if (enc)
+ NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
+ else
+ NX_CPB_FDM(csbcpb) &= ~NX_FDM_ENDE_ENCRYPT;
+
+ rc = nx_build_sg_lists(nx_ctx, desc, dst, src, nbytes, NULL);
+ if (rc)
+ goto out;
+
+ if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->aes_ops));
+ atomic64_add(csbcpb->csb.processed_byte_count,
+ &(nx_ctx->stats->aes_bytes));
+out:
+ return rc;
+}
+
+static int ecb_aes_nx_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int nbytes)
+{
+ return ecb_aes_nx_crypt(desc, dst, src, nbytes, 1);
+}
+
+static int ecb_aes_nx_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int nbytes)
+{
+ return ecb_aes_nx_crypt(desc, dst, src, nbytes, 0);
+}
+
+struct crypto_alg nx_ecb_aes_alg = {
+ .cra_name = "ecb(aes)",
+ .cra_driver_name = "ecb-aes-nx",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(nx_ecb_aes_alg.cra_list),
+ .cra_init = nx_crypto_ctx_aes_ecb_init,
+ .cra_exit = nx_crypto_ctx_exit,
+ .cra_blkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = ecb_aes_nx_set_key,
+ .encrypt = ecb_aes_nx_encrypt,
+ .decrypt = ecb_aes_nx_decrypt,
+ }
+};
diff --git a/drivers/crypto/nx/nx-aes-gcm.c b/drivers/crypto/nx/nx-aes-gcm.c
new file mode 100644
index 000000000000..9ab1c7341dac
--- /dev/null
+++ b/drivers/crypto/nx/nx-aes-gcm.c
@@ -0,0 +1,353 @@
+/**
+ * AES GCM routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2012 International Business Machines 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; version 2 only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/aead.h>
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <crypto/scatterwalk.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int gcm_aes_nx_set_key(struct crypto_aead *tfm,
+ const u8 *in_key,
+ unsigned int key_len)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+ struct nx_csbcpb *csbcpb_aead = nx_ctx->csbcpb_aead;
+
+ nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+ switch (key_len) {
+ case AES_KEYSIZE_128:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+ NX_CPB_SET_KEY_SIZE(csbcpb_aead, NX_KS_AES_128);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+ break;
+ case AES_KEYSIZE_192:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_192);
+ NX_CPB_SET_KEY_SIZE(csbcpb_aead, NX_KS_AES_192);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_192];
+ break;
+ case AES_KEYSIZE_256:
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_256);
+ NX_CPB_SET_KEY_SIZE(csbcpb_aead, NX_KS_AES_256);
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_256];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ csbcpb->cpb.hdr.mode = NX_MODE_AES_GCM;
+ memcpy(csbcpb->cpb.aes_gcm.key, in_key, key_len);
+
+ csbcpb_aead->cpb.hdr.mode = NX_MODE_AES_GCA;
+ memcpy(csbcpb_aead->cpb.aes_gca.key, in_key, key_len);
+
+ return 0;
+}
+
+static int gcm4106_aes_nx_set_key(struct crypto_aead *tfm,
+ const u8 *in_key,
+ unsigned int key_len)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&tfm->base);
+ char *nonce = nx_ctx->priv.gcm.nonce;
+ int rc;
+
+ if (key_len < 4)
+ return -EINVAL;
+
+ key_len -= 4;
+
+ rc = gcm_aes_nx_set_key(tfm, in_key, key_len);
+ if (rc)
+ goto out;
+
+ memcpy(nonce, in_key + key_len, 4);
+out:
+ return rc;
+}
+
+static int gcm_aes_nx_setauthsize(struct crypto_aead *tfm,
+ unsigned int authsize)
+{
+ if (authsize > crypto_aead_alg(tfm)->maxauthsize)
+ return -EINVAL;
+
+ crypto_aead_crt(tfm)->authsize = authsize;
+
+ return 0;
+}
+
+static int gcm4106_aes_nx_setauthsize(struct crypto_aead *tfm,
+ unsigned int authsize)
+{
+ switch (authsize) {
+ case 8:
+ case 12:
+ case 16:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ crypto_aead_crt(tfm)->authsize = authsize;
+
+ return 0;
+}
+
+static int nx_gca(struct nx_crypto_ctx *nx_ctx,
+ struct aead_request *req,
+ u8 *out)
+{
+ struct nx_csbcpb *csbcpb_aead = nx_ctx->csbcpb_aead;
+ int rc = -EINVAL;
+ struct scatter_walk walk;
+ struct nx_sg *nx_sg = nx_ctx->in_sg;
+
+ if (req->assoclen > nx_ctx->ap->databytelen)
+ goto out;
+
+ if (req->assoclen <= AES_BLOCK_SIZE) {
+ scatterwalk_start(&walk, req->assoc);
+ scatterwalk_copychunks(out, &walk, req->assoclen,
+ SCATTERWALK_FROM_SG);
+ scatterwalk_done(&walk, SCATTERWALK_FROM_SG, 0);
+
+ rc = 0;
+ goto out;
+ }
+
+ nx_sg = nx_walk_and_build(nx_sg, nx_ctx->ap->sglen, req->assoc, 0,
+ req->assoclen);
+ nx_ctx->op_aead.inlen = (nx_ctx->in_sg - nx_sg) * sizeof(struct nx_sg);
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op_aead,
+ req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->aes_ops));
+ atomic64_add(req->assoclen, &(nx_ctx->stats->aes_bytes));
+
+ memcpy(out, csbcpb_aead->cpb.aes_gca.out_pat, AES_BLOCK_SIZE);
+out:
+ return rc;
+}
+
+static int gcm_aes_nx_crypt(struct aead_request *req, int enc)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+ struct blkcipher_desc desc;
+ unsigned int nbytes = req->cryptlen;
+ int rc = -EINVAL;
+
+ if (nbytes > nx_ctx->ap->databytelen)
+ goto out;
+
+ desc.info = nx_ctx->priv.gcm.iv;
+ /* initialize the counter */
+ *(u32 *)(desc.info + NX_GCM_CTR_OFFSET) = 1;
+
+ /* For scenarios where the input message is zero length, AES CTR mode
+ * may be used. Set the source data to be a single block (16B) of all
+ * zeros, and set the input IV value to be the same as the GMAC IV
+ * value. - nx_wb 4.8.1.3 */
+ if (nbytes == 0) {
+ char src[AES_BLOCK_SIZE] = {};
+ struct scatterlist sg;
+
+ desc.tfm = crypto_alloc_blkcipher("ctr(aes)", 0, 0);
+ if (IS_ERR(desc.tfm)) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ crypto_blkcipher_setkey(desc.tfm, csbcpb->cpb.aes_gcm.key,
+ NX_CPB_KEY_SIZE(csbcpb) == NX_KS_AES_128 ? 16 :
+ NX_CPB_KEY_SIZE(csbcpb) == NX_KS_AES_192 ? 24 : 32);
+
+ sg_init_one(&sg, src, AES_BLOCK_SIZE);
+ if (enc)
+ crypto_blkcipher_encrypt_iv(&desc, req->dst, &sg,
+ AES_BLOCK_SIZE);
+ else
+ crypto_blkcipher_decrypt_iv(&desc, req->dst, &sg,
+ AES_BLOCK_SIZE);
+ crypto_free_blkcipher(desc.tfm);
+
+ rc = 0;
+ goto out;
+ }
+
+ desc.tfm = (struct crypto_blkcipher *)req->base.tfm;
+
+ csbcpb->cpb.aes_gcm.bit_length_aad = req->assoclen * 8;
+
+ if (req->assoclen) {
+ rc = nx_gca(nx_ctx, req, csbcpb->cpb.aes_gcm.in_pat_or_aad);
+ if (rc)
+ goto out;
+ }
+
+ if (enc)
+ NX_CPB_FDM(csbcpb) |= NX_FDM_ENDE_ENCRYPT;
+ else
+ nbytes -= AES_BLOCK_SIZE;
+
+ csbcpb->cpb.aes_gcm.bit_length_data = nbytes * 8;
+
+ rc = nx_build_sg_lists(nx_ctx, &desc, req->dst, req->src, nbytes,
+ csbcpb->cpb.aes_gcm.iv_or_cnt);
+ if (rc)
+ goto out;
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->aes_ops));
+ atomic64_add(csbcpb->csb.processed_byte_count,
+ &(nx_ctx->stats->aes_bytes));
+
+ if (enc) {
+ /* copy out the auth tag */
+ scatterwalk_map_and_copy(csbcpb->cpb.aes_gcm.out_pat_or_mac,
+ req->dst, nbytes,
+ crypto_aead_authsize(crypto_aead_reqtfm(req)),
+ SCATTERWALK_TO_SG);
+ } else if (req->assoclen) {
+ u8 *itag = nx_ctx->priv.gcm.iauth_tag;
+ u8 *otag = csbcpb->cpb.aes_gcm.out_pat_or_mac;
+
+ scatterwalk_map_and_copy(itag, req->dst, nbytes,
+ crypto_aead_authsize(crypto_aead_reqtfm(req)),
+ SCATTERWALK_FROM_SG);
+ rc = memcmp(itag, otag,
+ crypto_aead_authsize(crypto_aead_reqtfm(req))) ?
+ -EBADMSG : 0;
+ }
+out:
+ return rc;
+}
+
+static int gcm_aes_nx_encrypt(struct aead_request *req)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+ char *iv = nx_ctx->priv.gcm.iv;
+
+ memcpy(iv, req->iv, 12);
+
+ return gcm_aes_nx_crypt(req, 1);
+}
+
+static int gcm_aes_nx_decrypt(struct aead_request *req)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+ char *iv = nx_ctx->priv.gcm.iv;
+
+ memcpy(iv, req->iv, 12);
+
+ return gcm_aes_nx_crypt(req, 0);
+}
+
+static int gcm4106_aes_nx_encrypt(struct aead_request *req)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+ char *iv = nx_ctx->priv.gcm.iv;
+ char *nonce = nx_ctx->priv.gcm.nonce;
+
+ memcpy(iv, nonce, NX_GCM4106_NONCE_LEN);
+ memcpy(iv + NX_GCM4106_NONCE_LEN, req->iv, 8);
+
+ return gcm_aes_nx_crypt(req, 1);
+}
+
+static int gcm4106_aes_nx_decrypt(struct aead_request *req)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(req->base.tfm);
+ char *iv = nx_ctx->priv.gcm.iv;
+ char *nonce = nx_ctx->priv.gcm.nonce;
+
+ memcpy(iv, nonce, NX_GCM4106_NONCE_LEN);
+ memcpy(iv + NX_GCM4106_NONCE_LEN, req->iv, 8);
+
+ return gcm_aes_nx_crypt(req, 0);
+}
+
+/* tell the block cipher walk routines that this is a stream cipher by
+ * setting cra_blocksize to 1. Even using blkcipher_walk_virt_block
+ * during encrypt/decrypt doesn't solve this problem, because it calls
+ * blkcipher_walk_done under the covers, which doesn't use walk->blocksize,
+ * but instead uses this tfm->blocksize. */
+struct crypto_alg nx_gcm_aes_alg = {
+ .cra_name = "gcm(aes)",
+ .cra_driver_name = "gcm-aes-nx",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_AEAD,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_type = &crypto_aead_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(nx_gcm_aes_alg.cra_list),
+ .cra_init = nx_crypto_ctx_aes_gcm_init,
+ .cra_exit = nx_crypto_ctx_exit,
+ .cra_aead = {
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = AES_BLOCK_SIZE,
+ .setkey = gcm_aes_nx_set_key,
+ .setauthsize = gcm_aes_nx_setauthsize,
+ .encrypt = gcm_aes_nx_encrypt,
+ .decrypt = gcm_aes_nx_decrypt,
+ }
+};
+
+struct crypto_alg nx_gcm4106_aes_alg = {
+ .cra_name = "rfc4106(gcm(aes))",
+ .cra_driver_name = "rfc4106-gcm-aes-nx",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_AEAD,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_type = &crypto_nivaead_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(nx_gcm4106_aes_alg.cra_list),
+ .cra_init = nx_crypto_ctx_aes_gcm_init,
+ .cra_exit = nx_crypto_ctx_exit,
+ .cra_aead = {
+ .ivsize = 8,
+ .maxauthsize = AES_BLOCK_SIZE,
+ .geniv = "seqiv",
+ .setkey = gcm4106_aes_nx_set_key,
+ .setauthsize = gcm4106_aes_nx_setauthsize,
+ .encrypt = gcm4106_aes_nx_encrypt,
+ .decrypt = gcm4106_aes_nx_decrypt,
+ }
+};
diff --git a/drivers/crypto/nx/nx-aes-xcbc.c b/drivers/crypto/nx/nx-aes-xcbc.c
new file mode 100644
index 000000000000..93923e4628c0
--- /dev/null
+++ b/drivers/crypto/nx/nx-aes-xcbc.c
@@ -0,0 +1,236 @@
+/**
+ * AES XCBC routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines 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; version 2 only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/hash.h>
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+struct xcbc_state {
+ u8 state[AES_BLOCK_SIZE];
+ unsigned int count;
+ u8 buffer[AES_BLOCK_SIZE];
+};
+
+static int nx_xcbc_set_key(struct crypto_shash *desc,
+ const u8 *in_key,
+ unsigned int key_len)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_shash_ctx(desc);
+
+ switch (key_len) {
+ case AES_KEYSIZE_128:
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_AES_128];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ memcpy(nx_ctx->priv.xcbc.key, in_key, key_len);
+
+ return 0;
+}
+
+static int nx_xcbc_init(struct shash_desc *desc)
+{
+ struct xcbc_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+ struct nx_sg *out_sg;
+
+ nx_ctx_init(nx_ctx, HCOP_FC_AES);
+
+ memset(sctx, 0, sizeof *sctx);
+
+ NX_CPB_SET_KEY_SIZE(csbcpb, NX_KS_AES_128);
+ csbcpb->cpb.hdr.mode = NX_MODE_AES_XCBC_MAC;
+
+ memcpy(csbcpb->cpb.aes_xcbc.key, nx_ctx->priv.xcbc.key, AES_BLOCK_SIZE);
+ memset(nx_ctx->priv.xcbc.key, 0, sizeof *nx_ctx->priv.xcbc.key);
+
+ out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state,
+ AES_BLOCK_SIZE, nx_ctx->ap->sglen);
+ nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+ return 0;
+}
+
+static int nx_xcbc_update(struct shash_desc *desc,
+ const u8 *data,
+ unsigned int len)
+{
+ struct xcbc_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+ struct nx_sg *in_sg;
+ u32 to_process, leftover;
+ int rc = 0;
+
+ if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+ /* we've hit the nx chip previously and we're updating again,
+ * so copy over the partial digest */
+ memcpy(csbcpb->cpb.aes_xcbc.cv,
+ csbcpb->cpb.aes_xcbc.out_cv_mac, AES_BLOCK_SIZE);
+ }
+
+ /* 2 cases for total data len:
+ * 1: <= AES_BLOCK_SIZE: copy into state, return 0
+ * 2: > AES_BLOCK_SIZE: process X blocks, copy in leftover
+ */
+ if (len + sctx->count <= AES_BLOCK_SIZE) {
+ memcpy(sctx->buffer + sctx->count, data, len);
+ sctx->count += len;
+ goto out;
+ }
+
+ /* to_process: the AES_BLOCK_SIZE data chunk to process in this
+ * update */
+ to_process = (sctx->count + len) & ~(AES_BLOCK_SIZE - 1);
+ leftover = (sctx->count + len) & (AES_BLOCK_SIZE - 1);
+
+ /* the hardware will not accept a 0 byte operation for this algorithm
+ * and the operation MUST be finalized to be correct. So if we happen
+ * to get an update that falls on a block sized boundary, we must
+ * save off the last block to finalize with later. */
+ if (!leftover) {
+ to_process -= AES_BLOCK_SIZE;
+ leftover = AES_BLOCK_SIZE;
+ }
+
+ if (sctx->count) {
+ in_sg = nx_build_sg_list(nx_ctx->in_sg, sctx->buffer,
+ sctx->count, nx_ctx->ap->sglen);
+ in_sg = nx_build_sg_list(in_sg, (u8 *)data,
+ to_process - sctx->count,
+ nx_ctx->ap->sglen);
+ nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+ sizeof(struct nx_sg);
+ } else {
+ in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)data, to_process,
+ nx_ctx->ap->sglen);
+ nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+ sizeof(struct nx_sg);
+ }
+
+ NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+
+ if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->aes_ops));
+
+ /* copy the leftover back into the state struct */
+ memcpy(sctx->buffer, data + len - leftover, leftover);
+ sctx->count = leftover;
+
+ /* everything after the first update is continuation */
+ NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+out:
+ return rc;
+}
+
+static int nx_xcbc_final(struct shash_desc *desc, u8 *out)
+{
+ struct xcbc_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_csbcpb *csbcpb = nx_ctx->csbcpb;
+ struct nx_sg *in_sg, *out_sg;
+ int rc = 0;
+
+ if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+ /* we've hit the nx chip previously, now we're finalizing,
+ * so copy over the partial digest */
+ memcpy(csbcpb->cpb.aes_xcbc.cv,
+ csbcpb->cpb.aes_xcbc.out_cv_mac, AES_BLOCK_SIZE);
+ } else if (sctx->count == 0) {
+ /* we've never seen an update, so this is a 0 byte op. The
+ * hardware cannot handle a 0 byte op, so just copy out the
+ * known 0 byte result. This is cheaper than allocating a
+ * software context to do a 0 byte op */
+ u8 data[] = { 0x75, 0xf0, 0x25, 0x1d, 0x52, 0x8a, 0xc0, 0x1c,
+ 0x45, 0x73, 0xdf, 0xd5, 0x84, 0xd7, 0x9f, 0x29 };
+ memcpy(out, data, sizeof(data));
+ goto out;
+ }
+
+ /* final is represented by continuing the operation and indicating that
+ * this is not an intermediate operation */
+ NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
+
+ in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)sctx->buffer,
+ sctx->count, nx_ctx->ap->sglen);
+ out_sg = nx_build_sg_list(nx_ctx->out_sg, out, AES_BLOCK_SIZE,
+ nx_ctx->ap->sglen);
+
+ nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
+ nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+ if (!nx_ctx->op.outlen) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->aes_ops));
+
+ memcpy(out, csbcpb->cpb.aes_xcbc.out_cv_mac, AES_BLOCK_SIZE);
+out:
+ return rc;
+}
+
+struct shash_alg nx_shash_aes_xcbc_alg = {
+ .digestsize = AES_BLOCK_SIZE,
+ .init = nx_xcbc_init,
+ .update = nx_xcbc_update,
+ .final = nx_xcbc_final,
+ .setkey = nx_xcbc_set_key,
+ .descsize = sizeof(struct xcbc_state),
+ .statesize = sizeof(struct xcbc_state),
+ .base = {
+ .cra_name = "xcbc(aes)",
+ .cra_driver_name = "xcbc-aes-nx",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_module = THIS_MODULE,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_init = nx_crypto_ctx_aes_xcbc_init,
+ .cra_exit = nx_crypto_ctx_exit,
+ }
+};
diff --git a/drivers/crypto/nx/nx-sha256.c b/drivers/crypto/nx/nx-sha256.c
new file mode 100644
index 000000000000..9767315f8c0b
--- /dev/null
+++ b/drivers/crypto/nx/nx-sha256.c
@@ -0,0 +1,246 @@
+/**
+ * SHA-256 routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines 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; version 2 only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/hash.h>
+#include <crypto/sha.h>
+#include <linux/module.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int nx_sha256_init(struct shash_desc *desc)
+{
+ struct sha256_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_sg *out_sg;
+
+ nx_ctx_init(nx_ctx, HCOP_FC_SHA);
+
+ memset(sctx, 0, sizeof *sctx);
+
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_SHA256];
+
+ NX_CPB_SET_DIGEST_SIZE(nx_ctx->csbcpb, NX_DS_SHA256);
+ out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state,
+ SHA256_DIGEST_SIZE, nx_ctx->ap->sglen);
+ nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+ return 0;
+}
+
+static int nx_sha256_update(struct shash_desc *desc, const u8 *data,
+ unsigned int len)
+{
+ struct sha256_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+ struct nx_sg *in_sg;
+ u64 to_process, leftover;
+ int rc = 0;
+
+ if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+ /* we've hit the nx chip previously and we're updating again,
+ * so copy over the partial digest */
+ memcpy(csbcpb->cpb.sha256.input_partial_digest,
+ csbcpb->cpb.sha256.message_digest, SHA256_DIGEST_SIZE);
+ }
+
+ /* 2 cases for total data len:
+ * 1: <= SHA256_BLOCK_SIZE: copy into state, return 0
+ * 2: > SHA256_BLOCK_SIZE: process X blocks, copy in leftover
+ */
+ if (len + sctx->count <= SHA256_BLOCK_SIZE) {
+ memcpy(sctx->buf + sctx->count, data, len);
+ sctx->count += len;
+ goto out;
+ }
+
+ /* to_process: the SHA256_BLOCK_SIZE data chunk to process in this
+ * update */
+ to_process = (sctx->count + len) & ~(SHA256_BLOCK_SIZE - 1);
+ leftover = (sctx->count + len) & (SHA256_BLOCK_SIZE - 1);
+
+ if (sctx->count) {
+ in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)sctx->buf,
+ sctx->count, nx_ctx->ap->sglen);
+ in_sg = nx_build_sg_list(in_sg, (u8 *)data,
+ to_process - sctx->count,
+ nx_ctx->ap->sglen);
+ nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+ sizeof(struct nx_sg);
+ } else {
+ in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)data,
+ to_process, nx_ctx->ap->sglen);
+ nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+ sizeof(struct nx_sg);
+ }
+
+ NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+
+ if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->sha256_ops));
+
+ /* copy the leftover back into the state struct */
+ memcpy(sctx->buf, data + len - leftover, leftover);
+ sctx->count = leftover;
+
+ csbcpb->cpb.sha256.message_bit_length += (u64)
+ (csbcpb->cpb.sha256.spbc * 8);
+
+ /* everything after the first update is continuation */
+ NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+out:
+ return rc;
+}
+
+static int nx_sha256_final(struct shash_desc *desc, u8 *out)
+{
+ struct sha256_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+ struct nx_sg *in_sg, *out_sg;
+ int rc;
+
+ if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+ /* we've hit the nx chip previously, now we're finalizing,
+ * so copy over the partial digest */
+ memcpy(csbcpb->cpb.sha256.input_partial_digest,
+ csbcpb->cpb.sha256.message_digest, SHA256_DIGEST_SIZE);
+ }
+
+ /* final is represented by continuing the operation and indicating that
+ * this is not an intermediate operation */
+ NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
+
+ csbcpb->cpb.sha256.message_bit_length += (u64)(sctx->count * 8);
+
+ in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)sctx->buf,
+ sctx->count, nx_ctx->ap->sglen);
+ out_sg = nx_build_sg_list(nx_ctx->out_sg, out, SHA256_DIGEST_SIZE,
+ nx_ctx->ap->sglen);
+ nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
+ nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+ if (!nx_ctx->op.outlen) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->sha256_ops));
+
+ atomic64_add(csbcpb->cpb.sha256.message_bit_length,
+ &(nx_ctx->stats->sha256_bytes));
+ memcpy(out, csbcpb->cpb.sha256.message_digest, SHA256_DIGEST_SIZE);
+out:
+ return rc;
+}
+
+static int nx_sha256_export(struct shash_desc *desc, void *out)
+{
+ struct sha256_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+ struct sha256_state *octx = out;
+
+ octx->count = sctx->count +
+ (csbcpb->cpb.sha256.message_bit_length / 8);
+ memcpy(octx->buf, sctx->buf, sizeof(octx->buf));
+
+ /* if no data has been processed yet, we need to export SHA256's
+ * initial data, in case this context gets imported into a software
+ * context */
+ if (csbcpb->cpb.sha256.message_bit_length)
+ memcpy(octx->state, csbcpb->cpb.sha256.message_digest,
+ SHA256_DIGEST_SIZE);
+ else {
+ octx->state[0] = SHA256_H0;
+ octx->state[1] = SHA256_H1;
+ octx->state[2] = SHA256_H2;
+ octx->state[3] = SHA256_H3;
+ octx->state[4] = SHA256_H4;
+ octx->state[5] = SHA256_H5;
+ octx->state[6] = SHA256_H6;
+ octx->state[7] = SHA256_H7;
+ }
+
+ return 0;
+}
+
+static int nx_sha256_import(struct shash_desc *desc, const void *in)
+{
+ struct sha256_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+ const struct sha256_state *ictx = in;
+
+ memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf));
+
+ sctx->count = ictx->count & 0x3f;
+ csbcpb->cpb.sha256.message_bit_length = (ictx->count & ~0x3f) * 8;
+
+ if (csbcpb->cpb.sha256.message_bit_length) {
+ memcpy(csbcpb->cpb.sha256.message_digest, ictx->state,
+ SHA256_DIGEST_SIZE);
+
+ NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+ NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+ }
+
+ return 0;
+}
+
+struct shash_alg nx_shash_sha256_alg = {
+ .digestsize = SHA256_DIGEST_SIZE,
+ .init = nx_sha256_init,
+ .update = nx_sha256_update,
+ .final = nx_sha256_final,
+ .export = nx_sha256_export,
+ .import = nx_sha256_import,
+ .descsize = sizeof(struct sha256_state),
+ .statesize = sizeof(struct sha256_state),
+ .base = {
+ .cra_name = "sha256",
+ .cra_driver_name = "sha256-nx",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_module = THIS_MODULE,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_init = nx_crypto_ctx_sha_init,
+ .cra_exit = nx_crypto_ctx_exit,
+ }
+};
diff --git a/drivers/crypto/nx/nx-sha512.c b/drivers/crypto/nx/nx-sha512.c
new file mode 100644
index 000000000000..3177b8c3d5f1
--- /dev/null
+++ b/drivers/crypto/nx/nx-sha512.c
@@ -0,0 +1,265 @@
+/**
+ * SHA-512 routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines 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; version 2 only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/hash.h>
+#include <crypto/sha.h>
+#include <linux/module.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+static int nx_sha512_init(struct shash_desc *desc)
+{
+ struct sha512_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_sg *out_sg;
+
+ nx_ctx_init(nx_ctx, HCOP_FC_SHA);
+
+ memset(sctx, 0, sizeof *sctx);
+
+ nx_ctx->ap = &nx_ctx->props[NX_PROPS_SHA512];
+
+ NX_CPB_SET_DIGEST_SIZE(nx_ctx->csbcpb, NX_DS_SHA512);
+ out_sg = nx_build_sg_list(nx_ctx->out_sg, (u8 *)sctx->state,
+ SHA512_DIGEST_SIZE, nx_ctx->ap->sglen);
+ nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+ return 0;
+}
+
+static int nx_sha512_update(struct shash_desc *desc, const u8 *data,
+ unsigned int len)
+{
+ struct sha512_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+ struct nx_sg *in_sg;
+ u64 to_process, leftover, spbc_bits;
+ int rc = 0;
+
+ if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+ /* we've hit the nx chip previously and we're updating again,
+ * so copy over the partial digest */
+ memcpy(csbcpb->cpb.sha512.input_partial_digest,
+ csbcpb->cpb.sha512.message_digest, SHA512_DIGEST_SIZE);
+ }
+
+ /* 2 cases for total data len:
+ * 1: <= SHA512_BLOCK_SIZE: copy into state, return 0
+ * 2: > SHA512_BLOCK_SIZE: process X blocks, copy in leftover
+ */
+ if ((u64)len + sctx->count[0] <= SHA512_BLOCK_SIZE) {
+ memcpy(sctx->buf + sctx->count[0], data, len);
+ sctx->count[0] += len;
+ goto out;
+ }
+
+ /* to_process: the SHA512_BLOCK_SIZE data chunk to process in this
+ * update */
+ to_process = (sctx->count[0] + len) & ~(SHA512_BLOCK_SIZE - 1);
+ leftover = (sctx->count[0] + len) & (SHA512_BLOCK_SIZE - 1);
+
+ if (sctx->count[0]) {
+ in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)sctx->buf,
+ sctx->count[0], nx_ctx->ap->sglen);
+ in_sg = nx_build_sg_list(in_sg, (u8 *)data,
+ to_process - sctx->count[0],
+ nx_ctx->ap->sglen);
+ nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+ sizeof(struct nx_sg);
+ } else {
+ in_sg = nx_build_sg_list(nx_ctx->in_sg, (u8 *)data,
+ to_process, nx_ctx->ap->sglen);
+ nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) *
+ sizeof(struct nx_sg);
+ }
+
+ NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+
+ if (!nx_ctx->op.inlen || !nx_ctx->op.outlen) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->sha512_ops));
+
+ /* copy the leftover back into the state struct */
+ memcpy(sctx->buf, data + len - leftover, leftover);
+ sctx->count[0] = leftover;
+
+ spbc_bits = csbcpb->cpb.sha512.spbc * 8;
+ csbcpb->cpb.sha512.message_bit_length_lo += spbc_bits;
+ if (csbcpb->cpb.sha512.message_bit_length_lo < spbc_bits)
+ csbcpb->cpb.sha512.message_bit_length_hi++;
+
+ /* everything after the first update is continuation */
+ NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+out:
+ return rc;
+}
+
+static int nx_sha512_final(struct shash_desc *desc, u8 *out)
+{
+ struct sha512_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+ struct nx_sg *in_sg, *out_sg;
+ u64 count0;
+ int rc;
+
+ if (NX_CPB_FDM(csbcpb) & NX_FDM_CONTINUATION) {
+ /* we've hit the nx chip previously, now we're finalizing,
+ * so copy over the partial digest */
+ memcpy(csbcpb->cpb.sha512.input_partial_digest,
+ csbcpb->cpb.sha512.message_digest, SHA512_DIGEST_SIZE);
+ }
+
+ /* final is represented by continuing the operation and indicating that
+ * this is not an intermediate operation */
+ NX_CPB_FDM(csbcpb) &= ~NX_FDM_INTERMEDIATE;
+
+ count0 = sctx->count[0] * 8;
+
+ csbcpb->cpb.sha512.message_bit_length_lo += count0;
+ if (csbcpb->cpb.sha512.message_bit_length_lo < count0)
+ csbcpb->cpb.sha512.message_bit_length_hi++;
+
+ in_sg = nx_build_sg_list(nx_ctx->in_sg, sctx->buf, sctx->count[0],
+ nx_ctx->ap->sglen);
+ out_sg = nx_build_sg_list(nx_ctx->out_sg, out, SHA512_DIGEST_SIZE,
+ nx_ctx->ap->sglen);
+ nx_ctx->op.inlen = (nx_ctx->in_sg - in_sg) * sizeof(struct nx_sg);
+ nx_ctx->op.outlen = (nx_ctx->out_sg - out_sg) * sizeof(struct nx_sg);
+
+ if (!nx_ctx->op.outlen) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ rc = nx_hcall_sync(nx_ctx, &nx_ctx->op,
+ desc->flags & CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (rc)
+ goto out;
+
+ atomic_inc(&(nx_ctx->stats->sha512_ops));
+ atomic64_add(csbcpb->cpb.sha512.message_bit_length_lo,
+ &(nx_ctx->stats->sha512_bytes));
+
+ memcpy(out, csbcpb->cpb.sha512.message_digest, SHA512_DIGEST_SIZE);
+out:
+ return rc;
+}
+
+static int nx_sha512_export(struct shash_desc *desc, void *out)
+{
+ struct sha512_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+ struct sha512_state *octx = out;
+
+ /* move message_bit_length (128 bits) into count and convert its value
+ * to bytes */
+ octx->count[0] = csbcpb->cpb.sha512.message_bit_length_lo >> 3 |
+ ((csbcpb->cpb.sha512.message_bit_length_hi & 7) << 61);
+ octx->count[1] = csbcpb->cpb.sha512.message_bit_length_hi >> 3;
+
+ octx->count[0] += sctx->count[0];
+ if (octx->count[0] < sctx->count[0])
+ octx->count[1]++;
+
+ memcpy(octx->buf, sctx->buf, sizeof(octx->buf));
+
+ /* if no data has been processed yet, we need to export SHA512's
+ * initial data, in case this context gets imported into a software
+ * context */
+ if (csbcpb->cpb.sha512.message_bit_length_hi ||
+ csbcpb->cpb.sha512.message_bit_length_lo)
+ memcpy(octx->state, csbcpb->cpb.sha512.message_digest,
+ SHA512_DIGEST_SIZE);
+ else {
+ octx->state[0] = SHA512_H0;
+ octx->state[1] = SHA512_H1;
+ octx->state[2] = SHA512_H2;
+ octx->state[3] = SHA512_H3;
+ octx->state[4] = SHA512_H4;
+ octx->state[5] = SHA512_H5;
+ octx->state[6] = SHA512_H6;
+ octx->state[7] = SHA512_H7;
+ }
+
+ return 0;
+}
+
+static int nx_sha512_import(struct shash_desc *desc, const void *in)
+{
+ struct sha512_state *sctx = shash_desc_ctx(desc);
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(&desc->tfm->base);
+ struct nx_csbcpb *csbcpb = (struct nx_csbcpb *)nx_ctx->csbcpb;
+ const struct sha512_state *ictx = in;
+
+ memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf));
+ sctx->count[0] = ictx->count[0] & 0x3f;
+ csbcpb->cpb.sha512.message_bit_length_lo = (ictx->count[0] & ~0x3f)
+ << 3;
+ csbcpb->cpb.sha512.message_bit_length_hi = ictx->count[1] << 3 |
+ ictx->count[0] >> 61;
+
+ if (csbcpb->cpb.sha512.message_bit_length_hi ||
+ csbcpb->cpb.sha512.message_bit_length_lo) {
+ memcpy(csbcpb->cpb.sha512.message_digest, ictx->state,
+ SHA512_DIGEST_SIZE);
+
+ NX_CPB_FDM(csbcpb) |= NX_FDM_CONTINUATION;
+ NX_CPB_FDM(csbcpb) |= NX_FDM_INTERMEDIATE;
+ }
+
+ return 0;
+}
+
+struct shash_alg nx_shash_sha512_alg = {
+ .digestsize = SHA512_DIGEST_SIZE,
+ .init = nx_sha512_init,
+ .update = nx_sha512_update,
+ .final = nx_sha512_final,
+ .export = nx_sha512_export,
+ .import = nx_sha512_import,
+ .descsize = sizeof(struct sha512_state),
+ .statesize = sizeof(struct sha512_state),
+ .base = {
+ .cra_name = "sha512",
+ .cra_driver_name = "sha512-nx",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = SHA512_BLOCK_SIZE,
+ .cra_module = THIS_MODULE,
+ .cra_ctxsize = sizeof(struct nx_crypto_ctx),
+ .cra_init = nx_crypto_ctx_sha_init,
+ .cra_exit = nx_crypto_ctx_exit,
+ }
+};
diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c
new file mode 100644
index 000000000000..d7f179cc2e98
--- /dev/null
+++ b/drivers/crypto/nx/nx.c
@@ -0,0 +1,716 @@
+/**
+ * Routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines 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; version 2 only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <crypto/internal/hash.h>
+#include <crypto/hash.h>
+#include <crypto/aes.h>
+#include <crypto/sha.h>
+#include <crypto/algapi.h>
+#include <crypto/scatterwalk.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <asm/pSeries_reconfig.h>
+#include <asm/abs_addr.h>
+#include <asm/hvcall.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+
+/**
+ * nx_hcall_sync - make an H_COP_OP hcall for the passed in op structure
+ *
+ * @nx_ctx: the crypto context handle
+ * @op: PFO operation struct to pass in
+ * @may_sleep: flag indicating the request can sleep
+ *
+ * Make the hcall, retrying while the hardware is busy. If we cannot yield
+ * the thread, limit the number of retries to 10 here.
+ */
+int nx_hcall_sync(struct nx_crypto_ctx *nx_ctx,
+ struct vio_pfo_op *op,
+ u32 may_sleep)
+{
+ int rc, retries = 10;
+ struct vio_dev *viodev = nx_driver.viodev;
+
+ atomic_inc(&(nx_ctx->stats->sync_ops));
+
+ do {
+ rc = vio_h_cop_sync(viodev, op);
+ } while ((rc == -EBUSY && !may_sleep && retries--) ||
+ (rc == -EBUSY && may_sleep && cond_resched()));
+
+ if (rc) {
+ dev_dbg(&viodev->dev, "vio_h_cop_sync failed: rc: %d "
+ "hcall rc: %ld\n", rc, op->hcall_err);
+ atomic_inc(&(nx_ctx->stats->errors));
+ atomic_set(&(nx_ctx->stats->last_error), op->hcall_err);
+ atomic_set(&(nx_ctx->stats->last_error_pid), current->pid);
+ }
+
+ return rc;
+}
+
+/**
+ * nx_build_sg_list - build an NX scatter list describing a single buffer
+ *
+ * @sg_head: pointer to the first scatter list element to build
+ * @start_addr: pointer to the linear buffer
+ * @len: length of the data at @start_addr
+ * @sgmax: the largest number of scatter list elements we're allowed to create
+ *
+ * This function will start writing nx_sg elements at @sg_head and keep
+ * writing them until all of the data from @start_addr is described or
+ * until sgmax elements have been written. Scatter list elements will be
+ * created such that none of the elements describes a buffer that crosses a 4K
+ * boundary.
+ */
+struct nx_sg *nx_build_sg_list(struct nx_sg *sg_head,
+ u8 *start_addr,
+ unsigned int len,
+ u32 sgmax)
+{
+ unsigned int sg_len = 0;
+ struct nx_sg *sg;
+ u64 sg_addr = (u64)start_addr;
+ u64 end_addr;
+
+ /* determine the start and end for this address range - slightly
+ * different if this is in VMALLOC_REGION */
+ if (is_vmalloc_addr(start_addr))
+ sg_addr = phys_to_abs(page_to_phys(vmalloc_to_page(start_addr)))
+ + offset_in_page(sg_addr);
+ else
+ sg_addr = virt_to_abs(sg_addr);
+
+ end_addr = sg_addr + len;
+
+ /* each iteration will write one struct nx_sg element and add the
+ * length of data described by that element to sg_len. Once @len bytes
+ * have been described (or @sgmax elements have been written), the
+ * loop ends. min_t is used to ensure @end_addr falls on the same page
+ * as sg_addr, if not, we need to create another nx_sg element for the
+ * data on the next page */
+ for (sg = sg_head; sg_len < len; sg++) {
+ sg->addr = sg_addr;
+ sg_addr = min_t(u64, NX_PAGE_NUM(sg_addr + NX_PAGE_SIZE), end_addr);
+ sg->len = sg_addr - sg->addr;
+ sg_len += sg->len;
+
+ if ((sg - sg_head) == sgmax) {
+ pr_err("nx: scatter/gather list overflow, pid: %d\n",
+ current->pid);
+ return NULL;
+ }
+ }
+
+ /* return the moved sg_head pointer */
+ return sg;
+}
+
+/**
+ * nx_walk_and_build - walk a linux scatterlist and build an nx scatterlist
+ *
+ * @nx_dst: pointer to the first nx_sg element to write
+ * @sglen: max number of nx_sg entries we're allowed to write
+ * @sg_src: pointer to the source linux scatterlist to walk
+ * @start: number of bytes to fast-forward past at the beginning of @sg_src
+ * @src_len: number of bytes to walk in @sg_src
+ */
+struct nx_sg *nx_walk_and_build(struct nx_sg *nx_dst,
+ unsigned int sglen,
+ struct scatterlist *sg_src,
+ unsigned int start,
+ unsigned int src_len)
+{
+ struct scatter_walk walk;
+ struct nx_sg *nx_sg = nx_dst;
+ unsigned int n, offset = 0, len = src_len;
+ char *dst;
+
+ /* we need to fast forward through @start bytes first */
+ for (;;) {
+ scatterwalk_start(&walk, sg_src);
+
+ if (start < offset + sg_src->length)
+ break;
+
+ offset += sg_src->length;
+ sg_src = scatterwalk_sg_next(sg_src);
+ }
+
+ /* start - offset is the number of bytes to advance in the scatterlist
+ * element we're currently looking at */
+ scatterwalk_advance(&walk, start - offset);
+
+ while (len && nx_sg) {
+ n = scatterwalk_clamp(&walk, len);
+ if (!n) {
+ scatterwalk_start(&walk, sg_next(walk.sg));
+ n = scatterwalk_clamp(&walk, len);
+ }
+ dst = scatterwalk_map(&walk);
+
+ nx_sg = nx_build_sg_list(nx_sg, dst, n, sglen);
+ len -= n;
+
+ scatterwalk_unmap(dst);
+ scatterwalk_advance(&walk, n);
+ scatterwalk_done(&walk, SCATTERWALK_FROM_SG, len);
+ }
+
+ /* return the moved destination pointer */
+ return nx_sg;
+}
+
+/**
+ * nx_build_sg_lists - walk the input scatterlists and build arrays of NX
+ * scatterlists based on them.
+ *
+ * @nx_ctx: NX crypto context for the lists we're building
+ * @desc: the block cipher descriptor for the operation
+ * @dst: destination scatterlist
+ * @src: source scatterlist
+ * @nbytes: length of data described in the scatterlists
+ * @iv: destination for the iv data, if the algorithm requires it
+ *
+ * This is common code shared by all the AES algorithms. It uses the block
+ * cipher walk routines to traverse input and output scatterlists, building
+ * corresponding NX scatterlists
+ */
+int nx_build_sg_lists(struct nx_crypto_ctx *nx_ctx,
+ struct blkcipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int nbytes,
+ u8 *iv)
+{
+ struct nx_sg *nx_insg = nx_ctx->in_sg;
+ struct nx_sg *nx_outsg = nx_ctx->out_sg;
+ struct blkcipher_walk walk;
+ int rc;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ rc = blkcipher_walk_virt_block(desc, &walk, AES_BLOCK_SIZE);
+ if (rc)
+ goto out;
+
+ if (iv)
+ memcpy(iv, walk.iv, AES_BLOCK_SIZE);
+
+ while (walk.nbytes) {
+ nx_insg = nx_build_sg_list(nx_insg, walk.src.virt.addr,
+ walk.nbytes, nx_ctx->ap->sglen);
+ nx_outsg = nx_build_sg_list(nx_outsg, walk.dst.virt.addr,
+ walk.nbytes, nx_ctx->ap->sglen);
+
+ rc = blkcipher_walk_done(desc, &walk, 0);
+ if (rc)
+ break;
+ }
+
+ if (walk.nbytes) {
+ nx_insg = nx_build_sg_list(nx_insg, walk.src.virt.addr,
+ walk.nbytes, nx_ctx->ap->sglen);
+ nx_outsg = nx_build_sg_list(nx_outsg, walk.dst.virt.addr,
+ walk.nbytes, nx_ctx->ap->sglen);
+
+ rc = 0;
+ }
+
+ /* these lengths should be negative, which will indicate to phyp that
+ * the input and output parameters are scatterlists, not linear
+ * buffers */
+ nx_ctx->op.inlen = (nx_ctx->in_sg - nx_insg) * sizeof(struct nx_sg);
+ nx_ctx->op.outlen = (nx_ctx->out_sg - nx_outsg) * sizeof(struct nx_sg);
+out:
+ return rc;
+}
+
+/**
+ * nx_ctx_init - initialize an nx_ctx's vio_pfo_op struct
+ *
+ * @nx_ctx: the nx context to initialize
+ * @function: the function code for the op
+ */
+void nx_ctx_init(struct nx_crypto_ctx *nx_ctx, unsigned int function)
+{
+ memset(nx_ctx->kmem, 0, nx_ctx->kmem_len);
+ nx_ctx->csbcpb->csb.valid |= NX_CSB_VALID_BIT;
+
+ nx_ctx->op.flags = function;
+ nx_ctx->op.csbcpb = virt_to_abs(nx_ctx->csbcpb);
+ nx_ctx->op.in = virt_to_abs(nx_ctx->in_sg);
+ nx_ctx->op.out = virt_to_abs(nx_ctx->out_sg);
+
+ if (nx_ctx->csbcpb_aead) {
+ nx_ctx->csbcpb_aead->csb.valid |= NX_CSB_VALID_BIT;
+
+ nx_ctx->op_aead.flags = function;
+ nx_ctx->op_aead.csbcpb = virt_to_abs(nx_ctx->csbcpb_aead);
+ nx_ctx->op_aead.in = virt_to_abs(nx_ctx->in_sg);
+ nx_ctx->op_aead.out = virt_to_abs(nx_ctx->out_sg);
+ }
+}
+
+static void nx_of_update_status(struct device *dev,
+ struct property *p,
+ struct nx_of *props)
+{
+ if (!strncmp(p->value, "okay", p->length)) {
+ props->status = NX_WAITING;
+ props->flags |= NX_OF_FLAG_STATUS_SET;
+ } else {
+ dev_info(dev, "%s: status '%s' is not 'okay'\n", __func__,
+ (char *)p->value);
+ }
+}
+
+static void nx_of_update_sglen(struct device *dev,
+ struct property *p,
+ struct nx_of *props)
+{
+ if (p->length != sizeof(props->max_sg_len)) {
+ dev_err(dev, "%s: unexpected format for "
+ "ibm,max-sg-len property\n", __func__);
+ dev_dbg(dev, "%s: ibm,max-sg-len is %d bytes "
+ "long, expected %zd bytes\n", __func__,
+ p->length, sizeof(props->max_sg_len));
+ return;
+ }
+
+ props->max_sg_len = *(u32 *)p->value;
+ props->flags |= NX_OF_FLAG_MAXSGLEN_SET;
+}
+
+static void nx_of_update_msc(struct device *dev,
+ struct property *p,
+ struct nx_of *props)
+{
+ struct msc_triplet *trip;
+ struct max_sync_cop *msc;
+ unsigned int bytes_so_far, i, lenp;
+
+ msc = (struct max_sync_cop *)p->value;
+ lenp = p->length;
+
+ /* You can't tell if the data read in for this property is sane by its
+ * size alone. This is because there are sizes embedded in the data
+ * structure. The best we can do is check lengths as we parse and bail
+ * as soon as a length error is detected. */
+ bytes_so_far = 0;
+
+ while ((bytes_so_far + sizeof(struct max_sync_cop)) <= lenp) {
+ bytes_so_far += sizeof(struct max_sync_cop);
+
+ trip = msc->trip;
+
+ for (i = 0;
+ ((bytes_so_far + sizeof(struct msc_triplet)) <= lenp) &&
+ i < msc->triplets;
+ i++) {
+ if (msc->fc > NX_MAX_FC || msc->mode > NX_MAX_MODE) {
+ dev_err(dev, "unknown function code/mode "
+ "combo: %d/%d (ignored)\n", msc->fc,
+ msc->mode);
+ goto next_loop;
+ }
+
+ switch (trip->keybitlen) {
+ case 128:
+ case 160:
+ props->ap[msc->fc][msc->mode][0].databytelen =
+ trip->databytelen;
+ props->ap[msc->fc][msc->mode][0].sglen =
+ trip->sglen;
+ break;
+ case 192:
+ props->ap[msc->fc][msc->mode][1].databytelen =
+ trip->databytelen;
+ props->ap[msc->fc][msc->mode][1].sglen =
+ trip->sglen;
+ break;
+ case 256:
+ if (msc->fc == NX_FC_AES) {
+ props->ap[msc->fc][msc->mode][2].
+ databytelen = trip->databytelen;
+ props->ap[msc->fc][msc->mode][2].sglen =
+ trip->sglen;
+ } else if (msc->fc == NX_FC_AES_HMAC ||
+ msc->fc == NX_FC_SHA) {
+ props->ap[msc->fc][msc->mode][1].
+ databytelen = trip->databytelen;
+ props->ap[msc->fc][msc->mode][1].sglen =
+ trip->sglen;
+ } else {
+ dev_warn(dev, "unknown function "
+ "code/key bit len combo"
+ ": (%u/256)\n", msc->fc);
+ }
+ break;
+ case 512:
+ props->ap[msc->fc][msc->mode][2].databytelen =
+ trip->databytelen;
+ props->ap[msc->fc][msc->mode][2].sglen =
+ trip->sglen;
+ break;
+ default:
+ dev_warn(dev, "unknown function code/key bit "
+ "len combo: (%u/%u)\n", msc->fc,
+ trip->keybitlen);
+ break;
+ }
+next_loop:
+ bytes_so_far += sizeof(struct msc_triplet);
+ trip++;
+ }
+
+ msc = (struct max_sync_cop *)trip;
+ }
+
+ props->flags |= NX_OF_FLAG_MAXSYNCCOP_SET;
+}
+
+/**
+ * nx_of_init - read openFirmware values from the device tree
+ *
+ * @dev: device handle
+ * @props: pointer to struct to hold the properties values
+ *
+ * Called once at driver probe time, this function will read out the
+ * openFirmware properties we use at runtime. If all the OF properties are
+ * acceptable, when we exit this function props->flags will indicate that
+ * we're ready to register our crypto algorithms.
+ */
+static void nx_of_init(struct device *dev, struct nx_of *props)
+{
+ struct device_node *base_node = dev->of_node;
+ struct property *p;
+
+ p = of_find_property(base_node, "status", NULL);
+ if (!p)
+ dev_info(dev, "%s: property 'status' not found\n", __func__);
+ else
+ nx_of_update_status(dev, p, props);
+
+ p = of_find_property(base_node, "ibm,max-sg-len", NULL);
+ if (!p)
+ dev_info(dev, "%s: property 'ibm,max-sg-len' not found\n",
+ __func__);
+ else
+ nx_of_update_sglen(dev, p, props);
+
+ p = of_find_property(base_node, "ibm,max-sync-cop", NULL);
+ if (!p)
+ dev_info(dev, "%s: property 'ibm,max-sync-cop' not found\n",
+ __func__);
+ else
+ nx_of_update_msc(dev, p, props);
+}
+
+/**
+ * nx_register_algs - register algorithms with the crypto API
+ *
+ * Called from nx_probe()
+ *
+ * If all OF properties are in an acceptable state, the driver flags will
+ * indicate that we're ready and we'll create our debugfs files and register
+ * out crypto algorithms.
+ */
+static int nx_register_algs(void)
+{
+ int rc = -1;
+
+ if (nx_driver.of.flags != NX_OF_FLAG_MASK_READY)
+ goto out;
+
+ memset(&nx_driver.stats, 0, sizeof(struct nx_stats));
+
+ rc = NX_DEBUGFS_INIT(&nx_driver);
+ if (rc)
+ goto out;
+
+ rc = crypto_register_alg(&nx_ecb_aes_alg);
+ if (rc)
+ goto out;
+
+ rc = crypto_register_alg(&nx_cbc_aes_alg);
+ if (rc)
+ goto out_unreg_ecb;
+
+ rc = crypto_register_alg(&nx_ctr_aes_alg);
+ if (rc)
+ goto out_unreg_cbc;
+
+ rc = crypto_register_alg(&nx_ctr3686_aes_alg);
+ if (rc)
+ goto out_unreg_ctr;
+
+ rc = crypto_register_alg(&nx_gcm_aes_alg);
+ if (rc)
+ goto out_unreg_ctr3686;
+
+ rc = crypto_register_alg(&nx_gcm4106_aes_alg);
+ if (rc)
+ goto out_unreg_gcm;
+
+ rc = crypto_register_alg(&nx_ccm_aes_alg);
+ if (rc)
+ goto out_unreg_gcm4106;
+
+ rc = crypto_register_alg(&nx_ccm4309_aes_alg);
+ if (rc)
+ goto out_unreg_ccm;
+
+ rc = crypto_register_shash(&nx_shash_sha256_alg);
+ if (rc)
+ goto out_unreg_ccm4309;
+
+ rc = crypto_register_shash(&nx_shash_sha512_alg);
+ if (rc)
+ goto out_unreg_s256;
+
+ rc = crypto_register_shash(&nx_shash_aes_xcbc_alg);
+ if (rc)
+ goto out_unreg_s512;
+
+ nx_driver.of.status = NX_OKAY;
+
+ goto out;
+
+out_unreg_s512:
+ crypto_unregister_shash(&nx_shash_sha512_alg);
+out_unreg_s256:
+ crypto_unregister_shash(&nx_shash_sha256_alg);
+out_unreg_ccm4309:
+ crypto_unregister_alg(&nx_ccm4309_aes_alg);
+out_unreg_ccm:
+ crypto_unregister_alg(&nx_ccm_aes_alg);
+out_unreg_gcm4106:
+ crypto_unregister_alg(&nx_gcm4106_aes_alg);
+out_unreg_gcm:
+ crypto_unregister_alg(&nx_gcm_aes_alg);
+out_unreg_ctr3686:
+ crypto_unregister_alg(&nx_ctr3686_aes_alg);
+out_unreg_ctr:
+ crypto_unregister_alg(&nx_ctr_aes_alg);
+out_unreg_cbc:
+ crypto_unregister_alg(&nx_cbc_aes_alg);
+out_unreg_ecb:
+ crypto_unregister_alg(&nx_ecb_aes_alg);
+out:
+ return rc;
+}
+
+/**
+ * nx_crypto_ctx_init - create and initialize a crypto api context
+ *
+ * @nx_ctx: the crypto api context
+ * @fc: function code for the context
+ * @mode: the function code specific mode for this context
+ */
+static int nx_crypto_ctx_init(struct nx_crypto_ctx *nx_ctx, u32 fc, u32 mode)
+{
+ if (nx_driver.of.status != NX_OKAY) {
+ pr_err("Attempt to initialize NX crypto context while device "
+ "is not available!\n");
+ return -ENODEV;
+ }
+
+ /* we need an extra page for csbcpb_aead for these modes */
+ if (mode == NX_MODE_AES_GCM || mode == NX_MODE_AES_CCM)
+ nx_ctx->kmem_len = (4 * NX_PAGE_SIZE) +
+ sizeof(struct nx_csbcpb);
+ else
+ nx_ctx->kmem_len = (3 * NX_PAGE_SIZE) +
+ sizeof(struct nx_csbcpb);
+
+ nx_ctx->kmem = kmalloc(nx_ctx->kmem_len, GFP_KERNEL);
+ if (!nx_ctx->kmem)
+ return -ENOMEM;
+
+ /* the csbcpb and scatterlists must be 4K aligned pages */
+ nx_ctx->csbcpb = (struct nx_csbcpb *)(round_up((u64)nx_ctx->kmem,
+ (u64)NX_PAGE_SIZE));
+ nx_ctx->in_sg = (struct nx_sg *)((u8 *)nx_ctx->csbcpb + NX_PAGE_SIZE);
+ nx_ctx->out_sg = (struct nx_sg *)((u8 *)nx_ctx->in_sg + NX_PAGE_SIZE);
+
+ if (mode == NX_MODE_AES_GCM || mode == NX_MODE_AES_CCM)
+ nx_ctx->csbcpb_aead =
+ (struct nx_csbcpb *)((u8 *)nx_ctx->out_sg +
+ NX_PAGE_SIZE);
+
+ /* give each context a pointer to global stats and their OF
+ * properties */
+ nx_ctx->stats = &nx_driver.stats;
+ memcpy(nx_ctx->props, nx_driver.of.ap[fc][mode],
+ sizeof(struct alg_props) * 3);
+
+ return 0;
+}
+
+/* entry points from the crypto tfm initializers */
+int nx_crypto_ctx_aes_ccm_init(struct crypto_tfm *tfm)
+{
+ return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+ NX_MODE_AES_CCM);
+}
+
+int nx_crypto_ctx_aes_gcm_init(struct crypto_tfm *tfm)
+{
+ return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+ NX_MODE_AES_GCM);
+}
+
+int nx_crypto_ctx_aes_ctr_init(struct crypto_tfm *tfm)
+{
+ return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+ NX_MODE_AES_CTR);
+}
+
+int nx_crypto_ctx_aes_cbc_init(struct crypto_tfm *tfm)
+{
+ return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+ NX_MODE_AES_CBC);
+}
+
+int nx_crypto_ctx_aes_ecb_init(struct crypto_tfm *tfm)
+{
+ return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+ NX_MODE_AES_ECB);
+}
+
+int nx_crypto_ctx_sha_init(struct crypto_tfm *tfm)
+{
+ return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_SHA, NX_MODE_SHA);
+}
+
+int nx_crypto_ctx_aes_xcbc_init(struct crypto_tfm *tfm)
+{
+ return nx_crypto_ctx_init(crypto_tfm_ctx(tfm), NX_FC_AES,
+ NX_MODE_AES_XCBC_MAC);
+}
+
+/**
+ * nx_crypto_ctx_exit - destroy a crypto api context
+ *
+ * @tfm: the crypto transform pointer for the context
+ *
+ * As crypto API contexts are destroyed, this exit hook is called to free the
+ * memory associated with it.
+ */
+void nx_crypto_ctx_exit(struct crypto_tfm *tfm)
+{
+ struct nx_crypto_ctx *nx_ctx = crypto_tfm_ctx(tfm);
+
+ kzfree(nx_ctx->kmem);
+ nx_ctx->csbcpb = NULL;
+ nx_ctx->csbcpb_aead = NULL;
+ nx_ctx->in_sg = NULL;
+ nx_ctx->out_sg = NULL;
+}
+
+static int __devinit nx_probe(struct vio_dev *viodev,
+ const struct vio_device_id *id)
+{
+ dev_dbg(&viodev->dev, "driver probed: %s resource id: 0x%x\n",
+ viodev->name, viodev->resource_id);
+
+ if (nx_driver.viodev) {
+ dev_err(&viodev->dev, "%s: Attempt to register more than one "
+ "instance of the hardware\n", __func__);
+ return -EINVAL;
+ }
+
+ nx_driver.viodev = viodev;
+
+ nx_of_init(&viodev->dev, &nx_driver.of);
+
+ return nx_register_algs();
+}
+
+static int __devexit nx_remove(struct vio_dev *viodev)
+{
+ dev_dbg(&viodev->dev, "entering nx_remove for UA 0x%x\n",
+ viodev->unit_address);
+
+ if (nx_driver.of.status == NX_OKAY) {
+ NX_DEBUGFS_FINI(&nx_driver);
+
+ crypto_unregister_alg(&nx_ccm_aes_alg);
+ crypto_unregister_alg(&nx_ccm4309_aes_alg);
+ crypto_unregister_alg(&nx_gcm_aes_alg);
+ crypto_unregister_alg(&nx_gcm4106_aes_alg);
+ crypto_unregister_alg(&nx_ctr_aes_alg);
+ crypto_unregister_alg(&nx_ctr3686_aes_alg);
+ crypto_unregister_alg(&nx_cbc_aes_alg);
+ crypto_unregister_alg(&nx_ecb_aes_alg);
+ crypto_unregister_shash(&nx_shash_sha256_alg);
+ crypto_unregister_shash(&nx_shash_sha512_alg);
+ crypto_unregister_shash(&nx_shash_aes_xcbc_alg);
+ }
+
+ return 0;
+}
+
+
+/* module wide initialization/cleanup */
+static int __init nx_init(void)
+{
+ return vio_register_driver(&nx_driver.viodriver);
+}
+
+static void __exit nx_fini(void)
+{
+ vio_unregister_driver(&nx_driver.viodriver);
+}
+
+static struct vio_device_id nx_crypto_driver_ids[] __devinitdata = {
+ { "ibm,sym-encryption-v1", "ibm,sym-encryption" },
+ { "", "" }
+};
+MODULE_DEVICE_TABLE(vio, nx_crypto_driver_ids);
+
+/* driver state structure */
+struct nx_crypto_driver nx_driver = {
+ .viodriver = {
+ .id_table = nx_crypto_driver_ids,
+ .probe = nx_probe,
+ .remove = nx_remove,
+ .name = NX_NAME,
+ },
+};
+
+module_init(nx_init);
+module_exit(nx_fini);
+
+MODULE_AUTHOR("Kent Yoder <yoder1@us.ibm.com>");
+MODULE_DESCRIPTION(NX_STRING);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(NX_VERSION);
diff --git a/drivers/crypto/nx/nx.h b/drivers/crypto/nx/nx.h
new file mode 100644
index 000000000000..3232b182dd28
--- /dev/null
+++ b/drivers/crypto/nx/nx.h
@@ -0,0 +1,193 @@
+
+#ifndef __NX_H__
+#define __NX_H__
+
+#define NX_NAME "nx-crypto"
+#define NX_STRING "IBM Power7+ Nest Accelerator Crypto Driver"
+#define NX_VERSION "1.0"
+
+static const char nx_driver_string[] = NX_STRING;
+static const char nx_driver_version[] = NX_VERSION;
+
+/* a scatterlist in the format PHYP is expecting */
+struct nx_sg {
+ u64 addr;
+ u32 rsvd;
+ u32 len;
+} __attribute((packed));
+
+#define NX_PAGE_SIZE (4096)
+#define NX_MAX_SG_ENTRIES (NX_PAGE_SIZE/(sizeof(struct nx_sg)))
+
+enum nx_status {
+ NX_DISABLED,
+ NX_WAITING,
+ NX_OKAY
+};
+
+/* msc_triplet and max_sync_cop are used only to assist in parsing the
+ * openFirmware property */
+struct msc_triplet {
+ u32 keybitlen;
+ u32 databytelen;
+ u32 sglen;
+} __packed;
+
+struct max_sync_cop {
+ u32 fc;
+ u32 mode;
+ u32 triplets;
+ struct msc_triplet trip[0];
+} __packed;
+
+struct alg_props {
+ u32 databytelen;
+ u32 sglen;
+};
+
+#define NX_OF_FLAG_MAXSGLEN_SET (1)
+#define NX_OF_FLAG_STATUS_SET (2)
+#define NX_OF_FLAG_MAXSYNCCOP_SET (4)
+#define NX_OF_FLAG_MASK_READY (NX_OF_FLAG_MAXSGLEN_SET | \
+ NX_OF_FLAG_STATUS_SET | \
+ NX_OF_FLAG_MAXSYNCCOP_SET)
+struct nx_of {
+ u32 flags;
+ u32 max_sg_len;
+ enum nx_status status;
+ struct alg_props ap[NX_MAX_FC][NX_MAX_MODE][3];
+};
+
+struct nx_stats {
+ atomic_t aes_ops;
+ atomic64_t aes_bytes;
+ atomic_t sha256_ops;
+ atomic64_t sha256_bytes;
+ atomic_t sha512_ops;
+ atomic64_t sha512_bytes;
+
+ atomic_t sync_ops;
+
+ atomic_t errors;
+ atomic_t last_error;
+ atomic_t last_error_pid;
+};
+
+struct nx_debugfs {
+ struct dentry *dfs_root;
+ struct dentry *dfs_aes_ops, *dfs_aes_bytes;
+ struct dentry *dfs_sha256_ops, *dfs_sha256_bytes;
+ struct dentry *dfs_sha512_ops, *dfs_sha512_bytes;
+ struct dentry *dfs_errors, *dfs_last_error, *dfs_last_error_pid;
+};
+
+struct nx_crypto_driver {
+ struct nx_stats stats;
+ struct nx_of of;
+ struct vio_dev *viodev;
+ struct vio_driver viodriver;
+ struct nx_debugfs dfs;
+};
+
+#define NX_GCM4106_NONCE_LEN (4)
+#define NX_GCM_CTR_OFFSET (12)
+struct nx_gcm_priv {
+ u8 iv[16];
+ u8 iauth_tag[16];
+ u8 nonce[NX_GCM4106_NONCE_LEN];
+};
+
+#define NX_CCM_AES_KEY_LEN (16)
+#define NX_CCM4309_AES_KEY_LEN (19)
+#define NX_CCM4309_NONCE_LEN (3)
+struct nx_ccm_priv {
+ u8 iv[16];
+ u8 b0[16];
+ u8 iauth_tag[16];
+ u8 oauth_tag[16];
+ u8 nonce[NX_CCM4309_NONCE_LEN];
+};
+
+struct nx_xcbc_priv {
+ u8 key[16];
+};
+
+struct nx_ctr_priv {
+ u8 iv[16];
+};
+
+struct nx_crypto_ctx {
+ void *kmem; /* unaligned, kmalloc'd buffer */
+ size_t kmem_len; /* length of kmem */
+ struct nx_csbcpb *csbcpb; /* aligned page given to phyp @ hcall time */
+ struct vio_pfo_op op; /* operation struct with hcall parameters */
+ struct nx_csbcpb *csbcpb_aead; /* secondary csbcpb used by AEAD algs */
+ struct vio_pfo_op op_aead;/* operation struct for csbcpb_aead */
+
+ struct nx_sg *in_sg; /* aligned pointer into kmem to an sg list */
+ struct nx_sg *out_sg; /* aligned pointer into kmem to an sg list */
+
+ struct alg_props *ap; /* pointer into props based on our key size */
+ struct alg_props props[3];/* openFirmware properties for requests */
+ struct nx_stats *stats; /* pointer into an nx_crypto_driver for stats
+ reporting */
+
+ union {
+ struct nx_gcm_priv gcm;
+ struct nx_ccm_priv ccm;
+ struct nx_xcbc_priv xcbc;
+ struct nx_ctr_priv ctr;
+ } priv;
+};
+
+/* prototypes */
+int nx_crypto_ctx_aes_ccm_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_aes_gcm_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_aes_xcbc_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_aes_ctr_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_aes_cbc_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_aes_ecb_init(struct crypto_tfm *tfm);
+int nx_crypto_ctx_sha_init(struct crypto_tfm *tfm);
+void nx_crypto_ctx_exit(struct crypto_tfm *tfm);
+void nx_ctx_init(struct nx_crypto_ctx *nx_ctx, unsigned int function);
+int nx_hcall_sync(struct nx_crypto_ctx *ctx, struct vio_pfo_op *op,
+ u32 may_sleep);
+struct nx_sg *nx_build_sg_list(struct nx_sg *, u8 *, unsigned int, u32);
+int nx_build_sg_lists(struct nx_crypto_ctx *, struct blkcipher_desc *,
+ struct scatterlist *, struct scatterlist *, unsigned int,
+ u8 *);
+struct nx_sg *nx_walk_and_build(struct nx_sg *, unsigned int,
+ struct scatterlist *, unsigned int,
+ unsigned int);
+
+#ifdef CONFIG_DEBUG_FS
+#define NX_DEBUGFS_INIT(drv) nx_debugfs_init(drv)
+#define NX_DEBUGFS_FINI(drv) nx_debugfs_fini(drv)
+
+int nx_debugfs_init(struct nx_crypto_driver *);
+void nx_debugfs_fini(struct nx_crypto_driver *);
+#else
+#define NX_DEBUGFS_INIT(drv) (0)
+#define NX_DEBUGFS_FINI(drv) (0)
+#endif
+
+#define NX_PAGE_NUM(x) ((u64)(x) & 0xfffffffffffff000ULL)
+
+extern struct crypto_alg nx_cbc_aes_alg;
+extern struct crypto_alg nx_ecb_aes_alg;
+extern struct crypto_alg nx_gcm_aes_alg;
+extern struct crypto_alg nx_gcm4106_aes_alg;
+extern struct crypto_alg nx_ctr_aes_alg;
+extern struct crypto_alg nx_ctr3686_aes_alg;
+extern struct crypto_alg nx_ccm_aes_alg;
+extern struct crypto_alg nx_ccm4309_aes_alg;
+extern struct shash_alg nx_shash_aes_xcbc_alg;
+extern struct shash_alg nx_shash_sha512_alg;
+extern struct shash_alg nx_shash_sha256_alg;
+
+extern struct nx_crypto_driver nx_driver;
+
+#define SCATTERWALK_TO_SG 1
+#define SCATTERWALK_FROM_SG 0
+
+#endif
diff --git a/drivers/crypto/nx/nx_csbcpb.h b/drivers/crypto/nx/nx_csbcpb.h
new file mode 100644
index 000000000000..a304f956d6f8
--- /dev/null
+++ b/drivers/crypto/nx/nx_csbcpb.h
@@ -0,0 +1,205 @@
+
+#ifndef __NX_CSBCPB_H__
+#define __NX_CSBCPB_H__
+
+struct cop_symcpb_aes_ecb {
+ u8 key[32];
+ u8 __rsvd[80];
+} __packed;
+
+struct cop_symcpb_aes_cbc {
+ u8 iv[16];
+ u8 key[32];
+ u8 cv[16];
+ u32 spbc;
+ u8 __rsvd[44];
+} __packed;
+
+struct cop_symcpb_aes_gca {
+ u8 in_pat[16];
+ u8 key[32];
+ u8 out_pat[16];
+ u32 spbc;
+ u8 __rsvd[44];
+} __packed;
+
+struct cop_symcpb_aes_gcm {
+ u8 in_pat_or_aad[16];
+ u8 iv_or_cnt[16];
+ u64 bit_length_aad;
+ u64 bit_length_data;
+ u8 in_s0[16];
+ u8 key[32];
+ u8 __rsvd1[16];
+ u8 out_pat_or_mac[16];
+ u8 out_s0[16];
+ u8 out_cnt[16];
+ u32 spbc;
+ u8 __rsvd2[12];
+} __packed;
+
+struct cop_symcpb_aes_ctr {
+ u8 iv[16];
+ u8 key[32];
+ u8 cv[16];
+ u32 spbc;
+ u8 __rsvd2[44];
+} __packed;
+
+struct cop_symcpb_aes_cca {
+ u8 b0[16];
+ u8 b1[16];
+ u8 key[16];
+ u8 out_pat_or_b0[16];
+ u32 spbc;
+ u8 __rsvd[44];
+} __packed;
+
+struct cop_symcpb_aes_ccm {
+ u8 in_pat_or_b0[16];
+ u8 iv_or_ctr[16];
+ u8 in_s0[16];
+ u8 key[16];
+ u8 __rsvd1[48];
+ u8 out_pat_or_mac[16];
+ u8 out_s0[16];
+ u8 out_ctr[16];
+ u32 spbc;
+ u8 __rsvd2[12];
+} __packed;
+
+struct cop_symcpb_aes_xcbc {
+ u8 cv[16];
+ u8 key[16];
+ u8 __rsvd1[16];
+ u8 out_cv_mac[16];
+ u32 spbc;
+ u8 __rsvd2[44];
+} __packed;
+
+struct cop_symcpb_sha256 {
+ u64 message_bit_length;
+ u64 __rsvd1;
+ u8 input_partial_digest[32];
+ u8 message_digest[32];
+ u32 spbc;
+ u8 __rsvd2[44];
+} __packed;
+
+struct cop_symcpb_sha512 {
+ u64 message_bit_length_hi;
+ u64 message_bit_length_lo;
+ u8 input_partial_digest[64];
+ u8 __rsvd1[32];
+ u8 message_digest[64];
+ u32 spbc;
+ u8 __rsvd2[76];
+} __packed;
+
+#define NX_FDM_INTERMEDIATE 0x01
+#define NX_FDM_CONTINUATION 0x02
+#define NX_FDM_ENDE_ENCRYPT 0x80
+
+#define NX_CPB_FDM(c) ((c)->cpb.hdr.fdm)
+#define NX_CPB_KS_DS(c) ((c)->cpb.hdr.ks_ds)
+
+#define NX_CPB_KEY_SIZE(c) (NX_CPB_KS_DS(c) >> 4)
+#define NX_CPB_SET_KEY_SIZE(c, x) NX_CPB_KS_DS(c) |= ((x) << 4)
+#define NX_CPB_SET_DIGEST_SIZE(c, x) NX_CPB_KS_DS(c) |= (x)
+
+struct cop_symcpb_header {
+ u8 mode;
+ u8 fdm;
+ u8 ks_ds;
+ u8 pad_byte;
+ u8 __rsvd[12];
+} __packed;
+
+struct cop_parameter_block {
+ struct cop_symcpb_header hdr;
+ union {
+ struct cop_symcpb_aes_ecb aes_ecb;
+ struct cop_symcpb_aes_cbc aes_cbc;
+ struct cop_symcpb_aes_gca aes_gca;
+ struct cop_symcpb_aes_gcm aes_gcm;
+ struct cop_symcpb_aes_cca aes_cca;
+ struct cop_symcpb_aes_ccm aes_ccm;
+ struct cop_symcpb_aes_ctr aes_ctr;
+ struct cop_symcpb_aes_xcbc aes_xcbc;
+ struct cop_symcpb_sha256 sha256;
+ struct cop_symcpb_sha512 sha512;
+ };
+} __packed;
+
+#define NX_CSB_VALID_BIT 0x80
+
+/* co-processor status block */
+struct cop_status_block {
+ u8 valid;
+ u8 crb_seq_number;
+ u8 completion_code;
+ u8 completion_extension;
+ u32 processed_byte_count;
+ u64 address;
+} __packed;
+
+/* Nest accelerator workbook section 4.4 */
+struct nx_csbcpb {
+ unsigned char __rsvd[112];
+ struct cop_status_block csb;
+ struct cop_parameter_block cpb;
+} __packed;
+
+/* nx_csbcpb related definitions */
+#define NX_MODE_AES_ECB 0
+#define NX_MODE_AES_CBC 1
+#define NX_MODE_AES_GMAC 2
+#define NX_MODE_AES_GCA 3
+#define NX_MODE_AES_GCM 4
+#define NX_MODE_AES_CCA 5
+#define NX_MODE_AES_CCM 6
+#define NX_MODE_AES_CTR 7
+#define NX_MODE_AES_XCBC_MAC 20
+#define NX_MODE_SHA 0
+#define NX_MODE_SHA_HMAC 1
+#define NX_MODE_AES_CBC_HMAC_ETA 8
+#define NX_MODE_AES_CBC_HMAC_ATE 9
+#define NX_MODE_AES_CBC_HMAC_EAA 10
+#define NX_MODE_AES_CTR_HMAC_ETA 12
+#define NX_MODE_AES_CTR_HMAC_ATE 13
+#define NX_MODE_AES_CTR_HMAC_EAA 14
+
+#define NX_FDM_CI_FULL 0
+#define NX_FDM_CI_FIRST 1
+#define NX_FDM_CI_LAST 2
+#define NX_FDM_CI_MIDDLE 3
+
+#define NX_FDM_PR_NONE 0
+#define NX_FDM_PR_PAD 1
+
+#define NX_KS_AES_128 1
+#define NX_KS_AES_192 2
+#define NX_KS_AES_256 3
+
+#define NX_DS_SHA256 2
+#define NX_DS_SHA512 3
+
+#define NX_FC_AES 0
+#define NX_FC_SHA 2
+#define NX_FC_AES_HMAC 6
+
+#define NX_MAX_FC (NX_FC_AES_HMAC + 1)
+#define NX_MAX_MODE (NX_MODE_AES_XCBC_MAC + 1)
+
+#define HCOP_FC_AES NX_FC_AES
+#define HCOP_FC_SHA NX_FC_SHA
+#define HCOP_FC_AES_HMAC NX_FC_AES_HMAC
+
+/* indices into the array of algorithm properties */
+#define NX_PROPS_AES_128 0
+#define NX_PROPS_AES_192 1
+#define NX_PROPS_AES_256 2
+#define NX_PROPS_SHA256 1
+#define NX_PROPS_SHA512 2
+
+#endif
diff --git a/drivers/crypto/nx/nx_debugfs.c b/drivers/crypto/nx/nx_debugfs.c
new file mode 100644
index 000000000000..7ab2e8dcd9b4
--- /dev/null
+++ b/drivers/crypto/nx/nx_debugfs.c
@@ -0,0 +1,103 @@
+/**
+ * debugfs routines supporting the Power 7+ Nest Accelerators driver
+ *
+ * Copyright (C) 2011-2012 International Business Machines 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; version 2 only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Author: Kent Yoder <yoder1@us.ibm.com>
+ */
+
+#include <linux/device.h>
+#include <linux/kobject.h>
+#include <linux/string.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/crypto.h>
+#include <crypto/hash.h>
+#include <asm/vio.h>
+
+#include "nx_csbcpb.h"
+#include "nx.h"
+
+#ifdef CONFIG_DEBUG_FS
+
+/*
+ * debugfs
+ *
+ * For documentation on these attributes, please see:
+ *
+ * Documentation/ABI/testing/debugfs-pfo-nx-crypto
+ */
+
+int nx_debugfs_init(struct nx_crypto_driver *drv)
+{
+ struct nx_debugfs *dfs = &drv->dfs;
+
+ dfs->dfs_root = debugfs_create_dir(NX_NAME, NULL);
+
+ dfs->dfs_aes_ops =
+ debugfs_create_u32("aes_ops",
+ S_IRUSR | S_IRGRP | S_IROTH,
+ dfs->dfs_root, (u32 *)&drv->stats.aes_ops);
+ dfs->dfs_sha256_ops =
+ debugfs_create_u32("sha256_ops",
+ S_IRUSR | S_IRGRP | S_IROTH,
+ dfs->dfs_root,
+ (u32 *)&drv->stats.sha256_ops);
+ dfs->dfs_sha512_ops =
+ debugfs_create_u32("sha512_ops",
+ S_IRUSR | S_IRGRP | S_IROTH,
+ dfs->dfs_root,
+ (u32 *)&drv->stats.sha512_ops);
+ dfs->dfs_aes_bytes =
+ debugfs_create_u64("aes_bytes",
+ S_IRUSR | S_IRGRP | S_IROTH,
+ dfs->dfs_root,
+ (u64 *)&drv->stats.aes_bytes);
+ dfs->dfs_sha256_bytes =
+ debugfs_create_u64("sha256_bytes",
+ S_IRUSR | S_IRGRP | S_IROTH,
+ dfs->dfs_root,
+ (u64 *)&drv->stats.sha256_bytes);
+ dfs->dfs_sha512_bytes =
+ debugfs_create_u64("sha512_bytes",
+ S_IRUSR | S_IRGRP | S_IROTH,
+ dfs->dfs_root,
+ (u64 *)&drv->stats.sha512_bytes);
+ dfs->dfs_errors =
+ debugfs_create_u32("errors",
+ S_IRUSR | S_IRGRP | S_IROTH,
+ dfs->dfs_root, (u32 *)&drv->stats.errors);
+ dfs->dfs_last_error =
+ debugfs_create_u32("last_error",
+ S_IRUSR | S_IRGRP | S_IROTH,
+ dfs->dfs_root,
+ (u32 *)&drv->stats.last_error);
+ dfs->dfs_last_error_pid =
+ debugfs_create_u32("last_error_pid",
+ S_IRUSR | S_IRGRP | S_IROTH,
+ dfs->dfs_root,
+ (u32 *)&drv->stats.last_error_pid);
+ return 0;
+}
+
+void
+nx_debugfs_fini(struct nx_crypto_driver *drv)
+{
+ debugfs_remove_recursive(drv->dfs.dfs_root);
+}
+
+#endif
diff --git a/drivers/crypto/ux500/Kconfig b/drivers/crypto/ux500/Kconfig
new file mode 100644
index 000000000000..b35e5c4b025a
--- /dev/null
+++ b/drivers/crypto/ux500/Kconfig
@@ -0,0 +1,30 @@
+#
+# Copyright (C) ST-Ericsson SA 2010
+# Author: Shujuan Chen (shujuan.chen@stericsson.com)
+# License terms: GNU General Public License (GPL) version 2
+#
+
+config CRYPTO_DEV_UX500_CRYP
+ tristate "UX500 crypto driver for CRYP block"
+ depends on CRYPTO_DEV_UX500
+ select CRYPTO_DES
+ help
+ This selects the crypto driver for the UX500_CRYP hardware. It supports
+ AES-ECB, CBC and CTR with keys sizes of 128, 192 and 256 bit sizes.
+
+config CRYPTO_DEV_UX500_HASH
+ tristate "UX500 crypto driver for HASH block"
+ depends on CRYPTO_DEV_UX500
+ select CRYPTO_HASH
+ select CRYPTO_HMAC
+ help
+ This selects the hash driver for the UX500_HASH hardware.
+ Depends on UX500/STM DMA if running in DMA mode.
+
+config CRYPTO_DEV_UX500_DEBUG
+ bool "Activate ux500 platform debug-mode for crypto and hash block"
+ depends on CRYPTO_DEV_UX500_CRYP || CRYPTO_DEV_UX500_HASH
+ default n
+ help
+ Say Y if you want to add debug prints to ux500_hash and
+ ux500_cryp devices.
diff --git a/drivers/crypto/ux500/Makefile b/drivers/crypto/ux500/Makefile
new file mode 100644
index 000000000000..b9a365bade86
--- /dev/null
+++ b/drivers/crypto/ux500/Makefile
@@ -0,0 +1,8 @@
+#
+# Copyright (C) ST-Ericsson SA 2010
+# Author: Shujuan Chen (shujuan.chen@stericsson.com)
+# License terms: GNU General Public License (GPL) version 2
+#
+
+obj-$(CONFIG_CRYPTO_DEV_UX500_HASH) += hash/
+obj-$(CONFIG_CRYPTO_DEV_UX500_CRYP) += cryp/
diff --git a/drivers/crypto/ux500/cryp/Makefile b/drivers/crypto/ux500/cryp/Makefile
new file mode 100644
index 000000000000..e5d362a6f680
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/Makefile
@@ -0,0 +1,13 @@
+#/*
+# * Copyright (C) ST-Ericsson SA 2010
+# * Author: shujuan.chen@stericsson.com for ST-Ericsson.
+# * License terms: GNU General Public License (GPL) version 2 */
+
+ifdef CONFIG_CRYPTO_DEV_UX500_DEBUG
+CFLAGS_cryp_core.o := -DDEBUG -O0
+CFLAGS_cryp.o := -DDEBUG -O0
+CFLAGS_cryp_irq.o := -DDEBUG -O0
+endif
+
+obj-$(CONFIG_CRYPTO_DEV_UX500_CRYP) += ux500_cryp.o
+ux500_cryp-objs := cryp.o cryp_irq.o cryp_core.o
diff --git a/drivers/crypto/ux500/cryp/cryp.c b/drivers/crypto/ux500/cryp/cryp.c
new file mode 100644
index 000000000000..e208ceaf81c9
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/cryp.c
@@ -0,0 +1,389 @@
+/**
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson.
+ * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson.
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include <mach/hardware.h>
+
+#include "cryp_p.h"
+#include "cryp.h"
+
+/**
+ * cryp_wait_until_done - wait until the device logic is not busy
+ */
+void cryp_wait_until_done(struct cryp_device_data *device_data)
+{
+ while (cryp_is_logic_busy(device_data))
+ cpu_relax();
+}
+
+/**
+ * cryp_check - This routine checks Peripheral and PCell Id
+ * @device_data: Pointer to the device data struct for base address.
+ */
+int cryp_check(struct cryp_device_data *device_data)
+{
+ int peripheralid2 = 0;
+
+ if (NULL == device_data)
+ return -EINVAL;
+
+ peripheralid2 = readl_relaxed(&device_data->base->periphId2);
+
+ if (peripheralid2 != CRYP_PERIPHERAL_ID2_DB8500)
+ return -EPERM;
+
+ /* Check Peripheral and Pcell Id Register for CRYP */
+ if ((CRYP_PERIPHERAL_ID0 ==
+ readl_relaxed(&device_data->base->periphId0))
+ && (CRYP_PERIPHERAL_ID1 ==
+ readl_relaxed(&device_data->base->periphId1))
+ && (CRYP_PERIPHERAL_ID3 ==
+ readl_relaxed(&device_data->base->periphId3))
+ && (CRYP_PCELL_ID0 ==
+ readl_relaxed(&device_data->base->pcellId0))
+ && (CRYP_PCELL_ID1 ==
+ readl_relaxed(&device_data->base->pcellId1))
+ && (CRYP_PCELL_ID2 ==
+ readl_relaxed(&device_data->base->pcellId2))
+ && (CRYP_PCELL_ID3 ==
+ readl_relaxed(&device_data->base->pcellId3))) {
+ return 0;
+ }
+
+ return -EPERM;
+}
+
+/**
+ * cryp_activity - This routine enables/disable the cryptography function.
+ * @device_data: Pointer to the device data struct for base address.
+ * @cryp_crypen: Enable/Disable functionality
+ */
+void cryp_activity(struct cryp_device_data *device_data,
+ enum cryp_crypen cryp_crypen)
+{
+ CRYP_PUT_BITS(&device_data->base->cr,
+ cryp_crypen,
+ CRYP_CR_CRYPEN_POS,
+ CRYP_CR_CRYPEN_MASK);
+}
+
+/**
+ * cryp_flush_inoutfifo - Resets both the input and the output FIFOs
+ * @device_data: Pointer to the device data struct for base address.
+ */
+void cryp_flush_inoutfifo(struct cryp_device_data *device_data)
+{
+ /*
+ * We always need to disble the hardware before trying to flush the
+ * FIFO. This is something that isn't written in the design
+ * specification, but we have been informed by the hardware designers
+ * that this must be done.
+ */
+ cryp_activity(device_data, CRYP_CRYPEN_DISABLE);
+ cryp_wait_until_done(device_data);
+
+ CRYP_SET_BITS(&device_data->base->cr, CRYP_CR_FFLUSH_MASK);
+ /*
+ * CRYP_SR_INFIFO_READY_MASK is the expected value on the status
+ * register when starting a new calculation, which means Input FIFO is
+ * not full and input FIFO is empty.
+ */
+ while (readl_relaxed(&device_data->base->sr) !=
+ CRYP_SR_INFIFO_READY_MASK)
+ cpu_relax();
+}
+
+/**
+ * cryp_set_configuration - This routine set the cr CRYP IP
+ * @device_data: Pointer to the device data struct for base address.
+ * @cryp_config: Pointer to the configuration parameter
+ * @control_register: The control register to be written later on.
+ */
+int cryp_set_configuration(struct cryp_device_data *device_data,
+ struct cryp_config *cryp_config,
+ u32 *control_register)
+{
+ u32 cr_for_kse;
+
+ if (NULL == device_data || NULL == cryp_config)
+ return -EINVAL;
+
+ *control_register |= (cryp_config->keysize << CRYP_CR_KEYSIZE_POS);
+
+ /* Prepare key for decryption in AES_ECB and AES_CBC mode. */
+ if ((CRYP_ALGORITHM_DECRYPT == cryp_config->algodir) &&
+ ((CRYP_ALGO_AES_ECB == cryp_config->algomode) ||
+ (CRYP_ALGO_AES_CBC == cryp_config->algomode))) {
+ cr_for_kse = *control_register;
+ /*
+ * This seems a bit odd, but it is indeed needed to set this to
+ * encrypt even though it is a decryption that we are doing. It
+ * also mentioned in the design spec that you need to do this.
+ * After the keyprepartion for decrypting is done you should set
+ * algodir back to decryption, which is done outside this if
+ * statement.
+ *
+ * According to design specification we should set mode ECB
+ * during key preparation even though we might be running CBC
+ * when enter this function.
+ *
+ * Writing to KSE_ENABLED will drop CRYPEN when key preparation
+ * is done. Therefore we need to set CRYPEN again outside this
+ * if statement when running decryption.
+ */
+ cr_for_kse |= ((CRYP_ALGORITHM_ENCRYPT << CRYP_CR_ALGODIR_POS) |
+ (CRYP_ALGO_AES_ECB << CRYP_CR_ALGOMODE_POS) |
+ (CRYP_CRYPEN_ENABLE << CRYP_CR_CRYPEN_POS) |
+ (KSE_ENABLED << CRYP_CR_KSE_POS));
+
+ writel_relaxed(cr_for_kse, &device_data->base->cr);
+ cryp_wait_until_done(device_data);
+ }
+
+ *control_register |=
+ ((cryp_config->algomode << CRYP_CR_ALGOMODE_POS) |
+ (cryp_config->algodir << CRYP_CR_ALGODIR_POS));
+
+ return 0;
+}
+
+/**
+ * cryp_configure_protection - set the protection bits in the CRYP logic.
+ * @device_data: Pointer to the device data struct for base address.
+ * @p_protect_config: Pointer to the protection mode and
+ * secure mode configuration
+ */
+int cryp_configure_protection(struct cryp_device_data *device_data,
+ struct cryp_protection_config *p_protect_config)
+{
+ if (NULL == p_protect_config)
+ return -EINVAL;
+
+ CRYP_WRITE_BIT(&device_data->base->cr,
+ (u32) p_protect_config->secure_access,
+ CRYP_CR_SECURE_MASK);
+ CRYP_PUT_BITS(&device_data->base->cr,
+ p_protect_config->privilege_access,
+ CRYP_CR_PRLG_POS,
+ CRYP_CR_PRLG_MASK);
+
+ return 0;
+}
+
+/**
+ * cryp_is_logic_busy - returns the busy status of the CRYP logic
+ * @device_data: Pointer to the device data struct for base address.
+ */
+int cryp_is_logic_busy(struct cryp_device_data *device_data)
+{
+ return CRYP_TEST_BITS(&device_data->base->sr,
+ CRYP_SR_BUSY_MASK);
+}
+
+/**
+ * cryp_configure_for_dma - configures the CRYP IP for DMA operation
+ * @device_data: Pointer to the device data struct for base address.
+ * @dma_req: Specifies the DMA request type value.
+ */
+void cryp_configure_for_dma(struct cryp_device_data *device_data,
+ enum cryp_dma_req_type dma_req)
+{
+ CRYP_SET_BITS(&device_data->base->dmacr,
+ (u32) dma_req);
+}
+
+/**
+ * cryp_configure_key_values - configures the key values for CRYP operations
+ * @device_data: Pointer to the device data struct for base address.
+ * @key_reg_index: Key value index register
+ * @key_value: The key value struct
+ */
+int cryp_configure_key_values(struct cryp_device_data *device_data,
+ enum cryp_key_reg_index key_reg_index,
+ struct cryp_key_value key_value)
+{
+ while (cryp_is_logic_busy(device_data))
+ cpu_relax();
+
+ switch (key_reg_index) {
+ case CRYP_KEY_REG_1:
+ writel_relaxed(key_value.key_value_left,
+ &device_data->base->key_1_l);
+ writel_relaxed(key_value.key_value_right,
+ &device_data->base->key_1_r);
+ break;
+ case CRYP_KEY_REG_2:
+ writel_relaxed(key_value.key_value_left,
+ &device_data->base->key_2_l);
+ writel_relaxed(key_value.key_value_right,
+ &device_data->base->key_2_r);
+ break;
+ case CRYP_KEY_REG_3:
+ writel_relaxed(key_value.key_value_left,
+ &device_data->base->key_3_l);
+ writel_relaxed(key_value.key_value_right,
+ &device_data->base->key_3_r);
+ break;
+ case CRYP_KEY_REG_4:
+ writel_relaxed(key_value.key_value_left,
+ &device_data->base->key_4_l);
+ writel_relaxed(key_value.key_value_right,
+ &device_data->base->key_4_r);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * cryp_configure_init_vector - configures the initialization vector register
+ * @device_data: Pointer to the device data struct for base address.
+ * @init_vector_index: Specifies the index of the init vector.
+ * @init_vector_value: Specifies the value for the init vector.
+ */
+int cryp_configure_init_vector(struct cryp_device_data *device_data,
+ enum cryp_init_vector_index
+ init_vector_index,
+ struct cryp_init_vector_value
+ init_vector_value)
+{
+ while (cryp_is_logic_busy(device_data))
+ cpu_relax();
+
+ switch (init_vector_index) {
+ case CRYP_INIT_VECTOR_INDEX_0:
+ writel_relaxed(init_vector_value.init_value_left,
+ &device_data->base->init_vect_0_l);
+ writel_relaxed(init_vector_value.init_value_right,
+ &device_data->base->init_vect_0_r);
+ break;
+ case CRYP_INIT_VECTOR_INDEX_1:
+ writel_relaxed(init_vector_value.init_value_left,
+ &device_data->base->init_vect_1_l);
+ writel_relaxed(init_vector_value.init_value_right,
+ &device_data->base->init_vect_1_r);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * cryp_save_device_context - Store hardware registers and
+ * other device context parameter
+ * @device_data: Pointer to the device data struct for base address.
+ * @ctx: Crypto device context
+ */
+void cryp_save_device_context(struct cryp_device_data *device_data,
+ struct cryp_device_context *ctx,
+ int cryp_mode)
+{
+ enum cryp_algo_mode algomode;
+ struct cryp_register *src_reg = device_data->base;
+ struct cryp_config *config =
+ (struct cryp_config *)device_data->current_ctx;
+
+ /*
+ * Always start by disable the hardware and wait for it to finish the
+ * ongoing calculations before trying to reprogram it.
+ */
+ cryp_activity(device_data, CRYP_CRYPEN_DISABLE);
+ cryp_wait_until_done(device_data);
+
+ if (cryp_mode == CRYP_MODE_DMA)
+ cryp_configure_for_dma(device_data, CRYP_DMA_DISABLE_BOTH);
+
+ if (CRYP_TEST_BITS(&src_reg->sr, CRYP_SR_IFEM_MASK) == 0)
+ ctx->din = readl_relaxed(&src_reg->din);
+
+ ctx->cr = readl_relaxed(&src_reg->cr) & CRYP_CR_CONTEXT_SAVE_MASK;
+
+ switch (config->keysize) {
+ case CRYP_KEY_SIZE_256:
+ ctx->key_4_l = readl_relaxed(&src_reg->key_4_l);
+ ctx->key_4_r = readl_relaxed(&src_reg->key_4_r);
+
+ case CRYP_KEY_SIZE_192:
+ ctx->key_3_l = readl_relaxed(&src_reg->key_3_l);
+ ctx->key_3_r = readl_relaxed(&src_reg->key_3_r);
+
+ case CRYP_KEY_SIZE_128:
+ ctx->key_2_l = readl_relaxed(&src_reg->key_2_l);
+ ctx->key_2_r = readl_relaxed(&src_reg->key_2_r);
+
+ default:
+ ctx->key_1_l = readl_relaxed(&src_reg->key_1_l);
+ ctx->key_1_r = readl_relaxed(&src_reg->key_1_r);
+ }
+
+ /* Save IV for CBC mode for both AES and DES. */
+ algomode = ((ctx->cr & CRYP_CR_ALGOMODE_MASK) >> CRYP_CR_ALGOMODE_POS);
+ if (algomode == CRYP_ALGO_TDES_CBC ||
+ algomode == CRYP_ALGO_DES_CBC ||
+ algomode == CRYP_ALGO_AES_CBC) {
+ ctx->init_vect_0_l = readl_relaxed(&src_reg->init_vect_0_l);
+ ctx->init_vect_0_r = readl_relaxed(&src_reg->init_vect_0_r);
+ ctx->init_vect_1_l = readl_relaxed(&src_reg->init_vect_1_l);
+ ctx->init_vect_1_r = readl_relaxed(&src_reg->init_vect_1_r);
+ }
+}
+
+/**
+ * cryp_restore_device_context - Restore hardware registers and
+ * other device context parameter
+ * @device_data: Pointer to the device data struct for base address.
+ * @ctx: Crypto device context
+ */
+void cryp_restore_device_context(struct cryp_device_data *device_data,
+ struct cryp_device_context *ctx)
+{
+ struct cryp_register *reg = device_data->base;
+ struct cryp_config *config =
+ (struct cryp_config *)device_data->current_ctx;
+
+ /*
+ * Fall through for all items in switch statement. DES is captured in
+ * the default.
+ */
+ switch (config->keysize) {
+ case CRYP_KEY_SIZE_256:
+ writel_relaxed(ctx->key_4_l, &reg->key_4_l);
+ writel_relaxed(ctx->key_4_r, &reg->key_4_r);
+
+ case CRYP_KEY_SIZE_192:
+ writel_relaxed(ctx->key_3_l, &reg->key_3_l);
+ writel_relaxed(ctx->key_3_r, &reg->key_3_r);
+
+ case CRYP_KEY_SIZE_128:
+ writel_relaxed(ctx->key_2_l, &reg->key_2_l);
+ writel_relaxed(ctx->key_2_r, &reg->key_2_r);
+
+ default:
+ writel_relaxed(ctx->key_1_l, &reg->key_1_l);
+ writel_relaxed(ctx->key_1_r, &reg->key_1_r);
+ }
+
+ /* Restore IV for CBC mode for AES and DES. */
+ if (config->algomode == CRYP_ALGO_TDES_CBC ||
+ config->algomode == CRYP_ALGO_DES_CBC ||
+ config->algomode == CRYP_ALGO_AES_CBC) {
+ writel_relaxed(ctx->init_vect_0_l, &reg->init_vect_0_l);
+ writel_relaxed(ctx->init_vect_0_r, &reg->init_vect_0_r);
+ writel_relaxed(ctx->init_vect_1_l, &reg->init_vect_1_l);
+ writel_relaxed(ctx->init_vect_1_r, &reg->init_vect_1_r);
+ }
+}
diff --git a/drivers/crypto/ux500/cryp/cryp.h b/drivers/crypto/ux500/cryp/cryp.h
new file mode 100644
index 000000000000..14cfd05b777a
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/cryp.h
@@ -0,0 +1,308 @@
+/**
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson.
+ * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson.
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson.
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef _CRYP_H_
+#define _CRYP_H_
+
+#include <linux/completion.h>
+#include <linux/dmaengine.h>
+#include <linux/klist.h>
+#include <linux/mutex.h>
+
+#define DEV_DBG_NAME "crypX crypX:"
+
+/* CRYP enable/disable */
+enum cryp_crypen {
+ CRYP_CRYPEN_DISABLE = 0,
+ CRYP_CRYPEN_ENABLE = 1
+};
+
+/* CRYP Start Computation enable/disable */
+enum cryp_start {
+ CRYP_START_DISABLE = 0,
+ CRYP_START_ENABLE = 1
+};
+
+/* CRYP Init Signal enable/disable */
+enum cryp_init {
+ CRYP_INIT_DISABLE = 0,
+ CRYP_INIT_ENABLE = 1
+};
+
+/* Cryp State enable/disable */
+enum cryp_state {
+ CRYP_STATE_DISABLE = 0,
+ CRYP_STATE_ENABLE = 1
+};
+
+/* Key preparation bit enable */
+enum cryp_key_prep {
+ KSE_DISABLED = 0,
+ KSE_ENABLED = 1
+};
+
+/* Key size for AES */
+#define CRYP_KEY_SIZE_128 (0)
+#define CRYP_KEY_SIZE_192 (1)
+#define CRYP_KEY_SIZE_256 (2)
+
+/* AES modes */
+enum cryp_algo_mode {
+ CRYP_ALGO_TDES_ECB,
+ CRYP_ALGO_TDES_CBC,
+ CRYP_ALGO_DES_ECB,
+ CRYP_ALGO_DES_CBC,
+ CRYP_ALGO_AES_ECB,
+ CRYP_ALGO_AES_CBC,
+ CRYP_ALGO_AES_CTR,
+ CRYP_ALGO_AES_XTS
+};
+
+/* Cryp Encryption or Decryption */
+enum cryp_algorithm_dir {
+ CRYP_ALGORITHM_ENCRYPT,
+ CRYP_ALGORITHM_DECRYPT
+};
+
+/* Hardware access method */
+enum cryp_mode {
+ CRYP_MODE_POLLING,
+ CRYP_MODE_INTERRUPT,
+ CRYP_MODE_DMA
+};
+
+/**
+ * struct cryp_config -
+ * @keysize: Key size for AES
+ * @algomode: AES modes
+ * @algodir: Cryp Encryption or Decryption
+ *
+ * CRYP configuration structure to be passed to set configuration
+ */
+struct cryp_config {
+ int keysize;
+ enum cryp_algo_mode algomode;
+ enum cryp_algorithm_dir algodir;
+};
+
+/**
+ * struct cryp_protection_config -
+ * @privilege_access: Privileged cryp state enable/disable
+ * @secure_access: Secure cryp state enable/disable
+ *
+ * Protection configuration structure for setting privilage access
+ */
+struct cryp_protection_config {
+ enum cryp_state privilege_access;
+ enum cryp_state secure_access;
+};
+
+/* Cryp status */
+enum cryp_status_id {
+ CRYP_STATUS_BUSY = 0x10,
+ CRYP_STATUS_OUTPUT_FIFO_FULL = 0x08,
+ CRYP_STATUS_OUTPUT_FIFO_NOT_EMPTY = 0x04,
+ CRYP_STATUS_INPUT_FIFO_NOT_FULL = 0x02,
+ CRYP_STATUS_INPUT_FIFO_EMPTY = 0x01
+};
+
+/* Cryp DMA interface */
+enum cryp_dma_req_type {
+ CRYP_DMA_DISABLE_BOTH,
+ CRYP_DMA_ENABLE_IN_DATA,
+ CRYP_DMA_ENABLE_OUT_DATA,
+ CRYP_DMA_ENABLE_BOTH_DIRECTIONS
+};
+
+enum cryp_dma_channel {
+ CRYP_DMA_RX = 0,
+ CRYP_DMA_TX
+};
+
+/* Key registers */
+enum cryp_key_reg_index {
+ CRYP_KEY_REG_1,
+ CRYP_KEY_REG_2,
+ CRYP_KEY_REG_3,
+ CRYP_KEY_REG_4
+};
+
+/* Key register left and right */
+struct cryp_key_value {
+ u32 key_value_left;
+ u32 key_value_right;
+};
+
+/* Cryp Initialization structure */
+enum cryp_init_vector_index {
+ CRYP_INIT_VECTOR_INDEX_0,
+ CRYP_INIT_VECTOR_INDEX_1
+};
+
+/* struct cryp_init_vector_value -
+ * @init_value_left
+ * @init_value_right
+ * */
+struct cryp_init_vector_value {
+ u32 init_value_left;
+ u32 init_value_right;
+};
+
+/**
+ * struct cryp_device_context - structure for a cryp context.
+ * @cr: control register
+ * @dmacr: DMA control register
+ * @imsc: Interrupt mask set/clear register
+ * @key_1_l: Key 1l register
+ * @key_1_r: Key 1r register
+ * @key_2_l: Key 2l register
+ * @key_2_r: Key 2r register
+ * @key_3_l: Key 3l register
+ * @key_3_r: Key 3r register
+ * @key_4_l: Key 4l register
+ * @key_4_r: Key 4r register
+ * @init_vect_0_l: Initialization vector 0l register
+ * @init_vect_0_r: Initialization vector 0r register
+ * @init_vect_1_l: Initialization vector 1l register
+ * @init_vect_1_r: Initialization vector 0r register
+ * @din: Data in register
+ * @dout: Data out register
+ *
+ * CRYP power management specifc structure.
+ */
+struct cryp_device_context {
+ u32 cr;
+ u32 dmacr;
+ u32 imsc;
+
+ u32 key_1_l;
+ u32 key_1_r;
+ u32 key_2_l;
+ u32 key_2_r;
+ u32 key_3_l;
+ u32 key_3_r;
+ u32 key_4_l;
+ u32 key_4_r;
+
+ u32 init_vect_0_l;
+ u32 init_vect_0_r;
+ u32 init_vect_1_l;
+ u32 init_vect_1_r;
+
+ u32 din;
+ u32 dout;
+};
+
+struct cryp_dma {
+ dma_cap_mask_t mask;
+ struct completion cryp_dma_complete;
+ struct dma_chan *chan_cryp2mem;
+ struct dma_chan *chan_mem2cryp;
+ struct stedma40_chan_cfg *cfg_cryp2mem;
+ struct stedma40_chan_cfg *cfg_mem2cryp;
+ int sg_src_len;
+ int sg_dst_len;
+ struct scatterlist *sg_src;
+ struct scatterlist *sg_dst;
+ int nents_src;
+ int nents_dst;
+};
+
+/**
+ * struct cryp_device_data - structure for a cryp device.
+ * @base: Pointer to the hardware base address.
+ * @dev: Pointer to the devices dev structure.
+ * @clk: Pointer to the device's clock control.
+ * @pwr_regulator: Pointer to the device's power control.
+ * @power_status: Current status of the power.
+ * @ctx_lock: Lock for current_ctx.
+ * @current_ctx: Pointer to the currently allocated context.
+ * @list_node: For inclusion into a klist.
+ * @dma: The dma structure holding channel configuration.
+ * @power_state: TRUE = power state on, FALSE = power state off.
+ * @power_state_spinlock: Spinlock for power_state.
+ * @restore_dev_ctx: TRUE = saved ctx, FALSE = no saved ctx.
+ */
+struct cryp_device_data {
+ struct cryp_register __iomem *base;
+ struct device *dev;
+ struct clk *clk;
+ struct regulator *pwr_regulator;
+ int power_status;
+ struct spinlock ctx_lock;
+ struct cryp_ctx *current_ctx;
+ struct klist_node list_node;
+ struct cryp_dma dma;
+ bool power_state;
+ struct spinlock power_state_spinlock;
+ bool restore_dev_ctx;
+};
+
+void cryp_wait_until_done(struct cryp_device_data *device_data);
+
+/* Initialization functions */
+
+int cryp_check(struct cryp_device_data *device_data);
+
+void cryp_activity(struct cryp_device_data *device_data,
+ enum cryp_crypen cryp_crypen);
+
+void cryp_flush_inoutfifo(struct cryp_device_data *device_data);
+
+int cryp_set_configuration(struct cryp_device_data *device_data,
+ struct cryp_config *cryp_config,
+ u32 *control_register);
+
+void cryp_configure_for_dma(struct cryp_device_data *device_data,
+ enum cryp_dma_req_type dma_req);
+
+int cryp_configure_key_values(struct cryp_device_data *device_data,
+ enum cryp_key_reg_index key_reg_index,
+ struct cryp_key_value key_value);
+
+int cryp_configure_init_vector(struct cryp_device_data *device_data,
+ enum cryp_init_vector_index
+ init_vector_index,
+ struct cryp_init_vector_value
+ init_vector_value);
+
+int cryp_configure_protection(struct cryp_device_data *device_data,
+ struct cryp_protection_config *p_protect_config);
+
+/* Power management funtions */
+void cryp_save_device_context(struct cryp_device_data *device_data,
+ struct cryp_device_context *ctx,
+ int cryp_mode);
+
+void cryp_restore_device_context(struct cryp_device_data *device_data,
+ struct cryp_device_context *ctx);
+
+/* Data transfer and status bits. */
+int cryp_is_logic_busy(struct cryp_device_data *device_data);
+
+int cryp_get_status(struct cryp_device_data *device_data);
+
+/**
+ * cryp_write_indata - This routine writes 32 bit data into the data input
+ * register of the cryptography IP.
+ * @device_data: Pointer to the device data struct for base address.
+ * @write_data: Data to write.
+ */
+int cryp_write_indata(struct cryp_device_data *device_data, u32 write_data);
+
+/**
+ * cryp_read_outdata - This routine reads the data from the data output
+ * register of the CRYP logic
+ * @device_data: Pointer to the device data struct for base address.
+ * @read_data: Read the data from the output FIFO.
+ */
+int cryp_read_outdata(struct cryp_device_data *device_data, u32 *read_data);
+
+#endif /* _CRYP_H_ */
diff --git a/drivers/crypto/ux500/cryp/cryp_core.c b/drivers/crypto/ux500/cryp/cryp_core.c
new file mode 100644
index 000000000000..7cac12793a4b
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/cryp_core.c
@@ -0,0 +1,1784 @@
+/**
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson.
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson.
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson.
+ * Author: Andreas Westin <andreas.westin@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/crypto.h>
+#include <linux/dmaengine.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irqreturn.h>
+#include <linux/klist.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/semaphore.h>
+
+#include <crypto/aes.h>
+#include <crypto/algapi.h>
+#include <crypto/ctr.h>
+#include <crypto/des.h>
+#include <crypto/scatterwalk.h>
+
+#include <plat/ste_dma40.h>
+
+#include <mach/crypto-ux500.h>
+#include <mach/hardware.h>
+
+#include "cryp_p.h"
+#include "cryp.h"
+
+#define CRYP_MAX_KEY_SIZE 32
+#define BYTES_PER_WORD 4
+
+static int cryp_mode;
+static atomic_t session_id;
+
+static struct stedma40_chan_cfg *mem_to_engine;
+static struct stedma40_chan_cfg *engine_to_mem;
+
+/**
+ * struct cryp_driver_data - data specific to the driver.
+ *
+ * @device_list: A list of registered devices to choose from.
+ * @device_allocation: A semaphore initialized with number of devices.
+ */
+struct cryp_driver_data {
+ struct klist device_list;
+ struct semaphore device_allocation;
+};
+
+/**
+ * struct cryp_ctx - Crypto context
+ * @config: Crypto mode.
+ * @key[CRYP_MAX_KEY_SIZE]: Key.
+ * @keylen: Length of key.
+ * @iv: Pointer to initialization vector.
+ * @indata: Pointer to indata.
+ * @outdata: Pointer to outdata.
+ * @datalen: Length of indata.
+ * @outlen: Length of outdata.
+ * @blocksize: Size of blocks.
+ * @updated: Updated flag.
+ * @dev_ctx: Device dependent context.
+ * @device: Pointer to the device.
+ */
+struct cryp_ctx {
+ struct cryp_config config;
+ u8 key[CRYP_MAX_KEY_SIZE];
+ u32 keylen;
+ u8 *iv;
+ const u8 *indata;
+ u8 *outdata;
+ u32 datalen;
+ u32 outlen;
+ u32 blocksize;
+ u8 updated;
+ struct cryp_device_context dev_ctx;
+ struct cryp_device_data *device;
+ u32 session_id;
+};
+
+static struct cryp_driver_data driver_data;
+
+/**
+ * uint8p_to_uint32_be - 4*uint8 to uint32 big endian
+ * @in: Data to convert.
+ */
+static inline u32 uint8p_to_uint32_be(u8 *in)
+{
+ u32 *data = (u32 *)in;
+
+ return cpu_to_be32p(data);
+}
+
+/**
+ * swap_bits_in_byte - mirror the bits in a byte
+ * @b: the byte to be mirrored
+ *
+ * The bits are swapped the following way:
+ * Byte b include bits 0-7, nibble 1 (n1) include bits 0-3 and
+ * nibble 2 (n2) bits 4-7.
+ *
+ * Nibble 1 (n1):
+ * (The "old" (moved) bit is replaced with a zero)
+ * 1. Move bit 6 and 7, 4 positions to the left.
+ * 2. Move bit 3 and 5, 2 positions to the left.
+ * 3. Move bit 1-4, 1 position to the left.
+ *
+ * Nibble 2 (n2):
+ * 1. Move bit 0 and 1, 4 positions to the right.
+ * 2. Move bit 2 and 4, 2 positions to the right.
+ * 3. Move bit 3-6, 1 position to the right.
+ *
+ * Combine the two nibbles to a complete and swapped byte.
+ */
+
+static inline u8 swap_bits_in_byte(u8 b)
+{
+#define R_SHIFT_4_MASK 0xc0 /* Bits 6 and 7, right shift 4 */
+#define R_SHIFT_2_MASK 0x28 /* (After right shift 4) Bits 3 and 5,
+ right shift 2 */
+#define R_SHIFT_1_MASK 0x1e /* (After right shift 2) Bits 1-4,
+ right shift 1 */
+#define L_SHIFT_4_MASK 0x03 /* Bits 0 and 1, left shift 4 */
+#define L_SHIFT_2_MASK 0x14 /* (After left shift 4) Bits 2 and 4,
+ left shift 2 */
+#define L_SHIFT_1_MASK 0x78 /* (After left shift 1) Bits 3-6,
+ left shift 1 */
+
+ u8 n1;
+ u8 n2;
+
+ /* Swap most significant nibble */
+ /* Right shift 4, bits 6 and 7 */
+ n1 = ((b & R_SHIFT_4_MASK) >> 4) | (b & ~(R_SHIFT_4_MASK >> 4));
+ /* Right shift 2, bits 3 and 5 */
+ n1 = ((n1 & R_SHIFT_2_MASK) >> 2) | (n1 & ~(R_SHIFT_2_MASK >> 2));
+ /* Right shift 1, bits 1-4 */
+ n1 = (n1 & R_SHIFT_1_MASK) >> 1;
+
+ /* Swap least significant nibble */
+ /* Left shift 4, bits 0 and 1 */
+ n2 = ((b & L_SHIFT_4_MASK) << 4) | (b & ~(L_SHIFT_4_MASK << 4));
+ /* Left shift 2, bits 2 and 4 */
+ n2 = ((n2 & L_SHIFT_2_MASK) << 2) | (n2 & ~(L_SHIFT_2_MASK << 2));
+ /* Left shift 1, bits 3-6 */
+ n2 = (n2 & L_SHIFT_1_MASK) << 1;
+
+ return n1 | n2;
+}
+
+static inline void swap_words_in_key_and_bits_in_byte(const u8 *in,
+ u8 *out, u32 len)
+{
+ unsigned int i = 0;
+ int j;
+ int index = 0;
+
+ j = len - BYTES_PER_WORD;
+ while (j >= 0) {
+ for (i = 0; i < BYTES_PER_WORD; i++) {
+ index = len - j - BYTES_PER_WORD + i;
+ out[j + i] =
+ swap_bits_in_byte(in[index]);
+ }
+ j -= BYTES_PER_WORD;
+ }
+}
+
+static void add_session_id(struct cryp_ctx *ctx)
+{
+ /*
+ * We never want 0 to be a valid value, since this is the default value
+ * for the software context.
+ */
+ if (unlikely(atomic_inc_and_test(&session_id)))
+ atomic_inc(&session_id);
+
+ ctx->session_id = atomic_read(&session_id);
+}
+
+static irqreturn_t cryp_interrupt_handler(int irq, void *param)
+{
+ struct cryp_ctx *ctx;
+ int i;
+ struct cryp_device_data *device_data;
+
+ if (param == NULL) {
+ BUG_ON(!param);
+ return IRQ_HANDLED;
+ }
+
+ /* The device is coming from the one found in hw_crypt_noxts. */
+ device_data = (struct cryp_device_data *)param;
+
+ ctx = device_data->current_ctx;
+
+ if (ctx == NULL) {
+ BUG_ON(!ctx);
+ return IRQ_HANDLED;
+ }
+
+ dev_dbg(ctx->device->dev, "[%s] (len: %d) %s, ", __func__, ctx->outlen,
+ cryp_pending_irq_src(device_data, CRYP_IRQ_SRC_OUTPUT_FIFO) ?
+ "out" : "in");
+
+ if (cryp_pending_irq_src(device_data,
+ CRYP_IRQ_SRC_OUTPUT_FIFO)) {
+ if (ctx->outlen / ctx->blocksize > 0) {
+ for (i = 0; i < ctx->blocksize / 4; i++) {
+ *(ctx->outdata) = readl_relaxed(
+ &device_data->base->dout);
+ ctx->outdata += 4;
+ ctx->outlen -= 4;
+ }
+
+ if (ctx->outlen == 0) {
+ cryp_disable_irq_src(device_data,
+ CRYP_IRQ_SRC_OUTPUT_FIFO);
+ }
+ }
+ } else if (cryp_pending_irq_src(device_data,
+ CRYP_IRQ_SRC_INPUT_FIFO)) {
+ if (ctx->datalen / ctx->blocksize > 0) {
+ for (i = 0 ; i < ctx->blocksize / 4; i++) {
+ writel_relaxed(ctx->indata,
+ &device_data->base->din);
+ ctx->indata += 4;
+ ctx->datalen -= 4;
+ }
+
+ if (ctx->datalen == 0)
+ cryp_disable_irq_src(device_data,
+ CRYP_IRQ_SRC_INPUT_FIFO);
+
+ if (ctx->config.algomode == CRYP_ALGO_AES_XTS) {
+ CRYP_PUT_BITS(&device_data->base->cr,
+ CRYP_START_ENABLE,
+ CRYP_CR_START_POS,
+ CRYP_CR_START_MASK);
+
+ cryp_wait_until_done(device_data);
+ }
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int mode_is_aes(enum cryp_algo_mode mode)
+{
+ return CRYP_ALGO_AES_ECB == mode ||
+ CRYP_ALGO_AES_CBC == mode ||
+ CRYP_ALGO_AES_CTR == mode ||
+ CRYP_ALGO_AES_XTS == mode;
+}
+
+static int cfg_iv(struct cryp_device_data *device_data, u32 left, u32 right,
+ enum cryp_init_vector_index index)
+{
+ struct cryp_init_vector_value vector_value;
+
+ dev_dbg(device_data->dev, "[%s]", __func__);
+
+ vector_value.init_value_left = left;
+ vector_value.init_value_right = right;
+
+ return cryp_configure_init_vector(device_data,
+ index,
+ vector_value);
+}
+
+static int cfg_ivs(struct cryp_device_data *device_data, struct cryp_ctx *ctx)
+{
+ int i;
+ int status = 0;
+ int num_of_regs = ctx->blocksize / 8;
+ u32 iv[AES_BLOCK_SIZE / 4];
+
+ dev_dbg(device_data->dev, "[%s]", __func__);
+
+ /*
+ * Since we loop on num_of_regs we need to have a check in case
+ * someone provides an incorrect blocksize which would force calling
+ * cfg_iv with i greater than 2 which is an error.
+ */
+ if (num_of_regs > 2) {
+ dev_err(device_data->dev, "[%s] Incorrect blocksize %d",
+ __func__, ctx->blocksize);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ctx->blocksize / 4; i++)
+ iv[i] = uint8p_to_uint32_be(ctx->iv + i*4);
+
+ for (i = 0; i < num_of_regs; i++) {
+ status = cfg_iv(device_data, iv[i*2], iv[i*2+1],
+ (enum cryp_init_vector_index) i);
+ if (status != 0)
+ return status;
+ }
+ return status;
+}
+
+static int set_key(struct cryp_device_data *device_data,
+ u32 left_key,
+ u32 right_key,
+ enum cryp_key_reg_index index)
+{
+ struct cryp_key_value key_value;
+ int cryp_error;
+
+ dev_dbg(device_data->dev, "[%s]", __func__);
+
+ key_value.key_value_left = left_key;
+ key_value.key_value_right = right_key;
+
+ cryp_error = cryp_configure_key_values(device_data,
+ index,
+ key_value);
+ if (cryp_error != 0)
+ dev_err(device_data->dev, "[%s]: "
+ "cryp_configure_key_values() failed!", __func__);
+
+ return cryp_error;
+}
+
+static int cfg_keys(struct cryp_ctx *ctx)
+{
+ int i;
+ int num_of_regs = ctx->keylen / 8;
+ u32 swapped_key[CRYP_MAX_KEY_SIZE / 4];
+ int cryp_error = 0;
+
+ dev_dbg(ctx->device->dev, "[%s]", __func__);
+
+ if (mode_is_aes(ctx->config.algomode)) {
+ swap_words_in_key_and_bits_in_byte((u8 *)ctx->key,
+ (u8 *)swapped_key,
+ ctx->keylen);
+ } else {
+ for (i = 0; i < ctx->keylen / 4; i++)
+ swapped_key[i] = uint8p_to_uint32_be(ctx->key + i*4);
+ }
+
+ for (i = 0; i < num_of_regs; i++) {
+ cryp_error = set_key(ctx->device,
+ *(((u32 *)swapped_key)+i*2),
+ *(((u32 *)swapped_key)+i*2+1),
+ (enum cryp_key_reg_index) i);
+
+ if (cryp_error != 0) {
+ dev_err(ctx->device->dev, "[%s]: set_key() failed!",
+ __func__);
+ return cryp_error;
+ }
+ }
+ return cryp_error;
+}
+
+static int cryp_setup_context(struct cryp_ctx *ctx,
+ struct cryp_device_data *device_data)
+{
+ u32 control_register = CRYP_CR_DEFAULT;
+
+ switch (cryp_mode) {
+ case CRYP_MODE_INTERRUPT:
+ writel_relaxed(CRYP_IMSC_DEFAULT, &device_data->base->imsc);
+ break;
+
+ case CRYP_MODE_DMA:
+ writel_relaxed(CRYP_DMACR_DEFAULT, &device_data->base->dmacr);
+ break;
+
+ default:
+ break;
+ }
+
+ if (ctx->updated == 0) {
+ cryp_flush_inoutfifo(device_data);
+ if (cfg_keys(ctx) != 0) {
+ dev_err(ctx->device->dev, "[%s]: cfg_keys failed!",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (ctx->iv &&
+ CRYP_ALGO_AES_ECB != ctx->config.algomode &&
+ CRYP_ALGO_DES_ECB != ctx->config.algomode &&
+ CRYP_ALGO_TDES_ECB != ctx->config.algomode) {
+ if (cfg_ivs(device_data, ctx) != 0)
+ return -EPERM;
+ }
+
+ cryp_set_configuration(device_data, &ctx->config,
+ &control_register);
+ add_session_id(ctx);
+ } else if (ctx->updated == 1 &&
+ ctx->session_id != atomic_read(&session_id)) {
+ cryp_flush_inoutfifo(device_data);
+ cryp_restore_device_context(device_data, &ctx->dev_ctx);
+
+ add_session_id(ctx);
+ control_register = ctx->dev_ctx.cr;
+ } else
+ control_register = ctx->dev_ctx.cr;
+
+ writel(control_register |
+ (CRYP_CRYPEN_ENABLE << CRYP_CR_CRYPEN_POS),
+ &device_data->base->cr);
+
+ return 0;
+}
+
+static int cryp_get_device_data(struct cryp_ctx *ctx,
+ struct cryp_device_data **device_data)
+{
+ int ret;
+ struct klist_iter device_iterator;
+ struct klist_node *device_node;
+ struct cryp_device_data *local_device_data = NULL;
+ pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+ /* Wait until a device is available */
+ ret = down_interruptible(&driver_data.device_allocation);
+ if (ret)
+ return ret; /* Interrupted */
+
+ /* Select a device */
+ klist_iter_init(&driver_data.device_list, &device_iterator);
+
+ device_node = klist_next(&device_iterator);
+ while (device_node) {
+ local_device_data = container_of(device_node,
+ struct cryp_device_data, list_node);
+ spin_lock(&local_device_data->ctx_lock);
+ /* current_ctx allocates a device, NULL = unallocated */
+ if (local_device_data->current_ctx) {
+ device_node = klist_next(&device_iterator);
+ } else {
+ local_device_data->current_ctx = ctx;
+ ctx->device = local_device_data;
+ spin_unlock(&local_device_data->ctx_lock);
+ break;
+ }
+ spin_unlock(&local_device_data->ctx_lock);
+ }
+ klist_iter_exit(&device_iterator);
+
+ if (!device_node) {
+ /**
+ * No free device found.
+ * Since we allocated a device with down_interruptible, this
+ * should not be able to happen.
+ * Number of available devices, which are contained in
+ * device_allocation, is therefore decremented by not doing
+ * an up(device_allocation).
+ */
+ return -EBUSY;
+ }
+
+ *device_data = local_device_data;
+
+ return 0;
+}
+
+static void cryp_dma_setup_channel(struct cryp_device_data *device_data,
+ struct device *dev)
+{
+ dma_cap_zero(device_data->dma.mask);
+ dma_cap_set(DMA_SLAVE, device_data->dma.mask);
+
+ device_data->dma.cfg_mem2cryp = mem_to_engine;
+ device_data->dma.chan_mem2cryp =
+ dma_request_channel(device_data->dma.mask,
+ stedma40_filter,
+ device_data->dma.cfg_mem2cryp);
+
+ device_data->dma.cfg_cryp2mem = engine_to_mem;
+ device_data->dma.chan_cryp2mem =
+ dma_request_channel(device_data->dma.mask,
+ stedma40_filter,
+ device_data->dma.cfg_cryp2mem);
+
+ init_completion(&device_data->dma.cryp_dma_complete);
+}
+
+static void cryp_dma_out_callback(void *data)
+{
+ struct cryp_ctx *ctx = (struct cryp_ctx *) data;
+ dev_dbg(ctx->device->dev, "[%s]: ", __func__);
+
+ complete(&ctx->device->dma.cryp_dma_complete);
+}
+
+static int cryp_set_dma_transfer(struct cryp_ctx *ctx,
+ struct scatterlist *sg,
+ int len,
+ enum dma_data_direction direction)
+{
+ struct dma_async_tx_descriptor *desc;
+ struct dma_chan *channel = NULL;
+ dma_cookie_t cookie;
+
+ dev_dbg(ctx->device->dev, "[%s]: ", __func__);
+
+ if (unlikely(!IS_ALIGNED((u32)sg, 4))) {
+ dev_err(ctx->device->dev, "[%s]: Data in sg list isn't "
+ "aligned! Addr: 0x%08x", __func__, (u32)sg);
+ return -EFAULT;
+ }
+
+ switch (direction) {
+ case DMA_TO_DEVICE:
+ channel = ctx->device->dma.chan_mem2cryp;
+ ctx->device->dma.sg_src = sg;
+ ctx->device->dma.sg_src_len = dma_map_sg(channel->device->dev,
+ ctx->device->dma.sg_src,
+ ctx->device->dma.nents_src,
+ direction);
+
+ if (!ctx->device->dma.sg_src_len) {
+ dev_dbg(ctx->device->dev,
+ "[%s]: Could not map the sg list (TO_DEVICE)",
+ __func__);
+ return -EFAULT;
+ }
+
+ dev_dbg(ctx->device->dev, "[%s]: Setting up DMA for buffer "
+ "(TO_DEVICE)", __func__);
+
+ desc = channel->device->device_prep_slave_sg(channel,
+ ctx->device->dma.sg_src,
+ ctx->device->dma.sg_src_len,
+ direction, DMA_CTRL_ACK, NULL);
+ break;
+
+ case DMA_FROM_DEVICE:
+ channel = ctx->device->dma.chan_cryp2mem;
+ ctx->device->dma.sg_dst = sg;
+ ctx->device->dma.sg_dst_len = dma_map_sg(channel->device->dev,
+ ctx->device->dma.sg_dst,
+ ctx->device->dma.nents_dst,
+ direction);
+
+ if (!ctx->device->dma.sg_dst_len) {
+ dev_dbg(ctx->device->dev,
+ "[%s]: Could not map the sg list (FROM_DEVICE)",
+ __func__);
+ return -EFAULT;
+ }
+
+ dev_dbg(ctx->device->dev, "[%s]: Setting up DMA for buffer "
+ "(FROM_DEVICE)", __func__);
+
+ desc = channel->device->device_prep_slave_sg(channel,
+ ctx->device->dma.sg_dst,
+ ctx->device->dma.sg_dst_len,
+ direction,
+ DMA_CTRL_ACK |
+ DMA_PREP_INTERRUPT, NULL);
+
+ desc->callback = cryp_dma_out_callback;
+ desc->callback_param = ctx;
+ break;
+
+ default:
+ dev_dbg(ctx->device->dev, "[%s]: Invalid DMA direction",
+ __func__);
+ return -EFAULT;
+ }
+
+ cookie = desc->tx_submit(desc);
+ dma_async_issue_pending(channel);
+
+ return 0;
+}
+
+static void cryp_dma_done(struct cryp_ctx *ctx)
+{
+ struct dma_chan *chan;
+
+ dev_dbg(ctx->device->dev, "[%s]: ", __func__);
+
+ chan = ctx->device->dma.chan_mem2cryp;
+ chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+ dma_unmap_sg(chan->device->dev, ctx->device->dma.sg_src,
+ ctx->device->dma.sg_src_len, DMA_TO_DEVICE);
+
+ chan = ctx->device->dma.chan_cryp2mem;
+ chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+ dma_unmap_sg(chan->device->dev, ctx->device->dma.sg_dst,
+ ctx->device->dma.sg_dst_len, DMA_FROM_DEVICE);
+}
+
+static int cryp_dma_write(struct cryp_ctx *ctx, struct scatterlist *sg,
+ int len)
+{
+ int error = cryp_set_dma_transfer(ctx, sg, len, DMA_TO_DEVICE);
+ dev_dbg(ctx->device->dev, "[%s]: ", __func__);
+
+ if (error) {
+ dev_dbg(ctx->device->dev, "[%s]: cryp_set_dma_transfer() "
+ "failed", __func__);
+ return error;
+ }
+
+ return len;
+}
+
+static int cryp_dma_read(struct cryp_ctx *ctx, struct scatterlist *sg, int len)
+{
+ int error = cryp_set_dma_transfer(ctx, sg, len, DMA_FROM_DEVICE);
+ if (error) {
+ dev_dbg(ctx->device->dev, "[%s]: cryp_set_dma_transfer() "
+ "failed", __func__);
+ return error;
+ }
+
+ return len;
+}
+
+static void cryp_polling_mode(struct cryp_ctx *ctx,
+ struct cryp_device_data *device_data)
+{
+ int len = ctx->blocksize / BYTES_PER_WORD;
+ int remaining_length = ctx->datalen;
+ u32 *indata = (u32 *)ctx->indata;
+ u32 *outdata = (u32 *)ctx->outdata;
+
+ while (remaining_length > 0) {
+ writesl(&device_data->base->din, indata, len);
+ indata += len;
+ remaining_length -= (len * BYTES_PER_WORD);
+ cryp_wait_until_done(device_data);
+
+ readsl(&device_data->base->dout, outdata, len);
+ outdata += len;
+ cryp_wait_until_done(device_data);
+ }
+}
+
+static int cryp_disable_power(struct device *dev,
+ struct cryp_device_data *device_data,
+ bool save_device_context)
+{
+ int ret = 0;
+
+ dev_dbg(dev, "[%s]", __func__);
+
+ spin_lock(&device_data->power_state_spinlock);
+ if (!device_data->power_state)
+ goto out;
+
+ spin_lock(&device_data->ctx_lock);
+ if (save_device_context && device_data->current_ctx) {
+ cryp_save_device_context(device_data,
+ &device_data->current_ctx->dev_ctx,
+ cryp_mode);
+ device_data->restore_dev_ctx = true;
+ }
+ spin_unlock(&device_data->ctx_lock);
+
+ clk_disable(device_data->clk);
+ ret = regulator_disable(device_data->pwr_regulator);
+ if (ret)
+ dev_err(dev, "[%s]: "
+ "regulator_disable() failed!",
+ __func__);
+
+ device_data->power_state = false;
+
+out:
+ spin_unlock(&device_data->power_state_spinlock);
+
+ return ret;
+}
+
+static int cryp_enable_power(
+ struct device *dev,
+ struct cryp_device_data *device_data,
+ bool restore_device_context)
+{
+ int ret = 0;
+
+ dev_dbg(dev, "[%s]", __func__);
+
+ spin_lock(&device_data->power_state_spinlock);
+ if (!device_data->power_state) {
+ ret = regulator_enable(device_data->pwr_regulator);
+ if (ret) {
+ dev_err(dev, "[%s]: regulator_enable() failed!",
+ __func__);
+ goto out;
+ }
+
+ ret = clk_enable(device_data->clk);
+ if (ret) {
+ dev_err(dev, "[%s]: clk_enable() failed!",
+ __func__);
+ regulator_disable(device_data->pwr_regulator);
+ goto out;
+ }
+ device_data->power_state = true;
+ }
+
+ if (device_data->restore_dev_ctx) {
+ spin_lock(&device_data->ctx_lock);
+ if (restore_device_context && device_data->current_ctx) {
+ device_data->restore_dev_ctx = false;
+ cryp_restore_device_context(device_data,
+ &device_data->current_ctx->dev_ctx);
+ }
+ spin_unlock(&device_data->ctx_lock);
+ }
+out:
+ spin_unlock(&device_data->power_state_spinlock);
+
+ return ret;
+}
+
+static int hw_crypt_noxts(struct cryp_ctx *ctx,
+ struct cryp_device_data *device_data)
+{
+ int ret = 0;
+
+ const u8 *indata = ctx->indata;
+ u8 *outdata = ctx->outdata;
+ u32 datalen = ctx->datalen;
+ u32 outlen = datalen;
+
+ pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+ ctx->outlen = ctx->datalen;
+
+ if (unlikely(!IS_ALIGNED((u32)indata, 4))) {
+ pr_debug(DEV_DBG_NAME " [%s]: Data isn't aligned! Addr: "
+ "0x%08x", __func__, (u32)indata);
+ return -EINVAL;
+ }
+
+ ret = cryp_setup_context(ctx, device_data);
+
+ if (ret)
+ goto out;
+
+ if (cryp_mode == CRYP_MODE_INTERRUPT) {
+ cryp_enable_irq_src(device_data, CRYP_IRQ_SRC_INPUT_FIFO |
+ CRYP_IRQ_SRC_OUTPUT_FIFO);
+
+ /*
+ * ctx->outlen is decremented in the cryp_interrupt_handler
+ * function. We had to add cpu_relax() (barrier) to make sure
+ * that gcc didn't optimze away this variable.
+ */
+ while (ctx->outlen > 0)
+ cpu_relax();
+ } else if (cryp_mode == CRYP_MODE_POLLING ||
+ cryp_mode == CRYP_MODE_DMA) {
+ /*
+ * The reason for having DMA in this if case is that if we are
+ * running cryp_mode = 2, then we separate DMA routines for
+ * handling cipher/plaintext > blocksize, except when
+ * running the normal CRYPTO_ALG_TYPE_CIPHER, then we still use
+ * the polling mode. Overhead of doing DMA setup eats up the
+ * benefits using it.
+ */
+ cryp_polling_mode(ctx, device_data);
+ } else {
+ dev_err(ctx->device->dev, "[%s]: Invalid operation mode!",
+ __func__);
+ ret = -EPERM;
+ goto out;
+ }
+
+ cryp_save_device_context(device_data, &ctx->dev_ctx, cryp_mode);
+ ctx->updated = 1;
+
+out:
+ ctx->indata = indata;
+ ctx->outdata = outdata;
+ ctx->datalen = datalen;
+ ctx->outlen = outlen;
+
+ return ret;
+}
+
+static int get_nents(struct scatterlist *sg, int nbytes)
+{
+ int nents = 0;
+
+ while (nbytes > 0) {
+ nbytes -= sg->length;
+ sg = scatterwalk_sg_next(sg);
+ nents++;
+ }
+
+ return nents;
+}
+
+static int ablk_dma_crypt(struct ablkcipher_request *areq)
+{
+ struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+ struct cryp_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+ struct cryp_device_data *device_data;
+
+ int bytes_written = 0;
+ int bytes_read = 0;
+ int ret;
+
+ pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+ ctx->datalen = areq->nbytes;
+ ctx->outlen = areq->nbytes;
+
+ ret = cryp_get_device_data(ctx, &device_data);
+ if (ret)
+ return ret;
+
+ ret = cryp_setup_context(ctx, device_data);
+ if (ret)
+ goto out;
+
+ /* We have the device now, so store the nents in the dma struct. */
+ ctx->device->dma.nents_src = get_nents(areq->src, ctx->datalen);
+ ctx->device->dma.nents_dst = get_nents(areq->dst, ctx->outlen);
+
+ /* Enable DMA in- and output. */
+ cryp_configure_for_dma(device_data, CRYP_DMA_ENABLE_BOTH_DIRECTIONS);
+
+ bytes_written = cryp_dma_write(ctx, areq->src, ctx->datalen);
+ bytes_read = cryp_dma_read(ctx, areq->dst, bytes_written);
+
+ wait_for_completion(&ctx->device->dma.cryp_dma_complete);
+ cryp_dma_done(ctx);
+
+ cryp_save_device_context(device_data, &ctx->dev_ctx, cryp_mode);
+ ctx->updated = 1;
+
+out:
+ spin_lock(&device_data->ctx_lock);
+ device_data->current_ctx = NULL;
+ ctx->device = NULL;
+ spin_unlock(&device_data->ctx_lock);
+
+ /*
+ * The down_interruptible part for this semaphore is called in
+ * cryp_get_device_data.
+ */
+ up(&driver_data.device_allocation);
+
+ if (unlikely(bytes_written != bytes_read))
+ return -EPERM;
+
+ return 0;
+}
+
+static int ablk_crypt(struct ablkcipher_request *areq)
+{
+ struct ablkcipher_walk walk;
+ struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+ struct cryp_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+ struct cryp_device_data *device_data;
+ unsigned long src_paddr;
+ unsigned long dst_paddr;
+ int ret;
+ int nbytes;
+
+ pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+ ret = cryp_get_device_data(ctx, &device_data);
+ if (ret)
+ goto out;
+
+ ablkcipher_walk_init(&walk, areq->dst, areq->src, areq->nbytes);
+ ret = ablkcipher_walk_phys(areq, &walk);
+
+ if (ret) {
+ pr_err(DEV_DBG_NAME "[%s]: ablkcipher_walk_phys() failed!",
+ __func__);
+ goto out;
+ }
+
+ while ((nbytes = walk.nbytes) > 0) {
+ ctx->iv = walk.iv;
+ src_paddr = (page_to_phys(walk.src.page) + walk.src.offset);
+ ctx->indata = phys_to_virt(src_paddr);
+
+ dst_paddr = (page_to_phys(walk.dst.page) + walk.dst.offset);
+ ctx->outdata = phys_to_virt(dst_paddr);
+
+ ctx->datalen = nbytes - (nbytes % ctx->blocksize);
+
+ ret = hw_crypt_noxts(ctx, device_data);
+ if (ret)
+ goto out;
+
+ nbytes -= ctx->datalen;
+ ret = ablkcipher_walk_done(areq, &walk, nbytes);
+ if (ret)
+ goto out;
+ }
+ ablkcipher_walk_complete(&walk);
+
+out:
+ /* Release the device */
+ spin_lock(&device_data->ctx_lock);
+ device_data->current_ctx = NULL;
+ ctx->device = NULL;
+ spin_unlock(&device_data->ctx_lock);
+
+ /*
+ * The down_interruptible part for this semaphore is called in
+ * cryp_get_device_data.
+ */
+ up(&driver_data.device_allocation);
+
+ return ret;
+}
+
+static int aes_ablkcipher_setkey(struct crypto_ablkcipher *cipher,
+ const u8 *key, unsigned int keylen)
+{
+ struct cryp_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+ u32 *flags = &cipher->base.crt_flags;
+
+ pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+ switch (keylen) {
+ case AES_KEYSIZE_128:
+ ctx->config.keysize = CRYP_KEY_SIZE_128;
+ break;
+
+ case AES_KEYSIZE_192:
+ ctx->config.keysize = CRYP_KEY_SIZE_192;
+ break;
+
+ case AES_KEYSIZE_256:
+ ctx->config.keysize = CRYP_KEY_SIZE_256;
+ break;
+
+ default:
+ pr_err(DEV_DBG_NAME "[%s]: Unknown keylen!", __func__);
+ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ return -EINVAL;
+ }
+
+ memcpy(ctx->key, key, keylen);
+ ctx->keylen = keylen;
+
+ ctx->updated = 0;
+
+ return 0;
+}
+
+static int des_ablkcipher_setkey(struct crypto_ablkcipher *cipher,
+ const u8 *key, unsigned int keylen)
+{
+ struct cryp_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+ u32 *flags = &cipher->base.crt_flags;
+ u32 tmp[DES_EXPKEY_WORDS];
+ int ret;
+
+ pr_debug(DEV_DBG_NAME " [%s]", __func__);
+ if (keylen != DES_KEY_SIZE) {
+ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ pr_debug(DEV_DBG_NAME " [%s]: CRYPTO_TFM_RES_BAD_KEY_LEN",
+ __func__);
+ return -EINVAL;
+ }
+
+ ret = des_ekey(tmp, key);
+ if (unlikely(ret == 0) && (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
+ *flags |= CRYPTO_TFM_RES_WEAK_KEY;
+ pr_debug(DEV_DBG_NAME " [%s]: CRYPTO_TFM_REQ_WEAK_KEY",
+ __func__);
+ return -EINVAL;
+ }
+
+ memcpy(ctx->key, key, keylen);
+ ctx->keylen = keylen;
+
+ ctx->updated = 0;
+ return 0;
+}
+
+static int des3_ablkcipher_setkey(struct crypto_ablkcipher *cipher,
+ const u8 *key, unsigned int keylen)
+{
+ struct cryp_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+ u32 *flags = &cipher->base.crt_flags;
+ const u32 *K = (const u32 *)key;
+ u32 tmp[DES3_EDE_EXPKEY_WORDS];
+ int i, ret;
+
+ pr_debug(DEV_DBG_NAME " [%s]", __func__);
+ if (keylen != DES3_EDE_KEY_SIZE) {
+ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ pr_debug(DEV_DBG_NAME " [%s]: CRYPTO_TFM_RES_BAD_KEY_LEN",
+ __func__);
+ return -EINVAL;
+ }
+
+ /* Checking key interdependency for weak key detection. */
+ if (unlikely(!((K[0] ^ K[2]) | (K[1] ^ K[3])) ||
+ !((K[2] ^ K[4]) | (K[3] ^ K[5]))) &&
+ (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
+ *flags |= CRYPTO_TFM_RES_WEAK_KEY;
+ pr_debug(DEV_DBG_NAME " [%s]: CRYPTO_TFM_REQ_WEAK_KEY",
+ __func__);
+ return -EINVAL;
+ }
+ for (i = 0; i < 3; i++) {
+ ret = des_ekey(tmp, key + i*DES_KEY_SIZE);
+ if (unlikely(ret == 0) && (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
+ *flags |= CRYPTO_TFM_RES_WEAK_KEY;
+ pr_debug(DEV_DBG_NAME " [%s]: "
+ "CRYPTO_TFM_REQ_WEAK_KEY", __func__);
+ return -EINVAL;
+ }
+ }
+
+ memcpy(ctx->key, key, keylen);
+ ctx->keylen = keylen;
+
+ ctx->updated = 0;
+ return 0;
+}
+
+static int cryp_blk_encrypt(struct ablkcipher_request *areq)
+{
+ struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+ struct cryp_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+
+ pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+ ctx->config.algodir = CRYP_ALGORITHM_ENCRYPT;
+
+ /*
+ * DMA does not work for DES due to a hw bug */
+ if (cryp_mode == CRYP_MODE_DMA && mode_is_aes(ctx->config.algomode))
+ return ablk_dma_crypt(areq);
+
+ /* For everything except DMA, we run the non DMA version. */
+ return ablk_crypt(areq);
+}
+
+static int cryp_blk_decrypt(struct ablkcipher_request *areq)
+{
+ struct crypto_ablkcipher *cipher = crypto_ablkcipher_reqtfm(areq);
+ struct cryp_ctx *ctx = crypto_ablkcipher_ctx(cipher);
+
+ pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+ ctx->config.algodir = CRYP_ALGORITHM_DECRYPT;
+
+ /* DMA does not work for DES due to a hw bug */
+ if (cryp_mode == CRYP_MODE_DMA && mode_is_aes(ctx->config.algomode))
+ return ablk_dma_crypt(areq);
+
+ /* For everything except DMA, we run the non DMA version. */
+ return ablk_crypt(areq);
+}
+
+struct cryp_algo_template {
+ enum cryp_algo_mode algomode;
+ struct crypto_alg crypto;
+};
+
+static int cryp_cra_init(struct crypto_tfm *tfm)
+{
+ struct cryp_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct crypto_alg *alg = tfm->__crt_alg;
+ struct cryp_algo_template *cryp_alg = container_of(alg,
+ struct cryp_algo_template,
+ crypto);
+
+ ctx->config.algomode = cryp_alg->algomode;
+ ctx->blocksize = crypto_tfm_alg_blocksize(tfm);
+
+ return 0;
+}
+
+static struct cryp_algo_template cryp_algs[] = {
+ {
+ .algomode = CRYP_ALGO_AES_ECB,
+ .crypto = {
+ .cra_name = "aes",
+ .cra_driver_name = "aes-ux500",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct cryp_ctx),
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = cryp_cra_init,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = aes_ablkcipher_setkey,
+ .encrypt = cryp_blk_encrypt,
+ .decrypt = cryp_blk_decrypt
+ }
+ }
+ }
+ },
+ {
+ .algomode = CRYP_ALGO_AES_ECB,
+ .crypto = {
+ .cra_name = "ecb(aes)",
+ .cra_driver_name = "ecb-aes-ux500",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct cryp_ctx),
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = cryp_cra_init,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = aes_ablkcipher_setkey,
+ .encrypt = cryp_blk_encrypt,
+ .decrypt = cryp_blk_decrypt,
+ }
+ }
+ }
+ },
+ {
+ .algomode = CRYP_ALGO_AES_CBC,
+ .crypto = {
+ .cra_name = "cbc(aes)",
+ .cra_driver_name = "cbc-aes-ux500",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct cryp_ctx),
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = cryp_cra_init,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = aes_ablkcipher_setkey,
+ .encrypt = cryp_blk_encrypt,
+ .decrypt = cryp_blk_decrypt,
+ .ivsize = AES_BLOCK_SIZE,
+ }
+ }
+ }
+ },
+ {
+ .algomode = CRYP_ALGO_AES_CTR,
+ .crypto = {
+ .cra_name = "ctr(aes)",
+ .cra_driver_name = "ctr-aes-ux500",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct cryp_ctx),
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = cryp_cra_init,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = aes_ablkcipher_setkey,
+ .encrypt = cryp_blk_encrypt,
+ .decrypt = cryp_blk_decrypt,
+ .ivsize = AES_BLOCK_SIZE,
+ }
+ }
+ }
+ },
+ {
+ .algomode = CRYP_ALGO_DES_ECB,
+ .crypto = {
+ .cra_name = "des",
+ .cra_driver_name = "des-ux500",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct cryp_ctx),
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = cryp_cra_init,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = DES_KEY_SIZE,
+ .max_keysize = DES_KEY_SIZE,
+ .setkey = des_ablkcipher_setkey,
+ .encrypt = cryp_blk_encrypt,
+ .decrypt = cryp_blk_decrypt
+ }
+ }
+ }
+
+ },
+ {
+ .algomode = CRYP_ALGO_TDES_ECB,
+ .crypto = {
+ .cra_name = "des3_ede",
+ .cra_driver_name = "des3_ede-ux500",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct cryp_ctx),
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = cryp_cra_init,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ .setkey = des_ablkcipher_setkey,
+ .encrypt = cryp_blk_encrypt,
+ .decrypt = cryp_blk_decrypt
+ }
+ }
+ }
+ },
+ {
+ .algomode = CRYP_ALGO_DES_ECB,
+ .crypto = {
+ .cra_name = "ecb(des)",
+ .cra_driver_name = "ecb-des-ux500",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct cryp_ctx),
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = cryp_cra_init,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = DES_KEY_SIZE,
+ .max_keysize = DES_KEY_SIZE,
+ .setkey = des_ablkcipher_setkey,
+ .encrypt = cryp_blk_encrypt,
+ .decrypt = cryp_blk_decrypt,
+ }
+ }
+ }
+ },
+ {
+ .algomode = CRYP_ALGO_TDES_ECB,
+ .crypto = {
+ .cra_name = "ecb(des3_ede)",
+ .cra_driver_name = "ecb-des3_ede-ux500",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct cryp_ctx),
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = cryp_cra_init,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ .setkey = des3_ablkcipher_setkey,
+ .encrypt = cryp_blk_encrypt,
+ .decrypt = cryp_blk_decrypt,
+ }
+ }
+ }
+ },
+ {
+ .algomode = CRYP_ALGO_DES_CBC,
+ .crypto = {
+ .cra_name = "cbc(des)",
+ .cra_driver_name = "cbc-des-ux500",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct cryp_ctx),
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = cryp_cra_init,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = DES_KEY_SIZE,
+ .max_keysize = DES_KEY_SIZE,
+ .setkey = des_ablkcipher_setkey,
+ .encrypt = cryp_blk_encrypt,
+ .decrypt = cryp_blk_decrypt,
+ }
+ }
+ }
+ },
+ {
+ .algomode = CRYP_ALGO_TDES_CBC,
+ .crypto = {
+ .cra_name = "cbc(des3_ede)",
+ .cra_driver_name = "cbc-des3_ede-ux500",
+ .cra_priority = 300,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct cryp_ctx),
+ .cra_alignmask = 3,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_init = cryp_cra_init,
+ .cra_module = THIS_MODULE,
+ .cra_u = {
+ .ablkcipher = {
+ .min_keysize = DES3_EDE_KEY_SIZE,
+ .max_keysize = DES3_EDE_KEY_SIZE,
+ .setkey = des3_ablkcipher_setkey,
+ .encrypt = cryp_blk_encrypt,
+ .decrypt = cryp_blk_decrypt,
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ }
+ }
+ }
+ }
+};
+
+/**
+ * cryp_algs_register_all -
+ */
+static int cryp_algs_register_all(void)
+{
+ int ret;
+ int i;
+ int count;
+
+ pr_debug("[%s]", __func__);
+
+ for (i = 0; i < ARRAY_SIZE(cryp_algs); i++) {
+ ret = crypto_register_alg(&cryp_algs[i].crypto);
+ if (ret) {
+ count = i;
+ pr_err("[%s] alg registration failed",
+ cryp_algs[i].crypto.cra_driver_name);
+ goto unreg;
+ }
+ }
+ return 0;
+unreg:
+ for (i = 0; i < count; i++)
+ crypto_unregister_alg(&cryp_algs[i].crypto);
+ return ret;
+}
+
+/**
+ * cryp_algs_unregister_all -
+ */
+static void cryp_algs_unregister_all(void)
+{
+ int i;
+
+ pr_debug(DEV_DBG_NAME " [%s]", __func__);
+
+ for (i = 0; i < ARRAY_SIZE(cryp_algs); i++)
+ crypto_unregister_alg(&cryp_algs[i].crypto);
+}
+
+static int ux500_cryp_probe(struct platform_device *pdev)
+{
+ int ret;
+ int cryp_error = 0;
+ struct resource *res = NULL;
+ struct resource *res_irq = NULL;
+ struct cryp_device_data *device_data;
+ struct cryp_protection_config prot = {
+ .privilege_access = CRYP_STATE_ENABLE
+ };
+ struct device *dev = &pdev->dev;
+
+ dev_dbg(dev, "[%s]", __func__);
+ device_data = kzalloc(sizeof(struct cryp_device_data), GFP_ATOMIC);
+ if (!device_data) {
+ dev_err(dev, "[%s]: kzalloc() failed!", __func__);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ device_data->dev = dev;
+ device_data->current_ctx = NULL;
+
+ /* Grab the DMA configuration from platform data. */
+ mem_to_engine = &((struct cryp_platform_data *)
+ dev->platform_data)->mem_to_engine;
+ engine_to_mem = &((struct cryp_platform_data *)
+ dev->platform_data)->engine_to_mem;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "[%s]: platform_get_resource() failed",
+ __func__);
+ ret = -ENODEV;
+ goto out_kfree;
+ }
+
+ res = request_mem_region(res->start, resource_size(res), pdev->name);
+ if (res == NULL) {
+ dev_err(dev, "[%s]: request_mem_region() failed",
+ __func__);
+ ret = -EBUSY;
+ goto out_kfree;
+ }
+
+ device_data->base = ioremap(res->start, resource_size(res));
+ if (!device_data->base) {
+ dev_err(dev, "[%s]: ioremap failed!", __func__);
+ ret = -ENOMEM;
+ goto out_free_mem;
+ }
+
+ spin_lock_init(&device_data->ctx_lock);
+ spin_lock_init(&device_data->power_state_spinlock);
+
+ /* Enable power for CRYP hardware block */
+ device_data->pwr_regulator = regulator_get(&pdev->dev, "v-ape");
+ if (IS_ERR(device_data->pwr_regulator)) {
+ dev_err(dev, "[%s]: could not get cryp regulator", __func__);
+ ret = PTR_ERR(device_data->pwr_regulator);
+ device_data->pwr_regulator = NULL;
+ goto out_unmap;
+ }
+
+ /* Enable the clk for CRYP hardware block */
+ device_data->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(device_data->clk)) {
+ dev_err(dev, "[%s]: clk_get() failed!", __func__);
+ ret = PTR_ERR(device_data->clk);
+ goto out_regulator;
+ }
+
+ /* Enable device power (and clock) */
+ ret = cryp_enable_power(device_data->dev, device_data, false);
+ if (ret) {
+ dev_err(dev, "[%s]: cryp_enable_power() failed!", __func__);
+ goto out_clk;
+ }
+
+ cryp_error = cryp_check(device_data);
+ if (cryp_error != 0) {
+ dev_err(dev, "[%s]: cryp_init() failed!", __func__);
+ ret = -EINVAL;
+ goto out_power;
+ }
+
+ cryp_error = cryp_configure_protection(device_data, &prot);
+ if (cryp_error != 0) {
+ dev_err(dev, "[%s]: cryp_configure_protection() failed!",
+ __func__);
+ ret = -EINVAL;
+ goto out_power;
+ }
+
+ res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res_irq) {
+ dev_err(dev, "[%s]: IORESOURCE_IRQ unavailable",
+ __func__);
+ goto out_power;
+ }
+
+ ret = request_irq(res_irq->start,
+ cryp_interrupt_handler,
+ 0,
+ "cryp1",
+ device_data);
+ if (ret) {
+ dev_err(dev, "[%s]: Unable to request IRQ", __func__);
+ goto out_power;
+ }
+
+ if (cryp_mode == CRYP_MODE_DMA)
+ cryp_dma_setup_channel(device_data, dev);
+
+ platform_set_drvdata(pdev, device_data);
+
+ /* Put the new device into the device list... */
+ klist_add_tail(&device_data->list_node, &driver_data.device_list);
+
+ /* ... and signal that a new device is available. */
+ up(&driver_data.device_allocation);
+
+ atomic_set(&session_id, 1);
+
+ ret = cryp_algs_register_all();
+ if (ret) {
+ dev_err(dev, "[%s]: cryp_algs_register_all() failed!",
+ __func__);
+ goto out_power;
+ }
+
+ return 0;
+
+out_power:
+ cryp_disable_power(device_data->dev, device_data, false);
+
+out_clk:
+ clk_put(device_data->clk);
+
+out_regulator:
+ regulator_put(device_data->pwr_regulator);
+
+out_unmap:
+ iounmap(device_data->base);
+
+out_free_mem:
+ release_mem_region(res->start, resource_size(res));
+
+out_kfree:
+ kfree(device_data);
+out:
+ return ret;
+}
+
+static int ux500_cryp_remove(struct platform_device *pdev)
+{
+ struct resource *res = NULL;
+ struct resource *res_irq = NULL;
+ struct cryp_device_data *device_data;
+
+ dev_dbg(&pdev->dev, "[%s]", __func__);
+ device_data = platform_get_drvdata(pdev);
+ if (!device_data) {
+ dev_err(&pdev->dev, "[%s]: platform_get_drvdata() failed!",
+ __func__);
+ return -ENOMEM;
+ }
+
+ /* Try to decrease the number of available devices. */
+ if (down_trylock(&driver_data.device_allocation))
+ return -EBUSY;
+
+ /* Check that the device is free */
+ spin_lock(&device_data->ctx_lock);
+ /* current_ctx allocates a device, NULL = unallocated */
+ if (device_data->current_ctx) {
+ /* The device is busy */
+ spin_unlock(&device_data->ctx_lock);
+ /* Return the device to the pool. */
+ up(&driver_data.device_allocation);
+ return -EBUSY;
+ }
+
+ spin_unlock(&device_data->ctx_lock);
+
+ /* Remove the device from the list */
+ if (klist_node_attached(&device_data->list_node))
+ klist_remove(&device_data->list_node);
+
+ /* If this was the last device, remove the services */
+ if (list_empty(&driver_data.device_list.k_list))
+ cryp_algs_unregister_all();
+
+ res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res_irq)
+ dev_err(&pdev->dev, "[%s]: IORESOURCE_IRQ, unavailable",
+ __func__);
+ else {
+ disable_irq(res_irq->start);
+ free_irq(res_irq->start, device_data);
+ }
+
+ if (cryp_disable_power(&pdev->dev, device_data, false))
+ dev_err(&pdev->dev, "[%s]: cryp_disable_power() failed",
+ __func__);
+
+ clk_put(device_data->clk);
+ regulator_put(device_data->pwr_regulator);
+
+ iounmap(device_data->base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ kfree(device_data);
+
+ return 0;
+}
+
+static void ux500_cryp_shutdown(struct platform_device *pdev)
+{
+ struct resource *res_irq = NULL;
+ struct cryp_device_data *device_data;
+
+ dev_dbg(&pdev->dev, "[%s]", __func__);
+
+ device_data = platform_get_drvdata(pdev);
+ if (!device_data) {
+ dev_err(&pdev->dev, "[%s]: platform_get_drvdata() failed!",
+ __func__);
+ return;
+ }
+
+ /* Check that the device is free */
+ spin_lock(&device_data->ctx_lock);
+ /* current_ctx allocates a device, NULL = unallocated */
+ if (!device_data->current_ctx) {
+ if (down_trylock(&driver_data.device_allocation))
+ dev_dbg(&pdev->dev, "[%s]: Cryp still in use!"
+ "Shutting down anyway...", __func__);
+ /**
+ * (Allocate the device)
+ * Need to set this to non-null (dummy) value,
+ * to avoid usage if context switching.
+ */
+ device_data->current_ctx++;
+ }
+ spin_unlock(&device_data->ctx_lock);
+
+ /* Remove the device from the list */
+ if (klist_node_attached(&device_data->list_node))
+ klist_remove(&device_data->list_node);
+
+ /* If this was the last device, remove the services */
+ if (list_empty(&driver_data.device_list.k_list))
+ cryp_algs_unregister_all();
+
+ res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res_irq)
+ dev_err(&pdev->dev, "[%s]: IORESOURCE_IRQ, unavailable",
+ __func__);
+ else {
+ disable_irq(res_irq->start);
+ free_irq(res_irq->start, device_data);
+ }
+
+ if (cryp_disable_power(&pdev->dev, device_data, false))
+ dev_err(&pdev->dev, "[%s]: cryp_disable_power() failed",
+ __func__);
+
+}
+
+static int ux500_cryp_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ int ret;
+ struct cryp_device_data *device_data;
+ struct resource *res_irq;
+ struct cryp_ctx *temp_ctx = NULL;
+
+ dev_dbg(&pdev->dev, "[%s]", __func__);
+
+ /* Handle state? */
+ device_data = platform_get_drvdata(pdev);
+ if (!device_data) {
+ dev_err(&pdev->dev, "[%s]: platform_get_drvdata() failed!",
+ __func__);
+ return -ENOMEM;
+ }
+
+ res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res_irq)
+ dev_err(&pdev->dev, "[%s]: IORESOURCE_IRQ, unavailable",
+ __func__);
+ else
+ disable_irq(res_irq->start);
+
+ spin_lock(&device_data->ctx_lock);
+ if (!device_data->current_ctx)
+ device_data->current_ctx++;
+ spin_unlock(&device_data->ctx_lock);
+
+ if (device_data->current_ctx == ++temp_ctx) {
+ if (down_interruptible(&driver_data.device_allocation))
+ dev_dbg(&pdev->dev, "[%s]: down_interruptible() "
+ "failed", __func__);
+ ret = cryp_disable_power(&pdev->dev, device_data, false);
+
+ } else
+ ret = cryp_disable_power(&pdev->dev, device_data, true);
+
+ if (ret)
+ dev_err(&pdev->dev, "[%s]: cryp_disable_power()", __func__);
+
+ return ret;
+}
+
+static int ux500_cryp_resume(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct cryp_device_data *device_data;
+ struct resource *res_irq;
+ struct cryp_ctx *temp_ctx = NULL;
+
+ dev_dbg(&pdev->dev, "[%s]", __func__);
+
+ device_data = platform_get_drvdata(pdev);
+ if (!device_data) {
+ dev_err(&pdev->dev, "[%s]: platform_get_drvdata() failed!",
+ __func__);
+ return -ENOMEM;
+ }
+
+ spin_lock(&device_data->ctx_lock);
+ if (device_data->current_ctx == ++temp_ctx)
+ device_data->current_ctx = NULL;
+ spin_unlock(&device_data->ctx_lock);
+
+
+ if (!device_data->current_ctx)
+ up(&driver_data.device_allocation);
+ else
+ ret = cryp_enable_power(&pdev->dev, device_data, true);
+
+ if (ret)
+ dev_err(&pdev->dev, "[%s]: cryp_enable_power() failed!",
+ __func__);
+ else {
+ res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res_irq)
+ enable_irq(res_irq->start);
+ }
+
+ return ret;
+}
+
+static struct platform_driver cryp_driver = {
+ .probe = ux500_cryp_probe,
+ .remove = ux500_cryp_remove,
+ .shutdown = ux500_cryp_shutdown,
+ .suspend = ux500_cryp_suspend,
+ .resume = ux500_cryp_resume,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "cryp1"
+ }
+};
+
+static int __init ux500_cryp_mod_init(void)
+{
+ pr_debug("[%s] is called!", __func__);
+ klist_init(&driver_data.device_list, NULL, NULL);
+ /* Initialize the semaphore to 0 devices (locked state) */
+ sema_init(&driver_data.device_allocation, 0);
+ return platform_driver_register(&cryp_driver);
+}
+
+static void __exit ux500_cryp_mod_fini(void)
+{
+ pr_debug("[%s] is called!", __func__);
+ platform_driver_unregister(&cryp_driver);
+ return;
+}
+
+module_init(ux500_cryp_mod_init);
+module_exit(ux500_cryp_mod_fini);
+
+module_param(cryp_mode, int, 0);
+
+MODULE_DESCRIPTION("Driver for ST-Ericsson UX500 CRYP crypto engine.");
+MODULE_ALIAS("aes-all");
+MODULE_ALIAS("des-all");
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/crypto/ux500/cryp/cryp_irq.c b/drivers/crypto/ux500/cryp/cryp_irq.c
new file mode 100644
index 000000000000..08d291cdbe6d
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/cryp_irq.c
@@ -0,0 +1,45 @@
+/**
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson.
+ * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson.
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson.
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitmap.h>
+#include <linux/device.h>
+
+#include "cryp.h"
+#include "cryp_p.h"
+#include "cryp_irq.h"
+#include "cryp_irqp.h"
+
+void cryp_enable_irq_src(struct cryp_device_data *device_data, u32 irq_src)
+{
+ u32 i;
+
+ dev_dbg(device_data->dev, "[%s]", __func__);
+
+ i = readl_relaxed(&device_data->base->imsc);
+ i = i | irq_src;
+ writel_relaxed(i, &device_data->base->imsc);
+}
+
+void cryp_disable_irq_src(struct cryp_device_data *device_data, u32 irq_src)
+{
+ u32 i;
+
+ dev_dbg(device_data->dev, "[%s]", __func__);
+
+ i = readl_relaxed(&device_data->base->imsc);
+ i = i & ~irq_src;
+ writel_relaxed(i, &device_data->base->imsc);
+}
+
+bool cryp_pending_irq_src(struct cryp_device_data *device_data, u32 irq_src)
+{
+ return (readl_relaxed(&device_data->base->mis) & irq_src) > 0;
+}
diff --git a/drivers/crypto/ux500/cryp/cryp_irq.h b/drivers/crypto/ux500/cryp/cryp_irq.h
new file mode 100644
index 000000000000..5a7837f1b8f9
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/cryp_irq.h
@@ -0,0 +1,31 @@
+/**
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson.
+ * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson.
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson.
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef _CRYP_IRQ_H_
+#define _CRYP_IRQ_H_
+
+#include "cryp.h"
+
+enum cryp_irq_src_id {
+ CRYP_IRQ_SRC_INPUT_FIFO = 0x1,
+ CRYP_IRQ_SRC_OUTPUT_FIFO = 0x2,
+ CRYP_IRQ_SRC_ALL = 0x3
+};
+
+/**
+ * M0 Funtions
+ */
+void cryp_enable_irq_src(struct cryp_device_data *device_data, u32 irq_src);
+
+void cryp_disable_irq_src(struct cryp_device_data *device_data, u32 irq_src);
+
+bool cryp_pending_irq_src(struct cryp_device_data *device_data, u32 irq_src);
+
+#endif /* _CRYP_IRQ_H_ */
diff --git a/drivers/crypto/ux500/cryp/cryp_irqp.h b/drivers/crypto/ux500/cryp/cryp_irqp.h
new file mode 100644
index 000000000000..8b339cc34bf8
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/cryp_irqp.h
@@ -0,0 +1,125 @@
+/**
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson.
+ * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson.
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson.
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __CRYP_IRQP_H_
+#define __CRYP_IRQP_H_
+
+#include "cryp_irq.h"
+
+/**
+ *
+ * CRYP Registers - Offset mapping
+ * +-----------------+
+ * 00h | CRYP_CR | Configuration register
+ * +-----------------+
+ * 04h | CRYP_SR | Status register
+ * +-----------------+
+ * 08h | CRYP_DIN | Data In register
+ * +-----------------+
+ * 0ch | CRYP_DOUT | Data out register
+ * +-----------------+
+ * 10h | CRYP_DMACR | DMA control register
+ * +-----------------+
+ * 14h | CRYP_IMSC | IMSC
+ * +-----------------+
+ * 18h | CRYP_RIS | Raw interrupt status
+ * +-----------------+
+ * 1ch | CRYP_MIS | Masked interrupt status.
+ * +-----------------+
+ * Key registers
+ * IVR registers
+ * Peripheral
+ * Cell IDs
+ *
+ * Refer data structure for other register map
+ */
+
+/**
+ * struct cryp_register
+ * @cr - Configuration register
+ * @status - Status register
+ * @din - Data input register
+ * @din_size - Data input size register
+ * @dout - Data output register
+ * @dout_size - Data output size register
+ * @dmacr - Dma control register
+ * @imsc - Interrupt mask set/clear register
+ * @ris - Raw interrupt status
+ * @mis - Masked interrupt statu register
+ * @key_1_l - Key register 1 L
+ * @key_1_r - Key register 1 R
+ * @key_2_l - Key register 2 L
+ * @key_2_r - Key register 2 R
+ * @key_3_l - Key register 3 L
+ * @key_3_r - Key register 3 R
+ * @key_4_l - Key register 4 L
+ * @key_4_r - Key register 4 R
+ * @init_vect_0_l - init vector 0 L
+ * @init_vect_0_r - init vector 0 R
+ * @init_vect_1_l - init vector 1 L
+ * @init_vect_1_r - init vector 1 R
+ * @cryp_unused1 - unused registers
+ * @itcr - Integration test control register
+ * @itip - Integration test input register
+ * @itop - Integration test output register
+ * @cryp_unused2 - unused registers
+ * @periphId0 - FE0 CRYP Peripheral Identication Register
+ * @periphId1 - FE4
+ * @periphId2 - FE8
+ * @periphId3 - FEC
+ * @pcellId0 - FF0 CRYP PCell Identication Register
+ * @pcellId1 - FF4
+ * @pcellId2 - FF8
+ * @pcellId3 - FFC
+ */
+struct cryp_register {
+ u32 cr; /* Configuration register */
+ u32 sr; /* Status register */
+ u32 din; /* Data input register */
+ u32 din_size; /* Data input size register */
+ u32 dout; /* Data output register */
+ u32 dout_size; /* Data output size register */
+ u32 dmacr; /* Dma control register */
+ u32 imsc; /* Interrupt mask set/clear register */
+ u32 ris; /* Raw interrupt status */
+ u32 mis; /* Masked interrupt statu register */
+
+ u32 key_1_l; /*Key register 1 L */
+ u32 key_1_r; /*Key register 1 R */
+ u32 key_2_l; /*Key register 2 L */
+ u32 key_2_r; /*Key register 2 R */
+ u32 key_3_l; /*Key register 3 L */
+ u32 key_3_r; /*Key register 3 R */
+ u32 key_4_l; /*Key register 4 L */
+ u32 key_4_r; /*Key register 4 R */
+
+ u32 init_vect_0_l; /*init vector 0 L */
+ u32 init_vect_0_r; /*init vector 0 R */
+ u32 init_vect_1_l; /*init vector 1 L */
+ u32 init_vect_1_r; /*init vector 1 R */
+
+ u32 cryp_unused1[(0x80 - 0x58) / sizeof(u32)]; /* unused registers */
+ u32 itcr; /*Integration test control register */
+ u32 itip; /*Integration test input register */
+ u32 itop; /*Integration test output register */
+ u32 cryp_unused2[(0xFE0 - 0x8C) / sizeof(u32)]; /* unused registers */
+
+ u32 periphId0; /* FE0 CRYP Peripheral Identication Register */
+ u32 periphId1; /* FE4 */
+ u32 periphId2; /* FE8 */
+ u32 periphId3; /* FEC */
+
+ u32 pcellId0; /* FF0 CRYP PCell Identication Register */
+ u32 pcellId1; /* FF4 */
+ u32 pcellId2; /* FF8 */
+ u32 pcellId3; /* FFC */
+};
+
+#endif
diff --git a/drivers/crypto/ux500/cryp/cryp_p.h b/drivers/crypto/ux500/cryp/cryp_p.h
new file mode 100644
index 000000000000..6dcffe15c2bc
--- /dev/null
+++ b/drivers/crypto/ux500/cryp/cryp_p.h
@@ -0,0 +1,123 @@
+/**
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson.
+ * Author: Jonas Linde <jonas.linde@stericsson.com> for ST-Ericsson.
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson.
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef _CRYP_P_H_
+#define _CRYP_P_H_
+
+#include <linux/io.h>
+#include <linux/bitops.h>
+
+#include "cryp.h"
+#include "cryp_irqp.h"
+
+/**
+ * Generic Macros
+ */
+#define CRYP_SET_BITS(reg_name, mask) \
+ writel_relaxed((readl_relaxed(reg_name) | mask), reg_name)
+
+#define CRYP_WRITE_BIT(reg_name, val, mask) \
+ writel_relaxed(((readl_relaxed(reg_name) & ~(mask)) |\
+ ((val) & (mask))), reg_name)
+
+#define CRYP_TEST_BITS(reg_name, val) \
+ (readl_relaxed(reg_name) & (val))
+
+#define CRYP_PUT_BITS(reg, val, shift, mask) \
+ writel_relaxed(((readl_relaxed(reg) & ~(mask)) | \
+ (((u32)val << shift) & (mask))), reg)
+
+/**
+ * CRYP specific Macros
+ */
+#define CRYP_PERIPHERAL_ID0 0xE3
+#define CRYP_PERIPHERAL_ID1 0x05
+
+#define CRYP_PERIPHERAL_ID2_DB8500 0x28
+#define CRYP_PERIPHERAL_ID3 0x00
+
+#define CRYP_PCELL_ID0 0x0D
+#define CRYP_PCELL_ID1 0xF0
+#define CRYP_PCELL_ID2 0x05
+#define CRYP_PCELL_ID3 0xB1
+
+/**
+ * CRYP register default values
+ */
+#define MAX_DEVICE_SUPPORT 2
+
+/* Priv set, keyrden set and datatype 8bits swapped set as default. */
+#define CRYP_CR_DEFAULT 0x0482
+#define CRYP_DMACR_DEFAULT 0x0
+#define CRYP_IMSC_DEFAULT 0x0
+#define CRYP_DIN_DEFAULT 0x0
+#define CRYP_DOUT_DEFAULT 0x0
+#define CRYP_KEY_DEFAULT 0x0
+#define CRYP_INIT_VECT_DEFAULT 0x0
+
+/**
+ * CRYP Control register specific mask
+ */
+#define CRYP_CR_SECURE_MASK BIT(0)
+#define CRYP_CR_PRLG_MASK BIT(1)
+#define CRYP_CR_ALGODIR_MASK BIT(2)
+#define CRYP_CR_ALGOMODE_MASK (BIT(5) | BIT(4) | BIT(3))
+#define CRYP_CR_DATATYPE_MASK (BIT(7) | BIT(6))
+#define CRYP_CR_KEYSIZE_MASK (BIT(9) | BIT(8))
+#define CRYP_CR_KEYRDEN_MASK BIT(10)
+#define CRYP_CR_KSE_MASK BIT(11)
+#define CRYP_CR_START_MASK BIT(12)
+#define CRYP_CR_INIT_MASK BIT(13)
+#define CRYP_CR_FFLUSH_MASK BIT(14)
+#define CRYP_CR_CRYPEN_MASK BIT(15)
+#define CRYP_CR_CONTEXT_SAVE_MASK (CRYP_CR_SECURE_MASK |\
+ CRYP_CR_PRLG_MASK |\
+ CRYP_CR_ALGODIR_MASK |\
+ CRYP_CR_ALGOMODE_MASK |\
+ CRYP_CR_DATATYPE_MASK |\
+ CRYP_CR_KEYSIZE_MASK |\
+ CRYP_CR_KEYRDEN_MASK |\
+ CRYP_CR_DATATYPE_MASK)
+
+
+#define CRYP_SR_INFIFO_READY_MASK (BIT(0) | BIT(1))
+#define CRYP_SR_IFEM_MASK BIT(0)
+#define CRYP_SR_BUSY_MASK BIT(4)
+
+/**
+ * Bit position used while setting bits in register
+ */
+#define CRYP_CR_PRLG_POS 1
+#define CRYP_CR_ALGODIR_POS 2
+#define CRYP_CR_ALGOMODE_POS 3
+#define CRYP_CR_DATATYPE_POS 6
+#define CRYP_CR_KEYSIZE_POS 8
+#define CRYP_CR_KEYRDEN_POS 10
+#define CRYP_CR_KSE_POS 11
+#define CRYP_CR_START_POS 12
+#define CRYP_CR_INIT_POS 13
+#define CRYP_CR_CRYPEN_POS 15
+
+#define CRYP_SR_BUSY_POS 4
+
+/**
+ * CRYP PCRs------PC_NAND control register
+ * BIT_MASK
+ */
+#define CRYP_DMA_REQ_MASK (BIT(1) | BIT(0))
+#define CRYP_DMA_REQ_MASK_POS 0
+
+
+struct cryp_system_context {
+ /* CRYP Register structure */
+ struct cryp_register *p_cryp_reg[MAX_DEVICE_SUPPORT];
+};
+
+#endif
diff --git a/drivers/crypto/ux500/hash/Makefile b/drivers/crypto/ux500/hash/Makefile
new file mode 100644
index 000000000000..b2f90d9bac72
--- /dev/null
+++ b/drivers/crypto/ux500/hash/Makefile
@@ -0,0 +1,11 @@
+#
+# Copyright (C) ST-Ericsson SA 2010
+# Author: Shujuan Chen (shujuan.chen@stericsson.com)
+# License terms: GNU General Public License (GPL) version 2
+#
+ifdef CONFIG_CRYPTO_DEV_UX500_DEBUG
+CFLAGS_hash_core.o := -DDEBUG -O0
+endif
+
+obj-$(CONFIG_CRYPTO_DEV_UX500_HASH) += ux500_hash.o
+ux500_hash-objs := hash_core.o
diff --git a/drivers/crypto/ux500/hash/hash_alg.h b/drivers/crypto/ux500/hash/hash_alg.h
new file mode 100644
index 000000000000..cd9351cb24df
--- /dev/null
+++ b/drivers/crypto/ux500/hash/hash_alg.h
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen (shujuan.chen@stericsson.com)
+ * Author: Joakim Bech (joakim.xx.bech@stericsson.com)
+ * Author: Berne Hebark (berne.hebark@stericsson.com))
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#ifndef _HASH_ALG_H
+#define _HASH_ALG_H
+
+#include <linux/bitops.h>
+
+#define HASH_BLOCK_SIZE 64
+#define HASH_DMA_ALIGN_SIZE 4
+#define HASH_DMA_PERFORMANCE_MIN_SIZE 1024
+#define HASH_BYTES_PER_WORD 4
+
+/* Maximum value of the length's high word */
+#define HASH_HIGH_WORD_MAX_VAL 0xFFFFFFFFUL
+
+/* Power on Reset values HASH registers */
+#define HASH_RESET_CR_VALUE 0x0
+#define HASH_RESET_STR_VALUE 0x0
+
+/* Number of context swap registers */
+#define HASH_CSR_COUNT 52
+
+#define HASH_RESET_CSRX_REG_VALUE 0x0
+#define HASH_RESET_CSFULL_REG_VALUE 0x0
+#define HASH_RESET_CSDATAIN_REG_VALUE 0x0
+
+#define HASH_RESET_INDEX_VAL 0x0
+#define HASH_RESET_BIT_INDEX_VAL 0x0
+#define HASH_RESET_BUFFER_VAL 0x0
+#define HASH_RESET_LEN_HIGH_VAL 0x0
+#define HASH_RESET_LEN_LOW_VAL 0x0
+
+/* Control register bitfields */
+#define HASH_CR_RESUME_MASK 0x11FCF
+
+#define HASH_CR_SWITCHON_POS 31
+#define HASH_CR_SWITCHON_MASK BIT(31)
+
+#define HASH_CR_EMPTYMSG_POS 20
+#define HASH_CR_EMPTYMSG_MASK BIT(20)
+
+#define HASH_CR_DINF_POS 12
+#define HASH_CR_DINF_MASK BIT(12)
+
+#define HASH_CR_NBW_POS 8
+#define HASH_CR_NBW_MASK 0x00000F00UL
+
+#define HASH_CR_LKEY_POS 16
+#define HASH_CR_LKEY_MASK BIT(16)
+
+#define HASH_CR_ALGO_POS 7
+#define HASH_CR_ALGO_MASK BIT(7)
+
+#define HASH_CR_MODE_POS 6
+#define HASH_CR_MODE_MASK BIT(6)
+
+#define HASH_CR_DATAFORM_POS 4
+#define HASH_CR_DATAFORM_MASK (BIT(4) | BIT(5))
+
+#define HASH_CR_DMAE_POS 3
+#define HASH_CR_DMAE_MASK BIT(3)
+
+#define HASH_CR_INIT_POS 2
+#define HASH_CR_INIT_MASK BIT(2)
+
+#define HASH_CR_PRIVN_POS 1
+#define HASH_CR_PRIVN_MASK BIT(1)
+
+#define HASH_CR_SECN_POS 0
+#define HASH_CR_SECN_MASK BIT(0)
+
+/* Start register bitfields */
+#define HASH_STR_DCAL_POS 8
+#define HASH_STR_DCAL_MASK BIT(8)
+#define HASH_STR_DEFAULT 0x0
+
+#define HASH_STR_NBLW_POS 0
+#define HASH_STR_NBLW_MASK 0x0000001FUL
+
+#define HASH_NBLW_MAX_VAL 0x1F
+
+/* PrimeCell IDs */
+#define HASH_P_ID0 0xE0
+#define HASH_P_ID1 0x05
+#define HASH_P_ID2 0x38
+#define HASH_P_ID3 0x00
+#define HASH_CELL_ID0 0x0D
+#define HASH_CELL_ID1 0xF0
+#define HASH_CELL_ID2 0x05
+#define HASH_CELL_ID3 0xB1
+
+#define HASH_SET_BITS(reg_name, mask) \
+ writel_relaxed((readl_relaxed(reg_name) | mask), reg_name)
+
+#define HASH_CLEAR_BITS(reg_name, mask) \
+ writel_relaxed((readl_relaxed(reg_name) & ~mask), reg_name)
+
+#define HASH_PUT_BITS(reg, val, shift, mask) \
+ writel_relaxed(((readl(reg) & ~(mask)) | \
+ (((u32)val << shift) & (mask))), reg)
+
+#define HASH_SET_DIN(val, len) writesl(&device_data->base->din, (val), (len))
+
+#define HASH_INITIALIZE \
+ HASH_PUT_BITS( \
+ &device_data->base->cr, \
+ 0x01, HASH_CR_INIT_POS, \
+ HASH_CR_INIT_MASK)
+
+#define HASH_SET_DATA_FORMAT(data_format) \
+ HASH_PUT_BITS( \
+ &device_data->base->cr, \
+ (u32) (data_format), HASH_CR_DATAFORM_POS, \
+ HASH_CR_DATAFORM_MASK)
+#define HASH_SET_NBLW(val) \
+ HASH_PUT_BITS( \
+ &device_data->base->str, \
+ (u32) (val), HASH_STR_NBLW_POS, \
+ HASH_STR_NBLW_MASK)
+#define HASH_SET_DCAL \
+ HASH_PUT_BITS( \
+ &device_data->base->str, \
+ 0x01, HASH_STR_DCAL_POS, \
+ HASH_STR_DCAL_MASK)
+
+/* Hardware access method */
+enum hash_mode {
+ HASH_MODE_CPU,
+ HASH_MODE_DMA
+};
+
+/**
+ * struct uint64 - Structure to handle 64 bits integers.
+ * @high_word: Most significant bits.
+ * @low_word: Least significant bits.
+ *
+ * Used to handle 64 bits integers.
+ */
+struct uint64 {
+ u32 high_word;
+ u32 low_word;
+};
+
+/**
+ * struct hash_register - Contains all registers in ux500 hash hardware.
+ * @cr: HASH control register (0x000).
+ * @din: HASH data input register (0x004).
+ * @str: HASH start register (0x008).
+ * @hx: HASH digest register 0..7 (0x00c-0x01C).
+ * @padding0: Reserved (0x02C).
+ * @itcr: Integration test control register (0x080).
+ * @itip: Integration test input register (0x084).
+ * @itop: Integration test output register (0x088).
+ * @padding1: Reserved (0x08C).
+ * @csfull: HASH context full register (0x0F8).
+ * @csdatain: HASH context swap data input register (0x0FC).
+ * @csrx: HASH context swap register 0..51 (0x100-0x1CC).
+ * @padding2: Reserved (0x1D0).
+ * @periphid0: HASH peripheral identification register 0 (0xFE0).
+ * @periphid1: HASH peripheral identification register 1 (0xFE4).
+ * @periphid2: HASH peripheral identification register 2 (0xFE8).
+ * @periphid3: HASH peripheral identification register 3 (0xFEC).
+ * @cellid0: HASH PCell identification register 0 (0xFF0).
+ * @cellid1: HASH PCell identification register 1 (0xFF4).
+ * @cellid2: HASH PCell identification register 2 (0xFF8).
+ * @cellid3: HASH PCell identification register 3 (0xFFC).
+ *
+ * The device communicates to the HASH via 32-bit-wide control registers
+ * accessible via the 32-bit width AMBA rev. 2.0 AHB Bus. Below is a structure
+ * with the registers used.
+ */
+struct hash_register {
+ u32 cr;
+ u32 din;
+ u32 str;
+ u32 hx[8];
+
+ u32 padding0[(0x080 - 0x02C) / sizeof(u32)];
+
+ u32 itcr;
+ u32 itip;
+ u32 itop;
+
+ u32 padding1[(0x0F8 - 0x08C) / sizeof(u32)];
+
+ u32 csfull;
+ u32 csdatain;
+ u32 csrx[HASH_CSR_COUNT];
+
+ u32 padding2[(0xFE0 - 0x1D0) / sizeof(u32)];
+
+ u32 periphid0;
+ u32 periphid1;
+ u32 periphid2;
+ u32 periphid3;
+
+ u32 cellid0;
+ u32 cellid1;
+ u32 cellid2;
+ u32 cellid3;
+};
+
+/**
+ * struct hash_state - Hash context state.
+ * @temp_cr: Temporary HASH Control Register.
+ * @str_reg: HASH Start Register.
+ * @din_reg: HASH Data Input Register.
+ * @csr[52]: HASH Context Swap Registers 0-39.
+ * @csfull: HASH Context Swap Registers 40 ie Status flags.
+ * @csdatain: HASH Context Swap Registers 41 ie Input data.
+ * @buffer: Working buffer for messages going to the hardware.
+ * @length: Length of the part of message hashed so far (floor(N/64) * 64).
+ * @index: Valid number of bytes in buffer (N % 64).
+ * @bit_index: Valid number of bits in buffer (N % 8).
+ *
+ * This structure is used between context switches, i.e. when ongoing jobs are
+ * interupted with new jobs. When this happens we need to store intermediate
+ * results in software.
+ *
+ * WARNING: "index" is the member of the structure, to be sure that "buffer"
+ * is aligned on a 4-bytes boundary. This is highly implementation dependent
+ * and MUST be checked whenever this code is ported on new platforms.
+ */
+struct hash_state {
+ u32 temp_cr;
+ u32 str_reg;
+ u32 din_reg;
+ u32 csr[52];
+ u32 csfull;
+ u32 csdatain;
+ u32 buffer[HASH_BLOCK_SIZE / sizeof(u32)];
+ struct uint64 length;
+ u8 index;
+ u8 bit_index;
+};
+
+/**
+ * enum hash_device_id - HASH device ID.
+ * @HASH_DEVICE_ID_0: Hash hardware with ID 0
+ * @HASH_DEVICE_ID_1: Hash hardware with ID 1
+ */
+enum hash_device_id {
+ HASH_DEVICE_ID_0 = 0,
+ HASH_DEVICE_ID_1 = 1
+};
+
+/**
+ * enum hash_data_format - HASH data format.
+ * @HASH_DATA_32_BITS: 32 bits data format
+ * @HASH_DATA_16_BITS: 16 bits data format
+ * @HASH_DATA_8_BITS: 8 bits data format.
+ * @HASH_DATA_1_BITS: 1 bit data format.
+ */
+enum hash_data_format {
+ HASH_DATA_32_BITS = 0x0,
+ HASH_DATA_16_BITS = 0x1,
+ HASH_DATA_8_BITS = 0x2,
+ HASH_DATA_1_BIT = 0x3
+};
+
+/**
+ * enum hash_algo - Enumeration for selecting between SHA1 or SHA2 algorithm.
+ * @HASH_ALGO_SHA1: Indicates that SHA1 is used.
+ * @HASH_ALGO_SHA2: Indicates that SHA2 (SHA256) is used.
+ */
+enum hash_algo {
+ HASH_ALGO_SHA1 = 0x0,
+ HASH_ALGO_SHA256 = 0x1
+};
+
+/**
+ * enum hash_op - Enumeration for selecting between HASH or HMAC mode.
+ * @HASH_OPER_MODE_HASH: Indicates usage of normal HASH mode.
+ * @HASH_OPER_MODE_HMAC: Indicates usage of HMAC.
+ */
+enum hash_op {
+ HASH_OPER_MODE_HASH = 0x0,
+ HASH_OPER_MODE_HMAC = 0x1
+};
+
+/**
+ * struct hash_config - Configuration data for the hardware.
+ * @data_format: Format of data entered into the hash data in register.
+ * @algorithm: Algorithm selection bit.
+ * @oper_mode: Operating mode selection bit.
+ */
+struct hash_config {
+ int data_format;
+ int algorithm;
+ int oper_mode;
+};
+
+/**
+ * struct hash_dma - Structure used for dma.
+ * @mask: DMA capabilities bitmap mask.
+ * @complete: Used to maintain state for a "completion".
+ * @chan_mem2hash: DMA channel.
+ * @cfg_mem2hash: DMA channel configuration.
+ * @sg_len: Scatterlist length.
+ * @sg: Scatterlist.
+ * @nents: Number of sg entries.
+ */
+struct hash_dma {
+ dma_cap_mask_t mask;
+ struct completion complete;
+ struct dma_chan *chan_mem2hash;
+ void *cfg_mem2hash;
+ int sg_len;
+ struct scatterlist *sg;
+ int nents;
+};
+
+/**
+ * struct hash_ctx - The context used for hash calculations.
+ * @key: The key used in the operation.
+ * @keylen: The length of the key.
+ * @state: The state of the current calculations.
+ * @config: The current configuration.
+ * @digestsize: The size of current digest.
+ * @device: Pointer to the device structure.
+ */
+struct hash_ctx {
+ u8 *key;
+ u32 keylen;
+ struct hash_config config;
+ int digestsize;
+ struct hash_device_data *device;
+};
+
+/**
+ * struct hash_ctx - The request context used for hash calculations.
+ * @state: The state of the current calculations.
+ * @dma_mode: Used in special cases (workaround), e.g. need to change to
+ * cpu mode, if not supported/working in dma mode.
+ * @updated: Indicates if hardware is initialized for new operations.
+ */
+struct hash_req_ctx {
+ struct hash_state state;
+ bool dma_mode;
+ u8 updated;
+};
+
+/**
+ * struct hash_device_data - structure for a hash device.
+ * @base: Pointer to the hardware base address.
+ * @list_node: For inclusion in klist.
+ * @dev: Pointer to the device dev structure.
+ * @ctx_lock: Spinlock for current_ctx.
+ * @current_ctx: Pointer to the currently allocated context.
+ * @power_state: TRUE = power state on, FALSE = power state off.
+ * @power_state_lock: Spinlock for power_state.
+ * @regulator: Pointer to the device's power control.
+ * @clk: Pointer to the device's clock control.
+ * @restore_dev_state: TRUE = saved state, FALSE = no saved state.
+ * @dma: Structure used for dma.
+ */
+struct hash_device_data {
+ struct hash_register __iomem *base;
+ struct klist_node list_node;
+ struct device *dev;
+ struct spinlock ctx_lock;
+ struct hash_ctx *current_ctx;
+ bool power_state;
+ struct spinlock power_state_lock;
+ struct regulator *regulator;
+ struct clk *clk;
+ bool restore_dev_state;
+ struct hash_state state; /* Used for saving and resuming state */
+ struct hash_dma dma;
+};
+
+int hash_check_hw(struct hash_device_data *device_data);
+
+int hash_setconfiguration(struct hash_device_data *device_data,
+ struct hash_config *config);
+
+void hash_begin(struct hash_device_data *device_data, struct hash_ctx *ctx);
+
+void hash_get_digest(struct hash_device_data *device_data,
+ u8 *digest, int algorithm);
+
+int hash_hw_update(struct ahash_request *req);
+
+int hash_save_state(struct hash_device_data *device_data,
+ struct hash_state *state);
+
+int hash_resume_state(struct hash_device_data *device_data,
+ const struct hash_state *state);
+
+#endif
diff --git a/drivers/crypto/ux500/hash/hash_core.c b/drivers/crypto/ux500/hash/hash_core.c
new file mode 100644
index 000000000000..6dbb9ec709a3
--- /dev/null
+++ b/drivers/crypto/ux500/hash/hash_core.c
@@ -0,0 +1,2009 @@
+/*
+ * Cryptographic API.
+ * Support for Nomadik hardware crypto engine.
+
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Shujuan Chen <shujuan.chen@stericsson.com> for ST-Ericsson
+ * Author: Joakim Bech <joakim.xx.bech@stericsson.com> for ST-Ericsson
+ * Author: Berne Hebark <berne.herbark@stericsson.com> for ST-Ericsson.
+ * Author: Niklas Hernaeus <niklas.hernaeus@stericsson.com> for ST-Ericsson.
+ * Author: Andreas Westin <andreas.westin@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/klist.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/crypto.h>
+
+#include <linux/regulator/consumer.h>
+#include <linux/dmaengine.h>
+#include <linux/bitops.h>
+
+#include <crypto/internal/hash.h>
+#include <crypto/sha.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/algapi.h>
+
+#include <mach/crypto-ux500.h>
+#include <mach/hardware.h>
+
+#include "hash_alg.h"
+
+#define DEV_DBG_NAME "hashX hashX:"
+
+static int hash_mode;
+module_param(hash_mode, int, 0);
+MODULE_PARM_DESC(hash_mode, "CPU or DMA mode. CPU = 0 (default), DMA = 1");
+
+/**
+ * Pre-calculated empty message digests.
+ */
+static u8 zero_message_hash_sha1[SHA1_DIGEST_SIZE] = {
+ 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d,
+ 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90,
+ 0xaf, 0xd8, 0x07, 0x09
+};
+
+static u8 zero_message_hash_sha256[SHA256_DIGEST_SIZE] = {
+ 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
+ 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
+ 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
+ 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55
+};
+
+/* HMAC-SHA1, no key */
+static u8 zero_message_hmac_sha1[SHA1_DIGEST_SIZE] = {
+ 0xfb, 0xdb, 0x1d, 0x1b, 0x18, 0xaa, 0x6c, 0x08,
+ 0x32, 0x4b, 0x7d, 0x64, 0xb7, 0x1f, 0xb7, 0x63,
+ 0x70, 0x69, 0x0e, 0x1d
+};
+
+/* HMAC-SHA256, no key */
+static u8 zero_message_hmac_sha256[SHA256_DIGEST_SIZE] = {
+ 0xb6, 0x13, 0x67, 0x9a, 0x08, 0x14, 0xd9, 0xec,
+ 0x77, 0x2f, 0x95, 0xd7, 0x78, 0xc3, 0x5f, 0xc5,
+ 0xff, 0x16, 0x97, 0xc4, 0x93, 0x71, 0x56, 0x53,
+ 0xc6, 0xc7, 0x12, 0x14, 0x42, 0x92, 0xc5, 0xad
+};
+
+/**
+ * struct hash_driver_data - data specific to the driver.
+ *
+ * @device_list: A list of registered devices to choose from.
+ * @device_allocation: A semaphore initialized with number of devices.
+ */
+struct hash_driver_data {
+ struct klist device_list;
+ struct semaphore device_allocation;
+};
+
+static struct hash_driver_data driver_data;
+
+/* Declaration of functions */
+/**
+ * hash_messagepad - Pads a message and write the nblw bits.
+ * @device_data: Structure for the hash device.
+ * @message: Last word of a message
+ * @index_bytes: The number of bytes in the last message
+ *
+ * This function manages the final part of the digest calculation, when less
+ * than 512 bits (64 bytes) remain in message. This means index_bytes < 64.
+ *
+ */
+static void hash_messagepad(struct hash_device_data *device_data,
+ const u32 *message, u8 index_bytes);
+
+/**
+ * release_hash_device - Releases a previously allocated hash device.
+ * @device_data: Structure for the hash device.
+ *
+ */
+static void release_hash_device(struct hash_device_data *device_data)
+{
+ spin_lock(&device_data->ctx_lock);
+ device_data->current_ctx->device = NULL;
+ device_data->current_ctx = NULL;
+ spin_unlock(&device_data->ctx_lock);
+
+ /*
+ * The down_interruptible part for this semaphore is called in
+ * cryp_get_device_data.
+ */
+ up(&driver_data.device_allocation);
+}
+
+static void hash_dma_setup_channel(struct hash_device_data *device_data,
+ struct device *dev)
+{
+ struct hash_platform_data *platform_data = dev->platform_data;
+ dma_cap_zero(device_data->dma.mask);
+ dma_cap_set(DMA_SLAVE, device_data->dma.mask);
+
+ device_data->dma.cfg_mem2hash = platform_data->mem_to_engine;
+ device_data->dma.chan_mem2hash =
+ dma_request_channel(device_data->dma.mask,
+ platform_data->dma_filter,
+ device_data->dma.cfg_mem2hash);
+
+ init_completion(&device_data->dma.complete);
+}
+
+static void hash_dma_callback(void *data)
+{
+ struct hash_ctx *ctx = (struct hash_ctx *) data;
+
+ complete(&ctx->device->dma.complete);
+}
+
+static int hash_set_dma_transfer(struct hash_ctx *ctx, struct scatterlist *sg,
+ int len, enum dma_data_direction direction)
+{
+ struct dma_async_tx_descriptor *desc = NULL;
+ struct dma_chan *channel = NULL;
+ dma_cookie_t cookie;
+
+ if (direction != DMA_TO_DEVICE) {
+ dev_err(ctx->device->dev, "[%s] Invalid DMA direction",
+ __func__);
+ return -EFAULT;
+ }
+
+ sg->length = ALIGN(sg->length, HASH_DMA_ALIGN_SIZE);
+
+ channel = ctx->device->dma.chan_mem2hash;
+ ctx->device->dma.sg = sg;
+ ctx->device->dma.sg_len = dma_map_sg(channel->device->dev,
+ ctx->device->dma.sg, ctx->device->dma.nents,
+ direction);
+
+ if (!ctx->device->dma.sg_len) {
+ dev_err(ctx->device->dev,
+ "[%s]: Could not map the sg list (TO_DEVICE)",
+ __func__);
+ return -EFAULT;
+ }
+
+ dev_dbg(ctx->device->dev, "[%s]: Setting up DMA for buffer "
+ "(TO_DEVICE)", __func__);
+ desc = channel->device->device_prep_slave_sg(channel,
+ ctx->device->dma.sg, ctx->device->dma.sg_len,
+ direction, DMA_CTRL_ACK | DMA_PREP_INTERRUPT, NULL);
+ if (!desc) {
+ dev_err(ctx->device->dev,
+ "[%s]: device_prep_slave_sg() failed!", __func__);
+ return -EFAULT;
+ }
+
+ desc->callback = hash_dma_callback;
+ desc->callback_param = ctx;
+
+ cookie = desc->tx_submit(desc);
+ dma_async_issue_pending(channel);
+
+ return 0;
+}
+
+static void hash_dma_done(struct hash_ctx *ctx)
+{
+ struct dma_chan *chan;
+
+ chan = ctx->device->dma.chan_mem2hash;
+ chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+ dma_unmap_sg(chan->device->dev, ctx->device->dma.sg,
+ ctx->device->dma.sg_len, DMA_TO_DEVICE);
+
+}
+
+static int hash_dma_write(struct hash_ctx *ctx,
+ struct scatterlist *sg, int len)
+{
+ int error = hash_set_dma_transfer(ctx, sg, len, DMA_TO_DEVICE);
+ if (error) {
+ dev_dbg(ctx->device->dev, "[%s]: hash_set_dma_transfer() "
+ "failed", __func__);
+ return error;
+ }
+
+ return len;
+}
+
+/**
+ * get_empty_message_digest - Returns a pre-calculated digest for
+ * the empty message.
+ * @device_data: Structure for the hash device.
+ * @zero_hash: Buffer to return the empty message digest.
+ * @zero_hash_size: Hash size of the empty message digest.
+ * @zero_digest: True if zero_digest returned.
+ */
+static int get_empty_message_digest(
+ struct hash_device_data *device_data,
+ u8 *zero_hash, u32 *zero_hash_size, bool *zero_digest)
+{
+ int ret = 0;
+ struct hash_ctx *ctx = device_data->current_ctx;
+ *zero_digest = false;
+
+ /**
+ * Caller responsible for ctx != NULL.
+ */
+
+ if (HASH_OPER_MODE_HASH == ctx->config.oper_mode) {
+ if (HASH_ALGO_SHA1 == ctx->config.algorithm) {
+ memcpy(zero_hash, &zero_message_hash_sha1[0],
+ SHA1_DIGEST_SIZE);
+ *zero_hash_size = SHA1_DIGEST_SIZE;
+ *zero_digest = true;
+ } else if (HASH_ALGO_SHA256 ==
+ ctx->config.algorithm) {
+ memcpy(zero_hash, &zero_message_hash_sha256[0],
+ SHA256_DIGEST_SIZE);
+ *zero_hash_size = SHA256_DIGEST_SIZE;
+ *zero_digest = true;
+ } else {
+ dev_err(device_data->dev, "[%s] "
+ "Incorrect algorithm!"
+ , __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+ } else if (HASH_OPER_MODE_HMAC == ctx->config.oper_mode) {
+ if (!ctx->keylen) {
+ if (HASH_ALGO_SHA1 == ctx->config.algorithm) {
+ memcpy(zero_hash, &zero_message_hmac_sha1[0],
+ SHA1_DIGEST_SIZE);
+ *zero_hash_size = SHA1_DIGEST_SIZE;
+ *zero_digest = true;
+ } else if (HASH_ALGO_SHA256 == ctx->config.algorithm) {
+ memcpy(zero_hash, &zero_message_hmac_sha256[0],
+ SHA256_DIGEST_SIZE);
+ *zero_hash_size = SHA256_DIGEST_SIZE;
+ *zero_digest = true;
+ } else {
+ dev_err(device_data->dev, "[%s] "
+ "Incorrect algorithm!"
+ , __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+ } else {
+ dev_dbg(device_data->dev, "[%s] Continue hash "
+ "calculation, since hmac key avalable",
+ __func__);
+ }
+ }
+out:
+
+ return ret;
+}
+
+/**
+ * hash_disable_power - Request to disable power and clock.
+ * @device_data: Structure for the hash device.
+ * @save_device_state: If true, saves the current hw state.
+ *
+ * This function request for disabling power (regulator) and clock,
+ * and could also save current hw state.
+ */
+static int hash_disable_power(
+ struct hash_device_data *device_data,
+ bool save_device_state)
+{
+ int ret = 0;
+ struct device *dev = device_data->dev;
+
+ spin_lock(&device_data->power_state_lock);
+ if (!device_data->power_state)
+ goto out;
+
+ if (save_device_state) {
+ hash_save_state(device_data,
+ &device_data->state);
+ device_data->restore_dev_state = true;
+ }
+
+ clk_disable(device_data->clk);
+ ret = regulator_disable(device_data->regulator);
+ if (ret)
+ dev_err(dev, "[%s] regulator_disable() failed!", __func__);
+
+ device_data->power_state = false;
+
+out:
+ spin_unlock(&device_data->power_state_lock);
+
+ return ret;
+}
+
+/**
+ * hash_enable_power - Request to enable power and clock.
+ * @device_data: Structure for the hash device.
+ * @restore_device_state: If true, restores a previous saved hw state.
+ *
+ * This function request for enabling power (regulator) and clock,
+ * and could also restore a previously saved hw state.
+ */
+static int hash_enable_power(
+ struct hash_device_data *device_data,
+ bool restore_device_state)
+{
+ int ret = 0;
+ struct device *dev = device_data->dev;
+
+ spin_lock(&device_data->power_state_lock);
+ if (!device_data->power_state) {
+ ret = regulator_enable(device_data->regulator);
+ if (ret) {
+ dev_err(dev, "[%s]: regulator_enable() failed!",
+ __func__);
+ goto out;
+ }
+ ret = clk_enable(device_data->clk);
+ if (ret) {
+ dev_err(dev, "[%s]: clk_enable() failed!",
+ __func__);
+ ret = regulator_disable(
+ device_data->regulator);
+ goto out;
+ }
+ device_data->power_state = true;
+ }
+
+ if (device_data->restore_dev_state) {
+ if (restore_device_state) {
+ device_data->restore_dev_state = false;
+ hash_resume_state(device_data,
+ &device_data->state);
+ }
+ }
+out:
+ spin_unlock(&device_data->power_state_lock);
+
+ return ret;
+}
+
+/**
+ * hash_get_device_data - Checks for an available hash device and return it.
+ * @hash_ctx: Structure for the hash context.
+ * @device_data: Structure for the hash device.
+ *
+ * This function check for an available hash device and return it to
+ * the caller.
+ * Note! Caller need to release the device, calling up().
+ */
+static int hash_get_device_data(struct hash_ctx *ctx,
+ struct hash_device_data **device_data)
+{
+ int ret;
+ struct klist_iter device_iterator;
+ struct klist_node *device_node;
+ struct hash_device_data *local_device_data = NULL;
+
+ /* Wait until a device is available */
+ ret = down_interruptible(&driver_data.device_allocation);
+ if (ret)
+ return ret; /* Interrupted */
+
+ /* Select a device */
+ klist_iter_init(&driver_data.device_list, &device_iterator);
+ device_node = klist_next(&device_iterator);
+ while (device_node) {
+ local_device_data = container_of(device_node,
+ struct hash_device_data, list_node);
+ spin_lock(&local_device_data->ctx_lock);
+ /* current_ctx allocates a device, NULL = unallocated */
+ if (local_device_data->current_ctx) {
+ device_node = klist_next(&device_iterator);
+ } else {
+ local_device_data->current_ctx = ctx;
+ ctx->device = local_device_data;
+ spin_unlock(&local_device_data->ctx_lock);
+ break;
+ }
+ spin_unlock(&local_device_data->ctx_lock);
+ }
+ klist_iter_exit(&device_iterator);
+
+ if (!device_node) {
+ /**
+ * No free device found.
+ * Since we allocated a device with down_interruptible, this
+ * should not be able to happen.
+ * Number of available devices, which are contained in
+ * device_allocation, is therefore decremented by not doing
+ * an up(device_allocation).
+ */
+ return -EBUSY;
+ }
+
+ *device_data = local_device_data;
+
+ return 0;
+}
+
+/**
+ * hash_hw_write_key - Writes the key to the hardware registries.
+ *
+ * @device_data: Structure for the hash device.
+ * @key: Key to be written.
+ * @keylen: The lengt of the key.
+ *
+ * Note! This function DOES NOT write to the NBLW registry, even though
+ * specified in the the hw design spec. Either due to incorrect info in the
+ * spec or due to a bug in the hw.
+ */
+static void hash_hw_write_key(struct hash_device_data *device_data,
+ const u8 *key, unsigned int keylen)
+{
+ u32 word = 0;
+ int nwords = 1;
+
+ HASH_CLEAR_BITS(&device_data->base->str, HASH_STR_NBLW_MASK);
+
+ while (keylen >= 4) {
+ u32 *key_word = (u32 *)key;
+
+ HASH_SET_DIN(key_word, nwords);
+ keylen -= 4;
+ key += 4;
+ }
+
+ /* Take care of the remaining bytes in the last word */
+ if (keylen) {
+ word = 0;
+ while (keylen) {
+ word |= (key[keylen - 1] << (8 * (keylen - 1)));
+ keylen--;
+ }
+
+ HASH_SET_DIN(&word, nwords);
+ }
+
+ while (device_data->base->str & HASH_STR_DCAL_MASK)
+ cpu_relax();
+
+ HASH_SET_DCAL;
+
+ while (device_data->base->str & HASH_STR_DCAL_MASK)
+ cpu_relax();
+}
+
+/**
+ * init_hash_hw - Initialise the hash hardware for a new calculation.
+ * @device_data: Structure for the hash device.
+ * @ctx: The hash context.
+ *
+ * This function will enable the bits needed to clear and start a new
+ * calculation.
+ */
+static int init_hash_hw(struct hash_device_data *device_data,
+ struct hash_ctx *ctx)
+{
+ int ret = 0;
+
+ ret = hash_setconfiguration(device_data, &ctx->config);
+ if (ret) {
+ dev_err(device_data->dev, "[%s] hash_setconfiguration() "
+ "failed!", __func__);
+ return ret;
+ }
+
+ hash_begin(device_data, ctx);
+
+ if (ctx->config.oper_mode == HASH_OPER_MODE_HMAC)
+ hash_hw_write_key(device_data, ctx->key, ctx->keylen);
+
+ return ret;
+}
+
+/**
+ * hash_get_nents - Return number of entries (nents) in scatterlist (sg).
+ *
+ * @sg: Scatterlist.
+ * @size: Size in bytes.
+ * @aligned: True if sg data aligned to work in DMA mode.
+ *
+ */
+static int hash_get_nents(struct scatterlist *sg, int size, bool *aligned)
+{
+ int nents = 0;
+ bool aligned_data = true;
+
+ while (size > 0 && sg) {
+ nents++;
+ size -= sg->length;
+
+ /* hash_set_dma_transfer will align last nent */
+ if ((aligned && !IS_ALIGNED(sg->offset, HASH_DMA_ALIGN_SIZE))
+ || (!IS_ALIGNED(sg->length, HASH_DMA_ALIGN_SIZE) &&
+ size > 0))
+ aligned_data = false;
+
+ sg = sg_next(sg);
+ }
+
+ if (aligned)
+ *aligned = aligned_data;
+
+ if (size != 0)
+ return -EFAULT;
+
+ return nents;
+}
+
+/**
+ * hash_dma_valid_data - checks for dma valid sg data.
+ * @sg: Scatterlist.
+ * @datasize: Datasize in bytes.
+ *
+ * NOTE! This function checks for dma valid sg data, since dma
+ * only accept datasizes of even wordsize.
+ */
+static bool hash_dma_valid_data(struct scatterlist *sg, int datasize)
+{
+ bool aligned;
+
+ /* Need to include at least one nent, else error */
+ if (hash_get_nents(sg, datasize, &aligned) < 1)
+ return false;
+
+ return aligned;
+}
+
+/**
+ * hash_init - Common hash init function for SHA1/SHA2 (SHA256).
+ * @req: The hash request for the job.
+ *
+ * Initialize structures.
+ */
+static int hash_init(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct hash_req_ctx *req_ctx = ahash_request_ctx(req);
+
+ if (!ctx->key)
+ ctx->keylen = 0;
+
+ memset(&req_ctx->state, 0, sizeof(struct hash_state));
+ req_ctx->updated = 0;
+ if (hash_mode == HASH_MODE_DMA) {
+ if (req->nbytes < HASH_DMA_ALIGN_SIZE) {
+ req_ctx->dma_mode = false; /* Don't use DMA */
+
+ pr_debug(DEV_DBG_NAME " [%s] DMA mode, but direct "
+ "to CPU mode for data size < %d",
+ __func__, HASH_DMA_ALIGN_SIZE);
+ } else {
+ if (req->nbytes >= HASH_DMA_PERFORMANCE_MIN_SIZE &&
+ hash_dma_valid_data(req->src,
+ req->nbytes)) {
+ req_ctx->dma_mode = true;
+ } else {
+ req_ctx->dma_mode = false;
+ pr_debug(DEV_DBG_NAME " [%s] DMA mode, but use"
+ " CPU mode for datalength < %d"
+ " or non-aligned data, except "
+ "in last nent", __func__,
+ HASH_DMA_PERFORMANCE_MIN_SIZE);
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * hash_processblock - This function processes a single block of 512 bits (64
+ * bytes), word aligned, starting at message.
+ * @device_data: Structure for the hash device.
+ * @message: Block (512 bits) of message to be written to
+ * the HASH hardware.
+ *
+ */
+static void hash_processblock(
+ struct hash_device_data *device_data,
+ const u32 *message, int length)
+{
+ int len = length / HASH_BYTES_PER_WORD;
+ /*
+ * NBLW bits. Reset the number of bits in last word (NBLW).
+ */
+ HASH_CLEAR_BITS(&device_data->base->str, HASH_STR_NBLW_MASK);
+
+ /*
+ * Write message data to the HASH_DIN register.
+ */
+ HASH_SET_DIN(message, len);
+}
+
+/**
+ * hash_messagepad - Pads a message and write the nblw bits.
+ * @device_data: Structure for the hash device.
+ * @message: Last word of a message.
+ * @index_bytes: The number of bytes in the last message.
+ *
+ * This function manages the final part of the digest calculation, when less
+ * than 512 bits (64 bytes) remain in message. This means index_bytes < 64.
+ *
+ */
+static void hash_messagepad(struct hash_device_data *device_data,
+ const u32 *message, u8 index_bytes)
+{
+ int nwords = 1;
+
+ /*
+ * Clear hash str register, only clear NBLW
+ * since DCAL will be reset by hardware.
+ */
+ HASH_CLEAR_BITS(&device_data->base->str, HASH_STR_NBLW_MASK);
+
+ /* Main loop */
+ while (index_bytes >= 4) {
+ HASH_SET_DIN(message, nwords);
+ index_bytes -= 4;
+ message++;
+ }
+
+ if (index_bytes)
+ HASH_SET_DIN(message, nwords);
+
+ while (device_data->base->str & HASH_STR_DCAL_MASK)
+ cpu_relax();
+
+ /* num_of_bytes == 0 => NBLW <- 0 (32 bits valid in DATAIN) */
+ HASH_SET_NBLW(index_bytes * 8);
+ dev_dbg(device_data->dev, "[%s] DIN=0x%08x NBLW=%d", __func__,
+ readl_relaxed(&device_data->base->din),
+ (int)(readl_relaxed(&device_data->base->str) &
+ HASH_STR_NBLW_MASK));
+ HASH_SET_DCAL;
+ dev_dbg(device_data->dev, "[%s] after dcal -> DIN=0x%08x NBLW=%d",
+ __func__, readl_relaxed(&device_data->base->din),
+ (int)(readl_relaxed(&device_data->base->str) &
+ HASH_STR_NBLW_MASK));
+
+ while (device_data->base->str & HASH_STR_DCAL_MASK)
+ cpu_relax();
+}
+
+/**
+ * hash_incrementlength - Increments the length of the current message.
+ * @ctx: Hash context
+ * @incr: Length of message processed already
+ *
+ * Overflow cannot occur, because conditions for overflow are checked in
+ * hash_hw_update.
+ */
+static void hash_incrementlength(struct hash_req_ctx *ctx, u32 incr)
+{
+ ctx->state.length.low_word += incr;
+
+ /* Check for wrap-around */
+ if (ctx->state.length.low_word < incr)
+ ctx->state.length.high_word++;
+}
+
+/**
+ * hash_setconfiguration - Sets the required configuration for the hash
+ * hardware.
+ * @device_data: Structure for the hash device.
+ * @config: Pointer to a configuration structure.
+ */
+int hash_setconfiguration(struct hash_device_data *device_data,
+ struct hash_config *config)
+{
+ int ret = 0;
+
+ if (config->algorithm != HASH_ALGO_SHA1 &&
+ config->algorithm != HASH_ALGO_SHA256)
+ return -EPERM;
+
+ /*
+ * DATAFORM bits. Set the DATAFORM bits to 0b11, which means the data
+ * to be written to HASH_DIN is considered as 32 bits.
+ */
+ HASH_SET_DATA_FORMAT(config->data_format);
+
+ /*
+ * ALGO bit. Set to 0b1 for SHA-1 and 0b0 for SHA-256
+ */
+ switch (config->algorithm) {
+ case HASH_ALGO_SHA1:
+ HASH_SET_BITS(&device_data->base->cr, HASH_CR_ALGO_MASK);
+ break;
+
+ case HASH_ALGO_SHA256:
+ HASH_CLEAR_BITS(&device_data->base->cr, HASH_CR_ALGO_MASK);
+ break;
+
+ default:
+ dev_err(device_data->dev, "[%s] Incorrect algorithm.",
+ __func__);
+ return -EPERM;
+ }
+
+ /*
+ * MODE bit. This bit selects between HASH or HMAC mode for the
+ * selected algorithm. 0b0 = HASH and 0b1 = HMAC.
+ */
+ if (HASH_OPER_MODE_HASH == config->oper_mode)
+ HASH_CLEAR_BITS(&device_data->base->cr,
+ HASH_CR_MODE_MASK);
+ else if (HASH_OPER_MODE_HMAC == config->oper_mode) {
+ HASH_SET_BITS(&device_data->base->cr,
+ HASH_CR_MODE_MASK);
+ if (device_data->current_ctx->keylen > HASH_BLOCK_SIZE) {
+ /* Truncate key to blocksize */
+ dev_dbg(device_data->dev, "[%s] LKEY set", __func__);
+ HASH_SET_BITS(&device_data->base->cr,
+ HASH_CR_LKEY_MASK);
+ } else {
+ dev_dbg(device_data->dev, "[%s] LKEY cleared",
+ __func__);
+ HASH_CLEAR_BITS(&device_data->base->cr,
+ HASH_CR_LKEY_MASK);
+ }
+ } else { /* Wrong hash mode */
+ ret = -EPERM;
+ dev_err(device_data->dev, "[%s] HASH_INVALID_PARAMETER!",
+ __func__);
+ }
+ return ret;
+}
+
+/**
+ * hash_begin - This routine resets some globals and initializes the hash
+ * hardware.
+ * @device_data: Structure for the hash device.
+ * @ctx: Hash context.
+ */
+void hash_begin(struct hash_device_data *device_data, struct hash_ctx *ctx)
+{
+ /* HW and SW initializations */
+ /* Note: there is no need to initialize buffer and digest members */
+
+ while (device_data->base->str & HASH_STR_DCAL_MASK)
+ cpu_relax();
+
+ /*
+ * INIT bit. Set this bit to 0b1 to reset the HASH processor core and
+ * prepare the initialize the HASH accelerator to compute the message
+ * digest of a new message.
+ */
+ HASH_INITIALIZE;
+
+ /*
+ * NBLW bits. Reset the number of bits in last word (NBLW).
+ */
+ HASH_CLEAR_BITS(&device_data->base->str, HASH_STR_NBLW_MASK);
+}
+
+int hash_process_data(
+ struct hash_device_data *device_data,
+ struct hash_ctx *ctx, struct hash_req_ctx *req_ctx,
+ int msg_length, u8 *data_buffer, u8 *buffer, u8 *index)
+{
+ int ret = 0;
+ u32 count;
+
+ do {
+ if ((*index + msg_length) < HASH_BLOCK_SIZE) {
+ for (count = 0; count < msg_length; count++) {
+ buffer[*index + count] =
+ *(data_buffer + count);
+ }
+ *index += msg_length;
+ msg_length = 0;
+ } else {
+ if (req_ctx->updated) {
+
+ ret = hash_resume_state(device_data,
+ &device_data->state);
+ memmove(req_ctx->state.buffer,
+ device_data->state.buffer,
+ HASH_BLOCK_SIZE / sizeof(u32));
+ if (ret) {
+ dev_err(device_data->dev, "[%s] "
+ "hash_resume_state()"
+ " failed!", __func__);
+ goto out;
+ }
+ } else {
+ ret = init_hash_hw(device_data, ctx);
+ if (ret) {
+ dev_err(device_data->dev, "[%s] "
+ "init_hash_hw()"
+ " failed!", __func__);
+ goto out;
+ }
+ req_ctx->updated = 1;
+ }
+ /*
+ * If 'data_buffer' is four byte aligned and
+ * local buffer does not have any data, we can
+ * write data directly from 'data_buffer' to
+ * HW peripheral, otherwise we first copy data
+ * to a local buffer
+ */
+ if ((0 == (((u32)data_buffer) % 4))
+ && (0 == *index))
+ hash_processblock(device_data,
+ (const u32 *)
+ data_buffer, HASH_BLOCK_SIZE);
+ else {
+ for (count = 0; count <
+ (u32)(HASH_BLOCK_SIZE -
+ *index);
+ count++) {
+ buffer[*index + count] =
+ *(data_buffer + count);
+ }
+ hash_processblock(device_data,
+ (const u32 *)buffer,
+ HASH_BLOCK_SIZE);
+ }
+ hash_incrementlength(req_ctx, HASH_BLOCK_SIZE);
+ data_buffer += (HASH_BLOCK_SIZE - *index);
+
+ msg_length -= (HASH_BLOCK_SIZE - *index);
+ *index = 0;
+
+ ret = hash_save_state(device_data,
+ &device_data->state);
+
+ memmove(device_data->state.buffer,
+ req_ctx->state.buffer,
+ HASH_BLOCK_SIZE / sizeof(u32));
+ if (ret) {
+ dev_err(device_data->dev, "[%s] "
+ "hash_save_state()"
+ " failed!", __func__);
+ goto out;
+ }
+ }
+ } while (msg_length != 0);
+out:
+
+ return ret;
+}
+
+/**
+ * hash_dma_final - The hash dma final function for SHA1/SHA256.
+ * @req: The hash request for the job.
+ */
+static int hash_dma_final(struct ahash_request *req)
+{
+ int ret = 0;
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct hash_req_ctx *req_ctx = ahash_request_ctx(req);
+ struct hash_device_data *device_data;
+ u8 digest[SHA256_DIGEST_SIZE];
+ int bytes_written = 0;
+
+ ret = hash_get_device_data(ctx, &device_data);
+ if (ret)
+ return ret;
+
+ dev_dbg(device_data->dev, "[%s] (ctx=0x%x)!", __func__, (u32) ctx);
+
+ if (req_ctx->updated) {
+ ret = hash_resume_state(device_data, &device_data->state);
+
+ if (ret) {
+ dev_err(device_data->dev, "[%s] hash_resume_state() "
+ "failed!", __func__);
+ goto out;
+ }
+
+ }
+
+ if (!req_ctx->updated) {
+ ret = hash_setconfiguration(device_data, &ctx->config);
+ if (ret) {
+ dev_err(device_data->dev, "[%s] "
+ "hash_setconfiguration() failed!",
+ __func__);
+ goto out;
+ }
+
+ /* Enable DMA input */
+ if (hash_mode != HASH_MODE_DMA || !req_ctx->dma_mode) {
+ HASH_CLEAR_BITS(&device_data->base->cr,
+ HASH_CR_DMAE_MASK);
+ } else {
+ HASH_SET_BITS(&device_data->base->cr,
+ HASH_CR_DMAE_MASK);
+ HASH_SET_BITS(&device_data->base->cr,
+ HASH_CR_PRIVN_MASK);
+ }
+
+ HASH_INITIALIZE;
+
+ if (ctx->config.oper_mode == HASH_OPER_MODE_HMAC)
+ hash_hw_write_key(device_data, ctx->key, ctx->keylen);
+
+ /* Number of bits in last word = (nbytes * 8) % 32 */
+ HASH_SET_NBLW((req->nbytes * 8) % 32);
+ req_ctx->updated = 1;
+ }
+
+ /* Store the nents in the dma struct. */
+ ctx->device->dma.nents = hash_get_nents(req->src, req->nbytes, NULL);
+ if (!ctx->device->dma.nents) {
+ dev_err(device_data->dev, "[%s] "
+ "ctx->device->dma.nents = 0", __func__);
+ goto out;
+ }
+
+ bytes_written = hash_dma_write(ctx, req->src, req->nbytes);
+ if (bytes_written != req->nbytes) {
+ dev_err(device_data->dev, "[%s] "
+ "hash_dma_write() failed!", __func__);
+ goto out;
+ }
+
+ wait_for_completion(&ctx->device->dma.complete);
+ hash_dma_done(ctx);
+
+ while (device_data->base->str & HASH_STR_DCAL_MASK)
+ cpu_relax();
+
+ if (ctx->config.oper_mode == HASH_OPER_MODE_HMAC && ctx->key) {
+ unsigned int keylen = ctx->keylen;
+ u8 *key = ctx->key;
+
+ dev_dbg(device_data->dev, "[%s] keylen: %d", __func__,
+ ctx->keylen);
+ hash_hw_write_key(device_data, key, keylen);
+ }
+
+ hash_get_digest(device_data, digest, ctx->config.algorithm);
+ memcpy(req->result, digest, ctx->digestsize);
+
+out:
+ release_hash_device(device_data);
+
+ /**
+ * Allocated in setkey, and only used in HMAC.
+ */
+ kfree(ctx->key);
+
+ return ret;
+}
+
+/**
+ * hash_hw_final - The final hash calculation function
+ * @req: The hash request for the job.
+ */
+int hash_hw_final(struct ahash_request *req)
+{
+ int ret = 0;
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct hash_req_ctx *req_ctx = ahash_request_ctx(req);
+ struct hash_device_data *device_data;
+ u8 digest[SHA256_DIGEST_SIZE];
+
+ ret = hash_get_device_data(ctx, &device_data);
+ if (ret)
+ return ret;
+
+ dev_dbg(device_data->dev, "[%s] (ctx=0x%x)!", __func__, (u32) ctx);
+
+ if (req_ctx->updated) {
+ ret = hash_resume_state(device_data, &device_data->state);
+
+ if (ret) {
+ dev_err(device_data->dev, "[%s] hash_resume_state() "
+ "failed!", __func__);
+ goto out;
+ }
+ } else if (req->nbytes == 0 && ctx->keylen == 0) {
+ u8 zero_hash[SHA256_DIGEST_SIZE];
+ u32 zero_hash_size = 0;
+ bool zero_digest = false;
+ /**
+ * Use a pre-calculated empty message digest
+ * (workaround since hw return zeroes, hw bug!?)
+ */
+ ret = get_empty_message_digest(device_data, &zero_hash[0],
+ &zero_hash_size, &zero_digest);
+ if (!ret && likely(zero_hash_size == ctx->digestsize) &&
+ zero_digest) {
+ memcpy(req->result, &zero_hash[0], ctx->digestsize);
+ goto out;
+ } else if (!ret && !zero_digest) {
+ dev_dbg(device_data->dev, "[%s] HMAC zero msg with "
+ "key, continue...", __func__);
+ } else {
+ dev_err(device_data->dev, "[%s] ret=%d, or wrong "
+ "digest size? %s", __func__, ret,
+ (zero_hash_size == ctx->digestsize) ?
+ "true" : "false");
+ /* Return error */
+ goto out;
+ }
+ } else if (req->nbytes == 0 && ctx->keylen > 0) {
+ dev_err(device_data->dev, "[%s] Empty message with "
+ "keylength > 0, NOT supported.", __func__);
+ goto out;
+ }
+
+ if (!req_ctx->updated) {
+ ret = init_hash_hw(device_data, ctx);
+ if (ret) {
+ dev_err(device_data->dev, "[%s] init_hash_hw() "
+ "failed!", __func__);
+ goto out;
+ }
+ }
+
+ if (req_ctx->state.index) {
+ hash_messagepad(device_data, req_ctx->state.buffer,
+ req_ctx->state.index);
+ } else {
+ HASH_SET_DCAL;
+ while (device_data->base->str & HASH_STR_DCAL_MASK)
+ cpu_relax();
+ }
+
+ if (ctx->config.oper_mode == HASH_OPER_MODE_HMAC && ctx->key) {
+ unsigned int keylen = ctx->keylen;
+ u8 *key = ctx->key;
+
+ dev_dbg(device_data->dev, "[%s] keylen: %d", __func__,
+ ctx->keylen);
+ hash_hw_write_key(device_data, key, keylen);
+ }
+
+ hash_get_digest(device_data, digest, ctx->config.algorithm);
+ memcpy(req->result, digest, ctx->digestsize);
+
+out:
+ release_hash_device(device_data);
+
+ /**
+ * Allocated in setkey, and only used in HMAC.
+ */
+ kfree(ctx->key);
+
+ return ret;
+}
+
+/**
+ * hash_hw_update - Updates current HASH computation hashing another part of
+ * the message.
+ * @req: Byte array containing the message to be hashed (caller
+ * allocated).
+ */
+int hash_hw_update(struct ahash_request *req)
+{
+ int ret = 0;
+ u8 index = 0;
+ u8 *buffer;
+ struct hash_device_data *device_data;
+ u8 *data_buffer;
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct hash_req_ctx *req_ctx = ahash_request_ctx(req);
+ struct crypto_hash_walk walk;
+ int msg_length = crypto_hash_walk_first(req, &walk);
+
+ /* Empty message ("") is correct indata */
+ if (msg_length == 0)
+ return ret;
+
+ index = req_ctx->state.index;
+ buffer = (u8 *)req_ctx->state.buffer;
+
+ /* Check if ctx->state.length + msg_length
+ overflows */
+ if (msg_length > (req_ctx->state.length.low_word + msg_length) &&
+ HASH_HIGH_WORD_MAX_VAL ==
+ req_ctx->state.length.high_word) {
+ pr_err(DEV_DBG_NAME " [%s] HASH_MSG_LENGTH_OVERFLOW!",
+ __func__);
+ return -EPERM;
+ }
+
+ ret = hash_get_device_data(ctx, &device_data);
+ if (ret)
+ return ret;
+
+ /* Main loop */
+ while (0 != msg_length) {
+ data_buffer = walk.data;
+ ret = hash_process_data(device_data, ctx, req_ctx, msg_length,
+ data_buffer, buffer, &index);
+
+ if (ret) {
+ dev_err(device_data->dev, "[%s] hash_internal_hw_"
+ "update() failed!", __func__);
+ goto out;
+ }
+
+ msg_length = crypto_hash_walk_done(&walk, 0);
+ }
+
+ req_ctx->state.index = index;
+ dev_dbg(device_data->dev, "[%s] indata length=%d, bin=%d))",
+ __func__, req_ctx->state.index,
+ req_ctx->state.bit_index);
+
+out:
+ release_hash_device(device_data);
+
+ return ret;
+}
+
+/**
+ * hash_resume_state - Function that resumes the state of an calculation.
+ * @device_data: Pointer to the device structure.
+ * @device_state: The state to be restored in the hash hardware
+ */
+int hash_resume_state(struct hash_device_data *device_data,
+ const struct hash_state *device_state)
+{
+ u32 temp_cr;
+ s32 count;
+ int hash_mode = HASH_OPER_MODE_HASH;
+
+ if (NULL == device_state) {
+ dev_err(device_data->dev, "[%s] HASH_INVALID_PARAMETER!",
+ __func__);
+ return -EPERM;
+ }
+
+ /* Check correctness of index and length members */
+ if (device_state->index > HASH_BLOCK_SIZE
+ || (device_state->length.low_word % HASH_BLOCK_SIZE) != 0) {
+ dev_err(device_data->dev, "[%s] HASH_INVALID_PARAMETER!",
+ __func__);
+ return -EPERM;
+ }
+
+ /*
+ * INIT bit. Set this bit to 0b1 to reset the HASH processor core and
+ * prepare the initialize the HASH accelerator to compute the message
+ * digest of a new message.
+ */
+ HASH_INITIALIZE;
+
+ temp_cr = device_state->temp_cr;
+ writel_relaxed(temp_cr & HASH_CR_RESUME_MASK, &device_data->base->cr);
+
+ if (device_data->base->cr & HASH_CR_MODE_MASK)
+ hash_mode = HASH_OPER_MODE_HMAC;
+ else
+ hash_mode = HASH_OPER_MODE_HASH;
+
+ for (count = 0; count < HASH_CSR_COUNT; count++) {
+ if ((count >= 36) && (hash_mode == HASH_OPER_MODE_HASH))
+ break;
+
+ writel_relaxed(device_state->csr[count],
+ &device_data->base->csrx[count]);
+ }
+
+ writel_relaxed(device_state->csfull, &device_data->base->csfull);
+ writel_relaxed(device_state->csdatain, &device_data->base->csdatain);
+
+ writel_relaxed(device_state->str_reg, &device_data->base->str);
+ writel_relaxed(temp_cr, &device_data->base->cr);
+
+ return 0;
+}
+
+/**
+ * hash_save_state - Function that saves the state of hardware.
+ * @device_data: Pointer to the device structure.
+ * @device_state: The strucure where the hardware state should be saved.
+ */
+int hash_save_state(struct hash_device_data *device_data,
+ struct hash_state *device_state)
+{
+ u32 temp_cr;
+ u32 count;
+ int hash_mode = HASH_OPER_MODE_HASH;
+
+ if (NULL == device_state) {
+ dev_err(device_data->dev, "[%s] HASH_INVALID_PARAMETER!",
+ __func__);
+ return -ENOTSUPP;
+ }
+
+ /* Write dummy value to force digest intermediate calculation. This
+ * actually makes sure that there isn't any ongoing calculation in the
+ * hardware.
+ */
+ while (device_data->base->str & HASH_STR_DCAL_MASK)
+ cpu_relax();
+
+ temp_cr = readl_relaxed(&device_data->base->cr);
+
+ device_state->str_reg = readl_relaxed(&device_data->base->str);
+
+ device_state->din_reg = readl_relaxed(&device_data->base->din);
+
+ if (device_data->base->cr & HASH_CR_MODE_MASK)
+ hash_mode = HASH_OPER_MODE_HMAC;
+ else
+ hash_mode = HASH_OPER_MODE_HASH;
+
+ for (count = 0; count < HASH_CSR_COUNT; count++) {
+ if ((count >= 36) && (hash_mode == HASH_OPER_MODE_HASH))
+ break;
+
+ device_state->csr[count] =
+ readl_relaxed(&device_data->base->csrx[count]);
+ }
+
+ device_state->csfull = readl_relaxed(&device_data->base->csfull);
+ device_state->csdatain = readl_relaxed(&device_data->base->csdatain);
+
+ device_state->temp_cr = temp_cr;
+
+ return 0;
+}
+
+/**
+ * hash_check_hw - This routine checks for peripheral Ids and PCell Ids.
+ * @device_data:
+ *
+ */
+int hash_check_hw(struct hash_device_data *device_data)
+{
+ /* Checking Peripheral Ids */
+ if (HASH_P_ID0 == readl_relaxed(&device_data->base->periphid0)
+ && HASH_P_ID1 == readl_relaxed(&device_data->base->periphid1)
+ && HASH_P_ID2 == readl_relaxed(&device_data->base->periphid2)
+ && HASH_P_ID3 == readl_relaxed(&device_data->base->periphid3)
+ && HASH_CELL_ID0 == readl_relaxed(&device_data->base->cellid0)
+ && HASH_CELL_ID1 == readl_relaxed(&device_data->base->cellid1)
+ && HASH_CELL_ID2 == readl_relaxed(&device_data->base->cellid2)
+ && HASH_CELL_ID3 == readl_relaxed(&device_data->base->cellid3)
+ ) {
+ return 0;
+ }
+
+ dev_err(device_data->dev, "[%s] HASH_UNSUPPORTED_HW!",
+ __func__);
+ return -ENOTSUPP;
+}
+
+/**
+ * hash_get_digest - Gets the digest.
+ * @device_data: Pointer to the device structure.
+ * @digest: User allocated byte array for the calculated digest.
+ * @algorithm: The algorithm in use.
+ */
+void hash_get_digest(struct hash_device_data *device_data,
+ u8 *digest, int algorithm)
+{
+ u32 temp_hx_val, count;
+ int loop_ctr;
+
+ if (algorithm != HASH_ALGO_SHA1 && algorithm != HASH_ALGO_SHA256) {
+ dev_err(device_data->dev, "[%s] Incorrect algorithm %d",
+ __func__, algorithm);
+ return;
+ }
+
+ if (algorithm == HASH_ALGO_SHA1)
+ loop_ctr = SHA1_DIGEST_SIZE / sizeof(u32);
+ else
+ loop_ctr = SHA256_DIGEST_SIZE / sizeof(u32);
+
+ dev_dbg(device_data->dev, "[%s] digest array:(0x%x)",
+ __func__, (u32) digest);
+
+ /* Copy result into digest array */
+ for (count = 0; count < loop_ctr; count++) {
+ temp_hx_val = readl_relaxed(&device_data->base->hx[count]);
+ digest[count * 4] = (u8) ((temp_hx_val >> 24) & 0xFF);
+ digest[count * 4 + 1] = (u8) ((temp_hx_val >> 16) & 0xFF);
+ digest[count * 4 + 2] = (u8) ((temp_hx_val >> 8) & 0xFF);
+ digest[count * 4 + 3] = (u8) ((temp_hx_val >> 0) & 0xFF);
+ }
+}
+
+/**
+ * hash_update - The hash update function for SHA1/SHA2 (SHA256).
+ * @req: The hash request for the job.
+ */
+static int ahash_update(struct ahash_request *req)
+{
+ int ret = 0;
+ struct hash_req_ctx *req_ctx = ahash_request_ctx(req);
+
+ if (hash_mode != HASH_MODE_DMA || !req_ctx->dma_mode)
+ ret = hash_hw_update(req);
+ /* Skip update for DMA, all data will be passed to DMA in final */
+
+ if (ret) {
+ pr_err(DEV_DBG_NAME " [%s] hash_hw_update() failed!",
+ __func__);
+ }
+
+ return ret;
+}
+
+/**
+ * hash_final - The hash final function for SHA1/SHA2 (SHA256).
+ * @req: The hash request for the job.
+ */
+static int ahash_final(struct ahash_request *req)
+{
+ int ret = 0;
+ struct hash_req_ctx *req_ctx = ahash_request_ctx(req);
+
+ pr_debug(DEV_DBG_NAME " [%s] data size: %d", __func__, req->nbytes);
+
+ if ((hash_mode == HASH_MODE_DMA) && req_ctx->dma_mode)
+ ret = hash_dma_final(req);
+ else
+ ret = hash_hw_final(req);
+
+ if (ret) {
+ pr_err(DEV_DBG_NAME " [%s] hash_hw/dma_final() failed",
+ __func__);
+ }
+
+ return ret;
+}
+
+static int hash_setkey(struct crypto_ahash *tfm,
+ const u8 *key, unsigned int keylen, int alg)
+{
+ int ret = 0;
+ struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ /**
+ * Freed in final.
+ */
+ ctx->key = kmalloc(keylen, GFP_KERNEL);
+ if (!ctx->key) {
+ pr_err(DEV_DBG_NAME " [%s] Failed to allocate ctx->key "
+ "for %d\n", __func__, alg);
+ return -ENOMEM;
+ }
+
+ memcpy(ctx->key, key, keylen);
+ ctx->keylen = keylen;
+
+ return ret;
+}
+
+static int ahash_sha1_init(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ ctx->config.data_format = HASH_DATA_8_BITS;
+ ctx->config.algorithm = HASH_ALGO_SHA1;
+ ctx->config.oper_mode = HASH_OPER_MODE_HASH;
+ ctx->digestsize = SHA1_DIGEST_SIZE;
+
+ return hash_init(req);
+}
+
+static int ahash_sha256_init(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ ctx->config.data_format = HASH_DATA_8_BITS;
+ ctx->config.algorithm = HASH_ALGO_SHA256;
+ ctx->config.oper_mode = HASH_OPER_MODE_HASH;
+ ctx->digestsize = SHA256_DIGEST_SIZE;
+
+ return hash_init(req);
+}
+
+static int ahash_sha1_digest(struct ahash_request *req)
+{
+ int ret2, ret1;
+
+ ret1 = ahash_sha1_init(req);
+ if (ret1)
+ goto out;
+
+ ret1 = ahash_update(req);
+ ret2 = ahash_final(req);
+
+out:
+ return ret1 ? ret1 : ret2;
+}
+
+static int ahash_sha256_digest(struct ahash_request *req)
+{
+ int ret2, ret1;
+
+ ret1 = ahash_sha256_init(req);
+ if (ret1)
+ goto out;
+
+ ret1 = ahash_update(req);
+ ret2 = ahash_final(req);
+
+out:
+ return ret1 ? ret1 : ret2;
+}
+
+static int hmac_sha1_init(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ ctx->config.data_format = HASH_DATA_8_BITS;
+ ctx->config.algorithm = HASH_ALGO_SHA1;
+ ctx->config.oper_mode = HASH_OPER_MODE_HMAC;
+ ctx->digestsize = SHA1_DIGEST_SIZE;
+
+ return hash_init(req);
+}
+
+static int hmac_sha256_init(struct ahash_request *req)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ struct hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ ctx->config.data_format = HASH_DATA_8_BITS;
+ ctx->config.algorithm = HASH_ALGO_SHA256;
+ ctx->config.oper_mode = HASH_OPER_MODE_HMAC;
+ ctx->digestsize = SHA256_DIGEST_SIZE;
+
+ return hash_init(req);
+}
+
+static int hmac_sha1_digest(struct ahash_request *req)
+{
+ int ret2, ret1;
+
+ ret1 = hmac_sha1_init(req);
+ if (ret1)
+ goto out;
+
+ ret1 = ahash_update(req);
+ ret2 = ahash_final(req);
+
+out:
+ return ret1 ? ret1 : ret2;
+}
+
+static int hmac_sha256_digest(struct ahash_request *req)
+{
+ int ret2, ret1;
+
+ ret1 = hmac_sha256_init(req);
+ if (ret1)
+ goto out;
+
+ ret1 = ahash_update(req);
+ ret2 = ahash_final(req);
+
+out:
+ return ret1 ? ret1 : ret2;
+}
+
+static int hmac_sha1_setkey(struct crypto_ahash *tfm,
+ const u8 *key, unsigned int keylen)
+{
+ return hash_setkey(tfm, key, keylen, HASH_ALGO_SHA1);
+}
+
+static int hmac_sha256_setkey(struct crypto_ahash *tfm,
+ const u8 *key, unsigned int keylen)
+{
+ return hash_setkey(tfm, key, keylen, HASH_ALGO_SHA256);
+}
+
+struct hash_algo_template {
+ struct hash_config conf;
+ struct ahash_alg hash;
+};
+
+static int hash_cra_init(struct crypto_tfm *tfm)
+{
+ struct hash_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct crypto_alg *alg = tfm->__crt_alg;
+ struct hash_algo_template *hash_alg;
+
+ hash_alg = container_of(__crypto_ahash_alg(alg),
+ struct hash_algo_template,
+ hash);
+
+ crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
+ sizeof(struct hash_req_ctx));
+
+ ctx->config.data_format = HASH_DATA_8_BITS;
+ ctx->config.algorithm = hash_alg->conf.algorithm;
+ ctx->config.oper_mode = hash_alg->conf.oper_mode;
+
+ ctx->digestsize = hash_alg->hash.halg.digestsize;
+
+ return 0;
+}
+
+static struct hash_algo_template hash_algs[] = {
+ {
+ .conf.algorithm = HASH_ALGO_SHA1,
+ .conf.oper_mode = HASH_OPER_MODE_HASH,
+ .hash = {
+ .init = hash_init,
+ .update = ahash_update,
+ .final = ahash_final,
+ .digest = ahash_sha1_digest,
+ .halg.digestsize = SHA1_DIGEST_SIZE,
+ .halg.statesize = sizeof(struct hash_ctx),
+ .halg.base = {
+ .cra_name = "sha1",
+ .cra_driver_name = "sha1-ux500",
+ .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct hash_ctx),
+ .cra_init = hash_cra_init,
+ .cra_module = THIS_MODULE,
+ }
+ }
+ },
+ {
+ .conf.algorithm = HASH_ALGO_SHA256,
+ .conf.oper_mode = HASH_OPER_MODE_HASH,
+ .hash = {
+ .init = hash_init,
+ .update = ahash_update,
+ .final = ahash_final,
+ .digest = ahash_sha256_digest,
+ .halg.digestsize = SHA256_DIGEST_SIZE,
+ .halg.statesize = sizeof(struct hash_ctx),
+ .halg.base = {
+ .cra_name = "sha256",
+ .cra_driver_name = "sha256-ux500",
+ .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct hash_ctx),
+ .cra_type = &crypto_ahash_type,
+ .cra_init = hash_cra_init,
+ .cra_module = THIS_MODULE,
+ }
+ }
+
+ },
+ {
+ .conf.algorithm = HASH_ALGO_SHA1,
+ .conf.oper_mode = HASH_OPER_MODE_HMAC,
+ .hash = {
+ .init = hash_init,
+ .update = ahash_update,
+ .final = ahash_final,
+ .digest = hmac_sha1_digest,
+ .setkey = hmac_sha1_setkey,
+ .halg.digestsize = SHA1_DIGEST_SIZE,
+ .halg.statesize = sizeof(struct hash_ctx),
+ .halg.base = {
+ .cra_name = "hmac(sha1)",
+ .cra_driver_name = "hmac-sha1-ux500",
+ .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct hash_ctx),
+ .cra_type = &crypto_ahash_type,
+ .cra_init = hash_cra_init,
+ .cra_module = THIS_MODULE,
+ }
+ }
+ },
+ {
+ .conf.algorithm = HASH_ALGO_SHA256,
+ .conf.oper_mode = HASH_OPER_MODE_HMAC,
+ .hash = {
+ .init = hash_init,
+ .update = ahash_update,
+ .final = ahash_final,
+ .digest = hmac_sha256_digest,
+ .setkey = hmac_sha256_setkey,
+ .halg.digestsize = SHA256_DIGEST_SIZE,
+ .halg.statesize = sizeof(struct hash_ctx),
+ .halg.base = {
+ .cra_name = "hmac(sha256)",
+ .cra_driver_name = "hmac-sha256-ux500",
+ .cra_flags = CRYPTO_ALG_TYPE_AHASH |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct hash_ctx),
+ .cra_type = &crypto_ahash_type,
+ .cra_init = hash_cra_init,
+ .cra_module = THIS_MODULE,
+ }
+ }
+ }
+};
+
+/**
+ * hash_algs_register_all -
+ */
+static int ahash_algs_register_all(struct hash_device_data *device_data)
+{
+ int ret;
+ int i;
+ int count;
+
+ for (i = 0; i < ARRAY_SIZE(hash_algs); i++) {
+ ret = crypto_register_ahash(&hash_algs[i].hash);
+ if (ret) {
+ count = i;
+ dev_err(device_data->dev, "[%s] alg registration failed",
+ hash_algs[i].hash.halg.base.cra_driver_name);
+ goto unreg;
+ }
+ }
+ return 0;
+unreg:
+ for (i = 0; i < count; i++)
+ crypto_unregister_ahash(&hash_algs[i].hash);
+ return ret;
+}
+
+/**
+ * hash_algs_unregister_all -
+ */
+static void ahash_algs_unregister_all(struct hash_device_data *device_data)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hash_algs); i++)
+ crypto_unregister_ahash(&hash_algs[i].hash);
+}
+
+/**
+ * ux500_hash_probe - Function that probes the hash hardware.
+ * @pdev: The platform device.
+ */
+static int ux500_hash_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct resource *res = NULL;
+ struct hash_device_data *device_data;
+ struct device *dev = &pdev->dev;
+
+ device_data = kzalloc(sizeof(struct hash_device_data), GFP_ATOMIC);
+ if (!device_data) {
+ dev_dbg(dev, "[%s] kzalloc() failed!", __func__);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ device_data->dev = dev;
+ device_data->current_ctx = NULL;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_dbg(dev, "[%s] platform_get_resource() failed!", __func__);
+ ret = -ENODEV;
+ goto out_kfree;
+ }
+
+ res = request_mem_region(res->start, resource_size(res), pdev->name);
+ if (res == NULL) {
+ dev_dbg(dev, "[%s] request_mem_region() failed!", __func__);
+ ret = -EBUSY;
+ goto out_kfree;
+ }
+
+ device_data->base = ioremap(res->start, resource_size(res));
+ if (!device_data->base) {
+ dev_err(dev, "[%s] ioremap() failed!",
+ __func__);
+ ret = -ENOMEM;
+ goto out_free_mem;
+ }
+ spin_lock_init(&device_data->ctx_lock);
+ spin_lock_init(&device_data->power_state_lock);
+
+ /* Enable power for HASH1 hardware block */
+ device_data->regulator = regulator_get(dev, "v-ape");
+ if (IS_ERR(device_data->regulator)) {
+ dev_err(dev, "[%s] regulator_get() failed!", __func__);
+ ret = PTR_ERR(device_data->regulator);
+ device_data->regulator = NULL;
+ goto out_unmap;
+ }
+
+ /* Enable the clock for HASH1 hardware block */
+ device_data->clk = clk_get(dev, NULL);
+ if (IS_ERR(device_data->clk)) {
+ dev_err(dev, "[%s] clk_get() failed!", __func__);
+ ret = PTR_ERR(device_data->clk);
+ goto out_regulator;
+ }
+
+ /* Enable device power (and clock) */
+ ret = hash_enable_power(device_data, false);
+ if (ret) {
+ dev_err(dev, "[%s]: hash_enable_power() failed!", __func__);
+ goto out_clk;
+ }
+
+ ret = hash_check_hw(device_data);
+ if (ret) {
+ dev_err(dev, "[%s] hash_check_hw() failed!", __func__);
+ goto out_power;
+ }
+
+ if (hash_mode == HASH_MODE_DMA)
+ hash_dma_setup_channel(device_data, dev);
+
+ platform_set_drvdata(pdev, device_data);
+
+ /* Put the new device into the device list... */
+ klist_add_tail(&device_data->list_node, &driver_data.device_list);
+ /* ... and signal that a new device is available. */
+ up(&driver_data.device_allocation);
+
+ ret = ahash_algs_register_all(device_data);
+ if (ret) {
+ dev_err(dev, "[%s] ahash_algs_register_all() "
+ "failed!", __func__);
+ goto out_power;
+ }
+
+ dev_info(dev, "[%s] successfully probed\n", __func__);
+ return 0;
+
+out_power:
+ hash_disable_power(device_data, false);
+
+out_clk:
+ clk_put(device_data->clk);
+
+out_regulator:
+ regulator_put(device_data->regulator);
+
+out_unmap:
+ iounmap(device_data->base);
+
+out_free_mem:
+ release_mem_region(res->start, resource_size(res));
+
+out_kfree:
+ kfree(device_data);
+out:
+ return ret;
+}
+
+/**
+ * ux500_hash_remove - Function that removes the hash device from the platform.
+ * @pdev: The platform device.
+ */
+static int ux500_hash_remove(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct hash_device_data *device_data;
+ struct device *dev = &pdev->dev;
+
+ device_data = platform_get_drvdata(pdev);
+ if (!device_data) {
+ dev_err(dev, "[%s]: platform_get_drvdata() failed!",
+ __func__);
+ return -ENOMEM;
+ }
+
+ /* Try to decrease the number of available devices. */
+ if (down_trylock(&driver_data.device_allocation))
+ return -EBUSY;
+
+ /* Check that the device is free */
+ spin_lock(&device_data->ctx_lock);
+ /* current_ctx allocates a device, NULL = unallocated */
+ if (device_data->current_ctx) {
+ /* The device is busy */
+ spin_unlock(&device_data->ctx_lock);
+ /* Return the device to the pool. */
+ up(&driver_data.device_allocation);
+ return -EBUSY;
+ }
+
+ spin_unlock(&device_data->ctx_lock);
+
+ /* Remove the device from the list */
+ if (klist_node_attached(&device_data->list_node))
+ klist_remove(&device_data->list_node);
+
+ /* If this was the last device, remove the services */
+ if (list_empty(&driver_data.device_list.k_list))
+ ahash_algs_unregister_all(device_data);
+
+ if (hash_disable_power(device_data, false))
+ dev_err(dev, "[%s]: hash_disable_power() failed",
+ __func__);
+
+ clk_put(device_data->clk);
+ regulator_put(device_data->regulator);
+
+ iounmap(device_data->base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
+
+ kfree(device_data);
+
+ return 0;
+}
+
+/**
+ * ux500_hash_shutdown - Function that shutdown the hash device.
+ * @pdev: The platform device
+ */
+static void ux500_hash_shutdown(struct platform_device *pdev)
+{
+ struct resource *res = NULL;
+ struct hash_device_data *device_data;
+
+ device_data = platform_get_drvdata(pdev);
+ if (!device_data) {
+ dev_err(&pdev->dev, "[%s] platform_get_drvdata() failed!",
+ __func__);
+ return;
+ }
+
+ /* Check that the device is free */
+ spin_lock(&device_data->ctx_lock);
+ /* current_ctx allocates a device, NULL = unallocated */
+ if (!device_data->current_ctx) {
+ if (down_trylock(&driver_data.device_allocation))
+ dev_dbg(&pdev->dev, "[%s]: Cryp still in use!"
+ "Shutting down anyway...", __func__);
+ /**
+ * (Allocate the device)
+ * Need to set this to non-null (dummy) value,
+ * to avoid usage if context switching.
+ */
+ device_data->current_ctx++;
+ }
+ spin_unlock(&device_data->ctx_lock);
+
+ /* Remove the device from the list */
+ if (klist_node_attached(&device_data->list_node))
+ klist_remove(&device_data->list_node);
+
+ /* If this was the last device, remove the services */
+ if (list_empty(&driver_data.device_list.k_list))
+ ahash_algs_unregister_all(device_data);
+
+ iounmap(device_data->base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
+
+ if (hash_disable_power(device_data, false))
+ dev_err(&pdev->dev, "[%s] hash_disable_power() failed",
+ __func__);
+}
+
+/**
+ * ux500_hash_suspend - Function that suspends the hash device.
+ * @pdev: The platform device.
+ * @state: -
+ */
+static int ux500_hash_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ int ret;
+ struct hash_device_data *device_data;
+ struct hash_ctx *temp_ctx = NULL;
+
+ device_data = platform_get_drvdata(pdev);
+ if (!device_data) {
+ dev_err(&pdev->dev, "[%s] platform_get_drvdata() failed!",
+ __func__);
+ return -ENOMEM;
+ }
+
+ spin_lock(&device_data->ctx_lock);
+ if (!device_data->current_ctx)
+ device_data->current_ctx++;
+ spin_unlock(&device_data->ctx_lock);
+
+ if (device_data->current_ctx == ++temp_ctx) {
+ if (down_interruptible(&driver_data.device_allocation))
+ dev_dbg(&pdev->dev, "[%s]: down_interruptible() "
+ "failed", __func__);
+ ret = hash_disable_power(device_data, false);
+
+ } else
+ ret = hash_disable_power(device_data, true);
+
+ if (ret)
+ dev_err(&pdev->dev, "[%s]: hash_disable_power()", __func__);
+
+ return ret;
+}
+
+/**
+ * ux500_hash_resume - Function that resume the hash device.
+ * @pdev: The platform device.
+ */
+static int ux500_hash_resume(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct hash_device_data *device_data;
+ struct hash_ctx *temp_ctx = NULL;
+
+ device_data = platform_get_drvdata(pdev);
+ if (!device_data) {
+ dev_err(&pdev->dev, "[%s] platform_get_drvdata() failed!",
+ __func__);
+ return -ENOMEM;
+ }
+
+ spin_lock(&device_data->ctx_lock);
+ if (device_data->current_ctx == ++temp_ctx)
+ device_data->current_ctx = NULL;
+ spin_unlock(&device_data->ctx_lock);
+
+ if (!device_data->current_ctx)
+ up(&driver_data.device_allocation);
+ else
+ ret = hash_enable_power(device_data, true);
+
+ if (ret)
+ dev_err(&pdev->dev, "[%s]: hash_enable_power() failed!",
+ __func__);
+
+ return ret;
+}
+
+static struct platform_driver hash_driver = {
+ .probe = ux500_hash_probe,
+ .remove = ux500_hash_remove,
+ .shutdown = ux500_hash_shutdown,
+ .suspend = ux500_hash_suspend,
+ .resume = ux500_hash_resume,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "hash1",
+ }
+};
+
+/**
+ * ux500_hash_mod_init - The kernel module init function.
+ */
+static int __init ux500_hash_mod_init(void)
+{
+ klist_init(&driver_data.device_list, NULL, NULL);
+ /* Initialize the semaphore to 0 devices (locked state) */
+ sema_init(&driver_data.device_allocation, 0);
+
+ return platform_driver_register(&hash_driver);
+}
+
+/**
+ * ux500_hash_mod_fini - The kernel module exit function.
+ */
+static void __exit ux500_hash_mod_fini(void)
+{
+ platform_driver_unregister(&hash_driver);
+ return;
+}
+
+module_init(ux500_hash_mod_init);
+module_exit(ux500_hash_mod_fini);
+
+MODULE_DESCRIPTION("Driver for ST-Ericsson UX500 HASH engine.");
+MODULE_LICENSE("GPL");
+
+MODULE_ALIAS("sha1-all");
+MODULE_ALIAS("sha256-all");
+MODULE_ALIAS("hmac-sha1-all");
+MODULE_ALIAS("hmac-sha256-all");
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index 464fa2147dfb..f6b0a6e2ea50 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -16,7 +16,7 @@ menuconfig PM_DEVFREQ
is attached to a single device and returns a "representative"
clock frequency of the device, which is also attached
to a device by 1-to-1. The device registering devfreq takes the
- responsiblity to "interpret" the representative frequency and
+ responsibility to "interpret" the representative frequency and
to set its every clock accordingly with the "target" callback
given to devfreq.
diff --git a/drivers/devfreq/governor_performance.c b/drivers/devfreq/governor_performance.c
index 574a06b1b1de..af75ddd4f158 100644
--- a/drivers/devfreq/governor_performance.c
+++ b/drivers/devfreq/governor_performance.c
@@ -10,6 +10,7 @@
*/
#include <linux/devfreq.h>
+#include "governor.h"
static int devfreq_performance_func(struct devfreq *df,
unsigned long *freq)
@@ -25,8 +26,14 @@ static int devfreq_performance_func(struct devfreq *df,
return 0;
}
+static int performance_init(struct devfreq *devfreq)
+{
+ return update_devfreq(devfreq);
+}
+
const struct devfreq_governor devfreq_performance = {
.name = "performance",
+ .init = performance_init,
.get_target_freq = devfreq_performance_func,
.no_central_polling = true,
};
diff --git a/drivers/devfreq/governor_powersave.c b/drivers/devfreq/governor_powersave.c
index d742d4a82d6a..fec0cdbd2477 100644
--- a/drivers/devfreq/governor_powersave.c
+++ b/drivers/devfreq/governor_powersave.c
@@ -10,6 +10,7 @@
*/
#include <linux/devfreq.h>
+#include "governor.h"
static int devfreq_powersave_func(struct devfreq *df,
unsigned long *freq)
@@ -22,8 +23,14 @@ static int devfreq_powersave_func(struct devfreq *df,
return 0;
}
+static int powersave_init(struct devfreq *devfreq)
+{
+ return update_devfreq(devfreq);
+}
+
const struct devfreq_governor devfreq_powersave = {
.name = "powersave",
+ .init = powersave_init,
.get_target_freq = devfreq_powersave_func,
.no_central_polling = true,
};
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h
index e48ab3108ad8..5b739411d62f 100644
--- a/drivers/edac/edac_core.h
+++ b/drivers/edac/edac_core.h
@@ -107,13 +107,13 @@ extern int edac_debug_level;
*
* CPU caches (L1 and L2)
* DMA engines
- * Core CPU swithces
+ * Core CPU switches
* Fabric switch units
* PCIe interface controllers
* other EDAC/ECC type devices that can be monitored for
* errors, etc.
*
- * It allows for a 2 level set of hiearchry. For example:
+ * It allows for a 2 level set of hierarchy. For example:
*
* cache could be composed of L1, L2 and L3 levels of cache.
* Each CPU core would have its own L1 cache, while sharing
diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c
index 4b154593343a..45b8f4bdd773 100644
--- a/drivers/edac/edac_device.c
+++ b/drivers/edac/edac_device.c
@@ -56,7 +56,7 @@ static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev)
*
* The control structure is allocated in complete chunk
* from the OS. It is in turn sub allocated to the
- * various objects that compose the struture
+ * various objects that compose the structure
*
* The structure has a 'nr_instance' array within itself.
* Each instance represents a major component
@@ -118,7 +118,7 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
/* Calc the 'end' offset past the attributes array */
pvt = edac_align_ptr(&dev_attrib[count], sz_private);
} else {
- /* no attribute array specificed */
+ /* no attribute array specified */
pvt = edac_align_ptr(dev_attrib, sz_private);
}
@@ -394,7 +394,7 @@ static void edac_device_workq_function(struct work_struct *work_req)
/* Reschedule the workq for the next time period to start again
* if the number of msec is for 1 sec, then adjust to the next
- * whole one second to save timers fireing all over the period
+ * whole one second to save timers firing all over the period
* between integral seconds
*/
if (edac_dev->poll_msec == 1000)
@@ -563,7 +563,7 @@ EXPORT_SYMBOL_GPL(edac_device_add_device);
* Remove sysfs entries for specified edac_device structure and
* then remove edac_device structure from global list
*
- * @pdev:
+ * @dev:
* Pointer to 'struct device' representing edac_device
* structure to remove.
*
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index 85226ccf5290..7f1dfcc4e597 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
@@ -90,7 +90,7 @@ MODULE_PARM_DESC(use_pci_fixup, "Enable PCI fixup to seek for hidden devices");
#define MC_MAX_DOD 0x64
/*
- * OFFSETS for Device 3 Function 4, as inicated on Xeon 5500 datasheet:
+ * OFFSETS for Device 3 Function 4, as indicated on Xeon 5500 datasheet:
* http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf
*/
@@ -101,7 +101,7 @@ MODULE_PARM_DESC(use_pci_fixup, "Enable PCI fixup to seek for hidden devices");
#define DIMM1_COR_ERR(r) (((r) >> 16) & 0x7fff)
#define DIMM0_COR_ERR(r) ((r) & 0x7fff)
-/* OFFSETS for Device 3 Function 2, as inicated on Xeon 5500 datasheet */
+/* OFFSETS for Device 3 Function 2, as indicated on Xeon 5500 datasheet */
#define MC_SSRCONTROL 0x48
#define SSR_MODE_DISABLE 0x00
#define SSR_MODE_ENABLE 0x01
@@ -398,7 +398,7 @@ static DEFINE_PCI_DEVICE_TABLE(i7core_pci_tbl) = {
};
/****************************************************************************
- Anciliary status routines
+ Ancillary status routines
****************************************************************************/
/* MC_CONTROL bits */
@@ -1361,7 +1361,7 @@ static int i7core_get_onedevice(struct pci_dev **prev,
dev_descr->dev_id, *prev);
/*
- * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs
+ * On Xeon 55xx, the Intel QuickPath Arch Generic Non-core regs
* is at addr 8086:2c40, instead of 8086:2c41. So, we need
* to probe for the alternate address in case of failure
*/
@@ -2132,7 +2132,7 @@ static int set_sdram_scrub_rate(struct mem_ctl_info *mci, u32 new_bw)
/*
* get_sdram_scrub_rate This routine convert current scrub rate value
- * into byte/sec bandwidth accourding to
+ * into byte/sec bandwidth according to
* SCRUBINTERVAL formula found in datasheet.
*/
static int get_sdram_scrub_rate(struct mem_ctl_info *mci)
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index a203536d90dd..123204f8e23b 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -58,7 +58,7 @@ static int probed;
/*
* FIXME: For now, let's order by device function, as it makes
- * easier for driver's development proccess. This table should be
+ * easier for driver's development process. This table should be
* moved to pci_id.h when submitted upstream
*/
#define PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0 0x3cf4 /* 12.6 */
@@ -375,7 +375,7 @@ static DEFINE_PCI_DEVICE_TABLE(sbridge_pci_tbl) = {
/****************************************************************************
- Anciliary status routines
+ Ancillary status routines
****************************************************************************/
static inline int numrank(u32 mtr)
@@ -1430,7 +1430,7 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
type = "FATAL";
/*
- * According with Table 15-9 of the Intel Archictecture spec vol 3A,
+ * According with Table 15-9 of the Intel Architecture spec vol 3A,
* memory errors should fit in this mask:
* 000f 0000 1mmm cccc (binary)
* where:
diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
new file mode 100644
index 000000000000..29c5cf852efc
--- /dev/null
+++ b/drivers/extcon/Kconfig
@@ -0,0 +1,32 @@
+menuconfig EXTCON
+ tristate "External Connector Class (extcon) support"
+ help
+ Say Y here to enable external connector class (extcon) support.
+ This allows monitoring external connectors by userspace
+ via sysfs and uevent and supports external connectors with
+ multiple states; i.e., an extcon that may have multiple
+ cables attached. For example, an external connector of a device
+ may be used to connect an HDMI cable and a AC adaptor, and to
+ host USB ports. Many of 30-pin connectors including PDMI are
+ also good examples.
+
+if EXTCON
+
+comment "Extcon Device Drivers"
+
+config EXTCON_GPIO
+ tristate "GPIO extcon support"
+ depends on GENERIC_GPIO
+ help
+ Say Y here to enable GPIO based extcon support. Note that GPIO
+ extcon supports single state per extcon instance.
+
+config EXTCON_MAX8997
+ tristate "MAX8997 EXTCON Support"
+ depends on MFD_MAX8997
+ help
+ If you say yes here you get support for the MUIC device of
+ Maxim MAX8997 PMIC. The MAX8997 MUIC is a USB port accessory
+ detector and switch.
+
+endif # MULTISTATE_SWITCH
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
new file mode 100644
index 000000000000..86020bdb6da0
--- /dev/null
+++ b/drivers/extcon/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for external connector class (extcon) devices
+#
+
+obj-$(CONFIG_EXTCON) += extcon_class.o
+obj-$(CONFIG_EXTCON_GPIO) += extcon_gpio.o
+obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o
diff --git a/drivers/misc/max8997-muic.c b/drivers/extcon/extcon-max8997.c
index 19591eaa492a..23416e443765 100644
--- a/drivers/misc/max8997-muic.c
+++ b/drivers/extcon/extcon-max8997.c
@@ -1,7 +1,7 @@
/*
- * max8997-muic.c - MAX8997 muic driver for the Maxim 8997
+ * extcon-max8997.c - MAX8997 extcon driver to support MAX8997 MUIC
*
- * Copyright (C) 2011 Samsung Electrnoics
+ * Copyright (C) 2012 Samsung Electrnoics
* Donggeun Kim <dg77.kim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -13,11 +13,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
#include <linux/kernel.h>
@@ -30,6 +25,9 @@
#include <linux/kobject.h>
#include <linux/mfd/max8997.h>
#include <linux/mfd/max8997-private.h>
+#include <linux/extcon.h>
+
+#define DEV_NAME "max8997-muic"
/* MAX8997-MUIC STATUS1 register */
#define STATUS1_ADC_SHIFT 0
@@ -95,7 +93,6 @@ static struct max8997_muic_irq muic_irqs[] = {
struct max8997_muic_info {
struct device *dev;
- struct max8997_dev *iodev;
struct i2c_client *muic;
struct max8997_muic_platform_data *muic_pdata;
@@ -106,12 +103,28 @@ struct max8997_muic_info {
int pre_adc;
struct mutex mutex;
+
+ struct extcon_dev *edev;
+};
+
+const char *max8997_extcon_cable[] = {
+ [0] = "USB",
+ [1] = "USB-Host",
+ [2] = "TA",
+ [3] = "Fast-charger",
+ [4] = "Slow-charger",
+ [5] = "Charge-downstream",
+ [6] = "MHL",
+ [7] = "Dock-desk",
+ [7] = "Dock-card",
+ [8] = "JIG",
+
+ NULL,
};
static int max8997_muic_handle_usb(struct max8997_muic_info *info,
enum max8997_muic_usb_type usb_type, bool attached)
{
- struct max8997_muic_platform_data *mdata = info->muic_pdata;
int ret = 0;
if (usb_type == MAX8997_USB_HOST) {
@@ -125,25 +138,25 @@ static int max8997_muic_handle_usb(struct max8997_muic_info *info,
}
}
- if (mdata->usb_callback)
- mdata->usb_callback(usb_type, attached);
+ switch (usb_type) {
+ case MAX8997_USB_HOST:
+ extcon_set_cable_state(info->edev, "USB-Host", attached);
+ break;
+ case MAX8997_USB_DEVICE:
+ extcon_set_cable_state(info->edev, "USB", attached);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
out:
return ret;
}
-static void max8997_muic_handle_mhl(struct max8997_muic_info *info,
- bool attached)
-{
- struct max8997_muic_platform_data *mdata = info->muic_pdata;
-
- if (mdata->mhl_callback)
- mdata->mhl_callback(attached);
-}
-
static int max8997_muic_handle_dock(struct max8997_muic_info *info,
int adc, bool attached)
{
- struct max8997_muic_platform_data *mdata = info->muic_pdata;
int ret = 0;
/* switch to AUDIO */
@@ -157,14 +170,13 @@ static int max8997_muic_handle_dock(struct max8997_muic_info *info,
switch (adc) {
case MAX8997_ADC_DESKDOCK:
- if (mdata->deskdock_callback)
- mdata->deskdock_callback(attached);
+ extcon_set_cable_state(info->edev, "Dock-desk", attached);
break;
case MAX8997_ADC_CARDOCK:
- if (mdata->cardock_callback)
- mdata->cardock_callback(attached);
+ extcon_set_cable_state(info->edev, "Dock-card", attached);
break;
default:
+ ret = -EINVAL;
break;
}
out:
@@ -174,7 +186,6 @@ out:
static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info,
bool attached)
{
- struct max8997_muic_platform_data *mdata = info->muic_pdata;
int ret = 0;
/* switch to UART */
@@ -186,8 +197,7 @@ static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info,
goto out;
}
- if (mdata->uart_callback)
- mdata->uart_callback(attached);
+ extcon_set_cable_state(info->edev, "JIG", attached);
out:
return ret;
}
@@ -201,7 +211,7 @@ static int max8997_muic_handle_adc_detach(struct max8997_muic_info *info)
ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, false);
break;
case MAX8997_ADC_MHL:
- max8997_muic_handle_mhl(info, false);
+ extcon_set_cable_state(info->edev, "MHL", false);
break;
case MAX8997_ADC_JIG_USB_1:
case MAX8997_ADC_JIG_USB_2:
@@ -230,7 +240,7 @@ static int max8997_muic_handle_adc(struct max8997_muic_info *info, int adc)
ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, true);
break;
case MAX8997_ADC_MHL:
- max8997_muic_handle_mhl(info, true);
+ extcon_set_cable_state(info->edev, "MHL", true);
break;
case MAX8997_ADC_JIG_USB_1:
case MAX8997_ADC_JIG_USB_2:
@@ -247,10 +257,40 @@ static int max8997_muic_handle_adc(struct max8997_muic_info *info, int adc)
ret = max8997_muic_handle_adc_detach(info);
break;
default:
- break;
+ ret = -EINVAL;
+ goto out;
}
info->pre_adc = adc;
+out:
+ return ret;
+}
+
+static int max8997_muic_handle_charger_type_detach(
+ struct max8997_muic_info *info)
+{
+ int ret = 0;
+
+ switch (info->pre_charger_type) {
+ case MAX8997_CHARGER_TYPE_USB:
+ extcon_set_cable_state(info->edev, "USB", false);
+ break;
+ case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT:
+ extcon_set_cable_state(info->edev, "Charge-downstream", false);
+ break;
+ case MAX8997_CHARGER_TYPE_DEDICATED_CHG:
+ extcon_set_cable_state(info->edev, "TA", false);
+ break;
+ case MAX8997_CHARGER_TYPE_500MA:
+ extcon_set_cable_state(info->edev, "Slow-charger", false);
+ break;
+ case MAX8997_CHARGER_TYPE_1A:
+ extcon_set_cable_state(info->edev, "Fast-charger", false);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
return ret;
}
@@ -258,7 +298,6 @@ static int max8997_muic_handle_adc(struct max8997_muic_info *info, int adc)
static int max8997_muic_handle_charger_type(struct max8997_muic_info *info,
enum max8997_muic_charger_type charger_type)
{
- struct max8997_muic_platform_data *mdata = info->muic_pdata;
u8 adc;
int ret;
@@ -270,30 +309,29 @@ static int max8997_muic_handle_charger_type(struct max8997_muic_info *info,
switch (charger_type) {
case MAX8997_CHARGER_TYPE_NONE:
- if (mdata->charger_callback)
- mdata->charger_callback(false, charger_type);
- if (info->pre_charger_type == MAX8997_CHARGER_TYPE_USB) {
- max8997_muic_handle_usb(info,
- MAX8997_USB_DEVICE, false);
- }
+ ret = max8997_muic_handle_charger_type_detach(info);
break;
case MAX8997_CHARGER_TYPE_USB:
if ((adc & STATUS1_ADC_MASK) == MAX8997_ADC_OPEN) {
max8997_muic_handle_usb(info,
MAX8997_USB_DEVICE, true);
}
- if (mdata->charger_callback)
- mdata->charger_callback(true, charger_type);
break;
case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT:
+ extcon_set_cable_state(info->edev, "Charge-downstream", true);
+ break;
case MAX8997_CHARGER_TYPE_DEDICATED_CHG:
+ extcon_set_cable_state(info->edev, "TA", true);
+ break;
case MAX8997_CHARGER_TYPE_500MA:
+ extcon_set_cable_state(info->edev, "Slow-charger", true);
+ break;
case MAX8997_CHARGER_TYPE_1A:
- if (mdata->charger_callback)
- mdata->charger_callback(true, charger_type);
+ extcon_set_cable_state(info->edev, "Fast-charger", true);
break;
default:
- break;
+ ret = -EINVAL;
+ goto out;
}
info->pre_charger_type = charger_type;
@@ -305,18 +343,17 @@ static void max8997_muic_irq_work(struct work_struct *work)
{
struct max8997_muic_info *info = container_of(work,
struct max8997_muic_info, irq_work);
- struct max8997_platform_data *pdata =
- dev_get_platdata(info->iodev->dev);
- u8 status[3];
+ struct max8997_dev *max8997 = i2c_get_clientdata(info->muic);
+ u8 status[2];
u8 adc, chg_type;
- int irq_type = info->irq - pdata->irq_base;
+ int irq_type = info->irq - max8997->irq_base;
int ret;
mutex_lock(&info->mutex);
ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1,
- 3, status);
+ 2, status);
if (ret) {
dev_err(info->dev, "failed to read muic register\n");
mutex_unlock(&info->mutex);
@@ -340,8 +377,8 @@ static void max8997_muic_irq_work(struct work_struct *work)
max8997_muic_handle_charger_type(info, chg_type);
break;
default:
- dev_info(info->dev, "misc interrupt: %s occurred\n",
- muic_irqs[irq_type].name);
+ dev_info(info->dev, "misc interrupt: irq %d occurred\n",
+ irq_type);
break;
}
@@ -387,21 +424,10 @@ static void max8997_muic_detect_dev(struct max8997_muic_info *info)
max8997_muic_handle_charger_type(info, chg_type);
}
-static void max8997_initialize_device(struct max8997_muic_info *info)
-{
- struct max8997_muic_platform_data *mdata = info->muic_pdata;
- int i;
-
- for (i = 0; i < mdata->num_init_data; i++) {
- max8997_write_reg(info->muic, mdata->init_data[i].addr,
- mdata->init_data[i].data);
- }
-}
-
static int __devinit max8997_muic_probe(struct platform_device *pdev)
{
- struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
- struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev);
+ struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent);
+ struct max8997_platform_data *pdata = dev_get_platdata(max8997->dev);
struct max8997_muic_info *info;
int ret, i;
@@ -412,16 +438,8 @@ static int __devinit max8997_muic_probe(struct platform_device *pdev)
goto err_kfree;
}
- if (!pdata->muic_pdata) {
- dev_err(&pdev->dev, "failed to get platform_data\n");
- ret = -EINVAL;
- goto err_pdata;
- }
- info->muic_pdata = pdata->muic_pdata;
-
info->dev = &pdev->dev;
- info->iodev = iodev;
- info->muic = iodev->muic;
+ info->muic = max8997->muic;
platform_set_drvdata(pdev, info);
mutex_init(&info->mutex);
@@ -440,24 +458,45 @@ static int __devinit max8997_muic_probe(struct platform_device *pdev)
"failed: irq request (IRQ: %d,"
" error :%d)\n",
muic_irq->irq, ret);
-
- for (i = i - 1; i >= 0; i--)
- free_irq(muic_irq->irq, info);
-
goto err_irq;
}
}
+ /* External connector */
+ info->edev = kzalloc(sizeof(struct extcon_dev), GFP_KERNEL);
+ if (!info->edev) {
+ dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
+ ret = -ENOMEM;
+ goto err_irq;
+ }
+ info->edev->name = DEV_NAME;
+ info->edev->supported_cable = max8997_extcon_cable;
+ ret = extcon_dev_register(info->edev, NULL);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register extcon device\n");
+ goto err_extcon;
+ }
+
/* Initialize registers according to platform data */
- max8997_initialize_device(info);
+ if (pdata->muic_pdata) {
+ struct max8997_muic_platform_data *mdata = info->muic_pdata;
+
+ for (i = 0; i < mdata->num_init_data; i++) {
+ max8997_write_reg(info->muic, mdata->init_data[i].addr,
+ mdata->init_data[i].data);
+ }
+ }
/* Initial device detection */
max8997_muic_detect_dev(info);
return ret;
+err_extcon:
+ kfree(info->edev);
err_irq:
-err_pdata:
+ while (--i >= 0)
+ free_irq(pdata->irq_base + muic_irqs[i].irq, info);
kfree(info);
err_kfree:
return ret;
@@ -466,14 +505,15 @@ err_kfree:
static int __devexit max8997_muic_remove(struct platform_device *pdev)
{
struct max8997_muic_info *info = platform_get_drvdata(pdev);
- struct max8997_platform_data *pdata =
- dev_get_platdata(info->iodev->dev);
+ struct max8997_dev *max8997 = i2c_get_clientdata(info->muic);
int i;
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
- free_irq(pdata->irq_base + muic_irqs[i].irq, info);
+ free_irq(max8997->irq_base + muic_irqs[i].irq, info);
cancel_work_sync(&info->irq_work);
+ extcon_dev_unregister(info->edev);
+
kfree(info);
return 0;
@@ -481,7 +521,7 @@ static int __devexit max8997_muic_remove(struct platform_device *pdev)
static struct platform_driver max8997_muic_driver = {
.driver = {
- .name = "max8997-muic",
+ .name = DEV_NAME,
.owner = THIS_MODULE,
},
.probe = max8997_muic_probe,
@@ -490,6 +530,6 @@ static struct platform_driver max8997_muic_driver = {
module_platform_driver(max8997_muic_driver);
-MODULE_DESCRIPTION("Maxim MAX8997 MUIC driver");
+MODULE_DESCRIPTION("Maxim MAX8997 Extcon driver");
MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
MODULE_LICENSE("GPL");
diff --git a/drivers/extcon/extcon_class.c b/drivers/extcon/extcon_class.c
new file mode 100644
index 000000000000..f598a700ec15
--- /dev/null
+++ b/drivers/extcon/extcon_class.c
@@ -0,0 +1,832 @@
+/*
+ * drivers/extcon/extcon_class.c
+ *
+ * External connector (extcon) class driver
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Author: Donggeun Kim <dg77.kim@samsung.com>
+ * Author: MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * based on android/drivers/switch/switch_class.c
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+*/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <linux/extcon.h>
+#include <linux/slab.h>
+
+/*
+ * extcon_cable_name suggests the standard cable names for commonly used
+ * cable types.
+ *
+ * However, please do not use extcon_cable_name directly for extcon_dev
+ * struct's supported_cable pointer unless your device really supports
+ * every single port-type of the following cable names. Please choose cable
+ * names that are actually used in your extcon device.
+ */
+const char *extcon_cable_name[] = {
+ [EXTCON_USB] = "USB",
+ [EXTCON_USB_HOST] = "USB-Host",
+ [EXTCON_TA] = "TA",
+ [EXTCON_FAST_CHARGER] = "Fast-charger",
+ [EXTCON_SLOW_CHARGER] = "Slow-charger",
+ [EXTCON_CHARGE_DOWNSTREAM] = "Charge-downstream",
+ [EXTCON_HDMI] = "HDMI",
+ [EXTCON_MHL] = "MHL",
+ [EXTCON_DVI] = "DVI",
+ [EXTCON_VGA] = "VGA",
+ [EXTCON_DOCK] = "Dock",
+ [EXTCON_LINE_IN] = "Line-in",
+ [EXTCON_LINE_OUT] = "Line-out",
+ [EXTCON_MIC_IN] = "Microphone",
+ [EXTCON_HEADPHONE_OUT] = "Headphone",
+ [EXTCON_SPDIF_IN] = "SPDIF-in",
+ [EXTCON_SPDIF_OUT] = "SPDIF-out",
+ [EXTCON_VIDEO_IN] = "Video-in",
+ [EXTCON_VIDEO_OUT] = "Video-out",
+ [EXTCON_MECHANICAL] = "Mechanical",
+
+ NULL,
+};
+
+struct class *extcon_class;
+#if defined(CONFIG_ANDROID)
+static struct class_compat *switch_class;
+#endif /* CONFIG_ANDROID */
+
+static LIST_HEAD(extcon_dev_list);
+static DEFINE_MUTEX(extcon_dev_list_lock);
+
+/**
+ * check_mutually_exclusive - Check if new_state violates mutually_exclusive
+ * condition.
+ * @edev: the extcon device
+ * @new_state: new cable attach status for @edev
+ *
+ * Returns 0 if nothing violates. Returns the index + 1 for the first
+ * violated condition.
+ */
+static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state)
+{
+ int i = 0;
+
+ if (!edev->mutually_exclusive)
+ return 0;
+
+ for (i = 0; edev->mutually_exclusive[i]; i++) {
+ int count = 0, j;
+ u32 correspondants = new_state & edev->mutually_exclusive[i];
+ u32 exp = 1;
+
+ for (j = 0; j < 32; j++) {
+ if (exp & correspondants)
+ count++;
+ if (count > 1)
+ return i + 1;
+ exp <<= 1;
+ }
+ }
+
+ return 0;
+}
+
+static ssize_t state_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int i, count = 0;
+ struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
+
+ if (edev->print_state) {
+ int ret = edev->print_state(edev, buf);
+
+ if (ret >= 0)
+ return ret;
+ /* Use default if failed */
+ }
+
+ if (edev->max_supported == 0)
+ return sprintf(buf, "%u\n", edev->state);
+
+ for (i = 0; i < SUPPORTED_CABLE_MAX; i++) {
+ if (!edev->supported_cable[i])
+ break;
+ count += sprintf(buf + count, "%s=%d\n",
+ edev->supported_cable[i],
+ !!(edev->state & (1 << i)));
+ }
+
+ return count;
+}
+
+int extcon_set_state(struct extcon_dev *edev, u32 state);
+static ssize_t state_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ u32 state;
+ ssize_t ret = 0;
+ struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
+
+ ret = sscanf(buf, "0x%x", &state);
+ if (ret == 0)
+ ret = -EINVAL;
+ else
+ ret = extcon_set_state(edev, state);
+
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static ssize_t name_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
+
+ /* Optional callback given by the user */
+ if (edev->print_name) {
+ int ret = edev->print_name(edev, buf);
+ if (ret >= 0)
+ return ret;
+ }
+
+ return sprintf(buf, "%s\n", dev_name(edev->dev));
+}
+
+static ssize_t cable_name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct extcon_cable *cable = container_of(attr, struct extcon_cable,
+ attr_name);
+
+ return sprintf(buf, "%s\n",
+ cable->edev->supported_cable[cable->cable_index]);
+}
+
+static ssize_t cable_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct extcon_cable *cable = container_of(attr, struct extcon_cable,
+ attr_state);
+
+ return sprintf(buf, "%d\n",
+ extcon_get_cable_state_(cable->edev,
+ cable->cable_index));
+}
+
+static ssize_t cable_state_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct extcon_cable *cable = container_of(attr, struct extcon_cable,
+ attr_state);
+ int ret, state;
+
+ ret = sscanf(buf, "%d", &state);
+ if (ret == 0)
+ ret = -EINVAL;
+ else
+ ret = extcon_set_cable_state_(cable->edev, cable->cable_index,
+ state);
+
+ if (ret < 0)
+ return ret;
+ return count;
+}
+
+/**
+ * extcon_update_state() - Update the cable attach states of the extcon device
+ * only for the masked bits.
+ * @edev: the extcon device
+ * @mask: the bit mask to designate updated bits.
+ * @state: new cable attach status for @edev
+ *
+ * Changing the state sends uevent with environment variable containing
+ * the name of extcon device (envp[0]) and the state output (envp[1]).
+ * Tizen uses this format for extcon device to get events from ports.
+ * Android uses this format as well.
+ *
+ * Note that the notifier provides which bits are changed in the state
+ * variable with the val parameter (second) to the callback.
+ */
+int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state)
+{
+ char name_buf[120];
+ char state_buf[120];
+ char *prop_buf;
+ char *envp[3];
+ int env_offset = 0;
+ int length;
+ unsigned long flags;
+
+ spin_lock_irqsave(&edev->lock, flags);
+
+ if (edev->state != ((edev->state & ~mask) | (state & mask))) {
+ u32 old_state = edev->state;
+
+ if (check_mutually_exclusive(edev, (edev->state & ~mask) |
+ (state & mask))) {
+ spin_unlock_irqrestore(&edev->lock, flags);
+ return -EPERM;
+ }
+
+ edev->state &= ~mask;
+ edev->state |= state & mask;
+
+ raw_notifier_call_chain(&edev->nh, old_state, edev);
+
+ /* This could be in interrupt handler */
+ prop_buf = (char *)get_zeroed_page(GFP_ATOMIC);
+ if (prop_buf) {
+ length = name_show(edev->dev, NULL, prop_buf);
+ if (length > 0) {
+ if (prop_buf[length - 1] == '\n')
+ prop_buf[length - 1] = 0;
+ snprintf(name_buf, sizeof(name_buf),
+ "NAME=%s", prop_buf);
+ envp[env_offset++] = name_buf;
+ }
+ length = state_show(edev->dev, NULL, prop_buf);
+ if (length > 0) {
+ if (prop_buf[length - 1] == '\n')
+ prop_buf[length - 1] = 0;
+ snprintf(state_buf, sizeof(state_buf),
+ "STATE=%s", prop_buf);
+ envp[env_offset++] = state_buf;
+ }
+ envp[env_offset] = NULL;
+ /* Unlock early before uevent */
+ spin_unlock_irqrestore(&edev->lock, flags);
+
+ kobject_uevent_env(&edev->dev->kobj, KOBJ_CHANGE, envp);
+ free_page((unsigned long)prop_buf);
+ } else {
+ /* Unlock early before uevent */
+ spin_unlock_irqrestore(&edev->lock, flags);
+
+ dev_err(edev->dev, "out of memory in extcon_set_state\n");
+ kobject_uevent(&edev->dev->kobj, KOBJ_CHANGE);
+ }
+ } else {
+ /* No changes */
+ spin_unlock_irqrestore(&edev->lock, flags);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(extcon_update_state);
+
+/**
+ * extcon_set_state() - Set the cable attach states of the extcon device.
+ * @edev: the extcon device
+ * @state: new cable attach status for @edev
+ *
+ * Note that notifier provides which bits are changed in the state
+ * variable with the val parameter (second) to the callback.
+ */
+int extcon_set_state(struct extcon_dev *edev, u32 state)
+{
+ return extcon_update_state(edev, 0xffffffff, state);
+}
+EXPORT_SYMBOL_GPL(extcon_set_state);
+
+/**
+ * extcon_find_cable_index() - Get the cable index based on the cable name.
+ * @edev: the extcon device that has the cable.
+ * @cable_name: cable name to be searched.
+ *
+ * Note that accessing a cable state based on cable_index is faster than
+ * cable_name because using cable_name induces a loop with strncmp().
+ * Thus, when get/set_cable_state is repeatedly used, using cable_index
+ * is recommended.
+ */
+int extcon_find_cable_index(struct extcon_dev *edev, const char *cable_name)
+{
+ int i;
+
+ if (edev->supported_cable) {
+ for (i = 0; edev->supported_cable[i]; i++) {
+ if (!strncmp(edev->supported_cable[i],
+ cable_name, CABLE_NAME_MAX))
+ return i;
+ }
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(extcon_find_cable_index);
+
+/**
+ * extcon_get_cable_state_() - Get the status of a specific cable.
+ * @edev: the extcon device that has the cable.
+ * @index: cable index that can be retrieved by extcon_find_cable_index().
+ */
+int extcon_get_cable_state_(struct extcon_dev *edev, int index)
+{
+ if (index < 0 || (edev->max_supported && edev->max_supported <= index))
+ return -EINVAL;
+
+ return !!(edev->state & (1 << index));
+}
+EXPORT_SYMBOL_GPL(extcon_get_cable_state_);
+
+/**
+ * extcon_get_cable_state() - Get the status of a specific cable.
+ * @edev: the extcon device that has the cable.
+ * @cable_name: cable name.
+ *
+ * Note that this is slower than extcon_get_cable_state_.
+ */
+int extcon_get_cable_state(struct extcon_dev *edev, const char *cable_name)
+{
+ return extcon_get_cable_state_(edev, extcon_find_cable_index
+ (edev, cable_name));
+}
+EXPORT_SYMBOL_GPL(extcon_get_cable_state);
+
+/**
+ * extcon_get_cable_state_() - Set the status of a specific cable.
+ * @edev: the extcon device that has the cable.
+ * @index: cable index that can be retrieved by extcon_find_cable_index().
+ * @cable_state: the new cable status. The default semantics is
+ * true: attached / false: detached.
+ */
+int extcon_set_cable_state_(struct extcon_dev *edev,
+ int index, bool cable_state)
+{
+ u32 state;
+
+ if (index < 0 || (edev->max_supported && edev->max_supported <= index))
+ return -EINVAL;
+
+ state = cable_state ? (1 << index) : 0;
+ return extcon_update_state(edev, 1 << index, state);
+}
+EXPORT_SYMBOL_GPL(extcon_set_cable_state_);
+
+/**
+ * extcon_get_cable_state() - Set the status of a specific cable.
+ * @edev: the extcon device that has the cable.
+ * @cable_name: cable name.
+ * @cable_state: the new cable status. The default semantics is
+ * true: attached / false: detached.
+ *
+ * Note that this is slower than extcon_set_cable_state_.
+ */
+int extcon_set_cable_state(struct extcon_dev *edev,
+ const char *cable_name, bool cable_state)
+{
+ return extcon_set_cable_state_(edev, extcon_find_cable_index
+ (edev, cable_name), cable_state);
+}
+EXPORT_SYMBOL_GPL(extcon_set_cable_state);
+
+/**
+ * extcon_get_extcon_dev() - Get the extcon device instance from the name
+ * @extcon_name: The extcon name provided with extcon_dev_register()
+ */
+struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
+{
+ struct extcon_dev *sd;
+
+ mutex_lock(&extcon_dev_list_lock);
+ list_for_each_entry(sd, &extcon_dev_list, entry) {
+ if (!strcmp(sd->name, extcon_name))
+ goto out;
+ }
+ sd = NULL;
+out:
+ mutex_unlock(&extcon_dev_list_lock);
+ return sd;
+}
+EXPORT_SYMBOL_GPL(extcon_get_extcon_dev);
+
+static int _call_per_cable(struct notifier_block *nb, unsigned long val,
+ void *ptr)
+{
+ struct extcon_specific_cable_nb *obj = container_of(nb,
+ struct extcon_specific_cable_nb, internal_nb);
+ struct extcon_dev *edev = ptr;
+
+ if ((val & (1 << obj->cable_index)) !=
+ (edev->state & (1 << obj->cable_index))) {
+ bool cable_state = true;
+
+ obj->previous_value = val;
+
+ if (val & (1 << obj->cable_index))
+ cable_state = false;
+
+ return obj->user_nb->notifier_call(obj->user_nb,
+ cable_state, ptr);
+ }
+
+ return NOTIFY_OK;
+}
+
+/**
+ * extcon_register_interest() - Register a notifier for a state change of a
+ * specific cable, not a entier set of cables of a
+ * extcon device.
+ * @obj: an empty extcon_specific_cable_nb object to be returned.
+ * @extcon_name: the name of extcon device.
+ * @cable_name: the target cable name.
+ * @nb: the notifier block to get notified.
+ *
+ * Provide an empty extcon_specific_cable_nb. extcon_register_interest() sets
+ * the struct for you.
+ *
+ * extcon_register_interest is a helper function for those who want to get
+ * notification for a single specific cable's status change. If a user wants
+ * to get notification for any changes of all cables of a extcon device,
+ * he/she should use the general extcon_register_notifier().
+ *
+ * Note that the second parameter given to the callback of nb (val) is
+ * "old_state", not the current state. The current state can be retrieved
+ * by looking at the third pameter (edev pointer)'s state value.
+ */
+int extcon_register_interest(struct extcon_specific_cable_nb *obj,
+ const char *extcon_name, const char *cable_name,
+ struct notifier_block *nb)
+{
+ if (!obj || !extcon_name || !cable_name || !nb)
+ return -EINVAL;
+
+ obj->edev = extcon_get_extcon_dev(extcon_name);
+ if (!obj->edev)
+ return -ENODEV;
+
+ obj->cable_index = extcon_find_cable_index(obj->edev, cable_name);
+ if (obj->cable_index < 0)
+ return -ENODEV;
+
+ obj->user_nb = nb;
+
+ obj->internal_nb.notifier_call = _call_per_cable;
+
+ return raw_notifier_chain_register(&obj->edev->nh, &obj->internal_nb);
+}
+
+/**
+ * extcon_unregister_interest() - Unregister the notifier registered by
+ * extcon_register_interest().
+ * @obj: the extcon_specific_cable_nb object returned by
+ * extcon_register_interest().
+ */
+int extcon_unregister_interest(struct extcon_specific_cable_nb *obj)
+{
+ if (!obj)
+ return -EINVAL;
+
+ return raw_notifier_chain_unregister(&obj->edev->nh, &obj->internal_nb);
+}
+
+/**
+ * extcon_register_notifier() - Register a notifee to get notified by
+ * any attach status changes from the extcon.
+ * @edev: the extcon device.
+ * @nb: a notifier block to be registered.
+ *
+ * Note that the second parameter given to the callback of nb (val) is
+ * "old_state", not the current state. The current state can be retrieved
+ * by looking at the third pameter (edev pointer)'s state value.
+ */
+int extcon_register_notifier(struct extcon_dev *edev,
+ struct notifier_block *nb)
+{
+ return raw_notifier_chain_register(&edev->nh, nb);
+}
+EXPORT_SYMBOL_GPL(extcon_register_notifier);
+
+/**
+ * extcon_unregister_notifier() - Unregister a notifee from the extcon device.
+ * @edev: the extcon device.
+ * @nb: a registered notifier block to be unregistered.
+ */
+int extcon_unregister_notifier(struct extcon_dev *edev,
+ struct notifier_block *nb)
+{
+ return raw_notifier_chain_unregister(&edev->nh, nb);
+}
+EXPORT_SYMBOL_GPL(extcon_unregister_notifier);
+
+static struct device_attribute extcon_attrs[] = {
+ __ATTR(state, S_IRUGO | S_IWUSR, state_show, state_store),
+ __ATTR_RO(name),
+ __ATTR_NULL,
+};
+
+static int create_extcon_class(void)
+{
+ if (!extcon_class) {
+ extcon_class = class_create(THIS_MODULE, "extcon");
+ if (IS_ERR(extcon_class))
+ return PTR_ERR(extcon_class);
+ extcon_class->dev_attrs = extcon_attrs;
+
+#if defined(CONFIG_ANDROID)
+ switch_class = class_compat_register("switch");
+ if (WARN(!switch_class, "cannot allocate"))
+ return -ENOMEM;
+#endif /* CONFIG_ANDROID */
+ }
+
+ return 0;
+}
+
+static void extcon_cleanup(struct extcon_dev *edev, bool skip)
+{
+ mutex_lock(&extcon_dev_list_lock);
+ list_del(&edev->entry);
+ mutex_unlock(&extcon_dev_list_lock);
+
+ if (!skip && get_device(edev->dev)) {
+ int index;
+
+ if (edev->mutually_exclusive && edev->max_supported) {
+ for (index = 0; edev->mutually_exclusive[index];
+ index++)
+ kfree(edev->d_attrs_muex[index].attr.name);
+ kfree(edev->d_attrs_muex);
+ kfree(edev->attrs_muex);
+ }
+
+ for (index = 0; index < edev->max_supported; index++)
+ kfree(edev->cables[index].attr_g.name);
+
+ if (edev->max_supported) {
+ kfree(edev->extcon_dev_type.groups);
+ kfree(edev->cables);
+ }
+
+ device_unregister(edev->dev);
+ put_device(edev->dev);
+ }
+
+ kfree(edev->dev);
+}
+
+static void extcon_dev_release(struct device *dev)
+{
+ struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev);
+
+ extcon_cleanup(edev, true);
+}
+
+static const char *muex_name = "mutually_exclusive";
+static void dummy_sysfs_dev_release(struct device *dev)
+{
+}
+
+/**
+ * extcon_dev_register() - Register a new extcon device
+ * @edev : the new extcon device (should be allocated before calling)
+ * @dev : the parent device for this extcon device.
+ *
+ * Among the members of edev struct, please set the "user initializing data"
+ * in any case and set the "optional callbacks" if required. However, please
+ * do not set the values of "internal data", which are initialized by
+ * this function.
+ */
+int extcon_dev_register(struct extcon_dev *edev, struct device *dev)
+{
+ int ret, index = 0;
+
+ if (!extcon_class) {
+ ret = create_extcon_class();
+ if (ret < 0)
+ return ret;
+ }
+
+ if (edev->supported_cable) {
+ /* Get size of array */
+ for (index = 0; edev->supported_cable[index]; index++)
+ ;
+ edev->max_supported = index;
+ } else {
+ edev->max_supported = 0;
+ }
+
+ if (index > SUPPORTED_CABLE_MAX) {
+ dev_err(edev->dev, "extcon: maximum number of supported cables exceeded.\n");
+ return -EINVAL;
+ }
+
+ edev->dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+ if (!edev->dev)
+ return -ENOMEM;
+ edev->dev->parent = dev;
+ edev->dev->class = extcon_class;
+ edev->dev->release = extcon_dev_release;
+
+ dev_set_name(edev->dev, edev->name ? edev->name : dev_name(dev));
+
+ if (edev->max_supported) {
+ char buf[10];
+ char *str;
+ struct extcon_cable *cable;
+
+ edev->cables = kzalloc(sizeof(struct extcon_cable) *
+ edev->max_supported, GFP_KERNEL);
+ if (!edev->cables) {
+ ret = -ENOMEM;
+ goto err_sysfs_alloc;
+ }
+ for (index = 0; index < edev->max_supported; index++) {
+ cable = &edev->cables[index];
+
+ snprintf(buf, 10, "cable.%d", index);
+ str = kzalloc(sizeof(char) * (strlen(buf) + 1),
+ GFP_KERNEL);
+ if (!str) {
+ for (index--; index >= 0; index--) {
+ cable = &edev->cables[index];
+ kfree(cable->attr_g.name);
+ }
+ ret = -ENOMEM;
+
+ goto err_alloc_cables;
+ }
+ strcpy(str, buf);
+
+ cable->edev = edev;
+ cable->cable_index = index;
+ cable->attrs[0] = &cable->attr_name.attr;
+ cable->attrs[1] = &cable->attr_state.attr;
+ cable->attrs[2] = NULL;
+ cable->attr_g.name = str;
+ cable->attr_g.attrs = cable->attrs;
+
+ cable->attr_name.attr.name = "name";
+ cable->attr_name.attr.mode = 0444;
+ cable->attr_name.show = cable_name_show;
+
+ cable->attr_state.attr.name = "state";
+ cable->attr_state.attr.mode = 0644;
+ cable->attr_state.show = cable_state_show;
+ cable->attr_state.store = cable_state_store;
+ }
+ }
+
+ if (edev->max_supported && edev->mutually_exclusive) {
+ char buf[80];
+ char *name;
+
+ /* Count the size of mutually_exclusive array */
+ for (index = 0; edev->mutually_exclusive[index]; index++)
+ ;
+
+ edev->attrs_muex = kzalloc(sizeof(struct attribute *) *
+ (index + 1), GFP_KERNEL);
+ if (!edev->attrs_muex) {
+ ret = -ENOMEM;
+ goto err_muex;
+ }
+
+ edev->d_attrs_muex = kzalloc(sizeof(struct device_attribute) *
+ index, GFP_KERNEL);
+ if (!edev->d_attrs_muex) {
+ ret = -ENOMEM;
+ kfree(edev->attrs_muex);
+ goto err_muex;
+ }
+
+ for (index = 0; edev->mutually_exclusive[index]; index++) {
+ sprintf(buf, "0x%x", edev->mutually_exclusive[index]);
+ name = kzalloc(sizeof(char) * (strlen(buf) + 1),
+ GFP_KERNEL);
+ if (!name) {
+ for (index--; index >= 0; index--) {
+ kfree(edev->d_attrs_muex[index].attr.
+ name);
+ }
+ kfree(edev->d_attrs_muex);
+ kfree(edev->attrs_muex);
+ ret = -ENOMEM;
+ goto err_muex;
+ }
+ strcpy(name, buf);
+ edev->d_attrs_muex[index].attr.name = name;
+ edev->d_attrs_muex[index].attr.mode = 0000;
+ edev->attrs_muex[index] = &edev->d_attrs_muex[index]
+ .attr;
+ }
+ edev->attr_g_muex.name = muex_name;
+ edev->attr_g_muex.attrs = edev->attrs_muex;
+
+ }
+
+ if (edev->max_supported) {
+ edev->extcon_dev_type.groups =
+ kzalloc(sizeof(struct attribute_group *) *
+ (edev->max_supported + 2), GFP_KERNEL);
+ if (!edev->extcon_dev_type.groups) {
+ ret = -ENOMEM;
+ goto err_alloc_groups;
+ }
+
+ edev->extcon_dev_type.name = dev_name(edev->dev);
+ edev->extcon_dev_type.release = dummy_sysfs_dev_release;
+
+ for (index = 0; index < edev->max_supported; index++)
+ edev->extcon_dev_type.groups[index] =
+ &edev->cables[index].attr_g;
+ if (edev->mutually_exclusive)
+ edev->extcon_dev_type.groups[index] =
+ &edev->attr_g_muex;
+
+ edev->dev->type = &edev->extcon_dev_type;
+ }
+
+ ret = device_register(edev->dev);
+ if (ret) {
+ put_device(edev->dev);
+ goto err_dev;
+ }
+#if defined(CONFIG_ANDROID)
+ if (switch_class)
+ ret = class_compat_create_link(switch_class, edev->dev,
+ dev);
+#endif /* CONFIG_ANDROID */
+
+ spin_lock_init(&edev->lock);
+
+ RAW_INIT_NOTIFIER_HEAD(&edev->nh);
+
+ dev_set_drvdata(edev->dev, edev);
+ edev->state = 0;
+
+ mutex_lock(&extcon_dev_list_lock);
+ list_add(&edev->entry, &extcon_dev_list);
+ mutex_unlock(&extcon_dev_list_lock);
+
+ return 0;
+
+err_dev:
+ if (edev->max_supported)
+ kfree(edev->extcon_dev_type.groups);
+err_alloc_groups:
+ if (edev->max_supported && edev->mutually_exclusive) {
+ for (index = 0; edev->mutually_exclusive[index]; index++)
+ kfree(edev->d_attrs_muex[index].attr.name);
+ kfree(edev->d_attrs_muex);
+ kfree(edev->attrs_muex);
+ }
+err_muex:
+ for (index = 0; index < edev->max_supported; index++)
+ kfree(edev->cables[index].attr_g.name);
+err_alloc_cables:
+ if (edev->max_supported)
+ kfree(edev->cables);
+err_sysfs_alloc:
+ kfree(edev->dev);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(extcon_dev_register);
+
+/**
+ * extcon_dev_unregister() - Unregister the extcon device.
+ * @edev: the extcon device instance to be unregitered.
+ *
+ * Note that this does not call kfree(edev) because edev was not allocated
+ * by this class.
+ */
+void extcon_dev_unregister(struct extcon_dev *edev)
+{
+ extcon_cleanup(edev, false);
+}
+EXPORT_SYMBOL_GPL(extcon_dev_unregister);
+
+static int __init extcon_class_init(void)
+{
+ return create_extcon_class();
+}
+module_init(extcon_class_init);
+
+static void __exit extcon_class_exit(void)
+{
+ class_destroy(extcon_class);
+}
+module_exit(extcon_class_exit);
+
+MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
+MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_DESCRIPTION("External connector (extcon) class driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/extcon/extcon_gpio.c b/drivers/extcon/extcon_gpio.c
new file mode 100644
index 000000000000..fe7a07b47336
--- /dev/null
+++ b/drivers/extcon/extcon_gpio.c
@@ -0,0 +1,169 @@
+/*
+ * drivers/extcon/extcon_gpio.c
+ *
+ * Single-state GPIO extcon driver based on extcon class
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * Modified by MyungJoo Ham <myungjoo.ham@samsung.com> to support extcon
+ * (originally switch class is supported)
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/extcon.h>
+#include <linux/workqueue.h>
+#include <linux/gpio.h>
+#include <linux/extcon.h>
+#include <linux/extcon/extcon_gpio.h>
+
+struct gpio_extcon_data {
+ struct extcon_dev edev;
+ unsigned gpio;
+ const char *state_on;
+ const char *state_off;
+ int irq;
+ struct delayed_work work;
+ unsigned long debounce_jiffies;
+};
+
+static void gpio_extcon_work(struct work_struct *work)
+{
+ int state;
+ struct gpio_extcon_data *data =
+ container_of(to_delayed_work(work), struct gpio_extcon_data,
+ work);
+
+ state = gpio_get_value(data->gpio);
+ extcon_set_state(&data->edev, state);
+}
+
+static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
+{
+ struct gpio_extcon_data *extcon_data = dev_id;
+
+ schedule_delayed_work(&extcon_data->work,
+ extcon_data->debounce_jiffies);
+ return IRQ_HANDLED;
+}
+
+static ssize_t extcon_gpio_print_state(struct extcon_dev *edev, char *buf)
+{
+ struct gpio_extcon_data *extcon_data =
+ container_of(edev, struct gpio_extcon_data, edev);
+ const char *state;
+ if (extcon_get_state(edev))
+ state = extcon_data->state_on;
+ else
+ state = extcon_data->state_off;
+
+ if (state)
+ return sprintf(buf, "%s\n", state);
+ return -EINVAL;
+}
+
+static int __devinit gpio_extcon_probe(struct platform_device *pdev)
+{
+ struct gpio_extcon_platform_data *pdata = pdev->dev.platform_data;
+ struct gpio_extcon_data *extcon_data;
+ int ret = 0;
+
+ if (!pdata)
+ return -EBUSY;
+ if (!pdata->irq_flags) {
+ dev_err(&pdev->dev, "IRQ flag is not specified.\n");
+ return -EINVAL;
+ }
+
+ extcon_data = devm_kzalloc(&pdev->dev, sizeof(struct gpio_extcon_data),
+ GFP_KERNEL);
+ if (!extcon_data)
+ return -ENOMEM;
+
+ extcon_data->edev.name = pdata->name;
+ extcon_data->gpio = pdata->gpio;
+ extcon_data->state_on = pdata->state_on;
+ extcon_data->state_off = pdata->state_off;
+ if (pdata->state_on && pdata->state_off)
+ extcon_data->edev.print_state = extcon_gpio_print_state;
+ extcon_data->debounce_jiffies = msecs_to_jiffies(pdata->debounce);
+
+ ret = extcon_dev_register(&extcon_data->edev, &pdev->dev);
+ if (ret < 0)
+ goto err_extcon_dev_register;
+
+ ret = gpio_request_one(extcon_data->gpio, GPIOF_DIR_IN, pdev->name);
+ if (ret < 0)
+ goto err_request_gpio;
+
+ INIT_DELAYED_WORK(&extcon_data->work, gpio_extcon_work);
+
+ extcon_data->irq = gpio_to_irq(extcon_data->gpio);
+ if (extcon_data->irq < 0) {
+ ret = extcon_data->irq;
+ goto err_detect_irq_num_failed;
+ }
+
+ ret = request_any_context_irq(extcon_data->irq, gpio_irq_handler,
+ pdata->irq_flags, pdev->name,
+ extcon_data);
+ if (ret < 0)
+ goto err_request_irq;
+
+ /* Perform initial detection */
+ gpio_extcon_work(&extcon_data->work.work);
+
+ return 0;
+
+err_request_irq:
+err_detect_irq_num_failed:
+ gpio_free(extcon_data->gpio);
+err_request_gpio:
+ extcon_dev_unregister(&extcon_data->edev);
+err_extcon_dev_register:
+ devm_kfree(&pdev->dev, extcon_data);
+
+ return ret;
+}
+
+static int __devexit gpio_extcon_remove(struct platform_device *pdev)
+{
+ struct gpio_extcon_data *extcon_data = platform_get_drvdata(pdev);
+
+ cancel_delayed_work_sync(&extcon_data->work);
+ gpio_free(extcon_data->gpio);
+ extcon_dev_unregister(&extcon_data->edev);
+ devm_kfree(&pdev->dev, extcon_data);
+
+ return 0;
+}
+
+static struct platform_driver gpio_extcon_driver = {
+ .probe = gpio_extcon_probe,
+ .remove = __devexit_p(gpio_extcon_remove),
+ .driver = {
+ .name = "extcon-gpio",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(gpio_extcon_driver);
+
+MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
+MODULE_DESCRIPTION("GPIO extcon driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index cc595eba7ba9..57ea7f464178 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -421,8 +421,8 @@ static void bm_work(struct work_struct *work)
* root, and thus, IRM.
*/
new_root_id = local_id;
- fw_notice(card, "%s, making local node (%02x) root\n",
- "BM lock failed", new_root_id);
+ fw_notice(card, "BM lock failed (%s), making local node (%02x) root\n",
+ fw_rcode_string(rcode), new_root_id);
goto pick_me;
}
} else if (card->bm_generation != generation) {
@@ -676,6 +676,7 @@ void fw_card_release(struct kref *kref)
complete(&card->done);
}
+EXPORT_SYMBOL_GPL(fw_card_release);
void fw_core_remove_card(struct fw_card *card)
{
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index 2e6b24547e2a..2783f69dada6 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -22,6 +22,7 @@
#include <linux/compat.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/dma-mapping.h>
#include <linux/errno.h>
#include <linux/firewire.h>
#include <linux/firewire-cdev.h>
@@ -70,6 +71,7 @@ struct client {
u64 iso_closure;
struct fw_iso_buffer buffer;
unsigned long vm_start;
+ bool buffer_is_mapped;
struct list_head phy_receiver_link;
u64 phy_receiver_closure;
@@ -959,11 +961,20 @@ static void iso_mc_callback(struct fw_iso_context *context,
sizeof(e->interrupt), NULL, 0);
}
+static enum dma_data_direction iso_dma_direction(struct fw_iso_context *context)
+{
+ if (context->type == FW_ISO_CONTEXT_TRANSMIT)
+ return DMA_TO_DEVICE;
+ else
+ return DMA_FROM_DEVICE;
+}
+
static int ioctl_create_iso_context(struct client *client, union ioctl_arg *arg)
{
struct fw_cdev_create_iso_context *a = &arg->create_iso_context;
struct fw_iso_context *context;
fw_iso_callback_t cb;
+ int ret;
BUILD_BUG_ON(FW_CDEV_ISO_CONTEXT_TRANSMIT != FW_ISO_CONTEXT_TRANSMIT ||
FW_CDEV_ISO_CONTEXT_RECEIVE != FW_ISO_CONTEXT_RECEIVE ||
@@ -1004,8 +1015,21 @@ static int ioctl_create_iso_context(struct client *client, union ioctl_arg *arg)
if (client->iso_context != NULL) {
spin_unlock_irq(&client->lock);
fw_iso_context_destroy(context);
+
return -EBUSY;
}
+ if (!client->buffer_is_mapped) {
+ ret = fw_iso_buffer_map_dma(&client->buffer,
+ client->device->card,
+ iso_dma_direction(context));
+ if (ret < 0) {
+ spin_unlock_irq(&client->lock);
+ fw_iso_context_destroy(context);
+
+ return ret;
+ }
+ client->buffer_is_mapped = true;
+ }
client->iso_closure = a->closure;
client->iso_context = context;
spin_unlock_irq(&client->lock);
@@ -1651,7 +1675,6 @@ static long fw_device_op_compat_ioctl(struct file *file,
static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)
{
struct client *client = file->private_data;
- enum dma_data_direction direction;
unsigned long size;
int page_count, ret;
@@ -1674,20 +1697,28 @@ static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)
if (size & ~PAGE_MASK)
return -EINVAL;
- if (vma->vm_flags & VM_WRITE)
- direction = DMA_TO_DEVICE;
- else
- direction = DMA_FROM_DEVICE;
-
- ret = fw_iso_buffer_init(&client->buffer, client->device->card,
- page_count, direction);
+ ret = fw_iso_buffer_alloc(&client->buffer, page_count);
if (ret < 0)
return ret;
- ret = fw_iso_buffer_map(&client->buffer, vma);
+ spin_lock_irq(&client->lock);
+ if (client->iso_context) {
+ ret = fw_iso_buffer_map_dma(&client->buffer,
+ client->device->card,
+ iso_dma_direction(client->iso_context));
+ client->buffer_is_mapped = (ret == 0);
+ }
+ spin_unlock_irq(&client->lock);
if (ret < 0)
- fw_iso_buffer_destroy(&client->buffer, client->device->card);
+ goto fail;
+ ret = fw_iso_buffer_map_vma(&client->buffer, vma);
+ if (ret < 0)
+ goto fail;
+
+ return 0;
+ fail:
+ fw_iso_buffer_destroy(&client->buffer, client->device->card);
return ret;
}
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
index 68109e9bb04e..4d460ef87161 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -481,6 +481,7 @@ static int read_rom(struct fw_device *device,
* generation changes under us, read_config_rom will fail and get retried.
* It's better to start all over in this case because the node from which we
* are reading the ROM may have changed the ROM during the reset.
+ * Returns either a result code or a negative error code.
*/
static int read_config_rom(struct fw_device *device, int generation)
{
@@ -488,7 +489,7 @@ static int read_config_rom(struct fw_device *device, int generation)
const u32 *old_rom, *new_rom;
u32 *rom, *stack;
u32 sp, key;
- int i, end, length, ret = -1;
+ int i, end, length, ret;
rom = kmalloc(sizeof(*rom) * MAX_CONFIG_ROM_SIZE +
sizeof(*stack) * MAX_CONFIG_ROM_SIZE, GFP_KERNEL);
@@ -502,18 +503,21 @@ static int read_config_rom(struct fw_device *device, int generation)
/* First read the bus info block. */
for (i = 0; i < 5; i++) {
- if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE)
+ ret = read_rom(device, generation, i, &rom[i]);
+ if (ret != RCODE_COMPLETE)
goto out;
/*
- * As per IEEE1212 7.2, during power-up, devices can
+ * As per IEEE1212 7.2, during initialization, devices can
* reply with a 0 for the first quadlet of the config
* rom to indicate that they are booting (for example,
* if the firmware is on the disk of a external
* harddisk). In that case we just fail, and the
* retry mechanism will try again later.
*/
- if (i == 0 && rom[i] == 0)
+ if (i == 0 && rom[i] == 0) {
+ ret = RCODE_BUSY;
goto out;
+ }
}
device->max_speed = device->node->max_speed;
@@ -563,11 +567,14 @@ static int read_config_rom(struct fw_device *device, int generation)
*/
key = stack[--sp];
i = key & 0xffffff;
- if (WARN_ON(i >= MAX_CONFIG_ROM_SIZE))
+ if (WARN_ON(i >= MAX_CONFIG_ROM_SIZE)) {
+ ret = -ENXIO;
goto out;
+ }
/* Read header quadlet for the block to get the length. */
- if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE)
+ ret = read_rom(device, generation, i, &rom[i]);
+ if (ret != RCODE_COMPLETE)
goto out;
end = i + (rom[i] >> 16) + 1;
if (end > MAX_CONFIG_ROM_SIZE) {
@@ -590,8 +597,8 @@ static int read_config_rom(struct fw_device *device, int generation)
* it references another block, and push it in that case.
*/
for (; i < end; i++) {
- if (read_rom(device, generation, i, &rom[i]) !=
- RCODE_COMPLETE)
+ ret = read_rom(device, generation, i, &rom[i]);
+ if (ret != RCODE_COMPLETE)
goto out;
if ((key >> 30) != 3 || (rom[i] >> 30) < 2)
@@ -619,8 +626,10 @@ static int read_config_rom(struct fw_device *device, int generation)
old_rom = device->config_rom;
new_rom = kmemdup(rom, length * 4, GFP_KERNEL);
- if (new_rom == NULL)
+ if (new_rom == NULL) {
+ ret = -ENOMEM;
goto out;
+ }
down_write(&fw_device_rwsem);
device->config_rom = new_rom;
@@ -628,7 +637,7 @@ static int read_config_rom(struct fw_device *device, int generation)
up_write(&fw_device_rwsem);
kfree(old_rom);
- ret = 0;
+ ret = RCODE_COMPLETE;
device->max_rec = rom[2] >> 12 & 0xf;
device->cmc = rom[2] >> 30 & 1;
device->irmc = rom[2] >> 31 & 1;
@@ -967,15 +976,17 @@ static void fw_device_init(struct work_struct *work)
* device.
*/
- if (read_config_rom(device, device->generation) < 0) {
+ ret = read_config_rom(device, device->generation);
+ if (ret != RCODE_COMPLETE) {
if (device->config_rom_retries < MAX_RETRIES &&
atomic_read(&device->state) == FW_DEVICE_INITIALIZING) {
device->config_rom_retries++;
fw_schedule_device_work(device, RETRY_DELAY);
} else {
if (device->node->link_on)
- fw_notice(card, "giving up on Config ROM for node id %x\n",
- device->node_id);
+ fw_notice(card, "giving up on node %x: reading config rom failed: %s\n",
+ device->node_id,
+ fw_rcode_string(ret));
if (device->node == card->root_node)
fw_schedule_bm_work(card, 0);
fw_device_release(&device->device);
@@ -1069,31 +1080,30 @@ static void fw_device_init(struct work_struct *work)
put_device(&device->device); /* our reference */
}
-enum {
- REREAD_BIB_ERROR,
- REREAD_BIB_GONE,
- REREAD_BIB_UNCHANGED,
- REREAD_BIB_CHANGED,
-};
-
/* Reread and compare bus info block and header of root directory */
-static int reread_config_rom(struct fw_device *device, int generation)
+static int reread_config_rom(struct fw_device *device, int generation,
+ bool *changed)
{
u32 q;
- int i;
+ int i, rcode;
for (i = 0; i < 6; i++) {
- if (read_rom(device, generation, i, &q) != RCODE_COMPLETE)
- return REREAD_BIB_ERROR;
+ rcode = read_rom(device, generation, i, &q);
+ if (rcode != RCODE_COMPLETE)
+ return rcode;
if (i == 0 && q == 0)
- return REREAD_BIB_GONE;
+ /* inaccessible (see read_config_rom); retry later */
+ return RCODE_BUSY;
- if (q != device->config_rom[i])
- return REREAD_BIB_CHANGED;
+ if (q != device->config_rom[i]) {
+ *changed = true;
+ return RCODE_COMPLETE;
+ }
}
- return REREAD_BIB_UNCHANGED;
+ *changed = false;
+ return RCODE_COMPLETE;
}
static void fw_device_refresh(struct work_struct *work)
@@ -1101,23 +1111,14 @@ static void fw_device_refresh(struct work_struct *work)
struct fw_device *device =
container_of(work, struct fw_device, work.work);
struct fw_card *card = device->card;
- int node_id = device->node_id;
-
- switch (reread_config_rom(device, device->generation)) {
- case REREAD_BIB_ERROR:
- if (device->config_rom_retries < MAX_RETRIES / 2 &&
- atomic_read(&device->state) == FW_DEVICE_INITIALIZING) {
- device->config_rom_retries++;
- fw_schedule_device_work(device, RETRY_DELAY / 2);
-
- return;
- }
- goto give_up;
+ int ret, node_id = device->node_id;
+ bool changed;
- case REREAD_BIB_GONE:
- goto gone;
+ ret = reread_config_rom(device, device->generation, &changed);
+ if (ret != RCODE_COMPLETE)
+ goto failed_config_rom;
- case REREAD_BIB_UNCHANGED:
+ if (!changed) {
if (atomic_cmpxchg(&device->state,
FW_DEVICE_INITIALIZING,
FW_DEVICE_RUNNING) == FW_DEVICE_GONE)
@@ -1126,9 +1127,6 @@ static void fw_device_refresh(struct work_struct *work)
fw_device_update(work);
device->config_rom_retries = 0;
goto out;
-
- case REREAD_BIB_CHANGED:
- break;
}
/*
@@ -1137,16 +1135,9 @@ static void fw_device_refresh(struct work_struct *work)
*/
device_for_each_child(&device->device, NULL, shutdown_unit);
- if (read_config_rom(device, device->generation) < 0) {
- if (device->config_rom_retries < MAX_RETRIES &&
- atomic_read(&device->state) == FW_DEVICE_INITIALIZING) {
- device->config_rom_retries++;
- fw_schedule_device_work(device, RETRY_DELAY);
-
- return;
- }
- goto give_up;
- }
+ ret = read_config_rom(device, device->generation);
+ if (ret != RCODE_COMPLETE)
+ goto failed_config_rom;
fw_device_cdev_update(device);
create_units(device);
@@ -1163,9 +1154,16 @@ static void fw_device_refresh(struct work_struct *work)
device->config_rom_retries = 0;
goto out;
- give_up:
- fw_notice(card, "giving up on refresh of device %s\n",
- dev_name(&device->device));
+ failed_config_rom:
+ if (device->config_rom_retries < MAX_RETRIES &&
+ atomic_read(&device->state) == FW_DEVICE_INITIALIZING) {
+ device->config_rom_retries++;
+ fw_schedule_device_work(device, RETRY_DELAY);
+ return;
+ }
+
+ fw_notice(card, "giving up on refresh of device %s: %s\n",
+ dev_name(&device->device), fw_rcode_string(ret));
gone:
atomic_set(&device->state, FW_DEVICE_GONE);
PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c
index d1565828ae2c..8382e27e9a27 100644
--- a/drivers/firewire/core-iso.c
+++ b/drivers/firewire/core-iso.c
@@ -39,52 +39,73 @@
* Isochronous DMA context management
*/
-int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
- int page_count, enum dma_data_direction direction)
+int fw_iso_buffer_alloc(struct fw_iso_buffer *buffer, int page_count)
{
- int i, j;
- dma_addr_t address;
-
- buffer->page_count = page_count;
- buffer->direction = direction;
+ int i;
+ buffer->page_count = 0;
+ buffer->page_count_mapped = 0;
buffer->pages = kmalloc(page_count * sizeof(buffer->pages[0]),
GFP_KERNEL);
if (buffer->pages == NULL)
- goto out;
+ return -ENOMEM;
- for (i = 0; i < buffer->page_count; i++) {
+ for (i = 0; i < page_count; i++) {
buffer->pages[i] = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO);
if (buffer->pages[i] == NULL)
- goto out_pages;
+ break;
+ }
+ buffer->page_count = i;
+ if (i < page_count) {
+ fw_iso_buffer_destroy(buffer, NULL);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+int fw_iso_buffer_map_dma(struct fw_iso_buffer *buffer, struct fw_card *card,
+ enum dma_data_direction direction)
+{
+ dma_addr_t address;
+ int i;
+
+ buffer->direction = direction;
+
+ for (i = 0; i < buffer->page_count; i++) {
address = dma_map_page(card->device, buffer->pages[i],
0, PAGE_SIZE, direction);
- if (dma_mapping_error(card->device, address)) {
- __free_page(buffer->pages[i]);
- goto out_pages;
- }
+ if (dma_mapping_error(card->device, address))
+ break;
+
set_page_private(buffer->pages[i], address);
}
+ buffer->page_count_mapped = i;
+ if (i < buffer->page_count)
+ return -ENOMEM;
return 0;
+}
- out_pages:
- for (j = 0; j < i; j++) {
- address = page_private(buffer->pages[j]);
- dma_unmap_page(card->device, address,
- PAGE_SIZE, direction);
- __free_page(buffer->pages[j]);
- }
- kfree(buffer->pages);
- out:
- buffer->pages = NULL;
+int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
+ int page_count, enum dma_data_direction direction)
+{
+ int ret;
+
+ ret = fw_iso_buffer_alloc(buffer, page_count);
+ if (ret < 0)
+ return ret;
+
+ ret = fw_iso_buffer_map_dma(buffer, card, direction);
+ if (ret < 0)
+ fw_iso_buffer_destroy(buffer, card);
- return -ENOMEM;
+ return ret;
}
EXPORT_SYMBOL(fw_iso_buffer_init);
-int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma)
+int fw_iso_buffer_map_vma(struct fw_iso_buffer *buffer,
+ struct vm_area_struct *vma)
{
unsigned long uaddr;
int i, err;
@@ -107,15 +128,18 @@ void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer,
int i;
dma_addr_t address;
- for (i = 0; i < buffer->page_count; i++) {
+ for (i = 0; i < buffer->page_count_mapped; i++) {
address = page_private(buffer->pages[i]);
dma_unmap_page(card->device, address,
PAGE_SIZE, buffer->direction);
- __free_page(buffer->pages[i]);
}
+ for (i = 0; i < buffer->page_count; i++)
+ __free_page(buffer->pages[i]);
kfree(buffer->pages);
buffer->pages = NULL;
+ buffer->page_count = 0;
+ buffer->page_count_mapped = 0;
}
EXPORT_SYMBOL(fw_iso_buffer_destroy);
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index dea2dcc9310d..780708dc6e25 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -820,6 +820,15 @@ void fw_send_response(struct fw_card *card,
}
EXPORT_SYMBOL(fw_send_response);
+/**
+ * fw_get_request_speed() - returns speed at which the @request was received
+ */
+int fw_get_request_speed(struct fw_request *request)
+{
+ return request->response.speed;
+}
+EXPORT_SYMBOL(fw_get_request_speed);
+
static void handle_exclusive_region_request(struct fw_card *card,
struct fw_packet *p,
struct fw_request *request,
@@ -994,6 +1003,32 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
}
EXPORT_SYMBOL(fw_core_handle_response);
+/**
+ * fw_rcode_string - convert a firewire result code to an error description
+ * @rcode: the result code
+ */
+const char *fw_rcode_string(int rcode)
+{
+ static const char *const names[] = {
+ [RCODE_COMPLETE] = "no error",
+ [RCODE_CONFLICT_ERROR] = "conflict error",
+ [RCODE_DATA_ERROR] = "data error",
+ [RCODE_TYPE_ERROR] = "type error",
+ [RCODE_ADDRESS_ERROR] = "address error",
+ [RCODE_SEND_ERROR] = "send error",
+ [RCODE_CANCELLED] = "timeout",
+ [RCODE_BUSY] = "busy",
+ [RCODE_GENERATION] = "bus reset",
+ [RCODE_NO_ACK] = "no ack",
+ };
+
+ if ((unsigned int)rcode < ARRAY_SIZE(names) && names[rcode])
+ return names[rcode];
+ else
+ return "unknown";
+}
+EXPORT_SYMBOL(fw_rcode_string);
+
static const struct fw_address_region topology_map_region =
{ .start = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP,
.end = CSR_REGISTER_BASE | CSR_TOPOLOGY_MAP_END, };
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
index 9047f5547d98..515a42c786d0 100644
--- a/drivers/firewire/core.h
+++ b/drivers/firewire/core.h
@@ -3,6 +3,7 @@
#include <linux/compiler.h>
#include <linux/device.h>
+#include <linux/dma-mapping.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/idr.h>
@@ -120,21 +121,6 @@ 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);
-static inline struct fw_card *fw_card_get(struct fw_card *card)
-{
- kref_get(&card->kref);
-
- return card;
-}
-
-void fw_card_release(struct kref *kref);
-
-static inline void fw_card_put(struct fw_card *card)
-{
- kref_put(&card->kref, fw_card_release);
-}
-
-
/* -cdev */
extern const struct file_operations fw_device_ops;
@@ -169,7 +155,11 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event);
/* -iso */
-int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma);
+int fw_iso_buffer_alloc(struct fw_iso_buffer *buffer, int page_count);
+int fw_iso_buffer_map_dma(struct fw_iso_buffer *buffer, struct fw_card *card,
+ enum dma_data_direction direction);
+int fw_iso_buffer_map_vma(struct fw_iso_buffer *buffer,
+ struct vm_area_struct *vma);
/* -topology */
diff --git a/drivers/firewire/nosy.c b/drivers/firewire/nosy.c
index a7c4422a688e..4ebfb2273672 100644
--- a/drivers/firewire/nosy.c
+++ b/drivers/firewire/nosy.c
@@ -693,6 +693,8 @@ static struct pci_device_id pci_table[] __devinitdata = {
{ } /* Terminating entry */
};
+MODULE_DEVICE_TABLE(pci, pci_table);
+
static struct pci_driver lynx_pci_driver = {
.name = driver_name,
.id_table = pci_table,
@@ -700,22 +702,8 @@ static struct pci_driver lynx_pci_driver = {
.remove = remove_card,
};
+module_pci_driver(lynx_pci_driver);
+
MODULE_AUTHOR("Kristian Hoegsberg");
MODULE_DESCRIPTION("Snoop mode driver for TI pcilynx 1394 controllers");
MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(pci, pci_table);
-
-static int __init nosy_init(void)
-{
- return pci_register_driver(&lynx_pci_driver);
-}
-
-static void __exit nosy_cleanup(void)
-{
- pci_unregister_driver(&lynx_pci_driver);
-
- pr_info("Unloaded %s\n", driver_name);
-}
-
-module_init(nosy_init);
-module_exit(nosy_cleanup);
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 2b5460075a9f..c1af05e834b6 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -1821,9 +1821,8 @@ static void bus_reset_work(struct work_struct *work)
{
struct fw_ohci *ohci =
container_of(work, struct fw_ohci, bus_reset_work);
- int self_id_count, i, j, reg;
- int generation, new_generation;
- unsigned long flags;
+ int self_id_count, generation, new_generation, i, j;
+ u32 reg;
void *free_rom = NULL;
dma_addr_t free_rom_bus = 0;
bool is_new_root;
@@ -1930,13 +1929,13 @@ static void bus_reset_work(struct work_struct *work)
}
/* FIXME: Document how the locking works. */
- spin_lock_irqsave(&ohci->lock, flags);
+ spin_lock_irq(&ohci->lock);
ohci->generation = -1; /* prevent AT packet queueing */
context_stop(&ohci->at_request_ctx);
context_stop(&ohci->at_response_ctx);
- spin_unlock_irqrestore(&ohci->lock, flags);
+ spin_unlock_irq(&ohci->lock);
/*
* Per OHCI 1.2 draft, clause 7.2.3.3, hardware may leave unsent
@@ -1946,7 +1945,7 @@ static void bus_reset_work(struct work_struct *work)
at_context_flush(&ohci->at_request_ctx);
at_context_flush(&ohci->at_response_ctx);
- spin_lock_irqsave(&ohci->lock, flags);
+ spin_lock_irq(&ohci->lock);
ohci->generation = generation;
reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
@@ -1990,7 +1989,7 @@ static void bus_reset_work(struct work_struct *work)
reg_write(ohci, OHCI1394_PhyReqFilterLoSet, ~0);
#endif
- spin_unlock_irqrestore(&ohci->lock, flags);
+ spin_unlock_irq(&ohci->lock);
if (free_rom)
dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
@@ -2402,7 +2401,6 @@ static int ohci_set_config_rom(struct fw_card *card,
const __be32 *config_rom, size_t length)
{
struct fw_ohci *ohci;
- unsigned long flags;
__be32 *next_config_rom;
dma_addr_t uninitialized_var(next_config_rom_bus);
@@ -2441,7 +2439,7 @@ static int ohci_set_config_rom(struct fw_card *card,
if (next_config_rom == NULL)
return -ENOMEM;
- spin_lock_irqsave(&ohci->lock, flags);
+ spin_lock_irq(&ohci->lock);
/*
* If there is not an already pending config_rom update,
@@ -2467,7 +2465,7 @@ static int ohci_set_config_rom(struct fw_card *card,
reg_write(ohci, OHCI1394_ConfigROMmap, ohci->next_config_rom_bus);
- spin_unlock_irqrestore(&ohci->lock, flags);
+ spin_unlock_irq(&ohci->lock);
/* If we didn't use the DMA allocation, delete it. */
if (next_config_rom != NULL)
@@ -2891,10 +2889,9 @@ static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card,
descriptor_callback_t uninitialized_var(callback);
u64 *uninitialized_var(channels);
u32 *uninitialized_var(mask), uninitialized_var(regs);
- unsigned long flags;
int index, ret = -EBUSY;
- spin_lock_irqsave(&ohci->lock, flags);
+ spin_lock_irq(&ohci->lock);
switch (type) {
case FW_ISO_CONTEXT_TRANSMIT:
@@ -2938,7 +2935,7 @@ static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card,
ret = -ENOSYS;
}
- spin_unlock_irqrestore(&ohci->lock, flags);
+ spin_unlock_irq(&ohci->lock);
if (index < 0)
return ERR_PTR(ret);
@@ -2964,7 +2961,7 @@ static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card,
out_with_header:
free_page((unsigned long)ctx->header);
out:
- spin_lock_irqsave(&ohci->lock, flags);
+ spin_lock_irq(&ohci->lock);
switch (type) {
case FW_ISO_CONTEXT_RECEIVE:
@@ -2977,7 +2974,7 @@ static struct fw_iso_context *ohci_allocate_iso_context(struct fw_card *card,
}
*mask |= 1 << index;
- spin_unlock_irqrestore(&ohci->lock, flags);
+ spin_unlock_irq(&ohci->lock);
return ERR_PTR(ret);
}
@@ -3789,6 +3786,8 @@ static struct pci_driver fw_ohci_pci_driver = {
#endif
};
+module_pci_driver(fw_ohci_pci_driver);
+
MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
MODULE_DESCRIPTION("Driver for PCI OHCI IEEE1394 controllers");
MODULE_LICENSE("GPL");
@@ -3797,16 +3796,3 @@ MODULE_LICENSE("GPL");
#ifndef CONFIG_IEEE1394_OHCI1394_MODULE
MODULE_ALIAS("ohci1394");
#endif
-
-static int __init fw_ohci_init(void)
-{
- return pci_register_driver(&fw_ohci_pci_driver);
-}
-
-static void __exit fw_ohci_cleanup(void)
-{
- pci_unregister_driver(&fw_ohci_pci_driver);
-}
-
-module_init(fw_ohci_init);
-module_exit(fw_ohci_cleanup);
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c
index b7e65d7eab64..1162d6b3bf85 100644
--- a/drivers/firewire/sbp2.c
+++ b/drivers/firewire/sbp2.c
@@ -207,9 +207,8 @@ static const struct device *lu_dev(const struct sbp2_logical_unit *lu)
#define SBP2_MAX_CDB_SIZE 16
/*
- * The default maximum s/g segment size of a FireWire controller is
- * usually 0x10000, but SBP-2 only allows 0xffff. Since buffers have to
- * be quadlet-aligned, we set the length limit to 0xffff & ~3.
+ * The maximum SBP-2 data buffer size is 0xffff. We quadlet-align this
+ * for compatibility with earlier versions of this driver.
*/
#define SBP2_MAX_SEG_SIZE 0xfffc
@@ -1163,7 +1162,8 @@ static int sbp2_probe(struct device *dev)
shost->max_cmd_len = SBP2_MAX_CDB_SIZE;
- if (scsi_add_host(shost, &unit->device) < 0)
+ if (scsi_add_host_with_dma(shost, &unit->device,
+ device->card->device) < 0)
goto fail_shost_put;
/* implicit directory ID */
@@ -1295,10 +1295,7 @@ static struct fw_driver sbp2_driver = {
static void sbp2_unmap_scatterlist(struct device *card_device,
struct sbp2_command_orb *orb)
{
- if (scsi_sg_count(orb->cmd))
- dma_unmap_sg(card_device, scsi_sglist(orb->cmd),
- scsi_sg_count(orb->cmd),
- orb->cmd->sc_data_direction);
+ scsi_dma_unmap(orb->cmd);
if (orb->request.misc & cpu_to_be32(COMMAND_ORB_PAGE_TABLE_PRESENT))
dma_unmap_single(card_device, orb->page_table_bus,
@@ -1404,9 +1401,8 @@ static int sbp2_map_scatterlist(struct sbp2_command_orb *orb,
struct scatterlist *sg = scsi_sglist(orb->cmd);
int i, n;
- n = dma_map_sg(device->card->device, sg, scsi_sg_count(orb->cmd),
- orb->cmd->sc_data_direction);
- if (n == 0)
+ n = scsi_dma_map(orb->cmd);
+ if (n <= 0)
goto fail;
/*
@@ -1452,8 +1448,7 @@ static int sbp2_map_scatterlist(struct sbp2_command_orb *orb,
return 0;
fail_page_table:
- dma_unmap_sg(device->card->device, scsi_sglist(orb->cmd),
- scsi_sg_count(orb->cmd), orb->cmd->sc_data_direction);
+ scsi_dma_unmap(orb->cmd);
fail:
return -ENOMEM;
}
@@ -1534,7 +1529,10 @@ static int sbp2_scsi_slave_alloc(struct scsi_device *sdev)
sdev->allow_restart = 1;
- /* SBP-2 requires quadlet alignment of the data buffers. */
+ /*
+ * SBP-2 does not require any alignment, but we set it anyway
+ * for compatibility with earlier versions of this driver.
+ */
blk_queue_update_dma_alignment(sdev->request_queue, 4 - 1);
if (lu->tgt->workarounds & SBP2_WORKAROUND_INQUIRY_36)
@@ -1568,8 +1566,6 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev)
if (lu->tgt->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS)
blk_queue_max_hw_sectors(sdev->request_queue, 128 * 1024 / 512);
- blk_queue_max_segment_size(sdev->request_queue, SBP2_MAX_SEG_SIZE);
-
return 0;
}
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index e03653d69357..aa3642cb8209 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -2,6 +2,14 @@
# GPIO infrastructure and drivers
#
+config ARCH_HAVE_CUSTOM_GPIO_H
+ bool
+ help
+ Selecting this config option from the architecture Kconfig allows
+ the architecture to provide a custom asm/gpio.h implementation
+ overriding the default implementations. New uses of this are
+ strongly discouraged.
+
config ARCH_WANT_OPTIONAL_GPIOLIB
bool
help
@@ -37,6 +45,10 @@ menuconfig GPIOLIB
if GPIOLIB
+config OF_GPIO
+ def_bool y
+ depends on OF && !SPARC
+
config DEBUG_GPIO
bool "Debug GPIO calls"
depends on DEBUG_KERNEL
@@ -91,6 +103,12 @@ config GPIO_IT8761E
help
Say yes here to support GPIO functionality of IT8761E super I/O chip.
+config GPIO_EM
+ tristate "Emma Mobile GPIO"
+ depends on ARM
+ help
+ Say yes here to support GPIO on Renesas Emma Mobile SoCs.
+
config GPIO_EP93XX
def_bool y
depends on ARCH_EP93XX
@@ -243,7 +261,7 @@ config GPIO_MC9S08DZ60
Select this to enable the MC9S08DZ60 GPIO driver
config GPIO_PCA953X
- tristate "PCA953x, PCA955x, TCA64xx, and MAX7310 I/O ports"
+ tristate "PCA953x, PCA955x, PCA957x, TCA64xx, and MAX7310 I/O ports"
depends on I2C
help
Say yes here to provide access to several register-oriented
@@ -252,10 +270,11 @@ config GPIO_PCA953X
4 bits: pca9536, pca9537
- 8 bits: max7310, pca9534, pca9538, pca9554, pca9557,
- tca6408
+ 8 bits: max7310, max7315, pca6107, pca9534, pca9538, pca9554,
+ pca9556, pca9557, pca9574, tca6408
- 16 bits: pca9535, pca9539, pca9555, tca6416
+ 16 bits: max7312, max7313, pca9535, pca9539, pca9555, pca9575,
+ tca6416
config GPIO_PCA953X_IRQ
bool "Interrupt controller support for PCA953x"
@@ -288,6 +307,15 @@ config GPIO_PCF857X
This driver provides an in-kernel interface to those GPIOs using
platform-neutral GPIO calls.
+config GPIO_RC5T583
+ bool "RICOH RC5T583 GPIO"
+ depends on MFD_RC5T583
+ help
+ Select this option to enable GPIO driver for the Ricoh RC5T583
+ chip family.
+ This driver provides the support for driving/reading the gpio pins
+ of RC5T583 device through standard gpio library.
+
config GPIO_SX150X
bool "Semtech SX150x I2C GPIO expander"
depends on I2C=y
@@ -399,6 +427,7 @@ config GPIO_BT8XX
config GPIO_LANGWELL
bool "Intel Langwell/Penwell GPIO support"
depends on PCI && X86
+ select IRQ_DOMAIN
help
Say Y here to support Intel Langwell/Penwell GPIO.
@@ -514,4 +543,12 @@ config GPIO_TPS65910
help
Select this option to enable GPIO driver for the TPS65910
chip family.
+
+config GPIO_MSIC
+ bool "Intel MSIC mixed signal gpio support"
+ depends on MFD_INTEL_MSIC
+ help
+ Enable support for GPIO on intel MSIC controllers found in
+ intel MID devices
+
endif
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 007f54bd0081..07a79e245407 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -3,6 +3,7 @@
ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG
obj-$(CONFIG_GPIOLIB) += gpiolib.o devres.o
+obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
# Device drivers. Generally keep list sorted alphabetically
obj-$(CONFIG_GPIO_GENERIC) += gpio-generic.o
@@ -15,6 +16,7 @@ obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o
obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o
+obj-$(CONFIG_GPIO_EM) += gpio-em.o
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o
@@ -32,17 +34,18 @@ obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o
obj-$(CONFIG_GPIO_ML_IOH) += gpio-ml-ioh.o
obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o
obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o
+obj-$(CONFIG_GPIO_MSIC) += gpio-msic.o
obj-$(CONFIG_GPIO_MSM_V1) += gpio-msm-v1.o
obj-$(CONFIG_GPIO_MSM_V2) += gpio-msm-v2.o
obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o
obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o
-obj-$(CONFIG_PLAT_NOMADIK) += gpio-nomadik.o
obj-$(CONFIG_ARCH_OMAP) += gpio-omap.o
obj-$(CONFIG_GPIO_PCA953X) += gpio-pca953x.o
obj-$(CONFIG_GPIO_PCF857X) += gpio-pcf857x.o
obj-$(CONFIG_GPIO_PCH) += gpio-pch.o
obj-$(CONFIG_GPIO_PL061) += gpio-pl061.o
obj-$(CONFIG_GPIO_PXA) += gpio-pxa.o
+obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o
obj-$(CONFIG_PLAT_SAMSUNG) += gpio-samsung.o
obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c
index 3dd29399cef5..9e9947cb86a3 100644
--- a/drivers/gpio/devres.c
+++ b/drivers/gpio/devres.c
@@ -71,6 +71,35 @@ int devm_gpio_request(struct device *dev, unsigned gpio, const char *label)
EXPORT_SYMBOL(devm_gpio_request);
/**
+ * devm_gpio_request_one - request a single GPIO with initial setup
+ * @dev: device to request for
+ * @gpio: the GPIO number
+ * @flags: GPIO configuration as specified by GPIOF_*
+ * @label: a literal description string of this GPIO
+ */
+int devm_gpio_request_one(struct device *dev, unsigned gpio,
+ unsigned long flags, const char *label)
+{
+ unsigned *dr;
+ int rc;
+
+ dr = devres_alloc(devm_gpio_release, sizeof(unsigned), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ rc = gpio_request_one(gpio, flags, label);
+ if (rc) {
+ devres_free(dr);
+ return rc;
+ }
+
+ *dr = gpio;
+ devres_add(dev, dr);
+
+ return 0;
+}
+
+/**
* devm_gpio_free - free an interrupt
* @dev: device to free gpio for
* @gpio: gpio to free
@@ -83,8 +112,7 @@ EXPORT_SYMBOL(devm_gpio_request);
void devm_gpio_free(struct device *dev, unsigned int gpio)
{
- WARN_ON(devres_destroy(dev, devm_gpio_release, devm_gpio_match,
+ WARN_ON(devres_release(dev, devm_gpio_release, devm_gpio_match,
&gpio));
- gpio_free(gpio);
}
EXPORT_SYMBOL(devm_gpio_free);
diff --git a/drivers/gpio/gpio-bt8xx.c b/drivers/gpio/gpio-bt8xx.c
index 5ca4098ba092..e4cc7eb69bb2 100644
--- a/drivers/gpio/gpio-bt8xx.c
+++ b/drivers/gpio/gpio-bt8xx.c
@@ -328,17 +328,7 @@ static struct pci_driver bt8xxgpio_pci_driver = {
.resume = bt8xxgpio_resume,
};
-static int __init bt8xxgpio_init(void)
-{
- return pci_register_driver(&bt8xxgpio_pci_driver);
-}
-module_init(bt8xxgpio_init)
-
-static void __exit bt8xxgpio_exit(void)
-{
- pci_unregister_driver(&bt8xxgpio_pci_driver);
-}
-module_exit(bt8xxgpio_exit)
+module_pci_driver(bt8xxgpio_pci_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Michael Buesch");
diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c
new file mode 100644
index 000000000000..150d9768811d
--- /dev/null
+++ b/drivers/gpio/gpio-em.c
@@ -0,0 +1,418 @@
+/*
+ * Emma Mobile GPIO Support - GIO
+ *
+ * Copyright (C) 2012 Magnus Damm
+ *
+ * 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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_data/gpio-em.h>
+
+struct em_gio_priv {
+ void __iomem *base0;
+ void __iomem *base1;
+ unsigned int irq_base;
+ spinlock_t sense_lock;
+ struct platform_device *pdev;
+ struct gpio_chip gpio_chip;
+ struct irq_chip irq_chip;
+ struct irq_domain *irq_domain;
+};
+
+#define GIO_E1 0x00
+#define GIO_E0 0x04
+#define GIO_EM 0x04
+#define GIO_OL 0x08
+#define GIO_OH 0x0c
+#define GIO_I 0x10
+#define GIO_IIA 0x14
+#define GIO_IEN 0x18
+#define GIO_IDS 0x1c
+#define GIO_IIM 0x1c
+#define GIO_RAW 0x20
+#define GIO_MST 0x24
+#define GIO_IIR 0x28
+
+#define GIO_IDT0 0x40
+#define GIO_IDT1 0x44
+#define GIO_IDT2 0x48
+#define GIO_IDT3 0x4c
+#define GIO_RAWBL 0x50
+#define GIO_RAWBH 0x54
+#define GIO_IRBL 0x58
+#define GIO_IRBH 0x5c
+
+#define GIO_IDT(n) (GIO_IDT0 + ((n) * 4))
+
+static inline unsigned long em_gio_read(struct em_gio_priv *p, int offs)
+{
+ if (offs < GIO_IDT0)
+ return ioread32(p->base0 + offs);
+ else
+ return ioread32(p->base1 + (offs - GIO_IDT0));
+}
+
+static inline void em_gio_write(struct em_gio_priv *p, int offs,
+ unsigned long value)
+{
+ if (offs < GIO_IDT0)
+ iowrite32(value, p->base0 + offs);
+ else
+ iowrite32(value, p->base1 + (offs - GIO_IDT0));
+}
+
+static inline struct em_gio_priv *irq_to_priv(struct irq_data *d)
+{
+ struct irq_chip *chip = irq_data_get_irq_chip(d);
+ return container_of(chip, struct em_gio_priv, irq_chip);
+}
+
+static void em_gio_irq_disable(struct irq_data *d)
+{
+ struct em_gio_priv *p = irq_to_priv(d);
+
+ em_gio_write(p, GIO_IDS, BIT(irqd_to_hwirq(d)));
+}
+
+static void em_gio_irq_enable(struct irq_data *d)
+{
+ struct em_gio_priv *p = irq_to_priv(d);
+
+ em_gio_write(p, GIO_IEN, BIT(irqd_to_hwirq(d)));
+}
+
+#define GIO_ASYNC(x) (x + 8)
+
+static unsigned char em_gio_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
+ [IRQ_TYPE_EDGE_RISING] = GIO_ASYNC(0x00),
+ [IRQ_TYPE_EDGE_FALLING] = GIO_ASYNC(0x01),
+ [IRQ_TYPE_LEVEL_HIGH] = GIO_ASYNC(0x02),
+ [IRQ_TYPE_LEVEL_LOW] = GIO_ASYNC(0x03),
+ [IRQ_TYPE_EDGE_BOTH] = GIO_ASYNC(0x04),
+};
+
+static int em_gio_irq_set_type(struct irq_data *d, unsigned int type)
+{
+ unsigned char value = em_gio_sense_table[type & IRQ_TYPE_SENSE_MASK];
+ struct em_gio_priv *p = irq_to_priv(d);
+ unsigned int reg, offset, shift;
+ unsigned long flags;
+ unsigned long tmp;
+
+ if (!value)
+ return -EINVAL;
+
+ offset = irqd_to_hwirq(d);
+
+ pr_debug("gio: sense irq = %d, mode = %d\n", offset, value);
+
+ /* 8 x 4 bit fields in 4 IDT registers */
+ reg = GIO_IDT(offset >> 3);
+ shift = (offset & 0x07) << 4;
+
+ spin_lock_irqsave(&p->sense_lock, flags);
+
+ /* disable the interrupt in IIA */
+ tmp = em_gio_read(p, GIO_IIA);
+ tmp &= ~BIT(offset);
+ em_gio_write(p, GIO_IIA, tmp);
+
+ /* change the sense setting in IDT */
+ tmp = em_gio_read(p, reg);
+ tmp &= ~(0xf << shift);
+ tmp |= value << shift;
+ em_gio_write(p, reg, tmp);
+
+ /* clear pending interrupts */
+ em_gio_write(p, GIO_IIR, BIT(offset));
+
+ /* enable the interrupt in IIA */
+ tmp = em_gio_read(p, GIO_IIA);
+ tmp |= BIT(offset);
+ em_gio_write(p, GIO_IIA, tmp);
+
+ spin_unlock_irqrestore(&p->sense_lock, flags);
+
+ return 0;
+}
+
+static irqreturn_t em_gio_irq_handler(int irq, void *dev_id)
+{
+ struct em_gio_priv *p = dev_id;
+ unsigned long pending;
+ unsigned int offset, irqs_handled = 0;
+
+ while ((pending = em_gio_read(p, GIO_MST))) {
+ offset = __ffs(pending);
+ em_gio_write(p, GIO_IIR, BIT(offset));
+ generic_handle_irq(irq_find_mapping(p->irq_domain, offset));
+ irqs_handled++;
+ }
+
+ return irqs_handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static inline struct em_gio_priv *gpio_to_priv(struct gpio_chip *chip)
+{
+ return container_of(chip, struct em_gio_priv, gpio_chip);
+}
+
+static int em_gio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ em_gio_write(gpio_to_priv(chip), GIO_E0, BIT(offset));
+ return 0;
+}
+
+static int em_gio_get(struct gpio_chip *chip, unsigned offset)
+{
+ return (int)(em_gio_read(gpio_to_priv(chip), GIO_I) & BIT(offset));
+}
+
+static void __em_gio_set(struct gpio_chip *chip, unsigned int reg,
+ unsigned shift, int value)
+{
+ /* upper 16 bits contains mask and lower 16 actual value */
+ em_gio_write(gpio_to_priv(chip), reg,
+ (1 << (shift + 16)) | (value << shift));
+}
+
+static void em_gio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ /* output is split into two registers */
+ if (offset < 16)
+ __em_gio_set(chip, GIO_OL, offset, value);
+ else
+ __em_gio_set(chip, GIO_OH, offset - 16, value);
+}
+
+static int em_gio_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ /* write GPIO value to output before selecting output mode of pin */
+ em_gio_set(chip, offset, value);
+ em_gio_write(gpio_to_priv(chip), GIO_E1, BIT(offset));
+ return 0;
+}
+
+static int em_gio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ return irq_find_mapping(gpio_to_priv(chip)->irq_domain, offset);
+}
+
+static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct em_gio_priv *p = h->host_data;
+
+ pr_debug("gio: map hw irq = %d, virq = %d\n", (int)hw, virq);
+
+ irq_set_chip_data(virq, h->host_data);
+ irq_set_chip_and_handler(virq, &p->irq_chip, handle_level_irq);
+ set_irq_flags(virq, IRQF_VALID); /* kill me now */
+ return 0;
+}
+
+static struct irq_domain_ops em_gio_irq_domain_ops = {
+ .map = em_gio_irq_domain_map,
+};
+
+static int __devinit em_gio_irq_domain_init(struct em_gio_priv *p)
+{
+ struct platform_device *pdev = p->pdev;
+ struct gpio_em_config *pdata = pdev->dev.platform_data;
+
+ p->irq_base = irq_alloc_descs(pdata->irq_base, 0,
+ pdata->number_of_pins, numa_node_id());
+ if (IS_ERR_VALUE(p->irq_base)) {
+ dev_err(&pdev->dev, "cannot get irq_desc\n");
+ return -ENXIO;
+ }
+ pr_debug("gio: hw base = %d, nr = %d, sw base = %d\n",
+ pdata->gpio_base, pdata->number_of_pins, p->irq_base);
+
+ p->irq_domain = irq_domain_add_legacy(pdev->dev.of_node,
+ pdata->number_of_pins,
+ p->irq_base, 0,
+ &em_gio_irq_domain_ops, p);
+ if (!p->irq_domain) {
+ irq_free_descs(p->irq_base, pdata->number_of_pins);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static void __devexit em_gio_irq_domain_cleanup(struct em_gio_priv *p)
+{
+ struct gpio_em_config *pdata = p->pdev->dev.platform_data;
+
+ irq_free_descs(p->irq_base, pdata->number_of_pins);
+ /* FIXME: irq domain wants to be freed! */
+}
+
+static int __devinit em_gio_probe(struct platform_device *pdev)
+{
+ struct gpio_em_config *pdata = pdev->dev.platform_data;
+ struct em_gio_priv *p;
+ struct resource *io[2], *irq[2];
+ struct gpio_chip *gpio_chip;
+ struct irq_chip *irq_chip;
+ const char *name = dev_name(&pdev->dev);
+ int ret;
+
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p) {
+ dev_err(&pdev->dev, "failed to allocate driver data\n");
+ ret = -ENOMEM;
+ goto err0;
+ }
+
+ p->pdev = pdev;
+ platform_set_drvdata(pdev, p);
+ spin_lock_init(&p->sense_lock);
+
+ io[0] = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ io[1] = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+
+ if (!io[0] || !io[1] || !irq[0] || !irq[1] || !pdata) {
+ dev_err(&pdev->dev, "missing IRQ, IOMEM or configuration\n");
+ ret = -EINVAL;
+ goto err1;
+ }
+
+ p->base0 = ioremap_nocache(io[0]->start, resource_size(io[0]));
+ if (!p->base0) {
+ dev_err(&pdev->dev, "failed to remap low I/O memory\n");
+ ret = -ENXIO;
+ goto err1;
+ }
+
+ p->base1 = ioremap_nocache(io[1]->start, resource_size(io[1]));
+ if (!p->base1) {
+ dev_err(&pdev->dev, "failed to remap high I/O memory\n");
+ ret = -ENXIO;
+ goto err2;
+ }
+
+ gpio_chip = &p->gpio_chip;
+ gpio_chip->direction_input = em_gio_direction_input;
+ gpio_chip->get = em_gio_get;
+ gpio_chip->direction_output = em_gio_direction_output;
+ gpio_chip->set = em_gio_set;
+ gpio_chip->to_irq = em_gio_to_irq;
+ gpio_chip->label = name;
+ gpio_chip->owner = THIS_MODULE;
+ gpio_chip->base = pdata->gpio_base;
+ gpio_chip->ngpio = pdata->number_of_pins;
+
+ irq_chip = &p->irq_chip;
+ irq_chip->name = name;
+ irq_chip->irq_mask = em_gio_irq_disable;
+ irq_chip->irq_unmask = em_gio_irq_enable;
+ irq_chip->irq_enable = em_gio_irq_enable;
+ irq_chip->irq_disable = em_gio_irq_disable;
+ irq_chip->irq_set_type = em_gio_irq_set_type;
+ irq_chip->flags = IRQCHIP_SKIP_SET_WAKE;
+
+ ret = em_gio_irq_domain_init(p);
+ if (ret) {
+ dev_err(&pdev->dev, "cannot initialize irq domain\n");
+ goto err3;
+ }
+
+ if (request_irq(irq[0]->start, em_gio_irq_handler, 0, name, p)) {
+ dev_err(&pdev->dev, "failed to request low IRQ\n");
+ ret = -ENOENT;
+ goto err4;
+ }
+
+ if (request_irq(irq[1]->start, em_gio_irq_handler, 0, name, p)) {
+ dev_err(&pdev->dev, "failed to request high IRQ\n");
+ ret = -ENOENT;
+ goto err5;
+ }
+
+ ret = gpiochip_add(gpio_chip);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add GPIO controller\n");
+ goto err6;
+ }
+ return 0;
+
+err6:
+ free_irq(irq[1]->start, pdev);
+err5:
+ free_irq(irq[0]->start, pdev);
+err4:
+ em_gio_irq_domain_cleanup(p);
+err3:
+ iounmap(p->base1);
+err2:
+ iounmap(p->base0);
+err1:
+ kfree(p);
+err0:
+ return ret;
+}
+
+static int __devexit em_gio_remove(struct platform_device *pdev)
+{
+ struct em_gio_priv *p = platform_get_drvdata(pdev);
+ struct resource *irq[2];
+ int ret;
+
+ ret = gpiochip_remove(&p->gpio_chip);
+ if (ret)
+ return ret;
+
+ irq[0] = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ irq[1] = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+
+ free_irq(irq[1]->start, pdev);
+ free_irq(irq[0]->start, pdev);
+ em_gio_irq_domain_cleanup(p);
+ iounmap(p->base1);
+ iounmap(p->base0);
+ kfree(p);
+ return 0;
+}
+
+static struct platform_driver em_gio_device_driver = {
+ .probe = em_gio_probe,
+ .remove = __devexit_p(em_gio_remove),
+ .driver = {
+ .name = "em_gio",
+ }
+};
+
+module_platform_driver(em_gio_device_driver);
+
+MODULE_AUTHOR("Magnus Damm");
+MODULE_DESCRIPTION("Renesas Emma Mobile GIO Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c
index 776b772523e5..9fe5b8fe9be8 100644
--- a/drivers/gpio/gpio-ep93xx.c
+++ b/drivers/gpio/gpio-ep93xx.c
@@ -325,7 +325,7 @@ static int ep93xx_gpio_add_bank(struct bgpio_chip *bgc, struct device *dev,
void __iomem *dir = mmio_base + bank->dir;
int err;
- err = bgpio_init(bgc, dev, 1, data, NULL, NULL, dir, NULL, false);
+ err = bgpio_init(bgc, dev, 1, data, NULL, NULL, dir, NULL, 0);
if (err)
return err;
diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c
index e38dd0c31973..82e2e4fe599e 100644
--- a/drivers/gpio/gpio-generic.c
+++ b/drivers/gpio/gpio-generic.c
@@ -364,7 +364,7 @@ EXPORT_SYMBOL_GPL(bgpio_remove);
int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
unsigned long sz, void __iomem *dat, void __iomem *set,
void __iomem *clr, void __iomem *dirout, void __iomem *dirin,
- bool big_endian)
+ unsigned long flags)
{
int ret;
@@ -385,7 +385,7 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
if (ret)
return ret;
- ret = bgpio_setup_accessors(dev, bgc, big_endian);
+ ret = bgpio_setup_accessors(dev, bgc, flags & BGPIOF_BIG_ENDIAN);
if (ret)
return ret;
@@ -394,6 +394,11 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
return ret;
bgc->data = bgc->read_reg(bgc->reg_dat);
+ if (bgc->gc.set == bgpio_set_set &&
+ !(flags & BGPIOF_UNREADABLE_REG_SET))
+ bgc->data = bgc->read_reg(bgc->reg_set);
+ if (bgc->reg_dir && !(flags & BGPIOF_UNREADABLE_REG_DIR))
+ bgc->dir = bgc->read_reg(bgc->reg_dir);
return ret;
}
@@ -449,7 +454,7 @@ static int __devinit bgpio_pdev_probe(struct platform_device *pdev)
void __iomem *dirout;
void __iomem *dirin;
unsigned long sz;
- bool be;
+ unsigned long flags = 0;
int err;
struct bgpio_chip *bgc;
struct bgpio_pdata *pdata = dev_get_platdata(dev);
@@ -480,13 +485,14 @@ static int __devinit bgpio_pdev_probe(struct platform_device *pdev)
if (err)
return err;
- be = !strcmp(platform_get_device_id(pdev)->name, "basic-mmio-gpio-be");
+ if (!strcmp(platform_get_device_id(pdev)->name, "basic-mmio-gpio-be"))
+ flags |= BGPIOF_BIG_ENDIAN;
bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
if (!bgc)
return -ENOMEM;
- err = bgpio_init(bgc, dev, sz, dat, set, clr, dirout, dirin, be);
+ err = bgpio_init(bgc, dev, sz, dat, set, clr, dirout, dirin, flags);
if (err)
return err;
diff --git a/drivers/gpio/gpio-langwell.c b/drivers/gpio/gpio-langwell.c
index 00692e89ef87..a1c8754f52cf 100644
--- a/drivers/gpio/gpio-langwell.c
+++ b/drivers/gpio/gpio-langwell.c
@@ -36,6 +36,7 @@
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
+#include <linux/irqdomain.h>
/*
* Langwell chip has 64 pins and thus there are 2 32bit registers to control
@@ -66,8 +67,8 @@ struct lnw_gpio {
struct gpio_chip chip;
void *reg_base;
spinlock_t lock;
- unsigned irq_base;
struct pci_dev *pdev;
+ struct irq_domain *domain;
};
static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
@@ -176,13 +177,13 @@ static int lnw_gpio_direction_output(struct gpio_chip *chip,
static int lnw_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
- return lnw->irq_base + offset;
+ return irq_create_mapping(lnw->domain, offset);
}
static int lnw_irq_type(struct irq_data *d, unsigned type)
{
struct lnw_gpio *lnw = irq_data_get_irq_chip_data(d);
- u32 gpio = d->irq - lnw->irq_base;
+ u32 gpio = irqd_to_hwirq(d);
unsigned long flags;
u32 value;
void __iomem *grer = gpio_reg(&lnw->chip, gpio, GRER);
@@ -249,20 +250,55 @@ static void lnw_irq_handler(unsigned irq, struct irq_desc *desc)
/* check GPIO controller to check which pin triggered the interrupt */
for (base = 0; base < lnw->chip.ngpio; base += 32) {
gedr = gpio_reg(&lnw->chip, base, GEDR);
- pending = readl(gedr);
- while (pending) {
+ while ((pending = readl(gedr))) {
gpio = __ffs(pending);
mask = BIT(gpio);
- pending &= ~mask;
/* Clear before handling so we can't lose an edge */
writel(mask, gedr);
- generic_handle_irq(lnw->irq_base + base + gpio);
+ generic_handle_irq(irq_find_mapping(lnw->domain,
+ base + gpio));
}
}
chip->irq_eoi(data);
}
+static void lnw_irq_init_hw(struct lnw_gpio *lnw)
+{
+ void __iomem *reg;
+ unsigned base;
+
+ for (base = 0; base < lnw->chip.ngpio; base += 32) {
+ /* Clear the rising-edge detect register */
+ reg = gpio_reg(&lnw->chip, base, GRER);
+ writel(0, reg);
+ /* Clear the falling-edge detect register */
+ reg = gpio_reg(&lnw->chip, base, GFER);
+ writel(0, reg);
+ /* Clear the edge detect status register */
+ reg = gpio_reg(&lnw->chip, base, GEDR);
+ writel(~0, reg);
+ }
+}
+
+static int lnw_gpio_irq_map(struct irq_domain *d, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct lnw_gpio *lnw = d->host_data;
+
+ irq_set_chip_and_handler_name(virq, &lnw_irqchip, handle_simple_irq,
+ "demux");
+ irq_set_chip_data(virq, lnw);
+ irq_set_irq_type(virq, IRQ_TYPE_NONE);
+
+ return 0;
+}
+
+static const struct irq_domain_ops lnw_gpio_irq_ops = {
+ .map = lnw_gpio_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
#ifdef CONFIG_PM
static int lnw_gpio_runtime_resume(struct device *dev)
{
@@ -300,23 +336,22 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
void *base;
- int i;
resource_size_t start, len;
struct lnw_gpio *lnw;
- u32 irq_base;
u32 gpio_base;
int retval = 0;
+ int ngpio = id->driver_data;
retval = pci_enable_device(pdev);
if (retval)
- goto done;
+ return retval;
retval = pci_request_regions(pdev, "langwell_gpio");
if (retval) {
dev_err(&pdev->dev, "error requesting resources\n");
goto err2;
}
- /* get the irq_base from bar1 */
+ /* get the gpio_base from bar1 */
start = pci_resource_start(pdev, 1);
len = pci_resource_len(pdev, 1);
base = ioremap_nocache(start, len);
@@ -324,28 +359,32 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
dev_err(&pdev->dev, "error mapping bar1\n");
goto err3;
}
- irq_base = *(u32 *)base;
gpio_base = *((u32 *)base + 1);
/* release the IO mapping, since we already get the info from bar1 */
iounmap(base);
/* get the register base from bar0 */
start = pci_resource_start(pdev, 0);
len = pci_resource_len(pdev, 0);
- base = ioremap_nocache(start, len);
+ base = devm_ioremap_nocache(&pdev->dev, start, len);
if (!base) {
dev_err(&pdev->dev, "error mapping bar0\n");
retval = -EFAULT;
goto err3;
}
- lnw = kzalloc(sizeof(struct lnw_gpio), GFP_KERNEL);
+ lnw = devm_kzalloc(&pdev->dev, sizeof(struct lnw_gpio), GFP_KERNEL);
if (!lnw) {
dev_err(&pdev->dev, "can't allocate langwell_gpio chip data\n");
retval = -ENOMEM;
- goto err4;
+ goto err3;
}
+
+ lnw->domain = irq_domain_add_linear(pdev->dev.of_node, ngpio,
+ &lnw_gpio_irq_ops, lnw);
+ if (!lnw->domain)
+ goto err3;
+
lnw->reg_base = base;
- lnw->irq_base = irq_base;
lnw->chip.label = dev_name(&pdev->dev);
lnw->chip.request = lnw_gpio_request;
lnw->chip.direction_input = lnw_gpio_direction_input;
@@ -354,38 +393,32 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
lnw->chip.set = lnw_gpio_set;
lnw->chip.to_irq = lnw_gpio_to_irq;
lnw->chip.base = gpio_base;
- lnw->chip.ngpio = id->driver_data;
+ lnw->chip.ngpio = ngpio;
lnw->chip.can_sleep = 0;
lnw->pdev = pdev;
pci_set_drvdata(pdev, lnw);
retval = gpiochip_add(&lnw->chip);
if (retval) {
dev_err(&pdev->dev, "langwell gpiochip_add error %d\n", retval);
- goto err5;
+ goto err3;
}
+
+ lnw_irq_init_hw(lnw);
+
irq_set_handler_data(pdev->irq, lnw);
irq_set_chained_handler(pdev->irq, lnw_irq_handler);
- for (i = 0; i < lnw->chip.ngpio; i++) {
- irq_set_chip_and_handler_name(i + lnw->irq_base, &lnw_irqchip,
- handle_simple_irq, "demux");
- irq_set_chip_data(i + lnw->irq_base, lnw);
- }
spin_lock_init(&lnw->lock);
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_allow(&pdev->dev);
- goto done;
-err5:
- kfree(lnw);
-err4:
- iounmap(base);
+ return 0;
+
err3:
pci_release_regions(pdev);
err2:
pci_disable_device(pdev);
-done:
return retval;
}
diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c
index 61c2d08d37b6..c2199beca98a 100644
--- a/drivers/gpio/gpio-lpc32xx.c
+++ b/drivers/gpio/gpio-lpc32xx.c
@@ -21,6 +21,9 @@
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
#include <mach/hardware.h>
#include <mach/platform.h>
@@ -454,10 +457,57 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = {
},
};
+/* Empty now, can be removed later when mach-lpc32xx is finally switched over
+ * to DT support
+ */
void __init lpc32xx_gpio_init(void)
{
+}
+
+static int lpc32xx_of_xlate(struct gpio_chip *gc,
+ const struct of_phandle_args *gpiospec, u32 *flags)
+{
+ /* Is this the correct bank? */
+ u32 bank = gpiospec->args[0];
+ if ((bank > ARRAY_SIZE(lpc32xx_gpiochip) ||
+ (gc != &lpc32xx_gpiochip[bank].chip)))
+ return -EINVAL;
+
+ if (flags)
+ *flags = gpiospec->args[2];
+ return gpiospec->args[1];
+}
+
+static int __devinit lpc32xx_gpio_probe(struct platform_device *pdev)
+{
int i;
- for (i = 0; i < ARRAY_SIZE(lpc32xx_gpiochip); i++)
+ for (i = 0; i < ARRAY_SIZE(lpc32xx_gpiochip); i++) {
+ if (pdev->dev.of_node) {
+ lpc32xx_gpiochip[i].chip.of_xlate = lpc32xx_of_xlate;
+ lpc32xx_gpiochip[i].chip.of_gpio_n_cells = 3;
+ lpc32xx_gpiochip[i].chip.of_node = pdev->dev.of_node;
+ }
gpiochip_add(&lpc32xx_gpiochip[i].chip);
+ }
+
+ return 0;
}
+
+#ifdef CONFIG_OF
+static struct of_device_id lpc32xx_gpio_of_match[] __devinitdata = {
+ { .compatible = "nxp,lpc3220-gpio", },
+ { },
+};
+#endif
+
+static struct platform_driver lpc32xx_gpio_driver = {
+ .driver = {
+ .name = "lpc32xx-gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(lpc32xx_gpio_of_match),
+ },
+ .probe = lpc32xx_gpio_probe,
+};
+
+module_platform_driver(lpc32xx_gpio_driver);
diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c
index c5d83a8a91c2..0f425189de11 100644
--- a/drivers/gpio/gpio-mcp23s08.c
+++ b/drivers/gpio/gpio-mcp23s08.c
@@ -353,7 +353,7 @@ static void mcp23s08_dbg_show(struct seq_file *s, struct gpio_chip *chip)
chip->base + t, bank, t, label,
(mcp->cache[MCP_IODIR] & mask) ? "in " : "out",
(mcp->cache[MCP_GPIO] & mask) ? "hi" : "lo",
- (mcp->cache[MCP_GPPU] & mask) ? " " : "up");
+ (mcp->cache[MCP_GPPU] & mask) ? "up" : " ");
/* NOTE: ignoring the irq-related registers */
seq_printf(s, "\n");
}
diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c
index f0febe5b8221..db01f151d41c 100644
--- a/drivers/gpio/gpio-ml-ioh.c
+++ b/drivers/gpio/gpio-ml-ioh.c
@@ -611,17 +611,7 @@ static struct pci_driver ioh_gpio_driver = {
.resume = ioh_gpio_resume
};
-static int __init ioh_gpio_pci_init(void)
-{
- return pci_register_driver(&ioh_gpio_driver);
-}
-module_init(ioh_gpio_pci_init);
-
-static void __exit ioh_gpio_pci_exit(void)
-{
- pci_unregister_driver(&ioh_gpio_driver);
-}
-module_exit(ioh_gpio_pci_exit);
+module_pci_driver(ioh_gpio_driver);
MODULE_DESCRIPTION("OKI SEMICONDUCTOR ML-IOH series GPIO Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c
index e6568c19c939..5a1817eedd1b 100644
--- a/drivers/gpio/gpio-mpc8xxx.c
+++ b/drivers/gpio/gpio-mpc8xxx.c
@@ -163,7 +163,8 @@ static void mpc8xxx_gpio_irq_cascade(unsigned int irq, struct irq_desc *desc)
if (mask)
generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq,
32 - ffs(mask)));
- chip->irq_eoi(&desc->irq_data);
+ if (chip->irq_eoi)
+ chip->irq_eoi(&desc->irq_data);
}
static void mpc8xxx_irq_unmask(struct irq_data *d)
diff --git a/drivers/gpio/gpio-msic.c b/drivers/gpio/gpio-msic.c
new file mode 100644
index 000000000000..71a838f44501
--- /dev/null
+++ b/drivers/gpio/gpio-msic.c
@@ -0,0 +1,339 @@
+/*
+ * Intel Medfield MSIC GPIO driver>
+ * Copyright (c) 2011, Intel Corporation.
+ *
+ * Author: Mathias Nyman <mathias.nyman@linux.intel.com>
+ * Based on intel_pmic_gpio.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/intel_msic.h>
+
+/* the offset for the mapping of global gpio pin to irq */
+#define MSIC_GPIO_IRQ_OFFSET 0x100
+
+#define MSIC_GPIO_DIR_IN 0
+#define MSIC_GPIO_DIR_OUT BIT(5)
+#define MSIC_GPIO_TRIG_FALL BIT(1)
+#define MSIC_GPIO_TRIG_RISE BIT(2)
+
+/* masks for msic gpio output GPIOxxxxCTLO registers */
+#define MSIC_GPIO_DIR_MASK BIT(5)
+#define MSIC_GPIO_DRV_MASK BIT(4)
+#define MSIC_GPIO_REN_MASK BIT(3)
+#define MSIC_GPIO_RVAL_MASK (BIT(2) | BIT(1))
+#define MSIC_GPIO_DOUT_MASK BIT(0)
+
+/* masks for msic gpio input GPIOxxxxCTLI registers */
+#define MSIC_GPIO_GLBYP_MASK BIT(5)
+#define MSIC_GPIO_DBNC_MASK (BIT(4) | BIT(3))
+#define MSIC_GPIO_INTCNT_MASK (BIT(2) | BIT(1))
+#define MSIC_GPIO_DIN_MASK BIT(0)
+
+#define MSIC_NUM_GPIO 24
+
+struct msic_gpio {
+ struct platform_device *pdev;
+ struct mutex buslock;
+ struct gpio_chip chip;
+ int irq;
+ unsigned irq_base;
+ unsigned long trig_change_mask;
+ unsigned trig_type;
+};
+
+/*
+ * MSIC has 24 gpios, 16 low voltage (1.2-1.8v) and 8 high voltage (3v).
+ * Both the high and low voltage gpios are divided in two banks.
+ * GPIOs are numbered with GPIO0LV0 as gpio_base in the following order:
+ * GPIO0LV0..GPIO0LV7: low voltage, bank 0, gpio_base
+ * GPIO1LV0..GPIO1LV7: low voltage, bank 1, gpio_base + 8
+ * GPIO0HV0..GPIO0HV3: high voltage, bank 0, gpio_base + 16
+ * GPIO1HV0..GPIO1HV3: high voltage, bank 1, gpio_base + 20
+ */
+
+static int msic_gpio_to_ireg(unsigned offset)
+{
+ if (offset >= MSIC_NUM_GPIO)
+ return -EINVAL;
+
+ if (offset < 8)
+ return INTEL_MSIC_GPIO0LV0CTLI - offset;
+ if (offset < 16)
+ return INTEL_MSIC_GPIO1LV0CTLI - offset + 8;
+ if (offset < 20)
+ return INTEL_MSIC_GPIO0HV0CTLI - offset + 16;
+
+ return INTEL_MSIC_GPIO1HV0CTLI - offset + 20;
+}
+
+static int msic_gpio_to_oreg(unsigned offset)
+{
+ if (offset >= MSIC_NUM_GPIO)
+ return -EINVAL;
+
+ if (offset < 8)
+ return INTEL_MSIC_GPIO0LV0CTLO - offset;
+ if (offset < 16)
+ return INTEL_MSIC_GPIO1LV0CTLO - offset + 8;
+ if (offset < 20)
+ return INTEL_MSIC_GPIO0HV0CTLO - offset + 16;
+
+ return INTEL_MSIC_GPIO1HV0CTLO + offset + 20;
+}
+
+static int msic_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ int reg;
+
+ reg = msic_gpio_to_oreg(offset);
+ if (reg < 0)
+ return reg;
+
+ return intel_msic_reg_update(reg, MSIC_GPIO_DIR_IN, MSIC_GPIO_DIR_MASK);
+}
+
+static int msic_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ int reg;
+ unsigned mask;
+
+ value = (!!value) | MSIC_GPIO_DIR_OUT;
+ mask = MSIC_GPIO_DIR_MASK | MSIC_GPIO_DOUT_MASK;
+
+ reg = msic_gpio_to_oreg(offset);
+ if (reg < 0)
+ return reg;
+
+ return intel_msic_reg_update(reg, value, mask);
+}
+
+static int msic_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ u8 r;
+ int ret;
+ int reg;
+
+ reg = msic_gpio_to_ireg(offset);
+ if (reg < 0)
+ return reg;
+
+ ret = intel_msic_reg_read(reg, &r);
+ if (ret < 0)
+ return ret;
+
+ return r & MSIC_GPIO_DIN_MASK;
+}
+
+static void msic_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ int reg;
+
+ reg = msic_gpio_to_oreg(offset);
+ if (reg < 0)
+ return;
+
+ intel_msic_reg_update(reg, !!value , MSIC_GPIO_DOUT_MASK);
+}
+
+/*
+ * This is called from genirq with mg->buslock locked and
+ * irq_desc->lock held. We can not access the scu bus here, so we
+ * store the change and update in the bus_sync_unlock() function below
+ */
+static int msic_irq_type(struct irq_data *data, unsigned type)
+{
+ struct msic_gpio *mg = irq_data_get_irq_chip_data(data);
+ u32 gpio = data->irq - mg->irq_base;
+
+ if (gpio >= mg->chip.ngpio)
+ return -EINVAL;
+
+ /* mark for which gpio the trigger changed, protected by buslock */
+ mg->trig_change_mask |= (1 << gpio);
+ mg->trig_type = type;
+
+ return 0;
+}
+
+static int msic_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct msic_gpio *mg = container_of(chip, struct msic_gpio, chip);
+ return mg->irq_base + offset;
+}
+
+static void msic_bus_lock(struct irq_data *data)
+{
+ struct msic_gpio *mg = irq_data_get_irq_chip_data(data);
+ mutex_lock(&mg->buslock);
+}
+
+static void msic_bus_sync_unlock(struct irq_data *data)
+{
+ struct msic_gpio *mg = irq_data_get_irq_chip_data(data);
+ int offset;
+ int reg;
+ u8 trig = 0;
+
+ /* We can only get one change at a time as the buslock covers the
+ entire transaction. The irq_desc->lock is dropped before we are
+ called but that is fine */
+ if (mg->trig_change_mask) {
+ offset = __ffs(mg->trig_change_mask);
+
+ reg = msic_gpio_to_ireg(offset);
+ if (reg < 0)
+ goto out;
+
+ if (mg->trig_type & IRQ_TYPE_EDGE_RISING)
+ trig |= MSIC_GPIO_TRIG_RISE;
+ if (mg->trig_type & IRQ_TYPE_EDGE_FALLING)
+ trig |= MSIC_GPIO_TRIG_FALL;
+
+ intel_msic_reg_update(reg, trig, MSIC_GPIO_INTCNT_MASK);
+ mg->trig_change_mask = 0;
+ }
+out:
+ mutex_unlock(&mg->buslock);
+}
+
+/* Firmware does all the masking and unmasking for us, no masking here. */
+static void msic_irq_unmask(struct irq_data *data) { }
+
+static void msic_irq_mask(struct irq_data *data) { }
+
+static struct irq_chip msic_irqchip = {
+ .name = "MSIC-GPIO",
+ .irq_mask = msic_irq_mask,
+ .irq_unmask = msic_irq_unmask,
+ .irq_set_type = msic_irq_type,
+ .irq_bus_lock = msic_bus_lock,
+ .irq_bus_sync_unlock = msic_bus_sync_unlock,
+};
+
+static void msic_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+ struct irq_data *data = irq_desc_get_irq_data(desc);
+ struct msic_gpio *mg = irq_data_get_irq_handler_data(data);
+ struct irq_chip *chip = irq_data_get_irq_chip(data);
+ struct intel_msic *msic = pdev_to_intel_msic(mg->pdev);
+ int i;
+ int bitnr;
+ u8 pin;
+ unsigned long pending = 0;
+
+ for (i = 0; i < (mg->chip.ngpio / BITS_PER_BYTE); i++) {
+ intel_msic_irq_read(msic, INTEL_MSIC_GPIO0LVIRQ + i, &pin);
+ pending = pin;
+
+ if (pending) {
+ for_each_set_bit(bitnr, &pending, BITS_PER_BYTE)
+ generic_handle_irq(mg->irq_base +
+ (i * BITS_PER_BYTE) + bitnr);
+ }
+ }
+ chip->irq_eoi(data);
+}
+
+static int __devinit platform_msic_gpio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct intel_msic_gpio_pdata *pdata = dev->platform_data;
+ struct msic_gpio *mg;
+ int irq = platform_get_irq(pdev, 0);
+ int retval;
+ int i;
+
+ if (irq < 0) {
+ dev_err(dev, "no IRQ line\n");
+ return -EINVAL;
+ }
+
+ if (!pdata || !pdata->gpio_base) {
+ dev_err(dev, "incorrect or missing platform data\n");
+ return -EINVAL;
+ }
+
+ mg = kzalloc(sizeof(*mg), GFP_KERNEL);
+ if (!mg)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, mg);
+
+ mg->pdev = pdev;
+ mg->irq = irq;
+ mg->irq_base = pdata->gpio_base + MSIC_GPIO_IRQ_OFFSET;
+ mg->chip.label = "msic_gpio";
+ mg->chip.direction_input = msic_gpio_direction_input;
+ mg->chip.direction_output = msic_gpio_direction_output;
+ mg->chip.get = msic_gpio_get;
+ mg->chip.set = msic_gpio_set;
+ mg->chip.to_irq = msic_gpio_to_irq;
+ mg->chip.base = pdata->gpio_base;
+ mg->chip.ngpio = MSIC_NUM_GPIO;
+ mg->chip.can_sleep = 1;
+ mg->chip.dev = dev;
+
+ mutex_init(&mg->buslock);
+
+ retval = gpiochip_add(&mg->chip);
+ if (retval) {
+ dev_err(dev, "Adding MSIC gpio chip failed\n");
+ goto err;
+ }
+
+ for (i = 0; i < mg->chip.ngpio; i++) {
+ irq_set_chip_data(i + mg->irq_base, mg);
+ irq_set_chip_and_handler_name(i + mg->irq_base,
+ &msic_irqchip,
+ handle_simple_irq,
+ "demux");
+ }
+ irq_set_chained_handler(mg->irq, msic_gpio_irq_handler);
+ irq_set_handler_data(mg->irq, mg);
+
+ return 0;
+err:
+ kfree(mg);
+ return retval;
+}
+
+static struct platform_driver platform_msic_gpio_driver = {
+ .driver = {
+ .name = "msic_gpio",
+ .owner = THIS_MODULE,
+ },
+ .probe = platform_msic_gpio_probe,
+};
+
+static int __init platform_msic_gpio_init(void)
+{
+ return platform_driver_register(&platform_msic_gpio_driver);
+}
+
+subsys_initcall(platform_msic_gpio_init);
+
+MODULE_AUTHOR("Mathias Nyman <mathias.nyman@linux.intel.com>");
+MODULE_DESCRIPTION("Intel Medfield MSIC GPIO driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c
index e79147634573..c337143b18f8 100644
--- a/drivers/gpio/gpio-mxc.c
+++ b/drivers/gpio/gpio-mxc.c
@@ -417,7 +417,7 @@ static int __devinit mxc_gpio_probe(struct platform_device *pdev)
err = bgpio_init(&port->bgc, &pdev->dev, 4,
port->base + GPIO_PSR,
port->base + GPIO_DR, NULL,
- port->base + GPIO_GDIR, NULL, false);
+ port->base + GPIO_GDIR, NULL, 0);
if (err)
goto out_iounmap;
diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c
index 385c58e8405b..b4136501abd8 100644
--- a/drivers/gpio/gpio-mxs.c
+++ b/drivers/gpio/gpio-mxs.c
@@ -244,7 +244,7 @@ static int __devinit mxs_gpio_probe(struct platform_device *pdev)
err = bgpio_init(&port->bgc, &pdev->dev, 4,
port->base + PINCTRL_DIN(port->id),
port->base + PINCTRL_DOUT(port->id), NULL,
- port->base + PINCTRL_DOE(port->id), NULL, false);
+ port->base + PINCTRL_DOE(port->id), NULL, 0);
if (err)
goto out_iounmap;
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 4461540653a8..c4ed1722734c 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -57,14 +57,10 @@ struct gpio_bank {
u16 irq;
int irq_base;
struct irq_domain *domain;
- u32 suspend_wakeup;
- u32 saved_wakeup;
u32 non_wakeup_gpios;
u32 enabled_non_wakeup_gpios;
struct gpio_regs context;
u32 saved_datain;
- u32 saved_fallingdetect;
- u32 saved_risingdetect;
u32 level_mask;
u32 toggle_mask;
spinlock_t lock;
@@ -516,11 +512,11 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
spin_lock_irqsave(&bank->lock, flags);
if (enable)
- bank->suspend_wakeup |= gpio_bit;
+ bank->context.wake_en |= gpio_bit;
else
- bank->suspend_wakeup &= ~gpio_bit;
+ bank->context.wake_en &= ~gpio_bit;
- __raw_writel(bank->suspend_wakeup, bank->base + bank->regs->wkup_en);
+ __raw_writel(bank->context.wake_en, bank->base + bank->regs->wkup_en);
spin_unlock_irqrestore(&bank->lock, flags);
return 0;
@@ -640,7 +636,6 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
u32 isr;
unsigned int gpio_irq, gpio_index;
struct gpio_bank *bank;
- u32 retrigger = 0;
int unmasked = 0;
struct irq_chip *chip = irq_desc_get_chip(desc);
@@ -677,8 +672,6 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
- isr |= retrigger;
- retrigger = 0;
if (!isr)
break;
@@ -789,8 +782,7 @@ static int omap_mpuio_suspend_noirq(struct device *dev)
unsigned long flags;
spin_lock_irqsave(&bank->lock, flags);
- bank->saved_wakeup = __raw_readl(mask_reg);
- __raw_writel(0xffff & ~bank->suspend_wakeup, mask_reg);
+ __raw_writel(0xffff & ~bank->context.wake_en, mask_reg);
spin_unlock_irqrestore(&bank->lock, flags);
return 0;
@@ -805,7 +797,7 @@ static int omap_mpuio_resume_noirq(struct device *dev)
unsigned long flags;
spin_lock_irqsave(&bank->lock, flags);
- __raw_writel(bank->saved_wakeup, mask_reg);
+ __raw_writel(bank->context.wake_en, mask_reg);
spin_unlock_irqrestore(&bank->lock, flags);
return 0;
@@ -1152,54 +1144,6 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
#ifdef CONFIG_ARCH_OMAP2PLUS
-#if defined(CONFIG_PM_SLEEP)
-static int omap_gpio_suspend(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct gpio_bank *bank = platform_get_drvdata(pdev);
- void __iomem *base = bank->base;
- void __iomem *wakeup_enable;
- unsigned long flags;
-
- if (!bank->mod_usage || !bank->loses_context)
- return 0;
-
- if (!bank->regs->wkup_en || !bank->suspend_wakeup)
- return 0;
-
- wakeup_enable = bank->base + bank->regs->wkup_en;
-
- spin_lock_irqsave(&bank->lock, flags);
- bank->saved_wakeup = __raw_readl(wakeup_enable);
- _gpio_rmw(base, bank->regs->wkup_en, 0xffffffff, 0);
- _gpio_rmw(base, bank->regs->wkup_en, bank->suspend_wakeup, 1);
- spin_unlock_irqrestore(&bank->lock, flags);
-
- return 0;
-}
-
-static int omap_gpio_resume(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct gpio_bank *bank = platform_get_drvdata(pdev);
- void __iomem *base = bank->base;
- unsigned long flags;
-
- if (!bank->mod_usage || !bank->loses_context)
- return 0;
-
- if (!bank->regs->wkup_en || !bank->saved_wakeup)
- return 0;
-
- spin_lock_irqsave(&bank->lock, flags);
- _gpio_rmw(base, bank->regs->wkup_en, 0xffffffff, 0);
- _gpio_rmw(base, bank->regs->wkup_en, bank->saved_wakeup, 1);
- spin_unlock_irqrestore(&bank->lock, flags);
-
- return 0;
-}
-#endif /* CONFIG_PM_SLEEP */
-
#if defined(CONFIG_PM_RUNTIME)
static void omap_gpio_restore_context(struct gpio_bank *bank);
@@ -1233,6 +1177,9 @@ static int omap_gpio_runtime_suspend(struct device *dev)
__raw_writel(wake_hi | bank->context.risingdetect,
bank->base + bank->regs->risingdetect);
+ if (!bank->enabled_non_wakeup_gpios)
+ goto update_gpio_context_count;
+
if (bank->power_mode != OFF_MODE) {
bank->power_mode = 0;
goto update_gpio_context_count;
@@ -1244,11 +1191,9 @@ static int omap_gpio_runtime_suspend(struct device *dev)
*/
bank->saved_datain = __raw_readl(bank->base +
bank->regs->datain);
- l1 = __raw_readl(bank->base + bank->regs->fallingdetect);
- l2 = __raw_readl(bank->base + bank->regs->risingdetect);
+ l1 = bank->context.fallingdetect;
+ l2 = bank->context.risingdetect;
- bank->saved_fallingdetect = l1;
- bank->saved_risingdetect = l2;
l1 &= ~bank->enabled_non_wakeup_gpios;
l2 &= ~bank->enabled_non_wakeup_gpios;
@@ -1290,16 +1235,10 @@ static int omap_gpio_runtime_resume(struct device *dev)
__raw_writel(bank->context.risingdetect,
bank->base + bank->regs->risingdetect);
- if (!bank->workaround_enabled) {
- spin_unlock_irqrestore(&bank->lock, flags);
- return 0;
- }
-
if (bank->get_context_loss_count) {
context_lost_cnt_after =
bank->get_context_loss_count(bank->dev);
- if (context_lost_cnt_after != bank->context_loss_count ||
- !context_lost_cnt_after) {
+ if (context_lost_cnt_after != bank->context_loss_count) {
omap_gpio_restore_context(bank);
} else {
spin_unlock_irqrestore(&bank->lock, flags);
@@ -1307,9 +1246,14 @@ static int omap_gpio_runtime_resume(struct device *dev)
}
}
- __raw_writel(bank->saved_fallingdetect,
+ if (!bank->workaround_enabled) {
+ spin_unlock_irqrestore(&bank->lock, flags);
+ return 0;
+ }
+
+ __raw_writel(bank->context.fallingdetect,
bank->base + bank->regs->fallingdetect);
- __raw_writel(bank->saved_risingdetect,
+ __raw_writel(bank->context.risingdetect,
bank->base + bank->regs->risingdetect);
l = __raw_readl(bank->base + bank->regs->datain);
@@ -1326,14 +1270,15 @@ static int omap_gpio_runtime_resume(struct device *dev)
* No need to generate IRQs for the rising edge for gpio IRQs
* configured with falling edge only; and vice versa.
*/
- gen0 = l & bank->saved_fallingdetect;
+ gen0 = l & bank->context.fallingdetect;
gen0 &= bank->saved_datain;
- gen1 = l & bank->saved_risingdetect;
+ gen1 = l & bank->context.risingdetect;
gen1 &= ~(bank->saved_datain);
/* FIXME: Consider GPIO IRQs with level detections properly! */
- gen = l & (~(bank->saved_fallingdetect) & ~(bank->saved_risingdetect));
+ gen = l & (~(bank->context.fallingdetect) &
+ ~(bank->context.risingdetect));
/* Consider all GPIO IRQs needed to be updated */
gen |= gen0 | gen1;
@@ -1343,14 +1288,14 @@ static int omap_gpio_runtime_resume(struct device *dev)
old0 = __raw_readl(bank->base + bank->regs->leveldetect0);
old1 = __raw_readl(bank->base + bank->regs->leveldetect1);
- if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+ if (!bank->regs->irqstatus_raw0) {
__raw_writel(old0 | gen, bank->base +
bank->regs->leveldetect0);
__raw_writel(old1 | gen, bank->base +
bank->regs->leveldetect1);
}
- if (cpu_is_omap44xx()) {
+ if (bank->regs->irqstatus_raw0) {
__raw_writel(old0 | l, bank->base +
bank->regs->leveldetect0);
__raw_writel(old1 | l, bank->base +
@@ -1429,14 +1374,11 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
}
#endif /* CONFIG_PM_RUNTIME */
#else
-#define omap_gpio_suspend NULL
-#define omap_gpio_resume NULL
#define omap_gpio_runtime_suspend NULL
#define omap_gpio_runtime_resume NULL
#endif
static const struct dev_pm_ops gpio_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(omap_gpio_suspend, omap_gpio_resume)
SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume,
NULL)
};
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index d3f3e8f54561..1c313c710be3 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -28,6 +28,8 @@
#define PCA953X_INVERT 2
#define PCA953X_DIRECTION 3
+#define REG_ADDR_AI 0x80
+
#define PCA957X_IN 0
#define PCA957X_INVRT 1
#define PCA957X_BKEN 2
@@ -63,15 +65,15 @@ static const struct i2c_device_id pca953x_id[] = {
{ "pca6107", 8 | PCA953X_TYPE | PCA_INT, },
{ "tca6408", 8 | PCA953X_TYPE | PCA_INT, },
{ "tca6416", 16 | PCA953X_TYPE | PCA_INT, },
- /* NYET: { "tca6424", 24, }, */
+ { "tca6424", 24 | PCA953X_TYPE | PCA_INT, },
{ }
};
MODULE_DEVICE_TABLE(i2c, pca953x_id);
struct pca953x_chip {
unsigned gpio_start;
- uint16_t reg_output;
- uint16_t reg_direction;
+ u32 reg_output;
+ u32 reg_direction;
struct mutex i2c_lock;
#ifdef CONFIG_GPIO_PCA953X_IRQ
@@ -89,12 +91,20 @@ struct pca953x_chip {
int chip_type;
};
-static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val)
+static int pca953x_write_reg(struct pca953x_chip *chip, int reg, u32 val)
{
int ret = 0;
if (chip->gpio_chip.ngpio <= 8)
ret = i2c_smbus_write_byte_data(chip->client, reg, val);
+ else if (chip->gpio_chip.ngpio == 24) {
+ ret = i2c_smbus_write_word_data(chip->client,
+ (reg << 2) | REG_ADDR_AI,
+ val & 0xffff);
+ ret = i2c_smbus_write_byte_data(chip->client,
+ (reg << 2) + 2,
+ (val & 0xff0000) >> 16);
+ }
else {
switch (chip->chip_type) {
case PCA953X_TYPE:
@@ -121,12 +131,17 @@ static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val)
return 0;
}
-static int pca953x_read_reg(struct pca953x_chip *chip, int reg, uint16_t *val)
+static int pca953x_read_reg(struct pca953x_chip *chip, int reg, u32 *val)
{
int ret;
if (chip->gpio_chip.ngpio <= 8)
ret = i2c_smbus_read_byte_data(chip->client, reg);
+ else if (chip->gpio_chip.ngpio == 24) {
+ ret = i2c_smbus_read_word_data(chip->client, reg << 2);
+ ret |= (i2c_smbus_read_byte_data(chip->client,
+ (reg << 2) + 2)<<16);
+ }
else
ret = i2c_smbus_read_word_data(chip->client, reg << 1);
@@ -135,14 +150,14 @@ static int pca953x_read_reg(struct pca953x_chip *chip, int reg, uint16_t *val)
return ret;
}
- *val = (uint16_t)ret;
+ *val = (u32)ret;
return 0;
}
static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
{
struct pca953x_chip *chip;
- uint16_t reg_val;
+ uint reg_val;
int ret, offset = 0;
chip = container_of(gc, struct pca953x_chip, gpio_chip);
@@ -173,7 +188,7 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
unsigned off, int val)
{
struct pca953x_chip *chip;
- uint16_t reg_val;
+ uint reg_val;
int ret, offset = 0;
chip = container_of(gc, struct pca953x_chip, gpio_chip);
@@ -223,7 +238,7 @@ exit:
static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
{
struct pca953x_chip *chip;
- uint16_t reg_val;
+ u32 reg_val;
int ret, offset = 0;
chip = container_of(gc, struct pca953x_chip, gpio_chip);
@@ -253,7 +268,7 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
{
struct pca953x_chip *chip;
- uint16_t reg_val;
+ u32 reg_val;
int ret, offset = 0;
chip = container_of(gc, struct pca953x_chip, gpio_chip);
@@ -386,7 +401,7 @@ static struct irq_chip pca953x_irq_chip = {
static uint16_t pca953x_irq_pending(struct pca953x_chip *chip)
{
- uint16_t cur_stat;
+ u32 cur_stat;
uint16_t old_stat;
uint16_t pending;
uint16_t trigger;
@@ -449,6 +464,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
{
struct i2c_client *client = chip->client;
int ret, offset = 0;
+ u32 temporary;
if (irq_base != -1
&& (id->driver_data & PCA_INT)) {
@@ -462,7 +478,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
offset = PCA957X_IN;
break;
}
- ret = pca953x_read_reg(chip, offset, &chip->irq_stat);
+ ret = pca953x_read_reg(chip, offset, &temporary);
+ chip->irq_stat = temporary;
if (ret)
goto out_failed;
@@ -603,7 +620,7 @@ out:
static int __devinit device_pca957x_init(struct pca953x_chip *chip, int invert)
{
int ret;
- uint16_t val = 0;
+ u32 val = 0;
/* Let every port in proper state, that could save power */
pca953x_write_reg(chip, PCA957X_PUPD, 0x0);
diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c
index 2cd958e0b822..139ad3e20011 100644
--- a/drivers/gpio/gpio-pch.c
+++ b/drivers/gpio/gpio-pch.c
@@ -538,17 +538,7 @@ static struct pci_driver pch_gpio_driver = {
.resume = pch_gpio_resume
};
-static int __init pch_gpio_pci_init(void)
-{
- return pci_register_driver(&pch_gpio_driver);
-}
-module_init(pch_gpio_pci_init);
-
-static void __exit pch_gpio_pci_exit(void)
-{
- pci_unregister_driver(&pch_gpio_driver);
-}
-module_exit(pch_gpio_pci_exit);
+module_pci_driver(pch_gpio_driver);
MODULE_DESCRIPTION("PCH GPIO PCI Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index fc3ace3fd4cb..58a6a63a6ece 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -11,13 +11,17 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <linux/module.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/gpio-pxa.h>
#include <linux/init.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/syscore_ops.h>
#include <linux/slab.h>
@@ -56,6 +60,10 @@
int pxa_last_gpio;
+#ifdef CONFIG_OF
+static struct irq_domain *domain;
+#endif
+
struct pxa_gpio_chip {
struct gpio_chip chip;
void __iomem *regbase;
@@ -81,7 +89,6 @@ enum {
PXA3XX_GPIO,
PXA93X_GPIO,
MMP_GPIO = 0x10,
- MMP2_GPIO,
};
static DEFINE_SPINLOCK(gpio_lock);
@@ -475,22 +482,92 @@ static int pxa_gpio_nums(void)
gpio_type = MMP_GPIO;
} else if (cpu_is_mmp2()) {
count = 191;
- gpio_type = MMP2_GPIO;
+ gpio_type = MMP_GPIO;
}
#endif /* CONFIG_ARCH_MMP */
return count;
}
+static struct of_device_id pxa_gpio_dt_ids[] = {
+ { .compatible = "mrvl,pxa-gpio" },
+ { .compatible = "mrvl,mmp-gpio", .data = (void *)MMP_GPIO },
+ {}
+};
+
+static int pxa_irq_domain_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hw)
+{
+ irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
+ handle_edge_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ return 0;
+}
+
+const struct irq_domain_ops pxa_irq_domain_ops = {
+ .map = pxa_irq_domain_map,
+};
+
+#ifdef CONFIG_OF
+static int __devinit pxa_gpio_probe_dt(struct platform_device *pdev)
+{
+ int ret, nr_banks, nr_gpios, irq_base;
+ struct device_node *prev, *next, *np = pdev->dev.of_node;
+ const struct of_device_id *of_id =
+ of_match_device(pxa_gpio_dt_ids, &pdev->dev);
+
+ if (!of_id) {
+ dev_err(&pdev->dev, "Failed to find gpio controller\n");
+ return -EFAULT;
+ }
+ gpio_type = (int)of_id->data;
+
+ next = of_get_next_child(np, NULL);
+ prev = next;
+ if (!next) {
+ dev_err(&pdev->dev, "Failed to find child gpio node\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ for (nr_banks = 1; ; nr_banks++) {
+ next = of_get_next_child(np, prev);
+ if (!next)
+ break;
+ prev = next;
+ }
+ of_node_put(prev);
+ nr_gpios = nr_banks << 5;
+ pxa_last_gpio = nr_gpios - 1;
+
+ irq_base = irq_alloc_descs(-1, 0, nr_gpios, 0);
+ if (irq_base < 0) {
+ dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n");
+ goto err;
+ }
+ domain = irq_domain_add_legacy(np, nr_gpios, irq_base, 0,
+ &pxa_irq_domain_ops, NULL);
+ return 0;
+err:
+ iounmap(gpio_reg_base);
+ return ret;
+}
+#else
+#define pxa_gpio_probe_dt(pdev) (-1)
+#endif
+
static int __devinit pxa_gpio_probe(struct platform_device *pdev)
{
struct pxa_gpio_chip *c;
struct resource *res;
struct clk *clk;
struct pxa_gpio_platform_data *info;
- int gpio, irq, ret;
+ int gpio, irq, ret, use_of = 0;
int irq0 = 0, irq1 = 0, irq_mux, gpio_offset = 0;
- pxa_last_gpio = pxa_gpio_nums();
+ ret = pxa_gpio_probe_dt(pdev);
+ if (ret < 0)
+ pxa_last_gpio = pxa_gpio_nums();
+ else
+ use_of = 1;
if (!pxa_last_gpio)
return -EINVAL;
@@ -545,25 +622,27 @@ static int __devinit pxa_gpio_probe(struct platform_device *pdev)
writel_relaxed(~0, c->regbase + ED_MASK_OFFSET);
}
+ if (!use_of) {
#ifdef CONFIG_ARCH_PXA
- irq = gpio_to_irq(0);
- irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
- handle_edge_irq);
- set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
- irq_set_chained_handler(IRQ_GPIO0, pxa_gpio_demux_handler);
-
- irq = gpio_to_irq(1);
- irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
- handle_edge_irq);
- set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
- irq_set_chained_handler(IRQ_GPIO1, pxa_gpio_demux_handler);
-#endif
+ irq = gpio_to_irq(0);
+ irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
+ handle_edge_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ irq_set_chained_handler(IRQ_GPIO0, pxa_gpio_demux_handler);
- for (irq = gpio_to_irq(gpio_offset);
- irq <= gpio_to_irq(pxa_last_gpio); irq++) {
+ irq = gpio_to_irq(1);
irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
handle_edge_irq);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ irq_set_chained_handler(IRQ_GPIO1, pxa_gpio_demux_handler);
+#endif
+
+ for (irq = gpio_to_irq(gpio_offset);
+ irq <= gpio_to_irq(pxa_last_gpio); irq++) {
+ irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
+ handle_edge_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ }
}
irq_set_chained_handler(irq_mux, pxa_gpio_demux_handler);
@@ -574,6 +653,7 @@ static struct platform_driver pxa_gpio_driver = {
.probe = pxa_gpio_probe,
.driver = {
.name = "pxa-gpio",
+ .of_match_table = pxa_gpio_dt_ids,
},
};
diff --git a/drivers/gpio/gpio-rc5t583.c b/drivers/gpio/gpio-rc5t583.c
new file mode 100644
index 000000000000..08428bf17718
--- /dev/null
+++ b/drivers/gpio/gpio-rc5t583.c
@@ -0,0 +1,180 @@
+/*
+ * GPIO driver for RICOH583 power management chip.
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ * Author: Laxman dewangan <ldewangan@nvidia.com>
+ *
+ * Based on code
+ * Copyright (C) 2011 RICOH COMPANY,LTD
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/mfd/rc5t583.h>
+
+struct rc5t583_gpio {
+ struct gpio_chip gpio_chip;
+ struct rc5t583 *rc5t583;
+};
+
+static inline struct rc5t583_gpio *to_rc5t583_gpio(struct gpio_chip *chip)
+{
+ return container_of(chip, struct rc5t583_gpio, gpio_chip);
+}
+
+static int rc5t583_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+ struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+ struct device *parent = rc5t583_gpio->rc5t583->dev;
+ uint8_t val = 0;
+ int ret;
+
+ ret = rc5t583_read(parent, RC5T583_GPIO_MON_IOIN, &val);
+ if (ret < 0)
+ return ret;
+
+ return !!(val & BIT(offset));
+}
+
+static void rc5t583_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
+{
+ struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+ struct device *parent = rc5t583_gpio->rc5t583->dev;
+ if (val)
+ rc5t583_set_bits(parent, RC5T583_GPIO_IOOUT, BIT(offset));
+ else
+ rc5t583_clear_bits(parent, RC5T583_GPIO_IOOUT, BIT(offset));
+}
+
+static int rc5t583_gpio_dir_input(struct gpio_chip *gc, unsigned int offset)
+{
+ struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+ struct device *parent = rc5t583_gpio->rc5t583->dev;
+ int ret;
+
+ ret = rc5t583_clear_bits(parent, RC5T583_GPIO_IOSEL, BIT(offset));
+ if (ret < 0)
+ return ret;
+
+ /* Set pin to gpio mode */
+ return rc5t583_clear_bits(parent, RC5T583_GPIO_PGSEL, BIT(offset));
+}
+
+static int rc5t583_gpio_dir_output(struct gpio_chip *gc, unsigned offset,
+ int value)
+{
+ struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+ struct device *parent = rc5t583_gpio->rc5t583->dev;
+ int ret;
+
+ rc5t583_gpio_set(gc, offset, value);
+ ret = rc5t583_set_bits(parent, RC5T583_GPIO_IOSEL, BIT(offset));
+ if (ret < 0)
+ return ret;
+
+ /* Set pin to gpio mode */
+ return rc5t583_clear_bits(parent, RC5T583_GPIO_PGSEL, BIT(offset));
+}
+
+static int rc5t583_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+ struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+
+ if ((offset >= 0) && (offset < 8))
+ return rc5t583_gpio->rc5t583->irq_base +
+ RC5T583_IRQ_GPIO0 + offset;
+ return -EINVAL;
+}
+
+static void rc5t583_gpio_free(struct gpio_chip *gc, unsigned offset)
+{
+ struct rc5t583_gpio *rc5t583_gpio = to_rc5t583_gpio(gc);
+ struct device *parent = rc5t583_gpio->rc5t583->dev;
+
+ rc5t583_set_bits(parent, RC5T583_GPIO_PGSEL, BIT(offset));
+}
+
+static int __devinit rc5t583_gpio_probe(struct platform_device *pdev)
+{
+ struct rc5t583 *rc5t583 = dev_get_drvdata(pdev->dev.parent);
+ struct rc5t583_platform_data *pdata = dev_get_platdata(rc5t583->dev);
+ struct rc5t583_gpio *rc5t583_gpio;
+
+ rc5t583_gpio = devm_kzalloc(&pdev->dev, sizeof(*rc5t583_gpio),
+ GFP_KERNEL);
+ if (!rc5t583_gpio) {
+ dev_warn(&pdev->dev, "Mem allocation for rc5t583_gpio failed");
+ return -ENOMEM;
+ }
+
+ rc5t583_gpio->gpio_chip.label = "gpio-rc5t583",
+ rc5t583_gpio->gpio_chip.owner = THIS_MODULE,
+ rc5t583_gpio->gpio_chip.free = rc5t583_gpio_free,
+ rc5t583_gpio->gpio_chip.direction_input = rc5t583_gpio_dir_input,
+ rc5t583_gpio->gpio_chip.direction_output = rc5t583_gpio_dir_output,
+ rc5t583_gpio->gpio_chip.set = rc5t583_gpio_set,
+ rc5t583_gpio->gpio_chip.get = rc5t583_gpio_get,
+ rc5t583_gpio->gpio_chip.to_irq = rc5t583_gpio_to_irq,
+ rc5t583_gpio->gpio_chip.ngpio = RC5T583_MAX_GPIO,
+ rc5t583_gpio->gpio_chip.can_sleep = 1,
+ rc5t583_gpio->gpio_chip.dev = &pdev->dev;
+ rc5t583_gpio->gpio_chip.base = -1;
+ rc5t583_gpio->rc5t583 = rc5t583;
+
+ if (pdata && pdata->gpio_base)
+ rc5t583_gpio->gpio_chip.base = pdata->gpio_base;
+
+ platform_set_drvdata(pdev, rc5t583_gpio);
+
+ return gpiochip_add(&rc5t583_gpio->gpio_chip);
+}
+
+static int __devexit rc5t583_gpio_remove(struct platform_device *pdev)
+{
+ struct rc5t583_gpio *rc5t583_gpio = platform_get_drvdata(pdev);
+
+ return gpiochip_remove(&rc5t583_gpio->gpio_chip);
+}
+
+static struct platform_driver rc5t583_gpio_driver = {
+ .driver = {
+ .name = "rc5t583-gpio",
+ .owner = THIS_MODULE,
+ },
+ .probe = rc5t583_gpio_probe,
+ .remove = __devexit_p(rc5t583_gpio_remove),
+};
+
+static int __init rc5t583_gpio_init(void)
+{
+ return platform_driver_register(&rc5t583_gpio_driver);
+}
+subsys_initcall(rc5t583_gpio_init);
+
+static void __exit rc5t583_gpio_exit(void)
+{
+ platform_driver_unregister(&rc5t583_gpio_driver);
+}
+module_exit(rc5t583_gpio_exit);
+
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_DESCRIPTION("GPIO interface for RC5T583");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:rc5t583-gpio");
diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c
index e991d9171961..421f6af0f995 100644
--- a/drivers/gpio/gpio-samsung.c
+++ b/drivers/gpio/gpio-samsung.c
@@ -2716,14 +2716,224 @@ static __init void exynos_gpiolib_attach_ofnode(struct samsung_gpio_chip *chip,
}
#endif /* defined(CONFIG_ARCH_EXYNOS) && defined(CONFIG_OF) */
+static __init void exynos4_gpiolib_init(void)
+{
+#ifdef CONFIG_CPU_EXYNOS4210
+ struct samsung_gpio_chip *chip;
+ int i, nr_chips;
+ void __iomem *gpio_base1, *gpio_base2, *gpio_base3;
+ int group = 0;
+ void __iomem *gpx_base;
+
+ /* gpio part1 */
+ gpio_base1 = ioremap(EXYNOS4_PA_GPIO1, SZ_4K);
+ if (gpio_base1 == NULL) {
+ pr_err("unable to ioremap for gpio_base1\n");
+ goto err_ioremap1;
+ }
+
+ chip = exynos4_gpios_1;
+ nr_chips = ARRAY_SIZE(exynos4_gpios_1);
+
+ for (i = 0; i < nr_chips; i++, chip++) {
+ if (!chip->config) {
+ chip->config = &exynos_gpio_cfg;
+ chip->group = group++;
+ }
+ exynos_gpiolib_attach_ofnode(chip,
+ EXYNOS4_PA_GPIO1, i * 0x20);
+ }
+ samsung_gpiolib_add_4bit_chips(exynos4_gpios_1,
+ nr_chips, gpio_base1);
+
+ /* gpio part2 */
+ gpio_base2 = ioremap(EXYNOS4_PA_GPIO2, SZ_4K);
+ if (gpio_base2 == NULL) {
+ pr_err("unable to ioremap for gpio_base2\n");
+ goto err_ioremap2;
+ }
+
+ /* need to set base address for gpx */
+ chip = &exynos4_gpios_2[16];
+ gpx_base = gpio_base2 + 0xC00;
+ for (i = 0; i < 4; i++, chip++, gpx_base += 0x20)
+ chip->base = gpx_base;
+
+ chip = exynos4_gpios_2;
+ nr_chips = ARRAY_SIZE(exynos4_gpios_2);
+
+ for (i = 0; i < nr_chips; i++, chip++) {
+ if (!chip->config) {
+ chip->config = &exynos_gpio_cfg;
+ chip->group = group++;
+ }
+ exynos_gpiolib_attach_ofnode(chip,
+ EXYNOS4_PA_GPIO2, i * 0x20);
+ }
+ samsung_gpiolib_add_4bit_chips(exynos4_gpios_2,
+ nr_chips, gpio_base2);
+
+ /* gpio part3 */
+ gpio_base3 = ioremap(EXYNOS4_PA_GPIO3, SZ_256);
+ if (gpio_base3 == NULL) {
+ pr_err("unable to ioremap for gpio_base3\n");
+ goto err_ioremap3;
+ }
+
+ chip = exynos4_gpios_3;
+ nr_chips = ARRAY_SIZE(exynos4_gpios_3);
+
+ for (i = 0; i < nr_chips; i++, chip++) {
+ if (!chip->config) {
+ chip->config = &exynos_gpio_cfg;
+ chip->group = group++;
+ }
+ exynos_gpiolib_attach_ofnode(chip,
+ EXYNOS4_PA_GPIO3, i * 0x20);
+ }
+ samsung_gpiolib_add_4bit_chips(exynos4_gpios_3,
+ nr_chips, gpio_base3);
+
+#if defined(CONFIG_CPU_EXYNOS4210) && defined(CONFIG_S5P_GPIO_INT)
+ s5p_register_gpioint_bank(IRQ_GPIO_XA, 0, IRQ_GPIO1_NR_GROUPS);
+ s5p_register_gpioint_bank(IRQ_GPIO_XB, IRQ_GPIO1_NR_GROUPS, IRQ_GPIO2_NR_GROUPS);
+#endif
+
+ return;
+
+err_ioremap3:
+ iounmap(gpio_base2);
+err_ioremap2:
+ iounmap(gpio_base1);
+err_ioremap1:
+ return;
+#endif /* CONFIG_CPU_EXYNOS4210 */
+}
+
+static __init void exynos5_gpiolib_init(void)
+{
+#ifdef CONFIG_SOC_EXYNOS5250
+ struct samsung_gpio_chip *chip;
+ int i, nr_chips;
+ void __iomem *gpio_base1, *gpio_base2, *gpio_base3, *gpio_base4;
+ int group = 0;
+ void __iomem *gpx_base;
+
+ /* gpio part1 */
+ gpio_base1 = ioremap(EXYNOS5_PA_GPIO1, SZ_4K);
+ if (gpio_base1 == NULL) {
+ pr_err("unable to ioremap for gpio_base1\n");
+ goto err_ioremap1;
+ }
+
+ /* need to set base address for gpx */
+ chip = &exynos5_gpios_1[20];
+ gpx_base = gpio_base1 + 0xC00;
+ for (i = 0; i < 4; i++, chip++, gpx_base += 0x20)
+ chip->base = gpx_base;
+
+ chip = exynos5_gpios_1;
+ nr_chips = ARRAY_SIZE(exynos5_gpios_1);
+
+ for (i = 0; i < nr_chips; i++, chip++) {
+ if (!chip->config) {
+ chip->config = &exynos_gpio_cfg;
+ chip->group = group++;
+ }
+ exynos_gpiolib_attach_ofnode(chip,
+ EXYNOS5_PA_GPIO1, i * 0x20);
+ }
+ samsung_gpiolib_add_4bit_chips(exynos5_gpios_1,
+ nr_chips, gpio_base1);
+
+ /* gpio part2 */
+ gpio_base2 = ioremap(EXYNOS5_PA_GPIO2, SZ_4K);
+ if (gpio_base2 == NULL) {
+ pr_err("unable to ioremap for gpio_base2\n");
+ goto err_ioremap2;
+ }
+
+ chip = exynos5_gpios_2;
+ nr_chips = ARRAY_SIZE(exynos5_gpios_2);
+
+ for (i = 0; i < nr_chips; i++, chip++) {
+ if (!chip->config) {
+ chip->config = &exynos_gpio_cfg;
+ chip->group = group++;
+ }
+ exynos_gpiolib_attach_ofnode(chip,
+ EXYNOS5_PA_GPIO2, i * 0x20);
+ }
+ samsung_gpiolib_add_4bit_chips(exynos5_gpios_2,
+ nr_chips, gpio_base2);
+
+ /* gpio part3 */
+ gpio_base3 = ioremap(EXYNOS5_PA_GPIO3, SZ_4K);
+ if (gpio_base3 == NULL) {
+ pr_err("unable to ioremap for gpio_base3\n");
+ goto err_ioremap3;
+ }
+
+ /* need to set base address for gpv */
+ exynos5_gpios_3[0].base = gpio_base3;
+ exynos5_gpios_3[1].base = gpio_base3 + 0x20;
+ exynos5_gpios_3[2].base = gpio_base3 + 0x60;
+ exynos5_gpios_3[3].base = gpio_base3 + 0x80;
+ exynos5_gpios_3[4].base = gpio_base3 + 0xC0;
+
+ chip = exynos5_gpios_3;
+ nr_chips = ARRAY_SIZE(exynos5_gpios_3);
+
+ for (i = 0; i < nr_chips; i++, chip++) {
+ if (!chip->config) {
+ chip->config = &exynos_gpio_cfg;
+ chip->group = group++;
+ }
+ exynos_gpiolib_attach_ofnode(chip,
+ EXYNOS5_PA_GPIO3, i * 0x20);
+ }
+ samsung_gpiolib_add_4bit_chips(exynos5_gpios_3,
+ nr_chips, gpio_base3);
+
+ /* gpio part4 */
+ gpio_base4 = ioremap(EXYNOS5_PA_GPIO4, SZ_4K);
+ if (gpio_base4 == NULL) {
+ pr_err("unable to ioremap for gpio_base4\n");
+ goto err_ioremap4;
+ }
+
+ chip = exynos5_gpios_4;
+ nr_chips = ARRAY_SIZE(exynos5_gpios_4);
+
+ for (i = 0; i < nr_chips; i++, chip++) {
+ if (!chip->config) {
+ chip->config = &exynos_gpio_cfg;
+ chip->group = group++;
+ }
+ exynos_gpiolib_attach_ofnode(chip,
+ EXYNOS5_PA_GPIO4, i * 0x20);
+ }
+ samsung_gpiolib_add_4bit_chips(exynos5_gpios_4,
+ nr_chips, gpio_base4);
+ return;
+
+err_ioremap4:
+ iounmap(gpio_base3);
+err_ioremap3:
+ iounmap(gpio_base2);
+err_ioremap2:
+ iounmap(gpio_base1);
+err_ioremap1:
+ return;
+
+#endif /* CONFIG_SOC_EXYNOS5250 */
+}
+
/* TODO: cleanup soc_is_* */
static __init int samsung_gpiolib_init(void)
{
struct samsung_gpio_chip *chip;
int i, nr_chips;
-#if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS5250)
- void __iomem *gpio_base1, *gpio_base2, *gpio_base3, *gpio_base4;
-#endif
int group = 0;
samsung_gpiolib_set_cfg(samsung_gpio_cfgs, ARRAY_SIZE(samsung_gpio_cfgs));
@@ -2789,202 +2999,15 @@ static __init int samsung_gpiolib_init(void)
s5p_register_gpioint_bank(IRQ_GPIOINT, 0, S5P_GPIOINT_GROUP_MAXNR);
#endif
} else if (soc_is_exynos4210()) {
-#ifdef CONFIG_CPU_EXYNOS4210
- void __iomem *gpx_base;
-
- /* gpio part1 */
- gpio_base1 = ioremap(EXYNOS4_PA_GPIO1, SZ_4K);
- if (gpio_base1 == NULL) {
- pr_err("unable to ioremap for gpio_base1\n");
- goto err_ioremap1;
- }
-
- chip = exynos4_gpios_1;
- nr_chips = ARRAY_SIZE(exynos4_gpios_1);
-
- for (i = 0; i < nr_chips; i++, chip++) {
- if (!chip->config) {
- chip->config = &exynos_gpio_cfg;
- chip->group = group++;
- }
- exynos_gpiolib_attach_ofnode(chip,
- EXYNOS4_PA_GPIO1, i * 0x20);
- }
- samsung_gpiolib_add_4bit_chips(exynos4_gpios_1,
- nr_chips, gpio_base1);
-
- /* gpio part2 */
- gpio_base2 = ioremap(EXYNOS4_PA_GPIO2, SZ_4K);
- if (gpio_base2 == NULL) {
- pr_err("unable to ioremap for gpio_base2\n");
- goto err_ioremap2;
- }
-
- /* need to set base address for gpx */
- chip = &exynos4_gpios_2[16];
- gpx_base = gpio_base2 + 0xC00;
- for (i = 0; i < 4; i++, chip++, gpx_base += 0x20)
- chip->base = gpx_base;
-
- chip = exynos4_gpios_2;
- nr_chips = ARRAY_SIZE(exynos4_gpios_2);
-
- for (i = 0; i < nr_chips; i++, chip++) {
- if (!chip->config) {
- chip->config = &exynos_gpio_cfg;
- chip->group = group++;
- }
- exynos_gpiolib_attach_ofnode(chip,
- EXYNOS4_PA_GPIO2, i * 0x20);
- }
- samsung_gpiolib_add_4bit_chips(exynos4_gpios_2,
- nr_chips, gpio_base2);
-
- /* gpio part3 */
- gpio_base3 = ioremap(EXYNOS4_PA_GPIO3, SZ_256);
- if (gpio_base3 == NULL) {
- pr_err("unable to ioremap for gpio_base3\n");
- goto err_ioremap3;
- }
-
- chip = exynos4_gpios_3;
- nr_chips = ARRAY_SIZE(exynos4_gpios_3);
-
- for (i = 0; i < nr_chips; i++, chip++) {
- if (!chip->config) {
- chip->config = &exynos_gpio_cfg;
- chip->group = group++;
- }
- exynos_gpiolib_attach_ofnode(chip,
- EXYNOS4_PA_GPIO3, i * 0x20);
- }
- samsung_gpiolib_add_4bit_chips(exynos4_gpios_3,
- nr_chips, gpio_base3);
-
-#if defined(CONFIG_CPU_EXYNOS4210) && defined(CONFIG_S5P_GPIO_INT)
- s5p_register_gpioint_bank(IRQ_GPIO_XA, 0, IRQ_GPIO1_NR_GROUPS);
- s5p_register_gpioint_bank(IRQ_GPIO_XB, IRQ_GPIO1_NR_GROUPS, IRQ_GPIO2_NR_GROUPS);
-#endif
-
-#endif /* CONFIG_CPU_EXYNOS4210 */
+ exynos4_gpiolib_init();
} else if (soc_is_exynos5250()) {
-#ifdef CONFIG_SOC_EXYNOS5250
- void __iomem *gpx_base;
-
- /* gpio part1 */
- gpio_base1 = ioremap(EXYNOS5_PA_GPIO1, SZ_4K);
- if (gpio_base1 == NULL) {
- pr_err("unable to ioremap for gpio_base1\n");
- goto err_ioremap1;
- }
-
- /* need to set base address for gpx */
- chip = &exynos5_gpios_1[20];
- gpx_base = gpio_base1 + 0xC00;
- for (i = 0; i < 4; i++, chip++, gpx_base += 0x20)
- chip->base = gpx_base;
-
- chip = exynos5_gpios_1;
- nr_chips = ARRAY_SIZE(exynos5_gpios_1);
-
- for (i = 0; i < nr_chips; i++, chip++) {
- if (!chip->config) {
- chip->config = &exynos_gpio_cfg;
- chip->group = group++;
- }
- exynos_gpiolib_attach_ofnode(chip,
- EXYNOS5_PA_GPIO1, i * 0x20);
- }
- samsung_gpiolib_add_4bit_chips(exynos5_gpios_1,
- nr_chips, gpio_base1);
-
- /* gpio part2 */
- gpio_base2 = ioremap(EXYNOS5_PA_GPIO2, SZ_4K);
- if (gpio_base2 == NULL) {
- pr_err("unable to ioremap for gpio_base2\n");
- goto err_ioremap2;
- }
-
- chip = exynos5_gpios_2;
- nr_chips = ARRAY_SIZE(exynos5_gpios_2);
-
- for (i = 0; i < nr_chips; i++, chip++) {
- if (!chip->config) {
- chip->config = &exynos_gpio_cfg;
- chip->group = group++;
- }
- exynos_gpiolib_attach_ofnode(chip,
- EXYNOS5_PA_GPIO2, i * 0x20);
- }
- samsung_gpiolib_add_4bit_chips(exynos5_gpios_2,
- nr_chips, gpio_base2);
-
- /* gpio part3 */
- gpio_base3 = ioremap(EXYNOS5_PA_GPIO3, SZ_4K);
- if (gpio_base3 == NULL) {
- pr_err("unable to ioremap for gpio_base3\n");
- goto err_ioremap3;
- }
-
- /* need to set base address for gpv */
- exynos5_gpios_3[0].base = gpio_base3;
- exynos5_gpios_3[1].base = gpio_base3 + 0x20;
- exynos5_gpios_3[2].base = gpio_base3 + 0x60;
- exynos5_gpios_3[3].base = gpio_base3 + 0x80;
- exynos5_gpios_3[4].base = gpio_base3 + 0xC0;
-
- chip = exynos5_gpios_3;
- nr_chips = ARRAY_SIZE(exynos5_gpios_3);
-
- for (i = 0; i < nr_chips; i++, chip++) {
- if (!chip->config) {
- chip->config = &exynos_gpio_cfg;
- chip->group = group++;
- }
- exynos_gpiolib_attach_ofnode(chip,
- EXYNOS5_PA_GPIO3, i * 0x20);
- }
- samsung_gpiolib_add_4bit_chips(exynos5_gpios_3,
- nr_chips, gpio_base3);
-
- /* gpio part4 */
- gpio_base4 = ioremap(EXYNOS5_PA_GPIO4, SZ_4K);
- if (gpio_base4 == NULL) {
- pr_err("unable to ioremap for gpio_base4\n");
- goto err_ioremap4;
- }
-
- chip = exynos5_gpios_4;
- nr_chips = ARRAY_SIZE(exynos5_gpios_4);
-
- for (i = 0; i < nr_chips; i++, chip++) {
- if (!chip->config) {
- chip->config = &exynos_gpio_cfg;
- chip->group = group++;
- }
- exynos_gpiolib_attach_ofnode(chip,
- EXYNOS5_PA_GPIO4, i * 0x20);
- }
- samsung_gpiolib_add_4bit_chips(exynos5_gpios_4,
- nr_chips, gpio_base4);
-#endif /* CONFIG_SOC_EXYNOS5250 */
+ exynos5_gpiolib_init();
} else {
WARN(1, "Unknown SoC in gpio-samsung, no GPIOs added\n");
return -ENODEV;
}
return 0;
-
-#if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS5250)
-err_ioremap4:
- iounmap(gpio_base3);
-err_ioremap3:
- iounmap(gpio_base2);
-err_ioremap2:
- iounmap(gpio_base1);
-err_ioremap1:
- return -ENOMEM;
-#endif
}
core_initcall(samsung_gpiolib_init);
diff --git a/drivers/gpio/gpio-sodaville.c b/drivers/gpio/gpio-sodaville.c
index 031e5d24837d..9d9891f7a607 100644
--- a/drivers/gpio/gpio-sodaville.c
+++ b/drivers/gpio/gpio-sodaville.c
@@ -224,7 +224,7 @@ static int __devinit sdv_gpio_probe(struct pci_dev *pdev,
ret = bgpio_init(&sd->bgpio, &pdev->dev, 4,
sd->gpio_pub_base + GPINR, sd->gpio_pub_base + GPOUTR,
- NULL, sd->gpio_pub_base + GPOER, NULL, false);
+ NULL, sd->gpio_pub_base + GPOER, NULL, 0);
if (ret)
goto unmap;
sd->bgpio.gc.ngpio = SDV_NUM_PUB_GPIOS;
@@ -282,17 +282,7 @@ static struct pci_driver sdv_gpio_driver = {
.remove = sdv_gpio_remove,
};
-static int __init sdv_gpio_init(void)
-{
- return pci_register_driver(&sdv_gpio_driver);
-}
-module_init(sdv_gpio_init);
-
-static void __exit sdv_gpio_exit(void)
-{
- pci_unregister_driver(&sdv_gpio_driver);
-}
-module_exit(sdv_gpio_exit);
+module_pci_driver(sdv_gpio_driver);
MODULE_AUTHOR("Hans J. Koch <hjk@linutronix.de>");
MODULE_DESCRIPTION("GPIO interface for Intel Sodaville SoCs");
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 12f349b3830d..dc5184d57892 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -26,10 +26,10 @@
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/irqdomain.h>
+#include <linux/pinctrl/consumer.h>
#include <asm/mach/irq.h>
-#include <mach/gpio-tegra.h>
#include <mach/iomap.h>
#include <mach/suspend.h>
@@ -108,18 +108,29 @@ static void tegra_gpio_mask_write(u32 reg, int gpio, int value)
tegra_gpio_writel(val, reg);
}
-void tegra_gpio_enable(int gpio)
+static void tegra_gpio_enable(int gpio)
{
tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 1);
}
EXPORT_SYMBOL_GPL(tegra_gpio_enable);
-void tegra_gpio_disable(int gpio)
+static void tegra_gpio_disable(int gpio)
{
tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 0);
}
EXPORT_SYMBOL_GPL(tegra_gpio_disable);
+int tegra_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ return pinctrl_request_gpio(offset);
+}
+
+void tegra_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ pinctrl_free_gpio(offset);
+ tegra_gpio_disable(offset);
+}
+
static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
tegra_gpio_mask_write(GPIO_MSK_OUT(offset), offset, value);
@@ -133,6 +144,7 @@ static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset)
static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 0);
+ tegra_gpio_enable(offset);
return 0;
}
@@ -141,6 +153,7 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
{
tegra_gpio_set(chip, offset, value);
tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 1);
+ tegra_gpio_enable(offset);
return 0;
}
@@ -151,13 +164,14 @@ static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
static struct gpio_chip tegra_gpio_chip = {
.label = "tegra-gpio",
+ .request = tegra_gpio_request,
+ .free = tegra_gpio_free,
.direction_input = tegra_gpio_direction_input,
.get = tegra_gpio_get,
.direction_output = tegra_gpio_direction_output,
.set = tegra_gpio_set,
.to_irq = tegra_gpio_to_irq,
.base = 0,
- .ngpio = TEGRA_NR_GPIOS,
};
static void tegra_gpio_irq_ack(struct irq_data *d)
@@ -224,6 +238,9 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
spin_unlock_irqrestore(&bank->lvl_lock[port], flags);
+ tegra_gpio_mask_write(GPIO_MSK_OE(gpio), gpio, 0);
+ tegra_gpio_enable(gpio);
+
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
__irq_set_handler_locked(d->irq, handle_level_irq);
else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
@@ -490,20 +507,6 @@ static int __init tegra_gpio_init(void)
}
postcore_initcall(tegra_gpio_init);
-void tegra_gpio_config(struct tegra_gpio_table *table, int num)
-{
- int i;
-
- for (i = 0; i < num; i++) {
- int gpio = table[i].gpio;
-
- if (table[i].enable)
- tegra_gpio_enable(gpio);
- else
- tegra_gpio_disable(gpio);
- }
-}
-
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
diff --git a/drivers/of/gpio.c b/drivers/gpio/gpiolib-of.c
index bf984b6dc477..d18068a9f3ec 100644
--- a/drivers/of/gpio.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -15,11 +15,39 @@
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/io.h>
+#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/slab.h>
+/* Private data structure for of_gpiochip_is_match */
+struct gg_data {
+ enum of_gpio_flags *flags;
+ struct of_phandle_args gpiospec;
+
+ int out_gpio;
+};
+
+/* Private function for resolving node pointer to gpio_chip */
+static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data)
+{
+ struct gg_data *gg_data = data;
+ int ret;
+
+ if ((gc->of_node != gg_data->gpiospec.np) ||
+ (gc->of_gpio_n_cells != gg_data->gpiospec.args_count) ||
+ (!gc->of_xlate))
+ return false;
+
+ ret = gc->of_xlate(gc, &gg_data->gpiospec, gg_data->flags);
+ if (ret < 0)
+ return false;
+
+ gg_data->out_gpio = ret + gc->base;
+ return true;
+}
+
/**
* of_get_named_gpio_flags() - Get a GPIO number and flags to use with GPIO API
* @np: device node to get GPIO from
@@ -34,46 +62,25 @@
int of_get_named_gpio_flags(struct device_node *np, const char *propname,
int index, enum of_gpio_flags *flags)
{
+ struct gg_data gg_data = { .flags = flags, .out_gpio = -ENODEV };
int ret;
- struct gpio_chip *gc;
- struct of_phandle_args gpiospec;
+
+ /* .of_xlate might decide to not fill in the flags, so clear it. */
+ if (flags)
+ *flags = 0;
ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index,
- &gpiospec);
+ &gg_data.gpiospec);
if (ret) {
pr_debug("%s: can't parse gpios property\n", __func__);
- goto err0;
- }
-
- gc = of_node_to_gpiochip(gpiospec.np);
- if (!gc) {
- pr_debug("%s: gpio controller %s isn't registered\n",
- np->full_name, gpiospec.np->full_name);
- ret = -ENODEV;
- goto err1;
- }
-
- if (gpiospec.args_count != gc->of_gpio_n_cells) {
- pr_debug("%s: wrong #gpio-cells for %s\n",
- np->full_name, gpiospec.np->full_name);
- ret = -EINVAL;
- goto err1;
+ return -EINVAL;
}
- /* .xlate might decide to not fill in the flags, so clear it. */
- if (flags)
- *flags = 0;
-
- ret = gc->of_xlate(gc, &gpiospec, flags);
- if (ret < 0)
- goto err1;
+ gpiochip_find(&gg_data, of_gpiochip_find_and_xlate);
- ret += gc->base;
-err1:
- of_node_put(gpiospec.np);
-err0:
+ of_node_put(gg_data.gpiospec.np);
pr_debug("%s exited with status %d\n", __func__, ret);
- return ret;
+ return gg_data.out_gpio;
}
EXPORT_SYMBOL(of_get_named_gpio_flags);
@@ -227,14 +234,3 @@ void of_gpiochip_remove(struct gpio_chip *chip)
if (chip->of_node)
of_node_put(chip->of_node);
}
-
-/* Private function for resolving node pointer to gpio_chip */
-static int of_gpiochip_is_match(struct gpio_chip *chip, const void *data)
-{
- return chip->of_node == data;
-}
-
-struct gpio_chip *of_node_to_gpiochip(struct device_node *np)
-{
- return gpiochip_find(np, of_gpiochip_is_match);
-}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 5a75510d66bb..120b2a0e3167 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1093,7 +1093,7 @@ unlock:
if (status)
goto fail;
- pr_info("gpiochip_add: registered GPIOs %d to %d on device: %s\n",
+ pr_debug("gpiochip_add: registered GPIOs %d to %d on device: %s\n",
chip->base, chip->base + chip->ngpio - 1,
chip->label ? : "generic");
@@ -1154,9 +1154,9 @@ EXPORT_SYMBOL_GPL(gpiochip_remove);
* non-zero, this function will return to the caller and not iterate over any
* more gpio_chips.
*/
-struct gpio_chip *gpiochip_find(const void *data,
+struct gpio_chip *gpiochip_find(void *data,
int (*match)(struct gpio_chip *chip,
- const void *data))
+ void *data))
{
struct gpio_chip *chip = NULL;
unsigned long flags;
@@ -1302,8 +1302,18 @@ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)
(flags & GPIOF_INIT_HIGH) ? 1 : 0);
if (err)
- gpio_free(gpio);
+ goto free_gpio;
+
+ if (flags & GPIOF_EXPORT) {
+ err = gpio_export(gpio, flags & GPIOF_EXPORT_CHANGEABLE);
+ if (err)
+ goto free_gpio;
+ }
+
+ return 0;
+ free_gpio:
+ gpio_free(gpio);
return err;
}
EXPORT_SYMBOL_GPL(gpio_request_one);
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index e354bc0b052a..23120c00a881 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -186,3 +186,9 @@ source "drivers/gpu/drm/vmwgfx/Kconfig"
source "drivers/gpu/drm/gma500/Kconfig"
source "drivers/gpu/drm/udl/Kconfig"
+
+source "drivers/gpu/drm/ast/Kconfig"
+
+source "drivers/gpu/drm/mgag200/Kconfig"
+
+source "drivers/gpu/drm/cirrus/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index c20da5bda355..f65f65ed0ddf 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -34,6 +34,8 @@ obj-$(CONFIG_DRM_RADEON)+= radeon/
obj-$(CONFIG_DRM_MGA) += mga/
obj-$(CONFIG_DRM_I810) += i810/
obj-$(CONFIG_DRM_I915) += i915/
+obj-$(CONFIG_DRM_MGAG200) += mgag200/
+obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus/
obj-$(CONFIG_DRM_SIS) += sis/
obj-$(CONFIG_DRM_SAVAGE)+= savage/
obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/
@@ -42,4 +44,5 @@ obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
obj-$(CONFIG_DRM_EXYNOS) +=exynos/
obj-$(CONFIG_DRM_GMA500) += gma500/
obj-$(CONFIG_DRM_UDL) += udl/
+obj-$(CONFIG_DRM_AST) += ast/
obj-y += i2c/
diff --git a/drivers/gpu/drm/ast/Kconfig b/drivers/gpu/drm/ast/Kconfig
new file mode 100644
index 000000000000..a277b1257888
--- /dev/null
+++ b/drivers/gpu/drm/ast/Kconfig
@@ -0,0 +1,16 @@
+config DRM_AST
+ tristate "AST server chips"
+ depends on DRM && PCI && EXPERIMENTAL
+ select DRM_TTM
+ select FB_SYS_COPYAREA
+ select FB_SYS_FILLRECT
+ select FB_SYS_IMAGEBLIT
+ select DRM_KMS_HELPER
+ select DRM_TTM
+ help
+ Say yes for experimental AST GPU driver. Do not enable
+ this driver without having a working -modesetting,
+ and a version of AST that knows to fail if KMS
+ is bound to the driver. These GPUs are commonly found
+ in server chipsets.
+
diff --git a/drivers/gpu/drm/ast/Makefile b/drivers/gpu/drm/ast/Makefile
new file mode 100644
index 000000000000..8df4f284ee24
--- /dev/null
+++ b/drivers/gpu/drm/ast/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the drm device driver. This driver provides support for the
+# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
+
+ccflags-y := -Iinclude/drm
+
+ast-y := ast_drv.o ast_main.o ast_mode.o ast_fb.o ast_ttm.o ast_post.o
+
+obj-$(CONFIG_DRM_AST) := ast.o \ No newline at end of file
diff --git a/drivers/gpu/drm/ast/ast_dram_tables.h b/drivers/gpu/drm/ast/ast_dram_tables.h
new file mode 100644
index 000000000000..cc04539c0ff3
--- /dev/null
+++ b/drivers/gpu/drm/ast/ast_dram_tables.h
@@ -0,0 +1,144 @@
+#ifndef AST_DRAM_TABLES_H
+#define AST_DRAM_TABLES_H
+
+/* DRAM timing tables */
+struct ast_dramstruct {
+ u16 index;
+ u32 data;
+};
+
+static const struct ast_dramstruct ast2000_dram_table_data[] = {
+ { 0x0108, 0x00000000 },
+ { 0x0120, 0x00004a21 },
+ { 0xFF00, 0x00000043 },
+ { 0x0000, 0xFFFFFFFF },
+ { 0x0004, 0x00000089 },
+ { 0x0008, 0x22331353 },
+ { 0x000C, 0x0d07000b },
+ { 0x0010, 0x11113333 },
+ { 0x0020, 0x00110350 },
+ { 0x0028, 0x1e0828f0 },
+ { 0x0024, 0x00000001 },
+ { 0x001C, 0x00000000 },
+ { 0x0014, 0x00000003 },
+ { 0xFF00, 0x00000043 },
+ { 0x0018, 0x00000131 },
+ { 0x0014, 0x00000001 },
+ { 0xFF00, 0x00000043 },
+ { 0x0018, 0x00000031 },
+ { 0x0014, 0x00000001 },
+ { 0xFF00, 0x00000043 },
+ { 0x0028, 0x1e0828f1 },
+ { 0x0024, 0x00000003 },
+ { 0x002C, 0x1f0f28fb },
+ { 0x0030, 0xFFFFFE01 },
+ { 0xFFFF, 0xFFFFFFFF }
+};
+
+static const struct ast_dramstruct ast1100_dram_table_data[] = {
+ { 0x2000, 0x1688a8a8 },
+ { 0x2020, 0x000041f0 },
+ { 0xFF00, 0x00000043 },
+ { 0x0000, 0xfc600309 },
+ { 0x006C, 0x00909090 },
+ { 0x0064, 0x00050000 },
+ { 0x0004, 0x00000585 },
+ { 0x0008, 0x0011030f },
+ { 0x0010, 0x22201724 },
+ { 0x0018, 0x1e29011a },
+ { 0x0020, 0x00c82222 },
+ { 0x0014, 0x01001523 },
+ { 0x001C, 0x1024010d },
+ { 0x0024, 0x00cb2522 },
+ { 0x0038, 0xffffff82 },
+ { 0x003C, 0x00000000 },
+ { 0x0040, 0x00000000 },
+ { 0x0044, 0x00000000 },
+ { 0x0048, 0x00000000 },
+ { 0x004C, 0x00000000 },
+ { 0x0050, 0x00000000 },
+ { 0x0054, 0x00000000 },
+ { 0x0058, 0x00000000 },
+ { 0x005C, 0x00000000 },
+ { 0x0060, 0x032aa02a },
+ { 0x0064, 0x002d3000 },
+ { 0x0068, 0x00000000 },
+ { 0x0070, 0x00000000 },
+ { 0x0074, 0x00000000 },
+ { 0x0078, 0x00000000 },
+ { 0x007C, 0x00000000 },
+ { 0x0034, 0x00000001 },
+ { 0xFF00, 0x00000043 },
+ { 0x002C, 0x00000732 },
+ { 0x0030, 0x00000040 },
+ { 0x0028, 0x00000005 },
+ { 0x0028, 0x00000007 },
+ { 0x0028, 0x00000003 },
+ { 0x0028, 0x00000001 },
+ { 0x000C, 0x00005a08 },
+ { 0x002C, 0x00000632 },
+ { 0x0028, 0x00000001 },
+ { 0x0030, 0x000003c0 },
+ { 0x0028, 0x00000003 },
+ { 0x0030, 0x00000040 },
+ { 0x0028, 0x00000003 },
+ { 0x000C, 0x00005a21 },
+ { 0x0034, 0x00007c03 },
+ { 0x0120, 0x00004c41 },
+ { 0xffff, 0xffffffff },
+};
+
+static const struct ast_dramstruct ast2100_dram_table_data[] = {
+ { 0x2000, 0x1688a8a8 },
+ { 0x2020, 0x00004120 },
+ { 0xFF00, 0x00000043 },
+ { 0x0000, 0xfc600309 },
+ { 0x006C, 0x00909090 },
+ { 0x0064, 0x00070000 },
+ { 0x0004, 0x00000489 },
+ { 0x0008, 0x0011030f },
+ { 0x0010, 0x32302926 },
+ { 0x0018, 0x274c0122 },
+ { 0x0020, 0x00ce2222 },
+ { 0x0014, 0x01001523 },
+ { 0x001C, 0x1024010d },
+ { 0x0024, 0x00cb2522 },
+ { 0x0038, 0xffffff82 },
+ { 0x003C, 0x00000000 },
+ { 0x0040, 0x00000000 },
+ { 0x0044, 0x00000000 },
+ { 0x0048, 0x00000000 },
+ { 0x004C, 0x00000000 },
+ { 0x0050, 0x00000000 },
+ { 0x0054, 0x00000000 },
+ { 0x0058, 0x00000000 },
+ { 0x005C, 0x00000000 },
+ { 0x0060, 0x0f2aa02a },
+ { 0x0064, 0x003f3005 },
+ { 0x0068, 0x02020202 },
+ { 0x0070, 0x00000000 },
+ { 0x0074, 0x00000000 },
+ { 0x0078, 0x00000000 },
+ { 0x007C, 0x00000000 },
+ { 0x0034, 0x00000001 },
+ { 0xFF00, 0x00000043 },
+ { 0x002C, 0x00000942 },
+ { 0x0030, 0x00000040 },
+ { 0x0028, 0x00000005 },
+ { 0x0028, 0x00000007 },
+ { 0x0028, 0x00000003 },
+ { 0x0028, 0x00000001 },
+ { 0x000C, 0x00005a08 },
+ { 0x002C, 0x00000842 },
+ { 0x0028, 0x00000001 },
+ { 0x0030, 0x000003c0 },
+ { 0x0028, 0x00000003 },
+ { 0x0030, 0x00000040 },
+ { 0x0028, 0x00000003 },
+ { 0x000C, 0x00005a21 },
+ { 0x0034, 0x00007c03 },
+ { 0x0120, 0x00005061 },
+ { 0xffff, 0xffffffff },
+};
+
+#endif
diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c
new file mode 100644
index 000000000000..d0c4574ef49c
--- /dev/null
+++ b/drivers/gpu/drm/ast/ast_drv.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors: Dave Airlie <airlied@redhat.com>
+ */
+#include <linux/module.h>
+#include <linux/console.h>
+
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc_helper.h"
+
+#include "ast_drv.h"
+
+int ast_modeset = -1;
+
+MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
+module_param_named(modeset, ast_modeset, int, 0400);
+
+#define PCI_VENDOR_ASPEED 0x1a03
+
+static struct drm_driver driver;
+
+#define AST_VGA_DEVICE(id, info) { \
+ .class = PCI_BASE_CLASS_DISPLAY << 16, \
+ .class_mask = 0xff0000, \
+ .vendor = PCI_VENDOR_ASPEED, \
+ .device = id, \
+ .subvendor = PCI_ANY_ID, \
+ .subdevice = PCI_ANY_ID, \
+ .driver_data = (unsigned long) info }
+
+static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
+ AST_VGA_DEVICE(PCI_CHIP_AST2000, NULL),
+ AST_VGA_DEVICE(PCI_CHIP_AST2100, NULL),
+ /* AST_VGA_DEVICE(PCI_CHIP_AST1180, NULL), - don't bind to 1180 for now */
+ {0, 0, 0},
+};
+
+MODULE_DEVICE_TABLE(pci, pciidlist);
+
+static int __devinit
+ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ return drm_get_pci_dev(pdev, ent, &driver);
+}
+
+static void
+ast_pci_remove(struct pci_dev *pdev)
+{
+ struct drm_device *dev = pci_get_drvdata(pdev);
+
+ drm_put_dev(dev);
+}
+
+
+
+static int ast_drm_freeze(struct drm_device *dev)
+{
+ drm_kms_helper_poll_disable(dev);
+
+ pci_save_state(dev->pdev);
+
+ console_lock();
+ ast_fbdev_set_suspend(dev, 1);
+ console_unlock();
+ return 0;
+}
+
+static int ast_drm_thaw(struct drm_device *dev)
+{
+ int error = 0;
+
+ ast_post_gpu(dev);
+
+ drm_mode_config_reset(dev);
+ mutex_lock(&dev->mode_config.mutex);
+ drm_helper_resume_force_mode(dev);
+ mutex_unlock(&dev->mode_config.mutex);
+
+ console_lock();
+ ast_fbdev_set_suspend(dev, 0);
+ console_unlock();
+ return error;
+}
+
+static int ast_drm_resume(struct drm_device *dev)
+{
+ int ret;
+
+ if (pci_enable_device(dev->pdev))
+ return -EIO;
+
+ ret = ast_drm_thaw(dev);
+ if (ret)
+ return ret;
+
+ drm_kms_helper_poll_enable(dev);
+ return 0;
+}
+
+static int ast_pm_suspend(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *ddev = pci_get_drvdata(pdev);
+ int error;
+
+ error = ast_drm_freeze(ddev);
+ if (error)
+ return error;
+
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+ return 0;
+}
+static int ast_pm_resume(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *ddev = pci_get_drvdata(pdev);
+ return ast_drm_resume(ddev);
+}
+
+static int ast_pm_freeze(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *ddev = pci_get_drvdata(pdev);
+
+ if (!ddev || !ddev->dev_private)
+ return -ENODEV;
+ return ast_drm_freeze(ddev);
+
+}
+
+static int ast_pm_thaw(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *ddev = pci_get_drvdata(pdev);
+ return ast_drm_thaw(ddev);
+}
+
+static int ast_pm_poweroff(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct drm_device *ddev = pci_get_drvdata(pdev);
+
+ return ast_drm_freeze(ddev);
+}
+
+static const struct dev_pm_ops ast_pm_ops = {
+ .suspend = ast_pm_suspend,
+ .resume = ast_pm_resume,
+ .freeze = ast_pm_freeze,
+ .thaw = ast_pm_thaw,
+ .poweroff = ast_pm_poweroff,
+ .restore = ast_pm_resume,
+};
+
+static struct pci_driver ast_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = pciidlist,
+ .probe = ast_pci_probe,
+ .remove = ast_pci_remove,
+ .driver.pm = &ast_pm_ops,
+};
+
+static const struct file_operations ast_fops = {
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .unlocked_ioctl = drm_ioctl,
+ .mmap = ast_mmap,
+ .poll = drm_poll,
+ .fasync = drm_fasync,
+ .read = drm_read,
+};
+
+static struct drm_driver driver = {
+ .driver_features = DRIVER_USE_MTRR | DRIVER_MODESET | DRIVER_GEM,
+ .dev_priv_size = 0,
+
+ .load = ast_driver_load,
+ .unload = ast_driver_unload,
+
+ .fops = &ast_fops,
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+ .date = DRIVER_DATE,
+ .major = DRIVER_MAJOR,
+ .minor = DRIVER_MINOR,
+ .patchlevel = DRIVER_PATCHLEVEL,
+
+ .gem_init_object = ast_gem_init_object,
+ .gem_free_object = ast_gem_free_object,
+ .dumb_create = ast_dumb_create,
+ .dumb_map_offset = ast_dumb_mmap_offset,
+ .dumb_destroy = ast_dumb_destroy,
+
+};
+
+static int __init ast_init(void)
+{
+#ifdef CONFIG_VGA_CONSOLE
+ if (vgacon_text_force() && ast_modeset == -1)
+ return -EINVAL;
+#endif
+
+ if (ast_modeset == 0)
+ return -EINVAL;
+ return drm_pci_init(&driver, &ast_pci_driver);
+}
+static void __exit ast_exit(void)
+{
+ drm_pci_exit(&driver, &ast_pci_driver);
+}
+
+module_init(ast_init);
+module_exit(ast_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL and additional rights");
+
diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h
new file mode 100644
index 000000000000..d4af9edcbb97
--- /dev/null
+++ b/drivers/gpu/drm/ast/ast_drv.h
@@ -0,0 +1,356 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors: Dave Airlie <airlied@redhat.com>
+ */
+#ifndef __AST_DRV_H__
+#define __AST_DRV_H__
+
+#include "drm_fb_helper.h"
+
+#include "ttm/ttm_bo_api.h"
+#include "ttm/ttm_bo_driver.h"
+#include "ttm/ttm_placement.h"
+#include "ttm/ttm_memory.h"
+#include "ttm/ttm_module.h"
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#define DRIVER_AUTHOR "Dave Airlie"
+
+#define DRIVER_NAME "ast"
+#define DRIVER_DESC "AST"
+#define DRIVER_DATE "20120228"
+
+#define DRIVER_MAJOR 0
+#define DRIVER_MINOR 1
+#define DRIVER_PATCHLEVEL 0
+
+#define PCI_CHIP_AST2000 0x2000
+#define PCI_CHIP_AST2100 0x2010
+#define PCI_CHIP_AST1180 0x1180
+
+
+enum ast_chip {
+ AST2000,
+ AST2100,
+ AST1100,
+ AST2200,
+ AST2150,
+ AST2300,
+ AST1180,
+};
+
+#define AST_DRAM_512Mx16 0
+#define AST_DRAM_1Gx16 1
+#define AST_DRAM_512Mx32 2
+#define AST_DRAM_1Gx32 3
+#define AST_DRAM_2Gx16 6
+#define AST_DRAM_4Gx16 7
+
+struct ast_fbdev;
+
+struct ast_private {
+ struct drm_device *dev;
+
+ void __iomem *regs;
+ void __iomem *ioregs;
+
+ enum ast_chip chip;
+ bool vga2_clone;
+ uint32_t dram_bus_width;
+ uint32_t dram_type;
+ uint32_t mclk;
+ uint32_t vram_size;
+
+ struct ast_fbdev *fbdev;
+
+ int fb_mtrr;
+
+ struct {
+ struct drm_global_reference mem_global_ref;
+ struct ttm_bo_global_ref bo_global_ref;
+ struct ttm_bo_device bdev;
+ atomic_t validate_sequence;
+ } ttm;
+
+ struct drm_gem_object *cursor_cache;
+ uint64_t cursor_cache_gpu_addr;
+ struct ttm_bo_kmap_obj cache_kmap;
+ int next_cursor;
+};
+
+int ast_driver_load(struct drm_device *dev, unsigned long flags);
+int ast_driver_unload(struct drm_device *dev);
+
+struct ast_gem_object;
+
+#define AST_IO_AR_PORT_WRITE (0x40)
+#define AST_IO_MISC_PORT_WRITE (0x42)
+#define AST_IO_SEQ_PORT (0x44)
+#define AST_DAC_INDEX_READ (0x3c7)
+#define AST_IO_DAC_INDEX_WRITE (0x48)
+#define AST_IO_DAC_DATA (0x49)
+#define AST_IO_GR_PORT (0x4E)
+#define AST_IO_CRTC_PORT (0x54)
+#define AST_IO_INPUT_STATUS1_READ (0x5A)
+#define AST_IO_MISC_PORT_READ (0x4C)
+
+#define __ast_read(x) \
+static inline u##x ast_read##x(struct ast_private *ast, u32 reg) { \
+u##x val = 0;\
+val = ioread##x(ast->regs + reg); \
+return val;\
+}
+
+__ast_read(8);
+__ast_read(16);
+__ast_read(32)
+
+#define __ast_io_read(x) \
+static inline u##x ast_io_read##x(struct ast_private *ast, u32 reg) { \
+u##x val = 0;\
+val = ioread##x(ast->ioregs + reg); \
+return val;\
+}
+
+__ast_io_read(8);
+__ast_io_read(16);
+__ast_io_read(32);
+
+#define __ast_write(x) \
+static inline void ast_write##x(struct ast_private *ast, u32 reg, u##x val) {\
+ iowrite##x(val, ast->regs + reg);\
+ }
+
+__ast_write(8);
+__ast_write(16);
+__ast_write(32);
+
+#define __ast_io_write(x) \
+static inline void ast_io_write##x(struct ast_private *ast, u32 reg, u##x val) {\
+ iowrite##x(val, ast->ioregs + reg);\
+ }
+
+__ast_io_write(8);
+__ast_io_write(16);
+#undef __ast_io_write
+
+static inline void ast_set_index_reg(struct ast_private *ast,
+ uint32_t base, uint8_t index,
+ uint8_t val)
+{
+ ast_io_write16(ast, base, ((u16)val << 8) | index);
+}
+
+void ast_set_index_reg_mask(struct ast_private *ast,
+ uint32_t base, uint8_t index,
+ uint8_t mask, uint8_t val);
+uint8_t ast_get_index_reg(struct ast_private *ast,
+ uint32_t base, uint8_t index);
+uint8_t ast_get_index_reg_mask(struct ast_private *ast,
+ uint32_t base, uint8_t index, uint8_t mask);
+
+static inline void ast_open_key(struct ast_private *ast)
+{
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xA1, 0xFF, 0x04);
+}
+
+#define AST_VIDMEM_SIZE_8M 0x00800000
+#define AST_VIDMEM_SIZE_16M 0x01000000
+#define AST_VIDMEM_SIZE_32M 0x02000000
+#define AST_VIDMEM_SIZE_64M 0x04000000
+#define AST_VIDMEM_SIZE_128M 0x08000000
+
+#define AST_VIDMEM_DEFAULT_SIZE AST_VIDMEM_SIZE_8M
+
+#define AST_MAX_HWC_WIDTH 64
+#define AST_MAX_HWC_HEIGHT 64
+
+#define AST_HWC_SIZE (AST_MAX_HWC_WIDTH*AST_MAX_HWC_HEIGHT*2)
+#define AST_HWC_SIGNATURE_SIZE 32
+
+#define AST_DEFAULT_HWC_NUM 2
+/* define for signature structure */
+#define AST_HWC_SIGNATURE_CHECKSUM 0x00
+#define AST_HWC_SIGNATURE_SizeX 0x04
+#define AST_HWC_SIGNATURE_SizeY 0x08
+#define AST_HWC_SIGNATURE_X 0x0C
+#define AST_HWC_SIGNATURE_Y 0x10
+#define AST_HWC_SIGNATURE_HOTSPOTX 0x14
+#define AST_HWC_SIGNATURE_HOTSPOTY 0x18
+
+
+struct ast_i2c_chan {
+ struct i2c_adapter adapter;
+ struct drm_device *dev;
+ struct i2c_algo_bit_data bit;
+};
+
+struct ast_connector {
+ struct drm_connector base;
+ struct ast_i2c_chan *i2c;
+};
+
+struct ast_crtc {
+ struct drm_crtc base;
+ u8 lut_r[256], lut_g[256], lut_b[256];
+ struct drm_gem_object *cursor_bo;
+ uint64_t cursor_addr;
+ int cursor_width, cursor_height;
+ u8 offset_x, offset_y;
+};
+
+struct ast_encoder {
+ struct drm_encoder base;
+};
+
+struct ast_framebuffer {
+ struct drm_framebuffer base;
+ struct drm_gem_object *obj;
+};
+
+struct ast_fbdev {
+ struct drm_fb_helper helper;
+ struct ast_framebuffer afb;
+ struct list_head fbdev_list;
+ void *sysram;
+ int size;
+ struct ttm_bo_kmap_obj mapping;
+};
+
+#define to_ast_crtc(x) container_of(x, struct ast_crtc, base)
+#define to_ast_connector(x) container_of(x, struct ast_connector, base)
+#define to_ast_encoder(x) container_of(x, struct ast_encoder, base)
+#define to_ast_framebuffer(x) container_of(x, struct ast_framebuffer, base)
+
+struct ast_vbios_stdtable {
+ u8 misc;
+ u8 seq[4];
+ u8 crtc[25];
+ u8 ar[20];
+ u8 gr[9];
+};
+
+struct ast_vbios_enhtable {
+ u32 ht;
+ u32 hde;
+ u32 hfp;
+ u32 hsync;
+ u32 vt;
+ u32 vde;
+ u32 vfp;
+ u32 vsync;
+ u32 dclk_index;
+ u32 flags;
+ u32 refresh_rate;
+ u32 refresh_rate_index;
+ u32 mode_id;
+};
+
+struct ast_vbios_dclk_info {
+ u8 param1;
+ u8 param2;
+ u8 param3;
+};
+
+struct ast_vbios_mode_info {
+ struct ast_vbios_stdtable *std_table;
+ struct ast_vbios_enhtable *enh_table;
+};
+
+extern int ast_mode_init(struct drm_device *dev);
+extern void ast_mode_fini(struct drm_device *dev);
+
+int ast_framebuffer_init(struct drm_device *dev,
+ struct ast_framebuffer *ast_fb,
+ struct drm_mode_fb_cmd2 *mode_cmd,
+ struct drm_gem_object *obj);
+
+int ast_fbdev_init(struct drm_device *dev);
+void ast_fbdev_fini(struct drm_device *dev);
+void ast_fbdev_set_suspend(struct drm_device *dev, int state);
+
+struct ast_bo {
+ struct ttm_buffer_object bo;
+ struct ttm_placement placement;
+ struct ttm_bo_kmap_obj kmap;
+ struct drm_gem_object gem;
+ u32 placements[3];
+ int pin_count;
+};
+#define gem_to_ast_bo(gobj) container_of((gobj), struct ast_bo, gem)
+
+static inline struct ast_bo *
+ast_bo(struct ttm_buffer_object *bo)
+{
+ return container_of(bo, struct ast_bo, bo);
+}
+
+
+#define to_ast_obj(x) container_of(x, struct ast_gem_object, base)
+
+#define AST_MM_ALIGN_SHIFT 4
+#define AST_MM_ALIGN_MASK ((1 << AST_MM_ALIGN_SHIFT) - 1)
+
+extern int ast_dumb_create(struct drm_file *file,
+ struct drm_device *dev,
+ struct drm_mode_create_dumb *args);
+extern int ast_dumb_destroy(struct drm_file *file,
+ struct drm_device *dev,
+ uint32_t handle);
+
+extern int ast_gem_init_object(struct drm_gem_object *obj);
+extern void ast_gem_free_object(struct drm_gem_object *obj);
+extern int ast_dumb_mmap_offset(struct drm_file *file,
+ struct drm_device *dev,
+ uint32_t handle,
+ uint64_t *offset);
+
+#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
+
+int ast_mm_init(struct ast_private *ast);
+void ast_mm_fini(struct ast_private *ast);
+
+int ast_bo_create(struct drm_device *dev, int size, int align,
+ uint32_t flags, struct ast_bo **pastbo);
+
+int ast_gem_create(struct drm_device *dev,
+ u32 size, bool iskernel,
+ struct drm_gem_object **obj);
+
+int ast_bo_pin(struct ast_bo *bo, u32 pl_flag, u64 *gpu_addr);
+int ast_bo_unpin(struct ast_bo *bo);
+
+int ast_bo_reserve(struct ast_bo *bo, bool no_wait);
+void ast_bo_unreserve(struct ast_bo *bo);
+void ast_ttm_placement(struct ast_bo *bo, int domain);
+int ast_bo_push_sysram(struct ast_bo *bo);
+int ast_mmap(struct file *filp, struct vm_area_struct *vma);
+
+/* ast post */
+void ast_post_gpu(struct drm_device *dev);
+#endif
diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c
new file mode 100644
index 000000000000..2fc8e9e860b1
--- /dev/null
+++ b/drivers/gpu/drm/ast/ast_fb.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors: Dave Airlie <airlied@redhat.com>
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/sysrq.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+
+
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+#include "drm_fb_helper.h"
+#include "ast_drv.h"
+
+static void ast_dirty_update(struct ast_fbdev *afbdev,
+ int x, int y, int width, int height)
+{
+ int i;
+ struct drm_gem_object *obj;
+ struct ast_bo *bo;
+ int src_offset, dst_offset;
+ int bpp = (afbdev->afb.base.bits_per_pixel + 7)/8;
+ int ret;
+ bool unmap = false;
+
+ obj = afbdev->afb.obj;
+ bo = gem_to_ast_bo(obj);
+
+ ret = ast_bo_reserve(bo, true);
+ if (ret) {
+ DRM_ERROR("failed to reserve fb bo\n");
+ return;
+ }
+
+ if (!bo->kmap.virtual) {
+ ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
+ if (ret) {
+ DRM_ERROR("failed to kmap fb updates\n");
+ ast_bo_unreserve(bo);
+ return;
+ }
+ unmap = true;
+ }
+ for (i = y; i < y + height; i++) {
+ /* assume equal stride for now */
+ src_offset = dst_offset = i * afbdev->afb.base.pitches[0] + (x * bpp);
+ memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, width * bpp);
+
+ }
+ if (unmap)
+ ttm_bo_kunmap(&bo->kmap);
+
+ ast_bo_unreserve(bo);
+}
+
+static void ast_fillrect(struct fb_info *info,
+ const struct fb_fillrect *rect)
+{
+ struct ast_fbdev *afbdev = info->par;
+ sys_fillrect(info, rect);
+ ast_dirty_update(afbdev, rect->dx, rect->dy, rect->width,
+ rect->height);
+}
+
+static void ast_copyarea(struct fb_info *info,
+ const struct fb_copyarea *area)
+{
+ struct ast_fbdev *afbdev = info->par;
+ sys_copyarea(info, area);
+ ast_dirty_update(afbdev, area->dx, area->dy, area->width,
+ area->height);
+}
+
+static void ast_imageblit(struct fb_info *info,
+ const struct fb_image *image)
+{
+ struct ast_fbdev *afbdev = info->par;
+ sys_imageblit(info, image);
+ ast_dirty_update(afbdev, image->dx, image->dy, image->width,
+ image->height);
+}
+
+static struct fb_ops astfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = drm_fb_helper_check_var,
+ .fb_set_par = drm_fb_helper_set_par,
+ .fb_fillrect = ast_fillrect,
+ .fb_copyarea = ast_copyarea,
+ .fb_imageblit = ast_imageblit,
+ .fb_pan_display = drm_fb_helper_pan_display,
+ .fb_blank = drm_fb_helper_blank,
+ .fb_setcmap = drm_fb_helper_setcmap,
+ .fb_debug_enter = drm_fb_helper_debug_enter,
+ .fb_debug_leave = drm_fb_helper_debug_leave,
+};
+
+static int astfb_create_object(struct ast_fbdev *afbdev,
+ struct drm_mode_fb_cmd2 *mode_cmd,
+ struct drm_gem_object **gobj_p)
+{
+ struct drm_device *dev = afbdev->helper.dev;
+ u32 bpp, depth;
+ u32 size;
+ struct drm_gem_object *gobj;
+
+ int ret = 0;
+ drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp);
+
+ size = mode_cmd->pitches[0] * mode_cmd->height;
+ ret = ast_gem_create(dev, size, true, &gobj);
+ if (ret)
+ return ret;
+
+ *gobj_p = gobj;
+ return ret;
+}
+
+static int astfb_create(struct ast_fbdev *afbdev,
+ struct drm_fb_helper_surface_size *sizes)
+{
+ struct drm_device *dev = afbdev->helper.dev;
+ struct drm_mode_fb_cmd2 mode_cmd;
+ struct drm_framebuffer *fb;
+ struct fb_info *info;
+ int size, ret;
+ struct device *device = &dev->pdev->dev;
+ void *sysram;
+ struct drm_gem_object *gobj = NULL;
+ struct ast_bo *bo = NULL;
+ mode_cmd.width = sizes->surface_width;
+ mode_cmd.height = sizes->surface_height;
+ mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7)/8);
+
+ mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+ sizes->surface_depth);
+
+ size = mode_cmd.pitches[0] * mode_cmd.height;
+
+ ret = astfb_create_object(afbdev, &mode_cmd, &gobj);
+ if (ret) {
+ DRM_ERROR("failed to create fbcon backing object %d\n", ret);
+ return ret;
+ }
+ bo = gem_to_ast_bo(gobj);
+
+ sysram = vmalloc(size);
+ if (!sysram)
+ return -ENOMEM;
+
+ info = framebuffer_alloc(0, device);
+ if (!info) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ info->par = afbdev;
+
+ ret = ast_framebuffer_init(dev, &afbdev->afb, &mode_cmd, gobj);
+ if (ret)
+ goto out;
+
+ afbdev->sysram = sysram;
+ afbdev->size = size;
+
+ fb = &afbdev->afb.base;
+ afbdev->helper.fb = fb;
+ afbdev->helper.fbdev = info;
+
+ strcpy(info->fix.id, "astdrmfb");
+
+ info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
+ info->fbops = &astfb_ops;
+
+ ret = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (ret) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ info->apertures = alloc_apertures(1);
+ if (!info->apertures) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ info->apertures->ranges[0].base = pci_resource_start(dev->pdev, 0);
+ info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 0);
+
+ drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
+ drm_fb_helper_fill_var(info, &afbdev->helper, sizes->fb_width, sizes->fb_height);
+
+ info->screen_base = sysram;
+ info->screen_size = size;
+
+ info->pixmap.flags = FB_PIXMAP_SYSTEM;
+
+ DRM_DEBUG_KMS("allocated %dx%d\n",
+ fb->width, fb->height);
+
+ return 0;
+out:
+ return ret;
+}
+
+static void ast_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
+ u16 blue, int regno)
+{
+ struct ast_crtc *ast_crtc = to_ast_crtc(crtc);
+ ast_crtc->lut_r[regno] = red >> 8;
+ ast_crtc->lut_g[regno] = green >> 8;
+ ast_crtc->lut_b[regno] = blue >> 8;
+}
+
+static void ast_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
+ u16 *blue, int regno)
+{
+ struct ast_crtc *ast_crtc = to_ast_crtc(crtc);
+ *red = ast_crtc->lut_r[regno] << 8;
+ *green = ast_crtc->lut_g[regno] << 8;
+ *blue = ast_crtc->lut_b[regno] << 8;
+}
+
+static int ast_find_or_create_single(struct drm_fb_helper *helper,
+ struct drm_fb_helper_surface_size *sizes)
+{
+ struct ast_fbdev *afbdev = (struct ast_fbdev *)helper;
+ int new_fb = 0;
+ int ret;
+
+ if (!helper->fb) {
+ ret = astfb_create(afbdev, sizes);
+ if (ret)
+ return ret;
+ new_fb = 1;
+ }
+ return new_fb;
+}
+
+static struct drm_fb_helper_funcs ast_fb_helper_funcs = {
+ .gamma_set = ast_fb_gamma_set,
+ .gamma_get = ast_fb_gamma_get,
+ .fb_probe = ast_find_or_create_single,
+};
+
+static void ast_fbdev_destroy(struct drm_device *dev,
+ struct ast_fbdev *afbdev)
+{
+ struct fb_info *info;
+ struct ast_framebuffer *afb = &afbdev->afb;
+ if (afbdev->helper.fbdev) {
+ info = afbdev->helper.fbdev;
+ unregister_framebuffer(info);
+ if (info->cmap.len)
+ fb_dealloc_cmap(&info->cmap);
+ framebuffer_release(info);
+ }
+
+ if (afb->obj) {
+ drm_gem_object_unreference_unlocked(afb->obj);
+ afb->obj = NULL;
+ }
+ drm_fb_helper_fini(&afbdev->helper);
+
+ vfree(afbdev->sysram);
+ drm_framebuffer_cleanup(&afb->base);
+}
+
+int ast_fbdev_init(struct drm_device *dev)
+{
+ struct ast_private *ast = dev->dev_private;
+ struct ast_fbdev *afbdev;
+ int ret;
+
+ afbdev = kzalloc(sizeof(struct ast_fbdev), GFP_KERNEL);
+ if (!afbdev)
+ return -ENOMEM;
+
+ ast->fbdev = afbdev;
+ afbdev->helper.funcs = &ast_fb_helper_funcs;
+ ret = drm_fb_helper_init(dev, &afbdev->helper,
+ 1, 1);
+ if (ret) {
+ kfree(afbdev);
+ return ret;
+ }
+
+ drm_fb_helper_single_add_all_connectors(&afbdev->helper);
+ drm_fb_helper_initial_config(&afbdev->helper, 32);
+ return 0;
+}
+
+void ast_fbdev_fini(struct drm_device *dev)
+{
+ struct ast_private *ast = dev->dev_private;
+
+ if (!ast->fbdev)
+ return;
+
+ ast_fbdev_destroy(dev, ast->fbdev);
+ kfree(ast->fbdev);
+ ast->fbdev = NULL;
+}
+
+void ast_fbdev_set_suspend(struct drm_device *dev, int state)
+{
+ struct ast_private *ast = dev->dev_private;
+
+ if (!ast->fbdev)
+ return;
+
+ fb_set_suspend(ast->fbdev->helper.fbdev, state);
+}
diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c
new file mode 100644
index 000000000000..95ae55b8214b
--- /dev/null
+++ b/drivers/gpu/drm/ast/ast_main.c
@@ -0,0 +1,527 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors: Dave Airlie <airlied@redhat.com>
+ */
+#include "drmP.h"
+#include "ast_drv.h"
+
+
+#include "drm_fb_helper.h"
+#include "drm_crtc_helper.h"
+
+#include "ast_dram_tables.h"
+
+void ast_set_index_reg_mask(struct ast_private *ast,
+ uint32_t base, uint8_t index,
+ uint8_t mask, uint8_t val)
+{
+ u8 tmp;
+ ast_io_write8(ast, base, index);
+ tmp = (ast_io_read8(ast, base + 1) & mask) | val;
+ ast_set_index_reg(ast, base, index, tmp);
+}
+
+uint8_t ast_get_index_reg(struct ast_private *ast,
+ uint32_t base, uint8_t index)
+{
+ uint8_t ret;
+ ast_io_write8(ast, base, index);
+ ret = ast_io_read8(ast, base + 1);
+ return ret;
+}
+
+uint8_t ast_get_index_reg_mask(struct ast_private *ast,
+ uint32_t base, uint8_t index, uint8_t mask)
+{
+ uint8_t ret;
+ ast_io_write8(ast, base, index);
+ ret = ast_io_read8(ast, base + 1) & mask;
+ return ret;
+}
+
+
+static int ast_detect_chip(struct drm_device *dev)
+{
+ struct ast_private *ast = dev->dev_private;
+
+ if (dev->pdev->device == PCI_CHIP_AST1180) {
+ ast->chip = AST1100;
+ DRM_INFO("AST 1180 detected\n");
+ } else {
+ if (dev->pdev->revision >= 0x20) {
+ ast->chip = AST2300;
+ DRM_INFO("AST 2300 detected\n");
+ } else if (dev->pdev->revision >= 0x10) {
+ uint32_t data;
+ ast_write32(ast, 0xf004, 0x1e6e0000);
+ ast_write32(ast, 0xf000, 0x1);
+
+ data = ast_read32(ast, 0x1207c);
+ switch (data & 0x0300) {
+ case 0x0200:
+ ast->chip = AST1100;
+ DRM_INFO("AST 1100 detected\n");
+ break;
+ case 0x0100:
+ ast->chip = AST2200;
+ DRM_INFO("AST 2200 detected\n");
+ break;
+ case 0x0000:
+ ast->chip = AST2150;
+ DRM_INFO("AST 2150 detected\n");
+ break;
+ default:
+ ast->chip = AST2100;
+ DRM_INFO("AST 2100 detected\n");
+ break;
+ }
+ ast->vga2_clone = false;
+ } else {
+ ast->chip = 2000;
+ DRM_INFO("AST 2000 detected\n");
+ }
+ }
+ return 0;
+}
+
+static int ast_get_dram_info(struct drm_device *dev)
+{
+ struct ast_private *ast = dev->dev_private;
+ uint32_t data, data2;
+ uint32_t denum, num, div, ref_pll;
+
+ ast_write32(ast, 0xf004, 0x1e6e0000);
+ ast_write32(ast, 0xf000, 0x1);
+
+
+ ast_write32(ast, 0x10000, 0xfc600309);
+
+ do {
+ ;
+ } while (ast_read32(ast, 0x10000) != 0x01);
+ data = ast_read32(ast, 0x10004);
+
+ if (data & 0x400)
+ ast->dram_bus_width = 16;
+ else
+ ast->dram_bus_width = 32;
+
+ if (ast->chip == AST2300) {
+ switch (data & 0x03) {
+ case 0:
+ ast->dram_type = AST_DRAM_512Mx16;
+ break;
+ default:
+ case 1:
+ ast->dram_type = AST_DRAM_1Gx16;
+ break;
+ case 2:
+ ast->dram_type = AST_DRAM_2Gx16;
+ break;
+ case 3:
+ ast->dram_type = AST_DRAM_4Gx16;
+ break;
+ }
+ } else {
+ switch (data & 0x0c) {
+ case 0:
+ case 4:
+ ast->dram_type = AST_DRAM_512Mx16;
+ break;
+ case 8:
+ if (data & 0x40)
+ ast->dram_type = AST_DRAM_1Gx16;
+ else
+ ast->dram_type = AST_DRAM_512Mx32;
+ break;
+ case 0xc:
+ ast->dram_type = AST_DRAM_1Gx32;
+ break;
+ }
+ }
+
+ data = ast_read32(ast, 0x10120);
+ data2 = ast_read32(ast, 0x10170);
+ if (data2 & 0x2000)
+ ref_pll = 14318;
+ else
+ ref_pll = 12000;
+
+ denum = data & 0x1f;
+ num = (data & 0x3fe0) >> 5;
+ data = (data & 0xc000) >> 14;
+ switch (data) {
+ case 3:
+ div = 0x4;
+ break;
+ case 2:
+ case 1:
+ div = 0x2;
+ break;
+ default:
+ div = 0x1;
+ break;
+ }
+ ast->mclk = ref_pll * (num + 2) / (denum + 2) * (div * 1000);
+ return 0;
+}
+
+uint32_t ast_get_max_dclk(struct drm_device *dev, int bpp)
+{
+ struct ast_private *ast = dev->dev_private;
+ uint32_t dclk, jreg;
+ uint32_t dram_bus_width, mclk, dram_bandwidth, actual_dram_bandwidth, dram_efficency = 500;
+
+ dram_bus_width = ast->dram_bus_width;
+ mclk = ast->mclk;
+
+ if (ast->chip == AST2100 ||
+ ast->chip == AST1100 ||
+ ast->chip == AST2200 ||
+ ast->chip == AST2150 ||
+ ast->dram_bus_width == 16)
+ dram_efficency = 600;
+ else if (ast->chip == AST2300)
+ dram_efficency = 400;
+
+ dram_bandwidth = mclk * dram_bus_width * 2 / 8;
+ actual_dram_bandwidth = dram_bandwidth * dram_efficency / 1000;
+
+ if (ast->chip == AST1180)
+ dclk = actual_dram_bandwidth / ((bpp + 1) / 8);
+ else {
+ jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
+ if ((jreg & 0x08) && (ast->chip == AST2000))
+ dclk = actual_dram_bandwidth / ((bpp + 1 + 16) / 8);
+ else if ((jreg & 0x08) && (bpp == 8))
+ dclk = actual_dram_bandwidth / ((bpp + 1 + 24) / 8);
+ else
+ dclk = actual_dram_bandwidth / ((bpp + 1) / 8);
+ }
+
+ if (ast->chip == AST2100 ||
+ ast->chip == AST2200 ||
+ ast->chip == AST2300 ||
+ ast->chip == AST1180) {
+ if (dclk > 200)
+ dclk = 200;
+ } else {
+ if (dclk > 165)
+ dclk = 165;
+ }
+
+ return dclk;
+}
+
+static void ast_user_framebuffer_destroy(struct drm_framebuffer *fb)
+{
+ struct ast_framebuffer *ast_fb = to_ast_framebuffer(fb);
+ if (ast_fb->obj)
+ drm_gem_object_unreference_unlocked(ast_fb->obj);
+
+ drm_framebuffer_cleanup(fb);
+ kfree(fb);
+}
+
+static int ast_user_framebuffer_create_handle(struct drm_framebuffer *fb,
+ struct drm_file *file,
+ unsigned int *handle)
+{
+ return -EINVAL;
+}
+
+static const struct drm_framebuffer_funcs ast_fb_funcs = {
+ .destroy = ast_user_framebuffer_destroy,
+ .create_handle = ast_user_framebuffer_create_handle,
+};
+
+
+int ast_framebuffer_init(struct drm_device *dev,
+ struct ast_framebuffer *ast_fb,
+ struct drm_mode_fb_cmd2 *mode_cmd,
+ struct drm_gem_object *obj)
+{
+ int ret;
+
+ ret = drm_framebuffer_init(dev, &ast_fb->base, &ast_fb_funcs);
+ if (ret) {
+ DRM_ERROR("framebuffer init failed %d\n", ret);
+ return ret;
+ }
+ drm_helper_mode_fill_fb_struct(&ast_fb->base, mode_cmd);
+ ast_fb->obj = obj;
+ return 0;
+}
+
+static struct drm_framebuffer *
+ast_user_framebuffer_create(struct drm_device *dev,
+ struct drm_file *filp,
+ struct drm_mode_fb_cmd2 *mode_cmd)
+{
+ struct drm_gem_object *obj;
+ struct ast_framebuffer *ast_fb;
+ int ret;
+
+ obj = drm_gem_object_lookup(dev, filp, mode_cmd->handles[0]);
+ if (obj == NULL)
+ return ERR_PTR(-ENOENT);
+
+ ast_fb = kzalloc(sizeof(*ast_fb), GFP_KERNEL);
+ if (!ast_fb) {
+ drm_gem_object_unreference_unlocked(obj);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ ret = ast_framebuffer_init(dev, ast_fb, mode_cmd, obj);
+ if (ret) {
+ drm_gem_object_unreference_unlocked(obj);
+ kfree(ast_fb);
+ return ERR_PTR(ret);
+ }
+ return &ast_fb->base;
+}
+
+static const struct drm_mode_config_funcs ast_mode_funcs = {
+ .fb_create = ast_user_framebuffer_create,
+};
+
+static u32 ast_get_vram_info(struct drm_device *dev)
+{
+ struct ast_private *ast = dev->dev_private;
+ u8 jreg;
+
+ ast_open_key(ast);
+
+ jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xaa, 0xff);
+ switch (jreg & 3) {
+ case 0: return AST_VIDMEM_SIZE_8M;
+ case 1: return AST_VIDMEM_SIZE_16M;
+ case 2: return AST_VIDMEM_SIZE_32M;
+ case 3: return AST_VIDMEM_SIZE_64M;
+ }
+ return AST_VIDMEM_DEFAULT_SIZE;
+}
+
+int ast_driver_load(struct drm_device *dev, unsigned long flags)
+{
+ struct ast_private *ast;
+ int ret = 0;
+
+ ast = kzalloc(sizeof(struct ast_private), GFP_KERNEL);
+ if (!ast)
+ return -ENOMEM;
+
+ dev->dev_private = ast;
+ ast->dev = dev;
+
+ ast->regs = pci_iomap(dev->pdev, 1, 0);
+ if (!ast->regs) {
+ ret = -EIO;
+ goto out_free;
+ }
+ ast->ioregs = pci_iomap(dev->pdev, 2, 0);
+ if (!ast->ioregs) {
+ ret = -EIO;
+ goto out_free;
+ }
+
+ ast_detect_chip(dev);
+
+ if (ast->chip != AST1180) {
+ ast_get_dram_info(dev);
+ ast->vram_size = ast_get_vram_info(dev);
+ DRM_INFO("dram %d %d %d %08x\n", ast->mclk, ast->dram_type, ast->dram_bus_width, ast->vram_size);
+ }
+
+ ret = ast_mm_init(ast);
+ if (ret)
+ goto out_free;
+
+ drm_mode_config_init(dev);
+
+ dev->mode_config.funcs = (void *)&ast_mode_funcs;
+ dev->mode_config.min_width = 0;
+ dev->mode_config.min_height = 0;
+ dev->mode_config.preferred_depth = 24;
+ dev->mode_config.prefer_shadow = 1;
+
+ if (ast->chip == AST2100 ||
+ ast->chip == AST2200 ||
+ ast->chip == AST2300 ||
+ ast->chip == AST1180) {
+ dev->mode_config.max_width = 1920;
+ dev->mode_config.max_height = 2048;
+ } else {
+ dev->mode_config.max_width = 1600;
+ dev->mode_config.max_height = 1200;
+ }
+
+ ret = ast_mode_init(dev);
+ if (ret)
+ goto out_free;
+
+ ret = ast_fbdev_init(dev);
+ if (ret)
+ goto out_free;
+
+ return 0;
+out_free:
+ kfree(ast);
+ dev->dev_private = NULL;
+ return ret;
+}
+
+int ast_driver_unload(struct drm_device *dev)
+{
+ struct ast_private *ast = dev->dev_private;
+
+ ast_mode_fini(dev);
+ ast_fbdev_fini(dev);
+ drm_mode_config_cleanup(dev);
+
+ ast_mm_fini(ast);
+ pci_iounmap(dev->pdev, ast->ioregs);
+ pci_iounmap(dev->pdev, ast->regs);
+ kfree(ast);
+ return 0;
+}
+
+int ast_gem_create(struct drm_device *dev,
+ u32 size, bool iskernel,
+ struct drm_gem_object **obj)
+{
+ struct ast_bo *astbo;
+ int ret;
+
+ *obj = NULL;
+
+ size = roundup(size, PAGE_SIZE);
+ if (size == 0)
+ return -EINVAL;
+
+ ret = ast_bo_create(dev, size, 0, 0, &astbo);
+ if (ret) {
+ if (ret != -ERESTARTSYS)
+ DRM_ERROR("failed to allocate GEM object\n");
+ return ret;
+ }
+ *obj = &astbo->gem;
+ return 0;
+}
+
+int ast_dumb_create(struct drm_file *file,
+ struct drm_device *dev,
+ struct drm_mode_create_dumb *args)
+{
+ int ret;
+ struct drm_gem_object *gobj;
+ u32 handle;
+
+ args->pitch = args->width * ((args->bpp + 7) / 8);
+ args->size = args->pitch * args->height;
+
+ ret = ast_gem_create(dev, args->size, false,
+ &gobj);
+ if (ret)
+ return ret;
+
+ ret = drm_gem_handle_create(file, gobj, &handle);
+ drm_gem_object_unreference_unlocked(gobj);
+ if (ret)
+ return ret;
+
+ args->handle = handle;
+ return 0;
+}
+
+int ast_dumb_destroy(struct drm_file *file,
+ struct drm_device *dev,
+ uint32_t handle)
+{
+ return drm_gem_handle_delete(file, handle);
+}
+
+int ast_gem_init_object(struct drm_gem_object *obj)
+{
+ BUG();
+ return 0;
+}
+
+void ast_bo_unref(struct ast_bo **bo)
+{
+ struct ttm_buffer_object *tbo;
+
+ if ((*bo) == NULL)
+ return;
+
+ tbo = &((*bo)->bo);
+ ttm_bo_unref(&tbo);
+ if (tbo == NULL)
+ *bo = NULL;
+
+}
+void ast_gem_free_object(struct drm_gem_object *obj)
+{
+ struct ast_bo *ast_bo = gem_to_ast_bo(obj);
+
+ if (!ast_bo)
+ return;
+ ast_bo_unref(&ast_bo);
+}
+
+
+static inline u64 ast_bo_mmap_offset(struct ast_bo *bo)
+{
+ return bo->bo.addr_space_offset;
+}
+int
+ast_dumb_mmap_offset(struct drm_file *file,
+ struct drm_device *dev,
+ uint32_t handle,
+ uint64_t *offset)
+{
+ struct drm_gem_object *obj;
+ int ret;
+ struct ast_bo *bo;
+
+ mutex_lock(&dev->struct_mutex);
+ obj = drm_gem_object_lookup(dev, file, handle);
+ if (obj == NULL) {
+ ret = -ENOENT;
+ goto out_unlock;
+ }
+
+ bo = gem_to_ast_bo(obj);
+ *offset = ast_bo_mmap_offset(bo);
+
+ drm_gem_object_unreference(obj);
+ ret = 0;
+out_unlock:
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+
+}
+
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
new file mode 100644
index 000000000000..65f9d231af14
--- /dev/null
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -0,0 +1,1160 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ * Parts based on xf86-video-ast
+ * Copyright (c) 2005 ASPEED Technology Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors: Dave Airlie <airlied@redhat.com>
+ */
+#include <linux/export.h>
+#include "drmP.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+#include "ast_drv.h"
+
+#include "ast_tables.h"
+
+static struct ast_i2c_chan *ast_i2c_create(struct drm_device *dev);
+static void ast_i2c_destroy(struct ast_i2c_chan *i2c);
+static int ast_cursor_set(struct drm_crtc *crtc,
+ struct drm_file *file_priv,
+ uint32_t handle,
+ uint32_t width,
+ uint32_t height);
+static int ast_cursor_move(struct drm_crtc *crtc,
+ int x, int y);
+
+static inline void ast_load_palette_index(struct ast_private *ast,
+ u8 index, u8 red, u8 green,
+ u8 blue)
+{
+ ast_io_write8(ast, AST_IO_DAC_INDEX_WRITE, index);
+ ast_io_read8(ast, AST_IO_SEQ_PORT);
+ ast_io_write8(ast, AST_IO_DAC_DATA, red);
+ ast_io_read8(ast, AST_IO_SEQ_PORT);
+ ast_io_write8(ast, AST_IO_DAC_DATA, green);
+ ast_io_read8(ast, AST_IO_SEQ_PORT);
+ ast_io_write8(ast, AST_IO_DAC_DATA, blue);
+ ast_io_read8(ast, AST_IO_SEQ_PORT);
+}
+
+static void ast_crtc_load_lut(struct drm_crtc *crtc)
+{
+ struct ast_private *ast = crtc->dev->dev_private;
+ struct ast_crtc *ast_crtc = to_ast_crtc(crtc);
+ int i;
+
+ if (!crtc->enabled)
+ return;
+
+ for (i = 0; i < 256; i++)
+ ast_load_palette_index(ast, i, ast_crtc->lut_r[i],
+ ast_crtc->lut_g[i], ast_crtc->lut_b[i]);
+}
+
+static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode,
+ struct ast_vbios_mode_info *vbios_mode)
+{
+ struct ast_private *ast = crtc->dev->dev_private;
+ u32 refresh_rate_index = 0, mode_id, color_index, refresh_rate;
+ u32 hborder, vborder;
+
+ switch (crtc->fb->bits_per_pixel) {
+ case 8:
+ vbios_mode->std_table = &vbios_stdtable[VGAModeIndex];
+ color_index = VGAModeIndex - 1;
+ break;
+ case 16:
+ vbios_mode->std_table = &vbios_stdtable[HiCModeIndex];
+ color_index = HiCModeIndex;
+ break;
+ case 24:
+ case 32:
+ vbios_mode->std_table = &vbios_stdtable[TrueCModeIndex];
+ color_index = TrueCModeIndex;
+ break;
+ default:
+ return false;
+ }
+
+ switch (crtc->mode.crtc_hdisplay) {
+ case 640:
+ vbios_mode->enh_table = &res_640x480[refresh_rate_index];
+ break;
+ case 800:
+ vbios_mode->enh_table = &res_800x600[refresh_rate_index];
+ break;
+ case 1024:
+ vbios_mode->enh_table = &res_1024x768[refresh_rate_index];
+ break;
+ case 1280:
+ if (crtc->mode.crtc_vdisplay == 800)
+ vbios_mode->enh_table = &res_1280x800[refresh_rate_index];
+ else
+ vbios_mode->enh_table = &res_1280x1024[refresh_rate_index];
+ break;
+ case 1440:
+ vbios_mode->enh_table = &res_1440x900[refresh_rate_index];
+ break;
+ case 1600:
+ vbios_mode->enh_table = &res_1600x1200[refresh_rate_index];
+ break;
+ case 1680:
+ vbios_mode->enh_table = &res_1680x1050[refresh_rate_index];
+ break;
+ case 1920:
+ if (crtc->mode.crtc_vdisplay == 1080)
+ vbios_mode->enh_table = &res_1920x1080[refresh_rate_index];
+ else
+ vbios_mode->enh_table = &res_1920x1200[refresh_rate_index];
+ break;
+ default:
+ return false;
+ }
+
+ refresh_rate = drm_mode_vrefresh(mode);
+ while (vbios_mode->enh_table->refresh_rate < refresh_rate) {
+ vbios_mode->enh_table++;
+ if ((vbios_mode->enh_table->refresh_rate > refresh_rate) ||
+ (vbios_mode->enh_table->refresh_rate == 0xff)) {
+ vbios_mode->enh_table--;
+ break;
+ }
+ }
+
+ hborder = (vbios_mode->enh_table->flags & HBorder) ? 8 : 0;
+ vborder = (vbios_mode->enh_table->flags & VBorder) ? 8 : 0;
+
+ adjusted_mode->crtc_htotal = vbios_mode->enh_table->ht;
+ adjusted_mode->crtc_hblank_start = vbios_mode->enh_table->hde + hborder;
+ adjusted_mode->crtc_hblank_end = vbios_mode->enh_table->ht - hborder;
+ adjusted_mode->crtc_hsync_start = vbios_mode->enh_table->hde + hborder +
+ vbios_mode->enh_table->hfp;
+ adjusted_mode->crtc_hsync_end = (vbios_mode->enh_table->hde + hborder +
+ vbios_mode->enh_table->hfp +
+ vbios_mode->enh_table->hsync);
+
+ adjusted_mode->crtc_vtotal = vbios_mode->enh_table->vt;
+ adjusted_mode->crtc_vblank_start = vbios_mode->enh_table->vde + vborder;
+ adjusted_mode->crtc_vblank_end = vbios_mode->enh_table->vt - vborder;
+ adjusted_mode->crtc_vsync_start = vbios_mode->enh_table->vde + vborder +
+ vbios_mode->enh_table->vfp;
+ adjusted_mode->crtc_vsync_end = (vbios_mode->enh_table->vde + vborder +
+ vbios_mode->enh_table->vfp +
+ vbios_mode->enh_table->vsync);
+
+ refresh_rate_index = vbios_mode->enh_table->refresh_rate_index;
+ mode_id = vbios_mode->enh_table->mode_id;
+
+ if (ast->chip == AST1180) {
+ /* TODO 1180 */
+ } else {
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8c, (u8)((color_index & 0xf) << 4));
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8d, refresh_rate_index & 0xff);
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8e, mode_id & 0xff);
+
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0xa8);
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, crtc->fb->bits_per_pixel);
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x93, adjusted_mode->clock / 1000);
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x94, adjusted_mode->crtc_hdisplay);
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x95, adjusted_mode->crtc_hdisplay >> 8);
+
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x96, adjusted_mode->crtc_vdisplay);
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x97, adjusted_mode->crtc_vdisplay >> 8);
+ }
+
+ return true;
+
+
+}
+static void ast_set_std_reg(struct drm_crtc *crtc, struct drm_display_mode *mode,
+ struct ast_vbios_mode_info *vbios_mode)
+{
+ struct ast_private *ast = crtc->dev->dev_private;
+ struct ast_vbios_stdtable *stdtable;
+ u32 i;
+ u8 jreg;
+
+ stdtable = vbios_mode->std_table;
+
+ jreg = stdtable->misc;
+ ast_io_write8(ast, AST_IO_MISC_PORT_WRITE, jreg);
+
+ /* Set SEQ */
+ ast_set_index_reg(ast, AST_IO_SEQ_PORT, 0x00, 0x03);
+ for (i = 0; i < 4; i++) {
+ jreg = stdtable->seq[i];
+ if (!i)
+ jreg |= 0x20;
+ ast_set_index_reg(ast, AST_IO_SEQ_PORT, (i + 1) , jreg);
+ }
+
+ /* Set CRTC */
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x11, 0x7f, 0x00);
+ for (i = 0; i < 25; i++)
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, i, stdtable->crtc[i]);
+
+ /* set AR */
+ jreg = ast_io_read8(ast, AST_IO_INPUT_STATUS1_READ);
+ for (i = 0; i < 20; i++) {
+ jreg = stdtable->ar[i];
+ ast_io_write8(ast, AST_IO_AR_PORT_WRITE, (u8)i);
+ ast_io_write8(ast, AST_IO_AR_PORT_WRITE, jreg);
+ }
+ ast_io_write8(ast, AST_IO_AR_PORT_WRITE, 0x14);
+ ast_io_write8(ast, AST_IO_AR_PORT_WRITE, 0x00);
+
+ jreg = ast_io_read8(ast, AST_IO_INPUT_STATUS1_READ);
+ ast_io_write8(ast, AST_IO_AR_PORT_WRITE, 0x20);
+
+ /* Set GR */
+ for (i = 0; i < 9; i++)
+ ast_set_index_reg(ast, AST_IO_GR_PORT, i, stdtable->gr[i]);
+}
+
+static void ast_set_crtc_reg(struct drm_crtc *crtc, struct drm_display_mode *mode,
+ struct ast_vbios_mode_info *vbios_mode)
+{
+ struct ast_private *ast = crtc->dev->dev_private;
+ u8 jreg05 = 0, jreg07 = 0, jreg09 = 0, jregAC = 0, jregAD = 0, jregAE = 0;
+ u16 temp;
+
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x11, 0x7f, 0x00);
+
+ temp = (mode->crtc_htotal >> 3) - 5;
+ if (temp & 0x100)
+ jregAC |= 0x01; /* HT D[8] */
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x00, 0x00, temp);
+
+ temp = (mode->crtc_hdisplay >> 3) - 1;
+ if (temp & 0x100)
+ jregAC |= 0x04; /* HDE D[8] */
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x01, 0x00, temp);
+
+ temp = (mode->crtc_hblank_start >> 3) - 1;
+ if (temp & 0x100)
+ jregAC |= 0x10; /* HBS D[8] */
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x02, 0x00, temp);
+
+ temp = ((mode->crtc_hblank_end >> 3) - 1) & 0x7f;
+ if (temp & 0x20)
+ jreg05 |= 0x80; /* HBE D[5] */
+ if (temp & 0x40)
+ jregAD |= 0x01; /* HBE D[5] */
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x03, 0xE0, (temp & 0x1f));
+
+ temp = (mode->crtc_hsync_start >> 3) - 1;
+ if (temp & 0x100)
+ jregAC |= 0x40; /* HRS D[5] */
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x04, 0x00, temp);
+
+ temp = ((mode->crtc_hsync_end >> 3) - 1) & 0x3f;
+ if (temp & 0x20)
+ jregAD |= 0x04; /* HRE D[5] */
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x05, 0x60, (u8)((temp & 0x1f) | jreg05));
+
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xAC, 0x00, jregAC);
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xAD, 0x00, jregAD);
+
+ /* vert timings */
+ temp = (mode->crtc_vtotal) - 2;
+ if (temp & 0x100)
+ jreg07 |= 0x01;
+ if (temp & 0x200)
+ jreg07 |= 0x20;
+ if (temp & 0x400)
+ jregAE |= 0x01;
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x06, 0x00, temp);
+
+ temp = (mode->crtc_vsync_start) - 1;
+ if (temp & 0x100)
+ jreg07 |= 0x04;
+ if (temp & 0x200)
+ jreg07 |= 0x80;
+ if (temp & 0x400)
+ jregAE |= 0x08;
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x10, 0x00, temp);
+
+ temp = (mode->crtc_vsync_end - 1) & 0x3f;
+ if (temp & 0x10)
+ jregAE |= 0x20;
+ if (temp & 0x20)
+ jregAE |= 0x40;
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x11, 0x70, temp & 0xf);
+
+ temp = mode->crtc_vdisplay - 1;
+ if (temp & 0x100)
+ jreg07 |= 0x02;
+ if (temp & 0x200)
+ jreg07 |= 0x40;
+ if (temp & 0x400)
+ jregAE |= 0x02;
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x12, 0x00, temp);
+
+ temp = mode->crtc_vblank_start - 1;
+ if (temp & 0x100)
+ jreg07 |= 0x08;
+ if (temp & 0x200)
+ jreg09 |= 0x20;
+ if (temp & 0x400)
+ jregAE |= 0x04;
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x15, 0x00, temp);
+
+ temp = mode->crtc_vblank_end - 1;
+ if (temp & 0x100)
+ jregAE |= 0x10;
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x16, 0x00, temp);
+
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x07, 0x00, jreg07);
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x09, 0xdf, jreg09);
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xAE, 0x00, (jregAE | 0x80));
+
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x11, 0x7f, 0x80);
+}
+
+static void ast_set_offset_reg(struct drm_crtc *crtc)
+{
+ struct ast_private *ast = crtc->dev->dev_private;
+
+ u16 offset;
+
+ offset = crtc->fb->pitches[0] >> 3;
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x13, (offset & 0xff));
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xb0, (offset >> 8) & 0x3f);
+}
+
+static void ast_set_dclk_reg(struct drm_device *dev, struct drm_display_mode *mode,
+ struct ast_vbios_mode_info *vbios_mode)
+{
+ struct ast_private *ast = dev->dev_private;
+ struct ast_vbios_dclk_info *clk_info;
+
+ clk_info = &dclk_table[vbios_mode->enh_table->dclk_index];
+
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xc0, 0x00, clk_info->param1);
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xc1, 0x00, clk_info->param2);
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xbb, 0x0f,
+ (clk_info->param3 & 0x80) | ((clk_info->param3 & 0x3) << 4));
+}
+
+static void ast_set_ext_reg(struct drm_crtc *crtc, struct drm_display_mode *mode,
+ struct ast_vbios_mode_info *vbios_mode)
+{
+ struct ast_private *ast = crtc->dev->dev_private;
+ u8 jregA0 = 0, jregA3 = 0, jregA8 = 0;
+
+ switch (crtc->fb->bits_per_pixel) {
+ case 8:
+ jregA0 = 0x70;
+ jregA3 = 0x01;
+ jregA8 = 0x00;
+ break;
+ case 15:
+ case 16:
+ jregA0 = 0x70;
+ jregA3 = 0x04;
+ jregA8 = 0x02;
+ break;
+ case 32:
+ jregA0 = 0x70;
+ jregA3 = 0x08;
+ jregA8 = 0x02;
+ break;
+ }
+
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa0, 0x8f, jregA0);
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xf0, jregA3);
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa8, 0xfd, jregA8);
+
+ /* Set Threshold */
+ if (ast->chip == AST2300) {
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0x78);
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0x60);
+ } else if (ast->chip == AST2100 ||
+ ast->chip == AST1100 ||
+ ast->chip == AST2200 ||
+ ast->chip == AST2150) {
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0x3f);
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0x2f);
+ } else {
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0x2f);
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0x1f);
+ }
+}
+
+void ast_set_sync_reg(struct drm_device *dev, struct drm_display_mode *mode,
+ struct ast_vbios_mode_info *vbios_mode)
+{
+ struct ast_private *ast = dev->dev_private;
+ u8 jreg;
+
+ jreg = ast_io_read8(ast, AST_IO_MISC_PORT_READ);
+ jreg |= (vbios_mode->enh_table->flags & SyncNN);
+ ast_io_write8(ast, AST_IO_MISC_PORT_WRITE, jreg);
+}
+
+bool ast_set_dac_reg(struct drm_crtc *crtc, struct drm_display_mode *mode,
+ struct ast_vbios_mode_info *vbios_mode)
+{
+ switch (crtc->fb->bits_per_pixel) {
+ case 8:
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+void ast_set_start_address_crt1(struct drm_crtc *crtc, unsigned offset)
+{
+ struct ast_private *ast = crtc->dev->dev_private;
+ u32 addr;
+
+ addr = offset >> 2;
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x0d, (u8)(addr & 0xff));
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x0c, (u8)((addr >> 8) & 0xff));
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xaf, (u8)((addr >> 16) & 0xff));
+
+}
+
+static void ast_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+ struct ast_private *ast = crtc->dev->dev_private;
+
+ if (ast->chip == AST1180)
+ return;
+
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0);
+ ast_crtc_load_lut(crtc);
+ break;
+ case DRM_MODE_DPMS_OFF:
+ ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0x20);
+ break;
+ }
+}
+
+static bool ast_crtc_mode_fixup(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+/* ast is different - we will force move buffers out of VRAM */
+static int ast_crtc_do_set_base(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ int x, int y, int atomic)
+{
+ struct ast_private *ast = crtc->dev->dev_private;
+ struct drm_gem_object *obj;
+ struct ast_framebuffer *ast_fb;
+ struct ast_bo *bo;
+ int ret;
+ u64 gpu_addr;
+
+ /* push the previous fb to system ram */
+ if (!atomic && fb) {
+ ast_fb = to_ast_framebuffer(fb);
+ obj = ast_fb->obj;
+ bo = gem_to_ast_bo(obj);
+ ret = ast_bo_reserve(bo, false);
+ if (ret)
+ return ret;
+ ast_bo_push_sysram(bo);
+ ast_bo_unreserve(bo);
+ }
+
+ ast_fb = to_ast_framebuffer(crtc->fb);
+ obj = ast_fb->obj;
+ bo = gem_to_ast_bo(obj);
+
+ ret = ast_bo_reserve(bo, false);
+ if (ret)
+ return ret;
+
+ ret = ast_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
+ if (ret) {
+ ast_bo_unreserve(bo);
+ return ret;
+ }
+
+ if (&ast->fbdev->afb == ast_fb) {
+ /* if pushing console in kmap it */
+ ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
+ if (ret)
+ DRM_ERROR("failed to kmap fbcon\n");
+ }
+ ast_bo_unreserve(bo);
+
+ ast_set_start_address_crt1(crtc, (u32)gpu_addr);
+
+ return 0;
+}
+
+static int ast_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+ struct drm_framebuffer *old_fb)
+{
+ return ast_crtc_do_set_base(crtc, old_fb, x, y, 0);
+}
+
+static int ast_crtc_mode_set(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode,
+ int x, int y,
+ struct drm_framebuffer *old_fb)
+{
+ struct drm_device *dev = crtc->dev;
+ struct ast_private *ast = crtc->dev->dev_private;
+ struct ast_vbios_mode_info vbios_mode;
+ bool ret;
+ if (ast->chip == AST1180) {
+ DRM_ERROR("AST 1180 modesetting not supported\n");
+ return -EINVAL;
+ }
+
+ ret = ast_get_vbios_mode_info(crtc, mode, adjusted_mode, &vbios_mode);
+ if (ret == false)
+ return -EINVAL;
+ ast_open_key(ast);
+
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa1, 0xff, 0x04);
+
+ ast_set_std_reg(crtc, adjusted_mode, &vbios_mode);
+ ast_set_crtc_reg(crtc, adjusted_mode, &vbios_mode);
+ ast_set_offset_reg(crtc);
+ ast_set_dclk_reg(dev, adjusted_mode, &vbios_mode);
+ ast_set_ext_reg(crtc, adjusted_mode, &vbios_mode);
+ ast_set_sync_reg(dev, adjusted_mode, &vbios_mode);
+ ast_set_dac_reg(crtc, adjusted_mode, &vbios_mode);
+
+ ast_crtc_mode_set_base(crtc, x, y, old_fb);
+
+ return 0;
+}
+
+static void ast_crtc_disable(struct drm_crtc *crtc)
+{
+
+}
+
+static void ast_crtc_prepare(struct drm_crtc *crtc)
+{
+
+}
+
+static void ast_crtc_commit(struct drm_crtc *crtc)
+{
+ struct ast_private *ast = crtc->dev->dev_private;
+ ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0);
+}
+
+
+static const struct drm_crtc_helper_funcs ast_crtc_helper_funcs = {
+ .dpms = ast_crtc_dpms,
+ .mode_fixup = ast_crtc_mode_fixup,
+ .mode_set = ast_crtc_mode_set,
+ .mode_set_base = ast_crtc_mode_set_base,
+ .disable = ast_crtc_disable,
+ .load_lut = ast_crtc_load_lut,
+ .disable = ast_crtc_disable,
+ .prepare = ast_crtc_prepare,
+ .commit = ast_crtc_commit,
+
+};
+
+static void ast_crtc_reset(struct drm_crtc *crtc)
+{
+
+}
+
+static void ast_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
+ u16 *blue, uint32_t start, uint32_t size)
+{
+ struct ast_crtc *ast_crtc = to_ast_crtc(crtc);
+ int end = (start + size > 256) ? 256 : start + size, i;
+
+ /* userspace palettes are always correct as is */
+ for (i = start; i < end; i++) {
+ ast_crtc->lut_r[i] = red[i] >> 8;
+ ast_crtc->lut_g[i] = green[i] >> 8;
+ ast_crtc->lut_b[i] = blue[i] >> 8;
+ }
+ ast_crtc_load_lut(crtc);
+}
+
+
+static void ast_crtc_destroy(struct drm_crtc *crtc)
+{
+ drm_crtc_cleanup(crtc);
+ kfree(crtc);
+}
+
+static const struct drm_crtc_funcs ast_crtc_funcs = {
+ .cursor_set = ast_cursor_set,
+ .cursor_move = ast_cursor_move,
+ .reset = ast_crtc_reset,
+ .set_config = drm_crtc_helper_set_config,
+ .gamma_set = ast_crtc_gamma_set,
+ .destroy = ast_crtc_destroy,
+};
+
+int ast_crtc_init(struct drm_device *dev)
+{
+ struct ast_crtc *crtc;
+ int i;
+
+ crtc = kzalloc(sizeof(struct ast_crtc), GFP_KERNEL);
+ if (!crtc)
+ return -ENOMEM;
+
+ drm_crtc_init(dev, &crtc->base, &ast_crtc_funcs);
+ drm_mode_crtc_set_gamma_size(&crtc->base, 256);
+ drm_crtc_helper_add(&crtc->base, &ast_crtc_helper_funcs);
+
+ for (i = 0; i < 256; i++) {
+ crtc->lut_r[i] = i;
+ crtc->lut_g[i] = i;
+ crtc->lut_b[i] = i;
+ }
+ return 0;
+}
+
+static void ast_encoder_destroy(struct drm_encoder *encoder)
+{
+ drm_encoder_cleanup(encoder);
+ kfree(encoder);
+}
+
+
+static struct drm_encoder *ast_best_single_encoder(struct drm_connector *connector)
+{
+ int enc_id = connector->encoder_ids[0];
+ struct drm_mode_object *obj;
+ struct drm_encoder *encoder;
+
+ /* pick the encoder ids */
+ if (enc_id) {
+ obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER);
+ if (!obj)
+ return NULL;
+ encoder = obj_to_encoder(obj);
+ return encoder;
+ }
+ return NULL;
+}
+
+
+static const struct drm_encoder_funcs ast_enc_funcs = {
+ .destroy = ast_encoder_destroy,
+};
+
+static void ast_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+
+}
+
+static bool ast_mode_fixup(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void ast_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+}
+
+static void ast_encoder_prepare(struct drm_encoder *encoder)
+{
+
+}
+
+static void ast_encoder_commit(struct drm_encoder *encoder)
+{
+
+}
+
+
+static const struct drm_encoder_helper_funcs ast_enc_helper_funcs = {
+ .dpms = ast_encoder_dpms,
+ .mode_fixup = ast_mode_fixup,
+ .prepare = ast_encoder_prepare,
+ .commit = ast_encoder_commit,
+ .mode_set = ast_encoder_mode_set,
+};
+
+int ast_encoder_init(struct drm_device *dev)
+{
+ struct ast_encoder *ast_encoder;
+
+ ast_encoder = kzalloc(sizeof(struct ast_encoder), GFP_KERNEL);
+ if (!ast_encoder)
+ return -ENOMEM;
+
+ drm_encoder_init(dev, &ast_encoder->base, &ast_enc_funcs,
+ DRM_MODE_ENCODER_DAC);
+ drm_encoder_helper_add(&ast_encoder->base, &ast_enc_helper_funcs);
+
+ ast_encoder->base.possible_crtcs = 1;
+ return 0;
+}
+
+static int ast_get_modes(struct drm_connector *connector)
+{
+ struct ast_connector *ast_connector = to_ast_connector(connector);
+ struct edid *edid;
+ int ret;
+
+ edid = drm_get_edid(connector, &ast_connector->i2c->adapter);
+ if (edid) {
+ drm_mode_connector_update_edid_property(&ast_connector->base, edid);
+ ret = drm_add_edid_modes(connector, edid);
+ return ret;
+ } else
+ drm_mode_connector_update_edid_property(&ast_connector->base, NULL);
+ return 0;
+}
+
+static int ast_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ return MODE_OK;
+}
+
+static void ast_connector_destroy(struct drm_connector *connector)
+{
+ struct ast_connector *ast_connector = to_ast_connector(connector);
+ ast_i2c_destroy(ast_connector->i2c);
+ drm_sysfs_connector_remove(connector);
+ drm_connector_cleanup(connector);
+ kfree(connector);
+}
+
+static enum drm_connector_status
+ast_connector_detect(struct drm_connector *connector, bool force)
+{
+ return connector_status_connected;
+}
+
+static const struct drm_connector_helper_funcs ast_connector_helper_funcs = {
+ .mode_valid = ast_mode_valid,
+ .get_modes = ast_get_modes,
+ .best_encoder = ast_best_single_encoder,
+};
+
+static const struct drm_connector_funcs ast_connector_funcs = {
+ .dpms = drm_helper_connector_dpms,
+ .detect = ast_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = ast_connector_destroy,
+};
+
+int ast_connector_init(struct drm_device *dev)
+{
+ struct ast_connector *ast_connector;
+ struct drm_connector *connector;
+ struct drm_encoder *encoder;
+
+ ast_connector = kzalloc(sizeof(struct ast_connector), GFP_KERNEL);
+ if (!ast_connector)
+ return -ENOMEM;
+
+ connector = &ast_connector->base;
+ drm_connector_init(dev, connector, &ast_connector_funcs, DRM_MODE_CONNECTOR_VGA);
+
+ drm_connector_helper_add(connector, &ast_connector_helper_funcs);
+
+ connector->interlace_allowed = 0;
+ connector->doublescan_allowed = 0;
+
+ drm_sysfs_connector_add(connector);
+
+ connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+
+ encoder = list_first_entry(&dev->mode_config.encoder_list, struct drm_encoder, head);
+ drm_mode_connector_attach_encoder(connector, encoder);
+
+ ast_connector->i2c = ast_i2c_create(dev);
+ if (!ast_connector->i2c)
+ DRM_ERROR("failed to add ddc bus for connector\n");
+
+ return 0;
+}
+
+/* allocate cursor cache and pin at start of VRAM */
+int ast_cursor_init(struct drm_device *dev)
+{
+ struct ast_private *ast = dev->dev_private;
+ int size;
+ int ret;
+ struct drm_gem_object *obj;
+ struct ast_bo *bo;
+ uint64_t gpu_addr;
+
+ size = (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE) * AST_DEFAULT_HWC_NUM;
+
+ ret = ast_gem_create(dev, size, true, &obj);
+ if (ret)
+ return ret;
+ bo = gem_to_ast_bo(obj);
+ ret = ast_bo_reserve(bo, false);
+ if (unlikely(ret != 0))
+ goto fail;
+
+ ret = ast_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
+ ast_bo_unreserve(bo);
+ if (ret)
+ goto fail;
+
+ /* kmap the object */
+ ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &ast->cache_kmap);
+ if (ret)
+ goto fail;
+
+ ast->cursor_cache = obj;
+ ast->cursor_cache_gpu_addr = gpu_addr;
+ DRM_ERROR("pinned cursor cache at %llx\n", ast->cursor_cache_gpu_addr);
+ return 0;
+fail:
+ return ret;
+}
+
+void ast_cursor_fini(struct drm_device *dev)
+{
+ struct ast_private *ast = dev->dev_private;
+ ttm_bo_kunmap(&ast->cache_kmap);
+ drm_gem_object_unreference_unlocked(ast->cursor_cache);
+}
+
+int ast_mode_init(struct drm_device *dev)
+{
+ ast_cursor_init(dev);
+ ast_crtc_init(dev);
+ ast_encoder_init(dev);
+ ast_connector_init(dev);
+ return 0;
+}
+
+void ast_mode_fini(struct drm_device *dev)
+{
+ ast_cursor_fini(dev);
+}
+
+static int get_clock(void *i2c_priv)
+{
+ struct ast_i2c_chan *i2c = i2c_priv;
+ struct ast_private *ast = i2c->dev->dev_private;
+ uint32_t val;
+
+ val = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x10) >> 4;
+ return val & 1 ? 1 : 0;
+}
+
+static int get_data(void *i2c_priv)
+{
+ struct ast_i2c_chan *i2c = i2c_priv;
+ struct ast_private *ast = i2c->dev->dev_private;
+ uint32_t val;
+
+ val = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x20) >> 5;
+ return val & 1 ? 1 : 0;
+}
+
+static void set_clock(void *i2c_priv, int clock)
+{
+ struct ast_i2c_chan *i2c = i2c_priv;
+ struct ast_private *ast = i2c->dev->dev_private;
+ int i;
+ u8 ujcrb7, jtemp;
+
+ for (i = 0; i < 0x10000; i++) {
+ ujcrb7 = ((clock & 0x01) ? 0 : 1);
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xfe, ujcrb7);
+ jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x01);
+ if (ujcrb7 == jtemp)
+ break;
+ }
+}
+
+static void set_data(void *i2c_priv, int data)
+{
+ struct ast_i2c_chan *i2c = i2c_priv;
+ struct ast_private *ast = i2c->dev->dev_private;
+ int i;
+ u8 ujcrb7, jtemp;
+
+ for (i = 0; i < 0x10000; i++) {
+ ujcrb7 = ((data & 0x01) ? 0 : 1) << 2;
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xfb, ujcrb7);
+ jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x04);
+ if (ujcrb7 == jtemp)
+ break;
+ }
+}
+
+static struct ast_i2c_chan *ast_i2c_create(struct drm_device *dev)
+{
+ struct ast_i2c_chan *i2c;
+ int ret;
+
+ i2c = kzalloc(sizeof(struct ast_i2c_chan), GFP_KERNEL);
+ if (!i2c)
+ return NULL;
+
+ i2c->adapter.owner = THIS_MODULE;
+ i2c->adapter.class = I2C_CLASS_DDC;
+ i2c->adapter.dev.parent = &dev->pdev->dev;
+ i2c->dev = dev;
+ i2c_set_adapdata(&i2c->adapter, i2c);
+ snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
+ "AST i2c bit bus");
+ i2c->adapter.algo_data = &i2c->bit;
+
+ i2c->bit.udelay = 20;
+ i2c->bit.timeout = 2;
+ i2c->bit.data = i2c;
+ i2c->bit.setsda = set_data;
+ i2c->bit.setscl = set_clock;
+ i2c->bit.getsda = get_data;
+ i2c->bit.getscl = get_clock;
+ ret = i2c_bit_add_bus(&i2c->adapter);
+ if (ret) {
+ DRM_ERROR("Failed to register bit i2c\n");
+ goto out_free;
+ }
+
+ return i2c;
+out_free:
+ kfree(i2c);
+ return NULL;
+}
+
+static void ast_i2c_destroy(struct ast_i2c_chan *i2c)
+{
+ if (!i2c)
+ return;
+ i2c_del_adapter(&i2c->adapter);
+ kfree(i2c);
+}
+
+void ast_show_cursor(struct drm_crtc *crtc)
+{
+ struct ast_private *ast = crtc->dev->dev_private;
+ u8 jreg;
+
+ jreg = 0x2;
+ /* enable ARGB cursor */
+ jreg |= 1;
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, jreg);
+}
+
+void ast_hide_cursor(struct drm_crtc *crtc)
+{
+ struct ast_private *ast = crtc->dev->dev_private;
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, 0x00);
+}
+
+static u32 copy_cursor_image(u8 *src, u8 *dst, int width, int height)
+{
+ union {
+ u32 ul;
+ u8 b[4];
+ } srcdata32[2], data32;
+ union {
+ u16 us;
+ u8 b[2];
+ } data16;
+ u32 csum = 0;
+ s32 alpha_dst_delta, last_alpha_dst_delta;
+ u8 *srcxor, *dstxor;
+ int i, j;
+ u32 per_pixel_copy, two_pixel_copy;
+
+ alpha_dst_delta = AST_MAX_HWC_WIDTH << 1;
+ last_alpha_dst_delta = alpha_dst_delta - (width << 1);
+
+ srcxor = src;
+ dstxor = (u8 *)dst + last_alpha_dst_delta + (AST_MAX_HWC_HEIGHT - height) * alpha_dst_delta;
+ per_pixel_copy = width & 1;
+ two_pixel_copy = width >> 1;
+
+ for (j = 0; j < height; j++) {
+ for (i = 0; i < two_pixel_copy; i++) {
+ srcdata32[0].ul = *((u32 *)srcxor) & 0xf0f0f0f0;
+ srcdata32[1].ul = *((u32 *)(srcxor + 4)) & 0xf0f0f0f0;
+ data32.b[0] = srcdata32[0].b[1] | (srcdata32[0].b[0] >> 4);
+ data32.b[1] = srcdata32[0].b[3] | (srcdata32[0].b[2] >> 4);
+ data32.b[2] = srcdata32[0].b[1] | (srcdata32[1].b[0] >> 4);
+ data32.b[3] = srcdata32[0].b[3] | (srcdata32[1].b[2] >> 4);
+
+ writel(data32.ul, dstxor);
+ csum += data32.ul;
+
+ dstxor += 4;
+ srcxor += 8;
+
+ }
+
+ for (i = 0; i < per_pixel_copy; i++) {
+ srcdata32[0].ul = *((u32 *)srcxor) & 0xf0f0f0f0;
+ data16.b[0] = srcdata32[0].b[1] | (srcdata32[0].b[0] >> 4);
+ data16.b[1] = srcdata32[0].b[3] | (srcdata32[0].b[2] >> 4);
+ writew(data16.us, dstxor);
+ csum += (u32)data16.us;
+
+ dstxor += 2;
+ srcxor += 4;
+ }
+ dstxor += last_alpha_dst_delta;
+ }
+ return csum;
+}
+
+static int ast_cursor_set(struct drm_crtc *crtc,
+ struct drm_file *file_priv,
+ uint32_t handle,
+ uint32_t width,
+ uint32_t height)
+{
+ struct ast_private *ast = crtc->dev->dev_private;
+ struct ast_crtc *ast_crtc = to_ast_crtc(crtc);
+ struct drm_gem_object *obj;
+ struct ast_bo *bo;
+ uint64_t gpu_addr;
+ u32 csum;
+ int ret;
+ struct ttm_bo_kmap_obj uobj_map;
+ u8 *src, *dst;
+ bool src_isiomem, dst_isiomem;
+ if (!handle) {
+ ast_hide_cursor(crtc);
+ return 0;
+ }
+
+ if (width > AST_MAX_HWC_WIDTH || height > AST_MAX_HWC_HEIGHT)
+ return -EINVAL;
+
+ obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
+ if (!obj) {
+ DRM_ERROR("Cannot find cursor object %x for crtc\n", handle);
+ return -ENOENT;
+ }
+ bo = gem_to_ast_bo(obj);
+
+ ret = ast_bo_reserve(bo, false);
+ if (ret)
+ goto fail;
+
+ ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &uobj_map);
+
+ src = ttm_kmap_obj_virtual(&uobj_map, &src_isiomem);
+ dst = ttm_kmap_obj_virtual(&ast->cache_kmap, &dst_isiomem);
+
+ if (src_isiomem == true)
+ DRM_ERROR("src cursor bo should be in main memory\n");
+ if (dst_isiomem == false)
+ DRM_ERROR("dst bo should be in VRAM\n");
+
+ dst += (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE)*ast->next_cursor;
+
+ /* do data transfer to cursor cache */
+ csum = copy_cursor_image(src, dst, width, height);
+
+ /* write checksum + signature */
+ ttm_bo_kunmap(&uobj_map);
+ ast_bo_unreserve(bo);
+ {
+ u8 *dst = (u8 *)ast->cache_kmap.virtual + (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE)*ast->next_cursor + AST_HWC_SIZE;
+ writel(csum, dst);
+ writel(width, dst + AST_HWC_SIGNATURE_SizeX);
+ writel(height, dst + AST_HWC_SIGNATURE_SizeY);
+ writel(0, dst + AST_HWC_SIGNATURE_HOTSPOTX);
+ writel(0, dst + AST_HWC_SIGNATURE_HOTSPOTY);
+
+ /* set pattern offset */
+ gpu_addr = ast->cursor_cache_gpu_addr;
+ gpu_addr += (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE)*ast->next_cursor;
+ gpu_addr >>= 3;
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc8, gpu_addr & 0xff);
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc9, (gpu_addr >> 8) & 0xff);
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xca, (gpu_addr >> 16) & 0xff);
+ }
+ ast_crtc->cursor_width = width;
+ ast_crtc->cursor_height = height;
+ ast_crtc->offset_x = AST_MAX_HWC_WIDTH - width;
+ ast_crtc->offset_y = AST_MAX_HWC_WIDTH - height;
+
+ ast->next_cursor = (ast->next_cursor + 1) % AST_DEFAULT_HWC_NUM;
+
+ ast_show_cursor(crtc);
+
+ drm_gem_object_unreference_unlocked(obj);
+ return 0;
+fail:
+ drm_gem_object_unreference_unlocked(obj);
+ return ret;
+}
+
+static int ast_cursor_move(struct drm_crtc *crtc,
+ int x, int y)
+{
+ struct ast_crtc *ast_crtc = to_ast_crtc(crtc);
+ struct ast_private *ast = crtc->dev->dev_private;
+ int x_offset, y_offset;
+ u8 *sig;
+
+ sig = (u8 *)ast->cache_kmap.virtual + (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE)*ast->next_cursor + AST_HWC_SIZE;
+ writel(x, sig + AST_HWC_SIGNATURE_X);
+ writel(y, sig + AST_HWC_SIGNATURE_Y);
+
+ x_offset = ast_crtc->offset_x;
+ y_offset = ast_crtc->offset_y;
+ if (x < 0) {
+ x_offset = (-x) + ast_crtc->offset_x;
+ x = 0;
+ }
+
+ if (y < 0) {
+ y_offset = (-y) + ast_crtc->offset_y;
+ y = 0;
+ }
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc2, x_offset);
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc3, y_offset);
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc4, (x & 0xff));
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc5, ((x >> 8) & 0x0f));
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc6, (y & 0xff));
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc7, ((y >> 8) & 0x07));
+
+ /* dummy write to fire HWC */
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xCB, 0xFF, 0x00);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/ast/ast_post.c b/drivers/gpu/drm/ast/ast_post.c
new file mode 100644
index 000000000000..6edbee63b0cb
--- /dev/null
+++ b/drivers/gpu/drm/ast/ast_post.c
@@ -0,0 +1,1780 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors: Dave Airlie <airlied@redhat.com>
+ */
+
+#include "drmP.h"
+#include "ast_drv.h"
+
+#include "ast_dram_tables.h"
+
+static void ast_init_dram_2300(struct drm_device *dev);
+
+static void
+ast_enable_vga(struct drm_device *dev)
+{
+ struct ast_private *ast = dev->dev_private;
+
+ ast_io_write8(ast, 0x43, 0x01);
+ ast_io_write8(ast, 0x42, 0x01);
+}
+
+#if 0 /* will use later */
+static bool
+ast_is_vga_enabled(struct drm_device *dev)
+{
+ struct ast_private *ast = dev->dev_private;
+ u8 ch;
+
+ if (ast->chip == AST1180) {
+ /* TODO 1180 */
+ } else {
+ ch = ast_io_read8(ast, 0x43);
+ if (ch) {
+ ast_open_key(ast);
+ ch = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0xff);
+ return ch & 0x04;
+ }
+ }
+ return 0;
+}
+#endif
+
+static const u8 extreginfo[] = { 0x0f, 0x04, 0x1c, 0xff };
+static const u8 extreginfo_ast2300a0[] = { 0x0f, 0x04, 0x1c, 0xff };
+static const u8 extreginfo_ast2300[] = { 0x0f, 0x04, 0x1f, 0xff };
+
+static void
+ast_set_def_ext_reg(struct drm_device *dev)
+{
+ struct ast_private *ast = dev->dev_private;
+ u8 i, index, reg;
+ const u8 *ext_reg_info;
+
+ /* reset scratch */
+ for (i = 0x81; i <= 0x8f; i++)
+ ast_set_index_reg(ast, AST_IO_CRTC_PORT, i, 0x00);
+
+ if (ast->chip == AST2300) {
+ if (dev->pdev->revision >= 0x20)
+ ext_reg_info = extreginfo_ast2300;
+ else
+ ext_reg_info = extreginfo_ast2300a0;
+ } else
+ ext_reg_info = extreginfo;
+
+ index = 0xa0;
+ while (*ext_reg_info != 0xff) {
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, index, 0x00, *ext_reg_info);
+ index++;
+ ext_reg_info++;
+ }
+
+ /* disable standard IO/MEM decode if secondary */
+ /* ast_set_index_reg-mask(ast, AST_IO_CRTC_PORT, 0xa1, 0xff, 0x3); */
+
+ /* Set Ext. Default */
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x8c, 0x00, 0x01);
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x00, 0x00);
+
+ /* Enable RAMDAC for A1 */
+ reg = 0x04;
+ if (ast->chip == AST2300)
+ reg |= 0x20;
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0xff, reg);
+}
+
+static inline u32 mindwm(struct ast_private *ast, u32 r)
+{
+ ast_write32(ast, 0xf004, r & 0xffff0000);
+ ast_write32(ast, 0xf000, 0x1);
+
+ return ast_read32(ast, 0x10000 + (r & 0x0000ffff));
+}
+
+static inline void moutdwm(struct ast_private *ast, u32 r, u32 v)
+{
+ ast_write32(ast, 0xf004, r & 0xffff0000);
+ ast_write32(ast, 0xf000, 0x1);
+ ast_write32(ast, 0x10000 + (r & 0x0000ffff), v);
+}
+
+/*
+ * AST2100/2150 DLL CBR Setting
+ */
+#define CBR_SIZE_AST2150 ((16 << 10) - 1)
+#define CBR_PASSNUM_AST2150 5
+#define CBR_THRESHOLD_AST2150 10
+#define CBR_THRESHOLD2_AST2150 10
+#define TIMEOUT_AST2150 5000000
+
+#define CBR_PATNUM_AST2150 8
+
+static const u32 pattern_AST2150[14] = {
+ 0xFF00FF00,
+ 0xCC33CC33,
+ 0xAA55AA55,
+ 0xFFFE0001,
+ 0x683501FE,
+ 0x0F1929B0,
+ 0x2D0B4346,
+ 0x60767F02,
+ 0x6FBE36A6,
+ 0x3A253035,
+ 0x3019686D,
+ 0x41C6167E,
+ 0x620152BF,
+ 0x20F050E0
+};
+
+static u32 mmctestburst2_ast2150(struct ast_private *ast, u32 datagen)
+{
+ u32 data, timeout;
+
+ moutdwm(ast, 0x1e6e0070, 0x00000000);
+ moutdwm(ast, 0x1e6e0070, 0x00000001 | (datagen << 3));
+ timeout = 0;
+ do {
+ data = mindwm(ast, 0x1e6e0070) & 0x40;
+ if (++timeout > TIMEOUT_AST2150) {
+ moutdwm(ast, 0x1e6e0070, 0x00000000);
+ return 0xffffffff;
+ }
+ } while (!data);
+ moutdwm(ast, 0x1e6e0070, 0x00000000);
+ moutdwm(ast, 0x1e6e0070, 0x00000003 | (datagen << 3));
+ timeout = 0;
+ do {
+ data = mindwm(ast, 0x1e6e0070) & 0x40;
+ if (++timeout > TIMEOUT_AST2150) {
+ moutdwm(ast, 0x1e6e0070, 0x00000000);
+ return 0xffffffff;
+ }
+ } while (!data);
+ data = (mindwm(ast, 0x1e6e0070) & 0x80) >> 7;
+ moutdwm(ast, 0x1e6e0070, 0x00000000);
+ return data;
+}
+
+#if 0 /* unused in DDX driver - here for completeness */
+static u32 mmctestsingle2_ast2150(struct ast_private *ast, u32 datagen)
+{
+ u32 data, timeout;
+
+ moutdwm(ast, 0x1e6e0070, 0x00000000);
+ moutdwm(ast, 0x1e6e0070, 0x00000005 | (datagen << 3));
+ timeout = 0;
+ do {
+ data = mindwm(ast, 0x1e6e0070) & 0x40;
+ if (++timeout > TIMEOUT_AST2150) {
+ moutdwm(ast, 0x1e6e0070, 0x00000000);
+ return 0xffffffff;
+ }
+ } while (!data);
+ data = (mindwm(ast, 0x1e6e0070) & 0x80) >> 7;
+ moutdwm(ast, 0x1e6e0070, 0x00000000);
+ return data;
+}
+#endif
+
+static int cbrtest_ast2150(struct ast_private *ast)
+{
+ int i;
+
+ for (i = 0; i < 8; i++)
+ if (mmctestburst2_ast2150(ast, i))
+ return 0;
+ return 1;
+}
+
+static int cbrscan_ast2150(struct ast_private *ast, int busw)
+{
+ u32 patcnt, loop;
+
+ for (patcnt = 0; patcnt < CBR_PATNUM_AST2150; patcnt++) {
+ moutdwm(ast, 0x1e6e007c, pattern_AST2150[patcnt]);
+ for (loop = 0; loop < CBR_PASSNUM_AST2150; loop++) {
+ if (cbrtest_ast2150(ast))
+ break;
+ }
+ if (loop == CBR_PASSNUM_AST2150)
+ return 0;
+ }
+ return 1;
+}
+
+
+static void cbrdlli_ast2150(struct ast_private *ast, int busw)
+{
+ u32 dll_min[4], dll_max[4], dlli, data, passcnt;
+
+cbr_start:
+ dll_min[0] = dll_min[1] = dll_min[2] = dll_min[3] = 0xff;
+ dll_max[0] = dll_max[1] = dll_max[2] = dll_max[3] = 0x0;
+ passcnt = 0;
+
+ for (dlli = 0; dlli < 100; dlli++) {
+ moutdwm(ast, 0x1e6e0068, dlli | (dlli << 8) | (dlli << 16) | (dlli << 24));
+ data = cbrscan_ast2150(ast, busw);
+ if (data != 0) {
+ if (data & 0x1) {
+ if (dll_min[0] > dlli)
+ dll_min[0] = dlli;
+ if (dll_max[0] < dlli)
+ dll_max[0] = dlli;
+ }
+ passcnt++;
+ } else if (passcnt >= CBR_THRESHOLD_AST2150)
+ goto cbr_start;
+ }
+ if (dll_max[0] == 0 || (dll_max[0]-dll_min[0]) < CBR_THRESHOLD_AST2150)
+ goto cbr_start;
+
+ dlli = dll_min[0] + (((dll_max[0] - dll_min[0]) * 7) >> 4);
+ moutdwm(ast, 0x1e6e0068, dlli | (dlli << 8) | (dlli << 16) | (dlli << 24));
+}
+
+
+
+static void ast_init_dram_reg(struct drm_device *dev)
+{
+ struct ast_private *ast = dev->dev_private;
+ u8 j;
+ u32 data, temp, i;
+ const struct ast_dramstruct *dram_reg_info;
+
+ j = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
+
+ if ((j & 0x80) == 0) { /* VGA only */
+ if (ast->chip == AST2000) {
+ dram_reg_info = ast2000_dram_table_data;
+ ast_write32(ast, 0xf004, 0x1e6e0000);
+ ast_write32(ast, 0xf000, 0x1);
+ ast_write32(ast, 0x10100, 0xa8);
+
+ do {
+ ;
+ } while (ast_read32(ast, 0x10100) != 0xa8);
+ } else {/* AST2100/1100 */
+ if (ast->chip == AST2100 || ast->chip == 2200)
+ dram_reg_info = ast2100_dram_table_data;
+ else
+ dram_reg_info = ast1100_dram_table_data;
+
+ ast_write32(ast, 0xf004, 0x1e6e0000);
+ ast_write32(ast, 0xf000, 0x1);
+ ast_write32(ast, 0x12000, 0x1688A8A8);
+ do {
+ ;
+ } while (ast_read32(ast, 0x12000) != 0x01);
+
+ ast_write32(ast, 0x10000, 0xfc600309);
+ do {
+ ;
+ } while (ast_read32(ast, 0x10000) != 0x01);
+ }
+
+ while (dram_reg_info->index != 0xffff) {
+ if (dram_reg_info->index == 0xff00) {/* delay fn */
+ for (i = 0; i < 15; i++)
+ udelay(dram_reg_info->data);
+ } else if (dram_reg_info->index == 0x4 && ast->chip != AST2000) {
+ data = dram_reg_info->data;
+ if (ast->dram_type == AST_DRAM_1Gx16)
+ data = 0x00000d89;
+ else if (ast->dram_type == AST_DRAM_1Gx32)
+ data = 0x00000c8d;
+
+ temp = ast_read32(ast, 0x12070);
+ temp &= 0xc;
+ temp <<= 2;
+ ast_write32(ast, 0x10000 + dram_reg_info->index, data | temp);
+ } else
+ ast_write32(ast, 0x10000 + dram_reg_info->index, dram_reg_info->data);
+ dram_reg_info++;
+ }
+
+ /* AST 2100/2150 DRAM calibration */
+ data = ast_read32(ast, 0x10120);
+ if (data == 0x5061) { /* 266Mhz */
+ data = ast_read32(ast, 0x10004);
+ if (data & 0x40)
+ cbrdlli_ast2150(ast, 16); /* 16 bits */
+ else
+ cbrdlli_ast2150(ast, 32); /* 32 bits */
+ }
+
+ switch (ast->chip) {
+ case AST2000:
+ temp = ast_read32(ast, 0x10140);
+ ast_write32(ast, 0x10140, temp | 0x40);
+ break;
+ case AST1100:
+ case AST2100:
+ case AST2200:
+ case AST2150:
+ temp = ast_read32(ast, 0x1200c);
+ ast_write32(ast, 0x1200c, temp & 0xfffffffd);
+ temp = ast_read32(ast, 0x12040);
+ ast_write32(ast, 0x12040, temp | 0x40);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* wait ready */
+ do {
+ j = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
+ } while ((j & 0x40) == 0);
+}
+
+void ast_post_gpu(struct drm_device *dev)
+{
+ u32 reg;
+ struct ast_private *ast = dev->dev_private;
+
+ pci_read_config_dword(ast->dev->pdev, 0x04, &reg);
+ reg |= 0x3;
+ pci_write_config_dword(ast->dev->pdev, 0x04, reg);
+
+ ast_enable_vga(dev);
+ ast_open_key(ast);
+ ast_set_def_ext_reg(dev);
+
+ if (ast->chip == AST2300)
+ ast_init_dram_2300(dev);
+ else
+ ast_init_dram_reg(dev);
+}
+
+/* AST 2300 DRAM settings */
+#define AST_DDR3 0
+#define AST_DDR2 1
+
+struct ast2300_dram_param {
+ u32 dram_type;
+ u32 dram_chipid;
+ u32 dram_freq;
+ u32 vram_size;
+ u32 odt;
+ u32 wodt;
+ u32 rodt;
+ u32 dram_config;
+ u32 reg_PERIOD;
+ u32 reg_MADJ;
+ u32 reg_SADJ;
+ u32 reg_MRS;
+ u32 reg_EMRS;
+ u32 reg_AC1;
+ u32 reg_AC2;
+ u32 reg_DQSIC;
+ u32 reg_DRV;
+ u32 reg_IOZ;
+ u32 reg_DQIDLY;
+ u32 reg_FREQ;
+ u32 madj_max;
+ u32 dll2_finetune_step;
+};
+
+/*
+ * DQSI DLL CBR Setting
+ */
+#define CBR_SIZE1 ((4 << 10) - 1)
+#define CBR_SIZE2 ((64 << 10) - 1)
+#define CBR_PASSNUM 5
+#define CBR_PASSNUM2 5
+#define CBR_THRESHOLD 10
+#define CBR_THRESHOLD2 10
+#define TIMEOUT 5000000
+#define CBR_PATNUM 8
+
+static const u32 pattern[8] = {
+ 0xFF00FF00,
+ 0xCC33CC33,
+ 0xAA55AA55,
+ 0x88778877,
+ 0x92CC4D6E,
+ 0x543D3CDE,
+ 0xF1E843C7,
+ 0x7C61D253
+};
+
+#if 0 /* unused in DDX, included for completeness */
+static int mmc_test_burst(struct ast_private *ast, u32 datagen)
+{
+ u32 data, timeout;
+
+ moutdwm(ast, 0x1e6e0070, 0x00000000);
+ moutdwm(ast, 0x1e6e0070, 0x000000c1 | (datagen << 3));
+ timeout = 0;
+ do {
+ data = mindwm(ast, 0x1e6e0070) & 0x3000;
+ if (data & 0x2000) {
+ return 0;
+ }
+ if (++timeout > TIMEOUT) {
+ moutdwm(ast, 0x1e6e0070, 0x00000000);
+ return 0;
+ }
+ } while (!data);
+ moutdwm(ast, 0x1e6e0070, 0x00000000);
+ return 1;
+}
+#endif
+
+static int mmc_test_burst2(struct ast_private *ast, u32 datagen)
+{
+ u32 data, timeout;
+
+ moutdwm(ast, 0x1e6e0070, 0x00000000);
+ moutdwm(ast, 0x1e6e0070, 0x00000041 | (datagen << 3));
+ timeout = 0;
+ do {
+ data = mindwm(ast, 0x1e6e0070) & 0x1000;
+ if (++timeout > TIMEOUT) {
+ moutdwm(ast, 0x1e6e0070, 0x0);
+ return -1;
+ }
+ } while (!data);
+ data = mindwm(ast, 0x1e6e0078);
+ data = (data | (data >> 16)) & 0xffff;
+ moutdwm(ast, 0x1e6e0070, 0x0);
+ return data;
+}
+
+#if 0 /* Unused in DDX here for completeness */
+static int mmc_test_single(struct ast_private *ast, u32 datagen)
+{
+ u32 data, timeout;
+
+ moutdwm(ast, 0x1e6e0070, 0x00000000);
+ moutdwm(ast, 0x1e6e0070, 0x000000c5 | (datagen << 3));
+ timeout = 0;
+ do {
+ data = mindwm(ast, 0x1e6e0070) & 0x3000;
+ if (data & 0x2000)
+ return 0;
+ if (++timeout > TIMEOUT) {
+ moutdwm(ast, 0x1e6e0070, 0x0);
+ return 0;
+ }
+ } while (!data);
+ moutdwm(ast, 0x1e6e0070, 0x0);
+ return 1;
+}
+#endif
+
+static int mmc_test_single2(struct ast_private *ast, u32 datagen)
+{
+ u32 data, timeout;
+
+ moutdwm(ast, 0x1e6e0070, 0x00000000);
+ moutdwm(ast, 0x1e6e0070, 0x00000005 | (datagen << 3));
+ timeout = 0;
+ do {
+ data = mindwm(ast, 0x1e6e0070) & 0x1000;
+ if (++timeout > TIMEOUT) {
+ moutdwm(ast, 0x1e6e0070, 0x0);
+ return -1;
+ }
+ } while (!data);
+ data = mindwm(ast, 0x1e6e0078);
+ data = (data | (data >> 16)) & 0xffff;
+ moutdwm(ast, 0x1e6e0070, 0x0);
+ return data;
+}
+
+static int cbr_test(struct ast_private *ast)
+{
+ u32 data;
+ int i;
+ data = mmc_test_single2(ast, 0);
+ if ((data & 0xff) && (data & 0xff00))
+ return 0;
+ for (i = 0; i < 8; i++) {
+ data = mmc_test_burst2(ast, i);
+ if ((data & 0xff) && (data & 0xff00))
+ return 0;
+ }
+ if (!data)
+ return 3;
+ else if (data & 0xff)
+ return 2;
+ return 1;
+}
+
+static int cbr_scan(struct ast_private *ast)
+{
+ u32 data, data2, patcnt, loop;
+
+ data2 = 3;
+ for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) {
+ moutdwm(ast, 0x1e6e007c, pattern[patcnt]);
+ for (loop = 0; loop < CBR_PASSNUM2; loop++) {
+ if ((data = cbr_test(ast)) != 0) {
+ data2 &= data;
+ if (!data2)
+ return 0;
+ break;
+ }
+ }
+ if (loop == CBR_PASSNUM2)
+ return 0;
+ }
+ return data2;
+}
+
+static u32 cbr_test2(struct ast_private *ast)
+{
+ u32 data;
+
+ data = mmc_test_burst2(ast, 0);
+ if (data == 0xffff)
+ return 0;
+ data |= mmc_test_single2(ast, 0);
+ if (data == 0xffff)
+ return 0;
+
+ return ~data & 0xffff;
+}
+
+static u32 cbr_scan2(struct ast_private *ast)
+{
+ u32 data, data2, patcnt, loop;
+
+ data2 = 0xffff;
+ for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) {
+ moutdwm(ast, 0x1e6e007c, pattern[patcnt]);
+ for (loop = 0; loop < CBR_PASSNUM2; loop++) {
+ if ((data = cbr_test2(ast)) != 0) {
+ data2 &= data;
+ if (!data)
+ return 0;
+ break;
+ }
+ }
+ if (loop == CBR_PASSNUM2)
+ return 0;
+ }
+ return data2;
+}
+
+#if 0 /* unused in DDX - added for completeness */
+static void finetuneDQI(struct ast_private *ast, struct ast2300_dram_param *param)
+{
+ u32 gold_sadj[2], dllmin[16], dllmax[16], dlli, data, cnt, mask, passcnt;
+
+ gold_sadj[0] = (mindwm(ast, 0x1E6E0024) >> 16) & 0xffff;
+ gold_sadj[1] = gold_sadj[0] >> 8;
+ gold_sadj[0] = gold_sadj[0] & 0xff;
+ gold_sadj[0] = (gold_sadj[0] + gold_sadj[1]) >> 1;
+ gold_sadj[1] = gold_sadj[0];
+
+ for (cnt = 0; cnt < 16; cnt++) {
+ dllmin[cnt] = 0xff;
+ dllmax[cnt] = 0x0;
+ }
+ passcnt = 0;
+ for (dlli = 0; dlli < 76; dlli++) {
+ moutdwm(ast, 0x1E6E0068, 0x00001400 | (dlli << 16) | (dlli << 24));
+ /* Wait DQSI latch phase calibration */
+ moutdwm(ast, 0x1E6E0074, 0x00000010);
+ moutdwm(ast, 0x1E6E0070, 0x00000003);
+ do {
+ data = mindwm(ast, 0x1E6E0070);
+ } while (!(data & 0x00001000));
+ moutdwm(ast, 0x1E6E0070, 0x00000000);
+
+ moutdwm(ast, 0x1E6E0074, CBR_SIZE1);
+ data = cbr_scan2(ast);
+ if (data != 0) {
+ mask = 0x00010001;
+ for (cnt = 0; cnt < 16; cnt++) {
+ if (data & mask) {
+ if (dllmin[cnt] > dlli) {
+ dllmin[cnt] = dlli;
+ }
+ if (dllmax[cnt] < dlli) {
+ dllmax[cnt] = dlli;
+ }
+ }
+ mask <<= 1;
+ }
+ passcnt++;
+ } else if (passcnt >= CBR_THRESHOLD) {
+ break;
+ }
+ }
+ data = 0;
+ for (cnt = 0; cnt < 8; cnt++) {
+ data >>= 3;
+ if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD)) {
+ dlli = (dllmin[cnt] + dllmax[cnt]) >> 1;
+ if (gold_sadj[0] >= dlli) {
+ dlli = (gold_sadj[0] - dlli) >> 1;
+ if (dlli > 3) {
+ dlli = 3;
+ }
+ } else {
+ dlli = (dlli - gold_sadj[0]) >> 1;
+ if (dlli > 4) {
+ dlli = 4;
+ }
+ dlli = (8 - dlli) & 0x7;
+ }
+ data |= dlli << 21;
+ }
+ }
+ moutdwm(ast, 0x1E6E0080, data);
+
+ data = 0;
+ for (cnt = 8; cnt < 16; cnt++) {
+ data >>= 3;
+ if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD)) {
+ dlli = (dllmin[cnt] + dllmax[cnt]) >> 1;
+ if (gold_sadj[1] >= dlli) {
+ dlli = (gold_sadj[1] - dlli) >> 1;
+ if (dlli > 3) {
+ dlli = 3;
+ } else {
+ dlli = (dlli - 1) & 0x7;
+ }
+ } else {
+ dlli = (dlli - gold_sadj[1]) >> 1;
+ dlli += 1;
+ if (dlli > 4) {
+ dlli = 4;
+ }
+ dlli = (8 - dlli) & 0x7;
+ }
+ data |= dlli << 21;
+ }
+ }
+ moutdwm(ast, 0x1E6E0084, data);
+
+} /* finetuneDQI */
+#endif
+
+static void finetuneDQI_L(struct ast_private *ast, struct ast2300_dram_param *param)
+{
+ u32 gold_sadj[2], dllmin[16], dllmax[16], dlli, data, cnt, mask, passcnt;
+
+FINETUNE_START:
+ for (cnt = 0; cnt < 16; cnt++) {
+ dllmin[cnt] = 0xff;
+ dllmax[cnt] = 0x0;
+ }
+ passcnt = 0;
+ for (dlli = 0; dlli < 76; dlli++) {
+ moutdwm(ast, 0x1E6E0068, 0x00001400 | (dlli << 16) | (dlli << 24));
+ /* Wait DQSI latch phase calibration */
+ moutdwm(ast, 0x1E6E0074, 0x00000010);
+ moutdwm(ast, 0x1E6E0070, 0x00000003);
+ do {
+ data = mindwm(ast, 0x1E6E0070);
+ } while (!(data & 0x00001000));
+ moutdwm(ast, 0x1E6E0070, 0x00000000);
+
+ moutdwm(ast, 0x1E6E0074, CBR_SIZE1);
+ data = cbr_scan2(ast);
+ if (data != 0) {
+ mask = 0x00010001;
+ for (cnt = 0; cnt < 16; cnt++) {
+ if (data & mask) {
+ if (dllmin[cnt] > dlli) {
+ dllmin[cnt] = dlli;
+ }
+ if (dllmax[cnt] < dlli) {
+ dllmax[cnt] = dlli;
+ }
+ }
+ mask <<= 1;
+ }
+ passcnt++;
+ } else if (passcnt >= CBR_THRESHOLD2) {
+ break;
+ }
+ }
+ gold_sadj[0] = 0x0;
+ passcnt = 0;
+ for (cnt = 0; cnt < 16; cnt++) {
+ if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) {
+ gold_sadj[0] += dllmin[cnt];
+ passcnt++;
+ }
+ }
+ if (passcnt != 16) {
+ goto FINETUNE_START;
+ }
+ gold_sadj[0] = gold_sadj[0] >> 4;
+ gold_sadj[1] = gold_sadj[0];
+
+ data = 0;
+ for (cnt = 0; cnt < 8; cnt++) {
+ data >>= 3;
+ if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) {
+ dlli = dllmin[cnt];
+ if (gold_sadj[0] >= dlli) {
+ dlli = ((gold_sadj[0] - dlli) * 19) >> 5;
+ if (dlli > 3) {
+ dlli = 3;
+ }
+ } else {
+ dlli = ((dlli - gold_sadj[0]) * 19) >> 5;
+ if (dlli > 4) {
+ dlli = 4;
+ }
+ dlli = (8 - dlli) & 0x7;
+ }
+ data |= dlli << 21;
+ }
+ }
+ moutdwm(ast, 0x1E6E0080, data);
+
+ data = 0;
+ for (cnt = 8; cnt < 16; cnt++) {
+ data >>= 3;
+ if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) {
+ dlli = dllmin[cnt];
+ if (gold_sadj[1] >= dlli) {
+ dlli = ((gold_sadj[1] - dlli) * 19) >> 5;
+ if (dlli > 3) {
+ dlli = 3;
+ } else {
+ dlli = (dlli - 1) & 0x7;
+ }
+ } else {
+ dlli = ((dlli - gold_sadj[1]) * 19) >> 5;
+ dlli += 1;
+ if (dlli > 4) {
+ dlli = 4;
+ }
+ dlli = (8 - dlli) & 0x7;
+ }
+ data |= dlli << 21;
+ }
+ }
+ moutdwm(ast, 0x1E6E0084, data);
+
+} /* finetuneDQI_L */
+
+static void finetuneDQI_L2(struct ast_private *ast, struct ast2300_dram_param *param)
+{
+ u32 gold_sadj[2], dllmin[16], dllmax[16], dlli, data, cnt, mask, passcnt, data2;
+
+ for (cnt = 0; cnt < 16; cnt++) {
+ dllmin[cnt] = 0xff;
+ dllmax[cnt] = 0x0;
+ }
+ passcnt = 0;
+ for (dlli = 0; dlli < 76; dlli++) {
+ moutdwm(ast, 0x1E6E0068, 0x00001400 | (dlli << 16) | (dlli << 24));
+ /* Wait DQSI latch phase calibration */
+ moutdwm(ast, 0x1E6E0074, 0x00000010);
+ moutdwm(ast, 0x1E6E0070, 0x00000003);
+ do {
+ data = mindwm(ast, 0x1E6E0070);
+ } while (!(data & 0x00001000));
+ moutdwm(ast, 0x1E6E0070, 0x00000000);
+
+ moutdwm(ast, 0x1E6E0074, CBR_SIZE2);
+ data = cbr_scan2(ast);
+ if (data != 0) {
+ mask = 0x00010001;
+ for (cnt = 0; cnt < 16; cnt++) {
+ if (data & mask) {
+ if (dllmin[cnt] > dlli) {
+ dllmin[cnt] = dlli;
+ }
+ if (dllmax[cnt] < dlli) {
+ dllmax[cnt] = dlli;
+ }
+ }
+ mask <<= 1;
+ }
+ passcnt++;
+ } else if (passcnt >= CBR_THRESHOLD2) {
+ break;
+ }
+ }
+ gold_sadj[0] = 0x0;
+ gold_sadj[1] = 0xFF;
+ for (cnt = 0; cnt < 8; cnt++) {
+ if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) {
+ if (gold_sadj[0] < dllmin[cnt]) {
+ gold_sadj[0] = dllmin[cnt];
+ }
+ if (gold_sadj[1] > dllmax[cnt]) {
+ gold_sadj[1] = dllmax[cnt];
+ }
+ }
+ }
+ gold_sadj[0] = (gold_sadj[1] + gold_sadj[0]) >> 1;
+ gold_sadj[1] = mindwm(ast, 0x1E6E0080);
+
+ data = 0;
+ for (cnt = 0; cnt < 8; cnt++) {
+ data >>= 3;
+ data2 = gold_sadj[1] & 0x7;
+ gold_sadj[1] >>= 3;
+ if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) {
+ dlli = (dllmin[cnt] + dllmax[cnt]) >> 1;
+ if (gold_sadj[0] >= dlli) {
+ dlli = (gold_sadj[0] - dlli) >> 1;
+ if (dlli > 0) {
+ dlli = 1;
+ }
+ if (data2 != 3) {
+ data2 = (data2 + dlli) & 0x7;
+ }
+ } else {
+ dlli = (dlli - gold_sadj[0]) >> 1;
+ if (dlli > 0) {
+ dlli = 1;
+ }
+ if (data2 != 4) {
+ data2 = (data2 - dlli) & 0x7;
+ }
+ }
+ }
+ data |= data2 << 21;
+ }
+ moutdwm(ast, 0x1E6E0080, data);
+
+ gold_sadj[0] = 0x0;
+ gold_sadj[1] = 0xFF;
+ for (cnt = 8; cnt < 16; cnt++) {
+ if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) {
+ if (gold_sadj[0] < dllmin[cnt]) {
+ gold_sadj[0] = dllmin[cnt];
+ }
+ if (gold_sadj[1] > dllmax[cnt]) {
+ gold_sadj[1] = dllmax[cnt];
+ }
+ }
+ }
+ gold_sadj[0] = (gold_sadj[1] + gold_sadj[0]) >> 1;
+ gold_sadj[1] = mindwm(ast, 0x1E6E0084);
+
+ data = 0;
+ for (cnt = 8; cnt < 16; cnt++) {
+ data >>= 3;
+ data2 = gold_sadj[1] & 0x7;
+ gold_sadj[1] >>= 3;
+ if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) {
+ dlli = (dllmin[cnt] + dllmax[cnt]) >> 1;
+ if (gold_sadj[0] >= dlli) {
+ dlli = (gold_sadj[0] - dlli) >> 1;
+ if (dlli > 0) {
+ dlli = 1;
+ }
+ if (data2 != 3) {
+ data2 = (data2 + dlli) & 0x7;
+ }
+ } else {
+ dlli = (dlli - gold_sadj[0]) >> 1;
+ if (dlli > 0) {
+ dlli = 1;
+ }
+ if (data2 != 4) {
+ data2 = (data2 - dlli) & 0x7;
+ }
+ }
+ }
+ data |= data2 << 21;
+ }
+ moutdwm(ast, 0x1E6E0084, data);
+
+} /* finetuneDQI_L2 */
+
+static void cbr_dll2(struct ast_private *ast, struct ast2300_dram_param *param)
+{
+ u32 dllmin[2], dllmax[2], dlli, data, data2, passcnt;
+
+
+ finetuneDQI_L(ast, param);
+ finetuneDQI_L2(ast, param);
+
+CBR_START2:
+ dllmin[0] = dllmin[1] = 0xff;
+ dllmax[0] = dllmax[1] = 0x0;
+ passcnt = 0;
+ for (dlli = 0; dlli < 76; dlli++) {
+ moutdwm(ast, 0x1E6E0068, 0x00001300 | (dlli << 16) | (dlli << 24));
+ /* Wait DQSI latch phase calibration */
+ moutdwm(ast, 0x1E6E0074, 0x00000010);
+ moutdwm(ast, 0x1E6E0070, 0x00000003);
+ do {
+ data = mindwm(ast, 0x1E6E0070);
+ } while (!(data & 0x00001000));
+ moutdwm(ast, 0x1E6E0070, 0x00000000);
+
+ moutdwm(ast, 0x1E6E0074, CBR_SIZE2);
+ data = cbr_scan(ast);
+ if (data != 0) {
+ if (data & 0x1) {
+ if (dllmin[0] > dlli) {
+ dllmin[0] = dlli;
+ }
+ if (dllmax[0] < dlli) {
+ dllmax[0] = dlli;
+ }
+ }
+ if (data & 0x2) {
+ if (dllmin[1] > dlli) {
+ dllmin[1] = dlli;
+ }
+ if (dllmax[1] < dlli) {
+ dllmax[1] = dlli;
+ }
+ }
+ passcnt++;
+ } else if (passcnt >= CBR_THRESHOLD) {
+ break;
+ }
+ }
+ if (dllmax[0] == 0 || (dllmax[0]-dllmin[0]) < CBR_THRESHOLD) {
+ goto CBR_START2;
+ }
+ if (dllmax[1] == 0 || (dllmax[1]-dllmin[1]) < CBR_THRESHOLD) {
+ goto CBR_START2;
+ }
+ dlli = (dllmin[1] + dllmax[1]) >> 1;
+ dlli <<= 8;
+ dlli += (dllmin[0] + dllmax[0]) >> 1;
+ moutdwm(ast, 0x1E6E0068, (mindwm(ast, 0x1E6E0068) & 0xFFFF) | (dlli << 16));
+
+ data = (mindwm(ast, 0x1E6E0080) >> 24) & 0x1F;
+ data2 = (mindwm(ast, 0x1E6E0018) & 0xff80ffff) | (data << 16);
+ moutdwm(ast, 0x1E6E0018, data2);
+ moutdwm(ast, 0x1E6E0024, 0x8001 | (data << 1) | (param->dll2_finetune_step << 8));
+
+ /* Wait DQSI latch phase calibration */
+ moutdwm(ast, 0x1E6E0074, 0x00000010);
+ moutdwm(ast, 0x1E6E0070, 0x00000003);
+ do {
+ data = mindwm(ast, 0x1E6E0070);
+ } while (!(data & 0x00001000));
+ moutdwm(ast, 0x1E6E0070, 0x00000000);
+ moutdwm(ast, 0x1E6E0070, 0x00000003);
+ do {
+ data = mindwm(ast, 0x1E6E0070);
+ } while (!(data & 0x00001000));
+ moutdwm(ast, 0x1E6E0070, 0x00000000);
+} /* CBRDLL2 */
+
+static void get_ddr3_info(struct ast_private *ast, struct ast2300_dram_param *param)
+{
+ u32 trap, trap_AC2, trap_MRS;
+
+ moutdwm(ast, 0x1E6E2000, 0x1688A8A8);
+
+ /* Ger trap info */
+ trap = (mindwm(ast, 0x1E6E2070) >> 25) & 0x3;
+ trap_AC2 = 0x00020000 + (trap << 16);
+ trap_AC2 |= 0x00300000 + ((trap & 0x2) << 19);
+ trap_MRS = 0x00000010 + (trap << 4);
+ trap_MRS |= ((trap & 0x2) << 18);
+
+ param->reg_MADJ = 0x00034C4C;
+ param->reg_SADJ = 0x00001800;
+ param->reg_DRV = 0x000000F0;
+ param->reg_PERIOD = param->dram_freq;
+ param->rodt = 0;
+
+ switch (param->dram_freq) {
+ case 336:
+ moutdwm(ast, 0x1E6E2020, 0x0190);
+ param->wodt = 0;
+ param->reg_AC1 = 0x22202725;
+ param->reg_AC2 = 0xAA007613 | trap_AC2;
+ param->reg_DQSIC = 0x000000BA;
+ param->reg_MRS = 0x04001400 | trap_MRS;
+ param->reg_EMRS = 0x00000000;
+ param->reg_IOZ = 0x00000034;
+ param->reg_DQIDLY = 0x00000074;
+ param->reg_FREQ = 0x00004DC0;
+ param->madj_max = 96;
+ param->dll2_finetune_step = 3;
+ break;
+ default:
+ case 396:
+ moutdwm(ast, 0x1E6E2020, 0x03F1);
+ param->wodt = 1;
+ param->reg_AC1 = 0x33302825;
+ param->reg_AC2 = 0xCC009617 | trap_AC2;
+ param->reg_DQSIC = 0x000000E2;
+ param->reg_MRS = 0x04001600 | trap_MRS;
+ param->reg_EMRS = 0x00000000;
+ param->reg_IOZ = 0x00000034;
+ param->reg_DRV = 0x000000FA;
+ param->reg_DQIDLY = 0x00000089;
+ param->reg_FREQ = 0x000050C0;
+ param->madj_max = 96;
+ param->dll2_finetune_step = 4;
+
+ switch (param->dram_chipid) {
+ default:
+ case AST_DRAM_512Mx16:
+ case AST_DRAM_1Gx16:
+ param->reg_AC2 = 0xCC009617 | trap_AC2;
+ break;
+ case AST_DRAM_2Gx16:
+ param->reg_AC2 = 0xCC009622 | trap_AC2;
+ break;
+ case AST_DRAM_4Gx16:
+ param->reg_AC2 = 0xCC00963F | trap_AC2;
+ break;
+ }
+ break;
+
+ case 408:
+ moutdwm(ast, 0x1E6E2020, 0x01F0);
+ param->wodt = 1;
+ param->reg_AC1 = 0x33302825;
+ param->reg_AC2 = 0xCC009617 | trap_AC2;
+ param->reg_DQSIC = 0x000000E2;
+ param->reg_MRS = 0x04001600 | trap_MRS;
+ param->reg_EMRS = 0x00000000;
+ param->reg_IOZ = 0x00000034;
+ param->reg_DRV = 0x000000FA;
+ param->reg_DQIDLY = 0x00000089;
+ param->reg_FREQ = 0x000050C0;
+ param->madj_max = 96;
+ param->dll2_finetune_step = 4;
+
+ switch (param->dram_chipid) {
+ default:
+ case AST_DRAM_512Mx16:
+ case AST_DRAM_1Gx16:
+ param->reg_AC2 = 0xCC009617 | trap_AC2;
+ break;
+ case AST_DRAM_2Gx16:
+ param->reg_AC2 = 0xCC009622 | trap_AC2;
+ break;
+ case AST_DRAM_4Gx16:
+ param->reg_AC2 = 0xCC00963F | trap_AC2;
+ break;
+ }
+
+ break;
+ case 456:
+ moutdwm(ast, 0x1E6E2020, 0x0230);
+ param->wodt = 0;
+ param->reg_AC1 = 0x33302926;
+ param->reg_AC2 = 0xCD44961A;
+ param->reg_DQSIC = 0x000000FC;
+ param->reg_MRS = 0x00081830;
+ param->reg_EMRS = 0x00000000;
+ param->reg_IOZ = 0x00000045;
+ param->reg_DQIDLY = 0x00000097;
+ param->reg_FREQ = 0x000052C0;
+ param->madj_max = 88;
+ param->dll2_finetune_step = 4;
+ break;
+ case 504:
+ moutdwm(ast, 0x1E6E2020, 0x0270);
+ param->wodt = 1;
+ param->reg_AC1 = 0x33302926;
+ param->reg_AC2 = 0xDE44A61D;
+ param->reg_DQSIC = 0x00000117;
+ param->reg_MRS = 0x00081A30;
+ param->reg_EMRS = 0x00000000;
+ param->reg_IOZ = 0x070000BB;
+ param->reg_DQIDLY = 0x000000A0;
+ param->reg_FREQ = 0x000054C0;
+ param->madj_max = 79;
+ param->dll2_finetune_step = 4;
+ break;
+ case 528:
+ moutdwm(ast, 0x1E6E2020, 0x0290);
+ param->wodt = 1;
+ param->rodt = 1;
+ param->reg_AC1 = 0x33302926;
+ param->reg_AC2 = 0xEF44B61E;
+ param->reg_DQSIC = 0x00000125;
+ param->reg_MRS = 0x00081A30;
+ param->reg_EMRS = 0x00000040;
+ param->reg_DRV = 0x000000F5;
+ param->reg_IOZ = 0x00000023;
+ param->reg_DQIDLY = 0x00000088;
+ param->reg_FREQ = 0x000055C0;
+ param->madj_max = 76;
+ param->dll2_finetune_step = 3;
+ break;
+ case 576:
+ moutdwm(ast, 0x1E6E2020, 0x0140);
+ param->reg_MADJ = 0x00136868;
+ param->reg_SADJ = 0x00004534;
+ param->wodt = 1;
+ param->rodt = 1;
+ param->reg_AC1 = 0x33302A37;
+ param->reg_AC2 = 0xEF56B61E;
+ param->reg_DQSIC = 0x0000013F;
+ param->reg_MRS = 0x00101A50;
+ param->reg_EMRS = 0x00000040;
+ param->reg_DRV = 0x000000FA;
+ param->reg_IOZ = 0x00000023;
+ param->reg_DQIDLY = 0x00000078;
+ param->reg_FREQ = 0x000057C0;
+ param->madj_max = 136;
+ param->dll2_finetune_step = 3;
+ break;
+ case 600:
+ moutdwm(ast, 0x1E6E2020, 0x02E1);
+ param->reg_MADJ = 0x00136868;
+ param->reg_SADJ = 0x00004534;
+ param->wodt = 1;
+ param->rodt = 1;
+ param->reg_AC1 = 0x32302A37;
+ param->reg_AC2 = 0xDF56B61F;
+ param->reg_DQSIC = 0x0000014D;
+ param->reg_MRS = 0x00101A50;
+ param->reg_EMRS = 0x00000004;
+ param->reg_DRV = 0x000000F5;
+ param->reg_IOZ = 0x00000023;
+ param->reg_DQIDLY = 0x00000078;
+ param->reg_FREQ = 0x000058C0;
+ param->madj_max = 132;
+ param->dll2_finetune_step = 3;
+ break;
+ case 624:
+ moutdwm(ast, 0x1E6E2020, 0x0160);
+ param->reg_MADJ = 0x00136868;
+ param->reg_SADJ = 0x00004534;
+ param->wodt = 1;
+ param->rodt = 1;
+ param->reg_AC1 = 0x32302A37;
+ param->reg_AC2 = 0xEF56B621;
+ param->reg_DQSIC = 0x0000015A;
+ param->reg_MRS = 0x02101A50;
+ param->reg_EMRS = 0x00000004;
+ param->reg_DRV = 0x000000F5;
+ param->reg_IOZ = 0x00000034;
+ param->reg_DQIDLY = 0x00000078;
+ param->reg_FREQ = 0x000059C0;
+ param->madj_max = 128;
+ param->dll2_finetune_step = 3;
+ break;
+ } /* switch freq */
+
+ switch (param->dram_chipid) {
+ case AST_DRAM_512Mx16:
+ param->dram_config = 0x130;
+ break;
+ default:
+ case AST_DRAM_1Gx16:
+ param->dram_config = 0x131;
+ break;
+ case AST_DRAM_2Gx16:
+ param->dram_config = 0x132;
+ break;
+ case AST_DRAM_4Gx16:
+ param->dram_config = 0x133;
+ break;
+ }; /* switch size */
+
+ switch (param->vram_size) {
+ default:
+ case AST_VIDMEM_SIZE_8M:
+ param->dram_config |= 0x00;
+ break;
+ case AST_VIDMEM_SIZE_16M:
+ param->dram_config |= 0x04;
+ break;
+ case AST_VIDMEM_SIZE_32M:
+ param->dram_config |= 0x08;
+ break;
+ case AST_VIDMEM_SIZE_64M:
+ param->dram_config |= 0x0c;
+ break;
+ }
+
+}
+
+static void ddr3_init(struct ast_private *ast, struct ast2300_dram_param *param)
+{
+ u32 data, data2;
+
+ moutdwm(ast, 0x1E6E0000, 0xFC600309);
+ moutdwm(ast, 0x1E6E0018, 0x00000100);
+ moutdwm(ast, 0x1E6E0024, 0x00000000);
+ moutdwm(ast, 0x1E6E0034, 0x00000000);
+ udelay(10);
+ moutdwm(ast, 0x1E6E0064, param->reg_MADJ);
+ moutdwm(ast, 0x1E6E0068, param->reg_SADJ);
+ udelay(10);
+ moutdwm(ast, 0x1E6E0064, param->reg_MADJ | 0xC0000);
+ udelay(10);
+
+ moutdwm(ast, 0x1E6E0004, param->dram_config);
+ moutdwm(ast, 0x1E6E0008, 0x90040f);
+ moutdwm(ast, 0x1E6E0010, param->reg_AC1);
+ moutdwm(ast, 0x1E6E0014, param->reg_AC2);
+ moutdwm(ast, 0x1E6E0020, param->reg_DQSIC);
+ moutdwm(ast, 0x1E6E0080, 0x00000000);
+ moutdwm(ast, 0x1E6E0084, 0x00000000);
+ moutdwm(ast, 0x1E6E0088, param->reg_DQIDLY);
+ moutdwm(ast, 0x1E6E0018, 0x4040A170);
+ moutdwm(ast, 0x1E6E0018, 0x20402370);
+ moutdwm(ast, 0x1E6E0038, 0x00000000);
+ moutdwm(ast, 0x1E6E0040, 0xFF444444);
+ moutdwm(ast, 0x1E6E0044, 0x22222222);
+ moutdwm(ast, 0x1E6E0048, 0x22222222);
+ moutdwm(ast, 0x1E6E004C, 0x00000002);
+ moutdwm(ast, 0x1E6E0050, 0x80000000);
+ moutdwm(ast, 0x1E6E0050, 0x00000000);
+ moutdwm(ast, 0x1E6E0054, 0);
+ moutdwm(ast, 0x1E6E0060, param->reg_DRV);
+ moutdwm(ast, 0x1E6E006C, param->reg_IOZ);
+ moutdwm(ast, 0x1E6E0070, 0x00000000);
+ moutdwm(ast, 0x1E6E0074, 0x00000000);
+ moutdwm(ast, 0x1E6E0078, 0x00000000);
+ moutdwm(ast, 0x1E6E007C, 0x00000000);
+ /* Wait MCLK2X lock to MCLK */
+ do {
+ data = mindwm(ast, 0x1E6E001C);
+ } while (!(data & 0x08000000));
+ moutdwm(ast, 0x1E6E0034, 0x00000001);
+ moutdwm(ast, 0x1E6E000C, 0x00005C04);
+ udelay(10);
+ moutdwm(ast, 0x1E6E000C, 0x00000000);
+ moutdwm(ast, 0x1E6E0034, 0x00000000);
+ data = mindwm(ast, 0x1E6E001C);
+ data = (data >> 8) & 0xff;
+ while ((data & 0x08) || ((data & 0x7) < 2) || (data < 4)) {
+ data2 = (mindwm(ast, 0x1E6E0064) & 0xfff3ffff) + 4;
+ if ((data2 & 0xff) > param->madj_max) {
+ break;
+ }
+ moutdwm(ast, 0x1E6E0064, data2);
+ if (data2 & 0x00100000) {
+ data2 = ((data2 & 0xff) >> 3) + 3;
+ } else {
+ data2 = ((data2 & 0xff) >> 2) + 5;
+ }
+ data = mindwm(ast, 0x1E6E0068) & 0xffff00ff;
+ data2 += data & 0xff;
+ data = data | (data2 << 8);
+ moutdwm(ast, 0x1E6E0068, data);
+ udelay(10);
+ moutdwm(ast, 0x1E6E0064, mindwm(ast, 0x1E6E0064) | 0xC0000);
+ udelay(10);
+ data = mindwm(ast, 0x1E6E0018) & 0xfffff1ff;
+ moutdwm(ast, 0x1E6E0018, data);
+ data = data | 0x200;
+ moutdwm(ast, 0x1E6E0018, data);
+ do {
+ data = mindwm(ast, 0x1E6E001C);
+ } while (!(data & 0x08000000));
+
+ moutdwm(ast, 0x1E6E0034, 0x00000001);
+ moutdwm(ast, 0x1E6E000C, 0x00005C04);
+ udelay(10);
+ moutdwm(ast, 0x1E6E000C, 0x00000000);
+ moutdwm(ast, 0x1E6E0034, 0x00000000);
+ data = mindwm(ast, 0x1E6E001C);
+ data = (data >> 8) & 0xff;
+ }
+ data = mindwm(ast, 0x1E6E0018) | 0xC00;
+ moutdwm(ast, 0x1E6E0018, data);
+
+ moutdwm(ast, 0x1E6E0034, 0x00000001);
+ moutdwm(ast, 0x1E6E000C, 0x00000040);
+ udelay(50);
+ /* Mode Register Setting */
+ moutdwm(ast, 0x1E6E002C, param->reg_MRS | 0x100);
+ moutdwm(ast, 0x1E6E0030, param->reg_EMRS);
+ moutdwm(ast, 0x1E6E0028, 0x00000005);
+ moutdwm(ast, 0x1E6E0028, 0x00000007);
+ moutdwm(ast, 0x1E6E0028, 0x00000003);
+ moutdwm(ast, 0x1E6E0028, 0x00000001);
+ moutdwm(ast, 0x1E6E002C, param->reg_MRS);
+ moutdwm(ast, 0x1E6E000C, 0x00005C08);
+ moutdwm(ast, 0x1E6E0028, 0x00000001);
+
+ moutdwm(ast, 0x1E6E000C, 0x7FFF5C01);
+ data = 0;
+ if (param->wodt) {
+ data = 0x300;
+ }
+ if (param->rodt) {
+ data = data | 0x3000 | ((param->reg_AC2 & 0x60000) >> 3);
+ }
+ moutdwm(ast, 0x1E6E0034, data | 0x3);
+
+ /* Wait DQI delay lock */
+ do {
+ data = mindwm(ast, 0x1E6E0080);
+ } while (!(data & 0x40000000));
+ /* Wait DQSI delay lock */
+ do {
+ data = mindwm(ast, 0x1E6E0020);
+ } while (!(data & 0x00000800));
+ /* Calibrate the DQSI delay */
+ cbr_dll2(ast, param);
+
+ moutdwm(ast, 0x1E6E0120, param->reg_FREQ);
+ /* ECC Memory Initialization */
+#ifdef ECC
+ moutdwm(ast, 0x1E6E007C, 0x00000000);
+ moutdwm(ast, 0x1E6E0070, 0x221);
+ do {
+ data = mindwm(ast, 0x1E6E0070);
+ } while (!(data & 0x00001000));
+ moutdwm(ast, 0x1E6E0070, 0x00000000);
+ moutdwm(ast, 0x1E6E0050, 0x80000000);
+ moutdwm(ast, 0x1E6E0050, 0x00000000);
+#endif
+
+
+}
+
+static void get_ddr2_info(struct ast_private *ast, struct ast2300_dram_param *param)
+{
+ u32 trap, trap_AC2, trap_MRS;
+
+ moutdwm(ast, 0x1E6E2000, 0x1688A8A8);
+
+ /* Ger trap info */
+ trap = (mindwm(ast, 0x1E6E2070) >> 25) & 0x3;
+ trap_AC2 = (trap << 20) | (trap << 16);
+ trap_AC2 += 0x00110000;
+ trap_MRS = 0x00000040 | (trap << 4);
+
+
+ param->reg_MADJ = 0x00034C4C;
+ param->reg_SADJ = 0x00001800;
+ param->reg_DRV = 0x000000F0;
+ param->reg_PERIOD = param->dram_freq;
+ param->rodt = 0;
+
+ switch (param->dram_freq) {
+ case 264:
+ moutdwm(ast, 0x1E6E2020, 0x0130);
+ param->wodt = 0;
+ param->reg_AC1 = 0x11101513;
+ param->reg_AC2 = 0x78117011;
+ param->reg_DQSIC = 0x00000092;
+ param->reg_MRS = 0x00000842;
+ param->reg_EMRS = 0x00000000;
+ param->reg_DRV = 0x000000F0;
+ param->reg_IOZ = 0x00000034;
+ param->reg_DQIDLY = 0x0000005A;
+ param->reg_FREQ = 0x00004AC0;
+ param->madj_max = 138;
+ param->dll2_finetune_step = 3;
+ break;
+ case 336:
+ moutdwm(ast, 0x1E6E2020, 0x0190);
+ param->wodt = 1;
+ param->reg_AC1 = 0x22202613;
+ param->reg_AC2 = 0xAA009016 | trap_AC2;
+ param->reg_DQSIC = 0x000000BA;
+ param->reg_MRS = 0x00000A02 | trap_MRS;
+ param->reg_EMRS = 0x00000040;
+ param->reg_DRV = 0x000000FA;
+ param->reg_IOZ = 0x00000034;
+ param->reg_DQIDLY = 0x00000074;
+ param->reg_FREQ = 0x00004DC0;
+ param->madj_max = 96;
+ param->dll2_finetune_step = 3;
+ break;
+ default:
+ case 396:
+ moutdwm(ast, 0x1E6E2020, 0x03F1);
+ param->wodt = 1;
+ param->rodt = 0;
+ param->reg_AC1 = 0x33302714;
+ param->reg_AC2 = 0xCC00B01B | trap_AC2;
+ param->reg_DQSIC = 0x000000E2;
+ param->reg_MRS = 0x00000C02 | trap_MRS;
+ param->reg_EMRS = 0x00000040;
+ param->reg_DRV = 0x000000FA;
+ param->reg_IOZ = 0x00000034;
+ param->reg_DQIDLY = 0x00000089;
+ param->reg_FREQ = 0x000050C0;
+ param->madj_max = 96;
+ param->dll2_finetune_step = 4;
+
+ switch (param->dram_chipid) {
+ case AST_DRAM_512Mx16:
+ param->reg_AC2 = 0xCC00B016 | trap_AC2;
+ break;
+ default:
+ case AST_DRAM_1Gx16:
+ param->reg_AC2 = 0xCC00B01B | trap_AC2;
+ break;
+ case AST_DRAM_2Gx16:
+ param->reg_AC2 = 0xCC00B02B | trap_AC2;
+ break;
+ case AST_DRAM_4Gx16:
+ param->reg_AC2 = 0xCC00B03F | trap_AC2;
+ break;
+ }
+
+ break;
+
+ case 408:
+ moutdwm(ast, 0x1E6E2020, 0x01F0);
+ param->wodt = 1;
+ param->rodt = 0;
+ param->reg_AC1 = 0x33302714;
+ param->reg_AC2 = 0xCC00B01B | trap_AC2;
+ param->reg_DQSIC = 0x000000E2;
+ param->reg_MRS = 0x00000C02 | trap_MRS;
+ param->reg_EMRS = 0x00000040;
+ param->reg_DRV = 0x000000FA;
+ param->reg_IOZ = 0x00000034;
+ param->reg_DQIDLY = 0x00000089;
+ param->reg_FREQ = 0x000050C0;
+ param->madj_max = 96;
+ param->dll2_finetune_step = 4;
+
+ switch (param->dram_chipid) {
+ case AST_DRAM_512Mx16:
+ param->reg_AC2 = 0xCC00B016 | trap_AC2;
+ break;
+ default:
+ case AST_DRAM_1Gx16:
+ param->reg_AC2 = 0xCC00B01B | trap_AC2;
+ break;
+ case AST_DRAM_2Gx16:
+ param->reg_AC2 = 0xCC00B02B | trap_AC2;
+ break;
+ case AST_DRAM_4Gx16:
+ param->reg_AC2 = 0xCC00B03F | trap_AC2;
+ break;
+ }
+
+ break;
+ case 456:
+ moutdwm(ast, 0x1E6E2020, 0x0230);
+ param->wodt = 0;
+ param->reg_AC1 = 0x33302815;
+ param->reg_AC2 = 0xCD44B01E;
+ param->reg_DQSIC = 0x000000FC;
+ param->reg_MRS = 0x00000E72;
+ param->reg_EMRS = 0x00000000;
+ param->reg_DRV = 0x00000000;
+ param->reg_IOZ = 0x00000034;
+ param->reg_DQIDLY = 0x00000097;
+ param->reg_FREQ = 0x000052C0;
+ param->madj_max = 88;
+ param->dll2_finetune_step = 3;
+ break;
+ case 504:
+ moutdwm(ast, 0x1E6E2020, 0x0261);
+ param->wodt = 1;
+ param->rodt = 1;
+ param->reg_AC1 = 0x33302815;
+ param->reg_AC2 = 0xDE44C022;
+ param->reg_DQSIC = 0x00000117;
+ param->reg_MRS = 0x00000E72;
+ param->reg_EMRS = 0x00000040;
+ param->reg_DRV = 0x0000000A;
+ param->reg_IOZ = 0x00000045;
+ param->reg_DQIDLY = 0x000000A0;
+ param->reg_FREQ = 0x000054C0;
+ param->madj_max = 79;
+ param->dll2_finetune_step = 3;
+ break;
+ case 528:
+ moutdwm(ast, 0x1E6E2020, 0x0120);
+ param->wodt = 1;
+ param->rodt = 1;
+ param->reg_AC1 = 0x33302815;
+ param->reg_AC2 = 0xEF44D024;
+ param->reg_DQSIC = 0x00000125;
+ param->reg_MRS = 0x00000E72;
+ param->reg_EMRS = 0x00000004;
+ param->reg_DRV = 0x000000F9;
+ param->reg_IOZ = 0x00000045;
+ param->reg_DQIDLY = 0x000000A7;
+ param->reg_FREQ = 0x000055C0;
+ param->madj_max = 76;
+ param->dll2_finetune_step = 3;
+ break;
+ case 552:
+ moutdwm(ast, 0x1E6E2020, 0x02A1);
+ param->wodt = 1;
+ param->rodt = 1;
+ param->reg_AC1 = 0x43402915;
+ param->reg_AC2 = 0xFF44E025;
+ param->reg_DQSIC = 0x00000132;
+ param->reg_MRS = 0x00000E72;
+ param->reg_EMRS = 0x00000040;
+ param->reg_DRV = 0x0000000A;
+ param->reg_IOZ = 0x00000045;
+ param->reg_DQIDLY = 0x000000AD;
+ param->reg_FREQ = 0x000056C0;
+ param->madj_max = 76;
+ param->dll2_finetune_step = 3;
+ break;
+ case 576:
+ moutdwm(ast, 0x1E6E2020, 0x0140);
+ param->wodt = 1;
+ param->rodt = 1;
+ param->reg_AC1 = 0x43402915;
+ param->reg_AC2 = 0xFF44E027;
+ param->reg_DQSIC = 0x0000013F;
+ param->reg_MRS = 0x00000E72;
+ param->reg_EMRS = 0x00000004;
+ param->reg_DRV = 0x000000F5;
+ param->reg_IOZ = 0x00000045;
+ param->reg_DQIDLY = 0x000000B3;
+ param->reg_FREQ = 0x000057C0;
+ param->madj_max = 76;
+ param->dll2_finetune_step = 3;
+ break;
+ }
+
+ switch (param->dram_chipid) {
+ case AST_DRAM_512Mx16:
+ param->dram_config = 0x100;
+ break;
+ default:
+ case AST_DRAM_1Gx16:
+ param->dram_config = 0x121;
+ break;
+ case AST_DRAM_2Gx16:
+ param->dram_config = 0x122;
+ break;
+ case AST_DRAM_4Gx16:
+ param->dram_config = 0x123;
+ break;
+ }; /* switch size */
+
+ switch (param->vram_size) {
+ default:
+ case AST_VIDMEM_SIZE_8M:
+ param->dram_config |= 0x00;
+ break;
+ case AST_VIDMEM_SIZE_16M:
+ param->dram_config |= 0x04;
+ break;
+ case AST_VIDMEM_SIZE_32M:
+ param->dram_config |= 0x08;
+ break;
+ case AST_VIDMEM_SIZE_64M:
+ param->dram_config |= 0x0c;
+ break;
+ }
+}
+
+static void ddr2_init(struct ast_private *ast, struct ast2300_dram_param *param)
+{
+ u32 data, data2;
+
+ moutdwm(ast, 0x1E6E0000, 0xFC600309);
+ moutdwm(ast, 0x1E6E0018, 0x00000100);
+ moutdwm(ast, 0x1E6E0024, 0x00000000);
+ moutdwm(ast, 0x1E6E0064, param->reg_MADJ);
+ moutdwm(ast, 0x1E6E0068, param->reg_SADJ);
+ udelay(10);
+ moutdwm(ast, 0x1E6E0064, param->reg_MADJ | 0xC0000);
+ udelay(10);
+
+ moutdwm(ast, 0x1E6E0004, param->dram_config);
+ moutdwm(ast, 0x1E6E0008, 0x90040f);
+ moutdwm(ast, 0x1E6E0010, param->reg_AC1);
+ moutdwm(ast, 0x1E6E0014, param->reg_AC2);
+ moutdwm(ast, 0x1E6E0020, param->reg_DQSIC);
+ moutdwm(ast, 0x1E6E0080, 0x00000000);
+ moutdwm(ast, 0x1E6E0084, 0x00000000);
+ moutdwm(ast, 0x1E6E0088, param->reg_DQIDLY);
+ moutdwm(ast, 0x1E6E0018, 0x4040A130);
+ moutdwm(ast, 0x1E6E0018, 0x20402330);
+ moutdwm(ast, 0x1E6E0038, 0x00000000);
+ moutdwm(ast, 0x1E6E0040, 0xFF808000);
+ moutdwm(ast, 0x1E6E0044, 0x88848466);
+ moutdwm(ast, 0x1E6E0048, 0x44440008);
+ moutdwm(ast, 0x1E6E004C, 0x00000000);
+ moutdwm(ast, 0x1E6E0050, 0x80000000);
+ moutdwm(ast, 0x1E6E0050, 0x00000000);
+ moutdwm(ast, 0x1E6E0054, 0);
+ moutdwm(ast, 0x1E6E0060, param->reg_DRV);
+ moutdwm(ast, 0x1E6E006C, param->reg_IOZ);
+ moutdwm(ast, 0x1E6E0070, 0x00000000);
+ moutdwm(ast, 0x1E6E0074, 0x00000000);
+ moutdwm(ast, 0x1E6E0078, 0x00000000);
+ moutdwm(ast, 0x1E6E007C, 0x00000000);
+
+ /* Wait MCLK2X lock to MCLK */
+ do {
+ data = mindwm(ast, 0x1E6E001C);
+ } while (!(data & 0x08000000));
+ moutdwm(ast, 0x1E6E0034, 0x00000001);
+ moutdwm(ast, 0x1E6E000C, 0x00005C04);
+ udelay(10);
+ moutdwm(ast, 0x1E6E000C, 0x00000000);
+ moutdwm(ast, 0x1E6E0034, 0x00000000);
+ data = mindwm(ast, 0x1E6E001C);
+ data = (data >> 8) & 0xff;
+ while ((data & 0x08) || ((data & 0x7) < 2) || (data < 4)) {
+ data2 = (mindwm(ast, 0x1E6E0064) & 0xfff3ffff) + 4;
+ if ((data2 & 0xff) > param->madj_max) {
+ break;
+ }
+ moutdwm(ast, 0x1E6E0064, data2);
+ if (data2 & 0x00100000) {
+ data2 = ((data2 & 0xff) >> 3) + 3;
+ } else {
+ data2 = ((data2 & 0xff) >> 2) + 5;
+ }
+ data = mindwm(ast, 0x1E6E0068) & 0xffff00ff;
+ data2 += data & 0xff;
+ data = data | (data2 << 8);
+ moutdwm(ast, 0x1E6E0068, data);
+ udelay(10);
+ moutdwm(ast, 0x1E6E0064, mindwm(ast, 0x1E6E0064) | 0xC0000);
+ udelay(10);
+ data = mindwm(ast, 0x1E6E0018) & 0xfffff1ff;
+ moutdwm(ast, 0x1E6E0018, data);
+ data = data | 0x200;
+ moutdwm(ast, 0x1E6E0018, data);
+ do {
+ data = mindwm(ast, 0x1E6E001C);
+ } while (!(data & 0x08000000));
+
+ moutdwm(ast, 0x1E6E0034, 0x00000001);
+ moutdwm(ast, 0x1E6E000C, 0x00005C04);
+ udelay(10);
+ moutdwm(ast, 0x1E6E000C, 0x00000000);
+ moutdwm(ast, 0x1E6E0034, 0x00000000);
+ data = mindwm(ast, 0x1E6E001C);
+ data = (data >> 8) & 0xff;
+ }
+ data = mindwm(ast, 0x1E6E0018) | 0xC00;
+ moutdwm(ast, 0x1E6E0018, data);
+
+ moutdwm(ast, 0x1E6E0034, 0x00000001);
+ moutdwm(ast, 0x1E6E000C, 0x00000000);
+ udelay(50);
+ /* Mode Register Setting */
+ moutdwm(ast, 0x1E6E002C, param->reg_MRS | 0x100);
+ moutdwm(ast, 0x1E6E0030, param->reg_EMRS);
+ moutdwm(ast, 0x1E6E0028, 0x00000005);
+ moutdwm(ast, 0x1E6E0028, 0x00000007);
+ moutdwm(ast, 0x1E6E0028, 0x00000003);
+ moutdwm(ast, 0x1E6E0028, 0x00000001);
+
+ moutdwm(ast, 0x1E6E000C, 0x00005C08);
+ moutdwm(ast, 0x1E6E002C, param->reg_MRS);
+ moutdwm(ast, 0x1E6E0028, 0x00000001);
+ moutdwm(ast, 0x1E6E0030, param->reg_EMRS | 0x380);
+ moutdwm(ast, 0x1E6E0028, 0x00000003);
+ moutdwm(ast, 0x1E6E0030, param->reg_EMRS);
+ moutdwm(ast, 0x1E6E0028, 0x00000003);
+
+ moutdwm(ast, 0x1E6E000C, 0x7FFF5C01);
+ data = 0;
+ if (param->wodt) {
+ data = 0x500;
+ }
+ if (param->rodt) {
+ data = data | 0x3000 | ((param->reg_AC2 & 0x60000) >> 3);
+ }
+ moutdwm(ast, 0x1E6E0034, data | 0x3);
+ moutdwm(ast, 0x1E6E0120, param->reg_FREQ);
+
+ /* Wait DQI delay lock */
+ do {
+ data = mindwm(ast, 0x1E6E0080);
+ } while (!(data & 0x40000000));
+ /* Wait DQSI delay lock */
+ do {
+ data = mindwm(ast, 0x1E6E0020);
+ } while (!(data & 0x00000800));
+ /* Calibrate the DQSI delay */
+ cbr_dll2(ast, param);
+
+ /* ECC Memory Initialization */
+#ifdef ECC
+ moutdwm(ast, 0x1E6E007C, 0x00000000);
+ moutdwm(ast, 0x1E6E0070, 0x221);
+ do {
+ data = mindwm(ast, 0x1E6E0070);
+ } while (!(data & 0x00001000));
+ moutdwm(ast, 0x1E6E0070, 0x00000000);
+ moutdwm(ast, 0x1E6E0050, 0x80000000);
+ moutdwm(ast, 0x1E6E0050, 0x00000000);
+#endif
+
+}
+
+static void ast_init_dram_2300(struct drm_device *dev)
+{
+ struct ast_private *ast = dev->dev_private;
+ struct ast2300_dram_param param;
+ u32 temp;
+ u8 reg;
+
+ reg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
+ if ((reg & 0x80) == 0) {/* vga only */
+ ast_write32(ast, 0xf004, 0x1e6e0000);
+ ast_write32(ast, 0xf000, 0x1);
+ ast_write32(ast, 0x12000, 0x1688a8a8);
+ do {
+ ;
+ } while (ast_read32(ast, 0x12000) != 0x1);
+
+ ast_write32(ast, 0x10000, 0xfc600309);
+ do {
+ ;
+ } while (ast_read32(ast, 0x10000) != 0x1);
+
+ /* Slow down CPU/AHB CLK in VGA only mode */
+ temp = ast_read32(ast, 0x12008);
+ temp |= 0x73;
+ ast_write32(ast, 0x12008, temp);
+
+ param.dram_type = AST_DDR3;
+ if (temp & 0x01000000)
+ param.dram_type = AST_DDR2;
+ param.dram_chipid = ast->dram_type;
+ param.dram_freq = ast->mclk;
+ param.vram_size = ast->vram_size;
+
+ if (param.dram_type == AST_DDR3) {
+ get_ddr3_info(ast, &param);
+ ddr3_init(ast, &param);
+ } else {
+ get_ddr2_info(ast, &param);
+ ddr2_init(ast, &param);
+ }
+
+ temp = mindwm(ast, 0x1e6e2040);
+ moutdwm(ast, 0x1e6e2040, temp | 0x40);
+ }
+
+ /* wait ready */
+ do {
+ reg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
+ } while ((reg & 0x40) == 0);
+}
+
diff --git a/drivers/gpu/drm/ast/ast_tables.h b/drivers/gpu/drm/ast/ast_tables.h
new file mode 100644
index 000000000000..95fa6aba26bc
--- /dev/null
+++ b/drivers/gpu/drm/ast/ast_tables.h
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2005 ASPEED Technology Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the authors not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. The authors makes no representations
+ * about the suitability of this software for any purpose. It is provided
+ * "as is" without express or implied warranty.
+ *
+ * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+/* Ported from xf86-video-ast driver */
+
+#ifndef AST_TABLES_H
+#define AST_TABLES_H
+
+/* Std. Table Index Definition */
+#define TextModeIndex 0
+#define EGAModeIndex 1
+#define VGAModeIndex 2
+#define HiCModeIndex 3
+#define TrueCModeIndex 4
+
+#define Charx8Dot 0x00000001
+#define HalfDCLK 0x00000002
+#define DoubleScanMode 0x00000004
+#define LineCompareOff 0x00000008
+#define SyncPP 0x00000000
+#define SyncPN 0x00000040
+#define SyncNP 0x00000080
+#define SyncNN 0x000000C0
+#define HBorder 0x00000020
+#define VBorder 0x00000010
+#define WideScreenMode 0x00000100
+
+
+/* DCLK Index */
+#define VCLK25_175 0x00
+#define VCLK28_322 0x01
+#define VCLK31_5 0x02
+#define VCLK36 0x03
+#define VCLK40 0x04
+#define VCLK49_5 0x05
+#define VCLK50 0x06
+#define VCLK56_25 0x07
+#define VCLK65 0x08
+#define VCLK75 0x09
+#define VCLK78_75 0x0A
+#define VCLK94_5 0x0B
+#define VCLK108 0x0C
+#define VCLK135 0x0D
+#define VCLK157_5 0x0E
+#define VCLK162 0x0F
+/* #define VCLK193_25 0x10 */
+#define VCLK154 0x10
+#define VCLK83_5 0x11
+#define VCLK106_5 0x12
+#define VCLK146_25 0x13
+#define VCLK148_5 0x14
+
+static struct ast_vbios_dclk_info dclk_table[] = {
+ {0x2C, 0xE7, 0x03}, /* 00: VCLK25_175 */
+ {0x95, 0x62, 0x03}, /* 01: VCLK28_322 */
+ {0x67, 0x63, 0x01}, /* 02: VCLK31_5 */
+ {0x76, 0x63, 0x01}, /* 03: VCLK36 */
+ {0xEE, 0x67, 0x01}, /* 04: VCLK40 */
+ {0x82, 0x62, 0x01}, /* 05: VCLK49_5 */
+ {0xC6, 0x64, 0x01}, /* 06: VCLK50 */
+ {0x94, 0x62, 0x01}, /* 07: VCLK56_25 */
+ {0x80, 0x64, 0x00}, /* 08: VCLK65 */
+ {0x7B, 0x63, 0x00}, /* 09: VCLK75 */
+ {0x67, 0x62, 0x00}, /* 0A: VCLK78_75 */
+ {0x7C, 0x62, 0x00}, /* 0B: VCLK94_5 */
+ {0x8E, 0x62, 0x00}, /* 0C: VCLK108 */
+ {0x85, 0x24, 0x00}, /* 0D: VCLK135 */
+ {0x67, 0x22, 0x00}, /* 0E: VCLK157_5 */
+ {0x6A, 0x22, 0x00}, /* 0F: VCLK162 */
+ {0x4d, 0x4c, 0x80}, /* 10: VCLK154 */
+ {0xa7, 0x78, 0x80}, /* 11: VCLK83.5 */
+ {0x28, 0x49, 0x80}, /* 12: VCLK106.5 */
+ {0x37, 0x49, 0x80}, /* 13: VCLK146.25 */
+ {0x1f, 0x45, 0x80}, /* 14: VCLK148.5 */
+};
+
+static struct ast_vbios_stdtable vbios_stdtable[] = {
+ /* MD_2_3_400 */
+ {
+ 0x67,
+ {0x00,0x03,0x00,0x02},
+ {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+ 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
+ 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
+ 0xff},
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+ 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x0c,0x00,0x0f,0x08},
+ {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+ 0xff}
+ },
+ /* Mode12/ExtEGATable */
+ {
+ 0xe3,
+ {0x01,0x0f,0x00,0x06},
+ {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,
+ 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xe9,0x8b,0xdf,0x28,0x00,0xe7,0x04,0xe3,
+ 0xff},
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+ 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x01,0x00,0x0f,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
+ 0xff}
+ },
+ /* ExtVGATable */
+ {
+ 0x2f,
+ {0x01,0x0f,0x00,0x0e},
+ {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
+ 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
+ 0xff},
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+ 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+ 0x01,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
+ 0xff}
+ },
+ /* ExtHiCTable */
+ {
+ 0x2f,
+ {0x01,0x0f,0x00,0x0e},
+ {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
+ 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
+ 0xff},
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+ 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+ 0x01,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
+ 0xff}
+ },
+ /* ExtTrueCTable */
+ {
+ 0x2f,
+ {0x01,0x0f,0x00,0x0e},
+ {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
+ 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
+ 0xff},
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+ 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+ 0x01,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
+ 0xff}
+ },
+};
+
+static struct ast_vbios_enhtable res_640x480[] = {
+ { 800, 640, 8, 96, 525, 480, 2, 2, VCLK25_175, /* 60Hz */
+ (SyncNN | HBorder | VBorder | Charx8Dot), 60, 1, 0x2E },
+ { 832, 640, 16, 40, 520, 480, 1, 3, VCLK31_5, /* 72Hz */
+ (SyncNN | HBorder | VBorder | Charx8Dot), 72, 2, 0x2E },
+ { 840, 640, 16, 64, 500, 480, 1, 3, VCLK31_5, /* 75Hz */
+ (SyncNN | Charx8Dot) , 75, 3, 0x2E },
+ { 832, 640, 56, 56, 509, 480, 1, 3, VCLK36, /* 85Hz */
+ (SyncNN | Charx8Dot) , 85, 4, 0x2E },
+ { 832, 640, 56, 56, 509, 480, 1, 3, VCLK36, /* end */
+ (SyncNN | Charx8Dot) , 0xFF, 4, 0x2E },
+};
+
+static struct ast_vbios_enhtable res_800x600[] = {
+ {1024, 800, 24, 72, 625, 600, 1, 2, VCLK36, /* 56Hz */
+ (SyncPP | Charx8Dot), 56, 1, 0x30 },
+ {1056, 800, 40, 128, 628, 600, 1, 4, VCLK40, /* 60Hz */
+ (SyncPP | Charx8Dot), 60, 2, 0x30 },
+ {1040, 800, 56, 120, 666, 600, 37, 6, VCLK50, /* 72Hz */
+ (SyncPP | Charx8Dot), 72, 3, 0x30 },
+ {1056, 800, 16, 80, 625, 600, 1, 3, VCLK49_5, /* 75Hz */
+ (SyncPP | Charx8Dot), 75, 4, 0x30 },
+ {1048, 800, 32, 64, 631, 600, 1, 3, VCLK56_25, /* 85Hz */
+ (SyncPP | Charx8Dot), 84, 5, 0x30 },
+ {1048, 800, 32, 64, 631, 600, 1, 3, VCLK56_25, /* end */
+ (SyncPP | Charx8Dot), 0xFF, 5, 0x30 },
+};
+
+
+static struct ast_vbios_enhtable res_1024x768[] = {
+ {1344, 1024, 24, 136, 806, 768, 3, 6, VCLK65, /* 60Hz */
+ (SyncNN | Charx8Dot), 60, 1, 0x31 },
+ {1328, 1024, 24, 136, 806, 768, 3, 6, VCLK75, /* 70Hz */
+ (SyncNN | Charx8Dot), 70, 2, 0x31 },
+ {1312, 1024, 16, 96, 800, 768, 1, 3, VCLK78_75, /* 75Hz */
+ (SyncPP | Charx8Dot), 75, 3, 0x31 },
+ {1376, 1024, 48, 96, 808, 768, 1, 3, VCLK94_5, /* 85Hz */
+ (SyncPP | Charx8Dot), 84, 4, 0x31 },
+ {1376, 1024, 48, 96, 808, 768, 1, 3, VCLK94_5, /* end */
+ (SyncPP | Charx8Dot), 0xFF, 4, 0x31 },
+};
+
+static struct ast_vbios_enhtable res_1280x1024[] = {
+ {1688, 1280, 48, 112, 1066, 1024, 1, 3, VCLK108, /* 60Hz */
+ (SyncPP | Charx8Dot), 60, 1, 0x32 },
+ {1688, 1280, 16, 144, 1066, 1024, 1, 3, VCLK135, /* 75Hz */
+ (SyncPP | Charx8Dot), 75, 2, 0x32 },
+ {1728, 1280, 64, 160, 1072, 1024, 1, 3, VCLK157_5, /* 85Hz */
+ (SyncPP | Charx8Dot), 85, 3, 0x32 },
+ {1728, 1280, 64, 160, 1072, 1024, 1, 3, VCLK157_5, /* end */
+ (SyncPP | Charx8Dot), 0xFF, 3, 0x32 },
+};
+
+static struct ast_vbios_enhtable res_1600x1200[] = {
+ {2160, 1600, 64, 192, 1250, 1200, 1, 3, VCLK162, /* 60Hz */
+ (SyncPP | Charx8Dot), 60, 1, 0x33 },
+ {2160, 1600, 64, 192, 1250, 1200, 1, 3, VCLK162, /* end */
+ (SyncPP | Charx8Dot), 0xFF, 1, 0x33 },
+};
+
+static struct ast_vbios_enhtable res_1920x1200[] = {
+ {2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz */
+ (SyncNP | Charx8Dot), 60, 1, 0x34 },
+ {2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz */
+ (SyncNP | Charx8Dot), 0xFF, 1, 0x34 },
+};
+
+/* 16:10 */
+static struct ast_vbios_enhtable res_1280x800[] = {
+ {1680, 1280, 72,128, 831, 800, 3, 6, VCLK83_5, /* 60Hz */
+ (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 60, 1, 0x35 },
+ {1680, 1280, 72,128, 831, 800, 3, 6, VCLK83_5, /* 60Hz */
+ (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 0xFF, 1, 0x35 },
+
+};
+
+static struct ast_vbios_enhtable res_1440x900[] = {
+ {1904, 1440, 80,152, 934, 900, 3, 6, VCLK106_5, /* 60Hz */
+ (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 60, 1, 0x36 },
+ {1904, 1440, 80,152, 934, 900, 3, 6, VCLK106_5, /* 60Hz */
+ (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 0xFF, 1, 0x36 },
+};
+
+static struct ast_vbios_enhtable res_1680x1050[] = {
+ {2240, 1680,104,176, 1089, 1050, 3, 6, VCLK146_25, /* 60Hz */
+ (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 60, 1, 0x37 },
+ {2240, 1680,104,176, 1089, 1050, 3, 6, VCLK146_25, /* 60Hz */
+ (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 0xFF, 1, 0x37 },
+};
+
+/* HDTV */
+static struct ast_vbios_enhtable res_1920x1080[] = {
+ {2200, 1920, 88, 44, 1125, 1080, 4, 5, VCLK148_5, /* 60Hz */
+ (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode), 60, 1, 0x38 },
+ {2200, 1920, 88, 44, 1125, 1080, 4, 5, VCLK148_5, /* 60Hz */
+ (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode), 0xFF, 1, 0x38 },
+};
+#endif
diff --git a/drivers/gpu/drm/ast/ast_ttm.c b/drivers/gpu/drm/ast/ast_ttm.c
new file mode 100644
index 000000000000..6cf2adea66bc
--- /dev/null
+++ b/drivers/gpu/drm/ast/ast_ttm.c
@@ -0,0 +1,453 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors: Dave Airlie <airlied@redhat.com>
+ */
+#include "drmP.h"
+#include "ast_drv.h"
+#include <ttm/ttm_page_alloc.h>
+
+static inline struct ast_private *
+ast_bdev(struct ttm_bo_device *bd)
+{
+ return container_of(bd, struct ast_private, ttm.bdev);
+}
+
+static int
+ast_ttm_mem_global_init(struct drm_global_reference *ref)
+{
+ return ttm_mem_global_init(ref->object);
+}
+
+static void
+ast_ttm_mem_global_release(struct drm_global_reference *ref)
+{
+ ttm_mem_global_release(ref->object);
+}
+
+static int ast_ttm_global_init(struct ast_private *ast)
+{
+ struct drm_global_reference *global_ref;
+ int r;
+
+ global_ref = &ast->ttm.mem_global_ref;
+ global_ref->global_type = DRM_GLOBAL_TTM_MEM;
+ global_ref->size = sizeof(struct ttm_mem_global);
+ global_ref->init = &ast_ttm_mem_global_init;
+ global_ref->release = &ast_ttm_mem_global_release;
+ r = drm_global_item_ref(global_ref);
+ if (r != 0) {
+ DRM_ERROR("Failed setting up TTM memory accounting "
+ "subsystem.\n");
+ return r;
+ }
+
+ ast->ttm.bo_global_ref.mem_glob =
+ ast->ttm.mem_global_ref.object;
+ global_ref = &ast->ttm.bo_global_ref.ref;
+ global_ref->global_type = DRM_GLOBAL_TTM_BO;
+ global_ref->size = sizeof(struct ttm_bo_global);
+ global_ref->init = &ttm_bo_global_init;
+ global_ref->release = &ttm_bo_global_release;
+ r = drm_global_item_ref(global_ref);
+ if (r != 0) {
+ DRM_ERROR("Failed setting up TTM BO subsystem.\n");
+ drm_global_item_unref(&ast->ttm.mem_global_ref);
+ return r;
+ }
+ return 0;
+}
+
+void
+ast_ttm_global_release(struct ast_private *ast)
+{
+ if (ast->ttm.mem_global_ref.release == NULL)
+ return;
+
+ drm_global_item_unref(&ast->ttm.bo_global_ref.ref);
+ drm_global_item_unref(&ast->ttm.mem_global_ref);
+ ast->ttm.mem_global_ref.release = NULL;
+}
+
+
+static void ast_bo_ttm_destroy(struct ttm_buffer_object *tbo)
+{
+ struct ast_bo *bo;
+
+ bo = container_of(tbo, struct ast_bo, bo);
+
+ drm_gem_object_release(&bo->gem);
+ kfree(bo);
+}
+
+bool ast_ttm_bo_is_ast_bo(struct ttm_buffer_object *bo)
+{
+ if (bo->destroy == &ast_bo_ttm_destroy)
+ return true;
+ return false;
+}
+
+static int
+ast_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
+ struct ttm_mem_type_manager *man)
+{
+ switch (type) {
+ case TTM_PL_SYSTEM:
+ man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
+ man->available_caching = TTM_PL_MASK_CACHING;
+ man->default_caching = TTM_PL_FLAG_CACHED;
+ break;
+ case TTM_PL_VRAM:
+ man->func = &ttm_bo_manager_func;
+ man->flags = TTM_MEMTYPE_FLAG_FIXED |
+ TTM_MEMTYPE_FLAG_MAPPABLE;
+ man->available_caching = TTM_PL_FLAG_UNCACHED |
+ TTM_PL_FLAG_WC;
+ man->default_caching = TTM_PL_FLAG_WC;
+ break;
+ default:
+ DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void
+ast_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
+{
+ struct ast_bo *astbo = ast_bo(bo);
+
+ if (!ast_ttm_bo_is_ast_bo(bo))
+ return;
+
+ ast_ttm_placement(astbo, TTM_PL_FLAG_SYSTEM);
+ *pl = astbo->placement;
+}
+
+static int ast_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp)
+{
+ return 0;
+}
+
+static int ast_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
+ struct ttm_mem_reg *mem)
+{
+ struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
+ struct ast_private *ast = ast_bdev(bdev);
+
+ mem->bus.addr = NULL;
+ mem->bus.offset = 0;
+ mem->bus.size = mem->num_pages << PAGE_SHIFT;
+ mem->bus.base = 0;
+ mem->bus.is_iomem = false;
+ if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
+ return -EINVAL;
+ switch (mem->mem_type) {
+ case TTM_PL_SYSTEM:
+ /* system memory */
+ return 0;
+ case TTM_PL_VRAM:
+ mem->bus.offset = mem->start << PAGE_SHIFT;
+ mem->bus.base = pci_resource_start(ast->dev->pdev, 0);
+ mem->bus.is_iomem = true;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ return 0;
+}
+
+static void ast_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
+{
+}
+
+static int ast_bo_move(struct ttm_buffer_object *bo,
+ bool evict, bool interruptible,
+ bool no_wait_reserve, bool no_wait_gpu,
+ struct ttm_mem_reg *new_mem)
+{
+ int r;
+ r = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
+ return r;
+}
+
+
+static void ast_ttm_backend_destroy(struct ttm_tt *tt)
+{
+ ttm_tt_fini(tt);
+ kfree(tt);
+}
+
+static struct ttm_backend_func ast_tt_backend_func = {
+ .destroy = &ast_ttm_backend_destroy,
+};
+
+
+struct ttm_tt *ast_ttm_tt_create(struct ttm_bo_device *bdev,
+ unsigned long size, uint32_t page_flags,
+ struct page *dummy_read_page)
+{
+ struct ttm_tt *tt;
+
+ tt = kzalloc(sizeof(struct ttm_tt), GFP_KERNEL);
+ if (tt == NULL)
+ return NULL;
+ tt->func = &ast_tt_backend_func;
+ if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) {
+ kfree(tt);
+ return NULL;
+ }
+ return tt;
+}
+
+static int ast_ttm_tt_populate(struct ttm_tt *ttm)
+{
+ return ttm_pool_populate(ttm);
+}
+
+static void ast_ttm_tt_unpopulate(struct ttm_tt *ttm)
+{
+ ttm_pool_unpopulate(ttm);
+}
+
+struct ttm_bo_driver ast_bo_driver = {
+ .ttm_tt_create = ast_ttm_tt_create,
+ .ttm_tt_populate = ast_ttm_tt_populate,
+ .ttm_tt_unpopulate = ast_ttm_tt_unpopulate,
+ .init_mem_type = ast_bo_init_mem_type,
+ .evict_flags = ast_bo_evict_flags,
+ .move = ast_bo_move,
+ .verify_access = ast_bo_verify_access,
+ .io_mem_reserve = &ast_ttm_io_mem_reserve,
+ .io_mem_free = &ast_ttm_io_mem_free,
+};
+
+int ast_mm_init(struct ast_private *ast)
+{
+ int ret;
+ struct drm_device *dev = ast->dev;
+ struct ttm_bo_device *bdev = &ast->ttm.bdev;
+
+ ret = ast_ttm_global_init(ast);
+ if (ret)
+ return ret;
+
+ ret = ttm_bo_device_init(&ast->ttm.bdev,
+ ast->ttm.bo_global_ref.ref.object,
+ &ast_bo_driver, DRM_FILE_PAGE_OFFSET,
+ true);
+ if (ret) {
+ DRM_ERROR("Error initialising bo driver; %d\n", ret);
+ return ret;
+ }
+
+ ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
+ ast->vram_size >> PAGE_SHIFT);
+ if (ret) {
+ DRM_ERROR("Failed ttm VRAM init: %d\n", ret);
+ return ret;
+ }
+
+ ast->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 0),
+ pci_resource_len(dev->pdev, 0),
+ DRM_MTRR_WC);
+
+ return 0;
+}
+
+void ast_mm_fini(struct ast_private *ast)
+{
+ struct drm_device *dev = ast->dev;
+ ttm_bo_device_release(&ast->ttm.bdev);
+
+ ast_ttm_global_release(ast);
+
+ if (ast->fb_mtrr >= 0) {
+ drm_mtrr_del(ast->fb_mtrr,
+ pci_resource_start(dev->pdev, 0),
+ pci_resource_len(dev->pdev, 0), DRM_MTRR_WC);
+ ast->fb_mtrr = -1;
+ }
+}
+
+void ast_ttm_placement(struct ast_bo *bo, int domain)
+{
+ u32 c = 0;
+ bo->placement.fpfn = 0;
+ bo->placement.lpfn = 0;
+ bo->placement.placement = bo->placements;
+ bo->placement.busy_placement = bo->placements;
+ if (domain & TTM_PL_FLAG_VRAM)
+ bo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
+ if (domain & TTM_PL_FLAG_SYSTEM)
+ bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+ if (!c)
+ bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+ bo->placement.num_placement = c;
+ bo->placement.num_busy_placement = c;
+}
+
+int ast_bo_reserve(struct ast_bo *bo, bool no_wait)
+{
+ int ret;
+
+ ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0);
+ if (ret) {
+ if (ret != -ERESTARTSYS)
+ DRM_ERROR("reserve failed %p\n", bo);
+ return ret;
+ }
+ return 0;
+}
+
+void ast_bo_unreserve(struct ast_bo *bo)
+{
+ ttm_bo_unreserve(&bo->bo);
+}
+
+int ast_bo_create(struct drm_device *dev, int size, int align,
+ uint32_t flags, struct ast_bo **pastbo)
+{
+ struct ast_private *ast = dev->dev_private;
+ struct ast_bo *astbo;
+ size_t acc_size;
+ int ret;
+
+ astbo = kzalloc(sizeof(struct ast_bo), GFP_KERNEL);
+ if (!astbo)
+ return -ENOMEM;
+
+ ret = drm_gem_object_init(dev, &astbo->gem, size);
+ if (ret) {
+ kfree(astbo);
+ return ret;
+ }
+
+ astbo->gem.driver_private = NULL;
+ astbo->bo.bdev = &ast->ttm.bdev;
+
+ ast_ttm_placement(astbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
+
+ acc_size = ttm_bo_dma_acc_size(&ast->ttm.bdev, size,
+ sizeof(struct ast_bo));
+
+ ret = ttm_bo_init(&ast->ttm.bdev, &astbo->bo, size,
+ ttm_bo_type_device, &astbo->placement,
+ align >> PAGE_SHIFT, 0, false, NULL, acc_size,
+ NULL, ast_bo_ttm_destroy);
+ if (ret)
+ return ret;
+
+ *pastbo = astbo;
+ return 0;
+}
+
+static inline u64 ast_bo_gpu_offset(struct ast_bo *bo)
+{
+ return bo->bo.offset;
+}
+
+int ast_bo_pin(struct ast_bo *bo, u32 pl_flag, u64 *gpu_addr)
+{
+ int i, ret;
+
+ if (bo->pin_count) {
+ bo->pin_count++;
+ if (gpu_addr)
+ *gpu_addr = ast_bo_gpu_offset(bo);
+ }
+
+ ast_ttm_placement(bo, pl_flag);
+ for (i = 0; i < bo->placement.num_placement; i++)
+ bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
+ ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false);
+ if (ret)
+ return ret;
+
+ bo->pin_count = 1;
+ if (gpu_addr)
+ *gpu_addr = ast_bo_gpu_offset(bo);
+ return 0;
+}
+
+int ast_bo_unpin(struct ast_bo *bo)
+{
+ int i, ret;
+ if (!bo->pin_count) {
+ DRM_ERROR("unpin bad %p\n", bo);
+ return 0;
+ }
+ bo->pin_count--;
+ if (bo->pin_count)
+ return 0;
+
+ for (i = 0; i < bo->placement.num_placement ; i++)
+ bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT;
+ ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int ast_bo_push_sysram(struct ast_bo *bo)
+{
+ int i, ret;
+ if (!bo->pin_count) {
+ DRM_ERROR("unpin bad %p\n", bo);
+ return 0;
+ }
+ bo->pin_count--;
+ if (bo->pin_count)
+ return 0;
+
+ if (bo->kmap.virtual)
+ ttm_bo_kunmap(&bo->kmap);
+
+ ast_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
+ for (i = 0; i < bo->placement.num_placement ; i++)
+ bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
+
+ ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false);
+ if (ret) {
+ DRM_ERROR("pushing to VRAM failed\n");
+ return ret;
+ }
+ return 0;
+}
+
+int ast_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct drm_file *file_priv;
+ struct ast_private *ast;
+
+ if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
+ return drm_mmap(filp, vma);
+
+ file_priv = filp->private_data;
+ ast = file_priv->minor->dev->dev_private;
+ return ttm_bo_mmap(filp, vma, &ast->ttm.bdev);
+}
diff --git a/drivers/gpu/drm/cirrus/Kconfig b/drivers/gpu/drm/cirrus/Kconfig
new file mode 100644
index 000000000000..fc154dd75296
--- /dev/null
+++ b/drivers/gpu/drm/cirrus/Kconfig
@@ -0,0 +1,12 @@
+config DRM_CIRRUS_QEMU
+ tristate "Cirrus driver for QEMU emulated device"
+ depends on DRM && PCI && EXPERIMENTAL
+ select FB_SYS_FILLRECT
+ select FB_SYS_COPYAREA
+ select FB_SYS_IMAGEBLIT
+ select DRM_KMS_HELPER
+ select DRM_TTM
+ help
+ This is a KMS driver for emulated cirrus device in qemu.
+ It is *NOT* intended for real cirrus devices. This requires
+ the modesetting userspace X.org driver.
diff --git a/drivers/gpu/drm/cirrus/Makefile b/drivers/gpu/drm/cirrus/Makefile
new file mode 100644
index 000000000000..69ffe7006d55
--- /dev/null
+++ b/drivers/gpu/drm/cirrus/Makefile
@@ -0,0 +1,5 @@
+ccflags-y := -Iinclude/drm
+cirrus-y := cirrus_main.o cirrus_mode.o \
+ cirrus_drv.o cirrus_fbdev.o cirrus_ttm.o
+
+obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus.o
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c b/drivers/gpu/drm/cirrus/cirrus_drv.c
new file mode 100644
index 000000000000..d7038230b71e
--- /dev/null
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2012 Red Hat <mjg@redhat.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * Authors: Matthew Garrett
+ * Dave Airlie
+ */
+#include <linux/module.h>
+#include <linux/console.h>
+#include "drmP.h"
+#include "drm.h"
+
+#include "cirrus_drv.h"
+
+int cirrus_modeset = -1;
+
+MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
+module_param_named(modeset, cirrus_modeset, int, 0400);
+
+/*
+ * This is the generic driver code. This binds the driver to the drm core,
+ * which then performs further device association and calls our graphics init
+ * functions
+ */
+
+static struct drm_driver driver;
+
+/* only bind to the cirrus chip in qemu */
+static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
+ { PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_5446, 0x1af4, 0x1100, 0,
+ 0, 0 },
+ {0,}
+};
+
+static int __devinit
+cirrus_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ return drm_get_pci_dev(pdev, ent, &driver);
+}
+
+static void cirrus_pci_remove(struct pci_dev *pdev)
+{
+ struct drm_device *dev = pci_get_drvdata(pdev);
+
+ drm_put_dev(dev);
+}
+
+static const struct file_operations cirrus_driver_fops = {
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .unlocked_ioctl = drm_ioctl,
+ .mmap = cirrus_mmap,
+ .poll = drm_poll,
+ .fasync = drm_fasync,
+};
+static struct drm_driver driver = {
+ .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_USE_MTRR,
+ .load = cirrus_driver_load,
+ .unload = cirrus_driver_unload,
+ .fops = &cirrus_driver_fops,
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+ .date = DRIVER_DATE,
+ .major = DRIVER_MAJOR,
+ .minor = DRIVER_MINOR,
+ .patchlevel = DRIVER_PATCHLEVEL,
+ .gem_init_object = cirrus_gem_init_object,
+ .gem_free_object = cirrus_gem_free_object,
+ .dumb_create = cirrus_dumb_create,
+ .dumb_map_offset = cirrus_dumb_mmap_offset,
+ .dumb_destroy = cirrus_dumb_destroy,
+};
+
+static struct pci_driver cirrus_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = pciidlist,
+ .probe = cirrus_pci_probe,
+ .remove = cirrus_pci_remove,
+};
+
+static int __init cirrus_init(void)
+{
+#ifdef CONFIG_VGA_CONSOLE
+ if (vgacon_text_force() && cirrus_modeset == -1)
+ return -EINVAL;
+#endif
+
+ if (cirrus_modeset == 0)
+ return -EINVAL;
+ return drm_pci_init(&driver, &cirrus_pci_driver);
+}
+
+static void __exit cirrus_exit(void)
+{
+ drm_pci_exit(&driver, &cirrus_pci_driver);
+}
+
+module_init(cirrus_init);
+module_exit(cirrus_exit);
+
+MODULE_DEVICE_TABLE(pci, pciidlist);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h
new file mode 100644
index 000000000000..21bdfa8836f7
--- /dev/null
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.h
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2012 Red Hat
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * Authors: Matthew Garrett
+ * Dave Airlie
+ */
+#ifndef __CIRRUS_DRV_H__
+#define __CIRRUS_DRV_H__
+
+#include <video/vga.h>
+
+#include <drm/drm_fb_helper.h>
+
+#include "ttm/ttm_bo_api.h"
+#include "ttm/ttm_bo_driver.h"
+#include "ttm/ttm_placement.h"
+#include "ttm/ttm_memory.h"
+#include "ttm/ttm_module.h"
+
+#define DRIVER_AUTHOR "Matthew Garrett"
+
+#define DRIVER_NAME "cirrus"
+#define DRIVER_DESC "qemu Cirrus emulation"
+#define DRIVER_DATE "20110418"
+
+#define DRIVER_MAJOR 1
+#define DRIVER_MINOR 0
+#define DRIVER_PATCHLEVEL 0
+
+#define CIRRUSFB_CONN_LIMIT 1
+
+#define RREG8(reg) ioread8(((void __iomem *)cdev->rmmio) + (reg))
+#define WREG8(reg, v) iowrite8(v, ((void __iomem *)cdev->rmmio) + (reg))
+#define RREG32(reg) ioread32(((void __iomem *)cdev->rmmio) + (reg))
+#define WREG32(reg, v) iowrite32(v, ((void __iomem *)cdev->rmmio) + (reg))
+
+#define SEQ_INDEX 4
+#define SEQ_DATA 5
+
+#define WREG_SEQ(reg, v) \
+ do { \
+ WREG8(SEQ_INDEX, reg); \
+ WREG8(SEQ_DATA, v); \
+ } while (0) \
+
+#define CRT_INDEX 0x14
+#define CRT_DATA 0x15
+
+#define WREG_CRT(reg, v) \
+ do { \
+ WREG8(CRT_INDEX, reg); \
+ WREG8(CRT_DATA, v); \
+ } while (0) \
+
+#define GFX_INDEX 0xe
+#define GFX_DATA 0xf
+
+#define WREG_GFX(reg, v) \
+ do { \
+ WREG8(GFX_INDEX, reg); \
+ WREG8(GFX_DATA, v); \
+ } while (0) \
+
+/*
+ * Cirrus has a "hidden" DAC register that can be accessed by writing to
+ * the pixel mask register to reset the state, then reading from the register
+ * four times. The next write will then pass to the DAC
+ */
+#define VGA_DAC_MASK 0x6
+
+#define WREG_HDR(v) \
+ do { \
+ RREG8(VGA_DAC_MASK); \
+ RREG8(VGA_DAC_MASK); \
+ RREG8(VGA_DAC_MASK); \
+ RREG8(VGA_DAC_MASK); \
+ WREG8(VGA_DAC_MASK, v); \
+ } while (0) \
+
+
+#define CIRRUS_MAX_FB_HEIGHT 4096
+#define CIRRUS_MAX_FB_WIDTH 4096
+
+#define CIRRUS_DPMS_CLEARED (-1)
+
+#define to_cirrus_crtc(x) container_of(x, struct cirrus_crtc, base)
+#define to_cirrus_encoder(x) container_of(x, struct cirrus_encoder, base)
+#define to_cirrus_framebuffer(x) container_of(x, struct cirrus_framebuffer, base)
+
+struct cirrus_crtc {
+ struct drm_crtc base;
+ u8 lut_r[256], lut_g[256], lut_b[256];
+ int last_dpms;
+ bool enabled;
+};
+
+struct cirrus_fbdev;
+struct cirrus_mode_info {
+ bool mode_config_initialized;
+ struct cirrus_crtc *crtc;
+ /* pointer to fbdev info structure */
+ struct cirrus_fbdev *gfbdev;
+};
+
+struct cirrus_encoder {
+ struct drm_encoder base;
+ int last_dpms;
+};
+
+struct cirrus_connector {
+ struct drm_connector base;
+};
+
+struct cirrus_framebuffer {
+ struct drm_framebuffer base;
+ struct drm_gem_object *obj;
+};
+
+struct cirrus_mc {
+ resource_size_t vram_size;
+ resource_size_t vram_base;
+};
+
+struct cirrus_device {
+ struct drm_device *dev;
+ unsigned long flags;
+
+ resource_size_t rmmio_base;
+ resource_size_t rmmio_size;
+ void __iomem *rmmio;
+
+ struct cirrus_mc mc;
+ struct cirrus_mode_info mode_info;
+
+ int num_crtc;
+ int fb_mtrr;
+
+ struct {
+ struct drm_global_reference mem_global_ref;
+ struct ttm_bo_global_ref bo_global_ref;
+ struct ttm_bo_device bdev;
+ atomic_t validate_sequence;
+ } ttm;
+
+};
+
+
+struct cirrus_fbdev {
+ struct drm_fb_helper helper;
+ struct cirrus_framebuffer gfb;
+ struct list_head fbdev_list;
+ void *sysram;
+ int size;
+};
+
+struct cirrus_bo {
+ struct ttm_buffer_object bo;
+ struct ttm_placement placement;
+ struct ttm_bo_kmap_obj kmap;
+ struct drm_gem_object gem;
+ u32 placements[3];
+ int pin_count;
+};
+#define gem_to_cirrus_bo(gobj) container_of((gobj), struct cirrus_bo, gem)
+
+static inline struct cirrus_bo *
+cirrus_bo(struct ttm_buffer_object *bo)
+{
+ return container_of(bo, struct cirrus_bo, bo);
+}
+
+
+#define to_cirrus_obj(x) container_of(x, struct cirrus_gem_object, base)
+#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
+
+ /* cirrus_mode.c */
+void cirrus_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
+ u16 blue, int regno);
+void cirrus_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
+ u16 *blue, int regno);
+
+
+ /* cirrus_main.c */
+int cirrus_device_init(struct cirrus_device *cdev,
+ struct drm_device *ddev,
+ struct pci_dev *pdev,
+ uint32_t flags);
+void cirrus_device_fini(struct cirrus_device *cdev);
+int cirrus_gem_init_object(struct drm_gem_object *obj);
+void cirrus_gem_free_object(struct drm_gem_object *obj);
+int cirrus_dumb_mmap_offset(struct drm_file *file,
+ struct drm_device *dev,
+ uint32_t handle,
+ uint64_t *offset);
+int cirrus_gem_create(struct drm_device *dev,
+ u32 size, bool iskernel,
+ struct drm_gem_object **obj);
+int cirrus_dumb_create(struct drm_file *file,
+ struct drm_device *dev,
+ struct drm_mode_create_dumb *args);
+int cirrus_dumb_destroy(struct drm_file *file,
+ struct drm_device *dev,
+ uint32_t handle);
+
+int cirrus_framebuffer_init(struct drm_device *dev,
+ struct cirrus_framebuffer *gfb,
+ struct drm_mode_fb_cmd2 *mode_cmd,
+ struct drm_gem_object *obj);
+
+ /* cirrus_display.c */
+int cirrus_modeset_init(struct cirrus_device *cdev);
+void cirrus_modeset_fini(struct cirrus_device *cdev);
+
+ /* cirrus_fbdev.c */
+int cirrus_fbdev_init(struct cirrus_device *cdev);
+void cirrus_fbdev_fini(struct cirrus_device *cdev);
+
+
+
+ /* cirrus_irq.c */
+void cirrus_driver_irq_preinstall(struct drm_device *dev);
+int cirrus_driver_irq_postinstall(struct drm_device *dev);
+void cirrus_driver_irq_uninstall(struct drm_device *dev);
+irqreturn_t cirrus_driver_irq_handler(DRM_IRQ_ARGS);
+
+ /* cirrus_kms.c */
+int cirrus_driver_load(struct drm_device *dev, unsigned long flags);
+int cirrus_driver_unload(struct drm_device *dev);
+extern struct drm_ioctl_desc cirrus_ioctls[];
+extern int cirrus_max_ioctl;
+
+int cirrus_mm_init(struct cirrus_device *cirrus);
+void cirrus_mm_fini(struct cirrus_device *cirrus);
+void cirrus_ttm_placement(struct cirrus_bo *bo, int domain);
+int cirrus_bo_create(struct drm_device *dev, int size, int align,
+ uint32_t flags, struct cirrus_bo **pcirrusbo);
+int cirrus_mmap(struct file *filp, struct vm_area_struct *vma);
+int cirrus_bo_reserve(struct cirrus_bo *bo, bool no_wait);
+void cirrus_bo_unreserve(struct cirrus_bo *bo);
+int cirrus_bo_push_sysram(struct cirrus_bo *bo);
+int cirrus_bo_pin(struct cirrus_bo *bo, u32 pl_flag, u64 *gpu_addr);
+#endif /* __CIRRUS_DRV_H__ */
diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
new file mode 100644
index 000000000000..9a276a536992
--- /dev/null
+++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
@@ -0,0 +1,307 @@
+/*
+ * Copyright 2012 Red Hat
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * Authors: Matthew Garrett
+ * Dave Airlie
+ */
+#include <linux/module.h>
+#include "drmP.h"
+#include "drm.h"
+#include "drm_fb_helper.h"
+
+#include <linux/fb.h>
+
+#include "cirrus_drv.h"
+
+static void cirrus_dirty_update(struct cirrus_fbdev *afbdev,
+ int x, int y, int width, int height)
+{
+ int i;
+ struct drm_gem_object *obj;
+ struct cirrus_bo *bo;
+ int src_offset, dst_offset;
+ int bpp = (afbdev->gfb.base.bits_per_pixel + 7)/8;
+ int ret;
+ bool unmap = false;
+
+ obj = afbdev->gfb.obj;
+ bo = gem_to_cirrus_bo(obj);
+
+ ret = cirrus_bo_reserve(bo, true);
+ if (ret) {
+ DRM_ERROR("failed to reserve fb bo\n");
+ return;
+ }
+
+ if (!bo->kmap.virtual) {
+ ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
+ if (ret) {
+ DRM_ERROR("failed to kmap fb updates\n");
+ cirrus_bo_unreserve(bo);
+ return;
+ }
+ unmap = true;
+ }
+ for (i = y; i < y + height; i++) {
+ /* assume equal stride for now */
+ src_offset = dst_offset = i * afbdev->gfb.base.pitches[0] + (x * bpp);
+ memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, width * bpp);
+
+ }
+ if (unmap)
+ ttm_bo_kunmap(&bo->kmap);
+
+ cirrus_bo_unreserve(bo);
+}
+
+static void cirrus_fillrect(struct fb_info *info,
+ const struct fb_fillrect *rect)
+{
+ struct cirrus_fbdev *afbdev = info->par;
+ sys_fillrect(info, rect);
+ cirrus_dirty_update(afbdev, rect->dx, rect->dy, rect->width,
+ rect->height);
+}
+
+static void cirrus_copyarea(struct fb_info *info,
+ const struct fb_copyarea *area)
+{
+ struct cirrus_fbdev *afbdev = info->par;
+ sys_copyarea(info, area);
+ cirrus_dirty_update(afbdev, area->dx, area->dy, area->width,
+ area->height);
+}
+
+static void cirrus_imageblit(struct fb_info *info,
+ const struct fb_image *image)
+{
+ struct cirrus_fbdev *afbdev = info->par;
+ sys_imageblit(info, image);
+ cirrus_dirty_update(afbdev, image->dx, image->dy, image->width,
+ image->height);
+}
+
+
+static struct fb_ops cirrusfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = drm_fb_helper_check_var,
+ .fb_set_par = drm_fb_helper_set_par,
+ .fb_fillrect = cirrus_fillrect,
+ .fb_copyarea = cirrus_copyarea,
+ .fb_imageblit = cirrus_imageblit,
+ .fb_pan_display = drm_fb_helper_pan_display,
+ .fb_blank = drm_fb_helper_blank,
+ .fb_setcmap = drm_fb_helper_setcmap,
+};
+
+static int cirrusfb_create_object(struct cirrus_fbdev *afbdev,
+ struct drm_mode_fb_cmd2 *mode_cmd,
+ struct drm_gem_object **gobj_p)
+{
+ struct drm_device *dev = afbdev->helper.dev;
+ u32 bpp, depth;
+ u32 size;
+ struct drm_gem_object *gobj;
+
+ int ret = 0;
+ drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp);
+
+ if (bpp > 24)
+ return -EINVAL;
+ size = mode_cmd->pitches[0] * mode_cmd->height;
+ ret = cirrus_gem_create(dev, size, true, &gobj);
+ if (ret)
+ return ret;
+
+ *gobj_p = gobj;
+ return ret;
+}
+
+static int cirrusfb_create(struct cirrus_fbdev *gfbdev,
+ struct drm_fb_helper_surface_size *sizes)
+{
+ struct drm_device *dev = gfbdev->helper.dev;
+ struct cirrus_device *cdev = gfbdev->helper.dev->dev_private;
+ struct fb_info *info;
+ struct drm_framebuffer *fb;
+ struct drm_mode_fb_cmd2 mode_cmd;
+ struct device *device = &dev->pdev->dev;
+ void *sysram;
+ struct drm_gem_object *gobj = NULL;
+ struct cirrus_bo *bo = NULL;
+ int size, ret;
+
+ mode_cmd.width = sizes->surface_width;
+ mode_cmd.height = sizes->surface_height;
+ mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7) / 8);
+ mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+ sizes->surface_depth);
+ size = mode_cmd.pitches[0] * mode_cmd.height;
+
+ ret = cirrusfb_create_object(gfbdev, &mode_cmd, &gobj);
+ if (ret) {
+ DRM_ERROR("failed to create fbcon backing object %d\n", ret);
+ return ret;
+ }
+
+ bo = gem_to_cirrus_bo(gobj);
+
+ sysram = vmalloc(size);
+ if (!sysram)
+ return -ENOMEM;
+
+ info = framebuffer_alloc(0, device);
+ if (info == NULL)
+ return -ENOMEM;
+
+ info->par = gfbdev;
+
+ ret = cirrus_framebuffer_init(cdev->dev, &gfbdev->gfb, &mode_cmd, gobj);
+ if (ret)
+ return ret;
+
+ gfbdev->sysram = sysram;
+ gfbdev->size = size;
+
+ fb = &gfbdev->gfb.base;
+ if (!fb) {
+ DRM_INFO("fb is NULL\n");
+ return -EINVAL;
+ }
+
+ /* setup helper */
+ gfbdev->helper.fb = fb;
+ gfbdev->helper.fbdev = info;
+
+ strcpy(info->fix.id, "cirrusdrmfb");
+
+
+ info->flags = FBINFO_DEFAULT;
+ info->fbops = &cirrusfb_ops;
+
+ drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
+ drm_fb_helper_fill_var(info, &gfbdev->helper, sizes->fb_width,
+ sizes->fb_height);
+
+ /* setup aperture base/size for vesafb takeover */
+ info->apertures = alloc_apertures(1);
+ if (!info->apertures) {
+ ret = -ENOMEM;
+ goto out_iounmap;
+ }
+ info->apertures->ranges[0].base = cdev->dev->mode_config.fb_base;
+ info->apertures->ranges[0].size = cdev->mc.vram_size;
+
+ info->screen_base = sysram;
+ info->screen_size = size;
+
+ info->fix.mmio_start = 0;
+ info->fix.mmio_len = 0;
+
+ ret = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (ret) {
+ DRM_ERROR("%s: can't allocate color map\n", info->fix.id);
+ ret = -ENOMEM;
+ goto out_iounmap;
+ }
+
+ DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start);
+ DRM_INFO("vram aper at 0x%lX\n", (unsigned long)info->fix.smem_start);
+ DRM_INFO("size %lu\n", (unsigned long)info->fix.smem_len);
+ DRM_INFO("fb depth is %d\n", fb->depth);
+ DRM_INFO(" pitch is %d\n", fb->pitches[0]);
+
+ return 0;
+out_iounmap:
+ return ret;
+}
+
+static int cirrus_fb_find_or_create_single(struct drm_fb_helper *helper,
+ struct drm_fb_helper_surface_size
+ *sizes)
+{
+ struct cirrus_fbdev *gfbdev = (struct cirrus_fbdev *)helper;
+ int new_fb = 0;
+ int ret;
+
+ if (!helper->fb) {
+ ret = cirrusfb_create(gfbdev, sizes);
+ if (ret)
+ return ret;
+ new_fb = 1;
+ }
+ return new_fb;
+}
+
+static int cirrus_fbdev_destroy(struct drm_device *dev,
+ struct cirrus_fbdev *gfbdev)
+{
+ struct fb_info *info;
+ struct cirrus_framebuffer *gfb = &gfbdev->gfb;
+
+ if (gfbdev->helper.fbdev) {
+ info = gfbdev->helper.fbdev;
+
+ unregister_framebuffer(info);
+ if (info->cmap.len)
+ fb_dealloc_cmap(&info->cmap);
+ framebuffer_release(info);
+ }
+
+ if (gfb->obj) {
+ drm_gem_object_unreference_unlocked(gfb->obj);
+ gfb->obj = NULL;
+ }
+
+ vfree(gfbdev->sysram);
+ drm_fb_helper_fini(&gfbdev->helper);
+ drm_framebuffer_cleanup(&gfb->base);
+
+ return 0;
+}
+
+static struct drm_fb_helper_funcs cirrus_fb_helper_funcs = {
+ .gamma_set = cirrus_crtc_fb_gamma_set,
+ .gamma_get = cirrus_crtc_fb_gamma_get,
+ .fb_probe = cirrus_fb_find_or_create_single,
+};
+
+int cirrus_fbdev_init(struct cirrus_device *cdev)
+{
+ struct cirrus_fbdev *gfbdev;
+ int ret;
+ int bpp_sel = 24;
+
+ /*bpp_sel = 8;*/
+ gfbdev = kzalloc(sizeof(struct cirrus_fbdev), GFP_KERNEL);
+ if (!gfbdev)
+ return -ENOMEM;
+
+ cdev->mode_info.gfbdev = gfbdev;
+ gfbdev->helper.funcs = &cirrus_fb_helper_funcs;
+
+ ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper,
+ cdev->num_crtc, CIRRUSFB_CONN_LIMIT);
+ if (ret) {
+ kfree(gfbdev);
+ return ret;
+ }
+ drm_fb_helper_single_add_all_connectors(&gfbdev->helper);
+ drm_fb_helper_initial_config(&gfbdev->helper, bpp_sel);
+
+ return 0;
+}
+
+void cirrus_fbdev_fini(struct cirrus_device *cdev)
+{
+ if (!cdev->mode_info.gfbdev)
+ return;
+
+ cirrus_fbdev_destroy(cdev->dev, cdev->mode_info.gfbdev);
+ kfree(cdev->mode_info.gfbdev);
+ cdev->mode_info.gfbdev = NULL;
+}
diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c
new file mode 100644
index 000000000000..e3c122578417
--- /dev/null
+++ b/drivers/gpu/drm/cirrus/cirrus_main.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright 2012 Red Hat
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * Authors: Matthew Garrett
+ * Dave Airlie
+ */
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc_helper.h"
+
+#include "cirrus_drv.h"
+
+
+static void cirrus_user_framebuffer_destroy(struct drm_framebuffer *fb)
+{
+ struct cirrus_framebuffer *cirrus_fb = to_cirrus_framebuffer(fb);
+ if (cirrus_fb->obj)
+ drm_gem_object_unreference_unlocked(cirrus_fb->obj);
+ drm_framebuffer_cleanup(fb);
+ kfree(fb);
+}
+
+static int cirrus_user_framebuffer_create_handle(struct drm_framebuffer *fb,
+ struct drm_file *file_priv,
+ unsigned int *handle)
+{
+ return 0;
+}
+
+static const struct drm_framebuffer_funcs cirrus_fb_funcs = {
+ .destroy = cirrus_user_framebuffer_destroy,
+ .create_handle = cirrus_user_framebuffer_create_handle,
+};
+
+int cirrus_framebuffer_init(struct drm_device *dev,
+ struct cirrus_framebuffer *gfb,
+ struct drm_mode_fb_cmd2 *mode_cmd,
+ struct drm_gem_object *obj)
+{
+ int ret;
+
+ ret = drm_framebuffer_init(dev, &gfb->base, &cirrus_fb_funcs);
+ if (ret) {
+ DRM_ERROR("drm_framebuffer_init failed: %d\n", ret);
+ return ret;
+ }
+ drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd);
+ gfb->obj = obj;
+ return 0;
+}
+
+static struct drm_framebuffer *
+cirrus_user_framebuffer_create(struct drm_device *dev,
+ struct drm_file *filp,
+ struct drm_mode_fb_cmd2 *mode_cmd)
+{
+ struct drm_gem_object *obj;
+ struct cirrus_framebuffer *cirrus_fb;
+ int ret;
+ u32 bpp, depth;
+
+ drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp);
+ /* cirrus can't handle > 24bpp framebuffers at all */
+ if (bpp > 24)
+ return ERR_PTR(-EINVAL);
+
+ obj = drm_gem_object_lookup(dev, filp, mode_cmd->handles[0]);
+ if (obj == NULL)
+ return ERR_PTR(-ENOENT);
+
+ cirrus_fb = kzalloc(sizeof(*cirrus_fb), GFP_KERNEL);
+ if (!cirrus_fb) {
+ drm_gem_object_unreference_unlocked(obj);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ ret = cirrus_framebuffer_init(dev, cirrus_fb, mode_cmd, obj);
+ if (ret) {
+ drm_gem_object_unreference_unlocked(obj);
+ kfree(cirrus_fb);
+ return ERR_PTR(ret);
+ }
+ return &cirrus_fb->base;
+}
+
+static const struct drm_mode_config_funcs cirrus_mode_funcs = {
+ .fb_create = cirrus_user_framebuffer_create,
+};
+
+/* Unmap the framebuffer from the core and release the memory */
+static void cirrus_vram_fini(struct cirrus_device *cdev)
+{
+ iounmap(cdev->rmmio);
+ cdev->rmmio = NULL;
+ if (cdev->mc.vram_base)
+ release_mem_region(cdev->mc.vram_base, cdev->mc.vram_size);
+}
+
+/* Map the framebuffer from the card and configure the core */
+static int cirrus_vram_init(struct cirrus_device *cdev)
+{
+ /* BAR 0 is VRAM */
+ cdev->mc.vram_base = pci_resource_start(cdev->dev->pdev, 0);
+ /* We have 4MB of VRAM */
+ cdev->mc.vram_size = 4 * 1024 * 1024;
+
+ if (!request_mem_region(cdev->mc.vram_base, cdev->mc.vram_size,
+ "cirrusdrmfb_vram")) {
+ DRM_ERROR("can't reserve VRAM\n");
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+/*
+ * Our emulated hardware has two sets of memory. One is video RAM and can
+ * simply be used as a linear framebuffer - the other provides mmio access
+ * to the display registers. The latter can also be accessed via IO port
+ * access, but we map the range and use mmio to program them instead
+ */
+
+int cirrus_device_init(struct cirrus_device *cdev,
+ struct drm_device *ddev,
+ struct pci_dev *pdev, uint32_t flags)
+{
+ int ret;
+
+ cdev->dev = ddev;
+ cdev->flags = flags;
+
+ /* Hardcode the number of CRTCs to 1 */
+ cdev->num_crtc = 1;
+
+ /* BAR 0 is the framebuffer, BAR 1 contains registers */
+ cdev->rmmio_base = pci_resource_start(cdev->dev->pdev, 1);
+ cdev->rmmio_size = pci_resource_len(cdev->dev->pdev, 1);
+
+ if (!request_mem_region(cdev->rmmio_base, cdev->rmmio_size,
+ "cirrusdrmfb_mmio")) {
+ DRM_ERROR("can't reserve mmio registers\n");
+ return -ENOMEM;
+ }
+
+ cdev->rmmio = ioremap(cdev->rmmio_base, cdev->rmmio_size);
+
+ if (cdev->rmmio == NULL)
+ return -ENOMEM;
+
+ ret = cirrus_vram_init(cdev);
+ if (ret) {
+ release_mem_region(cdev->rmmio_base, cdev->rmmio_size);
+ return ret;
+ }
+
+ return 0;
+}
+
+void cirrus_device_fini(struct cirrus_device *cdev)
+{
+ release_mem_region(cdev->rmmio_base, cdev->rmmio_size);
+ cirrus_vram_fini(cdev);
+}
+
+/*
+ * Functions here will be called by the core once it's bound the driver to
+ * a PCI device
+ */
+
+int cirrus_driver_load(struct drm_device *dev, unsigned long flags)
+{
+ struct cirrus_device *cdev;
+ int r;
+
+ cdev = kzalloc(sizeof(struct cirrus_device), GFP_KERNEL);
+ if (cdev == NULL)
+ return -ENOMEM;
+ dev->dev_private = (void *)cdev;
+
+ r = cirrus_device_init(cdev, dev, dev->pdev, flags);
+ if (r) {
+ dev_err(&dev->pdev->dev, "Fatal error during GPU init: %d\n", r);
+ goto out;
+ }
+
+ r = cirrus_mm_init(cdev);
+ if (r)
+ dev_err(&dev->pdev->dev, "fatal err on mm init\n");
+
+ r = cirrus_modeset_init(cdev);
+ if (r)
+ dev_err(&dev->pdev->dev, "Fatal error during modeset init: %d\n", r);
+
+ dev->mode_config.funcs = (void *)&cirrus_mode_funcs;
+out:
+ if (r)
+ cirrus_driver_unload(dev);
+ return r;
+}
+
+int cirrus_driver_unload(struct drm_device *dev)
+{
+ struct cirrus_device *cdev = dev->dev_private;
+
+ if (cdev == NULL)
+ return 0;
+ cirrus_modeset_fini(cdev);
+ cirrus_mm_fini(cdev);
+ cirrus_device_fini(cdev);
+ kfree(cdev);
+ dev->dev_private = NULL;
+ return 0;
+}
+
+int cirrus_gem_create(struct drm_device *dev,
+ u32 size, bool iskernel,
+ struct drm_gem_object **obj)
+{
+ struct cirrus_bo *cirrusbo;
+ int ret;
+
+ *obj = NULL;
+
+ size = roundup(size, PAGE_SIZE);
+ if (size == 0)
+ return -EINVAL;
+
+ ret = cirrus_bo_create(dev, size, 0, 0, &cirrusbo);
+ if (ret) {
+ if (ret != -ERESTARTSYS)
+ DRM_ERROR("failed to allocate GEM object\n");
+ return ret;
+ }
+ *obj = &cirrusbo->gem;
+ return 0;
+}
+
+int cirrus_dumb_create(struct drm_file *file,
+ struct drm_device *dev,
+ struct drm_mode_create_dumb *args)
+{
+ int ret;
+ struct drm_gem_object *gobj;
+ u32 handle;
+
+ args->pitch = args->width * ((args->bpp + 7) / 8);
+ args->size = args->pitch * args->height;
+
+ ret = cirrus_gem_create(dev, args->size, false,
+ &gobj);
+ if (ret)
+ return ret;
+
+ ret = drm_gem_handle_create(file, gobj, &handle);
+ drm_gem_object_unreference_unlocked(gobj);
+ if (ret)
+ return ret;
+
+ args->handle = handle;
+ return 0;
+}
+
+int cirrus_dumb_destroy(struct drm_file *file,
+ struct drm_device *dev,
+ uint32_t handle)
+{
+ return drm_gem_handle_delete(file, handle);
+}
+
+int cirrus_gem_init_object(struct drm_gem_object *obj)
+{
+ BUG();
+ return 0;
+}
+
+void cirrus_bo_unref(struct cirrus_bo **bo)
+{
+ struct ttm_buffer_object *tbo;
+
+ if ((*bo) == NULL)
+ return;
+
+ tbo = &((*bo)->bo);
+ ttm_bo_unref(&tbo);
+ if (tbo == NULL)
+ *bo = NULL;
+
+}
+
+void cirrus_gem_free_object(struct drm_gem_object *obj)
+{
+ struct cirrus_bo *cirrus_bo = gem_to_cirrus_bo(obj);
+
+ if (!cirrus_bo)
+ return;
+ cirrus_bo_unref(&cirrus_bo);
+}
+
+
+static inline u64 cirrus_bo_mmap_offset(struct cirrus_bo *bo)
+{
+ return bo->bo.addr_space_offset;
+}
+
+int
+cirrus_dumb_mmap_offset(struct drm_file *file,
+ struct drm_device *dev,
+ uint32_t handle,
+ uint64_t *offset)
+{
+ struct drm_gem_object *obj;
+ int ret;
+ struct cirrus_bo *bo;
+
+ mutex_lock(&dev->struct_mutex);
+ obj = drm_gem_object_lookup(dev, file, handle);
+ if (obj == NULL) {
+ ret = -ENOENT;
+ goto out_unlock;
+ }
+
+ bo = gem_to_cirrus_bo(obj);
+ *offset = cirrus_bo_mmap_offset(bo);
+
+ drm_gem_object_unreference(obj);
+ ret = 0;
+out_unlock:
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+
+}
diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c
new file mode 100644
index 000000000000..100f6308c509
--- /dev/null
+++ b/drivers/gpu/drm/cirrus/cirrus_mode.c
@@ -0,0 +1,629 @@
+
+/*
+ * Copyright 2012 Red Hat
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * Authors: Matthew Garrett
+ * Dave Airlie
+ *
+ * Portions of this code derived from cirrusfb.c:
+ * drivers/video/cirrusfb.c - driver for Cirrus Logic chipsets
+ *
+ * Copyright 1999-2001 Jeff Garzik <jgarzik@pobox.com>
+ */
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc_helper.h"
+
+#include <video/cirrus.h>
+
+#include "cirrus_drv.h"
+
+#define CIRRUS_LUT_SIZE 256
+
+#define PALETTE_INDEX 0x8
+#define PALETTE_DATA 0x9
+
+/*
+ * This file contains setup code for the CRTC.
+ */
+
+static void cirrus_crtc_load_lut(struct drm_crtc *crtc)
+{
+ struct cirrus_crtc *cirrus_crtc = to_cirrus_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct cirrus_device *cdev = dev->dev_private;
+ int i;
+
+ if (!crtc->enabled)
+ return;
+
+ for (i = 0; i < CIRRUS_LUT_SIZE; i++) {
+ /* VGA registers */
+ WREG8(PALETTE_INDEX, i);
+ WREG8(PALETTE_DATA, cirrus_crtc->lut_r[i]);
+ WREG8(PALETTE_DATA, cirrus_crtc->lut_g[i]);
+ WREG8(PALETTE_DATA, cirrus_crtc->lut_b[i]);
+ }
+}
+
+/*
+ * The DRM core requires DPMS functions, but they make little sense in our
+ * case and so are just stubs
+ */
+
+static void cirrus_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+ struct drm_device *dev = crtc->dev;
+ struct cirrus_device *cdev = dev->dev_private;
+ u8 sr01, gr0e;
+
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ sr01 = 0x00;
+ gr0e = 0x00;
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ sr01 = 0x20;
+ gr0e = 0x02;
+ break;
+ case DRM_MODE_DPMS_SUSPEND:
+ sr01 = 0x20;
+ gr0e = 0x04;
+ break;
+ case DRM_MODE_DPMS_OFF:
+ sr01 = 0x20;
+ gr0e = 0x06;
+ break;
+ default:
+ return;
+ }
+
+ WREG8(SEQ_INDEX, 0x1);
+ sr01 |= RREG8(SEQ_DATA) & ~0x20;
+ WREG_SEQ(0x1, sr01);
+
+ WREG8(GFX_INDEX, 0xe);
+ gr0e |= RREG8(GFX_DATA) & ~0x06;
+ WREG_GFX(0xe, gr0e);
+}
+
+/*
+ * The core passes the desired mode to the CRTC code to see whether any
+ * CRTC-specific modifications need to be made to it. We're in a position
+ * to just pass that straight through, so this does nothing
+ */
+static bool cirrus_crtc_mode_fixup(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+void cirrus_set_start_address(struct drm_crtc *crtc, unsigned offset)
+{
+ struct cirrus_device *cdev = crtc->dev->dev_private;
+ u32 addr;
+ u8 tmp;
+
+ addr = offset >> 2;
+ WREG_CRT(0x0c, (u8)((addr >> 8) & 0xff));
+ WREG_CRT(0x0d, (u8)(addr & 0xff));
+
+ WREG8(CRT_INDEX, 0x1b);
+ tmp = RREG8(CRT_DATA);
+ tmp &= 0xf2;
+ tmp |= (addr >> 16) & 0x01;
+ tmp |= (addr >> 15) & 0x0c;
+ WREG_CRT(0x1b, tmp);
+ WREG8(CRT_INDEX, 0x1d);
+ tmp = RREG8(CRT_DATA);
+ tmp &= 0x7f;
+ tmp |= (addr >> 12) & 0x80;
+ WREG_CRT(0x1d, tmp);
+}
+
+/* cirrus is different - we will force move buffers out of VRAM */
+static int cirrus_crtc_do_set_base(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ int x, int y, int atomic)
+{
+ struct cirrus_device *cdev = crtc->dev->dev_private;
+ struct drm_gem_object *obj;
+ struct cirrus_framebuffer *cirrus_fb;
+ struct cirrus_bo *bo;
+ int ret;
+ u64 gpu_addr;
+
+ /* push the previous fb to system ram */
+ if (!atomic && fb) {
+ cirrus_fb = to_cirrus_framebuffer(fb);
+ obj = cirrus_fb->obj;
+ bo = gem_to_cirrus_bo(obj);
+ ret = cirrus_bo_reserve(bo, false);
+ if (ret)
+ return ret;
+ cirrus_bo_push_sysram(bo);
+ cirrus_bo_unreserve(bo);
+ }
+
+ cirrus_fb = to_cirrus_framebuffer(crtc->fb);
+ obj = cirrus_fb->obj;
+ bo = gem_to_cirrus_bo(obj);
+
+ ret = cirrus_bo_reserve(bo, false);
+ if (ret)
+ return ret;
+
+ ret = cirrus_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
+ if (ret) {
+ cirrus_bo_unreserve(bo);
+ return ret;
+ }
+
+ if (&cdev->mode_info.gfbdev->gfb == cirrus_fb) {
+ /* if pushing console in kmap it */
+ ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
+ if (ret)
+ DRM_ERROR("failed to kmap fbcon\n");
+ }
+ cirrus_bo_unreserve(bo);
+
+ cirrus_set_start_address(crtc, (u32)gpu_addr);
+ return 0;
+}
+
+static int cirrus_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+ struct drm_framebuffer *old_fb)
+{
+ return cirrus_crtc_do_set_base(crtc, old_fb, x, y, 0);
+}
+
+/*
+ * The meat of this driver. The core passes us a mode and we have to program
+ * it. The modesetting here is the bare minimum required to satisfy the qemu
+ * emulation of this hardware, and running this against a real device is
+ * likely to result in an inadequately programmed mode. We've already had
+ * the opportunity to modify the mode, so whatever we receive here should
+ * be something that can be correctly programmed and displayed
+ */
+static int cirrus_crtc_mode_set(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode,
+ int x, int y, struct drm_framebuffer *old_fb)
+{
+ struct drm_device *dev = crtc->dev;
+ struct cirrus_device *cdev = dev->dev_private;
+ int hsyncstart, hsyncend, htotal, hdispend;
+ int vtotal, vdispend;
+ int tmp;
+ int sr07 = 0, hdr = 0;
+
+ htotal = mode->htotal / 8;
+ hsyncend = mode->hsync_end / 8;
+ hsyncstart = mode->hsync_start / 8;
+ hdispend = mode->hdisplay / 8;
+
+ vtotal = mode->vtotal;
+ vdispend = mode->vdisplay;
+
+ vdispend -= 1;
+ vtotal -= 2;
+
+ htotal -= 5;
+ hdispend -= 1;
+ hsyncstart += 1;
+ hsyncend += 1;
+
+ WREG_CRT(VGA_CRTC_V_SYNC_END, 0x20);
+ WREG_CRT(VGA_CRTC_H_TOTAL, htotal);
+ WREG_CRT(VGA_CRTC_H_DISP, hdispend);
+ WREG_CRT(VGA_CRTC_H_SYNC_START, hsyncstart);
+ WREG_CRT(VGA_CRTC_H_SYNC_END, hsyncend);
+ WREG_CRT(VGA_CRTC_V_TOTAL, vtotal & 0xff);
+ WREG_CRT(VGA_CRTC_V_DISP_END, vdispend & 0xff);
+
+ tmp = 0x40;
+ if ((vdispend + 1) & 512)
+ tmp |= 0x20;
+ WREG_CRT(VGA_CRTC_MAX_SCAN, tmp);
+
+ /*
+ * Overflow bits for values that don't fit in the standard registers
+ */
+ tmp = 16;
+ if (vtotal & 256)
+ tmp |= 1;
+ if (vdispend & 256)
+ tmp |= 2;
+ if ((vdispend + 1) & 256)
+ tmp |= 8;
+ if (vtotal & 512)
+ tmp |= 32;
+ if (vdispend & 512)
+ tmp |= 64;
+ WREG_CRT(VGA_CRTC_OVERFLOW, tmp);
+
+ tmp = 0;
+
+ /* More overflow bits */
+
+ if ((htotal + 5) & 64)
+ tmp |= 16;
+ if ((htotal + 5) & 128)
+ tmp |= 32;
+ if (vtotal & 256)
+ tmp |= 64;
+ if (vtotal & 512)
+ tmp |= 128;
+
+ WREG_CRT(CL_CRT1A, tmp);
+
+ /* Disable Hercules/CGA compatibility */
+ WREG_CRT(VGA_CRTC_MODE, 0x03);
+
+ WREG8(SEQ_INDEX, 0x7);
+ sr07 = RREG8(SEQ_DATA);
+ sr07 &= 0xe0;
+ hdr = 0;
+ switch (crtc->fb->bits_per_pixel) {
+ case 8:
+ sr07 |= 0x11;
+ break;
+ case 16:
+ sr07 |= 0xc1;
+ hdr = 0xc0;
+ break;
+ case 24:
+ sr07 |= 0x15;
+ hdr = 0xc5;
+ break;
+ case 32:
+ sr07 |= 0x19;
+ hdr = 0xc5;
+ break;
+ default:
+ return -1;
+ }
+
+ WREG_SEQ(0x7, sr07);
+
+ /* Program the pitch */
+ tmp = crtc->fb->pitches[0] / 8;
+ WREG_CRT(VGA_CRTC_OFFSET, tmp);
+
+ /* Enable extended blanking and pitch bits, and enable full memory */
+ tmp = 0x22;
+ tmp |= (crtc->fb->pitches[0] >> 7) & 0x10;
+ tmp |= (crtc->fb->pitches[0] >> 6) & 0x40;
+ WREG_CRT(0x1b, tmp);
+
+ /* Enable high-colour modes */
+ WREG_GFX(VGA_GFX_MODE, 0x40);
+
+ /* And set graphics mode */
+ WREG_GFX(VGA_GFX_MISC, 0x01);
+
+ WREG_HDR(hdr);
+ cirrus_crtc_do_set_base(crtc, old_fb, x, y, 0);
+ return 0;
+}
+
+/*
+ * This is called before a mode is programmed. A typical use might be to
+ * enable DPMS during the programming to avoid seeing intermediate stages,
+ * but that's not relevant to us
+ */
+static void cirrus_crtc_prepare(struct drm_crtc *crtc)
+{
+}
+
+/*
+ * This is called after a mode is programmed. It should reverse anything done
+ * by the prepare function
+ */
+static void cirrus_crtc_commit(struct drm_crtc *crtc)
+{
+}
+
+/*
+ * The core can pass us a set of gamma values to program. We actually only
+ * use this for 8-bit mode so can't perform smooth fades on deeper modes,
+ * but it's a requirement that we provide the function
+ */
+static void cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
+ u16 *blue, uint32_t start, uint32_t size)
+{
+ struct cirrus_crtc *cirrus_crtc = to_cirrus_crtc(crtc);
+ int i;
+
+ if (size != CIRRUS_LUT_SIZE)
+ return;
+
+ for (i = 0; i < CIRRUS_LUT_SIZE; i++) {
+ cirrus_crtc->lut_r[i] = red[i];
+ cirrus_crtc->lut_g[i] = green[i];
+ cirrus_crtc->lut_b[i] = blue[i];
+ }
+ cirrus_crtc_load_lut(crtc);
+}
+
+/* Simple cleanup function */
+static void cirrus_crtc_destroy(struct drm_crtc *crtc)
+{
+ struct cirrus_crtc *cirrus_crtc = to_cirrus_crtc(crtc);
+
+ drm_crtc_cleanup(crtc);
+ kfree(cirrus_crtc);
+}
+
+/* These provide the minimum set of functions required to handle a CRTC */
+static const struct drm_crtc_funcs cirrus_crtc_funcs = {
+ .gamma_set = cirrus_crtc_gamma_set,
+ .set_config = drm_crtc_helper_set_config,
+ .destroy = cirrus_crtc_destroy,
+};
+
+static const struct drm_crtc_helper_funcs cirrus_helper_funcs = {
+ .dpms = cirrus_crtc_dpms,
+ .mode_fixup = cirrus_crtc_mode_fixup,
+ .mode_set = cirrus_crtc_mode_set,
+ .mode_set_base = cirrus_crtc_mode_set_base,
+ .prepare = cirrus_crtc_prepare,
+ .commit = cirrus_crtc_commit,
+ .load_lut = cirrus_crtc_load_lut,
+};
+
+/* CRTC setup */
+static void cirrus_crtc_init(struct drm_device *dev)
+{
+ struct cirrus_device *cdev = dev->dev_private;
+ struct cirrus_crtc *cirrus_crtc;
+ int i;
+
+ cirrus_crtc = kzalloc(sizeof(struct cirrus_crtc) +
+ (CIRRUSFB_CONN_LIMIT * sizeof(struct drm_connector *)),
+ GFP_KERNEL);
+
+ if (cirrus_crtc == NULL)
+ return;
+
+ drm_crtc_init(dev, &cirrus_crtc->base, &cirrus_crtc_funcs);
+
+ drm_mode_crtc_set_gamma_size(&cirrus_crtc->base, CIRRUS_LUT_SIZE);
+ cdev->mode_info.crtc = cirrus_crtc;
+
+ for (i = 0; i < CIRRUS_LUT_SIZE; i++) {
+ cirrus_crtc->lut_r[i] = i;
+ cirrus_crtc->lut_g[i] = i;
+ cirrus_crtc->lut_b[i] = i;
+ }
+
+ drm_crtc_helper_add(&cirrus_crtc->base, &cirrus_helper_funcs);
+}
+
+/** Sets the color ramps on behalf of fbcon */
+void cirrus_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
+ u16 blue, int regno)
+{
+ struct cirrus_crtc *cirrus_crtc = to_cirrus_crtc(crtc);
+
+ cirrus_crtc->lut_r[regno] = red;
+ cirrus_crtc->lut_g[regno] = green;
+ cirrus_crtc->lut_b[regno] = blue;
+}
+
+/** Gets the color ramps on behalf of fbcon */
+void cirrus_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
+ u16 *blue, int regno)
+{
+ struct cirrus_crtc *cirrus_crtc = to_cirrus_crtc(crtc);
+
+ *red = cirrus_crtc->lut_r[regno];
+ *green = cirrus_crtc->lut_g[regno];
+ *blue = cirrus_crtc->lut_b[regno];
+}
+
+
+static bool cirrus_encoder_mode_fixup(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void cirrus_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+}
+
+static void cirrus_encoder_dpms(struct drm_encoder *encoder, int state)
+{
+ return;
+}
+
+static void cirrus_encoder_prepare(struct drm_encoder *encoder)
+{
+}
+
+static void cirrus_encoder_commit(struct drm_encoder *encoder)
+{
+}
+
+void cirrus_encoder_destroy(struct drm_encoder *encoder)
+{
+ struct cirrus_encoder *cirrus_encoder = to_cirrus_encoder(encoder);
+ drm_encoder_cleanup(encoder);
+ kfree(cirrus_encoder);
+}
+
+static const struct drm_encoder_helper_funcs cirrus_encoder_helper_funcs = {
+ .dpms = cirrus_encoder_dpms,
+ .mode_fixup = cirrus_encoder_mode_fixup,
+ .mode_set = cirrus_encoder_mode_set,
+ .prepare = cirrus_encoder_prepare,
+ .commit = cirrus_encoder_commit,
+};
+
+static const struct drm_encoder_funcs cirrus_encoder_encoder_funcs = {
+ .destroy = cirrus_encoder_destroy,
+};
+
+static struct drm_encoder *cirrus_encoder_init(struct drm_device *dev)
+{
+ struct drm_encoder *encoder;
+ struct cirrus_encoder *cirrus_encoder;
+
+ cirrus_encoder = kzalloc(sizeof(struct cirrus_encoder), GFP_KERNEL);
+ if (!cirrus_encoder)
+ return NULL;
+
+ encoder = &cirrus_encoder->base;
+ encoder->possible_crtcs = 0x1;
+
+ drm_encoder_init(dev, encoder, &cirrus_encoder_encoder_funcs,
+ DRM_MODE_ENCODER_DAC);
+ drm_encoder_helper_add(encoder, &cirrus_encoder_helper_funcs);
+
+ return encoder;
+}
+
+
+int cirrus_vga_get_modes(struct drm_connector *connector)
+{
+ /* Just add a static list of modes */
+ drm_add_modes_noedid(connector, 640, 480);
+ drm_add_modes_noedid(connector, 800, 600);
+ drm_add_modes_noedid(connector, 1024, 768);
+ drm_add_modes_noedid(connector, 1280, 1024);
+
+ return 4;
+}
+
+static int cirrus_vga_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ /* Any mode we've added is valid */
+ return MODE_OK;
+}
+
+struct drm_encoder *cirrus_connector_best_encoder(struct drm_connector
+ *connector)
+{
+ int enc_id = connector->encoder_ids[0];
+ struct drm_mode_object *obj;
+ struct drm_encoder *encoder;
+
+ /* pick the encoder ids */
+ if (enc_id) {
+ obj =
+ drm_mode_object_find(connector->dev, enc_id,
+ DRM_MODE_OBJECT_ENCODER);
+ if (!obj)
+ return NULL;
+ encoder = obj_to_encoder(obj);
+ return encoder;
+ }
+ return NULL;
+}
+
+static enum drm_connector_status cirrus_vga_detect(struct drm_connector
+ *connector, bool force)
+{
+ return connector_status_connected;
+}
+
+static void cirrus_connector_destroy(struct drm_connector *connector)
+{
+ drm_connector_cleanup(connector);
+ kfree(connector);
+}
+
+struct drm_connector_helper_funcs cirrus_vga_connector_helper_funcs = {
+ .get_modes = cirrus_vga_get_modes,
+ .mode_valid = cirrus_vga_mode_valid,
+ .best_encoder = cirrus_connector_best_encoder,
+};
+
+struct drm_connector_funcs cirrus_vga_connector_funcs = {
+ .dpms = drm_helper_connector_dpms,
+ .detect = cirrus_vga_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = cirrus_connector_destroy,
+};
+
+static struct drm_connector *cirrus_vga_init(struct drm_device *dev)
+{
+ struct drm_connector *connector;
+ struct cirrus_connector *cirrus_connector;
+
+ cirrus_connector = kzalloc(sizeof(struct cirrus_connector), GFP_KERNEL);
+ if (!cirrus_connector)
+ return NULL;
+
+ connector = &cirrus_connector->base;
+
+ drm_connector_init(dev, connector,
+ &cirrus_vga_connector_funcs, DRM_MODE_CONNECTOR_VGA);
+
+ drm_connector_helper_add(connector, &cirrus_vga_connector_helper_funcs);
+
+ return connector;
+}
+
+
+int cirrus_modeset_init(struct cirrus_device *cdev)
+{
+ struct drm_encoder *encoder;
+ struct drm_connector *connector;
+ int ret;
+
+ drm_mode_config_init(cdev->dev);
+ cdev->mode_info.mode_config_initialized = true;
+
+ cdev->dev->mode_config.max_width = CIRRUS_MAX_FB_WIDTH;
+ cdev->dev->mode_config.max_height = CIRRUS_MAX_FB_HEIGHT;
+
+ cdev->dev->mode_config.fb_base = cdev->mc.vram_base;
+ cdev->dev->mode_config.preferred_depth = 24;
+ /* don't prefer a shadow on virt GPU */
+ cdev->dev->mode_config.prefer_shadow = 0;
+
+ cirrus_crtc_init(cdev->dev);
+
+ encoder = cirrus_encoder_init(cdev->dev);
+ if (!encoder) {
+ DRM_ERROR("cirrus_encoder_init failed\n");
+ return -1;
+ }
+
+ connector = cirrus_vga_init(cdev->dev);
+ if (!connector) {
+ DRM_ERROR("cirrus_vga_init failed\n");
+ return -1;
+ }
+
+ drm_mode_connector_attach_encoder(connector, encoder);
+
+ ret = cirrus_fbdev_init(cdev);
+ if (ret) {
+ DRM_ERROR("cirrus_fbdev_init failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+void cirrus_modeset_fini(struct cirrus_device *cdev)
+{
+ cirrus_fbdev_fini(cdev);
+
+ if (cdev->mode_info.mode_config_initialized) {
+ drm_mode_config_cleanup(cdev->dev);
+ cdev->mode_info.mode_config_initialized = false;
+ }
+}
diff --git a/drivers/gpu/drm/cirrus/cirrus_ttm.c b/drivers/gpu/drm/cirrus/cirrus_ttm.c
new file mode 100644
index 000000000000..2ebcd11a5023
--- /dev/null
+++ b/drivers/gpu/drm/cirrus/cirrus_ttm.c
@@ -0,0 +1,453 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors: Dave Airlie <airlied@redhat.com>
+ */
+#include "drmP.h"
+#include "cirrus_drv.h"
+#include <ttm/ttm_page_alloc.h>
+
+static inline struct cirrus_device *
+cirrus_bdev(struct ttm_bo_device *bd)
+{
+ return container_of(bd, struct cirrus_device, ttm.bdev);
+}
+
+static int
+cirrus_ttm_mem_global_init(struct drm_global_reference *ref)
+{
+ return ttm_mem_global_init(ref->object);
+}
+
+static void
+cirrus_ttm_mem_global_release(struct drm_global_reference *ref)
+{
+ ttm_mem_global_release(ref->object);
+}
+
+static int cirrus_ttm_global_init(struct cirrus_device *cirrus)
+{
+ struct drm_global_reference *global_ref;
+ int r;
+
+ global_ref = &cirrus->ttm.mem_global_ref;
+ global_ref->global_type = DRM_GLOBAL_TTM_MEM;
+ global_ref->size = sizeof(struct ttm_mem_global);
+ global_ref->init = &cirrus_ttm_mem_global_init;
+ global_ref->release = &cirrus_ttm_mem_global_release;
+ r = drm_global_item_ref(global_ref);
+ if (r != 0) {
+ DRM_ERROR("Failed setting up TTM memory accounting "
+ "subsystem.\n");
+ return r;
+ }
+
+ cirrus->ttm.bo_global_ref.mem_glob =
+ cirrus->ttm.mem_global_ref.object;
+ global_ref = &cirrus->ttm.bo_global_ref.ref;
+ global_ref->global_type = DRM_GLOBAL_TTM_BO;
+ global_ref->size = sizeof(struct ttm_bo_global);
+ global_ref->init = &ttm_bo_global_init;
+ global_ref->release = &ttm_bo_global_release;
+ r = drm_global_item_ref(global_ref);
+ if (r != 0) {
+ DRM_ERROR("Failed setting up TTM BO subsystem.\n");
+ drm_global_item_unref(&cirrus->ttm.mem_global_ref);
+ return r;
+ }
+ return 0;
+}
+
+void
+cirrus_ttm_global_release(struct cirrus_device *cirrus)
+{
+ if (cirrus->ttm.mem_global_ref.release == NULL)
+ return;
+
+ drm_global_item_unref(&cirrus->ttm.bo_global_ref.ref);
+ drm_global_item_unref(&cirrus->ttm.mem_global_ref);
+ cirrus->ttm.mem_global_ref.release = NULL;
+}
+
+
+static void cirrus_bo_ttm_destroy(struct ttm_buffer_object *tbo)
+{
+ struct cirrus_bo *bo;
+
+ bo = container_of(tbo, struct cirrus_bo, bo);
+
+ drm_gem_object_release(&bo->gem);
+ kfree(bo);
+}
+
+bool cirrus_ttm_bo_is_cirrus_bo(struct ttm_buffer_object *bo)
+{
+ if (bo->destroy == &cirrus_bo_ttm_destroy)
+ return true;
+ return false;
+}
+
+static int
+cirrus_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
+ struct ttm_mem_type_manager *man)
+{
+ switch (type) {
+ case TTM_PL_SYSTEM:
+ man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
+ man->available_caching = TTM_PL_MASK_CACHING;
+ man->default_caching = TTM_PL_FLAG_CACHED;
+ break;
+ case TTM_PL_VRAM:
+ man->func = &ttm_bo_manager_func;
+ man->flags = TTM_MEMTYPE_FLAG_FIXED |
+ TTM_MEMTYPE_FLAG_MAPPABLE;
+ man->available_caching = TTM_PL_FLAG_UNCACHED |
+ TTM_PL_FLAG_WC;
+ man->default_caching = TTM_PL_FLAG_WC;
+ break;
+ default:
+ DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void
+cirrus_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
+{
+ struct cirrus_bo *cirrusbo = cirrus_bo(bo);
+
+ if (!cirrus_ttm_bo_is_cirrus_bo(bo))
+ return;
+
+ cirrus_ttm_placement(cirrusbo, TTM_PL_FLAG_SYSTEM);
+ *pl = cirrusbo->placement;
+}
+
+static int cirrus_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp)
+{
+ return 0;
+}
+
+static int cirrus_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
+ struct ttm_mem_reg *mem)
+{
+ struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
+ struct cirrus_device *cirrus = cirrus_bdev(bdev);
+
+ mem->bus.addr = NULL;
+ mem->bus.offset = 0;
+ mem->bus.size = mem->num_pages << PAGE_SHIFT;
+ mem->bus.base = 0;
+ mem->bus.is_iomem = false;
+ if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
+ return -EINVAL;
+ switch (mem->mem_type) {
+ case TTM_PL_SYSTEM:
+ /* system memory */
+ return 0;
+ case TTM_PL_VRAM:
+ mem->bus.offset = mem->start << PAGE_SHIFT;
+ mem->bus.base = pci_resource_start(cirrus->dev->pdev, 0);
+ mem->bus.is_iomem = true;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ return 0;
+}
+
+static void cirrus_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
+{
+}
+
+static int cirrus_bo_move(struct ttm_buffer_object *bo,
+ bool evict, bool interruptible,
+ bool no_wait_reserve, bool no_wait_gpu,
+ struct ttm_mem_reg *new_mem)
+{
+ int r;
+ r = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
+ return r;
+}
+
+
+static void cirrus_ttm_backend_destroy(struct ttm_tt *tt)
+{
+ ttm_tt_fini(tt);
+ kfree(tt);
+}
+
+static struct ttm_backend_func cirrus_tt_backend_func = {
+ .destroy = &cirrus_ttm_backend_destroy,
+};
+
+
+struct ttm_tt *cirrus_ttm_tt_create(struct ttm_bo_device *bdev,
+ unsigned long size, uint32_t page_flags,
+ struct page *dummy_read_page)
+{
+ struct ttm_tt *tt;
+
+ tt = kzalloc(sizeof(struct ttm_tt), GFP_KERNEL);
+ if (tt == NULL)
+ return NULL;
+ tt->func = &cirrus_tt_backend_func;
+ if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) {
+ kfree(tt);
+ return NULL;
+ }
+ return tt;
+}
+
+static int cirrus_ttm_tt_populate(struct ttm_tt *ttm)
+{
+ return ttm_pool_populate(ttm);
+}
+
+static void cirrus_ttm_tt_unpopulate(struct ttm_tt *ttm)
+{
+ ttm_pool_unpopulate(ttm);
+}
+
+struct ttm_bo_driver cirrus_bo_driver = {
+ .ttm_tt_create = cirrus_ttm_tt_create,
+ .ttm_tt_populate = cirrus_ttm_tt_populate,
+ .ttm_tt_unpopulate = cirrus_ttm_tt_unpopulate,
+ .init_mem_type = cirrus_bo_init_mem_type,
+ .evict_flags = cirrus_bo_evict_flags,
+ .move = cirrus_bo_move,
+ .verify_access = cirrus_bo_verify_access,
+ .io_mem_reserve = &cirrus_ttm_io_mem_reserve,
+ .io_mem_free = &cirrus_ttm_io_mem_free,
+};
+
+int cirrus_mm_init(struct cirrus_device *cirrus)
+{
+ int ret;
+ struct drm_device *dev = cirrus->dev;
+ struct ttm_bo_device *bdev = &cirrus->ttm.bdev;
+
+ ret = cirrus_ttm_global_init(cirrus);
+ if (ret)
+ return ret;
+
+ ret = ttm_bo_device_init(&cirrus->ttm.bdev,
+ cirrus->ttm.bo_global_ref.ref.object,
+ &cirrus_bo_driver, DRM_FILE_PAGE_OFFSET,
+ true);
+ if (ret) {
+ DRM_ERROR("Error initialising bo driver; %d\n", ret);
+ return ret;
+ }
+
+ ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
+ cirrus->mc.vram_size >> PAGE_SHIFT);
+ if (ret) {
+ DRM_ERROR("Failed ttm VRAM init: %d\n", ret);
+ return ret;
+ }
+
+ cirrus->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 0),
+ pci_resource_len(dev->pdev, 0),
+ DRM_MTRR_WC);
+
+ return 0;
+}
+
+void cirrus_mm_fini(struct cirrus_device *cirrus)
+{
+ struct drm_device *dev = cirrus->dev;
+ ttm_bo_device_release(&cirrus->ttm.bdev);
+
+ cirrus_ttm_global_release(cirrus);
+
+ if (cirrus->fb_mtrr >= 0) {
+ drm_mtrr_del(cirrus->fb_mtrr,
+ pci_resource_start(dev->pdev, 0),
+ pci_resource_len(dev->pdev, 0), DRM_MTRR_WC);
+ cirrus->fb_mtrr = -1;
+ }
+}
+
+void cirrus_ttm_placement(struct cirrus_bo *bo, int domain)
+{
+ u32 c = 0;
+ bo->placement.fpfn = 0;
+ bo->placement.lpfn = 0;
+ bo->placement.placement = bo->placements;
+ bo->placement.busy_placement = bo->placements;
+ if (domain & TTM_PL_FLAG_VRAM)
+ bo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
+ if (domain & TTM_PL_FLAG_SYSTEM)
+ bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+ if (!c)
+ bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+ bo->placement.num_placement = c;
+ bo->placement.num_busy_placement = c;
+}
+
+int cirrus_bo_reserve(struct cirrus_bo *bo, bool no_wait)
+{
+ int ret;
+
+ ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0);
+ if (ret) {
+ if (ret != -ERESTARTSYS)
+ DRM_ERROR("reserve failed %p\n", bo);
+ return ret;
+ }
+ return 0;
+}
+
+void cirrus_bo_unreserve(struct cirrus_bo *bo)
+{
+ ttm_bo_unreserve(&bo->bo);
+}
+
+int cirrus_bo_create(struct drm_device *dev, int size, int align,
+ uint32_t flags, struct cirrus_bo **pcirrusbo)
+{
+ struct cirrus_device *cirrus = dev->dev_private;
+ struct cirrus_bo *cirrusbo;
+ size_t acc_size;
+ int ret;
+
+ cirrusbo = kzalloc(sizeof(struct cirrus_bo), GFP_KERNEL);
+ if (!cirrusbo)
+ return -ENOMEM;
+
+ ret = drm_gem_object_init(dev, &cirrusbo->gem, size);
+ if (ret) {
+ kfree(cirrusbo);
+ return ret;
+ }
+
+ cirrusbo->gem.driver_private = NULL;
+ cirrusbo->bo.bdev = &cirrus->ttm.bdev;
+
+ cirrus_ttm_placement(cirrusbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
+
+ acc_size = ttm_bo_dma_acc_size(&cirrus->ttm.bdev, size,
+ sizeof(struct cirrus_bo));
+
+ ret = ttm_bo_init(&cirrus->ttm.bdev, &cirrusbo->bo, size,
+ ttm_bo_type_device, &cirrusbo->placement,
+ align >> PAGE_SHIFT, 0, false, NULL, acc_size,
+ NULL, cirrus_bo_ttm_destroy);
+ if (ret)
+ return ret;
+
+ *pcirrusbo = cirrusbo;
+ return 0;
+}
+
+static inline u64 cirrus_bo_gpu_offset(struct cirrus_bo *bo)
+{
+ return bo->bo.offset;
+}
+
+int cirrus_bo_pin(struct cirrus_bo *bo, u32 pl_flag, u64 *gpu_addr)
+{
+ int i, ret;
+
+ if (bo->pin_count) {
+ bo->pin_count++;
+ if (gpu_addr)
+ *gpu_addr = cirrus_bo_gpu_offset(bo);
+ }
+
+ cirrus_ttm_placement(bo, pl_flag);
+ for (i = 0; i < bo->placement.num_placement; i++)
+ bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
+ ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false);
+ if (ret)
+ return ret;
+
+ bo->pin_count = 1;
+ if (gpu_addr)
+ *gpu_addr = cirrus_bo_gpu_offset(bo);
+ return 0;
+}
+
+int cirrus_bo_unpin(struct cirrus_bo *bo)
+{
+ int i, ret;
+ if (!bo->pin_count) {
+ DRM_ERROR("unpin bad %p\n", bo);
+ return 0;
+ }
+ bo->pin_count--;
+ if (bo->pin_count)
+ return 0;
+
+ for (i = 0; i < bo->placement.num_placement ; i++)
+ bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT;
+ ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int cirrus_bo_push_sysram(struct cirrus_bo *bo)
+{
+ int i, ret;
+ if (!bo->pin_count) {
+ DRM_ERROR("unpin bad %p\n", bo);
+ return 0;
+ }
+ bo->pin_count--;
+ if (bo->pin_count)
+ return 0;
+
+ if (bo->kmap.virtual)
+ ttm_bo_kunmap(&bo->kmap);
+
+ cirrus_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
+ for (i = 0; i < bo->placement.num_placement ; i++)
+ bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
+
+ ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false);
+ if (ret) {
+ DRM_ERROR("pushing to VRAM failed\n");
+ return ret;
+ }
+ return 0;
+}
+
+int cirrus_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct drm_file *file_priv;
+ struct cirrus_device *cirrus;
+
+ if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
+ return drm_mmap(filp, vma);
+
+ file_priv = filp->private_data;
+ cirrus = file_priv->minor->dev->dev_private;
+ return ttm_bo_mmap(filp, vma, &cirrus->ttm.bdev);
+}
diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c
index 4b8653b932f9..08758e061478 100644
--- a/drivers/gpu/drm/drm_cache.c
+++ b/drivers/gpu/drm/drm_cache.c
@@ -98,3 +98,26 @@ drm_clflush_pages(struct page *pages[], unsigned long num_pages)
#endif
}
EXPORT_SYMBOL(drm_clflush_pages);
+
+void
+drm_clflush_virt_range(char *addr, unsigned long length)
+{
+#if defined(CONFIG_X86)
+ if (cpu_has_clflush) {
+ char *end = addr + length;
+ mb();
+ for (; addr < end; addr += boot_cpu_data.x86_clflush_size)
+ clflush(addr);
+ clflush(end - 1);
+ mb();
+ return;
+ }
+
+ if (on_each_cpu(drm_clflush_ipi_handler, NULL, 1) != 0)
+ printk(KERN_ERR "Timed out waiting for cache flush.\n");
+#else
+ printk(KERN_ERR "Architecture has no drm_cache.c support\n");
+ WARN_ON_ONCE(1);
+#endif
+}
+EXPORT_SYMBOL(drm_clflush_virt_range);
diff --git a/drivers/gpu/drm/drm_context.c b/drivers/gpu/drm/drm_context.c
index 325365f6d355..affa629589ac 100644
--- a/drivers/gpu/drm/drm_context.c
+++ b/drivers/gpu/drm/drm_context.c
@@ -85,11 +85,12 @@ again:
mutex_lock(&dev->struct_mutex);
ret = idr_get_new_above(&dev->ctx_idr, NULL,
DRM_RESERVED_CONTEXTS, &new_id);
- if (ret == -EAGAIN) {
- mutex_unlock(&dev->struct_mutex);
- goto again;
- }
mutex_unlock(&dev->struct_mutex);
+ if (ret == -EAGAIN)
+ goto again;
+ else if (ret)
+ return ret;
+
return new_id;
}
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index c79870a75c2f..92cea9d77ec9 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -227,7 +227,7 @@ static int drm_mode_object_get(struct drm_device *dev,
again:
if (idr_pre_get(&dev->mode_config.crtc_idr, GFP_KERNEL) == 0) {
DRM_ERROR("Ran out memory getting a mode number\n");
- return -EINVAL;
+ return -ENOMEM;
}
mutex_lock(&dev->mode_config.idr_mutex);
@@ -235,6 +235,8 @@ again:
mutex_unlock(&dev->mode_config.idr_mutex);
if (ret == -EAGAIN)
goto again;
+ else if (ret)
+ return ret;
obj->id = new_id;
obj->type = obj_type;
@@ -361,7 +363,7 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup);
* @funcs: callbacks for the new CRTC
*
* LOCKING:
- * Caller must hold mode config lock.
+ * Takes mode_config lock.
*
* Inits a new object created as base part of an driver crtc object.
*
@@ -382,6 +384,8 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
if (ret)
goto out;
+ crtc->base.properties = &crtc->properties;
+
list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
dev->mode_config.num_crtc++;
@@ -481,6 +485,7 @@ int drm_connector_init(struct drm_device *dev,
if (ret)
goto out;
+ connector->base.properties = &connector->properties;
connector->dev = dev;
connector->funcs = funcs;
connector->connector_type = connector_type;
@@ -603,6 +608,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
if (ret)
goto out;
+ plane->base.properties = &plane->properties;
plane->dev = dev;
plane->funcs = funcs;
plane->format_types = kmalloc(sizeof(uint32_t) * format_count,
@@ -1422,11 +1428,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
}
connector = obj_to_connector(obj);
- for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) {
- if (connector->property_ids[i] != 0) {
- props_count++;
- }
- }
+ props_count = connector->properties.count;
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
if (connector->encoder_ids[i] != 0) {
@@ -1479,21 +1481,19 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
copied = 0;
prop_ptr = (uint32_t __user *)(unsigned long)(out_resp->props_ptr);
prop_values = (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr);
- for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) {
- if (connector->property_ids[i] != 0) {
- if (put_user(connector->property_ids[i],
- prop_ptr + copied)) {
- ret = -EFAULT;
- goto out;
- }
+ for (i = 0; i < connector->properties.count; i++) {
+ if (put_user(connector->properties.ids[i],
+ prop_ptr + copied)) {
+ ret = -EFAULT;
+ goto out;
+ }
- if (put_user(connector->property_values[i],
- prop_values + copied)) {
- ret = -EFAULT;
- goto out;
- }
- copied++;
+ if (put_user(connector->properties.values[i],
+ prop_values + copied)) {
+ ret = -EFAULT;
+ goto out;
}
+ copied++;
}
}
out_resp->count_props = props_count;
@@ -1830,7 +1830,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
struct drm_display_mode *mode = NULL;
struct drm_mode_set set;
uint32_t __user *set_connectors_ptr;
- int ret = 0;
+ int ret;
int i;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
@@ -2102,7 +2102,7 @@ int drm_mode_addfb(struct drm_device *dev,
fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r);
if (IS_ERR(fb)) {
- DRM_ERROR("could not create framebuffer\n");
+ DRM_DEBUG_KMS("could not create framebuffer\n");
ret = PTR_ERR(fb);
goto out;
}
@@ -2185,6 +2185,47 @@ static int format_check(struct drm_mode_fb_cmd2 *r)
}
}
+static int framebuffer_check(struct drm_mode_fb_cmd2 *r)
+{
+ int ret, hsub, vsub, num_planes, i;
+
+ ret = format_check(r);
+ if (ret) {
+ DRM_DEBUG_KMS("bad framebuffer format 0x%08x\n", r->pixel_format);
+ return ret;
+ }
+
+ hsub = drm_format_horz_chroma_subsampling(r->pixel_format);
+ vsub = drm_format_vert_chroma_subsampling(r->pixel_format);
+ num_planes = drm_format_num_planes(r->pixel_format);
+
+ if (r->width == 0 || r->width % hsub) {
+ DRM_DEBUG_KMS("bad framebuffer width %u\n", r->height);
+ return -EINVAL;
+ }
+
+ if (r->height == 0 || r->height % vsub) {
+ DRM_DEBUG_KMS("bad framebuffer height %u\n", r->height);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num_planes; i++) {
+ unsigned int width = r->width / (i != 0 ? hsub : 1);
+
+ if (!r->handles[i]) {
+ DRM_DEBUG_KMS("no buffer object handle for plane %d\n", i);
+ return -EINVAL;
+ }
+
+ if (r->pitches[i] < drm_format_plane_cpp(r->pixel_format, i) * width) {
+ DRM_DEBUG_KMS("bad pitch %u for plane %d\n", r->pitches[i], i);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
/**
* drm_mode_addfb2 - add an FB to the graphics configuration
* @inode: inode from the ioctl
@@ -2208,33 +2249,31 @@ int drm_mode_addfb2(struct drm_device *dev,
struct drm_mode_fb_cmd2 *r = data;
struct drm_mode_config *config = &dev->mode_config;
struct drm_framebuffer *fb;
- int ret = 0;
+ int ret;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
if ((config->min_width > r->width) || (r->width > config->max_width)) {
- DRM_ERROR("bad framebuffer width %d, should be >= %d && <= %d\n",
+ DRM_DEBUG_KMS("bad framebuffer width %d, should be >= %d && <= %d\n",
r->width, config->min_width, config->max_width);
return -EINVAL;
}
if ((config->min_height > r->height) || (r->height > config->max_height)) {
- DRM_ERROR("bad framebuffer height %d, should be >= %d && <= %d\n",
+ DRM_DEBUG_KMS("bad framebuffer height %d, should be >= %d && <= %d\n",
r->height, config->min_height, config->max_height);
return -EINVAL;
}
- ret = format_check(r);
- if (ret) {
- DRM_ERROR("bad framebuffer format 0x%08x\n", r->pixel_format);
+ ret = framebuffer_check(r);
+ if (ret)
return ret;
- }
mutex_lock(&dev->mode_config.mutex);
fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
if (IS_ERR(fb)) {
- DRM_ERROR("could not create framebuffer\n");
+ DRM_DEBUG_KMS("could not create framebuffer\n");
ret = PTR_ERR(fb);
goto out;
}
@@ -2365,7 +2404,7 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
struct drm_framebuffer *fb;
unsigned flags;
int num_clips;
- int ret = 0;
+ int ret;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
@@ -2564,7 +2603,7 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev,
struct drm_display_mode *mode;
struct drm_mode_object *obj;
struct drm_mode_modeinfo *umode = &mode_cmd->mode;
- int ret = 0;
+ int ret;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
@@ -2618,7 +2657,7 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev,
struct drm_connector *connector;
struct drm_display_mode mode;
struct drm_mode_modeinfo *umode = &mode_cmd->mode;
- int ret = 0;
+ int ret;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
@@ -2710,6 +2749,34 @@ struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
}
EXPORT_SYMBOL(drm_property_create_enum);
+struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
+ int flags, const char *name,
+ const struct drm_prop_enum_list *props,
+ int num_values)
+{
+ struct drm_property *property;
+ int i, ret;
+
+ flags |= DRM_MODE_PROP_BITMASK;
+
+ property = drm_property_create(dev, flags, name, num_values);
+ if (!property)
+ return NULL;
+
+ for (i = 0; i < num_values; i++) {
+ ret = drm_property_add_enum(property, i,
+ props[i].type,
+ props[i].name);
+ if (ret) {
+ drm_property_destroy(dev, property);
+ return NULL;
+ }
+ }
+
+ return property;
+}
+EXPORT_SYMBOL(drm_property_create_bitmask);
+
struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
const char *name,
uint64_t min, uint64_t max)
@@ -2734,7 +2801,14 @@ int drm_property_add_enum(struct drm_property *property, int index,
{
struct drm_property_enum *prop_enum;
- if (!(property->flags & DRM_MODE_PROP_ENUM))
+ if (!(property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)))
+ return -EINVAL;
+
+ /*
+ * Bitmask enum properties have the additional constraint of values
+ * from 0 to 63
+ */
+ if ((property->flags & DRM_MODE_PROP_BITMASK) && (value > 63))
return -EINVAL;
if (!list_empty(&property->enum_blob_list)) {
@@ -2778,60 +2852,78 @@ void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
}
EXPORT_SYMBOL(drm_property_destroy);
-int drm_connector_attach_property(struct drm_connector *connector,
+void drm_connector_attach_property(struct drm_connector *connector,
struct drm_property *property, uint64_t init_val)
{
- int i;
-
- for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) {
- if (connector->property_ids[i] == 0) {
- connector->property_ids[i] = property->base.id;
- connector->property_values[i] = init_val;
- break;
- }
- }
-
- if (i == DRM_CONNECTOR_MAX_PROPERTY)
- return -EINVAL;
- return 0;
+ drm_object_attach_property(&connector->base, property, init_val);
}
EXPORT_SYMBOL(drm_connector_attach_property);
int drm_connector_property_set_value(struct drm_connector *connector,
struct drm_property *property, uint64_t value)
{
+ return drm_object_property_set_value(&connector->base, property, value);
+}
+EXPORT_SYMBOL(drm_connector_property_set_value);
+
+int drm_connector_property_get_value(struct drm_connector *connector,
+ struct drm_property *property, uint64_t *val)
+{
+ return drm_object_property_get_value(&connector->base, property, val);
+}
+EXPORT_SYMBOL(drm_connector_property_get_value);
+
+void drm_object_attach_property(struct drm_mode_object *obj,
+ struct drm_property *property,
+ uint64_t init_val)
+{
+ int count = obj->properties->count;
+
+ if (count == DRM_OBJECT_MAX_PROPERTY) {
+ WARN(1, "Failed to attach object property (type: 0x%x). Please "
+ "increase DRM_OBJECT_MAX_PROPERTY by 1 for each time "
+ "you see this message on the same object type.\n",
+ obj->type);
+ return;
+ }
+
+ obj->properties->ids[count] = property->base.id;
+ obj->properties->values[count] = init_val;
+ obj->properties->count++;
+}
+EXPORT_SYMBOL(drm_object_attach_property);
+
+int drm_object_property_set_value(struct drm_mode_object *obj,
+ struct drm_property *property, uint64_t val)
+{
int i;
- for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) {
- if (connector->property_ids[i] == property->base.id) {
- connector->property_values[i] = value;
- break;
+ for (i = 0; i < obj->properties->count; i++) {
+ if (obj->properties->ids[i] == property->base.id) {
+ obj->properties->values[i] = val;
+ return 0;
}
}
- if (i == DRM_CONNECTOR_MAX_PROPERTY)
- return -EINVAL;
- return 0;
+ return -EINVAL;
}
-EXPORT_SYMBOL(drm_connector_property_set_value);
+EXPORT_SYMBOL(drm_object_property_set_value);
-int drm_connector_property_get_value(struct drm_connector *connector,
+int drm_object_property_get_value(struct drm_mode_object *obj,
struct drm_property *property, uint64_t *val)
{
int i;
- for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) {
- if (connector->property_ids[i] == property->base.id) {
- *val = connector->property_values[i];
- break;
+ for (i = 0; i < obj->properties->count; i++) {
+ if (obj->properties->ids[i] == property->base.id) {
+ *val = obj->properties->values[i];
+ return 0;
}
}
- if (i == DRM_CONNECTOR_MAX_PROPERTY)
- return -EINVAL;
- return 0;
+ return -EINVAL;
}
-EXPORT_SYMBOL(drm_connector_property_get_value);
+EXPORT_SYMBOL(drm_object_property_get_value);
int drm_mode_getproperty_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
@@ -2862,7 +2954,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
}
property = obj_to_property(obj);
- if (property->flags & DRM_MODE_PROP_ENUM) {
+ if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
list_for_each_entry(prop_enum, &property->enum_blob_list, head)
enum_count++;
} else if (property->flags & DRM_MODE_PROP_BLOB) {
@@ -2887,7 +2979,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
}
out_resp->count_values = value_count;
- if (property->flags & DRM_MODE_PROP_ENUM) {
+ if (property->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) {
if ((out_resp->count_enum_blobs >= enum_count) && enum_count) {
copied = 0;
enum_ptr = (struct drm_mode_property_enum __user *)(unsigned long)out_resp->enum_blob_ptr;
@@ -3009,7 +3101,7 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
struct edid *edid)
{
struct drm_device *dev = connector->dev;
- int ret = 0, size;
+ int ret, size;
if (connector->edid_blob_ptr)
drm_property_destroy_blob(dev, connector->edid_blob_ptr);
@@ -3033,75 +3125,202 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
}
EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
+static bool drm_property_change_is_valid(struct drm_property *property,
+ __u64 value)
+{
+ if (property->flags & DRM_MODE_PROP_IMMUTABLE)
+ return false;
+ if (property->flags & DRM_MODE_PROP_RANGE) {
+ if (value < property->values[0] || value > property->values[1])
+ return false;
+ return true;
+ } else if (property->flags & DRM_MODE_PROP_BITMASK) {
+ int i;
+ __u64 valid_mask = 0;
+ for (i = 0; i < property->num_values; i++)
+ valid_mask |= (1ULL << property->values[i]);
+ return !(value & ~valid_mask);
+ } else {
+ int i;
+ for (i = 0; i < property->num_values; i++)
+ if (property->values[i] == value)
+ return true;
+ return false;
+ }
+}
+
int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
{
- struct drm_mode_connector_set_property *out_resp = data;
- struct drm_mode_object *obj;
- struct drm_property *property;
- struct drm_connector *connector;
+ struct drm_mode_connector_set_property *conn_set_prop = data;
+ struct drm_mode_obj_set_property obj_set_prop = {
+ .value = conn_set_prop->value,
+ .prop_id = conn_set_prop->prop_id,
+ .obj_id = conn_set_prop->connector_id,
+ .obj_type = DRM_MODE_OBJECT_CONNECTOR
+ };
+
+ /* It does all the locking and checking we need */
+ return drm_mode_obj_set_property_ioctl(dev, &obj_set_prop, file_priv);
+}
+
+static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj,
+ struct drm_property *property,
+ uint64_t value)
+{
int ret = -EINVAL;
+ struct drm_connector *connector = obj_to_connector(obj);
+
+ /* Do DPMS ourselves */
+ if (property == connector->dev->mode_config.dpms_property) {
+ if (connector->funcs->dpms)
+ (*connector->funcs->dpms)(connector, (int)value);
+ ret = 0;
+ } else if (connector->funcs->set_property)
+ ret = connector->funcs->set_property(connector, property, value);
+
+ /* store the property value if successful */
+ if (!ret)
+ drm_connector_property_set_value(connector, property, value);
+ return ret;
+}
+
+static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
+ struct drm_property *property,
+ uint64_t value)
+{
+ int ret = -EINVAL;
+ struct drm_crtc *crtc = obj_to_crtc(obj);
+
+ if (crtc->funcs->set_property)
+ ret = crtc->funcs->set_property(crtc, property, value);
+ if (!ret)
+ drm_object_property_set_value(obj, property, value);
+
+ return ret;
+}
+
+static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj,
+ struct drm_property *property,
+ uint64_t value)
+{
+ int ret = -EINVAL;
+ struct drm_plane *plane = obj_to_plane(obj);
+
+ if (plane->funcs->set_property)
+ ret = plane->funcs->set_property(plane, property, value);
+ if (!ret)
+ drm_object_property_set_value(obj, property, value);
+
+ return ret;
+}
+
+int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_mode_obj_get_properties *arg = data;
+ struct drm_mode_object *obj;
+ int ret = 0;
int i;
+ int copied = 0;
+ int props_count = 0;
+ uint32_t __user *props_ptr;
+ uint64_t __user *prop_values_ptr;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
mutex_lock(&dev->mode_config.mutex);
- obj = drm_mode_object_find(dev, out_resp->connector_id, DRM_MODE_OBJECT_CONNECTOR);
+ obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
if (!obj) {
+ ret = -EINVAL;
+ goto out;
+ }
+ if (!obj->properties) {
+ ret = -EINVAL;
goto out;
}
- connector = obj_to_connector(obj);
- for (i = 0; i < DRM_CONNECTOR_MAX_PROPERTY; i++) {
- if (connector->property_ids[i] == out_resp->prop_id)
- break;
+ props_count = obj->properties->count;
+
+ /* This ioctl is called twice, once to determine how much space is
+ * needed, and the 2nd time to fill it. */
+ if ((arg->count_props >= props_count) && props_count) {
+ copied = 0;
+ props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
+ prop_values_ptr = (uint64_t __user *)(unsigned long)
+ (arg->prop_values_ptr);
+ for (i = 0; i < props_count; i++) {
+ if (put_user(obj->properties->ids[i],
+ props_ptr + copied)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ if (put_user(obj->properties->values[i],
+ prop_values_ptr + copied)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ copied++;
+ }
}
+ arg->count_props = props_count;
+out:
+ mutex_unlock(&dev->mode_config.mutex);
+ return ret;
+}
+
+int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_mode_obj_set_property *arg = data;
+ struct drm_mode_object *arg_obj;
+ struct drm_mode_object *prop_obj;
+ struct drm_property *property;
+ int ret = -EINVAL;
+ int i;
+
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
+ return -EINVAL;
+
+ mutex_lock(&dev->mode_config.mutex);
- if (i == DRM_CONNECTOR_MAX_PROPERTY) {
+ arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
+ if (!arg_obj)
+ goto out;
+ if (!arg_obj->properties)
goto out;
- }
- obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY);
- if (!obj) {
+ for (i = 0; i < arg_obj->properties->count; i++)
+ if (arg_obj->properties->ids[i] == arg->prop_id)
+ break;
+
+ if (i == arg_obj->properties->count)
goto out;
- }
- property = obj_to_property(obj);
- if (property->flags & DRM_MODE_PROP_IMMUTABLE)
+ prop_obj = drm_mode_object_find(dev, arg->prop_id,
+ DRM_MODE_OBJECT_PROPERTY);
+ if (!prop_obj)
goto out;
+ property = obj_to_property(prop_obj);
- if (property->flags & DRM_MODE_PROP_RANGE) {
- if (out_resp->value < property->values[0])
- goto out;
+ if (!drm_property_change_is_valid(property, arg->value))
+ goto out;
- if (out_resp->value > property->values[1])
- goto out;
- } else {
- int found = 0;
- for (i = 0; i < property->num_values; i++) {
- if (property->values[i] == out_resp->value) {
- found = 1;
- break;
- }
- }
- if (!found) {
- goto out;
- }
+ switch (arg_obj->type) {
+ case DRM_MODE_OBJECT_CONNECTOR:
+ ret = drm_mode_connector_set_obj_prop(arg_obj, property,
+ arg->value);
+ break;
+ case DRM_MODE_OBJECT_CRTC:
+ ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value);
+ break;
+ case DRM_MODE_OBJECT_PLANE:
+ ret = drm_mode_plane_set_obj_prop(arg_obj, property, arg->value);
+ break;
}
- /* Do DPMS ourselves */
- if (property == connector->dev->mode_config.dpms_property) {
- if (connector->funcs->dpms)
- (*connector->funcs->dpms)(connector, (int) out_resp->value);
- ret = 0;
- } else if (connector->funcs->set_property)
- ret = connector->funcs->set_property(connector, property, out_resp->value);
-
- /* store the property value if successful */
- if (!ret)
- drm_connector_property_set_value(connector, property, out_resp->value);
out:
mutex_unlock(&dev->mode_config.mutex);
return ret;
@@ -3173,6 +3392,11 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
}
crtc = obj_to_crtc(obj);
+ if (crtc->funcs->gamma_set == NULL) {
+ ret = -ENOSYS;
+ goto out;
+ }
+
/* memcpy into gamma store */
if (crtc_lut->gamma_size != crtc->gamma_size) {
ret = -EINVAL;
@@ -3468,3 +3692,140 @@ void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
}
}
EXPORT_SYMBOL(drm_fb_get_bpp_depth);
+
+/**
+ * drm_format_num_planes - get the number of planes for format
+ * @format: pixel format (DRM_FORMAT_*)
+ *
+ * RETURNS:
+ * The number of planes used by the specified pixel format.
+ */
+int drm_format_num_planes(uint32_t format)
+{
+ switch (format) {
+ case DRM_FORMAT_YUV410:
+ case DRM_FORMAT_YVU410:
+ case DRM_FORMAT_YUV411:
+ case DRM_FORMAT_YVU411:
+ case DRM_FORMAT_YUV420:
+ case DRM_FORMAT_YVU420:
+ case DRM_FORMAT_YUV422:
+ case DRM_FORMAT_YVU422:
+ case DRM_FORMAT_YUV444:
+ case DRM_FORMAT_YVU444:
+ return 3;
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ case DRM_FORMAT_NV16:
+ case DRM_FORMAT_NV61:
+ return 2;
+ default:
+ return 1;
+ }
+}
+EXPORT_SYMBOL(drm_format_num_planes);
+
+/**
+ * drm_format_plane_cpp - determine the bytes per pixel value
+ * @format: pixel format (DRM_FORMAT_*)
+ * @plane: plane index
+ *
+ * RETURNS:
+ * The bytes per pixel value for the specified plane.
+ */
+int drm_format_plane_cpp(uint32_t format, int plane)
+{
+ unsigned int depth;
+ int bpp;
+
+ if (plane >= drm_format_num_planes(format))
+ return 0;
+
+ switch (format) {
+ case DRM_FORMAT_YUYV:
+ case DRM_FORMAT_YVYU:
+ case DRM_FORMAT_UYVY:
+ case DRM_FORMAT_VYUY:
+ return 2;
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ case DRM_FORMAT_NV16:
+ case DRM_FORMAT_NV61:
+ return plane ? 2 : 1;
+ case DRM_FORMAT_YUV410:
+ case DRM_FORMAT_YVU410:
+ case DRM_FORMAT_YUV411:
+ case DRM_FORMAT_YVU411:
+ case DRM_FORMAT_YUV420:
+ case DRM_FORMAT_YVU420:
+ case DRM_FORMAT_YUV422:
+ case DRM_FORMAT_YVU422:
+ case DRM_FORMAT_YUV444:
+ case DRM_FORMAT_YVU444:
+ return 1;
+ default:
+ drm_fb_get_bpp_depth(format, &depth, &bpp);
+ return bpp >> 3;
+ }
+}
+EXPORT_SYMBOL(drm_format_plane_cpp);
+
+/**
+ * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor
+ * @format: pixel format (DRM_FORMAT_*)
+ *
+ * RETURNS:
+ * The horizontal chroma subsampling factor for the
+ * specified pixel format.
+ */
+int drm_format_horz_chroma_subsampling(uint32_t format)
+{
+ switch (format) {
+ case DRM_FORMAT_YUV411:
+ case DRM_FORMAT_YVU411:
+ case DRM_FORMAT_YUV410:
+ case DRM_FORMAT_YVU410:
+ return 4;
+ case DRM_FORMAT_YUYV:
+ case DRM_FORMAT_YVYU:
+ case DRM_FORMAT_UYVY:
+ case DRM_FORMAT_VYUY:
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ case DRM_FORMAT_NV16:
+ case DRM_FORMAT_NV61:
+ case DRM_FORMAT_YUV422:
+ case DRM_FORMAT_YVU422:
+ case DRM_FORMAT_YUV420:
+ case DRM_FORMAT_YVU420:
+ return 2;
+ default:
+ return 1;
+ }
+}
+EXPORT_SYMBOL(drm_format_horz_chroma_subsampling);
+
+/**
+ * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor
+ * @format: pixel format (DRM_FORMAT_*)
+ *
+ * RETURNS:
+ * The vertical chroma subsampling factor for the
+ * specified pixel format.
+ */
+int drm_format_vert_chroma_subsampling(uint32_t format)
+{
+ switch (format) {
+ case DRM_FORMAT_YUV410:
+ case DRM_FORMAT_YVU410:
+ return 4;
+ case DRM_FORMAT_YUV420:
+ case DRM_FORMAT_YVU420:
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ return 2;
+ default:
+ return 1;
+ }
+}
+EXPORT_SYMBOL(drm_format_vert_chroma_subsampling);
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 81118893264c..3252e7067d8b 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -518,7 +518,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
int count = 0, ro, fail = 0;
struct drm_crtc_helper_funcs *crtc_funcs;
struct drm_mode_set save_set;
- int ret = 0;
+ int ret;
int i;
DRM_DEBUG_KMS("\n");
@@ -1023,36 +1023,3 @@ void drm_helper_hpd_irq_event(struct drm_device *dev)
queue_delayed_work(system_nrt_wq, &dev->mode_config.output_poll_work, 0);
}
EXPORT_SYMBOL(drm_helper_hpd_irq_event);
-
-
-/**
- * drm_format_num_planes - get the number of planes for format
- * @format: pixel format (DRM_FORMAT_*)
- *
- * RETURNS:
- * The number of planes used by the specified pixel format.
- */
-int drm_format_num_planes(uint32_t format)
-{
- switch (format) {
- case DRM_FORMAT_YUV410:
- case DRM_FORMAT_YVU410:
- case DRM_FORMAT_YUV411:
- case DRM_FORMAT_YVU411:
- case DRM_FORMAT_YUV420:
- case DRM_FORMAT_YVU420:
- case DRM_FORMAT_YUV422:
- case DRM_FORMAT_YVU422:
- case DRM_FORMAT_YUV444:
- case DRM_FORMAT_YVU444:
- return 3;
- case DRM_FORMAT_NV12:
- case DRM_FORMAT_NV21:
- case DRM_FORMAT_NV16:
- case DRM_FORMAT_NV61:
- return 2;
- default:
- return 1;
- }
-}
-EXPORT_SYMBOL(drm_format_num_planes);
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 6116e3b75393..8a9d0792e4ec 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -163,7 +163,9 @@ static struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
- DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED)
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
};
#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 5a18b0df8285..608bddfc7e35 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -81,7 +81,7 @@ struct detailed_mode_closure {
#define LEVEL_CVT 3
static struct edid_quirk {
- char *vendor;
+ char vendor[4];
int product_id;
u32 quirks;
} edid_quirk_list[] = {
@@ -149,13 +149,13 @@ EXPORT_SYMBOL(drm_edid_header_is_valid);
* Sanity check the EDID block (base or extension). Return 0 if the block
* doesn't check out, or 1 if it's valid.
*/
-bool drm_edid_block_valid(u8 *raw_edid)
+bool drm_edid_block_valid(u8 *raw_edid, int block)
{
int i;
u8 csum = 0;
struct edid *edid = (struct edid *)raw_edid;
- if (raw_edid[0] == 0x00) {
+ if (block == 0) {
int score = drm_edid_header_is_valid(raw_edid);
if (score == 8) ;
else if (score >= 6) {
@@ -219,7 +219,7 @@ bool drm_edid_is_valid(struct edid *edid)
return false;
for (i = 0; i <= edid->extensions; i++)
- if (!drm_edid_block_valid(raw + i * EDID_LENGTH))
+ if (!drm_edid_block_valid(raw + i * EDID_LENGTH, i))
return false;
return true;
@@ -299,7 +299,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
for (i = 0; i < 4; i++) {
if (drm_do_probe_ddc_edid(adapter, block, 0, EDID_LENGTH))
goto out;
- if (drm_edid_block_valid(block))
+ if (drm_edid_block_valid(block, 0))
break;
if (i == 0 && drm_edid_is_zero(block, EDID_LENGTH)) {
connector->null_edid_counter++;
@@ -324,7 +324,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter)
block + (valid_extensions + 1) * EDID_LENGTH,
j, EDID_LENGTH))
goto out;
- if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH)) {
+ if (drm_edid_block_valid(block + (valid_extensions + 1) * EDID_LENGTH, j)) {
valid_extensions++;
break;
}
@@ -486,23 +486,47 @@ static void edid_fixup_preferred(struct drm_connector *connector,
preferred_mode->type |= DRM_MODE_TYPE_PREFERRED;
}
+static bool
+mode_is_rb(const struct drm_display_mode *mode)
+{
+ return (mode->htotal - mode->hdisplay == 160) &&
+ (mode->hsync_end - mode->hdisplay == 80) &&
+ (mode->hsync_end - mode->hsync_start == 32) &&
+ (mode->vsync_start - mode->vdisplay == 3);
+}
+
+/*
+ * drm_mode_find_dmt - Create a copy of a mode if present in DMT
+ * @dev: Device to duplicate against
+ * @hsize: Mode width
+ * @vsize: Mode height
+ * @fresh: Mode refresh rate
+ * @rb: Mode reduced-blanking-ness
+ *
+ * Walk the DMT mode list looking for a match for the given parameters.
+ * Return a newly allocated copy of the mode, or NULL if not found.
+ */
struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
- int hsize, int vsize, int fresh)
+ int hsize, int vsize, int fresh,
+ bool rb)
{
- struct drm_display_mode *mode = NULL;
int i;
for (i = 0; i < drm_num_dmt_modes; i++) {
const struct drm_display_mode *ptr = &drm_dmt_modes[i];
- if (hsize == ptr->hdisplay &&
- vsize == ptr->vdisplay &&
- fresh == drm_mode_vrefresh(ptr)) {
- /* get the expected default mode */
- mode = drm_mode_duplicate(dev, ptr);
- break;
- }
+ if (hsize != ptr->hdisplay)
+ continue;
+ if (vsize != ptr->vdisplay)
+ continue;
+ if (fresh != drm_mode_vrefresh(ptr))
+ continue;
+ if (rb != mode_is_rb(ptr))
+ continue;
+
+ return drm_mode_duplicate(dev, ptr);
}
- return mode;
+
+ return NULL;
}
EXPORT_SYMBOL(drm_mode_find_dmt);
@@ -731,10 +755,17 @@ drm_mode_std(struct drm_connector *connector, struct edid *edid,
}
/* check whether it can be found in default mode table */
- mode = drm_mode_find_dmt(dev, hsize, vsize, vrefresh_rate);
+ if (drm_monitor_supports_rb(edid)) {
+ mode = drm_mode_find_dmt(dev, hsize, vsize, vrefresh_rate,
+ true);
+ if (mode)
+ return mode;
+ }
+ mode = drm_mode_find_dmt(dev, hsize, vsize, vrefresh_rate, false);
if (mode)
return mode;
+ /* okay, generate it */
switch (timing_level) {
case LEVEL_DMT:
break;
@@ -748,6 +779,8 @@ drm_mode_std(struct drm_connector *connector, struct edid *edid,
* secondary GTF curve. Please don't do that.
*/
mode = drm_gtf_mode(dev, hsize, vsize, vrefresh_rate, 0, 0);
+ if (!mode)
+ return NULL;
if (drm_mode_hsync(mode) > drm_gtf2_hbreak(edid)) {
drm_mode_destroy(dev, mode);
mode = drm_gtf_mode_complex(dev, hsize, vsize,
@@ -909,15 +942,6 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
}
static bool
-mode_is_rb(const struct drm_display_mode *mode)
-{
- return (mode->htotal - mode->hdisplay == 160) &&
- (mode->hsync_end - mode->hdisplay == 80) &&
- (mode->hsync_end - mode->hsync_start == 32) &&
- (mode->vsync_start - mode->vdisplay == 3);
-}
-
-static bool
mode_in_hsync_range(const struct drm_display_mode *mode,
struct edid *edid, u8 *t)
{
@@ -994,12 +1018,8 @@ mode_in_range(const struct drm_display_mode *mode, struct edid *edid,
return true;
}
-/*
- * XXX If drm_dmt_modes ever regrows the CVT-R modes (and it will) this will
- * need to account for them.
- */
static int
-drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid,
+drm_dmt_modes_for_range(struct drm_connector *connector, struct edid *edid,
struct detailed_timing *timing)
{
int i, modes = 0;
@@ -1019,17 +1039,110 @@ drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid,
return modes;
}
+/* fix up 1366x768 mode from 1368x768;
+ * GFT/CVT can't express 1366 width which isn't dividable by 8
+ */
+static void fixup_mode_1366x768(struct drm_display_mode *mode)
+{
+ if (mode->hdisplay == 1368 && mode->vdisplay == 768) {
+ mode->hdisplay = 1366;
+ mode->hsync_start--;
+ mode->hsync_end--;
+ drm_mode_set_name(mode);
+ }
+}
+
+static int
+drm_gtf_modes_for_range(struct drm_connector *connector, struct edid *edid,
+ struct detailed_timing *timing)
+{
+ int i, modes = 0;
+ struct drm_display_mode *newmode;
+ struct drm_device *dev = connector->dev;
+
+ for (i = 0; i < num_extra_modes; i++) {
+ const struct minimode *m = &extra_modes[i];
+ newmode = drm_gtf_mode(dev, m->w, m->h, m->r, 0, 0);
+ if (!newmode)
+ return modes;
+
+ fixup_mode_1366x768(newmode);
+ if (!mode_in_range(newmode, edid, timing)) {
+ drm_mode_destroy(dev, newmode);
+ continue;
+ }
+
+ drm_mode_probed_add(connector, newmode);
+ modes++;
+ }
+
+ return modes;
+}
+
+static int
+drm_cvt_modes_for_range(struct drm_connector *connector, struct edid *edid,
+ struct detailed_timing *timing)
+{
+ int i, modes = 0;
+ struct drm_display_mode *newmode;
+ struct drm_device *dev = connector->dev;
+ bool rb = drm_monitor_supports_rb(edid);
+
+ for (i = 0; i < num_extra_modes; i++) {
+ const struct minimode *m = &extra_modes[i];
+ newmode = drm_cvt_mode(dev, m->w, m->h, m->r, rb, 0, 0);
+ if (!newmode)
+ return modes;
+
+ fixup_mode_1366x768(newmode);
+ if (!mode_in_range(newmode, edid, timing)) {
+ drm_mode_destroy(dev, newmode);
+ continue;
+ }
+
+ drm_mode_probed_add(connector, newmode);
+ modes++;
+ }
+
+ return modes;
+}
+
static void
do_inferred_modes(struct detailed_timing *timing, void *c)
{
struct detailed_mode_closure *closure = c;
struct detailed_non_pixel *data = &timing->data.other_data;
- int gtf = (closure->edid->features & DRM_EDID_FEATURE_DEFAULT_GTF);
+ struct detailed_data_monitor_range *range = &data->data.range;
+
+ if (data->type != EDID_DETAIL_MONITOR_RANGE)
+ return;
- if (gtf && data->type == EDID_DETAIL_MONITOR_RANGE)
+ closure->modes += drm_dmt_modes_for_range(closure->connector,
+ closure->edid,
+ timing);
+
+ if (!version_greater(closure->edid, 1, 1))
+ return; /* GTF not defined yet */
+
+ switch (range->flags) {
+ case 0x02: /* secondary gtf, XXX could do more */
+ case 0x00: /* default gtf */
closure->modes += drm_gtf_modes_for_range(closure->connector,
closure->edid,
timing);
+ break;
+ case 0x04: /* cvt, only in 1.4+ */
+ if (!version_greater(closure->edid, 1, 3))
+ break;
+
+ closure->modes += drm_cvt_modes_for_range(closure->connector,
+ closure->edid,
+ timing);
+ break;
+ case 0x01: /* just the ranges, no formula */
+ default:
+ break;
+ }
}
static int
@@ -1062,8 +1175,8 @@ drm_est3_modes(struct drm_connector *connector, struct detailed_timing *timing)
mode = drm_mode_find_dmt(connector->dev,
est3_modes[m].w,
est3_modes[m].h,
- est3_modes[m].r
- /*, est3_modes[m].rb */);
+ est3_modes[m].r,
+ est3_modes[m].rb);
if (mode) {
drm_mode_probed_add(connector, mode);
modes++;
@@ -1312,6 +1425,8 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
#define VENDOR_BLOCK 0x03
#define SPEAKER_BLOCK 0x04
#define EDID_BASIC_AUDIO (1 << 6)
+#define EDID_CEA_YCRCB444 (1 << 5)
+#define EDID_CEA_YCRCB422 (1 << 4)
/**
* Search EDID for CEA extension block.
@@ -1666,13 +1781,29 @@ static void drm_add_display_info(struct edid *edid,
info->bpc = 0;
info->color_formats = 0;
- /* Only defined for 1.4 with digital displays */
- if (edid->revision < 4)
+ if (edid->revision < 3)
return;
if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
return;
+ /* Get data from CEA blocks if present */
+ edid_ext = drm_find_cea_extension(edid);
+ if (edid_ext) {
+ info->cea_rev = edid_ext[1];
+
+ /* The existence of a CEA block should imply RGB support */
+ info->color_formats = DRM_COLOR_FORMAT_RGB444;
+ if (edid_ext[3] & EDID_CEA_YCRCB444)
+ info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
+ if (edid_ext[3] & EDID_CEA_YCRCB422)
+ info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
+ }
+
+ /* Only defined for 1.4 with digital displays */
+ if (edid->revision < 4)
+ return;
+
switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
case DRM_EDID_DIGITAL_DEPTH_6:
info->bpc = 6;
@@ -1698,18 +1829,11 @@ static void drm_add_display_info(struct edid *edid,
break;
}
- info->color_formats = DRM_COLOR_FORMAT_RGB444;
- if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB444)
- info->color_formats = DRM_COLOR_FORMAT_YCRCB444;
- if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB422)
- info->color_formats = DRM_COLOR_FORMAT_YCRCB422;
-
- /* Get data from CEA blocks if present */
- edid_ext = drm_find_cea_extension(edid);
- if (!edid_ext)
- return;
-
- info->cea_rev = edid_ext[1];
+ info->color_formats |= DRM_COLOR_FORMAT_RGB444;
+ if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444)
+ info->color_formats |= DRM_COLOR_FORMAT_YCRCB444;
+ if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422)
+ info->color_formats |= DRM_COLOR_FORMAT_YCRCB422;
}
/**
diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c
index da9acba2dd6c..66d4a28ad5a2 100644
--- a/drivers/gpu/drm/drm_edid_load.c
+++ b/drivers/gpu/drm/drm_edid_load.c
@@ -173,7 +173,7 @@ static int edid_load(struct drm_connector *connector, char *name,
}
memcpy(edid, fwdata, fwsize);
- if (!drm_edid_block_valid(edid)) {
+ if (!drm_edid_block_valid(edid, 0)) {
DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
name);
kfree(edid);
@@ -185,7 +185,7 @@ static int edid_load(struct drm_connector *connector, char *name,
if (i != valid_extensions + 1)
memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
edid + i * EDID_LENGTH, EDID_LENGTH);
- if (drm_edid_block_valid(edid + i * EDID_LENGTH))
+ if (drm_edid_block_valid(edid + i * EDID_LENGTH, i))
valid_extensions++;
}
@@ -220,18 +220,18 @@ int drm_load_edid_firmware(struct drm_connector *connector)
{
char *connector_name = drm_get_connector_name(connector);
char *edidname = edid_firmware, *last, *colon;
- int ret = 0;
+ int ret;
if (*edidname == '\0')
- return ret;
+ return 0;
colon = strchr(edidname, ':');
if (colon != NULL) {
if (strncmp(connector_name, edidname, colon - edidname))
- return ret;
+ return 0;
edidname = colon + 1;
if (*edidname == '\0')
- return ret;
+ return 0;
}
last = edidname + strlen(edidname) - 1;
diff --git a/drivers/gpu/drm/drm_edid_modes.h b/drivers/gpu/drm/drm_edid_modes.h
index a91ffb117220..ff98a7eb38dd 100644
--- a/drivers/gpu/drm/drm_edid_modes.h
+++ b/drivers/gpu/drm/drm_edid_modes.h
@@ -30,7 +30,6 @@
/*
* Autogenerated from the DMT spec.
* This table is copied from xfree86/modes/xf86EdidModes.c.
- * But the mode with Reduced blank feature is deleted.
*/
static const struct drm_display_mode drm_dmt_modes[] = {
/* 640x350@85Hz */
@@ -81,6 +80,10 @@ static const struct drm_display_mode drm_dmt_modes[] = {
{ DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 56250, 800, 832,
896, 1048, 0, 600, 601, 604, 631, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ /* 800x600@120Hz RB */
+ { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 73250, 800, 848,
+ 880, 960, 0, 600, 603, 607, 636, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 848x480@60Hz */
{ DRM_MODE("848x480", DRM_MODE_TYPE_DRIVER, 33750, 848, 864,
976, 1088, 0, 480, 486, 494, 517, 0,
@@ -106,10 +109,18 @@ static const struct drm_display_mode drm_dmt_modes[] = {
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 94500, 1024, 1072,
1168, 1376, 0, 768, 769, 772, 808, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ /* 1024x768@120Hz RB */
+ { DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 115500, 1024, 1072,
+ 1104, 1184, 0, 768, 771, 775, 813, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1152x864@75Hz */
{ DRM_MODE("1152x864", DRM_MODE_TYPE_DRIVER, 108000, 1152, 1216,
1344, 1600, 0, 864, 865, 868, 900, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ /* 1280x768@60Hz RB */
+ { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 68250, 1280, 1328,
+ 1360, 1440, 0, 768, 771, 778, 790, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1280x768@60Hz */
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 79500, 1280, 1344,
1472, 1664, 0, 768, 771, 778, 798, 0,
@@ -122,6 +133,14 @@ static const struct drm_display_mode drm_dmt_modes[] = {
{ DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 117500, 1280, 1360,
1496, 1712, 0, 768, 771, 778, 809, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ /* 1280x768@120Hz RB */
+ { DRM_MODE("1280x768", DRM_MODE_TYPE_DRIVER, 140250, 1280, 1328,
+ 1360, 1440, 0, 768, 771, 778, 813, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ /* 1280x800@60Hz RB */
+ { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 71000, 1280, 1328,
+ 1360, 1440, 0, 800, 803, 809, 823, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1280x800@60Hz */
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 83500, 1280, 1352,
1480, 1680, 0, 800, 803, 809, 831, 0,
@@ -134,6 +153,10 @@ static const struct drm_display_mode drm_dmt_modes[] = {
{ DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 122500, 1280, 1360,
1496, 1712, 0, 800, 803, 809, 843, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ /* 1280x800@120Hz RB */
+ { DRM_MODE("1280x800", DRM_MODE_TYPE_DRIVER, 146250, 1280, 1328,
+ 1360, 1440, 0, 800, 803, 809, 847, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1280x960@60Hz */
{ DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1376,
1488, 1800, 0, 960, 961, 964, 1000, 0,
@@ -142,6 +165,10 @@ static const struct drm_display_mode drm_dmt_modes[] = {
{ DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1344,
1504, 1728, 0, 960, 961, 964, 1011, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ /* 1280x960@120Hz RB */
+ { DRM_MODE("1280x960", DRM_MODE_TYPE_DRIVER, 175500, 1280, 1328,
+ 1360, 1440, 0, 960, 963, 967, 1017, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1280x1024@60Hz */
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 108000, 1280, 1328,
1440, 1688, 0, 1024, 1025, 1028, 1066, 0,
@@ -154,22 +181,42 @@ static const struct drm_display_mode drm_dmt_modes[] = {
{ DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 157500, 1280, 1344,
1504, 1728, 0, 1024, 1025, 1028, 1072, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ /* 1280x1024@120Hz RB */
+ { DRM_MODE("1280x1024", DRM_MODE_TYPE_DRIVER, 187250, 1280, 1328,
+ 1360, 1440, 0, 1024, 1027, 1034, 1084, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1360x768@60Hz */
{ DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 85500, 1360, 1424,
1536, 1792, 0, 768, 771, 777, 795, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
- /* 1440x1050@60Hz */
+ /* 1360x768@120Hz RB */
+ { DRM_MODE("1360x768", DRM_MODE_TYPE_DRIVER, 148250, 1360, 1408,
+ 1440, 1520, 0, 768, 771, 776, 813, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ /* 1400x1050@60Hz RB */
+ { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 101000, 1400, 1448,
+ 1480, 1560, 0, 1050, 1053, 1057, 1080, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ /* 1400x1050@60Hz */
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 121750, 1400, 1488,
1632, 1864, 0, 1050, 1053, 1057, 1089, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
- /* 1440x1050@75Hz */
+ /* 1400x1050@75Hz */
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 156000, 1400, 1504,
1648, 1896, 0, 1050, 1053, 1057, 1099, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
- /* 1440x1050@85Hz */
+ /* 1400x1050@85Hz */
{ DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 179500, 1400, 1504,
1656, 1912, 0, 1050, 1053, 1057, 1105, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ /* 1400x1050@120Hz RB */
+ { DRM_MODE("1400x1050", DRM_MODE_TYPE_DRIVER, 208000, 1400, 1448,
+ 1480, 1560, 0, 1050, 1053, 1057, 1112, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ /* 1440x900@60Hz RB */
+ { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 88750, 1440, 1488,
+ 1520, 1600, 0, 900, 903, 909, 926, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1440x900@60Hz */
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 106500, 1440, 1520,
1672, 1904, 0, 900, 903, 909, 934, 0,
@@ -182,6 +229,10 @@ static const struct drm_display_mode drm_dmt_modes[] = {
{ DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 157000, 1440, 1544,
1696, 1952, 0, 900, 903, 909, 948, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ /* 1440x900@120Hz RB */
+ { DRM_MODE("1440x900", DRM_MODE_TYPE_DRIVER, 182750, 1440, 1488,
+ 1520, 1600, 0, 900, 903, 909, 953, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1600x1200@60Hz */
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 162000, 1600, 1664,
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
@@ -202,6 +253,14 @@ static const struct drm_display_mode drm_dmt_modes[] = {
{ DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 229500, 1600, 1664,
1856, 2160, 0, 1200, 1201, 1204, 1250, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ /* 1600x1200@120Hz RB */
+ { DRM_MODE("1600x1200", DRM_MODE_TYPE_DRIVER, 268250, 1600, 1648,
+ 1680, 1760, 0, 1200, 1203, 1207, 1271, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ /* 1680x1050@60Hz RB */
+ { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 119000, 1680, 1728,
+ 1760, 1840, 0, 1050, 1053, 1059, 1080, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1680x1050@60Hz */
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 146250, 1680, 1784,
1960, 2240, 0, 1050, 1053, 1059, 1089, 0,
@@ -214,15 +273,23 @@ static const struct drm_display_mode drm_dmt_modes[] = {
{ DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 214750, 1680, 1808,
1984, 2288, 0, 1050, 1053, 1059, 1105, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ /* 1680x1050@120Hz RB */
+ { DRM_MODE("1680x1050", DRM_MODE_TYPE_DRIVER, 245500, 1680, 1728,
+ 1760, 1840, 0, 1050, 1053, 1059, 1112, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1792x1344@60Hz */
{ DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 204750, 1792, 1920,
2120, 2448, 0, 1344, 1345, 1348, 1394, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
- /* 1729x1344@75Hz */
+ /* 1792x1344@75Hz */
{ DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 261000, 1792, 1888,
2104, 2456, 0, 1344, 1345, 1348, 1417, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
- /* 1853x1392@60Hz */
+ /* 1792x1344@120Hz RB */
+ { DRM_MODE("1792x1344", DRM_MODE_TYPE_DRIVER, 333250, 1792, 1840,
+ 1872, 1952, 0, 1344, 1347, 1351, 1423, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ /* 1856x1392@60Hz */
{ DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 218250, 1856, 1952,
2176, 2528, 0, 1392, 1393, 1396, 1439, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
@@ -230,6 +297,14 @@ static const struct drm_display_mode drm_dmt_modes[] = {
{ DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 288000, 1856, 1984,
2208, 2560, 0, 1392, 1395, 1399, 1500, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ /* 1856x1392@120Hz RB */
+ { DRM_MODE("1856x1392", DRM_MODE_TYPE_DRIVER, 356500, 1856, 1904,
+ 1936, 2016, 0, 1392, 1395, 1399, 1474, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ /* 1920x1200@60Hz RB */
+ { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 154000, 1920, 1968,
+ 2000, 2080, 0, 1200, 1203, 1209, 1235, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1920x1200@60Hz */
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 193250, 1920, 2056,
2256, 2592, 0, 1200, 1203, 1209, 1245, 0,
@@ -242,6 +317,10 @@ static const struct drm_display_mode drm_dmt_modes[] = {
{ DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 281250, 1920, 2064,
2272, 2624, 0, 1200, 1203, 1209, 1262, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ /* 1920x1200@120Hz RB */
+ { DRM_MODE("1920x1200", DRM_MODE_TYPE_DRIVER, 317000, 1920, 1968,
+ 2000, 2080, 0, 1200, 1203, 1209, 1271, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 1920x1440@60Hz */
{ DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 234000, 1920, 2048,
2256, 2600, 0, 1440, 1441, 1444, 1500, 0,
@@ -250,6 +329,14 @@ static const struct drm_display_mode drm_dmt_modes[] = {
{ DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2064,
2288, 2640, 0, 1440, 1441, 1444, 1500, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ /* 1920x1440@120Hz RB */
+ { DRM_MODE("1920x1440", DRM_MODE_TYPE_DRIVER, 380500, 1920, 1968,
+ 2000, 2080, 0, 1440, 1443, 1447, 1525, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+ /* 2560x1600@60Hz RB */
+ { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 268500, 2560, 2608,
+ 2640, 2720, 0, 1600, 1603, 1609, 1646, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 2560x1600@60Hz */
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 348500, 2560, 2752,
3032, 3504, 0, 1600, 1603, 1609, 1658, 0,
@@ -262,6 +349,11 @@ static const struct drm_display_mode drm_dmt_modes[] = {
{ DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 505250, 2560, 2768,
3048, 3536, 0, 1600, 1603, 1609, 1682, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ /* 2560x1600@120Hz RB */
+ { DRM_MODE("2560x1600", DRM_MODE_TYPE_DRIVER, 552750, 2560, 2608,
+ 2640, 2720, 0, 1600, 1603, 1609, 1694, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC) },
+
};
static const int drm_num_dmt_modes =
sizeof(drm_dmt_modes) / sizeof(struct drm_display_mode);
@@ -320,12 +412,14 @@ static const struct drm_display_mode edid_est_modes[] = {
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) }, /* 1152x864@75Hz */
};
-static const struct {
+struct minimode {
short w;
short h;
short r;
short rb;
-} est3_modes[] = {
+};
+
+static const struct minimode est3_modes[] = {
/* byte 6 */
{ 640, 350, 85, 0 },
{ 640, 400, 85, 0 },
@@ -377,288 +471,304 @@ static const struct {
{ 1920, 1440, 60, 0 },
{ 1920, 1440, 75, 0 },
};
-static const int num_est3_modes = sizeof(est3_modes) / sizeof(est3_modes[0]);
+static const int num_est3_modes = ARRAY_SIZE(est3_modes);
+
+static const struct minimode extra_modes[] = {
+ { 1024, 576, 60, 0 },
+ { 1366, 768, 60, 0 },
+ { 1600, 900, 60, 0 },
+ { 1680, 945, 60, 0 },
+ { 1920, 1080, 60, 0 },
+ { 2048, 1152, 60, 0 },
+ { 2048, 1536, 60, 0 },
+};
+static const int num_extra_modes = ARRAY_SIZE(extra_modes);
/*
* Probably taken from CEA-861 spec.
* This table is converted from xorg's hw/xfree86/modes/xf86EdidModes.c.
*/
static const struct drm_display_mode edid_cea_modes[] = {
- /* 640x480@60Hz */
+ /* 1 - 640x480@60Hz */
{ DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
752, 800, 0, 480, 490, 492, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 720x480@60Hz */
+ /* 2 - 720x480@60Hz */
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736,
798, 858, 0, 480, 489, 495, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 720x480@60Hz */
+ /* 3 - 720x480@60Hz */
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736,
798, 858, 0, 480, 489, 495, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 1280x720@60Hz */
+ /* 4 - 1280x720@60Hz */
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390,
1430, 1650, 0, 720, 725, 730, 750, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
- /* 1920x1080i@60Hz */
+ /* 5 - 1920x1080i@60Hz */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
2052, 2200, 0, 1080, 1084, 1094, 1125, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
DRM_MODE_FLAG_INTERLACE) },
- /* 1440x480i@60Hz */
+ /* 6 - 1440x480i@60Hz */
{ DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
1602, 1716, 0, 480, 488, 494, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE) },
- /* 1440x480i@60Hz */
+ DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+ /* 7 - 1440x480i@60Hz */
{ DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
1602, 1716, 0, 480, 488, 494, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE) },
- /* 1440x240@60Hz */
+ DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+ /* 8 - 1440x240@60Hz */
{ DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
1602, 1716, 0, 240, 244, 247, 262, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 1440x240@60Hz */
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
+ DRM_MODE_FLAG_DBLCLK) },
+ /* 9 - 1440x240@60Hz */
{ DRM_MODE("1440x240", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1478,
1602, 1716, 0, 240, 244, 247, 262, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 2880x480i@60Hz */
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
+ DRM_MODE_FLAG_DBLCLK) },
+ /* 10 - 2880x480i@60Hz */
{ DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
3204, 3432, 0, 480, 488, 494, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
DRM_MODE_FLAG_INTERLACE) },
- /* 2880x480i@60Hz */
+ /* 11 - 2880x480i@60Hz */
{ DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
3204, 3432, 0, 480, 488, 494, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
DRM_MODE_FLAG_INTERLACE) },
- /* 2880x240@60Hz */
+ /* 12 - 2880x240@60Hz */
{ DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
3204, 3432, 0, 240, 244, 247, 262, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 2880x240@60Hz */
+ /* 13 - 2880x240@60Hz */
{ DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
3204, 3432, 0, 240, 244, 247, 262, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 1440x480@60Hz */
+ /* 14 - 1440x480@60Hz */
{ DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472,
1596, 1716, 0, 480, 489, 495, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 1440x480@60Hz */
+ /* 15 - 1440x480@60Hz */
{ DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472,
1596, 1716, 0, 480, 489, 495, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 1920x1080@60Hz */
+ /* 16 - 1920x1080@60Hz */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
- /* 720x576@50Hz */
+ /* 17 - 720x576@50Hz */
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732,
796, 864, 0, 576, 581, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 720x576@50Hz */
+ /* 18 - 720x576@50Hz */
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732,
796, 864, 0, 576, 581, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 1280x720@50Hz */
+ /* 19 - 1280x720@50Hz */
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720,
1760, 1980, 0, 720, 725, 730, 750, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
- /* 1920x1080i@50Hz */
+ /* 20 - 1920x1080i@50Hz */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
DRM_MODE_FLAG_INTERLACE) },
- /* 1440x576i@50Hz */
+ /* 21 - 1440x576i@50Hz */
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
1590, 1728, 0, 576, 580, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE) },
- /* 1440x576i@50Hz */
+ DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+ /* 22 - 1440x576i@50Hz */
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
1590, 1728, 0, 576, 580, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE) },
- /* 1440x288@50Hz */
+ DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+ /* 23 - 1440x288@50Hz */
{ DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
1590, 1728, 0, 288, 290, 293, 312, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 1440x288@50Hz */
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
+ DRM_MODE_FLAG_DBLCLK) },
+ /* 24 - 1440x288@50Hz */
{ DRM_MODE("1440x288", DRM_MODE_TYPE_DRIVER, 27000, 1440, 1464,
1590, 1728, 0, 288, 290, 293, 312, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 2880x576i@50Hz */
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
+ DRM_MODE_FLAG_DBLCLK) },
+ /* 25 - 2880x576i@50Hz */
{ DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
3180, 3456, 0, 576, 580, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
DRM_MODE_FLAG_INTERLACE) },
- /* 2880x576i@50Hz */
+ /* 26 - 2880x576i@50Hz */
{ DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
3180, 3456, 0, 576, 580, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
DRM_MODE_FLAG_INTERLACE) },
- /* 2880x288@50Hz */
+ /* 27 - 2880x288@50Hz */
{ DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
3180, 3456, 0, 288, 290, 293, 312, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 2880x288@50Hz */
+ /* 28 - 2880x288@50Hz */
{ DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
3180, 3456, 0, 288, 290, 293, 312, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 1440x576@50Hz */
+ /* 29 - 1440x576@50Hz */
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
1592, 1728, 0, 576, 581, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 1440x576@50Hz */
+ /* 30 - 1440x576@50Hz */
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
1592, 1728, 0, 576, 581, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 1920x1080@50Hz */
+ /* 31 - 1920x1080@50Hz */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
- /* 1920x1080@24Hz */
+ /* 32 - 1920x1080@24Hz */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558,
2602, 2750, 0, 1080, 1084, 1089, 1125, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
- /* 1920x1080@25Hz */
+ /* 33 - 1920x1080@25Hz */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
- /* 1920x1080@30Hz */
+ /* 34 - 1920x1080@30Hz */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
- /* 2880x480@60Hz */
+ /* 35 - 2880x480@60Hz */
{ DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944,
3192, 3432, 0, 480, 489, 495, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 2880x480@60Hz */
+ /* 36 - 2880x480@60Hz */
{ DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944,
3192, 3432, 0, 480, 489, 495, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 2880x576@50Hz */
+ /* 37 - 2880x576@50Hz */
{ DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928,
3184, 3456, 0, 576, 581, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 2880x576@50Hz */
+ /* 38 - 2880x576@50Hz */
{ DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928,
3184, 3456, 0, 576, 581, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 1920x1080i@50Hz */
+ /* 39 - 1920x1080i@50Hz */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 72000, 1920, 1952,
2120, 2304, 0, 1080, 1126, 1136, 1250, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC |
DRM_MODE_FLAG_INTERLACE) },
- /* 1920x1080i@100Hz */
+ /* 40 - 1920x1080i@100Hz */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
DRM_MODE_FLAG_INTERLACE) },
- /* 1280x720@100Hz */
+ /* 41 - 1280x720@100Hz */
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1720,
1760, 1980, 0, 720, 725, 730, 750, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
- /* 720x576@100Hz */
+ /* 42 - 720x576@100Hz */
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732,
796, 864, 0, 576, 581, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 720x576@100Hz */
+ /* 43 - 720x576@100Hz */
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732,
796, 864, 0, 576, 581, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 1440x576i@100Hz */
+ /* 44 - 1440x576i@100Hz */
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
1590, 1728, 0, 576, 580, 586, 625, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 1440x576i@100Hz */
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
+ DRM_MODE_FLAG_DBLCLK) },
+ /* 45 - 1440x576i@100Hz */
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
1590, 1728, 0, 576, 580, 586, 625, 0,
- DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 1920x1080i@120Hz */
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
+ DRM_MODE_FLAG_DBLCLK) },
+ /* 46 - 1920x1080i@120Hz */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
2052, 2200, 0, 1080, 1084, 1094, 1125, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
DRM_MODE_FLAG_INTERLACE) },
- /* 1280x720@120Hz */
+ /* 47 - 1280x720@120Hz */
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1390,
1430, 1650, 0, 720, 725, 730, 750, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
- /* 720x480@120Hz */
+ /* 48 - 720x480@120Hz */
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736,
798, 858, 0, 480, 489, 495, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 720x480@120Hz */
+ /* 49 - 720x480@120Hz */
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736,
798, 858, 0, 480, 489, 495, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 1440x480i@120Hz */
+ /* 50 - 1440x480i@120Hz */
{ DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
1602, 1716, 0, 480, 488, 494, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE) },
- /* 1440x480i@120Hz */
+ DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+ /* 51 - 1440x480i@120Hz */
{ DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1478,
1602, 1716, 0, 480, 488, 494, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE) },
- /* 720x576@200Hz */
+ DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+ /* 52 - 720x576@200Hz */
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732,
796, 864, 0, 576, 581, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 720x576@200Hz */
+ /* 53 - 720x576@200Hz */
{ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732,
796, 864, 0, 576, 581, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 1440x576i@200Hz */
+ /* 54 - 1440x576i@200Hz */
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
1590, 1728, 0, 576, 580, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE) },
- /* 1440x576i@200Hz */
+ DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+ /* 55 - 1440x576i@200Hz */
{ DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1464,
1590, 1728, 0, 576, 580, 586, 625, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE) },
- /* 720x480@240Hz */
+ DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+ /* 56 - 720x480@240Hz */
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736,
798, 858, 0, 480, 489, 495, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 720x480@240Hz */
+ /* 57 - 720x480@240Hz */
{ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736,
798, 858, 0, 480, 489, 495, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
- /* 1440x480i@240 */
+ /* 58 - 1440x480i@240 */
{ DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
1602, 1716, 0, 480, 488, 494, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE) },
- /* 1440x480i@240 */
+ DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+ /* 59 - 1440x480i@240 */
{ DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 108000, 1440, 1478,
1602, 1716, 0, 480, 488, 494, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
- DRM_MODE_FLAG_INTERLACE) },
- /* 1280x720@24Hz */
+ DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK) },
+ /* 60 - 1280x720@24Hz */
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 59400, 1280, 3040,
3080, 3300, 0, 720, 725, 730, 750, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
- /* 1280x720@25Hz */
+ /* 61 - 1280x720@25Hz */
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3700,
3740, 3960, 0, 720, 725, 730, 750, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
- /* 1280x720@30Hz */
+ /* 62 - 1280x720@30Hz */
{ DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3040,
3080, 3300, 0, 720, 725, 730, 750, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
- /* 1920x1080@120Hz */
+ /* 63 - 1920x1080@120Hz */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2008,
2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
- /* 1920x1080@100Hz */
+ /* 64 - 1920x1080@100Hz */
{ DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2448,
2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
};
-static const int drm_num_cea_modes =
- sizeof (edid_cea_modes) / sizeof (edid_cea_modes[0]);
+static const int drm_num_cea_modes = ARRAY_SIZE(edid_cea_modes);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index a0d6e894d97c..5683b7fdd746 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -136,6 +136,9 @@ static void drm_fb_helper_restore_lut_atomic(struct drm_crtc *crtc)
{
uint16_t *r_base, *g_base, *b_base;
+ if (crtc->funcs->gamma_set == NULL)
+ return;
+
r_base = crtc->gamma_store;
g_base = r_base + crtc->gamma_size;
b_base = g_base + crtc->gamma_size;
@@ -383,7 +386,6 @@ int drm_fb_helper_init(struct drm_device *dev,
int crtc_count, int max_conn_count)
{
struct drm_crtc *crtc;
- int ret = 0;
int i;
fb_helper->dev = dev;
@@ -408,10 +410,8 @@ int drm_fb_helper_init(struct drm_device *dev,
sizeof(struct drm_connector *),
GFP_KERNEL);
- if (!fb_helper->crtc_info[i].mode_set.connectors) {
- ret = -ENOMEM;
+ if (!fb_helper->crtc_info[i].mode_set.connectors)
goto out_free;
- }
fb_helper->crtc_info[i].mode_set.num_connectors = 0;
}
@@ -1083,7 +1083,7 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper,
/* try and find a 1024x768 mode on each connector */
can_clone = true;
- dmt_mode = drm_mode_find_dmt(fb_helper->dev, 1024, 768, 60);
+ dmt_mode = drm_mode_find_dmt(fb_helper->dev, 1024, 768, 60, false);
for (i = 0; i < fb_helper->connector_count; i++) {
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index 83114b5e3cee..d58e69da1fb5 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -201,6 +201,19 @@ free:
}
EXPORT_SYMBOL(drm_gem_object_alloc);
+static void
+drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp)
+{
+ if (obj->import_attach) {
+ drm_prime_remove_imported_buf_handle(&filp->prime,
+ obj->import_attach->dmabuf);
+ }
+ if (obj->export_dma_buf) {
+ drm_prime_remove_imported_buf_handle(&filp->prime,
+ obj->export_dma_buf);
+ }
+}
+
/**
* Removes the mapping from handle to filp for this object.
*/
@@ -233,9 +246,7 @@ drm_gem_handle_delete(struct drm_file *filp, u32 handle)
idr_remove(&filp->object_idr, handle);
spin_unlock(&filp->table_lock);
- if (obj->import_attach)
- drm_prime_remove_imported_buf_handle(&filp->prime,
- obj->import_attach->dmabuf);
+ drm_gem_remove_prime_handles(obj, filp);
if (dev->driver->gem_close_object)
dev->driver->gem_close_object(obj, filp);
@@ -272,8 +283,7 @@ again:
spin_unlock(&file_priv->table_lock);
if (ret == -EAGAIN)
goto again;
-
- if (ret != 0)
+ else if (ret)
return ret;
drm_gem_object_handle_reference(obj);
@@ -329,7 +339,7 @@ drm_gem_create_mmap_offset(struct drm_gem_object *obj)
struct drm_gem_mm *mm = dev->mm_private;
struct drm_map_list *list;
struct drm_local_map *map;
- int ret = 0;
+ int ret;
/* Set the object up for mmap'ing */
list = &obj->map_list;
@@ -456,8 +466,7 @@ again:
if (ret == -EAGAIN)
goto again;
-
- if (ret != 0)
+ else if (ret)
goto err;
/* Allocate a reference for the name table. */
@@ -532,9 +541,7 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
struct drm_gem_object *obj = ptr;
struct drm_device *dev = obj->dev;
- if (obj->import_attach)
- drm_prime_remove_imported_buf_handle(&file_priv->prime,
- obj->import_attach->dmabuf);
+ drm_gem_remove_prime_handles(obj, file_priv);
if (dev->driver->gem_close_object)
dev->driver->gem_close_object(obj, file_priv);
@@ -628,7 +635,7 @@ void drm_gem_vm_open(struct vm_area_struct *vma)
drm_gem_object_reference(obj);
mutex_lock(&obj->dev->struct_mutex);
- drm_vm_open_locked(vma);
+ drm_vm_open_locked(obj->dev, vma);
mutex_unlock(&obj->dev->struct_mutex);
}
EXPORT_SYMBOL(drm_gem_vm_open);
@@ -639,7 +646,7 @@ void drm_gem_vm_close(struct vm_area_struct *vma)
struct drm_device *dev = obj->dev;
mutex_lock(&dev->struct_mutex);
- drm_vm_close_locked(vma);
+ drm_vm_close_locked(obj->dev, vma);
drm_gem_object_unreference(obj);
mutex_unlock(&dev->struct_mutex);
}
@@ -712,7 +719,7 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
*/
drm_gem_object_reference(obj);
- drm_vm_open_locked(vma);
+ drm_vm_open_locked(dev, vma);
out_unlock:
mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index cf85155da2a0..64a62c697313 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -283,6 +283,10 @@ int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
case DRM_CAP_DUMB_PREFER_SHADOW:
req->value = dev->mode_config.prefer_shadow;
break;
+ case DRM_CAP_PRIME:
+ req->value |= dev->driver->prime_fd_to_handle ? DRM_PRIME_CAP_IMPORT : 0;
+ req->value |= dev->driver->prime_handle_to_fd ? DRM_PRIME_CAP_EXPORT : 0;
+ break;
default:
return -EINVAL;
}
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index c869436e238a..c798eeae0a03 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -189,7 +189,7 @@ void drm_vblank_cleanup(struct drm_device *dev)
if (dev->num_crtcs == 0)
return;
- del_timer(&dev->vblank_disable_timer);
+ del_timer_sync(&dev->vblank_disable_timer);
vblank_disable_fn((unsigned long)dev);
@@ -310,7 +310,7 @@ static void drm_irq_vgaarb_nokms(void *cookie, bool state)
*/
int drm_irq_install(struct drm_device *dev)
{
- int ret = 0;
+ int ret;
unsigned long sh_flags = 0;
char *irqname;
@@ -731,7 +731,7 @@ EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos);
u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
struct timeval *tvblank, unsigned flags)
{
- int ret = 0;
+ int ret;
/* Define requested maximum error on timestamps (nanoseconds). */
int max_error = (int) drm_timestamp_precision * 1000;
@@ -1031,18 +1031,15 @@ int drm_modeset_ctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_modeset_ctl *modeset = data;
- int ret = 0;
unsigned int crtc;
/* If drm_vblank_init() hasn't been called yet, just no-op */
if (!dev->num_crtcs)
- goto out;
+ return 0;
crtc = modeset->crtc;
- if (crtc >= dev->num_crtcs) {
- ret = -EINVAL;
- goto out;
- }
+ if (crtc >= dev->num_crtcs)
+ return -EINVAL;
switch (modeset->cmd) {
case _DRM_PRE_MODESET:
@@ -1052,12 +1049,10 @@ int drm_modeset_ctl(struct drm_device *dev, void *data,
drm_vblank_post_modeset(dev, crtc);
break;
default:
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
-out:
- return ret;
+ return 0;
}
static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
@@ -1154,7 +1149,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
union drm_wait_vblank *vblwait = data;
- int ret = 0;
+ int ret;
unsigned int flags, seq, crtc, high_crtc;
if ((!drm_dev_to_irq(dev)) || (!dev->irq_enabled))
diff --git a/drivers/gpu/drm/drm_lock.c b/drivers/gpu/drm/drm_lock.c
index c79c713eeba0..521152041691 100644
--- a/drivers/gpu/drm/drm_lock.c
+++ b/drivers/gpu/drm/drm_lock.c
@@ -331,7 +331,7 @@ static int drm_notifier(void *priv)
void drm_idlelock_take(struct drm_lock_data *lock_data)
{
- int ret = 0;
+ int ret;
spin_lock_bh(&lock_data->spinlock);
lock_data->kernel_waiters++;
diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index 1bdf2b54eaf6..f546ff98a114 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -68,6 +68,7 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev,
{
struct drm_gem_object *obj;
void *buf;
+ int ret;
obj = drm_gem_object_lookup(dev, file_priv, handle);
if (!obj)
@@ -100,6 +101,17 @@ int drm_gem_prime_handle_to_fd(struct drm_device *dev,
obj->export_dma_buf = buf;
*prime_fd = dma_buf_fd(buf, flags);
}
+ /* if we've exported this buffer the cheat and add it to the import list
+ * so we get the correct handle back
+ */
+ ret = drm_prime_add_imported_buf_handle(&file_priv->prime,
+ obj->export_dma_buf, handle);
+ if (ret) {
+ drm_gem_object_unreference_unlocked(obj);
+ mutex_unlock(&file_priv->prime.lock);
+ return ret;
+ }
+
mutex_unlock(&file_priv->prime.lock);
return 0;
}
@@ -227,6 +239,42 @@ out:
}
EXPORT_SYMBOL(drm_prime_pages_to_sg);
+/* export an sg table into an array of pages and addresses
+ this is currently required by the TTM driver in order to do correct fault
+ handling */
+int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
+ dma_addr_t *addrs, int max_pages)
+{
+ unsigned count;
+ struct scatterlist *sg;
+ struct page *page;
+ u32 len, offset;
+ int pg_index;
+ dma_addr_t addr;
+
+ pg_index = 0;
+ for_each_sg(sgt->sgl, sg, sgt->nents, count) {
+ len = sg->length;
+ offset = sg->offset;
+ page = sg_page(sg);
+ addr = sg_dma_address(sg);
+
+ while (len > 0) {
+ if (WARN_ON(pg_index >= max_pages))
+ return -1;
+ pages[pg_index] = page;
+ if (addrs)
+ addrs[pg_index] = addr;
+
+ page++;
+ addr += PAGE_SIZE;
+ len -= PAGE_SIZE;
+ pg_index++;
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL(drm_prime_sg_to_page_addr_arrays);
/* helper function to cleanup a GEM/prime object */
void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg)
{
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c
index aa454f80e109..21bcd4a555d8 100644
--- a/drivers/gpu/drm/drm_stub.c
+++ b/drivers/gpu/drm/drm_stub.c
@@ -122,11 +122,10 @@ again:
ret = idr_get_new_above(&drm_minors_idr, NULL,
base, &new_id);
mutex_unlock(&dev->struct_mutex);
- if (ret == -EAGAIN) {
+ if (ret == -EAGAIN)
goto again;
- } else if (ret) {
+ else if (ret)
return ret;
- }
if (new_id >= limit) {
idr_remove(&drm_minors_idr, new_id);
@@ -211,7 +210,7 @@ EXPORT_SYMBOL(drm_master_put);
int drm_setmaster_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- int ret = 0;
+ int ret;
if (file_priv->is_master)
return 0;
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index 5a7bd51fc3d8..45cf1dd3eb9c 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -347,17 +347,17 @@ static struct bin_attribute edid_attr = {
};
/**
- * drm_sysfs_connector_add - add an connector to sysfs
+ * drm_sysfs_connector_add - add a connector to sysfs
* @connector: connector to add
*
- * Create an connector device in sysfs, along with its associated connector
+ * Create a connector device in sysfs, along with its associated connector
* properties (so far, connection status, dpms, mode list & edid) and
* generate a hotplug event so userspace knows there's a new connector
* available.
*
* Note:
- * This routine should only be called *once* for each DRM minor registered.
- * A second call for an already registered device will trigger the BUG_ON
+ * This routine should only be called *once* for each registered connector.
+ * A second call for an already registered connector will trigger the BUG_ON
* below.
*/
int drm_sysfs_connector_add(struct drm_connector *connector)
@@ -366,7 +366,7 @@ int drm_sysfs_connector_add(struct drm_connector *connector)
int attr_cnt = 0;
int opt_cnt = 0;
int i;
- int ret = 0;
+ int ret;
/* We shouldn't get called more than once for the same connector */
BUG_ON(device_is_registered(&connector->kdev));
diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c
index 149561818349..961ee08927fe 100644
--- a/drivers/gpu/drm/drm_vm.c
+++ b/drivers/gpu/drm/drm_vm.c
@@ -406,10 +406,9 @@ static const struct vm_operations_struct drm_vm_sg_ops = {
* Create a new drm_vma_entry structure as the \p vma private data entry and
* add it to drm_device::vmalist.
*/
-void drm_vm_open_locked(struct vm_area_struct *vma)
+void drm_vm_open_locked(struct drm_device *dev,
+ struct vm_area_struct *vma)
{
- struct drm_file *priv = vma->vm_file->private_data;
- struct drm_device *dev = priv->minor->dev;
struct drm_vma_entry *vma_entry;
DRM_DEBUG("0x%08lx,0x%08lx\n",
@@ -430,14 +429,13 @@ static void drm_vm_open(struct vm_area_struct *vma)
struct drm_device *dev = priv->minor->dev;
mutex_lock(&dev->struct_mutex);
- drm_vm_open_locked(vma);
+ drm_vm_open_locked(dev, vma);
mutex_unlock(&dev->struct_mutex);
}
-void drm_vm_close_locked(struct vm_area_struct *vma)
+void drm_vm_close_locked(struct drm_device *dev,
+ struct vm_area_struct *vma)
{
- struct drm_file *priv = vma->vm_file->private_data;
- struct drm_device *dev = priv->minor->dev;
struct drm_vma_entry *pt, *temp;
DRM_DEBUG("0x%08lx,0x%08lx\n",
@@ -467,7 +465,7 @@ static void drm_vm_close(struct vm_area_struct *vma)
struct drm_device *dev = priv->minor->dev;
mutex_lock(&dev->struct_mutex);
- drm_vm_close_locked(vma);
+ drm_vm_close_locked(dev, vma);
mutex_unlock(&dev->struct_mutex);
}
@@ -519,7 +517,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
vma->vm_flags |= VM_RESERVED; /* Don't swap */
vma->vm_flags |= VM_DONTEXPAND;
- drm_vm_open_locked(vma);
+ drm_vm_open_locked(dev, vma);
return 0;
}
@@ -670,7 +668,7 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
vma->vm_flags |= VM_RESERVED; /* Don't swap */
vma->vm_flags |= VM_DONTEXPAND;
- drm_vm_open_locked(vma);
+ drm_vm_open_locked(dev, vma);
return 0;
}
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 3343ac437fe5..7f5096763b7d 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -10,6 +10,12 @@ config DRM_EXYNOS
Choose this option if you have a Samsung SoC EXYNOS chipset.
If M is selected the module will be called exynosdrm.
+config DRM_EXYNOS_DMABUF
+ bool "EXYNOS DRM DMABUF"
+ depends on DRM_EXYNOS
+ help
+ Choose this option if you want to use DMABUF feature for DRM.
+
config DRM_EXYNOS_FIMD
bool "Exynos DRM FIMD"
depends on DRM_EXYNOS && !FB_S3C
@@ -27,3 +33,9 @@ config DRM_EXYNOS_VIDI
depends on DRM_EXYNOS
help
Choose this option if you want to use Exynos VIDI for DRM.
+
+config DRM_EXYNOS_G2D
+ bool "Exynos DRM G2D"
+ depends on DRM_EXYNOS
+ help
+ Choose this option if you want to use Exynos G2D for DRM.
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index 9e0bff8badf9..eb651ca8e2a8 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -8,10 +8,12 @@ exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.o \
exynos_drm_buf.o exynos_drm_gem.o exynos_drm_core.o \
exynos_drm_plane.o
+exynosdrm-$(CONFIG_DRM_EXYNOS_DMABUF) += exynos_drm_dmabuf.o
exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o \
exynos_ddc.o exynos_hdmiphy.o \
exynos_drm_hdmi.o
exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI) += exynos_drm_vidi.o
+exynosdrm-$(CONFIG_DRM_EXYNOS_G2D) += exynos_drm_g2d.o
obj-$(CONFIG_DRM_EXYNOS) += exynosdrm.o
diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.c b/drivers/gpu/drm/exynos/exynos_drm_buf.c
index de8d2090bce3..b3cb0a69fbf2 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_buf.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_buf.c
@@ -35,7 +35,7 @@ static int lowlevel_buffer_allocate(struct drm_device *dev,
unsigned int flags, struct exynos_drm_gem_buf *buf)
{
dma_addr_t start_addr;
- unsigned int npages, page_size, i = 0;
+ unsigned int npages, i = 0;
struct scatterlist *sgl;
int ret = 0;
@@ -53,13 +53,13 @@ static int lowlevel_buffer_allocate(struct drm_device *dev,
if (buf->size >= SZ_1M) {
npages = buf->size >> SECTION_SHIFT;
- page_size = SECTION_SIZE;
+ buf->page_size = SECTION_SIZE;
} else if (buf->size >= SZ_64K) {
npages = buf->size >> 16;
- page_size = SZ_64K;
+ buf->page_size = SZ_64K;
} else {
npages = buf->size >> PAGE_SHIFT;
- page_size = PAGE_SIZE;
+ buf->page_size = PAGE_SIZE;
}
buf->sgt = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
@@ -96,9 +96,9 @@ static int lowlevel_buffer_allocate(struct drm_device *dev,
while (i < npages) {
buf->pages[i] = phys_to_page(start_addr);
- sg_set_page(sgl, buf->pages[i], page_size, 0);
+ sg_set_page(sgl, buf->pages[i], buf->page_size, 0);
sg_dma_address(sgl) = start_addr;
- start_addr += page_size;
+ start_addr += buf->page_size;
sgl = sg_next(sgl);
i++;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 3486ffed0bf0..4afb625128d7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -105,6 +105,8 @@ int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay,
overlay->fb_y = pos->fb_y;
overlay->fb_width = fb->width;
overlay->fb_height = fb->height;
+ overlay->src_width = pos->src_w;
+ overlay->src_height = pos->src_h;
overlay->bpp = fb->bits_per_pixel;
overlay->pitch = fb->pitches[0];
overlay->pixel_format = fb->pixel_format;
@@ -153,6 +155,8 @@ static int exynos_drm_crtc_update(struct drm_crtc *crtc)
pos.crtc_y = 0;
pos.crtc_w = fb->width - crtc->x;
pos.crtc_h = fb->height - crtc->y;
+ pos.src_w = pos.crtc_w;
+ pos.src_h = pos.crtc_h;
return exynos_drm_overlay_update(overlay, crtc->fb, mode, &pos);
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
index 25f72a62cb88..16b8e2195a0d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
@@ -42,6 +42,8 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc);
* - the unit is screen coordinates.
* @fb_y: offset y on a framebuffer to be displayed
* - the unit is screen coordinates.
+ * @src_w: width of source area to be displayed from a framebuffer.
+ * @src_h: height of source area to be displayed from a framebuffer.
* @crtc_x: offset x on hardware screen.
* @crtc_y: offset y on hardware screen.
* @crtc_w: width of hardware screen.
@@ -50,6 +52,8 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc);
struct exynos_drm_crtc_pos {
unsigned int fb_x;
unsigned int fb_y;
+ unsigned int src_w;
+ unsigned int src_h;
unsigned int crtc_x;
unsigned int crtc_y;
unsigned int crtc_w;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
new file mode 100644
index 000000000000..274909271c36
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
@@ -0,0 +1,272 @@
+/* exynos_drm_dmabuf.c
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * Author: Inki Dae <inki.dae@samsung.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "exynos_drm_drv.h"
+#include "exynos_drm_gem.h"
+
+#include <linux/dma-buf.h>
+
+static struct sg_table *exynos_pages_to_sg(struct page **pages, int nr_pages,
+ unsigned int page_size)
+{
+ struct sg_table *sgt = NULL;
+ struct scatterlist *sgl;
+ int i, ret;
+
+ sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
+ if (!sgt)
+ goto out;
+
+ ret = sg_alloc_table(sgt, nr_pages, GFP_KERNEL);
+ if (ret)
+ goto err_free_sgt;
+
+ if (page_size < PAGE_SIZE)
+ page_size = PAGE_SIZE;
+
+ for_each_sg(sgt->sgl, sgl, nr_pages, i)
+ sg_set_page(sgl, pages[i], page_size, 0);
+
+ return sgt;
+
+err_free_sgt:
+ kfree(sgt);
+ sgt = NULL;
+out:
+ return NULL;
+}
+
+static struct sg_table *
+ exynos_gem_map_dma_buf(struct dma_buf_attachment *attach,
+ enum dma_data_direction dir)
+{
+ struct exynos_drm_gem_obj *gem_obj = attach->dmabuf->priv;
+ struct drm_device *dev = gem_obj->base.dev;
+ struct exynos_drm_gem_buf *buf;
+ struct sg_table *sgt = NULL;
+ unsigned int npages;
+ int nents;
+
+ DRM_DEBUG_PRIME("%s\n", __FILE__);
+
+ mutex_lock(&dev->struct_mutex);
+
+ buf = gem_obj->buffer;
+
+ /* there should always be pages allocated. */
+ if (!buf->pages) {
+ DRM_ERROR("pages is null.\n");
+ goto err_unlock;
+ }
+
+ npages = buf->size / buf->page_size;
+
+ sgt = exynos_pages_to_sg(buf->pages, npages, buf->page_size);
+ nents = dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir);
+
+ DRM_DEBUG_PRIME("npages = %d buffer size = 0x%lx page_size = 0x%lx\n",
+ npages, buf->size, buf->page_size);
+
+err_unlock:
+ mutex_unlock(&dev->struct_mutex);
+ return sgt;
+}
+
+static void exynos_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
+ struct sg_table *sgt,
+ enum dma_data_direction dir)
+{
+ dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, dir);
+ sg_free_table(sgt);
+ kfree(sgt);
+ sgt = NULL;
+}
+
+static void exynos_dmabuf_release(struct dma_buf *dmabuf)
+{
+ struct exynos_drm_gem_obj *exynos_gem_obj = dmabuf->priv;
+
+ DRM_DEBUG_PRIME("%s\n", __FILE__);
+
+ /*
+ * exynos_dmabuf_release() call means that file object's
+ * f_count is 0 and it calls drm_gem_object_handle_unreference()
+ * to drop the references that these values had been increased
+ * at drm_prime_handle_to_fd()
+ */
+ if (exynos_gem_obj->base.export_dma_buf == dmabuf) {
+ exynos_gem_obj->base.export_dma_buf = NULL;
+
+ /*
+ * drop this gem object refcount to release allocated buffer
+ * and resources.
+ */
+ drm_gem_object_unreference_unlocked(&exynos_gem_obj->base);
+ }
+}
+
+static void *exynos_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf,
+ unsigned long page_num)
+{
+ /* TODO */
+
+ return NULL;
+}
+
+static void exynos_gem_dmabuf_kunmap_atomic(struct dma_buf *dma_buf,
+ unsigned long page_num,
+ void *addr)
+{
+ /* TODO */
+}
+
+static void *exynos_gem_dmabuf_kmap(struct dma_buf *dma_buf,
+ unsigned long page_num)
+{
+ /* TODO */
+
+ return NULL;
+}
+
+static void exynos_gem_dmabuf_kunmap(struct dma_buf *dma_buf,
+ unsigned long page_num, void *addr)
+{
+ /* TODO */
+}
+
+static struct dma_buf_ops exynos_dmabuf_ops = {
+ .map_dma_buf = exynos_gem_map_dma_buf,
+ .unmap_dma_buf = exynos_gem_unmap_dma_buf,
+ .kmap = exynos_gem_dmabuf_kmap,
+ .kmap_atomic = exynos_gem_dmabuf_kmap_atomic,
+ .kunmap = exynos_gem_dmabuf_kunmap,
+ .kunmap_atomic = exynos_gem_dmabuf_kunmap_atomic,
+ .release = exynos_dmabuf_release,
+};
+
+struct dma_buf *exynos_dmabuf_prime_export(struct drm_device *drm_dev,
+ struct drm_gem_object *obj, int flags)
+{
+ struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj);
+
+ return dma_buf_export(exynos_gem_obj, &exynos_dmabuf_ops,
+ exynos_gem_obj->base.size, 0600);
+}
+
+struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
+ struct dma_buf *dma_buf)
+{
+ struct dma_buf_attachment *attach;
+ struct sg_table *sgt;
+ struct scatterlist *sgl;
+ struct exynos_drm_gem_obj *exynos_gem_obj;
+ struct exynos_drm_gem_buf *buffer;
+ struct page *page;
+ int ret, i = 0;
+
+ DRM_DEBUG_PRIME("%s\n", __FILE__);
+
+ /* is this one of own objects? */
+ if (dma_buf->ops == &exynos_dmabuf_ops) {
+ struct drm_gem_object *obj;
+
+ exynos_gem_obj = dma_buf->priv;
+ obj = &exynos_gem_obj->base;
+
+ /* is it from our device? */
+ if (obj->dev == drm_dev) {
+ drm_gem_object_reference(obj);
+ return obj;
+ }
+ }
+
+ attach = dma_buf_attach(dma_buf, drm_dev->dev);
+ if (IS_ERR(attach))
+ return ERR_PTR(-EINVAL);
+
+
+ sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+ if (IS_ERR(sgt)) {
+ ret = PTR_ERR(sgt);
+ goto err_buf_detach;
+ }
+
+ buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
+ if (!buffer) {
+ DRM_ERROR("failed to allocate exynos_drm_gem_buf.\n");
+ ret = -ENOMEM;
+ goto err_unmap_attach;
+ }
+
+ buffer->pages = kzalloc(sizeof(*page) * sgt->nents, GFP_KERNEL);
+ if (!buffer->pages) {
+ DRM_ERROR("failed to allocate pages.\n");
+ ret = -ENOMEM;
+ goto err_free_buffer;
+ }
+
+ exynos_gem_obj = exynos_drm_gem_init(drm_dev, dma_buf->size);
+ if (!exynos_gem_obj) {
+ ret = -ENOMEM;
+ goto err_free_pages;
+ }
+
+ sgl = sgt->sgl;
+ buffer->dma_addr = sg_dma_address(sgl);
+
+ while (i < sgt->nents) {
+ buffer->pages[i] = sg_page(sgl);
+ buffer->size += sg_dma_len(sgl);
+ sgl = sg_next(sgl);
+ i++;
+ }
+
+ exynos_gem_obj->buffer = buffer;
+ buffer->sgt = sgt;
+ exynos_gem_obj->base.import_attach = attach;
+
+ DRM_DEBUG_PRIME("dma_addr = 0x%x, size = 0x%lx\n", buffer->dma_addr,
+ buffer->size);
+
+ return &exynos_gem_obj->base;
+
+err_free_pages:
+ kfree(buffer->pages);
+ buffer->pages = NULL;
+err_free_buffer:
+ kfree(buffer);
+ buffer = NULL;
+err_unmap_attach:
+ dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
+err_buf_detach:
+ dma_buf_detach(dma_buf, attach);
+ return ERR_PTR(ret);
+}
+
+MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
+MODULE_DESCRIPTION("Samsung SoC DRM DMABUF Module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.h b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.h
new file mode 100644
index 000000000000..662a8f98ccdb
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.h
@@ -0,0 +1,39 @@
+/* exynos_drm_dmabuf.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * Author: Inki Dae <inki.dae@samsung.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _EXYNOS_DRM_DMABUF_H_
+#define _EXYNOS_DRM_DMABUF_H_
+
+#ifdef CONFIG_DRM_EXYNOS_DMABUF
+struct dma_buf *exynos_dmabuf_prime_export(struct drm_device *drm_dev,
+ struct drm_gem_object *obj, int flags);
+
+struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
+ struct dma_buf *dma_buf);
+#else
+#define exynos_dmabuf_prime_export NULL
+#define exynos_dmabuf_prime_import NULL
+#endif
+#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index a6819b5f8428..420953197d0a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -39,6 +39,8 @@
#include "exynos_drm_gem.h"
#include "exynos_drm_plane.h"
#include "exynos_drm_vidi.h"
+#include "exynos_drm_dmabuf.h"
+#include "exynos_drm_g2d.h"
#define DRIVER_NAME "exynos"
#define DRIVER_DESC "Samsung SoC DRM"
@@ -147,8 +149,17 @@ static int exynos_drm_unload(struct drm_device *dev)
static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
{
+ struct drm_exynos_file_private *file_priv;
+
DRM_DEBUG_DRIVER("%s\n", __FILE__);
+ file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
+ if (!file_priv)
+ return -ENOMEM;
+
+ drm_prime_init_file_private(&file->prime);
+ file->driver_priv = file_priv;
+
return exynos_drm_subdrv_open(dev, file);
}
@@ -170,6 +181,7 @@ static void exynos_drm_preclose(struct drm_device *dev,
e->base.destroy(&e->base);
}
}
+ drm_prime_destroy_file_private(&file->prime);
spin_unlock_irqrestore(&dev->event_lock, flags);
exynos_drm_subdrv_close(dev, file);
@@ -193,7 +205,7 @@ static void exynos_drm_lastclose(struct drm_device *dev)
exynos_drm_fbdev_restore_mode(dev);
}
-static struct vm_operations_struct exynos_drm_gem_vm_ops = {
+static const struct vm_operations_struct exynos_drm_gem_vm_ops = {
.fault = exynos_drm_gem_fault,
.open = drm_gem_vm_open,
.close = drm_gem_vm_close,
@@ -207,10 +219,18 @@ static struct drm_ioctl_desc exynos_ioctls[] = {
DRM_AUTH),
DRM_IOCTL_DEF_DRV(EXYNOS_GEM_MMAP,
exynos_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET,
+ exynos_drm_gem_get_ioctl, DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(EXYNOS_PLANE_SET_ZPOS, exynos_plane_set_zpos_ioctl,
DRM_UNLOCKED | DRM_AUTH),
DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION,
vidi_connection_ioctl, DRM_UNLOCKED | DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(EXYNOS_G2D_GET_VER,
+ exynos_g2d_get_ver_ioctl, DRM_UNLOCKED | DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(EXYNOS_G2D_SET_CMDLIST,
+ exynos_g2d_set_cmdlist_ioctl, DRM_UNLOCKED | DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(EXYNOS_G2D_EXEC,
+ exynos_g2d_exec_ioctl, DRM_UNLOCKED | DRM_AUTH),
};
static const struct file_operations exynos_drm_driver_fops = {
@@ -225,7 +245,7 @@ static const struct file_operations exynos_drm_driver_fops = {
static struct drm_driver exynos_drm_driver = {
.driver_features = DRIVER_HAVE_IRQ | DRIVER_BUS_PLATFORM |
- DRIVER_MODESET | DRIVER_GEM,
+ DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
.load = exynos_drm_load,
.unload = exynos_drm_unload,
.open = exynos_drm_open,
@@ -241,6 +261,10 @@ static struct drm_driver exynos_drm_driver = {
.dumb_create = exynos_drm_gem_dumb_create,
.dumb_map_offset = exynos_drm_gem_dumb_map_offset,
.dumb_destroy = exynos_drm_gem_dumb_destroy,
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_export = exynos_dmabuf_prime_export,
+ .gem_prime_import = exynos_dmabuf_prime_import,
.ioctls = exynos_ioctls,
.fops = &exynos_drm_driver_fops,
.name = DRIVER_NAME,
@@ -307,6 +331,12 @@ static int __init exynos_drm_init(void)
goto out_vidi;
#endif
+#ifdef CONFIG_DRM_EXYNOS_G2D
+ ret = platform_driver_register(&g2d_driver);
+ if (ret < 0)
+ goto out_g2d;
+#endif
+
ret = platform_driver_register(&exynos_drm_platform_driver);
if (ret < 0)
goto out;
@@ -314,6 +344,11 @@ static int __init exynos_drm_init(void)
return 0;
out:
+#ifdef CONFIG_DRM_EXYNOS_G2D
+ platform_driver_unregister(&g2d_driver);
+out_g2d:
+#endif
+
#ifdef CONFIG_DRM_EXYNOS_VIDI
out_vidi:
platform_driver_unregister(&vidi_driver);
@@ -341,6 +376,10 @@ static void __exit exynos_drm_exit(void)
platform_driver_unregister(&exynos_drm_platform_driver);
+#ifdef CONFIG_DRM_EXYNOS_G2D
+ platform_driver_unregister(&g2d_driver);
+#endif
+
#ifdef CONFIG_DRM_EXYNOS_HDMI
platform_driver_unregister(&exynos_drm_common_hdmi_driver);
platform_driver_unregister(&mixer_driver);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 1d814175cd49..c82c90c443e7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -77,6 +77,8 @@ struct exynos_drm_overlay_ops {
* - the unit is screen coordinates.
* @fb_width: width of a framebuffer.
* @fb_height: height of a framebuffer.
+ * @src_width: width of a partial image to be displayed from framebuffer.
+ * @src_height: height of a partial image to be displayed from framebuffer.
* @crtc_x: offset x on hardware screen.
* @crtc_y: offset y on hardware screen.
* @crtc_width: window width to be displayed (hardware screen).
@@ -108,6 +110,8 @@ struct exynos_drm_overlay {
unsigned int fb_y;
unsigned int fb_width;
unsigned int fb_height;
+ unsigned int src_width;
+ unsigned int src_height;
unsigned int crtc_x;
unsigned int crtc_y;
unsigned int crtc_width;
@@ -205,6 +209,18 @@ struct exynos_drm_manager {
struct exynos_drm_display_ops *display_ops;
};
+struct exynos_drm_g2d_private {
+ struct device *dev;
+ struct list_head inuse_cmdlist;
+ struct list_head event_list;
+ struct list_head gem_list;
+ unsigned int gem_nr;
+};
+
+struct drm_exynos_file_private {
+ struct exynos_drm_g2d_private *g2d_priv;
+};
+
/*
* Exynos drm private structure.
*/
@@ -287,4 +303,5 @@ extern struct platform_driver hdmi_driver;
extern struct platform_driver mixer_driver;
extern struct platform_driver exynos_drm_common_hdmi_driver;
extern struct platform_driver vidi_driver;
+extern struct platform_driver g2d_driver;
#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index c38c8f468fa3..f82a299553fb 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -191,7 +191,7 @@ static void exynos_drm_output_poll_changed(struct drm_device *dev)
drm_fb_helper_hotplug_event(fb_helper);
}
-static struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
+static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
.fb_create = exynos_user_fb_create,
.output_poll_changed = exynos_drm_output_poll_changed,
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
new file mode 100644
index 000000000000..d2d88f22a037
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -0,0 +1,937 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ * Authors: Joonyoung Shim <jy0922.shim@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 Foundationr
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+
+#include "drmP.h"
+#include "exynos_drm.h"
+#include "exynos_drm_drv.h"
+#include "exynos_drm_gem.h"
+
+#define G2D_HW_MAJOR_VER 4
+#define G2D_HW_MINOR_VER 1
+
+/* vaild register range set from user: 0x0104 ~ 0x0880 */
+#define G2D_VALID_START 0x0104
+#define G2D_VALID_END 0x0880
+
+/* general registers */
+#define G2D_SOFT_RESET 0x0000
+#define G2D_INTEN 0x0004
+#define G2D_INTC_PEND 0x000C
+#define G2D_DMA_SFR_BASE_ADDR 0x0080
+#define G2D_DMA_COMMAND 0x0084
+#define G2D_DMA_STATUS 0x008C
+#define G2D_DMA_HOLD_CMD 0x0090
+
+/* command registers */
+#define G2D_BITBLT_START 0x0100
+
+/* registers for base address */
+#define G2D_SRC_BASE_ADDR 0x0304
+#define G2D_SRC_PLANE2_BASE_ADDR 0x0318
+#define G2D_DST_BASE_ADDR 0x0404
+#define G2D_DST_PLANE2_BASE_ADDR 0x0418
+#define G2D_PAT_BASE_ADDR 0x0500
+#define G2D_MSK_BASE_ADDR 0x0520
+
+/* G2D_SOFT_RESET */
+#define G2D_SFRCLEAR (1 << 1)
+#define G2D_R (1 << 0)
+
+/* G2D_INTEN */
+#define G2D_INTEN_ACF (1 << 3)
+#define G2D_INTEN_UCF (1 << 2)
+#define G2D_INTEN_GCF (1 << 1)
+#define G2D_INTEN_SCF (1 << 0)
+
+/* G2D_INTC_PEND */
+#define G2D_INTP_ACMD_FIN (1 << 3)
+#define G2D_INTP_UCMD_FIN (1 << 2)
+#define G2D_INTP_GCMD_FIN (1 << 1)
+#define G2D_INTP_SCMD_FIN (1 << 0)
+
+/* G2D_DMA_COMMAND */
+#define G2D_DMA_HALT (1 << 2)
+#define G2D_DMA_CONTINUE (1 << 1)
+#define G2D_DMA_START (1 << 0)
+
+/* G2D_DMA_STATUS */
+#define G2D_DMA_LIST_DONE_COUNT (0xFF << 17)
+#define G2D_DMA_BITBLT_DONE_COUNT (0xFFFF << 1)
+#define G2D_DMA_DONE (1 << 0)
+#define G2D_DMA_LIST_DONE_COUNT_OFFSET 17
+
+/* G2D_DMA_HOLD_CMD */
+#define G2D_USET_HOLD (1 << 2)
+#define G2D_LIST_HOLD (1 << 1)
+#define G2D_BITBLT_HOLD (1 << 0)
+
+/* G2D_BITBLT_START */
+#define G2D_START_CASESEL (1 << 2)
+#define G2D_START_NHOLT (1 << 1)
+#define G2D_START_BITBLT (1 << 0)
+
+#define G2D_CMDLIST_SIZE (PAGE_SIZE / 4)
+#define G2D_CMDLIST_NUM 64
+#define G2D_CMDLIST_POOL_SIZE (G2D_CMDLIST_SIZE * G2D_CMDLIST_NUM)
+#define G2D_CMDLIST_DATA_NUM (G2D_CMDLIST_SIZE / sizeof(u32) - 2)
+
+/* cmdlist data structure */
+struct g2d_cmdlist {
+ u32 head;
+ u32 data[G2D_CMDLIST_DATA_NUM];
+ u32 last; /* last data offset */
+};
+
+struct drm_exynos_pending_g2d_event {
+ struct drm_pending_event base;
+ struct drm_exynos_g2d_event event;
+};
+
+struct g2d_gem_node {
+ struct list_head list;
+ unsigned int handle;
+};
+
+struct g2d_cmdlist_node {
+ struct list_head list;
+ struct g2d_cmdlist *cmdlist;
+ unsigned int gem_nr;
+ dma_addr_t dma_addr;
+
+ struct drm_exynos_pending_g2d_event *event;
+};
+
+struct g2d_runqueue_node {
+ struct list_head list;
+ struct list_head run_cmdlist;
+ struct list_head event_list;
+ struct completion complete;
+ int async;
+};
+
+struct g2d_data {
+ struct device *dev;
+ struct clk *gate_clk;
+ struct resource *regs_res;
+ void __iomem *regs;
+ int irq;
+ struct workqueue_struct *g2d_workq;
+ struct work_struct runqueue_work;
+ struct exynos_drm_subdrv subdrv;
+ bool suspended;
+
+ /* cmdlist */
+ struct g2d_cmdlist_node *cmdlist_node;
+ struct list_head free_cmdlist;
+ struct mutex cmdlist_mutex;
+ dma_addr_t cmdlist_pool;
+ void *cmdlist_pool_virt;
+
+ /* runqueue*/
+ struct g2d_runqueue_node *runqueue_node;
+ struct list_head runqueue;
+ struct mutex runqueue_mutex;
+ struct kmem_cache *runqueue_slab;
+};
+
+static int g2d_init_cmdlist(struct g2d_data *g2d)
+{
+ struct device *dev = g2d->dev;
+ struct g2d_cmdlist_node *node = g2d->cmdlist_node;
+ int nr;
+ int ret;
+
+ g2d->cmdlist_pool_virt = dma_alloc_coherent(dev, G2D_CMDLIST_POOL_SIZE,
+ &g2d->cmdlist_pool, GFP_KERNEL);
+ if (!g2d->cmdlist_pool_virt) {
+ dev_err(dev, "failed to allocate dma memory\n");
+ return -ENOMEM;
+ }
+
+ node = kcalloc(G2D_CMDLIST_NUM, G2D_CMDLIST_NUM * sizeof(*node),
+ GFP_KERNEL);
+ if (!node) {
+ dev_err(dev, "failed to allocate memory\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (nr = 0; nr < G2D_CMDLIST_NUM; nr++) {
+ node[nr].cmdlist =
+ g2d->cmdlist_pool_virt + nr * G2D_CMDLIST_SIZE;
+ node[nr].dma_addr =
+ g2d->cmdlist_pool + nr * G2D_CMDLIST_SIZE;
+
+ list_add_tail(&node[nr].list, &g2d->free_cmdlist);
+ }
+
+ return 0;
+
+err:
+ dma_free_coherent(dev, G2D_CMDLIST_POOL_SIZE, g2d->cmdlist_pool_virt,
+ g2d->cmdlist_pool);
+ return ret;
+}
+
+static void g2d_fini_cmdlist(struct g2d_data *g2d)
+{
+ struct device *dev = g2d->dev;
+
+ kfree(g2d->cmdlist_node);
+ dma_free_coherent(dev, G2D_CMDLIST_POOL_SIZE, g2d->cmdlist_pool_virt,
+ g2d->cmdlist_pool);
+}
+
+static struct g2d_cmdlist_node *g2d_get_cmdlist(struct g2d_data *g2d)
+{
+ struct device *dev = g2d->dev;
+ struct g2d_cmdlist_node *node;
+
+ mutex_lock(&g2d->cmdlist_mutex);
+ if (list_empty(&g2d->free_cmdlist)) {
+ dev_err(dev, "there is no free cmdlist\n");
+ mutex_unlock(&g2d->cmdlist_mutex);
+ return NULL;
+ }
+
+ node = list_first_entry(&g2d->free_cmdlist, struct g2d_cmdlist_node,
+ list);
+ list_del_init(&node->list);
+ mutex_unlock(&g2d->cmdlist_mutex);
+
+ return node;
+}
+
+static void g2d_put_cmdlist(struct g2d_data *g2d, struct g2d_cmdlist_node *node)
+{
+ mutex_lock(&g2d->cmdlist_mutex);
+ list_move_tail(&node->list, &g2d->free_cmdlist);
+ mutex_unlock(&g2d->cmdlist_mutex);
+}
+
+static void g2d_add_cmdlist_to_inuse(struct exynos_drm_g2d_private *g2d_priv,
+ struct g2d_cmdlist_node *node)
+{
+ struct g2d_cmdlist_node *lnode;
+
+ if (list_empty(&g2d_priv->inuse_cmdlist))
+ goto add_to_list;
+
+ /* this links to base address of new cmdlist */
+ lnode = list_entry(g2d_priv->inuse_cmdlist.prev,
+ struct g2d_cmdlist_node, list);
+ lnode->cmdlist->data[lnode->cmdlist->last] = node->dma_addr;
+
+add_to_list:
+ list_add_tail(&node->list, &g2d_priv->inuse_cmdlist);
+
+ if (node->event)
+ list_add_tail(&node->event->base.link, &g2d_priv->event_list);
+}
+
+static int g2d_get_cmdlist_gem(struct drm_device *drm_dev,
+ struct drm_file *file,
+ struct g2d_cmdlist_node *node)
+{
+ struct drm_exynos_file_private *file_priv = file->driver_priv;
+ struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
+ struct g2d_cmdlist *cmdlist = node->cmdlist;
+ dma_addr_t *addr;
+ int offset;
+ int i;
+
+ for (i = 0; i < node->gem_nr; i++) {
+ struct g2d_gem_node *gem_node;
+
+ gem_node = kzalloc(sizeof(*gem_node), GFP_KERNEL);
+ if (!gem_node) {
+ dev_err(g2d_priv->dev, "failed to allocate gem node\n");
+ return -ENOMEM;
+ }
+
+ offset = cmdlist->last - (i * 2 + 1);
+ gem_node->handle = cmdlist->data[offset];
+
+ addr = exynos_drm_gem_get_dma_addr(drm_dev, gem_node->handle,
+ file);
+ if (IS_ERR(addr)) {
+ node->gem_nr = i;
+ kfree(gem_node);
+ return PTR_ERR(addr);
+ }
+
+ cmdlist->data[offset] = *addr;
+ list_add_tail(&gem_node->list, &g2d_priv->gem_list);
+ g2d_priv->gem_nr++;
+ }
+
+ return 0;
+}
+
+static void g2d_put_cmdlist_gem(struct drm_device *drm_dev,
+ struct drm_file *file,
+ unsigned int nr)
+{
+ struct drm_exynos_file_private *file_priv = file->driver_priv;
+ struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
+ struct g2d_gem_node *node, *n;
+
+ list_for_each_entry_safe_reverse(node, n, &g2d_priv->gem_list, list) {
+ if (!nr)
+ break;
+
+ exynos_drm_gem_put_dma_addr(drm_dev, node->handle, file);
+ list_del_init(&node->list);
+ kfree(node);
+ nr--;
+ }
+}
+
+static void g2d_dma_start(struct g2d_data *g2d,
+ struct g2d_runqueue_node *runqueue_node)
+{
+ struct g2d_cmdlist_node *node =
+ list_first_entry(&runqueue_node->run_cmdlist,
+ struct g2d_cmdlist_node, list);
+
+ pm_runtime_get_sync(g2d->dev);
+ clk_enable(g2d->gate_clk);
+
+ /* interrupt enable */
+ writel_relaxed(G2D_INTEN_ACF | G2D_INTEN_UCF | G2D_INTEN_GCF,
+ g2d->regs + G2D_INTEN);
+
+ writel_relaxed(node->dma_addr, g2d->regs + G2D_DMA_SFR_BASE_ADDR);
+ writel_relaxed(G2D_DMA_START, g2d->regs + G2D_DMA_COMMAND);
+}
+
+static struct g2d_runqueue_node *g2d_get_runqueue_node(struct g2d_data *g2d)
+{
+ struct g2d_runqueue_node *runqueue_node;
+
+ if (list_empty(&g2d->runqueue))
+ return NULL;
+
+ runqueue_node = list_first_entry(&g2d->runqueue,
+ struct g2d_runqueue_node, list);
+ list_del_init(&runqueue_node->list);
+ return runqueue_node;
+}
+
+static void g2d_free_runqueue_node(struct g2d_data *g2d,
+ struct g2d_runqueue_node *runqueue_node)
+{
+ if (!runqueue_node)
+ return;
+
+ mutex_lock(&g2d->cmdlist_mutex);
+ list_splice_tail_init(&runqueue_node->run_cmdlist, &g2d->free_cmdlist);
+ mutex_unlock(&g2d->cmdlist_mutex);
+
+ kmem_cache_free(g2d->runqueue_slab, runqueue_node);
+}
+
+static void g2d_exec_runqueue(struct g2d_data *g2d)
+{
+ g2d->runqueue_node = g2d_get_runqueue_node(g2d);
+ if (g2d->runqueue_node)
+ g2d_dma_start(g2d, g2d->runqueue_node);
+}
+
+static void g2d_runqueue_worker(struct work_struct *work)
+{
+ struct g2d_data *g2d = container_of(work, struct g2d_data,
+ runqueue_work);
+
+
+ mutex_lock(&g2d->runqueue_mutex);
+ clk_disable(g2d->gate_clk);
+ pm_runtime_put_sync(g2d->dev);
+
+ complete(&g2d->runqueue_node->complete);
+ if (g2d->runqueue_node->async)
+ g2d_free_runqueue_node(g2d, g2d->runqueue_node);
+
+ if (g2d->suspended)
+ g2d->runqueue_node = NULL;
+ else
+ g2d_exec_runqueue(g2d);
+ mutex_unlock(&g2d->runqueue_mutex);
+}
+
+static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no)
+{
+ struct drm_device *drm_dev = g2d->subdrv.drm_dev;
+ struct g2d_runqueue_node *runqueue_node = g2d->runqueue_node;
+ struct drm_exynos_pending_g2d_event *e;
+ struct timeval now;
+ unsigned long flags;
+
+ if (list_empty(&runqueue_node->event_list))
+ return;
+
+ e = list_first_entry(&runqueue_node->event_list,
+ struct drm_exynos_pending_g2d_event, base.link);
+
+ do_gettimeofday(&now);
+ e->event.tv_sec = now.tv_sec;
+ e->event.tv_usec = now.tv_usec;
+ e->event.cmdlist_no = cmdlist_no;
+
+ spin_lock_irqsave(&drm_dev->event_lock, flags);
+ list_move_tail(&e->base.link, &e->base.file_priv->event_list);
+ wake_up_interruptible(&e->base.file_priv->event_wait);
+ spin_unlock_irqrestore(&drm_dev->event_lock, flags);
+}
+
+static irqreturn_t g2d_irq_handler(int irq, void *dev_id)
+{
+ struct g2d_data *g2d = dev_id;
+ u32 pending;
+
+ pending = readl_relaxed(g2d->regs + G2D_INTC_PEND);
+ if (pending)
+ writel_relaxed(pending, g2d->regs + G2D_INTC_PEND);
+
+ if (pending & G2D_INTP_GCMD_FIN) {
+ u32 cmdlist_no = readl_relaxed(g2d->regs + G2D_DMA_STATUS);
+
+ cmdlist_no = (cmdlist_no & G2D_DMA_LIST_DONE_COUNT) >>
+ G2D_DMA_LIST_DONE_COUNT_OFFSET;
+
+ g2d_finish_event(g2d, cmdlist_no);
+
+ writel_relaxed(0, g2d->regs + G2D_DMA_HOLD_CMD);
+ if (!(pending & G2D_INTP_ACMD_FIN)) {
+ writel_relaxed(G2D_DMA_CONTINUE,
+ g2d->regs + G2D_DMA_COMMAND);
+ }
+ }
+
+ if (pending & G2D_INTP_ACMD_FIN)
+ queue_work(g2d->g2d_workq, &g2d->runqueue_work);
+
+ return IRQ_HANDLED;
+}
+
+static int g2d_check_reg_offset(struct device *dev, struct g2d_cmdlist *cmdlist,
+ int nr, bool for_addr)
+{
+ int reg_offset;
+ int index;
+ int i;
+
+ for (i = 0; i < nr; i++) {
+ index = cmdlist->last - 2 * (i + 1);
+ reg_offset = cmdlist->data[index] & ~0xfffff000;
+
+ if (reg_offset < G2D_VALID_START || reg_offset > G2D_VALID_END)
+ goto err;
+ if (reg_offset % 4)
+ goto err;
+
+ switch (reg_offset) {
+ case G2D_SRC_BASE_ADDR:
+ case G2D_SRC_PLANE2_BASE_ADDR:
+ case G2D_DST_BASE_ADDR:
+ case G2D_DST_PLANE2_BASE_ADDR:
+ case G2D_PAT_BASE_ADDR:
+ case G2D_MSK_BASE_ADDR:
+ if (!for_addr)
+ goto err;
+ break;
+ default:
+ if (for_addr)
+ goto err;
+ break;
+ }
+ }
+
+ return 0;
+
+err:
+ dev_err(dev, "Bad register offset: 0x%x\n", cmdlist->data[index]);
+ return -EINVAL;
+}
+
+/* ioctl functions */
+int exynos_g2d_get_ver_ioctl(struct drm_device *drm_dev, void *data,
+ struct drm_file *file)
+{
+ struct drm_exynos_g2d_get_ver *ver = data;
+
+ ver->major = G2D_HW_MAJOR_VER;
+ ver->minor = G2D_HW_MINOR_VER;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(exynos_g2d_get_ver_ioctl);
+
+int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
+ struct drm_file *file)
+{
+ struct drm_exynos_file_private *file_priv = file->driver_priv;
+ struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
+ struct device *dev = g2d_priv->dev;
+ struct g2d_data *g2d;
+ struct drm_exynos_g2d_set_cmdlist *req = data;
+ struct drm_exynos_g2d_cmd *cmd;
+ struct drm_exynos_pending_g2d_event *e;
+ struct g2d_cmdlist_node *node;
+ struct g2d_cmdlist *cmdlist;
+ unsigned long flags;
+ int size;
+ int ret;
+
+ if (!dev)
+ return -ENODEV;
+
+ g2d = dev_get_drvdata(dev);
+ if (!g2d)
+ return -EFAULT;
+
+ node = g2d_get_cmdlist(g2d);
+ if (!node)
+ return -ENOMEM;
+
+ node->event = NULL;
+
+ if (req->event_type != G2D_EVENT_NOT) {
+ spin_lock_irqsave(&drm_dev->event_lock, flags);
+ if (file->event_space < sizeof(e->event)) {
+ spin_unlock_irqrestore(&drm_dev->event_lock, flags);
+ ret = -ENOMEM;
+ goto err;
+ }
+ file->event_space -= sizeof(e->event);
+ spin_unlock_irqrestore(&drm_dev->event_lock, flags);
+
+ e = kzalloc(sizeof(*node->event), GFP_KERNEL);
+ if (!e) {
+ dev_err(dev, "failed to allocate event\n");
+
+ spin_lock_irqsave(&drm_dev->event_lock, flags);
+ file->event_space += sizeof(e->event);
+ spin_unlock_irqrestore(&drm_dev->event_lock, flags);
+
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ e->event.base.type = DRM_EXYNOS_G2D_EVENT;
+ e->event.base.length = sizeof(e->event);
+ e->event.user_data = req->user_data;
+ e->base.event = &e->event.base;
+ e->base.file_priv = file;
+ e->base.destroy = (void (*) (struct drm_pending_event *)) kfree;
+
+ node->event = e;
+ }
+
+ cmdlist = node->cmdlist;
+
+ cmdlist->last = 0;
+
+ /*
+ * If don't clear SFR registers, the cmdlist is affected by register
+ * values of previous cmdlist. G2D hw executes SFR clear command and
+ * a next command at the same time then the next command is ignored and
+ * is executed rightly from next next command, so needs a dummy command
+ * to next command of SFR clear command.
+ */
+ cmdlist->data[cmdlist->last++] = G2D_SOFT_RESET;
+ cmdlist->data[cmdlist->last++] = G2D_SFRCLEAR;
+ cmdlist->data[cmdlist->last++] = G2D_SRC_BASE_ADDR;
+ cmdlist->data[cmdlist->last++] = 0;
+
+ if (node->event) {
+ cmdlist->data[cmdlist->last++] = G2D_DMA_HOLD_CMD;
+ cmdlist->data[cmdlist->last++] = G2D_LIST_HOLD;
+ }
+
+ /* Check size of cmdlist: last 2 is about G2D_BITBLT_START */
+ size = cmdlist->last + req->cmd_nr * 2 + req->cmd_gem_nr * 2 + 2;
+ if (size > G2D_CMDLIST_DATA_NUM) {
+ dev_err(dev, "cmdlist size is too big\n");
+ ret = -EINVAL;
+ goto err_free_event;
+ }
+
+ cmd = (struct drm_exynos_g2d_cmd *)(uint32_t)req->cmd;
+
+ if (copy_from_user(cmdlist->data + cmdlist->last,
+ (void __user *)cmd,
+ sizeof(*cmd) * req->cmd_nr)) {
+ ret = -EFAULT;
+ goto err_free_event;
+ }
+ cmdlist->last += req->cmd_nr * 2;
+
+ ret = g2d_check_reg_offset(dev, cmdlist, req->cmd_nr, false);
+ if (ret < 0)
+ goto err_free_event;
+
+ node->gem_nr = req->cmd_gem_nr;
+ if (req->cmd_gem_nr) {
+ struct drm_exynos_g2d_cmd *cmd_gem;
+
+ cmd_gem = (struct drm_exynos_g2d_cmd *)(uint32_t)req->cmd_gem;
+
+ if (copy_from_user(cmdlist->data + cmdlist->last,
+ (void __user *)cmd_gem,
+ sizeof(*cmd_gem) * req->cmd_gem_nr)) {
+ ret = -EFAULT;
+ goto err_free_event;
+ }
+ cmdlist->last += req->cmd_gem_nr * 2;
+
+ ret = g2d_check_reg_offset(dev, cmdlist, req->cmd_gem_nr, true);
+ if (ret < 0)
+ goto err_free_event;
+
+ ret = g2d_get_cmdlist_gem(drm_dev, file, node);
+ if (ret < 0)
+ goto err_unmap;
+ }
+
+ cmdlist->data[cmdlist->last++] = G2D_BITBLT_START;
+ cmdlist->data[cmdlist->last++] = G2D_START_BITBLT;
+
+ /* head */
+ cmdlist->head = cmdlist->last / 2;
+
+ /* tail */
+ cmdlist->data[cmdlist->last] = 0;
+
+ g2d_add_cmdlist_to_inuse(g2d_priv, node);
+
+ return 0;
+
+err_unmap:
+ g2d_put_cmdlist_gem(drm_dev, file, node->gem_nr);
+err_free_event:
+ if (node->event) {
+ spin_lock_irqsave(&drm_dev->event_lock, flags);
+ file->event_space += sizeof(e->event);
+ spin_unlock_irqrestore(&drm_dev->event_lock, flags);
+ kfree(node->event);
+ }
+err:
+ g2d_put_cmdlist(g2d, node);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(exynos_g2d_set_cmdlist_ioctl);
+
+int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data,
+ struct drm_file *file)
+{
+ struct drm_exynos_file_private *file_priv = file->driver_priv;
+ struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
+ struct device *dev = g2d_priv->dev;
+ struct g2d_data *g2d;
+ struct drm_exynos_g2d_exec *req = data;
+ struct g2d_runqueue_node *runqueue_node;
+ struct list_head *run_cmdlist;
+ struct list_head *event_list;
+
+ if (!dev)
+ return -ENODEV;
+
+ g2d = dev_get_drvdata(dev);
+ if (!g2d)
+ return -EFAULT;
+
+ runqueue_node = kmem_cache_alloc(g2d->runqueue_slab, GFP_KERNEL);
+ if (!runqueue_node) {
+ dev_err(dev, "failed to allocate memory\n");
+ return -ENOMEM;
+ }
+ run_cmdlist = &runqueue_node->run_cmdlist;
+ event_list = &runqueue_node->event_list;
+ INIT_LIST_HEAD(run_cmdlist);
+ INIT_LIST_HEAD(event_list);
+ init_completion(&runqueue_node->complete);
+ runqueue_node->async = req->async;
+
+ list_splice_init(&g2d_priv->inuse_cmdlist, run_cmdlist);
+ list_splice_init(&g2d_priv->event_list, event_list);
+
+ if (list_empty(run_cmdlist)) {
+ dev_err(dev, "there is no inuse cmdlist\n");
+ kmem_cache_free(g2d->runqueue_slab, runqueue_node);
+ return -EPERM;
+ }
+
+ mutex_lock(&g2d->runqueue_mutex);
+ list_add_tail(&runqueue_node->list, &g2d->runqueue);
+ if (!g2d->runqueue_node)
+ g2d_exec_runqueue(g2d);
+ mutex_unlock(&g2d->runqueue_mutex);
+
+ if (runqueue_node->async)
+ goto out;
+
+ wait_for_completion(&runqueue_node->complete);
+ g2d_free_runqueue_node(g2d, runqueue_node);
+
+out:
+ return 0;
+}
+EXPORT_SYMBOL_GPL(exynos_g2d_exec_ioctl);
+
+static int g2d_open(struct drm_device *drm_dev, struct device *dev,
+ struct drm_file *file)
+{
+ struct drm_exynos_file_private *file_priv = file->driver_priv;
+ struct exynos_drm_g2d_private *g2d_priv;
+
+ g2d_priv = kzalloc(sizeof(*g2d_priv), GFP_KERNEL);
+ if (!g2d_priv) {
+ dev_err(dev, "failed to allocate g2d private data\n");
+ return -ENOMEM;
+ }
+
+ g2d_priv->dev = dev;
+ file_priv->g2d_priv = g2d_priv;
+
+ INIT_LIST_HEAD(&g2d_priv->inuse_cmdlist);
+ INIT_LIST_HEAD(&g2d_priv->event_list);
+ INIT_LIST_HEAD(&g2d_priv->gem_list);
+
+ return 0;
+}
+
+static void g2d_close(struct drm_device *drm_dev, struct device *dev,
+ struct drm_file *file)
+{
+ struct drm_exynos_file_private *file_priv = file->driver_priv;
+ struct exynos_drm_g2d_private *g2d_priv = file_priv->g2d_priv;
+ struct g2d_data *g2d;
+ struct g2d_cmdlist_node *node, *n;
+
+ if (!dev)
+ return;
+
+ g2d = dev_get_drvdata(dev);
+ if (!g2d)
+ return;
+
+ mutex_lock(&g2d->cmdlist_mutex);
+ list_for_each_entry_safe(node, n, &g2d_priv->inuse_cmdlist, list)
+ list_move_tail(&node->list, &g2d->free_cmdlist);
+ mutex_unlock(&g2d->cmdlist_mutex);
+
+ g2d_put_cmdlist_gem(drm_dev, file, g2d_priv->gem_nr);
+
+ kfree(file_priv->g2d_priv);
+}
+
+static int __devinit g2d_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct g2d_data *g2d;
+ struct exynos_drm_subdrv *subdrv;
+ int ret;
+
+ g2d = kzalloc(sizeof(*g2d), GFP_KERNEL);
+ if (!g2d) {
+ dev_err(dev, "failed to allocate driver data\n");
+ return -ENOMEM;
+ }
+
+ g2d->runqueue_slab = kmem_cache_create("g2d_runqueue_slab",
+ sizeof(struct g2d_runqueue_node), 0, 0, NULL);
+ if (!g2d->runqueue_slab) {
+ ret = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ g2d->dev = dev;
+
+ g2d->g2d_workq = create_singlethread_workqueue("g2d");
+ if (!g2d->g2d_workq) {
+ dev_err(dev, "failed to create workqueue\n");
+ ret = -EINVAL;
+ goto err_destroy_slab;
+ }
+
+ INIT_WORK(&g2d->runqueue_work, g2d_runqueue_worker);
+ INIT_LIST_HEAD(&g2d->free_cmdlist);
+ INIT_LIST_HEAD(&g2d->runqueue);
+
+ mutex_init(&g2d->cmdlist_mutex);
+ mutex_init(&g2d->runqueue_mutex);
+
+ ret = g2d_init_cmdlist(g2d);
+ if (ret < 0)
+ goto err_destroy_workqueue;
+
+ g2d->gate_clk = clk_get(dev, "fimg2d");
+ if (IS_ERR(g2d->gate_clk)) {
+ dev_err(dev, "failed to get gate clock\n");
+ ret = PTR_ERR(g2d->gate_clk);
+ goto err_fini_cmdlist;
+ }
+
+ pm_runtime_enable(dev);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "failed to get I/O memory\n");
+ ret = -ENOENT;
+ goto err_put_clk;
+ }
+
+ g2d->regs_res = request_mem_region(res->start, resource_size(res),
+ dev_name(dev));
+ if (!g2d->regs_res) {
+ dev_err(dev, "failed to request I/O memory\n");
+ ret = -ENOENT;
+ goto err_put_clk;
+ }
+
+ g2d->regs = ioremap(res->start, resource_size(res));
+ if (!g2d->regs) {
+ dev_err(dev, "failed to remap I/O memory\n");
+ ret = -ENXIO;
+ goto err_release_res;
+ }
+
+ g2d->irq = platform_get_irq(pdev, 0);
+ if (g2d->irq < 0) {
+ dev_err(dev, "failed to get irq\n");
+ ret = g2d->irq;
+ goto err_unmap_base;
+ }
+
+ ret = request_irq(g2d->irq, g2d_irq_handler, 0, "drm_g2d", g2d);
+ if (ret < 0) {
+ dev_err(dev, "irq request failed\n");
+ goto err_unmap_base;
+ }
+
+ platform_set_drvdata(pdev, g2d);
+
+ subdrv = &g2d->subdrv;
+ subdrv->dev = dev;
+ subdrv->open = g2d_open;
+ subdrv->close = g2d_close;
+
+ ret = exynos_drm_subdrv_register(subdrv);
+ if (ret < 0) {
+ dev_err(dev, "failed to register drm g2d device\n");
+ goto err_free_irq;
+ }
+
+ dev_info(dev, "The exynos g2d(ver %d.%d) successfully probed\n",
+ G2D_HW_MAJOR_VER, G2D_HW_MINOR_VER);
+
+ return 0;
+
+err_free_irq:
+ free_irq(g2d->irq, g2d);
+err_unmap_base:
+ iounmap(g2d->regs);
+err_release_res:
+ release_resource(g2d->regs_res);
+ kfree(g2d->regs_res);
+err_put_clk:
+ pm_runtime_disable(dev);
+ clk_put(g2d->gate_clk);
+err_fini_cmdlist:
+ g2d_fini_cmdlist(g2d);
+err_destroy_workqueue:
+ destroy_workqueue(g2d->g2d_workq);
+err_destroy_slab:
+ kmem_cache_destroy(g2d->runqueue_slab);
+err_free_mem:
+ kfree(g2d);
+ return ret;
+}
+
+static int __devexit g2d_remove(struct platform_device *pdev)
+{
+ struct g2d_data *g2d = platform_get_drvdata(pdev);
+
+ cancel_work_sync(&g2d->runqueue_work);
+ exynos_drm_subdrv_unregister(&g2d->subdrv);
+ free_irq(g2d->irq, g2d);
+
+ while (g2d->runqueue_node) {
+ g2d_free_runqueue_node(g2d, g2d->runqueue_node);
+ g2d->runqueue_node = g2d_get_runqueue_node(g2d);
+ }
+
+ iounmap(g2d->regs);
+ release_resource(g2d->regs_res);
+ kfree(g2d->regs_res);
+
+ pm_runtime_disable(&pdev->dev);
+ clk_put(g2d->gate_clk);
+
+ g2d_fini_cmdlist(g2d);
+ destroy_workqueue(g2d->g2d_workq);
+ kmem_cache_destroy(g2d->runqueue_slab);
+ kfree(g2d);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int g2d_suspend(struct device *dev)
+{
+ struct g2d_data *g2d = dev_get_drvdata(dev);
+
+ mutex_lock(&g2d->runqueue_mutex);
+ g2d->suspended = true;
+ mutex_unlock(&g2d->runqueue_mutex);
+
+ while (g2d->runqueue_node)
+ /* FIXME: good range? */
+ usleep_range(500, 1000);
+
+ flush_work_sync(&g2d->runqueue_work);
+
+ return 0;
+}
+
+static int g2d_resume(struct device *dev)
+{
+ struct g2d_data *g2d = dev_get_drvdata(dev);
+
+ g2d->suspended = false;
+ g2d_exec_runqueue(g2d);
+
+ return 0;
+}
+#endif
+
+SIMPLE_DEV_PM_OPS(g2d_pm_ops, g2d_suspend, g2d_resume);
+
+struct platform_driver g2d_driver = {
+ .probe = g2d_probe,
+ .remove = __devexit_p(g2d_remove),
+ .driver = {
+ .name = "s5p-g2d",
+ .owner = THIS_MODULE,
+ .pm = &g2d_pm_ops,
+ },
+};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.h b/drivers/gpu/drm/exynos/exynos_drm_g2d.h
new file mode 100644
index 000000000000..1a9c7ca8c15b
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co.Ltd
+ * Authors: Joonyoung Shim <jy0922.shim@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 Foundationr
+ */
+
+#ifdef CONFIG_DRM_EXYNOS_G2D
+extern int exynos_g2d_get_ver_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int exynos_g2d_set_cmdlist_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int exynos_g2d_exec_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+#else
+static inline int exynos_g2d_get_ver_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ return -ENODEV;
+}
+
+static inline int exynos_g2d_set_cmdlist_ioctl(struct drm_device *dev,
+ void *data,
+ struct drm_file *file_priv)
+{
+ return -ENODEV;
+}
+
+static inline int exynos_g2d_exec_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ return -ENODEV;
+}
+#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index 1dffa8359f88..fc91293c4560 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -66,6 +66,22 @@ static int check_gem_flags(unsigned int flags)
return 0;
}
+static void update_vm_cache_attr(struct exynos_drm_gem_obj *obj,
+ struct vm_area_struct *vma)
+{
+ DRM_DEBUG_KMS("flags = 0x%x\n", obj->flags);
+
+ /* non-cachable as default. */
+ if (obj->flags & EXYNOS_BO_CACHABLE)
+ vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+ else if (obj->flags & EXYNOS_BO_WC)
+ vma->vm_page_prot =
+ pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+ else
+ vma->vm_page_prot =
+ pgprot_noncached(vm_get_page_prot(vma->vm_flags));
+}
+
static unsigned long roundup_gem_size(unsigned long size, unsigned int flags)
{
if (!IS_NONCONTIG_BUFFER(flags)) {
@@ -80,7 +96,7 @@ out:
return roundup(size, PAGE_SIZE);
}
-static struct page **exynos_gem_get_pages(struct drm_gem_object *obj,
+struct page **exynos_gem_get_pages(struct drm_gem_object *obj,
gfp_t gfpmask)
{
struct inode *inode;
@@ -180,6 +196,7 @@ static int exynos_drm_gem_get_pages(struct drm_gem_object *obj)
}
npages = obj->size >> PAGE_SHIFT;
+ buf->page_size = PAGE_SIZE;
buf->sgt = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
if (!buf->sgt) {
@@ -262,24 +279,24 @@ static int exynos_drm_gem_handle_create(struct drm_gem_object *obj,
void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj)
{
struct drm_gem_object *obj;
+ struct exynos_drm_gem_buf *buf;
DRM_DEBUG_KMS("%s\n", __FILE__);
- if (!exynos_gem_obj)
- return;
-
obj = &exynos_gem_obj->base;
+ buf = exynos_gem_obj->buffer;
DRM_DEBUG_KMS("handle count = %d\n", atomic_read(&obj->handle_count));
- if ((exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG) &&
- exynos_gem_obj->buffer->pages)
+ if (!buf->pages)
+ return;
+
+ if (exynos_gem_obj->flags & EXYNOS_BO_NONCONTIG)
exynos_drm_gem_put_pages(obj);
else
- exynos_drm_free_buf(obj->dev, exynos_gem_obj->flags,
- exynos_gem_obj->buffer);
+ exynos_drm_free_buf(obj->dev, exynos_gem_obj->flags, buf);
- exynos_drm_fini_buf(obj->dev, exynos_gem_obj->buffer);
+ exynos_drm_fini_buf(obj->dev, buf);
exynos_gem_obj->buffer = NULL;
if (obj->map_list.map)
@@ -292,7 +309,7 @@ void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj)
exynos_gem_obj = NULL;
}
-static struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev,
+struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev,
unsigned long size)
{
struct exynos_drm_gem_obj *exynos_gem_obj;
@@ -493,8 +510,7 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp,
vma->vm_flags |= (VM_IO | VM_RESERVED);
- /* in case of direct mapping, always having non-cachable attribute */
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ update_vm_cache_attr(exynos_gem_obj, vma);
vm_size = usize = vma->vm_end - vma->vm_start;
@@ -588,6 +604,32 @@ int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
return 0;
}
+int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{ struct exynos_drm_gem_obj *exynos_gem_obj;
+ struct drm_exynos_gem_info *args = data;
+ struct drm_gem_object *obj;
+
+ mutex_lock(&dev->struct_mutex);
+
+ obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+ if (!obj) {
+ DRM_ERROR("failed to lookup gem object.\n");
+ mutex_unlock(&dev->struct_mutex);
+ return -EINVAL;
+ }
+
+ exynos_gem_obj = to_exynos_gem_obj(obj);
+
+ args->flags = exynos_gem_obj->flags;
+ args->size = exynos_gem_obj->size;
+
+ drm_gem_object_unreference(obj);
+ mutex_unlock(&dev->struct_mutex);
+
+ return 0;
+}
+
int exynos_drm_gem_init_object(struct drm_gem_object *obj)
{
DRM_DEBUG_KMS("%s\n", __FILE__);
@@ -597,8 +639,17 @@ int exynos_drm_gem_init_object(struct drm_gem_object *obj)
void exynos_drm_gem_free_object(struct drm_gem_object *obj)
{
+ struct exynos_drm_gem_obj *exynos_gem_obj;
+ struct exynos_drm_gem_buf *buf;
+
DRM_DEBUG_KMS("%s\n", __FILE__);
+ exynos_gem_obj = to_exynos_gem_obj(obj);
+ buf = exynos_gem_obj->buffer;
+
+ if (obj->import_attach)
+ drm_prime_gem_destroy(obj, buf->sgt);
+
exynos_drm_gem_destroy(to_exynos_gem_obj(obj));
}
@@ -724,6 +775,8 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
{
+ struct exynos_drm_gem_obj *exynos_gem_obj;
+ struct drm_gem_object *obj;
int ret;
DRM_DEBUG_KMS("%s\n", __FILE__);
@@ -735,8 +788,20 @@ int exynos_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
return ret;
}
+ obj = vma->vm_private_data;
+ exynos_gem_obj = to_exynos_gem_obj(obj);
+
+ ret = check_gem_flags(exynos_gem_obj->flags);
+ if (ret) {
+ drm_gem_vm_close(vma);
+ drm_gem_free_mmap_offset(obj);
+ return ret;
+ }
+
vma->vm_flags &= ~VM_PFNMAP;
vma->vm_flags |= VM_MIXEDMAP;
+ update_vm_cache_attr(exynos_gem_obj, vma);
+
return ret;
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h
index 4ed842039505..14d038b6cb02 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h
@@ -40,6 +40,7 @@
* device address with IOMMU.
* @sgt: sg table to transfer page data.
* @pages: contain all pages to allocated memory region.
+ * @page_size: could be 4K, 64K or 1MB.
* @size: size of allocated memory region.
*/
struct exynos_drm_gem_buf {
@@ -47,6 +48,7 @@ struct exynos_drm_gem_buf {
dma_addr_t dma_addr;
struct sg_table *sgt;
struct page **pages;
+ unsigned long page_size;
unsigned long size;
};
@@ -74,9 +76,15 @@ struct exynos_drm_gem_obj {
unsigned int flags;
};
+struct page **exynos_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask);
+
/* destroy a buffer with gem object */
void exynos_drm_gem_destroy(struct exynos_drm_gem_obj *exynos_gem_obj);
+/* create a private gem object and initialize it. */
+struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev,
+ unsigned long size);
+
/* create a new buffer with gem object */
struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev,
unsigned int flags,
@@ -119,6 +127,10 @@ int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+/* get buffer information to memory region allocated by gem. */
+int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+
/* initialize gem object. */
int exynos_drm_gem_init_object(struct drm_gem_object *obj);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index 3424463676e0..5d9d2c2f8f3f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -37,6 +37,8 @@ struct drm_hdmi_context {
struct exynos_drm_subdrv subdrv;
struct exynos_drm_hdmi_context *hdmi_ctx;
struct exynos_drm_hdmi_context *mixer_ctx;
+
+ bool enabled[MIXER_WIN_NR];
};
void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops)
@@ -189,23 +191,34 @@ static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)
DRM_DEBUG_KMS("%s\n", __FILE__);
- switch (mode) {
- case DRM_MODE_DPMS_ON:
- break;
- case DRM_MODE_DPMS_STANDBY:
- case DRM_MODE_DPMS_SUSPEND:
- case DRM_MODE_DPMS_OFF:
- if (hdmi_ops && hdmi_ops->disable)
- hdmi_ops->disable(ctx->hdmi_ctx->ctx);
- break;
- default:
- DRM_DEBUG_KMS("unkown dps mode: %d\n", mode);
- break;
+ if (mixer_ops && mixer_ops->dpms)
+ mixer_ops->dpms(ctx->mixer_ctx->ctx, mode);
+
+ if (hdmi_ops && hdmi_ops->dpms)
+ hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
+}
+
+static void drm_hdmi_apply(struct device *subdrv_dev)
+{
+ struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+ int i;
+
+ DRM_DEBUG_KMS("%s\n", __FILE__);
+
+ for (i = 0; i < MIXER_WIN_NR; i++) {
+ if (!ctx->enabled[i])
+ continue;
+ if (mixer_ops && mixer_ops->win_commit)
+ mixer_ops->win_commit(ctx->mixer_ctx->ctx, i);
}
+
+ if (hdmi_ops && hdmi_ops->commit)
+ hdmi_ops->commit(ctx->hdmi_ctx->ctx);
}
static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
.dpms = drm_hdmi_dpms,
+ .apply = drm_hdmi_apply,
.enable_vblank = drm_hdmi_enable_vblank,
.disable_vblank = drm_hdmi_disable_vblank,
.mode_fixup = drm_hdmi_mode_fixup,
@@ -228,21 +241,37 @@ static void drm_mixer_mode_set(struct device *subdrv_dev,
static void drm_mixer_commit(struct device *subdrv_dev, int zpos)
{
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+ int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
DRM_DEBUG_KMS("%s\n", __FILE__);
+ if (win < 0 || win > MIXER_WIN_NR) {
+ DRM_ERROR("mixer window[%d] is wrong\n", win);
+ return;
+ }
+
if (mixer_ops && mixer_ops->win_commit)
- mixer_ops->win_commit(ctx->mixer_ctx->ctx, zpos);
+ mixer_ops->win_commit(ctx->mixer_ctx->ctx, win);
+
+ ctx->enabled[win] = true;
}
static void drm_mixer_disable(struct device *subdrv_dev, int zpos)
{
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+ int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
DRM_DEBUG_KMS("%s\n", __FILE__);
+ if (win < 0 || win > MIXER_WIN_NR) {
+ DRM_ERROR("mixer window[%d] is wrong\n", win);
+ return;
+ }
+
if (mixer_ops && mixer_ops->win_disable)
- mixer_ops->win_disable(ctx->mixer_ctx->ctx, zpos);
+ mixer_ops->win_disable(ctx->mixer_ctx->ctx, win);
+
+ ctx->enabled[win] = false;
}
static struct exynos_drm_overlay_ops drm_hdmi_overlay_ops = {
@@ -335,25 +364,6 @@ static int __devinit exynos_drm_hdmi_probe(struct platform_device *pdev)
return 0;
}
-static int hdmi_runtime_suspend(struct device *dev)
-{
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
- return 0;
-}
-
-static int hdmi_runtime_resume(struct device *dev)
-{
- DRM_DEBUG_KMS("%s\n", __FILE__);
-
- return 0;
-}
-
-static const struct dev_pm_ops hdmi_pm_ops = {
- .runtime_suspend = hdmi_runtime_suspend,
- .runtime_resume = hdmi_runtime_resume,
-};
-
static int __devexit exynos_drm_hdmi_remove(struct platform_device *pdev)
{
struct drm_hdmi_context *ctx = platform_get_drvdata(pdev);
@@ -372,6 +382,5 @@ struct platform_driver exynos_drm_common_hdmi_driver = {
.driver = {
.name = "exynos-drm-hdmi",
.owner = THIS_MODULE,
- .pm = &hdmi_pm_ops,
},
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
index f3ae192c8dcf..bd8126996e52 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
@@ -26,6 +26,9 @@
#ifndef _EXYNOS_DRM_HDMI_H_
#define _EXYNOS_DRM_HDMI_H_
+#define MIXER_WIN_NR 3
+#define MIXER_DEFAULT_WIN 0
+
/*
* exynos hdmi common context structure.
*
@@ -54,13 +57,14 @@ struct exynos_hdmi_ops {
void (*get_max_resol)(void *ctx, unsigned int *width,
unsigned int *height);
void (*commit)(void *ctx);
- void (*disable)(void *ctx);
+ void (*dpms)(void *ctx, int mode);
};
struct exynos_mixer_ops {
/* manager */
int (*enable_vblank)(void *ctx, int pipe);
void (*disable_vblank)(void *ctx);
+ void (*dpms)(void *ctx, int mode);
/* overlay */
void (*win_mode_set)(void *ctx, struct exynos_drm_overlay *overlay);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index f92fe4c6174a..c4c6525d4653 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -41,8 +41,6 @@ exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
container_of(plane, struct exynos_plane, base);
struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
struct exynos_drm_crtc_pos pos;
- unsigned int x = src_x >> 16;
- unsigned int y = src_y >> 16;
int ret;
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
@@ -53,10 +51,12 @@ exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
pos.crtc_w = crtc_w;
pos.crtc_h = crtc_h;
- pos.fb_x = x;
- pos.fb_y = y;
+ /* considering 16.16 fixed point of source values */
+ pos.fb_x = src_x >> 16;
+ pos.fb_y = src_y >> 16;
+ pos.src_w = src_w >> 16;
+ pos.src_h = src_h >> 16;
- /* TODO: scale feature */
ret = exynos_drm_overlay_update(overlay, fb, &crtc->mode, &pos);
if (ret < 0)
return ret;
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index b00353876458..a137e9e39a33 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -57,18 +57,16 @@ struct hdmi_resources {
struct hdmi_context {
struct device *dev;
struct drm_device *drm_dev;
- struct fb_videomode *default_timing;
- unsigned int is_v13:1;
- unsigned int default_win;
- unsigned int default_bpp;
- bool hpd_handle;
- bool enabled;
+ bool hpd;
+ bool powered;
+ bool is_v13;
+ bool dvi_mode;
+ struct mutex hdmi_mutex;
struct resource *regs_res;
void __iomem *regs;
- unsigned int irq;
- struct workqueue_struct *wq;
- struct work_struct hotplug_work;
+ unsigned int external_irq;
+ unsigned int internal_irq;
struct i2c_client *ddc_port;
struct i2c_client *hdmiphy_port;
@@ -78,6 +76,9 @@ struct hdmi_context {
struct hdmi_resources res;
void *parent_ctx;
+
+ void (*cfg_hpd)(bool external);
+ int (*get_hpd)(void);
};
/* HDMI Version 1.3 */
@@ -361,6 +362,13 @@ static const u8 hdmiphy_conf27_027[32] = {
0x54, 0xe3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00,
};
+static const u8 hdmiphy_conf74_176[32] = {
+ 0x01, 0xd1, 0x1f, 0x10, 0x40, 0x5b, 0xef, 0x08,
+ 0x81, 0xa0, 0xb9, 0xd8, 0x45, 0xa0, 0xac, 0x80,
+ 0x5a, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
+ 0x54, 0xa6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00,
+};
+
static const u8 hdmiphy_conf74_25[32] = {
0x01, 0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0x08,
0x81, 0xa0, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80,
@@ -750,6 +758,63 @@ static const struct hdmi_preset_conf hdmi_conf_1080i60 = {
},
};
+static const struct hdmi_preset_conf hdmi_conf_1080p30 = {
+ .core = {
+ .h_blank = {0x18, 0x01},
+ .v2_blank = {0x65, 0x04},
+ .v1_blank = {0x2d, 0x00},
+ .v_line = {0x65, 0x04},
+ .h_line = {0x98, 0x08},
+ .hsync_pol = {0x00},
+ .vsync_pol = {0x00},
+ .int_pro_mode = {0x00},
+ .v_blank_f0 = {0xff, 0xff},
+ .v_blank_f1 = {0xff, 0xff},
+ .h_sync_start = {0x56, 0x00},
+ .h_sync_end = {0x82, 0x00},
+ .v_sync_line_bef_2 = {0x09, 0x00},
+ .v_sync_line_bef_1 = {0x04, 0x00},
+ .v_sync_line_aft_2 = {0xff, 0xff},
+ .v_sync_line_aft_1 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_2 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_1 = {0xff, 0xff},
+ .v_blank_f2 = {0xff, 0xff},
+ .v_blank_f3 = {0xff, 0xff},
+ .v_blank_f4 = {0xff, 0xff},
+ .v_blank_f5 = {0xff, 0xff},
+ .v_sync_line_aft_3 = {0xff, 0xff},
+ .v_sync_line_aft_4 = {0xff, 0xff},
+ .v_sync_line_aft_5 = {0xff, 0xff},
+ .v_sync_line_aft_6 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_3 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_4 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_5 = {0xff, 0xff},
+ .v_sync_line_aft_pxl_6 = {0xff, 0xff},
+ .vact_space_1 = {0xff, 0xff},
+ .vact_space_2 = {0xff, 0xff},
+ .vact_space_3 = {0xff, 0xff},
+ .vact_space_4 = {0xff, 0xff},
+ .vact_space_5 = {0xff, 0xff},
+ .vact_space_6 = {0xff, 0xff},
+ /* other don't care */
+ },
+ .tg = {
+ 0x00, /* cmd */
+ 0x98, 0x08, /* h_fsz */
+ 0x18, 0x01, 0x80, 0x07, /* hact */
+ 0x65, 0x04, /* v_fsz */
+ 0x01, 0x00, 0x33, 0x02, /* vsync */
+ 0x2d, 0x00, 0x38, 0x04, /* vact */
+ 0x33, 0x02, /* field_chg */
+ 0x48, 0x02, /* vact_st2 */
+ 0x00, 0x00, /* vact_st3 */
+ 0x00, 0x00, /* vact_st4 */
+ 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
+ 0x01, 0x00, 0x33, 0x02, /* field top/bot */
+ 0x00, /* 3d FP */
+ },
+};
+
static const struct hdmi_preset_conf hdmi_conf_1080p50 = {
.core = {
.h_blank = {0xd0, 0x02},
@@ -864,6 +929,7 @@ static const struct hdmi_conf hdmi_confs[] = {
{ 1280, 720, 60, false, hdmiphy_conf74_25, &hdmi_conf_720p60 },
{ 1920, 1080, 50, true, hdmiphy_conf74_25, &hdmi_conf_1080i50 },
{ 1920, 1080, 60, true, hdmiphy_conf74_25, &hdmi_conf_1080i60 },
+ { 1920, 1080, 30, false, hdmiphy_conf74_176, &hdmi_conf_1080p30 },
{ 1920, 1080, 50, false, hdmiphy_conf148_5, &hdmi_conf_1080p50 },
{ 1920, 1080, 60, false, hdmiphy_conf148_5, &hdmi_conf_1080p60 },
};
@@ -1194,12 +1260,8 @@ static int hdmi_conf_index(struct hdmi_context *hdata,
static bool hdmi_is_connected(void *ctx)
{
struct hdmi_context *hdata = ctx;
- u32 val = hdmi_reg_read(hdata, HDMI_HPD_STATUS);
-
- if (val)
- return true;
- return false;
+ return hdata->hpd;
}
static int hdmi_get_edid(void *ctx, struct drm_connector *connector,
@@ -1215,10 +1277,12 @@ static int hdmi_get_edid(void *ctx, struct drm_connector *connector,
raw_edid = drm_get_edid(connector, hdata->ddc_port->adapter);
if (raw_edid) {
+ hdata->dvi_mode = !drm_detect_hdmi_monitor(raw_edid);
memcpy(edid, raw_edid, min((1 + raw_edid->extensions)
* EDID_LENGTH, len));
- DRM_DEBUG_KMS("width[%d] x height[%d]\n",
- raw_edid->width_cm, raw_edid->height_cm);
+ DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
+ (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
+ raw_edid->width_cm, raw_edid->height_cm);
} else {
return -ENODEV;
}
@@ -1289,28 +1353,6 @@ static int hdmi_check_timing(void *ctx, void *timing)
return hdmi_v14_check_timing(check_timing);
}
-static int hdmi_display_power_on(void *ctx, int mode)
-{
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
- switch (mode) {
- case DRM_MODE_DPMS_ON:
- DRM_DEBUG_KMS("hdmi [on]\n");
- break;
- case DRM_MODE_DPMS_STANDBY:
- break;
- case DRM_MODE_DPMS_SUSPEND:
- break;
- case DRM_MODE_DPMS_OFF:
- DRM_DEBUG_KMS("hdmi [off]\n");
- break;
- default:
- break;
- }
-
- return 0;
-}
-
static void hdmi_set_acr(u32 freq, u8 *acr)
{
u32 n, cts;
@@ -1463,10 +1505,7 @@ static void hdmi_audio_init(struct hdmi_context *hdata)
static void hdmi_audio_control(struct hdmi_context *hdata, bool onoff)
{
- u32 mod;
-
- mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
- if (mod & HDMI_DVI_MODE_EN)
+ if (hdata->dvi_mode)
return;
hdmi_reg_writeb(hdata, HDMI_AUI_CON, onoff ? 2 : 0);
@@ -1478,9 +1517,6 @@ static void hdmi_conf_reset(struct hdmi_context *hdata)
{
u32 reg;
- /* disable hpd handle for drm */
- hdata->hpd_handle = false;
-
if (hdata->is_v13)
reg = HDMI_V13_CORE_RSTOUT;
else
@@ -1491,16 +1527,10 @@ static void hdmi_conf_reset(struct hdmi_context *hdata)
mdelay(10);
hdmi_reg_writemask(hdata, reg, ~0, HDMI_CORE_SW_RSTOUT);
mdelay(10);
-
- /* enable hpd handle for drm */
- hdata->hpd_handle = true;
}
static void hdmi_conf_init(struct hdmi_context *hdata)
{
- /* disable hpd handle for drm */
- hdata->hpd_handle = false;
-
/* enable HPD interrupts */
hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL |
HDMI_INTC_EN_HPD_PLUG | HDMI_INTC_EN_HPD_UNPLUG);
@@ -1514,6 +1544,14 @@ static void hdmi_conf_init(struct hdmi_context *hdata)
/* disable bluescreen */
hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_BLUE_SCR_EN);
+ if (hdata->dvi_mode) {
+ /* choose DVI mode */
+ hdmi_reg_writemask(hdata, HDMI_MODE_SEL,
+ HDMI_MODE_DVI_EN, HDMI_MODE_MASK);
+ hdmi_reg_writeb(hdata, HDMI_CON_2,
+ HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
+ }
+
if (hdata->is_v13) {
/* choose bluescreen (fecal) color */
hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
@@ -1535,9 +1573,6 @@ static void hdmi_conf_init(struct hdmi_context *hdata)
hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 2 << 5);
hdmi_reg_writemask(hdata, HDMI_CON_1, 2, 3 << 5);
}
-
- /* enable hpd handle for drm */
- hdata->hpd_handle = true;
}
static void hdmi_v13_timing_apply(struct hdmi_context *hdata)
@@ -1890,8 +1925,11 @@ static void hdmi_conf_apply(struct hdmi_context *hdata)
hdmiphy_conf_reset(hdata);
hdmiphy_conf_apply(hdata);
+ mutex_lock(&hdata->hdmi_mutex);
hdmi_conf_reset(hdata);
hdmi_conf_init(hdata);
+ mutex_unlock(&hdata->hdmi_mutex);
+
hdmi_audio_init(hdata);
/* setting core registers */
@@ -1971,20 +2009,86 @@ static void hdmi_commit(void *ctx)
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
hdmi_conf_apply(hdata);
+}
+
+static void hdmi_poweron(struct hdmi_context *hdata)
+{
+ struct hdmi_resources *res = &hdata->res;
+
+ DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+ mutex_lock(&hdata->hdmi_mutex);
+ if (hdata->powered) {
+ mutex_unlock(&hdata->hdmi_mutex);
+ return;
+ }
+
+ hdata->powered = true;
+
+ if (hdata->cfg_hpd)
+ hdata->cfg_hpd(true);
+ mutex_unlock(&hdata->hdmi_mutex);
+
+ pm_runtime_get_sync(hdata->dev);
+
+ regulator_bulk_enable(res->regul_count, res->regul_bulk);
+ clk_enable(res->hdmiphy);
+ clk_enable(res->hdmi);
+ clk_enable(res->sclk_hdmi);
+}
+
+static void hdmi_poweroff(struct hdmi_context *hdata)
+{
+ struct hdmi_resources *res = &hdata->res;
+
+ DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+ mutex_lock(&hdata->hdmi_mutex);
+ if (!hdata->powered)
+ goto out;
+ mutex_unlock(&hdata->hdmi_mutex);
+
+ /*
+ * The TV power domain needs any condition of hdmiphy to turn off and
+ * its reset state seems to meet the condition.
+ */
+ hdmiphy_conf_reset(hdata);
+
+ clk_disable(res->sclk_hdmi);
+ clk_disable(res->hdmi);
+ clk_disable(res->hdmiphy);
+ regulator_bulk_disable(res->regul_count, res->regul_bulk);
+
+ pm_runtime_put_sync(hdata->dev);
- hdata->enabled = true;
+ mutex_lock(&hdata->hdmi_mutex);
+ if (hdata->cfg_hpd)
+ hdata->cfg_hpd(false);
+
+ hdata->powered = false;
+
+out:
+ mutex_unlock(&hdata->hdmi_mutex);
}
-static void hdmi_disable(void *ctx)
+static void hdmi_dpms(void *ctx, int mode)
{
struct hdmi_context *hdata = ctx;
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
- if (hdata->enabled) {
- hdmi_audio_control(hdata, false);
- hdmiphy_conf_reset(hdata);
- hdmi_conf_reset(hdata);
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ hdmi_poweron(hdata);
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ case DRM_MODE_DPMS_OFF:
+ hdmi_poweroff(hdata);
+ break;
+ default:
+ DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
+ break;
}
}
@@ -1993,30 +2097,35 @@ static struct exynos_hdmi_ops hdmi_ops = {
.is_connected = hdmi_is_connected,
.get_edid = hdmi_get_edid,
.check_timing = hdmi_check_timing,
- .power_on = hdmi_display_power_on,
/* manager */
.mode_fixup = hdmi_mode_fixup,
.mode_set = hdmi_mode_set,
.get_max_resol = hdmi_get_max_resol,
.commit = hdmi_commit,
- .disable = hdmi_disable,
+ .dpms = hdmi_dpms,
};
-/*
- * Handle hotplug events outside the interrupt handler proper.
- */
-static void hdmi_hotplug_func(struct work_struct *work)
+static irqreturn_t hdmi_external_irq_thread(int irq, void *arg)
{
- struct hdmi_context *hdata =
- container_of(work, struct hdmi_context, hotplug_work);
- struct exynos_drm_hdmi_context *ctx =
- (struct exynos_drm_hdmi_context *)hdata->parent_ctx;
+ struct exynos_drm_hdmi_context *ctx = arg;
+ struct hdmi_context *hdata = ctx->ctx;
+
+ if (!hdata->get_hpd)
+ goto out;
+
+ mutex_lock(&hdata->hdmi_mutex);
+ hdata->hpd = hdata->get_hpd();
+ mutex_unlock(&hdata->hdmi_mutex);
- drm_helper_hpd_irq_event(ctx->drm_dev);
+ if (ctx->drm_dev)
+ drm_helper_hpd_irq_event(ctx->drm_dev);
+
+out:
+ return IRQ_HANDLED;
}
-static irqreturn_t hdmi_irq_handler(int irq, void *arg)
+static irqreturn_t hdmi_internal_irq_thread(int irq, void *arg)
{
struct exynos_drm_hdmi_context *ctx = arg;
struct hdmi_context *hdata = ctx->ctx;
@@ -2025,19 +2134,28 @@ static irqreturn_t hdmi_irq_handler(int irq, void *arg)
intc_flag = hdmi_reg_read(hdata, HDMI_INTC_FLAG);
/* clearing flags for HPD plug/unplug */
if (intc_flag & HDMI_INTC_FLAG_HPD_UNPLUG) {
- DRM_DEBUG_KMS("unplugged, handling:%d\n", hdata->hpd_handle);
+ DRM_DEBUG_KMS("unplugged\n");
hdmi_reg_writemask(hdata, HDMI_INTC_FLAG, ~0,
HDMI_INTC_FLAG_HPD_UNPLUG);
}
if (intc_flag & HDMI_INTC_FLAG_HPD_PLUG) {
- DRM_DEBUG_KMS("plugged, handling:%d\n", hdata->hpd_handle);
+ DRM_DEBUG_KMS("plugged\n");
hdmi_reg_writemask(hdata, HDMI_INTC_FLAG, ~0,
HDMI_INTC_FLAG_HPD_PLUG);
}
- if (ctx->drm_dev && hdata->hpd_handle)
- queue_work(hdata->wq, &hdata->hotplug_work);
+ mutex_lock(&hdata->hdmi_mutex);
+ hdata->hpd = hdmi_reg_read(hdata, HDMI_HPD_STATUS);
+ if (hdata->powered && hdata->hpd) {
+ mutex_unlock(&hdata->hdmi_mutex);
+ goto out;
+ }
+ mutex_unlock(&hdata->hdmi_mutex);
+
+ if (ctx->drm_dev)
+ drm_helper_hpd_irq_event(ctx->drm_dev);
+out:
return IRQ_HANDLED;
}
@@ -2131,68 +2249,6 @@ static int hdmi_resources_cleanup(struct hdmi_context *hdata)
return 0;
}
-static void hdmi_resource_poweron(struct hdmi_context *hdata)
-{
- struct hdmi_resources *res = &hdata->res;
-
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
- /* turn HDMI power on */
- regulator_bulk_enable(res->regul_count, res->regul_bulk);
- /* power-on hdmi physical interface */
- clk_enable(res->hdmiphy);
- /* turn clocks on */
- clk_enable(res->hdmi);
- clk_enable(res->sclk_hdmi);
-
- hdmiphy_conf_reset(hdata);
- hdmi_conf_reset(hdata);
- hdmi_conf_init(hdata);
- hdmi_audio_init(hdata);
-}
-
-static void hdmi_resource_poweroff(struct hdmi_context *hdata)
-{
- struct hdmi_resources *res = &hdata->res;
-
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
- /* turn clocks off */
- clk_disable(res->sclk_hdmi);
- clk_disable(res->hdmi);
- /* power-off hdmiphy */
- clk_disable(res->hdmiphy);
- /* turn HDMI power off */
- regulator_bulk_disable(res->regul_count, res->regul_bulk);
-}
-
-static int hdmi_runtime_suspend(struct device *dev)
-{
- struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
-
- DRM_DEBUG_KMS("%s\n", __func__);
-
- hdmi_resource_poweroff(ctx->ctx);
-
- return 0;
-}
-
-static int hdmi_runtime_resume(struct device *dev)
-{
- struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
-
- DRM_DEBUG_KMS("%s\n", __func__);
-
- hdmi_resource_poweron(ctx->ctx);
-
- return 0;
-}
-
-static const struct dev_pm_ops hdmi_pm_ops = {
- .runtime_suspend = hdmi_runtime_suspend,
- .runtime_resume = hdmi_runtime_resume,
-};
-
static struct i2c_client *hdmi_ddc, *hdmi_hdmiphy;
void hdmi_attach_ddc_client(struct i2c_client *ddc)
@@ -2237,15 +2293,16 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ mutex_init(&hdata->hdmi_mutex);
+
drm_hdmi_ctx->ctx = (void *)hdata;
hdata->parent_ctx = (void *)drm_hdmi_ctx;
platform_set_drvdata(pdev, drm_hdmi_ctx);
hdata->is_v13 = pdata->is_v13;
- hdata->default_win = pdata->default_win;
- hdata->default_timing = &pdata->timing;
- hdata->default_bpp = pdata->bpp;
+ hdata->cfg_hpd = pdata->cfg_hpd;
+ hdata->get_hpd = pdata->get_hpd;
hdata->dev = dev;
ret = hdmi_resources_init(hdata);
@@ -2294,41 +2351,49 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
hdata->hdmiphy_port = hdmi_hdmiphy;
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (res == NULL) {
- DRM_ERROR("get interrupt resource failed.\n");
- ret = -ENXIO;
+ hdata->external_irq = platform_get_irq_byname(pdev, "external_irq");
+ if (hdata->external_irq < 0) {
+ DRM_ERROR("failed to get platform irq\n");
+ ret = hdata->external_irq;
goto err_hdmiphy;
}
- /* create workqueue and hotplug work */
- hdata->wq = alloc_workqueue("exynos-drm-hdmi",
- WQ_UNBOUND | WQ_NON_REENTRANT, 1);
- if (hdata->wq == NULL) {
- DRM_ERROR("Failed to create workqueue.\n");
- ret = -ENOMEM;
+ hdata->internal_irq = platform_get_irq_byname(pdev, "internal_irq");
+ if (hdata->internal_irq < 0) {
+ DRM_ERROR("failed to get platform internal irq\n");
+ ret = hdata->internal_irq;
goto err_hdmiphy;
}
- INIT_WORK(&hdata->hotplug_work, hdmi_hotplug_func);
- /* register hpd interrupt */
- ret = request_irq(res->start, hdmi_irq_handler, 0, "drm_hdmi",
- drm_hdmi_ctx);
+ ret = request_threaded_irq(hdata->external_irq, NULL,
+ hdmi_external_irq_thread, IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "hdmi_external", drm_hdmi_ctx);
if (ret) {
- DRM_ERROR("request interrupt failed.\n");
- goto err_workqueue;
+ DRM_ERROR("failed to register hdmi internal interrupt\n");
+ goto err_hdmiphy;
+ }
+
+ if (hdata->cfg_hpd)
+ hdata->cfg_hpd(false);
+
+ ret = request_threaded_irq(hdata->internal_irq, NULL,
+ hdmi_internal_irq_thread, IRQF_ONESHOT,
+ "hdmi_internal", drm_hdmi_ctx);
+ if (ret) {
+ DRM_ERROR("failed to register hdmi internal interrupt\n");
+ goto err_free_irq;
}
- hdata->irq = res->start;
/* register specific callbacks to common hdmi. */
exynos_hdmi_ops_register(&hdmi_ops);
- hdmi_resource_poweron(hdata);
+ pm_runtime_enable(dev);
return 0;
-err_workqueue:
- destroy_workqueue(hdata->wq);
+err_free_irq:
+ free_irq(hdata->external_irq, drm_hdmi_ctx);
err_hdmiphy:
i2c_del_driver(&hdmiphy_driver);
err_ddc:
@@ -2348,18 +2413,15 @@ err_data:
static int __devexit hdmi_remove(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct exynos_drm_hdmi_context *ctx = platform_get_drvdata(pdev);
struct hdmi_context *hdata = ctx->ctx;
DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
- hdmi_resource_poweroff(hdata);
+ pm_runtime_disable(dev);
- disable_irq(hdata->irq);
- free_irq(hdata->irq, hdata);
-
- cancel_work_sync(&hdata->hotplug_work);
- destroy_workqueue(hdata->wq);
+ free_irq(hdata->internal_irq, hdata);
hdmi_resources_cleanup(hdata);
@@ -2378,12 +2440,43 @@ static int __devexit hdmi_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int hdmi_suspend(struct device *dev)
+{
+ struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
+ struct hdmi_context *hdata = ctx->ctx;
+
+ disable_irq(hdata->internal_irq);
+ disable_irq(hdata->external_irq);
+
+ hdata->hpd = false;
+ if (ctx->drm_dev)
+ drm_helper_hpd_irq_event(ctx->drm_dev);
+
+ hdmi_poweroff(hdata);
+
+ return 0;
+}
+
+static int hdmi_resume(struct device *dev)
+{
+ struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
+ struct hdmi_context *hdata = ctx->ctx;
+
+ enable_irq(hdata->external_irq);
+ enable_irq(hdata->internal_irq);
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(hdmi_pm_ops, hdmi_suspend, hdmi_resume);
+
struct platform_driver hdmi_driver = {
.probe = hdmi_probe,
.remove = __devexit_p(hdmi_remove),
.driver = {
.name = "exynos4-hdmi",
.owner = THIS_MODULE,
- .pm = &hdmi_pm_ops,
+ .pm = &hdmi_pm_ops,
},
};
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index e15438c01129..68ef01028375 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -37,9 +37,6 @@
#include "exynos_drm_drv.h"
#include "exynos_drm_hdmi.h"
-#define MIXER_WIN_NR 3
-#define MIXER_DEFAULT_WIN 0
-
#define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev))
struct hdmi_win_data {
@@ -57,13 +54,14 @@ struct hdmi_win_data {
unsigned int fb_y;
unsigned int fb_width;
unsigned int fb_height;
+ unsigned int src_width;
+ unsigned int src_height;
unsigned int mode_width;
unsigned int mode_height;
unsigned int scan_flags;
};
struct mixer_resources {
- struct device *dev;
int irq;
void __iomem *mixer_regs;
void __iomem *vp_regs;
@@ -76,10 +74,13 @@ struct mixer_resources {
};
struct mixer_context {
- unsigned int irq;
+ struct device *dev;
int pipe;
bool interlace;
+ bool powered;
+ u32 int_en;
+ struct mutex mixer_mutex;
struct mixer_resources mixer_res;
struct hdmi_win_data win_data[MIXER_WIN_NR];
};
@@ -352,10 +353,7 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
struct mixer_resources *res = &ctx->mixer_res;
unsigned long flags;
struct hdmi_win_data *win_data;
- unsigned int full_width, full_height, width, height;
unsigned int x_ratio, y_ratio;
- unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
- unsigned int mode_width, mode_height;
unsigned int buf_num;
dma_addr_t luma_addr[2], chroma_addr[2];
bool tiled_mode = false;
@@ -382,21 +380,9 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
return;
}
- full_width = win_data->fb_width;
- full_height = win_data->fb_height;
- width = win_data->crtc_width;
- height = win_data->crtc_height;
- mode_width = win_data->mode_width;
- mode_height = win_data->mode_height;
-
/* scaling feature: (src << 16) / dst */
- x_ratio = (width << 16) / width;
- y_ratio = (height << 16) / height;
-
- src_x_offset = win_data->fb_x;
- src_y_offset = win_data->fb_y;
- dst_x_offset = win_data->crtc_x;
- dst_y_offset = win_data->crtc_y;
+ x_ratio = (win_data->src_width << 16) / win_data->crtc_width;
+ y_ratio = (win_data->src_height << 16) / win_data->crtc_height;
if (buf_num == 2) {
luma_addr[0] = win_data->dma_addr;
@@ -404,7 +390,7 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
} else {
luma_addr[0] = win_data->dma_addr;
chroma_addr[0] = win_data->dma_addr
- + (full_width * full_height);
+ + (win_data->fb_width * win_data->fb_height);
}
if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) {
@@ -413,8 +399,8 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
luma_addr[1] = luma_addr[0] + 0x40;
chroma_addr[1] = chroma_addr[0] + 0x40;
} else {
- luma_addr[1] = luma_addr[0] + full_width;
- chroma_addr[1] = chroma_addr[0] + full_width;
+ luma_addr[1] = luma_addr[0] + win_data->fb_width;
+ chroma_addr[1] = chroma_addr[0] + win_data->fb_width;
}
} else {
ctx->interlace = false;
@@ -435,26 +421,26 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
/* setting size of input image */
- vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(full_width) |
- VP_IMG_VSIZE(full_height));
+ vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_width) |
+ VP_IMG_VSIZE(win_data->fb_height));
/* chroma height has to reduced by 2 to avoid chroma distorions */
- vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(full_width) |
- VP_IMG_VSIZE(full_height / 2));
+ vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_width) |
+ VP_IMG_VSIZE(win_data->fb_height / 2));
- vp_reg_write(res, VP_SRC_WIDTH, width);
- vp_reg_write(res, VP_SRC_HEIGHT, height);
+ vp_reg_write(res, VP_SRC_WIDTH, win_data->src_width);
+ vp_reg_write(res, VP_SRC_HEIGHT, win_data->src_height);
vp_reg_write(res, VP_SRC_H_POSITION,
- VP_SRC_H_POSITION_VAL(src_x_offset));
- vp_reg_write(res, VP_SRC_V_POSITION, src_y_offset);
+ VP_SRC_H_POSITION_VAL(win_data->fb_x));
+ vp_reg_write(res, VP_SRC_V_POSITION, win_data->fb_y);
- vp_reg_write(res, VP_DST_WIDTH, width);
- vp_reg_write(res, VP_DST_H_POSITION, dst_x_offset);
+ vp_reg_write(res, VP_DST_WIDTH, win_data->crtc_width);
+ vp_reg_write(res, VP_DST_H_POSITION, win_data->crtc_x);
if (ctx->interlace) {
- vp_reg_write(res, VP_DST_HEIGHT, height / 2);
- vp_reg_write(res, VP_DST_V_POSITION, dst_y_offset / 2);
+ vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height / 2);
+ vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y / 2);
} else {
- vp_reg_write(res, VP_DST_HEIGHT, height);
- vp_reg_write(res, VP_DST_V_POSITION, dst_y_offset);
+ vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height);
+ vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y);
}
vp_reg_write(res, VP_H_RATIO, x_ratio);
@@ -468,8 +454,8 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
- mixer_cfg_scan(ctx, mode_height);
- mixer_cfg_rgb_fmt(ctx, mode_height);
+ mixer_cfg_scan(ctx, win_data->mode_height);
+ mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
mixer_cfg_layer(ctx, win, true);
mixer_run(ctx);
@@ -484,10 +470,8 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win)
struct mixer_resources *res = &ctx->mixer_res;
unsigned long flags;
struct hdmi_win_data *win_data;
- unsigned int full_width, width, height;
unsigned int x_ratio, y_ratio;
unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
- unsigned int mode_width, mode_height;
dma_addr_t dma_addr;
unsigned int fmt;
u32 val;
@@ -510,26 +494,17 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win)
fmt = ARGB8888;
}
- dma_addr = win_data->dma_addr;
- full_width = win_data->fb_width;
- width = win_data->crtc_width;
- height = win_data->crtc_height;
- mode_width = win_data->mode_width;
- mode_height = win_data->mode_height;
-
/* 2x scaling feature */
x_ratio = 0;
y_ratio = 0;
- src_x_offset = win_data->fb_x;
- src_y_offset = win_data->fb_y;
dst_x_offset = win_data->crtc_x;
dst_y_offset = win_data->crtc_y;
/* converting dma address base and source offset */
- dma_addr = dma_addr
- + (src_x_offset * win_data->bpp >> 3)
- + (src_y_offset * full_width * win_data->bpp >> 3);
+ dma_addr = win_data->dma_addr
+ + (win_data->fb_x * win_data->bpp >> 3)
+ + (win_data->fb_y * win_data->fb_width * win_data->bpp >> 3);
src_x_offset = 0;
src_y_offset = 0;
@@ -546,10 +521,10 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win)
MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
/* setup geometry */
- mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), full_width);
+ mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), win_data->fb_width);
- val = MXR_GRP_WH_WIDTH(width);
- val |= MXR_GRP_WH_HEIGHT(height);
+ val = MXR_GRP_WH_WIDTH(win_data->crtc_width);
+ val |= MXR_GRP_WH_HEIGHT(win_data->crtc_height);
val |= MXR_GRP_WH_H_SCALE(x_ratio);
val |= MXR_GRP_WH_V_SCALE(y_ratio);
mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
@@ -567,8 +542,8 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win)
/* set buffer address to mixer */
mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
- mixer_cfg_scan(ctx, mode_height);
- mixer_cfg_rgb_fmt(ctx, mode_height);
+ mixer_cfg_scan(ctx, win_data->mode_height);
+ mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
mixer_cfg_layer(ctx, win, true);
mixer_run(ctx);
@@ -591,6 +566,116 @@ static void vp_win_reset(struct mixer_context *ctx)
WARN(tries == 0, "failed to reset Video Processor\n");
}
+static void mixer_win_reset(struct mixer_context *ctx)
+{
+ struct mixer_resources *res = &ctx->mixer_res;
+ unsigned long flags;
+ u32 val; /* value stored to register */
+
+ spin_lock_irqsave(&res->reg_slock, flags);
+ mixer_vsync_set_update(ctx, false);
+
+ mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
+
+ /* set output in RGB888 mode */
+ mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
+
+ /* 16 beat burst in DMA */
+ mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
+ MXR_STATUS_BURST_MASK);
+
+ /* setting default layer priority: layer1 > layer0 > video
+ * because typical usage scenario would be
+ * layer1 - OSD
+ * layer0 - framebuffer
+ * video - video overlay
+ */
+ val = MXR_LAYER_CFG_GRP1_VAL(3);
+ val |= MXR_LAYER_CFG_GRP0_VAL(2);
+ val |= MXR_LAYER_CFG_VP_VAL(1);
+ mixer_reg_write(res, MXR_LAYER_CFG, val);
+
+ /* setting background color */
+ mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
+ mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
+ mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
+
+ /* setting graphical layers */
+
+ val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
+ val |= MXR_GRP_CFG_WIN_BLEND_EN;
+ val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
+
+ /* the same configuration for both layers */
+ mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
+
+ val |= MXR_GRP_CFG_BLEND_PRE_MUL;
+ val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
+ mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
+
+ /* configuration of Video Processor Registers */
+ vp_win_reset(ctx);
+ vp_default_filter(res);
+
+ /* disable all layers */
+ mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
+ mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
+ mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
+
+ mixer_vsync_set_update(ctx, true);
+ spin_unlock_irqrestore(&res->reg_slock, flags);
+}
+
+static void mixer_poweron(struct mixer_context *ctx)
+{
+ struct mixer_resources *res = &ctx->mixer_res;
+
+ DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+ mutex_lock(&ctx->mixer_mutex);
+ if (ctx->powered) {
+ mutex_unlock(&ctx->mixer_mutex);
+ return;
+ }
+ ctx->powered = true;
+ mutex_unlock(&ctx->mixer_mutex);
+
+ pm_runtime_get_sync(ctx->dev);
+
+ clk_enable(res->mixer);
+ clk_enable(res->vp);
+ clk_enable(res->sclk_mixer);
+
+ mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
+ mixer_win_reset(ctx);
+}
+
+static void mixer_poweroff(struct mixer_context *ctx)
+{
+ struct mixer_resources *res = &ctx->mixer_res;
+
+ DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+ mutex_lock(&ctx->mixer_mutex);
+ if (!ctx->powered)
+ goto out;
+ mutex_unlock(&ctx->mixer_mutex);
+
+ ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
+
+ clk_disable(res->mixer);
+ clk_disable(res->vp);
+ clk_disable(res->sclk_mixer);
+
+ pm_runtime_put_sync(ctx->dev);
+
+ mutex_lock(&ctx->mixer_mutex);
+ ctx->powered = false;
+
+out:
+ mutex_unlock(&ctx->mixer_mutex);
+}
+
static int mixer_enable_vblank(void *ctx, int pipe)
{
struct mixer_context *mixer_ctx = ctx;
@@ -618,6 +703,27 @@ static void mixer_disable_vblank(void *ctx)
mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
}
+static void mixer_dpms(void *ctx, int mode)
+{
+ struct mixer_context *mixer_ctx = ctx;
+
+ DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
+
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ mixer_poweron(mixer_ctx);
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ case DRM_MODE_DPMS_OFF:
+ mixer_poweroff(mixer_ctx);
+ break;
+ default:
+ DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
+ break;
+ }
+}
+
static void mixer_win_mode_set(void *ctx,
struct exynos_drm_overlay *overlay)
{
@@ -643,7 +749,7 @@ static void mixer_win_mode_set(void *ctx,
win = MIXER_DEFAULT_WIN;
if (win < 0 || win > MIXER_WIN_NR) {
- DRM_ERROR("overlay plane[%d] is wrong\n", win);
+ DRM_ERROR("mixer window[%d] is wrong\n", win);
return;
}
@@ -665,6 +771,8 @@ static void mixer_win_mode_set(void *ctx,
win_data->fb_y = overlay->fb_y;
win_data->fb_width = overlay->fb_width;
win_data->fb_height = overlay->fb_height;
+ win_data->src_width = overlay->src_width;
+ win_data->src_height = overlay->src_height;
win_data->mode_width = overlay->mode_width;
win_data->mode_height = overlay->mode_height;
@@ -672,44 +780,26 @@ static void mixer_win_mode_set(void *ctx,
win_data->scan_flags = overlay->scan_flag;
}
-static void mixer_win_commit(void *ctx, int zpos)
+static void mixer_win_commit(void *ctx, int win)
{
struct mixer_context *mixer_ctx = ctx;
- int win = zpos;
DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
- if (win == DEFAULT_ZPOS)
- win = MIXER_DEFAULT_WIN;
-
- if (win < 0 || win > MIXER_WIN_NR) {
- DRM_ERROR("overlay plane[%d] is wrong\n", win);
- return;
- }
-
if (win > 1)
vp_video_buffer(mixer_ctx, win);
else
mixer_graph_buffer(mixer_ctx, win);
}
-static void mixer_win_disable(void *ctx, int zpos)
+static void mixer_win_disable(void *ctx, int win)
{
struct mixer_context *mixer_ctx = ctx;
struct mixer_resources *res = &mixer_ctx->mixer_res;
unsigned long flags;
- int win = zpos;
DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
- if (win == DEFAULT_ZPOS)
- win = MIXER_DEFAULT_WIN;
-
- if (win < 0 || win > MIXER_WIN_NR) {
- DRM_ERROR("overlay plane[%d] is wrong\n", win);
- return;
- }
-
spin_lock_irqsave(&res->reg_slock, flags);
mixer_vsync_set_update(mixer_ctx, false);
@@ -723,6 +813,7 @@ static struct exynos_mixer_ops mixer_ops = {
/* manager */
.enable_vblank = mixer_enable_vblank,
.disable_vblank = mixer_disable_vblank,
+ .dpms = mixer_dpms,
/* overlay */
.win_mode_set = mixer_win_mode_set,
@@ -773,7 +864,7 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg;
struct mixer_context *ctx = drm_hdmi_ctx->ctx;
struct mixer_resources *res = &ctx->mixer_res;
- u32 val, val_base;
+ u32 val, base, shadow;
spin_lock(&res->reg_slock);
@@ -784,12 +875,14 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
if (val & MXR_INT_STATUS_VSYNC) {
/* interlace scan need to check shadow register */
if (ctx->interlace) {
- val_base = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
- if (ctx->win_data[0].dma_addr != val_base)
+ base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
+ shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
+ if (base != shadow)
goto out;
- val_base = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
- if (ctx->win_data[1].dma_addr != val_base)
+ base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
+ shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
+ if (base != shadow)
goto out;
}
@@ -811,117 +904,6 @@ out:
return IRQ_HANDLED;
}
-static void mixer_win_reset(struct mixer_context *ctx)
-{
- struct mixer_resources *res = &ctx->mixer_res;
- unsigned long flags;
- u32 val; /* value stored to register */
-
- spin_lock_irqsave(&res->reg_slock, flags);
- mixer_vsync_set_update(ctx, false);
-
- mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
-
- /* set output in RGB888 mode */
- mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
-
- /* 16 beat burst in DMA */
- mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
- MXR_STATUS_BURST_MASK);
-
- /* setting default layer priority: layer1 > layer0 > video
- * because typical usage scenario would be
- * layer1 - OSD
- * layer0 - framebuffer
- * video - video overlay
- */
- val = MXR_LAYER_CFG_GRP1_VAL(3);
- val |= MXR_LAYER_CFG_GRP0_VAL(2);
- val |= MXR_LAYER_CFG_VP_VAL(1);
- mixer_reg_write(res, MXR_LAYER_CFG, val);
-
- /* setting background color */
- mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
- mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
- mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
-
- /* setting graphical layers */
-
- val = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
- val |= MXR_GRP_CFG_WIN_BLEND_EN;
- val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
-
- /* the same configuration for both layers */
- mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
-
- val |= MXR_GRP_CFG_BLEND_PRE_MUL;
- val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
- mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
-
- /* configuration of Video Processor Registers */
- vp_win_reset(ctx);
- vp_default_filter(res);
-
- /* disable all layers */
- mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
- mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
- mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
-
- mixer_vsync_set_update(ctx, true);
- spin_unlock_irqrestore(&res->reg_slock, flags);
-}
-
-static void mixer_resource_poweron(struct mixer_context *ctx)
-{
- struct mixer_resources *res = &ctx->mixer_res;
-
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
- clk_enable(res->mixer);
- clk_enable(res->vp);
- clk_enable(res->sclk_mixer);
-
- mixer_win_reset(ctx);
-}
-
-static void mixer_resource_poweroff(struct mixer_context *ctx)
-{
- struct mixer_resources *res = &ctx->mixer_res;
-
- DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
-
- clk_disable(res->mixer);
- clk_disable(res->vp);
- clk_disable(res->sclk_mixer);
-}
-
-static int mixer_runtime_resume(struct device *dev)
-{
- struct exynos_drm_hdmi_context *ctx = get_mixer_context(dev);
-
- DRM_DEBUG_KMS("resume - start\n");
-
- mixer_resource_poweron(ctx->ctx);
-
- return 0;
-}
-
-static int mixer_runtime_suspend(struct device *dev)
-{
- struct exynos_drm_hdmi_context *ctx = get_mixer_context(dev);
-
- DRM_DEBUG_KMS("suspend - start\n");
-
- mixer_resource_poweroff(ctx->ctx);
-
- return 0;
-}
-
-static const struct dev_pm_ops mixer_pm_ops = {
- .runtime_suspend = mixer_runtime_suspend,
- .runtime_resume = mixer_runtime_resume,
-};
-
static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
struct platform_device *pdev)
{
@@ -931,7 +913,6 @@ static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
struct resource *res;
int ret;
- mixer_res->dev = dev;
spin_lock_init(&mixer_res->reg_slock);
mixer_res->mixer = clk_get(dev, "mixer");
@@ -1027,7 +1008,6 @@ fail:
clk_put(mixer_res->vp);
if (!IS_ERR_OR_NULL(mixer_res->mixer))
clk_put(mixer_res->mixer);
- mixer_res->dev = NULL;
return ret;
}
@@ -1035,7 +1015,6 @@ static void mixer_resources_cleanup(struct mixer_context *ctx)
{
struct mixer_resources *res = &ctx->mixer_res;
- disable_irq(res->irq);
free_irq(res->irq, ctx);
iounmap(res->vp_regs);
@@ -1064,6 +1043,9 @@ static int __devinit mixer_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ mutex_init(&ctx->mixer_mutex);
+
+ ctx->dev = &pdev->dev;
drm_hdmi_ctx->ctx = (void *)ctx;
platform_set_drvdata(pdev, drm_hdmi_ctx);
@@ -1076,7 +1058,7 @@ static int __devinit mixer_probe(struct platform_device *pdev)
/* register specific callback point to common hdmi. */
exynos_mixer_ops_register(&mixer_ops);
- mixer_resource_poweron(ctx);
+ pm_runtime_enable(dev);
return 0;
@@ -1095,12 +1077,27 @@ static int mixer_remove(struct platform_device *pdev)
dev_info(dev, "remove successful\n");
- mixer_resource_poweroff(ctx);
+ pm_runtime_disable(&pdev->dev);
+
mixer_resources_cleanup(ctx);
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int mixer_suspend(struct device *dev)
+{
+ struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
+ struct mixer_context *ctx = drm_hdmi_ctx->ctx;
+
+ mixer_poweroff(ctx);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(mixer_pm_ops, mixer_suspend, NULL);
+
struct platform_driver mixer_driver = {
.driver = {
.name = "s5p-mixer",
diff --git a/drivers/gpu/drm/exynos/regs-hdmi.h b/drivers/gpu/drm/exynos/regs-hdmi.h
index 3c04bea842ce..9cc7c5e9718c 100644
--- a/drivers/gpu/drm/exynos/regs-hdmi.h
+++ b/drivers/gpu/drm/exynos/regs-hdmi.h
@@ -138,14 +138,16 @@
#define HDMI_ASP_MASK (1 << 2)
#define HDMI_EN (1 << 0)
+/* HDMI_CON_2 */
+#define HDMI_VID_PREAMBLE_DIS (1 << 5)
+#define HDMI_GUARD_BAND_DIS (1 << 1)
+
/* HDMI_PHY_STATUS */
#define HDMI_PHY_STATUS_READY (1 << 0)
/* HDMI_MODE_SEL */
#define HDMI_MODE_HDMI_EN (1 << 1)
#define HDMI_MODE_DVI_EN (1 << 0)
-#define HDMI_DVI_MODE_EN (1)
-#define HDMI_DVI_MODE_DIS (0)
#define HDMI_MODE_MASK (3 << 0)
/* HDMI_TG_CMD */
diff --git a/drivers/gpu/drm/gma500/Makefile b/drivers/gpu/drm/gma500/Makefile
index 1583982917ce..abfa2a93f0d0 100644
--- a/drivers/gpu/drm/gma500/Makefile
+++ b/drivers/gpu/drm/gma500/Makefile
@@ -1,7 +1,7 @@
#
# KMS driver for the GMA500
#
-ccflags-y += -Iinclude/drm
+ccflags-y += -I$(srctree)/include/drm
gma500_gfx-y += gem_glue.o \
accel_2d.o \
@@ -12,7 +12,6 @@ gma500_gfx-y += gem_glue.o \
intel_bios.o \
intel_i2c.o \
intel_gmbus.o \
- intel_opregion.o \
mmu.o \
power.o \
psb_drv.o \
@@ -25,6 +24,8 @@ gma500_gfx-y += gem_glue.o \
psb_device.o \
mid_bios.o
+gma500_gfx-$(CONFIG_ACPI) += opregion.o \
+
gma500_gfx-$(CONFIG_DRM_GMA3600) += cdv_device.o \
cdv_intel_crt.o \
cdv_intel_display.o \
diff --git a/drivers/gpu/drm/gma500/cdv_device.c b/drivers/gpu/drm/gma500/cdv_device.c
index a54cc738926a..9764045428ce 100644
--- a/drivers/gpu/drm/gma500/cdv_device.c
+++ b/drivers/gpu/drm/gma500/cdv_device.c
@@ -49,13 +49,15 @@ static void cdv_disable_vga(struct drm_device *dev)
static int cdv_output_init(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
+
+ drm_mode_create_scaling_mode_property(dev);
+
cdv_disable_vga(dev);
cdv_intel_crt_init(dev, &dev_priv->mode_dev);
cdv_intel_lvds_init(dev, &dev_priv->mode_dev);
- /* These bits indicate HDMI not SDVO on CDV, but we don't yet support
- the HDMI interface */
+ /* These bits indicate HDMI not SDVO on CDV */
if (REG_READ(SDVOB) & SDVO_DETECTED)
cdv_hdmi_init(dev, &dev_priv->mode_dev, SDVOB);
if (REG_READ(SDVOC) & SDVO_DETECTED)
@@ -66,76 +68,71 @@ static int cdv_output_init(struct drm_device *dev)
#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
/*
- * Poulsbo Backlight Interfaces
+ * Cedartrail Backlght Interfaces
*/
-#define BLC_PWM_PRECISION_FACTOR 100 /* 10000000 */
-#define BLC_PWM_FREQ_CALC_CONSTANT 32
-#define MHz 1000000
-
-#define PSB_BLC_PWM_PRECISION_FACTOR 10
-#define PSB_BLC_MAX_PWM_REG_FREQ 0xFFFE
-#define PSB_BLC_MIN_PWM_REG_FREQ 0x2
-
-#define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE)
-#define PSB_BACKLIGHT_PWM_CTL_SHIFT (16)
-
-static int cdv_brightness;
static struct backlight_device *cdv_backlight_device;
-static int cdv_get_brightness(struct backlight_device *bd)
+static int cdv_backlight_combination_mode(struct drm_device *dev)
{
- /* return locally cached var instead of HW read (due to DPST etc.) */
- /* FIXME: ideally return actual value in case firmware fiddled with
- it */
- return cdv_brightness;
+ return REG_READ(BLC_PWM_CTL2) & PWM_LEGACY_MODE;
}
-
-static int cdv_backlight_setup(struct drm_device *dev)
+static int cdv_get_brightness(struct backlight_device *bd)
{
- struct drm_psb_private *dev_priv = dev->dev_private;
- unsigned long core_clock;
- /* u32 bl_max_freq; */
- /* unsigned long value; */
- u16 bl_max_freq;
- uint32_t value;
- uint32_t blc_pwm_precision_factor;
-
- /* get bl_max_freq and pol from dev_priv*/
- if (!dev_priv->lvds_bl) {
- dev_err(dev->dev, "Has no valid LVDS backlight info\n");
- return -ENOENT;
- }
- bl_max_freq = dev_priv->lvds_bl->freq;
- blc_pwm_precision_factor = PSB_BLC_PWM_PRECISION_FACTOR;
+ struct drm_device *dev = bl_get_data(bd);
+ u32 val = REG_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
- core_clock = dev_priv->core_freq;
+ if (cdv_backlight_combination_mode(dev)) {
+ u8 lbpc;
- value = (core_clock * MHz) / BLC_PWM_FREQ_CALC_CONSTANT;
- value *= blc_pwm_precision_factor;
- value /= bl_max_freq;
- value /= blc_pwm_precision_factor;
+ val &= ~1;
+ pci_read_config_byte(dev->pdev, 0xF4, &lbpc);
+ val *= lbpc;
+ }
+ return val;
+}
- if (value > (unsigned long long)PSB_BLC_MAX_PWM_REG_FREQ ||
- value < (unsigned long long)PSB_BLC_MIN_PWM_REG_FREQ)
- return -ERANGE;
- else {
- /* FIXME */
+static u32 cdv_get_max_backlight(struct drm_device *dev)
+{
+ u32 max = REG_READ(BLC_PWM_CTL);
+
+ if (max == 0) {
+ DRM_DEBUG_KMS("LVDS Panel PWM value is 0!\n");
+ /* i915 does this, I believe which means that we should not
+ * smash PWM control as firmware will take control of it. */
+ return 1;
}
- return 0;
+
+ max >>= 16;
+ if (cdv_backlight_combination_mode(dev))
+ max *= 0xff;
+ return max;
}
static int cdv_set_brightness(struct backlight_device *bd)
{
+ struct drm_device *dev = bl_get_data(bd);
int level = bd->props.brightness;
+ u32 blc_pwm_ctl;
/* Percentage 1-100% being valid */
if (level < 1)
level = 1;
- /*cdv_intel_lvds_set_brightness(dev, level); FIXME */
- cdv_brightness = level;
+ if (cdv_backlight_combination_mode(dev)) {
+ u32 max = cdv_get_max_backlight(dev);
+ u8 lbpc;
+
+ lbpc = level * 0xfe / max + 1;
+ level /= lbpc;
+
+ pci_write_config_byte(dev->pdev, 0xF4, lbpc);
+ }
+
+ blc_pwm_ctl = REG_READ(BLC_PWM_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+ REG_WRITE(BLC_PWM_CTL, (blc_pwm_ctl |
+ (level << BACKLIGHT_DUTY_CYCLE_SHIFT)));
return 0;
}
@@ -147,7 +144,6 @@ static const struct backlight_ops cdv_ops = {
static int cdv_backlight_init(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
- int ret;
struct backlight_properties props;
memset(&props, 0, sizeof(struct backlight_properties));
@@ -159,14 +155,9 @@ static int cdv_backlight_init(struct drm_device *dev)
if (IS_ERR(cdv_backlight_device))
return PTR_ERR(cdv_backlight_device);
- ret = cdv_backlight_setup(dev);
- if (ret < 0) {
- backlight_device_unregister(cdv_backlight_device);
- cdv_backlight_device = NULL;
- return ret;
- }
- cdv_backlight_device->props.brightness = 100;
- cdv_backlight_device->props.max_brightness = 100;
+ cdv_backlight_device->props.brightness =
+ cdv_get_brightness(cdv_backlight_device);
+ cdv_backlight_device->props.max_brightness = cdv_get_max_backlight(dev);
backlight_update_status(cdv_backlight_device);
dev_priv->backlight_device = cdv_backlight_device;
return 0;
@@ -238,6 +229,19 @@ static void cdv_init_pm(struct drm_device *dev)
dev_err(dev->dev, "GPU: power management timed out.\n");
}
+static void cdv_errata(struct drm_device *dev)
+{
+ /* Disable bonus launch.
+ * CPU and GPU competes for memory and display misses updates and
+ * flickers. Worst with dual core, dual displays.
+ *
+ * Fixes were done to Win 7 gfx driver to disable a feature called
+ * Bonus Launch to work around the issue, by degrading
+ * performance.
+ */
+ CDV_MSG_WRITE32(3, 0x30, 0x08027108);
+}
+
/**
* cdv_save_display_registers - save registers lost on suspend
* @dev: our DRM device
@@ -251,7 +255,7 @@ static int cdv_save_display_registers(struct drm_device *dev)
struct psb_save_area *regs = &dev_priv->regs;
struct drm_connector *connector;
- dev_info(dev->dev, "Saving GPU registers.\n");
+ dev_dbg(dev->dev, "Saving GPU registers.\n");
pci_read_config_byte(dev->pdev, 0xF4, &regs->cdv.saveLBB);
@@ -355,7 +359,7 @@ static int cdv_restore_display_registers(struct drm_device *dev)
REG_WRITE(PSB_INT_MASK_R, regs->cdv.saveIMR);
/* Fix arbitration bug */
- CDV_MSG_WRITE32(3, 0x30, 0x08027108);
+ cdv_errata(dev);
drm_mode_config_reset(dev);
@@ -447,13 +451,106 @@ static void cdv_get_core_freq(struct drm_device *dev)
}
}
+static void cdv_hotplug_work_func(struct work_struct *work)
+{
+ struct drm_psb_private *dev_priv = container_of(work, struct drm_psb_private,
+ hotplug_work);
+ struct drm_device *dev = dev_priv->dev;
+
+ /* Just fire off a uevent and let userspace tell us what to do */
+ drm_helper_hpd_irq_event(dev);
+}
+
+/* The core driver has received a hotplug IRQ. We are in IRQ context
+ so extract the needed information and kick off queued processing */
+
+static int cdv_hotplug_event(struct drm_device *dev)
+{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ schedule_work(&dev_priv->hotplug_work);
+ REG_WRITE(PORT_HOTPLUG_STAT, REG_READ(PORT_HOTPLUG_STAT));
+ return 1;
+}
+
+static void cdv_hotplug_enable(struct drm_device *dev, bool on)
+{
+ if (on) {
+ u32 hotplug = REG_READ(PORT_HOTPLUG_EN);
+ hotplug |= HDMIB_HOTPLUG_INT_EN | HDMIC_HOTPLUG_INT_EN |
+ HDMID_HOTPLUG_INT_EN | CRT_HOTPLUG_INT_EN;
+ REG_WRITE(PORT_HOTPLUG_EN, hotplug);
+ } else {
+ REG_WRITE(PORT_HOTPLUG_EN, 0);
+ REG_WRITE(PORT_HOTPLUG_STAT, REG_READ(PORT_HOTPLUG_STAT));
+ }
+}
+
+/* Cedarview */
+static const struct psb_offset cdv_regmap[2] = {
+ {
+ .fp0 = FPA0,
+ .fp1 = FPA1,
+ .cntr = DSPACNTR,
+ .conf = PIPEACONF,
+ .src = PIPEASRC,
+ .dpll = DPLL_A,
+ .dpll_md = DPLL_A_MD,
+ .htotal = HTOTAL_A,
+ .hblank = HBLANK_A,
+ .hsync = HSYNC_A,
+ .vtotal = VTOTAL_A,
+ .vblank = VBLANK_A,
+ .vsync = VSYNC_A,
+ .stride = DSPASTRIDE,
+ .size = DSPASIZE,
+ .pos = DSPAPOS,
+ .base = DSPABASE,
+ .surf = DSPASURF,
+ .addr = DSPABASE,
+ .status = PIPEASTAT,
+ .linoff = DSPALINOFF,
+ .tileoff = DSPATILEOFF,
+ .palette = PALETTE_A,
+ },
+ {
+ .fp0 = FPB0,
+ .fp1 = FPB1,
+ .cntr = DSPBCNTR,
+ .conf = PIPEBCONF,
+ .src = PIPEBSRC,
+ .dpll = DPLL_B,
+ .dpll_md = DPLL_B_MD,
+ .htotal = HTOTAL_B,
+ .hblank = HBLANK_B,
+ .hsync = HSYNC_B,
+ .vtotal = VTOTAL_B,
+ .vblank = VBLANK_B,
+ .vsync = VSYNC_B,
+ .stride = DSPBSTRIDE,
+ .size = DSPBSIZE,
+ .pos = DSPBPOS,
+ .base = DSPBBASE,
+ .surf = DSPBSURF,
+ .addr = DSPBBASE,
+ .status = PIPEBSTAT,
+ .linoff = DSPBLINOFF,
+ .tileoff = DSPBTILEOFF,
+ .palette = PALETTE_B,
+ }
+};
+
static int cdv_chip_setup(struct drm_device *dev)
{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ INIT_WORK(&dev_priv->hotplug_work, cdv_hotplug_work_func);
+
+ if (pci_enable_msi(dev->pdev))
+ dev_warn(dev->dev, "Enabling MSI failed!\n");
+ dev_priv->regmap = cdv_regmap;
cdv_get_core_freq(dev);
- gma_intel_opregion_init(dev);
+ psb_intel_opregion_init(dev);
psb_intel_init_bios(dev);
- REG_WRITE(PORT_HOTPLUG_EN, 0);
- REG_WRITE(PORT_HOTPLUG_STAT, REG_READ(PORT_HOTPLUG_STAT));
+ cdv_hotplug_enable(dev, false);
return 0;
}
@@ -464,13 +561,19 @@ const struct psb_ops cdv_chip_ops = {
.accel_2d = 0,
.pipes = 2,
.crtcs = 2,
+ .hdmi_mask = (1 << 0) | (1 << 1),
+ .lvds_mask = (1 << 1),
+ .cursor_needs_phys = 0,
.sgx_offset = MRST_SGX_OFFSET,
.chip_setup = cdv_chip_setup,
+ .errata = cdv_errata,
.crtc_helper = &cdv_intel_helper_funcs,
.crtc_funcs = &cdv_intel_crtc_funcs,
.output_init = cdv_output_init,
+ .hotplug = cdv_hotplug_event,
+ .hotplug_enable = cdv_hotplug_enable,
#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
.backlight_init = cdv_backlight_init,
diff --git a/drivers/gpu/drm/gma500/cdv_intel_crt.c b/drivers/gpu/drm/gma500/cdv_intel_crt.c
index a71a6cd95bdd..187422018601 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_crt.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_crt.c
@@ -67,8 +67,6 @@ static void cdv_intel_crt_dpms(struct drm_encoder *encoder, int mode)
static int cdv_intel_crt_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
- struct drm_psb_private *dev_priv = connector->dev->dev_private;
- int max_clock = 0;
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
return MODE_NO_DBLESCAN;
@@ -77,18 +75,9 @@ static int cdv_intel_crt_mode_valid(struct drm_connector *connector,
return MODE_CLOCK_LOW;
/* The max clock for CDV is 355 instead of 400 */
- max_clock = 355000;
- if (mode->clock > max_clock)
+ if (mode->clock > 355000)
return MODE_CLOCK_HIGH;
- if (mode->hdisplay > 1680 || mode->vdisplay > 1050)
- return MODE_PANEL;
-
- /* We assume worst case scenario of 32 bpp here, since we don't know */
- if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) >
- dev_priv->vram_stolen_size)
- return MODE_MEM;
-
return MODE_OK;
}
@@ -156,13 +145,7 @@ static bool cdv_intel_crt_detect_hotplug(struct drm_connector *connector,
struct drm_device *dev = connector->dev;
u32 hotplug_en;
int i, tries = 0, ret = false;
- u32 adpa_orig;
-
- /* disable the DAC when doing the hotplug detection */
-
- adpa_orig = REG_READ(ADPA);
-
- REG_WRITE(ADPA, adpa_orig & ~(ADPA_DAC_ENABLE));
+ u32 orig;
/*
* On a CDV thep, CRT detect sequence need to be done twice
@@ -170,7 +153,7 @@ static bool cdv_intel_crt_detect_hotplug(struct drm_connector *connector,
*/
tries = 2;
- hotplug_en = REG_READ(PORT_HOTPLUG_EN);
+ orig = hotplug_en = REG_READ(PORT_HOTPLUG_EN);
hotplug_en &= ~(CRT_HOTPLUG_DETECT_MASK);
hotplug_en |= CRT_HOTPLUG_FORCE_DETECT;
@@ -195,8 +178,11 @@ static bool cdv_intel_crt_detect_hotplug(struct drm_connector *connector,
CRT_HOTPLUG_MONITOR_NONE)
ret = true;
- /* Restore the saved ADPA */
- REG_WRITE(ADPA, adpa_orig);
+ /* clear the interrupt we just generated, if any */
+ REG_WRITE(PORT_HOTPLUG_STAT, CRT_HOTPLUG_INT_STATUS);
+
+ /* and put the bits back */
+ REG_WRITE(PORT_HOTPLUG_EN, orig);
return ret;
}
diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c
index be8455919b33..c3e9a0f701df 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_display.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_display.c
@@ -216,22 +216,22 @@ static void cdv_sb_reset(struct drm_device *dev)
*/
static int
cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc,
- struct cdv_intel_clock_t *clock)
+ struct cdv_intel_clock_t *clock, bool is_lvds)
{
- struct psb_intel_crtc *psb_crtc =
- to_psb_intel_crtc(crtc);
+ struct psb_intel_crtc *psb_crtc = to_psb_intel_crtc(crtc);
int pipe = psb_crtc->pipe;
u32 m, n_vco, p;
int ret = 0;
int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
+ int ref_sfr = (pipe == 0) ? SB_REF_DPLLA : SB_REF_DPLLB;
u32 ref_value;
+ u32 lane_reg, lane_value;
cdv_sb_reset(dev);
- if ((REG_READ(dpll_reg) & DPLL_SYNCLOCK_ENABLE) == 0) {
- DRM_ERROR("Attempting to set DPLL with refclk disabled\n");
- return -EBUSY;
- }
+ REG_WRITE(dpll_reg, DPLL_SYNCLOCK_ENABLE | DPLL_VGA_MODE_DIS);
+
+ udelay(100);
/* Follow the BIOS and write the REF/SFR Register. Hardcoded value */
ref_value = 0x68A701;
@@ -241,6 +241,35 @@ cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc,
/* We don't know what the other fields of these regs are, so
* leave them in place.
*/
+ /*
+ * The BIT 14:13 of 0x8010/0x8030 is used to select the ref clk
+ * for the pipe A/B. Display spec 1.06 has wrong definition.
+ * Correct definition is like below:
+ *
+ * refclka mean use clock from same PLL
+ *
+ * if DPLLA sets 01 and DPLLB sets 01, they use clock from their pll
+ *
+ * if DPLLA sets 01 and DPLLB sets 02, both use clk from DPLLA
+ *
+ */
+ ret = cdv_sb_read(dev, ref_sfr, &ref_value);
+ if (ret)
+ return ret;
+ ref_value &= ~(REF_CLK_MASK);
+
+ /* use DPLL_A for pipeB on CRT/HDMI */
+ if (pipe == 1 && !is_lvds) {
+ DRM_DEBUG_KMS("use DPLLA for pipe B\n");
+ ref_value |= REF_CLK_DPLLA;
+ } else {
+ DRM_DEBUG_KMS("use their DPLL for pipe A/B\n");
+ ref_value |= REF_CLK_DPLL;
+ }
+ ret = cdv_sb_write(dev, ref_sfr, ref_value);
+ if (ret)
+ return ret;
+
ret = cdv_sb_read(dev, SB_M(pipe), &m);
if (ret)
return ret;
@@ -307,36 +336,29 @@ cdv_dpll_set_clock_cdv(struct drm_device *dev, struct drm_crtc *crtc,
if (ret)
return ret;
- /* always Program the Lane Register for the Pipe A*/
- if (pipe == 0) {
- /* Program the Lane0/1 for HDMI B */
- u32 lane_reg, lane_value;
-
- lane_reg = PSB_LANE0;
- cdv_sb_read(dev, lane_reg, &lane_value);
- lane_value &= ~(LANE_PLL_MASK);
- lane_value |= LANE_PLL_ENABLE;
- cdv_sb_write(dev, lane_reg, lane_value);
-
- lane_reg = PSB_LANE1;
- cdv_sb_read(dev, lane_reg, &lane_value);
- lane_value &= ~(LANE_PLL_MASK);
- lane_value |= LANE_PLL_ENABLE;
- cdv_sb_write(dev, lane_reg, lane_value);
-
- /* Program the Lane2/3 for HDMI C */
- lane_reg = PSB_LANE2;
- cdv_sb_read(dev, lane_reg, &lane_value);
- lane_value &= ~(LANE_PLL_MASK);
- lane_value |= LANE_PLL_ENABLE;
- cdv_sb_write(dev, lane_reg, lane_value);
-
- lane_reg = PSB_LANE3;
- cdv_sb_read(dev, lane_reg, &lane_value);
- lane_value &= ~(LANE_PLL_MASK);
- lane_value |= LANE_PLL_ENABLE;
- cdv_sb_write(dev, lane_reg, lane_value);
- }
+ lane_reg = PSB_LANE0;
+ cdv_sb_read(dev, lane_reg, &lane_value);
+ lane_value &= ~(LANE_PLL_MASK);
+ lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
+ cdv_sb_write(dev, lane_reg, lane_value);
+
+ lane_reg = PSB_LANE1;
+ cdv_sb_read(dev, lane_reg, &lane_value);
+ lane_value &= ~(LANE_PLL_MASK);
+ lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
+ cdv_sb_write(dev, lane_reg, lane_value);
+
+ lane_reg = PSB_LANE2;
+ cdv_sb_read(dev, lane_reg, &lane_value);
+ lane_value &= ~(LANE_PLL_MASK);
+ lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
+ cdv_sb_write(dev, lane_reg, lane_value);
+
+ lane_reg = PSB_LANE3;
+ cdv_sb_read(dev, lane_reg, &lane_value);
+ lane_value &= ~(LANE_PLL_MASK);
+ lane_value |= LANE_PLL_ENABLE | LANE_PLL_PIPE(pipe);
+ cdv_sb_write(dev, lane_reg, lane_value);
return 0;
}
@@ -480,14 +502,12 @@ static int cdv_intel_pipe_set_base(struct drm_crtc *crtc,
int x, int y, struct drm_framebuffer *old_fb)
{
struct drm_device *dev = crtc->dev;
+ struct drm_psb_private *dev_priv = dev->dev_private;
struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
int pipe = psb_intel_crtc->pipe;
+ const struct psb_offset *map = &dev_priv->regmap[pipe];
unsigned long start, offset;
- int dspbase = (pipe == 0 ? DSPABASE : DSPBBASE);
- int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF);
- int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE;
- int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
u32 dspcntr;
int ret = 0;
@@ -509,9 +529,9 @@ static int cdv_intel_pipe_set_base(struct drm_crtc *crtc,
start = psbfb->gtt->offset;
offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8);
- REG_WRITE(dspstride, crtc->fb->pitches[0]);
+ REG_WRITE(map->stride, crtc->fb->pitches[0]);
- dspcntr = REG_READ(dspcntr_reg);
+ dspcntr = REG_READ(map->cntr);
dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
switch (crtc->fb->bits_per_pixel) {
@@ -533,15 +553,15 @@ static int cdv_intel_pipe_set_base(struct drm_crtc *crtc,
ret = -EINVAL;
goto psb_intel_pipe_set_base_exit;
}
- REG_WRITE(dspcntr_reg, dspcntr);
+ REG_WRITE(map->cntr, dspcntr);
dev_dbg(dev->dev,
"Writing base %08lX %08lX %d %d\n", start, offset, x, y);
- REG_WRITE(dspbase, offset);
- REG_READ(dspbase);
- REG_WRITE(dspsurf, start);
- REG_READ(dspsurf);
+ REG_WRITE(map->base, offset);
+ REG_READ(map->base);
+ REG_WRITE(map->surf, start);
+ REG_READ(map->surf);
psb_intel_pipe_cleaner:
/* If there was a previous display we can now unpin it */
@@ -553,6 +573,199 @@ psb_intel_pipe_set_base_exit:
return ret;
}
+#define FIFO_PIPEA (1 << 0)
+#define FIFO_PIPEB (1 << 1)
+
+static bool cdv_intel_pipe_enabled(struct drm_device *dev, int pipe)
+{
+ struct drm_crtc *crtc;
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ struct psb_intel_crtc *psb_intel_crtc = NULL;
+
+ crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+ psb_intel_crtc = to_psb_intel_crtc(crtc);
+
+ if (crtc->fb == NULL || !psb_intel_crtc->active)
+ return false;
+ return true;
+}
+
+static bool cdv_intel_single_pipe_active (struct drm_device *dev)
+{
+ uint32_t pipe_enabled = 0;
+
+ if (cdv_intel_pipe_enabled(dev, 0))
+ pipe_enabled |= FIFO_PIPEA;
+
+ if (cdv_intel_pipe_enabled(dev, 1))
+ pipe_enabled |= FIFO_PIPEB;
+
+
+ DRM_DEBUG_KMS("pipe enabled %x\n", pipe_enabled);
+
+ if (pipe_enabled == FIFO_PIPEA || pipe_enabled == FIFO_PIPEB)
+ return true;
+ else
+ return false;
+}
+
+static bool is_pipeb_lvds(struct drm_device *dev, struct drm_crtc *crtc)
+{
+ struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
+ struct drm_mode_config *mode_config = &dev->mode_config;
+ struct drm_connector *connector;
+
+ if (psb_intel_crtc->pipe != 1)
+ return false;
+
+ list_for_each_entry(connector, &mode_config->connector_list, head) {
+ struct psb_intel_encoder *psb_intel_encoder =
+ psb_intel_attached_encoder(connector);
+
+ if (!connector->encoder
+ || connector->encoder->crtc != crtc)
+ continue;
+
+ if (psb_intel_encoder->type == INTEL_OUTPUT_LVDS)
+ return true;
+ }
+
+ return false;
+}
+
+static void cdv_intel_disable_self_refresh (struct drm_device *dev)
+{
+ if (REG_READ(FW_BLC_SELF) & FW_BLC_SELF_EN) {
+
+ /* Disable self-refresh before adjust WM */
+ REG_WRITE(FW_BLC_SELF, (REG_READ(FW_BLC_SELF) & ~FW_BLC_SELF_EN));
+ REG_READ(FW_BLC_SELF);
+
+ cdv_intel_wait_for_vblank(dev);
+
+ /* Cedarview workaround to write ovelay plane, which force to leave
+ * MAX_FIFO state.
+ */
+ REG_WRITE(OV_OVADD, 0/*dev_priv->ovl_offset*/);
+ REG_READ(OV_OVADD);
+
+ cdv_intel_wait_for_vblank(dev);
+ }
+
+}
+
+static void cdv_intel_update_watermark (struct drm_device *dev, struct drm_crtc *crtc)
+{
+
+ if (cdv_intel_single_pipe_active(dev)) {
+ u32 fw;
+
+ fw = REG_READ(DSPFW1);
+ fw &= ~DSP_FIFO_SR_WM_MASK;
+ fw |= (0x7e << DSP_FIFO_SR_WM_SHIFT);
+ fw &= ~CURSOR_B_FIFO_WM_MASK;
+ fw |= (0x4 << CURSOR_B_FIFO_WM_SHIFT);
+ REG_WRITE(DSPFW1, fw);
+
+ fw = REG_READ(DSPFW2);
+ fw &= ~CURSOR_A_FIFO_WM_MASK;
+ fw |= (0x6 << CURSOR_A_FIFO_WM_SHIFT);
+ fw &= ~DSP_PLANE_C_FIFO_WM_MASK;
+ fw |= (0x8 << DSP_PLANE_C_FIFO_WM_SHIFT);
+ REG_WRITE(DSPFW2, fw);
+
+ REG_WRITE(DSPFW3, 0x36000000);
+
+ /* ignore FW4 */
+
+ if (is_pipeb_lvds(dev, crtc)) {
+ REG_WRITE(DSPFW5, 0x00040330);
+ } else {
+ fw = (3 << DSP_PLANE_B_FIFO_WM1_SHIFT) |
+ (4 << DSP_PLANE_A_FIFO_WM1_SHIFT) |
+ (3 << CURSOR_B_FIFO_WM1_SHIFT) |
+ (4 << CURSOR_FIFO_SR_WM1_SHIFT);
+ REG_WRITE(DSPFW5, fw);
+ }
+
+ REG_WRITE(DSPFW6, 0x10);
+
+ cdv_intel_wait_for_vblank(dev);
+
+ /* enable self-refresh for single pipe active */
+ REG_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
+ REG_READ(FW_BLC_SELF);
+ cdv_intel_wait_for_vblank(dev);
+
+ } else {
+
+ /* HW team suggested values... */
+ REG_WRITE(DSPFW1, 0x3f880808);
+ REG_WRITE(DSPFW2, 0x0b020202);
+ REG_WRITE(DSPFW3, 0x24000000);
+ REG_WRITE(DSPFW4, 0x08030202);
+ REG_WRITE(DSPFW5, 0x01010101);
+ REG_WRITE(DSPFW6, 0x1d0);
+
+ cdv_intel_wait_for_vblank(dev);
+
+ cdv_intel_disable_self_refresh(dev);
+
+ }
+}
+
+/** Loads the palette/gamma unit for the CRTC with the prepared values */
+static void cdv_intel_crtc_load_lut(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
+ int palreg = PALETTE_A;
+ int i;
+
+ /* The clocks have to be on to load the palette. */
+ if (!crtc->enabled)
+ return;
+
+ switch (psb_intel_crtc->pipe) {
+ case 0:
+ break;
+ case 1:
+ palreg = PALETTE_B;
+ break;
+ case 2:
+ palreg = PALETTE_C;
+ break;
+ default:
+ dev_err(dev->dev, "Illegal Pipe Number.\n");
+ return;
+ }
+
+ if (gma_power_begin(dev, false)) {
+ for (i = 0; i < 256; i++) {
+ REG_WRITE(palreg + 4 * i,
+ ((psb_intel_crtc->lut_r[i] +
+ psb_intel_crtc->lut_adj[i]) << 16) |
+ ((psb_intel_crtc->lut_g[i] +
+ psb_intel_crtc->lut_adj[i]) << 8) |
+ (psb_intel_crtc->lut_b[i] +
+ psb_intel_crtc->lut_adj[i]));
+ }
+ gma_power_end(dev);
+ } else {
+ for (i = 0; i < 256; i++) {
+ dev_priv->regs.pipe[0].palette[i] =
+ ((psb_intel_crtc->lut_r[i] +
+ psb_intel_crtc->lut_adj[i]) << 16) |
+ ((psb_intel_crtc->lut_g[i] +
+ psb_intel_crtc->lut_adj[i]) << 8) |
+ (psb_intel_crtc->lut_b[i] +
+ psb_intel_crtc->lut_adj[i]);
+ }
+
+ }
+}
+
/**
* Sets the power management mode of the pipe and plane.
*
@@ -562,62 +775,80 @@ psb_intel_pipe_set_base_exit:
static void cdv_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
{
struct drm_device *dev = crtc->dev;
+ struct drm_psb_private *dev_priv = dev->dev_private;
struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
int pipe = psb_intel_crtc->pipe;
- int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
- int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
- int dspbase_reg = (pipe == 0) ? DSPABASE : DSPBBASE;
- int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
+ const struct psb_offset *map = &dev_priv->regmap[pipe];
u32 temp;
/* XXX: When our outputs are all unaware of DPMS modes other than off
* and on, we should map those modes to DRM_MODE_DPMS_OFF in the CRTC.
*/
+ cdv_intel_disable_self_refresh(dev);
+
switch (mode) {
case DRM_MODE_DPMS_ON:
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
+ if (psb_intel_crtc->active)
+ return;
+
+ psb_intel_crtc->active = true;
+
/* Enable the DPLL */
- temp = REG_READ(dpll_reg);
+ temp = REG_READ(map->dpll);
if ((temp & DPLL_VCO_ENABLE) == 0) {
- REG_WRITE(dpll_reg, temp);
- REG_READ(dpll_reg);
+ REG_WRITE(map->dpll, temp);
+ REG_READ(map->dpll);
/* Wait for the clocks to stabilize. */
udelay(150);
- REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
- REG_READ(dpll_reg);
+ REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE);
+ REG_READ(map->dpll);
/* Wait for the clocks to stabilize. */
udelay(150);
- REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
- REG_READ(dpll_reg);
+ REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE);
+ REG_READ(map->dpll);
/* Wait for the clocks to stabilize. */
udelay(150);
}
/* Jim Bish - switch plan and pipe per scott */
/* Enable the plane */
- temp = REG_READ(dspcntr_reg);
+ temp = REG_READ(map->cntr);
if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
- REG_WRITE(dspcntr_reg,
+ REG_WRITE(map->cntr,
temp | DISPLAY_PLANE_ENABLE);
/* Flush the plane changes */
- REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
+ REG_WRITE(map->base, REG_READ(map->base));
}
udelay(150);
/* Enable the pipe */
- temp = REG_READ(pipeconf_reg);
+ temp = REG_READ(map->conf);
if ((temp & PIPEACONF_ENABLE) == 0)
- REG_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE);
+ REG_WRITE(map->conf, temp | PIPEACONF_ENABLE);
+
+ temp = REG_READ(map->status);
+ temp &= ~(0xFFFF);
+ temp |= PIPE_FIFO_UNDERRUN;
+ REG_WRITE(map->status, temp);
+ REG_READ(map->status);
- psb_intel_crtc_load_lut(crtc);
+ cdv_intel_update_watermark(dev, crtc);
+ cdv_intel_crtc_load_lut(crtc);
/* Give the overlay scaler a chance to enable
* if it's on this pipe */
/* psb_intel_crtc_dpms_video(crtc, true); TODO */
+ psb_intel_crtc->crtc_enable = true;
break;
case DRM_MODE_DPMS_OFF:
+ if (!psb_intel_crtc->active)
+ return;
+
+ psb_intel_crtc->active = false;
+
/* Give the overlay scaler a chance to disable
* if it's on this pipe */
/* psb_intel_crtc_dpms_video(crtc, FALSE); TODO */
@@ -627,14 +858,15 @@ static void cdv_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
/* Jim Bish - changed pipe/plane here as well. */
+ drm_vblank_off(dev, pipe);
/* Wait for vblank for the disable to take effect */
cdv_intel_wait_for_vblank(dev);
/* Next, disable display pipes */
- temp = REG_READ(pipeconf_reg);
+ temp = REG_READ(map->conf);
if ((temp & PIPEACONF_ENABLE) != 0) {
- REG_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
- REG_READ(pipeconf_reg);
+ REG_WRITE(map->conf, temp & ~PIPEACONF_ENABLE);
+ REG_READ(map->conf);
}
/* Wait for vblank for the disable to take effect. */
@@ -643,23 +875,25 @@ static void cdv_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
udelay(150);
/* Disable display plane */
- temp = REG_READ(dspcntr_reg);
+ temp = REG_READ(map->cntr);
if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
- REG_WRITE(dspcntr_reg,
+ REG_WRITE(map->cntr,
temp & ~DISPLAY_PLANE_ENABLE);
/* Flush the plane changes */
- REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
- REG_READ(dspbase_reg);
+ REG_WRITE(map->base, REG_READ(map->base));
+ REG_READ(map->base);
}
- temp = REG_READ(dpll_reg);
+ temp = REG_READ(map->dpll);
if ((temp & DPLL_VCO_ENABLE) != 0) {
- REG_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE);
- REG_READ(dpll_reg);
+ REG_WRITE(map->dpll, temp & ~DPLL_VCO_ENABLE);
+ REG_READ(map->dpll);
}
/* Wait for the clocks to turn off. */
udelay(150);
+ cdv_intel_update_watermark(dev, crtc);
+ psb_intel_crtc->crtc_enable = false;
break;
}
/*Set FIFO Watermarks*/
@@ -709,21 +943,10 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
struct drm_framebuffer *old_fb)
{
struct drm_device *dev = crtc->dev;
+ struct drm_psb_private *dev_priv = dev->dev_private;
struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
int pipe = psb_intel_crtc->pipe;
- int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
- int dpll_md_reg = (psb_intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD;
- int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
- int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
- int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
- int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
- int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
- int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
- int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
- int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
- int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE;
- int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS;
- int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
+ const struct psb_offset *map = &dev_priv->regmap[pipe];
int refclk;
struct cdv_intel_clock_t clock;
u32 dpll = 0, dspcntr, pipeconf;
@@ -757,13 +980,18 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
}
}
- refclk = 96000;
-
- /* Hack selection about ref clk for CRT */
- /* Select 27MHz as the reference clk for HDMI */
- if (is_crt || is_hdmi)
+ if (dev_priv->dplla_96mhz)
+ /* low-end sku, 96/100 mhz */
+ refclk = 96000;
+ else
+ /* high-end sku, 27/100 mhz */
refclk = 27000;
+ if (is_lvds && dev_priv->lvds_use_ssc) {
+ refclk = dev_priv->lvds_ssc_freq * 1000;
+ DRM_DEBUG_KMS("Use SSC reference clock %d Mhz\n", dev_priv->lvds_ssc_freq);
+ }
+
drm_mode_debug_printmodeline(adjusted_mode);
ok = cdv_intel_find_best_PLL(crtc, adjusted_mode->clock, refclk,
@@ -779,18 +1007,17 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
/* dpll |= PLL_REF_INPUT_TVCLKINBC; */
dpll |= 3;
}
- dpll |= PLL_REF_INPUT_DREFCLK;
+/* dpll |= PLL_REF_INPUT_DREFCLK; */
dpll |= DPLL_SYNCLOCK_ENABLE;
- dpll |= DPLL_VGA_MODE_DIS;
- if (is_lvds)
+/* if (is_lvds)
dpll |= DPLLB_MODE_LVDS;
else
- dpll |= DPLLB_MODE_DAC_SERIAL;
+ dpll |= DPLLB_MODE_DAC_SERIAL; */
/* dpll |= (2 << 11); */
/* setup pipeconf */
- pipeconf = REG_READ(pipeconf_reg);
+ pipeconf = REG_READ(map->conf);
/* Set up the display plane register */
dspcntr = DISPPLANE_GAMMA_ENABLE;
@@ -803,10 +1030,10 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
dspcntr |= DISPLAY_PLANE_ENABLE;
pipeconf |= PIPEACONF_ENABLE;
- REG_WRITE(dpll_reg, dpll | DPLL_VGA_MODE_DIS | DPLL_SYNCLOCK_ENABLE);
- REG_READ(dpll_reg);
+ REG_WRITE(map->dpll, dpll | DPLL_VGA_MODE_DIS | DPLL_SYNCLOCK_ENABLE);
+ REG_READ(map->dpll);
- cdv_dpll_set_clock_cdv(dev, crtc, &clock);
+ cdv_dpll_set_clock_cdv(dev, crtc, &clock, is_lvds);
udelay(150);
@@ -848,48 +1075,48 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
drm_mode_debug_printmodeline(mode);
- REG_WRITE(dpll_reg,
- (REG_READ(dpll_reg) & ~DPLL_LOCK) | DPLL_VCO_ENABLE);
- REG_READ(dpll_reg);
+ REG_WRITE(map->dpll,
+ (REG_READ(map->dpll) & ~DPLL_LOCK) | DPLL_VCO_ENABLE);
+ REG_READ(map->dpll);
/* Wait for the clocks to stabilize. */
udelay(150); /* 42 usec w/o calibration, 110 with. rounded up. */
- if (!(REG_READ(dpll_reg) & DPLL_LOCK)) {
+ if (!(REG_READ(map->dpll) & DPLL_LOCK)) {
dev_err(dev->dev, "Failed to get DPLL lock\n");
return -EBUSY;
}
{
int sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
- REG_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT));
+ REG_WRITE(map->dpll_md, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) | ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT));
}
- REG_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
+ REG_WRITE(map->htotal, (adjusted_mode->crtc_hdisplay - 1) |
((adjusted_mode->crtc_htotal - 1) << 16));
- REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) |
+ REG_WRITE(map->hblank, (adjusted_mode->crtc_hblank_start - 1) |
((adjusted_mode->crtc_hblank_end - 1) << 16));
- REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) |
+ REG_WRITE(map->hsync, (adjusted_mode->crtc_hsync_start - 1) |
((adjusted_mode->crtc_hsync_end - 1) << 16));
- REG_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) |
+ REG_WRITE(map->vtotal, (adjusted_mode->crtc_vdisplay - 1) |
((adjusted_mode->crtc_vtotal - 1) << 16));
- REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) |
+ REG_WRITE(map->vblank, (adjusted_mode->crtc_vblank_start - 1) |
((adjusted_mode->crtc_vblank_end - 1) << 16));
- REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) |
+ REG_WRITE(map->vsync, (adjusted_mode->crtc_vsync_start - 1) |
((adjusted_mode->crtc_vsync_end - 1) << 16));
/* pipesrc and dspsize control the size that is scaled from,
* which should always be the user's requested size.
*/
- REG_WRITE(dspsize_reg,
+ REG_WRITE(map->size,
((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1));
- REG_WRITE(dsppos_reg, 0);
- REG_WRITE(pipesrc_reg,
+ REG_WRITE(map->pos, 0);
+ REG_WRITE(map->src,
((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
- REG_WRITE(pipeconf_reg, pipeconf);
- REG_READ(pipeconf_reg);
+ REG_WRITE(map->conf, pipeconf);
+ REG_READ(map->conf);
cdv_intel_wait_for_vblank(dev);
- REG_WRITE(dspcntr_reg, dspcntr);
+ REG_WRITE(map->cntr, dspcntr);
/* Flush the plane changes */
{
@@ -903,58 +1130,6 @@ static int cdv_intel_crtc_mode_set(struct drm_crtc *crtc,
return 0;
}
-/** Loads the palette/gamma unit for the CRTC with the prepared values */
-static void cdv_intel_crtc_load_lut(struct drm_crtc *crtc)
-{
- struct drm_device *dev = crtc->dev;
- struct drm_psb_private *dev_priv =
- (struct drm_psb_private *)dev->dev_private;
- struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
- int palreg = PALETTE_A;
- int i;
-
- /* The clocks have to be on to load the palette. */
- if (!crtc->enabled)
- return;
-
- switch (psb_intel_crtc->pipe) {
- case 0:
- break;
- case 1:
- palreg = PALETTE_B;
- break;
- case 2:
- palreg = PALETTE_C;
- break;
- default:
- dev_err(dev->dev, "Illegal Pipe Number.\n");
- return;
- }
-
- if (gma_power_begin(dev, false)) {
- for (i = 0; i < 256; i++) {
- REG_WRITE(palreg + 4 * i,
- ((psb_intel_crtc->lut_r[i] +
- psb_intel_crtc->lut_adj[i]) << 16) |
- ((psb_intel_crtc->lut_g[i] +
- psb_intel_crtc->lut_adj[i]) << 8) |
- (psb_intel_crtc->lut_b[i] +
- psb_intel_crtc->lut_adj[i]));
- }
- gma_power_end(dev);
- } else {
- for (i = 0; i < 256; i++) {
- dev_priv->regs.psb.save_palette_a[i] =
- ((psb_intel_crtc->lut_r[i] +
- psb_intel_crtc->lut_adj[i]) << 16) |
- ((psb_intel_crtc->lut_g[i] +
- psb_intel_crtc->lut_adj[i]) << 8) |
- (psb_intel_crtc->lut_b[i] +
- psb_intel_crtc->lut_adj[i]);
- }
-
- }
-}
/**
* Save HW states of giving crtc
@@ -962,11 +1137,10 @@ static void cdv_intel_crtc_load_lut(struct drm_crtc *crtc)
static void cdv_intel_crtc_save(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
- /* struct drm_psb_private *dev_priv =
- (struct drm_psb_private *)dev->dev_private; */
+ struct drm_psb_private *dev_priv = dev->dev_private;
struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
struct psb_intel_crtc_state *crtc_state = psb_intel_crtc->crtc_state;
- int pipeA = (psb_intel_crtc->pipe == 0);
+ const struct psb_offset *map = &dev_priv->regmap[psb_intel_crtc->pipe];
uint32_t paletteReg;
int i;
@@ -975,25 +1149,25 @@ static void cdv_intel_crtc_save(struct drm_crtc *crtc)
return;
}
- crtc_state->saveDSPCNTR = REG_READ(pipeA ? DSPACNTR : DSPBCNTR);
- crtc_state->savePIPECONF = REG_READ(pipeA ? PIPEACONF : PIPEBCONF);
- crtc_state->savePIPESRC = REG_READ(pipeA ? PIPEASRC : PIPEBSRC);
- crtc_state->saveFP0 = REG_READ(pipeA ? FPA0 : FPB0);
- crtc_state->saveFP1 = REG_READ(pipeA ? FPA1 : FPB1);
- crtc_state->saveDPLL = REG_READ(pipeA ? DPLL_A : DPLL_B);
- crtc_state->saveHTOTAL = REG_READ(pipeA ? HTOTAL_A : HTOTAL_B);
- crtc_state->saveHBLANK = REG_READ(pipeA ? HBLANK_A : HBLANK_B);
- crtc_state->saveHSYNC = REG_READ(pipeA ? HSYNC_A : HSYNC_B);
- crtc_state->saveVTOTAL = REG_READ(pipeA ? VTOTAL_A : VTOTAL_B);
- crtc_state->saveVBLANK = REG_READ(pipeA ? VBLANK_A : VBLANK_B);
- crtc_state->saveVSYNC = REG_READ(pipeA ? VSYNC_A : VSYNC_B);
- crtc_state->saveDSPSTRIDE = REG_READ(pipeA ? DSPASTRIDE : DSPBSTRIDE);
+ crtc_state->saveDSPCNTR = REG_READ(map->cntr);
+ crtc_state->savePIPECONF = REG_READ(map->conf);
+ crtc_state->savePIPESRC = REG_READ(map->src);
+ crtc_state->saveFP0 = REG_READ(map->fp0);
+ crtc_state->saveFP1 = REG_READ(map->fp1);
+ crtc_state->saveDPLL = REG_READ(map->dpll);
+ crtc_state->saveHTOTAL = REG_READ(map->htotal);
+ crtc_state->saveHBLANK = REG_READ(map->hblank);
+ crtc_state->saveHSYNC = REG_READ(map->hsync);
+ crtc_state->saveVTOTAL = REG_READ(map->vtotal);
+ crtc_state->saveVBLANK = REG_READ(map->vblank);
+ crtc_state->saveVSYNC = REG_READ(map->vsync);
+ crtc_state->saveDSPSTRIDE = REG_READ(map->stride);
/*NOTE: DSPSIZE DSPPOS only for psb*/
- crtc_state->saveDSPSIZE = REG_READ(pipeA ? DSPASIZE : DSPBSIZE);
- crtc_state->saveDSPPOS = REG_READ(pipeA ? DSPAPOS : DSPBPOS);
+ crtc_state->saveDSPSIZE = REG_READ(map->size);
+ crtc_state->saveDSPPOS = REG_READ(map->pos);
- crtc_state->saveDSPBASE = REG_READ(pipeA ? DSPABASE : DSPBBASE);
+ crtc_state->saveDSPBASE = REG_READ(map->base);
DRM_DEBUG("(%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x)\n",
crtc_state->saveDSPCNTR,
@@ -1014,7 +1188,7 @@ static void cdv_intel_crtc_save(struct drm_crtc *crtc)
crtc_state->saveDSPBASE
);
- paletteReg = pipeA ? PALETTE_A : PALETTE_B;
+ paletteReg = map->palette;
for (i = 0; i < 256; ++i)
crtc_state->savePalette[i] = REG_READ(paletteReg + (i << 2));
}
@@ -1025,12 +1199,10 @@ static void cdv_intel_crtc_save(struct drm_crtc *crtc)
static void cdv_intel_crtc_restore(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
- /* struct drm_psb_private * dev_priv =
- (struct drm_psb_private *)dev->dev_private; */
+ struct drm_psb_private *dev_priv = dev->dev_private;
struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
struct psb_intel_crtc_state *crtc_state = psb_intel_crtc->crtc_state;
- /* struct drm_crtc_helper_funcs * crtc_funcs = crtc->helper_private; */
- int pipeA = (psb_intel_crtc->pipe == 0);
+ const struct psb_offset *map = &dev_priv->regmap[psb_intel_crtc->pipe];
uint32_t paletteReg;
int i;
@@ -1041,23 +1213,23 @@ static void cdv_intel_crtc_restore(struct drm_crtc *crtc)
DRM_DEBUG(
"current:(%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x)\n",
- REG_READ(pipeA ? DSPACNTR : DSPBCNTR),
- REG_READ(pipeA ? PIPEACONF : PIPEBCONF),
- REG_READ(pipeA ? PIPEASRC : PIPEBSRC),
- REG_READ(pipeA ? FPA0 : FPB0),
- REG_READ(pipeA ? FPA1 : FPB1),
- REG_READ(pipeA ? DPLL_A : DPLL_B),
- REG_READ(pipeA ? HTOTAL_A : HTOTAL_B),
- REG_READ(pipeA ? HBLANK_A : HBLANK_B),
- REG_READ(pipeA ? HSYNC_A : HSYNC_B),
- REG_READ(pipeA ? VTOTAL_A : VTOTAL_B),
- REG_READ(pipeA ? VBLANK_A : VBLANK_B),
- REG_READ(pipeA ? VSYNC_A : VSYNC_B),
- REG_READ(pipeA ? DSPASTRIDE : DSPBSTRIDE),
- REG_READ(pipeA ? DSPASIZE : DSPBSIZE),
- REG_READ(pipeA ? DSPAPOS : DSPBPOS),
- REG_READ(pipeA ? DSPABASE : DSPBBASE)
- );
+ REG_READ(map->cntr),
+ REG_READ(map->conf),
+ REG_READ(map->src),
+ REG_READ(map->fp0),
+ REG_READ(map->fp1),
+ REG_READ(map->dpll),
+ REG_READ(map->htotal),
+ REG_READ(map->hblank),
+ REG_READ(map->hsync),
+ REG_READ(map->vtotal),
+ REG_READ(map->vblank),
+ REG_READ(map->vsync),
+ REG_READ(map->stride),
+ REG_READ(map->size),
+ REG_READ(map->pos),
+ REG_READ(map->base)
+ );
DRM_DEBUG(
"saved: (%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x)\n",
@@ -1077,51 +1249,51 @@ static void cdv_intel_crtc_restore(struct drm_crtc *crtc)
crtc_state->saveDSPSIZE,
crtc_state->saveDSPPOS,
crtc_state->saveDSPBASE
- );
+ );
if (crtc_state->saveDPLL & DPLL_VCO_ENABLE) {
- REG_WRITE(pipeA ? DPLL_A : DPLL_B,
- crtc_state->saveDPLL & ~DPLL_VCO_ENABLE);
- REG_READ(pipeA ? DPLL_A : DPLL_B);
+ REG_WRITE(map->dpll,
+ crtc_state->saveDPLL & ~DPLL_VCO_ENABLE);
+ REG_READ(map->dpll);
DRM_DEBUG("write dpll: %x\n",
- REG_READ(pipeA ? DPLL_A : DPLL_B));
+ REG_READ(map->dpll));
udelay(150);
}
- REG_WRITE(pipeA ? FPA0 : FPB0, crtc_state->saveFP0);
- REG_READ(pipeA ? FPA0 : FPB0);
+ REG_WRITE(map->fp0, crtc_state->saveFP0);
+ REG_READ(map->fp0);
- REG_WRITE(pipeA ? FPA1 : FPB1, crtc_state->saveFP1);
- REG_READ(pipeA ? FPA1 : FPB1);
+ REG_WRITE(map->fp1, crtc_state->saveFP1);
+ REG_READ(map->fp1);
- REG_WRITE(pipeA ? DPLL_A : DPLL_B, crtc_state->saveDPLL);
- REG_READ(pipeA ? DPLL_A : DPLL_B);
+ REG_WRITE(map->dpll, crtc_state->saveDPLL);
+ REG_READ(map->dpll);
udelay(150);
- REG_WRITE(pipeA ? HTOTAL_A : HTOTAL_B, crtc_state->saveHTOTAL);
- REG_WRITE(pipeA ? HBLANK_A : HBLANK_B, crtc_state->saveHBLANK);
- REG_WRITE(pipeA ? HSYNC_A : HSYNC_B, crtc_state->saveHSYNC);
- REG_WRITE(pipeA ? VTOTAL_A : VTOTAL_B, crtc_state->saveVTOTAL);
- REG_WRITE(pipeA ? VBLANK_A : VBLANK_B, crtc_state->saveVBLANK);
- REG_WRITE(pipeA ? VSYNC_A : VSYNC_B, crtc_state->saveVSYNC);
- REG_WRITE(pipeA ? DSPASTRIDE : DSPBSTRIDE, crtc_state->saveDSPSTRIDE);
+ REG_WRITE(map->htotal, crtc_state->saveHTOTAL);
+ REG_WRITE(map->hblank, crtc_state->saveHBLANK);
+ REG_WRITE(map->hsync, crtc_state->saveHSYNC);
+ REG_WRITE(map->vtotal, crtc_state->saveVTOTAL);
+ REG_WRITE(map->vblank, crtc_state->saveVBLANK);
+ REG_WRITE(map->vsync, crtc_state->saveVSYNC);
+ REG_WRITE(map->stride, crtc_state->saveDSPSTRIDE);
- REG_WRITE(pipeA ? DSPASIZE : DSPBSIZE, crtc_state->saveDSPSIZE);
- REG_WRITE(pipeA ? DSPAPOS : DSPBPOS, crtc_state->saveDSPPOS);
+ REG_WRITE(map->size, crtc_state->saveDSPSIZE);
+ REG_WRITE(map->pos, crtc_state->saveDSPPOS);
- REG_WRITE(pipeA ? PIPEASRC : PIPEBSRC, crtc_state->savePIPESRC);
- REG_WRITE(pipeA ? DSPABASE : DSPBBASE, crtc_state->saveDSPBASE);
- REG_WRITE(pipeA ? PIPEACONF : PIPEBCONF, crtc_state->savePIPECONF);
+ REG_WRITE(map->src, crtc_state->savePIPESRC);
+ REG_WRITE(map->base, crtc_state->saveDSPBASE);
+ REG_WRITE(map->conf, crtc_state->savePIPECONF);
cdv_intel_wait_for_vblank(dev);
- REG_WRITE(pipeA ? DSPACNTR : DSPBCNTR, crtc_state->saveDSPCNTR);
- REG_WRITE(pipeA ? DSPABASE : DSPBBASE, crtc_state->saveDSPBASE);
+ REG_WRITE(map->cntr, crtc_state->saveDSPCNTR);
+ REG_WRITE(map->base, crtc_state->saveDSPBASE);
cdv_intel_wait_for_vblank(dev);
- paletteReg = pipeA ? PALETTE_A : PALETTE_B;
+ paletteReg = map->palette;
for (i = 0; i < 256; ++i)
REG_WRITE(paletteReg + (i << 2), crtc_state->savePalette[i]);
}
@@ -1296,35 +1468,30 @@ static void i8xx_clock(int refclk, struct cdv_intel_clock_t *clock)
static int cdv_intel_crtc_clock_get(struct drm_device *dev,
struct drm_crtc *crtc)
{
+ struct drm_psb_private *dev_priv = dev->dev_private;
struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
int pipe = psb_intel_crtc->pipe;
+ const struct psb_offset *map = &dev_priv->regmap[pipe];
u32 dpll;
u32 fp;
struct cdv_intel_clock_t clock;
bool is_lvds;
- struct drm_psb_private *dev_priv = dev->dev_private;
+ struct psb_pipe *p = &dev_priv->regs.pipe[pipe];
if (gma_power_begin(dev, false)) {
- dpll = REG_READ((pipe == 0) ? DPLL_A : DPLL_B);
+ dpll = REG_READ(map->dpll);
if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0)
- fp = REG_READ((pipe == 0) ? FPA0 : FPB0);
+ fp = REG_READ(map->fp0);
else
- fp = REG_READ((pipe == 0) ? FPA1 : FPB1);
+ fp = REG_READ(map->fp1);
is_lvds = (pipe == 1) && (REG_READ(LVDS) & LVDS_PORT_EN);
gma_power_end(dev);
} else {
- dpll = (pipe == 0) ?
- dev_priv->regs.psb.saveDPLL_A :
- dev_priv->regs.psb.saveDPLL_B;
-
+ dpll = p->dpll;
if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0)
- fp = (pipe == 0) ?
- dev_priv->regs.psb.saveFPA0 :
- dev_priv->regs.psb.saveFPB0;
+ fp = p->fp0;
else
- fp = (pipe == 0) ?
- dev_priv->regs.psb.saveFPA1 :
- dev_priv->regs.psb.saveFPB1;
+ fp = p->fp1;
is_lvds = (pipe == 1) &&
(dev_priv->regs.psb.saveLVDS & LVDS_PORT_EN);
@@ -1382,32 +1549,26 @@ struct drm_display_mode *cdv_intel_crtc_mode_get(struct drm_device *dev,
{
struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
int pipe = psb_intel_crtc->pipe;
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ struct psb_pipe *p = &dev_priv->regs.pipe[pipe];
+ const struct psb_offset *map = &dev_priv->regmap[pipe];
struct drm_display_mode *mode;
int htot;
int hsync;
int vtot;
int vsync;
- struct drm_psb_private *dev_priv = dev->dev_private;
if (gma_power_begin(dev, false)) {
- htot = REG_READ((pipe == 0) ? HTOTAL_A : HTOTAL_B);
- hsync = REG_READ((pipe == 0) ? HSYNC_A : HSYNC_B);
- vtot = REG_READ((pipe == 0) ? VTOTAL_A : VTOTAL_B);
- vsync = REG_READ((pipe == 0) ? VSYNC_A : VSYNC_B);
+ htot = REG_READ(map->htotal);
+ hsync = REG_READ(map->hsync);
+ vtot = REG_READ(map->vtotal);
+ vsync = REG_READ(map->vsync);
gma_power_end(dev);
} else {
- htot = (pipe == 0) ?
- dev_priv->regs.psb.saveHTOTAL_A :
- dev_priv->regs.psb.saveHTOTAL_B;
- hsync = (pipe == 0) ?
- dev_priv->regs.psb.saveHSYNC_A :
- dev_priv->regs.psb.saveHSYNC_B;
- vtot = (pipe == 0) ?
- dev_priv->regs.psb.saveVTOTAL_A :
- dev_priv->regs.psb.saveVTOTAL_B;
- vsync = (pipe == 0) ?
- dev_priv->regs.psb.saveVSYNC_A :
- dev_priv->regs.psb.saveVSYNC_B;
+ htot = p->htotal;
+ hsync = p->hsync;
+ vtot = p->vtotal;
+ vsync = p->vsync;
}
mode = kzalloc(sizeof(*mode), GFP_KERNEL);
diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
index 8d5269555005..88b59d4a7b7f 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c
@@ -242,8 +242,6 @@ static int cdv_hdmi_get_modes(struct drm_connector *connector)
static int cdv_hdmi_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
- struct drm_psb_private *dev_priv = connector->dev->dev_private;
-
if (mode->clock > 165000)
return MODE_CLOCK_HIGH;
if (mode->clock < 20000)
@@ -257,11 +255,6 @@ static int cdv_hdmi_mode_valid(struct drm_connector *connector,
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
return MODE_NO_INTERLACE;
- /* We assume worst case scenario of 32 bpp here, since we don't know */
- if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) >
- dev_priv->vram_stolen_size)
- return MODE_MEM;
-
return MODE_OK;
}
diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
index 8359c1a3f45f..ff5b58eb878c 100644
--- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c
+++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c
@@ -356,6 +356,8 @@ static void cdv_intel_lvds_mode_set(struct drm_encoder *encoder,
{
struct drm_device *dev = encoder->dev;
struct drm_psb_private *dev_priv = dev->dev_private;
+ struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(
+ encoder->crtc);
u32 pfit_control;
/*
@@ -377,6 +379,8 @@ static void cdv_intel_lvds_mode_set(struct drm_encoder *encoder,
else
pfit_control = 0;
+ pfit_control |= psb_intel_crtc->pipe << PFIT_PIPE_SHIFT;
+
if (dev_priv->lvds_dither)
pfit_control |= PANEL_8TO6_DITHER_ENABLE;
@@ -552,10 +556,60 @@ static void cdv_intel_lvds_enc_destroy(struct drm_encoder *encoder)
drm_encoder_cleanup(encoder);
}
-const struct drm_encoder_funcs cdv_intel_lvds_enc_funcs = {
+static const struct drm_encoder_funcs cdv_intel_lvds_enc_funcs = {
.destroy = cdv_intel_lvds_enc_destroy,
};
+/*
+ * Enumerate the child dev array parsed from VBT to check whether
+ * the LVDS is present.
+ * If it is present, return 1.
+ * If it is not present, return false.
+ * If no child dev is parsed from VBT, it assumes that the LVDS is present.
+ */
+static bool lvds_is_present_in_vbt(struct drm_device *dev,
+ u8 *i2c_pin)
+{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ int i;
+
+ if (!dev_priv->child_dev_num)
+ return true;
+
+ for (i = 0; i < dev_priv->child_dev_num; i++) {
+ struct child_device_config *child = dev_priv->child_dev + i;
+
+ /* If the device type is not LFP, continue.
+ * We have to check both the new identifiers as well as the
+ * old for compatibility with some BIOSes.
+ */
+ if (child->device_type != DEVICE_TYPE_INT_LFP &&
+ child->device_type != DEVICE_TYPE_LFP)
+ continue;
+
+ if (child->i2c_pin)
+ *i2c_pin = child->i2c_pin;
+
+ /* However, we cannot trust the BIOS writers to populate
+ * the VBT correctly. Since LVDS requires additional
+ * information from AIM blocks, a non-zero addin offset is
+ * a good indicator that the LVDS is actually present.
+ */
+ if (child->addin_offset)
+ return true;
+
+ /* But even then some BIOS writers perform some black magic
+ * and instantiate the device without reference to any
+ * additional data. Trust that if the VBT was written into
+ * the OpRegion then they have validated the LVDS's existence.
+ */
+ if (dev_priv->opregion.vbt)
+ return true;
+ }
+
+ return false;
+}
+
/**
* cdv_intel_lvds_init - setup LVDS connectors on this device
* @dev: drm device
@@ -576,6 +630,13 @@ void cdv_intel_lvds_init(struct drm_device *dev,
struct drm_psb_private *dev_priv = dev->dev_private;
u32 lvds;
int pipe;
+ u8 pin;
+
+ pin = GMBUS_PORT_PANEL;
+ if (!lvds_is_present_in_vbt(dev, &pin)) {
+ DRM_DEBUG_KMS("LVDS is not present in VBT\n");
+ return;
+ }
psb_intel_encoder = kzalloc(sizeof(struct psb_intel_encoder),
GFP_KERNEL);
@@ -710,6 +771,19 @@ void cdv_intel_lvds_init(struct drm_device *dev,
goto failed_find;
}
+ /* setup PWM */
+ {
+ u32 pwm;
+
+ pwm = REG_READ(BLC_PWM_CTL2);
+ if (pipe == 1)
+ pwm |= PWM_PIPE_B;
+ else
+ pwm &= ~PWM_PIPE_B;
+ pwm |= PWM_ENABLE;
+ REG_WRITE(BLC_PWM_CTL2, pwm);
+ }
+
out:
drm_sysfs_connector_add(connector);
return;
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c
index 8ea202f1ba50..5732b5702e1c 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -153,7 +153,7 @@ static void psbfb_vm_close(struct vm_area_struct *vma)
{
}
-static struct vm_operations_struct psbfb_vm_ops = {
+static const struct vm_operations_struct psbfb_vm_ops = {
.fault = psbfb_vm_fault,
.open = psbfb_vm_open,
.close = psbfb_vm_close
@@ -408,6 +408,8 @@ static int psbfb_create(struct psb_fbdev *fbdev,
return -ENOMEM;
}
+ memset(dev_priv->vram_addr + backing->offset, 0, size);
+
mutex_lock(&dev->struct_mutex);
info = framebuffer_alloc(0, device);
@@ -453,8 +455,7 @@ static int psbfb_create(struct psb_fbdev *fbdev,
info->fix.ypanstep = 0;
/* Accessed stolen memory directly */
- info->screen_base = (char *)dev_priv->vram_addr +
- backing->offset;
+ info->screen_base = dev_priv->vram_addr + backing->offset;
info->screen_size = size;
if (dev_priv->gtt.stolen_size) {
@@ -475,7 +476,7 @@ static int psbfb_create(struct psb_fbdev *fbdev,
/* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
- dev_info(dev->dev, "allocated %dx%d fb\n",
+ dev_dbg(dev->dev, "allocated %dx%d fb\n",
psbfb->base.width, psbfb->base.height);
mutex_unlock(&dev->struct_mutex);
@@ -543,9 +544,25 @@ static int psbfb_probe(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes)
{
struct psb_fbdev *psb_fbdev = (struct psb_fbdev *)helper;
+ struct drm_device *dev = psb_fbdev->psb_fb_helper.dev;
+ struct drm_psb_private *dev_priv = dev->dev_private;
int new_fb = 0;
+ int bytespp;
int ret;
+ bytespp = sizes->surface_bpp / 8;
+ if (bytespp == 3) /* no 24bit packed */
+ bytespp = 4;
+
+ /* If the mode will not fit in 32bit then switch to 16bit to get
+ a console on full resolution. The X mode setting server will
+ allocate its own 32bit GEM framebuffer */
+ if (ALIGN(sizes->fb_width * bytespp, 64) * sizes->fb_height >
+ dev_priv->vram_stolen_size) {
+ sizes->surface_bpp = 16;
+ sizes->surface_depth = 16;
+ }
+
if (!helper->fb) {
ret = psbfb_create(psb_fbdev, sizes);
if (ret)
@@ -555,7 +572,7 @@ static int psbfb_probe(struct drm_fb_helper *helper,
return new_fb;
}
-struct drm_fb_helper_funcs psb_fb_helper_funcs = {
+static struct drm_fb_helper_funcs psb_fb_helper_funcs = {
.gamma_set = psbfb_gamma_set,
.gamma_get = psbfb_gamma_get,
.fb_probe = psbfb_probe,
@@ -732,10 +749,7 @@ static void psb_setup_outputs(struct drm_device *dev)
clone_mask = (1 << INTEL_OUTPUT_SDVO);
break;
case INTEL_OUTPUT_LVDS:
- if (IS_MRST(dev))
- crtc_mask = (1 << 0);
- else
- crtc_mask = (1 << 1);
+ crtc_mask = dev_priv->ops->lvds_mask;
clone_mask = (1 << INTEL_OUTPUT_LVDS);
break;
case INTEL_OUTPUT_MIPI:
@@ -747,10 +761,7 @@ static void psb_setup_outputs(struct drm_device *dev)
clone_mask = (1 << INTEL_OUTPUT_MIPI2);
break;
case INTEL_OUTPUT_HDMI:
- if (IS_MFLD(dev))
- crtc_mask = (1 << 1);
- else
- crtc_mask = (1 << 0);
+ crtc_mask = dev_priv->ops->hdmi_mask;
clone_mask = (1 << INTEL_OUTPUT_HDMI);
break;
}
@@ -771,7 +782,7 @@ void psb_modeset_init(struct drm_device *dev)
dev->mode_config.min_width = 0;
dev->mode_config.min_height = 0;
- dev->mode_config.funcs = (void *) &psb_mode_funcs;
+ dev->mode_config.funcs = &psb_mode_funcs;
/* set memory base */
/* Oaktrail and Poulsbo should use BAR 2*/
@@ -786,15 +797,23 @@ void psb_modeset_init(struct drm_device *dev)
dev->mode_config.max_height = 2048;
psb_setup_outputs(dev);
+
+ if (dev_priv->ops->errata)
+ dev_priv->ops->errata(dev);
+
+ dev_priv->modeset = true;
}
void psb_modeset_cleanup(struct drm_device *dev)
{
- mutex_lock(&dev->struct_mutex);
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ if (dev_priv->modeset) {
+ mutex_lock(&dev->struct_mutex);
- drm_kms_helper_poll_fini(dev);
- psb_fbdev_fini(dev);
- drm_mode_config_cleanup(dev);
+ drm_kms_helper_poll_fini(dev);
+ psb_fbdev_fini(dev);
+ drm_mode_config_cleanup(dev);
- mutex_unlock(&dev->struct_mutex);
+ mutex_unlock(&dev->struct_mutex);
+ }
}
diff --git a/drivers/gpu/drm/gma500/gem.c b/drivers/gpu/drm/gma500/gem.c
index 9fbb86868e2e..fc7d144bc2d3 100644
--- a/drivers/gpu/drm/gma500/gem.c
+++ b/drivers/gpu/drm/gma500/gem.c
@@ -124,6 +124,8 @@ static int psb_gem_create(struct drm_file *file,
dev_err(dev->dev, "GEM init failed for %lld\n", size);
return -ENOMEM;
}
+ /* Limit the object to 32bit mappings */
+ mapping_set_gfp_mask(r->gem.filp->f_mapping, GFP_KERNEL | __GFP_DMA32);
/* Give the object a handle so we can carry it more easily */
ret = drm_gem_handle_create(file, &r->gem, &handle);
if (ret) {
diff --git a/drivers/gpu/drm/gma500/gtt.c b/drivers/gpu/drm/gma500/gtt.c
index c6465b40090f..04a371aceb34 100644
--- a/drivers/gpu/drm/gma500/gtt.c
+++ b/drivers/gpu/drm/gma500/gtt.c
@@ -39,6 +39,10 @@ static inline uint32_t psb_gtt_mask_pte(uint32_t pfn, int type)
{
uint32_t mask = PSB_PTE_VALID;
+ /* Ensure we explode rather than put an invalid low mapping of
+ a high mapping page into the gtt */
+ BUG_ON(pfn & ~(0xFFFFFFFF >> PAGE_SHIFT));
+
if (type & PSB_MMU_CACHED_MEMORY)
mask |= PSB_PTE_CACHED;
if (type & PSB_MMU_RO_MEMORY)
@@ -57,7 +61,7 @@ static inline uint32_t psb_gtt_mask_pte(uint32_t pfn, int type)
* Given a gtt_range object return the GTT offset of the page table
* entries for this gtt_range
*/
-static u32 *psb_gtt_entry(struct drm_device *dev, struct gtt_range *r)
+static u32 __iomem *psb_gtt_entry(struct drm_device *dev, struct gtt_range *r)
{
struct drm_psb_private *dev_priv = dev->dev_private;
unsigned long offset;
@@ -78,7 +82,8 @@ static u32 *psb_gtt_entry(struct drm_device *dev, struct gtt_range *r)
*/
static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r)
{
- u32 *gtt_slot, pte;
+ u32 __iomem *gtt_slot;
+ u32 pte;
struct page **pages;
int i;
@@ -93,7 +98,7 @@ static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r)
pages = r->pages;
/* Make sure changes are visible to the GPU */
- set_pages_array_uc(pages, r->npage);
+ set_pages_array_wc(pages, r->npage);
/* Write our page entries into the GTT itself */
for (i = r->roll; i < r->npage; i++) {
@@ -122,7 +127,8 @@ static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r)
static void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r)
{
struct drm_psb_private *dev_priv = dev->dev_private;
- u32 *gtt_slot, pte;
+ u32 __iomem *gtt_slot;
+ u32 pte;
int i;
WARN_ON(r->stolen);
@@ -148,7 +154,8 @@ static void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r)
*/
void psb_gtt_roll(struct drm_device *dev, struct gtt_range *r, int roll)
{
- u32 *gtt_slot, pte;
+ u32 __iomem *gtt_slot;
+ u32 pte;
int i;
if (roll >= r->npage) {
@@ -409,8 +416,6 @@ int psb_gtt_init(struct drm_device *dev, int resume)
unsigned long stolen_size, vram_stolen_size;
unsigned i, num_pages;
unsigned pfn_base;
- uint32_t vram_pages;
- uint32_t dvmt_mode = 0;
struct psb_gtt *pg;
int ret = 0;
@@ -483,13 +488,8 @@ int psb_gtt_init(struct drm_device *dev, int resume)
stolen_size = vram_stolen_size;
- printk(KERN_INFO "Stolen memory information\n");
- printk(KERN_INFO " base in RAM: 0x%x\n", dev_priv->stolen_base);
- printk(KERN_INFO " size: %luK, calculated by (GTT RAM base) - (Stolen base), seems wrong\n",
- vram_stolen_size/1024);
- dvmt_mode = (dev_priv->gmch_ctrl >> 4) & 0x7;
- printk(KERN_INFO " the correct size should be: %dM(dvmt mode=%d)\n",
- (dvmt_mode == 1) ? 1 : (2 << (dvmt_mode - 1)), dvmt_mode);
+ dev_dbg(dev->dev, "Stolen memory base 0x%x, size %luK\n",
+ dev_priv->stolen_base, vram_stolen_size / 1024);
if (resume && (gtt_pages != pg->gtt_pages) &&
(stolen_size != pg->stolen_size)) {
@@ -525,8 +525,8 @@ int psb_gtt_init(struct drm_device *dev, int resume)
*/
pfn_base = dev_priv->stolen_base >> PAGE_SHIFT;
- vram_pages = num_pages = vram_stolen_size >> PAGE_SHIFT;
- printk(KERN_INFO"Set up %d stolen pages starting at 0x%08x, GTT offset %dK\n",
+ num_pages = vram_stolen_size >> PAGE_SHIFT;
+ dev_dbg(dev->dev, "Set up %d stolen pages starting at 0x%08x, GTT offset %dK\n",
num_pages, pfn_base << PAGE_SHIFT, 0);
for (i = 0; i < num_pages; ++i) {
pte = psb_gtt_mask_pte(pfn_base + i, 0);
diff --git a/drivers/gpu/drm/gma500/intel_bios.c b/drivers/gpu/drm/gma500/intel_bios.c
index d4d0c5b8bf91..973d7f6d66b7 100644
--- a/drivers/gpu/drm/gma500/intel_bios.c
+++ b/drivers/gpu/drm/gma500/intel_bios.c
@@ -26,6 +26,8 @@
#include "psb_intel_reg.h"
#include "intel_bios.h"
+#define SLAVE_ADDR1 0x70
+#define SLAVE_ADDR2 0x72
static void *find_section(struct bdb_header *bdb, int section_id)
{
@@ -52,6 +54,16 @@ static void *find_section(struct bdb_header *bdb, int section_id)
return NULL;
}
+static u16
+get_blocksize(void *p)
+{
+ u16 *block_ptr, block_size;
+
+ block_ptr = (u16 *)((char *)p - 2);
+ block_size = *block_ptr;
+ return block_size;
+}
+
static void fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
struct lvds_dvo_timing *dvo_timing)
{
@@ -75,6 +87,16 @@ static void fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
panel_fixed_mode->clock = dvo_timing->clock * 10;
panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED;
+ if (dvo_timing->hsync_positive)
+ panel_fixed_mode->flags |= DRM_MODE_FLAG_PHSYNC;
+ else
+ panel_fixed_mode->flags |= DRM_MODE_FLAG_NHSYNC;
+
+ if (dvo_timing->vsync_positive)
+ panel_fixed_mode->flags |= DRM_MODE_FLAG_PVSYNC;
+ else
+ panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC;
+
/* Some VBTs have bogus h/vtotal values */
if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal)
panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1;
@@ -217,6 +239,180 @@ static void parse_general_features(struct drm_psb_private *dev_priv,
}
}
+static void
+parse_sdvo_device_mapping(struct drm_psb_private *dev_priv,
+ struct bdb_header *bdb)
+{
+ struct sdvo_device_mapping *p_mapping;
+ struct bdb_general_definitions *p_defs;
+ struct child_device_config *p_child;
+ int i, child_device_num, count;
+ u16 block_size;
+
+ p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
+ if (!p_defs) {
+ DRM_DEBUG_KMS("No general definition block is found, unable to construct sdvo mapping.\n");
+ return;
+ }
+ /* judge whether the size of child device meets the requirements.
+ * If the child device size obtained from general definition block
+ * is different with sizeof(struct child_device_config), skip the
+ * parsing of sdvo device info
+ */
+ if (p_defs->child_dev_size != sizeof(*p_child)) {
+ /* different child dev size . Ignore it */
+ DRM_DEBUG_KMS("different child size is found. Invalid.\n");
+ return;
+ }
+ /* get the block size of general definitions */
+ block_size = get_blocksize(p_defs);
+ /* get the number of child device */
+ child_device_num = (block_size - sizeof(*p_defs)) /
+ sizeof(*p_child);
+ count = 0;
+ for (i = 0; i < child_device_num; i++) {
+ p_child = &(p_defs->devices[i]);
+ if (!p_child->device_type) {
+ /* skip the device block if device type is invalid */
+ continue;
+ }
+ if (p_child->slave_addr != SLAVE_ADDR1 &&
+ p_child->slave_addr != SLAVE_ADDR2) {
+ /*
+ * If the slave address is neither 0x70 nor 0x72,
+ * it is not a SDVO device. Skip it.
+ */
+ continue;
+ }
+ if (p_child->dvo_port != DEVICE_PORT_DVOB &&
+ p_child->dvo_port != DEVICE_PORT_DVOC) {
+ /* skip the incorrect SDVO port */
+ DRM_DEBUG_KMS("Incorrect SDVO port. Skip it\n");
+ continue;
+ }
+ DRM_DEBUG_KMS("the SDVO device with slave addr %2x is found on"
+ " %s port\n",
+ p_child->slave_addr,
+ (p_child->dvo_port == DEVICE_PORT_DVOB) ?
+ "SDVOB" : "SDVOC");
+ p_mapping = &(dev_priv->sdvo_mappings[p_child->dvo_port - 1]);
+ if (!p_mapping->initialized) {
+ p_mapping->dvo_port = p_child->dvo_port;
+ p_mapping->slave_addr = p_child->slave_addr;
+ p_mapping->dvo_wiring = p_child->dvo_wiring;
+ p_mapping->ddc_pin = p_child->ddc_pin;
+ p_mapping->i2c_pin = p_child->i2c_pin;
+ p_mapping->initialized = 1;
+ DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d\n",
+ p_mapping->dvo_port,
+ p_mapping->slave_addr,
+ p_mapping->dvo_wiring,
+ p_mapping->ddc_pin,
+ p_mapping->i2c_pin);
+ } else {
+ DRM_DEBUG_KMS("Maybe one SDVO port is shared by "
+ "two SDVO device.\n");
+ }
+ if (p_child->slave2_addr) {
+ /* Maybe this is a SDVO device with multiple inputs */
+ /* And the mapping info is not added */
+ DRM_DEBUG_KMS("there exists the slave2_addr. Maybe this"
+ " is a SDVO device with multiple inputs.\n");
+ }
+ count++;
+ }
+
+ if (!count) {
+ /* No SDVO device info is found */
+ DRM_DEBUG_KMS("No SDVO device info is found in VBT\n");
+ }
+ return;
+}
+
+
+static void
+parse_driver_features(struct drm_psb_private *dev_priv,
+ struct bdb_header *bdb)
+{
+ struct bdb_driver_features *driver;
+
+ driver = find_section(bdb, BDB_DRIVER_FEATURES);
+ if (!driver)
+ return;
+
+ /* This bit means to use 96Mhz for DPLL_A or not */
+ if (driver->primary_lfp_id)
+ dev_priv->dplla_96mhz = true;
+ else
+ dev_priv->dplla_96mhz = false;
+}
+
+static void
+parse_device_mapping(struct drm_psb_private *dev_priv,
+ struct bdb_header *bdb)
+{
+ struct bdb_general_definitions *p_defs;
+ struct child_device_config *p_child, *child_dev_ptr;
+ int i, child_device_num, count;
+ u16 block_size;
+
+ p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
+ if (!p_defs) {
+ DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n");
+ return;
+ }
+ /* judge whether the size of child device meets the requirements.
+ * If the child device size obtained from general definition block
+ * is different with sizeof(struct child_device_config), skip the
+ * parsing of sdvo device info
+ */
+ if (p_defs->child_dev_size != sizeof(*p_child)) {
+ /* different child dev size . Ignore it */
+ DRM_DEBUG_KMS("different child size is found. Invalid.\n");
+ return;
+ }
+ /* get the block size of general definitions */
+ block_size = get_blocksize(p_defs);
+ /* get the number of child device */
+ child_device_num = (block_size - sizeof(*p_defs)) /
+ sizeof(*p_child);
+ count = 0;
+ /* get the number of child devices that are present */
+ for (i = 0; i < child_device_num; i++) {
+ p_child = &(p_defs->devices[i]);
+ if (!p_child->device_type) {
+ /* skip the device block if device type is invalid */
+ continue;
+ }
+ count++;
+ }
+ if (!count) {
+ DRM_DEBUG_KMS("no child dev is parsed from VBT\n");
+ return;
+ }
+ dev_priv->child_dev = kcalloc(count, sizeof(*p_child), GFP_KERNEL);
+ if (!dev_priv->child_dev) {
+ DRM_DEBUG_KMS("No memory space for child devices\n");
+ return;
+ }
+
+ dev_priv->child_dev_num = count;
+ count = 0;
+ for (i = 0; i < child_device_num; i++) {
+ p_child = &(p_defs->devices[i]);
+ if (!p_child->device_type) {
+ /* skip the device block if device type is invalid */
+ continue;
+ }
+ child_dev_ptr = dev_priv->child_dev + count;
+ count++;
+ memcpy((void *)child_dev_ptr, (void *)p_child,
+ sizeof(*p_child));
+ }
+ return;
+}
+
+
/**
* psb_intel_init_bios - initialize VBIOS settings & find VBT
* @dev: DRM device
@@ -236,38 +432,54 @@ bool psb_intel_init_bios(struct drm_device *dev)
struct drm_psb_private *dev_priv = dev->dev_private;
struct pci_dev *pdev = dev->pdev;
struct vbt_header *vbt = NULL;
- struct bdb_header *bdb;
- u8 __iomem *bios;
+ struct bdb_header *bdb = NULL;
+ u8 __iomem *bios = NULL;
size_t size;
int i;
- bios = pci_map_rom(pdev, &size);
- if (!bios)
- return -1;
+ /* XXX Should this validation be moved to intel_opregion.c? */
+ if (dev_priv->opregion.vbt) {
+ struct vbt_header *vbt = dev_priv->opregion.vbt;
+ if (memcmp(vbt->signature, "$VBT", 4) == 0) {
+ DRM_DEBUG_KMS("Using VBT from OpRegion: %20s\n",
+ vbt->signature);
+ bdb = (struct bdb_header *)((char *)vbt + vbt->bdb_offset);
+ } else
+ dev_priv->opregion.vbt = NULL;
+ }
- /* Scour memory looking for the VBT signature */
- for (i = 0; i + 4 < size; i++) {
- if (!memcmp(bios + i, "$VBT", 4)) {
- vbt = (struct vbt_header *)(bios + i);
- break;
+ if (bdb == NULL) {
+ bios = pci_map_rom(pdev, &size);
+ if (!bios)
+ return -1;
+
+ /* Scour memory looking for the VBT signature */
+ for (i = 0; i + 4 < size; i++) {
+ if (!memcmp(bios + i, "$VBT", 4)) {
+ vbt = (struct vbt_header *)(bios + i);
+ break;
+ }
}
- }
- if (!vbt) {
- dev_err(dev->dev, "VBT signature missing\n");
- pci_unmap_rom(pdev, bios);
- return -1;
+ if (!vbt) {
+ dev_err(dev->dev, "VBT signature missing\n");
+ pci_unmap_rom(pdev, bios);
+ return -1;
+ }
+ bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset);
}
- bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset);
-
- /* Grab useful general definitions */
+ /* Grab useful general dxefinitions */
parse_general_features(dev_priv, bdb);
+ parse_driver_features(dev_priv, bdb);
parse_lfp_panel_data(dev_priv, bdb);
parse_sdvo_panel_data(dev_priv, bdb);
+ parse_sdvo_device_mapping(dev_priv, bdb);
+ parse_device_mapping(dev_priv, bdb);
parse_backlight_data(dev_priv, bdb);
- pci_unmap_rom(pdev, bios);
+ if (bios)
+ pci_unmap_rom(pdev, bios);
return 0;
}
@@ -278,26 +490,8 @@ bool psb_intel_init_bios(struct drm_device *dev)
void psb_intel_destroy_bios(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
- struct drm_display_mode *sdvo_lvds_vbt_mode =
- dev_priv->sdvo_lvds_vbt_mode;
- struct drm_display_mode *lfp_lvds_vbt_mode =
- dev_priv->lfp_lvds_vbt_mode;
- struct bdb_lvds_backlight *lvds_bl =
- dev_priv->lvds_bl;
-
- /*free sdvo panel mode*/
- if (sdvo_lvds_vbt_mode) {
- dev_priv->sdvo_lvds_vbt_mode = NULL;
- kfree(sdvo_lvds_vbt_mode);
- }
- if (lfp_lvds_vbt_mode) {
- dev_priv->lfp_lvds_vbt_mode = NULL;
- kfree(lfp_lvds_vbt_mode);
- }
-
- if (lvds_bl) {
- dev_priv->lvds_bl = NULL;
- kfree(lvds_bl);
- }
+ kfree(dev_priv->sdvo_lvds_vbt_mode);
+ kfree(dev_priv->lfp_lvds_vbt_mode);
+ kfree(dev_priv->lvds_bl);
}
diff --git a/drivers/gpu/drm/gma500/intel_bios.h b/drivers/gpu/drm/gma500/intel_bios.h
index 70f1bf018183..0a738663eb5a 100644
--- a/drivers/gpu/drm/gma500/intel_bios.h
+++ b/drivers/gpu/drm/gma500/intel_bios.h
@@ -127,9 +127,93 @@ struct bdb_general_features {
/* bits 5 */
u8 int_crt_support:1;
u8 int_tv_support:1;
- u8 rsvd11:6; /* finish byte */
+ u8 int_efp_support:1;
+ u8 dp_ssc_enb:1; /* PCH attached eDP supports SSC */
+ u8 dp_ssc_freq:1; /* SSC freq for PCH attached eDP */
+ u8 rsvd11:3; /* finish byte */
} __attribute__((packed));
+/* pre-915 */
+#define GPIO_PIN_DVI_LVDS 0x03 /* "DVI/LVDS DDC GPIO pins" */
+#define GPIO_PIN_ADD_I2C 0x05 /* "ADDCARD I2C GPIO pins" */
+#define GPIO_PIN_ADD_DDC 0x04 /* "ADDCARD DDC GPIO pins" */
+#define GPIO_PIN_ADD_DDC_I2C 0x06 /* "ADDCARD DDC/I2C GPIO pins" */
+
+/* Pre 915 */
+#define DEVICE_TYPE_NONE 0x00
+#define DEVICE_TYPE_CRT 0x01
+#define DEVICE_TYPE_TV 0x09
+#define DEVICE_TYPE_EFP 0x12
+#define DEVICE_TYPE_LFP 0x22
+/* On 915+ */
+#define DEVICE_TYPE_CRT_DPMS 0x6001
+#define DEVICE_TYPE_CRT_DPMS_HOTPLUG 0x4001
+#define DEVICE_TYPE_TV_COMPOSITE 0x0209
+#define DEVICE_TYPE_TV_MACROVISION 0x0289
+#define DEVICE_TYPE_TV_RF_COMPOSITE 0x020c
+#define DEVICE_TYPE_TV_SVIDEO_COMPOSITE 0x0609
+#define DEVICE_TYPE_TV_SCART 0x0209
+#define DEVICE_TYPE_TV_CODEC_HOTPLUG_PWR 0x6009
+#define DEVICE_TYPE_EFP_HOTPLUG_PWR 0x6012
+#define DEVICE_TYPE_EFP_DVI_HOTPLUG_PWR 0x6052
+#define DEVICE_TYPE_EFP_DVI_I 0x6053
+#define DEVICE_TYPE_EFP_DVI_D_DUAL 0x6152
+#define DEVICE_TYPE_EFP_DVI_D_HDCP 0x60d2
+#define DEVICE_TYPE_OPENLDI_HOTPLUG_PWR 0x6062
+#define DEVICE_TYPE_OPENLDI_DUALPIX 0x6162
+#define DEVICE_TYPE_LFP_PANELLINK 0x5012
+#define DEVICE_TYPE_LFP_CMOS_PWR 0x5042
+#define DEVICE_TYPE_LFP_LVDS_PWR 0x5062
+#define DEVICE_TYPE_LFP_LVDS_DUAL 0x5162
+#define DEVICE_TYPE_LFP_LVDS_DUAL_HDCP 0x51e2
+
+#define DEVICE_CFG_NONE 0x00
+#define DEVICE_CFG_12BIT_DVOB 0x01
+#define DEVICE_CFG_12BIT_DVOC 0x02
+#define DEVICE_CFG_24BIT_DVOBC 0x09
+#define DEVICE_CFG_24BIT_DVOCB 0x0a
+#define DEVICE_CFG_DUAL_DVOB 0x11
+#define DEVICE_CFG_DUAL_DVOC 0x12
+#define DEVICE_CFG_DUAL_DVOBC 0x13
+#define DEVICE_CFG_DUAL_LINK_DVOBC 0x19
+#define DEVICE_CFG_DUAL_LINK_DVOCB 0x1a
+
+#define DEVICE_WIRE_NONE 0x00
+#define DEVICE_WIRE_DVOB 0x01
+#define DEVICE_WIRE_DVOC 0x02
+#define DEVICE_WIRE_DVOBC 0x03
+#define DEVICE_WIRE_DVOBB 0x05
+#define DEVICE_WIRE_DVOCC 0x06
+#define DEVICE_WIRE_DVOB_MASTER 0x0d
+#define DEVICE_WIRE_DVOC_MASTER 0x0e
+
+#define DEVICE_PORT_DVOA 0x00 /* none on 845+ */
+#define DEVICE_PORT_DVOB 0x01
+#define DEVICE_PORT_DVOC 0x02
+
+struct child_device_config {
+ u16 handle;
+ u16 device_type;
+ u8 device_id[10]; /* ascii string */
+ u16 addin_offset;
+ u8 dvo_port; /* See Device_PORT_* above */
+ u8 i2c_pin;
+ u8 slave_addr;
+ u8 ddc_pin;
+ u16 edid_ptr;
+ u8 dvo_cfg; /* See DEVICE_CFG_* above */
+ u8 dvo2_port;
+ u8 i2c2_pin;
+ u8 slave2_addr;
+ u8 ddc2_pin;
+ u8 capabilities;
+ u8 dvo_wiring;/* See DEVICE_WIRE_* above */
+ u8 dvo2_wiring;
+ u16 extended_type;
+ u8 dvo_function;
+} __attribute__((packed));
+
+
struct bdb_general_definitions {
/* DDC GPIO */
u8 crt_ddc_gmbus_pin;
@@ -144,13 +228,18 @@ struct bdb_general_definitions {
u8 boot_display[2];
u8 child_dev_size;
- /* device info */
- u8 tv_or_lvds_info[33];
- u8 dev1[33];
- u8 dev2[33];
- u8 dev3[33];
- u8 dev4[33];
- /* may be another device block here on some platforms */
+ /*
+ * Device info:
+ * If TV is present, it'll be at devices[0].
+ * LVDS will be next, either devices[0] or [1], if present.
+ * On some platforms the number of device is 6. But could be as few as
+ * 4 if both TV and LVDS are missing.
+ * And the device num is related with the size of general definition
+ * block. It is obtained by using the following formula:
+ * number = (block_size - sizeof(bdb_general_definitions))/
+ * sizeof(child_device_config);
+ */
+ struct child_device_config devices[0];
};
struct bdb_lvds_options {
@@ -302,6 +391,45 @@ struct bdb_sdvo_lvds_options {
u8 panel_misc_bits_4;
} __attribute__((packed));
+struct bdb_driver_features {
+ u8 boot_dev_algorithm:1;
+ u8 block_display_switch:1;
+ u8 allow_display_switch:1;
+ u8 hotplug_dvo:1;
+ u8 dual_view_zoom:1;
+ u8 int15h_hook:1;
+ u8 sprite_in_clone:1;
+ u8 primary_lfp_id:1;
+
+ u16 boot_mode_x;
+ u16 boot_mode_y;
+ u8 boot_mode_bpp;
+ u8 boot_mode_refresh;
+
+ u16 enable_lfp_primary:1;
+ u16 selective_mode_pruning:1;
+ u16 dual_frequency:1;
+ u16 render_clock_freq:1; /* 0: high freq; 1: low freq */
+ u16 nt_clone_support:1;
+ u16 power_scheme_ui:1; /* 0: CUI; 1: 3rd party */
+ u16 sprite_display_assign:1; /* 0: secondary; 1: primary */
+ u16 cui_aspect_scaling:1;
+ u16 preserve_aspect_ratio:1;
+ u16 sdvo_device_power_down:1;
+ u16 crt_hotplug:1;
+ u16 lvds_config:2;
+ u16 tv_hotplug:1;
+ u16 hdmi_config:2;
+
+ u8 static_display:1;
+ u8 reserved2:7;
+ u16 legacy_crt_max_x;
+ u16 legacy_crt_max_y;
+ u8 legacy_crt_max_refresh;
+
+ u8 hdmi_termination;
+ u8 custom_vbt_version;
+} __attribute__((packed));
extern bool psb_intel_init_bios(struct drm_device *dev);
extern void psb_intel_destroy_bios(struct drm_device *dev);
@@ -427,4 +555,21 @@ extern void psb_intel_destroy_bios(struct drm_device *dev);
#define SWF14_APM_STANDBY 0x1
#define SWF14_APM_RESTORE 0x0
+/* Add the device class for LFP, TV, HDMI */
+#define DEVICE_TYPE_INT_LFP 0x1022
+#define DEVICE_TYPE_INT_TV 0x1009
+#define DEVICE_TYPE_HDMI 0x60D2
+#define DEVICE_TYPE_DP 0x68C6
+#define DEVICE_TYPE_eDP 0x78C6
+
+/* define the DVO port for HDMI output type */
+#define DVO_B 1
+#define DVO_C 2
+#define DVO_D 3
+
+/* define the PORT for DP output type */
+#define PORT_IDPB 7
+#define PORT_IDPC 8
+#define PORT_IDPD 9
+
#endif /* _I830_BIOS_H_ */
diff --git a/drivers/gpu/drm/gma500/mdfld_device.c b/drivers/gpu/drm/gma500/mdfld_device.c
index af656787db0f..265ad0de44a6 100644
--- a/drivers/gpu/drm/gma500/mdfld_device.c
+++ b/drivers/gpu/drm/gma500/mdfld_device.c
@@ -163,142 +163,30 @@ struct backlight_device *mdfld_get_backlight_device(void)
*
* Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
*/
-static int mdfld_save_display_registers(struct drm_device *dev, int pipe)
+static int mdfld_save_display_registers(struct drm_device *dev, int pipenum)
{
struct drm_psb_private *dev_priv = dev->dev_private;
struct medfield_state *regs = &dev_priv->regs.mdfld;
+ struct psb_pipe *pipe = &dev_priv->regs.pipe[pipenum];
+ const struct psb_offset *map = &dev_priv->regmap[pipenum];
int i;
+ u32 *mipi_val;
/* register */
- u32 dpll_reg = MRST_DPLL_A;
- u32 fp_reg = MRST_FPA0;
- u32 pipeconf_reg = PIPEACONF;
- u32 htot_reg = HTOTAL_A;
- u32 hblank_reg = HBLANK_A;
- u32 hsync_reg = HSYNC_A;
- u32 vtot_reg = VTOTAL_A;
- u32 vblank_reg = VBLANK_A;
- u32 vsync_reg = VSYNC_A;
- u32 pipesrc_reg = PIPEASRC;
- u32 dspstride_reg = DSPASTRIDE;
- u32 dsplinoff_reg = DSPALINOFF;
- u32 dsptileoff_reg = DSPATILEOFF;
- u32 dspsize_reg = DSPASIZE;
- u32 dsppos_reg = DSPAPOS;
- u32 dspsurf_reg = DSPASURF;
u32 mipi_reg = MIPI;
- u32 dspcntr_reg = DSPACNTR;
- u32 dspstatus_reg = PIPEASTAT;
- u32 palette_reg = PALETTE_A;
-
- /* pointer to values */
- u32 *dpll_val = &regs->saveDPLL_A;
- u32 *fp_val = &regs->saveFPA0;
- u32 *pipeconf_val = &regs->savePIPEACONF;
- u32 *htot_val = &regs->saveHTOTAL_A;
- u32 *hblank_val = &regs->saveHBLANK_A;
- u32 *hsync_val = &regs->saveHSYNC_A;
- u32 *vtot_val = &regs->saveVTOTAL_A;
- u32 *vblank_val = &regs->saveVBLANK_A;
- u32 *vsync_val = &regs->saveVSYNC_A;
- u32 *pipesrc_val = &regs->savePIPEASRC;
- u32 *dspstride_val = &regs->saveDSPASTRIDE;
- u32 *dsplinoff_val = &regs->saveDSPALINOFF;
- u32 *dsptileoff_val = &regs->saveDSPATILEOFF;
- u32 *dspsize_val = &regs->saveDSPASIZE;
- u32 *dsppos_val = &regs->saveDSPAPOS;
- u32 *dspsurf_val = &regs->saveDSPASURF;
- u32 *mipi_val = &regs->saveMIPI;
- u32 *dspcntr_val = &regs->saveDSPACNTR;
- u32 *dspstatus_val = &regs->saveDSPASTATUS;
- u32 *palette_val = regs->save_palette_a;
-
- switch (pipe) {
+
+ switch (pipenum) {
case 0:
+ mipi_val = &regs->saveMIPI;
break;
case 1:
- /* regester */
- dpll_reg = MDFLD_DPLL_B;
- fp_reg = MDFLD_DPLL_DIV0;
- pipeconf_reg = PIPEBCONF;
- htot_reg = HTOTAL_B;
- hblank_reg = HBLANK_B;
- hsync_reg = HSYNC_B;
- vtot_reg = VTOTAL_B;
- vblank_reg = VBLANK_B;
- vsync_reg = VSYNC_B;
- pipesrc_reg = PIPEBSRC;
- dspstride_reg = DSPBSTRIDE;
- dsplinoff_reg = DSPBLINOFF;
- dsptileoff_reg = DSPBTILEOFF;
- dspsize_reg = DSPBSIZE;
- dsppos_reg = DSPBPOS;
- dspsurf_reg = DSPBSURF;
- dspcntr_reg = DSPBCNTR;
- dspstatus_reg = PIPEBSTAT;
- palette_reg = PALETTE_B;
-
- /* values */
- dpll_val = &regs->saveDPLL_B;
- fp_val = &regs->saveFPB0;
- pipeconf_val = &regs->savePIPEBCONF;
- htot_val = &regs->saveHTOTAL_B;
- hblank_val = &regs->saveHBLANK_B;
- hsync_val = &regs->saveHSYNC_B;
- vtot_val = &regs->saveVTOTAL_B;
- vblank_val = &regs->saveVBLANK_B;
- vsync_val = &regs->saveVSYNC_B;
- pipesrc_val = &regs->savePIPEBSRC;
- dspstride_val = &regs->saveDSPBSTRIDE;
- dsplinoff_val = &regs->saveDSPBLINOFF;
- dsptileoff_val = &regs->saveDSPBTILEOFF;
- dspsize_val = &regs->saveDSPBSIZE;
- dsppos_val = &regs->saveDSPBPOS;
- dspsurf_val = &regs->saveDSPBSURF;
- dspcntr_val = &regs->saveDSPBCNTR;
- dspstatus_val = &regs->saveDSPBSTATUS;
- palette_val = regs->save_palette_b;
+ mipi_val = &regs->saveMIPI;
break;
case 2:
/* register */
- pipeconf_reg = PIPECCONF;
- htot_reg = HTOTAL_C;
- hblank_reg = HBLANK_C;
- hsync_reg = HSYNC_C;
- vtot_reg = VTOTAL_C;
- vblank_reg = VBLANK_C;
- vsync_reg = VSYNC_C;
- pipesrc_reg = PIPECSRC;
- dspstride_reg = DSPCSTRIDE;
- dsplinoff_reg = DSPCLINOFF;
- dsptileoff_reg = DSPCTILEOFF;
- dspsize_reg = DSPCSIZE;
- dsppos_reg = DSPCPOS;
- dspsurf_reg = DSPCSURF;
mipi_reg = MIPI_C;
- dspcntr_reg = DSPCCNTR;
- dspstatus_reg = PIPECSTAT;
- palette_reg = PALETTE_C;
-
/* pointer to values */
- pipeconf_val = &regs->savePIPECCONF;
- htot_val = &regs->saveHTOTAL_C;
- hblank_val = &regs->saveHBLANK_C;
- hsync_val = &regs->saveHSYNC_C;
- vtot_val = &regs->saveVTOTAL_C;
- vblank_val = &regs->saveVBLANK_C;
- vsync_val = &regs->saveVSYNC_C;
- pipesrc_val = &regs->savePIPECSRC;
- dspstride_val = &regs->saveDSPCSTRIDE;
- dsplinoff_val = &regs->saveDSPCLINOFF;
- dsptileoff_val = &regs->saveDSPCTILEOFF;
- dspsize_val = &regs->saveDSPCSIZE;
- dsppos_val = &regs->saveDSPCPOS;
- dspsurf_val = &regs->saveDSPCSURF;
mipi_val = &regs->saveMIPI_C;
- dspcntr_val = &regs->saveDSPCCNTR;
- dspstatus_val = &regs->saveDSPCSTATUS;
- palette_val = regs->save_palette_c;
break;
default:
DRM_ERROR("%s, invalid pipe number.\n", __func__);
@@ -306,30 +194,30 @@ static int mdfld_save_display_registers(struct drm_device *dev, int pipe)
}
/* Pipe & plane A info */
- *dpll_val = PSB_RVDC32(dpll_reg);
- *fp_val = PSB_RVDC32(fp_reg);
- *pipeconf_val = PSB_RVDC32(pipeconf_reg);
- *htot_val = PSB_RVDC32(htot_reg);
- *hblank_val = PSB_RVDC32(hblank_reg);
- *hsync_val = PSB_RVDC32(hsync_reg);
- *vtot_val = PSB_RVDC32(vtot_reg);
- *vblank_val = PSB_RVDC32(vblank_reg);
- *vsync_val = PSB_RVDC32(vsync_reg);
- *pipesrc_val = PSB_RVDC32(pipesrc_reg);
- *dspstride_val = PSB_RVDC32(dspstride_reg);
- *dsplinoff_val = PSB_RVDC32(dsplinoff_reg);
- *dsptileoff_val = PSB_RVDC32(dsptileoff_reg);
- *dspsize_val = PSB_RVDC32(dspsize_reg);
- *dsppos_val = PSB_RVDC32(dsppos_reg);
- *dspsurf_val = PSB_RVDC32(dspsurf_reg);
- *dspcntr_val = PSB_RVDC32(dspcntr_reg);
- *dspstatus_val = PSB_RVDC32(dspstatus_reg);
+ pipe->dpll = PSB_RVDC32(map->dpll);
+ pipe->fp0 = PSB_RVDC32(map->fp0);
+ pipe->conf = PSB_RVDC32(map->conf);
+ pipe->htotal = PSB_RVDC32(map->htotal);
+ pipe->hblank = PSB_RVDC32(map->hblank);
+ pipe->hsync = PSB_RVDC32(map->hsync);
+ pipe->vtotal = PSB_RVDC32(map->vtotal);
+ pipe->vblank = PSB_RVDC32(map->vblank);
+ pipe->vsync = PSB_RVDC32(map->vsync);
+ pipe->src = PSB_RVDC32(map->src);
+ pipe->stride = PSB_RVDC32(map->stride);
+ pipe->linoff = PSB_RVDC32(map->linoff);
+ pipe->tileoff = PSB_RVDC32(map->tileoff);
+ pipe->size = PSB_RVDC32(map->size);
+ pipe->pos = PSB_RVDC32(map->pos);
+ pipe->surf = PSB_RVDC32(map->surf);
+ pipe->cntr = PSB_RVDC32(map->cntr);
+ pipe->status = PSB_RVDC32(map->status);
/*save palette (gamma) */
for (i = 0; i < 256; i++)
- palette_val[i] = PSB_RVDC32(palette_reg + (i << 2));
+ pipe->palette[i] = PSB_RVDC32(map->palette + (i << 2));
- if (pipe == 1) {
+ if (pipenum == 1) {
regs->savePFIT_CONTROL = PSB_RVDC32(PFIT_CONTROL);
regs->savePFIT_PGM_RATIOS = PSB_RVDC32(PFIT_PGM_RATIOS);
@@ -349,7 +237,7 @@ static int mdfld_save_display_registers(struct drm_device *dev, int pipe)
*
* Notes: FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
*/
-static int mdfld_restore_display_registers(struct drm_device *dev, int pipe)
+static int mdfld_restore_display_registers(struct drm_device *dev, int pipenum)
{
/* To get panel out of ULPS mode. */
u32 temp = 0;
@@ -357,142 +245,30 @@ static int mdfld_restore_display_registers(struct drm_device *dev, int pipe)
struct drm_psb_private *dev_priv = dev->dev_private;
struct mdfld_dsi_config *dsi_config = NULL;
struct medfield_state *regs = &dev_priv->regs.mdfld;
- u32 i = 0;
- u32 dpll = 0;
+ struct psb_pipe *pipe = &dev_priv->regs.pipe[pipenum];
+ const struct psb_offset *map = &dev_priv->regmap[pipenum];
+ u32 i;
+ u32 dpll;
u32 timeout = 0;
- /* regester */
- u32 dpll_reg = MRST_DPLL_A;
- u32 fp_reg = MRST_FPA0;
- u32 pipeconf_reg = PIPEACONF;
- u32 htot_reg = HTOTAL_A;
- u32 hblank_reg = HBLANK_A;
- u32 hsync_reg = HSYNC_A;
- u32 vtot_reg = VTOTAL_A;
- u32 vblank_reg = VBLANK_A;
- u32 vsync_reg = VSYNC_A;
- u32 pipesrc_reg = PIPEASRC;
- u32 dspstride_reg = DSPASTRIDE;
- u32 dsplinoff_reg = DSPALINOFF;
- u32 dsptileoff_reg = DSPATILEOFF;
- u32 dspsize_reg = DSPASIZE;
- u32 dsppos_reg = DSPAPOS;
- u32 dspsurf_reg = DSPASURF;
- u32 dspstatus_reg = PIPEASTAT;
+ /* register */
u32 mipi_reg = MIPI;
- u32 dspcntr_reg = DSPACNTR;
- u32 palette_reg = PALETTE_A;
/* values */
- u32 dpll_val = regs->saveDPLL_A & ~DPLL_VCO_ENABLE;
- u32 fp_val = regs->saveFPA0;
- u32 pipeconf_val = regs->savePIPEACONF;
- u32 htot_val = regs->saveHTOTAL_A;
- u32 hblank_val = regs->saveHBLANK_A;
- u32 hsync_val = regs->saveHSYNC_A;
- u32 vtot_val = regs->saveVTOTAL_A;
- u32 vblank_val = regs->saveVBLANK_A;
- u32 vsync_val = regs->saveVSYNC_A;
- u32 pipesrc_val = regs->savePIPEASRC;
- u32 dspstride_val = regs->saveDSPASTRIDE;
- u32 dsplinoff_val = regs->saveDSPALINOFF;
- u32 dsptileoff_val = regs->saveDSPATILEOFF;
- u32 dspsize_val = regs->saveDSPASIZE;
- u32 dsppos_val = regs->saveDSPAPOS;
- u32 dspsurf_val = regs->saveDSPASURF;
- u32 dspstatus_val = regs->saveDSPASTATUS;
+ u32 dpll_val = pipe->dpll;
u32 mipi_val = regs->saveMIPI;
- u32 dspcntr_val = regs->saveDSPACNTR;
- u32 *palette_val = regs->save_palette_a;
- switch (pipe) {
+ switch (pipenum) {
case 0:
+ dpll_val &= ~DPLL_VCO_ENABLE;
dsi_config = dev_priv->dsi_configs[0];
break;
case 1:
- /* regester */
- dpll_reg = MDFLD_DPLL_B;
- fp_reg = MDFLD_DPLL_DIV0;
- pipeconf_reg = PIPEBCONF;
- htot_reg = HTOTAL_B;
- hblank_reg = HBLANK_B;
- hsync_reg = HSYNC_B;
- vtot_reg = VTOTAL_B;
- vblank_reg = VBLANK_B;
- vsync_reg = VSYNC_B;
- pipesrc_reg = PIPEBSRC;
- dspstride_reg = DSPBSTRIDE;
- dsplinoff_reg = DSPBLINOFF;
- dsptileoff_reg = DSPBTILEOFF;
- dspsize_reg = DSPBSIZE;
- dsppos_reg = DSPBPOS;
- dspsurf_reg = DSPBSURF;
- dspcntr_reg = DSPBCNTR;
- dspstatus_reg = PIPEBSTAT;
- palette_reg = PALETTE_B;
-
- /* values */
- dpll_val = regs->saveDPLL_B & ~DPLL_VCO_ENABLE;
- fp_val = regs->saveFPB0;
- pipeconf_val = regs->savePIPEBCONF;
- htot_val = regs->saveHTOTAL_B;
- hblank_val = regs->saveHBLANK_B;
- hsync_val = regs->saveHSYNC_B;
- vtot_val = regs->saveVTOTAL_B;
- vblank_val = regs->saveVBLANK_B;
- vsync_val = regs->saveVSYNC_B;
- pipesrc_val = regs->savePIPEBSRC;
- dspstride_val = regs->saveDSPBSTRIDE;
- dsplinoff_val = regs->saveDSPBLINOFF;
- dsptileoff_val = regs->saveDSPBTILEOFF;
- dspsize_val = regs->saveDSPBSIZE;
- dsppos_val = regs->saveDSPBPOS;
- dspsurf_val = regs->saveDSPBSURF;
- dspcntr_val = regs->saveDSPBCNTR;
- dspstatus_val = regs->saveDSPBSTATUS;
- palette_val = regs->save_palette_b;
+ dpll_val &= ~DPLL_VCO_ENABLE;
break;
case 2:
- /* regester */
- pipeconf_reg = PIPECCONF;
- htot_reg = HTOTAL_C;
- hblank_reg = HBLANK_C;
- hsync_reg = HSYNC_C;
- vtot_reg = VTOTAL_C;
- vblank_reg = VBLANK_C;
- vsync_reg = VSYNC_C;
- pipesrc_reg = PIPECSRC;
- dspstride_reg = DSPCSTRIDE;
- dsplinoff_reg = DSPCLINOFF;
- dsptileoff_reg = DSPCTILEOFF;
- dspsize_reg = DSPCSIZE;
- dsppos_reg = DSPCPOS;
- dspsurf_reg = DSPCSURF;
mipi_reg = MIPI_C;
- dspcntr_reg = DSPCCNTR;
- dspstatus_reg = PIPECSTAT;
- palette_reg = PALETTE_C;
-
- /* values */
- pipeconf_val = regs->savePIPECCONF;
- htot_val = regs->saveHTOTAL_C;
- hblank_val = regs->saveHBLANK_C;
- hsync_val = regs->saveHSYNC_C;
- vtot_val = regs->saveVTOTAL_C;
- vblank_val = regs->saveVBLANK_C;
- vsync_val = regs->saveVSYNC_C;
- pipesrc_val = regs->savePIPECSRC;
- dspstride_val = regs->saveDSPCSTRIDE;
- dsplinoff_val = regs->saveDSPCLINOFF;
- dsptileoff_val = regs->saveDSPCTILEOFF;
- dspsize_val = regs->saveDSPCSIZE;
- dsppos_val = regs->saveDSPCPOS;
- dspsurf_val = regs->saveDSPCSURF;
mipi_val = regs->saveMIPI_C;
- dspcntr_val = regs->saveDSPCCNTR;
- dspstatus_val = regs->saveDSPCSTATUS;
- palette_val = regs->save_palette_c;
-
dsi_config = dev_priv->dsi_configs[1];
break;
default:
@@ -503,14 +279,14 @@ static int mdfld_restore_display_registers(struct drm_device *dev, int pipe)
/*make sure VGA plane is off. it initializes to on after reset!*/
PSB_WVDC32(0x80000000, VGACNTRL);
- if (pipe == 1) {
- PSB_WVDC32(dpll_val & ~DPLL_VCO_ENABLE, dpll_reg);
- PSB_RVDC32(dpll_reg);
+ if (pipenum == 1) {
+ PSB_WVDC32(dpll_val & ~DPLL_VCO_ENABLE, map->dpll);
+ PSB_RVDC32(map->dpll);
- PSB_WVDC32(fp_val, fp_reg);
+ PSB_WVDC32(pipe->fp0, map->fp0);
} else {
- dpll = PSB_RVDC32(dpll_reg);
+ dpll = PSB_RVDC32(map->dpll);
if (!(dpll & DPLL_VCO_ENABLE)) {
@@ -518,23 +294,23 @@ static int mdfld_restore_display_registers(struct drm_device *dev, int pipe)
before enable the VCO */
if (dpll & MDFLD_PWR_GATE_EN) {
dpll &= ~MDFLD_PWR_GATE_EN;
- PSB_WVDC32(dpll, dpll_reg);
+ PSB_WVDC32(dpll, map->dpll);
/* FIXME_MDFLD PO - change 500 to 1 after PO */
udelay(500);
}
- PSB_WVDC32(fp_val, fp_reg);
- PSB_WVDC32(dpll_val, dpll_reg);
+ PSB_WVDC32(pipe->fp0, map->fp0);
+ PSB_WVDC32(dpll_val, map->dpll);
/* FIXME_MDFLD PO - change 500 to 1 after PO */
udelay(500);
dpll_val |= DPLL_VCO_ENABLE;
- PSB_WVDC32(dpll_val, dpll_reg);
- PSB_RVDC32(dpll_reg);
+ PSB_WVDC32(dpll_val, map->dpll);
+ PSB_RVDC32(map->dpll);
/* wait for DSI PLL to lock */
while (timeout < 20000 &&
- !(PSB_RVDC32(pipeconf_reg) & PIPECONF_DSIPLL_LOCK)) {
+ !(PSB_RVDC32(map->conf) & PIPECONF_DSIPLL_LOCK)) {
udelay(150);
timeout++;
}
@@ -547,28 +323,28 @@ static int mdfld_restore_display_registers(struct drm_device *dev, int pipe)
}
}
/* Restore mode */
- PSB_WVDC32(htot_val, htot_reg);
- PSB_WVDC32(hblank_val, hblank_reg);
- PSB_WVDC32(hsync_val, hsync_reg);
- PSB_WVDC32(vtot_val, vtot_reg);
- PSB_WVDC32(vblank_val, vblank_reg);
- PSB_WVDC32(vsync_val, vsync_reg);
- PSB_WVDC32(pipesrc_val, pipesrc_reg);
- PSB_WVDC32(dspstatus_val, dspstatus_reg);
+ PSB_WVDC32(pipe->htotal, map->htotal);
+ PSB_WVDC32(pipe->hblank, map->hblank);
+ PSB_WVDC32(pipe->hsync, map->hsync);
+ PSB_WVDC32(pipe->vtotal, map->vtotal);
+ PSB_WVDC32(pipe->vblank, map->vblank);
+ PSB_WVDC32(pipe->vsync, map->vsync);
+ PSB_WVDC32(pipe->src, map->src);
+ PSB_WVDC32(pipe->status, map->status);
/*set up the plane*/
- PSB_WVDC32(dspstride_val, dspstride_reg);
- PSB_WVDC32(dsplinoff_val, dsplinoff_reg);
- PSB_WVDC32(dsptileoff_val, dsptileoff_reg);
- PSB_WVDC32(dspsize_val, dspsize_reg);
- PSB_WVDC32(dsppos_val, dsppos_reg);
- PSB_WVDC32(dspsurf_val, dspsurf_reg);
-
- if (pipe == 1) {
+ PSB_WVDC32(pipe->stride, map->stride);
+ PSB_WVDC32(pipe->linoff, map->linoff);
+ PSB_WVDC32(pipe->tileoff, map->tileoff);
+ PSB_WVDC32(pipe->size, map->size);
+ PSB_WVDC32(pipe->pos, map->pos);
+ PSB_WVDC32(pipe->surf, map->surf);
+
+ if (pipenum == 1) {
/* restore palette (gamma) */
/*DRM_UDELAY(50000); */
for (i = 0; i < 256; i++)
- PSB_WVDC32(palette_val[i], palette_reg + (i << 2));
+ PSB_WVDC32(pipe->palette[i], map->palette + (i << 2));
PSB_WVDC32(regs->savePFIT_CONTROL, PFIT_CONTROL);
PSB_WVDC32(regs->savePFIT_PGM_RATIOS, PFIT_PGM_RATIOS);
@@ -578,7 +354,7 @@ static int mdfld_restore_display_registers(struct drm_device *dev, int pipe)
/*TODO: resume pipe*/
/*enable the plane*/
- PSB_WVDC32(dspcntr_val & ~DISPLAY_PLANE_ENABLE, dspcntr_reg);
+ PSB_WVDC32(pipe->cntr & ~DISPLAY_PLANE_ENABLE, map->cntr);
return 0;
}
@@ -588,7 +364,7 @@ static int mdfld_restore_display_registers(struct drm_device *dev, int pipe)
/*setup MIPI adapter + MIPI IP registers*/
if (dsi_config)
- mdfld_dsi_controller_init(dsi_config, pipe);
+ mdfld_dsi_controller_init(dsi_config, pipenum);
if (in_atomic() || in_interrupt())
mdelay(20);
@@ -596,7 +372,7 @@ static int mdfld_restore_display_registers(struct drm_device *dev, int pipe)
msleep(20);
/*enable the plane*/
- PSB_WVDC32(dspcntr_val, dspcntr_reg);
+ PSB_WVDC32(pipe->cntr, map->cntr);
if (in_atomic() || in_interrupt())
mdelay(20);
@@ -625,12 +401,12 @@ static int mdfld_restore_display_registers(struct drm_device *dev, int pipe)
mdelay(1);
/*enable the pipe*/
- PSB_WVDC32(pipeconf_val, pipeconf_reg);
+ PSB_WVDC32(pipe->conf, map->conf);
/* restore palette (gamma) */
/*DRM_UDELAY(50000); */
for (i = 0; i < 256; i++)
- PSB_WVDC32(palette_val[i], palette_reg + (i << 2));
+ PSB_WVDC32(pipe->palette[i], map->palette + (i << 2));
return 0;
}
@@ -667,14 +443,98 @@ static int mdfld_power_up(struct drm_device *dev)
return 0;
}
+/* Medfield */
+static const struct psb_offset mdfld_regmap[3] = {
+ {
+ .fp0 = MRST_FPA0,
+ .fp1 = MRST_FPA1,
+ .cntr = DSPACNTR,
+ .conf = PIPEACONF,
+ .src = PIPEASRC,
+ .dpll = MRST_DPLL_A,
+ .htotal = HTOTAL_A,
+ .hblank = HBLANK_A,
+ .hsync = HSYNC_A,
+ .vtotal = VTOTAL_A,
+ .vblank = VBLANK_A,
+ .vsync = VSYNC_A,
+ .stride = DSPASTRIDE,
+ .size = DSPASIZE,
+ .pos = DSPAPOS,
+ .surf = DSPASURF,
+ .addr = MRST_DSPABASE,
+ .status = PIPEASTAT,
+ .linoff = DSPALINOFF,
+ .tileoff = DSPATILEOFF,
+ .palette = PALETTE_A,
+ },
+ {
+ .fp0 = MDFLD_DPLL_DIV0,
+ .cntr = DSPBCNTR,
+ .conf = PIPEBCONF,
+ .src = PIPEBSRC,
+ .dpll = MDFLD_DPLL_B,
+ .htotal = HTOTAL_B,
+ .hblank = HBLANK_B,
+ .hsync = HSYNC_B,
+ .vtotal = VTOTAL_B,
+ .vblank = VBLANK_B,
+ .vsync = VSYNC_B,
+ .stride = DSPBSTRIDE,
+ .size = DSPBSIZE,
+ .pos = DSPBPOS,
+ .surf = DSPBSURF,
+ .addr = MRST_DSPBBASE,
+ .status = PIPEBSTAT,
+ .linoff = DSPBLINOFF,
+ .tileoff = DSPBTILEOFF,
+ .palette = PALETTE_B,
+ },
+ {
+ .fp0 = MRST_FPA0, /* This is what the old code did ?? */
+ .cntr = DSPCCNTR,
+ .conf = PIPECCONF,
+ .src = PIPECSRC,
+ /* No DPLL_C */
+ .dpll = MRST_DPLL_A,
+ .htotal = HTOTAL_C,
+ .hblank = HBLANK_C,
+ .hsync = HSYNC_C,
+ .vtotal = VTOTAL_C,
+ .vblank = VBLANK_C,
+ .vsync = VSYNC_C,
+ .stride = DSPCSTRIDE,
+ .size = DSPBSIZE,
+ .pos = DSPCPOS,
+ .surf = DSPCSURF,
+ .addr = MDFLD_DSPCBASE,
+ .status = PIPECSTAT,
+ .linoff = DSPCLINOFF,
+ .tileoff = DSPCTILEOFF,
+ .palette = PALETTE_C,
+ },
+};
+
+static int mdfld_chip_setup(struct drm_device *dev)
+{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ if (pci_enable_msi(dev->pdev))
+ dev_warn(dev->dev, "Enabling MSI failed!\n");
+ dev_priv->regmap = mdfld_regmap;
+ return mid_chip_setup(dev);
+}
+
const struct psb_ops mdfld_chip_ops = {
.name = "mdfld",
.accel_2d = 0,
.pipes = 3,
.crtcs = 3,
+ .lvds_mask = (1 << 1),
+ .hdmi_mask = (1 << 1),
+ .cursor_needs_phys = 0,
.sgx_offset = MRST_SGX_OFFSET,
- .chip_setup = mid_chip_setup,
+ .chip_setup = mdfld_chip_setup,
.crtc_helper = &mdfld_helper_funcs,
.crtc_funcs = &psb_intel_crtc_funcs,
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c
index d52358b744a0..b34ff097b979 100644
--- a/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_dpi.c
@@ -869,7 +869,6 @@ void mdfld_dsi_dpi_mode_set(struct drm_encoder *encoder,
mdfld_set_pipe_timing(dsi_config, pipe);
REG_WRITE(DSPABASE, 0x00);
- REG_WRITE(DSPASTRIDE, (mode->hdisplay * 4));
REG_WRITE(DSPASIZE,
((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1));
diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c b/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c
index baa0e14165e0..489ffd2c66e5 100644
--- a/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c
+++ b/drivers/gpu/drm/gma500/mdfld_dsi_pkg_sender.c
@@ -605,6 +605,8 @@ int mdfld_dsi_pkg_sender_init(struct mdfld_dsi_connector *dsi_connector,
struct mdfld_dsi_config *dsi_config =
mdfld_dsi_get_config(dsi_connector);
struct drm_device *dev = dsi_config->dev;
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ const struct psb_offset *map = &dev_priv->regmap[pipe];
u32 mipi_val = 0;
if (!dsi_connector) {
@@ -632,21 +634,13 @@ int mdfld_dsi_pkg_sender_init(struct mdfld_dsi_connector *dsi_connector,
pkg_sender->status = MDFLD_DSI_PKG_SENDER_FREE;
/*init regs*/
- if (pipe == 0) {
- pkg_sender->dpll_reg = MRST_DPLL_A;
- pkg_sender->dspcntr_reg = DSPACNTR;
- pkg_sender->pipeconf_reg = PIPEACONF;
- pkg_sender->dsplinoff_reg = DSPALINOFF;
- pkg_sender->dspsurf_reg = DSPASURF;
- pkg_sender->pipestat_reg = PIPEASTAT;
- } else if (pipe == 2) {
- pkg_sender->dpll_reg = MRST_DPLL_A;
- pkg_sender->dspcntr_reg = DSPCCNTR;
- pkg_sender->pipeconf_reg = PIPECCONF;
- pkg_sender->dsplinoff_reg = DSPCLINOFF;
- pkg_sender->dspsurf_reg = DSPCSURF;
- pkg_sender->pipestat_reg = PIPECSTAT;
- }
+ /* FIXME: should just copy the regmap ptr ? */
+ pkg_sender->dpll_reg = map->dpll;
+ pkg_sender->dspcntr_reg = map->cntr;
+ pkg_sender->pipeconf_reg = map->conf;
+ pkg_sender->dsplinoff_reg = map->linoff;
+ pkg_sender->dspsurf_reg = map->surf;
+ pkg_sender->pipestat_reg = map->status;
pkg_sender->mipi_intr_stat_reg = MIPI_INTR_STAT_REG(pipe);
pkg_sender->mipi_lp_gen_data_reg = MIPI_LP_GEN_DATA_REG(pipe);
diff --git a/drivers/gpu/drm/gma500/mdfld_intel_display.c b/drivers/gpu/drm/gma500/mdfld_intel_display.c
index a35a2921bdf7..3f3cd619c79f 100644
--- a/drivers/gpu/drm/gma500/mdfld_intel_display.c
+++ b/drivers/gpu/drm/gma500/mdfld_intel_display.c
@@ -50,17 +50,14 @@ struct mrst_clock_t {
void mdfldWaitForPipeDisable(struct drm_device *dev, int pipe)
{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ const struct psb_offset *map = &dev_priv->regmap[pipe];
int count, temp;
- u32 pipeconf_reg = PIPEACONF;
switch (pipe) {
case 0:
- break;
case 1:
- pipeconf_reg = PIPEBCONF;
- break;
case 2:
- pipeconf_reg = PIPECCONF;
break;
default:
DRM_ERROR("Illegal Pipe Number.\n");
@@ -73,7 +70,7 @@ void mdfldWaitForPipeDisable(struct drm_device *dev, int pipe)
/* Wait for for the pipe disable to take effect. */
for (count = 0; count < COUNT_MAX; count++) {
- temp = REG_READ(pipeconf_reg);
+ temp = REG_READ(map->conf);
if ((temp & PIPEACONF_PIPE_STATE) == 0)
break;
}
@@ -81,17 +78,14 @@ void mdfldWaitForPipeDisable(struct drm_device *dev, int pipe)
void mdfldWaitForPipeEnable(struct drm_device *dev, int pipe)
{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ const struct psb_offset *map = &dev_priv->regmap[pipe];
int count, temp;
- u32 pipeconf_reg = PIPEACONF;
switch (pipe) {
case 0:
- break;
case 1:
- pipeconf_reg = PIPEBCONF;
- break;
case 2:
- pipeconf_reg = PIPECCONF;
break;
default:
DRM_ERROR("Illegal Pipe Number.\n");
@@ -104,7 +98,7 @@ void mdfldWaitForPipeEnable(struct drm_device *dev, int pipe)
/* Wait for for the pipe enable to take effect. */
for (count = 0; count < COUNT_MAX; count++) {
- temp = REG_READ(pipeconf_reg);
+ temp = REG_READ(map->conf);
if ((temp & PIPEACONF_PIPE_STATE) == 1)
break;
}
@@ -189,15 +183,12 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
{
struct drm_device *dev = crtc->dev;
- /* struct drm_i915_master_private *master_priv; */
+ struct drm_psb_private *dev_priv = dev->dev_private;
struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
int pipe = psb_intel_crtc->pipe;
+ const struct psb_offset *map = &dev_priv->regmap[pipe];
unsigned long start, offset;
- int dsplinoff = DSPALINOFF;
- int dspsurf = DSPASURF;
- int dspstride = DSPASTRIDE;
- int dspcntr_reg = DSPACNTR;
u32 dspcntr;
int ret;
@@ -215,23 +206,7 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
if (ret)
return ret;
- switch (pipe) {
- case 0:
- dsplinoff = DSPALINOFF;
- break;
- case 1:
- dsplinoff = DSPBLINOFF;
- dspsurf = DSPBSURF;
- dspstride = DSPBSTRIDE;
- dspcntr_reg = DSPBCNTR;
- break;
- case 2:
- dsplinoff = DSPCLINOFF;
- dspsurf = DSPCSURF;
- dspstride = DSPCSTRIDE;
- dspcntr_reg = DSPCCNTR;
- break;
- default:
+ if (pipe > 2) {
DRM_ERROR("Illegal Pipe Number.\n");
return -EINVAL;
}
@@ -242,8 +217,8 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
start = psbfb->gtt->offset;
offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8);
- REG_WRITE(dspstride, crtc->fb->pitches[0]);
- dspcntr = REG_READ(dspcntr_reg);
+ REG_WRITE(map->stride, crtc->fb->pitches[0]);
+ dspcntr = REG_READ(map->cntr);
dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
switch (crtc->fb->bits_per_pixel) {
@@ -261,14 +236,14 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
break;
}
- REG_WRITE(dspcntr_reg, dspcntr);
+ REG_WRITE(map->cntr, dspcntr);
dev_dbg(dev->dev, "Writing base %08lX %08lX %d %d\n",
start, offset, x, y);
- REG_WRITE(dsplinoff, offset);
- REG_READ(dsplinoff);
- REG_WRITE(dspsurf, start);
- REG_READ(dspsurf);
+ REG_WRITE(map->linoff, offset);
+ REG_READ(map->linoff);
+ REG_WRITE(map->surf, start);
+ REG_READ(map->surf);
gma_power_end(dev);
@@ -281,78 +256,56 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
*/
void mdfld_disable_crtc(struct drm_device *dev, int pipe)
{
- int dpll_reg = MRST_DPLL_A;
- int dspcntr_reg = DSPACNTR;
- int dspbase_reg = MRST_DSPABASE;
- int pipeconf_reg = PIPEACONF;
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ const struct psb_offset *map = &dev_priv->regmap[pipe];
u32 temp;
dev_dbg(dev->dev, "pipe = %d\n", pipe);
- switch (pipe) {
- case 0:
- break;
- case 1:
- dpll_reg = MDFLD_DPLL_B;
- dspcntr_reg = DSPBCNTR;
- dspbase_reg = DSPBSURF;
- pipeconf_reg = PIPEBCONF;
- break;
- case 2:
- dpll_reg = MRST_DPLL_A;
- dspcntr_reg = DSPCCNTR;
- dspbase_reg = MDFLD_DSPCBASE;
- pipeconf_reg = PIPECCONF;
- break;
- default:
- DRM_ERROR("Illegal Pipe Number.\n");
- return;
- }
-
if (pipe != 1)
mdfld_dsi_gen_fifo_ready(dev, MIPI_GEN_FIFO_STAT_REG(pipe),
HS_CTRL_FIFO_EMPTY | HS_DATA_FIFO_EMPTY);
/* Disable display plane */
- temp = REG_READ(dspcntr_reg);
+ temp = REG_READ(map->cntr);
if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
- REG_WRITE(dspcntr_reg,
+ REG_WRITE(map->cntr,
temp & ~DISPLAY_PLANE_ENABLE);
/* Flush the plane changes */
- REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
- REG_READ(dspbase_reg);
+ REG_WRITE(map->base, REG_READ(map->base));
+ REG_READ(map->base);
}
/* FIXME_JLIU7 MDFLD_PO revisit */
/* Next, disable display pipes */
- temp = REG_READ(pipeconf_reg);
+ temp = REG_READ(map->conf);
if ((temp & PIPEACONF_ENABLE) != 0) {
temp &= ~PIPEACONF_ENABLE;
temp |= PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF;
- REG_WRITE(pipeconf_reg, temp);
- REG_READ(pipeconf_reg);
+ REG_WRITE(map->conf, temp);
+ REG_READ(map->conf);
/* Wait for for the pipe disable to take effect. */
mdfldWaitForPipeDisable(dev, pipe);
}
- temp = REG_READ(dpll_reg);
+ temp = REG_READ(map->dpll);
if (temp & DPLL_VCO_ENABLE) {
if ((pipe != 1 &&
!((REG_READ(PIPEACONF) | REG_READ(PIPECCONF))
& PIPEACONF_ENABLE)) || pipe == 1) {
temp &= ~(DPLL_VCO_ENABLE);
- REG_WRITE(dpll_reg, temp);
- REG_READ(dpll_reg);
+ REG_WRITE(map->dpll, temp);
+ REG_READ(map->dpll);
/* Wait for the clocks to turn off. */
/* FIXME_MDFLD PO may need more delay */
udelay(500);
if (!(temp & MDFLD_PWR_GATE_EN)) {
/* gating power of DPLL */
- REG_WRITE(dpll_reg, temp | MDFLD_PWR_GATE_EN);
+ REG_WRITE(map->dpll, temp | MDFLD_PWR_GATE_EN);
/* FIXME_MDFLD PO - change 500 to 1 after PO */
udelay(5000);
}
@@ -373,41 +326,15 @@ static void mdfld_crtc_dpms(struct drm_crtc *crtc, int mode)
struct drm_psb_private *dev_priv = dev->dev_private;
struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
int pipe = psb_intel_crtc->pipe;
- int dpll_reg = MRST_DPLL_A;
- int dspcntr_reg = DSPACNTR;
- int dspbase_reg = MRST_DSPABASE;
- int pipeconf_reg = PIPEACONF;
- u32 pipestat_reg = PIPEASTAT;
+ const struct psb_offset *map = &dev_priv->regmap[pipe];
u32 pipeconf = dev_priv->pipeconf[pipe];
u32 temp;
int timeout = 0;
dev_dbg(dev->dev, "mode = %d, pipe = %d\n", mode, pipe);
-/* FIXME_JLIU7 MDFLD_PO replaced w/ the following function */
-/* mdfld_dbi_dpms (struct drm_device *dev, int pipe, bool enabled) */
-
- switch (pipe) {
- case 0:
- break;
- case 1:
- dpll_reg = DPLL_B;
- dspcntr_reg = DSPBCNTR;
- dspbase_reg = MRST_DSPBBASE;
- pipeconf_reg = PIPEBCONF;
- dpll_reg = MDFLD_DPLL_B;
- break;
- case 2:
- dpll_reg = MRST_DPLL_A;
- dspcntr_reg = DSPCCNTR;
- dspbase_reg = MDFLD_DSPCBASE;
- pipeconf_reg = PIPECCONF;
- pipestat_reg = PIPECSTAT;
- break;
- default:
- DRM_ERROR("Illegal Pipe Number.\n");
- return;
- }
+ /* Note: Old code uses pipe a stat for pipe b but that appears
+ to be a bug */
if (!gma_power_begin(dev, true))
return;
@@ -420,25 +347,25 @@ static void mdfld_crtc_dpms(struct drm_crtc *crtc, int mode)
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
/* Enable the DPLL */
- temp = REG_READ(dpll_reg);
+ temp = REG_READ(map->dpll);
if ((temp & DPLL_VCO_ENABLE) == 0) {
/* When ungating power of DPLL, needs to wait 0.5us
before enable the VCO */
if (temp & MDFLD_PWR_GATE_EN) {
temp &= ~MDFLD_PWR_GATE_EN;
- REG_WRITE(dpll_reg, temp);
+ REG_WRITE(map->dpll, temp);
/* FIXME_MDFLD PO - change 500 to 1 after PO */
udelay(500);
}
- REG_WRITE(dpll_reg, temp);
- REG_READ(dpll_reg);
+ REG_WRITE(map->dpll, temp);
+ REG_READ(map->dpll);
/* FIXME_MDFLD PO - change 500 to 1 after PO */
udelay(500);
- REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
- REG_READ(dpll_reg);
+ REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE);
+ REG_READ(map->dpll);
/**
* wait for DSI PLL to lock
@@ -446,25 +373,25 @@ static void mdfld_crtc_dpms(struct drm_crtc *crtc, int mode)
* since both MIPI pipes share the same PLL.
*/
while ((pipe != 2) && (timeout < 20000) &&
- !(REG_READ(pipeconf_reg) & PIPECONF_DSIPLL_LOCK)) {
+ !(REG_READ(map->conf) & PIPECONF_DSIPLL_LOCK)) {
udelay(150);
timeout++;
}
}
/* Enable the plane */
- temp = REG_READ(dspcntr_reg);
+ temp = REG_READ(map->cntr);
if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
- REG_WRITE(dspcntr_reg,
+ REG_WRITE(map->cntr,
temp | DISPLAY_PLANE_ENABLE);
/* Flush the plane changes */
- REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
+ REG_WRITE(map->base, REG_READ(map->base));
}
/* Enable the pipe */
- temp = REG_READ(pipeconf_reg);
+ temp = REG_READ(map->conf);
if ((temp & PIPEACONF_ENABLE) == 0) {
- REG_WRITE(pipeconf_reg, pipeconf);
+ REG_WRITE(map->conf, pipeconf);
/* Wait for for the pipe enable to take effect. */
mdfldWaitForPipeEnable(dev, pipe);
@@ -473,39 +400,39 @@ static void mdfld_crtc_dpms(struct drm_crtc *crtc, int mode)
/*workaround for sighting 3741701 Random X blank display*/
/*perform w/a in video mode only on pipe A or C*/
if (pipe == 0 || pipe == 2) {
- REG_WRITE(pipestat_reg, REG_READ(pipestat_reg));
+ REG_WRITE(map->status, REG_READ(map->status));
msleep(100);
- if (PIPE_VBLANK_STATUS & REG_READ(pipestat_reg))
+ if (PIPE_VBLANK_STATUS & REG_READ(map->status))
dev_dbg(dev->dev, "OK");
else {
dev_dbg(dev->dev, "STUCK!!!!");
/*shutdown controller*/
- temp = REG_READ(dspcntr_reg);
- REG_WRITE(dspcntr_reg,
+ temp = REG_READ(map->cntr);
+ REG_WRITE(map->cntr,
temp & ~DISPLAY_PLANE_ENABLE);
- REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
+ REG_WRITE(map->base, REG_READ(map->base));
/*mdfld_dsi_dpi_shut_down(dev, pipe);*/
REG_WRITE(0xb048, 1);
msleep(100);
- temp = REG_READ(pipeconf_reg);
+ temp = REG_READ(map->conf);
temp &= ~PIPEACONF_ENABLE;
- REG_WRITE(pipeconf_reg, temp);
+ REG_WRITE(map->conf, temp);
msleep(100); /*wait for pipe disable*/
REG_WRITE(MIPI_DEVICE_READY_REG(pipe), 0);
msleep(100);
REG_WRITE(0xb004, REG_READ(0xb004));
/* try to bring the controller back up again*/
REG_WRITE(MIPI_DEVICE_READY_REG(pipe), 1);
- temp = REG_READ(dspcntr_reg);
- REG_WRITE(dspcntr_reg,
+ temp = REG_READ(map->cntr);
+ REG_WRITE(map->cntr,
temp | DISPLAY_PLANE_ENABLE);
- REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
+ REG_WRITE(map->base, REG_READ(map->base));
/*mdfld_dsi_dpi_turn_on(dev, pipe);*/
REG_WRITE(0xb048, 2);
msleep(100);
- temp = REG_READ(pipeconf_reg);
+ temp = REG_READ(map->conf);
temp |= PIPEACONF_ENABLE;
- REG_WRITE(pipeconf_reg, temp);
+ REG_WRITE(map->conf, temp);
}
}
@@ -529,35 +456,35 @@ static void mdfld_crtc_dpms(struct drm_crtc *crtc, int mode)
REG_WRITE(VGACNTRL, VGA_DISP_DISABLE);
/* Disable display plane */
- temp = REG_READ(dspcntr_reg);
+ temp = REG_READ(map->cntr);
if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
- REG_WRITE(dspcntr_reg,
+ REG_WRITE(map->cntr,
temp & ~DISPLAY_PLANE_ENABLE);
/* Flush the plane changes */
- REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
- REG_READ(dspbase_reg);
+ REG_WRITE(map->base, REG_READ(map->base));
+ REG_READ(map->base);
}
/* Next, disable display pipes */
- temp = REG_READ(pipeconf_reg);
+ temp = REG_READ(map->conf);
if ((temp & PIPEACONF_ENABLE) != 0) {
temp &= ~PIPEACONF_ENABLE;
temp |= PIPECONF_PLANE_OFF | PIPECONF_CURSOR_OFF;
- REG_WRITE(pipeconf_reg, temp);
- REG_READ(pipeconf_reg);
+ REG_WRITE(map->conf, temp);
+ REG_READ(map->conf);
/* Wait for for the pipe disable to take effect. */
mdfldWaitForPipeDisable(dev, pipe);
}
- temp = REG_READ(dpll_reg);
+ temp = REG_READ(map->dpll);
if (temp & DPLL_VCO_ENABLE) {
if ((pipe != 1 && !((REG_READ(PIPEACONF)
| REG_READ(PIPECCONF)) & PIPEACONF_ENABLE))
|| pipe == 1) {
temp &= ~(DPLL_VCO_ENABLE);
- REG_WRITE(dpll_reg, temp);
- REG_READ(dpll_reg);
+ REG_WRITE(map->dpll, temp);
+ REG_READ(map->dpll);
/* Wait for the clocks to turn off. */
/* FIXME_MDFLD PO may need more delay */
udelay(500);
@@ -764,21 +691,7 @@ static int mdfld_crtc_mode_set(struct drm_crtc *crtc,
struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
struct drm_psb_private *dev_priv = dev->dev_private;
int pipe = psb_intel_crtc->pipe;
- int fp_reg = MRST_FPA0;
- int dpll_reg = MRST_DPLL_A;
- int dspcntr_reg = DSPACNTR;
- int pipeconf_reg = PIPEACONF;
- int htot_reg = HTOTAL_A;
- int hblank_reg = HBLANK_A;
- int hsync_reg = HSYNC_A;
- int vtot_reg = VTOTAL_A;
- int vblank_reg = VBLANK_A;
- int vsync_reg = VSYNC_A;
- int dspsize_reg = DSPASIZE;
- int dsppos_reg = DSPAPOS;
- int pipesrc_reg = PIPEASRC;
- u32 *pipeconf = &dev_priv->pipeconf[pipe];
- u32 *dspcntr = &dev_priv->dspcntr[pipe];
+ const struct psb_offset *map = &dev_priv->regmap[pipe];
int refclk = 0;
int clk_n = 0, clk_p2 = 0, clk_byte = 1, clk = 0, m_conv = 0,
clk_tmp = 0;
@@ -806,45 +719,6 @@ static int mdfld_crtc_mode_set(struct drm_crtc *crtc,
}
#endif
- switch (pipe) {
- case 0:
- break;
- case 1:
- fp_reg = FPB0;
- dpll_reg = DPLL_B;
- dspcntr_reg = DSPBCNTR;
- pipeconf_reg = PIPEBCONF;
- htot_reg = HTOTAL_B;
- hblank_reg = HBLANK_B;
- hsync_reg = HSYNC_B;
- vtot_reg = VTOTAL_B;
- vblank_reg = VBLANK_B;
- vsync_reg = VSYNC_B;
- dspsize_reg = DSPBSIZE;
- dsppos_reg = DSPBPOS;
- pipesrc_reg = PIPEBSRC;
- fp_reg = MDFLD_DPLL_DIV0;
- dpll_reg = MDFLD_DPLL_B;
- break;
- case 2:
- dpll_reg = MRST_DPLL_A;
- dspcntr_reg = DSPCCNTR;
- pipeconf_reg = PIPECCONF;
- htot_reg = HTOTAL_C;
- hblank_reg = HBLANK_C;
- hsync_reg = HSYNC_C;
- vtot_reg = VTOTAL_C;
- vblank_reg = VBLANK_C;
- vsync_reg = VSYNC_C;
- dspsize_reg = DSPCSIZE;
- dsppos_reg = DSPCPOS;
- pipesrc_reg = PIPECSRC;
- break;
- default:
- DRM_ERROR("Illegal Pipe Number.\n");
- return 0;
- }
-
ret = check_fb(crtc->fb);
if (ret)
return ret;
@@ -929,21 +803,21 @@ static int mdfld_crtc_mode_set(struct drm_crtc *crtc,
* contained within the displayable area of the screen image
* (frame buffer).
*/
- REG_WRITE(dspsize_reg, ((min(mode->crtc_vdisplay, adjusted_mode->crtc_vdisplay) - 1) << 16)
+ REG_WRITE(map->size, ((min(mode->crtc_vdisplay, adjusted_mode->crtc_vdisplay) - 1) << 16)
| (min(mode->crtc_hdisplay, adjusted_mode->crtc_hdisplay) - 1));
/* Set the CRTC with encoder mode. */
- REG_WRITE(pipesrc_reg, ((mode->crtc_hdisplay - 1) << 16)
+ REG_WRITE(map->src, ((mode->crtc_hdisplay - 1) << 16)
| (mode->crtc_vdisplay - 1));
} else {
- REG_WRITE(dspsize_reg,
+ REG_WRITE(map->size,
((mode->crtc_vdisplay - 1) << 16) |
(mode->crtc_hdisplay - 1));
- REG_WRITE(pipesrc_reg,
+ REG_WRITE(map->src,
((mode->crtc_hdisplay - 1) << 16) |
(mode->crtc_vdisplay - 1));
}
- REG_WRITE(dsppos_reg, 0);
+ REG_WRITE(map->pos, 0);
if (psb_intel_encoder)
drm_connector_property_get_value(connector,
@@ -961,34 +835,34 @@ static int mdfld_crtc_mode_set(struct drm_crtc *crtc,
offsetY = (adjusted_mode->crtc_vdisplay -
mode->crtc_vdisplay) / 2;
- REG_WRITE(htot_reg, (mode->crtc_hdisplay - 1) |
+ REG_WRITE(map->htotal, (mode->crtc_hdisplay - 1) |
((adjusted_mode->crtc_htotal - 1) << 16));
- REG_WRITE(vtot_reg, (mode->crtc_vdisplay - 1) |
+ REG_WRITE(map->vtotal, (mode->crtc_vdisplay - 1) |
((adjusted_mode->crtc_vtotal - 1) << 16));
- REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start -
+ REG_WRITE(map->hblank, (adjusted_mode->crtc_hblank_start -
offsetX - 1) |
((adjusted_mode->crtc_hblank_end - offsetX - 1) << 16));
- REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start -
+ REG_WRITE(map->hsync, (adjusted_mode->crtc_hsync_start -
offsetX - 1) |
((adjusted_mode->crtc_hsync_end - offsetX - 1) << 16));
- REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start -
+ REG_WRITE(map->vblank, (adjusted_mode->crtc_vblank_start -
offsetY - 1) |
((adjusted_mode->crtc_vblank_end - offsetY - 1) << 16));
- REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start -
+ REG_WRITE(map->vsync, (adjusted_mode->crtc_vsync_start -
offsetY - 1) |
((adjusted_mode->crtc_vsync_end - offsetY - 1) << 16));
} else {
- REG_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
+ REG_WRITE(map->htotal, (adjusted_mode->crtc_hdisplay - 1) |
((adjusted_mode->crtc_htotal - 1) << 16));
- REG_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) |
+ REG_WRITE(map->vtotal, (adjusted_mode->crtc_vdisplay - 1) |
((adjusted_mode->crtc_vtotal - 1) << 16));
- REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) |
+ REG_WRITE(map->hblank, (adjusted_mode->crtc_hblank_start - 1) |
((adjusted_mode->crtc_hblank_end - 1) << 16));
- REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) |
+ REG_WRITE(map->hsync, (adjusted_mode->crtc_hsync_start - 1) |
((adjusted_mode->crtc_hsync_end - 1) << 16));
- REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) |
+ REG_WRITE(map->vblank, (adjusted_mode->crtc_vblank_start - 1) |
((adjusted_mode->crtc_vblank_end - 1) << 16));
- REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) |
+ REG_WRITE(map->vsync, (adjusted_mode->crtc_vsync_start - 1) |
((adjusted_mode->crtc_vsync_end - 1) << 16));
}
@@ -1000,12 +874,12 @@ static int mdfld_crtc_mode_set(struct drm_crtc *crtc,
}
/* setup pipeconf */
- *pipeconf = PIPEACONF_ENABLE; /* FIXME_JLIU7 REG_READ(pipeconf_reg); */
+ dev_priv->pipeconf[pipe] = PIPEACONF_ENABLE; /* FIXME_JLIU7 REG_READ(pipeconf_reg); */
/* Set up the display plane register */
- *dspcntr = REG_READ(dspcntr_reg);
- *dspcntr |= pipe << DISPPLANE_SEL_PIPE_POS;
- *dspcntr |= DISPLAY_PLANE_ENABLE;
+ dev_priv->dspcntr[pipe] = REG_READ(map->cntr);
+ dev_priv->dspcntr[pipe] |= pipe << DISPPLANE_SEL_PIPE_POS;
+ dev_priv->dspcntr[pipe] |= DISPLAY_PLANE_ENABLE;
if (is_mipi2)
goto mrst_crtc_mode_set_exit;
@@ -1070,21 +944,21 @@ static int mdfld_crtc_mode_set(struct drm_crtc *crtc,
clock.p1, m_conv);
}
- dpll = REG_READ(dpll_reg);
+ dpll = REG_READ(map->dpll);
if (dpll & DPLL_VCO_ENABLE) {
dpll &= ~DPLL_VCO_ENABLE;
- REG_WRITE(dpll_reg, dpll);
- REG_READ(dpll_reg);
+ REG_WRITE(map->dpll, dpll);
+ REG_READ(map->dpll);
/* FIXME jliu7 check the DPLL lock bit PIPEACONF[29] */
/* FIXME_MDFLD PO - change 500 to 1 after PO */
udelay(500);
/* reset M1, N1 & P1 */
- REG_WRITE(fp_reg, 0);
+ REG_WRITE(map->fp0, 0);
dpll &= ~MDFLD_P1_MASK;
- REG_WRITE(dpll_reg, dpll);
+ REG_WRITE(map->dpll, dpll);
/* FIXME_MDFLD PO - change 500 to 1 after PO */
udelay(500);
}
@@ -1093,7 +967,7 @@ static int mdfld_crtc_mode_set(struct drm_crtc *crtc,
* enable the VCO */
if (dpll & MDFLD_PWR_GATE_EN) {
dpll &= ~MDFLD_PWR_GATE_EN;
- REG_WRITE(dpll_reg, dpll);
+ REG_WRITE(map->dpll, dpll);
/* FIXME_MDFLD PO - change 500 to 1 after PO */
udelay(500);
}
@@ -1134,18 +1008,18 @@ static int mdfld_crtc_mode_set(struct drm_crtc *crtc,
fp = 0x000000c1;
}
- REG_WRITE(fp_reg, fp);
- REG_WRITE(dpll_reg, dpll);
+ REG_WRITE(map->fp0, fp);
+ REG_WRITE(map->dpll, dpll);
/* FIXME_MDFLD PO - change 500 to 1 after PO */
udelay(500);
dpll |= DPLL_VCO_ENABLE;
- REG_WRITE(dpll_reg, dpll);
- REG_READ(dpll_reg);
+ REG_WRITE(map->dpll, dpll);
+ REG_READ(map->dpll);
/* wait for DSI PLL to lock */
while (timeout < 20000 &&
- !(REG_READ(pipeconf_reg) & PIPECONF_DSIPLL_LOCK)) {
+ !(REG_READ(map->conf) & PIPECONF_DSIPLL_LOCK)) {
udelay(150);
timeout++;
}
@@ -1155,11 +1029,11 @@ static int mdfld_crtc_mode_set(struct drm_crtc *crtc,
dev_dbg(dev->dev, "is_mipi = 0x%x\n", is_mipi);
- REG_WRITE(pipeconf_reg, *pipeconf);
- REG_READ(pipeconf_reg);
+ REG_WRITE(map->conf, dev_priv->pipeconf[pipe]);
+ REG_READ(map->conf);
/* Wait for for the pipe enable to take effect. */
- REG_WRITE(dspcntr_reg, *dspcntr);
+ REG_WRITE(map->cntr, dev_priv->dspcntr[pipe]);
psb_intel_wait_for_vblank(dev);
mrst_crtc_mode_set_exit:
diff --git a/drivers/gpu/drm/gma500/mid_bios.c b/drivers/gpu/drm/gma500/mid_bios.c
index 5eee9ad80da4..b2a790bd9899 100644
--- a/drivers/gpu/drm/gma500/mid_bios.c
+++ b/drivers/gpu/drm/gma500/mid_bios.c
@@ -118,139 +118,214 @@ static void mid_get_pci_revID(struct drm_psb_private *dev_priv)
dev_priv->platform_rev_id);
}
+struct vbt_header {
+ u32 signature;
+ u8 revision;
+} __packed;
+
+/* The same for r0 and r1 */
+struct vbt_r0 {
+ struct vbt_header vbt_header;
+ u8 size;
+ u8 checksum;
+} __packed;
+
+struct vbt_r10 {
+ struct vbt_header vbt_header;
+ u8 checksum;
+ u16 size;
+ u8 panel_count;
+ u8 primary_panel_idx;
+ u8 secondary_panel_idx;
+ u8 __reserved[5];
+} __packed;
+
+static int read_vbt_r0(u32 addr, struct vbt_r0 *vbt)
+{
+ void __iomem *vbt_virtual;
+
+ vbt_virtual = ioremap(addr, sizeof(*vbt));
+ if (vbt_virtual == NULL)
+ return -1;
+
+ memcpy_fromio(vbt, vbt_virtual, sizeof(*vbt));
+ iounmap(vbt_virtual);
+
+ return 0;
+}
+
+static int read_vbt_r10(u32 addr, struct vbt_r10 *vbt)
+{
+ void __iomem *vbt_virtual;
+
+ vbt_virtual = ioremap(addr, sizeof(*vbt));
+ if (!vbt_virtual)
+ return -1;
+
+ memcpy_fromio(vbt, vbt_virtual, sizeof(*vbt));
+ iounmap(vbt_virtual);
+
+ return 0;
+}
+
+static int mid_get_vbt_data_r0(struct drm_psb_private *dev_priv, u32 addr)
+{
+ struct vbt_r0 vbt;
+ void __iomem *gct_virtual;
+ struct gct_r0 gct;
+ u8 bpi;
+
+ if (read_vbt_r0(addr, &vbt))
+ return -1;
+
+ gct_virtual = ioremap(addr + sizeof(vbt), vbt.size - sizeof(vbt));
+ if (!gct_virtual)
+ return -1;
+ memcpy_fromio(&gct, gct_virtual, sizeof(gct));
+ iounmap(gct_virtual);
+
+ bpi = gct.PD.BootPanelIndex;
+ dev_priv->gct_data.bpi = bpi;
+ dev_priv->gct_data.pt = gct.PD.PanelType;
+ dev_priv->gct_data.DTD = gct.panel[bpi].DTD;
+ dev_priv->gct_data.Panel_Port_Control =
+ gct.panel[bpi].Panel_Port_Control;
+ dev_priv->gct_data.Panel_MIPI_Display_Descriptor =
+ gct.panel[bpi].Panel_MIPI_Display_Descriptor;
+
+ return 0;
+}
+
+static int mid_get_vbt_data_r1(struct drm_psb_private *dev_priv, u32 addr)
+{
+ struct vbt_r0 vbt;
+ void __iomem *gct_virtual;
+ struct gct_r1 gct;
+ u8 bpi;
+
+ if (read_vbt_r0(addr, &vbt))
+ return -1;
+
+ gct_virtual = ioremap(addr + sizeof(vbt), vbt.size - sizeof(vbt));
+ if (!gct_virtual)
+ return -1;
+ memcpy_fromio(&gct, gct_virtual, sizeof(gct));
+ iounmap(gct_virtual);
+
+ bpi = gct.PD.BootPanelIndex;
+ dev_priv->gct_data.bpi = bpi;
+ dev_priv->gct_data.pt = gct.PD.PanelType;
+ dev_priv->gct_data.DTD = gct.panel[bpi].DTD;
+ dev_priv->gct_data.Panel_Port_Control =
+ gct.panel[bpi].Panel_Port_Control;
+ dev_priv->gct_data.Panel_MIPI_Display_Descriptor =
+ gct.panel[bpi].Panel_MIPI_Display_Descriptor;
+
+ return 0;
+}
+
+static int mid_get_vbt_data_r10(struct drm_psb_private *dev_priv, u32 addr)
+{
+ struct vbt_r10 vbt;
+ void __iomem *gct_virtual;
+ struct gct_r10 *gct;
+ struct oaktrail_timing_info *dp_ti = &dev_priv->gct_data.DTD;
+ struct gct_r10_timing_info *ti;
+ int ret = -1;
+
+ if (read_vbt_r10(addr, &vbt))
+ return -1;
+
+ gct = kmalloc(sizeof(*gct) * vbt.panel_count, GFP_KERNEL);
+ if (!gct)
+ return -1;
+
+ gct_virtual = ioremap(addr + sizeof(vbt),
+ sizeof(*gct) * vbt.panel_count);
+ if (!gct_virtual)
+ goto out;
+ memcpy_fromio(gct, gct_virtual, sizeof(*gct));
+ iounmap(gct_virtual);
+
+ dev_priv->gct_data.bpi = vbt.primary_panel_idx;
+ dev_priv->gct_data.Panel_MIPI_Display_Descriptor =
+ gct[vbt.primary_panel_idx].Panel_MIPI_Display_Descriptor;
+
+ ti = &gct[vbt.primary_panel_idx].DTD;
+ dp_ti->pixel_clock = ti->pixel_clock;
+ dp_ti->hactive_hi = ti->hactive_hi;
+ dp_ti->hactive_lo = ti->hactive_lo;
+ dp_ti->hblank_hi = ti->hblank_hi;
+ dp_ti->hblank_lo = ti->hblank_lo;
+ dp_ti->hsync_offset_hi = ti->hsync_offset_hi;
+ dp_ti->hsync_offset_lo = ti->hsync_offset_lo;
+ dp_ti->hsync_pulse_width_hi = ti->hsync_pulse_width_hi;
+ dp_ti->hsync_pulse_width_lo = ti->hsync_pulse_width_lo;
+ dp_ti->vactive_hi = ti->vactive_hi;
+ dp_ti->vactive_lo = ti->vactive_lo;
+ dp_ti->vblank_hi = ti->vblank_hi;
+ dp_ti->vblank_lo = ti->vblank_lo;
+ dp_ti->vsync_offset_hi = ti->vsync_offset_hi;
+ dp_ti->vsync_offset_lo = ti->vsync_offset_lo;
+ dp_ti->vsync_pulse_width_hi = ti->vsync_pulse_width_hi;
+ dp_ti->vsync_pulse_width_lo = ti->vsync_pulse_width_lo;
+
+ ret = 0;
+out:
+ kfree(gct);
+ return ret;
+}
+
static void mid_get_vbt_data(struct drm_psb_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
- struct oaktrail_vbt *vbt = &dev_priv->vbt_data;
u32 addr;
- u16 new_size;
- u8 *vbt_virtual;
- u8 bpi;
- u8 number_desc = 0;
- struct oaktrail_timing_info *dp_ti = &dev_priv->gct_data.DTD;
- struct gct_r10_timing_info ti;
- void *pGCT;
+ u8 __iomem *vbt_virtual;
+ struct vbt_header vbt_header;
struct pci_dev *pci_gfx_root = pci_get_bus_and_slot(0, PCI_DEVFN(2, 0));
+ int ret = -1;
- /* Get the address of the platform config vbt, B0:D2:F0;0xFC */
+ /* Get the address of the platform config vbt */
pci_read_config_dword(pci_gfx_root, 0xFC, &addr);
pci_dev_put(pci_gfx_root);
dev_dbg(dev->dev, "drm platform config address is %x\n", addr);
- /* check for platform config address == 0. */
- /* this means fw doesn't support vbt */
-
- if (addr == 0) {
- vbt->size = 0;
- return;
- }
+ if (!addr)
+ goto out;
/* get the virtual address of the vbt */
- vbt_virtual = ioremap(addr, sizeof(*vbt));
- if (vbt_virtual == NULL) {
- vbt->size = 0;
- return;
- }
+ vbt_virtual = ioremap(addr, sizeof(vbt_header));
+ if (!vbt_virtual)
+ goto out;
- memcpy(vbt, vbt_virtual, sizeof(*vbt));
- iounmap(vbt_virtual); /* Free virtual address space */
+ memcpy_fromio(&vbt_header, vbt_virtual, sizeof(vbt_header));
+ iounmap(vbt_virtual);
- /* No matching signature don't process the data */
- if (memcmp(vbt->signature, "$GCT", 4)) {
- vbt->size = 0;
- return;
- }
+ if (memcmp(&vbt_header.signature, "$GCT", 4))
+ goto out;
+
+ dev_dbg(dev->dev, "GCT revision is %02x\n", vbt_header.revision);
- dev_dbg(dev->dev, "GCT revision is %x\n", vbt->revision);
-
- switch (vbt->revision) {
- case 0:
- vbt->oaktrail_gct = ioremap(addr + sizeof(*vbt) - 4,
- vbt->size - sizeof(*vbt) + 4);
- pGCT = vbt->oaktrail_gct;
- bpi = ((struct oaktrail_gct_v1 *)pGCT)->PD.BootPanelIndex;
- dev_priv->gct_data.bpi = bpi;
- dev_priv->gct_data.pt =
- ((struct oaktrail_gct_v1 *)pGCT)->PD.PanelType;
- memcpy(&dev_priv->gct_data.DTD,
- &((struct oaktrail_gct_v1 *)pGCT)->panel[bpi].DTD,
- sizeof(struct oaktrail_timing_info));
- dev_priv->gct_data.Panel_Port_Control =
- ((struct oaktrail_gct_v1 *)pGCT)->panel[bpi].Panel_Port_Control;
- dev_priv->gct_data.Panel_MIPI_Display_Descriptor =
- ((struct oaktrail_gct_v1 *)pGCT)->panel[bpi].Panel_MIPI_Display_Descriptor;
+ switch (vbt_header.revision) {
+ case 0x00:
+ ret = mid_get_vbt_data_r0(dev_priv, addr);
break;
- case 1:
- vbt->oaktrail_gct = ioremap(addr + sizeof(*vbt) - 4,
- vbt->size - sizeof(*vbt) + 4);
- pGCT = vbt->oaktrail_gct;
- bpi = ((struct oaktrail_gct_v2 *)pGCT)->PD.BootPanelIndex;
- dev_priv->gct_data.bpi = bpi;
- dev_priv->gct_data.pt =
- ((struct oaktrail_gct_v2 *)pGCT)->PD.PanelType;
- memcpy(&dev_priv->gct_data.DTD,
- &((struct oaktrail_gct_v2 *)pGCT)->panel[bpi].DTD,
- sizeof(struct oaktrail_timing_info));
- dev_priv->gct_data.Panel_Port_Control =
- ((struct oaktrail_gct_v2 *)pGCT)->panel[bpi].Panel_Port_Control;
- dev_priv->gct_data.Panel_MIPI_Display_Descriptor =
- ((struct oaktrail_gct_v2 *)pGCT)->panel[bpi].Panel_MIPI_Display_Descriptor;
+ case 0x01:
+ ret = mid_get_vbt_data_r1(dev_priv, addr);
break;
case 0x10:
- /*header definition changed from rev 01 (v2) to rev 10h. */
- /*so, some values have changed location*/
- new_size = vbt->checksum; /*checksum contains lo size byte*/
- /*LSB of oaktrail_gct contains hi size byte*/
- new_size |= ((0xff & (unsigned int)(long)vbt->oaktrail_gct)) << 8;
-
- vbt->checksum = vbt->size; /*size contains the checksum*/
- if (new_size > 0xff)
- vbt->size = 0xff; /*restrict size to 255*/
- else
- vbt->size = new_size;
-
- /* number of descriptors defined in the GCT */
- number_desc = ((0xff00 & (unsigned int)(long)vbt->oaktrail_gct)) >> 8;
- bpi = ((0xff0000 & (unsigned int)(long)vbt->oaktrail_gct)) >> 16;
- vbt->oaktrail_gct = ioremap(addr + GCT_R10_HEADER_SIZE,
- GCT_R10_DISPLAY_DESC_SIZE * number_desc);
- pGCT = vbt->oaktrail_gct;
- pGCT = (u8 *)pGCT + (bpi*GCT_R10_DISPLAY_DESC_SIZE);
- dev_priv->gct_data.bpi = bpi; /*save boot panel id*/
-
- /*copy the GCT display timings into a temp structure*/
- memcpy(&ti, pGCT, sizeof(struct gct_r10_timing_info));
-
- /*now copy the temp struct into the dev_priv->gct_data*/
- dp_ti->pixel_clock = ti.pixel_clock;
- dp_ti->hactive_hi = ti.hactive_hi;
- dp_ti->hactive_lo = ti.hactive_lo;
- dp_ti->hblank_hi = ti.hblank_hi;
- dp_ti->hblank_lo = ti.hblank_lo;
- dp_ti->hsync_offset_hi = ti.hsync_offset_hi;
- dp_ti->hsync_offset_lo = ti.hsync_offset_lo;
- dp_ti->hsync_pulse_width_hi = ti.hsync_pulse_width_hi;
- dp_ti->hsync_pulse_width_lo = ti.hsync_pulse_width_lo;
- dp_ti->vactive_hi = ti.vactive_hi;
- dp_ti->vactive_lo = ti.vactive_lo;
- dp_ti->vblank_hi = ti.vblank_hi;
- dp_ti->vblank_lo = ti.vblank_lo;
- dp_ti->vsync_offset_hi = ti.vsync_offset_hi;
- dp_ti->vsync_offset_lo = ti.vsync_offset_lo;
- dp_ti->vsync_pulse_width_hi = ti.vsync_pulse_width_hi;
- dp_ti->vsync_pulse_width_lo = ti.vsync_pulse_width_lo;
-
- /* Move the MIPI_Display_Descriptor data from GCT to dev priv */
- dev_priv->gct_data.Panel_MIPI_Display_Descriptor =
- *((u8 *)pGCT + 0x0d);
- dev_priv->gct_data.Panel_MIPI_Display_Descriptor |=
- (*((u8 *)pGCT + 0x0e)) << 8;
+ ret = mid_get_vbt_data_r10(dev_priv, addr);
break;
default:
dev_err(dev->dev, "Unknown revision of GCT!\n");
- vbt->size = 0;
}
+
+out:
+ if (ret)
+ dev_err(dev->dev, "Unable to read GCT!");
+ else
+ dev_priv->has_gct = true;
}
int mid_chip_setup(struct drm_device *dev)
diff --git a/drivers/gpu/drm/gma500/oaktrail.h b/drivers/gpu/drm/gma500/oaktrail.h
index 2da1f368f14e..f2f9f38a5362 100644
--- a/drivers/gpu/drm/gma500/oaktrail.h
+++ b/drivers/gpu/drm/gma500/oaktrail.h
@@ -19,14 +19,6 @@
/* MID device specific descriptors */
-struct oaktrail_vbt {
- s8 signature[4]; /*4 bytes,"$GCT" */
- u8 revision;
- u8 size;
- u8 checksum;
- void *oaktrail_gct;
-} __packed;
-
struct oaktrail_timing_info {
u16 pixel_clock;
u8 hactive_lo;
@@ -161,7 +153,7 @@ union oaktrail_panel_rx {
u16 panel_receiver;
} __packed;
-struct oaktrail_gct_v1 {
+struct gct_r0 {
union { /*8 bits,Defined as follows: */
struct {
u8 PanelType:4; /*4 bits, Bit field for panels*/
@@ -178,7 +170,7 @@ struct oaktrail_gct_v1 {
union oaktrail_panel_rx panelrx[4]; /* panel receivers*/
} __packed;
-struct oaktrail_gct_v2 {
+struct gct_r1 {
union { /*8 bits,Defined as follows: */
struct {
u8 PanelType:4; /*4 bits, Bit field for panels*/
@@ -195,6 +187,16 @@ struct oaktrail_gct_v2 {
union oaktrail_panel_rx panelrx[4]; /* panel receivers*/
} __packed;
+struct gct_r10 {
+ struct gct_r10_timing_info DTD;
+ u16 Panel_MIPI_Display_Descriptor;
+ u16 Panel_MIPI_Receiver_Descriptor;
+ u16 Panel_Backlight_Inverter_Descriptor;
+ u8 Panel_Initial_Brightness;
+ u32 MIPI_Ctlr_Init_ptr;
+ u32 MIPI_Panel_Init_ptr;
+} __packed;
+
struct oaktrail_gct_data {
u8 bpi; /* boot panel index, number of panel used during boot */
u8 pt; /* panel type, 4 bit field, 0=lvds, 1=mipi */
@@ -213,9 +215,6 @@ struct oaktrail_gct_data {
#define MODE_SETTING_IN_DSR 0x4
#define MODE_SETTING_ENCODER_DONE 0x8
-#define GCT_R10_HEADER_SIZE 16
-#define GCT_R10_DISPLAY_DESC_SIZE 28
-
/*
* Moorestown HDMI interfaces
*/
diff --git a/drivers/gpu/drm/gma500/oaktrail_crtc.c b/drivers/gpu/drm/gma500/oaktrail_crtc.c
index a39b0d0d680f..f821c835ca90 100644
--- a/drivers/gpu/drm/gma500/oaktrail_crtc.c
+++ b/drivers/gpu/drm/gma500/oaktrail_crtc.c
@@ -162,12 +162,10 @@ mrstFindBestPLL(struct drm_crtc *crtc, int target, int refclk,
static void oaktrail_crtc_dpms(struct drm_crtc *crtc, int mode)
{
struct drm_device *dev = crtc->dev;
+ struct drm_psb_private *dev_priv = dev->dev_private;
struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
int pipe = psb_intel_crtc->pipe;
- int dpll_reg = (pipe == 0) ? MRST_DPLL_A : DPLL_B;
- int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
- int dspbase_reg = (pipe == 0) ? MRST_DSPABASE : DSPBBASE;
- int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
+ const struct psb_offset *map = &dev_priv->regmap[pipe];
u32 temp;
if (!gma_power_begin(dev, true))
@@ -181,32 +179,32 @@ static void oaktrail_crtc_dpms(struct drm_crtc *crtc, int mode)
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
/* Enable the DPLL */
- temp = REG_READ(dpll_reg);
+ temp = REG_READ(map->dpll);
if ((temp & DPLL_VCO_ENABLE) == 0) {
- REG_WRITE(dpll_reg, temp);
- REG_READ(dpll_reg);
+ REG_WRITE(map->dpll, temp);
+ REG_READ(map->dpll);
/* Wait for the clocks to stabilize. */
udelay(150);
- REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
- REG_READ(dpll_reg);
+ REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE);
+ REG_READ(map->dpll);
/* Wait for the clocks to stabilize. */
udelay(150);
- REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
- REG_READ(dpll_reg);
+ REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE);
+ REG_READ(map->dpll);
/* Wait for the clocks to stabilize. */
udelay(150);
}
/* Enable the pipe */
- temp = REG_READ(pipeconf_reg);
+ temp = REG_READ(map->conf);
if ((temp & PIPEACONF_ENABLE) == 0)
- REG_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE);
+ REG_WRITE(map->conf, temp | PIPEACONF_ENABLE);
/* Enable the plane */
- temp = REG_READ(dspcntr_reg);
+ temp = REG_READ(map->cntr);
if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
- REG_WRITE(dspcntr_reg,
+ REG_WRITE(map->cntr,
temp | DISPLAY_PLANE_ENABLE);
/* Flush the plane changes */
- REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
+ REG_WRITE(map->base, REG_READ(map->base));
}
psb_intel_crtc_load_lut(crtc);
@@ -223,28 +221,28 @@ static void oaktrail_crtc_dpms(struct drm_crtc *crtc, int mode)
/* Disable the VGA plane that we never use */
REG_WRITE(VGACNTRL, VGA_DISP_DISABLE);
/* Disable display plane */
- temp = REG_READ(dspcntr_reg);
+ temp = REG_READ(map->cntr);
if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
- REG_WRITE(dspcntr_reg,
+ REG_WRITE(map->cntr,
temp & ~DISPLAY_PLANE_ENABLE);
/* Flush the plane changes */
- REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
- REG_READ(dspbase_reg);
+ REG_WRITE(map->base, REG_READ(map->base));
+ REG_READ(map->base);
}
/* Next, disable display pipes */
- temp = REG_READ(pipeconf_reg);
+ temp = REG_READ(map->conf);
if ((temp & PIPEACONF_ENABLE) != 0) {
- REG_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
- REG_READ(pipeconf_reg);
+ REG_WRITE(map->conf, temp & ~PIPEACONF_ENABLE);
+ REG_READ(map->conf);
}
/* Wait for for the pipe disable to take effect. */
psb_intel_wait_for_vblank(dev);
- temp = REG_READ(dpll_reg);
+ temp = REG_READ(map->dpll);
if ((temp & DPLL_VCO_ENABLE) != 0) {
- REG_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE);
- REG_READ(dpll_reg);
+ REG_WRITE(map->dpll, temp & ~DPLL_VCO_ENABLE);
+ REG_READ(map->dpll);
}
/* Wait for the clocks to turn off. */
@@ -292,17 +290,7 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
struct drm_psb_private *dev_priv = dev->dev_private;
int pipe = psb_intel_crtc->pipe;
- int fp_reg = (pipe == 0) ? MRST_FPA0 : FPB0;
- int dpll_reg = (pipe == 0) ? MRST_DPLL_A : DPLL_B;
- int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
- int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
- int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
- int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
- int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
- int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
- int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
- int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
- int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
+ const struct psb_offset *map = &dev_priv->regmap[pipe];
int refclk = 0;
struct oaktrail_clock_t clock;
u32 dpll = 0, fp = 0, dspcntr, pipeconf;
@@ -350,7 +338,7 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
if (oaktrail_panel_fitter_pipe(dev) == pipe)
REG_WRITE(PFIT_CONTROL, 0);
- REG_WRITE(pipesrc_reg,
+ REG_WRITE(map->src,
((mode->crtc_hdisplay - 1) << 16) |
(mode->crtc_vdisplay - 1));
@@ -369,34 +357,34 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
offsetY = (adjusted_mode->crtc_vdisplay -
mode->crtc_vdisplay) / 2;
- REG_WRITE(htot_reg, (mode->crtc_hdisplay - 1) |
+ REG_WRITE(map->htotal, (mode->crtc_hdisplay - 1) |
((adjusted_mode->crtc_htotal - 1) << 16));
- REG_WRITE(vtot_reg, (mode->crtc_vdisplay - 1) |
+ REG_WRITE(map->vtotal, (mode->crtc_vdisplay - 1) |
((adjusted_mode->crtc_vtotal - 1) << 16));
- REG_WRITE(hblank_reg,
+ REG_WRITE(map->hblank,
(adjusted_mode->crtc_hblank_start - offsetX - 1) |
((adjusted_mode->crtc_hblank_end - offsetX - 1) << 16));
- REG_WRITE(hsync_reg,
+ REG_WRITE(map->hsync,
(adjusted_mode->crtc_hsync_start - offsetX - 1) |
((adjusted_mode->crtc_hsync_end - offsetX - 1) << 16));
- REG_WRITE(vblank_reg,
+ REG_WRITE(map->vblank,
(adjusted_mode->crtc_vblank_start - offsetY - 1) |
((adjusted_mode->crtc_vblank_end - offsetY - 1) << 16));
- REG_WRITE(vsync_reg,
+ REG_WRITE(map->vsync,
(adjusted_mode->crtc_vsync_start - offsetY - 1) |
((adjusted_mode->crtc_vsync_end - offsetY - 1) << 16));
} else {
- REG_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
+ REG_WRITE(map->htotal, (adjusted_mode->crtc_hdisplay - 1) |
((adjusted_mode->crtc_htotal - 1) << 16));
- REG_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) |
+ REG_WRITE(map->vtotal, (adjusted_mode->crtc_vdisplay - 1) |
((adjusted_mode->crtc_vtotal - 1) << 16));
- REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) |
+ REG_WRITE(map->hblank, (adjusted_mode->crtc_hblank_start - 1) |
((adjusted_mode->crtc_hblank_end - 1) << 16));
- REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) |
+ REG_WRITE(map->hsync, (adjusted_mode->crtc_hsync_start - 1) |
((adjusted_mode->crtc_hsync_end - 1) << 16));
- REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) |
+ REG_WRITE(map->vblank, (adjusted_mode->crtc_vblank_start - 1) |
((adjusted_mode->crtc_vblank_end - 1) << 16));
- REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) |
+ REG_WRITE(map->vsync, (adjusted_mode->crtc_vsync_start - 1) |
((adjusted_mode->crtc_vsync_end - 1) << 16));
}
@@ -408,10 +396,10 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
}
/* setup pipeconf */
- pipeconf = REG_READ(pipeconf_reg);
+ pipeconf = REG_READ(map->conf);
/* Set up the display plane register */
- dspcntr = REG_READ(dspcntr_reg);
+ dspcntr = REG_READ(map->cntr);
dspcntr |= DISPPLANE_GAMMA_ENABLE;
if (pipe == 0)
@@ -467,30 +455,30 @@ static int oaktrail_crtc_mode_set(struct drm_crtc *crtc,
mrstPrintPll("chosen", &clock);
if (dpll & DPLL_VCO_ENABLE) {
- REG_WRITE(fp_reg, fp);
- REG_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE);
- REG_READ(dpll_reg);
+ REG_WRITE(map->fp0, fp);
+ REG_WRITE(map->dpll, dpll & ~DPLL_VCO_ENABLE);
+ REG_READ(map->dpll);
/* Check the DPLLA lock bit PIPEACONF[29] */
udelay(150);
}
- REG_WRITE(fp_reg, fp);
- REG_WRITE(dpll_reg, dpll);
- REG_READ(dpll_reg);
+ REG_WRITE(map->fp0, fp);
+ REG_WRITE(map->dpll, dpll);
+ REG_READ(map->dpll);
/* Wait for the clocks to stabilize. */
udelay(150);
/* write it again -- the BIOS does, after all */
- REG_WRITE(dpll_reg, dpll);
- REG_READ(dpll_reg);
+ REG_WRITE(map->dpll, dpll);
+ REG_READ(map->dpll);
/* Wait for the clocks to stabilize. */
udelay(150);
- REG_WRITE(pipeconf_reg, pipeconf);
- REG_READ(pipeconf_reg);
+ REG_WRITE(map->conf, pipeconf);
+ REG_READ(map->conf);
psb_intel_wait_for_vblank(dev);
- REG_WRITE(dspcntr_reg, dspcntr);
+ REG_WRITE(map->cntr, dspcntr);
psb_intel_wait_for_vblank(dev);
oaktrail_crtc_mode_set_exit:
@@ -509,15 +497,13 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc,
int x, int y, struct drm_framebuffer *old_fb)
{
struct drm_device *dev = crtc->dev;
+ struct drm_psb_private *dev_priv = dev->dev_private;
struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
int pipe = psb_intel_crtc->pipe;
+ const struct psb_offset *map = &dev_priv->regmap[pipe];
unsigned long start, offset;
- int dspbase = (pipe == 0 ? DSPALINOFF : DSPBBASE);
- int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF);
- int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE;
- int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
u32 dspcntr;
int ret = 0;
@@ -533,9 +519,9 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc,
start = psbfb->gtt->offset;
offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8);
- REG_WRITE(dspstride, crtc->fb->pitches[0]);
+ REG_WRITE(map->stride, crtc->fb->pitches[0]);
- dspcntr = REG_READ(dspcntr_reg);
+ dspcntr = REG_READ(map->cntr);
dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
switch (crtc->fb->bits_per_pixel) {
@@ -557,12 +543,12 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc,
ret = -EINVAL;
goto pipe_set_base_exit;
}
- REG_WRITE(dspcntr_reg, dspcntr);
+ REG_WRITE(map->cntr, dspcntr);
- REG_WRITE(dspbase, offset);
- REG_READ(dspbase);
- REG_WRITE(dspsurf, start);
- REG_READ(dspsurf);
+ REG_WRITE(map->base, offset);
+ REG_READ(map->base);
+ REG_WRITE(map->surf, start);
+ REG_READ(map->surf);
pipe_set_base_exit:
gma_power_end(dev);
diff --git a/drivers/gpu/drm/gma500/oaktrail_device.c b/drivers/gpu/drm/gma500/oaktrail_device.c
index 41d1924ea31e..0f9b7db80f6b 100644
--- a/drivers/gpu/drm/gma500/oaktrail_device.c
+++ b/drivers/gpu/drm/gma500/oaktrail_device.c
@@ -187,6 +187,7 @@ static int oaktrail_save_display_registers(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
struct psb_save_area *regs = &dev_priv->regs;
+ struct psb_pipe *p = &regs->pipe[0];
int i;
u32 pp_stat;
@@ -201,24 +202,24 @@ static int oaktrail_save_display_registers(struct drm_device *dev)
regs->psb.saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT);
/* Pipe & plane A info */
- regs->psb.savePIPEACONF = PSB_RVDC32(PIPEACONF);
- regs->psb.savePIPEASRC = PSB_RVDC32(PIPEASRC);
- regs->psb.saveFPA0 = PSB_RVDC32(MRST_FPA0);
- regs->psb.saveFPA1 = PSB_RVDC32(MRST_FPA1);
- regs->psb.saveDPLL_A = PSB_RVDC32(MRST_DPLL_A);
- regs->psb.saveHTOTAL_A = PSB_RVDC32(HTOTAL_A);
- regs->psb.saveHBLANK_A = PSB_RVDC32(HBLANK_A);
- regs->psb.saveHSYNC_A = PSB_RVDC32(HSYNC_A);
- regs->psb.saveVTOTAL_A = PSB_RVDC32(VTOTAL_A);
- regs->psb.saveVBLANK_A = PSB_RVDC32(VBLANK_A);
- regs->psb.saveVSYNC_A = PSB_RVDC32(VSYNC_A);
+ p->conf = PSB_RVDC32(PIPEACONF);
+ p->src = PSB_RVDC32(PIPEASRC);
+ p->fp0 = PSB_RVDC32(MRST_FPA0);
+ p->fp1 = PSB_RVDC32(MRST_FPA1);
+ p->dpll = PSB_RVDC32(MRST_DPLL_A);
+ p->htotal = PSB_RVDC32(HTOTAL_A);
+ p->hblank = PSB_RVDC32(HBLANK_A);
+ p->hsync = PSB_RVDC32(HSYNC_A);
+ p->vtotal = PSB_RVDC32(VTOTAL_A);
+ p->vblank = PSB_RVDC32(VBLANK_A);
+ p->vsync = PSB_RVDC32(VSYNC_A);
regs->psb.saveBCLRPAT_A = PSB_RVDC32(BCLRPAT_A);
- regs->psb.saveDSPACNTR = PSB_RVDC32(DSPACNTR);
- regs->psb.saveDSPASTRIDE = PSB_RVDC32(DSPASTRIDE);
- regs->psb.saveDSPAADDR = PSB_RVDC32(DSPABASE);
- regs->psb.saveDSPASURF = PSB_RVDC32(DSPASURF);
- regs->psb.saveDSPALINOFF = PSB_RVDC32(DSPALINOFF);
- regs->psb.saveDSPATILEOFF = PSB_RVDC32(DSPATILEOFF);
+ p->cntr = PSB_RVDC32(DSPACNTR);
+ p->stride = PSB_RVDC32(DSPASTRIDE);
+ p->addr = PSB_RVDC32(DSPABASE);
+ p->surf = PSB_RVDC32(DSPASURF);
+ p->linoff = PSB_RVDC32(DSPALINOFF);
+ p->tileoff = PSB_RVDC32(DSPATILEOFF);
/* Save cursor regs */
regs->psb.saveDSPACURSOR_CTRL = PSB_RVDC32(CURACNTR);
@@ -227,7 +228,7 @@ static int oaktrail_save_display_registers(struct drm_device *dev)
/* Save palette (gamma) */
for (i = 0; i < 256; i++)
- regs->psb.save_palette_a[i] = PSB_RVDC32(PALETTE_A + (i << 2));
+ p->palette[i] = PSB_RVDC32(PALETTE_A + (i << 2));
if (dev_priv->hdmi_priv)
oaktrail_hdmi_save(dev);
@@ -300,6 +301,7 @@ static int oaktrail_restore_display_registers(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
struct psb_save_area *regs = &dev_priv->regs;
+ struct psb_pipe *p = &regs->pipe[0];
u32 pp_stat;
int i;
@@ -317,21 +319,21 @@ static int oaktrail_restore_display_registers(struct drm_device *dev)
PSB_WVDC32(0x80000000, VGACNTRL);
/* set the plls */
- PSB_WVDC32(regs->psb.saveFPA0, MRST_FPA0);
- PSB_WVDC32(regs->psb.saveFPA1, MRST_FPA1);
+ PSB_WVDC32(p->fp0, MRST_FPA0);
+ PSB_WVDC32(p->fp1, MRST_FPA1);
/* Actually enable it */
- PSB_WVDC32(regs->psb.saveDPLL_A, MRST_DPLL_A);
+ PSB_WVDC32(p->dpll, MRST_DPLL_A);
DRM_UDELAY(150);
/* Restore mode */
- PSB_WVDC32(regs->psb.saveHTOTAL_A, HTOTAL_A);
- PSB_WVDC32(regs->psb.saveHBLANK_A, HBLANK_A);
- PSB_WVDC32(regs->psb.saveHSYNC_A, HSYNC_A);
- PSB_WVDC32(regs->psb.saveVTOTAL_A, VTOTAL_A);
- PSB_WVDC32(regs->psb.saveVBLANK_A, VBLANK_A);
- PSB_WVDC32(regs->psb.saveVSYNC_A, VSYNC_A);
- PSB_WVDC32(regs->psb.savePIPEASRC, PIPEASRC);
+ PSB_WVDC32(p->htotal, HTOTAL_A);
+ PSB_WVDC32(p->hblank, HBLANK_A);
+ PSB_WVDC32(p->hsync, HSYNC_A);
+ PSB_WVDC32(p->vtotal, VTOTAL_A);
+ PSB_WVDC32(p->vblank, VBLANK_A);
+ PSB_WVDC32(p->vsync, VSYNC_A);
+ PSB_WVDC32(p->src, PIPEASRC);
PSB_WVDC32(regs->psb.saveBCLRPAT_A, BCLRPAT_A);
/* Restore performance mode*/
@@ -339,16 +341,16 @@ static int oaktrail_restore_display_registers(struct drm_device *dev)
/* Enable the pipe*/
if (dev_priv->iLVDS_enable)
- PSB_WVDC32(regs->psb.savePIPEACONF, PIPEACONF);
+ PSB_WVDC32(p->conf, PIPEACONF);
/* Set up the plane*/
- PSB_WVDC32(regs->psb.saveDSPALINOFF, DSPALINOFF);
- PSB_WVDC32(regs->psb.saveDSPASTRIDE, DSPASTRIDE);
- PSB_WVDC32(regs->psb.saveDSPATILEOFF, DSPATILEOFF);
+ PSB_WVDC32(p->linoff, DSPALINOFF);
+ PSB_WVDC32(p->stride, DSPASTRIDE);
+ PSB_WVDC32(p->tileoff, DSPATILEOFF);
/* Enable the plane */
- PSB_WVDC32(regs->psb.saveDSPACNTR, DSPACNTR);
- PSB_WVDC32(regs->psb.saveDSPASURF, DSPASURF);
+ PSB_WVDC32(p->cntr, DSPACNTR);
+ PSB_WVDC32(p->surf, DSPASURF);
/* Enable Cursor A */
PSB_WVDC32(regs->psb.saveDSPACURSOR_CTRL, CURACNTR);
@@ -357,7 +359,7 @@ static int oaktrail_restore_display_registers(struct drm_device *dev)
/* Restore palette (gamma) */
for (i = 0; i < 256; i++)
- PSB_WVDC32(regs->psb.save_palette_a[i], PALETTE_A + (i << 2));
+ PSB_WVDC32(p->palette[i], PALETTE_A + (i << 2));
if (dev_priv->hdmi_priv)
oaktrail_hdmi_restore(dev);
@@ -454,31 +456,84 @@ static int oaktrail_power_up(struct drm_device *dev)
return 0;
}
+/* Oaktrail */
+static const struct psb_offset oaktrail_regmap[2] = {
+ {
+ .fp0 = MRST_FPA0,
+ .fp1 = MRST_FPA1,
+ .cntr = DSPACNTR,
+ .conf = PIPEACONF,
+ .src = PIPEASRC,
+ .dpll = MRST_DPLL_A,
+ .htotal = HTOTAL_A,
+ .hblank = HBLANK_A,
+ .hsync = HSYNC_A,
+ .vtotal = VTOTAL_A,
+ .vblank = VBLANK_A,
+ .vsync = VSYNC_A,
+ .stride = DSPASTRIDE,
+ .size = DSPASIZE,
+ .pos = DSPAPOS,
+ .surf = DSPASURF,
+ .addr = MRST_DSPABASE,
+ .status = PIPEASTAT,
+ .linoff = DSPALINOFF,
+ .tileoff = DSPATILEOFF,
+ .palette = PALETTE_A,
+ },
+ {
+ .fp0 = FPB0,
+ .fp1 = FPB1,
+ .cntr = DSPBCNTR,
+ .conf = PIPEBCONF,
+ .src = PIPEBSRC,
+ .dpll = DPLL_B,
+ .htotal = HTOTAL_B,
+ .hblank = HBLANK_B,
+ .hsync = HSYNC_B,
+ .vtotal = VTOTAL_B,
+ .vblank = VBLANK_B,
+ .vsync = VSYNC_B,
+ .stride = DSPBSTRIDE,
+ .size = DSPBSIZE,
+ .pos = DSPBPOS,
+ .surf = DSPBSURF,
+ .addr = DSPBBASE,
+ .status = PIPEBSTAT,
+ .linoff = DSPBLINOFF,
+ .tileoff = DSPBTILEOFF,
+ .palette = PALETTE_B,
+ },
+};
static int oaktrail_chip_setup(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
- struct oaktrail_vbt *vbt = &dev_priv->vbt_data;
int ret;
+ if (pci_enable_msi(dev->pdev))
+ dev_warn(dev->dev, "Enabling MSI failed!\n");
+
+ dev_priv->regmap = oaktrail_regmap;
+
ret = mid_chip_setup(dev);
if (ret < 0)
return ret;
- if (vbt->size == 0) {
+ if (!dev_priv->has_gct) {
/* Now pull the BIOS data */
- gma_intel_opregion_init(dev);
+ psb_intel_opregion_init(dev);
psb_intel_init_bios(dev);
}
+ oaktrail_hdmi_setup(dev);
return 0;
}
static void oaktrail_teardown(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
- struct oaktrail_vbt *vbt = &dev_priv->vbt_data;
oaktrail_hdmi_teardown(dev);
- if (vbt->size == 0)
+ if (!dev_priv->has_gct)
psb_intel_destroy_bios(dev);
}
@@ -487,6 +542,9 @@ const struct psb_ops oaktrail_chip_ops = {
.accel_2d = 1,
.pipes = 2,
.crtcs = 2,
+ .hdmi_mask = (1 << 0),
+ .lvds_mask = (1 << 0),
+ .cursor_needs_phys = 0,
.sgx_offset = MRST_SGX_OFFSET,
.chip_setup = oaktrail_chip_setup,
diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi.c b/drivers/gpu/drm/gma500/oaktrail_hdmi.c
index f8b367b45f66..c10899c953b9 100644
--- a/drivers/gpu/drm/gma500/oaktrail_hdmi.c
+++ b/drivers/gpu/drm/gma500/oaktrail_hdmi.c
@@ -179,7 +179,6 @@ static void oaktrail_hdmi_dpms(struct drm_encoder *encoder, int mode)
static int oaktrail_hdmi_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
- struct drm_psb_private *dev_priv = connector->dev->dev_private;
if (mode->clock > 165000)
return MODE_CLOCK_HIGH;
if (mode->clock < 20000)
@@ -188,11 +187,6 @@ static int oaktrail_hdmi_mode_valid(struct drm_connector *connector,
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
return MODE_NO_DBLESCAN;
- /* We assume worst case scenario of 32 bpp here, since we don't know */
- if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) >
- dev_priv->vram_stolen_size)
- return MODE_MEM;
-
return MODE_OK;
}
@@ -440,6 +434,7 @@ void oaktrail_hdmi_save(struct drm_device *dev)
struct drm_psb_private *dev_priv = dev->dev_private;
struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv;
struct psb_state *regs = &dev_priv->regs.psb;
+ struct psb_pipe *pipeb = &dev_priv->regs.pipe[1];
int i;
/* dpll */
@@ -450,14 +445,14 @@ void oaktrail_hdmi_save(struct drm_device *dev)
hdmi_dev->saveDPLL_CLK_ENABLE = PSB_RVDC32(DPLL_CLK_ENABLE);
/* pipe B */
- regs->savePIPEBCONF = PSB_RVDC32(PIPEBCONF);
- regs->savePIPEBSRC = PSB_RVDC32(PIPEBSRC);
- regs->saveHTOTAL_B = PSB_RVDC32(HTOTAL_B);
- regs->saveHBLANK_B = PSB_RVDC32(HBLANK_B);
- regs->saveHSYNC_B = PSB_RVDC32(HSYNC_B);
- regs->saveVTOTAL_B = PSB_RVDC32(VTOTAL_B);
- regs->saveVBLANK_B = PSB_RVDC32(VBLANK_B);
- regs->saveVSYNC_B = PSB_RVDC32(VSYNC_B);
+ pipeb->conf = PSB_RVDC32(PIPEBCONF);
+ pipeb->src = PSB_RVDC32(PIPEBSRC);
+ pipeb->htotal = PSB_RVDC32(HTOTAL_B);
+ pipeb->hblank = PSB_RVDC32(HBLANK_B);
+ pipeb->hsync = PSB_RVDC32(HSYNC_B);
+ pipeb->vtotal = PSB_RVDC32(VTOTAL_B);
+ pipeb->vblank = PSB_RVDC32(VBLANK_B);
+ pipeb->vsync = PSB_RVDC32(VSYNC_B);
hdmi_dev->savePCH_PIPEBCONF = PSB_RVDC32(PCH_PIPEBCONF);
hdmi_dev->savePCH_PIPEBSRC = PSB_RVDC32(PCH_PIPEBSRC);
@@ -469,12 +464,12 @@ void oaktrail_hdmi_save(struct drm_device *dev)
hdmi_dev->savePCH_VSYNC_B = PSB_RVDC32(PCH_VSYNC_B);
/* plane */
- regs->saveDSPBCNTR = PSB_RVDC32(DSPBCNTR);
- regs->saveDSPBSTRIDE = PSB_RVDC32(DSPBSTRIDE);
- regs->saveDSPBADDR = PSB_RVDC32(DSPBBASE);
- regs->saveDSPBSURF = PSB_RVDC32(DSPBSURF);
- regs->saveDSPBLINOFF = PSB_RVDC32(DSPBLINOFF);
- regs->saveDSPBTILEOFF = PSB_RVDC32(DSPBTILEOFF);
+ pipeb->cntr = PSB_RVDC32(DSPBCNTR);
+ pipeb->stride = PSB_RVDC32(DSPBSTRIDE);
+ pipeb->addr = PSB_RVDC32(DSPBBASE);
+ pipeb->surf = PSB_RVDC32(DSPBSURF);
+ pipeb->linoff = PSB_RVDC32(DSPBLINOFF);
+ pipeb->tileoff = PSB_RVDC32(DSPBTILEOFF);
/* cursor B */
regs->saveDSPBCURSOR_CTRL = PSB_RVDC32(CURBCNTR);
@@ -483,7 +478,7 @@ void oaktrail_hdmi_save(struct drm_device *dev)
/* save palette */
for (i = 0; i < 256; i++)
- regs->save_palette_b[i] = PSB_RVDC32(PALETTE_B + (i << 2));
+ pipeb->palette[i] = PSB_RVDC32(PALETTE_B + (i << 2));
}
/* restore HDMI register state */
@@ -492,6 +487,7 @@ void oaktrail_hdmi_restore(struct drm_device *dev)
struct drm_psb_private *dev_priv = dev->dev_private;
struct oaktrail_hdmi_dev *hdmi_dev = dev_priv->hdmi_priv;
struct psb_state *regs = &dev_priv->regs.psb;
+ struct psb_pipe *pipeb = &dev_priv->regs.pipe[1];
int i;
/* dpll */
@@ -503,13 +499,13 @@ void oaktrail_hdmi_restore(struct drm_device *dev)
DRM_UDELAY(150);
/* pipe */
- PSB_WVDC32(regs->savePIPEBSRC, PIPEBSRC);
- PSB_WVDC32(regs->saveHTOTAL_B, HTOTAL_B);
- PSB_WVDC32(regs->saveHBLANK_B, HBLANK_B);
- PSB_WVDC32(regs->saveHSYNC_B, HSYNC_B);
- PSB_WVDC32(regs->saveVTOTAL_B, VTOTAL_B);
- PSB_WVDC32(regs->saveVBLANK_B, VBLANK_B);
- PSB_WVDC32(regs->saveVSYNC_B, VSYNC_B);
+ PSB_WVDC32(pipeb->src, PIPEBSRC);
+ PSB_WVDC32(pipeb->htotal, HTOTAL_B);
+ PSB_WVDC32(pipeb->hblank, HBLANK_B);
+ PSB_WVDC32(pipeb->hsync, HSYNC_B);
+ PSB_WVDC32(pipeb->vtotal, VTOTAL_B);
+ PSB_WVDC32(pipeb->vblank, VBLANK_B);
+ PSB_WVDC32(pipeb->vsync, VSYNC_B);
PSB_WVDC32(hdmi_dev->savePCH_PIPEBSRC, PCH_PIPEBSRC);
PSB_WVDC32(hdmi_dev->savePCH_HTOTAL_B, PCH_HTOTAL_B);
@@ -519,15 +515,15 @@ void oaktrail_hdmi_restore(struct drm_device *dev)
PSB_WVDC32(hdmi_dev->savePCH_VBLANK_B, PCH_VBLANK_B);
PSB_WVDC32(hdmi_dev->savePCH_VSYNC_B, PCH_VSYNC_B);
- PSB_WVDC32(regs->savePIPEBCONF, PIPEBCONF);
+ PSB_WVDC32(pipeb->conf, PIPEBCONF);
PSB_WVDC32(hdmi_dev->savePCH_PIPEBCONF, PCH_PIPEBCONF);
/* plane */
- PSB_WVDC32(regs->saveDSPBLINOFF, DSPBLINOFF);
- PSB_WVDC32(regs->saveDSPBSTRIDE, DSPBSTRIDE);
- PSB_WVDC32(regs->saveDSPBTILEOFF, DSPBTILEOFF);
- PSB_WVDC32(regs->saveDSPBCNTR, DSPBCNTR);
- PSB_WVDC32(regs->saveDSPBSURF, DSPBSURF);
+ PSB_WVDC32(pipeb->linoff, DSPBLINOFF);
+ PSB_WVDC32(pipeb->stride, DSPBSTRIDE);
+ PSB_WVDC32(pipeb->tileoff, DSPBTILEOFF);
+ PSB_WVDC32(pipeb->cntr, DSPBCNTR);
+ PSB_WVDC32(pipeb->surf, DSPBSURF);
/* cursor B */
PSB_WVDC32(regs->saveDSPBCURSOR_CTRL, CURBCNTR);
@@ -536,5 +532,5 @@ void oaktrail_hdmi_restore(struct drm_device *dev)
/* restore palette */
for (i = 0; i < 256; i++)
- PSB_WVDC32(regs->save_palette_b[i], PALETTE_B + (i << 2));
+ PSB_WVDC32(pipeb->palette[i], PALETTE_B + (i << 2));
}
diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c b/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c
index 5e84fbde749b..88627e3ba1e3 100644
--- a/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c
+++ b/drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c
@@ -250,7 +250,7 @@ static irqreturn_t oaktrail_hdmi_i2c_handler(int this_irq, void *dev)
*/
static void oaktrail_hdmi_i2c_gpio_fix(void)
{
- void *base;
+ void __iomem *base;
unsigned int gpio_base = 0xff12c000;
int gpio_len = 0x1000;
u32 temp;
diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds.c b/drivers/gpu/drm/gma500/oaktrail_lvds.c
index 654f32b22b21..558c77fb55ec 100644
--- a/drivers/gpu/drm/gma500/oaktrail_lvds.c
+++ b/drivers/gpu/drm/gma500/oaktrail_lvds.c
@@ -257,7 +257,7 @@ static void oaktrail_lvds_get_configuration_mode(struct drm_device *dev,
mode_dev->panel_fixed_mode = NULL;
/* Use the firmware provided data on Moorestown */
- if (dev_priv->vbt_data.size != 0x00) { /*if non-zero, then use vbt*/
+ if (dev_priv->has_gct) {
mode = kzalloc(sizeof(*mode), GFP_KERNEL);
if (!mode)
return;
@@ -371,7 +371,7 @@ void oaktrail_lvds_init(struct drm_device *dev,
BRIGHTNESS_MAX_LEVEL);
mode_dev->panel_wants_dither = false;
- if (dev_priv->vbt_data.size != 0x00)
+ if (dev_priv->has_gct)
mode_dev->panel_wants_dither = (dev_priv->gct_data.
Panel_Port_Control & MRST_PANEL_8TO6_DITHER_ENABLE);
if (dev_priv->lvds_dither)
diff --git a/drivers/gpu/drm/gma500/opregion.c b/drivers/gpu/drm/gma500/opregion.c
new file mode 100644
index 000000000000..4f186eca3a30
--- /dev/null
+++ b/drivers/gpu/drm/gma500/opregion.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <linux/acpi.h>
+#include <linux/acpi_io.h>
+#include "psb_drv.h"
+#include "psb_intel_reg.h"
+
+#define PCI_ASLE 0xe4
+#define PCI_ASLS 0xfc
+
+#define OPREGION_HEADER_OFFSET 0
+#define OPREGION_ACPI_OFFSET 0x100
+#define ACPI_CLID 0x01ac /* current lid state indicator */
+#define ACPI_CDCK 0x01b0 /* current docking state indicator */
+#define OPREGION_SWSCI_OFFSET 0x200
+#define OPREGION_ASLE_OFFSET 0x300
+#define OPREGION_VBT_OFFSET 0x400
+
+#define OPREGION_SIGNATURE "IntelGraphicsMem"
+#define MBOX_ACPI (1<<0)
+#define MBOX_SWSCI (1<<1)
+#define MBOX_ASLE (1<<2)
+
+struct opregion_header {
+ u8 signature[16];
+ u32 size;
+ u32 opregion_ver;
+ u8 bios_ver[32];
+ u8 vbios_ver[16];
+ u8 driver_ver[16];
+ u32 mboxes;
+ u8 reserved[164];
+} __packed;
+
+/* OpRegion mailbox #1: public ACPI methods */
+struct opregion_acpi {
+ u32 drdy; /* driver readiness */
+ u32 csts; /* notification status */
+ u32 cevt; /* current event */
+ u8 rsvd1[20];
+ u32 didl[8]; /* supported display devices ID list */
+ u32 cpdl[8]; /* currently presented display list */
+ u32 cadl[8]; /* currently active display list */
+ u32 nadl[8]; /* next active devices list */
+ u32 aslp; /* ASL sleep time-out */
+ u32 tidx; /* toggle table index */
+ u32 chpd; /* current hotplug enable indicator */
+ u32 clid; /* current lid state*/
+ u32 cdck; /* current docking state */
+ u32 sxsw; /* Sx state resume */
+ u32 evts; /* ASL supported events */
+ u32 cnot; /* current OS notification */
+ u32 nrdy; /* driver status */
+ u8 rsvd2[60];
+} __packed;
+
+/* OpRegion mailbox #2: SWSCI */
+struct opregion_swsci {
+ /*FIXME: add it later*/
+} __packed;
+
+/* OpRegion mailbox #3: ASLE */
+struct opregion_asle {
+ u32 ardy; /* driver readiness */
+ u32 aslc; /* ASLE interrupt command */
+ u32 tche; /* technology enabled indicator */
+ u32 alsi; /* current ALS illuminance reading */
+ u32 bclp; /* backlight brightness to set */
+ u32 pfit; /* panel fitting state */
+ u32 cblv; /* current brightness level */
+ u16 bclm[20]; /* backlight level duty cycle mapping table */
+ u32 cpfm; /* current panel fitting mode */
+ u32 epfm; /* enabled panel fitting modes */
+ u8 plut[74]; /* panel LUT and identifier */
+ u32 pfmb; /* PWM freq and min brightness */
+ u8 rsvd[102];
+} __packed;
+
+/* ASLE irq request bits */
+#define ASLE_SET_ALS_ILLUM (1 << 0)
+#define ASLE_SET_BACKLIGHT (1 << 1)
+#define ASLE_SET_PFIT (1 << 2)
+#define ASLE_SET_PWM_FREQ (1 << 3)
+#define ASLE_REQ_MSK 0xf
+
+/* response bits of ASLE irq request */
+#define ASLE_ALS_ILLUM_FAILED (1<<10)
+#define ASLE_BACKLIGHT_FAILED (1<<12)
+#define ASLE_PFIT_FAILED (1<<14)
+#define ASLE_PWM_FREQ_FAILED (1<<16)
+
+/* ASLE backlight brightness to set */
+#define ASLE_BCLP_VALID (1<<31)
+#define ASLE_BCLP_MSK (~(1<<31))
+
+/* ASLE panel fitting request */
+#define ASLE_PFIT_VALID (1<<31)
+#define ASLE_PFIT_CENTER (1<<0)
+#define ASLE_PFIT_STRETCH_TEXT (1<<1)
+#define ASLE_PFIT_STRETCH_GFX (1<<2)
+
+/* response bits of ASLE irq request */
+#define ASLE_ALS_ILLUM_FAILED (1<<10)
+#define ASLE_BACKLIGHT_FAILED (1<<12)
+#define ASLE_PFIT_FAILED (1<<14)
+#define ASLE_PWM_FREQ_FAILED (1<<16)
+
+/* ASLE backlight brightness to set */
+#define ASLE_BCLP_VALID (1<<31)
+#define ASLE_BCLP_MSK (~(1<<31))
+
+/* ASLE panel fitting request */
+#define ASLE_PFIT_VALID (1<<31)
+#define ASLE_PFIT_CENTER (1<<0)
+#define ASLE_PFIT_STRETCH_TEXT (1<<1)
+#define ASLE_PFIT_STRETCH_GFX (1<<2)
+
+/* PWM frequency and minimum brightness */
+#define ASLE_PFMB_BRIGHTNESS_MASK (0xff)
+#define ASLE_PFMB_BRIGHTNESS_VALID (1<<8)
+#define ASLE_PFMB_PWM_MASK (0x7ffffe00)
+#define ASLE_PFMB_PWM_VALID (1<<31)
+
+#define ASLE_CBLV_VALID (1<<31)
+
+static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
+{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ struct opregion_asle *asle = dev_priv->opregion.asle;
+ struct backlight_device *bd = dev_priv->backlight_device;
+
+ DRM_DEBUG_DRIVER("asle set backlight %x\n", bclp);
+
+ if (!(bclp & ASLE_BCLP_VALID))
+ return ASLE_BACKLIGHT_FAILED;
+
+ if (bd == NULL)
+ return ASLE_BACKLIGHT_FAILED;
+
+ bclp &= ASLE_BCLP_MSK;
+ if (bclp > 255)
+ return ASLE_BACKLIGHT_FAILED;
+
+ if (config_enabled(CONFIG_BACKLIGHT_CLASS_DEVICE)) {
+ int max = bd->props.max_brightness;
+ bd->props.brightness = bclp * max / 255;
+ backlight_update_status(bd);
+ }
+
+ asle->cblv = (bclp * 0x64) / 0xff | ASLE_CBLV_VALID;
+
+ return 0;
+}
+
+void psb_intel_opregion_asle_intr(struct drm_device *dev)
+{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ struct opregion_asle *asle = dev_priv->opregion.asle;
+ u32 asle_stat = 0;
+ u32 asle_req;
+
+ if (!asle)
+ return;
+
+ asle_req = asle->aslc & ASLE_REQ_MSK;
+ if (!asle_req) {
+ DRM_DEBUG_DRIVER("non asle set request??\n");
+ return;
+ }
+
+ if (asle_req & ASLE_SET_BACKLIGHT)
+ asle_stat |= asle_set_backlight(dev, asle->bclp);
+
+ asle->aslc = asle_stat;
+}
+
+#define ASLE_ALS_EN (1<<0)
+#define ASLE_BLC_EN (1<<1)
+#define ASLE_PFIT_EN (1<<2)
+#define ASLE_PFMB_EN (1<<3)
+
+void psb_intel_opregion_enable_asle(struct drm_device *dev)
+{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ struct opregion_asle *asle = dev_priv->opregion.asle;
+
+ if (asle) {
+ /* Don't do this on Medfield or other non PC like devices, they
+ use the bit for something different altogether */
+ psb_enable_pipestat(dev_priv, 0, PIPE_LEGACY_BLC_EVENT_ENABLE);
+ psb_enable_pipestat(dev_priv, 1, PIPE_LEGACY_BLC_EVENT_ENABLE);
+
+ asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN
+ | ASLE_PFMB_EN;
+ asle->ardy = 1;
+ }
+}
+
+#define ACPI_EV_DISPLAY_SWITCH (1<<0)
+#define ACPI_EV_LID (1<<1)
+#define ACPI_EV_DOCK (1<<2)
+
+static struct psb_intel_opregion *system_opregion;
+
+static int psb_intel_opregion_video_event(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ /* The only video events relevant to opregion are 0x80. These indicate
+ either a docking event, lid switch or display switch request. In
+ Linux, these are handled by the dock, button and video drivers.
+ We might want to fix the video driver to be opregion-aware in
+ future, but right now we just indicate to the firmware that the
+ request has been handled */
+
+ struct opregion_acpi *acpi;
+
+ if (!system_opregion)
+ return NOTIFY_DONE;
+
+ acpi = system_opregion->acpi;
+ acpi->csts = 0;
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block psb_intel_opregion_notifier = {
+ .notifier_call = psb_intel_opregion_video_event,
+};
+
+void psb_intel_opregion_init(struct drm_device *dev)
+{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ struct psb_intel_opregion *opregion = &dev_priv->opregion;
+
+ if (!opregion->header)
+ return;
+
+ if (opregion->acpi) {
+ /* Notify BIOS we are ready to handle ACPI video ext notifs.
+ * Right now, all the events are handled by the ACPI video
+ * module. We don't actually need to do anything with them. */
+ opregion->acpi->csts = 0;
+ opregion->acpi->drdy = 1;
+
+ system_opregion = opregion;
+ register_acpi_notifier(&psb_intel_opregion_notifier);
+ }
+
+ if (opregion->asle)
+ psb_intel_opregion_enable_asle(dev);
+}
+
+void psb_intel_opregion_fini(struct drm_device *dev)
+{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ struct psb_intel_opregion *opregion = &dev_priv->opregion;
+
+ if (!opregion->header)
+ return;
+
+ if (opregion->acpi) {
+ opregion->acpi->drdy = 0;
+
+ system_opregion = NULL;
+ unregister_acpi_notifier(&psb_intel_opregion_notifier);
+ }
+
+ /* just clear all opregion memory pointers now */
+ iounmap(opregion->header);
+ opregion->header = NULL;
+ opregion->acpi = NULL;
+ opregion->swsci = NULL;
+ opregion->asle = NULL;
+ opregion->vbt = NULL;
+}
+
+int psb_intel_opregion_setup(struct drm_device *dev)
+{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ struct psb_intel_opregion *opregion = &dev_priv->opregion;
+ u32 opregion_phy, mboxes;
+ void __iomem *base;
+ int err = 0;
+
+ pci_read_config_dword(dev->pdev, PCI_ASLS, &opregion_phy);
+ if (opregion_phy == 0) {
+ DRM_DEBUG_DRIVER("ACPI Opregion not supported\n");
+ return -ENOTSUPP;
+ }
+ DRM_DEBUG("OpRegion detected at 0x%8x\n", opregion_phy);
+ base = acpi_os_ioremap(opregion_phy, 8*1024);
+ if (!base)
+ return -ENOMEM;
+
+ if (memcmp(base, OPREGION_SIGNATURE, 16)) {
+ DRM_DEBUG_DRIVER("opregion signature mismatch\n");
+ err = -EINVAL;
+ goto err_out;
+ }
+
+ opregion->header = base;
+ opregion->vbt = base + OPREGION_VBT_OFFSET;
+
+ opregion->lid_state = base + ACPI_CLID;
+
+ mboxes = opregion->header->mboxes;
+ if (mboxes & MBOX_ACPI) {
+ DRM_DEBUG_DRIVER("Public ACPI methods supported\n");
+ opregion->acpi = base + OPREGION_ACPI_OFFSET;
+ }
+
+ if (mboxes & MBOX_ASLE) {
+ DRM_DEBUG_DRIVER("ASLE supported\n");
+ opregion->asle = base + OPREGION_ASLE_OFFSET;
+ }
+
+ return 0;
+
+err_out:
+ iounmap(base);
+ return err;
+}
+
diff --git a/drivers/gpu/drm/gma500/intel_opregion.c b/drivers/gpu/drm/gma500/opregion.h
index d946bc1b17bf..72dc6b921265 100644
--- a/drivers/gpu/drm/gma500/intel_opregion.c
+++ b/drivers/gpu/drm/gma500/opregion.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2010 Intel Corporation
+ * Copyright 2012 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -20,62 +20,30 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
- * FIXME: resolve with the i915 version
*/
-#include "psb_drv.h"
+#if defined(CONFIG_ACPI)
+extern void psb_intel_opregion_asle_intr(struct drm_device *dev);
+extern void psb_intel_opregion_init(struct drm_device *dev);
+extern void psb_intel_opregion_fini(struct drm_device *dev);
+extern int psb_intel_opregion_setup(struct drm_device *dev);
-struct opregion_header {
- u8 signature[16];
- u32 size;
- u32 opregion_ver;
- u8 bios_ver[32];
- u8 vbios_ver[16];
- u8 driver_ver[16];
- u32 mboxes;
- u8 reserved[164];
-} __packed;
+#else
-struct opregion_apci {
- /*FIXME: add it later*/
-} __packed;
-
-struct opregion_swsci {
- /*FIXME: add it later*/
-} __packed;
-
-struct opregion_acpi {
- /*FIXME: add it later*/
-} __packed;
-
-int gma_intel_opregion_init(struct drm_device *dev)
+extern inline void psb_intel_opregion_asle_intr(struct drm_device *dev)
{
- struct drm_psb_private *dev_priv = dev->dev_private;
- u32 opregion_phy;
- void *base;
- u32 *lid_state;
-
- dev_priv->lid_state = NULL;
-
- pci_read_config_dword(dev->pdev, 0xfc, &opregion_phy);
- if (opregion_phy == 0)
- return -ENOTSUPP;
-
- base = ioremap(opregion_phy, 8*1024);
- if (!base)
- return -ENOMEM;
+}
- lid_state = base + 0x01ac;
+extern inline void psb_intel_opregion_init(struct drm_device *dev)
+{
+}
- dev_priv->lid_state = lid_state;
- dev_priv->lid_last_state = readl(lid_state);
- return 0;
+extern inline void psb_intel_opregion_fini(struct drm_device *dev)
+{
}
-int gma_intel_opregion_exit(struct drm_device *dev)
+extern inline int psb_intel_opregion_setup(struct drm_device *dev)
{
- struct drm_psb_private *dev_priv = dev->dev_private;
- if (dev_priv->lid_state)
- iounmap(dev_priv->lid_state);
return 0;
}
+#endif
diff --git a/drivers/gpu/drm/gma500/psb_device.c b/drivers/gpu/drm/gma500/psb_device.c
index 95d163e4f1f4..eff039bf92d4 100644
--- a/drivers/gpu/drm/gma500/psb_device.c
+++ b/drivers/gpu/drm/gma500/psb_device.c
@@ -197,7 +197,8 @@ static int psb_save_display_registers(struct drm_device *dev)
}
list_for_each_entry(connector, &dev->mode_config.connector_list, head)
- connector->funcs->save(connector);
+ if (connector->funcs->save)
+ connector->funcs->save(connector);
mutex_unlock(&dev->mode_config.mutex);
return 0;
@@ -235,7 +236,8 @@ static int psb_restore_display_registers(struct drm_device *dev)
crtc->funcs->restore(crtc);
list_for_each_entry(connector, &dev->mode_config.connector_list, head)
- connector->funcs->restore(connector);
+ if (connector->funcs->restore)
+ connector->funcs->restore(connector);
mutex_unlock(&dev->mode_config.mutex);
return 0;
@@ -289,17 +291,80 @@ static void psb_get_core_freq(struct drm_device *dev)
}
}
+/* Poulsbo */
+static const struct psb_offset psb_regmap[2] = {
+ {
+ .fp0 = FPA0,
+ .fp1 = FPA1,
+ .cntr = DSPACNTR,
+ .conf = PIPEACONF,
+ .src = PIPEASRC,
+ .dpll = DPLL_A,
+ .htotal = HTOTAL_A,
+ .hblank = HBLANK_A,
+ .hsync = HSYNC_A,
+ .vtotal = VTOTAL_A,
+ .vblank = VBLANK_A,
+ .vsync = VSYNC_A,
+ .stride = DSPASTRIDE,
+ .size = DSPASIZE,
+ .pos = DSPAPOS,
+ .base = DSPABASE,
+ .surf = DSPASURF,
+ .addr = DSPABASE,
+ .status = PIPEASTAT,
+ .linoff = DSPALINOFF,
+ .tileoff = DSPATILEOFF,
+ .palette = PALETTE_A,
+ },
+ {
+ .fp0 = FPB0,
+ .fp1 = FPB1,
+ .cntr = DSPBCNTR,
+ .conf = PIPEBCONF,
+ .src = PIPEBSRC,
+ .dpll = DPLL_B,
+ .htotal = HTOTAL_B,
+ .hblank = HBLANK_B,
+ .hsync = HSYNC_B,
+ .vtotal = VTOTAL_B,
+ .vblank = VBLANK_B,
+ .vsync = VSYNC_B,
+ .stride = DSPBSTRIDE,
+ .size = DSPBSIZE,
+ .pos = DSPBPOS,
+ .base = DSPBBASE,
+ .surf = DSPBSURF,
+ .addr = DSPBBASE,
+ .status = PIPEBSTAT,
+ .linoff = DSPBLINOFF,
+ .tileoff = DSPBTILEOFF,
+ .palette = PALETTE_B,
+ }
+};
+
static int psb_chip_setup(struct drm_device *dev)
{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ dev_priv->regmap = psb_regmap;
psb_get_core_freq(dev);
gma_intel_setup_gmbus(dev);
- gma_intel_opregion_init(dev);
+ psb_intel_opregion_init(dev);
psb_intel_init_bios(dev);
return 0;
}
+/* Not exactly an erratum more an irritation */
+static void psb_chip_errata(struct drm_device *dev)
+{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ psb_lid_timer_init(dev_priv);
+}
+
static void psb_chip_teardown(struct drm_device *dev)
{
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ psb_lid_timer_takedown(dev_priv);
gma_intel_teardown_gmbus(dev);
}
@@ -308,9 +373,13 @@ const struct psb_ops psb_chip_ops = {
.accel_2d = 1,
.pipes = 2,
.crtcs = 2,
+ .hdmi_mask = (1 << 0),
+ .lvds_mask = (1 << 1),
+ .cursor_needs_phys = 1,
.sgx_offset = PSB_SGX_OFFSET,
.chip_setup = psb_chip_setup,
.chip_teardown = psb_chip_teardown,
+ .errata = psb_chip_errata,
.crtc_helper = &psb_intel_helper_funcs,
.crtc_funcs = &psb_intel_crtc_funcs,
diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c
index c34adf9d910a..caba6e08693c 100644
--- a/drivers/gpu/drm/gma500/psb_drv.c
+++ b/drivers/gpu/drm/gma500/psb_drv.c
@@ -79,6 +79,14 @@ static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
{ 0x8086, 0x0be5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
{ 0x8086, 0x0be6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
{ 0x8086, 0x0be7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
+ { 0x8086, 0x0be8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
+ { 0x8086, 0x0be9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
+ { 0x8086, 0x0bea, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
+ { 0x8086, 0x0beb, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
+ { 0x8086, 0x0bec, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
+ { 0x8086, 0x0bed, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
+ { 0x8086, 0x0bee, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
+ { 0x8086, 0x0bef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
#endif
{ 0, }
};
@@ -144,10 +152,6 @@ static void psb_lastclose(struct drm_device *dev)
return;
}
-static void psb_do_takedown(struct drm_device *dev)
-{
-}
-
static int psb_do_init(struct drm_device *dev)
{
struct drm_psb_private *dev_priv = dev->dev_private;
@@ -172,24 +176,6 @@ static int psb_do_init(struct drm_device *dev)
dev_priv->gatt_free_offset = pg->mmu_gatt_start +
(stolen_gtt << PAGE_SHIFT) * 1024;
- if (1 || drm_debug) {
- uint32_t core_id = PSB_RSGX32(PSB_CR_CORE_ID);
- uint32_t core_rev = PSB_RSGX32(PSB_CR_CORE_REVISION);
- DRM_INFO("SGX core id = 0x%08x\n", core_id);
- DRM_INFO("SGX core rev major = 0x%02x, minor = 0x%02x\n",
- (core_rev & _PSB_CC_REVISION_MAJOR_MASK) >>
- _PSB_CC_REVISION_MAJOR_SHIFT,
- (core_rev & _PSB_CC_REVISION_MINOR_MASK) >>
- _PSB_CC_REVISION_MINOR_SHIFT);
- DRM_INFO
- ("SGX core rev maintenance = 0x%02x, designer = 0x%02x\n",
- (core_rev & _PSB_CC_REVISION_MAINTENANCE_MASK) >>
- _PSB_CC_REVISION_MAINTENANCE_SHIFT,
- (core_rev & _PSB_CC_REVISION_DESIGNER_MASK) >>
- _PSB_CC_REVISION_DESIGNER_SHIFT);
- }
-
-
spin_lock_init(&dev_priv->irqmask_lock);
spin_lock_init(&dev_priv->lock_2d);
@@ -204,7 +190,6 @@ static int psb_do_init(struct drm_device *dev)
PSB_WSGX32(pg->gatt_start, PSB_CR_BIF_TWOD_REQ_BASE);
return 0;
out_err:
- psb_do_takedown(dev);
return ret;
}
@@ -214,18 +199,16 @@ static int psb_driver_unload(struct drm_device *dev)
/* Kill vblank etc here */
- gma_backlight_exit(dev);
-
- psb_modeset_cleanup(dev);
if (dev_priv) {
- psb_lid_timer_takedown(dev_priv);
- gma_intel_opregion_exit(dev);
+ if (dev_priv->backlight_device)
+ gma_backlight_exit(dev);
+ psb_modeset_cleanup(dev);
if (dev_priv->ops->chip_teardown)
dev_priv->ops->chip_teardown(dev);
- psb_do_takedown(dev);
+ psb_intel_opregion_fini(dev);
if (dev_priv->pf_pd) {
psb_mmu_free_pagedir(dev_priv->pf_pd);
@@ -246,6 +229,7 @@ static int psb_driver_unload(struct drm_device *dev)
}
psb_gtt_takedown(dev);
if (dev_priv->scratch_page) {
+ set_pages_wb(dev_priv->scratch_page, 1);
__free_page(dev_priv->scratch_page);
dev_priv->scratch_page = NULL;
}
@@ -258,15 +242,13 @@ static int psb_driver_unload(struct drm_device *dev)
dev_priv->sgx_reg = NULL;
}
+ /* Destroy VBT data */
+ psb_intel_destroy_bios(dev);
+
kfree(dev_priv);
dev->dev_private = NULL;
-
- /*destroy VBT data*/
- psb_intel_destroy_bios(dev);
}
-
gma_power_uninit(dev);
-
return 0;
}
@@ -290,11 +272,6 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset)
pci_set_master(dev->pdev);
- if (!IS_PSB(dev)) {
- if (pci_enable_msi(dev->pdev))
- dev_warn(dev->dev, "Enabling MSI failed!\n");
- }
-
dev_priv->num_pipe = dev_priv->ops->pipes;
resource_start = pci_resource_start(dev->pdev, PSB_MMIO_RESOURCE);
@@ -309,6 +286,8 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset)
if (!dev_priv->sgx_reg)
goto out_err;
+ psb_intel_opregion_setup(dev);
+
ret = dev_priv->ops->chip_setup(dev);
if (ret)
goto out_err;
@@ -348,10 +327,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset)
PSB_WSGX32(0x20000000, PSB_CR_PDS_EXEC_BASE);
PSB_WSGX32(0x30000000, PSB_CR_BIF_3D_REQ_BASE);
-/* igd_opregion_init(&dev_priv->opregion_dev); */
acpi_video_register();
- if (dev_priv->lid_state)
- psb_lid_timer_init(dev_priv);
ret = drm_vblank_init(dev, dev_priv->num_pipe);
if (ret)
@@ -370,8 +346,8 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset)
PSB_WVDC32(0x00000000, PSB_INT_ENABLE_R);
PSB_WVDC32(0xFFFFFFFF, PSB_INT_MASK_R);
spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
- if (IS_PSB(dev) && drm_core_check_feature(dev, DRIVER_MODESET))
- drm_irq_install(dev);
+
+ drm_irq_install(dev);
dev->vblank_disable_allowed = 1;
@@ -619,7 +595,7 @@ static const struct dev_pm_ops psb_pm_ops = {
.runtime_idle = psb_runtime_idle,
};
-static struct vm_operations_struct psb_gem_vm_ops = {
+static const struct vm_operations_struct psb_gem_vm_ops = {
.fault = psb_gem_fault,
.open = drm_gem_vm_open,
.close = drm_gem_vm_close,
diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h
index 40ce2c9bc2e4..1bd115ecefe1 100644
--- a/drivers/gpu/drm/gma500/psb_drv.h
+++ b/drivers/gpu/drm/gma500/psb_drv.h
@@ -30,6 +30,7 @@
#include "psb_intel_drv.h"
#include "gtt.h"
#include "power.h"
+#include "opregion.h"
#include "oaktrail.h"
/* Append new drm mode definition here, align with libdrm definition */
@@ -120,6 +121,7 @@ enum {
#define PSB_HWSTAM 0x2098
#define PSB_INSTPM 0x20C0
#define PSB_INT_IDENTITY_R 0x20A4
+#define _PSB_IRQ_ASLE (1<<0)
#define _MDFLD_PIPEC_EVENT_FLAG (1<<2)
#define _MDFLD_PIPEC_VBLANK_FLAG (1<<3)
#define _PSB_DPST_PIPEB_FLAG (1<<4)
@@ -130,6 +132,7 @@ enum {
#define _PSB_VSYNC_PIPEA_FLAG (1<<7)
#define _MDFLD_MIPIA_FLAG (1<<16)
#define _MDFLD_MIPIC_FLAG (1<<17)
+#define _PSB_IRQ_DISP_HOTSYNC (1<<17)
#define _PSB_IRQ_SGX_FLAG (1<<18)
#define _PSB_IRQ_MSVDX_FLAG (1<<19)
#define _LNC_IRQ_TOPAZ_FLAG (1<<20)
@@ -257,7 +260,8 @@ struct psb_intel_opregion {
struct opregion_acpi *acpi;
struct opregion_swsci *swsci;
struct opregion_asle *asle;
- int enabled;
+ void *vbt;
+ u32 __iomem *lid_state;
};
struct sdvo_device_mapping {
@@ -277,50 +281,72 @@ struct intel_gmbus {
};
/*
+ * Register offset maps
+ */
+
+struct psb_offset {
+ u32 fp0;
+ u32 fp1;
+ u32 cntr;
+ u32 conf;
+ u32 src;
+ u32 dpll;
+ u32 dpll_md;
+ u32 htotal;
+ u32 hblank;
+ u32 hsync;
+ u32 vtotal;
+ u32 vblank;
+ u32 vsync;
+ u32 stride;
+ u32 size;
+ u32 pos;
+ u32 surf;
+ u32 addr;
+ u32 base;
+ u32 status;
+ u32 linoff;
+ u32 tileoff;
+ u32 palette;
+};
+
+/*
* Register save state. This is used to hold the context when the
* device is powered off. In the case of Oaktrail this can (but does not
* yet) include screen blank. Operations occuring during the save
* update the register cache instead.
*/
+
+/*
+ * Common status for pipes.
+ */
+struct psb_pipe {
+ u32 fp0;
+ u32 fp1;
+ u32 cntr;
+ u32 conf;
+ u32 src;
+ u32 dpll;
+ u32 dpll_md;
+ u32 htotal;
+ u32 hblank;
+ u32 hsync;
+ u32 vtotal;
+ u32 vblank;
+ u32 vsync;
+ u32 stride;
+ u32 size;
+ u32 pos;
+ u32 base;
+ u32 surf;
+ u32 addr;
+ u32 status;
+ u32 linoff;
+ u32 tileoff;
+ u32 palette[256];
+};
+
struct psb_state {
- uint32_t saveDSPACNTR;
- uint32_t saveDSPBCNTR;
- uint32_t savePIPEACONF;
- uint32_t savePIPEBCONF;
- uint32_t savePIPEASRC;
- uint32_t savePIPEBSRC;
- uint32_t saveFPA0;
- uint32_t saveFPA1;
- uint32_t saveDPLL_A;
- uint32_t saveDPLL_A_MD;
- uint32_t saveHTOTAL_A;
- uint32_t saveHBLANK_A;
- uint32_t saveHSYNC_A;
- uint32_t saveVTOTAL_A;
- uint32_t saveVBLANK_A;
- uint32_t saveVSYNC_A;
- uint32_t saveDSPASTRIDE;
- uint32_t saveDSPASIZE;
- uint32_t saveDSPAPOS;
- uint32_t saveDSPABASE;
- uint32_t saveDSPASURF;
- uint32_t saveDSPASTATUS;
- uint32_t saveFPB0;
- uint32_t saveFPB1;
- uint32_t saveDPLL_B;
- uint32_t saveDPLL_B_MD;
- uint32_t saveHTOTAL_B;
- uint32_t saveHBLANK_B;
- uint32_t saveHSYNC_B;
- uint32_t saveVTOTAL_B;
- uint32_t saveVBLANK_B;
- uint32_t saveVSYNC_B;
- uint32_t saveDSPBSTRIDE;
- uint32_t saveDSPBSIZE;
- uint32_t saveDSPBPOS;
- uint32_t saveDSPBBASE;
- uint32_t saveDSPBSURF;
- uint32_t saveDSPBSTATUS;
uint32_t saveVCLK_DIVISOR_VGA0;
uint32_t saveVCLK_DIVISOR_VGA1;
uint32_t saveVCLK_POST_DIV;
@@ -335,14 +361,8 @@ struct psb_state {
uint32_t savePP_CONTROL;
uint32_t savePP_CYCLE;
uint32_t savePFIT_CONTROL;
- uint32_t savePaletteA[256];
- uint32_t savePaletteB[256];
uint32_t saveCLOCKGATING;
uint32_t saveDSPARB;
- uint32_t saveDSPATILEOFF;
- uint32_t saveDSPBTILEOFF;
- uint32_t saveDSPAADDR;
- uint32_t saveDSPBADDR;
uint32_t savePFIT_AUTO_RATIOS;
uint32_t savePFIT_PGM_RATIOS;
uint32_t savePP_ON_DELAYS;
@@ -350,8 +370,6 @@ struct psb_state {
uint32_t savePP_DIVISOR;
uint32_t saveBCLRPAT_A;
uint32_t saveBCLRPAT_B;
- uint32_t saveDSPALINOFF;
- uint32_t saveDSPBLINOFF;
uint32_t savePERF_MODE;
uint32_t saveDSPFW1;
uint32_t saveDSPFW2;
@@ -366,8 +384,6 @@ struct psb_state {
uint32_t saveDSPBCURSOR_BASE;
uint32_t saveDSPACURSOR_POS;
uint32_t saveDSPBCURSOR_POS;
- uint32_t save_palette_a[256];
- uint32_t save_palette_b[256];
uint32_t saveOV_OVADD;
uint32_t saveOV_OGAMC0;
uint32_t saveOV_OGAMC1;
@@ -390,64 +406,7 @@ struct psb_state {
};
struct medfield_state {
- uint32_t saveDPLL_A;
- uint32_t saveFPA0;
- uint32_t savePIPEACONF;
- uint32_t saveHTOTAL_A;
- uint32_t saveHBLANK_A;
- uint32_t saveHSYNC_A;
- uint32_t saveVTOTAL_A;
- uint32_t saveVBLANK_A;
- uint32_t saveVSYNC_A;
- uint32_t savePIPEASRC;
- uint32_t saveDSPASTRIDE;
- uint32_t saveDSPALINOFF;
- uint32_t saveDSPATILEOFF;
- uint32_t saveDSPASIZE;
- uint32_t saveDSPAPOS;
- uint32_t saveDSPASURF;
- uint32_t saveDSPACNTR;
- uint32_t saveDSPASTATUS;
- uint32_t save_palette_a[256];
uint32_t saveMIPI;
-
- uint32_t saveDPLL_B;
- uint32_t saveFPB0;
- uint32_t savePIPEBCONF;
- uint32_t saveHTOTAL_B;
- uint32_t saveHBLANK_B;
- uint32_t saveHSYNC_B;
- uint32_t saveVTOTAL_B;
- uint32_t saveVBLANK_B;
- uint32_t saveVSYNC_B;
- uint32_t savePIPEBSRC;
- uint32_t saveDSPBSTRIDE;
- uint32_t saveDSPBLINOFF;
- uint32_t saveDSPBTILEOFF;
- uint32_t saveDSPBSIZE;
- uint32_t saveDSPBPOS;
- uint32_t saveDSPBSURF;
- uint32_t saveDSPBCNTR;
- uint32_t saveDSPBSTATUS;
- uint32_t save_palette_b[256];
-
- uint32_t savePIPECCONF;
- uint32_t saveHTOTAL_C;
- uint32_t saveHBLANK_C;
- uint32_t saveHSYNC_C;
- uint32_t saveVTOTAL_C;
- uint32_t saveVBLANK_C;
- uint32_t saveVSYNC_C;
- uint32_t savePIPECSRC;
- uint32_t saveDSPCSTRIDE;
- uint32_t saveDSPCLINOFF;
- uint32_t saveDSPCTILEOFF;
- uint32_t saveDSPCSIZE;
- uint32_t saveDSPCPOS;
- uint32_t saveDSPCSURF;
- uint32_t saveDSPCCNTR;
- uint32_t saveDSPCSTATUS;
- uint32_t save_palette_c[256];
uint32_t saveMIPI_C;
uint32_t savePFIT_CONTROL;
@@ -476,6 +435,7 @@ struct cdv_state {
};
struct psb_save_area {
+ struct psb_pipe pipe[3];
uint32_t saveBSM;
uint32_t saveVBT;
union {
@@ -494,15 +454,19 @@ struct psb_ops;
struct drm_psb_private {
struct drm_device *dev;
const struct psb_ops *ops;
+ const struct psb_offset *regmap;
+
+ struct child_device_config *child_dev;
+ int child_dev_num;
struct psb_gtt gtt;
/* GTT Memory manager */
struct psb_gtt_mm *gtt_mm;
struct page *scratch_page;
- u32 *gtt_map;
+ u32 __iomem *gtt_map;
uint32_t stolen_base;
- void *vram_addr;
+ u8 __iomem *vram_addr;
unsigned long vram_stolen_size;
int gtt_initialized;
u16 gmch_ctrl; /* Saved GTT setup */
@@ -518,8 +482,8 @@ struct drm_psb_private {
* Register base
*/
- uint8_t *sgx_reg;
- uint8_t *vdc_reg;
+ uint8_t __iomem *sgx_reg;
+ uint8_t __iomem *vdc_reg;
uint32_t gatt_free_offset;
/*
@@ -543,6 +507,7 @@ struct drm_psb_private {
* Modesetting
*/
struct psb_intel_mode_device mode_dev;
+ bool modeset; /* true if we have done the mode_device setup */
struct drm_crtc *plane_to_crtc_mapping[PSB_NUM_PIPE];
struct drm_crtc *pipe_to_crtc_mapping[PSB_NUM_PIPE];
@@ -605,7 +570,7 @@ struct drm_psb_private {
int rpm_enabled;
/* MID specific */
- struct oaktrail_vbt vbt_data;
+ bool has_gct;
struct oaktrail_gct_data gct_data;
/* Oaktrail HDMI state */
@@ -621,6 +586,11 @@ struct drm_psb_private {
uint32_t msi_addr;
uint32_t msi_data;
+ /*
+ * Hotplug handling
+ */
+
+ struct work_struct hotplug_work;
/*
* LID-Switch
@@ -628,7 +598,6 @@ struct drm_psb_private {
spinlock_t lid_lock;
struct timer_list lid_timer;
struct psb_intel_opregion opregion;
- u32 *lid_state;
u32 lid_last_state;
/*
@@ -669,6 +638,8 @@ struct drm_psb_private {
u32 dspcntr[3];
int mdfld_panel_id;
+
+ bool dplla_96mhz; /* DPLL data from the VBT */
};
@@ -682,6 +653,9 @@ struct psb_ops {
int pipes; /* Number of output pipes */
int crtcs; /* Number of CRTCs */
int sgx_offset; /* Base offset of SGX device */
+ int hdmi_mask; /* Mask of HDMI CRTCs */
+ int lvds_mask; /* Mask of LVDS CRTCs */
+ int cursor_needs_phys; /* If cursor base reg need physical address */
/* Sub functions */
struct drm_crtc_helper_funcs const *crtc_helper;
@@ -690,9 +664,13 @@ struct psb_ops {
/* Setup hooks */
int (*chip_setup)(struct drm_device *dev);
void (*chip_teardown)(struct drm_device *dev);
+ /* Optional helper caller after modeset */
+ void (*errata)(struct drm_device *dev);
/* Display management hooks */
int (*output_init)(struct drm_device *dev);
+ int (*hotplug)(struct drm_device *dev);
+ void (*hotplug_enable)(struct drm_device *dev, bool on);
/* Power management hooks */
void (*init_pm)(struct drm_device *dev);
int (*save_regs)(struct drm_device *dev);
@@ -789,12 +767,6 @@ psb_disable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask);
extern u32 psb_get_vblank_counter(struct drm_device *dev, int crtc);
/*
- * intel_opregion.c
- */
-extern int gma_intel_opregion_init(struct drm_device *dev);
-extern int gma_intel_opregion_exit(struct drm_device *dev);
-
-/*
* framebuffer.c
*/
extern int psbfb_probed(struct drm_device *dev);
diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c
index 2616558457c8..36c3c99612f6 100644
--- a/drivers/gpu/drm/gma500/psb_intel_display.c
+++ b/drivers/gpu/drm/gma500/psb_intel_display.c
@@ -337,15 +337,12 @@ static int psb_intel_pipe_set_base(struct drm_crtc *crtc,
int x, int y, struct drm_framebuffer *old_fb)
{
struct drm_device *dev = crtc->dev;
- /* struct drm_i915_master_private *master_priv; */
+ struct drm_psb_private *dev_priv = dev->dev_private;
struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
int pipe = psb_intel_crtc->pipe;
+ const struct psb_offset *map = &dev_priv->regmap[pipe];
unsigned long start, offset;
- int dspbase = (pipe == 0 ? DSPABASE : DSPBBASE);
- int dspsurf = (pipe == 0 ? DSPASURF : DSPBSURF);
- int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE;
- int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
u32 dspcntr;
int ret = 0;
@@ -367,9 +364,9 @@ static int psb_intel_pipe_set_base(struct drm_crtc *crtc,
offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8);
- REG_WRITE(dspstride, crtc->fb->pitches[0]);
+ REG_WRITE(map->stride, crtc->fb->pitches[0]);
- dspcntr = REG_READ(dspcntr_reg);
+ dspcntr = REG_READ(map->cntr);
dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
switch (crtc->fb->bits_per_pixel) {
@@ -392,18 +389,10 @@ static int psb_intel_pipe_set_base(struct drm_crtc *crtc,
psb_gtt_unpin(psbfb->gtt);
goto psb_intel_pipe_set_base_exit;
}
- REG_WRITE(dspcntr_reg, dspcntr);
-
+ REG_WRITE(map->cntr, dspcntr);
- if (0 /* FIXMEAC - check what PSB needs */) {
- REG_WRITE(dspbase, offset);
- REG_READ(dspbase);
- REG_WRITE(dspsurf, start);
- REG_READ(dspsurf);
- } else {
- REG_WRITE(dspbase, start + offset);
- REG_READ(dspbase);
- }
+ REG_WRITE(map->base, start + offset);
+ REG_READ(map->base);
psb_intel_pipe_cleaner:
/* If there was a previous display we can now unpin it */
@@ -424,14 +413,10 @@ psb_intel_pipe_set_base_exit:
static void psb_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
{
struct drm_device *dev = crtc->dev;
- /* struct drm_i915_master_private *master_priv; */
- /* struct drm_i915_private *dev_priv = dev->dev_private; */
+ struct drm_psb_private *dev_priv = dev->dev_private;
struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
int pipe = psb_intel_crtc->pipe;
- int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
- int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
- int dspbase_reg = (pipe == 0) ? DSPABASE : DSPBBASE;
- int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
+ const struct psb_offset *map = &dev_priv->regmap[pipe];
u32 temp;
/* XXX: When our outputs are all unaware of DPMS modes other than off
@@ -442,34 +427,34 @@ static void psb_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
/* Enable the DPLL */
- temp = REG_READ(dpll_reg);
+ temp = REG_READ(map->dpll);
if ((temp & DPLL_VCO_ENABLE) == 0) {
- REG_WRITE(dpll_reg, temp);
- REG_READ(dpll_reg);
+ REG_WRITE(map->dpll, temp);
+ REG_READ(map->dpll);
/* Wait for the clocks to stabilize. */
udelay(150);
- REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
- REG_READ(dpll_reg);
+ REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE);
+ REG_READ(map->dpll);
/* Wait for the clocks to stabilize. */
udelay(150);
- REG_WRITE(dpll_reg, temp | DPLL_VCO_ENABLE);
- REG_READ(dpll_reg);
+ REG_WRITE(map->dpll, temp | DPLL_VCO_ENABLE);
+ REG_READ(map->dpll);
/* Wait for the clocks to stabilize. */
udelay(150);
}
/* Enable the pipe */
- temp = REG_READ(pipeconf_reg);
+ temp = REG_READ(map->conf);
if ((temp & PIPEACONF_ENABLE) == 0)
- REG_WRITE(pipeconf_reg, temp | PIPEACONF_ENABLE);
+ REG_WRITE(map->conf, temp | PIPEACONF_ENABLE);
/* Enable the plane */
- temp = REG_READ(dspcntr_reg);
+ temp = REG_READ(map->cntr);
if ((temp & DISPLAY_PLANE_ENABLE) == 0) {
- REG_WRITE(dspcntr_reg,
+ REG_WRITE(map->cntr,
temp | DISPLAY_PLANE_ENABLE);
/* Flush the plane changes */
- REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
+ REG_WRITE(map->base, REG_READ(map->base));
}
psb_intel_crtc_load_lut(crtc);
@@ -487,29 +472,29 @@ static void psb_intel_crtc_dpms(struct drm_crtc *crtc, int mode)
REG_WRITE(VGACNTRL, VGA_DISP_DISABLE);
/* Disable display plane */
- temp = REG_READ(dspcntr_reg);
+ temp = REG_READ(map->cntr);
if ((temp & DISPLAY_PLANE_ENABLE) != 0) {
- REG_WRITE(dspcntr_reg,
+ REG_WRITE(map->cntr,
temp & ~DISPLAY_PLANE_ENABLE);
/* Flush the plane changes */
- REG_WRITE(dspbase_reg, REG_READ(dspbase_reg));
- REG_READ(dspbase_reg);
+ REG_WRITE(map->base, REG_READ(map->base));
+ REG_READ(map->base);
}
/* Next, disable display pipes */
- temp = REG_READ(pipeconf_reg);
+ temp = REG_READ(map->conf);
if ((temp & PIPEACONF_ENABLE) != 0) {
- REG_WRITE(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
- REG_READ(pipeconf_reg);
+ REG_WRITE(map->conf, temp & ~PIPEACONF_ENABLE);
+ REG_READ(map->conf);
}
/* Wait for vblank for the disable to take effect. */
psb_intel_wait_for_vblank(dev);
- temp = REG_READ(dpll_reg);
+ temp = REG_READ(map->dpll);
if ((temp & DPLL_VCO_ENABLE) != 0) {
- REG_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE);
- REG_READ(dpll_reg);
+ REG_WRITE(map->dpll, temp & ~DPLL_VCO_ENABLE);
+ REG_READ(map->dpll);
}
/* Wait for the clocks to turn off. */
@@ -589,22 +574,11 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
struct drm_framebuffer *old_fb)
{
struct drm_device *dev = crtc->dev;
+ struct drm_psb_private *dev_priv = dev->dev_private;
struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
int pipe = psb_intel_crtc->pipe;
- int fp_reg = (pipe == 0) ? FPA0 : FPB0;
- int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
- int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
- int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
- int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
- int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
- int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
- int vtot_reg = (pipe == 0) ? VTOTAL_A : VTOTAL_B;
- int vblank_reg = (pipe == 0) ? VBLANK_A : VBLANK_B;
- int vsync_reg = (pipe == 0) ? VSYNC_A : VSYNC_B;
- int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE;
- int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS;
- int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
+ const struct psb_offset *map = &dev_priv->regmap[pipe];
int refclk;
struct psb_intel_clock_t clock;
u32 dpll = 0, fp = 0, dspcntr, pipeconf;
@@ -690,7 +664,7 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
dpll |= PLL_REF_INPUT_DREFCLK;
/* setup pipeconf */
- pipeconf = REG_READ(pipeconf_reg);
+ pipeconf = REG_READ(map->conf);
/* Set up the display plane register */
dspcntr = DISPPLANE_GAMMA_ENABLE;
@@ -712,9 +686,9 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
drm_mode_debug_printmodeline(mode);
if (dpll & DPLL_VCO_ENABLE) {
- REG_WRITE(fp_reg, fp);
- REG_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE);
- REG_READ(dpll_reg);
+ REG_WRITE(map->fp0, fp);
+ REG_WRITE(map->dpll, dpll & ~DPLL_VCO_ENABLE);
+ REG_READ(map->dpll);
udelay(150);
}
@@ -747,45 +721,45 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
REG_READ(LVDS);
}
- REG_WRITE(fp_reg, fp);
- REG_WRITE(dpll_reg, dpll);
- REG_READ(dpll_reg);
+ REG_WRITE(map->fp0, fp);
+ REG_WRITE(map->dpll, dpll);
+ REG_READ(map->dpll);
/* Wait for the clocks to stabilize. */
udelay(150);
/* write it again -- the BIOS does, after all */
- REG_WRITE(dpll_reg, dpll);
+ REG_WRITE(map->dpll, dpll);
- REG_READ(dpll_reg);
+ REG_READ(map->dpll);
/* Wait for the clocks to stabilize. */
udelay(150);
- REG_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
+ REG_WRITE(map->htotal, (adjusted_mode->crtc_hdisplay - 1) |
((adjusted_mode->crtc_htotal - 1) << 16));
- REG_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) |
+ REG_WRITE(map->hblank, (adjusted_mode->crtc_hblank_start - 1) |
((adjusted_mode->crtc_hblank_end - 1) << 16));
- REG_WRITE(hsync_reg, (adjusted_mode->crtc_hsync_start - 1) |
+ REG_WRITE(map->hsync, (adjusted_mode->crtc_hsync_start - 1) |
((adjusted_mode->crtc_hsync_end - 1) << 16));
- REG_WRITE(vtot_reg, (adjusted_mode->crtc_vdisplay - 1) |
+ REG_WRITE(map->vtotal, (adjusted_mode->crtc_vdisplay - 1) |
((adjusted_mode->crtc_vtotal - 1) << 16));
- REG_WRITE(vblank_reg, (adjusted_mode->crtc_vblank_start - 1) |
+ REG_WRITE(map->vblank, (adjusted_mode->crtc_vblank_start - 1) |
((adjusted_mode->crtc_vblank_end - 1) << 16));
- REG_WRITE(vsync_reg, (adjusted_mode->crtc_vsync_start - 1) |
+ REG_WRITE(map->vsync, (adjusted_mode->crtc_vsync_start - 1) |
((adjusted_mode->crtc_vsync_end - 1) << 16));
/* pipesrc and dspsize control the size that is scaled from,
* which should always be the user's requested size.
*/
- REG_WRITE(dspsize_reg,
+ REG_WRITE(map->size,
((mode->vdisplay - 1) << 16) | (mode->hdisplay - 1));
- REG_WRITE(dsppos_reg, 0);
- REG_WRITE(pipesrc_reg,
+ REG_WRITE(map->pos, 0);
+ REG_WRITE(map->src,
((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
- REG_WRITE(pipeconf_reg, pipeconf);
- REG_READ(pipeconf_reg);
+ REG_WRITE(map->conf, pipeconf);
+ REG_READ(map->conf);
psb_intel_wait_for_vblank(dev);
- REG_WRITE(dspcntr_reg, dspcntr);
+ REG_WRITE(map->cntr, dspcntr);
/* Flush the plane changes */
crtc_funcs->mode_set_base(crtc, x, y, old_fb);
@@ -799,10 +773,10 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
void psb_intel_crtc_load_lut(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
- struct drm_psb_private *dev_priv =
- (struct drm_psb_private *)dev->dev_private;
+ struct drm_psb_private *dev_priv = dev->dev_private;
struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
- int palreg = PALETTE_A;
+ const struct psb_offset *map = &dev_priv->regmap[psb_intel_crtc->pipe];
+ int palreg = map->palette;
int i;
/* The clocks have to be on to load the palette. */
@@ -811,12 +785,7 @@ void psb_intel_crtc_load_lut(struct drm_crtc *crtc)
switch (psb_intel_crtc->pipe) {
case 0:
- break;
case 1:
- palreg = PALETTE_B;
- break;
- case 2:
- palreg = PALETTE_C;
break;
default:
dev_err(dev->dev, "Illegal Pipe Number.\n");
@@ -836,7 +805,7 @@ void psb_intel_crtc_load_lut(struct drm_crtc *crtc)
gma_power_end(dev);
} else {
for (i = 0; i < 256; i++) {
- dev_priv->regs.psb.save_palette_a[i] =
+ dev_priv->regs.pipe[0].palette[i] =
((psb_intel_crtc->lut_r[i] +
psb_intel_crtc->lut_adj[i]) << 16) |
((psb_intel_crtc->lut_g[i] +
@@ -854,11 +823,10 @@ void psb_intel_crtc_load_lut(struct drm_crtc *crtc)
static void psb_intel_crtc_save(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
- /* struct drm_psb_private *dev_priv =
- (struct drm_psb_private *)dev->dev_private; */
+ struct drm_psb_private *dev_priv = dev->dev_private;
struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
struct psb_intel_crtc_state *crtc_state = psb_intel_crtc->crtc_state;
- int pipeA = (psb_intel_crtc->pipe == 0);
+ const struct psb_offset *map = &dev_priv->regmap[psb_intel_crtc->pipe];
uint32_t paletteReg;
int i;
@@ -867,27 +835,27 @@ static void psb_intel_crtc_save(struct drm_crtc *crtc)
return;
}
- crtc_state->saveDSPCNTR = REG_READ(pipeA ? DSPACNTR : DSPBCNTR);
- crtc_state->savePIPECONF = REG_READ(pipeA ? PIPEACONF : PIPEBCONF);
- crtc_state->savePIPESRC = REG_READ(pipeA ? PIPEASRC : PIPEBSRC);
- crtc_state->saveFP0 = REG_READ(pipeA ? FPA0 : FPB0);
- crtc_state->saveFP1 = REG_READ(pipeA ? FPA1 : FPB1);
- crtc_state->saveDPLL = REG_READ(pipeA ? DPLL_A : DPLL_B);
- crtc_state->saveHTOTAL = REG_READ(pipeA ? HTOTAL_A : HTOTAL_B);
- crtc_state->saveHBLANK = REG_READ(pipeA ? HBLANK_A : HBLANK_B);
- crtc_state->saveHSYNC = REG_READ(pipeA ? HSYNC_A : HSYNC_B);
- crtc_state->saveVTOTAL = REG_READ(pipeA ? VTOTAL_A : VTOTAL_B);
- crtc_state->saveVBLANK = REG_READ(pipeA ? VBLANK_A : VBLANK_B);
- crtc_state->saveVSYNC = REG_READ(pipeA ? VSYNC_A : VSYNC_B);
- crtc_state->saveDSPSTRIDE = REG_READ(pipeA ? DSPASTRIDE : DSPBSTRIDE);
+ crtc_state->saveDSPCNTR = REG_READ(map->cntr);
+ crtc_state->savePIPECONF = REG_READ(map->conf);
+ crtc_state->savePIPESRC = REG_READ(map->src);
+ crtc_state->saveFP0 = REG_READ(map->fp0);
+ crtc_state->saveFP1 = REG_READ(map->fp1);
+ crtc_state->saveDPLL = REG_READ(map->dpll);
+ crtc_state->saveHTOTAL = REG_READ(map->htotal);
+ crtc_state->saveHBLANK = REG_READ(map->hblank);
+ crtc_state->saveHSYNC = REG_READ(map->hsync);
+ crtc_state->saveVTOTAL = REG_READ(map->vtotal);
+ crtc_state->saveVBLANK = REG_READ(map->vblank);
+ crtc_state->saveVSYNC = REG_READ(map->vsync);
+ crtc_state->saveDSPSTRIDE = REG_READ(map->stride);
/*NOTE: DSPSIZE DSPPOS only for psb*/
- crtc_state->saveDSPSIZE = REG_READ(pipeA ? DSPASIZE : DSPBSIZE);
- crtc_state->saveDSPPOS = REG_READ(pipeA ? DSPAPOS : DSPBPOS);
+ crtc_state->saveDSPSIZE = REG_READ(map->size);
+ crtc_state->saveDSPPOS = REG_READ(map->pos);
- crtc_state->saveDSPBASE = REG_READ(pipeA ? DSPABASE : DSPBBASE);
+ crtc_state->saveDSPBASE = REG_READ(map->base);
- paletteReg = pipeA ? PALETTE_A : PALETTE_B;
+ paletteReg = map->palette;
for (i = 0; i < 256; ++i)
crtc_state->savePalette[i] = REG_READ(paletteReg + (i << 2));
}
@@ -898,12 +866,10 @@ static void psb_intel_crtc_save(struct drm_crtc *crtc)
static void psb_intel_crtc_restore(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
- /* struct drm_psb_private * dev_priv =
- (struct drm_psb_private *)dev->dev_private; */
+ struct drm_psb_private *dev_priv = dev->dev_private;
struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
struct psb_intel_crtc_state *crtc_state = psb_intel_crtc->crtc_state;
- /* struct drm_crtc_helper_funcs * crtc_funcs = crtc->helper_private; */
- int pipeA = (psb_intel_crtc->pipe == 0);
+ const struct psb_offset *map = &dev_priv->regmap[psb_intel_crtc->pipe];
uint32_t paletteReg;
int i;
@@ -913,45 +879,45 @@ static void psb_intel_crtc_restore(struct drm_crtc *crtc)
}
if (crtc_state->saveDPLL & DPLL_VCO_ENABLE) {
- REG_WRITE(pipeA ? DPLL_A : DPLL_B,
+ REG_WRITE(map->dpll,
crtc_state->saveDPLL & ~DPLL_VCO_ENABLE);
- REG_READ(pipeA ? DPLL_A : DPLL_B);
+ REG_READ(map->dpll);
udelay(150);
}
- REG_WRITE(pipeA ? FPA0 : FPB0, crtc_state->saveFP0);
- REG_READ(pipeA ? FPA0 : FPB0);
+ REG_WRITE(map->fp0, crtc_state->saveFP0);
+ REG_READ(map->fp0);
- REG_WRITE(pipeA ? FPA1 : FPB1, crtc_state->saveFP1);
- REG_READ(pipeA ? FPA1 : FPB1);
+ REG_WRITE(map->fp1, crtc_state->saveFP1);
+ REG_READ(map->fp1);
- REG_WRITE(pipeA ? DPLL_A : DPLL_B, crtc_state->saveDPLL);
- REG_READ(pipeA ? DPLL_A : DPLL_B);
+ REG_WRITE(map->dpll, crtc_state->saveDPLL);
+ REG_READ(map->dpll);
udelay(150);
- REG_WRITE(pipeA ? HTOTAL_A : HTOTAL_B, crtc_state->saveHTOTAL);
- REG_WRITE(pipeA ? HBLANK_A : HBLANK_B, crtc_state->saveHBLANK);
- REG_WRITE(pipeA ? HSYNC_A : HSYNC_B, crtc_state->saveHSYNC);
- REG_WRITE(pipeA ? VTOTAL_A : VTOTAL_B, crtc_state->saveVTOTAL);
- REG_WRITE(pipeA ? VBLANK_A : VBLANK_B, crtc_state->saveVBLANK);
- REG_WRITE(pipeA ? VSYNC_A : VSYNC_B, crtc_state->saveVSYNC);
- REG_WRITE(pipeA ? DSPASTRIDE : DSPBSTRIDE, crtc_state->saveDSPSTRIDE);
+ REG_WRITE(map->htotal, crtc_state->saveHTOTAL);
+ REG_WRITE(map->hblank, crtc_state->saveHBLANK);
+ REG_WRITE(map->hsync, crtc_state->saveHSYNC);
+ REG_WRITE(map->vtotal, crtc_state->saveVTOTAL);
+ REG_WRITE(map->vblank, crtc_state->saveVBLANK);
+ REG_WRITE(map->vsync, crtc_state->saveVSYNC);
+ REG_WRITE(map->stride, crtc_state->saveDSPSTRIDE);
- REG_WRITE(pipeA ? DSPASIZE : DSPBSIZE, crtc_state->saveDSPSIZE);
- REG_WRITE(pipeA ? DSPAPOS : DSPBPOS, crtc_state->saveDSPPOS);
+ REG_WRITE(map->size, crtc_state->saveDSPSIZE);
+ REG_WRITE(map->pos, crtc_state->saveDSPPOS);
- REG_WRITE(pipeA ? PIPEASRC : PIPEBSRC, crtc_state->savePIPESRC);
- REG_WRITE(pipeA ? DSPABASE : DSPBBASE, crtc_state->saveDSPBASE);
- REG_WRITE(pipeA ? PIPEACONF : PIPEBCONF, crtc_state->savePIPECONF);
+ REG_WRITE(map->src, crtc_state->savePIPESRC);
+ REG_WRITE(map->base, crtc_state->saveDSPBASE);
+ REG_WRITE(map->conf, crtc_state->savePIPECONF);
psb_intel_wait_for_vblank(dev);
- REG_WRITE(pipeA ? DSPACNTR : DSPBCNTR, crtc_state->saveDSPCNTR);
- REG_WRITE(pipeA ? DSPABASE : DSPBBASE, crtc_state->saveDSPBASE);
+ REG_WRITE(map->cntr, crtc_state->saveDSPCNTR);
+ REG_WRITE(map->base, crtc_state->saveDSPBASE);
psb_intel_wait_for_vblank(dev);
- paletteReg = pipeA ? PALETTE_A : PALETTE_B;
+ paletteReg = map->palette;
for (i = 0; i < 256; ++i)
REG_WRITE(paletteReg + (i << 2), crtc_state->savePalette[i]);
}
@@ -962,6 +928,7 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc,
uint32_t width, uint32_t height)
{
struct drm_device *dev = crtc->dev;
+ struct drm_psb_private *dev_priv = dev->dev_private;
struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
int pipe = psb_intel_crtc->pipe;
uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR;
@@ -969,8 +936,10 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc,
uint32_t temp;
size_t addr = 0;
struct gtt_range *gt;
+ struct gtt_range *cursor_gt = psb_intel_crtc->cursor_gt;
struct drm_gem_object *obj;
- int ret;
+ void *tmp_dst, *tmp_src;
+ int ret, i, cursor_pages;
/* if we want to turn of the cursor ignore width and height */
if (!handle) {
@@ -1019,10 +988,32 @@ static int psb_intel_crtc_cursor_set(struct drm_crtc *crtc,
return ret;
}
+ if (dev_priv->ops->cursor_needs_phys) {
+ if (cursor_gt == NULL) {
+ dev_err(dev->dev, "No hardware cursor mem available");
+ return -ENOMEM;
+ }
- addr = gt->offset; /* Or resource.start ??? */
+ /* Prevent overflow */
+ if (gt->npage > 4)
+ cursor_pages = 4;
+ else
+ cursor_pages = gt->npage;
+
+ /* Copy the cursor to cursor mem */
+ tmp_dst = dev_priv->vram_addr + cursor_gt->offset;
+ for (i = 0; i < cursor_pages; i++) {
+ tmp_src = kmap(gt->pages[i]);
+ memcpy(tmp_dst, tmp_src, PAGE_SIZE);
+ kunmap(gt->pages[i]);
+ tmp_dst += PAGE_SIZE;
+ }
- psb_intel_crtc->cursor_addr = addr;
+ addr = psb_intel_crtc->cursor_addr;
+ } else {
+ addr = gt->offset; /* Or resource.start ??? */
+ psb_intel_crtc->cursor_addr = addr;
+ }
temp = 0;
/* set the pipe for the cursor */
@@ -1115,34 +1106,30 @@ static int psb_intel_crtc_clock_get(struct drm_device *dev,
struct drm_crtc *crtc)
{
struct psb_intel_crtc *psb_intel_crtc = to_psb_intel_crtc(crtc);
+ struct drm_psb_private *dev_priv = dev->dev_private;
int pipe = psb_intel_crtc->pipe;
+ const struct psb_offset *map = &dev_priv->regmap[pipe];
u32 dpll;
u32 fp;
struct psb_intel_clock_t clock;
bool is_lvds;
- struct drm_psb_private *dev_priv = dev->dev_private;
+ struct psb_pipe *p = &dev_priv->regs.pipe[pipe];
if (gma_power_begin(dev, false)) {
- dpll = REG_READ((pipe == 0) ? DPLL_A : DPLL_B);
+ dpll = REG_READ(map->dpll);
if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0)
- fp = REG_READ((pipe == 0) ? FPA0 : FPB0);
+ fp = REG_READ(map->fp0);
else
- fp = REG_READ((pipe == 0) ? FPA1 : FPB1);
+ fp = REG_READ(map->fp1);
is_lvds = (pipe == 1) && (REG_READ(LVDS) & LVDS_PORT_EN);
gma_power_end(dev);
} else {
- dpll = (pipe == 0) ?
- dev_priv->regs.psb.saveDPLL_A :
- dev_priv->regs.psb.saveDPLL_B;
+ dpll = p->dpll;
if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0)
- fp = (pipe == 0) ?
- dev_priv->regs.psb.saveFPA0 :
- dev_priv->regs.psb.saveFPB0;
+ fp = p->fp0;
else
- fp = (pipe == 0) ?
- dev_priv->regs.psb.saveFPA1 :
- dev_priv->regs.psb.saveFPB1;
+ fp = p->fp1;
is_lvds = (pipe == 1) && (dev_priv->regs.psb.saveLVDS &
LVDS_PORT_EN);
@@ -1202,26 +1189,20 @@ struct drm_display_mode *psb_intel_crtc_mode_get(struct drm_device *dev,
int vtot;
int vsync;
struct drm_psb_private *dev_priv = dev->dev_private;
+ struct psb_pipe *p = &dev_priv->regs.pipe[pipe];
+ const struct psb_offset *map = &dev_priv->regmap[pipe];
if (gma_power_begin(dev, false)) {
- htot = REG_READ((pipe == 0) ? HTOTAL_A : HTOTAL_B);
- hsync = REG_READ((pipe == 0) ? HSYNC_A : HSYNC_B);
- vtot = REG_READ((pipe == 0) ? VTOTAL_A : VTOTAL_B);
- vsync = REG_READ((pipe == 0) ? VSYNC_A : VSYNC_B);
+ htot = REG_READ(map->htotal);
+ hsync = REG_READ(map->hsync);
+ vtot = REG_READ(map->vtotal);
+ vsync = REG_READ(map->vsync);
gma_power_end(dev);
} else {
- htot = (pipe == 0) ?
- dev_priv->regs.psb.saveHTOTAL_A :
- dev_priv->regs.psb.saveHTOTAL_B;
- hsync = (pipe == 0) ?
- dev_priv->regs.psb.saveHSYNC_A :
- dev_priv->regs.psb.saveHSYNC_B;
- vtot = (pipe == 0) ?
- dev_priv->regs.psb.saveVTOTAL_A :
- dev_priv->regs.psb.saveVTOTAL_B;
- vsync = (pipe == 0) ?
- dev_priv->regs.psb.saveVSYNC_A :
- dev_priv->regs.psb.saveVSYNC_B;
+ htot = p->htotal;
+ hsync = p->hsync;
+ vtot = p->vtotal;
+ vsync = p->vsync;
}
mode = kzalloc(sizeof(*mode), GFP_KERNEL);
@@ -1257,6 +1238,9 @@ void psb_intel_crtc_destroy(struct drm_crtc *crtc)
drm_gem_object_unreference(psb_intel_crtc->cursor_obj);
psb_intel_crtc->cursor_obj = NULL;
}
+
+ if (psb_intel_crtc->cursor_gt != NULL)
+ psb_gtt_free_range(crtc->dev, psb_intel_crtc->cursor_gt);
kfree(psb_intel_crtc->crtc_state);
drm_crtc_cleanup(crtc);
kfree(psb_intel_crtc);
@@ -1285,13 +1269,33 @@ const struct drm_crtc_funcs psb_intel_crtc_funcs = {
* Set the default value of cursor control and base register
* to zero. This is a workaround for h/w defect on Oaktrail
*/
-static void psb_intel_cursor_init(struct drm_device *dev, int pipe)
+static void psb_intel_cursor_init(struct drm_device *dev,
+ struct psb_intel_crtc *psb_intel_crtc)
{
+ struct drm_psb_private *dev_priv = dev->dev_private;
u32 control[3] = { CURACNTR, CURBCNTR, CURCCNTR };
u32 base[3] = { CURABASE, CURBBASE, CURCBASE };
+ struct gtt_range *cursor_gt;
+
+ if (dev_priv->ops->cursor_needs_phys) {
+ /* Allocate 4 pages of stolen mem for a hardware cursor. That
+ * is enough for the 64 x 64 ARGB cursors we support.
+ */
+ cursor_gt = psb_gtt_alloc_range(dev, 4 * PAGE_SIZE, "cursor", 1);
+ if (!cursor_gt) {
+ psb_intel_crtc->cursor_gt = NULL;
+ goto out;
+ }
+ psb_intel_crtc->cursor_gt = cursor_gt;
+ psb_intel_crtc->cursor_addr = dev_priv->stolen_base +
+ cursor_gt->offset;
+ } else {
+ psb_intel_crtc->cursor_gt = NULL;
+ }
- REG_WRITE(control[pipe], 0);
- REG_WRITE(base[pipe], 0);
+out:
+ REG_WRITE(control[psb_intel_crtc->pipe], 0);
+ REG_WRITE(base[psb_intel_crtc->pipe], 0);
}
void psb_intel_crtc_init(struct drm_device *dev, int pipe,
@@ -1357,7 +1361,7 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe,
psb_intel_crtc->mode_set.connectors =
(struct drm_connector **) (psb_intel_crtc + 1);
psb_intel_crtc->mode_set.num_connectors = 0;
- psb_intel_cursor_init(dev, pipe);
+ psb_intel_cursor_init(dev, psb_intel_crtc);
}
int psb_intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h
index f40535e56689..2515f83248cb 100644
--- a/drivers/gpu/drm/gma500/psb_intel_drv.h
+++ b/drivers/gpu/drm/gma500/psb_intel_drv.h
@@ -106,11 +106,6 @@ struct psb_intel_mode_device {
size_t(*bo_offset) (struct drm_device *dev, void *bo);
/*
- * Cursor (Can go ?)
- */
- int cursor_needs_physical;
-
- /*
* LVDS info
*/
int backlight_duty_cycle; /* restore backlight to this value */
@@ -176,6 +171,7 @@ struct psb_intel_crtc {
int pipe;
int plane;
uint32_t cursor_addr;
+ struct gtt_range *cursor_gt;
u8 lut_r[256], lut_g[256], lut_b[256];
u8 lut_adj[256];
struct psb_intel_framebuffer *fbdev_fb;
@@ -193,6 +189,9 @@ struct psb_intel_crtc {
/*crtc mode setting flags*/
u32 mode_flags;
+ bool active;
+ bool crtc_enable;
+
/* Saved Crtc HW states */
struct psb_intel_crtc_state *crtc_state;
};
diff --git a/drivers/gpu/drm/gma500/psb_intel_reg.h b/drivers/gpu/drm/gma500/psb_intel_reg.h
index e89d3a2e8fdc..8e8c8efb0a89 100644
--- a/drivers/gpu/drm/gma500/psb_intel_reg.h
+++ b/drivers/gpu/drm/gma500/psb_intel_reg.h
@@ -91,6 +91,9 @@
#define BLC_PWM_CTL 0x61254
#define BLC_PWM_CTL2 0x61250
+#define PWM_ENABLE (1 << 31)
+#define PWM_LEGACY_MODE (1 << 30)
+#define PWM_PIPE_B (1 << 29)
#define BLC_PWM_CTL_C 0x62254
#define BLC_PWM_CTL2_C 0x62250
#define BACKLIGHT_MODULATION_FREQ_SHIFT (17)
@@ -216,7 +219,7 @@
#define DPLLB_LVDS_P2_CLOCK_DIV_14 (0 << 24) /* i915 */
#define DPLLB_LVDS_P2_CLOCK_DIV_7 (1 << 24) /* i915 */
#define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */
-#define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */
+#define DPLL_FPA0h1_P1_POST_DIV_MASK 0x00ff0000 /* i915 */
#define DPLL_LOCK (1 << 15) /* CDV */
/*
@@ -343,6 +346,9 @@
#define FP_M2_DIV_SHIFT 0
#define PORT_HOTPLUG_EN 0x61110
+#define HDMIB_HOTPLUG_INT_EN (1 << 29)
+#define HDMIC_HOTPLUG_INT_EN (1 << 28)
+#define HDMID_HOTPLUG_INT_EN (1 << 27)
#define SDVOB_HOTPLUG_INT_EN (1 << 26)
#define SDVOC_HOTPLUG_INT_EN (1 << 25)
#define TV_HOTPLUG_INT_EN (1 << 18)
@@ -501,10 +507,12 @@
#define PIPE_VBLANK_INTERRUPT_ENABLE (1UL << 17)
#define PIPE_START_VBLANK_INTERRUPT_ENABLE (1UL << 18)
#define PIPE_TE_ENABLE (1UL << 22)
+#define PIPE_LEGACY_BLC_EVENT_ENABLE (1UL << 22)
#define PIPE_DPST_EVENT_ENABLE (1UL << 23)
#define PIPE_VSYNC_ENABL (1UL << 25)
#define PIPE_HDMI_AUDIO_UNDERRUN (1UL << 26)
#define PIPE_HDMI_AUDIO_BUFFER_DONE (1UL << 27)
+#define PIPE_FIFO_UNDERRUN (1UL << 31)
#define PIPE_HDMI_AUDIO_INT_MASK (PIPE_HDMI_AUDIO_UNDERRUN | \
PIPE_HDMI_AUDIO_BUFFER_DONE)
#define PIPE_EVENT_MASK ((1 << 29)|(1 << 28)|(1 << 27)|(1 << 26)|(1 << 24)|(1 << 23)|(1 << 22)|(1 << 21)|(1 << 20)|(1 << 16))
@@ -569,12 +577,27 @@ struct dpst_guardband {
#define PIPE_PIXEL_MASK 0x00ffffff
#define PIPE_PIXEL_SHIFT 0
+#define FW_BLC_SELF 0x20e0
+#define FW_BLC_SELF_EN (1<<15)
+
#define DSPARB 0x70030
#define DSPFW1 0x70034
+#define DSP_FIFO_SR_WM_MASK 0xFF800000
+#define DSP_FIFO_SR_WM_SHIFT 23
+#define CURSOR_B_FIFO_WM_MASK 0x003F0000
+#define CURSOR_B_FIFO_WM_SHIFT 16
#define DSPFW2 0x70038
+#define CURSOR_A_FIFO_WM_MASK 0x3F00
+#define CURSOR_A_FIFO_WM_SHIFT 8
+#define DSP_PLANE_C_FIFO_WM_MASK 0x7F
+#define DSP_PLANE_C_FIFO_WM_SHIFT 0
#define DSPFW3 0x7003c
#define DSPFW4 0x70050
#define DSPFW5 0x70054
+#define DSP_PLANE_B_FIFO_WM1_SHIFT 24
+#define DSP_PLANE_A_FIFO_WM1_SHIFT 16
+#define CURSOR_B_FIFO_WM1_SHIFT 8
+#define CURSOR_FIFO_SR_WM1_SHIFT 0
#define DSPFW6 0x70058
#define DSPCHICKENBIT 0x70400
#define DSPACNTR 0x70180
@@ -1290,6 +1313,15 @@ No status bits are changed.
#define SB_N_CB_TUNE_MASK PSB_MASK(25, 24)
#define SB_N_CB_TUNE_SHIFT 24
+/* the bit 14:13 is used to select between the different reference clock for Pipe A/B */
+#define SB_REF_DPLLA 0x8010
+#define SB_REF_DPLLB 0x8030
+#define REF_CLK_MASK (0x3 << 13)
+#define REF_CLK_CORE (0 << 13)
+#define REF_CLK_DPLL (1 << 13)
+#define REF_CLK_DPLLA (2 << 13)
+/* For the DPLL B, it will use the reference clk from DPLL A when using (2 << 13) */
+
#define _SB_REF_A 0x8018
#define _SB_REF_B 0x8038
#define SB_REF_SFR(pipe) _PIPE(pipe, _SB_REF_A, _SB_REF_B)
@@ -1313,6 +1345,7 @@ No status bits are changed.
#define LANE_PLL_MASK (0x7 << 20)
#define LANE_PLL_ENABLE (0x3 << 20)
+#define LANE_PLL_PIPE(p) (((p) == 0) ? (1 << 21) : (0 << 21))
#endif
diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
index 36330cabcea2..d39b15be7649 100644
--- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c
+++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c
@@ -1141,7 +1141,6 @@ static void psb_intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
static int psb_intel_sdvo_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
- struct drm_psb_private *dev_priv = connector->dev->dev_private;
struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector);
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
@@ -1161,11 +1160,6 @@ static int psb_intel_sdvo_mode_valid(struct drm_connector *connector,
return MODE_PANEL;
}
- /* We assume worst case scenario of 32 bpp here, since we don't know */
- if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) >
- dev_priv->vram_stolen_size)
- return MODE_MEM;
-
return MODE_OK;
}
@@ -2044,8 +2038,7 @@ psb_intel_sdvo_add_hdmi_properties(struct psb_intel_sdvo_connector *connector)
struct drm_device *dev = connector->base.base.dev;
intel_attach_force_audio_property(&connector->base.base);
- if (INTEL_INFO(dev)->gen >= 4 && IS_MOBILE(dev))
- intel_attach_broadcast_rgb_property(&connector->base.base);
+ intel_attach_broadcast_rgb_property(&connector->base.base);
*/
}
diff --git a/drivers/gpu/drm/gma500/psb_irq.c b/drivers/gpu/drm/gma500/psb_irq.c
index 1869586457b1..8652cdf3f03f 100644
--- a/drivers/gpu/drm/gma500/psb_irq.c
+++ b/drivers/gpu/drm/gma500/psb_irq.c
@@ -190,6 +190,9 @@ static void mid_pipe_event_handler(struct drm_device *dev, int pipe)
*/
static void psb_vdc_interrupt(struct drm_device *dev, uint32_t vdc_stat)
{
+ if (vdc_stat & _PSB_IRQ_ASLE)
+ psb_intel_opregion_asle_intr(dev);
+
if (vdc_stat & _PSB_VSYNC_PIPEA_FLAG)
mid_pipe_event_handler(dev, 0);
@@ -199,11 +202,9 @@ static void psb_vdc_interrupt(struct drm_device *dev, uint32_t vdc_stat)
irqreturn_t psb_irq_handler(DRM_IRQ_ARGS)
{
- struct drm_device *dev = (struct drm_device *) arg;
- struct drm_psb_private *dev_priv =
- (struct drm_psb_private *) dev->dev_private;
-
- uint32_t vdc_stat, dsp_int = 0, sgx_int = 0;
+ struct drm_device *dev = arg;
+ struct drm_psb_private *dev_priv = dev->dev_private;
+ uint32_t vdc_stat, dsp_int = 0, sgx_int = 0, hotplug_int = 0;
int handled = 0;
spin_lock(&dev_priv->irqmask_lock);
@@ -220,6 +221,8 @@ irqreturn_t psb_irq_handler(DRM_IRQ_ARGS)
if (vdc_stat & _PSB_IRQ_SGX_FLAG)
sgx_int = 1;
+ if (vdc_stat & _PSB_IRQ_DISP_HOTSYNC)
+ hotplug_int = 1;
vdc_stat &= dev_priv->vdc_irq_mask;
spin_unlock(&dev_priv->irqmask_lock);
@@ -241,6 +244,13 @@ irqreturn_t psb_irq_handler(DRM_IRQ_ARGS)
handled = 1;
}
+ /* Note: this bit has other meanings on some devices, so we will
+ need to address that later if it ever matters */
+ if (hotplug_int && dev_priv->ops->hotplug) {
+ handled = dev_priv->ops->hotplug(dev);
+ REG_WRITE(PORT_HOTPLUG_STAT, REG_READ(PORT_HOTPLUG_STAT));
+ }
+
PSB_WVDC32(vdc_stat, PSB_INT_IDENTITY_R);
(void) PSB_RVDC32(PSB_INT_IDENTITY_R);
DRM_READMEMORYBARRIER();
@@ -273,6 +283,11 @@ void psb_irq_preinstall(struct drm_device *dev)
dev_priv->vdc_irq_mask |= _MDFLD_PIPEC_EVENT_FLAG;
*/
+ /* Revisit this area - want per device masks ? */
+ if (dev_priv->ops->hotplug)
+ dev_priv->vdc_irq_mask |= _PSB_IRQ_DISP_HOTSYNC;
+ dev_priv->vdc_irq_mask |= _PSB_IRQ_ASLE;
+
/* This register is safe even if display island is off */
PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R);
spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
@@ -305,18 +320,23 @@ int psb_irq_postinstall(struct drm_device *dev)
else
psb_disable_pipestat(dev_priv, 2, PIPE_VBLANK_INTERRUPT_ENABLE);
+ if (dev_priv->ops->hotplug_enable)
+ dev_priv->ops->hotplug_enable(dev, true);
+
spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
return 0;
}
void psb_irq_uninstall(struct drm_device *dev)
{
- struct drm_psb_private *dev_priv =
- (struct drm_psb_private *) dev->dev_private;
+ struct drm_psb_private *dev_priv = dev->dev_private;
unsigned long irqflags;
spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
+ if (dev_priv->ops->hotplug_enable)
+ dev_priv->ops->hotplug_enable(dev, false);
+
PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM);
if (dev->vblank_enabled[0])
@@ -406,7 +426,7 @@ void psb_irq_turn_off_dpst(struct drm_device *dev)
psb_disable_pipestat(dev_priv, 0, PIPE_DPST_EVENT_ENABLE);
pwm_reg = PSB_RVDC32(PWM_CONTROL_LOGIC);
- PSB_WVDC32(pwm_reg & !(PWM_PHASEIN_INT_ENABLE),
+ PSB_WVDC32(pwm_reg & ~PWM_PHASEIN_INT_ENABLE,
PWM_CONTROL_LOGIC);
pwm_reg = PSB_RVDC32(PWM_CONTROL_LOGIC);
diff --git a/drivers/gpu/drm/gma500/psb_lid.c b/drivers/gpu/drm/gma500/psb_lid.c
index b867aabe6bf3..1d2ebb5e530f 100644
--- a/drivers/gpu/drm/gma500/psb_lid.c
+++ b/drivers/gpu/drm/gma500/psb_lid.c
@@ -29,7 +29,7 @@ static void psb_lid_timer_func(unsigned long data)
struct drm_device *dev = (struct drm_device *)dev_priv->dev;
struct timer_list *lid_timer = &dev_priv->lid_timer;
unsigned long irq_flags;
- u32 *lid_state = dev_priv->lid_state;
+ u32 __iomem *lid_state = dev_priv->opregion.lid_state;
u32 pp_status;
if (readl(lid_state) == dev_priv->lid_last_state)
@@ -40,10 +40,16 @@ static void psb_lid_timer_func(unsigned long data)
REG_WRITE(PP_CONTROL, REG_READ(PP_CONTROL) | POWER_TARGET_ON);
do {
pp_status = REG_READ(PP_STATUS);
- } while ((pp_status & PP_ON) == 0);
+ } while ((pp_status & PP_ON) == 0 &&
+ (pp_status & PP_SEQUENCE_MASK) != 0);
- /*FIXME: should be backlight level before*/
- psb_intel_lvds_set_brightness(dev, 100);
+ if (REG_READ(PP_STATUS) & PP_ON) {
+ /*FIXME: should be backlight level before*/
+ psb_intel_lvds_set_brightness(dev, 100);
+ } else {
+ DRM_DEBUG("LVDS panel never powered up");
+ return;
+ }
} else {
psb_intel_lvds_set_brightness(dev, 0);
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index ce7fc77678b4..2e9268da58d8 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -11,17 +11,21 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \
i915_gem_evict.o \
i915_gem_execbuffer.o \
i915_gem_gtt.o \
+ i915_gem_stolen.o \
i915_gem_tiling.o \
+ i915_sysfs.o \
i915_trace_points.o \
intel_display.o \
intel_crt.o \
intel_lvds.o \
intel_bios.o \
+ intel_ddi.o \
intel_dp.o \
intel_hdmi.o \
intel_sdvo.o \
intel_modes.o \
intel_panel.o \
+ intel_pm.o \
intel_i2c.o \
intel_fb.o \
intel_tv.o \
@@ -34,7 +38,8 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \
dvo_ch7017.o \
dvo_ivch.o \
dvo_tfp410.o \
- dvo_sil164.o
+ dvo_sil164.o \
+ i915_gem_dmabuf.o
i915-$(CONFIG_COMPAT) += i915_ioc32.o
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index e6162a1681f0..eb2b3c25b9e1 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -47,7 +47,6 @@ enum {
FLUSHING_LIST,
INACTIVE_LIST,
PINNED_LIST,
- DEFERRED_FREE_LIST,
};
static const char *yesno(int v)
@@ -178,18 +177,10 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
seq_printf(m, "Inactive:\n");
head = &dev_priv->mm.inactive_list;
break;
- case PINNED_LIST:
- seq_printf(m, "Pinned:\n");
- head = &dev_priv->mm.pinned_list;
- break;
case FLUSHING_LIST:
seq_printf(m, "Flushing:\n");
head = &dev_priv->mm.flushing_list;
break;
- case DEFERRED_FREE_LIST:
- seq_printf(m, "Deferred free:\n");
- head = &dev_priv->mm.deferred_free_list;
- break;
default:
mutex_unlock(&dev->struct_mutex);
return -EINVAL;
@@ -252,21 +243,11 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
count, mappable_count, size, mappable_size);
size = count = mappable_size = mappable_count = 0;
- count_objects(&dev_priv->mm.pinned_list, mm_list);
- seq_printf(m, " %u [%u] pinned objects, %zu [%zu] bytes\n",
- count, mappable_count, size, mappable_size);
-
- size = count = mappable_size = mappable_count = 0;
count_objects(&dev_priv->mm.inactive_list, mm_list);
seq_printf(m, " %u [%u] inactive objects, %zu [%zu] bytes\n",
count, mappable_count, size, mappable_size);
size = count = mappable_size = mappable_count = 0;
- count_objects(&dev_priv->mm.deferred_free_list, mm_list);
- seq_printf(m, " %u [%u] freed objects, %zu [%zu] bytes\n",
- count, mappable_count, size, mappable_size);
-
- size = count = mappable_size = mappable_count = 0;
list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
if (obj->fault_mappable) {
size += obj->gtt_space->size;
@@ -294,6 +275,7 @@ static int i915_gem_gtt_info(struct seq_file *m, void* data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
+ uintptr_t list = (uintptr_t) node->info_ent->data;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj;
size_t total_obj_size, total_gtt_size;
@@ -305,6 +287,9 @@ static int i915_gem_gtt_info(struct seq_file *m, void* data)
total_obj_size = total_gtt_size = count = 0;
list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
+ if (list == PINNED_LIST && obj->pin_count == 0)
+ continue;
+
seq_printf(m, " ");
describe_obj(m, obj);
seq_printf(m, "\n");
@@ -321,7 +306,6 @@ static int i915_gem_gtt_info(struct seq_file *m, void* data)
return 0;
}
-
static int i915_gem_pageflip_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -430,10 +414,6 @@ static void i915_ring_seqno_info(struct seq_file *m,
if (ring->get_seqno) {
seq_printf(m, "Current sequence (%s): %d\n",
ring->name, ring->get_seqno(ring));
- seq_printf(m, "Waiter sequence (%s): %d\n",
- ring->name, ring->waiting_seqno);
- seq_printf(m, "IRQ sequence (%s): %d\n",
- ring->name, ring->irq_seqno);
}
}
@@ -468,7 +448,45 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
if (ret)
return ret;
- if (!HAS_PCH_SPLIT(dev)) {
+ if (IS_VALLEYVIEW(dev)) {
+ seq_printf(m, "Display IER:\t%08x\n",
+ I915_READ(VLV_IER));
+ seq_printf(m, "Display IIR:\t%08x\n",
+ I915_READ(VLV_IIR));
+ seq_printf(m, "Display IIR_RW:\t%08x\n",
+ I915_READ(VLV_IIR_RW));
+ seq_printf(m, "Display IMR:\t%08x\n",
+ I915_READ(VLV_IMR));
+ for_each_pipe(pipe)
+ seq_printf(m, "Pipe %c stat:\t%08x\n",
+ pipe_name(pipe),
+ I915_READ(PIPESTAT(pipe)));
+
+ seq_printf(m, "Master IER:\t%08x\n",
+ I915_READ(VLV_MASTER_IER));
+
+ seq_printf(m, "Render IER:\t%08x\n",
+ I915_READ(GTIER));
+ seq_printf(m, "Render IIR:\t%08x\n",
+ I915_READ(GTIIR));
+ seq_printf(m, "Render IMR:\t%08x\n",
+ I915_READ(GTIMR));
+
+ seq_printf(m, "PM IER:\t\t%08x\n",
+ I915_READ(GEN6_PMIER));
+ seq_printf(m, "PM IIR:\t\t%08x\n",
+ I915_READ(GEN6_PMIIR));
+ seq_printf(m, "PM IMR:\t\t%08x\n",
+ I915_READ(GEN6_PMIMR));
+
+ seq_printf(m, "Port hotplug:\t%08x\n",
+ I915_READ(PORT_HOTPLUG_EN));
+ seq_printf(m, "DPFLIPSTAT:\t%08x\n",
+ I915_READ(VLV_DPFLIPSTAT));
+ seq_printf(m, "DPINVGTT:\t%08x\n",
+ I915_READ(DPINVGTT));
+
+ } else if (!HAS_PCH_SPLIT(dev)) {
seq_printf(m, "Interrupt enable: %08x\n",
I915_READ(IER));
seq_printf(m, "Interrupt identity: %08x\n",
@@ -564,69 +582,6 @@ static int i915_hws_info(struct seq_file *m, void *data)
return 0;
}
-static int i915_ringbuffer_data(struct seq_file *m, void *data)
-{
- struct drm_info_node *node = (struct drm_info_node *) m->private;
- struct drm_device *dev = node->minor->dev;
- drm_i915_private_t *dev_priv = dev->dev_private;
- struct intel_ring_buffer *ring;
- int ret;
-
- ret = mutex_lock_interruptible(&dev->struct_mutex);
- if (ret)
- return ret;
-
- ring = &dev_priv->ring[(uintptr_t)node->info_ent->data];
- if (!ring->obj) {
- seq_printf(m, "No ringbuffer setup\n");
- } else {
- const u8 __iomem *virt = ring->virtual_start;
- uint32_t off;
-
- for (off = 0; off < ring->size; off += 4) {
- uint32_t *ptr = (uint32_t *)(virt + off);
- seq_printf(m, "%08x : %08x\n", off, *ptr);
- }
- }
- mutex_unlock(&dev->struct_mutex);
-
- return 0;
-}
-
-static int i915_ringbuffer_info(struct seq_file *m, void *data)
-{
- struct drm_info_node *node = (struct drm_info_node *) m->private;
- struct drm_device *dev = node->minor->dev;
- drm_i915_private_t *dev_priv = dev->dev_private;
- struct intel_ring_buffer *ring;
- int ret;
-
- ring = &dev_priv->ring[(uintptr_t)node->info_ent->data];
- if (ring->size == 0)
- return 0;
-
- ret = mutex_lock_interruptible(&dev->struct_mutex);
- if (ret)
- return ret;
-
- seq_printf(m, "Ring %s:\n", ring->name);
- seq_printf(m, " Head : %08x\n", I915_READ_HEAD(ring) & HEAD_ADDR);
- seq_printf(m, " Tail : %08x\n", I915_READ_TAIL(ring) & TAIL_ADDR);
- seq_printf(m, " Size : %08x\n", ring->size);
- seq_printf(m, " Active : %08x\n", intel_ring_get_active_head(ring));
- seq_printf(m, " NOPID : %08x\n", I915_READ_NOPID(ring));
- if (IS_GEN6(dev) || IS_GEN7(dev)) {
- seq_printf(m, " Sync 0 : %08x\n", I915_READ_SYNC_0(ring));
- seq_printf(m, " Sync 1 : %08x\n", I915_READ_SYNC_1(ring));
- }
- seq_printf(m, " Control : %08x\n", I915_READ_CTL(ring));
- seq_printf(m, " Start : %08x\n", I915_READ_START(ring));
-
- mutex_unlock(&dev->struct_mutex);
-
- return 0;
-}
-
static const char *ring_str(int ring)
{
switch (ring) {
@@ -704,6 +659,7 @@ static void i915_ring_error_state(struct seq_file *m,
struct drm_i915_error_state *error,
unsigned ring)
{
+ BUG_ON(ring >= I915_NUM_RINGS); /* shut up confused gcc */
seq_printf(m, "%s command stream:\n", ring_str(ring));
seq_printf(m, " HEAD: 0x%08x\n", error->head[ring]);
seq_printf(m, " TAIL: 0x%08x\n", error->tail[ring]);
@@ -718,8 +674,8 @@ static void i915_ring_error_state(struct seq_file *m,
if (INTEL_INFO(dev)->gen >= 4)
seq_printf(m, " INSTPS: 0x%08x\n", error->instps[ring]);
seq_printf(m, " INSTPM: 0x%08x\n", error->instpm[ring]);
+ seq_printf(m, " FADDR: 0x%08x\n", error->faddr[ring]);
if (INTEL_INFO(dev)->gen >= 6) {
- seq_printf(m, " FADDR: 0x%08x\n", error->faddr[ring]);
seq_printf(m, " FAULT_REG: 0x%08x\n", error->fault_reg[ring]);
seq_printf(m, " SYNC_0: 0x%08x\n",
error->semaphore_mboxes[ring][0]);
@@ -727,31 +683,35 @@ static void i915_ring_error_state(struct seq_file *m,
error->semaphore_mboxes[ring][1]);
}
seq_printf(m, " seqno: 0x%08x\n", error->seqno[ring]);
+ seq_printf(m, " waiting: %s\n", yesno(error->waiting[ring]));
seq_printf(m, " ring->head: 0x%08x\n", error->cpu_ring_head[ring]);
seq_printf(m, " ring->tail: 0x%08x\n", error->cpu_ring_tail[ring]);
}
+struct i915_error_state_file_priv {
+ struct drm_device *dev;
+ struct drm_i915_error_state *error;
+};
+
static int i915_error_state(struct seq_file *m, void *unused)
{
- struct drm_info_node *node = (struct drm_info_node *) m->private;
- struct drm_device *dev = node->minor->dev;
+ struct i915_error_state_file_priv *error_priv = m->private;
+ struct drm_device *dev = error_priv->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_error_state *error;
- unsigned long flags;
+ struct drm_i915_error_state *error = error_priv->error;
+ struct intel_ring_buffer *ring;
int i, j, page, offset, elt;
- spin_lock_irqsave(&dev_priv->error_lock, flags);
- if (!dev_priv->first_error) {
+ if (!error) {
seq_printf(m, "no error state collected\n");
- goto out;
+ return 0;
}
- error = dev_priv->first_error;
-
seq_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec,
error->time.tv_usec);
seq_printf(m, "PCI ID: 0x%04x\n", dev->pci_device);
seq_printf(m, "EIR: 0x%08x\n", error->eir);
+ seq_printf(m, "IER: 0x%08x\n", error->ier);
seq_printf(m, "PGTBL_ER: 0x%08x\n", error->pgtbl_er);
for (i = 0; i < dev_priv->num_fence_regs; i++)
@@ -762,11 +722,8 @@ static int i915_error_state(struct seq_file *m, void *unused)
seq_printf(m, "DONE_REG: 0x%08x\n", error->done_reg);
}
- i915_ring_error_state(m, dev, error, RCS);
- if (HAS_BLT(dev))
- i915_ring_error_state(m, dev, error, BCS);
- if (HAS_BSD(dev))
- i915_ring_error_state(m, dev, error, VCS);
+ for_each_ring(ring, dev_priv, i)
+ i915_ring_error_state(m, dev, error, i);
if (error->active_bo)
print_error_buffers(m, "Active",
@@ -828,12 +785,71 @@ static int i915_error_state(struct seq_file *m, void *unused)
if (error->display)
intel_display_print_error_state(m, dev, error->display);
-out:
+ return 0;
+}
+
+static ssize_t
+i915_error_state_write(struct file *filp,
+ const char __user *ubuf,
+ size_t cnt,
+ loff_t *ppos)
+{
+ struct seq_file *m = filp->private_data;
+ struct i915_error_state_file_priv *error_priv = m->private;
+ struct drm_device *dev = error_priv->dev;
+
+ DRM_DEBUG_DRIVER("Resetting error state\n");
+
+ mutex_lock(&dev->struct_mutex);
+ i915_destroy_error_state(dev);
+ mutex_unlock(&dev->struct_mutex);
+
+ return cnt;
+}
+
+static int i915_error_state_open(struct inode *inode, struct file *file)
+{
+ struct drm_device *dev = inode->i_private;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct i915_error_state_file_priv *error_priv;
+ unsigned long flags;
+
+ error_priv = kzalloc(sizeof(*error_priv), GFP_KERNEL);
+ if (!error_priv)
+ return -ENOMEM;
+
+ error_priv->dev = dev;
+
+ spin_lock_irqsave(&dev_priv->error_lock, flags);
+ error_priv->error = dev_priv->first_error;
+ if (error_priv->error)
+ kref_get(&error_priv->error->ref);
spin_unlock_irqrestore(&dev_priv->error_lock, flags);
- return 0;
+ return single_open(file, i915_error_state, error_priv);
+}
+
+static int i915_error_state_release(struct inode *inode, struct file *file)
+{
+ struct seq_file *m = file->private_data;
+ struct i915_error_state_file_priv *error_priv = m->private;
+
+ if (error_priv->error)
+ kref_put(&error_priv->error->ref, i915_error_state_free);
+ kfree(error_priv);
+
+ return single_release(inode, file);
}
+static const struct file_operations i915_error_state_fops = {
+ .owner = THIS_MODULE,
+ .open = i915_error_state_open,
+ .read = seq_read,
+ .write = i915_error_state_write,
+ .llseek = default_llseek,
+ .release = i915_error_state_release,
+};
+
static int i915_rstdby_delays(struct seq_file *m, void *unused)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -1132,6 +1148,17 @@ static int gen6_drpc_info(struct seq_file *m)
seq_printf(m, "Core Power Down: %s\n",
yesno(gt_core_status & GEN6_CORE_CPD_STATE_MASK));
+
+ /* Not exactly sure what this is */
+ seq_printf(m, "RC6 \"Locked to RPn\" residency since boot: %u\n",
+ I915_READ(GEN6_GT_GFX_RC6_LOCKED));
+ seq_printf(m, "RC6 residency since boot: %u\n",
+ I915_READ(GEN6_GT_GFX_RC6));
+ seq_printf(m, "RC6+ residency since boot: %u\n",
+ I915_READ(GEN6_GT_GFX_RC6p));
+ seq_printf(m, "RC6++ residency since boot: %u\n",
+ I915_READ(GEN6_GT_GFX_RC6pp));
+
return 0;
}
@@ -1306,17 +1333,25 @@ static int i915_opregion(struct seq_file *m, void *unused)
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_opregion *opregion = &dev_priv->opregion;
+ void *data = kmalloc(OPREGION_SIZE, GFP_KERNEL);
int ret;
+ if (data == NULL)
+ return -ENOMEM;
+
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
- return ret;
+ goto out;
- if (opregion->header)
- seq_write(m, opregion->header, OPREGION_SIZE);
+ if (opregion->header) {
+ memcpy_fromio(data, opregion->header, OPREGION_SIZE);
+ seq_write(m, data, OPREGION_SIZE);
+ }
mutex_unlock(&dev->struct_mutex);
+out:
+ kfree(data);
return 0;
}
@@ -1505,6 +1540,53 @@ static int i915_ppgtt_info(struct seq_file *m, void *data)
return 0;
}
+static int i915_dpio_info(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int ret;
+
+
+ if (!IS_VALLEYVIEW(dev)) {
+ seq_printf(m, "unsupported\n");
+ return 0;
+ }
+
+ ret = mutex_lock_interruptible(&dev->mode_config.mutex);
+ if (ret)
+ return ret;
+
+ seq_printf(m, "DPIO_CTL: 0x%08x\n", I915_READ(DPIO_CTL));
+
+ seq_printf(m, "DPIO_DIV_A: 0x%08x\n",
+ intel_dpio_read(dev_priv, _DPIO_DIV_A));
+ seq_printf(m, "DPIO_DIV_B: 0x%08x\n",
+ intel_dpio_read(dev_priv, _DPIO_DIV_B));
+
+ seq_printf(m, "DPIO_REFSFR_A: 0x%08x\n",
+ intel_dpio_read(dev_priv, _DPIO_REFSFR_A));
+ seq_printf(m, "DPIO_REFSFR_B: 0x%08x\n",
+ intel_dpio_read(dev_priv, _DPIO_REFSFR_B));
+
+ seq_printf(m, "DPIO_CORE_CLK_A: 0x%08x\n",
+ intel_dpio_read(dev_priv, _DPIO_CORE_CLK_A));
+ seq_printf(m, "DPIO_CORE_CLK_B: 0x%08x\n",
+ intel_dpio_read(dev_priv, _DPIO_CORE_CLK_B));
+
+ seq_printf(m, "DPIO_LFP_COEFF_A: 0x%08x\n",
+ intel_dpio_read(dev_priv, _DPIO_LFP_COEFF_A));
+ seq_printf(m, "DPIO_LFP_COEFF_B: 0x%08x\n",
+ intel_dpio_read(dev_priv, _DPIO_LFP_COEFF_B));
+
+ seq_printf(m, "DPIO_FASTCLK_DISABLE: 0x%08x\n",
+ intel_dpio_read(dev_priv, DPIO_FASTCLK_DISABLE));
+
+ mutex_unlock(&dev->mode_config.mutex);
+
+ return 0;
+}
+
static ssize_t
i915_wedged_read(struct file *filp,
char __user *ubuf,
@@ -1562,6 +1644,65 @@ static const struct file_operations i915_wedged_fops = {
};
static ssize_t
+i915_ring_stop_read(struct file *filp,
+ char __user *ubuf,
+ size_t max,
+ loff_t *ppos)
+{
+ struct drm_device *dev = filp->private_data;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ char buf[20];
+ int len;
+
+ len = snprintf(buf, sizeof(buf),
+ "0x%08x\n", dev_priv->stop_rings);
+
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
+ return simple_read_from_buffer(ubuf, max, ppos, buf, len);
+}
+
+static ssize_t
+i915_ring_stop_write(struct file *filp,
+ const char __user *ubuf,
+ size_t cnt,
+ loff_t *ppos)
+{
+ struct drm_device *dev = filp->private_data;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ char buf[20];
+ int val = 0;
+
+ if (cnt > 0) {
+ if (cnt > sizeof(buf) - 1)
+ return -EINVAL;
+
+ if (copy_from_user(buf, ubuf, cnt))
+ return -EFAULT;
+ buf[cnt] = 0;
+
+ val = simple_strtoul(buf, NULL, 0);
+ }
+
+ DRM_DEBUG_DRIVER("Stopping rings 0x%08x\n", val);
+
+ mutex_lock(&dev->struct_mutex);
+ dev_priv->stop_rings = val;
+ mutex_unlock(&dev->struct_mutex);
+
+ return cnt;
+}
+
+static const struct file_operations i915_ring_stop_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = i915_ring_stop_read,
+ .write = i915_ring_stop_write,
+ .llseek = default_llseek,
+};
+
+static ssize_t
i915_max_freq_read(struct file *filp,
char __user *ubuf,
size_t max,
@@ -1738,7 +1879,7 @@ static int i915_forcewake_open(struct inode *inode, struct file *file)
return 0;
}
-int i915_forcewake_release(struct inode *inode, struct file *file)
+static int i915_forcewake_release(struct inode *inode, struct file *file)
{
struct drm_device *dev = inode->i_private;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1803,11 +1944,10 @@ static struct drm_info_list i915_debugfs_list[] = {
{"i915_capabilities", i915_capabilities, 0},
{"i915_gem_objects", i915_gem_object_info, 0},
{"i915_gem_gtt", i915_gem_gtt_info, 0},
+ {"i915_gem_pinned", i915_gem_gtt_info, 0, (void *) PINNED_LIST},
{"i915_gem_active", i915_gem_object_list_info, 0, (void *) ACTIVE_LIST},
{"i915_gem_flushing", i915_gem_object_list_info, 0, (void *) FLUSHING_LIST},
{"i915_gem_inactive", i915_gem_object_list_info, 0, (void *) INACTIVE_LIST},
- {"i915_gem_pinned", i915_gem_object_list_info, 0, (void *) PINNED_LIST},
- {"i915_gem_deferred_free", i915_gem_object_list_info, 0, (void *) DEFERRED_FREE_LIST},
{"i915_gem_pageflip", i915_gem_pageflip_info, 0},
{"i915_gem_request", i915_gem_request_info, 0},
{"i915_gem_seqno", i915_gem_seqno_info, 0},
@@ -1816,13 +1956,6 @@ static struct drm_info_list i915_debugfs_list[] = {
{"i915_gem_hws", i915_hws_info, 0, (void *)RCS},
{"i915_gem_hws_blt", i915_hws_info, 0, (void *)BCS},
{"i915_gem_hws_bsd", i915_hws_info, 0, (void *)VCS},
- {"i915_ringbuffer_data", i915_ringbuffer_data, 0, (void *)RCS},
- {"i915_ringbuffer_info", i915_ringbuffer_info, 0, (void *)RCS},
- {"i915_bsd_ringbuffer_data", i915_ringbuffer_data, 0, (void *)VCS},
- {"i915_bsd_ringbuffer_info", i915_ringbuffer_info, 0, (void *)VCS},
- {"i915_blt_ringbuffer_data", i915_ringbuffer_data, 0, (void *)BCS},
- {"i915_blt_ringbuffer_info", i915_ringbuffer_info, 0, (void *)BCS},
- {"i915_error_state", i915_error_state, 0},
{"i915_rstdby_delays", i915_rstdby_delays, 0},
{"i915_cur_delayinfo", i915_cur_delayinfo, 0},
{"i915_delayfreq_table", i915_delayfreq_table, 0},
@@ -1839,6 +1972,7 @@ static struct drm_info_list i915_debugfs_list[] = {
{"i915_gen6_forcewake_count", i915_gen6_forcewake_count_info, 0},
{"i915_swizzle_info", i915_swizzle_info, 0},
{"i915_ppgtt_info", i915_ppgtt_info, 0},
+ {"i915_dpio", i915_dpio_info, 0},
};
#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
@@ -1867,6 +2001,17 @@ int i915_debugfs_init(struct drm_minor *minor)
&i915_cache_sharing_fops);
if (ret)
return ret;
+ ret = i915_debugfs_create(minor->debugfs_root, minor,
+ "i915_ring_stop",
+ &i915_ring_stop_fops);
+ if (ret)
+ return ret;
+
+ ret = i915_debugfs_create(minor->debugfs_root, minor,
+ "i915_error_state",
+ &i915_error_state_fops);
+ if (ret)
+ return ret;
return drm_debugfs_create_files(i915_debugfs_list,
I915_DEBUGFS_ENTRIES,
@@ -1885,6 +2030,8 @@ void i915_debugfs_cleanup(struct drm_minor *minor)
1, minor);
drm_debugfs_remove_files((struct drm_info_list *) &i915_cache_sharing_fops,
1, minor);
+ drm_debugfs_remove_files((struct drm_info_list *) &i915_ring_stop_fops,
+ 1, minor);
}
#endif /* CONFIG_DEBUG_FS */
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index ba60f3c8f911..f94792626b94 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -26,6 +26,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include "drmP.h"
#include "drm.h"
#include "drm_crtc_helper.h"
@@ -34,15 +36,62 @@
#include "i915_drm.h"
#include "i915_drv.h"
#include "i915_trace.h"
-#include "../../../platform/x86/intel_ips.h"
#include <linux/pci.h>
#include <linux/vgaarb.h>
#include <linux/acpi.h>
#include <linux/pnp.h>
#include <linux/vga_switcheroo.h>
#include <linux/slab.h>
-#include <linux/module.h>
#include <acpi/video.h>
+#include <asm/pat.h>
+
+#define LP_RING(d) (&((struct drm_i915_private *)(d))->ring[RCS])
+
+#define BEGIN_LP_RING(n) \
+ intel_ring_begin(LP_RING(dev_priv), (n))
+
+#define OUT_RING(x) \
+ intel_ring_emit(LP_RING(dev_priv), x)
+
+#define ADVANCE_LP_RING() \
+ intel_ring_advance(LP_RING(dev_priv))
+
+/**
+ * Lock test for when it's just for synchronization of ring access.
+ *
+ * In that case, we don't need to do it when GEM is initialized as nobody else
+ * has access to the ring.
+ */
+#define RING_LOCK_TEST_WITH_RETURN(dev, file) do { \
+ if (LP_RING(dev->dev_private)->obj == NULL) \
+ LOCK_TEST_WITH_RETURN(dev, file); \
+} while (0)
+
+static inline u32
+intel_read_legacy_status_page(struct drm_i915_private *dev_priv, int reg)
+{
+ if (I915_NEED_GFX_HWS(dev_priv->dev))
+ return ioread32(dev_priv->dri1.gfx_hws_cpu_addr + reg);
+ else
+ return intel_read_status_page(LP_RING(dev_priv), reg);
+}
+
+#define READ_HWSP(dev_priv, reg) intel_read_legacy_status_page(dev_priv, reg)
+#define READ_BREADCRUMB(dev_priv) READ_HWSP(dev_priv, I915_BREADCRUMB_INDEX)
+#define I915_BREADCRUMB_INDEX 0x21
+
+void i915_update_dri1_breadcrumb(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_master_private *master_priv;
+
+ if (dev->primary->master) {
+ master_priv = dev->primary->master->driver_priv;
+ if (master_priv->sarea_priv)
+ master_priv->sarea_priv->last_dispatch =
+ READ_BREADCRUMB(dev_priv);
+ }
+}
static void i915_write_hws_pga(struct drm_device *dev)
{
@@ -97,7 +146,7 @@ static void i915_free_hws(struct drm_device *dev)
if (ring->status_page.gfx_addr) {
ring->status_page.gfx_addr = 0;
- drm_core_ioremapfree(&dev_priv->hws_map, dev);
+ iounmap(dev_priv->dri1.gfx_hws_cpu_addr);
}
/* Need to rewrite hardware status page */
@@ -195,7 +244,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
/* Allow hardware batchbuffers unless told otherwise.
*/
- dev_priv->allow_batchbuffer = 1;
+ dev_priv->dri1.allow_batchbuffer = 1;
return 0;
}
@@ -207,7 +256,7 @@ static int i915_dma_resume(struct drm_device * dev)
DRM_DEBUG_DRIVER("%s\n", __func__);
- if (ring->map.handle == NULL) {
+ if (ring->virtual_start == NULL) {
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
return -ENOMEM;
@@ -236,6 +285,9 @@ static int i915_dma_init(struct drm_device *dev, void *data,
drm_i915_init_t *init = data;
int retcode = 0;
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ return -ENODEV;
+
switch (init->func) {
case I915_INIT_DMA:
retcode = i915_initialize(dev, init);
@@ -578,6 +630,9 @@ static int i915_flush_ioctl(struct drm_device *dev, void *data,
{
int ret;
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ return -ENODEV;
+
RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
mutex_lock(&dev->struct_mutex);
@@ -598,7 +653,10 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,
int ret;
struct drm_clip_rect *cliprects = NULL;
- if (!dev_priv->allow_batchbuffer) {
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ return -ENODEV;
+
+ if (!dev_priv->dri1.allow_batchbuffer) {
DRM_ERROR("Batchbuffer ioctl disabled\n");
return -EINVAL;
}
@@ -655,6 +713,9 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
DRM_DEBUG_DRIVER("i915 cmdbuffer, buf %p sz %d cliprects %d\n",
cmdbuf->buf, cmdbuf->sz, cmdbuf->num_cliprects);
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ return -ENODEV;
+
RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
if (cmdbuf->num_cliprects < 0)
@@ -706,11 +767,166 @@ fail_batch_free:
return ret;
}
+static int i915_emit_irq(struct drm_device * dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
+
+ i915_kernel_lost_context(dev);
+
+ DRM_DEBUG_DRIVER("\n");
+
+ dev_priv->counter++;
+ if (dev_priv->counter > 0x7FFFFFFFUL)
+ dev_priv->counter = 1;
+ if (master_priv->sarea_priv)
+ master_priv->sarea_priv->last_enqueue = dev_priv->counter;
+
+ if (BEGIN_LP_RING(4) == 0) {
+ OUT_RING(MI_STORE_DWORD_INDEX);
+ OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+ OUT_RING(dev_priv->counter);
+ OUT_RING(MI_USER_INTERRUPT);
+ ADVANCE_LP_RING();
+ }
+
+ return dev_priv->counter;
+}
+
+static int i915_wait_irq(struct drm_device * dev, int irq_nr)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
+ int ret = 0;
+ struct intel_ring_buffer *ring = LP_RING(dev_priv);
+
+ DRM_DEBUG_DRIVER("irq_nr=%d breadcrumb=%d\n", irq_nr,
+ READ_BREADCRUMB(dev_priv));
+
+ if (READ_BREADCRUMB(dev_priv) >= irq_nr) {
+ if (master_priv->sarea_priv)
+ master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
+ return 0;
+ }
+
+ if (master_priv->sarea_priv)
+ master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
+
+ if (ring->irq_get(ring)) {
+ DRM_WAIT_ON(ret, ring->irq_queue, 3 * DRM_HZ,
+ READ_BREADCRUMB(dev_priv) >= irq_nr);
+ ring->irq_put(ring);
+ } else if (wait_for(READ_BREADCRUMB(dev_priv) >= irq_nr, 3000))
+ ret = -EBUSY;
+
+ if (ret == -EBUSY) {
+ DRM_ERROR("EBUSY -- rec: %d emitted: %d\n",
+ READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
+ }
+
+ return ret;
+}
+
+/* Needs the lock as it touches the ring.
+ */
+static int i915_irq_emit(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_irq_emit_t *emit = data;
+ int result;
+
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ return -ENODEV;
+
+ if (!dev_priv || !LP_RING(dev_priv)->virtual_start) {
+ DRM_ERROR("called with no initialization\n");
+ return -EINVAL;
+ }
+
+ RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
+
+ mutex_lock(&dev->struct_mutex);
+ result = i915_emit_irq(dev);
+ mutex_unlock(&dev->struct_mutex);
+
+ if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) {
+ DRM_ERROR("copy_to_user\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+/* Doesn't need the hardware lock.
+ */
+static int i915_irq_wait(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_irq_wait_t *irqwait = data;
+
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ return -ENODEV;
+
+ if (!dev_priv) {
+ DRM_ERROR("called with no initialization\n");
+ return -EINVAL;
+ }
+
+ return i915_wait_irq(dev, irqwait->irq_seq);
+}
+
+static int i915_vblank_pipe_get(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_vblank_pipe_t *pipe = data;
+
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ return -ENODEV;
+
+ if (!dev_priv) {
+ DRM_ERROR("called with no initialization\n");
+ return -EINVAL;
+ }
+
+ pipe->pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
+
+ return 0;
+}
+
+/**
+ * Schedule buffer swap at given vertical blank.
+ */
+static int i915_vblank_swap(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ /* The delayed swap mechanism was fundamentally racy, and has been
+ * removed. The model was that the client requested a delayed flip/swap
+ * from the kernel, then waited for vblank before continuing to perform
+ * rendering. The problem was that the kernel might wake the client
+ * up before it dispatched the vblank swap (since the lock has to be
+ * held while touching the ringbuffer), in which case the client would
+ * clear and start the next frame before the swap occurred, and
+ * flicker would occur in addition to likely missing the vblank.
+ *
+ * In the absence of this ioctl, userland falls back to a correct path
+ * of waiting for a vblank, then dispatching the swap on its own.
+ * Context switching to userland and back is plenty fast enough for
+ * meeting the requirements of vblank swapping.
+ */
+ return -EINVAL;
+}
+
static int i915_flip_bufs(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
int ret;
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ return -ENODEV;
+
DRM_DEBUG_DRIVER("%s\n", __func__);
RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
@@ -739,7 +955,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
value = dev->pdev->irq ? 1 : 0;
break;
case I915_PARAM_ALLOW_BATCHBUFFER:
- value = dev_priv->allow_batchbuffer ? 1 : 0;
+ value = dev_priv->dri1.allow_batchbuffer ? 1 : 0;
break;
case I915_PARAM_LAST_DISPATCH:
value = READ_BREADCRUMB(dev_priv);
@@ -748,7 +964,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
value = dev->pci_device;
break;
case I915_PARAM_HAS_GEM:
- value = dev_priv->has_gem;
+ value = 1;
break;
case I915_PARAM_NUM_FENCES_AVAIL:
value = dev_priv->num_fence_regs - dev_priv->fence_reg_start;
@@ -761,13 +977,13 @@ static int i915_getparam(struct drm_device *dev, void *data,
break;
case I915_PARAM_HAS_EXECBUF2:
/* depends on GEM */
- value = dev_priv->has_gem;
+ value = 1;
break;
case I915_PARAM_HAS_BSD:
- value = HAS_BSD(dev);
+ value = intel_ring_initialized(&dev_priv->ring[VCS]);
break;
case I915_PARAM_HAS_BLT:
- value = HAS_BLT(dev);
+ value = intel_ring_initialized(&dev_priv->ring[BCS]);
break;
case I915_PARAM_HAS_RELAXED_FENCING:
value = 1;
@@ -787,6 +1003,9 @@ static int i915_getparam(struct drm_device *dev, void *data,
case I915_PARAM_HAS_LLC:
value = HAS_LLC(dev);
break;
+ case I915_PARAM_HAS_ALIASING_PPGTT:
+ value = dev_priv->mm.aliasing_ppgtt ? 1 : 0;
+ break;
default:
DRM_DEBUG_DRIVER("Unknown parameter %d\n",
param->param);
@@ -816,10 +1035,9 @@ static int i915_setparam(struct drm_device *dev, void *data,
case I915_SETPARAM_USE_MI_BATCHBUFFER_START:
break;
case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY:
- dev_priv->tex_lru_log_granularity = param->value;
break;
case I915_SETPARAM_ALLOW_BATCHBUFFER:
- dev_priv->allow_batchbuffer = param->value;
+ dev_priv->dri1.allow_batchbuffer = param->value ? 1 : 0;
break;
case I915_SETPARAM_NUM_USED_FENCES:
if (param->value > dev_priv->num_fence_regs ||
@@ -844,6 +1062,9 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
drm_i915_hws_addr_t *hws = data;
struct intel_ring_buffer *ring = LP_RING(dev_priv);
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ return -ENODEV;
+
if (!I915_NEED_GFX_HWS(dev))
return -EINVAL;
@@ -861,23 +1082,17 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
ring->status_page.gfx_addr = hws->addr & (0x1ffff<<12);
- dev_priv->hws_map.offset = dev->agp->base + hws->addr;
- dev_priv->hws_map.size = 4*1024;
- dev_priv->hws_map.type = 0;
- dev_priv->hws_map.flags = 0;
- dev_priv->hws_map.mtrr = 0;
-
- drm_core_ioremap_wc(&dev_priv->hws_map, dev);
- if (dev_priv->hws_map.handle == NULL) {
+ dev_priv->dri1.gfx_hws_cpu_addr = ioremap_wc(dev->agp->base + hws->addr,
+ 4096);
+ if (dev_priv->dri1.gfx_hws_cpu_addr == NULL) {
i915_dma_cleanup(dev);
ring->status_page.gfx_addr = 0;
DRM_ERROR("can not ioremap virtual address for"
" G33 hw status page\n");
return -ENOMEM;
}
- ring->status_page.page_addr =
- (void __force __iomem *)dev_priv->hws_map.handle;
- memset_io(ring->status_page.page_addr, 0, PAGE_SIZE);
+
+ memset_io(dev_priv->dri1.gfx_hws_cpu_addr, 0, PAGE_SIZE);
I915_WRITE(HWS_PGA, ring->status_page.gfx_addr);
DRM_DEBUG_DRIVER("load hws HWS_PGA with gfx mem 0x%x\n",
@@ -1013,133 +1228,6 @@ intel_teardown_mchbar(struct drm_device *dev)
release_resource(&dev_priv->mch_res);
}
-#define PTE_ADDRESS_MASK 0xfffff000
-#define PTE_ADDRESS_MASK_HIGH 0x000000f0 /* i915+ */
-#define PTE_MAPPING_TYPE_UNCACHED (0 << 1)
-#define PTE_MAPPING_TYPE_DCACHE (1 << 1) /* i830 only */
-#define PTE_MAPPING_TYPE_CACHED (3 << 1)
-#define PTE_MAPPING_TYPE_MASK (3 << 1)
-#define PTE_VALID (1 << 0)
-
-/**
- * i915_stolen_to_phys - take an offset into stolen memory and turn it into
- * a physical one
- * @dev: drm device
- * @offset: address to translate
- *
- * Some chip functions require allocations from stolen space and need the
- * physical address of the memory in question.
- */
-static unsigned long i915_stolen_to_phys(struct drm_device *dev, u32 offset)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct pci_dev *pdev = dev_priv->bridge_dev;
- u32 base;
-
-#if 0
- /* On the machines I have tested the Graphics Base of Stolen Memory
- * is unreliable, so compute the base by subtracting the stolen memory
- * from the Top of Low Usable DRAM which is where the BIOS places
- * the graphics stolen memory.
- */
- if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) {
- /* top 32bits are reserved = 0 */
- pci_read_config_dword(pdev, 0xA4, &base);
- } else {
- /* XXX presume 8xx is the same as i915 */
- pci_bus_read_config_dword(pdev->bus, 2, 0x5C, &base);
- }
-#else
- if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) {
- u16 val;
- pci_read_config_word(pdev, 0xb0, &val);
- base = val >> 4 << 20;
- } else {
- u8 val;
- pci_read_config_byte(pdev, 0x9c, &val);
- base = val >> 3 << 27;
- }
- base -= dev_priv->mm.gtt->stolen_size;
-#endif
-
- return base + offset;
-}
-
-static void i915_warn_stolen(struct drm_device *dev)
-{
- DRM_ERROR("not enough stolen space for compressed buffer, disabling\n");
- DRM_ERROR("hint: you may be able to increase stolen memory size in the BIOS to avoid this\n");
-}
-
-static void i915_setup_compression(struct drm_device *dev, int size)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_mm_node *compressed_fb, *uninitialized_var(compressed_llb);
- unsigned long cfb_base;
- unsigned long ll_base = 0;
-
- /* Just in case the BIOS is doing something questionable. */
- intel_disable_fbc(dev);
-
- compressed_fb = drm_mm_search_free(&dev_priv->mm.stolen, size, 4096, 0);
- if (compressed_fb)
- compressed_fb = drm_mm_get_block(compressed_fb, size, 4096);
- if (!compressed_fb)
- goto err;
-
- cfb_base = i915_stolen_to_phys(dev, compressed_fb->start);
- if (!cfb_base)
- goto err_fb;
-
- if (!(IS_GM45(dev) || HAS_PCH_SPLIT(dev))) {
- compressed_llb = drm_mm_search_free(&dev_priv->mm.stolen,
- 4096, 4096, 0);
- if (compressed_llb)
- compressed_llb = drm_mm_get_block(compressed_llb,
- 4096, 4096);
- if (!compressed_llb)
- goto err_fb;
-
- ll_base = i915_stolen_to_phys(dev, compressed_llb->start);
- if (!ll_base)
- goto err_llb;
- }
-
- dev_priv->cfb_size = size;
-
- dev_priv->compressed_fb = compressed_fb;
- if (HAS_PCH_SPLIT(dev))
- I915_WRITE(ILK_DPFC_CB_BASE, compressed_fb->start);
- else if (IS_GM45(dev)) {
- I915_WRITE(DPFC_CB_BASE, compressed_fb->start);
- } else {
- I915_WRITE(FBC_CFB_BASE, cfb_base);
- I915_WRITE(FBC_LL_BASE, ll_base);
- dev_priv->compressed_llb = compressed_llb;
- }
-
- DRM_DEBUG_KMS("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n",
- cfb_base, ll_base, size >> 20);
- return;
-
-err_llb:
- drm_mm_put_block(compressed_llb);
-err_fb:
- drm_mm_put_block(compressed_fb);
-err:
- dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
- i915_warn_stolen(dev);
-}
-
-static void i915_cleanup_compression(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- drm_mm_put_block(dev_priv->compressed_fb);
- if (dev_priv->compressed_llb)
- drm_mm_put_block(dev_priv->compressed_llb);
-}
-
/* true = enable decode, false = disable decoder */
static unsigned int i915_vga_set_decode(void *cookie, bool state)
{
@@ -1158,14 +1246,14 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_
struct drm_device *dev = pci_get_drvdata(pdev);
pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
if (state == VGA_SWITCHEROO_ON) {
- printk(KERN_INFO "i915: switched on\n");
+ pr_info("switched on\n");
dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
/* i915 resume handler doesn't set to D0 */
pci_set_power_state(dev->pdev, PCI_D0);
i915_resume(dev);
dev->switch_power_state = DRM_SWITCH_POWER_ON;
} else {
- printk(KERN_ERR "i915: switched off\n");
+ pr_err("switched off\n");
dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
i915_suspend(dev, pmm);
dev->switch_power_state = DRM_SWITCH_POWER_OFF;
@@ -1183,88 +1271,11 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
return can_switch;
}
-static bool
-intel_enable_ppgtt(struct drm_device *dev)
-{
- if (i915_enable_ppgtt >= 0)
- return i915_enable_ppgtt;
-
-#ifdef CONFIG_INTEL_IOMMU
- /* Disable ppgtt on SNB if VT-d is on. */
- if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped)
- return false;
-#endif
-
- return true;
-}
-
-static int i915_load_gem_init(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- unsigned long prealloc_size, gtt_size, mappable_size;
- int ret;
-
- prealloc_size = dev_priv->mm.gtt->stolen_size;
- gtt_size = dev_priv->mm.gtt->gtt_total_entries << PAGE_SHIFT;
- mappable_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
-
- /* Basic memrange allocator for stolen space */
- drm_mm_init(&dev_priv->mm.stolen, 0, prealloc_size);
-
- mutex_lock(&dev->struct_mutex);
- if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) {
- /* PPGTT pdes are stolen from global gtt ptes, so shrink the
- * aperture accordingly when using aliasing ppgtt. */
- gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE;
- /* For paranoia keep the guard page in between. */
- gtt_size -= PAGE_SIZE;
-
- i915_gem_do_init(dev, 0, mappable_size, gtt_size);
-
- ret = i915_gem_init_aliasing_ppgtt(dev);
- if (ret) {
- mutex_unlock(&dev->struct_mutex);
- return ret;
- }
- } else {
- /* Let GEM Manage all of the aperture.
- *
- * However, leave one page at the end still bound to the scratch
- * page. There are a number of places where the hardware
- * apparently prefetches past the end of the object, and we've
- * seen multiple hangs with the GPU head pointer stuck in a
- * batchbuffer bound at the last page of the aperture. One page
- * should be enough to keep any prefetching inside of the
- * aperture.
- */
- i915_gem_do_init(dev, 0, mappable_size, gtt_size - PAGE_SIZE);
- }
-
- ret = i915_gem_init_hw(dev);
- mutex_unlock(&dev->struct_mutex);
- if (ret) {
- i915_gem_cleanup_aliasing_ppgtt(dev);
- return ret;
- }
-
- /* Try to set up FBC with a reasonable compressed buffer size */
- if (I915_HAS_FBC(dev) && i915_powersave) {
- int cfb_size;
-
- /* Leave 1M for line length buffer & misc. */
-
- /* Try to get a 32M buffer... */
- if (prealloc_size > (36*1024*1024))
- cfb_size = 32*1024*1024;
- else /* fall back to 7/8 of the stolen space */
- cfb_size = prealloc_size * 7 / 8;
- i915_setup_compression(dev, cfb_size);
- }
-
- /* Allow hardware batchbuffers unless told otherwise. */
- dev_priv->allow_batchbuffer = 1;
- return 0;
-}
+static const struct vga_switcheroo_client_ops i915_switcheroo_ops = {
+ .set_gpu_state = i915_switcheroo_set_state,
+ .reprobe = NULL,
+ .can_switch = i915_switcheroo_can_switch,
+};
static int i915_load_modeset_init(struct drm_device *dev)
{
@@ -1288,22 +1299,22 @@ static int i915_load_modeset_init(struct drm_device *dev)
intel_register_dsm_handler();
- ret = vga_switcheroo_register_client(dev->pdev,
- i915_switcheroo_set_state,
- NULL,
- i915_switcheroo_can_switch);
+ ret = vga_switcheroo_register_client(dev->pdev, &i915_switcheroo_ops);
if (ret)
goto cleanup_vga_client;
- /* IIR "flip pending" bit means done if this bit is set */
- if (IS_GEN3(dev) && (I915_READ(ECOSKPD) & ECO_FLIP_DONE))
- dev_priv->flip_pending_is_done = true;
+ /* Initialise stolen first so that we may reserve preallocated
+ * objects for the BIOS to KMS transition.
+ */
+ ret = i915_gem_init_stolen(dev);
+ if (ret)
+ goto cleanup_vga_switcheroo;
intel_modeset_init(dev);
- ret = i915_load_gem_init(dev);
+ ret = i915_gem_init(dev);
if (ret)
- goto cleanup_vga_switcheroo;
+ goto cleanup_gem_stolen;
intel_modeset_gem_init(dev);
@@ -1333,6 +1344,8 @@ cleanup_gem:
i915_gem_cleanup_ringbuffer(dev);
mutex_unlock(&dev->struct_mutex);
i915_gem_cleanup_aliasing_ppgtt(dev);
+cleanup_gem_stolen:
+ i915_gem_cleanup_stolen(dev);
cleanup_vga_switcheroo:
vga_switcheroo_unregister_client(dev->pdev);
cleanup_vga_client:
@@ -1365,572 +1378,26 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master)
master->driver_priv = NULL;
}
-static void i915_pineview_get_mem_freq(struct drm_device *dev)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- u32 tmp;
-
- tmp = I915_READ(CLKCFG);
-
- switch (tmp & CLKCFG_FSB_MASK) {
- case CLKCFG_FSB_533:
- dev_priv->fsb_freq = 533; /* 133*4 */
- break;
- case CLKCFG_FSB_800:
- dev_priv->fsb_freq = 800; /* 200*4 */
- break;
- case CLKCFG_FSB_667:
- dev_priv->fsb_freq = 667; /* 167*4 */
- break;
- case CLKCFG_FSB_400:
- dev_priv->fsb_freq = 400; /* 100*4 */
- break;
- }
-
- switch (tmp & CLKCFG_MEM_MASK) {
- case CLKCFG_MEM_533:
- dev_priv->mem_freq = 533;
- break;
- case CLKCFG_MEM_667:
- dev_priv->mem_freq = 667;
- break;
- case CLKCFG_MEM_800:
- dev_priv->mem_freq = 800;
- break;
- }
-
- /* detect pineview DDR3 setting */
- tmp = I915_READ(CSHRDDR3CTL);
- dev_priv->is_ddr3 = (tmp & CSHRDDR3CTL_DDR3) ? 1 : 0;
-}
-
-static void i915_ironlake_get_mem_freq(struct drm_device *dev)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- u16 ddrpll, csipll;
-
- ddrpll = I915_READ16(DDRMPLL1);
- csipll = I915_READ16(CSIPLL0);
-
- switch (ddrpll & 0xff) {
- case 0xc:
- dev_priv->mem_freq = 800;
- break;
- case 0x10:
- dev_priv->mem_freq = 1066;
- break;
- case 0x14:
- dev_priv->mem_freq = 1333;
- break;
- case 0x18:
- dev_priv->mem_freq = 1600;
- break;
- default:
- DRM_DEBUG_DRIVER("unknown memory frequency 0x%02x\n",
- ddrpll & 0xff);
- dev_priv->mem_freq = 0;
- break;
- }
-
- dev_priv->r_t = dev_priv->mem_freq;
-
- switch (csipll & 0x3ff) {
- case 0x00c:
- dev_priv->fsb_freq = 3200;
- break;
- case 0x00e:
- dev_priv->fsb_freq = 3733;
- break;
- case 0x010:
- dev_priv->fsb_freq = 4266;
- break;
- case 0x012:
- dev_priv->fsb_freq = 4800;
- break;
- case 0x014:
- dev_priv->fsb_freq = 5333;
- break;
- case 0x016:
- dev_priv->fsb_freq = 5866;
- break;
- case 0x018:
- dev_priv->fsb_freq = 6400;
- break;
- default:
- DRM_DEBUG_DRIVER("unknown fsb frequency 0x%04x\n",
- csipll & 0x3ff);
- dev_priv->fsb_freq = 0;
- break;
- }
-
- if (dev_priv->fsb_freq == 3200) {
- dev_priv->c_m = 0;
- } else if (dev_priv->fsb_freq > 3200 && dev_priv->fsb_freq <= 4800) {
- dev_priv->c_m = 1;
- } else {
- dev_priv->c_m = 2;
- }
-}
-
-static const struct cparams {
- u16 i;
- u16 t;
- u16 m;
- u16 c;
-} cparams[] = {
- { 1, 1333, 301, 28664 },
- { 1, 1066, 294, 24460 },
- { 1, 800, 294, 25192 },
- { 0, 1333, 276, 27605 },
- { 0, 1066, 276, 27605 },
- { 0, 800, 231, 23784 },
-};
-
-unsigned long i915_chipset_val(struct drm_i915_private *dev_priv)
-{
- u64 total_count, diff, ret;
- u32 count1, count2, count3, m = 0, c = 0;
- unsigned long now = jiffies_to_msecs(jiffies), diff1;
- int i;
-
- diff1 = now - dev_priv->last_time1;
-
- /* Prevent division-by-zero if we are asking too fast.
- * Also, we don't get interesting results if we are polling
- * faster than once in 10ms, so just return the saved value
- * in such cases.
- */
- if (diff1 <= 10)
- return dev_priv->chipset_power;
-
- count1 = I915_READ(DMIEC);
- count2 = I915_READ(DDREC);
- count3 = I915_READ(CSIEC);
-
- total_count = count1 + count2 + count3;
-
- /* FIXME: handle per-counter overflow */
- if (total_count < dev_priv->last_count1) {
- diff = ~0UL - dev_priv->last_count1;
- diff += total_count;
- } else {
- diff = total_count - dev_priv->last_count1;
- }
-
- for (i = 0; i < ARRAY_SIZE(cparams); i++) {
- if (cparams[i].i == dev_priv->c_m &&
- cparams[i].t == dev_priv->r_t) {
- m = cparams[i].m;
- c = cparams[i].c;
- break;
- }
- }
-
- diff = div_u64(diff, diff1);
- ret = ((m * diff) + c);
- ret = div_u64(ret, 10);
-
- dev_priv->last_count1 = total_count;
- dev_priv->last_time1 = now;
-
- dev_priv->chipset_power = ret;
-
- return ret;
-}
-
-unsigned long i915_mch_val(struct drm_i915_private *dev_priv)
-{
- unsigned long m, x, b;
- u32 tsfs;
-
- tsfs = I915_READ(TSFS);
-
- m = ((tsfs & TSFS_SLOPE_MASK) >> TSFS_SLOPE_SHIFT);
- x = I915_READ8(TR1);
-
- b = tsfs & TSFS_INTR_MASK;
-
- return ((m * x) / 127) - b;
-}
-
-static u16 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid)
-{
- static const struct v_table {
- u16 vd; /* in .1 mil */
- u16 vm; /* in .1 mil */
- } v_table[] = {
- { 0, 0, },
- { 375, 0, },
- { 500, 0, },
- { 625, 0, },
- { 750, 0, },
- { 875, 0, },
- { 1000, 0, },
- { 1125, 0, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4250, 3125, },
- { 4375, 3250, },
- { 4500, 3375, },
- { 4625, 3500, },
- { 4750, 3625, },
- { 4875, 3750, },
- { 5000, 3875, },
- { 5125, 4000, },
- { 5250, 4125, },
- { 5375, 4250, },
- { 5500, 4375, },
- { 5625, 4500, },
- { 5750, 4625, },
- { 5875, 4750, },
- { 6000, 4875, },
- { 6125, 5000, },
- { 6250, 5125, },
- { 6375, 5250, },
- { 6500, 5375, },
- { 6625, 5500, },
- { 6750, 5625, },
- { 6875, 5750, },
- { 7000, 5875, },
- { 7125, 6000, },
- { 7250, 6125, },
- { 7375, 6250, },
- { 7500, 6375, },
- { 7625, 6500, },
- { 7750, 6625, },
- { 7875, 6750, },
- { 8000, 6875, },
- { 8125, 7000, },
- { 8250, 7125, },
- { 8375, 7250, },
- { 8500, 7375, },
- { 8625, 7500, },
- { 8750, 7625, },
- { 8875, 7750, },
- { 9000, 7875, },
- { 9125, 8000, },
- { 9250, 8125, },
- { 9375, 8250, },
- { 9500, 8375, },
- { 9625, 8500, },
- { 9750, 8625, },
- { 9875, 8750, },
- { 10000, 8875, },
- { 10125, 9000, },
- { 10250, 9125, },
- { 10375, 9250, },
- { 10500, 9375, },
- { 10625, 9500, },
- { 10750, 9625, },
- { 10875, 9750, },
- { 11000, 9875, },
- { 11125, 10000, },
- { 11250, 10125, },
- { 11375, 10250, },
- { 11500, 10375, },
- { 11625, 10500, },
- { 11750, 10625, },
- { 11875, 10750, },
- { 12000, 10875, },
- { 12125, 11000, },
- { 12250, 11125, },
- { 12375, 11250, },
- { 12500, 11375, },
- { 12625, 11500, },
- { 12750, 11625, },
- { 12875, 11750, },
- { 13000, 11875, },
- { 13125, 12000, },
- { 13250, 12125, },
- { 13375, 12250, },
- { 13500, 12375, },
- { 13625, 12500, },
- { 13750, 12625, },
- { 13875, 12750, },
- { 14000, 12875, },
- { 14125, 13000, },
- { 14250, 13125, },
- { 14375, 13250, },
- { 14500, 13375, },
- { 14625, 13500, },
- { 14750, 13625, },
- { 14875, 13750, },
- { 15000, 13875, },
- { 15125, 14000, },
- { 15250, 14125, },
- { 15375, 14250, },
- { 15500, 14375, },
- { 15625, 14500, },
- { 15750, 14625, },
- { 15875, 14750, },
- { 16000, 14875, },
- { 16125, 15000, },
- };
- if (dev_priv->info->is_mobile)
- return v_table[pxvid].vm;
- else
- return v_table[pxvid].vd;
-}
-
-void i915_update_gfx_val(struct drm_i915_private *dev_priv)
+static void
+i915_mtrr_setup(struct drm_i915_private *dev_priv, unsigned long base,
+ unsigned long size)
{
- struct timespec now, diff1;
- u64 diff;
- unsigned long diffms;
- u32 count;
-
- if (dev_priv->info->gen != 5)
- return;
-
- getrawmonotonic(&now);
- diff1 = timespec_sub(now, dev_priv->last_time2);
+ dev_priv->mm.gtt_mtrr = -1;
- /* Don't divide by 0 */
- diffms = diff1.tv_sec * 1000 + diff1.tv_nsec / 1000000;
- if (!diffms)
+#if defined(CONFIG_X86_PAT)
+ if (cpu_has_pat)
return;
+#endif
- count = I915_READ(GFXEC);
-
- if (count < dev_priv->last_count2) {
- diff = ~0UL - dev_priv->last_count2;
- diff += count;
- } else {
- diff = count - dev_priv->last_count2;
- }
-
- dev_priv->last_count2 = count;
- dev_priv->last_time2 = now;
-
- /* More magic constants... */
- diff = diff * 1181;
- diff = div_u64(diff, diffms * 10);
- dev_priv->gfx_power = diff;
-}
-
-unsigned long i915_gfx_val(struct drm_i915_private *dev_priv)
-{
- unsigned long t, corr, state1, corr2, state2;
- u32 pxvid, ext_v;
-
- pxvid = I915_READ(PXVFREQ_BASE + (dev_priv->cur_delay * 4));
- pxvid = (pxvid >> 24) & 0x7f;
- ext_v = pvid_to_extvid(dev_priv, pxvid);
-
- state1 = ext_v;
-
- t = i915_mch_val(dev_priv);
-
- /* Revel in the empirically derived constants */
-
- /* Correction factor in 1/100000 units */
- if (t > 80)
- corr = ((t * 2349) + 135940);
- else if (t >= 50)
- corr = ((t * 964) + 29317);
- else /* < 50 */
- corr = ((t * 301) + 1004);
-
- corr = corr * ((150142 * state1) / 10000 - 78642);
- corr /= 100000;
- corr2 = (corr * dev_priv->corr);
-
- state2 = (corr2 * state1) / 10000;
- state2 /= 100; /* convert to mW */
-
- i915_update_gfx_val(dev_priv);
-
- return dev_priv->gfx_power + state2;
-}
-
-/* Global for IPS driver to get at the current i915 device */
-static struct drm_i915_private *i915_mch_dev;
-/*
- * Lock protecting IPS related data structures
- * - i915_mch_dev
- * - dev_priv->max_delay
- * - dev_priv->min_delay
- * - dev_priv->fmax
- * - dev_priv->gpu_busy
- */
-static DEFINE_SPINLOCK(mchdev_lock);
-
-/**
- * i915_read_mch_val - return value for IPS use
- *
- * Calculate and return a value for the IPS driver to use when deciding whether
- * we have thermal and power headroom to increase CPU or GPU power budget.
- */
-unsigned long i915_read_mch_val(void)
-{
- struct drm_i915_private *dev_priv;
- unsigned long chipset_val, graphics_val, ret = 0;
-
- spin_lock(&mchdev_lock);
- if (!i915_mch_dev)
- goto out_unlock;
- dev_priv = i915_mch_dev;
-
- chipset_val = i915_chipset_val(dev_priv);
- graphics_val = i915_gfx_val(dev_priv);
-
- ret = chipset_val + graphics_val;
-
-out_unlock:
- spin_unlock(&mchdev_lock);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(i915_read_mch_val);
-
-/**
- * i915_gpu_raise - raise GPU frequency limit
- *
- * Raise the limit; IPS indicates we have thermal headroom.
- */
-bool i915_gpu_raise(void)
-{
- struct drm_i915_private *dev_priv;
- bool ret = true;
-
- spin_lock(&mchdev_lock);
- if (!i915_mch_dev) {
- ret = false;
- goto out_unlock;
- }
- dev_priv = i915_mch_dev;
-
- if (dev_priv->max_delay > dev_priv->fmax)
- dev_priv->max_delay--;
-
-out_unlock:
- spin_unlock(&mchdev_lock);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(i915_gpu_raise);
-
-/**
- * i915_gpu_lower - lower GPU frequency limit
- *
- * IPS indicates we're close to a thermal limit, so throttle back the GPU
- * frequency maximum.
- */
-bool i915_gpu_lower(void)
-{
- struct drm_i915_private *dev_priv;
- bool ret = true;
-
- spin_lock(&mchdev_lock);
- if (!i915_mch_dev) {
- ret = false;
- goto out_unlock;
- }
- dev_priv = i915_mch_dev;
-
- if (dev_priv->max_delay < dev_priv->min_delay)
- dev_priv->max_delay++;
-
-out_unlock:
- spin_unlock(&mchdev_lock);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(i915_gpu_lower);
-
-/**
- * i915_gpu_busy - indicate GPU business to IPS
- *
- * Tell the IPS driver whether or not the GPU is busy.
- */
-bool i915_gpu_busy(void)
-{
- struct drm_i915_private *dev_priv;
- bool ret = false;
-
- spin_lock(&mchdev_lock);
- if (!i915_mch_dev)
- goto out_unlock;
- dev_priv = i915_mch_dev;
-
- ret = dev_priv->busy;
-
-out_unlock:
- spin_unlock(&mchdev_lock);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(i915_gpu_busy);
-
-/**
- * i915_gpu_turbo_disable - disable graphics turbo
- *
- * Disable graphics turbo by resetting the max frequency and setting the
- * current frequency to the default.
- */
-bool i915_gpu_turbo_disable(void)
-{
- struct drm_i915_private *dev_priv;
- bool ret = true;
-
- spin_lock(&mchdev_lock);
- if (!i915_mch_dev) {
- ret = false;
- goto out_unlock;
- }
- dev_priv = i915_mch_dev;
-
- dev_priv->max_delay = dev_priv->fstart;
-
- if (!ironlake_set_drps(dev_priv->dev, dev_priv->fstart))
- ret = false;
-
-out_unlock:
- spin_unlock(&mchdev_lock);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(i915_gpu_turbo_disable);
-
-/**
- * Tells the intel_ips driver that the i915 driver is now loaded, if
- * IPS got loaded first.
- *
- * This awkward dance is so that neither module has to depend on the
- * other in order for IPS to do the appropriate communication of
- * GPU turbo limits to i915.
- */
-static void
-ips_ping_for_i915_load(void)
-{
- void (*link)(void);
-
- link = symbol_get(ips_link_to_i915_driver);
- if (link) {
- link();
- symbol_put(ips_link_to_i915_driver);
+ /* Set up a WC MTRR for non-PAT systems. This is more common than
+ * one would think, because the kernel disables PAT on first
+ * generation Core chips because WC PAT gets overridden by a UC
+ * MTRR if present. Even if a UC MTRR isn't present.
+ */
+ dev_priv->mm.gtt_mtrr = mtrr_add(base, size, MTRR_TYPE_WRCOMB, 1);
+ if (dev_priv->mm.gtt_mtrr < 0) {
+ DRM_INFO("MTRR allocation failed. Graphics "
+ "performance may suffer.\n");
}
}
@@ -1948,8 +1415,16 @@ ips_ping_for_i915_load(void)
int i915_driver_load(struct drm_device *dev, unsigned long flags)
{
struct drm_i915_private *dev_priv;
+ struct intel_device_info *info;
int ret = 0, mmio_bar;
- uint32_t agp_size;
+ uint32_t aperture_size;
+
+ info = (struct intel_device_info *) flags;
+
+ /* Refuse to load on gen6+ without kms enabled. */
+ if (info->gen >= 6 && !drm_core_check_feature(dev, DRIVER_MODESET))
+ return -ENODEV;
+
/* i915 has 4 more counters */
dev->counters += 4;
@@ -1964,7 +1439,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
dev->dev_private = (void *)dev_priv;
dev_priv->dev = dev;
- dev_priv->info = (struct intel_device_info *) flags;
+ dev_priv->info = info;
if (i915_get_bridge_dev(dev)) {
ret = -EIO;
@@ -2003,27 +1478,16 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
goto out_rmmap;
}
- agp_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
+ aperture_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
dev_priv->mm.gtt_mapping =
- io_mapping_create_wc(dev->agp->base, agp_size);
+ io_mapping_create_wc(dev->agp->base, aperture_size);
if (dev_priv->mm.gtt_mapping == NULL) {
ret = -EIO;
goto out_rmmap;
}
- /* Set up a WC MTRR for non-PAT systems. This is more common than
- * one would think, because the kernel disables PAT on first
- * generation Core chips because WC PAT gets overridden by a UC
- * MTRR if present. Even if a UC MTRR isn't present.
- */
- dev_priv->mm.gtt_mtrr = mtrr_add(dev->agp->base,
- agp_size,
- MTRR_TYPE_WRCOMB, 1);
- if (dev_priv->mm.gtt_mtrr < 0) {
- DRM_INFO("MTRR allocation failed. Graphics "
- "performance may suffer.\n");
- }
+ i915_mtrr_setup(dev_priv, dev->agp->base, aperture_size);
/* The i915 workqueue is primarily used for batched retirement of
* requests (and thus managing bo) once the task has been completed
@@ -2047,9 +1511,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
goto out_mtrrfree;
}
- /* enable GEM by default */
- dev_priv->has_gem = 1;
-
intel_irq_init(dev);
/* Try to make sure MCHBAR is enabled before poking at it */
@@ -2069,11 +1530,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
goto out_gem_unload;
}
- if (IS_PINEVIEW(dev))
- i915_pineview_get_mem_freq(dev);
- else if (IS_GEN5(dev))
- i915_ironlake_get_mem_freq(dev);
-
/* On the 945G/GM, the chipset reports the MSI capability on the
* integrated graphics even though the support isn't actually there
* according to the published specs. It doesn't appear to function
@@ -2093,7 +1549,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
spin_lock_init(&dev_priv->error_lock);
spin_lock_init(&dev_priv->rps_lock);
- if (IS_IVYBRIDGE(dev))
+ if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
dev_priv->num_pipe = 3;
else if (IS_MOBILE(dev) || !IS_GEN2(dev))
dev_priv->num_pipe = 2;
@@ -2117,6 +1573,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
}
}
+ i915_setup_sysfs(dev);
+
/* Must be done after probing outputs */
intel_opregion_init(dev);
acpi_video_register();
@@ -2124,14 +1582,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed,
(unsigned long) dev);
- if (IS_GEN5(dev)) {
- spin_lock(&mchdev_lock);
- i915_mch_dev = dev_priv;
- dev_priv->mchdev_lock = &mchdev_lock;
- spin_unlock(&mchdev_lock);
-
- ips_ping_for_i915_load();
- }
+ if (IS_GEN5(dev))
+ intel_gpu_ips_init(dev_priv);
return 0;
@@ -2166,17 +1618,18 @@ int i915_driver_unload(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
- spin_lock(&mchdev_lock);
- i915_mch_dev = NULL;
- spin_unlock(&mchdev_lock);
+ intel_gpu_ips_teardown();
+
+ i915_teardown_sysfs(dev);
if (dev_priv->mm.inactive_shrinker.shrink)
unregister_shrinker(&dev_priv->mm.inactive_shrinker);
mutex_lock(&dev->struct_mutex);
- ret = i915_gpu_idle(dev, true);
+ ret = i915_gpu_idle(dev);
if (ret)
DRM_ERROR("failed to idle hardware: %d\n", ret);
+ i915_gem_retire_requests(dev);
mutex_unlock(&dev->struct_mutex);
/* Cancel the retire work handler, which should be idle now. */
@@ -2228,8 +1681,7 @@ int i915_driver_unload(struct drm_device *dev)
i915_gem_cleanup_ringbuffer(dev);
mutex_unlock(&dev->struct_mutex);
i915_gem_cleanup_aliasing_ppgtt(dev);
- if (I915_HAS_FBC(dev) && i915_powersave)
- i915_cleanup_compression(dev);
+ i915_gem_cleanup_stolen(dev);
drm_mm_takedown(&dev_priv->mm.stolen);
intel_cleanup_overlay(dev);
@@ -2277,7 +1729,7 @@ int i915_driver_open(struct drm_device *dev, struct drm_file *file)
* mode setting case, we want to restore the kernel's initial mode (just
* in case the last client left us in a bad state).
*
- * Additionally, in the non-mode setting case, we'll tear down the AGP
+ * Additionally, in the non-mode setting case, we'll tear down the GTT
* and DMA structures, since the kernel won't be using them, and clea
* up any GEM state.
*/
@@ -2322,7 +1774,7 @@ struct drm_ioctl_desc i915_ioctls[] = {
DRM_IOCTL_DEF_DRV(I915_INIT_HEAP, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF_DRV(I915_CMDBUFFER, i915_cmdbuffer, DRM_AUTH),
DRM_IOCTL_DEF_DRV(I915_DESTROY_HEAP, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
- DRM_IOCTL_DEF_DRV(I915_SET_VBLANK_PIPE, i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
+ DRM_IOCTL_DEF_DRV(I915_SET_VBLANK_PIPE, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF_DRV(I915_GET_VBLANK_PIPE, i915_vblank_pipe_get, DRM_AUTH),
DRM_IOCTL_DEF_DRV(I915_VBLANK_SWAP, i915_vblank_swap, DRM_AUTH),
DRM_IOCTL_DEF_DRV(I915_HWS_ADDR, i915_set_status_page, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
@@ -2355,16 +1807,10 @@ struct drm_ioctl_desc i915_ioctls[] = {
int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
-/**
- * Determine if the device really is AGP or not.
- *
- * All Intel graphics chipsets are treated as AGP, even if they are really
- * PCI-e.
- *
- * \param dev The device to be tested.
- *
- * \returns
- * A value of 1 is always retured to indictate every i9x5 is AGP.
+/*
+ * This is really ugly: Because old userspace abused the linux agp interface to
+ * manage the gtt, we need to claim that all intel devices are agp. For
+ * otherwise the drm core refuses to initialize the agp support code.
*/
int i915_driver_device_is_agp(struct drm_device * dev)
{
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index ae8a64f9f845..238a52165833 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -84,6 +84,12 @@ MODULE_PARM_DESC(lvds_downclock,
"Use panel (LVDS/eDP) downclocking for power savings "
"(default: false)");
+int i915_lvds_channel_mode __read_mostly;
+module_param_named(lvds_channel_mode, i915_lvds_channel_mode, int, 0600);
+MODULE_PARM_DESC(lvds_channel_mode,
+ "Specify LVDS channel mode "
+ "(0=probe BIOS [default], 1=single-channel, 2=dual-channel)");
+
int i915_panel_use_ssc __read_mostly = -1;
module_param_named(lvds_use_ssc, i915_panel_use_ssc, int, 0600);
MODULE_PARM_DESC(lvds_use_ssc,
@@ -93,8 +99,8 @@ MODULE_PARM_DESC(lvds_use_ssc,
int i915_vbt_sdvo_panel_type __read_mostly = -1;
module_param_named(vbt_sdvo_panel_type, i915_vbt_sdvo_panel_type, int, 0600);
MODULE_PARM_DESC(vbt_sdvo_panel_type,
- "Override selection of SDVO panel mode in the VBT "
- "(default: auto)");
+ "Override/Ignore selection of SDVO panel mode in the VBT "
+ "(-2=ignore, -1=auto [default], index in VBT BIOS table)");
static bool i915_try_reset __read_mostly = true;
module_param_named(reset, i915_try_reset, bool, 0600);
@@ -209,6 +215,7 @@ static const struct intel_device_info intel_ironlake_d_info = {
.gen = 5,
.need_gfx_hws = 1, .has_hotplug = 1,
.has_bsd_ring = 1,
+ .has_pch_split = 1,
};
static const struct intel_device_info intel_ironlake_m_info = {
@@ -216,6 +223,7 @@ static const struct intel_device_info intel_ironlake_m_info = {
.need_gfx_hws = 1, .has_hotplug = 1,
.has_fbc = 1,
.has_bsd_ring = 1,
+ .has_pch_split = 1,
};
static const struct intel_device_info intel_sandybridge_d_info = {
@@ -224,6 +232,7 @@ static const struct intel_device_info intel_sandybridge_d_info = {
.has_bsd_ring = 1,
.has_blt_ring = 1,
.has_llc = 1,
+ .has_pch_split = 1,
};
static const struct intel_device_info intel_sandybridge_m_info = {
@@ -233,6 +242,7 @@ static const struct intel_device_info intel_sandybridge_m_info = {
.has_bsd_ring = 1,
.has_blt_ring = 1,
.has_llc = 1,
+ .has_pch_split = 1,
};
static const struct intel_device_info intel_ivybridge_d_info = {
@@ -241,6 +251,7 @@ static const struct intel_device_info intel_ivybridge_d_info = {
.has_bsd_ring = 1,
.has_blt_ring = 1,
.has_llc = 1,
+ .has_pch_split = 1,
};
static const struct intel_device_info intel_ivybridge_m_info = {
@@ -250,6 +261,43 @@ static const struct intel_device_info intel_ivybridge_m_info = {
.has_bsd_ring = 1,
.has_blt_ring = 1,
.has_llc = 1,
+ .has_pch_split = 1,
+};
+
+static const struct intel_device_info intel_valleyview_m_info = {
+ .gen = 7, .is_mobile = 1,
+ .need_gfx_hws = 1, .has_hotplug = 1,
+ .has_fbc = 0,
+ .has_bsd_ring = 1,
+ .has_blt_ring = 1,
+ .is_valleyview = 1,
+};
+
+static const struct intel_device_info intel_valleyview_d_info = {
+ .gen = 7,
+ .need_gfx_hws = 1, .has_hotplug = 1,
+ .has_fbc = 0,
+ .has_bsd_ring = 1,
+ .has_blt_ring = 1,
+ .is_valleyview = 1,
+};
+
+static const struct intel_device_info intel_haswell_d_info = {
+ .is_haswell = 1, .gen = 7,
+ .need_gfx_hws = 1, .has_hotplug = 1,
+ .has_bsd_ring = 1,
+ .has_blt_ring = 1,
+ .has_llc = 1,
+ .has_pch_split = 1,
+};
+
+static const struct intel_device_info intel_haswell_m_info = {
+ .is_haswell = 1, .gen = 7, .is_mobile = 1,
+ .need_gfx_hws = 1, .has_hotplug = 1,
+ .has_bsd_ring = 1,
+ .has_blt_ring = 1,
+ .has_llc = 1,
+ .has_pch_split = 1,
};
static const struct pci_device_id pciidlist[] = { /* aka */
@@ -297,6 +345,13 @@ static const struct pci_device_id pciidlist[] = { /* aka */
INTEL_VGA_DEVICE(0x0162, &intel_ivybridge_d_info), /* GT2 desktop */
INTEL_VGA_DEVICE(0x015a, &intel_ivybridge_d_info), /* GT1 server */
INTEL_VGA_DEVICE(0x016a, &intel_ivybridge_d_info), /* GT2 server */
+ INTEL_VGA_DEVICE(0x0402, &intel_haswell_d_info), /* GT1 desktop */
+ INTEL_VGA_DEVICE(0x0412, &intel_haswell_d_info), /* GT2 desktop */
+ INTEL_VGA_DEVICE(0x040a, &intel_haswell_d_info), /* GT1 server */
+ INTEL_VGA_DEVICE(0x041a, &intel_haswell_d_info), /* GT2 server */
+ INTEL_VGA_DEVICE(0x0406, &intel_haswell_m_info), /* GT1 mobile */
+ INTEL_VGA_DEVICE(0x0416, &intel_haswell_m_info), /* GT2 mobile */
+ INTEL_VGA_DEVICE(0x0c16, &intel_haswell_d_info), /* SDV */
{0, 0, 0}
};
@@ -308,6 +363,7 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
#define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00
#define INTEL_PCH_CPT_DEVICE_ID_TYPE 0x1c00
#define INTEL_PCH_PPT_DEVICE_ID_TYPE 0x1e00
+#define INTEL_PCH_LPT_DEVICE_ID_TYPE 0x8c00
void intel_detect_pch(struct drm_device *dev)
{
@@ -328,20 +384,45 @@ void intel_detect_pch(struct drm_device *dev)
if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) {
dev_priv->pch_type = PCH_IBX;
+ dev_priv->num_pch_pll = 2;
DRM_DEBUG_KMS("Found Ibex Peak PCH\n");
} else if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) {
dev_priv->pch_type = PCH_CPT;
+ dev_priv->num_pch_pll = 2;
DRM_DEBUG_KMS("Found CougarPoint PCH\n");
} else if (id == INTEL_PCH_PPT_DEVICE_ID_TYPE) {
/* PantherPoint is CPT compatible */
dev_priv->pch_type = PCH_CPT;
+ dev_priv->num_pch_pll = 2;
DRM_DEBUG_KMS("Found PatherPoint PCH\n");
+ } else if (id == INTEL_PCH_LPT_DEVICE_ID_TYPE) {
+ dev_priv->pch_type = PCH_LPT;
+ dev_priv->num_pch_pll = 0;
+ DRM_DEBUG_KMS("Found LynxPoint PCH\n");
}
+ BUG_ON(dev_priv->num_pch_pll > I915_NUM_PLLS);
}
pci_dev_put(pch);
}
}
+bool i915_semaphore_is_enabled(struct drm_device *dev)
+{
+ if (INTEL_INFO(dev)->gen < 6)
+ return 0;
+
+ if (i915_semaphores >= 0)
+ return i915_semaphores;
+
+#ifdef CONFIG_INTEL_IOMMU
+ /* Enable semaphores on SNB when IO remapping is off */
+ if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped)
+ return false;
+#endif
+
+ return 1;
+}
+
void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
{
int count;
@@ -366,7 +447,7 @@ void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv)
while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_MT_ACK) & 1))
udelay(10);
- I915_WRITE_NOTRACE(FORCEWAKE_MT, (1<<16) | 1);
+ I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_ENABLE(1));
POSTING_READ(FORCEWAKE_MT);
count = 0;
@@ -408,7 +489,7 @@ void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv)
{
- I915_WRITE_NOTRACE(FORCEWAKE_MT, (1<<16) | 0);
+ I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_DISABLE(1));
/* The below doubles as a POSTING_READ */
gen6_gt_check_fifodbg(dev_priv);
}
@@ -446,6 +527,31 @@ int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
return ret;
}
+void vlv_force_wake_get(struct drm_i915_private *dev_priv)
+{
+ int count;
+
+ count = 0;
+
+ /* Already awake? */
+ if ((I915_READ(0x130094) & 0xa1) == 0xa1)
+ return;
+
+ I915_WRITE_NOTRACE(FORCEWAKE_VLV, 0xffffffff);
+ POSTING_READ(FORCEWAKE_VLV);
+
+ count = 0;
+ while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & 1) == 0)
+ udelay(10);
+}
+
+void vlv_force_wake_put(struct drm_i915_private *dev_priv)
+{
+ I915_WRITE_NOTRACE(FORCEWAKE_VLV, 0xffff0000);
+ /* FIXME: confirm VLV behavior with Punit folks */
+ POSTING_READ(FORCEWAKE_VLV);
+}
+
static int i915_drm_freeze(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -525,15 +631,16 @@ static int i915_drm_thaw(struct drm_device *dev)
/* KMS EnterVT equivalent */
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+ if (HAS_PCH_SPLIT(dev))
+ ironlake_init_pch_refclk(dev);
+
mutex_lock(&dev->struct_mutex);
dev_priv->mm.suspended = 0;
error = i915_gem_init_hw(dev);
mutex_unlock(&dev->struct_mutex);
- if (HAS_PCH_SPLIT(dev))
- ironlake_init_pch_refclk(dev);
-
+ intel_modeset_init_hw(dev);
drm_mode_config_reset(dev);
drm_irq_install(dev);
@@ -541,9 +648,6 @@ static int i915_drm_thaw(struct drm_device *dev)
mutex_lock(&dev->mode_config.mutex);
drm_helper_resume_force_mode(dev);
mutex_unlock(&dev->mode_config.mutex);
-
- if (IS_IRONLAKE_M(dev))
- ironlake_enable_rc6(dev);
}
intel_opregion_init(dev);
@@ -576,7 +680,7 @@ int i915_resume(struct drm_device *dev)
return 0;
}
-static int i8xx_do_reset(struct drm_device *dev, u8 flags)
+static int i8xx_do_reset(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -610,11 +714,12 @@ static int i965_reset_complete(struct drm_device *dev)
{
u8 gdrst;
pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst);
- return gdrst & 0x1;
+ return (gdrst & GRDOM_RESET_ENABLE) == 0;
}
-static int i965_do_reset(struct drm_device *dev, u8 flags)
+static int i965_do_reset(struct drm_device *dev)
{
+ int ret;
u8 gdrst;
/*
@@ -623,20 +728,43 @@ static int i965_do_reset(struct drm_device *dev, u8 flags)
* triggers the reset; when done, the hardware will clear it.
*/
pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst);
- pci_write_config_byte(dev->pdev, I965_GDRST, gdrst | flags | 0x1);
+ pci_write_config_byte(dev->pdev, I965_GDRST,
+ gdrst | GRDOM_RENDER |
+ GRDOM_RESET_ENABLE);
+ ret = wait_for(i965_reset_complete(dev), 500);
+ if (ret)
+ return ret;
+
+ /* We can't reset render&media without also resetting display ... */
+ pci_read_config_byte(dev->pdev, I965_GDRST, &gdrst);
+ pci_write_config_byte(dev->pdev, I965_GDRST,
+ gdrst | GRDOM_MEDIA |
+ GRDOM_RESET_ENABLE);
return wait_for(i965_reset_complete(dev), 500);
}
-static int ironlake_do_reset(struct drm_device *dev, u8 flags)
+static int ironlake_do_reset(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR);
- I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR, gdrst | flags | 0x1);
+ u32 gdrst;
+ int ret;
+
+ gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR);
+ I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR,
+ gdrst | GRDOM_RENDER | GRDOM_RESET_ENABLE);
+ ret = wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500);
+ if (ret)
+ return ret;
+
+ /* We can't reset render&media without also resetting display ... */
+ gdrst = I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR);
+ I915_WRITE(MCHBAR_MIRROR_BASE + ILK_GDSR,
+ gdrst | GRDOM_MEDIA | GRDOM_RESET_ENABLE);
return wait_for(I915_READ(MCHBAR_MIRROR_BASE + ILK_GDSR) & 0x1, 500);
}
-static int gen6_do_reset(struct drm_device *dev, u8 flags)
+static int gen6_do_reset(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
@@ -671,10 +799,44 @@ static int gen6_do_reset(struct drm_device *dev, u8 flags)
return ret;
}
+static int intel_gpu_reset(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int ret = -ENODEV;
+
+ switch (INTEL_INFO(dev)->gen) {
+ case 7:
+ case 6:
+ ret = gen6_do_reset(dev);
+ break;
+ case 5:
+ ret = ironlake_do_reset(dev);
+ break;
+ case 4:
+ ret = i965_do_reset(dev);
+ break;
+ case 2:
+ ret = i8xx_do_reset(dev);
+ break;
+ }
+
+ /* Also reset the gpu hangman. */
+ if (dev_priv->stop_rings) {
+ DRM_DEBUG("Simulated gpu hang, resetting stop_rings\n");
+ dev_priv->stop_rings = 0;
+ if (ret == -ENODEV) {
+ DRM_ERROR("Reset not implemented, but ignoring "
+ "error for simulated gpu hangs\n");
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
/**
* i915_reset - reset chip after a hang
* @dev: drm device to reset
- * @flags: reset domains
*
* Reset the chip. Useful if a hang is detected. Returns zero on successful
* reset or otherwise an error code.
@@ -687,14 +849,9 @@ static int gen6_do_reset(struct drm_device *dev, u8 flags)
* - re-init interrupt state
* - re-init display
*/
-int i915_reset(struct drm_device *dev, u8 flags)
+int i915_reset(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- /*
- * We really should only reset the display subsystem if we actually
- * need to
- */
- bool need_display = true;
int ret;
if (!i915_try_reset)
@@ -703,26 +860,16 @@ int i915_reset(struct drm_device *dev, u8 flags)
if (!mutex_trylock(&dev->struct_mutex))
return -EBUSY;
+ dev_priv->stop_rings = 0;
+
i915_gem_reset(dev);
ret = -ENODEV;
- if (get_seconds() - dev_priv->last_gpu_reset < 5) {
+ if (get_seconds() - dev_priv->last_gpu_reset < 5)
DRM_ERROR("GPU hanging too fast, declaring wedged!\n");
- } else switch (INTEL_INFO(dev)->gen) {
- case 7:
- case 6:
- ret = gen6_do_reset(dev, flags);
- break;
- case 5:
- ret = ironlake_do_reset(dev, flags);
- break;
- case 4:
- ret = i965_do_reset(dev, flags);
- break;
- case 2:
- ret = i8xx_do_reset(dev, flags);
- break;
- }
+ else
+ ret = intel_gpu_reset(dev);
+
dev_priv->last_gpu_reset = get_seconds();
if (ret) {
DRM_ERROR("Failed to reset chip.\n");
@@ -746,36 +893,27 @@ int i915_reset(struct drm_device *dev, u8 flags)
*/
if (drm_core_check_feature(dev, DRIVER_MODESET) ||
!dev_priv->mm.suspended) {
+ struct intel_ring_buffer *ring;
+ int i;
+
dev_priv->mm.suspended = 0;
i915_gem_init_swizzling(dev);
- dev_priv->ring[RCS].init(&dev_priv->ring[RCS]);
- if (HAS_BSD(dev))
- dev_priv->ring[VCS].init(&dev_priv->ring[VCS]);
- if (HAS_BLT(dev))
- dev_priv->ring[BCS].init(&dev_priv->ring[BCS]);
+ for_each_ring(ring, dev_priv, i)
+ ring->init(ring);
i915_gem_init_ppgtt(dev);
mutex_unlock(&dev->struct_mutex);
- drm_irq_uninstall(dev);
- drm_mode_config_reset(dev);
- drm_irq_install(dev);
- mutex_lock(&dev->struct_mutex);
- }
- mutex_unlock(&dev->struct_mutex);
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ intel_modeset_init_hw(dev);
- /*
- * Perform a full modeset as on later generations, e.g. Ironlake, we may
- * need to retrain the display link and cannot just restore the register
- * values.
- */
- if (need_display) {
- mutex_lock(&dev->mode_config.mutex);
- drm_helper_resume_force_mode(dev);
- mutex_unlock(&dev->mode_config.mutex);
+ drm_irq_uninstall(dev);
+ drm_irq_install(dev);
+ } else {
+ mutex_unlock(&dev->struct_mutex);
}
return 0;
@@ -874,7 +1012,7 @@ static const struct dev_pm_ops i915_pm_ops = {
.restore = i915_pm_resume,
};
-static struct vm_operations_struct i915_gem_vm_ops = {
+static const struct vm_operations_struct i915_gem_vm_ops = {
.fault = i915_gem_fault,
.open = drm_gem_vm_open,
.close = drm_gem_vm_close,
@@ -901,7 +1039,7 @@ static struct drm_driver driver = {
*/
.driver_features =
DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/
- DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM,
+ DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM | DRIVER_PRIME,
.load = i915_driver_load,
.unload = i915_driver_unload,
.open = i915_driver_open,
@@ -924,6 +1062,12 @@ static struct drm_driver driver = {
.gem_init_object = i915_gem_init_object,
.gem_free_object = i915_gem_free_object,
.gem_vm_ops = &i915_gem_vm_ops,
+
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_export = i915_gem_prime_export,
+ .gem_prime_import = i915_gem_prime_import,
+
.dumb_create = i915_gem_dumb_create,
.dumb_map_offset = i915_gem_mmap_gtt,
.dumb_destroy = i915_gem_dumb_destroy,
@@ -993,6 +1137,13 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL and additional rights");
+/* We give fast paths for the really cool registers */
+#define NEEDS_FORCE_WAKE(dev_priv, reg) \
+ (((dev_priv)->info->gen >= 6) && \
+ ((reg) < 0x40000) && \
+ ((reg) != FORCEWAKE)) && \
+ (!IS_VALLEYVIEW((dev_priv)->dev))
+
#define __i915_read(x, y) \
u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \
u##x val = 0; \
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 5fabc6c31fec..377c21f531e4 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -38,6 +38,8 @@
#include <linux/i2c-algo-bit.h>
#include <drm/intel-gtt.h>
#include <linux/backlight.h>
+#include <linux/intel-iommu.h>
+#include <linux/kref.h>
/* General customization:
*/
@@ -63,10 +65,30 @@ enum plane {
};
#define plane_name(p) ((p) + 'A')
+enum port {
+ PORT_A = 0,
+ PORT_B,
+ PORT_C,
+ PORT_D,
+ PORT_E,
+ I915_MAX_PORTS
+};
+#define port_name(p) ((p) + 'A')
+
#define I915_GEM_GPU_DOMAINS (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT))
#define for_each_pipe(p) for ((p) = 0; (p) < dev_priv->num_pipe; (p)++)
+struct intel_pch_pll {
+ int refcount; /* count of number of CRTCs sharing this PLL */
+ int active; /* count of number of active CRTCs (i.e. DPMS on) */
+ bool on; /* is the PLL actually active? Disabled during modeset */
+ int pll_reg;
+ int fp0_reg;
+ int fp1_reg;
+};
+#define I915_NUM_PLLS 2
+
/* Interface history:
*
* 1.1: Original.
@@ -111,11 +133,11 @@ struct opregion_asle;
struct drm_i915_private;
struct intel_opregion {
- struct opregion_header *header;
- struct opregion_acpi *acpi;
- struct opregion_swsci *swsci;
- struct opregion_asle *asle;
- void *vbt;
+ struct opregion_header __iomem *header;
+ struct opregion_acpi __iomem *acpi;
+ struct opregion_swsci __iomem *swsci;
+ struct opregion_asle __iomem *asle;
+ void __iomem *vbt;
u32 __iomem *lid_state;
};
#define OPREGION_SIZE (8*1024)
@@ -135,7 +157,6 @@ struct drm_i915_master_private {
struct drm_i915_fence_reg {
struct list_head lru_list;
struct drm_i915_gem_object *obj;
- uint32_t setup_seqno;
int pin_count;
};
@@ -151,8 +172,11 @@ struct sdvo_device_mapping {
struct intel_display_error_state;
struct drm_i915_error_state {
+ struct kref ref;
u32 eir;
u32 pgtbl_er;
+ u32 ier;
+ bool waiting[I915_NUM_RINGS];
u32 pipestat[I915_MAX_PIPES];
u32 tail[I915_NUM_RINGS];
u32 head[I915_NUM_RINGS];
@@ -218,11 +242,15 @@ struct drm_i915_display_funcs {
void (*update_wm)(struct drm_device *dev);
void (*update_sprite_wm)(struct drm_device *dev, int pipe,
uint32_t sprite_width, int pixel_size);
+ void (*sanitize_pm)(struct drm_device *dev);
+ void (*update_linetime_wm)(struct drm_device *dev, int pipe,
+ struct drm_display_mode *mode);
int (*crtc_mode_set)(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode,
int x, int y,
struct drm_framebuffer *old_fb);
+ void (*off)(struct drm_crtc *crtc);
void (*write_eld)(struct drm_connector *connector,
struct drm_crtc *crtc);
void (*fdi_link_train)(struct drm_crtc *crtc);
@@ -255,6 +283,9 @@ struct intel_device_info {
u8 is_broadwater:1;
u8 is_crestline:1;
u8 is_ivybridge:1;
+ u8 is_valleyview:1;
+ u8 has_pch_split:1;
+ u8 is_haswell:1;
u8 has_fbc:1;
u8 has_pipe_cxsr:1;
u8 has_hotplug:1;
@@ -291,10 +322,12 @@ enum no_fbc_reason {
enum intel_pch {
PCH_IBX, /* Ibexpeak PCH */
PCH_CPT, /* Cougarpoint PCH */
+ PCH_LPT, /* Lynxpoint PCH */
};
#define QUIRK_PIPEA_FORCE (1<<0)
#define QUIRK_LVDS_SSC_DISABLE (1<<1)
+#define QUIRK_INVERT_BRIGHTNESS (1<<2)
struct intel_fbdev;
struct intel_fbc_work;
@@ -302,7 +335,6 @@ struct intel_fbc_work;
struct intel_gmbus {
struct i2c_adapter adapter;
bool force_bit;
- bool has_gpio;
u32 reg0;
u32 gpio_reg;
struct i2c_algo_bit_data bit_algo;
@@ -314,7 +346,6 @@ typedef struct drm_i915_private {
const struct intel_device_info *info;
- int has_gem;
int relative_constants_mode;
void __iomem *regs;
@@ -326,19 +357,23 @@ typedef struct drm_i915_private {
/** gt_lock is also taken in irq contexts. */
struct spinlock gt_lock;
- struct intel_gmbus *gmbus;
+ struct intel_gmbus gmbus[GMBUS_NUM_PORTS];
/** gmbus_mutex protects against concurrent usage of the single hw gmbus
* controller on different i2c buses. */
struct mutex gmbus_mutex;
+ /**
+ * Base address of the gmbus and gpio block.
+ */
+ uint32_t gpio_mmio_base;
+
struct pci_dev *bridge_dev;
struct intel_ring_buffer ring[I915_NUM_RINGS];
uint32_t next_seqno;
drm_dma_handle_t *status_page_dmah;
uint32_t counter;
- drm_local_map_t hws_map;
struct drm_i915_gem_object *pwrctx;
struct drm_i915_gem_object *renderctx;
@@ -354,6 +389,10 @@ typedef struct drm_i915_private {
/* protects the irq masks */
spinlock_t irq_lock;
+
+ /* DPIO indirect register protection */
+ spinlock_t dpio_lock;
+
/** Cached value of IMR to avoid reads in updating the bitfield */
u32 pipestat[2];
u32 irq_mask;
@@ -363,22 +402,20 @@ typedef struct drm_i915_private {
u32 hotplug_supported_mask;
struct work_struct hotplug_work;
- int tex_lru_log_granularity;
- int allow_batchbuffer;
unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
- int vblank_pipe;
int num_pipe;
+ int num_pch_pll;
/* For hangcheck timer */
#define DRM_I915_HANGCHECK_PERIOD 1500 /* in ms */
struct timer_list hangcheck_timer;
int hangcheck_count;
- uint32_t last_acthd;
- uint32_t last_acthd_bsd;
- uint32_t last_acthd_blt;
+ uint32_t last_acthd[I915_NUM_RINGS];
uint32_t last_instdone;
uint32_t last_instdone1;
+ unsigned int stop_rings;
+
unsigned long cfb_size;
unsigned int cfb_fb;
enum plane cfb_plane;
@@ -405,6 +442,8 @@ typedef struct drm_i915_private {
unsigned int lvds_use_ssc:1;
unsigned int display_clock_mode:1;
int lvds_ssc_freq;
+ unsigned int bios_lvds_val; /* initial [PCH_]LVDS reg val in VBIOS */
+ unsigned int lvds_val; /* used for checking LVDS channel mode */
struct {
int rate;
int lanes;
@@ -428,6 +467,7 @@ typedef struct drm_i915_private {
unsigned int fsb_freq, mem_freq, is_ddr3;
spinlock_t error_lock;
+ /* Protected by dev->error_lock. */
struct drm_i915_error_state *first_error;
struct work_struct error_work;
struct completion error_completion;
@@ -652,24 +692,10 @@ typedef struct drm_i915_private {
*/
struct list_head inactive_list;
- /**
- * LRU list of objects which are not in the ringbuffer but
- * are still pinned in the GTT.
- */
- struct list_head pinned_list;
-
/** LRU list of objects with fence regs on them. */
struct list_head fence_list;
/**
- * List of objects currently pending being freed.
- *
- * These objects are no longer in use, but due to a signal
- * we were prevented from freeing them at the appointed time.
- */
- struct list_head deferred_free_list;
-
- /**
* We leave the user IRQ off as much as possible,
* but this means that requests will finish and never
* be retired once the system goes idle. Set a timer to
@@ -717,6 +743,16 @@ typedef struct drm_i915_private {
size_t object_memory;
u32 object_count;
} mm;
+
+ /* Old dri1 support infrastructure, beware the dragons ya fools entering
+ * here! */
+ struct {
+ unsigned allow_batchbuffer : 1;
+ u32 __iomem *gfx_hws_cpu_addr;
+ } dri1;
+
+ /* Kernel Modesetting */
+
struct sdvo_device_mapping sdvo_mappings[2];
/* indicate whether the LVDS_BORDER should be enabled or not */
unsigned int lvds_border_bits;
@@ -726,7 +762,8 @@ typedef struct drm_i915_private {
struct drm_crtc *plane_to_crtc_mapping[3];
struct drm_crtc *pipe_to_crtc_mapping[3];
wait_queue_head_t pending_flip_queue;
- bool flip_pending_is_done;
+
+ struct intel_pch_pll pch_plls[I915_NUM_PLLS];
/* Reclocking support */
bool render_reclock_avail;
@@ -781,6 +818,11 @@ typedef struct drm_i915_private {
struct drm_property *force_audio_property;
} drm_i915_private_t;
+/* Iterate over initialised rings */
+#define for_each_ring(ring__, dev_priv__, i__) \
+ for ((i__) = 0; (i__) < I915_NUM_RINGS; (i__)++) \
+ if (((ring__) = &(dev_priv__)->ring[(i__)]), intel_ring_initialized((ring__)))
+
enum hdmi_force_audio {
HDMI_AUDIO_OFF_DVI = -2, /* no aux data for HDMI-DVI converter */
HDMI_AUDIO_OFF, /* force turn off HDMI audio */
@@ -844,7 +886,14 @@ struct drm_i915_gem_object {
* Current tiling mode for the object.
*/
unsigned int tiling_mode:2;
- unsigned int tiling_changed:1;
+ /**
+ * Whether the tiling parameters for the currently associated fence
+ * register have changed. Note that for the purposes of tracking
+ * tiling changes we also treat the unfenced register, the register
+ * slot that the object occupies whilst it executes a fenced
+ * command (such as BLT on gen2/3), as a "fence".
+ */
+ unsigned int fence_dirty:1;
/** How many users have pinned this object in GTT space. The following
* users can each hold at most one reference: pwrite/pread, pin_ioctl
@@ -881,6 +930,7 @@ struct drm_i915_gem_object {
unsigned int cache_level:2;
unsigned int has_aliasing_ppgtt_mapping:1;
+ unsigned int has_global_gtt_mapping:1;
struct page **pages;
@@ -890,6 +940,8 @@ struct drm_i915_gem_object {
struct scatterlist *sg_list;
int num_sg;
+ /* prime dma-buf support */
+ struct sg_table *sg_table;
/**
* Used for performing relocations during execbuffer insertion.
*/
@@ -904,13 +956,12 @@ struct drm_i915_gem_object {
*/
uint32_t gtt_offset;
- /** Breadcrumb of last rendering to the buffer. */
- uint32_t last_rendering_seqno;
struct intel_ring_buffer *ring;
+ /** Breadcrumb of last rendering to the buffer. */
+ uint32_t last_rendering_seqno;
/** Breadcrumb of last fenced GPU access to the buffer. */
uint32_t last_fenced_seqno;
- struct intel_ring_buffer *last_fenced_ring;
/** Current tiling stride for the object, if it's tiled. */
uint32_t stride;
@@ -918,13 +969,6 @@ struct drm_i915_gem_object {
/** Record of address bit 17 of each page at last unbind. */
unsigned long *bit_17;
-
- /**
- * If present, while GEM_DOMAIN_CPU is in the read domain this array
- * flags which individual pages are valid.
- */
- uint8_t *page_cpu_valid;
-
/** User space pin count and filp owning the pin */
uint32_t user_pin_count;
struct drm_file *pin_filp;
@@ -1001,6 +1045,8 @@ struct drm_i915_file_private {
#define IS_IRONLAKE_D(dev) ((dev)->pci_device == 0x0042)
#define IS_IRONLAKE_M(dev) ((dev)->pci_device == 0x0046)
#define IS_IVYBRIDGE(dev) (INTEL_INFO(dev)->is_ivybridge)
+#define IS_VALLEYVIEW(dev) (INTEL_INFO(dev)->is_valleyview)
+#define IS_HASWELL(dev) (INTEL_INFO(dev)->is_haswell)
#define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile)
/*
@@ -1044,10 +1090,11 @@ struct drm_i915_file_private {
#define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr)
#define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc)
-#define HAS_PCH_SPLIT(dev) (IS_GEN5(dev) || IS_GEN6(dev) || IS_IVYBRIDGE(dev))
+#define HAS_PCH_SPLIT(dev) (INTEL_INFO(dev)->has_pch_split)
#define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5)
#define INTEL_PCH_TYPE(dev) (((struct drm_i915_private *)(dev)->dev_private)->pch_type)
+#define HAS_PCH_LPT(dev) (INTEL_PCH_TYPE(dev) == PCH_LPT)
#define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT)
#define HAS_PCH_IBX(dev) (INTEL_PCH_TYPE(dev) == PCH_IBX)
@@ -1081,6 +1128,7 @@ extern int i915_panel_ignore_lid __read_mostly;
extern unsigned int i915_powersave __read_mostly;
extern int i915_semaphores __read_mostly;
extern unsigned int i915_lvds_downclock __read_mostly;
+extern int i915_lvds_channel_mode __read_mostly;
extern int i915_panel_use_ssc __read_mostly;
extern int i915_vbt_sdvo_panel_type __read_mostly;
extern int i915_enable_rc6 __read_mostly;
@@ -1094,6 +1142,7 @@ extern int i915_master_create(struct drm_device *dev, struct drm_master *master)
extern void i915_master_destroy(struct drm_device *dev, struct drm_master *master);
/* i915_dma.c */
+void i915_update_dri1_breadcrumb(struct drm_device *dev);
extern void i915_kernel_lost_context(struct drm_device * dev);
extern int i915_driver_load(struct drm_device *, unsigned long flags);
extern int i915_driver_unload(struct drm_device *);
@@ -1104,12 +1153,14 @@ extern void i915_driver_preclose(struct drm_device *dev,
extern void i915_driver_postclose(struct drm_device *dev,
struct drm_file *file_priv);
extern int i915_driver_device_is_agp(struct drm_device * dev);
+#ifdef CONFIG_COMPAT
extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
+#endif
extern int i915_emit_box(struct drm_device *dev,
struct drm_clip_rect *box,
int DR1, int DR4);
-extern int i915_reset(struct drm_device *dev, u8 flags);
+extern int i915_reset(struct drm_device *dev);
extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv);
extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv);
extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv);
@@ -1119,19 +1170,10 @@ extern void i915_update_gfx_val(struct drm_i915_private *dev_priv);
/* i915_irq.c */
void i915_hangcheck_elapsed(unsigned long data);
void i915_handle_error(struct drm_device *dev, bool wedged);
-extern int i915_irq_emit(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-extern int i915_irq_wait(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
extern void intel_irq_init(struct drm_device *dev);
-extern int i915_vblank_pipe_set(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-extern int i915_vblank_pipe_get(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-extern int i915_vblank_swap(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
+void i915_error_state_free(struct kref *error_ref);
void
i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);
@@ -1205,8 +1247,12 @@ int __must_check i915_gem_object_unbind(struct drm_i915_gem_object *obj);
void i915_gem_release_mmap(struct drm_i915_gem_object *obj);
void i915_gem_lastclose(struct drm_device *dev);
+int i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj,
+ gfp_t gfpmask);
int __must_check i915_mutex_lock_interruptible(struct drm_device *dev);
int __must_check i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj);
+int i915_gem_object_sync(struct drm_i915_gem_object *obj,
+ struct intel_ring_buffer *to);
void i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
struct intel_ring_buffer *ring,
u32 seqno);
@@ -1229,17 +1275,18 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2)
u32 i915_gem_next_request_seqno(struct intel_ring_buffer *ring);
-int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj,
- struct intel_ring_buffer *pipelined);
+int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj);
int __must_check i915_gem_object_put_fence(struct drm_i915_gem_object *obj);
-static inline void
+static inline bool
i915_gem_object_pin_fence(struct drm_i915_gem_object *obj)
{
if (obj->fence_reg != I915_FENCE_REG_NONE) {
struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
dev_priv->fence_regs[obj->fence_reg].pin_count++;
- }
+ return true;
+ } else
+ return false;
}
static inline void
@@ -1260,27 +1307,25 @@ int __must_check i915_gem_object_set_domain(struct drm_i915_gem_object *obj,
uint32_t read_domains,
uint32_t write_domain);
int __must_check i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj);
+int __must_check i915_gem_init(struct drm_device *dev);
int __must_check i915_gem_init_hw(struct drm_device *dev);
void i915_gem_init_swizzling(struct drm_device *dev);
void i915_gem_init_ppgtt(struct drm_device *dev);
void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
-void i915_gem_do_init(struct drm_device *dev,
- unsigned long start,
- unsigned long mappable_end,
- unsigned long end);
-int __must_check i915_gpu_idle(struct drm_device *dev, bool do_retire);
+int __must_check i915_gpu_idle(struct drm_device *dev);
int __must_check i915_gem_idle(struct drm_device *dev);
int __must_check i915_add_request(struct intel_ring_buffer *ring,
struct drm_file *file,
struct drm_i915_gem_request *request);
int __must_check i915_wait_request(struct intel_ring_buffer *ring,
- uint32_t seqno,
- bool do_retire);
+ uint32_t seqno);
int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
int __must_check
i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj,
bool write);
int __must_check
+i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write);
+int __must_check
i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
u32 alignment,
struct intel_ring_buffer *pipelined);
@@ -1301,6 +1346,13 @@ i915_gem_get_unfenced_gtt_alignment(struct drm_device *dev,
int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
enum i915_cache_level cache_level);
+struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *dma_buf);
+
+struct dma_buf *i915_gem_prime_export(struct drm_device *dev,
+ struct drm_gem_object *gem_obj, int flags);
+
+
/* i915_gem_gtt.c */
int __must_check i915_gem_init_aliasing_ppgtt(struct drm_device *dev);
void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev);
@@ -1311,18 +1363,24 @@ void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
struct drm_i915_gem_object *obj);
void i915_gem_restore_gtt_mappings(struct drm_device *dev);
-int __must_check i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj);
-void i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj,
+int __must_check i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj);
+void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj,
enum i915_cache_level cache_level);
void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj);
+void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj);
+void i915_gem_init_global_gtt(struct drm_device *dev,
+ unsigned long start,
+ unsigned long mappable_end,
+ unsigned long end);
/* i915_gem_evict.c */
int __must_check i915_gem_evict_something(struct drm_device *dev, int min_size,
unsigned alignment, bool mappable);
-int __must_check i915_gem_evict_everything(struct drm_device *dev,
- bool purgeable_only);
-int __must_check i915_gem_evict_inactive(struct drm_device *dev,
- bool purgeable_only);
+int i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only);
+
+/* i915_gem_stolen.c */
+int i915_gem_init_stolen(struct drm_device *dev);
+void i915_gem_cleanup_stolen(struct drm_device *dev);
/* i915_gem_tiling.c */
void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
@@ -1354,9 +1412,20 @@ extern int i915_restore_state(struct drm_device *dev);
extern int i915_save_state(struct drm_device *dev);
extern int i915_restore_state(struct drm_device *dev);
+/* i915_sysfs.c */
+void i915_setup_sysfs(struct drm_device *dev_priv);
+void i915_teardown_sysfs(struct drm_device *dev_priv);
+
/* intel_i2c.c */
extern int intel_setup_gmbus(struct drm_device *dev);
extern void intel_teardown_gmbus(struct drm_device *dev);
+extern inline bool intel_gmbus_is_port_valid(unsigned port)
+{
+ return (port >= GMBUS_PORT_SSC && port <= GMBUS_PORT_DPD);
+}
+
+extern struct i2c_adapter *intel_gmbus_get_adapter(
+ struct drm_i915_private *dev_priv, unsigned port);
extern void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed);
extern void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit);
extern inline bool intel_gmbus_is_forced_bit(struct i2c_adapter *adapter)
@@ -1391,6 +1460,7 @@ static inline void intel_unregister_dsm_handler(void) { return; }
#endif /* CONFIG_ACPI */
/* modesetting */
+extern void intel_modeset_init_hw(struct drm_device *dev);
extern void intel_modeset_init(struct drm_device *dev);
extern void intel_modeset_gem_init(struct drm_device *dev);
extern void intel_modeset_cleanup(struct drm_device *dev);
@@ -1403,12 +1473,17 @@ extern void ironlake_enable_rc6(struct drm_device *dev);
extern void gen6_set_rps(struct drm_device *dev, u8 val);
extern void intel_detect_pch(struct drm_device *dev);
extern int intel_trans_dp_port_sel(struct drm_crtc *crtc);
+extern int intel_enable_rc6(const struct drm_device *dev);
+extern bool i915_semaphore_is_enabled(struct drm_device *dev);
extern void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv);
extern void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv);
extern void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv);
extern void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv);
+extern void vlv_force_wake_get(struct drm_i915_private *dev_priv);
+extern void vlv_force_wake_put(struct drm_i915_private *dev_priv);
+
/* overlay */
#ifdef CONFIG_DEBUG_FS
extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev);
@@ -1420,28 +1495,6 @@ extern void intel_display_print_error_state(struct seq_file *m,
struct intel_display_error_state *error);
#endif
-#define LP_RING(d) (&((struct drm_i915_private *)(d))->ring[RCS])
-
-#define BEGIN_LP_RING(n) \
- intel_ring_begin(LP_RING(dev_priv), (n))
-
-#define OUT_RING(x) \
- intel_ring_emit(LP_RING(dev_priv), x)
-
-#define ADVANCE_LP_RING() \
- intel_ring_advance(LP_RING(dev_priv))
-
-/**
- * Lock test for when it's just for synchronization of ring access.
- *
- * In that case, we don't need to do it when GEM is initialized as nobody else
- * has access to the ring.
- */
-#define RING_LOCK_TEST_WITH_RETURN(dev, file) do { \
- if (LP_RING(dev->dev_private)->obj == NULL) \
- LOCK_TEST_WITH_RETURN(dev, file); \
-} while (0)
-
/* On SNB platform, before reading ring registers forcewake bit
* must be set to prevent GT core from power down and stale values being
* returned.
@@ -1450,12 +1503,6 @@ void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv);
void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv);
int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
-/* We give fast paths for the really cool registers */
-#define NEEDS_FORCE_WAKE(dev_priv, reg) \
- (((dev_priv)->info->gen >= 6) && \
- ((reg) < 0x40000) && \
- ((reg) != FORCEWAKE))
-
#define __i915_read(x, y) \
u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 0d1e4b7b4b99..c1e5c66553df 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -35,31 +35,41 @@
#include <linux/slab.h>
#include <linux/swap.h>
#include <linux/pci.h>
+#include <linux/dma-buf.h>
static __must_check int i915_gem_object_flush_gpu_write_domain(struct drm_i915_gem_object *obj);
static void i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj);
static void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj);
-static __must_check int i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj,
- bool write);
-static __must_check int i915_gem_object_set_cpu_read_domain_range(struct drm_i915_gem_object *obj,
- uint64_t offset,
- uint64_t size);
-static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_i915_gem_object *obj);
static __must_check int i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
unsigned alignment,
bool map_and_fenceable);
-static void i915_gem_clear_fence_reg(struct drm_device *dev,
- struct drm_i915_fence_reg *reg);
static int i915_gem_phys_pwrite(struct drm_device *dev,
struct drm_i915_gem_object *obj,
struct drm_i915_gem_pwrite *args,
struct drm_file *file);
-static void i915_gem_free_object_tail(struct drm_i915_gem_object *obj);
+
+static void i915_gem_write_fence(struct drm_device *dev, int reg,
+ struct drm_i915_gem_object *obj);
+static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
+ struct drm_i915_fence_reg *fence,
+ bool enable);
static int i915_gem_inactive_shrink(struct shrinker *shrinker,
struct shrink_control *sc);
static void i915_gem_object_truncate(struct drm_i915_gem_object *obj);
+static inline void i915_gem_object_fence_lost(struct drm_i915_gem_object *obj)
+{
+ if (obj->tiling_mode)
+ i915_gem_release_mmap(obj);
+
+ /* As we do not have an associated fence register, we will force
+ * a tiling change if we ever need to acquire one.
+ */
+ obj->fence_dirty = false;
+ obj->fence_reg = I915_FENCE_REG_NONE;
+}
+
/* some bookkeeping */
static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv,
size_t size)
@@ -122,26 +132,7 @@ int i915_mutex_lock_interruptible(struct drm_device *dev)
static inline bool
i915_gem_object_is_inactive(struct drm_i915_gem_object *obj)
{
- return obj->gtt_space && !obj->active && obj->pin_count == 0;
-}
-
-void i915_gem_do_init(struct drm_device *dev,
- unsigned long start,
- unsigned long mappable_end,
- unsigned long end)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
-
- drm_mm_init(&dev_priv->mm.gtt_space, start, end - start);
-
- dev_priv->mm.gtt_start = start;
- dev_priv->mm.gtt_mappable_end = mappable_end;
- dev_priv->mm.gtt_end = end;
- dev_priv->mm.gtt_total = end - start;
- dev_priv->mm.mappable_gtt_total = min(end, mappable_end) - start;
-
- /* Take over this portion of the GTT */
- intel_gtt_clear_range(start / PAGE_SIZE, (end-start) / PAGE_SIZE);
+ return !obj->active;
}
int
@@ -150,12 +141,20 @@ i915_gem_init_ioctl(struct drm_device *dev, void *data,
{
struct drm_i915_gem_init *args = data;
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
+ return -ENODEV;
+
if (args->gtt_start >= args->gtt_end ||
(args->gtt_end | args->gtt_start) & (PAGE_SIZE - 1))
return -EINVAL;
+ /* GEM with user mode setting was never supported on ilk and later. */
+ if (INTEL_INFO(dev)->gen >= 5)
+ return -ENODEV;
+
mutex_lock(&dev->struct_mutex);
- i915_gem_do_init(dev, args->gtt_start, args->gtt_end, args->gtt_end);
+ i915_gem_init_global_gtt(dev, args->gtt_start,
+ args->gtt_end, args->gtt_end);
mutex_unlock(&dev->struct_mutex);
return 0;
@@ -170,13 +169,11 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
struct drm_i915_gem_object *obj;
size_t pinned;
- if (!(dev->driver->driver_features & DRIVER_GEM))
- return -ENODEV;
-
pinned = 0;
mutex_lock(&dev->struct_mutex);
- list_for_each_entry(obj, &dev_priv->mm.pinned_list, mm_list)
- pinned += obj->gtt_space->size;
+ list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list)
+ if (obj->pin_count)
+ pinned += obj->gtt_space->size;
mutex_unlock(&dev->struct_mutex);
args->aper_size = dev_priv->mm.gtt_total;
@@ -247,6 +244,7 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data,
struct drm_file *file)
{
struct drm_i915_gem_create *args = data;
+
return i915_gem_create(file, dev,
args->size, &args->handle);
}
@@ -259,66 +257,6 @@ static int i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj)
obj->tiling_mode != I915_TILING_NONE;
}
-/**
- * This is the fast shmem pread path, which attempts to copy_from_user directly
- * from the backing pages of the object to the user's address space. On a
- * fault, it fails so we can fall back to i915_gem_shmem_pwrite_slow().
- */
-static int
-i915_gem_shmem_pread_fast(struct drm_device *dev,
- struct drm_i915_gem_object *obj,
- struct drm_i915_gem_pread *args,
- struct drm_file *file)
-{
- struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
- ssize_t remain;
- loff_t offset;
- char __user *user_data;
- int page_offset, page_length;
-
- user_data = (char __user *) (uintptr_t) args->data_ptr;
- remain = args->size;
-
- offset = args->offset;
-
- while (remain > 0) {
- struct page *page;
- char *vaddr;
- int ret;
-
- /* Operation in this page
- *
- * page_offset = offset within page
- * page_length = bytes to copy for this page
- */
- page_offset = offset_in_page(offset);
- page_length = remain;
- if ((page_offset + remain) > PAGE_SIZE)
- page_length = PAGE_SIZE - page_offset;
-
- page = shmem_read_mapping_page(mapping, offset >> PAGE_SHIFT);
- if (IS_ERR(page))
- return PTR_ERR(page);
-
- vaddr = kmap_atomic(page);
- ret = __copy_to_user_inatomic(user_data,
- vaddr + page_offset,
- page_length);
- kunmap_atomic(vaddr);
-
- mark_page_accessed(page);
- page_cache_release(page);
- if (ret)
- return -EFAULT;
-
- remain -= page_length;
- user_data += page_length;
- offset += page_length;
- }
-
- return 0;
-}
-
static inline int
__copy_to_user_swizzled(char __user *cpu_vaddr,
const char *gpu_vaddr, int gpu_offset,
@@ -346,8 +284,8 @@ __copy_to_user_swizzled(char __user *cpu_vaddr,
}
static inline int
-__copy_from_user_swizzled(char __user *gpu_vaddr, int gpu_offset,
- const char *cpu_vaddr,
+__copy_from_user_swizzled(char *gpu_vaddr, int gpu_offset,
+ const char __user *cpu_vaddr,
int length)
{
int ret, cpu_offset = 0;
@@ -371,37 +309,121 @@ __copy_from_user_swizzled(char __user *gpu_vaddr, int gpu_offset,
return 0;
}
-/**
- * This is the fallback shmem pread path, which allocates temporary storage
- * in kernel space to copy_to_user into outside of the struct_mutex, so we
- * can copy out of the object's backing pages while holding the struct mutex
- * and not take page faults.
- */
+/* Per-page copy function for the shmem pread fastpath.
+ * Flushes invalid cachelines before reading the target if
+ * needs_clflush is set. */
static int
-i915_gem_shmem_pread_slow(struct drm_device *dev,
- struct drm_i915_gem_object *obj,
- struct drm_i915_gem_pread *args,
- struct drm_file *file)
+shmem_pread_fast(struct page *page, int shmem_page_offset, int page_length,
+ char __user *user_data,
+ bool page_do_bit17_swizzling, bool needs_clflush)
+{
+ char *vaddr;
+ int ret;
+
+ if (unlikely(page_do_bit17_swizzling))
+ return -EINVAL;
+
+ vaddr = kmap_atomic(page);
+ if (needs_clflush)
+ drm_clflush_virt_range(vaddr + shmem_page_offset,
+ page_length);
+ ret = __copy_to_user_inatomic(user_data,
+ vaddr + shmem_page_offset,
+ page_length);
+ kunmap_atomic(vaddr);
+
+ return ret;
+}
+
+static void
+shmem_clflush_swizzled_range(char *addr, unsigned long length,
+ bool swizzled)
+{
+ if (unlikely(swizzled)) {
+ unsigned long start = (unsigned long) addr;
+ unsigned long end = (unsigned long) addr + length;
+
+ /* For swizzling simply ensure that we always flush both
+ * channels. Lame, but simple and it works. Swizzled
+ * pwrite/pread is far from a hotpath - current userspace
+ * doesn't use it at all. */
+ start = round_down(start, 128);
+ end = round_up(end, 128);
+
+ drm_clflush_virt_range((void *)start, end - start);
+ } else {
+ drm_clflush_virt_range(addr, length);
+ }
+
+}
+
+/* Only difference to the fast-path function is that this can handle bit17
+ * and uses non-atomic copy and kmap functions. */
+static int
+shmem_pread_slow(struct page *page, int shmem_page_offset, int page_length,
+ char __user *user_data,
+ bool page_do_bit17_swizzling, bool needs_clflush)
+{
+ char *vaddr;
+ int ret;
+
+ vaddr = kmap(page);
+ if (needs_clflush)
+ shmem_clflush_swizzled_range(vaddr + shmem_page_offset,
+ page_length,
+ page_do_bit17_swizzling);
+
+ if (page_do_bit17_swizzling)
+ ret = __copy_to_user_swizzled(user_data,
+ vaddr, shmem_page_offset,
+ page_length);
+ else
+ ret = __copy_to_user(user_data,
+ vaddr + shmem_page_offset,
+ page_length);
+ kunmap(page);
+
+ return ret;
+}
+
+static int
+i915_gem_shmem_pread(struct drm_device *dev,
+ struct drm_i915_gem_object *obj,
+ struct drm_i915_gem_pread *args,
+ struct drm_file *file)
{
struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
char __user *user_data;
ssize_t remain;
loff_t offset;
- int shmem_page_offset, page_length, ret;
+ int shmem_page_offset, page_length, ret = 0;
int obj_do_bit17_swizzling, page_do_bit17_swizzling;
+ int hit_slowpath = 0;
+ int prefaulted = 0;
+ int needs_clflush = 0;
+ int release_page;
user_data = (char __user *) (uintptr_t) args->data_ptr;
remain = args->size;
obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
- offset = args->offset;
+ if (!(obj->base.read_domains & I915_GEM_DOMAIN_CPU)) {
+ /* If we're not in the cpu read domain, set ourself into the gtt
+ * read domain and manually flush cachelines (if required). This
+ * optimizes for the case when the gpu will dirty the data
+ * anyway again before the next pread happens. */
+ if (obj->cache_level == I915_CACHE_NONE)
+ needs_clflush = 1;
+ ret = i915_gem_object_set_to_gtt_domain(obj, false);
+ if (ret)
+ return ret;
+ }
- mutex_unlock(&dev->struct_mutex);
+ offset = args->offset;
while (remain > 0) {
struct page *page;
- char *vaddr;
/* Operation in this page
*
@@ -413,28 +435,51 @@ i915_gem_shmem_pread_slow(struct drm_device *dev,
if ((shmem_page_offset + page_length) > PAGE_SIZE)
page_length = PAGE_SIZE - shmem_page_offset;
- page = shmem_read_mapping_page(mapping, offset >> PAGE_SHIFT);
- if (IS_ERR(page)) {
- ret = PTR_ERR(page);
- goto out;
+ if (obj->pages) {
+ page = obj->pages[offset >> PAGE_SHIFT];
+ release_page = 0;
+ } else {
+ page = shmem_read_mapping_page(mapping, offset >> PAGE_SHIFT);
+ if (IS_ERR(page)) {
+ ret = PTR_ERR(page);
+ goto out;
+ }
+ release_page = 1;
}
page_do_bit17_swizzling = obj_do_bit17_swizzling &&
(page_to_phys(page) & (1 << 17)) != 0;
- vaddr = kmap(page);
- if (page_do_bit17_swizzling)
- ret = __copy_to_user_swizzled(user_data,
- vaddr, shmem_page_offset,
- page_length);
- else
- ret = __copy_to_user(user_data,
- vaddr + shmem_page_offset,
- page_length);
- kunmap(page);
+ ret = shmem_pread_fast(page, shmem_page_offset, page_length,
+ user_data, page_do_bit17_swizzling,
+ needs_clflush);
+ if (ret == 0)
+ goto next_page;
- mark_page_accessed(page);
+ hit_slowpath = 1;
+ page_cache_get(page);
+ mutex_unlock(&dev->struct_mutex);
+
+ if (!prefaulted) {
+ ret = fault_in_multipages_writeable(user_data, remain);
+ /* Userspace is tricking us, but we've already clobbered
+ * its pages with the prefault and promised to write the
+ * data up to the first fault. Hence ignore any errors
+ * and just continue. */
+ (void)ret;
+ prefaulted = 1;
+ }
+
+ ret = shmem_pread_slow(page, shmem_page_offset, page_length,
+ user_data, page_do_bit17_swizzling,
+ needs_clflush);
+
+ mutex_lock(&dev->struct_mutex);
page_cache_release(page);
+next_page:
+ mark_page_accessed(page);
+ if (release_page)
+ page_cache_release(page);
if (ret) {
ret = -EFAULT;
@@ -447,10 +492,11 @@ i915_gem_shmem_pread_slow(struct drm_device *dev,
}
out:
- mutex_lock(&dev->struct_mutex);
- /* Fixup: Kill any reinstated backing storage pages */
- if (obj->madv == __I915_MADV_PURGED)
- i915_gem_object_truncate(obj);
+ if (hit_slowpath) {
+ /* Fixup: Kill any reinstated backing storage pages */
+ if (obj->madv == __I915_MADV_PURGED)
+ i915_gem_object_truncate(obj);
+ }
return ret;
}
@@ -476,11 +522,6 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
args->size))
return -EFAULT;
- ret = fault_in_pages_writeable((char __user *)(uintptr_t)args->data_ptr,
- args->size);
- if (ret)
- return -EFAULT;
-
ret = i915_mutex_lock_interruptible(dev);
if (ret)
return ret;
@@ -498,19 +539,17 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data,
goto out;
}
- trace_i915_gem_object_pread(obj, args->offset, args->size);
-
- ret = i915_gem_object_set_cpu_read_domain_range(obj,
- args->offset,
- args->size);
- if (ret)
+ /* prime objects have no backing filp to GEM pread/pwrite
+ * pages from.
+ */
+ if (!obj->base.filp) {
+ ret = -EINVAL;
goto out;
+ }
- ret = -EFAULT;
- if (!i915_gem_object_needs_bit17_swizzle(obj))
- ret = i915_gem_shmem_pread_fast(dev, obj, args, file);
- if (ret == -EFAULT)
- ret = i915_gem_shmem_pread_slow(dev, obj, args, file);
+ trace_i915_gem_object_pread(obj, args->offset, args->size);
+
+ ret = i915_gem_shmem_pread(dev, obj, args, file);
out:
drm_gem_object_unreference(&obj->base);
@@ -529,40 +568,19 @@ fast_user_write(struct io_mapping *mapping,
char __user *user_data,
int length)
{
- char *vaddr_atomic;
+ void __iomem *vaddr_atomic;
+ void *vaddr;
unsigned long unwritten;
vaddr_atomic = io_mapping_map_atomic_wc(mapping, page_base);
- unwritten = __copy_from_user_inatomic_nocache(vaddr_atomic + page_offset,
+ /* We can use the cpu mem copy function because this is X86. */
+ vaddr = (void __force*)vaddr_atomic + page_offset;
+ unwritten = __copy_from_user_inatomic_nocache(vaddr,
user_data, length);
io_mapping_unmap_atomic(vaddr_atomic);
return unwritten;
}
-/* Here's the write path which can sleep for
- * page faults
- */
-
-static inline void
-slow_kernel_write(struct io_mapping *mapping,
- loff_t gtt_base, int gtt_offset,
- struct page *user_page, int user_offset,
- int length)
-{
- char __iomem *dst_vaddr;
- char *src_vaddr;
-
- dst_vaddr = io_mapping_map_wc(mapping, gtt_base);
- src_vaddr = kmap(user_page);
-
- memcpy_toio(dst_vaddr + gtt_offset,
- src_vaddr + user_offset,
- length);
-
- kunmap(user_page);
- io_mapping_unmap(dst_vaddr);
-}
-
/**
* This is the fast pwrite path, where we copy the data directly from the
* user into the GTT, uncached.
@@ -577,7 +595,19 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev,
ssize_t remain;
loff_t offset, page_base;
char __user *user_data;
- int page_offset, page_length;
+ int page_offset, page_length, ret;
+
+ ret = i915_gem_object_pin(obj, 0, true);
+ if (ret)
+ goto out;
+
+ ret = i915_gem_object_set_to_gtt_domain(obj, true);
+ if (ret)
+ goto out_unpin;
+
+ ret = i915_gem_object_put_fence(obj);
+ if (ret)
+ goto out_unpin;
user_data = (char __user *) (uintptr_t) args->data_ptr;
remain = args->size;
@@ -602,214 +632,133 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev,
* retry in the slow path.
*/
if (fast_user_write(dev_priv->mm.gtt_mapping, page_base,
- page_offset, user_data, page_length))
- return -EFAULT;
+ page_offset, user_data, page_length)) {
+ ret = -EFAULT;
+ goto out_unpin;
+ }
remain -= page_length;
user_data += page_length;
offset += page_length;
}
- return 0;
+out_unpin:
+ i915_gem_object_unpin(obj);
+out:
+ return ret;
}
-/**
- * This is the fallback GTT pwrite path, which uses get_user_pages to pin
- * the memory and maps it using kmap_atomic for copying.
- *
- * This code resulted in x11perf -rgb10text consuming about 10% more CPU
- * than using i915_gem_gtt_pwrite_fast on a G45 (32-bit).
- */
+/* Per-page copy function for the shmem pwrite fastpath.
+ * Flushes invalid cachelines before writing to the target if
+ * needs_clflush_before is set and flushes out any written cachelines after
+ * writing if needs_clflush is set. */
static int
-i915_gem_gtt_pwrite_slow(struct drm_device *dev,
- struct drm_i915_gem_object *obj,
- struct drm_i915_gem_pwrite *args,
- struct drm_file *file)
+shmem_pwrite_fast(struct page *page, int shmem_page_offset, int page_length,
+ char __user *user_data,
+ bool page_do_bit17_swizzling,
+ bool needs_clflush_before,
+ bool needs_clflush_after)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
- ssize_t remain;
- loff_t gtt_page_base, offset;
- loff_t first_data_page, last_data_page, num_pages;
- loff_t pinned_pages, i;
- struct page **user_pages;
- struct mm_struct *mm = current->mm;
- int gtt_page_offset, data_page_offset, data_page_index, page_length;
+ char *vaddr;
int ret;
- uint64_t data_ptr = args->data_ptr;
-
- remain = args->size;
-
- /* Pin the user pages containing the data. We can't fault while
- * holding the struct mutex, and all of the pwrite implementations
- * want to hold it while dereferencing the user data.
- */
- first_data_page = data_ptr / PAGE_SIZE;
- last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE;
- num_pages = last_data_page - first_data_page + 1;
-
- user_pages = drm_malloc_ab(num_pages, sizeof(struct page *));
- if (user_pages == NULL)
- return -ENOMEM;
-
- mutex_unlock(&dev->struct_mutex);
- down_read(&mm->mmap_sem);
- pinned_pages = get_user_pages(current, mm, (uintptr_t)args->data_ptr,
- num_pages, 0, 0, user_pages, NULL);
- up_read(&mm->mmap_sem);
- mutex_lock(&dev->struct_mutex);
- if (pinned_pages < num_pages) {
- ret = -EFAULT;
- goto out_unpin_pages;
- }
-
- ret = i915_gem_object_set_to_gtt_domain(obj, true);
- if (ret)
- goto out_unpin_pages;
-
- ret = i915_gem_object_put_fence(obj);
- if (ret)
- goto out_unpin_pages;
-
- offset = obj->gtt_offset + args->offset;
-
- while (remain > 0) {
- /* Operation in this page
- *
- * gtt_page_base = page offset within aperture
- * gtt_page_offset = offset within page in aperture
- * data_page_index = page number in get_user_pages return
- * data_page_offset = offset with data_page_index page.
- * page_length = bytes to copy for this page
- */
- gtt_page_base = offset & PAGE_MASK;
- gtt_page_offset = offset_in_page(offset);
- data_page_index = data_ptr / PAGE_SIZE - first_data_page;
- data_page_offset = offset_in_page(data_ptr);
-
- page_length = remain;
- if ((gtt_page_offset + page_length) > PAGE_SIZE)
- page_length = PAGE_SIZE - gtt_page_offset;
- if ((data_page_offset + page_length) > PAGE_SIZE)
- page_length = PAGE_SIZE - data_page_offset;
- slow_kernel_write(dev_priv->mm.gtt_mapping,
- gtt_page_base, gtt_page_offset,
- user_pages[data_page_index],
- data_page_offset,
- page_length);
-
- remain -= page_length;
- offset += page_length;
- data_ptr += page_length;
- }
+ if (unlikely(page_do_bit17_swizzling))
+ return -EINVAL;
-out_unpin_pages:
- for (i = 0; i < pinned_pages; i++)
- page_cache_release(user_pages[i]);
- drm_free_large(user_pages);
+ vaddr = kmap_atomic(page);
+ if (needs_clflush_before)
+ drm_clflush_virt_range(vaddr + shmem_page_offset,
+ page_length);
+ ret = __copy_from_user_inatomic_nocache(vaddr + shmem_page_offset,
+ user_data,
+ page_length);
+ if (needs_clflush_after)
+ drm_clflush_virt_range(vaddr + shmem_page_offset,
+ page_length);
+ kunmap_atomic(vaddr);
return ret;
}
-/**
- * This is the fast shmem pwrite path, which attempts to directly
- * copy_from_user into the kmapped pages backing the object.
- */
+/* Only difference to the fast-path function is that this can handle bit17
+ * and uses non-atomic copy and kmap functions. */
static int
-i915_gem_shmem_pwrite_fast(struct drm_device *dev,
- struct drm_i915_gem_object *obj,
- struct drm_i915_gem_pwrite *args,
- struct drm_file *file)
+shmem_pwrite_slow(struct page *page, int shmem_page_offset, int page_length,
+ char __user *user_data,
+ bool page_do_bit17_swizzling,
+ bool needs_clflush_before,
+ bool needs_clflush_after)
{
- struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
- ssize_t remain;
- loff_t offset;
- char __user *user_data;
- int page_offset, page_length;
-
- user_data = (char __user *) (uintptr_t) args->data_ptr;
- remain = args->size;
-
- offset = args->offset;
- obj->dirty = 1;
-
- while (remain > 0) {
- struct page *page;
- char *vaddr;
- int ret;
-
- /* Operation in this page
- *
- * page_offset = offset within page
- * page_length = bytes to copy for this page
- */
- page_offset = offset_in_page(offset);
- page_length = remain;
- if ((page_offset + remain) > PAGE_SIZE)
- page_length = PAGE_SIZE - page_offset;
-
- page = shmem_read_mapping_page(mapping, offset >> PAGE_SHIFT);
- if (IS_ERR(page))
- return PTR_ERR(page);
+ char *vaddr;
+ int ret;
- vaddr = kmap_atomic(page);
- ret = __copy_from_user_inatomic(vaddr + page_offset,
+ vaddr = kmap(page);
+ if (unlikely(needs_clflush_before || page_do_bit17_swizzling))
+ shmem_clflush_swizzled_range(vaddr + shmem_page_offset,
+ page_length,
+ page_do_bit17_swizzling);
+ if (page_do_bit17_swizzling)
+ ret = __copy_from_user_swizzled(vaddr, shmem_page_offset,
user_data,
page_length);
- kunmap_atomic(vaddr);
-
- set_page_dirty(page);
- mark_page_accessed(page);
- page_cache_release(page);
-
- /* If we get a fault while copying data, then (presumably) our
- * source page isn't available. Return the error and we'll
- * retry in the slow path.
- */
- if (ret)
- return -EFAULT;
-
- remain -= page_length;
- user_data += page_length;
- offset += page_length;
- }
+ else
+ ret = __copy_from_user(vaddr + shmem_page_offset,
+ user_data,
+ page_length);
+ if (needs_clflush_after)
+ shmem_clflush_swizzled_range(vaddr + shmem_page_offset,
+ page_length,
+ page_do_bit17_swizzling);
+ kunmap(page);
- return 0;
+ return ret;
}
-/**
- * This is the fallback shmem pwrite path, which uses get_user_pages to pin
- * the memory and maps it using kmap_atomic for copying.
- *
- * This avoids taking mmap_sem for faulting on the user's address while the
- * struct_mutex is held.
- */
static int
-i915_gem_shmem_pwrite_slow(struct drm_device *dev,
- struct drm_i915_gem_object *obj,
- struct drm_i915_gem_pwrite *args,
- struct drm_file *file)
+i915_gem_shmem_pwrite(struct drm_device *dev,
+ struct drm_i915_gem_object *obj,
+ struct drm_i915_gem_pwrite *args,
+ struct drm_file *file)
{
struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
ssize_t remain;
loff_t offset;
char __user *user_data;
- int shmem_page_offset, page_length, ret;
+ int shmem_page_offset, page_length, ret = 0;
int obj_do_bit17_swizzling, page_do_bit17_swizzling;
+ int hit_slowpath = 0;
+ int needs_clflush_after = 0;
+ int needs_clflush_before = 0;
+ int release_page;
user_data = (char __user *) (uintptr_t) args->data_ptr;
remain = args->size;
obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
+ if (obj->base.write_domain != I915_GEM_DOMAIN_CPU) {
+ /* If we're not in the cpu write domain, set ourself into the gtt
+ * write domain and manually flush cachelines (if required). This
+ * optimizes for the case when the gpu will use the data
+ * right away and we therefore have to clflush anyway. */
+ if (obj->cache_level == I915_CACHE_NONE)
+ needs_clflush_after = 1;
+ ret = i915_gem_object_set_to_gtt_domain(obj, true);
+ if (ret)
+ return ret;
+ }
+ /* Same trick applies for invalidate partially written cachelines before
+ * writing. */
+ if (!(obj->base.read_domains & I915_GEM_DOMAIN_CPU)
+ && obj->cache_level == I915_CACHE_NONE)
+ needs_clflush_before = 1;
+
offset = args->offset;
obj->dirty = 1;
- mutex_unlock(&dev->struct_mutex);
-
while (remain > 0) {
struct page *page;
- char *vaddr;
+ int partial_cacheline_write;
/* Operation in this page
*
@@ -822,29 +771,51 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev,
if ((shmem_page_offset + page_length) > PAGE_SIZE)
page_length = PAGE_SIZE - shmem_page_offset;
- page = shmem_read_mapping_page(mapping, offset >> PAGE_SHIFT);
- if (IS_ERR(page)) {
- ret = PTR_ERR(page);
- goto out;
+ /* If we don't overwrite a cacheline completely we need to be
+ * careful to have up-to-date data by first clflushing. Don't
+ * overcomplicate things and flush the entire patch. */
+ partial_cacheline_write = needs_clflush_before &&
+ ((shmem_page_offset | page_length)
+ & (boot_cpu_data.x86_clflush_size - 1));
+
+ if (obj->pages) {
+ page = obj->pages[offset >> PAGE_SHIFT];
+ release_page = 0;
+ } else {
+ page = shmem_read_mapping_page(mapping, offset >> PAGE_SHIFT);
+ if (IS_ERR(page)) {
+ ret = PTR_ERR(page);
+ goto out;
+ }
+ release_page = 1;
}
page_do_bit17_swizzling = obj_do_bit17_swizzling &&
(page_to_phys(page) & (1 << 17)) != 0;
- vaddr = kmap(page);
- if (page_do_bit17_swizzling)
- ret = __copy_from_user_swizzled(vaddr, shmem_page_offset,
- user_data,
- page_length);
- else
- ret = __copy_from_user(vaddr + shmem_page_offset,
- user_data,
- page_length);
- kunmap(page);
+ ret = shmem_pwrite_fast(page, shmem_page_offset, page_length,
+ user_data, page_do_bit17_swizzling,
+ partial_cacheline_write,
+ needs_clflush_after);
+ if (ret == 0)
+ goto next_page;
+
+ hit_slowpath = 1;
+ page_cache_get(page);
+ mutex_unlock(&dev->struct_mutex);
+
+ ret = shmem_pwrite_slow(page, shmem_page_offset, page_length,
+ user_data, page_do_bit17_swizzling,
+ partial_cacheline_write,
+ needs_clflush_after);
+ mutex_lock(&dev->struct_mutex);
+ page_cache_release(page);
+next_page:
set_page_dirty(page);
mark_page_accessed(page);
- page_cache_release(page);
+ if (release_page)
+ page_cache_release(page);
if (ret) {
ret = -EFAULT;
@@ -857,17 +828,21 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev,
}
out:
- mutex_lock(&dev->struct_mutex);
- /* Fixup: Kill any reinstated backing storage pages */
- if (obj->madv == __I915_MADV_PURGED)
- i915_gem_object_truncate(obj);
- /* and flush dirty cachelines in case the object isn't in the cpu write
- * domain anymore. */
- if (obj->base.write_domain != I915_GEM_DOMAIN_CPU) {
- i915_gem_clflush_object(obj);
- intel_gtt_chipset_flush();
+ if (hit_slowpath) {
+ /* Fixup: Kill any reinstated backing storage pages */
+ if (obj->madv == __I915_MADV_PURGED)
+ i915_gem_object_truncate(obj);
+ /* and flush dirty cachelines in case the object isn't in the cpu write
+ * domain anymore. */
+ if (obj->base.write_domain != I915_GEM_DOMAIN_CPU) {
+ i915_gem_clflush_object(obj);
+ intel_gtt_chipset_flush();
+ }
}
+ if (needs_clflush_after)
+ intel_gtt_chipset_flush();
+
return ret;
}
@@ -892,8 +867,8 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
args->size))
return -EFAULT;
- ret = fault_in_pages_readable((char __user *)(uintptr_t)args->data_ptr,
- args->size);
+ ret = fault_in_multipages_readable((char __user *)(uintptr_t)args->data_ptr,
+ args->size);
if (ret)
return -EFAULT;
@@ -914,8 +889,17 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
goto out;
}
+ /* prime objects have no backing filp to GEM pread/pwrite
+ * pages from.
+ */
+ if (!obj->base.filp) {
+ ret = -EINVAL;
+ goto out;
+ }
+
trace_i915_gem_object_pwrite(obj, args->offset, args->size);
+ ret = -EFAULT;
/* We can only do the GTT pwrite on untiled buffers, as otherwise
* it would end up going through the fenced access, and we'll get
* different detiling behavior between reading and writing.
@@ -928,42 +912,18 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
}
if (obj->gtt_space &&
+ obj->cache_level == I915_CACHE_NONE &&
+ obj->tiling_mode == I915_TILING_NONE &&
+ obj->map_and_fenceable &&
obj->base.write_domain != I915_GEM_DOMAIN_CPU) {
- ret = i915_gem_object_pin(obj, 0, true);
- if (ret)
- goto out;
-
- ret = i915_gem_object_set_to_gtt_domain(obj, true);
- if (ret)
- goto out_unpin;
-
- ret = i915_gem_object_put_fence(obj);
- if (ret)
- goto out_unpin;
-
ret = i915_gem_gtt_pwrite_fast(dev, obj, args, file);
- if (ret == -EFAULT)
- ret = i915_gem_gtt_pwrite_slow(dev, obj, args, file);
-
-out_unpin:
- i915_gem_object_unpin(obj);
-
- if (ret != -EFAULT)
- goto out;
- /* Fall through to the shmfs paths because the gtt paths might
- * fail with non-page-backed user pointers (e.g. gtt mappings
- * when moving data between textures). */
+ /* Note that the gtt paths might fail with non-page-backed user
+ * pointers (e.g. gtt mappings when moving data between
+ * textures). Fallback to the shmem path in that case. */
}
- ret = i915_gem_object_set_to_cpu_domain(obj, 1);
- if (ret)
- goto out;
-
- ret = -EFAULT;
- if (!i915_gem_object_needs_bit17_swizzle(obj))
- ret = i915_gem_shmem_pwrite_fast(dev, obj, args, file);
if (ret == -EFAULT)
- ret = i915_gem_shmem_pwrite_slow(dev, obj, args, file);
+ ret = i915_gem_shmem_pwrite(dev, obj, args, file);
out:
drm_gem_object_unreference(&obj->base);
@@ -986,9 +946,6 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
uint32_t write_domain = args->write_domain;
int ret;
- if (!(dev->driver->driver_features & DRIVER_GEM))
- return -ENODEV;
-
/* Only handle setting domains to types used by the CPU. */
if (write_domain & I915_GEM_GPU_DOMAINS)
return -EINVAL;
@@ -1042,9 +999,6 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
struct drm_i915_gem_object *obj;
int ret = 0;
- if (!(dev->driver->driver_features & DRIVER_GEM))
- return -ENODEV;
-
ret = i915_mutex_lock_interruptible(dev);
if (ret)
return ret;
@@ -1080,13 +1034,18 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
struct drm_gem_object *obj;
unsigned long addr;
- if (!(dev->driver->driver_features & DRIVER_GEM))
- return -ENODEV;
-
obj = drm_gem_object_lookup(dev, file, args->handle);
if (obj == NULL)
return -ENOENT;
+ /* prime objects have no backing filp to GEM mmap
+ * pages from.
+ */
+ if (!obj->filp) {
+ drm_gem_object_unreference_unlocked(obj);
+ return -EINVAL;
+ }
+
addr = vm_mmap(obj->filp, 0, args->size,
PROT_READ | PROT_WRITE, MAP_SHARED,
args->offset);
@@ -1151,10 +1110,10 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
goto unlock;
}
- if (obj->tiling_mode == I915_TILING_NONE)
- ret = i915_gem_object_put_fence(obj);
- else
- ret = i915_gem_object_get_fence(obj, NULL);
+ if (!obj->has_global_gtt_mapping)
+ i915_gem_gtt_bind_object(obj, obj->cache_level);
+
+ ret = i915_gem_object_get_fence(obj);
if (ret)
goto unlock;
@@ -1308,9 +1267,6 @@ i915_gem_mmap_gtt(struct drm_file *file,
struct drm_i915_gem_object *obj;
int ret;
- if (!(dev->driver->driver_features & DRIVER_GEM))
- return -ENODEV;
-
ret = i915_mutex_lock_interruptible(dev);
if (ret)
return ret;
@@ -1368,14 +1324,10 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
{
struct drm_i915_gem_mmap_gtt *args = data;
- if (!(dev->driver->driver_features & DRIVER_GEM))
- return -ENODEV;
-
return i915_gem_mmap_gtt(file, dev, args->handle, &args->offset);
}
-
-static int
+int
i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj,
gfp_t gfpmask)
{
@@ -1384,6 +1336,9 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj,
struct inode *inode;
struct page *page;
+ if (obj->pages || obj->sg_table)
+ return 0;
+
/* Get the list of pages out of our struct file. They'll be pinned
* at this point until we release them.
*/
@@ -1425,6 +1380,9 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj)
int page_count = obj->base.size / PAGE_SIZE;
int i;
+ if (!obj->pages)
+ return;
+
BUG_ON(obj->madv == __I915_MADV_PURGED);
if (i915_gem_object_needs_bit17_swizzle(obj))
@@ -1473,7 +1431,6 @@ i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
if (obj->fenced_gpu_access) {
obj->last_fenced_seqno = seqno;
- obj->last_fenced_ring = ring;
/* Bump MRU to take account of the delayed flush */
if (obj->fence_reg != I915_FENCE_REG_NONE) {
@@ -1512,15 +1469,11 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj)
struct drm_device *dev = obj->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- if (obj->pin_count != 0)
- list_move_tail(&obj->mm_list, &dev_priv->mm.pinned_list);
- else
- list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
+ list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
BUG_ON(!list_empty(&obj->gpu_write_list));
BUG_ON(!obj->active);
obj->ring = NULL;
- obj->last_fenced_ring = NULL;
i915_gem_object_move_off_active(obj);
obj->fenced_gpu_access = false;
@@ -1546,6 +1499,9 @@ i915_gem_object_truncate(struct drm_i915_gem_object *obj)
inode = obj->base.filp->f_path.dentry->d_inode;
shmem_truncate_range(inode, 0, (loff_t)-1);
+ if (obj->base.map_list.map)
+ drm_gem_free_mmap_offset(&obj->base);
+
obj->madv = __I915_MADV_PURGED;
}
@@ -1711,30 +1667,29 @@ static void i915_gem_reset_fences(struct drm_device *dev)
for (i = 0; i < dev_priv->num_fence_regs; i++) {
struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i];
- struct drm_i915_gem_object *obj = reg->obj;
- if (!obj)
- continue;
+ i915_gem_write_fence(dev, i, NULL);
- if (obj->tiling_mode)
- i915_gem_release_mmap(obj);
+ if (reg->obj)
+ i915_gem_object_fence_lost(reg->obj);
- reg->obj->fence_reg = I915_FENCE_REG_NONE;
- reg->obj->fenced_gpu_access = false;
- reg->obj->last_fenced_seqno = 0;
- reg->obj->last_fenced_ring = NULL;
- i915_gem_clear_fence_reg(dev, reg);
+ reg->pin_count = 0;
+ reg->obj = NULL;
+ INIT_LIST_HEAD(&reg->lru_list);
}
+
+ INIT_LIST_HEAD(&dev_priv->mm.fence_list);
}
void i915_gem_reset(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj;
+ struct intel_ring_buffer *ring;
int i;
- for (i = 0; i < I915_NUM_RINGS; i++)
- i915_gem_reset_ring_lists(dev_priv, &dev_priv->ring[i]);
+ for_each_ring(ring, dev_priv, i)
+ i915_gem_reset_ring_lists(dev_priv, ring);
/* Remove anything from the flushing lists. The GPU cache is likely
* to be lost on reset along with the data, so simply move the
@@ -1839,24 +1794,11 @@ void
i915_gem_retire_requests(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring;
int i;
- if (!list_empty(&dev_priv->mm.deferred_free_list)) {
- struct drm_i915_gem_object *obj, *next;
-
- /* We must be careful that during unbind() we do not
- * accidentally infinitely recurse into retire requests.
- * Currently:
- * retire -> free -> unbind -> wait -> retire_ring
- */
- list_for_each_entry_safe(obj, next,
- &dev_priv->mm.deferred_free_list,
- mm_list)
- i915_gem_free_object_tail(obj);
- }
-
- for (i = 0; i < I915_NUM_RINGS; i++)
- i915_gem_retire_requests_ring(&dev_priv->ring[i]);
+ for_each_ring(ring, dev_priv, i)
+ i915_gem_retire_requests_ring(ring);
}
static void
@@ -1864,6 +1806,7 @@ i915_gem_retire_work_handler(struct work_struct *work)
{
drm_i915_private_t *dev_priv;
struct drm_device *dev;
+ struct intel_ring_buffer *ring;
bool idle;
int i;
@@ -1883,9 +1826,7 @@ i915_gem_retire_work_handler(struct work_struct *work)
* objects indefinitely.
*/
idle = true;
- for (i = 0; i < I915_NUM_RINGS; i++) {
- struct intel_ring_buffer *ring = &dev_priv->ring[i];
-
+ for_each_ring(ring, dev_priv, i) {
if (!list_empty(&ring->gpu_write_list)) {
struct drm_i915_gem_request *request;
int ret;
@@ -1907,20 +1848,10 @@ i915_gem_retire_work_handler(struct work_struct *work)
mutex_unlock(&dev->struct_mutex);
}
-/**
- * Waits for a sequence number to be signaled, and cleans up the
- * request and object lists appropriately for that event.
- */
-int
-i915_wait_request(struct intel_ring_buffer *ring,
- uint32_t seqno,
- bool do_retire)
+static int
+i915_gem_check_wedge(struct drm_i915_private *dev_priv)
{
- drm_i915_private_t *dev_priv = ring->dev->dev_private;
- u32 ier;
- int ret = 0;
-
- BUG_ON(seqno == 0);
+ BUG_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
if (atomic_read(&dev_priv->mm.wedged)) {
struct completion *x = &dev_priv->error_completion;
@@ -1935,6 +1866,20 @@ i915_wait_request(struct intel_ring_buffer *ring,
return recovery_complete ? -EIO : -EAGAIN;
}
+ return 0;
+}
+
+/*
+ * Compare seqno against outstanding lazy request. Emit a request if they are
+ * equal.
+ */
+static int
+i915_gem_check_olr(struct intel_ring_buffer *ring, u32 seqno)
+{
+ int ret = 0;
+
+ BUG_ON(!mutex_is_locked(&ring->dev->struct_mutex));
+
if (seqno == ring->outstanding_lazy_request) {
struct drm_i915_gem_request *request;
@@ -1948,54 +1893,67 @@ i915_wait_request(struct intel_ring_buffer *ring,
return ret;
}
- seqno = request->seqno;
+ BUG_ON(seqno != request->seqno);
}
- if (!i915_seqno_passed(ring->get_seqno(ring), seqno)) {
- if (HAS_PCH_SPLIT(ring->dev))
- ier = I915_READ(DEIER) | I915_READ(GTIER);
- else
- ier = I915_READ(IER);
- if (!ier) {
- DRM_ERROR("something (likely vbetool) disabled "
- "interrupts, re-enabling\n");
- ring->dev->driver->irq_preinstall(ring->dev);
- ring->dev->driver->irq_postinstall(ring->dev);
- }
+ return ret;
+}
- trace_i915_gem_request_wait_begin(ring, seqno);
-
- ring->waiting_seqno = seqno;
- if (ring->irq_get(ring)) {
- if (dev_priv->mm.interruptible)
- ret = wait_event_interruptible(ring->irq_queue,
- i915_seqno_passed(ring->get_seqno(ring), seqno)
- || atomic_read(&dev_priv->mm.wedged));
- else
- wait_event(ring->irq_queue,
- i915_seqno_passed(ring->get_seqno(ring), seqno)
- || atomic_read(&dev_priv->mm.wedged));
-
- ring->irq_put(ring);
- } else if (wait_for_atomic(i915_seqno_passed(ring->get_seqno(ring),
- seqno) ||
- atomic_read(&dev_priv->mm.wedged), 3000))
- ret = -EBUSY;
- ring->waiting_seqno = 0;
-
- trace_i915_gem_request_wait_end(ring, seqno);
- }
+static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
+ bool interruptible)
+{
+ drm_i915_private_t *dev_priv = ring->dev->dev_private;
+ int ret = 0;
+
+ if (i915_seqno_passed(ring->get_seqno(ring), seqno))
+ return 0;
+
+ trace_i915_gem_request_wait_begin(ring, seqno);
+ if (WARN_ON(!ring->irq_get(ring)))
+ return -ENODEV;
+
+#define EXIT_COND \
+ (i915_seqno_passed(ring->get_seqno(ring), seqno) || \
+ atomic_read(&dev_priv->mm.wedged))
+
+ if (interruptible)
+ ret = wait_event_interruptible(ring->irq_queue,
+ EXIT_COND);
+ else
+ wait_event(ring->irq_queue, EXIT_COND);
+
+ ring->irq_put(ring);
+ trace_i915_gem_request_wait_end(ring, seqno);
+#undef EXIT_COND
+
+ return ret;
+}
+
+/**
+ * Waits for a sequence number to be signaled, and cleans up the
+ * request and object lists appropriately for that event.
+ */
+int
+i915_wait_request(struct intel_ring_buffer *ring,
+ uint32_t seqno)
+{
+ drm_i915_private_t *dev_priv = ring->dev->dev_private;
+ int ret = 0;
+
+ BUG_ON(seqno == 0);
+
+ ret = i915_gem_check_wedge(dev_priv);
+ if (ret)
+ return ret;
+
+ ret = i915_gem_check_olr(ring, seqno);
+ if (ret)
+ return ret;
+
+ ret = __wait_seqno(ring, seqno, dev_priv->mm.interruptible);
if (atomic_read(&dev_priv->mm.wedged))
ret = -EAGAIN;
- /* Directly dispatch request retiring. While we have the work queue
- * to handle this, the waiter on a request often wants an associated
- * buffer to have made it to the inactive list, and we would need
- * a separate wait queue to handle that.
- */
- if (ret == 0 && do_retire)
- i915_gem_retire_requests_ring(ring);
-
return ret;
}
@@ -2017,15 +1975,58 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj)
* it.
*/
if (obj->active) {
- ret = i915_wait_request(obj->ring, obj->last_rendering_seqno,
- true);
+ ret = i915_wait_request(obj->ring, obj->last_rendering_seqno);
if (ret)
return ret;
+ i915_gem_retire_requests_ring(obj->ring);
}
return 0;
}
+/**
+ * i915_gem_object_sync - sync an object to a ring.
+ *
+ * @obj: object which may be in use on another ring.
+ * @to: ring we wish to use the object on. May be NULL.
+ *
+ * This code is meant to abstract object synchronization with the GPU.
+ * Calling with NULL implies synchronizing the object with the CPU
+ * rather than a particular GPU ring.
+ *
+ * Returns 0 if successful, else propagates up the lower layer error.
+ */
+int
+i915_gem_object_sync(struct drm_i915_gem_object *obj,
+ struct intel_ring_buffer *to)
+{
+ struct intel_ring_buffer *from = obj->ring;
+ u32 seqno;
+ int ret, idx;
+
+ if (from == NULL || to == from)
+ return 0;
+
+ if (to == NULL || !i915_semaphore_is_enabled(obj->base.dev))
+ return i915_gem_object_wait_rendering(obj);
+
+ idx = intel_ring_sync_index(from, to);
+
+ seqno = obj->last_rendering_seqno;
+ if (seqno <= from->sync_seqno[idx])
+ return 0;
+
+ ret = i915_gem_check_olr(obj->ring, seqno);
+ if (ret)
+ return ret;
+
+ ret = to->sync_to(to, from, seqno);
+ if (!ret)
+ from->sync_seqno[idx] = seqno;
+
+ return ret;
+}
+
static void i915_gem_object_finish_gtt(struct drm_i915_gem_object *obj)
{
u32 old_write_domain, old_read_domains;
@@ -2068,7 +2069,7 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj)
}
ret = i915_gem_object_finish_gpu(obj);
- if (ret == -ERESTARTSYS)
+ if (ret)
return ret;
/* Continue on if we fail due to EIO, the GPU is hung so we
* should be safe and we need to cleanup or else we might
@@ -2095,16 +2096,18 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj)
/* release the fence reg _after_ flushing */
ret = i915_gem_object_put_fence(obj);
- if (ret == -ERESTARTSYS)
+ if (ret)
return ret;
trace_i915_gem_object_unbind(obj);
- i915_gem_gtt_unbind_object(obj);
+ if (obj->has_global_gtt_mapping)
+ i915_gem_gtt_unbind_object(obj);
if (obj->has_aliasing_ppgtt_mapping) {
i915_ppgtt_unbind_object(dev_priv->mm.aliasing_ppgtt, obj);
obj->has_aliasing_ppgtt_mapping = 0;
}
+ i915_gem_gtt_finish_object(obj);
i915_gem_object_put_pages_gtt(obj);
@@ -2145,7 +2148,7 @@ i915_gem_flush_ring(struct intel_ring_buffer *ring,
return 0;
}
-static int i915_ring_idle(struct intel_ring_buffer *ring, bool do_retire)
+static int i915_ring_idle(struct intel_ring_buffer *ring)
{
int ret;
@@ -2159,208 +2162,201 @@ static int i915_ring_idle(struct intel_ring_buffer *ring, bool do_retire)
return ret;
}
- return i915_wait_request(ring, i915_gem_next_request_seqno(ring),
- do_retire);
+ return i915_wait_request(ring, i915_gem_next_request_seqno(ring));
}
-int i915_gpu_idle(struct drm_device *dev, bool do_retire)
+int i915_gpu_idle(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring;
int ret, i;
/* Flush everything onto the inactive list. */
- for (i = 0; i < I915_NUM_RINGS; i++) {
- ret = i915_ring_idle(&dev_priv->ring[i], do_retire);
+ for_each_ring(ring, dev_priv, i) {
+ ret = i915_ring_idle(ring);
if (ret)
return ret;
+
+ /* Is the device fubar? */
+ if (WARN_ON(!list_empty(&ring->gpu_write_list)))
+ return -EBUSY;
}
return 0;
}
-static int sandybridge_write_fence_reg(struct drm_i915_gem_object *obj,
- struct intel_ring_buffer *pipelined)
+static void sandybridge_write_fence_reg(struct drm_device *dev, int reg,
+ struct drm_i915_gem_object *obj)
{
- struct drm_device *dev = obj->base.dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- u32 size = obj->gtt_space->size;
- int regnum = obj->fence_reg;
uint64_t val;
- val = (uint64_t)((obj->gtt_offset + size - 4096) &
- 0xfffff000) << 32;
- val |= obj->gtt_offset & 0xfffff000;
- val |= (uint64_t)((obj->stride / 128) - 1) <<
- SANDYBRIDGE_FENCE_PITCH_SHIFT;
+ if (obj) {
+ u32 size = obj->gtt_space->size;
- if (obj->tiling_mode == I915_TILING_Y)
- val |= 1 << I965_FENCE_TILING_Y_SHIFT;
- val |= I965_FENCE_REG_VALID;
+ val = (uint64_t)((obj->gtt_offset + size - 4096) &
+ 0xfffff000) << 32;
+ val |= obj->gtt_offset & 0xfffff000;
+ val |= (uint64_t)((obj->stride / 128) - 1) <<
+ SANDYBRIDGE_FENCE_PITCH_SHIFT;
- if (pipelined) {
- int ret = intel_ring_begin(pipelined, 6);
- if (ret)
- return ret;
-
- intel_ring_emit(pipelined, MI_NOOP);
- intel_ring_emit(pipelined, MI_LOAD_REGISTER_IMM(2));
- intel_ring_emit(pipelined, FENCE_REG_SANDYBRIDGE_0 + regnum*8);
- intel_ring_emit(pipelined, (u32)val);
- intel_ring_emit(pipelined, FENCE_REG_SANDYBRIDGE_0 + regnum*8 + 4);
- intel_ring_emit(pipelined, (u32)(val >> 32));
- intel_ring_advance(pipelined);
+ if (obj->tiling_mode == I915_TILING_Y)
+ val |= 1 << I965_FENCE_TILING_Y_SHIFT;
+ val |= I965_FENCE_REG_VALID;
} else
- I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + regnum * 8, val);
+ val = 0;
- return 0;
+ I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + reg * 8, val);
+ POSTING_READ(FENCE_REG_SANDYBRIDGE_0 + reg * 8);
}
-static int i965_write_fence_reg(struct drm_i915_gem_object *obj,
- struct intel_ring_buffer *pipelined)
+static void i965_write_fence_reg(struct drm_device *dev, int reg,
+ struct drm_i915_gem_object *obj)
{
- struct drm_device *dev = obj->base.dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- u32 size = obj->gtt_space->size;
- int regnum = obj->fence_reg;
uint64_t val;
- val = (uint64_t)((obj->gtt_offset + size - 4096) &
- 0xfffff000) << 32;
- val |= obj->gtt_offset & 0xfffff000;
- val |= ((obj->stride / 128) - 1) << I965_FENCE_PITCH_SHIFT;
- if (obj->tiling_mode == I915_TILING_Y)
- val |= 1 << I965_FENCE_TILING_Y_SHIFT;
- val |= I965_FENCE_REG_VALID;
+ if (obj) {
+ u32 size = obj->gtt_space->size;
- if (pipelined) {
- int ret = intel_ring_begin(pipelined, 6);
- if (ret)
- return ret;
-
- intel_ring_emit(pipelined, MI_NOOP);
- intel_ring_emit(pipelined, MI_LOAD_REGISTER_IMM(2));
- intel_ring_emit(pipelined, FENCE_REG_965_0 + regnum*8);
- intel_ring_emit(pipelined, (u32)val);
- intel_ring_emit(pipelined, FENCE_REG_965_0 + regnum*8 + 4);
- intel_ring_emit(pipelined, (u32)(val >> 32));
- intel_ring_advance(pipelined);
+ val = (uint64_t)((obj->gtt_offset + size - 4096) &
+ 0xfffff000) << 32;
+ val |= obj->gtt_offset & 0xfffff000;
+ val |= ((obj->stride / 128) - 1) << I965_FENCE_PITCH_SHIFT;
+ if (obj->tiling_mode == I915_TILING_Y)
+ val |= 1 << I965_FENCE_TILING_Y_SHIFT;
+ val |= I965_FENCE_REG_VALID;
} else
- I915_WRITE64(FENCE_REG_965_0 + regnum * 8, val);
+ val = 0;
- return 0;
+ I915_WRITE64(FENCE_REG_965_0 + reg * 8, val);
+ POSTING_READ(FENCE_REG_965_0 + reg * 8);
}
-static int i915_write_fence_reg(struct drm_i915_gem_object *obj,
- struct intel_ring_buffer *pipelined)
+static void i915_write_fence_reg(struct drm_device *dev, int reg,
+ struct drm_i915_gem_object *obj)
{
- struct drm_device *dev = obj->base.dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- u32 size = obj->gtt_space->size;
- u32 fence_reg, val, pitch_val;
- int tile_width;
-
- if (WARN((obj->gtt_offset & ~I915_FENCE_START_MASK) ||
- (size & -size) != size ||
- (obj->gtt_offset & (size - 1)),
- "object 0x%08x [fenceable? %d] not 1M or pot-size (0x%08x) aligned\n",
- obj->gtt_offset, obj->map_and_fenceable, size))
- return -EINVAL;
+ u32 val;
- if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev))
- tile_width = 128;
- else
- tile_width = 512;
-
- /* Note: pitch better be a power of two tile widths */
- pitch_val = obj->stride / tile_width;
- pitch_val = ffs(pitch_val) - 1;
-
- val = obj->gtt_offset;
- if (obj->tiling_mode == I915_TILING_Y)
- val |= 1 << I830_FENCE_TILING_Y_SHIFT;
- val |= I915_FENCE_SIZE_BITS(size);
- val |= pitch_val << I830_FENCE_PITCH_SHIFT;
- val |= I830_FENCE_REG_VALID;
-
- fence_reg = obj->fence_reg;
- if (fence_reg < 8)
- fence_reg = FENCE_REG_830_0 + fence_reg * 4;
- else
- fence_reg = FENCE_REG_945_8 + (fence_reg - 8) * 4;
+ if (obj) {
+ u32 size = obj->gtt_space->size;
+ int pitch_val;
+ int tile_width;
- if (pipelined) {
- int ret = intel_ring_begin(pipelined, 4);
- if (ret)
- return ret;
+ WARN((obj->gtt_offset & ~I915_FENCE_START_MASK) ||
+ (size & -size) != size ||
+ (obj->gtt_offset & (size - 1)),
+ "object 0x%08x [fenceable? %d] not 1M or pot-size (0x%08x) aligned\n",
+ obj->gtt_offset, obj->map_and_fenceable, size);
- intel_ring_emit(pipelined, MI_NOOP);
- intel_ring_emit(pipelined, MI_LOAD_REGISTER_IMM(1));
- intel_ring_emit(pipelined, fence_reg);
- intel_ring_emit(pipelined, val);
- intel_ring_advance(pipelined);
+ if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev))
+ tile_width = 128;
+ else
+ tile_width = 512;
+
+ /* Note: pitch better be a power of two tile widths */
+ pitch_val = obj->stride / tile_width;
+ pitch_val = ffs(pitch_val) - 1;
+
+ val = obj->gtt_offset;
+ if (obj->tiling_mode == I915_TILING_Y)
+ val |= 1 << I830_FENCE_TILING_Y_SHIFT;
+ val |= I915_FENCE_SIZE_BITS(size);
+ val |= pitch_val << I830_FENCE_PITCH_SHIFT;
+ val |= I830_FENCE_REG_VALID;
} else
- I915_WRITE(fence_reg, val);
+ val = 0;
- return 0;
+ if (reg < 8)
+ reg = FENCE_REG_830_0 + reg * 4;
+ else
+ reg = FENCE_REG_945_8 + (reg - 8) * 4;
+
+ I915_WRITE(reg, val);
+ POSTING_READ(reg);
}
-static int i830_write_fence_reg(struct drm_i915_gem_object *obj,
- struct intel_ring_buffer *pipelined)
+static void i830_write_fence_reg(struct drm_device *dev, int reg,
+ struct drm_i915_gem_object *obj)
{
- struct drm_device *dev = obj->base.dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- u32 size = obj->gtt_space->size;
- int regnum = obj->fence_reg;
uint32_t val;
- uint32_t pitch_val;
- if (WARN((obj->gtt_offset & ~I830_FENCE_START_MASK) ||
- (size & -size) != size ||
- (obj->gtt_offset & (size - 1)),
- "object 0x%08x not 512K or pot-size 0x%08x aligned\n",
- obj->gtt_offset, size))
- return -EINVAL;
-
- pitch_val = obj->stride / 128;
- pitch_val = ffs(pitch_val) - 1;
-
- val = obj->gtt_offset;
- if (obj->tiling_mode == I915_TILING_Y)
- val |= 1 << I830_FENCE_TILING_Y_SHIFT;
- val |= I830_FENCE_SIZE_BITS(size);
- val |= pitch_val << I830_FENCE_PITCH_SHIFT;
- val |= I830_FENCE_REG_VALID;
+ if (obj) {
+ u32 size = obj->gtt_space->size;
+ uint32_t pitch_val;
+
+ WARN((obj->gtt_offset & ~I830_FENCE_START_MASK) ||
+ (size & -size) != size ||
+ (obj->gtt_offset & (size - 1)),
+ "object 0x%08x not 512K or pot-size 0x%08x aligned\n",
+ obj->gtt_offset, size);
+
+ pitch_val = obj->stride / 128;
+ pitch_val = ffs(pitch_val) - 1;
+
+ val = obj->gtt_offset;
+ if (obj->tiling_mode == I915_TILING_Y)
+ val |= 1 << I830_FENCE_TILING_Y_SHIFT;
+ val |= I830_FENCE_SIZE_BITS(size);
+ val |= pitch_val << I830_FENCE_PITCH_SHIFT;
+ val |= I830_FENCE_REG_VALID;
+ } else
+ val = 0;
- if (pipelined) {
- int ret = intel_ring_begin(pipelined, 4);
- if (ret)
- return ret;
+ I915_WRITE(FENCE_REG_830_0 + reg * 4, val);
+ POSTING_READ(FENCE_REG_830_0 + reg * 4);
+}
- intel_ring_emit(pipelined, MI_NOOP);
- intel_ring_emit(pipelined, MI_LOAD_REGISTER_IMM(1));
- intel_ring_emit(pipelined, FENCE_REG_830_0 + regnum*4);
- intel_ring_emit(pipelined, val);
- intel_ring_advance(pipelined);
- } else
- I915_WRITE(FENCE_REG_830_0 + regnum * 4, val);
+static void i915_gem_write_fence(struct drm_device *dev, int reg,
+ struct drm_i915_gem_object *obj)
+{
+ switch (INTEL_INFO(dev)->gen) {
+ case 7:
+ case 6: sandybridge_write_fence_reg(dev, reg, obj); break;
+ case 5:
+ case 4: i965_write_fence_reg(dev, reg, obj); break;
+ case 3: i915_write_fence_reg(dev, reg, obj); break;
+ case 2: i830_write_fence_reg(dev, reg, obj); break;
+ default: break;
+ }
+}
- return 0;
+static inline int fence_number(struct drm_i915_private *dev_priv,
+ struct drm_i915_fence_reg *fence)
+{
+ return fence - dev_priv->fence_regs;
}
-static bool ring_passed_seqno(struct intel_ring_buffer *ring, u32 seqno)
+static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
+ struct drm_i915_fence_reg *fence,
+ bool enable)
{
- return i915_seqno_passed(ring->get_seqno(ring), seqno);
+ struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+ int reg = fence_number(dev_priv, fence);
+
+ i915_gem_write_fence(obj->base.dev, reg, enable ? obj : NULL);
+
+ if (enable) {
+ obj->fence_reg = reg;
+ fence->obj = obj;
+ list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list);
+ } else {
+ obj->fence_reg = I915_FENCE_REG_NONE;
+ fence->obj = NULL;
+ list_del_init(&fence->lru_list);
+ }
}
static int
-i915_gem_object_flush_fence(struct drm_i915_gem_object *obj,
- struct intel_ring_buffer *pipelined)
+i915_gem_object_flush_fence(struct drm_i915_gem_object *obj)
{
int ret;
if (obj->fenced_gpu_access) {
if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) {
- ret = i915_gem_flush_ring(obj->last_fenced_ring,
+ ret = i915_gem_flush_ring(obj->ring,
0, obj->base.write_domain);
if (ret)
return ret;
@@ -2369,18 +2365,12 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj,
obj->fenced_gpu_access = false;
}
- if (obj->last_fenced_seqno && pipelined != obj->last_fenced_ring) {
- if (!ring_passed_seqno(obj->last_fenced_ring,
- obj->last_fenced_seqno)) {
- ret = i915_wait_request(obj->last_fenced_ring,
- obj->last_fenced_seqno,
- true);
- if (ret)
- return ret;
- }
+ if (obj->last_fenced_seqno) {
+ ret = i915_wait_request(obj->ring, obj->last_fenced_seqno);
+ if (ret)
+ return ret;
obj->last_fenced_seqno = 0;
- obj->last_fenced_ring = NULL;
}
/* Ensure that all CPU reads are completed before installing a fence
@@ -2395,34 +2385,29 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj,
int
i915_gem_object_put_fence(struct drm_i915_gem_object *obj)
{
+ struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
int ret;
- if (obj->tiling_mode)
- i915_gem_release_mmap(obj);
-
- ret = i915_gem_object_flush_fence(obj, NULL);
+ ret = i915_gem_object_flush_fence(obj);
if (ret)
return ret;
- if (obj->fence_reg != I915_FENCE_REG_NONE) {
- struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
-
- WARN_ON(dev_priv->fence_regs[obj->fence_reg].pin_count);
- i915_gem_clear_fence_reg(obj->base.dev,
- &dev_priv->fence_regs[obj->fence_reg]);
+ if (obj->fence_reg == I915_FENCE_REG_NONE)
+ return 0;
- obj->fence_reg = I915_FENCE_REG_NONE;
- }
+ i915_gem_object_update_fence(obj,
+ &dev_priv->fence_regs[obj->fence_reg],
+ false);
+ i915_gem_object_fence_lost(obj);
return 0;
}
static struct drm_i915_fence_reg *
-i915_find_fence_reg(struct drm_device *dev,
- struct intel_ring_buffer *pipelined)
+i915_find_fence_reg(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_i915_fence_reg *reg, *first, *avail;
+ struct drm_i915_fence_reg *reg, *avail;
int i;
/* First try to find a free reg */
@@ -2440,204 +2425,77 @@ i915_find_fence_reg(struct drm_device *dev,
return NULL;
/* None available, try to steal one or wait for a user to finish */
- avail = first = NULL;
list_for_each_entry(reg, &dev_priv->mm.fence_list, lru_list) {
if (reg->pin_count)
continue;
- if (first == NULL)
- first = reg;
-
- if (!pipelined ||
- !reg->obj->last_fenced_ring ||
- reg->obj->last_fenced_ring == pipelined) {
- avail = reg;
- break;
- }
+ return reg;
}
- if (avail == NULL)
- avail = first;
-
- return avail;
+ return NULL;
}
/**
- * i915_gem_object_get_fence - set up a fence reg for an object
+ * i915_gem_object_get_fence - set up fencing for an object
* @obj: object to map through a fence reg
- * @pipelined: ring on which to queue the change, or NULL for CPU access
- * @interruptible: must we wait uninterruptibly for the register to retire?
*
* When mapping objects through the GTT, userspace wants to be able to write
* to them without having to worry about swizzling if the object is tiled.
- *
* This function walks the fence regs looking for a free one for @obj,
* stealing one if it can't find any.
*
* It then sets up the reg based on the object's properties: address, pitch
* and tiling format.
+ *
+ * For an untiled surface, this removes any existing fence.
*/
int
-i915_gem_object_get_fence(struct drm_i915_gem_object *obj,
- struct intel_ring_buffer *pipelined)
+i915_gem_object_get_fence(struct drm_i915_gem_object *obj)
{
struct drm_device *dev = obj->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
+ bool enable = obj->tiling_mode != I915_TILING_NONE;
struct drm_i915_fence_reg *reg;
int ret;
- /* XXX disable pipelining. There are bugs. Shocking. */
- pipelined = NULL;
+ /* Have we updated the tiling parameters upon the object and so
+ * will need to serialise the write to the associated fence register?
+ */
+ if (obj->fence_dirty) {
+ ret = i915_gem_object_flush_fence(obj);
+ if (ret)
+ return ret;
+ }
/* Just update our place in the LRU if our fence is getting reused. */
if (obj->fence_reg != I915_FENCE_REG_NONE) {
reg = &dev_priv->fence_regs[obj->fence_reg];
- list_move_tail(&reg->lru_list, &dev_priv->mm.fence_list);
-
- if (obj->tiling_changed) {
- ret = i915_gem_object_flush_fence(obj, pipelined);
- if (ret)
- return ret;
-
- if (!obj->fenced_gpu_access && !obj->last_fenced_seqno)
- pipelined = NULL;
-
- if (pipelined) {
- reg->setup_seqno =
- i915_gem_next_request_seqno(pipelined);
- obj->last_fenced_seqno = reg->setup_seqno;
- obj->last_fenced_ring = pipelined;
- }
-
- goto update;
+ if (!obj->fence_dirty) {
+ list_move_tail(&reg->lru_list,
+ &dev_priv->mm.fence_list);
+ return 0;
}
+ } else if (enable) {
+ reg = i915_find_fence_reg(dev);
+ if (reg == NULL)
+ return -EDEADLK;
- if (!pipelined) {
- if (reg->setup_seqno) {
- if (!ring_passed_seqno(obj->last_fenced_ring,
- reg->setup_seqno)) {
- ret = i915_wait_request(obj->last_fenced_ring,
- reg->setup_seqno,
- true);
- if (ret)
- return ret;
- }
+ if (reg->obj) {
+ struct drm_i915_gem_object *old = reg->obj;
- reg->setup_seqno = 0;
- }
- } else if (obj->last_fenced_ring &&
- obj->last_fenced_ring != pipelined) {
- ret = i915_gem_object_flush_fence(obj, pipelined);
+ ret = i915_gem_object_flush_fence(old);
if (ret)
return ret;
- }
-
- return 0;
- }
-
- reg = i915_find_fence_reg(dev, pipelined);
- if (reg == NULL)
- return -EDEADLK;
-
- ret = i915_gem_object_flush_fence(obj, pipelined);
- if (ret)
- return ret;
-
- if (reg->obj) {
- struct drm_i915_gem_object *old = reg->obj;
-
- drm_gem_object_reference(&old->base);
-
- if (old->tiling_mode)
- i915_gem_release_mmap(old);
- ret = i915_gem_object_flush_fence(old, pipelined);
- if (ret) {
- drm_gem_object_unreference(&old->base);
- return ret;
+ i915_gem_object_fence_lost(old);
}
+ } else
+ return 0;
- if (old->last_fenced_seqno == 0 && obj->last_fenced_seqno == 0)
- pipelined = NULL;
-
- old->fence_reg = I915_FENCE_REG_NONE;
- old->last_fenced_ring = pipelined;
- old->last_fenced_seqno =
- pipelined ? i915_gem_next_request_seqno(pipelined) : 0;
-
- drm_gem_object_unreference(&old->base);
- } else if (obj->last_fenced_seqno == 0)
- pipelined = NULL;
-
- reg->obj = obj;
- list_move_tail(&reg->lru_list, &dev_priv->mm.fence_list);
- obj->fence_reg = reg - dev_priv->fence_regs;
- obj->last_fenced_ring = pipelined;
-
- reg->setup_seqno =
- pipelined ? i915_gem_next_request_seqno(pipelined) : 0;
- obj->last_fenced_seqno = reg->setup_seqno;
-
-update:
- obj->tiling_changed = false;
- switch (INTEL_INFO(dev)->gen) {
- case 7:
- case 6:
- ret = sandybridge_write_fence_reg(obj, pipelined);
- break;
- case 5:
- case 4:
- ret = i965_write_fence_reg(obj, pipelined);
- break;
- case 3:
- ret = i915_write_fence_reg(obj, pipelined);
- break;
- case 2:
- ret = i830_write_fence_reg(obj, pipelined);
- break;
- }
-
- return ret;
-}
-
-/**
- * i915_gem_clear_fence_reg - clear out fence register info
- * @obj: object to clear
- *
- * Zeroes out the fence register itself and clears out the associated
- * data structures in dev_priv and obj.
- */
-static void
-i915_gem_clear_fence_reg(struct drm_device *dev,
- struct drm_i915_fence_reg *reg)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- uint32_t fence_reg = reg - dev_priv->fence_regs;
-
- switch (INTEL_INFO(dev)->gen) {
- case 7:
- case 6:
- I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + fence_reg*8, 0);
- break;
- case 5:
- case 4:
- I915_WRITE64(FENCE_REG_965_0 + fence_reg*8, 0);
- break;
- case 3:
- if (fence_reg >= 8)
- fence_reg = FENCE_REG_945_8 + (fence_reg - 8) * 4;
- else
- case 2:
- fence_reg = FENCE_REG_830_0 + fence_reg * 4;
-
- I915_WRITE(fence_reg, 0);
- break;
- }
+ i915_gem_object_update_fence(obj, reg, enable);
+ obj->fence_dirty = false;
- list_del_init(&reg->lru_list);
- reg->obj = NULL;
- reg->setup_seqno = 0;
- reg->pin_count = 0;
+ return 0;
}
/**
@@ -2749,7 +2607,7 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
return ret;
}
- ret = i915_gem_gtt_bind_object(obj);
+ ret = i915_gem_gtt_prepare_object(obj);
if (ret) {
i915_gem_object_put_pages_gtt(obj);
drm_mm_put_block(obj->gtt_space);
@@ -2761,6 +2619,9 @@ i915_gem_object_bind_to_gtt(struct drm_i915_gem_object *obj,
goto search_free;
}
+ if (!dev_priv->mm.aliasing_ppgtt)
+ i915_gem_gtt_bind_object(obj, obj->cache_level);
+
list_add_tail(&obj->gtt_list, &dev_priv->mm.gtt_list);
list_add_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
@@ -2878,6 +2739,7 @@ i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj)
int
i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
{
+ drm_i915_private_t *dev_priv = obj->base.dev->dev_private;
uint32_t old_write_domain, old_read_domains;
int ret;
@@ -2918,6 +2780,10 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
old_read_domains,
old_write_domain);
+ /* And bump the LRU for this access */
+ if (i915_gem_object_is_inactive(obj))
+ list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
+
return 0;
}
@@ -2953,7 +2819,8 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
return ret;
}
- i915_gem_gtt_rebind_object(obj, cache_level);
+ if (obj->has_global_gtt_mapping)
+ i915_gem_gtt_bind_object(obj, cache_level);
if (obj->has_aliasing_ppgtt_mapping)
i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt,
obj, cache_level);
@@ -2990,11 +2857,6 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
* Prepare buffer for display plane (scanout, cursors, etc).
* Can be called from an uninterruptible phase (modesetting) and allows
* any flushes to be pipelined (for pageflips).
- *
- * For the display plane, we want to be in the GTT but out of any write
- * domains. So in many ways this looks like set_to_gtt_domain() apart from the
- * ability to pipeline the waits, pinning and any additional subtleties
- * that may differentiate the display plane from ordinary buffers.
*/
int
i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
@@ -3009,8 +2871,8 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
return ret;
if (pipelined != obj->ring) {
- ret = i915_gem_object_wait_rendering(obj);
- if (ret == -ERESTARTSYS)
+ ret = i915_gem_object_sync(obj, pipelined);
+ if (ret)
return ret;
}
@@ -3082,7 +2944,7 @@ i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj)
* This function returns when the move is complete, including waiting on
* flushes to occur.
*/
-static int
+int
i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write)
{
uint32_t old_write_domain, old_read_domains;
@@ -3095,17 +2957,14 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write)
if (ret)
return ret;
- ret = i915_gem_object_wait_rendering(obj);
- if (ret)
- return ret;
+ if (write || obj->pending_gpu_write) {
+ ret = i915_gem_object_wait_rendering(obj);
+ if (ret)
+ return ret;
+ }
i915_gem_object_flush_gtt_write_domain(obj);
- /* If we have a partially-valid cache of the object in the CPU,
- * finish invalidating it and free the per-page flags.
- */
- i915_gem_object_set_to_full_cpu_read_domain(obj);
-
old_write_domain = obj->base.write_domain;
old_read_domains = obj->base.read_domains;
@@ -3136,113 +2995,6 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write)
return 0;
}
-/**
- * Moves the object from a partially CPU read to a full one.
- *
- * Note that this only resolves i915_gem_object_set_cpu_read_domain_range(),
- * and doesn't handle transitioning from !(read_domains & I915_GEM_DOMAIN_CPU).
- */
-static void
-i915_gem_object_set_to_full_cpu_read_domain(struct drm_i915_gem_object *obj)
-{
- if (!obj->page_cpu_valid)
- return;
-
- /* If we're partially in the CPU read domain, finish moving it in.
- */
- if (obj->base.read_domains & I915_GEM_DOMAIN_CPU) {
- int i;
-
- for (i = 0; i <= (obj->base.size - 1) / PAGE_SIZE; i++) {
- if (obj->page_cpu_valid[i])
- continue;
- drm_clflush_pages(obj->pages + i, 1);
- }
- }
-
- /* Free the page_cpu_valid mappings which are now stale, whether
- * or not we've got I915_GEM_DOMAIN_CPU.
- */
- kfree(obj->page_cpu_valid);
- obj->page_cpu_valid = NULL;
-}
-
-/**
- * Set the CPU read domain on a range of the object.
- *
- * The object ends up with I915_GEM_DOMAIN_CPU in its read flags although it's
- * not entirely valid. The page_cpu_valid member of the object flags which
- * pages have been flushed, and will be respected by
- * i915_gem_object_set_to_cpu_domain() if it's called on to get a valid mapping
- * of the whole object.
- *
- * This function returns when the move is complete, including waiting on
- * flushes to occur.
- */
-static int
-i915_gem_object_set_cpu_read_domain_range(struct drm_i915_gem_object *obj,
- uint64_t offset, uint64_t size)
-{
- uint32_t old_read_domains;
- int i, ret;
-
- if (offset == 0 && size == obj->base.size)
- return i915_gem_object_set_to_cpu_domain(obj, 0);
-
- ret = i915_gem_object_flush_gpu_write_domain(obj);
- if (ret)
- return ret;
-
- ret = i915_gem_object_wait_rendering(obj);
- if (ret)
- return ret;
-
- i915_gem_object_flush_gtt_write_domain(obj);
-
- /* If we're already fully in the CPU read domain, we're done. */
- if (obj->page_cpu_valid == NULL &&
- (obj->base.read_domains & I915_GEM_DOMAIN_CPU) != 0)
- return 0;
-
- /* Otherwise, create/clear the per-page CPU read domain flag if we're
- * newly adding I915_GEM_DOMAIN_CPU
- */
- if (obj->page_cpu_valid == NULL) {
- obj->page_cpu_valid = kzalloc(obj->base.size / PAGE_SIZE,
- GFP_KERNEL);
- if (obj->page_cpu_valid == NULL)
- return -ENOMEM;
- } else if ((obj->base.read_domains & I915_GEM_DOMAIN_CPU) == 0)
- memset(obj->page_cpu_valid, 0, obj->base.size / PAGE_SIZE);
-
- /* Flush the cache on any pages that are still invalid from the CPU's
- * perspective.
- */
- for (i = offset / PAGE_SIZE; i <= (offset + size - 1) / PAGE_SIZE;
- i++) {
- if (obj->page_cpu_valid[i])
- continue;
-
- drm_clflush_pages(obj->pages + i, 1);
-
- obj->page_cpu_valid[i] = 1;
- }
-
- /* It should now be out of any other write domains, and we can update
- * the domain values for our changes.
- */
- BUG_ON((obj->base.write_domain & ~I915_GEM_DOMAIN_CPU) != 0);
-
- old_read_domains = obj->base.read_domains;
- obj->base.read_domains |= I915_GEM_DOMAIN_CPU;
-
- trace_i915_gem_object_change_domain(obj,
- old_read_domains,
- obj->base.write_domain);
-
- return 0;
-}
-
/* Throttle our rendering by waiting until the ring has completed our requests
* emitted over 20 msec ago.
*
@@ -3280,28 +3032,7 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
if (seqno == 0)
return 0;
- ret = 0;
- if (!i915_seqno_passed(ring->get_seqno(ring), seqno)) {
- /* And wait for the seqno passing without holding any locks and
- * causing extra latency for others. This is safe as the irq
- * generation is designed to be run atomically and so is
- * lockless.
- */
- if (ring->irq_get(ring)) {
- ret = wait_event_interruptible(ring->irq_queue,
- i915_seqno_passed(ring->get_seqno(ring), seqno)
- || atomic_read(&dev_priv->mm.wedged));
- ring->irq_put(ring);
-
- if (ret == 0 && atomic_read(&dev_priv->mm.wedged))
- ret = -EIO;
- } else if (wait_for_atomic(i915_seqno_passed(ring->get_seqno(ring),
- seqno) ||
- atomic_read(&dev_priv->mm.wedged), 3000)) {
- ret = -EBUSY;
- }
- }
-
+ ret = __wait_seqno(ring, seqno, true);
if (ret == 0)
queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0);
@@ -3313,12 +3044,9 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj,
uint32_t alignment,
bool map_and_fenceable)
{
- struct drm_device *dev = obj->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
BUG_ON(obj->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT);
- WARN_ON(i915_verify_lists(dev));
if (obj->gtt_space != NULL) {
if ((alignment && obj->gtt_offset & (alignment - 1)) ||
@@ -3343,34 +3071,23 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj,
return ret;
}
- if (obj->pin_count++ == 0) {
- if (!obj->active)
- list_move_tail(&obj->mm_list,
- &dev_priv->mm.pinned_list);
- }
+ if (!obj->has_global_gtt_mapping && map_and_fenceable)
+ i915_gem_gtt_bind_object(obj, obj->cache_level);
+
+ obj->pin_count++;
obj->pin_mappable |= map_and_fenceable;
- WARN_ON(i915_verify_lists(dev));
return 0;
}
void
i915_gem_object_unpin(struct drm_i915_gem_object *obj)
{
- struct drm_device *dev = obj->base.dev;
- drm_i915_private_t *dev_priv = dev->dev_private;
-
- WARN_ON(i915_verify_lists(dev));
BUG_ON(obj->pin_count == 0);
BUG_ON(obj->gtt_space == NULL);
- if (--obj->pin_count == 0) {
- if (!obj->active)
- list_move_tail(&obj->mm_list,
- &dev_priv->mm.inactive_list);
+ if (--obj->pin_count == 0)
obj->pin_mappable = false;
- }
- WARN_ON(i915_verify_lists(dev));
}
int
@@ -3494,20 +3211,9 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) {
ret = i915_gem_flush_ring(obj->ring,
0, obj->base.write_domain);
- } else if (obj->ring->outstanding_lazy_request ==
- obj->last_rendering_seqno) {
- struct drm_i915_gem_request *request;
-
- /* This ring is not being cleared by active usage,
- * so emit a request to do so.
- */
- request = kzalloc(sizeof(*request), GFP_KERNEL);
- if (request) {
- ret = i915_add_request(obj->ring, NULL, request);
- if (ret)
- kfree(request);
- } else
- ret = -ENOMEM;
+ } else {
+ ret = i915_gem_check_olr(obj->ring,
+ obj->last_rendering_seqno);
}
/* Update the active list for the hardware's current position.
@@ -3643,46 +3349,42 @@ int i915_gem_init_object(struct drm_gem_object *obj)
return 0;
}
-static void i915_gem_free_object_tail(struct drm_i915_gem_object *obj)
+void i915_gem_free_object(struct drm_gem_object *gem_obj)
{
+ struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
struct drm_device *dev = obj->base.dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- int ret;
-
- ret = i915_gem_object_unbind(obj);
- if (ret == -ERESTARTSYS) {
- list_move(&obj->mm_list,
- &dev_priv->mm.deferred_free_list);
- return;
- }
trace_i915_gem_object_destroy(obj);
+ if (gem_obj->import_attach)
+ drm_prime_gem_destroy(gem_obj, obj->sg_table);
+
+ if (obj->phys_obj)
+ i915_gem_detach_phys_object(dev, obj);
+
+ obj->pin_count = 0;
+ if (WARN_ON(i915_gem_object_unbind(obj) == -ERESTARTSYS)) {
+ bool was_interruptible;
+
+ was_interruptible = dev_priv->mm.interruptible;
+ dev_priv->mm.interruptible = false;
+
+ WARN_ON(i915_gem_object_unbind(obj));
+
+ dev_priv->mm.interruptible = was_interruptible;
+ }
+
if (obj->base.map_list.map)
drm_gem_free_mmap_offset(&obj->base);
drm_gem_object_release(&obj->base);
i915_gem_info_remove_obj(dev_priv, obj->base.size);
- kfree(obj->page_cpu_valid);
kfree(obj->bit_17);
kfree(obj);
}
-void i915_gem_free_object(struct drm_gem_object *gem_obj)
-{
- struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
- struct drm_device *dev = obj->base.dev;
-
- while (obj->pin_count > 0)
- i915_gem_object_unpin(obj);
-
- if (obj->phys_obj)
- i915_gem_detach_phys_object(dev, obj);
-
- i915_gem_free_object_tail(obj);
-}
-
int
i915_gem_idle(struct drm_device *dev)
{
@@ -3696,20 +3398,16 @@ i915_gem_idle(struct drm_device *dev)
return 0;
}
- ret = i915_gpu_idle(dev, true);
+ ret = i915_gpu_idle(dev);
if (ret) {
mutex_unlock(&dev->struct_mutex);
return ret;
}
+ i915_gem_retire_requests(dev);
/* Under UMS, be paranoid and evict. */
- if (!drm_core_check_feature(dev, DRIVER_MODESET)) {
- ret = i915_gem_evict_inactive(dev, false);
- if (ret) {
- mutex_unlock(&dev->struct_mutex);
- return ret;
- }
- }
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
+ i915_gem_evict_everything(dev, false);
i915_gem_reset_fences(dev);
@@ -3747,9 +3445,9 @@ void i915_gem_init_swizzling(struct drm_device *dev)
I915_WRITE(TILECTL, I915_READ(TILECTL) | TILECTL_SWZCTL);
if (IS_GEN6(dev))
- I915_WRITE(ARB_MODE, ARB_MODE_ENABLE(ARB_MODE_SWIZZLE_SNB));
+ I915_WRITE(ARB_MODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_SNB));
else
- I915_WRITE(ARB_MODE, ARB_MODE_ENABLE(ARB_MODE_SWIZZLE_IVB));
+ I915_WRITE(ARB_MODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_IVB));
}
void i915_gem_init_ppgtt(struct drm_device *dev)
@@ -3787,21 +3485,27 @@ void i915_gem_init_ppgtt(struct drm_device *dev)
pd_offset <<= 16;
if (INTEL_INFO(dev)->gen == 6) {
- uint32_t ecochk = I915_READ(GAM_ECOCHK);
+ uint32_t ecochk, gab_ctl, ecobits;
+
+ ecobits = I915_READ(GAC_ECO_BITS);
+ I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B);
+
+ gab_ctl = I915_READ(GAB_CTL);
+ I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT);
+
+ ecochk = I915_READ(GAM_ECOCHK);
I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT |
ECOCHK_PPGTT_CACHE64B);
- I915_WRITE(GFX_MODE, GFX_MODE_ENABLE(GFX_PPGTT_ENABLE));
+ I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
} else if (INTEL_INFO(dev)->gen >= 7) {
I915_WRITE(GAM_ECOCHK, ECOCHK_PPGTT_CACHE64B);
/* GFX_MODE is per-ring on gen7+ */
}
- for (i = 0; i < I915_NUM_RINGS; i++) {
- ring = &dev_priv->ring[i];
-
+ for_each_ring(ring, dev_priv, i) {
if (INTEL_INFO(dev)->gen >= 7)
I915_WRITE(RING_MODE_GEN7(ring),
- GFX_MODE_ENABLE(GFX_PPGTT_ENABLE));
+ _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
I915_WRITE(RING_PP_DIR_BASE(ring), pd_offset);
@@ -3845,14 +3549,80 @@ cleanup_render_ring:
return ret;
}
+static bool
+intel_enable_ppgtt(struct drm_device *dev)
+{
+ if (i915_enable_ppgtt >= 0)
+ return i915_enable_ppgtt;
+
+#ifdef CONFIG_INTEL_IOMMU
+ /* Disable ppgtt on SNB if VT-d is on. */
+ if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped)
+ return false;
+#endif
+
+ return true;
+}
+
+int i915_gem_init(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ unsigned long gtt_size, mappable_size;
+ int ret;
+
+ gtt_size = dev_priv->mm.gtt->gtt_total_entries << PAGE_SHIFT;
+ mappable_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
+
+ mutex_lock(&dev->struct_mutex);
+ if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) {
+ /* PPGTT pdes are stolen from global gtt ptes, so shrink the
+ * aperture accordingly when using aliasing ppgtt. */
+ gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE;
+
+ i915_gem_init_global_gtt(dev, 0, mappable_size, gtt_size);
+
+ ret = i915_gem_init_aliasing_ppgtt(dev);
+ if (ret) {
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+ }
+ } else {
+ /* Let GEM Manage all of the aperture.
+ *
+ * However, leave one page at the end still bound to the scratch
+ * page. There are a number of places where the hardware
+ * apparently prefetches past the end of the object, and we've
+ * seen multiple hangs with the GPU head pointer stuck in a
+ * batchbuffer bound at the last page of the aperture. One page
+ * should be enough to keep any prefetching inside of the
+ * aperture.
+ */
+ i915_gem_init_global_gtt(dev, 0, mappable_size,
+ gtt_size);
+ }
+
+ ret = i915_gem_init_hw(dev);
+ mutex_unlock(&dev->struct_mutex);
+ if (ret) {
+ i915_gem_cleanup_aliasing_ppgtt(dev);
+ return ret;
+ }
+
+ /* Allow hardware batchbuffers unless told otherwise, but not for KMS. */
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
+ dev_priv->dri1.allow_batchbuffer = 1;
+ return 0;
+}
+
void
i915_gem_cleanup_ringbuffer(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring;
int i;
- for (i = 0; i < I915_NUM_RINGS; i++)
- intel_cleanup_ring_buffer(&dev_priv->ring[i]);
+ for_each_ring(ring, dev_priv, i)
+ intel_cleanup_ring_buffer(ring);
}
int
@@ -3860,7 +3630,7 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- int ret, i;
+ int ret;
if (drm_core_check_feature(dev, DRIVER_MODESET))
return 0;
@@ -3882,10 +3652,6 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
BUG_ON(!list_empty(&dev_priv->mm.active_list));
BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
BUG_ON(!list_empty(&dev_priv->mm.inactive_list));
- for (i = 0; i < I915_NUM_RINGS; i++) {
- BUG_ON(!list_empty(&dev_priv->ring[i].active_list));
- BUG_ON(!list_empty(&dev_priv->ring[i].request_list));
- }
mutex_unlock(&dev->struct_mutex);
ret = drm_irq_install(dev);
@@ -3944,9 +3710,7 @@ i915_gem_load(struct drm_device *dev)
INIT_LIST_HEAD(&dev_priv->mm.active_list);
INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
- INIT_LIST_HEAD(&dev_priv->mm.pinned_list);
INIT_LIST_HEAD(&dev_priv->mm.fence_list);
- INIT_LIST_HEAD(&dev_priv->mm.deferred_free_list);
INIT_LIST_HEAD(&dev_priv->mm.gtt_list);
for (i = 0; i < I915_NUM_RINGS; i++)
init_ring_lists(&dev_priv->ring[i]);
@@ -3958,12 +3722,8 @@ i915_gem_load(struct drm_device *dev)
/* On GEN3 we really need to make sure the ARB C3 LP bit is set */
if (IS_GEN3(dev)) {
- u32 tmp = I915_READ(MI_ARB_STATE);
- if (!(tmp & MI_ARB_C3_LP_WRITE_ENABLE)) {
- /* arb state is a masked write, so set bit + bit in mask */
- tmp = MI_ARB_C3_LP_WRITE_ENABLE | (MI_ARB_C3_LP_WRITE_ENABLE << MI_ARB_MASK_SHIFT);
- I915_WRITE(MI_ARB_STATE, tmp);
- }
+ I915_WRITE(MI_ARB_STATE,
+ _MASKED_BIT_ENABLE(MI_ARB_C3_LP_WRITE_ENABLE));
}
dev_priv->relative_constants_mode = I915_EXEC_CONSTANTS_REL_GENERAL;
@@ -3978,9 +3738,7 @@ i915_gem_load(struct drm_device *dev)
dev_priv->num_fence_regs = 8;
/* Initialize fence registers to zero */
- for (i = 0; i < dev_priv->num_fence_regs; i++) {
- i915_gem_clear_fence_reg(dev, &dev_priv->fence_regs[i]);
- }
+ i915_gem_reset_fences(dev);
i915_gem_detect_bit_6_swizzle(dev);
init_waitqueue_head(&dev_priv->pending_flip_queue);
@@ -4268,7 +4026,7 @@ rescan:
* This has a dramatic impact to reduce the number of
* OOM-killer events whilst running the GPU aggressively.
*/
- if (i915_gpu_idle(dev, true) == 0)
+ if (i915_gpu_idle(dev) == 0)
goto rescan;
}
mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/i915/i915_gem_debug.c b/drivers/gpu/drm/i915/i915_gem_debug.c
index cc93cac242d6..a4f6aaabca99 100644
--- a/drivers/gpu/drm/i915/i915_gem_debug.c
+++ b/drivers/gpu/drm/i915/i915_gem_debug.c
@@ -114,22 +114,6 @@ i915_verify_lists(struct drm_device *dev)
}
}
- list_for_each_entry(obj, &dev_priv->mm.pinned_list, list) {
- if (obj->base.dev != dev ||
- !atomic_read(&obj->base.refcount.refcount)) {
- DRM_ERROR("freed pinned %p\n", obj);
- err++;
- break;
- } else if (!obj->pin_count || obj->active ||
- (obj->base.write_domain & I915_GEM_GPU_DOMAINS)) {
- DRM_ERROR("invalid pinned %p (p %d a %d w %x)\n",
- obj,
- obj->pin_count, obj->active,
- obj->base.write_domain);
- err++;
- }
- }
-
return warned = err;
}
#endif /* WATCH_INACTIVE */
diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
new file mode 100644
index 000000000000..8e269178d6a5
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2012 Red Hat Inc
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Dave Airlie <airlied@redhat.com>
+ */
+#include "drmP.h"
+#include "i915_drv.h"
+#include <linux/dma-buf.h>
+
+static struct sg_table *i915_gem_map_dma_buf(struct dma_buf_attachment *attachment,
+ enum dma_data_direction dir)
+{
+ struct drm_i915_gem_object *obj = attachment->dmabuf->priv;
+ struct drm_device *dev = obj->base.dev;
+ int npages = obj->base.size / PAGE_SIZE;
+ struct sg_table *sg = NULL;
+ int ret;
+ int nents;
+
+ ret = i915_mutex_lock_interruptible(dev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ if (!obj->pages) {
+ ret = i915_gem_object_get_pages_gtt(obj, __GFP_NORETRY | __GFP_NOWARN);
+ if (ret)
+ goto out;
+ }
+
+ /* link the pages into an SG then map the sg */
+ sg = drm_prime_pages_to_sg(obj->pages, npages);
+ nents = dma_map_sg(attachment->dev, sg->sgl, sg->nents, dir);
+out:
+ mutex_unlock(&dev->struct_mutex);
+ return sg;
+}
+
+static void i915_gem_unmap_dma_buf(struct dma_buf_attachment *attachment,
+ struct sg_table *sg, enum dma_data_direction dir)
+{
+ dma_unmap_sg(attachment->dev, sg->sgl, sg->nents, dir);
+ sg_free_table(sg);
+ kfree(sg);
+}
+
+static void i915_gem_dmabuf_release(struct dma_buf *dma_buf)
+{
+ struct drm_i915_gem_object *obj = dma_buf->priv;
+
+ if (obj->base.export_dma_buf == dma_buf) {
+ /* drop the reference on the export fd holds */
+ obj->base.export_dma_buf = NULL;
+ drm_gem_object_unreference_unlocked(&obj->base);
+ }
+}
+
+static void *i915_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf, unsigned long page_num)
+{
+ return NULL;
+}
+
+static void i915_gem_dmabuf_kunmap_atomic(struct dma_buf *dma_buf, unsigned long page_num, void *addr)
+{
+
+}
+static void *i915_gem_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num)
+{
+ return NULL;
+}
+
+static void i915_gem_dmabuf_kunmap(struct dma_buf *dma_buf, unsigned long page_num, void *addr)
+{
+
+}
+
+static const struct dma_buf_ops i915_dmabuf_ops = {
+ .map_dma_buf = i915_gem_map_dma_buf,
+ .unmap_dma_buf = i915_gem_unmap_dma_buf,
+ .release = i915_gem_dmabuf_release,
+ .kmap = i915_gem_dmabuf_kmap,
+ .kmap_atomic = i915_gem_dmabuf_kmap_atomic,
+ .kunmap = i915_gem_dmabuf_kunmap,
+ .kunmap_atomic = i915_gem_dmabuf_kunmap_atomic,
+};
+
+struct dma_buf *i915_gem_prime_export(struct drm_device *dev,
+ struct drm_gem_object *gem_obj, int flags)
+{
+ struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
+
+ return dma_buf_export(obj, &i915_dmabuf_ops,
+ obj->base.size, 0600);
+}
+
+struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *dma_buf)
+{
+ struct dma_buf_attachment *attach;
+ struct sg_table *sg;
+ struct drm_i915_gem_object *obj;
+ int npages;
+ int size;
+ int ret;
+
+ /* is this one of own objects? */
+ if (dma_buf->ops == &i915_dmabuf_ops) {
+ obj = dma_buf->priv;
+ /* is it from our device? */
+ if (obj->base.dev == dev) {
+ drm_gem_object_reference(&obj->base);
+ return &obj->base;
+ }
+ }
+
+ /* need to attach */
+ attach = dma_buf_attach(dma_buf, dev->dev);
+ if (IS_ERR(attach))
+ return ERR_CAST(attach);
+
+ sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+ if (IS_ERR(sg)) {
+ ret = PTR_ERR(sg);
+ goto fail_detach;
+ }
+
+ size = dma_buf->size;
+ npages = size / PAGE_SIZE;
+
+ obj = kzalloc(sizeof(*obj), GFP_KERNEL);
+ if (obj == NULL) {
+ ret = -ENOMEM;
+ goto fail_unmap;
+ }
+
+ ret = drm_gem_private_object_init(dev, &obj->base, size);
+ if (ret) {
+ kfree(obj);
+ goto fail_unmap;
+ }
+
+ obj->sg_table = sg;
+ obj->base.import_attach = attach;
+
+ return &obj->base;
+
+fail_unmap:
+ dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);
+fail_detach:
+ dma_buf_detach(dma_buf, attach);
+ return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c
index 21a82710f4b2..ae7c24e12e52 100644
--- a/drivers/gpu/drm/i915/i915_gem_evict.c
+++ b/drivers/gpu/drm/i915/i915_gem_evict.c
@@ -35,6 +35,9 @@
static bool
mark_free(struct drm_i915_gem_object *obj, struct list_head *unwind)
{
+ if (obj->pin_count)
+ return false;
+
list_add(&obj->exec_list, unwind);
return drm_mm_scan_add_block(obj->gtt_space);
}
@@ -90,7 +93,7 @@ i915_gem_evict_something(struct drm_device *dev, int min_size,
/* Now merge in the soon-to-be-expired objects... */
list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
/* Does the object require an outstanding flush? */
- if (obj->base.write_domain || obj->pin_count)
+ if (obj->base.write_domain)
continue;
if (mark_free(obj, &unwind_list))
@@ -99,14 +102,11 @@ i915_gem_evict_something(struct drm_device *dev, int min_size,
/* Finally add anything with a pending flush (in order of retirement) */
list_for_each_entry(obj, &dev_priv->mm.flushing_list, mm_list) {
- if (obj->pin_count)
- continue;
-
if (mark_free(obj, &unwind_list))
goto found;
}
list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list) {
- if (!obj->base.write_domain || obj->pin_count)
+ if (!obj->base.write_domain)
continue;
if (mark_free(obj, &unwind_list))
@@ -166,8 +166,9 @@ int
i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- int ret;
+ struct drm_i915_gem_object *obj, *next;
bool lists_empty;
+ int ret;
lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
list_empty(&dev_priv->mm.flushing_list) &&
@@ -177,29 +178,24 @@ i915_gem_evict_everything(struct drm_device *dev, bool purgeable_only)
trace_i915_gem_evict_everything(dev, purgeable_only);
- /* Flush everything (on to the inactive lists) and evict */
- ret = i915_gpu_idle(dev, true);
+ /* The gpu_idle will flush everything in the write domain to the
+ * active list. Then we must move everything off the active list
+ * with retire requests.
+ */
+ ret = i915_gpu_idle(dev);
if (ret)
return ret;
- BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
+ i915_gem_retire_requests(dev);
- return i915_gem_evict_inactive(dev, purgeable_only);
-}
-
-/** Unbinds all inactive objects. */
-int
-i915_gem_evict_inactive(struct drm_device *dev, bool purgeable_only)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *obj, *next;
+ BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
+ /* Having flushed everything, unbind() should never raise an error */
list_for_each_entry_safe(obj, next,
&dev_priv->mm.inactive_list, mm_list) {
if (!purgeable_only || obj->madv != I915_MADV_WILLNEED) {
- int ret = i915_gem_object_unbind(obj);
- if (ret)
- return ret;
+ if (obj->pin_count == 0)
+ WARN_ON(i915_gem_object_unbind(obj));
}
}
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index de431942ded4..974a9f1068a3 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -266,6 +266,12 @@ eb_destroy(struct eb_objects *eb)
kfree(eb);
}
+static inline int use_cpu_reloc(struct drm_i915_gem_object *obj)
+{
+ return (obj->base.write_domain == I915_GEM_DOMAIN_CPU ||
+ obj->cache_level != I915_CACHE_NONE);
+}
+
static int
i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
struct eb_objects *eb,
@@ -273,6 +279,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
{
struct drm_device *dev = obj->base.dev;
struct drm_gem_object *target_obj;
+ struct drm_i915_gem_object *target_i915_obj;
uint32_t target_offset;
int ret = -EINVAL;
@@ -281,7 +288,8 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
if (unlikely(target_obj == NULL))
return -ENOENT;
- target_offset = to_intel_bo(target_obj)->gtt_offset;
+ target_i915_obj = to_intel_bo(target_obj);
+ target_offset = target_i915_obj->gtt_offset;
/* The target buffer should have appeared before us in the
* exec_object list, so it should have a GTT space bound by now.
@@ -352,11 +360,19 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
return ret;
}
+ /* We can't wait for rendering with pagefaults disabled */
+ if (obj->active && in_atomic())
+ return -EFAULT;
+
reloc->delta += target_offset;
- if (obj->base.write_domain == I915_GEM_DOMAIN_CPU) {
+ if (use_cpu_reloc(obj)) {
uint32_t page_offset = reloc->offset & ~PAGE_MASK;
char *vaddr;
+ ret = i915_gem_object_set_to_cpu_domain(obj, 1);
+ if (ret)
+ return ret;
+
vaddr = kmap_atomic(obj->pages[reloc->offset >> PAGE_SHIFT]);
*(uint32_t *)(vaddr + page_offset) = reloc->delta;
kunmap_atomic(vaddr);
@@ -365,11 +381,11 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
uint32_t __iomem *reloc_entry;
void __iomem *reloc_page;
- /* We can't wait for rendering with pagefaults disabled */
- if (obj->active && in_atomic())
- return -EFAULT;
+ ret = i915_gem_object_set_to_gtt_domain(obj, true);
+ if (ret)
+ return ret;
- ret = i915_gem_object_set_to_gtt_domain(obj, 1);
+ ret = i915_gem_object_put_fence(obj);
if (ret)
return ret;
@@ -383,6 +399,16 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
io_mapping_unmap_atomic(reloc_page);
}
+ /* Sandybridge PPGTT errata: We need a global gtt mapping for MI and
+ * pipe_control writes because the gpu doesn't properly redirect them
+ * through the ppgtt for non_secure batchbuffers. */
+ if (unlikely(IS_GEN6(dev) &&
+ reloc->write_domain == I915_GEM_DOMAIN_INSTRUCTION &&
+ !target_i915_obj->has_global_gtt_mapping)) {
+ i915_gem_gtt_bind_object(target_i915_obj,
+ target_i915_obj->cache_level);
+ }
+
/* and update the user's relocation entry */
reloc->presumed_offset = target_offset;
@@ -393,30 +419,46 @@ static int
i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj,
struct eb_objects *eb)
{
+#define N_RELOC(x) ((x) / sizeof(struct drm_i915_gem_relocation_entry))
+ struct drm_i915_gem_relocation_entry stack_reloc[N_RELOC(512)];
struct drm_i915_gem_relocation_entry __user *user_relocs;
struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
- int i, ret;
+ int remain, ret;
user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr;
- for (i = 0; i < entry->relocation_count; i++) {
- struct drm_i915_gem_relocation_entry reloc;
- if (__copy_from_user_inatomic(&reloc,
- user_relocs+i,
- sizeof(reloc)))
+ remain = entry->relocation_count;
+ while (remain) {
+ struct drm_i915_gem_relocation_entry *r = stack_reloc;
+ int count = remain;
+ if (count > ARRAY_SIZE(stack_reloc))
+ count = ARRAY_SIZE(stack_reloc);
+ remain -= count;
+
+ if (__copy_from_user_inatomic(r, user_relocs, count*sizeof(r[0])))
return -EFAULT;
- ret = i915_gem_execbuffer_relocate_entry(obj, eb, &reloc);
- if (ret)
- return ret;
+ do {
+ u64 offset = r->presumed_offset;
- if (__copy_to_user_inatomic(&user_relocs[i].presumed_offset,
- &reloc.presumed_offset,
- sizeof(reloc.presumed_offset)))
- return -EFAULT;
+ ret = i915_gem_execbuffer_relocate_entry(obj, eb, r);
+ if (ret)
+ return ret;
+
+ if (r->presumed_offset != offset &&
+ __copy_to_user_inatomic(&user_relocs->presumed_offset,
+ &r->presumed_offset,
+ sizeof(r->presumed_offset))) {
+ return -EFAULT;
+ }
+
+ user_relocs++;
+ r++;
+ } while (--count);
}
return 0;
+#undef N_RELOC
}
static int
@@ -465,6 +507,13 @@ i915_gem_execbuffer_relocate(struct drm_device *dev,
#define __EXEC_OBJECT_HAS_FENCE (1<<31)
static int
+need_reloc_mappable(struct drm_i915_gem_object *obj)
+{
+ struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
+ return entry->relocation_count && !use_cpu_reloc(obj);
+}
+
+static int
pin_and_fence_object(struct drm_i915_gem_object *obj,
struct intel_ring_buffer *ring)
{
@@ -477,8 +526,7 @@ pin_and_fence_object(struct drm_i915_gem_object *obj,
has_fenced_gpu_access &&
entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
obj->tiling_mode != I915_TILING_NONE;
- need_mappable =
- entry->relocation_count ? true : need_fence;
+ need_mappable = need_fence || need_reloc_mappable(obj);
ret = i915_gem_object_pin(obj, entry->alignment, need_mappable);
if (ret)
@@ -486,18 +534,13 @@ pin_and_fence_object(struct drm_i915_gem_object *obj,
if (has_fenced_gpu_access) {
if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) {
- if (obj->tiling_mode) {
- ret = i915_gem_object_get_fence(obj, ring);
- if (ret)
- goto err_unpin;
+ ret = i915_gem_object_get_fence(obj);
+ if (ret)
+ goto err_unpin;
+ if (i915_gem_object_pin_fence(obj))
entry->flags |= __EXEC_OBJECT_HAS_FENCE;
- i915_gem_object_pin_fence(obj);
- } else {
- ret = i915_gem_object_put_fence(obj);
- if (ret)
- goto err_unpin;
- }
+
obj->pending_fenced_gpu_access = true;
}
}
@@ -535,8 +578,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
has_fenced_gpu_access &&
entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
obj->tiling_mode != I915_TILING_NONE;
- need_mappable =
- entry->relocation_count ? true : need_fence;
+ need_mappable = need_fence || need_reloc_mappable(obj);
if (need_mappable)
list_move(&obj->exec_list, &ordered_objects);
@@ -576,8 +618,7 @@ i915_gem_execbuffer_reserve(struct intel_ring_buffer *ring,
has_fenced_gpu_access &&
entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
obj->tiling_mode != I915_TILING_NONE;
- need_mappable =
- entry->relocation_count ? true : need_fence;
+ need_mappable = need_fence || need_reloc_mappable(obj);
if ((entry->alignment && obj->gtt_offset & (entry->alignment - 1)) ||
(need_mappable && !obj->map_and_fenceable))
@@ -798,64 +839,6 @@ i915_gem_execbuffer_flush(struct drm_device *dev,
return 0;
}
-static bool
-intel_enable_semaphores(struct drm_device *dev)
-{
- if (INTEL_INFO(dev)->gen < 6)
- return 0;
-
- if (i915_semaphores >= 0)
- return i915_semaphores;
-
- /* Disable semaphores on SNB */
- if (INTEL_INFO(dev)->gen == 6)
- return 0;
-
- return 1;
-}
-
-static int
-i915_gem_execbuffer_sync_rings(struct drm_i915_gem_object *obj,
- struct intel_ring_buffer *to)
-{
- struct intel_ring_buffer *from = obj->ring;
- u32 seqno;
- int ret, idx;
-
- if (from == NULL || to == from)
- return 0;
-
- /* XXX gpu semaphores are implicated in various hard hangs on SNB */
- if (!intel_enable_semaphores(obj->base.dev))
- return i915_gem_object_wait_rendering(obj);
-
- idx = intel_ring_sync_index(from, to);
-
- seqno = obj->last_rendering_seqno;
- if (seqno <= from->sync_seqno[idx])
- return 0;
-
- if (seqno == from->outstanding_lazy_request) {
- struct drm_i915_gem_request *request;
-
- request = kzalloc(sizeof(*request), GFP_KERNEL);
- if (request == NULL)
- return -ENOMEM;
-
- ret = i915_add_request(from, NULL, request);
- if (ret) {
- kfree(request);
- return ret;
- }
-
- seqno = request->seqno;
- }
-
- from->sync_seqno[idx] = seqno;
-
- return to->sync_to(to, from, seqno - 1);
-}
-
static int
i915_gem_execbuffer_wait_for_flips(struct intel_ring_buffer *ring, u32 flips)
{
@@ -917,7 +900,7 @@ i915_gem_execbuffer_move_to_gpu(struct intel_ring_buffer *ring,
}
list_for_each_entry(obj, objects, exec_list) {
- ret = i915_gem_execbuffer_sync_rings(obj, ring);
+ ret = i915_gem_object_sync(obj, ring);
if (ret)
return ret;
}
@@ -955,7 +938,7 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
if (!access_ok(VERIFY_WRITE, ptr, length))
return -EFAULT;
- if (fault_in_pages_readable(ptr, length))
+ if (fault_in_multipages_readable(ptr, length))
return -EFAULT;
}
@@ -984,11 +967,14 @@ i915_gem_execbuffer_move_to_active(struct list_head *objects,
obj->pending_gpu_write = true;
list_move_tail(&obj->gpu_write_list,
&ring->gpu_write_list);
- intel_mark_busy(ring->dev, obj);
+ if (obj->pin_count) /* check for potential scanout */
+ intel_mark_busy(ring->dev, obj);
}
trace_i915_gem_object_change_domain(obj, old_read, old_write);
}
+
+ intel_mark_busy(ring->dev, NULL);
}
static void
@@ -1078,17 +1064,9 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
ring = &dev_priv->ring[RCS];
break;
case I915_EXEC_BSD:
- if (!HAS_BSD(dev)) {
- DRM_DEBUG("execbuf with invalid ring (BSD)\n");
- return -EINVAL;
- }
ring = &dev_priv->ring[VCS];
break;
case I915_EXEC_BLT:
- if (!HAS_BLT(dev)) {
- DRM_DEBUG("execbuf with invalid ring (BLT)\n");
- return -EINVAL;
- }
ring = &dev_priv->ring[BCS];
break;
default:
@@ -1096,6 +1074,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
(int)(args->flags & I915_EXEC_RING_MASK));
return -EINVAL;
}
+ if (!intel_ring_initialized(ring)) {
+ DRM_DEBUG("execbuf with invalid ring: %d\n",
+ (int)(args->flags & I915_EXEC_RING_MASK));
+ return -EINVAL;
+ }
mode = args->flags & I915_EXEC_CONSTANTS_MASK;
mask = I915_EXEC_CONSTANTS_MASK;
@@ -1133,11 +1116,17 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
return -EINVAL;
}
+ if (INTEL_INFO(dev)->gen >= 5) {
+ DRM_DEBUG("clip rectangles are only valid on pre-gen5\n");
+ return -EINVAL;
+ }
+
if (args->num_cliprects > UINT_MAX / sizeof(*cliprects)) {
DRM_DEBUG("execbuf with %u cliprects\n",
args->num_cliprects);
return -EINVAL;
}
+
cliprects = kmalloc(args->num_cliprects * sizeof(*cliprects),
GFP_KERNEL);
if (cliprects == NULL) {
@@ -1242,9 +1231,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
* so every billion or so execbuffers, we need to stall
* the GPU in order to reset the counters.
*/
- ret = i915_gpu_idle(dev, true);
+ ret = i915_gpu_idle(dev);
if (ret)
goto err;
+ i915_gem_retire_requests(dev);
BUG_ON(ring->sync_seqno[i]);
}
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index a135c61f4119..9fd25a435536 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -96,11 +96,10 @@ int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
GFP_KERNEL);
if (!ppgtt->pt_dma_addr)
goto err_pt_alloc;
- }
- for (i = 0; i < ppgtt->num_pd_entries; i++) {
- dma_addr_t pt_addr;
- if (dev_priv->mm.gtt->needs_dmar) {
+ for (i = 0; i < ppgtt->num_pd_entries; i++) {
+ dma_addr_t pt_addr;
+
pt_addr = pci_map_page(dev->pdev, ppgtt->pt_pages[i],
0, 4096,
PCI_DMA_BIDIRECTIONAL);
@@ -112,8 +111,7 @@ int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
}
ppgtt->pt_dma_addr[i] = pt_addr;
- } else
- pt_addr = page_to_phys(ppgtt->pt_pages[i]);
+ }
}
ppgtt->scratch_page_dma_addr = dev_priv->mm.gtt->scratch_page_dma;
@@ -269,7 +267,13 @@ void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
BUG();
}
- if (dev_priv->mm.gtt->needs_dmar) {
+ if (obj->sg_table) {
+ i915_ppgtt_insert_sg_entries(ppgtt,
+ obj->sg_table->sgl,
+ obj->sg_table->nents,
+ obj->gtt_space->start >> PAGE_SHIFT,
+ pte_flags);
+ } else if (dev_priv->mm.gtt->needs_dmar) {
BUG_ON(!obj->sg_list);
i915_ppgtt_insert_sg_entries(ppgtt,
@@ -319,7 +323,7 @@ static bool do_idling(struct drm_i915_private *dev_priv)
if (unlikely(dev_priv->mm.gtt->do_idle_maps)) {
dev_priv->mm.interruptible = false;
- if (i915_gpu_idle(dev_priv->dev, false)) {
+ if (i915_gpu_idle(dev_priv->dev)) {
DRM_ERROR("Couldn't idle GPU\n");
/* Wait a bit, in hopes it avoids the hang */
udelay(10);
@@ -346,48 +350,39 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
i915_gem_clflush_object(obj);
- i915_gem_gtt_rebind_object(obj, obj->cache_level);
+ i915_gem_gtt_bind_object(obj, obj->cache_level);
}
intel_gtt_chipset_flush();
}
-int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj)
+int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj)
{
struct drm_device *dev = obj->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- unsigned int agp_type = cache_level_to_agp_type(dev, obj->cache_level);
- int ret;
-
- if (dev_priv->mm.gtt->needs_dmar) {
- ret = intel_gtt_map_memory(obj->pages,
- obj->base.size >> PAGE_SHIFT,
- &obj->sg_list,
- &obj->num_sg);
- if (ret != 0)
- return ret;
-
- intel_gtt_insert_sg_entries(obj->sg_list,
- obj->num_sg,
- obj->gtt_space->start >> PAGE_SHIFT,
- agp_type);
- } else
- intel_gtt_insert_pages(obj->gtt_space->start >> PAGE_SHIFT,
- obj->base.size >> PAGE_SHIFT,
- obj->pages,
- agp_type);
- return 0;
+ if (dev_priv->mm.gtt->needs_dmar)
+ return intel_gtt_map_memory(obj->pages,
+ obj->base.size >> PAGE_SHIFT,
+ &obj->sg_list,
+ &obj->num_sg);
+ else
+ return 0;
}
-void i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj,
- enum i915_cache_level cache_level)
+void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj,
+ enum i915_cache_level cache_level)
{
struct drm_device *dev = obj->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned int agp_type = cache_level_to_agp_type(dev, cache_level);
- if (dev_priv->mm.gtt->needs_dmar) {
+ if (obj->sg_table) {
+ intel_gtt_insert_sg_entries(obj->sg_table->sgl,
+ obj->sg_table->nents,
+ obj->gtt_space->start >> PAGE_SHIFT,
+ agp_type);
+ } else if (dev_priv->mm.gtt->needs_dmar) {
BUG_ON(!obj->sg_list);
intel_gtt_insert_sg_entries(obj->sg_list,
@@ -399,19 +394,26 @@ void i915_gem_gtt_rebind_object(struct drm_i915_gem_object *obj,
obj->base.size >> PAGE_SHIFT,
obj->pages,
agp_type);
+
+ obj->has_global_gtt_mapping = 1;
}
void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj)
{
+ intel_gtt_clear_range(obj->gtt_space->start >> PAGE_SHIFT,
+ obj->base.size >> PAGE_SHIFT);
+
+ obj->has_global_gtt_mapping = 0;
+}
+
+void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj)
+{
struct drm_device *dev = obj->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
bool interruptible;
interruptible = do_idling(dev_priv);
- intel_gtt_clear_range(obj->gtt_space->start >> PAGE_SHIFT,
- obj->base.size >> PAGE_SHIFT);
-
if (obj->sg_list) {
intel_gtt_unmap_memory(obj->sg_list, obj->num_sg);
obj->sg_list = NULL;
@@ -419,3 +421,23 @@ void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj)
undo_idling(dev_priv, interruptible);
}
+
+void i915_gem_init_global_gtt(struct drm_device *dev,
+ unsigned long start,
+ unsigned long mappable_end,
+ unsigned long end)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ /* Substract the guard page ... */
+ drm_mm_init(&dev_priv->mm.gtt_space, start, end - start - PAGE_SIZE);
+
+ dev_priv->mm.gtt_start = start;
+ dev_priv->mm.gtt_mappable_end = mappable_end;
+ dev_priv->mm.gtt_end = end;
+ dev_priv->mm.gtt_total = end - start;
+ dev_priv->mm.mappable_gtt_total = min(end, mappable_end) - start;
+
+ /* ... but ensure that we clear the entire range. */
+ intel_gtt_clear_range(start / PAGE_SIZE, (end-start) / PAGE_SIZE);
+}
diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c
new file mode 100644
index 000000000000..ada2e90a2a60
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_gem_stolen.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright © 2008-2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+#include "i915_drv.h"
+
+/*
+ * The BIOS typically reserves some of the system's memory for the exclusive
+ * use of the integrated graphics. This memory is no longer available for
+ * use by the OS and so the user finds that his system has less memory
+ * available than he put in. We refer to this memory as stolen.
+ *
+ * The BIOS will allocate its framebuffer from the stolen memory. Our
+ * goal is try to reuse that object for our own fbcon which must always
+ * be available for panics. Anything else we can reuse the stolen memory
+ * for is a boon.
+ */
+
+#define PTE_ADDRESS_MASK 0xfffff000
+#define PTE_ADDRESS_MASK_HIGH 0x000000f0 /* i915+ */
+#define PTE_MAPPING_TYPE_UNCACHED (0 << 1)
+#define PTE_MAPPING_TYPE_DCACHE (1 << 1) /* i830 only */
+#define PTE_MAPPING_TYPE_CACHED (3 << 1)
+#define PTE_MAPPING_TYPE_MASK (3 << 1)
+#define PTE_VALID (1 << 0)
+
+/**
+ * i915_stolen_to_phys - take an offset into stolen memory and turn it into
+ * a physical one
+ * @dev: drm device
+ * @offset: address to translate
+ *
+ * Some chip functions require allocations from stolen space and need the
+ * physical address of the memory in question.
+ */
+static unsigned long i915_stolen_to_phys(struct drm_device *dev, u32 offset)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct pci_dev *pdev = dev_priv->bridge_dev;
+ u32 base;
+
+#if 0
+ /* On the machines I have tested the Graphics Base of Stolen Memory
+ * is unreliable, so compute the base by subtracting the stolen memory
+ * from the Top of Low Usable DRAM which is where the BIOS places
+ * the graphics stolen memory.
+ */
+ if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) {
+ /* top 32bits are reserved = 0 */
+ pci_read_config_dword(pdev, 0xA4, &base);
+ } else {
+ /* XXX presume 8xx is the same as i915 */
+ pci_bus_read_config_dword(pdev->bus, 2, 0x5C, &base);
+ }
+#else
+ if (INTEL_INFO(dev)->gen > 3 || IS_G33(dev)) {
+ u16 val;
+ pci_read_config_word(pdev, 0xb0, &val);
+ base = val >> 4 << 20;
+ } else {
+ u8 val;
+ pci_read_config_byte(pdev, 0x9c, &val);
+ base = val >> 3 << 27;
+ }
+ base -= dev_priv->mm.gtt->stolen_size;
+#endif
+
+ return base + offset;
+}
+
+static void i915_warn_stolen(struct drm_device *dev)
+{
+ DRM_INFO("not enough stolen space for compressed buffer, disabling\n");
+ DRM_INFO("hint: you may be able to increase stolen memory size in the BIOS to avoid this\n");
+}
+
+static void i915_setup_compression(struct drm_device *dev, int size)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_mm_node *compressed_fb, *uninitialized_var(compressed_llb);
+ unsigned long cfb_base;
+ unsigned long ll_base = 0;
+
+ /* Just in case the BIOS is doing something questionable. */
+ intel_disable_fbc(dev);
+
+ compressed_fb = drm_mm_search_free(&dev_priv->mm.stolen, size, 4096, 0);
+ if (compressed_fb)
+ compressed_fb = drm_mm_get_block(compressed_fb, size, 4096);
+ if (!compressed_fb)
+ goto err;
+
+ cfb_base = i915_stolen_to_phys(dev, compressed_fb->start);
+ if (!cfb_base)
+ goto err_fb;
+
+ if (!(IS_GM45(dev) || HAS_PCH_SPLIT(dev))) {
+ compressed_llb = drm_mm_search_free(&dev_priv->mm.stolen,
+ 4096, 4096, 0);
+ if (compressed_llb)
+ compressed_llb = drm_mm_get_block(compressed_llb,
+ 4096, 4096);
+ if (!compressed_llb)
+ goto err_fb;
+
+ ll_base = i915_stolen_to_phys(dev, compressed_llb->start);
+ if (!ll_base)
+ goto err_llb;
+ }
+
+ dev_priv->cfb_size = size;
+
+ dev_priv->compressed_fb = compressed_fb;
+ if (HAS_PCH_SPLIT(dev))
+ I915_WRITE(ILK_DPFC_CB_BASE, compressed_fb->start);
+ else if (IS_GM45(dev)) {
+ I915_WRITE(DPFC_CB_BASE, compressed_fb->start);
+ } else {
+ I915_WRITE(FBC_CFB_BASE, cfb_base);
+ I915_WRITE(FBC_LL_BASE, ll_base);
+ dev_priv->compressed_llb = compressed_llb;
+ }
+
+ DRM_DEBUG_KMS("FBC base 0x%08lx, ll base 0x%08lx, size %dM\n",
+ cfb_base, ll_base, size >> 20);
+ return;
+
+err_llb:
+ drm_mm_put_block(compressed_llb);
+err_fb:
+ drm_mm_put_block(compressed_fb);
+err:
+ dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
+ i915_warn_stolen(dev);
+}
+
+static void i915_cleanup_compression(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ drm_mm_put_block(dev_priv->compressed_fb);
+ if (dev_priv->compressed_llb)
+ drm_mm_put_block(dev_priv->compressed_llb);
+}
+
+void i915_gem_cleanup_stolen(struct drm_device *dev)
+{
+ if (I915_HAS_FBC(dev) && i915_powersave)
+ i915_cleanup_compression(dev);
+}
+
+int i915_gem_init_stolen(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ unsigned long prealloc_size = dev_priv->mm.gtt->stolen_size;
+
+ /* Basic memrange allocator for stolen space */
+ drm_mm_init(&dev_priv->mm.stolen, 0, prealloc_size);
+
+ /* Try to set up FBC with a reasonable compressed buffer size */
+ if (I915_HAS_FBC(dev) && i915_powersave) {
+ int cfb_size;
+
+ /* Leave 1M for line length buffer & misc. */
+
+ /* Try to get a 32M buffer... */
+ if (prealloc_size > (36*1024*1024))
+ cfb_size = 32*1024*1024;
+ else /* fall back to 7/8 of the stolen space */
+ cfb_size = prealloc_size * 7 / 8;
+ i915_setup_compression(dev, cfb_size);
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index 1a9306665987..b964df51cec7 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -354,9 +354,15 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
/* We need to rebind the object if its current allocation
* no longer meets the alignment restrictions for its new
* tiling mode. Otherwise we can just leave it alone, but
- * need to ensure that any fence register is cleared.
+ * need to ensure that any fence register is updated before
+ * the next fenced (either through the GTT or by the BLT unit
+ * on older GPUs) access.
+ *
+ * After updating the tiling parameters, we then flag whether
+ * we need to update an associated fence register. Note this
+ * has to also include the unfenced register the GPU uses
+ * whilst executing a fenced command for an untiled object.
*/
- i915_gem_release_mmap(obj);
obj->map_and_fenceable =
obj->gtt_space == NULL ||
@@ -374,9 +380,15 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
}
if (ret == 0) {
- obj->tiling_changed = true;
+ obj->fence_dirty =
+ obj->fenced_gpu_access ||
+ obj->fence_reg != I915_FENCE_REG_NONE;
+
obj->tiling_mode = args->tiling_mode;
obj->stride = args->stride;
+
+ /* Force the fence to be reacquired for GTT access */
+ i915_gem_release_mmap(obj);
}
}
/* we have to maintain this existing ABI... */
diff --git a/drivers/gpu/drm/i915/i915_ioc32.c b/drivers/gpu/drm/i915/i915_ioc32.c
index 13b028994b2b..0e72abb9f701 100644
--- a/drivers/gpu/drm/i915/i915_ioc32.c
+++ b/drivers/gpu/drm/i915/i915_ioc32.c
@@ -34,6 +34,7 @@
#include "drmP.h"
#include "drm.h"
#include "i915_drm.h"
+#include "i915_drv.h"
typedef struct _drm_i915_batchbuffer32 {
int start; /* agp offset */
@@ -181,7 +182,7 @@ static int compat_i915_alloc(struct file *file, unsigned int cmd,
(unsigned long)request);
}
-drm_ioctl_compat_t *i915_compat_ioctls[] = {
+static drm_ioctl_compat_t *i915_compat_ioctls[] = {
[DRM_I915_BATCHBUFFER] = compat_i915_batchbuffer,
[DRM_I915_CMDBUFFER] = compat_i915_cmdbuffer,
[DRM_I915_GETPARAM] = compat_i915_getparam,
@@ -189,6 +190,7 @@ drm_ioctl_compat_t *i915_compat_ioctls[] = {
[DRM_I915_ALLOC] = compat_i915_alloc
};
+#ifdef CONFIG_COMPAT
/**
* Called whenever a 32-bit process running under a 64-bit kernel
* performs an ioctl on /dev/dri/card<n>.
@@ -217,3 +219,4 @@ long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return ret;
}
+#endif
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index afd4e03e337e..cc4a63307611 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -26,6 +26,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/sysrq.h>
#include <linux/slab.h>
#include "drmP.h"
@@ -35,35 +37,6 @@
#include "i915_trace.h"
#include "intel_drv.h"
-#define MAX_NOPID ((u32)~0)
-
-/**
- * Interrupts that are always left unmasked.
- *
- * Since pipe events are edge-triggered from the PIPESTAT register to IIR,
- * we leave them always unmasked in IMR and then control enabling them through
- * PIPESTAT alone.
- */
-#define I915_INTERRUPT_ENABLE_FIX \
- (I915_ASLE_INTERRUPT | \
- I915_DISPLAY_PIPE_A_EVENT_INTERRUPT | \
- I915_DISPLAY_PIPE_B_EVENT_INTERRUPT | \
- I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT | \
- I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT | \
- I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
-
-/** Interrupts that we mask and unmask at runtime. */
-#define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT | I915_BSD_USER_INTERRUPT)
-
-#define I915_PIPE_VBLANK_STATUS (PIPE_START_VBLANK_INTERRUPT_STATUS |\
- PIPE_VBLANK_INTERRUPT_STATUS)
-
-#define I915_PIPE_VBLANK_ENABLE (PIPE_START_VBLANK_INTERRUPT_ENABLE |\
- PIPE_VBLANK_INTERRUPT_ENABLE)
-
-#define DRM_I915_VBLANK_PIPE_ALL (DRM_I915_VBLANK_PIPE_A | \
- DRM_I915_VBLANK_PIPE_B)
-
/* For display hotplug interrupt */
static void
ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
@@ -118,6 +91,10 @@ void intel_enable_asle(struct drm_device *dev)
drm_i915_private_t *dev_priv = dev->dev_private;
unsigned long irqflags;
+ /* FIXME: opregion/asle for VLV */
+ if (IS_VALLEYVIEW(dev))
+ return;
+
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
if (HAS_PCH_SPLIT(dev))
@@ -354,15 +331,12 @@ static void notify_ring(struct drm_device *dev,
struct intel_ring_buffer *ring)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 seqno;
if (ring->obj == NULL)
return;
- seqno = ring->get_seqno(ring);
- trace_i915_gem_request_complete(ring, seqno);
+ trace_i915_gem_request_complete(ring, ring->get_seqno(ring));
- ring->irq_seqno = seqno;
wake_up_all(&ring->irq_queue);
if (i915_enable_hangcheck) {
dev_priv->hangcheck_count = 0;
@@ -424,13 +398,145 @@ static void gen6_pm_rps_work(struct work_struct *work)
mutex_unlock(&dev_priv->dev->struct_mutex);
}
-static void pch_irq_handler(struct drm_device *dev)
+static void snb_gt_irq_handler(struct drm_device *dev,
+ struct drm_i915_private *dev_priv,
+ u32 gt_iir)
+{
+
+ if (gt_iir & (GEN6_RENDER_USER_INTERRUPT |
+ GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT))
+ notify_ring(dev, &dev_priv->ring[RCS]);
+ if (gt_iir & GEN6_BSD_USER_INTERRUPT)
+ notify_ring(dev, &dev_priv->ring[VCS]);
+ if (gt_iir & GEN6_BLITTER_USER_INTERRUPT)
+ notify_ring(dev, &dev_priv->ring[BCS]);
+
+ if (gt_iir & (GT_GEN6_BLT_CS_ERROR_INTERRUPT |
+ GT_GEN6_BSD_CS_ERROR_INTERRUPT |
+ GT_RENDER_CS_ERROR_INTERRUPT)) {
+ DRM_ERROR("GT error interrupt 0x%08x\n", gt_iir);
+ i915_handle_error(dev, false);
+ }
+}
+
+static void gen6_queue_rps_work(struct drm_i915_private *dev_priv,
+ u32 pm_iir)
+{
+ unsigned long flags;
+
+ /*
+ * IIR bits should never already be set because IMR should
+ * prevent an interrupt from being shown in IIR. The warning
+ * displays a case where we've unsafely cleared
+ * dev_priv->pm_iir. Although missing an interrupt of the same
+ * type is not a problem, it displays a problem in the logic.
+ *
+ * The mask bit in IMR is cleared by rps_work.
+ */
+
+ spin_lock_irqsave(&dev_priv->rps_lock, flags);
+ WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n");
+ dev_priv->pm_iir |= pm_iir;
+ I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir);
+ POSTING_READ(GEN6_PMIMR);
+ spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
+
+ queue_work(dev_priv->wq, &dev_priv->rps_work);
+}
+
+static irqreturn_t valleyview_irq_handler(DRM_IRQ_ARGS)
{
+ struct drm_device *dev = (struct drm_device *) arg;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u32 pch_iir;
+ u32 iir, gt_iir, pm_iir;
+ irqreturn_t ret = IRQ_NONE;
+ unsigned long irqflags;
int pipe;
+ u32 pipe_stats[I915_MAX_PIPES];
+ u32 vblank_status;
+ int vblank = 0;
+ bool blc_event;
- pch_iir = I915_READ(SDEIIR);
+ atomic_inc(&dev_priv->irq_received);
+
+ vblank_status = PIPE_START_VBLANK_INTERRUPT_STATUS |
+ PIPE_VBLANK_INTERRUPT_STATUS;
+
+ while (true) {
+ iir = I915_READ(VLV_IIR);
+ gt_iir = I915_READ(GTIIR);
+ pm_iir = I915_READ(GEN6_PMIIR);
+
+ if (gt_iir == 0 && pm_iir == 0 && iir == 0)
+ goto out;
+
+ ret = IRQ_HANDLED;
+
+ snb_gt_irq_handler(dev, dev_priv, gt_iir);
+
+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+ for_each_pipe(pipe) {
+ int reg = PIPESTAT(pipe);
+ pipe_stats[pipe] = I915_READ(reg);
+
+ /*
+ * Clear the PIPE*STAT regs before the IIR
+ */
+ if (pipe_stats[pipe] & 0x8000ffff) {
+ if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
+ DRM_DEBUG_DRIVER("pipe %c underrun\n",
+ pipe_name(pipe));
+ I915_WRITE(reg, pipe_stats[pipe]);
+ }
+ }
+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+ /* Consume port. Then clear IIR or we'll miss events */
+ if (iir & I915_DISPLAY_PORT_INTERRUPT) {
+ u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
+
+ DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
+ hotplug_status);
+ if (hotplug_status & dev_priv->hotplug_supported_mask)
+ queue_work(dev_priv->wq,
+ &dev_priv->hotplug_work);
+
+ I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
+ I915_READ(PORT_HOTPLUG_STAT);
+ }
+
+
+ if (iir & I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT) {
+ drm_handle_vblank(dev, 0);
+ vblank++;
+ intel_finish_page_flip(dev, 0);
+ }
+
+ if (iir & I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT) {
+ drm_handle_vblank(dev, 1);
+ vblank++;
+ intel_finish_page_flip(dev, 0);
+ }
+
+ if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
+ blc_event = true;
+
+ if (pm_iir & GEN6_PM_DEFERRED_EVENTS)
+ gen6_queue_rps_work(dev_priv, pm_iir);
+
+ I915_WRITE(GTIIR, gt_iir);
+ I915_WRITE(GEN6_PMIIR, pm_iir);
+ I915_WRITE(VLV_IIR, iir);
+ }
+
+out:
+ return ret;
+}
+
+static void pch_irq_handler(struct drm_device *dev, u32 pch_iir)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ int pipe;
if (pch_iir & SDE_AUDIO_POWER_MASK)
DRM_DEBUG_DRIVER("PCH audio power change on port %d\n",
@@ -471,91 +577,77 @@ static irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS)
{
struct drm_device *dev = (struct drm_device *) arg;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- int ret = IRQ_NONE;
- u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir;
- struct drm_i915_master_private *master_priv;
+ u32 de_iir, gt_iir, de_ier, pm_iir;
+ irqreturn_t ret = IRQ_NONE;
+ int i;
atomic_inc(&dev_priv->irq_received);
/* disable master interrupt before clearing iir */
de_ier = I915_READ(DEIER);
I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
- POSTING_READ(DEIER);
- de_iir = I915_READ(DEIIR);
gt_iir = I915_READ(GTIIR);
- pch_iir = I915_READ(SDEIIR);
- pm_iir = I915_READ(GEN6_PMIIR);
-
- if (de_iir == 0 && gt_iir == 0 && pch_iir == 0 && pm_iir == 0)
- goto done;
-
- ret = IRQ_HANDLED;
-
- if (dev->primary->master) {
- master_priv = dev->primary->master->driver_priv;
- if (master_priv->sarea_priv)
- master_priv->sarea_priv->last_dispatch =
- READ_BREADCRUMB(dev_priv);
+ if (gt_iir) {
+ snb_gt_irq_handler(dev, dev_priv, gt_iir);
+ I915_WRITE(GTIIR, gt_iir);
+ ret = IRQ_HANDLED;
}
- if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY))
- notify_ring(dev, &dev_priv->ring[RCS]);
- if (gt_iir & GT_GEN6_BSD_USER_INTERRUPT)
- notify_ring(dev, &dev_priv->ring[VCS]);
- if (gt_iir & GT_BLT_USER_INTERRUPT)
- notify_ring(dev, &dev_priv->ring[BCS]);
-
- if (de_iir & DE_GSE_IVB)
- intel_opregion_gse_intr(dev);
-
- if (de_iir & DE_PLANEA_FLIP_DONE_IVB) {
- intel_prepare_page_flip(dev, 0);
- intel_finish_page_flip_plane(dev, 0);
- }
+ de_iir = I915_READ(DEIIR);
+ if (de_iir) {
+ if (de_iir & DE_GSE_IVB)
+ intel_opregion_gse_intr(dev);
+
+ for (i = 0; i < 3; i++) {
+ if (de_iir & (DE_PLANEA_FLIP_DONE_IVB << (5 * i))) {
+ intel_prepare_page_flip(dev, i);
+ intel_finish_page_flip_plane(dev, i);
+ }
+ if (de_iir & (DE_PIPEA_VBLANK_IVB << (5 * i)))
+ drm_handle_vblank(dev, i);
+ }
- if (de_iir & DE_PLANEB_FLIP_DONE_IVB) {
- intel_prepare_page_flip(dev, 1);
- intel_finish_page_flip_plane(dev, 1);
- }
+ /* check event from PCH */
+ if (de_iir & DE_PCH_EVENT_IVB) {
+ u32 pch_iir = I915_READ(SDEIIR);
- if (de_iir & DE_PIPEA_VBLANK_IVB)
- drm_handle_vblank(dev, 0);
+ if (pch_iir & SDE_HOTPLUG_MASK_CPT)
+ queue_work(dev_priv->wq, &dev_priv->hotplug_work);
+ pch_irq_handler(dev, pch_iir);
- if (de_iir & DE_PIPEB_VBLANK_IVB)
- drm_handle_vblank(dev, 1);
+ /* clear PCH hotplug event before clear CPU irq */
+ I915_WRITE(SDEIIR, pch_iir);
+ }
- /* check event from PCH */
- if (de_iir & DE_PCH_EVENT_IVB) {
- if (pch_iir & SDE_HOTPLUG_MASK_CPT)
- queue_work(dev_priv->wq, &dev_priv->hotplug_work);
- pch_irq_handler(dev);
+ I915_WRITE(DEIIR, de_iir);
+ ret = IRQ_HANDLED;
}
- if (pm_iir & GEN6_PM_DEFERRED_EVENTS) {
- unsigned long flags;
- spin_lock_irqsave(&dev_priv->rps_lock, flags);
- WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n");
- dev_priv->pm_iir |= pm_iir;
- I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir);
- POSTING_READ(GEN6_PMIMR);
- spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
- queue_work(dev_priv->wq, &dev_priv->rps_work);
+ pm_iir = I915_READ(GEN6_PMIIR);
+ if (pm_iir) {
+ if (pm_iir & GEN6_PM_DEFERRED_EVENTS)
+ gen6_queue_rps_work(dev_priv, pm_iir);
+ I915_WRITE(GEN6_PMIIR, pm_iir);
+ ret = IRQ_HANDLED;
}
- /* should clear PCH hotplug event before clear CPU irq */
- I915_WRITE(SDEIIR, pch_iir);
- I915_WRITE(GTIIR, gt_iir);
- I915_WRITE(DEIIR, de_iir);
- I915_WRITE(GEN6_PMIIR, pm_iir);
-
-done:
I915_WRITE(DEIER, de_ier);
POSTING_READ(DEIER);
return ret;
}
+static void ilk_gt_irq_handler(struct drm_device *dev,
+ struct drm_i915_private *dev_priv,
+ u32 gt_iir)
+{
+ if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY))
+ notify_ring(dev, &dev_priv->ring[RCS]);
+ if (gt_iir & GT_BSD_USER_INTERRUPT)
+ notify_ring(dev, &dev_priv->ring[VCS]);
+}
+
static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS)
{
struct drm_device *dev = (struct drm_device *) arg;
@@ -563,14 +655,9 @@ static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS)
int ret = IRQ_NONE;
u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir;
u32 hotplug_mask;
- struct drm_i915_master_private *master_priv;
- u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT;
atomic_inc(&dev_priv->irq_received);
- if (IS_GEN6(dev))
- bsd_usr_interrupt = GT_GEN6_BSD_USER_INTERRUPT;
-
/* disable master interrupt before clearing iir */
de_ier = I915_READ(DEIER);
I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
@@ -592,19 +679,10 @@ static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS)
ret = IRQ_HANDLED;
- if (dev->primary->master) {
- master_priv = dev->primary->master->driver_priv;
- if (master_priv->sarea_priv)
- master_priv->sarea_priv->last_dispatch =
- READ_BREADCRUMB(dev_priv);
- }
-
- if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY))
- notify_ring(dev, &dev_priv->ring[RCS]);
- if (gt_iir & bsd_usr_interrupt)
- notify_ring(dev, &dev_priv->ring[VCS]);
- if (gt_iir & GT_BLT_USER_INTERRUPT)
- notify_ring(dev, &dev_priv->ring[BCS]);
+ if (IS_GEN5(dev))
+ ilk_gt_irq_handler(dev, dev_priv, gt_iir);
+ else
+ snb_gt_irq_handler(dev, dev_priv, gt_iir);
if (de_iir & DE_GSE)
intel_opregion_gse_intr(dev);
@@ -629,7 +707,7 @@ static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS)
if (de_iir & DE_PCH_EVENT) {
if (pch_iir & hotplug_mask)
queue_work(dev_priv->wq, &dev_priv->hotplug_work);
- pch_irq_handler(dev);
+ pch_irq_handler(dev, pch_iir);
}
if (de_iir & DE_PCU_EVENT) {
@@ -637,25 +715,8 @@ static irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS)
i915_handle_rps_change(dev);
}
- if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS) {
- /*
- * IIR bits should never already be set because IMR should
- * prevent an interrupt from being shown in IIR. The warning
- * displays a case where we've unsafely cleared
- * dev_priv->pm_iir. Although missing an interrupt of the same
- * type is not a problem, it displays a problem in the logic.
- *
- * The mask bit in IMR is cleared by rps_work.
- */
- unsigned long flags;
- spin_lock_irqsave(&dev_priv->rps_lock, flags);
- WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n");
- dev_priv->pm_iir |= pm_iir;
- I915_WRITE(GEN6_PMIMR, dev_priv->pm_iir);
- POSTING_READ(GEN6_PMIMR);
- spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
- queue_work(dev_priv->wq, &dev_priv->rps_work);
- }
+ if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS)
+ gen6_queue_rps_work(dev_priv, pm_iir);
/* should clear PCH hotplug event before clear CPU irq */
I915_WRITE(SDEIIR, pch_iir);
@@ -691,7 +752,7 @@ static void i915_error_work_func(struct work_struct *work)
if (atomic_read(&dev_priv->mm.wedged)) {
DRM_DEBUG_DRIVER("resetting chip\n");
kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_event);
- if (!i915_reset(dev, GRDOM_RENDER)) {
+ if (!i915_reset(dev)) {
atomic_set(&dev_priv->mm.wedged, 0);
kobject_uevent_env(&dev->primary->kdev.kobj, KOBJ_CHANGE, reset_done_event);
}
@@ -727,7 +788,8 @@ i915_error_object_create(struct drm_i915_private *dev_priv,
goto unwind;
local_irq_save(flags);
- if (reloc_offset < dev_priv->mm.gtt_mappable_end) {
+ if (reloc_offset < dev_priv->mm.gtt_mappable_end &&
+ src->has_global_gtt_mapping) {
void __iomem *s;
/* Simply ignore tiling or any overlapping fence.
@@ -782,10 +844,11 @@ i915_error_object_free(struct drm_i915_error_object *obj)
kfree(obj);
}
-static void
-i915_error_state_free(struct drm_device *dev,
- struct drm_i915_error_state *error)
+void
+i915_error_state_free(struct kref *error_ref)
{
+ struct drm_i915_error_state *error = container_of(error_ref,
+ typeof(*error), ref);
int i;
for (i = 0; i < ARRAY_SIZE(error->ring); i++) {
@@ -798,37 +861,56 @@ i915_error_state_free(struct drm_device *dev,
kfree(error->overlay);
kfree(error);
}
+static void capture_bo(struct drm_i915_error_buffer *err,
+ struct drm_i915_gem_object *obj)
+{
+ err->size = obj->base.size;
+ err->name = obj->base.name;
+ err->seqno = obj->last_rendering_seqno;
+ err->gtt_offset = obj->gtt_offset;
+ err->read_domains = obj->base.read_domains;
+ err->write_domain = obj->base.write_domain;
+ err->fence_reg = obj->fence_reg;
+ err->pinned = 0;
+ if (obj->pin_count > 0)
+ err->pinned = 1;
+ if (obj->user_pin_count > 0)
+ err->pinned = -1;
+ err->tiling = obj->tiling_mode;
+ err->dirty = obj->dirty;
+ err->purgeable = obj->madv != I915_MADV_WILLNEED;
+ err->ring = obj->ring ? obj->ring->id : -1;
+ err->cache_level = obj->cache_level;
+}
-static u32 capture_bo_list(struct drm_i915_error_buffer *err,
- int count,
- struct list_head *head)
+static u32 capture_active_bo(struct drm_i915_error_buffer *err,
+ int count, struct list_head *head)
{
struct drm_i915_gem_object *obj;
int i = 0;
list_for_each_entry(obj, head, mm_list) {
- err->size = obj->base.size;
- err->name = obj->base.name;
- err->seqno = obj->last_rendering_seqno;
- err->gtt_offset = obj->gtt_offset;
- err->read_domains = obj->base.read_domains;
- err->write_domain = obj->base.write_domain;
- err->fence_reg = obj->fence_reg;
- err->pinned = 0;
- if (obj->pin_count > 0)
- err->pinned = 1;
- if (obj->user_pin_count > 0)
- err->pinned = -1;
- err->tiling = obj->tiling_mode;
- err->dirty = obj->dirty;
- err->purgeable = obj->madv != I915_MADV_WILLNEED;
- err->ring = obj->ring ? obj->ring->id : -1;
- err->cache_level = obj->cache_level;
-
+ capture_bo(err++, obj);
if (++i == count)
break;
+ }
- err++;
+ return i;
+}
+
+static u32 capture_pinned_bo(struct drm_i915_error_buffer *err,
+ int count, struct list_head *head)
+{
+ struct drm_i915_gem_object *obj;
+ int i = 0;
+
+ list_for_each_entry(obj, head, gtt_list) {
+ if (obj->pin_count == 0)
+ continue;
+
+ capture_bo(err++, obj);
+ if (++i == count)
+ break;
}
return i;
@@ -901,7 +983,6 @@ static void i915_record_ring_state(struct drm_device *dev,
struct drm_i915_private *dev_priv = dev->dev_private;
if (INTEL_INFO(dev)->gen >= 6) {
- error->faddr[ring->id] = I915_READ(RING_DMA_FADD(ring->mmio_base));
error->fault_reg[ring->id] = I915_READ(RING_FAULT_REG(ring));
error->semaphore_mboxes[ring->id][0]
= I915_READ(RING_SYNC_0(ring->mmio_base));
@@ -910,6 +991,7 @@ static void i915_record_ring_state(struct drm_device *dev,
}
if (INTEL_INFO(dev)->gen >= 4) {
+ error->faddr[ring->id] = I915_READ(RING_DMA_FADD(ring->mmio_base));
error->ipeir[ring->id] = I915_READ(RING_IPEIR(ring->mmio_base));
error->ipehr[ring->id] = I915_READ(RING_IPEHR(ring->mmio_base));
error->instdone[ring->id] = I915_READ(RING_INSTDONE(ring->mmio_base));
@@ -919,11 +1001,13 @@ static void i915_record_ring_state(struct drm_device *dev,
error->bbaddr = I915_READ64(BB_ADDR);
}
} else {
+ error->faddr[ring->id] = I915_READ(DMA_FADD_I8XX);
error->ipeir[ring->id] = I915_READ(IPEIR);
error->ipehr[ring->id] = I915_READ(IPEHR);
error->instdone[ring->id] = I915_READ(INSTDONE);
}
+ error->waiting[ring->id] = waitqueue_active(&ring->irq_queue);
error->instpm[ring->id] = I915_READ(RING_INSTPM(ring->mmio_base));
error->seqno[ring->id] = ring->get_seqno(ring);
error->acthd[ring->id] = intel_ring_get_active_head(ring);
@@ -938,15 +1022,11 @@ static void i915_gem_record_rings(struct drm_device *dev,
struct drm_i915_error_state *error)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring;
struct drm_i915_gem_request *request;
int i, count;
- for (i = 0; i < I915_NUM_RINGS; i++) {
- struct intel_ring_buffer *ring = &dev_priv->ring[i];
-
- if (ring->obj == NULL)
- continue;
-
+ for_each_ring(ring, dev_priv, i) {
i915_record_ring_state(dev, error, ring);
error->ring[i].batchbuffer =
@@ -1013,8 +1093,19 @@ static void i915_capture_error_state(struct drm_device *dev)
DRM_INFO("capturing error event; look for more information in /debug/dri/%d/i915_error_state\n",
dev->primary->index);
+ kref_init(&error->ref);
error->eir = I915_READ(EIR);
error->pgtbl_er = I915_READ(PGTBL_ER);
+
+ if (HAS_PCH_SPLIT(dev))
+ error->ier = I915_READ(DEIER) | I915_READ(GTIER);
+ else if (IS_VALLEYVIEW(dev))
+ error->ier = I915_READ(GTIER) | I915_READ(VLV_IER);
+ else if (IS_GEN2(dev))
+ error->ier = I915_READ16(IER);
+ else
+ error->ier = I915_READ(IER);
+
for_each_pipe(pipe)
error->pipestat[pipe] = I915_READ(PIPESTAT(pipe));
@@ -1034,8 +1125,9 @@ static void i915_capture_error_state(struct drm_device *dev)
list_for_each_entry(obj, &dev_priv->mm.active_list, mm_list)
i++;
error->active_bo_count = i;
- list_for_each_entry(obj, &dev_priv->mm.pinned_list, mm_list)
- i++;
+ list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list)
+ if (obj->pin_count)
+ i++;
error->pinned_bo_count = i - error->active_bo_count;
error->active_bo = NULL;
@@ -1050,15 +1142,15 @@ static void i915_capture_error_state(struct drm_device *dev)
if (error->active_bo)
error->active_bo_count =
- capture_bo_list(error->active_bo,
- error->active_bo_count,
- &dev_priv->mm.active_list);
+ capture_active_bo(error->active_bo,
+ error->active_bo_count,
+ &dev_priv->mm.active_list);
if (error->pinned_bo)
error->pinned_bo_count =
- capture_bo_list(error->pinned_bo,
- error->pinned_bo_count,
- &dev_priv->mm.pinned_list);
+ capture_pinned_bo(error->pinned_bo,
+ error->pinned_bo_count,
+ &dev_priv->mm.gtt_list);
do_gettimeofday(&error->time);
@@ -1073,7 +1165,7 @@ static void i915_capture_error_state(struct drm_device *dev)
spin_unlock_irqrestore(&dev_priv->error_lock, flags);
if (error)
- i915_error_state_free(dev, error);
+ i915_error_state_free(&error->ref);
}
void i915_destroy_error_state(struct drm_device *dev)
@@ -1088,7 +1180,7 @@ void i915_destroy_error_state(struct drm_device *dev)
spin_unlock_irqrestore(&dev_priv->error_lock, flags);
if (error)
- i915_error_state_free(dev, error);
+ kref_put(&error->ref, i915_error_state_free);
}
#else
#define i915_capture_error_state(x)
@@ -1103,33 +1195,26 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
if (!eir)
return;
- printk(KERN_ERR "render error detected, EIR: 0x%08x\n",
- eir);
+ pr_err("render error detected, EIR: 0x%08x\n", eir);
if (IS_G4X(dev)) {
if (eir & (GM45_ERROR_MEM_PRIV | GM45_ERROR_CP_PRIV)) {
u32 ipeir = I915_READ(IPEIR_I965);
- printk(KERN_ERR " IPEIR: 0x%08x\n",
- I915_READ(IPEIR_I965));
- printk(KERN_ERR " IPEHR: 0x%08x\n",
- I915_READ(IPEHR_I965));
- printk(KERN_ERR " INSTDONE: 0x%08x\n",
+ pr_err(" IPEIR: 0x%08x\n", I915_READ(IPEIR_I965));
+ pr_err(" IPEHR: 0x%08x\n", I915_READ(IPEHR_I965));
+ pr_err(" INSTDONE: 0x%08x\n",
I915_READ(INSTDONE_I965));
- printk(KERN_ERR " INSTPS: 0x%08x\n",
- I915_READ(INSTPS));
- printk(KERN_ERR " INSTDONE1: 0x%08x\n",
- I915_READ(INSTDONE1));
- printk(KERN_ERR " ACTHD: 0x%08x\n",
- I915_READ(ACTHD_I965));
+ pr_err(" INSTPS: 0x%08x\n", I915_READ(INSTPS));
+ pr_err(" INSTDONE1: 0x%08x\n", I915_READ(INSTDONE1));
+ pr_err(" ACTHD: 0x%08x\n", I915_READ(ACTHD_I965));
I915_WRITE(IPEIR_I965, ipeir);
POSTING_READ(IPEIR_I965);
}
if (eir & GM45_ERROR_PAGE_TABLE) {
u32 pgtbl_err = I915_READ(PGTBL_ER);
- printk(KERN_ERR "page table error\n");
- printk(KERN_ERR " PGTBL_ER: 0x%08x\n",
- pgtbl_err);
+ pr_err("page table error\n");
+ pr_err(" PGTBL_ER: 0x%08x\n", pgtbl_err);
I915_WRITE(PGTBL_ER, pgtbl_err);
POSTING_READ(PGTBL_ER);
}
@@ -1138,53 +1223,42 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
if (!IS_GEN2(dev)) {
if (eir & I915_ERROR_PAGE_TABLE) {
u32 pgtbl_err = I915_READ(PGTBL_ER);
- printk(KERN_ERR "page table error\n");
- printk(KERN_ERR " PGTBL_ER: 0x%08x\n",
- pgtbl_err);
+ pr_err("page table error\n");
+ pr_err(" PGTBL_ER: 0x%08x\n", pgtbl_err);
I915_WRITE(PGTBL_ER, pgtbl_err);
POSTING_READ(PGTBL_ER);
}
}
if (eir & I915_ERROR_MEMORY_REFRESH) {
- printk(KERN_ERR "memory refresh error:\n");
+ pr_err("memory refresh error:\n");
for_each_pipe(pipe)
- printk(KERN_ERR "pipe %c stat: 0x%08x\n",
+ pr_err("pipe %c stat: 0x%08x\n",
pipe_name(pipe), I915_READ(PIPESTAT(pipe)));
/* pipestat has already been acked */
}
if (eir & I915_ERROR_INSTRUCTION) {
- printk(KERN_ERR "instruction error\n");
- printk(KERN_ERR " INSTPM: 0x%08x\n",
- I915_READ(INSTPM));
+ pr_err("instruction error\n");
+ pr_err(" INSTPM: 0x%08x\n", I915_READ(INSTPM));
if (INTEL_INFO(dev)->gen < 4) {
u32 ipeir = I915_READ(IPEIR);
- printk(KERN_ERR " IPEIR: 0x%08x\n",
- I915_READ(IPEIR));
- printk(KERN_ERR " IPEHR: 0x%08x\n",
- I915_READ(IPEHR));
- printk(KERN_ERR " INSTDONE: 0x%08x\n",
- I915_READ(INSTDONE));
- printk(KERN_ERR " ACTHD: 0x%08x\n",
- I915_READ(ACTHD));
+ pr_err(" IPEIR: 0x%08x\n", I915_READ(IPEIR));
+ pr_err(" IPEHR: 0x%08x\n", I915_READ(IPEHR));
+ pr_err(" INSTDONE: 0x%08x\n", I915_READ(INSTDONE));
+ pr_err(" ACTHD: 0x%08x\n", I915_READ(ACTHD));
I915_WRITE(IPEIR, ipeir);
POSTING_READ(IPEIR);
} else {
u32 ipeir = I915_READ(IPEIR_I965);
- printk(KERN_ERR " IPEIR: 0x%08x\n",
- I915_READ(IPEIR_I965));
- printk(KERN_ERR " IPEHR: 0x%08x\n",
- I915_READ(IPEHR_I965));
- printk(KERN_ERR " INSTDONE: 0x%08x\n",
+ pr_err(" IPEIR: 0x%08x\n", I915_READ(IPEIR_I965));
+ pr_err(" IPEHR: 0x%08x\n", I915_READ(IPEHR_I965));
+ pr_err(" INSTDONE: 0x%08x\n",
I915_READ(INSTDONE_I965));
- printk(KERN_ERR " INSTPS: 0x%08x\n",
- I915_READ(INSTPS));
- printk(KERN_ERR " INSTDONE1: 0x%08x\n",
- I915_READ(INSTDONE1));
- printk(KERN_ERR " ACTHD: 0x%08x\n",
- I915_READ(ACTHD_I965));
+ pr_err(" INSTPS: 0x%08x\n", I915_READ(INSTPS));
+ pr_err(" INSTDONE1: 0x%08x\n", I915_READ(INSTDONE1));
+ pr_err(" ACTHD: 0x%08x\n", I915_READ(ACTHD_I965));
I915_WRITE(IPEIR_I965, ipeir);
POSTING_READ(IPEIR_I965);
}
@@ -1217,6 +1291,8 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
void i915_handle_error(struct drm_device *dev, bool wedged)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring;
+ int i;
i915_capture_error_state(dev);
i915_report_and_clear_eir(dev);
@@ -1228,11 +1304,8 @@ void i915_handle_error(struct drm_device *dev, bool wedged)
/*
* Wakeup waiting processes so they don't hang
*/
- wake_up_all(&dev_priv->ring[RCS].irq_queue);
- if (HAS_BSD(dev))
- wake_up_all(&dev_priv->ring[VCS].irq_queue);
- if (HAS_BLT(dev))
- wake_up_all(&dev_priv->ring[BCS].irq_queue);
+ for_each_ring(ring, dev_priv, i)
+ wake_up_all(&ring->irq_queue);
}
queue_work(dev_priv->wq, &dev_priv->error_work);
@@ -1265,7 +1338,8 @@ static void i915_pageflip_stall_check(struct drm_device *dev, int pipe)
obj = work->pending_flip_obj;
if (INTEL_INFO(dev)->gen >= 4) {
int dspsurf = DSPSURF(intel_crtc->plane);
- stall_detected = I915_READ(dspsurf) == obj->gtt_offset;
+ stall_detected = I915_HI_DISPBASE(I915_READ(dspsurf)) ==
+ obj->gtt_offset;
} else {
int dspaddr = DSPADDR(intel_crtc->plane);
stall_detected = I915_READ(dspaddr) == (obj->gtt_offset +
@@ -1281,248 +1355,6 @@ static void i915_pageflip_stall_check(struct drm_device *dev, int pipe)
}
}
-static irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
-{
- struct drm_device *dev = (struct drm_device *) arg;
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- struct drm_i915_master_private *master_priv;
- u32 iir, new_iir;
- u32 pipe_stats[I915_MAX_PIPES];
- u32 vblank_status;
- int vblank = 0;
- unsigned long irqflags;
- int irq_received;
- int ret = IRQ_NONE, pipe;
- bool blc_event = false;
-
- atomic_inc(&dev_priv->irq_received);
-
- iir = I915_READ(IIR);
-
- if (INTEL_INFO(dev)->gen >= 4)
- vblank_status = PIPE_START_VBLANK_INTERRUPT_STATUS;
- else
- vblank_status = PIPE_VBLANK_INTERRUPT_STATUS;
-
- for (;;) {
- irq_received = iir != 0;
-
- /* Can't rely on pipestat interrupt bit in iir as it might
- * have been cleared after the pipestat interrupt was received.
- * It doesn't set the bit in iir again, but it still produces
- * interrupts (for non-MSI).
- */
- spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
- if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
- i915_handle_error(dev, false);
-
- for_each_pipe(pipe) {
- int reg = PIPESTAT(pipe);
- pipe_stats[pipe] = I915_READ(reg);
-
- /*
- * Clear the PIPE*STAT regs before the IIR
- */
- if (pipe_stats[pipe] & 0x8000ffff) {
- if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
- DRM_DEBUG_DRIVER("pipe %c underrun\n",
- pipe_name(pipe));
- I915_WRITE(reg, pipe_stats[pipe]);
- irq_received = 1;
- }
- }
- spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
-
- if (!irq_received)
- break;
-
- ret = IRQ_HANDLED;
-
- /* Consume port. Then clear IIR or we'll miss events */
- if ((I915_HAS_HOTPLUG(dev)) &&
- (iir & I915_DISPLAY_PORT_INTERRUPT)) {
- u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
-
- DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
- hotplug_status);
- if (hotplug_status & dev_priv->hotplug_supported_mask)
- queue_work(dev_priv->wq,
- &dev_priv->hotplug_work);
-
- I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
- I915_READ(PORT_HOTPLUG_STAT);
- }
-
- I915_WRITE(IIR, iir);
- new_iir = I915_READ(IIR); /* Flush posted writes */
-
- if (dev->primary->master) {
- master_priv = dev->primary->master->driver_priv;
- if (master_priv->sarea_priv)
- master_priv->sarea_priv->last_dispatch =
- READ_BREADCRUMB(dev_priv);
- }
-
- if (iir & I915_USER_INTERRUPT)
- notify_ring(dev, &dev_priv->ring[RCS]);
- if (iir & I915_BSD_USER_INTERRUPT)
- notify_ring(dev, &dev_priv->ring[VCS]);
-
- if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) {
- intel_prepare_page_flip(dev, 0);
- if (dev_priv->flip_pending_is_done)
- intel_finish_page_flip_plane(dev, 0);
- }
-
- if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) {
- intel_prepare_page_flip(dev, 1);
- if (dev_priv->flip_pending_is_done)
- intel_finish_page_flip_plane(dev, 1);
- }
-
- for_each_pipe(pipe) {
- if (pipe_stats[pipe] & vblank_status &&
- drm_handle_vblank(dev, pipe)) {
- vblank++;
- if (!dev_priv->flip_pending_is_done) {
- i915_pageflip_stall_check(dev, pipe);
- intel_finish_page_flip(dev, pipe);
- }
- }
-
- if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
- blc_event = true;
- }
-
-
- if (blc_event || (iir & I915_ASLE_INTERRUPT))
- intel_opregion_asle_intr(dev);
-
- /* With MSI, interrupts are only generated when iir
- * transitions from zero to nonzero. If another bit got
- * set while we were handling the existing iir bits, then
- * we would never get another interrupt.
- *
- * This is fine on non-MSI as well, as if we hit this path
- * we avoid exiting the interrupt handler only to generate
- * another one.
- *
- * Note that for MSI this could cause a stray interrupt report
- * if an interrupt landed in the time between writing IIR and
- * the posting read. This should be rare enough to never
- * trigger the 99% of 100,000 interrupts test for disabling
- * stray interrupts.
- */
- iir = new_iir;
- }
-
- return ret;
-}
-
-static int i915_emit_irq(struct drm_device * dev)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
-
- i915_kernel_lost_context(dev);
-
- DRM_DEBUG_DRIVER("\n");
-
- dev_priv->counter++;
- if (dev_priv->counter > 0x7FFFFFFFUL)
- dev_priv->counter = 1;
- if (master_priv->sarea_priv)
- master_priv->sarea_priv->last_enqueue = dev_priv->counter;
-
- if (BEGIN_LP_RING(4) == 0) {
- OUT_RING(MI_STORE_DWORD_INDEX);
- OUT_RING(I915_BREADCRUMB_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
- OUT_RING(dev_priv->counter);
- OUT_RING(MI_USER_INTERRUPT);
- ADVANCE_LP_RING();
- }
-
- return dev_priv->counter;
-}
-
-static int i915_wait_irq(struct drm_device * dev, int irq_nr)
-{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
- int ret = 0;
- struct intel_ring_buffer *ring = LP_RING(dev_priv);
-
- DRM_DEBUG_DRIVER("irq_nr=%d breadcrumb=%d\n", irq_nr,
- READ_BREADCRUMB(dev_priv));
-
- if (READ_BREADCRUMB(dev_priv) >= irq_nr) {
- if (master_priv->sarea_priv)
- master_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
- return 0;
- }
-
- if (master_priv->sarea_priv)
- master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
-
- if (ring->irq_get(ring)) {
- DRM_WAIT_ON(ret, ring->irq_queue, 3 * DRM_HZ,
- READ_BREADCRUMB(dev_priv) >= irq_nr);
- ring->irq_put(ring);
- } else if (wait_for(READ_BREADCRUMB(dev_priv) >= irq_nr, 3000))
- ret = -EBUSY;
-
- if (ret == -EBUSY) {
- DRM_ERROR("EBUSY -- rec: %d emitted: %d\n",
- READ_BREADCRUMB(dev_priv), (int)dev_priv->counter);
- }
-
- return ret;
-}
-
-/* Needs the lock as it touches the ring.
- */
-int i915_irq_emit(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_irq_emit_t *emit = data;
- int result;
-
- if (!dev_priv || !LP_RING(dev_priv)->virtual_start) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
-
- RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
-
- mutex_lock(&dev->struct_mutex);
- result = i915_emit_irq(dev);
- mutex_unlock(&dev->struct_mutex);
-
- if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) {
- DRM_ERROR("copy_to_user\n");
- return -EFAULT;
- }
-
- return 0;
-}
-
-/* Doesn't need the hardware lock.
- */
-int i915_irq_wait(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_irq_wait_t *irqwait = data;
-
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
-
- return i915_wait_irq(dev, irqwait->irq_seq);
-}
-
/* Called from drm generic code, passed 'crtc' which
* we use as a pipe index
*/
@@ -1544,7 +1376,7 @@ static int i915_enable_vblank(struct drm_device *dev, int pipe)
/* maintain vblank delivery even in deep C-states */
if (dev_priv->info->gen == 3)
- I915_WRITE(INSTPM, INSTPM_AGPBUSY_DIS << 16);
+ I915_WRITE(INSTPM, _MASKED_BIT_DISABLE(INSTPM_AGPBUSY_DIS));
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
return 0;
@@ -1575,8 +1407,34 @@ static int ivybridge_enable_vblank(struct drm_device *dev, int pipe)
return -EINVAL;
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
- ironlake_enable_display_irq(dev_priv, (pipe == 0) ?
- DE_PIPEA_VBLANK_IVB : DE_PIPEB_VBLANK_IVB);
+ ironlake_enable_display_irq(dev_priv,
+ DE_PIPEA_VBLANK_IVB << (5 * pipe));
+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+ return 0;
+}
+
+static int valleyview_enable_vblank(struct drm_device *dev, int pipe)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ unsigned long irqflags;
+ u32 dpfl, imr;
+
+ if (!i915_pipe_enabled(dev, pipe))
+ return -EINVAL;
+
+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+ dpfl = I915_READ(VLV_DPFLIPSTAT);
+ imr = I915_READ(VLV_IMR);
+ if (pipe == 0) {
+ dpfl |= PIPEA_VBLANK_INT_EN;
+ imr &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
+ } else {
+ dpfl |= PIPEA_VBLANK_INT_EN;
+ imr &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
+ }
+ I915_WRITE(VLV_DPFLIPSTAT, dpfl);
+ I915_WRITE(VLV_IMR, imr);
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
return 0;
@@ -1592,8 +1450,7 @@ static void i915_disable_vblank(struct drm_device *dev, int pipe)
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
if (dev_priv->info->gen == 3)
- I915_WRITE(INSTPM,
- INSTPM_AGPBUSY_DIS << 16 | INSTPM_AGPBUSY_DIS);
+ I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_AGPBUSY_DIS));
i915_disable_pipestat(dev_priv, pipe,
PIPE_VBLANK_INTERRUPT_ENABLE |
@@ -1618,63 +1475,30 @@ static void ivybridge_disable_vblank(struct drm_device *dev, int pipe)
unsigned long irqflags;
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
- ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
- DE_PIPEA_VBLANK_IVB : DE_PIPEB_VBLANK_IVB);
+ ironlake_disable_display_irq(dev_priv,
+ DE_PIPEA_VBLANK_IVB << (pipe * 5));
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
}
-/* Set the vblank monitor pipe
- */
-int i915_vblank_pipe_set(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
+static void valleyview_disable_vblank(struct drm_device *dev, int pipe)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
-
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-int i915_vblank_pipe_get(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_vblank_pipe_t *pipe = data;
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ unsigned long irqflags;
+ u32 dpfl, imr;
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+ dpfl = I915_READ(VLV_DPFLIPSTAT);
+ imr = I915_READ(VLV_IMR);
+ if (pipe == 0) {
+ dpfl &= ~PIPEA_VBLANK_INT_EN;
+ imr |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
+ } else {
+ dpfl &= ~PIPEB_VBLANK_INT_EN;
+ imr |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
}
-
- pipe->pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
-
- return 0;
-}
-
-/**
- * Schedule buffer swap at given vertical blank.
- */
-int i915_vblank_swap(struct drm_device *dev, void *data,
- struct drm_file *file_priv)
-{
- /* The delayed swap mechanism was fundamentally racy, and has been
- * removed. The model was that the client requested a delayed flip/swap
- * from the kernel, then waited for vblank before continuing to perform
- * rendering. The problem was that the kernel might wake the client
- * up before it dispatched the vblank swap (since the lock has to be
- * held while touching the ringbuffer), in which case the client would
- * clear and start the next frame before the swap occurred, and
- * flicker would occur in addition to likely missing the vblank.
- *
- * In the absence of this ioctl, userland falls back to a correct path
- * of waiting for a vblank, then dispatching the swap on its own.
- * Context switching to userland and back is plenty fast enough for
- * meeting the requirements of vblank swapping.
- */
- return -EINVAL;
+ I915_WRITE(VLV_IMR, imr);
+ I915_WRITE(VLV_DPFLIPSTAT, dpfl);
+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
}
static u32
@@ -1689,11 +1513,9 @@ static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err)
if (list_empty(&ring->request_list) ||
i915_seqno_passed(ring->get_seqno(ring), ring_last_seqno(ring))) {
/* Issue a wake-up to catch stuck h/w. */
- if (ring->waiting_seqno && waitqueue_active(&ring->irq_queue)) {
- DRM_ERROR("Hangcheck timer elapsed... %s idle [waiting on %d, at %d], missed IRQ?\n",
- ring->name,
- ring->waiting_seqno,
- ring->get_seqno(ring));
+ if (waitqueue_active(&ring->irq_queue)) {
+ DRM_ERROR("Hangcheck timer elapsed... %s idle\n",
+ ring->name);
wake_up_all(&ring->irq_queue);
*err = true;
}
@@ -1716,6 +1538,35 @@ static bool kick_ring(struct intel_ring_buffer *ring)
return false;
}
+static bool i915_hangcheck_hung(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ if (dev_priv->hangcheck_count++ > 1) {
+ bool hung = true;
+
+ DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
+ i915_handle_error(dev, true);
+
+ if (!IS_GEN2(dev)) {
+ struct intel_ring_buffer *ring;
+ int i;
+
+ /* Is the chip hanging on a WAIT_FOR_EVENT?
+ * If so we can simply poke the RB_WAIT bit
+ * and break the hang. This should work on
+ * all but the second generation chipsets.
+ */
+ for_each_ring(ring, dev_priv, i)
+ hung &= !kick_ring(ring);
+ }
+
+ return hung;
+ }
+
+ return false;
+}
+
/**
* This is called when the chip hasn't reported back with completed
* batchbuffers in a long time. The first time this is called we simply record
@@ -1726,19 +1577,31 @@ void i915_hangcheck_elapsed(unsigned long data)
{
struct drm_device *dev = (struct drm_device *)data;
drm_i915_private_t *dev_priv = dev->dev_private;
- uint32_t acthd, instdone, instdone1, acthd_bsd, acthd_blt;
- bool err = false;
+ uint32_t acthd[I915_NUM_RINGS], instdone, instdone1;
+ struct intel_ring_buffer *ring;
+ bool err = false, idle;
+ int i;
if (!i915_enable_hangcheck)
return;
+ memset(acthd, 0, sizeof(acthd));
+ idle = true;
+ for_each_ring(ring, dev_priv, i) {
+ idle &= i915_hangcheck_ring_idle(ring, &err);
+ acthd[i] = intel_ring_get_active_head(ring);
+ }
+
/* If all work is done then ACTHD clearly hasn't advanced. */
- if (i915_hangcheck_ring_idle(&dev_priv->ring[RCS], &err) &&
- i915_hangcheck_ring_idle(&dev_priv->ring[VCS], &err) &&
- i915_hangcheck_ring_idle(&dev_priv->ring[BCS], &err)) {
- dev_priv->hangcheck_count = 0;
- if (err)
+ if (idle) {
+ if (err) {
+ if (i915_hangcheck_hung(dev))
+ return;
+
goto repeat;
+ }
+
+ dev_priv->hangcheck_count = 0;
return;
}
@@ -1749,47 +1612,16 @@ void i915_hangcheck_elapsed(unsigned long data)
instdone = I915_READ(INSTDONE_I965);
instdone1 = I915_READ(INSTDONE1);
}
- acthd = intel_ring_get_active_head(&dev_priv->ring[RCS]);
- acthd_bsd = HAS_BSD(dev) ?
- intel_ring_get_active_head(&dev_priv->ring[VCS]) : 0;
- acthd_blt = HAS_BLT(dev) ?
- intel_ring_get_active_head(&dev_priv->ring[BCS]) : 0;
- if (dev_priv->last_acthd == acthd &&
- dev_priv->last_acthd_bsd == acthd_bsd &&
- dev_priv->last_acthd_blt == acthd_blt &&
+ if (memcmp(dev_priv->last_acthd, acthd, sizeof(acthd)) == 0 &&
dev_priv->last_instdone == instdone &&
dev_priv->last_instdone1 == instdone1) {
- if (dev_priv->hangcheck_count++ > 1) {
- DRM_ERROR("Hangcheck timer elapsed... GPU hung\n");
- i915_handle_error(dev, true);
-
- if (!IS_GEN2(dev)) {
- /* Is the chip hanging on a WAIT_FOR_EVENT?
- * If so we can simply poke the RB_WAIT bit
- * and break the hang. This should work on
- * all but the second generation chipsets.
- */
- if (kick_ring(&dev_priv->ring[RCS]))
- goto repeat;
-
- if (HAS_BSD(dev) &&
- kick_ring(&dev_priv->ring[VCS]))
- goto repeat;
-
- if (HAS_BLT(dev) &&
- kick_ring(&dev_priv->ring[BCS]))
- goto repeat;
- }
-
+ if (i915_hangcheck_hung(dev))
return;
- }
} else {
dev_priv->hangcheck_count = 0;
- dev_priv->last_acthd = acthd;
- dev_priv->last_acthd_bsd = acthd_bsd;
- dev_priv->last_acthd_blt = acthd_blt;
+ memcpy(dev_priv->last_acthd, acthd, sizeof(acthd));
dev_priv->last_instdone = instdone;
dev_priv->last_instdone1 = instdone1;
}
@@ -1808,10 +1640,6 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
atomic_set(&dev_priv->irq_received, 0);
- INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
- INIT_WORK(&dev_priv->error_work, i915_error_work_func);
- if (IS_GEN6(dev) || IS_IVYBRIDGE(dev))
- INIT_WORK(&dev_priv->rps_work, gen6_pm_rps_work);
I915_WRITE(HWSTAM, 0xeffe);
@@ -1832,6 +1660,38 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
POSTING_READ(SDEIER);
}
+static void valleyview_irq_preinstall(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ int pipe;
+
+ atomic_set(&dev_priv->irq_received, 0);
+
+ /* VLV magic */
+ I915_WRITE(VLV_IMR, 0);
+ I915_WRITE(RING_IMR(RENDER_RING_BASE), 0);
+ I915_WRITE(RING_IMR(GEN6_BSD_RING_BASE), 0);
+ I915_WRITE(RING_IMR(BLT_RING_BASE), 0);
+
+ /* and GT */
+ I915_WRITE(GTIIR, I915_READ(GTIIR));
+ I915_WRITE(GTIIR, I915_READ(GTIIR));
+ I915_WRITE(GTIMR, 0xffffffff);
+ I915_WRITE(GTIER, 0x0);
+ POSTING_READ(GTIER);
+
+ I915_WRITE(DPINVGTT, 0xff);
+
+ I915_WRITE(PORT_HOTPLUG_EN, 0);
+ I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
+ for_each_pipe(pipe)
+ I915_WRITE(PIPESTAT(pipe), 0xffff);
+ I915_WRITE(VLV_IIR, 0xffffffff);
+ I915_WRITE(VLV_IMR, 0xffffffff);
+ I915_WRITE(VLV_IER, 0x0);
+ POSTING_READ(VLV_IER);
+}
+
/*
* Enable digital hotplug on the PCH, and configure the DP short pulse
* duration to 2ms (which is the minimum in the Display Port spec)
@@ -1861,13 +1721,6 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
u32 render_irqs;
u32 hotplug_mask;
- DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue);
- if (HAS_BSD(dev))
- DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue);
- if (HAS_BLT(dev))
- DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue);
-
- dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
dev_priv->irq_mask = ~display_mask;
/* should always can generate irq */
@@ -1884,8 +1737,8 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
if (IS_GEN6(dev))
render_irqs =
GT_USER_INTERRUPT |
- GT_GEN6_BSD_USER_INTERRUPT |
- GT_BLT_USER_INTERRUPT;
+ GEN6_BSD_USER_INTERRUPT |
+ GEN6_BLITTER_USER_INTERRUPT;
else
render_irqs =
GT_USER_INTERRUPT |
@@ -1930,26 +1783,24 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
/* enable kind of interrupts always enabled */
- u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE_IVB |
- DE_PCH_EVENT_IVB | DE_PLANEA_FLIP_DONE_IVB |
- DE_PLANEB_FLIP_DONE_IVB;
+ u32 display_mask =
+ DE_MASTER_IRQ_CONTROL | DE_GSE_IVB | DE_PCH_EVENT_IVB |
+ DE_PLANEC_FLIP_DONE_IVB |
+ DE_PLANEB_FLIP_DONE_IVB |
+ DE_PLANEA_FLIP_DONE_IVB;
u32 render_irqs;
u32 hotplug_mask;
- DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue);
- if (HAS_BSD(dev))
- DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue);
- if (HAS_BLT(dev))
- DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue);
-
- dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
dev_priv->irq_mask = ~display_mask;
/* should always can generate irq */
I915_WRITE(DEIIR, I915_READ(DEIIR));
I915_WRITE(DEIMR, dev_priv->irq_mask);
- I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK_IVB |
- DE_PIPEB_VBLANK_IVB);
+ I915_WRITE(DEIER,
+ display_mask |
+ DE_PIPEC_VBLANK_IVB |
+ DE_PIPEB_VBLANK_IVB |
+ DE_PIPEA_VBLANK_IVB);
POSTING_READ(DEIER);
dev_priv->gt_irq_mask = ~0;
@@ -1957,8 +1808,8 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
I915_WRITE(GTIIR, I915_READ(GTIIR));
I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
- render_irqs = GT_USER_INTERRUPT | GT_GEN6_BSD_USER_INTERRUPT |
- GT_BLT_USER_INTERRUPT;
+ render_irqs = GT_USER_INTERRUPT | GEN6_BSD_USER_INTERRUPT |
+ GEN6_BLITTER_USER_INTERRUPT;
I915_WRITE(GTIER, render_irqs);
POSTING_READ(GTIER);
@@ -1978,15 +1829,496 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
return 0;
}
-static void i915_driver_irq_preinstall(struct drm_device * dev)
+static int valleyview_irq_postinstall(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ u32 render_irqs;
+ u32 enable_mask;
+ u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
+ u16 msid;
+
+ enable_mask = I915_DISPLAY_PORT_INTERRUPT;
+ enable_mask |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT |
+ I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
+
+ dev_priv->irq_mask = ~enable_mask;
+
+ dev_priv->pipestat[0] = 0;
+ dev_priv->pipestat[1] = 0;
+
+ /* Hack for broken MSIs on VLV */
+ pci_write_config_dword(dev_priv->dev->pdev, 0x94, 0xfee00000);
+ pci_read_config_word(dev->pdev, 0x98, &msid);
+ msid &= 0xff; /* mask out delivery bits */
+ msid |= (1<<14);
+ pci_write_config_word(dev_priv->dev->pdev, 0x98, msid);
+
+ I915_WRITE(VLV_IMR, dev_priv->irq_mask);
+ I915_WRITE(VLV_IER, enable_mask);
+ I915_WRITE(VLV_IIR, 0xffffffff);
+ I915_WRITE(PIPESTAT(0), 0xffff);
+ I915_WRITE(PIPESTAT(1), 0xffff);
+ POSTING_READ(VLV_IER);
+
+ I915_WRITE(VLV_IIR, 0xffffffff);
+ I915_WRITE(VLV_IIR, 0xffffffff);
+
+ render_irqs = GT_GEN6_BLT_FLUSHDW_NOTIFY_INTERRUPT |
+ GT_GEN6_BLT_CS_ERROR_INTERRUPT |
+ GT_GEN6_BLT_USER_INTERRUPT |
+ GT_GEN6_BSD_USER_INTERRUPT |
+ GT_GEN6_BSD_CS_ERROR_INTERRUPT |
+ GT_GEN7_L3_PARITY_ERROR_INTERRUPT |
+ GT_PIPE_NOTIFY |
+ GT_RENDER_CS_ERROR_INTERRUPT |
+ GT_SYNC_STATUS |
+ GT_USER_INTERRUPT;
+
+ dev_priv->gt_irq_mask = ~render_irqs;
+
+ I915_WRITE(GTIIR, I915_READ(GTIIR));
+ I915_WRITE(GTIIR, I915_READ(GTIIR));
+ I915_WRITE(GTIMR, 0);
+ I915_WRITE(GTIER, render_irqs);
+ POSTING_READ(GTIER);
+
+ /* ack & enable invalid PTE error interrupts */
+#if 0 /* FIXME: add support to irq handler for checking these bits */
+ I915_WRITE(DPINVGTT, DPINVGTT_STATUS_MASK);
+ I915_WRITE(DPINVGTT, DPINVGTT_EN_MASK);
+#endif
+
+ I915_WRITE(VLV_MASTER_IER, MASTER_INTERRUPT_ENABLE);
+#if 0 /* FIXME: check register definitions; some have moved */
+ /* Note HDMI and DP share bits */
+ if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS)
+ hotplug_en |= HDMIB_HOTPLUG_INT_EN;
+ if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS)
+ hotplug_en |= HDMIC_HOTPLUG_INT_EN;
+ if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS)
+ hotplug_en |= HDMID_HOTPLUG_INT_EN;
+ if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS)
+ hotplug_en |= SDVOC_HOTPLUG_INT_EN;
+ if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS)
+ hotplug_en |= SDVOB_HOTPLUG_INT_EN;
+ if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) {
+ hotplug_en |= CRT_HOTPLUG_INT_EN;
+ hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
+ }
+#endif
+
+ I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
+
+ return 0;
+}
+
+static void valleyview_irq_uninstall(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ int pipe;
+
+ if (!dev_priv)
+ return;
+
+ for_each_pipe(pipe)
+ I915_WRITE(PIPESTAT(pipe), 0xffff);
+
+ I915_WRITE(HWSTAM, 0xffffffff);
+ I915_WRITE(PORT_HOTPLUG_EN, 0);
+ I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
+ for_each_pipe(pipe)
+ I915_WRITE(PIPESTAT(pipe), 0xffff);
+ I915_WRITE(VLV_IIR, 0xffffffff);
+ I915_WRITE(VLV_IMR, 0xffffffff);
+ I915_WRITE(VLV_IER, 0x0);
+ POSTING_READ(VLV_IER);
+}
+
+static void ironlake_irq_uninstall(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+ if (!dev_priv)
+ return;
+
+ I915_WRITE(HWSTAM, 0xffffffff);
+
+ I915_WRITE(DEIMR, 0xffffffff);
+ I915_WRITE(DEIER, 0x0);
+ I915_WRITE(DEIIR, I915_READ(DEIIR));
+
+ I915_WRITE(GTIMR, 0xffffffff);
+ I915_WRITE(GTIER, 0x0);
+ I915_WRITE(GTIIR, I915_READ(GTIIR));
+
+ I915_WRITE(SDEIMR, 0xffffffff);
+ I915_WRITE(SDEIER, 0x0);
+ I915_WRITE(SDEIIR, I915_READ(SDEIIR));
+}
+
+static void i8xx_irq_preinstall(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
int pipe;
atomic_set(&dev_priv->irq_received, 0);
- INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
- INIT_WORK(&dev_priv->error_work, i915_error_work_func);
+ for_each_pipe(pipe)
+ I915_WRITE(PIPESTAT(pipe), 0);
+ I915_WRITE16(IMR, 0xffff);
+ I915_WRITE16(IER, 0x0);
+ POSTING_READ16(IER);
+}
+
+static int i8xx_irq_postinstall(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+ dev_priv->pipestat[0] = 0;
+ dev_priv->pipestat[1] = 0;
+
+ I915_WRITE16(EMR,
+ ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH));
+
+ /* Unmask the interrupts that we always want on. */
+ dev_priv->irq_mask =
+ ~(I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
+ I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
+ I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
+ I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT |
+ I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
+ I915_WRITE16(IMR, dev_priv->irq_mask);
+
+ I915_WRITE16(IER,
+ I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
+ I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
+ I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT |
+ I915_USER_INTERRUPT);
+ POSTING_READ16(IER);
+
+ return 0;
+}
+
+static irqreturn_t i8xx_irq_handler(DRM_IRQ_ARGS)
+{
+ struct drm_device *dev = (struct drm_device *) arg;
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ u16 iir, new_iir;
+ u32 pipe_stats[2];
+ unsigned long irqflags;
+ int irq_received;
+ int pipe;
+ u16 flip_mask =
+ I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
+ I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
+
+ atomic_inc(&dev_priv->irq_received);
+
+ iir = I915_READ16(IIR);
+ if (iir == 0)
+ return IRQ_NONE;
+
+ while (iir & ~flip_mask) {
+ /* Can't rely on pipestat interrupt bit in iir as it might
+ * have been cleared after the pipestat interrupt was received.
+ * It doesn't set the bit in iir again, but it still produces
+ * interrupts (for non-MSI).
+ */
+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+ if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
+ i915_handle_error(dev, false);
+
+ for_each_pipe(pipe) {
+ int reg = PIPESTAT(pipe);
+ pipe_stats[pipe] = I915_READ(reg);
+
+ /*
+ * Clear the PIPE*STAT regs before the IIR
+ */
+ if (pipe_stats[pipe] & 0x8000ffff) {
+ if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
+ DRM_DEBUG_DRIVER("pipe %c underrun\n",
+ pipe_name(pipe));
+ I915_WRITE(reg, pipe_stats[pipe]);
+ irq_received = 1;
+ }
+ }
+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+ I915_WRITE16(IIR, iir & ~flip_mask);
+ new_iir = I915_READ16(IIR); /* Flush posted writes */
+
+ i915_update_dri1_breadcrumb(dev);
+
+ if (iir & I915_USER_INTERRUPT)
+ notify_ring(dev, &dev_priv->ring[RCS]);
+
+ if (pipe_stats[0] & PIPE_VBLANK_INTERRUPT_STATUS &&
+ drm_handle_vblank(dev, 0)) {
+ if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT) {
+ intel_prepare_page_flip(dev, 0);
+ intel_finish_page_flip(dev, 0);
+ flip_mask &= ~I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT;
+ }
+ }
+
+ if (pipe_stats[1] & PIPE_VBLANK_INTERRUPT_STATUS &&
+ drm_handle_vblank(dev, 1)) {
+ if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT) {
+ intel_prepare_page_flip(dev, 1);
+ intel_finish_page_flip(dev, 1);
+ flip_mask &= ~I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
+ }
+ }
+
+ iir = new_iir;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void i8xx_irq_uninstall(struct drm_device * dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ int pipe;
+
+ for_each_pipe(pipe) {
+ /* Clear enable bits; then clear status bits */
+ I915_WRITE(PIPESTAT(pipe), 0);
+ I915_WRITE(PIPESTAT(pipe), I915_READ(PIPESTAT(pipe)));
+ }
+ I915_WRITE16(IMR, 0xffff);
+ I915_WRITE16(IER, 0x0);
+ I915_WRITE16(IIR, I915_READ16(IIR));
+}
+
+static void i915_irq_preinstall(struct drm_device * dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ int pipe;
+
+ atomic_set(&dev_priv->irq_received, 0);
+
+ if (I915_HAS_HOTPLUG(dev)) {
+ I915_WRITE(PORT_HOTPLUG_EN, 0);
+ I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
+ }
+
+ I915_WRITE16(HWSTAM, 0xeffe);
+ for_each_pipe(pipe)
+ I915_WRITE(PIPESTAT(pipe), 0);
+ I915_WRITE(IMR, 0xffffffff);
+ I915_WRITE(IER, 0x0);
+ POSTING_READ(IER);
+}
+
+static int i915_irq_postinstall(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ u32 enable_mask;
+
+ dev_priv->pipestat[0] = 0;
+ dev_priv->pipestat[1] = 0;
+
+ I915_WRITE(EMR, ~(I915_ERROR_PAGE_TABLE | I915_ERROR_MEMORY_REFRESH));
+
+ /* Unmask the interrupts that we always want on. */
+ dev_priv->irq_mask =
+ ~(I915_ASLE_INTERRUPT |
+ I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
+ I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
+ I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
+ I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT |
+ I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
+
+ enable_mask =
+ I915_ASLE_INTERRUPT |
+ I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
+ I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
+ I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT |
+ I915_USER_INTERRUPT;
+
+ if (I915_HAS_HOTPLUG(dev)) {
+ /* Enable in IER... */
+ enable_mask |= I915_DISPLAY_PORT_INTERRUPT;
+ /* and unmask in IMR */
+ dev_priv->irq_mask &= ~I915_DISPLAY_PORT_INTERRUPT;
+ }
+
+ I915_WRITE(IMR, dev_priv->irq_mask);
+ I915_WRITE(IER, enable_mask);
+ POSTING_READ(IER);
+
+ if (I915_HAS_HOTPLUG(dev)) {
+ u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
+
+ if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS)
+ hotplug_en |= HDMIB_HOTPLUG_INT_EN;
+ if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS)
+ hotplug_en |= HDMIC_HOTPLUG_INT_EN;
+ if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS)
+ hotplug_en |= HDMID_HOTPLUG_INT_EN;
+ if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS)
+ hotplug_en |= SDVOC_HOTPLUG_INT_EN;
+ if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS)
+ hotplug_en |= SDVOB_HOTPLUG_INT_EN;
+ if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS) {
+ hotplug_en |= CRT_HOTPLUG_INT_EN;
+ hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
+ }
+
+ /* Ignore TV since it's buggy */
+
+ I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
+ }
+
+ intel_opregion_enable_asle(dev);
+
+ return 0;
+}
+
+static irqreturn_t i915_irq_handler(DRM_IRQ_ARGS)
+{
+ struct drm_device *dev = (struct drm_device *) arg;
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ u32 iir, new_iir, pipe_stats[I915_MAX_PIPES];
+ unsigned long irqflags;
+ u32 flip_mask =
+ I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
+ I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
+ u32 flip[2] = {
+ I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT,
+ I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT
+ };
+ int pipe, ret = IRQ_NONE;
+
+ atomic_inc(&dev_priv->irq_received);
+
+ iir = I915_READ(IIR);
+ do {
+ bool irq_received = (iir & ~flip_mask) != 0;
+ bool blc_event = false;
+
+ /* Can't rely on pipestat interrupt bit in iir as it might
+ * have been cleared after the pipestat interrupt was received.
+ * It doesn't set the bit in iir again, but it still produces
+ * interrupts (for non-MSI).
+ */
+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+ if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
+ i915_handle_error(dev, false);
+
+ for_each_pipe(pipe) {
+ int reg = PIPESTAT(pipe);
+ pipe_stats[pipe] = I915_READ(reg);
+
+ /* Clear the PIPE*STAT regs before the IIR */
+ if (pipe_stats[pipe] & 0x8000ffff) {
+ if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
+ DRM_DEBUG_DRIVER("pipe %c underrun\n",
+ pipe_name(pipe));
+ I915_WRITE(reg, pipe_stats[pipe]);
+ irq_received = true;
+ }
+ }
+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+ if (!irq_received)
+ break;
+
+ /* Consume port. Then clear IIR or we'll miss events */
+ if ((I915_HAS_HOTPLUG(dev)) &&
+ (iir & I915_DISPLAY_PORT_INTERRUPT)) {
+ u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
+
+ DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
+ hotplug_status);
+ if (hotplug_status & dev_priv->hotplug_supported_mask)
+ queue_work(dev_priv->wq,
+ &dev_priv->hotplug_work);
+
+ I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
+ POSTING_READ(PORT_HOTPLUG_STAT);
+ }
+
+ I915_WRITE(IIR, iir & ~flip_mask);
+ new_iir = I915_READ(IIR); /* Flush posted writes */
+
+ if (iir & I915_USER_INTERRUPT)
+ notify_ring(dev, &dev_priv->ring[RCS]);
+
+ for_each_pipe(pipe) {
+ int plane = pipe;
+ if (IS_MOBILE(dev))
+ plane = !plane;
+ if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS &&
+ drm_handle_vblank(dev, pipe)) {
+ if (iir & flip[plane]) {
+ intel_prepare_page_flip(dev, plane);
+ intel_finish_page_flip(dev, pipe);
+ flip_mask &= ~flip[plane];
+ }
+ }
+
+ if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
+ blc_event = true;
+ }
+
+ if (blc_event || (iir & I915_ASLE_INTERRUPT))
+ intel_opregion_asle_intr(dev);
+
+ /* With MSI, interrupts are only generated when iir
+ * transitions from zero to nonzero. If another bit got
+ * set while we were handling the existing iir bits, then
+ * we would never get another interrupt.
+ *
+ * This is fine on non-MSI as well, as if we hit this path
+ * we avoid exiting the interrupt handler only to generate
+ * another one.
+ *
+ * Note that for MSI this could cause a stray interrupt report
+ * if an interrupt landed in the time between writing IIR and
+ * the posting read. This should be rare enough to never
+ * trigger the 99% of 100,000 interrupts test for disabling
+ * stray interrupts.
+ */
+ ret = IRQ_HANDLED;
+ iir = new_iir;
+ } while (iir & ~flip_mask);
+
+ i915_update_dri1_breadcrumb(dev);
+
+ return ret;
+}
+
+static void i915_irq_uninstall(struct drm_device * dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ int pipe;
+
+ if (I915_HAS_HOTPLUG(dev)) {
+ I915_WRITE(PORT_HOTPLUG_EN, 0);
+ I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
+ }
+
+ I915_WRITE16(HWSTAM, 0xffff);
+ for_each_pipe(pipe) {
+ /* Clear enable bits; then clear status bits */
+ I915_WRITE(PIPESTAT(pipe), 0);
+ I915_WRITE(PIPESTAT(pipe), I915_READ(PIPESTAT(pipe)));
+ }
+ I915_WRITE(IMR, 0xffffffff);
+ I915_WRITE(IER, 0x0);
+
+ I915_WRITE(IIR, I915_READ(IIR));
+}
+
+static void i965_irq_preinstall(struct drm_device * dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ int pipe;
+
+ atomic_set(&dev_priv->irq_received, 0);
if (I915_HAS_HOTPLUG(dev)) {
I915_WRITE(PORT_HOTPLUG_EN, 0);
@@ -2001,20 +2333,25 @@ static void i915_driver_irq_preinstall(struct drm_device * dev)
POSTING_READ(IER);
}
-/*
- * Must be called after intel_modeset_init or hotplug interrupts won't be
- * enabled correctly.
- */
-static int i915_driver_irq_postinstall(struct drm_device *dev)
+static int i965_irq_postinstall(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR;
+ u32 enable_mask;
u32 error_mask;
- dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
-
/* Unmask the interrupts that we always want on. */
- dev_priv->irq_mask = ~I915_INTERRUPT_ENABLE_FIX;
+ dev_priv->irq_mask = ~(I915_ASLE_INTERRUPT |
+ I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
+ I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
+ I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
+ I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT |
+ I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
+
+ enable_mask = ~dev_priv->irq_mask;
+ enable_mask |= I915_USER_INTERRUPT;
+
+ if (IS_G4X(dev))
+ enable_mask |= I915_BSD_USER_INTERRUPT;
dev_priv->pipestat[0] = 0;
dev_priv->pipestat[1] = 0;
@@ -2081,31 +2418,124 @@ static int i915_driver_irq_postinstall(struct drm_device *dev)
return 0;
}
-static void ironlake_irq_uninstall(struct drm_device *dev)
+static irqreturn_t i965_irq_handler(DRM_IRQ_ARGS)
{
+ struct drm_device *dev = (struct drm_device *) arg;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ u32 iir, new_iir;
+ u32 pipe_stats[I915_MAX_PIPES];
+ unsigned long irqflags;
+ int irq_received;
+ int ret = IRQ_NONE, pipe;
- if (!dev_priv)
- return;
+ atomic_inc(&dev_priv->irq_received);
- dev_priv->vblank_pipe = 0;
+ iir = I915_READ(IIR);
- I915_WRITE(HWSTAM, 0xffffffff);
+ for (;;) {
+ bool blc_event = false;
- I915_WRITE(DEIMR, 0xffffffff);
- I915_WRITE(DEIER, 0x0);
- I915_WRITE(DEIIR, I915_READ(DEIIR));
+ irq_received = iir != 0;
- I915_WRITE(GTIMR, 0xffffffff);
- I915_WRITE(GTIER, 0x0);
- I915_WRITE(GTIIR, I915_READ(GTIIR));
+ /* Can't rely on pipestat interrupt bit in iir as it might
+ * have been cleared after the pipestat interrupt was received.
+ * It doesn't set the bit in iir again, but it still produces
+ * interrupts (for non-MSI).
+ */
+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+ if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
+ i915_handle_error(dev, false);
- I915_WRITE(SDEIMR, 0xffffffff);
- I915_WRITE(SDEIER, 0x0);
- I915_WRITE(SDEIIR, I915_READ(SDEIIR));
+ for_each_pipe(pipe) {
+ int reg = PIPESTAT(pipe);
+ pipe_stats[pipe] = I915_READ(reg);
+
+ /*
+ * Clear the PIPE*STAT regs before the IIR
+ */
+ if (pipe_stats[pipe] & 0x8000ffff) {
+ if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
+ DRM_DEBUG_DRIVER("pipe %c underrun\n",
+ pipe_name(pipe));
+ I915_WRITE(reg, pipe_stats[pipe]);
+ irq_received = 1;
+ }
+ }
+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+ if (!irq_received)
+ break;
+
+ ret = IRQ_HANDLED;
+
+ /* Consume port. Then clear IIR or we'll miss events */
+ if ((I915_HAS_HOTPLUG(dev)) &&
+ (iir & I915_DISPLAY_PORT_INTERRUPT)) {
+ u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
+
+ DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
+ hotplug_status);
+ if (hotplug_status & dev_priv->hotplug_supported_mask)
+ queue_work(dev_priv->wq,
+ &dev_priv->hotplug_work);
+
+ I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
+ I915_READ(PORT_HOTPLUG_STAT);
+ }
+
+ I915_WRITE(IIR, iir);
+ new_iir = I915_READ(IIR); /* Flush posted writes */
+
+ if (iir & I915_USER_INTERRUPT)
+ notify_ring(dev, &dev_priv->ring[RCS]);
+ if (iir & I915_BSD_USER_INTERRUPT)
+ notify_ring(dev, &dev_priv->ring[VCS]);
+
+ if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT)
+ intel_prepare_page_flip(dev, 0);
+
+ if (iir & I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT)
+ intel_prepare_page_flip(dev, 1);
+
+ for_each_pipe(pipe) {
+ if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS &&
+ drm_handle_vblank(dev, pipe)) {
+ i915_pageflip_stall_check(dev, pipe);
+ intel_finish_page_flip(dev, pipe);
+ }
+
+ if (pipe_stats[pipe] & PIPE_LEGACY_BLC_EVENT_STATUS)
+ blc_event = true;
+ }
+
+
+ if (blc_event || (iir & I915_ASLE_INTERRUPT))
+ intel_opregion_asle_intr(dev);
+
+ /* With MSI, interrupts are only generated when iir
+ * transitions from zero to nonzero. If another bit got
+ * set while we were handling the existing iir bits, then
+ * we would never get another interrupt.
+ *
+ * This is fine on non-MSI as well, as if we hit this path
+ * we avoid exiting the interrupt handler only to generate
+ * another one.
+ *
+ * Note that for MSI this could cause a stray interrupt report
+ * if an interrupt landed in the time between writing IIR and
+ * the posting read. This should be rare enough to never
+ * trigger the 99% of 100,000 interrupts test for disabling
+ * stray interrupts.
+ */
+ iir = new_iir;
+ }
+
+ i915_update_dri1_breadcrumb(dev);
+
+ return ret;
}
-static void i915_driver_irq_uninstall(struct drm_device * dev)
+static void i965_irq_uninstall(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
int pipe;
@@ -2113,8 +2543,6 @@ static void i915_driver_irq_uninstall(struct drm_device * dev)
if (!dev_priv)
return;
- dev_priv->vblank_pipe = 0;
-
if (I915_HAS_HOTPLUG(dev)) {
I915_WRITE(PORT_HOTPLUG_EN, 0);
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
@@ -2134,9 +2562,15 @@ static void i915_driver_irq_uninstall(struct drm_device * dev)
void intel_irq_init(struct drm_device *dev)
{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
+ INIT_WORK(&dev_priv->error_work, i915_error_work_func);
+ INIT_WORK(&dev_priv->rps_work, gen6_pm_rps_work);
+
dev->driver->get_vblank_counter = i915_get_vblank_counter;
dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
- if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev) || IS_IVYBRIDGE(dev)) {
+ if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
dev->driver->get_vblank_counter = gm45_get_vblank_counter;
}
@@ -2147,7 +2581,14 @@ void intel_irq_init(struct drm_device *dev)
dev->driver->get_vblank_timestamp = NULL;
dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;
- if (IS_IVYBRIDGE(dev)) {
+ if (IS_VALLEYVIEW(dev)) {
+ dev->driver->irq_handler = valleyview_irq_handler;
+ dev->driver->irq_preinstall = valleyview_irq_preinstall;
+ dev->driver->irq_postinstall = valleyview_irq_postinstall;
+ dev->driver->irq_uninstall = valleyview_irq_uninstall;
+ dev->driver->enable_vblank = valleyview_enable_vblank;
+ dev->driver->disable_vblank = valleyview_disable_vblank;
+ } else if (IS_IVYBRIDGE(dev)) {
/* Share pre & uninstall handlers with ILK/SNB */
dev->driver->irq_handler = ivybridge_irq_handler;
dev->driver->irq_preinstall = ironlake_irq_preinstall;
@@ -2155,6 +2596,14 @@ void intel_irq_init(struct drm_device *dev)
dev->driver->irq_uninstall = ironlake_irq_uninstall;
dev->driver->enable_vblank = ivybridge_enable_vblank;
dev->driver->disable_vblank = ivybridge_disable_vblank;
+ } else if (IS_HASWELL(dev)) {
+ /* Share interrupts handling with IVB */
+ dev->driver->irq_handler = ivybridge_irq_handler;
+ dev->driver->irq_preinstall = ironlake_irq_preinstall;
+ dev->driver->irq_postinstall = ivybridge_irq_postinstall;
+ dev->driver->irq_uninstall = ironlake_irq_uninstall;
+ dev->driver->enable_vblank = ivybridge_enable_vblank;
+ dev->driver->disable_vblank = ivybridge_disable_vblank;
} else if (HAS_PCH_SPLIT(dev)) {
dev->driver->irq_handler = ironlake_irq_handler;
dev->driver->irq_preinstall = ironlake_irq_preinstall;
@@ -2163,10 +2612,25 @@ void intel_irq_init(struct drm_device *dev)
dev->driver->enable_vblank = ironlake_enable_vblank;
dev->driver->disable_vblank = ironlake_disable_vblank;
} else {
- dev->driver->irq_preinstall = i915_driver_irq_preinstall;
- dev->driver->irq_postinstall = i915_driver_irq_postinstall;
- dev->driver->irq_uninstall = i915_driver_irq_uninstall;
- dev->driver->irq_handler = i915_driver_irq_handler;
+ if (INTEL_INFO(dev)->gen == 2) {
+ dev->driver->irq_preinstall = i8xx_irq_preinstall;
+ dev->driver->irq_postinstall = i8xx_irq_postinstall;
+ dev->driver->irq_handler = i8xx_irq_handler;
+ dev->driver->irq_uninstall = i8xx_irq_uninstall;
+ } else if (INTEL_INFO(dev)->gen == 3) {
+ /* IIR "flip pending" means done if this bit is set */
+ I915_WRITE(ECOSKPD, _MASKED_BIT_DISABLE(ECO_FLIP_DONE));
+
+ dev->driver->irq_preinstall = i915_irq_preinstall;
+ dev->driver->irq_postinstall = i915_irq_postinstall;
+ dev->driver->irq_uninstall = i915_irq_uninstall;
+ dev->driver->irq_handler = i915_irq_handler;
+ } else {
+ dev->driver->irq_preinstall = i965_irq_preinstall;
+ dev->driver->irq_postinstall = i965_irq_postinstall;
+ dev->driver->irq_uninstall = i965_irq_uninstall;
+ dev->driver->irq_handler = i965_irq_handler;
+ }
dev->driver->enable_vblank = i915_enable_vblank;
dev->driver->disable_vblank = i915_disable_vblank;
}
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 9d24d65f0c3e..2d49b9507ed0 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -27,6 +27,11 @@
#define _PIPE(pipe, a, b) ((a) + (pipe)*((b)-(a)))
+#define _PORT(port, a, b) ((a) + (port)*((b)-(a)))
+
+#define _MASKED_BIT_ENABLE(a) (((a) << 16) | (a))
+#define _MASKED_BIT_DISABLE(a) ((a) << 16)
+
/*
* The Bridge device's PCI config space has information about the
* fb aperture size and the amount of pre-reserved memory.
@@ -77,6 +82,7 @@
#define GRDOM_FULL (0<<2)
#define GRDOM_RENDER (1<<2)
#define GRDOM_MEDIA (3<<2)
+#define GRDOM_RESET_ENABLE (1<<0)
#define GEN6_MBCUNIT_SNPCR 0x900c /* for LLC config */
#define GEN6_MBC_SNPCR_SHIFT 21
@@ -125,6 +131,13 @@
#define ECOCHK_PPGTT_CACHE64B (0x3<<3)
#define ECOCHK_PPGTT_CACHE4B (0x0<<3)
+#define GAC_ECO_BITS 0x14090
+#define ECOBITS_PPGTT_CACHE64B (3<<8)
+#define ECOBITS_PPGTT_CACHE4B (0<<8)
+
+#define GAB_CTL 0x24000
+#define GAB_CTL_CONT_AFTER_PAGEFAULT (1<<8)
+
/* VGA stuff */
#define VGA_ST01_MDA 0x3ba
@@ -222,6 +235,7 @@
#define MI_BATCH_NON_SECURE (1)
#define MI_BATCH_NON_SECURE_I965 (1<<8)
#define MI_BATCH_BUFFER_START MI_INSTR(0x31, 0)
+#define MI_BATCH_GTT (2<<6) /* aliased with (1<<7) on gen4 */
#define MI_SEMAPHORE_MBOX MI_INSTR(0x16, 1) /* gen6+ */
#define MI_SEMAPHORE_GLOBAL_GTT (1<<22)
#define MI_SEMAPHORE_UPDATE (1<<21)
@@ -301,6 +315,61 @@
#define DEBUG_RESET_RENDER (1<<8)
#define DEBUG_RESET_DISPLAY (1<<9)
+/*
+ * DPIO - a special bus for various display related registers to hide behind:
+ * 0x800c: m1, m2, n, p1, p2, k dividers
+ * 0x8014: REF and SFR select
+ * 0x8014: N divider, VCO select
+ * 0x801c/3c: core clock bits
+ * 0x8048/68: low pass filter coefficients
+ * 0x8100: fast clock controls
+ */
+#define DPIO_PKT 0x2100
+#define DPIO_RID (0<<24)
+#define DPIO_OP_WRITE (1<<16)
+#define DPIO_OP_READ (0<<16)
+#define DPIO_PORTID (0x12<<8)
+#define DPIO_BYTE (0xf<<4)
+#define DPIO_BUSY (1<<0) /* status only */
+#define DPIO_DATA 0x2104
+#define DPIO_REG 0x2108
+#define DPIO_CTL 0x2110
+#define DPIO_MODSEL1 (1<<3) /* if ref clk b == 27 */
+#define DPIO_MODSEL0 (1<<2) /* if ref clk a == 27 */
+#define DPIO_SFR_BYPASS (1<<1)
+#define DPIO_RESET (1<<0)
+
+#define _DPIO_DIV_A 0x800c
+#define DPIO_POST_DIV_SHIFT (28) /* 3 bits */
+#define DPIO_K_SHIFT (24) /* 4 bits */
+#define DPIO_P1_SHIFT (21) /* 3 bits */
+#define DPIO_P2_SHIFT (16) /* 5 bits */
+#define DPIO_N_SHIFT (12) /* 4 bits */
+#define DPIO_ENABLE_CALIBRATION (1<<11)
+#define DPIO_M1DIV_SHIFT (8) /* 3 bits */
+#define DPIO_M2DIV_MASK 0xff
+#define _DPIO_DIV_B 0x802c
+#define DPIO_DIV(pipe) _PIPE(pipe, _DPIO_DIV_A, _DPIO_DIV_B)
+
+#define _DPIO_REFSFR_A 0x8014
+#define DPIO_REFSEL_OVERRIDE 27
+#define DPIO_PLL_MODESEL_SHIFT 24 /* 3 bits */
+#define DPIO_BIAS_CURRENT_CTL_SHIFT 21 /* 3 bits, always 0x7 */
+#define DPIO_PLL_REFCLK_SEL_SHIFT 16 /* 2 bits */
+#define DPIO_DRIVER_CTL_SHIFT 12 /* always set to 0x8 */
+#define DPIO_CLK_BIAS_CTL_SHIFT 8 /* always set to 0x5 */
+#define _DPIO_REFSFR_B 0x8034
+#define DPIO_REFSFR(pipe) _PIPE(pipe, _DPIO_REFSFR_A, _DPIO_REFSFR_B)
+
+#define _DPIO_CORE_CLK_A 0x801c
+#define _DPIO_CORE_CLK_B 0x803c
+#define DPIO_CORE_CLK(pipe) _PIPE(pipe, _DPIO_CORE_CLK_A, _DPIO_CORE_CLK_B)
+
+#define _DPIO_LFP_COEFF_A 0x8048
+#define _DPIO_LFP_COEFF_B 0x8068
+#define DPIO_LFP_COEFF(pipe) _PIPE(pipe, _DPIO_LFP_COEFF_A, _DPIO_LFP_COEFF_B)
+
+#define DPIO_FASTCLK_DISABLE 0x8100
/*
* Fence registers
@@ -360,8 +429,6 @@
#define ARB_MODE 0x04030
#define ARB_MODE_SWIZZLE_SNB (1<<4)
#define ARB_MODE_SWIZZLE_IVB (1<<5)
-#define ARB_MODE_ENABLE(x) GFX_MODE_ENABLE(x)
-#define ARB_MODE_DISABLE(x) GFX_MODE_DISABLE(x)
#define RENDER_HWS_PGA_GEN7 (0x04080)
#define RING_FAULT_REG(ring) (0x4094 + 0x100*(ring)->id)
#define DONE_REG 0x40b0
@@ -417,6 +484,7 @@
#define INSTDONE 0x02090
#define NOPID 0x02094
#define HWSTAM 0x02098
+#define DMA_FADD_I8XX 0x020d0
#define ERROR_GEN6 0x040a0
@@ -432,6 +500,7 @@
*/
# define _3D_CHICKEN2_WM_READ_PIPELINED (1 << 14)
#define _3D_CHICKEN3 0x02090
+#define _3D_CHICKEN_SF_DISABLE_FASTCLIP_CULL (1 << 5)
#define MI_MODE 0x0209c
# define VS_TIMER_DISPATCH (1 << 6)
@@ -447,14 +516,16 @@
#define GFX_PSMI_GRANULARITY (1<<10)
#define GFX_PPGTT_ENABLE (1<<9)
-#define GFX_MODE_ENABLE(bit) (((bit) << 16) | (bit))
-#define GFX_MODE_DISABLE(bit) (((bit) << 16) | (0))
-
#define SCPD0 0x0209c /* 915+ only */
#define IER 0x020a0
#define IIR 0x020a4
#define IMR 0x020a8
#define ISR 0x020ac
+#define VLV_IIR_RW 0x182084
+#define VLV_IER 0x1820a0
+#define VLV_IIR 0x1820a4
+#define VLV_IMR 0x1820a8
+#define VLV_ISR 0x1820ac
#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18)
#define I915_DISPLAY_PORT_INTERRUPT (1<<17)
#define I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT (1<<15)
@@ -500,7 +571,6 @@
#define LM_BURST_LENGTH 0x00000700
#define LM_FIFO_WATERMARK 0x0000001F
#define MI_ARB_STATE 0x020e4 /* 915+ only */
-#define MI_ARB_MASK_SHIFT 16 /* shift for enable bits */
/* Make render/texture TLB fetches lower priorty than associated data
* fetches. This is not turned on by default
@@ -565,7 +635,6 @@
#define MI_ARB_DISPLAY_PRIORITY_B_A (1 << 0) /* display B > display A */
#define CACHE_MODE_0 0x02120 /* 915+ only */
-#define CM0_MASK_SHIFT 16
#define CM0_IZ_OPT_DISABLE (1<<6)
#define CM0_ZR_OPT_DISABLE (1<<5)
#define CM0_STC_EVICT_DISABLE_LRA_SNB (1<<5)
@@ -579,7 +648,12 @@
#define ECO_GATING_CX_ONLY (1<<3)
#define ECO_FLIP_DONE (1<<0)
-/* GEN6 interrupt control */
+#define CACHE_MODE_1 0x7004 /* IVB+ */
+#define PIXEL_SUBSPAN_COLLECT_OPT_DISABLE (1<<6)
+
+/* GEN6 interrupt control
+ * Note that the per-ring interrupt bits do alias with the global interrupt bits
+ * in GTIMR. */
#define GEN6_RENDER_HWSTAM 0x2098
#define GEN6_RENDER_IMR 0x20a8
#define GEN6_RENDER_CONTEXT_SWITCH_INTERRUPT (1 << 8)
@@ -615,6 +689,21 @@
#define GEN6_BSD_RNCID 0x12198
+#define GEN7_FF_THREAD_MODE 0x20a0
+#define GEN7_FF_SCHED_MASK 0x0077070
+#define GEN7_FF_TS_SCHED_HS1 (0x5<<16)
+#define GEN7_FF_TS_SCHED_HS0 (0x3<<16)
+#define GEN7_FF_TS_SCHED_LOAD_BALANCE (0x1<<16)
+#define GEN7_FF_TS_SCHED_HW (0x0<<16) /* Default */
+#define GEN7_FF_VS_SCHED_HS1 (0x5<<12)
+#define GEN7_FF_VS_SCHED_HS0 (0x3<<12)
+#define GEN7_FF_VS_SCHED_LOAD_BALANCE (0x1<<12) /* Default */
+#define GEN7_FF_VS_SCHED_HW (0x0<<12)
+#define GEN7_FF_DS_SCHED_HS1 (0x5<<4)
+#define GEN7_FF_DS_SCHED_HS0 (0x3<<4)
+#define GEN7_FF_DS_SCHED_LOAD_BALANCE (0x1<<4) /* Default */
+#define GEN7_FF_DS_SCHED_HW (0x0<<4)
+
/*
* Framebuffer compression (915+ only)
*/
@@ -743,9 +832,9 @@
#define GMBUS_PORT_PANEL 3
#define GMBUS_PORT_DPC 4 /* HDMIC */
#define GMBUS_PORT_DPB 5 /* SDVO, HDMIB */
- /* 6 reserved */
-#define GMBUS_PORT_DPD 7 /* HDMID */
-#define GMBUS_NUM_PORTS 8
+#define GMBUS_PORT_DPD 6 /* HDMID */
+#define GMBUS_PORT_RESERVED 7 /* 7 reserved */
+#define GMBUS_NUM_PORTS (GMBUS_PORT_DPD - GMBUS_PORT_SSC + 1)
#define GMBUS1 0x5104 /* command/status */
#define GMBUS_SW_CLR_INT (1<<31)
#define GMBUS_SW_RDY (1<<30)
@@ -797,7 +886,9 @@
#define DPLL(pipe) _PIPE(pipe, _DPLL_A, _DPLL_B)
#define DPLL_VCO_ENABLE (1 << 31)
#define DPLL_DVO_HIGH_SPEED (1 << 30)
+#define DPLL_EXT_BUFFER_ENABLE_VLV (1 << 30)
#define DPLL_SYNCLOCK_ENABLE (1 << 29)
+#define DPLL_REFA_CLK_ENABLE_VLV (1 << 29)
#define DPLL_VGA_MODE_DIS (1 << 28)
#define DPLLB_MODE_DAC_SERIAL (1 << 26) /* i915 */
#define DPLLB_MODE_LVDS (2 << 26) /* i915 */
@@ -809,6 +900,7 @@
#define DPLL_P2_CLOCK_DIV_MASK 0x03000000 /* i915 */
#define DPLL_FPA01_P1_POST_DIV_MASK 0x00ff0000 /* i915 */
#define DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW 0x00ff8000 /* Pineview */
+#define DPLL_INTEGRATED_CLOCK_VLV (1<<13)
#define SRX_INDEX 0x3c4
#define SRX_DATA 0x3c5
@@ -904,6 +996,7 @@
#define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0
#define _DPLL_B_MD 0x06020 /* 965+ only */
#define DPLL_MD(pipe) _PIPE(pipe, _DPLL_A_MD, _DPLL_B_MD)
+
#define _FPA0 0x06040
#define _FPA1 0x06044
#define _FPB0 0x06048
@@ -1044,6 +1137,9 @@
#define RAMCLK_GATE_D 0x6210 /* CRL only */
#define DEUC 0x6214 /* CRL only */
+#define FW_BLC_SELF_VLV 0x6500
+#define FW_CSPWRDWNEN (1<<15)
+
/*
* Palette regs
*/
@@ -1601,9 +1697,12 @@
/* Video Data Island Packet control */
#define VIDEO_DIP_DATA 0x61178
#define VIDEO_DIP_CTL 0x61170
+/* Pre HSW: */
#define VIDEO_DIP_ENABLE (1 << 31)
#define VIDEO_DIP_PORT_B (1 << 29)
#define VIDEO_DIP_PORT_C (2 << 29)
+#define VIDEO_DIP_PORT_D (3 << 29)
+#define VIDEO_DIP_PORT_MASK (3 << 29)
#define VIDEO_DIP_ENABLE_AVI (1 << 21)
#define VIDEO_DIP_ENABLE_VENDOR (2 << 21)
#define VIDEO_DIP_ENABLE_SPD (8 << 21)
@@ -1614,6 +1713,10 @@
#define VIDEO_DIP_FREQ_ONCE (0 << 16)
#define VIDEO_DIP_FREQ_VSYNC (1 << 16)
#define VIDEO_DIP_FREQ_2VSYNC (2 << 16)
+#define VIDEO_DIP_FREQ_MASK (3 << 16)
+/* HSW and later: */
+#define VIDEO_DIP_ENABLE_AVI_HSW (1 << 12)
+#define VIDEO_DIP_ENABLE_SPD_HSW (1 << 0)
/* Panel power sequencing */
#define PP_STATUS 0x61200
@@ -2380,7 +2483,8 @@
/* Pipe A */
#define _PIPEADSL 0x70000
-#define DSL_LINEMASK 0x00000fff
+#define DSL_LINEMASK_GEN2 0x00000fff
+#define DSL_LINEMASK_GEN3 0x00001fff
#define _PIPEACONF 0x70008
#define PIPECONF_ENABLE (1<<31)
#define PIPECONF_DISABLE 0
@@ -2422,23 +2526,30 @@
#define PIPECONF_DITHER_TYPE_TEMP (3<<2)
#define _PIPEASTAT 0x70024
#define PIPE_FIFO_UNDERRUN_STATUS (1UL<<31)
+#define SPRITE1_FLIPDONE_INT_EN_VLV (1UL<<30)
#define PIPE_CRC_ERROR_ENABLE (1UL<<29)
#define PIPE_CRC_DONE_ENABLE (1UL<<28)
#define PIPE_GMBUS_EVENT_ENABLE (1UL<<27)
+#define PLANE_FLIP_DONE_INT_EN_VLV (1UL<<26)
#define PIPE_HOTPLUG_INTERRUPT_ENABLE (1UL<<26)
#define PIPE_VSYNC_INTERRUPT_ENABLE (1UL<<25)
#define PIPE_DISPLAY_LINE_COMPARE_ENABLE (1UL<<24)
#define PIPE_DPST_EVENT_ENABLE (1UL<<23)
+#define SPRITE0_FLIP_DONE_INT_EN_VLV (1UL<<26)
#define PIPE_LEGACY_BLC_EVENT_ENABLE (1UL<<22)
#define PIPE_ODD_FIELD_INTERRUPT_ENABLE (1UL<<21)
#define PIPE_EVEN_FIELD_INTERRUPT_ENABLE (1UL<<20)
#define PIPE_HOTPLUG_TV_INTERRUPT_ENABLE (1UL<<18) /* pre-965 */
#define PIPE_START_VBLANK_INTERRUPT_ENABLE (1UL<<18) /* 965 or later */
#define PIPE_VBLANK_INTERRUPT_ENABLE (1UL<<17)
+#define PIPEA_HBLANK_INT_EN_VLV (1UL<<16)
#define PIPE_OVERLAY_UPDATED_ENABLE (1UL<<16)
+#define SPRITE1_FLIPDONE_INT_STATUS_VLV (1UL<<15)
+#define SPRITE0_FLIPDONE_INT_STATUS_VLV (1UL<<15)
#define PIPE_CRC_ERROR_INTERRUPT_STATUS (1UL<<13)
#define PIPE_CRC_DONE_INTERRUPT_STATUS (1UL<<12)
#define PIPE_GMBUS_INTERRUPT_STATUS (1UL<<11)
+#define PLANE_FLIPDONE_INT_STATUS_VLV (1UL<<10)
#define PIPE_HOTPLUG_INTERRUPT_STATUS (1UL<<10)
#define PIPE_VSYNC_INTERRUPT_STATUS (1UL<<9)
#define PIPE_DISPLAY_LINE_COMPARE_STATUS (1UL<<8)
@@ -2463,6 +2574,40 @@
#define PIPEFRAMEPIXEL(pipe) _PIPE(pipe, _PIPEAFRAMEPIXEL, _PIPEBFRAMEPIXEL)
#define PIPESTAT(pipe) _PIPE(pipe, _PIPEASTAT, _PIPEBSTAT)
+#define VLV_DPFLIPSTAT 0x70028
+#define PIPEB_LINE_COMPARE_STATUS (1<<29)
+#define PIPEB_HLINE_INT_EN (1<<28)
+#define PIPEB_VBLANK_INT_EN (1<<27)
+#define SPRITED_FLIPDONE_INT_EN (1<<26)
+#define SPRITEC_FLIPDONE_INT_EN (1<<25)
+#define PLANEB_FLIPDONE_INT_EN (1<<24)
+#define PIPEA_LINE_COMPARE_STATUS (1<<21)
+#define PIPEA_HLINE_INT_EN (1<<20)
+#define PIPEA_VBLANK_INT_EN (1<<19)
+#define SPRITEB_FLIPDONE_INT_EN (1<<18)
+#define SPRITEA_FLIPDONE_INT_EN (1<<17)
+#define PLANEA_FLIPDONE_INT_EN (1<<16)
+
+#define DPINVGTT 0x7002c /* VLV only */
+#define CURSORB_INVALID_GTT_INT_EN (1<<23)
+#define CURSORA_INVALID_GTT_INT_EN (1<<22)
+#define SPRITED_INVALID_GTT_INT_EN (1<<21)
+#define SPRITEC_INVALID_GTT_INT_EN (1<<20)
+#define PLANEB_INVALID_GTT_INT_EN (1<<19)
+#define SPRITEB_INVALID_GTT_INT_EN (1<<18)
+#define SPRITEA_INVALID_GTT_INT_EN (1<<17)
+#define PLANEA_INVALID_GTT_INT_EN (1<<16)
+#define DPINVGTT_EN_MASK 0xff0000
+#define CURSORB_INVALID_GTT_STATUS (1<<7)
+#define CURSORA_INVALID_GTT_STATUS (1<<6)
+#define SPRITED_INVALID_GTT_STATUS (1<<5)
+#define SPRITEC_INVALID_GTT_STATUS (1<<4)
+#define PLANEB_INVALID_GTT_STATUS (1<<3)
+#define SPRITEB_INVALID_GTT_STATUS (1<<2)
+#define SPRITEA_INVALID_GTT_STATUS (1<<1)
+#define PLANEA_INVALID_GTT_STATUS (1<<0)
+#define DPINVGTT_STATUS_MASK 0xff
+
#define DSPARB 0x70030
#define DSPARB_CSTART_MASK (0x7f << 7)
#define DSPARB_CSTART_SHIFT 7
@@ -2492,11 +2637,28 @@
#define DSPFW_HPLL_CURSOR_MASK (0x3f<<16)
#define DSPFW_HPLL_SR_MASK (0x1ff)
+/* drain latency register values*/
+#define DRAIN_LATENCY_PRECISION_32 32
+#define DRAIN_LATENCY_PRECISION_16 16
+#define VLV_DDL1 0x70050
+#define DDL_CURSORA_PRECISION_32 (1<<31)
+#define DDL_CURSORA_PRECISION_16 (0<<31)
+#define DDL_CURSORA_SHIFT 24
+#define DDL_PLANEA_PRECISION_32 (1<<7)
+#define DDL_PLANEA_PRECISION_16 (0<<7)
+#define VLV_DDL2 0x70054
+#define DDL_CURSORB_PRECISION_32 (1<<31)
+#define DDL_CURSORB_PRECISION_16 (0<<31)
+#define DDL_CURSORB_SHIFT 24
+#define DDL_PLANEB_PRECISION_32 (1<<7)
+#define DDL_PLANEB_PRECISION_16 (0<<7)
+
/* FIFO watermark sizes etc */
#define G4X_FIFO_LINE_SIZE 64
#define I915_FIFO_LINE_SIZE 64
#define I830_FIFO_LINE_SIZE 32
+#define VALLEYVIEW_FIFO_SIZE 255
#define G4X_FIFO_SIZE 127
#define I965_FIFO_SIZE 512
#define I945_FIFO_SIZE 127
@@ -2504,6 +2666,7 @@
#define I855GM_FIFO_SIZE 127 /* In cachelines */
#define I830_FIFO_SIZE 95
+#define VALLEYVIEW_MAX_WM 0xff
#define G4X_MAX_WM 0x3f
#define I915_MAX_WM 0x3f
@@ -2518,6 +2681,7 @@
#define PINEVIEW_CURSOR_DFT_WM 0
#define PINEVIEW_CURSOR_GUARD_WM 5
+#define VALLEYVIEW_CURSOR_MAX_WM 64
#define I965_CURSOR_FIFO 64
#define I965_CURSOR_MAX_WM 32
#define I965_CURSOR_DFT_WM 8
@@ -2726,6 +2890,13 @@
#define DSPSURF(plane) _PIPE(plane, _DSPASURF, _DSPBSURF)
#define DSPTILEOFF(plane) _PIPE(plane, _DSPATILEOFF, _DSPBTILEOFF)
+/* Display/Sprite base address macros */
+#define DISP_BASEADDR_MASK (0xfffff000)
+#define I915_LO_DISPBASE(val) (val & ~DISP_BASEADDR_MASK)
+#define I915_HI_DISPBASE(val) (val & DISP_BASEADDR_MASK)
+#define I915_MODIFY_DISPBASE(reg, gfx_addr) \
+ (I915_WRITE(reg, gfx_addr | I915_LO_DISPBASE(I915_READ(reg))))
+
/* VBIOS flags */
#define SWF00 0x71410
#define SWF01 0x71414
@@ -3058,25 +3229,38 @@
#define DE_PCH_EVENT_IVB (1<<28)
#define DE_DP_A_HOTPLUG_IVB (1<<27)
#define DE_AUX_CHANNEL_A_IVB (1<<26)
+#define DE_SPRITEC_FLIP_DONE_IVB (1<<14)
+#define DE_PLANEC_FLIP_DONE_IVB (1<<13)
+#define DE_PIPEC_VBLANK_IVB (1<<10)
#define DE_SPRITEB_FLIP_DONE_IVB (1<<9)
-#define DE_SPRITEA_FLIP_DONE_IVB (1<<4)
#define DE_PLANEB_FLIP_DONE_IVB (1<<8)
-#define DE_PLANEA_FLIP_DONE_IVB (1<<3)
#define DE_PIPEB_VBLANK_IVB (1<<5)
+#define DE_SPRITEA_FLIP_DONE_IVB (1<<4)
+#define DE_PLANEA_FLIP_DONE_IVB (1<<3)
#define DE_PIPEA_VBLANK_IVB (1<<0)
+#define VLV_MASTER_IER 0x4400c /* Gunit master IER */
+#define MASTER_INTERRUPT_ENABLE (1<<31)
+
#define DEISR 0x44000
#define DEIMR 0x44004
#define DEIIR 0x44008
#define DEIER 0x4400c
-/* GT interrupt */
-#define GT_PIPE_NOTIFY (1 << 4)
-#define GT_SYNC_STATUS (1 << 2)
-#define GT_USER_INTERRUPT (1 << 0)
-#define GT_BSD_USER_INTERRUPT (1 << 5)
-#define GT_GEN6_BSD_USER_INTERRUPT (1 << 12)
-#define GT_BLT_USER_INTERRUPT (1 << 22)
+/* GT interrupt.
+ * Note that for gen6+ the ring-specific interrupt bits do alias with the
+ * corresponding bits in the per-ring interrupt control registers. */
+#define GT_GEN6_BLT_FLUSHDW_NOTIFY_INTERRUPT (1 << 26)
+#define GT_GEN6_BLT_CS_ERROR_INTERRUPT (1 << 25)
+#define GT_GEN6_BLT_USER_INTERRUPT (1 << 22)
+#define GT_GEN6_BSD_CS_ERROR_INTERRUPT (1 << 15)
+#define GT_GEN6_BSD_USER_INTERRUPT (1 << 12)
+#define GT_BSD_USER_INTERRUPT (1 << 5) /* ilk only */
+#define GT_GEN7_L3_PARITY_ERROR_INTERRUPT (1 << 5)
+#define GT_PIPE_NOTIFY (1 << 4)
+#define GT_RENDER_CS_ERROR_INTERRUPT (1 << 3)
+#define GT_SYNC_STATUS (1 << 2)
+#define GT_USER_INTERRUPT (1 << 0)
#define GTISR 0x44010
#define GTIMR 0x44014
@@ -3226,15 +3410,15 @@
#define _PCH_DPLL_A 0xc6014
#define _PCH_DPLL_B 0xc6018
-#define PCH_DPLL(pipe) (pipe == 0 ? _PCH_DPLL_A : _PCH_DPLL_B)
+#define _PCH_DPLL(pll) (pll == 0 ? _PCH_DPLL_A : _PCH_DPLL_B)
#define _PCH_FPA0 0xc6040
#define FP_CB_TUNE (0x3<<22)
#define _PCH_FPA1 0xc6044
#define _PCH_FPB0 0xc6048
#define _PCH_FPB1 0xc604c
-#define PCH_FP0(pipe) (pipe == 0 ? _PCH_FPA0 : _PCH_FPB0)
-#define PCH_FP1(pipe) (pipe == 0 ? _PCH_FPA1 : _PCH_FPB1)
+#define _PCH_FP0(pll) (pll == 0 ? _PCH_FPA0 : _PCH_FPB0)
+#define _PCH_FP1(pll) (pll == 0 ? _PCH_FPA1 : _PCH_FPB1)
#define PCH_DPLL_TEST 0xc606c
@@ -3329,6 +3513,57 @@
#define TVIDEO_DIP_DATA(pipe) _PIPE(pipe, _VIDEO_DIP_DATA_A, _VIDEO_DIP_DATA_B)
#define TVIDEO_DIP_GCP(pipe) _PIPE(pipe, _VIDEO_DIP_GCP_A, _VIDEO_DIP_GCP_B)
+#define VLV_VIDEO_DIP_CTL_A 0x60220
+#define VLV_VIDEO_DIP_DATA_A 0x60208
+#define VLV_VIDEO_DIP_GDCP_PAYLOAD_A 0x60210
+
+#define VLV_VIDEO_DIP_CTL_B 0x61170
+#define VLV_VIDEO_DIP_DATA_B 0x61174
+#define VLV_VIDEO_DIP_GDCP_PAYLOAD_B 0x61178
+
+#define VLV_TVIDEO_DIP_CTL(pipe) \
+ _PIPE(pipe, VLV_VIDEO_DIP_CTL_A, VLV_VIDEO_DIP_CTL_B)
+#define VLV_TVIDEO_DIP_DATA(pipe) \
+ _PIPE(pipe, VLV_VIDEO_DIP_DATA_A, VLV_VIDEO_DIP_DATA_B)
+#define VLV_TVIDEO_DIP_GCP(pipe) \
+ _PIPE(pipe, VLV_VIDEO_DIP_GDCP_PAYLOAD_A, VLV_VIDEO_DIP_GDCP_PAYLOAD_B)
+
+/* Haswell DIP controls */
+#define HSW_VIDEO_DIP_CTL_A 0x60200
+#define HSW_VIDEO_DIP_AVI_DATA_A 0x60220
+#define HSW_VIDEO_DIP_VS_DATA_A 0x60260
+#define HSW_VIDEO_DIP_SPD_DATA_A 0x602A0
+#define HSW_VIDEO_DIP_GMP_DATA_A 0x602E0
+#define HSW_VIDEO_DIP_VSC_DATA_A 0x60320
+#define HSW_VIDEO_DIP_AVI_ECC_A 0x60240
+#define HSW_VIDEO_DIP_VS_ECC_A 0x60280
+#define HSW_VIDEO_DIP_SPD_ECC_A 0x602C0
+#define HSW_VIDEO_DIP_GMP_ECC_A 0x60300
+#define HSW_VIDEO_DIP_VSC_ECC_A 0x60344
+#define HSW_VIDEO_DIP_GCP_A 0x60210
+
+#define HSW_VIDEO_DIP_CTL_B 0x61200
+#define HSW_VIDEO_DIP_AVI_DATA_B 0x61220
+#define HSW_VIDEO_DIP_VS_DATA_B 0x61260
+#define HSW_VIDEO_DIP_SPD_DATA_B 0x612A0
+#define HSW_VIDEO_DIP_GMP_DATA_B 0x612E0
+#define HSW_VIDEO_DIP_VSC_DATA_B 0x61320
+#define HSW_VIDEO_DIP_BVI_ECC_B 0x61240
+#define HSW_VIDEO_DIP_VS_ECC_B 0x61280
+#define HSW_VIDEO_DIP_SPD_ECC_B 0x612C0
+#define HSW_VIDEO_DIP_GMP_ECC_B 0x61300
+#define HSW_VIDEO_DIP_VSC_ECC_B 0x61344
+#define HSW_VIDEO_DIP_GCP_B 0x61210
+
+#define HSW_TVIDEO_DIP_CTL(pipe) \
+ _PIPE(pipe, HSW_VIDEO_DIP_CTL_A, HSW_VIDEO_DIP_CTL_B)
+#define HSW_TVIDEO_DIP_AVI_DATA(pipe) \
+ _PIPE(pipe, HSW_VIDEO_DIP_AVI_DATA_A, HSW_VIDEO_DIP_AVI_DATA_B)
+#define HSW_TVIDEO_DIP_SPD_DATA(pipe) \
+ _PIPE(pipe, HSW_VIDEO_DIP_SPD_DATA_A, HSW_VIDEO_DIP_SPD_DATA_B)
+#define HSW_TVIDEO_DIP_GCP(pipe) \
+ _PIPE(pipe, HSW_VIDEO_DIP_GCP_A, HSW_VIDEO_DIP_GCP_B)
+
#define _TRANS_HTOTAL_B 0xe1000
#define _TRANS_HBLANK_B 0xe1004
#define _TRANS_HSYNC_B 0xe1008
@@ -3489,6 +3724,9 @@
#define FDI_LINK_TRAIN_PATTERN_IDLE_CPT (2<<8)
#define FDI_LINK_TRAIN_NORMAL_CPT (3<<8)
#define FDI_LINK_TRAIN_PATTERN_MASK_CPT (3<<8)
+/* LPT */
+#define FDI_PORT_WIDTH_2X_LPT (1<<19)
+#define FDI_PORT_WIDTH_1X_LPT (0<<19)
#define _FDI_RXA_MISC 0xf0010
#define _FDI_RXB_MISC 0xf1010
@@ -3549,6 +3787,7 @@
#define ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16)
/* or SDVOB */
+#define VLV_HDMIB 0x61140
#define HDMIB 0xe1140
#define PORT_ENABLE (1 << 31)
#define TRANSCODER(pipe) ((pipe) << 30)
@@ -3714,6 +3953,8 @@
#define EDP_LINK_TRAIN_VOL_EMP_MASK_IVB (0x3f<<22)
#define FORCEWAKE 0xA18C
+#define FORCEWAKE_VLV 0x1300b0
+#define FORCEWAKE_ACK_VLV 0x1300b4
#define FORCEWAKE_ACK 0x130090
#define FORCEWAKE_MT 0xa188 /* multi-threaded */
#define FORCEWAKE_MT_ACK 0x130040
@@ -3731,6 +3972,7 @@
#define GEN6_UCGCTL1 0x9400
# define GEN6_BLBUNIT_CLOCK_GATE_DISABLE (1 << 5)
+# define GEN6_CSUNIT_CLOCK_GATE_DISABLE (1 << 7)
#define GEN6_UCGCTL2 0x9404
# define GEN6_RCZUNIT_CLOCK_GATE_DISABLE (1 << 13)
@@ -3811,6 +4053,11 @@
GEN6_PM_RP_DOWN_THRESHOLD | \
GEN6_PM_RP_DOWN_TIMEOUT)
+#define GEN6_GT_GFX_RC6_LOCKED 0x138104
+#define GEN6_GT_GFX_RC6 0x138108
+#define GEN6_GT_GFX_RC6p 0x13810C
+#define GEN6_GT_GFX_RC6pp 0x138110
+
#define GEN6_PCODE_MAILBOX 0x138124
#define GEN6_PCODE_READY (1<<31)
#define GEN6_READ_OC_PARAMS 0xc
@@ -3870,4 +4117,197 @@
#define AUD_CONFIG_PIXEL_CLOCK_HDMI (0xf << 16)
#define AUD_CONFIG_DISABLE_NCTS (1 << 3)
+/* HSW Power Wells */
+#define HSW_PWR_WELL_CTL1 0x45400 /* BIOS */
+#define HSW_PWR_WELL_CTL2 0x45404 /* Driver */
+#define HSW_PWR_WELL_CTL3 0x45408 /* KVMR */
+#define HSW_PWR_WELL_CTL4 0x4540C /* Debug */
+#define HSW_PWR_WELL_ENABLE (1<<31)
+#define HSW_PWR_WELL_STATE (1<<30)
+#define HSW_PWR_WELL_CTL5 0x45410
+#define HSW_PWR_WELL_ENABLE_SINGLE_STEP (1<<31)
+#define HSW_PWR_WELL_PWR_GATE_OVERRIDE (1<<20)
+#define HSW_PWR_WELL_FORCE_ON (1<<19)
+#define HSW_PWR_WELL_CTL6 0x45414
+
+/* Per-pipe DDI Function Control */
+#define PIPE_DDI_FUNC_CTL_A 0x60400
+#define PIPE_DDI_FUNC_CTL_B 0x61400
+#define PIPE_DDI_FUNC_CTL_C 0x62400
+#define PIPE_DDI_FUNC_CTL_EDP 0x6F400
+#define DDI_FUNC_CTL(pipe) _PIPE(pipe, \
+ PIPE_DDI_FUNC_CTL_A, \
+ PIPE_DDI_FUNC_CTL_B)
+#define PIPE_DDI_FUNC_ENABLE (1<<31)
+/* Those bits are ignored by pipe EDP since it can only connect to DDI A */
+#define PIPE_DDI_PORT_MASK (0xf<<28)
+#define PIPE_DDI_SELECT_PORT(x) ((x)<<28)
+#define PIPE_DDI_MODE_SELECT_HDMI (0<<24)
+#define PIPE_DDI_MODE_SELECT_DVI (1<<24)
+#define PIPE_DDI_MODE_SELECT_DP_SST (2<<24)
+#define PIPE_DDI_MODE_SELECT_DP_MST (3<<24)
+#define PIPE_DDI_MODE_SELECT_FDI (4<<24)
+#define PIPE_DDI_BPC_8 (0<<20)
+#define PIPE_DDI_BPC_10 (1<<20)
+#define PIPE_DDI_BPC_6 (2<<20)
+#define PIPE_DDI_BPC_12 (3<<20)
+#define PIPE_DDI_BFI_ENABLE (1<<4)
+#define PIPE_DDI_PORT_WIDTH_X1 (0<<1)
+#define PIPE_DDI_PORT_WIDTH_X2 (1<<1)
+#define PIPE_DDI_PORT_WIDTH_X4 (3<<1)
+
+/* DisplayPort Transport Control */
+#define DP_TP_CTL_A 0x64040
+#define DP_TP_CTL_B 0x64140
+#define DP_TP_CTL(port) _PORT(port, \
+ DP_TP_CTL_A, \
+ DP_TP_CTL_B)
+#define DP_TP_CTL_ENABLE (1<<31)
+#define DP_TP_CTL_MODE_SST (0<<27)
+#define DP_TP_CTL_MODE_MST (1<<27)
+#define DP_TP_CTL_ENHANCED_FRAME_ENABLE (1<<18)
+#define DP_TP_CTL_FDI_AUTOTRAIN (1<<15)
+#define DP_TP_CTL_LINK_TRAIN_MASK (7<<8)
+#define DP_TP_CTL_LINK_TRAIN_PAT1 (0<<8)
+#define DP_TP_CTL_LINK_TRAIN_PAT2 (1<<8)
+#define DP_TP_CTL_LINK_TRAIN_NORMAL (3<<8)
+
+/* DisplayPort Transport Status */
+#define DP_TP_STATUS_A 0x64044
+#define DP_TP_STATUS_B 0x64144
+#define DP_TP_STATUS(port) _PORT(port, \
+ DP_TP_STATUS_A, \
+ DP_TP_STATUS_B)
+#define DP_TP_STATUS_AUTOTRAIN_DONE (1<<12)
+
+/* DDI Buffer Control */
+#define DDI_BUF_CTL_A 0x64000
+#define DDI_BUF_CTL_B 0x64100
+#define DDI_BUF_CTL(port) _PORT(port, \
+ DDI_BUF_CTL_A, \
+ DDI_BUF_CTL_B)
+#define DDI_BUF_CTL_ENABLE (1<<31)
+#define DDI_BUF_EMP_400MV_0DB_HSW (0<<24) /* Sel0 */
+#define DDI_BUF_EMP_400MV_3_5DB_HSW (1<<24) /* Sel1 */
+#define DDI_BUF_EMP_400MV_6DB_HSW (2<<24) /* Sel2 */
+#define DDI_BUF_EMP_400MV_9_5DB_HSW (3<<24) /* Sel3 */
+#define DDI_BUF_EMP_600MV_0DB_HSW (4<<24) /* Sel4 */
+#define DDI_BUF_EMP_600MV_3_5DB_HSW (5<<24) /* Sel5 */
+#define DDI_BUF_EMP_600MV_6DB_HSW (6<<24) /* Sel6 */
+#define DDI_BUF_EMP_800MV_0DB_HSW (7<<24) /* Sel7 */
+#define DDI_BUF_EMP_800MV_3_5DB_HSW (8<<24) /* Sel8 */
+#define DDI_BUF_EMP_MASK (0xf<<24)
+#define DDI_BUF_IS_IDLE (1<<7)
+#define DDI_PORT_WIDTH_X1 (0<<1)
+#define DDI_PORT_WIDTH_X2 (1<<1)
+#define DDI_PORT_WIDTH_X4 (3<<1)
+#define DDI_INIT_DISPLAY_DETECTED (1<<0)
+
+/* DDI Buffer Translations */
+#define DDI_BUF_TRANS_A 0x64E00
+#define DDI_BUF_TRANS_B 0x64E60
+#define DDI_BUF_TRANS(port) _PORT(port, \
+ DDI_BUF_TRANS_A, \
+ DDI_BUF_TRANS_B)
+
+/* Sideband Interface (SBI) is programmed indirectly, via
+ * SBI_ADDR, which contains the register offset; and SBI_DATA,
+ * which contains the payload */
+#define SBI_ADDR 0xC6000
+#define SBI_DATA 0xC6004
+#define SBI_CTL_STAT 0xC6008
+#define SBI_CTL_OP_CRRD (0x6<<8)
+#define SBI_CTL_OP_CRWR (0x7<<8)
+#define SBI_RESPONSE_FAIL (0x1<<1)
+#define SBI_RESPONSE_SUCCESS (0x0<<1)
+#define SBI_BUSY (0x1<<0)
+#define SBI_READY (0x0<<0)
+
+/* SBI offsets */
+#define SBI_SSCDIVINTPHASE6 0x0600
+#define SBI_SSCDIVINTPHASE_DIVSEL_MASK ((0x7f)<<1)
+#define SBI_SSCDIVINTPHASE_DIVSEL(x) ((x)<<1)
+#define SBI_SSCDIVINTPHASE_INCVAL_MASK ((0x7f)<<8)
+#define SBI_SSCDIVINTPHASE_INCVAL(x) ((x)<<8)
+#define SBI_SSCDIVINTPHASE_DIR(x) ((x)<<15)
+#define SBI_SSCDIVINTPHASE_PROPAGATE (1<<0)
+#define SBI_SSCCTL 0x020c
+#define SBI_SSCCTL6 0x060C
+#define SBI_SSCCTL_DISABLE (1<<0)
+#define SBI_SSCAUXDIV6 0x0610
+#define SBI_SSCAUXDIV_FINALDIV2SEL(x) ((x)<<4)
+#define SBI_DBUFF0 0x2a00
+
+/* LPT PIXCLK_GATE */
+#define PIXCLK_GATE 0xC6020
+#define PIXCLK_GATE_UNGATE 1<<0
+#define PIXCLK_GATE_GATE 0<<0
+
+/* SPLL */
+#define SPLL_CTL 0x46020
+#define SPLL_PLL_ENABLE (1<<31)
+#define SPLL_PLL_SCC (1<<28)
+#define SPLL_PLL_NON_SCC (2<<28)
+#define SPLL_PLL_FREQ_810MHz (0<<26)
+#define SPLL_PLL_FREQ_1350MHz (1<<26)
+
+/* WRPLL */
+#define WRPLL_CTL1 0x46040
+#define WRPLL_CTL2 0x46060
+#define WRPLL_PLL_ENABLE (1<<31)
+#define WRPLL_PLL_SELECT_SSC (0x01<<28)
+#define WRPLL_PLL_SELECT_NON_SCC (0x02<<28)
+#define WRPLL_PLL_SELECT_LCPLL_2700 (0x03<<28)
+/* WRPLL divider programming */
+#define WRPLL_DIVIDER_REFERENCE(x) ((x)<<0)
+#define WRPLL_DIVIDER_POST(x) ((x)<<8)
+#define WRPLL_DIVIDER_FEEDBACK(x) ((x)<<16)
+
+/* Port clock selection */
+#define PORT_CLK_SEL_A 0x46100
+#define PORT_CLK_SEL_B 0x46104
+#define PORT_CLK_SEL(port) _PORT(port, \
+ PORT_CLK_SEL_A, \
+ PORT_CLK_SEL_B)
+#define PORT_CLK_SEL_LCPLL_2700 (0<<29)
+#define PORT_CLK_SEL_LCPLL_1350 (1<<29)
+#define PORT_CLK_SEL_LCPLL_810 (2<<29)
+#define PORT_CLK_SEL_SPLL (3<<29)
+#define PORT_CLK_SEL_WRPLL1 (4<<29)
+#define PORT_CLK_SEL_WRPLL2 (5<<29)
+
+/* Pipe clock selection */
+#define PIPE_CLK_SEL_A 0x46140
+#define PIPE_CLK_SEL_B 0x46144
+#define PIPE_CLK_SEL(pipe) _PIPE(pipe, \
+ PIPE_CLK_SEL_A, \
+ PIPE_CLK_SEL_B)
+/* For each pipe, we need to select the corresponding port clock */
+#define PIPE_CLK_SEL_DISABLED (0x0<<29)
+#define PIPE_CLK_SEL_PORT(x) ((x+1)<<29)
+
+/* LCPLL Control */
+#define LCPLL_CTL 0x130040
+#define LCPLL_PLL_DISABLE (1<<31)
+#define LCPLL_PLL_LOCK (1<<30)
+#define LCPLL_CD_CLOCK_DISABLE (1<<25)
+#define LCPLL_CD2X_CLOCK_DISABLE (1<<23)
+
+/* Pipe WM_LINETIME - watermark line time */
+#define PIPE_WM_LINETIME_A 0x45270
+#define PIPE_WM_LINETIME_B 0x45274
+#define PIPE_WM_LINETIME(pipe) _PIPE(pipe, \
+ PIPE_WM_LINETIME_A, \
+ PIPE_WM_LINETIME_A)
+#define PIPE_WM_LINETIME_MASK (0x1ff)
+#define PIPE_WM_LINETIME_TIME(x) ((x))
+#define PIPE_WM_LINETIME_IPS_LINETIME_MASK (0x1ff<<16)
+#define PIPE_WM_LINETIME_IPS_LINETIME(x) ((x)<<16)
+
+/* SFUSE_STRAP */
+#define SFUSE_STRAP 0xc2014
+#define SFUSE_STRAP_DDIB_DETECTED (1<<2)
+#define SFUSE_STRAP_DDIC_DETECTED (1<<1)
+#define SFUSE_STRAP_DDID_DETECTED (1<<0)
+
#endif /* _I915_REG_H_ */
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index 2b5eb229ff2c..0ede02a99d91 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -40,7 +40,7 @@ static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe)
return false;
if (HAS_PCH_SPLIT(dev))
- dpll_reg = PCH_DPLL(pipe);
+ dpll_reg = _PCH_DPLL(pipe);
else
dpll_reg = (pipe == PIPE_A) ? _DPLL_A : _DPLL_B;
@@ -876,22 +876,6 @@ int i915_restore_state(struct drm_device *dev)
I915_WRITE(IER, dev_priv->saveIER);
I915_WRITE(IMR, dev_priv->saveIMR);
}
- mutex_unlock(&dev->struct_mutex);
-
- if (drm_core_check_feature(dev, DRIVER_MODESET))
- intel_init_clock_gating(dev);
-
- if (IS_IRONLAKE_M(dev)) {
- ironlake_enable_drps(dev);
- intel_init_emon(dev);
- }
-
- if (INTEL_INFO(dev)->gen >= 6) {
- gen6_enable_rps(dev_priv);
- gen6_update_ring_freq(dev_priv);
- }
-
- mutex_lock(&dev->struct_mutex);
/* Cache mode state */
I915_WRITE(CACHE_MODE_0, dev_priv->saveCACHE_MODE_0 | 0xffff0000);
diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
new file mode 100644
index 000000000000..79f83445afa0
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Ben Widawsky <ben@bwidawsk.net>
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/stat.h>
+#include <linux/sysfs.h>
+#include "i915_drv.h"
+
+static u32 calc_residency(struct drm_device *dev, const u32 reg)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u64 raw_time; /* 32b value may overflow during fixed point math */
+
+ if (!intel_enable_rc6(dev))
+ return 0;
+
+ raw_time = I915_READ(reg) * 128ULL;
+ return DIV_ROUND_UP_ULL(raw_time, 100000);
+}
+
+static ssize_t
+show_rc6_mask(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
+ return snprintf(buf, PAGE_SIZE, "%x", intel_enable_rc6(dminor->dev));
+}
+
+static ssize_t
+show_rc6_ms(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
+ u32 rc6_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6);
+ return snprintf(buf, PAGE_SIZE, "%u", rc6_residency);
+}
+
+static ssize_t
+show_rc6p_ms(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
+ u32 rc6p_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6p);
+ return snprintf(buf, PAGE_SIZE, "%u", rc6p_residency);
+}
+
+static ssize_t
+show_rc6pp_ms(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
+ u32 rc6pp_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6pp);
+ return snprintf(buf, PAGE_SIZE, "%u", rc6pp_residency);
+}
+
+static DEVICE_ATTR(rc6_enable, S_IRUGO, show_rc6_mask, NULL);
+static DEVICE_ATTR(rc6_residency_ms, S_IRUGO, show_rc6_ms, NULL);
+static DEVICE_ATTR(rc6p_residency_ms, S_IRUGO, show_rc6p_ms, NULL);
+static DEVICE_ATTR(rc6pp_residency_ms, S_IRUGO, show_rc6pp_ms, NULL);
+
+static struct attribute *rc6_attrs[] = {
+ &dev_attr_rc6_enable.attr,
+ &dev_attr_rc6_residency_ms.attr,
+ &dev_attr_rc6p_residency_ms.attr,
+ &dev_attr_rc6pp_residency_ms.attr,
+ NULL
+};
+
+static struct attribute_group rc6_attr_group = {
+ .name = power_group_name,
+ .attrs = rc6_attrs
+};
+
+void i915_setup_sysfs(struct drm_device *dev)
+{
+ int ret;
+
+ /* ILK doesn't have any residency information */
+ if (INTEL_INFO(dev)->gen < 6)
+ return;
+
+ ret = sysfs_merge_group(&dev->primary->kdev.kobj, &rc6_attr_group);
+ if (ret)
+ DRM_ERROR("sysfs setup failed\n");
+}
+
+void i915_teardown_sysfs(struct drm_device *dev)
+{
+ sysfs_unmerge_group(&dev->primary->kdev.kobj, &rc6_attr_group);
+}
diff --git a/drivers/gpu/drm/i915/i915_trace_points.c b/drivers/gpu/drm/i915/i915_trace_points.c
index ead876eb6ea0..f1df2bd4ecf4 100644
--- a/drivers/gpu/drm/i915/i915_trace_points.c
+++ b/drivers/gpu/drm/i915/i915_trace_points.c
@@ -7,5 +7,7 @@
#include "i915_drv.h"
+#ifndef __CHECKER__
#define CREATE_TRACE_POINTS
#include "i915_trace.h"
+#endif
diff --git a/drivers/gpu/drm/i915/intel_acpi.c b/drivers/gpu/drm/i915/intel_acpi.c
index bae3edf956a4..f413899475e9 100644
--- a/drivers/gpu/drm/i915/intel_acpi.c
+++ b/drivers/gpu/drm/i915/intel_acpi.c
@@ -9,6 +9,7 @@
#include <acpi/acpi_drivers.h>
#include "drmP.h"
+#include "i915_drv.h"
#define INTEL_DSM_REVISION_ID 1 /* For Calpella anyway... */
@@ -182,8 +183,6 @@ static void intel_dsm_platform_mux_info(void)
DRM_DEBUG_DRIVER(" hpd mux info: %s\n",
intel_dsm_mux_type(info->buffer.pointer[3]));
}
- } else {
- DRM_ERROR("MUX INFO call failed\n");
}
out:
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index b48fc2a8410c..353459362f6f 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -174,6 +174,28 @@ get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *lvds_lfp_data,
return (struct lvds_dvo_timing *)(entry + dvo_timing_offset);
}
+/* get lvds_fp_timing entry
+ * this function may return NULL if the corresponding entry is invalid
+ */
+static const struct lvds_fp_timing *
+get_lvds_fp_timing(const struct bdb_header *bdb,
+ const struct bdb_lvds_lfp_data *data,
+ const struct bdb_lvds_lfp_data_ptrs *ptrs,
+ int index)
+{
+ size_t data_ofs = (const u8 *)data - (const u8 *)bdb;
+ u16 data_size = ((const u16 *)data)[-1]; /* stored in header */
+ size_t ofs;
+
+ if (index >= ARRAY_SIZE(ptrs->ptr))
+ return NULL;
+ ofs = ptrs->ptr[index].fp_timing_offset;
+ if (ofs < data_ofs ||
+ ofs + sizeof(struct lvds_fp_timing) > data_ofs + data_size)
+ return NULL;
+ return (const struct lvds_fp_timing *)((const u8 *)bdb + ofs);
+}
+
/* Try to find integrated panel data */
static void
parse_lfp_panel_data(struct drm_i915_private *dev_priv,
@@ -183,6 +205,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
const struct bdb_lvds_lfp_data *lvds_lfp_data;
const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs;
const struct lvds_dvo_timing *panel_dvo_timing;
+ const struct lvds_fp_timing *fp_timing;
struct drm_display_mode *panel_fixed_mode;
int i, downclock;
@@ -244,6 +267,19 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
"Normal Clock %dKHz, downclock %dKHz\n",
panel_fixed_mode->clock, 10*downclock);
}
+
+ fp_timing = get_lvds_fp_timing(bdb, lvds_lfp_data,
+ lvds_lfp_data_ptrs,
+ lvds_options->panel_type);
+ if (fp_timing) {
+ /* check the resolution, just to be sure */
+ if (fp_timing->x_res == panel_fixed_mode->hdisplay &&
+ fp_timing->y_res == panel_fixed_mode->vdisplay) {
+ dev_priv->bios_lvds_val = fp_timing->lvds_reg_val;
+ DRM_DEBUG_KMS("VBT initial LVDS value %x\n",
+ dev_priv->bios_lvds_val);
+ }
+ }
}
/* Try to find sdvo panel data */
@@ -256,6 +292,11 @@ parse_sdvo_panel_data(struct drm_i915_private *dev_priv,
int index;
index = i915_vbt_sdvo_panel_type;
+ if (index == -2) {
+ DRM_DEBUG_KMS("Ignore SDVO panel mode from BIOS VBT tables.\n");
+ return;
+ }
+
if (index == -1) {
struct bdb_sdvo_lvds_options *sdvo_lvds_options;
@@ -332,11 +373,11 @@ parse_general_definitions(struct drm_i915_private *dev_priv,
if (block_size >= sizeof(*general)) {
int bus_pin = general->crt_ddc_gmbus_pin;
DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin);
- if (bus_pin >= 1 && bus_pin <= 6)
+ if (intel_gmbus_is_port_valid(bus_pin))
dev_priv->crt_ddc_pin = bus_pin;
} else {
DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n",
- block_size);
+ block_size);
}
}
}
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 90b9793fd5da..75a70c46ef1b 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -55,18 +55,36 @@ static struct intel_crt *intel_attached_crt(struct drm_connector *connector)
struct intel_crt, base);
}
-static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
+static void pch_crt_dpms(struct drm_encoder *encoder, int mode)
{
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 temp, reg;
+ u32 temp;
- if (HAS_PCH_SPLIT(dev))
- reg = PCH_ADPA;
- else
- reg = ADPA;
+ temp = I915_READ(PCH_ADPA);
+ temp &= ~ADPA_DAC_ENABLE;
+
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ temp |= ADPA_DAC_ENABLE;
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ case DRM_MODE_DPMS_OFF:
+ /* Just leave port enable cleared */
+ break;
+ }
+
+ I915_WRITE(PCH_ADPA, temp);
+}
- temp = I915_READ(reg);
+static void gmch_crt_dpms(struct drm_encoder *encoder, int mode)
+{
+ struct drm_device *dev = encoder->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 temp;
+
+ temp = I915_READ(ADPA);
temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE);
temp &= ~ADPA_DAC_ENABLE;
@@ -85,7 +103,7 @@ static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
break;
}
- I915_WRITE(reg, temp);
+ I915_WRITE(ADPA, temp);
}
static int intel_crt_mode_valid(struct drm_connector *connector,
@@ -278,9 +296,10 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector)
if (intel_ddc_probe(&crt->base, dev_priv->crt_ddc_pin)) {
struct edid *edid;
bool is_digital = false;
+ struct i2c_adapter *i2c;
- edid = drm_get_edid(connector,
- &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
+ i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin);
+ edid = drm_get_edid(connector, i2c);
/*
* This may be a DVI-I connector with a shared DDC
* link between analog and digital outputs, so we
@@ -476,15 +495,16 @@ static int intel_crt_get_modes(struct drm_connector *connector)
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
+ struct i2c_adapter *i2c;
- ret = intel_ddc_get_modes(connector,
- &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
+ i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->crt_ddc_pin);
+ ret = intel_ddc_get_modes(connector, i2c);
if (ret || !IS_G4X(dev))
return ret;
/* Try to probe digital port for output in DVI-I -> VGA mode. */
- return intel_ddc_get_modes(connector,
- &dev_priv->gmbus[GMBUS_PORT_DPB].adapter);
+ i2c = intel_gmbus_get_adapter(dev_priv, GMBUS_PORT_DPB);
+ return intel_ddc_get_modes(connector, i2c);
}
static int intel_crt_set_property(struct drm_connector *connector,
@@ -507,12 +527,20 @@ static void intel_crt_reset(struct drm_connector *connector)
* Routines for controlling stuff on the analog port
*/
-static const struct drm_encoder_helper_funcs intel_crt_helper_funcs = {
- .dpms = intel_crt_dpms,
+static const struct drm_encoder_helper_funcs pch_encoder_funcs = {
.mode_fixup = intel_crt_mode_fixup,
.prepare = intel_encoder_prepare,
.commit = intel_encoder_commit,
.mode_set = intel_crt_mode_set,
+ .dpms = pch_crt_dpms,
+};
+
+static const struct drm_encoder_helper_funcs gmch_encoder_funcs = {
+ .mode_fixup = intel_crt_mode_fixup,
+ .prepare = intel_encoder_prepare,
+ .commit = intel_encoder_commit,
+ .mode_set = intel_crt_mode_set,
+ .dpms = gmch_crt_dpms,
};
static const struct drm_connector_funcs intel_crt_connector_funcs = {
@@ -536,7 +564,7 @@ static const struct drm_encoder_funcs intel_crt_enc_funcs = {
static int __init intel_no_crt_dmi_callback(const struct dmi_system_id *id)
{
- DRM_DEBUG_KMS("Skipping CRT initialization for %s\n", id->ident);
+ DRM_INFO("Skipping CRT initialization for %s\n", id->ident);
return 1;
}
@@ -558,6 +586,7 @@ void intel_crt_init(struct drm_device *dev)
struct intel_crt *crt;
struct intel_connector *intel_connector;
struct drm_i915_private *dev_priv = dev->dev_private;
+ const struct drm_encoder_helper_funcs *encoder_helper_funcs;
/* Skip machines without VGA that falsely report hotplug events */
if (dmi_check_system(intel_no_crt))
@@ -586,14 +615,23 @@ void intel_crt_init(struct drm_device *dev)
crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT |
1 << INTEL_ANALOG_CLONE_BIT |
1 << INTEL_SDVO_LVDS_CLONE_BIT);
- crt->base.crtc_mask = (1 << 0) | (1 << 1);
+ if (IS_HASWELL(dev))
+ crt->base.crtc_mask = (1 << 0);
+ else
+ crt->base.crtc_mask = (1 << 0) | (1 << 1);
+
if (IS_GEN2(dev))
connector->interlace_allowed = 0;
else
connector->interlace_allowed = 1;
connector->doublescan_allowed = 0;
- drm_encoder_helper_add(&crt->base.base, &intel_crt_helper_funcs);
+ if (HAS_PCH_SPLIT(dev))
+ encoder_helper_funcs = &pch_encoder_funcs;
+ else
+ encoder_helper_funcs = &gmch_encoder_funcs;
+
+ drm_encoder_helper_add(&crt->base.base, encoder_helper_funcs);
drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
drm_sysfs_connector_add(connector);
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
new file mode 100644
index 000000000000..46d1e886c692
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -0,0 +1,755 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Eugeni Dodonov <eugeni.dodonov@intel.com>
+ *
+ */
+
+#include "i915_drv.h"
+#include "intel_drv.h"
+
+/* HDMI/DVI modes ignore everything but the last 2 items. So we share
+ * them for both DP and FDI transports, allowing those ports to
+ * automatically adapt to HDMI connections as well
+ */
+static const u32 hsw_ddi_translations_dp[] = {
+ 0x00FFFFFF, 0x0006000E, /* DP parameters */
+ 0x00D75FFF, 0x0005000A,
+ 0x00C30FFF, 0x00040006,
+ 0x80AAAFFF, 0x000B0000,
+ 0x00FFFFFF, 0x0005000A,
+ 0x00D75FFF, 0x000C0004,
+ 0x80C30FFF, 0x000B0000,
+ 0x00FFFFFF, 0x00040006,
+ 0x80D75FFF, 0x000B0000,
+ 0x00FFFFFF, 0x00040006 /* HDMI parameters */
+};
+
+static const u32 hsw_ddi_translations_fdi[] = {
+ 0x00FFFFFF, 0x0007000E, /* FDI parameters */
+ 0x00D75FFF, 0x000F000A,
+ 0x00C30FFF, 0x00060006,
+ 0x00AAAFFF, 0x001E0000,
+ 0x00FFFFFF, 0x000F000A,
+ 0x00D75FFF, 0x00160004,
+ 0x00C30FFF, 0x001E0000,
+ 0x00FFFFFF, 0x00060006,
+ 0x00D75FFF, 0x001E0000,
+ 0x00FFFFFF, 0x00040006 /* HDMI parameters */
+};
+
+/* On Haswell, DDI port buffers must be programmed with correct values
+ * in advance. The buffer values are different for FDI and DP modes,
+ * but the HDMI/DVI fields are shared among those. So we program the DDI
+ * in either FDI or DP modes only, as HDMI connections will work with both
+ * of those
+ */
+void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port, bool use_fdi_mode)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 reg;
+ int i;
+ const u32 *ddi_translations = ((use_fdi_mode) ?
+ hsw_ddi_translations_fdi :
+ hsw_ddi_translations_dp);
+
+ DRM_DEBUG_DRIVER("Initializing DDI buffers for port %c in %s mode\n",
+ port_name(port),
+ use_fdi_mode ? "FDI" : "DP");
+
+ WARN((use_fdi_mode && (port != PORT_E)),
+ "Programming port %c in FDI mode, this probably will not work.\n",
+ port_name(port));
+
+ for (i=0, reg=DDI_BUF_TRANS(port); i < ARRAY_SIZE(hsw_ddi_translations_fdi); i++) {
+ I915_WRITE(reg, ddi_translations[i]);
+ reg += 4;
+ }
+}
+
+/* Program DDI buffers translations for DP. By default, program ports A-D in DP
+ * mode and port E for FDI.
+ */
+void intel_prepare_ddi(struct drm_device *dev)
+{
+ int port;
+
+ if (IS_HASWELL(dev)) {
+ for (port = PORT_A; port < PORT_E; port++)
+ intel_prepare_ddi_buffers(dev, port, false);
+
+ /* DDI E is the suggested one to work in FDI mode, so program is as such by
+ * default. It will have to be re-programmed in case a digital DP output
+ * will be detected on it
+ */
+ intel_prepare_ddi_buffers(dev, PORT_E, true);
+ }
+}
+
+static const long hsw_ddi_buf_ctl_values[] = {
+ DDI_BUF_EMP_400MV_0DB_HSW,
+ DDI_BUF_EMP_400MV_3_5DB_HSW,
+ DDI_BUF_EMP_400MV_6DB_HSW,
+ DDI_BUF_EMP_400MV_9_5DB_HSW,
+ DDI_BUF_EMP_600MV_0DB_HSW,
+ DDI_BUF_EMP_600MV_3_5DB_HSW,
+ DDI_BUF_EMP_600MV_6DB_HSW,
+ DDI_BUF_EMP_800MV_0DB_HSW,
+ DDI_BUF_EMP_800MV_3_5DB_HSW
+};
+
+
+/* Starting with Haswell, different DDI ports can work in FDI mode for
+ * connection to the PCH-located connectors. For this, it is necessary to train
+ * both the DDI port and PCH receiver for the desired DDI buffer settings.
+ *
+ * The recommended port to work in FDI mode is DDI E, which we use here. Also,
+ * please note that when FDI mode is active on DDI E, it shares 2 lines with
+ * DDI A (which is used for eDP)
+ */
+
+void hsw_fdi_link_train(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ int pipe = intel_crtc->pipe;
+ u32 reg, temp, i;
+
+ /* Configure CPU PLL, wait for warmup */
+ I915_WRITE(SPLL_CTL,
+ SPLL_PLL_ENABLE |
+ SPLL_PLL_FREQ_1350MHz |
+ SPLL_PLL_SCC);
+
+ /* Use SPLL to drive the output when in FDI mode */
+ I915_WRITE(PORT_CLK_SEL(PORT_E),
+ PORT_CLK_SEL_SPLL);
+ I915_WRITE(PIPE_CLK_SEL(pipe),
+ PIPE_CLK_SEL_PORT(PORT_E));
+
+ udelay(20);
+
+ /* Start the training iterating through available voltages and emphasis */
+ for (i=0; i < ARRAY_SIZE(hsw_ddi_buf_ctl_values); i++) {
+ /* Configure DP_TP_CTL with auto-training */
+ I915_WRITE(DP_TP_CTL(PORT_E),
+ DP_TP_CTL_FDI_AUTOTRAIN |
+ DP_TP_CTL_ENHANCED_FRAME_ENABLE |
+ DP_TP_CTL_LINK_TRAIN_PAT1 |
+ DP_TP_CTL_ENABLE);
+
+ /* Configure and enable DDI_BUF_CTL for DDI E with next voltage */
+ temp = I915_READ(DDI_BUF_CTL(PORT_E));
+ temp = (temp & ~DDI_BUF_EMP_MASK);
+ I915_WRITE(DDI_BUF_CTL(PORT_E),
+ temp |
+ DDI_BUF_CTL_ENABLE |
+ DDI_PORT_WIDTH_X2 |
+ hsw_ddi_buf_ctl_values[i]);
+
+ udelay(600);
+
+ /* Enable CPU FDI Receiver with auto-training */
+ reg = FDI_RX_CTL(pipe);
+ I915_WRITE(reg,
+ I915_READ(reg) |
+ FDI_LINK_TRAIN_AUTO |
+ FDI_RX_ENABLE |
+ FDI_LINK_TRAIN_PATTERN_1_CPT |
+ FDI_RX_ENHANCE_FRAME_ENABLE |
+ FDI_PORT_WIDTH_2X_LPT |
+ FDI_RX_PLL_ENABLE);
+ POSTING_READ(reg);
+ udelay(100);
+
+ temp = I915_READ(DP_TP_STATUS(PORT_E));
+ if (temp & DP_TP_STATUS_AUTOTRAIN_DONE) {
+ DRM_DEBUG_DRIVER("BUF_CTL training done on %d step\n", i);
+
+ /* Enable normal pixel sending for FDI */
+ I915_WRITE(DP_TP_CTL(PORT_E),
+ DP_TP_CTL_FDI_AUTOTRAIN |
+ DP_TP_CTL_LINK_TRAIN_NORMAL |
+ DP_TP_CTL_ENHANCED_FRAME_ENABLE |
+ DP_TP_CTL_ENABLE);
+
+ /* Enable PIPE_DDI_FUNC_CTL for the pipe to work in FDI mode */
+ temp = I915_READ(DDI_FUNC_CTL(pipe));
+ temp &= ~PIPE_DDI_PORT_MASK;
+ temp |= PIPE_DDI_SELECT_PORT(PORT_E) |
+ PIPE_DDI_MODE_SELECT_FDI |
+ PIPE_DDI_FUNC_ENABLE |
+ PIPE_DDI_PORT_WIDTH_X2;
+ I915_WRITE(DDI_FUNC_CTL(pipe),
+ temp);
+ break;
+ } else {
+ DRM_ERROR("Error training BUF_CTL %d\n", i);
+
+ /* Disable DP_TP_CTL and FDI_RX_CTL) and retry */
+ I915_WRITE(DP_TP_CTL(PORT_E),
+ I915_READ(DP_TP_CTL(PORT_E)) &
+ ~DP_TP_CTL_ENABLE);
+ I915_WRITE(FDI_RX_CTL(pipe),
+ I915_READ(FDI_RX_CTL(pipe)) &
+ ~FDI_RX_PLL_ENABLE);
+ continue;
+ }
+ }
+
+ DRM_DEBUG_KMS("FDI train done.\n");
+}
+
+/* For DDI connections, it is possible to support different outputs over the
+ * same DDI port, such as HDMI or DP or even VGA via FDI. So we don't know by
+ * the time the output is detected what exactly is on the other end of it. This
+ * function aims at providing support for this detection and proper output
+ * configuration.
+ */
+void intel_ddi_init(struct drm_device *dev, enum port port)
+{
+ /* For now, we don't do any proper output detection and assume that we
+ * handle HDMI only */
+
+ switch(port){
+ case PORT_A:
+ /* We don't handle eDP and DP yet */
+ DRM_DEBUG_DRIVER("Found digital output on DDI port A\n");
+ break;
+ /* Assume that the ports B, C and D are working in HDMI mode for now */
+ case PORT_B:
+ case PORT_C:
+ case PORT_D:
+ intel_hdmi_init(dev, DDI_BUF_CTL(port));
+ break;
+ default:
+ DRM_DEBUG_DRIVER("No handlers defined for port %d, skipping DDI initialization\n",
+ port);
+ break;
+ }
+}
+
+/* WRPLL clock dividers */
+struct wrpll_tmds_clock {
+ u32 clock;
+ u16 p; /* Post divider */
+ u16 n2; /* Feedback divider */
+ u16 r2; /* Reference divider */
+};
+
+/* Table of matching values for WRPLL clocks programming for each frequency */
+static const struct wrpll_tmds_clock wrpll_tmds_clock_table[] = {
+ {19750, 38, 25, 18},
+ {20000, 48, 32, 18},
+ {21000, 36, 21, 15},
+ {21912, 42, 29, 17},
+ {22000, 36, 22, 15},
+ {23000, 36, 23, 15},
+ {23500, 40, 40, 23},
+ {23750, 26, 16, 14},
+ {23750, 26, 16, 14},
+ {24000, 36, 24, 15},
+ {25000, 36, 25, 15},
+ {25175, 26, 40, 33},
+ {25200, 30, 21, 15},
+ {26000, 36, 26, 15},
+ {27000, 30, 21, 14},
+ {27027, 18, 100, 111},
+ {27500, 30, 29, 19},
+ {28000, 34, 30, 17},
+ {28320, 26, 30, 22},
+ {28322, 32, 42, 25},
+ {28750, 24, 23, 18},
+ {29000, 30, 29, 18},
+ {29750, 32, 30, 17},
+ {30000, 30, 25, 15},
+ {30750, 30, 41, 24},
+ {31000, 30, 31, 18},
+ {31500, 30, 28, 16},
+ {32000, 30, 32, 18},
+ {32500, 28, 32, 19},
+ {33000, 24, 22, 15},
+ {34000, 28, 30, 17},
+ {35000, 26, 32, 19},
+ {35500, 24, 30, 19},
+ {36000, 26, 26, 15},
+ {36750, 26, 46, 26},
+ {37000, 24, 23, 14},
+ {37762, 22, 40, 26},
+ {37800, 20, 21, 15},
+ {38000, 24, 27, 16},
+ {38250, 24, 34, 20},
+ {39000, 24, 26, 15},
+ {40000, 24, 32, 18},
+ {40500, 20, 21, 14},
+ {40541, 22, 147, 89},
+ {40750, 18, 19, 14},
+ {41000, 16, 17, 14},
+ {41500, 22, 44, 26},
+ {41540, 22, 44, 26},
+ {42000, 18, 21, 15},
+ {42500, 22, 45, 26},
+ {43000, 20, 43, 27},
+ {43163, 20, 24, 15},
+ {44000, 18, 22, 15},
+ {44900, 20, 108, 65},
+ {45000, 20, 25, 15},
+ {45250, 20, 52, 31},
+ {46000, 18, 23, 15},
+ {46750, 20, 45, 26},
+ {47000, 20, 40, 23},
+ {48000, 18, 24, 15},
+ {49000, 18, 49, 30},
+ {49500, 16, 22, 15},
+ {50000, 18, 25, 15},
+ {50500, 18, 32, 19},
+ {51000, 18, 34, 20},
+ {52000, 18, 26, 15},
+ {52406, 14, 34, 25},
+ {53000, 16, 22, 14},
+ {54000, 16, 24, 15},
+ {54054, 16, 173, 108},
+ {54500, 14, 24, 17},
+ {55000, 12, 22, 18},
+ {56000, 14, 45, 31},
+ {56250, 16, 25, 15},
+ {56750, 14, 25, 17},
+ {57000, 16, 27, 16},
+ {58000, 16, 43, 25},
+ {58250, 16, 38, 22},
+ {58750, 16, 40, 23},
+ {59000, 14, 26, 17},
+ {59341, 14, 40, 26},
+ {59400, 16, 44, 25},
+ {60000, 16, 32, 18},
+ {60500, 12, 39, 29},
+ {61000, 14, 49, 31},
+ {62000, 14, 37, 23},
+ {62250, 14, 42, 26},
+ {63000, 12, 21, 15},
+ {63500, 14, 28, 17},
+ {64000, 12, 27, 19},
+ {65000, 14, 32, 19},
+ {65250, 12, 29, 20},
+ {65500, 12, 32, 22},
+ {66000, 12, 22, 15},
+ {66667, 14, 38, 22},
+ {66750, 10, 21, 17},
+ {67000, 14, 33, 19},
+ {67750, 14, 58, 33},
+ {68000, 14, 30, 17},
+ {68179, 14, 46, 26},
+ {68250, 14, 46, 26},
+ {69000, 12, 23, 15},
+ {70000, 12, 28, 18},
+ {71000, 12, 30, 19},
+ {72000, 12, 24, 15},
+ {73000, 10, 23, 17},
+ {74000, 12, 23, 14},
+ {74176, 8, 100, 91},
+ {74250, 10, 22, 16},
+ {74481, 12, 43, 26},
+ {74500, 10, 29, 21},
+ {75000, 12, 25, 15},
+ {75250, 10, 39, 28},
+ {76000, 12, 27, 16},
+ {77000, 12, 53, 31},
+ {78000, 12, 26, 15},
+ {78750, 12, 28, 16},
+ {79000, 10, 38, 26},
+ {79500, 10, 28, 19},
+ {80000, 12, 32, 18},
+ {81000, 10, 21, 14},
+ {81081, 6, 100, 111},
+ {81624, 8, 29, 24},
+ {82000, 8, 17, 14},
+ {83000, 10, 40, 26},
+ {83950, 10, 28, 18},
+ {84000, 10, 28, 18},
+ {84750, 6, 16, 17},
+ {85000, 6, 17, 18},
+ {85250, 10, 30, 19},
+ {85750, 10, 27, 17},
+ {86000, 10, 43, 27},
+ {87000, 10, 29, 18},
+ {88000, 10, 44, 27},
+ {88500, 10, 41, 25},
+ {89000, 10, 28, 17},
+ {89012, 6, 90, 91},
+ {89100, 10, 33, 20},
+ {90000, 10, 25, 15},
+ {91000, 10, 32, 19},
+ {92000, 10, 46, 27},
+ {93000, 10, 31, 18},
+ {94000, 10, 40, 23},
+ {94500, 10, 28, 16},
+ {95000, 10, 44, 25},
+ {95654, 10, 39, 22},
+ {95750, 10, 39, 22},
+ {96000, 10, 32, 18},
+ {97000, 8, 23, 16},
+ {97750, 8, 42, 29},
+ {98000, 8, 45, 31},
+ {99000, 8, 22, 15},
+ {99750, 8, 34, 23},
+ {100000, 6, 20, 18},
+ {100500, 6, 19, 17},
+ {101000, 6, 37, 33},
+ {101250, 8, 21, 14},
+ {102000, 6, 17, 15},
+ {102250, 6, 25, 22},
+ {103000, 8, 29, 19},
+ {104000, 8, 37, 24},
+ {105000, 8, 28, 18},
+ {106000, 8, 22, 14},
+ {107000, 8, 46, 29},
+ {107214, 8, 27, 17},
+ {108000, 8, 24, 15},
+ {108108, 8, 173, 108},
+ {109000, 6, 23, 19},
+ {109000, 6, 23, 19},
+ {110000, 6, 22, 18},
+ {110013, 6, 22, 18},
+ {110250, 8, 49, 30},
+ {110500, 8, 36, 22},
+ {111000, 8, 23, 14},
+ {111264, 8, 150, 91},
+ {111375, 8, 33, 20},
+ {112000, 8, 63, 38},
+ {112500, 8, 25, 15},
+ {113100, 8, 57, 34},
+ {113309, 8, 42, 25},
+ {114000, 8, 27, 16},
+ {115000, 6, 23, 18},
+ {116000, 8, 43, 25},
+ {117000, 8, 26, 15},
+ {117500, 8, 40, 23},
+ {118000, 6, 38, 29},
+ {119000, 8, 30, 17},
+ {119500, 8, 46, 26},
+ {119651, 8, 39, 22},
+ {120000, 8, 32, 18},
+ {121000, 6, 39, 29},
+ {121250, 6, 31, 23},
+ {121750, 6, 23, 17},
+ {122000, 6, 42, 31},
+ {122614, 6, 30, 22},
+ {123000, 6, 41, 30},
+ {123379, 6, 37, 27},
+ {124000, 6, 51, 37},
+ {125000, 6, 25, 18},
+ {125250, 4, 13, 14},
+ {125750, 4, 27, 29},
+ {126000, 6, 21, 15},
+ {127000, 6, 24, 17},
+ {127250, 6, 41, 29},
+ {128000, 6, 27, 19},
+ {129000, 6, 43, 30},
+ {129859, 4, 25, 26},
+ {130000, 6, 26, 18},
+ {130250, 6, 42, 29},
+ {131000, 6, 32, 22},
+ {131500, 6, 38, 26},
+ {131850, 6, 41, 28},
+ {132000, 6, 22, 15},
+ {132750, 6, 28, 19},
+ {133000, 6, 34, 23},
+ {133330, 6, 37, 25},
+ {134000, 6, 61, 41},
+ {135000, 6, 21, 14},
+ {135250, 6, 167, 111},
+ {136000, 6, 62, 41},
+ {137000, 6, 35, 23},
+ {138000, 6, 23, 15},
+ {138500, 6, 40, 26},
+ {138750, 6, 37, 24},
+ {139000, 6, 34, 22},
+ {139050, 6, 34, 22},
+ {139054, 6, 34, 22},
+ {140000, 6, 28, 18},
+ {141000, 6, 36, 23},
+ {141500, 6, 22, 14},
+ {142000, 6, 30, 19},
+ {143000, 6, 27, 17},
+ {143472, 4, 17, 16},
+ {144000, 6, 24, 15},
+ {145000, 6, 29, 18},
+ {146000, 6, 47, 29},
+ {146250, 6, 26, 16},
+ {147000, 6, 49, 30},
+ {147891, 6, 23, 14},
+ {148000, 6, 23, 14},
+ {148250, 6, 28, 17},
+ {148352, 4, 100, 91},
+ {148500, 6, 33, 20},
+ {149000, 6, 48, 29},
+ {150000, 6, 25, 15},
+ {151000, 4, 19, 17},
+ {152000, 6, 27, 16},
+ {152280, 6, 44, 26},
+ {153000, 6, 34, 20},
+ {154000, 6, 53, 31},
+ {155000, 6, 31, 18},
+ {155250, 6, 50, 29},
+ {155750, 6, 45, 26},
+ {156000, 6, 26, 15},
+ {157000, 6, 61, 35},
+ {157500, 6, 28, 16},
+ {158000, 6, 65, 37},
+ {158250, 6, 44, 25},
+ {159000, 6, 53, 30},
+ {159500, 6, 39, 22},
+ {160000, 6, 32, 18},
+ {161000, 4, 31, 26},
+ {162000, 4, 18, 15},
+ {162162, 4, 131, 109},
+ {162500, 4, 53, 44},
+ {163000, 4, 29, 24},
+ {164000, 4, 17, 14},
+ {165000, 4, 22, 18},
+ {166000, 4, 32, 26},
+ {167000, 4, 26, 21},
+ {168000, 4, 46, 37},
+ {169000, 4, 104, 83},
+ {169128, 4, 64, 51},
+ {169500, 4, 39, 31},
+ {170000, 4, 34, 27},
+ {171000, 4, 19, 15},
+ {172000, 4, 51, 40},
+ {172750, 4, 32, 25},
+ {172800, 4, 32, 25},
+ {173000, 4, 41, 32},
+ {174000, 4, 49, 38},
+ {174787, 4, 22, 17},
+ {175000, 4, 35, 27},
+ {176000, 4, 30, 23},
+ {177000, 4, 38, 29},
+ {178000, 4, 29, 22},
+ {178500, 4, 37, 28},
+ {179000, 4, 53, 40},
+ {179500, 4, 73, 55},
+ {180000, 4, 20, 15},
+ {181000, 4, 55, 41},
+ {182000, 4, 31, 23},
+ {183000, 4, 42, 31},
+ {184000, 4, 30, 22},
+ {184750, 4, 26, 19},
+ {185000, 4, 37, 27},
+ {186000, 4, 51, 37},
+ {187000, 4, 36, 26},
+ {188000, 4, 32, 23},
+ {189000, 4, 21, 15},
+ {190000, 4, 38, 27},
+ {190960, 4, 41, 29},
+ {191000, 4, 41, 29},
+ {192000, 4, 27, 19},
+ {192250, 4, 37, 26},
+ {193000, 4, 20, 14},
+ {193250, 4, 53, 37},
+ {194000, 4, 23, 16},
+ {194208, 4, 23, 16},
+ {195000, 4, 26, 18},
+ {196000, 4, 45, 31},
+ {197000, 4, 35, 24},
+ {197750, 4, 41, 28},
+ {198000, 4, 22, 15},
+ {198500, 4, 25, 17},
+ {199000, 4, 28, 19},
+ {200000, 4, 37, 25},
+ {201000, 4, 61, 41},
+ {202000, 4, 112, 75},
+ {202500, 4, 21, 14},
+ {203000, 4, 146, 97},
+ {204000, 4, 62, 41},
+ {204750, 4, 44, 29},
+ {205000, 4, 38, 25},
+ {206000, 4, 29, 19},
+ {207000, 4, 23, 15},
+ {207500, 4, 40, 26},
+ {208000, 4, 37, 24},
+ {208900, 4, 48, 31},
+ {209000, 4, 48, 31},
+ {209250, 4, 31, 20},
+ {210000, 4, 28, 18},
+ {211000, 4, 25, 16},
+ {212000, 4, 22, 14},
+ {213000, 4, 30, 19},
+ {213750, 4, 38, 24},
+ {214000, 4, 46, 29},
+ {214750, 4, 35, 22},
+ {215000, 4, 43, 27},
+ {216000, 4, 24, 15},
+ {217000, 4, 37, 23},
+ {218000, 4, 42, 26},
+ {218250, 4, 42, 26},
+ {218750, 4, 34, 21},
+ {219000, 4, 47, 29},
+ {219000, 4, 47, 29},
+ {220000, 4, 44, 27},
+ {220640, 4, 49, 30},
+ {220750, 4, 36, 22},
+ {221000, 4, 36, 22},
+ {222000, 4, 23, 14},
+ {222525, 4, 28, 17},
+ {222750, 4, 33, 20},
+ {227000, 4, 37, 22},
+ {230250, 4, 29, 17},
+ {233500, 4, 38, 22},
+ {235000, 4, 40, 23},
+ {238000, 4, 30, 17},
+ {241500, 2, 17, 19},
+ {245250, 2, 20, 22},
+ {247750, 2, 22, 24},
+ {253250, 2, 15, 16},
+ {256250, 2, 18, 19},
+ {262500, 2, 31, 32},
+ {267250, 2, 66, 67},
+ {268500, 2, 94, 95},
+ {270000, 2, 14, 14},
+ {272500, 2, 77, 76},
+ {273750, 2, 57, 56},
+ {280750, 2, 24, 23},
+ {281250, 2, 23, 22},
+ {286000, 2, 17, 16},
+ {291750, 2, 26, 24},
+ {296703, 2, 56, 51},
+ {297000, 2, 22, 20},
+ {298000, 2, 21, 19},
+};
+
+void intel_ddi_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct drm_device *dev = encoder->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc = encoder->crtc;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+ int port = intel_hdmi->ddi_port;
+ int pipe = intel_crtc->pipe;
+ int p, n2, r2, valid=0;
+ u32 temp, i;
+
+ /* On Haswell, we need to enable the clocks and prepare DDI function to
+ * work in HDMI mode for this pipe.
+ */
+ DRM_DEBUG_KMS("Preparing HDMI DDI mode for Haswell on port %c, pipe %c\n", port_name(port), pipe_name(pipe));
+
+ for (i=0; i < ARRAY_SIZE(wrpll_tmds_clock_table); i++) {
+ if (crtc->mode.clock == wrpll_tmds_clock_table[i].clock) {
+ p = wrpll_tmds_clock_table[i].p;
+ n2 = wrpll_tmds_clock_table[i].n2;
+ r2 = wrpll_tmds_clock_table[i].r2;
+
+ DRM_DEBUG_KMS("WR PLL clock: found settings for %dKHz refresh rate: p=%d, n2=%d, r2=%d\n",
+ crtc->mode.clock,
+ p, n2, r2);
+
+ valid = 1;
+ break;
+ }
+ }
+
+ if (!valid) {
+ DRM_ERROR("Unable to find WR PLL clock settings for %dKHz refresh rate\n",
+ crtc->mode.clock);
+ return;
+ }
+
+ /* Enable LCPLL if disabled */
+ temp = I915_READ(LCPLL_CTL);
+ if (temp & LCPLL_PLL_DISABLE)
+ I915_WRITE(LCPLL_CTL,
+ temp & ~LCPLL_PLL_DISABLE);
+
+ /* Configure WR PLL 1, program the correct divider values for
+ * the desired frequency and wait for warmup */
+ I915_WRITE(WRPLL_CTL1,
+ WRPLL_PLL_ENABLE |
+ WRPLL_PLL_SELECT_LCPLL_2700 |
+ WRPLL_DIVIDER_REFERENCE(r2) |
+ WRPLL_DIVIDER_FEEDBACK(n2) |
+ WRPLL_DIVIDER_POST(p));
+
+ udelay(20);
+
+ /* Use WRPLL1 clock to drive the output to the port, and tell the pipe to use
+ * this port for connection.
+ */
+ I915_WRITE(PORT_CLK_SEL(port),
+ PORT_CLK_SEL_WRPLL1);
+ I915_WRITE(PIPE_CLK_SEL(pipe),
+ PIPE_CLK_SEL_PORT(port));
+
+ udelay(20);
+
+ if (intel_hdmi->has_audio) {
+ /* Proper support for digital audio needs a new logic and a new set
+ * of registers, so we leave it for future patch bombing.
+ */
+ DRM_DEBUG_DRIVER("HDMI audio on pipe %c not yet supported on DDI\n",
+ pipe_name(intel_crtc->pipe));
+ }
+
+ /* Enable PIPE_DDI_FUNC_CTL for the pipe to work in HDMI mode */
+ temp = I915_READ(DDI_FUNC_CTL(pipe));
+ temp &= ~PIPE_DDI_PORT_MASK;
+ temp &= ~PIPE_DDI_BPC_12;
+ temp |= PIPE_DDI_SELECT_PORT(port) |
+ PIPE_DDI_MODE_SELECT_HDMI |
+ ((intel_crtc->bpp > 24) ?
+ PIPE_DDI_BPC_12 :
+ PIPE_DDI_BPC_8) |
+ PIPE_DDI_FUNC_ENABLE;
+
+ I915_WRITE(DDI_FUNC_CTL(pipe), temp);
+
+ intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
+ intel_hdmi_set_spd_infoframe(encoder);
+}
+
+void intel_ddi_dpms(struct drm_encoder *encoder, int mode)
+{
+ struct drm_device *dev = encoder->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
+ int port = intel_hdmi->ddi_port;
+ u32 temp;
+
+ temp = I915_READ(DDI_BUF_CTL(port));
+
+ if (mode != DRM_MODE_DPMS_ON) {
+ temp &= ~DDI_BUF_CTL_ENABLE;
+ } else {
+ temp |= DDI_BUF_CTL_ENABLE;
+ }
+
+ /* Enable DDI_BUF_CTL. In HDMI/DVI mode, the port width,
+ * and swing/emphasis values are ignored so nothing special needs
+ * to be done besides enabling the port.
+ */
+ I915_WRITE(DDI_BUF_CTL(port),
+ temp);
+}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 1b1cf3b3ff51..ee61ad1e642b 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -24,7 +24,7 @@
* Eric Anholt <eric@anholt.net>
*/
-#include <linux/cpufreq.h>
+#include <linux/dmi.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/i2c.h>
@@ -44,7 +44,6 @@
#define HAS_eDP (intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))
bool intel_pipe_has_type(struct drm_crtc *crtc, int type);
-static void intel_update_watermarks(struct drm_device *dev);
static void intel_increase_pllclock(struct drm_crtc *crtc);
static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
@@ -360,6 +359,88 @@ static const intel_limit_t intel_limits_ironlake_display_port = {
.find_pll = intel_find_pll_ironlake_dp,
};
+u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg)
+{
+ unsigned long flags;
+ u32 val = 0;
+
+ spin_lock_irqsave(&dev_priv->dpio_lock, flags);
+ if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) {
+ DRM_ERROR("DPIO idle wait timed out\n");
+ goto out_unlock;
+ }
+
+ I915_WRITE(DPIO_REG, reg);
+ I915_WRITE(DPIO_PKT, DPIO_RID | DPIO_OP_READ | DPIO_PORTID |
+ DPIO_BYTE);
+ if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) {
+ DRM_ERROR("DPIO read wait timed out\n");
+ goto out_unlock;
+ }
+ val = I915_READ(DPIO_DATA);
+
+out_unlock:
+ spin_unlock_irqrestore(&dev_priv->dpio_lock, flags);
+ return val;
+}
+
+static void vlv_init_dpio(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ /* Reset the DPIO config */
+ I915_WRITE(DPIO_CTL, 0);
+ POSTING_READ(DPIO_CTL);
+ I915_WRITE(DPIO_CTL, 1);
+ POSTING_READ(DPIO_CTL);
+}
+
+static int intel_dual_link_lvds_callback(const struct dmi_system_id *id)
+{
+ DRM_INFO("Forcing lvds to dual link mode on %s\n", id->ident);
+ return 1;
+}
+
+static const struct dmi_system_id intel_dual_link_lvds[] = {
+ {
+ .callback = intel_dual_link_lvds_callback,
+ .ident = "Apple MacBook Pro (Core i5/i7 Series)",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro8,2"),
+ },
+ },
+ { } /* terminating entry */
+};
+
+static bool is_dual_link_lvds(struct drm_i915_private *dev_priv,
+ unsigned int reg)
+{
+ unsigned int val;
+
+ /* use the module option value if specified */
+ if (i915_lvds_channel_mode > 0)
+ return i915_lvds_channel_mode == 2;
+
+ if (dmi_check_system(intel_dual_link_lvds))
+ return true;
+
+ if (dev_priv->lvds_val)
+ val = dev_priv->lvds_val;
+ else {
+ /* BIOS should set the proper LVDS register value at boot, but
+ * in reality, it doesn't set the value when the lid is closed;
+ * we need to check "the value to be set" in VBT when LVDS
+ * register is uninitialized.
+ */
+ val = I915_READ(reg);
+ if (!(val & ~LVDS_DETECTED))
+ val = dev_priv->bios_lvds_val;
+ dev_priv->lvds_val = val;
+ }
+ return (val & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP;
+}
+
static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc,
int refclk)
{
@@ -368,8 +449,7 @@ static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc,
const intel_limit_t *limit;
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
- if ((I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) ==
- LVDS_CLKB_POWER_UP) {
+ if (is_dual_link_lvds(dev_priv, PCH_LVDS)) {
/* LVDS dual channel */
if (refclk == 100000)
limit = &intel_limits_ironlake_dual_lvds_100m;
@@ -397,8 +477,7 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc)
const intel_limit_t *limit;
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
- if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
- LVDS_CLKB_POWER_UP)
+ if (is_dual_link_lvds(dev_priv, LVDS))
/* LVDS with dual channel */
limit = &intel_limits_g4x_dual_channel_lvds;
else
@@ -536,8 +615,7 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
* reliably set up different single/dual channel state, if we
* even can.
*/
- if ((I915_READ(LVDS) & LVDS_CLKB_POWER_MASK) ==
- LVDS_CLKB_POWER_UP)
+ if (is_dual_link_lvds(dev_priv, LVDS))
clock.p2 = limit->p2.p2_fast;
else
clock.p2 = limit->p2.p2_slow;
@@ -706,6 +784,17 @@ intel_find_pll_g4x_dp(const intel_limit_t *limit, struct drm_crtc *crtc,
return true;
}
+static void ironlake_wait_for_vblank(struct drm_device *dev, int pipe)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 frame, frame_reg = PIPEFRAME(pipe);
+
+ frame = I915_READ(frame_reg);
+
+ if (wait_for(I915_READ_NOTRACE(frame_reg) != frame, 50))
+ DRM_DEBUG_KMS("vblank wait timed out\n");
+}
+
/**
* intel_wait_for_vblank - wait for vblank on a given pipe
* @dev: drm device
@@ -719,6 +808,11 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe)
struct drm_i915_private *dev_priv = dev->dev_private;
int pipestat_reg = PIPESTAT(pipe);
+ if (INTEL_INFO(dev)->gen >= 5) {
+ ironlake_wait_for_vblank(dev, pipe);
+ return;
+ }
+
/* Clear existing vblank status. Note this will clear any other
* sticky status fields as well.
*
@@ -771,15 +865,20 @@ void intel_wait_for_pipe_off(struct drm_device *dev, int pipe)
100))
DRM_DEBUG_KMS("pipe_off wait timed out\n");
} else {
- u32 last_line;
+ u32 last_line, line_mask;
int reg = PIPEDSL(pipe);
unsigned long timeout = jiffies + msecs_to_jiffies(100);
+ if (IS_GEN2(dev))
+ line_mask = DSL_LINEMASK_GEN2;
+ else
+ line_mask = DSL_LINEMASK_GEN3;
+
/* Wait for the display line to settle */
do {
- last_line = I915_READ(reg) & DSL_LINEMASK;
+ last_line = I915_READ(reg) & line_mask;
mdelay(5);
- } while (((I915_READ(reg) & DSL_LINEMASK) != last_line) &&
+ } while (((I915_READ(reg) & line_mask) != last_line) &&
time_after(timeout, jiffies));
if (time_after(jiffies, timeout))
DRM_DEBUG_KMS("pipe_off wait timed out\n");
@@ -811,26 +910,33 @@ static void assert_pll(struct drm_i915_private *dev_priv,
/* For ILK+ */
static void assert_pch_pll(struct drm_i915_private *dev_priv,
- enum pipe pipe, bool state)
+ struct intel_crtc *intel_crtc, bool state)
{
int reg;
u32 val;
bool cur_state;
+ if (HAS_PCH_LPT(dev_priv->dev)) {
+ DRM_DEBUG_DRIVER("LPT detected: skipping PCH PLL test\n");
+ return;
+ }
+
+ if (!intel_crtc->pch_pll) {
+ WARN(1, "asserting PCH PLL enabled with no PLL\n");
+ return;
+ }
+
if (HAS_PCH_CPT(dev_priv->dev)) {
u32 pch_dpll;
pch_dpll = I915_READ(PCH_DPLL_SEL);
/* Make sure the selected PLL is enabled to the transcoder */
- WARN(!((pch_dpll >> (4 * pipe)) & 8),
- "transcoder %d PLL not enabled\n", pipe);
-
- /* Convert the transcoder pipe number to a pll pipe number */
- pipe = (pch_dpll >> (4 * pipe)) & 1;
+ WARN(!((pch_dpll >> (4 * intel_crtc->pipe)) & 8),
+ "transcoder %d PLL not enabled\n", intel_crtc->pipe);
}
- reg = PCH_DPLL(pipe);
+ reg = intel_crtc->pch_pll->pll_reg;
val = I915_READ(reg);
cur_state = !!(val & DPLL_VCO_ENABLE);
WARN(cur_state != state,
@@ -847,9 +953,16 @@ static void assert_fdi_tx(struct drm_i915_private *dev_priv,
u32 val;
bool cur_state;
- reg = FDI_TX_CTL(pipe);
- val = I915_READ(reg);
- cur_state = !!(val & FDI_TX_ENABLE);
+ if (IS_HASWELL(dev_priv->dev)) {
+ /* On Haswell, DDI is used instead of FDI_TX_CTL */
+ reg = DDI_FUNC_CTL(pipe);
+ val = I915_READ(reg);
+ cur_state = !!(val & PIPE_DDI_FUNC_ENABLE);
+ } else {
+ reg = FDI_TX_CTL(pipe);
+ val = I915_READ(reg);
+ cur_state = !!(val & FDI_TX_ENABLE);
+ }
WARN(cur_state != state,
"FDI TX state assertion failure (expected %s, current %s)\n",
state_string(state), state_string(cur_state));
@@ -864,9 +977,14 @@ static void assert_fdi_rx(struct drm_i915_private *dev_priv,
u32 val;
bool cur_state;
- reg = FDI_RX_CTL(pipe);
- val = I915_READ(reg);
- cur_state = !!(val & FDI_RX_ENABLE);
+ if (IS_HASWELL(dev_priv->dev) && pipe > 0) {
+ DRM_ERROR("Attempting to enable FDI_RX on Haswell pipe > 0\n");
+ return;
+ } else {
+ reg = FDI_RX_CTL(pipe);
+ val = I915_READ(reg);
+ cur_state = !!(val & FDI_RX_ENABLE);
+ }
WARN(cur_state != state,
"FDI RX state assertion failure (expected %s, current %s)\n",
state_string(state), state_string(cur_state));
@@ -884,6 +1002,10 @@ static void assert_fdi_tx_pll_enabled(struct drm_i915_private *dev_priv,
if (dev_priv->info->gen == 5)
return;
+ /* On Haswell, DDI ports are responsible for the FDI PLL setup */
+ if (IS_HASWELL(dev_priv->dev))
+ return;
+
reg = FDI_TX_CTL(pipe);
val = I915_READ(reg);
WARN(!(val & FDI_TX_PLL_ENABLE), "FDI TX PLL assertion failure, should be active but is disabled\n");
@@ -895,6 +1017,10 @@ static void assert_fdi_rx_pll_enabled(struct drm_i915_private *dev_priv,
int reg;
u32 val;
+ if (IS_HASWELL(dev_priv->dev) && pipe > 0) {
+ DRM_ERROR("Attempting to enable FDI on Haswell with pipe > 0\n");
+ return;
+ }
reg = FDI_RX_CTL(pipe);
val = I915_READ(reg);
WARN(!(val & FDI_RX_PLL_ENABLE), "FDI RX PLL assertion failure, should be active but is disabled\n");
@@ -1000,6 +1126,11 @@ static void assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
u32 val;
bool enabled;
+ if (HAS_PCH_LPT(dev_priv->dev)) {
+ DRM_DEBUG_DRIVER("LPT does not has PCH refclk, skipping check\n");
+ return;
+ }
+
val = I915_READ(PCH_DREF_CONTROL);
enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK |
DREF_SUPERSPREAD_SOURCE_MASK));
@@ -1198,6 +1329,69 @@ static void intel_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
POSTING_READ(reg);
}
+/* SBI access */
+static void
+intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev_priv->dpio_lock, flags);
+ if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_READY) == 0,
+ 100)) {
+ DRM_ERROR("timeout waiting for SBI to become ready\n");
+ goto out_unlock;
+ }
+
+ I915_WRITE(SBI_ADDR,
+ (reg << 16));
+ I915_WRITE(SBI_DATA,
+ value);
+ I915_WRITE(SBI_CTL_STAT,
+ SBI_BUSY |
+ SBI_CTL_OP_CRWR);
+
+ if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_READY | SBI_RESPONSE_SUCCESS)) == 0,
+ 100)) {
+ DRM_ERROR("timeout waiting for SBI to complete write transaction\n");
+ goto out_unlock;
+ }
+
+out_unlock:
+ spin_unlock_irqrestore(&dev_priv->dpio_lock, flags);
+}
+
+static u32
+intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg)
+{
+ unsigned long flags;
+ u32 value;
+
+ spin_lock_irqsave(&dev_priv->dpio_lock, flags);
+ if (wait_for((I915_READ(SBI_CTL_STAT) & SBI_READY) == 0,
+ 100)) {
+ DRM_ERROR("timeout waiting for SBI to become ready\n");
+ goto out_unlock;
+ }
+
+ I915_WRITE(SBI_ADDR,
+ (reg << 16));
+ I915_WRITE(SBI_CTL_STAT,
+ SBI_BUSY |
+ SBI_CTL_OP_CRRD);
+
+ if (wait_for((I915_READ(SBI_CTL_STAT) & (SBI_READY | SBI_RESPONSE_SUCCESS)) == 0,
+ 100)) {
+ DRM_ERROR("timeout waiting for SBI to complete read transaction\n");
+ goto out_unlock;
+ }
+
+ value = I915_READ(SBI_DATA);
+
+out_unlock:
+ spin_unlock_irqrestore(&dev_priv->dpio_lock, flags);
+ return value;
+}
+
/**
* intel_enable_pch_pll - enable PCH PLL
* @dev_priv: i915 private structure
@@ -1206,60 +1400,88 @@ static void intel_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
* The PCH PLL needs to be enabled before the PCH transcoder, since it
* drives the transcoder clock.
*/
-static void intel_enable_pch_pll(struct drm_i915_private *dev_priv,
- enum pipe pipe)
+static void intel_enable_pch_pll(struct intel_crtc *intel_crtc)
{
+ struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private;
+ struct intel_pch_pll *pll;
int reg;
u32 val;
- if (pipe > 1)
+ /* PCH PLLs only available on ILK, SNB and IVB */
+ BUG_ON(dev_priv->info->gen < 5);
+ pll = intel_crtc->pch_pll;
+ if (pll == NULL)
return;
- /* PCH only available on ILK+ */
- BUG_ON(dev_priv->info->gen < 5);
+ if (WARN_ON(pll->refcount == 0))
+ return;
+
+ DRM_DEBUG_KMS("enable PCH PLL %x (active %d, on? %d)for crtc %d\n",
+ pll->pll_reg, pll->active, pll->on,
+ intel_crtc->base.base.id);
/* PCH refclock must be enabled first */
assert_pch_refclk_enabled(dev_priv);
- reg = PCH_DPLL(pipe);
+ if (pll->active++ && pll->on) {
+ assert_pch_pll_enabled(dev_priv, intel_crtc);
+ return;
+ }
+
+ DRM_DEBUG_KMS("enabling PCH PLL %x\n", pll->pll_reg);
+
+ reg = pll->pll_reg;
val = I915_READ(reg);
val |= DPLL_VCO_ENABLE;
I915_WRITE(reg, val);
POSTING_READ(reg);
udelay(200);
+
+ pll->on = true;
}
-static void intel_disable_pch_pll(struct drm_i915_private *dev_priv,
- enum pipe pipe)
+static void intel_disable_pch_pll(struct intel_crtc *intel_crtc)
{
+ struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private;
+ struct intel_pch_pll *pll = intel_crtc->pch_pll;
int reg;
- u32 val, pll_mask = TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL,
- pll_sel = TRANSC_DPLL_ENABLE;
-
- if (pipe > 1)
- return;
+ u32 val;
/* PCH only available on ILK+ */
BUG_ON(dev_priv->info->gen < 5);
+ if (pll == NULL)
+ return;
- /* Make sure transcoder isn't still depending on us */
- assert_transcoder_disabled(dev_priv, pipe);
+ if (WARN_ON(pll->refcount == 0))
+ return;
- if (pipe == 0)
- pll_sel |= TRANSC_DPLLA_SEL;
- else if (pipe == 1)
- pll_sel |= TRANSC_DPLLB_SEL;
+ DRM_DEBUG_KMS("disable PCH PLL %x (active %d, on? %d) for crtc %d\n",
+ pll->pll_reg, pll->active, pll->on,
+ intel_crtc->base.base.id);
+ if (WARN_ON(pll->active == 0)) {
+ assert_pch_pll_disabled(dev_priv, intel_crtc);
+ return;
+ }
- if ((I915_READ(PCH_DPLL_SEL) & pll_mask) == pll_sel)
+ if (--pll->active) {
+ assert_pch_pll_enabled(dev_priv, intel_crtc);
return;
+ }
+
+ DRM_DEBUG_KMS("disabling PCH PLL %x\n", pll->pll_reg);
- reg = PCH_DPLL(pipe);
+ /* Make sure transcoder isn't still depending on us */
+ assert_transcoder_disabled(dev_priv, intel_crtc->pipe);
+
+ reg = pll->pll_reg;
val = I915_READ(reg);
val &= ~DPLL_VCO_ENABLE;
I915_WRITE(reg, val);
POSTING_READ(reg);
udelay(200);
+
+ pll->on = false;
}
static void intel_enable_transcoder(struct drm_i915_private *dev_priv,
@@ -1273,12 +1495,16 @@ static void intel_enable_transcoder(struct drm_i915_private *dev_priv,
BUG_ON(dev_priv->info->gen < 5);
/* Make sure PCH DPLL is enabled */
- assert_pch_pll_enabled(dev_priv, pipe);
+ assert_pch_pll_enabled(dev_priv, to_intel_crtc(crtc));
/* FDI must be feeding us bits for PCH ports */
assert_fdi_tx_enabled(dev_priv, pipe);
assert_fdi_rx_enabled(dev_priv, pipe);
+ if (IS_HASWELL(dev_priv->dev) && pipe > 0) {
+ DRM_ERROR("Attempting to enable transcoder on Haswell with pipe > 0\n");
+ return;
+ }
reg = TRANSCONF(pipe);
val = I915_READ(reg);
pipeconf_val = I915_READ(PIPECONF(pipe));
@@ -1415,7 +1641,7 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv,
* Plane regs are double buffered, going from enabled->disabled needs a
* trigger in order to latch. The display address reg provides this.
*/
-static void intel_flush_display_plane(struct drm_i915_private *dev_priv,
+void intel_flush_display_plane(struct drm_i915_private *dev_priv,
enum plane plane)
{
I915_WRITE(DSPADDR(plane), I915_READ(DSPADDR(plane)));
@@ -1526,490 +1752,6 @@ static void intel_disable_pch_ports(struct drm_i915_private *dev_priv,
disable_pch_hdmi(dev_priv, pipe, HDMID);
}
-static void i8xx_disable_fbc(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 fbc_ctl;
-
- /* Disable compression */
- fbc_ctl = I915_READ(FBC_CONTROL);
- if ((fbc_ctl & FBC_CTL_EN) == 0)
- return;
-
- fbc_ctl &= ~FBC_CTL_EN;
- I915_WRITE(FBC_CONTROL, fbc_ctl);
-
- /* Wait for compressing bit to clear */
- if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10)) {
- DRM_DEBUG_KMS("FBC idle timed out\n");
- return;
- }
-
- DRM_DEBUG_KMS("disabled FBC\n");
-}
-
-static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
-{
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_framebuffer *fb = crtc->fb;
- struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
- struct drm_i915_gem_object *obj = intel_fb->obj;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- int cfb_pitch;
- int plane, i;
- u32 fbc_ctl, fbc_ctl2;
-
- cfb_pitch = dev_priv->cfb_size / FBC_LL_SIZE;
- if (fb->pitches[0] < cfb_pitch)
- cfb_pitch = fb->pitches[0];
-
- /* FBC_CTL wants 64B units */
- cfb_pitch = (cfb_pitch / 64) - 1;
- plane = intel_crtc->plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB;
-
- /* Clear old tags */
- for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++)
- I915_WRITE(FBC_TAG + (i * 4), 0);
-
- /* Set it up... */
- fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE;
- fbc_ctl2 |= plane;
- I915_WRITE(FBC_CONTROL2, fbc_ctl2);
- I915_WRITE(FBC_FENCE_OFF, crtc->y);
-
- /* enable it... */
- fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC;
- if (IS_I945GM(dev))
- fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */
- fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
- fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT;
- fbc_ctl |= obj->fence_reg;
- I915_WRITE(FBC_CONTROL, fbc_ctl);
-
- DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %d, ",
- cfb_pitch, crtc->y, intel_crtc->plane);
-}
-
-static bool i8xx_fbc_enabled(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- return I915_READ(FBC_CONTROL) & FBC_CTL_EN;
-}
-
-static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
-{
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_framebuffer *fb = crtc->fb;
- struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
- struct drm_i915_gem_object *obj = intel_fb->obj;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
- unsigned long stall_watermark = 200;
- u32 dpfc_ctl;
-
- dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X;
- dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg;
- I915_WRITE(DPFC_CHICKEN, DPFC_HT_MODIFY);
-
- I915_WRITE(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
- (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
- (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
- I915_WRITE(DPFC_FENCE_YOFF, crtc->y);
-
- /* enable it... */
- I915_WRITE(DPFC_CONTROL, I915_READ(DPFC_CONTROL) | DPFC_CTL_EN);
-
- DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
-}
-
-static void g4x_disable_fbc(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 dpfc_ctl;
-
- /* Disable compression */
- dpfc_ctl = I915_READ(DPFC_CONTROL);
- if (dpfc_ctl & DPFC_CTL_EN) {
- dpfc_ctl &= ~DPFC_CTL_EN;
- I915_WRITE(DPFC_CONTROL, dpfc_ctl);
-
- DRM_DEBUG_KMS("disabled FBC\n");
- }
-}
-
-static bool g4x_fbc_enabled(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN;
-}
-
-static void sandybridge_blit_fbc_update(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 blt_ecoskpd;
-
- /* Make sure blitter notifies FBC of writes */
- gen6_gt_force_wake_get(dev_priv);
- blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD);
- blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY <<
- GEN6_BLITTER_LOCK_SHIFT;
- I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
- blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY;
- I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
- blt_ecoskpd &= ~(GEN6_BLITTER_FBC_NOTIFY <<
- GEN6_BLITTER_LOCK_SHIFT);
- I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
- POSTING_READ(GEN6_BLITTER_ECOSKPD);
- gen6_gt_force_wake_put(dev_priv);
-}
-
-static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
-{
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_framebuffer *fb = crtc->fb;
- struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
- struct drm_i915_gem_object *obj = intel_fb->obj;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
- unsigned long stall_watermark = 200;
- u32 dpfc_ctl;
-
- dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
- dpfc_ctl &= DPFC_RESERVED;
- dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X);
- /* Set persistent mode for front-buffer rendering, ala X. */
- dpfc_ctl |= DPFC_CTL_PERSISTENT_MODE;
- dpfc_ctl |= (DPFC_CTL_FENCE_EN | obj->fence_reg);
- I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY);
-
- I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
- (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
- (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
- I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y);
- I915_WRITE(ILK_FBC_RT_BASE, obj->gtt_offset | ILK_FBC_RT_VALID);
- /* enable it... */
- I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
-
- if (IS_GEN6(dev)) {
- I915_WRITE(SNB_DPFC_CTL_SA,
- SNB_CPU_FENCE_ENABLE | obj->fence_reg);
- I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
- sandybridge_blit_fbc_update(dev);
- }
-
- DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
-}
-
-static void ironlake_disable_fbc(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 dpfc_ctl;
-
- /* Disable compression */
- dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
- if (dpfc_ctl & DPFC_CTL_EN) {
- dpfc_ctl &= ~DPFC_CTL_EN;
- I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
-
- DRM_DEBUG_KMS("disabled FBC\n");
- }
-}
-
-static bool ironlake_fbc_enabled(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN;
-}
-
-bool intel_fbc_enabled(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- if (!dev_priv->display.fbc_enabled)
- return false;
-
- return dev_priv->display.fbc_enabled(dev);
-}
-
-static void intel_fbc_work_fn(struct work_struct *__work)
-{
- struct intel_fbc_work *work =
- container_of(to_delayed_work(__work),
- struct intel_fbc_work, work);
- struct drm_device *dev = work->crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- mutex_lock(&dev->struct_mutex);
- if (work == dev_priv->fbc_work) {
- /* Double check that we haven't switched fb without cancelling
- * the prior work.
- */
- if (work->crtc->fb == work->fb) {
- dev_priv->display.enable_fbc(work->crtc,
- work->interval);
-
- dev_priv->cfb_plane = to_intel_crtc(work->crtc)->plane;
- dev_priv->cfb_fb = work->crtc->fb->base.id;
- dev_priv->cfb_y = work->crtc->y;
- }
-
- dev_priv->fbc_work = NULL;
- }
- mutex_unlock(&dev->struct_mutex);
-
- kfree(work);
-}
-
-static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv)
-{
- if (dev_priv->fbc_work == NULL)
- return;
-
- DRM_DEBUG_KMS("cancelling pending FBC enable\n");
-
- /* Synchronisation is provided by struct_mutex and checking of
- * dev_priv->fbc_work, so we can perform the cancellation
- * entirely asynchronously.
- */
- if (cancel_delayed_work(&dev_priv->fbc_work->work))
- /* tasklet was killed before being run, clean up */
- kfree(dev_priv->fbc_work);
-
- /* Mark the work as no longer wanted so that if it does
- * wake-up (because the work was already running and waiting
- * for our mutex), it will discover that is no longer
- * necessary to run.
- */
- dev_priv->fbc_work = NULL;
-}
-
-static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
-{
- struct intel_fbc_work *work;
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- if (!dev_priv->display.enable_fbc)
- return;
-
- intel_cancel_fbc_work(dev_priv);
-
- work = kzalloc(sizeof *work, GFP_KERNEL);
- if (work == NULL) {
- dev_priv->display.enable_fbc(crtc, interval);
- return;
- }
-
- work->crtc = crtc;
- work->fb = crtc->fb;
- work->interval = interval;
- INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn);
-
- dev_priv->fbc_work = work;
-
- DRM_DEBUG_KMS("scheduling delayed FBC enable\n");
-
- /* Delay the actual enabling to let pageflipping cease and the
- * display to settle before starting the compression. Note that
- * this delay also serves a second purpose: it allows for a
- * vblank to pass after disabling the FBC before we attempt
- * to modify the control registers.
- *
- * A more complicated solution would involve tracking vblanks
- * following the termination of the page-flipping sequence
- * and indeed performing the enable as a co-routine and not
- * waiting synchronously upon the vblank.
- */
- schedule_delayed_work(&work->work, msecs_to_jiffies(50));
-}
-
-void intel_disable_fbc(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- intel_cancel_fbc_work(dev_priv);
-
- if (!dev_priv->display.disable_fbc)
- return;
-
- dev_priv->display.disable_fbc(dev);
- dev_priv->cfb_plane = -1;
-}
-
-/**
- * intel_update_fbc - enable/disable FBC as needed
- * @dev: the drm_device
- *
- * Set up the framebuffer compression hardware at mode set time. We
- * enable it if possible:
- * - plane A only (on pre-965)
- * - no pixel mulitply/line duplication
- * - no alpha buffer discard
- * - no dual wide
- * - framebuffer <= 2048 in width, 1536 in height
- *
- * We can't assume that any compression will take place (worst case),
- * so the compressed buffer has to be the same size as the uncompressed
- * one. It also must reside (along with the line length buffer) in
- * stolen memory.
- *
- * We need to enable/disable FBC on a global basis.
- */
-static void intel_update_fbc(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_crtc *crtc = NULL, *tmp_crtc;
- struct intel_crtc *intel_crtc;
- struct drm_framebuffer *fb;
- struct intel_framebuffer *intel_fb;
- struct drm_i915_gem_object *obj;
- int enable_fbc;
-
- DRM_DEBUG_KMS("\n");
-
- if (!i915_powersave)
- return;
-
- if (!I915_HAS_FBC(dev))
- return;
-
- /*
- * If FBC is already on, we just have to verify that we can
- * keep it that way...
- * Need to disable if:
- * - more than one pipe is active
- * - changing FBC params (stride, fence, mode)
- * - new fb is too large to fit in compressed buffer
- * - going to an unsupported config (interlace, pixel multiply, etc.)
- */
- list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) {
- if (tmp_crtc->enabled && tmp_crtc->fb) {
- if (crtc) {
- DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
- dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES;
- goto out_disable;
- }
- crtc = tmp_crtc;
- }
- }
-
- if (!crtc || crtc->fb == NULL) {
- DRM_DEBUG_KMS("no output, disabling\n");
- dev_priv->no_fbc_reason = FBC_NO_OUTPUT;
- goto out_disable;
- }
-
- intel_crtc = to_intel_crtc(crtc);
- fb = crtc->fb;
- intel_fb = to_intel_framebuffer(fb);
- obj = intel_fb->obj;
-
- enable_fbc = i915_enable_fbc;
- if (enable_fbc < 0) {
- DRM_DEBUG_KMS("fbc set to per-chip default\n");
- enable_fbc = 1;
- if (INTEL_INFO(dev)->gen <= 6)
- enable_fbc = 0;
- }
- if (!enable_fbc) {
- DRM_DEBUG_KMS("fbc disabled per module param\n");
- dev_priv->no_fbc_reason = FBC_MODULE_PARAM;
- goto out_disable;
- }
- if (intel_fb->obj->base.size > dev_priv->cfb_size) {
- DRM_DEBUG_KMS("framebuffer too large, disabling "
- "compression\n");
- dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
- goto out_disable;
- }
- if ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) ||
- (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) {
- DRM_DEBUG_KMS("mode incompatible with compression, "
- "disabling\n");
- dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE;
- goto out_disable;
- }
- if ((crtc->mode.hdisplay > 2048) ||
- (crtc->mode.vdisplay > 1536)) {
- DRM_DEBUG_KMS("mode too large for compression, disabling\n");
- dev_priv->no_fbc_reason = FBC_MODE_TOO_LARGE;
- goto out_disable;
- }
- if ((IS_I915GM(dev) || IS_I945GM(dev)) && intel_crtc->plane != 0) {
- DRM_DEBUG_KMS("plane not 0, disabling compression\n");
- dev_priv->no_fbc_reason = FBC_BAD_PLANE;
- goto out_disable;
- }
-
- /* The use of a CPU fence is mandatory in order to detect writes
- * by the CPU to the scanout and trigger updates to the FBC.
- */
- if (obj->tiling_mode != I915_TILING_X ||
- obj->fence_reg == I915_FENCE_REG_NONE) {
- DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n");
- dev_priv->no_fbc_reason = FBC_NOT_TILED;
- goto out_disable;
- }
-
- /* If the kernel debugger is active, always disable compression */
- if (in_dbg_master())
- goto out_disable;
-
- /* If the scanout has not changed, don't modify the FBC settings.
- * Note that we make the fundamental assumption that the fb->obj
- * cannot be unpinned (and have its GTT offset and fence revoked)
- * without first being decoupled from the scanout and FBC disabled.
- */
- if (dev_priv->cfb_plane == intel_crtc->plane &&
- dev_priv->cfb_fb == fb->base.id &&
- dev_priv->cfb_y == crtc->y)
- return;
-
- if (intel_fbc_enabled(dev)) {
- /* We update FBC along two paths, after changing fb/crtc
- * configuration (modeswitching) and after page-flipping
- * finishes. For the latter, we know that not only did
- * we disable the FBC at the start of the page-flip
- * sequence, but also more than one vblank has passed.
- *
- * For the former case of modeswitching, it is possible
- * to switch between two FBC valid configurations
- * instantaneously so we do need to disable the FBC
- * before we can modify its control registers. We also
- * have to wait for the next vblank for that to take
- * effect. However, since we delay enabling FBC we can
- * assume that a vblank has passed since disabling and
- * that we can safely alter the registers in the deferred
- * callback.
- *
- * In the scenario that we go from a valid to invalid
- * and then back to valid FBC configuration we have
- * no strict enforcement that a vblank occurred since
- * disabling the FBC. However, along all current pipe
- * disabling paths we do need to wait for a vblank at
- * some point. And we wait before enabling FBC anyway.
- */
- DRM_DEBUG_KMS("disabling active FBC for update\n");
- intel_disable_fbc(dev);
- }
-
- intel_enable_fbc(crtc, 500);
- return;
-
-out_disable:
- /* Multiple disables should be harmless */
- if (intel_fbc_enabled(dev)) {
- DRM_DEBUG_KMS("unsupported config, disabling FBC\n");
- intel_disable_fbc(dev);
- }
-}
-
int
intel_pin_and_fence_fb_obj(struct drm_device *dev,
struct drm_i915_gem_object *obj,
@@ -2050,13 +1792,11 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev,
* framebuffer compression. For simplicity, we always install
* a fence as the cost is not that onerous.
*/
- if (obj->tiling_mode != I915_TILING_NONE) {
- ret = i915_gem_object_get_fence(obj, pipelined);
- if (ret)
- goto err_unpin;
+ ret = i915_gem_object_get_fence(obj);
+ if (ret)
+ goto err_unpin;
- i915_gem_object_pin_fence(obj);
- }
+ i915_gem_object_pin_fence(obj);
dev_priv->mm.interruptible = true;
return 0;
@@ -2137,7 +1877,7 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
Start, Offset, x, y, fb->pitches[0]);
I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
if (INTEL_INFO(dev)->gen >= 4) {
- I915_WRITE(DSPSURF(plane), Start);
+ I915_MODIFY_DISPBASE(DSPSURF(plane), Start);
I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
I915_WRITE(DSPADDR(plane), Offset);
} else
@@ -2217,7 +1957,7 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n",
Start, Offset, x, y, fb->pitches[0]);
I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
- I915_WRITE(DSPSURF(plane), Start);
+ I915_MODIFY_DISPBASE(DSPSURF(plane), Start);
I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
I915_WRITE(DSPADDR(plane), Offset);
POSTING_READ(reg);
@@ -2232,16 +1972,12 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- int ret;
-
- ret = dev_priv->display.update_plane(crtc, fb, x, y);
- if (ret)
- return ret;
- intel_update_fbc(dev);
+ if (dev_priv->display.disable_fbc)
+ dev_priv->display.disable_fbc(dev);
intel_increase_pllclock(crtc);
- return 0;
+ return dev_priv->display.update_plane(crtc, fb, x, y);
}
static int
@@ -2276,6 +2012,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
{
struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_master_private *master_priv;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int ret;
@@ -2286,16 +2023,10 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
return 0;
}
- switch (intel_crtc->plane) {
- case 0:
- case 1:
- break;
- case 2:
- if (IS_IVYBRIDGE(dev))
- break;
- /* fall through otherwise */
- default:
- DRM_ERROR("no plane for crtc\n");
+ if(intel_crtc->plane > dev_priv->num_pipe) {
+ DRM_ERROR("no plane for crtc: plane %d, num_pipes %d\n",
+ intel_crtc->plane,
+ dev_priv->num_pipe);
return -EINVAL;
}
@@ -2312,8 +2043,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
if (old_fb)
intel_finish_fb(old_fb);
- ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y,
- LEAVE_ATOMIC_MODE_SET);
+ ret = dev_priv->display.update_plane(crtc, crtc->fb, x, y);
if (ret) {
intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj);
mutex_unlock(&dev->struct_mutex);
@@ -2326,6 +2056,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
intel_unpin_fb_obj(to_intel_framebuffer(old_fb)->obj);
}
+ intel_update_fbc(dev);
mutex_unlock(&dev->struct_mutex);
if (!dev->primary->master)
@@ -2547,7 +2278,7 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
- u32 reg, temp, i;
+ u32 reg, temp, i, retry;
/* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
for train result */
@@ -2599,15 +2330,19 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
POSTING_READ(reg);
udelay(500);
- reg = FDI_RX_IIR(pipe);
- temp = I915_READ(reg);
- DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
-
- if (temp & FDI_RX_BIT_LOCK) {
- I915_WRITE(reg, temp | FDI_RX_BIT_LOCK);
- DRM_DEBUG_KMS("FDI train 1 done.\n");
- break;
+ for (retry = 0; retry < 5; retry++) {
+ reg = FDI_RX_IIR(pipe);
+ temp = I915_READ(reg);
+ DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
+ if (temp & FDI_RX_BIT_LOCK) {
+ I915_WRITE(reg, temp | FDI_RX_BIT_LOCK);
+ DRM_DEBUG_KMS("FDI train 1 done.\n");
+ break;
+ }
+ udelay(50);
}
+ if (retry < 5)
+ break;
}
if (i == 4)
DRM_ERROR("FDI train 1 fail!\n");
@@ -2648,15 +2383,19 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
POSTING_READ(reg);
udelay(500);
- reg = FDI_RX_IIR(pipe);
- temp = I915_READ(reg);
- DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
-
- if (temp & FDI_RX_SYMBOL_LOCK) {
- I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK);
- DRM_DEBUG_KMS("FDI train 2 done.\n");
- break;
+ for (retry = 0; retry < 5; retry++) {
+ reg = FDI_RX_IIR(pipe);
+ temp = I915_READ(reg);
+ DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
+ if (temp & FDI_RX_SYMBOL_LOCK) {
+ I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK);
+ DRM_DEBUG_KMS("FDI train 2 done.\n");
+ break;
+ }
+ udelay(50);
}
+ if (retry < 5)
+ break;
}
if (i == 4)
DRM_ERROR("FDI train 2 fail!\n");
@@ -2808,14 +2547,18 @@ static void ironlake_fdi_pll_enable(struct drm_crtc *crtc)
POSTING_READ(reg);
udelay(200);
- /* Enable CPU FDI TX PLL, always on for Ironlake */
- reg = FDI_TX_CTL(pipe);
- temp = I915_READ(reg);
- if ((temp & FDI_TX_PLL_ENABLE) == 0) {
- I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE);
+ /* On Haswell, the PLL configuration for ports and pipes is handled
+ * separately, as part of DDI setup */
+ if (!IS_HASWELL(dev)) {
+ /* Enable CPU FDI TX PLL, always on for Ironlake */
+ reg = FDI_TX_CTL(pipe);
+ temp = I915_READ(reg);
+ if ((temp & FDI_TX_PLL_ENABLE) == 0) {
+ I915_WRITE(reg, temp | FDI_TX_PLL_ENABLE);
- POSTING_READ(reg);
- udelay(100);
+ POSTING_READ(reg);
+ udelay(100);
+ }
}
}
@@ -2888,38 +2631,16 @@ static void ironlake_fdi_disable(struct drm_crtc *crtc)
udelay(100);
}
-/*
- * When we disable a pipe, we need to clear any pending scanline wait events
- * to avoid hanging the ring, which we assume we are waiting on.
- */
-static void intel_clear_scanline_wait(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_ring_buffer *ring;
- u32 tmp;
-
- if (IS_GEN2(dev))
- /* Can't break the hang on i8xx */
- return;
-
- ring = LP_RING(dev_priv);
- tmp = I915_READ_CTL(ring);
- if (tmp & RING_WAIT)
- I915_WRITE_CTL(ring, tmp);
-}
-
static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
{
- struct drm_i915_gem_object *obj;
- struct drm_i915_private *dev_priv;
+ struct drm_device *dev = crtc->dev;
if (crtc->fb == NULL)
return;
- obj = to_intel_framebuffer(crtc->fb)->obj;
- dev_priv = crtc->dev->dev_private;
- wait_event(dev_priv->pending_flip_queue,
- atomic_read(&obj->pending_flip) == 0);
+ mutex_lock(&dev->struct_mutex);
+ intel_finish_fb(crtc->fb);
+ mutex_unlock(&dev->struct_mutex);
}
static bool intel_crtc_driving_pch(struct drm_crtc *crtc)
@@ -2936,6 +2657,22 @@ static bool intel_crtc_driving_pch(struct drm_crtc *crtc)
if (encoder->base.crtc != crtc)
continue;
+ /* On Haswell, LPT PCH handles the VGA connection via FDI, and Haswell
+ * CPU handles all others */
+ if (IS_HASWELL(dev)) {
+ /* It is still unclear how this will work on PPT, so throw up a warning */
+ WARN_ON(!HAS_PCH_LPT(dev));
+
+ if (encoder->type == DRM_MODE_ENCODER_DAC) {
+ DRM_DEBUG_KMS("Haswell detected DAC encoder, assuming is PCH\n");
+ return true;
+ } else {
+ DRM_DEBUG_KMS("Haswell detected encoder %d, assuming is CPU\n",
+ encoder->type);
+ return false;
+ }
+ }
+
switch (encoder->type) {
case INTEL_OUTPUT_EDP:
if (!intel_encoder_is_pch_edp(&encoder->base))
@@ -2947,6 +2684,97 @@ static bool intel_crtc_driving_pch(struct drm_crtc *crtc)
return true;
}
+/* Program iCLKIP clock to the desired frequency */
+static void lpt_program_iclkip(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 divsel, phaseinc, auxdiv, phasedir = 0;
+ u32 temp;
+
+ /* It is necessary to ungate the pixclk gate prior to programming
+ * the divisors, and gate it back when it is done.
+ */
+ I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_GATE);
+
+ /* Disable SSCCTL */
+ intel_sbi_write(dev_priv, SBI_SSCCTL6,
+ intel_sbi_read(dev_priv, SBI_SSCCTL6) |
+ SBI_SSCCTL_DISABLE);
+
+ /* 20MHz is a corner case which is out of range for the 7-bit divisor */
+ if (crtc->mode.clock == 20000) {
+ auxdiv = 1;
+ divsel = 0x41;
+ phaseinc = 0x20;
+ } else {
+ /* The iCLK virtual clock root frequency is in MHz,
+ * but the crtc->mode.clock in in KHz. To get the divisors,
+ * it is necessary to divide one by another, so we
+ * convert the virtual clock precision to KHz here for higher
+ * precision.
+ */
+ u32 iclk_virtual_root_freq = 172800 * 1000;
+ u32 iclk_pi_range = 64;
+ u32 desired_divisor, msb_divisor_value, pi_value;
+
+ desired_divisor = (iclk_virtual_root_freq / crtc->mode.clock);
+ msb_divisor_value = desired_divisor / iclk_pi_range;
+ pi_value = desired_divisor % iclk_pi_range;
+
+ auxdiv = 0;
+ divsel = msb_divisor_value - 2;
+ phaseinc = pi_value;
+ }
+
+ /* This should not happen with any sane values */
+ WARN_ON(SBI_SSCDIVINTPHASE_DIVSEL(divsel) &
+ ~SBI_SSCDIVINTPHASE_DIVSEL_MASK);
+ WARN_ON(SBI_SSCDIVINTPHASE_DIR(phasedir) &
+ ~SBI_SSCDIVINTPHASE_INCVAL_MASK);
+
+ DRM_DEBUG_KMS("iCLKIP clock: found settings for %dKHz refresh rate: auxdiv=%x, divsel=%x, phasedir=%x, phaseinc=%x\n",
+ crtc->mode.clock,
+ auxdiv,
+ divsel,
+ phasedir,
+ phaseinc);
+
+ /* Program SSCDIVINTPHASE6 */
+ temp = intel_sbi_read(dev_priv, SBI_SSCDIVINTPHASE6);
+ temp &= ~SBI_SSCDIVINTPHASE_DIVSEL_MASK;
+ temp |= SBI_SSCDIVINTPHASE_DIVSEL(divsel);
+ temp &= ~SBI_SSCDIVINTPHASE_INCVAL_MASK;
+ temp |= SBI_SSCDIVINTPHASE_INCVAL(phaseinc);
+ temp |= SBI_SSCDIVINTPHASE_DIR(phasedir);
+ temp |= SBI_SSCDIVINTPHASE_PROPAGATE;
+
+ intel_sbi_write(dev_priv,
+ SBI_SSCDIVINTPHASE6,
+ temp);
+
+ /* Program SSCAUXDIV */
+ temp = intel_sbi_read(dev_priv, SBI_SSCAUXDIV6);
+ temp &= ~SBI_SSCAUXDIV_FINALDIV2SEL(1);
+ temp |= SBI_SSCAUXDIV_FINALDIV2SEL(auxdiv);
+ intel_sbi_write(dev_priv,
+ SBI_SSCAUXDIV6,
+ temp);
+
+
+ /* Enable modulator and associated divider */
+ temp = intel_sbi_read(dev_priv, SBI_SSCCTL6);
+ temp &= ~SBI_SSCCTL_DISABLE;
+ intel_sbi_write(dev_priv,
+ SBI_SSCCTL6,
+ temp);
+
+ /* Wait for initialization time */
+ udelay(24);
+
+ I915_WRITE(PIXCLK_GATE, PIXCLK_GATE_UNGATE);
+}
+
/*
* Enable PCH resources required for PCH ports:
* - PCH PLLs
@@ -2961,29 +2789,41 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
- u32 reg, temp, transc_sel;
+ u32 reg, temp;
+
+ assert_transcoder_disabled(dev_priv, pipe);
/* For PCH output, training FDI link */
dev_priv->display.fdi_link_train(crtc);
- intel_enable_pch_pll(dev_priv, pipe);
+ intel_enable_pch_pll(intel_crtc);
- if (HAS_PCH_CPT(dev)) {
- transc_sel = intel_crtc->use_pll_a ? TRANSC_DPLLA_SEL :
- TRANSC_DPLLB_SEL;
+ if (HAS_PCH_LPT(dev)) {
+ DRM_DEBUG_KMS("LPT detected: programming iCLKIP\n");
+ lpt_program_iclkip(crtc);
+ } else if (HAS_PCH_CPT(dev)) {
+ u32 sel;
- /* Be sure PCH DPLL SEL is set */
temp = I915_READ(PCH_DPLL_SEL);
- if (pipe == 0) {
- temp &= ~(TRANSA_DPLLB_SEL);
- temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
- } else if (pipe == 1) {
- temp &= ~(TRANSB_DPLLB_SEL);
- temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
- } else if (pipe == 2) {
- temp &= ~(TRANSC_DPLLB_SEL);
- temp |= (TRANSC_DPLL_ENABLE | transc_sel);
+ switch (pipe) {
+ default:
+ case 0:
+ temp |= TRANSA_DPLL_ENABLE;
+ sel = TRANSA_DPLLB_SEL;
+ break;
+ case 1:
+ temp |= TRANSB_DPLL_ENABLE;
+ sel = TRANSB_DPLLB_SEL;
+ break;
+ case 2:
+ temp |= TRANSC_DPLL_ENABLE;
+ sel = TRANSC_DPLLB_SEL;
+ break;
}
+ if (intel_crtc->pch_pll->pll_reg == _PCH_DPLL_B)
+ temp |= sel;
+ else
+ temp &= ~sel;
I915_WRITE(PCH_DPLL_SEL, temp);
}
@@ -2998,7 +2838,8 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
I915_WRITE(TRANS_VSYNC(pipe), I915_READ(VSYNC(pipe)));
I915_WRITE(TRANS_VSYNCSHIFT(pipe), I915_READ(VSYNCSHIFT(pipe)));
- intel_fdi_normal_train(crtc);
+ if (!IS_HASWELL(dev))
+ intel_fdi_normal_train(crtc);
/* For PCH DP, enable TRANS_DP_CTL */
if (HAS_PCH_CPT(dev) &&
@@ -3041,6 +2882,93 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
intel_enable_transcoder(dev_priv, pipe);
}
+static void intel_put_pch_pll(struct intel_crtc *intel_crtc)
+{
+ struct intel_pch_pll *pll = intel_crtc->pch_pll;
+
+ if (pll == NULL)
+ return;
+
+ if (pll->refcount == 0) {
+ WARN(1, "bad PCH PLL refcount\n");
+ return;
+ }
+
+ --pll->refcount;
+ intel_crtc->pch_pll = NULL;
+}
+
+static struct intel_pch_pll *intel_get_pch_pll(struct intel_crtc *intel_crtc, u32 dpll, u32 fp)
+{
+ struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private;
+ struct intel_pch_pll *pll;
+ int i;
+
+ pll = intel_crtc->pch_pll;
+ if (pll) {
+ DRM_DEBUG_KMS("CRTC:%d reusing existing PCH PLL %x\n",
+ intel_crtc->base.base.id, pll->pll_reg);
+ goto prepare;
+ }
+
+ if (HAS_PCH_IBX(dev_priv->dev)) {
+ /* Ironlake PCH has a fixed PLL->PCH pipe mapping. */
+ i = intel_crtc->pipe;
+ pll = &dev_priv->pch_plls[i];
+
+ DRM_DEBUG_KMS("CRTC:%d using pre-allocated PCH PLL %x\n",
+ intel_crtc->base.base.id, pll->pll_reg);
+
+ goto found;
+ }
+
+ for (i = 0; i < dev_priv->num_pch_pll; i++) {
+ pll = &dev_priv->pch_plls[i];
+
+ /* Only want to check enabled timings first */
+ if (pll->refcount == 0)
+ continue;
+
+ if (dpll == (I915_READ(pll->pll_reg) & 0x7fffffff) &&
+ fp == I915_READ(pll->fp0_reg)) {
+ DRM_DEBUG_KMS("CRTC:%d sharing existing PCH PLL %x (refcount %d, ative %d)\n",
+ intel_crtc->base.base.id,
+ pll->pll_reg, pll->refcount, pll->active);
+
+ goto found;
+ }
+ }
+
+ /* Ok no matching timings, maybe there's a free one? */
+ for (i = 0; i < dev_priv->num_pch_pll; i++) {
+ pll = &dev_priv->pch_plls[i];
+ if (pll->refcount == 0) {
+ DRM_DEBUG_KMS("CRTC:%d allocated PCH PLL %x\n",
+ intel_crtc->base.base.id, pll->pll_reg);
+ goto found;
+ }
+ }
+
+ return NULL;
+
+found:
+ intel_crtc->pch_pll = pll;
+ pll->refcount++;
+ DRM_DEBUG_DRIVER("using pll %d for pipe %d\n", i, intel_crtc->pipe);
+prepare: /* separate function? */
+ DRM_DEBUG_DRIVER("switching PLL %x off\n", pll->pll_reg);
+
+ /* Wait for the clocks to stabilize before rewriting the regs */
+ I915_WRITE(pll->pll_reg, dpll & ~DPLL_VCO_ENABLE);
+ POSTING_READ(pll->pll_reg);
+ udelay(150);
+
+ I915_WRITE(pll->fp0_reg, fp);
+ I915_WRITE(pll->pll_reg, dpll & ~DPLL_VCO_ENABLE);
+ pll->on = false;
+ return pll;
+}
+
void intel_cpt_verify_modeset(struct drm_device *dev, int pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3185,8 +3113,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
}
/* disable PCH DPLL */
- if (!intel_crtc->no_pll)
- intel_disable_pch_pll(dev_priv, pipe);
+ intel_disable_pch_pll(intel_crtc);
/* Switch from PCDclk to Rawclk */
reg = FDI_RX_CTL(pipe);
@@ -3214,7 +3141,6 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
mutex_lock(&dev->struct_mutex);
intel_update_fbc(dev);
- intel_clear_scanline_wait(dev);
mutex_unlock(&dev->struct_mutex);
}
@@ -3242,6 +3168,12 @@ static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
}
}
+static void ironlake_crtc_off(struct drm_crtc *crtc)
+{
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ intel_put_pch_pll(intel_crtc);
+}
+
static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable)
{
if (!enable && intel_crtc->overlay) {
@@ -3313,7 +3245,6 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
intel_crtc->active = false;
intel_update_fbc(dev);
intel_update_watermarks(dev);
- intel_clear_scanline_wait(dev);
}
static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
@@ -3333,6 +3264,10 @@ static void i9xx_crtc_dpms(struct drm_crtc *crtc, int mode)
}
}
+static void i9xx_crtc_off(struct drm_crtc *crtc)
+{
+}
+
/**
* Sets the power management mode of the pipe and plane.
*/
@@ -3380,25 +3315,11 @@ static void intel_crtc_disable(struct drm_crtc *crtc)
{
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
struct drm_device *dev = crtc->dev;
-
- /* Flush any pending WAITs before we disable the pipe. Note that
- * we need to drop the struct_mutex in order to acquire it again
- * during the lowlevel dpms routines around a couple of the
- * operations. It does not look trivial nor desirable to move
- * that locking higher. So instead we leave a window for the
- * submission of further commands on the fb before we can actually
- * disable it. This race with userspace exists anyway, and we can
- * only rely on the pipe being disabled by userspace after it
- * receives the hotplug notification and has flushed any pending
- * batches.
- */
- if (crtc->fb) {
- mutex_lock(&dev->struct_mutex);
- intel_finish_fb(crtc->fb);
- mutex_unlock(&dev->struct_mutex);
- }
+ struct drm_i915_private *dev_priv = dev->dev_private;
crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
+ dev_priv->display.off(crtc);
+
assert_plane_disabled(dev->dev_private, to_intel_crtc(crtc)->plane);
assert_pipe_disabled(dev->dev_private, to_intel_crtc(crtc)->pipe);
@@ -3448,8 +3369,7 @@ void intel_encoder_commit(struct drm_encoder *encoder)
{
struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
struct drm_device *dev = encoder->dev;
- struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
- struct intel_crtc *intel_crtc = to_intel_crtc(intel_encoder->base.crtc);
+ struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
/* lvds has its own version of commit see intel_lvds_commit */
encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
@@ -3487,6 +3407,11 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
return true;
}
+static int valleyview_get_display_clock_speed(struct drm_device *dev)
+{
+ return 400000; /* FIXME */
+}
+
static int i945_get_display_clock_speed(struct drm_device *dev)
{
return 400000;
@@ -3584,1342 +3509,6 @@ ironlake_compute_m_n(int bits_per_pixel, int nlanes, int pixel_clock,
fdi_reduce_ratio(&m_n->link_m, &m_n->link_n);
}
-
-struct intel_watermark_params {
- unsigned long fifo_size;
- unsigned long max_wm;
- unsigned long default_wm;
- unsigned long guard_size;
- unsigned long cacheline_size;
-};
-
-/* Pineview has different values for various configs */
-static const struct intel_watermark_params pineview_display_wm = {
- PINEVIEW_DISPLAY_FIFO,
- PINEVIEW_MAX_WM,
- PINEVIEW_DFT_WM,
- PINEVIEW_GUARD_WM,
- PINEVIEW_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params pineview_display_hplloff_wm = {
- PINEVIEW_DISPLAY_FIFO,
- PINEVIEW_MAX_WM,
- PINEVIEW_DFT_HPLLOFF_WM,
- PINEVIEW_GUARD_WM,
- PINEVIEW_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params pineview_cursor_wm = {
- PINEVIEW_CURSOR_FIFO,
- PINEVIEW_CURSOR_MAX_WM,
- PINEVIEW_CURSOR_DFT_WM,
- PINEVIEW_CURSOR_GUARD_WM,
- PINEVIEW_FIFO_LINE_SIZE,
-};
-static const struct intel_watermark_params pineview_cursor_hplloff_wm = {
- PINEVIEW_CURSOR_FIFO,
- PINEVIEW_CURSOR_MAX_WM,
- PINEVIEW_CURSOR_DFT_WM,
- PINEVIEW_CURSOR_GUARD_WM,
- PINEVIEW_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params g4x_wm_info = {
- G4X_FIFO_SIZE,
- G4X_MAX_WM,
- G4X_MAX_WM,
- 2,
- G4X_FIFO_LINE_SIZE,
-};
-static const struct intel_watermark_params g4x_cursor_wm_info = {
- I965_CURSOR_FIFO,
- I965_CURSOR_MAX_WM,
- I965_CURSOR_DFT_WM,
- 2,
- G4X_FIFO_LINE_SIZE,
-};
-static const struct intel_watermark_params i965_cursor_wm_info = {
- I965_CURSOR_FIFO,
- I965_CURSOR_MAX_WM,
- I965_CURSOR_DFT_WM,
- 2,
- I915_FIFO_LINE_SIZE,
-};
-static const struct intel_watermark_params i945_wm_info = {
- I945_FIFO_SIZE,
- I915_MAX_WM,
- 1,
- 2,
- I915_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params i915_wm_info = {
- I915_FIFO_SIZE,
- I915_MAX_WM,
- 1,
- 2,
- I915_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params i855_wm_info = {
- I855GM_FIFO_SIZE,
- I915_MAX_WM,
- 1,
- 2,
- I830_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params i830_wm_info = {
- I830_FIFO_SIZE,
- I915_MAX_WM,
- 1,
- 2,
- I830_FIFO_LINE_SIZE
-};
-
-static const struct intel_watermark_params ironlake_display_wm_info = {
- ILK_DISPLAY_FIFO,
- ILK_DISPLAY_MAXWM,
- ILK_DISPLAY_DFTWM,
- 2,
- ILK_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params ironlake_cursor_wm_info = {
- ILK_CURSOR_FIFO,
- ILK_CURSOR_MAXWM,
- ILK_CURSOR_DFTWM,
- 2,
- ILK_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params ironlake_display_srwm_info = {
- ILK_DISPLAY_SR_FIFO,
- ILK_DISPLAY_MAX_SRWM,
- ILK_DISPLAY_DFT_SRWM,
- 2,
- ILK_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params ironlake_cursor_srwm_info = {
- ILK_CURSOR_SR_FIFO,
- ILK_CURSOR_MAX_SRWM,
- ILK_CURSOR_DFT_SRWM,
- 2,
- ILK_FIFO_LINE_SIZE
-};
-
-static const struct intel_watermark_params sandybridge_display_wm_info = {
- SNB_DISPLAY_FIFO,
- SNB_DISPLAY_MAXWM,
- SNB_DISPLAY_DFTWM,
- 2,
- SNB_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params sandybridge_cursor_wm_info = {
- SNB_CURSOR_FIFO,
- SNB_CURSOR_MAXWM,
- SNB_CURSOR_DFTWM,
- 2,
- SNB_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params sandybridge_display_srwm_info = {
- SNB_DISPLAY_SR_FIFO,
- SNB_DISPLAY_MAX_SRWM,
- SNB_DISPLAY_DFT_SRWM,
- 2,
- SNB_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params sandybridge_cursor_srwm_info = {
- SNB_CURSOR_SR_FIFO,
- SNB_CURSOR_MAX_SRWM,
- SNB_CURSOR_DFT_SRWM,
- 2,
- SNB_FIFO_LINE_SIZE
-};
-
-
-/**
- * intel_calculate_wm - calculate watermark level
- * @clock_in_khz: pixel clock
- * @wm: chip FIFO params
- * @pixel_size: display pixel size
- * @latency_ns: memory latency for the platform
- *
- * Calculate the watermark level (the level at which the display plane will
- * start fetching from memory again). Each chip has a different display
- * FIFO size and allocation, so the caller needs to figure that out and pass
- * in the correct intel_watermark_params structure.
- *
- * As the pixel clock runs, the FIFO will be drained at a rate that depends
- * on the pixel size. When it reaches the watermark level, it'll start
- * fetching FIFO line sized based chunks from memory until the FIFO fills
- * past the watermark point. If the FIFO drains completely, a FIFO underrun
- * will occur, and a display engine hang could result.
- */
-static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
- const struct intel_watermark_params *wm,
- int fifo_size,
- int pixel_size,
- unsigned long latency_ns)
-{
- long entries_required, wm_size;
-
- /*
- * Note: we need to make sure we don't overflow for various clock &
- * latency values.
- * clocks go from a few thousand to several hundred thousand.
- * latency is usually a few thousand
- */
- entries_required = ((clock_in_khz / 1000) * pixel_size * latency_ns) /
- 1000;
- entries_required = DIV_ROUND_UP(entries_required, wm->cacheline_size);
-
- DRM_DEBUG_KMS("FIFO entries required for mode: %ld\n", entries_required);
-
- wm_size = fifo_size - (entries_required + wm->guard_size);
-
- DRM_DEBUG_KMS("FIFO watermark level: %ld\n", wm_size);
-
- /* Don't promote wm_size to unsigned... */
- if (wm_size > (long)wm->max_wm)
- wm_size = wm->max_wm;
- if (wm_size <= 0)
- wm_size = wm->default_wm;
- return wm_size;
-}
-
-struct cxsr_latency {
- int is_desktop;
- int is_ddr3;
- unsigned long fsb_freq;
- unsigned long mem_freq;
- unsigned long display_sr;
- unsigned long display_hpll_disable;
- unsigned long cursor_sr;
- unsigned long cursor_hpll_disable;
-};
-
-static const struct cxsr_latency cxsr_latency_table[] = {
- {1, 0, 800, 400, 3382, 33382, 3983, 33983}, /* DDR2-400 SC */
- {1, 0, 800, 667, 3354, 33354, 3807, 33807}, /* DDR2-667 SC */
- {1, 0, 800, 800, 3347, 33347, 3763, 33763}, /* DDR2-800 SC */
- {1, 1, 800, 667, 6420, 36420, 6873, 36873}, /* DDR3-667 SC */
- {1, 1, 800, 800, 5902, 35902, 6318, 36318}, /* DDR3-800 SC */
-
- {1, 0, 667, 400, 3400, 33400, 4021, 34021}, /* DDR2-400 SC */
- {1, 0, 667, 667, 3372, 33372, 3845, 33845}, /* DDR2-667 SC */
- {1, 0, 667, 800, 3386, 33386, 3822, 33822}, /* DDR2-800 SC */
- {1, 1, 667, 667, 6438, 36438, 6911, 36911}, /* DDR3-667 SC */
- {1, 1, 667, 800, 5941, 35941, 6377, 36377}, /* DDR3-800 SC */
-
- {1, 0, 400, 400, 3472, 33472, 4173, 34173}, /* DDR2-400 SC */
- {1, 0, 400, 667, 3443, 33443, 3996, 33996}, /* DDR2-667 SC */
- {1, 0, 400, 800, 3430, 33430, 3946, 33946}, /* DDR2-800 SC */
- {1, 1, 400, 667, 6509, 36509, 7062, 37062}, /* DDR3-667 SC */
- {1, 1, 400, 800, 5985, 35985, 6501, 36501}, /* DDR3-800 SC */
-
- {0, 0, 800, 400, 3438, 33438, 4065, 34065}, /* DDR2-400 SC */
- {0, 0, 800, 667, 3410, 33410, 3889, 33889}, /* DDR2-667 SC */
- {0, 0, 800, 800, 3403, 33403, 3845, 33845}, /* DDR2-800 SC */
- {0, 1, 800, 667, 6476, 36476, 6955, 36955}, /* DDR3-667 SC */
- {0, 1, 800, 800, 5958, 35958, 6400, 36400}, /* DDR3-800 SC */
-
- {0, 0, 667, 400, 3456, 33456, 4103, 34106}, /* DDR2-400 SC */
- {0, 0, 667, 667, 3428, 33428, 3927, 33927}, /* DDR2-667 SC */
- {0, 0, 667, 800, 3443, 33443, 3905, 33905}, /* DDR2-800 SC */
- {0, 1, 667, 667, 6494, 36494, 6993, 36993}, /* DDR3-667 SC */
- {0, 1, 667, 800, 5998, 35998, 6460, 36460}, /* DDR3-800 SC */
-
- {0, 0, 400, 400, 3528, 33528, 4255, 34255}, /* DDR2-400 SC */
- {0, 0, 400, 667, 3500, 33500, 4079, 34079}, /* DDR2-667 SC */
- {0, 0, 400, 800, 3487, 33487, 4029, 34029}, /* DDR2-800 SC */
- {0, 1, 400, 667, 6566, 36566, 7145, 37145}, /* DDR3-667 SC */
- {0, 1, 400, 800, 6042, 36042, 6584, 36584}, /* DDR3-800 SC */
-};
-
-static const struct cxsr_latency *intel_get_cxsr_latency(int is_desktop,
- int is_ddr3,
- int fsb,
- int mem)
-{
- const struct cxsr_latency *latency;
- int i;
-
- if (fsb == 0 || mem == 0)
- return NULL;
-
- for (i = 0; i < ARRAY_SIZE(cxsr_latency_table); i++) {
- latency = &cxsr_latency_table[i];
- if (is_desktop == latency->is_desktop &&
- is_ddr3 == latency->is_ddr3 &&
- fsb == latency->fsb_freq && mem == latency->mem_freq)
- return latency;
- }
-
- DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n");
-
- return NULL;
-}
-
-static void pineview_disable_cxsr(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- /* deactivate cxsr */
- I915_WRITE(DSPFW3, I915_READ(DSPFW3) & ~PINEVIEW_SELF_REFRESH_EN);
-}
-
-/*
- * Latency for FIFO fetches is dependent on several factors:
- * - memory configuration (speed, channels)
- * - chipset
- * - current MCH state
- * It can be fairly high in some situations, so here we assume a fairly
- * pessimal value. It's a tradeoff between extra memory fetches (if we
- * set this value too high, the FIFO will fetch frequently to stay full)
- * and power consumption (set it too low to save power and we might see
- * FIFO underruns and display "flicker").
- *
- * A value of 5us seems to be a good balance; safe for very low end
- * platforms but not overly aggressive on lower latency configs.
- */
-static const int latency_ns = 5000;
-
-static int i9xx_get_fifo_size(struct drm_device *dev, int plane)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t dsparb = I915_READ(DSPARB);
- int size;
-
- size = dsparb & 0x7f;
- if (plane)
- size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) - size;
-
- DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
- plane ? "B" : "A", size);
-
- return size;
-}
-
-static int i85x_get_fifo_size(struct drm_device *dev, int plane)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t dsparb = I915_READ(DSPARB);
- int size;
-
- size = dsparb & 0x1ff;
- if (plane)
- size = ((dsparb >> DSPARB_BEND_SHIFT) & 0x1ff) - size;
- size >>= 1; /* Convert to cachelines */
-
- DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
- plane ? "B" : "A", size);
-
- return size;
-}
-
-static int i845_get_fifo_size(struct drm_device *dev, int plane)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t dsparb = I915_READ(DSPARB);
- int size;
-
- size = dsparb & 0x7f;
- size >>= 2; /* Convert to cachelines */
-
- DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
- plane ? "B" : "A",
- size);
-
- return size;
-}
-
-static int i830_get_fifo_size(struct drm_device *dev, int plane)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t dsparb = I915_READ(DSPARB);
- int size;
-
- size = dsparb & 0x7f;
- size >>= 1; /* Convert to cachelines */
-
- DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
- plane ? "B" : "A", size);
-
- return size;
-}
-
-static struct drm_crtc *single_enabled_crtc(struct drm_device *dev)
-{
- struct drm_crtc *crtc, *enabled = NULL;
-
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- if (crtc->enabled && crtc->fb) {
- if (enabled)
- return NULL;
- enabled = crtc;
- }
- }
-
- return enabled;
-}
-
-static void pineview_update_wm(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_crtc *crtc;
- const struct cxsr_latency *latency;
- u32 reg;
- unsigned long wm;
-
- latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->is_ddr3,
- dev_priv->fsb_freq, dev_priv->mem_freq);
- if (!latency) {
- DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n");
- pineview_disable_cxsr(dev);
- return;
- }
-
- crtc = single_enabled_crtc(dev);
- if (crtc) {
- int clock = crtc->mode.clock;
- int pixel_size = crtc->fb->bits_per_pixel / 8;
-
- /* Display SR */
- wm = intel_calculate_wm(clock, &pineview_display_wm,
- pineview_display_wm.fifo_size,
- pixel_size, latency->display_sr);
- reg = I915_READ(DSPFW1);
- reg &= ~DSPFW_SR_MASK;
- reg |= wm << DSPFW_SR_SHIFT;
- I915_WRITE(DSPFW1, reg);
- DRM_DEBUG_KMS("DSPFW1 register is %x\n", reg);
-
- /* cursor SR */
- wm = intel_calculate_wm(clock, &pineview_cursor_wm,
- pineview_display_wm.fifo_size,
- pixel_size, latency->cursor_sr);
- reg = I915_READ(DSPFW3);
- reg &= ~DSPFW_CURSOR_SR_MASK;
- reg |= (wm & 0x3f) << DSPFW_CURSOR_SR_SHIFT;
- I915_WRITE(DSPFW3, reg);
-
- /* Display HPLL off SR */
- wm = intel_calculate_wm(clock, &pineview_display_hplloff_wm,
- pineview_display_hplloff_wm.fifo_size,
- pixel_size, latency->display_hpll_disable);
- reg = I915_READ(DSPFW3);
- reg &= ~DSPFW_HPLL_SR_MASK;
- reg |= wm & DSPFW_HPLL_SR_MASK;
- I915_WRITE(DSPFW3, reg);
-
- /* cursor HPLL off SR */
- wm = intel_calculate_wm(clock, &pineview_cursor_hplloff_wm,
- pineview_display_hplloff_wm.fifo_size,
- pixel_size, latency->cursor_hpll_disable);
- reg = I915_READ(DSPFW3);
- reg &= ~DSPFW_HPLL_CURSOR_MASK;
- reg |= (wm & 0x3f) << DSPFW_HPLL_CURSOR_SHIFT;
- I915_WRITE(DSPFW3, reg);
- DRM_DEBUG_KMS("DSPFW3 register is %x\n", reg);
-
- /* activate cxsr */
- I915_WRITE(DSPFW3,
- I915_READ(DSPFW3) | PINEVIEW_SELF_REFRESH_EN);
- DRM_DEBUG_KMS("Self-refresh is enabled\n");
- } else {
- pineview_disable_cxsr(dev);
- DRM_DEBUG_KMS("Self-refresh is disabled\n");
- }
-}
-
-static bool g4x_compute_wm0(struct drm_device *dev,
- int plane,
- const struct intel_watermark_params *display,
- int display_latency_ns,
- const struct intel_watermark_params *cursor,
- int cursor_latency_ns,
- int *plane_wm,
- int *cursor_wm)
-{
- struct drm_crtc *crtc;
- int htotal, hdisplay, clock, pixel_size;
- int line_time_us, line_count;
- int entries, tlb_miss;
-
- crtc = intel_get_crtc_for_plane(dev, plane);
- if (crtc->fb == NULL || !crtc->enabled) {
- *cursor_wm = cursor->guard_size;
- *plane_wm = display->guard_size;
- return false;
- }
-
- htotal = crtc->mode.htotal;
- hdisplay = crtc->mode.hdisplay;
- clock = crtc->mode.clock;
- pixel_size = crtc->fb->bits_per_pixel / 8;
-
- /* Use the small buffer method to calculate plane watermark */
- entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000;
- tlb_miss = display->fifo_size*display->cacheline_size - hdisplay * 8;
- if (tlb_miss > 0)
- entries += tlb_miss;
- entries = DIV_ROUND_UP(entries, display->cacheline_size);
- *plane_wm = entries + display->guard_size;
- if (*plane_wm > (int)display->max_wm)
- *plane_wm = display->max_wm;
-
- /* Use the large buffer method to calculate cursor watermark */
- line_time_us = ((htotal * 1000) / clock);
- line_count = (cursor_latency_ns / line_time_us + 1000) / 1000;
- entries = line_count * 64 * pixel_size;
- tlb_miss = cursor->fifo_size*cursor->cacheline_size - hdisplay * 8;
- if (tlb_miss > 0)
- entries += tlb_miss;
- entries = DIV_ROUND_UP(entries, cursor->cacheline_size);
- *cursor_wm = entries + cursor->guard_size;
- if (*cursor_wm > (int)cursor->max_wm)
- *cursor_wm = (int)cursor->max_wm;
-
- return true;
-}
-
-/*
- * Check the wm result.
- *
- * If any calculated watermark values is larger than the maximum value that
- * can be programmed into the associated watermark register, that watermark
- * must be disabled.
- */
-static bool g4x_check_srwm(struct drm_device *dev,
- int display_wm, int cursor_wm,
- const struct intel_watermark_params *display,
- const struct intel_watermark_params *cursor)
-{
- DRM_DEBUG_KMS("SR watermark: display plane %d, cursor %d\n",
- display_wm, cursor_wm);
-
- if (display_wm > display->max_wm) {
- DRM_DEBUG_KMS("display watermark is too large(%d/%ld), disabling\n",
- display_wm, display->max_wm);
- return false;
- }
-
- if (cursor_wm > cursor->max_wm) {
- DRM_DEBUG_KMS("cursor watermark is too large(%d/%ld), disabling\n",
- cursor_wm, cursor->max_wm);
- return false;
- }
-
- if (!(display_wm || cursor_wm)) {
- DRM_DEBUG_KMS("SR latency is 0, disabling\n");
- return false;
- }
-
- return true;
-}
-
-static bool g4x_compute_srwm(struct drm_device *dev,
- int plane,
- int latency_ns,
- const struct intel_watermark_params *display,
- const struct intel_watermark_params *cursor,
- int *display_wm, int *cursor_wm)
-{
- struct drm_crtc *crtc;
- int hdisplay, htotal, pixel_size, clock;
- unsigned long line_time_us;
- int line_count, line_size;
- int small, large;
- int entries;
-
- if (!latency_ns) {
- *display_wm = *cursor_wm = 0;
- return false;
- }
-
- crtc = intel_get_crtc_for_plane(dev, plane);
- hdisplay = crtc->mode.hdisplay;
- htotal = crtc->mode.htotal;
- clock = crtc->mode.clock;
- pixel_size = crtc->fb->bits_per_pixel / 8;
-
- line_time_us = (htotal * 1000) / clock;
- line_count = (latency_ns / line_time_us + 1000) / 1000;
- line_size = hdisplay * pixel_size;
-
- /* Use the minimum of the small and large buffer method for primary */
- small = ((clock * pixel_size / 1000) * latency_ns) / 1000;
- large = line_count * line_size;
-
- entries = DIV_ROUND_UP(min(small, large), display->cacheline_size);
- *display_wm = entries + display->guard_size;
-
- /* calculate the self-refresh watermark for display cursor */
- entries = line_count * pixel_size * 64;
- entries = DIV_ROUND_UP(entries, cursor->cacheline_size);
- *cursor_wm = entries + cursor->guard_size;
-
- return g4x_check_srwm(dev,
- *display_wm, *cursor_wm,
- display, cursor);
-}
-
-#define single_plane_enabled(mask) is_power_of_2(mask)
-
-static void g4x_update_wm(struct drm_device *dev)
-{
- static const int sr_latency_ns = 12000;
- struct drm_i915_private *dev_priv = dev->dev_private;
- int planea_wm, planeb_wm, cursora_wm, cursorb_wm;
- int plane_sr, cursor_sr;
- unsigned int enabled = 0;
-
- if (g4x_compute_wm0(dev, 0,
- &g4x_wm_info, latency_ns,
- &g4x_cursor_wm_info, latency_ns,
- &planea_wm, &cursora_wm))
- enabled |= 1;
-
- if (g4x_compute_wm0(dev, 1,
- &g4x_wm_info, latency_ns,
- &g4x_cursor_wm_info, latency_ns,
- &planeb_wm, &cursorb_wm))
- enabled |= 2;
-
- plane_sr = cursor_sr = 0;
- if (single_plane_enabled(enabled) &&
- g4x_compute_srwm(dev, ffs(enabled) - 1,
- sr_latency_ns,
- &g4x_wm_info,
- &g4x_cursor_wm_info,
- &plane_sr, &cursor_sr))
- I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
- else
- I915_WRITE(FW_BLC_SELF,
- I915_READ(FW_BLC_SELF) & ~FW_BLC_SELF_EN);
-
- DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n",
- planea_wm, cursora_wm,
- planeb_wm, cursorb_wm,
- plane_sr, cursor_sr);
-
- I915_WRITE(DSPFW1,
- (plane_sr << DSPFW_SR_SHIFT) |
- (cursorb_wm << DSPFW_CURSORB_SHIFT) |
- (planeb_wm << DSPFW_PLANEB_SHIFT) |
- planea_wm);
- I915_WRITE(DSPFW2,
- (I915_READ(DSPFW2) & DSPFW_CURSORA_MASK) |
- (cursora_wm << DSPFW_CURSORA_SHIFT));
- /* HPLL off in SR has some issues on G4x... disable it */
- I915_WRITE(DSPFW3,
- (I915_READ(DSPFW3) & ~DSPFW_HPLL_SR_EN) |
- (cursor_sr << DSPFW_CURSOR_SR_SHIFT));
-}
-
-static void i965_update_wm(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_crtc *crtc;
- int srwm = 1;
- int cursor_sr = 16;
-
- /* Calc sr entries for one plane configs */
- crtc = single_enabled_crtc(dev);
- if (crtc) {
- /* self-refresh has much higher latency */
- static const int sr_latency_ns = 12000;
- int clock = crtc->mode.clock;
- int htotal = crtc->mode.htotal;
- int hdisplay = crtc->mode.hdisplay;
- int pixel_size = crtc->fb->bits_per_pixel / 8;
- unsigned long line_time_us;
- int entries;
-
- line_time_us = ((htotal * 1000) / clock);
-
- /* Use ns/us then divide to preserve precision */
- entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
- pixel_size * hdisplay;
- entries = DIV_ROUND_UP(entries, I915_FIFO_LINE_SIZE);
- srwm = I965_FIFO_SIZE - entries;
- if (srwm < 0)
- srwm = 1;
- srwm &= 0x1ff;
- DRM_DEBUG_KMS("self-refresh entries: %d, wm: %d\n",
- entries, srwm);
-
- entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
- pixel_size * 64;
- entries = DIV_ROUND_UP(entries,
- i965_cursor_wm_info.cacheline_size);
- cursor_sr = i965_cursor_wm_info.fifo_size -
- (entries + i965_cursor_wm_info.guard_size);
-
- if (cursor_sr > i965_cursor_wm_info.max_wm)
- cursor_sr = i965_cursor_wm_info.max_wm;
-
- DRM_DEBUG_KMS("self-refresh watermark: display plane %d "
- "cursor %d\n", srwm, cursor_sr);
-
- if (IS_CRESTLINE(dev))
- I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
- } else {
- /* Turn off self refresh if both pipes are enabled */
- if (IS_CRESTLINE(dev))
- I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
- & ~FW_BLC_SELF_EN);
- }
-
- DRM_DEBUG_KMS("Setting FIFO watermarks - A: 8, B: 8, C: 8, SR %d\n",
- srwm);
-
- /* 965 has limitations... */
- I915_WRITE(DSPFW1, (srwm << DSPFW_SR_SHIFT) |
- (8 << 16) | (8 << 8) | (8 << 0));
- I915_WRITE(DSPFW2, (8 << 8) | (8 << 0));
- /* update cursor SR watermark */
- I915_WRITE(DSPFW3, (cursor_sr << DSPFW_CURSOR_SR_SHIFT));
-}
-
-static void i9xx_update_wm(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- const struct intel_watermark_params *wm_info;
- uint32_t fwater_lo;
- uint32_t fwater_hi;
- int cwm, srwm = 1;
- int fifo_size;
- int planea_wm, planeb_wm;
- struct drm_crtc *crtc, *enabled = NULL;
-
- if (IS_I945GM(dev))
- wm_info = &i945_wm_info;
- else if (!IS_GEN2(dev))
- wm_info = &i915_wm_info;
- else
- wm_info = &i855_wm_info;
-
- fifo_size = dev_priv->display.get_fifo_size(dev, 0);
- crtc = intel_get_crtc_for_plane(dev, 0);
- if (crtc->enabled && crtc->fb) {
- planea_wm = intel_calculate_wm(crtc->mode.clock,
- wm_info, fifo_size,
- crtc->fb->bits_per_pixel / 8,
- latency_ns);
- enabled = crtc;
- } else
- planea_wm = fifo_size - wm_info->guard_size;
-
- fifo_size = dev_priv->display.get_fifo_size(dev, 1);
- crtc = intel_get_crtc_for_plane(dev, 1);
- if (crtc->enabled && crtc->fb) {
- planeb_wm = intel_calculate_wm(crtc->mode.clock,
- wm_info, fifo_size,
- crtc->fb->bits_per_pixel / 8,
- latency_ns);
- if (enabled == NULL)
- enabled = crtc;
- else
- enabled = NULL;
- } else
- planeb_wm = fifo_size - wm_info->guard_size;
-
- DRM_DEBUG_KMS("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm);
-
- /*
- * Overlay gets an aggressive default since video jitter is bad.
- */
- cwm = 2;
-
- /* Play safe and disable self-refresh before adjusting watermarks. */
- if (IS_I945G(dev) || IS_I945GM(dev))
- I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | 0);
- else if (IS_I915GM(dev))
- I915_WRITE(INSTPM, I915_READ(INSTPM) & ~INSTPM_SELF_EN);
-
- /* Calc sr entries for one plane configs */
- if (HAS_FW_BLC(dev) && enabled) {
- /* self-refresh has much higher latency */
- static const int sr_latency_ns = 6000;
- int clock = enabled->mode.clock;
- int htotal = enabled->mode.htotal;
- int hdisplay = enabled->mode.hdisplay;
- int pixel_size = enabled->fb->bits_per_pixel / 8;
- unsigned long line_time_us;
- int entries;
-
- line_time_us = (htotal * 1000) / clock;
-
- /* Use ns/us then divide to preserve precision */
- entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
- pixel_size * hdisplay;
- entries = DIV_ROUND_UP(entries, wm_info->cacheline_size);
- DRM_DEBUG_KMS("self-refresh entries: %d\n", entries);
- srwm = wm_info->fifo_size - entries;
- if (srwm < 0)
- srwm = 1;
-
- if (IS_I945G(dev) || IS_I945GM(dev))
- I915_WRITE(FW_BLC_SELF,
- FW_BLC_SELF_FIFO_MASK | (srwm & 0xff));
- else if (IS_I915GM(dev))
- I915_WRITE(FW_BLC_SELF, srwm & 0x3f);
- }
-
- DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
- planea_wm, planeb_wm, cwm, srwm);
-
- fwater_lo = ((planeb_wm & 0x3f) << 16) | (planea_wm & 0x3f);
- fwater_hi = (cwm & 0x1f);
-
- /* Set request length to 8 cachelines per fetch */
- fwater_lo = fwater_lo | (1 << 24) | (1 << 8);
- fwater_hi = fwater_hi | (1 << 8);
-
- I915_WRITE(FW_BLC, fwater_lo);
- I915_WRITE(FW_BLC2, fwater_hi);
-
- if (HAS_FW_BLC(dev)) {
- if (enabled) {
- if (IS_I945G(dev) || IS_I945GM(dev))
- I915_WRITE(FW_BLC_SELF,
- FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN);
- else if (IS_I915GM(dev))
- I915_WRITE(INSTPM, I915_READ(INSTPM) | INSTPM_SELF_EN);
- DRM_DEBUG_KMS("memory self refresh enabled\n");
- } else
- DRM_DEBUG_KMS("memory self refresh disabled\n");
- }
-}
-
-static void i830_update_wm(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_crtc *crtc;
- uint32_t fwater_lo;
- int planea_wm;
-
- crtc = single_enabled_crtc(dev);
- if (crtc == NULL)
- return;
-
- planea_wm = intel_calculate_wm(crtc->mode.clock, &i830_wm_info,
- dev_priv->display.get_fifo_size(dev, 0),
- crtc->fb->bits_per_pixel / 8,
- latency_ns);
- fwater_lo = I915_READ(FW_BLC) & ~0xfff;
- fwater_lo |= (3<<8) | planea_wm;
-
- DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d\n", planea_wm);
-
- I915_WRITE(FW_BLC, fwater_lo);
-}
-
-#define ILK_LP0_PLANE_LATENCY 700
-#define ILK_LP0_CURSOR_LATENCY 1300
-
-/*
- * Check the wm result.
- *
- * If any calculated watermark values is larger than the maximum value that
- * can be programmed into the associated watermark register, that watermark
- * must be disabled.
- */
-static bool ironlake_check_srwm(struct drm_device *dev, int level,
- int fbc_wm, int display_wm, int cursor_wm,
- const struct intel_watermark_params *display,
- const struct intel_watermark_params *cursor)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- DRM_DEBUG_KMS("watermark %d: display plane %d, fbc lines %d,"
- " cursor %d\n", level, display_wm, fbc_wm, cursor_wm);
-
- if (fbc_wm > SNB_FBC_MAX_SRWM) {
- DRM_DEBUG_KMS("fbc watermark(%d) is too large(%d), disabling wm%d+\n",
- fbc_wm, SNB_FBC_MAX_SRWM, level);
-
- /* fbc has it's own way to disable FBC WM */
- I915_WRITE(DISP_ARB_CTL,
- I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS);
- return false;
- }
-
- if (display_wm > display->max_wm) {
- DRM_DEBUG_KMS("display watermark(%d) is too large(%d), disabling wm%d+\n",
- display_wm, SNB_DISPLAY_MAX_SRWM, level);
- return false;
- }
-
- if (cursor_wm > cursor->max_wm) {
- DRM_DEBUG_KMS("cursor watermark(%d) is too large(%d), disabling wm%d+\n",
- cursor_wm, SNB_CURSOR_MAX_SRWM, level);
- return false;
- }
-
- if (!(fbc_wm || display_wm || cursor_wm)) {
- DRM_DEBUG_KMS("latency %d is 0, disabling wm%d+\n", level, level);
- return false;
- }
-
- return true;
-}
-
-/*
- * Compute watermark values of WM[1-3],
- */
-static bool ironlake_compute_srwm(struct drm_device *dev, int level, int plane,
- int latency_ns,
- const struct intel_watermark_params *display,
- const struct intel_watermark_params *cursor,
- int *fbc_wm, int *display_wm, int *cursor_wm)
-{
- struct drm_crtc *crtc;
- unsigned long line_time_us;
- int hdisplay, htotal, pixel_size, clock;
- int line_count, line_size;
- int small, large;
- int entries;
-
- if (!latency_ns) {
- *fbc_wm = *display_wm = *cursor_wm = 0;
- return false;
- }
-
- crtc = intel_get_crtc_for_plane(dev, plane);
- hdisplay = crtc->mode.hdisplay;
- htotal = crtc->mode.htotal;
- clock = crtc->mode.clock;
- pixel_size = crtc->fb->bits_per_pixel / 8;
-
- line_time_us = (htotal * 1000) / clock;
- line_count = (latency_ns / line_time_us + 1000) / 1000;
- line_size = hdisplay * pixel_size;
-
- /* Use the minimum of the small and large buffer method for primary */
- small = ((clock * pixel_size / 1000) * latency_ns) / 1000;
- large = line_count * line_size;
-
- entries = DIV_ROUND_UP(min(small, large), display->cacheline_size);
- *display_wm = entries + display->guard_size;
-
- /*
- * Spec says:
- * FBC WM = ((Final Primary WM * 64) / number of bytes per line) + 2
- */
- *fbc_wm = DIV_ROUND_UP(*display_wm * 64, line_size) + 2;
-
- /* calculate the self-refresh watermark for display cursor */
- entries = line_count * pixel_size * 64;
- entries = DIV_ROUND_UP(entries, cursor->cacheline_size);
- *cursor_wm = entries + cursor->guard_size;
-
- return ironlake_check_srwm(dev, level,
- *fbc_wm, *display_wm, *cursor_wm,
- display, cursor);
-}
-
-static void ironlake_update_wm(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- int fbc_wm, plane_wm, cursor_wm;
- unsigned int enabled;
-
- enabled = 0;
- if (g4x_compute_wm0(dev, 0,
- &ironlake_display_wm_info,
- ILK_LP0_PLANE_LATENCY,
- &ironlake_cursor_wm_info,
- ILK_LP0_CURSOR_LATENCY,
- &plane_wm, &cursor_wm)) {
- I915_WRITE(WM0_PIPEA_ILK,
- (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
- DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
- " plane %d, " "cursor: %d\n",
- plane_wm, cursor_wm);
- enabled |= 1;
- }
-
- if (g4x_compute_wm0(dev, 1,
- &ironlake_display_wm_info,
- ILK_LP0_PLANE_LATENCY,
- &ironlake_cursor_wm_info,
- ILK_LP0_CURSOR_LATENCY,
- &plane_wm, &cursor_wm)) {
- I915_WRITE(WM0_PIPEB_ILK,
- (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
- DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
- " plane %d, cursor: %d\n",
- plane_wm, cursor_wm);
- enabled |= 2;
- }
-
- /*
- * Calculate and update the self-refresh watermark only when one
- * display plane is used.
- */
- I915_WRITE(WM3_LP_ILK, 0);
- I915_WRITE(WM2_LP_ILK, 0);
- I915_WRITE(WM1_LP_ILK, 0);
-
- if (!single_plane_enabled(enabled))
- return;
- enabled = ffs(enabled) - 1;
-
- /* WM1 */
- if (!ironlake_compute_srwm(dev, 1, enabled,
- ILK_READ_WM1_LATENCY() * 500,
- &ironlake_display_srwm_info,
- &ironlake_cursor_srwm_info,
- &fbc_wm, &plane_wm, &cursor_wm))
- return;
-
- I915_WRITE(WM1_LP_ILK,
- WM1_LP_SR_EN |
- (ILK_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) |
- (fbc_wm << WM1_LP_FBC_SHIFT) |
- (plane_wm << WM1_LP_SR_SHIFT) |
- cursor_wm);
-
- /* WM2 */
- if (!ironlake_compute_srwm(dev, 2, enabled,
- ILK_READ_WM2_LATENCY() * 500,
- &ironlake_display_srwm_info,
- &ironlake_cursor_srwm_info,
- &fbc_wm, &plane_wm, &cursor_wm))
- return;
-
- I915_WRITE(WM2_LP_ILK,
- WM2_LP_EN |
- (ILK_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) |
- (fbc_wm << WM1_LP_FBC_SHIFT) |
- (plane_wm << WM1_LP_SR_SHIFT) |
- cursor_wm);
-
- /*
- * WM3 is unsupported on ILK, probably because we don't have latency
- * data for that power state
- */
-}
-
-void sandybridge_update_wm(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */
- u32 val;
- int fbc_wm, plane_wm, cursor_wm;
- unsigned int enabled;
-
- enabled = 0;
- if (g4x_compute_wm0(dev, 0,
- &sandybridge_display_wm_info, latency,
- &sandybridge_cursor_wm_info, latency,
- &plane_wm, &cursor_wm)) {
- val = I915_READ(WM0_PIPEA_ILK);
- val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
- I915_WRITE(WM0_PIPEA_ILK, val |
- ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
- DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
- " plane %d, " "cursor: %d\n",
- plane_wm, cursor_wm);
- enabled |= 1;
- }
-
- if (g4x_compute_wm0(dev, 1,
- &sandybridge_display_wm_info, latency,
- &sandybridge_cursor_wm_info, latency,
- &plane_wm, &cursor_wm)) {
- val = I915_READ(WM0_PIPEB_ILK);
- val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
- I915_WRITE(WM0_PIPEB_ILK, val |
- ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
- DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
- " plane %d, cursor: %d\n",
- plane_wm, cursor_wm);
- enabled |= 2;
- }
-
- /* IVB has 3 pipes */
- if (IS_IVYBRIDGE(dev) &&
- g4x_compute_wm0(dev, 2,
- &sandybridge_display_wm_info, latency,
- &sandybridge_cursor_wm_info, latency,
- &plane_wm, &cursor_wm)) {
- val = I915_READ(WM0_PIPEC_IVB);
- val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
- I915_WRITE(WM0_PIPEC_IVB, val |
- ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
- DRM_DEBUG_KMS("FIFO watermarks For pipe C -"
- " plane %d, cursor: %d\n",
- plane_wm, cursor_wm);
- enabled |= 3;
- }
-
- /*
- * Calculate and update the self-refresh watermark only when one
- * display plane is used.
- *
- * SNB support 3 levels of watermark.
- *
- * WM1/WM2/WM2 watermarks have to be enabled in the ascending order,
- * and disabled in the descending order
- *
- */
- I915_WRITE(WM3_LP_ILK, 0);
- I915_WRITE(WM2_LP_ILK, 0);
- I915_WRITE(WM1_LP_ILK, 0);
-
- if (!single_plane_enabled(enabled) ||
- dev_priv->sprite_scaling_enabled)
- return;
- enabled = ffs(enabled) - 1;
-
- /* WM1 */
- if (!ironlake_compute_srwm(dev, 1, enabled,
- SNB_READ_WM1_LATENCY() * 500,
- &sandybridge_display_srwm_info,
- &sandybridge_cursor_srwm_info,
- &fbc_wm, &plane_wm, &cursor_wm))
- return;
-
- I915_WRITE(WM1_LP_ILK,
- WM1_LP_SR_EN |
- (SNB_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) |
- (fbc_wm << WM1_LP_FBC_SHIFT) |
- (plane_wm << WM1_LP_SR_SHIFT) |
- cursor_wm);
-
- /* WM2 */
- if (!ironlake_compute_srwm(dev, 2, enabled,
- SNB_READ_WM2_LATENCY() * 500,
- &sandybridge_display_srwm_info,
- &sandybridge_cursor_srwm_info,
- &fbc_wm, &plane_wm, &cursor_wm))
- return;
-
- I915_WRITE(WM2_LP_ILK,
- WM2_LP_EN |
- (SNB_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) |
- (fbc_wm << WM1_LP_FBC_SHIFT) |
- (plane_wm << WM1_LP_SR_SHIFT) |
- cursor_wm);
-
- /* WM3 */
- if (!ironlake_compute_srwm(dev, 3, enabled,
- SNB_READ_WM3_LATENCY() * 500,
- &sandybridge_display_srwm_info,
- &sandybridge_cursor_srwm_info,
- &fbc_wm, &plane_wm, &cursor_wm))
- return;
-
- I915_WRITE(WM3_LP_ILK,
- WM3_LP_EN |
- (SNB_READ_WM3_LATENCY() << WM1_LP_LATENCY_SHIFT) |
- (fbc_wm << WM1_LP_FBC_SHIFT) |
- (plane_wm << WM1_LP_SR_SHIFT) |
- cursor_wm);
-}
-
-static bool
-sandybridge_compute_sprite_wm(struct drm_device *dev, int plane,
- uint32_t sprite_width, int pixel_size,
- const struct intel_watermark_params *display,
- int display_latency_ns, int *sprite_wm)
-{
- struct drm_crtc *crtc;
- int clock;
- int entries, tlb_miss;
-
- crtc = intel_get_crtc_for_plane(dev, plane);
- if (crtc->fb == NULL || !crtc->enabled) {
- *sprite_wm = display->guard_size;
- return false;
- }
-
- clock = crtc->mode.clock;
-
- /* Use the small buffer method to calculate the sprite watermark */
- entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000;
- tlb_miss = display->fifo_size*display->cacheline_size -
- sprite_width * 8;
- if (tlb_miss > 0)
- entries += tlb_miss;
- entries = DIV_ROUND_UP(entries, display->cacheline_size);
- *sprite_wm = entries + display->guard_size;
- if (*sprite_wm > (int)display->max_wm)
- *sprite_wm = display->max_wm;
-
- return true;
-}
-
-static bool
-sandybridge_compute_sprite_srwm(struct drm_device *dev, int plane,
- uint32_t sprite_width, int pixel_size,
- const struct intel_watermark_params *display,
- int latency_ns, int *sprite_wm)
-{
- struct drm_crtc *crtc;
- unsigned long line_time_us;
- int clock;
- int line_count, line_size;
- int small, large;
- int entries;
-
- if (!latency_ns) {
- *sprite_wm = 0;
- return false;
- }
-
- crtc = intel_get_crtc_for_plane(dev, plane);
- clock = crtc->mode.clock;
- if (!clock) {
- *sprite_wm = 0;
- return false;
- }
-
- line_time_us = (sprite_width * 1000) / clock;
- if (!line_time_us) {
- *sprite_wm = 0;
- return false;
- }
-
- line_count = (latency_ns / line_time_us + 1000) / 1000;
- line_size = sprite_width * pixel_size;
-
- /* Use the minimum of the small and large buffer method for primary */
- small = ((clock * pixel_size / 1000) * latency_ns) / 1000;
- large = line_count * line_size;
-
- entries = DIV_ROUND_UP(min(small, large), display->cacheline_size);
- *sprite_wm = entries + display->guard_size;
-
- return *sprite_wm > 0x3ff ? false : true;
-}
-
-static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe,
- uint32_t sprite_width, int pixel_size)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */
- u32 val;
- int sprite_wm, reg;
- int ret;
-
- switch (pipe) {
- case 0:
- reg = WM0_PIPEA_ILK;
- break;
- case 1:
- reg = WM0_PIPEB_ILK;
- break;
- case 2:
- reg = WM0_PIPEC_IVB;
- break;
- default:
- return; /* bad pipe */
- }
-
- ret = sandybridge_compute_sprite_wm(dev, pipe, sprite_width, pixel_size,
- &sandybridge_display_wm_info,
- latency, &sprite_wm);
- if (!ret) {
- DRM_DEBUG_KMS("failed to compute sprite wm for pipe %d\n",
- pipe);
- return;
- }
-
- val = I915_READ(reg);
- val &= ~WM0_PIPE_SPRITE_MASK;
- I915_WRITE(reg, val | (sprite_wm << WM0_PIPE_SPRITE_SHIFT));
- DRM_DEBUG_KMS("sprite watermarks For pipe %d - %d\n", pipe, sprite_wm);
-
-
- ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width,
- pixel_size,
- &sandybridge_display_srwm_info,
- SNB_READ_WM1_LATENCY() * 500,
- &sprite_wm);
- if (!ret) {
- DRM_DEBUG_KMS("failed to compute sprite lp1 wm on pipe %d\n",
- pipe);
- return;
- }
- I915_WRITE(WM1S_LP_ILK, sprite_wm);
-
- /* Only IVB has two more LP watermarks for sprite */
- if (!IS_IVYBRIDGE(dev))
- return;
-
- ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width,
- pixel_size,
- &sandybridge_display_srwm_info,
- SNB_READ_WM2_LATENCY() * 500,
- &sprite_wm);
- if (!ret) {
- DRM_DEBUG_KMS("failed to compute sprite lp2 wm on pipe %d\n",
- pipe);
- return;
- }
- I915_WRITE(WM2S_LP_IVB, sprite_wm);
-
- ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width,
- pixel_size,
- &sandybridge_display_srwm_info,
- SNB_READ_WM3_LATENCY() * 500,
- &sprite_wm);
- if (!ret) {
- DRM_DEBUG_KMS("failed to compute sprite lp3 wm on pipe %d\n",
- pipe);
- return;
- }
- I915_WRITE(WM3S_LP_IVB, sprite_wm);
-}
-
-/**
- * intel_update_watermarks - update FIFO watermark values based on current modes
- *
- * Calculate watermark values for the various WM regs based on current mode
- * and plane configuration.
- *
- * There are several cases to deal with here:
- * - normal (i.e. non-self-refresh)
- * - self-refresh (SR) mode
- * - lines are large relative to FIFO size (buffer can hold up to 2)
- * - lines are small relative to FIFO size (buffer can hold more than 2
- * lines), so need to account for TLB latency
- *
- * The normal calculation is:
- * watermark = dotclock * bytes per pixel * latency
- * where latency is platform & configuration dependent (we assume pessimal
- * values here).
- *
- * The SR calculation is:
- * watermark = (trunc(latency/line time)+1) * surface width *
- * bytes per pixel
- * where
- * line time = htotal / dotclock
- * surface width = hdisplay for normal plane and 64 for cursor
- * and latency is assumed to be high, as above.
- *
- * The final value programmed to the register should always be rounded up,
- * and include an extra 2 entries to account for clock crossings.
- *
- * We don't use the sprite, so we can ignore that. And on Crestline we have
- * to set the non-SR watermarks to 8.
- */
-static void intel_update_watermarks(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- if (dev_priv->display.update_wm)
- dev_priv->display.update_wm(dev);
-}
-
-void intel_update_sprite_watermarks(struct drm_device *dev, int pipe,
- uint32_t sprite_width, int pixel_size)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- if (dev_priv->display.update_sprite_wm)
- dev_priv->display.update_sprite_wm(dev, pipe, sprite_width,
- pixel_size);
-}
-
static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
{
if (i915_panel_use_ssc >= 0)
@@ -5143,6 +3732,222 @@ static void i9xx_update_pll_dividers(struct drm_crtc *crtc,
}
}
+static void intel_update_lvds(struct drm_crtc *crtc, intel_clock_t *clock,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ int pipe = intel_crtc->pipe;
+ u32 temp;
+
+ temp = I915_READ(LVDS);
+ temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
+ if (pipe == 1) {
+ temp |= LVDS_PIPEB_SELECT;
+ } else {
+ temp &= ~LVDS_PIPEB_SELECT;
+ }
+ /* set the corresponsding LVDS_BORDER bit */
+ temp |= dev_priv->lvds_border_bits;
+ /* Set the B0-B3 data pairs corresponding to whether we're going to
+ * set the DPLLs for dual-channel mode or not.
+ */
+ if (clock->p2 == 7)
+ temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
+ else
+ temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
+
+ /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP)
+ * appropriately here, but we need to look more thoroughly into how
+ * panels behave in the two modes.
+ */
+ /* set the dithering flag on LVDS as needed */
+ if (INTEL_INFO(dev)->gen >= 4) {
+ if (dev_priv->lvds_dither)
+ temp |= LVDS_ENABLE_DITHER;
+ else
+ temp &= ~LVDS_ENABLE_DITHER;
+ }
+ temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
+ if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
+ temp |= LVDS_HSYNC_POLARITY;
+ if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
+ temp |= LVDS_VSYNC_POLARITY;
+ I915_WRITE(LVDS, temp);
+}
+
+static void i9xx_update_pll(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode,
+ intel_clock_t *clock, intel_clock_t *reduced_clock,
+ int num_connectors)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ int pipe = intel_crtc->pipe;
+ u32 dpll;
+ bool is_sdvo;
+
+ is_sdvo = intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO) ||
+ intel_pipe_has_type(crtc, INTEL_OUTPUT_HDMI);
+
+ dpll = DPLL_VGA_MODE_DIS;
+
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
+ dpll |= DPLLB_MODE_LVDS;
+ else
+ dpll |= DPLLB_MODE_DAC_SERIAL;
+ if (is_sdvo) {
+ int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
+ if (pixel_multiplier > 1) {
+ if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+ dpll |= (pixel_multiplier - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
+ }
+ dpll |= DPLL_DVO_HIGH_SPEED;
+ }
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT))
+ dpll |= DPLL_DVO_HIGH_SPEED;
+
+ /* compute bitmask from p1 value */
+ if (IS_PINEVIEW(dev))
+ dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW;
+ else {
+ dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+ if (IS_G4X(dev) && reduced_clock)
+ dpll |= (1 << (reduced_clock->p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
+ }
+ switch (clock->p2) {
+ case 5:
+ dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
+ break;
+ case 7:
+ dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
+ break;
+ case 10:
+ dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
+ break;
+ case 14:
+ dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
+ break;
+ }
+ if (INTEL_INFO(dev)->gen >= 4)
+ dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
+
+ if (is_sdvo && intel_pipe_has_type(crtc, INTEL_OUTPUT_TVOUT))
+ dpll |= PLL_REF_INPUT_TVCLKINBC;
+ else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_TVOUT))
+ /* XXX: just matching BIOS for now */
+ /* dpll |= PLL_REF_INPUT_TVCLKINBC; */
+ dpll |= 3;
+ else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+ intel_panel_use_ssc(dev_priv) && num_connectors < 2)
+ dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
+ else
+ dpll |= PLL_REF_INPUT_DREFCLK;
+
+ dpll |= DPLL_VCO_ENABLE;
+ I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
+ POSTING_READ(DPLL(pipe));
+ udelay(150);
+
+ /* The LVDS pin pair needs to be on before the DPLLs are enabled.
+ * This is an exception to the general rule that mode_set doesn't turn
+ * things on.
+ */
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
+ intel_update_lvds(crtc, clock, adjusted_mode);
+
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT))
+ intel_dp_set_m_n(crtc, mode, adjusted_mode);
+
+ I915_WRITE(DPLL(pipe), dpll);
+
+ /* Wait for the clocks to stabilize. */
+ POSTING_READ(DPLL(pipe));
+ udelay(150);
+
+ if (INTEL_INFO(dev)->gen >= 4) {
+ u32 temp = 0;
+ if (is_sdvo) {
+ temp = intel_mode_get_pixel_multiplier(adjusted_mode);
+ if (temp > 1)
+ temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
+ else
+ temp = 0;
+ }
+ I915_WRITE(DPLL_MD(pipe), temp);
+ } else {
+ /* The pixel multiplier can only be updated once the
+ * DPLL is enabled and the clocks are stable.
+ *
+ * So write it again.
+ */
+ I915_WRITE(DPLL(pipe), dpll);
+ }
+}
+
+static void i8xx_update_pll(struct drm_crtc *crtc,
+ struct drm_display_mode *adjusted_mode,
+ intel_clock_t *clock,
+ int num_connectors)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ int pipe = intel_crtc->pipe;
+ u32 dpll;
+
+ dpll = DPLL_VGA_MODE_DIS;
+
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
+ dpll |= (1 << (clock->p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+ } else {
+ if (clock->p1 == 2)
+ dpll |= PLL_P1_DIVIDE_BY_TWO;
+ else
+ dpll |= (clock->p1 - 2) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+ if (clock->p2 == 4)
+ dpll |= PLL_P2_DIVIDE_BY_4;
+ }
+
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_TVOUT))
+ /* XXX: just matching BIOS for now */
+ /* dpll |= PLL_REF_INPUT_TVCLKINBC; */
+ dpll |= 3;
+ else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+ intel_panel_use_ssc(dev_priv) && num_connectors < 2)
+ dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
+ else
+ dpll |= PLL_REF_INPUT_DREFCLK;
+
+ dpll |= DPLL_VCO_ENABLE;
+ I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
+ POSTING_READ(DPLL(pipe));
+ udelay(150);
+
+ I915_WRITE(DPLL(pipe), dpll);
+
+ /* Wait for the clocks to stabilize. */
+ POSTING_READ(DPLL(pipe));
+ udelay(150);
+
+ /* The LVDS pin pair needs to be on before the DPLLs are enabled.
+ * This is an exception to the general rule that mode_set doesn't turn
+ * things on.
+ */
+ if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS))
+ intel_update_lvds(crtc, clock, adjusted_mode);
+
+ /* The pixel multiplier can only be updated once the
+ * DPLL is enabled and the clocks are stable.
+ *
+ * So write it again.
+ */
+ I915_WRITE(DPLL(pipe), dpll);
+}
+
static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode,
@@ -5156,15 +3961,13 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
int plane = intel_crtc->plane;
int refclk, num_connectors = 0;
intel_clock_t clock, reduced_clock;
- u32 dpll, dspcntr, pipeconf, vsyncshift;
- bool ok, has_reduced_clock = false, is_sdvo = false, is_dvo = false;
- bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
+ u32 dspcntr, pipeconf, vsyncshift;
+ bool ok, has_reduced_clock = false, is_sdvo = false;
+ bool is_lvds = false, is_tv = false, is_dp = false;
struct drm_mode_config *mode_config = &dev->mode_config;
struct intel_encoder *encoder;
const intel_limit_t *limit;
int ret;
- u32 temp;
- u32 lvds_sync = 0;
list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
if (encoder->base.crtc != crtc)
@@ -5180,15 +3983,9 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
if (encoder->needs_tv_clock)
is_tv = true;
break;
- case INTEL_OUTPUT_DVO:
- is_dvo = true;
- break;
case INTEL_OUTPUT_TVOUT:
is_tv = true;
break;
- case INTEL_OUTPUT_ANALOG:
- is_crt = true;
- break;
case INTEL_OUTPUT_DISPLAYPORT:
is_dp = true;
break;
@@ -5235,71 +4032,12 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
i9xx_update_pll_dividers(crtc, &clock, has_reduced_clock ?
&reduced_clock : NULL);
- dpll = DPLL_VGA_MODE_DIS;
-
- if (!IS_GEN2(dev)) {
- if (is_lvds)
- dpll |= DPLLB_MODE_LVDS;
- else
- dpll |= DPLLB_MODE_DAC_SERIAL;
- if (is_sdvo) {
- int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
- if (pixel_multiplier > 1) {
- if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
- dpll |= (pixel_multiplier - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
- }
- dpll |= DPLL_DVO_HIGH_SPEED;
- }
- if (is_dp)
- dpll |= DPLL_DVO_HIGH_SPEED;
-
- /* compute bitmask from p1 value */
- if (IS_PINEVIEW(dev))
- dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW;
- else {
- dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
- if (IS_G4X(dev) && has_reduced_clock)
- dpll |= (1 << (reduced_clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
- }
- switch (clock.p2) {
- case 5:
- dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
- break;
- case 7:
- dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
- break;
- case 10:
- dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
- break;
- case 14:
- dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
- break;
- }
- if (INTEL_INFO(dev)->gen >= 4)
- dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
- } else {
- if (is_lvds) {
- dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
- } else {
- if (clock.p1 == 2)
- dpll |= PLL_P1_DIVIDE_BY_TWO;
- else
- dpll |= (clock.p1 - 2) << DPLL_FPA01_P1_POST_DIV_SHIFT;
- if (clock.p2 == 4)
- dpll |= PLL_P2_DIVIDE_BY_4;
- }
- }
-
- if (is_sdvo && is_tv)
- dpll |= PLL_REF_INPUT_TVCLKINBC;
- else if (is_tv)
- /* XXX: just matching BIOS for now */
- /* dpll |= PLL_REF_INPUT_TVCLKINBC; */
- dpll |= 3;
- else if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2)
- dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
+ if (IS_GEN2(dev))
+ i8xx_update_pll(crtc, adjusted_mode, &clock, num_connectors);
else
- dpll |= PLL_REF_INPUT_DREFCLK;
+ i9xx_update_pll(crtc, mode, adjusted_mode, &clock,
+ has_reduced_clock ? &reduced_clock : NULL,
+ num_connectors);
/* setup pipeconf */
pipeconf = I915_READ(PIPECONF(pipe));
@@ -5336,97 +4074,9 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
}
}
- dpll |= DPLL_VCO_ENABLE;
-
DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
drm_mode_debug_printmodeline(mode);
- I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
-
- POSTING_READ(DPLL(pipe));
- udelay(150);
-
- /* The LVDS pin pair needs to be on before the DPLLs are enabled.
- * This is an exception to the general rule that mode_set doesn't turn
- * things on.
- */
- if (is_lvds) {
- temp = I915_READ(LVDS);
- temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
- if (pipe == 1) {
- temp |= LVDS_PIPEB_SELECT;
- } else {
- temp &= ~LVDS_PIPEB_SELECT;
- }
- /* set the corresponsding LVDS_BORDER bit */
- temp |= dev_priv->lvds_border_bits;
- /* Set the B0-B3 data pairs corresponding to whether we're going to
- * set the DPLLs for dual-channel mode or not.
- */
- if (clock.p2 == 7)
- temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
- else
- temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
-
- /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP)
- * appropriately here, but we need to look more thoroughly into how
- * panels behave in the two modes.
- */
- /* set the dithering flag on LVDS as needed */
- if (INTEL_INFO(dev)->gen >= 4) {
- if (dev_priv->lvds_dither)
- temp |= LVDS_ENABLE_DITHER;
- else
- temp &= ~LVDS_ENABLE_DITHER;
- }
- if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
- lvds_sync |= LVDS_HSYNC_POLARITY;
- if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
- lvds_sync |= LVDS_VSYNC_POLARITY;
- if ((temp & (LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY))
- != lvds_sync) {
- char flags[2] = "-+";
- DRM_INFO("Changing LVDS panel from "
- "(%chsync, %cvsync) to (%chsync, %cvsync)\n",
- flags[!(temp & LVDS_HSYNC_POLARITY)],
- flags[!(temp & LVDS_VSYNC_POLARITY)],
- flags[!(lvds_sync & LVDS_HSYNC_POLARITY)],
- flags[!(lvds_sync & LVDS_VSYNC_POLARITY)]);
- temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
- temp |= lvds_sync;
- }
- I915_WRITE(LVDS, temp);
- }
-
- if (is_dp) {
- intel_dp_set_m_n(crtc, mode, adjusted_mode);
- }
-
- I915_WRITE(DPLL(pipe), dpll);
-
- /* Wait for the clocks to stabilize. */
- POSTING_READ(DPLL(pipe));
- udelay(150);
-
- if (INTEL_INFO(dev)->gen >= 4) {
- temp = 0;
- if (is_sdvo) {
- temp = intel_mode_get_pixel_multiplier(adjusted_mode);
- if (temp > 1)
- temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
- else
- temp = 0;
- }
- I915_WRITE(DPLL_MD(pipe), temp);
- } else {
- /* The pixel multiplier can only be updated once the
- * DPLL is enabled and the clocks are stable.
- *
- * So write it again.
- */
- I915_WRITE(DPLL(pipe), dpll);
- }
-
if (HAS_PIPE_CXSR(dev)) {
if (intel_crtc->lowfreq_avail) {
DRM_DEBUG_KMS("enabling CxSR downclocking\n");
@@ -5492,7 +4142,6 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
I915_WRITE(DSPCNTR(plane), dspcntr);
POSTING_READ(DSPCNTR(plane));
- intel_enable_plane(dev_priv, plane, pipe);
ret = intel_pipe_set_base(crtc, x, y, old_fb);
@@ -5668,17 +4317,16 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf;
bool ok, has_reduced_clock = false, is_sdvo = false;
bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
- struct intel_encoder *has_edp_encoder = NULL;
struct drm_mode_config *mode_config = &dev->mode_config;
- struct intel_encoder *encoder;
+ struct intel_encoder *encoder, *edp_encoder = NULL;
const intel_limit_t *limit;
int ret;
struct fdi_m_n m_n = {0};
u32 temp;
- u32 lvds_sync = 0;
int target_clock, pixel_multiplier, lane, link_bw, factor;
unsigned int pipe_bpp;
bool dither;
+ bool is_cpu_edp = false, is_pch_edp = false;
list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
if (encoder->base.crtc != crtc)
@@ -5704,7 +4352,12 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
is_dp = true;
break;
case INTEL_OUTPUT_EDP:
- has_edp_encoder = encoder;
+ is_dp = true;
+ if (intel_encoder_is_pch_edp(&encoder->base))
+ is_pch_edp = true;
+ else
+ is_cpu_edp = true;
+ edp_encoder = encoder;
break;
}
@@ -5767,15 +4420,13 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
lane = 0;
/* CPU eDP doesn't require FDI link, so just set DP M/N
according to current link config */
- if (has_edp_encoder &&
- !intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+ if (is_cpu_edp) {
target_clock = mode->clock;
- intel_edp_link_config(has_edp_encoder,
- &lane, &link_bw);
+ intel_edp_link_config(edp_encoder, &lane, &link_bw);
} else {
/* [e]DP over FDI requires target mode clock
instead of link clock */
- if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
+ if (is_dp)
target_clock = mode->clock;
else
target_clock = adjusted_mode->clock;
@@ -5866,7 +4517,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
}
dpll |= DPLL_DVO_HIGH_SPEED;
}
- if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
+ if (is_dp && !is_cpu_edp)
dpll |= DPLL_DVO_HIGH_SPEED;
/* compute bitmask from p1 value */
@@ -5909,30 +4560,22 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe);
drm_mode_debug_printmodeline(mode);
- /* PCH eDP needs FDI, but CPU eDP does not */
- if (!intel_crtc->no_pll) {
- if (!has_edp_encoder ||
- intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
- I915_WRITE(PCH_FP0(pipe), fp);
- I915_WRITE(PCH_DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
-
- POSTING_READ(PCH_DPLL(pipe));
- udelay(150);
- }
- } else {
- if (dpll == (I915_READ(PCH_DPLL(0)) & 0x7fffffff) &&
- fp == I915_READ(PCH_FP0(0))) {
- intel_crtc->use_pll_a = true;
- DRM_DEBUG_KMS("using pipe a dpll\n");
- } else if (dpll == (I915_READ(PCH_DPLL(1)) & 0x7fffffff) &&
- fp == I915_READ(PCH_FP0(1))) {
- intel_crtc->use_pll_a = false;
- DRM_DEBUG_KMS("using pipe b dpll\n");
- } else {
- DRM_DEBUG_KMS("no matching PLL configuration for pipe 2\n");
+ /* CPU eDP is the only output that doesn't need a PCH PLL of its own on
+ * pre-Haswell/LPT generation */
+ if (HAS_PCH_LPT(dev)) {
+ DRM_DEBUG_KMS("LPT detected: no PLL for pipe %d necessary\n",
+ pipe);
+ } else if (!is_cpu_edp) {
+ struct intel_pch_pll *pll;
+
+ pll = intel_get_pch_pll(intel_crtc, dpll, fp);
+ if (pll == NULL) {
+ DRM_DEBUG_DRIVER("failed to find PLL for pipe %d\n",
+ pipe);
return -EINVAL;
}
- }
+ } else
+ intel_put_pch_pll(intel_crtc);
/* The LVDS pin pair needs to be on before the DPLLs are enabled.
* This is an exception to the general rule that mode_set doesn't turn
@@ -5965,22 +4608,11 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
* appropriately here, but we need to look more thoroughly into how
* panels behave in the two modes.
*/
+ temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
- lvds_sync |= LVDS_HSYNC_POLARITY;
+ temp |= LVDS_HSYNC_POLARITY;
if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
- lvds_sync |= LVDS_VSYNC_POLARITY;
- if ((temp & (LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY))
- != lvds_sync) {
- char flags[2] = "-+";
- DRM_INFO("Changing LVDS panel from "
- "(%chsync, %cvsync) to (%chsync, %cvsync)\n",
- flags[!(temp & LVDS_HSYNC_POLARITY)],
- flags[!(temp & LVDS_VSYNC_POLARITY)],
- flags[!(lvds_sync & LVDS_HSYNC_POLARITY)],
- flags[!(lvds_sync & LVDS_VSYNC_POLARITY)]);
- temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
- temp |= lvds_sync;
- }
+ temp |= LVDS_VSYNC_POLARITY;
I915_WRITE(PCH_LVDS, temp);
}
@@ -5990,7 +4622,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
pipeconf |= PIPECONF_DITHER_EN;
pipeconf |= PIPECONF_DITHER_TYPE_SP;
}
- if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+ if (is_dp && !is_cpu_edp) {
intel_dp_set_m_n(crtc, mode, adjusted_mode);
} else {
/* For non-DP output, clear any trans DP clock recovery setting.*/
@@ -6000,13 +4632,11 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
I915_WRITE(TRANSDPLINK_N1(pipe), 0);
}
- if (!intel_crtc->no_pll &&
- (!has_edp_encoder ||
- intel_encoder_is_pch_edp(&has_edp_encoder->base))) {
- I915_WRITE(PCH_DPLL(pipe), dpll);
+ if (intel_crtc->pch_pll) {
+ I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll);
/* Wait for the clocks to stabilize. */
- POSTING_READ(PCH_DPLL(pipe));
+ POSTING_READ(intel_crtc->pch_pll->pll_reg);
udelay(150);
/* The pixel multiplier can only be updated once the
@@ -6014,20 +4644,20 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
*
* So write it again.
*/
- I915_WRITE(PCH_DPLL(pipe), dpll);
+ I915_WRITE(intel_crtc->pch_pll->pll_reg, dpll);
}
intel_crtc->lowfreq_avail = false;
- if (!intel_crtc->no_pll) {
+ if (intel_crtc->pch_pll) {
if (is_lvds && has_reduced_clock && i915_powersave) {
- I915_WRITE(PCH_FP1(pipe), fp2);
+ I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp2);
intel_crtc->lowfreq_avail = true;
if (HAS_PIPE_CXSR(dev)) {
DRM_DEBUG_KMS("enabling CxSR downclocking\n");
pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
}
} else {
- I915_WRITE(PCH_FP1(pipe), fp);
+ I915_WRITE(intel_crtc->pch_pll->fp1_reg, fp);
if (HAS_PIPE_CXSR(dev)) {
DRM_DEBUG_KMS("disabling CxSR downclocking\n");
pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
@@ -6080,10 +4710,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m);
I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n);
- if (has_edp_encoder &&
- !intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+ if (is_cpu_edp)
ironlake_set_pll_edp(crtc, adjusted_mode->clock);
- }
I915_WRITE(PIPECONF(pipe), pipeconf);
POSTING_READ(PIPECONF(pipe));
@@ -6097,6 +4725,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
intel_update_watermarks(dev);
+ intel_update_linetime_watermarks(dev, pipe, adjusted_mode);
+
return ret;
}
@@ -6451,7 +5081,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
if (!visible && !intel_crtc->cursor_visible)
return;
- if (IS_IVYBRIDGE(dev)) {
+ if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
I915_WRITE(CURPOS_IVB(pipe), pos);
ivb_update_cursor(crtc, base);
} else {
@@ -6461,9 +5091,6 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
else
i9xx_update_cursor(crtc, base);
}
-
- if (visible)
- intel_mark_busy(dev, to_intel_framebuffer(crtc->fb)->obj);
}
static int intel_crtc_cursor_set(struct drm_crtc *crtc,
@@ -6987,7 +5614,6 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
mode->vsync_end = ((vsync & 0xffff0000) >> 16) + 1;
drm_mode_set_name(mode);
- drm_mode_set_crtcinfo(mode, 0);
return mode;
}
@@ -7086,7 +5712,7 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc)
if (!HAS_PIPE_CXSR(dev) && intel_crtc->lowfreq_avail) {
int pipe = intel_crtc->pipe;
int dpll_reg = DPLL(pipe);
- u32 dpll;
+ int dpll;
DRM_DEBUG_DRIVER("downclocking LVDS\n");
@@ -7100,6 +5726,7 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc)
if (!(dpll & DISPLAY_RATE_SELECT_FPA1))
DRM_DEBUG_DRIVER("failed to downclock LVDS!\n");
}
+
}
/**
@@ -7158,12 +5785,16 @@ void intel_mark_busy(struct drm_device *dev, struct drm_i915_gem_object *obj)
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return;
- if (!dev_priv->busy)
+ if (!dev_priv->busy) {
+ intel_sanitize_pm(dev);
dev_priv->busy = true;
- else
+ } else
mod_timer(&dev_priv->idle_timer, jiffies +
msecs_to_jiffies(GPU_IDLE_TIMEOUT));
+ if (obj == NULL)
+ return;
+
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
if (!crtc->fb)
continue;
@@ -7336,18 +5967,19 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
unsigned long offset;
u32 flip_mask;
+ struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
int ret;
- ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv));
+ ret = intel_pin_and_fence_fb_obj(dev, obj, ring);
if (ret)
- goto out;
+ goto err;
/* Offset into the new buffer for cases of shared fbs between CRTCs */
offset = crtc->y * fb->pitches[0] + crtc->x * fb->bits_per_pixel/8;
- ret = BEGIN_LP_RING(6);
+ ret = intel_ring_begin(ring, 6);
if (ret)
- goto out;
+ goto err_unpin;
/* Can't queue multiple flips, so wait for the previous
* one to finish before executing the next.
@@ -7356,15 +5988,19 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
else
flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
- OUT_RING(MI_WAIT_FOR_EVENT | flip_mask);
- OUT_RING(MI_NOOP);
- OUT_RING(MI_DISPLAY_FLIP |
- MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
- OUT_RING(fb->pitches[0]);
- OUT_RING(obj->gtt_offset + offset);
- OUT_RING(0); /* aux display base address, unused */
- ADVANCE_LP_RING();
-out:
+ intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask);
+ intel_ring_emit(ring, MI_NOOP);
+ intel_ring_emit(ring, MI_DISPLAY_FLIP |
+ MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
+ intel_ring_emit(ring, fb->pitches[0]);
+ intel_ring_emit(ring, obj->gtt_offset + offset);
+ intel_ring_emit(ring, 0); /* aux display base address, unused */
+ intel_ring_advance(ring);
+ return 0;
+
+err_unpin:
+ intel_unpin_fb_obj(obj);
+err:
return ret;
}
@@ -7377,33 +6013,38 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
unsigned long offset;
u32 flip_mask;
+ struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
int ret;
- ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv));
+ ret = intel_pin_and_fence_fb_obj(dev, obj, ring);
if (ret)
- goto out;
+ goto err;
/* Offset into the new buffer for cases of shared fbs between CRTCs */
offset = crtc->y * fb->pitches[0] + crtc->x * fb->bits_per_pixel/8;
- ret = BEGIN_LP_RING(6);
+ ret = intel_ring_begin(ring, 6);
if (ret)
- goto out;
+ goto err_unpin;
if (intel_crtc->plane)
flip_mask = MI_WAIT_FOR_PLANE_B_FLIP;
else
flip_mask = MI_WAIT_FOR_PLANE_A_FLIP;
- OUT_RING(MI_WAIT_FOR_EVENT | flip_mask);
- OUT_RING(MI_NOOP);
- OUT_RING(MI_DISPLAY_FLIP_I915 |
- MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
- OUT_RING(fb->pitches[0]);
- OUT_RING(obj->gtt_offset + offset);
- OUT_RING(MI_NOOP);
-
- ADVANCE_LP_RING();
-out:
+ intel_ring_emit(ring, MI_WAIT_FOR_EVENT | flip_mask);
+ intel_ring_emit(ring, MI_NOOP);
+ intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 |
+ MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
+ intel_ring_emit(ring, fb->pitches[0]);
+ intel_ring_emit(ring, obj->gtt_offset + offset);
+ intel_ring_emit(ring, MI_NOOP);
+
+ intel_ring_advance(ring);
+ return 0;
+
+err_unpin:
+ intel_unpin_fb_obj(obj);
+err:
return ret;
}
@@ -7415,24 +6056,25 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
uint32_t pf, pipesrc;
+ struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
int ret;
- ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv));
+ ret = intel_pin_and_fence_fb_obj(dev, obj, ring);
if (ret)
- goto out;
+ goto err;
- ret = BEGIN_LP_RING(4);
+ ret = intel_ring_begin(ring, 4);
if (ret)
- goto out;
+ goto err_unpin;
/* i965+ uses the linear or tiled offsets from the
* Display Registers (which do not change across a page-flip)
* so we need only reprogram the base address.
*/
- OUT_RING(MI_DISPLAY_FLIP |
- MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
- OUT_RING(fb->pitches[0]);
- OUT_RING(obj->gtt_offset | obj->tiling_mode);
+ intel_ring_emit(ring, MI_DISPLAY_FLIP |
+ MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
+ intel_ring_emit(ring, fb->pitches[0]);
+ intel_ring_emit(ring, obj->gtt_offset | obj->tiling_mode);
/* XXX Enabling the panel-fitter across page-flip is so far
* untested on non-native modes, so ignore it for now.
@@ -7440,9 +6082,13 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
*/
pf = 0;
pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
- OUT_RING(pf | pipesrc);
- ADVANCE_LP_RING();
-out:
+ intel_ring_emit(ring, pf | pipesrc);
+ intel_ring_advance(ring);
+ return 0;
+
+err_unpin:
+ intel_unpin_fb_obj(obj);
+err:
return ret;
}
@@ -7453,21 +6099,22 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
uint32_t pf, pipesrc;
int ret;
- ret = intel_pin_and_fence_fb_obj(dev, obj, LP_RING(dev_priv));
+ ret = intel_pin_and_fence_fb_obj(dev, obj, ring);
if (ret)
- goto out;
+ goto err;
- ret = BEGIN_LP_RING(4);
+ ret = intel_ring_begin(ring, 4);
if (ret)
- goto out;
+ goto err_unpin;
- OUT_RING(MI_DISPLAY_FLIP |
- MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
- OUT_RING(fb->pitches[0] | obj->tiling_mode);
- OUT_RING(obj->gtt_offset);
+ intel_ring_emit(ring, MI_DISPLAY_FLIP |
+ MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
+ intel_ring_emit(ring, fb->pitches[0] | obj->tiling_mode);
+ intel_ring_emit(ring, obj->gtt_offset);
/* Contrary to the suggestions in the documentation,
* "Enable Panel Fitter" does not seem to be required when page
@@ -7477,9 +6124,13 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
*/
pf = 0;
pipesrc = I915_READ(PIPESRC(intel_crtc->pipe)) & 0x0fff0fff;
- OUT_RING(pf | pipesrc);
- ADVANCE_LP_RING();
-out:
+ intel_ring_emit(ring, pf | pipesrc);
+ intel_ring_advance(ring);
+ return 0;
+
+err_unpin:
+ intel_unpin_fb_obj(obj);
+err:
return ret;
}
@@ -7501,18 +6152,22 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
ret = intel_pin_and_fence_fb_obj(dev, obj, ring);
if (ret)
- goto out;
+ goto err;
ret = intel_ring_begin(ring, 4);
if (ret)
- goto out;
+ goto err_unpin;
intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | (intel_crtc->plane << 19));
intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode));
intel_ring_emit(ring, (obj->gtt_offset));
intel_ring_emit(ring, (MI_NOOP));
intel_ring_advance(ring);
-out:
+ return 0;
+
+err_unpin:
+ intel_unpin_fb_obj(obj);
+err:
return ret;
}
@@ -7589,6 +6244,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
goto cleanup_pending;
intel_disable_fbc(dev);
+ intel_mark_busy(dev, obj);
mutex_unlock(&dev->struct_mutex);
trace_i915_flip_request(intel_crtc->plane, obj);
@@ -7617,10 +6273,11 @@ static void intel_sanitize_modesetting(struct drm_device *dev,
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 reg, val;
+ int i;
/* Clear any frame start delays used for debugging left by the BIOS */
- for_each_pipe(pipe) {
- reg = PIPECONF(pipe);
+ for_each_pipe(i) {
+ reg = PIPECONF(i);
I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
}
@@ -7690,6 +6347,23 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
.page_flip = intel_crtc_page_flip,
};
+static void intel_pch_pll_init(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int i;
+
+ if (dev_priv->num_pch_pll == 0) {
+ DRM_DEBUG_KMS("No PCH PLLs on this hardware, skipping initialisation\n");
+ return;
+ }
+
+ for (i = 0; i < dev_priv->num_pch_pll; i++) {
+ dev_priv->pch_plls[i].pll_reg = _PCH_DPLL(i);
+ dev_priv->pch_plls[i].fp0_reg = _PCH_FP0(i);
+ dev_priv->pch_plls[i].fp1_reg = _PCH_FP1(i);
+ }
+}
+
static void intel_crtc_init(struct drm_device *dev, int pipe)
{
drm_i915_private_t *dev_priv = dev->dev_private;
@@ -7727,8 +6401,6 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
intel_crtc->bpp = 24; /* default for pre-Ironlake */
if (HAS_PCH_SPLIT(dev)) {
- if (pipe == 2 && IS_IVYBRIDGE(dev))
- intel_crtc->no_pll = true;
intel_helper_funcs.prepare = ironlake_crtc_prepare;
intel_helper_funcs.commit = ironlake_crtc_commit;
} else {
@@ -7747,15 +6419,12 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
struct drm_file *file)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_get_pipe_from_crtc_id *pipe_from_crtc_id = data;
struct drm_mode_object *drmmode_obj;
struct intel_crtc *crtc;
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
+ return -ENODEV;
drmmode_obj = drm_mode_object_find(dev, pipe_from_crtc_id->crtc_id,
DRM_MODE_OBJECT_CRTC);
@@ -7828,12 +6497,31 @@ static void intel_setup_outputs(struct drm_device *dev)
intel_crt_init(dev);
- if (HAS_PCH_SPLIT(dev)) {
+ if (IS_HASWELL(dev)) {
+ int found;
+
+ /* Haswell uses DDI functions to detect digital outputs */
+ found = I915_READ(DDI_BUF_CTL_A) & DDI_INIT_DISPLAY_DETECTED;
+ /* DDI A only supports eDP */
+ if (found)
+ intel_ddi_init(dev, PORT_A);
+
+ /* DDI B, C and D detection is indicated by the SFUSE_STRAP
+ * register */
+ found = I915_READ(SFUSE_STRAP);
+
+ if (found & SFUSE_STRAP_DDIB_DETECTED)
+ intel_ddi_init(dev, PORT_B);
+ if (found & SFUSE_STRAP_DDIC_DETECTED)
+ intel_ddi_init(dev, PORT_C);
+ if (found & SFUSE_STRAP_DDID_DETECTED)
+ intel_ddi_init(dev, PORT_D);
+ } else if (HAS_PCH_SPLIT(dev)) {
int found;
if (I915_READ(HDMIB) & PORT_DETECTED) {
/* PCH SDVOB multiplex with HDMIB */
- found = intel_sdvo_init(dev, PCH_SDVOB);
+ found = intel_sdvo_init(dev, PCH_SDVOB, true);
if (!found)
intel_hdmi_init(dev, HDMIB);
if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED))
@@ -7857,7 +6545,7 @@ static void intel_setup_outputs(struct drm_device *dev)
if (I915_READ(SDVOB) & SDVO_DETECTED) {
DRM_DEBUG_KMS("probing SDVOB\n");
- found = intel_sdvo_init(dev, SDVOB);
+ found = intel_sdvo_init(dev, SDVOB, true);
if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) {
DRM_DEBUG_KMS("probing HDMI on SDVOB\n");
intel_hdmi_init(dev, SDVOB);
@@ -7873,7 +6561,7 @@ static void intel_setup_outputs(struct drm_device *dev)
if (I915_READ(SDVOB) & SDVO_DETECTED) {
DRM_DEBUG_KMS("probing SDVOC\n");
- found = intel_sdvo_init(dev, SDVOC);
+ found = intel_sdvo_init(dev, SDVOC, false);
}
if (!found && (I915_READ(SDVOC) & SDVO_DETECTED)) {
@@ -8002,882 +6690,6 @@ static const struct drm_mode_config_funcs intel_mode_funcs = {
.output_poll_changed = intel_fb_output_poll_changed,
};
-static struct drm_i915_gem_object *
-intel_alloc_context_page(struct drm_device *dev)
-{
- struct drm_i915_gem_object *ctx;
- int ret;
-
- WARN_ON(!mutex_is_locked(&dev->struct_mutex));
-
- ctx = i915_gem_alloc_object(dev, 4096);
- if (!ctx) {
- DRM_DEBUG("failed to alloc power context, RC6 disabled\n");
- return NULL;
- }
-
- ret = i915_gem_object_pin(ctx, 4096, true);
- if (ret) {
- DRM_ERROR("failed to pin power context: %d\n", ret);
- goto err_unref;
- }
-
- ret = i915_gem_object_set_to_gtt_domain(ctx, 1);
- if (ret) {
- DRM_ERROR("failed to set-domain on power context: %d\n", ret);
- goto err_unpin;
- }
-
- return ctx;
-
-err_unpin:
- i915_gem_object_unpin(ctx);
-err_unref:
- drm_gem_object_unreference(&ctx->base);
- mutex_unlock(&dev->struct_mutex);
- return NULL;
-}
-
-bool ironlake_set_drps(struct drm_device *dev, u8 val)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u16 rgvswctl;
-
- rgvswctl = I915_READ16(MEMSWCTL);
- if (rgvswctl & MEMCTL_CMD_STS) {
- DRM_DEBUG("gpu busy, RCS change rejected\n");
- return false; /* still busy with another command */
- }
-
- rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
- (val << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
- I915_WRITE16(MEMSWCTL, rgvswctl);
- POSTING_READ16(MEMSWCTL);
-
- rgvswctl |= MEMCTL_CMD_STS;
- I915_WRITE16(MEMSWCTL, rgvswctl);
-
- return true;
-}
-
-void ironlake_enable_drps(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 rgvmodectl = I915_READ(MEMMODECTL);
- u8 fmax, fmin, fstart, vstart;
-
- /* Enable temp reporting */
- I915_WRITE16(PMMISC, I915_READ(PMMISC) | MCPPCE_EN);
- I915_WRITE16(TSC1, I915_READ(TSC1) | TSE);
-
- /* 100ms RC evaluation intervals */
- I915_WRITE(RCUPEI, 100000);
- I915_WRITE(RCDNEI, 100000);
-
- /* Set max/min thresholds to 90ms and 80ms respectively */
- I915_WRITE(RCBMAXAVG, 90000);
- I915_WRITE(RCBMINAVG, 80000);
-
- I915_WRITE(MEMIHYST, 1);
-
- /* Set up min, max, and cur for interrupt handling */
- fmax = (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT;
- fmin = (rgvmodectl & MEMMODE_FMIN_MASK);
- fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >>
- MEMMODE_FSTART_SHIFT;
-
- vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >>
- PXVFREQ_PX_SHIFT;
-
- dev_priv->fmax = fmax; /* IPS callback will increase this */
- dev_priv->fstart = fstart;
-
- dev_priv->max_delay = fstart;
- dev_priv->min_delay = fmin;
- dev_priv->cur_delay = fstart;
-
- DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n",
- fmax, fmin, fstart);
-
- I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN);
-
- /*
- * Interrupts will be enabled in ironlake_irq_postinstall
- */
-
- I915_WRITE(VIDSTART, vstart);
- POSTING_READ(VIDSTART);
-
- rgvmodectl |= MEMMODE_SWMODE_EN;
- I915_WRITE(MEMMODECTL, rgvmodectl);
-
- if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10))
- DRM_ERROR("stuck trying to change perf mode\n");
- msleep(1);
-
- ironlake_set_drps(dev, fstart);
-
- dev_priv->last_count1 = I915_READ(0x112e4) + I915_READ(0x112e8) +
- I915_READ(0x112e0);
- dev_priv->last_time1 = jiffies_to_msecs(jiffies);
- dev_priv->last_count2 = I915_READ(0x112f4);
- getrawmonotonic(&dev_priv->last_time2);
-}
-
-void ironlake_disable_drps(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u16 rgvswctl = I915_READ16(MEMSWCTL);
-
- /* Ack interrupts, disable EFC interrupt */
- I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN);
- I915_WRITE(MEMINTRSTS, MEMINT_EVAL_CHG);
- I915_WRITE(DEIER, I915_READ(DEIER) & ~DE_PCU_EVENT);
- I915_WRITE(DEIIR, DE_PCU_EVENT);
- I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT);
-
- /* Go back to the starting frequency */
- ironlake_set_drps(dev, dev_priv->fstart);
- msleep(1);
- rgvswctl |= MEMCTL_CMD_STS;
- I915_WRITE(MEMSWCTL, rgvswctl);
- msleep(1);
-
-}
-
-void gen6_set_rps(struct drm_device *dev, u8 val)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 swreq;
-
- swreq = (val & 0x3ff) << 25;
- I915_WRITE(GEN6_RPNSWREQ, swreq);
-}
-
-void gen6_disable_rps(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
- I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
- I915_WRITE(GEN6_PMIER, 0);
- /* Complete PM interrupt masking here doesn't race with the rps work
- * item again unmasking PM interrupts because that is using a different
- * register (PMIMR) to mask PM interrupts. The only risk is in leaving
- * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */
-
- spin_lock_irq(&dev_priv->rps_lock);
- dev_priv->pm_iir = 0;
- spin_unlock_irq(&dev_priv->rps_lock);
-
- I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
-}
-
-static unsigned long intel_pxfreq(u32 vidfreq)
-{
- unsigned long freq;
- int div = (vidfreq & 0x3f0000) >> 16;
- int post = (vidfreq & 0x3000) >> 12;
- int pre = (vidfreq & 0x7);
-
- if (!pre)
- return 0;
-
- freq = ((div * 133333) / ((1<<post) * pre));
-
- return freq;
-}
-
-void intel_init_emon(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 lcfuse;
- u8 pxw[16];
- int i;
-
- /* Disable to program */
- I915_WRITE(ECR, 0);
- POSTING_READ(ECR);
-
- /* Program energy weights for various events */
- I915_WRITE(SDEW, 0x15040d00);
- I915_WRITE(CSIEW0, 0x007f0000);
- I915_WRITE(CSIEW1, 0x1e220004);
- I915_WRITE(CSIEW2, 0x04000004);
-
- for (i = 0; i < 5; i++)
- I915_WRITE(PEW + (i * 4), 0);
- for (i = 0; i < 3; i++)
- I915_WRITE(DEW + (i * 4), 0);
-
- /* Program P-state weights to account for frequency power adjustment */
- for (i = 0; i < 16; i++) {
- u32 pxvidfreq = I915_READ(PXVFREQ_BASE + (i * 4));
- unsigned long freq = intel_pxfreq(pxvidfreq);
- unsigned long vid = (pxvidfreq & PXVFREQ_PX_MASK) >>
- PXVFREQ_PX_SHIFT;
- unsigned long val;
-
- val = vid * vid;
- val *= (freq / 1000);
- val *= 255;
- val /= (127*127*900);
- if (val > 0xff)
- DRM_ERROR("bad pxval: %ld\n", val);
- pxw[i] = val;
- }
- /* Render standby states get 0 weight */
- pxw[14] = 0;
- pxw[15] = 0;
-
- for (i = 0; i < 4; i++) {
- u32 val = (pxw[i*4] << 24) | (pxw[(i*4)+1] << 16) |
- (pxw[(i*4)+2] << 8) | (pxw[(i*4)+3]);
- I915_WRITE(PXW + (i * 4), val);
- }
-
- /* Adjust magic regs to magic values (more experimental results) */
- I915_WRITE(OGW0, 0);
- I915_WRITE(OGW1, 0);
- I915_WRITE(EG0, 0x00007f00);
- I915_WRITE(EG1, 0x0000000e);
- I915_WRITE(EG2, 0x000e0000);
- I915_WRITE(EG3, 0x68000300);
- I915_WRITE(EG4, 0x42000000);
- I915_WRITE(EG5, 0x00140031);
- I915_WRITE(EG6, 0);
- I915_WRITE(EG7, 0);
-
- for (i = 0; i < 8; i++)
- I915_WRITE(PXWL + (i * 4), 0);
-
- /* Enable PMON + select events */
- I915_WRITE(ECR, 0x80000019);
-
- lcfuse = I915_READ(LCFUSE02);
-
- dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK);
-}
-
-static int intel_enable_rc6(struct drm_device *dev)
-{
- /*
- * Respect the kernel parameter if it is set
- */
- if (i915_enable_rc6 >= 0)
- return i915_enable_rc6;
-
- /*
- * Disable RC6 on Ironlake
- */
- if (INTEL_INFO(dev)->gen == 5)
- return 0;
-
- /*
- * Disable rc6 on Sandybridge
- */
- if (INTEL_INFO(dev)->gen == 6) {
- DRM_DEBUG_DRIVER("Sandybridge: deep RC6 disabled\n");
- return INTEL_RC6_ENABLE;
- }
- DRM_DEBUG_DRIVER("RC6 and deep RC6 enabled\n");
- return (INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE);
-}
-
-void gen6_enable_rps(struct drm_i915_private *dev_priv)
-{
- u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
- u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
- u32 pcu_mbox, rc6_mask = 0;
- u32 gtfifodbg;
- int cur_freq, min_freq, max_freq;
- int rc6_mode;
- int i;
-
- /* Here begins a magic sequence of register writes to enable
- * auto-downclocking.
- *
- * Perhaps there might be some value in exposing these to
- * userspace...
- */
- I915_WRITE(GEN6_RC_STATE, 0);
- mutex_lock(&dev_priv->dev->struct_mutex);
-
- /* Clear the DBG now so we don't confuse earlier errors */
- if ((gtfifodbg = I915_READ(GTFIFODBG))) {
- DRM_ERROR("GT fifo had a previous error %x\n", gtfifodbg);
- I915_WRITE(GTFIFODBG, gtfifodbg);
- }
-
- gen6_gt_force_wake_get(dev_priv);
-
- /* disable the counters and set deterministic thresholds */
- I915_WRITE(GEN6_RC_CONTROL, 0);
-
- I915_WRITE(GEN6_RC1_WAKE_RATE_LIMIT, 1000 << 16);
- I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 40 << 16 | 30);
- I915_WRITE(GEN6_RC6pp_WAKE_RATE_LIMIT, 30);
- I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000);
- I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 25);
-
- for (i = 0; i < I915_NUM_RINGS; i++)
- I915_WRITE(RING_MAX_IDLE(dev_priv->ring[i].mmio_base), 10);
-
- I915_WRITE(GEN6_RC_SLEEP, 0);
- I915_WRITE(GEN6_RC1e_THRESHOLD, 1000);
- I915_WRITE(GEN6_RC6_THRESHOLD, 50000);
- I915_WRITE(GEN6_RC6p_THRESHOLD, 100000);
- I915_WRITE(GEN6_RC6pp_THRESHOLD, 64000); /* unused */
-
- rc6_mode = intel_enable_rc6(dev_priv->dev);
- if (rc6_mode & INTEL_RC6_ENABLE)
- rc6_mask |= GEN6_RC_CTL_RC6_ENABLE;
-
- if (rc6_mode & INTEL_RC6p_ENABLE)
- rc6_mask |= GEN6_RC_CTL_RC6p_ENABLE;
-
- if (rc6_mode & INTEL_RC6pp_ENABLE)
- rc6_mask |= GEN6_RC_CTL_RC6pp_ENABLE;
-
- DRM_INFO("Enabling RC6 states: RC6 %s, RC6p %s, RC6pp %s\n",
- (rc6_mode & INTEL_RC6_ENABLE) ? "on" : "off",
- (rc6_mode & INTEL_RC6p_ENABLE) ? "on" : "off",
- (rc6_mode & INTEL_RC6pp_ENABLE) ? "on" : "off");
-
- I915_WRITE(GEN6_RC_CONTROL,
- rc6_mask |
- GEN6_RC_CTL_EI_MODE(1) |
- GEN6_RC_CTL_HW_ENABLE);
-
- I915_WRITE(GEN6_RPNSWREQ,
- GEN6_FREQUENCY(10) |
- GEN6_OFFSET(0) |
- GEN6_AGGRESSIVE_TURBO);
- I915_WRITE(GEN6_RC_VIDEO_FREQ,
- GEN6_FREQUENCY(12));
-
- I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000);
- I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
- 18 << 24 |
- 6 << 16);
- I915_WRITE(GEN6_RP_UP_THRESHOLD, 10000);
- I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 1000000);
- I915_WRITE(GEN6_RP_UP_EI, 100000);
- I915_WRITE(GEN6_RP_DOWN_EI, 5000000);
- I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
- I915_WRITE(GEN6_RP_CONTROL,
- GEN6_RP_MEDIA_TURBO |
- GEN6_RP_MEDIA_HW_MODE |
- GEN6_RP_MEDIA_IS_GFX |
- GEN6_RP_ENABLE |
- GEN6_RP_UP_BUSY_AVG |
- GEN6_RP_DOWN_IDLE_CONT);
-
- if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
- 500))
- DRM_ERROR("timeout waiting for pcode mailbox to become idle\n");
-
- I915_WRITE(GEN6_PCODE_DATA, 0);
- I915_WRITE(GEN6_PCODE_MAILBOX,
- GEN6_PCODE_READY |
- GEN6_PCODE_WRITE_MIN_FREQ_TABLE);
- if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
- 500))
- DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
-
- min_freq = (rp_state_cap & 0xff0000) >> 16;
- max_freq = rp_state_cap & 0xff;
- cur_freq = (gt_perf_status & 0xff00) >> 8;
-
- /* Check for overclock support */
- if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
- 500))
- DRM_ERROR("timeout waiting for pcode mailbox to become idle\n");
- I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_READ_OC_PARAMS);
- pcu_mbox = I915_READ(GEN6_PCODE_DATA);
- if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
- 500))
- DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
- if (pcu_mbox & (1<<31)) { /* OC supported */
- max_freq = pcu_mbox & 0xff;
- DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50);
- }
-
- /* In units of 100MHz */
- dev_priv->max_delay = max_freq;
- dev_priv->min_delay = min_freq;
- dev_priv->cur_delay = cur_freq;
-
- /* requires MSI enabled */
- I915_WRITE(GEN6_PMIER,
- GEN6_PM_MBOX_EVENT |
- GEN6_PM_THERMAL_EVENT |
- GEN6_PM_RP_DOWN_TIMEOUT |
- GEN6_PM_RP_UP_THRESHOLD |
- GEN6_PM_RP_DOWN_THRESHOLD |
- GEN6_PM_RP_UP_EI_EXPIRED |
- GEN6_PM_RP_DOWN_EI_EXPIRED);
- spin_lock_irq(&dev_priv->rps_lock);
- WARN_ON(dev_priv->pm_iir != 0);
- I915_WRITE(GEN6_PMIMR, 0);
- spin_unlock_irq(&dev_priv->rps_lock);
- /* enable all PM interrupts */
- I915_WRITE(GEN6_PMINTRMSK, 0);
-
- gen6_gt_force_wake_put(dev_priv);
- mutex_unlock(&dev_priv->dev->struct_mutex);
-}
-
-void gen6_update_ring_freq(struct drm_i915_private *dev_priv)
-{
- int min_freq = 15;
- int gpu_freq, ia_freq, max_ia_freq;
- int scaling_factor = 180;
-
- max_ia_freq = cpufreq_quick_get_max(0);
- /*
- * Default to measured freq if none found, PCU will ensure we don't go
- * over
- */
- if (!max_ia_freq)
- max_ia_freq = tsc_khz;
-
- /* Convert from kHz to MHz */
- max_ia_freq /= 1000;
-
- mutex_lock(&dev_priv->dev->struct_mutex);
-
- /*
- * For each potential GPU frequency, load a ring frequency we'd like
- * to use for memory access. We do this by specifying the IA frequency
- * the PCU should use as a reference to determine the ring frequency.
- */
- for (gpu_freq = dev_priv->max_delay; gpu_freq >= dev_priv->min_delay;
- gpu_freq--) {
- int diff = dev_priv->max_delay - gpu_freq;
-
- /*
- * For GPU frequencies less than 750MHz, just use the lowest
- * ring freq.
- */
- if (gpu_freq < min_freq)
- ia_freq = 800;
- else
- ia_freq = max_ia_freq - ((diff * scaling_factor) / 2);
- ia_freq = DIV_ROUND_CLOSEST(ia_freq, 100);
-
- I915_WRITE(GEN6_PCODE_DATA,
- (ia_freq << GEN6_PCODE_FREQ_IA_RATIO_SHIFT) |
- gpu_freq);
- I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY |
- GEN6_PCODE_WRITE_MIN_FREQ_TABLE);
- if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) &
- GEN6_PCODE_READY) == 0, 10)) {
- DRM_ERROR("pcode write of freq table timed out\n");
- continue;
- }
- }
-
- mutex_unlock(&dev_priv->dev->struct_mutex);
-}
-
-static void ironlake_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
-
- /* Required for FBC */
- dspclk_gate |= DPFCUNIT_CLOCK_GATE_DISABLE |
- DPFCRUNIT_CLOCK_GATE_DISABLE |
- DPFDUNIT_CLOCK_GATE_DISABLE;
- /* Required for CxSR */
- dspclk_gate |= DPARBUNIT_CLOCK_GATE_DISABLE;
-
- I915_WRITE(PCH_3DCGDIS0,
- MARIUNIT_CLOCK_GATE_DISABLE |
- SVSMUNIT_CLOCK_GATE_DISABLE);
- I915_WRITE(PCH_3DCGDIS1,
- VFMUNIT_CLOCK_GATE_DISABLE);
-
- I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
-
- /*
- * According to the spec the following bits should be set in
- * order to enable memory self-refresh
- * The bit 22/21 of 0x42004
- * The bit 5 of 0x42020
- * The bit 15 of 0x45000
- */
- I915_WRITE(ILK_DISPLAY_CHICKEN2,
- (I915_READ(ILK_DISPLAY_CHICKEN2) |
- ILK_DPARB_GATE | ILK_VSDPFD_FULL));
- I915_WRITE(ILK_DSPCLK_GATE,
- (I915_READ(ILK_DSPCLK_GATE) |
- ILK_DPARB_CLK_GATE));
- I915_WRITE(DISP_ARB_CTL,
- (I915_READ(DISP_ARB_CTL) |
- DISP_FBC_WM_DIS));
- I915_WRITE(WM3_LP_ILK, 0);
- I915_WRITE(WM2_LP_ILK, 0);
- I915_WRITE(WM1_LP_ILK, 0);
-
- /*
- * Based on the document from hardware guys the following bits
- * should be set unconditionally in order to enable FBC.
- * The bit 22 of 0x42000
- * The bit 22 of 0x42004
- * The bit 7,8,9 of 0x42020.
- */
- if (IS_IRONLAKE_M(dev)) {
- I915_WRITE(ILK_DISPLAY_CHICKEN1,
- I915_READ(ILK_DISPLAY_CHICKEN1) |
- ILK_FBCQ_DIS);
- I915_WRITE(ILK_DISPLAY_CHICKEN2,
- I915_READ(ILK_DISPLAY_CHICKEN2) |
- ILK_DPARB_GATE);
- I915_WRITE(ILK_DSPCLK_GATE,
- I915_READ(ILK_DSPCLK_GATE) |
- ILK_DPFC_DIS1 |
- ILK_DPFC_DIS2 |
- ILK_CLK_FBC);
- }
-
- I915_WRITE(ILK_DISPLAY_CHICKEN2,
- I915_READ(ILK_DISPLAY_CHICKEN2) |
- ILK_ELPIN_409_SELECT);
- I915_WRITE(_3D_CHICKEN2,
- _3D_CHICKEN2_WM_READ_PIPELINED << 16 |
- _3D_CHICKEN2_WM_READ_PIPELINED);
-}
-
-static void gen6_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- int pipe;
- uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
-
- I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
-
- I915_WRITE(ILK_DISPLAY_CHICKEN2,
- I915_READ(ILK_DISPLAY_CHICKEN2) |
- ILK_ELPIN_409_SELECT);
-
- I915_WRITE(WM3_LP_ILK, 0);
- I915_WRITE(WM2_LP_ILK, 0);
- I915_WRITE(WM1_LP_ILK, 0);
-
- I915_WRITE(GEN6_UCGCTL1,
- I915_READ(GEN6_UCGCTL1) |
- GEN6_BLBUNIT_CLOCK_GATE_DISABLE);
-
- /* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock
- * gating disable must be set. Failure to set it results in
- * flickering pixels due to Z write ordering failures after
- * some amount of runtime in the Mesa "fire" demo, and Unigine
- * Sanctuary and Tropics, and apparently anything else with
- * alpha test or pixel discard.
- *
- * According to the spec, bit 11 (RCCUNIT) must also be set,
- * but we didn't debug actual testcases to find it out.
- */
- I915_WRITE(GEN6_UCGCTL2,
- GEN6_RCPBUNIT_CLOCK_GATE_DISABLE |
- GEN6_RCCUNIT_CLOCK_GATE_DISABLE);
-
- /*
- * According to the spec the following bits should be
- * set in order to enable memory self-refresh and fbc:
- * The bit21 and bit22 of 0x42000
- * The bit21 and bit22 of 0x42004
- * The bit5 and bit7 of 0x42020
- * The bit14 of 0x70180
- * The bit14 of 0x71180
- */
- I915_WRITE(ILK_DISPLAY_CHICKEN1,
- I915_READ(ILK_DISPLAY_CHICKEN1) |
- ILK_FBCQ_DIS | ILK_PABSTRETCH_DIS);
- I915_WRITE(ILK_DISPLAY_CHICKEN2,
- I915_READ(ILK_DISPLAY_CHICKEN2) |
- ILK_DPARB_GATE | ILK_VSDPFD_FULL);
- I915_WRITE(ILK_DSPCLK_GATE,
- I915_READ(ILK_DSPCLK_GATE) |
- ILK_DPARB_CLK_GATE |
- ILK_DPFD_CLK_GATE);
-
- for_each_pipe(pipe) {
- I915_WRITE(DSPCNTR(pipe),
- I915_READ(DSPCNTR(pipe)) |
- DISPPLANE_TRICKLE_FEED_DISABLE);
- intel_flush_display_plane(dev_priv, pipe);
- }
-}
-
-static void ivybridge_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- int pipe;
- uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
-
- I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
-
- I915_WRITE(WM3_LP_ILK, 0);
- I915_WRITE(WM2_LP_ILK, 0);
- I915_WRITE(WM1_LP_ILK, 0);
-
- /* According to the spec, bit 13 (RCZUNIT) must be set on IVB.
- * This implements the WaDisableRCZUnitClockGating workaround.
- */
- I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE);
-
- I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE);
-
- I915_WRITE(IVB_CHICKEN3,
- CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE |
- CHICKEN3_DGMG_DONE_FIX_DISABLE);
-
- /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */
- I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1,
- GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC);
-
- /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */
- I915_WRITE(GEN7_L3CNTLREG1,
- GEN7_WA_FOR_GEN7_L3_CONTROL);
- I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER,
- GEN7_WA_L3_CHICKEN_MODE);
-
- /* This is required by WaCatErrorRejectionIssue */
- I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
- I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
- GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
-
- for_each_pipe(pipe) {
- I915_WRITE(DSPCNTR(pipe),
- I915_READ(DSPCNTR(pipe)) |
- DISPPLANE_TRICKLE_FEED_DISABLE);
- intel_flush_display_plane(dev_priv, pipe);
- }
-}
-
-static void g4x_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t dspclk_gate;
-
- I915_WRITE(RENCLK_GATE_D1, 0);
- I915_WRITE(RENCLK_GATE_D2, VF_UNIT_CLOCK_GATE_DISABLE |
- GS_UNIT_CLOCK_GATE_DISABLE |
- CL_UNIT_CLOCK_GATE_DISABLE);
- I915_WRITE(RAMCLK_GATE_D, 0);
- dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE |
- OVRUNIT_CLOCK_GATE_DISABLE |
- OVCUNIT_CLOCK_GATE_DISABLE;
- if (IS_GM45(dev))
- dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE;
- I915_WRITE(DSPCLK_GATE_D, dspclk_gate);
-}
-
-static void crestline_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
- I915_WRITE(RENCLK_GATE_D2, 0);
- I915_WRITE(DSPCLK_GATE_D, 0);
- I915_WRITE(RAMCLK_GATE_D, 0);
- I915_WRITE16(DEUC, 0);
-}
-
-static void broadwater_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE |
- I965_RCC_CLOCK_GATE_DISABLE |
- I965_RCPB_CLOCK_GATE_DISABLE |
- I965_ISC_CLOCK_GATE_DISABLE |
- I965_FBC_CLOCK_GATE_DISABLE);
- I915_WRITE(RENCLK_GATE_D2, 0);
-}
-
-static void gen3_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 dstate = I915_READ(D_STATE);
-
- dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING |
- DSTATE_DOT_CLOCK_GATING;
- I915_WRITE(D_STATE, dstate);
-}
-
-static void i85x_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- I915_WRITE(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE);
-}
-
-static void i830_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
-}
-
-static void ibx_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- /*
- * On Ibex Peak and Cougar Point, we need to disable clock
- * gating for the panel power sequencer or it will fail to
- * start up when no ports are active.
- */
- I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
-}
-
-static void cpt_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- int pipe;
-
- /*
- * On Ibex Peak and Cougar Point, we need to disable clock
- * gating for the panel power sequencer or it will fail to
- * start up when no ports are active.
- */
- I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
- I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) |
- DPLS_EDP_PPS_FIX_DIS);
- /* Without this, mode sets may fail silently on FDI */
- for_each_pipe(pipe)
- I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_AUTOTRAIN_GEN_STALL_DIS);
-}
-
-static void ironlake_teardown_rc6(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- if (dev_priv->renderctx) {
- i915_gem_object_unpin(dev_priv->renderctx);
- drm_gem_object_unreference(&dev_priv->renderctx->base);
- dev_priv->renderctx = NULL;
- }
-
- if (dev_priv->pwrctx) {
- i915_gem_object_unpin(dev_priv->pwrctx);
- drm_gem_object_unreference(&dev_priv->pwrctx->base);
- dev_priv->pwrctx = NULL;
- }
-}
-
-static void ironlake_disable_rc6(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- if (I915_READ(PWRCTXA)) {
- /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */
- I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT);
- wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON),
- 50);
-
- I915_WRITE(PWRCTXA, 0);
- POSTING_READ(PWRCTXA);
-
- I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
- POSTING_READ(RSTDBYCTL);
- }
-
- ironlake_teardown_rc6(dev);
-}
-
-static int ironlake_setup_rc6(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- if (dev_priv->renderctx == NULL)
- dev_priv->renderctx = intel_alloc_context_page(dev);
- if (!dev_priv->renderctx)
- return -ENOMEM;
-
- if (dev_priv->pwrctx == NULL)
- dev_priv->pwrctx = intel_alloc_context_page(dev);
- if (!dev_priv->pwrctx) {
- ironlake_teardown_rc6(dev);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-void ironlake_enable_rc6(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- int ret;
-
- /* rc6 disabled by default due to repeated reports of hanging during
- * boot and resume.
- */
- if (!intel_enable_rc6(dev))
- return;
-
- mutex_lock(&dev->struct_mutex);
- ret = ironlake_setup_rc6(dev);
- if (ret) {
- mutex_unlock(&dev->struct_mutex);
- return;
- }
-
- /*
- * GPU can automatically power down the render unit if given a page
- * to save state.
- */
- ret = BEGIN_LP_RING(6);
- if (ret) {
- ironlake_teardown_rc6(dev);
- mutex_unlock(&dev->struct_mutex);
- return;
- }
-
- OUT_RING(MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN);
- OUT_RING(MI_SET_CONTEXT);
- OUT_RING(dev_priv->renderctx->gtt_offset |
- MI_MM_SPACE_GTT |
- MI_SAVE_EXT_STATE_EN |
- MI_RESTORE_EXT_STATE_EN |
- MI_RESTORE_INHIBIT);
- OUT_RING(MI_SUSPEND_FLUSH);
- OUT_RING(MI_NOOP);
- OUT_RING(MI_FLUSH);
- ADVANCE_LP_RING();
-
- /*
- * Wait for the command parser to advance past MI_SET_CONTEXT. The HW
- * does an implicit flush, combined with MI_FLUSH above, it should be
- * safe to assume that renderctx is valid
- */
- ret = intel_wait_ring_idle(LP_RING(dev_priv));
- if (ret) {
- DRM_ERROR("failed to enable ironlake power power savings\n");
- ironlake_teardown_rc6(dev);
- mutex_unlock(&dev->struct_mutex);
- return;
- }
-
- I915_WRITE(PWRCTXA, dev_priv->pwrctx->gtt_offset | PWRCTX_EN);
- I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
- mutex_unlock(&dev->struct_mutex);
-}
-
-void intel_init_clock_gating(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- dev_priv->display.init_clock_gating(dev);
-
- if (dev_priv->display.init_pch_clock_gating)
- dev_priv->display.init_pch_clock_gating(dev);
-}
-
/* Set up chip specific display functions */
static void intel_init_display(struct drm_device *dev)
{
@@ -8887,32 +6699,20 @@ static void intel_init_display(struct drm_device *dev)
if (HAS_PCH_SPLIT(dev)) {
dev_priv->display.dpms = ironlake_crtc_dpms;
dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set;
+ dev_priv->display.off = ironlake_crtc_off;
dev_priv->display.update_plane = ironlake_update_plane;
} else {
dev_priv->display.dpms = i9xx_crtc_dpms;
dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
+ dev_priv->display.off = i9xx_crtc_off;
dev_priv->display.update_plane = i9xx_update_plane;
}
- if (I915_HAS_FBC(dev)) {
- if (HAS_PCH_SPLIT(dev)) {
- dev_priv->display.fbc_enabled = ironlake_fbc_enabled;
- dev_priv->display.enable_fbc = ironlake_enable_fbc;
- dev_priv->display.disable_fbc = ironlake_disable_fbc;
- } else if (IS_GM45(dev)) {
- dev_priv->display.fbc_enabled = g4x_fbc_enabled;
- dev_priv->display.enable_fbc = g4x_enable_fbc;
- dev_priv->display.disable_fbc = g4x_disable_fbc;
- } else if (IS_CRESTLINE(dev)) {
- dev_priv->display.fbc_enabled = i8xx_fbc_enabled;
- dev_priv->display.enable_fbc = i8xx_enable_fbc;
- dev_priv->display.disable_fbc = i8xx_disable_fbc;
- }
- /* 855GM needs testing */
- }
-
/* Returns the core display clock speed */
- if (IS_I945G(dev) || (IS_G33(dev) && !IS_PINEVIEW_M(dev)))
+ if (IS_VALLEYVIEW(dev))
+ dev_priv->display.get_display_clock_speed =
+ valleyview_get_display_clock_speed;
+ else if (IS_I945G(dev) || (IS_G33(dev) && !IS_PINEVIEW_M(dev)))
dev_priv->display.get_display_clock_speed =
i945_get_display_clock_speed;
else if (IS_I915G(dev))
@@ -8934,124 +6734,27 @@ static void intel_init_display(struct drm_device *dev)
dev_priv->display.get_display_clock_speed =
i830_get_display_clock_speed;
- /* For FIFO watermark updates */
if (HAS_PCH_SPLIT(dev)) {
- dev_priv->display.force_wake_get = __gen6_gt_force_wake_get;
- dev_priv->display.force_wake_put = __gen6_gt_force_wake_put;
-
- /* IVB configs may use multi-threaded forcewake */
- if (IS_IVYBRIDGE(dev)) {
- u32 ecobus;
-
- /* A small trick here - if the bios hasn't configured MT forcewake,
- * and if the device is in RC6, then force_wake_mt_get will not wake
- * the device and the ECOBUS read will return zero. Which will be
- * (correctly) interpreted by the test below as MT forcewake being
- * disabled.
- */
- mutex_lock(&dev->struct_mutex);
- __gen6_gt_force_wake_mt_get(dev_priv);
- ecobus = I915_READ_NOTRACE(ECOBUS);
- __gen6_gt_force_wake_mt_put(dev_priv);
- mutex_unlock(&dev->struct_mutex);
-
- if (ecobus & FORCEWAKE_MT_ENABLE) {
- DRM_DEBUG_KMS("Using MT version of forcewake\n");
- dev_priv->display.force_wake_get =
- __gen6_gt_force_wake_mt_get;
- dev_priv->display.force_wake_put =
- __gen6_gt_force_wake_mt_put;
- }
- }
-
- if (HAS_PCH_IBX(dev))
- dev_priv->display.init_pch_clock_gating = ibx_init_clock_gating;
- else if (HAS_PCH_CPT(dev))
- dev_priv->display.init_pch_clock_gating = cpt_init_clock_gating;
-
if (IS_GEN5(dev)) {
- if (I915_READ(MLTR_ILK) & ILK_SRLT_MASK)
- dev_priv->display.update_wm = ironlake_update_wm;
- else {
- DRM_DEBUG_KMS("Failed to get proper latency. "
- "Disable CxSR\n");
- dev_priv->display.update_wm = NULL;
- }
dev_priv->display.fdi_link_train = ironlake_fdi_link_train;
- dev_priv->display.init_clock_gating = ironlake_init_clock_gating;
dev_priv->display.write_eld = ironlake_write_eld;
} else if (IS_GEN6(dev)) {
- if (SNB_READ_WM0_LATENCY()) {
- dev_priv->display.update_wm = sandybridge_update_wm;
- dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm;
- } else {
- DRM_DEBUG_KMS("Failed to read display plane latency. "
- "Disable CxSR\n");
- dev_priv->display.update_wm = NULL;
- }
dev_priv->display.fdi_link_train = gen6_fdi_link_train;
- dev_priv->display.init_clock_gating = gen6_init_clock_gating;
dev_priv->display.write_eld = ironlake_write_eld;
} else if (IS_IVYBRIDGE(dev)) {
/* FIXME: detect B0+ stepping and use auto training */
dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
- if (SNB_READ_WM0_LATENCY()) {
- dev_priv->display.update_wm = sandybridge_update_wm;
- dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm;
- } else {
- DRM_DEBUG_KMS("Failed to read display plane latency. "
- "Disable CxSR\n");
- dev_priv->display.update_wm = NULL;
- }
- dev_priv->display.init_clock_gating = ivybridge_init_clock_gating;
+ dev_priv->display.write_eld = ironlake_write_eld;
+ } else if (IS_HASWELL(dev)) {
+ dev_priv->display.fdi_link_train = hsw_fdi_link_train;
dev_priv->display.write_eld = ironlake_write_eld;
} else
dev_priv->display.update_wm = NULL;
- } else if (IS_PINEVIEW(dev)) {
- if (!intel_get_cxsr_latency(IS_PINEVIEW_G(dev),
- dev_priv->is_ddr3,
- dev_priv->fsb_freq,
- dev_priv->mem_freq)) {
- DRM_INFO("failed to find known CxSR latency "
- "(found ddr%s fsb freq %d, mem freq %d), "
- "disabling CxSR\n",
- (dev_priv->is_ddr3 == 1) ? "3" : "2",
- dev_priv->fsb_freq, dev_priv->mem_freq);
- /* Disable CxSR and never update its watermark again */
- pineview_disable_cxsr(dev);
- dev_priv->display.update_wm = NULL;
- } else
- dev_priv->display.update_wm = pineview_update_wm;
- dev_priv->display.init_clock_gating = gen3_init_clock_gating;
+ } else if (IS_VALLEYVIEW(dev)) {
+ dev_priv->display.force_wake_get = vlv_force_wake_get;
+ dev_priv->display.force_wake_put = vlv_force_wake_put;
} else if (IS_G4X(dev)) {
dev_priv->display.write_eld = g4x_write_eld;
- dev_priv->display.update_wm = g4x_update_wm;
- dev_priv->display.init_clock_gating = g4x_init_clock_gating;
- } else if (IS_GEN4(dev)) {
- dev_priv->display.update_wm = i965_update_wm;
- if (IS_CRESTLINE(dev))
- dev_priv->display.init_clock_gating = crestline_init_clock_gating;
- else if (IS_BROADWATER(dev))
- dev_priv->display.init_clock_gating = broadwater_init_clock_gating;
- } else if (IS_GEN3(dev)) {
- dev_priv->display.update_wm = i9xx_update_wm;
- dev_priv->display.get_fifo_size = i9xx_get_fifo_size;
- dev_priv->display.init_clock_gating = gen3_init_clock_gating;
- } else if (IS_I865G(dev)) {
- dev_priv->display.update_wm = i830_update_wm;
- dev_priv->display.init_clock_gating = i85x_init_clock_gating;
- dev_priv->display.get_fifo_size = i830_get_fifo_size;
- } else if (IS_I85X(dev)) {
- dev_priv->display.update_wm = i9xx_update_wm;
- dev_priv->display.get_fifo_size = i85x_get_fifo_size;
- dev_priv->display.init_clock_gating = i85x_init_clock_gating;
- } else {
- dev_priv->display.update_wm = i830_update_wm;
- dev_priv->display.init_clock_gating = i830_init_clock_gating;
- if (IS_845G(dev))
- dev_priv->display.get_fifo_size = i845_get_fifo_size;
- else
- dev_priv->display.get_fifo_size = i830_get_fifo_size;
}
/* Default just returns -ENODEV to indicate unsupported */
@@ -9090,7 +6793,7 @@ static void quirk_pipea_force(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
dev_priv->quirks |= QUIRK_PIPEA_FORCE;
- DRM_DEBUG_DRIVER("applying pipe a force quirk\n");
+ DRM_INFO("applying pipe a force quirk\n");
}
/*
@@ -9100,6 +6803,18 @@ static void quirk_ssc_force_disable(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
dev_priv->quirks |= QUIRK_LVDS_SSC_DISABLE;
+ DRM_INFO("applying lvds SSC disable quirk\n");
+}
+
+/*
+ * A machine (e.g. Acer Aspire 5734Z) may need to invert the panel backlight
+ * brightness value
+ */
+static void quirk_invert_brightness(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ dev_priv->quirks |= QUIRK_INVERT_BRIGHTNESS;
+ DRM_INFO("applying inverted panel brightness quirk\n");
}
struct intel_quirk {
@@ -9109,7 +6824,7 @@ struct intel_quirk {
void (*hook)(struct drm_device *dev);
};
-struct intel_quirk intel_quirks[] = {
+static struct intel_quirk intel_quirks[] = {
/* HP Mini needs pipe A force quirk (LP: #322104) */
{ 0x27ae, 0x103c, 0x361a, quirk_pipea_force },
@@ -9134,6 +6849,9 @@ struct intel_quirk intel_quirks[] = {
/* Sony Vaio Y cannot use SSC on LVDS */
{ 0x0046, 0x104d, 0x9076, quirk_ssc_force_disable },
+
+ /* Acer Aspire 5734Z must invert backlight brightness */
+ { 0x2a42, 0x1025, 0x0459, quirk_invert_brightness },
};
static void intel_init_quirks(struct drm_device *dev)
@@ -9166,7 +6884,7 @@ static void i915_disable_vga(struct drm_device *dev)
vga_reg = VGACNTRL;
vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO);
- outb(1, VGA_SR_INDEX);
+ outb(SR01, VGA_SR_INDEX);
sr1 = inb(VGA_SR_DATA);
outb(sr1 | 1<<5, VGA_SR_DATA);
vga_put(dev->pdev, VGA_RSRC_LEGACY_IO);
@@ -9176,6 +6894,40 @@ static void i915_disable_vga(struct drm_device *dev)
POSTING_READ(vga_reg);
}
+static void ivb_pch_pwm_override(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ /*
+ * IVB has CPU eDP backlight regs too, set things up to let the
+ * PCH regs control the backlight
+ */
+ I915_WRITE(BLC_PWM_CPU_CTL2, PWM_ENABLE);
+ I915_WRITE(BLC_PWM_CPU_CTL, 0);
+ I915_WRITE(BLC_PWM_PCH_CTL1, PWM_ENABLE | (1<<30));
+}
+
+void intel_modeset_init_hw(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ intel_init_clock_gating(dev);
+
+ if (IS_IRONLAKE_M(dev)) {
+ ironlake_enable_drps(dev);
+ ironlake_enable_rc6(dev);
+ intel_init_emon(dev);
+ }
+
+ if ((IS_GEN6(dev) || IS_GEN7(dev)) && !IS_VALLEYVIEW(dev)) {
+ gen6_enable_rps(dev_priv);
+ gen6_update_ring_freq(dev_priv);
+ }
+
+ if (IS_IVYBRIDGE(dev))
+ ivb_pch_pwm_override(dev);
+}
+
void intel_modeset_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -9189,10 +6941,14 @@ void intel_modeset_init(struct drm_device *dev)
dev->mode_config.preferred_depth = 24;
dev->mode_config.prefer_shadow = 1;
- dev->mode_config.funcs = (void *)&intel_mode_funcs;
+ dev->mode_config.funcs = &intel_mode_funcs;
intel_init_quirks(dev);
+ intel_init_pm(dev);
+
+ intel_prepare_ddi(dev);
+
intel_init_display(dev);
if (IS_GEN2(dev)) {
@@ -9217,22 +6973,12 @@ void intel_modeset_init(struct drm_device *dev)
DRM_DEBUG_KMS("plane %d init failed: %d\n", i, ret);
}
+ intel_pch_pll_init(dev);
+
/* Just disable it once at startup */
i915_disable_vga(dev);
intel_setup_outputs(dev);
- intel_init_clock_gating(dev);
-
- if (IS_IRONLAKE_M(dev)) {
- ironlake_enable_drps(dev);
- intel_init_emon(dev);
- }
-
- if (IS_GEN6(dev) || IS_GEN7(dev)) {
- gen6_enable_rps(dev_priv);
- gen6_update_ring_freq(dev_priv);
- }
-
INIT_WORK(&dev_priv->idle_work, intel_idle_update);
setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
(unsigned long)dev);
@@ -9240,8 +6986,7 @@ void intel_modeset_init(struct drm_device *dev)
void intel_modeset_gem_init(struct drm_device *dev)
{
- if (IS_IRONLAKE_M(dev))
- ironlake_enable_rc6(dev);
+ intel_modeset_init_hw(dev);
intel_setup_overlay(dev);
}
@@ -9271,12 +7016,15 @@ void intel_modeset_cleanup(struct drm_device *dev)
if (IS_IRONLAKE_M(dev))
ironlake_disable_drps(dev);
- if (IS_GEN6(dev) || IS_GEN7(dev))
+ if ((IS_GEN6(dev) || IS_GEN7(dev)) && !IS_VALLEYVIEW(dev))
gen6_disable_rps(dev);
if (IS_IRONLAKE_M(dev))
ironlake_disable_rc6(dev);
+ if (IS_VALLEYVIEW(dev))
+ vlv_init_dpio(dev);
+
mutex_unlock(&dev->struct_mutex);
/* Disable the irq before mode object teardown, for the irq might
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 4b637919f74f..71c7096e3869 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -688,7 +688,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
int lane_count, clock;
int max_lane_count = intel_dp_max_lane_count(intel_dp);
int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0;
- int bpp;
+ int bpp, mode_rate;
static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) {
@@ -702,24 +702,30 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
mode->clock = intel_dp->panel_fixed_mode->clock;
}
+ DRM_DEBUG_KMS("DP link computation with max lane count %i "
+ "max bw %02x pixel clock %iKHz\n",
+ max_lane_count, bws[max_clock], mode->clock);
+
if (!intel_dp_adjust_dithering(intel_dp, mode, adjusted_mode))
return false;
bpp = adjusted_mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 24;
+ mode_rate = intel_dp_link_required(mode->clock, bpp);
for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
for (clock = 0; clock <= max_clock; clock++) {
int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count);
- if (intel_dp_link_required(mode->clock, bpp)
- <= link_avail) {
+ if (mode_rate <= link_avail) {
intel_dp->link_bw = bws[clock];
intel_dp->lane_count = lane_count;
adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw);
- DRM_DEBUG_KMS("Display port link bw %02x lane "
- "count %d clock %d\n",
+ DRM_DEBUG_KMS("DP link bw %02x lane "
+ "count %d clock %d bpp %d\n",
intel_dp->link_bw, intel_dp->lane_count,
- adjusted_mode->clock);
+ adjusted_mode->clock, bpp);
+ DRM_DEBUG_KMS("DP link bw required %i available %i\n",
+ mode_rate, link_avail);
return true;
}
}
@@ -1149,6 +1155,7 @@ static void ironlake_edp_panel_off(struct intel_dp *intel_dp)
DRM_DEBUG_KMS("Turn eDP power off\n");
WARN(intel_dp->want_panel_vdd, "Cannot turn power off while VDD is on\n");
+ ironlake_panel_vdd_off_sync(intel_dp); /* finish any pending work */
pp = ironlake_get_pp_control(dev_priv);
pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE);
@@ -1954,6 +1961,23 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
return false;
}
+static void
+intel_dp_probe_oui(struct intel_dp *intel_dp)
+{
+ u8 buf[3];
+
+ if (!(intel_dp->dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT))
+ return;
+
+ if (intel_dp_aux_native_read_retry(intel_dp, DP_SINK_OUI, buf, 3))
+ DRM_DEBUG_KMS("Sink OUI: %02hx%02hx%02hx\n",
+ buf[0], buf[1], buf[2]);
+
+ if (intel_dp_aux_native_read_retry(intel_dp, DP_BRANCH_OUI, buf, 3))
+ DRM_DEBUG_KMS("Branch OUI: %02hx%02hx%02hx\n",
+ buf[0], buf[1], buf[2]);
+}
+
static bool
intel_dp_get_sink_irq(struct intel_dp *intel_dp, u8 *sink_irq_vector)
{
@@ -2137,6 +2161,8 @@ intel_dp_detect(struct drm_connector *connector, bool force)
if (status != connector_status_connected)
return status;
+ intel_dp_probe_oui(intel_dp);
+
if (intel_dp->force_audio != HDMI_AUDIO_AUTO) {
intel_dp->has_audio = (intel_dp->force_audio == HDMI_AUDIO_ON);
} else {
@@ -2438,6 +2464,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
}
intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
+
connector->interlace_allowed = true;
connector->doublescan_allowed = 0;
@@ -2483,6 +2510,13 @@ intel_dp_init(struct drm_device *dev, int output_reg)
pp_off = I915_READ(PCH_PP_OFF_DELAYS);
pp_div = I915_READ(PCH_PP_DIVISOR);
+ if (!pp_on || !pp_off || !pp_div) {
+ DRM_INFO("bad panel power sequencing delays, disabling panel\n");
+ intel_dp_encoder_destroy(&intel_dp->base.base);
+ intel_dp_destroy(&intel_connector->base);
+ return;
+ }
+
/* Pull timing values out of registers */
cur.t1_t3 = (pp_on & PANEL_POWER_UP_DELAY_MASK) >>
PANEL_POWER_UP_DELAY_SHIFT;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 715afa153025..3e0918834e7e 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -45,6 +45,18 @@
ret__; \
})
+#define wait_for_atomic_us(COND, US) ({ \
+ int i, ret__ = -ETIMEDOUT; \
+ for (i = 0; i < (US); i++) { \
+ if ((COND)) { \
+ ret__ = 0; \
+ break; \
+ } \
+ udelay(1); \
+ } \
+ ret__; \
+})
+
#define wait_for(COND, MS) _wait_for(COND, MS, 1)
#define wait_for_atomic(COND, MS) _wait_for(COND, MS, 0)
@@ -171,8 +183,8 @@ struct intel_crtc {
bool cursor_visible;
unsigned int bpp;
- bool no_pll; /* tertiary pipe for IVB */
- bool use_pll_a;
+ /* We can share PLLs across outputs if the timings match */
+ struct intel_pch_pll *pch_pll;
};
struct intel_plane {
@@ -196,6 +208,25 @@ struct intel_plane {
struct drm_intel_sprite_colorkey *key);
};
+struct intel_watermark_params {
+ unsigned long fifo_size;
+ unsigned long max_wm;
+ unsigned long default_wm;
+ unsigned long guard_size;
+ unsigned long cacheline_size;
+};
+
+struct cxsr_latency {
+ int is_desktop;
+ int is_ddr3;
+ unsigned long fsb_freq;
+ unsigned long mem_freq;
+ unsigned long display_sr;
+ unsigned long display_hpll_disable;
+ unsigned long cursor_sr;
+ unsigned long cursor_hpll_disable;
+};
+
#define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
#define to_intel_connector(x) container_of(x, struct intel_connector, base)
#define to_intel_encoder(x) container_of(x, struct intel_encoder, base)
@@ -207,6 +238,8 @@ struct intel_plane {
#define DIP_TYPE_AVI 0x82
#define DIP_VERSION_AVI 0x2
#define DIP_LEN_AVI 13
+#define DIP_AVI_PR_1 0
+#define DIP_AVI_PR_2 1
#define DIP_TYPE_SPD 0x83
#define DIP_VERSION_SPD 0x1
@@ -240,23 +273,36 @@ struct dip_infoframe {
uint8_t ITC_EC_Q_SC;
/* PB4 - VIC 6:0 */
uint8_t VIC;
- /* PB5 - PR 3:0 */
- uint8_t PR;
+ /* PB5 - YQ 7:6, CN 5:4, PR 3:0 */
+ uint8_t YQ_CN_PR;
/* PB6 to PB13 */
uint16_t top_bar_end;
uint16_t bottom_bar_start;
uint16_t left_bar_end;
uint16_t right_bar_start;
- } avi;
+ } __attribute__ ((packed)) avi;
struct {
uint8_t vn[8];
uint8_t pd[16];
uint8_t sdi;
- } spd;
+ } __attribute__ ((packed)) spd;
uint8_t payload[27];
} __attribute__ ((packed)) body;
} __attribute__((packed));
+struct intel_hdmi {
+ struct intel_encoder base;
+ u32 sdvox_reg;
+ int ddc_bus;
+ int ddi_port;
+ uint32_t color_range;
+ bool has_hdmi_sink;
+ bool has_audio;
+ enum hdmi_force_audio force_audio;
+ void (*write_infoframe)(struct drm_encoder *encoder,
+ struct dip_infoframe *frame);
+};
+
static inline struct drm_crtc *
intel_get_crtc_for_pipe(struct drm_device *dev, int pipe)
{
@@ -296,8 +342,13 @@ extern void intel_attach_broadcast_rgb_property(struct drm_connector *connector)
extern void intel_crt_init(struct drm_device *dev);
extern void intel_hdmi_init(struct drm_device *dev, int sdvox_reg);
-void intel_dip_infoframe_csum(struct dip_infoframe *avi_if);
-extern bool intel_sdvo_init(struct drm_device *dev, int output_device);
+extern struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder);
+extern void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
+ struct drm_display_mode *adjusted_mode);
+extern void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder);
+extern void intel_dip_infoframe_csum(struct dip_infoframe *avi_if);
+extern bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg,
+ bool is_sdvob);
extern void intel_dvo_init(struct drm_device *dev);
extern void intel_tv_init(struct drm_device *dev);
extern void intel_mark_busy(struct drm_device *dev,
@@ -311,6 +362,10 @@ extern bool intel_dpd_is_edp(struct drm_device *dev);
extern void intel_edp_link_config(struct intel_encoder *, int *, int *);
extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder);
extern int intel_plane_init(struct drm_device *dev, enum pipe pipe);
+extern void intel_flush_display_plane(struct drm_i915_private *dev_priv,
+ enum plane plane);
+
+void intel_sanitize_pm(struct drm_device *dev);
/* intel_panel.c */
extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
@@ -368,12 +423,9 @@ extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
u16 *blue, int regno);
extern void intel_enable_clock_gating(struct drm_device *dev);
+extern void ironlake_disable_rc6(struct drm_device *dev);
extern void ironlake_enable_drps(struct drm_device *dev);
extern void ironlake_disable_drps(struct drm_device *dev);
-extern void gen6_enable_rps(struct drm_i915_private *dev_priv);
-extern void gen6_update_ring_freq(struct drm_i915_private *dev_priv);
-extern void gen6_disable_rps(struct drm_device *dev);
-extern void intel_init_emon(struct drm_device *dev);
extern int intel_pin_and_fence_fb_obj(struct drm_device *dev,
struct drm_i915_gem_object *obj,
@@ -411,16 +463,43 @@ extern void intel_init_clock_gating(struct drm_device *dev);
extern void intel_write_eld(struct drm_encoder *encoder,
struct drm_display_mode *mode);
extern void intel_cpt_verify_modeset(struct drm_device *dev, int pipe);
+extern void intel_prepare_ddi(struct drm_device *dev);
+extern void hsw_fdi_link_train(struct drm_crtc *crtc);
+extern void intel_ddi_init(struct drm_device *dev, enum port port);
/* For use by IVB LP watermark workaround in intel_sprite.c */
-extern void sandybridge_update_wm(struct drm_device *dev);
+extern void intel_update_watermarks(struct drm_device *dev);
extern void intel_update_sprite_watermarks(struct drm_device *dev, int pipe,
uint32_t sprite_width,
int pixel_size);
+extern void intel_update_linetime_watermarks(struct drm_device *dev, int pipe,
+ struct drm_display_mode *mode);
extern int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+extern u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg);
+
+/* Power-related functions, located in intel_pm.c */
+extern void intel_init_pm(struct drm_device *dev);
+/* FBC */
+extern bool intel_fbc_enabled(struct drm_device *dev);
+extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval);
+extern void intel_update_fbc(struct drm_device *dev);
+/* IPS */
+extern void intel_gpu_ips_init(struct drm_i915_private *dev_priv);
+extern void intel_gpu_ips_teardown(void);
+
+extern void gen6_enable_rps(struct drm_i915_private *dev_priv);
+extern void gen6_update_ring_freq(struct drm_i915_private *dev_priv);
+extern void gen6_disable_rps(struct drm_device *dev);
+extern void intel_init_emon(struct drm_device *dev);
+
+extern void intel_ddi_dpms(struct drm_encoder *encoder, int mode);
+extern void intel_ddi_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode);
+
#endif /* __INTEL_DRV_H__ */
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
index 020a7d7f744d..60ba50b956f2 100644
--- a/drivers/gpu/drm/i915/intel_dvo.c
+++ b/drivers/gpu/drm/i915/intel_dvo.c
@@ -243,7 +243,7 @@ static int intel_dvo_get_modes(struct drm_connector *connector)
* that's not the case.
*/
intel_ddc_get_modes(connector,
- &dev_priv->gmbus[GMBUS_PORT_DPC].adapter);
+ intel_gmbus_get_adapter(dev_priv, GMBUS_PORT_DPC));
if (!list_empty(&connector->probed_modes))
return 1;
@@ -375,7 +375,7 @@ void intel_dvo_init(struct drm_device *dev)
* special cases, but otherwise default to what's defined
* in the spec.
*/
- if (dvo->gpio != 0)
+ if (intel_gmbus_is_port_valid(dvo->gpio))
gpio = dvo->gpio;
else if (dvo->type == INTEL_DVO_CHIP_LVDS)
gpio = GMBUS_PORT_SSC;
@@ -386,7 +386,7 @@ void intel_dvo_init(struct drm_device *dev)
* It appears that everything is on GPIOE except for panels
* on i830 laptops, which are on GPIOB (DVOA).
*/
- i2c = &dev_priv->gmbus[gpio].adapter;
+ i2c = intel_gmbus_get_adapter(dev_priv, gpio);
intel_dvo->dev = *dvo;
if (!dvo->dev_ops->init(&intel_dvo->dev, i2c))
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 6e9ee33fd412..bf8690720a0c 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -94,7 +94,7 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
mutex_lock(&dev->struct_mutex);
/* Flush everything out, we'll be doing GTT only from now on */
- ret = intel_pin_and_fence_fb_obj(dev, obj, false);
+ ret = intel_pin_and_fence_fb_obj(dev, obj, NULL);
if (ret) {
DRM_ERROR("failed to pin fb: %d\n", ret);
goto out_unref;
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 2d7f47b56b6a..2ead3bf7c21d 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -37,19 +37,7 @@
#include "i915_drm.h"
#include "i915_drv.h"
-struct intel_hdmi {
- struct intel_encoder base;
- u32 sdvox_reg;
- int ddc_bus;
- uint32_t color_range;
- bool has_hdmi_sink;
- bool has_audio;
- enum hdmi_force_audio force_audio;
- void (*write_infoframe)(struct drm_encoder *encoder,
- struct dip_infoframe *frame);
-};
-
-static struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
+struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder)
{
return container_of(encoder, struct intel_hdmi, base.base);
}
@@ -75,108 +63,246 @@ void intel_dip_infoframe_csum(struct dip_infoframe *frame)
frame->checksum = 0x100 - sum;
}
-static u32 intel_infoframe_index(struct dip_infoframe *frame)
+static u32 g4x_infoframe_index(struct dip_infoframe *frame)
{
- u32 flags = 0;
-
switch (frame->type) {
case DIP_TYPE_AVI:
- flags |= VIDEO_DIP_SELECT_AVI;
- break;
+ return VIDEO_DIP_SELECT_AVI;
case DIP_TYPE_SPD:
- flags |= VIDEO_DIP_SELECT_SPD;
- break;
+ return VIDEO_DIP_SELECT_SPD;
default:
DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
- break;
+ return 0;
}
-
- return flags;
}
-static u32 intel_infoframe_flags(struct dip_infoframe *frame)
+static u32 g4x_infoframe_enable(struct dip_infoframe *frame)
{
- u32 flags = 0;
+ switch (frame->type) {
+ case DIP_TYPE_AVI:
+ return VIDEO_DIP_ENABLE_AVI;
+ case DIP_TYPE_SPD:
+ return VIDEO_DIP_ENABLE_SPD;
+ default:
+ DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
+ return 0;
+ }
+}
+static u32 hsw_infoframe_enable(struct dip_infoframe *frame)
+{
switch (frame->type) {
case DIP_TYPE_AVI:
- flags |= VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_FREQ_VSYNC;
- break;
+ return VIDEO_DIP_ENABLE_AVI_HSW;
case DIP_TYPE_SPD:
- flags |= VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_FREQ_VSYNC;
- break;
+ return VIDEO_DIP_ENABLE_SPD_HSW;
default:
DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
- break;
+ return 0;
}
+}
- return flags;
+static u32 hsw_infoframe_data_reg(struct dip_infoframe *frame, enum pipe pipe)
+{
+ switch (frame->type) {
+ case DIP_TYPE_AVI:
+ return HSW_TVIDEO_DIP_AVI_DATA(pipe);
+ case DIP_TYPE_SPD:
+ return HSW_TVIDEO_DIP_SPD_DATA(pipe);
+ default:
+ DRM_DEBUG_DRIVER("unknown info frame type %d\n", frame->type);
+ return 0;
+ }
}
-static void i9xx_write_infoframe(struct drm_encoder *encoder,
- struct dip_infoframe *frame)
+static void g4x_write_infoframe(struct drm_encoder *encoder,
+ struct dip_infoframe *frame)
{
uint32_t *data = (uint32_t *)frame;
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
- u32 port, flags, val = I915_READ(VIDEO_DIP_CTL);
+ u32 val = I915_READ(VIDEO_DIP_CTL);
unsigned i, len = DIP_HEADER_SIZE + frame->len;
-
- /* XXX first guess at handling video port, is this corrent? */
+ val &= ~VIDEO_DIP_PORT_MASK;
if (intel_hdmi->sdvox_reg == SDVOB)
- port = VIDEO_DIP_PORT_B;
+ val |= VIDEO_DIP_PORT_B;
else if (intel_hdmi->sdvox_reg == SDVOC)
- port = VIDEO_DIP_PORT_C;
+ val |= VIDEO_DIP_PORT_C;
else
return;
- flags = intel_infoframe_index(frame);
+ val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
+ val |= g4x_infoframe_index(frame);
- val &= ~VIDEO_DIP_SELECT_MASK;
+ val &= ~g4x_infoframe_enable(frame);
+ val |= VIDEO_DIP_ENABLE;
- I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | val | port | flags);
+ I915_WRITE(VIDEO_DIP_CTL, val);
for (i = 0; i < len; i += 4) {
I915_WRITE(VIDEO_DIP_DATA, *data);
data++;
}
- flags |= intel_infoframe_flags(frame);
+ val |= g4x_infoframe_enable(frame);
+ val &= ~VIDEO_DIP_FREQ_MASK;
+ val |= VIDEO_DIP_FREQ_VSYNC;
- I915_WRITE(VIDEO_DIP_CTL, VIDEO_DIP_ENABLE | val | port | flags);
+ I915_WRITE(VIDEO_DIP_CTL, val);
}
-static void ironlake_write_infoframe(struct drm_encoder *encoder,
- struct dip_infoframe *frame)
+static void ibx_write_infoframe(struct drm_encoder *encoder,
+ struct dip_infoframe *frame)
{
uint32_t *data = (uint32_t *)frame;
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_crtc *crtc = encoder->crtc;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
+ struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
unsigned i, len = DIP_HEADER_SIZE + frame->len;
- u32 flags, val = I915_READ(reg);
+ u32 val = I915_READ(reg);
+
+ val &= ~VIDEO_DIP_PORT_MASK;
+ switch (intel_hdmi->sdvox_reg) {
+ case HDMIB:
+ val |= VIDEO_DIP_PORT_B;
+ break;
+ case HDMIC:
+ val |= VIDEO_DIP_PORT_C;
+ break;
+ case HDMID:
+ val |= VIDEO_DIP_PORT_D;
+ break;
+ default:
+ return;
+ }
intel_wait_for_vblank(dev, intel_crtc->pipe);
- flags = intel_infoframe_index(frame);
+ val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
+ val |= g4x_infoframe_index(frame);
+
+ val &= ~g4x_infoframe_enable(frame);
+ val |= VIDEO_DIP_ENABLE;
+
+ I915_WRITE(reg, val);
+
+ for (i = 0; i < len; i += 4) {
+ I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
+ data++;
+ }
+
+ val |= g4x_infoframe_enable(frame);
+ val &= ~VIDEO_DIP_FREQ_MASK;
+ val |= VIDEO_DIP_FREQ_VSYNC;
+
+ I915_WRITE(reg, val);
+}
+
+static void cpt_write_infoframe(struct drm_encoder *encoder,
+ struct dip_infoframe *frame)
+{
+ uint32_t *data = (uint32_t *)frame;
+ struct drm_device *dev = encoder->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
+ int reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
+ unsigned i, len = DIP_HEADER_SIZE + frame->len;
+ u32 val = I915_READ(reg);
+
+ intel_wait_for_vblank(dev, intel_crtc->pipe);
val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
+ val |= g4x_infoframe_index(frame);
+
+ /* The DIP control register spec says that we need to update the AVI
+ * infoframe without clearing its enable bit */
+ if (frame->type == DIP_TYPE_AVI)
+ val |= VIDEO_DIP_ENABLE_AVI;
+ else
+ val &= ~g4x_infoframe_enable(frame);
+
+ val |= VIDEO_DIP_ENABLE;
- I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags);
+ I915_WRITE(reg, val);
for (i = 0; i < len; i += 4) {
I915_WRITE(TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
data++;
}
- flags |= intel_infoframe_flags(frame);
+ val |= g4x_infoframe_enable(frame);
+ val &= ~VIDEO_DIP_FREQ_MASK;
+ val |= VIDEO_DIP_FREQ_VSYNC;
- I915_WRITE(reg, VIDEO_DIP_ENABLE | val | flags);
+ I915_WRITE(reg, val);
}
+
+static void vlv_write_infoframe(struct drm_encoder *encoder,
+ struct dip_infoframe *frame)
+{
+ uint32_t *data = (uint32_t *)frame;
+ struct drm_device *dev = encoder->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
+ int reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe);
+ unsigned i, len = DIP_HEADER_SIZE + frame->len;
+ u32 val = I915_READ(reg);
+
+ intel_wait_for_vblank(dev, intel_crtc->pipe);
+
+ val &= ~(VIDEO_DIP_SELECT_MASK | 0xf); /* clear DIP data offset */
+ val |= g4x_infoframe_index(frame);
+
+ val &= ~g4x_infoframe_enable(frame);
+ val |= VIDEO_DIP_ENABLE;
+
+ I915_WRITE(reg, val);
+
+ for (i = 0; i < len; i += 4) {
+ I915_WRITE(VLV_TVIDEO_DIP_DATA(intel_crtc->pipe), *data);
+ data++;
+ }
+
+ val |= g4x_infoframe_enable(frame);
+ val &= ~VIDEO_DIP_FREQ_MASK;
+ val |= VIDEO_DIP_FREQ_VSYNC;
+
+ I915_WRITE(reg, val);
+}
+
+static void hsw_write_infoframe(struct drm_encoder *encoder,
+ struct dip_infoframe *frame)
+{
+ uint32_t *data = (uint32_t *)frame;
+ struct drm_device *dev = encoder->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
+ u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->pipe);
+ u32 data_reg = hsw_infoframe_data_reg(frame, intel_crtc->pipe);
+ unsigned int i, len = DIP_HEADER_SIZE + frame->len;
+ u32 val = I915_READ(ctl_reg);
+
+ if (data_reg == 0)
+ return;
+
+ intel_wait_for_vblank(dev, intel_crtc->pipe);
+
+ val &= ~hsw_infoframe_enable(frame);
+ I915_WRITE(ctl_reg, val);
+
+ for (i = 0; i < len; i += 4) {
+ I915_WRITE(data_reg + i, *data);
+ data++;
+ }
+
+ val |= hsw_infoframe_enable(frame);
+ I915_WRITE(ctl_reg, val);
+}
+
static void intel_set_infoframe(struct drm_encoder *encoder,
struct dip_infoframe *frame)
{
@@ -189,7 +315,8 @@ static void intel_set_infoframe(struct drm_encoder *encoder,
intel_hdmi->write_infoframe(encoder, frame);
}
-static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
+void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
+ struct drm_display_mode *adjusted_mode)
{
struct dip_infoframe avi_if = {
.type = DIP_TYPE_AVI,
@@ -197,10 +324,13 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
.len = DIP_LEN_AVI,
};
+ if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK)
+ avi_if.body.avi.YQ_CN_PR |= DIP_AVI_PR_2;
+
intel_set_infoframe(encoder, &avi_if);
}
-static void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
+void intel_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
{
struct dip_infoframe spd_if;
@@ -221,8 +351,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
{
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_crtc *crtc = encoder->crtc;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
u32 sdvox;
@@ -259,7 +388,7 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
I915_WRITE(intel_hdmi->sdvox_reg, sdvox);
POSTING_READ(intel_hdmi->sdvox_reg);
- intel_hdmi_set_avi_infoframe(encoder);
+ intel_hdmi_set_avi_infoframe(encoder, adjusted_mode);
intel_hdmi_set_spd_infoframe(encoder);
}
@@ -334,7 +463,8 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
intel_hdmi->has_hdmi_sink = false;
intel_hdmi->has_audio = false;
edid = drm_get_edid(connector,
- &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter);
+ intel_gmbus_get_adapter(dev_priv,
+ intel_hdmi->ddc_bus));
if (edid) {
if (edid->input & DRM_EDID_INPUT_DIGITAL) {
@@ -367,7 +497,8 @@ static int intel_hdmi_get_modes(struct drm_connector *connector)
*/
return intel_ddc_get_modes(connector,
- &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter);
+ intel_gmbus_get_adapter(dev_priv,
+ intel_hdmi->ddc_bus));
}
static bool
@@ -379,7 +510,8 @@ intel_hdmi_detect_audio(struct drm_connector *connector)
bool has_audio = false;
edid = drm_get_edid(connector,
- &dev_priv->gmbus[intel_hdmi->ddc_bus].adapter);
+ intel_gmbus_get_adapter(dev_priv,
+ intel_hdmi->ddc_bus));
if (edid) {
if (edid->input & DRM_EDID_INPUT_DIGITAL)
has_audio = drm_detect_monitor_audio(edid);
@@ -393,8 +525,8 @@ intel_hdmi_detect_audio(struct drm_connector *connector)
static int
intel_hdmi_set_property(struct drm_connector *connector,
- struct drm_property *property,
- uint64_t val)
+ struct drm_property *property,
+ uint64_t val)
{
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
struct drm_i915_private *dev_priv = connector->dev->dev_private;
@@ -453,6 +585,14 @@ static void intel_hdmi_destroy(struct drm_connector *connector)
kfree(connector);
}
+static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs_hsw = {
+ .dpms = intel_ddi_dpms,
+ .mode_fixup = intel_hdmi_mode_fixup,
+ .prepare = intel_encoder_prepare,
+ .mode_set = intel_ddi_mode_set,
+ .commit = intel_encoder_commit,
+};
+
static const struct drm_encoder_helper_funcs intel_hdmi_helper_funcs = {
.dpms = intel_hdmi_dpms,
.mode_fixup = intel_hdmi_mode_fixup,
@@ -542,20 +682,60 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
intel_encoder->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT);
intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
+ } else if (sdvox_reg == DDI_BUF_CTL(PORT_B)) {
+ DRM_DEBUG_DRIVER("LPT: detected output on DDI B\n");
+ intel_encoder->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
+ intel_hdmi->ddc_bus = GMBUS_PORT_DPB;
+ intel_hdmi->ddi_port = PORT_B;
+ dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
+ } else if (sdvox_reg == DDI_BUF_CTL(PORT_C)) {
+ DRM_DEBUG_DRIVER("LPT: detected output on DDI C\n");
+ intel_encoder->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
+ intel_hdmi->ddc_bus = GMBUS_PORT_DPC;
+ intel_hdmi->ddi_port = PORT_C;
+ dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
+ } else if (sdvox_reg == DDI_BUF_CTL(PORT_D)) {
+ DRM_DEBUG_DRIVER("LPT: detected output on DDI D\n");
+ intel_encoder->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
+ intel_hdmi->ddc_bus = GMBUS_PORT_DPD;
+ intel_hdmi->ddi_port = PORT_D;
+ dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
+ } else {
+ /* If we got an unknown sdvox_reg, things are pretty much broken
+ * in a way that we should let the kernel know about it */
+ BUG();
}
intel_hdmi->sdvox_reg = sdvox_reg;
if (!HAS_PCH_SPLIT(dev)) {
- intel_hdmi->write_infoframe = i9xx_write_infoframe;
+ intel_hdmi->write_infoframe = g4x_write_infoframe;
I915_WRITE(VIDEO_DIP_CTL, 0);
+ } else if (IS_VALLEYVIEW(dev)) {
+ intel_hdmi->write_infoframe = vlv_write_infoframe;
+ for_each_pipe(i)
+ I915_WRITE(VLV_TVIDEO_DIP_CTL(i), 0);
+ } else if (IS_HASWELL(dev)) {
+ /* FIXME: Haswell has a new set of DIP frame registers, but we are
+ * just doing the minimal required for HDMI to work at this stage.
+ */
+ intel_hdmi->write_infoframe = hsw_write_infoframe;
+ for_each_pipe(i)
+ I915_WRITE(HSW_TVIDEO_DIP_CTL(i), 0);
+ } else if (HAS_PCH_IBX(dev)) {
+ intel_hdmi->write_infoframe = ibx_write_infoframe;
+ for_each_pipe(i)
+ I915_WRITE(TVIDEO_DIP_CTL(i), 0);
} else {
- intel_hdmi->write_infoframe = ironlake_write_infoframe;
+ intel_hdmi->write_infoframe = cpt_write_infoframe;
for_each_pipe(i)
I915_WRITE(TVIDEO_DIP_CTL(i), 0);
}
- drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
+ if (IS_HASWELL(dev))
+ drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs_hsw);
+ else
+ drm_encoder_helper_add(&intel_encoder->base, &intel_hdmi_helper_funcs);
intel_hdmi_add_properties(intel_hdmi, connector);
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index 8fdc95700218..4a9707dd0f9c 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -35,6 +35,20 @@
#include "i915_drm.h"
#include "i915_drv.h"
+struct gmbus_port {
+ const char *name;
+ int reg;
+};
+
+static const struct gmbus_port gmbus_ports[] = {
+ { "ssc", GPIOB },
+ { "vga", GPIOA },
+ { "panel", GPIOC },
+ { "dpc", GPIOD },
+ { "dpb", GPIOE },
+ { "dpd", GPIOF },
+};
+
/* Intel GPIO access functions */
#define I2C_RISEFALL_TIME 10
@@ -49,10 +63,7 @@ void
intel_i2c_reset(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- if (HAS_PCH_SPLIT(dev))
- I915_WRITE(PCH_GMBUS0, 0);
- else
- I915_WRITE(GMBUS0, 0);
+ I915_WRITE(dev_priv->gpio_mmio_base + GMBUS0, 0);
}
static void intel_i2c_quirk_set(struct drm_i915_private *dev_priv, bool enable)
@@ -140,63 +151,173 @@ static void set_data(void *data, int state_high)
POSTING_READ(bus->gpio_reg);
}
-static bool
+static int
+intel_gpio_pre_xfer(struct i2c_adapter *adapter)
+{
+ struct intel_gmbus *bus = container_of(adapter,
+ struct intel_gmbus,
+ adapter);
+ struct drm_i915_private *dev_priv = bus->dev_priv;
+
+ intel_i2c_reset(dev_priv->dev);
+ intel_i2c_quirk_set(dev_priv, true);
+ set_data(bus, 1);
+ set_clock(bus, 1);
+ udelay(I2C_RISEFALL_TIME);
+ return 0;
+}
+
+static void
+intel_gpio_post_xfer(struct i2c_adapter *adapter)
+{
+ struct intel_gmbus *bus = container_of(adapter,
+ struct intel_gmbus,
+ adapter);
+ struct drm_i915_private *dev_priv = bus->dev_priv;
+
+ set_data(bus, 1);
+ set_clock(bus, 1);
+ intel_i2c_quirk_set(dev_priv, false);
+}
+
+static void
intel_gpio_setup(struct intel_gmbus *bus, u32 pin)
{
struct drm_i915_private *dev_priv = bus->dev_priv;
- static const int map_pin_to_reg[] = {
- 0,
- GPIOB,
- GPIOA,
- GPIOC,
- GPIOD,
- GPIOE,
- 0,
- GPIOF,
- };
struct i2c_algo_bit_data *algo;
- if (pin >= ARRAY_SIZE(map_pin_to_reg) || !map_pin_to_reg[pin])
- return false;
-
algo = &bus->bit_algo;
- bus->gpio_reg = map_pin_to_reg[pin];
- if (HAS_PCH_SPLIT(dev_priv->dev))
- bus->gpio_reg += PCH_GPIOA - GPIOA;
+ /* -1 to map pin pair to gmbus index */
+ bus->gpio_reg = dev_priv->gpio_mmio_base + gmbus_ports[pin - 1].reg;
bus->adapter.algo_data = algo;
algo->setsda = set_data;
algo->setscl = set_clock;
algo->getsda = get_data;
algo->getscl = get_clock;
+ algo->pre_xfer = intel_gpio_pre_xfer;
+ algo->post_xfer = intel_gpio_post_xfer;
algo->udelay = I2C_RISEFALL_TIME;
algo->timeout = usecs_to_jiffies(2200);
algo->data = bus;
+}
+
+static int
+gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg,
+ u32 gmbus1_index)
+{
+ int reg_offset = dev_priv->gpio_mmio_base;
+ u16 len = msg->len;
+ u8 *buf = msg->buf;
+
+ I915_WRITE(GMBUS1 + reg_offset,
+ gmbus1_index |
+ GMBUS_CYCLE_WAIT |
+ (len << GMBUS_BYTE_COUNT_SHIFT) |
+ (msg->addr << GMBUS_SLAVE_ADDR_SHIFT) |
+ GMBUS_SLAVE_READ | GMBUS_SW_RDY);
+ while (len) {
+ int ret;
+ u32 val, loop = 0;
+ u32 gmbus2;
+
+ ret = wait_for((gmbus2 = I915_READ(GMBUS2 + reg_offset)) &
+ (GMBUS_SATOER | GMBUS_HW_RDY),
+ 50);
+ if (ret)
+ return -ETIMEDOUT;
+ if (gmbus2 & GMBUS_SATOER)
+ return -ENXIO;
+
+ val = I915_READ(GMBUS3 + reg_offset);
+ do {
+ *buf++ = val & 0xff;
+ val >>= 8;
+ } while (--len && ++loop < 4);
+ }
- return true;
+ return 0;
}
static int
-intel_i2c_quirk_xfer(struct intel_gmbus *bus,
- struct i2c_msg *msgs,
- int num)
+gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg)
{
- struct drm_i915_private *dev_priv = bus->dev_priv;
+ int reg_offset = dev_priv->gpio_mmio_base;
+ u16 len = msg->len;
+ u8 *buf = msg->buf;
+ u32 val, loop;
+
+ val = loop = 0;
+ while (len && loop < 4) {
+ val |= *buf++ << (8 * loop++);
+ len -= 1;
+ }
+
+ I915_WRITE(GMBUS3 + reg_offset, val);
+ I915_WRITE(GMBUS1 + reg_offset,
+ GMBUS_CYCLE_WAIT |
+ (msg->len << GMBUS_BYTE_COUNT_SHIFT) |
+ (msg->addr << GMBUS_SLAVE_ADDR_SHIFT) |
+ GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
+ while (len) {
+ int ret;
+ u32 gmbus2;
+
+ val = loop = 0;
+ do {
+ val |= *buf++ << (8 * loop);
+ } while (--len && ++loop < 4);
+
+ I915_WRITE(GMBUS3 + reg_offset, val);
+
+ ret = wait_for((gmbus2 = I915_READ(GMBUS2 + reg_offset)) &
+ (GMBUS_SATOER | GMBUS_HW_RDY),
+ 50);
+ if (ret)
+ return -ETIMEDOUT;
+ if (gmbus2 & GMBUS_SATOER)
+ return -ENXIO;
+ }
+ return 0;
+}
+
+/*
+ * The gmbus controller can combine a 1 or 2 byte write with a read that
+ * immediately follows it by using an "INDEX" cycle.
+ */
+static bool
+gmbus_is_index_read(struct i2c_msg *msgs, int i, int num)
+{
+ return (i + 1 < num &&
+ !(msgs[i].flags & I2C_M_RD) && msgs[i].len <= 2 &&
+ (msgs[i + 1].flags & I2C_M_RD));
+}
+
+static int
+gmbus_xfer_index_read(struct drm_i915_private *dev_priv, struct i2c_msg *msgs)
+{
+ int reg_offset = dev_priv->gpio_mmio_base;
+ u32 gmbus1_index = 0;
+ u32 gmbus5 = 0;
int ret;
- intel_i2c_reset(dev_priv->dev);
+ if (msgs[0].len == 2)
+ gmbus5 = GMBUS_2BYTE_INDEX_EN |
+ msgs[0].buf[1] | (msgs[0].buf[0] << 8);
+ if (msgs[0].len == 1)
+ gmbus1_index = GMBUS_CYCLE_INDEX |
+ (msgs[0].buf[0] << GMBUS_SLAVE_INDEX_SHIFT);
- intel_i2c_quirk_set(dev_priv, true);
- set_data(bus, 1);
- set_clock(bus, 1);
- udelay(I2C_RISEFALL_TIME);
+ /* GMBUS5 holds 16-bit index */
+ if (gmbus5)
+ I915_WRITE(GMBUS5 + reg_offset, gmbus5);
- ret = i2c_bit_algo.master_xfer(&bus->adapter, msgs, num);
+ ret = gmbus_xfer_read(dev_priv, &msgs[1], gmbus1_index);
- set_data(bus, 1);
- set_clock(bus, 1);
- intel_i2c_quirk_set(dev_priv, false);
+ /* Clear GMBUS5 after each index transfer */
+ if (gmbus5)
+ I915_WRITE(GMBUS5 + reg_offset, 0);
return ret;
}
@@ -210,117 +331,108 @@ gmbus_xfer(struct i2c_adapter *adapter,
struct intel_gmbus,
adapter);
struct drm_i915_private *dev_priv = bus->dev_priv;
- int i, reg_offset, ret;
+ int i, reg_offset;
+ int ret = 0;
mutex_lock(&dev_priv->gmbus_mutex);
if (bus->force_bit) {
- ret = intel_i2c_quirk_xfer(bus, msgs, num);
+ ret = i2c_bit_algo.master_xfer(adapter, msgs, num);
goto out;
}
- reg_offset = HAS_PCH_SPLIT(dev_priv->dev) ? PCH_GMBUS0 - GMBUS0 : 0;
+ reg_offset = dev_priv->gpio_mmio_base;
I915_WRITE(GMBUS0 + reg_offset, bus->reg0);
for (i = 0; i < num; i++) {
- u16 len = msgs[i].len;
- u8 *buf = msgs[i].buf;
-
- if (msgs[i].flags & I2C_M_RD) {
- I915_WRITE(GMBUS1 + reg_offset,
- GMBUS_CYCLE_WAIT |
- (i + 1 == num ? GMBUS_CYCLE_STOP : 0) |
- (len << GMBUS_BYTE_COUNT_SHIFT) |
- (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) |
- GMBUS_SLAVE_READ | GMBUS_SW_RDY);
- POSTING_READ(GMBUS2+reg_offset);
- do {
- u32 val, loop = 0;
-
- if (wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50))
- goto timeout;
- if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
- goto clear_err;
-
- val = I915_READ(GMBUS3 + reg_offset);
- do {
- *buf++ = val & 0xff;
- val >>= 8;
- } while (--len && ++loop < 4);
- } while (len);
+ u32 gmbus2;
+
+ if (gmbus_is_index_read(msgs, i, num)) {
+ ret = gmbus_xfer_index_read(dev_priv, &msgs[i]);
+ i += 1; /* set i to the index of the read xfer */
+ } else if (msgs[i].flags & I2C_M_RD) {
+ ret = gmbus_xfer_read(dev_priv, &msgs[i], 0);
} else {
- u32 val, loop;
-
- val = loop = 0;
- do {
- val |= *buf++ << (8 * loop);
- } while (--len && ++loop < 4);
-
- I915_WRITE(GMBUS3 + reg_offset, val);
- I915_WRITE(GMBUS1 + reg_offset,
- GMBUS_CYCLE_WAIT |
- (i + 1 == num ? GMBUS_CYCLE_STOP : 0) |
- (msgs[i].len << GMBUS_BYTE_COUNT_SHIFT) |
- (msgs[i].addr << GMBUS_SLAVE_ADDR_SHIFT) |
- GMBUS_SLAVE_WRITE | GMBUS_SW_RDY);
- POSTING_READ(GMBUS2+reg_offset);
-
- while (len) {
- if (wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_RDY), 50))
- goto timeout;
- if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
- goto clear_err;
-
- val = loop = 0;
- do {
- val |= *buf++ << (8 * loop);
- } while (--len && ++loop < 4);
-
- I915_WRITE(GMBUS3 + reg_offset, val);
- POSTING_READ(GMBUS2+reg_offset);
- }
+ ret = gmbus_xfer_write(dev_priv, &msgs[i]);
}
- if (i + 1 < num && wait_for(I915_READ(GMBUS2 + reg_offset) & (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE), 50))
+ if (ret == -ETIMEDOUT)
+ goto timeout;
+ if (ret == -ENXIO)
+ goto clear_err;
+
+ ret = wait_for((gmbus2 = I915_READ(GMBUS2 + reg_offset)) &
+ (GMBUS_SATOER | GMBUS_HW_WAIT_PHASE),
+ 50);
+ if (ret)
goto timeout;
- if (I915_READ(GMBUS2 + reg_offset) & GMBUS_SATOER)
+ if (gmbus2 & GMBUS_SATOER)
goto clear_err;
}
- goto done;
+ /* Generate a STOP condition on the bus. Note that gmbus can't generata
+ * a STOP on the very first cycle. To simplify the code we
+ * unconditionally generate the STOP condition with an additional gmbus
+ * cycle. */
+ I915_WRITE(GMBUS1 + reg_offset, GMBUS_CYCLE_STOP | GMBUS_SW_RDY);
+
+ /* Mark the GMBUS interface as disabled after waiting for idle.
+ * We will re-enable it at the start of the next xfer,
+ * till then let it sleep.
+ */
+ if (wait_for((I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0,
+ 10)) {
+ DRM_DEBUG_KMS("GMBUS [%s] timed out waiting for idle\n",
+ adapter->name);
+ ret = -ETIMEDOUT;
+ }
+ I915_WRITE(GMBUS0 + reg_offset, 0);
+ ret = ret ?: i;
+ goto out;
clear_err:
+ /*
+ * Wait for bus to IDLE before clearing NAK.
+ * If we clear the NAK while bus is still active, then it will stay
+ * active and the next transaction may fail.
+ */
+ if (wait_for((I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0,
+ 10))
+ DRM_DEBUG_KMS("GMBUS [%s] timed out after NAK\n",
+ adapter->name);
+
/* Toggle the Software Clear Interrupt bit. This has the effect
* of resetting the GMBUS controller and so clearing the
* BUS_ERROR raised by the slave's NAK.
*/
I915_WRITE(GMBUS1 + reg_offset, GMBUS_SW_CLR_INT);
I915_WRITE(GMBUS1 + reg_offset, 0);
+ I915_WRITE(GMBUS0 + reg_offset, 0);
-done:
- /* Mark the GMBUS interface as disabled after waiting for idle.
- * We will re-enable it at the start of the next xfer,
- * till then let it sleep.
+ DRM_DEBUG_KMS("GMBUS [%s] NAK for addr: %04x %c(%d)\n",
+ adapter->name, msgs[i].addr,
+ (msgs[i].flags & I2C_M_RD) ? 'r' : 'w', msgs[i].len);
+
+ /*
+ * If no ACK is received during the address phase of a transaction,
+ * the adapter must report -ENXIO.
+ * It is not clear what to return if no ACK is received at other times.
+ * So, we always return -ENXIO in all NAK cases, to ensure we send
+ * it at least during the one case that is specified.
*/
- if (wait_for((I915_READ(GMBUS2 + reg_offset) & GMBUS_ACTIVE) == 0, 10))
- DRM_INFO("GMBUS timed out waiting for idle\n");
- I915_WRITE(GMBUS0 + reg_offset, 0);
- ret = i;
+ ret = -ENXIO;
goto out;
timeout:
- DRM_INFO("GMBUS timed out, falling back to bit banging on pin %d [%s]\n",
- bus->reg0 & 0xff, bus->adapter.name);
+ DRM_INFO("GMBUS [%s] timed out, falling back to bit banging on pin %d\n",
+ bus->adapter.name, bus->reg0 & 0xff);
I915_WRITE(GMBUS0 + reg_offset, 0);
/* Hardware may not support GMBUS over these pins? Try GPIO bitbanging instead. */
- if (!bus->has_gpio) {
- ret = -EIO;
- } else {
- bus->force_bit = true;
- ret = intel_i2c_quirk_xfer(bus, msgs, num);
- }
+ bus->force_bit = true;
+ ret = i2c_bit_algo.master_xfer(adapter, msgs, num);
+
out:
mutex_unlock(&dev_priv->gmbus_mutex);
return ret;
@@ -346,35 +458,26 @@ static const struct i2c_algorithm gmbus_algorithm = {
*/
int intel_setup_gmbus(struct drm_device *dev)
{
- static const char *names[GMBUS_NUM_PORTS] = {
- "disabled",
- "ssc",
- "vga",
- "panel",
- "dpc",
- "dpb",
- "reserved",
- "dpd",
- };
struct drm_i915_private *dev_priv = dev->dev_private;
int ret, i;
- dev_priv->gmbus = kcalloc(GMBUS_NUM_PORTS, sizeof(struct intel_gmbus),
- GFP_KERNEL);
- if (dev_priv->gmbus == NULL)
- return -ENOMEM;
+ if (HAS_PCH_SPLIT(dev))
+ dev_priv->gpio_mmio_base = PCH_GPIOA - GPIOA;
+ else
+ dev_priv->gpio_mmio_base = 0;
mutex_init(&dev_priv->gmbus_mutex);
for (i = 0; i < GMBUS_NUM_PORTS; i++) {
struct intel_gmbus *bus = &dev_priv->gmbus[i];
+ u32 port = i + 1; /* +1 to map gmbus index to pin pair */
bus->adapter.owner = THIS_MODULE;
bus->adapter.class = I2C_CLASS_DDC;
snprintf(bus->adapter.name,
sizeof(bus->adapter.name),
"i915 gmbus %s",
- names[i]);
+ gmbus_ports[i].name);
bus->adapter.dev.parent = &dev->pdev->dev;
bus->dev_priv = dev_priv;
@@ -385,13 +488,13 @@ int intel_setup_gmbus(struct drm_device *dev)
goto err;
/* By default use a conservative clock rate */
- bus->reg0 = i | GMBUS_RATE_100KHZ;
+ bus->reg0 = port | GMBUS_RATE_100KHZ;
- bus->has_gpio = intel_gpio_setup(bus, i);
-
- /* XXX force bit banging until GMBUS is fully debugged */
- if (bus->has_gpio)
+ /* gmbus seems to be broken on i830 */
+ if (IS_I830(dev))
bus->force_bit = true;
+
+ intel_gpio_setup(bus, port);
}
intel_i2c_reset(dev_priv->dev);
@@ -403,11 +506,18 @@ err:
struct intel_gmbus *bus = &dev_priv->gmbus[i];
i2c_del_adapter(&bus->adapter);
}
- kfree(dev_priv->gmbus);
- dev_priv->gmbus = NULL;
return ret;
}
+struct i2c_adapter *intel_gmbus_get_adapter(struct drm_i915_private *dev_priv,
+ unsigned port)
+{
+ WARN_ON(!intel_gmbus_is_port_valid(port));
+ /* -1 to map pin pair to gmbus index */
+ return (intel_gmbus_is_port_valid(port)) ?
+ &dev_priv->gmbus[port - 1].adapter : NULL;
+}
+
void intel_gmbus_set_speed(struct i2c_adapter *adapter, int speed)
{
struct intel_gmbus *bus = to_intel_gmbus(adapter);
@@ -419,8 +529,7 @@ void intel_gmbus_force_bit(struct i2c_adapter *adapter, bool force_bit)
{
struct intel_gmbus *bus = to_intel_gmbus(adapter);
- if (bus->has_gpio)
- bus->force_bit = force_bit;
+ bus->force_bit = force_bit;
}
void intel_teardown_gmbus(struct drm_device *dev)
@@ -435,7 +544,4 @@ void intel_teardown_gmbus(struct drm_device *dev)
struct intel_gmbus *bus = &dev_priv->gmbus[i];
i2c_del_adapter(&bus->adapter);
}
-
- kfree(dev_priv->gmbus);
- dev_priv->gmbus = NULL;
}
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 9c71183629c2..9dee82350def 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -480,7 +480,7 @@ static int intel_lvds_get_modes(struct drm_connector *connector)
static int intel_no_modeset_on_lid_dmi_callback(const struct dmi_system_id *id)
{
- DRM_DEBUG_KMS("Skipping forced modeset for %s\n", id->ident);
+ DRM_INFO("Skipping forced modeset for %s\n", id->ident);
return 1;
}
@@ -628,7 +628,7 @@ static const struct drm_encoder_funcs intel_lvds_enc_funcs = {
static int __init intel_no_lvds_dmi_callback(const struct dmi_system_id *id)
{
- DRM_DEBUG_KMS("Skipping LVDS initialization for %s\n", id->ident);
+ DRM_INFO("Skipping LVDS initialization for %s\n", id->ident);
return 1;
}
@@ -851,8 +851,8 @@ static bool lvds_is_present_in_vbt(struct drm_device *dev,
child->device_type != DEVICE_TYPE_LFP)
continue;
- if (child->i2c_pin)
- *i2c_pin = child->i2c_pin;
+ if (intel_gmbus_is_port_valid(child->i2c_pin))
+ *i2c_pin = child->i2c_pin;
/* However, we cannot trust the BIOS writers to populate
* the VBT correctly. Since LVDS requires additional
@@ -993,7 +993,8 @@ bool intel_lvds_init(struct drm_device *dev)
* preferred mode is the right one.
*/
intel_lvds->edid = drm_get_edid(connector,
- &dev_priv->gmbus[pin].adapter);
+ intel_gmbus_get_adapter(dev_priv,
+ pin));
if (intel_lvds->edid) {
if (drm_add_edid_modes(connector,
intel_lvds->edid)) {
diff --git a/drivers/gpu/drm/i915/intel_modes.c b/drivers/gpu/drm/i915/intel_modes.c
index d1928e79d9b6..d67ec3a51e42 100644
--- a/drivers/gpu/drm/i915/intel_modes.c
+++ b/drivers/gpu/drm/i915/intel_modes.c
@@ -56,7 +56,8 @@ bool intel_ddc_probe(struct intel_encoder *intel_encoder, int ddc_bus)
}
};
- return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 2) == 2;
+ return i2c_transfer(intel_gmbus_get_adapter(dev_priv, ddc_bus),
+ msgs, 2) == 2;
}
/**
diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c
index 289140bc83cb..18bd0af855dc 100644
--- a/drivers/gpu/drm/i915/intel_opregion.c
+++ b/drivers/gpu/drm/i915/intel_opregion.c
@@ -25,6 +25,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/acpi.h>
#include <linux/acpi_io.h>
#include <acpi/video.h>
@@ -149,7 +151,7 @@ struct opregion_asle {
static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- struct opregion_asle *asle = dev_priv->opregion.asle;
+ struct opregion_asle __iomem *asle = dev_priv->opregion.asle;
u32 max;
if (!(bclp & ASLE_BCLP_VALID))
@@ -161,7 +163,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
max = intel_panel_get_max_backlight(dev);
intel_panel_set_backlight(dev, bclp * max / 255);
- asle->cblv = (bclp*0x64)/0xff | ASLE_CBLV_VALID;
+ iowrite32((bclp*0x64)/0xff | ASLE_CBLV_VALID, &asle->cblv);
return 0;
}
@@ -198,14 +200,14 @@ static u32 asle_set_pfit(struct drm_device *dev, u32 pfit)
void intel_opregion_asle_intr(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- struct opregion_asle *asle = dev_priv->opregion.asle;
+ struct opregion_asle __iomem *asle = dev_priv->opregion.asle;
u32 asle_stat = 0;
u32 asle_req;
if (!asle)
return;
- asle_req = asle->aslc & ASLE_REQ_MSK;
+ asle_req = ioread32(&asle->aslc) & ASLE_REQ_MSK;
if (!asle_req) {
DRM_DEBUG_DRIVER("non asle set request??\n");
@@ -213,31 +215,31 @@ void intel_opregion_asle_intr(struct drm_device *dev)
}
if (asle_req & ASLE_SET_ALS_ILLUM)
- asle_stat |= asle_set_als_illum(dev, asle->alsi);
+ asle_stat |= asle_set_als_illum(dev, ioread32(&asle->alsi));
if (asle_req & ASLE_SET_BACKLIGHT)
- asle_stat |= asle_set_backlight(dev, asle->bclp);
+ asle_stat |= asle_set_backlight(dev, ioread32(&asle->bclp));
if (asle_req & ASLE_SET_PFIT)
- asle_stat |= asle_set_pfit(dev, asle->pfit);
+ asle_stat |= asle_set_pfit(dev, ioread32(&asle->pfit));
if (asle_req & ASLE_SET_PWM_FREQ)
- asle_stat |= asle_set_pwm_freq(dev, asle->pfmb);
+ asle_stat |= asle_set_pwm_freq(dev, ioread32(&asle->pfmb));
- asle->aslc = asle_stat;
+ iowrite32(asle_stat, &asle->aslc);
}
void intel_opregion_gse_intr(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- struct opregion_asle *asle = dev_priv->opregion.asle;
+ struct opregion_asle __iomem *asle = dev_priv->opregion.asle;
u32 asle_stat = 0;
u32 asle_req;
if (!asle)
return;
- asle_req = asle->aslc & ASLE_REQ_MSK;
+ asle_req = ioread32(&asle->aslc) & ASLE_REQ_MSK;
if (!asle_req) {
DRM_DEBUG_DRIVER("non asle set request??\n");
@@ -250,7 +252,7 @@ void intel_opregion_gse_intr(struct drm_device *dev)
}
if (asle_req & ASLE_SET_BACKLIGHT)
- asle_stat |= asle_set_backlight(dev, asle->bclp);
+ asle_stat |= asle_set_backlight(dev, ioread32(&asle->bclp));
if (asle_req & ASLE_SET_PFIT) {
DRM_DEBUG_DRIVER("Pfit is not supported\n");
@@ -262,7 +264,7 @@ void intel_opregion_gse_intr(struct drm_device *dev)
asle_stat |= ASLE_PWM_FREQ_FAILED;
}
- asle->aslc = asle_stat;
+ iowrite32(asle_stat, &asle->aslc);
}
#define ASLE_ALS_EN (1<<0)
#define ASLE_BLC_EN (1<<1)
@@ -272,15 +274,16 @@ void intel_opregion_gse_intr(struct drm_device *dev)
void intel_opregion_enable_asle(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- struct opregion_asle *asle = dev_priv->opregion.asle;
+ struct opregion_asle __iomem *asle = dev_priv->opregion.asle;
if (asle) {
if (IS_MOBILE(dev))
intel_enable_asle(dev);
- asle->tche = ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
- ASLE_PFMB_EN;
- asle->ardy = 1;
+ iowrite32(ASLE_ALS_EN | ASLE_BLC_EN | ASLE_PFIT_EN |
+ ASLE_PFMB_EN,
+ &asle->tche);
+ iowrite32(1, &asle->ardy);
}
}
@@ -298,7 +301,7 @@ static int intel_opregion_video_event(struct notifier_block *nb,
Linux, these are handled by the dock, button and video drivers.
*/
- struct opregion_acpi *acpi;
+ struct opregion_acpi __iomem *acpi;
struct acpi_bus_event *event = data;
int ret = NOTIFY_OK;
@@ -310,10 +313,11 @@ static int intel_opregion_video_event(struct notifier_block *nb,
acpi = system_opregion->acpi;
- if (event->type == 0x80 && !(acpi->cevt & 0x1))
+ if (event->type == 0x80 &&
+ (ioread32(&acpi->cevt) & 1) == 0)
ret = NOTIFY_BAD;
- acpi->csts = 0;
+ iowrite32(0, &acpi->csts);
return ret;
}
@@ -337,6 +341,7 @@ static void intel_didl_outputs(struct drm_device *dev)
struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL;
unsigned long long device_id;
acpi_status status;
+ u32 temp;
int i = 0;
handle = DEVICE_ACPI_HANDLE(&dev->pdev->dev);
@@ -355,7 +360,7 @@ static void intel_didl_outputs(struct drm_device *dev)
}
if (!acpi_video_bus) {
- printk(KERN_WARNING "No ACPI video bus found\n");
+ pr_warn("No ACPI video bus found\n");
return;
}
@@ -371,7 +376,8 @@ static void intel_didl_outputs(struct drm_device *dev)
if (ACPI_SUCCESS(status)) {
if (!device_id)
goto blind_set;
- opregion->acpi->didl[i] = (u32)(device_id & 0x0f0f);
+ iowrite32((u32)(device_id & 0x0f0f),
+ &opregion->acpi->didl[i]);
i++;
}
}
@@ -379,7 +385,7 @@ static void intel_didl_outputs(struct drm_device *dev)
end:
/* If fewer than 8 outputs, the list must be null terminated */
if (i < 8)
- opregion->acpi->didl[i] = 0;
+ iowrite32(0, &opregion->acpi->didl[i]);
return;
blind_set:
@@ -413,7 +419,9 @@ blind_set:
output_type = ACPI_LVDS_OUTPUT;
break;
}
- opregion->acpi->didl[i] |= (1<<31) | output_type | i;
+ temp = ioread32(&opregion->acpi->didl[i]);
+ iowrite32(temp | (1<<31) | output_type | i,
+ &opregion->acpi->didl[i]);
i++;
}
goto end;
@@ -434,8 +442,8 @@ void intel_opregion_init(struct drm_device *dev)
/* Notify BIOS we are ready to handle ACPI video ext notifs.
* Right now, all the events are handled by the ACPI video module.
* We don't actually need to do anything with them. */
- opregion->acpi->csts = 0;
- opregion->acpi->drdy = 1;
+ iowrite32(0, &opregion->acpi->csts);
+ iowrite32(1, &opregion->acpi->drdy);
system_opregion = opregion;
register_acpi_notifier(&intel_opregion_notifier);
@@ -454,7 +462,7 @@ void intel_opregion_fini(struct drm_device *dev)
return;
if (opregion->acpi) {
- opregion->acpi->drdy = 0;
+ iowrite32(0, &opregion->acpi->drdy);
system_opregion = NULL;
unregister_acpi_notifier(&intel_opregion_notifier);
@@ -474,8 +482,9 @@ int intel_opregion_setup(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_opregion *opregion = &dev_priv->opregion;
- void *base;
+ void __iomem *base;
u32 asls, mboxes;
+ char buf[sizeof(OPREGION_SIGNATURE)];
int err = 0;
pci_read_config_dword(dev->pdev, PCI_ASLS, &asls);
@@ -489,7 +498,9 @@ int intel_opregion_setup(struct drm_device *dev)
if (!base)
return -ENOMEM;
- if (memcmp(base, OPREGION_SIGNATURE, 16)) {
+ memcpy_fromio(buf, base, sizeof(buf));
+
+ if (memcmp(buf, OPREGION_SIGNATURE, 16)) {
DRM_DEBUG_DRIVER("opregion signature mismatch\n");
err = -EINVAL;
goto err_out;
@@ -499,7 +510,7 @@ int intel_opregion_setup(struct drm_device *dev)
opregion->lid_state = base + ACPI_CLID;
- mboxes = opregion->header->mboxes;
+ mboxes = ioread32(&opregion->header->mboxes);
if (mboxes & MBOX_ACPI) {
DRM_DEBUG_DRIVER("Public ACPI methods supported\n");
opregion->acpi = base + OPREGION_ACPI_OFFSET;
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index 80b331c322fb..458743da3774 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -187,14 +187,14 @@ struct intel_overlay {
void (*flip_tail)(struct intel_overlay *);
};
-static struct overlay_registers *
+static struct overlay_registers __iomem *
intel_overlay_map_regs(struct intel_overlay *overlay)
{
drm_i915_private_t *dev_priv = overlay->dev->dev_private;
- struct overlay_registers *regs;
+ struct overlay_registers __iomem *regs;
if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
- regs = overlay->reg_bo->phys_obj->handle->vaddr;
+ regs = (struct overlay_registers __iomem *)overlay->reg_bo->phys_obj->handle->vaddr;
else
regs = io_mapping_map_wc(dev_priv->mm.gtt_mapping,
overlay->reg_bo->gtt_offset);
@@ -203,7 +203,7 @@ intel_overlay_map_regs(struct intel_overlay *overlay)
}
static void intel_overlay_unmap_regs(struct intel_overlay *overlay,
- struct overlay_registers *regs)
+ struct overlay_registers __iomem *regs)
{
if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))
io_mapping_unmap(regs);
@@ -215,20 +215,21 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
{
struct drm_device *dev = overlay->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
int ret;
BUG_ON(overlay->last_flip_req);
- ret = i915_add_request(LP_RING(dev_priv), NULL, request);
+ ret = i915_add_request(ring, NULL, request);
if (ret) {
kfree(request);
return ret;
}
overlay->last_flip_req = request->seqno;
overlay->flip_tail = tail;
- ret = i915_wait_request(LP_RING(dev_priv), overlay->last_flip_req,
- true);
+ ret = i915_wait_request(ring, overlay->last_flip_req);
if (ret)
return ret;
+ i915_gem_retire_requests(dev);
overlay->last_flip_req = 0;
return 0;
@@ -262,7 +263,7 @@ i830_activate_pipe_a(struct drm_device *dev)
DRM_DEBUG_DRIVER("Enabling pipe A in order to enable overlay\n");
mode = drm_mode_duplicate(dev, &vesa_640x480);
- drm_mode_set_crtcinfo(mode, 0);
+
if (!drm_crtc_helper_set_mode(&crtc->base, mode,
crtc->base.x, crtc->base.y,
crtc->base.fb))
@@ -287,6 +288,7 @@ static int intel_overlay_on(struct intel_overlay *overlay)
{
struct drm_device *dev = overlay->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
struct drm_i915_gem_request *request;
int pipe_a_quirk = 0;
int ret;
@@ -306,17 +308,17 @@ static int intel_overlay_on(struct intel_overlay *overlay)
goto out;
}
- ret = BEGIN_LP_RING(4);
+ ret = intel_ring_begin(ring, 4);
if (ret) {
kfree(request);
goto out;
}
- OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_ON);
- OUT_RING(overlay->flip_addr | OFC_UPDATE);
- OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
- OUT_RING(MI_NOOP);
- ADVANCE_LP_RING();
+ intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_ON);
+ intel_ring_emit(ring, overlay->flip_addr | OFC_UPDATE);
+ intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
+ intel_ring_emit(ring, MI_NOOP);
+ intel_ring_advance(ring);
ret = intel_overlay_do_wait_request(overlay, request, NULL);
out:
@@ -332,6 +334,7 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
{
struct drm_device *dev = overlay->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
struct drm_i915_gem_request *request;
u32 flip_addr = overlay->flip_addr;
u32 tmp;
@@ -351,16 +354,16 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
if (tmp & (1 << 17))
DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp);
- ret = BEGIN_LP_RING(2);
+ ret = intel_ring_begin(ring, 2);
if (ret) {
kfree(request);
return ret;
}
- OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
- OUT_RING(flip_addr);
- ADVANCE_LP_RING();
+ intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
+ intel_ring_emit(ring, flip_addr);
+ intel_ring_advance(ring);
- ret = i915_add_request(LP_RING(dev_priv), NULL, request);
+ ret = i915_add_request(ring, NULL, request);
if (ret) {
kfree(request);
return ret;
@@ -401,6 +404,7 @@ static int intel_overlay_off(struct intel_overlay *overlay)
{
struct drm_device *dev = overlay->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
u32 flip_addr = overlay->flip_addr;
struct drm_i915_gem_request *request;
int ret;
@@ -417,20 +421,20 @@ static int intel_overlay_off(struct intel_overlay *overlay)
* of the hw. Do it in both cases */
flip_addr |= OFC_UPDATE;
- ret = BEGIN_LP_RING(6);
+ ret = intel_ring_begin(ring, 6);
if (ret) {
kfree(request);
return ret;
}
/* wait for overlay to go idle */
- OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
- OUT_RING(flip_addr);
- OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
+ intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE);
+ intel_ring_emit(ring, flip_addr);
+ intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
/* turn overlay off */
- OUT_RING(MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
- OUT_RING(flip_addr);
- OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
- ADVANCE_LP_RING();
+ intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_OFF);
+ intel_ring_emit(ring, flip_addr);
+ intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
+ intel_ring_advance(ring);
return intel_overlay_do_wait_request(overlay, request,
intel_overlay_off_tail);
@@ -442,15 +446,16 @@ static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)
{
struct drm_device *dev = overlay->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
int ret;
if (overlay->last_flip_req == 0)
return 0;
- ret = i915_wait_request(LP_RING(dev_priv), overlay->last_flip_req,
- true);
+ ret = i915_wait_request(ring, overlay->last_flip_req);
if (ret)
return ret;
+ i915_gem_retire_requests(dev);
if (overlay->flip_tail)
overlay->flip_tail(overlay);
@@ -467,6 +472,7 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
{
struct drm_device *dev = overlay->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
int ret;
/* Only wait if there is actually an old frame to release to
@@ -483,15 +489,15 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
if (request == NULL)
return -ENOMEM;
- ret = BEGIN_LP_RING(2);
+ ret = intel_ring_begin(ring, 2);
if (ret) {
kfree(request);
return ret;
}
- OUT_RING(MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
- OUT_RING(MI_NOOP);
- ADVANCE_LP_RING();
+ intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP);
+ intel_ring_emit(ring, MI_NOOP);
+ intel_ring_advance(ring);
ret = intel_overlay_do_wait_request(overlay, request,
intel_overlay_release_old_vid_tail);
@@ -619,14 +625,15 @@ static const u16 uv_static_hcoeffs[N_HORIZ_UV_TAPS * N_PHASES] = {
0x3000, 0x0800, 0x3000
};
-static void update_polyphase_filter(struct overlay_registers *regs)
+static void update_polyphase_filter(struct overlay_registers __iomem *regs)
{
- memcpy(regs->Y_HCOEFS, y_static_hcoeffs, sizeof(y_static_hcoeffs));
- memcpy(regs->UV_HCOEFS, uv_static_hcoeffs, sizeof(uv_static_hcoeffs));
+ memcpy_toio(regs->Y_HCOEFS, y_static_hcoeffs, sizeof(y_static_hcoeffs));
+ memcpy_toio(regs->UV_HCOEFS, uv_static_hcoeffs,
+ sizeof(uv_static_hcoeffs));
}
static bool update_scaling_factors(struct intel_overlay *overlay,
- struct overlay_registers *regs,
+ struct overlay_registers __iomem *regs,
struct put_image_params *params)
{
/* fixed point with a 12 bit shift */
@@ -665,16 +672,19 @@ static bool update_scaling_factors(struct intel_overlay *overlay,
overlay->old_xscale = xscale;
overlay->old_yscale = yscale;
- regs->YRGBSCALE = (((yscale & FRACT_MASK) << 20) |
- ((xscale >> FP_SHIFT) << 16) |
- ((xscale & FRACT_MASK) << 3));
+ iowrite32(((yscale & FRACT_MASK) << 20) |
+ ((xscale >> FP_SHIFT) << 16) |
+ ((xscale & FRACT_MASK) << 3),
+ &regs->YRGBSCALE);
- regs->UVSCALE = (((yscale_UV & FRACT_MASK) << 20) |
- ((xscale_UV >> FP_SHIFT) << 16) |
- ((xscale_UV & FRACT_MASK) << 3));
+ iowrite32(((yscale_UV & FRACT_MASK) << 20) |
+ ((xscale_UV >> FP_SHIFT) << 16) |
+ ((xscale_UV & FRACT_MASK) << 3),
+ &regs->UVSCALE);
- regs->UVSCALEV = ((((yscale >> FP_SHIFT) << 16) |
- ((yscale_UV >> FP_SHIFT) << 0)));
+ iowrite32((((yscale >> FP_SHIFT) << 16) |
+ ((yscale_UV >> FP_SHIFT) << 0)),
+ &regs->UVSCALEV);
if (scale_changed)
update_polyphase_filter(regs);
@@ -683,30 +693,32 @@ static bool update_scaling_factors(struct intel_overlay *overlay,
}
static void update_colorkey(struct intel_overlay *overlay,
- struct overlay_registers *regs)
+ struct overlay_registers __iomem *regs)
{
u32 key = overlay->color_key;
switch (overlay->crtc->base.fb->bits_per_pixel) {
case 8:
- regs->DCLRKV = 0;
- regs->DCLRKM = CLK_RGB8I_MASK | DST_KEY_ENABLE;
+ iowrite32(0, &regs->DCLRKV);
+ iowrite32(CLK_RGB8I_MASK | DST_KEY_ENABLE, &regs->DCLRKM);
break;
case 16:
if (overlay->crtc->base.fb->depth == 15) {
- regs->DCLRKV = RGB15_TO_COLORKEY(key);
- regs->DCLRKM = CLK_RGB15_MASK | DST_KEY_ENABLE;
+ iowrite32(RGB15_TO_COLORKEY(key), &regs->DCLRKV);
+ iowrite32(CLK_RGB15_MASK | DST_KEY_ENABLE,
+ &regs->DCLRKM);
} else {
- regs->DCLRKV = RGB16_TO_COLORKEY(key);
- regs->DCLRKM = CLK_RGB16_MASK | DST_KEY_ENABLE;
+ iowrite32(RGB16_TO_COLORKEY(key), &regs->DCLRKV);
+ iowrite32(CLK_RGB16_MASK | DST_KEY_ENABLE,
+ &regs->DCLRKM);
}
break;
case 24:
case 32:
- regs->DCLRKV = key;
- regs->DCLRKM = CLK_RGB24_MASK | DST_KEY_ENABLE;
+ iowrite32(key, &regs->DCLRKV);
+ iowrite32(CLK_RGB24_MASK | DST_KEY_ENABLE, &regs->DCLRKM);
break;
}
}
@@ -761,9 +773,10 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
struct put_image_params *params)
{
int ret, tmp_width;
- struct overlay_registers *regs;
+ struct overlay_registers __iomem *regs;
bool scale_changed = false;
struct drm_device *dev = overlay->dev;
+ u32 swidth, swidthsw, sheight, ostride;
BUG_ON(!mutex_is_locked(&dev->struct_mutex));
BUG_ON(!mutex_is_locked(&dev->mode_config.mutex));
@@ -782,16 +795,18 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
goto out_unpin;
if (!overlay->active) {
+ u32 oconfig;
regs = intel_overlay_map_regs(overlay);
if (!regs) {
ret = -ENOMEM;
goto out_unpin;
}
- regs->OCONFIG = OCONF_CC_OUT_8BIT;
+ oconfig = OCONF_CC_OUT_8BIT;
if (IS_GEN4(overlay->dev))
- regs->OCONFIG |= OCONF_CSC_MODE_BT709;
- regs->OCONFIG |= overlay->crtc->pipe == 0 ?
+ oconfig |= OCONF_CSC_MODE_BT709;
+ oconfig |= overlay->crtc->pipe == 0 ?
OCONF_PIPE_A : OCONF_PIPE_B;
+ iowrite32(oconfig, &regs->OCONFIG);
intel_overlay_unmap_regs(overlay, regs);
ret = intel_overlay_on(overlay);
@@ -805,42 +820,46 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
goto out_unpin;
}
- regs->DWINPOS = (params->dst_y << 16) | params->dst_x;
- regs->DWINSZ = (params->dst_h << 16) | params->dst_w;
+ iowrite32((params->dst_y << 16) | params->dst_x, &regs->DWINPOS);
+ iowrite32((params->dst_h << 16) | params->dst_w, &regs->DWINSZ);
if (params->format & I915_OVERLAY_YUV_PACKED)
tmp_width = packed_width_bytes(params->format, params->src_w);
else
tmp_width = params->src_w;
- regs->SWIDTH = params->src_w;
- regs->SWIDTHSW = calc_swidthsw(overlay->dev,
- params->offset_Y, tmp_width);
- regs->SHEIGHT = params->src_h;
- regs->OBUF_0Y = new_bo->gtt_offset + params->offset_Y;
- regs->OSTRIDE = params->stride_Y;
+ swidth = params->src_w;
+ swidthsw = calc_swidthsw(overlay->dev, params->offset_Y, tmp_width);
+ sheight = params->src_h;
+ iowrite32(new_bo->gtt_offset + params->offset_Y, &regs->OBUF_0Y);
+ ostride = params->stride_Y;
if (params->format & I915_OVERLAY_YUV_PLANAR) {
int uv_hscale = uv_hsubsampling(params->format);
int uv_vscale = uv_vsubsampling(params->format);
u32 tmp_U, tmp_V;
- regs->SWIDTH |= (params->src_w/uv_hscale) << 16;
+ swidth |= (params->src_w/uv_hscale) << 16;
tmp_U = calc_swidthsw(overlay->dev, params->offset_U,
params->src_w/uv_hscale);
tmp_V = calc_swidthsw(overlay->dev, params->offset_V,
params->src_w/uv_hscale);
- regs->SWIDTHSW |= max_t(u32, tmp_U, tmp_V) << 16;
- regs->SHEIGHT |= (params->src_h/uv_vscale) << 16;
- regs->OBUF_0U = new_bo->gtt_offset + params->offset_U;
- regs->OBUF_0V = new_bo->gtt_offset + params->offset_V;
- regs->OSTRIDE |= params->stride_UV << 16;
+ swidthsw |= max_t(u32, tmp_U, tmp_V) << 16;
+ sheight |= (params->src_h/uv_vscale) << 16;
+ iowrite32(new_bo->gtt_offset + params->offset_U, &regs->OBUF_0U);
+ iowrite32(new_bo->gtt_offset + params->offset_V, &regs->OBUF_0V);
+ ostride |= params->stride_UV << 16;
}
+ iowrite32(swidth, &regs->SWIDTH);
+ iowrite32(swidthsw, &regs->SWIDTHSW);
+ iowrite32(sheight, &regs->SHEIGHT);
+ iowrite32(ostride, &regs->OSTRIDE);
+
scale_changed = update_scaling_factors(overlay, regs, params);
update_colorkey(overlay, regs);
- regs->OCMD = overlay_cmd_reg(params);
+ iowrite32(overlay_cmd_reg(params), &regs->OCMD);
intel_overlay_unmap_regs(overlay, regs);
@@ -860,7 +879,7 @@ out_unpin:
int intel_overlay_switch_off(struct intel_overlay *overlay)
{
- struct overlay_registers *regs;
+ struct overlay_registers __iomem *regs;
struct drm_device *dev = overlay->dev;
int ret;
@@ -879,7 +898,7 @@ int intel_overlay_switch_off(struct intel_overlay *overlay)
return ret;
regs = intel_overlay_map_regs(overlay);
- regs->OCMD = 0;
+ iowrite32(0, &regs->OCMD);
intel_overlay_unmap_regs(overlay, regs);
ret = intel_overlay_off(overlay);
@@ -1109,11 +1128,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
struct put_image_params *params;
int ret;
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
-
+ /* No need to check for DRIVER_MODESET - we don't set it up then. */
overlay = dev_priv->overlay;
if (!overlay) {
DRM_DEBUG("userspace bug: no overlay\n");
@@ -1250,10 +1265,11 @@ out_free:
}
static void update_reg_attrs(struct intel_overlay *overlay,
- struct overlay_registers *regs)
+ struct overlay_registers __iomem *regs)
{
- regs->OCLRC0 = (overlay->contrast << 18) | (overlay->brightness & 0xff);
- regs->OCLRC1 = overlay->saturation;
+ iowrite32((overlay->contrast << 18) | (overlay->brightness & 0xff),
+ &regs->OCLRC0);
+ iowrite32(overlay->saturation, &regs->OCLRC1);
}
static bool check_gamma_bounds(u32 gamma1, u32 gamma2)
@@ -1306,14 +1322,10 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
struct drm_intel_overlay_attrs *attrs = data;
drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_overlay *overlay;
- struct overlay_registers *regs;
+ struct overlay_registers __iomem *regs;
int ret;
- if (!dev_priv) {
- DRM_ERROR("called with no initialization\n");
- return -EINVAL;
- }
-
+ /* No need to check for DRIVER_MODESET - we don't set it up then. */
overlay = dev_priv->overlay;
if (!overlay) {
DRM_DEBUG("userspace bug: no overlay\n");
@@ -1396,7 +1408,7 @@ void intel_setup_overlay(struct drm_device *dev)
drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_overlay *overlay;
struct drm_i915_gem_object *reg_bo;
- struct overlay_registers *regs;
+ struct overlay_registers __iomem *regs;
int ret;
if (!HAS_OVERLAY(dev))
@@ -1451,7 +1463,7 @@ void intel_setup_overlay(struct drm_device *dev)
if (!regs)
goto out_unpin_bo;
- memset(regs, 0, sizeof(struct overlay_registers));
+ memset_io(regs, 0, sizeof(struct overlay_registers));
update_polyphase_filter(regs);
update_reg_attrs(overlay, regs);
@@ -1499,14 +1511,17 @@ struct intel_overlay_error_state {
u32 isr;
};
-static struct overlay_registers *
+static struct overlay_registers __iomem *
intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
{
drm_i915_private_t *dev_priv = overlay->dev->dev_private;
- struct overlay_registers *regs;
+ struct overlay_registers __iomem *regs;
if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
- regs = overlay->reg_bo->phys_obj->handle->vaddr;
+ /* Cast to make sparse happy, but it's wc memory anyway, so
+ * equivalent to the wc io mapping on X86. */
+ regs = (struct overlay_registers __iomem *)
+ overlay->reg_bo->phys_obj->handle->vaddr;
else
regs = io_mapping_map_atomic_wc(dev_priv->mm.gtt_mapping,
overlay->reg_bo->gtt_offset);
@@ -1515,7 +1530,7 @@ intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
}
static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay,
- struct overlay_registers *regs)
+ struct overlay_registers __iomem *regs)
{
if (!OVERLAY_NEEDS_PHYSICAL(overlay->dev))
io_mapping_unmap_atomic(regs);
@@ -1540,9 +1555,9 @@ intel_overlay_capture_error_state(struct drm_device *dev)
error->dovsta = I915_READ(DOVSTA);
error->isr = I915_READ(ISR);
if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
- error->base = (long) overlay->reg_bo->phys_obj->handle->vaddr;
+ error->base = (__force long)overlay->reg_bo->phys_obj->handle->vaddr;
else
- error->base = (long) overlay->reg_bo->gtt_offset;
+ error->base = overlay->reg_bo->gtt_offset;
regs = intel_overlay_map_regs_atomic(overlay);
if (!regs)
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index 48177ec4720e..2a1625d84a69 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -28,6 +28,9 @@
* Chris Wilson <chris@chris-wilson.co.uk>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/moduleparam.h>
#include "intel_drv.h"
#define PCI_LBPC 0xf4 /* legacy/combination backlight modes */
@@ -169,7 +172,7 @@ u32 intel_panel_get_max_backlight(struct drm_device *dev)
/* XXX add code here to query mode clock or hardware clock
* and program max PWM appropriately.
*/
- printk_once(KERN_WARNING "fixme: max PWM is zero.\n");
+ pr_warn_once("fixme: max PWM is zero\n");
return 1;
}
@@ -189,6 +192,27 @@ u32 intel_panel_get_max_backlight(struct drm_device *dev)
return max;
}
+static int i915_panel_invert_brightness;
+MODULE_PARM_DESC(invert_brightness, "Invert backlight brightness "
+ "(-1 force normal, 0 machine defaults, 1 force inversion), please "
+ "report PCI device ID, subsystem vendor and subsystem device ID "
+ "to dri-devel@lists.freedesktop.org, if your machine needs it. "
+ "It will then be included in an upcoming module version.");
+module_param_named(invert_brightness, i915_panel_invert_brightness, int, 0600);
+static u32 intel_panel_compute_brightness(struct drm_device *dev, u32 val)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (i915_panel_invert_brightness < 0)
+ return val;
+
+ if (i915_panel_invert_brightness > 0 ||
+ dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS)
+ return intel_panel_get_max_backlight(dev) - val;
+
+ return val;
+}
+
u32 intel_panel_get_backlight(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -209,6 +233,7 @@ u32 intel_panel_get_backlight(struct drm_device *dev)
}
}
+ val = intel_panel_compute_brightness(dev, val);
DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
return val;
}
@@ -226,6 +251,7 @@ static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level
u32 tmp;
DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level);
+ level = intel_panel_compute_brightness(dev, level);
if (HAS_PCH_SPLIT(dev))
return intel_pch_panel_set_backlight(dev, level);
@@ -342,6 +368,7 @@ int intel_panel_setup_backlight(struct drm_device *dev)
else
return -ENODEV;
+ memset(&props, 0, sizeof(props));
props.type = BACKLIGHT_RAW;
props.max_brightness = intel_panel_get_max_backlight(dev);
dev_priv->backlight =
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
new file mode 100644
index 000000000000..8e79ff67ec98
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -0,0 +1,3796 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Eugeni Dodonov <eugeni.dodonov@intel.com>
+ *
+ */
+
+#include <linux/cpufreq.h>
+#include "i915_drv.h"
+#include "intel_drv.h"
+#include "../../../platform/x86/intel_ips.h"
+#include <linux/module.h>
+
+/* FBC, or Frame Buffer Compression, is a technique employed to compress the
+ * framebuffer contents in-memory, aiming at reducing the required bandwidth
+ * during in-memory transfers and, therefore, reduce the power packet.
+ *
+ * The benefits of FBC are mostly visible with solid backgrounds and
+ * variation-less patterns.
+ *
+ * FBC-related functionality can be enabled by the means of the
+ * i915.i915_enable_fbc parameter
+ */
+
+static void i8xx_disable_fbc(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 fbc_ctl;
+
+ /* Disable compression */
+ fbc_ctl = I915_READ(FBC_CONTROL);
+ if ((fbc_ctl & FBC_CTL_EN) == 0)
+ return;
+
+ fbc_ctl &= ~FBC_CTL_EN;
+ I915_WRITE(FBC_CONTROL, fbc_ctl);
+
+ /* Wait for compressing bit to clear */
+ if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10)) {
+ DRM_DEBUG_KMS("FBC idle timed out\n");
+ return;
+ }
+
+ DRM_DEBUG_KMS("disabled FBC\n");
+}
+
+static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_framebuffer *fb = crtc->fb;
+ struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
+ struct drm_i915_gem_object *obj = intel_fb->obj;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ int cfb_pitch;
+ int plane, i;
+ u32 fbc_ctl, fbc_ctl2;
+
+ cfb_pitch = dev_priv->cfb_size / FBC_LL_SIZE;
+ if (fb->pitches[0] < cfb_pitch)
+ cfb_pitch = fb->pitches[0];
+
+ /* FBC_CTL wants 64B units */
+ cfb_pitch = (cfb_pitch / 64) - 1;
+ plane = intel_crtc->plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB;
+
+ /* Clear old tags */
+ for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++)
+ I915_WRITE(FBC_TAG + (i * 4), 0);
+
+ /* Set it up... */
+ fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE;
+ fbc_ctl2 |= plane;
+ I915_WRITE(FBC_CONTROL2, fbc_ctl2);
+ I915_WRITE(FBC_FENCE_OFF, crtc->y);
+
+ /* enable it... */
+ fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC;
+ if (IS_I945GM(dev))
+ fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */
+ fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
+ fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT;
+ fbc_ctl |= obj->fence_reg;
+ I915_WRITE(FBC_CONTROL, fbc_ctl);
+
+ DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %d, ",
+ cfb_pitch, crtc->y, intel_crtc->plane);
+}
+
+static bool i8xx_fbc_enabled(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ return I915_READ(FBC_CONTROL) & FBC_CTL_EN;
+}
+
+static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_framebuffer *fb = crtc->fb;
+ struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
+ struct drm_i915_gem_object *obj = intel_fb->obj;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
+ unsigned long stall_watermark = 200;
+ u32 dpfc_ctl;
+
+ dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X;
+ dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg;
+ I915_WRITE(DPFC_CHICKEN, DPFC_HT_MODIFY);
+
+ I915_WRITE(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
+ (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
+ (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
+ I915_WRITE(DPFC_FENCE_YOFF, crtc->y);
+
+ /* enable it... */
+ I915_WRITE(DPFC_CONTROL, I915_READ(DPFC_CONTROL) | DPFC_CTL_EN);
+
+ DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
+}
+
+static void g4x_disable_fbc(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 dpfc_ctl;
+
+ /* Disable compression */
+ dpfc_ctl = I915_READ(DPFC_CONTROL);
+ if (dpfc_ctl & DPFC_CTL_EN) {
+ dpfc_ctl &= ~DPFC_CTL_EN;
+ I915_WRITE(DPFC_CONTROL, dpfc_ctl);
+
+ DRM_DEBUG_KMS("disabled FBC\n");
+ }
+}
+
+static bool g4x_fbc_enabled(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN;
+}
+
+static void sandybridge_blit_fbc_update(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 blt_ecoskpd;
+
+ /* Make sure blitter notifies FBC of writes */
+ gen6_gt_force_wake_get(dev_priv);
+ blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD);
+ blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY <<
+ GEN6_BLITTER_LOCK_SHIFT;
+ I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
+ blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY;
+ I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
+ blt_ecoskpd &= ~(GEN6_BLITTER_FBC_NOTIFY <<
+ GEN6_BLITTER_LOCK_SHIFT);
+ I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
+ POSTING_READ(GEN6_BLITTER_ECOSKPD);
+ gen6_gt_force_wake_put(dev_priv);
+}
+
+static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_framebuffer *fb = crtc->fb;
+ struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
+ struct drm_i915_gem_object *obj = intel_fb->obj;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
+ unsigned long stall_watermark = 200;
+ u32 dpfc_ctl;
+
+ dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
+ dpfc_ctl &= DPFC_RESERVED;
+ dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X);
+ /* Set persistent mode for front-buffer rendering, ala X. */
+ dpfc_ctl |= DPFC_CTL_PERSISTENT_MODE;
+ dpfc_ctl |= (DPFC_CTL_FENCE_EN | obj->fence_reg);
+ I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY);
+
+ I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
+ (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
+ (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
+ I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y);
+ I915_WRITE(ILK_FBC_RT_BASE, obj->gtt_offset | ILK_FBC_RT_VALID);
+ /* enable it... */
+ I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
+
+ if (IS_GEN6(dev)) {
+ I915_WRITE(SNB_DPFC_CTL_SA,
+ SNB_CPU_FENCE_ENABLE | obj->fence_reg);
+ I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
+ sandybridge_blit_fbc_update(dev);
+ }
+
+ DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
+}
+
+static void ironlake_disable_fbc(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 dpfc_ctl;
+
+ /* Disable compression */
+ dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
+ if (dpfc_ctl & DPFC_CTL_EN) {
+ dpfc_ctl &= ~DPFC_CTL_EN;
+ I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
+
+ DRM_DEBUG_KMS("disabled FBC\n");
+ }
+}
+
+static bool ironlake_fbc_enabled(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN;
+}
+
+bool intel_fbc_enabled(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (!dev_priv->display.fbc_enabled)
+ return false;
+
+ return dev_priv->display.fbc_enabled(dev);
+}
+
+static void intel_fbc_work_fn(struct work_struct *__work)
+{
+ struct intel_fbc_work *work =
+ container_of(to_delayed_work(__work),
+ struct intel_fbc_work, work);
+ struct drm_device *dev = work->crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ mutex_lock(&dev->struct_mutex);
+ if (work == dev_priv->fbc_work) {
+ /* Double check that we haven't switched fb without cancelling
+ * the prior work.
+ */
+ if (work->crtc->fb == work->fb) {
+ dev_priv->display.enable_fbc(work->crtc,
+ work->interval);
+
+ dev_priv->cfb_plane = to_intel_crtc(work->crtc)->plane;
+ dev_priv->cfb_fb = work->crtc->fb->base.id;
+ dev_priv->cfb_y = work->crtc->y;
+ }
+
+ dev_priv->fbc_work = NULL;
+ }
+ mutex_unlock(&dev->struct_mutex);
+
+ kfree(work);
+}
+
+static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv)
+{
+ if (dev_priv->fbc_work == NULL)
+ return;
+
+ DRM_DEBUG_KMS("cancelling pending FBC enable\n");
+
+ /* Synchronisation is provided by struct_mutex and checking of
+ * dev_priv->fbc_work, so we can perform the cancellation
+ * entirely asynchronously.
+ */
+ if (cancel_delayed_work(&dev_priv->fbc_work->work))
+ /* tasklet was killed before being run, clean up */
+ kfree(dev_priv->fbc_work);
+
+ /* Mark the work as no longer wanted so that if it does
+ * wake-up (because the work was already running and waiting
+ * for our mutex), it will discover that is no longer
+ * necessary to run.
+ */
+ dev_priv->fbc_work = NULL;
+}
+
+void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
+{
+ struct intel_fbc_work *work;
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (!dev_priv->display.enable_fbc)
+ return;
+
+ intel_cancel_fbc_work(dev_priv);
+
+ work = kzalloc(sizeof *work, GFP_KERNEL);
+ if (work == NULL) {
+ dev_priv->display.enable_fbc(crtc, interval);
+ return;
+ }
+
+ work->crtc = crtc;
+ work->fb = crtc->fb;
+ work->interval = interval;
+ INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn);
+
+ dev_priv->fbc_work = work;
+
+ DRM_DEBUG_KMS("scheduling delayed FBC enable\n");
+
+ /* Delay the actual enabling to let pageflipping cease and the
+ * display to settle before starting the compression. Note that
+ * this delay also serves a second purpose: it allows for a
+ * vblank to pass after disabling the FBC before we attempt
+ * to modify the control registers.
+ *
+ * A more complicated solution would involve tracking vblanks
+ * following the termination of the page-flipping sequence
+ * and indeed performing the enable as a co-routine and not
+ * waiting synchronously upon the vblank.
+ */
+ schedule_delayed_work(&work->work, msecs_to_jiffies(50));
+}
+
+void intel_disable_fbc(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ intel_cancel_fbc_work(dev_priv);
+
+ if (!dev_priv->display.disable_fbc)
+ return;
+
+ dev_priv->display.disable_fbc(dev);
+ dev_priv->cfb_plane = -1;
+}
+
+/**
+ * intel_update_fbc - enable/disable FBC as needed
+ * @dev: the drm_device
+ *
+ * Set up the framebuffer compression hardware at mode set time. We
+ * enable it if possible:
+ * - plane A only (on pre-965)
+ * - no pixel mulitply/line duplication
+ * - no alpha buffer discard
+ * - no dual wide
+ * - framebuffer <= 2048 in width, 1536 in height
+ *
+ * We can't assume that any compression will take place (worst case),
+ * so the compressed buffer has to be the same size as the uncompressed
+ * one. It also must reside (along with the line length buffer) in
+ * stolen memory.
+ *
+ * We need to enable/disable FBC on a global basis.
+ */
+void intel_update_fbc(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc = NULL, *tmp_crtc;
+ struct intel_crtc *intel_crtc;
+ struct drm_framebuffer *fb;
+ struct intel_framebuffer *intel_fb;
+ struct drm_i915_gem_object *obj;
+ int enable_fbc;
+
+ DRM_DEBUG_KMS("\n");
+
+ if (!i915_powersave)
+ return;
+
+ if (!I915_HAS_FBC(dev))
+ return;
+
+ /*
+ * If FBC is already on, we just have to verify that we can
+ * keep it that way...
+ * Need to disable if:
+ * - more than one pipe is active
+ * - changing FBC params (stride, fence, mode)
+ * - new fb is too large to fit in compressed buffer
+ * - going to an unsupported config (interlace, pixel multiply, etc.)
+ */
+ list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) {
+ if (tmp_crtc->enabled && tmp_crtc->fb) {
+ if (crtc) {
+ DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
+ dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES;
+ goto out_disable;
+ }
+ crtc = tmp_crtc;
+ }
+ }
+
+ if (!crtc || crtc->fb == NULL) {
+ DRM_DEBUG_KMS("no output, disabling\n");
+ dev_priv->no_fbc_reason = FBC_NO_OUTPUT;
+ goto out_disable;
+ }
+
+ intel_crtc = to_intel_crtc(crtc);
+ fb = crtc->fb;
+ intel_fb = to_intel_framebuffer(fb);
+ obj = intel_fb->obj;
+
+ enable_fbc = i915_enable_fbc;
+ if (enable_fbc < 0) {
+ DRM_DEBUG_KMS("fbc set to per-chip default\n");
+ enable_fbc = 1;
+ if (INTEL_INFO(dev)->gen <= 6)
+ enable_fbc = 0;
+ }
+ if (!enable_fbc) {
+ DRM_DEBUG_KMS("fbc disabled per module param\n");
+ dev_priv->no_fbc_reason = FBC_MODULE_PARAM;
+ goto out_disable;
+ }
+ if (intel_fb->obj->base.size > dev_priv->cfb_size) {
+ DRM_DEBUG_KMS("framebuffer too large, disabling "
+ "compression\n");
+ dev_priv->no_fbc_reason = FBC_STOLEN_TOO_SMALL;
+ goto out_disable;
+ }
+ if ((crtc->mode.flags & DRM_MODE_FLAG_INTERLACE) ||
+ (crtc->mode.flags & DRM_MODE_FLAG_DBLSCAN)) {
+ DRM_DEBUG_KMS("mode incompatible with compression, "
+ "disabling\n");
+ dev_priv->no_fbc_reason = FBC_UNSUPPORTED_MODE;
+ goto out_disable;
+ }
+ if ((crtc->mode.hdisplay > 2048) ||
+ (crtc->mode.vdisplay > 1536)) {
+ DRM_DEBUG_KMS("mode too large for compression, disabling\n");
+ dev_priv->no_fbc_reason = FBC_MODE_TOO_LARGE;
+ goto out_disable;
+ }
+ if ((IS_I915GM(dev) || IS_I945GM(dev)) && intel_crtc->plane != 0) {
+ DRM_DEBUG_KMS("plane not 0, disabling compression\n");
+ dev_priv->no_fbc_reason = FBC_BAD_PLANE;
+ goto out_disable;
+ }
+
+ /* The use of a CPU fence is mandatory in order to detect writes
+ * by the CPU to the scanout and trigger updates to the FBC.
+ */
+ if (obj->tiling_mode != I915_TILING_X ||
+ obj->fence_reg == I915_FENCE_REG_NONE) {
+ DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n");
+ dev_priv->no_fbc_reason = FBC_NOT_TILED;
+ goto out_disable;
+ }
+
+ /* If the kernel debugger is active, always disable compression */
+ if (in_dbg_master())
+ goto out_disable;
+
+ /* If the scanout has not changed, don't modify the FBC settings.
+ * Note that we make the fundamental assumption that the fb->obj
+ * cannot be unpinned (and have its GTT offset and fence revoked)
+ * without first being decoupled from the scanout and FBC disabled.
+ */
+ if (dev_priv->cfb_plane == intel_crtc->plane &&
+ dev_priv->cfb_fb == fb->base.id &&
+ dev_priv->cfb_y == crtc->y)
+ return;
+
+ if (intel_fbc_enabled(dev)) {
+ /* We update FBC along two paths, after changing fb/crtc
+ * configuration (modeswitching) and after page-flipping
+ * finishes. For the latter, we know that not only did
+ * we disable the FBC at the start of the page-flip
+ * sequence, but also more than one vblank has passed.
+ *
+ * For the former case of modeswitching, it is possible
+ * to switch between two FBC valid configurations
+ * instantaneously so we do need to disable the FBC
+ * before we can modify its control registers. We also
+ * have to wait for the next vblank for that to take
+ * effect. However, since we delay enabling FBC we can
+ * assume that a vblank has passed since disabling and
+ * that we can safely alter the registers in the deferred
+ * callback.
+ *
+ * In the scenario that we go from a valid to invalid
+ * and then back to valid FBC configuration we have
+ * no strict enforcement that a vblank occurred since
+ * disabling the FBC. However, along all current pipe
+ * disabling paths we do need to wait for a vblank at
+ * some point. And we wait before enabling FBC anyway.
+ */
+ DRM_DEBUG_KMS("disabling active FBC for update\n");
+ intel_disable_fbc(dev);
+ }
+
+ intel_enable_fbc(crtc, 500);
+ return;
+
+out_disable:
+ /* Multiple disables should be harmless */
+ if (intel_fbc_enabled(dev)) {
+ DRM_DEBUG_KMS("unsupported config, disabling FBC\n");
+ intel_disable_fbc(dev);
+ }
+}
+
+static void i915_pineview_get_mem_freq(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ u32 tmp;
+
+ tmp = I915_READ(CLKCFG);
+
+ switch (tmp & CLKCFG_FSB_MASK) {
+ case CLKCFG_FSB_533:
+ dev_priv->fsb_freq = 533; /* 133*4 */
+ break;
+ case CLKCFG_FSB_800:
+ dev_priv->fsb_freq = 800; /* 200*4 */
+ break;
+ case CLKCFG_FSB_667:
+ dev_priv->fsb_freq = 667; /* 167*4 */
+ break;
+ case CLKCFG_FSB_400:
+ dev_priv->fsb_freq = 400; /* 100*4 */
+ break;
+ }
+
+ switch (tmp & CLKCFG_MEM_MASK) {
+ case CLKCFG_MEM_533:
+ dev_priv->mem_freq = 533;
+ break;
+ case CLKCFG_MEM_667:
+ dev_priv->mem_freq = 667;
+ break;
+ case CLKCFG_MEM_800:
+ dev_priv->mem_freq = 800;
+ break;
+ }
+
+ /* detect pineview DDR3 setting */
+ tmp = I915_READ(CSHRDDR3CTL);
+ dev_priv->is_ddr3 = (tmp & CSHRDDR3CTL_DDR3) ? 1 : 0;
+}
+
+static void i915_ironlake_get_mem_freq(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ u16 ddrpll, csipll;
+
+ ddrpll = I915_READ16(DDRMPLL1);
+ csipll = I915_READ16(CSIPLL0);
+
+ switch (ddrpll & 0xff) {
+ case 0xc:
+ dev_priv->mem_freq = 800;
+ break;
+ case 0x10:
+ dev_priv->mem_freq = 1066;
+ break;
+ case 0x14:
+ dev_priv->mem_freq = 1333;
+ break;
+ case 0x18:
+ dev_priv->mem_freq = 1600;
+ break;
+ default:
+ DRM_DEBUG_DRIVER("unknown memory frequency 0x%02x\n",
+ ddrpll & 0xff);
+ dev_priv->mem_freq = 0;
+ break;
+ }
+
+ dev_priv->r_t = dev_priv->mem_freq;
+
+ switch (csipll & 0x3ff) {
+ case 0x00c:
+ dev_priv->fsb_freq = 3200;
+ break;
+ case 0x00e:
+ dev_priv->fsb_freq = 3733;
+ break;
+ case 0x010:
+ dev_priv->fsb_freq = 4266;
+ break;
+ case 0x012:
+ dev_priv->fsb_freq = 4800;
+ break;
+ case 0x014:
+ dev_priv->fsb_freq = 5333;
+ break;
+ case 0x016:
+ dev_priv->fsb_freq = 5866;
+ break;
+ case 0x018:
+ dev_priv->fsb_freq = 6400;
+ break;
+ default:
+ DRM_DEBUG_DRIVER("unknown fsb frequency 0x%04x\n",
+ csipll & 0x3ff);
+ dev_priv->fsb_freq = 0;
+ break;
+ }
+
+ if (dev_priv->fsb_freq == 3200) {
+ dev_priv->c_m = 0;
+ } else if (dev_priv->fsb_freq > 3200 && dev_priv->fsb_freq <= 4800) {
+ dev_priv->c_m = 1;
+ } else {
+ dev_priv->c_m = 2;
+ }
+}
+
+static const struct cxsr_latency cxsr_latency_table[] = {
+ {1, 0, 800, 400, 3382, 33382, 3983, 33983}, /* DDR2-400 SC */
+ {1, 0, 800, 667, 3354, 33354, 3807, 33807}, /* DDR2-667 SC */
+ {1, 0, 800, 800, 3347, 33347, 3763, 33763}, /* DDR2-800 SC */
+ {1, 1, 800, 667, 6420, 36420, 6873, 36873}, /* DDR3-667 SC */
+ {1, 1, 800, 800, 5902, 35902, 6318, 36318}, /* DDR3-800 SC */
+
+ {1, 0, 667, 400, 3400, 33400, 4021, 34021}, /* DDR2-400 SC */
+ {1, 0, 667, 667, 3372, 33372, 3845, 33845}, /* DDR2-667 SC */
+ {1, 0, 667, 800, 3386, 33386, 3822, 33822}, /* DDR2-800 SC */
+ {1, 1, 667, 667, 6438, 36438, 6911, 36911}, /* DDR3-667 SC */
+ {1, 1, 667, 800, 5941, 35941, 6377, 36377}, /* DDR3-800 SC */
+
+ {1, 0, 400, 400, 3472, 33472, 4173, 34173}, /* DDR2-400 SC */
+ {1, 0, 400, 667, 3443, 33443, 3996, 33996}, /* DDR2-667 SC */
+ {1, 0, 400, 800, 3430, 33430, 3946, 33946}, /* DDR2-800 SC */
+ {1, 1, 400, 667, 6509, 36509, 7062, 37062}, /* DDR3-667 SC */
+ {1, 1, 400, 800, 5985, 35985, 6501, 36501}, /* DDR3-800 SC */
+
+ {0, 0, 800, 400, 3438, 33438, 4065, 34065}, /* DDR2-400 SC */
+ {0, 0, 800, 667, 3410, 33410, 3889, 33889}, /* DDR2-667 SC */
+ {0, 0, 800, 800, 3403, 33403, 3845, 33845}, /* DDR2-800 SC */
+ {0, 1, 800, 667, 6476, 36476, 6955, 36955}, /* DDR3-667 SC */
+ {0, 1, 800, 800, 5958, 35958, 6400, 36400}, /* DDR3-800 SC */
+
+ {0, 0, 667, 400, 3456, 33456, 4103, 34106}, /* DDR2-400 SC */
+ {0, 0, 667, 667, 3428, 33428, 3927, 33927}, /* DDR2-667 SC */
+ {0, 0, 667, 800, 3443, 33443, 3905, 33905}, /* DDR2-800 SC */
+ {0, 1, 667, 667, 6494, 36494, 6993, 36993}, /* DDR3-667 SC */
+ {0, 1, 667, 800, 5998, 35998, 6460, 36460}, /* DDR3-800 SC */
+
+ {0, 0, 400, 400, 3528, 33528, 4255, 34255}, /* DDR2-400 SC */
+ {0, 0, 400, 667, 3500, 33500, 4079, 34079}, /* DDR2-667 SC */
+ {0, 0, 400, 800, 3487, 33487, 4029, 34029}, /* DDR2-800 SC */
+ {0, 1, 400, 667, 6566, 36566, 7145, 37145}, /* DDR3-667 SC */
+ {0, 1, 400, 800, 6042, 36042, 6584, 36584}, /* DDR3-800 SC */
+};
+
+static const struct cxsr_latency *intel_get_cxsr_latency(int is_desktop,
+ int is_ddr3,
+ int fsb,
+ int mem)
+{
+ const struct cxsr_latency *latency;
+ int i;
+
+ if (fsb == 0 || mem == 0)
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(cxsr_latency_table); i++) {
+ latency = &cxsr_latency_table[i];
+ if (is_desktop == latency->is_desktop &&
+ is_ddr3 == latency->is_ddr3 &&
+ fsb == latency->fsb_freq && mem == latency->mem_freq)
+ return latency;
+ }
+
+ DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n");
+
+ return NULL;
+}
+
+static void pineview_disable_cxsr(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ /* deactivate cxsr */
+ I915_WRITE(DSPFW3, I915_READ(DSPFW3) & ~PINEVIEW_SELF_REFRESH_EN);
+}
+
+/*
+ * Latency for FIFO fetches is dependent on several factors:
+ * - memory configuration (speed, channels)
+ * - chipset
+ * - current MCH state
+ * It can be fairly high in some situations, so here we assume a fairly
+ * pessimal value. It's a tradeoff between extra memory fetches (if we
+ * set this value too high, the FIFO will fetch frequently to stay full)
+ * and power consumption (set it too low to save power and we might see
+ * FIFO underruns and display "flicker").
+ *
+ * A value of 5us seems to be a good balance; safe for very low end
+ * platforms but not overly aggressive on lower latency configs.
+ */
+static const int latency_ns = 5000;
+
+static int i9xx_get_fifo_size(struct drm_device *dev, int plane)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t dsparb = I915_READ(DSPARB);
+ int size;
+
+ size = dsparb & 0x7f;
+ if (plane)
+ size = ((dsparb >> DSPARB_CSTART_SHIFT) & 0x7f) - size;
+
+ DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
+ plane ? "B" : "A", size);
+
+ return size;
+}
+
+static int i85x_get_fifo_size(struct drm_device *dev, int plane)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t dsparb = I915_READ(DSPARB);
+ int size;
+
+ size = dsparb & 0x1ff;
+ if (plane)
+ size = ((dsparb >> DSPARB_BEND_SHIFT) & 0x1ff) - size;
+ size >>= 1; /* Convert to cachelines */
+
+ DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
+ plane ? "B" : "A", size);
+
+ return size;
+}
+
+static int i845_get_fifo_size(struct drm_device *dev, int plane)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t dsparb = I915_READ(DSPARB);
+ int size;
+
+ size = dsparb & 0x7f;
+ size >>= 2; /* Convert to cachelines */
+
+ DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
+ plane ? "B" : "A",
+ size);
+
+ return size;
+}
+
+static int i830_get_fifo_size(struct drm_device *dev, int plane)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t dsparb = I915_READ(DSPARB);
+ int size;
+
+ size = dsparb & 0x7f;
+ size >>= 1; /* Convert to cachelines */
+
+ DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
+ plane ? "B" : "A", size);
+
+ return size;
+}
+
+/* Pineview has different values for various configs */
+static const struct intel_watermark_params pineview_display_wm = {
+ PINEVIEW_DISPLAY_FIFO,
+ PINEVIEW_MAX_WM,
+ PINEVIEW_DFT_WM,
+ PINEVIEW_GUARD_WM,
+ PINEVIEW_FIFO_LINE_SIZE
+};
+static const struct intel_watermark_params pineview_display_hplloff_wm = {
+ PINEVIEW_DISPLAY_FIFO,
+ PINEVIEW_MAX_WM,
+ PINEVIEW_DFT_HPLLOFF_WM,
+ PINEVIEW_GUARD_WM,
+ PINEVIEW_FIFO_LINE_SIZE
+};
+static const struct intel_watermark_params pineview_cursor_wm = {
+ PINEVIEW_CURSOR_FIFO,
+ PINEVIEW_CURSOR_MAX_WM,
+ PINEVIEW_CURSOR_DFT_WM,
+ PINEVIEW_CURSOR_GUARD_WM,
+ PINEVIEW_FIFO_LINE_SIZE,
+};
+static const struct intel_watermark_params pineview_cursor_hplloff_wm = {
+ PINEVIEW_CURSOR_FIFO,
+ PINEVIEW_CURSOR_MAX_WM,
+ PINEVIEW_CURSOR_DFT_WM,
+ PINEVIEW_CURSOR_GUARD_WM,
+ PINEVIEW_FIFO_LINE_SIZE
+};
+static const struct intel_watermark_params g4x_wm_info = {
+ G4X_FIFO_SIZE,
+ G4X_MAX_WM,
+ G4X_MAX_WM,
+ 2,
+ G4X_FIFO_LINE_SIZE,
+};
+static const struct intel_watermark_params g4x_cursor_wm_info = {
+ I965_CURSOR_FIFO,
+ I965_CURSOR_MAX_WM,
+ I965_CURSOR_DFT_WM,
+ 2,
+ G4X_FIFO_LINE_SIZE,
+};
+static const struct intel_watermark_params valleyview_wm_info = {
+ VALLEYVIEW_FIFO_SIZE,
+ VALLEYVIEW_MAX_WM,
+ VALLEYVIEW_MAX_WM,
+ 2,
+ G4X_FIFO_LINE_SIZE,
+};
+static const struct intel_watermark_params valleyview_cursor_wm_info = {
+ I965_CURSOR_FIFO,
+ VALLEYVIEW_CURSOR_MAX_WM,
+ I965_CURSOR_DFT_WM,
+ 2,
+ G4X_FIFO_LINE_SIZE,
+};
+static const struct intel_watermark_params i965_cursor_wm_info = {
+ I965_CURSOR_FIFO,
+ I965_CURSOR_MAX_WM,
+ I965_CURSOR_DFT_WM,
+ 2,
+ I915_FIFO_LINE_SIZE,
+};
+static const struct intel_watermark_params i945_wm_info = {
+ I945_FIFO_SIZE,
+ I915_MAX_WM,
+ 1,
+ 2,
+ I915_FIFO_LINE_SIZE
+};
+static const struct intel_watermark_params i915_wm_info = {
+ I915_FIFO_SIZE,
+ I915_MAX_WM,
+ 1,
+ 2,
+ I915_FIFO_LINE_SIZE
+};
+static const struct intel_watermark_params i855_wm_info = {
+ I855GM_FIFO_SIZE,
+ I915_MAX_WM,
+ 1,
+ 2,
+ I830_FIFO_LINE_SIZE
+};
+static const struct intel_watermark_params i830_wm_info = {
+ I830_FIFO_SIZE,
+ I915_MAX_WM,
+ 1,
+ 2,
+ I830_FIFO_LINE_SIZE
+};
+
+static const struct intel_watermark_params ironlake_display_wm_info = {
+ ILK_DISPLAY_FIFO,
+ ILK_DISPLAY_MAXWM,
+ ILK_DISPLAY_DFTWM,
+ 2,
+ ILK_FIFO_LINE_SIZE
+};
+static const struct intel_watermark_params ironlake_cursor_wm_info = {
+ ILK_CURSOR_FIFO,
+ ILK_CURSOR_MAXWM,
+ ILK_CURSOR_DFTWM,
+ 2,
+ ILK_FIFO_LINE_SIZE
+};
+static const struct intel_watermark_params ironlake_display_srwm_info = {
+ ILK_DISPLAY_SR_FIFO,
+ ILK_DISPLAY_MAX_SRWM,
+ ILK_DISPLAY_DFT_SRWM,
+ 2,
+ ILK_FIFO_LINE_SIZE
+};
+static const struct intel_watermark_params ironlake_cursor_srwm_info = {
+ ILK_CURSOR_SR_FIFO,
+ ILK_CURSOR_MAX_SRWM,
+ ILK_CURSOR_DFT_SRWM,
+ 2,
+ ILK_FIFO_LINE_SIZE
+};
+
+static const struct intel_watermark_params sandybridge_display_wm_info = {
+ SNB_DISPLAY_FIFO,
+ SNB_DISPLAY_MAXWM,
+ SNB_DISPLAY_DFTWM,
+ 2,
+ SNB_FIFO_LINE_SIZE
+};
+static const struct intel_watermark_params sandybridge_cursor_wm_info = {
+ SNB_CURSOR_FIFO,
+ SNB_CURSOR_MAXWM,
+ SNB_CURSOR_DFTWM,
+ 2,
+ SNB_FIFO_LINE_SIZE
+};
+static const struct intel_watermark_params sandybridge_display_srwm_info = {
+ SNB_DISPLAY_SR_FIFO,
+ SNB_DISPLAY_MAX_SRWM,
+ SNB_DISPLAY_DFT_SRWM,
+ 2,
+ SNB_FIFO_LINE_SIZE
+};
+static const struct intel_watermark_params sandybridge_cursor_srwm_info = {
+ SNB_CURSOR_SR_FIFO,
+ SNB_CURSOR_MAX_SRWM,
+ SNB_CURSOR_DFT_SRWM,
+ 2,
+ SNB_FIFO_LINE_SIZE
+};
+
+
+/**
+ * intel_calculate_wm - calculate watermark level
+ * @clock_in_khz: pixel clock
+ * @wm: chip FIFO params
+ * @pixel_size: display pixel size
+ * @latency_ns: memory latency for the platform
+ *
+ * Calculate the watermark level (the level at which the display plane will
+ * start fetching from memory again). Each chip has a different display
+ * FIFO size and allocation, so the caller needs to figure that out and pass
+ * in the correct intel_watermark_params structure.
+ *
+ * As the pixel clock runs, the FIFO will be drained at a rate that depends
+ * on the pixel size. When it reaches the watermark level, it'll start
+ * fetching FIFO line sized based chunks from memory until the FIFO fills
+ * past the watermark point. If the FIFO drains completely, a FIFO underrun
+ * will occur, and a display engine hang could result.
+ */
+static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
+ const struct intel_watermark_params *wm,
+ int fifo_size,
+ int pixel_size,
+ unsigned long latency_ns)
+{
+ long entries_required, wm_size;
+
+ /*
+ * Note: we need to make sure we don't overflow for various clock &
+ * latency values.
+ * clocks go from a few thousand to several hundred thousand.
+ * latency is usually a few thousand
+ */
+ entries_required = ((clock_in_khz / 1000) * pixel_size * latency_ns) /
+ 1000;
+ entries_required = DIV_ROUND_UP(entries_required, wm->cacheline_size);
+
+ DRM_DEBUG_KMS("FIFO entries required for mode: %ld\n", entries_required);
+
+ wm_size = fifo_size - (entries_required + wm->guard_size);
+
+ DRM_DEBUG_KMS("FIFO watermark level: %ld\n", wm_size);
+
+ /* Don't promote wm_size to unsigned... */
+ if (wm_size > (long)wm->max_wm)
+ wm_size = wm->max_wm;
+ if (wm_size <= 0)
+ wm_size = wm->default_wm;
+ return wm_size;
+}
+
+static struct drm_crtc *single_enabled_crtc(struct drm_device *dev)
+{
+ struct drm_crtc *crtc, *enabled = NULL;
+
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ if (crtc->enabled && crtc->fb) {
+ if (enabled)
+ return NULL;
+ enabled = crtc;
+ }
+ }
+
+ return enabled;
+}
+
+static void pineview_update_wm(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc;
+ const struct cxsr_latency *latency;
+ u32 reg;
+ unsigned long wm;
+
+ latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->is_ddr3,
+ dev_priv->fsb_freq, dev_priv->mem_freq);
+ if (!latency) {
+ DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n");
+ pineview_disable_cxsr(dev);
+ return;
+ }
+
+ crtc = single_enabled_crtc(dev);
+ if (crtc) {
+ int clock = crtc->mode.clock;
+ int pixel_size = crtc->fb->bits_per_pixel / 8;
+
+ /* Display SR */
+ wm = intel_calculate_wm(clock, &pineview_display_wm,
+ pineview_display_wm.fifo_size,
+ pixel_size, latency->display_sr);
+ reg = I915_READ(DSPFW1);
+ reg &= ~DSPFW_SR_MASK;
+ reg |= wm << DSPFW_SR_SHIFT;
+ I915_WRITE(DSPFW1, reg);
+ DRM_DEBUG_KMS("DSPFW1 register is %x\n", reg);
+
+ /* cursor SR */
+ wm = intel_calculate_wm(clock, &pineview_cursor_wm,
+ pineview_display_wm.fifo_size,
+ pixel_size, latency->cursor_sr);
+ reg = I915_READ(DSPFW3);
+ reg &= ~DSPFW_CURSOR_SR_MASK;
+ reg |= (wm & 0x3f) << DSPFW_CURSOR_SR_SHIFT;
+ I915_WRITE(DSPFW3, reg);
+
+ /* Display HPLL off SR */
+ wm = intel_calculate_wm(clock, &pineview_display_hplloff_wm,
+ pineview_display_hplloff_wm.fifo_size,
+ pixel_size, latency->display_hpll_disable);
+ reg = I915_READ(DSPFW3);
+ reg &= ~DSPFW_HPLL_SR_MASK;
+ reg |= wm & DSPFW_HPLL_SR_MASK;
+ I915_WRITE(DSPFW3, reg);
+
+ /* cursor HPLL off SR */
+ wm = intel_calculate_wm(clock, &pineview_cursor_hplloff_wm,
+ pineview_display_hplloff_wm.fifo_size,
+ pixel_size, latency->cursor_hpll_disable);
+ reg = I915_READ(DSPFW3);
+ reg &= ~DSPFW_HPLL_CURSOR_MASK;
+ reg |= (wm & 0x3f) << DSPFW_HPLL_CURSOR_SHIFT;
+ I915_WRITE(DSPFW3, reg);
+ DRM_DEBUG_KMS("DSPFW3 register is %x\n", reg);
+
+ /* activate cxsr */
+ I915_WRITE(DSPFW3,
+ I915_READ(DSPFW3) | PINEVIEW_SELF_REFRESH_EN);
+ DRM_DEBUG_KMS("Self-refresh is enabled\n");
+ } else {
+ pineview_disable_cxsr(dev);
+ DRM_DEBUG_KMS("Self-refresh is disabled\n");
+ }
+}
+
+static bool g4x_compute_wm0(struct drm_device *dev,
+ int plane,
+ const struct intel_watermark_params *display,
+ int display_latency_ns,
+ const struct intel_watermark_params *cursor,
+ int cursor_latency_ns,
+ int *plane_wm,
+ int *cursor_wm)
+{
+ struct drm_crtc *crtc;
+ int htotal, hdisplay, clock, pixel_size;
+ int line_time_us, line_count;
+ int entries, tlb_miss;
+
+ crtc = intel_get_crtc_for_plane(dev, plane);
+ if (crtc->fb == NULL || !crtc->enabled) {
+ *cursor_wm = cursor->guard_size;
+ *plane_wm = display->guard_size;
+ return false;
+ }
+
+ htotal = crtc->mode.htotal;
+ hdisplay = crtc->mode.hdisplay;
+ clock = crtc->mode.clock;
+ pixel_size = crtc->fb->bits_per_pixel / 8;
+
+ /* Use the small buffer method to calculate plane watermark */
+ entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000;
+ tlb_miss = display->fifo_size*display->cacheline_size - hdisplay * 8;
+ if (tlb_miss > 0)
+ entries += tlb_miss;
+ entries = DIV_ROUND_UP(entries, display->cacheline_size);
+ *plane_wm = entries + display->guard_size;
+ if (*plane_wm > (int)display->max_wm)
+ *plane_wm = display->max_wm;
+
+ /* Use the large buffer method to calculate cursor watermark */
+ line_time_us = ((htotal * 1000) / clock);
+ line_count = (cursor_latency_ns / line_time_us + 1000) / 1000;
+ entries = line_count * 64 * pixel_size;
+ tlb_miss = cursor->fifo_size*cursor->cacheline_size - hdisplay * 8;
+ if (tlb_miss > 0)
+ entries += tlb_miss;
+ entries = DIV_ROUND_UP(entries, cursor->cacheline_size);
+ *cursor_wm = entries + cursor->guard_size;
+ if (*cursor_wm > (int)cursor->max_wm)
+ *cursor_wm = (int)cursor->max_wm;
+
+ return true;
+}
+
+/*
+ * Check the wm result.
+ *
+ * If any calculated watermark values is larger than the maximum value that
+ * can be programmed into the associated watermark register, that watermark
+ * must be disabled.
+ */
+static bool g4x_check_srwm(struct drm_device *dev,
+ int display_wm, int cursor_wm,
+ const struct intel_watermark_params *display,
+ const struct intel_watermark_params *cursor)
+{
+ DRM_DEBUG_KMS("SR watermark: display plane %d, cursor %d\n",
+ display_wm, cursor_wm);
+
+ if (display_wm > display->max_wm) {
+ DRM_DEBUG_KMS("display watermark is too large(%d/%ld), disabling\n",
+ display_wm, display->max_wm);
+ return false;
+ }
+
+ if (cursor_wm > cursor->max_wm) {
+ DRM_DEBUG_KMS("cursor watermark is too large(%d/%ld), disabling\n",
+ cursor_wm, cursor->max_wm);
+ return false;
+ }
+
+ if (!(display_wm || cursor_wm)) {
+ DRM_DEBUG_KMS("SR latency is 0, disabling\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool g4x_compute_srwm(struct drm_device *dev,
+ int plane,
+ int latency_ns,
+ const struct intel_watermark_params *display,
+ const struct intel_watermark_params *cursor,
+ int *display_wm, int *cursor_wm)
+{
+ struct drm_crtc *crtc;
+ int hdisplay, htotal, pixel_size, clock;
+ unsigned long line_time_us;
+ int line_count, line_size;
+ int small, large;
+ int entries;
+
+ if (!latency_ns) {
+ *display_wm = *cursor_wm = 0;
+ return false;
+ }
+
+ crtc = intel_get_crtc_for_plane(dev, plane);
+ hdisplay = crtc->mode.hdisplay;
+ htotal = crtc->mode.htotal;
+ clock = crtc->mode.clock;
+ pixel_size = crtc->fb->bits_per_pixel / 8;
+
+ line_time_us = (htotal * 1000) / clock;
+ line_count = (latency_ns / line_time_us + 1000) / 1000;
+ line_size = hdisplay * pixel_size;
+
+ /* Use the minimum of the small and large buffer method for primary */
+ small = ((clock * pixel_size / 1000) * latency_ns) / 1000;
+ large = line_count * line_size;
+
+ entries = DIV_ROUND_UP(min(small, large), display->cacheline_size);
+ *display_wm = entries + display->guard_size;
+
+ /* calculate the self-refresh watermark for display cursor */
+ entries = line_count * pixel_size * 64;
+ entries = DIV_ROUND_UP(entries, cursor->cacheline_size);
+ *cursor_wm = entries + cursor->guard_size;
+
+ return g4x_check_srwm(dev,
+ *display_wm, *cursor_wm,
+ display, cursor);
+}
+
+static bool vlv_compute_drain_latency(struct drm_device *dev,
+ int plane,
+ int *plane_prec_mult,
+ int *plane_dl,
+ int *cursor_prec_mult,
+ int *cursor_dl)
+{
+ struct drm_crtc *crtc;
+ int clock, pixel_size;
+ int entries;
+
+ crtc = intel_get_crtc_for_plane(dev, plane);
+ if (crtc->fb == NULL || !crtc->enabled)
+ return false;
+
+ clock = crtc->mode.clock; /* VESA DOT Clock */
+ pixel_size = crtc->fb->bits_per_pixel / 8; /* BPP */
+
+ entries = (clock / 1000) * pixel_size;
+ *plane_prec_mult = (entries > 256) ?
+ DRAIN_LATENCY_PRECISION_32 : DRAIN_LATENCY_PRECISION_16;
+ *plane_dl = (64 * (*plane_prec_mult) * 4) / ((clock / 1000) *
+ pixel_size);
+
+ entries = (clock / 1000) * 4; /* BPP is always 4 for cursor */
+ *cursor_prec_mult = (entries > 256) ?
+ DRAIN_LATENCY_PRECISION_32 : DRAIN_LATENCY_PRECISION_16;
+ *cursor_dl = (64 * (*cursor_prec_mult) * 4) / ((clock / 1000) * 4);
+
+ return true;
+}
+
+/*
+ * Update drain latency registers of memory arbiter
+ *
+ * Valleyview SoC has a new memory arbiter and needs drain latency registers
+ * to be programmed. Each plane has a drain latency multiplier and a drain
+ * latency value.
+ */
+
+static void vlv_update_drain_latency(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int planea_prec, planea_dl, planeb_prec, planeb_dl;
+ int cursora_prec, cursora_dl, cursorb_prec, cursorb_dl;
+ int plane_prec_mult, cursor_prec_mult; /* Precision multiplier is
+ either 16 or 32 */
+
+ /* For plane A, Cursor A */
+ if (vlv_compute_drain_latency(dev, 0, &plane_prec_mult, &planea_dl,
+ &cursor_prec_mult, &cursora_dl)) {
+ cursora_prec = (cursor_prec_mult == DRAIN_LATENCY_PRECISION_32) ?
+ DDL_CURSORA_PRECISION_32 : DDL_CURSORA_PRECISION_16;
+ planea_prec = (plane_prec_mult == DRAIN_LATENCY_PRECISION_32) ?
+ DDL_PLANEA_PRECISION_32 : DDL_PLANEA_PRECISION_16;
+
+ I915_WRITE(VLV_DDL1, cursora_prec |
+ (cursora_dl << DDL_CURSORA_SHIFT) |
+ planea_prec | planea_dl);
+ }
+
+ /* For plane B, Cursor B */
+ if (vlv_compute_drain_latency(dev, 1, &plane_prec_mult, &planeb_dl,
+ &cursor_prec_mult, &cursorb_dl)) {
+ cursorb_prec = (cursor_prec_mult == DRAIN_LATENCY_PRECISION_32) ?
+ DDL_CURSORB_PRECISION_32 : DDL_CURSORB_PRECISION_16;
+ planeb_prec = (plane_prec_mult == DRAIN_LATENCY_PRECISION_32) ?
+ DDL_PLANEB_PRECISION_32 : DDL_PLANEB_PRECISION_16;
+
+ I915_WRITE(VLV_DDL2, cursorb_prec |
+ (cursorb_dl << DDL_CURSORB_SHIFT) |
+ planeb_prec | planeb_dl);
+ }
+}
+
+#define single_plane_enabled(mask) is_power_of_2(mask)
+
+static void valleyview_update_wm(struct drm_device *dev)
+{
+ static const int sr_latency_ns = 12000;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int planea_wm, planeb_wm, cursora_wm, cursorb_wm;
+ int plane_sr, cursor_sr;
+ unsigned int enabled = 0;
+
+ vlv_update_drain_latency(dev);
+
+ if (g4x_compute_wm0(dev, 0,
+ &valleyview_wm_info, latency_ns,
+ &valleyview_cursor_wm_info, latency_ns,
+ &planea_wm, &cursora_wm))
+ enabled |= 1;
+
+ if (g4x_compute_wm0(dev, 1,
+ &valleyview_wm_info, latency_ns,
+ &valleyview_cursor_wm_info, latency_ns,
+ &planeb_wm, &cursorb_wm))
+ enabled |= 2;
+
+ plane_sr = cursor_sr = 0;
+ if (single_plane_enabled(enabled) &&
+ g4x_compute_srwm(dev, ffs(enabled) - 1,
+ sr_latency_ns,
+ &valleyview_wm_info,
+ &valleyview_cursor_wm_info,
+ &plane_sr, &cursor_sr))
+ I915_WRITE(FW_BLC_SELF_VLV, FW_CSPWRDWNEN);
+ else
+ I915_WRITE(FW_BLC_SELF_VLV,
+ I915_READ(FW_BLC_SELF_VLV) & ~FW_CSPWRDWNEN);
+
+ DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n",
+ planea_wm, cursora_wm,
+ planeb_wm, cursorb_wm,
+ plane_sr, cursor_sr);
+
+ I915_WRITE(DSPFW1,
+ (plane_sr << DSPFW_SR_SHIFT) |
+ (cursorb_wm << DSPFW_CURSORB_SHIFT) |
+ (planeb_wm << DSPFW_PLANEB_SHIFT) |
+ planea_wm);
+ I915_WRITE(DSPFW2,
+ (I915_READ(DSPFW2) & DSPFW_CURSORA_MASK) |
+ (cursora_wm << DSPFW_CURSORA_SHIFT));
+ I915_WRITE(DSPFW3,
+ (I915_READ(DSPFW3) | (cursor_sr << DSPFW_CURSOR_SR_SHIFT)));
+}
+
+static void g4x_update_wm(struct drm_device *dev)
+{
+ static const int sr_latency_ns = 12000;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int planea_wm, planeb_wm, cursora_wm, cursorb_wm;
+ int plane_sr, cursor_sr;
+ unsigned int enabled = 0;
+
+ if (g4x_compute_wm0(dev, 0,
+ &g4x_wm_info, latency_ns,
+ &g4x_cursor_wm_info, latency_ns,
+ &planea_wm, &cursora_wm))
+ enabled |= 1;
+
+ if (g4x_compute_wm0(dev, 1,
+ &g4x_wm_info, latency_ns,
+ &g4x_cursor_wm_info, latency_ns,
+ &planeb_wm, &cursorb_wm))
+ enabled |= 2;
+
+ plane_sr = cursor_sr = 0;
+ if (single_plane_enabled(enabled) &&
+ g4x_compute_srwm(dev, ffs(enabled) - 1,
+ sr_latency_ns,
+ &g4x_wm_info,
+ &g4x_cursor_wm_info,
+ &plane_sr, &cursor_sr))
+ I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
+ else
+ I915_WRITE(FW_BLC_SELF,
+ I915_READ(FW_BLC_SELF) & ~FW_BLC_SELF_EN);
+
+ DRM_DEBUG_KMS("Setting FIFO watermarks - A: plane=%d, cursor=%d, B: plane=%d, cursor=%d, SR: plane=%d, cursor=%d\n",
+ planea_wm, cursora_wm,
+ planeb_wm, cursorb_wm,
+ plane_sr, cursor_sr);
+
+ I915_WRITE(DSPFW1,
+ (plane_sr << DSPFW_SR_SHIFT) |
+ (cursorb_wm << DSPFW_CURSORB_SHIFT) |
+ (planeb_wm << DSPFW_PLANEB_SHIFT) |
+ planea_wm);
+ I915_WRITE(DSPFW2,
+ (I915_READ(DSPFW2) & DSPFW_CURSORA_MASK) |
+ (cursora_wm << DSPFW_CURSORA_SHIFT));
+ /* HPLL off in SR has some issues on G4x... disable it */
+ I915_WRITE(DSPFW3,
+ (I915_READ(DSPFW3) & ~DSPFW_HPLL_SR_EN) |
+ (cursor_sr << DSPFW_CURSOR_SR_SHIFT));
+}
+
+static void i965_update_wm(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc;
+ int srwm = 1;
+ int cursor_sr = 16;
+
+ /* Calc sr entries for one plane configs */
+ crtc = single_enabled_crtc(dev);
+ if (crtc) {
+ /* self-refresh has much higher latency */
+ static const int sr_latency_ns = 12000;
+ int clock = crtc->mode.clock;
+ int htotal = crtc->mode.htotal;
+ int hdisplay = crtc->mode.hdisplay;
+ int pixel_size = crtc->fb->bits_per_pixel / 8;
+ unsigned long line_time_us;
+ int entries;
+
+ line_time_us = ((htotal * 1000) / clock);
+
+ /* Use ns/us then divide to preserve precision */
+ entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
+ pixel_size * hdisplay;
+ entries = DIV_ROUND_UP(entries, I915_FIFO_LINE_SIZE);
+ srwm = I965_FIFO_SIZE - entries;
+ if (srwm < 0)
+ srwm = 1;
+ srwm &= 0x1ff;
+ DRM_DEBUG_KMS("self-refresh entries: %d, wm: %d\n",
+ entries, srwm);
+
+ entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
+ pixel_size * 64;
+ entries = DIV_ROUND_UP(entries,
+ i965_cursor_wm_info.cacheline_size);
+ cursor_sr = i965_cursor_wm_info.fifo_size -
+ (entries + i965_cursor_wm_info.guard_size);
+
+ if (cursor_sr > i965_cursor_wm_info.max_wm)
+ cursor_sr = i965_cursor_wm_info.max_wm;
+
+ DRM_DEBUG_KMS("self-refresh watermark: display plane %d "
+ "cursor %d\n", srwm, cursor_sr);
+
+ if (IS_CRESTLINE(dev))
+ I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
+ } else {
+ /* Turn off self refresh if both pipes are enabled */
+ if (IS_CRESTLINE(dev))
+ I915_WRITE(FW_BLC_SELF, I915_READ(FW_BLC_SELF)
+ & ~FW_BLC_SELF_EN);
+ }
+
+ DRM_DEBUG_KMS("Setting FIFO watermarks - A: 8, B: 8, C: 8, SR %d\n",
+ srwm);
+
+ /* 965 has limitations... */
+ I915_WRITE(DSPFW1, (srwm << DSPFW_SR_SHIFT) |
+ (8 << 16) | (8 << 8) | (8 << 0));
+ I915_WRITE(DSPFW2, (8 << 8) | (8 << 0));
+ /* update cursor SR watermark */
+ I915_WRITE(DSPFW3, (cursor_sr << DSPFW_CURSOR_SR_SHIFT));
+}
+
+static void i9xx_update_wm(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ const struct intel_watermark_params *wm_info;
+ uint32_t fwater_lo;
+ uint32_t fwater_hi;
+ int cwm, srwm = 1;
+ int fifo_size;
+ int planea_wm, planeb_wm;
+ struct drm_crtc *crtc, *enabled = NULL;
+
+ if (IS_I945GM(dev))
+ wm_info = &i945_wm_info;
+ else if (!IS_GEN2(dev))
+ wm_info = &i915_wm_info;
+ else
+ wm_info = &i855_wm_info;
+
+ fifo_size = dev_priv->display.get_fifo_size(dev, 0);
+ crtc = intel_get_crtc_for_plane(dev, 0);
+ if (crtc->enabled && crtc->fb) {
+ planea_wm = intel_calculate_wm(crtc->mode.clock,
+ wm_info, fifo_size,
+ crtc->fb->bits_per_pixel / 8,
+ latency_ns);
+ enabled = crtc;
+ } else
+ planea_wm = fifo_size - wm_info->guard_size;
+
+ fifo_size = dev_priv->display.get_fifo_size(dev, 1);
+ crtc = intel_get_crtc_for_plane(dev, 1);
+ if (crtc->enabled && crtc->fb) {
+ planeb_wm = intel_calculate_wm(crtc->mode.clock,
+ wm_info, fifo_size,
+ crtc->fb->bits_per_pixel / 8,
+ latency_ns);
+ if (enabled == NULL)
+ enabled = crtc;
+ else
+ enabled = NULL;
+ } else
+ planeb_wm = fifo_size - wm_info->guard_size;
+
+ DRM_DEBUG_KMS("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm);
+
+ /*
+ * Overlay gets an aggressive default since video jitter is bad.
+ */
+ cwm = 2;
+
+ /* Play safe and disable self-refresh before adjusting watermarks. */
+ if (IS_I945G(dev) || IS_I945GM(dev))
+ I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | 0);
+ else if (IS_I915GM(dev))
+ I915_WRITE(INSTPM, I915_READ(INSTPM) & ~INSTPM_SELF_EN);
+
+ /* Calc sr entries for one plane configs */
+ if (HAS_FW_BLC(dev) && enabled) {
+ /* self-refresh has much higher latency */
+ static const int sr_latency_ns = 6000;
+ int clock = enabled->mode.clock;
+ int htotal = enabled->mode.htotal;
+ int hdisplay = enabled->mode.hdisplay;
+ int pixel_size = enabled->fb->bits_per_pixel / 8;
+ unsigned long line_time_us;
+ int entries;
+
+ line_time_us = (htotal * 1000) / clock;
+
+ /* Use ns/us then divide to preserve precision */
+ entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
+ pixel_size * hdisplay;
+ entries = DIV_ROUND_UP(entries, wm_info->cacheline_size);
+ DRM_DEBUG_KMS("self-refresh entries: %d\n", entries);
+ srwm = wm_info->fifo_size - entries;
+ if (srwm < 0)
+ srwm = 1;
+
+ if (IS_I945G(dev) || IS_I945GM(dev))
+ I915_WRITE(FW_BLC_SELF,
+ FW_BLC_SELF_FIFO_MASK | (srwm & 0xff));
+ else if (IS_I915GM(dev))
+ I915_WRITE(FW_BLC_SELF, srwm & 0x3f);
+ }
+
+ DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, C: %d, SR %d\n",
+ planea_wm, planeb_wm, cwm, srwm);
+
+ fwater_lo = ((planeb_wm & 0x3f) << 16) | (planea_wm & 0x3f);
+ fwater_hi = (cwm & 0x1f);
+
+ /* Set request length to 8 cachelines per fetch */
+ fwater_lo = fwater_lo | (1 << 24) | (1 << 8);
+ fwater_hi = fwater_hi | (1 << 8);
+
+ I915_WRITE(FW_BLC, fwater_lo);
+ I915_WRITE(FW_BLC2, fwater_hi);
+
+ if (HAS_FW_BLC(dev)) {
+ if (enabled) {
+ if (IS_I945G(dev) || IS_I945GM(dev))
+ I915_WRITE(FW_BLC_SELF,
+ FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN);
+ else if (IS_I915GM(dev))
+ I915_WRITE(INSTPM, I915_READ(INSTPM) | INSTPM_SELF_EN);
+ DRM_DEBUG_KMS("memory self refresh enabled\n");
+ } else
+ DRM_DEBUG_KMS("memory self refresh disabled\n");
+ }
+}
+
+static void i830_update_wm(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc;
+ uint32_t fwater_lo;
+ int planea_wm;
+
+ crtc = single_enabled_crtc(dev);
+ if (crtc == NULL)
+ return;
+
+ planea_wm = intel_calculate_wm(crtc->mode.clock, &i830_wm_info,
+ dev_priv->display.get_fifo_size(dev, 0),
+ crtc->fb->bits_per_pixel / 8,
+ latency_ns);
+ fwater_lo = I915_READ(FW_BLC) & ~0xfff;
+ fwater_lo |= (3<<8) | planea_wm;
+
+ DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d\n", planea_wm);
+
+ I915_WRITE(FW_BLC, fwater_lo);
+}
+
+#define ILK_LP0_PLANE_LATENCY 700
+#define ILK_LP0_CURSOR_LATENCY 1300
+
+/*
+ * Check the wm result.
+ *
+ * If any calculated watermark values is larger than the maximum value that
+ * can be programmed into the associated watermark register, that watermark
+ * must be disabled.
+ */
+static bool ironlake_check_srwm(struct drm_device *dev, int level,
+ int fbc_wm, int display_wm, int cursor_wm,
+ const struct intel_watermark_params *display,
+ const struct intel_watermark_params *cursor)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ DRM_DEBUG_KMS("watermark %d: display plane %d, fbc lines %d,"
+ " cursor %d\n", level, display_wm, fbc_wm, cursor_wm);
+
+ if (fbc_wm > SNB_FBC_MAX_SRWM) {
+ DRM_DEBUG_KMS("fbc watermark(%d) is too large(%d), disabling wm%d+\n",
+ fbc_wm, SNB_FBC_MAX_SRWM, level);
+
+ /* fbc has it's own way to disable FBC WM */
+ I915_WRITE(DISP_ARB_CTL,
+ I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS);
+ return false;
+ }
+
+ if (display_wm > display->max_wm) {
+ DRM_DEBUG_KMS("display watermark(%d) is too large(%d), disabling wm%d+\n",
+ display_wm, SNB_DISPLAY_MAX_SRWM, level);
+ return false;
+ }
+
+ if (cursor_wm > cursor->max_wm) {
+ DRM_DEBUG_KMS("cursor watermark(%d) is too large(%d), disabling wm%d+\n",
+ cursor_wm, SNB_CURSOR_MAX_SRWM, level);
+ return false;
+ }
+
+ if (!(fbc_wm || display_wm || cursor_wm)) {
+ DRM_DEBUG_KMS("latency %d is 0, disabling wm%d+\n", level, level);
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Compute watermark values of WM[1-3],
+ */
+static bool ironlake_compute_srwm(struct drm_device *dev, int level, int plane,
+ int latency_ns,
+ const struct intel_watermark_params *display,
+ const struct intel_watermark_params *cursor,
+ int *fbc_wm, int *display_wm, int *cursor_wm)
+{
+ struct drm_crtc *crtc;
+ unsigned long line_time_us;
+ int hdisplay, htotal, pixel_size, clock;
+ int line_count, line_size;
+ int small, large;
+ int entries;
+
+ if (!latency_ns) {
+ *fbc_wm = *display_wm = *cursor_wm = 0;
+ return false;
+ }
+
+ crtc = intel_get_crtc_for_plane(dev, plane);
+ hdisplay = crtc->mode.hdisplay;
+ htotal = crtc->mode.htotal;
+ clock = crtc->mode.clock;
+ pixel_size = crtc->fb->bits_per_pixel / 8;
+
+ line_time_us = (htotal * 1000) / clock;
+ line_count = (latency_ns / line_time_us + 1000) / 1000;
+ line_size = hdisplay * pixel_size;
+
+ /* Use the minimum of the small and large buffer method for primary */
+ small = ((clock * pixel_size / 1000) * latency_ns) / 1000;
+ large = line_count * line_size;
+
+ entries = DIV_ROUND_UP(min(small, large), display->cacheline_size);
+ *display_wm = entries + display->guard_size;
+
+ /*
+ * Spec says:
+ * FBC WM = ((Final Primary WM * 64) / number of bytes per line) + 2
+ */
+ *fbc_wm = DIV_ROUND_UP(*display_wm * 64, line_size) + 2;
+
+ /* calculate the self-refresh watermark for display cursor */
+ entries = line_count * pixel_size * 64;
+ entries = DIV_ROUND_UP(entries, cursor->cacheline_size);
+ *cursor_wm = entries + cursor->guard_size;
+
+ return ironlake_check_srwm(dev, level,
+ *fbc_wm, *display_wm, *cursor_wm,
+ display, cursor);
+}
+
+static void ironlake_update_wm(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int fbc_wm, plane_wm, cursor_wm;
+ unsigned int enabled;
+
+ enabled = 0;
+ if (g4x_compute_wm0(dev, 0,
+ &ironlake_display_wm_info,
+ ILK_LP0_PLANE_LATENCY,
+ &ironlake_cursor_wm_info,
+ ILK_LP0_CURSOR_LATENCY,
+ &plane_wm, &cursor_wm)) {
+ I915_WRITE(WM0_PIPEA_ILK,
+ (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+ DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
+ " plane %d, " "cursor: %d\n",
+ plane_wm, cursor_wm);
+ enabled |= 1;
+ }
+
+ if (g4x_compute_wm0(dev, 1,
+ &ironlake_display_wm_info,
+ ILK_LP0_PLANE_LATENCY,
+ &ironlake_cursor_wm_info,
+ ILK_LP0_CURSOR_LATENCY,
+ &plane_wm, &cursor_wm)) {
+ I915_WRITE(WM0_PIPEB_ILK,
+ (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+ DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
+ " plane %d, cursor: %d\n",
+ plane_wm, cursor_wm);
+ enabled |= 2;
+ }
+
+ /*
+ * Calculate and update the self-refresh watermark only when one
+ * display plane is used.
+ */
+ I915_WRITE(WM3_LP_ILK, 0);
+ I915_WRITE(WM2_LP_ILK, 0);
+ I915_WRITE(WM1_LP_ILK, 0);
+
+ if (!single_plane_enabled(enabled))
+ return;
+ enabled = ffs(enabled) - 1;
+
+ /* WM1 */
+ if (!ironlake_compute_srwm(dev, 1, enabled,
+ ILK_READ_WM1_LATENCY() * 500,
+ &ironlake_display_srwm_info,
+ &ironlake_cursor_srwm_info,
+ &fbc_wm, &plane_wm, &cursor_wm))
+ return;
+
+ I915_WRITE(WM1_LP_ILK,
+ WM1_LP_SR_EN |
+ (ILK_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) |
+ (fbc_wm << WM1_LP_FBC_SHIFT) |
+ (plane_wm << WM1_LP_SR_SHIFT) |
+ cursor_wm);
+
+ /* WM2 */
+ if (!ironlake_compute_srwm(dev, 2, enabled,
+ ILK_READ_WM2_LATENCY() * 500,
+ &ironlake_display_srwm_info,
+ &ironlake_cursor_srwm_info,
+ &fbc_wm, &plane_wm, &cursor_wm))
+ return;
+
+ I915_WRITE(WM2_LP_ILK,
+ WM2_LP_EN |
+ (ILK_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) |
+ (fbc_wm << WM1_LP_FBC_SHIFT) |
+ (plane_wm << WM1_LP_SR_SHIFT) |
+ cursor_wm);
+
+ /*
+ * WM3 is unsupported on ILK, probably because we don't have latency
+ * data for that power state
+ */
+}
+
+static void sandybridge_update_wm(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */
+ u32 val;
+ int fbc_wm, plane_wm, cursor_wm;
+ unsigned int enabled;
+
+ enabled = 0;
+ if (g4x_compute_wm0(dev, 0,
+ &sandybridge_display_wm_info, latency,
+ &sandybridge_cursor_wm_info, latency,
+ &plane_wm, &cursor_wm)) {
+ val = I915_READ(WM0_PIPEA_ILK);
+ val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
+ I915_WRITE(WM0_PIPEA_ILK, val |
+ ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
+ DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
+ " plane %d, " "cursor: %d\n",
+ plane_wm, cursor_wm);
+ enabled |= 1;
+ }
+
+ if (g4x_compute_wm0(dev, 1,
+ &sandybridge_display_wm_info, latency,
+ &sandybridge_cursor_wm_info, latency,
+ &plane_wm, &cursor_wm)) {
+ val = I915_READ(WM0_PIPEB_ILK);
+ val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
+ I915_WRITE(WM0_PIPEB_ILK, val |
+ ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
+ DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
+ " plane %d, cursor: %d\n",
+ plane_wm, cursor_wm);
+ enabled |= 2;
+ }
+
+ if ((dev_priv->num_pipe == 3) &&
+ g4x_compute_wm0(dev, 2,
+ &sandybridge_display_wm_info, latency,
+ &sandybridge_cursor_wm_info, latency,
+ &plane_wm, &cursor_wm)) {
+ val = I915_READ(WM0_PIPEC_IVB);
+ val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
+ I915_WRITE(WM0_PIPEC_IVB, val |
+ ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
+ DRM_DEBUG_KMS("FIFO watermarks For pipe C -"
+ " plane %d, cursor: %d\n",
+ plane_wm, cursor_wm);
+ enabled |= 3;
+ }
+
+ /*
+ * Calculate and update the self-refresh watermark only when one
+ * display plane is used.
+ *
+ * SNB support 3 levels of watermark.
+ *
+ * WM1/WM2/WM2 watermarks have to be enabled in the ascending order,
+ * and disabled in the descending order
+ *
+ */
+ I915_WRITE(WM3_LP_ILK, 0);
+ I915_WRITE(WM2_LP_ILK, 0);
+ I915_WRITE(WM1_LP_ILK, 0);
+
+ if (!single_plane_enabled(enabled) ||
+ dev_priv->sprite_scaling_enabled)
+ return;
+ enabled = ffs(enabled) - 1;
+
+ /* WM1 */
+ if (!ironlake_compute_srwm(dev, 1, enabled,
+ SNB_READ_WM1_LATENCY() * 500,
+ &sandybridge_display_srwm_info,
+ &sandybridge_cursor_srwm_info,
+ &fbc_wm, &plane_wm, &cursor_wm))
+ return;
+
+ I915_WRITE(WM1_LP_ILK,
+ WM1_LP_SR_EN |
+ (SNB_READ_WM1_LATENCY() << WM1_LP_LATENCY_SHIFT) |
+ (fbc_wm << WM1_LP_FBC_SHIFT) |
+ (plane_wm << WM1_LP_SR_SHIFT) |
+ cursor_wm);
+
+ /* WM2 */
+ if (!ironlake_compute_srwm(dev, 2, enabled,
+ SNB_READ_WM2_LATENCY() * 500,
+ &sandybridge_display_srwm_info,
+ &sandybridge_cursor_srwm_info,
+ &fbc_wm, &plane_wm, &cursor_wm))
+ return;
+
+ I915_WRITE(WM2_LP_ILK,
+ WM2_LP_EN |
+ (SNB_READ_WM2_LATENCY() << WM1_LP_LATENCY_SHIFT) |
+ (fbc_wm << WM1_LP_FBC_SHIFT) |
+ (plane_wm << WM1_LP_SR_SHIFT) |
+ cursor_wm);
+
+ /* WM3 */
+ if (!ironlake_compute_srwm(dev, 3, enabled,
+ SNB_READ_WM3_LATENCY() * 500,
+ &sandybridge_display_srwm_info,
+ &sandybridge_cursor_srwm_info,
+ &fbc_wm, &plane_wm, &cursor_wm))
+ return;
+
+ I915_WRITE(WM3_LP_ILK,
+ WM3_LP_EN |
+ (SNB_READ_WM3_LATENCY() << WM1_LP_LATENCY_SHIFT) |
+ (fbc_wm << WM1_LP_FBC_SHIFT) |
+ (plane_wm << WM1_LP_SR_SHIFT) |
+ cursor_wm);
+}
+
+static void
+haswell_update_linetime_wm(struct drm_device *dev, int pipe,
+ struct drm_display_mode *mode)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 temp;
+
+ temp = I915_READ(PIPE_WM_LINETIME(pipe));
+ temp &= ~PIPE_WM_LINETIME_MASK;
+
+ /* The WM are computed with base on how long it takes to fill a single
+ * row at the given clock rate, multiplied by 8.
+ * */
+ temp |= PIPE_WM_LINETIME_TIME(
+ ((mode->crtc_hdisplay * 1000) / mode->clock) * 8);
+
+ /* IPS watermarks are only used by pipe A, and are ignored by
+ * pipes B and C. They are calculated similarly to the common
+ * linetime values, except that we are using CD clock frequency
+ * in MHz instead of pixel rate for the division.
+ *
+ * This is a placeholder for the IPS watermark calculation code.
+ */
+
+ I915_WRITE(PIPE_WM_LINETIME(pipe), temp);
+}
+
+static bool
+sandybridge_compute_sprite_wm(struct drm_device *dev, int plane,
+ uint32_t sprite_width, int pixel_size,
+ const struct intel_watermark_params *display,
+ int display_latency_ns, int *sprite_wm)
+{
+ struct drm_crtc *crtc;
+ int clock;
+ int entries, tlb_miss;
+
+ crtc = intel_get_crtc_for_plane(dev, plane);
+ if (crtc->fb == NULL || !crtc->enabled) {
+ *sprite_wm = display->guard_size;
+ return false;
+ }
+
+ clock = crtc->mode.clock;
+
+ /* Use the small buffer method to calculate the sprite watermark */
+ entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000;
+ tlb_miss = display->fifo_size*display->cacheline_size -
+ sprite_width * 8;
+ if (tlb_miss > 0)
+ entries += tlb_miss;
+ entries = DIV_ROUND_UP(entries, display->cacheline_size);
+ *sprite_wm = entries + display->guard_size;
+ if (*sprite_wm > (int)display->max_wm)
+ *sprite_wm = display->max_wm;
+
+ return true;
+}
+
+static bool
+sandybridge_compute_sprite_srwm(struct drm_device *dev, int plane,
+ uint32_t sprite_width, int pixel_size,
+ const struct intel_watermark_params *display,
+ int latency_ns, int *sprite_wm)
+{
+ struct drm_crtc *crtc;
+ unsigned long line_time_us;
+ int clock;
+ int line_count, line_size;
+ int small, large;
+ int entries;
+
+ if (!latency_ns) {
+ *sprite_wm = 0;
+ return false;
+ }
+
+ crtc = intel_get_crtc_for_plane(dev, plane);
+ clock = crtc->mode.clock;
+ if (!clock) {
+ *sprite_wm = 0;
+ return false;
+ }
+
+ line_time_us = (sprite_width * 1000) / clock;
+ if (!line_time_us) {
+ *sprite_wm = 0;
+ return false;
+ }
+
+ line_count = (latency_ns / line_time_us + 1000) / 1000;
+ line_size = sprite_width * pixel_size;
+
+ /* Use the minimum of the small and large buffer method for primary */
+ small = ((clock * pixel_size / 1000) * latency_ns) / 1000;
+ large = line_count * line_size;
+
+ entries = DIV_ROUND_UP(min(small, large), display->cacheline_size);
+ *sprite_wm = entries + display->guard_size;
+
+ return *sprite_wm > 0x3ff ? false : true;
+}
+
+static void sandybridge_update_sprite_wm(struct drm_device *dev, int pipe,
+ uint32_t sprite_width, int pixel_size)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int latency = SNB_READ_WM0_LATENCY() * 100; /* In unit 0.1us */
+ u32 val;
+ int sprite_wm, reg;
+ int ret;
+
+ switch (pipe) {
+ case 0:
+ reg = WM0_PIPEA_ILK;
+ break;
+ case 1:
+ reg = WM0_PIPEB_ILK;
+ break;
+ case 2:
+ reg = WM0_PIPEC_IVB;
+ break;
+ default:
+ return; /* bad pipe */
+ }
+
+ ret = sandybridge_compute_sprite_wm(dev, pipe, sprite_width, pixel_size,
+ &sandybridge_display_wm_info,
+ latency, &sprite_wm);
+ if (!ret) {
+ DRM_DEBUG_KMS("failed to compute sprite wm for pipe %d\n",
+ pipe);
+ return;
+ }
+
+ val = I915_READ(reg);
+ val &= ~WM0_PIPE_SPRITE_MASK;
+ I915_WRITE(reg, val | (sprite_wm << WM0_PIPE_SPRITE_SHIFT));
+ DRM_DEBUG_KMS("sprite watermarks For pipe %d - %d\n", pipe, sprite_wm);
+
+
+ ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width,
+ pixel_size,
+ &sandybridge_display_srwm_info,
+ SNB_READ_WM1_LATENCY() * 500,
+ &sprite_wm);
+ if (!ret) {
+ DRM_DEBUG_KMS("failed to compute sprite lp1 wm on pipe %d\n",
+ pipe);
+ return;
+ }
+ I915_WRITE(WM1S_LP_ILK, sprite_wm);
+
+ /* Only IVB has two more LP watermarks for sprite */
+ if (!IS_IVYBRIDGE(dev))
+ return;
+
+ ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width,
+ pixel_size,
+ &sandybridge_display_srwm_info,
+ SNB_READ_WM2_LATENCY() * 500,
+ &sprite_wm);
+ if (!ret) {
+ DRM_DEBUG_KMS("failed to compute sprite lp2 wm on pipe %d\n",
+ pipe);
+ return;
+ }
+ I915_WRITE(WM2S_LP_IVB, sprite_wm);
+
+ ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width,
+ pixel_size,
+ &sandybridge_display_srwm_info,
+ SNB_READ_WM3_LATENCY() * 500,
+ &sprite_wm);
+ if (!ret) {
+ DRM_DEBUG_KMS("failed to compute sprite lp3 wm on pipe %d\n",
+ pipe);
+ return;
+ }
+ I915_WRITE(WM3S_LP_IVB, sprite_wm);
+}
+
+/**
+ * intel_update_watermarks - update FIFO watermark values based on current modes
+ *
+ * Calculate watermark values for the various WM regs based on current mode
+ * and plane configuration.
+ *
+ * There are several cases to deal with here:
+ * - normal (i.e. non-self-refresh)
+ * - self-refresh (SR) mode
+ * - lines are large relative to FIFO size (buffer can hold up to 2)
+ * - lines are small relative to FIFO size (buffer can hold more than 2
+ * lines), so need to account for TLB latency
+ *
+ * The normal calculation is:
+ * watermark = dotclock * bytes per pixel * latency
+ * where latency is platform & configuration dependent (we assume pessimal
+ * values here).
+ *
+ * The SR calculation is:
+ * watermark = (trunc(latency/line time)+1) * surface width *
+ * bytes per pixel
+ * where
+ * line time = htotal / dotclock
+ * surface width = hdisplay for normal plane and 64 for cursor
+ * and latency is assumed to be high, as above.
+ *
+ * The final value programmed to the register should always be rounded up,
+ * and include an extra 2 entries to account for clock crossings.
+ *
+ * We don't use the sprite, so we can ignore that. And on Crestline we have
+ * to set the non-SR watermarks to 8.
+ */
+void intel_update_watermarks(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->display.update_wm)
+ dev_priv->display.update_wm(dev);
+}
+
+void intel_update_linetime_watermarks(struct drm_device *dev,
+ int pipe, struct drm_display_mode *mode)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->display.update_linetime_wm)
+ dev_priv->display.update_linetime_wm(dev, pipe, mode);
+}
+
+void intel_update_sprite_watermarks(struct drm_device *dev, int pipe,
+ uint32_t sprite_width, int pixel_size)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->display.update_sprite_wm)
+ dev_priv->display.update_sprite_wm(dev, pipe, sprite_width,
+ pixel_size);
+}
+
+static struct drm_i915_gem_object *
+intel_alloc_context_page(struct drm_device *dev)
+{
+ struct drm_i915_gem_object *ctx;
+ int ret;
+
+ WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
+ ctx = i915_gem_alloc_object(dev, 4096);
+ if (!ctx) {
+ DRM_DEBUG("failed to alloc power context, RC6 disabled\n");
+ return NULL;
+ }
+
+ ret = i915_gem_object_pin(ctx, 4096, true);
+ if (ret) {
+ DRM_ERROR("failed to pin power context: %d\n", ret);
+ goto err_unref;
+ }
+
+ ret = i915_gem_object_set_to_gtt_domain(ctx, 1);
+ if (ret) {
+ DRM_ERROR("failed to set-domain on power context: %d\n", ret);
+ goto err_unpin;
+ }
+
+ return ctx;
+
+err_unpin:
+ i915_gem_object_unpin(ctx);
+err_unref:
+ drm_gem_object_unreference(&ctx->base);
+ mutex_unlock(&dev->struct_mutex);
+ return NULL;
+}
+
+bool ironlake_set_drps(struct drm_device *dev, u8 val)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u16 rgvswctl;
+
+ rgvswctl = I915_READ16(MEMSWCTL);
+ if (rgvswctl & MEMCTL_CMD_STS) {
+ DRM_DEBUG("gpu busy, RCS change rejected\n");
+ return false; /* still busy with another command */
+ }
+
+ rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
+ (val << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
+ I915_WRITE16(MEMSWCTL, rgvswctl);
+ POSTING_READ16(MEMSWCTL);
+
+ rgvswctl |= MEMCTL_CMD_STS;
+ I915_WRITE16(MEMSWCTL, rgvswctl);
+
+ return true;
+}
+
+void ironlake_enable_drps(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 rgvmodectl = I915_READ(MEMMODECTL);
+ u8 fmax, fmin, fstart, vstart;
+
+ /* Enable temp reporting */
+ I915_WRITE16(PMMISC, I915_READ(PMMISC) | MCPPCE_EN);
+ I915_WRITE16(TSC1, I915_READ(TSC1) | TSE);
+
+ /* 100ms RC evaluation intervals */
+ I915_WRITE(RCUPEI, 100000);
+ I915_WRITE(RCDNEI, 100000);
+
+ /* Set max/min thresholds to 90ms and 80ms respectively */
+ I915_WRITE(RCBMAXAVG, 90000);
+ I915_WRITE(RCBMINAVG, 80000);
+
+ I915_WRITE(MEMIHYST, 1);
+
+ /* Set up min, max, and cur for interrupt handling */
+ fmax = (rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT;
+ fmin = (rgvmodectl & MEMMODE_FMIN_MASK);
+ fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >>
+ MEMMODE_FSTART_SHIFT;
+
+ vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >>
+ PXVFREQ_PX_SHIFT;
+
+ dev_priv->fmax = fmax; /* IPS callback will increase this */
+ dev_priv->fstart = fstart;
+
+ dev_priv->max_delay = fstart;
+ dev_priv->min_delay = fmin;
+ dev_priv->cur_delay = fstart;
+
+ DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n",
+ fmax, fmin, fstart);
+
+ I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN);
+
+ /*
+ * Interrupts will be enabled in ironlake_irq_postinstall
+ */
+
+ I915_WRITE(VIDSTART, vstart);
+ POSTING_READ(VIDSTART);
+
+ rgvmodectl |= MEMMODE_SWMODE_EN;
+ I915_WRITE(MEMMODECTL, rgvmodectl);
+
+ if (wait_for((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10))
+ DRM_ERROR("stuck trying to change perf mode\n");
+ msleep(1);
+
+ ironlake_set_drps(dev, fstart);
+
+ dev_priv->last_count1 = I915_READ(0x112e4) + I915_READ(0x112e8) +
+ I915_READ(0x112e0);
+ dev_priv->last_time1 = jiffies_to_msecs(jiffies);
+ dev_priv->last_count2 = I915_READ(0x112f4);
+ getrawmonotonic(&dev_priv->last_time2);
+}
+
+void ironlake_disable_drps(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u16 rgvswctl = I915_READ16(MEMSWCTL);
+
+ /* Ack interrupts, disable EFC interrupt */
+ I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN);
+ I915_WRITE(MEMINTRSTS, MEMINT_EVAL_CHG);
+ I915_WRITE(DEIER, I915_READ(DEIER) & ~DE_PCU_EVENT);
+ I915_WRITE(DEIIR, DE_PCU_EVENT);
+ I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT);
+
+ /* Go back to the starting frequency */
+ ironlake_set_drps(dev, dev_priv->fstart);
+ msleep(1);
+ rgvswctl |= MEMCTL_CMD_STS;
+ I915_WRITE(MEMSWCTL, rgvswctl);
+ msleep(1);
+
+}
+
+void gen6_set_rps(struct drm_device *dev, u8 val)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 swreq;
+
+ swreq = (val & 0x3ff) << 25;
+ I915_WRITE(GEN6_RPNSWREQ, swreq);
+}
+
+void gen6_disable_rps(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
+ I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
+ I915_WRITE(GEN6_PMIER, 0);
+ /* Complete PM interrupt masking here doesn't race with the rps work
+ * item again unmasking PM interrupts because that is using a different
+ * register (PMIMR) to mask PM interrupts. The only risk is in leaving
+ * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */
+
+ spin_lock_irq(&dev_priv->rps_lock);
+ dev_priv->pm_iir = 0;
+ spin_unlock_irq(&dev_priv->rps_lock);
+
+ I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
+}
+
+int intel_enable_rc6(const struct drm_device *dev)
+{
+ /*
+ * Respect the kernel parameter if it is set
+ */
+ if (i915_enable_rc6 >= 0)
+ return i915_enable_rc6;
+
+ /*
+ * Disable RC6 on Ironlake
+ */
+ if (INTEL_INFO(dev)->gen == 5)
+ return 0;
+
+ /* Sorry Haswell, no RC6 for you for now. */
+ if (IS_HASWELL(dev))
+ return 0;
+
+ /*
+ * Disable rc6 on Sandybridge
+ */
+ if (INTEL_INFO(dev)->gen == 6) {
+ DRM_DEBUG_DRIVER("Sandybridge: deep RC6 disabled\n");
+ return INTEL_RC6_ENABLE;
+ }
+ DRM_DEBUG_DRIVER("RC6 and deep RC6 enabled\n");
+ return (INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE);
+}
+
+void gen6_enable_rps(struct drm_i915_private *dev_priv)
+{
+ struct intel_ring_buffer *ring;
+ u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
+ u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
+ u32 pcu_mbox, rc6_mask = 0;
+ u32 gtfifodbg;
+ int cur_freq, min_freq, max_freq;
+ int rc6_mode;
+ int i;
+
+ /* Here begins a magic sequence of register writes to enable
+ * auto-downclocking.
+ *
+ * Perhaps there might be some value in exposing these to
+ * userspace...
+ */
+ I915_WRITE(GEN6_RC_STATE, 0);
+ mutex_lock(&dev_priv->dev->struct_mutex);
+
+ /* Clear the DBG now so we don't confuse earlier errors */
+ if ((gtfifodbg = I915_READ(GTFIFODBG))) {
+ DRM_ERROR("GT fifo had a previous error %x\n", gtfifodbg);
+ I915_WRITE(GTFIFODBG, gtfifodbg);
+ }
+
+ gen6_gt_force_wake_get(dev_priv);
+
+ /* disable the counters and set deterministic thresholds */
+ I915_WRITE(GEN6_RC_CONTROL, 0);
+
+ I915_WRITE(GEN6_RC1_WAKE_RATE_LIMIT, 1000 << 16);
+ I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 40 << 16 | 30);
+ I915_WRITE(GEN6_RC6pp_WAKE_RATE_LIMIT, 30);
+ I915_WRITE(GEN6_RC_EVALUATION_INTERVAL, 125000);
+ I915_WRITE(GEN6_RC_IDLE_HYSTERSIS, 25);
+
+ for_each_ring(ring, dev_priv, i)
+ I915_WRITE(RING_MAX_IDLE(ring->mmio_base), 10);
+
+ I915_WRITE(GEN6_RC_SLEEP, 0);
+ I915_WRITE(GEN6_RC1e_THRESHOLD, 1000);
+ I915_WRITE(GEN6_RC6_THRESHOLD, 50000);
+ I915_WRITE(GEN6_RC6p_THRESHOLD, 100000);
+ I915_WRITE(GEN6_RC6pp_THRESHOLD, 64000); /* unused */
+
+ rc6_mode = intel_enable_rc6(dev_priv->dev);
+ if (rc6_mode & INTEL_RC6_ENABLE)
+ rc6_mask |= GEN6_RC_CTL_RC6_ENABLE;
+
+ if (rc6_mode & INTEL_RC6p_ENABLE)
+ rc6_mask |= GEN6_RC_CTL_RC6p_ENABLE;
+
+ if (rc6_mode & INTEL_RC6pp_ENABLE)
+ rc6_mask |= GEN6_RC_CTL_RC6pp_ENABLE;
+
+ DRM_INFO("Enabling RC6 states: RC6 %s, RC6p %s, RC6pp %s\n",
+ (rc6_mode & INTEL_RC6_ENABLE) ? "on" : "off",
+ (rc6_mode & INTEL_RC6p_ENABLE) ? "on" : "off",
+ (rc6_mode & INTEL_RC6pp_ENABLE) ? "on" : "off");
+
+ I915_WRITE(GEN6_RC_CONTROL,
+ rc6_mask |
+ GEN6_RC_CTL_EI_MODE(1) |
+ GEN6_RC_CTL_HW_ENABLE);
+
+ I915_WRITE(GEN6_RPNSWREQ,
+ GEN6_FREQUENCY(10) |
+ GEN6_OFFSET(0) |
+ GEN6_AGGRESSIVE_TURBO);
+ I915_WRITE(GEN6_RC_VIDEO_FREQ,
+ GEN6_FREQUENCY(12));
+
+ I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000);
+ I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
+ 18 << 24 |
+ 6 << 16);
+ I915_WRITE(GEN6_RP_UP_THRESHOLD, 10000);
+ I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 1000000);
+ I915_WRITE(GEN6_RP_UP_EI, 100000);
+ I915_WRITE(GEN6_RP_DOWN_EI, 5000000);
+ I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
+ I915_WRITE(GEN6_RP_CONTROL,
+ GEN6_RP_MEDIA_TURBO |
+ GEN6_RP_MEDIA_HW_MODE |
+ GEN6_RP_MEDIA_IS_GFX |
+ GEN6_RP_ENABLE |
+ GEN6_RP_UP_BUSY_AVG |
+ GEN6_RP_DOWN_IDLE_CONT);
+
+ if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
+ 500))
+ DRM_ERROR("timeout waiting for pcode mailbox to become idle\n");
+
+ I915_WRITE(GEN6_PCODE_DATA, 0);
+ I915_WRITE(GEN6_PCODE_MAILBOX,
+ GEN6_PCODE_READY |
+ GEN6_PCODE_WRITE_MIN_FREQ_TABLE);
+ if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
+ 500))
+ DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
+
+ min_freq = (rp_state_cap & 0xff0000) >> 16;
+ max_freq = rp_state_cap & 0xff;
+ cur_freq = (gt_perf_status & 0xff00) >> 8;
+
+ /* Check for overclock support */
+ if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
+ 500))
+ DRM_ERROR("timeout waiting for pcode mailbox to become idle\n");
+ I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_READ_OC_PARAMS);
+ pcu_mbox = I915_READ(GEN6_PCODE_DATA);
+ if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
+ 500))
+ DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
+ if (pcu_mbox & (1<<31)) { /* OC supported */
+ max_freq = pcu_mbox & 0xff;
+ DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50);
+ }
+
+ /* In units of 100MHz */
+ dev_priv->max_delay = max_freq;
+ dev_priv->min_delay = min_freq;
+ dev_priv->cur_delay = cur_freq;
+
+ /* requires MSI enabled */
+ I915_WRITE(GEN6_PMIER,
+ GEN6_PM_MBOX_EVENT |
+ GEN6_PM_THERMAL_EVENT |
+ GEN6_PM_RP_DOWN_TIMEOUT |
+ GEN6_PM_RP_UP_THRESHOLD |
+ GEN6_PM_RP_DOWN_THRESHOLD |
+ GEN6_PM_RP_UP_EI_EXPIRED |
+ GEN6_PM_RP_DOWN_EI_EXPIRED);
+ spin_lock_irq(&dev_priv->rps_lock);
+ WARN_ON(dev_priv->pm_iir != 0);
+ I915_WRITE(GEN6_PMIMR, 0);
+ spin_unlock_irq(&dev_priv->rps_lock);
+ /* enable all PM interrupts */
+ I915_WRITE(GEN6_PMINTRMSK, 0);
+
+ gen6_gt_force_wake_put(dev_priv);
+ mutex_unlock(&dev_priv->dev->struct_mutex);
+}
+
+void gen6_update_ring_freq(struct drm_i915_private *dev_priv)
+{
+ int min_freq = 15;
+ int gpu_freq, ia_freq, max_ia_freq;
+ int scaling_factor = 180;
+
+ max_ia_freq = cpufreq_quick_get_max(0);
+ /*
+ * Default to measured freq if none found, PCU will ensure we don't go
+ * over
+ */
+ if (!max_ia_freq)
+ max_ia_freq = tsc_khz;
+
+ /* Convert from kHz to MHz */
+ max_ia_freq /= 1000;
+
+ mutex_lock(&dev_priv->dev->struct_mutex);
+
+ /*
+ * For each potential GPU frequency, load a ring frequency we'd like
+ * to use for memory access. We do this by specifying the IA frequency
+ * the PCU should use as a reference to determine the ring frequency.
+ */
+ for (gpu_freq = dev_priv->max_delay; gpu_freq >= dev_priv->min_delay;
+ gpu_freq--) {
+ int diff = dev_priv->max_delay - gpu_freq;
+
+ /*
+ * For GPU frequencies less than 750MHz, just use the lowest
+ * ring freq.
+ */
+ if (gpu_freq < min_freq)
+ ia_freq = 800;
+ else
+ ia_freq = max_ia_freq - ((diff * scaling_factor) / 2);
+ ia_freq = DIV_ROUND_CLOSEST(ia_freq, 100);
+
+ I915_WRITE(GEN6_PCODE_DATA,
+ (ia_freq << GEN6_PCODE_FREQ_IA_RATIO_SHIFT) |
+ gpu_freq);
+ I915_WRITE(GEN6_PCODE_MAILBOX, GEN6_PCODE_READY |
+ GEN6_PCODE_WRITE_MIN_FREQ_TABLE);
+ if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) &
+ GEN6_PCODE_READY) == 0, 10)) {
+ DRM_ERROR("pcode write of freq table timed out\n");
+ continue;
+ }
+ }
+
+ mutex_unlock(&dev_priv->dev->struct_mutex);
+}
+
+static void ironlake_teardown_rc6(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->renderctx) {
+ i915_gem_object_unpin(dev_priv->renderctx);
+ drm_gem_object_unreference(&dev_priv->renderctx->base);
+ dev_priv->renderctx = NULL;
+ }
+
+ if (dev_priv->pwrctx) {
+ i915_gem_object_unpin(dev_priv->pwrctx);
+ drm_gem_object_unreference(&dev_priv->pwrctx->base);
+ dev_priv->pwrctx = NULL;
+ }
+}
+
+void ironlake_disable_rc6(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (I915_READ(PWRCTXA)) {
+ /* Wake the GPU, prevent RC6, then restore RSTDBYCTL */
+ I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) | RCX_SW_EXIT);
+ wait_for(((I915_READ(RSTDBYCTL) & RSX_STATUS_MASK) == RSX_STATUS_ON),
+ 50);
+
+ I915_WRITE(PWRCTXA, 0);
+ POSTING_READ(PWRCTXA);
+
+ I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
+ POSTING_READ(RSTDBYCTL);
+ }
+
+ ironlake_teardown_rc6(dev);
+}
+
+static int ironlake_setup_rc6(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->renderctx == NULL)
+ dev_priv->renderctx = intel_alloc_context_page(dev);
+ if (!dev_priv->renderctx)
+ return -ENOMEM;
+
+ if (dev_priv->pwrctx == NULL)
+ dev_priv->pwrctx = intel_alloc_context_page(dev);
+ if (!dev_priv->pwrctx) {
+ ironlake_teardown_rc6(dev);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void ironlake_enable_rc6(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
+ int ret;
+
+ /* rc6 disabled by default due to repeated reports of hanging during
+ * boot and resume.
+ */
+ if (!intel_enable_rc6(dev))
+ return;
+
+ mutex_lock(&dev->struct_mutex);
+ ret = ironlake_setup_rc6(dev);
+ if (ret) {
+ mutex_unlock(&dev->struct_mutex);
+ return;
+ }
+
+ /*
+ * GPU can automatically power down the render unit if given a page
+ * to save state.
+ */
+ ret = intel_ring_begin(ring, 6);
+ if (ret) {
+ ironlake_teardown_rc6(dev);
+ mutex_unlock(&dev->struct_mutex);
+ return;
+ }
+
+ intel_ring_emit(ring, MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN);
+ intel_ring_emit(ring, MI_SET_CONTEXT);
+ intel_ring_emit(ring, dev_priv->renderctx->gtt_offset |
+ MI_MM_SPACE_GTT |
+ MI_SAVE_EXT_STATE_EN |
+ MI_RESTORE_EXT_STATE_EN |
+ MI_RESTORE_INHIBIT);
+ intel_ring_emit(ring, MI_SUSPEND_FLUSH);
+ intel_ring_emit(ring, MI_NOOP);
+ intel_ring_emit(ring, MI_FLUSH);
+ intel_ring_advance(ring);
+
+ /*
+ * Wait for the command parser to advance past MI_SET_CONTEXT. The HW
+ * does an implicit flush, combined with MI_FLUSH above, it should be
+ * safe to assume that renderctx is valid
+ */
+ ret = intel_wait_ring_idle(ring);
+ if (ret) {
+ DRM_ERROR("failed to enable ironlake power power savings\n");
+ ironlake_teardown_rc6(dev);
+ mutex_unlock(&dev->struct_mutex);
+ return;
+ }
+
+ I915_WRITE(PWRCTXA, dev_priv->pwrctx->gtt_offset | PWRCTX_EN);
+ I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
+ mutex_unlock(&dev->struct_mutex);
+}
+
+static unsigned long intel_pxfreq(u32 vidfreq)
+{
+ unsigned long freq;
+ int div = (vidfreq & 0x3f0000) >> 16;
+ int post = (vidfreq & 0x3000) >> 12;
+ int pre = (vidfreq & 0x7);
+
+ if (!pre)
+ return 0;
+
+ freq = ((div * 133333) / ((1<<post) * pre));
+
+ return freq;
+}
+
+static const struct cparams {
+ u16 i;
+ u16 t;
+ u16 m;
+ u16 c;
+} cparams[] = {
+ { 1, 1333, 301, 28664 },
+ { 1, 1066, 294, 24460 },
+ { 1, 800, 294, 25192 },
+ { 0, 1333, 276, 27605 },
+ { 0, 1066, 276, 27605 },
+ { 0, 800, 231, 23784 },
+};
+
+unsigned long i915_chipset_val(struct drm_i915_private *dev_priv)
+{
+ u64 total_count, diff, ret;
+ u32 count1, count2, count3, m = 0, c = 0;
+ unsigned long now = jiffies_to_msecs(jiffies), diff1;
+ int i;
+
+ diff1 = now - dev_priv->last_time1;
+
+ /* Prevent division-by-zero if we are asking too fast.
+ * Also, we don't get interesting results if we are polling
+ * faster than once in 10ms, so just return the saved value
+ * in such cases.
+ */
+ if (diff1 <= 10)
+ return dev_priv->chipset_power;
+
+ count1 = I915_READ(DMIEC);
+ count2 = I915_READ(DDREC);
+ count3 = I915_READ(CSIEC);
+
+ total_count = count1 + count2 + count3;
+
+ /* FIXME: handle per-counter overflow */
+ if (total_count < dev_priv->last_count1) {
+ diff = ~0UL - dev_priv->last_count1;
+ diff += total_count;
+ } else {
+ diff = total_count - dev_priv->last_count1;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cparams); i++) {
+ if (cparams[i].i == dev_priv->c_m &&
+ cparams[i].t == dev_priv->r_t) {
+ m = cparams[i].m;
+ c = cparams[i].c;
+ break;
+ }
+ }
+
+ diff = div_u64(diff, diff1);
+ ret = ((m * diff) + c);
+ ret = div_u64(ret, 10);
+
+ dev_priv->last_count1 = total_count;
+ dev_priv->last_time1 = now;
+
+ dev_priv->chipset_power = ret;
+
+ return ret;
+}
+
+unsigned long i915_mch_val(struct drm_i915_private *dev_priv)
+{
+ unsigned long m, x, b;
+ u32 tsfs;
+
+ tsfs = I915_READ(TSFS);
+
+ m = ((tsfs & TSFS_SLOPE_MASK) >> TSFS_SLOPE_SHIFT);
+ x = I915_READ8(TR1);
+
+ b = tsfs & TSFS_INTR_MASK;
+
+ return ((m * x) / 127) - b;
+}
+
+static u16 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid)
+{
+ static const struct v_table {
+ u16 vd; /* in .1 mil */
+ u16 vm; /* in .1 mil */
+ } v_table[] = {
+ { 0, 0, },
+ { 375, 0, },
+ { 500, 0, },
+ { 625, 0, },
+ { 750, 0, },
+ { 875, 0, },
+ { 1000, 0, },
+ { 1125, 0, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4125, 3000, },
+ { 4250, 3125, },
+ { 4375, 3250, },
+ { 4500, 3375, },
+ { 4625, 3500, },
+ { 4750, 3625, },
+ { 4875, 3750, },
+ { 5000, 3875, },
+ { 5125, 4000, },
+ { 5250, 4125, },
+ { 5375, 4250, },
+ { 5500, 4375, },
+ { 5625, 4500, },
+ { 5750, 4625, },
+ { 5875, 4750, },
+ { 6000, 4875, },
+ { 6125, 5000, },
+ { 6250, 5125, },
+ { 6375, 5250, },
+ { 6500, 5375, },
+ { 6625, 5500, },
+ { 6750, 5625, },
+ { 6875, 5750, },
+ { 7000, 5875, },
+ { 7125, 6000, },
+ { 7250, 6125, },
+ { 7375, 6250, },
+ { 7500, 6375, },
+ { 7625, 6500, },
+ { 7750, 6625, },
+ { 7875, 6750, },
+ { 8000, 6875, },
+ { 8125, 7000, },
+ { 8250, 7125, },
+ { 8375, 7250, },
+ { 8500, 7375, },
+ { 8625, 7500, },
+ { 8750, 7625, },
+ { 8875, 7750, },
+ { 9000, 7875, },
+ { 9125, 8000, },
+ { 9250, 8125, },
+ { 9375, 8250, },
+ { 9500, 8375, },
+ { 9625, 8500, },
+ { 9750, 8625, },
+ { 9875, 8750, },
+ { 10000, 8875, },
+ { 10125, 9000, },
+ { 10250, 9125, },
+ { 10375, 9250, },
+ { 10500, 9375, },
+ { 10625, 9500, },
+ { 10750, 9625, },
+ { 10875, 9750, },
+ { 11000, 9875, },
+ { 11125, 10000, },
+ { 11250, 10125, },
+ { 11375, 10250, },
+ { 11500, 10375, },
+ { 11625, 10500, },
+ { 11750, 10625, },
+ { 11875, 10750, },
+ { 12000, 10875, },
+ { 12125, 11000, },
+ { 12250, 11125, },
+ { 12375, 11250, },
+ { 12500, 11375, },
+ { 12625, 11500, },
+ { 12750, 11625, },
+ { 12875, 11750, },
+ { 13000, 11875, },
+ { 13125, 12000, },
+ { 13250, 12125, },
+ { 13375, 12250, },
+ { 13500, 12375, },
+ { 13625, 12500, },
+ { 13750, 12625, },
+ { 13875, 12750, },
+ { 14000, 12875, },
+ { 14125, 13000, },
+ { 14250, 13125, },
+ { 14375, 13250, },
+ { 14500, 13375, },
+ { 14625, 13500, },
+ { 14750, 13625, },
+ { 14875, 13750, },
+ { 15000, 13875, },
+ { 15125, 14000, },
+ { 15250, 14125, },
+ { 15375, 14250, },
+ { 15500, 14375, },
+ { 15625, 14500, },
+ { 15750, 14625, },
+ { 15875, 14750, },
+ { 16000, 14875, },
+ { 16125, 15000, },
+ };
+ if (dev_priv->info->is_mobile)
+ return v_table[pxvid].vm;
+ else
+ return v_table[pxvid].vd;
+}
+
+void i915_update_gfx_val(struct drm_i915_private *dev_priv)
+{
+ struct timespec now, diff1;
+ u64 diff;
+ unsigned long diffms;
+ u32 count;
+
+ if (dev_priv->info->gen != 5)
+ return;
+
+ getrawmonotonic(&now);
+ diff1 = timespec_sub(now, dev_priv->last_time2);
+
+ /* Don't divide by 0 */
+ diffms = diff1.tv_sec * 1000 + diff1.tv_nsec / 1000000;
+ if (!diffms)
+ return;
+
+ count = I915_READ(GFXEC);
+
+ if (count < dev_priv->last_count2) {
+ diff = ~0UL - dev_priv->last_count2;
+ diff += count;
+ } else {
+ diff = count - dev_priv->last_count2;
+ }
+
+ dev_priv->last_count2 = count;
+ dev_priv->last_time2 = now;
+
+ /* More magic constants... */
+ diff = diff * 1181;
+ diff = div_u64(diff, diffms * 10);
+ dev_priv->gfx_power = diff;
+}
+
+unsigned long i915_gfx_val(struct drm_i915_private *dev_priv)
+{
+ unsigned long t, corr, state1, corr2, state2;
+ u32 pxvid, ext_v;
+
+ pxvid = I915_READ(PXVFREQ_BASE + (dev_priv->cur_delay * 4));
+ pxvid = (pxvid >> 24) & 0x7f;
+ ext_v = pvid_to_extvid(dev_priv, pxvid);
+
+ state1 = ext_v;
+
+ t = i915_mch_val(dev_priv);
+
+ /* Revel in the empirically derived constants */
+
+ /* Correction factor in 1/100000 units */
+ if (t > 80)
+ corr = ((t * 2349) + 135940);
+ else if (t >= 50)
+ corr = ((t * 964) + 29317);
+ else /* < 50 */
+ corr = ((t * 301) + 1004);
+
+ corr = corr * ((150142 * state1) / 10000 - 78642);
+ corr /= 100000;
+ corr2 = (corr * dev_priv->corr);
+
+ state2 = (corr2 * state1) / 10000;
+ state2 /= 100; /* convert to mW */
+
+ i915_update_gfx_val(dev_priv);
+
+ return dev_priv->gfx_power + state2;
+}
+
+/* Global for IPS driver to get at the current i915 device */
+static struct drm_i915_private *i915_mch_dev;
+/*
+ * Lock protecting IPS related data structures
+ * - i915_mch_dev
+ * - dev_priv->max_delay
+ * - dev_priv->min_delay
+ * - dev_priv->fmax
+ * - dev_priv->gpu_busy
+ */
+static DEFINE_SPINLOCK(mchdev_lock);
+
+/**
+ * i915_read_mch_val - return value for IPS use
+ *
+ * Calculate and return a value for the IPS driver to use when deciding whether
+ * we have thermal and power headroom to increase CPU or GPU power budget.
+ */
+unsigned long i915_read_mch_val(void)
+{
+ struct drm_i915_private *dev_priv;
+ unsigned long chipset_val, graphics_val, ret = 0;
+
+ spin_lock(&mchdev_lock);
+ if (!i915_mch_dev)
+ goto out_unlock;
+ dev_priv = i915_mch_dev;
+
+ chipset_val = i915_chipset_val(dev_priv);
+ graphics_val = i915_gfx_val(dev_priv);
+
+ ret = chipset_val + graphics_val;
+
+out_unlock:
+ spin_unlock(&mchdev_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(i915_read_mch_val);
+
+/**
+ * i915_gpu_raise - raise GPU frequency limit
+ *
+ * Raise the limit; IPS indicates we have thermal headroom.
+ */
+bool i915_gpu_raise(void)
+{
+ struct drm_i915_private *dev_priv;
+ bool ret = true;
+
+ spin_lock(&mchdev_lock);
+ if (!i915_mch_dev) {
+ ret = false;
+ goto out_unlock;
+ }
+ dev_priv = i915_mch_dev;
+
+ if (dev_priv->max_delay > dev_priv->fmax)
+ dev_priv->max_delay--;
+
+out_unlock:
+ spin_unlock(&mchdev_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(i915_gpu_raise);
+
+/**
+ * i915_gpu_lower - lower GPU frequency limit
+ *
+ * IPS indicates we're close to a thermal limit, so throttle back the GPU
+ * frequency maximum.
+ */
+bool i915_gpu_lower(void)
+{
+ struct drm_i915_private *dev_priv;
+ bool ret = true;
+
+ spin_lock(&mchdev_lock);
+ if (!i915_mch_dev) {
+ ret = false;
+ goto out_unlock;
+ }
+ dev_priv = i915_mch_dev;
+
+ if (dev_priv->max_delay < dev_priv->min_delay)
+ dev_priv->max_delay++;
+
+out_unlock:
+ spin_unlock(&mchdev_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(i915_gpu_lower);
+
+/**
+ * i915_gpu_busy - indicate GPU business to IPS
+ *
+ * Tell the IPS driver whether or not the GPU is busy.
+ */
+bool i915_gpu_busy(void)
+{
+ struct drm_i915_private *dev_priv;
+ bool ret = false;
+
+ spin_lock(&mchdev_lock);
+ if (!i915_mch_dev)
+ goto out_unlock;
+ dev_priv = i915_mch_dev;
+
+ ret = dev_priv->busy;
+
+out_unlock:
+ spin_unlock(&mchdev_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(i915_gpu_busy);
+
+/**
+ * i915_gpu_turbo_disable - disable graphics turbo
+ *
+ * Disable graphics turbo by resetting the max frequency and setting the
+ * current frequency to the default.
+ */
+bool i915_gpu_turbo_disable(void)
+{
+ struct drm_i915_private *dev_priv;
+ bool ret = true;
+
+ spin_lock(&mchdev_lock);
+ if (!i915_mch_dev) {
+ ret = false;
+ goto out_unlock;
+ }
+ dev_priv = i915_mch_dev;
+
+ dev_priv->max_delay = dev_priv->fstart;
+
+ if (!ironlake_set_drps(dev_priv->dev, dev_priv->fstart))
+ ret = false;
+
+out_unlock:
+ spin_unlock(&mchdev_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(i915_gpu_turbo_disable);
+
+/**
+ * Tells the intel_ips driver that the i915 driver is now loaded, if
+ * IPS got loaded first.
+ *
+ * This awkward dance is so that neither module has to depend on the
+ * other in order for IPS to do the appropriate communication of
+ * GPU turbo limits to i915.
+ */
+static void
+ips_ping_for_i915_load(void)
+{
+ void (*link)(void);
+
+ link = symbol_get(ips_link_to_i915_driver);
+ if (link) {
+ link();
+ symbol_put(ips_link_to_i915_driver);
+ }
+}
+
+void intel_gpu_ips_init(struct drm_i915_private *dev_priv)
+{
+ spin_lock(&mchdev_lock);
+ i915_mch_dev = dev_priv;
+ dev_priv->mchdev_lock = &mchdev_lock;
+ spin_unlock(&mchdev_lock);
+
+ ips_ping_for_i915_load();
+}
+
+void intel_gpu_ips_teardown(void)
+{
+ spin_lock(&mchdev_lock);
+ i915_mch_dev = NULL;
+ spin_unlock(&mchdev_lock);
+}
+
+void intel_init_emon(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 lcfuse;
+ u8 pxw[16];
+ int i;
+
+ /* Disable to program */
+ I915_WRITE(ECR, 0);
+ POSTING_READ(ECR);
+
+ /* Program energy weights for various events */
+ I915_WRITE(SDEW, 0x15040d00);
+ I915_WRITE(CSIEW0, 0x007f0000);
+ I915_WRITE(CSIEW1, 0x1e220004);
+ I915_WRITE(CSIEW2, 0x04000004);
+
+ for (i = 0; i < 5; i++)
+ I915_WRITE(PEW + (i * 4), 0);
+ for (i = 0; i < 3; i++)
+ I915_WRITE(DEW + (i * 4), 0);
+
+ /* Program P-state weights to account for frequency power adjustment */
+ for (i = 0; i < 16; i++) {
+ u32 pxvidfreq = I915_READ(PXVFREQ_BASE + (i * 4));
+ unsigned long freq = intel_pxfreq(pxvidfreq);
+ unsigned long vid = (pxvidfreq & PXVFREQ_PX_MASK) >>
+ PXVFREQ_PX_SHIFT;
+ unsigned long val;
+
+ val = vid * vid;
+ val *= (freq / 1000);
+ val *= 255;
+ val /= (127*127*900);
+ if (val > 0xff)
+ DRM_ERROR("bad pxval: %ld\n", val);
+ pxw[i] = val;
+ }
+ /* Render standby states get 0 weight */
+ pxw[14] = 0;
+ pxw[15] = 0;
+
+ for (i = 0; i < 4; i++) {
+ u32 val = (pxw[i*4] << 24) | (pxw[(i*4)+1] << 16) |
+ (pxw[(i*4)+2] << 8) | (pxw[(i*4)+3]);
+ I915_WRITE(PXW + (i * 4), val);
+ }
+
+ /* Adjust magic regs to magic values (more experimental results) */
+ I915_WRITE(OGW0, 0);
+ I915_WRITE(OGW1, 0);
+ I915_WRITE(EG0, 0x00007f00);
+ I915_WRITE(EG1, 0x0000000e);
+ I915_WRITE(EG2, 0x000e0000);
+ I915_WRITE(EG3, 0x68000300);
+ I915_WRITE(EG4, 0x42000000);
+ I915_WRITE(EG5, 0x00140031);
+ I915_WRITE(EG6, 0);
+ I915_WRITE(EG7, 0);
+
+ for (i = 0; i < 8; i++)
+ I915_WRITE(PXWL + (i * 4), 0);
+
+ /* Enable PMON + select events */
+ I915_WRITE(ECR, 0x80000019);
+
+ lcfuse = I915_READ(LCFUSE02);
+
+ dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK);
+}
+
+static void ironlake_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
+
+ /* Required for FBC */
+ dspclk_gate |= DPFCUNIT_CLOCK_GATE_DISABLE |
+ DPFCRUNIT_CLOCK_GATE_DISABLE |
+ DPFDUNIT_CLOCK_GATE_DISABLE;
+ /* Required for CxSR */
+ dspclk_gate |= DPARBUNIT_CLOCK_GATE_DISABLE;
+
+ I915_WRITE(PCH_3DCGDIS0,
+ MARIUNIT_CLOCK_GATE_DISABLE |
+ SVSMUNIT_CLOCK_GATE_DISABLE);
+ I915_WRITE(PCH_3DCGDIS1,
+ VFMUNIT_CLOCK_GATE_DISABLE);
+
+ I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
+
+ /*
+ * According to the spec the following bits should be set in
+ * order to enable memory self-refresh
+ * The bit 22/21 of 0x42004
+ * The bit 5 of 0x42020
+ * The bit 15 of 0x45000
+ */
+ I915_WRITE(ILK_DISPLAY_CHICKEN2,
+ (I915_READ(ILK_DISPLAY_CHICKEN2) |
+ ILK_DPARB_GATE | ILK_VSDPFD_FULL));
+ I915_WRITE(ILK_DSPCLK_GATE,
+ (I915_READ(ILK_DSPCLK_GATE) |
+ ILK_DPARB_CLK_GATE));
+ I915_WRITE(DISP_ARB_CTL,
+ (I915_READ(DISP_ARB_CTL) |
+ DISP_FBC_WM_DIS));
+ I915_WRITE(WM3_LP_ILK, 0);
+ I915_WRITE(WM2_LP_ILK, 0);
+ I915_WRITE(WM1_LP_ILK, 0);
+
+ /*
+ * Based on the document from hardware guys the following bits
+ * should be set unconditionally in order to enable FBC.
+ * The bit 22 of 0x42000
+ * The bit 22 of 0x42004
+ * The bit 7,8,9 of 0x42020.
+ */
+ if (IS_IRONLAKE_M(dev)) {
+ I915_WRITE(ILK_DISPLAY_CHICKEN1,
+ I915_READ(ILK_DISPLAY_CHICKEN1) |
+ ILK_FBCQ_DIS);
+ I915_WRITE(ILK_DISPLAY_CHICKEN2,
+ I915_READ(ILK_DISPLAY_CHICKEN2) |
+ ILK_DPARB_GATE);
+ I915_WRITE(ILK_DSPCLK_GATE,
+ I915_READ(ILK_DSPCLK_GATE) |
+ ILK_DPFC_DIS1 |
+ ILK_DPFC_DIS2 |
+ ILK_CLK_FBC);
+ }
+
+ I915_WRITE(ILK_DISPLAY_CHICKEN2,
+ I915_READ(ILK_DISPLAY_CHICKEN2) |
+ ILK_ELPIN_409_SELECT);
+ I915_WRITE(_3D_CHICKEN2,
+ _3D_CHICKEN2_WM_READ_PIPELINED << 16 |
+ _3D_CHICKEN2_WM_READ_PIPELINED);
+}
+
+static void gen6_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int pipe;
+ uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
+
+ I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
+
+ I915_WRITE(ILK_DISPLAY_CHICKEN2,
+ I915_READ(ILK_DISPLAY_CHICKEN2) |
+ ILK_ELPIN_409_SELECT);
+
+ I915_WRITE(WM3_LP_ILK, 0);
+ I915_WRITE(WM2_LP_ILK, 0);
+ I915_WRITE(WM1_LP_ILK, 0);
+
+ I915_WRITE(CACHE_MODE_0,
+ _MASKED_BIT_DISABLE(CM0_STC_EVICT_DISABLE_LRA_SNB));
+
+ I915_WRITE(GEN6_UCGCTL1,
+ I915_READ(GEN6_UCGCTL1) |
+ GEN6_BLBUNIT_CLOCK_GATE_DISABLE |
+ GEN6_CSUNIT_CLOCK_GATE_DISABLE);
+
+ /* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock
+ * gating disable must be set. Failure to set it results in
+ * flickering pixels due to Z write ordering failures after
+ * some amount of runtime in the Mesa "fire" demo, and Unigine
+ * Sanctuary and Tropics, and apparently anything else with
+ * alpha test or pixel discard.
+ *
+ * According to the spec, bit 11 (RCCUNIT) must also be set,
+ * but we didn't debug actual testcases to find it out.
+ */
+ I915_WRITE(GEN6_UCGCTL2,
+ GEN6_RCPBUNIT_CLOCK_GATE_DISABLE |
+ GEN6_RCCUNIT_CLOCK_GATE_DISABLE);
+
+ /* Bspec says we need to always set all mask bits. */
+ I915_WRITE(_3D_CHICKEN, (0xFFFF << 16) |
+ _3D_CHICKEN_SF_DISABLE_FASTCLIP_CULL);
+
+ /*
+ * According to the spec the following bits should be
+ * set in order to enable memory self-refresh and fbc:
+ * The bit21 and bit22 of 0x42000
+ * The bit21 and bit22 of 0x42004
+ * The bit5 and bit7 of 0x42020
+ * The bit14 of 0x70180
+ * The bit14 of 0x71180
+ */
+ I915_WRITE(ILK_DISPLAY_CHICKEN1,
+ I915_READ(ILK_DISPLAY_CHICKEN1) |
+ ILK_FBCQ_DIS | ILK_PABSTRETCH_DIS);
+ I915_WRITE(ILK_DISPLAY_CHICKEN2,
+ I915_READ(ILK_DISPLAY_CHICKEN2) |
+ ILK_DPARB_GATE | ILK_VSDPFD_FULL);
+ I915_WRITE(ILK_DSPCLK_GATE,
+ I915_READ(ILK_DSPCLK_GATE) |
+ ILK_DPARB_CLK_GATE |
+ ILK_DPFD_CLK_GATE);
+
+ for_each_pipe(pipe) {
+ I915_WRITE(DSPCNTR(pipe),
+ I915_READ(DSPCNTR(pipe)) |
+ DISPPLANE_TRICKLE_FEED_DISABLE);
+ intel_flush_display_plane(dev_priv, pipe);
+ }
+}
+
+static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv)
+{
+ uint32_t reg = I915_READ(GEN7_FF_THREAD_MODE);
+
+ reg &= ~GEN7_FF_SCHED_MASK;
+ reg |= GEN7_FF_TS_SCHED_HW;
+ reg |= GEN7_FF_VS_SCHED_HW;
+ reg |= GEN7_FF_DS_SCHED_HW;
+
+ I915_WRITE(GEN7_FF_THREAD_MODE, reg);
+}
+
+static void ivybridge_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int pipe;
+ uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
+
+ I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
+
+ I915_WRITE(WM3_LP_ILK, 0);
+ I915_WRITE(WM2_LP_ILK, 0);
+ I915_WRITE(WM1_LP_ILK, 0);
+
+ /* According to the spec, bit 13 (RCZUNIT) must be set on IVB.
+ * This implements the WaDisableRCZUnitClockGating workaround.
+ */
+ I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE);
+
+ I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE);
+
+ I915_WRITE(IVB_CHICKEN3,
+ CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE |
+ CHICKEN3_DGMG_DONE_FIX_DISABLE);
+
+ /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */
+ I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1,
+ GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC);
+
+ /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */
+ I915_WRITE(GEN7_L3CNTLREG1,
+ GEN7_WA_FOR_GEN7_L3_CONTROL);
+ I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER,
+ GEN7_WA_L3_CHICKEN_MODE);
+
+ /* This is required by WaCatErrorRejectionIssue */
+ I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
+ I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
+ GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
+
+ for_each_pipe(pipe) {
+ I915_WRITE(DSPCNTR(pipe),
+ I915_READ(DSPCNTR(pipe)) |
+ DISPPLANE_TRICKLE_FEED_DISABLE);
+ intel_flush_display_plane(dev_priv, pipe);
+ }
+
+ gen7_setup_fixed_func_scheduler(dev_priv);
+
+ /* WaDisable4x2SubspanOptimization */
+ I915_WRITE(CACHE_MODE_1,
+ _MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE));
+}
+
+static void valleyview_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int pipe;
+ uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
+
+ I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
+
+ I915_WRITE(WM3_LP_ILK, 0);
+ I915_WRITE(WM2_LP_ILK, 0);
+ I915_WRITE(WM1_LP_ILK, 0);
+
+ /* According to the spec, bit 13 (RCZUNIT) must be set on IVB.
+ * This implements the WaDisableRCZUnitClockGating workaround.
+ */
+ I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE);
+
+ I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE);
+
+ I915_WRITE(IVB_CHICKEN3,
+ CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE |
+ CHICKEN3_DGMG_DONE_FIX_DISABLE);
+
+ /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */
+ I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1,
+ GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC);
+
+ /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */
+ I915_WRITE(GEN7_L3CNTLREG1, GEN7_WA_FOR_GEN7_L3_CONTROL);
+ I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, GEN7_WA_L3_CHICKEN_MODE);
+
+ /* This is required by WaCatErrorRejectionIssue */
+ I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
+ I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
+ GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
+
+ for_each_pipe(pipe) {
+ I915_WRITE(DSPCNTR(pipe),
+ I915_READ(DSPCNTR(pipe)) |
+ DISPPLANE_TRICKLE_FEED_DISABLE);
+ intel_flush_display_plane(dev_priv, pipe);
+ }
+
+ I915_WRITE(CACHE_MODE_1,
+ _MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE));
+}
+
+static void g4x_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t dspclk_gate;
+
+ I915_WRITE(RENCLK_GATE_D1, 0);
+ I915_WRITE(RENCLK_GATE_D2, VF_UNIT_CLOCK_GATE_DISABLE |
+ GS_UNIT_CLOCK_GATE_DISABLE |
+ CL_UNIT_CLOCK_GATE_DISABLE);
+ I915_WRITE(RAMCLK_GATE_D, 0);
+ dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE |
+ OVRUNIT_CLOCK_GATE_DISABLE |
+ OVCUNIT_CLOCK_GATE_DISABLE;
+ if (IS_GM45(dev))
+ dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE;
+ I915_WRITE(DSPCLK_GATE_D, dspclk_gate);
+}
+
+static void crestline_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
+ I915_WRITE(RENCLK_GATE_D2, 0);
+ I915_WRITE(DSPCLK_GATE_D, 0);
+ I915_WRITE(RAMCLK_GATE_D, 0);
+ I915_WRITE16(DEUC, 0);
+}
+
+static void broadwater_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE |
+ I965_RCC_CLOCK_GATE_DISABLE |
+ I965_RCPB_CLOCK_GATE_DISABLE |
+ I965_ISC_CLOCK_GATE_DISABLE |
+ I965_FBC_CLOCK_GATE_DISABLE);
+ I915_WRITE(RENCLK_GATE_D2, 0);
+}
+
+static void gen3_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 dstate = I915_READ(D_STATE);
+
+ dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING |
+ DSTATE_DOT_CLOCK_GATING;
+ I915_WRITE(D_STATE, dstate);
+
+ if (IS_PINEVIEW(dev))
+ I915_WRITE(ECOSKPD, _MASKED_BIT_ENABLE(ECO_GATING_CX_ONLY));
+}
+
+static void i85x_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ I915_WRITE(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE);
+}
+
+static void i830_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
+}
+
+static void ibx_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ /*
+ * On Ibex Peak and Cougar Point, we need to disable clock
+ * gating for the panel power sequencer or it will fail to
+ * start up when no ports are active.
+ */
+ I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
+}
+
+static void cpt_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int pipe;
+
+ /*
+ * On Ibex Peak and Cougar Point, we need to disable clock
+ * gating for the panel power sequencer or it will fail to
+ * start up when no ports are active.
+ */
+ I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
+ I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) |
+ DPLS_EDP_PPS_FIX_DIS);
+ /* Without this, mode sets may fail silently on FDI */
+ for_each_pipe(pipe)
+ I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_AUTOTRAIN_GEN_STALL_DIS);
+}
+
+void intel_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ dev_priv->display.init_clock_gating(dev);
+
+ if (dev_priv->display.init_pch_clock_gating)
+ dev_priv->display.init_pch_clock_gating(dev);
+}
+
+static void gen6_sanitize_pm(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 limits, delay, old;
+
+ gen6_gt_force_wake_get(dev_priv);
+
+ old = limits = I915_READ(GEN6_RP_INTERRUPT_LIMITS);
+ /* Make sure we continue to get interrupts
+ * until we hit the minimum or maximum frequencies.
+ */
+ limits &= ~(0x3f << 16 | 0x3f << 24);
+ delay = dev_priv->cur_delay;
+ if (delay < dev_priv->max_delay)
+ limits |= (dev_priv->max_delay & 0x3f) << 24;
+ if (delay > dev_priv->min_delay)
+ limits |= (dev_priv->min_delay & 0x3f) << 16;
+
+ if (old != limits) {
+ DRM_ERROR("Power management discrepancy: GEN6_RP_INTERRUPT_LIMITS expected %08x, was %08x\n",
+ limits, old);
+ I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits);
+ }
+
+ gen6_gt_force_wake_put(dev_priv);
+}
+
+void intel_sanitize_pm(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->display.sanitize_pm)
+ dev_priv->display.sanitize_pm(dev);
+}
+
+/* Starting with Haswell, we have different power wells for
+ * different parts of the GPU. This attempts to enable them all.
+ */
+void intel_init_power_wells(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ unsigned long power_wells[] = {
+ HSW_PWR_WELL_CTL1,
+ HSW_PWR_WELL_CTL2,
+ HSW_PWR_WELL_CTL4
+ };
+ int i;
+
+ if (!IS_HASWELL(dev))
+ return;
+
+ mutex_lock(&dev->struct_mutex);
+
+ for (i = 0; i < ARRAY_SIZE(power_wells); i++) {
+ int well = I915_READ(power_wells[i]);
+
+ if ((well & HSW_PWR_WELL_STATE) == 0) {
+ I915_WRITE(power_wells[i], well & HSW_PWR_WELL_ENABLE);
+ if (wait_for(I915_READ(power_wells[i] & HSW_PWR_WELL_STATE), 20))
+ DRM_ERROR("Error enabling power well %lx\n", power_wells[i]);
+ }
+ }
+
+ mutex_unlock(&dev->struct_mutex);
+}
+
+/* Set up chip specific power management-related functions */
+void intel_init_pm(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (I915_HAS_FBC(dev)) {
+ if (HAS_PCH_SPLIT(dev)) {
+ dev_priv->display.fbc_enabled = ironlake_fbc_enabled;
+ dev_priv->display.enable_fbc = ironlake_enable_fbc;
+ dev_priv->display.disable_fbc = ironlake_disable_fbc;
+ } else if (IS_GM45(dev)) {
+ dev_priv->display.fbc_enabled = g4x_fbc_enabled;
+ dev_priv->display.enable_fbc = g4x_enable_fbc;
+ dev_priv->display.disable_fbc = g4x_disable_fbc;
+ } else if (IS_CRESTLINE(dev)) {
+ dev_priv->display.fbc_enabled = i8xx_fbc_enabled;
+ dev_priv->display.enable_fbc = i8xx_enable_fbc;
+ dev_priv->display.disable_fbc = i8xx_disable_fbc;
+ }
+ /* 855GM needs testing */
+ }
+
+ /* For cxsr */
+ if (IS_PINEVIEW(dev))
+ i915_pineview_get_mem_freq(dev);
+ else if (IS_GEN5(dev))
+ i915_ironlake_get_mem_freq(dev);
+
+ /* For FIFO watermark updates */
+ if (HAS_PCH_SPLIT(dev)) {
+ dev_priv->display.force_wake_get = __gen6_gt_force_wake_get;
+ dev_priv->display.force_wake_put = __gen6_gt_force_wake_put;
+
+ /* IVB configs may use multi-threaded forcewake */
+ if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
+ u32 ecobus;
+
+ /* A small trick here - if the bios hasn't configured MT forcewake,
+ * and if the device is in RC6, then force_wake_mt_get will not wake
+ * the device and the ECOBUS read will return zero. Which will be
+ * (correctly) interpreted by the test below as MT forcewake being
+ * disabled.
+ */
+ mutex_lock(&dev->struct_mutex);
+ __gen6_gt_force_wake_mt_get(dev_priv);
+ ecobus = I915_READ_NOTRACE(ECOBUS);
+ __gen6_gt_force_wake_mt_put(dev_priv);
+ mutex_unlock(&dev->struct_mutex);
+
+ if (ecobus & FORCEWAKE_MT_ENABLE) {
+ DRM_DEBUG_KMS("Using MT version of forcewake\n");
+ dev_priv->display.force_wake_get =
+ __gen6_gt_force_wake_mt_get;
+ dev_priv->display.force_wake_put =
+ __gen6_gt_force_wake_mt_put;
+ }
+ }
+
+ if (HAS_PCH_IBX(dev))
+ dev_priv->display.init_pch_clock_gating = ibx_init_clock_gating;
+ else if (HAS_PCH_CPT(dev))
+ dev_priv->display.init_pch_clock_gating = cpt_init_clock_gating;
+
+ if (IS_GEN5(dev)) {
+ if (I915_READ(MLTR_ILK) & ILK_SRLT_MASK)
+ dev_priv->display.update_wm = ironlake_update_wm;
+ else {
+ DRM_DEBUG_KMS("Failed to get proper latency. "
+ "Disable CxSR\n");
+ dev_priv->display.update_wm = NULL;
+ }
+ dev_priv->display.init_clock_gating = ironlake_init_clock_gating;
+ } else if (IS_GEN6(dev)) {
+ if (SNB_READ_WM0_LATENCY()) {
+ dev_priv->display.update_wm = sandybridge_update_wm;
+ dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm;
+ } else {
+ DRM_DEBUG_KMS("Failed to read display plane latency. "
+ "Disable CxSR\n");
+ dev_priv->display.update_wm = NULL;
+ }
+ dev_priv->display.init_clock_gating = gen6_init_clock_gating;
+ dev_priv->display.sanitize_pm = gen6_sanitize_pm;
+ } else if (IS_IVYBRIDGE(dev)) {
+ /* FIXME: detect B0+ stepping and use auto training */
+ if (SNB_READ_WM0_LATENCY()) {
+ dev_priv->display.update_wm = sandybridge_update_wm;
+ dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm;
+ } else {
+ DRM_DEBUG_KMS("Failed to read display plane latency. "
+ "Disable CxSR\n");
+ dev_priv->display.update_wm = NULL;
+ }
+ dev_priv->display.init_clock_gating = ivybridge_init_clock_gating;
+ dev_priv->display.sanitize_pm = gen6_sanitize_pm;
+ } else if (IS_HASWELL(dev)) {
+ if (SNB_READ_WM0_LATENCY()) {
+ dev_priv->display.update_wm = sandybridge_update_wm;
+ dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm;
+ dev_priv->display.update_linetime_wm = haswell_update_linetime_wm;
+ } else {
+ DRM_DEBUG_KMS("Failed to read display plane latency. "
+ "Disable CxSR\n");
+ dev_priv->display.update_wm = NULL;
+ }
+ dev_priv->display.init_clock_gating = ivybridge_init_clock_gating;
+ dev_priv->display.sanitize_pm = gen6_sanitize_pm;
+ } else
+ dev_priv->display.update_wm = NULL;
+ } else if (IS_VALLEYVIEW(dev)) {
+ dev_priv->display.update_wm = valleyview_update_wm;
+ dev_priv->display.init_clock_gating =
+ valleyview_init_clock_gating;
+ dev_priv->display.force_wake_get = vlv_force_wake_get;
+ dev_priv->display.force_wake_put = vlv_force_wake_put;
+ } else if (IS_PINEVIEW(dev)) {
+ if (!intel_get_cxsr_latency(IS_PINEVIEW_G(dev),
+ dev_priv->is_ddr3,
+ dev_priv->fsb_freq,
+ dev_priv->mem_freq)) {
+ DRM_INFO("failed to find known CxSR latency "
+ "(found ddr%s fsb freq %d, mem freq %d), "
+ "disabling CxSR\n",
+ (dev_priv->is_ddr3 == 1) ? "3" : "2",
+ dev_priv->fsb_freq, dev_priv->mem_freq);
+ /* Disable CxSR and never update its watermark again */
+ pineview_disable_cxsr(dev);
+ dev_priv->display.update_wm = NULL;
+ } else
+ dev_priv->display.update_wm = pineview_update_wm;
+ dev_priv->display.init_clock_gating = gen3_init_clock_gating;
+ } else if (IS_G4X(dev)) {
+ dev_priv->display.update_wm = g4x_update_wm;
+ dev_priv->display.init_clock_gating = g4x_init_clock_gating;
+ } else if (IS_GEN4(dev)) {
+ dev_priv->display.update_wm = i965_update_wm;
+ if (IS_CRESTLINE(dev))
+ dev_priv->display.init_clock_gating = crestline_init_clock_gating;
+ else if (IS_BROADWATER(dev))
+ dev_priv->display.init_clock_gating = broadwater_init_clock_gating;
+ } else if (IS_GEN3(dev)) {
+ dev_priv->display.update_wm = i9xx_update_wm;
+ dev_priv->display.get_fifo_size = i9xx_get_fifo_size;
+ dev_priv->display.init_clock_gating = gen3_init_clock_gating;
+ } else if (IS_I865G(dev)) {
+ dev_priv->display.update_wm = i830_update_wm;
+ dev_priv->display.init_clock_gating = i85x_init_clock_gating;
+ dev_priv->display.get_fifo_size = i830_get_fifo_size;
+ } else if (IS_I85X(dev)) {
+ dev_priv->display.update_wm = i9xx_update_wm;
+ dev_priv->display.get_fifo_size = i85x_get_fifo_size;
+ dev_priv->display.init_clock_gating = i85x_init_clock_gating;
+ } else {
+ dev_priv->display.update_wm = i830_update_wm;
+ dev_priv->display.init_clock_gating = i830_init_clock_gating;
+ if (IS_845G(dev))
+ dev_priv->display.get_fifo_size = i845_get_fifo_size;
+ else
+ dev_priv->display.get_fifo_size = i830_get_fifo_size;
+ }
+
+ /* We attempt to init the necessary power wells early in the initialization
+ * time, so the subsystems that expect power to be enabled can work.
+ */
+ intel_init_power_wells(dev);
+}
+
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 62892a826ede..b59b6d5b7583 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -53,9 +53,35 @@ static inline int ring_space(struct intel_ring_buffer *ring)
}
static int
-render_ring_flush(struct intel_ring_buffer *ring,
- u32 invalidate_domains,
- u32 flush_domains)
+gen2_render_ring_flush(struct intel_ring_buffer *ring,
+ u32 invalidate_domains,
+ u32 flush_domains)
+{
+ u32 cmd;
+ int ret;
+
+ cmd = MI_FLUSH;
+ if (((invalidate_domains|flush_domains) & I915_GEM_DOMAIN_RENDER) == 0)
+ cmd |= MI_NO_WRITE_FLUSH;
+
+ if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER)
+ cmd |= MI_READ_FLUSH;
+
+ ret = intel_ring_begin(ring, 2);
+ if (ret)
+ return ret;
+
+ intel_ring_emit(ring, cmd);
+ intel_ring_emit(ring, MI_NOOP);
+ intel_ring_advance(ring);
+
+ return 0;
+}
+
+static int
+gen4_render_ring_flush(struct intel_ring_buffer *ring,
+ u32 invalidate_domains,
+ u32 flush_domains)
{
struct drm_device *dev = ring->dev;
u32 cmd;
@@ -90,17 +116,8 @@ render_ring_flush(struct intel_ring_buffer *ring,
*/
cmd = MI_FLUSH | MI_NO_WRITE_FLUSH;
- if ((invalidate_domains|flush_domains) &
- I915_GEM_DOMAIN_RENDER)
+ if ((invalidate_domains|flush_domains) & I915_GEM_DOMAIN_RENDER)
cmd &= ~MI_NO_WRITE_FLUSH;
- if (INTEL_INFO(dev)->gen < 4) {
- /*
- * On the 965, the sampler cache always gets flushed
- * and this bit is reserved.
- */
- if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER)
- cmd |= MI_READ_FLUSH;
- }
if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION)
cmd |= MI_EXE_FLUSH;
@@ -290,9 +307,9 @@ static int init_ring_common(struct intel_ring_buffer *ring)
| RING_VALID);
/* If the head is still not zero, the ring is dead */
- if ((I915_READ_CTL(ring) & RING_VALID) == 0 ||
- I915_READ_START(ring) != obj->gtt_offset ||
- (I915_READ_HEAD(ring) & HEAD_ADDR) != 0) {
+ if (wait_for((I915_READ_CTL(ring) & RING_VALID) != 0 &&
+ I915_READ_START(ring) == obj->gtt_offset &&
+ (I915_READ_HEAD(ring) & HEAD_ADDR) == 0, 50)) {
DRM_ERROR("%s initialization failed "
"ctl %08x head %08x tail %08x start %08x\n",
ring->name,
@@ -384,12 +401,11 @@ static int init_render_ring(struct intel_ring_buffer *ring)
int ret = init_ring_common(ring);
if (INTEL_INFO(dev)->gen > 3) {
- int mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH;
- I915_WRITE(MI_MODE, mode);
+ I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(VS_TIMER_DISPATCH));
if (IS_GEN7(dev))
I915_WRITE(GFX_MODE_GEN7,
- GFX_MODE_DISABLE(GFX_TLB_INVALIDATE_ALWAYS) |
- GFX_MODE_ENABLE(GFX_REPLAY_MODE));
+ _MASKED_BIT_DISABLE(GFX_TLB_INVALIDATE_ALWAYS) |
+ _MASKED_BIT_ENABLE(GFX_REPLAY_MODE));
}
if (INTEL_INFO(dev)->gen >= 5) {
@@ -398,7 +414,6 @@ static int init_render_ring(struct intel_ring_buffer *ring)
return ret;
}
-
if (IS_GEN6(dev)) {
/* From the Sandybridge PRM, volume 1 part 3, page 24:
* "If this bit is set, STCunit will have LRA as replacement
@@ -406,13 +421,11 @@ static int init_render_ring(struct intel_ring_buffer *ring)
* policy is not supported."
*/
I915_WRITE(CACHE_MODE_0,
- CM0_STC_EVICT_DISABLE_LRA_SNB << CM0_MASK_SHIFT);
+ _MASKED_BIT_DISABLE(CM0_STC_EVICT_DISABLE_LRA_SNB));
}
- if (INTEL_INFO(dev)->gen >= 6) {
- I915_WRITE(INSTPM,
- INSTPM_FORCE_ORDERING << 16 | INSTPM_FORCE_ORDERING);
- }
+ if (INTEL_INFO(dev)->gen >= 6)
+ I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING));
return ret;
}
@@ -483,21 +496,30 @@ gen6_add_request(struct intel_ring_buffer *ring,
* @seqno - seqno which the waiter will block on
*/
static int
-intel_ring_sync(struct intel_ring_buffer *waiter,
- struct intel_ring_buffer *signaller,
- int ring,
- u32 seqno)
+gen6_ring_sync(struct intel_ring_buffer *waiter,
+ struct intel_ring_buffer *signaller,
+ u32 seqno)
{
int ret;
u32 dw1 = MI_SEMAPHORE_MBOX |
MI_SEMAPHORE_COMPARE |
MI_SEMAPHORE_REGISTER;
+ /* Throughout all of the GEM code, seqno passed implies our current
+ * seqno is >= the last seqno executed. However for hardware the
+ * comparison is strictly greater than.
+ */
+ seqno -= 1;
+
+ WARN_ON(signaller->semaphore_register[waiter->id] ==
+ MI_SEMAPHORE_SYNC_INVALID);
+
ret = intel_ring_begin(waiter, 4);
if (ret)
return ret;
- intel_ring_emit(waiter, dw1 | signaller->semaphore_register[ring]);
+ intel_ring_emit(waiter,
+ dw1 | signaller->semaphore_register[waiter->id]);
intel_ring_emit(waiter, seqno);
intel_ring_emit(waiter, 0);
intel_ring_emit(waiter, MI_NOOP);
@@ -506,47 +528,6 @@ intel_ring_sync(struct intel_ring_buffer *waiter,
return 0;
}
-/* VCS->RCS (RVSYNC) or BCS->RCS (RBSYNC) */
-int
-render_ring_sync_to(struct intel_ring_buffer *waiter,
- struct intel_ring_buffer *signaller,
- u32 seqno)
-{
- WARN_ON(signaller->semaphore_register[RCS] == MI_SEMAPHORE_SYNC_INVALID);
- return intel_ring_sync(waiter,
- signaller,
- RCS,
- seqno);
-}
-
-/* RCS->VCS (VRSYNC) or BCS->VCS (VBSYNC) */
-int
-gen6_bsd_ring_sync_to(struct intel_ring_buffer *waiter,
- struct intel_ring_buffer *signaller,
- u32 seqno)
-{
- WARN_ON(signaller->semaphore_register[VCS] == MI_SEMAPHORE_SYNC_INVALID);
- return intel_ring_sync(waiter,
- signaller,
- VCS,
- seqno);
-}
-
-/* RCS->BCS (BRSYNC) or VCS->BCS (BVSYNC) */
-int
-gen6_blt_ring_sync_to(struct intel_ring_buffer *waiter,
- struct intel_ring_buffer *signaller,
- u32 seqno)
-{
- WARN_ON(signaller->semaphore_register[BCS] == MI_SEMAPHORE_SYNC_INVALID);
- return intel_ring_sync(waiter,
- signaller,
- BCS,
- seqno);
-}
-
-
-
#define PIPE_CONTROL_FLUSH(ring__, addr__) \
do { \
intel_ring_emit(ring__, GFX_OP_PIPE_CONTROL(4) | PIPE_CONTROL_QW_WRITE | \
@@ -608,27 +589,6 @@ pc_render_add_request(struct intel_ring_buffer *ring,
return 0;
}
-static int
-render_ring_add_request(struct intel_ring_buffer *ring,
- u32 *result)
-{
- u32 seqno = i915_gem_next_request_seqno(ring);
- int ret;
-
- ret = intel_ring_begin(ring, 4);
- if (ret)
- return ret;
-
- intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
- intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
- intel_ring_emit(ring, seqno);
- intel_ring_emit(ring, MI_USER_INTERRUPT);
- intel_ring_advance(ring);
-
- *result = seqno;
- return 0;
-}
-
static u32
gen6_ring_get_seqno(struct intel_ring_buffer *ring)
{
@@ -655,76 +615,115 @@ pc_render_get_seqno(struct intel_ring_buffer *ring)
return pc->cpu_page[0];
}
-static void
-ironlake_enable_irq(drm_i915_private_t *dev_priv, u32 mask)
+static bool
+gen5_ring_get_irq(struct intel_ring_buffer *ring)
{
- dev_priv->gt_irq_mask &= ~mask;
- I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
- POSTING_READ(GTIMR);
+ struct drm_device *dev = ring->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ unsigned long flags;
+
+ if (!dev->irq_enabled)
+ return false;
+
+ spin_lock_irqsave(&dev_priv->irq_lock, flags);
+ if (ring->irq_refcount++ == 0) {
+ dev_priv->gt_irq_mask &= ~ring->irq_enable_mask;
+ I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
+ POSTING_READ(GTIMR);
+ }
+ spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+
+ return true;
}
static void
-ironlake_disable_irq(drm_i915_private_t *dev_priv, u32 mask)
+gen5_ring_put_irq(struct intel_ring_buffer *ring)
{
- dev_priv->gt_irq_mask |= mask;
- I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
- POSTING_READ(GTIMR);
+ struct drm_device *dev = ring->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev_priv->irq_lock, flags);
+ if (--ring->irq_refcount == 0) {
+ dev_priv->gt_irq_mask |= ring->irq_enable_mask;
+ I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
+ POSTING_READ(GTIMR);
+ }
+ spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
}
-static void
-i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask)
+static bool
+i9xx_ring_get_irq(struct intel_ring_buffer *ring)
{
- dev_priv->irq_mask &= ~mask;
- I915_WRITE(IMR, dev_priv->irq_mask);
- POSTING_READ(IMR);
+ struct drm_device *dev = ring->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ unsigned long flags;
+
+ if (!dev->irq_enabled)
+ return false;
+
+ spin_lock_irqsave(&dev_priv->irq_lock, flags);
+ if (ring->irq_refcount++ == 0) {
+ dev_priv->irq_mask &= ~ring->irq_enable_mask;
+ I915_WRITE(IMR, dev_priv->irq_mask);
+ POSTING_READ(IMR);
+ }
+ spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+
+ return true;
}
static void
-i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask)
+i9xx_ring_put_irq(struct intel_ring_buffer *ring)
{
- dev_priv->irq_mask |= mask;
- I915_WRITE(IMR, dev_priv->irq_mask);
- POSTING_READ(IMR);
+ struct drm_device *dev = ring->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev_priv->irq_lock, flags);
+ if (--ring->irq_refcount == 0) {
+ dev_priv->irq_mask |= ring->irq_enable_mask;
+ I915_WRITE(IMR, dev_priv->irq_mask);
+ POSTING_READ(IMR);
+ }
+ spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
}
static bool
-render_ring_get_irq(struct intel_ring_buffer *ring)
+i8xx_ring_get_irq(struct intel_ring_buffer *ring)
{
struct drm_device *dev = ring->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
+ unsigned long flags;
if (!dev->irq_enabled)
return false;
- spin_lock(&ring->irq_lock);
+ spin_lock_irqsave(&dev_priv->irq_lock, flags);
if (ring->irq_refcount++ == 0) {
- if (HAS_PCH_SPLIT(dev))
- ironlake_enable_irq(dev_priv,
- GT_PIPE_NOTIFY | GT_USER_INTERRUPT);
- else
- i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
+ dev_priv->irq_mask &= ~ring->irq_enable_mask;
+ I915_WRITE16(IMR, dev_priv->irq_mask);
+ POSTING_READ16(IMR);
}
- spin_unlock(&ring->irq_lock);
+ spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
return true;
}
static void
-render_ring_put_irq(struct intel_ring_buffer *ring)
+i8xx_ring_put_irq(struct intel_ring_buffer *ring)
{
struct drm_device *dev = ring->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
+ unsigned long flags;
- spin_lock(&ring->irq_lock);
+ spin_lock_irqsave(&dev_priv->irq_lock, flags);
if (--ring->irq_refcount == 0) {
- if (HAS_PCH_SPLIT(dev))
- ironlake_disable_irq(dev_priv,
- GT_USER_INTERRUPT |
- GT_PIPE_NOTIFY);
- else
- i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
+ dev_priv->irq_mask |= ring->irq_enable_mask;
+ I915_WRITE16(IMR, dev_priv->irq_mask);
+ POSTING_READ16(IMR);
}
- spin_unlock(&ring->irq_lock);
+ spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
}
void intel_ring_setup_status_page(struct intel_ring_buffer *ring)
@@ -776,7 +775,7 @@ bsd_ring_flush(struct intel_ring_buffer *ring,
}
static int
-ring_add_request(struct intel_ring_buffer *ring,
+i9xx_add_request(struct intel_ring_buffer *ring,
u32 *result)
{
u32 seqno;
@@ -799,10 +798,11 @@ ring_add_request(struct intel_ring_buffer *ring,
}
static bool
-gen6_ring_get_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
+gen6_ring_get_irq(struct intel_ring_buffer *ring)
{
struct drm_device *dev = ring->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
+ unsigned long flags;
if (!dev->irq_enabled)
return false;
@@ -812,120 +812,87 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
* blt/bsd rings on ivb. */
gen6_gt_force_wake_get(dev_priv);
- spin_lock(&ring->irq_lock);
+ spin_lock_irqsave(&dev_priv->irq_lock, flags);
if (ring->irq_refcount++ == 0) {
- ring->irq_mask &= ~rflag;
- I915_WRITE_IMR(ring, ring->irq_mask);
- ironlake_enable_irq(dev_priv, gflag);
+ I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
+ dev_priv->gt_irq_mask &= ~ring->irq_enable_mask;
+ I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
+ POSTING_READ(GTIMR);
}
- spin_unlock(&ring->irq_lock);
+ spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
return true;
}
static void
-gen6_ring_put_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
+gen6_ring_put_irq(struct intel_ring_buffer *ring)
{
struct drm_device *dev = ring->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
+ unsigned long flags;
- spin_lock(&ring->irq_lock);
+ spin_lock_irqsave(&dev_priv->irq_lock, flags);
if (--ring->irq_refcount == 0) {
- ring->irq_mask |= rflag;
- I915_WRITE_IMR(ring, ring->irq_mask);
- ironlake_disable_irq(dev_priv, gflag);
+ I915_WRITE_IMR(ring, ~0);
+ dev_priv->gt_irq_mask |= ring->irq_enable_mask;
+ I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
+ POSTING_READ(GTIMR);
}
- spin_unlock(&ring->irq_lock);
+ spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
gen6_gt_force_wake_put(dev_priv);
}
-static bool
-bsd_ring_get_irq(struct intel_ring_buffer *ring)
+static int
+i965_dispatch_execbuffer(struct intel_ring_buffer *ring, u32 offset, u32 length)
{
- struct drm_device *dev = ring->dev;
- drm_i915_private_t *dev_priv = dev->dev_private;
-
- if (!dev->irq_enabled)
- return false;
+ int ret;
- spin_lock(&ring->irq_lock);
- if (ring->irq_refcount++ == 0) {
- if (IS_G4X(dev))
- i915_enable_irq(dev_priv, I915_BSD_USER_INTERRUPT);
- else
- ironlake_enable_irq(dev_priv, GT_BSD_USER_INTERRUPT);
- }
- spin_unlock(&ring->irq_lock);
+ ret = intel_ring_begin(ring, 2);
+ if (ret)
+ return ret;
- return true;
-}
-static void
-bsd_ring_put_irq(struct intel_ring_buffer *ring)
-{
- struct drm_device *dev = ring->dev;
- drm_i915_private_t *dev_priv = dev->dev_private;
+ intel_ring_emit(ring,
+ MI_BATCH_BUFFER_START |
+ MI_BATCH_GTT |
+ MI_BATCH_NON_SECURE_I965);
+ intel_ring_emit(ring, offset);
+ intel_ring_advance(ring);
- spin_lock(&ring->irq_lock);
- if (--ring->irq_refcount == 0) {
- if (IS_G4X(dev))
- i915_disable_irq(dev_priv, I915_BSD_USER_INTERRUPT);
- else
- ironlake_disable_irq(dev_priv, GT_BSD_USER_INTERRUPT);
- }
- spin_unlock(&ring->irq_lock);
+ return 0;
}
static int
-ring_dispatch_execbuffer(struct intel_ring_buffer *ring, u32 offset, u32 length)
+i830_dispatch_execbuffer(struct intel_ring_buffer *ring,
+ u32 offset, u32 len)
{
int ret;
- ret = intel_ring_begin(ring, 2);
+ ret = intel_ring_begin(ring, 4);
if (ret)
return ret;
- intel_ring_emit(ring,
- MI_BATCH_BUFFER_START | (2 << 6) |
- MI_BATCH_NON_SECURE_I965);
- intel_ring_emit(ring, offset);
+ intel_ring_emit(ring, MI_BATCH_BUFFER);
+ intel_ring_emit(ring, offset | MI_BATCH_NON_SECURE);
+ intel_ring_emit(ring, offset + len - 8);
+ intel_ring_emit(ring, 0);
intel_ring_advance(ring);
return 0;
}
static int
-render_ring_dispatch_execbuffer(struct intel_ring_buffer *ring,
+i915_dispatch_execbuffer(struct intel_ring_buffer *ring,
u32 offset, u32 len)
{
- struct drm_device *dev = ring->dev;
int ret;
- if (IS_I830(dev) || IS_845G(dev)) {
- ret = intel_ring_begin(ring, 4);
- if (ret)
- return ret;
-
- intel_ring_emit(ring, MI_BATCH_BUFFER);
- intel_ring_emit(ring, offset | MI_BATCH_NON_SECURE);
- intel_ring_emit(ring, offset + len - 8);
- intel_ring_emit(ring, 0);
- } else {
- ret = intel_ring_begin(ring, 2);
- if (ret)
- return ret;
+ ret = intel_ring_begin(ring, 2);
+ if (ret)
+ return ret;
- if (INTEL_INFO(dev)->gen >= 4) {
- intel_ring_emit(ring,
- MI_BATCH_BUFFER_START | (2 << 6) |
- MI_BATCH_NON_SECURE_I965);
- intel_ring_emit(ring, offset);
- } else {
- intel_ring_emit(ring,
- MI_BATCH_BUFFER_START | (2 << 6));
- intel_ring_emit(ring, offset | MI_BATCH_NON_SECURE);
- }
- }
+ intel_ring_emit(ring, MI_BATCH_BUFFER_START | MI_BATCH_GTT);
+ intel_ring_emit(ring, offset | MI_BATCH_NON_SECURE);
intel_ring_advance(ring);
return 0;
@@ -933,7 +900,6 @@ render_ring_dispatch_execbuffer(struct intel_ring_buffer *ring,
static void cleanup_status_page(struct intel_ring_buffer *ring)
{
- drm_i915_private_t *dev_priv = ring->dev->dev_private;
struct drm_i915_gem_object *obj;
obj = ring->status_page.obj;
@@ -944,14 +910,11 @@ static void cleanup_status_page(struct intel_ring_buffer *ring)
i915_gem_object_unpin(obj);
drm_gem_object_unreference(&obj->base);
ring->status_page.obj = NULL;
-
- memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
}
static int init_status_page(struct intel_ring_buffer *ring)
{
struct drm_device *dev = ring->dev;
- drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj;
int ret;
@@ -972,7 +935,6 @@ static int init_status_page(struct intel_ring_buffer *ring)
ring->status_page.gfx_addr = obj->gtt_offset;
ring->status_page.page_addr = kmap(obj->pages[0]);
if (ring->status_page.page_addr == NULL) {
- memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
goto err_unpin;
}
ring->status_page.obj = obj;
@@ -992,8 +954,8 @@ err:
return ret;
}
-int intel_init_ring_buffer(struct drm_device *dev,
- struct intel_ring_buffer *ring)
+static int intel_init_ring_buffer(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
{
struct drm_i915_gem_object *obj;
int ret;
@@ -1002,10 +964,9 @@ int intel_init_ring_buffer(struct drm_device *dev,
INIT_LIST_HEAD(&ring->active_list);
INIT_LIST_HEAD(&ring->request_list);
INIT_LIST_HEAD(&ring->gpu_write_list);
+ ring->size = 32 * PAGE_SIZE;
init_waitqueue_head(&ring->irq_queue);
- spin_lock_init(&ring->irq_lock);
- ring->irq_mask = ~0;
if (I915_NEED_GFX_HWS(dev)) {
ret = init_status_page(ring);
@@ -1026,20 +987,14 @@ int intel_init_ring_buffer(struct drm_device *dev,
if (ret)
goto err_unref;
- ring->map.size = ring->size;
- ring->map.offset = dev->agp->base + obj->gtt_offset;
- ring->map.type = 0;
- ring->map.flags = 0;
- ring->map.mtrr = 0;
-
- drm_core_ioremap_wc(&ring->map, dev);
- if (ring->map.handle == NULL) {
+ ring->virtual_start = ioremap_wc(dev->agp->base + obj->gtt_offset,
+ ring->size);
+ if (ring->virtual_start == NULL) {
DRM_ERROR("Failed to map ringbuffer.\n");
ret = -EINVAL;
goto err_unpin;
}
- ring->virtual_start = ring->map.handle;
ret = ring->init(ring);
if (ret)
goto err_unmap;
@@ -1055,7 +1010,7 @@ int intel_init_ring_buffer(struct drm_device *dev,
return 0;
err_unmap:
- drm_core_ioremapfree(&ring->map, dev);
+ iounmap(ring->virtual_start);
err_unpin:
i915_gem_object_unpin(obj);
err_unref:
@@ -1083,7 +1038,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring)
I915_WRITE_CTL(ring, 0);
- drm_core_ioremapfree(&ring->map, ring->dev);
+ iounmap(ring->virtual_start);
i915_gem_object_unpin(ring->obj);
drm_gem_object_unreference(&ring->obj->base);
@@ -1097,7 +1052,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring)
static int intel_wrap_ring_buffer(struct intel_ring_buffer *ring)
{
- unsigned int *virt;
+ uint32_t __iomem *virt;
int rem = ring->size - ring->tail;
if (ring->space < rem) {
@@ -1106,12 +1061,10 @@ static int intel_wrap_ring_buffer(struct intel_ring_buffer *ring)
return ret;
}
- virt = (unsigned int *)(ring->virtual_start + ring->tail);
- rem /= 8;
- while (rem--) {
- *virt++ = MI_NOOP;
- *virt++ = MI_NOOP;
- }
+ virt = ring->virtual_start + ring->tail;
+ rem /= 4;
+ while (rem--)
+ iowrite32(MI_NOOP, virt++);
ring->tail = 0;
ring->space = ring_space(ring);
@@ -1132,9 +1085,11 @@ static int intel_ring_wait_seqno(struct intel_ring_buffer *ring, u32 seqno)
was_interruptible = dev_priv->mm.interruptible;
dev_priv->mm.interruptible = false;
- ret = i915_wait_request(ring, seqno, true);
+ ret = i915_wait_request(ring, seqno);
dev_priv->mm.interruptible = was_interruptible;
+ if (!ret)
+ i915_gem_retire_requests_ring(ring);
return ret;
}
@@ -1208,15 +1163,12 @@ int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n)
return ret;
trace_i915_ring_wait_begin(ring);
- if (drm_core_check_feature(dev, DRIVER_GEM))
- /* With GEM the hangcheck timer should kick us out of the loop,
- * leaving it early runs the risk of corrupting GEM state (due
- * to running on almost untested codepaths). But on resume
- * timers don't work yet, so prevent a complete hang in that
- * case by choosing an insanely large timeout. */
- end = jiffies + 60 * HZ;
- else
- end = jiffies + 3 * HZ;
+ /* With GEM the hangcheck timer should kick us out of the loop,
+ * leaving it early runs the risk of corrupting GEM state (due
+ * to running on almost untested codepaths). But on resume
+ * timers don't work yet, so prevent a complete hang in that
+ * case by choosing an insanely large timeout. */
+ end = jiffies + 60 * HZ;
do {
ring->head = I915_READ_HEAD(ring);
@@ -1268,48 +1220,14 @@ int intel_ring_begin(struct intel_ring_buffer *ring,
void intel_ring_advance(struct intel_ring_buffer *ring)
{
+ struct drm_i915_private *dev_priv = ring->dev->dev_private;
+
ring->tail &= ring->size - 1;
+ if (dev_priv->stop_rings & intel_ring_flag(ring))
+ return;
ring->write_tail(ring, ring->tail);
}
-static const struct intel_ring_buffer render_ring = {
- .name = "render ring",
- .id = RCS,
- .mmio_base = RENDER_RING_BASE,
- .size = 32 * PAGE_SIZE,
- .init = init_render_ring,
- .write_tail = ring_write_tail,
- .flush = render_ring_flush,
- .add_request = render_ring_add_request,
- .get_seqno = ring_get_seqno,
- .irq_get = render_ring_get_irq,
- .irq_put = render_ring_put_irq,
- .dispatch_execbuffer = render_ring_dispatch_execbuffer,
- .cleanup = render_ring_cleanup,
- .sync_to = render_ring_sync_to,
- .semaphore_register = {MI_SEMAPHORE_SYNC_INVALID,
- MI_SEMAPHORE_SYNC_RV,
- MI_SEMAPHORE_SYNC_RB},
- .signal_mbox = {GEN6_VRSYNC, GEN6_BRSYNC},
-};
-
-/* ring buffer for bit-stream decoder */
-
-static const struct intel_ring_buffer bsd_ring = {
- .name = "bsd ring",
- .id = VCS,
- .mmio_base = BSD_RING_BASE,
- .size = 32 * PAGE_SIZE,
- .init = init_ring_common,
- .write_tail = ring_write_tail,
- .flush = bsd_ring_flush,
- .add_request = ring_add_request,
- .get_seqno = ring_get_seqno,
- .irq_get = bsd_ring_get_irq,
- .irq_put = bsd_ring_put_irq,
- .dispatch_execbuffer = ring_dispatch_execbuffer,
-};
-
static void gen6_bsd_ring_write_tail(struct intel_ring_buffer *ring,
u32 value)
@@ -1372,77 +1290,8 @@ gen6_ring_dispatch_execbuffer(struct intel_ring_buffer *ring,
return 0;
}
-static bool
-gen6_render_ring_get_irq(struct intel_ring_buffer *ring)
-{
- return gen6_ring_get_irq(ring,
- GT_USER_INTERRUPT,
- GEN6_RENDER_USER_INTERRUPT);
-}
-
-static void
-gen6_render_ring_put_irq(struct intel_ring_buffer *ring)
-{
- return gen6_ring_put_irq(ring,
- GT_USER_INTERRUPT,
- GEN6_RENDER_USER_INTERRUPT);
-}
-
-static bool
-gen6_bsd_ring_get_irq(struct intel_ring_buffer *ring)
-{
- return gen6_ring_get_irq(ring,
- GT_GEN6_BSD_USER_INTERRUPT,
- GEN6_BSD_USER_INTERRUPT);
-}
-
-static void
-gen6_bsd_ring_put_irq(struct intel_ring_buffer *ring)
-{
- return gen6_ring_put_irq(ring,
- GT_GEN6_BSD_USER_INTERRUPT,
- GEN6_BSD_USER_INTERRUPT);
-}
-
-/* ring buffer for Video Codec for Gen6+ */
-static const struct intel_ring_buffer gen6_bsd_ring = {
- .name = "gen6 bsd ring",
- .id = VCS,
- .mmio_base = GEN6_BSD_RING_BASE,
- .size = 32 * PAGE_SIZE,
- .init = init_ring_common,
- .write_tail = gen6_bsd_ring_write_tail,
- .flush = gen6_ring_flush,
- .add_request = gen6_add_request,
- .get_seqno = gen6_ring_get_seqno,
- .irq_get = gen6_bsd_ring_get_irq,
- .irq_put = gen6_bsd_ring_put_irq,
- .dispatch_execbuffer = gen6_ring_dispatch_execbuffer,
- .sync_to = gen6_bsd_ring_sync_to,
- .semaphore_register = {MI_SEMAPHORE_SYNC_VR,
- MI_SEMAPHORE_SYNC_INVALID,
- MI_SEMAPHORE_SYNC_VB},
- .signal_mbox = {GEN6_RVSYNC, GEN6_BVSYNC},
-};
-
/* Blitter support (SandyBridge+) */
-static bool
-blt_ring_get_irq(struct intel_ring_buffer *ring)
-{
- return gen6_ring_get_irq(ring,
- GT_BLT_USER_INTERRUPT,
- GEN6_BLITTER_USER_INTERRUPT);
-}
-
-static void
-blt_ring_put_irq(struct intel_ring_buffer *ring)
-{
- gen6_ring_put_irq(ring,
- GT_BLT_USER_INTERRUPT,
- GEN6_BLITTER_USER_INTERRUPT);
-}
-
static int blt_ring_flush(struct intel_ring_buffer *ring,
u32 invalidate, u32 flush)
{
@@ -1464,42 +1313,63 @@ static int blt_ring_flush(struct intel_ring_buffer *ring,
return 0;
}
-static const struct intel_ring_buffer gen6_blt_ring = {
- .name = "blt ring",
- .id = BCS,
- .mmio_base = BLT_RING_BASE,
- .size = 32 * PAGE_SIZE,
- .init = init_ring_common,
- .write_tail = ring_write_tail,
- .flush = blt_ring_flush,
- .add_request = gen6_add_request,
- .get_seqno = gen6_ring_get_seqno,
- .irq_get = blt_ring_get_irq,
- .irq_put = blt_ring_put_irq,
- .dispatch_execbuffer = gen6_ring_dispatch_execbuffer,
- .sync_to = gen6_blt_ring_sync_to,
- .semaphore_register = {MI_SEMAPHORE_SYNC_BR,
- MI_SEMAPHORE_SYNC_BV,
- MI_SEMAPHORE_SYNC_INVALID},
- .signal_mbox = {GEN6_RBSYNC, GEN6_VBSYNC},
-};
-
int intel_init_render_ring_buffer(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
- *ring = render_ring;
+ ring->name = "render ring";
+ ring->id = RCS;
+ ring->mmio_base = RENDER_RING_BASE;
+
if (INTEL_INFO(dev)->gen >= 6) {
ring->add_request = gen6_add_request;
ring->flush = gen6_render_ring_flush;
- ring->irq_get = gen6_render_ring_get_irq;
- ring->irq_put = gen6_render_ring_put_irq;
+ ring->irq_get = gen6_ring_get_irq;
+ ring->irq_put = gen6_ring_put_irq;
+ ring->irq_enable_mask = GT_USER_INTERRUPT;
ring->get_seqno = gen6_ring_get_seqno;
+ ring->sync_to = gen6_ring_sync;
+ ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_INVALID;
+ ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_RV;
+ ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_RB;
+ ring->signal_mbox[0] = GEN6_VRSYNC;
+ ring->signal_mbox[1] = GEN6_BRSYNC;
} else if (IS_GEN5(dev)) {
ring->add_request = pc_render_add_request;
+ ring->flush = gen4_render_ring_flush;
ring->get_seqno = pc_render_get_seqno;
+ ring->irq_get = gen5_ring_get_irq;
+ ring->irq_put = gen5_ring_put_irq;
+ ring->irq_enable_mask = GT_USER_INTERRUPT | GT_PIPE_NOTIFY;
+ } else {
+ ring->add_request = i9xx_add_request;
+ if (INTEL_INFO(dev)->gen < 4)
+ ring->flush = gen2_render_ring_flush;
+ else
+ ring->flush = gen4_render_ring_flush;
+ ring->get_seqno = ring_get_seqno;
+ if (IS_GEN2(dev)) {
+ ring->irq_get = i8xx_ring_get_irq;
+ ring->irq_put = i8xx_ring_put_irq;
+ } else {
+ ring->irq_get = i9xx_ring_get_irq;
+ ring->irq_put = i9xx_ring_put_irq;
+ }
+ ring->irq_enable_mask = I915_USER_INTERRUPT;
}
+ ring->write_tail = ring_write_tail;
+ if (INTEL_INFO(dev)->gen >= 6)
+ ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
+ else if (INTEL_INFO(dev)->gen >= 4)
+ ring->dispatch_execbuffer = i965_dispatch_execbuffer;
+ else if (IS_I830(dev) || IS_845G(dev))
+ ring->dispatch_execbuffer = i830_dispatch_execbuffer;
+ else
+ ring->dispatch_execbuffer = i915_dispatch_execbuffer;
+ ring->init = init_render_ring;
+ ring->cleanup = render_ring_cleanup;
+
if (!I915_NEED_GFX_HWS(dev)) {
ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr;
@@ -1514,15 +1384,41 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size)
drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
- *ring = render_ring;
+ ring->name = "render ring";
+ ring->id = RCS;
+ ring->mmio_base = RENDER_RING_BASE;
+
if (INTEL_INFO(dev)->gen >= 6) {
- ring->add_request = gen6_add_request;
- ring->irq_get = gen6_render_ring_get_irq;
- ring->irq_put = gen6_render_ring_put_irq;
- } else if (IS_GEN5(dev)) {
- ring->add_request = pc_render_add_request;
- ring->get_seqno = pc_render_get_seqno;
+ /* non-kms not supported on gen6+ */
+ return -ENODEV;
+ }
+
+ /* Note: gem is not supported on gen5/ilk without kms (the corresponding
+ * gem_init ioctl returns with -ENODEV). Hence we do not need to set up
+ * the special gen5 functions. */
+ ring->add_request = i9xx_add_request;
+ if (INTEL_INFO(dev)->gen < 4)
+ ring->flush = gen2_render_ring_flush;
+ else
+ ring->flush = gen4_render_ring_flush;
+ ring->get_seqno = ring_get_seqno;
+ if (IS_GEN2(dev)) {
+ ring->irq_get = i8xx_ring_get_irq;
+ ring->irq_put = i8xx_ring_put_irq;
+ } else {
+ ring->irq_get = i9xx_ring_get_irq;
+ ring->irq_put = i9xx_ring_put_irq;
}
+ ring->irq_enable_mask = I915_USER_INTERRUPT;
+ ring->write_tail = ring_write_tail;
+ if (INTEL_INFO(dev)->gen >= 4)
+ ring->dispatch_execbuffer = i965_dispatch_execbuffer;
+ else if (IS_I830(dev) || IS_845G(dev))
+ ring->dispatch_execbuffer = i830_dispatch_execbuffer;
+ else
+ ring->dispatch_execbuffer = i915_dispatch_execbuffer;
+ ring->init = init_render_ring;
+ ring->cleanup = render_ring_cleanup;
if (!I915_NEED_GFX_HWS(dev))
ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr;
@@ -1537,20 +1433,13 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size)
if (IS_I830(ring->dev))
ring->effective_size -= 128;
- ring->map.offset = start;
- ring->map.size = size;
- ring->map.type = 0;
- ring->map.flags = 0;
- ring->map.mtrr = 0;
-
- drm_core_ioremap_wc(&ring->map, dev);
- if (ring->map.handle == NULL) {
+ ring->virtual_start = ioremap_wc(start, size);
+ if (ring->virtual_start == NULL) {
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
return -ENOMEM;
}
- ring->virtual_start = (void __force __iomem *)ring->map.handle;
return 0;
}
@@ -1559,10 +1448,46 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev)
drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring = &dev_priv->ring[VCS];
- if (IS_GEN6(dev) || IS_GEN7(dev))
- *ring = gen6_bsd_ring;
- else
- *ring = bsd_ring;
+ ring->name = "bsd ring";
+ ring->id = VCS;
+
+ ring->write_tail = ring_write_tail;
+ if (IS_GEN6(dev) || IS_GEN7(dev)) {
+ ring->mmio_base = GEN6_BSD_RING_BASE;
+ /* gen6 bsd needs a special wa for tail updates */
+ if (IS_GEN6(dev))
+ ring->write_tail = gen6_bsd_ring_write_tail;
+ ring->flush = gen6_ring_flush;
+ ring->add_request = gen6_add_request;
+ ring->get_seqno = gen6_ring_get_seqno;
+ ring->irq_enable_mask = GEN6_BSD_USER_INTERRUPT;
+ ring->irq_get = gen6_ring_get_irq;
+ ring->irq_put = gen6_ring_put_irq;
+ ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
+ ring->sync_to = gen6_ring_sync;
+ ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_VR;
+ ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_INVALID;
+ ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_VB;
+ ring->signal_mbox[0] = GEN6_RVSYNC;
+ ring->signal_mbox[1] = GEN6_BVSYNC;
+ } else {
+ ring->mmio_base = BSD_RING_BASE;
+ ring->flush = bsd_ring_flush;
+ ring->add_request = i9xx_add_request;
+ ring->get_seqno = ring_get_seqno;
+ if (IS_GEN5(dev)) {
+ ring->irq_enable_mask = GT_BSD_USER_INTERRUPT;
+ ring->irq_get = gen5_ring_get_irq;
+ ring->irq_put = gen5_ring_put_irq;
+ } else {
+ ring->irq_enable_mask = I915_BSD_USER_INTERRUPT;
+ ring->irq_get = i9xx_ring_get_irq;
+ ring->irq_put = i9xx_ring_put_irq;
+ }
+ ring->dispatch_execbuffer = i965_dispatch_execbuffer;
+ }
+ ring->init = init_ring_common;
+
return intel_init_ring_buffer(dev, ring);
}
@@ -1572,7 +1497,25 @@ int intel_init_blt_ring_buffer(struct drm_device *dev)
drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring = &dev_priv->ring[BCS];
- *ring = gen6_blt_ring;
+ ring->name = "blitter ring";
+ ring->id = BCS;
+
+ ring->mmio_base = BLT_RING_BASE;
+ ring->write_tail = ring_write_tail;
+ ring->flush = blt_ring_flush;
+ ring->add_request = gen6_add_request;
+ ring->get_seqno = gen6_ring_get_seqno;
+ ring->irq_enable_mask = GEN6_BLITTER_USER_INTERRUPT;
+ ring->irq_get = gen6_ring_get_irq;
+ ring->irq_put = gen6_ring_put_irq;
+ ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
+ ring->sync_to = gen6_ring_sync;
+ ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_BR;
+ ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_BV;
+ ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_INVALID;
+ ring->signal_mbox[0] = GEN6_RBSYNC;
+ ring->signal_mbox[1] = GEN6_VBSYNC;
+ ring->init = init_ring_common;
return intel_init_ring_buffer(dev, ring);
}
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index bc0365b8fa4d..55d3da26bae7 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -2,7 +2,7 @@
#define _INTEL_RINGBUFFER_H_
struct intel_hw_status_page {
- u32 __iomem *page_addr;
+ u32 *page_addr;
unsigned int gfx_addr;
struct drm_i915_gem_object *obj;
};
@@ -56,12 +56,9 @@ struct intel_ring_buffer {
*/
u32 last_retired_head;
- spinlock_t irq_lock;
- u32 irq_refcount;
- u32 irq_mask;
- u32 irq_seqno; /* last seq seem at irq time */
+ u32 irq_refcount; /* protected by dev_priv->irq_lock */
+ u32 irq_enable_mask; /* bitmask to enable ring interrupt */
u32 trace_irq_seqno;
- u32 waiting_seqno;
u32 sync_seqno[I915_NUM_RINGS-1];
bool __must_check (*irq_get)(struct intel_ring_buffer *ring);
void (*irq_put)(struct intel_ring_buffer *ring);
@@ -118,11 +115,16 @@ struct intel_ring_buffer {
u32 outstanding_lazy_request;
wait_queue_head_t irq_queue;
- drm_local_map_t map;
void *private;
};
+static inline bool
+intel_ring_initialized(struct intel_ring_buffer *ring)
+{
+ return ring->obj != NULL;
+}
+
static inline unsigned
intel_ring_flag(struct intel_ring_buffer *ring)
{
@@ -152,7 +154,9 @@ static inline u32
intel_read_status_page(struct intel_ring_buffer *ring,
int reg)
{
- return ioread32(ring->status_page.page_addr + reg);
+ /* Ensure that the compiler doesn't optimize away the load. */
+ barrier();
+ return ring->status_page.page_addr[reg];
}
/**
@@ -170,10 +174,7 @@ intel_read_status_page(struct intel_ring_buffer *ring,
*
* The area from dword 0x20 to 0x3ff is available for driver usage.
*/
-#define READ_HWSP(dev_priv, reg) intel_read_status_page(LP_RING(dev_priv), reg)
-#define READ_BREADCRUMB(dev_priv) READ_HWSP(dev_priv, I915_BREADCRUMB_INDEX)
#define I915_GEM_HWS_INDEX 0x20
-#define I915_BREADCRUMB_INDEX 0x21
void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring);
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index ae5e748f39bb..a949b73880c8 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -41,7 +41,7 @@
#define SDVO_TMDS_MASK (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)
#define SDVO_RGB_MASK (SDVO_OUTPUT_RGB0 | SDVO_OUTPUT_RGB1)
#define SDVO_LVDS_MASK (SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1)
-#define SDVO_TV_MASK (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_SVID0)
+#define SDVO_TV_MASK (SDVO_OUTPUT_CVBS0 | SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_YPRPB0)
#define SDVO_OUTPUT_MASK (SDVO_TMDS_MASK | SDVO_RGB_MASK | SDVO_LVDS_MASK |\
SDVO_TV_MASK)
@@ -74,7 +74,7 @@ struct intel_sdvo {
struct i2c_adapter ddc;
/* Register for the SDVO device: SDVOB or SDVOC */
- int sdvo_reg;
+ uint32_t sdvo_reg;
/* Active outputs controlled by this SDVO output */
uint16_t controlled_output;
@@ -114,6 +114,9 @@ struct intel_sdvo {
*/
bool is_tv;
+ /* On different gens SDVOB is at different places. */
+ bool is_sdvob;
+
/* This is for current tv format name */
int tv_format_index;
@@ -403,8 +406,7 @@ static const struct _sdvo_cmd_name {
SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_DATA),
};
-#define IS_SDVOB(reg) (reg == SDVOB || reg == PCH_SDVOB)
-#define SDVO_NAME(svdo) (IS_SDVOB((svdo)->sdvo_reg) ? "SDVOB" : "SDVOC")
+#define SDVO_NAME(svdo) ((svdo)->is_sdvob ? "SDVOB" : "SDVOC")
static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd,
const void *args, int args_len)
@@ -441,9 +443,17 @@ static const char *cmd_status_names[] = {
static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
const void *args, int args_len)
{
- u8 buf[args_len*2 + 2], status;
- struct i2c_msg msgs[args_len + 3];
- int i, ret;
+ u8 *buf, status;
+ struct i2c_msg *msgs;
+ int i, ret = true;
+
+ buf = (u8 *)kzalloc(args_len * 2 + 2, GFP_KERNEL);
+ if (!buf)
+ return false;
+
+ msgs = kcalloc(args_len + 3, sizeof(*msgs), GFP_KERNEL);
+ if (!msgs)
+ return false;
intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len);
@@ -477,15 +487,19 @@ static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
ret = i2c_transfer(intel_sdvo->i2c, msgs, i+3);
if (ret < 0) {
DRM_DEBUG_KMS("I2c transfer returned %d\n", ret);
- return false;
+ ret = false;
+ goto out;
}
if (ret != i+3) {
/* failure in I2C transfer */
DRM_DEBUG_KMS("I2c transfer returned %d/%d\n", ret, i+3);
- return false;
+ ret = false;
}
- return true;
+out:
+ kfree(msgs);
+ kfree(buf);
+ return ret;
}
static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
@@ -733,18 +747,18 @@ static void intel_sdvo_get_dtd_from_mode(struct intel_sdvo_dtd *dtd,
uint16_t h_sync_offset, v_sync_offset;
int mode_clock;
- width = mode->crtc_hdisplay;
- height = mode->crtc_vdisplay;
+ width = mode->hdisplay;
+ height = mode->vdisplay;
/* do some mode translations */
- h_blank_len = mode->crtc_hblank_end - mode->crtc_hblank_start;
- h_sync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
+ h_blank_len = mode->htotal - mode->hdisplay;
+ h_sync_len = mode->hsync_end - mode->hsync_start;
- v_blank_len = mode->crtc_vblank_end - mode->crtc_vblank_start;
- v_sync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
+ v_blank_len = mode->vtotal - mode->vdisplay;
+ v_sync_len = mode->vsync_end - mode->vsync_start;
- h_sync_offset = mode->crtc_hsync_start - mode->crtc_hblank_start;
- v_sync_offset = mode->crtc_vsync_start - mode->crtc_vblank_start;
+ h_sync_offset = mode->hsync_start - mode->hdisplay;
+ v_sync_offset = mode->vsync_start - mode->vdisplay;
mode_clock = mode->clock;
mode_clock /= intel_mode_get_pixel_multiplier(mode) ?: 1;
@@ -873,17 +887,24 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo)
};
uint8_t tx_rate = SDVO_HBUF_TX_VSYNC;
uint8_t set_buf_index[2] = { 1, 0 };
- uint64_t *data = (uint64_t *)&avi_if;
+ uint8_t sdvo_data[4 + sizeof(avi_if.body.avi)];
+ uint64_t *data = (uint64_t *)sdvo_data;
unsigned i;
intel_dip_infoframe_csum(&avi_if);
+ /* sdvo spec says that the ecc is handled by the hw, and it looks like
+ * we must not send the ecc field, either. */
+ memcpy(sdvo_data, &avi_if, 3);
+ sdvo_data[3] = avi_if.checksum;
+ memcpy(&sdvo_data[4], &avi_if.body, sizeof(avi_if.body.avi));
+
if (!intel_sdvo_set_value(intel_sdvo,
SDVO_CMD_SET_HBUF_INDEX,
set_buf_index, 2))
return false;
- for (i = 0; i < sizeof(avi_if); i += 8) {
+ for (i = 0; i < sizeof(sdvo_data); i += 8) {
if (!intel_sdvo_set_value(intel_sdvo,
SDVO_CMD_SET_HBUF_DATA,
data, 8))
@@ -1260,10 +1281,11 @@ intel_sdvo_get_analog_edid(struct drm_connector *connector)
struct drm_i915_private *dev_priv = connector->dev->dev_private;
return drm_get_edid(connector,
- &dev_priv->gmbus[dev_priv->crt_ddc_pin].adapter);
+ intel_gmbus_get_adapter(dev_priv,
+ dev_priv->crt_ddc_pin));
}
-enum drm_connector_status
+static enum drm_connector_status
intel_sdvo_tmds_sink_detect(struct drm_connector *connector)
{
struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
@@ -1349,8 +1371,7 @@ intel_sdvo_detect(struct drm_connector *connector, bool force)
return connector_status_unknown;
/* add 30ms delay when the output type might be TV */
- if (intel_sdvo->caps.output_flags &
- (SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_CVBS0))
+ if (intel_sdvo->caps.output_flags & SDVO_TV_MASK)
mdelay(30);
if (!intel_sdvo_read_response(intel_sdvo, &response, 2))
@@ -1570,9 +1591,6 @@ end:
intel_sdvo->sdvo_lvds_fixed_mode =
drm_mode_duplicate(connector->dev, newmode);
- drm_mode_set_crtcinfo(intel_sdvo->sdvo_lvds_fixed_mode,
- 0);
-
intel_sdvo->is_lvds = true;
break;
}
@@ -1901,7 +1919,7 @@ intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv,
{
struct sdvo_device_mapping *mapping;
- if (IS_SDVOB(reg))
+ if (sdvo->is_sdvob)
mapping = &(dev_priv->sdvo_mappings[0]);
else
mapping = &(dev_priv->sdvo_mappings[1]);
@@ -1919,7 +1937,7 @@ intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv,
struct sdvo_device_mapping *mapping;
u8 pin;
- if (IS_SDVOB(reg))
+ if (sdvo->is_sdvob)
mapping = &dev_priv->sdvo_mappings[0];
else
mapping = &dev_priv->sdvo_mappings[1];
@@ -1928,12 +1946,12 @@ intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv,
if (mapping->initialized)
pin = mapping->i2c_pin;
- if (pin < GMBUS_NUM_PORTS) {
- sdvo->i2c = &dev_priv->gmbus[pin].adapter;
+ if (intel_gmbus_is_port_valid(pin)) {
+ sdvo->i2c = intel_gmbus_get_adapter(dev_priv, pin);
intel_gmbus_set_speed(sdvo->i2c, GMBUS_RATE_1MHZ);
intel_gmbus_force_bit(sdvo->i2c, true);
} else {
- sdvo->i2c = &dev_priv->gmbus[GMBUS_PORT_DPB].adapter;
+ sdvo->i2c = intel_gmbus_get_adapter(dev_priv, GMBUS_PORT_DPB);
}
}
@@ -1944,12 +1962,12 @@ intel_sdvo_is_hdmi_connector(struct intel_sdvo *intel_sdvo, int device)
}
static u8
-intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg)
+intel_sdvo_get_slave_addr(struct drm_device *dev, struct intel_sdvo *sdvo)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct sdvo_device_mapping *my_mapping, *other_mapping;
- if (IS_SDVOB(sdvo_reg)) {
+ if (sdvo->is_sdvob) {
my_mapping = &dev_priv->sdvo_mappings[0];
other_mapping = &dev_priv->sdvo_mappings[1];
} else {
@@ -1974,7 +1992,7 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int sdvo_reg)
/* No SDVO device info is found for another DVO port,
* so use mapping assumption we had before BIOS parsing.
*/
- if (IS_SDVOB(sdvo_reg))
+ if (sdvo->is_sdvob)
return 0x70;
else
return 0x72;
@@ -2199,6 +2217,10 @@ intel_sdvo_output_setup(struct intel_sdvo *intel_sdvo, uint16_t flags)
if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_CVBS0))
return false;
+ if (flags & SDVO_OUTPUT_YPRPB0)
+ if (!intel_sdvo_tv_init(intel_sdvo, SDVO_OUTPUT_YPRPB0))
+ return false;
+
if (flags & SDVO_OUTPUT_RGB0)
if (!intel_sdvo_analog_init(intel_sdvo, 0))
return false;
@@ -2490,7 +2512,7 @@ intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo,
return i2c_add_adapter(&sdvo->ddc) == 0;
}
-bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
+bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_encoder *intel_encoder;
@@ -2502,7 +2524,8 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
return false;
intel_sdvo->sdvo_reg = sdvo_reg;
- intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg) >> 1;
+ intel_sdvo->is_sdvob = is_sdvob;
+ intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, intel_sdvo) >> 1;
intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg);
if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev)) {
kfree(intel_sdvo);
@@ -2519,13 +2542,13 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
u8 byte;
if (!intel_sdvo_read_byte(intel_sdvo, i, &byte)) {
- DRM_DEBUG_KMS("No SDVO device found on SDVO%c\n",
- IS_SDVOB(sdvo_reg) ? 'B' : 'C');
+ DRM_DEBUG_KMS("No SDVO device found on %s\n",
+ SDVO_NAME(intel_sdvo));
goto err;
}
}
- if (IS_SDVOB(sdvo_reg))
+ if (intel_sdvo->is_sdvob)
dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS;
else
dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS;
@@ -2546,8 +2569,8 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
if (intel_sdvo_output_setup(intel_sdvo,
intel_sdvo->caps.output_flags) != true) {
- DRM_DEBUG_KMS("SDVO output failed to setup on SDVO%c\n",
- IS_SDVOB(sdvo_reg) ? 'B' : 'C');
+ DRM_DEBUG_KMS("SDVO output failed to setup on %s\n",
+ SDVO_NAME(intel_sdvo));
goto err;
}
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index e90dfb625c42..2a20fb0781d7 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -110,14 +110,18 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
* when scaling is disabled.
*/
if (crtc_w != src_w || crtc_h != src_h) {
- dev_priv->sprite_scaling_enabled = true;
- sandybridge_update_wm(dev);
- intel_wait_for_vblank(dev, pipe);
+ if (!dev_priv->sprite_scaling_enabled) {
+ dev_priv->sprite_scaling_enabled = true;
+ intel_update_watermarks(dev);
+ intel_wait_for_vblank(dev, pipe);
+ }
sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h;
} else {
- dev_priv->sprite_scaling_enabled = false;
- /* potentially re-enable LP watermarks */
- sandybridge_update_wm(dev);
+ if (dev_priv->sprite_scaling_enabled) {
+ dev_priv->sprite_scaling_enabled = false;
+ /* potentially re-enable LP watermarks */
+ intel_update_watermarks(dev);
+ }
}
I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
@@ -133,7 +137,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w);
I915_WRITE(SPRSCALE(pipe), sprscale);
I915_WRITE(SPRCTL(pipe), sprctl);
- I915_WRITE(SPRSURF(pipe), obj->gtt_offset);
+ I915_MODIFY_DISPBASE(SPRSURF(pipe), obj->gtt_offset);
POSTING_READ(SPRSURF(pipe));
}
@@ -149,8 +153,11 @@ ivb_disable_plane(struct drm_plane *plane)
/* Can't leave the scaler enabled... */
I915_WRITE(SPRSCALE(pipe), 0);
/* Activate double buffered register update */
- I915_WRITE(SPRSURF(pipe), 0);
+ I915_MODIFY_DISPBASE(SPRSURF(pipe), 0);
POSTING_READ(SPRSURF(pipe));
+
+ dev_priv->sprite_scaling_enabled = false;
+ intel_update_watermarks(dev);
}
static int
@@ -208,7 +215,7 @@ ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
}
static void
-snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
+ilk_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
unsigned int crtc_w, unsigned int crtc_h,
uint32_t x, uint32_t y,
@@ -218,7 +225,7 @@ snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_plane *intel_plane = to_intel_plane(plane);
int pipe = intel_plane->pipe, pixel_size;
- u32 dvscntr, dvsscale = 0;
+ u32 dvscntr, dvsscale;
dvscntr = I915_READ(DVSCNTR(pipe));
@@ -262,8 +269,8 @@ snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
if (obj->tiling_mode != I915_TILING_NONE)
dvscntr |= DVS_TILED;
- /* must disable */
- dvscntr |= DVS_TRICKLE_FEED_DISABLE;
+ if (IS_GEN6(dev))
+ dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */
dvscntr |= DVS_ENABLE;
/* Sizes are 0 based */
@@ -274,7 +281,8 @@ snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
intel_update_sprite_watermarks(dev, pipe, crtc_w, pixel_size);
- if (crtc_w != src_w || crtc_h != src_h)
+ dvsscale = 0;
+ if (IS_GEN5(dev) || crtc_w != src_w || crtc_h != src_h)
dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h;
I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
@@ -290,12 +298,12 @@ snb_update_plane(struct drm_plane *plane, struct drm_framebuffer *fb,
I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w);
I915_WRITE(DVSSCALE(pipe), dvsscale);
I915_WRITE(DVSCNTR(pipe), dvscntr);
- I915_WRITE(DVSSURF(pipe), obj->gtt_offset);
+ I915_MODIFY_DISPBASE(DVSSURF(pipe), obj->gtt_offset);
POSTING_READ(DVSSURF(pipe));
}
static void
-snb_disable_plane(struct drm_plane *plane)
+ilk_disable_plane(struct drm_plane *plane)
{
struct drm_device *dev = plane->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -306,7 +314,7 @@ snb_disable_plane(struct drm_plane *plane)
/* Disable the scaler */
I915_WRITE(DVSSCALE(pipe), 0);
/* Flush double buffered register updates */
- I915_WRITE(DVSSURF(pipe), 0);
+ I915_MODIFY_DISPBASE(DVSSURF(pipe), 0);
POSTING_READ(DVSSURF(pipe));
}
@@ -333,7 +341,7 @@ intel_disable_primary(struct drm_crtc *crtc)
}
static int
-snb_update_colorkey(struct drm_plane *plane,
+ilk_update_colorkey(struct drm_plane *plane,
struct drm_intel_sprite_colorkey *key)
{
struct drm_device *dev = plane->dev;
@@ -362,7 +370,7 @@ snb_update_colorkey(struct drm_plane *plane,
}
static void
-snb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
+ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
{
struct drm_device *dev = plane->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -550,14 +558,13 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_intel_sprite_colorkey *set = data;
- struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_mode_object *obj;
struct drm_plane *plane;
struct intel_plane *intel_plane;
int ret = 0;
- if (!dev_priv)
- return -EINVAL;
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
+ return -ENODEV;
/* Make sure we don't try to enable both src & dest simultaneously */
if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
@@ -584,14 +591,13 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
struct drm_intel_sprite_colorkey *get = data;
- struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_mode_object *obj;
struct drm_plane *plane;
struct intel_plane *intel_plane;
int ret = 0;
- if (!dev_priv)
- return -EINVAL;
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
+ return -ENODEV;
mutex_lock(&dev->mode_config.mutex);
@@ -616,6 +622,14 @@ static const struct drm_plane_funcs intel_plane_funcs = {
.destroy = intel_destroy_plane,
};
+static uint32_t ilk_plane_formats[] = {
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_YUYV,
+ DRM_FORMAT_YVYU,
+ DRM_FORMAT_UYVY,
+ DRM_FORMAT_VYUY,
+};
+
static uint32_t snb_plane_formats[] = {
DRM_FORMAT_XBGR8888,
DRM_FORMAT_XRGB8888,
@@ -630,34 +644,56 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe)
{
struct intel_plane *intel_plane;
unsigned long possible_crtcs;
+ const uint32_t *plane_formats;
+ int num_plane_formats;
int ret;
- if (!(IS_GEN6(dev) || IS_GEN7(dev)))
+ if (INTEL_INFO(dev)->gen < 5)
return -ENODEV;
intel_plane = kzalloc(sizeof(struct intel_plane), GFP_KERNEL);
if (!intel_plane)
return -ENOMEM;
- if (IS_GEN6(dev)) {
+ switch (INTEL_INFO(dev)->gen) {
+ case 5:
+ case 6:
intel_plane->max_downscale = 16;
- intel_plane->update_plane = snb_update_plane;
- intel_plane->disable_plane = snb_disable_plane;
- intel_plane->update_colorkey = snb_update_colorkey;
- intel_plane->get_colorkey = snb_get_colorkey;
- } else if (IS_GEN7(dev)) {
+ intel_plane->update_plane = ilk_update_plane;
+ intel_plane->disable_plane = ilk_disable_plane;
+ intel_plane->update_colorkey = ilk_update_colorkey;
+ intel_plane->get_colorkey = ilk_get_colorkey;
+
+ if (IS_GEN6(dev)) {
+ plane_formats = snb_plane_formats;
+ num_plane_formats = ARRAY_SIZE(snb_plane_formats);
+ } else {
+ plane_formats = ilk_plane_formats;
+ num_plane_formats = ARRAY_SIZE(ilk_plane_formats);
+ }
+ break;
+
+ case 7:
intel_plane->max_downscale = 2;
intel_plane->update_plane = ivb_update_plane;
intel_plane->disable_plane = ivb_disable_plane;
intel_plane->update_colorkey = ivb_update_colorkey;
intel_plane->get_colorkey = ivb_get_colorkey;
+
+ plane_formats = snb_plane_formats;
+ num_plane_formats = ARRAY_SIZE(snb_plane_formats);
+ break;
+
+ default:
+ return -ENODEV;
}
intel_plane->pipe = pipe;
possible_crtcs = (1 << pipe);
ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs,
- &intel_plane_funcs, snb_plane_formats,
- ARRAY_SIZE(snb_plane_formats), false);
+ &intel_plane_funcs,
+ plane_formats, num_plane_formats,
+ false);
if (ret)
kfree(intel_plane);
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 05f765ef5464..3346612d2953 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -811,7 +811,7 @@ intel_tv_mode_lookup(const char *tv_format)
{
int i;
- for (i = 0; i < sizeof(tv_modes) / sizeof(tv_modes[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(tv_modes); i++) {
const struct tv_mode *tv_mode = &tv_modes[i];
if (!strcmp(tv_format, tv_mode->name))
@@ -1153,6 +1153,15 @@ intel_tv_detect_type(struct intel_tv *intel_tv,
DAC_B_0_7_V |
DAC_C_0_7_V);
+
+ /*
+ * The TV sense state should be cleared to zero on cantiga platform. Otherwise
+ * the TV is misdetected. This is hardware requirement.
+ */
+ if (IS_GM45(dev))
+ tv_dac &= ~(TVDAC_STATE_CHG_EN | TVDAC_A_SENSE_CTL |
+ TVDAC_B_SENSE_CTL | TVDAC_C_SENSE_CTL);
+
I915_WRITE(TV_CTL, tv_ctl);
I915_WRITE(TV_DAC, tv_dac);
POSTING_READ(TV_DAC);
@@ -1240,11 +1249,8 @@ intel_tv_detect(struct drm_connector *connector, bool force)
int type;
mode = reported_modes[0];
- drm_mode_set_crtcinfo(&mode, 0);
- if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) {
- type = intel_tv_detect_type(intel_tv, connector);
- } else if (force) {
+ if (force) {
struct intel_load_detect_pipe tmp;
if (intel_get_load_detect_pipe(&intel_tv->base, connector,
diff --git a/drivers/gpu/drm/mgag200/Kconfig b/drivers/gpu/drm/mgag200/Kconfig
new file mode 100644
index 000000000000..d63013497f66
--- /dev/null
+++ b/drivers/gpu/drm/mgag200/Kconfig
@@ -0,0 +1,15 @@
+config DRM_MGAG200
+ tristate "Kernel modesetting driver for MGA G200 server engines"
+ depends on DRM && PCI && EXPERIMENTAL
+ select FB_SYS_FILLRECT
+ select FB_SYS_COPYAREA
+ select FB_SYS_IMAGEBLIT
+ select DRM_KMS_HELPER
+ select DRM_TTM
+ help
+ This is a KMS driver for the MGA G200 server chips, it
+ does not support the original MGA G200 or any of the desktop
+ chips. It requires 0.3.0 of the modesetting userspace driver,
+ and a version of mga driver that will fail on KMS enabled
+ devices.
+
diff --git a/drivers/gpu/drm/mgag200/Makefile b/drivers/gpu/drm/mgag200/Makefile
new file mode 100644
index 000000000000..7db592eedbf1
--- /dev/null
+++ b/drivers/gpu/drm/mgag200/Makefile
@@ -0,0 +1,5 @@
+ccflags-y := -Iinclude/drm
+mgag200-y := mgag200_main.o mgag200_mode.o \
+ mgag200_drv.o mgag200_fb.o mgag200_i2c.o mgag200_ttm.o
+
+obj-$(CONFIG_DRM_MGAG200) += mgag200.o
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c
new file mode 100644
index 000000000000..3c8e04f54713
--- /dev/null
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2012 Red Hat
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * Authors: Matthew Garrett
+ * Dave Airlie
+ */
+#include <linux/module.h>
+#include <linux/console.h>
+#include "drmP.h"
+#include "drm.h"
+
+#include "mgag200_drv.h"
+
+#include "drm_pciids.h"
+
+/*
+ * This is the generic driver code. This binds the driver to the drm core,
+ * which then performs further device association and calls our graphics init
+ * functions
+ */
+int mgag200_modeset = -1;
+
+MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
+module_param_named(modeset, mgag200_modeset, int, 0400);
+
+static struct drm_driver driver;
+
+static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
+ { PCI_VENDOR_ID_MATROX, 0x522, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_A },
+ { PCI_VENDOR_ID_MATROX, 0x524, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_SE_B },
+ { PCI_VENDOR_ID_MATROX, 0x530, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_EV },
+ { PCI_VENDOR_ID_MATROX, 0x532, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_WB },
+ { PCI_VENDOR_ID_MATROX, 0x533, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_EH },
+ { PCI_VENDOR_ID_MATROX, 0x534, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_ER },
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, pciidlist);
+
+static int __devinit
+mga_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ return drm_get_pci_dev(pdev, ent, &driver);
+}
+
+static void mga_pci_remove(struct pci_dev *pdev)
+{
+ struct drm_device *dev = pci_get_drvdata(pdev);
+
+ drm_put_dev(dev);
+}
+
+static const struct file_operations mgag200_driver_fops = {
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .unlocked_ioctl = drm_ioctl,
+ .mmap = mgag200_mmap,
+ .poll = drm_poll,
+ .fasync = drm_fasync,
+ .read = drm_read,
+};
+
+static struct drm_driver driver = {
+ .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_USE_MTRR,
+ .load = mgag200_driver_load,
+ .unload = mgag200_driver_unload,
+ .fops = &mgag200_driver_fops,
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+ .date = DRIVER_DATE,
+ .major = DRIVER_MAJOR,
+ .minor = DRIVER_MINOR,
+ .patchlevel = DRIVER_PATCHLEVEL,
+
+ .gem_init_object = mgag200_gem_init_object,
+ .gem_free_object = mgag200_gem_free_object,
+ .dumb_create = mgag200_dumb_create,
+ .dumb_map_offset = mgag200_dumb_mmap_offset,
+ .dumb_destroy = mgag200_dumb_destroy,
+};
+
+static struct pci_driver mgag200_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = pciidlist,
+ .probe = mga_pci_probe,
+ .remove = mga_pci_remove,
+};
+
+static int __init mgag200_init(void)
+{
+#ifdef CONFIG_VGA_CONSOLE
+ if (vgacon_text_force() && mgag200_modeset == -1)
+ return -EINVAL;
+#endif
+
+ if (mgag200_modeset == 0)
+ return -EINVAL;
+ return drm_pci_init(&driver, &mgag200_pci_driver);
+}
+
+static void __exit mgag200_exit(void)
+{
+ drm_pci_exit(&driver, &mgag200_pci_driver);
+}
+
+module_init(mgag200_init);
+module_exit(mgag200_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h
new file mode 100644
index 000000000000..6f13b3563234
--- /dev/null
+++ b/drivers/gpu/drm/mgag200/mgag200_drv.h
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2010 Matt Turner.
+ * Copyright 2012 Red Hat
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * Authors: Matthew Garrett
+ * Matt Turner
+ * Dave Airlie
+ */
+#ifndef __MGAG200_DRV_H__
+#define __MGAG200_DRV_H__
+
+#include <video/vga.h>
+
+#include "drm/drm_fb_helper.h"
+#include "ttm/ttm_bo_api.h"
+#include "ttm/ttm_bo_driver.h"
+#include "ttm/ttm_placement.h"
+#include "ttm/ttm_memory.h"
+#include "ttm/ttm_module.h"
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#include "mgag200_reg.h"
+
+#define DRIVER_AUTHOR "Matthew Garrett"
+
+#define DRIVER_NAME "mgag200"
+#define DRIVER_DESC "MGA G200 SE"
+#define DRIVER_DATE "20110418"
+
+#define DRIVER_MAJOR 1
+#define DRIVER_MINOR 0
+#define DRIVER_PATCHLEVEL 0
+
+#define MGAG200FB_CONN_LIMIT 1
+
+#define RREG8(reg) ioread8(((void __iomem *)mdev->rmmio) + (reg))
+#define WREG8(reg, v) iowrite8(v, ((void __iomem *)mdev->rmmio) + (reg))
+#define RREG32(reg) ioread32(((void __iomem *)mdev->rmmio) + (reg))
+#define WREG32(reg, v) iowrite32(v, ((void __iomem *)mdev->rmmio) + (reg))
+
+#define ATTR_INDEX 0x1fc0
+#define ATTR_DATA 0x1fc1
+
+#define WREG_ATTR(reg, v) \
+ do { \
+ RREG8(0x1fda); \
+ WREG8(ATTR_INDEX, reg); \
+ WREG8(ATTR_DATA, v); \
+ } while (0) \
+
+#define WREG_SEQ(reg, v) \
+ do { \
+ WREG8(MGAREG_SEQ_INDEX, reg); \
+ WREG8(MGAREG_SEQ_DATA, v); \
+ } while (0) \
+
+#define WREG_CRT(reg, v) \
+ do { \
+ WREG8(MGAREG_CRTC_INDEX, reg); \
+ WREG8(MGAREG_CRTC_DATA, v); \
+ } while (0) \
+
+
+#define WREG_ECRT(reg, v) \
+ do { \
+ WREG8(MGAREG_CRTCEXT_INDEX, reg); \
+ WREG8(MGAREG_CRTCEXT_DATA, v); \
+ } while (0) \
+
+#define GFX_INDEX 0x1fce
+#define GFX_DATA 0x1fcf
+
+#define WREG_GFX(reg, v) \
+ do { \
+ WREG8(GFX_INDEX, reg); \
+ WREG8(GFX_DATA, v); \
+ } while (0) \
+
+#define DAC_INDEX 0x3c00
+#define DAC_DATA 0x3c0a
+
+#define WREG_DAC(reg, v) \
+ do { \
+ WREG8(DAC_INDEX, reg); \
+ WREG8(DAC_DATA, v); \
+ } while (0) \
+
+#define MGA_MISC_OUT 0x1fc2
+#define MGA_MISC_IN 0x1fcc
+
+#define MGAG200_MAX_FB_HEIGHT 4096
+#define MGAG200_MAX_FB_WIDTH 4096
+
+#define MATROX_DPMS_CLEARED (-1)
+
+#define to_mga_crtc(x) container_of(x, struct mga_crtc, base)
+#define to_mga_encoder(x) container_of(x, struct mga_encoder, base)
+#define to_mga_connector(x) container_of(x, struct mga_connector, base)
+#define to_mga_framebuffer(x) container_of(x, struct mga_framebuffer, base)
+
+struct mga_framebuffer {
+ struct drm_framebuffer base;
+ struct drm_gem_object *obj;
+};
+
+struct mga_fbdev {
+ struct drm_fb_helper helper;
+ struct mga_framebuffer mfb;
+ struct list_head fbdev_list;
+ void *sysram;
+ int size;
+ struct ttm_bo_kmap_obj mapping;
+};
+
+struct mga_crtc {
+ struct drm_crtc base;
+ u8 lut_r[256], lut_g[256], lut_b[256];
+ int last_dpms;
+ bool enabled;
+};
+
+struct mga_mode_info {
+ bool mode_config_initialized;
+ struct mga_crtc *crtc;
+};
+
+struct mga_encoder {
+ struct drm_encoder base;
+ int last_dpms;
+};
+
+
+struct mga_i2c_chan {
+ struct i2c_adapter adapter;
+ struct drm_device *dev;
+ struct i2c_algo_bit_data bit;
+ int data, clock;
+};
+
+struct mga_connector {
+ struct drm_connector base;
+ struct mga_i2c_chan *i2c;
+};
+
+
+struct mga_mc {
+ resource_size_t vram_size;
+ resource_size_t vram_base;
+ resource_size_t vram_window;
+};
+
+enum mga_type {
+ G200_SE_A,
+ G200_SE_B,
+ G200_WB,
+ G200_EV,
+ G200_EH,
+ G200_ER,
+};
+
+#define IS_G200_SE(mdev) (mdev->type == G200_SE_A || mdev->type == G200_SE_B)
+
+struct mga_device {
+ struct drm_device *dev;
+ unsigned long flags;
+
+ resource_size_t rmmio_base;
+ resource_size_t rmmio_size;
+ void __iomem *rmmio;
+
+ drm_local_map_t *framebuffer;
+
+ struct mga_mc mc;
+ struct mga_mode_info mode_info;
+
+ struct mga_fbdev *mfbdev;
+
+ bool suspended;
+ int num_crtc;
+ enum mga_type type;
+ int has_sdram;
+ struct drm_display_mode mode;
+
+ int bpp_shifts[4];
+
+ int fb_mtrr;
+
+ struct {
+ struct drm_global_reference mem_global_ref;
+ struct ttm_bo_global_ref bo_global_ref;
+ struct ttm_bo_device bdev;
+ atomic_t validate_sequence;
+ } ttm;
+
+ u32 reg_1e24; /* SE model number */
+};
+
+
+struct mgag200_bo {
+ struct ttm_buffer_object bo;
+ struct ttm_placement placement;
+ struct ttm_bo_kmap_obj kmap;
+ struct drm_gem_object gem;
+ u32 placements[3];
+ int pin_count;
+};
+#define gem_to_mga_bo(gobj) container_of((gobj), struct mgag200_bo, gem)
+
+static inline struct mgag200_bo *
+mgag200_bo(struct ttm_buffer_object *bo)
+{
+ return container_of(bo, struct mgag200_bo, bo);
+}
+ /* mga_crtc.c */
+void mga_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
+ u16 blue, int regno);
+void mga_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
+ u16 *blue, int regno);
+
+ /* mgag200_mode.c */
+int mgag200_modeset_init(struct mga_device *mdev);
+void mgag200_modeset_fini(struct mga_device *mdev);
+
+ /* mga_fbdev.c */
+int mgag200_fbdev_init(struct mga_device *mdev);
+void mgag200_fbdev_fini(struct mga_device *mdev);
+
+ /* mgag200_main.c */
+int mgag200_framebuffer_init(struct drm_device *dev,
+ struct mga_framebuffer *mfb,
+ struct drm_mode_fb_cmd2 *mode_cmd,
+ struct drm_gem_object *obj);
+
+
+int mgag200_driver_load(struct drm_device *dev, unsigned long flags);
+int mgag200_driver_unload(struct drm_device *dev);
+int mgag200_gem_create(struct drm_device *dev,
+ u32 size, bool iskernel,
+ struct drm_gem_object **obj);
+int mgag200_gem_init_object(struct drm_gem_object *obj);
+int mgag200_dumb_create(struct drm_file *file,
+ struct drm_device *dev,
+ struct drm_mode_create_dumb *args);
+int mgag200_dumb_destroy(struct drm_file *file,
+ struct drm_device *dev,
+ uint32_t handle);
+void mgag200_gem_free_object(struct drm_gem_object *obj);
+int
+mgag200_dumb_mmap_offset(struct drm_file *file,
+ struct drm_device *dev,
+ uint32_t handle,
+ uint64_t *offset);
+ /* mga_i2c.c */
+struct mga_i2c_chan *mgag200_i2c_create(struct drm_device *dev);
+void mgag200_i2c_destroy(struct mga_i2c_chan *i2c);
+
+#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
+void mgag200_ttm_placement(struct mgag200_bo *bo, int domain);
+
+int mgag200_bo_reserve(struct mgag200_bo *bo, bool no_wait);
+void mgag200_bo_unreserve(struct mgag200_bo *bo);
+int mgag200_bo_create(struct drm_device *dev, int size, int align,
+ uint32_t flags, struct mgag200_bo **pastbo);
+int mgag200_mm_init(struct mga_device *mdev);
+void mgag200_mm_fini(struct mga_device *mdev);
+int mgag200_mmap(struct file *filp, struct vm_area_struct *vma);
+int mgag200_bo_pin(struct mgag200_bo *bo, u32 pl_flag, u64 *gpu_addr);
+int mgag200_bo_unpin(struct mgag200_bo *bo);
+int mgag200_bo_push_sysram(struct mgag200_bo *bo);
+#endif /* __MGAG200_DRV_H__ */
diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c b/drivers/gpu/drm/mgag200/mgag200_fb.c
new file mode 100644
index 000000000000..880d3369760e
--- /dev/null
+++ b/drivers/gpu/drm/mgag200/mgag200_fb.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2010 Matt Turner.
+ * Copyright 2012 Red Hat
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * Authors: Matthew Garrett
+ * Matt Turner
+ * Dave Airlie
+ */
+#include <linux/module.h>
+#include "drmP.h"
+#include "drm.h"
+#include "drm_fb_helper.h"
+
+#include <linux/fb.h>
+
+#include "mgag200_drv.h"
+
+static void mga_dirty_update(struct mga_fbdev *mfbdev,
+ int x, int y, int width, int height)
+{
+ int i;
+ struct drm_gem_object *obj;
+ struct mgag200_bo *bo;
+ int src_offset, dst_offset;
+ int bpp = (mfbdev->mfb.base.bits_per_pixel + 7)/8;
+ int ret;
+ bool unmap = false;
+
+ obj = mfbdev->mfb.obj;
+ bo = gem_to_mga_bo(obj);
+
+ ret = mgag200_bo_reserve(bo, true);
+ if (ret) {
+ DRM_ERROR("failed to reserve fb bo\n");
+ return;
+ }
+
+ if (!bo->kmap.virtual) {
+ ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
+ if (ret) {
+ DRM_ERROR("failed to kmap fb updates\n");
+ mgag200_bo_unreserve(bo);
+ return;
+ }
+ unmap = true;
+ }
+ for (i = y; i < y + height; i++) {
+ /* assume equal stride for now */
+ src_offset = dst_offset = i * mfbdev->mfb.base.pitches[0] + (x * bpp);
+ memcpy_toio(bo->kmap.virtual + src_offset, mfbdev->sysram + src_offset, width * bpp);
+
+ }
+ if (unmap)
+ ttm_bo_kunmap(&bo->kmap);
+
+ mgag200_bo_unreserve(bo);
+}
+
+static void mga_fillrect(struct fb_info *info,
+ const struct fb_fillrect *rect)
+{
+ struct mga_fbdev *mfbdev = info->par;
+ sys_fillrect(info, rect);
+ mga_dirty_update(mfbdev, rect->dx, rect->dy, rect->width,
+ rect->height);
+}
+
+static void mga_copyarea(struct fb_info *info,
+ const struct fb_copyarea *area)
+{
+ struct mga_fbdev *mfbdev = info->par;
+ sys_copyarea(info, area);
+ mga_dirty_update(mfbdev, area->dx, area->dy, area->width,
+ area->height);
+}
+
+static void mga_imageblit(struct fb_info *info,
+ const struct fb_image *image)
+{
+ struct mga_fbdev *mfbdev = info->par;
+ sys_imageblit(info, image);
+ mga_dirty_update(mfbdev, image->dx, image->dy, image->width,
+ image->height);
+}
+
+
+static struct fb_ops mgag200fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = drm_fb_helper_check_var,
+ .fb_set_par = drm_fb_helper_set_par,
+ .fb_fillrect = mga_fillrect,
+ .fb_copyarea = mga_copyarea,
+ .fb_imageblit = mga_imageblit,
+ .fb_pan_display = drm_fb_helper_pan_display,
+ .fb_blank = drm_fb_helper_blank,
+ .fb_setcmap = drm_fb_helper_setcmap,
+};
+
+static int mgag200fb_create_object(struct mga_fbdev *afbdev,
+ struct drm_mode_fb_cmd2 *mode_cmd,
+ struct drm_gem_object **gobj_p)
+{
+ struct drm_device *dev = afbdev->helper.dev;
+ u32 bpp, depth;
+ u32 size;
+ struct drm_gem_object *gobj;
+
+ int ret = 0;
+ drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp);
+
+ size = mode_cmd->pitches[0] * mode_cmd->height;
+ ret = mgag200_gem_create(dev, size, true, &gobj);
+ if (ret)
+ return ret;
+
+ *gobj_p = gobj;
+ return ret;
+}
+
+static int mgag200fb_create(struct mga_fbdev *mfbdev,
+ struct drm_fb_helper_surface_size *sizes)
+{
+ struct drm_device *dev = mfbdev->helper.dev;
+ struct drm_mode_fb_cmd2 mode_cmd;
+ struct mga_device *mdev = dev->dev_private;
+ struct fb_info *info;
+ struct drm_framebuffer *fb;
+ struct drm_gem_object *gobj = NULL;
+ struct device *device = &dev->pdev->dev;
+ struct mgag200_bo *bo;
+ int ret;
+ void *sysram;
+ int size;
+
+ mode_cmd.width = sizes->surface_width;
+ mode_cmd.height = sizes->surface_height;
+ mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7) / 8);
+
+ mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+ sizes->surface_depth);
+ size = mode_cmd.pitches[0] * mode_cmd.height;
+
+ ret = mgag200fb_create_object(mfbdev, &mode_cmd, &gobj);
+ if (ret) {
+ DRM_ERROR("failed to create fbcon backing object %d\n", ret);
+ return ret;
+ }
+ bo = gem_to_mga_bo(gobj);
+
+ sysram = vmalloc(size);
+ if (!sysram)
+ return -ENOMEM;
+
+ info = framebuffer_alloc(0, device);
+ if (info == NULL)
+ return -ENOMEM;
+
+ info->par = mfbdev;
+
+ ret = mgag200_framebuffer_init(dev, &mfbdev->mfb, &mode_cmd, gobj);
+ if (ret)
+ return ret;
+
+ mfbdev->sysram = sysram;
+ mfbdev->size = size;
+
+ fb = &mfbdev->mfb.base;
+
+ /* setup helper */
+ mfbdev->helper.fb = fb;
+ mfbdev->helper.fbdev = info;
+
+ ret = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (ret) {
+ DRM_ERROR("%s: can't allocate color map\n", info->fix.id);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ strcpy(info->fix.id, "mgadrmfb");
+
+ info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
+ info->fbops = &mgag200fb_ops;
+
+ /* setup aperture base/size for vesafb takeover */
+ info->apertures = alloc_apertures(1);
+ if (!info->apertures) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ info->apertures->ranges[0].base = mdev->dev->mode_config.fb_base;
+ info->apertures->ranges[0].size = mdev->mc.vram_size;
+
+ drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
+ drm_fb_helper_fill_var(info, &mfbdev->helper, sizes->fb_width,
+ sizes->fb_height);
+
+ info->screen_base = sysram;
+ info->screen_size = size;
+ info->pixmap.flags = FB_PIXMAP_SYSTEM;
+
+ DRM_DEBUG_KMS("allocated %dx%d\n",
+ fb->width, fb->height);
+ return 0;
+out:
+ return ret;
+}
+
+static int mga_fb_find_or_create_single(struct drm_fb_helper *helper,
+ struct drm_fb_helper_surface_size
+ *sizes)
+{
+ struct mga_fbdev *mfbdev = (struct mga_fbdev *)helper;
+ int new_fb = 0;
+ int ret;
+
+ if (!helper->fb) {
+ ret = mgag200fb_create(mfbdev, sizes);
+ if (ret)
+ return ret;
+ new_fb = 1;
+ }
+ return new_fb;
+}
+
+static int mga_fbdev_destroy(struct drm_device *dev,
+ struct mga_fbdev *mfbdev)
+{
+ struct fb_info *info;
+ struct mga_framebuffer *mfb = &mfbdev->mfb;
+
+ if (mfbdev->helper.fbdev) {
+ info = mfbdev->helper.fbdev;
+
+ unregister_framebuffer(info);
+ if (info->cmap.len)
+ fb_dealloc_cmap(&info->cmap);
+ framebuffer_release(info);
+ }
+
+ if (mfb->obj) {
+ drm_gem_object_unreference_unlocked(mfb->obj);
+ mfb->obj = NULL;
+ }
+ drm_fb_helper_fini(&mfbdev->helper);
+ vfree(mfbdev->sysram);
+ drm_framebuffer_cleanup(&mfb->base);
+
+ return 0;
+}
+
+static struct drm_fb_helper_funcs mga_fb_helper_funcs = {
+ .gamma_set = mga_crtc_fb_gamma_set,
+ .gamma_get = mga_crtc_fb_gamma_get,
+ .fb_probe = mga_fb_find_or_create_single,
+};
+
+int mgag200_fbdev_init(struct mga_device *mdev)
+{
+ struct mga_fbdev *mfbdev;
+ int ret;
+
+ mfbdev = kzalloc(sizeof(struct mga_fbdev), GFP_KERNEL);
+ if (!mfbdev)
+ return -ENOMEM;
+
+ mdev->mfbdev = mfbdev;
+ mfbdev->helper.funcs = &mga_fb_helper_funcs;
+
+ ret = drm_fb_helper_init(mdev->dev, &mfbdev->helper,
+ mdev->num_crtc, MGAG200FB_CONN_LIMIT);
+ if (ret) {
+ kfree(mfbdev);
+ return ret;
+ }
+ drm_fb_helper_single_add_all_connectors(&mfbdev->helper);
+ drm_fb_helper_initial_config(&mfbdev->helper, 32);
+
+ return 0;
+}
+
+void mgag200_fbdev_fini(struct mga_device *mdev)
+{
+ if (!mdev->mfbdev)
+ return;
+
+ mga_fbdev_destroy(mdev->dev, mdev->mfbdev);
+ kfree(mdev->mfbdev);
+ mdev->mfbdev = NULL;
+}
diff --git a/drivers/gpu/drm/mgag200/mgag200_i2c.c b/drivers/gpu/drm/mgag200/mgag200_i2c.c
new file mode 100644
index 000000000000..dd3568a1b6b0
--- /dev/null
+++ b/drivers/gpu/drm/mgag200/mgag200_i2c.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors: Dave Airlie <airlied@redhat.com>
+ */
+#include <linux/export.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include "drmP.h"
+#include "drm.h"
+
+#include "mgag200_drv.h"
+
+static int mga_i2c_read_gpio(struct mga_device *mdev)
+{
+ WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA);
+ return RREG8(DAC_DATA);
+}
+
+static void mga_i2c_set_gpio(struct mga_device *mdev, int mask, int val)
+{
+ int tmp;
+
+ WREG8(DAC_INDEX, MGA1064_GEN_IO_CTL);
+ tmp = (RREG8(DAC_DATA) & mask) | val;
+ WREG_DAC(MGA1064_GEN_IO_CTL, tmp);
+ WREG_DAC(MGA1064_GEN_IO_DATA, 0);
+}
+
+static inline void mga_i2c_set(struct mga_device *mdev, int mask, int state)
+{
+ if (state)
+ state = 0;
+ else
+ state = mask;
+ mga_i2c_set_gpio(mdev, ~mask, state);
+}
+
+static void mga_gpio_setsda(void *data, int state)
+{
+ struct mga_i2c_chan *i2c = data;
+ struct mga_device *mdev = i2c->dev->dev_private;
+ mga_i2c_set(mdev, i2c->data, state);
+}
+
+static void mga_gpio_setscl(void *data, int state)
+{
+ struct mga_i2c_chan *i2c = data;
+ struct mga_device *mdev = i2c->dev->dev_private;
+ mga_i2c_set(mdev, i2c->clock, state);
+}
+
+static int mga_gpio_getsda(void *data)
+{
+ struct mga_i2c_chan *i2c = data;
+ struct mga_device *mdev = i2c->dev->dev_private;
+ return (mga_i2c_read_gpio(mdev) & i2c->data) ? 1 : 0;
+}
+
+static int mga_gpio_getscl(void *data)
+{
+ struct mga_i2c_chan *i2c = data;
+ struct mga_device *mdev = i2c->dev->dev_private;
+ return (mga_i2c_read_gpio(mdev) & i2c->clock) ? 1 : 0;
+}
+
+struct mga_i2c_chan *mgag200_i2c_create(struct drm_device *dev)
+{
+ struct mga_device *mdev = dev->dev_private;
+ struct mga_i2c_chan *i2c;
+ int ret;
+ int data, clock;
+
+ WREG_DAC(MGA1064_GEN_IO_DATA, 0xff);
+ WREG_DAC(MGA1064_GEN_IO_CTL, 0);
+
+ switch (mdev->type) {
+ case G200_SE_A:
+ case G200_SE_B:
+ case G200_EV:
+ case G200_WB:
+ data = 1;
+ clock = 2;
+ break;
+ case G200_EH:
+ case G200_ER:
+ data = 2;
+ clock = 1;
+ break;
+ default:
+ data = 2;
+ clock = 8;
+ break;
+ }
+
+ i2c = kzalloc(sizeof(struct mga_i2c_chan), GFP_KERNEL);
+ if (!i2c)
+ return NULL;
+
+ i2c->data = data;
+ i2c->clock = clock;
+ i2c->adapter.owner = THIS_MODULE;
+ i2c->adapter.class = I2C_CLASS_DDC;
+ i2c->adapter.dev.parent = &dev->pdev->dev;
+ i2c->dev = dev;
+ i2c_set_adapdata(&i2c->adapter, i2c);
+ snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), "mga i2c");
+
+ i2c->adapter.algo_data = &i2c->bit;
+
+ i2c->bit.udelay = 10;
+ i2c->bit.timeout = 2;
+ i2c->bit.data = i2c;
+ i2c->bit.setsda = mga_gpio_setsda;
+ i2c->bit.setscl = mga_gpio_setscl;
+ i2c->bit.getsda = mga_gpio_getsda;
+ i2c->bit.getscl = mga_gpio_getscl;
+
+ ret = i2c_bit_add_bus(&i2c->adapter);
+ if (ret) {
+ kfree(i2c);
+ i2c = NULL;
+ }
+ return i2c;
+}
+
+void mgag200_i2c_destroy(struct mga_i2c_chan *i2c)
+{
+ if (!i2c)
+ return;
+ i2c_del_adapter(&i2c->adapter);
+ kfree(i2c);
+}
+
diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c
new file mode 100644
index 000000000000..636a81cd2f37
--- /dev/null
+++ b/drivers/gpu/drm/mgag200/mgag200_main.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright 2010 Matt Turner.
+ * Copyright 2012 Red Hat
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * Authors: Matthew Garrett
+ * Matt Turner
+ * Dave Airlie
+ */
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc_helper.h"
+#include "mgag200_drv.h"
+
+static void mga_user_framebuffer_destroy(struct drm_framebuffer *fb)
+{
+ struct mga_framebuffer *mga_fb = to_mga_framebuffer(fb);
+ if (mga_fb->obj)
+ drm_gem_object_unreference_unlocked(mga_fb->obj);
+ drm_framebuffer_cleanup(fb);
+ kfree(fb);
+}
+
+static int mga_user_framebuffer_create_handle(struct drm_framebuffer *fb,
+ struct drm_file *file_priv,
+ unsigned int *handle)
+{
+ return 0;
+}
+
+static const struct drm_framebuffer_funcs mga_fb_funcs = {
+ .destroy = mga_user_framebuffer_destroy,
+ .create_handle = mga_user_framebuffer_create_handle,
+};
+
+int mgag200_framebuffer_init(struct drm_device *dev,
+ struct mga_framebuffer *gfb,
+ struct drm_mode_fb_cmd2 *mode_cmd,
+ struct drm_gem_object *obj)
+{
+ int ret = drm_framebuffer_init(dev, &gfb->base, &mga_fb_funcs);
+ if (ret) {
+ DRM_ERROR("drm_framebuffer_init failed: %d\n", ret);
+ return ret;
+ }
+ drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd);
+ gfb->obj = obj;
+ return 0;
+}
+
+static struct drm_framebuffer *
+mgag200_user_framebuffer_create(struct drm_device *dev,
+ struct drm_file *filp,
+ struct drm_mode_fb_cmd2 *mode_cmd)
+{
+ struct drm_gem_object *obj;
+ struct mga_framebuffer *mga_fb;
+ int ret;
+
+ obj = drm_gem_object_lookup(dev, filp, mode_cmd->handles[0]);
+ if (obj == NULL)
+ return ERR_PTR(-ENOENT);
+
+ mga_fb = kzalloc(sizeof(*mga_fb), GFP_KERNEL);
+ if (!mga_fb) {
+ drm_gem_object_unreference_unlocked(obj);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ ret = mgag200_framebuffer_init(dev, mga_fb, mode_cmd, obj);
+ if (ret) {
+ drm_gem_object_unreference_unlocked(obj);
+ kfree(mga_fb);
+ return ERR_PTR(ret);
+ }
+ return &mga_fb->base;
+}
+
+static const struct drm_mode_config_funcs mga_mode_funcs = {
+ .fb_create = mgag200_user_framebuffer_create,
+};
+
+/* Unmap the framebuffer from the core and release the memory */
+static void mga_vram_fini(struct mga_device *mdev)
+{
+ pci_iounmap(mdev->dev->pdev, mdev->rmmio);
+ mdev->rmmio = NULL;
+ if (mdev->mc.vram_base)
+ release_mem_region(mdev->mc.vram_base, mdev->mc.vram_window);
+}
+
+static int mga_probe_vram(struct mga_device *mdev, void __iomem *mem)
+{
+ int offset;
+ int orig;
+ int test1, test2;
+ int orig1, orig2;
+
+ /* Probe */
+ orig = ioread16(mem);
+ iowrite16(0, mem);
+
+ for (offset = 0x100000; offset < mdev->mc.vram_window; offset += 0x4000) {
+ orig1 = ioread8(mem + offset);
+ orig2 = ioread8(mem + offset + 0x100);
+
+ iowrite16(0xaa55, mem + offset);
+ iowrite16(0xaa55, mem + offset + 0x100);
+
+ test1 = ioread16(mem + offset);
+ test2 = ioread16(mem);
+
+ iowrite16(orig1, mem + offset);
+ iowrite16(orig2, mem + offset + 0x100);
+
+ if (test1 != 0xaa55) {
+ break;
+ }
+
+ if (test2) {
+ break;
+ }
+ }
+
+ iowrite16(orig, mem);
+ return offset - 65536;
+}
+
+/* Map the framebuffer from the card and configure the core */
+static int mga_vram_init(struct mga_device *mdev)
+{
+ void __iomem *mem;
+ struct apertures_struct *aper = alloc_apertures(1);
+
+ /* BAR 0 is VRAM */
+ mdev->mc.vram_base = pci_resource_start(mdev->dev->pdev, 0);
+ mdev->mc.vram_window = pci_resource_len(mdev->dev->pdev, 0);
+
+ aper->ranges[0].base = mdev->mc.vram_base;
+ aper->ranges[0].size = mdev->mc.vram_window;
+ aper->count = 1;
+
+ remove_conflicting_framebuffers(aper, "mgafb", true);
+
+ if (!request_mem_region(mdev->mc.vram_base, mdev->mc.vram_window,
+ "mgadrmfb_vram")) {
+ DRM_ERROR("can't reserve VRAM\n");
+ return -ENXIO;
+ }
+
+ mem = pci_iomap(mdev->dev->pdev, 0, 0);
+
+ mdev->mc.vram_size = mga_probe_vram(mdev, mem);
+
+ pci_iounmap(mdev->dev->pdev, mem);
+
+ return 0;
+}
+
+static int mgag200_device_init(struct drm_device *dev,
+ uint32_t flags)
+{
+ struct mga_device *mdev = dev->dev_private;
+ int ret, option;
+
+ mdev->type = flags;
+
+ /* Hardcode the number of CRTCs to 1 */
+ mdev->num_crtc = 1;
+
+ pci_read_config_dword(dev->pdev, PCI_MGA_OPTION, &option);
+ mdev->has_sdram = !(option & (1 << 14));
+
+ /* BAR 0 is the framebuffer, BAR 1 contains registers */
+ mdev->rmmio_base = pci_resource_start(mdev->dev->pdev, 1);
+ mdev->rmmio_size = pci_resource_len(mdev->dev->pdev, 1);
+
+ if (!request_mem_region(mdev->rmmio_base, mdev->rmmio_size,
+ "mgadrmfb_mmio")) {
+ DRM_ERROR("can't reserve mmio registers\n");
+ return -ENOMEM;
+ }
+
+ mdev->rmmio = pci_iomap(dev->pdev, 1, 0);
+ if (mdev->rmmio == NULL)
+ return -ENOMEM;
+
+ /* stash G200 SE model number for later use */
+ if (IS_G200_SE(mdev))
+ mdev->reg_1e24 = RREG32(0x1e24);
+
+ ret = mga_vram_init(mdev);
+ if (ret) {
+ release_mem_region(mdev->rmmio_base, mdev->rmmio_size);
+ return ret;
+ }
+
+ mdev->bpp_shifts[0] = 0;
+ mdev->bpp_shifts[1] = 1;
+ mdev->bpp_shifts[2] = 0;
+ mdev->bpp_shifts[3] = 2;
+ return 0;
+}
+
+void mgag200_device_fini(struct mga_device *mdev)
+{
+ release_mem_region(mdev->rmmio_base, mdev->rmmio_size);
+ mga_vram_fini(mdev);
+}
+
+/*
+ * Functions here will be called by the core once it's bound the driver to
+ * a PCI device
+ */
+
+
+int mgag200_driver_load(struct drm_device *dev, unsigned long flags)
+{
+ struct mga_device *mdev;
+ int r;
+
+ mdev = kzalloc(sizeof(struct mga_device), GFP_KERNEL);
+ if (mdev == NULL)
+ return -ENOMEM;
+ dev->dev_private = (void *)mdev;
+ mdev->dev = dev;
+
+ r = mgag200_device_init(dev, flags);
+ if (r) {
+ dev_err(&dev->pdev->dev, "Fatal error during GPU init: %d\n", r);
+ goto out;
+ }
+ r = mgag200_mm_init(mdev);
+ if (r)
+ goto out;
+
+ drm_mode_config_init(dev);
+ dev->mode_config.funcs = (void *)&mga_mode_funcs;
+ dev->mode_config.min_width = 0;
+ dev->mode_config.min_height = 0;
+ dev->mode_config.preferred_depth = 24;
+ dev->mode_config.prefer_shadow = 1;
+
+ r = mgag200_modeset_init(mdev);
+ if (r)
+ dev_err(&dev->pdev->dev, "Fatal error during modeset init: %d\n", r);
+out:
+ if (r)
+ mgag200_driver_unload(dev);
+ return r;
+}
+
+int mgag200_driver_unload(struct drm_device *dev)
+{
+ struct mga_device *mdev = dev->dev_private;
+
+ if (mdev == NULL)
+ return 0;
+ mgag200_modeset_fini(mdev);
+ mgag200_fbdev_fini(mdev);
+ drm_mode_config_cleanup(dev);
+ mgag200_mm_fini(mdev);
+ mgag200_device_fini(mdev);
+ kfree(mdev);
+ dev->dev_private = NULL;
+ return 0;
+}
+
+int mgag200_gem_create(struct drm_device *dev,
+ u32 size, bool iskernel,
+ struct drm_gem_object **obj)
+{
+ struct mgag200_bo *astbo;
+ int ret;
+
+ *obj = NULL;
+
+ size = roundup(size, PAGE_SIZE);
+ if (size == 0)
+ return -EINVAL;
+
+ ret = mgag200_bo_create(dev, size, 0, 0, &astbo);
+ if (ret) {
+ if (ret != -ERESTARTSYS)
+ DRM_ERROR("failed to allocate GEM object\n");
+ return ret;
+ }
+ *obj = &astbo->gem;
+ return 0;
+}
+
+int mgag200_dumb_create(struct drm_file *file,
+ struct drm_device *dev,
+ struct drm_mode_create_dumb *args)
+{
+ int ret;
+ struct drm_gem_object *gobj;
+ u32 handle;
+
+ args->pitch = args->width * ((args->bpp + 7) / 8);
+ args->size = args->pitch * args->height;
+
+ ret = mgag200_gem_create(dev, args->size, false,
+ &gobj);
+ if (ret)
+ return ret;
+
+ ret = drm_gem_handle_create(file, gobj, &handle);
+ drm_gem_object_unreference_unlocked(gobj);
+ if (ret)
+ return ret;
+
+ args->handle = handle;
+ return 0;
+}
+
+int mgag200_dumb_destroy(struct drm_file *file,
+ struct drm_device *dev,
+ uint32_t handle)
+{
+ return drm_gem_handle_delete(file, handle);
+}
+
+int mgag200_gem_init_object(struct drm_gem_object *obj)
+{
+ BUG();
+ return 0;
+}
+
+void mgag200_bo_unref(struct mgag200_bo **bo)
+{
+ struct ttm_buffer_object *tbo;
+
+ if ((*bo) == NULL)
+ return;
+
+ tbo = &((*bo)->bo);
+ ttm_bo_unref(&tbo);
+ if (tbo == NULL)
+ *bo = NULL;
+
+}
+
+void mgag200_gem_free_object(struct drm_gem_object *obj)
+{
+ struct mgag200_bo *mgag200_bo = gem_to_mga_bo(obj);
+
+ if (!mgag200_bo)
+ return;
+ mgag200_bo_unref(&mgag200_bo);
+}
+
+
+static inline u64 mgag200_bo_mmap_offset(struct mgag200_bo *bo)
+{
+ return bo->bo.addr_space_offset;
+}
+
+int
+mgag200_dumb_mmap_offset(struct drm_file *file,
+ struct drm_device *dev,
+ uint32_t handle,
+ uint64_t *offset)
+{
+ struct drm_gem_object *obj;
+ int ret;
+ struct mgag200_bo *bo;
+
+ mutex_lock(&dev->struct_mutex);
+ obj = drm_gem_object_lookup(dev, file, handle);
+ if (obj == NULL) {
+ ret = -ENOENT;
+ goto out_unlock;
+ }
+
+ bo = gem_to_mga_bo(obj);
+ *offset = mgag200_bo_mmap_offset(bo);
+
+ drm_gem_object_unreference(obj);
+ ret = 0;
+out_unlock:
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+
+}
diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c
new file mode 100644
index 000000000000..d303061b251e
--- /dev/null
+++ b/drivers/gpu/drm/mgag200/mgag200_mode.c
@@ -0,0 +1,1533 @@
+/*
+ * Copyright 2010 Matt Turner.
+ * Copyright 2012 Red Hat
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * Authors: Matthew Garrett
+ * Matt Turner
+ * Dave Airlie
+ */
+
+#include <linux/delay.h>
+
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc_helper.h"
+
+#include "mgag200_drv.h"
+
+#define MGAG200_LUT_SIZE 256
+
+/*
+ * This file contains setup code for the CRTC.
+ */
+
+static void mga_crtc_load_lut(struct drm_crtc *crtc)
+{
+ struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct mga_device *mdev = dev->dev_private;
+ int i;
+
+ if (!crtc->enabled)
+ return;
+
+ WREG8(DAC_INDEX + MGA1064_INDEX, 0);
+
+ for (i = 0; i < MGAG200_LUT_SIZE; i++) {
+ /* VGA registers */
+ WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_r[i]);
+ WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_g[i]);
+ WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_b[i]);
+ }
+}
+
+static inline void mga_wait_vsync(struct mga_device *mdev)
+{
+ unsigned int count = 0;
+ unsigned int status = 0;
+
+ do {
+ status = RREG32(MGAREG_Status);
+ count++;
+ } while ((status & 0x08) && (count < 250000));
+ count = 0;
+ status = 0;
+ do {
+ status = RREG32(MGAREG_Status);
+ count++;
+ } while (!(status & 0x08) && (count < 250000));
+}
+
+static inline void mga_wait_busy(struct mga_device *mdev)
+{
+ unsigned int count = 0;
+ unsigned int status = 0;
+ do {
+ status = RREG8(MGAREG_Status + 2);
+ count++;
+ } while ((status & 0x01) && (count < 500000));
+}
+
+/*
+ * The core passes the desired mode to the CRTC code to see whether any
+ * CRTC-specific modifications need to be made to it. We're in a position
+ * to just pass that straight through, so this does nothing
+ */
+static bool mga_crtc_mode_fixup(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static int mga_g200se_set_plls(struct mga_device *mdev, long clock)
+{
+ unsigned int vcomax, vcomin, pllreffreq;
+ unsigned int delta, tmpdelta, permitteddelta;
+ unsigned int testp, testm, testn;
+ unsigned int p, m, n;
+ unsigned int computed;
+
+ m = n = p = 0;
+ vcomax = 320000;
+ vcomin = 160000;
+ pllreffreq = 25000;
+
+ delta = 0xffffffff;
+ permitteddelta = clock * 5 / 1000;
+
+ for (testp = 8; testp > 0; testp /= 2) {
+ if (clock * testp > vcomax)
+ continue;
+ if (clock * testp < vcomin)
+ continue;
+
+ for (testn = 17; testn < 256; testn++) {
+ for (testm = 1; testm < 32; testm++) {
+ computed = (pllreffreq * testn) /
+ (testm * testp);
+ if (computed > clock)
+ tmpdelta = computed - clock;
+ else
+ tmpdelta = clock - computed;
+ if (tmpdelta < delta) {
+ delta = tmpdelta;
+ m = testm - 1;
+ n = testn - 1;
+ p = testp - 1;
+ }
+ }
+ }
+ }
+
+ if (delta > permitteddelta) {
+ printk(KERN_WARNING "PLL delta too large\n");
+ return 1;
+ }
+
+ WREG_DAC(MGA1064_PIX_PLLC_M, m);
+ WREG_DAC(MGA1064_PIX_PLLC_N, n);
+ WREG_DAC(MGA1064_PIX_PLLC_P, p);
+ return 0;
+}
+
+static int mga_g200wb_set_plls(struct mga_device *mdev, long clock)
+{
+ unsigned int vcomax, vcomin, pllreffreq;
+ unsigned int delta, tmpdelta, permitteddelta;
+ unsigned int testp, testm, testn;
+ unsigned int p, m, n;
+ unsigned int computed;
+ int i, j, tmpcount, vcount;
+ bool pll_locked = false;
+ u8 tmp;
+
+ m = n = p = 0;
+ vcomax = 550000;
+ vcomin = 150000;
+ pllreffreq = 48000;
+
+ delta = 0xffffffff;
+ permitteddelta = clock * 5 / 1000;
+
+ for (testp = 1; testp < 9; testp++) {
+ if (clock * testp > vcomax)
+ continue;
+ if (clock * testp < vcomin)
+ continue;
+
+ for (testm = 1; testm < 17; testm++) {
+ for (testn = 1; testn < 151; testn++) {
+ computed = (pllreffreq * testn) /
+ (testm * testp);
+ if (computed > clock)
+ tmpdelta = computed - clock;
+ else
+ tmpdelta = clock - computed;
+ if (tmpdelta < delta) {
+ delta = tmpdelta;
+ n = testn - 1;
+ m = (testm - 1) | ((n >> 1) & 0x80);
+ p = testp - 1;
+ }
+ }
+ }
+ }
+
+ for (i = 0; i <= 32 && pll_locked == false; i++) {
+ if (i > 0) {
+ WREG8(MGAREG_CRTC_INDEX, 0x1e);
+ tmp = RREG8(MGAREG_CRTC_DATA);
+ if (tmp < 0xff)
+ WREG8(MGAREG_CRTC_DATA, tmp+1);
+ }
+
+ /* set pixclkdis to 1 */
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
+ WREG_DAC(MGA1064_PIX_CLK_CTL_CLK_DIS, tmp);
+
+ WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
+ tmp = RREG8(DAC_DATA);
+ tmp |= MGA1064_REMHEADCTL_CLKDIS;
+ WREG_DAC(MGA1064_REMHEADCTL, tmp);
+
+ /* select PLL Set C */
+ tmp = RREG8(MGAREG_MEM_MISC_READ);
+ tmp |= 0x3 << 2;
+ WREG8(MGAREG_MEM_MISC_WRITE, tmp);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN | 0x80;
+ WREG_DAC(MGA1064_PIX_CLK_CTL, tmp);
+
+ udelay(500);
+
+ /* reset the PLL */
+ WREG8(DAC_INDEX, MGA1064_VREF_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~0x04;
+ WREG_DAC(MGA1064_VREF_CTL, tmp);
+
+ udelay(50);
+
+ /* program pixel pll register */
+ WREG_DAC(MGA1064_WB_PIX_PLLC_N, n);
+ WREG_DAC(MGA1064_WB_PIX_PLLC_M, m);
+ WREG_DAC(MGA1064_WB_PIX_PLLC_P, p);
+
+ udelay(50);
+
+ /* turn pll on */
+ WREG8(DAC_INDEX, MGA1064_VREF_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp |= 0x04;
+ WREG_DAC(MGA1064_VREF_CTL, tmp);
+
+ udelay(500);
+
+ /* select the pixel pll */
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
+ tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
+ WREG_DAC(MGA1064_PIX_CLK_CTL, tmp);
+
+ WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~MGA1064_REMHEADCTL_CLKSL_MSK;
+ tmp |= MGA1064_REMHEADCTL_CLKSL_PLL;
+ WREG_DAC(MGA1064_REMHEADCTL, tmp);
+
+ /* reset dotclock rate bit */
+ WREG8(MGAREG_SEQ_INDEX, 1);
+ tmp = RREG8(MGAREG_SEQ_DATA);
+ tmp &= ~0x8;
+ WREG8(MGAREG_SEQ_DATA, tmp);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
+ WREG_DAC(MGA1064_PIX_CLK_CTL, tmp);
+
+ vcount = RREG8(MGAREG_VCOUNT);
+
+ for (j = 0; j < 30 && pll_locked == false; j++) {
+ tmpcount = RREG8(MGAREG_VCOUNT);
+ if (tmpcount < vcount)
+ vcount = 0;
+ if ((tmpcount - vcount) > 2)
+ pll_locked = true;
+ else
+ udelay(5);
+ }
+ }
+ WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~MGA1064_REMHEADCTL_CLKDIS;
+ WREG_DAC(MGA1064_REMHEADCTL, tmp);
+ return 0;
+}
+
+static int mga_g200ev_set_plls(struct mga_device *mdev, long clock)
+{
+ unsigned int vcomax, vcomin, pllreffreq;
+ unsigned int delta, tmpdelta, permitteddelta;
+ unsigned int testp, testm, testn;
+ unsigned int p, m, n;
+ unsigned int computed;
+ u8 tmp;
+
+ m = n = p = 0;
+ vcomax = 550000;
+ vcomin = 150000;
+ pllreffreq = 50000;
+
+ delta = 0xffffffff;
+ permitteddelta = clock * 5 / 1000;
+
+ for (testp = 16; testp > 0; testp--) {
+ if (clock * testp > vcomax)
+ continue;
+ if (clock * testp < vcomin)
+ continue;
+
+ for (testn = 1; testn < 257; testn++) {
+ for (testm = 1; testm < 17; testm++) {
+ computed = (pllreffreq * testn) /
+ (testm * testp);
+ if (computed > clock)
+ tmpdelta = computed - clock;
+ else
+ tmpdelta = clock - computed;
+ if (tmpdelta < delta) {
+ delta = tmpdelta;
+ n = testn - 1;
+ m = testm - 1;
+ p = testp - 1;
+ }
+ }
+ }
+ }
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
+ WREG_DAC(MGA1064_PIX_CLK_CTL_CLK_DIS, tmp);
+
+ tmp = RREG8(MGAREG_MEM_MISC_READ);
+ tmp |= 0x3 << 2;
+ WREG8(MGAREG_MEM_MISC_WRITE, tmp);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT);
+ tmp = RREG8(DAC_DATA);
+ WREG_DAC(MGA1064_PIX_PLL_STAT, tmp & ~0x40);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
+ WREG_DAC(MGA1064_PIX_CLK_CTL, tmp);
+
+ WREG_DAC(MGA1064_EV_PIX_PLLC_M, m);
+ WREG_DAC(MGA1064_EV_PIX_PLLC_N, n);
+ WREG_DAC(MGA1064_EV_PIX_PLLC_P, p);
+
+ udelay(50);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
+ WREG_DAC(MGA1064_PIX_CLK_CTL, tmp);
+
+ udelay(500);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
+ tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
+ WREG_DAC(MGA1064_PIX_CLK_CTL, tmp);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_PLL_STAT);
+ tmp = RREG8(DAC_DATA);
+ WREG_DAC(MGA1064_PIX_PLL_STAT, tmp | 0x40);
+
+ tmp = RREG8(MGAREG_MEM_MISC_READ);
+ tmp |= (0x3 << 2);
+ WREG8(MGAREG_MEM_MISC_WRITE, tmp);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
+ WREG_DAC(MGA1064_PIX_CLK_CTL, tmp);
+
+ return 0;
+}
+
+static int mga_g200eh_set_plls(struct mga_device *mdev, long clock)
+{
+ unsigned int vcomax, vcomin, pllreffreq;
+ unsigned int delta, tmpdelta, permitteddelta;
+ unsigned int testp, testm, testn;
+ unsigned int p, m, n;
+ unsigned int computed;
+ int i, j, tmpcount, vcount;
+ u8 tmp;
+ bool pll_locked = false;
+
+ m = n = p = 0;
+ vcomax = 800000;
+ vcomin = 400000;
+ pllreffreq = 3333;
+
+ delta = 0xffffffff;
+ permitteddelta = clock * 5 / 1000;
+
+ for (testp = 16; testp > 0; testp--) {
+ if (clock * testp > vcomax)
+ continue;
+ if (clock * testp < vcomin)
+ continue;
+
+ for (testm = 1; testm < 33; testm++) {
+ for (testn = 1; testn < 257; testn++) {
+ computed = (pllreffreq * testn) /
+ (testm * testp);
+ if (computed > clock)
+ tmpdelta = computed - clock;
+ else
+ tmpdelta = clock - computed;
+ if (tmpdelta < delta) {
+ delta = tmpdelta;
+ n = testn - 1;
+ m = (testm - 1) | ((n >> 1) & 0x80);
+ p = testp - 1;
+ }
+ if ((clock * testp) >= 600000)
+ p |= 80;
+ }
+ }
+ }
+ for (i = 0; i <= 32 && pll_locked == false; i++) {
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
+ WREG_DAC(MGA1064_PIX_CLK_CTL_CLK_DIS, tmp);
+
+ tmp = RREG8(MGAREG_MEM_MISC_READ);
+ tmp |= 0x3 << 2;
+ WREG8(MGAREG_MEM_MISC_WRITE, tmp);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
+ WREG_DAC(MGA1064_PIX_CLK_CTL, tmp);
+
+ udelay(500);
+
+ WREG_DAC(MGA1064_EH_PIX_PLLC_M, m);
+ WREG_DAC(MGA1064_EH_PIX_PLLC_N, n);
+ WREG_DAC(MGA1064_EH_PIX_PLLC_P, p);
+
+ udelay(500);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~MGA1064_PIX_CLK_CTL_SEL_MSK;
+ tmp |= MGA1064_PIX_CLK_CTL_SEL_PLL;
+ WREG_DAC(MGA1064_PIX_CLK_CTL, tmp);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
+ tmp &= ~MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
+ WREG_DAC(MGA1064_PIX_CLK_CTL, tmp);
+
+ vcount = RREG8(MGAREG_VCOUNT);
+
+ for (j = 0; j < 30 && pll_locked == false; j++) {
+ tmpcount = RREG8(MGAREG_VCOUNT);
+ if (tmpcount < vcount)
+ vcount = 0;
+ if ((tmpcount - vcount) > 2)
+ pll_locked = true;
+ else
+ udelay(5);
+ }
+ }
+
+ return 0;
+}
+
+static int mga_g200er_set_plls(struct mga_device *mdev, long clock)
+{
+ unsigned int vcomax, vcomin, pllreffreq;
+ unsigned int delta, tmpdelta;
+ unsigned int testr, testn, testm, testo;
+ unsigned int p, m, n;
+ unsigned int computed;
+ int tmp;
+
+ m = n = p = 0;
+ vcomax = 1488000;
+ vcomin = 1056000;
+ pllreffreq = 48000;
+
+ delta = 0xffffffff;
+
+ for (testr = 0; testr < 4; testr++) {
+ if (delta == 0)
+ break;
+ for (testn = 5; testn < 129; testn++) {
+ if (delta == 0)
+ break;
+ for (testm = 3; testm >= 0; testm--) {
+ if (delta == 0)
+ break;
+ for (testo = 5; testo < 33; testo++) {
+ computed = pllreffreq * (testn + 1) /
+ (testr + 1);
+ if (computed < vcomin)
+ continue;
+ if (computed > vcomax)
+ continue;
+ if (computed > clock)
+ tmpdelta = computed - clock;
+ else
+ tmpdelta = clock - computed;
+ if (tmpdelta < delta) {
+ delta = tmpdelta;
+ m = testm | (testo << 3);
+ n = testn;
+ p = testr | (testr << 3);
+ }
+ }
+ }
+ }
+ }
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp |= MGA1064_PIX_CLK_CTL_CLK_DIS;
+ WREG_DAC(MGA1064_PIX_CLK_CTL_CLK_DIS, tmp);
+
+ WREG8(DAC_INDEX, MGA1064_REMHEADCTL);
+ tmp = RREG8(DAC_DATA);
+ tmp |= MGA1064_REMHEADCTL_CLKDIS;
+ WREG_DAC(MGA1064_REMHEADCTL, tmp);
+
+ tmp = RREG8(MGAREG_MEM_MISC_READ);
+ tmp |= (0x3<<2) | 0xc0;
+ WREG8(MGAREG_MEM_MISC_WRITE, tmp);
+
+ WREG8(DAC_INDEX, MGA1064_PIX_CLK_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~MGA1064_PIX_CLK_CTL_CLK_DIS;
+ tmp |= MGA1064_PIX_CLK_CTL_CLK_POW_DOWN;
+ WREG_DAC(MGA1064_PIX_CLK_CTL, tmp);
+
+ udelay(500);
+
+ WREG_DAC(MGA1064_ER_PIX_PLLC_N, n);
+ WREG_DAC(MGA1064_ER_PIX_PLLC_M, m);
+ WREG_DAC(MGA1064_ER_PIX_PLLC_P, p);
+
+ udelay(50);
+
+ return 0;
+}
+
+static int mga_crtc_set_plls(struct mga_device *mdev, long clock)
+{
+ switch(mdev->type) {
+ case G200_SE_A:
+ case G200_SE_B:
+ return mga_g200se_set_plls(mdev, clock);
+ break;
+ case G200_WB:
+ return mga_g200wb_set_plls(mdev, clock);
+ break;
+ case G200_EV:
+ return mga_g200ev_set_plls(mdev, clock);
+ break;
+ case G200_EH:
+ return mga_g200eh_set_plls(mdev, clock);
+ break;
+ case G200_ER:
+ return mga_g200er_set_plls(mdev, clock);
+ break;
+ }
+ return 0;
+}
+
+static void mga_g200wb_prepare(struct drm_crtc *crtc)
+{
+ struct mga_device *mdev = crtc->dev->dev_private;
+ u8 tmp;
+ int iter_max;
+
+ /* 1- The first step is to warn the BMC of an upcoming mode change.
+ * We are putting the misc<0> to output.*/
+
+ WREG8(DAC_INDEX, MGA1064_GEN_IO_CTL);
+ tmp = RREG8(DAC_DATA);
+ tmp |= 0x10;
+ WREG_DAC(MGA1064_GEN_IO_CTL, tmp);
+
+ /* we are putting a 1 on the misc<0> line */
+ WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA);
+ tmp = RREG8(DAC_DATA);
+ tmp |= 0x10;
+ WREG_DAC(MGA1064_GEN_IO_DATA, tmp);
+
+ /* 2- Second step to mask and further scan request
+ * This will be done by asserting the remfreqmsk bit (XSPAREREG<7>)
+ */
+ WREG8(DAC_INDEX, MGA1064_SPAREREG);
+ tmp = RREG8(DAC_DATA);
+ tmp |= 0x80;
+ WREG_DAC(MGA1064_SPAREREG, tmp);
+
+ /* 3a- the third step is to verifu if there is an active scan
+ * We are searching for a 0 on remhsyncsts <XSPAREREG<0>)
+ */
+ iter_max = 300;
+ while (!(tmp & 0x1) && iter_max) {
+ WREG8(DAC_INDEX, MGA1064_SPAREREG);
+ tmp = RREG8(DAC_DATA);
+ udelay(1000);
+ iter_max--;
+ }
+
+ /* 3b- this step occurs only if the remove is actually scanning
+ * we are waiting for the end of the frame which is a 1 on
+ * remvsyncsts (XSPAREREG<1>)
+ */
+ if (iter_max) {
+ iter_max = 300;
+ while ((tmp & 0x2) && iter_max) {
+ WREG8(DAC_INDEX, MGA1064_SPAREREG);
+ tmp = RREG8(DAC_DATA);
+ udelay(1000);
+ iter_max--;
+ }
+ }
+}
+
+static void mga_g200wb_commit(struct drm_crtc *crtc)
+{
+ u8 tmp;
+ struct mga_device *mdev = crtc->dev->dev_private;
+
+ /* 1- The first step is to ensure that the vrsten and hrsten are set */
+ WREG8(MGAREG_CRTCEXT_INDEX, 1);
+ tmp = RREG8(MGAREG_CRTCEXT_DATA);
+ WREG8(MGAREG_CRTCEXT_DATA, tmp | 0x88);
+
+ /* 2- second step is to assert the rstlvl2 */
+ WREG8(DAC_INDEX, MGA1064_REMHEADCTL2);
+ tmp = RREG8(DAC_DATA);
+ tmp |= 0x8;
+ WREG8(DAC_DATA, tmp);
+
+ /* wait 10 us */
+ udelay(10);
+
+ /* 3- deassert rstlvl2 */
+ tmp &= ~0x08;
+ WREG8(DAC_INDEX, MGA1064_REMHEADCTL2);
+ WREG8(DAC_DATA, tmp);
+
+ /* 4- remove mask of scan request */
+ WREG8(DAC_INDEX, MGA1064_SPAREREG);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~0x80;
+ WREG8(DAC_DATA, tmp);
+
+ /* 5- put back a 0 on the misc<0> line */
+ WREG8(DAC_INDEX, MGA1064_GEN_IO_DATA);
+ tmp = RREG8(DAC_DATA);
+ tmp &= ~0x10;
+ WREG_DAC(MGA1064_GEN_IO_DATA, tmp);
+}
+
+
+void mga_set_start_address(struct drm_crtc *crtc, unsigned offset)
+{
+ struct mga_device *mdev = crtc->dev->dev_private;
+ u32 addr;
+ int count;
+
+ while (RREG8(0x1fda) & 0x08);
+ while (!(RREG8(0x1fda) & 0x08));
+
+ count = RREG8(MGAREG_VCOUNT) + 2;
+ while (RREG8(MGAREG_VCOUNT) < count);
+
+ addr = offset >> 2;
+ WREG_CRT(0x0d, (u8)(addr & 0xff));
+ WREG_CRT(0x0c, (u8)(addr >> 8) & 0xff);
+ WREG_CRT(0xaf, (u8)(addr >> 16) & 0xf);
+}
+
+
+/* ast is different - we will force move buffers out of VRAM */
+static int mga_crtc_do_set_base(struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ int x, int y, int atomic)
+{
+ struct mga_device *mdev = crtc->dev->dev_private;
+ struct drm_gem_object *obj;
+ struct mga_framebuffer *mga_fb;
+ struct mgag200_bo *bo;
+ int ret;
+ u64 gpu_addr;
+
+ /* push the previous fb to system ram */
+ if (!atomic && fb) {
+ mga_fb = to_mga_framebuffer(fb);
+ obj = mga_fb->obj;
+ bo = gem_to_mga_bo(obj);
+ ret = mgag200_bo_reserve(bo, false);
+ if (ret)
+ return ret;
+ mgag200_bo_push_sysram(bo);
+ mgag200_bo_unreserve(bo);
+ }
+
+ mga_fb = to_mga_framebuffer(crtc->fb);
+ obj = mga_fb->obj;
+ bo = gem_to_mga_bo(obj);
+
+ ret = mgag200_bo_reserve(bo, false);
+ if (ret)
+ return ret;
+
+ ret = mgag200_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
+ if (ret) {
+ mgag200_bo_unreserve(bo);
+ return ret;
+ }
+
+ if (&mdev->mfbdev->mfb == mga_fb) {
+ /* if pushing console in kmap it */
+ ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
+ if (ret)
+ DRM_ERROR("failed to kmap fbcon\n");
+
+ }
+ mgag200_bo_unreserve(bo);
+
+ DRM_INFO("mga base %llx\n", gpu_addr);
+
+ mga_set_start_address(crtc, (u32)gpu_addr);
+
+ return 0;
+}
+
+static int mga_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+ struct drm_framebuffer *old_fb)
+{
+ return mga_crtc_do_set_base(crtc, old_fb, x, y, 0);
+}
+
+static int mga_crtc_mode_set(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode,
+ int x, int y, struct drm_framebuffer *old_fb)
+{
+ struct drm_device *dev = crtc->dev;
+ struct mga_device *mdev = dev->dev_private;
+ int hdisplay, hsyncstart, hsyncend, htotal;
+ int vdisplay, vsyncstart, vsyncend, vtotal;
+ int pitch;
+ int option = 0, option2 = 0;
+ int i;
+ unsigned char misc = 0;
+ unsigned char ext_vga[6];
+ unsigned char ext_vga_index24;
+ unsigned char dac_index90 = 0;
+ u8 bppshift;
+
+ static unsigned char dacvalue[] = {
+ /* 0x00: */ 0, 0, 0, 0, 0, 0, 0x00, 0,
+ /* 0x08: */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x10: */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x18: */ 0x00, 0, 0xC9, 0xFF, 0xBF, 0x20, 0x1F, 0x20,
+ /* 0x20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ /* 0x28: */ 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x40,
+ /* 0x30: */ 0x00, 0xB0, 0x00, 0xC2, 0x34, 0x14, 0x02, 0x83,
+ /* 0x38: */ 0x00, 0x93, 0x00, 0x77, 0x00, 0x00, 0x00, 0x3A,
+ /* 0x40: */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x48: */ 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ bppshift = mdev->bpp_shifts[(crtc->fb->bits_per_pixel >> 3) - 1];
+
+ switch (mdev->type) {
+ case G200_SE_A:
+ case G200_SE_B:
+ dacvalue[MGA1064_VREF_CTL] = 0x03;
+ dacvalue[MGA1064_PIX_CLK_CTL] = MGA1064_PIX_CLK_CTL_SEL_PLL;
+ dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_DAC_EN |
+ MGA1064_MISC_CTL_VGA8 |
+ MGA1064_MISC_CTL_DAC_RAM_CS;
+ if (mdev->has_sdram)
+ option = 0x40049120;
+ else
+ option = 0x4004d120;
+ option2 = 0x00008000;
+ break;
+ case G200_WB:
+ dacvalue[MGA1064_VREF_CTL] = 0x07;
+ option = 0x41049120;
+ option2 = 0x0000b000;
+ break;
+ case G200_EV:
+ dacvalue[MGA1064_PIX_CLK_CTL] = MGA1064_PIX_CLK_CTL_SEL_PLL;
+ dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 |
+ MGA1064_MISC_CTL_DAC_RAM_CS;
+ option = 0x00000120;
+ option2 = 0x0000b000;
+ break;
+ case G200_EH:
+ dacvalue[MGA1064_MISC_CTL] = MGA1064_MISC_CTL_VGA8 |
+ MGA1064_MISC_CTL_DAC_RAM_CS;
+ option = 0x00000120;
+ option2 = 0x0000b000;
+ break;
+ case G200_ER:
+ dac_index90 = 0;
+ break;
+ }
+
+ switch (crtc->fb->bits_per_pixel) {
+ case 8:
+ dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_8bits;
+ break;
+ case 16:
+ if (crtc->fb->depth == 15)
+ dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_15bits;
+ else
+ dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_16bits;
+ break;
+ case 24:
+ dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_24bits;
+ break;
+ case 32:
+ dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_32_24bits;
+ break;
+ }
+
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ misc |= 0x40;
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ misc |= 0x80;
+
+
+ for (i = 0; i < sizeof(dacvalue); i++) {
+ if ((i <= 0x03) ||
+ (i == 0x07) ||
+ (i == 0x0b) ||
+ (i == 0x0f) ||
+ ((i >= 0x13) && (i <= 0x17)) ||
+ (i == 0x1b) ||
+ (i == 0x1c) ||
+ ((i >= 0x1f) && (i <= 0x29)) ||
+ ((i >= 0x30) && (i <= 0x37)))
+ continue;
+ if (IS_G200_SE(mdev) &&
+ ((i == 0x2c) || (i == 0x2d) || (i == 0x2e)))
+ continue;
+ if ((mdev->type == G200_EV || mdev->type == G200_WB || mdev->type == G200_EH) &&
+ (i >= 0x44) && (i <= 0x4e))
+ continue;
+
+ WREG_DAC(i, dacvalue[i]);
+ }
+
+ if (mdev->type == G200_ER) {
+ WREG_DAC(0x90, dac_index90);
+ }
+
+
+ if (option)
+ pci_write_config_dword(dev->pdev, PCI_MGA_OPTION, option);
+ if (option2)
+ pci_write_config_dword(dev->pdev, PCI_MGA_OPTION2, option2);
+
+ WREG_SEQ(2, 0xf);
+ WREG_SEQ(3, 0);
+ WREG_SEQ(4, 0xe);
+
+ pitch = crtc->fb->pitches[0] / (crtc->fb->bits_per_pixel / 8);
+ if (crtc->fb->bits_per_pixel == 24)
+ pitch = pitch >> (4 - bppshift);
+ else
+ pitch = pitch >> (4 - bppshift);
+
+ hdisplay = mode->hdisplay / 8 - 1;
+ hsyncstart = mode->hsync_start / 8 - 1;
+ hsyncend = mode->hsync_end / 8 - 1;
+ htotal = mode->htotal / 8 - 1;
+
+ /* Work around hardware quirk */
+ if ((htotal & 0x07) == 0x06 || (htotal & 0x07) == 0x04)
+ htotal++;
+
+ vdisplay = mode->vdisplay - 1;
+ vsyncstart = mode->vsync_start - 1;
+ vsyncend = mode->vsync_end - 1;
+ vtotal = mode->vtotal - 2;
+
+ WREG_GFX(0, 0);
+ WREG_GFX(1, 0);
+ WREG_GFX(2, 0);
+ WREG_GFX(3, 0);
+ WREG_GFX(4, 0);
+ WREG_GFX(5, 0x40);
+ WREG_GFX(6, 0x5);
+ WREG_GFX(7, 0xf);
+ WREG_GFX(8, 0xf);
+
+ WREG_CRT(0, htotal - 4);
+ WREG_CRT(1, hdisplay);
+ WREG_CRT(2, hdisplay);
+ WREG_CRT(3, (htotal & 0x1F) | 0x80);
+ WREG_CRT(4, hsyncstart);
+ WREG_CRT(5, ((htotal & 0x20) << 2) | (hsyncend & 0x1F));
+ WREG_CRT(6, vtotal & 0xFF);
+ WREG_CRT(7, ((vtotal & 0x100) >> 8) |
+ ((vdisplay & 0x100) >> 7) |
+ ((vsyncstart & 0x100) >> 6) |
+ ((vdisplay & 0x100) >> 5) |
+ ((vdisplay & 0x100) >> 4) | /* linecomp */
+ ((vtotal & 0x200) >> 4)|
+ ((vdisplay & 0x200) >> 3) |
+ ((vsyncstart & 0x200) >> 2));
+ WREG_CRT(9, ((vdisplay & 0x200) >> 4) |
+ ((vdisplay & 0x200) >> 3));
+ WREG_CRT(10, 0);
+ WREG_CRT(11, 0);
+ WREG_CRT(12, 0);
+ WREG_CRT(13, 0);
+ WREG_CRT(14, 0);
+ WREG_CRT(15, 0);
+ WREG_CRT(16, vsyncstart & 0xFF);
+ WREG_CRT(17, (vsyncend & 0x0F) | 0x20);
+ WREG_CRT(18, vdisplay & 0xFF);
+ WREG_CRT(19, pitch & 0xFF);
+ WREG_CRT(20, 0);
+ WREG_CRT(21, vdisplay & 0xFF);
+ WREG_CRT(22, (vtotal + 1) & 0xFF);
+ WREG_CRT(23, 0xc3);
+ WREG_CRT(24, vdisplay & 0xFF);
+
+ ext_vga[0] = 0;
+ ext_vga[5] = 0;
+
+ /* TODO interlace */
+
+ ext_vga[0] |= (pitch & 0x300) >> 4;
+ ext_vga[1] = (((htotal - 4) & 0x100) >> 8) |
+ ((hdisplay & 0x100) >> 7) |
+ ((hsyncstart & 0x100) >> 6) |
+ (htotal & 0x40);
+ ext_vga[2] = ((vtotal & 0xc00) >> 10) |
+ ((vdisplay & 0x400) >> 8) |
+ ((vdisplay & 0xc00) >> 7) |
+ ((vsyncstart & 0xc00) >> 5) |
+ ((vdisplay & 0x400) >> 3);
+ if (crtc->fb->bits_per_pixel == 24)
+ ext_vga[3] = (((1 << bppshift) * 3) - 1) | 0x80;
+ else
+ ext_vga[3] = ((1 << bppshift) - 1) | 0x80;
+ ext_vga[4] = 0;
+ if (mdev->type == G200_WB)
+ ext_vga[1] |= 0x88;
+
+ ext_vga_index24 = 0x05;
+
+ /* Set pixel clocks */
+ misc = 0x2d;
+ WREG8(MGA_MISC_OUT, misc);
+
+ mga_crtc_set_plls(mdev, mode->clock);
+
+ for (i = 0; i < 6; i++) {
+ WREG_ECRT(i, ext_vga[i]);
+ }
+
+ if (mdev->type == G200_ER)
+ WREG_ECRT(24, ext_vga_index24);
+
+ if (mdev->type == G200_EV) {
+ WREG_ECRT(6, 0);
+ }
+
+ WREG_ECRT(0, ext_vga[0]);
+ /* Enable mga pixel clock */
+ misc = 0x2d;
+
+ WREG8(MGA_MISC_OUT, misc);
+
+ if (adjusted_mode)
+ memcpy(&mdev->mode, mode, sizeof(struct drm_display_mode));
+
+ mga_crtc_do_set_base(crtc, old_fb, x, y, 0);
+
+ /* reset tagfifo */
+ if (mdev->type == G200_ER) {
+ u32 mem_ctl = RREG32(MGAREG_MEMCTL);
+ u8 seq1;
+
+ /* screen off */
+ WREG8(MGAREG_SEQ_INDEX, 0x01);
+ seq1 = RREG8(MGAREG_SEQ_DATA) | 0x20;
+ WREG8(MGAREG_SEQ_DATA, seq1);
+
+ WREG32(MGAREG_MEMCTL, mem_ctl | 0x00200000);
+ udelay(1000);
+ WREG32(MGAREG_MEMCTL, mem_ctl & ~0x00200000);
+
+ WREG8(MGAREG_SEQ_DATA, seq1 & ~0x20);
+ }
+
+
+ if (IS_G200_SE(mdev)) {
+ if (mdev->reg_1e24 >= 0x02) {
+ u8 hi_pri_lvl;
+ u32 bpp;
+ u32 mb;
+
+ if (crtc->fb->bits_per_pixel > 16)
+ bpp = 32;
+ else if (crtc->fb->bits_per_pixel > 8)
+ bpp = 16;
+ else
+ bpp = 8;
+
+ mb = (mode->clock * bpp) / 1000;
+ if (mb > 3100)
+ hi_pri_lvl = 0;
+ else if (mb > 2600)
+ hi_pri_lvl = 1;
+ else if (mb > 1900)
+ hi_pri_lvl = 2;
+ else if (mb > 1160)
+ hi_pri_lvl = 3;
+ else if (mb > 440)
+ hi_pri_lvl = 4;
+ else
+ hi_pri_lvl = 5;
+
+ WREG8(0x1fde, 0x06);
+ WREG8(0x1fdf, hi_pri_lvl);
+ } else {
+ if (mdev->reg_1e24 >= 0x01)
+ WREG8(0x1fdf, 0x03);
+ else
+ WREG8(0x1fdf, 0x04);
+ }
+ }
+ return 0;
+}
+
+#if 0 /* code from mjg to attempt D3 on crtc dpms off - revisit later */
+static int mga_suspend(struct drm_crtc *crtc)
+{
+ struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct mga_device *mdev = dev->dev_private;
+ struct pci_dev *pdev = dev->pdev;
+ int option;
+
+ if (mdev->suspended)
+ return 0;
+
+ WREG_SEQ(1, 0x20);
+ WREG_ECRT(1, 0x30);
+ /* Disable the pixel clock */
+ WREG_DAC(0x1a, 0x05);
+ /* Power down the DAC */
+ WREG_DAC(0x1e, 0x18);
+ /* Power down the pixel PLL */
+ WREG_DAC(0x1a, 0x0d);
+
+ /* Disable PLLs and clocks */
+ pci_read_config_dword(pdev, PCI_MGA_OPTION, &option);
+ option &= ~(0x1F8024);
+ pci_write_config_dword(pdev, PCI_MGA_OPTION, option);
+ pci_set_power_state(pdev, PCI_D3hot);
+ pci_disable_device(pdev);
+
+ mdev->suspended = true;
+
+ return 0;
+}
+
+static int mga_resume(struct drm_crtc *crtc)
+{
+ struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct mga_device *mdev = dev->dev_private;
+ struct pci_dev *pdev = dev->pdev;
+ int option;
+
+ if (!mdev->suspended)
+ return 0;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_enable_device(pdev);
+
+ /* Disable sysclk */
+ pci_read_config_dword(pdev, PCI_MGA_OPTION, &option);
+ option &= ~(0x4);
+ pci_write_config_dword(pdev, PCI_MGA_OPTION, option);
+
+ mdev->suspended = false;
+
+ return 0;
+}
+
+#endif
+
+static void mga_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+ struct drm_device *dev = crtc->dev;
+ struct mga_device *mdev = dev->dev_private;
+ u8 seq1 = 0, crtcext1 = 0;
+
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ seq1 = 0;
+ crtcext1 = 0;
+ mga_crtc_load_lut(crtc);
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ seq1 = 0x20;
+ crtcext1 = 0x10;
+ break;
+ case DRM_MODE_DPMS_SUSPEND:
+ seq1 = 0x20;
+ crtcext1 = 0x20;
+ break;
+ case DRM_MODE_DPMS_OFF:
+ seq1 = 0x20;
+ crtcext1 = 0x30;
+ break;
+ }
+
+#if 0
+ if (mode == DRM_MODE_DPMS_OFF) {
+ mga_suspend(crtc);
+ }
+#endif
+ WREG8(MGAREG_SEQ_INDEX, 0x01);
+ seq1 |= RREG8(MGAREG_SEQ_DATA) & ~0x20;
+ mga_wait_vsync(mdev);
+ mga_wait_busy(mdev);
+ WREG8(MGAREG_SEQ_DATA, seq1);
+ msleep(20);
+ WREG8(MGAREG_CRTCEXT_INDEX, 0x01);
+ crtcext1 |= RREG8(MGAREG_CRTCEXT_DATA) & ~0x30;
+ WREG8(MGAREG_CRTCEXT_DATA, crtcext1);
+
+#if 0
+ if (mode == DRM_MODE_DPMS_ON && mdev->suspended == true) {
+ mga_resume(crtc);
+ drm_helper_resume_force_mode(dev);
+ }
+#endif
+}
+
+/*
+ * This is called before a mode is programmed. A typical use might be to
+ * enable DPMS during the programming to avoid seeing intermediate stages,
+ * but that's not relevant to us
+ */
+static void mga_crtc_prepare(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct mga_device *mdev = dev->dev_private;
+ u8 tmp;
+
+ /* mga_resume(crtc);*/
+
+ WREG8(MGAREG_CRTC_INDEX, 0x11);
+ tmp = RREG8(MGAREG_CRTC_DATA);
+ WREG_CRT(0x11, tmp | 0x80);
+
+ if (mdev->type == G200_SE_A || mdev->type == G200_SE_B) {
+ WREG_SEQ(0, 1);
+ msleep(50);
+ WREG_SEQ(1, 0x20);
+ msleep(20);
+ } else {
+ WREG8(MGAREG_SEQ_INDEX, 0x1);
+ tmp = RREG8(MGAREG_SEQ_DATA);
+
+ /* start sync reset */
+ WREG_SEQ(0, 1);
+ WREG_SEQ(1, tmp | 0x20);
+ }
+
+ if (mdev->type == G200_WB)
+ mga_g200wb_prepare(crtc);
+
+ WREG_CRT(17, 0);
+}
+
+/*
+ * This is called after a mode is programmed. It should reverse anything done
+ * by the prepare function
+ */
+static void mga_crtc_commit(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct mga_device *mdev = dev->dev_private;
+ struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+ u8 tmp;
+
+ if (mdev->type == G200_WB)
+ mga_g200wb_commit(crtc);
+
+ if (mdev->type == G200_SE_A || mdev->type == G200_SE_B) {
+ msleep(50);
+ WREG_SEQ(1, 0x0);
+ msleep(20);
+ WREG_SEQ(0, 0x3);
+ } else {
+ WREG8(MGAREG_SEQ_INDEX, 0x1);
+ tmp = RREG8(MGAREG_SEQ_DATA);
+
+ tmp &= ~0x20;
+ WREG_SEQ(0x1, tmp);
+ WREG_SEQ(0, 3);
+ }
+ crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
+}
+
+/*
+ * The core can pass us a set of gamma values to program. We actually only
+ * use this for 8-bit mode so can't perform smooth fades on deeper modes,
+ * but it's a requirement that we provide the function
+ */
+static void mga_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
+ u16 *blue, uint32_t start, uint32_t size)
+{
+ struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
+ int end = (start + size > MGAG200_LUT_SIZE) ? MGAG200_LUT_SIZE : start + size;
+ int i;
+
+ for (i = start; i < end; i++) {
+ mga_crtc->lut_r[i] = red[i] >> 8;
+ mga_crtc->lut_g[i] = green[i] >> 8;
+ mga_crtc->lut_b[i] = blue[i] >> 8;
+ }
+ mga_crtc_load_lut(crtc);
+}
+
+/* Simple cleanup function */
+static void mga_crtc_destroy(struct drm_crtc *crtc)
+{
+ struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
+
+ drm_crtc_cleanup(crtc);
+ kfree(mga_crtc);
+}
+
+/* These provide the minimum set of functions required to handle a CRTC */
+static const struct drm_crtc_funcs mga_crtc_funcs = {
+ .gamma_set = mga_crtc_gamma_set,
+ .set_config = drm_crtc_helper_set_config,
+ .destroy = mga_crtc_destroy,
+};
+
+static const struct drm_crtc_helper_funcs mga_helper_funcs = {
+ .dpms = mga_crtc_dpms,
+ .mode_fixup = mga_crtc_mode_fixup,
+ .mode_set = mga_crtc_mode_set,
+ .mode_set_base = mga_crtc_mode_set_base,
+ .prepare = mga_crtc_prepare,
+ .commit = mga_crtc_commit,
+ .load_lut = mga_crtc_load_lut,
+};
+
+/* CRTC setup */
+static void mga_crtc_init(struct drm_device *dev)
+{
+ struct mga_device *mdev = dev->dev_private;
+ struct mga_crtc *mga_crtc;
+ int i;
+
+ mga_crtc = kzalloc(sizeof(struct mga_crtc) +
+ (MGAG200FB_CONN_LIMIT * sizeof(struct drm_connector *)),
+ GFP_KERNEL);
+
+ if (mga_crtc == NULL)
+ return;
+
+ drm_crtc_init(dev, &mga_crtc->base, &mga_crtc_funcs);
+
+ drm_mode_crtc_set_gamma_size(&mga_crtc->base, MGAG200_LUT_SIZE);
+ mdev->mode_info.crtc = mga_crtc;
+
+ for (i = 0; i < MGAG200_LUT_SIZE; i++) {
+ mga_crtc->lut_r[i] = i;
+ mga_crtc->lut_g[i] = i;
+ mga_crtc->lut_b[i] = i;
+ }
+
+ drm_crtc_helper_add(&mga_crtc->base, &mga_helper_funcs);
+}
+
+/** Sets the color ramps on behalf of fbcon */
+void mga_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
+ u16 blue, int regno)
+{
+ struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
+
+ mga_crtc->lut_r[regno] = red >> 8;
+ mga_crtc->lut_g[regno] = green >> 8;
+ mga_crtc->lut_b[regno] = blue >> 8;
+}
+
+/** Gets the color ramps on behalf of fbcon */
+void mga_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
+ u16 *blue, int regno)
+{
+ struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
+
+ *red = (u16)mga_crtc->lut_r[regno] << 8;
+ *green = (u16)mga_crtc->lut_g[regno] << 8;
+ *blue = (u16)mga_crtc->lut_b[regno] << 8;
+}
+
+/*
+ * The encoder comes after the CRTC in the output pipeline, but before
+ * the connector. It's responsible for ensuring that the digital
+ * stream is appropriately converted into the output format. Setup is
+ * very simple in this case - all we have to do is inform qemu of the
+ * colour depth in order to ensure that it displays appropriately
+ */
+
+/*
+ * These functions are analagous to those in the CRTC code, but are intended
+ * to handle any encoder-specific limitations
+ */
+static bool mga_encoder_mode_fixup(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void mga_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+
+}
+
+static void mga_encoder_dpms(struct drm_encoder *encoder, int state)
+{
+ return;
+}
+
+static void mga_encoder_prepare(struct drm_encoder *encoder)
+{
+}
+
+static void mga_encoder_commit(struct drm_encoder *encoder)
+{
+}
+
+void mga_encoder_destroy(struct drm_encoder *encoder)
+{
+ struct mga_encoder *mga_encoder = to_mga_encoder(encoder);
+ drm_encoder_cleanup(encoder);
+ kfree(mga_encoder);
+}
+
+static const struct drm_encoder_helper_funcs mga_encoder_helper_funcs = {
+ .dpms = mga_encoder_dpms,
+ .mode_fixup = mga_encoder_mode_fixup,
+ .mode_set = mga_encoder_mode_set,
+ .prepare = mga_encoder_prepare,
+ .commit = mga_encoder_commit,
+};
+
+static const struct drm_encoder_funcs mga_encoder_encoder_funcs = {
+ .destroy = mga_encoder_destroy,
+};
+
+static struct drm_encoder *mga_encoder_init(struct drm_device *dev)
+{
+ struct drm_encoder *encoder;
+ struct mga_encoder *mga_encoder;
+
+ mga_encoder = kzalloc(sizeof(struct mga_encoder), GFP_KERNEL);
+ if (!mga_encoder)
+ return NULL;
+
+ encoder = &mga_encoder->base;
+ encoder->possible_crtcs = 0x1;
+
+ drm_encoder_init(dev, encoder, &mga_encoder_encoder_funcs,
+ DRM_MODE_ENCODER_DAC);
+ drm_encoder_helper_add(encoder, &mga_encoder_helper_funcs);
+
+ return encoder;
+}
+
+
+static int mga_vga_get_modes(struct drm_connector *connector)
+{
+ struct mga_connector *mga_connector = to_mga_connector(connector);
+ struct edid *edid;
+ int ret = 0;
+
+ edid = drm_get_edid(connector, &mga_connector->i2c->adapter);
+ if (edid) {
+ drm_mode_connector_update_edid_property(connector, edid);
+ ret = drm_add_edid_modes(connector, edid);
+ connector->display_info.raw_edid = NULL;
+ kfree(edid);
+ }
+ return ret;
+}
+
+static int mga_vga_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ /* FIXME: Add bandwidth and g200se limitations */
+
+ if (mode->crtc_hdisplay > 2048 || mode->crtc_hsync_start > 4096 ||
+ mode->crtc_hsync_end > 4096 || mode->crtc_htotal > 4096 ||
+ mode->crtc_vdisplay > 2048 || mode->crtc_vsync_start > 4096 ||
+ mode->crtc_vsync_end > 4096 || mode->crtc_vtotal > 4096) {
+ return MODE_BAD;
+ }
+
+ return MODE_OK;
+}
+
+struct drm_encoder *mga_connector_best_encoder(struct drm_connector
+ *connector)
+{
+ int enc_id = connector->encoder_ids[0];
+ struct drm_mode_object *obj;
+ struct drm_encoder *encoder;
+
+ /* pick the encoder ids */
+ if (enc_id) {
+ obj =
+ drm_mode_object_find(connector->dev, enc_id,
+ DRM_MODE_OBJECT_ENCODER);
+ if (!obj)
+ return NULL;
+ encoder = obj_to_encoder(obj);
+ return encoder;
+ }
+ return NULL;
+}
+
+static enum drm_connector_status mga_vga_detect(struct drm_connector
+ *connector, bool force)
+{
+ return connector_status_connected;
+}
+
+static void mga_connector_destroy(struct drm_connector *connector)
+{
+ struct mga_connector *mga_connector = to_mga_connector(connector);
+ mgag200_i2c_destroy(mga_connector->i2c);
+ drm_connector_cleanup(connector);
+ kfree(connector);
+}
+
+struct drm_connector_helper_funcs mga_vga_connector_helper_funcs = {
+ .get_modes = mga_vga_get_modes,
+ .mode_valid = mga_vga_mode_valid,
+ .best_encoder = mga_connector_best_encoder,
+};
+
+struct drm_connector_funcs mga_vga_connector_funcs = {
+ .dpms = drm_helper_connector_dpms,
+ .detect = mga_vga_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = mga_connector_destroy,
+};
+
+static struct drm_connector *mga_vga_init(struct drm_device *dev)
+{
+ struct drm_connector *connector;
+ struct mga_connector *mga_connector;
+
+ mga_connector = kzalloc(sizeof(struct mga_connector), GFP_KERNEL);
+ if (!mga_connector)
+ return NULL;
+
+ connector = &mga_connector->base;
+
+ drm_connector_init(dev, connector,
+ &mga_vga_connector_funcs, DRM_MODE_CONNECTOR_VGA);
+
+ drm_connector_helper_add(connector, &mga_vga_connector_helper_funcs);
+
+ mga_connector->i2c = mgag200_i2c_create(dev);
+ if (!mga_connector->i2c)
+ DRM_ERROR("failed to add ddc bus\n");
+
+ return connector;
+}
+
+
+int mgag200_modeset_init(struct mga_device *mdev)
+{
+ struct drm_encoder *encoder;
+ struct drm_connector *connector;
+ int ret;
+
+ mdev->mode_info.mode_config_initialized = true;
+
+ mdev->dev->mode_config.max_width = MGAG200_MAX_FB_WIDTH;
+ mdev->dev->mode_config.max_height = MGAG200_MAX_FB_HEIGHT;
+
+ mdev->dev->mode_config.fb_base = mdev->mc.vram_base;
+
+ mga_crtc_init(mdev->dev);
+
+ encoder = mga_encoder_init(mdev->dev);
+ if (!encoder) {
+ DRM_ERROR("mga_encoder_init failed\n");
+ return -1;
+ }
+
+ connector = mga_vga_init(mdev->dev);
+ if (!connector) {
+ DRM_ERROR("mga_vga_init failed\n");
+ return -1;
+ }
+
+ drm_mode_connector_attach_encoder(connector, encoder);
+
+ ret = mgag200_fbdev_init(mdev);
+ if (ret) {
+ DRM_ERROR("mga_fbdev_init failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+void mgag200_modeset_fini(struct mga_device *mdev)
+{
+
+}
diff --git a/drivers/gpu/drm/mgag200/mgag200_reg.h b/drivers/gpu/drm/mgag200/mgag200_reg.h
new file mode 100644
index 000000000000..fb24d8655feb
--- /dev/null
+++ b/drivers/gpu/drm/mgag200/mgag200_reg.h
@@ -0,0 +1,661 @@
+/*
+ * MGA Millennium (MGA2064W) functions
+ * MGA Mystique (MGA1064SG) functions
+ *
+ * Copyright 1996 The XFree86 Project, Inc.
+ *
+ * Authors
+ * Dirk Hohndel
+ * hohndel@XFree86.Org
+ * David Dawes
+ * dawes@XFree86.Org
+ * Contributors:
+ * Guy DESBIEF, Aix-en-provence, France
+ * g.desbief@aix.pacwan.net
+ * MGA1064SG Mystique register file
+ */
+
+
+#ifndef _MGA_REG_H_
+#define _MGA_REG_H_
+
+#define MGAREG_DWGCTL 0x1c00
+#define MGAREG_MACCESS 0x1c04
+/* the following is a mystique only register */
+#define MGAREG_MCTLWTST 0x1c08
+#define MGAREG_ZORG 0x1c0c
+
+#define MGAREG_PAT0 0x1c10
+#define MGAREG_PAT1 0x1c14
+#define MGAREG_PLNWT 0x1c1c
+
+#define MGAREG_BCOL 0x1c20
+#define MGAREG_FCOL 0x1c24
+
+#define MGAREG_SRC0 0x1c30
+#define MGAREG_SRC1 0x1c34
+#define MGAREG_SRC2 0x1c38
+#define MGAREG_SRC3 0x1c3c
+
+#define MGAREG_XYSTRT 0x1c40
+#define MGAREG_XYEND 0x1c44
+
+#define MGAREG_SHIFT 0x1c50
+/* the following is a mystique only register */
+#define MGAREG_DMAPAD 0x1c54
+#define MGAREG_SGN 0x1c58
+#define MGAREG_LEN 0x1c5c
+
+#define MGAREG_AR0 0x1c60
+#define MGAREG_AR1 0x1c64
+#define MGAREG_AR2 0x1c68
+#define MGAREG_AR3 0x1c6c
+#define MGAREG_AR4 0x1c70
+#define MGAREG_AR5 0x1c74
+#define MGAREG_AR6 0x1c78
+
+#define MGAREG_CXBNDRY 0x1c80
+#define MGAREG_FXBNDRY 0x1c84
+#define MGAREG_YDSTLEN 0x1c88
+#define MGAREG_PITCH 0x1c8c
+
+#define MGAREG_YDST 0x1c90
+#define MGAREG_YDSTORG 0x1c94
+#define MGAREG_YTOP 0x1c98
+#define MGAREG_YBOT 0x1c9c
+
+#define MGAREG_CXLEFT 0x1ca0
+#define MGAREG_CXRIGHT 0x1ca4
+#define MGAREG_FXLEFT 0x1ca8
+#define MGAREG_FXRIGHT 0x1cac
+
+#define MGAREG_XDST 0x1cb0
+
+#define MGAREG_DR0 0x1cc0
+#define MGAREG_DR1 0x1cc4
+#define MGAREG_DR2 0x1cc8
+#define MGAREG_DR3 0x1ccc
+
+#define MGAREG_DR4 0x1cd0
+#define MGAREG_DR5 0x1cd4
+#define MGAREG_DR6 0x1cd8
+#define MGAREG_DR7 0x1cdc
+
+#define MGAREG_DR8 0x1ce0
+#define MGAREG_DR9 0x1ce4
+#define MGAREG_DR10 0x1ce8
+#define MGAREG_DR11 0x1cec
+
+#define MGAREG_DR12 0x1cf0
+#define MGAREG_DR13 0x1cf4
+#define MGAREG_DR14 0x1cf8
+#define MGAREG_DR15 0x1cfc
+
+#define MGAREG_SRCORG 0x2cb4
+#define MGAREG_DSTORG 0x2cb8
+
+/* add or or this to one of the previous "power registers" to start
+ the drawing engine */
+
+#define MGAREG_EXEC 0x0100
+
+#define MGAREG_FIFOSTATUS 0x1e10
+#define MGAREG_Status 0x1e14
+#define MGAREG_CACHEFLUSH 0x1fff
+#define MGAREG_ICLEAR 0x1e18
+#define MGAREG_IEN 0x1e1c
+
+#define MGAREG_VCOUNT 0x1e20
+
+#define MGAREG_Reset 0x1e40
+
+#define MGAREG_OPMODE 0x1e54
+
+/* Warp Registers */
+#define MGAREG_WIADDR 0x1dc0
+#define MGAREG_WIADDR2 0x1dd8
+#define MGAREG_WGETMSB 0x1dc8
+#define MGAREG_WVRTXSZ 0x1dcc
+#define MGAREG_WACCEPTSEQ 0x1dd4
+#define MGAREG_WMISC 0x1e70
+
+#define MGAREG_MEMCTL 0x2e08
+
+/* OPMODE register additives */
+
+#define MGAOPM_DMA_GENERAL (0x00 << 2)
+#define MGAOPM_DMA_BLIT (0x01 << 2)
+#define MGAOPM_DMA_VECTOR (0x10 << 2)
+
+/* MACCESS register additives */
+#define MGAMAC_PW8 0x00
+#define MGAMAC_PW16 0x01
+#define MGAMAC_PW24 0x03 /* not a typo */
+#define MGAMAC_PW32 0x02 /* not a typo */
+#define MGAMAC_BYPASS332 0x10000000
+#define MGAMAC_NODITHER 0x40000000
+#define MGAMAC_DIT555 0x80000000
+
+/* DWGCTL register additives */
+
+/* Lines */
+
+#define MGADWG_LINE_OPEN 0x00
+#define MGADWG_AUTOLINE_OPEN 0x01
+#define MGADWG_LINE_CLOSE 0x02
+#define MGADWG_AUTOLINE_CLOSE 0x03
+
+/* Trapezoids */
+#define MGADWG_TRAP 0x04
+#define MGADWG_TEXTURE_TRAP 0x06
+
+/* BitBlts */
+
+#define MGADWG_BITBLT 0x08
+#define MGADWG_FBITBLT 0x0c
+#define MGADWG_ILOAD 0x09
+#define MGADWG_ILOAD_SCALE 0x0d
+#define MGADWG_ILOAD_FILTER 0x0f
+#define MGADWG_ILOAD_HIQH 0x07
+#define MGADWG_ILOAD_HIQHV 0x0e
+#define MGADWG_IDUMP 0x0a
+
+/* atype access to WRAM */
+
+#define MGADWG_RPL ( 0x00 << 4 )
+#define MGADWG_RSTR ( 0x01 << 4 )
+#define MGADWG_ZI ( 0x03 << 4 )
+#define MGADWG_BLK ( 0x04 << 4 )
+#define MGADWG_I ( 0x07 << 4 )
+
+/* specifies whether bit blits are linear or xy */
+#define MGADWG_LINEAR ( 0x01 << 7 )
+
+/* z drawing mode. use MGADWG_NOZCMP for always */
+
+#define MGADWG_NOZCMP ( 0x00 << 8 )
+#define MGADWG_ZE ( 0x02 << 8 )
+#define MGADWG_ZNE ( 0x03 << 8 )
+#define MGADWG_ZLT ( 0x04 << 8 )
+#define MGADWG_ZLTE ( 0x05 << 8 )
+#define MGADWG_GT ( 0x06 << 8 )
+#define MGADWG_GTE ( 0x07 << 8 )
+
+/* use this to force colour expansion circuitry to do its stuff */
+
+#define MGADWG_SOLID ( 0x01 << 11 )
+
+/* ar register at zero */
+
+#define MGADWG_ARZERO ( 0x01 << 12 )
+
+#define MGADWG_SGNZERO ( 0x01 << 13 )
+
+#define MGADWG_SHIFTZERO ( 0x01 << 14 )
+
+/* See table on 4-43 for bop ALU operations */
+
+/* See table on 4-44 for translucidity masks */
+
+#define MGADWG_BMONOLEF ( 0x00 << 25 )
+#define MGADWG_BMONOWF ( 0x04 << 25 )
+#define MGADWG_BPLAN ( 0x01 << 25 )
+
+/* note that if bfcol is specified and you're doing a bitblt, it causes
+ a fbitblt to be performed, so check that you obey the fbitblt rules */
+
+#define MGADWG_BFCOL ( 0x02 << 25 )
+#define MGADWG_BUYUV ( 0x0e << 25 )
+#define MGADWG_BU32BGR ( 0x03 << 25 )
+#define MGADWG_BU32RGB ( 0x07 << 25 )
+#define MGADWG_BU24BGR ( 0x0b << 25 )
+#define MGADWG_BU24RGB ( 0x0f << 25 )
+
+#define MGADWG_PATTERN ( 0x01 << 29 )
+#define MGADWG_TRANSC ( 0x01 << 30 )
+#define MGAREG_MISC_WRITE 0x3c2
+#define MGAREG_MISC_READ 0x3cc
+#define MGAREG_MEM_MISC_WRITE 0x1fc2
+#define MGAREG_MEM_MISC_READ 0x1fcc
+
+#define MGAREG_MISC_IOADSEL (0x1 << 0)
+#define MGAREG_MISC_RAMMAPEN (0x1 << 1)
+#define MGAREG_MISC_CLK_SEL_VGA25 (0x0 << 2)
+#define MGAREG_MISC_CLK_SEL_VGA28 (0x1 << 2)
+#define MGAREG_MISC_CLK_SEL_MGA_PIX (0x2 << 2)
+#define MGAREG_MISC_CLK_SEL_MGA_MSK (0x3 << 2)
+#define MGAREG_MISC_VIDEO_DIS (0x1 << 4)
+#define MGAREG_MISC_HIGH_PG_SEL (0x1 << 5)
+
+/* MMIO VGA registers */
+#define MGAREG_SEQ_INDEX 0x1fc4
+#define MGAREG_SEQ_DATA 0x1fc5
+#define MGAREG_CRTC_INDEX 0x1fd4
+#define MGAREG_CRTC_DATA 0x1fd5
+#define MGAREG_CRTCEXT_INDEX 0x1fde
+#define MGAREG_CRTCEXT_DATA 0x1fdf
+
+
+
+/* MGA bits for registers PCI_OPTION_REG */
+#define MGA1064_OPT_SYS_CLK_PCI ( 0x00 << 0 )
+#define MGA1064_OPT_SYS_CLK_PLL ( 0x01 << 0 )
+#define MGA1064_OPT_SYS_CLK_EXT ( 0x02 << 0 )
+#define MGA1064_OPT_SYS_CLK_MSK ( 0x03 << 0 )
+
+#define MGA1064_OPT_SYS_CLK_DIS ( 0x01 << 2 )
+#define MGA1064_OPT_G_CLK_DIV_1 ( 0x01 << 3 )
+#define MGA1064_OPT_M_CLK_DIV_1 ( 0x01 << 4 )
+
+#define MGA1064_OPT_SYS_PLL_PDN ( 0x01 << 5 )
+#define MGA1064_OPT_VGA_ION ( 0x01 << 8 )
+
+/* MGA registers in PCI config space */
+#define PCI_MGA_INDEX 0x44
+#define PCI_MGA_DATA 0x48
+#define PCI_MGA_OPTION 0x40
+#define PCI_MGA_OPTION2 0x50
+#define PCI_MGA_OPTION3 0x54
+
+#define RAMDAC_OFFSET 0x3c00
+
+/* TVP3026 direct registers */
+
+#define TVP3026_INDEX 0x00
+#define TVP3026_WADR_PAL 0x00
+#define TVP3026_COL_PAL 0x01
+#define TVP3026_PIX_RD_MSK 0x02
+#define TVP3026_RADR_PAL 0x03
+#define TVP3026_CUR_COL_ADDR 0x04
+#define TVP3026_CUR_COL_DATA 0x05
+#define TVP3026_DATA 0x0a
+#define TVP3026_CUR_RAM 0x0b
+#define TVP3026_CUR_XLOW 0x0c
+#define TVP3026_CUR_XHI 0x0d
+#define TVP3026_CUR_YLOW 0x0e
+#define TVP3026_CUR_YHI 0x0f
+
+/* TVP3026 indirect registers */
+
+#define TVP3026_SILICON_REV 0x01
+#define TVP3026_CURSOR_CTL 0x06
+#define TVP3026_LATCH_CTL 0x0f
+#define TVP3026_TRUE_COLOR_CTL 0x18
+#define TVP3026_MUX_CTL 0x19
+#define TVP3026_CLK_SEL 0x1a
+#define TVP3026_PAL_PAGE 0x1c
+#define TVP3026_GEN_CTL 0x1d
+#define TVP3026_MISC_CTL 0x1e
+#define TVP3026_GEN_IO_CTL 0x2a
+#define TVP3026_GEN_IO_DATA 0x2b
+#define TVP3026_PLL_ADDR 0x2c
+#define TVP3026_PIX_CLK_DATA 0x2d
+#define TVP3026_MEM_CLK_DATA 0x2e
+#define TVP3026_LOAD_CLK_DATA 0x2f
+#define TVP3026_KEY_RED_LOW 0x32
+#define TVP3026_KEY_RED_HI 0x33
+#define TVP3026_KEY_GREEN_LOW 0x34
+#define TVP3026_KEY_GREEN_HI 0x35
+#define TVP3026_KEY_BLUE_LOW 0x36
+#define TVP3026_KEY_BLUE_HI 0x37
+#define TVP3026_KEY_CTL 0x38
+#define TVP3026_MCLK_CTL 0x39
+#define TVP3026_SENSE_TEST 0x3a
+#define TVP3026_TEST_DATA 0x3b
+#define TVP3026_CRC_LSB 0x3c
+#define TVP3026_CRC_MSB 0x3d
+#define TVP3026_CRC_CTL 0x3e
+#define TVP3026_ID 0x3f
+#define TVP3026_RESET 0xff
+
+
+/* MGA1064 DAC Register file */
+/* MGA1064 direct registers */
+
+#define MGA1064_INDEX 0x00
+#define MGA1064_WADR_PAL 0x00
+#define MGA1064_SPAREREG 0x00
+#define MGA1064_COL_PAL 0x01
+#define MGA1064_PIX_RD_MSK 0x02
+#define MGA1064_RADR_PAL 0x03
+#define MGA1064_DATA 0x0a
+
+#define MGA1064_CUR_XLOW 0x0c
+#define MGA1064_CUR_XHI 0x0d
+#define MGA1064_CUR_YLOW 0x0e
+#define MGA1064_CUR_YHI 0x0f
+
+/* MGA1064 indirect registers */
+#define MGA1064_DVI_PIPE_CTL 0x03
+#define MGA1064_CURSOR_BASE_ADR_LOW 0x04
+#define MGA1064_CURSOR_BASE_ADR_HI 0x05
+#define MGA1064_CURSOR_CTL 0x06
+#define MGA1064_CURSOR_COL0_RED 0x08
+#define MGA1064_CURSOR_COL0_GREEN 0x09
+#define MGA1064_CURSOR_COL0_BLUE 0x0a
+
+#define MGA1064_CURSOR_COL1_RED 0x0c
+#define MGA1064_CURSOR_COL1_GREEN 0x0d
+#define MGA1064_CURSOR_COL1_BLUE 0x0e
+
+#define MGA1064_CURSOR_COL2_RED 0x010
+#define MGA1064_CURSOR_COL2_GREEN 0x011
+#define MGA1064_CURSOR_COL2_BLUE 0x012
+
+#define MGA1064_VREF_CTL 0x018
+
+#define MGA1064_MUL_CTL 0x19
+#define MGA1064_MUL_CTL_8bits 0x0
+#define MGA1064_MUL_CTL_15bits 0x01
+#define MGA1064_MUL_CTL_16bits 0x02
+#define MGA1064_MUL_CTL_24bits 0x03
+#define MGA1064_MUL_CTL_32bits 0x04
+#define MGA1064_MUL_CTL_2G8V16bits 0x05
+#define MGA1064_MUL_CTL_G16V16bits 0x06
+#define MGA1064_MUL_CTL_32_24bits 0x07
+
+#define MGA1064_PIX_CLK_CTL 0x1a
+#define MGA1064_PIX_CLK_CTL_CLK_DIS ( 0x01 << 2 )
+#define MGA1064_PIX_CLK_CTL_CLK_POW_DOWN ( 0x01 << 3 )
+#define MGA1064_PIX_CLK_CTL_SEL_PCI ( 0x00 << 0 )
+#define MGA1064_PIX_CLK_CTL_SEL_PLL ( 0x01 << 0 )
+#define MGA1064_PIX_CLK_CTL_SEL_EXT ( 0x02 << 0 )
+#define MGA1064_PIX_CLK_CTL_SEL_MSK ( 0x03 << 0 )
+
+#define MGA1064_GEN_CTL 0x1d
+#define MGA1064_GEN_CTL_SYNC_ON_GREEN_DIS (0x01 << 5)
+#define MGA1064_MISC_CTL 0x1e
+#define MGA1064_MISC_CTL_DAC_EN ( 0x01 << 0 )
+#define MGA1064_MISC_CTL_VGA ( 0x01 << 1 )
+#define MGA1064_MISC_CTL_DIS_CON ( 0x03 << 1 )
+#define MGA1064_MISC_CTL_MAFC ( 0x02 << 1 )
+#define MGA1064_MISC_CTL_VGA8 ( 0x01 << 3 )
+#define MGA1064_MISC_CTL_DAC_RAM_CS ( 0x01 << 4 )
+
+#define MGA1064_GEN_IO_CTL2 0x29
+#define MGA1064_GEN_IO_CTL 0x2a
+#define MGA1064_GEN_IO_DATA 0x2b
+#define MGA1064_SYS_PLL_M 0x2c
+#define MGA1064_SYS_PLL_N 0x2d
+#define MGA1064_SYS_PLL_P 0x2e
+#define MGA1064_SYS_PLL_STAT 0x2f
+
+#define MGA1064_REMHEADCTL 0x30
+#define MGA1064_REMHEADCTL_CLKDIS ( 0x01 << 0 )
+#define MGA1064_REMHEADCTL_CLKSL_OFF ( 0x00 << 1 )
+#define MGA1064_REMHEADCTL_CLKSL_PLL ( 0x01 << 1 )
+#define MGA1064_REMHEADCTL_CLKSL_PCI ( 0x02 << 1 )
+#define MGA1064_REMHEADCTL_CLKSL_MSK ( 0x03 << 1 )
+
+#define MGA1064_REMHEADCTL2 0x31
+
+#define MGA1064_ZOOM_CTL 0x38
+#define MGA1064_SENSE_TST 0x3a
+
+#define MGA1064_CRC_LSB 0x3c
+#define MGA1064_CRC_MSB 0x3d
+#define MGA1064_CRC_CTL 0x3e
+#define MGA1064_COL_KEY_MSK_LSB 0x40
+#define MGA1064_COL_KEY_MSK_MSB 0x41
+#define MGA1064_COL_KEY_LSB 0x42
+#define MGA1064_COL_KEY_MSB 0x43
+#define MGA1064_PIX_PLLA_M 0x44
+#define MGA1064_PIX_PLLA_N 0x45
+#define MGA1064_PIX_PLLA_P 0x46
+#define MGA1064_PIX_PLLB_M 0x48
+#define MGA1064_PIX_PLLB_N 0x49
+#define MGA1064_PIX_PLLB_P 0x4a
+#define MGA1064_PIX_PLLC_M 0x4c
+#define MGA1064_PIX_PLLC_N 0x4d
+#define MGA1064_PIX_PLLC_P 0x4e
+
+#define MGA1064_PIX_PLL_STAT 0x4f
+
+/*Added for G450 dual head*/
+
+#define MGA1064_VID_PLL_STAT 0x8c
+#define MGA1064_VID_PLL_P 0x8D
+#define MGA1064_VID_PLL_M 0x8E
+#define MGA1064_VID_PLL_N 0x8F
+
+/* Modified PLL for G200 Winbond (G200WB) */
+#define MGA1064_WB_PIX_PLLC_M 0xb7
+#define MGA1064_WB_PIX_PLLC_N 0xb6
+#define MGA1064_WB_PIX_PLLC_P 0xb8
+
+/* Modified PLL for G200 Maxim (G200EV) */
+#define MGA1064_EV_PIX_PLLC_M 0xb6
+#define MGA1064_EV_PIX_PLLC_N 0xb7
+#define MGA1064_EV_PIX_PLLC_P 0xb8
+
+/* Modified PLL for G200 EH */
+#define MGA1064_EH_PIX_PLLC_M 0xb6
+#define MGA1064_EH_PIX_PLLC_N 0xb7
+#define MGA1064_EH_PIX_PLLC_P 0xb8
+
+/* Modified PLL for G200 Maxim (G200ER) */
+#define MGA1064_ER_PIX_PLLC_M 0xb7
+#define MGA1064_ER_PIX_PLLC_N 0xb6
+#define MGA1064_ER_PIX_PLLC_P 0xb8
+
+#define MGA1064_DISP_CTL 0x8a
+#define MGA1064_DISP_CTL_DAC1OUTSEL_MASK 0x01
+#define MGA1064_DISP_CTL_DAC1OUTSEL_DIS 0x00
+#define MGA1064_DISP_CTL_DAC1OUTSEL_EN 0x01
+#define MGA1064_DISP_CTL_DAC2OUTSEL_MASK (0x03 << 2)
+#define MGA1064_DISP_CTL_DAC2OUTSEL_DIS 0x00
+#define MGA1064_DISP_CTL_DAC2OUTSEL_CRTC1 (0x01 << 2)
+#define MGA1064_DISP_CTL_DAC2OUTSEL_CRTC2 (0x02 << 2)
+#define MGA1064_DISP_CTL_DAC2OUTSEL_TVE (0x03 << 2)
+#define MGA1064_DISP_CTL_PANOUTSEL_MASK (0x03 << 5)
+#define MGA1064_DISP_CTL_PANOUTSEL_DIS 0x00
+#define MGA1064_DISP_CTL_PANOUTSEL_CRTC1 (0x01 << 5)
+#define MGA1064_DISP_CTL_PANOUTSEL_CRTC2RGB (0x02 << 5)
+#define MGA1064_DISP_CTL_PANOUTSEL_CRTC2656 (0x03 << 5)
+
+#define MGA1064_SYNC_CTL 0x8b
+
+#define MGA1064_PWR_CTL 0xa0
+#define MGA1064_PWR_CTL_DAC2_EN (0x01 << 0)
+#define MGA1064_PWR_CTL_VID_PLL_EN (0x01 << 1)
+#define MGA1064_PWR_CTL_PANEL_EN (0x01 << 2)
+#define MGA1064_PWR_CTL_RFIFO_EN (0x01 << 3)
+#define MGA1064_PWR_CTL_CFIFO_EN (0x01 << 4)
+
+#define MGA1064_PAN_CTL 0xa2
+
+/* Using crtc2 */
+#define MGAREG2_C2CTL 0x10
+#define MGAREG2_C2HPARAM 0x14
+#define MGAREG2_C2HSYNC 0x18
+#define MGAREG2_C2VPARAM 0x1c
+#define MGAREG2_C2VSYNC 0x20
+#define MGAREG2_C2STARTADD0 0x28
+
+#define MGAREG2_C2OFFSET 0x40
+#define MGAREG2_C2DATACTL 0x4c
+
+#define MGAREG_C2CTL 0x3c10
+#define MGAREG_C2CTL_C2_EN 0x01
+
+#define MGAREG_C2_HIPRILVL_M (0x07 << 4)
+#define MGAREG_C2_MAXHIPRI_M (0x07 << 8)
+
+#define MGAREG_C2CTL_PIXCLKSEL_MASK (0x03 << 1)
+#define MGAREG_C2CTL_PIXCLKSELH_MASK (0x01 << 14)
+#define MGAREG_C2CTL_PIXCLKSEL_PCICLK 0x00
+#define MGAREG_C2CTL_PIXCLKSEL_VDOCLK (0x01 << 1)
+#define MGAREG_C2CTL_PIXCLKSEL_PIXELPLL (0x02 << 1)
+#define MGAREG_C2CTL_PIXCLKSEL_VIDEOPLL (0x03 << 1)
+#define MGAREG_C2CTL_PIXCLKSEL_VDCLK (0x01 << 14)
+
+#define MGAREG_C2CTL_PIXCLKSEL_CRISTAL (0x01 << 1) | (0x01 << 14)
+#define MGAREG_C2CTL_PIXCLKSEL_SYSTEMPLL (0x02 << 1) | (0x01 << 14)
+
+#define MGAREG_C2CTL_PIXCLKDIS_MASK (0x01 << 3)
+#define MGAREG_C2CTL_PIXCLKDIS_DISABLE (0x01 << 3)
+
+#define MGAREG_C2CTL_CRTCDACSEL_MASK (0x01 << 20)
+#define MGAREG_C2CTL_CRTCDACSEL_CRTC1 0x00
+#define MGAREG_C2CTL_CRTCDACSEL_CRTC2 (0x01 << 20)
+
+#define MGAREG_C2HPARAM 0x3c14
+#define MGAREG_C2HSYNC 0x3c18
+#define MGAREG_C2VPARAM 0x3c1c
+#define MGAREG_C2VSYNC 0x3c20
+#define MGAREG_C2STARTADD0 0x3c28
+
+#define MGAREG_C2OFFSET 0x3c40
+#define MGAREG_C2DATACTL 0x3c4c
+
+/* video register */
+
+#define MGAREG_BESA1C3ORG 0x3d60
+#define MGAREG_BESA1CORG 0x3d10
+#define MGAREG_BESA1ORG 0x3d00
+#define MGAREG_BESCTL 0x3d20
+#define MGAREG_BESGLOBCTL 0x3dc0
+#define MGAREG_BESHCOORD 0x3d28
+#define MGAREG_BESHISCAL 0x3d30
+#define MGAREG_BESHSRCEND 0x3d3c
+#define MGAREG_BESHSRCLST 0x3d50
+#define MGAREG_BESHSRCST 0x3d38
+#define MGAREG_BESLUMACTL 0x3d40
+#define MGAREG_BESPITCH 0x3d24
+#define MGAREG_BESV1SRCLST 0x3d54
+#define MGAREG_BESV1WGHT 0x3d48
+#define MGAREG_BESVCOORD 0x3d2c
+#define MGAREG_BESVISCAL 0x3d34
+
+/* texture engine registers */
+
+#define MGAREG_TMR0 0x2c00
+#define MGAREG_TMR1 0x2c04
+#define MGAREG_TMR2 0x2c08
+#define MGAREG_TMR3 0x2c0c
+#define MGAREG_TMR4 0x2c10
+#define MGAREG_TMR5 0x2c14
+#define MGAREG_TMR6 0x2c18
+#define MGAREG_TMR7 0x2c1c
+#define MGAREG_TMR8 0x2c20
+#define MGAREG_TEXORG 0x2c24
+#define MGAREG_TEXWIDTH 0x2c28
+#define MGAREG_TEXHEIGHT 0x2c2c
+#define MGAREG_TEXCTL 0x2c30
+# define MGA_TW4 (0x00000000)
+# define MGA_TW8 (0x00000001)
+# define MGA_TW15 (0x00000002)
+# define MGA_TW16 (0x00000003)
+# define MGA_TW12 (0x00000004)
+# define MGA_TW32 (0x00000006)
+# define MGA_TW8A (0x00000007)
+# define MGA_TW8AL (0x00000008)
+# define MGA_TW422 (0x0000000A)
+# define MGA_TW422UYVY (0x0000000B)
+# define MGA_PITCHLIN (0x00000100)
+# define MGA_NOPERSPECTIVE (0x00200000)
+# define MGA_TAKEY (0x02000000)
+# define MGA_TAMASK (0x04000000)
+# define MGA_CLAMPUV (0x18000000)
+# define MGA_TEXMODULATE (0x20000000)
+#define MGAREG_TEXCTL2 0x2c3c
+# define MGA_G400_TC2_MAGIC (0x00008000)
+# define MGA_TC2_DECALBLEND (0x00000001)
+# define MGA_TC2_IDECAL (0x00000002)
+# define MGA_TC2_DECALDIS (0x00000004)
+# define MGA_TC2_CKSTRANSDIS (0x00000010)
+# define MGA_TC2_BORDEREN (0x00000020)
+# define MGA_TC2_SPECEN (0x00000040)
+# define MGA_TC2_DUALTEX (0x00000080)
+# define MGA_TC2_TABLEFOG (0x00000100)
+# define MGA_TC2_BUMPMAP (0x00000200)
+# define MGA_TC2_SELECT_TMU1 (0x80000000)
+#define MGAREG_TEXTRANS 0x2c34
+#define MGAREG_TEXTRANSHIGH 0x2c38
+#define MGAREG_TEXFILTER 0x2c58
+# define MGA_MIN_NRST (0x00000000)
+# define MGA_MIN_BILIN (0x00000002)
+# define MGA_MIN_ANISO (0x0000000D)
+# define MGA_MAG_NRST (0x00000000)
+# define MGA_MAG_BILIN (0x00000020)
+# define MGA_FILTERALPHA (0x00100000)
+#define MGAREG_ALPHASTART 0x2c70
+#define MGAREG_ALPHAXINC 0x2c74
+#define MGAREG_ALPHAYINC 0x2c78
+#define MGAREG_ALPHACTRL 0x2c7c
+# define MGA_SRC_ZERO (0x00000000)
+# define MGA_SRC_ONE (0x00000001)
+# define MGA_SRC_DST_COLOR (0x00000002)
+# define MGA_SRC_ONE_MINUS_DST_COLOR (0x00000003)
+# define MGA_SRC_ALPHA (0x00000004)
+# define MGA_SRC_ONE_MINUS_SRC_ALPHA (0x00000005)
+# define MGA_SRC_DST_ALPHA (0x00000006)
+# define MGA_SRC_ONE_MINUS_DST_ALPHA (0x00000007)
+# define MGA_SRC_SRC_ALPHA_SATURATE (0x00000008)
+# define MGA_SRC_BLEND_MASK (0x0000000f)
+# define MGA_DST_ZERO (0x00000000)
+# define MGA_DST_ONE (0x00000010)
+# define MGA_DST_SRC_COLOR (0x00000020)
+# define MGA_DST_ONE_MINUS_SRC_COLOR (0x00000030)
+# define MGA_DST_SRC_ALPHA (0x00000040)
+# define MGA_DST_ONE_MINUS_SRC_ALPHA (0x00000050)
+# define MGA_DST_DST_ALPHA (0x00000060)
+# define MGA_DST_ONE_MINUS_DST_ALPHA (0x00000070)
+# define MGA_DST_BLEND_MASK (0x00000070)
+# define MGA_ALPHACHANNEL (0x00000100)
+# define MGA_VIDEOALPHA (0x00000200)
+# define MGA_DIFFUSEDALPHA (0x01000000)
+# define MGA_MODULATEDALPHA (0x02000000)
+#define MGAREG_TDUALSTAGE0 (0x2CF8)
+#define MGAREG_TDUALSTAGE1 (0x2CFC)
+# define MGA_TDS_COLOR_ARG2_DIFFUSE (0x00000000)
+# define MGA_TDS_COLOR_ARG2_SPECULAR (0x00000001)
+# define MGA_TDS_COLOR_ARG2_FCOL (0x00000002)
+# define MGA_TDS_COLOR_ARG2_PREVSTAGE (0x00000003)
+# define MGA_TDS_COLOR_ALPHA_DIFFUSE (0x00000000)
+# define MGA_TDS_COLOR_ALPHA_FCOL (0x00000004)
+# define MGA_TDS_COLOR_ALPHA_CURRTEX (0x00000008)
+# define MGA_TDS_COLOR_ALPHA_PREVTEX (0x0000000c)
+# define MGA_TDS_COLOR_ALPHA_PREVSTAGE (0x00000010)
+# define MGA_TDS_COLOR_ARG1_REPLICATEALPHA (0x00000020)
+# define MGA_TDS_COLOR_ARG1_INV (0x00000040)
+# define MGA_TDS_COLOR_ARG2_REPLICATEALPHA (0x00000080)
+# define MGA_TDS_COLOR_ARG2_INV (0x00000100)
+# define MGA_TDS_COLOR_ALPHA1INV (0x00000200)
+# define MGA_TDS_COLOR_ALPHA2INV (0x00000400)
+# define MGA_TDS_COLOR_ARG1MUL_ALPHA1 (0x00000800)
+# define MGA_TDS_COLOR_ARG2MUL_ALPHA2 (0x00001000)
+# define MGA_TDS_COLOR_ARG1ADD_MULOUT (0x00002000)
+# define MGA_TDS_COLOR_ARG2ADD_MULOUT (0x00004000)
+# define MGA_TDS_COLOR_MODBRIGHT_2X (0x00008000)
+# define MGA_TDS_COLOR_MODBRIGHT_4X (0x00010000)
+# define MGA_TDS_COLOR_ADD_SUB (0x00000000)
+# define MGA_TDS_COLOR_ADD_ADD (0x00020000)
+# define MGA_TDS_COLOR_ADD2X (0x00040000)
+# define MGA_TDS_COLOR_ADDBIAS (0x00080000)
+# define MGA_TDS_COLOR_BLEND (0x00100000)
+# define MGA_TDS_COLOR_SEL_ARG1 (0x00000000)
+# define MGA_TDS_COLOR_SEL_ARG2 (0x00200000)
+# define MGA_TDS_COLOR_SEL_ADD (0x00400000)
+# define MGA_TDS_COLOR_SEL_MUL (0x00600000)
+# define MGA_TDS_ALPHA_ARG1_INV (0x00800000)
+# define MGA_TDS_ALPHA_ARG2_DIFFUSE (0x00000000)
+# define MGA_TDS_ALPHA_ARG2_FCOL (0x01000000)
+# define MGA_TDS_ALPHA_ARG2_PREVTEX (0x02000000)
+# define MGA_TDS_ALPHA_ARG2_PREVSTAGE (0x03000000)
+# define MGA_TDS_ALPHA_ARG2_INV (0x04000000)
+# define MGA_TDS_ALPHA_ADD (0x08000000)
+# define MGA_TDS_ALPHA_ADDBIAS (0x10000000)
+# define MGA_TDS_ALPHA_ADD2X (0x20000000)
+# define MGA_TDS_ALPHA_SEL_ARG1 (0x00000000)
+# define MGA_TDS_ALPHA_SEL_ARG2 (0x40000000)
+# define MGA_TDS_ALPHA_SEL_ADD (0x80000000)
+# define MGA_TDS_ALPHA_SEL_MUL (0xc0000000)
+
+#define MGAREG_DWGSYNC 0x2c4c
+
+#define MGAREG_AGP_PLL 0x1e4c
+#define MGA_AGP2XPLL_ENABLE 0x1
+#define MGA_AGP2XPLL_DISABLE 0x0
+
+#endif
diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c
new file mode 100644
index 000000000000..b223dcb7a710
--- /dev/null
+++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c
@@ -0,0 +1,452 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ */
+/*
+ * Authors: Dave Airlie <airlied@redhat.com>
+ */
+#include "drmP.h"
+#include "mgag200_drv.h"
+#include <ttm/ttm_page_alloc.h>
+
+static inline struct mga_device *
+mgag200_bdev(struct ttm_bo_device *bd)
+{
+ return container_of(bd, struct mga_device, ttm.bdev);
+}
+
+static int
+mgag200_ttm_mem_global_init(struct drm_global_reference *ref)
+{
+ return ttm_mem_global_init(ref->object);
+}
+
+static void
+mgag200_ttm_mem_global_release(struct drm_global_reference *ref)
+{
+ ttm_mem_global_release(ref->object);
+}
+
+static int mgag200_ttm_global_init(struct mga_device *ast)
+{
+ struct drm_global_reference *global_ref;
+ int r;
+
+ global_ref = &ast->ttm.mem_global_ref;
+ global_ref->global_type = DRM_GLOBAL_TTM_MEM;
+ global_ref->size = sizeof(struct ttm_mem_global);
+ global_ref->init = &mgag200_ttm_mem_global_init;
+ global_ref->release = &mgag200_ttm_mem_global_release;
+ r = drm_global_item_ref(global_ref);
+ if (r != 0) {
+ DRM_ERROR("Failed setting up TTM memory accounting "
+ "subsystem.\n");
+ return r;
+ }
+
+ ast->ttm.bo_global_ref.mem_glob =
+ ast->ttm.mem_global_ref.object;
+ global_ref = &ast->ttm.bo_global_ref.ref;
+ global_ref->global_type = DRM_GLOBAL_TTM_BO;
+ global_ref->size = sizeof(struct ttm_bo_global);
+ global_ref->init = &ttm_bo_global_init;
+ global_ref->release = &ttm_bo_global_release;
+ r = drm_global_item_ref(global_ref);
+ if (r != 0) {
+ DRM_ERROR("Failed setting up TTM BO subsystem.\n");
+ drm_global_item_unref(&ast->ttm.mem_global_ref);
+ return r;
+ }
+ return 0;
+}
+
+void
+mgag200_ttm_global_release(struct mga_device *ast)
+{
+ if (ast->ttm.mem_global_ref.release == NULL)
+ return;
+
+ drm_global_item_unref(&ast->ttm.bo_global_ref.ref);
+ drm_global_item_unref(&ast->ttm.mem_global_ref);
+ ast->ttm.mem_global_ref.release = NULL;
+}
+
+
+static void mgag200_bo_ttm_destroy(struct ttm_buffer_object *tbo)
+{
+ struct mgag200_bo *bo;
+
+ bo = container_of(tbo, struct mgag200_bo, bo);
+
+ drm_gem_object_release(&bo->gem);
+ kfree(bo);
+}
+
+bool mgag200_ttm_bo_is_mgag200_bo(struct ttm_buffer_object *bo)
+{
+ if (bo->destroy == &mgag200_bo_ttm_destroy)
+ return true;
+ return false;
+}
+
+static int
+mgag200_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
+ struct ttm_mem_type_manager *man)
+{
+ switch (type) {
+ case TTM_PL_SYSTEM:
+ man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
+ man->available_caching = TTM_PL_MASK_CACHING;
+ man->default_caching = TTM_PL_FLAG_CACHED;
+ break;
+ case TTM_PL_VRAM:
+ man->func = &ttm_bo_manager_func;
+ man->flags = TTM_MEMTYPE_FLAG_FIXED |
+ TTM_MEMTYPE_FLAG_MAPPABLE;
+ man->available_caching = TTM_PL_FLAG_UNCACHED |
+ TTM_PL_FLAG_WC;
+ man->default_caching = TTM_PL_FLAG_WC;
+ break;
+ default:
+ DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void
+mgag200_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
+{
+ struct mgag200_bo *mgabo = mgag200_bo(bo);
+
+ if (!mgag200_ttm_bo_is_mgag200_bo(bo))
+ return;
+
+ mgag200_ttm_placement(mgabo, TTM_PL_FLAG_SYSTEM);
+ *pl = mgabo->placement;
+}
+
+static int mgag200_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp)
+{
+ return 0;
+}
+
+static int mgag200_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
+ struct ttm_mem_reg *mem)
+{
+ struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
+ struct mga_device *mdev = mgag200_bdev(bdev);
+
+ mem->bus.addr = NULL;
+ mem->bus.offset = 0;
+ mem->bus.size = mem->num_pages << PAGE_SHIFT;
+ mem->bus.base = 0;
+ mem->bus.is_iomem = false;
+ if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
+ return -EINVAL;
+ switch (mem->mem_type) {
+ case TTM_PL_SYSTEM:
+ /* system memory */
+ return 0;
+ case TTM_PL_VRAM:
+ mem->bus.offset = mem->start << PAGE_SHIFT;
+ mem->bus.base = pci_resource_start(mdev->dev->pdev, 0);
+ mem->bus.is_iomem = true;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ return 0;
+}
+
+static void mgag200_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
+{
+}
+
+static int mgag200_bo_move(struct ttm_buffer_object *bo,
+ bool evict, bool interruptible,
+ bool no_wait_reserve, bool no_wait_gpu,
+ struct ttm_mem_reg *new_mem)
+{
+ int r;
+ r = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
+ return r;
+}
+
+
+static void mgag200_ttm_backend_destroy(struct ttm_tt *tt)
+{
+ ttm_tt_fini(tt);
+ kfree(tt);
+}
+
+static struct ttm_backend_func mgag200_tt_backend_func = {
+ .destroy = &mgag200_ttm_backend_destroy,
+};
+
+
+struct ttm_tt *mgag200_ttm_tt_create(struct ttm_bo_device *bdev,
+ unsigned long size, uint32_t page_flags,
+ struct page *dummy_read_page)
+{
+ struct ttm_tt *tt;
+
+ tt = kzalloc(sizeof(struct ttm_tt), GFP_KERNEL);
+ if (tt == NULL)
+ return NULL;
+ tt->func = &mgag200_tt_backend_func;
+ if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) {
+ kfree(tt);
+ return NULL;
+ }
+ return tt;
+}
+
+static int mgag200_ttm_tt_populate(struct ttm_tt *ttm)
+{
+ return ttm_pool_populate(ttm);
+}
+
+static void mgag200_ttm_tt_unpopulate(struct ttm_tt *ttm)
+{
+ ttm_pool_unpopulate(ttm);
+}
+
+struct ttm_bo_driver mgag200_bo_driver = {
+ .ttm_tt_create = mgag200_ttm_tt_create,
+ .ttm_tt_populate = mgag200_ttm_tt_populate,
+ .ttm_tt_unpopulate = mgag200_ttm_tt_unpopulate,
+ .init_mem_type = mgag200_bo_init_mem_type,
+ .evict_flags = mgag200_bo_evict_flags,
+ .move = mgag200_bo_move,
+ .verify_access = mgag200_bo_verify_access,
+ .io_mem_reserve = &mgag200_ttm_io_mem_reserve,
+ .io_mem_free = &mgag200_ttm_io_mem_free,
+};
+
+int mgag200_mm_init(struct mga_device *mdev)
+{
+ int ret;
+ struct drm_device *dev = mdev->dev;
+ struct ttm_bo_device *bdev = &mdev->ttm.bdev;
+
+ ret = mgag200_ttm_global_init(mdev);
+ if (ret)
+ return ret;
+
+ ret = ttm_bo_device_init(&mdev->ttm.bdev,
+ mdev->ttm.bo_global_ref.ref.object,
+ &mgag200_bo_driver, DRM_FILE_PAGE_OFFSET,
+ true);
+ if (ret) {
+ DRM_ERROR("Error initialising bo driver; %d\n", ret);
+ return ret;
+ }
+
+ ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM, mdev->mc.vram_size >> PAGE_SHIFT);
+ if (ret) {
+ DRM_ERROR("Failed ttm VRAM init: %d\n", ret);
+ return ret;
+ }
+
+ mdev->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 0),
+ pci_resource_len(dev->pdev, 0),
+ DRM_MTRR_WC);
+
+ return 0;
+}
+
+void mgag200_mm_fini(struct mga_device *mdev)
+{
+ struct drm_device *dev = mdev->dev;
+ ttm_bo_device_release(&mdev->ttm.bdev);
+
+ mgag200_ttm_global_release(mdev);
+
+ if (mdev->fb_mtrr >= 0) {
+ drm_mtrr_del(mdev->fb_mtrr,
+ pci_resource_start(dev->pdev, 0),
+ pci_resource_len(dev->pdev, 0), DRM_MTRR_WC);
+ mdev->fb_mtrr = -1;
+ }
+}
+
+void mgag200_ttm_placement(struct mgag200_bo *bo, int domain)
+{
+ u32 c = 0;
+ bo->placement.fpfn = 0;
+ bo->placement.lpfn = 0;
+ bo->placement.placement = bo->placements;
+ bo->placement.busy_placement = bo->placements;
+ if (domain & TTM_PL_FLAG_VRAM)
+ bo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
+ if (domain & TTM_PL_FLAG_SYSTEM)
+ bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+ if (!c)
+ bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+ bo->placement.num_placement = c;
+ bo->placement.num_busy_placement = c;
+}
+
+int mgag200_bo_reserve(struct mgag200_bo *bo, bool no_wait)
+{
+ int ret;
+
+ ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0);
+ if (ret) {
+ if (ret != -ERESTARTSYS)
+ DRM_ERROR("reserve failed %p\n", bo);
+ return ret;
+ }
+ return 0;
+}
+
+void mgag200_bo_unreserve(struct mgag200_bo *bo)
+{
+ ttm_bo_unreserve(&bo->bo);
+}
+
+int mgag200_bo_create(struct drm_device *dev, int size, int align,
+ uint32_t flags, struct mgag200_bo **pmgabo)
+{
+ struct mga_device *mdev = dev->dev_private;
+ struct mgag200_bo *mgabo;
+ size_t acc_size;
+ int ret;
+
+ mgabo = kzalloc(sizeof(struct mgag200_bo), GFP_KERNEL);
+ if (!mgabo)
+ return -ENOMEM;
+
+ ret = drm_gem_object_init(dev, &mgabo->gem, size);
+ if (ret) {
+ kfree(mgabo);
+ return ret;
+ }
+
+ mgabo->gem.driver_private = NULL;
+ mgabo->bo.bdev = &mdev->ttm.bdev;
+
+ mgag200_ttm_placement(mgabo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
+
+ acc_size = ttm_bo_dma_acc_size(&mdev->ttm.bdev, size,
+ sizeof(struct mgag200_bo));
+
+ ret = ttm_bo_init(&mdev->ttm.bdev, &mgabo->bo, size,
+ ttm_bo_type_device, &mgabo->placement,
+ align >> PAGE_SHIFT, 0, false, NULL, acc_size,
+ NULL, mgag200_bo_ttm_destroy);
+ if (ret)
+ return ret;
+
+ *pmgabo = mgabo;
+ return 0;
+}
+
+static inline u64 mgag200_bo_gpu_offset(struct mgag200_bo *bo)
+{
+ return bo->bo.offset;
+}
+
+int mgag200_bo_pin(struct mgag200_bo *bo, u32 pl_flag, u64 *gpu_addr)
+{
+ int i, ret;
+
+ if (bo->pin_count) {
+ bo->pin_count++;
+ if (gpu_addr)
+ *gpu_addr = mgag200_bo_gpu_offset(bo);
+ }
+
+ mgag200_ttm_placement(bo, pl_flag);
+ for (i = 0; i < bo->placement.num_placement; i++)
+ bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
+ ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false);
+ if (ret)
+ return ret;
+
+ bo->pin_count = 1;
+ if (gpu_addr)
+ *gpu_addr = mgag200_bo_gpu_offset(bo);
+ return 0;
+}
+
+int mgag200_bo_unpin(struct mgag200_bo *bo)
+{
+ int i, ret;
+ if (!bo->pin_count) {
+ DRM_ERROR("unpin bad %p\n", bo);
+ return 0;
+ }
+ bo->pin_count--;
+ if (bo->pin_count)
+ return 0;
+
+ for (i = 0; i < bo->placement.num_placement ; i++)
+ bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT;
+ ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int mgag200_bo_push_sysram(struct mgag200_bo *bo)
+{
+ int i, ret;
+ if (!bo->pin_count) {
+ DRM_ERROR("unpin bad %p\n", bo);
+ return 0;
+ }
+ bo->pin_count--;
+ if (bo->pin_count)
+ return 0;
+
+ if (bo->kmap.virtual)
+ ttm_bo_kunmap(&bo->kmap);
+
+ mgag200_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
+ for (i = 0; i < bo->placement.num_placement ; i++)
+ bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
+
+ ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false);
+ if (ret) {
+ DRM_ERROR("pushing to VRAM failed\n");
+ return ret;
+ }
+ return 0;
+}
+
+int mgag200_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct drm_file *file_priv;
+ struct mga_device *mdev;
+
+ if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
+ return drm_mmap(filp, vma);
+
+ file_priv = filp->private_data;
+ mdev = file_priv->minor->dev->dev_private;
+ return ttm_bo_mmap(filp, vma, &mdev->ttm.bdev);
+}
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index 1a2ad7eb1734..fe5267d06ab5 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -16,10 +16,13 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
nv04_mc.o nv40_mc.o nv50_mc.o \
nv04_fb.o nv10_fb.o nv20_fb.o nv30_fb.o nv40_fb.o \
nv50_fb.o nvc0_fb.o \
- nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o nvc0_fifo.o \
+ nv04_fifo.o nv10_fifo.o nv17_fifo.o nv40_fifo.o nv50_fifo.o \
+ nv84_fifo.o nvc0_fifo.o nve0_fifo.o \
+ nv04_fence.o nv10_fence.o nv84_fence.o nvc0_fence.o \
+ nv04_software.o nv50_software.o nvc0_software.o \
nv04_graph.o nv10_graph.o nv20_graph.o \
- nv40_graph.o nv50_graph.o nvc0_graph.o \
- nv40_grctx.o nv50_grctx.o nvc0_grctx.o \
+ nv40_graph.o nv50_graph.o nvc0_graph.o nve0_graph.o \
+ nv40_grctx.o nv50_grctx.o nvc0_grctx.o nve0_grctx.o \
nv84_crypt.o nv98_crypt.o \
nva3_copy.o nvc0_copy.o \
nv31_mpeg.o nv50_mpeg.o \
@@ -37,7 +40,7 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
nv50_calc.o \
nv04_pm.o nv40_pm.o nv50_pm.o nva3_pm.o nvc0_pm.o \
nv50_vram.o nvc0_vram.o \
- nv50_vm.o nvc0_vm.o
+ nv50_vm.o nvc0_vm.o nouveau_prime.o
nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o
nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index 284bd25d5d21..fc841e87b343 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -338,7 +338,8 @@ void nouveau_switcheroo_optimus_dsm(void)
void nouveau_unregister_dsm_handler(void)
{
- vga_switcheroo_unregister_handler();
+ if (nouveau_dsm_priv.optimus_detected || nouveau_dsm_priv.dsm_detected)
+ vga_switcheroo_unregister_handler();
}
/* retrieve the ROM in 4k blocks */
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index 0be4a815e706..2f11e16a81a9 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -30,6 +30,7 @@
#include "nouveau_gpio.h"
#include <linux/io-mapping.h>
+#include <linux/firmware.h>
/* these defines are made up */
#define NV_CIO_CRE_44_HEADA 0x0
@@ -195,35 +196,24 @@ static void
bios_shadow_acpi(struct nvbios *bios)
{
struct pci_dev *pdev = bios->dev->pdev;
- int ptr, len, ret;
- u8 data[3];
+ int cnt = 65536 / ROM_BIOS_PAGE;
+ int ret;
if (!nouveau_acpi_rom_supported(pdev))
return;
- ret = nouveau_acpi_get_bios_chunk(data, 0, sizeof(data));
- if (ret != sizeof(data))
- return;
-
- bios->length = min(data[2] * 512, 65536);
- bios->data = kmalloc(bios->length, GFP_KERNEL);
+ bios->data = kmalloc(cnt * ROM_BIOS_PAGE, GFP_KERNEL);
if (!bios->data)
return;
- len = bios->length;
- ptr = 0;
- while (len) {
- int size = (len > ROM_BIOS_PAGE) ? ROM_BIOS_PAGE : len;
-
- ret = nouveau_acpi_get_bios_chunk(bios->data, ptr, size);
- if (ret != size) {
- kfree(bios->data);
- bios->data = NULL;
+ bios->length = 0;
+ while (cnt--) {
+ ret = nouveau_acpi_get_bios_chunk(bios->data, bios->length,
+ ROM_BIOS_PAGE);
+ if (ret != ROM_BIOS_PAGE)
return;
- }
- len -= size;
- ptr += size;
+ bios->length += ROM_BIOS_PAGE;
}
}
@@ -249,8 +239,12 @@ bios_shadow(struct drm_device *dev)
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nvbios *bios = &dev_priv->vbios;
struct methods *mthd, *best;
+ const struct firmware *fw;
+ char fname[32];
+ int ret;
if (nouveau_vbios) {
+ /* try to match one of the built-in methods */
mthd = shadow_methods;
do {
if (strcasecmp(nouveau_vbios, mthd->desc))
@@ -263,6 +257,22 @@ bios_shadow(struct drm_device *dev)
return true;
} while ((++mthd)->shadow);
+ /* attempt to load firmware image */
+ snprintf(fname, sizeof(fname), "nouveau/%s", nouveau_vbios);
+ ret = request_firmware(&fw, fname, &dev->pdev->dev);
+ if (ret == 0) {
+ bios->length = fw->size;
+ bios->data = kmemdup(fw->data, fw->size, GFP_KERNEL);
+ release_firmware(fw);
+
+ NV_INFO(dev, "VBIOS image: %s\n", nouveau_vbios);
+ if (score_vbios(bios, 1))
+ return true;
+
+ kfree(bios->data);
+ bios->data = NULL;
+ }
+
NV_ERROR(dev, "VBIOS source \'%s\' invalid\n", nouveau_vbios);
}
@@ -273,6 +283,7 @@ bios_shadow(struct drm_device *dev)
mthd->score = score_vbios(bios, mthd->rw);
mthd->size = bios->length;
mthd->data = bios->data;
+ bios->data = NULL;
} while (mthd->score != 3 && (++mthd)->shadow);
mthd = shadow_methods;
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 7d15a774f9c9..7f80ed523562 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -35,6 +35,8 @@
#include "nouveau_dma.h"
#include "nouveau_mm.h"
#include "nouveau_vm.h"
+#include "nouveau_fence.h"
+#include "nouveau_ramht.h"
#include <linux/log2.h>
#include <linux/slab.h>
@@ -89,12 +91,17 @@ nouveau_bo_fixup_align(struct nouveau_bo *nvbo, u32 flags,
int
nouveau_bo_new(struct drm_device *dev, int size, int align,
uint32_t flags, uint32_t tile_mode, uint32_t tile_flags,
+ struct sg_table *sg,
struct nouveau_bo **pnvbo)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_bo *nvbo;
size_t acc_size;
int ret;
+ int type = ttm_bo_type_device;
+
+ if (sg)
+ type = ttm_bo_type_sg;
nvbo = kzalloc(sizeof(struct nouveau_bo), GFP_KERNEL);
if (!nvbo)
@@ -120,8 +127,8 @@ nouveau_bo_new(struct drm_device *dev, int size, int align,
sizeof(struct nouveau_bo));
ret = ttm_bo_init(&dev_priv->ttm.bdev, &nvbo->bo, size,
- ttm_bo_type_device, &nvbo->placement,
- align >> PAGE_SHIFT, 0, false, NULL, acc_size,
+ type, &nvbo->placement,
+ align >> PAGE_SHIFT, 0, false, NULL, acc_size, sg,
nouveau_bo_del_ttm);
if (ret) {
/* ttm will call nouveau_bo_del_ttm if it fails.. */
@@ -473,7 +480,7 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan,
struct nouveau_fence *fence = NULL;
int ret;
- ret = nouveau_fence_new(chan, &fence, true);
+ ret = nouveau_fence_new(chan, &fence);
if (ret)
return ret;
@@ -484,6 +491,76 @@ nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan,
}
static int
+nve0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
+ struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
+{
+ struct nouveau_mem *node = old_mem->mm_node;
+ int ret = RING_SPACE(chan, 10);
+ if (ret == 0) {
+ BEGIN_NVC0(chan, NvSubCopy, 0x0400, 8);
+ OUT_RING (chan, upper_32_bits(node->vma[0].offset));
+ OUT_RING (chan, lower_32_bits(node->vma[0].offset));
+ OUT_RING (chan, upper_32_bits(node->vma[1].offset));
+ OUT_RING (chan, lower_32_bits(node->vma[1].offset));
+ OUT_RING (chan, PAGE_SIZE);
+ OUT_RING (chan, PAGE_SIZE);
+ OUT_RING (chan, PAGE_SIZE);
+ OUT_RING (chan, new_mem->num_pages);
+ BEGIN_IMC0(chan, NvSubCopy, 0x0300, 0x0386);
+ }
+ return ret;
+}
+
+static int
+nvc0_bo_move_init(struct nouveau_channel *chan, u32 handle)
+{
+ int ret = RING_SPACE(chan, 2);
+ if (ret == 0) {
+ BEGIN_NVC0(chan, NvSubCopy, 0x0000, 1);
+ OUT_RING (chan, handle);
+ }
+ return ret;
+}
+
+static int
+nvc0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
+ struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
+{
+ struct nouveau_mem *node = old_mem->mm_node;
+ u64 src_offset = node->vma[0].offset;
+ u64 dst_offset = node->vma[1].offset;
+ u32 page_count = new_mem->num_pages;
+ int ret;
+
+ page_count = new_mem->num_pages;
+ while (page_count) {
+ int line_count = (page_count > 8191) ? 8191 : page_count;
+
+ ret = RING_SPACE(chan, 11);
+ if (ret)
+ return ret;
+
+ BEGIN_NVC0(chan, NvSubCopy, 0x030c, 8);
+ OUT_RING (chan, upper_32_bits(src_offset));
+ OUT_RING (chan, lower_32_bits(src_offset));
+ OUT_RING (chan, upper_32_bits(dst_offset));
+ OUT_RING (chan, lower_32_bits(dst_offset));
+ OUT_RING (chan, PAGE_SIZE);
+ OUT_RING (chan, PAGE_SIZE);
+ OUT_RING (chan, PAGE_SIZE);
+ OUT_RING (chan, line_count);
+ BEGIN_NVC0(chan, NvSubCopy, 0x0300, 1);
+ OUT_RING (chan, 0x00000110);
+
+ page_count -= line_count;
+ src_offset += (PAGE_SIZE * line_count);
+ dst_offset += (PAGE_SIZE * line_count);
+ }
+
+ return 0;
+}
+
+static int
nvc0_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
{
@@ -501,17 +578,17 @@ nvc0_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
if (ret)
return ret;
- BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0238, 2);
+ BEGIN_NVC0(chan, NvSubCopy, 0x0238, 2);
OUT_RING (chan, upper_32_bits(dst_offset));
OUT_RING (chan, lower_32_bits(dst_offset));
- BEGIN_NVC0(chan, 2, NvSubM2MF, 0x030c, 6);
+ BEGIN_NVC0(chan, NvSubCopy, 0x030c, 6);
OUT_RING (chan, upper_32_bits(src_offset));
OUT_RING (chan, lower_32_bits(src_offset));
OUT_RING (chan, PAGE_SIZE); /* src_pitch */
OUT_RING (chan, PAGE_SIZE); /* dst_pitch */
OUT_RING (chan, PAGE_SIZE); /* line_length */
OUT_RING (chan, line_count);
- BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0300, 1);
+ BEGIN_NVC0(chan, NvSubCopy, 0x0300, 1);
OUT_RING (chan, 0x00100110);
page_count -= line_count;
@@ -523,6 +600,102 @@ nvc0_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
}
static int
+nva3_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
+ struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
+{
+ struct nouveau_mem *node = old_mem->mm_node;
+ u64 src_offset = node->vma[0].offset;
+ u64 dst_offset = node->vma[1].offset;
+ u32 page_count = new_mem->num_pages;
+ int ret;
+
+ page_count = new_mem->num_pages;
+ while (page_count) {
+ int line_count = (page_count > 8191) ? 8191 : page_count;
+
+ ret = RING_SPACE(chan, 11);
+ if (ret)
+ return ret;
+
+ BEGIN_NV04(chan, NvSubCopy, 0x030c, 8);
+ OUT_RING (chan, upper_32_bits(src_offset));
+ OUT_RING (chan, lower_32_bits(src_offset));
+ OUT_RING (chan, upper_32_bits(dst_offset));
+ OUT_RING (chan, lower_32_bits(dst_offset));
+ OUT_RING (chan, PAGE_SIZE);
+ OUT_RING (chan, PAGE_SIZE);
+ OUT_RING (chan, PAGE_SIZE);
+ OUT_RING (chan, line_count);
+ BEGIN_NV04(chan, NvSubCopy, 0x0300, 1);
+ OUT_RING (chan, 0x00000110);
+
+ page_count -= line_count;
+ src_offset += (PAGE_SIZE * line_count);
+ dst_offset += (PAGE_SIZE * line_count);
+ }
+
+ return 0;
+}
+
+static int
+nv98_bo_move_exec(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
+ struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
+{
+ struct nouveau_mem *node = old_mem->mm_node;
+ int ret = RING_SPACE(chan, 7);
+ if (ret == 0) {
+ BEGIN_NV04(chan, NvSubCopy, 0x0320, 6);
+ OUT_RING (chan, upper_32_bits(node->vma[0].offset));
+ OUT_RING (chan, lower_32_bits(node->vma[0].offset));
+ OUT_RING (chan, upper_32_bits(node->vma[1].offset));
+ OUT_RING (chan, lower_32_bits(node->vma[1].offset));
+ OUT_RING (chan, 0x00000000 /* COPY */);
+ OUT_RING (chan, new_mem->num_pages << PAGE_SHIFT);
+ }
+ return ret;
+}
+
+static int
+nv84_bo_move_exec(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
+ struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
+{
+ struct nouveau_mem *node = old_mem->mm_node;
+ int ret = RING_SPACE(chan, 7);
+ if (ret == 0) {
+ BEGIN_NV04(chan, NvSubCopy, 0x0304, 6);
+ OUT_RING (chan, new_mem->num_pages << PAGE_SHIFT);
+ OUT_RING (chan, upper_32_bits(node->vma[0].offset));
+ OUT_RING (chan, lower_32_bits(node->vma[0].offset));
+ OUT_RING (chan, upper_32_bits(node->vma[1].offset));
+ OUT_RING (chan, lower_32_bits(node->vma[1].offset));
+ OUT_RING (chan, 0x00000000 /* MODE_COPY, QUERY_NONE */);
+ }
+ return ret;
+}
+
+static int
+nv50_bo_move_init(struct nouveau_channel *chan, u32 handle)
+{
+ int ret = nouveau_notifier_alloc(chan, NvNotify0, 32, 0xfe0, 0x1000,
+ &chan->m2mf_ntfy);
+ if (ret == 0) {
+ ret = RING_SPACE(chan, 6);
+ if (ret == 0) {
+ BEGIN_NV04(chan, NvSubCopy, 0x0000, 1);
+ OUT_RING (chan, handle);
+ BEGIN_NV04(chan, NvSubCopy, 0x0180, 3);
+ OUT_RING (chan, NvNotify0);
+ OUT_RING (chan, NvDmaFB);
+ OUT_RING (chan, NvDmaFB);
+ } else {
+ nouveau_ramht_remove(chan, NvNotify0);
+ }
+ }
+
+ return ret;
+}
+
+static int
nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
{
@@ -546,7 +719,7 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
if (ret)
return ret;
- BEGIN_RING(chan, NvSubM2MF, 0x0200, 7);
+ BEGIN_NV04(chan, NvSubCopy, 0x0200, 7);
OUT_RING (chan, 0);
OUT_RING (chan, 0);
OUT_RING (chan, stride);
@@ -559,7 +732,7 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
if (ret)
return ret;
- BEGIN_RING(chan, NvSubM2MF, 0x0200, 1);
+ BEGIN_NV04(chan, NvSubCopy, 0x0200, 1);
OUT_RING (chan, 1);
}
if (old_mem->mem_type == TTM_PL_VRAM &&
@@ -568,7 +741,7 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
if (ret)
return ret;
- BEGIN_RING(chan, NvSubM2MF, 0x021c, 7);
+ BEGIN_NV04(chan, NvSubCopy, 0x021c, 7);
OUT_RING (chan, 0);
OUT_RING (chan, 0);
OUT_RING (chan, stride);
@@ -581,7 +754,7 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
if (ret)
return ret;
- BEGIN_RING(chan, NvSubM2MF, 0x021c, 1);
+ BEGIN_NV04(chan, NvSubCopy, 0x021c, 1);
OUT_RING (chan, 1);
}
@@ -589,10 +762,10 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
if (ret)
return ret;
- BEGIN_RING(chan, NvSubM2MF, 0x0238, 2);
+ BEGIN_NV04(chan, NvSubCopy, 0x0238, 2);
OUT_RING (chan, upper_32_bits(src_offset));
OUT_RING (chan, upper_32_bits(dst_offset));
- BEGIN_RING(chan, NvSubM2MF, 0x030c, 8);
+ BEGIN_NV04(chan, NvSubCopy, 0x030c, 8);
OUT_RING (chan, lower_32_bits(src_offset));
OUT_RING (chan, lower_32_bits(dst_offset));
OUT_RING (chan, stride);
@@ -601,7 +774,7 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
OUT_RING (chan, height);
OUT_RING (chan, 0x00000101);
OUT_RING (chan, 0x00000000);
- BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NOP, 1);
+ BEGIN_NV04(chan, NvSubCopy, NV_MEMORY_TO_MEMORY_FORMAT_NOP, 1);
OUT_RING (chan, 0);
length -= amount;
@@ -612,6 +785,24 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
return 0;
}
+static int
+nv04_bo_move_init(struct nouveau_channel *chan, u32 handle)
+{
+ int ret = nouveau_notifier_alloc(chan, NvNotify0, 32, 0xfe0, 0x1000,
+ &chan->m2mf_ntfy);
+ if (ret == 0) {
+ ret = RING_SPACE(chan, 4);
+ if (ret == 0) {
+ BEGIN_NV04(chan, NvSubCopy, 0x0000, 1);
+ OUT_RING (chan, handle);
+ BEGIN_NV04(chan, NvSubCopy, 0x0180, 1);
+ OUT_RING (chan, NvNotify0);
+ }
+ }
+
+ return ret;
+}
+
static inline uint32_t
nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo,
struct nouveau_channel *chan, struct ttm_mem_reg *mem)
@@ -634,7 +825,7 @@ nv04_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
if (ret)
return ret;
- BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_SOURCE, 2);
+ BEGIN_NV04(chan, NvSubCopy, NV_MEMORY_TO_MEMORY_FORMAT_DMA_SOURCE, 2);
OUT_RING (chan, nouveau_bo_mem_ctxdma(bo, chan, old_mem));
OUT_RING (chan, nouveau_bo_mem_ctxdma(bo, chan, new_mem));
@@ -646,7 +837,7 @@ nv04_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
if (ret)
return ret;
- BEGIN_RING(chan, NvSubM2MF,
+ BEGIN_NV04(chan, NvSubCopy,
NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
OUT_RING (chan, src_offset);
OUT_RING (chan, dst_offset);
@@ -656,7 +847,7 @@ nv04_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
OUT_RING (chan, line_count);
OUT_RING (chan, 0x00000101);
OUT_RING (chan, 0x00000000);
- BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NOP, 1);
+ BEGIN_NV04(chan, NvSubCopy, NV_MEMORY_TO_MEMORY_FORMAT_NOP, 1);
OUT_RING (chan, 0);
page_count -= line_count;
@@ -716,13 +907,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
goto out;
}
- if (dev_priv->card_type < NV_50)
- ret = nv04_bo_move_m2mf(chan, bo, &bo->mem, new_mem);
- else
- if (dev_priv->card_type < NV_C0)
- ret = nv50_bo_move_m2mf(chan, bo, &bo->mem, new_mem);
- else
- ret = nvc0_bo_move_m2mf(chan, bo, &bo->mem, new_mem);
+ ret = dev_priv->ttm.move(chan, bo, &bo->mem, new_mem);
if (ret == 0) {
ret = nouveau_bo_move_accel_cleanup(chan, nvbo, evict,
no_wait_reserve,
@@ -734,6 +919,49 @@ out:
return ret;
}
+void
+nouveau_bo_move_init(struct nouveau_channel *chan)
+{
+ struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+ static const struct {
+ const char *name;
+ int engine;
+ u32 oclass;
+ int (*exec)(struct nouveau_channel *,
+ struct ttm_buffer_object *,
+ struct ttm_mem_reg *, struct ttm_mem_reg *);
+ int (*init)(struct nouveau_channel *, u32 handle);
+ } _methods[] = {
+ { "COPY", 0, 0xa0b5, nve0_bo_move_copy, nvc0_bo_move_init },
+ { "COPY1", 5, 0x90b8, nvc0_bo_move_copy, nvc0_bo_move_init },
+ { "COPY0", 4, 0x90b5, nvc0_bo_move_copy, nvc0_bo_move_init },
+ { "COPY", 0, 0x85b5, nva3_bo_move_copy, nv50_bo_move_init },
+ { "CRYPT", 0, 0x74c1, nv84_bo_move_exec, nv50_bo_move_init },
+ { "M2MF", 0, 0x9039, nvc0_bo_move_m2mf, nvc0_bo_move_init },
+ { "M2MF", 0, 0x5039, nv50_bo_move_m2mf, nv50_bo_move_init },
+ { "M2MF", 0, 0x0039, nv04_bo_move_m2mf, nv04_bo_move_init },
+ {},
+ { "CRYPT", 0, 0x88b4, nv98_bo_move_exec, nv50_bo_move_init },
+ }, *mthd = _methods;
+ const char *name = "CPU";
+ int ret;
+
+ do {
+ u32 handle = (mthd->engine << 16) | mthd->oclass;
+ ret = nouveau_gpuobj_gr_new(chan, handle, mthd->oclass);
+ if (ret == 0) {
+ ret = mthd->init(chan, handle);
+ if (ret == 0) {
+ dev_priv->ttm.move = mthd->exec;
+ name = mthd->name;
+ break;
+ }
+ }
+ } while ((++mthd)->exec);
+
+ NV_INFO(chan->dev, "MM: using %s for buffer copies\n", name);
+}
+
static int
nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr,
bool no_wait_reserve, bool no_wait_gpu,
@@ -817,9 +1045,14 @@ nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem)
} else
if (new_mem && new_mem->mem_type == TTM_PL_TT &&
nvbo->page_shift == vma->vm->spg_shift) {
- nouveau_vm_map_sg(vma, 0, new_mem->
- num_pages << PAGE_SHIFT,
- new_mem->mm_node);
+ if (((struct nouveau_mem *)new_mem->mm_node)->sg)
+ nouveau_vm_map_sg_table(vma, 0, new_mem->
+ num_pages << PAGE_SHIFT,
+ new_mem->mm_node);
+ else
+ nouveau_vm_map_sg(vma, 0, new_mem->
+ num_pages << PAGE_SHIFT,
+ new_mem->mm_node);
} else {
nouveau_vm_unmap(vma);
}
@@ -885,8 +1118,8 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr,
goto out;
}
- /* Software copy if the card isn't up and running yet. */
- if (!dev_priv->channel) {
+ /* CPU copy if we have no accelerated method available */
+ if (!dev_priv->ttm.move) {
ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
goto out;
}
@@ -1030,26 +1263,10 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
nvbo->placement.fpfn = 0;
nvbo->placement.lpfn = dev_priv->fb_mappable_pages;
- nouveau_bo_placement_set(nvbo, TTM_PL_VRAM, 0);
+ nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_VRAM, 0);
return nouveau_bo_validate(nvbo, false, true, false);
}
-void
-nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence)
-{
- struct nouveau_fence *old_fence;
-
- if (likely(fence))
- nouveau_fence_ref(fence);
-
- spin_lock(&nvbo->bo.bdev->fence_lock);
- old_fence = nvbo->bo.sync_obj;
- nvbo->bo.sync_obj = fence;
- spin_unlock(&nvbo->bo.bdev->fence_lock);
-
- nouveau_fence_unref(&old_fence);
-}
-
static int
nouveau_ttm_tt_populate(struct ttm_tt *ttm)
{
@@ -1058,10 +1275,19 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm)
struct drm_device *dev;
unsigned i;
int r;
+ bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
if (ttm->state != tt_unpopulated)
return 0;
+ if (slave && ttm->sg) {
+ /* make userspace faulting work */
+ drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages,
+ ttm_dma->dma_address, ttm->num_pages);
+ ttm->state = tt_unbound;
+ return 0;
+ }
+
dev_priv = nouveau_bdev(ttm->bdev);
dev = dev_priv->dev;
@@ -1106,6 +1332,10 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
struct drm_nouveau_private *dev_priv;
struct drm_device *dev;
unsigned i;
+ bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
+
+ if (slave)
+ return;
dev_priv = nouveau_bdev(ttm->bdev);
dev = dev_priv->dev;
@@ -1134,6 +1364,52 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
ttm_pool_unpopulate(ttm);
}
+void
+nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence)
+{
+ struct nouveau_fence *old_fence = NULL;
+
+ if (likely(fence))
+ nouveau_fence_ref(fence);
+
+ spin_lock(&nvbo->bo.bdev->fence_lock);
+ old_fence = nvbo->bo.sync_obj;
+ nvbo->bo.sync_obj = fence;
+ spin_unlock(&nvbo->bo.bdev->fence_lock);
+
+ nouveau_fence_unref(&old_fence);
+}
+
+static void
+nouveau_bo_fence_unref(void **sync_obj)
+{
+ nouveau_fence_unref((struct nouveau_fence **)sync_obj);
+}
+
+static void *
+nouveau_bo_fence_ref(void *sync_obj)
+{
+ return nouveau_fence_ref(sync_obj);
+}
+
+static bool
+nouveau_bo_fence_signalled(void *sync_obj, void *sync_arg)
+{
+ return nouveau_fence_done(sync_obj);
+}
+
+static int
+nouveau_bo_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr)
+{
+ return nouveau_fence_wait(sync_obj, lazy, intr);
+}
+
+static int
+nouveau_bo_fence_flush(void *sync_obj, void *sync_arg)
+{
+ return 0;
+}
+
struct ttm_bo_driver nouveau_bo_driver = {
.ttm_tt_create = &nouveau_ttm_tt_create,
.ttm_tt_populate = &nouveau_ttm_tt_populate,
@@ -1144,11 +1420,11 @@ struct ttm_bo_driver nouveau_bo_driver = {
.move_notify = nouveau_bo_move_ntfy,
.move = nouveau_bo_move,
.verify_access = nouveau_bo_verify_access,
- .sync_obj_signaled = __nouveau_fence_signalled,
- .sync_obj_wait = __nouveau_fence_wait,
- .sync_obj_flush = __nouveau_fence_flush,
- .sync_obj_unref = __nouveau_fence_unref,
- .sync_obj_ref = __nouveau_fence_ref,
+ .sync_obj_signaled = nouveau_bo_fence_signalled,
+ .sync_obj_wait = nouveau_bo_fence_wait,
+ .sync_obj_flush = nouveau_bo_fence_flush,
+ .sync_obj_unref = nouveau_bo_fence_unref,
+ .sync_obj_ref = nouveau_bo_fence_ref,
.fault_reserve_notify = &nouveau_ttm_fault_reserve_notify,
.io_mem_reserve = &nouveau_ttm_io_mem_reserve,
.io_mem_free = &nouveau_ttm_io_mem_free,
@@ -1181,9 +1457,12 @@ nouveau_bo_vma_add(struct nouveau_bo *nvbo, struct nouveau_vm *vm,
if (nvbo->bo.mem.mem_type == TTM_PL_VRAM)
nouveau_vm_map(vma, nvbo->bo.mem.mm_node);
- else
- if (nvbo->bo.mem.mem_type == TTM_PL_TT)
- nouveau_vm_map_sg(vma, 0, size, node);
+ else if (nvbo->bo.mem.mem_type == TTM_PL_TT) {
+ if (node->sg)
+ nouveau_vm_map_sg_table(vma, 0, size, node);
+ else
+ nouveau_vm_map_sg(vma, 0, size, node);
+ }
list_add_tail(&vma->head, &nvbo->vma_list);
vma->refcount = 1;
diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c
index 846afb0bfef4..629d8a2df5bd 100644
--- a/drivers/gpu/drm/nouveau/nouveau_channel.c
+++ b/drivers/gpu/drm/nouveau/nouveau_channel.c
@@ -27,7 +27,10 @@
#include "nouveau_drv.h"
#include "nouveau_drm.h"
#include "nouveau_dma.h"
+#include "nouveau_fifo.h"
#include "nouveau_ramht.h"
+#include "nouveau_fence.h"
+#include "nouveau_software.h"
static int
nouveau_channel_pushbuf_init(struct nouveau_channel *chan)
@@ -38,7 +41,7 @@ nouveau_channel_pushbuf_init(struct nouveau_channel *chan)
int ret;
/* allocate buffer object */
- ret = nouveau_bo_new(dev, 65536, 0, mem, 0, 0, &chan->pushbuf_bo);
+ ret = nouveau_bo_new(dev, 65536, 0, mem, 0, 0, NULL, &chan->pushbuf_bo);
if (ret)
goto out;
@@ -117,8 +120,9 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
struct drm_file *file_priv,
uint32_t vram_handle, uint32_t gart_handle)
{
+ struct nouveau_exec_engine *fence = nv_engine(dev, NVOBJ_ENGINE_FENCE);
+ struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv);
struct nouveau_channel *chan;
unsigned long flags;
@@ -155,10 +159,6 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
}
NV_DEBUG(dev, "initialising channel %d\n", chan->id);
- INIT_LIST_HEAD(&chan->nvsw.vbl_wait);
- INIT_LIST_HEAD(&chan->nvsw.flip);
- INIT_LIST_HEAD(&chan->fence.pending);
- spin_lock_init(&chan->fence.lock);
/* setup channel's memory and vm */
ret = nouveau_gpuobj_channel_init(chan, vram_handle, gart_handle);
@@ -188,20 +188,15 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
chan->user_put = 0x40;
chan->user_get = 0x44;
if (dev_priv->card_type >= NV_50)
- chan->user_get_hi = 0x60;
+ chan->user_get_hi = 0x60;
- /* disable the fifo caches */
- pfifo->reassign(dev, false);
-
- /* Construct initial RAMFC for new channel */
- ret = pfifo->create_context(chan);
+ /* create fifo context */
+ ret = pfifo->base.context_new(chan, NVOBJ_ENGINE_FIFO);
if (ret) {
nouveau_channel_put(&chan);
return ret;
}
- pfifo->reassign(dev, true);
-
/* Insert NOPs for NOUVEAU_DMA_SKIPS */
ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS);
if (ret) {
@@ -211,9 +206,28 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret,
for (i = 0; i < NOUVEAU_DMA_SKIPS; i++)
OUT_RING (chan, 0x00000000);
+
+ ret = nouveau_gpuobj_gr_new(chan, NvSw, nouveau_software_class(dev));
+ if (ret) {
+ nouveau_channel_put(&chan);
+ return ret;
+ }
+
+ if (dev_priv->card_type < NV_C0) {
+ ret = RING_SPACE(chan, 2);
+ if (ret) {
+ nouveau_channel_put(&chan);
+ return ret;
+ }
+
+ BEGIN_NV04(chan, NvSubSw, NV01_SUBCHAN_OBJECT, 1);
+ OUT_RING (chan, NvSw);
+ FIRE_RING (chan);
+ }
+
FIRE_RING(chan);
- ret = nouveau_fence_channel_init(chan);
+ ret = fence->context_new(chan, NVOBJ_ENGINE_FENCE);
if (ret) {
nouveau_channel_put(&chan);
return ret;
@@ -268,7 +282,6 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan)
struct nouveau_channel *chan = *pchan;
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
unsigned long flags;
int i;
@@ -285,24 +298,12 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan)
/* give it chance to idle */
nouveau_channel_idle(chan);
- /* ensure all outstanding fences are signaled. they should be if the
- * above attempts at idling were OK, but if we failed this'll tell TTM
- * we're done with the buffers.
- */
- nouveau_fence_channel_fini(chan);
-
- /* boot it off the hardware */
- pfifo->reassign(dev, false);
-
/* destroy the engine specific contexts */
- pfifo->destroy_context(chan);
- for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
+ for (i = NVOBJ_ENGINE_NR - 1; i >= 0; i--) {
if (chan->engctx[i])
dev_priv->eng[i]->context_del(chan, i);
}
- pfifo->reassign(dev, true);
-
/* aside from its resources, the channel should now be dead,
* remove it from the channel list
*/
@@ -354,38 +355,37 @@ nouveau_channel_ref(struct nouveau_channel *chan,
*pchan = chan;
}
-void
+int
nouveau_channel_idle(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct nouveau_fence *fence = NULL;
int ret;
- nouveau_fence_update(chan);
-
- if (chan->fence.sequence != chan->fence.sequence_ack) {
- ret = nouveau_fence_new(chan, &fence, true);
- if (!ret) {
- ret = nouveau_fence_wait(fence, false, false);
- nouveau_fence_unref(&fence);
- }
-
- if (ret)
- NV_ERROR(dev, "Failed to idle channel %d.\n", chan->id);
+ ret = nouveau_fence_new(chan, &fence);
+ if (!ret) {
+ ret = nouveau_fence_wait(fence, false, false);
+ nouveau_fence_unref(&fence);
}
+
+ if (ret)
+ NV_ERROR(dev, "Failed to idle channel %d.\n", chan->id);
+ return ret;
}
/* cleans up all the fifos from file_priv */
void
nouveau_channel_cleanup(struct drm_device *dev, struct drm_file *file_priv)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_engine *engine = &dev_priv->engine;
+ struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct nouveau_channel *chan;
int i;
+ if (!pfifo)
+ return;
+
NV_DEBUG(dev, "clearing FIFO enables from file_priv\n");
- for (i = 0; i < engine->fifo.channels; i++) {
+ for (i = 0; i < pfifo->channels; i++) {
chan = nouveau_channel_get(file_priv, i);
if (IS_ERR(chan))
continue;
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index fa860358add1..7b11edb077d0 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -654,7 +654,13 @@ nouveau_connector_detect_depth(struct drm_connector *connector)
if (nv_connector->edid && connector->display_info.bpc)
return;
- /* if not, we're out of options unless we're LVDS, default to 8bpc */
+ /* EDID 1.4 is *supposed* to be supported on eDP, but, Apple... */
+ if (nv_connector->type == DCB_CONNECTOR_eDP) {
+ connector->display_info.bpc = 6;
+ return;
+ }
+
+ /* we're out of options unless we're LVDS, default to 8bpc */
if (nv_encoder->dcb->type != OUTPUT_LVDS) {
connector->display_info.bpc = 8;
return;
diff --git a/drivers/gpu/drm/nouveau/nouveau_debugfs.c b/drivers/gpu/drm/nouveau/nouveau_debugfs.c
index fa2ec491f6a7..188c92b327e2 100644
--- a/drivers/gpu/drm/nouveau/nouveau_debugfs.c
+++ b/drivers/gpu/drm/nouveau/nouveau_debugfs.c
@@ -67,8 +67,6 @@ nouveau_debugfs_channel_info(struct seq_file *m, void *data)
nvchan_rd32(chan, 0x8c));
}
- seq_printf(m, "last fence : %d\n", chan->fence.sequence);
- seq_printf(m, "last signalled: %d\n", chan->fence.sequence_ack);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index a85e112863d1..69688ef5cf46 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -33,7 +33,9 @@
#include "nouveau_crtc.h"
#include "nouveau_dma.h"
#include "nouveau_connector.h"
+#include "nouveau_software.h"
#include "nouveau_gpio.h"
+#include "nouveau_fence.h"
#include "nv50_display.h"
static void
@@ -300,7 +302,7 @@ nouveau_display_create(struct drm_device *dev)
disp->color_vibrance_property->values[1] = 200; /* -100..+100 */
}
- dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs;
+ dev->mode_config.funcs = &nouveau_mode_config_funcs;
dev->mode_config.fb_base = pci_resource_start(dev->pdev, 1);
dev->mode_config.min_width = 0;
@@ -325,14 +327,21 @@ nouveau_display_create(struct drm_device *dev)
ret = disp->create(dev);
if (ret)
- return ret;
+ goto disp_create_err;
if (dev->mode_config.num_crtc) {
ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
if (ret)
- return ret;
+ goto vblank_err;
}
+ return 0;
+
+vblank_err:
+ disp->destroy(dev);
+disp_create_err:
+ drm_kms_helper_poll_fini(dev);
+ drm_mode_config_cleanup(dev);
return ret;
}
@@ -425,6 +434,7 @@ nouveau_page_flip_emit(struct nouveau_channel *chan,
struct nouveau_page_flip_state *s,
struct nouveau_fence **pfence)
{
+ struct nouveau_software_chan *swch = chan->engctx[NVOBJ_ENGINE_SW];
struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
struct drm_device *dev = chan->dev;
unsigned long flags;
@@ -432,7 +442,7 @@ nouveau_page_flip_emit(struct nouveau_channel *chan,
/* Queue it to the pending list */
spin_lock_irqsave(&dev->event_lock, flags);
- list_add_tail(&s->head, &chan->nvsw.flip);
+ list_add_tail(&s->head, &swch->flip);
spin_unlock_irqrestore(&dev->event_lock, flags);
/* Synchronize with the old framebuffer */
@@ -446,17 +456,17 @@ nouveau_page_flip_emit(struct nouveau_channel *chan,
goto fail;
if (dev_priv->card_type < NV_C0) {
- BEGIN_RING(chan, NvSubSw, NV_SW_PAGE_FLIP, 1);
+ BEGIN_NV04(chan, NvSubSw, NV_SW_PAGE_FLIP, 1);
OUT_RING (chan, 0x00000000);
OUT_RING (chan, 0x00000000);
} else {
- BEGIN_NVC0(chan, 2, 0, NV10_SUBCHAN_REF_CNT, 1);
- OUT_RING (chan, ++chan->fence.sequence);
- BEGIN_NVC0(chan, 8, 0, NVSW_SUBCHAN_PAGE_FLIP, 0x0000);
+ BEGIN_NVC0(chan, 0, NV10_SUBCHAN_REF_CNT, 1);
+ OUT_RING (chan, 0);
+ BEGIN_IMC0(chan, 0, NVSW_SUBCHAN_PAGE_FLIP, 0x0000);
}
FIRE_RING (chan);
- ret = nouveau_fence_new(chan, pfence, true);
+ ret = nouveau_fence_new(chan, pfence);
if (ret)
goto fail;
@@ -477,7 +487,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo;
struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo;
struct nouveau_page_flip_state *s;
- struct nouveau_channel *chan;
+ struct nouveau_channel *chan = NULL;
struct nouveau_fence *fence;
int ret;
@@ -500,7 +510,9 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
new_bo->bo.offset };
/* Choose the channel the flip will be handled in */
- chan = nouveau_fence_channel(new_bo->bo.sync_obj);
+ fence = new_bo->bo.sync_obj;
+ if (fence)
+ chan = nouveau_channel_get_unlocked(fence->channel);
if (!chan)
chan = nouveau_channel_get_unlocked(dev_priv->channel);
mutex_lock(&chan->mutex);
@@ -540,20 +552,20 @@ int
nouveau_finish_page_flip(struct nouveau_channel *chan,
struct nouveau_page_flip_state *ps)
{
+ struct nouveau_software_chan *swch = chan->engctx[NVOBJ_ENGINE_SW];
struct drm_device *dev = chan->dev;
struct nouveau_page_flip_state *s;
unsigned long flags;
spin_lock_irqsave(&dev->event_lock, flags);
- if (list_empty(&chan->nvsw.flip)) {
+ if (list_empty(&swch->flip)) {
NV_ERROR(dev, "Unexpected pageflip in channel %d.\n", chan->id);
spin_unlock_irqrestore(&dev->event_lock, flags);
return -EINVAL;
}
- s = list_first_entry(&chan->nvsw.flip,
- struct nouveau_page_flip_state, head);
+ s = list_first_entry(&swch->flip, struct nouveau_page_flip_state, head);
if (s->event) {
struct drm_pending_vblank_event *e = s->event;
struct timeval now;
diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.h b/drivers/gpu/drm/nouveau/nouveau_dma.h
index 23d4edf992b7..8db68be9544f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dma.h
+++ b/drivers/gpu/drm/nouveau/nouveau_dma.h
@@ -48,12 +48,12 @@ void nv50_dma_push(struct nouveau_channel *, struct nouveau_bo *,
/* Hardcoded object assignments to subchannels (subchannel id). */
enum {
- NvSubM2MF = 0,
+ NvSubCtxSurf2D = 0,
NvSubSw = 1,
- NvSub2D = 2,
- NvSubCtxSurf2D = 2,
+ NvSubImageBlit = 2,
+ NvSub2D = 3,
NvSubGdiRect = 3,
- NvSubImageBlit = 4
+ NvSubCopy = 4,
};
/* Object handles. */
@@ -73,6 +73,7 @@ enum {
NvSema = 0x8000000f,
NvEvoSema0 = 0x80000010,
NvEvoSema1 = 0x80000011,
+ NvNotify1 = 0x80000012,
/* G80+ display objects */
NvEvoVRAM = 0x01000000,
@@ -127,15 +128,33 @@ extern void
OUT_RINGp(struct nouveau_channel *chan, const void *data, unsigned nr_dwords);
static inline void
-BEGIN_NVC0(struct nouveau_channel *chan, int op, int subc, int mthd, int size)
+BEGIN_NV04(struct nouveau_channel *chan, int subc, int mthd, int size)
{
- OUT_RING(chan, (op << 28) | (size << 16) | (subc << 13) | (mthd >> 2));
+ OUT_RING(chan, 0x00000000 | (subc << 13) | (size << 18) | mthd);
}
static inline void
-BEGIN_RING(struct nouveau_channel *chan, int subc, int mthd, int size)
+BEGIN_NI04(struct nouveau_channel *chan, int subc, int mthd, int size)
{
- OUT_RING(chan, (subc << 13) | (size << 18) | mthd);
+ OUT_RING(chan, 0x40000000 | (subc << 13) | (size << 18) | mthd);
+}
+
+static inline void
+BEGIN_NVC0(struct nouveau_channel *chan, int subc, int mthd, int size)
+{
+ OUT_RING(chan, 0x20000000 | (size << 16) | (subc << 13) | (mthd >> 2));
+}
+
+static inline void
+BEGIN_NIC0(struct nouveau_channel *chan, int subc, int mthd, int size)
+{
+ OUT_RING(chan, 0x60000000 | (size << 16) | (subc << 13) | (mthd >> 2));
+}
+
+static inline void
+BEGIN_IMC0(struct nouveau_channel *chan, int subc, int mthd, u16 data)
+{
+ OUT_RING(chan, 0x80000000 | (data << 16) | (subc << 13) | (mthd >> 2));
}
#define WRITE_PUT(val) do { \
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index d996134b1b28..7e289d2ad8e4 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -510,6 +510,25 @@ nouveau_dp_dpms(struct drm_encoder *encoder, int mode, u32 datarate,
nouveau_dp_link_train(encoder, datarate, func);
}
+static void
+nouveau_dp_probe_oui(struct drm_device *dev, struct nouveau_i2c_chan *auxch,
+ u8 *dpcd)
+{
+ u8 buf[3];
+
+ if (!(dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT))
+ return;
+
+ if (!auxch_tx(dev, auxch->drive, 9, DP_SINK_OUI, buf, 3))
+ NV_DEBUG_KMS(dev, "Sink OUI: %02hx%02hx%02hx\n",
+ buf[0], buf[1], buf[2]);
+
+ if (!auxch_tx(dev, auxch->drive, 9, DP_BRANCH_OUI, buf, 3))
+ NV_DEBUG_KMS(dev, "Branch OUI: %02hx%02hx%02hx\n",
+ buf[0], buf[1], buf[2]);
+
+}
+
bool
nouveau_dp_detect(struct drm_encoder *encoder)
{
@@ -544,6 +563,8 @@ nouveau_dp_detect(struct drm_encoder *encoder)
NV_DEBUG_KMS(dev, "maximum: %dx%d\n",
nv_encoder->dp.link_nr, nv_encoder->dp.link_bw);
+ nouveau_dp_probe_oui(dev, auxch, dpcd);
+
return true;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index 4f2030bd5676..cad254c8e387 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -33,6 +33,7 @@
#include "nouveau_fb.h"
#include "nouveau_fbcon.h"
#include "nouveau_pm.h"
+#include "nouveau_fifo.h"
#include "nv50_display.h"
#include "drm_pciids.h"
@@ -175,7 +176,7 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
struct drm_device *dev = pci_get_drvdata(pdev);
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+ struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct nouveau_channel *chan;
struct drm_crtc *crtc;
int ret, i, e;
@@ -214,17 +215,13 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
ttm_bo_evict_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
NV_INFO(dev, "Idling channels...\n");
- for (i = 0; i < pfifo->channels; i++) {
+ for (i = 0; i < (pfifo ? pfifo->channels : 0); i++) {
chan = dev_priv->channels.ptr[i];
if (chan && chan->pushbuf_bo)
nouveau_channel_idle(chan);
}
- pfifo->reassign(dev, false);
- pfifo->disable(dev);
- pfifo->unload_context(dev);
-
for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
if (!dev_priv->eng[e])
continue;
@@ -265,8 +262,6 @@ out_abort:
if (dev_priv->eng[e])
dev_priv->eng[e]->init(dev, e);
}
- pfifo->enable(dev);
- pfifo->reassign(dev, true);
return ret;
}
@@ -274,6 +269,7 @@ int
nouveau_pci_resume(struct pci_dev *pdev)
{
struct drm_device *dev = pci_get_drvdata(pdev);
+ struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_engine *engine = &dev_priv->engine;
struct drm_crtc *crtc;
@@ -321,7 +317,6 @@ nouveau_pci_resume(struct pci_dev *pdev)
if (dev_priv->eng[i])
dev_priv->eng[i]->init(dev, i);
}
- engine->fifo.init(dev);
nouveau_irq_postinstall(dev);
@@ -330,7 +325,7 @@ nouveau_pci_resume(struct pci_dev *pdev)
struct nouveau_channel *chan;
int j;
- for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
+ for (i = 0; i < (pfifo ? pfifo->channels : 0); i++) {
chan = dev_priv->channels.ptr[i];
if (!chan || !chan->pushbuf_bo)
continue;
@@ -408,7 +403,7 @@ static struct drm_driver driver = {
.driver_features =
DRIVER_USE_AGP | DRIVER_PCI_DMA | DRIVER_SG |
DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM |
- DRIVER_MODESET,
+ DRIVER_MODESET | DRIVER_PRIME,
.load = nouveau_load,
.firstopen = nouveau_firstopen,
.lastclose = nouveau_lastclose,
@@ -430,6 +425,12 @@ static struct drm_driver driver = {
.reclaim_buffers = drm_core_reclaim_buffers,
.ioctls = nouveau_ioctls,
.fops = &nouveau_driver_fops,
+
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_export = nouveau_gem_prime_export,
+ .gem_prime_import = nouveau_gem_prime_import,
+
.gem_init_object = nouveau_gem_object_new,
.gem_free_object = nouveau_gem_object_del,
.gem_open_object = nouveau_gem_object_open,
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 3aef353a926c..634d222c93de 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -70,7 +70,7 @@ struct nouveau_mem;
#define MAX_NUM_DCB_ENTRIES 16
-#define NOUVEAU_MAX_CHANNEL_NR 128
+#define NOUVEAU_MAX_CHANNEL_NR 4096
#define NOUVEAU_MAX_TILE_NR 15
struct nouveau_mem {
@@ -86,6 +86,7 @@ struct nouveau_mem {
u32 memtype;
u64 offset;
u64 size;
+ struct sg_table *sg;
};
struct nouveau_tile_reg {
@@ -164,8 +165,10 @@ enum nouveau_flags {
#define NVOBJ_ENGINE_PPP NVOBJ_ENGINE_MPEG
#define NVOBJ_ENGINE_BSP 6
#define NVOBJ_ENGINE_VP 7
-#define NVOBJ_ENGINE_DISPLAY 15
+#define NVOBJ_ENGINE_FIFO 14
+#define NVOBJ_ENGINE_FENCE 15
#define NVOBJ_ENGINE_NR 16
+#define NVOBJ_ENGINE_DISPLAY (NVOBJ_ENGINE_NR + 0) /*XXX*/
#define NVOBJ_FLAG_DONT_MAP (1 << 0)
#define NVOBJ_FLAG_ZERO_ALLOC (1 << 1)
@@ -233,17 +236,6 @@ struct nouveau_channel {
uint32_t user_get_hi;
uint32_t user_put;
- /* Fencing */
- struct {
- /* lock protects the pending list only */
- spinlock_t lock;
- struct list_head pending;
- uint32_t sequence;
- uint32_t sequence_ack;
- atomic_t last_sequence_irq;
- struct nouveau_vma vma;
- } fence;
-
/* DMA push buffer */
struct nouveau_gpuobj *pushbuf;
struct nouveau_bo *pushbuf_bo;
@@ -257,8 +249,6 @@ struct nouveau_channel {
/* PFIFO context */
struct nouveau_gpuobj *ramfc;
- struct nouveau_gpuobj *cache;
- void *fifo_priv;
/* Execution engine contexts */
void *engctx[NVOBJ_ENGINE_NR];
@@ -292,18 +282,6 @@ struct nouveau_channel {
int ib_put;
} dma;
- uint32_t sw_subchannel[8];
-
- struct nouveau_vma dispc_vma[4];
- struct {
- struct nouveau_gpuobj *vblsem;
- uint32_t vblsem_head;
- uint32_t vblsem_offset;
- uint32_t vblsem_rval;
- struct list_head vbl_wait;
- struct list_head flip;
- } nvsw;
-
struct {
bool active;
char name[32];
@@ -366,30 +344,6 @@ struct nouveau_fb_engine {
void (*free_tile_region)(struct drm_device *dev, int i);
};
-struct nouveau_fifo_engine {
- void *priv;
- int channels;
-
- struct nouveau_gpuobj *playlist[2];
- int cur_playlist;
-
- int (*init)(struct drm_device *);
- void (*takedown)(struct drm_device *);
-
- void (*disable)(struct drm_device *);
- void (*enable)(struct drm_device *);
- bool (*reassign)(struct drm_device *, bool enable);
- bool (*cache_pull)(struct drm_device *dev, bool enable);
-
- int (*channel_id)(struct drm_device *);
-
- int (*create_context)(struct nouveau_channel *);
- void (*destroy_context)(struct nouveau_channel *);
- int (*load_context)(struct nouveau_channel *);
- int (*unload_context)(struct drm_device *);
- void (*tlb_flush)(struct drm_device *dev);
-};
-
struct nouveau_display_engine {
void *priv;
int (*early_init)(struct drm_device *);
@@ -597,7 +551,6 @@ struct nouveau_engine {
struct nouveau_mc_engine mc;
struct nouveau_timer_engine timer;
struct nouveau_fb_engine fb;
- struct nouveau_fifo_engine fifo;
struct nouveau_display_engine display;
struct nouveau_gpio_engine gpio;
struct nouveau_pm_engine pm;
@@ -740,6 +693,9 @@ struct drm_nouveau_private {
struct ttm_bo_global_ref bo_global_ref;
struct ttm_bo_device bdev;
atomic_t validate_sequence;
+ int (*move)(struct nouveau_channel *,
+ struct ttm_buffer_object *,
+ struct ttm_mem_reg *, struct ttm_mem_reg *);
} ttm;
struct {
@@ -977,7 +933,7 @@ extern void nouveau_channel_put_unlocked(struct nouveau_channel **);
extern void nouveau_channel_put(struct nouveau_channel **);
extern void nouveau_channel_ref(struct nouveau_channel *chan,
struct nouveau_channel **pchan);
-extern void nouveau_channel_idle(struct nouveau_channel *chan);
+extern int nouveau_channel_idle(struct nouveau_channel *chan);
/* nouveau_object.c */
#define NVOBJ_ENGINE_ADD(d, e, p) do { \
@@ -1209,56 +1165,6 @@ extern void nv50_fb_vm_trap(struct drm_device *, int display);
extern int nvc0_fb_init(struct drm_device *);
extern void nvc0_fb_takedown(struct drm_device *);
-/* nv04_fifo.c */
-extern int nv04_fifo_init(struct drm_device *);
-extern void nv04_fifo_fini(struct drm_device *);
-extern void nv04_fifo_disable(struct drm_device *);
-extern void nv04_fifo_enable(struct drm_device *);
-extern bool nv04_fifo_reassign(struct drm_device *, bool);
-extern bool nv04_fifo_cache_pull(struct drm_device *, bool);
-extern int nv04_fifo_channel_id(struct drm_device *);
-extern int nv04_fifo_create_context(struct nouveau_channel *);
-extern void nv04_fifo_destroy_context(struct nouveau_channel *);
-extern int nv04_fifo_load_context(struct nouveau_channel *);
-extern int nv04_fifo_unload_context(struct drm_device *);
-extern void nv04_fifo_isr(struct drm_device *);
-
-/* nv10_fifo.c */
-extern int nv10_fifo_init(struct drm_device *);
-extern int nv10_fifo_channel_id(struct drm_device *);
-extern int nv10_fifo_create_context(struct nouveau_channel *);
-extern int nv10_fifo_load_context(struct nouveau_channel *);
-extern int nv10_fifo_unload_context(struct drm_device *);
-
-/* nv40_fifo.c */
-extern int nv40_fifo_init(struct drm_device *);
-extern int nv40_fifo_create_context(struct nouveau_channel *);
-extern int nv40_fifo_load_context(struct nouveau_channel *);
-extern int nv40_fifo_unload_context(struct drm_device *);
-
-/* nv50_fifo.c */
-extern int nv50_fifo_init(struct drm_device *);
-extern void nv50_fifo_takedown(struct drm_device *);
-extern int nv50_fifo_channel_id(struct drm_device *);
-extern int nv50_fifo_create_context(struct nouveau_channel *);
-extern void nv50_fifo_destroy_context(struct nouveau_channel *);
-extern int nv50_fifo_load_context(struct nouveau_channel *);
-extern int nv50_fifo_unload_context(struct drm_device *);
-extern void nv50_fifo_tlb_flush(struct drm_device *dev);
-
-/* nvc0_fifo.c */
-extern int nvc0_fifo_init(struct drm_device *);
-extern void nvc0_fifo_takedown(struct drm_device *);
-extern void nvc0_fifo_disable(struct drm_device *);
-extern void nvc0_fifo_enable(struct drm_device *);
-extern bool nvc0_fifo_reassign(struct drm_device *, bool);
-extern bool nvc0_fifo_cache_pull(struct drm_device *, bool);
-extern int nvc0_fifo_channel_id(struct drm_device *);
-extern int nvc0_fifo_create_context(struct nouveau_channel *);
-extern void nvc0_fifo_destroy_context(struct nouveau_channel *);
-extern int nvc0_fifo_load_context(struct nouveau_channel *);
-extern int nvc0_fifo_unload_context(struct drm_device *);
-
/* nv04_graph.c */
extern int nv04_graph_create(struct drm_device *);
extern int nv04_graph_object_new(struct nouveau_channel *, int, u32, u16);
@@ -1277,18 +1183,23 @@ extern int nv20_graph_create(struct drm_device *);
/* nv40_graph.c */
extern int nv40_graph_create(struct drm_device *);
-extern void nv40_grctx_init(struct nouveau_grctx *);
+extern void nv40_grctx_init(struct drm_device *, u32 *size);
+extern void nv40_grctx_fill(struct drm_device *, struct nouveau_gpuobj *);
/* nv50_graph.c */
extern int nv50_graph_create(struct drm_device *);
-extern int nv50_grctx_init(struct nouveau_grctx *);
extern struct nouveau_enum nv50_data_error_names[];
extern int nv50_graph_isr_chid(struct drm_device *dev, u64 inst);
+extern int nv50_grctx_init(struct drm_device *, u32 *, u32, u32 *, u32 *);
+extern void nv50_grctx_fill(struct drm_device *, struct nouveau_gpuobj *);
/* nvc0_graph.c */
extern int nvc0_graph_create(struct drm_device *);
extern int nvc0_graph_isr_chid(struct drm_device *dev, u64 inst);
+/* nve0_graph.c */
+extern int nve0_graph_create(struct drm_device *);
+
/* nv84_crypt.c */
extern int nv84_crypt_create(struct drm_device *);
@@ -1414,9 +1325,12 @@ extern int nv04_crtc_create(struct drm_device *, int index);
/* nouveau_bo.c */
extern struct ttm_bo_driver nouveau_bo_driver;
+extern void nouveau_bo_move_init(struct nouveau_channel *);
extern int nouveau_bo_new(struct drm_device *, int size, int align,
uint32_t flags, uint32_t tile_mode,
- uint32_t tile_flags, struct nouveau_bo **);
+ uint32_t tile_flags,
+ struct sg_table *sg,
+ struct nouveau_bo **);
extern int nouveau_bo_pin(struct nouveau_bo *, uint32_t flags);
extern int nouveau_bo_unpin(struct nouveau_bo *);
extern int nouveau_bo_map(struct nouveau_bo *);
@@ -1437,50 +1351,6 @@ extern int nouveau_bo_vma_add(struct nouveau_bo *, struct nouveau_vm *,
struct nouveau_vma *);
extern void nouveau_bo_vma_del(struct nouveau_bo *, struct nouveau_vma *);
-/* nouveau_fence.c */
-struct nouveau_fence;
-extern int nouveau_fence_init(struct drm_device *);
-extern void nouveau_fence_fini(struct drm_device *);
-extern int nouveau_fence_channel_init(struct nouveau_channel *);
-extern void nouveau_fence_channel_fini(struct nouveau_channel *);
-extern void nouveau_fence_update(struct nouveau_channel *);
-extern int nouveau_fence_new(struct nouveau_channel *, struct nouveau_fence **,
- bool emit);
-extern int nouveau_fence_emit(struct nouveau_fence *);
-extern void nouveau_fence_work(struct nouveau_fence *fence,
- void (*work)(void *priv, bool signalled),
- void *priv);
-struct nouveau_channel *nouveau_fence_channel(struct nouveau_fence *);
-
-extern bool __nouveau_fence_signalled(void *obj, void *arg);
-extern int __nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr);
-extern int __nouveau_fence_flush(void *obj, void *arg);
-extern void __nouveau_fence_unref(void **obj);
-extern void *__nouveau_fence_ref(void *obj);
-
-static inline bool nouveau_fence_signalled(struct nouveau_fence *obj)
-{
- return __nouveau_fence_signalled(obj, NULL);
-}
-static inline int
-nouveau_fence_wait(struct nouveau_fence *obj, bool lazy, bool intr)
-{
- return __nouveau_fence_wait(obj, NULL, lazy, intr);
-}
-extern int nouveau_fence_sync(struct nouveau_fence *, struct nouveau_channel *);
-static inline int nouveau_fence_flush(struct nouveau_fence *obj)
-{
- return __nouveau_fence_flush(obj, NULL);
-}
-static inline void nouveau_fence_unref(struct nouveau_fence **obj)
-{
- __nouveau_fence_unref((void **)obj);
-}
-static inline struct nouveau_fence *nouveau_fence_ref(struct nouveau_fence *obj)
-{
- return __nouveau_fence_ref(obj);
-}
-
/* nouveau_gem.c */
extern int nouveau_gem_new(struct drm_device *, int size, int align,
uint32_t domain, uint32_t tile_mode,
@@ -1501,6 +1371,11 @@ extern int nouveau_gem_ioctl_cpu_fini(struct drm_device *, void *,
extern int nouveau_gem_ioctl_info(struct drm_device *, void *,
struct drm_file *);
+extern struct dma_buf *nouveau_gem_prime_export(struct drm_device *dev,
+ struct drm_gem_object *obj, int flags);
+extern struct drm_gem_object *nouveau_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *dma_buf);
+
/* nouveau_display.c */
int nouveau_display_create(struct drm_device *dev);
void nouveau_display_destroy(struct drm_device *dev);
@@ -1772,6 +1647,7 @@ nv44_graph_class(struct drm_device *dev)
#define NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL 0x00000001
#define NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG 0x00000002
#define NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_GEQUAL 0x00000004
+#define NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD 0x00001000
#define NV84_SUBCHAN_NOTIFY_INTR 0x00000020
#define NV84_SUBCHAN_WRCACHE_FLUSH 0x00000024
#define NV10_SUBCHAN_REF_CNT 0x00000050
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 8113e9201ed9..153b9a15469b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -153,7 +153,7 @@ nouveau_fbcon_sync(struct fb_info *info)
struct drm_device *dev = nfbdev->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = dev_priv->channel;
- int ret, i;
+ int ret;
if (!chan || !chan->accel_done || in_interrupt() ||
info->state != FBINFO_STATE_RUNNING ||
@@ -163,38 +163,8 @@ nouveau_fbcon_sync(struct fb_info *info)
if (!mutex_trylock(&chan->mutex))
return 0;
- ret = RING_SPACE(chan, 4);
- if (ret) {
- mutex_unlock(&chan->mutex);
- nouveau_fbcon_gpu_lockup(info);
- return 0;
- }
-
- if (dev_priv->card_type >= NV_C0) {
- BEGIN_NVC0(chan, 2, NvSub2D, 0x010c, 1);
- OUT_RING (chan, 0);
- BEGIN_NVC0(chan, 2, NvSub2D, 0x0100, 1);
- OUT_RING (chan, 0);
- } else {
- BEGIN_RING(chan, 0, 0x0104, 1);
- OUT_RING (chan, 0);
- BEGIN_RING(chan, 0, 0x0100, 1);
- OUT_RING (chan, 0);
- }
-
- nouveau_bo_wr32(chan->notifier_bo, chan->m2mf_ntfy/4 + 3, 0xffffffff);
- FIRE_RING(chan);
+ ret = nouveau_channel_idle(chan);
mutex_unlock(&chan->mutex);
-
- ret = -EBUSY;
- for (i = 0; i < 100000; i++) {
- if (!nouveau_bo_rd32(chan->notifier_bo, chan->m2mf_ntfy/4 + 3)) {
- ret = 0;
- break;
- }
- DRM_UDELAY(1);
- }
-
if (ret) {
nouveau_fbcon_gpu_lockup(info);
return 0;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index c1dc20f6cb85..3c180493dab8 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -32,220 +32,100 @@
#include "nouveau_drv.h"
#include "nouveau_ramht.h"
+#include "nouveau_fence.h"
+#include "nouveau_software.h"
#include "nouveau_dma.h"
-#define USE_REFCNT(dev) (nouveau_private(dev)->chipset >= 0x10)
-#define USE_SEMA(dev) (nouveau_private(dev)->chipset >= 0x17)
-
-struct nouveau_fence {
- struct nouveau_channel *channel;
- struct kref refcount;
- struct list_head entry;
-
- uint32_t sequence;
- bool signalled;
-
- void (*work)(void *priv, bool signalled);
- void *priv;
-};
-
-struct nouveau_semaphore {
- struct kref ref;
- struct drm_device *dev;
- struct drm_mm_node *mem;
-};
-
-static inline struct nouveau_fence *
-nouveau_fence(void *sync_obj)
+void
+nouveau_fence_context_del(struct nouveau_fence_chan *fctx)
{
- return (struct nouveau_fence *)sync_obj;
+ struct nouveau_fence *fence, *fnext;
+ spin_lock(&fctx->lock);
+ list_for_each_entry_safe(fence, fnext, &fctx->pending, head) {
+ if (fence->work)
+ fence->work(fence->priv, false);
+ fence->channel = NULL;
+ list_del(&fence->head);
+ nouveau_fence_unref(&fence);
+ }
+ spin_unlock(&fctx->lock);
}
-static void
-nouveau_fence_del(struct kref *ref)
+void
+nouveau_fence_context_new(struct nouveau_fence_chan *fctx)
{
- struct nouveau_fence *fence =
- container_of(ref, struct nouveau_fence, refcount);
-
- nouveau_channel_ref(NULL, &fence->channel);
- kfree(fence);
+ INIT_LIST_HEAD(&fctx->pending);
+ spin_lock_init(&fctx->lock);
}
void
nouveau_fence_update(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
- struct nouveau_fence *tmp, *fence;
- uint32_t sequence;
+ struct nouveau_fence_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FENCE);
+ struct nouveau_fence_chan *fctx = chan->engctx[NVOBJ_ENGINE_FENCE];
+ struct nouveau_fence *fence, *fnext;
- spin_lock(&chan->fence.lock);
-
- /* Fetch the last sequence if the channel is still up and running */
- if (likely(!list_empty(&chan->fence.pending))) {
- if (USE_REFCNT(dev))
- sequence = nvchan_rd32(chan, 0x48);
- else
- sequence = atomic_read(&chan->fence.last_sequence_irq);
-
- if (chan->fence.sequence_ack == sequence)
- goto out;
- chan->fence.sequence_ack = sequence;
- }
-
- list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) {
- if (fence->sequence > chan->fence.sequence_ack)
+ spin_lock(&fctx->lock);
+ list_for_each_entry_safe(fence, fnext, &fctx->pending, head) {
+ if (priv->read(chan) < fence->sequence)
break;
- fence->signalled = true;
- list_del(&fence->entry);
if (fence->work)
fence->work(fence->priv, true);
-
- kref_put(&fence->refcount, nouveau_fence_del);
- }
-
-out:
- spin_unlock(&chan->fence.lock);
-}
-
-int
-nouveau_fence_new(struct nouveau_channel *chan, struct nouveau_fence **pfence,
- bool emit)
-{
- struct nouveau_fence *fence;
- int ret = 0;
-
- fence = kzalloc(sizeof(*fence), GFP_KERNEL);
- if (!fence)
- return -ENOMEM;
- kref_init(&fence->refcount);
- nouveau_channel_ref(chan, &fence->channel);
-
- if (emit)
- ret = nouveau_fence_emit(fence);
-
- if (ret)
+ fence->channel = NULL;
+ list_del(&fence->head);
nouveau_fence_unref(&fence);
- *pfence = fence;
- return ret;
-}
-
-struct nouveau_channel *
-nouveau_fence_channel(struct nouveau_fence *fence)
-{
- return fence ? nouveau_channel_get_unlocked(fence->channel) : NULL;
+ }
+ spin_unlock(&fctx->lock);
}
int
-nouveau_fence_emit(struct nouveau_fence *fence)
+nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan)
{
- struct nouveau_channel *chan = fence->channel;
struct drm_device *dev = chan->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_fence_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FENCE);
+ struct nouveau_fence_chan *fctx = chan->engctx[NVOBJ_ENGINE_FENCE];
int ret;
- ret = RING_SPACE(chan, 2);
- if (ret)
- return ret;
-
- if (unlikely(chan->fence.sequence == chan->fence.sequence_ack - 1)) {
- nouveau_fence_update(chan);
+ fence->channel = chan;
+ fence->timeout = jiffies + (3 * DRM_HZ);
+ fence->sequence = ++fctx->sequence;
- BUG_ON(chan->fence.sequence ==
- chan->fence.sequence_ack - 1);
+ ret = priv->emit(fence);
+ if (!ret) {
+ kref_get(&fence->kref);
+ spin_lock(&fctx->lock);
+ list_add_tail(&fence->head, &fctx->pending);
+ spin_unlock(&fctx->lock);
}
- fence->sequence = ++chan->fence.sequence;
-
- kref_get(&fence->refcount);
- spin_lock(&chan->fence.lock);
- list_add_tail(&fence->entry, &chan->fence.pending);
- spin_unlock(&chan->fence.lock);
-
- if (USE_REFCNT(dev)) {
- if (dev_priv->card_type < NV_C0)
- BEGIN_RING(chan, 0, NV10_SUBCHAN_REF_CNT, 1);
- else
- BEGIN_NVC0(chan, 2, 0, NV10_SUBCHAN_REF_CNT, 1);
- } else {
- BEGIN_RING(chan, NvSubSw, 0x0150, 1);
- }
- OUT_RING (chan, fence->sequence);
- FIRE_RING(chan);
-
- return 0;
-}
-
-void
-nouveau_fence_work(struct nouveau_fence *fence,
- void (*work)(void *priv, bool signalled),
- void *priv)
-{
- BUG_ON(fence->work);
-
- spin_lock(&fence->channel->fence.lock);
-
- if (fence->signalled) {
- work(priv, true);
- } else {
- fence->work = work;
- fence->priv = priv;
- }
-
- spin_unlock(&fence->channel->fence.lock);
-}
-
-void
-__nouveau_fence_unref(void **sync_obj)
-{
- struct nouveau_fence *fence = nouveau_fence(*sync_obj);
-
- if (fence)
- kref_put(&fence->refcount, nouveau_fence_del);
- *sync_obj = NULL;
-}
-
-void *
-__nouveau_fence_ref(void *sync_obj)
-{
- struct nouveau_fence *fence = nouveau_fence(sync_obj);
-
- kref_get(&fence->refcount);
- return sync_obj;
+ return ret;
}
bool
-__nouveau_fence_signalled(void *sync_obj, void *sync_arg)
+nouveau_fence_done(struct nouveau_fence *fence)
{
- struct nouveau_fence *fence = nouveau_fence(sync_obj);
- struct nouveau_channel *chan = fence->channel;
-
- if (fence->signalled)
- return true;
-
- nouveau_fence_update(chan);
- return fence->signalled;
+ if (fence->channel)
+ nouveau_fence_update(fence->channel);
+ return !fence->channel;
}
int
-__nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr)
+nouveau_fence_wait(struct nouveau_fence *fence, bool lazy, bool intr)
{
- unsigned long timeout = jiffies + (3 * DRM_HZ);
unsigned long sleep_time = NSEC_PER_MSEC / 1000;
ktime_t t;
int ret = 0;
- while (1) {
- if (__nouveau_fence_signalled(sync_obj, sync_arg))
- break;
-
- if (time_after_eq(jiffies, timeout)) {
+ while (!nouveau_fence_done(fence)) {
+ if (fence->timeout && time_after_eq(jiffies, fence->timeout)) {
ret = -EBUSY;
break;
}
- __set_current_state(intr ? TASK_INTERRUPTIBLE
- : TASK_UNINTERRUPTIBLE);
+ __set_current_state(intr ? TASK_INTERRUPTIBLE :
+ TASK_UNINTERRUPTIBLE);
if (lazy) {
t = ktime_set(0, sleep_time);
schedule_hrtimeout(&t, HRTIMER_MODE_REL);
@@ -261,354 +141,72 @@ __nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr)
}
__set_current_state(TASK_RUNNING);
-
return ret;
}
-static struct nouveau_semaphore *
-semaphore_alloc(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_semaphore *sema;
- int size = (dev_priv->chipset < 0x84) ? 4 : 16;
- int ret, i;
-
- if (!USE_SEMA(dev))
- return NULL;
-
- sema = kmalloc(sizeof(*sema), GFP_KERNEL);
- if (!sema)
- goto fail;
-
- ret = drm_mm_pre_get(&dev_priv->fence.heap);
- if (ret)
- goto fail;
-
- spin_lock(&dev_priv->fence.lock);
- sema->mem = drm_mm_search_free(&dev_priv->fence.heap, size, 0, 0);
- if (sema->mem)
- sema->mem = drm_mm_get_block_atomic(sema->mem, size, 0);
- spin_unlock(&dev_priv->fence.lock);
-
- if (!sema->mem)
- goto fail;
-
- kref_init(&sema->ref);
- sema->dev = dev;
- for (i = sema->mem->start; i < sema->mem->start + size; i += 4)
- nouveau_bo_wr32(dev_priv->fence.bo, i / 4, 0);
-
- return sema;
-fail:
- kfree(sema);
- return NULL;
-}
-
-static void
-semaphore_free(struct kref *ref)
-{
- struct nouveau_semaphore *sema =
- container_of(ref, struct nouveau_semaphore, ref);
- struct drm_nouveau_private *dev_priv = sema->dev->dev_private;
-
- spin_lock(&dev_priv->fence.lock);
- drm_mm_put_block(sema->mem);
- spin_unlock(&dev_priv->fence.lock);
-
- kfree(sema);
-}
-
-static void
-semaphore_work(void *priv, bool signalled)
-{
- struct nouveau_semaphore *sema = priv;
- struct drm_nouveau_private *dev_priv = sema->dev->dev_private;
-
- if (unlikely(!signalled))
- nouveau_bo_wr32(dev_priv->fence.bo, sema->mem->start / 4, 1);
-
- kref_put(&sema->ref, semaphore_free);
-}
-
-static int
-semaphore_acquire(struct nouveau_channel *chan, struct nouveau_semaphore *sema)
-{
- struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
- struct nouveau_fence *fence = NULL;
- u64 offset = chan->fence.vma.offset + sema->mem->start;
- int ret;
-
- if (dev_priv->chipset < 0x84) {
- ret = RING_SPACE(chan, 4);
- if (ret)
- return ret;
-
- BEGIN_RING(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 3);
- OUT_RING (chan, NvSema);
- OUT_RING (chan, offset);
- OUT_RING (chan, 1);
- } else
- if (dev_priv->chipset < 0xc0) {
- ret = RING_SPACE(chan, 7);
- if (ret)
- return ret;
-
- BEGIN_RING(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
- OUT_RING (chan, chan->vram_handle);
- BEGIN_RING(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
- OUT_RING (chan, upper_32_bits(offset));
- OUT_RING (chan, lower_32_bits(offset));
- OUT_RING (chan, 1);
- OUT_RING (chan, 1); /* ACQUIRE_EQ */
- } else {
- ret = RING_SPACE(chan, 5);
- if (ret)
- return ret;
-
- BEGIN_NVC0(chan, 2, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
- OUT_RING (chan, upper_32_bits(offset));
- OUT_RING (chan, lower_32_bits(offset));
- OUT_RING (chan, 1);
- OUT_RING (chan, 0x1001); /* ACQUIRE_EQ */
- }
-
- /* Delay semaphore destruction until its work is done */
- ret = nouveau_fence_new(chan, &fence, true);
- if (ret)
- return ret;
-
- kref_get(&sema->ref);
- nouveau_fence_work(fence, semaphore_work, sema);
- nouveau_fence_unref(&fence);
- return 0;
-}
-
-static int
-semaphore_release(struct nouveau_channel *chan, struct nouveau_semaphore *sema)
-{
- struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
- struct nouveau_fence *fence = NULL;
- u64 offset = chan->fence.vma.offset + sema->mem->start;
- int ret;
-
- if (dev_priv->chipset < 0x84) {
- ret = RING_SPACE(chan, 5);
- if (ret)
- return ret;
-
- BEGIN_RING(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2);
- OUT_RING (chan, NvSema);
- OUT_RING (chan, offset);
- BEGIN_RING(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1);
- OUT_RING (chan, 1);
- } else
- if (dev_priv->chipset < 0xc0) {
- ret = RING_SPACE(chan, 7);
- if (ret)
- return ret;
-
- BEGIN_RING(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
- OUT_RING (chan, chan->vram_handle);
- BEGIN_RING(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
- OUT_RING (chan, upper_32_bits(offset));
- OUT_RING (chan, lower_32_bits(offset));
- OUT_RING (chan, 1);
- OUT_RING (chan, 2); /* RELEASE */
- } else {
- ret = RING_SPACE(chan, 5);
- if (ret)
- return ret;
-
- BEGIN_NVC0(chan, 2, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
- OUT_RING (chan, upper_32_bits(offset));
- OUT_RING (chan, lower_32_bits(offset));
- OUT_RING (chan, 1);
- OUT_RING (chan, 0x1002); /* RELEASE */
- }
-
- /* Delay semaphore destruction until its work is done */
- ret = nouveau_fence_new(chan, &fence, true);
- if (ret)
- return ret;
-
- kref_get(&sema->ref);
- nouveau_fence_work(fence, semaphore_work, sema);
- nouveau_fence_unref(&fence);
- return 0;
-}
-
int
-nouveau_fence_sync(struct nouveau_fence *fence,
- struct nouveau_channel *wchan)
+nouveau_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *chan)
{
- struct nouveau_channel *chan = nouveau_fence_channel(fence);
- struct drm_device *dev = wchan->dev;
- struct nouveau_semaphore *sema;
+ struct drm_device *dev = chan->dev;
+ struct nouveau_fence_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FENCE);
+ struct nouveau_channel *prev;
int ret = 0;
- if (likely(!chan || chan == wchan ||
- nouveau_fence_signalled(fence)))
- goto out;
-
- sema = semaphore_alloc(dev);
- if (!sema) {
- /* Early card or broken userspace, fall back to
- * software sync. */
- ret = nouveau_fence_wait(fence, true, false);
- goto out;
- }
-
- /* try to take chan's mutex, if we can't take it right away
- * we have to fallback to software sync to prevent locking
- * order issues
- */
- if (!mutex_trylock(&chan->mutex)) {
- ret = nouveau_fence_wait(fence, true, false);
- goto out_unref;
+ prev = fence ? nouveau_channel_get_unlocked(fence->channel) : NULL;
+ if (prev) {
+ if (unlikely(prev != chan && !nouveau_fence_done(fence))) {
+ ret = priv->sync(fence, prev, chan);
+ if (unlikely(ret))
+ ret = nouveau_fence_wait(fence, true, false);
+ }
+ nouveau_channel_put_unlocked(&prev);
}
- /* Make wchan wait until it gets signalled */
- ret = semaphore_acquire(wchan, sema);
- if (ret)
- goto out_unlock;
-
- /* Signal the semaphore from chan */
- ret = semaphore_release(chan, sema);
-
-out_unlock:
- mutex_unlock(&chan->mutex);
-out_unref:
- kref_put(&sema->ref, semaphore_free);
-out:
- if (chan)
- nouveau_channel_put_unlocked(&chan);
return ret;
}
-int
-__nouveau_fence_flush(void *sync_obj, void *sync_arg)
+static void
+nouveau_fence_del(struct kref *kref)
{
- return 0;
+ struct nouveau_fence *fence = container_of(kref, typeof(*fence), kref);
+ kfree(fence);
}
-int
-nouveau_fence_channel_init(struct nouveau_channel *chan)
+void
+nouveau_fence_unref(struct nouveau_fence **pfence)
{
- struct drm_device *dev = chan->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_gpuobj *obj = NULL;
- int ret;
-
- if (dev_priv->card_type < NV_C0) {
- /* Create an NV_SW object for various sync purposes */
- ret = nouveau_gpuobj_gr_new(chan, NvSw, NV_SW);
- if (ret)
- return ret;
-
- ret = RING_SPACE(chan, 2);
- if (ret)
- return ret;
-
- BEGIN_RING(chan, NvSubSw, NV01_SUBCHAN_OBJECT, 1);
- OUT_RING (chan, NvSw);
- FIRE_RING (chan);
- }
-
- /* Setup area of memory shared between all channels for x-chan sync */
- if (USE_SEMA(dev) && dev_priv->chipset < 0x84) {
- struct ttm_mem_reg *mem = &dev_priv->fence.bo->bo.mem;
-
- ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_FROM_MEMORY,
- mem->start << PAGE_SHIFT,
- mem->size, NV_MEM_ACCESS_RW,
- NV_MEM_TARGET_VRAM, &obj);
- if (ret)
- return ret;
-
- ret = nouveau_ramht_insert(chan, NvSema, obj);
- nouveau_gpuobj_ref(NULL, &obj);
- if (ret)
- return ret;
- } else
- if (USE_SEMA(dev)) {
- /* map fence bo into channel's vm */
- ret = nouveau_bo_vma_add(dev_priv->fence.bo, chan->vm,
- &chan->fence.vma);
- if (ret)
- return ret;
- }
-
- atomic_set(&chan->fence.last_sequence_irq, 0);
- return 0;
+ if (*pfence)
+ kref_put(&(*pfence)->kref, nouveau_fence_del);
+ *pfence = NULL;
}
-void
-nouveau_fence_channel_fini(struct nouveau_channel *chan)
+struct nouveau_fence *
+nouveau_fence_ref(struct nouveau_fence *fence)
{
- struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
- struct nouveau_fence *tmp, *fence;
-
- spin_lock(&chan->fence.lock);
- list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) {
- fence->signalled = true;
- list_del(&fence->entry);
-
- if (unlikely(fence->work))
- fence->work(fence->priv, false);
-
- kref_put(&fence->refcount, nouveau_fence_del);
- }
- spin_unlock(&chan->fence.lock);
-
- nouveau_bo_vma_del(dev_priv->fence.bo, &chan->fence.vma);
+ kref_get(&fence->kref);
+ return fence;
}
int
-nouveau_fence_init(struct drm_device *dev)
+nouveau_fence_new(struct nouveau_channel *chan, struct nouveau_fence **pfence)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- int size = (dev_priv->chipset < 0x84) ? 4096 : 16384;
- int ret;
-
- /* Create a shared VRAM heap for cross-channel sync. */
- if (USE_SEMA(dev)) {
- ret = nouveau_bo_new(dev, size, 0, TTM_PL_FLAG_VRAM,
- 0, 0, &dev_priv->fence.bo);
- if (ret)
- return ret;
+ struct nouveau_fence *fence;
+ int ret = 0;
- ret = nouveau_bo_pin(dev_priv->fence.bo, TTM_PL_FLAG_VRAM);
- if (ret)
- goto fail;
+ if (unlikely(!chan->engctx[NVOBJ_ENGINE_FENCE]))
+ return -ENODEV;
- ret = nouveau_bo_map(dev_priv->fence.bo);
- if (ret)
- goto fail;
+ fence = kzalloc(sizeof(*fence), GFP_KERNEL);
+ if (!fence)
+ return -ENOMEM;
+ kref_init(&fence->kref);
- ret = drm_mm_init(&dev_priv->fence.heap, 0,
- dev_priv->fence.bo->bo.mem.size);
+ if (chan) {
+ ret = nouveau_fence_emit(fence, chan);
if (ret)
- goto fail;
-
- spin_lock_init(&dev_priv->fence.lock);
+ nouveau_fence_unref(&fence);
}
- return 0;
-fail:
- nouveau_bo_unmap(dev_priv->fence.bo);
- nouveau_bo_ref(NULL, &dev_priv->fence.bo);
+ *pfence = fence;
return ret;
}
-
-void
-nouveau_fence_fini(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- if (USE_SEMA(dev)) {
- drm_mm_takedown(&dev_priv->fence.heap);
- nouveau_bo_unmap(dev_priv->fence.bo);
- nouveau_bo_unpin(dev_priv->fence.bo);
- nouveau_bo_ref(NULL, &dev_priv->fence.bo);
- }
-}
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h
new file mode 100644
index 000000000000..82ba733393ae
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.h
@@ -0,0 +1,52 @@
+#ifndef __NOUVEAU_FENCE_H__
+#define __NOUVEAU_FENCE_H__
+
+struct nouveau_fence {
+ struct list_head head;
+ struct kref kref;
+
+ struct nouveau_channel *channel;
+ unsigned long timeout;
+ u32 sequence;
+
+ void (*work)(void *priv, bool signalled);
+ void *priv;
+};
+
+int nouveau_fence_new(struct nouveau_channel *, struct nouveau_fence **);
+struct nouveau_fence *
+nouveau_fence_ref(struct nouveau_fence *);
+void nouveau_fence_unref(struct nouveau_fence **);
+
+int nouveau_fence_emit(struct nouveau_fence *, struct nouveau_channel *);
+bool nouveau_fence_done(struct nouveau_fence *);
+int nouveau_fence_wait(struct nouveau_fence *, bool lazy, bool intr);
+int nouveau_fence_sync(struct nouveau_fence *, struct nouveau_channel *);
+void nouveau_fence_idle(struct nouveau_channel *);
+void nouveau_fence_update(struct nouveau_channel *);
+
+struct nouveau_fence_chan {
+ struct list_head pending;
+ spinlock_t lock;
+ u32 sequence;
+};
+
+struct nouveau_fence_priv {
+ struct nouveau_exec_engine engine;
+ int (*emit)(struct nouveau_fence *);
+ int (*sync)(struct nouveau_fence *, struct nouveau_channel *,
+ struct nouveau_channel *);
+ u32 (*read)(struct nouveau_channel *);
+};
+
+void nouveau_fence_context_new(struct nouveau_fence_chan *);
+void nouveau_fence_context_del(struct nouveau_fence_chan *);
+
+int nv04_fence_create(struct drm_device *dev);
+int nv04_fence_mthd(struct nouveau_channel *, u32, u32, u32);
+
+int nv10_fence_create(struct drm_device *dev);
+int nv84_fence_create(struct drm_device *dev);
+int nvc0_fence_create(struct drm_device *dev);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_fifo.h b/drivers/gpu/drm/nouveau/nouveau_fifo.h
new file mode 100644
index 000000000000..ce99cab2f257
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_fifo.h
@@ -0,0 +1,32 @@
+#ifndef __NOUVEAU_FIFO_H__
+#define __NOUVEAU_FIFO_H__
+
+struct nouveau_fifo_priv {
+ struct nouveau_exec_engine base;
+ u32 channels;
+};
+
+struct nouveau_fifo_chan {
+};
+
+bool nv04_fifo_cache_pull(struct drm_device *, bool);
+void nv04_fifo_context_del(struct nouveau_channel *, int);
+int nv04_fifo_fini(struct drm_device *, int, bool);
+int nv04_fifo_init(struct drm_device *, int);
+void nv04_fifo_isr(struct drm_device *);
+void nv04_fifo_destroy(struct drm_device *, int);
+
+void nv50_fifo_playlist_update(struct drm_device *);
+void nv50_fifo_destroy(struct drm_device *, int);
+void nv50_fifo_tlb_flush(struct drm_device *, int);
+
+int nv04_fifo_create(struct drm_device *);
+int nv10_fifo_create(struct drm_device *);
+int nv17_fifo_create(struct drm_device *);
+int nv40_fifo_create(struct drm_device *);
+int nv50_fifo_create(struct drm_device *);
+int nv84_fifo_create(struct drm_device *);
+int nvc0_fifo_create(struct drm_device *);
+int nve0_fifo_create(struct drm_device *);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index ed52a6f41613..30f542316944 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -23,12 +23,14 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
+#include <linux/dma-buf.h>
#include "drmP.h"
#include "drm.h"
#include "nouveau_drv.h"
#include "nouveau_drm.h"
#include "nouveau_dma.h"
+#include "nouveau_fence.h"
#define nouveau_gem_pushbuf_sync(chan) 0
@@ -53,6 +55,9 @@ nouveau_gem_object_del(struct drm_gem_object *gem)
nouveau_bo_unpin(nvbo);
}
+ if (gem->import_attach)
+ drm_prime_gem_destroy(gem, nvbo->bo.sg);
+
ttm_bo_unref(&bo);
drm_gem_object_release(gem);
@@ -139,7 +144,7 @@ nouveau_gem_new(struct drm_device *dev, int size, int align, uint32_t domain,
flags |= TTM_PL_FLAG_SYSTEM;
ret = nouveau_bo_new(dev, size, align, flags, tile_mode,
- tile_flags, pnvbo);
+ tile_flags, NULL, pnvbo);
if (ret)
return ret;
nvbo = *pnvbo;
@@ -704,7 +709,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
}
if (chan->dma.ib_max) {
- ret = nouveau_dma_wait(chan, req->nr_push + 1, 6);
+ ret = nouveau_dma_wait(chan, req->nr_push + 1, 16);
if (ret) {
NV_INFO(dev, "nv50cal_space: %d\n", ret);
goto out;
@@ -774,7 +779,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data,
}
}
- ret = nouveau_fence_new(chan, &fence, true);
+ ret = nouveau_fence_new(chan, &fence);
if (ret) {
NV_ERROR(dev, "error fencing pushbuf: %d\n", ret);
WIND_RING(chan);
diff --git a/drivers/gpu/drm/nouveau/nouveau_gpio.c b/drivers/gpu/drm/nouveau/nouveau_gpio.c
index a580cc62337a..82c19e82ff02 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gpio.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gpio.c
@@ -387,7 +387,7 @@ nouveau_gpio_reset(struct drm_device *dev)
if (dev_priv->card_type >= NV_D0) {
nv_mask(dev, 0x00d610 + (line * 4), 0xff, unk0);
if (unk1--)
- nv_mask(dev, 0x00d640 + (unk1 * 4), 0xff, line);
+ nv_mask(dev, 0x00d740 + (unk1 * 4), 0xff, line);
} else
if (dev_priv->card_type >= NV_50) {
static const u32 regs[] = { 0xe100, 0xe28c };
diff --git a/drivers/gpu/drm/nouveau/nouveau_grctx.h b/drivers/gpu/drm/nouveau/nouveau_grctx.h
index 86c2e374e938..b0795ececbda 100644
--- a/drivers/gpu/drm/nouveau/nouveau_grctx.h
+++ b/drivers/gpu/drm/nouveau/nouveau_grctx.h
@@ -18,7 +18,6 @@ struct nouveau_grctx {
uint32_t ctxvals_base;
};
-#ifdef CP_CTX
static inline void
cp_out(struct nouveau_grctx *ctx, uint32_t inst)
{
@@ -88,10 +87,8 @@ _cp_bra(struct nouveau_grctx *ctx, u32 mod, int flag, int state, int name)
(state ? 0 : CP_BRA_IF_CLEAR));
}
#define cp_bra(c, f, s, n) _cp_bra((c), 0, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
-#ifdef CP_BRA_MOD
#define cp_cal(c, f, s, n) _cp_bra((c), 1, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
#define cp_ret(c, f, s) _cp_bra((c), 2, CP_FLAG_##f, CP_FLAG_##f##_##s, 0)
-#endif
static inline void
_cp_wait(struct nouveau_grctx *ctx, int flag, int state)
@@ -128,6 +125,5 @@ gr_def(struct nouveau_grctx *ctx, uint32_t reg, uint32_t val)
nv_wo32(ctx->data, reg * 4, val);
}
-#endif
#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_hw.c b/drivers/gpu/drm/nouveau/nouveau_hw.c
index ba896e54b799..b87ad3bd7739 100644
--- a/drivers/gpu/drm/nouveau/nouveau_hw.c
+++ b/drivers/gpu/drm/nouveau/nouveau_hw.c
@@ -1018,11 +1018,6 @@ nv_load_state_ext(struct drm_device *dev, int head,
}
NVWriteCRTC(dev, head, NV_PCRTC_START, regp->fb_start);
-
- /* Enable vblank interrupts. */
- NVWriteCRTC(dev, head, NV_PCRTC_INTR_EN_0,
- (dev->vblank_enabled[head] ? 1 : 0));
- NVWriteCRTC(dev, head, NV_PCRTC_INTR_0, NV_PCRTC_INTR_0_VBLANK);
}
static void
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index b08065f981df..5b498ea32e14 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -39,6 +39,8 @@
#include "nouveau_pm.h"
#include "nouveau_mm.h"
#include "nouveau_vm.h"
+#include "nouveau_fifo.h"
+#include "nouveau_fence.h"
/*
* NV10-NV40 tiling helpers
@@ -50,7 +52,6 @@ nv10_mem_update_tile_region(struct drm_device *dev,
uint32_t size, uint32_t pitch, uint32_t flags)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
int i = tile - dev_priv->tile.reg, j;
unsigned long save;
@@ -64,8 +65,8 @@ nv10_mem_update_tile_region(struct drm_device *dev,
pfb->init_tile_region(dev, i, addr, size, pitch, flags);
spin_lock_irqsave(&dev_priv->context_switch_lock, save);
- pfifo->reassign(dev, false);
- pfifo->cache_pull(dev, false);
+ nv_wr32(dev, NV03_PFIFO_CACHES, 0);
+ nv04_fifo_cache_pull(dev, false);
nouveau_wait_for_idle(dev);
@@ -75,8 +76,8 @@ nv10_mem_update_tile_region(struct drm_device *dev,
dev_priv->eng[j]->set_tile_region(dev, i);
}
- pfifo->cache_pull(dev, true);
- pfifo->reassign(dev, true);
+ nv04_fifo_cache_pull(dev, true);
+ nv_wr32(dev, NV03_PFIFO_CACHES, 1);
spin_unlock_irqrestore(&dev_priv->context_switch_lock, save);
}
@@ -89,7 +90,7 @@ nv10_mem_get_tile_region(struct drm_device *dev, int i)
spin_lock(&dev_priv->tile.lock);
if (!tile->used &&
- (!tile->fence || nouveau_fence_signalled(tile->fence)))
+ (!tile->fence || nouveau_fence_done(tile->fence)))
tile->used = true;
else
tile = NULL;
@@ -416,7 +417,7 @@ nouveau_mem_vram_init(struct drm_device *dev)
if (dev_priv->card_type < NV_50) {
ret = nouveau_bo_new(dev, 256*1024, 0, TTM_PL_FLAG_VRAM,
- 0, 0, &dev_priv->vga_ram);
+ 0, 0, NULL, &dev_priv->vga_ram);
if (ret == 0)
ret = nouveau_bo_pin(dev_priv->vga_ram,
TTM_PL_FLAG_VRAM);
@@ -843,6 +844,7 @@ nouveau_mem_timing_calc(struct drm_device *dev, u32 freq,
ret = nv50_mem_timing_calc(dev, freq, e, len, boot, t);
break;
case NV_C0:
+ case NV_D0:
ret = nvc0_mem_timing_calc(dev, freq, e, len, boot, t);
break;
default:
@@ -977,6 +979,8 @@ nouveau_mem_exec(struct nouveau_mem_exec_func *exec,
break;
case NV_MEM_TYPE_DDR3:
tDLLK = 12000;
+ tCKSRE = 2000;
+ tXS = 1000;
mr1_dlloff = 0x00000001;
break;
case NV_MEM_TYPE_GDDR3:
@@ -1023,6 +1027,7 @@ nouveau_mem_exec(struct nouveau_mem_exec_func *exec,
exec->refresh_self(exec, false);
exec->refresh_auto(exec, true);
exec->wait(exec, tXS);
+ exec->wait(exec, tXS);
/* update MRs */
if (mr[2] != info->mr[2]) {
diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c
index cc419fae794b..b190cc01c820 100644
--- a/drivers/gpu/drm/nouveau/nouveau_object.c
+++ b/drivers/gpu/drm/nouveau/nouveau_object.c
@@ -34,9 +34,10 @@
#include "drm.h"
#include "nouveau_drv.h"
#include "nouveau_drm.h"
+#include "nouveau_fifo.h"
#include "nouveau_ramht.h"
+#include "nouveau_software.h"
#include "nouveau_vm.h"
-#include "nv50_display.h"
struct nouveau_gpuobj_method {
struct list_head head;
@@ -120,12 +121,13 @@ nouveau_gpuobj_mthd_call2(struct drm_device *dev, int chid,
u32 class, u32 mthd, u32 data)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct nouveau_channel *chan = NULL;
unsigned long flags;
int ret = -EINVAL;
spin_lock_irqsave(&dev_priv->channels.lock, flags);
- if (chid >= 0 && chid < dev_priv->engine.fifo.channels)
+ if (chid >= 0 && chid < pfifo->channels)
chan = dev_priv->channels.ptr[chid];
if (chan)
ret = nouveau_gpuobj_mthd_call(chan, class, mthd, data);
@@ -133,37 +135,6 @@ nouveau_gpuobj_mthd_call2(struct drm_device *dev, int chid,
return ret;
}
-/* NVidia uses context objects to drive drawing operations.
-
- Context objects can be selected into 8 subchannels in the FIFO,
- and then used via DMA command buffers.
-
- A context object is referenced by a user defined handle (CARD32). The HW
- looks up graphics objects in a hash table in the instance RAM.
-
- An entry in the hash table consists of 2 CARD32. The first CARD32 contains
- the handle, the second one a bitfield, that contains the address of the
- object in instance RAM.
-
- The format of the second CARD32 seems to be:
-
- NV4 to NV30:
-
- 15: 0 instance_addr >> 4
- 17:16 engine (here uses 1 = graphics)
- 28:24 channel id (here uses 0)
- 31 valid (use 1)
-
- NV40:
-
- 15: 0 instance_addr >> 4 (maybe 19-0)
- 21:20 engine (here uses 1 = graphics)
- I'm unsure about the other bits, but using 0 seems to work.
-
- The key into the hash table depends on the object handle and channel id and
- is given as:
-*/
-
int
nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan,
uint32_t size, int align, uint32_t flags,
@@ -267,7 +238,7 @@ nouveau_gpuobj_takedown(struct drm_device *dev)
kfree(oc);
}
- BUG_ON(!list_empty(&dev_priv->gpuobj_list));
+ WARN_ON(!list_empty(&dev_priv->gpuobj_list));
}
@@ -361,34 +332,6 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, u32 pinst, u64 vinst,
return 0;
}
-/*
- DMA objects are used to reference a piece of memory in the
- framebuffer, PCI or AGP address space. Each object is 16 bytes big
- and looks as follows:
-
- entry[0]
- 11:0 class (seems like I can always use 0 here)
- 12 page table present?
- 13 page entry linear?
- 15:14 access: 0 rw, 1 ro, 2 wo
- 17:16 target: 0 NV memory, 1 NV memory tiled, 2 PCI, 3 AGP
- 31:20 dma adjust (bits 0-11 of the address)
- entry[1]
- dma limit (size of transfer)
- entry[X]
- 1 0 readonly, 1 readwrite
- 31:12 dma frame address of the page (bits 12-31 of the address)
- entry[N]
- page table terminator, same value as the first pte, as does nvidia
- rivatv uses 0xffffffff
-
- Non linear page tables need a list of frame addresses afterwards,
- the rivatv project has some info on this.
-
- The method below creates a DMA object in instance RAM and returns a handle
- to it that can be used to set up context objects.
-*/
-
void
nv50_gpuobj_dma_init(struct nouveau_gpuobj *obj, u32 offset, int class,
u64 base, u64 size, int target, int access,
@@ -540,82 +483,6 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base,
return 0;
}
-/* Context objects in the instance RAM have the following structure.
- * On NV40 they are 32 byte long, on NV30 and smaller 16 bytes.
-
- NV4 - NV30:
-
- entry[0]
- 11:0 class
- 12 chroma key enable
- 13 user clip enable
- 14 swizzle enable
- 17:15 patch config:
- scrcopy_and, rop_and, blend_and, scrcopy, srccopy_pre, blend_pre
- 18 synchronize enable
- 19 endian: 1 big, 0 little
- 21:20 dither mode
- 23 single step enable
- 24 patch status: 0 invalid, 1 valid
- 25 context_surface 0: 1 valid
- 26 context surface 1: 1 valid
- 27 context pattern: 1 valid
- 28 context rop: 1 valid
- 29,30 context beta, beta4
- entry[1]
- 7:0 mono format
- 15:8 color format
- 31:16 notify instance address
- entry[2]
- 15:0 dma 0 instance address
- 31:16 dma 1 instance address
- entry[3]
- dma method traps
-
- NV40:
- No idea what the exact format is. Here's what can be deducted:
-
- entry[0]:
- 11:0 class (maybe uses more bits here?)
- 17 user clip enable
- 21:19 patch config
- 25 patch status valid ?
- entry[1]:
- 15:0 DMA notifier (maybe 20:0)
- entry[2]:
- 15:0 DMA 0 instance (maybe 20:0)
- 24 big endian
- entry[3]:
- 15:0 DMA 1 instance (maybe 20:0)
- entry[4]:
- entry[5]:
- set to 0?
-*/
-static int
-nouveau_gpuobj_sw_new(struct nouveau_channel *chan, u32 handle, u16 class)
-{
- struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
- struct nouveau_gpuobj *gpuobj;
- int ret;
-
- gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL);
- if (!gpuobj)
- return -ENOMEM;
- gpuobj->dev = chan->dev;
- gpuobj->engine = NVOBJ_ENGINE_SW;
- gpuobj->class = class;
- kref_init(&gpuobj->refcount);
- gpuobj->cinst = 0x40;
-
- spin_lock(&dev_priv->ramin_lock);
- list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
- spin_unlock(&dev_priv->ramin_lock);
-
- ret = nouveau_ramht_insert(chan, handle, gpuobj);
- nouveau_gpuobj_ref(NULL, &gpuobj);
- return ret;
-}
-
int
nouveau_gpuobj_gr_new(struct nouveau_channel *chan, u32 handle, int class)
{
@@ -632,9 +499,6 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, u32 handle, int class)
if (oc->id != class)
continue;
- if (oc->engine == NVOBJ_ENGINE_SW)
- return nouveau_gpuobj_sw_new(chan, handle, class);
-
if (!chan->engctx[oc->engine]) {
ret = eng->context_new(chan, oc->engine);
if (ret)
@@ -644,7 +508,6 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, u32 handle, int class)
return eng->object_new(chan, oc->engine, handle, class);
}
- NV_ERROR(dev, "illegal object class: 0x%x\n", class);
return -EINVAL;
}
@@ -693,11 +556,10 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
static int
nvc0_gpuobj_channel_init(struct nouveau_channel *chan, struct nouveau_vm *vm)
{
- struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
struct drm_device *dev = chan->dev;
struct nouveau_gpuobj *pgd = NULL;
struct nouveau_vm_pgd *vpgd;
- int ret, i;
+ int ret;
ret = nouveau_gpuobj_new(dev, NULL, 4096, 0x1000, 0, &chan->ramin);
if (ret)
@@ -722,19 +584,6 @@ nvc0_gpuobj_channel_init(struct nouveau_channel *chan, struct nouveau_vm *vm)
nv_wo32(chan->ramin, 0x0208, 0xffffffff);
nv_wo32(chan->ramin, 0x020c, 0x000000ff);
- /* map display semaphore buffers into channel's vm */
- for (i = 0; i < dev->mode_config.num_crtc; i++) {
- struct nouveau_bo *bo;
- if (dev_priv->card_type >= NV_D0)
- bo = nvd0_display_crtc_sema(dev, i);
- else
- bo = nv50_display(dev)->crtc[i].sem.bo;
-
- ret = nouveau_bo_vma_add(bo, chan->vm, &chan->dispc_vma[i]);
- if (ret)
- return ret;
- }
-
return 0;
}
@@ -747,7 +596,7 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
struct nouveau_fpriv *fpriv = nouveau_fpriv(chan->file_priv);
struct nouveau_vm *vm = fpriv ? fpriv->vm : dev_priv->chan_vm;
struct nouveau_gpuobj *vram = NULL, *tt = NULL;
- int ret, i;
+ int ret;
NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h);
if (dev_priv->card_type >= NV_C0)
@@ -795,25 +644,6 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
nouveau_gpuobj_ref(NULL, &ramht);
if (ret)
return ret;
-
- /* dma objects for display sync channel semaphore blocks */
- for (i = 0; i < dev->mode_config.num_crtc; i++) {
- struct nouveau_gpuobj *sem = NULL;
- struct nv50_display_crtc *dispc =
- &nv50_display(dev)->crtc[i];
- u64 offset = dispc->sem.bo->bo.offset;
-
- ret = nouveau_gpuobj_dma_new(chan, 0x3d, offset, 0xfff,
- NV_MEM_ACCESS_RW,
- NV_MEM_TARGET_VRAM, &sem);
- if (ret)
- return ret;
-
- ret = nouveau_ramht_insert(chan, NvEvoSema0 + i, sem);
- nouveau_gpuobj_ref(NULL, &sem);
- if (ret)
- return ret;
- }
}
/* VRAM ctxdma */
@@ -873,25 +703,7 @@ nouveau_gpuobj_channel_init(struct nouveau_channel *chan,
void
nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan)
{
- struct drm_device *dev = chan->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- int i;
-
- NV_DEBUG(dev, "ch%d\n", chan->id);
-
- if (dev_priv->card_type >= NV_D0) {
- for (i = 0; i < dev->mode_config.num_crtc; i++) {
- struct nouveau_bo *bo = nvd0_display_crtc_sema(dev, i);
- nouveau_bo_vma_del(bo, &chan->dispc_vma[i]);
- }
- } else
- if (dev_priv->card_type >= NV_50) {
- struct nv50_display *disp = nv50_display(dev);
- for (i = 0; i < dev->mode_config.num_crtc; i++) {
- struct nv50_display_crtc *dispc = &disp->crtc[i];
- nouveau_bo_vma_del(dispc->sem.bo, &chan->dispc_vma[i]);
- }
- }
+ NV_DEBUG(chan->dev, "ch%d\n", chan->id);
nouveau_vm_ref(NULL, &chan->vm, chan->vm_pd);
nouveau_gpuobj_ref(NULL, &chan->vm_pd);
@@ -956,6 +768,17 @@ int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data,
if (init->handle == ~0)
return -EINVAL;
+ /* compatibility with userspace that assumes 506e for all chipsets */
+ if (init->class == 0x506e) {
+ init->class = nouveau_software_class(dev);
+ if (init->class == 0x906e)
+ return 0;
+ } else
+ if (init->class == 0x906e) {
+ NV_ERROR(dev, "906e not supported yet\n");
+ return -EINVAL;
+ }
+
chan = nouveau_channel_get(file_priv, init->channel);
if (IS_ERR(chan))
return PTR_ERR(chan);
diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c
index 69a528d106e6..ea6acf1c4a78 100644
--- a/drivers/gpu/drm/nouveau/nouveau_perf.c
+++ b/drivers/gpu/drm/nouveau/nouveau_perf.c
@@ -83,7 +83,7 @@ nouveau_perf_entry(struct drm_device *dev, int idx,
return NULL;
}
-static u8 *
+u8 *
nouveau_perf_rammap(struct drm_device *dev, u32 freq,
u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
{
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.h b/drivers/gpu/drm/nouveau/nouveau_pm.h
index 3f82dfea61dd..07cac72c72b4 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.h
@@ -61,8 +61,10 @@ int nouveau_voltage_gpio_set(struct drm_device *, int voltage);
/* nouveau_perf.c */
void nouveau_perf_init(struct drm_device *);
void nouveau_perf_fini(struct drm_device *);
-u8 *nouveau_perf_timing(struct drm_device *, u32 freq, u8 *ver, u8 *len);
+u8 *nouveau_perf_rammap(struct drm_device *, u32 freq, u8 *ver,
+ u8 *hdr, u8 *cnt, u8 *len);
u8 *nouveau_perf_ramcfg(struct drm_device *, u32 freq, u8 *ver, u8 *len);
+u8 *nouveau_perf_timing(struct drm_device *, u32 freq, u8 *ver, u8 *len);
/* nouveau_mem.c */
void nouveau_mem_timing_init(struct drm_device *);
diff --git a/drivers/gpu/drm/nouveau/nouveau_prime.c b/drivers/gpu/drm/nouveau/nouveau_prime.c
new file mode 100644
index 000000000000..c58aab7370c5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_prime.c
@@ -0,0 +1,163 @@
+
+#include "drmP.h"
+#include "drm.h"
+
+#include "nouveau_drv.h"
+#include "nouveau_drm.h"
+#include "nouveau_dma.h"
+
+#include <linux/dma-buf.h>
+
+static struct sg_table *nouveau_gem_map_dma_buf(struct dma_buf_attachment *attachment,
+ enum dma_data_direction dir)
+{
+ struct nouveau_bo *nvbo = attachment->dmabuf->priv;
+ struct drm_device *dev = nvbo->gem->dev;
+ int npages = nvbo->bo.num_pages;
+ struct sg_table *sg;
+ int nents;
+
+ mutex_lock(&dev->struct_mutex);
+ sg = drm_prime_pages_to_sg(nvbo->bo.ttm->pages, npages);
+ nents = dma_map_sg(attachment->dev, sg->sgl, sg->nents, dir);
+ mutex_unlock(&dev->struct_mutex);
+ return sg;
+}
+
+static void nouveau_gem_unmap_dma_buf(struct dma_buf_attachment *attachment,
+ struct sg_table *sg, enum dma_data_direction dir)
+{
+ dma_unmap_sg(attachment->dev, sg->sgl, sg->nents, dir);
+ sg_free_table(sg);
+ kfree(sg);
+}
+
+static void nouveau_gem_dmabuf_release(struct dma_buf *dma_buf)
+{
+ struct nouveau_bo *nvbo = dma_buf->priv;
+
+ if (nvbo->gem->export_dma_buf == dma_buf) {
+ nvbo->gem->export_dma_buf = NULL;
+ drm_gem_object_unreference_unlocked(nvbo->gem);
+ }
+}
+
+static void *nouveau_gem_kmap_atomic(struct dma_buf *dma_buf, unsigned long page_num)
+{
+ return NULL;
+}
+
+static void nouveau_gem_kunmap_atomic(struct dma_buf *dma_buf, unsigned long page_num, void *addr)
+{
+
+}
+static void *nouveau_gem_kmap(struct dma_buf *dma_buf, unsigned long page_num)
+{
+ return NULL;
+}
+
+static void nouveau_gem_kunmap(struct dma_buf *dma_buf, unsigned long page_num, void *addr)
+{
+
+}
+
+static const struct dma_buf_ops nouveau_dmabuf_ops = {
+ .map_dma_buf = nouveau_gem_map_dma_buf,
+ .unmap_dma_buf = nouveau_gem_unmap_dma_buf,
+ .release = nouveau_gem_dmabuf_release,
+ .kmap = nouveau_gem_kmap,
+ .kmap_atomic = nouveau_gem_kmap_atomic,
+ .kunmap = nouveau_gem_kunmap,
+ .kunmap_atomic = nouveau_gem_kunmap_atomic,
+};
+
+static int
+nouveau_prime_new(struct drm_device *dev,
+ size_t size,
+ struct sg_table *sg,
+ struct nouveau_bo **pnvbo)
+{
+ struct nouveau_bo *nvbo;
+ u32 flags = 0;
+ int ret;
+
+ flags = TTM_PL_FLAG_TT;
+
+ ret = nouveau_bo_new(dev, size, 0, flags, 0, 0,
+ sg, pnvbo);
+ if (ret)
+ return ret;
+ nvbo = *pnvbo;
+
+ /* we restrict allowed domains on nv50+ to only the types
+ * that were requested at creation time. not possibly on
+ * earlier chips without busting the ABI.
+ */
+ nvbo->valid_domains = NOUVEAU_GEM_DOMAIN_GART;
+ nvbo->gem = drm_gem_object_alloc(dev, nvbo->bo.mem.size);
+ if (!nvbo->gem) {
+ nouveau_bo_ref(NULL, pnvbo);
+ return -ENOMEM;
+ }
+
+ nvbo->gem->driver_private = nvbo;
+ return 0;
+}
+
+struct dma_buf *nouveau_gem_prime_export(struct drm_device *dev,
+ struct drm_gem_object *obj, int flags)
+{
+ struct nouveau_bo *nvbo = nouveau_gem_object(obj);
+ int ret = 0;
+
+ /* pin buffer into GTT */
+ ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_TT);
+ if (ret)
+ return ERR_PTR(-EINVAL);
+
+ return dma_buf_export(nvbo, &nouveau_dmabuf_ops, obj->size, flags);
+}
+
+struct drm_gem_object *nouveau_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *dma_buf)
+{
+ struct dma_buf_attachment *attach;
+ struct sg_table *sg;
+ struct nouveau_bo *nvbo;
+ int ret;
+
+ if (dma_buf->ops == &nouveau_dmabuf_ops) {
+ nvbo = dma_buf->priv;
+ if (nvbo->gem) {
+ if (nvbo->gem->dev == dev) {
+ drm_gem_object_reference(nvbo->gem);
+ return nvbo->gem;
+ }
+ }
+ }
+ /* need to attach */
+ attach = dma_buf_attach(dma_buf, dev->dev);
+ if (IS_ERR(attach))
+ return ERR_PTR(PTR_ERR(attach));
+
+ sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+ if (IS_ERR(sg)) {
+ ret = PTR_ERR(sg);
+ goto fail_detach;
+ }
+
+ ret = nouveau_prime_new(dev, dma_buf->size, sg, &nvbo);
+ if (ret)
+ goto fail_unmap;
+
+ nvbo->gem->import_attach = attach;
+
+ return nvbo->gem;
+
+fail_unmap:
+ dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);
+fail_detach:
+ dma_buf_detach(dma_buf, attach);
+ return ERR_PTR(ret);
+}
+
diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
index 47f245edf538..38483a042bc2 100644
--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
@@ -290,7 +290,10 @@ nv50_sgdma_bind(struct ttm_tt *ttm, struct ttm_mem_reg *mem)
struct nouveau_mem *node = mem->mm_node;
/* noop: bound in move_notify() */
- node->pages = nvbe->ttm.dma_address;
+ if (ttm->sg) {
+ node->sg = ttm->sg;
+ } else
+ node->pages = nvbe->ttm.dma_address;
return 0;
}
@@ -338,10 +341,10 @@ nouveau_sgdma_init(struct drm_device *dev)
u32 aper_size, align;
int ret;
- if (dev_priv->card_type >= NV_40 && pci_is_pcie(dev->pdev))
+ if (dev_priv->card_type >= NV_40)
aper_size = 512 * 1024 * 1024;
else
- aper_size = 64 * 1024 * 1024;
+ aper_size = 128 * 1024 * 1024;
/* Dear NVIDIA, NV44+ would like proper present bits in PTEs for
* christmas. The cards before it have them, the cards after
diff --git a/drivers/gpu/drm/nouveau/nouveau_software.h b/drivers/gpu/drm/nouveau/nouveau_software.h
new file mode 100644
index 000000000000..e60bc6ce9003
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nouveau_software.h
@@ -0,0 +1,69 @@
+#ifndef __NOUVEAU_SOFTWARE_H__
+#define __NOUVEAU_SOFTWARE_H__
+
+struct nouveau_software_priv {
+ struct nouveau_exec_engine base;
+ struct list_head vblank;
+};
+
+struct nouveau_software_chan {
+ struct list_head flip;
+ struct {
+ struct list_head list;
+ struct nouveau_bo *bo;
+ u32 offset;
+ u32 value;
+ u32 head;
+ } vblank;
+};
+
+static inline void
+nouveau_software_vblank(struct drm_device *dev, int crtc)
+{
+ struct nouveau_software_priv *psw = nv_engine(dev, NVOBJ_ENGINE_SW);
+ struct nouveau_software_chan *pch, *tmp;
+
+ list_for_each_entry_safe(pch, tmp, &psw->vblank, vblank.list) {
+ if (pch->vblank.head != crtc)
+ continue;
+
+ nouveau_bo_wr32(pch->vblank.bo, pch->vblank.offset,
+ pch->vblank.value);
+ list_del(&pch->vblank.list);
+ drm_vblank_put(dev, crtc);
+ }
+}
+
+static inline void
+nouveau_software_context_new(struct nouveau_software_chan *pch)
+{
+ INIT_LIST_HEAD(&pch->flip);
+}
+
+static inline void
+nouveau_software_create(struct nouveau_software_priv *psw)
+{
+ INIT_LIST_HEAD(&psw->vblank);
+}
+
+static inline u16
+nouveau_software_class(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ if (dev_priv->card_type <= NV_04)
+ return 0x006e;
+ if (dev_priv->card_type <= NV_40)
+ return 0x016e;
+ if (dev_priv->card_type <= NV_50)
+ return 0x506e;
+ if (dev_priv->card_type <= NV_E0)
+ return 0x906e;
+ return 0x0000;
+}
+
+int nv04_software_create(struct drm_device *);
+int nv50_software_create(struct drm_device *);
+int nvc0_software_create(struct drm_device *);
+u64 nvc0_software_crtc(struct nouveau_channel *, int crtc);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index c2a8511e855a..19706f0532ea 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -39,6 +39,9 @@
#include "nouveau_gpio.h"
#include "nouveau_pm.h"
#include "nv50_display.h"
+#include "nouveau_fifo.h"
+#include "nouveau_fence.h"
+#include "nouveau_software.h"
static void nouveau_stub_takedown(struct drm_device *dev) {}
static int nouveau_stub_init(struct drm_device *dev) { return 0; }
@@ -66,18 +69,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nv04_fb_init;
engine->fb.takedown = nv04_fb_takedown;
- engine->fifo.channels = 16;
- engine->fifo.init = nv04_fifo_init;
- engine->fifo.takedown = nv04_fifo_fini;
- engine->fifo.disable = nv04_fifo_disable;
- engine->fifo.enable = nv04_fifo_enable;
- engine->fifo.reassign = nv04_fifo_reassign;
- engine->fifo.cache_pull = nv04_fifo_cache_pull;
- engine->fifo.channel_id = nv04_fifo_channel_id;
- engine->fifo.create_context = nv04_fifo_create_context;
- engine->fifo.destroy_context = nv04_fifo_destroy_context;
- engine->fifo.load_context = nv04_fifo_load_context;
- engine->fifo.unload_context = nv04_fifo_unload_context;
engine->display.early_init = nv04_display_early_init;
engine->display.late_takedown = nv04_display_late_takedown;
engine->display.create = nv04_display_create;
@@ -111,18 +102,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fb.init_tile_region = nv10_fb_init_tile_region;
engine->fb.set_tile_region = nv10_fb_set_tile_region;
engine->fb.free_tile_region = nv10_fb_free_tile_region;
- engine->fifo.channels = 32;
- engine->fifo.init = nv10_fifo_init;
- engine->fifo.takedown = nv04_fifo_fini;
- engine->fifo.disable = nv04_fifo_disable;
- engine->fifo.enable = nv04_fifo_enable;
- engine->fifo.reassign = nv04_fifo_reassign;
- engine->fifo.cache_pull = nv04_fifo_cache_pull;
- engine->fifo.channel_id = nv10_fifo_channel_id;
- engine->fifo.create_context = nv10_fifo_create_context;
- engine->fifo.destroy_context = nv04_fifo_destroy_context;
- engine->fifo.load_context = nv10_fifo_load_context;
- engine->fifo.unload_context = nv10_fifo_unload_context;
engine->display.early_init = nv04_display_early_init;
engine->display.late_takedown = nv04_display_late_takedown;
engine->display.create = nv04_display_create;
@@ -162,18 +141,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fb.init_tile_region = nv20_fb_init_tile_region;
engine->fb.set_tile_region = nv20_fb_set_tile_region;
engine->fb.free_tile_region = nv20_fb_free_tile_region;
- engine->fifo.channels = 32;
- engine->fifo.init = nv10_fifo_init;
- engine->fifo.takedown = nv04_fifo_fini;
- engine->fifo.disable = nv04_fifo_disable;
- engine->fifo.enable = nv04_fifo_enable;
- engine->fifo.reassign = nv04_fifo_reassign;
- engine->fifo.cache_pull = nv04_fifo_cache_pull;
- engine->fifo.channel_id = nv10_fifo_channel_id;
- engine->fifo.create_context = nv10_fifo_create_context;
- engine->fifo.destroy_context = nv04_fifo_destroy_context;
- engine->fifo.load_context = nv10_fifo_load_context;
- engine->fifo.unload_context = nv10_fifo_unload_context;
engine->display.early_init = nv04_display_early_init;
engine->display.late_takedown = nv04_display_late_takedown;
engine->display.create = nv04_display_create;
@@ -209,18 +176,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fb.init_tile_region = nv30_fb_init_tile_region;
engine->fb.set_tile_region = nv10_fb_set_tile_region;
engine->fb.free_tile_region = nv30_fb_free_tile_region;
- engine->fifo.channels = 32;
- engine->fifo.init = nv10_fifo_init;
- engine->fifo.takedown = nv04_fifo_fini;
- engine->fifo.disable = nv04_fifo_disable;
- engine->fifo.enable = nv04_fifo_enable;
- engine->fifo.reassign = nv04_fifo_reassign;
- engine->fifo.cache_pull = nv04_fifo_cache_pull;
- engine->fifo.channel_id = nv10_fifo_channel_id;
- engine->fifo.create_context = nv10_fifo_create_context;
- engine->fifo.destroy_context = nv04_fifo_destroy_context;
- engine->fifo.load_context = nv10_fifo_load_context;
- engine->fifo.unload_context = nv10_fifo_unload_context;
engine->display.early_init = nv04_display_early_init;
engine->display.late_takedown = nv04_display_late_takedown;
engine->display.create = nv04_display_create;
@@ -259,18 +214,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fb.init_tile_region = nv30_fb_init_tile_region;
engine->fb.set_tile_region = nv40_fb_set_tile_region;
engine->fb.free_tile_region = nv30_fb_free_tile_region;
- engine->fifo.channels = 32;
- engine->fifo.init = nv40_fifo_init;
- engine->fifo.takedown = nv04_fifo_fini;
- engine->fifo.disable = nv04_fifo_disable;
- engine->fifo.enable = nv04_fifo_enable;
- engine->fifo.reassign = nv04_fifo_reassign;
- engine->fifo.cache_pull = nv04_fifo_cache_pull;
- engine->fifo.channel_id = nv10_fifo_channel_id;
- engine->fifo.create_context = nv40_fifo_create_context;
- engine->fifo.destroy_context = nv04_fifo_destroy_context;
- engine->fifo.load_context = nv40_fifo_load_context;
- engine->fifo.unload_context = nv40_fifo_unload_context;
engine->display.early_init = nv04_display_early_init;
engine->display.late_takedown = nv04_display_late_takedown;
engine->display.create = nv04_display_create;
@@ -317,18 +260,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nv50_fb_init;
engine->fb.takedown = nv50_fb_takedown;
- engine->fifo.channels = 128;
- engine->fifo.init = nv50_fifo_init;
- engine->fifo.takedown = nv50_fifo_takedown;
- engine->fifo.disable = nv04_fifo_disable;
- engine->fifo.enable = nv04_fifo_enable;
- engine->fifo.reassign = nv04_fifo_reassign;
- engine->fifo.channel_id = nv50_fifo_channel_id;
- engine->fifo.create_context = nv50_fifo_create_context;
- engine->fifo.destroy_context = nv50_fifo_destroy_context;
- engine->fifo.load_context = nv50_fifo_load_context;
- engine->fifo.unload_context = nv50_fifo_unload_context;
- engine->fifo.tlb_flush = nv50_fifo_tlb_flush;
engine->display.early_init = nv50_display_early_init;
engine->display.late_takedown = nv50_display_late_takedown;
engine->display.create = nv50_display_create;
@@ -392,17 +323,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nvc0_fb_init;
engine->fb.takedown = nvc0_fb_takedown;
- engine->fifo.channels = 128;
- engine->fifo.init = nvc0_fifo_init;
- engine->fifo.takedown = nvc0_fifo_takedown;
- engine->fifo.disable = nvc0_fifo_disable;
- engine->fifo.enable = nvc0_fifo_enable;
- engine->fifo.reassign = nvc0_fifo_reassign;
- engine->fifo.channel_id = nvc0_fifo_channel_id;
- engine->fifo.create_context = nvc0_fifo_create_context;
- engine->fifo.destroy_context = nvc0_fifo_destroy_context;
- engine->fifo.load_context = nvc0_fifo_load_context;
- engine->fifo.unload_context = nvc0_fifo_unload_context;
engine->display.early_init = nv50_display_early_init;
engine->display.late_takedown = nv50_display_late_takedown;
engine->display.create = nv50_display_create;
@@ -445,17 +365,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nvc0_fb_init;
engine->fb.takedown = nvc0_fb_takedown;
- engine->fifo.channels = 128;
- engine->fifo.init = nvc0_fifo_init;
- engine->fifo.takedown = nvc0_fifo_takedown;
- engine->fifo.disable = nvc0_fifo_disable;
- engine->fifo.enable = nvc0_fifo_enable;
- engine->fifo.reassign = nvc0_fifo_reassign;
- engine->fifo.channel_id = nvc0_fifo_channel_id;
- engine->fifo.create_context = nvc0_fifo_create_context;
- engine->fifo.destroy_context = nvc0_fifo_destroy_context;
- engine->fifo.load_context = nvc0_fifo_load_context;
- engine->fifo.unload_context = nvc0_fifo_unload_context;
engine->display.early_init = nouveau_stub_init;
engine->display.late_takedown = nouveau_stub_takedown;
engine->display.create = nvd0_display_create;
@@ -496,13 +405,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nvc0_fb_init;
engine->fb.takedown = nvc0_fb_takedown;
- engine->fifo.channels = 0;
- engine->fifo.init = nouveau_stub_init;
- engine->fifo.takedown = nouveau_stub_takedown;
- engine->fifo.disable = nvc0_fifo_disable;
- engine->fifo.enable = nvc0_fifo_enable;
- engine->fifo.reassign = nvc0_fifo_reassign;
- engine->fifo.unload_context = nouveau_stub_init;
engine->display.early_init = nouveau_stub_init;
engine->display.late_takedown = nouveau_stub_takedown;
engine->display.create = nvd0_display_create;
@@ -607,61 +509,24 @@ nouveau_card_channel_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan;
- int ret, oclass;
+ int ret;
ret = nouveau_channel_alloc(dev, &chan, NULL, NvDmaFB, NvDmaTT);
dev_priv->channel = chan;
if (ret)
return ret;
-
mutex_unlock(&dev_priv->channel->mutex);
- if (dev_priv->card_type <= NV_50) {
- if (dev_priv->card_type < NV_50)
- oclass = 0x0039;
- else
- oclass = 0x5039;
-
- ret = nouveau_gpuobj_gr_new(chan, NvM2MF, oclass);
- if (ret)
- goto error;
-
- ret = nouveau_notifier_alloc(chan, NvNotify0, 32, 0xfe0, 0x1000,
- &chan->m2mf_ntfy);
- if (ret)
- goto error;
-
- ret = RING_SPACE(chan, 6);
- if (ret)
- goto error;
-
- BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NAME, 1);
- OUT_RING (chan, NvM2MF);
- BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 3);
- OUT_RING (chan, NvNotify0);
- OUT_RING (chan, chan->vram_handle);
- OUT_RING (chan, chan->gart_handle);
- } else
- if (dev_priv->card_type <= NV_D0) {
- ret = nouveau_gpuobj_gr_new(chan, 0x9039, 0x9039);
- if (ret)
- goto error;
-
- ret = RING_SPACE(chan, 2);
- if (ret)
- goto error;
-
- BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0000, 1);
- OUT_RING (chan, 0x00009039);
- }
-
- FIRE_RING (chan);
-error:
- if (ret)
- nouveau_card_channel_fini(dev);
- return ret;
+ nouveau_bo_move_init(chan);
+ return 0;
}
+static const struct vga_switcheroo_client_ops nouveau_switcheroo_ops = {
+ .set_gpu_state = nouveau_switcheroo_set_state,
+ .reprobe = nouveau_switcheroo_reprobe,
+ .can_switch = nouveau_switcheroo_can_switch,
+};
+
int
nouveau_card_init(struct drm_device *dev)
{
@@ -670,9 +535,7 @@ nouveau_card_init(struct drm_device *dev)
int ret, e = 0;
vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);
- vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state,
- nouveau_switcheroo_reprobe,
- nouveau_switcheroo_can_switch);
+ vga_switcheroo_register_client(dev->pdev, &nouveau_switcheroo_ops);
/* Initialise internal driver API hooks */
ret = nouveau_init_engine_ptrs(dev);
@@ -745,6 +608,81 @@ nouveau_card_init(struct drm_device *dev)
if (!dev_priv->noaccel) {
switch (dev_priv->card_type) {
case NV_04:
+ nv04_fifo_create(dev);
+ break;
+ case NV_10:
+ case NV_20:
+ case NV_30:
+ if (dev_priv->chipset < 0x17)
+ nv10_fifo_create(dev);
+ else
+ nv17_fifo_create(dev);
+ break;
+ case NV_40:
+ nv40_fifo_create(dev);
+ break;
+ case NV_50:
+ if (dev_priv->chipset == 0x50)
+ nv50_fifo_create(dev);
+ else
+ nv84_fifo_create(dev);
+ break;
+ case NV_C0:
+ case NV_D0:
+ nvc0_fifo_create(dev);
+ break;
+ case NV_E0:
+ nve0_fifo_create(dev);
+ break;
+ default:
+ break;
+ }
+
+ switch (dev_priv->card_type) {
+ case NV_04:
+ nv04_fence_create(dev);
+ break;
+ case NV_10:
+ case NV_20:
+ case NV_30:
+ case NV_40:
+ case NV_50:
+ if (dev_priv->chipset < 0x84)
+ nv10_fence_create(dev);
+ else
+ nv84_fence_create(dev);
+ break;
+ case NV_C0:
+ case NV_D0:
+ case NV_E0:
+ nvc0_fence_create(dev);
+ break;
+ default:
+ break;
+ }
+
+ switch (dev_priv->card_type) {
+ case NV_04:
+ case NV_10:
+ case NV_20:
+ case NV_30:
+ case NV_40:
+ nv04_software_create(dev);
+ break;
+ case NV_50:
+ nv50_software_create(dev);
+ break;
+ case NV_C0:
+ case NV_D0:
+ case NV_E0:
+ nvc0_software_create(dev);
+ break;
+ default:
+ break;
+ }
+
+ switch (dev_priv->card_type) {
+ case NV_04:
nv04_graph_create(dev);
break;
case NV_10:
@@ -764,6 +702,9 @@ nouveau_card_init(struct drm_device *dev)
case NV_D0:
nvc0_graph_create(dev);
break;
+ case NV_E0:
+ nve0_graph_create(dev);
+ break;
default:
break;
}
@@ -796,8 +737,9 @@ nouveau_card_init(struct drm_device *dev)
}
break;
case NV_C0:
- nvc0_copy_create(dev, 0);
nvc0_copy_create(dev, 1);
+ case NV_D0:
+ nvc0_copy_create(dev, 0);
break;
default:
break;
@@ -830,16 +772,11 @@ nouveau_card_init(struct drm_device *dev)
goto out_engine;
}
}
-
- /* PFIFO */
- ret = engine->fifo.init(dev);
- if (ret)
- goto out_engine;
}
ret = nouveau_irq_init(dev);
if (ret)
- goto out_fifo;
+ goto out_engine;
ret = nouveau_display_create(dev);
if (ret)
@@ -848,14 +785,10 @@ nouveau_card_init(struct drm_device *dev)
nouveau_backlight_init(dev);
nouveau_pm_init(dev);
- ret = nouveau_fence_init(dev);
- if (ret)
- goto out_pm;
-
if (dev_priv->eng[NVOBJ_ENGINE_GR]) {
ret = nouveau_card_channel_init(dev);
if (ret)
- goto out_fence;
+ goto out_pm;
}
if (dev->mode_config.num_crtc) {
@@ -870,17 +803,12 @@ nouveau_card_init(struct drm_device *dev)
out_chan:
nouveau_card_channel_fini(dev);
-out_fence:
- nouveau_fence_fini(dev);
out_pm:
nouveau_pm_fini(dev);
nouveau_backlight_exit(dev);
nouveau_display_destroy(dev);
out_irq:
nouveau_irq_fini(dev);
-out_fifo:
- if (!dev_priv->noaccel)
- engine->fifo.takedown(dev);
out_engine:
if (!dev_priv->noaccel) {
for (e = e - 1; e >= 0; e--) {
@@ -912,6 +840,7 @@ out_bios:
out_display_early:
engine->display.late_takedown(dev);
out:
+ vga_switcheroo_unregister_client(dev->pdev);
vga_client_register(dev->pdev, NULL, NULL, NULL);
return ret;
}
@@ -928,13 +857,11 @@ static void nouveau_card_takedown(struct drm_device *dev)
}
nouveau_card_channel_fini(dev);
- nouveau_fence_fini(dev);
nouveau_pm_fini(dev);
nouveau_backlight_exit(dev);
nouveau_display_destroy(dev);
if (!dev_priv->noaccel) {
- engine->fifo.takedown(dev);
for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
if (dev_priv->eng[e]) {
dev_priv->eng[e]->fini(dev, e, false);
@@ -969,6 +896,7 @@ static void nouveau_card_takedown(struct drm_device *dev)
nouveau_irq_fini(dev);
+ vga_switcheroo_unregister_client(dev->pdev);
vga_client_register(dev->pdev, NULL, NULL, NULL);
}
@@ -1176,7 +1104,7 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
goto err_priv;
}
- NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n",
+ NV_INFO(dev, "Detected an NV%02x generation card (0x%08x)\n",
dev_priv->card_type, reg0);
/* map the mmio regs, limiting the amount to preserve vmap space */
@@ -1219,6 +1147,8 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
if (nouveau_noaccel == -1) {
switch (dev_priv->chipset) {
case 0xd9: /* known broken */
+ case 0xe4: /* needs binary driver firmware */
+ case 0xe7: /* needs binary driver firmware */
NV_INFO(dev, "acceleration disabled by default, pass "
"noaccel=0 to force enable\n");
dev_priv->noaccel = true;
diff --git a/drivers/gpu/drm/nouveau/nouveau_vm.c b/drivers/gpu/drm/nouveau/nouveau_vm.c
index 2bf6c0350b4b..11edd5e91a0a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_vm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_vm.c
@@ -77,6 +77,63 @@ nouveau_vm_map(struct nouveau_vma *vma, struct nouveau_mem *node)
}
void
+nouveau_vm_map_sg_table(struct nouveau_vma *vma, u64 delta, u64 length,
+ struct nouveau_mem *mem)
+{
+ struct nouveau_vm *vm = vma->vm;
+ int big = vma->node->type != vm->spg_shift;
+ u32 offset = vma->node->offset + (delta >> 12);
+ u32 bits = vma->node->type - 12;
+ u32 num = length >> vma->node->type;
+ u32 pde = (offset >> vm->pgt_bits) - vm->fpde;
+ u32 pte = (offset & ((1 << vm->pgt_bits) - 1)) >> bits;
+ u32 max = 1 << (vm->pgt_bits - bits);
+ unsigned m, sglen;
+ u32 end, len;
+ int i;
+ struct scatterlist *sg;
+
+ for_each_sg(mem->sg->sgl, sg, mem->sg->nents, i) {
+ struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big];
+ sglen = sg_dma_len(sg) >> PAGE_SHIFT;
+
+ end = pte + sglen;
+ if (unlikely(end >= max))
+ end = max;
+ len = end - pte;
+
+ for (m = 0; m < len; m++) {
+ dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
+
+ vm->map_sg(vma, pgt, mem, pte, 1, &addr);
+ num--;
+ pte++;
+
+ if (num == 0)
+ goto finish;
+ }
+ if (unlikely(end >= max)) {
+ pde++;
+ pte = 0;
+ }
+ if (m < sglen) {
+ for (; m < sglen; m++) {
+ dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
+
+ vm->map_sg(vma, pgt, mem, pte, 1, &addr);
+ num--;
+ pte++;
+ if (num == 0)
+ goto finish;
+ }
+ }
+
+ }
+finish:
+ vm->flush(vm);
+}
+
+void
nouveau_vm_map_sg(struct nouveau_vma *vma, u64 delta, u64 length,
struct nouveau_mem *mem)
{
diff --git a/drivers/gpu/drm/nouveau/nouveau_vm.h b/drivers/gpu/drm/nouveau/nouveau_vm.h
index 4fb6e728734d..a8246e7e4a89 100644
--- a/drivers/gpu/drm/nouveau/nouveau_vm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_vm.h
@@ -72,6 +72,9 @@ struct nouveau_vm {
u64 phys, u64 delta);
void (*map_sg)(struct nouveau_vma *, struct nouveau_gpuobj *,
struct nouveau_mem *, u32 pte, u32 cnt, dma_addr_t *);
+
+ void (*map_sg_table)(struct nouveau_vma *, struct nouveau_gpuobj *,
+ struct nouveau_mem *, u32 pte, u32 cnt, dma_addr_t *);
void (*unmap)(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt);
void (*flush)(struct nouveau_vm *);
};
@@ -90,7 +93,8 @@ void nouveau_vm_unmap(struct nouveau_vma *);
void nouveau_vm_unmap_at(struct nouveau_vma *, u64 offset, u64 length);
void nouveau_vm_map_sg(struct nouveau_vma *, u64 offset, u64 length,
struct nouveau_mem *);
-
+void nouveau_vm_map_sg_table(struct nouveau_vma *vma, u64 delta, u64 length,
+ struct nouveau_mem *mem);
/* nv50_vm.c */
void nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde,
struct nouveau_gpuobj *pgt[2]);
diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c
index 728d07584d39..4c31c63e5528 100644
--- a/drivers/gpu/drm/nouveau/nv04_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv04_crtc.c
@@ -1047,7 +1047,7 @@ nv04_crtc_create(struct drm_device *dev, int crtc_num)
drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256);
ret = nouveau_bo_new(dev, 64*64*4, 0x100, TTM_PL_FLAG_VRAM,
- 0, 0x0000, &nv_crtc->cursor.nvbo);
+ 0, 0x0000, NULL, &nv_crtc->cursor.nvbo);
if (!ret) {
ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
if (!ret)
diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c
index 7047d37e8dab..44488e3a257d 100644
--- a/drivers/gpu/drm/nouveau/nv04_display.c
+++ b/drivers/gpu/drm/nouveau/nv04_display.c
@@ -98,6 +98,13 @@ nv04_display_early_init(struct drm_device *dev)
NVSetOwner(dev, 0);
}
+ /* ensure vblank interrupts are off, they can't be enabled until
+ * drm_vblank has been initialised
+ */
+ NVWriteCRTC(dev, 0, NV_PCRTC_INTR_EN_0, 0);
+ if (nv_two_heads(dev))
+ NVWriteCRTC(dev, 1, NV_PCRTC_INTR_EN_0, 0);
+
return 0;
}
@@ -246,6 +253,10 @@ nv04_display_init(struct drm_device *dev)
void
nv04_display_fini(struct drm_device *dev)
{
+ /* disable vblank interrupts */
+ NVWriteCRTC(dev, 0, NV_PCRTC_INTR_EN_0, 0);
+ if (nv_two_heads(dev))
+ NVWriteCRTC(dev, 1, NV_PCRTC_INTR_EN_0, 0);
}
static void
diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c
index 7a1189371096..7cd7857347ef 100644
--- a/drivers/gpu/drm/nouveau/nv04_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c
@@ -41,7 +41,7 @@ nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
if (ret)
return ret;
- BEGIN_RING(chan, NvSubImageBlit, 0x0300, 3);
+ BEGIN_NV04(chan, NvSubImageBlit, 0x0300, 3);
OUT_RING(chan, (region->sy << 16) | region->sx);
OUT_RING(chan, (region->dy << 16) | region->dx);
OUT_RING(chan, (region->height << 16) | region->width);
@@ -62,15 +62,15 @@ nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
if (ret)
return ret;
- BEGIN_RING(chan, NvSubGdiRect, 0x02fc, 1);
+ BEGIN_NV04(chan, NvSubGdiRect, 0x02fc, 1);
OUT_RING(chan, (rect->rop != ROP_COPY) ? 1 : 3);
- BEGIN_RING(chan, NvSubGdiRect, 0x03fc, 1);
+ BEGIN_NV04(chan, NvSubGdiRect, 0x03fc, 1);
if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
info->fix.visual == FB_VISUAL_DIRECTCOLOR)
OUT_RING(chan, ((uint32_t *)info->pseudo_palette)[rect->color]);
else
OUT_RING(chan, rect->color);
- BEGIN_RING(chan, NvSubGdiRect, 0x0400, 2);
+ BEGIN_NV04(chan, NvSubGdiRect, 0x0400, 2);
OUT_RING(chan, (rect->dx << 16) | rect->dy);
OUT_RING(chan, (rect->width << 16) | rect->height);
FIRE_RING(chan);
@@ -110,7 +110,7 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
bg = image->bg_color;
}
- BEGIN_RING(chan, NvSubGdiRect, 0x0be4, 7);
+ BEGIN_NV04(chan, NvSubGdiRect, 0x0be4, 7);
OUT_RING(chan, (image->dy << 16) | (image->dx & 0xffff));
OUT_RING(chan, ((image->dy + image->height) << 16) |
((image->dx + image->width) & 0xffff));
@@ -127,7 +127,7 @@ nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
if (ret)
return ret;
- BEGIN_RING(chan, NvSubGdiRect, 0x0c00, iter_len);
+ BEGIN_NV04(chan, NvSubGdiRect, 0x0c00, iter_len);
OUT_RINGp(chan, data, iter_len);
data += iter_len;
dsize -= iter_len;
@@ -209,25 +209,25 @@ nv04_fbcon_accel_init(struct fb_info *info)
return 0;
}
- BEGIN_RING(chan, sub, 0x0000, 1);
+ BEGIN_NV04(chan, sub, 0x0000, 1);
OUT_RING(chan, NvCtxSurf2D);
- BEGIN_RING(chan, sub, 0x0184, 2);
+ BEGIN_NV04(chan, sub, 0x0184, 2);
OUT_RING(chan, NvDmaFB);
OUT_RING(chan, NvDmaFB);
- BEGIN_RING(chan, sub, 0x0300, 4);
+ BEGIN_NV04(chan, sub, 0x0300, 4);
OUT_RING(chan, surface_fmt);
OUT_RING(chan, info->fix.line_length | (info->fix.line_length << 16));
OUT_RING(chan, info->fix.smem_start - dev->mode_config.fb_base);
OUT_RING(chan, info->fix.smem_start - dev->mode_config.fb_base);
- BEGIN_RING(chan, sub, 0x0000, 1);
+ BEGIN_NV04(chan, sub, 0x0000, 1);
OUT_RING(chan, NvRop);
- BEGIN_RING(chan, sub, 0x0300, 1);
+ BEGIN_NV04(chan, sub, 0x0300, 1);
OUT_RING(chan, 0x55);
- BEGIN_RING(chan, sub, 0x0000, 1);
+ BEGIN_NV04(chan, sub, 0x0000, 1);
OUT_RING(chan, NvImagePatt);
- BEGIN_RING(chan, sub, 0x0300, 8);
+ BEGIN_NV04(chan, sub, 0x0300, 8);
OUT_RING(chan, pattern_fmt);
#ifdef __BIG_ENDIAN
OUT_RING(chan, 2);
@@ -241,31 +241,31 @@ nv04_fbcon_accel_init(struct fb_info *info)
OUT_RING(chan, ~0);
OUT_RING(chan, ~0);
- BEGIN_RING(chan, sub, 0x0000, 1);
+ BEGIN_NV04(chan, sub, 0x0000, 1);
OUT_RING(chan, NvClipRect);
- BEGIN_RING(chan, sub, 0x0300, 2);
+ BEGIN_NV04(chan, sub, 0x0300, 2);
OUT_RING(chan, 0);
OUT_RING(chan, (info->var.yres_virtual << 16) | info->var.xres_virtual);
- BEGIN_RING(chan, NvSubImageBlit, 0x0000, 1);
+ BEGIN_NV04(chan, NvSubImageBlit, 0x0000, 1);
OUT_RING(chan, NvImageBlit);
- BEGIN_RING(chan, NvSubImageBlit, 0x019c, 1);
+ BEGIN_NV04(chan, NvSubImageBlit, 0x019c, 1);
OUT_RING(chan, NvCtxSurf2D);
- BEGIN_RING(chan, NvSubImageBlit, 0x02fc, 1);
+ BEGIN_NV04(chan, NvSubImageBlit, 0x02fc, 1);
OUT_RING(chan, 3);
- BEGIN_RING(chan, NvSubGdiRect, 0x0000, 1);
+ BEGIN_NV04(chan, NvSubGdiRect, 0x0000, 1);
OUT_RING(chan, NvGdiRect);
- BEGIN_RING(chan, NvSubGdiRect, 0x0198, 1);
+ BEGIN_NV04(chan, NvSubGdiRect, 0x0198, 1);
OUT_RING(chan, NvCtxSurf2D);
- BEGIN_RING(chan, NvSubGdiRect, 0x0188, 2);
+ BEGIN_NV04(chan, NvSubGdiRect, 0x0188, 2);
OUT_RING(chan, NvImagePatt);
OUT_RING(chan, NvRop);
- BEGIN_RING(chan, NvSubGdiRect, 0x0304, 1);
+ BEGIN_NV04(chan, NvSubGdiRect, 0x0304, 1);
OUT_RING(chan, 1);
- BEGIN_RING(chan, NvSubGdiRect, 0x0300, 1);
+ BEGIN_NV04(chan, NvSubGdiRect, 0x0300, 1);
OUT_RING(chan, rect_fmt);
- BEGIN_RING(chan, NvSubGdiRect, 0x02fc, 1);
+ BEGIN_NV04(chan, NvSubGdiRect, 0x02fc, 1);
OUT_RING(chan, 3);
FIRE_RING(chan);
diff --git a/drivers/gpu/drm/nouveau/nv04_fence.c b/drivers/gpu/drm/nouveau/nv04_fence.c
new file mode 100644
index 000000000000..abe89db6de24
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv04_fence.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_dma.h"
+#include "nouveau_ramht.h"
+#include "nouveau_fence.h"
+
+struct nv04_fence_chan {
+ struct nouveau_fence_chan base;
+ atomic_t sequence;
+};
+
+struct nv04_fence_priv {
+ struct nouveau_fence_priv base;
+};
+
+static int
+nv04_fence_emit(struct nouveau_fence *fence)
+{
+ struct nouveau_channel *chan = fence->channel;
+ int ret = RING_SPACE(chan, 2);
+ if (ret == 0) {
+ BEGIN_NV04(chan, NvSubSw, 0x0150, 1);
+ OUT_RING (chan, fence->sequence);
+ FIRE_RING (chan);
+ }
+ return ret;
+}
+
+static int
+nv04_fence_sync(struct nouveau_fence *fence,
+ struct nouveau_channel *prev, struct nouveau_channel *chan)
+{
+ return -ENODEV;
+}
+
+int
+nv04_fence_mthd(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
+{
+ struct nv04_fence_chan *fctx = chan->engctx[NVOBJ_ENGINE_FENCE];
+ atomic_set(&fctx->sequence, data);
+ return 0;
+}
+
+static u32
+nv04_fence_read(struct nouveau_channel *chan)
+{
+ struct nv04_fence_chan *fctx = chan->engctx[NVOBJ_ENGINE_FENCE];
+ return atomic_read(&fctx->sequence);
+}
+
+static void
+nv04_fence_context_del(struct nouveau_channel *chan, int engine)
+{
+ struct nv04_fence_chan *fctx = chan->engctx[engine];
+ nouveau_fence_context_del(&fctx->base);
+ chan->engctx[engine] = NULL;
+ kfree(fctx);
+}
+
+static int
+nv04_fence_context_new(struct nouveau_channel *chan, int engine)
+{
+ struct nv04_fence_chan *fctx = kzalloc(sizeof(*fctx), GFP_KERNEL);
+ if (fctx) {
+ nouveau_fence_context_new(&fctx->base);
+ atomic_set(&fctx->sequence, 0);
+ chan->engctx[engine] = fctx;
+ return 0;
+ }
+ return -ENOMEM;
+}
+
+static int
+nv04_fence_fini(struct drm_device *dev, int engine, bool suspend)
+{
+ return 0;
+}
+
+static int
+nv04_fence_init(struct drm_device *dev, int engine)
+{
+ return 0;
+}
+
+static void
+nv04_fence_destroy(struct drm_device *dev, int engine)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv04_fence_priv *priv = nv_engine(dev, engine);
+
+ dev_priv->eng[engine] = NULL;
+ kfree(priv);
+}
+
+int
+nv04_fence_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv04_fence_priv *priv;
+ int ret;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base.engine.destroy = nv04_fence_destroy;
+ priv->base.engine.init = nv04_fence_init;
+ priv->base.engine.fini = nv04_fence_fini;
+ priv->base.engine.context_new = nv04_fence_context_new;
+ priv->base.engine.context_del = nv04_fence_context_del;
+ priv->base.emit = nv04_fence_emit;
+ priv->base.sync = nv04_fence_sync;
+ priv->base.read = nv04_fence_read;
+ dev_priv->eng[NVOBJ_ENGINE_FENCE] = &priv->base.engine;
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nv04_fifo.c b/drivers/gpu/drm/nouveau/nv04_fifo.c
index db465a3ee1b2..a6295cd00ec7 100644
--- a/drivers/gpu/drm/nouveau/nv04_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv04_fifo.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Ben Skeggs.
+ * Copyright (C) 2012 Ben Skeggs.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
@@ -27,49 +27,38 @@
#include "drmP.h"
#include "drm.h"
#include "nouveau_drv.h"
-#include "nouveau_ramht.h"
+#include "nouveau_fifo.h"
#include "nouveau_util.h"
-
-#define NV04_RAMFC(c) (dev_priv->ramfc->pinst + ((c) * NV04_RAMFC__SIZE))
-#define NV04_RAMFC__SIZE 32
-#define NV04_RAMFC_DMA_PUT 0x00
-#define NV04_RAMFC_DMA_GET 0x04
-#define NV04_RAMFC_DMA_INSTANCE 0x08
-#define NV04_RAMFC_DMA_STATE 0x0C
-#define NV04_RAMFC_DMA_FETCH 0x10
-#define NV04_RAMFC_ENGINE 0x14
-#define NV04_RAMFC_PULL1_ENGINE 0x18
-
-#define RAMFC_WR(offset, val) nv_wo32(chan->ramfc, NV04_RAMFC_##offset, (val))
-#define RAMFC_RD(offset) nv_ro32(chan->ramfc, NV04_RAMFC_##offset)
-
-void
-nv04_fifo_disable(struct drm_device *dev)
-{
- uint32_t tmp;
-
- tmp = nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUSH);
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, tmp & ~1);
- nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 0);
- tmp = nv_rd32(dev, NV03_PFIFO_CACHE1_PULL1);
- nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, tmp & ~1);
-}
-
-void
-nv04_fifo_enable(struct drm_device *dev)
-{
- nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 1);
- nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
-}
-
-bool
-nv04_fifo_reassign(struct drm_device *dev, bool enable)
-{
- uint32_t reassign = nv_rd32(dev, NV03_PFIFO_CACHES);
-
- nv_wr32(dev, NV03_PFIFO_CACHES, enable ? 1 : 0);
- return (reassign == 1);
-}
+#include "nouveau_ramht.h"
+#include "nouveau_software.h"
+
+static struct ramfc_desc {
+ unsigned bits:6;
+ unsigned ctxs:5;
+ unsigned ctxp:8;
+ unsigned regs:5;
+ unsigned regp;
+} nv04_ramfc[] = {
+ { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
+ { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
+ { 16, 0, 0x08, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
+ { 16, 16, 0x08, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
+ { 32, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_STATE },
+ { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
+ { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_ENGINE },
+ { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_PULL1 },
+ {}
+};
+
+struct nv04_fifo_priv {
+ struct nouveau_fifo_priv base;
+ struct ramfc_desc *ramfc_desc;
+};
+
+struct nv04_fifo_chan {
+ struct nouveau_fifo_chan base;
+ struct nouveau_gpuobj *ramfc;
+};
bool
nv04_fifo_cache_pull(struct drm_device *dev, bool enable)
@@ -86,13 +75,13 @@ nv04_fifo_cache_pull(struct drm_device *dev, bool enable)
* invalidate the most recently calculated instance.
*/
if (!nv_wait(dev, NV04_PFIFO_CACHE1_PULL0,
- NV04_PFIFO_CACHE1_PULL0_HASH_BUSY, 0))
+ NV04_PFIFO_CACHE1_PULL0_HASH_BUSY, 0))
NV_ERROR(dev, "Timeout idling the PFIFO puller.\n");
if (nv_rd32(dev, NV04_PFIFO_CACHE1_PULL0) &
- NV04_PFIFO_CACHE1_PULL0_HASH_FAILED)
+ NV04_PFIFO_CACHE1_PULL0_HASH_FAILED)
nv_wr32(dev, NV03_PFIFO_INTR_0,
- NV_PFIFO_INTR_CACHE_ERROR);
+ NV_PFIFO_INTR_CACHE_ERROR);
nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0);
}
@@ -100,242 +89,182 @@ nv04_fifo_cache_pull(struct drm_device *dev, bool enable)
return pull & 1;
}
-int
-nv04_fifo_channel_id(struct drm_device *dev)
-{
- return nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH1) &
- NV03_PFIFO_CACHE1_PUSH1_CHID_MASK;
-}
-
-#ifdef __BIG_ENDIAN
-#define DMA_FETCH_ENDIANNESS NV_PFIFO_CACHE1_BIG_ENDIAN
-#else
-#define DMA_FETCH_ENDIANNESS 0
-#endif
-
-int
-nv04_fifo_create_context(struct nouveau_channel *chan)
+static int
+nv04_fifo_context_new(struct nouveau_channel *chan, int engine)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv04_fifo_priv *priv = nv_engine(dev, engine);
+ struct nv04_fifo_chan *fctx;
unsigned long flags;
int ret;
- ret = nouveau_gpuobj_new_fake(dev, NV04_RAMFC(chan->id), ~0,
- NV04_RAMFC__SIZE,
- NVOBJ_FLAG_ZERO_ALLOC |
- NVOBJ_FLAG_ZERO_FREE,
- &chan->ramfc);
- if (ret)
- return ret;
+ fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
+ if (!fctx)
+ return -ENOMEM;
+ /* map channel control registers */
chan->user = ioremap(pci_resource_start(dev->pdev, 0) +
NV03_USER(chan->id), PAGE_SIZE);
- if (!chan->user)
- return -ENOMEM;
-
- spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-
- /* Setup initial state */
- RAMFC_WR(DMA_PUT, chan->pushbuf_base);
- RAMFC_WR(DMA_GET, chan->pushbuf_base);
- RAMFC_WR(DMA_INSTANCE, chan->pushbuf->pinst >> 4);
- RAMFC_WR(DMA_FETCH, (NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
- DMA_FETCH_ENDIANNESS));
+ if (!chan->user) {
+ ret = -ENOMEM;
+ goto error;
+ }
- /* enable the fifo dma operation */
- nv_wr32(dev, NV04_PFIFO_MODE,
- nv_rd32(dev, NV04_PFIFO_MODE) | (1 << chan->id));
+ /* initialise default fifo context */
+ ret = nouveau_gpuobj_new_fake(dev, dev_priv->ramfc->pinst +
+ chan->id * 32, ~0, 32,
+ NVOBJ_FLAG_ZERO_FREE, &fctx->ramfc);
+ if (ret)
+ goto error;
+
+ nv_wo32(fctx->ramfc, 0x00, chan->pushbuf_base);
+ nv_wo32(fctx->ramfc, 0x04, chan->pushbuf_base);
+ nv_wo32(fctx->ramfc, 0x08, chan->pushbuf->pinst >> 4);
+ nv_wo32(fctx->ramfc, 0x0c, 0x00000000);
+ nv_wo32(fctx->ramfc, 0x10, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
+ NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
+#ifdef __BIG_ENDIAN
+ NV_PFIFO_CACHE1_BIG_ENDIAN |
+#endif
+ NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
+ nv_wo32(fctx->ramfc, 0x14, 0x00000000);
+ nv_wo32(fctx->ramfc, 0x18, 0x00000000);
+ nv_wo32(fctx->ramfc, 0x1c, 0x00000000);
+ /* enable dma mode on the channel */
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ nv_mask(dev, NV04_PFIFO_MODE, (1 << chan->id), (1 << chan->id));
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
- return 0;
+
+error:
+ if (ret)
+ priv->base.base.context_del(chan, engine);
+ return ret;
}
void
-nv04_fifo_destroy_context(struct nouveau_channel *chan)
+nv04_fifo_context_del(struct nouveau_channel *chan, int engine)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+ struct nv04_fifo_priv *priv = nv_engine(chan->dev, engine);
+ struct nv04_fifo_chan *fctx = chan->engctx[engine];
+ struct ramfc_desc *c = priv->ramfc_desc;
unsigned long flags;
+ int chid;
+ /* prevent fifo context switches */
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
- pfifo->reassign(dev, false);
-
- /* Unload the context if it's the currently active one */
- if (pfifo->channel_id(dev) == chan->id) {
- pfifo->disable(dev);
- pfifo->unload_context(dev);
- pfifo->enable(dev);
+ nv_wr32(dev, NV03_PFIFO_CACHES, 0);
+
+ /* if this channel is active, replace it with a null context */
+ chid = nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH1) & priv->base.channels;
+ if (chid == chan->id) {
+ nv_mask(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0);
+ nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 0);
+ nv_mask(dev, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0);
+
+ do {
+ u32 mask = ((1ULL << c->bits) - 1) << c->regs;
+ nv_mask(dev, c->regp, mask, 0x00000000);
+ } while ((++c)->bits);
+
+ nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
+ nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
+ nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, priv->base.channels);
+ nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 1);
+ nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
}
- /* Keep it from being rescheduled */
+ /* restore normal operation, after disabling dma mode */
nv_mask(dev, NV04_PFIFO_MODE, 1 << chan->id, 0);
-
- pfifo->reassign(dev, true);
+ nv_wr32(dev, NV03_PFIFO_CACHES, 1);
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
- /* Free the channel resources */
+ /* clean up */
+ nouveau_gpuobj_ref(NULL, &fctx->ramfc);
+ nouveau_gpuobj_ref(NULL, &chan->ramfc); /*XXX: nv40 */
if (chan->user) {
iounmap(chan->user);
chan->user = NULL;
}
- nouveau_gpuobj_ref(NULL, &chan->ramfc);
-}
-
-static void
-nv04_fifo_do_load_context(struct drm_device *dev, int chid)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t fc = NV04_RAMFC(chid), tmp;
-
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0));
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4));
- tmp = nv_ri32(dev, fc + 8);
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_INSTANCE, tmp & 0xFFFF);
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_DCOUNT, tmp >> 16);
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_STATE, nv_ri32(dev, fc + 12));
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_FETCH, nv_ri32(dev, fc + 16));
- nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_ri32(dev, fc + 20));
- nv_wr32(dev, NV04_PFIFO_CACHE1_PULL1, nv_ri32(dev, fc + 24));
-
- nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
- nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
-}
-
-int
-nv04_fifo_load_context(struct nouveau_channel *chan)
-{
- uint32_t tmp;
-
- nv_wr32(chan->dev, NV03_PFIFO_CACHE1_PUSH1,
- NV03_PFIFO_CACHE1_PUSH1_DMA | chan->id);
- nv04_fifo_do_load_context(chan->dev, chan->id);
- nv_wr32(chan->dev, NV04_PFIFO_CACHE1_DMA_PUSH, 1);
-
- /* Reset NV04_PFIFO_CACHE1_DMA_CTL_AT_INFO to INVALID */
- tmp = nv_rd32(chan->dev, NV04_PFIFO_CACHE1_DMA_CTL) & ~(1 << 31);
- nv_wr32(chan->dev, NV04_PFIFO_CACHE1_DMA_CTL, tmp);
-
- return 0;
}
int
-nv04_fifo_unload_context(struct drm_device *dev)
+nv04_fifo_init(struct drm_device *dev, int engine)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- struct nouveau_channel *chan = NULL;
- uint32_t tmp;
- int chid;
-
- chid = pfifo->channel_id(dev);
- if (chid < 0 || chid >= dev_priv->engine.fifo.channels)
- return 0;
-
- chan = dev_priv->channels.ptr[chid];
- if (!chan) {
- NV_ERROR(dev, "Inactive channel on PFIFO: %d\n", chid);
- return -EINVAL;
- }
-
- RAMFC_WR(DMA_PUT, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT));
- RAMFC_WR(DMA_GET, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
- tmp = nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_DCOUNT) << 16;
- tmp |= nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_INSTANCE);
- RAMFC_WR(DMA_INSTANCE, tmp);
- RAMFC_WR(DMA_STATE, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_STATE));
- RAMFC_WR(DMA_FETCH, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_FETCH));
- RAMFC_WR(ENGINE, nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE));
- RAMFC_WR(PULL1_ENGINE, nv_rd32(dev, NV04_PFIFO_CACHE1_PULL1));
-
- nv04_fifo_do_load_context(dev, pfifo->channels - 1);
- nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1);
- return 0;
-}
+ struct nv04_fifo_priv *priv = nv_engine(dev, engine);
+ int i;
-static void
-nv04_fifo_init_reset(struct drm_device *dev)
-{
- nv_wr32(dev, NV03_PMC_ENABLE,
- nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PFIFO);
- nv_wr32(dev, NV03_PMC_ENABLE,
- nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PFIFO);
-
- nv_wr32(dev, 0x003224, 0x000f0078);
- nv_wr32(dev, 0x002044, 0x0101ffff);
- nv_wr32(dev, 0x002040, 0x000000ff);
- nv_wr32(dev, 0x002500, 0x00000000);
- nv_wr32(dev, 0x003000, 0x00000000);
- nv_wr32(dev, 0x003050, 0x00000000);
- nv_wr32(dev, 0x003200, 0x00000000);
- nv_wr32(dev, 0x003250, 0x00000000);
- nv_wr32(dev, 0x003220, 0x00000000);
-
- nv_wr32(dev, 0x003250, 0x00000000);
- nv_wr32(dev, 0x003270, 0x00000000);
- nv_wr32(dev, 0x003210, 0x00000000);
-}
+ nv_mask(dev, NV03_PMC_ENABLE, NV_PMC_ENABLE_PFIFO, 0);
+ nv_mask(dev, NV03_PMC_ENABLE, NV_PMC_ENABLE_PFIFO, NV_PMC_ENABLE_PFIFO);
-static void
-nv04_fifo_init_ramxx(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
+ nv_wr32(dev, NV04_PFIFO_DELAY_0, 0x000000ff);
+ nv_wr32(dev, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
((dev_priv->ramht->bits - 9) << 16) |
(dev_priv->ramht->gpuobj->pinst >> 8));
nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro->pinst >> 8);
nv_wr32(dev, NV03_PFIFO_RAMFC, dev_priv->ramfc->pinst >> 8);
-}
-static void
-nv04_fifo_init_intr(struct drm_device *dev)
-{
- nouveau_irq_register(dev, 8, nv04_fifo_isr);
- nv_wr32(dev, 0x002100, 0xffffffff);
- nv_wr32(dev, 0x002140, 0xffffffff);
+ nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, priv->base.channels);
+
+ nv_wr32(dev, NV03_PFIFO_INTR_0, 0xffffffff);
+ nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0xffffffff);
+
+ nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 1);
+ nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
+ nv_wr32(dev, NV03_PFIFO_CACHES, 1);
+
+ for (i = 0; i < priv->base.channels; i++) {
+ if (dev_priv->channels.ptr[i])
+ nv_mask(dev, NV04_PFIFO_MODE, (1 << i), (1 << i));
+ }
+
+ return 0;
}
int
-nv04_fifo_init(struct drm_device *dev)
+nv04_fifo_fini(struct drm_device *dev, int engine, bool suspend)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- int i;
-
- nv04_fifo_init_reset(dev);
- nv04_fifo_init_ramxx(dev);
-
- nv04_fifo_do_load_context(dev, pfifo->channels - 1);
- nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1);
+ struct nv04_fifo_priv *priv = nv_engine(dev, engine);
+ struct nouveau_channel *chan;
+ int chid;
- nv04_fifo_init_intr(dev);
- pfifo->enable(dev);
- pfifo->reassign(dev, true);
+ /* prevent context switches and halt fifo operation */
+ nv_wr32(dev, NV03_PFIFO_CACHES, 0);
+ nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 0);
+ nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 0);
+ nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 0);
- for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
- if (dev_priv->channels.ptr[i]) {
- uint32_t mode = nv_rd32(dev, NV04_PFIFO_MODE);
- nv_wr32(dev, NV04_PFIFO_MODE, mode | (1 << i));
- }
+ /* store current fifo context in ramfc */
+ chid = nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH1) & priv->base.channels;
+ chan = dev_priv->channels.ptr[chid];
+ if (suspend && chid != priv->base.channels && chan) {
+ struct nv04_fifo_chan *fctx = chan->engctx[engine];
+ struct nouveau_gpuobj *ctx = fctx->ramfc;
+ struct ramfc_desc *c = priv->ramfc_desc;
+ do {
+ u32 rm = ((1ULL << c->bits) - 1) << c->regs;
+ u32 cm = ((1ULL << c->bits) - 1) << c->ctxs;
+ u32 rv = (nv_rd32(dev, c->regp) & rm) >> c->regs;
+ u32 cv = (nv_ro32(ctx, c->ctxp) & ~cm);
+ nv_wo32(ctx, c->ctxp, cv | (rv << c->ctxs));
+ } while ((++c)->bits);
}
+ nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0x00000000);
return 0;
}
-void
-nv04_fifo_fini(struct drm_device *dev)
-{
- nv_wr32(dev, 0x2140, 0x00000000);
- nouveau_irq_unregister(dev, 8);
-}
-
static bool
nouveau_fifo_swmthd(struct drm_device *dev, u32 chid, u32 addr, u32 data)
{
+ struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = NULL;
struct nouveau_gpuobj *obj;
@@ -346,7 +275,7 @@ nouveau_fifo_swmthd(struct drm_device *dev, u32 chid, u32 addr, u32 data)
u32 engine;
spin_lock_irqsave(&dev_priv->channels.lock, flags);
- if (likely(chid >= 0 && chid < dev_priv->engine.fifo.channels))
+ if (likely(chid >= 0 && chid < pfifo->channels))
chan = dev_priv->channels.ptr[chid];
if (unlikely(!chan))
goto out;
@@ -357,7 +286,6 @@ nouveau_fifo_swmthd(struct drm_device *dev, u32 chid, u32 addr, u32 data)
if (unlikely(!obj || obj->engine != NVOBJ_ENGINE_SW))
break;
- chan->sw_subchannel[subc] = obj->class;
engine = 0x0000000f << (subc * 4);
nv_mask(dev, NV04_PFIFO_CACHE1_ENGINE, engine, 0x00000000);
@@ -368,7 +296,7 @@ nouveau_fifo_swmthd(struct drm_device *dev, u32 chid, u32 addr, u32 data)
if (unlikely(((engine >> (subc * 4)) & 0xf) != 0))
break;
- if (!nouveau_gpuobj_mthd_call(chan, chan->sw_subchannel[subc],
+ if (!nouveau_gpuobj_mthd_call(chan, nouveau_software_class(dev),
mthd, data))
handled = true;
break;
@@ -391,8 +319,8 @@ static const char *nv_dma_state_err(u32 state)
void
nv04_fifo_isr(struct drm_device *dev)
{
+ struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_engine *engine = &dev_priv->engine;
uint32_t status, reassign;
int cnt = 0;
@@ -402,7 +330,7 @@ nv04_fifo_isr(struct drm_device *dev)
nv_wr32(dev, NV03_PFIFO_CACHES, 0);
- chid = engine->fifo.channel_id(dev);
+ chid = nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH1) & pfifo->channels;
get = nv_rd32(dev, NV03_PFIFO_CACHE1_GET);
if (status & NV_PFIFO_INTR_CACHE_ERROR) {
@@ -541,3 +469,38 @@ nv04_fifo_isr(struct drm_device *dev)
nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PFIFO_PENDING);
}
+
+void
+nv04_fifo_destroy(struct drm_device *dev, int engine)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv04_fifo_priv *priv = nv_engine(dev, engine);
+
+ nouveau_irq_unregister(dev, 8);
+
+ dev_priv->eng[engine] = NULL;
+ kfree(priv);
+}
+
+int
+nv04_fifo_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv04_fifo_priv *priv;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base.base.destroy = nv04_fifo_destroy;
+ priv->base.base.init = nv04_fifo_init;
+ priv->base.base.fini = nv04_fifo_fini;
+ priv->base.base.context_new = nv04_fifo_context_new;
+ priv->base.base.context_del = nv04_fifo_context_del;
+ priv->base.channels = 15;
+ priv->ramfc_desc = nv04_ramfc;
+ dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
+
+ nouveau_irq_register(dev, 8, nv04_fifo_isr);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c
index dbdea8ed3925..72f1a62903b3 100644
--- a/drivers/gpu/drm/nouveau/nv04_graph.c
+++ b/drivers/gpu/drm/nouveau/nv04_graph.c
@@ -356,12 +356,12 @@ static struct nouveau_channel *
nv04_graph_channel(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- int chid = dev_priv->engine.fifo.channels;
+ int chid = 15;
if (nv_rd32(dev, NV04_PGRAPH_CTX_CONTROL) & 0x00010000)
chid = nv_rd32(dev, NV04_PGRAPH_CTX_USER) >> 24;
- if (chid >= dev_priv->engine.fifo.channels)
+ if (chid > 15)
return NULL;
return dev_priv->channels.ptr[chid];
@@ -404,7 +404,6 @@ nv04_graph_load_context(struct nouveau_channel *chan)
static int
nv04_graph_unload_context(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = NULL;
struct graph_state *ctx;
uint32_t tmp;
@@ -420,7 +419,7 @@ nv04_graph_unload_context(struct drm_device *dev)
nv_wr32(dev, NV04_PGRAPH_CTX_CONTROL, 0x10000000);
tmp = nv_rd32(dev, NV04_PGRAPH_CTX_USER) & 0x00ffffff;
- tmp |= (dev_priv->engine.fifo.channels - 1) << 24;
+ tmp |= 15 << 24;
nv_wr32(dev, NV04_PGRAPH_CTX_USER, tmp);
return 0;
}
@@ -495,7 +494,6 @@ nv04_graph_object_new(struct nouveau_channel *chan, int engine,
static int
nv04_graph_init(struct drm_device *dev, int engine)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
uint32_t tmp;
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
@@ -527,7 +525,7 @@ nv04_graph_init(struct drm_device *dev, int engine)
nv_wr32(dev, NV04_PGRAPH_STATE , 0xFFFFFFFF);
nv_wr32(dev, NV04_PGRAPH_CTX_CONTROL , 0x10000100);
tmp = nv_rd32(dev, NV04_PGRAPH_CTX_USER) & 0x00ffffff;
- tmp |= (dev_priv->engine.fifo.channels - 1) << 24;
+ tmp |= 15 << 24;
nv_wr32(dev, NV04_PGRAPH_CTX_USER, tmp);
/* These don't belong here, they're part of a per-channel context */
@@ -550,28 +548,6 @@ nv04_graph_fini(struct drm_device *dev, int engine, bool suspend)
return 0;
}
-static int
-nv04_graph_mthd_set_ref(struct nouveau_channel *chan,
- u32 class, u32 mthd, u32 data)
-{
- atomic_set(&chan->fence.last_sequence_irq, data);
- return 0;
-}
-
-int
-nv04_graph_mthd_page_flip(struct nouveau_channel *chan,
- u32 class, u32 mthd, u32 data)
-{
- struct drm_device *dev = chan->dev;
- struct nouveau_page_flip_state s;
-
- if (!nouveau_finish_page_flip(chan, &s))
- nv_set_crtc_base(dev, s.crtc,
- s.offset + s.y * s.pitch + s.x * s.bpp / 8);
-
- return 0;
-}
-
/*
* Software methods, why they are needed, and how they all work:
*
@@ -1020,7 +996,8 @@ nv04_graph_context_switch(struct drm_device *dev)
nv04_graph_unload_context(dev);
/* Load context for next channel */
- chid = dev_priv->engine.fifo.channel_id(dev);
+ chid = nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH1) &
+ NV03_PFIFO_CACHE1_PUSH1_CHID_MASK;
chan = dev_priv->channels.ptr[chid];
if (chan)
nv04_graph_load_context(chan);
@@ -1345,9 +1322,5 @@ nv04_graph_create(struct drm_device *dev)
NVOBJ_MTHD (dev, 0x005e, 0x0198, nv04_graph_mthd_bind_surf2d);
NVOBJ_MTHD (dev, 0x005e, 0x02fc, nv04_graph_mthd_set_operation);
- /* nvsw */
- NVOBJ_CLASS(dev, 0x506e, SW);
- NVOBJ_MTHD (dev, 0x506e, 0x0150, nv04_graph_mthd_set_ref);
- NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv04_instmem.c b/drivers/gpu/drm/nouveau/nv04_instmem.c
index c1248e0740a3..ef7a934a499a 100644
--- a/drivers/gpu/drm/nouveau/nv04_instmem.c
+++ b/drivers/gpu/drm/nouveau/nv04_instmem.c
@@ -1,6 +1,8 @@
#include "drmP.h"
#include "drm.h"
+
#include "nouveau_drv.h"
+#include "nouveau_fifo.h"
#include "nouveau_ramht.h"
/* returns the size of fifo context */
@@ -10,12 +12,15 @@ nouveau_fifo_ctx_size(struct drm_device *dev)
struct drm_nouveau_private *dev_priv = dev->dev_private;
if (dev_priv->chipset >= 0x40)
- return 128;
+ return 128 * 32;
else
if (dev_priv->chipset >= 0x17)
- return 64;
+ return 64 * 32;
+ else
+ if (dev_priv->chipset >= 0x10)
+ return 32 * 32;
- return 32;
+ return 32 * 16;
}
int nv04_instmem_init(struct drm_device *dev)
@@ -39,14 +44,10 @@ int nv04_instmem_init(struct drm_device *dev)
else if (nv44_graph_class(dev)) rsvd = 0x4980 * vs;
else rsvd = 0x4a40 * vs;
rsvd += 16 * 1024;
- rsvd *= dev_priv->engine.fifo.channels;
-
- /* pciegart table */
- if (pci_is_pcie(dev->pdev))
- rsvd += 512 * 1024;
+ rsvd *= 32; /* per-channel */
- /* object storage */
- rsvd += 512 * 1024;
+ rsvd += 512 * 1024; /* pci(e)gart table */
+ rsvd += 512 * 1024; /* object storage */
dev_priv->ramin_rsvd_vram = round_up(rsvd, 4096);
} else {
@@ -71,7 +72,7 @@ int nv04_instmem_init(struct drm_device *dev)
return ret;
/* And RAMFC */
- length = dev_priv->engine.fifo.channels * nouveau_fifo_ctx_size(dev);
+ length = nouveau_fifo_ctx_size(dev);
switch (dev_priv->card_type) {
case NV_40:
offset = 0x20000;
diff --git a/drivers/gpu/drm/nouveau/nv04_software.c b/drivers/gpu/drm/nouveau/nv04_software.c
new file mode 100644
index 000000000000..0c41abf48774
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv04_software.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+#include "nouveau_ramht.h"
+#include "nouveau_fence.h"
+#include "nouveau_software.h"
+#include "nouveau_hw.h"
+
+struct nv04_software_priv {
+ struct nouveau_software_priv base;
+};
+
+struct nv04_software_chan {
+ struct nouveau_software_chan base;
+};
+
+static int
+mthd_flip(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
+{
+
+ struct nouveau_page_flip_state state;
+
+ if (!nouveau_finish_page_flip(chan, &state)) {
+ nv_set_crtc_base(chan->dev, state.crtc, state.offset +
+ state.y * state.pitch +
+ state.x * state.bpp / 8);
+ }
+
+ return 0;
+}
+
+static int
+nv04_software_context_new(struct nouveau_channel *chan, int engine)
+{
+ struct nv04_software_chan *pch;
+
+ pch = kzalloc(sizeof(*pch), GFP_KERNEL);
+ if (!pch)
+ return -ENOMEM;
+
+ nouveau_software_context_new(&pch->base);
+ chan->engctx[engine] = pch;
+ return 0;
+}
+
+static void
+nv04_software_context_del(struct nouveau_channel *chan, int engine)
+{
+ struct nv04_software_chan *pch = chan->engctx[engine];
+ chan->engctx[engine] = NULL;
+ kfree(pch);
+}
+
+static int
+nv04_software_object_new(struct nouveau_channel *chan, int engine,
+ u32 handle, u16 class)
+{
+ struct drm_device *dev = chan->dev;
+ struct nouveau_gpuobj *obj = NULL;
+ int ret;
+
+ ret = nouveau_gpuobj_new(dev, chan, 16, 16, 0, &obj);
+ if (ret)
+ return ret;
+ obj->engine = 0;
+ obj->class = class;
+
+ ret = nouveau_ramht_insert(chan, handle, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
+ return ret;
+}
+
+static int
+nv04_software_init(struct drm_device *dev, int engine)
+{
+ return 0;
+}
+
+static int
+nv04_software_fini(struct drm_device *dev, int engine, bool suspend)
+{
+ return 0;
+}
+
+static void
+nv04_software_destroy(struct drm_device *dev, int engine)
+{
+ struct nv04_software_priv *psw = nv_engine(dev, engine);
+
+ NVOBJ_ENGINE_DEL(dev, SW);
+ kfree(psw);
+}
+
+int
+nv04_software_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv04_software_priv *psw;
+
+ psw = kzalloc(sizeof(*psw), GFP_KERNEL);
+ if (!psw)
+ return -ENOMEM;
+
+ psw->base.base.destroy = nv04_software_destroy;
+ psw->base.base.init = nv04_software_init;
+ psw->base.base.fini = nv04_software_fini;
+ psw->base.base.context_new = nv04_software_context_new;
+ psw->base.base.context_del = nv04_software_context_del;
+ psw->base.base.object_new = nv04_software_object_new;
+ nouveau_software_create(&psw->base);
+
+ NVOBJ_ENGINE_ADD(dev, SW, &psw->base.base);
+ if (dev_priv->card_type <= NV_04) {
+ NVOBJ_CLASS(dev, 0x006e, SW);
+ NVOBJ_MTHD (dev, 0x006e, 0x0150, nv04_fence_mthd);
+ NVOBJ_MTHD (dev, 0x006e, 0x0500, mthd_flip);
+ } else {
+ NVOBJ_CLASS(dev, 0x016e, SW);
+ NVOBJ_MTHD (dev, 0x016e, 0x0500, mthd_flip);
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nv10_fence.c b/drivers/gpu/drm/nouveau/nv10_fence.c
new file mode 100644
index 000000000000..8a1b75009185
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv10_fence.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_dma.h"
+#include "nouveau_ramht.h"
+#include "nouveau_fence.h"
+
+struct nv10_fence_chan {
+ struct nouveau_fence_chan base;
+};
+
+struct nv10_fence_priv {
+ struct nouveau_fence_priv base;
+ struct nouveau_bo *bo;
+ spinlock_t lock;
+ u32 sequence;
+};
+
+static int
+nv10_fence_emit(struct nouveau_fence *fence)
+{
+ struct nouveau_channel *chan = fence->channel;
+ int ret = RING_SPACE(chan, 2);
+ if (ret == 0) {
+ BEGIN_NV04(chan, 0, NV10_SUBCHAN_REF_CNT, 1);
+ OUT_RING (chan, fence->sequence);
+ FIRE_RING (chan);
+ }
+ return ret;
+}
+
+
+static int
+nv10_fence_sync(struct nouveau_fence *fence,
+ struct nouveau_channel *prev, struct nouveau_channel *chan)
+{
+ return -ENODEV;
+}
+
+static int
+nv17_fence_sync(struct nouveau_fence *fence,
+ struct nouveau_channel *prev, struct nouveau_channel *chan)
+{
+ struct nv10_fence_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_FENCE);
+ u32 value;
+ int ret;
+
+ if (!mutex_trylock(&prev->mutex))
+ return -EBUSY;
+
+ spin_lock(&priv->lock);
+ value = priv->sequence;
+ priv->sequence += 2;
+ spin_unlock(&priv->lock);
+
+ ret = RING_SPACE(prev, 5);
+ if (!ret) {
+ BEGIN_NV04(prev, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 4);
+ OUT_RING (prev, NvSema);
+ OUT_RING (prev, 0);
+ OUT_RING (prev, value + 0);
+ OUT_RING (prev, value + 1);
+ FIRE_RING (prev);
+ }
+
+ if (!ret && !(ret = RING_SPACE(chan, 5))) {
+ BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 4);
+ OUT_RING (chan, NvSema);
+ OUT_RING (chan, 0);
+ OUT_RING (chan, value + 1);
+ OUT_RING (chan, value + 2);
+ FIRE_RING (chan);
+ }
+
+ mutex_unlock(&prev->mutex);
+ return 0;
+}
+
+static u32
+nv10_fence_read(struct nouveau_channel *chan)
+{
+ return nvchan_rd32(chan, 0x0048);
+}
+
+static void
+nv10_fence_context_del(struct nouveau_channel *chan, int engine)
+{
+ struct nv10_fence_chan *fctx = chan->engctx[engine];
+ nouveau_fence_context_del(&fctx->base);
+ chan->engctx[engine] = NULL;
+ kfree(fctx);
+}
+
+static int
+nv10_fence_context_new(struct nouveau_channel *chan, int engine)
+{
+ struct nv10_fence_priv *priv = nv_engine(chan->dev, engine);
+ struct nv10_fence_chan *fctx;
+ struct nouveau_gpuobj *obj;
+ int ret = 0;
+
+ fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
+ if (!fctx)
+ return -ENOMEM;
+
+ nouveau_fence_context_new(&fctx->base);
+
+ if (priv->bo) {
+ struct ttm_mem_reg *mem = &priv->bo->bo.mem;
+
+ ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_FROM_MEMORY,
+ mem->start * PAGE_SIZE, mem->size,
+ NV_MEM_ACCESS_RW,
+ NV_MEM_TARGET_VRAM, &obj);
+ if (!ret) {
+ ret = nouveau_ramht_insert(chan, NvSema, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
+ }
+ }
+
+ if (ret)
+ nv10_fence_context_del(chan, engine);
+ return ret;
+}
+
+static int
+nv10_fence_fini(struct drm_device *dev, int engine, bool suspend)
+{
+ return 0;
+}
+
+static int
+nv10_fence_init(struct drm_device *dev, int engine)
+{
+ return 0;
+}
+
+static void
+nv10_fence_destroy(struct drm_device *dev, int engine)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv10_fence_priv *priv = nv_engine(dev, engine);
+
+ nouveau_bo_ref(NULL, &priv->bo);
+ dev_priv->eng[engine] = NULL;
+ kfree(priv);
+}
+
+int
+nv10_fence_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv10_fence_priv *priv;
+ int ret = 0;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base.engine.destroy = nv10_fence_destroy;
+ priv->base.engine.init = nv10_fence_init;
+ priv->base.engine.fini = nv10_fence_fini;
+ priv->base.engine.context_new = nv10_fence_context_new;
+ priv->base.engine.context_del = nv10_fence_context_del;
+ priv->base.emit = nv10_fence_emit;
+ priv->base.read = nv10_fence_read;
+ priv->base.sync = nv10_fence_sync;
+ dev_priv->eng[NVOBJ_ENGINE_FENCE] = &priv->base.engine;
+ spin_lock_init(&priv->lock);
+
+ if (dev_priv->chipset >= 0x17) {
+ ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
+ 0, 0x0000, NULL, &priv->bo);
+ if (!ret) {
+ ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM);
+ if (!ret)
+ ret = nouveau_bo_map(priv->bo);
+ if (ret)
+ nouveau_bo_ref(NULL, &priv->bo);
+ }
+
+ if (ret == 0) {
+ nouveau_bo_wr32(priv->bo, 0x000, 0x00000000);
+ priv->base.sync = nv17_fence_sync;
+ }
+ }
+
+ if (ret)
+ nv10_fence_destroy(dev, NVOBJ_ENGINE_FENCE);
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nv10_fifo.c b/drivers/gpu/drm/nouveau/nv10_fifo.c
index d2ecbff4bee1..f1fe7d758241 100644
--- a/drivers/gpu/drm/nouveau/nv10_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv10_fifo.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Ben Skeggs.
+ * Copyright (C) 2012 Ben Skeggs.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
@@ -27,220 +27,112 @@
#include "drmP.h"
#include "drm.h"
#include "nouveau_drv.h"
+#include "nouveau_fifo.h"
+#include "nouveau_util.h"
#include "nouveau_ramht.h"
-#define NV10_RAMFC(c) (dev_priv->ramfc->pinst + ((c) * NV10_RAMFC__SIZE))
-#define NV10_RAMFC__SIZE ((dev_priv->chipset) >= 0x17 ? 64 : 32)
-
-int
-nv10_fifo_channel_id(struct drm_device *dev)
-{
- return nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH1) &
- NV10_PFIFO_CACHE1_PUSH1_CHID_MASK;
-}
-
-int
-nv10_fifo_create_context(struct nouveau_channel *chan)
+static struct ramfc_desc {
+ unsigned bits:6;
+ unsigned ctxs:5;
+ unsigned ctxp:8;
+ unsigned regs:5;
+ unsigned regp;
+} nv10_ramfc[] = {
+ { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
+ { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
+ { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT },
+ { 16, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
+ { 16, 16, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
+ { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_STATE },
+ { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
+ { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_ENGINE },
+ { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_PULL1 },
+ {}
+};
+
+struct nv10_fifo_priv {
+ struct nouveau_fifo_priv base;
+ struct ramfc_desc *ramfc_desc;
+};
+
+struct nv10_fifo_chan {
+ struct nouveau_fifo_chan base;
+ struct nouveau_gpuobj *ramfc;
+};
+
+static int
+nv10_fifo_context_new(struct nouveau_channel *chan, int engine)
{
- struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
struct drm_device *dev = chan->dev;
- uint32_t fc = NV10_RAMFC(chan->id);
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv10_fifo_priv *priv = nv_engine(dev, engine);
+ struct nv10_fifo_chan *fctx;
+ unsigned long flags;
int ret;
- ret = nouveau_gpuobj_new_fake(dev, NV10_RAMFC(chan->id), ~0,
- NV10_RAMFC__SIZE, NVOBJ_FLAG_ZERO_ALLOC |
- NVOBJ_FLAG_ZERO_FREE, &chan->ramfc);
- if (ret)
- return ret;
+ fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
+ if (!fctx)
+ return -ENOMEM;
+ /* map channel control registers */
chan->user = ioremap(pci_resource_start(dev->pdev, 0) +
NV03_USER(chan->id), PAGE_SIZE);
- if (!chan->user)
- return -ENOMEM;
+ if (!chan->user) {
+ ret = -ENOMEM;
+ goto error;
+ }
- /* Fill entries that are seen filled in dumps of nvidia driver just
- * after channel's is put into DMA mode
- */
- nv_wi32(dev, fc + 0, chan->pushbuf_base);
- nv_wi32(dev, fc + 4, chan->pushbuf_base);
- nv_wi32(dev, fc + 12, chan->pushbuf->pinst >> 4);
- nv_wi32(dev, fc + 20, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
+ /* initialise default fifo context */
+ ret = nouveau_gpuobj_new_fake(dev, dev_priv->ramfc->pinst +
+ chan->id * 32, ~0, 32,
+ NVOBJ_FLAG_ZERO_FREE, &fctx->ramfc);
+ if (ret)
+ goto error;
+
+ nv_wo32(fctx->ramfc, 0x00, chan->pushbuf_base);
+ nv_wo32(fctx->ramfc, 0x04, chan->pushbuf_base);
+ nv_wo32(fctx->ramfc, 0x08, 0x00000000);
+ nv_wo32(fctx->ramfc, 0x0c, chan->pushbuf->pinst >> 4);
+ nv_wo32(fctx->ramfc, 0x10, 0x00000000);
+ nv_wo32(fctx->ramfc, 0x14, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
+ NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
#ifdef __BIG_ENDIAN
- NV_PFIFO_CACHE1_BIG_ENDIAN |
+ NV_PFIFO_CACHE1_BIG_ENDIAN |
#endif
- 0);
-
- /* enable the fifo dma operation */
- nv_wr32(dev, NV04_PFIFO_MODE,
- nv_rd32(dev, NV04_PFIFO_MODE) | (1 << chan->id));
- return 0;
-}
-
-static void
-nv10_fifo_do_load_context(struct drm_device *dev, int chid)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t fc = NV10_RAMFC(chid), tmp;
-
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0));
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4));
- nv_wr32(dev, NV10_PFIFO_CACHE1_REF_CNT, nv_ri32(dev, fc + 8));
-
- tmp = nv_ri32(dev, fc + 12);
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_INSTANCE, tmp & 0xFFFF);
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_DCOUNT, tmp >> 16);
-
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_STATE, nv_ri32(dev, fc + 16));
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_FETCH, nv_ri32(dev, fc + 20));
- nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_ri32(dev, fc + 24));
- nv_wr32(dev, NV04_PFIFO_CACHE1_PULL1, nv_ri32(dev, fc + 28));
-
- if (dev_priv->chipset < 0x17)
- goto out;
-
- nv_wr32(dev, NV10_PFIFO_CACHE1_ACQUIRE_VALUE, nv_ri32(dev, fc + 32));
- tmp = nv_ri32(dev, fc + 36);
- nv_wr32(dev, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP, tmp);
- nv_wr32(dev, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT, nv_ri32(dev, fc + 40));
- nv_wr32(dev, NV10_PFIFO_CACHE1_SEMAPHORE, nv_ri32(dev, fc + 44));
- nv_wr32(dev, NV10_PFIFO_CACHE1_DMA_SUBROUTINE, nv_ri32(dev, fc + 48));
-
-out:
- nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
- nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
-}
-
-int
-nv10_fifo_load_context(struct nouveau_channel *chan)
-{
- struct drm_device *dev = chan->dev;
- uint32_t tmp;
-
- nv10_fifo_do_load_context(dev, chan->id);
+ NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
+ nv_wo32(fctx->ramfc, 0x18, 0x00000000);
+ nv_wo32(fctx->ramfc, 0x1c, 0x00000000);
- nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1,
- NV03_PFIFO_CACHE1_PUSH1_DMA | chan->id);
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 1);
+ /* enable dma mode on the channel */
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ nv_mask(dev, NV04_PFIFO_MODE, (1 << chan->id), (1 << chan->id));
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
- /* Reset NV04_PFIFO_CACHE1_DMA_CTL_AT_INFO to INVALID */
- tmp = nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_CTL) & ~(1 << 31);
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_CTL, tmp);
-
- return 0;
+error:
+ if (ret)
+ priv->base.base.context_del(chan, engine);
+ return ret;
}
int
-nv10_fifo_unload_context(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- uint32_t fc, tmp;
- int chid;
-
- chid = pfifo->channel_id(dev);
- if (chid < 0 || chid >= dev_priv->engine.fifo.channels)
- return 0;
- fc = NV10_RAMFC(chid);
-
- nv_wi32(dev, fc + 0, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT));
- nv_wi32(dev, fc + 4, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
- nv_wi32(dev, fc + 8, nv_rd32(dev, NV10_PFIFO_CACHE1_REF_CNT));
- tmp = nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_INSTANCE) & 0xFFFF;
- tmp |= (nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_DCOUNT) << 16);
- nv_wi32(dev, fc + 12, tmp);
- nv_wi32(dev, fc + 16, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_STATE));
- nv_wi32(dev, fc + 20, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_FETCH));
- nv_wi32(dev, fc + 24, nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE));
- nv_wi32(dev, fc + 28, nv_rd32(dev, NV04_PFIFO_CACHE1_PULL1));
-
- if (dev_priv->chipset < 0x17)
- goto out;
-
- nv_wi32(dev, fc + 32, nv_rd32(dev, NV10_PFIFO_CACHE1_ACQUIRE_VALUE));
- tmp = nv_rd32(dev, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP);
- nv_wi32(dev, fc + 36, tmp);
- nv_wi32(dev, fc + 40, nv_rd32(dev, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT));
- nv_wi32(dev, fc + 44, nv_rd32(dev, NV10_PFIFO_CACHE1_SEMAPHORE));
- nv_wi32(dev, fc + 48, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
-
-out:
- nv10_fifo_do_load_context(dev, pfifo->channels - 1);
- nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1);
- return 0;
-}
-
-static void
-nv10_fifo_init_reset(struct drm_device *dev)
-{
- nv_wr32(dev, NV03_PMC_ENABLE,
- nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PFIFO);
- nv_wr32(dev, NV03_PMC_ENABLE,
- nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PFIFO);
-
- nv_wr32(dev, 0x003224, 0x000f0078);
- nv_wr32(dev, 0x002044, 0x0101ffff);
- nv_wr32(dev, 0x002040, 0x000000ff);
- nv_wr32(dev, 0x002500, 0x00000000);
- nv_wr32(dev, 0x003000, 0x00000000);
- nv_wr32(dev, 0x003050, 0x00000000);
-
- nv_wr32(dev, 0x003258, 0x00000000);
- nv_wr32(dev, 0x003210, 0x00000000);
- nv_wr32(dev, 0x003270, 0x00000000);
-}
-
-static void
-nv10_fifo_init_ramxx(struct drm_device *dev)
+nv10_fifo_create(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv10_fifo_priv *priv;
- nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
- ((dev_priv->ramht->bits - 9) << 16) |
- (dev_priv->ramht->gpuobj->pinst >> 8));
- nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro->pinst >> 8);
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
- if (dev_priv->chipset < 0x17) {
- nv_wr32(dev, NV03_PFIFO_RAMFC, dev_priv->ramfc->pinst >> 8);
- } else {
- nv_wr32(dev, NV03_PFIFO_RAMFC, (dev_priv->ramfc->pinst >> 8) |
- (1 << 16) /* 64 Bytes entry*/);
- /* XXX nvidia blob set bit 18, 21,23 for nv20 & nv30 */
- }
-}
+ priv->base.base.destroy = nv04_fifo_destroy;
+ priv->base.base.init = nv04_fifo_init;
+ priv->base.base.fini = nv04_fifo_fini;
+ priv->base.base.context_new = nv10_fifo_context_new;
+ priv->base.base.context_del = nv04_fifo_context_del;
+ priv->base.channels = 31;
+ priv->ramfc_desc = nv10_ramfc;
+ dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
-static void
-nv10_fifo_init_intr(struct drm_device *dev)
-{
nouveau_irq_register(dev, 8, nv04_fifo_isr);
- nv_wr32(dev, 0x002100, 0xffffffff);
- nv_wr32(dev, 0x002140, 0xffffffff);
-}
-
-int
-nv10_fifo_init(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- int i;
-
- nv10_fifo_init_reset(dev);
- nv10_fifo_init_ramxx(dev);
-
- nv10_fifo_do_load_context(dev, pfifo->channels - 1);
- nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1);
-
- nv10_fifo_init_intr(dev);
- pfifo->enable(dev);
- pfifo->reassign(dev, true);
-
- for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
- if (dev_priv->channels.ptr[i]) {
- uint32_t mode = nv_rd32(dev, NV04_PFIFO_MODE);
- nv_wr32(dev, NV04_PFIFO_MODE, mode | (1 << i));
- }
- }
-
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c
index 7255e4a4d3f3..fb1d88a951de 100644
--- a/drivers/gpu/drm/nouveau/nv10_graph.c
+++ b/drivers/gpu/drm/nouveau/nv10_graph.c
@@ -759,7 +759,6 @@ static int
nv10_graph_unload_context(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nouveau_channel *chan;
struct graph_state *ctx;
uint32_t tmp;
@@ -782,7 +781,7 @@ nv10_graph_unload_context(struct drm_device *dev)
nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
- tmp |= (pfifo->channels - 1) << 24;
+ tmp |= 31 << 24;
nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp);
return 0;
}
@@ -822,12 +821,12 @@ struct nouveau_channel *
nv10_graph_channel(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- int chid = dev_priv->engine.fifo.channels;
+ int chid = 31;
if (nv_rd32(dev, NV10_PGRAPH_CTX_CONTROL) & 0x00010000)
chid = nv_rd32(dev, NV10_PGRAPH_CTX_USER) >> 24;
- if (chid >= dev_priv->engine.fifo.channels)
+ if (chid >= 31)
return NULL;
return dev_priv->channels.ptr[chid];
@@ -948,7 +947,7 @@ nv10_graph_init(struct drm_device *dev, int engine)
nv_wr32(dev, NV10_PGRAPH_STATE, 0xFFFFFFFF);
tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
- tmp |= (dev_priv->engine.fifo.channels - 1) << 24;
+ tmp |= 31 << 24;
nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp);
nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2, 0x08000000);
@@ -1153,10 +1152,6 @@ nv10_graph_create(struct drm_device *dev)
NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
nouveau_irq_register(dev, 12, nv10_graph_isr);
- /* nvsw */
- NVOBJ_CLASS(dev, 0x506e, SW);
- NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
NVOBJ_CLASS(dev, 0x0030, GR); /* null */
NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
diff --git a/drivers/gpu/drm/nouveau/nv17_fifo.c b/drivers/gpu/drm/nouveau/nv17_fifo.c
new file mode 100644
index 000000000000..d9e482e4abee
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv17_fifo.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2012 Ben Skeggs.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "nouveau_drv.h"
+#include "nouveau_fifo.h"
+#include "nouveau_util.h"
+#include "nouveau_ramht.h"
+
+static struct ramfc_desc {
+ unsigned bits:6;
+ unsigned ctxs:5;
+ unsigned ctxp:8;
+ unsigned regs:5;
+ unsigned regp;
+} nv17_ramfc[] = {
+ { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
+ { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
+ { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT },
+ { 16, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
+ { 16, 16, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
+ { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_STATE },
+ { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
+ { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_ENGINE },
+ { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_PULL1 },
+ { 32, 0, 0x20, 0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE },
+ { 32, 0, 0x24, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP },
+ { 32, 0, 0x28, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT },
+ { 32, 0, 0x2c, 0, NV10_PFIFO_CACHE1_SEMAPHORE },
+ { 32, 0, 0x30, 0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE },
+ {}
+};
+
+struct nv17_fifo_priv {
+ struct nouveau_fifo_priv base;
+ struct ramfc_desc *ramfc_desc;
+};
+
+struct nv17_fifo_chan {
+ struct nouveau_fifo_chan base;
+ struct nouveau_gpuobj *ramfc;
+};
+
+static int
+nv17_fifo_context_new(struct nouveau_channel *chan, int engine)
+{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv17_fifo_priv *priv = nv_engine(dev, engine);
+ struct nv17_fifo_chan *fctx;
+ unsigned long flags;
+ int ret;
+
+ fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
+ if (!fctx)
+ return -ENOMEM;
+
+ /* map channel control registers */
+ chan->user = ioremap(pci_resource_start(dev->pdev, 0) +
+ NV03_USER(chan->id), PAGE_SIZE);
+ if (!chan->user) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ /* initialise default fifo context */
+ ret = nouveau_gpuobj_new_fake(dev, dev_priv->ramfc->pinst +
+ chan->id * 64, ~0, 64,
+ NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE, &fctx->ramfc);
+ if (ret)
+ goto error;
+
+ nv_wo32(fctx->ramfc, 0x00, chan->pushbuf_base);
+ nv_wo32(fctx->ramfc, 0x04, chan->pushbuf_base);
+ nv_wo32(fctx->ramfc, 0x0c, chan->pushbuf->pinst >> 4);
+ nv_wo32(fctx->ramfc, 0x14, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
+ NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
+#ifdef __BIG_ENDIAN
+ NV_PFIFO_CACHE1_BIG_ENDIAN |
+#endif
+ NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
+
+ /* enable dma mode on the channel */
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ nv_mask(dev, NV04_PFIFO_MODE, (1 << chan->id), (1 << chan->id));
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+error:
+ if (ret)
+ priv->base.base.context_del(chan, engine);
+ return ret;
+}
+
+static int
+nv17_fifo_init(struct drm_device *dev, int engine)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv17_fifo_priv *priv = nv_engine(dev, engine);
+ int i;
+
+ nv_mask(dev, NV03_PMC_ENABLE, NV_PMC_ENABLE_PFIFO, 0);
+ nv_mask(dev, NV03_PMC_ENABLE, NV_PMC_ENABLE_PFIFO, NV_PMC_ENABLE_PFIFO);
+
+ nv_wr32(dev, NV04_PFIFO_DELAY_0, 0x000000ff);
+ nv_wr32(dev, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
+
+ nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
+ ((dev_priv->ramht->bits - 9) << 16) |
+ (dev_priv->ramht->gpuobj->pinst >> 8));
+ nv_wr32(dev, NV03_PFIFO_RAMRO, dev_priv->ramro->pinst >> 8);
+ nv_wr32(dev, NV03_PFIFO_RAMFC, 0x00010000 |
+ dev_priv->ramfc->pinst >> 8);
+
+ nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, priv->base.channels);
+
+ nv_wr32(dev, NV03_PFIFO_INTR_0, 0xffffffff);
+ nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0xffffffff);
+
+ nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 1);
+ nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
+ nv_wr32(dev, NV03_PFIFO_CACHES, 1);
+
+ for (i = 0; i < priv->base.channels; i++) {
+ if (dev_priv->channels.ptr[i])
+ nv_mask(dev, NV04_PFIFO_MODE, (1 << i), (1 << i));
+ }
+
+ return 0;
+}
+
+int
+nv17_fifo_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv17_fifo_priv *priv;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base.base.destroy = nv04_fifo_destroy;
+ priv->base.base.init = nv17_fifo_init;
+ priv->base.base.fini = nv04_fifo_fini;
+ priv->base.base.context_new = nv17_fifo_context_new;
+ priv->base.base.context_del = nv04_fifo_context_del;
+ priv->base.channels = 31;
+ priv->ramfc_desc = nv17_ramfc;
+ dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
+
+ nouveau_irq_register(dev, 8, nv04_fifo_isr);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c
index 183e37512ef9..e34ea30758f6 100644
--- a/drivers/gpu/drm/nouveau/nv20_graph.c
+++ b/drivers/gpu/drm/nouveau/nv20_graph.c
@@ -43,8 +43,6 @@ struct nv20_graph_engine {
int
nv20_graph_unload_context(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nouveau_channel *chan;
struct nouveau_gpuobj *grctx;
u32 tmp;
@@ -62,7 +60,7 @@ nv20_graph_unload_context(struct drm_device *dev)
nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
- tmp |= (pfifo->channels - 1) << 24;
+ tmp |= 31 << 24;
nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp);
return 0;
}
@@ -796,10 +794,6 @@ nv20_graph_create(struct drm_device *dev)
NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
nouveau_irq_register(dev, 12, nv20_graph_isr);
- /* nvsw */
- NVOBJ_CLASS(dev, 0x506e, SW);
- NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
NVOBJ_CLASS(dev, 0x0030, GR); /* null */
NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
diff --git a/drivers/gpu/drm/nouveau/nv31_mpeg.c b/drivers/gpu/drm/nouveau/nv31_mpeg.c
index 6f06a0713f00..5f239bf658c4 100644
--- a/drivers/gpu/drm/nouveau/nv31_mpeg.c
+++ b/drivers/gpu/drm/nouveau/nv31_mpeg.c
@@ -24,6 +24,7 @@
#include "drmP.h"
#include "nouveau_drv.h"
+#include "nouveau_fifo.h"
#include "nouveau_ramht.h"
struct nv31_mpeg_engine {
@@ -208,6 +209,7 @@ nv31_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
static int
nv31_mpeg_isr_chid(struct drm_device *dev, u32 inst)
{
+ struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *ctx;
unsigned long flags;
@@ -218,7 +220,7 @@ nv31_mpeg_isr_chid(struct drm_device *dev, u32 inst)
return 0;
spin_lock_irqsave(&dev_priv->channels.lock, flags);
- for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
+ for (i = 0; i < pfifo->channels; i++) {
if (!dev_priv->channels.ptr[i])
continue;
diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c
index 68cb2d991c88..cdc818479b0a 100644
--- a/drivers/gpu/drm/nouveau/nv40_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv40_fifo.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Ben Skeggs.
+ * Copyright (C) 2012 Ben Skeggs.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
@@ -25,215 +25,123 @@
*/
#include "drmP.h"
+#include "drm.h"
#include "nouveau_drv.h"
-#include "nouveau_drm.h"
+#include "nouveau_fifo.h"
+#include "nouveau_util.h"
#include "nouveau_ramht.h"
-#define NV40_RAMFC(c) (dev_priv->ramfc->pinst + ((c) * NV40_RAMFC__SIZE))
-#define NV40_RAMFC__SIZE 128
-
-int
-nv40_fifo_create_context(struct nouveau_channel *chan)
+static struct ramfc_desc {
+ unsigned bits:6;
+ unsigned ctxs:5;
+ unsigned ctxp:8;
+ unsigned regs:5;
+ unsigned regp;
+} nv40_ramfc[] = {
+ { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
+ { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
+ { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT },
+ { 32, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
+ { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
+ { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_STATE },
+ { 28, 0, 0x18, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
+ { 2, 28, 0x18, 28, 0x002058 },
+ { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_ENGINE },
+ { 32, 0, 0x20, 0, NV04_PFIFO_CACHE1_PULL1 },
+ { 32, 0, 0x24, 0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE },
+ { 32, 0, 0x28, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP },
+ { 32, 0, 0x2c, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT },
+ { 32, 0, 0x30, 0, NV10_PFIFO_CACHE1_SEMAPHORE },
+ { 32, 0, 0x34, 0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE },
+ { 32, 0, 0x38, 0, NV40_PFIFO_GRCTX_INSTANCE },
+ { 17, 0, 0x3c, 0, NV04_PFIFO_DMA_TIMESLICE },
+ { 32, 0, 0x40, 0, 0x0032e4 },
+ { 32, 0, 0x44, 0, 0x0032e8 },
+ { 32, 0, 0x4c, 0, 0x002088 },
+ { 32, 0, 0x50, 0, 0x003300 },
+ { 32, 0, 0x54, 0, 0x00330c },
+ {}
+};
+
+struct nv40_fifo_priv {
+ struct nouveau_fifo_priv base;
+ struct ramfc_desc *ramfc_desc;
+};
+
+struct nv40_fifo_chan {
+ struct nouveau_fifo_chan base;
+ struct nouveau_gpuobj *ramfc;
+};
+
+static int
+nv40_fifo_context_new(struct nouveau_channel *chan, int engine)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t fc = NV40_RAMFC(chan->id);
+ struct nv40_fifo_priv *priv = nv_engine(dev, engine);
+ struct nv40_fifo_chan *fctx;
unsigned long flags;
int ret;
- ret = nouveau_gpuobj_new_fake(dev, NV40_RAMFC(chan->id), ~0,
- NV40_RAMFC__SIZE, NVOBJ_FLAG_ZERO_ALLOC |
- NVOBJ_FLAG_ZERO_FREE, &chan->ramfc);
- if (ret)
- return ret;
-
- chan->user = ioremap(pci_resource_start(dev->pdev, 0) +
- NV40_USER(chan->id), PAGE_SIZE);
- if (!chan->user)
+ fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
+ if (!fctx)
return -ENOMEM;
- spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ /* map channel control registers */
+ chan->user = ioremap(pci_resource_start(dev->pdev, 0) +
+ NV03_USER(chan->id), PAGE_SIZE);
+ if (!chan->user) {
+ ret = -ENOMEM;
+ goto error;
+ }
- nv_wi32(dev, fc + 0, chan->pushbuf_base);
- nv_wi32(dev, fc + 4, chan->pushbuf_base);
- nv_wi32(dev, fc + 12, chan->pushbuf->pinst >> 4);
- nv_wi32(dev, fc + 24, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 |
+ /* initialise default fifo context */
+ ret = nouveau_gpuobj_new_fake(dev, dev_priv->ramfc->pinst +
+ chan->id * 128, ~0, 128,
+ NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE, &fctx->ramfc);
+ if (ret)
+ goto error;
+
+ nv_wo32(fctx->ramfc, 0x00, chan->pushbuf_base);
+ nv_wo32(fctx->ramfc, 0x04, chan->pushbuf_base);
+ nv_wo32(fctx->ramfc, 0x0c, chan->pushbuf->pinst >> 4);
+ nv_wo32(fctx->ramfc, 0x18, 0x30000000 |
+ NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
+ NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
#ifdef __BIG_ENDIAN
- NV_PFIFO_CACHE1_BIG_ENDIAN |
+ NV_PFIFO_CACHE1_BIG_ENDIAN |
#endif
- 0x30000000 /* no idea.. */);
- nv_wi32(dev, fc + 60, 0x0001FFFF);
-
- /* enable the fifo dma operation */
- nv_wr32(dev, NV04_PFIFO_MODE,
- nv_rd32(dev, NV04_PFIFO_MODE) | (1 << chan->id));
+ NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
+ nv_wo32(fctx->ramfc, 0x3c, 0x0001ffff);
+ /* enable dma mode on the channel */
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ nv_mask(dev, NV04_PFIFO_MODE, (1 << chan->id), (1 << chan->id));
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
- return 0;
-}
-
-static void
-nv40_fifo_do_load_context(struct drm_device *dev, int chid)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t fc = NV40_RAMFC(chid), tmp, tmp2;
-
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUT, nv_ri32(dev, fc + 0));
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_GET, nv_ri32(dev, fc + 4));
- nv_wr32(dev, NV10_PFIFO_CACHE1_REF_CNT, nv_ri32(dev, fc + 8));
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_INSTANCE, nv_ri32(dev, fc + 12));
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_DCOUNT, nv_ri32(dev, fc + 16));
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_STATE, nv_ri32(dev, fc + 20));
-
- /* No idea what 0x2058 is.. */
- tmp = nv_ri32(dev, fc + 24);
- tmp2 = nv_rd32(dev, 0x2058) & 0xFFF;
- tmp2 |= (tmp & 0x30000000);
- nv_wr32(dev, 0x2058, tmp2);
- tmp &= ~0x30000000;
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_FETCH, tmp);
- nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_ri32(dev, fc + 28));
- nv_wr32(dev, NV04_PFIFO_CACHE1_PULL1, nv_ri32(dev, fc + 32));
- nv_wr32(dev, NV10_PFIFO_CACHE1_ACQUIRE_VALUE, nv_ri32(dev, fc + 36));
- tmp = nv_ri32(dev, fc + 40);
- nv_wr32(dev, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP, tmp);
- nv_wr32(dev, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT, nv_ri32(dev, fc + 44));
- nv_wr32(dev, NV10_PFIFO_CACHE1_SEMAPHORE, nv_ri32(dev, fc + 48));
- nv_wr32(dev, NV10_PFIFO_CACHE1_DMA_SUBROUTINE, nv_ri32(dev, fc + 52));
- nv_wr32(dev, NV40_PFIFO_GRCTX_INSTANCE, nv_ri32(dev, fc + 56));
+ /*XXX: remove this later, need fifo engine context commit hook */
+ nouveau_gpuobj_ref(fctx->ramfc, &chan->ramfc);
- /* Don't clobber the TIMEOUT_ENABLED flag when restoring from RAMFC */
- tmp = nv_rd32(dev, NV04_PFIFO_DMA_TIMESLICE) & ~0x1FFFF;
- tmp |= nv_ri32(dev, fc + 60) & 0x1FFFF;
- nv_wr32(dev, NV04_PFIFO_DMA_TIMESLICE, tmp);
-
- nv_wr32(dev, 0x32e4, nv_ri32(dev, fc + 64));
- /* NVIDIA does this next line twice... */
- nv_wr32(dev, 0x32e8, nv_ri32(dev, fc + 68));
- nv_wr32(dev, 0x2088, nv_ri32(dev, fc + 76));
- nv_wr32(dev, 0x3300, nv_ri32(dev, fc + 80));
- nv_wr32(dev, 0x330c, nv_ri32(dev, fc + 84));
-
- nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
- nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
-}
-
-int
-nv40_fifo_load_context(struct nouveau_channel *chan)
-{
- struct drm_device *dev = chan->dev;
- uint32_t tmp;
-
- nv40_fifo_do_load_context(dev, chan->id);
-
- /* Set channel active, and in DMA mode */
- nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1,
- NV40_PFIFO_CACHE1_PUSH1_DMA | chan->id);
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 1);
-
- /* Reset DMA_CTL_AT_INFO to INVALID */
- tmp = nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_CTL) & ~(1 << 31);
- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_CTL, tmp);
-
- return 0;
+error:
+ if (ret)
+ priv->base.base.context_del(chan, engine);
+ return ret;
}
-int
-nv40_fifo_unload_context(struct drm_device *dev)
+static int
+nv40_fifo_init(struct drm_device *dev, int engine)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- uint32_t fc, tmp;
- int chid;
-
- chid = pfifo->channel_id(dev);
- if (chid < 0 || chid >= dev_priv->engine.fifo.channels)
- return 0;
- fc = NV40_RAMFC(chid);
-
- nv_wi32(dev, fc + 0, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUT));
- nv_wi32(dev, fc + 4, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
- nv_wi32(dev, fc + 8, nv_rd32(dev, NV10_PFIFO_CACHE1_REF_CNT));
- nv_wi32(dev, fc + 12, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_INSTANCE));
- nv_wi32(dev, fc + 16, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_DCOUNT));
- nv_wi32(dev, fc + 20, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_STATE));
- tmp = nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_FETCH);
- tmp |= nv_rd32(dev, 0x2058) & 0x30000000;
- nv_wi32(dev, fc + 24, tmp);
- nv_wi32(dev, fc + 28, nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE));
- nv_wi32(dev, fc + 32, nv_rd32(dev, NV04_PFIFO_CACHE1_PULL1));
- nv_wi32(dev, fc + 36, nv_rd32(dev, NV10_PFIFO_CACHE1_ACQUIRE_VALUE));
- tmp = nv_rd32(dev, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP);
- nv_wi32(dev, fc + 40, tmp);
- nv_wi32(dev, fc + 44, nv_rd32(dev, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT));
- nv_wi32(dev, fc + 48, nv_rd32(dev, NV10_PFIFO_CACHE1_SEMAPHORE));
- /* NVIDIA read 0x3228 first, then write DMA_GET here.. maybe something
- * more involved depending on the value of 0x3228?
- */
- nv_wi32(dev, fc + 52, nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_GET));
- nv_wi32(dev, fc + 56, nv_rd32(dev, NV40_PFIFO_GRCTX_INSTANCE));
- nv_wi32(dev, fc + 60, nv_rd32(dev, NV04_PFIFO_DMA_TIMESLICE) & 0x1ffff);
- /* No idea what the below is for exactly, ripped from a mmio-trace */
- nv_wi32(dev, fc + 64, nv_rd32(dev, NV40_PFIFO_UNK32E4));
- /* NVIDIA do this next line twice.. bug? */
- nv_wi32(dev, fc + 68, nv_rd32(dev, 0x32e8));
- nv_wi32(dev, fc + 76, nv_rd32(dev, 0x2088));
- nv_wi32(dev, fc + 80, nv_rd32(dev, 0x3300));
-#if 0 /* no real idea which is PUT/GET in UNK_48.. */
- tmp = nv_rd32(dev, NV04_PFIFO_CACHE1_GET);
- tmp |= (nv_rd32(dev, NV04_PFIFO_CACHE1_PUT) << 16);
- nv_wi32(dev, fc + 72, tmp);
-#endif
- nv_wi32(dev, fc + 84, nv_rd32(dev, 0x330c));
-
- nv40_fifo_do_load_context(dev, pfifo->channels - 1);
- nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1,
- NV40_PFIFO_CACHE1_PUSH1_DMA | (pfifo->channels - 1));
- return 0;
-}
-
-static void
-nv40_fifo_init_reset(struct drm_device *dev)
-{
+ struct nv40_fifo_priv *priv = nv_engine(dev, engine);
int i;
- nv_wr32(dev, NV03_PMC_ENABLE,
- nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PFIFO);
- nv_wr32(dev, NV03_PMC_ENABLE,
- nv_rd32(dev, NV03_PMC_ENABLE) | NV_PMC_ENABLE_PFIFO);
+ nv_mask(dev, NV03_PMC_ENABLE, NV_PMC_ENABLE_PFIFO, 0);
+ nv_mask(dev, NV03_PMC_ENABLE, NV_PMC_ENABLE_PFIFO, NV_PMC_ENABLE_PFIFO);
- nv_wr32(dev, 0x003224, 0x000f0078);
- nv_wr32(dev, 0x003210, 0x00000000);
- nv_wr32(dev, 0x003270, 0x00000000);
- nv_wr32(dev, 0x003240, 0x00000000);
- nv_wr32(dev, 0x003244, 0x00000000);
- nv_wr32(dev, 0x003258, 0x00000000);
- nv_wr32(dev, 0x002504, 0x00000000);
- for (i = 0; i < 16; i++)
- nv_wr32(dev, 0x002510 + (i * 4), 0x00000000);
- nv_wr32(dev, 0x00250c, 0x0000ffff);
- nv_wr32(dev, 0x002048, 0x00000000);
- nv_wr32(dev, 0x003228, 0x00000000);
- nv_wr32(dev, 0x0032e8, 0x00000000);
- nv_wr32(dev, 0x002410, 0x00000000);
- nv_wr32(dev, 0x002420, 0x00000000);
- nv_wr32(dev, 0x002058, 0x00000001);
- nv_wr32(dev, 0x00221c, 0x00000000);
- /* something with 0x2084, read/modify/write, no change */
nv_wr32(dev, 0x002040, 0x000000ff);
- nv_wr32(dev, 0x002500, 0x00000000);
- nv_wr32(dev, 0x003200, 0x00000000);
-
- nv_wr32(dev, NV04_PFIFO_DMA_TIMESLICE, 0x2101ffff);
-}
-
-static void
-nv40_fifo_init_ramxx(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
+ nv_wr32(dev, 0x002044, 0x2101ffff);
+ nv_wr32(dev, 0x002058, 0x00000001);
nv_wr32(dev, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
((dev_priv->ramht->bits - 9) << 16) |
@@ -244,64 +152,59 @@ nv40_fifo_init_ramxx(struct drm_device *dev)
case 0x47:
case 0x49:
case 0x4b:
- nv_wr32(dev, 0x2230, 1);
- break;
- default:
- break;
- }
-
- switch (dev_priv->chipset) {
+ nv_wr32(dev, 0x002230, 0x00000001);
case 0x40:
case 0x41:
case 0x42:
case 0x43:
case 0x45:
- case 0x47:
case 0x48:
- case 0x49:
- case 0x4b:
- nv_wr32(dev, NV40_PFIFO_RAMFC, 0x30002);
+ nv_wr32(dev, 0x002220, 0x00030002);
break;
default:
- nv_wr32(dev, 0x2230, 0);
- nv_wr32(dev, NV40_PFIFO_RAMFC,
- ((dev_priv->vram_size - 512 * 1024 +
- dev_priv->ramfc->pinst) >> 16) | (3 << 16));
+ nv_wr32(dev, 0x002230, 0x00000000);
+ nv_wr32(dev, 0x002220, ((dev_priv->vram_size - 512 * 1024 +
+ dev_priv->ramfc->pinst) >> 16) |
+ 0x00030000);
break;
}
-}
-static void
-nv40_fifo_init_intr(struct drm_device *dev)
-{
- nouveau_irq_register(dev, 8, nv04_fifo_isr);
- nv_wr32(dev, 0x002100, 0xffffffff);
- nv_wr32(dev, 0x002140, 0xffffffff);
+ nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, priv->base.channels);
+
+ nv_wr32(dev, NV03_PFIFO_INTR_0, 0xffffffff);
+ nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0xffffffff);
+
+ nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, 1);
+ nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1);
+ nv_wr32(dev, NV03_PFIFO_CACHES, 1);
+
+ for (i = 0; i < priv->base.channels; i++) {
+ if (dev_priv->channels.ptr[i])
+ nv_mask(dev, NV04_PFIFO_MODE, (1 << i), (1 << i));
+ }
+
+ return 0;
}
int
-nv40_fifo_init(struct drm_device *dev)
+nv40_fifo_create(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- int i;
-
- nv40_fifo_init_reset(dev);
- nv40_fifo_init_ramxx(dev);
+ struct nv40_fifo_priv *priv;
- nv40_fifo_do_load_context(dev, pfifo->channels - 1);
- nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, pfifo->channels - 1);
-
- nv40_fifo_init_intr(dev);
- pfifo->enable(dev);
- pfifo->reassign(dev, true);
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
- for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
- if (dev_priv->channels.ptr[i]) {
- uint32_t mode = nv_rd32(dev, NV04_PFIFO_MODE);
- nv_wr32(dev, NV04_PFIFO_MODE, mode | (1 << i));
- }
- }
+ priv->base.base.destroy = nv04_fifo_destroy;
+ priv->base.base.init = nv40_fifo_init;
+ priv->base.base.fini = nv04_fifo_fini;
+ priv->base.base.context_new = nv40_fifo_context_new;
+ priv->base.base.context_del = nv04_fifo_context_del;
+ priv->base.channels = 31;
+ priv->ramfc_desc = nv40_ramfc;
+ dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
+ nouveau_irq_register(dev, 8, nv04_fifo_isr);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv40_graph.c b/drivers/gpu/drm/nouveau/nv40_graph.c
index ba14a93d8afa..aa9e2df64a26 100644
--- a/drivers/gpu/drm/nouveau/nv40_graph.c
+++ b/drivers/gpu/drm/nouveau/nv40_graph.c
@@ -27,7 +27,7 @@
#include "drmP.h"
#include "drm.h"
#include "nouveau_drv.h"
-#include "nouveau_grctx.h"
+#include "nouveau_fifo.h"
#include "nouveau_ramht.h"
struct nv40_graph_engine {
@@ -42,7 +42,6 @@ nv40_graph_context_new(struct nouveau_channel *chan, int engine)
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *grctx = NULL;
- struct nouveau_grctx ctx = {};
unsigned long flags;
int ret;
@@ -52,11 +51,7 @@ nv40_graph_context_new(struct nouveau_channel *chan, int engine)
return ret;
/* Initialise default context values */
- ctx.dev = chan->dev;
- ctx.mode = NOUVEAU_GRCTX_VALS;
- ctx.data = grctx;
- nv40_grctx_init(&ctx);
-
+ nv40_grctx_fill(dev, grctx);
nv_wo32(grctx, 0, grctx->vinst);
/* init grctx pointer in ramfc, and on PFIFO if channel is
@@ -184,8 +179,7 @@ nv40_graph_init(struct drm_device *dev, int engine)
struct nv40_graph_engine *pgraph = nv_engine(dev, engine);
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
- struct nouveau_grctx ctx = {};
- uint32_t vramsz, *cp;
+ uint32_t vramsz;
int i, j;
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
@@ -193,22 +187,8 @@ nv40_graph_init(struct drm_device *dev, int engine)
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
NV_PMC_ENABLE_PGRAPH);
- cp = kmalloc(sizeof(*cp) * 256, GFP_KERNEL);
- if (!cp)
- return -ENOMEM;
-
- ctx.dev = dev;
- ctx.mode = NOUVEAU_GRCTX_PROG;
- ctx.data = cp;
- ctx.ctxprog_max = 256;
- nv40_grctx_init(&ctx);
- pgraph->grctx_size = ctx.ctxvals_pos * 4;
-
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
- for (i = 0; i < ctx.ctxprog_len; i++)
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
-
- kfree(cp);
+ /* generate and upload context program */
+ nv40_grctx_init(dev, &pgraph->grctx_size);
/* No context present currently */
nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
@@ -366,13 +346,14 @@ nv40_graph_fini(struct drm_device *dev, int engine, bool suspend)
static int
nv40_graph_isr_chid(struct drm_device *dev, u32 inst)
{
+ struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *grctx;
unsigned long flags;
int i;
spin_lock_irqsave(&dev_priv->channels.lock, flags);
- for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
+ for (i = 0; i < pfifo->channels; i++) {
if (!dev_priv->channels.ptr[i])
continue;
grctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_GR];
@@ -460,7 +441,6 @@ nv40_graph_create(struct drm_device *dev)
NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
nouveau_irq_register(dev, 12, nv40_graph_isr);
- NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
NVOBJ_CLASS(dev, 0x0030, GR); /* null */
NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
@@ -483,8 +463,5 @@ nv40_graph_create(struct drm_device *dev)
else
NVOBJ_CLASS(dev, 0x4097, GR);
- /* nvsw */
- NVOBJ_CLASS(dev, 0x506e, SW);
- NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv40_grctx.c b/drivers/gpu/drm/nouveau/nv40_grctx.c
index f70447d131d7..be0a74750fb1 100644
--- a/drivers/gpu/drm/nouveau/nv40_grctx.c
+++ b/drivers/gpu/drm/nouveau/nv40_grctx.c
@@ -595,8 +595,8 @@ nv40_graph_construct_shader(struct nouveau_grctx *ctx)
}
}
-void
-nv40_grctx_init(struct nouveau_grctx *ctx)
+static void
+nv40_grctx_generate(struct nouveau_grctx *ctx)
{
/* decide whether we're loading/unloading the context */
cp_bra (ctx, AUTO_SAVE, PENDING, cp_setup_save);
@@ -660,3 +660,31 @@ nv40_grctx_init(struct nouveau_grctx *ctx)
cp_out (ctx, CP_END);
}
+void
+nv40_grctx_fill(struct drm_device *dev, struct nouveau_gpuobj *mem)
+{
+ nv40_grctx_generate(&(struct nouveau_grctx) {
+ .dev = dev,
+ .mode = NOUVEAU_GRCTX_VALS,
+ .data = mem,
+ });
+}
+
+void
+nv40_grctx_init(struct drm_device *dev, u32 *size)
+{
+ u32 ctxprog[256], i;
+ struct nouveau_grctx ctx = {
+ .dev = dev,
+ .mode = NOUVEAU_GRCTX_PROG,
+ .data = ctxprog,
+ .ctxprog_max = ARRAY_SIZE(ctxprog)
+ };
+
+ nv40_grctx_generate(&ctx);
+
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
+ for (i = 0; i < ctx.ctxprog_len; i++)
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, ctxprog[i]);
+ *size = ctx.ctxvals_pos * 4;
+}
diff --git a/drivers/gpu/drm/nouveau/nv40_pm.c b/drivers/gpu/drm/nouveau/nv40_pm.c
index c7615381c5d9..e66273aff493 100644
--- a/drivers/gpu/drm/nouveau/nv40_pm.c
+++ b/drivers/gpu/drm/nouveau/nv40_pm.c
@@ -27,6 +27,7 @@
#include "nouveau_bios.h"
#include "nouveau_pm.h"
#include "nouveau_hw.h"
+#include "nouveau_fifo.h"
#define min2(a,b) ((a) < (b) ? (a) : (b))
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
index 701b927998bf..97a477b3d52d 100644
--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
@@ -79,15 +79,15 @@ nv50_crtc_blank(struct nouveau_crtc *nv_crtc, bool blanked)
NV_ERROR(dev, "no space while blanking crtc\n");
return ret;
}
- BEGIN_RING(evo, 0, NV50_EVO_CRTC(index, CLUT_MODE), 2);
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(index, CLUT_MODE), 2);
OUT_RING(evo, NV50_EVO_CRTC_CLUT_MODE_BLANK);
OUT_RING(evo, 0);
if (dev_priv->chipset != 0x50) {
- BEGIN_RING(evo, 0, NV84_EVO_CRTC(index, CLUT_DMA), 1);
+ BEGIN_NV04(evo, 0, NV84_EVO_CRTC(index, CLUT_DMA), 1);
OUT_RING(evo, NV84_EVO_CRTC_CLUT_DMA_HANDLE_NONE);
}
- BEGIN_RING(evo, 0, NV50_EVO_CRTC(index, FB_DMA), 1);
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(index, FB_DMA), 1);
OUT_RING(evo, NV50_EVO_CRTC_FB_DMA_HANDLE_NONE);
} else {
if (nv_crtc->cursor.visible)
@@ -100,20 +100,20 @@ nv50_crtc_blank(struct nouveau_crtc *nv_crtc, bool blanked)
NV_ERROR(dev, "no space while unblanking crtc\n");
return ret;
}
- BEGIN_RING(evo, 0, NV50_EVO_CRTC(index, CLUT_MODE), 2);
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(index, CLUT_MODE), 2);
OUT_RING(evo, nv_crtc->lut.depth == 8 ?
NV50_EVO_CRTC_CLUT_MODE_OFF :
NV50_EVO_CRTC_CLUT_MODE_ON);
OUT_RING(evo, nv_crtc->lut.nvbo->bo.offset >> 8);
if (dev_priv->chipset != 0x50) {
- BEGIN_RING(evo, 0, NV84_EVO_CRTC(index, CLUT_DMA), 1);
+ BEGIN_NV04(evo, 0, NV84_EVO_CRTC(index, CLUT_DMA), 1);
OUT_RING(evo, NvEvoVRAM);
}
- BEGIN_RING(evo, 0, NV50_EVO_CRTC(index, FB_OFFSET), 2);
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(index, FB_OFFSET), 2);
OUT_RING(evo, nv_crtc->fb.offset >> 8);
OUT_RING(evo, 0);
- BEGIN_RING(evo, 0, NV50_EVO_CRTC(index, FB_DMA), 1);
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(index, FB_DMA), 1);
if (dev_priv->chipset != 0x50)
if (nv_crtc->fb.tile_flags == 0x7a00 ||
nv_crtc->fb.tile_flags == 0xfe00)
@@ -158,10 +158,10 @@ nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update)
ret = RING_SPACE(evo, 2 + (update ? 2 : 0));
if (ret == 0) {
- BEGIN_RING(evo, 0, NV50_EVO_CRTC(head, DITHER_CTRL), 1);
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(head, DITHER_CTRL), 1);
OUT_RING (evo, mode);
if (update) {
- BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
+ BEGIN_NV04(evo, 0, NV50_EVO_UPDATE, 1);
OUT_RING (evo, 0);
FIRE_RING (evo);
}
@@ -193,11 +193,11 @@ nv50_crtc_set_color_vibrance(struct nouveau_crtc *nv_crtc, bool update)
hue = ((nv_crtc->vibrant_hue * 2047) / 100) & 0xfff;
- BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, COLOR_CTRL), 1);
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(nv_crtc->index, COLOR_CTRL), 1);
OUT_RING (evo, (hue << 20) | (vib << 8));
if (update) {
- BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
+ BEGIN_NV04(evo, 0, NV50_EVO_UPDATE, 1);
OUT_RING (evo, 0);
FIRE_RING (evo);
}
@@ -311,9 +311,9 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update)
if (ret)
return ret;
- BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, SCALE_CTRL), 1);
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(nv_crtc->index, SCALE_CTRL), 1);
OUT_RING (evo, ctrl);
- BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, SCALE_RES1), 2);
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(nv_crtc->index, SCALE_RES1), 2);
OUT_RING (evo, oY << 16 | oX);
OUT_RING (evo, oY << 16 | oX);
@@ -383,23 +383,15 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
static void
nv50_crtc_destroy(struct drm_crtc *crtc)
{
- struct drm_device *dev;
- struct nouveau_crtc *nv_crtc;
-
- if (!crtc)
- return;
-
- dev = crtc->dev;
- nv_crtc = nouveau_crtc(crtc);
-
- NV_DEBUG_KMS(dev, "\n");
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
- drm_crtc_cleanup(&nv_crtc->base);
+ NV_DEBUG_KMS(crtc->dev, "\n");
nouveau_bo_unmap(nv_crtc->lut.nvbo);
nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
nouveau_bo_unmap(nv_crtc->cursor.nvbo);
nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
+ drm_crtc_cleanup(&nv_crtc->base);
kfree(nv_crtc);
}
@@ -593,7 +585,7 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
if (ret)
return ret;
- BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_DMA), 1);
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_DMA), 1);
OUT_RING (evo, fb->r_dma);
}
@@ -601,18 +593,18 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
if (ret)
return ret;
- BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_OFFSET), 5);
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_OFFSET), 5);
OUT_RING (evo, nv_crtc->fb.offset >> 8);
OUT_RING (evo, 0);
OUT_RING (evo, (drm_fb->height << 16) | drm_fb->width);
OUT_RING (evo, fb->r_pitch);
OUT_RING (evo, fb->r_format);
- BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, CLUT_MODE), 1);
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(nv_crtc->index, CLUT_MODE), 1);
OUT_RING (evo, fb->base.depth == 8 ?
NV50_EVO_CRTC_CLUT_MODE_OFF : NV50_EVO_CRTC_CLUT_MODE_ON);
- BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_POS), 1);
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_POS), 1);
OUT_RING (evo, (y << 16) | x);
if (nv_crtc->lut.depth != fb->base.depth) {
@@ -672,23 +664,23 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
ret = RING_SPACE(evo, 18);
if (ret == 0) {
- BEGIN_RING(evo, 0, 0x0804 + head, 2);
+ BEGIN_NV04(evo, 0, 0x0804 + head, 2);
OUT_RING (evo, 0x00800000 | mode->clock);
OUT_RING (evo, (ilace == 2) ? 2 : 0);
- BEGIN_RING(evo, 0, 0x0810 + head, 6);
+ BEGIN_NV04(evo, 0, 0x0810 + head, 6);
OUT_RING (evo, 0x00000000); /* border colour */
OUT_RING (evo, (vactive << 16) | hactive);
OUT_RING (evo, ( vsynce << 16) | hsynce);
OUT_RING (evo, (vblanke << 16) | hblanke);
OUT_RING (evo, (vblanks << 16) | hblanks);
OUT_RING (evo, (vblan2e << 16) | vblan2s);
- BEGIN_RING(evo, 0, 0x082c + head, 1);
+ BEGIN_NV04(evo, 0, 0x082c + head, 1);
OUT_RING (evo, 0x00000000);
- BEGIN_RING(evo, 0, 0x0900 + head, 1);
+ BEGIN_NV04(evo, 0, 0x0900 + head, 1);
OUT_RING (evo, 0x00000311); /* makes sync channel work */
- BEGIN_RING(evo, 0, 0x08c8 + head, 1);
+ BEGIN_NV04(evo, 0, 0x08c8 + head, 1);
OUT_RING (evo, (umode->vdisplay << 16) | umode->hdisplay);
- BEGIN_RING(evo, 0, 0x08d4 + head, 1);
+ BEGIN_NV04(evo, 0, 0x08d4 + head, 1);
OUT_RING (evo, 0x00000000); /* screen position */
}
@@ -755,21 +747,25 @@ nv50_crtc_create(struct drm_device *dev, int index)
if (!nv_crtc)
return -ENOMEM;
+ nv_crtc->index = index;
+ nv_crtc->set_dither = nv50_crtc_set_dither;
+ nv_crtc->set_scale = nv50_crtc_set_scale;
+ nv_crtc->set_color_vibrance = nv50_crtc_set_color_vibrance;
nv_crtc->color_vibrance = 50;
nv_crtc->vibrant_hue = 0;
-
- /* Default CLUT parameters, will be activated on the hw upon
- * first mode set.
- */
+ nv_crtc->lut.depth = 0;
for (i = 0; i < 256; i++) {
nv_crtc->lut.r[i] = i << 8;
nv_crtc->lut.g[i] = i << 8;
nv_crtc->lut.b[i] = i << 8;
}
- nv_crtc->lut.depth = 0;
+
+ drm_crtc_init(dev, &nv_crtc->base, &nv50_crtc_funcs);
+ drm_crtc_helper_add(&nv_crtc->base, &nv50_crtc_helper_funcs);
+ drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256);
ret = nouveau_bo_new(dev, 4096, 0x100, TTM_PL_FLAG_VRAM,
- 0, 0x0000, &nv_crtc->lut.nvbo);
+ 0, 0x0000, NULL, &nv_crtc->lut.nvbo);
if (!ret) {
ret = nouveau_bo_pin(nv_crtc->lut.nvbo, TTM_PL_FLAG_VRAM);
if (!ret)
@@ -778,24 +774,12 @@ nv50_crtc_create(struct drm_device *dev, int index)
nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo);
}
- if (ret) {
- kfree(nv_crtc);
- return ret;
- }
-
- nv_crtc->index = index;
+ if (ret)
+ goto out;
- /* set function pointers */
- nv_crtc->set_dither = nv50_crtc_set_dither;
- nv_crtc->set_scale = nv50_crtc_set_scale;
- nv_crtc->set_color_vibrance = nv50_crtc_set_color_vibrance;
-
- drm_crtc_init(dev, &nv_crtc->base, &nv50_crtc_funcs);
- drm_crtc_helper_add(&nv_crtc->base, &nv50_crtc_helper_funcs);
- drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256);
ret = nouveau_bo_new(dev, 64*64*4, 0x100, TTM_PL_FLAG_VRAM,
- 0, 0x0000, &nv_crtc->cursor.nvbo);
+ 0, 0x0000, NULL, &nv_crtc->cursor.nvbo);
if (!ret) {
ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
if (!ret)
@@ -804,6 +788,12 @@ nv50_crtc_create(struct drm_device *dev, int index)
nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
}
+ if (ret)
+ goto out;
+
nv50_cursor_init(nv_crtc);
- return 0;
+out:
+ if (ret)
+ nv50_crtc_destroy(&nv_crtc->base);
+ return ret;
}
diff --git a/drivers/gpu/drm/nouveau/nv50_cursor.c b/drivers/gpu/drm/nouveau/nv50_cursor.c
index adfc9b607a50..af4ec7bf3670 100644
--- a/drivers/gpu/drm/nouveau/nv50_cursor.c
+++ b/drivers/gpu/drm/nouveau/nv50_cursor.c
@@ -53,15 +53,15 @@ nv50_cursor_show(struct nouveau_crtc *nv_crtc, bool update)
}
if (dev_priv->chipset != 0x50) {
- BEGIN_RING(evo, 0, NV84_EVO_CRTC(nv_crtc->index, CURSOR_DMA), 1);
+ BEGIN_NV04(evo, 0, NV84_EVO_CRTC(nv_crtc->index, CURSOR_DMA), 1);
OUT_RING(evo, NvEvoVRAM);
}
- BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, CURSOR_CTRL), 2);
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(nv_crtc->index, CURSOR_CTRL), 2);
OUT_RING(evo, NV50_EVO_CRTC_CURSOR_CTRL_SHOW);
OUT_RING(evo, nv_crtc->cursor.offset >> 8);
if (update) {
- BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
+ BEGIN_NV04(evo, 0, NV50_EVO_UPDATE, 1);
OUT_RING(evo, 0);
FIRE_RING(evo);
nv_crtc->cursor.visible = true;
@@ -86,16 +86,16 @@ nv50_cursor_hide(struct nouveau_crtc *nv_crtc, bool update)
NV_ERROR(dev, "no space while hiding cursor\n");
return;
}
- BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, CURSOR_CTRL), 2);
+ BEGIN_NV04(evo, 0, NV50_EVO_CRTC(nv_crtc->index, CURSOR_CTRL), 2);
OUT_RING(evo, NV50_EVO_CRTC_CURSOR_CTRL_HIDE);
OUT_RING(evo, 0);
if (dev_priv->chipset != 0x50) {
- BEGIN_RING(evo, 0, NV84_EVO_CRTC(nv_crtc->index, CURSOR_DMA), 1);
+ BEGIN_NV04(evo, 0, NV84_EVO_CRTC(nv_crtc->index, CURSOR_DMA), 1);
OUT_RING(evo, NV84_EVO_CRTC_CURSOR_DMA_HANDLE_NONE);
}
if (update) {
- BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
+ BEGIN_NV04(evo, 0, NV50_EVO_UPDATE, 1);
OUT_RING(evo, 0);
FIRE_RING(evo);
nv_crtc->cursor.visible = false;
diff --git a/drivers/gpu/drm/nouveau/nv50_dac.c b/drivers/gpu/drm/nouveau/nv50_dac.c
index 55c56330be6d..eb216a446b89 100644
--- a/drivers/gpu/drm/nouveau/nv50_dac.c
+++ b/drivers/gpu/drm/nouveau/nv50_dac.c
@@ -55,9 +55,9 @@ nv50_dac_disconnect(struct drm_encoder *encoder)
NV_ERROR(dev, "no space while disconnecting DAC\n");
return;
}
- BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 1);
+ BEGIN_NV04(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 1);
OUT_RING (evo, 0);
- BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
+ BEGIN_NV04(evo, 0, NV50_EVO_UPDATE, 1);
OUT_RING (evo, 0);
nv_encoder->crtc = NULL;
@@ -240,7 +240,7 @@ nv50_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
NV_ERROR(dev, "no space while connecting DAC\n");
return;
}
- BEGIN_RING(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 2);
+ BEGIN_NV04(evo, 0, NV50_EVO_DAC(nv_encoder->or, MODE_CTRL), 2);
OUT_RING(evo, mode_ctl);
OUT_RING(evo, mode_ctl2);
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 8b78b9cfa383..5c41612723b4 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -32,6 +32,7 @@
#include "nouveau_fb.h"
#include "nouveau_fbcon.h"
#include "nouveau_ramht.h"
+#include "nouveau_software.h"
#include "drm_crtc_helper.h"
static void nv50_display_isr(struct drm_device *);
@@ -140,11 +141,11 @@ nv50_display_sync(struct drm_device *dev)
ret = RING_SPACE(evo, 6);
if (ret == 0) {
- BEGIN_RING(evo, 0, 0x0084, 1);
+ BEGIN_NV04(evo, 0, 0x0084, 1);
OUT_RING (evo, 0x80000000);
- BEGIN_RING(evo, 0, 0x0080, 1);
+ BEGIN_NV04(evo, 0, 0x0080, 1);
OUT_RING (evo, 0);
- BEGIN_RING(evo, 0, 0x0084, 1);
+ BEGIN_NV04(evo, 0, 0x0084, 1);
OUT_RING (evo, 0x00000000);
nv_wo32(disp->ntfy, 0x000, 0x00000000);
@@ -267,7 +268,7 @@ nv50_display_init(struct drm_device *dev)
ret = RING_SPACE(evo, 3);
if (ret)
return ret;
- BEGIN_RING(evo, 0, NV50_EVO_UNK84, 2);
+ BEGIN_NV04(evo, 0, NV50_EVO_UNK84, 2);
OUT_RING (evo, NV50_EVO_UNK84_NOTIFY_DISABLED);
OUT_RING (evo, NvEvoSync);
@@ -292,7 +293,7 @@ nv50_display_fini(struct drm_device *dev)
ret = RING_SPACE(evo, 2);
if (ret == 0) {
- BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
+ BEGIN_NV04(evo, 0, NV50_EVO_UPDATE, 1);
OUT_RING(evo, 0);
}
FIRE_RING(evo);
@@ -358,8 +359,11 @@ nv50_display_create(struct drm_device *dev)
dev_priv->engine.display.priv = priv;
/* Create CRTC objects */
- for (i = 0; i < 2; i++)
- nv50_crtc_create(dev, i);
+ for (i = 0; i < 2; i++) {
+ ret = nv50_crtc_create(dev, i);
+ if (ret)
+ return ret;
+ }
/* We setup the encoders from the BIOS table */
for (i = 0 ; i < dcb->entries; i++) {
@@ -438,13 +442,13 @@ nv50_display_flip_stop(struct drm_crtc *crtc)
return;
}
- BEGIN_RING(evo, 0, 0x0084, 1);
+ BEGIN_NV04(evo, 0, 0x0084, 1);
OUT_RING (evo, 0x00000000);
- BEGIN_RING(evo, 0, 0x0094, 1);
+ BEGIN_NV04(evo, 0, 0x0094, 1);
OUT_RING (evo, 0x00000000);
- BEGIN_RING(evo, 0, 0x00c0, 1);
+ BEGIN_NV04(evo, 0, 0x00c0, 1);
OUT_RING (evo, 0x00000000);
- BEGIN_RING(evo, 0, 0x0080, 1);
+ BEGIN_NV04(evo, 0, 0x0080, 1);
OUT_RING (evo, 0x00000000);
FIRE_RING (evo);
}
@@ -474,28 +478,28 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
}
if (dev_priv->chipset < 0xc0) {
- BEGIN_RING(chan, 0, 0x0060, 2);
+ BEGIN_NV04(chan, 0, 0x0060, 2);
OUT_RING (chan, NvEvoSema0 + nv_crtc->index);
OUT_RING (chan, dispc->sem.offset);
- BEGIN_RING(chan, 0, 0x006c, 1);
+ BEGIN_NV04(chan, 0, 0x006c, 1);
OUT_RING (chan, 0xf00d0000 | dispc->sem.value);
- BEGIN_RING(chan, 0, 0x0064, 2);
+ BEGIN_NV04(chan, 0, 0x0064, 2);
OUT_RING (chan, dispc->sem.offset ^ 0x10);
OUT_RING (chan, 0x74b1e000);
- BEGIN_RING(chan, 0, 0x0060, 1);
+ BEGIN_NV04(chan, 0, 0x0060, 1);
if (dev_priv->chipset < 0x84)
OUT_RING (chan, NvSema);
else
OUT_RING (chan, chan->vram_handle);
} else {
- u64 offset = chan->dispc_vma[nv_crtc->index].offset;
+ u64 offset = nvc0_software_crtc(chan, nv_crtc->index);
offset += dispc->sem.offset;
- BEGIN_NVC0(chan, 2, 0, 0x0010, 4);
+ BEGIN_NVC0(chan, 0, 0x0010, 4);
OUT_RING (chan, upper_32_bits(offset));
OUT_RING (chan, lower_32_bits(offset));
OUT_RING (chan, 0xf00d0000 | dispc->sem.value);
OUT_RING (chan, 0x1002);
- BEGIN_NVC0(chan, 2, 0, 0x0010, 4);
+ BEGIN_NVC0(chan, 0, 0x0010, 4);
OUT_RING (chan, upper_32_bits(offset));
OUT_RING (chan, lower_32_bits(offset ^ 0x10));
OUT_RING (chan, 0x74b1e000);
@@ -508,40 +512,40 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
}
/* queue the flip on the crtc's "display sync" channel */
- BEGIN_RING(evo, 0, 0x0100, 1);
+ BEGIN_NV04(evo, 0, 0x0100, 1);
OUT_RING (evo, 0xfffe0000);
if (chan) {
- BEGIN_RING(evo, 0, 0x0084, 1);
+ BEGIN_NV04(evo, 0, 0x0084, 1);
OUT_RING (evo, 0x00000100);
} else {
- BEGIN_RING(evo, 0, 0x0084, 1);
+ BEGIN_NV04(evo, 0, 0x0084, 1);
OUT_RING (evo, 0x00000010);
/* allows gamma somehow, PDISP will bitch at you if
* you don't wait for vblank before changing this..
*/
- BEGIN_RING(evo, 0, 0x00e0, 1);
+ BEGIN_NV04(evo, 0, 0x00e0, 1);
OUT_RING (evo, 0x40000000);
}
- BEGIN_RING(evo, 0, 0x0088, 4);
+ BEGIN_NV04(evo, 0, 0x0088, 4);
OUT_RING (evo, dispc->sem.offset);
OUT_RING (evo, 0xf00d0000 | dispc->sem.value);
OUT_RING (evo, 0x74b1e000);
OUT_RING (evo, NvEvoSync);
- BEGIN_RING(evo, 0, 0x00a0, 2);
+ BEGIN_NV04(evo, 0, 0x00a0, 2);
OUT_RING (evo, 0x00000000);
OUT_RING (evo, 0x00000000);
- BEGIN_RING(evo, 0, 0x00c0, 1);
+ BEGIN_NV04(evo, 0, 0x00c0, 1);
OUT_RING (evo, nv_fb->r_dma);
- BEGIN_RING(evo, 0, 0x0110, 2);
+ BEGIN_NV04(evo, 0, 0x0110, 2);
OUT_RING (evo, 0x00000000);
OUT_RING (evo, 0x00000000);
- BEGIN_RING(evo, 0, 0x0800, 5);
+ BEGIN_NV04(evo, 0, 0x0800, 5);
OUT_RING (evo, nv_fb->nvbo->bo.offset >> 8);
OUT_RING (evo, 0);
OUT_RING (evo, (fb->height << 16) | fb->width);
OUT_RING (evo, nv_fb->r_pitch);
OUT_RING (evo, nv_fb->r_format);
- BEGIN_RING(evo, 0, 0x0080, 1);
+ BEGIN_NV04(evo, 0, 0x0080, 1);
OUT_RING (evo, 0x00000000);
FIRE_RING (evo);
@@ -642,20 +646,7 @@ nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcb,
static void
nv50_display_vblank_crtc_handler(struct drm_device *dev, int crtc)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_channel *chan, *tmp;
-
- list_for_each_entry_safe(chan, tmp, &dev_priv->vbl_waiting,
- nvsw.vbl_wait) {
- if (chan->nvsw.vblsem_head != crtc)
- continue;
-
- nouveau_bo_wr32(chan->notifier_bo, chan->nvsw.vblsem_offset,
- chan->nvsw.vblsem_rval);
- list_del(&chan->nvsw.vbl_wait);
- drm_vblank_put(dev, crtc);
- }
-
+ nouveau_software_vblank(dev, crtc);
drm_handle_vblank(dev, crtc);
}
diff --git a/drivers/gpu/drm/nouveau/nv50_display.h b/drivers/gpu/drm/nouveau/nv50_display.h
index 5d3dd14d2837..e9db9b97f041 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.h
+++ b/drivers/gpu/drm/nouveau/nv50_display.h
@@ -33,6 +33,7 @@
#include "nouveau_dma.h"
#include "nouveau_reg.h"
#include "nouveau_crtc.h"
+#include "nouveau_software.h"
#include "nv50_evo.h"
struct nv50_display_crtc {
diff --git a/drivers/gpu/drm/nouveau/nv50_evo.c b/drivers/gpu/drm/nouveau/nv50_evo.c
index 9b962e989d7c..ddcd55595824 100644
--- a/drivers/gpu/drm/nouveau/nv50_evo.c
+++ b/drivers/gpu/drm/nouveau/nv50_evo.c
@@ -117,7 +117,7 @@ nv50_evo_channel_new(struct drm_device *dev, int chid,
evo->user_get = 4;
evo->user_put = 0;
- ret = nouveau_bo_new(dev, 4096, 0, TTM_PL_FLAG_VRAM, 0, 0,
+ ret = nouveau_bo_new(dev, 4096, 0, TTM_PL_FLAG_VRAM, 0, 0, NULL,
&evo->pushbuf_bo);
if (ret == 0)
ret = nouveau_bo_pin(evo->pushbuf_bo, TTM_PL_FLAG_VRAM);
@@ -333,7 +333,7 @@ nv50_evo_create(struct drm_device *dev)
goto err;
ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
- 0, 0x0000, &dispc->sem.bo);
+ 0, 0x0000, NULL, &dispc->sem.bo);
if (!ret) {
ret = nouveau_bo_pin(dispc->sem.bo, TTM_PL_FLAG_VRAM);
if (!ret)
diff --git a/drivers/gpu/drm/nouveau/nv50_fb.c b/drivers/gpu/drm/nouveau/nv50_fb.c
index bdd2afe29205..f1e4b9e07d14 100644
--- a/drivers/gpu/drm/nouveau/nv50_fb.c
+++ b/drivers/gpu/drm/nouveau/nv50_fb.c
@@ -2,6 +2,7 @@
#include "drm.h"
#include "nouveau_drv.h"
#include "nouveau_drm.h"
+#include "nouveau_fifo.h"
struct nv50_fb_priv {
struct page *r100c08_page;
@@ -212,6 +213,7 @@ static struct nouveau_enum vm_fault[] = {
void
nv50_fb_vm_trap(struct drm_device *dev, int display)
{
+ struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct drm_nouveau_private *dev_priv = dev->dev_private;
const struct nouveau_enum *en, *cl;
unsigned long flags;
@@ -236,7 +238,7 @@ nv50_fb_vm_trap(struct drm_device *dev, int display)
/* lookup channel id */
chinst = (trap[2] << 16) | trap[1];
spin_lock_irqsave(&dev_priv->channels.lock, flags);
- for (ch = 0; ch < dev_priv->engine.fifo.channels; ch++) {
+ for (ch = 0; ch < pfifo->channels; ch++) {
struct nouveau_channel *chan = dev_priv->channels.ptr[ch];
if (!chan || !chan->ramin)
diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c
index dc75a7206524..e3c8b05dcae4 100644
--- a/drivers/gpu/drm/nouveau/nv50_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c
@@ -43,22 +43,22 @@ nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
return ret;
if (rect->rop != ROP_COPY) {
- BEGIN_RING(chan, NvSub2D, 0x02ac, 1);
+ BEGIN_NV04(chan, NvSub2D, 0x02ac, 1);
OUT_RING(chan, 1);
}
- BEGIN_RING(chan, NvSub2D, 0x0588, 1);
+ BEGIN_NV04(chan, NvSub2D, 0x0588, 1);
if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
info->fix.visual == FB_VISUAL_DIRECTCOLOR)
OUT_RING(chan, ((uint32_t *)info->pseudo_palette)[rect->color]);
else
OUT_RING(chan, rect->color);
- BEGIN_RING(chan, NvSub2D, 0x0600, 4);
+ BEGIN_NV04(chan, NvSub2D, 0x0600, 4);
OUT_RING(chan, rect->dx);
OUT_RING(chan, rect->dy);
OUT_RING(chan, rect->dx + rect->width);
OUT_RING(chan, rect->dy + rect->height);
if (rect->rop != ROP_COPY) {
- BEGIN_RING(chan, NvSub2D, 0x02ac, 1);
+ BEGIN_NV04(chan, NvSub2D, 0x02ac, 1);
OUT_RING(chan, 3);
}
FIRE_RING(chan);
@@ -78,14 +78,14 @@ nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
if (ret)
return ret;
- BEGIN_RING(chan, NvSub2D, 0x0110, 1);
+ BEGIN_NV04(chan, NvSub2D, 0x0110, 1);
OUT_RING(chan, 0);
- BEGIN_RING(chan, NvSub2D, 0x08b0, 4);
+ BEGIN_NV04(chan, NvSub2D, 0x08b0, 4);
OUT_RING(chan, region->dx);
OUT_RING(chan, region->dy);
OUT_RING(chan, region->width);
OUT_RING(chan, region->height);
- BEGIN_RING(chan, NvSub2D, 0x08d0, 4);
+ BEGIN_NV04(chan, NvSub2D, 0x08d0, 4);
OUT_RING(chan, 0);
OUT_RING(chan, region->sx);
OUT_RING(chan, 0);
@@ -116,7 +116,7 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
width = ALIGN(image->width, 32);
dwords = (width * image->height) >> 5;
- BEGIN_RING(chan, NvSub2D, 0x0814, 2);
+ BEGIN_NV04(chan, NvSub2D, 0x0814, 2);
if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
OUT_RING(chan, palette[image->bg_color] | mask);
@@ -125,10 +125,10 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
OUT_RING(chan, image->bg_color);
OUT_RING(chan, image->fg_color);
}
- BEGIN_RING(chan, NvSub2D, 0x0838, 2);
+ BEGIN_NV04(chan, NvSub2D, 0x0838, 2);
OUT_RING(chan, image->width);
OUT_RING(chan, image->height);
- BEGIN_RING(chan, NvSub2D, 0x0850, 4);
+ BEGIN_NV04(chan, NvSub2D, 0x0850, 4);
OUT_RING(chan, 0);
OUT_RING(chan, image->dx);
OUT_RING(chan, 0);
@@ -143,7 +143,7 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
dwords -= push;
- BEGIN_RING(chan, NvSub2D, 0x40000860, push);
+ BEGIN_NI04(chan, NvSub2D, 0x0860, push);
OUT_RINGp(chan, data, push);
data += push;
}
@@ -199,60 +199,59 @@ nv50_fbcon_accel_init(struct fb_info *info)
return ret;
}
- BEGIN_RING(chan, NvSub2D, 0x0000, 1);
+ BEGIN_NV04(chan, NvSub2D, 0x0000, 1);
OUT_RING(chan, Nv2D);
- BEGIN_RING(chan, NvSub2D, 0x0180, 4);
- OUT_RING(chan, NvNotify0);
+ BEGIN_NV04(chan, NvSub2D, 0x0184, 3);
OUT_RING(chan, chan->vram_handle);
OUT_RING(chan, chan->vram_handle);
OUT_RING(chan, chan->vram_handle);
- BEGIN_RING(chan, NvSub2D, 0x0290, 1);
+ BEGIN_NV04(chan, NvSub2D, 0x0290, 1);
OUT_RING(chan, 0);
- BEGIN_RING(chan, NvSub2D, 0x0888, 1);
+ BEGIN_NV04(chan, NvSub2D, 0x0888, 1);
OUT_RING(chan, 1);
- BEGIN_RING(chan, NvSub2D, 0x02ac, 1);
+ BEGIN_NV04(chan, NvSub2D, 0x02ac, 1);
OUT_RING(chan, 3);
- BEGIN_RING(chan, NvSub2D, 0x02a0, 1);
+ BEGIN_NV04(chan, NvSub2D, 0x02a0, 1);
OUT_RING(chan, 0x55);
- BEGIN_RING(chan, NvSub2D, 0x08c0, 4);
+ BEGIN_NV04(chan, NvSub2D, 0x08c0, 4);
OUT_RING(chan, 0);
OUT_RING(chan, 1);
OUT_RING(chan, 0);
OUT_RING(chan, 1);
- BEGIN_RING(chan, NvSub2D, 0x0580, 2);
+ BEGIN_NV04(chan, NvSub2D, 0x0580, 2);
OUT_RING(chan, 4);
OUT_RING(chan, format);
- BEGIN_RING(chan, NvSub2D, 0x02e8, 2);
+ BEGIN_NV04(chan, NvSub2D, 0x02e8, 2);
OUT_RING(chan, 2);
OUT_RING(chan, 1);
- BEGIN_RING(chan, NvSub2D, 0x0804, 1);
+ BEGIN_NV04(chan, NvSub2D, 0x0804, 1);
OUT_RING(chan, format);
- BEGIN_RING(chan, NvSub2D, 0x0800, 1);
+ BEGIN_NV04(chan, NvSub2D, 0x0800, 1);
OUT_RING(chan, 1);
- BEGIN_RING(chan, NvSub2D, 0x0808, 3);
+ BEGIN_NV04(chan, NvSub2D, 0x0808, 3);
OUT_RING(chan, 0);
OUT_RING(chan, 0);
OUT_RING(chan, 1);
- BEGIN_RING(chan, NvSub2D, 0x081c, 1);
+ BEGIN_NV04(chan, NvSub2D, 0x081c, 1);
OUT_RING(chan, 1);
- BEGIN_RING(chan, NvSub2D, 0x0840, 4);
+ BEGIN_NV04(chan, NvSub2D, 0x0840, 4);
OUT_RING(chan, 0);
OUT_RING(chan, 1);
OUT_RING(chan, 0);
OUT_RING(chan, 1);
- BEGIN_RING(chan, NvSub2D, 0x0200, 2);
+ BEGIN_NV04(chan, NvSub2D, 0x0200, 2);
OUT_RING(chan, format);
OUT_RING(chan, 1);
- BEGIN_RING(chan, NvSub2D, 0x0214, 5);
+ BEGIN_NV04(chan, NvSub2D, 0x0214, 5);
OUT_RING(chan, info->fix.line_length);
OUT_RING(chan, info->var.xres_virtual);
OUT_RING(chan, info->var.yres_virtual);
OUT_RING(chan, upper_32_bits(fb->vma.offset));
OUT_RING(chan, lower_32_bits(fb->vma.offset));
- BEGIN_RING(chan, NvSub2D, 0x0230, 2);
+ BEGIN_NV04(chan, NvSub2D, 0x0230, 2);
OUT_RING(chan, format);
OUT_RING(chan, 1);
- BEGIN_RING(chan, NvSub2D, 0x0244, 5);
+ BEGIN_NV04(chan, NvSub2D, 0x0244, 5);
OUT_RING(chan, info->fix.line_length);
OUT_RING(chan, info->var.xres_virtual);
OUT_RING(chan, info->var.yres_virtual);
diff --git a/drivers/gpu/drm/nouveau/nv50_fifo.c b/drivers/gpu/drm/nouveau/nv50_fifo.c
index 3bc2a565c20b..55383b85db0b 100644
--- a/drivers/gpu/drm/nouveau/nv50_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv50_fifo.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Ben Skeggs.
+ * Copyright (C) 2012 Ben Skeggs.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
@@ -27,480 +27,268 @@
#include "drmP.h"
#include "drm.h"
#include "nouveau_drv.h"
+#include "nouveau_fifo.h"
#include "nouveau_ramht.h"
#include "nouveau_vm.h"
-static void
+struct nv50_fifo_priv {
+ struct nouveau_fifo_priv base;
+ struct nouveau_gpuobj *playlist[2];
+ int cur_playlist;
+};
+
+struct nv50_fifo_chan {
+ struct nouveau_fifo_chan base;
+};
+
+void
nv50_fifo_playlist_update(struct drm_device *dev)
{
+ struct nv50_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nouveau_gpuobj *cur;
- int i, nr;
-
- NV_DEBUG(dev, "\n");
+ int i, p;
- cur = pfifo->playlist[pfifo->cur_playlist];
- pfifo->cur_playlist = !pfifo->cur_playlist;
+ cur = priv->playlist[priv->cur_playlist];
+ priv->cur_playlist = !priv->cur_playlist;
- /* We never schedule channel 0 or 127 */
- for (i = 1, nr = 0; i < 127; i++) {
- if (dev_priv->channels.ptr[i] &&
- dev_priv->channels.ptr[i]->ramfc) {
- nv_wo32(cur, (nr * 4), i);
- nr++;
- }
+ for (i = 0, p = 0; i < priv->base.channels; i++) {
+ if (nv_rd32(dev, 0x002600 + (i * 4)) & 0x80000000)
+ nv_wo32(cur, p++ * 4, i);
}
- dev_priv->engine.instmem.flush(dev);
-
- nv_wr32(dev, 0x32f4, cur->vinst >> 12);
- nv_wr32(dev, 0x32ec, nr);
- nv_wr32(dev, 0x2500, 0x101);
-}
-static void
-nv50_fifo_channel_enable(struct drm_device *dev, int channel)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_channel *chan = dev_priv->channels.ptr[channel];
- uint32_t inst;
-
- NV_DEBUG(dev, "ch%d\n", channel);
-
- if (dev_priv->chipset == 0x50)
- inst = chan->ramfc->vinst >> 12;
- else
- inst = chan->ramfc->vinst >> 8;
+ dev_priv->engine.instmem.flush(dev);
- nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel), inst |
- NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED);
+ nv_wr32(dev, 0x0032f4, cur->vinst >> 12);
+ nv_wr32(dev, 0x0032ec, p);
+ nv_wr32(dev, 0x002500, 0x00000101);
}
-static void
-nv50_fifo_channel_disable(struct drm_device *dev, int channel)
+static int
+nv50_fifo_context_new(struct nouveau_channel *chan, int engine)
{
+ struct nv50_fifo_priv *priv = nv_engine(chan->dev, engine);
+ struct nv50_fifo_chan *fctx;
+ struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t inst;
-
- NV_DEBUG(dev, "ch%d\n", channel);
+ u64 ib_offset = chan->pushbuf_base + chan->dma.ib_base * 4;
+ u64 instance = chan->ramin->vinst >> 12;
+ unsigned long flags;
+ int ret = 0, i;
- if (dev_priv->chipset == 0x50)
- inst = NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G80;
- else
- inst = NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G84;
- nv_wr32(dev, NV50_PFIFO_CTX_TABLE(channel), inst);
-}
+ fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
+ if (!fctx)
+ return -ENOMEM;
+ atomic_inc(&chan->vm->engref[engine]);
-static void
-nv50_fifo_init_reset(struct drm_device *dev)
-{
- uint32_t pmc_e = NV_PMC_ENABLE_PFIFO;
+ chan->user = ioremap(pci_resource_start(dev->pdev, 0) +
+ NV50_USER(chan->id), PAGE_SIZE);
+ if (!chan->user) {
+ ret = -ENOMEM;
+ goto error;
+ }
- NV_DEBUG(dev, "\n");
+ for (i = 0; i < 0x100; i += 4)
+ nv_wo32(chan->ramin, i, 0x00000000);
+ nv_wo32(chan->ramin, 0x3c, 0x403f6078);
+ nv_wo32(chan->ramin, 0x40, 0x00000000);
+ nv_wo32(chan->ramin, 0x44, 0x01003fff);
+ nv_wo32(chan->ramin, 0x48, chan->pushbuf->cinst >> 4);
+ nv_wo32(chan->ramin, 0x50, lower_32_bits(ib_offset));
+ nv_wo32(chan->ramin, 0x54, upper_32_bits(ib_offset) |
+ drm_order(chan->dma.ib_max + 1) << 16);
+ nv_wo32(chan->ramin, 0x60, 0x7fffffff);
+ nv_wo32(chan->ramin, 0x78, 0x00000000);
+ nv_wo32(chan->ramin, 0x7c, 0x30000001);
+ nv_wo32(chan->ramin, 0x80, ((chan->ramht->bits - 9) << 27) |
+ (4 << 24) /* SEARCH_FULL */ |
+ (chan->ramht->gpuobj->cinst >> 4));
- nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & ~pmc_e);
- nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) | pmc_e);
-}
+ dev_priv->engine.instmem.flush(dev);
-static void
-nv50_fifo_init_intr(struct drm_device *dev)
-{
- NV_DEBUG(dev, "\n");
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ nv_wr32(dev, 0x002600 + (chan->id * 4), 0x80000000 | instance);
+ nv50_fifo_playlist_update(dev);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
- nouveau_irq_register(dev, 8, nv04_fifo_isr);
- nv_wr32(dev, NV03_PFIFO_INTR_0, 0xFFFFFFFF);
- nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0xFFFFFFFF);
+error:
+ if (ret)
+ priv->base.base.context_del(chan, engine);
+ return ret;
}
-static void
-nv50_fifo_init_context_table(struct drm_device *dev)
+static bool
+nv50_fifo_kickoff(struct nouveau_channel *chan)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- int i;
-
- NV_DEBUG(dev, "\n");
-
- for (i = 0; i < NV50_PFIFO_CTX_TABLE__SIZE; i++) {
- if (dev_priv->channels.ptr[i])
- nv50_fifo_channel_enable(dev, i);
- else
- nv50_fifo_channel_disable(dev, i);
+ struct drm_device *dev = chan->dev;
+ bool done = true;
+ u32 me;
+
+ /* HW bug workaround:
+ *
+ * PFIFO will hang forever if the connected engines don't report
+ * that they've processed the context switch request.
+ *
+ * In order for the kickoff to work, we need to ensure all the
+ * connected engines are in a state where they can answer.
+ *
+ * Newer chipsets don't seem to suffer from this issue, and well,
+ * there's also a "ignore these engines" bitmask reg we can use
+ * if we hit the issue there..
+ */
+
+ /* PME: make sure engine is enabled */
+ me = nv_mask(dev, 0x00b860, 0x00000001, 0x00000001);
+
+ /* do the kickoff... */
+ nv_wr32(dev, 0x0032fc, chan->ramin->vinst >> 12);
+ if (!nv_wait_ne(dev, 0x0032fc, 0xffffffff, 0xffffffff)) {
+ NV_INFO(dev, "PFIFO: channel %d unload timeout\n", chan->id);
+ done = false;
}
- nv50_fifo_playlist_update(dev);
+ /* restore any engine states we changed, and exit */
+ nv_wr32(dev, 0x00b860, me);
+ return done;
}
static void
-nv50_fifo_init_regs__nv(struct drm_device *dev)
-{
- NV_DEBUG(dev, "\n");
-
- nv_wr32(dev, 0x250c, 0x6f3cfc34);
-}
-
-static void
-nv50_fifo_init_regs(struct drm_device *dev)
-{
- NV_DEBUG(dev, "\n");
-
- nv_wr32(dev, 0x2500, 0);
- nv_wr32(dev, 0x3250, 0);
- nv_wr32(dev, 0x3220, 0);
- nv_wr32(dev, 0x3204, 0);
- nv_wr32(dev, 0x3210, 0);
- nv_wr32(dev, 0x3270, 0);
- nv_wr32(dev, 0x2044, 0x01003fff);
-
- /* Enable dummy channels setup by nv50_instmem.c */
- nv50_fifo_channel_enable(dev, 0);
- nv50_fifo_channel_enable(dev, 127);
-}
-
-int
-nv50_fifo_init(struct drm_device *dev)
+nv50_fifo_context_del(struct nouveau_channel *chan, int engine)
{
+ struct nv50_fifo_chan *fctx = chan->engctx[engine];
+ struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- int ret;
+ unsigned long flags;
- NV_DEBUG(dev, "\n");
+ /* remove channel from playlist, will context switch if active */
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ nv_mask(dev, 0x002600 + (chan->id * 4), 0x80000000, 0x00000000);
+ nv50_fifo_playlist_update(dev);
- if (pfifo->playlist[0]) {
- pfifo->cur_playlist = !pfifo->cur_playlist;
- goto just_reset;
- }
+ /* tell any engines on this channel to unload their contexts */
+ nv50_fifo_kickoff(chan);
- ret = nouveau_gpuobj_new(dev, NULL, 128*4, 0x1000,
- NVOBJ_FLAG_ZERO_ALLOC,
- &pfifo->playlist[0]);
- if (ret) {
- NV_ERROR(dev, "error creating playlist 0: %d\n", ret);
- return ret;
- }
+ nv_wr32(dev, 0x002600 + (chan->id * 4), 0x00000000);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
- ret = nouveau_gpuobj_new(dev, NULL, 128*4, 0x1000,
- NVOBJ_FLAG_ZERO_ALLOC,
- &pfifo->playlist[1]);
- if (ret) {
- nouveau_gpuobj_ref(NULL, &pfifo->playlist[0]);
- NV_ERROR(dev, "error creating playlist 1: %d\n", ret);
- return ret;
+ /* clean up */
+ if (chan->user) {
+ iounmap(chan->user);
+ chan->user = NULL;
}
-just_reset:
- nv50_fifo_init_reset(dev);
- nv50_fifo_init_intr(dev);
- nv50_fifo_init_context_table(dev);
- nv50_fifo_init_regs__nv(dev);
- nv50_fifo_init_regs(dev);
- dev_priv->engine.fifo.enable(dev);
- dev_priv->engine.fifo.reassign(dev, true);
-
- return 0;
+ atomic_dec(&chan->vm->engref[engine]);
+ chan->engctx[engine] = NULL;
+ kfree(fctx);
}
-void
-nv50_fifo_takedown(struct drm_device *dev)
+static int
+nv50_fifo_init(struct drm_device *dev, int engine)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+ u32 instance;
+ int i;
- NV_DEBUG(dev, "\n");
+ nv_mask(dev, 0x000200, 0x00000100, 0x00000000);
+ nv_mask(dev, 0x000200, 0x00000100, 0x00000100);
+ nv_wr32(dev, 0x00250c, 0x6f3cfc34);
+ nv_wr32(dev, 0x002044, 0x01003fff);
- if (!pfifo->playlist[0])
- return;
+ nv_wr32(dev, 0x002100, 0xffffffff);
+ nv_wr32(dev, 0x002140, 0xffffffff);
- nv_wr32(dev, 0x2140, 0x00000000);
- nouveau_irq_unregister(dev, 8);
+ for (i = 0; i < 128; i++) {
+ struct nouveau_channel *chan = dev_priv->channels.ptr[i];
+ if (chan && chan->engctx[engine])
+ instance = 0x80000000 | chan->ramin->vinst >> 12;
+ else
+ instance = 0x00000000;
+ nv_wr32(dev, 0x002600 + (i * 4), instance);
+ }
- nouveau_gpuobj_ref(NULL, &pfifo->playlist[0]);
- nouveau_gpuobj_ref(NULL, &pfifo->playlist[1]);
-}
+ nv50_fifo_playlist_update(dev);
-int
-nv50_fifo_channel_id(struct drm_device *dev)
-{
- return nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH1) &
- NV50_PFIFO_CACHE1_PUSH1_CHID_MASK;
+ nv_wr32(dev, 0x003200, 1);
+ nv_wr32(dev, 0x003250, 1);
+ nv_wr32(dev, 0x002500, 1);
+ return 0;
}
-int
-nv50_fifo_create_context(struct nouveau_channel *chan)
+static int
+nv50_fifo_fini(struct drm_device *dev, int engine, bool suspend)
{
- struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_gpuobj *ramfc = NULL;
- uint64_t ib_offset = chan->pushbuf_base + chan->dma.ib_base * 4;
- unsigned long flags;
- int ret;
-
- NV_DEBUG(dev, "ch%d\n", chan->id);
-
- if (dev_priv->chipset == 0x50) {
- ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst,
- chan->ramin->vinst, 0x100,
- NVOBJ_FLAG_ZERO_ALLOC |
- NVOBJ_FLAG_ZERO_FREE,
- &chan->ramfc);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst + 0x0400,
- chan->ramin->vinst + 0x0400,
- 4096, 0, &chan->cache);
- if (ret)
- return ret;
- } else {
- ret = nouveau_gpuobj_new(dev, chan, 0x100, 256,
- NVOBJ_FLAG_ZERO_ALLOC |
- NVOBJ_FLAG_ZERO_FREE, &chan->ramfc);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(dev, chan, 4096, 1024,
- 0, &chan->cache);
- if (ret)
- return ret;
- }
- ramfc = chan->ramfc;
+ struct nv50_fifo_priv *priv = nv_engine(dev, engine);
+ int i;
- chan->user = ioremap(pci_resource_start(dev->pdev, 0) +
- NV50_USER(chan->id), PAGE_SIZE);
- if (!chan->user)
- return -ENOMEM;
+ /* set playlist length to zero, fifo will unload context */
+ nv_wr32(dev, 0x0032ec, 0);
- spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-
- nv_wo32(ramfc, 0x48, chan->pushbuf->cinst >> 4);
- nv_wo32(ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
- (4 << 24) /* SEARCH_FULL */ |
- (chan->ramht->gpuobj->cinst >> 4));
- nv_wo32(ramfc, 0x44, 0x01003fff);
- nv_wo32(ramfc, 0x60, 0x7fffffff);
- nv_wo32(ramfc, 0x40, 0x00000000);
- nv_wo32(ramfc, 0x7c, 0x30000001);
- nv_wo32(ramfc, 0x78, 0x00000000);
- nv_wo32(ramfc, 0x3c, 0x403f6078);
- nv_wo32(ramfc, 0x50, lower_32_bits(ib_offset));
- nv_wo32(ramfc, 0x54, upper_32_bits(ib_offset) |
- drm_order(chan->dma.ib_max + 1) << 16);
-
- if (dev_priv->chipset != 0x50) {
- nv_wo32(chan->ramin, 0, chan->id);
- nv_wo32(chan->ramin, 4, chan->ramfc->vinst >> 8);
-
- nv_wo32(ramfc, 0x88, chan->cache->vinst >> 10);
- nv_wo32(ramfc, 0x98, chan->ramin->vinst >> 12);
+ /* tell all connected engines to unload their contexts */
+ for (i = 0; i < priv->base.channels; i++) {
+ struct nouveau_channel *chan = dev_priv->channels.ptr[i];
+ if (chan && !nv50_fifo_kickoff(chan))
+ return -EBUSY;
}
- dev_priv->engine.instmem.flush(dev);
-
- nv50_fifo_channel_enable(dev, chan->id);
- nv50_fifo_playlist_update(dev);
- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+ nv_wr32(dev, 0x002140, 0);
return 0;
}
void
-nv50_fifo_destroy_context(struct nouveau_channel *chan)
+nv50_fifo_tlb_flush(struct drm_device *dev, int engine)
{
- struct drm_device *dev = chan->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- struct nouveau_gpuobj *ramfc = NULL;
- unsigned long flags;
-
- NV_DEBUG(dev, "ch%d\n", chan->id);
-
- spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
- pfifo->reassign(dev, false);
-
- /* Unload the context if it's the currently active one */
- if (pfifo->channel_id(dev) == chan->id) {
- pfifo->disable(dev);
- pfifo->unload_context(dev);
- pfifo->enable(dev);
- }
-
- /* This will ensure the channel is seen as disabled. */
- nouveau_gpuobj_ref(chan->ramfc, &ramfc);
- nouveau_gpuobj_ref(NULL, &chan->ramfc);
- nv50_fifo_channel_disable(dev, chan->id);
-
- /* Dummy channel, also used on ch 127 */
- if (chan->id == 0)
- nv50_fifo_channel_disable(dev, 127);
- nv50_fifo_playlist_update(dev);
-
- pfifo->reassign(dev, true);
- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
- /* Free the channel resources */
- if (chan->user) {
- iounmap(chan->user);
- chan->user = NULL;
- }
- nouveau_gpuobj_ref(NULL, &ramfc);
- nouveau_gpuobj_ref(NULL, &chan->cache);
+ nv50_vm_flush_engine(dev, 5);
}
-int
-nv50_fifo_load_context(struct nouveau_channel *chan)
+void
+nv50_fifo_destroy(struct drm_device *dev, int engine)
{
- struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_gpuobj *ramfc = chan->ramfc;
- struct nouveau_gpuobj *cache = chan->cache;
- int ptr, cnt;
-
- NV_DEBUG(dev, "ch%d\n", chan->id);
-
- nv_wr32(dev, 0x3330, nv_ro32(ramfc, 0x00));
- nv_wr32(dev, 0x3334, nv_ro32(ramfc, 0x04));
- nv_wr32(dev, 0x3240, nv_ro32(ramfc, 0x08));
- nv_wr32(dev, 0x3320, nv_ro32(ramfc, 0x0c));
- nv_wr32(dev, 0x3244, nv_ro32(ramfc, 0x10));
- nv_wr32(dev, 0x3328, nv_ro32(ramfc, 0x14));
- nv_wr32(dev, 0x3368, nv_ro32(ramfc, 0x18));
- nv_wr32(dev, 0x336c, nv_ro32(ramfc, 0x1c));
- nv_wr32(dev, 0x3370, nv_ro32(ramfc, 0x20));
- nv_wr32(dev, 0x3374, nv_ro32(ramfc, 0x24));
- nv_wr32(dev, 0x3378, nv_ro32(ramfc, 0x28));
- nv_wr32(dev, 0x337c, nv_ro32(ramfc, 0x2c));
- nv_wr32(dev, 0x3228, nv_ro32(ramfc, 0x30));
- nv_wr32(dev, 0x3364, nv_ro32(ramfc, 0x34));
- nv_wr32(dev, 0x32a0, nv_ro32(ramfc, 0x38));
- nv_wr32(dev, 0x3224, nv_ro32(ramfc, 0x3c));
- nv_wr32(dev, 0x324c, nv_ro32(ramfc, 0x40));
- nv_wr32(dev, 0x2044, nv_ro32(ramfc, 0x44));
- nv_wr32(dev, 0x322c, nv_ro32(ramfc, 0x48));
- nv_wr32(dev, 0x3234, nv_ro32(ramfc, 0x4c));
- nv_wr32(dev, 0x3340, nv_ro32(ramfc, 0x50));
- nv_wr32(dev, 0x3344, nv_ro32(ramfc, 0x54));
- nv_wr32(dev, 0x3280, nv_ro32(ramfc, 0x58));
- nv_wr32(dev, 0x3254, nv_ro32(ramfc, 0x5c));
- nv_wr32(dev, 0x3260, nv_ro32(ramfc, 0x60));
- nv_wr32(dev, 0x3264, nv_ro32(ramfc, 0x64));
- nv_wr32(dev, 0x3268, nv_ro32(ramfc, 0x68));
- nv_wr32(dev, 0x326c, nv_ro32(ramfc, 0x6c));
- nv_wr32(dev, 0x32e4, nv_ro32(ramfc, 0x70));
- nv_wr32(dev, 0x3248, nv_ro32(ramfc, 0x74));
- nv_wr32(dev, 0x2088, nv_ro32(ramfc, 0x78));
- nv_wr32(dev, 0x2058, nv_ro32(ramfc, 0x7c));
- nv_wr32(dev, 0x2210, nv_ro32(ramfc, 0x80));
-
- cnt = nv_ro32(ramfc, 0x84);
- for (ptr = 0; ptr < cnt; ptr++) {
- nv_wr32(dev, NV40_PFIFO_CACHE1_METHOD(ptr),
- nv_ro32(cache, (ptr * 8) + 0));
- nv_wr32(dev, NV40_PFIFO_CACHE1_DATA(ptr),
- nv_ro32(cache, (ptr * 8) + 4));
- }
- nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, cnt << 2);
- nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
-
- /* guessing that all the 0x34xx regs aren't on NV50 */
- if (dev_priv->chipset != 0x50) {
- nv_wr32(dev, 0x340c, nv_ro32(ramfc, 0x88));
- nv_wr32(dev, 0x3400, nv_ro32(ramfc, 0x8c));
- nv_wr32(dev, 0x3404, nv_ro32(ramfc, 0x90));
- nv_wr32(dev, 0x3408, nv_ro32(ramfc, 0x94));
- nv_wr32(dev, 0x3410, nv_ro32(ramfc, 0x98));
- }
+ struct nv50_fifo_priv *priv = nv_engine(dev, engine);
- nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, chan->id | (1<<16));
- return 0;
+ nouveau_irq_unregister(dev, 8);
+
+ nouveau_gpuobj_ref(NULL, &priv->playlist[0]);
+ nouveau_gpuobj_ref(NULL, &priv->playlist[1]);
+
+ dev_priv->eng[engine] = NULL;
+ kfree(priv);
}
int
-nv50_fifo_unload_context(struct drm_device *dev)
+nv50_fifo_create(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- struct nouveau_gpuobj *ramfc, *cache;
- struct nouveau_channel *chan = NULL;
- int chid, get, put, ptr;
-
- NV_DEBUG(dev, "\n");
-
- chid = pfifo->channel_id(dev);
- if (chid < 1 || chid >= dev_priv->engine.fifo.channels - 1)
- return 0;
-
- chan = dev_priv->channels.ptr[chid];
- if (!chan) {
- NV_ERROR(dev, "Inactive channel on PFIFO: %d\n", chid);
- return -EINVAL;
- }
- NV_DEBUG(dev, "ch%d\n", chan->id);
- ramfc = chan->ramfc;
- cache = chan->cache;
-
- nv_wo32(ramfc, 0x00, nv_rd32(dev, 0x3330));
- nv_wo32(ramfc, 0x04, nv_rd32(dev, 0x3334));
- nv_wo32(ramfc, 0x08, nv_rd32(dev, 0x3240));
- nv_wo32(ramfc, 0x0c, nv_rd32(dev, 0x3320));
- nv_wo32(ramfc, 0x10, nv_rd32(dev, 0x3244));
- nv_wo32(ramfc, 0x14, nv_rd32(dev, 0x3328));
- nv_wo32(ramfc, 0x18, nv_rd32(dev, 0x3368));
- nv_wo32(ramfc, 0x1c, nv_rd32(dev, 0x336c));
- nv_wo32(ramfc, 0x20, nv_rd32(dev, 0x3370));
- nv_wo32(ramfc, 0x24, nv_rd32(dev, 0x3374));
- nv_wo32(ramfc, 0x28, nv_rd32(dev, 0x3378));
- nv_wo32(ramfc, 0x2c, nv_rd32(dev, 0x337c));
- nv_wo32(ramfc, 0x30, nv_rd32(dev, 0x3228));
- nv_wo32(ramfc, 0x34, nv_rd32(dev, 0x3364));
- nv_wo32(ramfc, 0x38, nv_rd32(dev, 0x32a0));
- nv_wo32(ramfc, 0x3c, nv_rd32(dev, 0x3224));
- nv_wo32(ramfc, 0x40, nv_rd32(dev, 0x324c));
- nv_wo32(ramfc, 0x44, nv_rd32(dev, 0x2044));
- nv_wo32(ramfc, 0x48, nv_rd32(dev, 0x322c));
- nv_wo32(ramfc, 0x4c, nv_rd32(dev, 0x3234));
- nv_wo32(ramfc, 0x50, nv_rd32(dev, 0x3340));
- nv_wo32(ramfc, 0x54, nv_rd32(dev, 0x3344));
- nv_wo32(ramfc, 0x58, nv_rd32(dev, 0x3280));
- nv_wo32(ramfc, 0x5c, nv_rd32(dev, 0x3254));
- nv_wo32(ramfc, 0x60, nv_rd32(dev, 0x3260));
- nv_wo32(ramfc, 0x64, nv_rd32(dev, 0x3264));
- nv_wo32(ramfc, 0x68, nv_rd32(dev, 0x3268));
- nv_wo32(ramfc, 0x6c, nv_rd32(dev, 0x326c));
- nv_wo32(ramfc, 0x70, nv_rd32(dev, 0x32e4));
- nv_wo32(ramfc, 0x74, nv_rd32(dev, 0x3248));
- nv_wo32(ramfc, 0x78, nv_rd32(dev, 0x2088));
- nv_wo32(ramfc, 0x7c, nv_rd32(dev, 0x2058));
- nv_wo32(ramfc, 0x80, nv_rd32(dev, 0x2210));
-
- put = (nv_rd32(dev, NV03_PFIFO_CACHE1_PUT) & 0x7ff) >> 2;
- get = (nv_rd32(dev, NV03_PFIFO_CACHE1_GET) & 0x7ff) >> 2;
- ptr = 0;
- while (put != get) {
- nv_wo32(cache, ptr + 0,
- nv_rd32(dev, NV40_PFIFO_CACHE1_METHOD(get)));
- nv_wo32(cache, ptr + 4,
- nv_rd32(dev, NV40_PFIFO_CACHE1_DATA(get)));
- get = (get + 1) & 0x1ff;
- ptr += 8;
- }
-
- /* guessing that all the 0x34xx regs aren't on NV50 */
- if (dev_priv->chipset != 0x50) {
- nv_wo32(ramfc, 0x84, ptr >> 3);
- nv_wo32(ramfc, 0x88, nv_rd32(dev, 0x340c));
- nv_wo32(ramfc, 0x8c, nv_rd32(dev, 0x3400));
- nv_wo32(ramfc, 0x90, nv_rd32(dev, 0x3404));
- nv_wo32(ramfc, 0x94, nv_rd32(dev, 0x3408));
- nv_wo32(ramfc, 0x98, nv_rd32(dev, 0x3410));
- }
+ struct nv50_fifo_priv *priv;
+ int ret;
- dev_priv->engine.instmem.flush(dev);
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
- /*XXX: probably reload ch127 (NULL) state back too */
- nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1, 127);
- return 0;
-}
+ priv->base.base.destroy = nv50_fifo_destroy;
+ priv->base.base.init = nv50_fifo_init;
+ priv->base.base.fini = nv50_fifo_fini;
+ priv->base.base.context_new = nv50_fifo_context_new;
+ priv->base.base.context_del = nv50_fifo_context_del;
+ priv->base.base.tlb_flush = nv50_fifo_tlb_flush;
+ priv->base.channels = 127;
+ dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
+
+ ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 4, 0x1000,
+ NVOBJ_FLAG_ZERO_ALLOC, &priv->playlist[0]);
+ if (ret)
+ goto error;
+
+ ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 4, 0x1000,
+ NVOBJ_FLAG_ZERO_ALLOC, &priv->playlist[1]);
+ if (ret)
+ goto error;
-void
-nv50_fifo_tlb_flush(struct drm_device *dev)
-{
- nv50_vm_flush_engine(dev, 5);
+ nouveau_irq_register(dev, 8, nv04_fifo_isr);
+error:
+ if (ret)
+ priv->base.base.destroy(dev, NVOBJ_ENGINE_FIFO);
+ return ret;
}
diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c
index 33d5711a918d..d9cc2f2638d6 100644
--- a/drivers/gpu/drm/nouveau/nv50_graph.c
+++ b/drivers/gpu/drm/nouveau/nv50_graph.c
@@ -27,8 +27,8 @@
#include "drmP.h"
#include "drm.h"
#include "nouveau_drv.h"
+#include "nouveau_fifo.h"
#include "nouveau_ramht.h"
-#include "nouveau_grctx.h"
#include "nouveau_dma.h"
#include "nouveau_vm.h"
#include "nv50_evo.h"
@@ -40,86 +40,6 @@ struct nv50_graph_engine {
u32 grctx_size;
};
-static void
-nv50_graph_fifo_access(struct drm_device *dev, bool enabled)
-{
- const uint32_t mask = 0x00010001;
-
- if (enabled)
- nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) | mask);
- else
- nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) & ~mask);
-}
-
-static struct nouveau_channel *
-nv50_graph_channel(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t inst;
- int i;
-
- /* Be sure we're not in the middle of a context switch or bad things
- * will happen, such as unloading the wrong pgraph context.
- */
- if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000))
- NV_ERROR(dev, "Ctxprog is still running\n");
-
- inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
- if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
- return NULL;
- inst = (inst & NV50_PGRAPH_CTXCTL_CUR_INSTANCE) << 12;
-
- for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
- struct nouveau_channel *chan = dev_priv->channels.ptr[i];
-
- if (chan && chan->ramin && chan->ramin->vinst == inst)
- return chan;
- }
-
- return NULL;
-}
-
-static int
-nv50_graph_do_load_context(struct drm_device *dev, uint32_t inst)
-{
- uint32_t fifo = nv_rd32(dev, 0x400500);
-
- nv_wr32(dev, 0x400500, fifo & ~1);
- nv_wr32(dev, 0x400784, inst);
- nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x40);
- nv_wr32(dev, 0x400320, nv_rd32(dev, 0x400320) | 0x11);
- nv_wr32(dev, 0x400040, 0xffffffff);
- (void)nv_rd32(dev, 0x400040);
- nv_wr32(dev, 0x400040, 0x00000000);
- nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 1);
-
- if (nouveau_wait_for_idle(dev))
- nv_wr32(dev, 0x40032c, inst | (1<<31));
- nv_wr32(dev, 0x400500, fifo);
-
- return 0;
-}
-
-static int
-nv50_graph_unload_context(struct drm_device *dev)
-{
- uint32_t inst;
-
- inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
- if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
- return 0;
- inst &= NV50_PGRAPH_CTXCTL_CUR_INSTANCE;
-
- nouveau_wait_for_idle(dev);
- nv_wr32(dev, 0x400784, inst);
- nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x20);
- nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 0x01);
- nouveau_wait_for_idle(dev);
-
- nv_wr32(dev, NV50_PGRAPH_CTXCTL_CUR, inst);
- return 0;
-}
-
static int
nv50_graph_init(struct drm_device *dev, int engine)
{
@@ -211,12 +131,6 @@ nv50_graph_init(struct drm_device *dev, int engine)
static int
nv50_graph_fini(struct drm_device *dev, int engine, bool suspend)
{
- nv_mask(dev, 0x400500, 0x00010001, 0x00000000);
- if (!nv_wait(dev, 0x400700, ~0, 0) && suspend) {
- nv_mask(dev, 0x400500, 0x00010001, 0x00010001);
- return -EBUSY;
- }
- nv50_graph_unload_context(dev);
nv_wr32(dev, 0x40013c, 0x00000000);
return 0;
}
@@ -229,7 +143,6 @@ nv50_graph_context_new(struct nouveau_channel *chan, int engine)
struct nouveau_gpuobj *ramin = chan->ramin;
struct nouveau_gpuobj *grctx = NULL;
struct nv50_graph_engine *pgraph = nv_engine(dev, engine);
- struct nouveau_grctx ctx = {};
int hdr, ret;
NV_DEBUG(dev, "ch%d\n", chan->id);
@@ -248,11 +161,7 @@ nv50_graph_context_new(struct nouveau_channel *chan, int engine)
nv_wo32(ramin, hdr + 0x10, 0);
nv_wo32(ramin, hdr + 0x14, 0x00010000);
- ctx.dev = chan->dev;
- ctx.mode = NOUVEAU_GRCTX_VALS;
- ctx.data = grctx;
- nv50_grctx_init(&ctx);
-
+ nv50_grctx_fill(dev, grctx);
nv_wo32(grctx, 0x00000, chan->ramin->vinst >> 12);
dev_priv->engine.instmem.flush(dev);
@@ -268,33 +177,14 @@ nv50_graph_context_del(struct nouveau_channel *chan, int engine)
struct nouveau_gpuobj *grctx = chan->engctx[engine];
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
- unsigned long flags;
-
- NV_DEBUG(dev, "ch%d\n", chan->id);
-
- if (!chan->ramin)
- return;
-
- spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
- pfifo->reassign(dev, false);
- nv50_graph_fifo_access(dev, false);
-
- if (nv50_graph_channel(dev) == chan)
- nv50_graph_unload_context(dev);
for (i = hdr; i < hdr + 24; i += 4)
nv_wo32(chan->ramin, i, 0);
dev_priv->engine.instmem.flush(dev);
- nv50_graph_fifo_access(dev, true);
- pfifo->reassign(dev, true);
- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
- nouveau_gpuobj_ref(NULL, &grctx);
-
atomic_dec(&chan->vm->engref[engine]);
+ nouveau_gpuobj_ref(NULL, &grctx);
chan->engctx[engine] = NULL;
}
@@ -325,85 +215,6 @@ nv50_graph_object_new(struct nouveau_channel *chan, int engine,
}
static void
-nv50_graph_context_switch(struct drm_device *dev)
-{
- uint32_t inst;
-
- nv50_graph_unload_context(dev);
-
- inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_NEXT);
- inst &= NV50_PGRAPH_CTXCTL_NEXT_INSTANCE;
- nv50_graph_do_load_context(dev, inst);
-
- nv_wr32(dev, NV40_PGRAPH_INTR_EN, nv_rd32(dev,
- NV40_PGRAPH_INTR_EN) | NV_PGRAPH_INTR_CONTEXT_SWITCH);
-}
-
-static int
-nv50_graph_nvsw_dma_vblsem(struct nouveau_channel *chan,
- u32 class, u32 mthd, u32 data)
-{
- struct nouveau_gpuobj *gpuobj;
-
- gpuobj = nouveau_ramht_find(chan, data);
- if (!gpuobj)
- return -ENOENT;
-
- if (nouveau_notifier_offset(gpuobj, NULL))
- return -EINVAL;
-
- chan->nvsw.vblsem = gpuobj;
- chan->nvsw.vblsem_offset = ~0;
- return 0;
-}
-
-static int
-nv50_graph_nvsw_vblsem_offset(struct nouveau_channel *chan,
- u32 class, u32 mthd, u32 data)
-{
- if (nouveau_notifier_offset(chan->nvsw.vblsem, &data))
- return -ERANGE;
-
- chan->nvsw.vblsem_offset = data >> 2;
- return 0;
-}
-
-static int
-nv50_graph_nvsw_vblsem_release_val(struct nouveau_channel *chan,
- u32 class, u32 mthd, u32 data)
-{
- chan->nvsw.vblsem_rval = data;
- return 0;
-}
-
-static int
-nv50_graph_nvsw_vblsem_release(struct nouveau_channel *chan,
- u32 class, u32 mthd, u32 data)
-{
- struct drm_device *dev = chan->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- if (!chan->nvsw.vblsem || chan->nvsw.vblsem_offset == ~0 || data > 1)
- return -EINVAL;
-
- drm_vblank_get(dev, data);
-
- chan->nvsw.vblsem_head = data;
- list_add(&chan->nvsw.vbl_wait, &dev_priv->vbl_waiting);
-
- return 0;
-}
-
-static int
-nv50_graph_nvsw_mthd_page_flip(struct nouveau_channel *chan,
- u32 class, u32 mthd, u32 data)
-{
- nouveau_finish_page_flip(chan, NULL);
- return 0;
-}
-
-
-static void
nv50_graph_tlb_flush(struct drm_device *dev, int engine)
{
nv50_vm_flush_engine(dev, 0);
@@ -514,6 +325,7 @@ struct nouveau_enum nv50_data_error_names[] = {
{ 0x0000001f, "RT_BPP128_WITH_MS8", NULL },
{ 0x00000021, "Z_OUT_OF_BOUNDS", NULL },
{ 0x00000023, "XY_OUT_OF_BOUNDS", NULL },
+ { 0x00000024, "VP_ZERO_INPUTS", NULL },
{ 0x00000027, "CP_MORE_PARAMS_THAN_SHARED", NULL },
{ 0x00000028, "CP_NO_REG_SPACE_STRIPED", NULL },
{ 0x00000029, "CP_NO_REG_SPACE_PACKED", NULL },
@@ -900,13 +712,14 @@ nv50_pgraph_trap_handler(struct drm_device *dev, u32 display, u64 inst, u32 chid
int
nv50_graph_isr_chid(struct drm_device *dev, u64 inst)
{
+ struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan;
unsigned long flags;
int i;
spin_lock_irqsave(&dev_priv->channels.lock, flags);
- for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
+ for (i = 0; i < pfifo->channels; i++) {
chan = dev_priv->channels.ptr[i];
if (!chan || !chan->ramin)
continue;
@@ -939,15 +752,6 @@ nv50_graph_isr(struct drm_device *dev)
show &= ~0x00000010;
}
- if (stat & 0x00001000) {
- nv_wr32(dev, 0x400500, 0x00000000);
- nv_wr32(dev, 0x400100, 0x00001000);
- nv_mask(dev, 0x40013c, 0x00001000, 0x00000000);
- nv50_graph_context_switch(dev);
- stat &= ~0x00001000;
- show &= ~0x00001000;
- }
-
show = (show && nouveau_ratelimit()) ? show : 0;
if (show & 0x00100000) {
@@ -996,28 +800,21 @@ nv50_graph_create(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv50_graph_engine *pgraph;
- struct nouveau_grctx ctx = {};
int ret;
pgraph = kzalloc(sizeof(*pgraph),GFP_KERNEL);
if (!pgraph)
return -ENOMEM;
- ctx.dev = dev;
- ctx.mode = NOUVEAU_GRCTX_PROG;
- ctx.data = pgraph->ctxprog;
- ctx.ctxprog_max = ARRAY_SIZE(pgraph->ctxprog);
-
- ret = nv50_grctx_init(&ctx);
+ ret = nv50_grctx_init(dev, pgraph->ctxprog, ARRAY_SIZE(pgraph->ctxprog),
+ &pgraph->ctxprog_size,
+ &pgraph->grctx_size);
if (ret) {
NV_ERROR(dev, "PGRAPH: ctxprog build failed\n");
kfree(pgraph);
return 0;
}
- pgraph->grctx_size = ctx.ctxvals_pos * 4;
- pgraph->ctxprog_size = ctx.ctxprog_len;
-
pgraph->base.destroy = nv50_graph_destroy;
pgraph->base.init = nv50_graph_init;
pgraph->base.fini = nv50_graph_fini;
@@ -1031,14 +828,6 @@ nv50_graph_create(struct drm_device *dev)
nouveau_irq_register(dev, 12, nv50_graph_isr);
- /* NVSW really doesn't live here... */
- NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
- NVOBJ_MTHD (dev, 0x506e, 0x018c, nv50_graph_nvsw_dma_vblsem);
- NVOBJ_MTHD (dev, 0x506e, 0x0400, nv50_graph_nvsw_vblsem_offset);
- NVOBJ_MTHD (dev, 0x506e, 0x0404, nv50_graph_nvsw_vblsem_release_val);
- NVOBJ_MTHD (dev, 0x506e, 0x0408, nv50_graph_nvsw_vblsem_release);
- NVOBJ_MTHD (dev, 0x506e, 0x0500, nv50_graph_nvsw_mthd_page_flip);
-
NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
NVOBJ_CLASS(dev, 0x0030, GR); /* null */
NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */
diff --git a/drivers/gpu/drm/nouveau/nv50_grctx.c b/drivers/gpu/drm/nouveau/nv50_grctx.c
index 4b46d6968566..881e22b249fc 100644
--- a/drivers/gpu/drm/nouveau/nv50_grctx.c
+++ b/drivers/gpu/drm/nouveau/nv50_grctx.c
@@ -172,8 +172,8 @@ static void nv50_graph_construct_xfer2(struct nouveau_grctx *ctx);
/* Main function: construct the ctxprog skeleton, call the other functions. */
-int
-nv50_grctx_init(struct nouveau_grctx *ctx)
+static int
+nv50_grctx_generate(struct nouveau_grctx *ctx)
{
struct drm_nouveau_private *dev_priv = ctx->dev->dev_private;
@@ -210,7 +210,7 @@ nv50_grctx_init(struct nouveau_grctx *ctx)
cp_name(ctx, cp_check_load);
cp_bra (ctx, AUTO_LOAD, PENDING, cp_setup_auto_load);
cp_bra (ctx, USER_LOAD, PENDING, cp_setup_load);
- cp_bra (ctx, ALWAYS, TRUE, cp_exit);
+ cp_bra (ctx, ALWAYS, TRUE, cp_prepare_exit);
/* setup for context load */
cp_name(ctx, cp_setup_auto_load);
@@ -277,6 +277,33 @@ nv50_grctx_init(struct nouveau_grctx *ctx)
return 0;
}
+void
+nv50_grctx_fill(struct drm_device *dev, struct nouveau_gpuobj *mem)
+{
+ nv50_grctx_generate(&(struct nouveau_grctx) {
+ .dev = dev,
+ .mode = NOUVEAU_GRCTX_VALS,
+ .data = mem,
+ });
+}
+
+int
+nv50_grctx_init(struct drm_device *dev, u32 *data, u32 max, u32 *len, u32 *cnt)
+{
+ struct nouveau_grctx ctx = {
+ .dev = dev,
+ .mode = NOUVEAU_GRCTX_PROG,
+ .data = data,
+ .ctxprog_max = max
+ };
+ int ret;
+
+ ret = nv50_grctx_generate(&ctx);
+ *cnt = ctx.ctxvals_pos * 4;
+ *len = ctx.ctxprog_len;
+ return ret;
+}
+
/*
* Constructs MMIO part of ctxprog and ctxvals. Just a matter of knowing which
* registers to save/restore and the default values for them.
diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c
index a7c12c94a5a6..0bba54f11800 100644
--- a/drivers/gpu/drm/nouveau/nv50_instmem.c
+++ b/drivers/gpu/drm/nouveau/nv50_instmem.c
@@ -83,7 +83,7 @@ nv50_channel_new(struct drm_device *dev, u32 size, struct nouveau_vm *vm,
return ret;
}
- ret = drm_mm_init(&chan->ramin_heap, 0x6000, chan->ramin->size);
+ ret = drm_mm_init(&chan->ramin_heap, 0x6000, chan->ramin->size - 0x6000);
if (ret) {
nv50_channel_del(&chan);
return ret;
diff --git a/drivers/gpu/drm/nouveau/nv50_mpeg.c b/drivers/gpu/drm/nouveau/nv50_mpeg.c
index b57a2d180ad2..90e8ed22cfcb 100644
--- a/drivers/gpu/drm/nouveau/nv50_mpeg.c
+++ b/drivers/gpu/drm/nouveau/nv50_mpeg.c
@@ -77,27 +77,13 @@ nv50_mpeg_context_new(struct nouveau_channel *chan, int engine)
static void
nv50_mpeg_context_del(struct nouveau_channel *chan, int engine)
{
- struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
struct nouveau_gpuobj *ctx = chan->engctx[engine];
struct drm_device *dev = chan->dev;
- unsigned long flags;
- u32 inst, i;
-
- if (!chan->ramin)
- return;
-
- inst = chan->ramin->vinst >> 12;
- inst |= 0x80000000;
-
- spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
- nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
- if (nv_rd32(dev, 0x00b318) == inst)
- nv_mask(dev, 0x00b318, 0x80000000, 0x00000000);
- nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+ int i;
for (i = 0x00; i <= 0x14; i += 4)
nv_wo32(chan->ramin, CTX_PTR(dev, i), 0x00000000);
+
nouveau_gpuobj_ref(NULL, &ctx);
chan->engctx[engine] = NULL;
}
@@ -162,7 +148,6 @@ nv50_mpeg_init(struct drm_device *dev, int engine)
static int
nv50_mpeg_fini(struct drm_device *dev, int engine, bool suspend)
{
- /*XXX: context save for s/r */
nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
nv_wr32(dev, 0x00b140, 0x00000000);
return 0;
diff --git a/drivers/gpu/drm/nouveau/nv50_software.c b/drivers/gpu/drm/nouveau/nv50_software.c
new file mode 100644
index 000000000000..114d2517d4a8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv50_software.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+#include "nouveau_ramht.h"
+#include "nouveau_software.h"
+
+#include "nv50_display.h"
+
+struct nv50_software_priv {
+ struct nouveau_software_priv base;
+};
+
+struct nv50_software_chan {
+ struct nouveau_software_chan base;
+ struct {
+ struct nouveau_gpuobj *object;
+ } vblank;
+};
+
+static int
+mthd_dma_vblsem(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
+{
+ struct nv50_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
+ struct nouveau_gpuobj *gpuobj;
+
+ gpuobj = nouveau_ramht_find(chan, data);
+ if (!gpuobj)
+ return -ENOENT;
+
+ if (nouveau_notifier_offset(gpuobj, NULL))
+ return -EINVAL;
+
+ pch->vblank.object = gpuobj;
+ pch->base.vblank.offset = ~0;
+ return 0;
+}
+
+static int
+mthd_vblsem_offset(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
+{
+ struct nv50_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
+
+ if (nouveau_notifier_offset(pch->vblank.object, &data))
+ return -ERANGE;
+
+ pch->base.vblank.offset = data >> 2;
+ return 0;
+}
+
+static int
+mthd_vblsem_value(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
+{
+ struct nv50_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
+ pch->base.vblank.value = data;
+ return 0;
+}
+
+static int
+mthd_vblsem_release(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
+{
+ struct nv50_software_priv *psw = nv_engine(chan->dev, NVOBJ_ENGINE_SW);
+ struct nv50_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
+ struct drm_device *dev = chan->dev;
+
+ if (!pch->vblank.object || pch->base.vblank.offset == ~0 || data > 1)
+ return -EINVAL;
+
+ drm_vblank_get(dev, data);
+
+ pch->base.vblank.head = data;
+ list_add(&pch->base.vblank.list, &psw->base.vblank);
+ return 0;
+}
+
+static int
+mthd_flip(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
+{
+ nouveau_finish_page_flip(chan, NULL);
+ return 0;
+}
+
+static int
+nv50_software_context_new(struct nouveau_channel *chan, int engine)
+{
+ struct nv50_software_priv *psw = nv_engine(chan->dev, NVOBJ_ENGINE_SW);
+ struct nv50_display *pdisp = nv50_display(chan->dev);
+ struct nv50_software_chan *pch;
+ int ret = 0, i;
+
+ pch = kzalloc(sizeof(*pch), GFP_KERNEL);
+ if (!pch)
+ return -ENOMEM;
+
+ nouveau_software_context_new(&pch->base);
+ pch->base.vblank.bo = chan->notifier_bo;
+ chan->engctx[engine] = pch;
+
+ /* dma objects for display sync channel semaphore blocks */
+ for (i = 0; i < chan->dev->mode_config.num_crtc; i++) {
+ struct nv50_display_crtc *dispc = &pdisp->crtc[i];
+ struct nouveau_gpuobj *obj = NULL;
+
+ ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY,
+ dispc->sem.bo->bo.offset, 0x1000,
+ NV_MEM_ACCESS_RW,
+ NV_MEM_TARGET_VRAM, &obj);
+ if (ret)
+ break;
+
+ ret = nouveau_ramht_insert(chan, NvEvoSema0 + i, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
+ }
+
+ if (ret)
+ psw->base.base.context_del(chan, engine);
+ return ret;
+}
+
+static void
+nv50_software_context_del(struct nouveau_channel *chan, int engine)
+{
+ struct nv50_software_chan *pch = chan->engctx[engine];
+ chan->engctx[engine] = NULL;
+ kfree(pch);
+}
+
+static int
+nv50_software_object_new(struct nouveau_channel *chan, int engine,
+ u32 handle, u16 class)
+{
+ struct drm_device *dev = chan->dev;
+ struct nouveau_gpuobj *obj = NULL;
+ int ret;
+
+ ret = nouveau_gpuobj_new(dev, chan, 16, 16, 0, &obj);
+ if (ret)
+ return ret;
+ obj->engine = 0;
+ obj->class = class;
+
+ ret = nouveau_ramht_insert(chan, handle, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
+ return ret;
+}
+
+static int
+nv50_software_init(struct drm_device *dev, int engine)
+{
+ return 0;
+}
+
+static int
+nv50_software_fini(struct drm_device *dev, int engine, bool suspend)
+{
+ return 0;
+}
+
+static void
+nv50_software_destroy(struct drm_device *dev, int engine)
+{
+ struct nv50_software_priv *psw = nv_engine(dev, engine);
+
+ NVOBJ_ENGINE_DEL(dev, SW);
+ kfree(psw);
+}
+
+int
+nv50_software_create(struct drm_device *dev)
+{
+ struct nv50_software_priv *psw = kzalloc(sizeof(*psw), GFP_KERNEL);
+ if (!psw)
+ return -ENOMEM;
+
+ psw->base.base.destroy = nv50_software_destroy;
+ psw->base.base.init = nv50_software_init;
+ psw->base.base.fini = nv50_software_fini;
+ psw->base.base.context_new = nv50_software_context_new;
+ psw->base.base.context_del = nv50_software_context_del;
+ psw->base.base.object_new = nv50_software_object_new;
+ nouveau_software_create(&psw->base);
+
+ NVOBJ_ENGINE_ADD(dev, SW, &psw->base.base);
+ NVOBJ_CLASS(dev, 0x506e, SW);
+ NVOBJ_MTHD (dev, 0x506e, 0x018c, mthd_dma_vblsem);
+ NVOBJ_MTHD (dev, 0x506e, 0x0400, mthd_vblsem_offset);
+ NVOBJ_MTHD (dev, 0x506e, 0x0404, mthd_vblsem_value);
+ NVOBJ_MTHD (dev, 0x506e, 0x0408, mthd_vblsem_release);
+ NVOBJ_MTHD (dev, 0x506e, 0x0500, mthd_flip);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c
index 274640212475..a9514eaa74c1 100644
--- a/drivers/gpu/drm/nouveau/nv50_sor.c
+++ b/drivers/gpu/drm/nouveau/nv50_sor.c
@@ -242,9 +242,9 @@ nv50_sor_disconnect(struct drm_encoder *encoder)
NV_ERROR(dev, "no space while disconnecting SOR\n");
return;
}
- BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1);
+ BEGIN_NV04(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1);
OUT_RING (evo, 0);
- BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1);
+ BEGIN_NV04(evo, 0, NV50_EVO_UPDATE, 1);
OUT_RING (evo, 0);
nouveau_hdmi_mode_set(encoder, NULL);
@@ -430,7 +430,7 @@ nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode,
nv_encoder->crtc = NULL;
return;
}
- BEGIN_RING(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1);
+ BEGIN_NV04(evo, 0, NV50_EVO_SOR(nv_encoder->or, MODE_CTRL), 1);
OUT_RING(evo, mode_ctl);
}
diff --git a/drivers/gpu/drm/nouveau/nv50_vm.c b/drivers/gpu/drm/nouveau/nv50_vm.c
index 44fbac9c7d93..179bb42a635c 100644
--- a/drivers/gpu/drm/nouveau/nv50_vm.c
+++ b/drivers/gpu/drm/nouveau/nv50_vm.c
@@ -147,7 +147,6 @@ nv50_vm_flush(struct nouveau_vm *vm)
{
struct drm_nouveau_private *dev_priv = vm->dev->dev_private;
struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
int i;
pinstmem->flush(vm->dev);
@@ -158,7 +157,6 @@ nv50_vm_flush(struct nouveau_vm *vm)
return;
}
- pfifo->tlb_flush(vm->dev);
for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
if (atomic_read(&vm->engref[i]))
dev_priv->eng[i]->tlb_flush(vm->dev, i);
diff --git a/drivers/gpu/drm/nouveau/nv84_fence.c b/drivers/gpu/drm/nouveau/nv84_fence.c
new file mode 100644
index 000000000000..c2f889b0d340
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv84_fence.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_dma.h"
+#include "nouveau_fifo.h"
+#include "nouveau_ramht.h"
+#include "nouveau_fence.h"
+
+struct nv84_fence_chan {
+ struct nouveau_fence_chan base;
+};
+
+struct nv84_fence_priv {
+ struct nouveau_fence_priv base;
+ struct nouveau_gpuobj *mem;
+};
+
+static int
+nv84_fence_emit(struct nouveau_fence *fence)
+{
+ struct nouveau_channel *chan = fence->channel;
+ int ret = RING_SPACE(chan, 7);
+ if (ret == 0) {
+ BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
+ OUT_RING (chan, NvSema);
+ BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
+ OUT_RING (chan, upper_32_bits(chan->id * 16));
+ OUT_RING (chan, lower_32_bits(chan->id * 16));
+ OUT_RING (chan, fence->sequence);
+ OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG);
+ FIRE_RING (chan);
+ }
+ return ret;
+}
+
+
+static int
+nv84_fence_sync(struct nouveau_fence *fence,
+ struct nouveau_channel *prev, struct nouveau_channel *chan)
+{
+ int ret = RING_SPACE(chan, 7);
+ if (ret == 0) {
+ BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
+ OUT_RING (chan, NvSema);
+ BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
+ OUT_RING (chan, upper_32_bits(prev->id * 16));
+ OUT_RING (chan, lower_32_bits(prev->id * 16));
+ OUT_RING (chan, fence->sequence);
+ OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_GEQUAL);
+ FIRE_RING (chan);
+ }
+ return ret;
+}
+
+static u32
+nv84_fence_read(struct nouveau_channel *chan)
+{
+ struct nv84_fence_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_FENCE);
+ return nv_ro32(priv->mem, chan->id * 16);
+}
+
+static void
+nv84_fence_context_del(struct nouveau_channel *chan, int engine)
+{
+ struct nv84_fence_chan *fctx = chan->engctx[engine];
+ nouveau_fence_context_del(&fctx->base);
+ chan->engctx[engine] = NULL;
+ kfree(fctx);
+}
+
+static int
+nv84_fence_context_new(struct nouveau_channel *chan, int engine)
+{
+ struct nv84_fence_priv *priv = nv_engine(chan->dev, engine);
+ struct nv84_fence_chan *fctx;
+ struct nouveau_gpuobj *obj;
+ int ret;
+
+ fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
+ if (!fctx)
+ return -ENOMEM;
+
+ nouveau_fence_context_new(&fctx->base);
+
+ ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_FROM_MEMORY,
+ priv->mem->vinst, priv->mem->size,
+ NV_MEM_ACCESS_RW,
+ NV_MEM_TARGET_VRAM, &obj);
+ if (ret == 0) {
+ ret = nouveau_ramht_insert(chan, NvSema, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
+ nv_wo32(priv->mem, chan->id * 16, 0x00000000);
+ }
+
+ if (ret)
+ nv84_fence_context_del(chan, engine);
+ return ret;
+}
+
+static int
+nv84_fence_fini(struct drm_device *dev, int engine, bool suspend)
+{
+ return 0;
+}
+
+static int
+nv84_fence_init(struct drm_device *dev, int engine)
+{
+ return 0;
+}
+
+static void
+nv84_fence_destroy(struct drm_device *dev, int engine)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv84_fence_priv *priv = nv_engine(dev, engine);
+
+ nouveau_gpuobj_ref(NULL, &priv->mem);
+ dev_priv->eng[engine] = NULL;
+ kfree(priv);
+}
+
+int
+nv84_fence_create(struct drm_device *dev)
+{
+ struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv84_fence_priv *priv;
+ int ret;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base.engine.destroy = nv84_fence_destroy;
+ priv->base.engine.init = nv84_fence_init;
+ priv->base.engine.fini = nv84_fence_fini;
+ priv->base.engine.context_new = nv84_fence_context_new;
+ priv->base.engine.context_del = nv84_fence_context_del;
+ priv->base.emit = nv84_fence_emit;
+ priv->base.sync = nv84_fence_sync;
+ priv->base.read = nv84_fence_read;
+ dev_priv->eng[NVOBJ_ENGINE_FENCE] = &priv->base.engine;
+
+ ret = nouveau_gpuobj_new(dev, NULL, 16 * pfifo->channels,
+ 0x1000, 0, &priv->mem);
+ if (ret)
+ goto out;
+
+out:
+ if (ret)
+ nv84_fence_destroy(dev, NVOBJ_ENGINE_FENCE);
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nv84_fifo.c b/drivers/gpu/drm/nouveau/nv84_fifo.c
new file mode 100644
index 000000000000..cc82d799fc3b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv84_fifo.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2012 Ben Skeggs.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "nouveau_drv.h"
+#include "nouveau_fifo.h"
+#include "nouveau_ramht.h"
+#include "nouveau_vm.h"
+
+struct nv84_fifo_priv {
+ struct nouveau_fifo_priv base;
+ struct nouveau_gpuobj *playlist[2];
+ int cur_playlist;
+};
+
+struct nv84_fifo_chan {
+ struct nouveau_fifo_chan base;
+ struct nouveau_gpuobj *ramfc;
+ struct nouveau_gpuobj *cache;
+};
+
+static int
+nv84_fifo_context_new(struct nouveau_channel *chan, int engine)
+{
+ struct nv84_fifo_priv *priv = nv_engine(chan->dev, engine);
+ struct nv84_fifo_chan *fctx;
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ u64 ib_offset = chan->pushbuf_base + chan->dma.ib_base * 4;
+ u64 instance;
+ unsigned long flags;
+ int ret;
+
+ fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
+ if (!fctx)
+ return -ENOMEM;
+ atomic_inc(&chan->vm->engref[engine]);
+
+ chan->user = ioremap(pci_resource_start(dev->pdev, 0) +
+ NV50_USER(chan->id), PAGE_SIZE);
+ if (!chan->user) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ret = nouveau_gpuobj_new(dev, chan, 256, 256, NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE, &fctx->ramfc);
+ if (ret)
+ goto error;
+
+ instance = fctx->ramfc->vinst >> 8;
+
+ ret = nouveau_gpuobj_new(dev, chan, 4096, 1024, 0, &fctx->cache);
+ if (ret)
+ goto error;
+
+ nv_wo32(fctx->ramfc, 0x3c, 0x403f6078);
+ nv_wo32(fctx->ramfc, 0x40, 0x00000000);
+ nv_wo32(fctx->ramfc, 0x44, 0x01003fff);
+ nv_wo32(fctx->ramfc, 0x48, chan->pushbuf->cinst >> 4);
+ nv_wo32(fctx->ramfc, 0x50, lower_32_bits(ib_offset));
+ nv_wo32(fctx->ramfc, 0x54, upper_32_bits(ib_offset) |
+ drm_order(chan->dma.ib_max + 1) << 16);
+ nv_wo32(fctx->ramfc, 0x60, 0x7fffffff);
+ nv_wo32(fctx->ramfc, 0x78, 0x00000000);
+ nv_wo32(fctx->ramfc, 0x7c, 0x30000001);
+ nv_wo32(fctx->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
+ (4 << 24) /* SEARCH_FULL */ |
+ (chan->ramht->gpuobj->cinst >> 4));
+ nv_wo32(fctx->ramfc, 0x88, fctx->cache->vinst >> 10);
+ nv_wo32(fctx->ramfc, 0x98, chan->ramin->vinst >> 12);
+
+ nv_wo32(chan->ramin, 0x00, chan->id);
+ nv_wo32(chan->ramin, 0x04, fctx->ramfc->vinst >> 8);
+
+ dev_priv->engine.instmem.flush(dev);
+
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ nv_wr32(dev, 0x002600 + (chan->id * 4), 0x80000000 | instance);
+ nv50_fifo_playlist_update(dev);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+error:
+ if (ret)
+ priv->base.base.context_del(chan, engine);
+ return ret;
+}
+
+static void
+nv84_fifo_context_del(struct nouveau_channel *chan, int engine)
+{
+ struct nv84_fifo_chan *fctx = chan->engctx[engine];
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ unsigned long flags;
+
+ /* remove channel from playlist, will context switch if active */
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ nv_mask(dev, 0x002600 + (chan->id * 4), 0x80000000, 0x00000000);
+ nv50_fifo_playlist_update(dev);
+
+ /* tell any engines on this channel to unload their contexts */
+ nv_wr32(dev, 0x0032fc, chan->ramin->vinst >> 12);
+ if (!nv_wait_ne(dev, 0x0032fc, 0xffffffff, 0xffffffff))
+ NV_INFO(dev, "PFIFO: channel %d unload timeout\n", chan->id);
+
+ nv_wr32(dev, 0x002600 + (chan->id * 4), 0x00000000);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+ /* clean up */
+ if (chan->user) {
+ iounmap(chan->user);
+ chan->user = NULL;
+ }
+
+ nouveau_gpuobj_ref(NULL, &fctx->ramfc);
+ nouveau_gpuobj_ref(NULL, &fctx->cache);
+
+ atomic_dec(&chan->vm->engref[engine]);
+ chan->engctx[engine] = NULL;
+ kfree(fctx);
+}
+
+static int
+nv84_fifo_init(struct drm_device *dev, int engine)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv84_fifo_chan *fctx;
+ u32 instance;
+ int i;
+
+ nv_mask(dev, 0x000200, 0x00000100, 0x00000000);
+ nv_mask(dev, 0x000200, 0x00000100, 0x00000100);
+ nv_wr32(dev, 0x00250c, 0x6f3cfc34);
+ nv_wr32(dev, 0x002044, 0x01003fff);
+
+ nv_wr32(dev, 0x002100, 0xffffffff);
+ nv_wr32(dev, 0x002140, 0xffffffff);
+
+ for (i = 0; i < 128; i++) {
+ struct nouveau_channel *chan = dev_priv->channels.ptr[i];
+ if (chan && (fctx = chan->engctx[engine]))
+ instance = 0x80000000 | fctx->ramfc->vinst >> 8;
+ else
+ instance = 0x00000000;
+ nv_wr32(dev, 0x002600 + (i * 4), instance);
+ }
+
+ nv50_fifo_playlist_update(dev);
+
+ nv_wr32(dev, 0x003200, 1);
+ nv_wr32(dev, 0x003250, 1);
+ nv_wr32(dev, 0x002500, 1);
+ return 0;
+}
+
+static int
+nv84_fifo_fini(struct drm_device *dev, int engine, bool suspend)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv84_fifo_priv *priv = nv_engine(dev, engine);
+ int i;
+
+ /* set playlist length to zero, fifo will unload context */
+ nv_wr32(dev, 0x0032ec, 0);
+
+ /* tell all connected engines to unload their contexts */
+ for (i = 0; i < priv->base.channels; i++) {
+ struct nouveau_channel *chan = dev_priv->channels.ptr[i];
+ if (chan)
+ nv_wr32(dev, 0x0032fc, chan->ramin->vinst >> 12);
+ if (!nv_wait_ne(dev, 0x0032fc, 0xffffffff, 0xffffffff)) {
+ NV_INFO(dev, "PFIFO: channel %d unload timeout\n", i);
+ return -EBUSY;
+ }
+ }
+
+ nv_wr32(dev, 0x002140, 0);
+ return 0;
+}
+
+int
+nv84_fifo_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv84_fifo_priv *priv;
+ int ret;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base.base.destroy = nv50_fifo_destroy;
+ priv->base.base.init = nv84_fifo_init;
+ priv->base.base.fini = nv84_fifo_fini;
+ priv->base.base.context_new = nv84_fifo_context_new;
+ priv->base.base.context_del = nv84_fifo_context_del;
+ priv->base.base.tlb_flush = nv50_fifo_tlb_flush;
+ priv->base.channels = 127;
+ dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
+
+ ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 4, 0x1000,
+ NVOBJ_FLAG_ZERO_ALLOC, &priv->playlist[0]);
+ if (ret)
+ goto error;
+
+ ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 4, 0x1000,
+ NVOBJ_FLAG_ZERO_ALLOC, &priv->playlist[1]);
+ if (ret)
+ goto error;
+
+ nouveau_irq_register(dev, 8, nv04_fifo_isr);
+error:
+ if (ret)
+ priv->base.base.destroy(dev, NVOBJ_ENGINE_FIFO);
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nv98_crypt.c b/drivers/gpu/drm/nouveau/nv98_crypt.c
index db94ff0a9fab..e25e13fb894e 100644
--- a/drivers/gpu/drm/nouveau/nv98_crypt.c
+++ b/drivers/gpu/drm/nouveau/nv98_crypt.c
@@ -23,21 +23,93 @@
*/
#include "drmP.h"
+
#include "nouveau_drv.h"
#include "nouveau_util.h"
#include "nouveau_vm.h"
#include "nouveau_ramht.h"
-struct nv98_crypt_engine {
+#include "nv98_crypt.fuc.h"
+
+struct nv98_crypt_priv {
struct nouveau_exec_engine base;
};
+struct nv98_crypt_chan {
+ struct nouveau_gpuobj *mem;
+};
+
static int
-nv98_crypt_fini(struct drm_device *dev, int engine, bool suspend)
+nv98_crypt_context_new(struct nouveau_channel *chan, int engine)
+{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv98_crypt_priv *priv = nv_engine(dev, engine);
+ struct nv98_crypt_chan *cctx;
+ int ret;
+
+ cctx = chan->engctx[engine] = kzalloc(sizeof(*cctx), GFP_KERNEL);
+ if (!cctx)
+ return -ENOMEM;
+
+ atomic_inc(&chan->vm->engref[engine]);
+
+ ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE, &cctx->mem);
+ if (ret)
+ goto error;
+
+ nv_wo32(chan->ramin, 0xa0, 0x00190000);
+ nv_wo32(chan->ramin, 0xa4, cctx->mem->vinst + cctx->mem->size - 1);
+ nv_wo32(chan->ramin, 0xa8, cctx->mem->vinst);
+ nv_wo32(chan->ramin, 0xac, 0x00000000);
+ nv_wo32(chan->ramin, 0xb0, 0x00000000);
+ nv_wo32(chan->ramin, 0xb4, 0x00000000);
+ dev_priv->engine.instmem.flush(dev);
+
+error:
+ if (ret)
+ priv->base.context_del(chan, engine);
+ return ret;
+}
+
+static void
+nv98_crypt_context_del(struct nouveau_channel *chan, int engine)
+{
+ struct nv98_crypt_chan *cctx = chan->engctx[engine];
+ int i;
+
+ for (i = 0xa0; i < 0xb4; i += 4)
+ nv_wo32(chan->ramin, i, 0x00000000);
+
+ nouveau_gpuobj_ref(NULL, &cctx->mem);
+
+ atomic_dec(&chan->vm->engref[engine]);
+ chan->engctx[engine] = NULL;
+ kfree(cctx);
+}
+
+static int
+nv98_crypt_object_new(struct nouveau_channel *chan, int engine,
+ u32 handle, u16 class)
{
- if (!(nv_rd32(dev, 0x000200) & 0x00004000))
- return 0;
+ struct nv98_crypt_chan *cctx = chan->engctx[engine];
+
+ /* fuc engine doesn't need an object, our ramht code does.. */
+ cctx->mem->engine = 5;
+ cctx->mem->class = class;
+ return nouveau_ramht_insert(chan, handle, cctx->mem);
+}
+static void
+nv98_crypt_tlb_flush(struct drm_device *dev, int engine)
+{
+ nv50_vm_flush_engine(dev, 0x0a);
+}
+
+static int
+nv98_crypt_fini(struct drm_device *dev, int engine, bool suspend)
+{
nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
return 0;
}
@@ -45,34 +117,100 @@ nv98_crypt_fini(struct drm_device *dev, int engine, bool suspend)
static int
nv98_crypt_init(struct drm_device *dev, int engine)
{
+ int i;
+
+ /* reset! */
nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
nv_mask(dev, 0x000200, 0x00004000, 0x00004000);
+
+ /* wait for exit interrupt to signal */
+ nv_wait(dev, 0x087008, 0x00000010, 0x00000010);
+ nv_wr32(dev, 0x087004, 0x00000010);
+
+ /* upload microcode code and data segments */
+ nv_wr32(dev, 0x087ff8, 0x00100000);
+ for (i = 0; i < ARRAY_SIZE(nv98_pcrypt_code); i++)
+ nv_wr32(dev, 0x087ff4, nv98_pcrypt_code[i]);
+
+ nv_wr32(dev, 0x087ff8, 0x00000000);
+ for (i = 0; i < ARRAY_SIZE(nv98_pcrypt_data); i++)
+ nv_wr32(dev, 0x087ff4, nv98_pcrypt_data[i]);
+
+ /* start it running */
+ nv_wr32(dev, 0x08710c, 0x00000000);
+ nv_wr32(dev, 0x087104, 0x00000000); /* ENTRY */
+ nv_wr32(dev, 0x087100, 0x00000002); /* TRIGGER */
return 0;
}
+static struct nouveau_enum nv98_crypt_isr_error_name[] = {
+ { 0x0000, "ILLEGAL_MTHD" },
+ { 0x0001, "INVALID_BITFIELD" },
+ { 0x0002, "INVALID_ENUM" },
+ { 0x0003, "QUERY" },
+ {}
+};
+
+static void
+nv98_crypt_isr(struct drm_device *dev)
+{
+ u32 disp = nv_rd32(dev, 0x08701c);
+ u32 stat = nv_rd32(dev, 0x087008) & disp & ~(disp >> 16);
+ u32 inst = nv_rd32(dev, 0x087050) & 0x3fffffff;
+ u32 ssta = nv_rd32(dev, 0x087040) & 0x0000ffff;
+ u32 addr = nv_rd32(dev, 0x087040) >> 16;
+ u32 mthd = (addr & 0x07ff) << 2;
+ u32 subc = (addr & 0x3800) >> 11;
+ u32 data = nv_rd32(dev, 0x087044);
+ int chid = nv50_graph_isr_chid(dev, inst);
+
+ if (stat & 0x00000040) {
+ NV_INFO(dev, "PCRYPT: DISPATCH_ERROR [");
+ nouveau_enum_print(nv98_crypt_isr_error_name, ssta);
+ printk("] ch %d [0x%08x] subc %d mthd 0x%04x data 0x%08x\n",
+ chid, inst, subc, mthd, data);
+ nv_wr32(dev, 0x087004, 0x00000040);
+ stat &= ~0x00000040;
+ }
+
+ if (stat) {
+ NV_INFO(dev, "PCRYPT: unhandled intr 0x%08x\n", stat);
+ nv_wr32(dev, 0x087004, stat);
+ }
+
+ nv50_fb_vm_trap(dev, 1);
+}
+
static void
nv98_crypt_destroy(struct drm_device *dev, int engine)
{
- struct nv98_crypt_engine *pcrypt = nv_engine(dev, engine);
+ struct nv98_crypt_priv *priv = nv_engine(dev, engine);
+ nouveau_irq_unregister(dev, 14);
NVOBJ_ENGINE_DEL(dev, CRYPT);
-
- kfree(pcrypt);
+ kfree(priv);
}
int
nv98_crypt_create(struct drm_device *dev)
{
- struct nv98_crypt_engine *pcrypt;
+ struct nv98_crypt_priv *priv;
- pcrypt = kzalloc(sizeof(*pcrypt), GFP_KERNEL);
- if (!pcrypt)
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
return -ENOMEM;
- pcrypt->base.destroy = nv98_crypt_destroy;
- pcrypt->base.init = nv98_crypt_init;
- pcrypt->base.fini = nv98_crypt_fini;
+ priv->base.destroy = nv98_crypt_destroy;
+ priv->base.init = nv98_crypt_init;
+ priv->base.fini = nv98_crypt_fini;
+ priv->base.context_new = nv98_crypt_context_new;
+ priv->base.context_del = nv98_crypt_context_del;
+ priv->base.object_new = nv98_crypt_object_new;
+ priv->base.tlb_flush = nv98_crypt_tlb_flush;
+
+ nouveau_irq_register(dev, 14, nv98_crypt_isr);
- NVOBJ_ENGINE_ADD(dev, CRYPT, &pcrypt->base);
+ NVOBJ_ENGINE_ADD(dev, CRYPT, &priv->base);
+ NVOBJ_CLASS(dev, 0x88b4, CRYPT);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nv98_crypt.fuc b/drivers/gpu/drm/nouveau/nv98_crypt.fuc
new file mode 100644
index 000000000000..7393813044de
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv98_crypt.fuc
@@ -0,0 +1,698 @@
+/*
+ * fuc microcode for nv98 pcrypt engine
+ * Copyright (C) 2010 Marcin Kościelnicki
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+.section #nv98_pcrypt_data
+
+ctx_dma:
+ctx_dma_query: .b32 0
+ctx_dma_src: .b32 0
+ctx_dma_dst: .b32 0
+.equ #dma_count 3
+ctx_query_address_high: .b32 0
+ctx_query_address_low: .b32 0
+ctx_query_counter: .b32 0
+ctx_cond_address_high: .b32 0
+ctx_cond_address_low: .b32 0
+ctx_cond_off: .b32 0
+ctx_src_address_high: .b32 0
+ctx_src_address_low: .b32 0
+ctx_dst_address_high: .b32 0
+ctx_dst_address_low: .b32 0
+ctx_mode: .b32 0
+.align 16
+ctx_key: .skip 16
+ctx_iv: .skip 16
+
+.align 0x80
+swap:
+.skip 32
+
+.align 8
+common_cmd_dtable:
+.b32 #ctx_query_address_high + 0x20000 ~0xff
+.b32 #ctx_query_address_low + 0x20000 ~0xfffffff0
+.b32 #ctx_query_counter + 0x20000 ~0xffffffff
+.b32 #cmd_query_get + 0x00000 ~1
+.b32 #ctx_cond_address_high + 0x20000 ~0xff
+.b32 #ctx_cond_address_low + 0x20000 ~0xfffffff0
+.b32 #cmd_cond_mode + 0x00000 ~7
+.b32 #cmd_wrcache_flush + 0x00000 ~0
+.equ #common_cmd_max 0x88
+
+
+.align 8
+engine_cmd_dtable:
+.b32 #ctx_key + 0x0 + 0x20000 ~0xffffffff
+.b32 #ctx_key + 0x4 + 0x20000 ~0xffffffff
+.b32 #ctx_key + 0x8 + 0x20000 ~0xffffffff
+.b32 #ctx_key + 0xc + 0x20000 ~0xffffffff
+.b32 #ctx_iv + 0x0 + 0x20000 ~0xffffffff
+.b32 #ctx_iv + 0x4 + 0x20000 ~0xffffffff
+.b32 #ctx_iv + 0x8 + 0x20000 ~0xffffffff
+.b32 #ctx_iv + 0xc + 0x20000 ~0xffffffff
+.b32 #ctx_src_address_high + 0x20000 ~0xff
+.b32 #ctx_src_address_low + 0x20000 ~0xfffffff0
+.b32 #ctx_dst_address_high + 0x20000 ~0xff
+.b32 #ctx_dst_address_low + 0x20000 ~0xfffffff0
+.b32 #crypt_cmd_mode + 0x00000 ~0xf
+.b32 #crypt_cmd_length + 0x10000 ~0x0ffffff0
+.equ #engine_cmd_max 0xce
+
+.align 4
+crypt_dtable:
+.b16 #crypt_copy_prep #crypt_do_inout
+.b16 #crypt_store_prep #crypt_do_out
+.b16 #crypt_ecb_e_prep #crypt_do_inout
+.b16 #crypt_ecb_d_prep #crypt_do_inout
+.b16 #crypt_cbc_e_prep #crypt_do_inout
+.b16 #crypt_cbc_d_prep #crypt_do_inout
+.b16 #crypt_pcbc_e_prep #crypt_do_inout
+.b16 #crypt_pcbc_d_prep #crypt_do_inout
+.b16 #crypt_cfb_e_prep #crypt_do_inout
+.b16 #crypt_cfb_d_prep #crypt_do_inout
+.b16 #crypt_ofb_prep #crypt_do_inout
+.b16 #crypt_ctr_prep #crypt_do_inout
+.b16 #crypt_cbc_mac_prep #crypt_do_in
+.b16 #crypt_cmac_finish_complete_prep #crypt_do_in
+.b16 #crypt_cmac_finish_partial_prep #crypt_do_in
+
+.align 0x100
+
+.section #nv98_pcrypt_code
+
+ // $r0 is always set to 0 in our code - this allows some space savings.
+ clear b32 $r0
+
+ // set up the interrupt handler
+ mov $r1 #ih
+ mov $iv0 $r1
+
+ // init stack pointer
+ mov $sp $r0
+
+ // set interrupt dispatch - route timer, fifo, ctxswitch to i0, others to host
+ movw $r1 0xfff0
+ sethi $r1 0
+ mov $r2 0x400
+ iowr I[$r2 + 0x300] $r1
+
+ // enable the interrupts
+ or $r1 0xc
+ iowr I[$r2] $r1
+
+ // enable fifo access and context switching
+ mov $r1 3
+ mov $r2 0x1200
+ iowr I[$r2] $r1
+
+ // enable i0 delivery
+ bset $flags ie0
+
+ // sleep forver, waking only for interrupts.
+ bset $flags $p0
+ spin:
+ sleep $p0
+ bra #spin
+
+// i0 handler
+ih:
+ // see which interrupts we got
+ iord $r1 I[$r0 + 0x200]
+
+ and $r2 $r1 0x8
+ cmpu b32 $r2 0
+ bra e #noctx
+
+ // context switch... prepare the regs for xfer
+ mov $r2 0x7700
+ mov $xtargets $r2
+ mov $xdbase $r0
+ // 128-byte context.
+ mov $r2 0
+ sethi $r2 0x50000
+
+ // read current channel
+ mov $r3 0x1400
+ iord $r4 I[$r3]
+ // if bit 30 set, it's active, so we have to unload it first.
+ shl b32 $r5 $r4 1
+ cmps b32 $r5 0
+ bra nc #ctxload
+
+ // unload the current channel - save the context
+ xdst $r0 $r2
+ xdwait
+ // and clear bit 30, then write back
+ bclr $r4 0x1e
+ iowr I[$r3] $r4
+ // tell PFIFO we unloaded
+ mov $r4 1
+ iowr I[$r3 + 0x200] $r4
+
+ bra #noctx
+
+ ctxload:
+ // no channel loaded - perhaps we're requested to load one
+ iord $r4 I[$r3 + 0x100]
+ shl b32 $r15 $r4 1
+ cmps b32 $r15 0
+ // if bit 30 of next channel not set, probably PFIFO is just
+ // killing a context. do a faux load, without the active bit.
+ bra nc #dummyload
+
+ // ok, do a real context load.
+ xdld $r0 $r2
+ xdwait
+ mov $r5 #ctx_dma
+ mov $r6 #dma_count - 1
+ ctxload_dma_loop:
+ ld b32 $r7 D[$r5 + $r6 * 4]
+ add b32 $r8 $r6 0x180
+ shl b32 $r8 8
+ iowr I[$r8] $r7
+ sub b32 $r6 1
+ bra nc #ctxload_dma_loop
+
+ dummyload:
+ // tell PFIFO we're done
+ mov $r5 2
+ iowr I[$r3 + 0x200] $r5
+
+ noctx:
+ and $r2 $r1 0x4
+ cmpu b32 $r2 0
+ bra e #nocmd
+
+ // incoming fifo command.
+ mov $r3 0x1900
+ iord $r2 I[$r3 + 0x100]
+ iord $r3 I[$r3]
+ // extract the method
+ and $r4 $r2 0x7ff
+ // shift the addr to proper position if we need to interrupt later
+ shl b32 $r2 0x10
+
+ // mthd 0 and 0x100 [NAME, NOP]: ignore
+ and $r5 $r4 0x7bf
+ cmpu b32 $r5 0
+ bra e #cmddone
+
+ mov $r5 #engine_cmd_dtable - 0xc0 * 8
+ mov $r6 #engine_cmd_max
+ cmpu b32 $r4 0xc0
+ bra nc #dtable_cmd
+ mov $r5 #common_cmd_dtable - 0x80 * 8
+ mov $r6 #common_cmd_max
+ cmpu b32 $r4 0x80
+ bra nc #dtable_cmd
+ cmpu b32 $r4 0x60
+ bra nc #dma_cmd
+ cmpu b32 $r4 0x50
+ bra ne #illegal_mthd
+
+ // mthd 0x140: PM_TRIGGER
+ mov $r2 0x2200
+ clear b32 $r3
+ sethi $r3 0x20000
+ iowr I[$r2] $r3
+ bra #cmddone
+
+ dma_cmd:
+ // mthd 0x180...: DMA_*
+ cmpu b32 $r4 0x60+#dma_count
+ bra nc #illegal_mthd
+ shl b32 $r5 $r4 2
+ add b32 $r5 (#ctx_dma - 0x60 * 4) & 0xffff
+ bset $r3 0x1e
+ st b32 D[$r5] $r3
+ add b32 $r4 0x180 - 0x60
+ shl b32 $r4 8
+ iowr I[$r4] $r3
+ bra #cmddone
+
+ dtable_cmd:
+ cmpu b32 $r4 $r6
+ bra nc #illegal_mthd
+ shl b32 $r4 3
+ add b32 $r4 $r5
+ ld b32 $r5 D[$r4 + 4]
+ and $r5 $r3
+ cmpu b32 $r5 0
+ bra ne #invalid_bitfield
+ ld b16 $r5 D[$r4]
+ ld b16 $r6 D[$r4 + 2]
+ cmpu b32 $r6 2
+ bra e #cmd_setctx
+ ld b32 $r7 D[$r0 + #ctx_cond_off]
+ and $r6 $r7
+ cmpu b32 $r6 1
+ bra e #cmddone
+ call $r5
+ bra $p1 #dispatch_error
+ bra #cmddone
+
+ cmd_setctx:
+ st b32 D[$r5] $r3
+ bra #cmddone
+
+
+ invalid_bitfield:
+ or $r2 1
+ dispatch_error:
+ illegal_mthd:
+ mov $r4 0x1000
+ iowr I[$r4] $r2
+ iowr I[$r4 + 0x100] $r3
+ mov $r4 0x40
+ iowr I[$r0] $r4
+
+ im_loop:
+ iord $r4 I[$r0 + 0x200]
+ and $r4 0x40
+ cmpu b32 $r4 0
+ bra ne #im_loop
+
+ cmddone:
+ // remove the command from FIFO
+ mov $r3 0x1d00
+ mov $r4 1
+ iowr I[$r3] $r4
+
+ nocmd:
+ // ack the processed interrupts
+ and $r1 $r1 0xc
+ iowr I[$r0 + 0x100] $r1
+iret
+
+cmd_query_get:
+ // if bit 0 of param set, trigger interrupt afterwards.
+ setp $p1 $r3
+ or $r2 3
+
+ // read PTIMER, beware of races...
+ mov $r4 0xb00
+ ptimer_retry:
+ iord $r6 I[$r4 + 0x100]
+ iord $r5 I[$r4]
+ iord $r7 I[$r4 + 0x100]
+ cmpu b32 $r6 $r7
+ bra ne #ptimer_retry
+
+ // prepare the query structure
+ ld b32 $r4 D[$r0 + #ctx_query_counter]
+ st b32 D[$r0 + #swap + 0x0] $r4
+ st b32 D[$r0 + #swap + 0x4] $r0
+ st b32 D[$r0 + #swap + 0x8] $r5
+ st b32 D[$r0 + #swap + 0xc] $r6
+
+ // will use target 0, DMA_QUERY.
+ mov $xtargets $r0
+
+ ld b32 $r4 D[$r0 + #ctx_query_address_high]
+ shl b32 $r4 0x18
+ mov $xdbase $r4
+
+ ld b32 $r4 D[$r0 + #ctx_query_address_low]
+ mov $r5 #swap
+ sethi $r5 0x20000
+ xdst $r4 $r5
+ xdwait
+
+ ret
+
+cmd_cond_mode:
+ // if >= 5, INVALID_ENUM
+ bset $flags $p1
+ or $r2 2
+ cmpu b32 $r3 5
+ bra nc #return
+
+ // otherwise, no error.
+ bclr $flags $p1
+
+ // if < 2, no QUERY object is involved
+ cmpu b32 $r3 2
+ bra nc #cmd_cond_mode_queryful
+
+ xor $r3 1
+ st b32 D[$r0 + #ctx_cond_off] $r3
+ return:
+ ret
+
+ cmd_cond_mode_queryful:
+ // ok, will need to pull a QUERY object, prepare offsets
+ ld b32 $r4 D[$r0 + #ctx_cond_address_high]
+ ld b32 $r5 D[$r0 + #ctx_cond_address_low]
+ and $r6 $r5 0xff
+ shr b32 $r5 8
+ shl b32 $r4 0x18
+ or $r4 $r5
+ mov $xdbase $r4
+ mov $xtargets $r0
+
+ // pull the first one
+ mov $r5 #swap
+ sethi $r5 0x20000
+ xdld $r6 $r5
+
+ // if == 2, only a single QUERY is involved...
+ cmpu b32 $r3 2
+ bra ne #cmd_cond_mode_double
+
+ xdwait
+ ld b32 $r4 D[$r0 + #swap + 4]
+ cmpu b32 $r4 0
+ xbit $r4 $flags z
+ st b32 D[$r0 + #ctx_cond_off] $r4
+ ret
+
+ // ok, we'll need to pull second one too
+ cmd_cond_mode_double:
+ add b32 $r6 0x10
+ add b32 $r5 0x10
+ xdld $r6 $r5
+ xdwait
+
+ // compare COUNTERs
+ ld b32 $r5 D[$r0 + #swap + 0x00]
+ ld b32 $r6 D[$r0 + #swap + 0x10]
+ cmpu b32 $r5 $r6
+ xbit $r4 $flags z
+
+ // compare RESen
+ ld b32 $r5 D[$r0 + #swap + 0x04]
+ ld b32 $r6 D[$r0 + #swap + 0x14]
+ cmpu b32 $r5 $r6
+ xbit $r5 $flags z
+ and $r4 $r5
+
+ // and negate or not, depending on mode
+ cmpu b32 $r3 3
+ xbit $r5 $flags z
+ xor $r4 $r5
+ st b32 D[$r0 + #ctx_cond_off] $r4
+ ret
+
+cmd_wrcache_flush:
+ bclr $flags $p1
+ mov $r2 0x2200
+ clear b32 $r3
+ sethi $r3 0x10000
+ iowr I[$r2] $r3
+ ret
+
+crypt_cmd_mode:
+ // if >= 0xf, INVALID_ENUM
+ bset $flags $p1
+ or $r2 2
+ cmpu b32 $r3 0xf
+ bra nc #crypt_cmd_mode_return
+
+ bclr $flags $p1
+ st b32 D[$r0 + #ctx_mode] $r3
+
+ crypt_cmd_mode_return:
+ ret
+
+crypt_cmd_length:
+ // nop if length == 0
+ cmpu b32 $r3 0
+ bra e #crypt_cmd_mode_return
+
+ // init key, IV
+ cxset 3
+ mov $r4 #ctx_key
+ sethi $r4 0x70000
+ xdst $r0 $r4
+ mov $r4 #ctx_iv
+ sethi $r4 0x60000
+ xdst $r0 $r4
+ xdwait
+ ckeyreg $c7
+
+ // prepare the targets
+ mov $r4 0x2100
+ mov $xtargets $r4
+
+ // prepare src address
+ ld b32 $r4 D[$r0 + #ctx_src_address_high]
+ ld b32 $r5 D[$r0 + #ctx_src_address_low]
+ shr b32 $r8 $r5 8
+ shl b32 $r4 0x18
+ or $r4 $r8
+ and $r5 $r5 0xff
+
+ // prepare dst address
+ ld b32 $r6 D[$r0 + #ctx_dst_address_high]
+ ld b32 $r7 D[$r0 + #ctx_dst_address_low]
+ shr b32 $r8 $r7 8
+ shl b32 $r6 0x18
+ or $r6 $r8
+ and $r7 $r7 0xff
+
+ // find the proper prep & do functions
+ ld b32 $r8 D[$r0 + #ctx_mode]
+ shl b32 $r8 2
+
+ // run prep
+ ld b16 $r9 D[$r8 + #crypt_dtable]
+ call $r9
+
+ // do it
+ ld b16 $r9 D[$r8 + #crypt_dtable + 2]
+ call $r9
+ cxset 1
+ xdwait
+ cxset 0x61
+ xdwait
+ xdwait
+
+ // update src address
+ shr b32 $r8 $r4 0x18
+ shl b32 $r9 $r4 8
+ add b32 $r9 $r5
+ adc b32 $r8 0
+ st b32 D[$r0 + #ctx_src_address_high] $r8
+ st b32 D[$r0 + #ctx_src_address_low] $r9
+
+ // update dst address
+ shr b32 $r8 $r6 0x18
+ shl b32 $r9 $r6 8
+ add b32 $r9 $r7
+ adc b32 $r8 0
+ st b32 D[$r0 + #ctx_dst_address_high] $r8
+ st b32 D[$r0 + #ctx_dst_address_low] $r9
+
+ // pull updated IV
+ cxset 2
+ mov $r4 #ctx_iv
+ sethi $r4 0x60000
+ xdld $r0 $r4
+ xdwait
+
+ ret
+
+
+crypt_copy_prep:
+ cs0begin 2
+ cxsin $c0
+ cxsout $c0
+ ret
+
+crypt_store_prep:
+ cs0begin 1
+ cxsout $c6
+ ret
+
+crypt_ecb_e_prep:
+ cs0begin 3
+ cxsin $c0
+ cenc $c0 $c0
+ cxsout $c0
+ ret
+
+crypt_ecb_d_prep:
+ ckexp $c7 $c7
+ cs0begin 3
+ cxsin $c0
+ cdec $c0 $c0
+ cxsout $c0
+ ret
+
+crypt_cbc_e_prep:
+ cs0begin 4
+ cxsin $c0
+ cxor $c6 $c0
+ cenc $c6 $c6
+ cxsout $c6
+ ret
+
+crypt_cbc_d_prep:
+ ckexp $c7 $c7
+ cs0begin 5
+ cmov $c2 $c6
+ cxsin $c6
+ cdec $c0 $c6
+ cxor $c0 $c2
+ cxsout $c0
+ ret
+
+crypt_pcbc_e_prep:
+ cs0begin 5
+ cxsin $c0
+ cxor $c6 $c0
+ cenc $c6 $c6
+ cxsout $c6
+ cxor $c6 $c0
+ ret
+
+crypt_pcbc_d_prep:
+ ckexp $c7 $c7
+ cs0begin 5
+ cxsin $c0
+ cdec $c1 $c0
+ cxor $c6 $c1
+ cxsout $c6
+ cxor $c6 $c0
+ ret
+
+crypt_cfb_e_prep:
+ cs0begin 4
+ cenc $c6 $c6
+ cxsin $c0
+ cxor $c6 $c0
+ cxsout $c6
+ ret
+
+crypt_cfb_d_prep:
+ cs0begin 4
+ cenc $c0 $c6
+ cxsin $c6
+ cxor $c0 $c6
+ cxsout $c0
+ ret
+
+crypt_ofb_prep:
+ cs0begin 4
+ cenc $c6 $c6
+ cxsin $c0
+ cxor $c0 $c6
+ cxsout $c0
+ ret
+
+crypt_ctr_prep:
+ cs0begin 5
+ cenc $c1 $c6
+ cadd $c6 1
+ cxsin $c0
+ cxor $c0 $c1
+ cxsout $c0
+ ret
+
+crypt_cbc_mac_prep:
+ cs0begin 3
+ cxsin $c0
+ cxor $c6 $c0
+ cenc $c6 $c6
+ ret
+
+crypt_cmac_finish_complete_prep:
+ cs0begin 7
+ cxsin $c0
+ cxor $c6 $c0
+ cxor $c0 $c0
+ cenc $c0 $c0
+ cprecmac $c0 $c0
+ cxor $c6 $c0
+ cenc $c6 $c6
+ ret
+
+crypt_cmac_finish_partial_prep:
+ cs0begin 8
+ cxsin $c0
+ cxor $c6 $c0
+ cxor $c0 $c0
+ cenc $c0 $c0
+ cprecmac $c0 $c0
+ cprecmac $c0 $c0
+ cxor $c6 $c0
+ cenc $c6 $c6
+ ret
+
+// TODO
+crypt_do_in:
+ add b32 $r3 $r5
+ mov $xdbase $r4
+ mov $r9 #swap
+ sethi $r9 0x20000
+ crypt_do_in_loop:
+ xdld $r5 $r9
+ xdwait
+ cxset 0x22
+ xdst $r0 $r9
+ cs0exec 1
+ xdwait
+ add b32 $r5 0x10
+ cmpu b32 $r5 $r3
+ bra ne #crypt_do_in_loop
+ cxset 1
+ xdwait
+ ret
+
+crypt_do_out:
+ add b32 $r3 $r7
+ mov $xdbase $r6
+ mov $r9 #swap
+ sethi $r9 0x20000
+ crypt_do_out_loop:
+ cs0exec 1
+ cxset 0x61
+ xdld $r7 $r9
+ xdst $r7 $r9
+ cxset 1
+ xdwait
+ add b32 $r7 0x10
+ cmpu b32 $r7 $r3
+ bra ne #crypt_do_out_loop
+ ret
+
+crypt_do_inout:
+ add b32 $r3 $r5
+ mov $r9 #swap
+ sethi $r9 0x20000
+ crypt_do_inout_loop:
+ mov $xdbase $r4
+ xdld $r5 $r9
+ xdwait
+ cxset 0x21
+ xdst $r0 $r9
+ cs0exec 1
+ cxset 0x61
+ mov $xdbase $r6
+ xdld $r7 $r9
+ xdst $r7 $r9
+ cxset 1
+ xdwait
+ add b32 $r5 0x10
+ add b32 $r7 0x10
+ cmpu b32 $r5 $r3
+ bra ne #crypt_do_inout_loop
+ ret
+
+.align 0x100
diff --git a/drivers/gpu/drm/nouveau/nv98_crypt.fuc.h b/drivers/gpu/drm/nouveau/nv98_crypt.fuc.h
new file mode 100644
index 000000000000..38676c74e6e0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv98_crypt.fuc.h
@@ -0,0 +1,584 @@
+uint32_t nv98_pcrypt_data[] = {
+/* 0x0000: ctx_dma */
+/* 0x0000: ctx_dma_query */
+ 0x00000000,
+/* 0x0004: ctx_dma_src */
+ 0x00000000,
+/* 0x0008: ctx_dma_dst */
+ 0x00000000,
+/* 0x000c: ctx_query_address_high */
+ 0x00000000,
+/* 0x0010: ctx_query_address_low */
+ 0x00000000,
+/* 0x0014: ctx_query_counter */
+ 0x00000000,
+/* 0x0018: ctx_cond_address_high */
+ 0x00000000,
+/* 0x001c: ctx_cond_address_low */
+ 0x00000000,
+/* 0x0020: ctx_cond_off */
+ 0x00000000,
+/* 0x0024: ctx_src_address_high */
+ 0x00000000,
+/* 0x0028: ctx_src_address_low */
+ 0x00000000,
+/* 0x002c: ctx_dst_address_high */
+ 0x00000000,
+/* 0x0030: ctx_dst_address_low */
+ 0x00000000,
+/* 0x0034: ctx_mode */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0040: ctx_key */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0050: ctx_iv */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0080: swap */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x00a0: common_cmd_dtable */
+ 0x0002000c,
+ 0xffffff00,
+ 0x00020010,
+ 0x0000000f,
+ 0x00020014,
+ 0x00000000,
+ 0x00000192,
+ 0xfffffffe,
+ 0x00020018,
+ 0xffffff00,
+ 0x0002001c,
+ 0x0000000f,
+ 0x000001d7,
+ 0xfffffff8,
+ 0x00000260,
+ 0xffffffff,
+/* 0x00e0: engine_cmd_dtable */
+ 0x00020040,
+ 0x00000000,
+ 0x00020044,
+ 0x00000000,
+ 0x00020048,
+ 0x00000000,
+ 0x0002004c,
+ 0x00000000,
+ 0x00020050,
+ 0x00000000,
+ 0x00020054,
+ 0x00000000,
+ 0x00020058,
+ 0x00000000,
+ 0x0002005c,
+ 0x00000000,
+ 0x00020024,
+ 0xffffff00,
+ 0x00020028,
+ 0x0000000f,
+ 0x0002002c,
+ 0xffffff00,
+ 0x00020030,
+ 0x0000000f,
+ 0x00000271,
+ 0xfffffff0,
+ 0x00010285,
+ 0xf000000f,
+/* 0x0150: crypt_dtable */
+ 0x04db0321,
+ 0x04b1032f,
+ 0x04db0339,
+ 0x04db034b,
+ 0x04db0361,
+ 0x04db0377,
+ 0x04db0395,
+ 0x04db03af,
+ 0x04db03cd,
+ 0x04db03e3,
+ 0x04db03f9,
+ 0x04db040f,
+ 0x04830429,
+ 0x0483043b,
+ 0x0483045d,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+uint32_t nv98_pcrypt_code[] = {
+ 0x17f004bd,
+ 0x0010fe35,
+ 0xf10004fe,
+ 0xf0fff017,
+ 0x27f10013,
+ 0x21d00400,
+ 0x0c15f0c0,
+ 0xf00021d0,
+ 0x27f10317,
+ 0x21d01200,
+ 0x1031f400,
+/* 0x002f: spin */
+ 0xf40031f4,
+ 0x0ef40028,
+/* 0x0035: ih */
+ 0x8001cffd,
+ 0xb00812c4,
+ 0x0bf40024,
+ 0x0027f167,
+ 0x002bfe77,
+ 0xf00007fe,
+ 0x23f00027,
+ 0x0037f105,
+ 0x0034cf14,
+ 0xb0014594,
+ 0x18f40055,
+ 0x0602fa17,
+ 0x4af003f8,
+ 0x0034d01e,
+ 0xd00147f0,
+ 0x0ef48034,
+/* 0x0075: ctxload */
+ 0x4034cf33,
+ 0xb0014f94,
+ 0x18f400f5,
+ 0x0502fa21,
+ 0x57f003f8,
+ 0x0267f000,
+/* 0x008c: ctxload_dma_loop */
+ 0xa07856bc,
+ 0xb6018068,
+ 0x87d00884,
+ 0x0162b600,
+/* 0x009f: dummyload */
+ 0xf0f018f4,
+ 0x35d00257,
+/* 0x00a5: noctx */
+ 0x0412c480,
+ 0xf50024b0,
+ 0xf100df0b,
+ 0xcf190037,
+ 0x33cf4032,
+ 0xff24e400,
+ 0x1024b607,
+ 0x07bf45e4,
+ 0xf50054b0,
+ 0xf100b90b,
+ 0xf1fae057,
+ 0xb000ce67,
+ 0x18f4c044,
+ 0xa057f14d,
+ 0x8867f1fc,
+ 0x8044b000,
+ 0xb03f18f4,
+ 0x18f46044,
+ 0x5044b019,
+ 0xf1741bf4,
+ 0xbd220027,
+ 0x0233f034,
+ 0xf50023d0,
+/* 0x0103: dma_cmd */
+ 0xb000810e,
+ 0x18f46344,
+ 0x0245945e,
+ 0xfe8050b7,
+ 0x801e39f0,
+ 0x40b70053,
+ 0x44b60120,
+ 0x0043d008,
+/* 0x0123: dtable_cmd */
+ 0xb8600ef4,
+ 0x18f40446,
+ 0x0344b63e,
+ 0x980045bb,
+ 0x53fd0145,
+ 0x0054b004,
+ 0x58291bf4,
+ 0x46580045,
+ 0x0264b001,
+ 0x98170bf4,
+ 0x67fd0807,
+ 0x0164b004,
+ 0xf9300bf4,
+ 0x0f01f455,
+/* 0x015b: cmd_setctx */
+ 0x80280ef4,
+ 0x0ef40053,
+/* 0x0161: invalid_bitfield */
+ 0x0125f022,
+/* 0x0164: dispatch_error */
+/* 0x0164: illegal_mthd */
+ 0x100047f1,
+ 0xd00042d0,
+ 0x47f04043,
+ 0x0004d040,
+/* 0x0174: im_loop */
+ 0xf08004cf,
+ 0x44b04044,
+ 0xf71bf400,
+/* 0x0180: cmddone */
+ 0x1d0037f1,
+ 0xd00147f0,
+/* 0x018a: nocmd */
+ 0x11c40034,
+ 0x4001d00c,
+/* 0x0192: cmd_query_get */
+ 0x38f201f8,
+ 0x0325f001,
+ 0x0b0047f1,
+/* 0x019c: ptimer_retry */
+ 0xcf4046cf,
+ 0x47cf0045,
+ 0x0467b840,
+ 0x98f41bf4,
+ 0x04800504,
+ 0x21008020,
+ 0x80220580,
+ 0x0bfe2306,
+ 0x03049800,
+ 0xfe1844b6,
+ 0x04980047,
+ 0x8057f104,
+ 0x0253f000,
+ 0xf80645fa,
+/* 0x01d7: cmd_cond_mode */
+ 0xf400f803,
+ 0x25f00131,
+ 0x0534b002,
+ 0xf41218f4,
+ 0x34b00132,
+ 0x0b18f402,
+ 0x800136f0,
+/* 0x01f2: return */
+ 0x00f80803,
+/* 0x01f4: cmd_cond_mode_queryful */
+ 0x98060498,
+ 0x56c40705,
+ 0x0855b6ff,
+ 0xfd1844b6,
+ 0x47fe0545,
+ 0x000bfe00,
+ 0x008057f1,
+ 0xfa0253f0,
+ 0x34b00565,
+ 0x131bf402,
+ 0x049803f8,
+ 0x0044b021,
+ 0x800b4cf0,
+ 0x00f80804,
+/* 0x022c: cmd_cond_mode_double */
+ 0xb61060b6,
+ 0x65fa1050,
+ 0x9803f805,
+ 0x06982005,
+ 0x0456b824,
+ 0x980b4cf0,
+ 0x06982105,
+ 0x0456b825,
+ 0xfd0b5cf0,
+ 0x34b00445,
+ 0x0b5cf003,
+ 0x800645fd,
+ 0x00f80804,
+/* 0x0260: cmd_wrcache_flush */
+ 0xf10132f4,
+ 0xbd220027,
+ 0x0133f034,
+ 0xf80023d0,
+/* 0x0271: crypt_cmd_mode */
+ 0x0131f400,
+ 0xb00225f0,
+ 0x18f40f34,
+ 0x0132f409,
+/* 0x0283: crypt_cmd_mode_return */
+ 0xf80d0380,
+/* 0x0285: crypt_cmd_length */
+ 0x0034b000,
+ 0xf4fb0bf4,
+ 0x47f0033c,
+ 0x0743f040,
+ 0xf00604fa,
+ 0x43f05047,
+ 0x0604fa06,
+ 0x3cf503f8,
+ 0x47f1c407,
+ 0x4bfe2100,
+ 0x09049800,
+ 0x950a0598,
+ 0x44b60858,
+ 0x0548fd18,
+ 0x98ff55c4,
+ 0x07980b06,
+ 0x0878950c,
+ 0xfd1864b6,
+ 0x77c40568,
+ 0x0d0898ff,
+ 0x580284b6,
+ 0x95f9a889,
+ 0xf9a98958,
+ 0x013cf495,
+ 0x3cf403f8,
+ 0xf803f861,
+ 0x18489503,
+ 0xbb084994,
+ 0x81b60095,
+ 0x09088000,
+ 0x950a0980,
+ 0x69941868,
+ 0x0097bb08,
+ 0x800081b6,
+ 0x09800b08,
+ 0x023cf40c,
+ 0xf05047f0,
+ 0x04fa0643,
+ 0xf803f805,
+/* 0x0321: crypt_copy_prep */
+ 0x203cf500,
+ 0x003cf594,
+ 0x003cf588,
+/* 0x032f: crypt_store_prep */
+ 0xf500f88c,
+ 0xf594103c,
+ 0xf88c063c,
+/* 0x0339: crypt_ecb_e_prep */
+ 0x303cf500,
+ 0x003cf594,
+ 0x003cf588,
+ 0x003cf5d0,
+/* 0x034b: crypt_ecb_d_prep */
+ 0xf500f88c,
+ 0xf5c8773c,
+ 0xf594303c,
+ 0xf588003c,
+ 0xf5d4003c,
+ 0xf88c003c,
+/* 0x0361: crypt_cbc_e_prep */
+ 0x403cf500,
+ 0x003cf594,
+ 0x063cf588,
+ 0x663cf5ac,
+ 0x063cf5d0,
+/* 0x0377: crypt_cbc_d_prep */
+ 0xf500f88c,
+ 0xf5c8773c,
+ 0xf594503c,
+ 0xf584623c,
+ 0xf588063c,
+ 0xf5d4603c,
+ 0xf5ac203c,
+ 0xf88c003c,
+/* 0x0395: crypt_pcbc_e_prep */
+ 0x503cf500,
+ 0x003cf594,
+ 0x063cf588,
+ 0x663cf5ac,
+ 0x063cf5d0,
+ 0x063cf58c,
+/* 0x03af: crypt_pcbc_d_prep */
+ 0xf500f8ac,
+ 0xf5c8773c,
+ 0xf594503c,
+ 0xf588003c,
+ 0xf5d4013c,
+ 0xf5ac163c,
+ 0xf58c063c,
+ 0xf8ac063c,
+/* 0x03cd: crypt_cfb_e_prep */
+ 0x403cf500,
+ 0x663cf594,
+ 0x003cf5d0,
+ 0x063cf588,
+ 0x063cf5ac,
+/* 0x03e3: crypt_cfb_d_prep */
+ 0xf500f88c,
+ 0xf594403c,
+ 0xf5d0603c,
+ 0xf588063c,
+ 0xf5ac603c,
+ 0xf88c003c,
+/* 0x03f9: crypt_ofb_prep */
+ 0x403cf500,
+ 0x663cf594,
+ 0x003cf5d0,
+ 0x603cf588,
+ 0x003cf5ac,
+/* 0x040f: crypt_ctr_prep */
+ 0xf500f88c,
+ 0xf594503c,
+ 0xf5d0613c,
+ 0xf5b0163c,
+ 0xf588003c,
+ 0xf5ac103c,
+ 0xf88c003c,
+/* 0x0429: crypt_cbc_mac_prep */
+ 0x303cf500,
+ 0x003cf594,
+ 0x063cf588,
+ 0x663cf5ac,
+/* 0x043b: crypt_cmac_finish_complete_prep */
+ 0xf500f8d0,
+ 0xf594703c,
+ 0xf588003c,
+ 0xf5ac063c,
+ 0xf5ac003c,
+ 0xf5d0003c,
+ 0xf5bc003c,
+ 0xf5ac063c,
+ 0xf8d0663c,
+/* 0x045d: crypt_cmac_finish_partial_prep */
+ 0x803cf500,
+ 0x003cf594,
+ 0x063cf588,
+ 0x003cf5ac,
+ 0x003cf5ac,
+ 0x003cf5d0,
+ 0x003cf5bc,
+ 0x063cf5bc,
+ 0x663cf5ac,
+/* 0x0483: crypt_do_in */
+ 0xbb00f8d0,
+ 0x47fe0035,
+ 0x8097f100,
+ 0x0293f000,
+/* 0x0490: crypt_do_in_loop */
+ 0xf80559fa,
+ 0x223cf403,
+ 0xf50609fa,
+ 0xf898103c,
+ 0x1050b603,
+ 0xf40453b8,
+ 0x3cf4e91b,
+ 0xf803f801,
+/* 0x04b1: crypt_do_out */
+ 0x0037bb00,
+ 0xf10067fe,
+ 0xf0008097,
+/* 0x04be: crypt_do_out_loop */
+ 0x3cf50293,
+ 0x3cf49810,
+ 0x0579fa61,
+ 0xf40679fa,
+ 0x03f8013c,
+ 0xb81070b6,
+ 0x1bf40473,
+/* 0x04db: crypt_do_inout */
+ 0xbb00f8e8,
+ 0x97f10035,
+ 0x93f00080,
+/* 0x04e5: crypt_do_inout_loop */
+ 0x0047fe02,
+ 0xf80559fa,
+ 0x213cf403,
+ 0xf50609fa,
+ 0xf498103c,
+ 0x67fe613c,
+ 0x0579fa00,
+ 0xf40679fa,
+ 0x03f8013c,
+ 0xb61050b6,
+ 0x53b81070,
+ 0xd41bf404,
+ 0x000000f8,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nva3_copy.c b/drivers/gpu/drm/nouveau/nva3_copy.c
index 8f356d58e409..0387dc7f4f42 100644
--- a/drivers/gpu/drm/nouveau/nva3_copy.c
+++ b/drivers/gpu/drm/nouveau/nva3_copy.c
@@ -79,29 +79,13 @@ static void
nva3_copy_context_del(struct nouveau_channel *chan, int engine)
{
struct nouveau_gpuobj *ctx = chan->engctx[engine];
- struct drm_device *dev = chan->dev;
- u32 inst;
-
- inst = (chan->ramin->vinst >> 12);
- inst |= 0x40000000;
-
- /* disable fifo access */
- nv_wr32(dev, 0x104048, 0x00000000);
- /* mark channel as unloaded if it's currently active */
- if (nv_rd32(dev, 0x104050) == inst)
- nv_mask(dev, 0x104050, 0x40000000, 0x00000000);
- /* mark next channel as invalid if it's about to be loaded */
- if (nv_rd32(dev, 0x104054) == inst)
- nv_mask(dev, 0x104054, 0x40000000, 0x00000000);
- /* restore fifo access */
- nv_wr32(dev, 0x104048, 0x00000003);
+ int i;
- for (inst = 0xc0; inst <= 0xd4; inst += 4)
- nv_wo32(chan->ramin, inst, 0x00000000);
-
- nouveau_gpuobj_ref(NULL, &ctx);
+ for (i = 0xc0; i <= 0xd4; i += 4)
+ nv_wo32(chan->ramin, i, 0x00000000);
atomic_dec(&chan->vm->engref[engine]);
+ nouveau_gpuobj_ref(NULL, &ctx);
chan->engctx[engine] = ctx;
}
@@ -143,13 +127,6 @@ static int
nva3_copy_fini(struct drm_device *dev, int engine, bool suspend)
{
nv_mask(dev, 0x104048, 0x00000003, 0x00000000);
-
- /* trigger fuc context unload */
- nv_wait(dev, 0x104008, 0x0000000c, 0x00000000);
- nv_mask(dev, 0x104054, 0x40000000, 0x00000000);
- nv_wr32(dev, 0x104000, 0x00000008);
- nv_wait(dev, 0x104008, 0x00000008, 0x00000000);
-
nv_wr32(dev, 0x104014, 0xffffffff);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nva3_pm.c b/drivers/gpu/drm/nouveau/nva3_pm.c
index 9e636e6ef6d7..798829353fb6 100644
--- a/drivers/gpu/drm/nouveau/nva3_pm.c
+++ b/drivers/gpu/drm/nouveau/nva3_pm.c
@@ -98,7 +98,9 @@ read_pll(struct drm_device *dev, int clk, u32 pll)
sclk = read_clk(dev, 0x10 + clk, false);
}
- return sclk * N / (M * P);
+ if (M * P)
+ return sclk * N / (M * P);
+ return 0;
}
struct creg {
@@ -182,23 +184,26 @@ prog_pll(struct drm_device *dev, int clk, u32 pll, struct creg *reg)
const u32 src1 = 0x004160 + (clk * 4);
const u32 ctrl = pll + 0;
const u32 coef = pll + 4;
- u32 cntl;
if (!reg->clk && !reg->pll) {
NV_DEBUG(dev, "no clock for %02x\n", clk);
return;
}
- cntl = nv_rd32(dev, ctrl) & 0xfffffff2;
if (reg->pll) {
nv_mask(dev, src0, 0x00000101, 0x00000101);
nv_wr32(dev, coef, reg->pll);
- nv_wr32(dev, ctrl, cntl | 0x00000015);
+ nv_mask(dev, ctrl, 0x00000015, 0x00000015);
+ nv_mask(dev, ctrl, 0x00000010, 0x00000000);
+ nv_wait(dev, ctrl, 0x00020000, 0x00020000);
+ nv_mask(dev, ctrl, 0x00000010, 0x00000010);
+ nv_mask(dev, ctrl, 0x00000008, 0x00000000);
nv_mask(dev, src1, 0x00000100, 0x00000000);
nv_mask(dev, src1, 0x00000001, 0x00000000);
} else {
nv_mask(dev, src1, 0x003f3141, 0x00000101 | reg->clk);
- nv_wr32(dev, ctrl, cntl | 0x0000001d);
+ nv_mask(dev, ctrl, 0x00000018, 0x00000018);
+ udelay(20);
nv_mask(dev, ctrl, 0x00000001, 0x00000000);
nv_mask(dev, src0, 0x00000100, 0x00000000);
nv_mask(dev, src0, 0x00000001, 0x00000000);
@@ -230,17 +235,28 @@ nva3_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
}
struct nva3_pm_state {
+ struct nouveau_pm_level *perflvl;
+
struct creg nclk;
struct creg sclk;
- struct creg mclk;
struct creg vdec;
struct creg unka0;
+
+ struct creg mclk;
+ u8 *rammap;
+ u8 rammap_ver;
+ u8 rammap_len;
+ u8 *ramcfg;
+ u8 ramcfg_len;
+ u32 r004018;
+ u32 r100760;
};
void *
nva3_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl)
{
struct nva3_pm_state *info;
+ u8 ramcfg_cnt;
int ret;
info = kzalloc(sizeof(*info), GFP_KERNEL);
@@ -267,6 +283,20 @@ nva3_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl)
if (ret < 0)
goto out;
+ info->rammap = nouveau_perf_rammap(dev, perflvl->memory,
+ &info->rammap_ver,
+ &info->rammap_len,
+ &ramcfg_cnt, &info->ramcfg_len);
+ if (info->rammap_ver != 0x10 || info->rammap_len < 5)
+ info->rammap = NULL;
+
+ info->ramcfg = nouveau_perf_ramcfg(dev, perflvl->memory,
+ &info->rammap_ver,
+ &info->ramcfg_len);
+ if (info->rammap_ver != 0x10)
+ info->ramcfg = NULL;
+
+ info->perflvl = perflvl;
out:
if (ret < 0) {
kfree(info);
@@ -287,6 +317,240 @@ nva3_pm_grcp_idle(void *data)
return false;
}
+static void
+mclk_precharge(struct nouveau_mem_exec_func *exec)
+{
+ nv_wr32(exec->dev, 0x1002d4, 0x00000001);
+}
+
+static void
+mclk_refresh(struct nouveau_mem_exec_func *exec)
+{
+ nv_wr32(exec->dev, 0x1002d0, 0x00000001);
+}
+
+static void
+mclk_refresh_auto(struct nouveau_mem_exec_func *exec, bool enable)
+{
+ nv_wr32(exec->dev, 0x100210, enable ? 0x80000000 : 0x00000000);
+}
+
+static void
+mclk_refresh_self(struct nouveau_mem_exec_func *exec, bool enable)
+{
+ nv_wr32(exec->dev, 0x1002dc, enable ? 0x00000001 : 0x00000000);
+}
+
+static void
+mclk_wait(struct nouveau_mem_exec_func *exec, u32 nsec)
+{
+ volatile u32 post = nv_rd32(exec->dev, 0); (void)post;
+ udelay((nsec + 500) / 1000);
+}
+
+static u32
+mclk_mrg(struct nouveau_mem_exec_func *exec, int mr)
+{
+ if (mr <= 1)
+ return nv_rd32(exec->dev, 0x1002c0 + ((mr - 0) * 4));
+ if (mr <= 3)
+ return nv_rd32(exec->dev, 0x1002e0 + ((mr - 2) * 4));
+ return 0;
+}
+
+static void
+mclk_mrs(struct nouveau_mem_exec_func *exec, int mr, u32 data)
+{
+ struct drm_nouveau_private *dev_priv = exec->dev->dev_private;
+
+ if (mr <= 1) {
+ if (dev_priv->vram_rank_B)
+ nv_wr32(exec->dev, 0x1002c8 + ((mr - 0) * 4), data);
+ nv_wr32(exec->dev, 0x1002c0 + ((mr - 0) * 4), data);
+ } else
+ if (mr <= 3) {
+ if (dev_priv->vram_rank_B)
+ nv_wr32(exec->dev, 0x1002e8 + ((mr - 2) * 4), data);
+ nv_wr32(exec->dev, 0x1002e0 + ((mr - 2) * 4), data);
+ }
+}
+
+static void
+mclk_clock_set(struct nouveau_mem_exec_func *exec)
+{
+ struct drm_device *dev = exec->dev;
+ struct nva3_pm_state *info = exec->priv;
+ u32 ctrl;
+
+ ctrl = nv_rd32(dev, 0x004000);
+ if (!(ctrl & 0x00000008) && info->mclk.pll) {
+ nv_wr32(dev, 0x004000, (ctrl |= 0x00000008));
+ nv_mask(dev, 0x1110e0, 0x00088000, 0x00088000);
+ nv_wr32(dev, 0x004018, 0x00001000);
+ nv_wr32(dev, 0x004000, (ctrl &= ~0x00000001));
+ nv_wr32(dev, 0x004004, info->mclk.pll);
+ nv_wr32(dev, 0x004000, (ctrl |= 0x00000001));
+ udelay(64);
+ nv_wr32(dev, 0x004018, 0x00005000 | info->r004018);
+ udelay(20);
+ } else
+ if (!info->mclk.pll) {
+ nv_mask(dev, 0x004168, 0x003f3040, info->mclk.clk);
+ nv_wr32(dev, 0x004000, (ctrl |= 0x00000008));
+ nv_mask(dev, 0x1110e0, 0x00088000, 0x00088000);
+ nv_wr32(dev, 0x004018, 0x0000d000 | info->r004018);
+ }
+
+ if (info->rammap) {
+ if (info->ramcfg && (info->rammap[4] & 0x08)) {
+ u32 unk5a0 = (ROM16(info->ramcfg[5]) << 8) |
+ info->ramcfg[5];
+ u32 unk5a4 = ROM16(info->ramcfg[7]);
+ u32 unk804 = (info->ramcfg[9] & 0xf0) << 16 |
+ (info->ramcfg[3] & 0x0f) << 16 |
+ (info->ramcfg[9] & 0x0f) |
+ 0x80000000;
+ nv_wr32(dev, 0x1005a0, unk5a0);
+ nv_wr32(dev, 0x1005a4, unk5a4);
+ nv_wr32(dev, 0x10f804, unk804);
+ nv_mask(dev, 0x10053c, 0x00001000, 0x00000000);
+ } else {
+ nv_mask(dev, 0x10053c, 0x00001000, 0x00001000);
+ nv_mask(dev, 0x10f804, 0x80000000, 0x00000000);
+ nv_mask(dev, 0x100760, 0x22222222, info->r100760);
+ nv_mask(dev, 0x1007a0, 0x22222222, info->r100760);
+ nv_mask(dev, 0x1007e0, 0x22222222, info->r100760);
+ }
+ }
+
+ if (info->mclk.pll) {
+ nv_mask(dev, 0x1110e0, 0x00088000, 0x00011000);
+ nv_wr32(dev, 0x004000, (ctrl &= ~0x00000008));
+ }
+}
+
+static void
+mclk_timing_set(struct nouveau_mem_exec_func *exec)
+{
+ struct drm_device *dev = exec->dev;
+ struct nva3_pm_state *info = exec->priv;
+ struct nouveau_pm_level *perflvl = info->perflvl;
+ int i;
+
+ for (i = 0; i < 9; i++)
+ nv_wr32(dev, 0x100220 + (i * 4), perflvl->timing.reg[i]);
+
+ if (info->ramcfg) {
+ u32 data = (info->ramcfg[2] & 0x08) ? 0x00000000 : 0x00001000;
+ nv_mask(dev, 0x100200, 0x00001000, data);
+ }
+
+ if (info->ramcfg) {
+ u32 unk714 = nv_rd32(dev, 0x100714) & ~0xf0000010;
+ u32 unk718 = nv_rd32(dev, 0x100718) & ~0x00000100;
+ u32 unk71c = nv_rd32(dev, 0x10071c) & ~0x00000100;
+ if ( (info->ramcfg[2] & 0x20))
+ unk714 |= 0xf0000000;
+ if (!(info->ramcfg[2] & 0x04))
+ unk714 |= 0x00000010;
+ nv_wr32(dev, 0x100714, unk714);
+
+ if (info->ramcfg[2] & 0x01)
+ unk71c |= 0x00000100;
+ nv_wr32(dev, 0x10071c, unk71c);
+
+ if (info->ramcfg[2] & 0x02)
+ unk718 |= 0x00000100;
+ nv_wr32(dev, 0x100718, unk718);
+
+ if (info->ramcfg[2] & 0x10)
+ nv_wr32(dev, 0x111100, 0x48000000); /*XXX*/
+ }
+}
+
+static void
+prog_mem(struct drm_device *dev, struct nva3_pm_state *info)
+{
+ struct nouveau_mem_exec_func exec = {
+ .dev = dev,
+ .precharge = mclk_precharge,
+ .refresh = mclk_refresh,
+ .refresh_auto = mclk_refresh_auto,
+ .refresh_self = mclk_refresh_self,
+ .wait = mclk_wait,
+ .mrg = mclk_mrg,
+ .mrs = mclk_mrs,
+ .clock_set = mclk_clock_set,
+ .timing_set = mclk_timing_set,
+ .priv = info
+ };
+ u32 ctrl;
+
+ /* XXX: where the fuck does 750MHz come from? */
+ if (info->perflvl->memory <= 750000) {
+ info->r004018 = 0x10000000;
+ info->r100760 = 0x22222222;
+ }
+
+ ctrl = nv_rd32(dev, 0x004000);
+ if (ctrl & 0x00000008) {
+ if (info->mclk.pll) {
+ nv_mask(dev, 0x004128, 0x00000101, 0x00000101);
+ nv_wr32(dev, 0x004004, info->mclk.pll);
+ nv_wr32(dev, 0x004000, (ctrl |= 0x00000001));
+ nv_wr32(dev, 0x004000, (ctrl &= 0xffffffef));
+ nv_wait(dev, 0x004000, 0x00020000, 0x00020000);
+ nv_wr32(dev, 0x004000, (ctrl |= 0x00000010));
+ nv_wr32(dev, 0x004018, 0x00005000 | info->r004018);
+ nv_wr32(dev, 0x004000, (ctrl |= 0x00000004));
+ }
+ } else {
+ u32 ssel = 0x00000101;
+ if (info->mclk.clk)
+ ssel |= info->mclk.clk;
+ else
+ ssel |= 0x00080000; /* 324MHz, shouldn't matter... */
+ nv_mask(dev, 0x004168, 0x003f3141, ctrl);
+ }
+
+ if (info->ramcfg) {
+ if (info->ramcfg[2] & 0x10) {
+ nv_mask(dev, 0x111104, 0x00000600, 0x00000000);
+ } else {
+ nv_mask(dev, 0x111100, 0x40000000, 0x40000000);
+ nv_mask(dev, 0x111104, 0x00000180, 0x00000000);
+ }
+ }
+ if (info->rammap && !(info->rammap[4] & 0x02))
+ nv_mask(dev, 0x100200, 0x00000800, 0x00000000);
+ nv_wr32(dev, 0x611200, 0x00003300);
+ if (!(info->ramcfg[2] & 0x10))
+ nv_wr32(dev, 0x111100, 0x4c020000); /*XXX*/
+
+ nouveau_mem_exec(&exec, info->perflvl);
+
+ nv_wr32(dev, 0x611200, 0x00003330);
+ if (info->rammap && (info->rammap[4] & 0x02))
+ nv_mask(dev, 0x100200, 0x00000800, 0x00000800);
+ if (info->ramcfg) {
+ if (info->ramcfg[2] & 0x10) {
+ nv_mask(dev, 0x111104, 0x00000180, 0x00000180);
+ nv_mask(dev, 0x111100, 0x40000000, 0x00000000);
+ } else {
+ nv_mask(dev, 0x111104, 0x00000600, 0x00000600);
+ }
+ }
+
+ if (info->mclk.pll) {
+ nv_mask(dev, 0x004168, 0x00000001, 0x00000000);
+ nv_mask(dev, 0x004168, 0x00000100, 0x00000000);
+ } else {
+ nv_mask(dev, 0x004000, 0x00000001, 0x00000000);
+ nv_mask(dev, 0x004128, 0x00000001, 0x00000000);
+ nv_mask(dev, 0x004128, 0x00000100, 0x00000000);
+ }
+}
+
int
nva3_pm_clocks_set(struct drm_device *dev, void *pre_state)
{
@@ -316,18 +580,8 @@ nva3_pm_clocks_set(struct drm_device *dev, void *pre_state)
prog_clk(dev, 0x20, &info->unka0);
prog_clk(dev, 0x21, &info->vdec);
- if (info->mclk.clk || info->mclk.pll) {
- nv_wr32(dev, 0x100210, 0);
- nv_wr32(dev, 0x1002dc, 1);
- nv_wr32(dev, 0x004018, 0x00001000);
- prog_pll(dev, 0x02, 0x004000, &info->mclk);
- if (nv_rd32(dev, 0x4000) & 0x00000008)
- nv_wr32(dev, 0x004018, 0x1000d000);
- else
- nv_wr32(dev, 0x004018, 0x10005000);
- nv_wr32(dev, 0x1002dc, 0);
- nv_wr32(dev, 0x100210, 0x80000000);
- }
+ if (info->mclk.clk || info->mclk.pll)
+ prog_mem(dev, info);
ret = 0;
diff --git a/drivers/gpu/drm/nouveau/nvc0_fbcon.c b/drivers/gpu/drm/nouveau/nvc0_fbcon.c
index a495e48197ca..797159e7b7a6 100644
--- a/drivers/gpu/drm/nouveau/nvc0_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nvc0_fbcon.c
@@ -43,22 +43,22 @@ nvc0_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
return ret;
if (rect->rop != ROP_COPY) {
- BEGIN_NVC0(chan, 2, NvSub2D, 0x02ac, 1);
+ BEGIN_NVC0(chan, NvSub2D, 0x02ac, 1);
OUT_RING (chan, 1);
}
- BEGIN_NVC0(chan, 2, NvSub2D, 0x0588, 1);
+ BEGIN_NVC0(chan, NvSub2D, 0x0588, 1);
if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
info->fix.visual == FB_VISUAL_DIRECTCOLOR)
OUT_RING (chan, ((uint32_t *)info->pseudo_palette)[rect->color]);
else
OUT_RING (chan, rect->color);
- BEGIN_NVC0(chan, 2, NvSub2D, 0x0600, 4);
+ BEGIN_NVC0(chan, NvSub2D, 0x0600, 4);
OUT_RING (chan, rect->dx);
OUT_RING (chan, rect->dy);
OUT_RING (chan, rect->dx + rect->width);
OUT_RING (chan, rect->dy + rect->height);
if (rect->rop != ROP_COPY) {
- BEGIN_NVC0(chan, 2, NvSub2D, 0x02ac, 1);
+ BEGIN_NVC0(chan, NvSub2D, 0x02ac, 1);
OUT_RING (chan, 3);
}
FIRE_RING(chan);
@@ -78,14 +78,14 @@ nvc0_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
if (ret)
return ret;
- BEGIN_NVC0(chan, 2, NvSub2D, 0x0110, 1);
+ BEGIN_NVC0(chan, NvSub2D, 0x0110, 1);
OUT_RING (chan, 0);
- BEGIN_NVC0(chan, 2, NvSub2D, 0x08b0, 4);
+ BEGIN_NVC0(chan, NvSub2D, 0x08b0, 4);
OUT_RING (chan, region->dx);
OUT_RING (chan, region->dy);
OUT_RING (chan, region->width);
OUT_RING (chan, region->height);
- BEGIN_NVC0(chan, 2, NvSub2D, 0x08d0, 4);
+ BEGIN_NVC0(chan, NvSub2D, 0x08d0, 4);
OUT_RING (chan, 0);
OUT_RING (chan, region->sx);
OUT_RING (chan, 0);
@@ -116,7 +116,7 @@ nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
width = ALIGN(image->width, 32);
dwords = (width * image->height) >> 5;
- BEGIN_NVC0(chan, 2, NvSub2D, 0x0814, 2);
+ BEGIN_NVC0(chan, NvSub2D, 0x0814, 2);
if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
OUT_RING (chan, palette[image->bg_color] | mask);
@@ -125,10 +125,10 @@ nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
OUT_RING (chan, image->bg_color);
OUT_RING (chan, image->fg_color);
}
- BEGIN_NVC0(chan, 2, NvSub2D, 0x0838, 2);
+ BEGIN_NVC0(chan, NvSub2D, 0x0838, 2);
OUT_RING (chan, image->width);
OUT_RING (chan, image->height);
- BEGIN_NVC0(chan, 2, NvSub2D, 0x0850, 4);
+ BEGIN_NVC0(chan, NvSub2D, 0x0850, 4);
OUT_RING (chan, 0);
OUT_RING (chan, image->dx);
OUT_RING (chan, 0);
@@ -143,7 +143,7 @@ nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
dwords -= push;
- BEGIN_NVC0(chan, 6, NvSub2D, 0x0860, push);
+ BEGIN_NIC0(chan, NvSub2D, 0x0860, push);
OUT_RINGp(chan, data, push);
data += push;
}
@@ -200,47 +200,47 @@ nvc0_fbcon_accel_init(struct fb_info *info)
return ret;
}
- BEGIN_NVC0(chan, 2, NvSub2D, 0x0000, 1);
+ BEGIN_NVC0(chan, NvSub2D, 0x0000, 1);
OUT_RING (chan, 0x0000902d);
- BEGIN_NVC0(chan, 2, NvSub2D, 0x0104, 2);
+ BEGIN_NVC0(chan, NvSub2D, 0x0104, 2);
OUT_RING (chan, upper_32_bits(chan->notifier_vma.offset));
OUT_RING (chan, lower_32_bits(chan->notifier_vma.offset));
- BEGIN_NVC0(chan, 2, NvSub2D, 0x0290, 1);
+ BEGIN_NVC0(chan, NvSub2D, 0x0290, 1);
OUT_RING (chan, 0);
- BEGIN_NVC0(chan, 2, NvSub2D, 0x0888, 1);
+ BEGIN_NVC0(chan, NvSub2D, 0x0888, 1);
OUT_RING (chan, 1);
- BEGIN_NVC0(chan, 2, NvSub2D, 0x02ac, 1);
+ BEGIN_NVC0(chan, NvSub2D, 0x02ac, 1);
OUT_RING (chan, 3);
- BEGIN_NVC0(chan, 2, NvSub2D, 0x02a0, 1);
+ BEGIN_NVC0(chan, NvSub2D, 0x02a0, 1);
OUT_RING (chan, 0x55);
- BEGIN_NVC0(chan, 2, NvSub2D, 0x08c0, 4);
+ BEGIN_NVC0(chan, NvSub2D, 0x08c0, 4);
OUT_RING (chan, 0);
OUT_RING (chan, 1);
OUT_RING (chan, 0);
OUT_RING (chan, 1);
- BEGIN_NVC0(chan, 2, NvSub2D, 0x0580, 2);
+ BEGIN_NVC0(chan, NvSub2D, 0x0580, 2);
OUT_RING (chan, 4);
OUT_RING (chan, format);
- BEGIN_NVC0(chan, 2, NvSub2D, 0x02e8, 2);
+ BEGIN_NVC0(chan, NvSub2D, 0x02e8, 2);
OUT_RING (chan, 2);
OUT_RING (chan, 1);
- BEGIN_NVC0(chan, 2, NvSub2D, 0x0804, 1);
+ BEGIN_NVC0(chan, NvSub2D, 0x0804, 1);
OUT_RING (chan, format);
- BEGIN_NVC0(chan, 2, NvSub2D, 0x0800, 1);
+ BEGIN_NVC0(chan, NvSub2D, 0x0800, 1);
OUT_RING (chan, 1);
- BEGIN_NVC0(chan, 2, NvSub2D, 0x0808, 3);
+ BEGIN_NVC0(chan, NvSub2D, 0x0808, 3);
OUT_RING (chan, 0);
OUT_RING (chan, 0);
OUT_RING (chan, 1);
- BEGIN_NVC0(chan, 2, NvSub2D, 0x081c, 1);
+ BEGIN_NVC0(chan, NvSub2D, 0x081c, 1);
OUT_RING (chan, 1);
- BEGIN_NVC0(chan, 2, NvSub2D, 0x0840, 4);
+ BEGIN_NVC0(chan, NvSub2D, 0x0840, 4);
OUT_RING (chan, 0);
OUT_RING (chan, 1);
OUT_RING (chan, 0);
OUT_RING (chan, 1);
- BEGIN_NVC0(chan, 2, NvSub2D, 0x0200, 10);
+ BEGIN_NVC0(chan, NvSub2D, 0x0200, 10);
OUT_RING (chan, format);
OUT_RING (chan, 1);
OUT_RING (chan, 0);
@@ -251,7 +251,7 @@ nvc0_fbcon_accel_init(struct fb_info *info)
OUT_RING (chan, info->var.yres_virtual);
OUT_RING (chan, upper_32_bits(fb->vma.offset));
OUT_RING (chan, lower_32_bits(fb->vma.offset));
- BEGIN_NVC0(chan, 2, NvSub2D, 0x0230, 10);
+ BEGIN_NVC0(chan, NvSub2D, 0x0230, 10);
OUT_RING (chan, format);
OUT_RING (chan, 1);
OUT_RING (chan, 0);
diff --git a/drivers/gpu/drm/nouveau/nvc0_fence.c b/drivers/gpu/drm/nouveau/nvc0_fence.c
new file mode 100644
index 000000000000..47ab388a606e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvc0_fence.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_dma.h"
+#include "nouveau_fifo.h"
+#include "nouveau_ramht.h"
+#include "nouveau_fence.h"
+
+struct nvc0_fence_priv {
+ struct nouveau_fence_priv base;
+ struct nouveau_bo *bo;
+};
+
+struct nvc0_fence_chan {
+ struct nouveau_fence_chan base;
+ struct nouveau_vma vma;
+};
+
+static int
+nvc0_fence_emit(struct nouveau_fence *fence)
+{
+ struct nouveau_channel *chan = fence->channel;
+ struct nvc0_fence_chan *fctx = chan->engctx[NVOBJ_ENGINE_FENCE];
+ u64 addr = fctx->vma.offset + chan->id * 16;
+ int ret;
+
+ ret = RING_SPACE(chan, 5);
+ if (ret == 0) {
+ BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
+ OUT_RING (chan, upper_32_bits(addr));
+ OUT_RING (chan, lower_32_bits(addr));
+ OUT_RING (chan, fence->sequence);
+ OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG);
+ FIRE_RING (chan);
+ }
+
+ return ret;
+}
+
+static int
+nvc0_fence_sync(struct nouveau_fence *fence,
+ struct nouveau_channel *prev, struct nouveau_channel *chan)
+{
+ struct nvc0_fence_chan *fctx = chan->engctx[NVOBJ_ENGINE_FENCE];
+ u64 addr = fctx->vma.offset + prev->id * 16;
+ int ret;
+
+ ret = RING_SPACE(chan, 5);
+ if (ret == 0) {
+ BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
+ OUT_RING (chan, upper_32_bits(addr));
+ OUT_RING (chan, lower_32_bits(addr));
+ OUT_RING (chan, fence->sequence);
+ OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_GEQUAL |
+ NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD);
+ FIRE_RING (chan);
+ }
+
+ return ret;
+}
+
+static u32
+nvc0_fence_read(struct nouveau_channel *chan)
+{
+ struct nvc0_fence_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_FENCE);
+ return nouveau_bo_rd32(priv->bo, chan->id * 16/4);
+}
+
+static void
+nvc0_fence_context_del(struct nouveau_channel *chan, int engine)
+{
+ struct nvc0_fence_priv *priv = nv_engine(chan->dev, engine);
+ struct nvc0_fence_chan *fctx = chan->engctx[engine];
+
+ nouveau_bo_vma_del(priv->bo, &fctx->vma);
+ nouveau_fence_context_del(&fctx->base);
+ chan->engctx[engine] = NULL;
+ kfree(fctx);
+}
+
+static int
+nvc0_fence_context_new(struct nouveau_channel *chan, int engine)
+{
+ struct nvc0_fence_priv *priv = nv_engine(chan->dev, engine);
+ struct nvc0_fence_chan *fctx;
+ int ret;
+
+ fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
+ if (!fctx)
+ return -ENOMEM;
+
+ nouveau_fence_context_new(&fctx->base);
+
+ ret = nouveau_bo_vma_add(priv->bo, chan->vm, &fctx->vma);
+ if (ret)
+ nvc0_fence_context_del(chan, engine);
+
+ nouveau_bo_wr32(priv->bo, chan->id * 16/4, 0x00000000);
+ return ret;
+}
+
+static int
+nvc0_fence_fini(struct drm_device *dev, int engine, bool suspend)
+{
+ return 0;
+}
+
+static int
+nvc0_fence_init(struct drm_device *dev, int engine)
+{
+ return 0;
+}
+
+static void
+nvc0_fence_destroy(struct drm_device *dev, int engine)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nvc0_fence_priv *priv = nv_engine(dev, engine);
+
+ nouveau_bo_unmap(priv->bo);
+ nouveau_bo_ref(NULL, &priv->bo);
+ dev_priv->eng[engine] = NULL;
+ kfree(priv);
+}
+
+int
+nvc0_fence_create(struct drm_device *dev)
+{
+ struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nvc0_fence_priv *priv;
+ int ret;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base.engine.destroy = nvc0_fence_destroy;
+ priv->base.engine.init = nvc0_fence_init;
+ priv->base.engine.fini = nvc0_fence_fini;
+ priv->base.engine.context_new = nvc0_fence_context_new;
+ priv->base.engine.context_del = nvc0_fence_context_del;
+ priv->base.emit = nvc0_fence_emit;
+ priv->base.sync = nvc0_fence_sync;
+ priv->base.read = nvc0_fence_read;
+ dev_priv->eng[NVOBJ_ENGINE_FENCE] = &priv->base.engine;
+
+ ret = nouveau_bo_new(dev, 16 * pfifo->channels, 0, TTM_PL_FLAG_VRAM,
+ 0, 0, NULL, &priv->bo);
+ if (ret == 0) {
+ ret = nouveau_bo_pin(priv->bo, TTM_PL_FLAG_VRAM);
+ if (ret == 0)
+ ret = nouveau_bo_map(priv->bo);
+ if (ret)
+ nouveau_bo_ref(NULL, &priv->bo);
+ }
+
+ if (ret)
+ nvc0_fence_destroy(dev, NVOBJ_ENGINE_FENCE);
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c
index 50d68a7a1379..7d85553d518c 100644
--- a/drivers/gpu/drm/nouveau/nvc0_fifo.c
+++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c
@@ -26,10 +26,12 @@
#include "nouveau_drv.h"
#include "nouveau_mm.h"
+#include "nouveau_fifo.h"
static void nvc0_fifo_isr(struct drm_device *);
struct nvc0_fifo_priv {
+ struct nouveau_fifo_priv base;
struct nouveau_gpuobj *playlist[2];
int cur_playlist;
struct nouveau_vma user_vma;
@@ -37,8 +39,8 @@ struct nvc0_fifo_priv {
};
struct nvc0_fifo_chan {
+ struct nouveau_fifo_chan base;
struct nouveau_gpuobj *user;
- struct nouveau_gpuobj *ramfc;
};
static void
@@ -46,8 +48,7 @@ nvc0_fifo_playlist_update(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- struct nvc0_fifo_priv *priv = pfifo->priv;
+ struct nvc0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct nouveau_gpuobj *cur;
int i, p;
@@ -69,59 +70,20 @@ nvc0_fifo_playlist_update(struct drm_device *dev)
NV_ERROR(dev, "PFIFO - playlist update failed\n");
}
-void
-nvc0_fifo_disable(struct drm_device *dev)
-{
-}
-
-void
-nvc0_fifo_enable(struct drm_device *dev)
-{
-}
-
-bool
-nvc0_fifo_reassign(struct drm_device *dev, bool enable)
-{
- return false;
-}
-
-bool
-nvc0_fifo_cache_pull(struct drm_device *dev, bool enable)
-{
- return false;
-}
-
-int
-nvc0_fifo_channel_id(struct drm_device *dev)
-{
- return 127;
-}
-
-int
-nvc0_fifo_create_context(struct nouveau_channel *chan)
+static int
+nvc0_fifo_context_new(struct nouveau_channel *chan, int engine)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- struct nvc0_fifo_priv *priv = pfifo->priv;
- struct nvc0_fifo_chan *fifoch;
+ struct nvc0_fifo_priv *priv = nv_engine(dev, engine);
+ struct nvc0_fifo_chan *fctx;
u64 ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4;
- int ret;
+ int ret, i;
- chan->fifo_priv = kzalloc(sizeof(*fifoch), GFP_KERNEL);
- if (!chan->fifo_priv)
+ fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
+ if (!fctx)
return -ENOMEM;
- fifoch = chan->fifo_priv;
-
- /* allocate vram for control regs, map into polling area */
- ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x1000,
- NVOBJ_FLAG_ZERO_ALLOC, &fifoch->user);
- if (ret)
- goto error;
-
- nouveau_vm_map_at(&priv->user_vma, chan->id * 0x1000,
- *(struct nouveau_mem **)fifoch->user->node);
chan->user = ioremap_wc(pci_resource_start(dev->pdev, 1) +
priv->user_vma.offset + (chan->id * 0x1000),
@@ -131,176 +93,77 @@ nvc0_fifo_create_context(struct nouveau_channel *chan)
goto error;
}
- /* ramfc */
- ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst,
- chan->ramin->vinst, 0x100,
- NVOBJ_FLAG_ZERO_ALLOC, &fifoch->ramfc);
+ /* allocate vram for control regs, map into polling area */
+ ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x1000,
+ NVOBJ_FLAG_ZERO_ALLOC, &fctx->user);
if (ret)
goto error;
- nv_wo32(fifoch->ramfc, 0x08, lower_32_bits(fifoch->user->vinst));
- nv_wo32(fifoch->ramfc, 0x0c, upper_32_bits(fifoch->user->vinst));
- nv_wo32(fifoch->ramfc, 0x10, 0x0000face);
- nv_wo32(fifoch->ramfc, 0x30, 0xfffff902);
- nv_wo32(fifoch->ramfc, 0x48, lower_32_bits(ib_virt));
- nv_wo32(fifoch->ramfc, 0x4c, drm_order(chan->dma.ib_max + 1) << 16 |
+ nouveau_vm_map_at(&priv->user_vma, chan->id * 0x1000,
+ *(struct nouveau_mem **)fctx->user->node);
+
+ for (i = 0; i < 0x100; i += 4)
+ nv_wo32(chan->ramin, i, 0x00000000);
+ nv_wo32(chan->ramin, 0x08, lower_32_bits(fctx->user->vinst));
+ nv_wo32(chan->ramin, 0x0c, upper_32_bits(fctx->user->vinst));
+ nv_wo32(chan->ramin, 0x10, 0x0000face);
+ nv_wo32(chan->ramin, 0x30, 0xfffff902);
+ nv_wo32(chan->ramin, 0x48, lower_32_bits(ib_virt));
+ nv_wo32(chan->ramin, 0x4c, drm_order(chan->dma.ib_max + 1) << 16 |
upper_32_bits(ib_virt));
- nv_wo32(fifoch->ramfc, 0x54, 0x00000002);
- nv_wo32(fifoch->ramfc, 0x84, 0x20400000);
- nv_wo32(fifoch->ramfc, 0x94, 0x30000001);
- nv_wo32(fifoch->ramfc, 0x9c, 0x00000100);
- nv_wo32(fifoch->ramfc, 0xa4, 0x1f1f1f1f);
- nv_wo32(fifoch->ramfc, 0xa8, 0x1f1f1f1f);
- nv_wo32(fifoch->ramfc, 0xac, 0x0000001f);
- nv_wo32(fifoch->ramfc, 0xb8, 0xf8000000);
- nv_wo32(fifoch->ramfc, 0xf8, 0x10003080); /* 0x002310 */
- nv_wo32(fifoch->ramfc, 0xfc, 0x10000010); /* 0x002350 */
+ nv_wo32(chan->ramin, 0x54, 0x00000002);
+ nv_wo32(chan->ramin, 0x84, 0x20400000);
+ nv_wo32(chan->ramin, 0x94, 0x30000001);
+ nv_wo32(chan->ramin, 0x9c, 0x00000100);
+ nv_wo32(chan->ramin, 0xa4, 0x1f1f1f1f);
+ nv_wo32(chan->ramin, 0xa8, 0x1f1f1f1f);
+ nv_wo32(chan->ramin, 0xac, 0x0000001f);
+ nv_wo32(chan->ramin, 0xb8, 0xf8000000);
+ nv_wo32(chan->ramin, 0xf8, 0x10003080); /* 0x002310 */
+ nv_wo32(chan->ramin, 0xfc, 0x10000010); /* 0x002350 */
pinstmem->flush(dev);
nv_wr32(dev, 0x003000 + (chan->id * 8), 0xc0000000 |
(chan->ramin->vinst >> 12));
nv_wr32(dev, 0x003004 + (chan->id * 8), 0x001f0001);
nvc0_fifo_playlist_update(dev);
- return 0;
error:
- pfifo->destroy_context(chan);
+ if (ret)
+ priv->base.base.context_del(chan, engine);
return ret;
}
-void
-nvc0_fifo_destroy_context(struct nouveau_channel *chan)
+static void
+nvc0_fifo_context_del(struct nouveau_channel *chan, int engine)
{
+ struct nvc0_fifo_chan *fctx = chan->engctx[engine];
struct drm_device *dev = chan->dev;
- struct nvc0_fifo_chan *fifoch;
nv_mask(dev, 0x003004 + (chan->id * 8), 0x00000001, 0x00000000);
nv_wr32(dev, 0x002634, chan->id);
if (!nv_wait(dev, 0x0002634, 0xffffffff, chan->id))
NV_WARN(dev, "0x2634 != chid: 0x%08x\n", nv_rd32(dev, 0x2634));
-
nvc0_fifo_playlist_update(dev);
-
nv_wr32(dev, 0x003000 + (chan->id * 8), 0x00000000);
+ nouveau_gpuobj_ref(NULL, &fctx->user);
if (chan->user) {
iounmap(chan->user);
chan->user = NULL;
}
- fifoch = chan->fifo_priv;
- chan->fifo_priv = NULL;
- if (!fifoch)
- return;
-
- nouveau_gpuobj_ref(NULL, &fifoch->ramfc);
- nouveau_gpuobj_ref(NULL, &fifoch->user);
- kfree(fifoch);
-}
-
-int
-nvc0_fifo_load_context(struct nouveau_channel *chan)
-{
- return 0;
-}
-
-int
-nvc0_fifo_unload_context(struct drm_device *dev)
-{
- int i;
-
- for (i = 0; i < 128; i++) {
- if (!(nv_rd32(dev, 0x003004 + (i * 8)) & 1))
- continue;
-
- nv_mask(dev, 0x003004 + (i * 8), 0x00000001, 0x00000000);
- nv_wr32(dev, 0x002634, i);
- if (!nv_wait(dev, 0x002634, 0xffffffff, i)) {
- NV_INFO(dev, "PFIFO: kick ch %d failed: 0x%08x\n",
- i, nv_rd32(dev, 0x002634));
- return -EBUSY;
- }
- }
-
- return 0;
-}
-
-static void
-nvc0_fifo_destroy(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- struct nvc0_fifo_priv *priv;
-
- priv = pfifo->priv;
- if (!priv)
- return;
-
- nouveau_vm_put(&priv->user_vma);
- nouveau_gpuobj_ref(NULL, &priv->playlist[1]);
- nouveau_gpuobj_ref(NULL, &priv->playlist[0]);
- kfree(priv);
-}
-
-void
-nvc0_fifo_takedown(struct drm_device *dev)
-{
- nv_wr32(dev, 0x002140, 0x00000000);
- nvc0_fifo_destroy(dev);
+ chan->engctx[engine] = NULL;
+ kfree(fctx);
}
static int
-nvc0_fifo_create(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- struct nvc0_fifo_priv *priv;
- int ret;
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
- pfifo->priv = priv;
-
- ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x1000, 0,
- &priv->playlist[0]);
- if (ret)
- goto error;
-
- ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x1000, 0,
- &priv->playlist[1]);
- if (ret)
- goto error;
-
- ret = nouveau_vm_get(dev_priv->bar1_vm, pfifo->channels * 0x1000,
- 12, NV_MEM_ACCESS_RW, &priv->user_vma);
- if (ret)
- goto error;
-
- nouveau_irq_register(dev, 8, nvc0_fifo_isr);
- NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
- return 0;
-
-error:
- nvc0_fifo_destroy(dev);
- return ret;
-}
-
-int
-nvc0_fifo_init(struct drm_device *dev)
+nvc0_fifo_init(struct drm_device *dev, int engine)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+ struct nvc0_fifo_priv *priv = nv_engine(dev, engine);
struct nouveau_channel *chan;
- struct nvc0_fifo_priv *priv;
- int ret, i;
-
- if (!pfifo->priv) {
- ret = nvc0_fifo_create(dev);
- if (ret)
- return ret;
- }
- priv = pfifo->priv;
+ int i;
/* reset PFIFO, enable all available PSUBFIFO areas */
nv_mask(dev, 0x000200, 0x00000100, 0x00000000);
@@ -338,7 +201,7 @@ nvc0_fifo_init(struct drm_device *dev)
/* restore PFIFO context table */
for (i = 0; i < 128; i++) {
chan = dev_priv->channels.ptr[i];
- if (!chan || !chan->fifo_priv)
+ if (!chan || !chan->engctx[engine])
continue;
nv_wr32(dev, 0x003000 + (i * 8), 0xc0000000 |
@@ -350,6 +213,29 @@ nvc0_fifo_init(struct drm_device *dev)
return 0;
}
+static int
+nvc0_fifo_fini(struct drm_device *dev, int engine, bool suspend)
+{
+ int i;
+
+ for (i = 0; i < 128; i++) {
+ if (!(nv_rd32(dev, 0x003004 + (i * 8)) & 1))
+ continue;
+
+ nv_mask(dev, 0x003004 + (i * 8), 0x00000001, 0x00000000);
+ nv_wr32(dev, 0x002634, i);
+ if (!nv_wait(dev, 0x002634, 0xffffffff, i)) {
+ NV_INFO(dev, "PFIFO: kick ch %d failed: 0x%08x\n",
+ i, nv_rd32(dev, 0x002634));
+ return -EBUSY;
+ }
+ }
+
+ nv_wr32(dev, 0x002140, 0x00000000);
+ return 0;
+}
+
+
struct nouveau_enum nvc0_fifo_fault_unit[] = {
{ 0x00, "PGRAPH" },
{ 0x03, "PEEPHOLE" },
@@ -439,13 +325,14 @@ nvc0_fifo_isr_vm_fault(struct drm_device *dev, int unit)
static int
nvc0_fifo_page_flip(struct drm_device *dev, u32 chid)
{
+ struct nvc0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan = NULL;
unsigned long flags;
int ret = -EINVAL;
spin_lock_irqsave(&dev_priv->channels.lock, flags);
- if (likely(chid >= 0 && chid < dev_priv->engine.fifo.channels)) {
+ if (likely(chid >= 0 && chid < priv->base.channels)) {
chan = dev_priv->channels.ptr[chid];
if (likely(chan))
ret = nouveau_finish_page_flip(chan, NULL);
@@ -534,3 +421,56 @@ nvc0_fifo_isr(struct drm_device *dev)
nv_wr32(dev, 0x002140, 0);
}
}
+
+static void
+nvc0_fifo_destroy(struct drm_device *dev, int engine)
+{
+ struct nvc0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ nouveau_vm_put(&priv->user_vma);
+ nouveau_gpuobj_ref(NULL, &priv->playlist[1]);
+ nouveau_gpuobj_ref(NULL, &priv->playlist[0]);
+
+ dev_priv->eng[engine] = NULL;
+ kfree(priv);
+}
+
+int
+nvc0_fifo_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nvc0_fifo_priv *priv;
+ int ret;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base.base.destroy = nvc0_fifo_destroy;
+ priv->base.base.init = nvc0_fifo_init;
+ priv->base.base.fini = nvc0_fifo_fini;
+ priv->base.base.context_new = nvc0_fifo_context_new;
+ priv->base.base.context_del = nvc0_fifo_context_del;
+ priv->base.channels = 128;
+ dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
+
+ ret = nouveau_gpuobj_new(dev, NULL, 4096, 4096, 0, &priv->playlist[0]);
+ if (ret)
+ goto error;
+
+ ret = nouveau_gpuobj_new(dev, NULL, 4096, 4096, 0, &priv->playlist[1]);
+ if (ret)
+ goto error;
+
+ ret = nouveau_vm_get(dev_priv->bar1_vm, priv->base.channels * 0x1000,
+ 12, NV_MEM_ACCESS_RW, &priv->user_vma);
+ if (ret)
+ goto error;
+
+ nouveau_irq_register(dev, 8, nvc0_fifo_isr);
+error:
+ if (ret)
+ priv->base.base.destroy(dev, NVOBJ_ENGINE_FIFO);
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c
index 9066102d1159..2a01e6e47724 100644
--- a/drivers/gpu/drm/nouveau/nvc0_graph.c
+++ b/drivers/gpu/drm/nouveau/nvc0_graph.c
@@ -29,6 +29,7 @@
#include "nouveau_drv.h"
#include "nouveau_mm.h"
+#include "nouveau_fifo.h"
#include "nvc0_graph.h"
#include "nvc0_grhub.fuc.h"
@@ -620,13 +621,14 @@ nvc0_graph_init(struct drm_device *dev, int engine)
int
nvc0_graph_isr_chid(struct drm_device *dev, u64 inst)
{
+ struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *chan;
unsigned long flags;
int i;
spin_lock_irqsave(&dev_priv->channels.lock, flags);
- for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
+ for (i = 0; i < pfifo->channels; i++) {
chan = dev_priv->channels.ptr[i];
if (!chan || !chan->ramin)
continue;
diff --git a/drivers/gpu/drm/nouveau/nvc0_pm.c b/drivers/gpu/drm/nouveau/nvc0_pm.c
index ce65f81bb871..7c95c44e2887 100644
--- a/drivers/gpu/drm/nouveau/nvc0_pm.c
+++ b/drivers/gpu/drm/nouveau/nvc0_pm.c
@@ -164,7 +164,9 @@ struct nvc0_pm_clock {
};
struct nvc0_pm_state {
+ struct nouveau_pm_level *perflvl;
struct nvc0_pm_clock eng[16];
+ struct nvc0_pm_clock mem;
};
static u32
@@ -303,6 +305,48 @@ calc_clk(struct drm_device *dev, int clk, struct nvc0_pm_clock *info, u32 freq)
return 0;
}
+static int
+calc_mem(struct drm_device *dev, struct nvc0_pm_clock *info, u32 freq)
+{
+ struct pll_lims pll;
+ int N, M, P, ret;
+ u32 ctrl;
+
+ /* mclk pll input freq comes from another pll, make sure it's on */
+ ctrl = nv_rd32(dev, 0x132020);
+ if (!(ctrl & 0x00000001)) {
+ /* if not, program it to 567MHz. nfi where this value comes
+ * from - it looks like it's in the pll limits table for
+ * 132000 but the binary driver ignores all my attempts to
+ * change this value.
+ */
+ nv_wr32(dev, 0x137320, 0x00000103);
+ nv_wr32(dev, 0x137330, 0x81200606);
+ nv_wait(dev, 0x132020, 0x00010000, 0x00010000);
+ nv_wr32(dev, 0x132024, 0x0001150f);
+ nv_mask(dev, 0x132020, 0x00000001, 0x00000001);
+ nv_wait(dev, 0x137390, 0x00020000, 0x00020000);
+ nv_mask(dev, 0x132020, 0x00000004, 0x00000004);
+ }
+
+ /* for the moment, until the clock tree is better understood, use
+ * pll mode for all clock frequencies
+ */
+ ret = get_pll_limits(dev, 0x132000, &pll);
+ if (ret == 0) {
+ pll.refclk = read_pll(dev, 0x132020);
+ if (pll.refclk) {
+ ret = nva3_calc_pll(dev, &pll, freq, &N, NULL, &M, &P);
+ if (ret > 0) {
+ info->coef = (P << 16) | (N << 8) | M;
+ return 0;
+ }
+ }
+ }
+
+ return -EINVAL;
+}
+
void *
nvc0_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl)
{
@@ -335,6 +379,15 @@ nvc0_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl)
return ERR_PTR(ret);
}
+ if (perflvl->memory) {
+ ret = calc_mem(dev, &info->mem, perflvl->memory);
+ if (ret) {
+ kfree(info);
+ return ERR_PTR(ret);
+ }
+ }
+
+ info->perflvl = perflvl;
return info;
}
@@ -375,12 +428,148 @@ prog_clk(struct drm_device *dev, int clk, struct nvc0_pm_clock *info)
nv_mask(dev, 0x137250 + (clk * 0x04), 0x00003f3f, info->mdiv);
}
+static void
+mclk_precharge(struct nouveau_mem_exec_func *exec)
+{
+}
+
+static void
+mclk_refresh(struct nouveau_mem_exec_func *exec)
+{
+}
+
+static void
+mclk_refresh_auto(struct nouveau_mem_exec_func *exec, bool enable)
+{
+ nv_wr32(exec->dev, 0x10f210, enable ? 0x80000000 : 0x00000000);
+}
+
+static void
+mclk_refresh_self(struct nouveau_mem_exec_func *exec, bool enable)
+{
+}
+
+static void
+mclk_wait(struct nouveau_mem_exec_func *exec, u32 nsec)
+{
+ udelay((nsec + 500) / 1000);
+}
+
+static u32
+mclk_mrg(struct nouveau_mem_exec_func *exec, int mr)
+{
+ struct drm_device *dev = exec->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ if (dev_priv->vram_type != NV_MEM_TYPE_GDDR5) {
+ if (mr <= 1)
+ return nv_rd32(dev, 0x10f300 + ((mr - 0) * 4));
+ return nv_rd32(dev, 0x10f320 + ((mr - 2) * 4));
+ } else {
+ if (mr == 0)
+ return nv_rd32(dev, 0x10f300 + (mr * 4));
+ else
+ if (mr <= 7)
+ return nv_rd32(dev, 0x10f32c + (mr * 4));
+ return nv_rd32(dev, 0x10f34c);
+ }
+}
+
+static void
+mclk_mrs(struct nouveau_mem_exec_func *exec, int mr, u32 data)
+{
+ struct drm_device *dev = exec->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ if (dev_priv->vram_type != NV_MEM_TYPE_GDDR5) {
+ if (mr <= 1) {
+ nv_wr32(dev, 0x10f300 + ((mr - 0) * 4), data);
+ if (dev_priv->vram_rank_B)
+ nv_wr32(dev, 0x10f308 + ((mr - 0) * 4), data);
+ } else
+ if (mr <= 3) {
+ nv_wr32(dev, 0x10f320 + ((mr - 2) * 4), data);
+ if (dev_priv->vram_rank_B)
+ nv_wr32(dev, 0x10f328 + ((mr - 2) * 4), data);
+ }
+ } else {
+ if (mr == 0) nv_wr32(dev, 0x10f300 + (mr * 4), data);
+ else if (mr <= 7) nv_wr32(dev, 0x10f32c + (mr * 4), data);
+ else if (mr == 15) nv_wr32(dev, 0x10f34c, data);
+ }
+}
+
+static void
+mclk_clock_set(struct nouveau_mem_exec_func *exec)
+{
+ struct nvc0_pm_state *info = exec->priv;
+ struct drm_device *dev = exec->dev;
+ u32 ctrl = nv_rd32(dev, 0x132000);
+
+ nv_wr32(dev, 0x137360, 0x00000001);
+ nv_wr32(dev, 0x137370, 0x00000000);
+ nv_wr32(dev, 0x137380, 0x00000000);
+ if (ctrl & 0x00000001)
+ nv_wr32(dev, 0x132000, (ctrl &= ~0x00000001));
+
+ nv_wr32(dev, 0x132004, info->mem.coef);
+ nv_wr32(dev, 0x132000, (ctrl |= 0x00000001));
+ nv_wait(dev, 0x137390, 0x00000002, 0x00000002);
+ nv_wr32(dev, 0x132018, 0x00005000);
+
+ nv_wr32(dev, 0x137370, 0x00000001);
+ nv_wr32(dev, 0x137380, 0x00000001);
+ nv_wr32(dev, 0x137360, 0x00000000);
+}
+
+static void
+mclk_timing_set(struct nouveau_mem_exec_func *exec)
+{
+ struct nvc0_pm_state *info = exec->priv;
+ struct nouveau_pm_level *perflvl = info->perflvl;
+ int i;
+
+ for (i = 0; i < 5; i++)
+ nv_wr32(exec->dev, 0x10f290 + (i * 4), perflvl->timing.reg[i]);
+}
+
+static void
+prog_mem(struct drm_device *dev, struct nvc0_pm_state *info)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_mem_exec_func exec = {
+ .dev = dev,
+ .precharge = mclk_precharge,
+ .refresh = mclk_refresh,
+ .refresh_auto = mclk_refresh_auto,
+ .refresh_self = mclk_refresh_self,
+ .wait = mclk_wait,
+ .mrg = mclk_mrg,
+ .mrs = mclk_mrs,
+ .clock_set = mclk_clock_set,
+ .timing_set = mclk_timing_set,
+ .priv = info
+ };
+
+ if (dev_priv->chipset < 0xd0)
+ nv_wr32(dev, 0x611200, 0x00003300);
+ else
+ nv_wr32(dev, 0x62c000, 0x03030000);
+
+ nouveau_mem_exec(&exec, info->perflvl);
+
+ if (dev_priv->chipset < 0xd0)
+ nv_wr32(dev, 0x611200, 0x00003300);
+ else
+ nv_wr32(dev, 0x62c000, 0x03030300);
+}
int
nvc0_pm_clocks_set(struct drm_device *dev, void *data)
{
struct nvc0_pm_state *info = data;
int i;
+ if (info->mem.coef)
+ prog_mem(dev, info);
+
for (i = 0; i < 16; i++) {
if (!info->eng[i].freq)
continue;
diff --git a/drivers/gpu/drm/nouveau/nvc0_software.c b/drivers/gpu/drm/nouveau/nvc0_software.c
new file mode 100644
index 000000000000..93e8c164fec6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvc0_software.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+#include "nouveau_ramht.h"
+#include "nouveau_software.h"
+
+#include "nv50_display.h"
+
+struct nvc0_software_priv {
+ struct nouveau_software_priv base;
+};
+
+struct nvc0_software_chan {
+ struct nouveau_software_chan base;
+ struct nouveau_vma dispc_vma[4];
+};
+
+u64
+nvc0_software_crtc(struct nouveau_channel *chan, int crtc)
+{
+ struct nvc0_software_chan *pch = chan->engctx[NVOBJ_ENGINE_SW];
+ return pch->dispc_vma[crtc].offset;
+}
+
+static int
+nvc0_software_context_new(struct nouveau_channel *chan, int engine)
+{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nvc0_software_priv *psw = nv_engine(dev, NVOBJ_ENGINE_SW);
+ struct nvc0_software_chan *pch;
+ int ret = 0, i;
+
+ pch = kzalloc(sizeof(*pch), GFP_KERNEL);
+ if (!pch)
+ return -ENOMEM;
+
+ nouveau_software_context_new(&pch->base);
+ chan->engctx[engine] = pch;
+
+ /* map display semaphore buffers into channel's vm */
+ for (i = 0; !ret && i < dev->mode_config.num_crtc; i++) {
+ struct nouveau_bo *bo;
+ if (dev_priv->card_type >= NV_D0)
+ bo = nvd0_display_crtc_sema(dev, i);
+ else
+ bo = nv50_display(dev)->crtc[i].sem.bo;
+
+ ret = nouveau_bo_vma_add(bo, chan->vm, &pch->dispc_vma[i]);
+ }
+
+ if (ret)
+ psw->base.base.context_del(chan, engine);
+ return ret;
+}
+
+static void
+nvc0_software_context_del(struct nouveau_channel *chan, int engine)
+{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nvc0_software_chan *pch = chan->engctx[engine];
+ int i;
+
+ if (dev_priv->card_type >= NV_D0) {
+ for (i = 0; i < dev->mode_config.num_crtc; i++) {
+ struct nouveau_bo *bo = nvd0_display_crtc_sema(dev, i);
+ nouveau_bo_vma_del(bo, &pch->dispc_vma[i]);
+ }
+ } else
+ if (dev_priv->card_type >= NV_50) {
+ struct nv50_display *disp = nv50_display(dev);
+ for (i = 0; i < dev->mode_config.num_crtc; i++) {
+ struct nv50_display_crtc *dispc = &disp->crtc[i];
+ nouveau_bo_vma_del(dispc->sem.bo, &pch->dispc_vma[i]);
+ }
+ }
+
+ chan->engctx[engine] = NULL;
+ kfree(pch);
+}
+
+static int
+nvc0_software_object_new(struct nouveau_channel *chan, int engine,
+ u32 handle, u16 class)
+{
+ return 0;
+}
+
+static int
+nvc0_software_init(struct drm_device *dev, int engine)
+{
+ return 0;
+}
+
+static int
+nvc0_software_fini(struct drm_device *dev, int engine, bool suspend)
+{
+ return 0;
+}
+
+static void
+nvc0_software_destroy(struct drm_device *dev, int engine)
+{
+ struct nvc0_software_priv *psw = nv_engine(dev, engine);
+
+ NVOBJ_ENGINE_DEL(dev, SW);
+ kfree(psw);
+}
+
+int
+nvc0_software_create(struct drm_device *dev)
+{
+ struct nvc0_software_priv *psw = kzalloc(sizeof(*psw), GFP_KERNEL);
+ if (!psw)
+ return -ENOMEM;
+
+ psw->base.base.destroy = nvc0_software_destroy;
+ psw->base.base.init = nvc0_software_init;
+ psw->base.base.fini = nvc0_software_fini;
+ psw->base.base.context_new = nvc0_software_context_new;
+ psw->base.base.context_del = nvc0_software_context_del;
+ psw->base.base.object_new = nvc0_software_object_new;
+ nouveau_software_create(&psw->base);
+
+ NVOBJ_ENGINE_ADD(dev, SW, &psw->base.base);
+ NVOBJ_CLASS(dev, 0x906e, SW);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c
index 0247250939e8..c486d3ce3c2c 100644
--- a/drivers/gpu/drm/nouveau/nvd0_display.c
+++ b/drivers/gpu/drm/nouveau/nvd0_display.c
@@ -33,6 +33,7 @@
#include "nouveau_crtc.h"
#include "nouveau_dma.h"
#include "nouveau_fb.h"
+#include "nouveau_software.h"
#include "nv50_display.h"
#define EVO_DMA_NR 9
@@ -284,8 +285,6 @@ nvd0_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
u32 *push;
int ret;
- evo_sync(crtc->dev, EVO_MASTER);
-
swap_interval <<= 4;
if (swap_interval == 0)
swap_interval |= 0x100;
@@ -300,15 +299,16 @@ nvd0_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
if (ret)
return ret;
- offset = chan->dispc_vma[nv_crtc->index].offset;
+
+ offset = nvc0_software_crtc(chan, nv_crtc->index);
offset += evo->sem.offset;
- BEGIN_NVC0(chan, 2, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
+ BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
OUT_RING (chan, upper_32_bits(offset));
OUT_RING (chan, lower_32_bits(offset));
OUT_RING (chan, 0xf00d0000 | evo->sem.value);
OUT_RING (chan, 0x1002);
- BEGIN_NVC0(chan, 2, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
+ BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
OUT_RING (chan, upper_32_bits(offset));
OUT_RING (chan, lower_32_bits(offset ^ 0x10));
OUT_RING (chan, 0x74b1e000);
@@ -882,7 +882,7 @@ nvd0_crtc_create(struct drm_device *dev, int index)
drm_mode_crtc_set_gamma_size(crtc, 256);
ret = nouveau_bo_new(dev, 64 * 64 * 4, 0x100, TTM_PL_FLAG_VRAM,
- 0, 0x0000, &nv_crtc->cursor.nvbo);
+ 0, 0x0000, NULL, &nv_crtc->cursor.nvbo);
if (!ret) {
ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
if (!ret)
@@ -895,7 +895,7 @@ nvd0_crtc_create(struct drm_device *dev, int index)
goto out;
ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM,
- 0, 0x0000, &nv_crtc->lut.nvbo);
+ 0, 0x0000, NULL, &nv_crtc->lut.nvbo);
if (!ret) {
ret = nouveau_bo_pin(nv_crtc->lut.nvbo, TTM_PL_FLAG_VRAM);
if (!ret)
@@ -2030,7 +2030,7 @@ nvd0_display_create(struct drm_device *dev)
/* small shared memory area we use for notifiers and semaphores */
ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
- 0, 0x0000, &disp->sync);
+ 0, 0x0000, NULL, &disp->sync);
if (!ret) {
ret = nouveau_bo_pin(disp->sync, TTM_PL_FLAG_VRAM);
if (!ret)
diff --git a/drivers/gpu/drm/nouveau/nve0_fifo.c b/drivers/gpu/drm/nouveau/nve0_fifo.c
new file mode 100644
index 000000000000..1855ecbd843b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nve0_fifo.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+#include "nouveau_mm.h"
+#include "nouveau_fifo.h"
+
+#define NVE0_FIFO_ENGINE_NUM 32
+
+static void nve0_fifo_isr(struct drm_device *);
+
+struct nve0_fifo_engine {
+ struct nouveau_gpuobj *playlist[2];
+ int cur_playlist;
+};
+
+struct nve0_fifo_priv {
+ struct nouveau_fifo_priv base;
+ struct nve0_fifo_engine engine[NVE0_FIFO_ENGINE_NUM];
+ struct {
+ struct nouveau_gpuobj *mem;
+ struct nouveau_vma bar;
+ } user;
+ int spoon_nr;
+};
+
+struct nve0_fifo_chan {
+ struct nouveau_fifo_chan base;
+ u32 engine;
+};
+
+static void
+nve0_fifo_playlist_update(struct drm_device *dev, u32 engine)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
+ struct nve0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
+ struct nve0_fifo_engine *peng = &priv->engine[engine];
+ struct nouveau_gpuobj *cur;
+ u32 match = (engine << 16) | 0x00000001;
+ int ret, i, p;
+
+ cur = peng->playlist[peng->cur_playlist];
+ if (unlikely(cur == NULL)) {
+ ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 0x1000, 0, &cur);
+ if (ret) {
+ NV_ERROR(dev, "PFIFO: playlist alloc failed\n");
+ return;
+ }
+
+ peng->playlist[peng->cur_playlist] = cur;
+ }
+
+ peng->cur_playlist = !peng->cur_playlist;
+
+ for (i = 0, p = 0; i < priv->base.channels; i++) {
+ u32 ctrl = nv_rd32(dev, 0x800004 + (i * 8)) & 0x001f0001;
+ if (ctrl != match)
+ continue;
+ nv_wo32(cur, p + 0, i);
+ nv_wo32(cur, p + 4, 0x00000000);
+ p += 8;
+ }
+ pinstmem->flush(dev);
+
+ nv_wr32(dev, 0x002270, cur->vinst >> 12);
+ nv_wr32(dev, 0x002274, (engine << 20) | (p >> 3));
+ if (!nv_wait(dev, 0x002284 + (engine * 4), 0x00100000, 0x00000000))
+ NV_ERROR(dev, "PFIFO: playlist %d update timeout\n", engine);
+}
+
+static int
+nve0_fifo_context_new(struct nouveau_channel *chan, int engine)
+{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
+ struct nve0_fifo_priv *priv = nv_engine(dev, engine);
+ struct nve0_fifo_chan *fctx;
+ u64 usermem = priv->user.mem->vinst + chan->id * 512;
+ u64 ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4;
+ int ret = 0, i;
+
+ fctx = chan->engctx[engine] = kzalloc(sizeof(*fctx), GFP_KERNEL);
+ if (!fctx)
+ return -ENOMEM;
+
+ fctx->engine = 0; /* PGRAPH */
+
+ /* allocate vram for control regs, map into polling area */
+ chan->user = ioremap_wc(pci_resource_start(dev->pdev, 1) +
+ priv->user.bar.offset + (chan->id * 512), 512);
+ if (!chan->user) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ for (i = 0; i < 0x100; i += 4)
+ nv_wo32(chan->ramin, i, 0x00000000);
+ nv_wo32(chan->ramin, 0x08, lower_32_bits(usermem));
+ nv_wo32(chan->ramin, 0x0c, upper_32_bits(usermem));
+ nv_wo32(chan->ramin, 0x10, 0x0000face);
+ nv_wo32(chan->ramin, 0x30, 0xfffff902);
+ nv_wo32(chan->ramin, 0x48, lower_32_bits(ib_virt));
+ nv_wo32(chan->ramin, 0x4c, drm_order(chan->dma.ib_max + 1) << 16 |
+ upper_32_bits(ib_virt));
+ nv_wo32(chan->ramin, 0x84, 0x20400000);
+ nv_wo32(chan->ramin, 0x94, 0x30000001);
+ nv_wo32(chan->ramin, 0x9c, 0x00000100);
+ nv_wo32(chan->ramin, 0xac, 0x0000001f);
+ nv_wo32(chan->ramin, 0xe4, 0x00000000);
+ nv_wo32(chan->ramin, 0xe8, chan->id);
+ nv_wo32(chan->ramin, 0xf8, 0x10003080); /* 0x002310 */
+ nv_wo32(chan->ramin, 0xfc, 0x10000010); /* 0x002350 */
+ pinstmem->flush(dev);
+
+ nv_wr32(dev, 0x800000 + (chan->id * 8), 0x80000000 |
+ (chan->ramin->vinst >> 12));
+ nv_mask(dev, 0x800004 + (chan->id * 8), 0x00000400, 0x00000400);
+ nve0_fifo_playlist_update(dev, fctx->engine);
+ nv_mask(dev, 0x800004 + (chan->id * 8), 0x00000400, 0x00000400);
+
+error:
+ if (ret)
+ priv->base.base.context_del(chan, engine);
+ return ret;
+}
+
+static void
+nve0_fifo_context_del(struct nouveau_channel *chan, int engine)
+{
+ struct nve0_fifo_chan *fctx = chan->engctx[engine];
+ struct drm_device *dev = chan->dev;
+
+ nv_mask(dev, 0x800004 + (chan->id * 8), 0x00000800, 0x00000800);
+ nv_wr32(dev, 0x002634, chan->id);
+ if (!nv_wait(dev, 0x0002634, 0xffffffff, chan->id))
+ NV_WARN(dev, "0x2634 != chid: 0x%08x\n", nv_rd32(dev, 0x2634));
+ nve0_fifo_playlist_update(dev, fctx->engine);
+ nv_wr32(dev, 0x800000 + (chan->id * 8), 0x00000000);
+
+ if (chan->user) {
+ iounmap(chan->user);
+ chan->user = NULL;
+ }
+
+ chan->engctx[NVOBJ_ENGINE_FIFO] = NULL;
+ kfree(fctx);
+}
+
+static int
+nve0_fifo_init(struct drm_device *dev, int engine)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nve0_fifo_priv *priv = nv_engine(dev, engine);
+ struct nve0_fifo_chan *fctx;
+ int i;
+
+ /* reset PFIFO, enable all available PSUBFIFO areas */
+ nv_mask(dev, 0x000200, 0x00000100, 0x00000000);
+ nv_mask(dev, 0x000200, 0x00000100, 0x00000100);
+ nv_wr32(dev, 0x000204, 0xffffffff);
+
+ priv->spoon_nr = hweight32(nv_rd32(dev, 0x000204));
+ NV_DEBUG(dev, "PFIFO: %d subfifo(s)\n", priv->spoon_nr);
+
+ /* PSUBFIFO[n] */
+ for (i = 0; i < priv->spoon_nr; i++) {
+ nv_mask(dev, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
+ nv_wr32(dev, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
+ nv_wr32(dev, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTR_EN */
+ }
+
+ nv_wr32(dev, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
+
+ nv_wr32(dev, 0x002a00, 0xffffffff);
+ nv_wr32(dev, 0x002100, 0xffffffff);
+ nv_wr32(dev, 0x002140, 0xbfffffff);
+
+ /* restore PFIFO context table */
+ for (i = 0; i < priv->base.channels; i++) {
+ struct nouveau_channel *chan = dev_priv->channels.ptr[i];
+ if (!chan || !(fctx = chan->engctx[engine]))
+ continue;
+
+ nv_wr32(dev, 0x800000 + (i * 8), 0x80000000 |
+ (chan->ramin->vinst >> 12));
+ nv_mask(dev, 0x800004 + (i * 8), 0x00000400, 0x00000400);
+ nve0_fifo_playlist_update(dev, fctx->engine);
+ nv_mask(dev, 0x800004 + (i * 8), 0x00000400, 0x00000400);
+ }
+
+ return 0;
+}
+
+static int
+nve0_fifo_fini(struct drm_device *dev, int engine, bool suspend)
+{
+ struct nve0_fifo_priv *priv = nv_engine(dev, engine);
+ int i;
+
+ for (i = 0; i < priv->base.channels; i++) {
+ if (!(nv_rd32(dev, 0x800004 + (i * 8)) & 1))
+ continue;
+
+ nv_mask(dev, 0x800004 + (i * 8), 0x00000800, 0x00000800);
+ nv_wr32(dev, 0x002634, i);
+ if (!nv_wait(dev, 0x002634, 0xffffffff, i)) {
+ NV_INFO(dev, "PFIFO: kick ch %d failed: 0x%08x\n",
+ i, nv_rd32(dev, 0x002634));
+ return -EBUSY;
+ }
+ }
+
+ nv_wr32(dev, 0x002140, 0x00000000);
+ return 0;
+}
+
+struct nouveau_enum nve0_fifo_fault_unit[] = {
+ {}
+};
+
+struct nouveau_enum nve0_fifo_fault_reason[] = {
+ { 0x00, "PT_NOT_PRESENT" },
+ { 0x01, "PT_TOO_SHORT" },
+ { 0x02, "PAGE_NOT_PRESENT" },
+ { 0x03, "VM_LIMIT_EXCEEDED" },
+ { 0x04, "NO_CHANNEL" },
+ { 0x05, "PAGE_SYSTEM_ONLY" },
+ { 0x06, "PAGE_READ_ONLY" },
+ { 0x0a, "COMPRESSED_SYSRAM" },
+ { 0x0c, "INVALID_STORAGE_TYPE" },
+ {}
+};
+
+struct nouveau_enum nve0_fifo_fault_hubclient[] = {
+ {}
+};
+
+struct nouveau_enum nve0_fifo_fault_gpcclient[] = {
+ {}
+};
+
+struct nouveau_bitfield nve0_fifo_subfifo_intr[] = {
+ { 0x00200000, "ILLEGAL_MTHD" },
+ { 0x00800000, "EMPTY_SUBC" },
+ {}
+};
+
+static void
+nve0_fifo_isr_vm_fault(struct drm_device *dev, int unit)
+{
+ u32 inst = nv_rd32(dev, 0x2800 + (unit * 0x10));
+ u32 valo = nv_rd32(dev, 0x2804 + (unit * 0x10));
+ u32 vahi = nv_rd32(dev, 0x2808 + (unit * 0x10));
+ u32 stat = nv_rd32(dev, 0x280c + (unit * 0x10));
+ u32 client = (stat & 0x00001f00) >> 8;
+
+ NV_INFO(dev, "PFIFO: %s fault at 0x%010llx [",
+ (stat & 0x00000080) ? "write" : "read", (u64)vahi << 32 | valo);
+ nouveau_enum_print(nve0_fifo_fault_reason, stat & 0x0000000f);
+ printk("] from ");
+ nouveau_enum_print(nve0_fifo_fault_unit, unit);
+ if (stat & 0x00000040) {
+ printk("/");
+ nouveau_enum_print(nve0_fifo_fault_hubclient, client);
+ } else {
+ printk("/GPC%d/", (stat & 0x1f000000) >> 24);
+ nouveau_enum_print(nve0_fifo_fault_gpcclient, client);
+ }
+ printk(" on channel 0x%010llx\n", (u64)inst << 12);
+}
+
+static void
+nve0_fifo_isr_subfifo_intr(struct drm_device *dev, int unit)
+{
+ u32 stat = nv_rd32(dev, 0x040108 + (unit * 0x2000));
+ u32 addr = nv_rd32(dev, 0x0400c0 + (unit * 0x2000));
+ u32 data = nv_rd32(dev, 0x0400c4 + (unit * 0x2000));
+ u32 chid = nv_rd32(dev, 0x040120 + (unit * 0x2000)) & 0x7f;
+ u32 subc = (addr & 0x00070000);
+ u32 mthd = (addr & 0x00003ffc);
+
+ NV_INFO(dev, "PSUBFIFO %d:", unit);
+ nouveau_bitfield_print(nve0_fifo_subfifo_intr, stat);
+ NV_INFO(dev, "PSUBFIFO %d: ch %d subc %d mthd 0x%04x data 0x%08x\n",
+ unit, chid, subc, mthd, data);
+
+ nv_wr32(dev, 0x0400c0 + (unit * 0x2000), 0x80600008);
+ nv_wr32(dev, 0x040108 + (unit * 0x2000), stat);
+}
+
+static void
+nve0_fifo_isr(struct drm_device *dev)
+{
+ u32 stat = nv_rd32(dev, 0x002100);
+
+ if (stat & 0x00000100) {
+ NV_INFO(dev, "PFIFO: unknown status 0x00000100\n");
+ nv_wr32(dev, 0x002100, 0x00000100);
+ stat &= ~0x00000100;
+ }
+
+ if (stat & 0x10000000) {
+ u32 units = nv_rd32(dev, 0x00259c);
+ u32 u = units;
+
+ while (u) {
+ int i = ffs(u) - 1;
+ nve0_fifo_isr_vm_fault(dev, i);
+ u &= ~(1 << i);
+ }
+
+ nv_wr32(dev, 0x00259c, units);
+ stat &= ~0x10000000;
+ }
+
+ if (stat & 0x20000000) {
+ u32 units = nv_rd32(dev, 0x0025a0);
+ u32 u = units;
+
+ while (u) {
+ int i = ffs(u) - 1;
+ nve0_fifo_isr_subfifo_intr(dev, i);
+ u &= ~(1 << i);
+ }
+
+ nv_wr32(dev, 0x0025a0, units);
+ stat &= ~0x20000000;
+ }
+
+ if (stat & 0x40000000) {
+ NV_INFO(dev, "PFIFO: unknown status 0x40000000\n");
+ nv_mask(dev, 0x002a00, 0x00000000, 0x00000000);
+ stat &= ~0x40000000;
+ }
+
+ if (stat) {
+ NV_INFO(dev, "PFIFO: unhandled status 0x%08x\n", stat);
+ nv_wr32(dev, 0x002100, stat);
+ nv_wr32(dev, 0x002140, 0);
+ }
+}
+
+static void
+nve0_fifo_destroy(struct drm_device *dev, int engine)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nve0_fifo_priv *priv = nv_engine(dev, engine);
+ int i;
+
+ nouveau_vm_put(&priv->user.bar);
+ nouveau_gpuobj_ref(NULL, &priv->user.mem);
+
+ for (i = 0; i < NVE0_FIFO_ENGINE_NUM; i++) {
+ nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[0]);
+ nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[1]);
+ }
+
+ dev_priv->eng[engine] = NULL;
+ kfree(priv);
+}
+
+int
+nve0_fifo_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nve0_fifo_priv *priv;
+ int ret;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base.base.destroy = nve0_fifo_destroy;
+ priv->base.base.init = nve0_fifo_init;
+ priv->base.base.fini = nve0_fifo_fini;
+ priv->base.base.context_new = nve0_fifo_context_new;
+ priv->base.base.context_del = nve0_fifo_context_del;
+ priv->base.channels = 4096;
+ dev_priv->eng[NVOBJ_ENGINE_FIFO] = &priv->base.base;
+
+ ret = nouveau_gpuobj_new(dev, NULL, priv->base.channels * 512, 0x1000,
+ NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem);
+ if (ret)
+ goto error;
+
+ ret = nouveau_vm_get(dev_priv->bar1_vm, priv->user.mem->size,
+ 12, NV_MEM_ACCESS_RW, &priv->user.bar);
+ if (ret)
+ goto error;
+
+ nouveau_vm_map(&priv->user.bar, *(struct nouveau_mem **)priv->user.mem->node);
+
+ nouveau_irq_register(dev, 8, nve0_fifo_isr);
+error:
+ if (ret)
+ priv->base.base.destroy(dev, NVOBJ_ENGINE_FIFO);
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nve0_graph.c b/drivers/gpu/drm/nouveau/nve0_graph.c
new file mode 100644
index 000000000000..8a8051b68f10
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nve0_graph.c
@@ -0,0 +1,831 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <linux/firmware.h>
+#include <linux/module.h>
+
+#include "drmP.h"
+
+#include "nouveau_drv.h"
+#include "nouveau_mm.h"
+#include "nouveau_fifo.h"
+
+#include "nve0_graph.h"
+
+static void
+nve0_graph_ctxctl_debug_unit(struct drm_device *dev, u32 base)
+{
+ NV_INFO(dev, "PGRAPH: %06x - done 0x%08x\n", base,
+ nv_rd32(dev, base + 0x400));
+ NV_INFO(dev, "PGRAPH: %06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
+ nv_rd32(dev, base + 0x800), nv_rd32(dev, base + 0x804),
+ nv_rd32(dev, base + 0x808), nv_rd32(dev, base + 0x80c));
+ NV_INFO(dev, "PGRAPH: %06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
+ nv_rd32(dev, base + 0x810), nv_rd32(dev, base + 0x814),
+ nv_rd32(dev, base + 0x818), nv_rd32(dev, base + 0x81c));
+}
+
+static void
+nve0_graph_ctxctl_debug(struct drm_device *dev)
+{
+ u32 gpcnr = nv_rd32(dev, 0x409604) & 0xffff;
+ u32 gpc;
+
+ nve0_graph_ctxctl_debug_unit(dev, 0x409000);
+ for (gpc = 0; gpc < gpcnr; gpc++)
+ nve0_graph_ctxctl_debug_unit(dev, 0x502000 + (gpc * 0x8000));
+}
+
+static int
+nve0_graph_load_context(struct nouveau_channel *chan)
+{
+ struct drm_device *dev = chan->dev;
+
+ nv_wr32(dev, 0x409840, 0x00000030);
+ nv_wr32(dev, 0x409500, 0x80000000 | chan->ramin->vinst >> 12);
+ nv_wr32(dev, 0x409504, 0x00000003);
+ if (!nv_wait(dev, 0x409800, 0x00000010, 0x00000010))
+ NV_ERROR(dev, "PGRAPH: load_ctx timeout\n");
+
+ return 0;
+}
+
+static int
+nve0_graph_unload_context_to(struct drm_device *dev, u64 chan)
+{
+ nv_wr32(dev, 0x409840, 0x00000003);
+ nv_wr32(dev, 0x409500, 0x80000000 | chan >> 12);
+ nv_wr32(dev, 0x409504, 0x00000009);
+ if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000000)) {
+ NV_ERROR(dev, "PGRAPH: unload_ctx timeout\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int
+nve0_graph_construct_context(struct nouveau_channel *chan)
+{
+ struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+ struct nve0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR);
+ struct nve0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR];
+ struct drm_device *dev = chan->dev;
+ int ret, i;
+ u32 *ctx;
+
+ ctx = kmalloc(priv->grctx_size, GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ nve0_graph_load_context(chan);
+
+ nv_wo32(grch->grctx, 0x1c, 1);
+ nv_wo32(grch->grctx, 0x20, 0);
+ nv_wo32(grch->grctx, 0x28, 0);
+ nv_wo32(grch->grctx, 0x2c, 0);
+ dev_priv->engine.instmem.flush(dev);
+
+ ret = nve0_grctx_generate(chan);
+ if (ret)
+ goto err;
+
+ ret = nve0_graph_unload_context_to(dev, chan->ramin->vinst);
+ if (ret)
+ goto err;
+
+ for (i = 0; i < priv->grctx_size; i += 4)
+ ctx[i / 4] = nv_ro32(grch->grctx, i);
+
+ priv->grctx_vals = ctx;
+ return 0;
+
+err:
+ kfree(ctx);
+ return ret;
+}
+
+static int
+nve0_graph_create_context_mmio_list(struct nouveau_channel *chan)
+{
+ struct nve0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR);
+ struct nve0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR];
+ struct drm_device *dev = chan->dev;
+ u32 magic[GPC_MAX][2];
+ u16 offset = 0x0000;
+ int gpc;
+ int ret;
+
+ ret = nouveau_gpuobj_new(dev, chan, 0x3000, 256, NVOBJ_FLAG_VM,
+ &grch->unk408004);
+ if (ret)
+ return ret;
+
+ ret = nouveau_gpuobj_new(dev, chan, 0x8000, 256, NVOBJ_FLAG_VM,
+ &grch->unk40800c);
+ if (ret)
+ return ret;
+
+ ret = nouveau_gpuobj_new(dev, chan, 384 * 1024, 4096,
+ NVOBJ_FLAG_VM | NVOBJ_FLAG_VM_USER,
+ &grch->unk418810);
+ if (ret)
+ return ret;
+
+ ret = nouveau_gpuobj_new(dev, chan, 0x1000, 0, NVOBJ_FLAG_VM,
+ &grch->mmio);
+ if (ret)
+ return ret;
+
+#define mmio(r,v) do { \
+ nv_wo32(grch->mmio, (grch->mmio_nr * 8) + 0, (r)); \
+ nv_wo32(grch->mmio, (grch->mmio_nr * 8) + 4, (v)); \
+ grch->mmio_nr++; \
+} while (0)
+ mmio(0x40800c, grch->unk40800c->linst >> 8);
+ mmio(0x408010, 0x80000000);
+ mmio(0x419004, grch->unk40800c->linst >> 8);
+ mmio(0x419008, 0x00000000);
+ mmio(0x4064cc, 0x80000000);
+ mmio(0x408004, grch->unk408004->linst >> 8);
+ mmio(0x408008, 0x80000030);
+ mmio(0x418808, grch->unk408004->linst >> 8);
+ mmio(0x41880c, 0x80000030);
+ mmio(0x4064c8, 0x01800600);
+ mmio(0x418810, 0x80000000 | grch->unk418810->linst >> 12);
+ mmio(0x419848, 0x10000000 | grch->unk418810->linst >> 12);
+ mmio(0x405830, 0x02180648);
+ mmio(0x4064c4, 0x0192ffff);
+
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ u16 magic0 = 0x0218 * priv->tpc_nr[gpc];
+ u16 magic1 = 0x0648 * priv->tpc_nr[gpc];
+ magic[gpc][0] = 0x10000000 | (magic0 << 16) | offset;
+ magic[gpc][1] = 0x00000000 | (magic1 << 16);
+ offset += 0x0324 * priv->tpc_nr[gpc];
+ }
+
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ mmio(GPC_UNIT(gpc, 0x30c0), magic[gpc][0]);
+ mmio(GPC_UNIT(gpc, 0x30e4), magic[gpc][1] | offset);
+ offset += 0x07ff * priv->tpc_nr[gpc];
+ }
+
+ mmio(0x17e91c, 0x06060609);
+ mmio(0x17e920, 0x00090a05);
+#undef mmio
+ return 0;
+}
+
+static int
+nve0_graph_context_new(struct nouveau_channel *chan, int engine)
+{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
+ struct nve0_graph_priv *priv = nv_engine(dev, engine);
+ struct nve0_graph_chan *grch;
+ struct nouveau_gpuobj *grctx;
+ int ret, i;
+
+ grch = kzalloc(sizeof(*grch), GFP_KERNEL);
+ if (!grch)
+ return -ENOMEM;
+ chan->engctx[NVOBJ_ENGINE_GR] = grch;
+
+ ret = nouveau_gpuobj_new(dev, chan, priv->grctx_size, 256,
+ NVOBJ_FLAG_VM | NVOBJ_FLAG_ZERO_ALLOC,
+ &grch->grctx);
+ if (ret)
+ goto error;
+ grctx = grch->grctx;
+
+ ret = nve0_graph_create_context_mmio_list(chan);
+ if (ret)
+ goto error;
+
+ nv_wo32(chan->ramin, 0x0210, lower_32_bits(grctx->linst) | 4);
+ nv_wo32(chan->ramin, 0x0214, upper_32_bits(grctx->linst));
+ pinstmem->flush(dev);
+
+ if (!priv->grctx_vals) {
+ ret = nve0_graph_construct_context(chan);
+ if (ret)
+ goto error;
+ }
+
+ for (i = 0; i < priv->grctx_size; i += 4)
+ nv_wo32(grctx, i, priv->grctx_vals[i / 4]);
+ nv_wo32(grctx, 0xf4, 0);
+ nv_wo32(grctx, 0xf8, 0);
+ nv_wo32(grctx, 0x10, grch->mmio_nr);
+ nv_wo32(grctx, 0x14, lower_32_bits(grch->mmio->linst));
+ nv_wo32(grctx, 0x18, upper_32_bits(grch->mmio->linst));
+ nv_wo32(grctx, 0x1c, 1);
+ nv_wo32(grctx, 0x20, 0);
+ nv_wo32(grctx, 0x28, 0);
+ nv_wo32(grctx, 0x2c, 0);
+
+ pinstmem->flush(dev);
+ return 0;
+
+error:
+ priv->base.context_del(chan, engine);
+ return ret;
+}
+
+static void
+nve0_graph_context_del(struct nouveau_channel *chan, int engine)
+{
+ struct nve0_graph_chan *grch = chan->engctx[engine];
+
+ nouveau_gpuobj_ref(NULL, &grch->mmio);
+ nouveau_gpuobj_ref(NULL, &grch->unk418810);
+ nouveau_gpuobj_ref(NULL, &grch->unk40800c);
+ nouveau_gpuobj_ref(NULL, &grch->unk408004);
+ nouveau_gpuobj_ref(NULL, &grch->grctx);
+ chan->engctx[engine] = NULL;
+}
+
+static int
+nve0_graph_object_new(struct nouveau_channel *chan, int engine,
+ u32 handle, u16 class)
+{
+ return 0;
+}
+
+static int
+nve0_graph_fini(struct drm_device *dev, int engine, bool suspend)
+{
+ return 0;
+}
+
+static void
+nve0_graph_init_obj418880(struct drm_device *dev)
+{
+ struct nve0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
+ int i;
+
+ nv_wr32(dev, GPC_BCAST(0x0880), 0x00000000);
+ nv_wr32(dev, GPC_BCAST(0x08a4), 0x00000000);
+ for (i = 0; i < 4; i++)
+ nv_wr32(dev, GPC_BCAST(0x0888) + (i * 4), 0x00000000);
+ nv_wr32(dev, GPC_BCAST(0x08b4), priv->unk4188b4->vinst >> 8);
+ nv_wr32(dev, GPC_BCAST(0x08b8), priv->unk4188b8->vinst >> 8);
+}
+
+static void
+nve0_graph_init_regs(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x400080, 0x003083c2);
+ nv_wr32(dev, 0x400088, 0x0001ffe7);
+ nv_wr32(dev, 0x40008c, 0x00000000);
+ nv_wr32(dev, 0x400090, 0x00000030);
+ nv_wr32(dev, 0x40013c, 0x003901f7);
+ nv_wr32(dev, 0x400140, 0x00000100);
+ nv_wr32(dev, 0x400144, 0x00000000);
+ nv_wr32(dev, 0x400148, 0x00000110);
+ nv_wr32(dev, 0x400138, 0x00000000);
+ nv_wr32(dev, 0x400130, 0x00000000);
+ nv_wr32(dev, 0x400134, 0x00000000);
+ nv_wr32(dev, 0x400124, 0x00000002);
+}
+
+static void
+nve0_graph_init_units(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x409ffc, 0x00000000);
+ nv_wr32(dev, 0x409c14, 0x00003e3e);
+ nv_wr32(dev, 0x409c24, 0x000f0000);
+
+ nv_wr32(dev, 0x404000, 0xc0000000);
+ nv_wr32(dev, 0x404600, 0xc0000000);
+ nv_wr32(dev, 0x408030, 0xc0000000);
+ nv_wr32(dev, 0x404490, 0xc0000000);
+ nv_wr32(dev, 0x406018, 0xc0000000);
+ nv_wr32(dev, 0x407020, 0xc0000000);
+ nv_wr32(dev, 0x405840, 0xc0000000);
+ nv_wr32(dev, 0x405844, 0x00ffffff);
+
+ nv_mask(dev, 0x419cc0, 0x00000008, 0x00000008);
+ nv_mask(dev, 0x419eb4, 0x00001000, 0x00001000);
+
+}
+
+static void
+nve0_graph_init_gpc_0(struct drm_device *dev)
+{
+ struct nve0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
+ const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
+ u32 data[TPC_MAX / 8];
+ u8 tpcnr[GPC_MAX];
+ int i, gpc, tpc;
+
+ nv_wr32(dev, GPC_UNIT(0, 0x3018), 0x00000001);
+
+ memset(data, 0x00, sizeof(data));
+ memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+ for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
+ do {
+ gpc = (gpc + 1) % priv->gpc_nr;
+ } while (!tpcnr[gpc]);
+ tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
+
+ data[i / 8] |= tpc << ((i % 8) * 4);
+ }
+
+ nv_wr32(dev, GPC_BCAST(0x0980), data[0]);
+ nv_wr32(dev, GPC_BCAST(0x0984), data[1]);
+ nv_wr32(dev, GPC_BCAST(0x0988), data[2]);
+ nv_wr32(dev, GPC_BCAST(0x098c), data[3]);
+
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ nv_wr32(dev, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 |
+ priv->tpc_nr[gpc]);
+ nv_wr32(dev, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tpc_total);
+ nv_wr32(dev, GPC_UNIT(gpc, 0x0918), magicgpc918);
+ }
+
+ nv_wr32(dev, GPC_BCAST(0x1bd4), magicgpc918);
+ nv_wr32(dev, GPC_BCAST(0x08ac), nv_rd32(dev, 0x100800));
+}
+
+static void
+nve0_graph_init_gpc_1(struct drm_device *dev)
+{
+ struct nve0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
+ int gpc, tpc;
+
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ nv_wr32(dev, GPC_UNIT(gpc, 0x3038), 0xc0000000);
+ nv_wr32(dev, GPC_UNIT(gpc, 0x0420), 0xc0000000);
+ nv_wr32(dev, GPC_UNIT(gpc, 0x0900), 0xc0000000);
+ nv_wr32(dev, GPC_UNIT(gpc, 0x1028), 0xc0000000);
+ nv_wr32(dev, GPC_UNIT(gpc, 0x0824), 0xc0000000);
+ for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+ nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
+ nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
+ nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
+ nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
+ nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
+ nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
+ nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
+ }
+ nv_wr32(dev, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
+ nv_wr32(dev, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
+ }
+}
+
+static void
+nve0_graph_init_rop(struct drm_device *dev)
+{
+ struct nve0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
+ int rop;
+
+ for (rop = 0; rop < priv->rop_nr; rop++) {
+ nv_wr32(dev, ROP_UNIT(rop, 0x144), 0xc0000000);
+ nv_wr32(dev, ROP_UNIT(rop, 0x070), 0xc0000000);
+ nv_wr32(dev, ROP_UNIT(rop, 0x204), 0xffffffff);
+ nv_wr32(dev, ROP_UNIT(rop, 0x208), 0xffffffff);
+ }
+}
+
+static void
+nve0_graph_init_fuc(struct drm_device *dev, u32 fuc_base,
+ struct nve0_graph_fuc *code, struct nve0_graph_fuc *data)
+{
+ int i;
+
+ nv_wr32(dev, fuc_base + 0x01c0, 0x01000000);
+ for (i = 0; i < data->size / 4; i++)
+ nv_wr32(dev, fuc_base + 0x01c4, data->data[i]);
+
+ nv_wr32(dev, fuc_base + 0x0180, 0x01000000);
+ for (i = 0; i < code->size / 4; i++) {
+ if ((i & 0x3f) == 0)
+ nv_wr32(dev, fuc_base + 0x0188, i >> 6);
+ nv_wr32(dev, fuc_base + 0x0184, code->data[i]);
+ }
+}
+
+static int
+nve0_graph_init_ctxctl(struct drm_device *dev)
+{
+ struct nve0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
+ u32 r000260;
+
+ /* load fuc microcode */
+ r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000);
+ nve0_graph_init_fuc(dev, 0x409000, &priv->fuc409c, &priv->fuc409d);
+ nve0_graph_init_fuc(dev, 0x41a000, &priv->fuc41ac, &priv->fuc41ad);
+ nv_wr32(dev, 0x000260, r000260);
+
+ /* start both of them running */
+ nv_wr32(dev, 0x409840, 0xffffffff);
+ nv_wr32(dev, 0x41a10c, 0x00000000);
+ nv_wr32(dev, 0x40910c, 0x00000000);
+ nv_wr32(dev, 0x41a100, 0x00000002);
+ nv_wr32(dev, 0x409100, 0x00000002);
+ if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000001))
+ NV_INFO(dev, "0x409800 wait failed\n");
+
+ nv_wr32(dev, 0x409840, 0xffffffff);
+ nv_wr32(dev, 0x409500, 0x7fffffff);
+ nv_wr32(dev, 0x409504, 0x00000021);
+
+ nv_wr32(dev, 0x409840, 0xffffffff);
+ nv_wr32(dev, 0x409500, 0x00000000);
+ nv_wr32(dev, 0x409504, 0x00000010);
+ if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
+ NV_ERROR(dev, "fuc09 req 0x10 timeout\n");
+ return -EBUSY;
+ }
+ priv->grctx_size = nv_rd32(dev, 0x409800);
+
+ nv_wr32(dev, 0x409840, 0xffffffff);
+ nv_wr32(dev, 0x409500, 0x00000000);
+ nv_wr32(dev, 0x409504, 0x00000016);
+ if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
+ NV_ERROR(dev, "fuc09 req 0x16 timeout\n");
+ return -EBUSY;
+ }
+
+ nv_wr32(dev, 0x409840, 0xffffffff);
+ nv_wr32(dev, 0x409500, 0x00000000);
+ nv_wr32(dev, 0x409504, 0x00000025);
+ if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
+ NV_ERROR(dev, "fuc09 req 0x25 timeout\n");
+ return -EBUSY;
+ }
+
+ nv_wr32(dev, 0x409800, 0x00000000);
+ nv_wr32(dev, 0x409500, 0x00000001);
+ nv_wr32(dev, 0x409504, 0x00000030);
+ if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
+ NV_ERROR(dev, "fuc09 req 0x30 timeout\n");
+ return -EBUSY;
+ }
+
+ nv_wr32(dev, 0x409810, 0xb00095c8);
+ nv_wr32(dev, 0x409800, 0x00000000);
+ nv_wr32(dev, 0x409500, 0x00000001);
+ nv_wr32(dev, 0x409504, 0x00000031);
+ if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
+ NV_ERROR(dev, "fuc09 req 0x31 timeout\n");
+ return -EBUSY;
+ }
+
+ nv_wr32(dev, 0x409810, 0x00080420);
+ nv_wr32(dev, 0x409800, 0x00000000);
+ nv_wr32(dev, 0x409500, 0x00000001);
+ nv_wr32(dev, 0x409504, 0x00000032);
+ if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) {
+ NV_ERROR(dev, "fuc09 req 0x32 timeout\n");
+ return -EBUSY;
+ }
+
+ nv_wr32(dev, 0x409614, 0x00000070);
+ nv_wr32(dev, 0x409614, 0x00000770);
+ nv_wr32(dev, 0x40802c, 0x00000001);
+ return 0;
+}
+
+static int
+nve0_graph_init(struct drm_device *dev, int engine)
+{
+ int ret;
+
+ nv_mask(dev, 0x000200, 0x18001000, 0x00000000);
+ nv_mask(dev, 0x000200, 0x18001000, 0x18001000);
+
+ nve0_graph_init_obj418880(dev);
+ nve0_graph_init_regs(dev);
+ nve0_graph_init_gpc_0(dev);
+
+ nv_wr32(dev, 0x400500, 0x00010001);
+ nv_wr32(dev, 0x400100, 0xffffffff);
+ nv_wr32(dev, 0x40013c, 0xffffffff);
+
+ nve0_graph_init_units(dev);
+ nve0_graph_init_gpc_1(dev);
+ nve0_graph_init_rop(dev);
+
+ nv_wr32(dev, 0x400108, 0xffffffff);
+ nv_wr32(dev, 0x400138, 0xffffffff);
+ nv_wr32(dev, 0x400118, 0xffffffff);
+ nv_wr32(dev, 0x400130, 0xffffffff);
+ nv_wr32(dev, 0x40011c, 0xffffffff);
+ nv_wr32(dev, 0x400134, 0xffffffff);
+ nv_wr32(dev, 0x400054, 0x34ce3464);
+
+ ret = nve0_graph_init_ctxctl(dev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int
+nve0_graph_isr_chid(struct drm_device *dev, u64 inst)
+{
+ struct nouveau_fifo_priv *pfifo = nv_engine(dev, NVOBJ_ENGINE_FIFO);
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_channel *chan;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&dev_priv->channels.lock, flags);
+ for (i = 0; i < pfifo->channels; i++) {
+ chan = dev_priv->channels.ptr[i];
+ if (!chan || !chan->ramin)
+ continue;
+
+ if (inst == chan->ramin->vinst)
+ break;
+ }
+ spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
+ return i;
+}
+
+static void
+nve0_graph_ctxctl_isr(struct drm_device *dev)
+{
+ u32 ustat = nv_rd32(dev, 0x409c18);
+
+ if (ustat & 0x00000001)
+ NV_INFO(dev, "PGRAPH: CTXCTRL ucode error\n");
+ if (ustat & 0x00080000)
+ NV_INFO(dev, "PGRAPH: CTXCTRL watchdog timeout\n");
+ if (ustat & ~0x00080001)
+ NV_INFO(dev, "PGRAPH: CTXCTRL 0x%08x\n", ustat);
+
+ nve0_graph_ctxctl_debug(dev);
+ nv_wr32(dev, 0x409c20, ustat);
+}
+
+static void
+nve0_graph_trap_isr(struct drm_device *dev, int chid)
+{
+ struct nve0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
+ u32 trap = nv_rd32(dev, 0x400108);
+ int rop;
+
+ if (trap & 0x00000001) {
+ u32 stat = nv_rd32(dev, 0x404000);
+ NV_INFO(dev, "PGRAPH: DISPATCH ch %d 0x%08x\n", chid, stat);
+ nv_wr32(dev, 0x404000, 0xc0000000);
+ nv_wr32(dev, 0x400108, 0x00000001);
+ trap &= ~0x00000001;
+ }
+
+ if (trap & 0x00000010) {
+ u32 stat = nv_rd32(dev, 0x405840);
+ NV_INFO(dev, "PGRAPH: SHADER ch %d 0x%08x\n", chid, stat);
+ nv_wr32(dev, 0x405840, 0xc0000000);
+ nv_wr32(dev, 0x400108, 0x00000010);
+ trap &= ~0x00000010;
+ }
+
+ if (trap & 0x02000000) {
+ for (rop = 0; rop < priv->rop_nr; rop++) {
+ u32 statz = nv_rd32(dev, ROP_UNIT(rop, 0x070));
+ u32 statc = nv_rd32(dev, ROP_UNIT(rop, 0x144));
+ NV_INFO(dev, "PGRAPH: ROP%d ch %d 0x%08x 0x%08x\n",
+ rop, chid, statz, statc);
+ nv_wr32(dev, ROP_UNIT(rop, 0x070), 0xc0000000);
+ nv_wr32(dev, ROP_UNIT(rop, 0x144), 0xc0000000);
+ }
+ nv_wr32(dev, 0x400108, 0x02000000);
+ trap &= ~0x02000000;
+ }
+
+ if (trap) {
+ NV_INFO(dev, "PGRAPH: TRAP ch %d 0x%08x\n", chid, trap);
+ nv_wr32(dev, 0x400108, trap);
+ }
+}
+
+static void
+nve0_graph_isr(struct drm_device *dev)
+{
+ u64 inst = (u64)(nv_rd32(dev, 0x409b00) & 0x0fffffff) << 12;
+ u32 chid = nve0_graph_isr_chid(dev, inst);
+ u32 stat = nv_rd32(dev, 0x400100);
+ u32 addr = nv_rd32(dev, 0x400704);
+ u32 mthd = (addr & 0x00003ffc);
+ u32 subc = (addr & 0x00070000) >> 16;
+ u32 data = nv_rd32(dev, 0x400708);
+ u32 code = nv_rd32(dev, 0x400110);
+ u32 class = nv_rd32(dev, 0x404200 + (subc * 4));
+
+ if (stat & 0x00000010) {
+ if (nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) {
+ NV_INFO(dev, "PGRAPH: ILLEGAL_MTHD ch %d [0x%010llx] "
+ "subc %d class 0x%04x mthd 0x%04x "
+ "data 0x%08x\n",
+ chid, inst, subc, class, mthd, data);
+ }
+ nv_wr32(dev, 0x400100, 0x00000010);
+ stat &= ~0x00000010;
+ }
+
+ if (stat & 0x00000020) {
+ NV_INFO(dev, "PGRAPH: ILLEGAL_CLASS ch %d [0x%010llx] subc %d "
+ "class 0x%04x mthd 0x%04x data 0x%08x\n",
+ chid, inst, subc, class, mthd, data);
+ nv_wr32(dev, 0x400100, 0x00000020);
+ stat &= ~0x00000020;
+ }
+
+ if (stat & 0x00100000) {
+ NV_INFO(dev, "PGRAPH: DATA_ERROR [");
+ nouveau_enum_print(nv50_data_error_names, code);
+ printk("] ch %d [0x%010llx] subc %d class 0x%04x "
+ "mthd 0x%04x data 0x%08x\n",
+ chid, inst, subc, class, mthd, data);
+ nv_wr32(dev, 0x400100, 0x00100000);
+ stat &= ~0x00100000;
+ }
+
+ if (stat & 0x00200000) {
+ nve0_graph_trap_isr(dev, chid);
+ nv_wr32(dev, 0x400100, 0x00200000);
+ stat &= ~0x00200000;
+ }
+
+ if (stat & 0x00080000) {
+ nve0_graph_ctxctl_isr(dev);
+ nv_wr32(dev, 0x400100, 0x00080000);
+ stat &= ~0x00080000;
+ }
+
+ if (stat) {
+ NV_INFO(dev, "PGRAPH: unknown stat 0x%08x\n", stat);
+ nv_wr32(dev, 0x400100, stat);
+ }
+
+ nv_wr32(dev, 0x400500, 0x00010001);
+}
+
+static int
+nve0_graph_create_fw(struct drm_device *dev, const char *fwname,
+ struct nve0_graph_fuc *fuc)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ const struct firmware *fw;
+ char f[32];
+ int ret;
+
+ snprintf(f, sizeof(f), "nouveau/nv%02x_%s", dev_priv->chipset, fwname);
+ ret = request_firmware(&fw, f, &dev->pdev->dev);
+ if (ret)
+ return ret;
+
+ fuc->size = fw->size;
+ fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL);
+ release_firmware(fw);
+ return (fuc->data != NULL) ? 0 : -ENOMEM;
+}
+
+static void
+nve0_graph_destroy_fw(struct nve0_graph_fuc *fuc)
+{
+ if (fuc->data) {
+ kfree(fuc->data);
+ fuc->data = NULL;
+ }
+}
+
+static void
+nve0_graph_destroy(struct drm_device *dev, int engine)
+{
+ struct nve0_graph_priv *priv = nv_engine(dev, engine);
+
+ nve0_graph_destroy_fw(&priv->fuc409c);
+ nve0_graph_destroy_fw(&priv->fuc409d);
+ nve0_graph_destroy_fw(&priv->fuc41ac);
+ nve0_graph_destroy_fw(&priv->fuc41ad);
+
+ nouveau_irq_unregister(dev, 12);
+
+ nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
+ nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
+
+ if (priv->grctx_vals)
+ kfree(priv->grctx_vals);
+
+ NVOBJ_ENGINE_DEL(dev, GR);
+ kfree(priv);
+}
+
+int
+nve0_graph_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nve0_graph_priv *priv;
+ int ret, gpc, i;
+ u32 kepler;
+
+ kepler = nve0_graph_class(dev);
+ if (!kepler) {
+ NV_ERROR(dev, "PGRAPH: unsupported chipset, please report!\n");
+ return 0;
+ }
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base.destroy = nve0_graph_destroy;
+ priv->base.init = nve0_graph_init;
+ priv->base.fini = nve0_graph_fini;
+ priv->base.context_new = nve0_graph_context_new;
+ priv->base.context_del = nve0_graph_context_del;
+ priv->base.object_new = nve0_graph_object_new;
+
+ NVOBJ_ENGINE_ADD(dev, GR, &priv->base);
+ nouveau_irq_register(dev, 12, nve0_graph_isr);
+
+ NV_INFO(dev, "PGRAPH: using external firmware\n");
+ if (nve0_graph_create_fw(dev, "fuc409c", &priv->fuc409c) ||
+ nve0_graph_create_fw(dev, "fuc409d", &priv->fuc409d) ||
+ nve0_graph_create_fw(dev, "fuc41ac", &priv->fuc41ac) ||
+ nve0_graph_create_fw(dev, "fuc41ad", &priv->fuc41ad)) {
+ ret = 0;
+ goto error;
+ }
+
+ ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4);
+ if (ret)
+ goto error;
+
+ ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b8);
+ if (ret)
+ goto error;
+
+ for (i = 0; i < 0x1000; i += 4) {
+ nv_wo32(priv->unk4188b4, i, 0x00000010);
+ nv_wo32(priv->unk4188b8, i, 0x00000010);
+ }
+
+ priv->gpc_nr = nv_rd32(dev, 0x409604) & 0x0000001f;
+ priv->rop_nr = (nv_rd32(dev, 0x409604) & 0x001f0000) >> 16;
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ priv->tpc_nr[gpc] = nv_rd32(dev, GPC_UNIT(gpc, 0x2608));
+ priv->tpc_total += priv->tpc_nr[gpc];
+ }
+
+ switch (dev_priv->chipset) {
+ case 0xe4:
+ if (priv->tpc_total == 8)
+ priv->magic_not_rop_nr = 3;
+ else
+ if (priv->tpc_total == 7)
+ priv->magic_not_rop_nr = 1;
+ break;
+ case 0xe7:
+ priv->magic_not_rop_nr = 1;
+ break;
+ default:
+ break;
+ }
+
+ if (!priv->magic_not_rop_nr) {
+ NV_ERROR(dev, "PGRAPH: unknown config: %d/%d/%d/%d, %d\n",
+ priv->tpc_nr[0], priv->tpc_nr[1], priv->tpc_nr[2],
+ priv->tpc_nr[3], priv->rop_nr);
+ priv->magic_not_rop_nr = 0x00;
+ }
+
+ NVOBJ_CLASS(dev, 0xa097, GR); /* subc 0: 3D */
+ NVOBJ_CLASS(dev, 0xa0c0, GR); /* subc 1: COMPUTE */
+ NVOBJ_CLASS(dev, 0xa040, GR); /* subc 2: P2MF */
+ NVOBJ_CLASS(dev, 0x902d, GR); /* subc 3: 2D */
+ NVOBJ_CLASS(dev, 0xa0b5, GR); /* subc 4: COPY */
+ return 0;
+
+error:
+ nve0_graph_destroy(dev, NVOBJ_ENGINE_GR);
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nve0_graph.h b/drivers/gpu/drm/nouveau/nve0_graph.h
new file mode 100644
index 000000000000..2ba70449ba01
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nve0_graph.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifndef __NVE0_GRAPH_H__
+#define __NVE0_GRAPH_H__
+
+#define GPC_MAX 4
+#define TPC_MAX 32
+
+#define ROP_BCAST(r) (0x408800 + (r))
+#define ROP_UNIT(u, r) (0x410000 + (u) * 0x400 + (r))
+#define GPC_BCAST(r) (0x418000 + (r))
+#define GPC_UNIT(t, r) (0x500000 + (t) * 0x8000 + (r))
+#define TPC_UNIT(t, m, r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r))
+
+struct nve0_graph_fuc {
+ u32 *data;
+ u32 size;
+};
+
+struct nve0_graph_priv {
+ struct nouveau_exec_engine base;
+
+ struct nve0_graph_fuc fuc409c;
+ struct nve0_graph_fuc fuc409d;
+ struct nve0_graph_fuc fuc41ac;
+ struct nve0_graph_fuc fuc41ad;
+
+ u8 gpc_nr;
+ u8 rop_nr;
+ u8 tpc_nr[GPC_MAX];
+ u8 tpc_total;
+
+ u32 grctx_size;
+ u32 *grctx_vals;
+ struct nouveau_gpuobj *unk4188b4;
+ struct nouveau_gpuobj *unk4188b8;
+
+ u8 magic_not_rop_nr;
+};
+
+struct nve0_graph_chan {
+ struct nouveau_gpuobj *grctx;
+ struct nouveau_gpuobj *unk408004; /* 0x418810 too */
+ struct nouveau_gpuobj *unk40800c; /* 0x419004 too */
+ struct nouveau_gpuobj *unk418810; /* 0x419848 too */
+ struct nouveau_gpuobj *mmio;
+ int mmio_nr;
+};
+
+int nve0_grctx_generate(struct nouveau_channel *);
+
+/* nve0_graph.c uses this also to determine supported chipsets */
+static inline u32
+nve0_graph_class(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ switch (dev_priv->chipset) {
+ case 0xe4:
+ case 0xe7:
+ return 0xa097;
+ default:
+ return 0;
+ }
+}
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nve0_grctx.c b/drivers/gpu/drm/nouveau/nve0_grctx.c
new file mode 100644
index 000000000000..d8cb360e92c1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nve0_grctx.c
@@ -0,0 +1,2777 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_mm.h"
+#include "nve0_graph.h"
+
+static void
+nv_icmd(struct drm_device *dev, u32 icmd, u32 data)
+{
+ nv_wr32(dev, 0x400204, data);
+ nv_wr32(dev, 0x400200, icmd);
+ while (nv_rd32(dev, 0x400700) & 0x00000002) {}
+}
+
+static void
+nve0_grctx_generate_icmd(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x400208, 0x80000000);
+ nv_icmd(dev, 0x001000, 0x00000004);
+ nv_icmd(dev, 0x000039, 0x00000000);
+ nv_icmd(dev, 0x00003a, 0x00000000);
+ nv_icmd(dev, 0x00003b, 0x00000000);
+ nv_icmd(dev, 0x0000a9, 0x0000ffff);
+ nv_icmd(dev, 0x000038, 0x0fac6881);
+ nv_icmd(dev, 0x00003d, 0x00000001);
+ nv_icmd(dev, 0x0000e8, 0x00000400);
+ nv_icmd(dev, 0x0000e9, 0x00000400);
+ nv_icmd(dev, 0x0000ea, 0x00000400);
+ nv_icmd(dev, 0x0000eb, 0x00000400);
+ nv_icmd(dev, 0x0000ec, 0x00000400);
+ nv_icmd(dev, 0x0000ed, 0x00000400);
+ nv_icmd(dev, 0x0000ee, 0x00000400);
+ nv_icmd(dev, 0x0000ef, 0x00000400);
+ nv_icmd(dev, 0x000078, 0x00000300);
+ nv_icmd(dev, 0x000079, 0x00000300);
+ nv_icmd(dev, 0x00007a, 0x00000300);
+ nv_icmd(dev, 0x00007b, 0x00000300);
+ nv_icmd(dev, 0x00007c, 0x00000300);
+ nv_icmd(dev, 0x00007d, 0x00000300);
+ nv_icmd(dev, 0x00007e, 0x00000300);
+ nv_icmd(dev, 0x00007f, 0x00000300);
+ nv_icmd(dev, 0x000050, 0x00000011);
+ nv_icmd(dev, 0x000058, 0x00000008);
+ nv_icmd(dev, 0x000059, 0x00000008);
+ nv_icmd(dev, 0x00005a, 0x00000008);
+ nv_icmd(dev, 0x00005b, 0x00000008);
+ nv_icmd(dev, 0x00005c, 0x00000008);
+ nv_icmd(dev, 0x00005d, 0x00000008);
+ nv_icmd(dev, 0x00005e, 0x00000008);
+ nv_icmd(dev, 0x00005f, 0x00000008);
+ nv_icmd(dev, 0x000208, 0x00000001);
+ nv_icmd(dev, 0x000209, 0x00000001);
+ nv_icmd(dev, 0x00020a, 0x00000001);
+ nv_icmd(dev, 0x00020b, 0x00000001);
+ nv_icmd(dev, 0x00020c, 0x00000001);
+ nv_icmd(dev, 0x00020d, 0x00000001);
+ nv_icmd(dev, 0x00020e, 0x00000001);
+ nv_icmd(dev, 0x00020f, 0x00000001);
+ nv_icmd(dev, 0x000081, 0x00000001);
+ nv_icmd(dev, 0x000085, 0x00000004);
+ nv_icmd(dev, 0x000088, 0x00000400);
+ nv_icmd(dev, 0x000090, 0x00000300);
+ nv_icmd(dev, 0x000098, 0x00001001);
+ nv_icmd(dev, 0x0000e3, 0x00000001);
+ nv_icmd(dev, 0x0000da, 0x00000001);
+ nv_icmd(dev, 0x0000f8, 0x00000003);
+ nv_icmd(dev, 0x0000fa, 0x00000001);
+ nv_icmd(dev, 0x00009f, 0x0000ffff);
+ nv_icmd(dev, 0x0000a0, 0x0000ffff);
+ nv_icmd(dev, 0x0000a1, 0x0000ffff);
+ nv_icmd(dev, 0x0000a2, 0x0000ffff);
+ nv_icmd(dev, 0x0000b1, 0x00000001);
+ nv_icmd(dev, 0x0000ad, 0x0000013e);
+ nv_icmd(dev, 0x0000e1, 0x00000010);
+ nv_icmd(dev, 0x000290, 0x00000000);
+ nv_icmd(dev, 0x000291, 0x00000000);
+ nv_icmd(dev, 0x000292, 0x00000000);
+ nv_icmd(dev, 0x000293, 0x00000000);
+ nv_icmd(dev, 0x000294, 0x00000000);
+ nv_icmd(dev, 0x000295, 0x00000000);
+ nv_icmd(dev, 0x000296, 0x00000000);
+ nv_icmd(dev, 0x000297, 0x00000000);
+ nv_icmd(dev, 0x000298, 0x00000000);
+ nv_icmd(dev, 0x000299, 0x00000000);
+ nv_icmd(dev, 0x00029a, 0x00000000);
+ nv_icmd(dev, 0x00029b, 0x00000000);
+ nv_icmd(dev, 0x00029c, 0x00000000);
+ nv_icmd(dev, 0x00029d, 0x00000000);
+ nv_icmd(dev, 0x00029e, 0x00000000);
+ nv_icmd(dev, 0x00029f, 0x00000000);
+ nv_icmd(dev, 0x0003b0, 0x00000000);
+ nv_icmd(dev, 0x0003b1, 0x00000000);
+ nv_icmd(dev, 0x0003b2, 0x00000000);
+ nv_icmd(dev, 0x0003b3, 0x00000000);
+ nv_icmd(dev, 0x0003b4, 0x00000000);
+ nv_icmd(dev, 0x0003b5, 0x00000000);
+ nv_icmd(dev, 0x0003b6, 0x00000000);
+ nv_icmd(dev, 0x0003b7, 0x00000000);
+ nv_icmd(dev, 0x0003b8, 0x00000000);
+ nv_icmd(dev, 0x0003b9, 0x00000000);
+ nv_icmd(dev, 0x0003ba, 0x00000000);
+ nv_icmd(dev, 0x0003bb, 0x00000000);
+ nv_icmd(dev, 0x0003bc, 0x00000000);
+ nv_icmd(dev, 0x0003bd, 0x00000000);
+ nv_icmd(dev, 0x0003be, 0x00000000);
+ nv_icmd(dev, 0x0003bf, 0x00000000);
+ nv_icmd(dev, 0x0002a0, 0x00000000);
+ nv_icmd(dev, 0x0002a1, 0x00000000);
+ nv_icmd(dev, 0x0002a2, 0x00000000);
+ nv_icmd(dev, 0x0002a3, 0x00000000);
+ nv_icmd(dev, 0x0002a4, 0x00000000);
+ nv_icmd(dev, 0x0002a5, 0x00000000);
+ nv_icmd(dev, 0x0002a6, 0x00000000);
+ nv_icmd(dev, 0x0002a7, 0x00000000);
+ nv_icmd(dev, 0x0002a8, 0x00000000);
+ nv_icmd(dev, 0x0002a9, 0x00000000);
+ nv_icmd(dev, 0x0002aa, 0x00000000);
+ nv_icmd(dev, 0x0002ab, 0x00000000);
+ nv_icmd(dev, 0x0002ac, 0x00000000);
+ nv_icmd(dev, 0x0002ad, 0x00000000);
+ nv_icmd(dev, 0x0002ae, 0x00000000);
+ nv_icmd(dev, 0x0002af, 0x00000000);
+ nv_icmd(dev, 0x000420, 0x00000000);
+ nv_icmd(dev, 0x000421, 0x00000000);
+ nv_icmd(dev, 0x000422, 0x00000000);
+ nv_icmd(dev, 0x000423, 0x00000000);
+ nv_icmd(dev, 0x000424, 0x00000000);
+ nv_icmd(dev, 0x000425, 0x00000000);
+ nv_icmd(dev, 0x000426, 0x00000000);
+ nv_icmd(dev, 0x000427, 0x00000000);
+ nv_icmd(dev, 0x000428, 0x00000000);
+ nv_icmd(dev, 0x000429, 0x00000000);
+ nv_icmd(dev, 0x00042a, 0x00000000);
+ nv_icmd(dev, 0x00042b, 0x00000000);
+ nv_icmd(dev, 0x00042c, 0x00000000);
+ nv_icmd(dev, 0x00042d, 0x00000000);
+ nv_icmd(dev, 0x00042e, 0x00000000);
+ nv_icmd(dev, 0x00042f, 0x00000000);
+ nv_icmd(dev, 0x0002b0, 0x00000000);
+ nv_icmd(dev, 0x0002b1, 0x00000000);
+ nv_icmd(dev, 0x0002b2, 0x00000000);
+ nv_icmd(dev, 0x0002b3, 0x00000000);
+ nv_icmd(dev, 0x0002b4, 0x00000000);
+ nv_icmd(dev, 0x0002b5, 0x00000000);
+ nv_icmd(dev, 0x0002b6, 0x00000000);
+ nv_icmd(dev, 0x0002b7, 0x00000000);
+ nv_icmd(dev, 0x0002b8, 0x00000000);
+ nv_icmd(dev, 0x0002b9, 0x00000000);
+ nv_icmd(dev, 0x0002ba, 0x00000000);
+ nv_icmd(dev, 0x0002bb, 0x00000000);
+ nv_icmd(dev, 0x0002bc, 0x00000000);
+ nv_icmd(dev, 0x0002bd, 0x00000000);
+ nv_icmd(dev, 0x0002be, 0x00000000);
+ nv_icmd(dev, 0x0002bf, 0x00000000);
+ nv_icmd(dev, 0x000430, 0x00000000);
+ nv_icmd(dev, 0x000431, 0x00000000);
+ nv_icmd(dev, 0x000432, 0x00000000);
+ nv_icmd(dev, 0x000433, 0x00000000);
+ nv_icmd(dev, 0x000434, 0x00000000);
+ nv_icmd(dev, 0x000435, 0x00000000);
+ nv_icmd(dev, 0x000436, 0x00000000);
+ nv_icmd(dev, 0x000437, 0x00000000);
+ nv_icmd(dev, 0x000438, 0x00000000);
+ nv_icmd(dev, 0x000439, 0x00000000);
+ nv_icmd(dev, 0x00043a, 0x00000000);
+ nv_icmd(dev, 0x00043b, 0x00000000);
+ nv_icmd(dev, 0x00043c, 0x00000000);
+ nv_icmd(dev, 0x00043d, 0x00000000);
+ nv_icmd(dev, 0x00043e, 0x00000000);
+ nv_icmd(dev, 0x00043f, 0x00000000);
+ nv_icmd(dev, 0x0002c0, 0x00000000);
+ nv_icmd(dev, 0x0002c1, 0x00000000);
+ nv_icmd(dev, 0x0002c2, 0x00000000);
+ nv_icmd(dev, 0x0002c3, 0x00000000);
+ nv_icmd(dev, 0x0002c4, 0x00000000);
+ nv_icmd(dev, 0x0002c5, 0x00000000);
+ nv_icmd(dev, 0x0002c6, 0x00000000);
+ nv_icmd(dev, 0x0002c7, 0x00000000);
+ nv_icmd(dev, 0x0002c8, 0x00000000);
+ nv_icmd(dev, 0x0002c9, 0x00000000);
+ nv_icmd(dev, 0x0002ca, 0x00000000);
+ nv_icmd(dev, 0x0002cb, 0x00000000);
+ nv_icmd(dev, 0x0002cc, 0x00000000);
+ nv_icmd(dev, 0x0002cd, 0x00000000);
+ nv_icmd(dev, 0x0002ce, 0x00000000);
+ nv_icmd(dev, 0x0002cf, 0x00000000);
+ nv_icmd(dev, 0x0004d0, 0x00000000);
+ nv_icmd(dev, 0x0004d1, 0x00000000);
+ nv_icmd(dev, 0x0004d2, 0x00000000);
+ nv_icmd(dev, 0x0004d3, 0x00000000);
+ nv_icmd(dev, 0x0004d4, 0x00000000);
+ nv_icmd(dev, 0x0004d5, 0x00000000);
+ nv_icmd(dev, 0x0004d6, 0x00000000);
+ nv_icmd(dev, 0x0004d7, 0x00000000);
+ nv_icmd(dev, 0x0004d8, 0x00000000);
+ nv_icmd(dev, 0x0004d9, 0x00000000);
+ nv_icmd(dev, 0x0004da, 0x00000000);
+ nv_icmd(dev, 0x0004db, 0x00000000);
+ nv_icmd(dev, 0x0004dc, 0x00000000);
+ nv_icmd(dev, 0x0004dd, 0x00000000);
+ nv_icmd(dev, 0x0004de, 0x00000000);
+ nv_icmd(dev, 0x0004df, 0x00000000);
+ nv_icmd(dev, 0x000720, 0x00000000);
+ nv_icmd(dev, 0x000721, 0x00000000);
+ nv_icmd(dev, 0x000722, 0x00000000);
+ nv_icmd(dev, 0x000723, 0x00000000);
+ nv_icmd(dev, 0x000724, 0x00000000);
+ nv_icmd(dev, 0x000725, 0x00000000);
+ nv_icmd(dev, 0x000726, 0x00000000);
+ nv_icmd(dev, 0x000727, 0x00000000);
+ nv_icmd(dev, 0x000728, 0x00000000);
+ nv_icmd(dev, 0x000729, 0x00000000);
+ nv_icmd(dev, 0x00072a, 0x00000000);
+ nv_icmd(dev, 0x00072b, 0x00000000);
+ nv_icmd(dev, 0x00072c, 0x00000000);
+ nv_icmd(dev, 0x00072d, 0x00000000);
+ nv_icmd(dev, 0x00072e, 0x00000000);
+ nv_icmd(dev, 0x00072f, 0x00000000);
+ nv_icmd(dev, 0x0008c0, 0x00000000);
+ nv_icmd(dev, 0x0008c1, 0x00000000);
+ nv_icmd(dev, 0x0008c2, 0x00000000);
+ nv_icmd(dev, 0x0008c3, 0x00000000);
+ nv_icmd(dev, 0x0008c4, 0x00000000);
+ nv_icmd(dev, 0x0008c5, 0x00000000);
+ nv_icmd(dev, 0x0008c6, 0x00000000);
+ nv_icmd(dev, 0x0008c7, 0x00000000);
+ nv_icmd(dev, 0x0008c8, 0x00000000);
+ nv_icmd(dev, 0x0008c9, 0x00000000);
+ nv_icmd(dev, 0x0008ca, 0x00000000);
+ nv_icmd(dev, 0x0008cb, 0x00000000);
+ nv_icmd(dev, 0x0008cc, 0x00000000);
+ nv_icmd(dev, 0x0008cd, 0x00000000);
+ nv_icmd(dev, 0x0008ce, 0x00000000);
+ nv_icmd(dev, 0x0008cf, 0x00000000);
+ nv_icmd(dev, 0x000890, 0x00000000);
+ nv_icmd(dev, 0x000891, 0x00000000);
+ nv_icmd(dev, 0x000892, 0x00000000);
+ nv_icmd(dev, 0x000893, 0x00000000);
+ nv_icmd(dev, 0x000894, 0x00000000);
+ nv_icmd(dev, 0x000895, 0x00000000);
+ nv_icmd(dev, 0x000896, 0x00000000);
+ nv_icmd(dev, 0x000897, 0x00000000);
+ nv_icmd(dev, 0x000898, 0x00000000);
+ nv_icmd(dev, 0x000899, 0x00000000);
+ nv_icmd(dev, 0x00089a, 0x00000000);
+ nv_icmd(dev, 0x00089b, 0x00000000);
+ nv_icmd(dev, 0x00089c, 0x00000000);
+ nv_icmd(dev, 0x00089d, 0x00000000);
+ nv_icmd(dev, 0x00089e, 0x00000000);
+ nv_icmd(dev, 0x00089f, 0x00000000);
+ nv_icmd(dev, 0x0008e0, 0x00000000);
+ nv_icmd(dev, 0x0008e1, 0x00000000);
+ nv_icmd(dev, 0x0008e2, 0x00000000);
+ nv_icmd(dev, 0x0008e3, 0x00000000);
+ nv_icmd(dev, 0x0008e4, 0x00000000);
+ nv_icmd(dev, 0x0008e5, 0x00000000);
+ nv_icmd(dev, 0x0008e6, 0x00000000);
+ nv_icmd(dev, 0x0008e7, 0x00000000);
+ nv_icmd(dev, 0x0008e8, 0x00000000);
+ nv_icmd(dev, 0x0008e9, 0x00000000);
+ nv_icmd(dev, 0x0008ea, 0x00000000);
+ nv_icmd(dev, 0x0008eb, 0x00000000);
+ nv_icmd(dev, 0x0008ec, 0x00000000);
+ nv_icmd(dev, 0x0008ed, 0x00000000);
+ nv_icmd(dev, 0x0008ee, 0x00000000);
+ nv_icmd(dev, 0x0008ef, 0x00000000);
+ nv_icmd(dev, 0x0008a0, 0x00000000);
+ nv_icmd(dev, 0x0008a1, 0x00000000);
+ nv_icmd(dev, 0x0008a2, 0x00000000);
+ nv_icmd(dev, 0x0008a3, 0x00000000);
+ nv_icmd(dev, 0x0008a4, 0x00000000);
+ nv_icmd(dev, 0x0008a5, 0x00000000);
+ nv_icmd(dev, 0x0008a6, 0x00000000);
+ nv_icmd(dev, 0x0008a7, 0x00000000);
+ nv_icmd(dev, 0x0008a8, 0x00000000);
+ nv_icmd(dev, 0x0008a9, 0x00000000);
+ nv_icmd(dev, 0x0008aa, 0x00000000);
+ nv_icmd(dev, 0x0008ab, 0x00000000);
+ nv_icmd(dev, 0x0008ac, 0x00000000);
+ nv_icmd(dev, 0x0008ad, 0x00000000);
+ nv_icmd(dev, 0x0008ae, 0x00000000);
+ nv_icmd(dev, 0x0008af, 0x00000000);
+ nv_icmd(dev, 0x0008f0, 0x00000000);
+ nv_icmd(dev, 0x0008f1, 0x00000000);
+ nv_icmd(dev, 0x0008f2, 0x00000000);
+ nv_icmd(dev, 0x0008f3, 0x00000000);
+ nv_icmd(dev, 0x0008f4, 0x00000000);
+ nv_icmd(dev, 0x0008f5, 0x00000000);
+ nv_icmd(dev, 0x0008f6, 0x00000000);
+ nv_icmd(dev, 0x0008f7, 0x00000000);
+ nv_icmd(dev, 0x0008f8, 0x00000000);
+ nv_icmd(dev, 0x0008f9, 0x00000000);
+ nv_icmd(dev, 0x0008fa, 0x00000000);
+ nv_icmd(dev, 0x0008fb, 0x00000000);
+ nv_icmd(dev, 0x0008fc, 0x00000000);
+ nv_icmd(dev, 0x0008fd, 0x00000000);
+ nv_icmd(dev, 0x0008fe, 0x00000000);
+ nv_icmd(dev, 0x0008ff, 0x00000000);
+ nv_icmd(dev, 0x00094c, 0x000000ff);
+ nv_icmd(dev, 0x00094d, 0xffffffff);
+ nv_icmd(dev, 0x00094e, 0x00000002);
+ nv_icmd(dev, 0x0002ec, 0x00000001);
+ nv_icmd(dev, 0x000303, 0x00000001);
+ nv_icmd(dev, 0x0002e6, 0x00000001);
+ nv_icmd(dev, 0x000466, 0x00000052);
+ nv_icmd(dev, 0x000301, 0x3f800000);
+ nv_icmd(dev, 0x000304, 0x30201000);
+ nv_icmd(dev, 0x000305, 0x70605040);
+ nv_icmd(dev, 0x000306, 0xb8a89888);
+ nv_icmd(dev, 0x000307, 0xf8e8d8c8);
+ nv_icmd(dev, 0x00030a, 0x00ffff00);
+ nv_icmd(dev, 0x00030b, 0x0000001a);
+ nv_icmd(dev, 0x00030c, 0x00000001);
+ nv_icmd(dev, 0x000318, 0x00000001);
+ nv_icmd(dev, 0x000340, 0x00000000);
+ nv_icmd(dev, 0x000375, 0x00000001);
+ nv_icmd(dev, 0x00037d, 0x00000006);
+ nv_icmd(dev, 0x0003a0, 0x00000002);
+ nv_icmd(dev, 0x0003aa, 0x00000001);
+ nv_icmd(dev, 0x0003a9, 0x00000001);
+ nv_icmd(dev, 0x000380, 0x00000001);
+ nv_icmd(dev, 0x000383, 0x00000011);
+ nv_icmd(dev, 0x000360, 0x00000040);
+ nv_icmd(dev, 0x000366, 0x00000000);
+ nv_icmd(dev, 0x000367, 0x00000000);
+ nv_icmd(dev, 0x000368, 0x00000fff);
+ nv_icmd(dev, 0x000370, 0x00000000);
+ nv_icmd(dev, 0x000371, 0x00000000);
+ nv_icmd(dev, 0x000372, 0x000fffff);
+ nv_icmd(dev, 0x00037a, 0x00000012);
+ nv_icmd(dev, 0x000619, 0x00000003);
+ nv_icmd(dev, 0x000811, 0x00000003);
+ nv_icmd(dev, 0x000812, 0x00000004);
+ nv_icmd(dev, 0x000813, 0x00000006);
+ nv_icmd(dev, 0x000814, 0x00000008);
+ nv_icmd(dev, 0x000815, 0x0000000b);
+ nv_icmd(dev, 0x000800, 0x00000001);
+ nv_icmd(dev, 0x000801, 0x00000001);
+ nv_icmd(dev, 0x000802, 0x00000001);
+ nv_icmd(dev, 0x000803, 0x00000001);
+ nv_icmd(dev, 0x000804, 0x00000001);
+ nv_icmd(dev, 0x000805, 0x00000001);
+ nv_icmd(dev, 0x000632, 0x00000001);
+ nv_icmd(dev, 0x000633, 0x00000002);
+ nv_icmd(dev, 0x000634, 0x00000003);
+ nv_icmd(dev, 0x000635, 0x00000004);
+ nv_icmd(dev, 0x000654, 0x3f800000);
+ nv_icmd(dev, 0x000657, 0x3f800000);
+ nv_icmd(dev, 0x000655, 0x3f800000);
+ nv_icmd(dev, 0x000656, 0x3f800000);
+ nv_icmd(dev, 0x0006cd, 0x3f800000);
+ nv_icmd(dev, 0x0007f5, 0x3f800000);
+ nv_icmd(dev, 0x0007dc, 0x39291909);
+ nv_icmd(dev, 0x0007dd, 0x79695949);
+ nv_icmd(dev, 0x0007de, 0xb9a99989);
+ nv_icmd(dev, 0x0007df, 0xf9e9d9c9);
+ nv_icmd(dev, 0x0007e8, 0x00003210);
+ nv_icmd(dev, 0x0007e9, 0x00007654);
+ nv_icmd(dev, 0x0007ea, 0x00000098);
+ nv_icmd(dev, 0x0007ec, 0x39291909);
+ nv_icmd(dev, 0x0007ed, 0x79695949);
+ nv_icmd(dev, 0x0007ee, 0xb9a99989);
+ nv_icmd(dev, 0x0007ef, 0xf9e9d9c9);
+ nv_icmd(dev, 0x0007f0, 0x00003210);
+ nv_icmd(dev, 0x0007f1, 0x00007654);
+ nv_icmd(dev, 0x0007f2, 0x00000098);
+ nv_icmd(dev, 0x0005a5, 0x00000001);
+ nv_icmd(dev, 0x000980, 0x00000000);
+ nv_icmd(dev, 0x000981, 0x00000000);
+ nv_icmd(dev, 0x000982, 0x00000000);
+ nv_icmd(dev, 0x000983, 0x00000000);
+ nv_icmd(dev, 0x000984, 0x00000000);
+ nv_icmd(dev, 0x000985, 0x00000000);
+ nv_icmd(dev, 0x000986, 0x00000000);
+ nv_icmd(dev, 0x000987, 0x00000000);
+ nv_icmd(dev, 0x000988, 0x00000000);
+ nv_icmd(dev, 0x000989, 0x00000000);
+ nv_icmd(dev, 0x00098a, 0x00000000);
+ nv_icmd(dev, 0x00098b, 0x00000000);
+ nv_icmd(dev, 0x00098c, 0x00000000);
+ nv_icmd(dev, 0x00098d, 0x00000000);
+ nv_icmd(dev, 0x00098e, 0x00000000);
+ nv_icmd(dev, 0x00098f, 0x00000000);
+ nv_icmd(dev, 0x000990, 0x00000000);
+ nv_icmd(dev, 0x000991, 0x00000000);
+ nv_icmd(dev, 0x000992, 0x00000000);
+ nv_icmd(dev, 0x000993, 0x00000000);
+ nv_icmd(dev, 0x000994, 0x00000000);
+ nv_icmd(dev, 0x000995, 0x00000000);
+ nv_icmd(dev, 0x000996, 0x00000000);
+ nv_icmd(dev, 0x000997, 0x00000000);
+ nv_icmd(dev, 0x000998, 0x00000000);
+ nv_icmd(dev, 0x000999, 0x00000000);
+ nv_icmd(dev, 0x00099a, 0x00000000);
+ nv_icmd(dev, 0x00099b, 0x00000000);
+ nv_icmd(dev, 0x00099c, 0x00000000);
+ nv_icmd(dev, 0x00099d, 0x00000000);
+ nv_icmd(dev, 0x00099e, 0x00000000);
+ nv_icmd(dev, 0x00099f, 0x00000000);
+ nv_icmd(dev, 0x0009a0, 0x00000000);
+ nv_icmd(dev, 0x0009a1, 0x00000000);
+ nv_icmd(dev, 0x0009a2, 0x00000000);
+ nv_icmd(dev, 0x0009a3, 0x00000000);
+ nv_icmd(dev, 0x0009a4, 0x00000000);
+ nv_icmd(dev, 0x0009a5, 0x00000000);
+ nv_icmd(dev, 0x0009a6, 0x00000000);
+ nv_icmd(dev, 0x0009a7, 0x00000000);
+ nv_icmd(dev, 0x0009a8, 0x00000000);
+ nv_icmd(dev, 0x0009a9, 0x00000000);
+ nv_icmd(dev, 0x0009aa, 0x00000000);
+ nv_icmd(dev, 0x0009ab, 0x00000000);
+ nv_icmd(dev, 0x0009ac, 0x00000000);
+ nv_icmd(dev, 0x0009ad, 0x00000000);
+ nv_icmd(dev, 0x0009ae, 0x00000000);
+ nv_icmd(dev, 0x0009af, 0x00000000);
+ nv_icmd(dev, 0x0009b0, 0x00000000);
+ nv_icmd(dev, 0x0009b1, 0x00000000);
+ nv_icmd(dev, 0x0009b2, 0x00000000);
+ nv_icmd(dev, 0x0009b3, 0x00000000);
+ nv_icmd(dev, 0x0009b4, 0x00000000);
+ nv_icmd(dev, 0x0009b5, 0x00000000);
+ nv_icmd(dev, 0x0009b6, 0x00000000);
+ nv_icmd(dev, 0x0009b7, 0x00000000);
+ nv_icmd(dev, 0x0009b8, 0x00000000);
+ nv_icmd(dev, 0x0009b9, 0x00000000);
+ nv_icmd(dev, 0x0009ba, 0x00000000);
+ nv_icmd(dev, 0x0009bb, 0x00000000);
+ nv_icmd(dev, 0x0009bc, 0x00000000);
+ nv_icmd(dev, 0x0009bd, 0x00000000);
+ nv_icmd(dev, 0x0009be, 0x00000000);
+ nv_icmd(dev, 0x0009bf, 0x00000000);
+ nv_icmd(dev, 0x0009c0, 0x00000000);
+ nv_icmd(dev, 0x0009c1, 0x00000000);
+ nv_icmd(dev, 0x0009c2, 0x00000000);
+ nv_icmd(dev, 0x0009c3, 0x00000000);
+ nv_icmd(dev, 0x0009c4, 0x00000000);
+ nv_icmd(dev, 0x0009c5, 0x00000000);
+ nv_icmd(dev, 0x0009c6, 0x00000000);
+ nv_icmd(dev, 0x0009c7, 0x00000000);
+ nv_icmd(dev, 0x0009c8, 0x00000000);
+ nv_icmd(dev, 0x0009c9, 0x00000000);
+ nv_icmd(dev, 0x0009ca, 0x00000000);
+ nv_icmd(dev, 0x0009cb, 0x00000000);
+ nv_icmd(dev, 0x0009cc, 0x00000000);
+ nv_icmd(dev, 0x0009cd, 0x00000000);
+ nv_icmd(dev, 0x0009ce, 0x00000000);
+ nv_icmd(dev, 0x0009cf, 0x00000000);
+ nv_icmd(dev, 0x0009d0, 0x00000000);
+ nv_icmd(dev, 0x0009d1, 0x00000000);
+ nv_icmd(dev, 0x0009d2, 0x00000000);
+ nv_icmd(dev, 0x0009d3, 0x00000000);
+ nv_icmd(dev, 0x0009d4, 0x00000000);
+ nv_icmd(dev, 0x0009d5, 0x00000000);
+ nv_icmd(dev, 0x0009d6, 0x00000000);
+ nv_icmd(dev, 0x0009d7, 0x00000000);
+ nv_icmd(dev, 0x0009d8, 0x00000000);
+ nv_icmd(dev, 0x0009d9, 0x00000000);
+ nv_icmd(dev, 0x0009da, 0x00000000);
+ nv_icmd(dev, 0x0009db, 0x00000000);
+ nv_icmd(dev, 0x0009dc, 0x00000000);
+ nv_icmd(dev, 0x0009dd, 0x00000000);
+ nv_icmd(dev, 0x0009de, 0x00000000);
+ nv_icmd(dev, 0x0009df, 0x00000000);
+ nv_icmd(dev, 0x0009e0, 0x00000000);
+ nv_icmd(dev, 0x0009e1, 0x00000000);
+ nv_icmd(dev, 0x0009e2, 0x00000000);
+ nv_icmd(dev, 0x0009e3, 0x00000000);
+ nv_icmd(dev, 0x0009e4, 0x00000000);
+ nv_icmd(dev, 0x0009e5, 0x00000000);
+ nv_icmd(dev, 0x0009e6, 0x00000000);
+ nv_icmd(dev, 0x0009e7, 0x00000000);
+ nv_icmd(dev, 0x0009e8, 0x00000000);
+ nv_icmd(dev, 0x0009e9, 0x00000000);
+ nv_icmd(dev, 0x0009ea, 0x00000000);
+ nv_icmd(dev, 0x0009eb, 0x00000000);
+ nv_icmd(dev, 0x0009ec, 0x00000000);
+ nv_icmd(dev, 0x0009ed, 0x00000000);
+ nv_icmd(dev, 0x0009ee, 0x00000000);
+ nv_icmd(dev, 0x0009ef, 0x00000000);
+ nv_icmd(dev, 0x0009f0, 0x00000000);
+ nv_icmd(dev, 0x0009f1, 0x00000000);
+ nv_icmd(dev, 0x0009f2, 0x00000000);
+ nv_icmd(dev, 0x0009f3, 0x00000000);
+ nv_icmd(dev, 0x0009f4, 0x00000000);
+ nv_icmd(dev, 0x0009f5, 0x00000000);
+ nv_icmd(dev, 0x0009f6, 0x00000000);
+ nv_icmd(dev, 0x0009f7, 0x00000000);
+ nv_icmd(dev, 0x0009f8, 0x00000000);
+ nv_icmd(dev, 0x0009f9, 0x00000000);
+ nv_icmd(dev, 0x0009fa, 0x00000000);
+ nv_icmd(dev, 0x0009fb, 0x00000000);
+ nv_icmd(dev, 0x0009fc, 0x00000000);
+ nv_icmd(dev, 0x0009fd, 0x00000000);
+ nv_icmd(dev, 0x0009fe, 0x00000000);
+ nv_icmd(dev, 0x0009ff, 0x00000000);
+ nv_icmd(dev, 0x000468, 0x00000004);
+ nv_icmd(dev, 0x00046c, 0x00000001);
+ nv_icmd(dev, 0x000470, 0x00000000);
+ nv_icmd(dev, 0x000471, 0x00000000);
+ nv_icmd(dev, 0x000472, 0x00000000);
+ nv_icmd(dev, 0x000473, 0x00000000);
+ nv_icmd(dev, 0x000474, 0x00000000);
+ nv_icmd(dev, 0x000475, 0x00000000);
+ nv_icmd(dev, 0x000476, 0x00000000);
+ nv_icmd(dev, 0x000477, 0x00000000);
+ nv_icmd(dev, 0x000478, 0x00000000);
+ nv_icmd(dev, 0x000479, 0x00000000);
+ nv_icmd(dev, 0x00047a, 0x00000000);
+ nv_icmd(dev, 0x00047b, 0x00000000);
+ nv_icmd(dev, 0x00047c, 0x00000000);
+ nv_icmd(dev, 0x00047d, 0x00000000);
+ nv_icmd(dev, 0x00047e, 0x00000000);
+ nv_icmd(dev, 0x00047f, 0x00000000);
+ nv_icmd(dev, 0x000480, 0x00000000);
+ nv_icmd(dev, 0x000481, 0x00000000);
+ nv_icmd(dev, 0x000482, 0x00000000);
+ nv_icmd(dev, 0x000483, 0x00000000);
+ nv_icmd(dev, 0x000484, 0x00000000);
+ nv_icmd(dev, 0x000485, 0x00000000);
+ nv_icmd(dev, 0x000486, 0x00000000);
+ nv_icmd(dev, 0x000487, 0x00000000);
+ nv_icmd(dev, 0x000488, 0x00000000);
+ nv_icmd(dev, 0x000489, 0x00000000);
+ nv_icmd(dev, 0x00048a, 0x00000000);
+ nv_icmd(dev, 0x00048b, 0x00000000);
+ nv_icmd(dev, 0x00048c, 0x00000000);
+ nv_icmd(dev, 0x00048d, 0x00000000);
+ nv_icmd(dev, 0x00048e, 0x00000000);
+ nv_icmd(dev, 0x00048f, 0x00000000);
+ nv_icmd(dev, 0x000490, 0x00000000);
+ nv_icmd(dev, 0x000491, 0x00000000);
+ nv_icmd(dev, 0x000492, 0x00000000);
+ nv_icmd(dev, 0x000493, 0x00000000);
+ nv_icmd(dev, 0x000494, 0x00000000);
+ nv_icmd(dev, 0x000495, 0x00000000);
+ nv_icmd(dev, 0x000496, 0x00000000);
+ nv_icmd(dev, 0x000497, 0x00000000);
+ nv_icmd(dev, 0x000498, 0x00000000);
+ nv_icmd(dev, 0x000499, 0x00000000);
+ nv_icmd(dev, 0x00049a, 0x00000000);
+ nv_icmd(dev, 0x00049b, 0x00000000);
+ nv_icmd(dev, 0x00049c, 0x00000000);
+ nv_icmd(dev, 0x00049d, 0x00000000);
+ nv_icmd(dev, 0x00049e, 0x00000000);
+ nv_icmd(dev, 0x00049f, 0x00000000);
+ nv_icmd(dev, 0x0004a0, 0x00000000);
+ nv_icmd(dev, 0x0004a1, 0x00000000);
+ nv_icmd(dev, 0x0004a2, 0x00000000);
+ nv_icmd(dev, 0x0004a3, 0x00000000);
+ nv_icmd(dev, 0x0004a4, 0x00000000);
+ nv_icmd(dev, 0x0004a5, 0x00000000);
+ nv_icmd(dev, 0x0004a6, 0x00000000);
+ nv_icmd(dev, 0x0004a7, 0x00000000);
+ nv_icmd(dev, 0x0004a8, 0x00000000);
+ nv_icmd(dev, 0x0004a9, 0x00000000);
+ nv_icmd(dev, 0x0004aa, 0x00000000);
+ nv_icmd(dev, 0x0004ab, 0x00000000);
+ nv_icmd(dev, 0x0004ac, 0x00000000);
+ nv_icmd(dev, 0x0004ad, 0x00000000);
+ nv_icmd(dev, 0x0004ae, 0x00000000);
+ nv_icmd(dev, 0x0004af, 0x00000000);
+ nv_icmd(dev, 0x0004b0, 0x00000000);
+ nv_icmd(dev, 0x0004b1, 0x00000000);
+ nv_icmd(dev, 0x0004b2, 0x00000000);
+ nv_icmd(dev, 0x0004b3, 0x00000000);
+ nv_icmd(dev, 0x0004b4, 0x00000000);
+ nv_icmd(dev, 0x0004b5, 0x00000000);
+ nv_icmd(dev, 0x0004b6, 0x00000000);
+ nv_icmd(dev, 0x0004b7, 0x00000000);
+ nv_icmd(dev, 0x0004b8, 0x00000000);
+ nv_icmd(dev, 0x0004b9, 0x00000000);
+ nv_icmd(dev, 0x0004ba, 0x00000000);
+ nv_icmd(dev, 0x0004bb, 0x00000000);
+ nv_icmd(dev, 0x0004bc, 0x00000000);
+ nv_icmd(dev, 0x0004bd, 0x00000000);
+ nv_icmd(dev, 0x0004be, 0x00000000);
+ nv_icmd(dev, 0x0004bf, 0x00000000);
+ nv_icmd(dev, 0x0004c0, 0x00000000);
+ nv_icmd(dev, 0x0004c1, 0x00000000);
+ nv_icmd(dev, 0x0004c2, 0x00000000);
+ nv_icmd(dev, 0x0004c3, 0x00000000);
+ nv_icmd(dev, 0x0004c4, 0x00000000);
+ nv_icmd(dev, 0x0004c5, 0x00000000);
+ nv_icmd(dev, 0x0004c6, 0x00000000);
+ nv_icmd(dev, 0x0004c7, 0x00000000);
+ nv_icmd(dev, 0x0004c8, 0x00000000);
+ nv_icmd(dev, 0x0004c9, 0x00000000);
+ nv_icmd(dev, 0x0004ca, 0x00000000);
+ nv_icmd(dev, 0x0004cb, 0x00000000);
+ nv_icmd(dev, 0x0004cc, 0x00000000);
+ nv_icmd(dev, 0x0004cd, 0x00000000);
+ nv_icmd(dev, 0x0004ce, 0x00000000);
+ nv_icmd(dev, 0x0004cf, 0x00000000);
+ nv_icmd(dev, 0x000510, 0x3f800000);
+ nv_icmd(dev, 0x000511, 0x3f800000);
+ nv_icmd(dev, 0x000512, 0x3f800000);
+ nv_icmd(dev, 0x000513, 0x3f800000);
+ nv_icmd(dev, 0x000514, 0x3f800000);
+ nv_icmd(dev, 0x000515, 0x3f800000);
+ nv_icmd(dev, 0x000516, 0x3f800000);
+ nv_icmd(dev, 0x000517, 0x3f800000);
+ nv_icmd(dev, 0x000518, 0x3f800000);
+ nv_icmd(dev, 0x000519, 0x3f800000);
+ nv_icmd(dev, 0x00051a, 0x3f800000);
+ nv_icmd(dev, 0x00051b, 0x3f800000);
+ nv_icmd(dev, 0x00051c, 0x3f800000);
+ nv_icmd(dev, 0x00051d, 0x3f800000);
+ nv_icmd(dev, 0x00051e, 0x3f800000);
+ nv_icmd(dev, 0x00051f, 0x3f800000);
+ nv_icmd(dev, 0x000520, 0x000002b6);
+ nv_icmd(dev, 0x000529, 0x00000001);
+ nv_icmd(dev, 0x000530, 0xffff0000);
+ nv_icmd(dev, 0x000531, 0xffff0000);
+ nv_icmd(dev, 0x000532, 0xffff0000);
+ nv_icmd(dev, 0x000533, 0xffff0000);
+ nv_icmd(dev, 0x000534, 0xffff0000);
+ nv_icmd(dev, 0x000535, 0xffff0000);
+ nv_icmd(dev, 0x000536, 0xffff0000);
+ nv_icmd(dev, 0x000537, 0xffff0000);
+ nv_icmd(dev, 0x000538, 0xffff0000);
+ nv_icmd(dev, 0x000539, 0xffff0000);
+ nv_icmd(dev, 0x00053a, 0xffff0000);
+ nv_icmd(dev, 0x00053b, 0xffff0000);
+ nv_icmd(dev, 0x00053c, 0xffff0000);
+ nv_icmd(dev, 0x00053d, 0xffff0000);
+ nv_icmd(dev, 0x00053e, 0xffff0000);
+ nv_icmd(dev, 0x00053f, 0xffff0000);
+ nv_icmd(dev, 0x000585, 0x0000003f);
+ nv_icmd(dev, 0x000576, 0x00000003);
+ nv_icmd(dev, 0x00057b, 0x00000059);
+ nv_icmd(dev, 0x000586, 0x00000040);
+ nv_icmd(dev, 0x000582, 0x00000080);
+ nv_icmd(dev, 0x000583, 0x00000080);
+ nv_icmd(dev, 0x0005c2, 0x00000001);
+ nv_icmd(dev, 0x000638, 0x00000001);
+ nv_icmd(dev, 0x000639, 0x00000001);
+ nv_icmd(dev, 0x00063a, 0x00000002);
+ nv_icmd(dev, 0x00063b, 0x00000001);
+ nv_icmd(dev, 0x00063c, 0x00000001);
+ nv_icmd(dev, 0x00063d, 0x00000002);
+ nv_icmd(dev, 0x00063e, 0x00000001);
+ nv_icmd(dev, 0x0008b8, 0x00000001);
+ nv_icmd(dev, 0x0008b9, 0x00000001);
+ nv_icmd(dev, 0x0008ba, 0x00000001);
+ nv_icmd(dev, 0x0008bb, 0x00000001);
+ nv_icmd(dev, 0x0008bc, 0x00000001);
+ nv_icmd(dev, 0x0008bd, 0x00000001);
+ nv_icmd(dev, 0x0008be, 0x00000001);
+ nv_icmd(dev, 0x0008bf, 0x00000001);
+ nv_icmd(dev, 0x000900, 0x00000001);
+ nv_icmd(dev, 0x000901, 0x00000001);
+ nv_icmd(dev, 0x000902, 0x00000001);
+ nv_icmd(dev, 0x000903, 0x00000001);
+ nv_icmd(dev, 0x000904, 0x00000001);
+ nv_icmd(dev, 0x000905, 0x00000001);
+ nv_icmd(dev, 0x000906, 0x00000001);
+ nv_icmd(dev, 0x000907, 0x00000001);
+ nv_icmd(dev, 0x000908, 0x00000002);
+ nv_icmd(dev, 0x000909, 0x00000002);
+ nv_icmd(dev, 0x00090a, 0x00000002);
+ nv_icmd(dev, 0x00090b, 0x00000002);
+ nv_icmd(dev, 0x00090c, 0x00000002);
+ nv_icmd(dev, 0x00090d, 0x00000002);
+ nv_icmd(dev, 0x00090e, 0x00000002);
+ nv_icmd(dev, 0x00090f, 0x00000002);
+ nv_icmd(dev, 0x000910, 0x00000001);
+ nv_icmd(dev, 0x000911, 0x00000001);
+ nv_icmd(dev, 0x000912, 0x00000001);
+ nv_icmd(dev, 0x000913, 0x00000001);
+ nv_icmd(dev, 0x000914, 0x00000001);
+ nv_icmd(dev, 0x000915, 0x00000001);
+ nv_icmd(dev, 0x000916, 0x00000001);
+ nv_icmd(dev, 0x000917, 0x00000001);
+ nv_icmd(dev, 0x000918, 0x00000001);
+ nv_icmd(dev, 0x000919, 0x00000001);
+ nv_icmd(dev, 0x00091a, 0x00000001);
+ nv_icmd(dev, 0x00091b, 0x00000001);
+ nv_icmd(dev, 0x00091c, 0x00000001);
+ nv_icmd(dev, 0x00091d, 0x00000001);
+ nv_icmd(dev, 0x00091e, 0x00000001);
+ nv_icmd(dev, 0x00091f, 0x00000001);
+ nv_icmd(dev, 0x000920, 0x00000002);
+ nv_icmd(dev, 0x000921, 0x00000002);
+ nv_icmd(dev, 0x000922, 0x00000002);
+ nv_icmd(dev, 0x000923, 0x00000002);
+ nv_icmd(dev, 0x000924, 0x00000002);
+ nv_icmd(dev, 0x000925, 0x00000002);
+ nv_icmd(dev, 0x000926, 0x00000002);
+ nv_icmd(dev, 0x000927, 0x00000002);
+ nv_icmd(dev, 0x000928, 0x00000001);
+ nv_icmd(dev, 0x000929, 0x00000001);
+ nv_icmd(dev, 0x00092a, 0x00000001);
+ nv_icmd(dev, 0x00092b, 0x00000001);
+ nv_icmd(dev, 0x00092c, 0x00000001);
+ nv_icmd(dev, 0x00092d, 0x00000001);
+ nv_icmd(dev, 0x00092e, 0x00000001);
+ nv_icmd(dev, 0x00092f, 0x00000001);
+ nv_icmd(dev, 0x000648, 0x00000001);
+ nv_icmd(dev, 0x000649, 0x00000001);
+ nv_icmd(dev, 0x00064a, 0x00000001);
+ nv_icmd(dev, 0x00064b, 0x00000001);
+ nv_icmd(dev, 0x00064c, 0x00000001);
+ nv_icmd(dev, 0x00064d, 0x00000001);
+ nv_icmd(dev, 0x00064e, 0x00000001);
+ nv_icmd(dev, 0x00064f, 0x00000001);
+ nv_icmd(dev, 0x000650, 0x00000001);
+ nv_icmd(dev, 0x000658, 0x0000000f);
+ nv_icmd(dev, 0x0007ff, 0x0000000a);
+ nv_icmd(dev, 0x00066a, 0x40000000);
+ nv_icmd(dev, 0x00066b, 0x10000000);
+ nv_icmd(dev, 0x00066c, 0xffff0000);
+ nv_icmd(dev, 0x00066d, 0xffff0000);
+ nv_icmd(dev, 0x0007af, 0x00000008);
+ nv_icmd(dev, 0x0007b0, 0x00000008);
+ nv_icmd(dev, 0x0007f6, 0x00000001);
+ nv_icmd(dev, 0x0006b2, 0x00000055);
+ nv_icmd(dev, 0x0007ad, 0x00000003);
+ nv_icmd(dev, 0x000937, 0x00000001);
+ nv_icmd(dev, 0x000971, 0x00000008);
+ nv_icmd(dev, 0x000972, 0x00000040);
+ nv_icmd(dev, 0x000973, 0x0000012c);
+ nv_icmd(dev, 0x00097c, 0x00000040);
+ nv_icmd(dev, 0x000979, 0x00000003);
+ nv_icmd(dev, 0x000975, 0x00000020);
+ nv_icmd(dev, 0x000976, 0x00000001);
+ nv_icmd(dev, 0x000977, 0x00000020);
+ nv_icmd(dev, 0x000978, 0x00000001);
+ nv_icmd(dev, 0x000957, 0x00000003);
+ nv_icmd(dev, 0x00095e, 0x20164010);
+ nv_icmd(dev, 0x00095f, 0x00000020);
+ nv_icmd(dev, 0x00097d, 0x00000020);
+ nv_icmd(dev, 0x000683, 0x00000006);
+ nv_icmd(dev, 0x000685, 0x003fffff);
+ nv_icmd(dev, 0x000687, 0x003fffff);
+ nv_icmd(dev, 0x0006a0, 0x00000005);
+ nv_icmd(dev, 0x000840, 0x00400008);
+ nv_icmd(dev, 0x000841, 0x08000080);
+ nv_icmd(dev, 0x000842, 0x00400008);
+ nv_icmd(dev, 0x000843, 0x08000080);
+ nv_icmd(dev, 0x000818, 0x00000000);
+ nv_icmd(dev, 0x000819, 0x00000000);
+ nv_icmd(dev, 0x00081a, 0x00000000);
+ nv_icmd(dev, 0x00081b, 0x00000000);
+ nv_icmd(dev, 0x00081c, 0x00000000);
+ nv_icmd(dev, 0x00081d, 0x00000000);
+ nv_icmd(dev, 0x00081e, 0x00000000);
+ nv_icmd(dev, 0x00081f, 0x00000000);
+ nv_icmd(dev, 0x000848, 0x00000000);
+ nv_icmd(dev, 0x000849, 0x00000000);
+ nv_icmd(dev, 0x00084a, 0x00000000);
+ nv_icmd(dev, 0x00084b, 0x00000000);
+ nv_icmd(dev, 0x00084c, 0x00000000);
+ nv_icmd(dev, 0x00084d, 0x00000000);
+ nv_icmd(dev, 0x00084e, 0x00000000);
+ nv_icmd(dev, 0x00084f, 0x00000000);
+ nv_icmd(dev, 0x000850, 0x00000000);
+ nv_icmd(dev, 0x000851, 0x00000000);
+ nv_icmd(dev, 0x000852, 0x00000000);
+ nv_icmd(dev, 0x000853, 0x00000000);
+ nv_icmd(dev, 0x000854, 0x00000000);
+ nv_icmd(dev, 0x000855, 0x00000000);
+ nv_icmd(dev, 0x000856, 0x00000000);
+ nv_icmd(dev, 0x000857, 0x00000000);
+ nv_icmd(dev, 0x000738, 0x00000000);
+ nv_icmd(dev, 0x0006aa, 0x00000001);
+ nv_icmd(dev, 0x0006ab, 0x00000002);
+ nv_icmd(dev, 0x0006ac, 0x00000080);
+ nv_icmd(dev, 0x0006ad, 0x00000100);
+ nv_icmd(dev, 0x0006ae, 0x00000100);
+ nv_icmd(dev, 0x0006b1, 0x00000011);
+ nv_icmd(dev, 0x0006bb, 0x000000cf);
+ nv_icmd(dev, 0x0006ce, 0x2a712488);
+ nv_icmd(dev, 0x000739, 0x4085c000);
+ nv_icmd(dev, 0x00073a, 0x00000080);
+ nv_icmd(dev, 0x000786, 0x80000100);
+ nv_icmd(dev, 0x00073c, 0x00010100);
+ nv_icmd(dev, 0x00073d, 0x02800000);
+ nv_icmd(dev, 0x000787, 0x000000cf);
+ nv_icmd(dev, 0x00078c, 0x00000008);
+ nv_icmd(dev, 0x000792, 0x00000001);
+ nv_icmd(dev, 0x000794, 0x00000001);
+ nv_icmd(dev, 0x000795, 0x00000001);
+ nv_icmd(dev, 0x000796, 0x00000001);
+ nv_icmd(dev, 0x000797, 0x000000cf);
+ nv_icmd(dev, 0x000836, 0x00000001);
+ nv_icmd(dev, 0x00079a, 0x00000002);
+ nv_icmd(dev, 0x000833, 0x04444480);
+ nv_icmd(dev, 0x0007a1, 0x00000001);
+ nv_icmd(dev, 0x0007a3, 0x00000001);
+ nv_icmd(dev, 0x0007a4, 0x00000001);
+ nv_icmd(dev, 0x0007a5, 0x00000001);
+ nv_icmd(dev, 0x000831, 0x00000004);
+ nv_icmd(dev, 0x000b07, 0x00000002);
+ nv_icmd(dev, 0x000b08, 0x00000100);
+ nv_icmd(dev, 0x000b09, 0x00000100);
+ nv_icmd(dev, 0x000b0a, 0x00000001);
+ nv_icmd(dev, 0x000a04, 0x000000ff);
+ nv_icmd(dev, 0x000a0b, 0x00000040);
+ nv_icmd(dev, 0x00097f, 0x00000100);
+ nv_icmd(dev, 0x000a02, 0x00000001);
+ nv_icmd(dev, 0x000809, 0x00000007);
+ nv_icmd(dev, 0x00c221, 0x00000040);
+ nv_icmd(dev, 0x00c1b0, 0x0000000f);
+ nv_icmd(dev, 0x00c1b1, 0x0000000f);
+ nv_icmd(dev, 0x00c1b2, 0x0000000f);
+ nv_icmd(dev, 0x00c1b3, 0x0000000f);
+ nv_icmd(dev, 0x00c1b4, 0x0000000f);
+ nv_icmd(dev, 0x00c1b5, 0x0000000f);
+ nv_icmd(dev, 0x00c1b6, 0x0000000f);
+ nv_icmd(dev, 0x00c1b7, 0x0000000f);
+ nv_icmd(dev, 0x00c1b8, 0x0fac6881);
+ nv_icmd(dev, 0x00c1b9, 0x00fac688);
+ nv_icmd(dev, 0x00c401, 0x00000001);
+ nv_icmd(dev, 0x00c402, 0x00010001);
+ nv_icmd(dev, 0x00c403, 0x00000001);
+ nv_icmd(dev, 0x00c404, 0x00000001);
+ nv_icmd(dev, 0x00c40e, 0x00000020);
+ nv_icmd(dev, 0x00c500, 0x00000003);
+ nv_icmd(dev, 0x01e100, 0x00000001);
+ nv_icmd(dev, 0x001000, 0x00000002);
+ nv_icmd(dev, 0x0006aa, 0x00000001);
+ nv_icmd(dev, 0x0006ad, 0x00000100);
+ nv_icmd(dev, 0x0006ae, 0x00000100);
+ nv_icmd(dev, 0x0006b1, 0x00000011);
+ nv_icmd(dev, 0x00078c, 0x00000008);
+ nv_icmd(dev, 0x000792, 0x00000001);
+ nv_icmd(dev, 0x000794, 0x00000001);
+ nv_icmd(dev, 0x000795, 0x00000001);
+ nv_icmd(dev, 0x000796, 0x00000001);
+ nv_icmd(dev, 0x000797, 0x000000cf);
+ nv_icmd(dev, 0x00079a, 0x00000002);
+ nv_icmd(dev, 0x000833, 0x04444480);
+ nv_icmd(dev, 0x0007a1, 0x00000001);
+ nv_icmd(dev, 0x0007a3, 0x00000001);
+ nv_icmd(dev, 0x0007a4, 0x00000001);
+ nv_icmd(dev, 0x0007a5, 0x00000001);
+ nv_icmd(dev, 0x000831, 0x00000004);
+ nv_icmd(dev, 0x01e100, 0x00000001);
+ nv_icmd(dev, 0x001000, 0x00000008);
+ nv_icmd(dev, 0x000039, 0x00000000);
+ nv_icmd(dev, 0x00003a, 0x00000000);
+ nv_icmd(dev, 0x00003b, 0x00000000);
+ nv_icmd(dev, 0x000380, 0x00000001);
+ nv_icmd(dev, 0x000366, 0x00000000);
+ nv_icmd(dev, 0x000367, 0x00000000);
+ nv_icmd(dev, 0x000368, 0x00000fff);
+ nv_icmd(dev, 0x000370, 0x00000000);
+ nv_icmd(dev, 0x000371, 0x00000000);
+ nv_icmd(dev, 0x000372, 0x000fffff);
+ nv_icmd(dev, 0x000813, 0x00000006);
+ nv_icmd(dev, 0x000814, 0x00000008);
+ nv_icmd(dev, 0x000957, 0x00000003);
+ nv_icmd(dev, 0x000818, 0x00000000);
+ nv_icmd(dev, 0x000819, 0x00000000);
+ nv_icmd(dev, 0x00081a, 0x00000000);
+ nv_icmd(dev, 0x00081b, 0x00000000);
+ nv_icmd(dev, 0x00081c, 0x00000000);
+ nv_icmd(dev, 0x00081d, 0x00000000);
+ nv_icmd(dev, 0x00081e, 0x00000000);
+ nv_icmd(dev, 0x00081f, 0x00000000);
+ nv_icmd(dev, 0x000848, 0x00000000);
+ nv_icmd(dev, 0x000849, 0x00000000);
+ nv_icmd(dev, 0x00084a, 0x00000000);
+ nv_icmd(dev, 0x00084b, 0x00000000);
+ nv_icmd(dev, 0x00084c, 0x00000000);
+ nv_icmd(dev, 0x00084d, 0x00000000);
+ nv_icmd(dev, 0x00084e, 0x00000000);
+ nv_icmd(dev, 0x00084f, 0x00000000);
+ nv_icmd(dev, 0x000850, 0x00000000);
+ nv_icmd(dev, 0x000851, 0x00000000);
+ nv_icmd(dev, 0x000852, 0x00000000);
+ nv_icmd(dev, 0x000853, 0x00000000);
+ nv_icmd(dev, 0x000854, 0x00000000);
+ nv_icmd(dev, 0x000855, 0x00000000);
+ nv_icmd(dev, 0x000856, 0x00000000);
+ nv_icmd(dev, 0x000857, 0x00000000);
+ nv_icmd(dev, 0x000738, 0x00000000);
+ nv_icmd(dev, 0x000b07, 0x00000002);
+ nv_icmd(dev, 0x000b08, 0x00000100);
+ nv_icmd(dev, 0x000b09, 0x00000100);
+ nv_icmd(dev, 0x000b0a, 0x00000001);
+ nv_icmd(dev, 0x000a04, 0x000000ff);
+ nv_icmd(dev, 0x00097f, 0x00000100);
+ nv_icmd(dev, 0x000a02, 0x00000001);
+ nv_icmd(dev, 0x000809, 0x00000007);
+ nv_icmd(dev, 0x00c221, 0x00000040);
+ nv_icmd(dev, 0x00c401, 0x00000001);
+ nv_icmd(dev, 0x00c402, 0x00010001);
+ nv_icmd(dev, 0x00c403, 0x00000001);
+ nv_icmd(dev, 0x00c404, 0x00000001);
+ nv_icmd(dev, 0x00c40e, 0x00000020);
+ nv_icmd(dev, 0x00c500, 0x00000003);
+ nv_icmd(dev, 0x01e100, 0x00000001);
+ nv_icmd(dev, 0x001000, 0x00000001);
+ nv_icmd(dev, 0x000b07, 0x00000002);
+ nv_icmd(dev, 0x000b08, 0x00000100);
+ nv_icmd(dev, 0x000b09, 0x00000100);
+ nv_icmd(dev, 0x000b0a, 0x00000001);
+ nv_icmd(dev, 0x01e100, 0x00000001);
+ nv_wr32(dev, 0x400208, 0x00000000);
+}
+
+static void
+nv_mthd(struct drm_device *dev, u32 class, u32 mthd, u32 data)
+{
+ nv_wr32(dev, 0x40448c, data);
+ nv_wr32(dev, 0x404488, 0x80000000 | (mthd << 14) | class);
+}
+
+static void
+nve0_grctx_generate_a097(struct drm_device *dev)
+{
+ nv_mthd(dev, 0xa097, 0x0800, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0840, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0880, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x08c0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0900, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0940, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0980, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x09c0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0804, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0844, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0884, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x08c4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0904, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0944, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0984, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x09c4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0808, 0x00000400);
+ nv_mthd(dev, 0xa097, 0x0848, 0x00000400);
+ nv_mthd(dev, 0xa097, 0x0888, 0x00000400);
+ nv_mthd(dev, 0xa097, 0x08c8, 0x00000400);
+ nv_mthd(dev, 0xa097, 0x0908, 0x00000400);
+ nv_mthd(dev, 0xa097, 0x0948, 0x00000400);
+ nv_mthd(dev, 0xa097, 0x0988, 0x00000400);
+ nv_mthd(dev, 0xa097, 0x09c8, 0x00000400);
+ nv_mthd(dev, 0xa097, 0x080c, 0x00000300);
+ nv_mthd(dev, 0xa097, 0x084c, 0x00000300);
+ nv_mthd(dev, 0xa097, 0x088c, 0x00000300);
+ nv_mthd(dev, 0xa097, 0x08cc, 0x00000300);
+ nv_mthd(dev, 0xa097, 0x090c, 0x00000300);
+ nv_mthd(dev, 0xa097, 0x094c, 0x00000300);
+ nv_mthd(dev, 0xa097, 0x098c, 0x00000300);
+ nv_mthd(dev, 0xa097, 0x09cc, 0x00000300);
+ nv_mthd(dev, 0xa097, 0x0810, 0x000000cf);
+ nv_mthd(dev, 0xa097, 0x0850, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0890, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x08d0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0910, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0950, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0990, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x09d0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0814, 0x00000040);
+ nv_mthd(dev, 0xa097, 0x0854, 0x00000040);
+ nv_mthd(dev, 0xa097, 0x0894, 0x00000040);
+ nv_mthd(dev, 0xa097, 0x08d4, 0x00000040);
+ nv_mthd(dev, 0xa097, 0x0914, 0x00000040);
+ nv_mthd(dev, 0xa097, 0x0954, 0x00000040);
+ nv_mthd(dev, 0xa097, 0x0994, 0x00000040);
+ nv_mthd(dev, 0xa097, 0x09d4, 0x00000040);
+ nv_mthd(dev, 0xa097, 0x0818, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x0858, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x0898, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x08d8, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x0918, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x0958, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x0998, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x09d8, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x081c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x085c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x089c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x08dc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x091c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x095c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x099c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x09dc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0820, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0860, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x08a0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x08e0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0920, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0960, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x09a0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x09e0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c00, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c10, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c20, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c30, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c40, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c50, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c60, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c70, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c80, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c90, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1ca0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1cb0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1cc0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1cd0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1ce0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1cf0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c04, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c14, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c24, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c34, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c44, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c54, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c64, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c74, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c84, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c94, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1ca4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1cb4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1cc4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1cd4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1ce4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1cf4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c08, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c18, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c28, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c38, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c48, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c58, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c68, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c78, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c88, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c98, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1ca8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1cb8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1cc8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1cd8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1ce8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1cf8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c0c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c1c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c2c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c3c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c4c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c5c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c6c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c7c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c8c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1c9c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1cac, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1cbc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1ccc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1cdc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1cec, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1cfc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d00, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d10, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d20, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d30, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d40, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d50, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d60, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d70, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d80, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d90, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1da0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1db0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1dc0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1dd0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1de0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1df0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d04, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d14, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d24, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d34, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d44, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d54, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d64, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d74, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d84, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d94, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1da4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1db4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1dc4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1dd4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1de4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1df4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d08, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d18, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d28, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d38, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d48, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d58, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d68, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d78, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d88, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d98, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1da8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1db8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1dc8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1dd8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1de8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1df8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d0c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d1c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d2c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d3c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d4c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d5c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d6c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d7c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d8c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1d9c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1dac, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1dbc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1dcc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1ddc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1dec, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1dfc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f00, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f08, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f10, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f18, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f20, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f28, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f30, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f38, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f40, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f48, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f50, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f58, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f60, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f68, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f70, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f78, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f04, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f0c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f14, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f1c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f24, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f2c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f34, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f3c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f44, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f4c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f54, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f5c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f64, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f6c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f74, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f7c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f80, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f88, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f90, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f98, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1fa0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1fa8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1fb0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1fb8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1fc0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1fc8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1fd0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1fd8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1fe0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1fe8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1ff0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1ff8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f84, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f8c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f94, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1f9c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1fa4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1fac, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1fb4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1fbc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1fc4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1fcc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1fd4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1fdc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1fe4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1fec, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1ff4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1ffc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2000, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2040, 0x00000011);
+ nv_mthd(dev, 0xa097, 0x2080, 0x00000020);
+ nv_mthd(dev, 0xa097, 0x20c0, 0x00000030);
+ nv_mthd(dev, 0xa097, 0x2100, 0x00000040);
+ nv_mthd(dev, 0xa097, 0x2140, 0x00000051);
+ nv_mthd(dev, 0xa097, 0x200c, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x204c, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x208c, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x20cc, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x210c, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x214c, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x2010, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2050, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2090, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x20d0, 0x00000002);
+ nv_mthd(dev, 0xa097, 0x2110, 0x00000003);
+ nv_mthd(dev, 0xa097, 0x2150, 0x00000004);
+ nv_mthd(dev, 0xa097, 0x0380, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x03a0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x03c0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x03e0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0384, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x03a4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x03c4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x03e4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0388, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x03a8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x03c8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x03e8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x038c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x03ac, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x03cc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x03ec, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0700, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0710, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0720, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0730, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0704, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0714, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0724, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0734, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0708, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0718, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0728, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0738, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2800, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2804, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2808, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x280c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2810, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2814, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2818, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x281c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2820, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2824, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2828, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x282c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2830, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2834, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2838, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x283c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2840, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2844, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2848, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x284c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2850, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2854, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2858, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x285c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2860, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2864, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2868, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x286c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2870, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2874, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2878, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x287c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2880, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2884, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2888, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x288c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2890, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2894, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2898, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x289c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28a0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28a4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28a8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28ac, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28b0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28b4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28b8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28bc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28c0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28c4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28c8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28cc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28d0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28d4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28d8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28dc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28e0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28e4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28e8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28ec, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28f0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28f4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28f8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x28fc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2900, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2904, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2908, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x290c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2910, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2914, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2918, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x291c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2920, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2924, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2928, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x292c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2930, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2934, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2938, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x293c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2940, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2944, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2948, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x294c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2950, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2954, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2958, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x295c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2960, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2964, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2968, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x296c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2970, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2974, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2978, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x297c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2980, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2984, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2988, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x298c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2990, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2994, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2998, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x299c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29a0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29a4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29a8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29ac, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29b0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29b4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29b8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29bc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29c0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29c4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29c8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29cc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29d0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29d4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29d8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29dc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29e0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29e4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29e8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29ec, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29f0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29f4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29f8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x29fc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a00, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a20, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a40, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a60, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a80, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0aa0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ac0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ae0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b00, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b20, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b40, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b60, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b80, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ba0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0bc0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0be0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a04, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a24, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a44, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a64, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a84, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0aa4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ac4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ae4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b04, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b24, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b44, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b64, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b84, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ba4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0bc4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0be4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a08, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a28, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a48, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a68, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a88, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0aa8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ac8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ae8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b08, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b28, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b48, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b68, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b88, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ba8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0bc8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0be8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a0c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a2c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a4c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a6c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a8c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0aac, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0acc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0aec, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b0c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b2c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b4c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b6c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b8c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0bac, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0bcc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0bec, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a10, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a30, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a50, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a70, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a90, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ab0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ad0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0af0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b10, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b30, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b50, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b70, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b90, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0bb0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0bd0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0bf0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a14, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a34, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a54, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a74, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0a94, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ab4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ad4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0af4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b14, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b34, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b54, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b74, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0b94, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0bb4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0bd4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0bf4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c00, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c10, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c20, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c30, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c40, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c50, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c60, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c70, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c80, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c90, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ca0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0cb0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0cc0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0cd0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ce0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0cf0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c04, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c14, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c24, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c34, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c44, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c54, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c64, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c74, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c84, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c94, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ca4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0cb4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0cc4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0cd4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ce4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0cf4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c08, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c18, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c28, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c38, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c48, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c58, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c68, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c78, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c88, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c98, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ca8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0cb8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0cc8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0cd8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ce8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0cf8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0c0c, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x0c1c, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x0c2c, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x0c3c, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x0c4c, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x0c5c, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x0c6c, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x0c7c, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x0c8c, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x0c9c, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x0cac, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x0cbc, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x0ccc, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x0cdc, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x0cec, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x0cfc, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x0d00, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0d08, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0d10, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0d18, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0d20, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0d28, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0d30, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0d38, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0d04, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0d0c, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0d14, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0d1c, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0d24, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0d2c, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0d34, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0d3c, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0e00, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0e10, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0e20, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0e30, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0e40, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0e50, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0e60, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0e70, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0e80, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0e90, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ea0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0eb0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ec0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ed0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ee0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ef0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0e04, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0e14, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0e24, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0e34, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0e44, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0e54, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0e64, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0e74, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0e84, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0e94, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0ea4, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0eb4, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0ec4, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0ed4, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0ee4, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0ef4, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0e08, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0e18, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0e28, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0e38, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0e48, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0e58, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0e68, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0e78, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0e88, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0e98, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0ea8, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0eb8, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0ec8, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0ed8, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0ee8, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0ef8, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0d40, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0d48, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0d50, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0d58, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0d44, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0d4c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0d54, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0d5c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1e00, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e20, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e40, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e60, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e80, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1ea0, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1ec0, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1ee0, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e04, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e24, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e44, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e64, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e84, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1ea4, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1ec4, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1ee4, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e08, 0x00000002);
+ nv_mthd(dev, 0xa097, 0x1e28, 0x00000002);
+ nv_mthd(dev, 0xa097, 0x1e48, 0x00000002);
+ nv_mthd(dev, 0xa097, 0x1e68, 0x00000002);
+ nv_mthd(dev, 0xa097, 0x1e88, 0x00000002);
+ nv_mthd(dev, 0xa097, 0x1ea8, 0x00000002);
+ nv_mthd(dev, 0xa097, 0x1ec8, 0x00000002);
+ nv_mthd(dev, 0xa097, 0x1ee8, 0x00000002);
+ nv_mthd(dev, 0xa097, 0x1e0c, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e2c, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e4c, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e6c, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e8c, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1eac, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1ecc, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1eec, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e10, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e30, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e50, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e70, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e90, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1eb0, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1ed0, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1ef0, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e14, 0x00000002);
+ nv_mthd(dev, 0xa097, 0x1e34, 0x00000002);
+ nv_mthd(dev, 0xa097, 0x1e54, 0x00000002);
+ nv_mthd(dev, 0xa097, 0x1e74, 0x00000002);
+ nv_mthd(dev, 0xa097, 0x1e94, 0x00000002);
+ nv_mthd(dev, 0xa097, 0x1eb4, 0x00000002);
+ nv_mthd(dev, 0xa097, 0x1ed4, 0x00000002);
+ nv_mthd(dev, 0xa097, 0x1ef4, 0x00000002);
+ nv_mthd(dev, 0xa097, 0x1e18, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e38, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e58, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e78, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1e98, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1eb8, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1ed8, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1ef8, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x3400, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3404, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3408, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x340c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3410, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3414, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3418, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x341c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3420, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3424, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3428, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x342c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3430, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3434, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3438, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x343c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3440, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3444, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3448, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x344c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3450, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3454, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3458, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x345c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3460, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3464, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3468, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x346c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3470, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3474, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3478, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x347c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3480, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3484, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3488, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x348c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3490, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3494, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3498, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x349c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34a0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34a4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34a8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34ac, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34b0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34b4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34b8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34bc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34c0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34c4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34c8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34cc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34d0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34d4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34d8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34dc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34e0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34e4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34e8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34ec, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34f0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34f4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34f8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x34fc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3500, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3504, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3508, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x350c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3510, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3514, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3518, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x351c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3520, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3524, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3528, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x352c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3530, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3534, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3538, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x353c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3540, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3544, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3548, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x354c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3550, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3554, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3558, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x355c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3560, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3564, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3568, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x356c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3570, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3574, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3578, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x357c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3580, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3584, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3588, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x358c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3590, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3594, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x3598, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x359c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35a0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35a4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35a8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35ac, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35b0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35b4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35b8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35bc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35c0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35c4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35c8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35cc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35d0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35d4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35d8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35dc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35e0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35e4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35e8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35ec, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35f0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35f4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35f8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x35fc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x030c, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1944, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1514, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0d68, 0x0000ffff);
+ nv_mthd(dev, 0xa097, 0x121c, 0x0fac6881);
+ nv_mthd(dev, 0xa097, 0x0fac, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1538, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x0fe0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0fe4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0fe8, 0x00000014);
+ nv_mthd(dev, 0xa097, 0x0fec, 0x00000040);
+ nv_mthd(dev, 0xa097, 0x0ff0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x179c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1228, 0x00000400);
+ nv_mthd(dev, 0xa097, 0x122c, 0x00000300);
+ nv_mthd(dev, 0xa097, 0x1230, 0x00010001);
+ nv_mthd(dev, 0xa097, 0x07f8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x15b4, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x15cc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1534, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0fb0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x15d0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x153c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x16b4, 0x00000003);
+ nv_mthd(dev, 0xa097, 0x0fbc, 0x0000ffff);
+ nv_mthd(dev, 0xa097, 0x0fc0, 0x0000ffff);
+ nv_mthd(dev, 0xa097, 0x0fc4, 0x0000ffff);
+ nv_mthd(dev, 0xa097, 0x0fc8, 0x0000ffff);
+ nv_mthd(dev, 0xa097, 0x0df8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0dfc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1948, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1970, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x161c, 0x000009f0);
+ nv_mthd(dev, 0xa097, 0x0dcc, 0x00000010);
+ nv_mthd(dev, 0xa097, 0x163c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x15e4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1160, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x1164, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x1168, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x116c, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x1170, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x1174, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x1178, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x117c, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x1180, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x1184, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x1188, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x118c, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x1190, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x1194, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x1198, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x119c, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x11a0, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x11a4, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x11a8, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x11ac, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x11b0, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x11b4, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x11b8, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x11bc, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x11c0, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x11c4, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x11c8, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x11cc, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x11d0, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x11d4, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x11d8, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x11dc, 0x25e00040);
+ nv_mthd(dev, 0xa097, 0x1880, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1884, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1888, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x188c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1890, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1894, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1898, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x189c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18a0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18a4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18a8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18ac, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18b0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18b4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18b8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18bc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18c0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18c4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18c8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18cc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18d0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18d4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18d8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18dc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18e0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18e4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18e8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18ec, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18f0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18f4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18f8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x18fc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0f84, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0f88, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x17c8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x17cc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x17d0, 0x000000ff);
+ nv_mthd(dev, 0xa097, 0x17d4, 0xffffffff);
+ nv_mthd(dev, 0xa097, 0x17d8, 0x00000002);
+ nv_mthd(dev, 0xa097, 0x17dc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x15f4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x15f8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1434, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1438, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0d74, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0dec, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x13a4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1318, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1644, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0748, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0de8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1648, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x12a4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1120, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1124, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1128, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x112c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1118, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x164c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1658, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1910, 0x00000290);
+ nv_mthd(dev, 0xa097, 0x1518, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x165c, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1520, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1604, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1570, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x13b0, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x13b4, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x020c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1670, 0x30201000);
+ nv_mthd(dev, 0xa097, 0x1674, 0x70605040);
+ nv_mthd(dev, 0xa097, 0x1678, 0xb8a89888);
+ nv_mthd(dev, 0xa097, 0x167c, 0xf8e8d8c8);
+ nv_mthd(dev, 0xa097, 0x166c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1680, 0x00ffff00);
+ nv_mthd(dev, 0xa097, 0x12d0, 0x00000003);
+ nv_mthd(dev, 0xa097, 0x12d4, 0x00000002);
+ nv_mthd(dev, 0xa097, 0x1684, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1688, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0dac, 0x00001b02);
+ nv_mthd(dev, 0xa097, 0x0db0, 0x00001b02);
+ nv_mthd(dev, 0xa097, 0x0db4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x168c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x15bc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x156c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x187c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1110, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x0dc0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0dc4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0dc8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1234, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1690, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x12ac, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x0790, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0794, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0798, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x079c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x07a0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x077c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1000, 0x00000010);
+ nv_mthd(dev, 0xa097, 0x10fc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1290, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0218, 0x00000010);
+ nv_mthd(dev, 0xa097, 0x12d8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x12dc, 0x00000010);
+ nv_mthd(dev, 0xa097, 0x0d94, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x155c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1560, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1564, 0x00000fff);
+ nv_mthd(dev, 0xa097, 0x1574, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1578, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x157c, 0x000fffff);
+ nv_mthd(dev, 0xa097, 0x1354, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1610, 0x00000012);
+ nv_mthd(dev, 0xa097, 0x1608, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x160c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x260c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x07ac, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x162c, 0x00000003);
+ nv_mthd(dev, 0xa097, 0x0210, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0320, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0324, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x0328, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x032c, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x0330, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x0334, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x0338, 0x3f800000);
+ nv_mthd(dev, 0xa097, 0x0750, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0760, 0x39291909);
+ nv_mthd(dev, 0xa097, 0x0764, 0x79695949);
+ nv_mthd(dev, 0xa097, 0x0768, 0xb9a99989);
+ nv_mthd(dev, 0xa097, 0x076c, 0xf9e9d9c9);
+ nv_mthd(dev, 0xa097, 0x0770, 0x30201000);
+ nv_mthd(dev, 0xa097, 0x0774, 0x70605040);
+ nv_mthd(dev, 0xa097, 0x0778, 0x00009080);
+ nv_mthd(dev, 0xa097, 0x0780, 0x39291909);
+ nv_mthd(dev, 0xa097, 0x0784, 0x79695949);
+ nv_mthd(dev, 0xa097, 0x0788, 0xb9a99989);
+ nv_mthd(dev, 0xa097, 0x078c, 0xf9e9d9c9);
+ nv_mthd(dev, 0xa097, 0x07d0, 0x30201000);
+ nv_mthd(dev, 0xa097, 0x07d4, 0x70605040);
+ nv_mthd(dev, 0xa097, 0x07d8, 0x00009080);
+ nv_mthd(dev, 0xa097, 0x037c, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x0740, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0744, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x2600, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1918, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x191c, 0x00000900);
+ nv_mthd(dev, 0xa097, 0x1920, 0x00000405);
+ nv_mthd(dev, 0xa097, 0x1308, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1924, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x13ac, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x192c, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x193c, 0x00002c1c);
+ nv_mthd(dev, 0xa097, 0x0d7c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0f8c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x02c0, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1510, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1940, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ff4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0ff8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x194c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1950, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1968, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1590, 0x0000003f);
+ nv_mthd(dev, 0xa097, 0x07e8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x07ec, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x07f0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x07f4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x196c, 0x00000011);
+ nv_mthd(dev, 0xa097, 0x02e4, 0x0000b001);
+ nv_mthd(dev, 0xa097, 0x036c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0370, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x197c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0fcc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0fd0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x02d8, 0x00000040);
+ nv_mthd(dev, 0xa097, 0x1980, 0x00000080);
+ nv_mthd(dev, 0xa097, 0x1504, 0x00000080);
+ nv_mthd(dev, 0xa097, 0x1984, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0300, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x13a8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x12ec, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1310, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1314, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1380, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1384, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1388, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x138c, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1390, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1394, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x139c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1398, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1594, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1598, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x159c, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x15a0, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x15a4, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x0f54, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0f58, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0f5c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x19bc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0f9c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0fa0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x12cc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x12e8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x130c, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1360, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1364, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1368, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x136c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1370, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1374, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1378, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x137c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x133c, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1340, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1344, 0x00000002);
+ nv_mthd(dev, 0xa097, 0x1348, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x134c, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1350, 0x00000002);
+ nv_mthd(dev, 0xa097, 0x1358, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x12e4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x131c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1320, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1324, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1328, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x19c0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1140, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x19c4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x19c8, 0x00001500);
+ nv_mthd(dev, 0xa097, 0x135c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0f90, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x19e0, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x19e4, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x19e8, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x19ec, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x19f0, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x19f4, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x19f8, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x19fc, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x19cc, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x15b8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1a00, 0x00001111);
+ nv_mthd(dev, 0xa097, 0x1a04, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1a08, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1a0c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1a10, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1a14, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1a18, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1a1c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0d6c, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x0d70, 0xffff0000);
+ nv_mthd(dev, 0xa097, 0x10f8, 0x00001010);
+ nv_mthd(dev, 0xa097, 0x0d80, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0d84, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0d88, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0d8c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0d90, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0da0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x07a4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x07a8, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1508, 0x80000000);
+ nv_mthd(dev, 0xa097, 0x150c, 0x40000000);
+ nv_mthd(dev, 0xa097, 0x1668, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0318, 0x00000008);
+ nv_mthd(dev, 0xa097, 0x031c, 0x00000008);
+ nv_mthd(dev, 0xa097, 0x0d9c, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x0374, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0378, 0x00000020);
+ nv_mthd(dev, 0xa097, 0x07dc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x074c, 0x00000055);
+ nv_mthd(dev, 0xa097, 0x1420, 0x00000003);
+ nv_mthd(dev, 0xa097, 0x17bc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x17c0, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x17c4, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1008, 0x00000008);
+ nv_mthd(dev, 0xa097, 0x100c, 0x00000040);
+ nv_mthd(dev, 0xa097, 0x1010, 0x0000012c);
+ nv_mthd(dev, 0xa097, 0x0d60, 0x00000040);
+ nv_mthd(dev, 0xa097, 0x075c, 0x00000003);
+ nv_mthd(dev, 0xa097, 0x1018, 0x00000020);
+ nv_mthd(dev, 0xa097, 0x101c, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1020, 0x00000020);
+ nv_mthd(dev, 0xa097, 0x1024, 0x00000001);
+ nv_mthd(dev, 0xa097, 0x1444, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x1448, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x144c, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0360, 0x20164010);
+ nv_mthd(dev, 0xa097, 0x0364, 0x00000020);
+ nv_mthd(dev, 0xa097, 0x0368, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0de4, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0204, 0x00000006);
+ nv_mthd(dev, 0xa097, 0x0208, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x02cc, 0x003fffff);
+ nv_mthd(dev, 0xa097, 0x02d0, 0x003fffff);
+ nv_mthd(dev, 0xa097, 0x1220, 0x00000005);
+ nv_mthd(dev, 0xa097, 0x0fdc, 0x00000000);
+ nv_mthd(dev, 0xa097, 0x0f98, 0x00400008);
+ nv_mthd(dev, 0xa097, 0x1284, 0x08000080);
+ nv_mthd(dev, 0xa097, 0x1450, 0x00400008);
+ nv_mthd(dev, 0xa097, 0x1454, 0x08000080);
+ nv_mthd(dev, 0xa097, 0x0214, 0x00000000);
+}
+
+static void
+nve0_grctx_generate_902d(struct drm_device *dev)
+{
+ nv_mthd(dev, 0x902d, 0x0200, 0x000000cf);
+ nv_mthd(dev, 0x902d, 0x0204, 0x00000001);
+ nv_mthd(dev, 0x902d, 0x0208, 0x00000020);
+ nv_mthd(dev, 0x902d, 0x020c, 0x00000001);
+ nv_mthd(dev, 0x902d, 0x0210, 0x00000000);
+ nv_mthd(dev, 0x902d, 0x0214, 0x00000080);
+ nv_mthd(dev, 0x902d, 0x0218, 0x00000100);
+ nv_mthd(dev, 0x902d, 0x021c, 0x00000100);
+ nv_mthd(dev, 0x902d, 0x0220, 0x00000000);
+ nv_mthd(dev, 0x902d, 0x0224, 0x00000000);
+ nv_mthd(dev, 0x902d, 0x0230, 0x000000cf);
+ nv_mthd(dev, 0x902d, 0x0234, 0x00000001);
+ nv_mthd(dev, 0x902d, 0x0238, 0x00000020);
+ nv_mthd(dev, 0x902d, 0x023c, 0x00000001);
+ nv_mthd(dev, 0x902d, 0x0244, 0x00000080);
+ nv_mthd(dev, 0x902d, 0x0248, 0x00000100);
+ nv_mthd(dev, 0x902d, 0x024c, 0x00000100);
+ nv_mthd(dev, 0x902d, 0x3410, 0x00000000);
+}
+
+static void
+nve0_graph_generate_unk40xx(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x404010, 0x0);
+ nv_wr32(dev, 0x404014, 0x0);
+ nv_wr32(dev, 0x404018, 0x0);
+ nv_wr32(dev, 0x40401c, 0x0);
+ nv_wr32(dev, 0x404020, 0x0);
+ nv_wr32(dev, 0x404024, 0xe000);
+ nv_wr32(dev, 0x404028, 0x0);
+ nv_wr32(dev, 0x4040a8, 0x0);
+ nv_wr32(dev, 0x4040ac, 0x0);
+ nv_wr32(dev, 0x4040b0, 0x0);
+ nv_wr32(dev, 0x4040b4, 0x0);
+ nv_wr32(dev, 0x4040b8, 0x0);
+ nv_wr32(dev, 0x4040bc, 0x0);
+ nv_wr32(dev, 0x4040c0, 0x0);
+ nv_wr32(dev, 0x4040c4, 0x0);
+ nv_wr32(dev, 0x4040c8, 0xf800008f);
+ nv_wr32(dev, 0x4040d0, 0x0);
+ nv_wr32(dev, 0x4040d4, 0x0);
+ nv_wr32(dev, 0x4040d8, 0x0);
+ nv_wr32(dev, 0x4040dc, 0x0);
+ nv_wr32(dev, 0x4040e0, 0x0);
+ nv_wr32(dev, 0x4040e4, 0x0);
+ nv_wr32(dev, 0x4040e8, 0x1000);
+ nv_wr32(dev, 0x4040f8, 0x0);
+ nv_wr32(dev, 0x404130, 0x0);
+ nv_wr32(dev, 0x404134, 0x0);
+ nv_wr32(dev, 0x404138, 0x20000040);
+ nv_wr32(dev, 0x404150, 0x2e);
+ nv_wr32(dev, 0x404154, 0x400);
+ nv_wr32(dev, 0x404158, 0x200);
+ nv_wr32(dev, 0x404164, 0x55);
+ nv_wr32(dev, 0x4041a0, 0x0);
+ nv_wr32(dev, 0x4041a4, 0x0);
+ nv_wr32(dev, 0x4041a8, 0x0);
+ nv_wr32(dev, 0x4041ac, 0x0);
+ nv_wr32(dev, 0x404200, 0x0);
+ nv_wr32(dev, 0x404204, 0x0);
+ nv_wr32(dev, 0x404208, 0x0);
+ nv_wr32(dev, 0x40420c, 0x0);
+}
+
+static void
+nve0_graph_generate_unk44xx(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x404404, 0x0);
+ nv_wr32(dev, 0x404408, 0x0);
+ nv_wr32(dev, 0x40440c, 0x0);
+ nv_wr32(dev, 0x404410, 0x0);
+ nv_wr32(dev, 0x404414, 0x0);
+ nv_wr32(dev, 0x404418, 0x0);
+ nv_wr32(dev, 0x40441c, 0x0);
+ nv_wr32(dev, 0x404420, 0x0);
+ nv_wr32(dev, 0x404424, 0x0);
+ nv_wr32(dev, 0x404428, 0x0);
+ nv_wr32(dev, 0x40442c, 0x0);
+ nv_wr32(dev, 0x404430, 0x0);
+ nv_wr32(dev, 0x404434, 0x0);
+ nv_wr32(dev, 0x404438, 0x0);
+ nv_wr32(dev, 0x404460, 0x0);
+ nv_wr32(dev, 0x404464, 0x0);
+ nv_wr32(dev, 0x404468, 0xffffff);
+ nv_wr32(dev, 0x40446c, 0x0);
+ nv_wr32(dev, 0x404480, 0x1);
+ nv_wr32(dev, 0x404498, 0x1);
+}
+
+static void
+nve0_graph_generate_unk46xx(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x404604, 0x14);
+ nv_wr32(dev, 0x404608, 0x0);
+ nv_wr32(dev, 0x40460c, 0x3fff);
+ nv_wr32(dev, 0x404610, 0x100);
+ nv_wr32(dev, 0x404618, 0x0);
+ nv_wr32(dev, 0x40461c, 0x0);
+ nv_wr32(dev, 0x404620, 0x0);
+ nv_wr32(dev, 0x404624, 0x0);
+ nv_wr32(dev, 0x40462c, 0x0);
+ nv_wr32(dev, 0x404630, 0x0);
+ nv_wr32(dev, 0x404640, 0x0);
+ nv_wr32(dev, 0x404654, 0x0);
+ nv_wr32(dev, 0x404660, 0x0);
+ nv_wr32(dev, 0x404678, 0x0);
+ nv_wr32(dev, 0x40467c, 0x2);
+ nv_wr32(dev, 0x404680, 0x0);
+ nv_wr32(dev, 0x404684, 0x0);
+ nv_wr32(dev, 0x404688, 0x0);
+ nv_wr32(dev, 0x40468c, 0x0);
+ nv_wr32(dev, 0x404690, 0x0);
+ nv_wr32(dev, 0x404694, 0x0);
+ nv_wr32(dev, 0x404698, 0x0);
+ nv_wr32(dev, 0x40469c, 0x0);
+ nv_wr32(dev, 0x4046a0, 0x7f0080);
+ nv_wr32(dev, 0x4046a4, 0x0);
+ nv_wr32(dev, 0x4046a8, 0x0);
+ nv_wr32(dev, 0x4046ac, 0x0);
+ nv_wr32(dev, 0x4046b0, 0x0);
+ nv_wr32(dev, 0x4046b4, 0x0);
+ nv_wr32(dev, 0x4046b8, 0x0);
+ nv_wr32(dev, 0x4046bc, 0x0);
+ nv_wr32(dev, 0x4046c0, 0x0);
+ nv_wr32(dev, 0x4046c8, 0x0);
+ nv_wr32(dev, 0x4046cc, 0x0);
+ nv_wr32(dev, 0x4046d0, 0x0);
+}
+
+static void
+nve0_graph_generate_unk47xx(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x404700, 0x0);
+ nv_wr32(dev, 0x404704, 0x0);
+ nv_wr32(dev, 0x404708, 0x0);
+ nv_wr32(dev, 0x404718, 0x0);
+ nv_wr32(dev, 0x40471c, 0x0);
+ nv_wr32(dev, 0x404720, 0x0);
+ nv_wr32(dev, 0x404724, 0x0);
+ nv_wr32(dev, 0x404728, 0x0);
+ nv_wr32(dev, 0x40472c, 0x0);
+ nv_wr32(dev, 0x404730, 0x0);
+ nv_wr32(dev, 0x404734, 0x100);
+ nv_wr32(dev, 0x404738, 0x0);
+ nv_wr32(dev, 0x40473c, 0x0);
+ nv_wr32(dev, 0x404744, 0x0);
+ nv_wr32(dev, 0x404748, 0x0);
+ nv_wr32(dev, 0x404754, 0x0);
+}
+
+static void
+nve0_graph_generate_unk58xx(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x405800, 0xf8000bf);
+ nv_wr32(dev, 0x405830, 0x2180648);
+ nv_wr32(dev, 0x405834, 0x8000000);
+ nv_wr32(dev, 0x405838, 0x0);
+ nv_wr32(dev, 0x405854, 0x0);
+ nv_wr32(dev, 0x405870, 0x1);
+ nv_wr32(dev, 0x405874, 0x1);
+ nv_wr32(dev, 0x405878, 0x1);
+ nv_wr32(dev, 0x40587c, 0x1);
+ nv_wr32(dev, 0x405a00, 0x0);
+ nv_wr32(dev, 0x405a04, 0x0);
+ nv_wr32(dev, 0x405a18, 0x0);
+ nv_wr32(dev, 0x405b00, 0x0);
+ nv_wr32(dev, 0x405b10, 0x1000);
+}
+
+static void
+nve0_graph_generate_unk60xx(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x406020, 0x4103c1);
+ nv_wr32(dev, 0x406028, 0x1);
+ nv_wr32(dev, 0x40602c, 0x1);
+ nv_wr32(dev, 0x406030, 0x1);
+ nv_wr32(dev, 0x406034, 0x1);
+}
+
+static void
+nve0_graph_generate_unk64xx(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x4064a8, 0x0);
+ nv_wr32(dev, 0x4064ac, 0x3fff);
+ nv_wr32(dev, 0x4064b4, 0x0);
+ nv_wr32(dev, 0x4064b8, 0x0);
+ nv_wr32(dev, 0x4064c0, 0x801a00f0);
+ nv_wr32(dev, 0x4064c4, 0x192ffff);
+ nv_wr32(dev, 0x4064c8, 0x1800600);
+ nv_wr32(dev, 0x4064cc, 0x0);
+ nv_wr32(dev, 0x4064d0, 0x0);
+ nv_wr32(dev, 0x4064d4, 0x0);
+ nv_wr32(dev, 0x4064d8, 0x0);
+ nv_wr32(dev, 0x4064dc, 0x0);
+ nv_wr32(dev, 0x4064e0, 0x0);
+ nv_wr32(dev, 0x4064e4, 0x0);
+ nv_wr32(dev, 0x4064e8, 0x0);
+ nv_wr32(dev, 0x4064ec, 0x0);
+ nv_wr32(dev, 0x4064fc, 0x22a);
+}
+
+static void
+nve0_graph_generate_unk70xx(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x407040, 0x0);
+}
+
+static void
+nve0_graph_generate_unk78xx(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x407804, 0x23);
+ nv_wr32(dev, 0x40780c, 0xa418820);
+ nv_wr32(dev, 0x407810, 0x62080e6);
+ nv_wr32(dev, 0x407814, 0x20398a4);
+ nv_wr32(dev, 0x407818, 0xe629062);
+ nv_wr32(dev, 0x40781c, 0xa418820);
+ nv_wr32(dev, 0x407820, 0xe6);
+ nv_wr32(dev, 0x4078bc, 0x103);
+}
+
+static void
+nve0_graph_generate_unk80xx(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x408000, 0x0);
+ nv_wr32(dev, 0x408004, 0x0);
+ nv_wr32(dev, 0x408008, 0x30);
+ nv_wr32(dev, 0x40800c, 0x0);
+ nv_wr32(dev, 0x408010, 0x0);
+ nv_wr32(dev, 0x408014, 0x69);
+ nv_wr32(dev, 0x408018, 0xe100e100);
+ nv_wr32(dev, 0x408064, 0x0);
+}
+
+static void
+nve0_graph_generate_unk88xx(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x408800, 0x2802a3c);
+ nv_wr32(dev, 0x408804, 0x40);
+ nv_wr32(dev, 0x408808, 0x1043e005);
+ nv_wr32(dev, 0x408840, 0xb);
+ nv_wr32(dev, 0x408900, 0x3080b801);
+ nv_wr32(dev, 0x408904, 0x62000001);
+ nv_wr32(dev, 0x408908, 0xc8102f);
+ nv_wr32(dev, 0x408980, 0x11d);
+}
+
+static void
+nve0_graph_generate_gpc(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x418380, 0x16);
+ nv_wr32(dev, 0x418400, 0x38004e00);
+ nv_wr32(dev, 0x418404, 0x71e0ffff);
+ nv_wr32(dev, 0x41840c, 0x1008);
+ nv_wr32(dev, 0x418410, 0xfff0fff);
+ nv_wr32(dev, 0x418414, 0x2200fff);
+ nv_wr32(dev, 0x418450, 0x0);
+ nv_wr32(dev, 0x418454, 0x0);
+ nv_wr32(dev, 0x418458, 0x0);
+ nv_wr32(dev, 0x41845c, 0x0);
+ nv_wr32(dev, 0x418460, 0x0);
+ nv_wr32(dev, 0x418464, 0x0);
+ nv_wr32(dev, 0x418468, 0x1);
+ nv_wr32(dev, 0x41846c, 0x0);
+ nv_wr32(dev, 0x418470, 0x0);
+ nv_wr32(dev, 0x418600, 0x1f);
+ nv_wr32(dev, 0x418684, 0xf);
+ nv_wr32(dev, 0x418700, 0x2);
+ nv_wr32(dev, 0x418704, 0x80);
+ nv_wr32(dev, 0x418708, 0x0);
+ nv_wr32(dev, 0x41870c, 0x0);
+ nv_wr32(dev, 0x418710, 0x0);
+ nv_wr32(dev, 0x418800, 0x7006860a);
+ nv_wr32(dev, 0x418808, 0x0);
+ nv_wr32(dev, 0x41880c, 0x0);
+ nv_wr32(dev, 0x418810, 0x0);
+ nv_wr32(dev, 0x418828, 0x44);
+ nv_wr32(dev, 0x418830, 0x10000001);
+ nv_wr32(dev, 0x4188d8, 0x8);
+ nv_wr32(dev, 0x4188e0, 0x1000000);
+ nv_wr32(dev, 0x4188e8, 0x0);
+ nv_wr32(dev, 0x4188ec, 0x0);
+ nv_wr32(dev, 0x4188f0, 0x0);
+ nv_wr32(dev, 0x4188f4, 0x0);
+ nv_wr32(dev, 0x4188f8, 0x0);
+ nv_wr32(dev, 0x4188fc, 0x20100018);
+ nv_wr32(dev, 0x41891c, 0xff00ff);
+ nv_wr32(dev, 0x418924, 0x0);
+ nv_wr32(dev, 0x418928, 0xffff00);
+ nv_wr32(dev, 0x41892c, 0xff00);
+ nv_wr32(dev, 0x418a00, 0x0);
+ nv_wr32(dev, 0x418a04, 0x0);
+ nv_wr32(dev, 0x418a08, 0x0);
+ nv_wr32(dev, 0x418a0c, 0x10000);
+ nv_wr32(dev, 0x418a10, 0x0);
+ nv_wr32(dev, 0x418a14, 0x0);
+ nv_wr32(dev, 0x418a18, 0x0);
+ nv_wr32(dev, 0x418a20, 0x0);
+ nv_wr32(dev, 0x418a24, 0x0);
+ nv_wr32(dev, 0x418a28, 0x0);
+ nv_wr32(dev, 0x418a2c, 0x10000);
+ nv_wr32(dev, 0x418a30, 0x0);
+ nv_wr32(dev, 0x418a34, 0x0);
+ nv_wr32(dev, 0x418a38, 0x0);
+ nv_wr32(dev, 0x418a40, 0x0);
+ nv_wr32(dev, 0x418a44, 0x0);
+ nv_wr32(dev, 0x418a48, 0x0);
+ nv_wr32(dev, 0x418a4c, 0x10000);
+ nv_wr32(dev, 0x418a50, 0x0);
+ nv_wr32(dev, 0x418a54, 0x0);
+ nv_wr32(dev, 0x418a58, 0x0);
+ nv_wr32(dev, 0x418a60, 0x0);
+ nv_wr32(dev, 0x418a64, 0x0);
+ nv_wr32(dev, 0x418a68, 0x0);
+ nv_wr32(dev, 0x418a6c, 0x10000);
+ nv_wr32(dev, 0x418a70, 0x0);
+ nv_wr32(dev, 0x418a74, 0x0);
+ nv_wr32(dev, 0x418a78, 0x0);
+ nv_wr32(dev, 0x418a80, 0x0);
+ nv_wr32(dev, 0x418a84, 0x0);
+ nv_wr32(dev, 0x418a88, 0x0);
+ nv_wr32(dev, 0x418a8c, 0x10000);
+ nv_wr32(dev, 0x418a90, 0x0);
+ nv_wr32(dev, 0x418a94, 0x0);
+ nv_wr32(dev, 0x418a98, 0x0);
+ nv_wr32(dev, 0x418aa0, 0x0);
+ nv_wr32(dev, 0x418aa4, 0x0);
+ nv_wr32(dev, 0x418aa8, 0x0);
+ nv_wr32(dev, 0x418aac, 0x10000);
+ nv_wr32(dev, 0x418ab0, 0x0);
+ nv_wr32(dev, 0x418ab4, 0x0);
+ nv_wr32(dev, 0x418ab8, 0x0);
+ nv_wr32(dev, 0x418ac0, 0x0);
+ nv_wr32(dev, 0x418ac4, 0x0);
+ nv_wr32(dev, 0x418ac8, 0x0);
+ nv_wr32(dev, 0x418acc, 0x10000);
+ nv_wr32(dev, 0x418ad0, 0x0);
+ nv_wr32(dev, 0x418ad4, 0x0);
+ nv_wr32(dev, 0x418ad8, 0x0);
+ nv_wr32(dev, 0x418ae0, 0x0);
+ nv_wr32(dev, 0x418ae4, 0x0);
+ nv_wr32(dev, 0x418ae8, 0x0);
+ nv_wr32(dev, 0x418aec, 0x10000);
+ nv_wr32(dev, 0x418af0, 0x0);
+ nv_wr32(dev, 0x418af4, 0x0);
+ nv_wr32(dev, 0x418af8, 0x0);
+ nv_wr32(dev, 0x418b00, 0x6);
+ nv_wr32(dev, 0x418b08, 0xa418820);
+ nv_wr32(dev, 0x418b0c, 0x62080e6);
+ nv_wr32(dev, 0x418b10, 0x20398a4);
+ nv_wr32(dev, 0x418b14, 0xe629062);
+ nv_wr32(dev, 0x418b18, 0xa418820);
+ nv_wr32(dev, 0x418b1c, 0xe6);
+ nv_wr32(dev, 0x418bb8, 0x103);
+ nv_wr32(dev, 0x418c08, 0x1);
+ nv_wr32(dev, 0x418c10, 0x0);
+ nv_wr32(dev, 0x418c14, 0x0);
+ nv_wr32(dev, 0x418c18, 0x0);
+ nv_wr32(dev, 0x418c1c, 0x0);
+ nv_wr32(dev, 0x418c20, 0x0);
+ nv_wr32(dev, 0x418c24, 0x0);
+ nv_wr32(dev, 0x418c28, 0x0);
+ nv_wr32(dev, 0x418c2c, 0x0);
+ nv_wr32(dev, 0x418c40, 0xffffffff);
+ nv_wr32(dev, 0x418c6c, 0x1);
+ nv_wr32(dev, 0x418c80, 0x20200004);
+ nv_wr32(dev, 0x418c8c, 0x1);
+ nv_wr32(dev, 0x419000, 0x780);
+ nv_wr32(dev, 0x419004, 0x0);
+ nv_wr32(dev, 0x419008, 0x0);
+ nv_wr32(dev, 0x419014, 0x4);
+}
+
+static void
+nve0_graph_generate_tpc(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x419848, 0x0);
+ nv_wr32(dev, 0x419864, 0x129);
+ nv_wr32(dev, 0x419888, 0x0);
+ nv_wr32(dev, 0x419a00, 0xf0);
+ nv_wr32(dev, 0x419a04, 0x1);
+ nv_wr32(dev, 0x419a08, 0x21);
+ nv_wr32(dev, 0x419a0c, 0x20000);
+ nv_wr32(dev, 0x419a10, 0x0);
+ nv_wr32(dev, 0x419a14, 0x200);
+ nv_wr32(dev, 0x419a1c, 0xc000);
+ nv_wr32(dev, 0x419a20, 0x800);
+ nv_wr32(dev, 0x419a30, 0x1);
+ nv_wr32(dev, 0x419ac4, 0x37f440);
+ nv_wr32(dev, 0x419c00, 0xa);
+ nv_wr32(dev, 0x419c04, 0x80000006);
+ nv_wr32(dev, 0x419c08, 0x2);
+ nv_wr32(dev, 0x419c20, 0x0);
+ nv_wr32(dev, 0x419c24, 0x84210);
+ nv_wr32(dev, 0x419c28, 0x3efbefbe);
+ nv_wr32(dev, 0x419ce8, 0x0);
+ nv_wr32(dev, 0x419cf4, 0x3203);
+ nv_wr32(dev, 0x419e04, 0x0);
+ nv_wr32(dev, 0x419e08, 0x0);
+ nv_wr32(dev, 0x419e0c, 0x0);
+ nv_wr32(dev, 0x419e10, 0x402);
+ nv_wr32(dev, 0x419e44, 0x13eff2);
+ nv_wr32(dev, 0x419e48, 0x0);
+ nv_wr32(dev, 0x419e4c, 0x7f);
+ nv_wr32(dev, 0x419e50, 0x0);
+ nv_wr32(dev, 0x419e54, 0x0);
+ nv_wr32(dev, 0x419e58, 0x0);
+ nv_wr32(dev, 0x419e5c, 0x0);
+ nv_wr32(dev, 0x419e60, 0x0);
+ nv_wr32(dev, 0x419e64, 0x0);
+ nv_wr32(dev, 0x419e68, 0x0);
+ nv_wr32(dev, 0x419e6c, 0x0);
+ nv_wr32(dev, 0x419e70, 0x0);
+ nv_wr32(dev, 0x419e74, 0x0);
+ nv_wr32(dev, 0x419e78, 0x0);
+ nv_wr32(dev, 0x419e7c, 0x0);
+ nv_wr32(dev, 0x419e80, 0x0);
+ nv_wr32(dev, 0x419e84, 0x0);
+ nv_wr32(dev, 0x419e88, 0x0);
+ nv_wr32(dev, 0x419e8c, 0x0);
+ nv_wr32(dev, 0x419e90, 0x0);
+ nv_wr32(dev, 0x419e94, 0x0);
+ nv_wr32(dev, 0x419e98, 0x0);
+ nv_wr32(dev, 0x419eac, 0x1fcf);
+ nv_wr32(dev, 0x419eb0, 0xd3f);
+ nv_wr32(dev, 0x419ec8, 0x1304f);
+ nv_wr32(dev, 0x419f30, 0x0);
+ nv_wr32(dev, 0x419f34, 0x0);
+ nv_wr32(dev, 0x419f38, 0x0);
+ nv_wr32(dev, 0x419f3c, 0x0);
+ nv_wr32(dev, 0x419f40, 0x0);
+ nv_wr32(dev, 0x419f44, 0x0);
+ nv_wr32(dev, 0x419f48, 0x0);
+ nv_wr32(dev, 0x419f4c, 0x0);
+ nv_wr32(dev, 0x419f58, 0x0);
+ nv_wr32(dev, 0x419f78, 0xb);
+}
+
+static void
+nve0_graph_generate_tpcunk(struct drm_device *dev)
+{
+ nv_wr32(dev, 0x41be24, 0x6);
+ nv_wr32(dev, 0x41bec0, 0x12180000);
+ nv_wr32(dev, 0x41bec4, 0x37f7f);
+ nv_wr32(dev, 0x41bee4, 0x6480430);
+ nv_wr32(dev, 0x41bf00, 0xa418820);
+ nv_wr32(dev, 0x41bf04, 0x62080e6);
+ nv_wr32(dev, 0x41bf08, 0x20398a4);
+ nv_wr32(dev, 0x41bf0c, 0xe629062);
+ nv_wr32(dev, 0x41bf10, 0xa418820);
+ nv_wr32(dev, 0x41bf14, 0xe6);
+ nv_wr32(dev, 0x41bfd0, 0x900103);
+ nv_wr32(dev, 0x41bfe0, 0x400001);
+ nv_wr32(dev, 0x41bfe4, 0x0);
+}
+
+int
+nve0_grctx_generate(struct nouveau_channel *chan)
+{
+ struct nve0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR);
+ struct nve0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR];
+ struct drm_device *dev = chan->dev;
+ u32 data[6] = {}, data2[2] = {}, tmp;
+ u32 tpc_set = 0, tpc_mask = 0;
+ u8 tpcnr[GPC_MAX], a, b;
+ u8 shift, ntpcv;
+ int i, gpc, tpc, id;
+
+ nv_mask(dev, 0x000260, 0x00000001, 0x00000000);
+ nv_wr32(dev, 0x400204, 0x00000000);
+ nv_wr32(dev, 0x400208, 0x00000000);
+
+ nve0_graph_generate_unk40xx(dev);
+ nve0_graph_generate_unk44xx(dev);
+ nve0_graph_generate_unk46xx(dev);
+ nve0_graph_generate_unk47xx(dev);
+ nve0_graph_generate_unk58xx(dev);
+ nve0_graph_generate_unk60xx(dev);
+ nve0_graph_generate_unk64xx(dev);
+ nve0_graph_generate_unk70xx(dev);
+ nve0_graph_generate_unk78xx(dev);
+ nve0_graph_generate_unk80xx(dev);
+ nve0_graph_generate_unk88xx(dev);
+ nve0_graph_generate_gpc(dev);
+ nve0_graph_generate_tpc(dev);
+ nve0_graph_generate_tpcunk(dev);
+
+ nv_wr32(dev, 0x404154, 0x0);
+
+ for (i = 0; i < grch->mmio_nr * 8; i += 8) {
+ u32 reg = nv_ro32(grch->mmio, i + 0);
+ u32 val = nv_ro32(grch->mmio, i + 4);
+ nv_wr32(dev, reg, val);
+ }
+
+ nv_wr32(dev, 0x418c6c, 0x1);
+ nv_wr32(dev, 0x41980c, 0x10);
+ nv_wr32(dev, 0x41be08, 0x4);
+ nv_wr32(dev, 0x4064c0, 0x801a00f0);
+ nv_wr32(dev, 0x405800, 0xf8000bf);
+ nv_wr32(dev, 0x419c00, 0xa);
+
+ for (tpc = 0, id = 0; tpc < 4; tpc++) {
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ if (tpc < priv->tpc_nr[gpc]) {
+ nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x0698), id);
+ nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x04e8), id);
+ nv_wr32(dev, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id);
+ nv_wr32(dev, TPC_UNIT(gpc, tpc, 0x0088), id++);
+ }
+
+ nv_wr32(dev, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]);
+ nv_wr32(dev, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]);
+ }
+ }
+
+ tmp = 0;
+ for (i = 0; i < priv->gpc_nr; i++)
+ tmp |= priv->tpc_nr[i] << (i * 4);
+ nv_wr32(dev, 0x406028, tmp);
+ nv_wr32(dev, 0x405870, tmp);
+
+ nv_wr32(dev, 0x40602c, 0x0);
+ nv_wr32(dev, 0x405874, 0x0);
+ nv_wr32(dev, 0x406030, 0x0);
+ nv_wr32(dev, 0x405878, 0x0);
+ nv_wr32(dev, 0x406034, 0x0);
+ nv_wr32(dev, 0x40587c, 0x0);
+
+ /* calculate first set of magics */
+ memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+
+ gpc = -1;
+ for (tpc = 0; tpc < priv->tpc_total; tpc++) {
+ do {
+ gpc = (gpc + 1) % priv->gpc_nr;
+ } while (!tpcnr[gpc]);
+ tpcnr[gpc]--;
+
+ data[tpc / 6] |= gpc << ((tpc % 6) * 5);
+ }
+
+ for (; tpc < 32; tpc++)
+ data[tpc / 6] |= 7 << ((tpc % 6) * 5);
+
+ /* and the second... */
+ shift = 0;
+ ntpcv = priv->tpc_total;
+ while (!(ntpcv & (1 << 4))) {
+ ntpcv <<= 1;
+ shift++;
+ }
+
+ data2[0] = ntpcv << 16;
+ data2[0] |= shift << 21;
+ data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24);
+ data2[0] |= priv->tpc_total << 8;
+ data2[0] |= priv->magic_not_rop_nr;
+ for (i = 1; i < 7; i++)
+ data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
+
+ /* and write it all the various parts of PGRAPH */
+ nv_wr32(dev, 0x418bb8, (priv->tpc_total << 8) | priv->magic_not_rop_nr);
+ for (i = 0; i < 6; i++)
+ nv_wr32(dev, 0x418b08 + (i * 4), data[i]);
+
+ nv_wr32(dev, 0x41bfd0, data2[0]);
+ nv_wr32(dev, 0x41bfe4, data2[1]);
+ for (i = 0; i < 6; i++)
+ nv_wr32(dev, 0x41bf00 + (i * 4), data[i]);
+
+ nv_wr32(dev, 0x4078bc, (priv->tpc_total << 8) | priv->magic_not_rop_nr);
+ for (i = 0; i < 6; i++)
+ nv_wr32(dev, 0x40780c + (i * 4), data[i]);
+
+
+ memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++)
+ tpc_mask |= ((1 << priv->tpc_nr[gpc]) - 1) << (gpc * 8);
+
+ for (i = 0, gpc = -1, b = -1; i < 32; i++) {
+ a = (i * (priv->tpc_total - 1)) / 32;
+ if (a != b) {
+ b = a;
+ do {
+ gpc = (gpc + 1) % priv->gpc_nr;
+ } while (!tpcnr[gpc]);
+ tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
+
+ tpc_set |= 1 << ((gpc * 8) + tpc);
+ }
+
+ nv_wr32(dev, 0x406800 + (i * 0x20), tpc_set);
+ nv_wr32(dev, 0x406c00 + (i * 0x20), tpc_set ^ tpc_mask);
+ }
+
+ for (i = 0; i < 8; i++)
+ nv_wr32(dev, 0x4064d0 + (i * 0x04), 0x00000000);
+
+ nv_wr32(dev, 0x405b00, 0x201);
+ nv_wr32(dev, 0x408850, 0x2);
+ nv_wr32(dev, 0x408958, 0x2);
+ nv_wr32(dev, 0x419f78, 0xa);
+
+ nve0_grctx_generate_icmd(dev);
+ nve0_grctx_generate_a097(dev);
+ nve0_grctx_generate_902d(dev);
+
+ nv_mask(dev, 0x000260, 0x00000001, 0x00000001);
+ nv_wr32(dev, 0x418800, 0x7026860a); //XXX
+ nv_wr32(dev, 0x41be10, 0x00bb8bc7); //XXX
+ return 0;
+}
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index 9d83729956ff..a6598fd66423 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -70,8 +70,9 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \
r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o \
evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o \
- radeon_trace_points.o ni.o cayman_blit_shaders.o atombios_encoders.o \
- radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o si_blit_shaders.o
+ evergreen_hdmi.o radeon_trace_points.o ni.o cayman_blit_shaders.o \
+ atombios_encoders.o radeon_semaphore.o radeon_sa.o atombios_i2c.o si.o \
+ si_blit_shaders.o radeon_prime.o
radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index af1054f8202a..01d77d1554f4 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -591,8 +591,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
if (encoder->crtc == crtc) {
radeon_encoder = to_radeon_encoder(encoder);
connector = radeon_get_connector_for_encoder(encoder);
- /* if (connector && connector->display_info.bpc)
- bpc = connector->display_info.bpc; */
+ bpc = radeon_get_monitor_bpc(connector);
encoder_mode = atombios_get_encoder_mode(encoder);
is_duallink = radeon_dig_monitor_is_duallink(encoder, mode->clock);
if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
@@ -968,9 +967,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
struct radeon_connector_atom_dig *dig_connector =
radeon_connector->con_priv;
int dp_clock;
-
- /* if (connector->display_info.bpc)
- bpc = connector->display_info.bpc; */
+ bpc = radeon_get_monitor_bpc(connector);
switch (encoder_mode) {
case ATOM_ENCODER_MODE_DP_MST:
diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c
index c57d85664e77..5131b3b0f7d2 100644
--- a/drivers/gpu/drm/radeon/atombios_dp.c
+++ b/drivers/gpu/drm/radeon/atombios_dp.c
@@ -405,13 +405,10 @@ static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
/* get bpc from the EDID */
static int convert_bpc_to_bpp(int bpc)
{
-#if 0
if (bpc == 0)
return 24;
else
return bpc * 3;
-#endif
- return 24;
}
/* get the max pix clock supported by the link rate and lane num */
@@ -463,7 +460,7 @@ static int radeon_dp_get_dp_lane_number(struct drm_connector *connector,
u8 dpcd[DP_DPCD_SIZE],
int pix_clock)
{
- int bpp = convert_bpc_to_bpp(connector->display_info.bpc);
+ int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector));
int max_link_rate = dp_get_max_link_rate(dpcd);
int max_lane_num = dp_get_max_lane_number(dpcd);
int lane_num;
@@ -482,7 +479,7 @@ static int radeon_dp_get_dp_link_clock(struct drm_connector *connector,
u8 dpcd[DP_DPCD_SIZE],
int pix_clock)
{
- int bpp = convert_bpc_to_bpp(connector->display_info.bpc);
+ int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector));
int lane_num, max_pix_clock;
if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) ==
@@ -533,6 +530,23 @@ u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector)
dig_connector->dp_i2c_bus->rec.i2c_id, 0);
}
+static void radeon_dp_probe_oui(struct radeon_connector *radeon_connector)
+{
+ struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
+ u8 buf[3];
+
+ if (!(dig_connector->dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT))
+ return;
+
+ if (radeon_dp_aux_native_read(radeon_connector, DP_SINK_OUI, buf, 3, 0))
+ DRM_DEBUG_KMS("Sink OUI: %02hx%02hx%02hx\n",
+ buf[0], buf[1], buf[2]);
+
+ if (radeon_dp_aux_native_read(radeon_connector, DP_BRANCH_OUI, buf, 3, 0))
+ DRM_DEBUG_KMS("Branch OUI: %02hx%02hx%02hx\n",
+ buf[0], buf[1], buf[2]);
+}
+
bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector)
{
struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
@@ -546,6 +560,9 @@ bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector)
for (i = 0; i < 8; i++)
DRM_DEBUG_KMS("%02x ", msg[i]);
DRM_DEBUG_KMS("\n");
+
+ radeon_dp_probe_oui(radeon_connector);
+
return true;
}
dig_connector->dpcd[0] = 0;
diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c
index 2d39f9977e00..e7b1ec5ae8c6 100644
--- a/drivers/gpu/drm/radeon/atombios_encoders.c
+++ b/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -545,7 +545,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo
dp_clock = dig_connector->dp_clock;
dp_lane_count = dig_connector->dp_lane_count;
hpd_id = radeon_connector->hpd.hpd;
- /* bpc = connector->display_info.bpc; */
+ bpc = radeon_get_monitor_bpc(connector);
}
/* no dig encoder assigned */
@@ -1163,7 +1163,7 @@ atombios_external_encoder_setup(struct drm_encoder *encoder,
dp_lane_count = dig_connector->dp_lane_count;
connector_object_id =
(radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
- /* bpc = connector->display_info.bpc; */
+ bpc = radeon_get_monitor_bpc(connector);
}
memset(&args, 0, sizeof(args));
@@ -1926,7 +1926,10 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
r600_hdmi_enable(encoder);
- r600_hdmi_setmode(encoder, adjusted_mode);
+ if (ASIC_IS_DCE4(rdev))
+ evergreen_hdmi_setmode(encoder, adjusted_mode);
+ else
+ r600_hdmi_setmode(encoder, adjusted_mode);
}
}
@@ -2081,6 +2084,7 @@ radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder)
static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
{
+ struct radeon_device *rdev = encoder->dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
@@ -2089,8 +2093,16 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
(radeon_encoder_get_dp_bridge_encoder_id(encoder) !=
ENCODER_OBJECT_ID_NONE)) {
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
- if (dig)
+ if (dig) {
dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder);
+ if (radeon_encoder->active_device & ATOM_DEVICE_DFP_SUPPORT) {
+ if (rdev->family >= CHIP_R600)
+ dig->afmt = rdev->mode_info.afmt[dig->dig_encoder];
+ else
+ /* RS600/690/740 have only 1 afmt block */
+ dig->afmt = rdev->mode_info.afmt[0];
+ }
+ }
}
radeon_atom_output_lock(encoder, true);
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index cfa372cb1cb3..58991af90502 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -2424,27 +2424,18 @@ bool evergreen_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *rin
u32 srbm_status;
u32 grbm_status;
u32 grbm_status_se0, grbm_status_se1;
- struct r100_gpu_lockup *lockup = &rdev->config.evergreen.lockup;
- int r;
srbm_status = RREG32(SRBM_STATUS);
grbm_status = RREG32(GRBM_STATUS);
grbm_status_se0 = RREG32(GRBM_STATUS_SE0);
grbm_status_se1 = RREG32(GRBM_STATUS_SE1);
if (!(grbm_status & GUI_ACTIVE)) {
- r100_gpu_lockup_update(lockup, ring);
+ radeon_ring_lockup_update(ring);
return false;
}
/* force CP activities */
- r = radeon_ring_lock(rdev, ring, 2);
- if (!r) {
- /* PACKET2 NOP */
- radeon_ring_write(ring, 0x80000000);
- radeon_ring_write(ring, 0x80000000);
- radeon_ring_unlock_commit(rdev, ring);
- }
- ring->rptr = RREG32(CP_RB_RPTR);
- return r100_gpu_cp_is_lockup(rdev, lockup, ring);
+ radeon_ring_force_activity(rdev, ring);
+ return radeon_ring_test_lockup(rdev, ring);
}
static int evergreen_gpu_soft_reset(struct radeon_device *rdev)
@@ -2594,6 +2585,7 @@ int evergreen_irq_set(struct radeon_device *rdev)
u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6;
u32 grbm_int_cntl = 0;
u32 grph1 = 0, grph2 = 0, grph3 = 0, grph4 = 0, grph5 = 0, grph6 = 0;
+ u32 afmt1 = 0, afmt2 = 0, afmt3 = 0, afmt4 = 0, afmt5 = 0, afmt6 = 0;
if (!rdev->irq.installed) {
WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
@@ -2614,6 +2606,13 @@ int evergreen_irq_set(struct radeon_device *rdev)
hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
+ afmt1 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
+ afmt2 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
+ afmt3 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
+ afmt4 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
+ afmt5 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
+ afmt6 = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
+
if (rdev->family >= CHIP_CAYMAN) {
/* enable CP interrupts on all rings */
if (rdev->irq.sw_int[RADEON_RING_TYPE_GFX_INDEX]) {
@@ -2690,6 +2689,30 @@ int evergreen_irq_set(struct radeon_device *rdev)
DRM_DEBUG("evergreen_irq_set: hpd 6\n");
hpd6 |= DC_HPDx_INT_EN;
}
+ if (rdev->irq.afmt[0]) {
+ DRM_DEBUG("evergreen_irq_set: hdmi 0\n");
+ afmt1 |= AFMT_AZ_FORMAT_WTRIG_MASK;
+ }
+ if (rdev->irq.afmt[1]) {
+ DRM_DEBUG("evergreen_irq_set: hdmi 1\n");
+ afmt2 |= AFMT_AZ_FORMAT_WTRIG_MASK;
+ }
+ if (rdev->irq.afmt[2]) {
+ DRM_DEBUG("evergreen_irq_set: hdmi 2\n");
+ afmt3 |= AFMT_AZ_FORMAT_WTRIG_MASK;
+ }
+ if (rdev->irq.afmt[3]) {
+ DRM_DEBUG("evergreen_irq_set: hdmi 3\n");
+ afmt4 |= AFMT_AZ_FORMAT_WTRIG_MASK;
+ }
+ if (rdev->irq.afmt[4]) {
+ DRM_DEBUG("evergreen_irq_set: hdmi 4\n");
+ afmt5 |= AFMT_AZ_FORMAT_WTRIG_MASK;
+ }
+ if (rdev->irq.afmt[5]) {
+ DRM_DEBUG("evergreen_irq_set: hdmi 5\n");
+ afmt6 |= AFMT_AZ_FORMAT_WTRIG_MASK;
+ }
if (rdev->irq.gui_idle) {
DRM_DEBUG("gui idle\n");
grbm_int_cntl |= GUI_IDLE_INT_ENABLE;
@@ -2732,6 +2755,13 @@ int evergreen_irq_set(struct radeon_device *rdev)
WREG32(DC_HPD5_INT_CONTROL, hpd5);
WREG32(DC_HPD6_INT_CONTROL, hpd6);
+ WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, afmt1);
+ WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, afmt2);
+ WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, afmt3);
+ WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, afmt4);
+ WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, afmt5);
+ WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, afmt6);
+
return 0;
}
@@ -2756,6 +2786,13 @@ static void evergreen_irq_ack(struct radeon_device *rdev)
rdev->irq.stat_regs.evergreen.d6grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET);
}
+ rdev->irq.stat_regs.evergreen.afmt_status1 = RREG32(AFMT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET);
+ rdev->irq.stat_regs.evergreen.afmt_status2 = RREG32(AFMT_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET);
+ rdev->irq.stat_regs.evergreen.afmt_status3 = RREG32(AFMT_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET);
+ rdev->irq.stat_regs.evergreen.afmt_status4 = RREG32(AFMT_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET);
+ rdev->irq.stat_regs.evergreen.afmt_status5 = RREG32(AFMT_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET);
+ rdev->irq.stat_regs.evergreen.afmt_status6 = RREG32(AFMT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET);
+
if (rdev->irq.stat_regs.evergreen.d1grph_int & GRPH_PFLIP_INT_OCCURRED)
WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR);
if (rdev->irq.stat_regs.evergreen.d2grph_int & GRPH_PFLIP_INT_OCCURRED)
@@ -2829,6 +2866,36 @@ static void evergreen_irq_ack(struct radeon_device *rdev)
tmp |= DC_HPDx_INT_ACK;
WREG32(DC_HPD6_INT_CONTROL, tmp);
}
+ if (rdev->irq.stat_regs.evergreen.afmt_status1 & AFMT_AZ_FORMAT_WTRIG) {
+ tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET);
+ tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
+ WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, tmp);
+ }
+ if (rdev->irq.stat_regs.evergreen.afmt_status2 & AFMT_AZ_FORMAT_WTRIG) {
+ tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET);
+ tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
+ WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, tmp);
+ }
+ if (rdev->irq.stat_regs.evergreen.afmt_status3 & AFMT_AZ_FORMAT_WTRIG) {
+ tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET);
+ tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
+ WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, tmp);
+ }
+ if (rdev->irq.stat_regs.evergreen.afmt_status4 & AFMT_AZ_FORMAT_WTRIG) {
+ tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET);
+ tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
+ WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, tmp);
+ }
+ if (rdev->irq.stat_regs.evergreen.afmt_status5 & AFMT_AZ_FORMAT_WTRIG) {
+ tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET);
+ tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
+ WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, tmp);
+ }
+ if (rdev->irq.stat_regs.evergreen.afmt_status6 & AFMT_AZ_FORMAT_WTRIG) {
+ tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET);
+ tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
+ WREG32(AFMT_AUDIO_PACKET_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, tmp);
+ }
}
void evergreen_irq_disable(struct radeon_device *rdev)
@@ -2878,6 +2945,7 @@ int evergreen_irq_process(struct radeon_device *rdev)
u32 ring_index;
unsigned long flags;
bool queue_hotplug = false;
+ bool queue_hdmi = false;
if (!rdev->ih.enabled || rdev->shutdown)
return IRQ_NONE;
@@ -3111,6 +3179,55 @@ restart_ih:
break;
}
break;
+ case 44: /* hdmi */
+ switch (src_data) {
+ case 0:
+ if (rdev->irq.stat_regs.evergreen.afmt_status1 & AFMT_AZ_FORMAT_WTRIG) {
+ rdev->irq.stat_regs.evergreen.afmt_status1 &= ~AFMT_AZ_FORMAT_WTRIG;
+ queue_hdmi = true;
+ DRM_DEBUG("IH: HDMI0\n");
+ }
+ break;
+ case 1:
+ if (rdev->irq.stat_regs.evergreen.afmt_status2 & AFMT_AZ_FORMAT_WTRIG) {
+ rdev->irq.stat_regs.evergreen.afmt_status2 &= ~AFMT_AZ_FORMAT_WTRIG;
+ queue_hdmi = true;
+ DRM_DEBUG("IH: HDMI1\n");
+ }
+ break;
+ case 2:
+ if (rdev->irq.stat_regs.evergreen.afmt_status3 & AFMT_AZ_FORMAT_WTRIG) {
+ rdev->irq.stat_regs.evergreen.afmt_status3 &= ~AFMT_AZ_FORMAT_WTRIG;
+ queue_hdmi = true;
+ DRM_DEBUG("IH: HDMI2\n");
+ }
+ break;
+ case 3:
+ if (rdev->irq.stat_regs.evergreen.afmt_status4 & AFMT_AZ_FORMAT_WTRIG) {
+ rdev->irq.stat_regs.evergreen.afmt_status4 &= ~AFMT_AZ_FORMAT_WTRIG;
+ queue_hdmi = true;
+ DRM_DEBUG("IH: HDMI3\n");
+ }
+ break;
+ case 4:
+ if (rdev->irq.stat_regs.evergreen.afmt_status5 & AFMT_AZ_FORMAT_WTRIG) {
+ rdev->irq.stat_regs.evergreen.afmt_status5 &= ~AFMT_AZ_FORMAT_WTRIG;
+ queue_hdmi = true;
+ DRM_DEBUG("IH: HDMI4\n");
+ }
+ break;
+ case 5:
+ if (rdev->irq.stat_regs.evergreen.afmt_status6 & AFMT_AZ_FORMAT_WTRIG) {
+ rdev->irq.stat_regs.evergreen.afmt_status6 &= ~AFMT_AZ_FORMAT_WTRIG;
+ queue_hdmi = true;
+ DRM_DEBUG("IH: HDMI5\n");
+ }
+ break;
+ default:
+ DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data);
+ break;
+ }
+ break;
case 176: /* CP_INT in ring buffer */
case 177: /* CP_INT in IB1 */
case 178: /* CP_INT in IB2 */
@@ -3154,6 +3271,8 @@ restart_ih:
goto restart_ih;
if (queue_hotplug)
schedule_work(&rdev->hotplug_work);
+ if (queue_hdmi)
+ schedule_work(&rdev->audio_work);
rdev->ih.rptr = rptr;
WREG32(IH_RB_RPTR, rdev->ih.rptr);
spin_unlock_irqrestore(&rdev->ih.lock, flags);
@@ -3248,12 +3367,9 @@ static int evergreen_startup(struct radeon_device *rdev)
if (r)
return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
- if (r) {
- DRM_ERROR("radeon: failed testing IB (%d).\n", r);
- rdev->accel_working = false;
+ r = radeon_ib_ring_tests(rdev);
+ if (r)
return r;
- }
r = r600_audio_init(rdev);
if (r) {
@@ -3319,10 +3435,6 @@ int evergreen_init(struct radeon_device *rdev)
{
int r;
- /* This don't do much */
- r = radeon_gem_init(rdev);
- if (r)
- return r;
/* Read BIOS */
if (!radeon_get_bios(rdev)) {
if (ASIC_IS_AVIVO(rdev))
@@ -3434,7 +3546,6 @@ void evergreen_fini(struct radeon_device *rdev)
evergreen_pcie_gart_fini(rdev);
r600_vram_scratch_fini(rdev);
radeon_gem_fini(rdev);
- radeon_semaphore_driver_fini(rdev);
radeon_fence_driver_fini(rdev);
radeon_agp_fini(rdev);
radeon_bo_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/evergreen_blit_kms.c b/drivers/gpu/drm/radeon/evergreen_blit_kms.c
index 222acd2d33df..1e96bd458cfd 100644
--- a/drivers/gpu/drm/radeon/evergreen_blit_kms.c
+++ b/drivers/gpu/drm/radeon/evergreen_blit_kms.c
@@ -637,7 +637,6 @@ int evergreen_blit_init(struct radeon_device *rdev)
if (rdev->r600_blit.shader_obj)
goto done;
- mutex_init(&rdev->r600_blit.mutex);
rdev->r600_blit.state_offset = 0;
if (rdev->family < CHIP_CAYMAN)
@@ -669,7 +668,7 @@ int evergreen_blit_init(struct radeon_device *rdev)
obj_size = ALIGN(obj_size, 256);
r = radeon_bo_create(rdev, obj_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
- &rdev->r600_blit.shader_obj);
+ NULL, &rdev->r600_blit.shader_obj);
if (r) {
DRM_ERROR("evergreen failed to allocate shader\n");
return r;
diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c
index 70089d32b80f..4e7dd2b4843d 100644
--- a/drivers/gpu/drm/radeon/evergreen_cs.c
+++ b/drivers/gpu/drm/radeon/evergreen_cs.c
@@ -1057,7 +1057,7 @@ static int evergreen_cs_packet_parse_vline(struct radeon_cs_parser *p)
uint32_t header, h_idx, reg, wait_reg_mem_info;
volatile uint32_t *ib;
- ib = p->ib->ptr;
+ ib = p->ib.ptr;
/* parse the WAIT_REG_MEM */
r = evergreen_cs_packet_parse(p, &wait_reg_mem, p->idx);
@@ -1215,7 +1215,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
if (!(evergreen_reg_safe_bm[i] & m))
return 0;
}
- ib = p->ib->ptr;
+ ib = p->ib.ptr;
switch (reg) {
/* force following reg to 0 in an attempt to disable out buffer
* which will need us to better understand how it works to perform
@@ -1896,7 +1896,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
u32 idx_value;
track = (struct evergreen_cs_track *)p->track;
- ib = p->ib->ptr;
+ ib = p->ib.ptr;
idx = pkt->idx + 1;
idx_value = radeon_get_ib_value(p, idx);
@@ -2610,8 +2610,8 @@ int evergreen_cs_parse(struct radeon_cs_parser *p)
}
} while (p->idx < p->chunks[p->chunk_ib_idx].length_dw);
#if 0
- for (r = 0; r < p->ib->length_dw; r++) {
- printk(KERN_INFO "%05d 0x%08X\n", r, p->ib->ptr[r]);
+ for (r = 0; r < p->ib.length_dw; r++) {
+ printk(KERN_INFO "%05d 0x%08X\n", r, p->ib.ptr[r]);
mdelay(1);
}
#endif
diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c
new file mode 100644
index 000000000000..a51f880985f8
--- /dev/null
+++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Christian König.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Christian König
+ * Rafał Miłecki
+ */
+#include "drmP.h"
+#include "radeon_drm.h"
+#include "radeon.h"
+#include "radeon_asic.h"
+#include "evergreend.h"
+#include "atom.h"
+
+/*
+ * update the N and CTS parameters for a given pixel clock rate
+ */
+static void evergreen_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock)
+{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct radeon_hdmi_acr acr = r600_hdmi_acr(clock);
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+ uint32_t offset = dig->afmt->offset;
+
+ WREG32(HDMI_ACR_32_0 + offset, HDMI_ACR_CTS_32(acr.cts_32khz));
+ WREG32(HDMI_ACR_32_1 + offset, acr.n_32khz);
+
+ WREG32(HDMI_ACR_44_0 + offset, HDMI_ACR_CTS_44(acr.cts_44_1khz));
+ WREG32(HDMI_ACR_44_1 + offset, acr.n_44_1khz);
+
+ WREG32(HDMI_ACR_48_0 + offset, HDMI_ACR_CTS_48(acr.cts_48khz));
+ WREG32(HDMI_ACR_48_1 + offset, acr.n_48khz);
+}
+
+/*
+ * calculate the crc for a given info frame
+ */
+static void evergreen_hdmi_infoframe_checksum(uint8_t packetType,
+ uint8_t versionNumber,
+ uint8_t length,
+ uint8_t *frame)
+{
+ int i;
+ frame[0] = packetType + versionNumber + length;
+ for (i = 1; i <= length; i++)
+ frame[0] += frame[i];
+ frame[0] = 0x100 - frame[0];
+}
+
+/*
+ * build a HDMI Video Info Frame
+ */
+static void evergreen_hdmi_videoinfoframe(
+ struct drm_encoder *encoder,
+ uint8_t color_format,
+ int active_information_present,
+ uint8_t active_format_aspect_ratio,
+ uint8_t scan_information,
+ uint8_t colorimetry,
+ uint8_t ex_colorimetry,
+ uint8_t quantization,
+ int ITC,
+ uint8_t picture_aspect_ratio,
+ uint8_t video_format_identification,
+ uint8_t pixel_repetition,
+ uint8_t non_uniform_picture_scaling,
+ uint8_t bar_info_data_valid,
+ uint16_t top_bar,
+ uint16_t bottom_bar,
+ uint16_t left_bar,
+ uint16_t right_bar
+)
+{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+ uint32_t offset = dig->afmt->offset;
+
+ uint8_t frame[14];
+
+ frame[0x0] = 0;
+ frame[0x1] =
+ (scan_information & 0x3) |
+ ((bar_info_data_valid & 0x3) << 2) |
+ ((active_information_present & 0x1) << 4) |
+ ((color_format & 0x3) << 5);
+ frame[0x2] =
+ (active_format_aspect_ratio & 0xF) |
+ ((picture_aspect_ratio & 0x3) << 4) |
+ ((colorimetry & 0x3) << 6);
+ frame[0x3] =
+ (non_uniform_picture_scaling & 0x3) |
+ ((quantization & 0x3) << 2) |
+ ((ex_colorimetry & 0x7) << 4) |
+ ((ITC & 0x1) << 7);
+ frame[0x4] = (video_format_identification & 0x7F);
+ frame[0x5] = (pixel_repetition & 0xF);
+ frame[0x6] = (top_bar & 0xFF);
+ frame[0x7] = (top_bar >> 8);
+ frame[0x8] = (bottom_bar & 0xFF);
+ frame[0x9] = (bottom_bar >> 8);
+ frame[0xA] = (left_bar & 0xFF);
+ frame[0xB] = (left_bar >> 8);
+ frame[0xC] = (right_bar & 0xFF);
+ frame[0xD] = (right_bar >> 8);
+
+ evergreen_hdmi_infoframe_checksum(0x82, 0x02, 0x0D, frame);
+ /* Our header values (type, version, length) should be alright, Intel
+ * is using the same. Checksum function also seems to be OK, it works
+ * fine for audio infoframe. However calculated value is always lower
+ * by 2 in comparison to fglrx. It breaks displaying anything in case
+ * of TVs that strictly check the checksum. Hack it manually here to
+ * workaround this issue. */
+ frame[0x0] += 2;
+
+ WREG32(AFMT_AVI_INFO0 + offset,
+ frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
+ WREG32(AFMT_AVI_INFO1 + offset,
+ frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x7] << 24));
+ WREG32(AFMT_AVI_INFO2 + offset,
+ frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24));
+ WREG32(AFMT_AVI_INFO3 + offset,
+ frame[0xC] | (frame[0xD] << 8));
+}
+
+/*
+ * update the info frames with the data from the current display mode
+ */
+void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode)
+{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+ uint32_t offset;
+
+ if (ASIC_IS_DCE5(rdev))
+ return;
+
+ /* Silent, r600_hdmi_enable will raise WARN for us */
+ if (!dig->afmt->enabled)
+ return;
+ offset = dig->afmt->offset;
+
+ r600_audio_set_clock(encoder, mode->clock);
+
+ WREG32(HDMI_VBI_PACKET_CONTROL + offset,
+ HDMI_NULL_SEND); /* send null packets when required */
+
+ WREG32(AFMT_AUDIO_CRC_CONTROL + offset, 0x1000);
+
+ WREG32(HDMI_AUDIO_PACKET_CONTROL + offset,
+ HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */
+ HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
+
+ WREG32(AFMT_AUDIO_PACKET_CONTROL + offset,
+ AFMT_AUDIO_SAMPLE_SEND | /* send audio packets */
+ AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */
+
+ WREG32(HDMI_ACR_PACKET_CONTROL + offset,
+ HDMI_ACR_AUTO_SEND | /* allow hw to sent ACR packets when required */
+ HDMI_ACR_SOURCE); /* select SW CTS value */
+
+ WREG32(HDMI_VBI_PACKET_CONTROL + offset,
+ HDMI_NULL_SEND | /* send null packets when required */
+ HDMI_GC_SEND | /* send general control packets */
+ HDMI_GC_CONT); /* send general control packets every frame */
+
+ WREG32(HDMI_INFOFRAME_CONTROL0 + offset,
+ HDMI_AVI_INFO_SEND | /* enable AVI info frames */
+ HDMI_AVI_INFO_CONT | /* send AVI info frames every frame/field */
+ HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
+ HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */
+
+ WREG32(AFMT_INFOFRAME_CONTROL0 + offset,
+ AFMT_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */
+
+ WREG32(HDMI_INFOFRAME_CONTROL1 + offset,
+ HDMI_AVI_INFO_LINE(2) | /* anything other than 0 */
+ HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */
+
+ WREG32(HDMI_GC + offset, 0); /* unset HDMI_GC_AVMUTE */
+
+ evergreen_hdmi_videoinfoframe(encoder, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0);
+
+ evergreen_hdmi_update_ACR(encoder, mode->clock);
+
+ /* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */
+ WREG32(AFMT_RAMP_CONTROL0 + offset, 0x00FFFFFF);
+ WREG32(AFMT_RAMP_CONTROL1 + offset, 0x007FFFFF);
+ WREG32(AFMT_RAMP_CONTROL2 + offset, 0x00000001);
+ WREG32(AFMT_RAMP_CONTROL3 + offset, 0x00000001);
+}
diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h
index 96c10b3991aa..8beac1065025 100644
--- a/drivers/gpu/drm/radeon/evergreen_reg.h
+++ b/drivers/gpu/drm/radeon/evergreen_reg.h
@@ -232,6 +232,4 @@
/* HDMI blocks at 0x7030, 0x7c30, 0x10830, 0x11430, 0x12030, 0x12c30 */
#define EVERGREEN_HDMI_BASE 0x7030
-#define EVERGREEN_HDMI_CONFIG_OFFSET 0xf0
-
#endif
diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h
index b4eefc355f16..79130bfd1d6f 100644
--- a/drivers/gpu/drm/radeon/evergreend.h
+++ b/drivers/gpu/drm/radeon/evergreend.h
@@ -112,6 +112,226 @@
#define CP_SEM_INCOMPLETE_TIMER_CNTL 0x85C8
#define CP_DEBUG 0xC1FC
+/* Audio clocks */
+#define DCCG_AUDIO_DTO_SOURCE 0x05ac
+# define DCCG_AUDIO_DTO0_SOURCE_SEL(x) ((x) << 0) /* crtc0 - crtc5 */
+# define DCCG_AUDIO_DTO_SEL (1 << 4) /* 0=dto0 1=dto1 */
+
+#define DCCG_AUDIO_DTO0_PHASE 0x05b0
+#define DCCG_AUDIO_DTO0_MODULE 0x05b4
+#define DCCG_AUDIO_DTO0_LOAD 0x05b8
+#define DCCG_AUDIO_DTO0_CNTL 0x05bc
+
+#define DCCG_AUDIO_DTO1_PHASE 0x05c0
+#define DCCG_AUDIO_DTO1_MODULE 0x05c4
+#define DCCG_AUDIO_DTO1_LOAD 0x05c8
+#define DCCG_AUDIO_DTO1_CNTL 0x05cc
+
+/* DCE 4.0 AFMT */
+#define HDMI_CONTROL 0x7030
+# define HDMI_KEEPOUT_MODE (1 << 0)
+# define HDMI_PACKET_GEN_VERSION (1 << 4) /* 0 = r6xx compat */
+# define HDMI_ERROR_ACK (1 << 8)
+# define HDMI_ERROR_MASK (1 << 9)
+# define HDMI_DEEP_COLOR_ENABLE (1 << 24)
+# define HDMI_DEEP_COLOR_DEPTH (((x) & 3) << 28)
+# define HDMI_24BIT_DEEP_COLOR 0
+# define HDMI_30BIT_DEEP_COLOR 1
+# define HDMI_36BIT_DEEP_COLOR 2
+#define HDMI_STATUS 0x7034
+# define HDMI_ACTIVE_AVMUTE (1 << 0)
+# define HDMI_AUDIO_PACKET_ERROR (1 << 16)
+# define HDMI_VBI_PACKET_ERROR (1 << 20)
+#define HDMI_AUDIO_PACKET_CONTROL 0x7038
+# define HDMI_AUDIO_DELAY_EN(x) (((x) & 3) << 4)
+# define HDMI_AUDIO_PACKETS_PER_LINE(x) (((x) & 0x1f) << 16)
+#define HDMI_ACR_PACKET_CONTROL 0x703c
+# define HDMI_ACR_SEND (1 << 0)
+# define HDMI_ACR_CONT (1 << 1)
+# define HDMI_ACR_SELECT(x) (((x) & 3) << 4)
+# define HDMI_ACR_HW 0
+# define HDMI_ACR_32 1
+# define HDMI_ACR_44 2
+# define HDMI_ACR_48 3
+# define HDMI_ACR_SOURCE (1 << 8) /* 0 - hw; 1 - cts value */
+# define HDMI_ACR_AUTO_SEND (1 << 12)
+# define HDMI_ACR_N_MULTIPLE(x) (((x) & 7) << 16)
+# define HDMI_ACR_X1 1
+# define HDMI_ACR_X2 2
+# define HDMI_ACR_X4 4
+# define HDMI_ACR_AUDIO_PRIORITY (1 << 31)
+#define HDMI_VBI_PACKET_CONTROL 0x7040
+# define HDMI_NULL_SEND (1 << 0)
+# define HDMI_GC_SEND (1 << 4)
+# define HDMI_GC_CONT (1 << 5) /* 0 - once; 1 - every frame */
+#define HDMI_INFOFRAME_CONTROL0 0x7044
+# define HDMI_AVI_INFO_SEND (1 << 0)
+# define HDMI_AVI_INFO_CONT (1 << 1)
+# define HDMI_AUDIO_INFO_SEND (1 << 4)
+# define HDMI_AUDIO_INFO_CONT (1 << 5)
+# define HDMI_MPEG_INFO_SEND (1 << 8)
+# define HDMI_MPEG_INFO_CONT (1 << 9)
+#define HDMI_INFOFRAME_CONTROL1 0x7048
+# define HDMI_AVI_INFO_LINE(x) (((x) & 0x3f) << 0)
+# define HDMI_AUDIO_INFO_LINE(x) (((x) & 0x3f) << 8)
+# define HDMI_MPEG_INFO_LINE(x) (((x) & 0x3f) << 16)
+#define HDMI_GENERIC_PACKET_CONTROL 0x704c
+# define HDMI_GENERIC0_SEND (1 << 0)
+# define HDMI_GENERIC0_CONT (1 << 1)
+# define HDMI_GENERIC1_SEND (1 << 4)
+# define HDMI_GENERIC1_CONT (1 << 5)
+# define HDMI_GENERIC0_LINE(x) (((x) & 0x3f) << 16)
+# define HDMI_GENERIC1_LINE(x) (((x) & 0x3f) << 24)
+#define HDMI_GC 0x7058
+# define HDMI_GC_AVMUTE (1 << 0)
+# define HDMI_GC_AVMUTE_CONT (1 << 2)
+#define AFMT_AUDIO_PACKET_CONTROL2 0x705c
+# define AFMT_AUDIO_LAYOUT_OVRD (1 << 0)
+# define AFMT_AUDIO_LAYOUT_SELECT (1 << 1)
+# define AFMT_60958_CS_SOURCE (1 << 4)
+# define AFMT_AUDIO_CHANNEL_ENABLE(x) (((x) & 0xff) << 8)
+# define AFMT_DP_AUDIO_STREAM_ID(x) (((x) & 0xff) << 16)
+#define AFMT_AVI_INFO0 0x7084
+# define AFMT_AVI_INFO_CHECKSUM(x) (((x) & 0xff) << 0)
+# define AFMT_AVI_INFO_S(x) (((x) & 3) << 8)
+# define AFMT_AVI_INFO_B(x) (((x) & 3) << 10)
+# define AFMT_AVI_INFO_A(x) (((x) & 1) << 12)
+# define AFMT_AVI_INFO_Y(x) (((x) & 3) << 13)
+# define AFMT_AVI_INFO_Y_RGB 0
+# define AFMT_AVI_INFO_Y_YCBCR422 1
+# define AFMT_AVI_INFO_Y_YCBCR444 2
+# define AFMT_AVI_INFO_Y_A_B_S(x) (((x) & 0xff) << 8)
+# define AFMT_AVI_INFO_R(x) (((x) & 0xf) << 16)
+# define AFMT_AVI_INFO_M(x) (((x) & 0x3) << 20)
+# define AFMT_AVI_INFO_C(x) (((x) & 0x3) << 22)
+# define AFMT_AVI_INFO_C_M_R(x) (((x) & 0xff) << 16)
+# define AFMT_AVI_INFO_SC(x) (((x) & 0x3) << 24)
+# define AFMT_AVI_INFO_Q(x) (((x) & 0x3) << 26)
+# define AFMT_AVI_INFO_EC(x) (((x) & 0x3) << 28)
+# define AFMT_AVI_INFO_ITC(x) (((x) & 0x1) << 31)
+# define AFMT_AVI_INFO_ITC_EC_Q_SC(x) (((x) & 0xff) << 24)
+#define AFMT_AVI_INFO1 0x7088
+# define AFMT_AVI_INFO_VIC(x) (((x) & 0x7f) << 0) /* don't use avi infoframe v1 */
+# define AFMT_AVI_INFO_PR(x) (((x) & 0xf) << 8) /* don't use avi infoframe v1 */
+# define AFMT_AVI_INFO_CN(x) (((x) & 0x3) << 12)
+# define AFMT_AVI_INFO_YQ(x) (((x) & 0x3) << 14)
+# define AFMT_AVI_INFO_TOP(x) (((x) & 0xffff) << 16)
+#define AFMT_AVI_INFO2 0x708c
+# define AFMT_AVI_INFO_BOTTOM(x) (((x) & 0xffff) << 0)
+# define AFMT_AVI_INFO_LEFT(x) (((x) & 0xffff) << 16)
+#define AFMT_AVI_INFO3 0x7090
+# define AFMT_AVI_INFO_RIGHT(x) (((x) & 0xffff) << 0)
+# define AFMT_AVI_INFO_VERSION(x) (((x) & 3) << 24)
+#define AFMT_MPEG_INFO0 0x7094
+# define AFMT_MPEG_INFO_CHECKSUM(x) (((x) & 0xff) << 0)
+# define AFMT_MPEG_INFO_MB0(x) (((x) & 0xff) << 8)
+# define AFMT_MPEG_INFO_MB1(x) (((x) & 0xff) << 16)
+# define AFMT_MPEG_INFO_MB2(x) (((x) & 0xff) << 24)
+#define AFMT_MPEG_INFO1 0x7098
+# define AFMT_MPEG_INFO_MB3(x) (((x) & 0xff) << 0)
+# define AFMT_MPEG_INFO_MF(x) (((x) & 3) << 8)
+# define AFMT_MPEG_INFO_FR(x) (((x) & 1) << 12)
+#define AFMT_GENERIC0_HDR 0x709c
+#define AFMT_GENERIC0_0 0x70a0
+#define AFMT_GENERIC0_1 0x70a4
+#define AFMT_GENERIC0_2 0x70a8
+#define AFMT_GENERIC0_3 0x70ac
+#define AFMT_GENERIC0_4 0x70b0
+#define AFMT_GENERIC0_5 0x70b4
+#define AFMT_GENERIC0_6 0x70b8
+#define AFMT_GENERIC1_HDR 0x70bc
+#define AFMT_GENERIC1_0 0x70c0
+#define AFMT_GENERIC1_1 0x70c4
+#define AFMT_GENERIC1_2 0x70c8
+#define AFMT_GENERIC1_3 0x70cc
+#define AFMT_GENERIC1_4 0x70d0
+#define AFMT_GENERIC1_5 0x70d4
+#define AFMT_GENERIC1_6 0x70d8
+#define HDMI_ACR_32_0 0x70dc
+# define HDMI_ACR_CTS_32(x) (((x) & 0xfffff) << 12)
+#define HDMI_ACR_32_1 0x70e0
+# define HDMI_ACR_N_32(x) (((x) & 0xfffff) << 0)
+#define HDMI_ACR_44_0 0x70e4
+# define HDMI_ACR_CTS_44(x) (((x) & 0xfffff) << 12)
+#define HDMI_ACR_44_1 0x70e8
+# define HDMI_ACR_N_44(x) (((x) & 0xfffff) << 0)
+#define HDMI_ACR_48_0 0x70ec
+# define HDMI_ACR_CTS_48(x) (((x) & 0xfffff) << 12)
+#define HDMI_ACR_48_1 0x70f0
+# define HDMI_ACR_N_48(x) (((x) & 0xfffff) << 0)
+#define HDMI_ACR_STATUS_0 0x70f4
+#define HDMI_ACR_STATUS_1 0x70f8
+#define AFMT_AUDIO_INFO0 0x70fc
+# define AFMT_AUDIO_INFO_CHECKSUM(x) (((x) & 0xff) << 0)
+# define AFMT_AUDIO_INFO_CC(x) (((x) & 7) << 8)
+# define AFMT_AUDIO_INFO_CT(x) (((x) & 0xf) << 11)
+# define AFMT_AUDIO_INFO_CHECKSUM_OFFSET(x) (((x) & 0xff) << 16)
+# define AFMT_AUDIO_INFO_CXT(x) (((x) & 0x1f) << 24)
+#define AFMT_AUDIO_INFO1 0x7100
+# define AFMT_AUDIO_INFO_CA(x) (((x) & 0xff) << 0)
+# define AFMT_AUDIO_INFO_LSV(x) (((x) & 0xf) << 11)
+# define AFMT_AUDIO_INFO_DM_INH(x) (((x) & 1) << 15)
+# define AFMT_AUDIO_INFO_DM_INH_LSV(x) (((x) & 0xff) << 8)
+# define AFMT_AUDIO_INFO_LFEBPL(x) (((x) & 3) << 16)
+#define AFMT_60958_0 0x7104
+# define AFMT_60958_CS_A(x) (((x) & 1) << 0)
+# define AFMT_60958_CS_B(x) (((x) & 1) << 1)
+# define AFMT_60958_CS_C(x) (((x) & 1) << 2)
+# define AFMT_60958_CS_D(x) (((x) & 3) << 3)
+# define AFMT_60958_CS_MODE(x) (((x) & 3) << 6)
+# define AFMT_60958_CS_CATEGORY_CODE(x) (((x) & 0xff) << 8)
+# define AFMT_60958_CS_SOURCE_NUMBER(x) (((x) & 0xf) << 16)
+# define AFMT_60958_CS_CHANNEL_NUMBER_L(x) (((x) & 0xf) << 20)
+# define AFMT_60958_CS_SAMPLING_FREQUENCY(x) (((x) & 0xf) << 24)
+# define AFMT_60958_CS_CLOCK_ACCURACY(x) (((x) & 3) << 28)
+#define AFMT_60958_1 0x7108
+# define AFMT_60958_CS_WORD_LENGTH(x) (((x) & 0xf) << 0)
+# define AFMT_60958_CS_ORIGINAL_SAMPLING_FREQUENCY(x) (((x) & 0xf) << 4)
+# define AFMT_60958_CS_VALID_L(x) (((x) & 1) << 16)
+# define AFMT_60958_CS_VALID_R(x) (((x) & 1) << 18)
+# define AFMT_60958_CS_CHANNEL_NUMBER_R(x) (((x) & 0xf) << 20)
+#define AFMT_AUDIO_CRC_CONTROL 0x710c
+# define AFMT_AUDIO_CRC_EN (1 << 0)
+#define AFMT_RAMP_CONTROL0 0x7110
+# define AFMT_RAMP_MAX_COUNT(x) (((x) & 0xffffff) << 0)
+# define AFMT_RAMP_DATA_SIGN (1 << 31)
+#define AFMT_RAMP_CONTROL1 0x7114
+# define AFMT_RAMP_MIN_COUNT(x) (((x) & 0xffffff) << 0)
+# define AFMT_AUDIO_TEST_CH_DISABLE(x) (((x) & 0xff) << 24)
+#define AFMT_RAMP_CONTROL2 0x7118
+# define AFMT_RAMP_INC_COUNT(x) (((x) & 0xffffff) << 0)
+#define AFMT_RAMP_CONTROL3 0x711c
+# define AFMT_RAMP_DEC_COUNT(x) (((x) & 0xffffff) << 0)
+#define AFMT_60958_2 0x7120
+# define AFMT_60958_CS_CHANNEL_NUMBER_2(x) (((x) & 0xf) << 0)
+# define AFMT_60958_CS_CHANNEL_NUMBER_3(x) (((x) & 0xf) << 4)
+# define AFMT_60958_CS_CHANNEL_NUMBER_4(x) (((x) & 0xf) << 8)
+# define AFMT_60958_CS_CHANNEL_NUMBER_5(x) (((x) & 0xf) << 12)
+# define AFMT_60958_CS_CHANNEL_NUMBER_6(x) (((x) & 0xf) << 16)
+# define AFMT_60958_CS_CHANNEL_NUMBER_7(x) (((x) & 0xf) << 20)
+#define AFMT_STATUS 0x7128
+# define AFMT_AUDIO_ENABLE (1 << 4)
+# define AFMT_AUDIO_HBR_ENABLE (1 << 8)
+# define AFMT_AZ_FORMAT_WTRIG (1 << 28)
+# define AFMT_AZ_FORMAT_WTRIG_INT (1 << 29)
+# define AFMT_AZ_AUDIO_ENABLE_CHG (1 << 30)
+#define AFMT_AUDIO_PACKET_CONTROL 0x712c
+# define AFMT_AUDIO_SAMPLE_SEND (1 << 0)
+# define AFMT_RESET_FIFO_WHEN_AUDIO_DIS (1 << 11) /* set to 1 */
+# define AFMT_AUDIO_TEST_EN (1 << 12)
+# define AFMT_AUDIO_CHANNEL_SWAP (1 << 24)
+# define AFMT_60958_CS_UPDATE (1 << 26)
+# define AFMT_AZ_AUDIO_ENABLE_CHG_MASK (1 << 27)
+# define AFMT_AZ_FORMAT_WTRIG_MASK (1 << 28)
+# define AFMT_AZ_FORMAT_WTRIG_ACK (1 << 29)
+# define AFMT_AZ_AUDIO_ENABLE_CHG_ACK (1 << 30)
+#define AFMT_VBI_PACKET_CONTROL 0x7130
+# define AFMT_GENERIC0_UPDATE (1 << 2)
+#define AFMT_INFOFRAME_CONTROL0 0x7134
+# define AFMT_AUDIO_INFO_SOURCE (1 << 6) /* 0 - sound block; 1 - afmt regs */
+# define AFMT_AUDIO_INFO_UPDATE (1 << 7)
+# define AFMT_MPEG_INFO_UPDATE (1 << 10)
+#define AFMT_GENERIC0_7 0x7138
#define GC_USER_SHADER_PIPE_CONFIG 0x8954
#define INACTIVE_QD_PIPES(x) ((x) << 8)
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index a48ca53fcd6a..b01c2dd627b0 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -1392,35 +1392,6 @@ int cayman_cp_resume(struct radeon_device *rdev)
return 0;
}
-bool cayman_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
-{
- u32 srbm_status;
- u32 grbm_status;
- u32 grbm_status_se0, grbm_status_se1;
- struct r100_gpu_lockup *lockup = &rdev->config.cayman.lockup;
- int r;
-
- srbm_status = RREG32(SRBM_STATUS);
- grbm_status = RREG32(GRBM_STATUS);
- grbm_status_se0 = RREG32(GRBM_STATUS_SE0);
- grbm_status_se1 = RREG32(GRBM_STATUS_SE1);
- if (!(grbm_status & GUI_ACTIVE)) {
- r100_gpu_lockup_update(lockup, ring);
- return false;
- }
- /* force CP activities */
- r = radeon_ring_lock(rdev, ring, 2);
- if (!r) {
- /* PACKET2 NOP */
- radeon_ring_write(ring, 0x80000000);
- radeon_ring_write(ring, 0x80000000);
- radeon_ring_unlock_commit(rdev, ring);
- }
- /* XXX deal with CP0,1,2 */
- ring->rptr = RREG32(ring->rptr_reg);
- return r100_gpu_cp_is_lockup(rdev, lockup, ring);
-}
-
static int cayman_gpu_soft_reset(struct radeon_device *rdev)
{
struct evergreen_mc_save save;
@@ -1601,12 +1572,9 @@ static int cayman_startup(struct radeon_device *rdev)
if (r)
return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
- if (r) {
- DRM_ERROR("radeon: failed testing IB (%d).\n", r);
- rdev->accel_working = false;
+ r = radeon_ib_ring_tests(rdev);
+ if (r)
return r;
- }
r = radeon_vm_manager_start(rdev);
if (r)
@@ -1661,10 +1629,6 @@ int cayman_init(struct radeon_device *rdev)
struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
int r;
- /* This don't do much */
- r = radeon_gem_init(rdev);
- if (r)
- return r;
/* Read BIOS */
if (!radeon_get_bios(rdev)) {
if (ASIC_IS_AVIVO(rdev))
@@ -1776,7 +1740,6 @@ void cayman_fini(struct radeon_device *rdev)
cayman_pcie_gart_fini(rdev);
r600_vram_scratch_fini(rdev);
radeon_gem_fini(rdev);
- radeon_semaphore_driver_fini(rdev);
radeon_fence_driver_fini(rdev);
radeon_bo_fini(rdev);
radeon_atombios_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index fe33d35dae8c..fb44e7e49083 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -139,9 +139,9 @@ int r100_reloc_pitch_offset(struct radeon_cs_parser *p,
}
tmp |= tile_flags;
- p->ib->ptr[idx] = (value & 0x3fc00000) | tmp;
+ p->ib.ptr[idx] = (value & 0x3fc00000) | tmp;
} else
- p->ib->ptr[idx] = (value & 0xffc00000) | tmp;
+ p->ib.ptr[idx] = (value & 0xffc00000) | tmp;
return 0;
}
@@ -156,7 +156,7 @@ int r100_packet3_load_vbpntr(struct radeon_cs_parser *p,
volatile uint32_t *ib;
u32 idx_value;
- ib = p->ib->ptr;
+ ib = p->ib.ptr;
track = (struct r100_cs_track *)p->track;
c = radeon_get_ib_value(p, idx++) & 0x1F;
if (c > 16) {
@@ -660,7 +660,7 @@ int r100_pci_gart_enable(struct radeon_device *rdev)
tmp = RREG32(RADEON_AIC_CNTL) | RADEON_PCIGART_TRANSLATE_EN;
WREG32(RADEON_AIC_CNTL, tmp);
r100_pci_gart_tlb_flush(rdev);
- DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n",
+ DRM_INFO("PCI GART of %uM enabled (table at 0x%016llX).\n",
(unsigned)(rdev->mc.gtt_size >> 20),
(unsigned long long)rdev->gart.table_addr);
rdev->gart.ready = true;
@@ -1180,6 +1180,10 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size)
WREG32(RADEON_CP_RB_WPTR_DELAY, 0);
WREG32(RADEON_CP_CSQ_MODE, 0x00004D4D);
WREG32(RADEON_CP_CSQ_CNTL, RADEON_CSQ_PRIBM_INDBM);
+
+ /* at this point everything should be setup correctly to enable master */
+ pci_set_master(rdev->pdev);
+
radeon_ring_start(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
r = radeon_ring_test(rdev, RADEON_RING_TYPE_GFX_INDEX, ring);
if (r) {
@@ -1271,7 +1275,7 @@ void r100_cs_dump_packet(struct radeon_cs_parser *p,
unsigned i;
unsigned idx;
- ib = p->ib->ptr;
+ ib = p->ib.ptr;
idx = pkt->idx;
for (i = 0; i <= (pkt->count + 1); i++, idx++) {
DRM_INFO("ib[%d]=0x%08X\n", idx, ib[idx]);
@@ -1350,7 +1354,7 @@ int r100_cs_packet_parse_vline(struct radeon_cs_parser *p)
uint32_t header, h_idx, reg;
volatile uint32_t *ib;
- ib = p->ib->ptr;
+ ib = p->ib.ptr;
/* parse the wait until */
r = r100_cs_packet_parse(p, &waitreloc, p->idx);
@@ -1529,7 +1533,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
u32 tile_flags = 0;
u32 idx_value;
- ib = p->ib->ptr;
+ ib = p->ib.ptr;
track = (struct r100_cs_track *)p->track;
idx_value = radeon_get_ib_value(p, idx);
@@ -1885,7 +1889,7 @@ static int r100_packet3_check(struct radeon_cs_parser *p,
volatile uint32_t *ib;
int r;
- ib = p->ib->ptr;
+ ib = p->ib.ptr;
idx = pkt->idx + 1;
track = (struct r100_cs_track *)p->track;
switch (pkt->opcode) {
@@ -2004,6 +2008,8 @@ int r100_cs_parse(struct radeon_cs_parser *p)
int r;
track = kzalloc(sizeof(*track), GFP_KERNEL);
+ if (!track)
+ return -ENOMEM;
r100_cs_track_clear(p->rdev, track);
p->track = track;
do {
@@ -2155,79 +2161,18 @@ int r100_mc_wait_for_idle(struct radeon_device *rdev)
return -1;
}
-void r100_gpu_lockup_update(struct r100_gpu_lockup *lockup, struct radeon_ring *ring)
-{
- lockup->last_cp_rptr = ring->rptr;
- lockup->last_jiffies = jiffies;
-}
-
-/**
- * r100_gpu_cp_is_lockup() - check if CP is lockup by recording information
- * @rdev: radeon device structure
- * @lockup: r100_gpu_lockup structure holding CP lockup tracking informations
- * @cp: radeon_cp structure holding CP information
- *
- * We don't need to initialize the lockup tracking information as we will either
- * have CP rptr to a different value of jiffies wrap around which will force
- * initialization of the lockup tracking informations.
- *
- * A possible false positivie is if we get call after while and last_cp_rptr ==
- * the current CP rptr, even if it's unlikely it might happen. To avoid this
- * if the elapsed time since last call is bigger than 2 second than we return
- * false and update the tracking information. Due to this the caller must call
- * r100_gpu_cp_is_lockup several time in less than 2sec for lockup to be reported
- * the fencing code should be cautious about that.
- *
- * Caller should write to the ring to force CP to do something so we don't get
- * false positive when CP is just gived nothing to do.
- *
- **/
-bool r100_gpu_cp_is_lockup(struct radeon_device *rdev, struct r100_gpu_lockup *lockup, struct radeon_ring *ring)
-{
- unsigned long cjiffies, elapsed;
-
- cjiffies = jiffies;
- if (!time_after(cjiffies, lockup->last_jiffies)) {
- /* likely a wrap around */
- lockup->last_cp_rptr = ring->rptr;
- lockup->last_jiffies = jiffies;
- return false;
- }
- if (ring->rptr != lockup->last_cp_rptr) {
- /* CP is still working no lockup */
- lockup->last_cp_rptr = ring->rptr;
- lockup->last_jiffies = jiffies;
- return false;
- }
- elapsed = jiffies_to_msecs(cjiffies - lockup->last_jiffies);
- if (elapsed >= 10000) {
- dev_err(rdev->dev, "GPU lockup CP stall for more than %lumsec\n", elapsed);
- return true;
- }
- /* give a chance to the GPU ... */
- return false;
-}
-
bool r100_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
{
u32 rbbm_status;
- int r;
rbbm_status = RREG32(R_000E40_RBBM_STATUS);
if (!G_000E40_GUI_ACTIVE(rbbm_status)) {
- r100_gpu_lockup_update(&rdev->config.r100.lockup, ring);
+ radeon_ring_lockup_update(ring);
return false;
}
/* force CP activities */
- r = radeon_ring_lock(rdev, ring, 2);
- if (!r) {
- /* PACKET2 NOP */
- radeon_ring_write(ring, 0x80000000);
- radeon_ring_write(ring, 0x80000000);
- radeon_ring_unlock_commit(rdev, ring);
- }
- ring->rptr = RREG32(ring->rptr_reg);
- return r100_gpu_cp_is_lockup(rdev, &rdev->config.r100.lockup, ring);
+ radeon_ring_force_activity(rdev, ring);
+ return radeon_ring_test_lockup(rdev, ring);
}
void r100_bm_disable(struct radeon_device *rdev)
@@ -2296,7 +2241,6 @@ int r100_asic_reset(struct radeon_device *rdev)
if (G_000E40_SE_BUSY(status) || G_000E40_RE_BUSY(status) ||
G_000E40_TAM_BUSY(status) || G_000E40_PB_BUSY(status)) {
dev_err(rdev->dev, "failed to reset GPU\n");
- rdev->gpu_lockup = true;
ret = -1;
} else
dev_info(rdev->dev, "GPU reset succeed\n");
@@ -3742,7 +3686,7 @@ void r100_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
int r100_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
{
- struct radeon_ib *ib;
+ struct radeon_ib ib;
uint32_t scratch;
uint32_t tmp = 0;
unsigned i;
@@ -3758,22 +3702,22 @@ int r100_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
if (r) {
return r;
}
- ib->ptr[0] = PACKET0(scratch, 0);
- ib->ptr[1] = 0xDEADBEEF;
- ib->ptr[2] = PACKET2(0);
- ib->ptr[3] = PACKET2(0);
- ib->ptr[4] = PACKET2(0);
- ib->ptr[5] = PACKET2(0);
- ib->ptr[6] = PACKET2(0);
- ib->ptr[7] = PACKET2(0);
- ib->length_dw = 8;
- r = radeon_ib_schedule(rdev, ib);
+ ib.ptr[0] = PACKET0(scratch, 0);
+ ib.ptr[1] = 0xDEADBEEF;
+ ib.ptr[2] = PACKET2(0);
+ ib.ptr[3] = PACKET2(0);
+ ib.ptr[4] = PACKET2(0);
+ ib.ptr[5] = PACKET2(0);
+ ib.ptr[6] = PACKET2(0);
+ ib.ptr[7] = PACKET2(0);
+ ib.length_dw = 8;
+ r = radeon_ib_schedule(rdev, &ib);
if (r) {
radeon_scratch_free(rdev, scratch);
radeon_ib_free(rdev, &ib);
return r;
}
- r = radeon_fence_wait(ib->fence, false);
+ r = radeon_fence_wait(ib.fence, false);
if (r) {
return r;
}
@@ -3965,12 +3909,9 @@ static int r100_startup(struct radeon_device *rdev)
if (r)
return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
- if (r) {
- dev_err(rdev->dev, "failed testing IB (%d).\n", r);
- rdev->accel_working = false;
+ r = radeon_ib_ring_tests(rdev);
+ if (r)
return r;
- }
return 0;
}
diff --git a/drivers/gpu/drm/radeon/r200.c b/drivers/gpu/drm/radeon/r200.c
index a59cc474d537..a26144d01207 100644
--- a/drivers/gpu/drm/radeon/r200.c
+++ b/drivers/gpu/drm/radeon/r200.c
@@ -154,7 +154,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
u32 tile_flags = 0;
u32 idx_value;
- ib = p->ib->ptr;
+ ib = p->ib.ptr;
track = (struct r100_cs_track *)p->track;
idx_value = radeon_get_ib_value(p, idx);
switch (reg) {
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index fa14383f9ca0..97722a33e513 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -377,28 +377,6 @@ void r300_gpu_init(struct radeon_device *rdev)
rdev->num_gb_pipes, rdev->num_z_pipes);
}
-bool r300_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
-{
- u32 rbbm_status;
- int r;
-
- rbbm_status = RREG32(R_000E40_RBBM_STATUS);
- if (!G_000E40_GUI_ACTIVE(rbbm_status)) {
- r100_gpu_lockup_update(&rdev->config.r300.lockup, ring);
- return false;
- }
- /* force CP activities */
- r = radeon_ring_lock(rdev, ring, 2);
- if (!r) {
- /* PACKET2 NOP */
- radeon_ring_write(ring, 0x80000000);
- radeon_ring_write(ring, 0x80000000);
- radeon_ring_unlock_commit(rdev, ring);
- }
- ring->rptr = RREG32(RADEON_CP_RB_RPTR);
- return r100_gpu_cp_is_lockup(rdev, &rdev->config.r300.lockup, ring);
-}
-
int r300_asic_reset(struct radeon_device *rdev)
{
struct r100_mc_save save;
@@ -449,7 +427,6 @@ int r300_asic_reset(struct radeon_device *rdev)
/* Check if GPU is idle */
if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) {
dev_err(rdev->dev, "failed to reset GPU\n");
- rdev->gpu_lockup = true;
ret = -1;
} else
dev_info(rdev->dev, "GPU reset succeed\n");
@@ -627,7 +604,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
int r;
u32 idx_value;
- ib = p->ib->ptr;
+ ib = p->ib.ptr;
track = (struct r100_cs_track *)p->track;
idx_value = radeon_get_ib_value(p, idx);
@@ -1169,7 +1146,7 @@ static int r300_packet3_check(struct radeon_cs_parser *p,
unsigned idx;
int r;
- ib = p->ib->ptr;
+ ib = p->ib.ptr;
idx = pkt->idx + 1;
track = (struct r100_cs_track *)p->track;
switch(pkt->opcode) {
@@ -1418,12 +1395,9 @@ static int r300_startup(struct radeon_device *rdev)
if (r)
return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
- if (r) {
- dev_err(rdev->dev, "failed testing IB (%d).\n", r);
- rdev->accel_working = false;
+ r = radeon_ib_ring_tests(rdev);
+ if (r)
return r;
- }
return 0;
}
diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c
index f3fcaacfea01..99137be7a300 100644
--- a/drivers/gpu/drm/radeon/r420.c
+++ b/drivers/gpu/drm/radeon/r420.c
@@ -279,12 +279,9 @@ static int r420_startup(struct radeon_device *rdev)
if (r)
return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
- if (r) {
- dev_err(rdev->dev, "failed testing IB (%d).\n", r);
- rdev->accel_working = false;
+ r = radeon_ib_ring_tests(rdev);
+ if (r)
return r;
- }
return 0;
}
diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c
index ebcc15b03c9f..b5cf8375cd25 100644
--- a/drivers/gpu/drm/radeon/r520.c
+++ b/drivers/gpu/drm/radeon/r520.c
@@ -207,12 +207,10 @@ static int r520_startup(struct radeon_device *rdev)
if (r)
return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
- if (r) {
- dev_err(rdev->dev, "failed testing IB (%d).\n", r);
- rdev->accel_working = false;
+ r = radeon_ib_ring_tests(rdev);
+ if (r)
return r;
- }
+
return 0;
}
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index c8187c4b6ae8..f388a1d73b63 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -713,6 +713,14 @@ void r600_hpd_init(struct radeon_device *rdev)
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+ if (connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
+ connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
+ /* don't try to enable hpd on eDP or LVDS avoid breaking the
+ * aux dp channel on imac and help (but not completely fix)
+ * https://bugzilla.redhat.com/show_bug.cgi?id=726143
+ */
+ continue;
+ }
if (ASIC_IS_DCE3(rdev)) {
u32 tmp = DC_HPDx_CONNECTION_TIMER(0x9c4) | DC_HPDx_RX_INT_TIMER(0xfa);
if (ASIC_IS_DCE32(rdev))
@@ -1223,7 +1231,7 @@ int r600_vram_scratch_init(struct radeon_device *rdev)
if (rdev->vram_scratch.robj == NULL) {
r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE,
PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
- &rdev->vram_scratch.robj);
+ NULL, &rdev->vram_scratch.robj);
if (r) {
return r;
}
@@ -1350,31 +1358,17 @@ bool r600_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
u32 srbm_status;
u32 grbm_status;
u32 grbm_status2;
- struct r100_gpu_lockup *lockup;
- int r;
-
- if (rdev->family >= CHIP_RV770)
- lockup = &rdev->config.rv770.lockup;
- else
- lockup = &rdev->config.r600.lockup;
srbm_status = RREG32(R_000E50_SRBM_STATUS);
grbm_status = RREG32(R_008010_GRBM_STATUS);
grbm_status2 = RREG32(R_008014_GRBM_STATUS2);
if (!G_008010_GUI_ACTIVE(grbm_status)) {
- r100_gpu_lockup_update(lockup, ring);
+ radeon_ring_lockup_update(ring);
return false;
}
/* force CP activities */
- r = radeon_ring_lock(rdev, ring, 2);
- if (!r) {
- /* PACKET2 NOP */
- radeon_ring_write(ring, 0x80000000);
- radeon_ring_write(ring, 0x80000000);
- radeon_ring_unlock_commit(rdev, ring);
- }
- ring->rptr = RREG32(ring->rptr_reg);
- return r100_gpu_cp_is_lockup(rdev, lockup, ring);
+ radeon_ring_force_activity(rdev, ring);
+ return radeon_ring_test_lockup(rdev, ring);
}
int r600_asic_reset(struct radeon_device *rdev)
@@ -2377,20 +2371,15 @@ int r600_copy_blit(struct radeon_device *rdev,
unsigned num_gpu_pages,
struct radeon_fence *fence)
{
+ struct radeon_sa_bo *vb = NULL;
int r;
- mutex_lock(&rdev->r600_blit.mutex);
- rdev->r600_blit.vb_ib = NULL;
- r = r600_blit_prepare_copy(rdev, num_gpu_pages);
+ r = r600_blit_prepare_copy(rdev, num_gpu_pages, &vb);
if (r) {
- if (rdev->r600_blit.vb_ib)
- radeon_ib_free(rdev, &rdev->r600_blit.vb_ib);
- mutex_unlock(&rdev->r600_blit.mutex);
return r;
}
- r600_kms_blit_copy(rdev, src_offset, dst_offset, num_gpu_pages);
- r600_blit_done_copy(rdev, fence);
- mutex_unlock(&rdev->r600_blit.mutex);
+ r600_kms_blit_copy(rdev, src_offset, dst_offset, num_gpu_pages, vb);
+ r600_blit_done_copy(rdev, fence, vb);
return 0;
}
@@ -2494,12 +2483,9 @@ int r600_startup(struct radeon_device *rdev)
if (r)
return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
- if (r) {
- DRM_ERROR("radeon: failed testing IB (%d).\n", r);
- rdev->accel_working = false;
+ r = radeon_ib_ring_tests(rdev);
+ if (r)
return r;
- }
return 0;
}
@@ -2574,10 +2560,6 @@ int r600_init(struct radeon_device *rdev)
if (r600_debugfs_mc_info_init(rdev)) {
DRM_ERROR("Failed to register debugfs file for mc !\n");
}
- /* This don't do much */
- r = radeon_gem_init(rdev);
- if (r)
- return r;
/* Read BIOS */
if (!radeon_get_bios(rdev)) {
if (ASIC_IS_AVIVO(rdev))
@@ -2675,7 +2657,6 @@ void r600_fini(struct radeon_device *rdev)
r600_vram_scratch_fini(rdev);
radeon_agp_fini(rdev);
radeon_gem_fini(rdev);
- radeon_semaphore_driver_fini(rdev);
radeon_fence_driver_fini(rdev);
radeon_bo_fini(rdev);
radeon_atombios_fini(rdev);
@@ -2704,7 +2685,7 @@ void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
int r600_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
{
- struct radeon_ib *ib;
+ struct radeon_ib ib;
uint32_t scratch;
uint32_t tmp = 0;
unsigned i;
@@ -2722,18 +2703,18 @@ int r600_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
DRM_ERROR("radeon: failed to get ib (%d).\n", r);
return r;
}
- ib->ptr[0] = PACKET3(PACKET3_SET_CONFIG_REG, 1);
- ib->ptr[1] = ((scratch - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
- ib->ptr[2] = 0xDEADBEEF;
- ib->length_dw = 3;
- r = radeon_ib_schedule(rdev, ib);
+ ib.ptr[0] = PACKET3(PACKET3_SET_CONFIG_REG, 1);
+ ib.ptr[1] = ((scratch - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
+ ib.ptr[2] = 0xDEADBEEF;
+ ib.length_dw = 3;
+ r = radeon_ib_schedule(rdev, &ib);
if (r) {
radeon_scratch_free(rdev, scratch);
radeon_ib_free(rdev, &ib);
DRM_ERROR("radeon: failed to schedule ib (%d).\n", r);
return r;
}
- r = radeon_fence_wait(ib->fence, false);
+ r = radeon_fence_wait(ib.fence, false);
if (r) {
DRM_ERROR("radeon: fence wait failed (%d).\n", r);
return r;
@@ -2745,7 +2726,7 @@ int r600_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
DRM_UDELAY(1);
}
if (i < rdev->usec_timeout) {
- DRM_INFO("ib test on ring %d succeeded in %u usecs\n", ib->fence->ring, i);
+ DRM_INFO("ib test on ring %d succeeded in %u usecs\n", ib.fence->ring, i);
} else {
DRM_ERROR("radeon: ib test failed (scratch(0x%04X)=0x%08X)\n",
scratch, tmp);
@@ -2788,7 +2769,7 @@ int r600_ih_ring_alloc(struct radeon_device *rdev)
r = radeon_bo_create(rdev, rdev->ih.ring_size,
PAGE_SIZE, true,
RADEON_GEM_DOMAIN_GTT,
- &rdev->ih.ring_obj);
+ NULL, &rdev->ih.ring_obj);
if (r) {
DRM_ERROR("radeon: failed to create ih ring buffer (%d).\n", r);
return r;
@@ -2968,6 +2949,15 @@ static void r600_disable_interrupt_state(struct radeon_device *rdev)
WREG32(DC_HPD5_INT_CONTROL, tmp);
tmp = RREG32(DC_HPD6_INT_CONTROL) & DC_HPDx_INT_POLARITY;
WREG32(DC_HPD6_INT_CONTROL, tmp);
+ tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET0) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
+ WREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET0, tmp);
+ tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET1) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
+ WREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET1, tmp);
+ } else {
+ tmp = RREG32(HDMI0_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
+ WREG32(HDMI0_AUDIO_PACKET_CONTROL, tmp);
+ tmp = RREG32(DCE3_HDMI1_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
+ WREG32(DCE3_HDMI1_AUDIO_PACKET_CONTROL, tmp);
}
} else {
WREG32(DACA_AUTODETECT_INT_CONTROL, 0);
@@ -2978,6 +2968,10 @@ static void r600_disable_interrupt_state(struct radeon_device *rdev)
WREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL, tmp);
tmp = RREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL) & DC_HOT_PLUG_DETECTx_INT_POLARITY;
WREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL, tmp);
+ tmp = RREG32(HDMI0_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
+ WREG32(HDMI0_AUDIO_PACKET_CONTROL, tmp);
+ tmp = RREG32(HDMI1_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
+ WREG32(HDMI1_AUDIO_PACKET_CONTROL, tmp);
}
}
@@ -3047,6 +3041,9 @@ int r600_irq_init(struct radeon_device *rdev)
else
r600_disable_interrupt_state(rdev);
+ /* at this point everything should be setup correctly to enable master */
+ pci_set_master(rdev->pdev);
+
/* enable irqs */
r600_enable_interrupts(rdev);
@@ -3071,7 +3068,7 @@ int r600_irq_set(struct radeon_device *rdev)
u32 mode_int = 0;
u32 hpd1, hpd2, hpd3, hpd4 = 0, hpd5 = 0, hpd6 = 0;
u32 grbm_int_cntl = 0;
- u32 hdmi1, hdmi2;
+ u32 hdmi0, hdmi1;
u32 d1grph = 0, d2grph = 0;
if (!rdev->irq.installed) {
@@ -3086,9 +3083,7 @@ int r600_irq_set(struct radeon_device *rdev)
return 0;
}
- hdmi1 = RREG32(R600_HDMI_BLOCK1 + R600_HDMI_CNTL) & ~R600_HDMI_INT_EN;
if (ASIC_IS_DCE3(rdev)) {
- hdmi2 = RREG32(R600_HDMI_BLOCK3 + R600_HDMI_CNTL) & ~R600_HDMI_INT_EN;
hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN;
@@ -3096,12 +3091,18 @@ int r600_irq_set(struct radeon_device *rdev)
if (ASIC_IS_DCE32(rdev)) {
hpd5 = RREG32(DC_HPD5_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd6 = RREG32(DC_HPD6_INT_CONTROL) & ~DC_HPDx_INT_EN;
+ hdmi0 = RREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET0) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
+ hdmi1 = RREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET1) & ~AFMT_AZ_FORMAT_WTRIG_MASK;
+ } else {
+ hdmi0 = RREG32(HDMI0_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
+ hdmi1 = RREG32(DCE3_HDMI1_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
}
} else {
- hdmi2 = RREG32(R600_HDMI_BLOCK2 + R600_HDMI_CNTL) & ~R600_HDMI_INT_EN;
hpd1 = RREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd2 = RREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL) & ~DC_HPDx_INT_EN;
hpd3 = RREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL) & ~DC_HPDx_INT_EN;
+ hdmi0 = RREG32(HDMI0_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
+ hdmi1 = RREG32(HDMI1_AUDIO_PACKET_CONTROL) & ~HDMI0_AZ_FORMAT_WTRIG_MASK;
}
if (rdev->irq.sw_int[RADEON_RING_TYPE_GFX_INDEX]) {
@@ -3143,13 +3144,13 @@ int r600_irq_set(struct radeon_device *rdev)
DRM_DEBUG("r600_irq_set: hpd 6\n");
hpd6 |= DC_HPDx_INT_EN;
}
- if (rdev->irq.hdmi[0]) {
- DRM_DEBUG("r600_irq_set: hdmi 1\n");
- hdmi1 |= R600_HDMI_INT_EN;
+ if (rdev->irq.afmt[0]) {
+ DRM_DEBUG("r600_irq_set: hdmi 0\n");
+ hdmi0 |= HDMI0_AZ_FORMAT_WTRIG_MASK;
}
- if (rdev->irq.hdmi[1]) {
- DRM_DEBUG("r600_irq_set: hdmi 2\n");
- hdmi2 |= R600_HDMI_INT_EN;
+ if (rdev->irq.afmt[1]) {
+ DRM_DEBUG("r600_irq_set: hdmi 0\n");
+ hdmi1 |= HDMI0_AZ_FORMAT_WTRIG_MASK;
}
if (rdev->irq.gui_idle) {
DRM_DEBUG("gui idle\n");
@@ -3161,9 +3162,7 @@ int r600_irq_set(struct radeon_device *rdev)
WREG32(D1GRPH_INTERRUPT_CONTROL, d1grph);
WREG32(D2GRPH_INTERRUPT_CONTROL, d2grph);
WREG32(GRBM_INT_CNTL, grbm_int_cntl);
- WREG32(R600_HDMI_BLOCK1 + R600_HDMI_CNTL, hdmi1);
if (ASIC_IS_DCE3(rdev)) {
- WREG32(R600_HDMI_BLOCK3 + R600_HDMI_CNTL, hdmi2);
WREG32(DC_HPD1_INT_CONTROL, hpd1);
WREG32(DC_HPD2_INT_CONTROL, hpd2);
WREG32(DC_HPD3_INT_CONTROL, hpd3);
@@ -3171,12 +3170,18 @@ int r600_irq_set(struct radeon_device *rdev)
if (ASIC_IS_DCE32(rdev)) {
WREG32(DC_HPD5_INT_CONTROL, hpd5);
WREG32(DC_HPD6_INT_CONTROL, hpd6);
+ WREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET0, hdmi0);
+ WREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET1, hdmi1);
+ } else {
+ WREG32(HDMI0_AUDIO_PACKET_CONTROL, hdmi0);
+ WREG32(DCE3_HDMI1_AUDIO_PACKET_CONTROL, hdmi1);
}
} else {
- WREG32(R600_HDMI_BLOCK2 + R600_HDMI_CNTL, hdmi2);
WREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL, hpd1);
WREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL, hpd2);
WREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL, hpd3);
+ WREG32(HDMI0_AUDIO_PACKET_CONTROL, hdmi0);
+ WREG32(HDMI1_AUDIO_PACKET_CONTROL, hdmi1);
}
return 0;
@@ -3190,10 +3195,19 @@ static void r600_irq_ack(struct radeon_device *rdev)
rdev->irq.stat_regs.r600.disp_int = RREG32(DCE3_DISP_INTERRUPT_STATUS);
rdev->irq.stat_regs.r600.disp_int_cont = RREG32(DCE3_DISP_INTERRUPT_STATUS_CONTINUE);
rdev->irq.stat_regs.r600.disp_int_cont2 = RREG32(DCE3_DISP_INTERRUPT_STATUS_CONTINUE2);
+ if (ASIC_IS_DCE32(rdev)) {
+ rdev->irq.stat_regs.r600.hdmi0_status = RREG32(AFMT_STATUS + DCE3_HDMI_OFFSET0);
+ rdev->irq.stat_regs.r600.hdmi1_status = RREG32(AFMT_STATUS + DCE3_HDMI_OFFSET1);
+ } else {
+ rdev->irq.stat_regs.r600.hdmi0_status = RREG32(HDMI0_STATUS);
+ rdev->irq.stat_regs.r600.hdmi1_status = RREG32(DCE3_HDMI1_STATUS);
+ }
} else {
rdev->irq.stat_regs.r600.disp_int = RREG32(DISP_INTERRUPT_STATUS);
rdev->irq.stat_regs.r600.disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE);
rdev->irq.stat_regs.r600.disp_int_cont2 = 0;
+ rdev->irq.stat_regs.r600.hdmi0_status = RREG32(HDMI0_STATUS);
+ rdev->irq.stat_regs.r600.hdmi1_status = RREG32(HDMI1_STATUS);
}
rdev->irq.stat_regs.r600.d1grph_int = RREG32(D1GRPH_INTERRUPT_STATUS);
rdev->irq.stat_regs.r600.d2grph_int = RREG32(D2GRPH_INTERRUPT_STATUS);
@@ -3259,17 +3273,32 @@ static void r600_irq_ack(struct radeon_device *rdev)
tmp |= DC_HPDx_INT_ACK;
WREG32(DC_HPD6_INT_CONTROL, tmp);
}
- }
- if (RREG32(R600_HDMI_BLOCK1 + R600_HDMI_STATUS) & R600_HDMI_INT_PENDING) {
- WREG32_P(R600_HDMI_BLOCK1 + R600_HDMI_CNTL, R600_HDMI_INT_ACK, ~R600_HDMI_INT_ACK);
- }
- if (ASIC_IS_DCE3(rdev)) {
- if (RREG32(R600_HDMI_BLOCK3 + R600_HDMI_STATUS) & R600_HDMI_INT_PENDING) {
- WREG32_P(R600_HDMI_BLOCK3 + R600_HDMI_CNTL, R600_HDMI_INT_ACK, ~R600_HDMI_INT_ACK);
+ if (rdev->irq.stat_regs.r600.hdmi0_status & AFMT_AZ_FORMAT_WTRIG) {
+ tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET0);
+ tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
+ WREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET0, tmp);
+ }
+ if (rdev->irq.stat_regs.r600.hdmi1_status & AFMT_AZ_FORMAT_WTRIG) {
+ tmp = RREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET1);
+ tmp |= AFMT_AZ_FORMAT_WTRIG_ACK;
+ WREG32(AFMT_AUDIO_PACKET_CONTROL + DCE3_HDMI_OFFSET1, tmp);
}
} else {
- if (RREG32(R600_HDMI_BLOCK2 + R600_HDMI_STATUS) & R600_HDMI_INT_PENDING) {
- WREG32_P(R600_HDMI_BLOCK2 + R600_HDMI_CNTL, R600_HDMI_INT_ACK, ~R600_HDMI_INT_ACK);
+ if (rdev->irq.stat_regs.r600.hdmi0_status & HDMI0_AZ_FORMAT_WTRIG) {
+ tmp = RREG32(HDMI0_AUDIO_PACKET_CONTROL);
+ tmp |= HDMI0_AZ_FORMAT_WTRIG_ACK;
+ WREG32(HDMI0_AUDIO_PACKET_CONTROL, tmp);
+ }
+ if (rdev->irq.stat_regs.r600.hdmi1_status & HDMI0_AZ_FORMAT_WTRIG) {
+ if (ASIC_IS_DCE3(rdev)) {
+ tmp = RREG32(DCE3_HDMI1_AUDIO_PACKET_CONTROL);
+ tmp |= HDMI0_AZ_FORMAT_WTRIG_ACK;
+ WREG32(DCE3_HDMI1_AUDIO_PACKET_CONTROL, tmp);
+ } else {
+ tmp = RREG32(HDMI1_AUDIO_PACKET_CONTROL);
+ tmp |= HDMI0_AZ_FORMAT_WTRIG_ACK;
+ WREG32(HDMI1_AUDIO_PACKET_CONTROL, tmp);
+ }
}
}
}
@@ -3345,6 +3374,7 @@ int r600_irq_process(struct radeon_device *rdev)
u32 ring_index;
unsigned long flags;
bool queue_hotplug = false;
+ bool queue_hdmi = false;
if (!rdev->ih.enabled || rdev->shutdown)
return IRQ_NONE;
@@ -3480,9 +3510,26 @@ restart_ih:
break;
}
break;
- case 21: /* HDMI */
- DRM_DEBUG("IH: HDMI: 0x%x\n", src_data);
- r600_audio_schedule_polling(rdev);
+ case 21: /* hdmi */
+ switch (src_data) {
+ case 4:
+ if (rdev->irq.stat_regs.r600.hdmi0_status & HDMI0_AZ_FORMAT_WTRIG) {
+ rdev->irq.stat_regs.r600.hdmi0_status &= ~HDMI0_AZ_FORMAT_WTRIG;
+ queue_hdmi = true;
+ DRM_DEBUG("IH: HDMI0\n");
+ }
+ break;
+ case 5:
+ if (rdev->irq.stat_regs.r600.hdmi1_status & HDMI0_AZ_FORMAT_WTRIG) {
+ rdev->irq.stat_regs.r600.hdmi1_status &= ~HDMI0_AZ_FORMAT_WTRIG;
+ queue_hdmi = true;
+ DRM_DEBUG("IH: HDMI1\n");
+ }
+ break;
+ default:
+ DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data);
+ break;
+ }
break;
case 176: /* CP_INT in ring buffer */
case 177: /* CP_INT in IB1 */
@@ -3514,6 +3561,8 @@ restart_ih:
goto restart_ih;
if (queue_hotplug)
schedule_work(&rdev->hotplug_work);
+ if (queue_hdmi)
+ schedule_work(&rdev->audio_work);
rdev->ih.rptr = rptr;
WREG32(IH_RB_RPTR, rdev->ih.rptr);
spin_unlock_irqrestore(&rdev->ih.lock, flags);
diff --git a/drivers/gpu/drm/radeon/r600_audio.c b/drivers/gpu/drm/radeon/r600_audio.c
index ba66f3093d46..7c4fa77f018f 100644
--- a/drivers/gpu/drm/radeon/r600_audio.c
+++ b/drivers/gpu/drm/radeon/r600_audio.c
@@ -29,7 +29,28 @@
#include "radeon_asic.h"
#include "atom.h"
-#define AUDIO_TIMER_INTERVALL 100 /* 1/10 sekund should be enough */
+/*
+ * check if enc_priv stores radeon_encoder_atom_dig
+ */
+static bool radeon_dig_encoder(struct drm_encoder *encoder)
+{
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ switch (radeon_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_LVDS:
+ case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
+ case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
+ case ENCODER_OBJECT_ID_INTERNAL_DVO1:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+ case ENCODER_OBJECT_ID_INTERNAL_DDI:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ return true;
+ }
+ return false;
+}
/*
* check if the chipset is supported
@@ -42,118 +63,85 @@ static int r600_audio_chipset_supported(struct radeon_device *rdev)
|| rdev->family == CHIP_RS740;
}
-/*
- * current number of channels
- */
-int r600_audio_channels(struct radeon_device *rdev)
+struct r600_audio r600_audio_status(struct radeon_device *rdev)
{
- return (RREG32(R600_AUDIO_RATE_BPS_CHANNEL) & 0x7) + 1;
-}
+ struct r600_audio status;
+ uint32_t value;
-/*
- * current bits per sample
- */
-int r600_audio_bits_per_sample(struct radeon_device *rdev)
-{
- uint32_t value = (RREG32(R600_AUDIO_RATE_BPS_CHANNEL) & 0xF0) >> 4;
- switch (value) {
- case 0x0: return 8;
- case 0x1: return 16;
- case 0x2: return 20;
- case 0x3: return 24;
- case 0x4: return 32;
- }
+ value = RREG32(R600_AUDIO_RATE_BPS_CHANNEL);
- dev_err(rdev->dev, "Unknown bits per sample 0x%x using 16 instead\n",
- (int)value);
+ /* number of channels */
+ status.channels = (value & 0x7) + 1;
- return 16;
-}
-
-/*
- * current sampling rate in HZ
- */
-int r600_audio_rate(struct radeon_device *rdev)
-{
- uint32_t value = RREG32(R600_AUDIO_RATE_BPS_CHANNEL);
- uint32_t result;
+ /* bits per sample */
+ switch ((value & 0xF0) >> 4) {
+ case 0x0:
+ status.bits_per_sample = 8;
+ break;
+ case 0x1:
+ status.bits_per_sample = 16;
+ break;
+ case 0x2:
+ status.bits_per_sample = 20;
+ break;
+ case 0x3:
+ status.bits_per_sample = 24;
+ break;
+ case 0x4:
+ status.bits_per_sample = 32;
+ break;
+ default:
+ dev_err(rdev->dev, "Unknown bits per sample 0x%x, using 16\n",
+ (int)value);
+ status.bits_per_sample = 16;
+ }
+ /* current sampling rate in HZ */
if (value & 0x4000)
- result = 44100;
+ status.rate = 44100;
else
- result = 48000;
+ status.rate = 48000;
+ status.rate *= ((value >> 11) & 0x7) + 1;
+ status.rate /= ((value >> 8) & 0x7) + 1;
- result *= ((value >> 11) & 0x7) + 1;
- result /= ((value >> 8) & 0x7) + 1;
+ value = RREG32(R600_AUDIO_STATUS_BITS);
- return result;
-}
+ /* iec 60958 status bits */
+ status.status_bits = value & 0xff;
-/*
- * iec 60958 status bits
- */
-uint8_t r600_audio_status_bits(struct radeon_device *rdev)
-{
- return RREG32(R600_AUDIO_STATUS_BITS) & 0xff;
-}
+ /* iec 60958 category code */
+ status.category_code = (value >> 8) & 0xff;
-/*
- * iec 60958 category code
- */
-uint8_t r600_audio_category_code(struct radeon_device *rdev)
-{
- return (RREG32(R600_AUDIO_STATUS_BITS) >> 8) & 0xff;
-}
-
-/*
- * schedule next audio update event
- */
-void r600_audio_schedule_polling(struct radeon_device *rdev)
-{
- mod_timer(&rdev->audio_timer,
- jiffies + msecs_to_jiffies(AUDIO_TIMER_INTERVALL));
+ return status;
}
/*
* update all hdmi interfaces with current audio parameters
*/
-static void r600_audio_update_hdmi(unsigned long param)
+void r600_audio_update_hdmi(struct work_struct *work)
{
- struct radeon_device *rdev = (struct radeon_device *)param;
+ struct radeon_device *rdev = container_of(work, struct radeon_device,
+ audio_work);
struct drm_device *dev = rdev->ddev;
-
- int channels = r600_audio_channels(rdev);
- int rate = r600_audio_rate(rdev);
- int bps = r600_audio_bits_per_sample(rdev);
- uint8_t status_bits = r600_audio_status_bits(rdev);
- uint8_t category_code = r600_audio_category_code(rdev);
-
+ struct r600_audio audio_status = r600_audio_status(rdev);
struct drm_encoder *encoder;
- int changes = 0, still_going = 0;
-
- changes |= channels != rdev->audio_channels;
- changes |= rate != rdev->audio_rate;
- changes |= bps != rdev->audio_bits_per_sample;
- changes |= status_bits != rdev->audio_status_bits;
- changes |= category_code != rdev->audio_category_code;
-
- if (changes) {
- rdev->audio_channels = channels;
- rdev->audio_rate = rate;
- rdev->audio_bits_per_sample = bps;
- rdev->audio_status_bits = status_bits;
- rdev->audio_category_code = category_code;
+ bool changed = false;
+
+ if (rdev->audio_status.channels != audio_status.channels ||
+ rdev->audio_status.rate != audio_status.rate ||
+ rdev->audio_status.bits_per_sample != audio_status.bits_per_sample ||
+ rdev->audio_status.status_bits != audio_status.status_bits ||
+ rdev->audio_status.category_code != audio_status.category_code) {
+ rdev->audio_status = audio_status;
+ changed = true;
}
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- still_going |= radeon_encoder->audio_polling_active;
- if (changes || r600_hdmi_buffer_status_changed(encoder))
+ if (!radeon_dig_encoder(encoder))
+ continue;
+ if (changed || r600_hdmi_buffer_status_changed(encoder))
r600_hdmi_update_audio_settings(encoder);
}
-
- if (still_going)
- r600_audio_schedule_polling(rdev);
}
/*
@@ -177,7 +165,7 @@ static void r600_audio_engine_enable(struct radeon_device *rdev, bool enable)
}
/*
- * initialize the audio vars and register the update timer
+ * initialize the audio vars
*/
int r600_audio_init(struct radeon_device *rdev)
{
@@ -186,51 +174,16 @@ int r600_audio_init(struct radeon_device *rdev)
r600_audio_engine_enable(rdev, true);
- rdev->audio_channels = -1;
- rdev->audio_rate = -1;
- rdev->audio_bits_per_sample = -1;
- rdev->audio_status_bits = 0;
- rdev->audio_category_code = 0;
-
- setup_timer(
- &rdev->audio_timer,
- r600_audio_update_hdmi,
- (unsigned long)rdev);
+ rdev->audio_status.channels = -1;
+ rdev->audio_status.rate = -1;
+ rdev->audio_status.bits_per_sample = -1;
+ rdev->audio_status.status_bits = 0;
+ rdev->audio_status.category_code = 0;
return 0;
}
/*
- * enable the polling timer, to check for status changes
- */
-void r600_audio_enable_polling(struct drm_encoder *encoder)
-{
- struct drm_device *dev = encoder->dev;
- struct radeon_device *rdev = dev->dev_private;
- struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-
- DRM_DEBUG("r600_audio_enable_polling: %d\n",
- radeon_encoder->audio_polling_active);
- if (radeon_encoder->audio_polling_active)
- return;
-
- radeon_encoder->audio_polling_active = 1;
- if (rdev->audio_enabled)
- mod_timer(&rdev->audio_timer, jiffies + 1);
-}
-
-/*
- * disable the polling timer, so we get no more status updates
- */
-void r600_audio_disable_polling(struct drm_encoder *encoder)
-{
- struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- DRM_DEBUG("r600_audio_disable_polling: %d\n",
- radeon_encoder->audio_polling_active);
- radeon_encoder->audio_polling_active = 0;
-}
-
-/*
* atach the audio codec to the clock source of the encoder
*/
void r600_audio_set_clock(struct drm_encoder *encoder, int clock)
@@ -297,7 +250,5 @@ void r600_audio_fini(struct radeon_device *rdev)
if (!rdev->audio_enabled)
return;
- del_timer(&rdev->audio_timer);
-
r600_audio_engine_enable(rdev, false);
}
diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c
index db38f587f27a..03b6e0d3d503 100644
--- a/drivers/gpu/drm/radeon/r600_blit_kms.c
+++ b/drivers/gpu/drm/radeon/r600_blit_kms.c
@@ -513,7 +513,6 @@ int r600_blit_init(struct radeon_device *rdev)
rdev->r600_blit.primitives.set_default_state = set_default_state;
rdev->r600_blit.ring_size_common = 40; /* shaders + def state */
- rdev->r600_blit.ring_size_common += 16; /* fence emit for VB IB */
rdev->r600_blit.ring_size_common += 5; /* done copy */
rdev->r600_blit.ring_size_common += 16; /* fence emit for done copy */
@@ -528,7 +527,6 @@ int r600_blit_init(struct radeon_device *rdev)
if (rdev->r600_blit.shader_obj)
goto done;
- mutex_init(&rdev->r600_blit.mutex);
rdev->r600_blit.state_offset = 0;
if (rdev->family >= CHIP_RV770)
@@ -554,7 +552,7 @@ int r600_blit_init(struct radeon_device *rdev)
obj_size = ALIGN(obj_size, 256);
r = radeon_bo_create(rdev, obj_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
- &rdev->r600_blit.shader_obj);
+ NULL, &rdev->r600_blit.shader_obj);
if (r) {
DRM_ERROR("r600 failed to allocate shader\n");
return r;
@@ -621,27 +619,6 @@ void r600_blit_fini(struct radeon_device *rdev)
radeon_bo_unref(&rdev->r600_blit.shader_obj);
}
-static int r600_vb_ib_get(struct radeon_device *rdev, unsigned size)
-{
- int r;
- r = radeon_ib_get(rdev, RADEON_RING_TYPE_GFX_INDEX,
- &rdev->r600_blit.vb_ib, size);
- if (r) {
- DRM_ERROR("failed to get IB for vertex buffer\n");
- return r;
- }
-
- rdev->r600_blit.vb_total = size;
- rdev->r600_blit.vb_used = 0;
- return 0;
-}
-
-static void r600_vb_ib_put(struct radeon_device *rdev)
-{
- radeon_fence_emit(rdev, rdev->r600_blit.vb_ib->fence);
- radeon_ib_free(rdev, &rdev->r600_blit.vb_ib);
-}
-
static unsigned r600_blit_create_rect(unsigned num_gpu_pages,
int *width, int *height, int max_dim)
{
@@ -688,7 +665,8 @@ static unsigned r600_blit_create_rect(unsigned num_gpu_pages,
}
-int r600_blit_prepare_copy(struct radeon_device *rdev, unsigned num_gpu_pages)
+int r600_blit_prepare_copy(struct radeon_device *rdev, unsigned num_gpu_pages,
+ struct radeon_sa_bo **vb)
{
struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
int r;
@@ -705,46 +683,54 @@ int r600_blit_prepare_copy(struct radeon_device *rdev, unsigned num_gpu_pages)
}
/* 48 bytes for vertex per loop */
- r = r600_vb_ib_get(rdev, (num_loops*48)+256);
- if (r)
+ r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo, vb,
+ (num_loops*48)+256, 256, true);
+ if (r) {
return r;
+ }
/* calculate number of loops correctly */
ring_size = num_loops * dwords_per_loop;
ring_size += rdev->r600_blit.ring_size_common;
r = radeon_ring_lock(rdev, ring, ring_size);
- if (r)
+ if (r) {
+ radeon_sa_bo_free(rdev, vb, NULL);
return r;
+ }
rdev->r600_blit.primitives.set_default_state(rdev);
rdev->r600_blit.primitives.set_shaders(rdev);
return 0;
}
-void r600_blit_done_copy(struct radeon_device *rdev, struct radeon_fence *fence)
+void r600_blit_done_copy(struct radeon_device *rdev, struct radeon_fence *fence,
+ struct radeon_sa_bo *vb)
{
+ struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
int r;
- if (rdev->r600_blit.vb_ib)
- r600_vb_ib_put(rdev);
-
- if (fence)
- r = radeon_fence_emit(rdev, fence);
+ r = radeon_fence_emit(rdev, fence);
+ if (r) {
+ radeon_ring_unlock_undo(rdev, ring);
+ return;
+ }
- radeon_ring_unlock_commit(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
+ radeon_ring_unlock_commit(rdev, ring);
+ radeon_sa_bo_free(rdev, &vb, fence);
}
void r600_kms_blit_copy(struct radeon_device *rdev,
u64 src_gpu_addr, u64 dst_gpu_addr,
- unsigned num_gpu_pages)
+ unsigned num_gpu_pages,
+ struct radeon_sa_bo *vb)
{
u64 vb_gpu_addr;
- u32 *vb;
+ u32 *vb_cpu_addr;
- DRM_DEBUG("emitting copy %16llx %16llx %d %d\n",
- src_gpu_addr, dst_gpu_addr,
- num_gpu_pages, rdev->r600_blit.vb_used);
- vb = (u32 *)(rdev->r600_blit.vb_ib->ptr + rdev->r600_blit.vb_used);
+ DRM_DEBUG("emitting copy %16llx %16llx %d\n",
+ src_gpu_addr, dst_gpu_addr, num_gpu_pages);
+ vb_cpu_addr = (u32 *)radeon_sa_bo_cpu_addr(vb);
+ vb_gpu_addr = radeon_sa_bo_gpu_addr(vb);
while (num_gpu_pages) {
int w, h;
@@ -756,39 +742,34 @@ void r600_kms_blit_copy(struct radeon_device *rdev,
size_in_bytes = pages_per_loop * RADEON_GPU_PAGE_SIZE;
DRM_DEBUG("rectangle w=%d h=%d\n", w, h);
- if ((rdev->r600_blit.vb_used + 48) > rdev->r600_blit.vb_total) {
- WARN_ON(1);
- }
-
- vb[0] = 0;
- vb[1] = 0;
- vb[2] = 0;
- vb[3] = 0;
+ vb_cpu_addr[0] = 0;
+ vb_cpu_addr[1] = 0;
+ vb_cpu_addr[2] = 0;
+ vb_cpu_addr[3] = 0;
- vb[4] = 0;
- vb[5] = i2f(h);
- vb[6] = 0;
- vb[7] = i2f(h);
+ vb_cpu_addr[4] = 0;
+ vb_cpu_addr[5] = i2f(h);
+ vb_cpu_addr[6] = 0;
+ vb_cpu_addr[7] = i2f(h);
- vb[8] = i2f(w);
- vb[9] = i2f(h);
- vb[10] = i2f(w);
- vb[11] = i2f(h);
+ vb_cpu_addr[8] = i2f(w);
+ vb_cpu_addr[9] = i2f(h);
+ vb_cpu_addr[10] = i2f(w);
+ vb_cpu_addr[11] = i2f(h);
rdev->r600_blit.primitives.set_tex_resource(rdev, FMT_8_8_8_8,
w, h, w, src_gpu_addr, size_in_bytes);
rdev->r600_blit.primitives.set_render_target(rdev, COLOR_8_8_8_8,
w, h, dst_gpu_addr);
rdev->r600_blit.primitives.set_scissors(rdev, 0, 0, w, h);
- vb_gpu_addr = rdev->r600_blit.vb_ib->gpu_addr + rdev->r600_blit.vb_used;
rdev->r600_blit.primitives.set_vtx_resource(rdev, vb_gpu_addr);
rdev->r600_blit.primitives.draw_auto(rdev);
rdev->r600_blit.primitives.cp_set_surface_sync(rdev,
PACKET3_CB_ACTION_ENA | PACKET3_CB0_DEST_BASE_ENA,
size_in_bytes, dst_gpu_addr);
- vb += 12;
- rdev->r600_blit.vb_used += 4*12;
+ vb_cpu_addr += 12;
+ vb_gpu_addr += 4*12;
src_gpu_addr += size_in_bytes;
dst_gpu_addr += size_in_bytes;
num_gpu_pages -= pages_per_loop;
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c
index b8e12af304a9..0133f5f09bd6 100644
--- a/drivers/gpu/drm/radeon/r600_cs.c
+++ b/drivers/gpu/drm/radeon/r600_cs.c
@@ -345,7 +345,7 @@ static int r600_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
u32 height, height_align, pitch, pitch_align, depth_align;
u64 base_offset, base_align;
struct array_mode_checker array_check;
- volatile u32 *ib = p->ib->ptr;
+ volatile u32 *ib = p->ib.ptr;
unsigned array_mode;
u32 format;
@@ -471,7 +471,7 @@ static int r600_cs_track_validate_db(struct radeon_cs_parser *p)
u64 base_offset, base_align;
struct array_mode_checker array_check;
int array_mode;
- volatile u32 *ib = p->ib->ptr;
+ volatile u32 *ib = p->ib.ptr;
if (track->db_bo == NULL) {
@@ -961,7 +961,7 @@ static int r600_cs_packet_parse_vline(struct radeon_cs_parser *p)
uint32_t header, h_idx, reg, wait_reg_mem_info;
volatile uint32_t *ib;
- ib = p->ib->ptr;
+ ib = p->ib.ptr;
/* parse the WAIT_REG_MEM */
r = r600_cs_packet_parse(p, &wait_reg_mem, p->idx);
@@ -1110,7 +1110,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
m = 1 << ((reg >> 2) & 31);
if (!(r600_reg_safe_bm[i] & m))
return 0;
- ib = p->ib->ptr;
+ ib = p->ib.ptr;
switch (reg) {
/* force following reg to 0 in an attempt to disable out buffer
* which will need us to better understand how it works to perform
@@ -1714,7 +1714,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
u32 idx_value;
track = (struct r600_cs_track *)p->track;
- ib = p->ib->ptr;
+ ib = p->ib.ptr;
idx = pkt->idx + 1;
idx_value = radeon_get_ib_value(p, idx);
@@ -2249,8 +2249,8 @@ int r600_cs_parse(struct radeon_cs_parser *p)
}
} while (p->idx < p->chunks[p->chunk_ib_idx].length_dw);
#if 0
- for (r = 0; r < p->ib->length_dw; r++) {
- printk(KERN_INFO "%05d 0x%08X\n", r, p->ib->ptr[r]);
+ for (r = 0; r < p->ib.length_dw; r++) {
+ printk(KERN_INFO "%05d 0x%08X\n", r, p->ib.ptr[r]);
mdelay(1);
}
#endif
@@ -2298,7 +2298,6 @@ int r600_cs_legacy(struct drm_device *dev, void *data, struct drm_file *filp,
{
struct radeon_cs_parser parser;
struct radeon_cs_chunk *ib_chunk;
- struct radeon_ib fake_ib;
struct r600_cs_track *track;
int r;
@@ -2314,9 +2313,8 @@ int r600_cs_legacy(struct drm_device *dev, void *data, struct drm_file *filp,
parser.dev = &dev->pdev->dev;
parser.rdev = NULL;
parser.family = family;
- parser.ib = &fake_ib;
parser.track = track;
- fake_ib.ptr = ib;
+ parser.ib.ptr = ib;
r = radeon_cs_parser_init(&parser, data);
if (r) {
DRM_ERROR("Failed to initialize parser !\n");
@@ -2333,8 +2331,8 @@ int r600_cs_legacy(struct drm_device *dev, void *data, struct drm_file *filp,
* input memory (cached) and write to the IB (which can be
* uncached). */
ib_chunk = &parser.chunks[parser.chunk_ib_idx];
- parser.ib->length_dw = ib_chunk->length_dw;
- *l = parser.ib->length_dw;
+ parser.ib.length_dw = ib_chunk->length_dw;
+ *l = parser.ib.length_dw;
r = r600_cs_parse(&parser);
if (r) {
DRM_ERROR("Invalid command stream !\n");
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c
index 0b5920671450..226379e00ac1 100644
--- a/drivers/gpu/drm/radeon/r600_hdmi.c
+++ b/drivers/gpu/drm/radeon/r600_hdmi.c
@@ -27,6 +27,7 @@
#include "radeon_drm.h"
#include "radeon.h"
#include "radeon_asic.h"
+#include "r600d.h"
#include "atom.h"
/*
@@ -52,19 +53,7 @@ enum r600_hdmi_iec_status_bits {
AUDIO_STATUS_LEVEL = 0x80
};
-struct {
- uint32_t Clock;
-
- int N_32kHz;
- int CTS_32kHz;
-
- int N_44_1kHz;
- int CTS_44_1kHz;
-
- int N_48kHz;
- int CTS_48kHz;
-
-} r600_hdmi_ACR[] = {
+struct radeon_hdmi_acr r600_hdmi_predefined_acr[] = {
/* 32kHz 44.1kHz 48kHz */
/* Clock N CTS N CTS N CTS */
{ 25174, 4576, 28125, 7007, 31250, 6864, 28125 }, /* 25,20/1.001 MHz */
@@ -83,7 +72,7 @@ struct {
/*
* calculate CTS value if it's not found in the table
*/
-static void r600_hdmi_calc_CTS(uint32_t clock, int *CTS, int N, int freq)
+static void r600_hdmi_calc_cts(uint32_t clock, int *CTS, int N, int freq)
{
if (*CTS == 0)
*CTS = clock * N / (128 * freq) * 1000;
@@ -91,6 +80,24 @@ static void r600_hdmi_calc_CTS(uint32_t clock, int *CTS, int N, int freq)
N, *CTS, freq);
}
+struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock)
+{
+ struct radeon_hdmi_acr res;
+ u8 i;
+
+ for (i = 0; r600_hdmi_predefined_acr[i].clock != clock &&
+ r600_hdmi_predefined_acr[i].clock != 0; i++)
+ ;
+ res = r600_hdmi_predefined_acr[i];
+
+ /* In case some CTS are missing */
+ r600_hdmi_calc_cts(clock, &res.cts_32khz, res.n_32khz, 32000);
+ r600_hdmi_calc_cts(clock, &res.cts_44_1khz, res.n_44_1khz, 44100);
+ r600_hdmi_calc_cts(clock, &res.cts_48khz, res.n_48khz, 48000);
+
+ return res;
+}
+
/*
* update the N and CTS parameters for a given pixel clock rate
*/
@@ -98,30 +105,19 @@ static void r600_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
- uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset;
- int CTS;
- int N;
- int i;
+ struct radeon_hdmi_acr acr = r600_hdmi_acr(clock);
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+ uint32_t offset = dig->afmt->offset;
+
+ WREG32(HDMI0_ACR_32_0 + offset, HDMI0_ACR_CTS_32(acr.cts_32khz));
+ WREG32(HDMI0_ACR_32_1 + offset, acr.n_32khz);
- for (i = 0; r600_hdmi_ACR[i].Clock != clock && r600_hdmi_ACR[i].Clock != 0; i++);
-
- CTS = r600_hdmi_ACR[i].CTS_32kHz;
- N = r600_hdmi_ACR[i].N_32kHz;
- r600_hdmi_calc_CTS(clock, &CTS, N, 32000);
- WREG32(offset+R600_HDMI_32kHz_CTS, CTS << 12);
- WREG32(offset+R600_HDMI_32kHz_N, N);
-
- CTS = r600_hdmi_ACR[i].CTS_44_1kHz;
- N = r600_hdmi_ACR[i].N_44_1kHz;
- r600_hdmi_calc_CTS(clock, &CTS, N, 44100);
- WREG32(offset+R600_HDMI_44_1kHz_CTS, CTS << 12);
- WREG32(offset+R600_HDMI_44_1kHz_N, N);
-
- CTS = r600_hdmi_ACR[i].CTS_48kHz;
- N = r600_hdmi_ACR[i].N_48kHz;
- r600_hdmi_calc_CTS(clock, &CTS, N, 48000);
- WREG32(offset+R600_HDMI_48kHz_CTS, CTS << 12);
- WREG32(offset+R600_HDMI_48kHz_N, N);
+ WREG32(HDMI0_ACR_44_0 + offset, HDMI0_ACR_CTS_44(acr.cts_44_1khz));
+ WREG32(HDMI0_ACR_44_1 + offset, acr.n_44_1khz);
+
+ WREG32(HDMI0_ACR_48_0 + offset, HDMI0_ACR_CTS_48(acr.cts_48khz));
+ WREG32(HDMI0_ACR_48_1 + offset, acr.n_48khz);
}
/*
@@ -165,7 +161,9 @@ static void r600_hdmi_videoinfoframe(
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
- uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset;
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+ uint32_t offset = dig->afmt->offset;
uint8_t frame[14];
@@ -204,13 +202,13 @@ static void r600_hdmi_videoinfoframe(
* workaround this issue. */
frame[0x0] += 2;
- WREG32(offset+R600_HDMI_VIDEOINFOFRAME_0,
+ WREG32(HDMI0_AVI_INFO0 + offset,
frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
- WREG32(offset+R600_HDMI_VIDEOINFOFRAME_1,
+ WREG32(HDMI0_AVI_INFO1 + offset,
frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x7] << 24));
- WREG32(offset+R600_HDMI_VIDEOINFOFRAME_2,
+ WREG32(HDMI0_AVI_INFO2 + offset,
frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24));
- WREG32(offset+R600_HDMI_VIDEOINFOFRAME_3,
+ WREG32(HDMI0_AVI_INFO3 + offset,
frame[0xC] | (frame[0xD] << 8));
}
@@ -231,7 +229,9 @@ static void r600_hdmi_audioinfoframe(
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
- uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset;
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+ uint32_t offset = dig->afmt->offset;
uint8_t frame[11];
@@ -249,22 +249,24 @@ static void r600_hdmi_audioinfoframe(
r600_hdmi_infoframe_checksum(0x84, 0x01, 0x0A, frame);
- WREG32(offset+R600_HDMI_AUDIOINFOFRAME_0,
+ WREG32(HDMI0_AUDIO_INFO0 + offset,
frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
- WREG32(offset+R600_HDMI_AUDIOINFOFRAME_1,
+ WREG32(HDMI0_AUDIO_INFO1 + offset,
frame[0x4] | (frame[0x5] << 8) | (frame[0x6] << 16) | (frame[0x8] << 24));
}
/*
* test if audio buffer is filled enough to start playing
*/
-static int r600_hdmi_is_audio_buffer_filled(struct drm_encoder *encoder)
+static bool r600_hdmi_is_audio_buffer_filled(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
- uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset;
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+ uint32_t offset = dig->afmt->offset;
- return (RREG32(offset+R600_HDMI_STATUS) & 0x10) != 0;
+ return (RREG32(HDMI0_STATUS + offset) & 0x10) != 0;
}
/*
@@ -273,14 +275,15 @@ static int r600_hdmi_is_audio_buffer_filled(struct drm_encoder *encoder)
int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder)
{
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
int status, result;
- if (!radeon_encoder->hdmi_offset)
+ if (!dig->afmt || !dig->afmt->enabled)
return 0;
status = r600_hdmi_is_audio_buffer_filled(encoder);
- result = radeon_encoder->hdmi_buffer_status != status;
- radeon_encoder->hdmi_buffer_status = status;
+ result = dig->afmt->last_buffer_filled_status != status;
+ dig->afmt->last_buffer_filled_status = status;
return result;
}
@@ -288,26 +291,23 @@ int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder)
/*
* write the audio workaround status to the hardware
*/
-void r600_hdmi_audio_workaround(struct drm_encoder *encoder)
+static void r600_hdmi_audio_workaround(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- uint32_t offset = radeon_encoder->hdmi_offset;
-
- if (!offset)
- return;
-
- if (!radeon_encoder->hdmi_audio_workaround ||
- r600_hdmi_is_audio_buffer_filled(encoder)) {
-
- /* disable audio workaround */
- WREG32_P(offset+R600_HDMI_CNTL, 0x00000001, ~0x00001001);
-
- } else {
- /* enable audio workaround */
- WREG32_P(offset+R600_HDMI_CNTL, 0x00001001, ~0x00001001);
- }
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+ uint32_t offset = dig->afmt->offset;
+ bool hdmi_audio_workaround = false; /* FIXME */
+ u32 value;
+
+ if (!hdmi_audio_workaround ||
+ r600_hdmi_is_audio_buffer_filled(encoder))
+ value = 0; /* disable workaround */
+ else
+ value = HDMI0_AUDIO_TEST_EN; /* enable workaround */
+ WREG32_P(HDMI0_AUDIO_PACKET_CONTROL + offset,
+ value, ~HDMI0_AUDIO_TEST_EN);
}
@@ -318,39 +318,75 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
- uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset;
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+ uint32_t offset;
if (ASIC_IS_DCE5(rdev))
return;
- if (!offset)
+ /* Silent, r600_hdmi_enable will raise WARN for us */
+ if (!dig->afmt->enabled)
return;
+ offset = dig->afmt->offset;
r600_audio_set_clock(encoder, mode->clock);
- WREG32(offset+R600_HDMI_UNKNOWN_0, 0x1000);
- WREG32(offset+R600_HDMI_UNKNOWN_1, 0x0);
- WREG32(offset+R600_HDMI_UNKNOWN_2, 0x1000);
+ WREG32(HDMI0_VBI_PACKET_CONTROL + offset,
+ HDMI0_NULL_SEND); /* send null packets when required */
- r600_hdmi_update_ACR(encoder, mode->clock);
+ WREG32(HDMI0_AUDIO_CRC_CONTROL + offset, 0x1000);
+
+ if (ASIC_IS_DCE32(rdev)) {
+ WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset,
+ HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */
+ HDMI0_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
+ WREG32(AFMT_AUDIO_PACKET_CONTROL + offset,
+ AFMT_AUDIO_SAMPLE_SEND | /* send audio packets */
+ AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */
+ } else {
+ WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset,
+ HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */
+ HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */
+ HDMI0_AUDIO_SEND_MAX_PACKETS | /* send NULL packets if no audio is available */
+ HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */
+ HDMI0_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */
+ }
+
+ WREG32(HDMI0_ACR_PACKET_CONTROL + offset,
+ HDMI0_ACR_AUTO_SEND | /* allow hw to sent ACR packets when required */
+ HDMI0_ACR_SOURCE); /* select SW CTS value */
+
+ WREG32(HDMI0_VBI_PACKET_CONTROL + offset,
+ HDMI0_NULL_SEND | /* send null packets when required */
+ HDMI0_GC_SEND | /* send general control packets */
+ HDMI0_GC_CONT); /* send general control packets every frame */
- WREG32(offset+R600_HDMI_VIDEOCNTL, 0x13);
+ /* TODO: HDMI0_AUDIO_INFO_UPDATE */
+ WREG32(HDMI0_INFOFRAME_CONTROL0 + offset,
+ HDMI0_AVI_INFO_SEND | /* enable AVI info frames */
+ HDMI0_AVI_INFO_CONT | /* send AVI info frames every frame/field */
+ HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
+ HDMI0_AUDIO_INFO_CONT); /* send audio info frames every frame/field */
- WREG32(offset+R600_HDMI_VERSION, 0x202);
+ WREG32(HDMI0_INFOFRAME_CONTROL1 + offset,
+ HDMI0_AVI_INFO_LINE(2) | /* anything other than 0 */
+ HDMI0_AUDIO_INFO_LINE(2)); /* anything other than 0 */
+
+ WREG32(HDMI0_GC + offset, 0); /* unset HDMI0_GC_AVMUTE */
r600_hdmi_videoinfoframe(encoder, RGB, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ r600_hdmi_update_ACR(encoder, mode->clock);
+
/* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */
- WREG32(offset+R600_HDMI_AUDIO_DEBUG_0, 0x00FFFFFF);
- WREG32(offset+R600_HDMI_AUDIO_DEBUG_1, 0x007FFFFF);
- WREG32(offset+R600_HDMI_AUDIO_DEBUG_2, 0x00000001);
- WREG32(offset+R600_HDMI_AUDIO_DEBUG_3, 0x00000001);
+ WREG32(HDMI0_RAMP_CONTROL0 + offset, 0x00FFFFFF);
+ WREG32(HDMI0_RAMP_CONTROL1 + offset, 0x007FFFFF);
+ WREG32(HDMI0_RAMP_CONTROL2 + offset, 0x00000001);
+ WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001);
r600_hdmi_audio_workaround(encoder);
-
- /* audio packets per line, does anyone know how to calc this ? */
- WREG32_P(offset+R600_HDMI_CNTL, 0x00040000, ~0x001F0000);
}
/*
@@ -360,145 +396,82 @@ void r600_hdmi_update_audio_settings(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
- uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset;
-
- int channels = r600_audio_channels(rdev);
- int rate = r600_audio_rate(rdev);
- int bps = r600_audio_bits_per_sample(rdev);
- uint8_t status_bits = r600_audio_status_bits(rdev);
- uint8_t category_code = r600_audio_category_code(rdev);
-
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+ struct r600_audio audio = r600_audio_status(rdev);
+ uint32_t offset;
uint32_t iec;
- if (!offset)
+ if (!dig->afmt || !dig->afmt->enabled)
return;
+ offset = dig->afmt->offset;
DRM_DEBUG("%s with %d channels, %d Hz sampling rate, %d bits per sample,\n",
r600_hdmi_is_audio_buffer_filled(encoder) ? "playing" : "stopped",
- channels, rate, bps);
+ audio.channels, audio.rate, audio.bits_per_sample);
DRM_DEBUG("0x%02X IEC60958 status bits and 0x%02X category code\n",
- (int)status_bits, (int)category_code);
+ (int)audio.status_bits, (int)audio.category_code);
iec = 0;
- if (status_bits & AUDIO_STATUS_PROFESSIONAL)
+ if (audio.status_bits & AUDIO_STATUS_PROFESSIONAL)
iec |= 1 << 0;
- if (status_bits & AUDIO_STATUS_NONAUDIO)
+ if (audio.status_bits & AUDIO_STATUS_NONAUDIO)
iec |= 1 << 1;
- if (status_bits & AUDIO_STATUS_COPYRIGHT)
+ if (audio.status_bits & AUDIO_STATUS_COPYRIGHT)
iec |= 1 << 2;
- if (status_bits & AUDIO_STATUS_EMPHASIS)
+ if (audio.status_bits & AUDIO_STATUS_EMPHASIS)
iec |= 1 << 3;
- iec |= category_code << 8;
-
- switch (rate) {
- case 32000: iec |= 0x3 << 24; break;
- case 44100: iec |= 0x0 << 24; break;
- case 88200: iec |= 0x8 << 24; break;
- case 176400: iec |= 0xc << 24; break;
- case 48000: iec |= 0x2 << 24; break;
- case 96000: iec |= 0xa << 24; break;
- case 192000: iec |= 0xe << 24; break;
+ iec |= HDMI0_60958_CS_CATEGORY_CODE(audio.category_code);
+
+ switch (audio.rate) {
+ case 32000:
+ iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x3);
+ break;
+ case 44100:
+ iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x0);
+ break;
+ case 48000:
+ iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x2);
+ break;
+ case 88200:
+ iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0x8);
+ break;
+ case 96000:
+ iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0xa);
+ break;
+ case 176400:
+ iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0xc);
+ break;
+ case 192000:
+ iec |= HDMI0_60958_CS_SAMPLING_FREQUENCY(0xe);
+ break;
}
- WREG32(offset+R600_HDMI_IEC60958_1, iec);
+ WREG32(HDMI0_60958_0 + offset, iec);
iec = 0;
- switch (bps) {
- case 16: iec |= 0x2; break;
- case 20: iec |= 0x3; break;
- case 24: iec |= 0xb; break;
+ switch (audio.bits_per_sample) {
+ case 16:
+ iec |= HDMI0_60958_CS_WORD_LENGTH(0x2);
+ break;
+ case 20:
+ iec |= HDMI0_60958_CS_WORD_LENGTH(0x3);
+ break;
+ case 24:
+ iec |= HDMI0_60958_CS_WORD_LENGTH(0xb);
+ break;
}
- if (status_bits & AUDIO_STATUS_V)
+ if (audio.status_bits & AUDIO_STATUS_V)
iec |= 0x5 << 16;
+ WREG32_P(HDMI0_60958_1 + offset, iec, ~0x5000f);
- WREG32_P(offset+R600_HDMI_IEC60958_2, iec, ~0x5000f);
-
- /* 0x021 or 0x031 sets the audio frame length */
- WREG32(offset+R600_HDMI_AUDIOCNTL, 0x31);
- r600_hdmi_audioinfoframe(encoder, channels-1, 0, 0, 0, 0, 0, 0, 0);
+ r600_hdmi_audioinfoframe(encoder, audio.channels - 1, 0, 0, 0, 0, 0, 0,
+ 0);
r600_hdmi_audio_workaround(encoder);
}
-static int r600_hdmi_find_free_block(struct drm_device *dev)
-{
- struct radeon_device *rdev = dev->dev_private;
- struct drm_encoder *encoder;
- struct radeon_encoder *radeon_encoder;
- bool free_blocks[3] = { true, true, true };
-
- list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
- radeon_encoder = to_radeon_encoder(encoder);
- switch (radeon_encoder->hdmi_offset) {
- case R600_HDMI_BLOCK1:
- free_blocks[0] = false;
- break;
- case R600_HDMI_BLOCK2:
- free_blocks[1] = false;
- break;
- case R600_HDMI_BLOCK3:
- free_blocks[2] = false;
- break;
- }
- }
-
- if (rdev->family == CHIP_RS600 || rdev->family == CHIP_RS690 ||
- rdev->family == CHIP_RS740) {
- return free_blocks[0] ? R600_HDMI_BLOCK1 : 0;
- } else if (rdev->family >= CHIP_R600) {
- if (free_blocks[0])
- return R600_HDMI_BLOCK1;
- else if (free_blocks[1])
- return R600_HDMI_BLOCK2;
- }
- return 0;
-}
-
-static void r600_hdmi_assign_block(struct drm_encoder *encoder)
-{
- struct drm_device *dev = encoder->dev;
- struct radeon_device *rdev = dev->dev_private;
- struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-
- u16 eg_offsets[] = {
- EVERGREEN_CRTC0_REGISTER_OFFSET,
- EVERGREEN_CRTC1_REGISTER_OFFSET,
- EVERGREEN_CRTC2_REGISTER_OFFSET,
- EVERGREEN_CRTC3_REGISTER_OFFSET,
- EVERGREEN_CRTC4_REGISTER_OFFSET,
- EVERGREEN_CRTC5_REGISTER_OFFSET,
- };
-
- if (!dig) {
- dev_err(rdev->dev, "Enabling HDMI on non-dig encoder\n");
- return;
- }
-
- if (ASIC_IS_DCE5(rdev)) {
- /* TODO */
- } else if (ASIC_IS_DCE4(rdev)) {
- if (dig->dig_encoder >= ARRAY_SIZE(eg_offsets)) {
- dev_err(rdev->dev, "Enabling HDMI on unknown dig\n");
- return;
- }
- radeon_encoder->hdmi_offset = EVERGREEN_HDMI_BASE +
- eg_offsets[dig->dig_encoder];
- radeon_encoder->hdmi_config_offset = radeon_encoder->hdmi_offset
- + EVERGREEN_HDMI_CONFIG_OFFSET;
- } else if (ASIC_IS_DCE3(rdev)) {
- radeon_encoder->hdmi_offset = dig->dig_encoder ?
- R600_HDMI_BLOCK3 : R600_HDMI_BLOCK1;
- if (ASIC_IS_DCE32(rdev))
- radeon_encoder->hdmi_config_offset = dig->dig_encoder ?
- R600_HDMI_CONFIG2 : R600_HDMI_CONFIG1;
- } else if (rdev->family >= CHIP_R600 || rdev->family == CHIP_RS600 ||
- rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) {
- radeon_encoder->hdmi_offset = r600_hdmi_find_free_block(dev);
- }
-}
-
/*
* enable the HDMI engine
*/
@@ -507,64 +480,57 @@ void r600_hdmi_enable(struct drm_encoder *encoder)
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
uint32_t offset;
+ u32 hdmi;
if (ASIC_IS_DCE5(rdev))
return;
- if (!radeon_encoder->hdmi_offset) {
- r600_hdmi_assign_block(encoder);
- if (!radeon_encoder->hdmi_offset) {
- dev_warn(rdev->dev, "Could not find HDMI block for "
- "0x%x encoder\n", radeon_encoder->encoder_id);
- return;
- }
- }
+ /* Silent, r600_hdmi_enable will raise WARN for us */
+ if (dig->afmt->enabled)
+ return;
+ offset = dig->afmt->offset;
- offset = radeon_encoder->hdmi_offset;
- if (ASIC_IS_DCE5(rdev)) {
- /* TODO */
- } else if (ASIC_IS_DCE4(rdev)) {
- WREG32_P(radeon_encoder->hdmi_config_offset + 0xc, 0x1, ~0x1);
- } else if (ASIC_IS_DCE32(rdev)) {
- WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0x1, ~0x1);
- } else if (ASIC_IS_DCE3(rdev)) {
- /* TODO */
- } else if (rdev->family >= CHIP_R600) {
+ /* Older chipsets require setting HDMI and routing manually */
+ if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) {
+ hdmi = HDMI0_ERROR_ACK | HDMI0_ENABLE;
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
WREG32_P(AVIVO_TMDSA_CNTL, AVIVO_TMDSA_CNTL_HDMI_EN,
~AVIVO_TMDSA_CNTL_HDMI_EN);
- WREG32(offset + R600_HDMI_ENABLE, 0x101);
+ hdmi |= HDMI0_STREAM(HDMI0_STREAM_TMDSA);
break;
case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
WREG32_P(AVIVO_LVTMA_CNTL, AVIVO_LVTMA_CNTL_HDMI_EN,
~AVIVO_LVTMA_CNTL_HDMI_EN);
- WREG32(offset + R600_HDMI_ENABLE, 0x105);
+ hdmi |= HDMI0_STREAM(HDMI0_STREAM_LVTMA);
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_DDI:
+ WREG32_P(DDIA_CNTL, DDIA_HDMI_EN, ~DDIA_HDMI_EN);
+ hdmi |= HDMI0_STREAM(HDMI0_STREAM_DDIA);
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
+ hdmi |= HDMI0_STREAM(HDMI0_STREAM_DVOA);
break;
default:
- dev_err(rdev->dev, "Unknown HDMI output type\n");
+ dev_err(rdev->dev, "Invalid encoder for HDMI: 0x%X\n",
+ radeon_encoder->encoder_id);
break;
}
+ WREG32(HDMI0_CONTROL + offset, hdmi);
}
- if (rdev->irq.installed
- && rdev->family != CHIP_RS600
- && rdev->family != CHIP_RS690
- && rdev->family != CHIP_RS740
- && !ASIC_IS_DCE4(rdev)) {
+ if (rdev->irq.installed) {
/* if irq is available use it */
- rdev->irq.hdmi[offset == R600_HDMI_BLOCK1 ? 0 : 1] = true;
+ rdev->irq.afmt[dig->afmt->id] = true;
radeon_irq_set(rdev);
-
- r600_audio_disable_polling(encoder);
- } else {
- /* if not fallback to polling */
- r600_audio_enable_polling(encoder);
}
+ dig->afmt->enabled = true;
+
DRM_DEBUG("Enabling HDMI interface @ 0x%04X for encoder 0x%x\n",
- radeon_encoder->hdmi_offset, radeon_encoder->encoder_id);
+ offset, radeon_encoder->encoder_id);
}
/*
@@ -575,51 +541,51 @@ void r600_hdmi_disable(struct drm_encoder *encoder)
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
uint32_t offset;
if (ASIC_IS_DCE5(rdev))
return;
- offset = radeon_encoder->hdmi_offset;
- if (!offset) {
- dev_err(rdev->dev, "Disabling not enabled HDMI\n");
+ /* Called for ATOM_ENCODER_MODE_HDMI only */
+ if (!dig || !dig->afmt) {
+ WARN_ON(1);
return;
}
+ if (!dig->afmt->enabled)
+ return;
+ offset = dig->afmt->offset;
DRM_DEBUG("Disabling HDMI interface @ 0x%04X for encoder 0x%x\n",
- offset, radeon_encoder->encoder_id);
+ offset, radeon_encoder->encoder_id);
/* disable irq */
- rdev->irq.hdmi[offset == R600_HDMI_BLOCK1 ? 0 : 1] = false;
+ rdev->irq.afmt[dig->afmt->id] = false;
radeon_irq_set(rdev);
- /* disable polling */
- r600_audio_disable_polling(encoder);
-
- if (ASIC_IS_DCE5(rdev)) {
- /* TODO */
- } else if (ASIC_IS_DCE4(rdev)) {
- WREG32_P(radeon_encoder->hdmi_config_offset + 0xc, 0, ~0x1);
- } else if (ASIC_IS_DCE32(rdev)) {
- WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0, ~0x1);
- } else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) {
+ /* Older chipsets not handled by AtomBIOS */
+ if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) {
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
WREG32_P(AVIVO_TMDSA_CNTL, 0,
~AVIVO_TMDSA_CNTL_HDMI_EN);
- WREG32(offset + R600_HDMI_ENABLE, 0);
break;
case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
WREG32_P(AVIVO_LVTMA_CNTL, 0,
~AVIVO_LVTMA_CNTL_HDMI_EN);
- WREG32(offset + R600_HDMI_ENABLE, 0);
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_DDI:
+ WREG32_P(DDIA_CNTL, 0, ~DDIA_HDMI_EN);
+ break;
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
break;
default:
- dev_err(rdev->dev, "Unknown HDMI output type\n");
+ dev_err(rdev->dev, "Invalid encoder for HDMI: 0x%X\n",
+ radeon_encoder->encoder_id);
break;
}
+ WREG32(HDMI0_CONTROL + offset, HDMI0_ERROR_ACK);
}
- radeon_encoder->hdmi_offset = 0;
- radeon_encoder->hdmi_config_offset = 0;
+ dig->afmt->enabled = false;
}
diff --git a/drivers/gpu/drm/radeon/r600_reg.h b/drivers/gpu/drm/radeon/r600_reg.h
index f869897c7456..2b960cb5c18a 100644
--- a/drivers/gpu/drm/radeon/r600_reg.h
+++ b/drivers/gpu/drm/radeon/r600_reg.h
@@ -156,45 +156,10 @@
#define R600_AUDIO_PIN_WIDGET_CNTL 0x73d4
#define R600_AUDIO_STATUS_BITS 0x73d8
-/* HDMI base register addresses */
-#define R600_HDMI_BLOCK1 0x7400
-#define R600_HDMI_BLOCK2 0x7700
-#define R600_HDMI_BLOCK3 0x7800
-
-/* HDMI registers */
-#define R600_HDMI_ENABLE 0x00
-#define R600_HDMI_STATUS 0x04
-# define R600_HDMI_INT_PENDING (1 << 29)
-#define R600_HDMI_CNTL 0x08
-# define R600_HDMI_INT_EN (1 << 28)
-# define R600_HDMI_INT_ACK (1 << 29)
-#define R600_HDMI_UNKNOWN_0 0x0C
-#define R600_HDMI_AUDIOCNTL 0x10
-#define R600_HDMI_VIDEOCNTL 0x14
-#define R600_HDMI_VERSION 0x18
-#define R600_HDMI_UNKNOWN_1 0x28
-#define R600_HDMI_VIDEOINFOFRAME_0 0x54
-#define R600_HDMI_VIDEOINFOFRAME_1 0x58
-#define R600_HDMI_VIDEOINFOFRAME_2 0x5c
-#define R600_HDMI_VIDEOINFOFRAME_3 0x60
-#define R600_HDMI_32kHz_CTS 0xac
-#define R600_HDMI_32kHz_N 0xb0
-#define R600_HDMI_44_1kHz_CTS 0xb4
-#define R600_HDMI_44_1kHz_N 0xb8
-#define R600_HDMI_48kHz_CTS 0xbc
-#define R600_HDMI_48kHz_N 0xc0
-#define R600_HDMI_AUDIOINFOFRAME_0 0xcc
-#define R600_HDMI_AUDIOINFOFRAME_1 0xd0
-#define R600_HDMI_IEC60958_1 0xd4
-#define R600_HDMI_IEC60958_2 0xd8
-#define R600_HDMI_UNKNOWN_2 0xdc
-#define R600_HDMI_AUDIO_DEBUG_0 0xe0
-#define R600_HDMI_AUDIO_DEBUG_1 0xe4
-#define R600_HDMI_AUDIO_DEBUG_2 0xe8
-#define R600_HDMI_AUDIO_DEBUG_3 0xec
-
-/* HDMI additional config base register addresses */
-#define R600_HDMI_CONFIG1 0x7600
-#define R600_HDMI_CONFIG2 0x7a00
+#define DCE2_HDMI_OFFSET0 (0x7400 - 0x7400)
+#define DCE2_HDMI_OFFSET1 (0x7700 - 0x7400)
+/* DCE3.2 second instance starts at 0x7800 */
+#define DCE3_HDMI_OFFSET0 (0x7400 - 0x7400)
+#define DCE3_HDMI_OFFSET1 (0x7800 - 0x7400)
#endif
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h
index 59f9c993cc31..15bd3b216243 100644
--- a/drivers/gpu/drm/radeon/r600d.h
+++ b/drivers/gpu/drm/radeon/r600d.h
@@ -824,6 +824,239 @@
# define TARGET_LINK_SPEED_MASK (0xf << 0)
# define SELECTABLE_DEEMPHASIS (1 << 6)
+/* Audio clocks */
+#define DCCG_AUDIO_DTO0_PHASE 0x0514
+#define DCCG_AUDIO_DTO0_MODULE 0x0518
+#define DCCG_AUDIO_DTO0_LOAD 0x051c
+# define DTO_LOAD (1 << 31)
+#define DCCG_AUDIO_DTO0_CNTL 0x0520
+
+#define DCCG_AUDIO_DTO1_PHASE 0x0524
+#define DCCG_AUDIO_DTO1_MODULE 0x0528
+#define DCCG_AUDIO_DTO1_LOAD 0x052c
+#define DCCG_AUDIO_DTO1_CNTL 0x0530
+
+#define DCCG_AUDIO_DTO_SELECT 0x0534
+
+/* digital blocks */
+#define TMDSA_CNTL 0x7880
+# define TMDSA_HDMI_EN (1 << 2)
+#define LVTMA_CNTL 0x7a80
+# define LVTMA_HDMI_EN (1 << 2)
+#define DDIA_CNTL 0x7200
+# define DDIA_HDMI_EN (1 << 2)
+#define DIG0_CNTL 0x75a0
+# define DIG_MODE(x) (((x) & 7) << 8)
+# define DIG_MODE_DP 0
+# define DIG_MODE_LVDS 1
+# define DIG_MODE_TMDS_DVI 2
+# define DIG_MODE_TMDS_HDMI 3
+# define DIG_MODE_SDVO 4
+#define DIG1_CNTL 0x79a0
+
+/* rs6xx/rs740 and r6xx share the same HDMI blocks, however, rs6xx has only one
+ * instance of the blocks while r6xx has 2. DCE 3.0 cards are slightly
+ * different due to the new DIG blocks, but also have 2 instances.
+ * DCE 3.0 HDMI blocks are part of each DIG encoder.
+ */
+
+/* rs6xx/rs740/r6xx/dce3 */
+#define HDMI0_CONTROL 0x7400
+/* rs6xx/rs740/r6xx */
+# define HDMI0_ENABLE (1 << 0)
+# define HDMI0_STREAM(x) (((x) & 3) << 2)
+# define HDMI0_STREAM_TMDSA 0
+# define HDMI0_STREAM_LVTMA 1
+# define HDMI0_STREAM_DVOA 2
+# define HDMI0_STREAM_DDIA 3
+/* rs6xx/r6xx/dce3 */
+# define HDMI0_ERROR_ACK (1 << 8)
+# define HDMI0_ERROR_MASK (1 << 9)
+#define HDMI0_STATUS 0x7404
+# define HDMI0_ACTIVE_AVMUTE (1 << 0)
+# define HDMI0_AUDIO_ENABLE (1 << 4)
+# define HDMI0_AZ_FORMAT_WTRIG (1 << 28)
+# define HDMI0_AZ_FORMAT_WTRIG_INT (1 << 29)
+#define HDMI0_AUDIO_PACKET_CONTROL 0x7408
+# define HDMI0_AUDIO_SAMPLE_SEND (1 << 0)
+# define HDMI0_AUDIO_DELAY_EN(x) (((x) & 3) << 4)
+# define HDMI0_AUDIO_SEND_MAX_PACKETS (1 << 8)
+# define HDMI0_AUDIO_TEST_EN (1 << 12)
+# define HDMI0_AUDIO_PACKETS_PER_LINE(x) (((x) & 0x1f) << 16)
+# define HDMI0_AUDIO_CHANNEL_SWAP (1 << 24)
+# define HDMI0_60958_CS_UPDATE (1 << 26)
+# define HDMI0_AZ_FORMAT_WTRIG_MASK (1 << 28)
+# define HDMI0_AZ_FORMAT_WTRIG_ACK (1 << 29)
+#define HDMI0_AUDIO_CRC_CONTROL 0x740c
+# define HDMI0_AUDIO_CRC_EN (1 << 0)
+#define HDMI0_VBI_PACKET_CONTROL 0x7410
+# define HDMI0_NULL_SEND (1 << 0)
+# define HDMI0_GC_SEND (1 << 4)
+# define HDMI0_GC_CONT (1 << 5) /* 0 - once; 1 - every frame */
+#define HDMI0_INFOFRAME_CONTROL0 0x7414
+# define HDMI0_AVI_INFO_SEND (1 << 0)
+# define HDMI0_AVI_INFO_CONT (1 << 1)
+# define HDMI0_AUDIO_INFO_SEND (1 << 4)
+# define HDMI0_AUDIO_INFO_CONT (1 << 5)
+# define HDMI0_AUDIO_INFO_SOURCE (1 << 6) /* 0 - sound block; 1 - hmdi regs */
+# define HDMI0_AUDIO_INFO_UPDATE (1 << 7)
+# define HDMI0_MPEG_INFO_SEND (1 << 8)
+# define HDMI0_MPEG_INFO_CONT (1 << 9)
+# define HDMI0_MPEG_INFO_UPDATE (1 << 10)
+#define HDMI0_INFOFRAME_CONTROL1 0x7418
+# define HDMI0_AVI_INFO_LINE(x) (((x) & 0x3f) << 0)
+# define HDMI0_AUDIO_INFO_LINE(x) (((x) & 0x3f) << 8)
+# define HDMI0_MPEG_INFO_LINE(x) (((x) & 0x3f) << 16)
+#define HDMI0_GENERIC_PACKET_CONTROL 0x741c
+# define HDMI0_GENERIC0_SEND (1 << 0)
+# define HDMI0_GENERIC0_CONT (1 << 1)
+# define HDMI0_GENERIC0_UPDATE (1 << 2)
+# define HDMI0_GENERIC1_SEND (1 << 4)
+# define HDMI0_GENERIC1_CONT (1 << 5)
+# define HDMI0_GENERIC0_LINE(x) (((x) & 0x3f) << 16)
+# define HDMI0_GENERIC1_LINE(x) (((x) & 0x3f) << 24)
+#define HDMI0_GC 0x7428
+# define HDMI0_GC_AVMUTE (1 << 0)
+#define HDMI0_AVI_INFO0 0x7454
+# define HDMI0_AVI_INFO_CHECKSUM(x) (((x) & 0xff) << 0)
+# define HDMI0_AVI_INFO_S(x) (((x) & 3) << 8)
+# define HDMI0_AVI_INFO_B(x) (((x) & 3) << 10)
+# define HDMI0_AVI_INFO_A(x) (((x) & 1) << 12)
+# define HDMI0_AVI_INFO_Y(x) (((x) & 3) << 13)
+# define HDMI0_AVI_INFO_Y_RGB 0
+# define HDMI0_AVI_INFO_Y_YCBCR422 1
+# define HDMI0_AVI_INFO_Y_YCBCR444 2
+# define HDMI0_AVI_INFO_Y_A_B_S(x) (((x) & 0xff) << 8)
+# define HDMI0_AVI_INFO_R(x) (((x) & 0xf) << 16)
+# define HDMI0_AVI_INFO_M(x) (((x) & 0x3) << 20)
+# define HDMI0_AVI_INFO_C(x) (((x) & 0x3) << 22)
+# define HDMI0_AVI_INFO_C_M_R(x) (((x) & 0xff) << 16)
+# define HDMI0_AVI_INFO_SC(x) (((x) & 0x3) << 24)
+# define HDMI0_AVI_INFO_ITC_EC_Q_SC(x) (((x) & 0xff) << 24)
+#define HDMI0_AVI_INFO1 0x7458
+# define HDMI0_AVI_INFO_VIC(x) (((x) & 0x7f) << 0) /* don't use avi infoframe v1 */
+# define HDMI0_AVI_INFO_PR(x) (((x) & 0xf) << 8) /* don't use avi infoframe v1 */
+# define HDMI0_AVI_INFO_TOP(x) (((x) & 0xffff) << 16)
+#define HDMI0_AVI_INFO2 0x745c
+# define HDMI0_AVI_INFO_BOTTOM(x) (((x) & 0xffff) << 0)
+# define HDMI0_AVI_INFO_LEFT(x) (((x) & 0xffff) << 16)
+#define HDMI0_AVI_INFO3 0x7460
+# define HDMI0_AVI_INFO_RIGHT(x) (((x) & 0xffff) << 0)
+# define HDMI0_AVI_INFO_VERSION(x) (((x) & 3) << 24)
+#define HDMI0_MPEG_INFO0 0x7464
+# define HDMI0_MPEG_INFO_CHECKSUM(x) (((x) & 0xff) << 0)
+# define HDMI0_MPEG_INFO_MB0(x) (((x) & 0xff) << 8)
+# define HDMI0_MPEG_INFO_MB1(x) (((x) & 0xff) << 16)
+# define HDMI0_MPEG_INFO_MB2(x) (((x) & 0xff) << 24)
+#define HDMI0_MPEG_INFO1 0x7468
+# define HDMI0_MPEG_INFO_MB3(x) (((x) & 0xff) << 0)
+# define HDMI0_MPEG_INFO_MF(x) (((x) & 3) << 8)
+# define HDMI0_MPEG_INFO_FR(x) (((x) & 1) << 12)
+#define HDMI0_GENERIC0_HDR 0x746c
+#define HDMI0_GENERIC0_0 0x7470
+#define HDMI0_GENERIC0_1 0x7474
+#define HDMI0_GENERIC0_2 0x7478
+#define HDMI0_GENERIC0_3 0x747c
+#define HDMI0_GENERIC0_4 0x7480
+#define HDMI0_GENERIC0_5 0x7484
+#define HDMI0_GENERIC0_6 0x7488
+#define HDMI0_GENERIC1_HDR 0x748c
+#define HDMI0_GENERIC1_0 0x7490
+#define HDMI0_GENERIC1_1 0x7494
+#define HDMI0_GENERIC1_2 0x7498
+#define HDMI0_GENERIC1_3 0x749c
+#define HDMI0_GENERIC1_4 0x74a0
+#define HDMI0_GENERIC1_5 0x74a4
+#define HDMI0_GENERIC1_6 0x74a8
+#define HDMI0_ACR_32_0 0x74ac
+# define HDMI0_ACR_CTS_32(x) (((x) & 0xfffff) << 12)
+#define HDMI0_ACR_32_1 0x74b0
+# define HDMI0_ACR_N_32(x) (((x) & 0xfffff) << 0)
+#define HDMI0_ACR_44_0 0x74b4
+# define HDMI0_ACR_CTS_44(x) (((x) & 0xfffff) << 12)
+#define HDMI0_ACR_44_1 0x74b8
+# define HDMI0_ACR_N_44(x) (((x) & 0xfffff) << 0)
+#define HDMI0_ACR_48_0 0x74bc
+# define HDMI0_ACR_CTS_48(x) (((x) & 0xfffff) << 12)
+#define HDMI0_ACR_48_1 0x74c0
+# define HDMI0_ACR_N_48(x) (((x) & 0xfffff) << 0)
+#define HDMI0_ACR_STATUS_0 0x74c4
+#define HDMI0_ACR_STATUS_1 0x74c8
+#define HDMI0_AUDIO_INFO0 0x74cc
+# define HDMI0_AUDIO_INFO_CHECKSUM(x) (((x) & 0xff) << 0)
+# define HDMI0_AUDIO_INFO_CC(x) (((x) & 7) << 8)
+#define HDMI0_AUDIO_INFO1 0x74d0
+# define HDMI0_AUDIO_INFO_CA(x) (((x) & 0xff) << 0)
+# define HDMI0_AUDIO_INFO_LSV(x) (((x) & 0xf) << 11)
+# define HDMI0_AUDIO_INFO_DM_INH(x) (((x) & 1) << 15)
+# define HDMI0_AUDIO_INFO_DM_INH_LSV(x) (((x) & 0xff) << 8)
+#define HDMI0_60958_0 0x74d4
+# define HDMI0_60958_CS_A(x) (((x) & 1) << 0)
+# define HDMI0_60958_CS_B(x) (((x) & 1) << 1)
+# define HDMI0_60958_CS_C(x) (((x) & 1) << 2)
+# define HDMI0_60958_CS_D(x) (((x) & 3) << 3)
+# define HDMI0_60958_CS_MODE(x) (((x) & 3) << 6)
+# define HDMI0_60958_CS_CATEGORY_CODE(x) (((x) & 0xff) << 8)
+# define HDMI0_60958_CS_SOURCE_NUMBER(x) (((x) & 0xf) << 16)
+# define HDMI0_60958_CS_CHANNEL_NUMBER_L(x) (((x) & 0xf) << 20)
+# define HDMI0_60958_CS_SAMPLING_FREQUENCY(x) (((x) & 0xf) << 24)
+# define HDMI0_60958_CS_CLOCK_ACCURACY(x) (((x) & 3) << 28)
+#define HDMI0_60958_1 0x74d8
+# define HDMI0_60958_CS_WORD_LENGTH(x) (((x) & 0xf) << 0)
+# define HDMI0_60958_CS_ORIGINAL_SAMPLING_FREQUENCY(x) (((x) & 0xf) << 4)
+# define HDMI0_60958_CS_VALID_L(x) (((x) & 1) << 16)
+# define HDMI0_60958_CS_VALID_R(x) (((x) & 1) << 18)
+# define HDMI0_60958_CS_CHANNEL_NUMBER_R(x) (((x) & 0xf) << 20)
+#define HDMI0_ACR_PACKET_CONTROL 0x74dc
+# define HDMI0_ACR_SEND (1 << 0)
+# define HDMI0_ACR_CONT (1 << 1)
+# define HDMI0_ACR_SELECT(x) (((x) & 3) << 4)
+# define HDMI0_ACR_HW 0
+# define HDMI0_ACR_32 1
+# define HDMI0_ACR_44 2
+# define HDMI0_ACR_48 3
+# define HDMI0_ACR_SOURCE (1 << 8) /* 0 - hw; 1 - cts value */
+# define HDMI0_ACR_AUTO_SEND (1 << 12)
+#define HDMI0_RAMP_CONTROL0 0x74e0
+# define HDMI0_RAMP_MAX_COUNT(x) (((x) & 0xffffff) << 0)
+#define HDMI0_RAMP_CONTROL1 0x74e4
+# define HDMI0_RAMP_MIN_COUNT(x) (((x) & 0xffffff) << 0)
+#define HDMI0_RAMP_CONTROL2 0x74e8
+# define HDMI0_RAMP_INC_COUNT(x) (((x) & 0xffffff) << 0)
+#define HDMI0_RAMP_CONTROL3 0x74ec
+# define HDMI0_RAMP_DEC_COUNT(x) (((x) & 0xffffff) << 0)
+/* HDMI0_60958_2 is r7xx only */
+#define HDMI0_60958_2 0x74f0
+# define HDMI0_60958_CS_CHANNEL_NUMBER_2(x) (((x) & 0xf) << 0)
+# define HDMI0_60958_CS_CHANNEL_NUMBER_3(x) (((x) & 0xf) << 4)
+# define HDMI0_60958_CS_CHANNEL_NUMBER_4(x) (((x) & 0xf) << 8)
+# define HDMI0_60958_CS_CHANNEL_NUMBER_5(x) (((x) & 0xf) << 12)
+# define HDMI0_60958_CS_CHANNEL_NUMBER_6(x) (((x) & 0xf) << 16)
+# define HDMI0_60958_CS_CHANNEL_NUMBER_7(x) (((x) & 0xf) << 20)
+/* r6xx only; second instance starts at 0x7700 */
+#define HDMI1_CONTROL 0x7700
+#define HDMI1_STATUS 0x7704
+#define HDMI1_AUDIO_PACKET_CONTROL 0x7708
+/* DCE3; second instance starts at 0x7800 NOT 0x7700 */
+#define DCE3_HDMI1_CONTROL 0x7800
+#define DCE3_HDMI1_STATUS 0x7804
+#define DCE3_HDMI1_AUDIO_PACKET_CONTROL 0x7808
+/* DCE3.2 (for interrupts) */
+#define AFMT_STATUS 0x7600
+# define AFMT_AUDIO_ENABLE (1 << 4)
+# define AFMT_AZ_FORMAT_WTRIG (1 << 28)
+# define AFMT_AZ_FORMAT_WTRIG_INT (1 << 29)
+# define AFMT_AZ_AUDIO_ENABLE_CHG (1 << 30)
+#define AFMT_AUDIO_PACKET_CONTROL 0x7604
+# define AFMT_AUDIO_SAMPLE_SEND (1 << 0)
+# define AFMT_AUDIO_TEST_EN (1 << 12)
+# define AFMT_AUDIO_CHANNEL_SWAP (1 << 24)
+# define AFMT_60958_CS_UPDATE (1 << 26)
+# define AFMT_AZ_AUDIO_ENABLE_CHG_MASK (1 << 27)
+# define AFMT_AZ_FORMAT_WTRIG_MASK (1 << 28)
+# define AFMT_AZ_FORMAT_WTRIG_ACK (1 << 29)
+# define AFMT_AZ_AUDIO_ENABLE_CHG_ACK (1 << 30)
+
/*
* PM4
*/
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 138b95216d8d..1dc3a4aba020 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -94,33 +94,38 @@ extern int radeon_disp_priority;
extern int radeon_hw_i2c;
extern int radeon_pcie_gen2;
extern int radeon_msi;
+extern int radeon_lockup_timeout;
/*
* Copy from radeon_drv.h so we don't have to include both and have conflicting
* symbol;
*/
-#define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */
-#define RADEON_FENCE_JIFFIES_TIMEOUT (HZ / 2)
+#define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */
+#define RADEON_FENCE_JIFFIES_TIMEOUT (HZ / 2)
/* RADEON_IB_POOL_SIZE must be a power of 2 */
-#define RADEON_IB_POOL_SIZE 16
-#define RADEON_DEBUGFS_MAX_COMPONENTS 32
-#define RADEONFB_CONN_LIMIT 4
-#define RADEON_BIOS_NUM_SCRATCH 8
+#define RADEON_IB_POOL_SIZE 16
+#define RADEON_DEBUGFS_MAX_COMPONENTS 32
+#define RADEONFB_CONN_LIMIT 4
+#define RADEON_BIOS_NUM_SCRATCH 8
/* max number of rings */
-#define RADEON_NUM_RINGS 3
+#define RADEON_NUM_RINGS 3
+
+/* fence seq are set to this number when signaled */
+#define RADEON_FENCE_SIGNALED_SEQ 0LL
+#define RADEON_FENCE_NOTEMITED_SEQ (~0LL)
/* internal ring indices */
/* r1xx+ has gfx CP ring */
-#define RADEON_RING_TYPE_GFX_INDEX 0
+#define RADEON_RING_TYPE_GFX_INDEX 0
/* cayman has 2 compute CP rings */
-#define CAYMAN_RING_TYPE_CP1_INDEX 1
-#define CAYMAN_RING_TYPE_CP2_INDEX 2
+#define CAYMAN_RING_TYPE_CP1_INDEX 1
+#define CAYMAN_RING_TYPE_CP2_INDEX 2
/* hardcode those limit for now */
-#define RADEON_VA_RESERVED_SIZE (8 << 20)
-#define RADEON_IB_VM_MAX_SIZE (64 << 10)
+#define RADEON_VA_RESERVED_SIZE (8 << 20)
+#define RADEON_IB_VM_MAX_SIZE (64 << 10)
/*
* Errata workarounds.
@@ -253,28 +258,20 @@ struct radeon_fence_driver {
uint32_t scratch_reg;
uint64_t gpu_addr;
volatile uint32_t *cpu_addr;
- atomic_t seq;
- uint32_t last_seq;
- unsigned long last_jiffies;
- unsigned long last_timeout;
- wait_queue_head_t queue;
- struct list_head created;
- struct list_head emitted;
- struct list_head signaled;
+ /* seq is protected by ring emission lock */
+ uint64_t seq;
+ atomic64_t last_seq;
+ unsigned long last_activity;
bool initialized;
};
struct radeon_fence {
struct radeon_device *rdev;
struct kref kref;
- struct list_head list;
/* protected by radeon_fence.lock */
- uint32_t seq;
- bool emitted;
- bool signaled;
+ uint64_t seq;
/* RB, DMA, etc. */
- int ring;
- struct radeon_semaphore *semaphore;
+ unsigned ring;
};
int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring);
@@ -285,11 +282,14 @@ int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence);
void radeon_fence_process(struct radeon_device *rdev, int ring);
bool radeon_fence_signaled(struct radeon_fence *fence);
int radeon_fence_wait(struct radeon_fence *fence, bool interruptible);
-int radeon_fence_wait_next(struct radeon_device *rdev, int ring);
-int radeon_fence_wait_last(struct radeon_device *rdev, int ring);
+int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring);
+int radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring);
+int radeon_fence_wait_any(struct radeon_device *rdev,
+ struct radeon_fence **fences,
+ bool intr);
struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence);
void radeon_fence_unref(struct radeon_fence **fence);
-int radeon_fence_count_emitted(struct radeon_device *rdev, int ring);
+unsigned radeon_fence_count_emitted(struct radeon_device *rdev, int ring);
/*
* Tiling registers
@@ -382,8 +382,11 @@ struct radeon_bo_list {
* alignment).
*/
struct radeon_sa_manager {
+ spinlock_t lock;
struct radeon_bo *bo;
- struct list_head sa_bo;
+ struct list_head *hole;
+ struct list_head flist[RADEON_NUM_RINGS];
+ struct list_head olist;
unsigned size;
uint64_t gpu_addr;
void *cpu_ptr;
@@ -394,10 +397,12 @@ struct radeon_sa_bo;
/* sub-allocation buffer */
struct radeon_sa_bo {
- struct list_head list;
+ struct list_head olist;
+ struct list_head flist;
struct radeon_sa_manager *manager;
- unsigned offset;
- unsigned size;
+ unsigned soffset;
+ unsigned eoffset;
+ struct radeon_fence *fence;
};
/*
@@ -428,42 +433,26 @@ int radeon_mode_dumb_destroy(struct drm_file *file_priv,
/*
* Semaphores.
*/
-struct radeon_ring;
-
-#define RADEON_SEMAPHORE_BO_SIZE 256
-
-struct radeon_semaphore_driver {
- rwlock_t lock;
- struct list_head bo;
-};
-
-struct radeon_semaphore_bo;
-
/* everything here is constant */
struct radeon_semaphore {
- struct list_head list;
+ struct radeon_sa_bo *sa_bo;
+ signed waiters;
uint64_t gpu_addr;
- uint32_t *cpu_ptr;
- struct radeon_semaphore_bo *bo;
};
-struct radeon_semaphore_bo {
- struct list_head list;
- struct radeon_ib *ib;
- struct list_head free;
- struct radeon_semaphore semaphores[RADEON_SEMAPHORE_BO_SIZE/8];
- unsigned nused;
-};
-
-void radeon_semaphore_driver_fini(struct radeon_device *rdev);
int radeon_semaphore_create(struct radeon_device *rdev,
struct radeon_semaphore **semaphore);
void radeon_semaphore_emit_signal(struct radeon_device *rdev, int ring,
struct radeon_semaphore *semaphore);
void radeon_semaphore_emit_wait(struct radeon_device *rdev, int ring,
struct radeon_semaphore *semaphore);
+int radeon_semaphore_sync_rings(struct radeon_device *rdev,
+ struct radeon_semaphore *semaphore,
+ bool sync_to[RADEON_NUM_RINGS],
+ int dst_ring);
void radeon_semaphore_free(struct radeon_device *rdev,
- struct radeon_semaphore *semaphore);
+ struct radeon_semaphore *semaphore,
+ struct radeon_fence *fence);
/*
* GART structures, functions & helpers
@@ -560,6 +549,7 @@ struct radeon_unpin_work {
struct r500_irq_stat_regs {
u32 disp_int;
+ u32 hdmi0_status;
};
struct r600_irq_stat_regs {
@@ -568,6 +558,8 @@ struct r600_irq_stat_regs {
u32 disp_int_cont2;
u32 d1grph_int;
u32 d2grph_int;
+ u32 hdmi0_status;
+ u32 hdmi1_status;
};
struct evergreen_irq_stat_regs {
@@ -583,6 +575,12 @@ struct evergreen_irq_stat_regs {
u32 d4grph_int;
u32 d5grph_int;
u32 d6grph_int;
+ u32 afmt_status1;
+ u32 afmt_status2;
+ u32 afmt_status3;
+ u32 afmt_status4;
+ u32 afmt_status5;
+ u32 afmt_status6;
};
union radeon_irq_stat_regs {
@@ -593,7 +591,7 @@ union radeon_irq_stat_regs {
#define RADEON_MAX_HPD_PINS 6
#define RADEON_MAX_CRTCS 6
-#define RADEON_MAX_HDMI_BLOCKS 2
+#define RADEON_MAX_AFMT_BLOCKS 6
struct radeon_irq {
bool installed;
@@ -605,7 +603,7 @@ struct radeon_irq {
bool gui_idle;
bool gui_idle_acked;
wait_queue_head_t idle_queue;
- bool hdmi[RADEON_MAX_HDMI_BLOCKS];
+ bool afmt[RADEON_MAX_AFMT_BLOCKS];
spinlock_t sw_lock;
int sw_refcount[RADEON_NUM_RINGS];
union radeon_irq_stat_regs stat_regs;
@@ -625,26 +623,14 @@ void radeon_irq_kms_pflip_irq_put(struct radeon_device *rdev, int crtc);
*/
struct radeon_ib {
- struct radeon_sa_bo sa_bo;
- unsigned idx;
- uint32_t length_dw;
- uint64_t gpu_addr;
- uint32_t *ptr;
- struct radeon_fence *fence;
- unsigned vm_id;
- bool is_const_ib;
-};
-
-/*
- * locking -
- * mutex protects scheduled_ibs, ready, alloc_bm
- */
-struct radeon_ib_pool {
- struct radeon_mutex mutex;
- struct radeon_sa_manager sa_manager;
- struct radeon_ib ibs[RADEON_IB_POOL_SIZE];
- bool ready;
- unsigned head_id;
+ struct radeon_sa_bo *sa_bo;
+ uint32_t length_dw;
+ uint64_t gpu_addr;
+ uint32_t *ptr;
+ struct radeon_fence *fence;
+ unsigned vm_id;
+ bool is_const_ib;
+ struct radeon_semaphore *semaphore;
};
struct radeon_ring {
@@ -659,10 +645,11 @@ struct radeon_ring {
unsigned ring_size;
unsigned ring_free_dw;
int count_dw;
+ unsigned long last_activity;
+ unsigned last_rptr;
uint64_t gpu_addr;
uint32_t align_mask;
uint32_t ptr_mask;
- struct mutex mutex;
bool ready;
u32 ptr_reg_shift;
u32 ptr_reg_mask;
@@ -679,7 +666,7 @@ struct radeon_vm {
unsigned last_pfn;
u64 pt_gpu_addr;
u64 *pt;
- struct radeon_sa_bo sa_bo;
+ struct radeon_sa_bo *sa_bo;
struct mutex mutex;
/* last fence for cs using this vm */
struct radeon_fence *fence;
@@ -756,7 +743,6 @@ struct r600_blit_cp_primitives {
};
struct r600_blit {
- struct mutex mutex;
struct radeon_bo *shader_obj;
struct r600_blit_cp_primitives primitives;
int max_dim;
@@ -766,8 +752,6 @@ struct r600_blit {
u32 vs_offset, ps_offset;
u32 state_offset;
u32 state_len;
- u32 vb_used, vb_total;
- struct radeon_ib *vb_ib;
};
void r600_blit_suspend(struct radeon_device *rdev);
@@ -785,14 +769,14 @@ struct si_rlc {
};
int radeon_ib_get(struct radeon_device *rdev, int ring,
- struct radeon_ib **ib, unsigned size);
-void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib);
-bool radeon_ib_try_free(struct radeon_device *rdev, struct radeon_ib *ib);
+ struct radeon_ib *ib, unsigned size);
+void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib *ib);
int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib);
int radeon_ib_pool_init(struct radeon_device *rdev);
void radeon_ib_pool_fini(struct radeon_device *rdev);
int radeon_ib_pool_start(struct radeon_device *rdev);
int radeon_ib_pool_suspend(struct radeon_device *rdev);
+int radeon_ib_ring_tests(struct radeon_device *rdev);
/* Ring access between begin & end cannot sleep */
int radeon_ring_index(struct radeon_device *rdev, struct radeon_ring *cp);
void radeon_ring_free_size(struct radeon_device *rdev, struct radeon_ring *cp);
@@ -800,8 +784,12 @@ int radeon_ring_alloc(struct radeon_device *rdev, struct radeon_ring *cp, unsign
int radeon_ring_lock(struct radeon_device *rdev, struct radeon_ring *cp, unsigned ndw);
void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *cp);
void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *cp);
+void radeon_ring_undo(struct radeon_ring *ring);
void radeon_ring_unlock_undo(struct radeon_device *rdev, struct radeon_ring *cp);
int radeon_ring_test(struct radeon_device *rdev, struct radeon_ring *cp);
+void radeon_ring_force_activity(struct radeon_device *rdev, struct radeon_ring *ring);
+void radeon_ring_lockup_update(struct radeon_ring *ring);
+bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *ring);
int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *cp, unsigned ring_size,
unsigned rptr_offs, unsigned rptr_reg, unsigned wptr_reg,
u32 ptr_reg_shift, u32 ptr_reg_mask, u32 nop);
@@ -850,8 +838,8 @@ struct radeon_cs_parser {
int chunk_relocs_idx;
int chunk_flags_idx;
int chunk_const_ib_idx;
- struct radeon_ib *ib;
- struct radeon_ib *const_ib;
+ struct radeon_ib ib;
+ struct radeon_ib const_ib;
void *track;
unsigned family;
int parser_error;
@@ -1105,6 +1093,14 @@ int radeon_pm_get_type_index(struct radeon_device *rdev,
enum radeon_pm_state_type ps_type,
int instance);
+struct r600_audio {
+ int channels;
+ int rate;
+ int bits_per_sample;
+ u8 status_bits;
+ u8 category_code;
+};
+
/*
* Benchmarking
*/
@@ -1144,7 +1140,6 @@ struct radeon_asic {
int (*resume)(struct radeon_device *rdev);
int (*suspend)(struct radeon_device *rdev);
void (*vga_set_state)(struct radeon_device *rdev, bool state);
- bool (*gpu_is_lockup)(struct radeon_device *rdev, struct radeon_ring *cp);
int (*asic_reset)(struct radeon_device *rdev);
/* ioctl hw specific callback. Some hw might want to perform special
* operation on specific ioctl. For instance on wait idle some hw
@@ -1173,6 +1168,7 @@ struct radeon_asic {
void (*ring_start)(struct radeon_device *rdev, struct radeon_ring *cp);
int (*ring_test)(struct radeon_device *rdev, struct radeon_ring *cp);
int (*ib_test)(struct radeon_device *rdev, struct radeon_ring *cp);
+ bool (*is_lockup)(struct radeon_device *rdev, struct radeon_ring *cp);
} ring[RADEON_NUM_RINGS];
/* irqs */
struct {
@@ -1251,16 +1247,10 @@ struct radeon_asic {
/*
* Asic structures
*/
-struct r100_gpu_lockup {
- unsigned long last_jiffies;
- u32 last_cp_rptr;
-};
-
struct r100_asic {
const unsigned *reg_safe_bm;
unsigned reg_safe_bm_size;
u32 hdp_cntl;
- struct r100_gpu_lockup lockup;
};
struct r300_asic {
@@ -1268,7 +1258,6 @@ struct r300_asic {
unsigned reg_safe_bm_size;
u32 resync_scratch;
u32 hdp_cntl;
- struct r100_gpu_lockup lockup;
};
struct r600_asic {
@@ -1290,7 +1279,6 @@ struct r600_asic {
unsigned tiling_group_size;
unsigned tile_config;
unsigned backend_map;
- struct r100_gpu_lockup lockup;
};
struct rv770_asic {
@@ -1316,7 +1304,6 @@ struct rv770_asic {
unsigned tiling_group_size;
unsigned tile_config;
unsigned backend_map;
- struct r100_gpu_lockup lockup;
};
struct evergreen_asic {
@@ -1343,7 +1330,6 @@ struct evergreen_asic {
unsigned tiling_group_size;
unsigned tile_config;
unsigned backend_map;
- struct r100_gpu_lockup lockup;
};
struct cayman_asic {
@@ -1382,7 +1368,6 @@ struct cayman_asic {
unsigned multi_gpu_tile_size;
unsigned tile_config;
- struct r100_gpu_lockup lockup;
};
struct si_asic {
@@ -1413,7 +1398,6 @@ struct si_asic {
unsigned multi_gpu_tile_size;
unsigned tile_config;
- struct r100_gpu_lockup lockup;
};
union radeon_asic_config {
@@ -1516,11 +1500,12 @@ struct radeon_device {
struct radeon_mode_info mode_info;
struct radeon_scratch scratch;
struct radeon_mman mman;
- rwlock_t fence_lock;
struct radeon_fence_driver fence_drv[RADEON_NUM_RINGS];
- struct radeon_semaphore_driver semaphore_drv;
+ wait_queue_head_t fence_queue;
+ struct mutex ring_lock;
struct radeon_ring ring[RADEON_NUM_RINGS];
- struct radeon_ib_pool ib_pool;
+ bool ib_pool_ready;
+ struct radeon_sa_manager ring_tmp_bo;
struct radeon_irq irq;
struct radeon_asic *asic;
struct radeon_gem gem;
@@ -1529,7 +1514,6 @@ struct radeon_device {
struct radeon_mutex cs_mutex;
struct radeon_wb wb;
struct radeon_dummy_page dummy_page;
- bool gpu_lockup;
bool shutdown;
bool suspend;
bool need_dma32;
@@ -1546,19 +1530,12 @@ struct radeon_device {
struct r600_ih ih; /* r6/700 interrupt ring */
struct si_rlc rlc;
struct work_struct hotplug_work;
+ struct work_struct audio_work;
int num_crtc; /* number of crtcs */
struct mutex dc_hw_i2c_mutex; /* display controller hw i2c mutex */
struct mutex vram_mutex;
-
- /* audio stuff */
- bool audio_enabled;
- struct timer_list audio_timer;
- int audio_channels;
- int audio_rate;
- int audio_bits_per_sample;
- uint8_t audio_status_bits;
- uint8_t audio_category_code;
-
+ bool audio_enabled;
+ struct r600_audio audio_status; /* audio stuff */
struct notifier_block acpi_nb;
/* only one userspace can use Hyperz features or CMASK at a time */
struct drm_file *hyperz_filp;
@@ -1730,7 +1707,6 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
#define radeon_suspend(rdev) (rdev)->asic->suspend((rdev))
#define radeon_cs_parse(rdev, r, p) (rdev)->asic->ring[(r)].cs_parse((p))
#define radeon_vga_set_state(rdev, state) (rdev)->asic->vga_set_state((rdev), (state))
-#define radeon_gpu_is_lockup(rdev, cp) (rdev)->asic->gpu_is_lockup((rdev), (cp))
#define radeon_asic_reset(rdev) (rdev)->asic->asic_reset((rdev))
#define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart.tlb_flush((rdev))
#define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart.set_page((rdev), (i), (p))
@@ -1739,6 +1715,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
#define radeon_ib_test(rdev, r, cp) (rdev)->asic->ring[(r)].ib_test((rdev), (cp))
#define radeon_ring_ib_execute(rdev, r, ib) (rdev)->asic->ring[(r)].ib_execute((rdev), (ib))
#define radeon_ring_ib_parse(rdev, r, ib) (rdev)->asic->ring[(r)].ib_parse((rdev), (ib))
+#define radeon_ring_is_lockup(rdev, r, cp) (rdev)->asic->ring[(r)].is_lockup((rdev), (cp))
#define radeon_irq_set(rdev) (rdev)->asic->irq.set((rdev))
#define radeon_irq_process(rdev) (rdev)->asic->irq.process((rdev))
#define radeon_get_vblank_counter(rdev, crtc) (rdev)->asic->display.get_vblank_counter((rdev), (crtc))
@@ -1828,6 +1805,8 @@ int radeon_vm_bo_rmv(struct radeon_device *rdev,
struct radeon_vm *vm,
struct radeon_bo *bo);
+/* audio */
+void r600_audio_update_hdmi(struct work_struct *work);
/*
* R600 vram scratch functions
@@ -1848,10 +1827,32 @@ int r600_fmt_get_nblocksy(u32 format, u32 h);
/*
* r600 functions used by radeon_encoder.c
*/
+struct radeon_hdmi_acr {
+ u32 clock;
+
+ int n_32khz;
+ int cts_32khz;
+
+ int n_44_1khz;
+ int cts_44_1khz;
+
+ int n_48khz;
+ int cts_48khz;
+
+};
+
+extern struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock);
+
extern void r600_hdmi_enable(struct drm_encoder *encoder);
extern void r600_hdmi_disable(struct drm_encoder *encoder);
extern void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
+/*
+ * evergreen functions used by radeon_encoder.c
+ */
+
+extern void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
+
extern int ni_init_microcode(struct radeon_device *rdev);
extern int ni_mc_load_microcode(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index be4dc2ff0e40..f533df5f7d50 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -134,7 +134,6 @@ static struct radeon_asic r100_asic = {
.suspend = &r100_suspend,
.resume = &r100_resume,
.vga_set_state = &r100_vga_set_state,
- .gpu_is_lockup = &r100_gpu_is_lockup,
.asic_reset = &r100_asic_reset,
.ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle,
@@ -152,6 +151,7 @@ static struct radeon_asic r100_asic = {
.ring_start = &r100_ring_start,
.ring_test = &r100_ring_test,
.ib_test = &r100_ib_test,
+ .is_lockup = &r100_gpu_is_lockup,
}
},
.irq = {
@@ -208,7 +208,6 @@ static struct radeon_asic r200_asic = {
.suspend = &r100_suspend,
.resume = &r100_resume,
.vga_set_state = &r100_vga_set_state,
- .gpu_is_lockup = &r100_gpu_is_lockup,
.asic_reset = &r100_asic_reset,
.ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle,
@@ -226,6 +225,7 @@ static struct radeon_asic r200_asic = {
.ring_start = &r100_ring_start,
.ring_test = &r100_ring_test,
.ib_test = &r100_ib_test,
+ .is_lockup = &r100_gpu_is_lockup,
}
},
.irq = {
@@ -282,7 +282,6 @@ static struct radeon_asic r300_asic = {
.suspend = &r300_suspend,
.resume = &r300_resume,
.vga_set_state = &r100_vga_set_state,
- .gpu_is_lockup = &r300_gpu_is_lockup,
.asic_reset = &r300_asic_reset,
.ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle,
@@ -300,6 +299,7 @@ static struct radeon_asic r300_asic = {
.ring_start = &r300_ring_start,
.ring_test = &r100_ring_test,
.ib_test = &r100_ib_test,
+ .is_lockup = &r100_gpu_is_lockup,
}
},
.irq = {
@@ -356,7 +356,6 @@ static struct radeon_asic r300_asic_pcie = {
.suspend = &r300_suspend,
.resume = &r300_resume,
.vga_set_state = &r100_vga_set_state,
- .gpu_is_lockup = &r300_gpu_is_lockup,
.asic_reset = &r300_asic_reset,
.ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle,
@@ -374,6 +373,7 @@ static struct radeon_asic r300_asic_pcie = {
.ring_start = &r300_ring_start,
.ring_test = &r100_ring_test,
.ib_test = &r100_ib_test,
+ .is_lockup = &r100_gpu_is_lockup,
}
},
.irq = {
@@ -430,7 +430,6 @@ static struct radeon_asic r420_asic = {
.suspend = &r420_suspend,
.resume = &r420_resume,
.vga_set_state = &r100_vga_set_state,
- .gpu_is_lockup = &r300_gpu_is_lockup,
.asic_reset = &r300_asic_reset,
.ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle,
@@ -448,6 +447,7 @@ static struct radeon_asic r420_asic = {
.ring_start = &r300_ring_start,
.ring_test = &r100_ring_test,
.ib_test = &r100_ib_test,
+ .is_lockup = &r100_gpu_is_lockup,
}
},
.irq = {
@@ -504,7 +504,6 @@ static struct radeon_asic rs400_asic = {
.suspend = &rs400_suspend,
.resume = &rs400_resume,
.vga_set_state = &r100_vga_set_state,
- .gpu_is_lockup = &r300_gpu_is_lockup,
.asic_reset = &r300_asic_reset,
.ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle,
@@ -522,6 +521,7 @@ static struct radeon_asic rs400_asic = {
.ring_start = &r300_ring_start,
.ring_test = &r100_ring_test,
.ib_test = &r100_ib_test,
+ .is_lockup = &r100_gpu_is_lockup,
}
},
.irq = {
@@ -578,7 +578,6 @@ static struct radeon_asic rs600_asic = {
.suspend = &rs600_suspend,
.resume = &rs600_resume,
.vga_set_state = &r100_vga_set_state,
- .gpu_is_lockup = &r300_gpu_is_lockup,
.asic_reset = &rs600_asic_reset,
.ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle,
@@ -596,6 +595,7 @@ static struct radeon_asic rs600_asic = {
.ring_start = &r300_ring_start,
.ring_test = &r100_ring_test,
.ib_test = &r100_ib_test,
+ .is_lockup = &r100_gpu_is_lockup,
}
},
.irq = {
@@ -652,7 +652,6 @@ static struct radeon_asic rs690_asic = {
.suspend = &rs690_suspend,
.resume = &rs690_resume,
.vga_set_state = &r100_vga_set_state,
- .gpu_is_lockup = &r300_gpu_is_lockup,
.asic_reset = &rs600_asic_reset,
.ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle,
@@ -670,6 +669,7 @@ static struct radeon_asic rs690_asic = {
.ring_start = &r300_ring_start,
.ring_test = &r100_ring_test,
.ib_test = &r100_ib_test,
+ .is_lockup = &r100_gpu_is_lockup,
}
},
.irq = {
@@ -726,7 +726,6 @@ static struct radeon_asic rv515_asic = {
.suspend = &rv515_suspend,
.resume = &rv515_resume,
.vga_set_state = &r100_vga_set_state,
- .gpu_is_lockup = &r300_gpu_is_lockup,
.asic_reset = &rs600_asic_reset,
.ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle,
@@ -744,6 +743,7 @@ static struct radeon_asic rv515_asic = {
.ring_start = &rv515_ring_start,
.ring_test = &r100_ring_test,
.ib_test = &r100_ib_test,
+ .is_lockup = &r100_gpu_is_lockup,
}
},
.irq = {
@@ -800,7 +800,6 @@ static struct radeon_asic r520_asic = {
.suspend = &rv515_suspend,
.resume = &r520_resume,
.vga_set_state = &r100_vga_set_state,
- .gpu_is_lockup = &r300_gpu_is_lockup,
.asic_reset = &rs600_asic_reset,
.ioctl_wait_idle = NULL,
.gui_idle = &r100_gui_idle,
@@ -818,6 +817,7 @@ static struct radeon_asic r520_asic = {
.ring_start = &rv515_ring_start,
.ring_test = &r100_ring_test,
.ib_test = &r100_ib_test,
+ .is_lockup = &r100_gpu_is_lockup,
}
},
.irq = {
@@ -874,7 +874,6 @@ static struct radeon_asic r600_asic = {
.suspend = &r600_suspend,
.resume = &r600_resume,
.vga_set_state = &r600_vga_set_state,
- .gpu_is_lockup = &r600_gpu_is_lockup,
.asic_reset = &r600_asic_reset,
.ioctl_wait_idle = r600_ioctl_wait_idle,
.gui_idle = &r600_gui_idle,
@@ -891,6 +890,7 @@ static struct radeon_asic r600_asic = {
.cs_parse = &r600_cs_parse,
.ring_test = &r600_ring_test,
.ib_test = &r600_ib_test,
+ .is_lockup = &r600_gpu_is_lockup,
}
},
.irq = {
@@ -946,7 +946,6 @@ static struct radeon_asic rs780_asic = {
.fini = &r600_fini,
.suspend = &r600_suspend,
.resume = &r600_resume,
- .gpu_is_lockup = &r600_gpu_is_lockup,
.vga_set_state = &r600_vga_set_state,
.asic_reset = &r600_asic_reset,
.ioctl_wait_idle = r600_ioctl_wait_idle,
@@ -964,6 +963,7 @@ static struct radeon_asic rs780_asic = {
.cs_parse = &r600_cs_parse,
.ring_test = &r600_ring_test,
.ib_test = &r600_ib_test,
+ .is_lockup = &r600_gpu_is_lockup,
}
},
.irq = {
@@ -1020,7 +1020,6 @@ static struct radeon_asic rv770_asic = {
.suspend = &rv770_suspend,
.resume = &rv770_resume,
.asic_reset = &r600_asic_reset,
- .gpu_is_lockup = &r600_gpu_is_lockup,
.vga_set_state = &r600_vga_set_state,
.ioctl_wait_idle = r600_ioctl_wait_idle,
.gui_idle = &r600_gui_idle,
@@ -1037,6 +1036,7 @@ static struct radeon_asic rv770_asic = {
.cs_parse = &r600_cs_parse,
.ring_test = &r600_ring_test,
.ib_test = &r600_ib_test,
+ .is_lockup = &r600_gpu_is_lockup,
}
},
.irq = {
@@ -1092,7 +1092,6 @@ static struct radeon_asic evergreen_asic = {
.fini = &evergreen_fini,
.suspend = &evergreen_suspend,
.resume = &evergreen_resume,
- .gpu_is_lockup = &evergreen_gpu_is_lockup,
.asic_reset = &evergreen_asic_reset,
.vga_set_state = &r600_vga_set_state,
.ioctl_wait_idle = r600_ioctl_wait_idle,
@@ -1110,6 +1109,7 @@ static struct radeon_asic evergreen_asic = {
.cs_parse = &evergreen_cs_parse,
.ring_test = &r600_ring_test,
.ib_test = &r600_ib_test,
+ .is_lockup = &evergreen_gpu_is_lockup,
}
},
.irq = {
@@ -1165,7 +1165,6 @@ static struct radeon_asic sumo_asic = {
.fini = &evergreen_fini,
.suspend = &evergreen_suspend,
.resume = &evergreen_resume,
- .gpu_is_lockup = &evergreen_gpu_is_lockup,
.asic_reset = &evergreen_asic_reset,
.vga_set_state = &r600_vga_set_state,
.ioctl_wait_idle = r600_ioctl_wait_idle,
@@ -1183,6 +1182,7 @@ static struct radeon_asic sumo_asic = {
.cs_parse = &evergreen_cs_parse,
.ring_test = &r600_ring_test,
.ib_test = &r600_ib_test,
+ .is_lockup = &evergreen_gpu_is_lockup,
},
},
.irq = {
@@ -1238,7 +1238,6 @@ static struct radeon_asic btc_asic = {
.fini = &evergreen_fini,
.suspend = &evergreen_suspend,
.resume = &evergreen_resume,
- .gpu_is_lockup = &evergreen_gpu_is_lockup,
.asic_reset = &evergreen_asic_reset,
.vga_set_state = &r600_vga_set_state,
.ioctl_wait_idle = r600_ioctl_wait_idle,
@@ -1256,6 +1255,7 @@ static struct radeon_asic btc_asic = {
.cs_parse = &evergreen_cs_parse,
.ring_test = &r600_ring_test,
.ib_test = &r600_ib_test,
+ .is_lockup = &evergreen_gpu_is_lockup,
}
},
.irq = {
@@ -1321,7 +1321,6 @@ static struct radeon_asic cayman_asic = {
.fini = &cayman_fini,
.suspend = &cayman_suspend,
.resume = &cayman_resume,
- .gpu_is_lockup = &cayman_gpu_is_lockup,
.asic_reset = &cayman_asic_reset,
.vga_set_state = &r600_vga_set_state,
.ioctl_wait_idle = r600_ioctl_wait_idle,
@@ -1340,6 +1339,7 @@ static struct radeon_asic cayman_asic = {
.cs_parse = &evergreen_cs_parse,
.ring_test = &r600_ring_test,
.ib_test = &r600_ib_test,
+ .is_lockup = &evergreen_gpu_is_lockup,
},
[CAYMAN_RING_TYPE_CP1_INDEX] = {
.ib_execute = &cayman_ring_ib_execute,
@@ -1349,6 +1349,7 @@ static struct radeon_asic cayman_asic = {
.cs_parse = &evergreen_cs_parse,
.ring_test = &r600_ring_test,
.ib_test = &r600_ib_test,
+ .is_lockup = &evergreen_gpu_is_lockup,
},
[CAYMAN_RING_TYPE_CP2_INDEX] = {
.ib_execute = &cayman_ring_ib_execute,
@@ -1358,6 +1359,7 @@ static struct radeon_asic cayman_asic = {
.cs_parse = &evergreen_cs_parse,
.ring_test = &r600_ring_test,
.ib_test = &r600_ib_test,
+ .is_lockup = &evergreen_gpu_is_lockup,
}
},
.irq = {
@@ -1413,7 +1415,6 @@ static struct radeon_asic trinity_asic = {
.fini = &cayman_fini,
.suspend = &cayman_suspend,
.resume = &cayman_resume,
- .gpu_is_lockup = &cayman_gpu_is_lockup,
.asic_reset = &cayman_asic_reset,
.vga_set_state = &r600_vga_set_state,
.ioctl_wait_idle = r600_ioctl_wait_idle,
@@ -1432,6 +1433,7 @@ static struct radeon_asic trinity_asic = {
.cs_parse = &evergreen_cs_parse,
.ring_test = &r600_ring_test,
.ib_test = &r600_ib_test,
+ .is_lockup = &evergreen_gpu_is_lockup,
},
[CAYMAN_RING_TYPE_CP1_INDEX] = {
.ib_execute = &cayman_ring_ib_execute,
@@ -1441,6 +1443,7 @@ static struct radeon_asic trinity_asic = {
.cs_parse = &evergreen_cs_parse,
.ring_test = &r600_ring_test,
.ib_test = &r600_ib_test,
+ .is_lockup = &evergreen_gpu_is_lockup,
},
[CAYMAN_RING_TYPE_CP2_INDEX] = {
.ib_execute = &cayman_ring_ib_execute,
@@ -1450,6 +1453,7 @@ static struct radeon_asic trinity_asic = {
.cs_parse = &evergreen_cs_parse,
.ring_test = &r600_ring_test,
.ib_test = &r600_ib_test,
+ .is_lockup = &evergreen_gpu_is_lockup,
}
},
.irq = {
@@ -1515,7 +1519,6 @@ static struct radeon_asic si_asic = {
.fini = &si_fini,
.suspend = &si_suspend,
.resume = &si_resume,
- .gpu_is_lockup = &si_gpu_is_lockup,
.asic_reset = &si_asic_reset,
.vga_set_state = &r600_vga_set_state,
.ioctl_wait_idle = r600_ioctl_wait_idle,
@@ -1534,6 +1537,7 @@ static struct radeon_asic si_asic = {
.cs_parse = NULL,
.ring_test = &r600_ring_test,
.ib_test = &r600_ib_test,
+ .is_lockup = &si_gpu_is_lockup,
},
[CAYMAN_RING_TYPE_CP1_INDEX] = {
.ib_execute = &si_ring_ib_execute,
@@ -1543,6 +1547,7 @@ static struct radeon_asic si_asic = {
.cs_parse = NULL,
.ring_test = &r600_ring_test,
.ib_test = &r600_ib_test,
+ .is_lockup = &si_gpu_is_lockup,
},
[CAYMAN_RING_TYPE_CP2_INDEX] = {
.ib_execute = &si_ring_ib_execute,
@@ -1552,6 +1557,7 @@ static struct radeon_asic si_asic = {
.cs_parse = NULL,
.ring_test = &r600_ring_test,
.ib_test = &r600_ib_test,
+ .is_lockup = &si_gpu_is_lockup,
}
},
.irq = {
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 3d9f9f1d8f90..e76a941ef14e 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -103,11 +103,6 @@ int r100_pci_gart_enable(struct radeon_device *rdev);
void r100_pci_gart_disable(struct radeon_device *rdev);
int r100_debugfs_mc_info_init(struct radeon_device *rdev);
int r100_gui_wait_for_idle(struct radeon_device *rdev);
-void r100_gpu_lockup_update(struct r100_gpu_lockup *lockup,
- struct radeon_ring *cp);
-bool r100_gpu_cp_is_lockup(struct radeon_device *rdev,
- struct r100_gpu_lockup *lockup,
- struct radeon_ring *cp);
void r100_ib_fini(struct radeon_device *rdev);
int r100_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
void r100_irq_disable(struct radeon_device *rdev);
@@ -159,7 +154,6 @@ extern int r300_init(struct radeon_device *rdev);
extern void r300_fini(struct radeon_device *rdev);
extern int r300_suspend(struct radeon_device *rdev);
extern int r300_resume(struct radeon_device *rdev);
-extern bool r300_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp);
extern int r300_asic_reset(struct radeon_device *rdev);
extern void r300_ring_start(struct radeon_device *rdev, struct radeon_ring *ring);
extern void r300_fence_ring_emit(struct radeon_device *rdev,
@@ -362,26 +356,20 @@ void r600_disable_interrupts(struct radeon_device *rdev);
void r600_rlc_stop(struct radeon_device *rdev);
/* r600 audio */
int r600_audio_init(struct radeon_device *rdev);
-int r600_audio_tmds_index(struct drm_encoder *encoder);
void r600_audio_set_clock(struct drm_encoder *encoder, int clock);
-int r600_audio_channels(struct radeon_device *rdev);
-int r600_audio_bits_per_sample(struct radeon_device *rdev);
-int r600_audio_rate(struct radeon_device *rdev);
-uint8_t r600_audio_status_bits(struct radeon_device *rdev);
-uint8_t r600_audio_category_code(struct radeon_device *rdev);
-void r600_audio_schedule_polling(struct radeon_device *rdev);
-void r600_audio_enable_polling(struct drm_encoder *encoder);
-void r600_audio_disable_polling(struct drm_encoder *encoder);
+struct r600_audio r600_audio_status(struct radeon_device *rdev);
void r600_audio_fini(struct radeon_device *rdev);
-void r600_hdmi_init(struct drm_encoder *encoder);
int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder);
void r600_hdmi_update_audio_settings(struct drm_encoder *encoder);
/* r600 blit */
-int r600_blit_prepare_copy(struct radeon_device *rdev, unsigned num_gpu_pages);
-void r600_blit_done_copy(struct radeon_device *rdev, struct radeon_fence *fence);
+int r600_blit_prepare_copy(struct radeon_device *rdev, unsigned num_gpu_pages,
+ struct radeon_sa_bo **vb);
+void r600_blit_done_copy(struct radeon_device *rdev, struct radeon_fence *fence,
+ struct radeon_sa_bo *vb);
void r600_kms_blit_copy(struct radeon_device *rdev,
u64 src_gpu_addr, u64 dst_gpu_addr,
- unsigned num_gpu_pages);
+ unsigned num_gpu_pages,
+ struct radeon_sa_bo *vb);
int r600_mc_wait_for_idle(struct radeon_device *rdev);
/*
@@ -446,7 +434,6 @@ int cayman_init(struct radeon_device *rdev);
void cayman_fini(struct radeon_device *rdev);
int cayman_suspend(struct radeon_device *rdev);
int cayman_resume(struct radeon_device *rdev);
-bool cayman_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp);
int cayman_asic_reset(struct radeon_device *rdev);
void cayman_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
int cayman_vm_init(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_benchmark.c b/drivers/gpu/drm/radeon/radeon_benchmark.c
index fef7b722b05d..364f5b1a04b9 100644
--- a/drivers/gpu/drm/radeon/radeon_benchmark.c
+++ b/drivers/gpu/drm/radeon/radeon_benchmark.c
@@ -103,7 +103,7 @@ static void radeon_benchmark_move(struct radeon_device *rdev, unsigned size,
int time;
n = RADEON_BENCHMARK_ITERATIONS;
- r = radeon_bo_create(rdev, size, PAGE_SIZE, true, sdomain, &sobj);
+ r = radeon_bo_create(rdev, size, PAGE_SIZE, true, sdomain, NULL, &sobj);
if (r) {
goto out_cleanup;
}
@@ -115,7 +115,7 @@ static void radeon_benchmark_move(struct radeon_device *rdev, unsigned size,
if (r) {
goto out_cleanup;
}
- r = radeon_bo_create(rdev, size, PAGE_SIZE, true, ddomain, &dobj);
+ r = radeon_bo_create(rdev, size, PAGE_SIZE, true, ddomain, NULL, &dobj);
if (r) {
goto out_cleanup;
}
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c
index 2cad9fde92fc..576f4f6919f2 100644
--- a/drivers/gpu/drm/radeon/radeon_combios.c
+++ b/drivers/gpu/drm/radeon/radeon_combios.c
@@ -1561,6 +1561,11 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
(rdev->pdev->subsystem_device == 0x4150)) {
/* Mac G5 tower 9600 */
rdev->mode_info.connector_table = CT_MAC_G5_9600;
+ } else if ((rdev->pdev->device == 0x4c66) &&
+ (rdev->pdev->subsystem_vendor == 0x1002) &&
+ (rdev->pdev->subsystem_device == 0x4c66)) {
+ /* SAM440ep RV250 embedded board */
+ rdev->mode_info.connector_table = CT_SAM440EP;
} else
#endif /* CONFIG_PPC_PMAC */
#ifdef CONFIG_PPC64
@@ -2134,6 +2139,67 @@ bool radeon_get_legacy_connector_info_from_table(struct drm_device *dev)
CONNECTOR_OBJECT_ID_SVIDEO,
&hpd);
break;
+ case CT_SAM440EP:
+ DRM_INFO("Connector Table: %d (SAM440ep embedded board)\n",
+ rdev->mode_info.connector_table);
+ /* LVDS */
+ ddc_i2c = combios_setup_i2c_bus(rdev, DDC_NONE_DETECTED, 0, 0);
+ hpd.hpd = RADEON_HPD_NONE;
+ radeon_add_legacy_encoder(dev,
+ radeon_get_encoder_enum(dev,
+ ATOM_DEVICE_LCD1_SUPPORT,
+ 0),
+ ATOM_DEVICE_LCD1_SUPPORT);
+ radeon_add_legacy_connector(dev, 0, ATOM_DEVICE_LCD1_SUPPORT,
+ DRM_MODE_CONNECTOR_LVDS, &ddc_i2c,
+ CONNECTOR_OBJECT_ID_LVDS,
+ &hpd);
+ /* DVI-I - secondary dac, int tmds */
+ ddc_i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
+ hpd.hpd = RADEON_HPD_1; /* ??? */
+ radeon_add_legacy_encoder(dev,
+ radeon_get_encoder_enum(dev,
+ ATOM_DEVICE_DFP1_SUPPORT,
+ 0),
+ ATOM_DEVICE_DFP1_SUPPORT);
+ radeon_add_legacy_encoder(dev,
+ radeon_get_encoder_enum(dev,
+ ATOM_DEVICE_CRT2_SUPPORT,
+ 2),
+ ATOM_DEVICE_CRT2_SUPPORT);
+ radeon_add_legacy_connector(dev, 1,
+ ATOM_DEVICE_DFP1_SUPPORT |
+ ATOM_DEVICE_CRT2_SUPPORT,
+ DRM_MODE_CONNECTOR_DVII, &ddc_i2c,
+ CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I,
+ &hpd);
+ /* VGA - primary dac */
+ ddc_i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
+ hpd.hpd = RADEON_HPD_NONE;
+ radeon_add_legacy_encoder(dev,
+ radeon_get_encoder_enum(dev,
+ ATOM_DEVICE_CRT1_SUPPORT,
+ 1),
+ ATOM_DEVICE_CRT1_SUPPORT);
+ radeon_add_legacy_connector(dev, 2,
+ ATOM_DEVICE_CRT1_SUPPORT,
+ DRM_MODE_CONNECTOR_VGA, &ddc_i2c,
+ CONNECTOR_OBJECT_ID_VGA,
+ &hpd);
+ /* TV - TV DAC */
+ ddc_i2c.valid = false;
+ hpd.hpd = RADEON_HPD_NONE;
+ radeon_add_legacy_encoder(dev,
+ radeon_get_encoder_enum(dev,
+ ATOM_DEVICE_TV1_SUPPORT,
+ 2),
+ ATOM_DEVICE_TV1_SUPPORT);
+ radeon_add_legacy_connector(dev, 3, ATOM_DEVICE_TV1_SUPPORT,
+ DRM_MODE_CONNECTOR_SVIDEO,
+ &ddc_i2c,
+ CONNECTOR_OBJECT_ID_SVIDEO,
+ &hpd);
+ break;
default:
DRM_INFO("Connector table: %d (invalid)\n",
rdev->mode_info.connector_table);
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 3c2e7a000a2a..2914c5761cfc 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -84,6 +84,62 @@ static void radeon_property_change_mode(struct drm_encoder *encoder)
crtc->x, crtc->y, crtc->fb);
}
}
+
+int radeon_get_monitor_bpc(struct drm_connector *connector)
+{
+ struct drm_device *dev = connector->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+ struct radeon_connector_atom_dig *dig_connector;
+ int bpc = 8;
+
+ switch (connector->connector_type) {
+ case DRM_MODE_CONNECTOR_DVII:
+ case DRM_MODE_CONNECTOR_HDMIB:
+ if (radeon_connector->use_digital) {
+ if (drm_detect_hdmi_monitor(radeon_connector->edid)) {
+ if (connector->display_info.bpc)
+ bpc = connector->display_info.bpc;
+ }
+ }
+ break;
+ case DRM_MODE_CONNECTOR_DVID:
+ case DRM_MODE_CONNECTOR_HDMIA:
+ if (drm_detect_hdmi_monitor(radeon_connector->edid)) {
+ if (connector->display_info.bpc)
+ bpc = connector->display_info.bpc;
+ }
+ break;
+ case DRM_MODE_CONNECTOR_DisplayPort:
+ dig_connector = radeon_connector->con_priv;
+ if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
+ (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) ||
+ drm_detect_hdmi_monitor(radeon_connector->edid)) {
+ if (connector->display_info.bpc)
+ bpc = connector->display_info.bpc;
+ }
+ break;
+ case DRM_MODE_CONNECTOR_eDP:
+ case DRM_MODE_CONNECTOR_LVDS:
+ if (connector->display_info.bpc)
+ bpc = connector->display_info.bpc;
+ else if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE5(rdev)) {
+ struct drm_connector_helper_funcs *connector_funcs =
+ connector->helper_private;
+ struct drm_encoder *encoder = connector_funcs->best_encoder(connector);
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+
+ if (dig->lcd_misc & ATOM_PANEL_MISC_V13_6BIT_PER_COLOR)
+ bpc = 6;
+ else if (dig->lcd_misc & ATOM_PANEL_MISC_V13_8BIT_PER_COLOR)
+ bpc = 8;
+ }
+ break;
+ }
+ return bpc;
+}
+
static void
radeon_connector_update_scratch_regs(struct drm_connector *connector, enum drm_connector_status status)
{
diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c
index 0ebb7d4796fa..ef67e181377b 100644
--- a/drivers/gpu/drm/radeon/radeon_cp.c
+++ b/drivers/gpu/drm/radeon/radeon_cp.c
@@ -1827,14 +1827,10 @@ void radeon_do_release(struct drm_device * dev)
r600_do_cleanup_cp(dev);
else
radeon_do_cleanup_cp(dev);
- if (dev_priv->me_fw) {
- release_firmware(dev_priv->me_fw);
- dev_priv->me_fw = NULL;
- }
- if (dev_priv->pfp_fw) {
- release_firmware(dev_priv->pfp_fw);
- dev_priv->pfp_fw = NULL;
- }
+ release_firmware(dev_priv->me_fw);
+ dev_priv->me_fw = NULL;
+ release_firmware(dev_priv->pfp_fw);
+ dev_priv->pfp_fw = NULL;
}
}
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c
index 5cac83278338..c7d64a739033 100644
--- a/drivers/gpu/drm/radeon/radeon_cs.c
+++ b/drivers/gpu/drm/radeon/radeon_cs.c
@@ -118,44 +118,33 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority
static int radeon_cs_sync_rings(struct radeon_cs_parser *p)
{
bool sync_to_ring[RADEON_NUM_RINGS] = { };
+ bool need_sync = false;
int i, r;
for (i = 0; i < p->nrelocs; i++) {
+ struct radeon_fence *fence;
+
if (!p->relocs[i].robj || !p->relocs[i].robj->tbo.sync_obj)
continue;
- if (!(p->relocs[i].flags & RADEON_RELOC_DONT_SYNC)) {
- struct radeon_fence *fence = p->relocs[i].robj->tbo.sync_obj;
- if (!radeon_fence_signaled(fence)) {
- sync_to_ring[fence->ring] = true;
- }
+ fence = p->relocs[i].robj->tbo.sync_obj;
+ if (fence->ring != p->ring && !radeon_fence_signaled(fence)) {
+ sync_to_ring[fence->ring] = true;
+ need_sync = true;
}
}
- for (i = 0; i < RADEON_NUM_RINGS; ++i) {
- /* no need to sync to our own or unused rings */
- if (i == p->ring || !sync_to_ring[i] || !p->rdev->ring[i].ready)
- continue;
-
- if (!p->ib->fence->semaphore) {
- r = radeon_semaphore_create(p->rdev, &p->ib->fence->semaphore);
- if (r)
- return r;
- }
-
- r = radeon_ring_lock(p->rdev, &p->rdev->ring[i], 3);
- if (r)
- return r;
- radeon_semaphore_emit_signal(p->rdev, i, p->ib->fence->semaphore);
- radeon_ring_unlock_commit(p->rdev, &p->rdev->ring[i]);
+ if (!need_sync) {
+ return 0;
+ }
- r = radeon_ring_lock(p->rdev, &p->rdev->ring[p->ring], 3);
- if (r)
- return r;
- radeon_semaphore_emit_wait(p->rdev, p->ring, p->ib->fence->semaphore);
- radeon_ring_unlock_commit(p->rdev, &p->rdev->ring[p->ring]);
+ r = radeon_semaphore_create(p->rdev, &p->ib.semaphore);
+ if (r) {
+ return r;
}
- return 0;
+
+ return radeon_semaphore_sync_rings(p->rdev, p->ib.semaphore,
+ sync_to_ring, p->ring);
}
int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
@@ -172,6 +161,10 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
/* get chunks */
INIT_LIST_HEAD(&p->validated);
p->idx = 0;
+ p->ib.sa_bo = NULL;
+ p->ib.semaphore = NULL;
+ p->const_ib.sa_bo = NULL;
+ p->const_ib.semaphore = NULL;
p->chunk_ib_idx = -1;
p->chunk_relocs_idx = -1;
p->chunk_flags_idx = -1;
@@ -278,11 +271,16 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
p->chunks[p->chunk_ib_idx].length_dw);
return -EINVAL;
}
- p->chunks[p->chunk_ib_idx].kpage[0] = kmalloc(PAGE_SIZE, GFP_KERNEL);
- p->chunks[p->chunk_ib_idx].kpage[1] = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (p->chunks[p->chunk_ib_idx].kpage[0] == NULL ||
- p->chunks[p->chunk_ib_idx].kpage[1] == NULL)
- return -ENOMEM;
+ if ((p->rdev->flags & RADEON_IS_AGP)) {
+ p->chunks[p->chunk_ib_idx].kpage[0] = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ p->chunks[p->chunk_ib_idx].kpage[1] = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (p->chunks[p->chunk_ib_idx].kpage[0] == NULL ||
+ p->chunks[p->chunk_ib_idx].kpage[1] == NULL) {
+ kfree(p->chunks[i].kpage[0]);
+ kfree(p->chunks[i].kpage[1]);
+ return -ENOMEM;
+ }
+ }
p->chunks[p->chunk_ib_idx].kpage_idx[0] = -1;
p->chunks[p->chunk_ib_idx].kpage_idx[1] = -1;
p->chunks[p->chunk_ib_idx].last_copied_page = -1;
@@ -305,10 +303,9 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error)
{
unsigned i;
-
- if (!error && parser->ib)
+ if (!error)
ttm_eu_fence_buffer_objects(&parser->validated,
- parser->ib->fence);
+ parser->ib.fence);
else
ttm_eu_backoff_reservation(&parser->validated);
@@ -323,12 +320,15 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error)
kfree(parser->relocs_ptr);
for (i = 0; i < parser->nchunks; i++) {
kfree(parser->chunks[i].kdata);
- kfree(parser->chunks[i].kpage[0]);
- kfree(parser->chunks[i].kpage[1]);
+ if ((parser->rdev->flags & RADEON_IS_AGP)) {
+ kfree(parser->chunks[i].kpage[0]);
+ kfree(parser->chunks[i].kpage[1]);
+ }
}
kfree(parser->chunks);
kfree(parser->chunks_array);
radeon_ib_free(parser->rdev, &parser->ib);
+ radeon_ib_free(parser->rdev, &parser->const_ib);
}
static int radeon_cs_ib_chunk(struct radeon_device *rdev,
@@ -354,7 +354,7 @@ static int radeon_cs_ib_chunk(struct radeon_device *rdev,
DRM_ERROR("Failed to get ib !\n");
return r;
}
- parser->ib->length_dw = ib_chunk->length_dw;
+ parser->ib.length_dw = ib_chunk->length_dw;
r = radeon_cs_parse(rdev, parser->ring, parser);
if (r || parser->parser_error) {
DRM_ERROR("Invalid command stream !\n");
@@ -369,8 +369,8 @@ static int radeon_cs_ib_chunk(struct radeon_device *rdev,
if (r) {
DRM_ERROR("Failed to synchronize rings !\n");
}
- parser->ib->vm_id = 0;
- r = radeon_ib_schedule(rdev, parser->ib);
+ parser->ib.vm_id = 0;
+ r = radeon_ib_schedule(rdev, &parser->ib);
if (r) {
DRM_ERROR("Failed to schedule IB !\n");
}
@@ -421,14 +421,14 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,
DRM_ERROR("Failed to get const ib !\n");
return r;
}
- parser->const_ib->is_const_ib = true;
- parser->const_ib->length_dw = ib_chunk->length_dw;
+ parser->const_ib.is_const_ib = true;
+ parser->const_ib.length_dw = ib_chunk->length_dw;
/* Copy the packet into the IB */
- if (DRM_COPY_FROM_USER(parser->const_ib->ptr, ib_chunk->user_ptr,
+ if (DRM_COPY_FROM_USER(parser->const_ib.ptr, ib_chunk->user_ptr,
ib_chunk->length_dw * 4)) {
return -EFAULT;
}
- r = radeon_ring_ib_parse(rdev, parser->ring, parser->const_ib);
+ r = radeon_ring_ib_parse(rdev, parser->ring, &parser->const_ib);
if (r) {
return r;
}
@@ -445,13 +445,13 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,
DRM_ERROR("Failed to get ib !\n");
return r;
}
- parser->ib->length_dw = ib_chunk->length_dw;
+ parser->ib.length_dw = ib_chunk->length_dw;
/* Copy the packet into the IB */
- if (DRM_COPY_FROM_USER(parser->ib->ptr, ib_chunk->user_ptr,
+ if (DRM_COPY_FROM_USER(parser->ib.ptr, ib_chunk->user_ptr,
ib_chunk->length_dw * 4)) {
return -EFAULT;
}
- r = radeon_ring_ib_parse(rdev, parser->ring, parser->ib);
+ r = radeon_ring_ib_parse(rdev, parser->ring, &parser->ib);
if (r) {
return r;
}
@@ -472,34 +472,44 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,
if ((rdev->family >= CHIP_TAHITI) &&
(parser->chunk_const_ib_idx != -1)) {
- parser->const_ib->vm_id = vm->id;
+ parser->const_ib.vm_id = vm->id;
/* ib pool is bind at 0 in virtual address space to gpu_addr is the
* offset inside the pool bo
*/
- parser->const_ib->gpu_addr = parser->const_ib->sa_bo.offset;
- r = radeon_ib_schedule(rdev, parser->const_ib);
+ parser->const_ib.gpu_addr = parser->const_ib.sa_bo->soffset;
+ r = radeon_ib_schedule(rdev, &parser->const_ib);
if (r)
goto out;
}
- parser->ib->vm_id = vm->id;
+ parser->ib.vm_id = vm->id;
/* ib pool is bind at 0 in virtual address space to gpu_addr is the
* offset inside the pool bo
*/
- parser->ib->gpu_addr = parser->ib->sa_bo.offset;
- parser->ib->is_const_ib = false;
- r = radeon_ib_schedule(rdev, parser->ib);
+ parser->ib.gpu_addr = parser->ib.sa_bo->soffset;
+ parser->ib.is_const_ib = false;
+ r = radeon_ib_schedule(rdev, &parser->ib);
out:
if (!r) {
if (vm->fence) {
radeon_fence_unref(&vm->fence);
}
- vm->fence = radeon_fence_ref(parser->ib->fence);
+ vm->fence = radeon_fence_ref(parser->ib.fence);
}
mutex_unlock(&fpriv->vm.mutex);
return r;
}
+static int radeon_cs_handle_lockup(struct radeon_device *rdev, int r)
+{
+ if (r == -EDEADLK) {
+ r = radeon_gpu_reset(rdev);
+ if (!r)
+ r = -EAGAIN;
+ }
+ return r;
+}
+
int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
{
struct radeon_device *rdev = dev->dev_private;
@@ -521,6 +531,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
if (r) {
DRM_ERROR("Failed to initialize parser !\n");
radeon_cs_parser_fini(&parser, r);
+ r = radeon_cs_handle_lockup(rdev, r);
radeon_mutex_unlock(&rdev->cs_mutex);
return r;
}
@@ -529,6 +540,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
if (r != -ERESTARTSYS)
DRM_ERROR("Failed to parse relocation %d!\n", r);
radeon_cs_parser_fini(&parser, r);
+ r = radeon_cs_handle_lockup(rdev, r);
radeon_mutex_unlock(&rdev->cs_mutex);
return r;
}
@@ -542,6 +554,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
}
out:
radeon_cs_parser_fini(&parser, r);
+ r = radeon_cs_handle_lockup(rdev, r);
radeon_mutex_unlock(&rdev->cs_mutex);
return r;
}
@@ -559,7 +572,7 @@ int radeon_cs_finish_pages(struct radeon_cs_parser *p)
size = PAGE_SIZE;
}
- if (DRM_COPY_FROM_USER(p->ib->ptr + (i * (PAGE_SIZE/4)),
+ if (DRM_COPY_FROM_USER(p->ib.ptr + (i * (PAGE_SIZE/4)),
ibc->user_ptr + (i * PAGE_SIZE),
size))
return -EFAULT;
@@ -573,9 +586,10 @@ int radeon_cs_update_pages(struct radeon_cs_parser *p, int pg_idx)
struct radeon_cs_chunk *ibc = &p->chunks[p->chunk_ib_idx];
int i;
int size = PAGE_SIZE;
+ bool copy1 = (p->rdev->flags & RADEON_IS_AGP) ? false : true;
for (i = ibc->last_copied_page + 1; i < pg_idx; i++) {
- if (DRM_COPY_FROM_USER(p->ib->ptr + (i * (PAGE_SIZE/4)),
+ if (DRM_COPY_FROM_USER(p->ib.ptr + (i * (PAGE_SIZE/4)),
ibc->user_ptr + (i * PAGE_SIZE),
PAGE_SIZE)) {
p->parser_error = -EFAULT;
@@ -583,14 +597,16 @@ int radeon_cs_update_pages(struct radeon_cs_parser *p, int pg_idx)
}
}
- new_page = ibc->kpage_idx[0] < ibc->kpage_idx[1] ? 0 : 1;
-
if (pg_idx == ibc->last_page_index) {
size = (ibc->length_dw * 4) % PAGE_SIZE;
- if (size == 0)
- size = PAGE_SIZE;
+ if (size == 0)
+ size = PAGE_SIZE;
}
+ new_page = ibc->kpage_idx[0] < ibc->kpage_idx[1] ? 0 : 1;
+ if (copy1)
+ ibc->kpage[new_page] = p->ib.ptr + (pg_idx * (PAGE_SIZE / 4));
+
if (DRM_COPY_FROM_USER(ibc->kpage[new_page],
ibc->user_ptr + (pg_idx * PAGE_SIZE),
size)) {
@@ -598,8 +614,9 @@ int radeon_cs_update_pages(struct radeon_cs_parser *p, int pg_idx)
return 0;
}
- /* copy to IB here */
- memcpy((void *)(p->ib->ptr+(pg_idx*(PAGE_SIZE/4))), ibc->kpage[new_page], size);
+ /* copy to IB for non single case */
+ if (!copy1)
+ memcpy((void *)(p->ib.ptr+(pg_idx*(PAGE_SIZE/4))), ibc->kpage[new_page], size);
ibc->last_copied_page = pg_idx;
ibc->kpage_idx[new_page] = pg_idx;
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 5992502a3448..066c98b888a5 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -193,7 +193,7 @@ int radeon_wb_init(struct radeon_device *rdev)
if (rdev->wb.wb_obj == NULL) {
r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true,
- RADEON_GEM_DOMAIN_GTT, &rdev->wb.wb_obj);
+ RADEON_GEM_DOMAIN_GTT, NULL, &rdev->wb.wb_obj);
if (r) {
dev_warn(rdev->dev, "(%d) create WB bo failed\n", r);
return r;
@@ -225,9 +225,9 @@ int radeon_wb_init(struct radeon_device *rdev)
/* disable event_write fences */
rdev->wb.use_event = false;
/* disabled via module param */
- if (radeon_no_wb == 1)
+ if (radeon_no_wb == 1) {
rdev->wb.enabled = false;
- else {
+ } else {
if (rdev->flags & RADEON_IS_AGP) {
/* often unreliable on AGP */
rdev->wb.enabled = false;
@@ -237,8 +237,9 @@ int radeon_wb_init(struct radeon_device *rdev)
} else {
rdev->wb.enabled = true;
/* event_write fences are only available on r600+ */
- if (rdev->family >= CHIP_R600)
+ if (rdev->family >= CHIP_R600) {
rdev->wb.use_event = true;
+ }
}
}
/* always use writeback/events on NI, APUs */
@@ -696,6 +697,11 @@ static bool radeon_switcheroo_can_switch(struct pci_dev *pdev)
return can_switch;
}
+static const struct vga_switcheroo_client_ops radeon_switcheroo_ops = {
+ .set_gpu_state = radeon_switcheroo_set_state,
+ .reprobe = NULL,
+ .can_switch = radeon_switcheroo_can_switch,
+};
int radeon_device_init(struct radeon_device *rdev,
struct drm_device *ddev,
@@ -714,7 +720,6 @@ int radeon_device_init(struct radeon_device *rdev,
rdev->is_atom_bios = false;
rdev->usec_timeout = RADEON_MAX_USEC_TIMEOUT;
rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
- rdev->gpu_lockup = false;
rdev->accel_working = false;
DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X).\n",
@@ -724,21 +729,18 @@ int radeon_device_init(struct radeon_device *rdev,
/* mutex initialization are all done here so we
* can recall function without having locking issues */
radeon_mutex_init(&rdev->cs_mutex);
- radeon_mutex_init(&rdev->ib_pool.mutex);
- for (i = 0; i < RADEON_NUM_RINGS; ++i)
- mutex_init(&rdev->ring[i].mutex);
+ mutex_init(&rdev->ring_lock);
mutex_init(&rdev->dc_hw_i2c_mutex);
if (rdev->family >= CHIP_R600)
spin_lock_init(&rdev->ih.lock);
mutex_init(&rdev->gem.mutex);
mutex_init(&rdev->pm.mutex);
mutex_init(&rdev->vram_mutex);
- rwlock_init(&rdev->fence_lock);
- rwlock_init(&rdev->semaphore_drv.lock);
- INIT_LIST_HEAD(&rdev->gem.objects);
init_waitqueue_head(&rdev->irq.vblank_queue);
init_waitqueue_head(&rdev->irq.idle_queue);
- INIT_LIST_HEAD(&rdev->semaphore_drv.bo);
+ r = radeon_gem_init(rdev);
+ if (r)
+ return r;
/* initialize vm here */
rdev->vm_manager.use_bitmap = 1;
rdev->vm_manager.max_pfn = 1 << 20;
@@ -814,10 +816,7 @@ int radeon_device_init(struct radeon_device *rdev,
/* this will fail for cards that aren't VGA class devices, just
* ignore it */
vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode);
- vga_switcheroo_register_client(rdev->pdev,
- radeon_switcheroo_set_state,
- NULL,
- radeon_switcheroo_can_switch);
+ vga_switcheroo_register_client(rdev->pdev, &radeon_switcheroo_ops);
r = radeon_init(rdev);
if (r)
@@ -914,9 +913,12 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
}
/* evict vram memory */
radeon_bo_evict_vram(rdev);
+
+ mutex_lock(&rdev->ring_lock);
/* wait for gpu to finish processing current batch */
for (i = 0; i < RADEON_NUM_RINGS; i++)
- radeon_fence_wait_last(rdev, i);
+ radeon_fence_wait_empty_locked(rdev, i);
+ mutex_unlock(&rdev->ring_lock);
radeon_save_bios_scratch_regs(rdev);
@@ -955,7 +957,6 @@ int radeon_resume_kms(struct drm_device *dev)
console_unlock();
return -1;
}
- pci_set_master(dev->pdev);
/* resume AGP if in use */
radeon_agp_resume(rdev);
radeon_resume(rdev);
@@ -988,9 +989,6 @@ int radeon_gpu_reset(struct radeon_device *rdev)
int r;
int resched;
- /* Prevent CS ioctl from interfering */
- radeon_mutex_lock(&rdev->cs_mutex);
-
radeon_save_bios_scratch_regs(rdev);
/* block TTM */
resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev);
@@ -1005,8 +1003,6 @@ int radeon_gpu_reset(struct radeon_device *rdev)
ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched);
}
- radeon_mutex_unlock(&rdev->cs_mutex);
-
if (r) {
/* bad news, how to tell it to userspace ? */
dev_info(rdev->dev, "GPU reset failed\n");
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 0a1d4bd65edc..64a008d14493 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -573,24 +573,6 @@ static const char *encoder_names[37] = {
"INTERNAL_VCE"
};
-static const char *connector_names[15] = {
- "Unknown",
- "VGA",
- "DVI-I",
- "DVI-D",
- "DVI-A",
- "Composite",
- "S-video",
- "LVDS",
- "Component",
- "DIN",
- "DisplayPort",
- "HDMI-A",
- "HDMI-B",
- "TV",
- "eDP",
-};
-
static const char *hpd_names[6] = {
"HPD1",
"HPD2",
@@ -613,7 +595,7 @@ static void radeon_print_display_setup(struct drm_device *dev)
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
radeon_connector = to_radeon_connector(connector);
DRM_INFO("Connector %d:\n", i);
- DRM_INFO(" %s\n", connector_names[connector->connector_type]);
+ DRM_INFO(" %s\n", drm_get_connector_name(connector));
if (radeon_connector->hpd.hpd != RADEON_HPD_NONE)
DRM_INFO(" %s\n", hpd_names[radeon_connector->hpd.hpd]);
if (radeon_connector->ddc_bus) {
@@ -1243,6 +1225,93 @@ void radeon_update_display_priority(struct radeon_device *rdev)
}
+/*
+ * Allocate hdmi structs and determine register offsets
+ */
+static void radeon_afmt_init(struct radeon_device *rdev)
+{
+ int i;
+
+ for (i = 0; i < RADEON_MAX_AFMT_BLOCKS; i++)
+ rdev->mode_info.afmt[i] = NULL;
+
+ if (ASIC_IS_DCE6(rdev)) {
+ /* todo */
+ } else if (ASIC_IS_DCE4(rdev)) {
+ /* DCE4/5 has 6 audio blocks tied to DIG encoders */
+ /* DCE4.1 has 2 audio blocks tied to DIG encoders */
+ rdev->mode_info.afmt[0] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL);
+ if (rdev->mode_info.afmt[0]) {
+ rdev->mode_info.afmt[0]->offset = EVERGREEN_CRTC0_REGISTER_OFFSET;
+ rdev->mode_info.afmt[0]->id = 0;
+ }
+ rdev->mode_info.afmt[1] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL);
+ if (rdev->mode_info.afmt[1]) {
+ rdev->mode_info.afmt[1]->offset = EVERGREEN_CRTC1_REGISTER_OFFSET;
+ rdev->mode_info.afmt[1]->id = 1;
+ }
+ if (!ASIC_IS_DCE41(rdev)) {
+ rdev->mode_info.afmt[2] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL);
+ if (rdev->mode_info.afmt[2]) {
+ rdev->mode_info.afmt[2]->offset = EVERGREEN_CRTC2_REGISTER_OFFSET;
+ rdev->mode_info.afmt[2]->id = 2;
+ }
+ rdev->mode_info.afmt[3] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL);
+ if (rdev->mode_info.afmt[3]) {
+ rdev->mode_info.afmt[3]->offset = EVERGREEN_CRTC3_REGISTER_OFFSET;
+ rdev->mode_info.afmt[3]->id = 3;
+ }
+ rdev->mode_info.afmt[4] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL);
+ if (rdev->mode_info.afmt[4]) {
+ rdev->mode_info.afmt[4]->offset = EVERGREEN_CRTC4_REGISTER_OFFSET;
+ rdev->mode_info.afmt[4]->id = 4;
+ }
+ rdev->mode_info.afmt[5] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL);
+ if (rdev->mode_info.afmt[5]) {
+ rdev->mode_info.afmt[5]->offset = EVERGREEN_CRTC5_REGISTER_OFFSET;
+ rdev->mode_info.afmt[5]->id = 5;
+ }
+ }
+ } else if (ASIC_IS_DCE3(rdev)) {
+ /* DCE3.x has 2 audio blocks tied to DIG encoders */
+ rdev->mode_info.afmt[0] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL);
+ if (rdev->mode_info.afmt[0]) {
+ rdev->mode_info.afmt[0]->offset = DCE3_HDMI_OFFSET0;
+ rdev->mode_info.afmt[0]->id = 0;
+ }
+ rdev->mode_info.afmt[1] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL);
+ if (rdev->mode_info.afmt[1]) {
+ rdev->mode_info.afmt[1]->offset = DCE3_HDMI_OFFSET1;
+ rdev->mode_info.afmt[1]->id = 1;
+ }
+ } else if (ASIC_IS_DCE2(rdev)) {
+ /* DCE2 has at least 1 routable audio block */
+ rdev->mode_info.afmt[0] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL);
+ if (rdev->mode_info.afmt[0]) {
+ rdev->mode_info.afmt[0]->offset = DCE2_HDMI_OFFSET0;
+ rdev->mode_info.afmt[0]->id = 0;
+ }
+ /* r6xx has 2 routable audio blocks */
+ if (rdev->family >= CHIP_R600) {
+ rdev->mode_info.afmt[1] = kzalloc(sizeof(struct radeon_afmt), GFP_KERNEL);
+ if (rdev->mode_info.afmt[1]) {
+ rdev->mode_info.afmt[1]->offset = DCE2_HDMI_OFFSET1;
+ rdev->mode_info.afmt[1]->id = 1;
+ }
+ }
+ }
+}
+
+static void radeon_afmt_fini(struct radeon_device *rdev)
+{
+ int i;
+
+ for (i = 0; i < RADEON_MAX_AFMT_BLOCKS; i++) {
+ kfree(rdev->mode_info.afmt[i]);
+ rdev->mode_info.afmt[i] = NULL;
+ }
+}
+
int radeon_modeset_init(struct radeon_device *rdev)
{
int i;
@@ -1251,7 +1320,7 @@ int radeon_modeset_init(struct radeon_device *rdev)
drm_mode_config_init(rdev->ddev);
rdev->mode_info.mode_config_initialized = true;
- rdev->ddev->mode_config.funcs = (void *)&radeon_mode_funcs;
+ rdev->ddev->mode_config.funcs = &radeon_mode_funcs;
if (ASIC_IS_DCE5(rdev)) {
rdev->ddev->mode_config.max_width = 16384;
@@ -1303,6 +1372,9 @@ int radeon_modeset_init(struct radeon_device *rdev)
/* initialize hpd */
radeon_hpd_init(rdev);
+ /* setup afmt */
+ radeon_afmt_init(rdev);
+
/* Initialize power management */
radeon_pm_init(rdev);
@@ -1319,6 +1391,7 @@ void radeon_modeset_fini(struct radeon_device *rdev)
radeon_pm_fini(rdev);
if (rdev->mode_info.mode_config_initialized) {
+ radeon_afmt_fini(rdev);
drm_kms_helper_poll_fini(rdev->ddev);
radeon_hpd_fini(rdev);
drm_mode_config_cleanup(rdev->ddev);
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index ef7bb3f6ecae..f0bb2b543b13 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -105,6 +105,11 @@ int radeon_mode_dumb_create(struct drm_file *file_priv,
int radeon_mode_dumb_destroy(struct drm_file *file_priv,
struct drm_device *dev,
uint32_t handle);
+struct dma_buf *radeon_gem_prime_export(struct drm_device *dev,
+ struct drm_gem_object *obj,
+ int flags);
+struct drm_gem_object *radeon_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *dma_buf);
#if defined(CONFIG_DEBUG_FS)
int radeon_debugfs_init(struct drm_minor *minor);
@@ -128,6 +133,7 @@ int radeon_disp_priority = 0;
int radeon_hw_i2c = 0;
int radeon_pcie_gen2 = 0;
int radeon_msi = -1;
+int radeon_lockup_timeout = 10000;
MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
module_param_named(no_wb, radeon_no_wb, int, 0444);
@@ -177,6 +183,9 @@ module_param_named(pcie_gen2, radeon_pcie_gen2, int, 0444);
MODULE_PARM_DESC(msi, "MSI support (1 = enable, 0 = disable, -1 = auto)");
module_param_named(msi, radeon_msi, int, 0444);
+MODULE_PARM_DESC(lockup_timeout, "GPU lockup timeout in ms (defaul 10000 = 10 seconds, 0 = disable)");
+module_param_named(lockup_timeout, radeon_lockup_timeout, int, 0444);
+
static int radeon_suspend(struct drm_device *dev, pm_message_t state)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -329,7 +338,8 @@ static const struct file_operations radeon_driver_kms_fops = {
static struct drm_driver kms_driver = {
.driver_features =
DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_PCI_DMA | DRIVER_SG |
- DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED | DRIVER_GEM,
+ DRIVER_HAVE_IRQ | DRIVER_HAVE_DMA | DRIVER_IRQ_SHARED | DRIVER_GEM |
+ DRIVER_PRIME,
.dev_priv_size = 0,
.load = radeon_driver_load_kms,
.firstopen = radeon_driver_firstopen_kms,
@@ -364,6 +374,12 @@ static struct drm_driver kms_driver = {
.dumb_map_offset = radeon_mode_dumb_mmap,
.dumb_destroy = radeon_mode_dumb_destroy,
.fops = &radeon_driver_kms_fops,
+
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_export = radeon_gem_prime_export,
+ .gem_prime_import = radeon_gem_prime_import,
+
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
.date = DRIVER_DATE,
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c
index 4bd36a354fbe..11f5f402d22c 100644
--- a/drivers/gpu/drm/radeon/radeon_fence.c
+++ b/drivers/gpu/drm/radeon/radeon_fence.c
@@ -63,98 +63,82 @@ static u32 radeon_fence_read(struct radeon_device *rdev, int ring)
int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence)
{
- unsigned long irq_flags;
-
- write_lock_irqsave(&rdev->fence_lock, irq_flags);
- if (fence->emitted) {
- write_unlock_irqrestore(&rdev->fence_lock, irq_flags);
+ /* we are protected by the ring emission mutex */
+ if (fence->seq && fence->seq < RADEON_FENCE_NOTEMITED_SEQ) {
return 0;
}
- fence->seq = atomic_add_return(1, &rdev->fence_drv[fence->ring].seq);
- if (!rdev->ring[fence->ring].ready)
- /* FIXME: cp is not running assume everythings is done right
- * away
- */
- radeon_fence_write(rdev, fence->seq, fence->ring);
- else
- radeon_fence_ring_emit(rdev, fence->ring, fence);
-
+ fence->seq = ++rdev->fence_drv[fence->ring].seq;
+ radeon_fence_ring_emit(rdev, fence->ring, fence);
trace_radeon_fence_emit(rdev->ddev, fence->seq);
- fence->emitted = true;
- list_move_tail(&fence->list, &rdev->fence_drv[fence->ring].emitted);
- write_unlock_irqrestore(&rdev->fence_lock, irq_flags);
return 0;
}
-static bool radeon_fence_poll_locked(struct radeon_device *rdev, int ring)
+void radeon_fence_process(struct radeon_device *rdev, int ring)
{
- struct radeon_fence *fence;
- struct list_head *i, *n;
- uint32_t seq;
+ uint64_t seq, last_seq;
+ unsigned count_loop = 0;
bool wake = false;
- unsigned long cjiffies;
- seq = radeon_fence_read(rdev, ring);
- if (seq != rdev->fence_drv[ring].last_seq) {
- rdev->fence_drv[ring].last_seq = seq;
- rdev->fence_drv[ring].last_jiffies = jiffies;
- rdev->fence_drv[ring].last_timeout = RADEON_FENCE_JIFFIES_TIMEOUT;
- } else {
- cjiffies = jiffies;
- if (time_after(cjiffies, rdev->fence_drv[ring].last_jiffies)) {
- cjiffies -= rdev->fence_drv[ring].last_jiffies;
- if (time_after(rdev->fence_drv[ring].last_timeout, cjiffies)) {
- /* update the timeout */
- rdev->fence_drv[ring].last_timeout -= cjiffies;
- } else {
- /* the 500ms timeout is elapsed we should test
- * for GPU lockup
- */
- rdev->fence_drv[ring].last_timeout = 1;
- }
- } else {
- /* wrap around update last jiffies, we will just wait
- * a little longer
- */
- rdev->fence_drv[ring].last_jiffies = cjiffies;
+ /* Note there is a scenario here for an infinite loop but it's
+ * very unlikely to happen. For it to happen, the current polling
+ * process need to be interrupted by another process and another
+ * process needs to update the last_seq btw the atomic read and
+ * xchg of the current process.
+ *
+ * More over for this to go in infinite loop there need to be
+ * continuously new fence signaled ie radeon_fence_read needs
+ * to return a different value each time for both the currently
+ * polling process and the other process that xchg the last_seq
+ * btw atomic read and xchg of the current process. And the
+ * value the other process set as last seq must be higher than
+ * the seq value we just read. Which means that current process
+ * need to be interrupted after radeon_fence_read and before
+ * atomic xchg.
+ *
+ * To be even more safe we count the number of time we loop and
+ * we bail after 10 loop just accepting the fact that we might
+ * have temporarly set the last_seq not to the true real last
+ * seq but to an older one.
+ */
+ last_seq = atomic64_read(&rdev->fence_drv[ring].last_seq);
+ do {
+ seq = radeon_fence_read(rdev, ring);
+ seq |= last_seq & 0xffffffff00000000LL;
+ if (seq < last_seq) {
+ seq += 0x100000000LL;
}
- return false;
- }
- n = NULL;
- list_for_each(i, &rdev->fence_drv[ring].emitted) {
- fence = list_entry(i, struct radeon_fence, list);
- if (fence->seq == seq) {
- n = i;
+
+ if (seq == last_seq) {
break;
}
- }
- /* all fence previous to this one are considered as signaled */
- if (n) {
- i = n;
- do {
- n = i->prev;
- list_move_tail(i, &rdev->fence_drv[ring].signaled);
- fence = list_entry(i, struct radeon_fence, list);
- fence->signaled = true;
- i = n;
- } while (i != &rdev->fence_drv[ring].emitted);
+ /* If we loop over we don't want to return without
+ * checking if a fence is signaled as it means that the
+ * seq we just read is different from the previous on.
+ */
wake = true;
+ last_seq = seq;
+ if ((count_loop++) > 10) {
+ /* We looped over too many time leave with the
+ * fact that we might have set an older fence
+ * seq then the current real last seq as signaled
+ * by the hw.
+ */
+ break;
+ }
+ } while (atomic64_xchg(&rdev->fence_drv[ring].last_seq, seq) > seq);
+
+ if (wake) {
+ rdev->fence_drv[ring].last_activity = jiffies;
+ wake_up_all(&rdev->fence_queue);
}
- return wake;
}
static void radeon_fence_destroy(struct kref *kref)
{
- unsigned long irq_flags;
- struct radeon_fence *fence;
+ struct radeon_fence *fence;
fence = container_of(kref, struct radeon_fence, kref);
- write_lock_irqsave(&fence->rdev->fence_lock, irq_flags);
- list_del(&fence->list);
- fence->emitted = false;
- write_unlock_irqrestore(&fence->rdev->fence_lock, irq_flags);
- if (fence->semaphore)
- radeon_semaphore_free(fence->rdev, fence->semaphore);
+ fence->seq = RADEON_FENCE_NOTEMITED_SEQ;
kfree(fence);
}
@@ -162,171 +146,342 @@ int radeon_fence_create(struct radeon_device *rdev,
struct radeon_fence **fence,
int ring)
{
- unsigned long irq_flags;
-
*fence = kmalloc(sizeof(struct radeon_fence), GFP_KERNEL);
if ((*fence) == NULL) {
return -ENOMEM;
}
kref_init(&((*fence)->kref));
(*fence)->rdev = rdev;
- (*fence)->emitted = false;
- (*fence)->signaled = false;
- (*fence)->seq = 0;
+ (*fence)->seq = RADEON_FENCE_NOTEMITED_SEQ;
(*fence)->ring = ring;
- (*fence)->semaphore = NULL;
- INIT_LIST_HEAD(&(*fence)->list);
-
- write_lock_irqsave(&rdev->fence_lock, irq_flags);
- list_add_tail(&(*fence)->list, &rdev->fence_drv[ring].created);
- write_unlock_irqrestore(&rdev->fence_lock, irq_flags);
return 0;
}
-bool radeon_fence_signaled(struct radeon_fence *fence)
+static bool radeon_fence_seq_signaled(struct radeon_device *rdev,
+ u64 seq, unsigned ring)
{
- unsigned long irq_flags;
- bool signaled = false;
-
- if (!fence)
+ if (atomic64_read(&rdev->fence_drv[ring].last_seq) >= seq) {
return true;
-
- if (fence->rdev->gpu_lockup)
+ }
+ /* poll new last sequence at least once */
+ radeon_fence_process(rdev, ring);
+ if (atomic64_read(&rdev->fence_drv[ring].last_seq) >= seq) {
return true;
+ }
+ return false;
+}
- write_lock_irqsave(&fence->rdev->fence_lock, irq_flags);
- signaled = fence->signaled;
- /* if we are shuting down report all fence as signaled */
- if (fence->rdev->shutdown) {
- signaled = true;
+bool radeon_fence_signaled(struct radeon_fence *fence)
+{
+ if (!fence) {
+ return true;
}
- if (!fence->emitted) {
+ if (fence->seq == RADEON_FENCE_NOTEMITED_SEQ) {
WARN(1, "Querying an unemitted fence : %p !\n", fence);
- signaled = true;
+ return true;
}
- if (!signaled) {
- radeon_fence_poll_locked(fence->rdev, fence->ring);
- signaled = fence->signaled;
+ if (fence->seq == RADEON_FENCE_SIGNALED_SEQ) {
+ return true;
+ }
+ if (radeon_fence_seq_signaled(fence->rdev, fence->seq, fence->ring)) {
+ fence->seq = RADEON_FENCE_SIGNALED_SEQ;
+ return true;
}
- write_unlock_irqrestore(&fence->rdev->fence_lock, irq_flags);
- return signaled;
+ return false;
+}
+
+static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 target_seq,
+ unsigned ring, bool intr, bool lock_ring)
+{
+ unsigned long timeout, last_activity;
+ uint64_t seq;
+ unsigned i;
+ bool signaled;
+ int r;
+
+ while (target_seq > atomic64_read(&rdev->fence_drv[ring].last_seq)) {
+ if (!rdev->ring[ring].ready) {
+ return -EBUSY;
+ }
+
+ timeout = jiffies - RADEON_FENCE_JIFFIES_TIMEOUT;
+ if (time_after(rdev->fence_drv[ring].last_activity, timeout)) {
+ /* the normal case, timeout is somewhere before last_activity */
+ timeout = rdev->fence_drv[ring].last_activity - timeout;
+ } else {
+ /* either jiffies wrapped around, or no fence was signaled in the last 500ms
+ * anyway we will just wait for the minimum amount and then check for a lockup
+ */
+ timeout = 1;
+ }
+ seq = atomic64_read(&rdev->fence_drv[ring].last_seq);
+ /* Save current last activity valuee, used to check for GPU lockups */
+ last_activity = rdev->fence_drv[ring].last_activity;
+
+ trace_radeon_fence_wait_begin(rdev->ddev, seq);
+ radeon_irq_kms_sw_irq_get(rdev, ring);
+ if (intr) {
+ r = wait_event_interruptible_timeout(rdev->fence_queue,
+ (signaled = radeon_fence_seq_signaled(rdev, target_seq, ring)),
+ timeout);
+ } else {
+ r = wait_event_timeout(rdev->fence_queue,
+ (signaled = radeon_fence_seq_signaled(rdev, target_seq, ring)),
+ timeout);
+ }
+ radeon_irq_kms_sw_irq_put(rdev, ring);
+ if (unlikely(r < 0)) {
+ return r;
+ }
+ trace_radeon_fence_wait_end(rdev->ddev, seq);
+
+ if (unlikely(!signaled)) {
+ /* we were interrupted for some reason and fence
+ * isn't signaled yet, resume waiting */
+ if (r) {
+ continue;
+ }
+
+ /* check if sequence value has changed since last_activity */
+ if (seq != atomic64_read(&rdev->fence_drv[ring].last_seq)) {
+ continue;
+ }
+
+ if (lock_ring) {
+ mutex_lock(&rdev->ring_lock);
+ }
+
+ /* test if somebody else has already decided that this is a lockup */
+ if (last_activity != rdev->fence_drv[ring].last_activity) {
+ if (lock_ring) {
+ mutex_unlock(&rdev->ring_lock);
+ }
+ continue;
+ }
+
+ if (radeon_ring_is_lockup(rdev, ring, &rdev->ring[ring])) {
+ /* good news we believe it's a lockup */
+ dev_warn(rdev->dev, "GPU lockup (waiting for 0x%016llx last fence id 0x%016llx)\n",
+ target_seq, seq);
+
+ /* change last activity so nobody else think there is a lockup */
+ for (i = 0; i < RADEON_NUM_RINGS; ++i) {
+ rdev->fence_drv[i].last_activity = jiffies;
+ }
+
+ /* mark the ring as not ready any more */
+ rdev->ring[ring].ready = false;
+ if (lock_ring) {
+ mutex_unlock(&rdev->ring_lock);
+ }
+ return -EDEADLK;
+ }
+
+ if (lock_ring) {
+ mutex_unlock(&rdev->ring_lock);
+ }
+ }
+ }
+ return 0;
}
int radeon_fence_wait(struct radeon_fence *fence, bool intr)
{
- struct radeon_device *rdev;
- unsigned long irq_flags, timeout;
- u32 seq;
int r;
if (fence == NULL) {
WARN(1, "Querying an invalid fence : %p !\n", fence);
- return 0;
+ return -EINVAL;
}
- rdev = fence->rdev;
- if (radeon_fence_signaled(fence)) {
- return 0;
+
+ r = radeon_fence_wait_seq(fence->rdev, fence->seq,
+ fence->ring, intr, true);
+ if (r) {
+ return r;
}
- timeout = rdev->fence_drv[fence->ring].last_timeout;
-retry:
- /* save current sequence used to check for GPU lockup */
- seq = rdev->fence_drv[fence->ring].last_seq;
- trace_radeon_fence_wait_begin(rdev->ddev, seq);
- if (intr) {
- radeon_irq_kms_sw_irq_get(rdev, fence->ring);
- r = wait_event_interruptible_timeout(rdev->fence_drv[fence->ring].queue,
- radeon_fence_signaled(fence), timeout);
- radeon_irq_kms_sw_irq_put(rdev, fence->ring);
- if (unlikely(r < 0)) {
- return r;
+ fence->seq = RADEON_FENCE_SIGNALED_SEQ;
+ return 0;
+}
+
+bool radeon_fence_any_seq_signaled(struct radeon_device *rdev, u64 *seq)
+{
+ unsigned i;
+
+ for (i = 0; i < RADEON_NUM_RINGS; ++i) {
+ if (seq[i] && radeon_fence_seq_signaled(rdev, seq[i], i)) {
+ return true;
}
- } else {
- radeon_irq_kms_sw_irq_get(rdev, fence->ring);
- r = wait_event_timeout(rdev->fence_drv[fence->ring].queue,
- radeon_fence_signaled(fence), timeout);
- radeon_irq_kms_sw_irq_put(rdev, fence->ring);
}
- trace_radeon_fence_wait_end(rdev->ddev, seq);
- if (unlikely(!radeon_fence_signaled(fence))) {
- /* we were interrupted for some reason and fence isn't
- * isn't signaled yet, resume wait
- */
- if (r) {
- timeout = r;
- goto retry;
+ return false;
+}
+
+static int radeon_fence_wait_any_seq(struct radeon_device *rdev,
+ u64 *target_seq, bool intr)
+{
+ unsigned long timeout, last_activity, tmp;
+ unsigned i, ring = RADEON_NUM_RINGS;
+ bool signaled;
+ int r;
+
+ for (i = 0, last_activity = 0; i < RADEON_NUM_RINGS; ++i) {
+ if (!target_seq[i]) {
+ continue;
+ }
+
+ /* use the most recent one as indicator */
+ if (time_after(rdev->fence_drv[i].last_activity, last_activity)) {
+ last_activity = rdev->fence_drv[i].last_activity;
}
- /* don't protect read access to rdev->fence_drv[t].last_seq
- * if we experiencing a lockup the value doesn't change
+
+ /* For lockup detection just pick the lowest ring we are
+ * actively waiting for
*/
- if (seq == rdev->fence_drv[fence->ring].last_seq &&
- radeon_gpu_is_lockup(rdev, &rdev->ring[fence->ring])) {
- /* good news we believe it's a lockup */
- printk(KERN_WARNING "GPU lockup (waiting for 0x%08X last fence id 0x%08X)\n",
- fence->seq, seq);
- /* FIXME: what should we do ? marking everyone
- * as signaled for now
+ if (i < ring) {
+ ring = i;
+ }
+ }
+
+ /* nothing to wait for ? */
+ if (ring == RADEON_NUM_RINGS) {
+ return 0;
+ }
+
+ while (!radeon_fence_any_seq_signaled(rdev, target_seq)) {
+ timeout = jiffies - RADEON_FENCE_JIFFIES_TIMEOUT;
+ if (time_after(last_activity, timeout)) {
+ /* the normal case, timeout is somewhere before last_activity */
+ timeout = last_activity - timeout;
+ } else {
+ /* either jiffies wrapped around, or no fence was signaled in the last 500ms
+ * anyway we will just wait for the minimum amount and then check for a lockup
*/
- rdev->gpu_lockup = true;
- r = radeon_gpu_reset(rdev);
- if (r)
- return r;
- radeon_fence_write(rdev, fence->seq, fence->ring);
- rdev->gpu_lockup = false;
+ timeout = 1;
+ }
+
+ trace_radeon_fence_wait_begin(rdev->ddev, target_seq[ring]);
+ for (i = 0; i < RADEON_NUM_RINGS; ++i) {
+ if (target_seq[i]) {
+ radeon_irq_kms_sw_irq_get(rdev, i);
+ }
+ }
+ if (intr) {
+ r = wait_event_interruptible_timeout(rdev->fence_queue,
+ (signaled = radeon_fence_any_seq_signaled(rdev, target_seq)),
+ timeout);
+ } else {
+ r = wait_event_timeout(rdev->fence_queue,
+ (signaled = radeon_fence_any_seq_signaled(rdev, target_seq)),
+ timeout);
+ }
+ for (i = 0; i < RADEON_NUM_RINGS; ++i) {
+ if (target_seq[i]) {
+ radeon_irq_kms_sw_irq_put(rdev, i);
+ }
+ }
+ if (unlikely(r < 0)) {
+ return r;
+ }
+ trace_radeon_fence_wait_end(rdev->ddev, target_seq[ring]);
+
+ if (unlikely(!signaled)) {
+ /* we were interrupted for some reason and fence
+ * isn't signaled yet, resume waiting */
+ if (r) {
+ continue;
+ }
+
+ mutex_lock(&rdev->ring_lock);
+ for (i = 0, tmp = 0; i < RADEON_NUM_RINGS; ++i) {
+ if (time_after(rdev->fence_drv[i].last_activity, tmp)) {
+ tmp = rdev->fence_drv[i].last_activity;
+ }
+ }
+ /* test if somebody else has already decided that this is a lockup */
+ if (last_activity != tmp) {
+ last_activity = tmp;
+ mutex_unlock(&rdev->ring_lock);
+ continue;
+ }
+
+ if (radeon_ring_is_lockup(rdev, ring, &rdev->ring[ring])) {
+ /* good news we believe it's a lockup */
+ dev_warn(rdev->dev, "GPU lockup (waiting for 0x%016llx)\n",
+ target_seq[ring]);
+
+ /* change last activity so nobody else think there is a lockup */
+ for (i = 0; i < RADEON_NUM_RINGS; ++i) {
+ rdev->fence_drv[i].last_activity = jiffies;
+ }
+
+ /* mark the ring as not ready any more */
+ rdev->ring[ring].ready = false;
+ mutex_unlock(&rdev->ring_lock);
+ return -EDEADLK;
+ }
+ mutex_unlock(&rdev->ring_lock);
}
- timeout = RADEON_FENCE_JIFFIES_TIMEOUT;
- write_lock_irqsave(&rdev->fence_lock, irq_flags);
- rdev->fence_drv[fence->ring].last_timeout = RADEON_FENCE_JIFFIES_TIMEOUT;
- rdev->fence_drv[fence->ring].last_jiffies = jiffies;
- write_unlock_irqrestore(&rdev->fence_lock, irq_flags);
- goto retry;
}
return 0;
}
-int radeon_fence_wait_next(struct radeon_device *rdev, int ring)
+int radeon_fence_wait_any(struct radeon_device *rdev,
+ struct radeon_fence **fences,
+ bool intr)
{
- unsigned long irq_flags;
- struct radeon_fence *fence;
+ uint64_t seq[RADEON_NUM_RINGS];
+ unsigned i;
int r;
- if (rdev->gpu_lockup) {
- return 0;
+ for (i = 0; i < RADEON_NUM_RINGS; ++i) {
+ seq[i] = 0;
+
+ if (!fences[i]) {
+ continue;
+ }
+
+ if (fences[i]->seq == RADEON_FENCE_SIGNALED_SEQ) {
+ /* something was allready signaled */
+ return 0;
+ }
+
+ if (fences[i]->seq < RADEON_FENCE_NOTEMITED_SEQ) {
+ seq[i] = fences[i]->seq;
+ }
}
- write_lock_irqsave(&rdev->fence_lock, irq_flags);
- if (list_empty(&rdev->fence_drv[ring].emitted)) {
- write_unlock_irqrestore(&rdev->fence_lock, irq_flags);
- return 0;
+
+ r = radeon_fence_wait_any_seq(rdev, seq, intr);
+ if (r) {
+ return r;
}
- fence = list_entry(rdev->fence_drv[ring].emitted.next,
- struct radeon_fence, list);
- radeon_fence_ref(fence);
- write_unlock_irqrestore(&rdev->fence_lock, irq_flags);
- r = radeon_fence_wait(fence, false);
- radeon_fence_unref(&fence);
- return r;
+ return 0;
}
-int radeon_fence_wait_last(struct radeon_device *rdev, int ring)
+int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring)
{
- unsigned long irq_flags;
- struct radeon_fence *fence;
- int r;
-
- if (rdev->gpu_lockup) {
- return 0;
+ uint64_t seq;
+
+ /* We are not protected by ring lock when reading current seq but
+ * it's ok as worst case is we return to early while we could have
+ * wait.
+ */
+ seq = atomic64_read(&rdev->fence_drv[ring].last_seq) + 1ULL;
+ if (seq >= rdev->fence_drv[ring].seq) {
+ /* nothing to wait for, last_seq is
+ already the last emited fence */
+ return -ENOENT;
}
- write_lock_irqsave(&rdev->fence_lock, irq_flags);
- if (list_empty(&rdev->fence_drv[ring].emitted)) {
- write_unlock_irqrestore(&rdev->fence_lock, irq_flags);
- return 0;
- }
- fence = list_entry(rdev->fence_drv[ring].emitted.prev,
- struct radeon_fence, list);
- radeon_fence_ref(fence);
- write_unlock_irqrestore(&rdev->fence_lock, irq_flags);
- r = radeon_fence_wait(fence, false);
- radeon_fence_unref(&fence);
- return r;
+ return radeon_fence_wait_seq(rdev, seq, ring, false, false);
+}
+
+int radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring)
+{
+ /* We are not protected by ring lock when reading current seq
+ * but it's ok as wait empty is call from place where no more
+ * activity can be scheduled so there won't be concurrent access
+ * to seq value.
+ */
+ return radeon_fence_wait_seq(rdev, rdev->fence_drv[ring].seq,
+ ring, false, false);
}
struct radeon_fence *radeon_fence_ref(struct radeon_fence *fence)
@@ -345,49 +500,27 @@ void radeon_fence_unref(struct radeon_fence **fence)
}
}
-void radeon_fence_process(struct radeon_device *rdev, int ring)
-{
- unsigned long irq_flags;
- bool wake;
-
- write_lock_irqsave(&rdev->fence_lock, irq_flags);
- wake = radeon_fence_poll_locked(rdev, ring);
- write_unlock_irqrestore(&rdev->fence_lock, irq_flags);
- if (wake) {
- wake_up_all(&rdev->fence_drv[ring].queue);
- }
-}
-
-int radeon_fence_count_emitted(struct radeon_device *rdev, int ring)
+unsigned radeon_fence_count_emitted(struct radeon_device *rdev, int ring)
{
- unsigned long irq_flags;
- int not_processed = 0;
-
- read_lock_irqsave(&rdev->fence_lock, irq_flags);
- if (!rdev->fence_drv[ring].initialized) {
- read_unlock_irqrestore(&rdev->fence_lock, irq_flags);
- return 0;
+ uint64_t emitted;
+
+ /* We are not protected by ring lock when reading the last sequence
+ * but it's ok to report slightly wrong fence count here.
+ */
+ radeon_fence_process(rdev, ring);
+ emitted = rdev->fence_drv[ring].seq - atomic64_read(&rdev->fence_drv[ring].last_seq);
+ /* to avoid 32bits warp around */
+ if (emitted > 0x10000000) {
+ emitted = 0x10000000;
}
-
- if (!list_empty(&rdev->fence_drv[ring].emitted)) {
- struct list_head *ptr;
- list_for_each(ptr, &rdev->fence_drv[ring].emitted) {
- /* count up to 3, that's enought info */
- if (++not_processed >= 3)
- break;
- }
- }
- read_unlock_irqrestore(&rdev->fence_lock, irq_flags);
- return not_processed;
+ return (unsigned)emitted;
}
int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring)
{
- unsigned long irq_flags;
uint64_t index;
int r;
- write_lock_irqsave(&rdev->fence_lock, irq_flags);
radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg);
if (rdev->wb.use_event) {
rdev->fence_drv[ring].scratch_reg = 0;
@@ -396,7 +529,6 @@ int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring)
r = radeon_scratch_get(rdev, &rdev->fence_drv[ring].scratch_reg);
if (r) {
dev_err(rdev->dev, "fence failed to get scratch register\n");
- write_unlock_irqrestore(&rdev->fence_lock, irq_flags);
return r;
}
index = RADEON_WB_SCRATCH_OFFSET +
@@ -405,11 +537,10 @@ int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring)
}
rdev->fence_drv[ring].cpu_addr = &rdev->wb.wb[index/4];
rdev->fence_drv[ring].gpu_addr = rdev->wb.gpu_addr + index;
- radeon_fence_write(rdev, atomic_read(&rdev->fence_drv[ring].seq), ring);
+ radeon_fence_write(rdev, rdev->fence_drv[ring].seq, ring);
rdev->fence_drv[ring].initialized = true;
- DRM_INFO("fence driver on ring %d use gpu addr 0x%08Lx and cpu addr 0x%p\n",
+ dev_info(rdev->dev, "fence driver on ring %d use gpu addr 0x%016llx and cpu addr 0x%p\n",
ring, rdev->fence_drv[ring].gpu_addr, rdev->fence_drv[ring].cpu_addr);
- write_unlock_irqrestore(&rdev->fence_lock, irq_flags);
return 0;
}
@@ -418,24 +549,20 @@ static void radeon_fence_driver_init_ring(struct radeon_device *rdev, int ring)
rdev->fence_drv[ring].scratch_reg = -1;
rdev->fence_drv[ring].cpu_addr = NULL;
rdev->fence_drv[ring].gpu_addr = 0;
- atomic_set(&rdev->fence_drv[ring].seq, 0);
- INIT_LIST_HEAD(&rdev->fence_drv[ring].created);
- INIT_LIST_HEAD(&rdev->fence_drv[ring].emitted);
- INIT_LIST_HEAD(&rdev->fence_drv[ring].signaled);
- init_waitqueue_head(&rdev->fence_drv[ring].queue);
+ rdev->fence_drv[ring].seq = 0;
+ atomic64_set(&rdev->fence_drv[ring].last_seq, 0);
+ rdev->fence_drv[ring].last_activity = jiffies;
rdev->fence_drv[ring].initialized = false;
}
int radeon_fence_driver_init(struct radeon_device *rdev)
{
- unsigned long irq_flags;
int ring;
- write_lock_irqsave(&rdev->fence_lock, irq_flags);
+ init_waitqueue_head(&rdev->fence_queue);
for (ring = 0; ring < RADEON_NUM_RINGS; ring++) {
radeon_fence_driver_init_ring(rdev, ring);
}
- write_unlock_irqrestore(&rdev->fence_lock, irq_flags);
if (radeon_debugfs_fence_init(rdev)) {
dev_err(rdev->dev, "fence debugfs file creation failed\n");
}
@@ -444,19 +571,18 @@ int radeon_fence_driver_init(struct radeon_device *rdev)
void radeon_fence_driver_fini(struct radeon_device *rdev)
{
- unsigned long irq_flags;
int ring;
+ mutex_lock(&rdev->ring_lock);
for (ring = 0; ring < RADEON_NUM_RINGS; ring++) {
if (!rdev->fence_drv[ring].initialized)
continue;
- radeon_fence_wait_last(rdev, ring);
- wake_up_all(&rdev->fence_drv[ring].queue);
- write_lock_irqsave(&rdev->fence_lock, irq_flags);
+ radeon_fence_wait_empty_locked(rdev, ring);
+ wake_up_all(&rdev->fence_queue);
radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg);
- write_unlock_irqrestore(&rdev->fence_lock, irq_flags);
rdev->fence_drv[ring].initialized = false;
}
+ mutex_unlock(&rdev->ring_lock);
}
@@ -469,7 +595,6 @@ static int radeon_debugfs_fence_info(struct seq_file *m, void *data)
struct drm_info_node *node = (struct drm_info_node *)m->private;
struct drm_device *dev = node->minor->dev;
struct radeon_device *rdev = dev->dev_private;
- struct radeon_fence *fence;
int i;
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
@@ -477,14 +602,10 @@ static int radeon_debugfs_fence_info(struct seq_file *m, void *data)
continue;
seq_printf(m, "--- ring %d ---\n", i);
- seq_printf(m, "Last signaled fence 0x%08X\n",
- radeon_fence_read(rdev, i));
- if (!list_empty(&rdev->fence_drv[i].emitted)) {
- fence = list_entry(rdev->fence_drv[i].emitted.prev,
- struct radeon_fence, list);
- seq_printf(m, "Last emitted fence %p with 0x%08X\n",
- fence, fence->seq);
- }
+ seq_printf(m, "Last signaled fence 0x%016llx\n",
+ (unsigned long long)atomic64_read(&rdev->fence_drv[i].last_seq));
+ seq_printf(m, "Last emitted 0x%016llx\n",
+ rdev->fence_drv[i].seq);
}
return 0;
}
diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c
index c58a036233fb..79db56e6c2ac 100644
--- a/drivers/gpu/drm/radeon/radeon_gart.c
+++ b/drivers/gpu/drm/radeon/radeon_gart.c
@@ -80,7 +80,7 @@ int radeon_gart_table_vram_alloc(struct radeon_device *rdev)
if (rdev->gart.robj == NULL) {
r = radeon_bo_create(rdev, rdev->gart.table_size,
PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
- &rdev->gart.robj);
+ NULL, &rdev->gart.robj);
if (r) {
return r;
}
@@ -326,7 +326,7 @@ static void radeon_vm_unbind_locked(struct radeon_device *rdev,
rdev->vm_manager.use_bitmap &= ~(1 << vm->id);
list_del_init(&vm->list);
vm->id = -1;
- radeon_sa_bo_free(rdev, &vm->sa_bo);
+ radeon_sa_bo_free(rdev, &vm->sa_bo, NULL);
vm->pt = NULL;
list_for_each_entry(bo_va, &vm->va, vm_list) {
@@ -395,7 +395,7 @@ int radeon_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm)
retry:
r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager, &vm->sa_bo,
RADEON_GPU_PAGE_ALIGN(vm->last_pfn * 8),
- RADEON_GPU_PAGE_SIZE);
+ RADEON_GPU_PAGE_SIZE, false);
if (r) {
if (list_empty(&rdev->vm_manager.lru_vm)) {
return r;
@@ -404,10 +404,8 @@ retry:
radeon_vm_unbind(rdev, vm_evict);
goto retry;
}
- vm->pt = rdev->vm_manager.sa_manager.cpu_ptr;
- vm->pt += (vm->sa_bo.offset >> 3);
- vm->pt_gpu_addr = rdev->vm_manager.sa_manager.gpu_addr;
- vm->pt_gpu_addr += vm->sa_bo.offset;
+ vm->pt = radeon_sa_bo_cpu_addr(vm->sa_bo);
+ vm->pt_gpu_addr = radeon_sa_bo_gpu_addr(vm->sa_bo);
memset(vm->pt, 0, RADEON_GPU_PAGE_ALIGN(vm->last_pfn * 8));
retry_id:
@@ -428,14 +426,14 @@ retry_id:
/* do hw bind */
r = rdev->vm_manager.funcs->bind(rdev, vm, id);
if (r) {
- radeon_sa_bo_free(rdev, &vm->sa_bo);
+ radeon_sa_bo_free(rdev, &vm->sa_bo, NULL);
return r;
}
rdev->vm_manager.use_bitmap |= 1 << id;
vm->id = id;
list_add_tail(&vm->list, &rdev->vm_manager.lru_vm);
- return radeon_vm_bo_update_pte(rdev, vm, rdev->ib_pool.sa_manager.bo,
- &rdev->ib_pool.sa_manager.bo->tbo.mem);
+ return radeon_vm_bo_update_pte(rdev, vm, rdev->ring_tmp_bo.bo,
+ &rdev->ring_tmp_bo.bo->tbo.mem);
}
/* object have to be reserved */
@@ -551,7 +549,7 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev,
/* nothing to do if vm isn't bound */
if (vm->id == -1)
- return 0;;
+ return 0;
bo_va = radeon_bo_va(bo, vm);
if (bo_va == NULL) {
@@ -633,7 +631,7 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm)
/* map the ib pool buffer at 0 in virtual address space, set
* read only
*/
- r = radeon_vm_bo_add(rdev, vm, rdev->ib_pool.sa_manager.bo, 0,
+ r = radeon_vm_bo_add(rdev, vm, rdev->ring_tmp_bo.bo, 0,
RADEON_VM_PAGE_READABLE | RADEON_VM_PAGE_SNOOPED);
return r;
}
@@ -650,12 +648,12 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm)
radeon_mutex_unlock(&rdev->cs_mutex);
/* remove all bo */
- r = radeon_bo_reserve(rdev->ib_pool.sa_manager.bo, false);
+ r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false);
if (!r) {
- bo_va = radeon_bo_va(rdev->ib_pool.sa_manager.bo, vm);
+ bo_va = radeon_bo_va(rdev->ring_tmp_bo.bo, vm);
list_del_init(&bo_va->bo_list);
list_del_init(&bo_va->vm_list);
- radeon_bo_unreserve(rdev->ib_pool.sa_manager.bo);
+ radeon_bo_unreserve(rdev->ring_tmp_bo.bo);
kfree(bo_va);
}
if (!list_empty(&vm->va)) {
diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c
index c7008b5210f7..f28bd4b7ef98 100644
--- a/drivers/gpu/drm/radeon/radeon_gem.c
+++ b/drivers/gpu/drm/radeon/radeon_gem.c
@@ -42,6 +42,8 @@ void radeon_gem_object_free(struct drm_gem_object *gobj)
struct radeon_bo *robj = gem_to_radeon_bo(gobj);
if (robj) {
+ if (robj->gem_base.import_attach)
+ drm_prime_gem_destroy(&robj->gem_base, robj->tbo.sg);
radeon_bo_unref(&robj);
}
}
@@ -59,7 +61,7 @@ int radeon_gem_object_create(struct radeon_device *rdev, int size,
if (alignment < PAGE_SIZE) {
alignment = PAGE_SIZE;
}
- r = radeon_bo_create(rdev, size, alignment, kernel, initial_domain, &robj);
+ r = radeon_bo_create(rdev, size, alignment, kernel, initial_domain, NULL, &robj);
if (r) {
if (r != -ERESTARTSYS)
DRM_ERROR("Failed to allocate GEM object (%d, %d, %u, %d)\n",
@@ -91,7 +93,7 @@ int radeon_gem_set_domain(struct drm_gem_object *gobj,
}
if (!domain) {
/* Do nothings */
- printk(KERN_WARNING "Set domain withou domain !\n");
+ printk(KERN_WARNING "Set domain without domain !\n");
return 0;
}
if (domain == RADEON_GEM_DOMAIN_CPU) {
@@ -154,6 +156,17 @@ void radeon_gem_object_close(struct drm_gem_object *obj,
radeon_bo_unreserve(rbo);
}
+static int radeon_gem_handle_lockup(struct radeon_device *rdev, int r)
+{
+ if (r == -EDEADLK) {
+ radeon_mutex_lock(&rdev->cs_mutex);
+ r = radeon_gpu_reset(rdev);
+ if (!r)
+ r = -EAGAIN;
+ radeon_mutex_unlock(&rdev->cs_mutex);
+ }
+ return r;
+}
/*
* GEM ioctls.
@@ -210,12 +223,14 @@ int radeon_gem_create_ioctl(struct drm_device *dev, void *data,
args->initial_domain, false,
false, &gobj);
if (r) {
+ r = radeon_gem_handle_lockup(rdev, r);
return r;
}
r = drm_gem_handle_create(filp, gobj, &handle);
/* drop reference from allocate - handle holds it now */
drm_gem_object_unreference_unlocked(gobj);
if (r) {
+ r = radeon_gem_handle_lockup(rdev, r);
return r;
}
args->handle = handle;
@@ -245,6 +260,7 @@ int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data,
r = radeon_gem_set_domain(gobj, args->read_domains, args->write_domain);
drm_gem_object_unreference_unlocked(gobj);
+ r = radeon_gem_handle_lockup(robj->rdev, r);
return r;
}
@@ -301,6 +317,7 @@ int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,
break;
}
drm_gem_object_unreference_unlocked(gobj);
+ r = radeon_gem_handle_lockup(robj->rdev, r);
return r;
}
@@ -322,6 +339,7 @@ int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
if (robj->rdev->asic->ioctl_wait_idle)
robj->rdev->asic->ioctl_wait_idle(robj->rdev, robj);
drm_gem_object_unreference_unlocked(gobj);
+ r = radeon_gem_handle_lockup(robj->rdev, r);
return r;
}
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
index 65060b77c805..5df58d1aba06 100644
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
@@ -73,6 +73,7 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev)
for (i = 0; i < RADEON_MAX_CRTCS; i++) {
rdev->irq.crtc_vblank_int[i] = false;
rdev->irq.pflip[i] = false;
+ rdev->irq.afmt[i] = false;
}
radeon_irq_set(rdev);
/* Clear bits */
@@ -108,6 +109,7 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev)
for (i = 0; i < RADEON_MAX_CRTCS; i++) {
rdev->irq.crtc_vblank_int[i] = false;
rdev->irq.pflip[i] = false;
+ rdev->irq.afmt[i] = false;
}
radeon_irq_set(rdev);
}
@@ -170,6 +172,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
int r = 0;
INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
+ INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi);
spin_lock_init(&rdev->irq.sw_lock);
for (i = 0; i < rdev->num_crtc; i++)
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index 3c2628b14d56..f1016a5820d1 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -57,8 +57,6 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags)
}
dev->dev_private = (void *)rdev;
- pci_set_master(dev->pdev);
-
/* update BUS flag */
if (drm_pci_device_is_agp(dev)) {
flags |= RADEON_IS_AGP;
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
index 42db254f6bb0..a0c82229e8f0 100644
--- a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
@@ -369,6 +369,7 @@ void radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder,
goto error;
}
+ memset(&props, 0, sizeof(props));
props.max_brightness = MAX_RADEON_LEVEL;
props.type = BACKLIGHT_RAW;
bd = backlight_device_register("radeon_bl", &drm_connector->kdev,
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index f7eb5d8b9fd3..5b10ffd7bb2f 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -210,6 +210,7 @@ enum radeon_connector_table {
CT_RN50_POWER,
CT_MAC_X800,
CT_MAC_G5_9600,
+ CT_SAM440EP
};
enum radeon_dvo_chip {
@@ -219,12 +220,20 @@ enum radeon_dvo_chip {
struct radeon_fbdev;
+struct radeon_afmt {
+ bool enabled;
+ int offset;
+ bool last_buffer_filled_status;
+ int id;
+};
+
struct radeon_mode_info {
struct atom_context *atom_context;
struct card_info *atom_card_info;
enum radeon_connector_table connector_table;
bool mode_config_initialized;
struct radeon_crtc *crtcs[6];
+ struct radeon_afmt *afmt[6];
/* DVI-I properties */
struct drm_property *coherent_mode_property;
/* DAC enable load detect */
@@ -363,6 +372,7 @@ struct radeon_encoder_atom_dig {
int dpms_mode;
uint8_t backlight_level;
int panel_mode;
+ struct radeon_afmt *afmt;
};
struct radeon_encoder_atom_dac {
@@ -384,10 +394,6 @@ struct radeon_encoder {
struct drm_display_mode native_mode;
void *enc_priv;
int audio_polling_active;
- int hdmi_offset;
- int hdmi_config_offset;
- int hdmi_audio_workaround;
- int hdmi_buffer_status;
bool is_ext_encoder;
u16 caps;
};
@@ -476,6 +482,7 @@ extern u16 radeon_encoder_get_dp_bridge_encoder_id(struct drm_encoder *encoder);
extern u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector);
extern bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector);
extern bool radeon_connector_is_dp12_capable(struct drm_connector *connector);
+extern int radeon_get_monitor_bpc(struct drm_connector *connector);
extern void radeon_connector_hotplug(struct drm_connector *connector);
extern int radeon_dp_mode_valid_helper(struct drm_connector *connector,
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index df6a4dbd93f8..830f1a7b486f 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -104,7 +104,7 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
int radeon_bo_create(struct radeon_device *rdev,
unsigned long size, int byte_align, bool kernel, u32 domain,
- struct radeon_bo **bo_ptr)
+ struct sg_table *sg, struct radeon_bo **bo_ptr)
{
struct radeon_bo *bo;
enum ttm_bo_type type;
@@ -120,6 +120,8 @@ int radeon_bo_create(struct radeon_device *rdev,
}
if (kernel) {
type = ttm_bo_type_kernel;
+ } else if (sg) {
+ type = ttm_bo_type_sg;
} else {
type = ttm_bo_type_device;
}
@@ -155,7 +157,7 @@ retry:
mutex_lock(&rdev->vram_mutex);
r = ttm_bo_init(&rdev->mman.bdev, &bo->tbo, size, type,
&bo->placement, page_align, 0, !kernel, NULL,
- acc_size, &radeon_ttm_bo_destroy);
+ acc_size, sg, &radeon_ttm_bo_destroy);
mutex_unlock(&rdev->vram_mutex);
if (unlikely(r != 0)) {
if (r != -ERESTARTSYS) {
diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h
index f9104be88d7c..17fb99f177cf 100644
--- a/drivers/gpu/drm/radeon/radeon_object.h
+++ b/drivers/gpu/drm/radeon/radeon_object.h
@@ -111,9 +111,10 @@ extern int radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type,
bool no_wait);
extern int radeon_bo_create(struct radeon_device *rdev,
- unsigned long size, int byte_align,
- bool kernel, u32 domain,
- struct radeon_bo **bo_ptr);
+ unsigned long size, int byte_align,
+ bool kernel, u32 domain,
+ struct sg_table *sg,
+ struct radeon_bo **bo_ptr);
extern int radeon_bo_kmap(struct radeon_bo *bo, void **ptr);
extern void radeon_bo_kunmap(struct radeon_bo *bo);
extern void radeon_bo_unref(struct radeon_bo **bo);
@@ -146,6 +147,17 @@ extern struct radeon_bo_va *radeon_bo_va(struct radeon_bo *rbo,
/*
* sub allocation
*/
+
+static inline uint64_t radeon_sa_bo_gpu_addr(struct radeon_sa_bo *sa_bo)
+{
+ return sa_bo->manager->gpu_addr + sa_bo->soffset;
+}
+
+static inline void * radeon_sa_bo_cpu_addr(struct radeon_sa_bo *sa_bo)
+{
+ return sa_bo->manager->cpu_ptr + sa_bo->soffset;
+}
+
extern int radeon_sa_bo_manager_init(struct radeon_device *rdev,
struct radeon_sa_manager *sa_manager,
unsigned size, u32 domain);
@@ -157,9 +169,15 @@ extern int radeon_sa_bo_manager_suspend(struct radeon_device *rdev,
struct radeon_sa_manager *sa_manager);
extern int radeon_sa_bo_new(struct radeon_device *rdev,
struct radeon_sa_manager *sa_manager,
- struct radeon_sa_bo *sa_bo,
- unsigned size, unsigned align);
+ struct radeon_sa_bo **sa_bo,
+ unsigned size, unsigned align, bool block);
extern void radeon_sa_bo_free(struct radeon_device *rdev,
- struct radeon_sa_bo *sa_bo);
+ struct radeon_sa_bo **sa_bo,
+ struct radeon_fence *fence);
+#if defined(CONFIG_DEBUG_FS)
+extern void radeon_sa_bo_dump_debug_info(struct radeon_sa_manager *sa_manager,
+ struct seq_file *m);
+#endif
+
#endif
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index caa55d68f319..08825548ee69 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -252,10 +252,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev)
mutex_lock(&rdev->ddev->struct_mutex);
mutex_lock(&rdev->vram_mutex);
- for (i = 0; i < RADEON_NUM_RINGS; ++i) {
- if (rdev->ring[i].ring_obj)
- mutex_lock(&rdev->ring[i].mutex);
- }
+ mutex_lock(&rdev->ring_lock);
/* gui idle int has issues on older chips it seems */
if (rdev->family >= CHIP_R600) {
@@ -273,13 +270,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev)
} else {
struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
if (ring->ready) {
- struct radeon_fence *fence;
- radeon_ring_alloc(rdev, ring, 64);
- radeon_fence_create(rdev, &fence, radeon_ring_index(rdev, ring));
- radeon_fence_emit(rdev, fence);
- radeon_ring_commit(rdev, ring);
- radeon_fence_wait(fence, false);
- radeon_fence_unref(&fence);
+ radeon_fence_wait_empty_locked(rdev, RADEON_RING_TYPE_GFX_INDEX);
}
}
radeon_unmap_vram_bos(rdev);
@@ -311,10 +302,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev)
rdev->pm.dynpm_planned_action = DYNPM_ACTION_NONE;
- for (i = 0; i < RADEON_NUM_RINGS; ++i) {
- if (rdev->ring[i].ring_obj)
- mutex_unlock(&rdev->ring[i].mutex);
- }
+ mutex_unlock(&rdev->ring_lock);
mutex_unlock(&rdev->vram_mutex);
mutex_unlock(&rdev->ddev->struct_mutex);
}
diff --git a/drivers/gpu/drm/radeon/radeon_prime.c b/drivers/gpu/drm/radeon/radeon_prime.c
new file mode 100644
index 000000000000..b8f835d8ecb4
--- /dev/null
+++ b/drivers/gpu/drm/radeon/radeon_prime.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * based on nouveau_prime.c
+ *
+ * Authors: Alex Deucher
+ */
+#include "drmP.h"
+#include "drm.h"
+
+#include "radeon.h"
+#include "radeon_drm.h"
+
+#include <linux/dma-buf.h>
+
+static struct sg_table *radeon_gem_map_dma_buf(struct dma_buf_attachment *attachment,
+ enum dma_data_direction dir)
+{
+ struct radeon_bo *bo = attachment->dmabuf->priv;
+ struct drm_device *dev = bo->rdev->ddev;
+ int npages = bo->tbo.num_pages;
+ struct sg_table *sg;
+ int nents;
+
+ mutex_lock(&dev->struct_mutex);
+ sg = drm_prime_pages_to_sg(bo->tbo.ttm->pages, npages);
+ nents = dma_map_sg(attachment->dev, sg->sgl, sg->nents, dir);
+ mutex_unlock(&dev->struct_mutex);
+ return sg;
+}
+
+static void radeon_gem_unmap_dma_buf(struct dma_buf_attachment *attachment,
+ struct sg_table *sg, enum dma_data_direction dir)
+{
+ dma_unmap_sg(attachment->dev, sg->sgl, sg->nents, dir);
+ sg_free_table(sg);
+ kfree(sg);
+}
+
+static void radeon_gem_dmabuf_release(struct dma_buf *dma_buf)
+{
+ struct radeon_bo *bo = dma_buf->priv;
+
+ if (bo->gem_base.export_dma_buf == dma_buf) {
+ DRM_ERROR("unreference dmabuf %p\n", &bo->gem_base);
+ bo->gem_base.export_dma_buf = NULL;
+ drm_gem_object_unreference_unlocked(&bo->gem_base);
+ }
+}
+
+static void *radeon_gem_kmap_atomic(struct dma_buf *dma_buf, unsigned long page_num)
+{
+ return NULL;
+}
+
+static void radeon_gem_kunmap_atomic(struct dma_buf *dma_buf, unsigned long page_num, void *addr)
+{
+
+}
+static void *radeon_gem_kmap(struct dma_buf *dma_buf, unsigned long page_num)
+{
+ return NULL;
+}
+
+static void radeon_gem_kunmap(struct dma_buf *dma_buf, unsigned long page_num, void *addr)
+{
+
+}
+
+const static struct dma_buf_ops radeon_dmabuf_ops = {
+ .map_dma_buf = radeon_gem_map_dma_buf,
+ .unmap_dma_buf = radeon_gem_unmap_dma_buf,
+ .release = radeon_gem_dmabuf_release,
+ .kmap = radeon_gem_kmap,
+ .kmap_atomic = radeon_gem_kmap_atomic,
+ .kunmap = radeon_gem_kunmap,
+ .kunmap_atomic = radeon_gem_kunmap_atomic,
+};
+
+static int radeon_prime_create(struct drm_device *dev,
+ size_t size,
+ struct sg_table *sg,
+ struct radeon_bo **pbo)
+{
+ struct radeon_device *rdev = dev->dev_private;
+ struct radeon_bo *bo;
+ int ret;
+
+ ret = radeon_bo_create(rdev, size, PAGE_SIZE, false,
+ RADEON_GEM_DOMAIN_GTT, sg, pbo);
+ if (ret)
+ return ret;
+ bo = *pbo;
+ bo->gem_base.driver_private = bo;
+
+ mutex_lock(&rdev->gem.mutex);
+ list_add_tail(&bo->list, &rdev->gem.objects);
+ mutex_unlock(&rdev->gem.mutex);
+
+ return 0;
+}
+
+struct dma_buf *radeon_gem_prime_export(struct drm_device *dev,
+ struct drm_gem_object *obj,
+ int flags)
+{
+ struct radeon_bo *bo = gem_to_radeon_bo(obj);
+ int ret = 0;
+
+ /* pin buffer into GTT */
+ ret = radeon_bo_pin(bo, RADEON_GEM_DOMAIN_GTT, NULL);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return dma_buf_export(bo, &radeon_dmabuf_ops, obj->size, flags);
+}
+
+struct drm_gem_object *radeon_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *dma_buf)
+{
+ struct dma_buf_attachment *attach;
+ struct sg_table *sg;
+ struct radeon_bo *bo;
+ int ret;
+
+ if (dma_buf->ops == &radeon_dmabuf_ops) {
+ bo = dma_buf->priv;
+ if (bo->gem_base.dev == dev) {
+ drm_gem_object_reference(&bo->gem_base);
+ return &bo->gem_base;
+ }
+ }
+
+ /* need to attach */
+ attach = dma_buf_attach(dma_buf, dev->dev);
+ if (IS_ERR(attach))
+ return ERR_CAST(attach);
+
+ sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+ if (IS_ERR(sg)) {
+ ret = PTR_ERR(sg);
+ goto fail_detach;
+ }
+
+ ret = radeon_prime_create(dev, dma_buf->size, sg, &bo);
+ if (ret)
+ goto fail_unmap;
+
+ bo->gem_base.import_attach = attach;
+
+ return &bo->gem_base;
+
+fail_unmap:
+ dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);
+fail_detach:
+ dma_buf_detach(dma_buf, attach);
+ return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
index cc33b3d7c33b..493a7be75306 100644
--- a/drivers/gpu/drm/radeon/radeon_ring.c
+++ b/drivers/gpu/drm/radeon/radeon_ring.c
@@ -24,6 +24,7 @@
* Authors: Dave Airlie
* Alex Deucher
* Jerome Glisse
+ * Christian König
*/
#include <linux/seq_file.h>
#include <linux/slab.h>
@@ -33,8 +34,10 @@
#include "radeon.h"
#include "atom.h"
-int radeon_debugfs_ib_init(struct radeon_device *rdev);
-int radeon_debugfs_ring_init(struct radeon_device *rdev);
+/*
+ * IB.
+ */
+int radeon_debugfs_sa_init(struct radeon_device *rdev);
u32 radeon_get_ib_value(struct radeon_cs_parser *p, int idx)
{
@@ -61,123 +64,37 @@ u32 radeon_get_ib_value(struct radeon_cs_parser *p, int idx)
return idx_value;
}
-void radeon_ring_write(struct radeon_ring *ring, uint32_t v)
-{
-#if DRM_DEBUG_CODE
- if (ring->count_dw <= 0) {
- DRM_ERROR("radeon: writting more dword to ring than expected !\n");
- }
-#endif
- ring->ring[ring->wptr++] = v;
- ring->wptr &= ring->ptr_mask;
- ring->count_dw--;
- ring->ring_free_dw--;
-}
-
-/*
- * IB.
- */
-bool radeon_ib_try_free(struct radeon_device *rdev, struct radeon_ib *ib)
-{
- bool done = false;
-
- /* only free ib which have been emited */
- if (ib->fence && ib->fence->emitted) {
- if (radeon_fence_signaled(ib->fence)) {
- radeon_fence_unref(&ib->fence);
- radeon_sa_bo_free(rdev, &ib->sa_bo);
- done = true;
- }
- }
- return done;
-}
-
int radeon_ib_get(struct radeon_device *rdev, int ring,
- struct radeon_ib **ib, unsigned size)
+ struct radeon_ib *ib, unsigned size)
{
- struct radeon_fence *fence;
- unsigned cretry = 0;
- int r = 0, i, idx;
-
- *ib = NULL;
- /* align size on 256 bytes */
- size = ALIGN(size, 256);
+ int r;
- r = radeon_fence_create(rdev, &fence, ring);
+ r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo, &ib->sa_bo, size, 256, true);
if (r) {
- dev_err(rdev->dev, "failed to create fence for new IB\n");
+ dev_err(rdev->dev, "failed to get a new IB (%d)\n", r);
return r;
}
-
- radeon_mutex_lock(&rdev->ib_pool.mutex);
- idx = rdev->ib_pool.head_id;
-retry:
- if (cretry > 5) {
- dev_err(rdev->dev, "failed to get an ib after 5 retry\n");
- radeon_mutex_unlock(&rdev->ib_pool.mutex);
- radeon_fence_unref(&fence);
- return -ENOMEM;
- }
- cretry++;
- for (i = 0; i < RADEON_IB_POOL_SIZE; i++) {
- radeon_ib_try_free(rdev, &rdev->ib_pool.ibs[idx]);
- if (rdev->ib_pool.ibs[idx].fence == NULL) {
- r = radeon_sa_bo_new(rdev, &rdev->ib_pool.sa_manager,
- &rdev->ib_pool.ibs[idx].sa_bo,
- size, 256);
- if (!r) {
- *ib = &rdev->ib_pool.ibs[idx];
- (*ib)->ptr = rdev->ib_pool.sa_manager.cpu_ptr;
- (*ib)->ptr += ((*ib)->sa_bo.offset >> 2);
- (*ib)->gpu_addr = rdev->ib_pool.sa_manager.gpu_addr;
- (*ib)->gpu_addr += (*ib)->sa_bo.offset;
- (*ib)->fence = fence;
- (*ib)->vm_id = 0;
- (*ib)->is_const_ib = false;
- /* ib are most likely to be allocated in a ring fashion
- * thus rdev->ib_pool.head_id should be the id of the
- * oldest ib
- */
- rdev->ib_pool.head_id = (1 + idx);
- rdev->ib_pool.head_id &= (RADEON_IB_POOL_SIZE - 1);
- radeon_mutex_unlock(&rdev->ib_pool.mutex);
- return 0;
- }
- }
- idx = (idx + 1) & (RADEON_IB_POOL_SIZE - 1);
- }
- /* this should be rare event, ie all ib scheduled none signaled yet.
- */
- for (i = 0; i < RADEON_IB_POOL_SIZE; i++) {
- if (rdev->ib_pool.ibs[idx].fence && rdev->ib_pool.ibs[idx].fence->emitted) {
- r = radeon_fence_wait(rdev->ib_pool.ibs[idx].fence, false);
- if (!r) {
- goto retry;
- }
- /* an error happened */
- break;
- }
- idx = (idx + 1) & (RADEON_IB_POOL_SIZE - 1);
+ r = radeon_fence_create(rdev, &ib->fence, ring);
+ if (r) {
+ dev_err(rdev->dev, "failed to create fence for new IB (%d)\n", r);
+ radeon_sa_bo_free(rdev, &ib->sa_bo, NULL);
+ return r;
}
- radeon_mutex_unlock(&rdev->ib_pool.mutex);
- radeon_fence_unref(&fence);
- return r;
+
+ ib->ptr = radeon_sa_bo_cpu_addr(ib->sa_bo);
+ ib->gpu_addr = radeon_sa_bo_gpu_addr(ib->sa_bo);
+ ib->vm_id = 0;
+ ib->is_const_ib = false;
+ ib->semaphore = NULL;
+
+ return 0;
}
-void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib **ib)
+void radeon_ib_free(struct radeon_device *rdev, struct radeon_ib *ib)
{
- struct radeon_ib *tmp = *ib;
-
- *ib = NULL;
- if (tmp == NULL) {
- return;
- }
- radeon_mutex_lock(&rdev->ib_pool.mutex);
- if (tmp->fence && !tmp->fence->emitted) {
- radeon_sa_bo_free(rdev, &tmp->sa_bo);
- radeon_fence_unref(&tmp->fence);
- }
- radeon_mutex_unlock(&rdev->ib_pool.mutex);
+ radeon_semaphore_free(rdev, ib->semaphore, ib->fence);
+ radeon_sa_bo_free(rdev, &ib->sa_bo, ib->fence);
+ radeon_fence_unref(&ib->fence);
}
int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib)
@@ -187,14 +104,14 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib)
if (!ib->length_dw || !ring->ready) {
/* TODO: Nothings in the ib we should report. */
- DRM_ERROR("radeon: couldn't schedule IB(%u).\n", ib->idx);
+ dev_err(rdev->dev, "couldn't schedule ib\n");
return -EINVAL;
}
/* 64 dwords should be enough for fence too */
r = radeon_ring_lock(rdev, ring, 64);
if (r) {
- DRM_ERROR("radeon: scheduling IB failed (%d).\n", r);
+ dev_err(rdev->dev, "scheduling IB failed (%d).\n", r);
return r;
}
radeon_ring_ib_execute(rdev, ib->fence->ring, ib);
@@ -205,74 +122,90 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib)
int radeon_ib_pool_init(struct radeon_device *rdev)
{
- struct radeon_sa_manager tmp;
- int i, r;
+ int r;
- r = radeon_sa_bo_manager_init(rdev, &tmp,
+ if (rdev->ib_pool_ready) {
+ return 0;
+ }
+ r = radeon_sa_bo_manager_init(rdev, &rdev->ring_tmp_bo,
RADEON_IB_POOL_SIZE*64*1024,
RADEON_GEM_DOMAIN_GTT);
if (r) {
return r;
}
-
- radeon_mutex_lock(&rdev->ib_pool.mutex);
- if (rdev->ib_pool.ready) {
- radeon_mutex_unlock(&rdev->ib_pool.mutex);
- radeon_sa_bo_manager_fini(rdev, &tmp);
- return 0;
- }
-
- rdev->ib_pool.sa_manager = tmp;
- INIT_LIST_HEAD(&rdev->ib_pool.sa_manager.sa_bo);
- for (i = 0; i < RADEON_IB_POOL_SIZE; i++) {
- rdev->ib_pool.ibs[i].fence = NULL;
- rdev->ib_pool.ibs[i].idx = i;
- rdev->ib_pool.ibs[i].length_dw = 0;
- INIT_LIST_HEAD(&rdev->ib_pool.ibs[i].sa_bo.list);
- }
- rdev->ib_pool.head_id = 0;
- rdev->ib_pool.ready = true;
- DRM_INFO("radeon: ib pool ready.\n");
-
- if (radeon_debugfs_ib_init(rdev)) {
- DRM_ERROR("Failed to register debugfs file for IB !\n");
- }
- if (radeon_debugfs_ring_init(rdev)) {
- DRM_ERROR("Failed to register debugfs file for rings !\n");
+ rdev->ib_pool_ready = true;
+ if (radeon_debugfs_sa_init(rdev)) {
+ dev_err(rdev->dev, "failed to register debugfs file for SA\n");
}
- radeon_mutex_unlock(&rdev->ib_pool.mutex);
return 0;
}
void radeon_ib_pool_fini(struct radeon_device *rdev)
{
- unsigned i;
-
- radeon_mutex_lock(&rdev->ib_pool.mutex);
- if (rdev->ib_pool.ready) {
- for (i = 0; i < RADEON_IB_POOL_SIZE; i++) {
- radeon_sa_bo_free(rdev, &rdev->ib_pool.ibs[i].sa_bo);
- radeon_fence_unref(&rdev->ib_pool.ibs[i].fence);
- }
- radeon_sa_bo_manager_fini(rdev, &rdev->ib_pool.sa_manager);
- rdev->ib_pool.ready = false;
+ if (rdev->ib_pool_ready) {
+ radeon_sa_bo_manager_fini(rdev, &rdev->ring_tmp_bo);
+ rdev->ib_pool_ready = false;
}
- radeon_mutex_unlock(&rdev->ib_pool.mutex);
}
int radeon_ib_pool_start(struct radeon_device *rdev)
{
- return radeon_sa_bo_manager_start(rdev, &rdev->ib_pool.sa_manager);
+ return radeon_sa_bo_manager_start(rdev, &rdev->ring_tmp_bo);
}
int radeon_ib_pool_suspend(struct radeon_device *rdev)
{
- return radeon_sa_bo_manager_suspend(rdev, &rdev->ib_pool.sa_manager);
+ return radeon_sa_bo_manager_suspend(rdev, &rdev->ring_tmp_bo);
+}
+
+int radeon_ib_ring_tests(struct radeon_device *rdev)
+{
+ unsigned i;
+ int r;
+
+ for (i = 0; i < RADEON_NUM_RINGS; ++i) {
+ struct radeon_ring *ring = &rdev->ring[i];
+
+ if (!ring->ready)
+ continue;
+
+ r = radeon_ib_test(rdev, i, ring);
+ if (r) {
+ ring->ready = false;
+
+ if (i == RADEON_RING_TYPE_GFX_INDEX) {
+ /* oh, oh, that's really bad */
+ DRM_ERROR("radeon: failed testing IB on GFX ring (%d).\n", r);
+ rdev->accel_working = false;
+ return r;
+
+ } else {
+ /* still not good, but we can live with it */
+ DRM_ERROR("radeon: failed testing IB on ring %d (%d).\n", i, r);
+ }
+ }
+ }
+ return 0;
}
/*
* Ring.
*/
+int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring);
+
+void radeon_ring_write(struct radeon_ring *ring, uint32_t v)
+{
+#if DRM_DEBUG_CODE
+ if (ring->count_dw <= 0) {
+ DRM_ERROR("radeon: writting more dword to ring than expected !\n");
+ }
+#endif
+ ring->ring[ring->wptr++] = v;
+ ring->wptr &= ring->ptr_mask;
+ ring->count_dw--;
+ ring->ring_free_dw--;
+}
+
int radeon_ring_index(struct radeon_device *rdev, struct radeon_ring *ring)
{
/* r1xx-r5xx only has CP ring */
@@ -319,7 +252,7 @@ int radeon_ring_alloc(struct radeon_device *rdev, struct radeon_ring *ring, unsi
if (ndw < ring->ring_free_dw) {
break;
}
- r = radeon_fence_wait_next(rdev, radeon_ring_index(rdev, ring));
+ r = radeon_fence_wait_next_locked(rdev, radeon_ring_index(rdev, ring));
if (r)
return r;
}
@@ -332,10 +265,10 @@ int radeon_ring_lock(struct radeon_device *rdev, struct radeon_ring *ring, unsig
{
int r;
- mutex_lock(&ring->mutex);
+ mutex_lock(&rdev->ring_lock);
r = radeon_ring_alloc(rdev, ring, ndw);
if (r) {
- mutex_unlock(&ring->mutex);
+ mutex_unlock(&rdev->ring_lock);
return r;
}
return 0;
@@ -360,13 +293,85 @@ void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *ring)
void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *ring)
{
radeon_ring_commit(rdev, ring);
- mutex_unlock(&ring->mutex);
+ mutex_unlock(&rdev->ring_lock);
}
-void radeon_ring_unlock_undo(struct radeon_device *rdev, struct radeon_ring *ring)
+void radeon_ring_undo(struct radeon_ring *ring)
{
ring->wptr = ring->wptr_old;
- mutex_unlock(&ring->mutex);
+}
+
+void radeon_ring_unlock_undo(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+ radeon_ring_undo(ring);
+ mutex_unlock(&rdev->ring_lock);
+}
+
+void radeon_ring_force_activity(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+ int r;
+
+ radeon_ring_free_size(rdev, ring);
+ if (ring->rptr == ring->wptr) {
+ r = radeon_ring_alloc(rdev, ring, 1);
+ if (!r) {
+ radeon_ring_write(ring, ring->nop);
+ radeon_ring_commit(rdev, ring);
+ }
+ }
+}
+
+void radeon_ring_lockup_update(struct radeon_ring *ring)
+{
+ ring->last_rptr = ring->rptr;
+ ring->last_activity = jiffies;
+}
+
+/**
+ * radeon_ring_test_lockup() - check if ring is lockedup by recording information
+ * @rdev: radeon device structure
+ * @ring: radeon_ring structure holding ring information
+ *
+ * We don't need to initialize the lockup tracking information as we will either
+ * have CP rptr to a different value of jiffies wrap around which will force
+ * initialization of the lockup tracking informations.
+ *
+ * A possible false positivie is if we get call after while and last_cp_rptr ==
+ * the current CP rptr, even if it's unlikely it might happen. To avoid this
+ * if the elapsed time since last call is bigger than 2 second than we return
+ * false and update the tracking information. Due to this the caller must call
+ * radeon_ring_test_lockup several time in less than 2sec for lockup to be reported
+ * the fencing code should be cautious about that.
+ *
+ * Caller should write to the ring to force CP to do something so we don't get
+ * false positive when CP is just gived nothing to do.
+ *
+ **/
+bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+ unsigned long cjiffies, elapsed;
+ uint32_t rptr;
+
+ cjiffies = jiffies;
+ if (!time_after(cjiffies, ring->last_activity)) {
+ /* likely a wrap around */
+ radeon_ring_lockup_update(ring);
+ return false;
+ }
+ rptr = RREG32(ring->rptr_reg);
+ ring->rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
+ if (ring->rptr != ring->last_rptr) {
+ /* CP is still working no lockup */
+ radeon_ring_lockup_update(ring);
+ return false;
+ }
+ elapsed = jiffies_to_msecs(cjiffies - ring->last_activity);
+ if (radeon_lockup_timeout && elapsed >= radeon_lockup_timeout) {
+ dev_err(rdev->dev, "GPU lockup CP stall for more than %lumsec\n", elapsed);
+ return true;
+ }
+ /* give a chance to the GPU ... */
+ return false;
}
int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsigned ring_size,
@@ -385,8 +390,8 @@ int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsig
/* Allocate ring buffer */
if (ring->ring_obj == NULL) {
r = radeon_bo_create(rdev, ring->ring_size, PAGE_SIZE, true,
- RADEON_GEM_DOMAIN_GTT,
- &ring->ring_obj);
+ RADEON_GEM_DOMAIN_GTT,
+ NULL, &ring->ring_obj);
if (r) {
dev_err(rdev->dev, "(%d) ring create failed\n", r);
return r;
@@ -411,6 +416,9 @@ int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsig
}
ring->ptr_mask = (ring->ring_size / 4) - 1;
ring->ring_free_dw = ring->ring_size / 4;
+ if (radeon_debugfs_ring_init(rdev, ring)) {
+ DRM_ERROR("Failed to register debugfs file for rings !\n");
+ }
return 0;
}
@@ -419,11 +427,12 @@ void radeon_ring_fini(struct radeon_device *rdev, struct radeon_ring *ring)
int r;
struct radeon_bo *ring_obj;
- mutex_lock(&ring->mutex);
+ mutex_lock(&rdev->ring_lock);
ring_obj = ring->ring_obj;
+ ring->ready = false;
ring->ring = NULL;
ring->ring_obj = NULL;
- mutex_unlock(&ring->mutex);
+ mutex_unlock(&rdev->ring_lock);
if (ring_obj) {
r = radeon_bo_reserve(ring_obj, false);
@@ -476,59 +485,48 @@ static struct drm_info_list radeon_debugfs_ring_info_list[] = {
{"radeon_ring_cp2", radeon_debugfs_ring_info, 0, &cayman_ring_type_cp2_index},
};
-static int radeon_debugfs_ib_info(struct seq_file *m, void *data)
+static int radeon_debugfs_sa_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
struct radeon_device *rdev = dev->dev_private;
- struct radeon_ib *ib = &rdev->ib_pool.ibs[*((unsigned*)node->info_ent->data)];
- unsigned i;
- if (ib == NULL) {
- return 0;
- }
- seq_printf(m, "IB %04u\n", ib->idx);
- seq_printf(m, "IB fence %p\n", ib->fence);
- seq_printf(m, "IB size %05u dwords\n", ib->length_dw);
- for (i = 0; i < ib->length_dw; i++) {
- seq_printf(m, "[%05u]=0x%08X\n", i, ib->ptr[i]);
- }
+ radeon_sa_bo_dump_debug_info(&rdev->ring_tmp_bo, m);
+
return 0;
+
}
-static struct drm_info_list radeon_debugfs_ib_list[RADEON_IB_POOL_SIZE];
-static char radeon_debugfs_ib_names[RADEON_IB_POOL_SIZE][32];
-static unsigned radeon_debugfs_ib_idx[RADEON_IB_POOL_SIZE];
+static struct drm_info_list radeon_debugfs_sa_list[] = {
+ {"radeon_sa_info", &radeon_debugfs_sa_info, 0, NULL},
+};
+
#endif
-int radeon_debugfs_ring_init(struct radeon_device *rdev)
+int radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring)
{
#if defined(CONFIG_DEBUG_FS)
- if (rdev->family >= CHIP_CAYMAN)
- return radeon_debugfs_add_files(rdev, radeon_debugfs_ring_info_list,
- ARRAY_SIZE(radeon_debugfs_ring_info_list));
- else
- return radeon_debugfs_add_files(rdev, radeon_debugfs_ring_info_list, 1);
-#else
- return 0;
+ unsigned i;
+ for (i = 0; i < ARRAY_SIZE(radeon_debugfs_ring_info_list); ++i) {
+ struct drm_info_list *info = &radeon_debugfs_ring_info_list[i];
+ int ridx = *(int*)radeon_debugfs_ring_info_list[i].data;
+ unsigned r;
+
+ if (&rdev->ring[ridx] != ring)
+ continue;
+
+ r = radeon_debugfs_add_files(rdev, info, 1);
+ if (r)
+ return r;
+ }
#endif
+ return 0;
}
-int radeon_debugfs_ib_init(struct radeon_device *rdev)
+int radeon_debugfs_sa_init(struct radeon_device *rdev)
{
#if defined(CONFIG_DEBUG_FS)
- unsigned i;
-
- for (i = 0; i < RADEON_IB_POOL_SIZE; i++) {
- sprintf(radeon_debugfs_ib_names[i], "radeon_ib_%04u", i);
- radeon_debugfs_ib_idx[i] = i;
- radeon_debugfs_ib_list[i].name = radeon_debugfs_ib_names[i];
- radeon_debugfs_ib_list[i].show = &radeon_debugfs_ib_info;
- radeon_debugfs_ib_list[i].driver_features = 0;
- radeon_debugfs_ib_list[i].data = &radeon_debugfs_ib_idx[i];
- }
- return radeon_debugfs_add_files(rdev, radeon_debugfs_ib_list,
- RADEON_IB_POOL_SIZE);
+ return radeon_debugfs_add_files(rdev, radeon_debugfs_sa_list, 1);
#else
return 0;
#endif
diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c
index 4cce47e7dc0d..32059b745728 100644
--- a/drivers/gpu/drm/radeon/radeon_sa.c
+++ b/drivers/gpu/drm/radeon/radeon_sa.c
@@ -27,23 +27,45 @@
* Authors:
* Jerome Glisse <glisse@freedesktop.org>
*/
+/* Algorithm:
+ *
+ * We store the last allocated bo in "hole", we always try to allocate
+ * after the last allocated bo. Principle is that in a linear GPU ring
+ * progression was is after last is the oldest bo we allocated and thus
+ * the first one that should no longer be in use by the GPU.
+ *
+ * If it's not the case we skip over the bo after last to the closest
+ * done bo if such one exist. If none exist and we are not asked to
+ * block we report failure to allocate.
+ *
+ * If we are asked to block we wait on all the oldest fence of all
+ * rings. We just wait for any of those fence to complete.
+ */
#include "drmP.h"
#include "drm.h"
#include "radeon.h"
+static void radeon_sa_bo_remove_locked(struct radeon_sa_bo *sa_bo);
+static void radeon_sa_bo_try_free(struct radeon_sa_manager *sa_manager);
+
int radeon_sa_bo_manager_init(struct radeon_device *rdev,
struct radeon_sa_manager *sa_manager,
unsigned size, u32 domain)
{
- int r;
+ int i, r;
+ spin_lock_init(&sa_manager->lock);
sa_manager->bo = NULL;
sa_manager->size = size;
sa_manager->domain = domain;
- INIT_LIST_HEAD(&sa_manager->sa_bo);
+ sa_manager->hole = &sa_manager->olist;
+ INIT_LIST_HEAD(&sa_manager->olist);
+ for (i = 0; i < RADEON_NUM_RINGS; ++i) {
+ INIT_LIST_HEAD(&sa_manager->flist[i]);
+ }
r = radeon_bo_create(rdev, size, RADEON_GPU_PAGE_SIZE, true,
- RADEON_GEM_DOMAIN_CPU, &sa_manager->bo);
+ RADEON_GEM_DOMAIN_CPU, NULL, &sa_manager->bo);
if (r) {
dev_err(rdev->dev, "(%d) failed to allocate bo for manager\n", r);
return r;
@@ -57,11 +79,15 @@ void radeon_sa_bo_manager_fini(struct radeon_device *rdev,
{
struct radeon_sa_bo *sa_bo, *tmp;
- if (!list_empty(&sa_manager->sa_bo)) {
- dev_err(rdev->dev, "sa_manager is not empty, clearing anyway\n");
+ if (!list_empty(&sa_manager->olist)) {
+ sa_manager->hole = &sa_manager->olist,
+ radeon_sa_bo_try_free(sa_manager);
+ if (!list_empty(&sa_manager->olist)) {
+ dev_err(rdev->dev, "sa_manager is not empty, clearing anyway\n");
+ }
}
- list_for_each_entry_safe(sa_bo, tmp, &sa_manager->sa_bo, list) {
- list_del_init(&sa_bo->list);
+ list_for_each_entry_safe(sa_bo, tmp, &sa_manager->olist, olist) {
+ radeon_sa_bo_remove_locked(sa_bo);
}
radeon_bo_unref(&sa_manager->bo);
sa_manager->size = 0;
@@ -113,77 +139,248 @@ int radeon_sa_bo_manager_suspend(struct radeon_device *rdev,
return r;
}
-/*
- * Principe is simple, we keep a list of sub allocation in offset
- * order (first entry has offset == 0, last entry has the highest
- * offset).
- *
- * When allocating new object we first check if there is room at
- * the end total_size - (last_object_offset + last_object_size) >=
- * alloc_size. If so we allocate new object there.
- *
- * When there is not enough room at the end, we start waiting for
- * each sub object until we reach object_offset+object_size >=
- * alloc_size, this object then become the sub object we return.
- *
- * Alignment can't be bigger than page size
- */
+static void radeon_sa_bo_remove_locked(struct radeon_sa_bo *sa_bo)
+{
+ struct radeon_sa_manager *sa_manager = sa_bo->manager;
+ if (sa_manager->hole == &sa_bo->olist) {
+ sa_manager->hole = sa_bo->olist.prev;
+ }
+ list_del_init(&sa_bo->olist);
+ list_del_init(&sa_bo->flist);
+ radeon_fence_unref(&sa_bo->fence);
+ kfree(sa_bo);
+}
+
+static void radeon_sa_bo_try_free(struct radeon_sa_manager *sa_manager)
+{
+ struct radeon_sa_bo *sa_bo, *tmp;
+
+ if (sa_manager->hole->next == &sa_manager->olist)
+ return;
+
+ sa_bo = list_entry(sa_manager->hole->next, struct radeon_sa_bo, olist);
+ list_for_each_entry_safe_from(sa_bo, tmp, &sa_manager->olist, olist) {
+ if (sa_bo->fence == NULL || !radeon_fence_signaled(sa_bo->fence)) {
+ return;
+ }
+ radeon_sa_bo_remove_locked(sa_bo);
+ }
+}
+
+static inline unsigned radeon_sa_bo_hole_soffset(struct radeon_sa_manager *sa_manager)
+{
+ struct list_head *hole = sa_manager->hole;
+
+ if (hole != &sa_manager->olist) {
+ return list_entry(hole, struct radeon_sa_bo, olist)->eoffset;
+ }
+ return 0;
+}
+
+static inline unsigned radeon_sa_bo_hole_eoffset(struct radeon_sa_manager *sa_manager)
+{
+ struct list_head *hole = sa_manager->hole;
+
+ if (hole->next != &sa_manager->olist) {
+ return list_entry(hole->next, struct radeon_sa_bo, olist)->soffset;
+ }
+ return sa_manager->size;
+}
+
+static bool radeon_sa_bo_try_alloc(struct radeon_sa_manager *sa_manager,
+ struct radeon_sa_bo *sa_bo,
+ unsigned size, unsigned align)
+{
+ unsigned soffset, eoffset, wasted;
+
+ soffset = radeon_sa_bo_hole_soffset(sa_manager);
+ eoffset = radeon_sa_bo_hole_eoffset(sa_manager);
+ wasted = (align - (soffset % align)) % align;
+
+ if ((eoffset - soffset) >= (size + wasted)) {
+ soffset += wasted;
+
+ sa_bo->manager = sa_manager;
+ sa_bo->soffset = soffset;
+ sa_bo->eoffset = soffset + size;
+ list_add(&sa_bo->olist, sa_manager->hole);
+ INIT_LIST_HEAD(&sa_bo->flist);
+ sa_manager->hole = &sa_bo->olist;
+ return true;
+ }
+ return false;
+}
+
+static bool radeon_sa_bo_next_hole(struct radeon_sa_manager *sa_manager,
+ struct radeon_fence **fences,
+ unsigned *tries)
+{
+ struct radeon_sa_bo *best_bo = NULL;
+ unsigned i, soffset, best, tmp;
+
+ /* if hole points to the end of the buffer */
+ if (sa_manager->hole->next == &sa_manager->olist) {
+ /* try again with its beginning */
+ sa_manager->hole = &sa_manager->olist;
+ return true;
+ }
+
+ soffset = radeon_sa_bo_hole_soffset(sa_manager);
+ /* to handle wrap around we add sa_manager->size */
+ best = sa_manager->size * 2;
+ /* go over all fence list and try to find the closest sa_bo
+ * of the current last
+ */
+ for (i = 0; i < RADEON_NUM_RINGS; ++i) {
+ struct radeon_sa_bo *sa_bo;
+
+ if (list_empty(&sa_manager->flist[i])) {
+ continue;
+ }
+
+ sa_bo = list_first_entry(&sa_manager->flist[i],
+ struct radeon_sa_bo, flist);
+
+ if (!radeon_fence_signaled(sa_bo->fence)) {
+ fences[i] = sa_bo->fence;
+ continue;
+ }
+
+ /* limit the number of tries each ring gets */
+ if (tries[i] > 2) {
+ continue;
+ }
+
+ tmp = sa_bo->soffset;
+ if (tmp < soffset) {
+ /* wrap around, pretend it's after */
+ tmp += sa_manager->size;
+ }
+ tmp -= soffset;
+ if (tmp < best) {
+ /* this sa bo is the closest one */
+ best = tmp;
+ best_bo = sa_bo;
+ }
+ }
+
+ if (best_bo) {
+ ++tries[best_bo->fence->ring];
+ sa_manager->hole = best_bo->olist.prev;
+
+ /* we knew that this one is signaled,
+ so it's save to remote it */
+ radeon_sa_bo_remove_locked(best_bo);
+ return true;
+ }
+ return false;
+}
+
int radeon_sa_bo_new(struct radeon_device *rdev,
struct radeon_sa_manager *sa_manager,
- struct radeon_sa_bo *sa_bo,
- unsigned size, unsigned align)
+ struct radeon_sa_bo **sa_bo,
+ unsigned size, unsigned align, bool block)
{
- struct radeon_sa_bo *tmp;
- struct list_head *head;
- unsigned offset = 0, wasted = 0;
+ struct radeon_fence *fences[RADEON_NUM_RINGS];
+ unsigned tries[RADEON_NUM_RINGS];
+ int i, r = -ENOMEM;
BUG_ON(align > RADEON_GPU_PAGE_SIZE);
BUG_ON(size > sa_manager->size);
- /* no one ? */
- head = sa_manager->sa_bo.prev;
- if (list_empty(&sa_manager->sa_bo)) {
- goto out;
+ *sa_bo = kmalloc(sizeof(struct radeon_sa_bo), GFP_KERNEL);
+ if ((*sa_bo) == NULL) {
+ return -ENOMEM;
}
+ (*sa_bo)->manager = sa_manager;
+ (*sa_bo)->fence = NULL;
+ INIT_LIST_HEAD(&(*sa_bo)->olist);
+ INIT_LIST_HEAD(&(*sa_bo)->flist);
- /* look for a hole big enough */
- offset = 0;
- list_for_each_entry(tmp, &sa_manager->sa_bo, list) {
- /* room before this object ? */
- if ((tmp->offset - offset) >= size) {
- head = tmp->list.prev;
- goto out;
+ spin_lock(&sa_manager->lock);
+ do {
+ for (i = 0; i < RADEON_NUM_RINGS; ++i) {
+ fences[i] = NULL;
+ tries[i] = 0;
}
- offset = tmp->offset + tmp->size;
- wasted = offset % align;
- if (wasted) {
- wasted = align - wasted;
+
+ do {
+ radeon_sa_bo_try_free(sa_manager);
+
+ if (radeon_sa_bo_try_alloc(sa_manager, *sa_bo,
+ size, align)) {
+ spin_unlock(&sa_manager->lock);
+ return 0;
+ }
+
+ /* see if we can skip over some allocations */
+ } while (radeon_sa_bo_next_hole(sa_manager, fences, tries));
+
+ if (block) {
+ spin_unlock(&sa_manager->lock);
+ r = radeon_fence_wait_any(rdev, fences, false);
+ spin_lock(&sa_manager->lock);
+ if (r) {
+ /* if we have nothing to wait for we
+ are practically out of memory */
+ if (r == -ENOENT) {
+ r = -ENOMEM;
+ }
+ goto out_err;
+ }
}
- offset += wasted;
- }
- /* room at the end ? */
- head = sa_manager->sa_bo.prev;
- tmp = list_entry(head, struct radeon_sa_bo, list);
- offset = tmp->offset + tmp->size;
- wasted = offset % align;
- if (wasted) {
- wasted = align - wasted;
- }
- offset += wasted;
- if ((sa_manager->size - offset) < size) {
- /* failed to find somethings big enough */
- return -ENOMEM;
+ } while (block);
+
+out_err:
+ spin_unlock(&sa_manager->lock);
+ kfree(*sa_bo);
+ *sa_bo = NULL;
+ return r;
+}
+
+void radeon_sa_bo_free(struct radeon_device *rdev, struct radeon_sa_bo **sa_bo,
+ struct radeon_fence *fence)
+{
+ struct radeon_sa_manager *sa_manager;
+
+ if (sa_bo == NULL || *sa_bo == NULL) {
+ return;
}
-out:
- sa_bo->manager = sa_manager;
- sa_bo->offset = offset;
- sa_bo->size = size;
- list_add(&sa_bo->list, head);
- return 0;
+ sa_manager = (*sa_bo)->manager;
+ spin_lock(&sa_manager->lock);
+ if (fence && fence->seq && fence->seq < RADEON_FENCE_NOTEMITED_SEQ) {
+ (*sa_bo)->fence = radeon_fence_ref(fence);
+ list_add_tail(&(*sa_bo)->flist,
+ &sa_manager->flist[fence->ring]);
+ } else {
+ radeon_sa_bo_remove_locked(*sa_bo);
+ }
+ spin_unlock(&sa_manager->lock);
+ *sa_bo = NULL;
}
-void radeon_sa_bo_free(struct radeon_device *rdev, struct radeon_sa_bo *sa_bo)
+#if defined(CONFIG_DEBUG_FS)
+void radeon_sa_bo_dump_debug_info(struct radeon_sa_manager *sa_manager,
+ struct seq_file *m)
{
- list_del_init(&sa_bo->list);
+ struct radeon_sa_bo *i;
+
+ spin_lock(&sa_manager->lock);
+ list_for_each_entry(i, &sa_manager->olist, olist) {
+ if (&i->olist == sa_manager->hole) {
+ seq_printf(m, ">");
+ } else {
+ seq_printf(m, " ");
+ }
+ seq_printf(m, "[0x%08x 0x%08x] size %8d",
+ i->soffset, i->eoffset, i->eoffset - i->soffset);
+ if (i->fence) {
+ seq_printf(m, " protected by 0x%016llx on ring %d",
+ i->fence->seq, i->fence->ring);
+ }
+ seq_printf(m, "\n");
+ }
+ spin_unlock(&sa_manager->lock);
}
+#endif
diff --git a/drivers/gpu/drm/radeon/radeon_semaphore.c b/drivers/gpu/drm/radeon/radeon_semaphore.c
index 61dd4e3c9209..e2ace5dce117 100644
--- a/drivers/gpu/drm/radeon/radeon_semaphore.c
+++ b/drivers/gpu/drm/radeon/radeon_semaphore.c
@@ -31,148 +31,107 @@
#include "drm.h"
#include "radeon.h"
-static int radeon_semaphore_add_bo(struct radeon_device *rdev)
-{
- struct radeon_semaphore_bo *bo;
- unsigned long irq_flags;
- uint64_t gpu_addr;
- uint32_t *cpu_ptr;
- int r, i;
-
-
- bo = kmalloc(sizeof(struct radeon_semaphore_bo), GFP_KERNEL);
- if (bo == NULL) {
- return -ENOMEM;
- }
- INIT_LIST_HEAD(&bo->free);
- INIT_LIST_HEAD(&bo->list);
- bo->nused = 0;
-
- r = radeon_ib_get(rdev, 0, &bo->ib, RADEON_SEMAPHORE_BO_SIZE);
- if (r) {
- dev_err(rdev->dev, "failed to get a bo after 5 retry\n");
- kfree(bo);
- return r;
- }
- gpu_addr = rdev->ib_pool.sa_manager.gpu_addr;
- gpu_addr += bo->ib->sa_bo.offset;
- cpu_ptr = rdev->ib_pool.sa_manager.cpu_ptr;
- cpu_ptr += (bo->ib->sa_bo.offset >> 2);
- for (i = 0; i < (RADEON_SEMAPHORE_BO_SIZE/8); i++) {
- bo->semaphores[i].gpu_addr = gpu_addr;
- bo->semaphores[i].cpu_ptr = cpu_ptr;
- bo->semaphores[i].bo = bo;
- list_add_tail(&bo->semaphores[i].list, &bo->free);
- gpu_addr += 8;
- cpu_ptr += 2;
- }
- write_lock_irqsave(&rdev->semaphore_drv.lock, irq_flags);
- list_add_tail(&bo->list, &rdev->semaphore_drv.bo);
- write_unlock_irqrestore(&rdev->semaphore_drv.lock, irq_flags);
- return 0;
-}
-
-static void radeon_semaphore_del_bo_locked(struct radeon_device *rdev,
- struct radeon_semaphore_bo *bo)
-{
- radeon_sa_bo_free(rdev, &bo->ib->sa_bo);
- radeon_fence_unref(&bo->ib->fence);
- list_del(&bo->list);
- kfree(bo);
-}
-
-void radeon_semaphore_shrink_locked(struct radeon_device *rdev)
-{
- struct radeon_semaphore_bo *bo, *n;
-
- if (list_empty(&rdev->semaphore_drv.bo)) {
- return;
- }
- /* only shrink if first bo has free semaphore */
- bo = list_first_entry(&rdev->semaphore_drv.bo, struct radeon_semaphore_bo, list);
- if (list_empty(&bo->free)) {
- return;
- }
- list_for_each_entry_safe_continue(bo, n, &rdev->semaphore_drv.bo, list) {
- if (bo->nused)
- continue;
- radeon_semaphore_del_bo_locked(rdev, bo);
- }
-}
int radeon_semaphore_create(struct radeon_device *rdev,
struct radeon_semaphore **semaphore)
{
- struct radeon_semaphore_bo *bo;
- unsigned long irq_flags;
- bool do_retry = true;
int r;
-retry:
- *semaphore = NULL;
- write_lock_irqsave(&rdev->semaphore_drv.lock, irq_flags);
- list_for_each_entry(bo, &rdev->semaphore_drv.bo, list) {
- if (list_empty(&bo->free))
- continue;
- *semaphore = list_first_entry(&bo->free, struct radeon_semaphore, list);
- (*semaphore)->cpu_ptr[0] = 0;
- (*semaphore)->cpu_ptr[1] = 0;
- list_del(&(*semaphore)->list);
- bo->nused++;
- break;
- }
- write_unlock_irqrestore(&rdev->semaphore_drv.lock, irq_flags);
-
+ *semaphore = kmalloc(sizeof(struct radeon_semaphore), GFP_KERNEL);
if (*semaphore == NULL) {
- if (do_retry) {
- do_retry = false;
- r = radeon_semaphore_add_bo(rdev);
- if (r)
- return r;
- goto retry;
- }
return -ENOMEM;
}
-
+ r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo,
+ &(*semaphore)->sa_bo, 8, 8, true);
+ if (r) {
+ kfree(*semaphore);
+ *semaphore = NULL;
+ return r;
+ }
+ (*semaphore)->waiters = 0;
+ (*semaphore)->gpu_addr = radeon_sa_bo_gpu_addr((*semaphore)->sa_bo);
+ *((uint64_t*)radeon_sa_bo_cpu_addr((*semaphore)->sa_bo)) = 0;
return 0;
}
void radeon_semaphore_emit_signal(struct radeon_device *rdev, int ring,
struct radeon_semaphore *semaphore)
{
+ --semaphore->waiters;
radeon_semaphore_ring_emit(rdev, ring, &rdev->ring[ring], semaphore, false);
}
void radeon_semaphore_emit_wait(struct radeon_device *rdev, int ring,
struct radeon_semaphore *semaphore)
{
+ ++semaphore->waiters;
radeon_semaphore_ring_emit(rdev, ring, &rdev->ring[ring], semaphore, true);
}
-void radeon_semaphore_free(struct radeon_device *rdev,
- struct radeon_semaphore *semaphore)
+int radeon_semaphore_sync_rings(struct radeon_device *rdev,
+ struct radeon_semaphore *semaphore,
+ bool sync_to[RADEON_NUM_RINGS],
+ int dst_ring)
{
- unsigned long irq_flags;
+ int i = 0, r;
+
+ mutex_lock(&rdev->ring_lock);
+ r = radeon_ring_alloc(rdev, &rdev->ring[dst_ring], RADEON_NUM_RINGS * 8);
+ if (r) {
+ goto error;
+ }
+
+ for (i = 0; i < RADEON_NUM_RINGS; ++i) {
+ /* no need to sync to our own or unused rings */
+ if (!sync_to[i] || i == dst_ring)
+ continue;
- write_lock_irqsave(&rdev->semaphore_drv.lock, irq_flags);
- semaphore->bo->nused--;
- list_add_tail(&semaphore->list, &semaphore->bo->free);
- radeon_semaphore_shrink_locked(rdev);
- write_unlock_irqrestore(&rdev->semaphore_drv.lock, irq_flags);
+ /* prevent GPU deadlocks */
+ if (!rdev->ring[i].ready) {
+ dev_err(rdev->dev, "Trying to sync to a disabled ring!");
+ r = -EINVAL;
+ goto error;
+ }
+
+ r = radeon_ring_alloc(rdev, &rdev->ring[i], 8);
+ if (r) {
+ goto error;
+ }
+
+ radeon_semaphore_emit_signal(rdev, i, semaphore);
+ radeon_semaphore_emit_wait(rdev, dst_ring, semaphore);
+
+ radeon_ring_commit(rdev, &rdev->ring[i]);
+ }
+
+ radeon_ring_commit(rdev, &rdev->ring[dst_ring]);
+ mutex_unlock(&rdev->ring_lock);
+
+ return 0;
+
+error:
+ /* unlock all locks taken so far */
+ for (--i; i >= 0; --i) {
+ if (sync_to[i] || i == dst_ring) {
+ radeon_ring_undo(&rdev->ring[i]);
+ }
+ }
+ radeon_ring_undo(&rdev->ring[dst_ring]);
+ mutex_unlock(&rdev->ring_lock);
+ return r;
}
-void radeon_semaphore_driver_fini(struct radeon_device *rdev)
+void radeon_semaphore_free(struct radeon_device *rdev,
+ struct radeon_semaphore *semaphore,
+ struct radeon_fence *fence)
{
- struct radeon_semaphore_bo *bo, *n;
- unsigned long irq_flags;
-
- write_lock_irqsave(&rdev->semaphore_drv.lock, irq_flags);
- /* we force to free everything */
- list_for_each_entry_safe(bo, n, &rdev->semaphore_drv.bo, list) {
- if (!list_empty(&bo->free)) {
- dev_err(rdev->dev, "still in use semaphore\n");
- }
- radeon_semaphore_del_bo_locked(rdev, bo);
+ if (semaphore == NULL) {
+ return;
+ }
+ if (semaphore->waiters > 0) {
+ dev_err(rdev->dev, "semaphore %p has more waiters than signalers,"
+ " hardware lockup imminent!\n", semaphore);
}
- write_unlock_irqrestore(&rdev->semaphore_drv.lock, irq_flags);
+ radeon_sa_bo_free(rdev, &semaphore->sa_bo, fence);
+ kfree(semaphore);
}
diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c
index dc5dcf483aa3..efff929ea49d 100644
--- a/drivers/gpu/drm/radeon/radeon_test.c
+++ b/drivers/gpu/drm/radeon/radeon_test.c
@@ -59,7 +59,7 @@ void radeon_test_moves(struct radeon_device *rdev)
}
r = radeon_bo_create(rdev, size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM,
- &vram_obj);
+ NULL, &vram_obj);
if (r) {
DRM_ERROR("Failed to create VRAM object\n");
goto out_cleanup;
@@ -78,7 +78,7 @@ void radeon_test_moves(struct radeon_device *rdev)
void **vram_start, **vram_end;
r = radeon_bo_create(rdev, size, PAGE_SIZE, true,
- RADEON_GEM_DOMAIN_GTT, gtt_obj + i);
+ RADEON_GEM_DOMAIN_GTT, NULL, gtt_obj + i);
if (r) {
DRM_ERROR("Failed to create GTT object %d\n", i);
goto out_cleanup;
@@ -317,7 +317,7 @@ void radeon_test_ring_sync(struct radeon_device *rdev,
out_cleanup:
if (semaphore)
- radeon_semaphore_free(rdev, semaphore);
+ radeon_semaphore_free(rdev, semaphore, NULL);
if (fence1)
radeon_fence_unref(&fence1);
@@ -437,7 +437,7 @@ void radeon_test_ring_sync2(struct radeon_device *rdev,
out_cleanup:
if (semaphore)
- radeon_semaphore_free(rdev, semaphore);
+ radeon_semaphore_free(rdev, semaphore, NULL);
if (fenceA)
radeon_fence_unref(&fenceA);
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index f493c6403af5..c94a2257761f 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -222,8 +222,9 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,
{
struct radeon_device *rdev;
uint64_t old_start, new_start;
- struct radeon_fence *fence;
- int r, i;
+ struct radeon_fence *fence, *old_fence;
+ struct radeon_semaphore *sem = NULL;
+ int r;
rdev = radeon_get_rdev(bo->bdev);
r = radeon_fence_create(rdev, &fence, radeon_copy_ring_index(rdev));
@@ -242,6 +243,7 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,
break;
default:
DRM_ERROR("Unknown placement %d\n", old_mem->mem_type);
+ radeon_fence_unref(&fence);
return -EINVAL;
}
switch (new_mem->mem_type) {
@@ -253,42 +255,36 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,
break;
default:
DRM_ERROR("Unknown placement %d\n", old_mem->mem_type);
+ radeon_fence_unref(&fence);
return -EINVAL;
}
if (!rdev->ring[radeon_copy_ring_index(rdev)].ready) {
DRM_ERROR("Trying to move memory with ring turned off.\n");
+ radeon_fence_unref(&fence);
return -EINVAL;
}
BUILD_BUG_ON((PAGE_SIZE % RADEON_GPU_PAGE_SIZE) != 0);
/* sync other rings */
- if (rdev->family >= CHIP_R600) {
- for (i = 0; i < RADEON_NUM_RINGS; ++i) {
- /* no need to sync to our own or unused rings */
- if (i == radeon_copy_ring_index(rdev) || !rdev->ring[i].ready)
- continue;
-
- if (!fence->semaphore) {
- r = radeon_semaphore_create(rdev, &fence->semaphore);
- /* FIXME: handle semaphore error */
- if (r)
- continue;
- }
+ old_fence = bo->sync_obj;
+ if (old_fence && old_fence->ring != fence->ring
+ && !radeon_fence_signaled(old_fence)) {
+ bool sync_to_ring[RADEON_NUM_RINGS] = { };
+ sync_to_ring[old_fence->ring] = true;
+
+ r = radeon_semaphore_create(rdev, &sem);
+ if (r) {
+ radeon_fence_unref(&fence);
+ return r;
+ }
- r = radeon_ring_lock(rdev, &rdev->ring[i], 3);
- /* FIXME: handle ring lock error */
- if (r)
- continue;
- radeon_semaphore_emit_signal(rdev, i, fence->semaphore);
- radeon_ring_unlock_commit(rdev, &rdev->ring[i]);
-
- r = radeon_ring_lock(rdev, &rdev->ring[radeon_copy_ring_index(rdev)], 3);
- /* FIXME: handle ring lock error */
- if (r)
- continue;
- radeon_semaphore_emit_wait(rdev, radeon_copy_ring_index(rdev), fence->semaphore);
- radeon_ring_unlock_commit(rdev, &rdev->ring[radeon_copy_ring_index(rdev)]);
+ r = radeon_semaphore_sync_rings(rdev, sem,
+ sync_to_ring, fence->ring);
+ if (r) {
+ radeon_semaphore_free(rdev, sem, NULL);
+ radeon_fence_unref(&fence);
+ return r;
}
}
@@ -298,6 +294,7 @@ static int radeon_move_blit(struct ttm_buffer_object *bo,
/* FIXME: handle copy error */
r = ttm_bo_move_accel_cleanup(bo, (void *)fence, NULL,
evict, no_wait_reserve, no_wait_gpu, new_mem);
+ radeon_semaphore_free(rdev, sem, fence);
radeon_fence_unref(&fence);
return r;
}
@@ -614,10 +611,18 @@ static int radeon_ttm_tt_populate(struct ttm_tt *ttm)
struct radeon_ttm_tt *gtt = (void *)ttm;
unsigned i;
int r;
+ bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
if (ttm->state != tt_unpopulated)
return 0;
+ if (slave && ttm->sg) {
+ drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages,
+ gtt->ttm.dma_address, ttm->num_pages);
+ ttm->state = tt_unbound;
+ return 0;
+ }
+
rdev = radeon_get_rdev(ttm->bdev);
#if __OS_HAS_AGP
if (rdev->flags & RADEON_IS_AGP) {
@@ -658,6 +663,10 @@ static void radeon_ttm_tt_unpopulate(struct ttm_tt *ttm)
struct radeon_device *rdev;
struct radeon_ttm_tt *gtt = (void *)ttm;
unsigned i;
+ bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
+
+ if (slave)
+ return;
rdev = radeon_get_rdev(ttm->bdev);
#if __OS_HAS_AGP
@@ -729,8 +738,8 @@ int radeon_ttm_init(struct radeon_device *rdev)
return r;
}
r = radeon_bo_create(rdev, 256 * 1024, PAGE_SIZE, true,
- RADEON_GEM_DOMAIN_VRAM,
- &rdev->stollen_vga_memory);
+ RADEON_GEM_DOMAIN_VRAM,
+ NULL, &rdev->stollen_vga_memory);
if (r) {
return r;
}
diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c
index 4cf381b3a6d8..a464eb5e2df2 100644
--- a/drivers/gpu/drm/radeon/rs400.c
+++ b/drivers/gpu/drm/radeon/rs400.c
@@ -430,12 +430,9 @@ static int rs400_startup(struct radeon_device *rdev)
if (r)
return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
- if (r) {
- dev_err(rdev->dev, "failed testing IB (%d).\n", r);
- rdev->accel_working = false;
+ r = radeon_ib_ring_tests(rdev);
+ if (r)
return r;
- }
return 0;
}
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index d25cf869d08d..25f9eef12c42 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -396,7 +396,6 @@ int rs600_asic_reset(struct radeon_device *rdev)
/* Check if GPU is idle */
if (G_000E40_GA_BUSY(status) || G_000E40_VAP_BUSY(status)) {
dev_err(rdev->dev, "failed to reset GPU\n");
- rdev->gpu_lockup = true;
ret = -1;
} else
dev_info(rdev->dev, "GPU reset succeed\n");
@@ -553,6 +552,12 @@ int rs600_irq_set(struct radeon_device *rdev)
~S_007D08_DC_HOT_PLUG_DETECT1_INT_EN(1);
u32 hpd2 = RREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL) &
~S_007D18_DC_HOT_PLUG_DETECT2_INT_EN(1);
+ u32 hdmi0;
+ if (ASIC_IS_DCE2(rdev))
+ hdmi0 = RREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL) &
+ ~S_007408_HDMI0_AZ_FORMAT_WTRIG_MASK(1);
+ else
+ hdmi0 = 0;
if (!rdev->irq.installed) {
WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
@@ -579,10 +584,15 @@ int rs600_irq_set(struct radeon_device *rdev)
if (rdev->irq.hpd[1]) {
hpd2 |= S_007D18_DC_HOT_PLUG_DETECT2_INT_EN(1);
}
+ if (rdev->irq.afmt[0]) {
+ hdmi0 |= S_007408_HDMI0_AZ_FORMAT_WTRIG_MASK(1);
+ }
WREG32(R_000040_GEN_INT_CNTL, tmp);
WREG32(R_006540_DxMODE_INT_MASK, mode_int);
WREG32(R_007D08_DC_HOT_PLUG_DETECT1_INT_CONTROL, hpd1);
WREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL, hpd2);
+ if (ASIC_IS_DCE2(rdev))
+ WREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL, hdmi0);
return 0;
}
@@ -622,6 +632,17 @@ static inline u32 rs600_irq_ack(struct radeon_device *rdev)
rdev->irq.stat_regs.r500.disp_int = 0;
}
+ if (ASIC_IS_DCE2(rdev)) {
+ rdev->irq.stat_regs.r500.hdmi0_status = RREG32(R_007404_HDMI0_STATUS) &
+ S_007404_HDMI0_AZ_FORMAT_WTRIG(1);
+ if (G_007404_HDMI0_AZ_FORMAT_WTRIG(rdev->irq.stat_regs.r500.hdmi0_status)) {
+ tmp = RREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL);
+ tmp |= S_007408_HDMI0_AZ_FORMAT_WTRIG_ACK(1);
+ WREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL, tmp);
+ }
+ } else
+ rdev->irq.stat_regs.r500.hdmi0_status = 0;
+
if (irqs) {
WREG32(R_000044_GEN_INT_STATUS, irqs);
}
@@ -630,6 +651,9 @@ static inline u32 rs600_irq_ack(struct radeon_device *rdev)
void rs600_irq_disable(struct radeon_device *rdev)
{
+ u32 hdmi0 = RREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL) &
+ ~S_007408_HDMI0_AZ_FORMAT_WTRIG_MASK(1);
+ WREG32(R_007408_HDMI0_AUDIO_PACKET_CONTROL, hdmi0);
WREG32(R_000040_GEN_INT_CNTL, 0);
WREG32(R_006540_DxMODE_INT_MASK, 0);
/* Wait and acknowledge irq */
@@ -641,15 +665,20 @@ int rs600_irq_process(struct radeon_device *rdev)
{
u32 status, msi_rearm;
bool queue_hotplug = false;
+ bool queue_hdmi = false;
/* reset gui idle ack. the status bit is broken */
rdev->irq.gui_idle_acked = false;
status = rs600_irq_ack(rdev);
- if (!status && !rdev->irq.stat_regs.r500.disp_int) {
+ if (!status &&
+ !rdev->irq.stat_regs.r500.disp_int &&
+ !rdev->irq.stat_regs.r500.hdmi0_status) {
return IRQ_NONE;
}
- while (status || rdev->irq.stat_regs.r500.disp_int) {
+ while (status ||
+ rdev->irq.stat_regs.r500.disp_int ||
+ rdev->irq.stat_regs.r500.hdmi0_status) {
/* SW interrupt */
if (G_000044_SW_INT(status)) {
radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
@@ -687,12 +716,18 @@ int rs600_irq_process(struct radeon_device *rdev)
queue_hotplug = true;
DRM_DEBUG("HPD2\n");
}
+ if (G_007404_HDMI0_AZ_FORMAT_WTRIG(rdev->irq.stat_regs.r500.hdmi0_status)) {
+ queue_hdmi = true;
+ DRM_DEBUG("HDMI0\n");
+ }
status = rs600_irq_ack(rdev);
}
/* reset gui idle ack. the status bit is broken */
rdev->irq.gui_idle_acked = false;
if (queue_hotplug)
schedule_work(&rdev->hotplug_work);
+ if (queue_hdmi)
+ schedule_work(&rdev->audio_work);
if (rdev->msi_enabled) {
switch (rdev->family) {
case CHIP_RS600:
@@ -883,12 +918,9 @@ static int rs600_startup(struct radeon_device *rdev)
if (r)
return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
- if (r) {
- dev_err(rdev->dev, "failed testing IB (%d).\n", r);
- rdev->accel_working = false;
+ r = radeon_ib_ring_tests(rdev);
+ if (r)
return r;
- }
return 0;
}
diff --git a/drivers/gpu/drm/radeon/rs600d.h b/drivers/gpu/drm/radeon/rs600d.h
index a27c13ac47c3..f1f89414dc63 100644
--- a/drivers/gpu/drm/radeon/rs600d.h
+++ b/drivers/gpu/drm/radeon/rs600d.h
@@ -485,6 +485,20 @@
#define S_007D18_DC_HOT_PLUG_DETECT2_INT_EN(x) (((x) & 0x1) << 16)
#define G_007D18_DC_HOT_PLUG_DETECT2_INT_EN(x) (((x) >> 16) & 0x1)
#define C_007D18_DC_HOT_PLUG_DETECT2_INT_EN 0xFFFEFFFF
+#define R_007404_HDMI0_STATUS 0x007404
+#define S_007404_HDMI0_AZ_FORMAT_WTRIG(x) (((x) & 0x1) << 28)
+#define G_007404_HDMI0_AZ_FORMAT_WTRIG(x) (((x) >> 28) & 0x1)
+#define C_007404_HDMI0_AZ_FORMAT_WTRIG 0xEFFFFFFF
+#define S_007404_HDMI0_AZ_FORMAT_WTRIG_INT(x) (((x) & 0x1) << 29)
+#define G_007404_HDMI0_AZ_FORMAT_WTRIG_INT(x) (((x) >> 29) & 0x1)
+#define C_007404_HDMI0_AZ_FORMAT_WTRIG_INT 0xDFFFFFFF
+#define R_007408_HDMI0_AUDIO_PACKET_CONTROL 0x007408
+#define S_007408_HDMI0_AZ_FORMAT_WTRIG_MASK(x) (((x) & 0x1) << 28)
+#define G_007408_HDMI0_AZ_FORMAT_WTRIG_MASK(x) (((x) >> 28) & 0x1)
+#define C_007408_HDMI0_AZ_FORMAT_WTRIG_MASK 0xEFFFFFFF
+#define S_007408_HDMI0_AZ_FORMAT_WTRIG_ACK(x) (((x) & 0x1) << 29)
+#define G_007408_HDMI0_AZ_FORMAT_WTRIG_ACK(x) (((x) >> 29) & 0x1)
+#define C_007408_HDMI0_AZ_FORMAT_WTRIG_ACK 0xDFFFFFFF
/* MC registers */
#define R_000000_MC_STATUS 0x000000
diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c
index f2c3b9d75f18..3277ddecfe9f 100644
--- a/drivers/gpu/drm/radeon/rs690.c
+++ b/drivers/gpu/drm/radeon/rs690.c
@@ -647,12 +647,9 @@ static int rs690_startup(struct radeon_device *rdev)
if (r)
return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
- if (r) {
- dev_err(rdev->dev, "failed testing IB (%d).\n", r);
- rdev->accel_working = false;
+ r = radeon_ib_ring_tests(rdev);
+ if (r)
return r;
- }
return 0;
}
diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c
index d8d78fe17946..7f08cedb5333 100644
--- a/drivers/gpu/drm/radeon/rv515.c
+++ b/drivers/gpu/drm/radeon/rv515.c
@@ -412,12 +412,10 @@ static int rv515_startup(struct radeon_device *rdev)
if (r)
return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
- if (r) {
- dev_err(rdev->dev, "failed testing IB (%d).\n", r);
- rdev->accel_working = false;
+ r = radeon_ib_ring_tests(rdev);
+ if (r)
return r;
- }
+
return 0;
}
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index cdab1aeaed6e..c2f473bc13b8 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -1114,12 +1114,9 @@ static int rv770_startup(struct radeon_device *rdev)
if (r)
return r;
- r = radeon_ib_test(rdev, RADEON_RING_TYPE_GFX_INDEX, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]);
- if (r) {
- dev_err(rdev->dev, "IB test failed (%d).\n", r);
- rdev->accel_working = false;
+ r = radeon_ib_ring_tests(rdev);
+ if (r)
return r;
- }
return 0;
}
@@ -1178,10 +1175,6 @@ int rv770_init(struct radeon_device *rdev)
{
int r;
- /* This don't do much */
- r = radeon_gem_init(rdev);
- if (r)
- return r;
/* Read BIOS */
if (!radeon_get_bios(rdev)) {
if (ASIC_IS_AVIVO(rdev))
@@ -1281,7 +1274,6 @@ void rv770_fini(struct radeon_device *rdev)
rv770_pcie_gart_fini(rdev);
r600_vram_scratch_fini(rdev);
radeon_gem_fini(rdev);
- radeon_semaphore_driver_fini(rdev);
radeon_fence_driver_fini(rdev);
radeon_agp_fini(rdev);
radeon_bo_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h
index 79fa588e9ed5..9c549f702f2f 100644
--- a/drivers/gpu/drm/radeon/rv770d.h
+++ b/drivers/gpu/drm/radeon/rv770d.h
@@ -353,6 +353,197 @@
#define SRBM_STATUS 0x0E50
+/* DCE 3.2 HDMI */
+#define HDMI_CONTROL 0x7400
+# define HDMI_KEEPOUT_MODE (1 << 0)
+# define HDMI_PACKET_GEN_VERSION (1 << 4) /* 0 = r6xx compat */
+# define HDMI_ERROR_ACK (1 << 8)
+# define HDMI_ERROR_MASK (1 << 9)
+#define HDMI_STATUS 0x7404
+# define HDMI_ACTIVE_AVMUTE (1 << 0)
+# define HDMI_AUDIO_PACKET_ERROR (1 << 16)
+# define HDMI_VBI_PACKET_ERROR (1 << 20)
+#define HDMI_AUDIO_PACKET_CONTROL 0x7408
+# define HDMI_AUDIO_DELAY_EN(x) (((x) & 3) << 4)
+# define HDMI_AUDIO_PACKETS_PER_LINE(x) (((x) & 0x1f) << 16)
+#define HDMI_ACR_PACKET_CONTROL 0x740c
+# define HDMI_ACR_SEND (1 << 0)
+# define HDMI_ACR_CONT (1 << 1)
+# define HDMI_ACR_SELECT(x) (((x) & 3) << 4)
+# define HDMI_ACR_HW 0
+# define HDMI_ACR_32 1
+# define HDMI_ACR_44 2
+# define HDMI_ACR_48 3
+# define HDMI_ACR_SOURCE (1 << 8) /* 0 - hw; 1 - cts value */
+# define HDMI_ACR_AUTO_SEND (1 << 12)
+#define HDMI_VBI_PACKET_CONTROL 0x7410
+# define HDMI_NULL_SEND (1 << 0)
+# define HDMI_GC_SEND (1 << 4)
+# define HDMI_GC_CONT (1 << 5) /* 0 - once; 1 - every frame */
+#define HDMI_INFOFRAME_CONTROL0 0x7414
+# define HDMI_AVI_INFO_SEND (1 << 0)
+# define HDMI_AVI_INFO_CONT (1 << 1)
+# define HDMI_AUDIO_INFO_SEND (1 << 4)
+# define HDMI_AUDIO_INFO_CONT (1 << 5)
+# define HDMI_MPEG_INFO_SEND (1 << 8)
+# define HDMI_MPEG_INFO_CONT (1 << 9)
+#define HDMI_INFOFRAME_CONTROL1 0x7418
+# define HDMI_AVI_INFO_LINE(x) (((x) & 0x3f) << 0)
+# define HDMI_AUDIO_INFO_LINE(x) (((x) & 0x3f) << 8)
+# define HDMI_MPEG_INFO_LINE(x) (((x) & 0x3f) << 16)
+#define HDMI_GENERIC_PACKET_CONTROL 0x741c
+# define HDMI_GENERIC0_SEND (1 << 0)
+# define HDMI_GENERIC0_CONT (1 << 1)
+# define HDMI_GENERIC1_SEND (1 << 4)
+# define HDMI_GENERIC1_CONT (1 << 5)
+# define HDMI_GENERIC0_LINE(x) (((x) & 0x3f) << 16)
+# define HDMI_GENERIC1_LINE(x) (((x) & 0x3f) << 24)
+#define HDMI_GC 0x7428
+# define HDMI_GC_AVMUTE (1 << 0)
+#define AFMT_AUDIO_PACKET_CONTROL2 0x742c
+# define AFMT_AUDIO_LAYOUT_OVRD (1 << 0)
+# define AFMT_AUDIO_LAYOUT_SELECT (1 << 1)
+# define AFMT_60958_CS_SOURCE (1 << 4)
+# define AFMT_AUDIO_CHANNEL_ENABLE(x) (((x) & 0xff) << 8)
+# define AFMT_DP_AUDIO_STREAM_ID(x) (((x) & 0xff) << 16)
+#define AFMT_AVI_INFO0 0x7454
+# define AFMT_AVI_INFO_CHECKSUM(x) (((x) & 0xff) << 0)
+# define AFMT_AVI_INFO_S(x) (((x) & 3) << 8)
+# define AFMT_AVI_INFO_B(x) (((x) & 3) << 10)
+# define AFMT_AVI_INFO_A(x) (((x) & 1) << 12)
+# define AFMT_AVI_INFO_Y(x) (((x) & 3) << 13)
+# define AFMT_AVI_INFO_Y_RGB 0
+# define AFMT_AVI_INFO_Y_YCBCR422 1
+# define AFMT_AVI_INFO_Y_YCBCR444 2
+# define AFMT_AVI_INFO_Y_A_B_S(x) (((x) & 0xff) << 8)
+# define AFMT_AVI_INFO_R(x) (((x) & 0xf) << 16)
+# define AFMT_AVI_INFO_M(x) (((x) & 0x3) << 20)
+# define AFMT_AVI_INFO_C(x) (((x) & 0x3) << 22)
+# define AFMT_AVI_INFO_C_M_R(x) (((x) & 0xff) << 16)
+# define AFMT_AVI_INFO_SC(x) (((x) & 0x3) << 24)
+# define AFMT_AVI_INFO_Q(x) (((x) & 0x3) << 26)
+# define AFMT_AVI_INFO_EC(x) (((x) & 0x3) << 28)
+# define AFMT_AVI_INFO_ITC(x) (((x) & 0x1) << 31)
+# define AFMT_AVI_INFO_ITC_EC_Q_SC(x) (((x) & 0xff) << 24)
+#define AFMT_AVI_INFO1 0x7458
+# define AFMT_AVI_INFO_VIC(x) (((x) & 0x7f) << 0) /* don't use avi infoframe v1 */
+# define AFMT_AVI_INFO_PR(x) (((x) & 0xf) << 8) /* don't use avi infoframe v1 */
+# define AFMT_AVI_INFO_TOP(x) (((x) & 0xffff) << 16)
+#define AFMT_AVI_INFO2 0x745c
+# define AFMT_AVI_INFO_BOTTOM(x) (((x) & 0xffff) << 0)
+# define AFMT_AVI_INFO_LEFT(x) (((x) & 0xffff) << 16)
+#define AFMT_AVI_INFO3 0x7460
+# define AFMT_AVI_INFO_RIGHT(x) (((x) & 0xffff) << 0)
+# define AFMT_AVI_INFO_VERSION(x) (((x) & 3) << 24)
+#define AFMT_MPEG_INFO0 0x7464
+# define AFMT_MPEG_INFO_CHECKSUM(x) (((x) & 0xff) << 0)
+# define AFMT_MPEG_INFO_MB0(x) (((x) & 0xff) << 8)
+# define AFMT_MPEG_INFO_MB1(x) (((x) & 0xff) << 16)
+# define AFMT_MPEG_INFO_MB2(x) (((x) & 0xff) << 24)
+#define AFMT_MPEG_INFO1 0x7468
+# define AFMT_MPEG_INFO_MB3(x) (((x) & 0xff) << 0)
+# define AFMT_MPEG_INFO_MF(x) (((x) & 3) << 8)
+# define AFMT_MPEG_INFO_FR(x) (((x) & 1) << 12)
+#define AFMT_GENERIC0_HDR 0x746c
+#define AFMT_GENERIC0_0 0x7470
+#define AFMT_GENERIC0_1 0x7474
+#define AFMT_GENERIC0_2 0x7478
+#define AFMT_GENERIC0_3 0x747c
+#define AFMT_GENERIC0_4 0x7480
+#define AFMT_GENERIC0_5 0x7484
+#define AFMT_GENERIC0_6 0x7488
+#define AFMT_GENERIC1_HDR 0x748c
+#define AFMT_GENERIC1_0 0x7490
+#define AFMT_GENERIC1_1 0x7494
+#define AFMT_GENERIC1_2 0x7498
+#define AFMT_GENERIC1_3 0x749c
+#define AFMT_GENERIC1_4 0x74a0
+#define AFMT_GENERIC1_5 0x74a4
+#define AFMT_GENERIC1_6 0x74a8
+#define HDMI_ACR_32_0 0x74ac
+# define HDMI_ACR_CTS_32(x) (((x) & 0xfffff) << 12)
+#define HDMI_ACR_32_1 0x74b0
+# define HDMI_ACR_N_32(x) (((x) & 0xfffff) << 0)
+#define HDMI_ACR_44_0 0x74b4
+# define HDMI_ACR_CTS_44(x) (((x) & 0xfffff) << 12)
+#define HDMI_ACR_44_1 0x74b8
+# define HDMI_ACR_N_44(x) (((x) & 0xfffff) << 0)
+#define HDMI_ACR_48_0 0x74bc
+# define HDMI_ACR_CTS_48(x) (((x) & 0xfffff) << 12)
+#define HDMI_ACR_48_1 0x74c0
+# define HDMI_ACR_N_48(x) (((x) & 0xfffff) << 0)
+#define HDMI_ACR_STATUS_0 0x74c4
+#define HDMI_ACR_STATUS_1 0x74c8
+#define AFMT_AUDIO_INFO0 0x74cc
+# define AFMT_AUDIO_INFO_CHECKSUM(x) (((x) & 0xff) << 0)
+# define AFMT_AUDIO_INFO_CC(x) (((x) & 7) << 8)
+# define AFMT_AUDIO_INFO_CHECKSUM_OFFSET(x) (((x) & 0xff) << 16)
+#define AFMT_AUDIO_INFO1 0x74d0
+# define AFMT_AUDIO_INFO_CA(x) (((x) & 0xff) << 0)
+# define AFMT_AUDIO_INFO_LSV(x) (((x) & 0xf) << 11)
+# define AFMT_AUDIO_INFO_DM_INH(x) (((x) & 1) << 15)
+# define AFMT_AUDIO_INFO_DM_INH_LSV(x) (((x) & 0xff) << 8)
+#define AFMT_60958_0 0x74d4
+# define AFMT_60958_CS_A(x) (((x) & 1) << 0)
+# define AFMT_60958_CS_B(x) (((x) & 1) << 1)
+# define AFMT_60958_CS_C(x) (((x) & 1) << 2)
+# define AFMT_60958_CS_D(x) (((x) & 3) << 3)
+# define AFMT_60958_CS_MODE(x) (((x) & 3) << 6)
+# define AFMT_60958_CS_CATEGORY_CODE(x) (((x) & 0xff) << 8)
+# define AFMT_60958_CS_SOURCE_NUMBER(x) (((x) & 0xf) << 16)
+# define AFMT_60958_CS_CHANNEL_NUMBER_L(x) (((x) & 0xf) << 20)
+# define AFMT_60958_CS_SAMPLING_FREQUENCY(x) (((x) & 0xf) << 24)
+# define AFMT_60958_CS_CLOCK_ACCURACY(x) (((x) & 3) << 28)
+#define AFMT_60958_1 0x74d8
+# define AFMT_60958_CS_WORD_LENGTH(x) (((x) & 0xf) << 0)
+# define AFMT_60958_CS_ORIGINAL_SAMPLING_FREQUENCY(x) (((x) & 0xf) << 4)
+# define AFMT_60958_CS_VALID_L(x) (((x) & 1) << 16)
+# define AFMT_60958_CS_VALID_R(x) (((x) & 1) << 18)
+# define AFMT_60958_CS_CHANNEL_NUMBER_R(x) (((x) & 0xf) << 20)
+#define AFMT_AUDIO_CRC_CONTROL 0x74dc
+# define AFMT_AUDIO_CRC_EN (1 << 0)
+#define AFMT_RAMP_CONTROL0 0x74e0
+# define AFMT_RAMP_MAX_COUNT(x) (((x) & 0xffffff) << 0)
+# define AFMT_RAMP_DATA_SIGN (1 << 31)
+#define AFMT_RAMP_CONTROL1 0x74e4
+# define AFMT_RAMP_MIN_COUNT(x) (((x) & 0xffffff) << 0)
+# define AFMT_AUDIO_TEST_CH_DISABLE(x) (((x) & 0xff) << 24)
+#define AFMT_RAMP_CONTROL2 0x74e8
+# define AFMT_RAMP_INC_COUNT(x) (((x) & 0xffffff) << 0)
+#define AFMT_RAMP_CONTROL3 0x74ec
+# define AFMT_RAMP_DEC_COUNT(x) (((x) & 0xffffff) << 0)
+#define AFMT_60958_2 0x74f0
+# define AFMT_60958_CS_CHANNEL_NUMBER_2(x) (((x) & 0xf) << 0)
+# define AFMT_60958_CS_CHANNEL_NUMBER_3(x) (((x) & 0xf) << 4)
+# define AFMT_60958_CS_CHANNEL_NUMBER_4(x) (((x) & 0xf) << 8)
+# define AFMT_60958_CS_CHANNEL_NUMBER_5(x) (((x) & 0xf) << 12)
+# define AFMT_60958_CS_CHANNEL_NUMBER_6(x) (((x) & 0xf) << 16)
+# define AFMT_60958_CS_CHANNEL_NUMBER_7(x) (((x) & 0xf) << 20)
+#define AFMT_STATUS 0x7600
+# define AFMT_AUDIO_ENABLE (1 << 4)
+# define AFMT_AZ_FORMAT_WTRIG (1 << 28)
+# define AFMT_AZ_FORMAT_WTRIG_INT (1 << 29)
+# define AFMT_AZ_AUDIO_ENABLE_CHG (1 << 30)
+#define AFMT_AUDIO_PACKET_CONTROL 0x7604
+# define AFMT_AUDIO_SAMPLE_SEND (1 << 0)
+# define AFMT_AUDIO_TEST_EN (1 << 12)
+# define AFMT_AUDIO_CHANNEL_SWAP (1 << 24)
+# define AFMT_60958_CS_UPDATE (1 << 26)
+# define AFMT_AZ_AUDIO_ENABLE_CHG_MASK (1 << 27)
+# define AFMT_AZ_FORMAT_WTRIG_MASK (1 << 28)
+# define AFMT_AZ_FORMAT_WTRIG_ACK (1 << 29)
+# define AFMT_AZ_AUDIO_ENABLE_CHG_ACK (1 << 30)
+#define AFMT_VBI_PACKET_CONTROL 0x7608
+# define AFMT_GENERIC0_UPDATE (1 << 2)
+#define AFMT_INFOFRAME_CONTROL0 0x760c
+# define AFMT_AUDIO_INFO_SOURCE (1 << 6) /* 0 - sound block; 1 - hmdi regs */
+# define AFMT_AUDIO_INFO_UPDATE (1 << 7)
+# define AFMT_MPEG_INFO_UPDATE (1 << 10)
+#define AFMT_GENERIC0_7 0x7610
+/* second instance starts at 0x7800 */
+#define HDMI_OFFSET0 (0x7400 - 0x7400)
+#define HDMI_OFFSET1 (0x7800 - 0x7400)
+
#define D1GRPH_PRIMARY_SURFACE_ADDRESS 0x6110
#define D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x6914
#define D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x6114
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
index 27bda986fc2b..549732e56ca9 100644
--- a/drivers/gpu/drm/radeon/si.c
+++ b/drivers/gpu/drm/radeon/si.c
@@ -2217,8 +2217,6 @@ bool si_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
u32 srbm_status;
u32 grbm_status, grbm_status2;
u32 grbm_status_se0, grbm_status_se1;
- struct r100_gpu_lockup *lockup = &rdev->config.si.lockup;
- int r;
srbm_status = RREG32(SRBM_STATUS);
grbm_status = RREG32(GRBM_STATUS);
@@ -2226,20 +2224,12 @@ bool si_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
grbm_status_se0 = RREG32(GRBM_STATUS_SE0);
grbm_status_se1 = RREG32(GRBM_STATUS_SE1);
if (!(grbm_status & GUI_ACTIVE)) {
- r100_gpu_lockup_update(lockup, ring);
+ radeon_ring_lockup_update(ring);
return false;
}
/* force CP activities */
- r = radeon_ring_lock(rdev, ring, 2);
- if (!r) {
- /* PACKET2 NOP */
- radeon_ring_write(ring, 0x80000000);
- radeon_ring_write(ring, 0x80000000);
- radeon_ring_unlock_commit(rdev, ring);
- }
- /* XXX deal with CP0,1,2 */
- ring->rptr = RREG32(ring->rptr_reg);
- return r100_gpu_cp_is_lockup(rdev, lockup, ring);
+ radeon_ring_force_activity(rdev, ring);
+ return radeon_ring_test_lockup(rdev, ring);
}
static int si_gpu_soft_reset(struct radeon_device *rdev)
@@ -2275,6 +2265,7 @@ static int si_gpu_soft_reset(struct radeon_device *rdev)
SOFT_RESET_GDS |
SOFT_RESET_PA |
SOFT_RESET_SC |
+ SOFT_RESET_BCI |
SOFT_RESET_SPI |
SOFT_RESET_SX |
SOFT_RESET_TC |
@@ -2985,7 +2976,8 @@ int si_rlc_init(struct radeon_device *rdev)
/* save restore block */
if (rdev->rlc.save_restore_obj == NULL) {
r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true,
- RADEON_GEM_DOMAIN_VRAM, &rdev->rlc.save_restore_obj);
+ RADEON_GEM_DOMAIN_VRAM, NULL,
+ &rdev->rlc.save_restore_obj);
if (r) {
dev_warn(rdev->dev, "(%d) create RLC sr bo failed\n", r);
return r;
@@ -3009,7 +3001,8 @@ int si_rlc_init(struct radeon_device *rdev)
/* clear state block */
if (rdev->rlc.clear_state_obj == NULL) {
r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, PAGE_SIZE, true,
- RADEON_GEM_DOMAIN_VRAM, &rdev->rlc.clear_state_obj);
+ RADEON_GEM_DOMAIN_VRAM, NULL,
+ &rdev->rlc.clear_state_obj);
if (r) {
dev_warn(rdev->dev, "(%d) create RLC c bo failed\n", r);
si_rlc_fini(rdev);
@@ -3216,6 +3209,8 @@ static int si_irq_init(struct radeon_device *rdev)
/* force the active interrupt state to all disabled */
si_disable_interrupt_state(rdev);
+ pci_set_master(rdev->pdev);
+
/* enable irqs */
si_enable_interrupts(rdev);
@@ -3994,10 +3989,6 @@ int si_init(struct radeon_device *rdev)
struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
int r;
- /* This don't do much */
- r = radeon_gem_init(rdev);
- if (r)
- return r;
/* Read BIOS */
if (!radeon_get_bios(rdev)) {
if (ASIC_IS_AVIVO(rdev))
@@ -4117,7 +4108,6 @@ void si_fini(struct radeon_device *rdev)
si_pcie_gart_fini(rdev);
r600_vram_scratch_fini(rdev);
radeon_gem_fini(rdev);
- radeon_semaphore_driver_fini(rdev);
radeon_fence_driver_fini(rdev);
radeon_bo_fini(rdev);
radeon_atombios_fini(rdev);
diff --git a/drivers/gpu/drm/savage/savage_bci.c b/drivers/gpu/drm/savage/savage_bci.c
index cb1ee4e0050a..6eb507a5d130 100644
--- a/drivers/gpu/drm/savage/savage_bci.c
+++ b/drivers/gpu/drm/savage/savage_bci.c
@@ -735,7 +735,7 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
return -EINVAL;
}
drm_core_ioremap(dev->agp_buffer_map, dev);
- if (!dev->agp_buffer_map) {
+ if (!dev->agp_buffer_map->handle) {
DRM_ERROR("failed to ioremap DMA buffer region!\n");
savage_do_cleanup_bci(dev);
return -ENOMEM;
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 1f5c67c579cf..36792bd4da77 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -343,6 +343,16 @@ static int ttm_bo_add_ttm(struct ttm_buffer_object *bo, bool zero_alloc)
if (unlikely(bo->ttm == NULL))
ret = -ENOMEM;
break;
+ case ttm_bo_type_sg:
+ bo->ttm = bdev->driver->ttm_tt_create(bdev, bo->num_pages << PAGE_SHIFT,
+ page_flags | TTM_PAGE_FLAG_SG,
+ glob->dummy_read_page);
+ if (unlikely(bo->ttm == NULL)) {
+ ret = -ENOMEM;
+ break;
+ }
+ bo->ttm->sg = bo->sg;
+ break;
default:
pr_err("Illegal buffer object type\n");
ret = -EINVAL;
@@ -1169,6 +1179,7 @@ int ttm_bo_init(struct ttm_bo_device *bdev,
bool interruptible,
struct file *persistent_swap_storage,
size_t acc_size,
+ struct sg_table *sg,
void (*destroy) (struct ttm_buffer_object *))
{
int ret = 0;
@@ -1223,6 +1234,7 @@ int ttm_bo_init(struct ttm_bo_device *bdev,
bo->seq_valid = false;
bo->persistent_swap_storage = persistent_swap_storage;
bo->acc_size = acc_size;
+ bo->sg = sg;
atomic_inc(&bo->glob->bo_count);
ret = ttm_bo_check_placement(bo, placement);
@@ -1233,7 +1245,8 @@ int ttm_bo_init(struct ttm_bo_device *bdev,
* For ttm_bo_type_device buffers, allocate
* address space from the device.
*/
- if (bo->type == ttm_bo_type_device) {
+ if (bo->type == ttm_bo_type_device ||
+ bo->type == ttm_bo_type_sg) {
ret = ttm_bo_setup_vm(bo);
if (ret)
goto out_err;
@@ -1312,7 +1325,7 @@ int ttm_bo_create(struct ttm_bo_device *bdev,
ret = ttm_bo_init(bdev, bo, size, type, placement, page_alignment,
buffer_start, interruptible,
- persistent_swap_storage, acc_size, NULL);
+ persistent_swap_storage, acc_size, NULL, NULL);
if (likely(ret == 0))
*p_bo = bo;
diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c
index 53673907a6a0..4d02c46a9420 100644
--- a/drivers/gpu/drm/udl/udl_drv.c
+++ b/drivers/gpu/drm/udl/udl_drv.c
@@ -38,7 +38,7 @@ static void udl_usb_disconnect(struct usb_interface *interface)
drm_unplug_dev(dev);
}
-static struct vm_operations_struct udl_gem_vm_ops = {
+static const struct vm_operations_struct udl_gem_vm_ops = {
.fault = udl_gem_fault,
.open = drm_gem_vm_open,
.close = drm_gem_vm_close,
@@ -57,7 +57,7 @@ static const struct file_operations udl_driver_fops = {
};
static struct drm_driver driver = {
- .driver_features = DRIVER_MODESET | DRIVER_GEM,
+ .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
.load = udl_driver_load,
.unload = udl_driver_unload,
@@ -70,6 +70,10 @@ static struct drm_driver driver = {
.dumb_map_offset = udl_gem_mmap,
.dumb_destroy = udl_dumb_destroy,
.fops = &udl_driver_fops,
+
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_import = udl_gem_prime_import,
+
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
.date = DRIVER_DATE,
diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h
index 96820d03a303..fccd361f7b50 100644
--- a/drivers/gpu/drm/udl/udl_drv.h
+++ b/drivers/gpu/drm/udl/udl_drv.h
@@ -66,6 +66,7 @@ struct udl_gem_object {
struct drm_gem_object base;
struct page **pages;
void *vmapping;
+ struct sg_table *sg;
};
#define to_udl_bo(x) container_of(x, struct udl_gem_object, base)
@@ -118,6 +119,8 @@ int udl_gem_init_object(struct drm_gem_object *obj);
void udl_gem_free_object(struct drm_gem_object *gem_obj);
struct udl_gem_object *udl_gem_alloc_object(struct drm_device *dev,
size_t size);
+struct drm_gem_object *udl_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *dma_buf);
int udl_gem_vmap(struct udl_gem_object *obj);
void udl_gem_vunmap(struct udl_gem_object *obj);
diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c
index 4d9c3a5d8a45..a029ee39b0c5 100644
--- a/drivers/gpu/drm/udl/udl_fb.c
+++ b/drivers/gpu/drm/udl/udl_fb.c
@@ -593,11 +593,20 @@ udl_fb_user_fb_create(struct drm_device *dev,
struct drm_gem_object *obj;
struct udl_framebuffer *ufb;
int ret;
+ uint32_t size;
obj = drm_gem_object_lookup(dev, file, mode_cmd->handles[0]);
if (obj == NULL)
return ERR_PTR(-ENOENT);
+ size = mode_cmd->pitches[0] * mode_cmd->height;
+ size = ALIGN(size, PAGE_SIZE);
+
+ if (size > obj->size) {
+ DRM_ERROR("object size not sufficient for fb %d %zu %d %d\n", size, obj->size, mode_cmd->pitches[0], mode_cmd->height);
+ return ERR_PTR(-ENOMEM);
+ }
+
ufb = kzalloc(sizeof(*ufb), GFP_KERNEL);
if (ufb == NULL)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/gpu/drm/udl/udl_gem.c b/drivers/gpu/drm/udl/udl_gem.c
index 92f19ef329b0..40efd32f7dce 100644
--- a/drivers/gpu/drm/udl/udl_gem.c
+++ b/drivers/gpu/drm/udl/udl_gem.c
@@ -9,6 +9,7 @@
#include "drmP.h"
#include "udl_drv.h"
#include <linux/shmem_fs.h>
+#include <linux/dma-buf.h>
struct udl_gem_object *udl_gem_alloc_object(struct drm_device *dev,
size_t size)
@@ -161,6 +162,12 @@ static void udl_gem_put_pages(struct udl_gem_object *obj)
int page_count = obj->base.size / PAGE_SIZE;
int i;
+ if (obj->base.import_attach) {
+ drm_free_large(obj->pages);
+ obj->pages = NULL;
+ return;
+ }
+
for (i = 0; i < page_count; i++)
page_cache_release(obj->pages[i]);
@@ -195,6 +202,9 @@ void udl_gem_free_object(struct drm_gem_object *gem_obj)
{
struct udl_gem_object *obj = to_udl_bo(gem_obj);
+ if (gem_obj->import_attach)
+ drm_prime_gem_destroy(gem_obj, obj->sg);
+
if (obj->vmapping)
udl_gem_vunmap(obj);
@@ -239,3 +249,68 @@ unlock:
mutex_unlock(&dev->struct_mutex);
return ret;
}
+
+static int udl_prime_create(struct drm_device *dev,
+ size_t size,
+ struct sg_table *sg,
+ struct udl_gem_object **obj_p)
+{
+ struct udl_gem_object *obj;
+ int npages;
+ int i;
+ struct scatterlist *iter;
+
+ npages = size / PAGE_SIZE;
+
+ *obj_p = NULL;
+ obj = udl_gem_alloc_object(dev, npages * PAGE_SIZE);
+ if (!obj)
+ return -ENOMEM;
+
+ obj->sg = sg;
+ obj->pages = drm_malloc_ab(npages, sizeof(struct page *));
+ if (obj->pages == NULL) {
+ DRM_ERROR("obj pages is NULL %d\n", npages);
+ return -ENOMEM;
+ }
+
+ drm_prime_sg_to_page_addr_arrays(sg, obj->pages, NULL, npages);
+
+ *obj_p = obj;
+ return 0;
+}
+
+struct drm_gem_object *udl_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *dma_buf)
+{
+ struct dma_buf_attachment *attach;
+ struct sg_table *sg;
+ struct udl_gem_object *uobj;
+ int ret;
+
+ /* need to attach */
+ attach = dma_buf_attach(dma_buf, dev->dev);
+ if (IS_ERR(attach))
+ return ERR_PTR(PTR_ERR(attach));
+
+ sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
+ if (IS_ERR(sg)) {
+ ret = PTR_ERR(sg);
+ goto fail_detach;
+ }
+
+ ret = udl_prime_create(dev, dma_buf->size, sg, &uobj);
+ if (ret) {
+ goto fail_unmap;
+ }
+
+ uobj->base.import_attach = attach;
+
+ return &uobj->base;
+
+fail_unmap:
+ dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);
+fail_detach:
+ dma_buf_detach(dma_buf, attach);
+ return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
index b3ecb3d12a1d..0d7816789da1 100644
--- a/drivers/gpu/drm/udl/udl_modeset.c
+++ b/drivers/gpu/drm/udl/udl_modeset.c
@@ -395,7 +395,7 @@ int udl_modeset_init(struct drm_device *dev)
dev->mode_config.prefer_shadow = 0;
dev->mode_config.preferred_depth = 24;
- dev->mode_config.funcs = (void *)&udl_mode_funcs;
+ dev->mode_config.funcs = &udl_mode_funcs;
drm_mode_create_dirty_info_property(dev);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 2286d47e5022..6b0078ffa763 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -1178,7 +1178,7 @@ err_out:
return &vfb->base;
}
-static struct drm_mode_config_funcs vmw_kms_funcs = {
+static const struct drm_mode_config_funcs vmw_kms_funcs = {
.fb_create = vmw_kms_fb_create,
};
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
index a37abb581cbb..22bf9a21ec71 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
@@ -1567,7 +1567,7 @@ int vmw_dmabuf_init(struct vmw_private *dev_priv,
ret = ttm_bo_init(bdev, &vmw_bo->base, size,
ttm_bo_type_device, placement,
0, 0, interruptible,
- NULL, acc_size, bo_free);
+ NULL, acc_size, NULL, bo_free);
return ret;
}
diff --git a/drivers/gpu/vga/Kconfig b/drivers/gpu/vga/Kconfig
index 96c83a9a76bb..f34838839b08 100644
--- a/drivers/gpu/vga/Kconfig
+++ b/drivers/gpu/vga/Kconfig
@@ -21,6 +21,7 @@ config VGA_SWITCHEROO
bool "Laptop Hybrid Graphics - GPU switching support"
depends on X86
depends on ACPI
+ select VGA_ARB
help
Many laptops released in 2008/9/10 have two GPUs with a multiplexer
to switch between them. This adds support for dynamic switching when
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index 58434e804d91..38f9534ac513 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -28,15 +28,16 @@
#include <linux/pci.h>
#include <linux/vga_switcheroo.h>
+#include <linux/vgaarb.h>
+
struct vga_switcheroo_client {
struct pci_dev *pdev;
struct fb_info *fb_info;
int pwr_state;
- void (*set_gpu_state)(struct pci_dev *pdev, enum vga_switcheroo_state);
- void (*reprobe)(struct pci_dev *pdev);
- bool (*can_switch)(struct pci_dev *pdev);
+ const struct vga_switcheroo_client_ops *ops;
int id;
bool active;
+ struct list_head list;
};
static DEFINE_MUTEX(vgasr_mutex);
@@ -51,16 +52,23 @@ struct vgasr_priv {
struct dentry *switch_file;
int registered_clients;
- struct vga_switcheroo_client clients[VGA_SWITCHEROO_MAX_CLIENTS];
+ struct list_head clients;
struct vga_switcheroo_handler *handler;
};
+#define ID_BIT_AUDIO 0x100
+#define client_is_audio(c) ((c)->id & ID_BIT_AUDIO)
+#define client_is_vga(c) ((c)->id == -1 || !client_is_audio(c))
+#define client_id(c) ((c)->id & ~ID_BIT_AUDIO)
+
static int vga_switcheroo_debugfs_init(struct vgasr_priv *priv);
static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv);
/* only one switcheroo per system */
-static struct vgasr_priv vgasr_priv;
+static struct vgasr_priv vgasr_priv = {
+ .clients = LIST_HEAD_INIT(vgasr_priv.clients),
+};
int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
{
@@ -86,72 +94,119 @@ EXPORT_SYMBOL(vga_switcheroo_unregister_handler);
static void vga_switcheroo_enable(void)
{
- int i;
int ret;
+ struct vga_switcheroo_client *client;
+
/* call the handler to init */
vgasr_priv.handler->init();
- for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
- ret = vgasr_priv.handler->get_client_id(vgasr_priv.clients[i].pdev);
+ list_for_each_entry(client, &vgasr_priv.clients, list) {
+ if (client->id != -1)
+ continue;
+ ret = vgasr_priv.handler->get_client_id(client->pdev);
if (ret < 0)
return;
- vgasr_priv.clients[i].id = ret;
+ client->id = ret;
}
vga_switcheroo_debugfs_init(&vgasr_priv);
vgasr_priv.active = true;
}
-int vga_switcheroo_register_client(struct pci_dev *pdev,
- void (*set_gpu_state)(struct pci_dev *pdev, enum vga_switcheroo_state),
- void (*reprobe)(struct pci_dev *pdev),
- bool (*can_switch)(struct pci_dev *pdev))
+static int register_client(struct pci_dev *pdev,
+ const struct vga_switcheroo_client_ops *ops,
+ int id, bool active)
{
- int index;
+ struct vga_switcheroo_client *client;
+
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (!client)
+ return -ENOMEM;
+
+ client->pwr_state = VGA_SWITCHEROO_ON;
+ client->pdev = pdev;
+ client->ops = ops;
+ client->id = id;
+ client->active = active;
mutex_lock(&vgasr_mutex);
- /* don't do IGD vs DIS here */
- if (vgasr_priv.registered_clients & 1)
- index = 1;
- else
- index = 0;
-
- vgasr_priv.clients[index].pwr_state = VGA_SWITCHEROO_ON;
- vgasr_priv.clients[index].pdev = pdev;
- vgasr_priv.clients[index].set_gpu_state = set_gpu_state;
- vgasr_priv.clients[index].reprobe = reprobe;
- vgasr_priv.clients[index].can_switch = can_switch;
- vgasr_priv.clients[index].id = -1;
- if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)
- vgasr_priv.clients[index].active = true;
-
- vgasr_priv.registered_clients |= (1 << index);
+ list_add_tail(&client->list, &vgasr_priv.clients);
+ if (client_is_vga(client))
+ vgasr_priv.registered_clients++;
/* if we get two clients + handler */
- if (vgasr_priv.registered_clients == 0x3 && vgasr_priv.handler) {
+ if (!vgasr_priv.active &&
+ vgasr_priv.registered_clients == 2 && vgasr_priv.handler) {
printk(KERN_INFO "vga_switcheroo: enabled\n");
vga_switcheroo_enable();
}
mutex_unlock(&vgasr_mutex);
return 0;
}
+
+int vga_switcheroo_register_client(struct pci_dev *pdev,
+ const struct vga_switcheroo_client_ops *ops)
+{
+ return register_client(pdev, ops, -1,
+ pdev == vga_default_device());
+}
EXPORT_SYMBOL(vga_switcheroo_register_client);
+int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
+ const struct vga_switcheroo_client_ops *ops,
+ int id, bool active)
+{
+ return register_client(pdev, ops, id | ID_BIT_AUDIO, active);
+}
+EXPORT_SYMBOL(vga_switcheroo_register_audio_client);
+
+static struct vga_switcheroo_client *
+find_client_from_pci(struct list_head *head, struct pci_dev *pdev)
+{
+ struct vga_switcheroo_client *client;
+ list_for_each_entry(client, head, list)
+ if (client->pdev == pdev)
+ return client;
+ return NULL;
+}
+
+static struct vga_switcheroo_client *
+find_client_from_id(struct list_head *head, int client_id)
+{
+ struct vga_switcheroo_client *client;
+ list_for_each_entry(client, head, list)
+ if (client->id == client_id)
+ return client;
+ return NULL;
+}
+
+static struct vga_switcheroo_client *
+find_active_client(struct list_head *head)
+{
+ struct vga_switcheroo_client *client;
+ list_for_each_entry(client, head, list)
+ if (client->active && client_is_vga(client))
+ return client;
+ return NULL;
+}
+
void vga_switcheroo_unregister_client(struct pci_dev *pdev)
{
- int i;
+ struct vga_switcheroo_client *client;
mutex_lock(&vgasr_mutex);
- for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
- if (vgasr_priv.clients[i].pdev == pdev) {
- vgasr_priv.registered_clients &= ~(1 << i);
- break;
- }
+ client = find_client_from_pci(&vgasr_priv.clients, pdev);
+ if (client) {
+ if (client_is_vga(client))
+ vgasr_priv.registered_clients--;
+ list_del(&client->list);
+ kfree(client);
+ }
+ if (vgasr_priv.active && vgasr_priv.registered_clients < 2) {
+ printk(KERN_INFO "vga_switcheroo: disabled\n");
+ vga_switcheroo_debugfs_fini(&vgasr_priv);
+ vgasr_priv.active = false;
}
-
- printk(KERN_INFO "vga_switcheroo: disabled\n");
- vga_switcheroo_debugfs_fini(&vgasr_priv);
- vgasr_priv.active = false;
mutex_unlock(&vgasr_mutex);
}
EXPORT_SYMBOL(vga_switcheroo_unregister_client);
@@ -159,29 +214,29 @@ EXPORT_SYMBOL(vga_switcheroo_unregister_client);
void vga_switcheroo_client_fb_set(struct pci_dev *pdev,
struct fb_info *info)
{
- int i;
+ struct vga_switcheroo_client *client;
mutex_lock(&vgasr_mutex);
- for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
- if (vgasr_priv.clients[i].pdev == pdev) {
- vgasr_priv.clients[i].fb_info = info;
- break;
- }
- }
+ client = find_client_from_pci(&vgasr_priv.clients, pdev);
+ if (client)
+ client->fb_info = info;
mutex_unlock(&vgasr_mutex);
}
EXPORT_SYMBOL(vga_switcheroo_client_fb_set);
static int vga_switcheroo_show(struct seq_file *m, void *v)
{
- int i;
+ struct vga_switcheroo_client *client;
+ int i = 0;
mutex_lock(&vgasr_mutex);
- for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
- seq_printf(m, "%d:%s:%c:%s:%s\n", i,
- vgasr_priv.clients[i].id == VGA_SWITCHEROO_DIS ? "DIS" : "IGD",
- vgasr_priv.clients[i].active ? '+' : ' ',
- vgasr_priv.clients[i].pwr_state ? "Pwr" : "Off",
- pci_name(vgasr_priv.clients[i].pdev));
+ list_for_each_entry(client, &vgasr_priv.clients, list) {
+ seq_printf(m, "%d:%s%s:%c:%s:%s\n", i,
+ client_id(client) == VGA_SWITCHEROO_DIS ? "DIS" : "IGD",
+ client_is_vga(client) ? "" : "-Audio",
+ client->active ? '+' : ' ',
+ client->pwr_state ? "Pwr" : "Off",
+ pci_name(client->pdev));
+ i++;
}
mutex_unlock(&vgasr_mutex);
return 0;
@@ -197,7 +252,7 @@ static int vga_switchon(struct vga_switcheroo_client *client)
if (vgasr_priv.handler->power_state)
vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_ON);
/* call the driver callback to turn on device */
- client->set_gpu_state(client->pdev, VGA_SWITCHEROO_ON);
+ client->ops->set_gpu_state(client->pdev, VGA_SWITCHEROO_ON);
client->pwr_state = VGA_SWITCHEROO_ON;
return 0;
}
@@ -205,34 +260,39 @@ static int vga_switchon(struct vga_switcheroo_client *client)
static int vga_switchoff(struct vga_switcheroo_client *client)
{
/* call the driver callback to turn off device */
- client->set_gpu_state(client->pdev, VGA_SWITCHEROO_OFF);
+ client->ops->set_gpu_state(client->pdev, VGA_SWITCHEROO_OFF);
if (vgasr_priv.handler->power_state)
vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_OFF);
client->pwr_state = VGA_SWITCHEROO_OFF;
return 0;
}
+static void set_audio_state(int id, int state)
+{
+ struct vga_switcheroo_client *client;
+
+ client = find_client_from_id(&vgasr_priv.clients, id | ID_BIT_AUDIO);
+ if (client && client->pwr_state != state) {
+ client->ops->set_gpu_state(client->pdev, state);
+ client->pwr_state = state;
+ }
+}
+
/* stage one happens before delay */
static int vga_switchto_stage1(struct vga_switcheroo_client *new_client)
{
- int i;
- struct vga_switcheroo_client *active = NULL;
+ struct vga_switcheroo_client *active;
- for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
- if (vgasr_priv.clients[i].active == true) {
- active = &vgasr_priv.clients[i];
- break;
- }
- }
+ active = find_active_client(&vgasr_priv.clients);
if (!active)
return 0;
if (new_client->pwr_state == VGA_SWITCHEROO_OFF)
vga_switchon(new_client);
- /* swap shadow resource to denote boot VGA device has changed so X starts on new device */
- active->pdev->resource[PCI_ROM_RESOURCE].flags &= ~IORESOURCE_ROM_SHADOW;
- new_client->pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
+ vga_set_default_device(new_client->pdev);
+ set_audio_state(new_client->id, VGA_SWITCHEROO_ON);
+
return 0;
}
@@ -240,15 +300,9 @@ static int vga_switchto_stage1(struct vga_switcheroo_client *new_client)
static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
{
int ret;
- int i;
- struct vga_switcheroo_client *active = NULL;
+ struct vga_switcheroo_client *active;
- for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
- if (vgasr_priv.clients[i].active == true) {
- active = &vgasr_priv.clients[i];
- break;
- }
- }
+ active = find_active_client(&vgasr_priv.clients);
if (!active)
return 0;
@@ -264,8 +318,10 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
if (ret)
return ret;
- if (new_client->reprobe)
- new_client->reprobe(new_client->pdev);
+ if (new_client->ops->reprobe)
+ new_client->ops->reprobe(new_client->pdev);
+
+ set_audio_state(active->id, VGA_SWITCHEROO_OFF);
if (active->pwr_state == VGA_SWITCHEROO_ON)
vga_switchoff(active);
@@ -274,13 +330,26 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
return 0;
}
+static bool check_can_switch(void)
+{
+ struct vga_switcheroo_client *client;
+
+ list_for_each_entry(client, &vgasr_priv.clients, list) {
+ if (!client->ops->can_switch(client->pdev)) {
+ printk(KERN_ERR "vga_switcheroo: client %x refused switch\n", client->id);
+ return false;
+ }
+ }
+ return true;
+}
+
static ssize_t
vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
size_t cnt, loff_t *ppos)
{
char usercmd[64];
const char *pdev_name;
- int i, ret;
+ int ret;
bool delay = false, can_switch;
bool just_mux = false;
int client_id = -1;
@@ -301,21 +370,21 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
/* pwr off the device not in use */
if (strncmp(usercmd, "OFF", 3) == 0) {
- for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
- if (vgasr_priv.clients[i].active)
+ list_for_each_entry(client, &vgasr_priv.clients, list) {
+ if (client->active)
continue;
- if (vgasr_priv.clients[i].pwr_state == VGA_SWITCHEROO_ON)
- vga_switchoff(&vgasr_priv.clients[i]);
+ if (client->pwr_state == VGA_SWITCHEROO_ON)
+ vga_switchoff(client);
}
goto out;
}
/* pwr on the device not in use */
if (strncmp(usercmd, "ON", 2) == 0) {
- for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
- if (vgasr_priv.clients[i].active)
+ list_for_each_entry(client, &vgasr_priv.clients, list) {
+ if (client->active)
continue;
- if (vgasr_priv.clients[i].pwr_state == VGA_SWITCHEROO_OFF)
- vga_switchon(&vgasr_priv.clients[i]);
+ if (client->pwr_state == VGA_SWITCHEROO_OFF)
+ vga_switchon(client);
}
goto out;
}
@@ -348,13 +417,9 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
if (client_id == -1)
goto out;
-
- for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
- if (vgasr_priv.clients[i].id == client_id) {
- client = &vgasr_priv.clients[i];
- break;
- }
- }
+ client = find_client_from_id(&vgasr_priv.clients, client_id);
+ if (!client)
+ goto out;
vgasr_priv.delayed_switch_active = false;
@@ -363,23 +428,16 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
goto out;
}
- if (client->active == true)
+ if (client->active)
goto out;
/* okay we want a switch - test if devices are willing to switch */
- can_switch = true;
- for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
- can_switch = vgasr_priv.clients[i].can_switch(vgasr_priv.clients[i].pdev);
- if (can_switch == false) {
- printk(KERN_ERR "vga_switcheroo: client %d refused switch\n", i);
- break;
- }
- }
+ can_switch = check_can_switch();
if (can_switch == false && delay == false)
goto out;
- if (can_switch == true) {
+ if (can_switch) {
pdev_name = pci_name(client->pdev);
ret = vga_switchto_stage1(client);
if (ret)
@@ -451,10 +509,8 @@ fail:
int vga_switcheroo_process_delayed_switch(void)
{
- struct vga_switcheroo_client *client = NULL;
+ struct vga_switcheroo_client *client;
const char *pdev_name;
- bool can_switch = true;
- int i;
int ret;
int err = -EINVAL;
@@ -464,17 +520,9 @@ int vga_switcheroo_process_delayed_switch(void)
printk(KERN_INFO "vga_switcheroo: processing delayed switch to %d\n", vgasr_priv.delayed_client_id);
- for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
- if (vgasr_priv.clients[i].id == vgasr_priv.delayed_client_id)
- client = &vgasr_priv.clients[i];
- can_switch = vgasr_priv.clients[i].can_switch(vgasr_priv.clients[i].pdev);
- if (can_switch == false) {
- printk(KERN_ERR "vga_switcheroo: client %d refused switch\n", i);
- break;
- }
- }
-
- if (can_switch == false || client == NULL)
+ client = find_client_from_id(&vgasr_priv.clients,
+ vgasr_priv.delayed_client_id);
+ if (!client || !check_can_switch())
goto err;
pdev_name = pci_name(client->pdev);
diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c
index 111d956d8e7d..3df8fc0ec01a 100644
--- a/drivers/gpu/vga/vgaarb.c
+++ b/drivers/gpu/vga/vgaarb.c
@@ -136,6 +136,13 @@ struct pci_dev *vga_default_device(void)
{
return vga_default;
}
+
+EXPORT_SYMBOL_GPL(vga_default_device);
+
+void vga_set_default_device(struct pci_dev *pdev)
+{
+ vga_default = pdev;
+}
#endif
static inline void vga_irq_set_state(struct vga_device *vgadev, bool state)
@@ -605,10 +612,12 @@ static bool vga_arbiter_del_pci_device(struct pci_dev *pdev)
goto bail;
}
+#ifndef __ARCH_HAS_VGA_DEFAULT_DEVICE
if (vga_default == pdev) {
pci_dev_put(vga_default);
vga_default = NULL;
}
+#endif
if (vgadev->decodes & (VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM))
vga_decode_count--;
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index ffddcba32af6..034c80a10f1f 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -32,9 +32,13 @@ config HID
If unsure, say Y.
config HID_BATTERY_STRENGTH
- bool
+ bool "Battery level reporting for HID devices"
depends on HID && POWER_SUPPLY && HID = POWER_SUPPLY
default n
+ ---help---
+ This option adds support of reporting battery strength (for HID devices
+ that support this feature) through power_supply class so that userspace
+ tools, such as upower, can display it.
config HIDRAW
bool "/dev/hidraw raw HID device support"
@@ -60,6 +64,18 @@ source "drivers/hid/usbhid/Kconfig"
menu "Special HID drivers"
depends on HID
+config HID_GENERIC
+ tristate "Generic HID driver"
+ depends on HID
+ default y
+ ---help---
+ Support for generic HID devices.
+
+ To compile this driver as a module, choose M here: the module
+ will be called hid-generic.
+
+ If unsure, say Y.
+
config HID_A4TECH
tristate "A4 tech mice" if EXPERT
depends on USB_HID
@@ -92,6 +108,12 @@ config HID_APPLE
Say Y here if you want support for keyboards of Apple iBooks, PowerBooks,
MacBooks, MacBook Pros and Apple Aluminum.
+config HID_AUREAL
+ tristate "Aureal"
+ depends on USB_HID
+ ---help---
+ Support for Aureal Cy se W-01RN Remote Controller and other Aureal derived remotes.
+
config HID_BELKIN
tristate "Belkin Flip KVM and Wireless keyboard" if EXPERT
depends on USB_HID
@@ -448,7 +470,7 @@ config HID_PICOLCD_FB
select FB_SYS_FOPS
---help---
Provide access to PicoLCD's 256x64 monochrome display via a
- frambuffer device.
+ framebuffer device.
config HID_PICOLCD_BACKLIGHT
bool "Backlight control" if EXPERT
@@ -595,16 +617,10 @@ config THRUSTMASTER_FF
config HID_WACOM
tristate "Wacom Bluetooth devices support"
depends on BT_HIDP
- ---help---
- Support for Wacom Graphire Bluetooth tablet.
-
-config HID_WACOM_POWER_SUPPLY
- bool "Wacom Bluetooth devices power supply status support"
- depends on HID_WACOM
+ depends on LEDS_CLASS
select POWER_SUPPLY
---help---
- Say Y here if you want to enable power supply status monitoring for
- Wacom Bluetooth devices.
+ Support for Wacom Graphire Bluetooth and Intuos4 WL tablets.
config HID_WIIMOTE
tristate "Nintendo Wii Remote support"
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 22f1d16cd79c..ca6cc9f0485c 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -9,6 +9,8 @@ endif
obj-$(CONFIG_HID) += hid.o
+obj-$(CONFIG_HID_GENERIC) += hid-generic.o
+
hid-$(CONFIG_HIDRAW) += hidraw.o
hid-logitech-y := hid-lg.o
@@ -36,6 +38,7 @@ endif
obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
obj-$(CONFIG_HID_ACRUX) += hid-axff.o
obj-$(CONFIG_HID_APPLE) += hid-apple.o
+obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 299d23871122..fa10f847f7db 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -234,7 +234,7 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
}
}
- if (iso_layout) {
+ if (iso_layout) {
if (asc->quirks & APPLE_ISO_KEYBOARD) {
trans = apple_find_translation(apple_iso_keyboard, usage->code);
if (trans) {
@@ -458,6 +458,9 @@ static const struct hid_device_id apple_devices[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
APPLE_ISO_KEYBOARD },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
+ USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI),
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
diff --git a/drivers/hid/hid-aureal.c b/drivers/hid/hid-aureal.c
new file mode 100644
index 000000000000..ba64b041b8bf
--- /dev/null
+++ b/drivers/hid/hid-aureal.c
@@ -0,0 +1,54 @@
+/*
+ * HID driver for Aureal Cy se W-01RN USB_V3.1 devices
+ *
+ * Copyright (c) 2010 Franco Catrin <fcatrin@gmail.com>
+ * Copyright (c) 2010 Ben Cropley <bcropley@internode.on.net>
+ *
+ * Based on HID sunplus driver by
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ * Copyright (c) 2008 Jiri Slaby
+ */
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static __u8 *aureal_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
+{
+ if (*rsize >= 54 && rdesc[52] == 0x25 && rdesc[53] == 0x01) {
+ dev_info(&hdev->dev, "fixing Aureal Cy se W-01RN USB_V3.1 report descriptor.\n");
+ rdesc[53] = 0x65;
+ } return rdesc;
+}
+
+static const struct hid_device_id aureal_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, aureal_devices);
+
+static struct hid_driver aureal_driver = {
+ .name = "aureal",
+ .id_table = aureal_devices,
+ .report_fixup = aureal_report_fixup,
+};
+
+static int __init aureal_init(void)
+{
+ return hid_register_driver(&aureal_driver);
+}
+
+static void __exit aureal_exit(void)
+{
+ hid_unregister_driver(&aureal_driver);
+}
+
+module_init(aureal_init);
+module_exit(aureal_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 4da66b4b977c..8e3a6b261477 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -230,9 +230,16 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
return -1;
}
- if (parser->global.logical_maximum < parser->global.logical_minimum) {
- hid_err(parser->device, "logical range invalid %d %d\n",
- parser->global.logical_minimum, parser->global.logical_maximum);
+ /* Handle both signed and unsigned cases properly */
+ if ((parser->global.logical_minimum < 0 &&
+ parser->global.logical_maximum <
+ parser->global.logical_minimum) ||
+ (parser->global.logical_minimum >= 0 &&
+ (__u32)parser->global.logical_maximum <
+ (__u32)parser->global.logical_minimum)) {
+ dbg_hid("logical range invalid 0x%x 0x%x\n",
+ parser->global.logical_minimum,
+ parser->global.logical_maximum);
return -1;
}
@@ -546,12 +553,11 @@ static void hid_free_report(struct hid_report *report)
}
/*
- * Free a device structure, all reports, and all fields.
+ * Close report. This function returns the device
+ * state to the point prior to hid_open_report().
*/
-
-static void hid_device_release(struct device *dev)
+static void hid_close_report(struct hid_device *device)
{
- struct hid_device *device = container_of(dev, struct hid_device, dev);
unsigned i, j;
for (i = 0; i < HID_REPORT_TYPES; i++) {
@@ -562,11 +568,34 @@ static void hid_device_release(struct device *dev)
if (report)
hid_free_report(report);
}
+ memset(report_enum, 0, sizeof(*report_enum));
+ INIT_LIST_HEAD(&report_enum->report_list);
}
kfree(device->rdesc);
+ device->rdesc = NULL;
+ device->rsize = 0;
+
kfree(device->collection);
- kfree(device);
+ device->collection = NULL;
+ device->collection_size = 0;
+ device->maxcollection = 0;
+ device->maxapplication = 0;
+
+ device->status &= ~HID_STAT_PARSED;
+}
+
+/*
+ * Free a device structure, all reports, and all fields.
+ */
+
+static void hid_device_release(struct device *dev)
+{
+ struct hid_device *hid = container_of(dev, struct hid_device, dev);
+
+ hid_close_report(hid);
+ kfree(hid->dev_rdesc);
+ kfree(hid);
}
/*
@@ -636,6 +665,60 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
return NULL;
}
+static void hid_scan_usage(struct hid_device *hid, u32 usage)
+{
+ if (usage == HID_DG_CONTACTID)
+ hid->group = HID_GROUP_MULTITOUCH;
+}
+
+/*
+ * Scan a report descriptor before the device is added to the bus.
+ * Sets device groups and other properties that determine what driver
+ * to load.
+ */
+static int hid_scan_report(struct hid_device *hid)
+{
+ unsigned int page = 0, delim = 0;
+ __u8 *start = hid->dev_rdesc;
+ __u8 *end = start + hid->dev_rsize;
+ unsigned int u, u_min = 0, u_max = 0;
+ struct hid_item item;
+
+ hid->group = HID_GROUP_GENERIC;
+ while ((start = fetch_item(start, end, &item)) != NULL) {
+ if (item.format != HID_ITEM_FORMAT_SHORT)
+ return -EINVAL;
+ if (item.type == HID_ITEM_TYPE_GLOBAL) {
+ if (item.tag == HID_GLOBAL_ITEM_TAG_USAGE_PAGE)
+ page = item_udata(&item) << 16;
+ } else if (item.type == HID_ITEM_TYPE_LOCAL) {
+ if (delim > 1)
+ break;
+ u = item_udata(&item);
+ if (item.size <= 2)
+ u += page;
+ switch (item.tag) {
+ case HID_LOCAL_ITEM_TAG_DELIMITER:
+ delim += !!u;
+ break;
+ case HID_LOCAL_ITEM_TAG_USAGE:
+ hid_scan_usage(hid, u);
+ break;
+ case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
+ u_min = u;
+ break;
+ case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
+ u_max = u;
+ for (u = u_min; u <= u_max; u++)
+ hid_scan_usage(hid, u);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
/**
* hid_parse_report - parse device report
*
@@ -643,15 +726,37 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
* @start: report start
* @size: report size
*
+ * Allocate the device report as read by the bus driver. This function should
+ * only be called from parse() in ll drivers.
+ */
+int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size)
+{
+ hid->dev_rdesc = kmemdup(start, size, GFP_KERNEL);
+ if (!hid->dev_rdesc)
+ return -ENOMEM;
+ hid->dev_rsize = size;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hid_parse_report);
+
+/**
+ * hid_open_report - open a driver-specific device report
+ *
+ * @device: hid device
+ *
* Parse a report description into a hid_device structure. Reports are
* enumerated, fields are attached to these reports.
* 0 returned on success, otherwise nonzero error value.
+ *
+ * This function (or the equivalent hid_parse() macro) should only be
+ * called from probe() in drivers, before starting the device.
*/
-int hid_parse_report(struct hid_device *device, __u8 *start,
- unsigned size)
+int hid_open_report(struct hid_device *device)
{
struct hid_parser *parser;
struct hid_item item;
+ unsigned int size;
+ __u8 *start;
__u8 *end;
int ret;
static int (*dispatch_type[])(struct hid_parser *parser,
@@ -662,6 +767,14 @@ int hid_parse_report(struct hid_device *device, __u8 *start,
hid_parser_reserved
};
+ if (WARN_ON(device->status & HID_STAT_PARSED))
+ return -EBUSY;
+
+ start = device->dev_rdesc;
+ if (WARN_ON(!start))
+ return -ENODEV;
+ size = device->dev_rsize;
+
if (device->driver->report_fixup)
start = device->driver->report_fixup(device, start, &size);
@@ -679,6 +792,15 @@ int hid_parse_report(struct hid_device *device, __u8 *start,
parser->device = device;
end = start + size;
+
+ device->collection = kcalloc(HID_DEFAULT_NUM_COLLECTIONS,
+ sizeof(struct hid_collection), GFP_KERNEL);
+ if (!device->collection) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
+
ret = -EINVAL;
while ((start = fetch_item(start, end, &item)) != NULL) {
@@ -704,6 +826,7 @@ int hid_parse_report(struct hid_device *device, __u8 *start,
goto err;
}
vfree(parser);
+ device->status |= HID_STAT_PARSED;
return 0;
}
}
@@ -711,9 +834,10 @@ int hid_parse_report(struct hid_device *device, __u8 *start,
hid_err(device, "item fetching failed at offset %d\n", (int)(end - start));
err:
vfree(parser);
+ hid_close_report(device);
return ret;
}
-EXPORT_SYMBOL_GPL(hid_parse_report);
+EXPORT_SYMBOL_GPL(hid_open_report);
/*
* Convert a signed n-bit integer to signed 32-bit integer. Common
@@ -1032,7 +1156,7 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
return report;
}
-void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
+int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
int interrupt)
{
struct hid_report_enum *report_enum = hid->report_enum + type;
@@ -1040,10 +1164,11 @@ void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
unsigned int a;
int rsize, csize = size;
u8 *cdata = data;
+ int ret = 0;
report = hid_get_report(report_enum, data);
if (!report)
- return;
+ goto out;
if (report_enum->numbered) {
cdata++;
@@ -1063,14 +1188,19 @@ void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
hid->hiddev_report_event(hid, report);
- if (hid->claimed & HID_CLAIMED_HIDRAW)
- hidraw_report_event(hid, data, size);
+ if (hid->claimed & HID_CLAIMED_HIDRAW) {
+ ret = hidraw_report_event(hid, data, size);
+ if (ret)
+ goto out;
+ }
for (a = 0; a < report->maxfield; a++)
hid_input_field(hid, report->field[a], cdata, interrupt);
if (hid->claimed & HID_CLAIMED_INPUT)
hidinput_report_event(hid, report);
+out:
+ return ret;
}
EXPORT_SYMBOL_GPL(hid_report_raw_event);
@@ -1147,7 +1277,7 @@ nomem:
}
}
- hid_report_raw_event(hid, type, data, size, interrupt);
+ ret = hid_report_raw_event(hid, type, data, size, interrupt);
unlock:
up(&hid->driver_lock);
@@ -1158,7 +1288,8 @@ EXPORT_SYMBOL_GPL(hid_input_report);
static bool hid_match_one_id(struct hid_device *hdev,
const struct hid_device_id *id)
{
- return id->bus == hdev->bus &&
+ return (id->bus == HID_BUS_ANY || id->bus == hdev->bus) &&
+ (id->group == HID_GROUP_ANY || id->group == hdev->group) &&
(id->vendor == HID_ANY_ID || id->vendor == hdev->vendor) &&
(id->product == HID_ANY_ID || id->product == hdev->product);
}
@@ -1234,10 +1365,6 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
if ((connect_mask & HID_CONNECT_HIDINPUT) && !hidinput_connect(hdev,
connect_mask & HID_CONNECT_HIDINPUT_FORCE))
hdev->claimed |= HID_CLAIMED_INPUT;
- if (hdev->quirks & HID_QUIRK_MULTITOUCH) {
- /* this device should be handled by hid-multitouch, skip it */
- return -ENODEV;
- }
if ((connect_mask & HID_CONNECT_HIDDEV) && hdev->hiddev_connect &&
!hdev->hiddev_connect(hdev,
@@ -1314,13 +1441,10 @@ EXPORT_SYMBOL_GPL(hid_disconnect);
/* a list of devices for which there is a specialized driver on HID bus */
static const struct hid_device_id hid_have_special_driver[] = {
- { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
- { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
- { HID_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR, USB_DEVICE_ID_ACTIONSTAR_1011) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
@@ -1385,60 +1509,33 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
- { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) },
- { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) },
- { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) },
- { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
- { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) },
- { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) },
- { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) },
- { HID_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
- { HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, USB_DEVICE_ID_CVTOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
- { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_TRUETOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_725E) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
- { HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2515) },
{ HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) },
{ HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
- { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_FRUCTEL, USB_DEVICE_ID_GAMETEL_MT_MODE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) },
- { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) },
- { HID_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH, USB_DEVICE_ID_GOODTOUCH_000f) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
- { HID_USB_DEVICE(USB_VENDOR_ID_HANVON, USB_DEVICE_ID_HANVON_MULTITOUCH) },
- { HID_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT, USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) },
- { HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6650) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) },
- { HID_USB_DEVICE(USB_VENDOR_ID_ILITEK, USB_DEVICE_ID_ILITEK_MULTITOUCH) },
- { HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
@@ -1447,7 +1544,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) },
- { HID_USB_DEVICE(USB_VENDOR_ID_LG, USB_DEVICE_ID_LG_MULTITOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
@@ -1480,8 +1576,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) },
- { HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, USB_DEVICE_ID_CRYSTALTOUCH) },
- { HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, USB_DEVICE_ID_CRYSTALTOUCH_DUAL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) },
@@ -1513,15 +1607,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
- { HID_USB_DEVICE(USB_VENDOR_ID_PANASONIC, USB_DEVICE_ID_PANABOARD_UBT780) },
- { HID_USB_DEVICE(USB_VENDOR_ID_PANASONIC, USB_DEVICE_ID_PANABOARD_UBT880) },
- { HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_PCI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
- { HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN) },
- { HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1) },
- { HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) },
- { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
@@ -1538,9 +1625,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
- { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) },
- { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_MTP_STM) },
- { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, USB_DEVICE_ID_MTP_SITRONIX) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
@@ -1554,16 +1638,13 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
- { HID_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL, USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
- { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
- { HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) },
- { HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SUPER_JOY_BOX_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) },
@@ -1578,16 +1659,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_PID_0038) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
- { HID_USB_DEVICE(USB_VENDOR_ID_XAT, USB_DEVICE_ID_XAT_CSR) },
- { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_SPX) },
- { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_MPX) },
- { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR) },
- { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_SPX1) },
- { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_MPX1) },
- { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR1) },
- { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_SPX2) },
- { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_MPX2) },
- { HID_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) },
{ HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
@@ -1631,6 +1703,7 @@ static ssize_t store_new_id(struct device_driver *drv, const char *buf,
return -ENOMEM;
dynid->id.bus = bus;
+ dynid->id.group = HID_GROUP_ANY;
dynid->id.vendor = vendor;
dynid->id.product = product;
dynid->id.driver_data = driver_data;
@@ -1679,18 +1752,7 @@ static int hid_bus_match(struct device *dev, struct device_driver *drv)
struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver);
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
- if ((hdev->quirks & HID_QUIRK_MULTITOUCH) &&
- !strncmp(hdrv->name, "hid-multitouch", 14))
- return 1;
-
- if (!hid_match_device(hdev, hdrv))
- return 0;
-
- /* generic wants all that don't have specialized driver */
- if (!strncmp(hdrv->name, "generic-", 8) && !hid_ignore_special_drivers)
- return !hid_match_id(hdev, hid_have_special_driver);
-
- return 1;
+ return hid_match_device(hdev, hdrv) != NULL;
}
static int hid_device_probe(struct device *dev)
@@ -1707,23 +1769,22 @@ static int hid_device_probe(struct device *dev)
if (!hdev->driver) {
id = hid_match_device(hdev, hdrv);
if (id == NULL) {
- if (!((hdev->quirks & HID_QUIRK_MULTITOUCH) &&
- !strncmp(hdrv->name, "hid-multitouch", 14))) {
- ret = -ENODEV;
- goto unlock;
- }
+ ret = -ENODEV;
+ goto unlock;
}
hdev->driver = hdrv;
if (hdrv->probe) {
ret = hdrv->probe(hdev, id);
} else { /* default probe */
- ret = hid_parse(hdev);
+ ret = hid_open_report(hdev);
if (!ret)
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
}
- if (ret)
+ if (ret) {
+ hid_close_report(hdev);
hdev->driver = NULL;
+ }
}
unlock:
up(&hdev->driver_lock);
@@ -1744,6 +1805,7 @@ static int hid_device_remove(struct device *dev)
hdrv->remove(hdev);
else /* default remove */
hid_hw_stop(hdev);
+ hid_close_report(hdev);
hdev->driver = NULL;
}
@@ -1751,6 +1813,23 @@ static int hid_device_remove(struct device *dev)
return 0;
}
+static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
+ char *buf)
+{
+ struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ int len;
+
+ len = snprintf(buf, PAGE_SIZE, "hid:b%04Xg%04Xv%08Xp%08X\n",
+ hdev->bus, hdev->group, hdev->vendor, hdev->product);
+
+ return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
+}
+
+static struct device_attribute hid_dev_attrs[] = {
+ __ATTR_RO(modalias),
+ __ATTR_NULL,
+};
+
static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
@@ -1768,8 +1847,8 @@ static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
if (add_uevent_var(env, "HID_UNIQ=%s", hdev->uniq))
return -ENOMEM;
- if (add_uevent_var(env, "MODALIAS=hid:b%04Xv%08Xp%08X",
- hdev->bus, hdev->vendor, hdev->product))
+ if (add_uevent_var(env, "MODALIAS=hid:b%04Xg%04Xv%08Xp%08X",
+ hdev->bus, hdev->group, hdev->vendor, hdev->product))
return -ENOMEM;
return 0;
@@ -1777,6 +1856,7 @@ static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
static struct bus_type hid_bus_type = {
.name = "hid",
+ .dev_attrs = hid_dev_attrs,
.match = hid_bus_match,
.probe = hid_device_probe,
.remove = hid_device_remove,
@@ -2075,6 +2155,26 @@ int hid_add_device(struct hid_device *hdev)
&& (hid_ignore(hdev) || (hdev->quirks & HID_QUIRK_IGNORE)))
return -ENODEV;
+ /*
+ * Read the device report descriptor once and use as template
+ * for the driver-specific modifications.
+ */
+ ret = hdev->ll_driver->parse(hdev);
+ if (ret)
+ return ret;
+ if (!hdev->dev_rdesc)
+ return -ENODEV;
+
+ /*
+ * Scan generic devices for group information
+ */
+ if (hid_ignore_special_drivers ||
+ !hid_match_id(hdev, hid_have_special_driver)) {
+ ret = hid_scan_report(hdev);
+ if (ret)
+ hid_warn(hdev, "bad device descriptor (%d)\n", ret);
+ }
+
/* XXX hack, any other cleaner solution after the driver core
* is converted to allow more than 20 bytes as the device name? */
dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus,
@@ -2103,7 +2203,6 @@ EXPORT_SYMBOL_GPL(hid_add_device);
struct hid_device *hid_allocate_device(void)
{
struct hid_device *hdev;
- unsigned int i;
int ret = -ENOMEM;
hdev = kzalloc(sizeof(*hdev), GFP_KERNEL);
@@ -2114,23 +2213,13 @@ struct hid_device *hid_allocate_device(void)
hdev->dev.release = hid_device_release;
hdev->dev.bus = &hid_bus_type;
- hdev->collection = kcalloc(HID_DEFAULT_NUM_COLLECTIONS,
- sizeof(struct hid_collection), GFP_KERNEL);
- if (hdev->collection == NULL)
- goto err;
- hdev->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
-
- for (i = 0; i < HID_REPORT_TYPES; i++)
- INIT_LIST_HEAD(&hdev->report_enum[i].report_list);
+ hid_close_report(hdev);
init_waitqueue_head(&hdev->debug_wait);
INIT_LIST_HEAD(&hdev->debug_list);
sema_init(&hdev->driver_lock, 1);
return hdev;
-err:
- put_device(&hdev->dev);
- return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(hid_allocate_device);
@@ -2141,6 +2230,9 @@ static void hid_remove_device(struct hid_device *hdev)
hid_debug_unregister(hdev);
hdev->status &= ~HID_STAT_ADDED;
}
+ kfree(hdev->dev_rdesc);
+ hdev->dev_rdesc = NULL;
+ hdev->dev_rsize = 0;
}
/**
diff --git a/drivers/hid/hid-generic.c b/drivers/hid/hid-generic.c
new file mode 100644
index 000000000000..a8b3148e03a2
--- /dev/null
+++ b/drivers/hid/hid-generic.c
@@ -0,0 +1,53 @@
+/*
+ * HID support for Linux
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2007-2008 Oliver Neukum
+ * Copyright (c) 2006-2012 Jiri Kosina
+ * Copyright (c) 2012 Henrik Rydberg
+ */
+
+/*
+ * 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/slab.h>
+#include <linux/kernel.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+#include <linux/hid.h>
+
+static const struct hid_device_id hid_table[] = {
+ { HID_DEVICE(HID_BUS_ANY, HID_GROUP_GENERIC, HID_ANY_ID, HID_ANY_ID) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, hid_table);
+
+static struct hid_driver hid_generic = {
+ .name = "hid-generic",
+ .id_table = hid_table,
+};
+
+static int __init hid_init(void)
+{
+ return hid_register_driver(&hid_generic);
+}
+
+static void __exit hid_exit(void)
+{
+ hid_unregister_driver(&hid_generic);
+}
+
+module_init(hid_init);
+module_exit(hid_exit);
+
+MODULE_AUTHOR("Henrik Rydberg");
+MODULE_DESCRIPTION("HID generic driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
index 406632472c1b..3d62781b8993 100644
--- a/drivers/hid/hid-hyperv.c
+++ b/drivers/hid/hid-hyperv.c
@@ -430,6 +430,15 @@ cleanup:
return ret;
}
+static int mousevsc_hid_parse(struct hid_device *hid)
+{
+ struct hv_device *dev = hid_get_drvdata(hid);
+ struct mousevsc_dev *input_dev = hv_get_drvdata(dev);
+
+ return hid_parse_report(hid, input_dev->report_desc,
+ input_dev->report_desc_size);
+}
+
static int mousevsc_hid_open(struct hid_device *hid)
{
return 0;
@@ -449,6 +458,7 @@ static void mousevsc_hid_stop(struct hid_device *hid)
}
static struct hid_ll_driver mousevsc_ll_driver = {
+ .parse = mousevsc_hid_parse,
.open = mousevsc_hid_open,
.close = mousevsc_hid_close,
.start = mousevsc_hid_start,
@@ -506,13 +516,14 @@ static int mousevsc_probe(struct hv_device *device,
sprintf(hid_dev->name, "%s", "Microsoft Vmbus HID-compliant Mouse");
+ hid_set_drvdata(hid_dev, device);
+
ret = hid_add_device(hid_dev);
if (ret)
goto probe_err1;
- ret = hid_parse_report(hid_dev, input_dev->report_desc,
- input_dev->report_desc_size);
+ ret = hid_parse(hid_dev);
if (ret) {
hid_err(hid_dev, "parse failed\n");
goto probe_err2;
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index e39aecb1f9f2..9373f535dfe9 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -154,9 +154,15 @@
#define USB_DEVICE_ID_ATMEL_MULTITOUCH 0x211c
#define USB_DEVICE_ID_ATMEL_MXT_DIGITIZER 0x2118
+#define USB_VENDOR_ID_AUREAL 0x0755
+#define USB_DEVICE_ID_AUREAL_W01RN 0x2626
+
#define USB_VENDOR_ID_AVERMEDIA 0x07ca
#define USB_DEVICE_ID_AVER_FM_MR800 0xb800
+#define USB_VENDOR_ID_BAANTO 0x2453
+#define USB_DEVICE_ID_BAANTO_MT_190W2 0x0100
+
#define USB_VENDOR_ID_BELKIN 0x050d
#define USB_DEVICE_ID_FLIP_KVM 0x3201
@@ -726,6 +732,7 @@
#define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U 0x0004
#define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005
#define USB_DEVICE_ID_UCLOGIC_TABLET_WP1062 0x0064
+#define USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850 0x0522
#define USB_VENDOR_ID_UNITEC 0x227d
#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 0x0709
@@ -749,6 +756,7 @@
#define USB_DEVICE_ID_WALTOP_PID_0038 0x0038
#define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH 0x0501
#define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH 0x0500
+#define USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET 0x0502
#define USB_VENDOR_ID_WISEGROUP 0x0925
#define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 002781c5a616..132b0019365e 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -225,7 +225,10 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
* Verify and convert units.
* See HID specification v1.11 6.2.2.7 Global Items for unit decoding
*/
- if (code == ABS_X || code == ABS_Y || code == ABS_Z) {
+ switch (code) {
+ case ABS_X:
+ case ABS_Y:
+ case ABS_Z:
if (field->unit == 0x11) { /* If centimeters */
/* Convert to millimeters */
unit_exponent += 1;
@@ -239,7 +242,13 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
} else {
return 0;
}
- } else if (code == ABS_RX || code == ABS_RY || code == ABS_RZ) {
+ break;
+
+ case ABS_RX:
+ case ABS_RY:
+ case ABS_RZ:
+ case ABS_TILT_X:
+ case ABS_TILT_Y:
if (field->unit == 0x14) { /* If degrees */
/* Convert to radians */
prev = logical_extents;
@@ -250,7 +259,9 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
} else if (field->unit != 0x12) { /* If not radians */
return 0;
}
- } else {
+ break;
+
+ default:
return 0;
}
@@ -623,6 +634,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
map_key_clear(BTN_TOOL_RUBBER);
break;
+ case 0x3d: /* X Tilt */
+ map_abs_clear(ABS_TILT_X);
+ break;
+
+ case 0x3e: /* Y Tilt */
+ map_abs_clear(ABS_TILT_Y);
+ break;
+
case 0x33: /* Touch */
case 0x42: /* TipSwitch */
case 0x43: /* TipSwitch2 */
@@ -638,10 +657,6 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
map_key_clear(BTN_STYLUS2);
break;
- case 0x51: /* ContactID */
- device->quirks |= HID_QUIRK_MULTITOUCH;
- goto unknown;
-
default: goto unknown;
}
break;
@@ -1208,13 +1223,6 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
}
}
- if (hid->quirks & HID_QUIRK_MULTITOUCH) {
- /* generic hid does not know how to handle multitouch devices */
- if (hidinput)
- goto out_cleanup;
- goto out_unwind;
- }
-
if (hidinput && input_register_device(hidinput->input))
goto out_cleanup;
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index e7a7bd1eb34a..fc37ed6b108c 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -109,23 +109,23 @@ static __u8 dfp_rdesc_fixed[] = {
static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
- unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+ struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
- if ((quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
+ if ((drv_data->quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
rdesc[84] == 0x8c && rdesc[85] == 0x02) {
hid_info(hdev,
"fixing up Logitech keyboard report descriptor\n");
rdesc[84] = rdesc[89] = 0x4d;
rdesc[85] = rdesc[90] = 0x10;
}
- if ((quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
+ if ((drv_data->quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
rdesc[49] == 0x81 && rdesc[50] == 0x06) {
hid_info(hdev,
"fixing up rel/abs in Logitech report descriptor\n");
rdesc[33] = rdesc[50] = 0x02;
}
- if ((quirks & LG_FF4) && *rsize >= 101 &&
+ if ((drv_data->quirks & LG_FF4) && *rsize >= 101 &&
rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
rdesc[47] == 0x05 && rdesc[48] == 0x09) {
hid_info(hdev, "fixing up Logitech Speed Force Wireless button descriptor\n");
@@ -278,7 +278,7 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
0, 0, 0, 0, 0,183,184,185,186,187,
188,189,190,191,192,193,194, 0, 0, 0
};
- unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+ struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
unsigned int hid = usage->hid;
if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
@@ -289,7 +289,7 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
lg_dinovo_mapping(hi, usage, bit, max))
return 1;
- if ((quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
+ if ((drv_data->quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
return 1;
if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
@@ -299,11 +299,11 @@ static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
/* Special handling for Logitech Cordless Desktop */
if (field->application == HID_GD_MOUSE) {
- if ((quirks & LG_IGNORE_DOUBLED_WHEEL) &&
+ if ((drv_data->quirks & LG_IGNORE_DOUBLED_WHEEL) &&
(hid == 7 || hid == 8))
return -1;
} else {
- if ((quirks & LG_EXPANDED_KEYMAP) &&
+ if ((drv_data->quirks & LG_EXPANDED_KEYMAP) &&
hid < ARRAY_SIZE(e_keymap) &&
e_keymap[hid] != 0) {
hid_map_usage(hi, usage, bit, max, EV_KEY,
@@ -319,13 +319,13 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
- unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+ struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
- if ((quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
+ if ((drv_data->quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
(field->flags & HID_MAIN_ITEM_RELATIVE))
field->flags &= ~HID_MAIN_ITEM_RELATIVE;
- if ((quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
+ if ((drv_data->quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
usage->type == EV_REL || usage->type == EV_ABS))
clear_bit(usage->code, *bit);
@@ -335,9 +335,9 @@ static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
static int lg_event(struct hid_device *hdev, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
- unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+ struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
- if ((quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
+ if ((drv_data->quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
input_event(field->hidinput->input, usage->type, usage->code,
-value);
return 1;
@@ -348,13 +348,20 @@ static int lg_event(struct hid_device *hdev, struct hid_field *field,
static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
- unsigned long quirks = id->driver_data;
unsigned int connect_mask = HID_CONNECT_DEFAULT;
+ struct lg_drv_data *drv_data;
int ret;
- hid_set_drvdata(hdev, (void *)quirks);
+ drv_data = kzalloc(sizeof(struct lg_drv_data), GFP_KERNEL);
+ if (!drv_data) {
+ hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
+ return -ENOMEM;
+ }
+ drv_data->quirks = id->driver_data;
+
+ hid_set_drvdata(hdev, (void *)drv_data);
- if (quirks & LG_NOGET)
+ if (drv_data->quirks & LG_NOGET)
hdev->quirks |= HID_QUIRK_NOGET;
ret = hid_parse(hdev);
@@ -363,7 +370,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_free;
}
- if (quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
+ if (drv_data->quirks & (LG_FF | LG_FF2 | LG_FF3 | LG_FF4))
connect_mask &= ~HID_CONNECT_FF;
ret = hid_hw_start(hdev, connect_mask);
@@ -392,27 +399,29 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
}
}
- if (quirks & LG_FF)
+ if (drv_data->quirks & LG_FF)
lgff_init(hdev);
- if (quirks & LG_FF2)
+ if (drv_data->quirks & LG_FF2)
lg2ff_init(hdev);
- if (quirks & LG_FF3)
+ if (drv_data->quirks & LG_FF3)
lg3ff_init(hdev);
- if (quirks & LG_FF4)
+ if (drv_data->quirks & LG_FF4)
lg4ff_init(hdev);
return 0;
err_free:
+ kfree(drv_data);
return ret;
}
static void lg_remove(struct hid_device *hdev)
{
- unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
- if(quirks & LG_FF4)
+ struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hdev);
+ if (drv_data->quirks & LG_FF4)
lg4ff_deinit(hdev);
hid_hw_stop(hdev);
+ kfree(drv_data);
}
static const struct hid_device_id lg_devices[] = {
diff --git a/drivers/hid/hid-lg.h b/drivers/hid/hid-lg.h
index 4b097286dc78..d64cf8d2751e 100644
--- a/drivers/hid/hid-lg.h
+++ b/drivers/hid/hid-lg.h
@@ -1,6 +1,11 @@
#ifndef __HID_LG_H
#define __HID_LG_H
+struct lg_drv_data {
+ unsigned long quirks;
+ void *device_props; /* Device specific properties */
+};
+
#ifdef CONFIG_LOGITECH_FF
int lgff_init(struct hid_device *hdev);
#else
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index 6ecc9e220440..f3390ee6105c 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -1,7 +1,8 @@
/*
- * Force feedback support for Logitech Speed Force Wireless
+ * Force feedback support for Logitech Gaming Wheels
*
- * http://wiibrew.org/wiki/Logitech_USB_steering_wheel
+ * Including G27, G25, DFP, DFGT, FFEX, Momo, Momo2 &
+ * Speed Force Wireless (WiiWheel)
*
* Copyright (c) 2010 Simon Wood <simon@mungewell.org>
*/
@@ -51,20 +52,18 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at
static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IRWXO, lg4ff_range_show, lg4ff_range_store);
-static bool list_inited;
-
struct lg4ff_device_entry {
- char *device_id; /* Use name in respective kobject structure's address as the ID */
__u16 range;
__u16 min_range;
__u16 max_range;
- __u8 leds;
+#ifdef CONFIG_LEDS_CLASS
+ __u8 led_state;
+ struct led_classdev *led[5];
+#endif
struct list_head list;
void (*set_range)(struct hid_device *hid, u16 range);
};
-static struct lg4ff_device_entry device_list;
-
static const signed short lg4ff_wheel_effects[] = {
FF_CONSTANT,
FF_AUTOCENTER,
@@ -285,18 +284,20 @@ static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_n
/* Read current range and display it in terminal */
static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf)
{
- struct lg4ff_device_entry *uninitialized_var(entry);
- struct list_head *h;
struct hid_device *hid = to_hid_device(dev);
+ struct lg4ff_device_entry *entry;
+ struct lg_drv_data *drv_data;
size_t count;
- list_for_each(h, &device_list.list) {
- entry = list_entry(h, struct lg4ff_device_entry, list);
- if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0)
- break;
+ drv_data = hid_get_drvdata(hid);
+ if (!drv_data) {
+ hid_err(hid, "Private driver data not found!\n");
+ return 0;
}
- if (h == &device_list.list) {
- dbg_hid("Device not found!");
+
+ entry = drv_data->device_props;
+ if (!entry) {
+ hid_err(hid, "Device properties not found!\n");
return 0;
}
@@ -308,19 +309,21 @@ static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *att
* according to the type of the wheel */
static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- struct lg4ff_device_entry *uninitialized_var(entry);
- struct list_head *h;
struct hid_device *hid = to_hid_device(dev);
+ struct lg4ff_device_entry *entry;
+ struct lg_drv_data *drv_data;
__u16 range = simple_strtoul(buf, NULL, 10);
- list_for_each(h, &device_list.list) {
- entry = list_entry(h, struct lg4ff_device_entry, list);
- if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0)
- break;
+ drv_data = hid_get_drvdata(hid);
+ if (!drv_data) {
+ hid_err(hid, "Private driver data not found!\n");
+ return 0;
}
- if (h == &device_list.list) {
- dbg_hid("Device not found!");
- return count;
+
+ entry = drv_data->device_props;
+ if (!entry) {
+ hid_err(hid, "Device properties not found!\n");
+ return 0;
}
if (range == 0)
@@ -336,6 +339,88 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at
return count;
}
+#ifdef CONFIG_LEDS_CLASS
+static void lg4ff_set_leds(struct hid_device *hid, __u8 leds)
+{
+ struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+
+ report->field[0]->value[0] = 0xf8;
+ report->field[0]->value[1] = 0x12;
+ report->field[0]->value[2] = leds;
+ report->field[0]->value[3] = 0x00;
+ report->field[0]->value[4] = 0x00;
+ report->field[0]->value[5] = 0x00;
+ report->field[0]->value[6] = 0x00;
+ usbhid_submit_report(hid, report, USB_DIR_OUT);
+}
+
+static void lg4ff_led_set_brightness(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct device *dev = led_cdev->dev->parent;
+ struct hid_device *hid = container_of(dev, struct hid_device, dev);
+ struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid);
+ struct lg4ff_device_entry *entry;
+ int i, state = 0;
+
+ if (!drv_data) {
+ hid_err(hid, "Device data not found.");
+ return;
+ }
+
+ entry = (struct lg4ff_device_entry *)drv_data->device_props;
+
+ if (!entry) {
+ hid_err(hid, "Device properties not found.");
+ return;
+ }
+
+ for (i = 0; i < 5; i++) {
+ if (led_cdev != entry->led[i])
+ continue;
+ state = (entry->led_state >> i) & 1;
+ if (value == LED_OFF && state) {
+ entry->led_state &= ~(1 << i);
+ lg4ff_set_leds(hid, entry->led_state);
+ } else if (value != LED_OFF && !state) {
+ entry->led_state |= 1 << i;
+ lg4ff_set_leds(hid, entry->led_state);
+ }
+ break;
+ }
+}
+
+static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cdev)
+{
+ struct device *dev = led_cdev->dev->parent;
+ struct hid_device *hid = container_of(dev, struct hid_device, dev);
+ struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid);
+ struct lg4ff_device_entry *entry;
+ int i, value = 0;
+
+ if (!drv_data) {
+ hid_err(hid, "Device data not found.");
+ return LED_OFF;
+ }
+
+ entry = (struct lg4ff_device_entry *)drv_data->device_props;
+
+ if (!entry) {
+ hid_err(hid, "Device properties not found.");
+ return LED_OFF;
+ }
+
+ for (i = 0; i < 5; i++)
+ if (led_cdev == entry->led[i]) {
+ value = (entry->led_state >> i) & 1;
+ break;
+ }
+
+ return value ? LED_FULL : LED_OFF;
+}
+#endif
+
int lg4ff_init(struct hid_device *hid)
{
struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
@@ -344,6 +429,7 @@ int lg4ff_init(struct hid_device *hid)
struct hid_report *report;
struct hid_field *field;
struct lg4ff_device_entry *entry;
+ struct lg_drv_data *drv_data;
struct usb_device_descriptor *udesc;
int error, i, j;
__u16 bcdDevice, rev_maj, rev_min;
@@ -423,28 +509,24 @@ int lg4ff_init(struct hid_device *hid)
dev->ff->set_autocenter(dev, 0);
}
- /* Initialize device_list if this is the first device to handle by lg4ff */
- if (!list_inited) {
- INIT_LIST_HEAD(&device_list.list);
- list_inited = 1;
+ /* Get private driver data */
+ drv_data = hid_get_drvdata(hid);
+ if (!drv_data) {
+ hid_err(hid, "Cannot add device, private driver data not allocated\n");
+ return -1;
}
- /* Add the device to device_list */
+ /* Initialize device properties */
entry = kzalloc(sizeof(struct lg4ff_device_entry), GFP_KERNEL);
if (!entry) {
- hid_err(hid, "Cannot add device, insufficient memory.\n");
- return -ENOMEM;
- }
- entry->device_id = kstrdup((&hid->dev)->kobj.name, GFP_KERNEL);
- if (!entry->device_id) {
- hid_err(hid, "Cannot set device_id, insufficient memory.\n");
- kfree(entry);
+ hid_err(hid, "Cannot add device, insufficient memory to allocate device properties.\n");
return -ENOMEM;
}
+ drv_data->device_props = entry;
+
entry->min_range = lg4ff_devices[i].min_range;
entry->max_range = lg4ff_devices[i].max_range;
entry->set_range = lg4ff_devices[i].set_range;
- list_add(&entry->list, &device_list.list);
/* Create sysfs interface */
error = device_create_file(&hid->dev, &dev_attr_range);
@@ -457,32 +539,100 @@ int lg4ff_init(struct hid_device *hid)
if (entry->set_range != NULL)
entry->set_range(hid, entry->range);
- hid_info(hid, "Force feedback for Logitech Speed Force Wireless by Simon Wood <simon@mungewell.org>\n");
+#ifdef CONFIG_LEDS_CLASS
+ /* register led subsystem - G27 only */
+ entry->led_state = 0;
+ for (j = 0; j < 5; j++)
+ entry->led[j] = NULL;
+
+ if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G27_WHEEL) {
+ struct led_classdev *led;
+ size_t name_sz;
+ char *name;
+
+ lg4ff_set_leds(hid, 0);
+
+ name_sz = strlen(dev_name(&hid->dev)) + 8;
+
+ for (j = 0; j < 5; j++) {
+ led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
+ if (!led) {
+ hid_err(hid, "can't allocate memory for LED %d\n", j);
+ goto err;
+ }
+
+ name = (void *)(&led[1]);
+ snprintf(name, name_sz, "%s::RPM%d", dev_name(&hid->dev), j+1);
+ led->name = name;
+ led->brightness = 0;
+ led->max_brightness = 1;
+ led->brightness_get = lg4ff_led_get_brightness;
+ led->brightness_set = lg4ff_led_set_brightness;
+
+ entry->led[j] = led;
+ error = led_classdev_register(&hid->dev, led);
+
+ if (error) {
+ hid_err(hid, "failed to register LED %d. Aborting.\n", j);
+err:
+ /* Deregister LEDs (if any) */
+ for (j = 0; j < 5; j++) {
+ led = entry->led[j];
+ entry->led[j] = NULL;
+ if (!led)
+ continue;
+ led_classdev_unregister(led);
+ kfree(led);
+ }
+ goto out; /* Let the driver continue without LEDs */
+ }
+ }
+ }
+out:
+#endif
+ hid_info(hid, "Force feedback support for Logitech Gaming Wheels\n");
return 0;
}
int lg4ff_deinit(struct hid_device *hid)
{
- bool found = 0;
struct lg4ff_device_entry *entry;
- struct list_head *h, *g;
- list_for_each_safe(h, g, &device_list.list) {
- entry = list_entry(h, struct lg4ff_device_entry, list);
- if (strcmp(entry->device_id, (&hid->dev)->kobj.name) == 0) {
- list_del(h);
- kfree(entry->device_id);
- kfree(entry);
- found = 1;
- break;
- }
- }
+ struct lg_drv_data *drv_data;
+
+ device_remove_file(&hid->dev, &dev_attr_range);
- if (!found) {
- dbg_hid("Device entry not found!\n");
+ drv_data = hid_get_drvdata(hid);
+ if (!drv_data) {
+ hid_err(hid, "Error while deinitializing device, no private driver data.\n");
+ return -1;
+ }
+ entry = drv_data->device_props;
+ if (!entry) {
+ hid_err(hid, "Error while deinitializing device, no device properties data.\n");
return -1;
}
- device_remove_file(&hid->dev, &dev_attr_range);
+#ifdef CONFIG_LEDS_CLASS
+ {
+ int j;
+ struct led_classdev *led;
+
+ /* Deregister LEDs (if any) */
+ for (j = 0; j < 5; j++) {
+
+ led = entry->led[j];
+ entry->led[j] = NULL;
+ if (!led)
+ continue;
+ led_classdev_unregister(led);
+ kfree(led);
+ }
+ }
+#endif
+
+ /* Deallocate memory */
+ kfree(entry);
+
dbg_hid("Device successfully unregistered\n");
return 0;
}
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index 2b56efcbdf61..5e8a7ed42344 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -26,6 +26,7 @@
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/usb.h>
+#include <asm/unaligned.h>
#include "usbhid/usbhid.h"
#include "hid-ids.h"
#include "hid-logitech-dj.h"
@@ -155,6 +156,14 @@ static const char media_descriptor[] = {
/* Maximum size of all defined hid reports in bytes (including report id) */
#define MAX_REPORT_SIZE 8
+/* Make sure all descriptors are present here */
+#define MAX_RDESC_SIZE \
+ (sizeof(kbd_descriptor) + \
+ sizeof(mse_descriptor) + \
+ sizeof(consumer_descriptor) + \
+ sizeof(syscontrol_descriptor) + \
+ sizeof(media_descriptor))
+
/* Number of possible hid report types that can be created by this driver.
*
* Right now, RF report types have the same report types (or report id's)
@@ -265,8 +274,8 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
goto dj_device_allocate_fail;
}
- dj_dev->reports_supported = le32_to_cpu(
- dj_report->report_params[DEVICE_PAIRED_RF_REPORT_TYPE]);
+ dj_dev->reports_supported = get_unaligned_le32(
+ dj_report->report_params + DEVICE_PAIRED_RF_REPORT_TYPE);
dj_dev->hdev = dj_hiddev;
dj_dev->dj_receiver_dev = djrcv_dev;
dj_dev->device_index = dj_report->device_index;
@@ -473,9 +482,17 @@ static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
return 0;
}
+static void rdcat(char **rdesc, unsigned int *rsize, const char *data, unsigned int size)
+{
+ memcpy(*rdesc + *rsize, data, size);
+ *rsize += size;
+}
+
static int logi_dj_ll_parse(struct hid_device *hid)
{
struct dj_device *djdev = hid->driver_data;
+ unsigned int rsize = 0;
+ char *rdesc;
int retval;
dbg_hid("%s\n", __func__);
@@ -483,70 +500,38 @@ static int logi_dj_ll_parse(struct hid_device *hid)
djdev->hdev->version = 0x0111;
djdev->hdev->country = 0x00;
+ rdesc = kmalloc(MAX_RDESC_SIZE, GFP_KERNEL);
+ if (!rdesc)
+ return -ENOMEM;
+
if (djdev->reports_supported & STD_KEYBOARD) {
dbg_hid("%s: sending a kbd descriptor, reports_supported: %x\n",
__func__, djdev->reports_supported);
- retval = hid_parse_report(hid,
- (u8 *) kbd_descriptor,
- sizeof(kbd_descriptor));
- if (retval) {
- dbg_hid("%s: sending a kbd descriptor, hid_parse failed"
- " error: %d\n", __func__, retval);
- return retval;
- }
+ rdcat(&rdesc, &rsize, kbd_descriptor, sizeof(kbd_descriptor));
}
if (djdev->reports_supported & STD_MOUSE) {
dbg_hid("%s: sending a mouse descriptor, reports_supported: "
"%x\n", __func__, djdev->reports_supported);
- retval = hid_parse_report(hid,
- (u8 *) mse_descriptor,
- sizeof(mse_descriptor));
- if (retval) {
- dbg_hid("%s: sending a mouse descriptor, hid_parse "
- "failed error: %d\n", __func__, retval);
- return retval;
- }
+ rdcat(&rdesc, &rsize, mse_descriptor, sizeof(mse_descriptor));
}
if (djdev->reports_supported & MULTIMEDIA) {
dbg_hid("%s: sending a multimedia report descriptor: %x\n",
__func__, djdev->reports_supported);
- retval = hid_parse_report(hid,
- (u8 *) consumer_descriptor,
- sizeof(consumer_descriptor));
- if (retval) {
- dbg_hid("%s: sending a consumer_descriptor, hid_parse "
- "failed error: %d\n", __func__, retval);
- return retval;
- }
+ rdcat(&rdesc, &rsize, consumer_descriptor, sizeof(consumer_descriptor));
}
if (djdev->reports_supported & POWER_KEYS) {
dbg_hid("%s: sending a power keys report descriptor: %x\n",
__func__, djdev->reports_supported);
- retval = hid_parse_report(hid,
- (u8 *) syscontrol_descriptor,
- sizeof(syscontrol_descriptor));
- if (retval) {
- dbg_hid("%s: sending a syscontrol_descriptor, "
- "hid_parse failed error: %d\n",
- __func__, retval);
- return retval;
- }
+ rdcat(&rdesc, &rsize, syscontrol_descriptor, sizeof(syscontrol_descriptor));
}
if (djdev->reports_supported & MEDIA_CENTER) {
dbg_hid("%s: sending a media center report descriptor: %x\n",
__func__, djdev->reports_supported);
- retval = hid_parse_report(hid,
- (u8 *) media_descriptor,
- sizeof(media_descriptor));
- if (retval) {
- dbg_hid("%s: sending a media_descriptor, hid_parse "
- "failed error: %d\n", __func__, retval);
- return retval;
- }
+ rdcat(&rdesc, &rsize, media_descriptor, sizeof(media_descriptor));
}
if (djdev->reports_supported & KBD_LEDS) {
@@ -554,7 +539,10 @@ static int logi_dj_ll_parse(struct hid_device *hid)
__func__, djdev->reports_supported);
}
- return 0;
+ retval = hid_parse_report(hid, rdesc, rsize);
+ kfree(rdesc);
+
+ return retval;
}
static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type,
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 1d5b94167b52..6e3332a99976 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -70,9 +70,16 @@ struct mt_class {
bool is_indirect; /* true for touchpads */
};
+struct mt_fields {
+ unsigned usages[HID_MAX_FIELDS];
+ unsigned int length;
+};
+
struct mt_device {
struct mt_slot curdata; /* placeholder of incoming data */
struct mt_class mtclass; /* our mt device class */
+ struct mt_fields *fields; /* temporary placeholder for storing the
+ multitouch fields */
unsigned last_field_index; /* last field index of the report */
unsigned last_slot_field; /* the last field of a slot */
__s8 inputmode; /* InputMode HID feature, -1 if non-existent */
@@ -110,6 +117,9 @@ struct mt_device {
#define MT_DEFAULT_MAXCONTACT 10
+#define MT_USB_DEVICE(v, p) HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH, v, p)
+#define MT_BT_DEVICE(v, p) HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH, v, p)
+
/*
* these device-dependent functions determine what slot corresponds
* to a valid contact that was just read.
@@ -275,11 +285,15 @@ static void set_abs(struct input_dev *input, unsigned int code,
input_set_abs_params(input, code, fmin, fmax, fuzz, 0);
}
-static void set_last_slot_field(struct hid_usage *usage, struct mt_device *td,
+static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
struct hid_input *hi)
{
- if (!test_bit(usage->hid, hi->input->absbit))
- td->last_slot_field = usage->hid;
+ struct mt_fields *f = td->fields;
+
+ if (f->length >= HID_MAX_FIELDS)
+ return;
+
+ f->usages[f->length++] = usage->hid;
}
static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
@@ -330,7 +344,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
cls->sn_move);
/* touchscreen emulation */
set_abs(hi->input, ABS_X, field, cls->sn_move);
- set_last_slot_field(usage, td, hi);
+ mt_store_field(usage, td, hi);
td->last_field_index = field->index;
return 1;
case HID_GD_Y:
@@ -340,7 +354,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
cls->sn_move);
/* touchscreen emulation */
set_abs(hi->input, ABS_Y, field, cls->sn_move);
- set_last_slot_field(usage, td, hi);
+ mt_store_field(usage, td, hi);
td->last_field_index = field->index;
return 1;
}
@@ -349,24 +363,24 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_UP_DIGITIZER:
switch (usage->hid) {
case HID_DG_INRANGE:
- set_last_slot_field(usage, td, hi);
+ mt_store_field(usage, td, hi);
td->last_field_index = field->index;
return 1;
case HID_DG_CONFIDENCE:
- set_last_slot_field(usage, td, hi);
+ mt_store_field(usage, td, hi);
td->last_field_index = field->index;
return 1;
case HID_DG_TIPSWITCH:
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
- set_last_slot_field(usage, td, hi);
+ mt_store_field(usage, td, hi);
td->last_field_index = field->index;
return 1;
case HID_DG_CONTACTID:
if (!td->maxcontacts)
td->maxcontacts = MT_DEFAULT_MAXCONTACT;
input_mt_init_slots(hi->input, td->maxcontacts);
- td->last_slot_field = usage->hid;
+ mt_store_field(usage, td, hi);
td->last_field_index = field->index;
td->touches_by_report++;
return 1;
@@ -375,7 +389,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
EV_ABS, ABS_MT_TOUCH_MAJOR);
set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
cls->sn_width);
- set_last_slot_field(usage, td, hi);
+ mt_store_field(usage, td, hi);
td->last_field_index = field->index;
return 1;
case HID_DG_HEIGHT:
@@ -385,7 +399,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
cls->sn_height);
input_set_abs_params(hi->input,
ABS_MT_ORIENTATION, 0, 1, 0, 0);
- set_last_slot_field(usage, td, hi);
+ mt_store_field(usage, td, hi);
td->last_field_index = field->index;
return 1;
case HID_DG_TIPPRESSURE:
@@ -396,7 +410,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
/* touchscreen emulation */
set_abs(hi->input, ABS_PRESSURE, field,
cls->sn_pressure);
- set_last_slot_field(usage, td, hi);
+ mt_store_field(usage, td, hi);
td->last_field_index = field->index;
return 1;
case HID_DG_CONTACTCOUNT:
@@ -635,6 +649,31 @@ static void mt_set_maxcontacts(struct hid_device *hdev)
}
}
+static void mt_post_parse_default_settings(struct mt_device *td)
+{
+ __s32 quirks = td->mtclass.quirks;
+
+ /* unknown serial device needs special quirks */
+ if (td->touches_by_report == 1) {
+ quirks |= MT_QUIRK_ALWAYS_VALID;
+ quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
+ quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
+ quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE;
+ }
+
+ td->mtclass.quirks = quirks;
+}
+
+static void mt_post_parse(struct mt_device *td)
+{
+ struct mt_fields *f = td->fields;
+
+ if (td->touches_by_report > 0) {
+ int field_count_per_touch = f->length / td->touches_by_report;
+ td->last_slot_field = f->usages[field_count_per_touch - 1];
+ }
+}
+
static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret, i;
@@ -654,7 +693,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
* that emit events over several HID messages.
*/
hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
- hdev->quirks &= ~HID_QUIRK_MULTITOUCH;
td = kzalloc(sizeof(struct mt_device), GFP_KERNEL);
if (!td) {
@@ -666,6 +704,13 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
td->maxcontact_report_id = -1;
hid_set_drvdata(hdev, td);
+ td->fields = kzalloc(sizeof(struct mt_fields), GFP_KERNEL);
+ if (!td->fields) {
+ dev_err(&hdev->dev, "cannot allocate multitouch fields data\n");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
ret = hid_parse(hdev);
if (ret != 0)
goto fail;
@@ -674,14 +719,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (ret)
goto fail;
- if (!id && td->touches_by_report == 1) {
- /* the device has been sent by hid-generic */
- mtclass = &td->mtclass;
- mtclass->quirks |= MT_QUIRK_ALWAYS_VALID;
- mtclass->quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
- mtclass->quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
- mtclass->quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE;
- }
+ mt_post_parse(td);
+
+ if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
+ mt_post_parse_default_settings(td);
td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot),
GFP_KERNEL);
@@ -697,9 +738,13 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
mt_set_maxcontacts(hdev);
mt_set_input_mode(hdev);
+ kfree(td->fields);
+ td->fields = NULL;
+
return 0;
fail:
+ kfree(td->fields);
kfree(td);
return ret;
}
@@ -727,50 +772,54 @@ static const struct hid_device_id mt_devices[] = {
/* 3M panels */
{ .driver_data = MT_CLS_3M,
- HID_USB_DEVICE(USB_VENDOR_ID_3M,
+ MT_USB_DEVICE(USB_VENDOR_ID_3M,
USB_DEVICE_ID_3M1968) },
{ .driver_data = MT_CLS_3M,
- HID_USB_DEVICE(USB_VENDOR_ID_3M,
+ MT_USB_DEVICE(USB_VENDOR_ID_3M,
USB_DEVICE_ID_3M2256) },
{ .driver_data = MT_CLS_3M,
- HID_USB_DEVICE(USB_VENDOR_ID_3M,
+ MT_USB_DEVICE(USB_VENDOR_ID_3M,
USB_DEVICE_ID_3M3266) },
/* ActionStar panels */
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR,
+ MT_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR,
USB_DEVICE_ID_ACTIONSTAR_1011) },
/* Atmel panels */
{ .driver_data = MT_CLS_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_ATMEL,
+ MT_USB_DEVICE(USB_VENDOR_ID_ATMEL,
USB_DEVICE_ID_ATMEL_MULTITOUCH) },
{ .driver_data = MT_CLS_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_ATMEL,
+ MT_USB_DEVICE(USB_VENDOR_ID_ATMEL,
USB_DEVICE_ID_ATMEL_MXT_DIGITIZER) },
+ /* Baanto multitouch devices */
+ { .driver_data = MT_CLS_DEFAULT,
+ MT_USB_DEVICE(USB_VENDOR_ID_BAANTO,
+ USB_DEVICE_ID_BAANTO_MT_190W2) },
/* Cando panels */
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
- HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+ MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
- HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+ MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) },
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
- HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+ MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) },
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
- HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+ MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
/* Chunghwa Telecom touch panels */
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT,
+ MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT,
USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) },
/* CVTouch panels */
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH,
+ MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH,
USB_DEVICE_ID_CVTOUCH_SCREEN) },
/* Cypress panel */
@@ -780,225 +829,227 @@ static const struct hid_device_id mt_devices[] = {
/* eGalax devices (resistive) */
{ .driver_data = MT_CLS_EGALAX,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D) },
{ .driver_data = MT_CLS_EGALAX,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E) },
/* eGalax devices (capacitive) */
{ .driver_data = MT_CLS_EGALAX,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) },
{ .driver_data = MT_CLS_EGALAX_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7207) },
{ .driver_data = MT_CLS_EGALAX_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_725E) },
{ .driver_data = MT_CLS_EGALAX_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) },
{ .driver_data = MT_CLS_EGALAX_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_722A) },
{ .driver_data = MT_CLS_EGALAX,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) },
{ .driver_data = MT_CLS_EGALAX_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7262) },
{ .driver_data = MT_CLS_EGALAX,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) },
{ .driver_data = MT_CLS_EGALAX_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72AA) },
{ .driver_data = MT_CLS_EGALAX,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA) },
{ .driver_data = MT_CLS_EGALAX,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302) },
{ .driver_data = MT_CLS_EGALAX_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349) },
{ .driver_data = MT_CLS_EGALAX_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) },
/* Elo TouchSystems IntelliTouch Plus panel */
{ .driver_data = MT_CLS_DUAL_NSMU_CONTACTID,
- HID_USB_DEVICE(USB_VENDOR_ID_ELO,
+ MT_USB_DEVICE(USB_VENDOR_ID_ELO,
USB_DEVICE_ID_ELO_TS2515) },
/* GeneralTouch panel */
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
- HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
+ MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) },
/* Gametel game controller */
{ .driver_data = MT_CLS_DEFAULT,
- HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_FRUCTEL,
+ MT_BT_DEVICE(USB_VENDOR_ID_FRUCTEL,
USB_DEVICE_ID_GAMETEL_MT_MODE) },
/* GoodTouch panels */
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH,
+ MT_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH,
USB_DEVICE_ID_GOODTOUCH_000f) },
/* Hanvon panels */
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
- HID_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT,
+ MT_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT,
USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) },
/* Ideacom panel */
{ .driver_data = MT_CLS_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM,
+ MT_USB_DEVICE(USB_VENDOR_ID_IDEACOM,
USB_DEVICE_ID_IDEACOM_IDC6650) },
{ .driver_data = MT_CLS_SERIAL,
- HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM,
+ MT_USB_DEVICE(USB_VENDOR_ID_IDEACOM,
USB_DEVICE_ID_IDEACOM_IDC6651) },
/* Ilitek dual touch panel */
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_ILITEK,
+ MT_USB_DEVICE(USB_VENDOR_ID_ILITEK,
USB_DEVICE_ID_ILITEK_MULTITOUCH) },
/* IRTOUCH panels */
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
- HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS,
+ MT_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS,
USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
/* LG Display panels */
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_LG,
+ MT_USB_DEVICE(USB_VENDOR_ID_LG,
USB_DEVICE_ID_LG_MULTITOUCH) },
/* Lumio panels */
{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
- HID_USB_DEVICE(USB_VENDOR_ID_LUMIO,
+ MT_USB_DEVICE(USB_VENDOR_ID_LUMIO,
USB_DEVICE_ID_CRYSTALTOUCH) },
{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
- HID_USB_DEVICE(USB_VENDOR_ID_LUMIO,
+ MT_USB_DEVICE(USB_VENDOR_ID_LUMIO,
USB_DEVICE_ID_CRYSTALTOUCH_DUAL) },
/* MosArt panels */
{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
- HID_USB_DEVICE(USB_VENDOR_ID_ASUS,
+ MT_USB_DEVICE(USB_VENDOR_ID_ASUS,
USB_DEVICE_ID_ASUS_T91MT)},
{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
- HID_USB_DEVICE(USB_VENDOR_ID_ASUS,
+ MT_USB_DEVICE(USB_VENDOR_ID_ASUS,
USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) },
{ .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
- HID_USB_DEVICE(USB_VENDOR_ID_TURBOX,
+ MT_USB_DEVICE(USB_VENDOR_ID_TURBOX,
USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
/* Panasonic panels */
{ .driver_data = MT_CLS_PANASONIC,
- HID_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
+ MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
USB_DEVICE_ID_PANABOARD_UBT780) },
{ .driver_data = MT_CLS_PANASONIC,
- HID_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
+ MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
USB_DEVICE_ID_PANABOARD_UBT880) },
/* PenMount panels */
{ .driver_data = MT_CLS_CONFIDENCE,
- HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT,
+ MT_USB_DEVICE(USB_VENDOR_ID_PENMOUNT,
USB_DEVICE_ID_PENMOUNT_PCI) },
/* PixArt optical touch screen */
{ .driver_data = MT_CLS_INRANGE_CONTACTNUMBER,
- HID_USB_DEVICE(USB_VENDOR_ID_PIXART,
+ MT_USB_DEVICE(USB_VENDOR_ID_PIXART,
USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN) },
{ .driver_data = MT_CLS_INRANGE_CONTACTNUMBER,
- HID_USB_DEVICE(USB_VENDOR_ID_PIXART,
+ MT_USB_DEVICE(USB_VENDOR_ID_PIXART,
USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1) },
{ .driver_data = MT_CLS_INRANGE_CONTACTNUMBER,
- HID_USB_DEVICE(USB_VENDOR_ID_PIXART,
+ MT_USB_DEVICE(USB_VENDOR_ID_PIXART,
USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2) },
/* PixCir-based panels */
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
- HID_USB_DEVICE(USB_VENDOR_ID_HANVON,
+ MT_USB_DEVICE(USB_VENDOR_ID_HANVON,
USB_DEVICE_ID_HANVON_MULTITOUCH) },
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
- HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+ MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) },
/* Quanta-based panels */
{ .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID,
- HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
+ MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,
USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
{ .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID,
- HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
+ MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,
USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001) },
{ .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID,
- HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
+ MT_USB_DEVICE(USB_VENDOR_ID_QUANTA,
USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008) },
/* Stantum panels */
{ .driver_data = MT_CLS_CONFIDENCE,
- HID_USB_DEVICE(USB_VENDOR_ID_STANTUM,
+ MT_USB_DEVICE(USB_VENDOR_ID_STANTUM,
USB_DEVICE_ID_MTP)},
{ .driver_data = MT_CLS_CONFIDENCE,
- HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
+ MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
USB_DEVICE_ID_MTP_STM)},
{ .driver_data = MT_CLS_CONFIDENCE,
- HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX,
+ MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX,
USB_DEVICE_ID_MTP_SITRONIX)},
/* TopSeed panels */
{ .driver_data = MT_CLS_TOPSEED,
- HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2,
+ MT_USB_DEVICE(USB_VENDOR_ID_TOPSEED2,
USB_DEVICE_ID_TOPSEED2_PERIPAD_701) },
/* Touch International panels */
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL,
+ MT_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL,
USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) },
/* Unitec panels */
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_UNITEC,
+ MT_USB_DEVICE(USB_VENDOR_ID_UNITEC,
USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) },
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_UNITEC,
+ MT_USB_DEVICE(USB_VENDOR_ID_UNITEC,
USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) },
/* XAT */
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_XAT,
+ MT_USB_DEVICE(USB_VENDOR_ID_XAT,
USB_DEVICE_ID_XAT_CSR) },
/* Xiroku */
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+ MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_SPX) },
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+ MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_MPX) },
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+ MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_CSR) },
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+ MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_SPX1) },
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+ MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_MPX1) },
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+ MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_CSR1) },
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+ MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_SPX2) },
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+ MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_MPX2) },
{ .driver_data = MT_CLS_DEFAULT,
- HID_USB_DEVICE(USB_VENDOR_ID_XIROKU,
+ MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
USB_DEVICE_ID_XIROKU_CSR2) },
+ /* Generic MT device */
+ { HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) },
{ }
};
MODULE_DEVICE_TABLE(hid, mt_devices);
diff --git a/drivers/hid/hid-uclogic.c b/drivers/hid/hid-uclogic.c
index 1f1128910337..3aba02be1f26 100644
--- a/drivers/hid/hid-uclogic.c
+++ b/drivers/hid/hid-uclogic.c
@@ -14,6 +14,7 @@
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
+#include <linux/usb.h>
#include "hid-ids.h"
@@ -352,9 +353,125 @@ static __u8 pf1209_rdesc_fixed[] = {
0xC0 /* End Collection */
};
+/*
+ * See TWHL850 description, device and HID report descriptors at
+ * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Wireless_Tablet_TWHL850
+ */
+
+/* Size of the original descriptors of TWHL850 tablet */
+#define TWHL850_RDESC_ORIG_SIZE0 182
+#define TWHL850_RDESC_ORIG_SIZE1 161
+#define TWHL850_RDESC_ORIG_SIZE2 92
+
+/* Fixed PID 0522 tablet report descriptor, interface 0 (stylus) */
+static __u8 twhl850_rdesc_fixed0[] = {
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x09, 0x02, /* Usage (Pen), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x09, /* Report ID (9), */
+ 0x09, 0x20, /* Usage (Stylus), */
+ 0xA0, /* Collection (Physical), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x09, 0x42, /* Usage (Tip Switch), */
+ 0x09, 0x44, /* Usage (Barrel Switch), */
+ 0x09, 0x46, /* Usage (Tablet Pick), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x09, 0x32, /* Usage (In Range), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0xA4, /* Push, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x65, 0x13, /* Unit (Inch), */
+ 0x55, 0xFD, /* Unit Exponent (-3), */
+ 0x34, /* Physical Minimum (0), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x46, 0x40, 0x1F, /* Physical Maximum (8000), */
+ 0x26, 0x00, 0x7D, /* Logical Maximum (32000), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x46, 0x88, 0x13, /* Physical Maximum (5000), */
+ 0x26, 0x20, 0x4E, /* Logical Maximum (20000), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xB4, /* Pop, */
+ 0x09, 0x30, /* Usage (Tip Pressure), */
+ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xC0, /* End Collection, */
+ 0xC0 /* End Collection */
+};
+
+/* Fixed PID 0522 tablet report descriptor, interface 1 (mouse) */
+static __u8 twhl850_rdesc_fixed1[] = {
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x02, /* Usage (Mouse), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x01, /* Report ID (1), */
+ 0x09, 0x01, /* Usage (Pointer), */
+ 0xA0, /* Collection (Physical), */
+ 0x05, 0x09, /* Usage Page (Button), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x19, 0x01, /* Usage Minimum (01h), */
+ 0x29, 0x03, /* Usage Maximum (03h), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x05, /* Report Count (5), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x16, 0x00, 0x80, /* Logical Minimum (-32768), */
+ 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x81, 0x06, /* Input (Variable, Relative), */
+ 0x09, 0x38, /* Usage (Wheel), */
+ 0x15, 0xFF, /* Logical Minimum (-1), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x81, 0x06, /* Input (Variable, Relative), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0xC0, /* End Collection, */
+ 0xC0 /* End Collection */
+};
+
+/* Fixed PID 0522 tablet report descriptor, interface 2 (frame buttons) */
+static __u8 twhl850_rdesc_fixed2[] = {
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x06, /* Usage (Keyboard), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x03, /* Report ID (3), */
+ 0x05, 0x07, /* Usage Page (Keyboard), */
+ 0x14, /* Logical Minimum (0), */
+ 0x19, 0xE0, /* Usage Minimum (KB Leftcontrol), */
+ 0x29, 0xE7, /* Usage Maximum (KB Right GUI), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x08, /* Report Count (8), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x18, /* Usage Minimum (None), */
+ 0x29, 0xFF, /* Usage Maximum (FFh), */
+ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x06, /* Report Count (6), */
+ 0x80, /* Input, */
+ 0xC0 /* End Collection */
+};
+
static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
+ struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
+ __u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
+
switch (hdev->product) {
case USB_DEVICE_ID_UCLOGIC_TABLET_PF1209:
if (*rsize == PF1209_RDESC_ORIG_SIZE) {
@@ -386,6 +503,28 @@ static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
*rsize = sizeof(wp1062_rdesc_fixed);
}
break;
+ case USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850:
+ switch (iface_num) {
+ case 0:
+ if (*rsize == TWHL850_RDESC_ORIG_SIZE0) {
+ rdesc = twhl850_rdesc_fixed0;
+ *rsize = sizeof(twhl850_rdesc_fixed0);
+ }
+ break;
+ case 1:
+ if (*rsize == TWHL850_RDESC_ORIG_SIZE1) {
+ rdesc = twhl850_rdesc_fixed1;
+ *rsize = sizeof(twhl850_rdesc_fixed1);
+ }
+ break;
+ case 2:
+ if (*rsize == TWHL850_RDESC_ORIG_SIZE2) {
+ rdesc = twhl850_rdesc_fixed2;
+ *rsize = sizeof(twhl850_rdesc_fixed2);
+ }
+ break;
+ }
+ break;
}
return rdesc;
@@ -402,6 +541,8 @@ static const struct hid_device_id uclogic_devices[] = {
USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
+ USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
{ }
};
MODULE_DEVICE_TABLE(hid, uclogic_devices);
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
index 067e2963314c..fe23a1eb586b 100644
--- a/drivers/hid/hid-wacom.c
+++ b/drivers/hid/hid-wacom.c
@@ -24,15 +24,16 @@
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
+#include <linux/leds.h>
#include <linux/slab.h>
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
#include <linux/power_supply.h>
-#endif
#include "hid-ids.h"
#define PAD_DEVICE_ID 0x0F
+#define WAC_CMD_LED_CONTROL 0x20
+
struct wacom_data {
__u16 tool;
__u16 butstate;
@@ -41,16 +42,20 @@ struct wacom_data {
__u32 id;
__u32 serial;
unsigned char high_speed;
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
- int battery_capacity;
+ __u8 battery_capacity;
+ __u8 power_raw;
+ __u8 ps_connected;
struct power_supply battery;
struct power_supply ac;
-#endif
+ __u8 led_selector;
+ struct led_classdev *leds[4];
};
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
-/*percent of battery capacity, 0 means AC online*/
-static unsigned short batcap[8] = { 1, 15, 25, 35, 50, 70, 100, 0 };
+/*percent of battery capacity for Graphire
+ 8th value means AC online and show 100% capacity */
+static unsigned short batcap_gr[8] = { 1, 15, 25, 35, 50, 70, 100, 100 };
+/*percent of battery capacity for Intuos4 WL, AC has a separate bit*/
+static unsigned short batcap_i4[8] = { 1, 15, 30, 45, 60, 70, 85, 100 };
static enum power_supply_property wacom_battery_props[] = {
POWER_SUPPLY_PROP_PRESENT,
@@ -64,13 +69,123 @@ static enum power_supply_property wacom_ac_props[] = {
POWER_SUPPLY_PROP_SCOPE,
};
+static void wacom_leds_set_brightness(struct led_classdev *led_dev,
+ enum led_brightness value)
+{
+ struct device *dev = led_dev->dev->parent;
+ struct hid_device *hdev;
+ struct wacom_data *wdata;
+ unsigned char *buf;
+ __u8 led = 0;
+ int i;
+
+ hdev = container_of(dev, struct hid_device, dev);
+ wdata = hid_get_drvdata(hdev);
+ for (i = 0; i < 4; ++i) {
+ if (wdata->leds[i] == led_dev)
+ wdata->led_selector = i;
+ }
+
+ led = wdata->led_selector | 0x04;
+ buf = kzalloc(9, GFP_KERNEL);
+ if (buf) {
+ buf[0] = WAC_CMD_LED_CONTROL;
+ buf[1] = led;
+ buf[2] = value;
+ hdev->hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT);
+ kfree(buf);
+ }
+
+ return;
+}
+
+static enum led_brightness wacom_leds_get_brightness(struct led_classdev *led_dev)
+{
+ struct wacom_data *wdata;
+ struct device *dev = led_dev->dev->parent;
+ int value = 0;
+ int i;
+
+ wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
+
+ for (i = 0; i < 4; ++i) {
+ if (wdata->leds[i] == led_dev) {
+ value = wdata->leds[i]->brightness;
+ break;
+ }
+ }
+
+ return value;
+}
+
+
+static int wacom_initialize_leds(struct hid_device *hdev)
+{
+ struct wacom_data *wdata = hid_get_drvdata(hdev);
+ struct led_classdev *led;
+ struct device *dev = &hdev->dev;
+ size_t namesz = strlen(dev_name(dev)) + 12;
+ char *name;
+ int i, ret;
+
+ wdata->led_selector = 0;
+
+ for (i = 0; i < 4; i++) {
+ led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL);
+ if (!led) {
+ hid_warn(hdev,
+ "can't allocate memory for LED selector\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ name = (void *)&led[1];
+ snprintf(name, namesz, "%s:selector:%d", dev_name(dev), i);
+ led->name = name;
+ led->brightness = 0;
+ led->max_brightness = 127;
+ led->brightness_get = wacom_leds_get_brightness;
+ led->brightness_set = wacom_leds_set_brightness;
+
+ wdata->leds[i] = led;
+
+ ret = led_classdev_register(dev, wdata->leds[i]);
+
+ if (ret) {
+ wdata->leds[i] = NULL;
+ kfree(led);
+ hid_warn(hdev, "can't register LED\n");
+ goto err;
+ }
+ }
+
+err:
+ return ret;
+}
+
+static void wacom_destroy_leds(struct hid_device *hdev)
+{
+ struct wacom_data *wdata = hid_get_drvdata(hdev);
+ struct led_classdev *led;
+ int i;
+
+ for (i = 0; i < 4; ++i) {
+ if (wdata->leds[i]) {
+ led = wdata->leds[i];
+ wdata->leds[i] = NULL;
+ led_classdev_unregister(led);
+ kfree(led);
+ }
+ }
+
+}
+
static int wacom_battery_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct wacom_data *wdata = container_of(psy,
struct wacom_data, battery);
- int power_state = batcap[wdata->battery_capacity];
int ret = 0;
switch (psp) {
@@ -81,11 +196,7 @@ static int wacom_battery_get_property(struct power_supply *psy,
val->intval = POWER_SUPPLY_SCOPE_DEVICE;
break;
case POWER_SUPPLY_PROP_CAPACITY:
- /* show 100% battery capacity when charging */
- if (power_state == 0)
- val->intval = 100;
- else
- val->intval = power_state;
+ val->intval = wdata->battery_capacity;
break;
default:
ret = -EINVAL;
@@ -99,17 +210,13 @@ static int wacom_ac_get_property(struct power_supply *psy,
union power_supply_propval *val)
{
struct wacom_data *wdata = container_of(psy, struct wacom_data, ac);
- int power_state = batcap[wdata->battery_capacity];
int ret = 0;
switch (psp) {
case POWER_SUPPLY_PROP_PRESENT:
/* fall through */
case POWER_SUPPLY_PROP_ONLINE:
- if (power_state == 0)
- val->intval = 1;
- else
- val->intval = 0;
+ val->intval = wdata->ps_connected;
break;
case POWER_SUPPLY_PROP_SCOPE:
val->intval = POWER_SUPPLY_SCOPE_DEVICE;
@@ -120,41 +227,16 @@ static int wacom_ac_get_property(struct power_supply *psy,
}
return ret;
}
-#endif
-
-static void wacom_set_features(struct hid_device *hdev)
-{
- int ret;
- __u8 rep_data[2];
-
- /*set high speed, tablet mode*/
- rep_data[0] = 0x03;
- rep_data[1] = 0x20;
- ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
- HID_FEATURE_REPORT);
- return;
-}
-static void wacom_poke(struct hid_device *hdev, u8 speed)
+static void wacom_set_features(struct hid_device *hdev, u8 speed)
{
struct wacom_data *wdata = hid_get_drvdata(hdev);
int limit, ret;
- char rep_data[2];
-
- rep_data[0] = 0x03 ; rep_data[1] = 0x00;
- limit = 3;
- do {
- ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
- HID_FEATURE_REPORT);
- } while (ret < 0 && limit-- > 0);
-
- if (ret >= 0) {
- if (speed == 0)
- rep_data[0] = 0x05;
- else
- rep_data[0] = 0x06;
+ __u8 rep_data[2];
- rep_data[1] = 0x00;
+ switch (hdev->product) {
+ case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
+ rep_data[0] = 0x03 ; rep_data[1] = 0x00;
limit = 3;
do {
ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
@@ -162,17 +244,47 @@ static void wacom_poke(struct hid_device *hdev, u8 speed)
} while (ret < 0 && limit-- > 0);
if (ret >= 0) {
- wdata->high_speed = speed;
- return;
+ if (speed == 0)
+ rep_data[0] = 0x05;
+ else
+ rep_data[0] = 0x06;
+
+ rep_data[1] = 0x00;
+ limit = 3;
+ do {
+ ret = hdev->hid_output_raw_report(hdev,
+ rep_data, 2, HID_FEATURE_REPORT);
+ } while (ret < 0 && limit-- > 0);
+
+ if (ret >= 0) {
+ wdata->high_speed = speed;
+ return;
+ }
}
+
+ /*
+ * Note that if the raw queries fail, it's not a hard failure
+ * and it is safe to continue
+ */
+ hid_warn(hdev, "failed to poke device, command %d, err %d\n",
+ rep_data[0], ret);
+ break;
+ case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
+ if (speed == 1)
+ wdata->features &= ~0x20;
+ else
+ wdata->features |= 0x20;
+
+ rep_data[0] = 0x03;
+ rep_data[1] = wdata->features;
+
+ ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
+ HID_FEATURE_REPORT);
+ if (ret >= 0)
+ wdata->high_speed = speed;
+ break;
}
- /*
- * Note that if the raw queries fail, it's not a hard failure and it
- * is safe to continue
- */
- hid_warn(hdev, "failed to poke device, command %d, err %d\n",
- rep_data[0], ret);
return;
}
@@ -196,7 +308,7 @@ static ssize_t wacom_store_speed(struct device *dev,
return -EINVAL;
if (new_speed == 0 || new_speed == 1) {
- wacom_poke(hdev, new_speed);
+ wacom_set_features(hdev, new_speed);
return strnlen(buf, PAGE_SIZE);
} else
return -EINVAL;
@@ -310,12 +422,16 @@ static int wacom_gr_parse_report(struct hid_device *hdev,
input_sync(input);
}
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
- /* Store current battery capacity */
+ /* Store current battery capacity and power supply state*/
rw = (data[7] >> 2 & 0x07);
- if (rw != wdata->battery_capacity)
- wdata->battery_capacity = rw;
-#endif
+ if (rw != wdata->power_raw) {
+ wdata->power_raw = rw;
+ wdata->battery_capacity = batcap_gr[rw];
+ if (rw == 7)
+ wdata->ps_connected = 1;
+ else
+ wdata->ps_connected = 0;
+ }
return 1;
}
@@ -369,6 +485,7 @@ static void wacom_i4_parse_pen_report(struct wacom_data *wdata,
{
__u16 x, y, pressure;
__u8 distance;
+ __u8 tilt_x, tilt_y;
switch (data[1]) {
case 0x80: /* Out of proximity report */
@@ -405,6 +522,8 @@ static void wacom_i4_parse_pen_report(struct wacom_data *wdata,
pressure = (data[6] << 3) | ((data[7] & 0xC0) >> 5)
| (data[1] & 0x01);
distance = (data[9] >> 2) & 0x3f;
+ tilt_x = ((data[7] << 1) & 0x7e) | (data[8] >> 7);
+ tilt_y = data[8] & 0x7f;
input_report_key(input, BTN_TOUCH, pressure > 1);
@@ -415,6 +534,8 @@ static void wacom_i4_parse_pen_report(struct wacom_data *wdata,
input_report_abs(input, ABS_Y, y);
input_report_abs(input, ABS_PRESSURE, pressure);
input_report_abs(input, ABS_DISTANCE, distance);
+ input_report_abs(input, ABS_TILT_X, tilt_x);
+ input_report_abs(input, ABS_TILT_Y, tilt_y);
input_report_abs(input, ABS_MISC, wdata->id);
input_event(input, EV_MSC, MSC_SERIAL, wdata->serial);
input_report_key(input, wdata->tool, 1);
@@ -455,6 +576,7 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
struct input_dev *input;
unsigned char *data = (unsigned char *) raw_data;
int i;
+ __u8 power_raw;
if (!(hdev->claimed & HID_CLAIMED_INPUT))
return 0;
@@ -462,13 +584,15 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
input = hidinput->input;
- /* Check if this is a tablet report */
- if (data[0] != 0x03)
- return 0;
-
switch (hdev->product) {
case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
- return wacom_gr_parse_report(hdev, wdata, input, data);
+ if (data[0] == 0x03) {
+ return wacom_gr_parse_report(hdev, wdata, input, data);
+ } else {
+ hid_err(hdev, "Unknown report: %d,%d size:%d\n",
+ data[0], data[1], size);
+ return 0;
+ }
break;
case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
i = 1;
@@ -482,6 +606,13 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
wacom_i4_parse_report(hdev, wdata, input, data + i);
i += 10;
wacom_i4_parse_report(hdev, wdata, input, data + i);
+ power_raw = data[i+10];
+ if (power_raw != wdata->power_raw) {
+ wdata->power_raw = power_raw;
+ wdata->battery_capacity = batcap_i4[power_raw & 0x07];
+ wdata->ps_connected = power_raw & 0x08;
+ }
+
break;
default:
hid_err(hdev, "Unknown report: %d,%d size:%d\n",
@@ -546,6 +677,8 @@ static int wacom_input_mapped(struct hid_device *hdev, struct hid_input *hi,
input_set_abs_params(input, ABS_Y, 0, 25400, 4, 0);
input_set_abs_params(input, ABS_PRESSURE, 0, 2047, 0, 0);
input_set_abs_params(input, ABS_DISTANCE, 0, 63, 0, 0);
+ input_set_abs_params(input, ABS_TILT_X, 0, 127, 0, 0);
+ input_set_abs_params(input, ABS_TILT_Y, 0, 127, 0, 0);
break;
}
@@ -584,19 +717,19 @@ static int wacom_probe(struct hid_device *hdev,
hid_warn(hdev,
"can't create sysfs speed attribute err: %d\n", ret);
- switch (hdev->product) {
- case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
- /* Set Wacom mode 2 with high reporting speed */
- wacom_poke(hdev, 1);
- break;
- case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
+ wdata->features = 0;
+ wacom_set_features(hdev, 1);
+
+ if (hdev->product == USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) {
sprintf(hdev->name, "%s", "Wacom Intuos4 WL");
- wdata->features = 0;
- wacom_set_features(hdev);
- break;
+ ret = wacom_initialize_leds(hdev);
+ if (ret) {
+ hid_warn(hdev,
+ "can't create led attribute, err: %d\n", ret);
+ goto destroy_leds;
+ }
}
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
wdata->battery.properties = wacom_battery_props;
wdata->battery.num_properties = ARRAY_SIZE(wacom_battery_props);
wdata->battery.get_property = wacom_battery_get_property;
@@ -629,16 +762,15 @@ static int wacom_probe(struct hid_device *hdev,
}
power_supply_powers(&wdata->ac, &hdev->dev);
-#endif
return 0;
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
err_ac:
power_supply_unregister(&wdata->battery);
err_battery:
device_remove_file(&hdev->dev, &dev_attr_speed);
hid_hw_stop(hdev);
-#endif
+destroy_leds:
+ wacom_destroy_leds(hdev);
err_free:
kfree(wdata);
return ret;
@@ -646,16 +778,14 @@ err_free:
static void wacom_remove(struct hid_device *hdev)
{
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
struct wacom_data *wdata = hid_get_drvdata(hdev);
-#endif
+
+ wacom_destroy_leds(hdev);
device_remove_file(&hdev->dev, &dev_attr_speed);
hid_hw_stop(hdev);
-#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
power_supply_unregister(&wdata->battery);
power_supply_unregister(&wdata->ac);
-#endif
kfree(hid_get_drvdata(hdev));
}
@@ -693,5 +823,5 @@ static void __exit wacom_exit(void)
module_init(wacom_init);
module_exit(wacom_exit);
+MODULE_DESCRIPTION("Driver for Wacom Graphire Bluetooth and Wacom Intuos4 WL");
MODULE_LICENSE("GPL");
-
diff --git a/drivers/hid/hid-waltop.c b/drivers/hid/hid-waltop.c
index 2cfd95c4467b..745e4e9a8cf2 100644
--- a/drivers/hid/hid-waltop.c
+++ b/drivers/hid/hid-waltop.c
@@ -502,28 +502,146 @@ static __u8 media_tablet_14_1_inch_rdesc_fixed[] = {
0xC0 /* End Collection */
};
-struct waltop_state {
- u8 pressure0;
- u8 pressure1;
+/*
+ * See Sirius Battery Free Tablet description, device and HID report descriptors
+ * at
+ * http://sf.net/apps/mediawiki/digimend/?title=Waltop_Sirius_Battery_Free_Tablet
+ */
+
+/* Size of the original report descriptor of Sirius Battery Free Tablet */
+#define SIRIUS_BATTERY_FREE_TABLET_RDESC_ORIG_SIZE 335
+
+/* Fixed Sirius Battery Free Tablet descriptor */
+static __u8 sirius_battery_free_tablet_rdesc_fixed[] = {
+ 0x05, 0x0D, /* Usage Page (Digitizer), */
+ 0x09, 0x02, /* Usage (Pen), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x10, /* Report ID (16), */
+ 0x09, 0x20, /* Usage (Stylus), */
+ 0xA0, /* Collection (Physical), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x15, 0x01, /* Logical Minimum (1), */
+ 0x25, 0x03, /* Logical Maximum (3), */
+ 0x75, 0x02, /* Report Size (2), */
+ 0x09, 0x42, /* Usage (Tip Switch), */
+ 0x09, 0x44, /* Usage (Barrel Switch), */
+ 0x09, 0x46, /* Usage (Tablet Pick), */
+ 0x80, /* Input, */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x09, 0x3C, /* Usage (Invert), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x09, 0x32, /* Usage (In Range), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0xA4, /* Push, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x55, 0xFD, /* Unit Exponent (-3), */
+ 0x65, 0x13, /* Unit (Inch), */
+ 0x34, /* Physical Minimum (0), */
+ 0x14, /* Logical Minimum (0), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x46, 0x10, 0x27, /* Physical Maximum (10000), */
+ 0x26, 0x20, 0x4E, /* Logical Maximum (20000), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x46, 0x70, 0x17, /* Physical Maximum (6000), */
+ 0x26, 0xE0, 0x2E, /* Logical Maximum (12000), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xB4, /* Pop, */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x14, /* Logical Minimum (0), */
+ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
+ 0x09, 0x30, /* Usage (Tip Pressure), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xA4, /* Push, */
+ 0x55, 0xFE, /* Unit Exponent (-2), */
+ 0x65, 0x12, /* Unit (Radians), */
+ 0x35, 0x97, /* Physical Minimum (-105), */
+ 0x45, 0x69, /* Physical Maximum (105), */
+ 0x15, 0x97, /* Logical Minimum (-105), */
+ 0x25, 0x69, /* Logical Maximum (105), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x09, 0x3D, /* Usage (X Tilt), */
+ 0x09, 0x3E, /* Usage (Y Tilt), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xB4, /* Pop, */
+ 0xC0, /* End Collection, */
+ 0xC0, /* End Collection, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x02, /* Usage (Mouse), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x01, /* Report ID (1), */
+ 0x09, 0x01, /* Usage (Pointer), */
+ 0xA0, /* Collection (Physical), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x09, 0x38, /* Usage (Wheel), */
+ 0x15, 0xFF, /* Logical Minimum (-1), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x06, /* Input (Variable, Relative), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0xC0, /* End Collection, */
+ 0xC0, /* End Collection, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x06, /* Usage (Keyboard), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x0D, /* Report ID (13), */
+ 0x05, 0x07, /* Usage Page (Keyboard), */
+ 0x19, 0xE0, /* Usage Minimum (KB Leftcontrol), */
+ 0x29, 0xE7, /* Usage Maximum (KB Right GUI), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x08, /* Report Count (8), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0x18, /* Usage Minimum (None), */
+ 0x29, 0x65, /* Usage Maximum (KB Application), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x65, /* Logical Maximum (101), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x05, /* Report Count (5), */
+ 0x80, /* Input, */
+ 0xC0, /* End Collection, */
+ 0x05, 0x0C, /* Usage Page (Consumer), */
+ 0x09, 0x01, /* Usage (Consumer Control), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0x85, 0x0C, /* Report ID (12), */
+ 0x09, 0xE9, /* Usage (Volume Inc), */
+ 0x09, 0xEA, /* Usage (Volume Dec), */
+ 0x14, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x75, 0x06, /* Report Size (6), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0xC0 /* End Collection */
};
static int waltop_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
int ret;
- struct waltop_state *s;
-
- s = kzalloc(sizeof(*s), GFP_KERNEL);
- if (s == NULL) {
- hid_err(hdev, "can't allocate device state\n");
- ret = -ENOMEM;
- goto err;
- }
-
- s->pressure0 = 0;
- s->pressure1 = 0;
-
- hid_set_drvdata(hdev, s);
ret = hid_parse(hdev);
if (ret) {
@@ -539,7 +657,6 @@ static int waltop_probe(struct hid_device *hdev,
return 0;
err:
- kfree(s);
return ret;
}
@@ -583,6 +700,12 @@ static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc,
*rsize = sizeof(media_tablet_14_1_inch_rdesc_fixed);
}
break;
+ case USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET:
+ if (*rsize == SIRIUS_BATTERY_FREE_TABLET_RDESC_ORIG_SIZE) {
+ rdesc = sirius_battery_free_tablet_rdesc_fixed;
+ *rsize = sizeof(sirius_battery_free_tablet_rdesc_fixed);
+ }
+ break;
}
return rdesc;
}
@@ -590,39 +713,72 @@ static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc,
static int waltop_raw_event(struct hid_device *hdev, struct hid_report *report,
u8 *data, int size)
{
- /* If this is a pen input report of a tablet with PID 0038 */
- if (hdev->product == USB_DEVICE_ID_WALTOP_PID_0038 &&
- report->type == HID_INPUT_REPORT &&
- report->id == 16 &&
- size == 8) {
- struct waltop_state *s = hid_get_drvdata(hdev);
-
+ /* If this is a pen input report */
+ if (report->type == HID_INPUT_REPORT && report->id == 16 && size >= 8) {
/*
- * Ignore maximum pressure reported when a barrel button is
- * pressed.
+ * Ignore reported pressure when a barrel button is pressed,
+ * because it is rarely correct.
*/
/* If a barrel button is pressed */
if ((data[1] & 0xF) > 1) {
- /* Use the last known pressure */
- data[6] = s->pressure0;
- data[7] = s->pressure1;
- } else {
- /* Remember reported pressure */
- s->pressure0 = data[6];
- s->pressure1 = data[7];
+ /* Report zero pressure */
+ data[6] = 0;
+ data[7] = 0;
}
}
+ /* If this is a pen input report of Sirius Battery Free Tablet */
+ if (hdev->product == USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET &&
+ report->type == HID_INPUT_REPORT &&
+ report->id == 16 &&
+ size == 10) {
+ /*
+ * The tablet reports tilt as roughly sin(a)*21 (18 means 60
+ * degrees).
+ *
+ * This array stores angles as radians * 100, corresponding to
+ * reported values up to 60 degrees, as expected by userspace.
+ */
+ static const s8 tilt_to_radians[] = {
+ 0, 5, 10, 14, 19, 24, 29, 34, 40, 45,
+ 50, 56, 62, 68, 74, 81, 88, 96, 105
+ };
+
+ s8 tilt_x = (s8)data[8];
+ s8 tilt_y = (s8)data[9];
+ s8 sign_x = tilt_x >= 0 ? 1 : -1;
+ s8 sign_y = tilt_y >= 0 ? 1 : -1;
+
+ tilt_x *= sign_x;
+ tilt_y *= sign_y;
+
+ /*
+ * Reverse the Y Tilt direction to match the HID standard and
+ * userspace expectations. See HID Usage Tables v1.12 16.3.2
+ * Tilt Orientation.
+ */
+ sign_y *= -1;
+
+ /*
+ * This effectively clamps reported tilt to 60 degrees - the
+ * range expected by userspace
+ */
+ if (tilt_x > ARRAY_SIZE(tilt_to_radians) - 1)
+ tilt_x = ARRAY_SIZE(tilt_to_radians) - 1;
+ if (tilt_y > ARRAY_SIZE(tilt_to_radians) - 1)
+ tilt_y = ARRAY_SIZE(tilt_to_radians) - 1;
+
+ data[8] = tilt_to_radians[tilt_x] * sign_x;
+ data[9] = tilt_to_radians[tilt_y] * sign_y;
+ }
+
return 0;
}
static void waltop_remove(struct hid_device *hdev)
{
- struct waltop_state *s = hid_get_drvdata(hdev);
-
hid_hw_stop(hdev);
- kfree(s);
}
static const struct hid_device_id waltop_devices[] = {
@@ -638,6 +794,8 @@ static const struct hid_device_id waltop_devices[] = {
USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
+ USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) },
{ }
};
MODULE_DEVICE_TABLE(hid, waltop_devices);
diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c
index cac3589b1ed5..84e2fbec5fbb 100644
--- a/drivers/hid/hid-wiimote-core.c
+++ b/drivers/hid/hid-wiimote-core.c
@@ -769,7 +769,7 @@ static void __ir_to_input(struct wiimote_data *wdata, const __u8 *ir,
/*
* Basic IR data is encoded into 3 bytes. The first two bytes are the
- * upper 8 bit of the X/Y data, the 3rd byte contains the lower 2 bits
+ * lower 8 bit of the X/Y data, the 3rd byte contains the upper 2 bits
* of both.
* If data is packed, then the 3rd byte is put first and slightly
* reordered. This allows to interleave packed and non-packed data to
@@ -778,17 +778,11 @@ static void __ir_to_input(struct wiimote_data *wdata, const __u8 *ir,
*/
if (packed) {
- x = ir[1] << 2;
- y = ir[2] << 2;
-
- x |= ir[0] & 0x3;
- y |= (ir[0] >> 2) & 0x3;
+ x = ir[1] | ((ir[0] & 0x03) << 8);
+ y = ir[2] | ((ir[0] & 0x0c) << 6);
} else {
- x = ir[0] << 2;
- y = ir[1] << 2;
-
- x |= (ir[2] >> 4) & 0x3;
- y |= (ir[2] >> 6) & 0x3;
+ x = ir[0] | ((ir[2] & 0x30) << 4);
+ y = ir[1] | ((ir[2] & 0xc0) << 2);
}
input_report_abs(wdata->ir, xid, x);
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index cf7d6d58e79f..36fa77b40ffb 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -87,11 +87,13 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
len = list->buffer[list->tail].len > count ?
count : list->buffer[list->tail].len;
- if (copy_to_user(buffer, list->buffer[list->tail].value, len)) {
- ret = -EFAULT;
- goto out;
+ if (list->buffer[list->tail].value) {
+ if (copy_to_user(buffer, list->buffer[list->tail].value, len)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ ret = len;
}
- ret = len;
kfree(list->buffer[list->tail].value);
list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1);
@@ -437,19 +439,24 @@ static const struct file_operations hidraw_ops = {
.llseek = noop_llseek,
};
-void hidraw_report_event(struct hid_device *hid, u8 *data, int len)
+int hidraw_report_event(struct hid_device *hid, u8 *data, int len)
{
struct hidraw *dev = hid->hidraw;
struct hidraw_list *list;
+ int ret = 0;
list_for_each_entry(list, &dev->list, node) {
- list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC);
+ if (!(list->buffer[list->head].value = kmemdup(data, len, GFP_ATOMIC))) {
+ ret = -ENOMEM;
+ break;
+ }
list->buffer[list->head].len = len;
list->head = (list->head + 1) & (HIDRAW_BUFFER_SIZE - 1);
kill_fasync(&list->fasync, SIGIO, POLL_IN);
}
wake_up_interruptible(&dev->wait);
+ return ret;
}
EXPORT_SYMBOL_GPL(hidraw_report_event);
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 5bf91dbad59d..482f936fc29b 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -28,6 +28,7 @@
#include <linux/input.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
+#include <linux/string.h>
#include <linux/usb.h>
@@ -86,8 +87,13 @@ static int hid_start_in(struct hid_device *hid)
!test_bit(HID_REPORTED_IDLE, &usbhid->iofl) &&
!test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) {
rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC);
- if (rc != 0)
+ if (rc != 0) {
clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+ if (rc == -ENOSPC)
+ set_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
+ } else {
+ clear_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
+ }
}
spin_unlock_irqrestore(&usbhid->lock, flags);
return rc;
@@ -173,8 +179,10 @@ static void hid_io_error(struct hid_device *hid)
if (time_after(jiffies, usbhid->stop_retry)) {
- /* Retries failed, so do a port reset */
- if (!test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) {
+ /* Retries failed, so do a port reset unless we lack bandwidth*/
+ if (test_bit(HID_NO_BANDWIDTH, &usbhid->iofl)
+ && !test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) {
+
schedule_work(&usbhid->reset_work);
goto done;
}
@@ -203,7 +211,7 @@ static int usbhid_restart_out_queue(struct usbhid_device *usbhid)
return 0;
if ((kicked = (usbhid->outhead != usbhid->outtail))) {
- dbg("Kicking head %d tail %d", usbhid->outhead, usbhid->outtail);
+ hid_dbg(hid, "Kicking head %d tail %d", usbhid->outhead, usbhid->outtail);
r = usb_autopm_get_interface_async(usbhid->intf);
if (r < 0)
@@ -230,7 +238,7 @@ static int usbhid_restart_ctrl_queue(struct usbhid_device *usbhid)
return 0;
if ((kicked = (usbhid->ctrlhead != usbhid->ctrltail))) {
- dbg("Kicking head %d tail %d", usbhid->ctrlhead, usbhid->ctrltail);
+ hid_dbg(hid, "Kicking head %d tail %d", usbhid->ctrlhead, usbhid->ctrltail);
r = usb_autopm_get_interface_async(usbhid->intf);
if (r < 0)
@@ -399,6 +407,16 @@ static int hid_submit_ctrl(struct hid_device *hid)
* Output interrupt completion handler.
*/
+static int irq_out_pump_restart(struct hid_device *hid)
+{
+ struct usbhid_device *usbhid = hid->driver_data;
+
+ if (usbhid->outhead != usbhid->outtail)
+ return hid_submit_out(hid);
+ else
+ return -1;
+}
+
static void hid_irq_out(struct urb *urb)
{
struct hid_device *hid = urb->context;
@@ -428,7 +446,7 @@ static void hid_irq_out(struct urb *urb)
else
usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1);
- if (usbhid->outhead != usbhid->outtail && !hid_submit_out(hid)) {
+ if (!irq_out_pump_restart(hid)) {
/* Successfully submitted next urb in queue */
spin_unlock_irqrestore(&usbhid->lock, flags);
return;
@@ -443,6 +461,15 @@ static void hid_irq_out(struct urb *urb)
/*
* Control pipe completion handler.
*/
+static int ctrl_pump_restart(struct hid_device *hid)
+{
+ struct usbhid_device *usbhid = hid->driver_data;
+
+ if (usbhid->ctrlhead != usbhid->ctrltail)
+ return hid_submit_ctrl(hid);
+ else
+ return -1;
+}
static void hid_ctrl(struct urb *urb)
{
@@ -476,7 +503,7 @@ static void hid_ctrl(struct urb *urb)
else
usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
- if (usbhid->ctrlhead != usbhid->ctrltail && !hid_submit_ctrl(hid)) {
+ if (!ctrl_pump_restart(hid)) {
/* Successfully submitted next urb in queue */
spin_unlock(&usbhid->lock);
return;
@@ -535,11 +562,27 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
* the queue is known to run
* but an earlier request may be stuck
* we may need to time out
- * no race because this is called under
+ * no race because the URB is blocked under
* spinlock
*/
- if (time_after(jiffies, usbhid->last_out + HZ * 5))
+ if (time_after(jiffies, usbhid->last_out + HZ * 5)) {
+ usb_block_urb(usbhid->urbout);
+ /* drop lock to not deadlock if the callback is called */
+ spin_unlock(&usbhid->lock);
usb_unlink_urb(usbhid->urbout);
+ spin_lock(&usbhid->lock);
+ usb_unblock_urb(usbhid->urbout);
+ /*
+ * if the unlinking has already completed
+ * the pump will have been stopped
+ * it must be restarted now
+ */
+ if (!test_bit(HID_OUT_RUNNING, &usbhid->iofl))
+ if (!irq_out_pump_restart(hid))
+ set_bit(HID_OUT_RUNNING, &usbhid->iofl);
+
+
+ }
}
return;
}
@@ -583,11 +626,25 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
* the queue is known to run
* but an earlier request may be stuck
* we may need to time out
- * no race because this is called under
+ * no race because the URB is blocked under
* spinlock
*/
- if (time_after(jiffies, usbhid->last_ctrl + HZ * 5))
+ if (time_after(jiffies, usbhid->last_ctrl + HZ * 5)) {
+ usb_block_urb(usbhid->urbctrl);
+ /* drop lock to not deadlock if the callback is called */
+ spin_unlock(&usbhid->lock);
usb_unlink_urb(usbhid->urbctrl);
+ spin_lock(&usbhid->lock);
+ usb_unblock_urb(usbhid->urbctrl);
+ /*
+ * if the unlinking has already completed
+ * the pump will have been stopped
+ * it must be restarted now
+ */
+ if (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl))
+ if (!ctrl_pump_restart(hid))
+ set_bit(HID_CTRL_RUNNING, &usbhid->iofl);
+ }
}
}
@@ -700,7 +757,7 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
int usbhid_open(struct hid_device *hid)
{
struct usbhid_device *usbhid = hid->driver_data;
- int res;
+ int res = 0;
mutex_lock(&hid_open_mut);
if (!hid->open++) {
@@ -708,17 +765,27 @@ int usbhid_open(struct hid_device *hid)
/* the device must be awake to reliably request remote wakeup */
if (res < 0) {
hid->open--;
- mutex_unlock(&hid_open_mut);
- return -EIO;
+ res = -EIO;
+ goto done;
}
usbhid->intf->needs_remote_wakeup = 1;
- if (hid_start_in(hid))
- hid_io_error(hid);
-
+ res = hid_start_in(hid);
+ if (res) {
+ if (res != -ENOSPC) {
+ hid_io_error(hid);
+ res = 0;
+ } else {
+ /* no use opening if resources are insufficient */
+ hid->open--;
+ res = -EBUSY;
+ usbhid->intf->needs_remote_wakeup = 0;
+ }
+ }
usb_autopm_put_interface(usbhid->intf);
}
+done:
mutex_unlock(&hid_open_mut);
- return 0;
+ return res;
}
void usbhid_close(struct hid_device *hid)
@@ -1347,7 +1414,34 @@ static int hid_post_reset(struct usb_interface *intf)
struct usb_device *dev = interface_to_usbdev (intf);
struct hid_device *hid = usb_get_intfdata(intf);
struct usbhid_device *usbhid = hid->driver_data;
+ struct usb_host_interface *interface = intf->cur_altsetting;
int status;
+ char *rdesc;
+
+ /* Fetch and examine the HID report descriptor. If this
+ * has changed, then rebind. Since usbcore's check of the
+ * configuration descriptors passed, we already know that
+ * the size of the HID report descriptor has not changed.
+ */
+ rdesc = kmalloc(hid->rsize, GFP_KERNEL);
+ if (!rdesc) {
+ dbg_hid("couldn't allocate rdesc memory (post_reset)\n");
+ return 1;
+ }
+ status = hid_get_class_descriptor(dev,
+ interface->desc.bInterfaceNumber,
+ HID_DT_REPORT, rdesc, hid->rsize);
+ if (status < 0) {
+ dbg_hid("reading report descriptor failed (post_reset)\n");
+ kfree(rdesc);
+ return 1;
+ }
+ status = memcmp(rdesc, hid->rdesc, hid->rsize);
+ kfree(rdesc);
+ if (status != 0) {
+ dbg_hid("report descriptor changed\n");
+ return 1;
+ }
spin_lock_irq(&usbhid->lock);
clear_bit(HID_RESET_PENDING, &usbhid->iofl);
@@ -1504,28 +1598,15 @@ static struct usb_driver hid_driver = {
.supports_autosuspend = 1,
};
-static const struct hid_device_id hid_usb_table[] = {
- { HID_USB_DEVICE(HID_ANY_ID, HID_ANY_ID) },
- { }
-};
-
struct usb_interface *usbhid_find_interface(int minor)
{
return usb_find_interface(&hid_driver, minor);
}
-static struct hid_driver hid_usb_driver = {
- .name = "generic-usb",
- .id_table = hid_usb_table,
-};
-
static int __init hid_init(void)
{
int retval = -ENOMEM;
- retval = hid_register_driver(&hid_usb_driver);
- if (retval)
- goto hid_register_fail;
retval = usbhid_quirks_init(quirks_param);
if (retval)
goto usbhid_quirks_init_fail;
@@ -1538,8 +1619,6 @@ static int __init hid_init(void)
usb_register_fail:
usbhid_quirks_exit();
usbhid_quirks_init_fail:
- hid_unregister_driver(&hid_usb_driver);
-hid_register_fail:
return retval;
}
@@ -1547,7 +1626,6 @@ static void __exit hid_exit(void)
{
usb_deregister(&hid_driver);
usbhid_quirks_exit();
- hid_unregister_driver(&hid_usb_driver);
}
module_init(hid_init);
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 782c63955f29..0597ee604f6e 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -88,6 +88,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index b1ec0e2aeb57..14599e256791 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -34,6 +34,7 @@
#include <linux/hid.h>
#include <linux/hiddev.h>
#include <linux/compat.h>
+#include <linux/vmalloc.h>
#include "usbhid.h"
#ifdef CONFIG_USB_DYNAMIC_MINORS
@@ -250,13 +251,13 @@ static int hiddev_release(struct inode * inode, struct file * file)
} else {
mutex_unlock(&list->hiddev->existancelock);
kfree(list->hiddev);
- kfree(list);
+ vfree(list);
return 0;
}
}
mutex_unlock(&list->hiddev->existancelock);
- kfree(list);
+ vfree(list);
return 0;
}
@@ -278,7 +279,7 @@ static int hiddev_open(struct inode *inode, struct file *file)
hid = usb_get_intfdata(intf);
hiddev = hid->hiddev;
- if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
+ if (!(list = vzalloc(sizeof(struct hiddev_list))))
return -ENOMEM;
mutex_init(&list->thread_lock);
list->hiddev = hiddev;
@@ -322,7 +323,7 @@ bail_unlock:
mutex_unlock(&hiddev->existancelock);
bail:
file->private_data = NULL;
- kfree(list);
+ vfree(list);
return res;
}
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
index cb8f703efde5..1883d7b94870 100644
--- a/drivers/hid/usbhid/usbhid.h
+++ b/drivers/hid/usbhid/usbhid.h
@@ -55,6 +55,7 @@ struct usb_interface *usbhid_find_interface(int minor);
#define HID_STARTED 8
#define HID_REPORTED_IDLE 9
#define HID_KEYS_PRESSED 10
+#define HID_NO_BANDWIDTH 11
/*
* USB-specific HID struct, to be pointed to
diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c
index 0f6be45d43d5..bf16d72dc370 100644
--- a/drivers/hid/usbhid/usbmouse.c
+++ b/drivers/hid/usbhid/usbmouse.c
@@ -92,9 +92,10 @@ static void usb_mouse_irq(struct urb *urb)
resubmit:
status = usb_submit_urb (urb, GFP_ATOMIC);
if (status)
- err ("can't resubmit intr, %s-%s/input0, status %d",
- mouse->usbdev->bus->bus_name,
- mouse->usbdev->devpath, status);
+ dev_err(&mouse->usbdev->dev,
+ "can't resubmit intr, %s-%s/input0, status %d\n",
+ mouse->usbdev->bus->bus_name,
+ mouse->usbdev->devpath, status);
}
static int usb_mouse_open(struct input_dev *dev)
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 9ffbfc575a0c..2b8b8d4558d2 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -46,40 +46,61 @@ struct vmbus_channel_message_table_entry {
*
* @icmsghdrp is of type &struct icmsg_hdr.
* @negop is of type &struct icmsg_negotiate.
- * Set up and fill in default negotiate response message. This response can
- * come from both the vmbus driver and the hv_utils driver. The current api
- * will respond properly to both Windows 2008 and Windows 2008-R2 operating
- * systems.
+ * Set up and fill in default negotiate response message.
+ *
+ * The max_fw_version specifies the maximum framework version that
+ * we can support and max _srv_version specifies the maximum service
+ * version we can support. A special value MAX_SRV_VER can be
+ * specified to indicate that we can handle the maximum version
+ * exposed by the host.
*
* Mainly used by Hyper-V drivers.
*/
void vmbus_prep_negotiate_resp(struct icmsg_hdr *icmsghdrp,
- struct icmsg_negotiate *negop, u8 *buf)
+ struct icmsg_negotiate *negop, u8 *buf,
+ int max_fw_version, int max_srv_version)
{
- if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
- icmsghdrp->icmsgsize = 0x10;
-
- negop = (struct icmsg_negotiate *)&buf[
- sizeof(struct vmbuspipe_hdr) +
- sizeof(struct icmsg_hdr)];
-
- if (negop->icframe_vercnt == 2 &&
- negop->icversion_data[1].major == 3) {
- negop->icversion_data[0].major = 3;
- negop->icversion_data[0].minor = 0;
- negop->icversion_data[1].major = 3;
- negop->icversion_data[1].minor = 0;
- } else {
- negop->icversion_data[0].major = 1;
- negop->icversion_data[0].minor = 0;
- negop->icversion_data[1].major = 1;
- negop->icversion_data[1].minor = 0;
- }
+ int icframe_vercnt;
+ int icmsg_vercnt;
+ int i;
+
+ icmsghdrp->icmsgsize = 0x10;
+
+ negop = (struct icmsg_negotiate *)&buf[
+ sizeof(struct vmbuspipe_hdr) +
+ sizeof(struct icmsg_hdr)];
+
+ icframe_vercnt = negop->icframe_vercnt;
+ icmsg_vercnt = negop->icmsg_vercnt;
+
+ /*
+ * Select the framework version number we will
+ * support.
+ */
+
+ for (i = 0; i < negop->icframe_vercnt; i++) {
+ if (negop->icversion_data[i].major <= max_fw_version)
+ icframe_vercnt = negop->icversion_data[i].major;
+ }
- negop->icframe_vercnt = 1;
- negop->icmsg_vercnt = 1;
+ for (i = negop->icframe_vercnt;
+ (i < negop->icframe_vercnt + negop->icmsg_vercnt); i++) {
+ if (negop->icversion_data[i].major <= max_srv_version)
+ icmsg_vercnt = negop->icversion_data[i].major;
}
+
+ /*
+ * Respond with the maximum framework and service
+ * version numbers we can support.
+ */
+ negop->icframe_vercnt = 1;
+ negop->icmsg_vercnt = 1;
+ negop->icversion_data[0].major = icframe_vercnt;
+ negop->icversion_data[0].minor = 0;
+ negop->icversion_data[1].major = icmsg_vercnt;
+ negop->icversion_data[1].minor = 0;
}
+
EXPORT_SYMBOL_GPL(vmbus_prep_negotiate_resp);
/*
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index 15956bd48b48..86f8885aeb45 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -252,7 +252,7 @@ void hv_cleanup(void)
*
* This involves a hypercall.
*/
-u16 hv_post_message(union hv_connection_id connection_id,
+int hv_post_message(union hv_connection_id connection_id,
enum hv_message_type message_type,
void *payload, size_t payload_size)
{
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 6186025209ce..0012eed6d872 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -394,7 +394,8 @@ void hv_kvp_onchannelcallback(void *context)
sizeof(struct vmbuspipe_hdr)];
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
- vmbus_prep_negotiate_resp(icmsghdrp, negop, recv_buffer);
+ vmbus_prep_negotiate_resp(icmsghdrp, negop,
+ recv_buffer, MAX_SRV_VER, MAX_SRV_VER);
} else {
kvp_msg = (struct hv_kvp_msg *)&recv_buffer[
sizeof(struct vmbuspipe_hdr) +
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c
index dbb8b8eec210..d3ac6a40118b 100644
--- a/drivers/hv/hv_util.c
+++ b/drivers/hv/hv_util.c
@@ -70,7 +70,8 @@ static void shutdown_onchannelcallback(void *context)
sizeof(struct vmbuspipe_hdr)];
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
- vmbus_prep_negotiate_resp(icmsghdrp, negop, shut_txf_buf);
+ vmbus_prep_negotiate_resp(icmsghdrp, negop,
+ shut_txf_buf, MAX_SRV_VER, MAX_SRV_VER);
} else {
shutdown_msg =
(struct shutdown_msg_data *)&shut_txf_buf[
@@ -195,7 +196,8 @@ static void timesync_onchannelcallback(void *context)
sizeof(struct vmbuspipe_hdr)];
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
- vmbus_prep_negotiate_resp(icmsghdrp, NULL, time_txf_buf);
+ vmbus_prep_negotiate_resp(icmsghdrp, NULL, time_txf_buf,
+ MAX_SRV_VER, MAX_SRV_VER);
} else {
timedatap = (struct ictimesync_data *)&time_txf_buf[
sizeof(struct vmbuspipe_hdr) +
@@ -234,7 +236,8 @@ static void heartbeat_onchannelcallback(void *context)
sizeof(struct vmbuspipe_hdr)];
if (icmsghdrp->icmsgtype == ICMSGTYPE_NEGOTIATE) {
- vmbus_prep_negotiate_resp(icmsghdrp, NULL, hbeat_txf_buf);
+ vmbus_prep_negotiate_resp(icmsghdrp, NULL,
+ hbeat_txf_buf, MAX_SRV_VER, MAX_SRV_VER);
} else {
heartbeat_msg =
(struct heartbeat_msg_data *)&hbeat_txf_buf[
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 699f0d8e59ed..b9426a6592ee 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -495,7 +495,7 @@ extern int hv_init(void);
extern void hv_cleanup(void);
-extern u16 hv_post_message(union hv_connection_id connection_id,
+extern int hv_post_message(union hv_connection_id connection_id,
enum hv_message_type message_type,
void *payload, size_t payload_size);
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 8deedc1b9840..7cd9bf42108b 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -318,7 +318,7 @@ config SENSORS_EXYNOS4_TMU
tristate "Temperature sensor on Samsung EXYNOS4"
depends on ARCH_EXYNOS4
help
- If you say yes here you get support for TMU (Thermal Managment
+ If you say yes here you get support for TMU (Thermal Management
Unit) on SAMSUNG EXYNOS4 series of SoC.
This driver can also be built as a module. If so, the module
@@ -1102,6 +1102,19 @@ config SENSORS_AMC6821
This driver can also be build as a module. If so, the module
will be called amc6821.
+config SENSORS_INA2XX
+ tristate "Texas Instruments INA219, INA226"
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for INA219 and INA226 power
+ monitor chips.
+
+ The INA2xx driver is configured for the default configuration of
+ the part as described in the datasheet.
+ Default value for Rshunt is 10 mOhms.
+ This driver can also be built as a module. If so, the module
+ will be called ina2xx.
+
config SENSORS_THMC50
tristate "Texas Instruments THMC50 / Analog Devices ADM1022"
depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 6d3f11f71815..e1eeac13b851 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -62,6 +62,7 @@ obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o
obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o
+obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o
obj-$(CONFIG_SENSORS_IT87) += it87.o
obj-$(CONFIG_SENSORS_JC42) += jc42.o
obj-$(CONFIG_SENSORS_JZ4740) += jz4740-hwmon.o
diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c
index 9140236a0182..34ad5a27a7e9 100644
--- a/drivers/hwmon/acpi_power_meter.c
+++ b/drivers/hwmon/acpi_power_meter.c
@@ -107,15 +107,7 @@ struct acpi_power_meter_resource {
struct kobject *holders_dir;
};
-struct ro_sensor_template {
- char *label;
- ssize_t (*show)(struct device *dev,
- struct device_attribute *devattr,
- char *buf);
- int index;
-};
-
-struct rw_sensor_template {
+struct sensor_template {
char *label;
ssize_t (*show)(struct device *dev,
struct device_attribute *devattr,
@@ -469,52 +461,67 @@ static ssize_t show_name(struct device *dev,
return sprintf(buf, "%s\n", ACPI_POWER_METER_NAME);
}
+#define RO_SENSOR_TEMPLATE(_label, _show, _index) \
+ { \
+ .label = _label, \
+ .show = _show, \
+ .index = _index, \
+ }
+
+#define RW_SENSOR_TEMPLATE(_label, _show, _set, _index) \
+ { \
+ .label = _label, \
+ .show = _show, \
+ .set = _set, \
+ .index = _index, \
+ }
+
/* Sensor descriptions. If you add a sensor, update NUM_SENSORS above! */
-static struct ro_sensor_template meter_ro_attrs[] = {
-{POWER_AVERAGE_NAME, show_power, 0},
-{"power1_accuracy", show_accuracy, 0},
-{"power1_average_interval_min", show_val, 0},
-{"power1_average_interval_max", show_val, 1},
-{"power1_is_battery", show_val, 5},
-{NULL, NULL, 0},
+static struct sensor_template meter_attrs[] = {
+ RO_SENSOR_TEMPLATE(POWER_AVERAGE_NAME, show_power, 0),
+ RO_SENSOR_TEMPLATE("power1_accuracy", show_accuracy, 0),
+ RO_SENSOR_TEMPLATE("power1_average_interval_min", show_val, 0),
+ RO_SENSOR_TEMPLATE("power1_average_interval_max", show_val, 1),
+ RO_SENSOR_TEMPLATE("power1_is_battery", show_val, 5),
+ RW_SENSOR_TEMPLATE(POWER_AVG_INTERVAL_NAME, show_avg_interval,
+ set_avg_interval, 0),
+ {},
};
-static struct rw_sensor_template meter_rw_attrs[] = {
-{POWER_AVG_INTERVAL_NAME, show_avg_interval, set_avg_interval, 0},
-{NULL, NULL, NULL, 0},
+static struct sensor_template misc_cap_attrs[] = {
+ RO_SENSOR_TEMPLATE("power1_cap_min", show_val, 2),
+ RO_SENSOR_TEMPLATE("power1_cap_max", show_val, 3),
+ RO_SENSOR_TEMPLATE("power1_cap_hyst", show_val, 4),
+ RO_SENSOR_TEMPLATE(POWER_ALARM_NAME, show_val, 6),
+ {},
};
-static struct ro_sensor_template misc_cap_attrs[] = {
-{"power1_cap_min", show_val, 2},
-{"power1_cap_max", show_val, 3},
-{"power1_cap_hyst", show_val, 4},
-{POWER_ALARM_NAME, show_val, 6},
-{NULL, NULL, 0},
+static struct sensor_template ro_cap_attrs[] = {
+ RO_SENSOR_TEMPLATE(POWER_CAP_NAME, show_cap, 0),
+ {},
};
-static struct ro_sensor_template ro_cap_attrs[] = {
-{POWER_CAP_NAME, show_cap, 0},
-{NULL, NULL, 0},
+static struct sensor_template rw_cap_attrs[] = {
+ RW_SENSOR_TEMPLATE(POWER_CAP_NAME, show_cap, set_cap, 0),
+ {},
};
-static struct rw_sensor_template rw_cap_attrs[] = {
-{POWER_CAP_NAME, show_cap, set_cap, 0},
-{NULL, NULL, NULL, 0},
+static struct sensor_template trip_attrs[] = {
+ RW_SENSOR_TEMPLATE("power1_average_min", show_val, set_trip, 7),
+ RW_SENSOR_TEMPLATE("power1_average_max", show_val, set_trip, 8),
+ {},
};
-static struct rw_sensor_template trip_attrs[] = {
-{"power1_average_min", show_val, set_trip, 7},
-{"power1_average_max", show_val, set_trip, 8},
-{NULL, NULL, NULL, 0},
+static struct sensor_template misc_attrs[] = {
+ RO_SENSOR_TEMPLATE("name", show_name, 0),
+ RO_SENSOR_TEMPLATE("power1_model_number", show_str, 0),
+ RO_SENSOR_TEMPLATE("power1_oem_info", show_str, 2),
+ RO_SENSOR_TEMPLATE("power1_serial_number", show_str, 1),
+ {},
};
-static struct ro_sensor_template misc_attrs[] = {
-{"name", show_name, 0},
-{"power1_model_number", show_str, 0},
-{"power1_oem_info", show_str, 2},
-{"power1_serial_number", show_str, 1},
-{NULL, NULL, 0},
-};
+#undef RO_SENSOR_TEMPLATE
+#undef RW_SENSOR_TEMPLATE
/* Read power domain data */
static void remove_domain_devices(struct acpi_power_meter_resource *resource)
@@ -619,49 +626,24 @@ end:
}
/* Registration and deregistration */
-static int register_ro_attrs(struct acpi_power_meter_resource *resource,
- struct ro_sensor_template *ro)
+static int register_attrs(struct acpi_power_meter_resource *resource,
+ struct sensor_template *attrs)
{
struct device *dev = &resource->acpi_dev->dev;
struct sensor_device_attribute *sensors =
&resource->sensors[resource->num_sensors];
int res = 0;
- while (ro->label) {
- sensors->dev_attr.attr.name = ro->label;
+ while (attrs->label) {
+ sensors->dev_attr.attr.name = attrs->label;
sensors->dev_attr.attr.mode = S_IRUGO;
- sensors->dev_attr.show = ro->show;
- sensors->index = ro->index;
+ sensors->dev_attr.show = attrs->show;
+ sensors->index = attrs->index;
- sysfs_attr_init(&sensors->dev_attr.attr);
- res = device_create_file(dev, &sensors->dev_attr);
- if (res) {
- sensors->dev_attr.attr.name = NULL;
- goto error;
+ if (attrs->set) {
+ sensors->dev_attr.attr.mode |= S_IWUSR;
+ sensors->dev_attr.store = attrs->set;
}
- sensors++;
- resource->num_sensors++;
- ro++;
- }
-
-error:
- return res;
-}
-
-static int register_rw_attrs(struct acpi_power_meter_resource *resource,
- struct rw_sensor_template *rw)
-{
- struct device *dev = &resource->acpi_dev->dev;
- struct sensor_device_attribute *sensors =
- &resource->sensors[resource->num_sensors];
- int res = 0;
-
- while (rw->label) {
- sensors->dev_attr.attr.name = rw->label;
- sensors->dev_attr.attr.mode = S_IRUGO | S_IWUSR;
- sensors->dev_attr.show = rw->show;
- sensors->dev_attr.store = rw->set;
- sensors->index = rw->index;
sysfs_attr_init(&sensors->dev_attr.attr);
res = device_create_file(dev, &sensors->dev_attr);
@@ -671,7 +653,7 @@ static int register_rw_attrs(struct acpi_power_meter_resource *resource,
}
sensors++;
resource->num_sensors++;
- rw++;
+ attrs++;
}
error:
@@ -703,10 +685,7 @@ static int setup_attrs(struct acpi_power_meter_resource *resource)
return res;
if (resource->caps.flags & POWER_METER_CAN_MEASURE) {
- res = register_ro_attrs(resource, meter_ro_attrs);
- if (res)
- goto error;
- res = register_rw_attrs(resource, meter_rw_attrs);
+ res = register_attrs(resource, meter_attrs);
if (res)
goto error;
}
@@ -718,28 +697,27 @@ static int setup_attrs(struct acpi_power_meter_resource *resource)
goto skip_unsafe_cap;
}
- if (resource->caps.configurable_cap) {
- res = register_rw_attrs(resource, rw_cap_attrs);
- if (res)
- goto error;
- } else {
- res = register_ro_attrs(resource, ro_cap_attrs);
- if (res)
- goto error;
- }
- res = register_ro_attrs(resource, misc_cap_attrs);
+ if (resource->caps.configurable_cap)
+ res = register_attrs(resource, rw_cap_attrs);
+ else
+ res = register_attrs(resource, ro_cap_attrs);
+
+ if (res)
+ goto error;
+
+ res = register_attrs(resource, misc_cap_attrs);
if (res)
goto error;
}
-skip_unsafe_cap:
+skip_unsafe_cap:
if (resource->caps.flags & POWER_METER_CAN_TRIP) {
- res = register_rw_attrs(resource, trip_attrs);
+ res = register_attrs(resource, trip_attrs);
if (res)
goto error;
}
- res = register_ro_attrs(resource, misc_attrs);
+ res = register_attrs(resource, misc_attrs);
if (res)
goto error;
diff --git a/drivers/hwmon/ad7314.c b/drivers/hwmon/ad7314.c
index f85ce70d9677..cfec802cf9ca 100644
--- a/drivers/hwmon/ad7314.c
+++ b/drivers/hwmon/ad7314.c
@@ -18,21 +18,14 @@
#include <linux/hwmon-sysfs.h>
/*
- * AD7314 power mode
- */
-#define AD7314_PD 0x2000
-
-/*
* AD7314 temperature masks
*/
-#define AD7314_TEMP_SIGN 0x200
#define AD7314_TEMP_MASK 0x7FE0
-#define AD7314_TEMP_OFFSET 5
+#define AD7314_TEMP_SHIFT 5
/*
* ADT7301 and ADT7302 temperature masks
*/
-#define ADT7301_TEMP_SIGN 0x2000
#define ADT7301_TEMP_MASK 0x3FFF
enum ad7314_variant {
@@ -73,7 +66,7 @@ static ssize_t ad7314_show_temperature(struct device *dev,
return ret;
switch (spi_get_device_id(chip->spi_dev)->driver_data) {
case ad7314:
- data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_OFFSET;
+ data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_SHIFT;
data = (data << 6) >> 6;
return sprintf(buf, "%d\n", 250 * data);
diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c
index e8e18cab1fb8..6b13f1a4dc27 100644
--- a/drivers/hwmon/fam15h_power.c
+++ b/drivers/hwmon/fam15h_power.c
@@ -257,15 +257,4 @@ static struct pci_driver fam15h_power_driver = {
.remove = __devexit_p(fam15h_power_remove),
};
-static int __init fam15h_power_init(void)
-{
- return pci_register_driver(&fam15h_power_driver);
-}
-
-static void __exit fam15h_power_exit(void)
-{
- pci_unregister_driver(&fam15h_power_driver);
-}
-
-module_init(fam15h_power_init)
-module_exit(fam15h_power_exit)
+module_pci_driver(fam15h_power_driver);
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
new file mode 100644
index 000000000000..7f3f4a385729
--- /dev/null
+++ b/drivers/hwmon/ina2xx.c
@@ -0,0 +1,368 @@
+/*
+ * Driver for Texas Instruments INA219, INA226 power monitor chips
+ *
+ * INA219:
+ * Zero Drift Bi-Directional Current/Power Monitor with I2C Interface
+ * Datasheet: http://www.ti.com/product/ina219
+ *
+ * INA226:
+ * Bi-Directional Current/Power Monitor with I2C Interface
+ * Datasheet: http://www.ti.com/product/ina226
+ *
+ * Copyright (C) 2012 Lothar Felten <l-felten@ti.com>
+ * Thanks to Jan Volkering
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+
+#include <linux/platform_data/ina2xx.h>
+
+/* common register definitions */
+#define INA2XX_CONFIG 0x00
+#define INA2XX_SHUNT_VOLTAGE 0x01 /* readonly */
+#define INA2XX_BUS_VOLTAGE 0x02 /* readonly */
+#define INA2XX_POWER 0x03 /* readonly */
+#define INA2XX_CURRENT 0x04 /* readonly */
+#define INA2XX_CALIBRATION 0x05
+
+/* INA226 register definitions */
+#define INA226_MASK_ENABLE 0x06
+#define INA226_ALERT_LIMIT 0x07
+#define INA226_DIE_ID 0xFF
+
+
+/* register count */
+#define INA219_REGISTERS 6
+#define INA226_REGISTERS 8
+
+#define INA2XX_MAX_REGISTERS 8
+
+/* settings - depend on use case */
+#define INA219_CONFIG_DEFAULT 0x399F /* PGA=8 */
+#define INA226_CONFIG_DEFAULT 0x4527 /* averages=16 */
+
+/* worst case is 68.10 ms (~14.6Hz, ina219) */
+#define INA2XX_CONVERSION_RATE 15
+
+enum ina2xx_ids { ina219, ina226 };
+
+struct ina2xx_data {
+ struct device *hwmon_dev;
+
+ struct mutex update_lock;
+ bool valid;
+ unsigned long last_updated;
+
+ int kind;
+ int registers;
+ u16 regs[INA2XX_MAX_REGISTERS];
+};
+
+int ina2xx_read_word(struct i2c_client *client, int reg)
+{
+ int val = i2c_smbus_read_word_data(client, reg);
+ if (unlikely(val < 0)) {
+ dev_dbg(&client->dev,
+ "Failed to read register: %d\n", reg);
+ return val;
+ }
+ return be16_to_cpu(val);
+}
+
+void ina2xx_write_word(struct i2c_client *client, int reg, int data)
+{
+ i2c_smbus_write_word_data(client, reg, cpu_to_be16(data));
+}
+
+static struct ina2xx_data *ina2xx_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ina2xx_data *data = i2c_get_clientdata(client);
+ struct ina2xx_data *ret = data;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated +
+ HZ / INA2XX_CONVERSION_RATE) || !data->valid) {
+
+ int i;
+
+ dev_dbg(&client->dev, "Starting ina2xx update\n");
+
+ /* Read all registers */
+ for (i = 0; i < data->registers; i++) {
+ int rv = ina2xx_read_word(client, i);
+ if (rv < 0) {
+ ret = ERR_PTR(rv);
+ goto abort;
+ }
+ data->regs[i] = rv;
+ }
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+abort:
+ mutex_unlock(&data->update_lock);
+ return ret;
+}
+
+static int ina219_get_value(struct ina2xx_data *data, u8 reg)
+{
+ /*
+ * calculate exact value for the given register
+ * we assume default power-on reset settings:
+ * bus voltage range 32V
+ * gain = /8
+ * adc 1 & 2 -> conversion time 532uS
+ * mode is continuous shunt and bus
+ * calibration value is INA219_CALIBRATION_VALUE
+ */
+ int val = data->regs[reg];
+
+ switch (reg) {
+ case INA2XX_SHUNT_VOLTAGE:
+ /* LSB=10uV. Convert to mV. */
+ val = DIV_ROUND_CLOSEST(val, 100);
+ break;
+ case INA2XX_BUS_VOLTAGE:
+ /* LSB=4mV. Register is not right aligned, convert to mV. */
+ val = (val >> 3) * 4;
+ break;
+ case INA2XX_POWER:
+ /* LSB=20mW. Convert to uW */
+ val = val * 20 * 1000;
+ break;
+ case INA2XX_CURRENT:
+ /* LSB=1mA (selected). Is in mA */
+ break;
+ default:
+ /* programmer goofed */
+ WARN_ON_ONCE(1);
+ val = 0;
+ break;
+ }
+
+ return val;
+}
+
+static int ina226_get_value(struct ina2xx_data *data, u8 reg)
+{
+ /*
+ * calculate exact value for the given register
+ * we assume default power-on reset settings:
+ * bus voltage range 32V
+ * gain = /8
+ * adc 1 & 2 -> conversion time 532uS
+ * mode is continuous shunt and bus
+ * calibration value is INA226_CALIBRATION_VALUE
+ */
+ int val = data->regs[reg];
+
+ switch (reg) {
+ case INA2XX_SHUNT_VOLTAGE:
+ /* LSB=2.5uV. Convert to mV. */
+ val = DIV_ROUND_CLOSEST(val, 400);
+ break;
+ case INA2XX_BUS_VOLTAGE:
+ /* LSB=1.25mV. Convert to mV. */
+ val = val + DIV_ROUND_CLOSEST(val, 4);
+ break;
+ case INA2XX_POWER:
+ /* LSB=25mW. Convert to uW */
+ val = val * 25 * 1000;
+ break;
+ case INA2XX_CURRENT:
+ /* LSB=1mA (selected). Is in mA */
+ break;
+ default:
+ /* programmer goofed */
+ WARN_ON_ONCE(1);
+ val = 0;
+ break;
+ }
+
+ return val;
+}
+
+static ssize_t ina2xx_show_value(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct ina2xx_data *data = ina2xx_update_device(dev);
+ int value = 0;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ switch (data->kind) {
+ case ina219:
+ value = ina219_get_value(data, attr->index);
+ break;
+ case ina226:
+ value = ina226_get_value(data, attr->index);
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ break;
+ }
+ return snprintf(buf, PAGE_SIZE, "%d\n", value);
+}
+
+/* shunt voltage */
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, \
+ ina2xx_show_value, NULL, INA2XX_SHUNT_VOLTAGE);
+
+/* bus voltage */
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, \
+ ina2xx_show_value, NULL, INA2XX_BUS_VOLTAGE);
+
+/* calculated current */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, \
+ ina2xx_show_value, NULL, INA2XX_CURRENT);
+
+/* calculated power */
+static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, \
+ ina2xx_show_value, NULL, INA2XX_POWER);
+
+/* pointers to created device attributes */
+static struct attribute *ina2xx_attributes[] = {
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_curr1_input.dev_attr.attr,
+ &sensor_dev_attr_power1_input.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ina2xx_group = {
+ .attrs = ina2xx_attributes,
+};
+
+static int ina2xx_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct ina2xx_data *data;
+ struct ina2xx_platform_data *pdata;
+ int ret = 0;
+ long shunt = 10000; /* default shunt value 10mOhms */
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
+ return -ENODEV;
+
+ data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ if (client->dev.platform_data) {
+ pdata =
+ (struct ina2xx_platform_data *)client->dev.platform_data;
+ shunt = pdata->shunt_uohms;
+ }
+
+ if (shunt <= 0)
+ return -ENODEV;
+
+ /* set the device type */
+ data->kind = id->driver_data;
+
+ switch (data->kind) {
+ case ina219:
+ /* device configuration */
+ ina2xx_write_word(client, INA2XX_CONFIG, INA219_CONFIG_DEFAULT);
+
+ /* set current LSB to 1mA, shunt is in uOhms */
+ /* (equation 13 in datasheet) */
+ ina2xx_write_word(client, INA2XX_CALIBRATION, 40960000 / shunt);
+ dev_info(&client->dev,
+ "power monitor INA219 (Rshunt = %li uOhm)\n", shunt);
+ data->registers = INA219_REGISTERS;
+ break;
+ case ina226:
+ /* device configuration */
+ ina2xx_write_word(client, INA2XX_CONFIG, INA226_CONFIG_DEFAULT);
+
+ /* set current LSB to 1mA, shunt is in uOhms */
+ /* (equation 1 in datasheet)*/
+ ina2xx_write_word(client, INA2XX_CALIBRATION, 5120000 / shunt);
+ dev_info(&client->dev,
+ "power monitor INA226 (Rshunt = %li uOhm)\n", shunt);
+ data->registers = INA226_REGISTERS;
+ break;
+ default:
+ /* unknown device id */
+ return -ENODEV;
+ }
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+
+ ret = sysfs_create_group(&client->dev.kobj, &ina2xx_group);
+ if (ret)
+ return ret;
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ ret = PTR_ERR(data->hwmon_dev);
+ goto out_err_hwmon;
+ }
+
+ return 0;
+
+out_err_hwmon:
+ sysfs_remove_group(&client->dev.kobj, &ina2xx_group);
+ return ret;
+}
+
+static int ina2xx_remove(struct i2c_client *client)
+{
+ struct ina2xx_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &ina2xx_group);
+
+ return 0;
+}
+
+static const struct i2c_device_id ina2xx_id[] = {
+ { "ina219", ina219 },
+ { "ina226", ina226 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ina2xx_id);
+
+static struct i2c_driver ina2xx_driver = {
+ .driver = {
+ .name = "ina2xx",
+ },
+ .probe = ina2xx_probe,
+ .remove = ina2xx_remove,
+ .id_table = ina2xx_id,
+};
+
+static int __init ina2xx_init(void)
+{
+ return i2c_add_driver(&ina2xx_driver);
+}
+
+static void __exit ina2xx_exit(void)
+{
+ i2c_del_driver(&ina2xx_driver);
+}
+
+MODULE_AUTHOR("Lothar Felten <l-felten@ti.com>");
+MODULE_DESCRIPTION("ina2xx driver");
+MODULE_LICENSE("GPL");
+
+module_init(ina2xx_init);
+module_exit(ina2xx_exit);
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 0b204e4cf51c..e7701d99f8e8 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -19,6 +19,8 @@
* IT8726F Super I/O chip w/LPC interface
* IT8728F Super I/O chip w/LPC interface
* IT8758E Super I/O chip w/LPC interface
+ * IT8782F Super I/O chip w/LPC interface
+ * IT8783E/F Super I/O chip w/LPC interface
* Sis950 A clone of the IT8705F
*
* Copyright (C) 2001 Chris Gauthron
@@ -59,7 +61,8 @@
#define DRVNAME "it87"
-enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728 };
+enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8782,
+ it8783 };
static unsigned short force_id;
module_param(force_id, ushort, 0);
@@ -137,13 +140,18 @@ static inline void superio_exit(void)
#define IT8721F_DEVID 0x8721
#define IT8726F_DEVID 0x8726
#define IT8728F_DEVID 0x8728
+#define IT8782F_DEVID 0x8782
+#define IT8783E_DEVID 0x8783
#define IT87_ACT_REG 0x30
#define IT87_BASE_REG 0x60
/* Logical device 7 registers (IT8712F and later) */
+#define IT87_SIO_GPIO1_REG 0x25
#define IT87_SIO_GPIO3_REG 0x27
#define IT87_SIO_GPIO5_REG 0x29
+#define IT87_SIO_PINX1_REG 0x2a /* Pin selection */
#define IT87_SIO_PINX2_REG 0x2c /* Pin selection */
+#define IT87_SIO_SPI_REG 0xef /* SPI function pin select */
#define IT87_SIO_VID_REG 0xfc /* VID value */
#define IT87_SIO_BEEP_PIN_REG 0xf6 /* Beep pin mapping */
@@ -210,6 +218,7 @@ static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87 };
#define IT87_REG_VIN_ENABLE 0x50
#define IT87_REG_TEMP_ENABLE 0x51
+#define IT87_REG_TEMP_EXTRA 0x55
#define IT87_REG_BEEP_ENABLE 0x5c
#define IT87_REG_CHIPID 0x58
@@ -226,9 +235,11 @@ struct it87_sio_data {
u8 beep_pin;
u8 internal; /* Internal sensors can be labeled */
/* Features skipped based on config or DMI */
+ u16 skip_in;
u8 skip_vid;
u8 skip_fan;
u8 skip_pwm;
+ u8 skip_temp;
};
/*
@@ -253,6 +264,7 @@ struct it87_data {
u8 has_fan; /* Bitfield, fans enabled */
u16 fan[5]; /* Register values, possibly combined */
u16 fan_min[5]; /* Register values, possibly combined */
+ u8 has_temp; /* Bitfield, temp sensors enabled */
s8 temp[3]; /* Register value */
s8 temp_high[3]; /* Register value */
s8 temp_low[3]; /* Register value */
@@ -304,31 +316,23 @@ static inline int has_newer_autopwm(const struct it87_data *data)
|| data->type == it8728;
}
-static u8 in_to_reg(const struct it87_data *data, int nr, long val)
+static int adc_lsb(const struct it87_data *data, int nr)
{
- long lsb;
-
- if (has_12mv_adc(data)) {
- if (data->in_scaled & (1 << nr))
- lsb = 24;
- else
- lsb = 12;
- } else
- lsb = 16;
+ int lsb = has_12mv_adc(data) ? 12 : 16;
+ if (data->in_scaled & (1 << nr))
+ lsb <<= 1;
+ return lsb;
+}
- val = DIV_ROUND_CLOSEST(val, lsb);
+static u8 in_to_reg(const struct it87_data *data, int nr, long val)
+{
+ val = DIV_ROUND_CLOSEST(val, adc_lsb(data, nr));
return SENSORS_LIMIT(val, 0, 255);
}
static int in_from_reg(const struct it87_data *data, int nr, int val)
{
- if (has_12mv_adc(data)) {
- if (data->in_scaled & (1 << nr))
- return val * 24;
- else
- return val * 12;
- } else
- return val * 16;
+ return val * adc_lsb(data, nr);
}
static inline u8 FAN_TO_REG(long rpm, int div)
@@ -407,7 +411,9 @@ static inline int has_16bit_fans(const struct it87_data *data)
|| data->type == it8718
|| data->type == it8720
|| data->type == it8721
- || data->type == it8728;
+ || data->type == it8728
+ || data->type == it8782
+ || data->type == it8783;
}
static inline int has_old_autopwm(const struct it87_data *data)
@@ -1369,57 +1375,103 @@ static ssize_t show_name(struct device *dev, struct device_attribute
}
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
-static struct attribute *it87_attributes[] = {
+static struct attribute *it87_attributes_in[9][5] = {
+{
&sensor_dev_attr_in0_input.dev_attr.attr,
- &sensor_dev_attr_in1_input.dev_attr.attr,
- &sensor_dev_attr_in2_input.dev_attr.attr,
- &sensor_dev_attr_in3_input.dev_attr.attr,
- &sensor_dev_attr_in4_input.dev_attr.attr,
- &sensor_dev_attr_in5_input.dev_attr.attr,
- &sensor_dev_attr_in6_input.dev_attr.attr,
- &sensor_dev_attr_in7_input.dev_attr.attr,
- &sensor_dev_attr_in8_input.dev_attr.attr,
&sensor_dev_attr_in0_min.dev_attr.attr,
- &sensor_dev_attr_in1_min.dev_attr.attr,
- &sensor_dev_attr_in2_min.dev_attr.attr,
- &sensor_dev_attr_in3_min.dev_attr.attr,
- &sensor_dev_attr_in4_min.dev_attr.attr,
- &sensor_dev_attr_in5_min.dev_attr.attr,
- &sensor_dev_attr_in6_min.dev_attr.attr,
- &sensor_dev_attr_in7_min.dev_attr.attr,
&sensor_dev_attr_in0_max.dev_attr.attr,
- &sensor_dev_attr_in1_max.dev_attr.attr,
- &sensor_dev_attr_in2_max.dev_attr.attr,
- &sensor_dev_attr_in3_max.dev_attr.attr,
- &sensor_dev_attr_in4_max.dev_attr.attr,
- &sensor_dev_attr_in5_max.dev_attr.attr,
- &sensor_dev_attr_in6_max.dev_attr.attr,
- &sensor_dev_attr_in7_max.dev_attr.attr,
&sensor_dev_attr_in0_alarm.dev_attr.attr,
+ NULL
+}, {
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
&sensor_dev_attr_in1_alarm.dev_attr.attr,
+ NULL
+}, {
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
&sensor_dev_attr_in2_alarm.dev_attr.attr,
+ NULL
+}, {
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
&sensor_dev_attr_in3_alarm.dev_attr.attr,
+ NULL
+}, {
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
&sensor_dev_attr_in4_alarm.dev_attr.attr,
+ NULL
+}, {
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
&sensor_dev_attr_in5_alarm.dev_attr.attr,
+ NULL
+}, {
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
&sensor_dev_attr_in6_alarm.dev_attr.attr,
+ NULL
+}, {
+ &sensor_dev_attr_in7_input.dev_attr.attr,
+ &sensor_dev_attr_in7_min.dev_attr.attr,
+ &sensor_dev_attr_in7_max.dev_attr.attr,
&sensor_dev_attr_in7_alarm.dev_attr.attr,
+ NULL
+}, {
+ &sensor_dev_attr_in8_input.dev_attr.attr,
+ NULL
+} };
+static const struct attribute_group it87_group_in[9] = {
+ { .attrs = it87_attributes_in[0] },
+ { .attrs = it87_attributes_in[1] },
+ { .attrs = it87_attributes_in[2] },
+ { .attrs = it87_attributes_in[3] },
+ { .attrs = it87_attributes_in[4] },
+ { .attrs = it87_attributes_in[5] },
+ { .attrs = it87_attributes_in[6] },
+ { .attrs = it87_attributes_in[7] },
+ { .attrs = it87_attributes_in[8] },
+};
+
+static struct attribute *it87_attributes_temp[3][6] = {
+{
&sensor_dev_attr_temp1_input.dev_attr.attr,
- &sensor_dev_attr_temp2_input.dev_attr.attr,
- &sensor_dev_attr_temp3_input.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
- &sensor_dev_attr_temp2_max.dev_attr.attr,
- &sensor_dev_attr_temp3_max.dev_attr.attr,
&sensor_dev_attr_temp1_min.dev_attr.attr,
- &sensor_dev_attr_temp2_min.dev_attr.attr,
- &sensor_dev_attr_temp3_min.dev_attr.attr,
&sensor_dev_attr_temp1_type.dev_attr.attr,
- &sensor_dev_attr_temp2_type.dev_attr.attr,
- &sensor_dev_attr_temp3_type.dev_attr.attr,
&sensor_dev_attr_temp1_alarm.dev_attr.attr,
+ NULL
+} , {
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_type.dev_attr.attr,
&sensor_dev_attr_temp2_alarm.dev_attr.attr,
+ NULL
+} , {
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_type.dev_attr.attr,
&sensor_dev_attr_temp3_alarm.dev_attr.attr,
+ NULL
+} };
+
+static const struct attribute_group it87_group_temp[3] = {
+ { .attrs = it87_attributes_temp[0] },
+ { .attrs = it87_attributes_temp[1] },
+ { .attrs = it87_attributes_temp[2] },
+};
+static struct attribute *it87_attributes[] = {
&dev_attr_alarms.attr,
&sensor_dev_attr_intrusion0_alarm.dev_attr.attr,
&dev_attr_name.attr,
@@ -1430,7 +1482,7 @@ static const struct attribute_group it87_group = {
.attrs = it87_attributes,
};
-static struct attribute *it87_attributes_beep[] = {
+static struct attribute *it87_attributes_in_beep[] = {
&sensor_dev_attr_in0_beep.dev_attr.attr,
&sensor_dev_attr_in1_beep.dev_attr.attr,
&sensor_dev_attr_in2_beep.dev_attr.attr,
@@ -1439,15 +1491,13 @@ static struct attribute *it87_attributes_beep[] = {
&sensor_dev_attr_in5_beep.dev_attr.attr,
&sensor_dev_attr_in6_beep.dev_attr.attr,
&sensor_dev_attr_in7_beep.dev_attr.attr,
+ NULL
+};
+static struct attribute *it87_attributes_temp_beep[] = {
&sensor_dev_attr_temp1_beep.dev_attr.attr,
&sensor_dev_attr_temp2_beep.dev_attr.attr,
&sensor_dev_attr_temp3_beep.dev_attr.attr,
- NULL
-};
-
-static const struct attribute_group it87_group_beep = {
- .attrs = it87_attributes_beep,
};
static struct attribute *it87_attributes_fan16[5][3+1] = { {
@@ -1651,6 +1701,12 @@ static int __init it87_find(unsigned short *address,
case IT8728F_DEVID:
sio_data->type = it8728;
break;
+ case IT8782F_DEVID:
+ sio_data->type = it8782;
+ break;
+ case IT8783E_DEVID:
+ sio_data->type = it8783;
+ break;
case 0xffff: /* No device at all */
goto exit;
default:
@@ -1686,16 +1742,86 @@ static int __init it87_find(unsigned short *address,
/* The IT8705F has a different LD number for GPIO */
superio_select(5);
sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
+ } else if (sio_data->type == it8783) {
+ int reg25, reg27, reg2A, reg2C, regEF;
+
+ sio_data->skip_vid = 1; /* No VID */
+
+ superio_select(GPIO);
+
+ reg25 = superio_inb(IT87_SIO_GPIO1_REG);
+ reg27 = superio_inb(IT87_SIO_GPIO3_REG);
+ reg2A = superio_inb(IT87_SIO_PINX1_REG);
+ reg2C = superio_inb(IT87_SIO_PINX2_REG);
+ regEF = superio_inb(IT87_SIO_SPI_REG);
+
+ /* Check if fan3 is there or not */
+ if ((reg27 & (1 << 0)) || !(reg2C & (1 << 2)))
+ sio_data->skip_fan |= (1 << 2);
+ if ((reg25 & (1 << 4))
+ || (!(reg2A & (1 << 1)) && (regEF & (1 << 0))))
+ sio_data->skip_pwm |= (1 << 2);
+
+ /* Check if fan2 is there or not */
+ if (reg27 & (1 << 7))
+ sio_data->skip_fan |= (1 << 1);
+ if (reg27 & (1 << 3))
+ sio_data->skip_pwm |= (1 << 1);
+
+ /* VIN5 */
+ if ((reg27 & (1 << 0)) || (reg2C & (1 << 2)))
+ sio_data->skip_in |= (1 << 5); /* No VIN5 */
+
+ /* VIN6 */
+ if (reg27 & (1 << 1))
+ sio_data->skip_in |= (1 << 6); /* No VIN6 */
+
+ /*
+ * VIN7
+ * Does not depend on bit 2 of Reg2C, contrary to datasheet.
+ */
+ if (reg27 & (1 << 2)) {
+ /*
+ * The data sheet is a bit unclear regarding the
+ * internal voltage divider for VCCH5V. It says
+ * "This bit enables and switches VIN7 (pin 91) to the
+ * internal voltage divider for VCCH5V".
+ * This is different to other chips, where the internal
+ * voltage divider would connect VIN7 to an internal
+ * voltage source. Maybe that is the case here as well.
+ *
+ * Since we don't know for sure, re-route it if that is
+ * not the case, and ask the user to report if the
+ * resulting voltage is sane.
+ */
+ if (!(reg2C & (1 << 1))) {
+ reg2C |= (1 << 1);
+ superio_outb(IT87_SIO_PINX2_REG, reg2C);
+ pr_notice("Routing internal VCCH5V to in7.\n");
+ }
+ pr_notice("in7 routed to internal voltage divider, with external pin disabled.\n");
+ pr_notice("Please report if it displays a reasonable voltage.\n");
+ }
+
+ if (reg2C & (1 << 0))
+ sio_data->internal |= (1 << 0);
+ if (reg2C & (1 << 1))
+ sio_data->internal |= (1 << 1);
+
+ sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
+
} else {
int reg;
+ bool uart6;
superio_select(GPIO);
reg = superio_inb(IT87_SIO_GPIO3_REG);
- if (sio_data->type == it8721 || sio_data->type == it8728) {
+ if (sio_data->type == it8721 || sio_data->type == it8728 ||
+ sio_data->type == it8782) {
/*
- * The IT8721F/IT8758E doesn't have VID pins at all,
- * not sure about the IT8728F.
+ * IT8721F/IT8758E, and IT8782F don't have VID pins
+ * at all, not sure about the IT8728F.
*/
sio_data->skip_vid = 1;
} else {
@@ -1724,6 +1850,9 @@ static int __init it87_find(unsigned short *address,
sio_data->vid_value = superio_inb(IT87_SIO_VID_REG);
reg = superio_inb(IT87_SIO_PINX2_REG);
+
+ uart6 = sio_data->type == it8782 && (reg & (1 << 2));
+
/*
* The IT8720F has no VIN7 pin, so VCCH should always be
* routed internally to VIN7 with an internal divider.
@@ -1733,8 +1862,12 @@ static int __init it87_find(unsigned short *address,
* configured, even though the IT8720F datasheet claims
* that the internal routing of VCCH to VIN7 is the default
* setting. So we force the internal routing in this case.
+ *
+ * On IT8782F, VIN7 is multiplexed with one of the UART6 pins.
+ * If UART6 is enabled, re-route VIN7 to the internal divider
+ * if that is not already the case.
*/
- if (sio_data->type == it8720 && !(reg & (1 << 1))) {
+ if ((sio_data->type == it8720 || uart6) && !(reg & (1 << 1))) {
reg |= (1 << 1);
superio_outb(IT87_SIO_PINX2_REG, reg);
pr_notice("Routing internal VCCH to in7\n");
@@ -1745,6 +1878,20 @@ static int __init it87_find(unsigned short *address,
sio_data->type == it8728)
sio_data->internal |= (1 << 1);
+ /*
+ * On IT8782F, UART6 pins overlap with VIN5, VIN6, and VIN7.
+ * While VIN7 can be routed to the internal voltage divider,
+ * VIN5 and VIN6 are not available if UART6 is enabled.
+ *
+ * Also, temp3 is not available if UART6 is enabled and TEMPIN3
+ * is the temperature source. Since we can not read the
+ * temperature source here, skip_temp is preliminary.
+ */
+ if (uart6) {
+ sio_data->skip_in |= (1 << 5) | (1 << 6);
+ sio_data->skip_temp |= (1 << 2);
+ }
+
sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
}
if (sio_data->beep_pin)
@@ -1782,8 +1929,22 @@ static void it87_remove_files(struct device *dev)
int i;
sysfs_remove_group(&dev->kobj, &it87_group);
- if (sio_data->beep_pin)
- sysfs_remove_group(&dev->kobj, &it87_group_beep);
+ for (i = 0; i < 9; i++) {
+ if (sio_data->skip_in & (1 << i))
+ continue;
+ sysfs_remove_group(&dev->kobj, &it87_group_in[i]);
+ if (it87_attributes_in_beep[i])
+ sysfs_remove_file(&dev->kobj,
+ it87_attributes_in_beep[i]);
+ }
+ for (i = 0; i < 3; i++) {
+ if (!(data->has_temp & (1 << i)))
+ continue;
+ sysfs_remove_group(&dev->kobj, &it87_group_temp[i]);
+ if (sio_data->beep_pin)
+ sysfs_remove_file(&dev->kobj,
+ it87_attributes_temp_beep[i]);
+ }
for (i = 0; i < 5; i++) {
if (!(data->has_fan & (1 << i)))
continue;
@@ -1823,22 +1984,22 @@ static int __devinit it87_probe(struct platform_device *pdev)
"it8720",
"it8721",
"it8728",
+ "it8782",
+ "it8783",
};
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- if (!request_region(res->start, IT87_EC_EXTENT, DRVNAME)) {
+ if (!devm_request_region(&pdev->dev, res->start, IT87_EC_EXTENT,
+ DRVNAME)) {
dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
(unsigned long)res->start,
(unsigned long)(res->start + IT87_EC_EXTENT - 1));
- err = -EBUSY;
- goto ERROR0;
+ return -EBUSY;
}
- data = kzalloc(sizeof(struct it87_data), GFP_KERNEL);
- if (!data) {
- err = -ENOMEM;
- goto ERROR1;
- }
+ data = devm_kzalloc(&pdev->dev, sizeof(struct it87_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
data->addr = res->start;
data->type = sio_data->type;
@@ -1847,10 +2008,8 @@ static int __devinit it87_probe(struct platform_device *pdev)
/* Now, we do the remaining detection. */
if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80)
- || it87_read_value(data, IT87_REG_CHIPID) != 0x90) {
- err = -ENODEV;
- goto ERROR2;
- }
+ || it87_read_value(data, IT87_REG_CHIPID) != 0x90)
+ return -ENODEV;
platform_set_drvdata(pdev, data);
@@ -1867,6 +2026,18 @@ static int __devinit it87_probe(struct platform_device *pdev)
data->in_scaled |= (1 << 7); /* in7 is VSB */
if (sio_data->internal & (1 << 2))
data->in_scaled |= (1 << 8); /* in8 is Vbat */
+ } else if (sio_data->type == it8782 || sio_data->type == it8783) {
+ if (sio_data->internal & (1 << 0))
+ data->in_scaled |= (1 << 3); /* in3 is VCC5V */
+ if (sio_data->internal & (1 << 1))
+ data->in_scaled |= (1 << 7); /* in7 is VCCH5V */
+ }
+
+ data->has_temp = 0x07;
+ if (sio_data->skip_temp & (1 << 2)) {
+ if (sio_data->type == it8782
+ && !(it87_read_value(data, IT87_REG_TEMP_EXTRA) & 0x80))
+ data->has_temp &= ~(1 << 2);
}
/* Initialize the IT87 chip */
@@ -1875,12 +2046,34 @@ static int __devinit it87_probe(struct platform_device *pdev)
/* Register sysfs hooks */
err = sysfs_create_group(&dev->kobj, &it87_group);
if (err)
- goto ERROR2;
+ return err;
- if (sio_data->beep_pin) {
- err = sysfs_create_group(&dev->kobj, &it87_group_beep);
+ for (i = 0; i < 9; i++) {
+ if (sio_data->skip_in & (1 << i))
+ continue;
+ err = sysfs_create_group(&dev->kobj, &it87_group_in[i]);
if (err)
- goto ERROR4;
+ goto error;
+ if (sio_data->beep_pin && it87_attributes_in_beep[i]) {
+ err = sysfs_create_file(&dev->kobj,
+ it87_attributes_in_beep[i]);
+ if (err)
+ goto error;
+ }
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (!(data->has_temp & (1 << i)))
+ continue;
+ err = sysfs_create_group(&dev->kobj, &it87_group_temp[i]);
+ if (err)
+ goto error;
+ if (sio_data->beep_pin) {
+ err = sysfs_create_file(&dev->kobj,
+ it87_attributes_temp_beep[i]);
+ if (err)
+ goto error;
+ }
}
/* Do not create fan files for disabled fans */
@@ -1891,13 +2084,13 @@ static int __devinit it87_probe(struct platform_device *pdev)
continue;
err = sysfs_create_group(&dev->kobj, &fan_group[i]);
if (err)
- goto ERROR4;
+ goto error;
if (sio_data->beep_pin) {
err = sysfs_create_file(&dev->kobj,
it87_attributes_fan_beep[i]);
if (err)
- goto ERROR4;
+ goto error;
if (!fan_beep_need_rw)
continue;
@@ -1922,14 +2115,14 @@ static int __devinit it87_probe(struct platform_device *pdev)
err = sysfs_create_group(&dev->kobj,
&it87_group_pwm[i]);
if (err)
- goto ERROR4;
+ goto error;
if (!has_old_autopwm(data))
continue;
err = sysfs_create_group(&dev->kobj,
&it87_group_autopwm[i]);
if (err)
- goto ERROR4;
+ goto error;
}
}
@@ -1939,7 +2132,7 @@ static int __devinit it87_probe(struct platform_device *pdev)
data->vid = sio_data->vid_value;
err = sysfs_create_group(&dev->kobj, &it87_group_vid);
if (err)
- goto ERROR4;
+ goto error;
}
/* Export labels for internal sensors */
@@ -1949,25 +2142,19 @@ static int __devinit it87_probe(struct platform_device *pdev)
err = sysfs_create_file(&dev->kobj,
it87_attributes_label[i]);
if (err)
- goto ERROR4;
+ goto error;
}
data->hwmon_dev = hwmon_device_register(dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
- goto ERROR4;
+ goto error;
}
return 0;
-ERROR4:
+error:
it87_remove_files(dev);
-ERROR2:
- platform_set_drvdata(pdev, NULL);
- kfree(data);
-ERROR1:
- release_region(res->start, IT87_EC_EXTENT);
-ERROR0:
return err;
}
@@ -1978,10 +2165,6 @@ static int __devexit it87_remove(struct platform_device *pdev)
hwmon_device_unregister(data->hwmon_dev);
it87_remove_files(&pdev->dev);
- release_region(data->addr, IT87_EC_EXTENT);
- platform_set_drvdata(pdev, NULL);
- kfree(data);
-
return 0;
}
@@ -2143,8 +2326,9 @@ static void __devinit it87_init_device(struct platform_device *pdev)
it87_write_value(data, IT87_REG_FAN_16BIT,
tmp | 0x07);
}
- /* IT8705F only supports three fans. */
- if (data->type != it87) {
+ /* IT8705F, IT8782F, and IT8783E/F only support three fans. */
+ if (data->type != it87 && data->type != it8782 &&
+ data->type != it8783) {
if (tmp & (1 << 4))
data->has_fan |= (1 << 3); /* fan4 enabled */
if (tmp & (1 << 5))
@@ -2233,6 +2417,8 @@ static struct it87_data *it87_update_device(struct device *dev)
}
}
for (i = 0; i < 3; i++) {
+ if (!(data->has_temp & (1 << i)))
+ continue;
data->temp[i] =
it87_read_value(data, IT87_REG_TEMP(i));
data->temp_high[i] =
diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
index 307bb325dde9..7356b5ec8f67 100644
--- a/drivers/hwmon/k10temp.c
+++ b/drivers/hwmon/k10temp.c
@@ -225,15 +225,4 @@ static struct pci_driver k10temp_driver = {
.remove = __devexit_p(k10temp_remove),
};
-static int __init k10temp_init(void)
-{
- return pci_register_driver(&k10temp_driver);
-}
-
-static void __exit k10temp_exit(void)
-{
- pci_unregister_driver(&k10temp_driver);
-}
-
-module_init(k10temp_init)
-module_exit(k10temp_exit)
+module_pci_driver(k10temp_driver);
diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c
index 575101988751..35aac82ee8eb 100644
--- a/drivers/hwmon/k8temp.c
+++ b/drivers/hwmon/k8temp.c
@@ -339,19 +339,8 @@ static struct pci_driver k8temp_driver = {
.remove = __devexit_p(k8temp_remove),
};
-static int __init k8temp_init(void)
-{
- return pci_register_driver(&k8temp_driver);
-}
-
-static void __exit k8temp_exit(void)
-{
- pci_unregister_driver(&k8temp_driver);
-}
+module_pci_driver(k8temp_driver);
MODULE_AUTHOR("Rudolf Marek <r.marek@assembler.cz>");
MODULE_DESCRIPTION("AMD K8 core temperature monitor");
MODULE_LICENSE("GPL");
-
-module_init(k8temp_init)
-module_exit(k8temp_exit)
diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
index 9b382ec2c3bd..6da9696e1827 100644
--- a/drivers/hwmon/ntc_thermistor.c
+++ b/drivers/hwmon/ntc_thermistor.c
@@ -134,8 +134,7 @@ static inline u64 div64_u64_safe(u64 dividend, u64 divisor)
return div64_u64(dividend, divisor);
}
-static unsigned int get_ohm_of_thermistor(struct ntc_data *data,
- unsigned int uV)
+static int get_ohm_of_thermistor(struct ntc_data *data, unsigned int uV)
{
struct ntc_thermistor_platform_data *pdata = data->pdata;
u64 mV = uV / 1000;
@@ -146,12 +145,12 @@ static unsigned int get_ohm_of_thermistor(struct ntc_data *data,
if (mV == 0) {
if (pdata->connect == NTC_CONNECTED_POSITIVE)
- return UINT_MAX;
+ return INT_MAX;
return 0;
}
if (mV >= pmV)
return (pdata->connect == NTC_CONNECTED_POSITIVE) ?
- 0 : UINT_MAX;
+ 0 : INT_MAX;
if (pdata->connect == NTC_CONNECTED_POSITIVE && puO == 0)
N = div64_u64_safe(pdO * (pmV - mV), mV);
@@ -163,113 +162,109 @@ static unsigned int get_ohm_of_thermistor(struct ntc_data *data,
else
N = div64_u64_safe(pdO * puO * mV, pdO * (pmV - mV) - puO * mV);
- return (unsigned int) N;
+ if (N > INT_MAX)
+ N = INT_MAX;
+ return N;
}
-static int lookup_comp(struct ntc_data *data,
- unsigned int ohm, int *i_low, int *i_high)
+static void lookup_comp(struct ntc_data *data, unsigned int ohm,
+ int *i_low, int *i_high)
{
- int start, end, mid = -1;
+ int start, end, mid;
+
+ /*
+ * Handle special cases: Resistance is higher than or equal to
+ * resistance in first table entry, or resistance is lower or equal
+ * to resistance in last table entry.
+ * In these cases, return i_low == i_high, either pointing to the
+ * beginning or to the end of the table depending on the condition.
+ */
+ if (ohm >= data->comp[0].ohm) {
+ *i_low = 0;
+ *i_high = 0;
+ return;
+ }
+ if (ohm <= data->comp[data->n_comp - 1].ohm) {
+ *i_low = data->n_comp - 1;
+ *i_high = data->n_comp - 1;
+ return;
+ }
/* Do a binary search on compensation table */
start = 0;
end = data->n_comp;
-
- while (end > start) {
+ while (start < end) {
mid = start + (end - start) / 2;
- if (data->comp[mid].ohm < ohm)
+ /*
+ * start <= mid < end
+ * data->comp[start].ohm > ohm >= data->comp[end].ohm
+ *
+ * We could check for "ohm == data->comp[mid].ohm" here, but
+ * that is a quite unlikely condition, and we would have to
+ * check again after updating start. Check it at the end instead
+ * for simplicity.
+ */
+ if (ohm >= data->comp[mid].ohm) {
end = mid;
- else if (data->comp[mid].ohm > ohm)
- start = mid + 1;
- else
- break;
- }
-
- if (mid == 0) {
- if (data->comp[mid].ohm > ohm) {
- *i_high = mid;
- *i_low = mid + 1;
- return 0;
- } else {
- *i_low = mid;
- *i_high = -1;
- return -EINVAL;
- }
- }
- if (mid == (data->n_comp - 1)) {
- if (data->comp[mid].ohm <= ohm) {
- *i_low = mid;
- *i_high = mid - 1;
- return 0;
} else {
- *i_low = -1;
- *i_high = mid;
- return -EINVAL;
+ start = mid + 1;
+ /*
+ * ohm >= data->comp[start].ohm might be true here,
+ * since we set start to mid + 1. In that case, we are
+ * done. We could keep going, but the condition is quite
+ * likely to occur, so it is worth checking for it.
+ */
+ if (ohm >= data->comp[start].ohm)
+ end = start;
}
+ /*
+ * start <= end
+ * data->comp[start].ohm >= ohm >= data->comp[end].ohm
+ */
}
-
- if (data->comp[mid].ohm <= ohm) {
- *i_low = mid;
- *i_high = mid - 1;
- } else {
- *i_low = mid + 1;
- *i_high = mid;
- }
-
- return 0;
+ /*
+ * start == end
+ * ohm >= data->comp[end].ohm
+ */
+ *i_low = end;
+ if (ohm == data->comp[end].ohm)
+ *i_high = end;
+ else
+ *i_high = end - 1;
}
-static int get_temp_mC(struct ntc_data *data, unsigned int ohm, int *temp)
+static int get_temp_mC(struct ntc_data *data, unsigned int ohm)
{
int low, high;
- int ret;
+ int temp;
- ret = lookup_comp(data, ohm, &low, &high);
- if (ret) {
+ lookup_comp(data, ohm, &low, &high);
+ if (low == high) {
/* Unable to use linear approximation */
- if (low != -1)
- *temp = data->comp[low].temp_C * 1000;
- else if (high != -1)
- *temp = data->comp[high].temp_C * 1000;
- else
- return ret;
+ temp = data->comp[low].temp_C * 1000;
} else {
- *temp = data->comp[low].temp_C * 1000 +
+ temp = data->comp[low].temp_C * 1000 +
((data->comp[high].temp_C - data->comp[low].temp_C) *
1000 * ((int)ohm - (int)data->comp[low].ohm)) /
((int)data->comp[high].ohm - (int)data->comp[low].ohm);
}
-
- return 0;
+ return temp;
}
-static int ntc_thermistor_read(struct ntc_data *data, int *temp)
+static int ntc_thermistor_get_ohm(struct ntc_data *data)
{
- int ret;
- int read_ohm, read_uV;
- unsigned int ohm = 0;
-
- if (data->pdata->read_ohm) {
- read_ohm = data->pdata->read_ohm();
- if (read_ohm < 0)
- return read_ohm;
- ohm = (unsigned int)read_ohm;
- }
+ int read_uV;
+
+ if (data->pdata->read_ohm)
+ return data->pdata->read_ohm();
if (data->pdata->read_uV) {
read_uV = data->pdata->read_uV();
if (read_uV < 0)
return read_uV;
- ohm = get_ohm_of_thermistor(data, (unsigned int)read_uV);
- }
-
- ret = get_temp_mC(data, ohm, temp);
- if (ret) {
- dev_dbg(data->dev, "Sensor reading function not available.\n");
- return ret;
+ return get_ohm_of_thermistor(data, read_uV);
}
-
- return 0;
+ return -EINVAL;
}
static ssize_t ntc_show_name(struct device *dev,
@@ -290,12 +285,13 @@ static ssize_t ntc_show_temp(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ntc_data *data = dev_get_drvdata(dev);
- int temp, ret;
+ int ohm;
- ret = ntc_thermistor_read(data, &temp);
- if (ret)
- return ret;
- return sprintf(buf, "%d\n", temp);
+ ohm = ntc_thermistor_get_ohm(data);
+ if (ohm < 0)
+ return ohm;
+
+ return sprintf(buf, "%d\n", get_temp_mC(data, ohm));
}
static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, ntc_show_type, NULL, 0);
@@ -326,14 +322,14 @@ static int __devinit ntc_thermistor_probe(struct platform_device *pdev)
/* Either one of the two is required. */
if (!pdata->read_uV && !pdata->read_ohm) {
- dev_err(&pdev->dev, "Both read_uV and read_ohm missing."
- "Need either one of the two.\n");
+ dev_err(&pdev->dev,
+ "Both read_uV and read_ohm missing. Need either one of the two.\n");
return -EINVAL;
}
if (pdata->read_uV && pdata->read_ohm) {
- dev_warn(&pdev->dev, "Only one of read_uV and read_ohm "
- "is needed; ignoring read_uV.\n");
+ dev_warn(&pdev->dev,
+ "Only one of read_uV and read_ohm is needed; ignoring read_uV.\n");
pdata->read_uV = NULL;
}
@@ -344,12 +340,12 @@ static int __devinit ntc_thermistor_probe(struct platform_device *pdev)
NTC_CONNECTED_POSITIVE) ||
(pdata->connect != NTC_CONNECTED_POSITIVE &&
pdata->connect != NTC_CONNECTED_GROUND))) {
- dev_err(&pdev->dev, "Required data to use read_uV not "
- "supplied.\n");
+ dev_err(&pdev->dev,
+ "Required data to use read_uV not supplied.\n");
return -EINVAL;
}
- data = kzalloc(sizeof(struct ntc_data), GFP_KERNEL);
+ data = devm_kzalloc(&pdev->dev, sizeof(struct ntc_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -370,8 +366,7 @@ static int __devinit ntc_thermistor_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Unknown device type: %lu(%s)\n",
pdev->id_entry->driver_data,
pdev->id_entry->name);
- ret = -EINVAL;
- goto err;
+ return -EINVAL;
}
platform_set_drvdata(pdev, data);
@@ -379,13 +374,13 @@ static int __devinit ntc_thermistor_probe(struct platform_device *pdev)
ret = sysfs_create_group(&data->dev->kobj, &ntc_attr_group);
if (ret) {
dev_err(data->dev, "unable to create sysfs files\n");
- goto err;
+ return ret;
}
data->hwmon_dev = hwmon_device_register(data->dev);
- if (IS_ERR_OR_NULL(data->hwmon_dev)) {
+ if (IS_ERR(data->hwmon_dev)) {
dev_err(data->dev, "unable to register as hwmon device.\n");
- ret = -EINVAL;
+ ret = PTR_ERR(data->hwmon_dev);
goto err_after_sysfs;
}
@@ -395,8 +390,6 @@ static int __devinit ntc_thermistor_probe(struct platform_device *pdev)
return 0;
err_after_sysfs:
sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
-err:
- kfree(data);
return ret;
}
@@ -408,8 +401,6 @@ static int __devexit ntc_thermistor_remove(struct platform_device *pdev)
sysfs_remove_group(&data->dev->kobj, &ntc_attr_group);
platform_set_drvdata(pdev, NULL);
- kfree(data);
-
return 0;
}
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index d2c5095deeac..94468a64ce3a 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -351,7 +351,7 @@ config I2C_DAVINCI
For details please see http://www.ti.com/davinci
config I2C_DESIGNWARE_PLATFORM
- tristate "Synopsys DesignWare Platfrom"
+ tristate "Synopsys DesignWare Platform"
depends on HAVE_CLK
help
If you say yes to this option, support will be included for the
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index dfb84b7ee550..56bce9a8bcbb 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -51,6 +51,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_i2c.h>
+#include <linux/pinctrl/consumer.h>
#include <mach/irqs.h>
#include <mach/hardware.h>
@@ -470,6 +471,7 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
struct imx_i2c_struct *i2c_imx;
struct resource *res;
struct imxi2c_platform_data *pdata = pdev->dev.platform_data;
+ struct pinctrl *pinctrl;
void __iomem *base;
resource_size_t res_size;
int irq, bitrate;
@@ -520,6 +522,12 @@ static int __init i2c_imx_probe(struct platform_device *pdev)
i2c_imx->base = base;
i2c_imx->res = res;
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ goto fail3;
+ }
+
/* Get I2C clock */
i2c_imx->clk = clk_get(&pdev->dev, "i2c_clk");
if (IS_ERR(i2c_imx->clk)) {
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index 76b8af44f634..7fa73eed84a7 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -26,6 +26,7 @@
#include <linux/platform_device.h>
#include <linux/jiffies.h>
#include <linux/io.h>
+#include <linux/pinctrl/consumer.h>
#include <mach/common.h>
@@ -325,10 +326,15 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct mxs_i2c_dev *i2c;
struct i2c_adapter *adap;
+ struct pinctrl *pinctrl;
struct resource *res;
resource_size_t res_size;
int err, irq;
+ pinctrl = devm_pinctrl_get_select_default(dev);
+ if (IS_ERR(pinctrl))
+ return PTR_ERR(pinctrl);
+
i2c = devm_kzalloc(dev, sizeof(struct mxs_i2c_dev), GFP_KERNEL);
if (!i2c)
return -ENOMEM;
diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c
index eb8ad538c79f..99389d2eae51 100644
--- a/drivers/i2c/busses/i2c-pnx.c
+++ b/drivers/i2c/busses/i2c-pnx.c
@@ -23,16 +23,61 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/slab.h>
+#include <linux/of_i2c.h>
+
+#define I2C_PNX_TIMEOUT_DEFAULT 10 /* msec */
+#define I2C_PNX_SPEED_KHZ_DEFAULT 100
+#define I2C_PNX_REGION_SIZE 0x100
+
+enum {
+ mstatus_tdi = 0x00000001,
+ mstatus_afi = 0x00000002,
+ mstatus_nai = 0x00000004,
+ mstatus_drmi = 0x00000008,
+ mstatus_active = 0x00000020,
+ mstatus_scl = 0x00000040,
+ mstatus_sda = 0x00000080,
+ mstatus_rff = 0x00000100,
+ mstatus_rfe = 0x00000200,
+ mstatus_tff = 0x00000400,
+ mstatus_tfe = 0x00000800,
+};
-#include <mach/hardware.h>
-#include <mach/i2c.h>
+enum {
+ mcntrl_tdie = 0x00000001,
+ mcntrl_afie = 0x00000002,
+ mcntrl_naie = 0x00000004,
+ mcntrl_drmie = 0x00000008,
+ mcntrl_daie = 0x00000020,
+ mcntrl_rffie = 0x00000040,
+ mcntrl_tffie = 0x00000080,
+ mcntrl_reset = 0x00000100,
+ mcntrl_cdbmode = 0x00000400,
+};
-#define I2C_PNX_TIMEOUT 10 /* msec */
-#define I2C_PNX_SPEED_KHZ 100
-#define I2C_PNX_REGION_SIZE 0x100
+enum {
+ rw_bit = 1 << 0,
+ start_bit = 1 << 8,
+ stop_bit = 1 << 9,
+};
-static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data)
+#define I2C_REG_RX(a) ((a)->ioaddr) /* Rx FIFO reg (RO) */
+#define I2C_REG_TX(a) ((a)->ioaddr) /* Tx FIFO reg (WO) */
+#define I2C_REG_STS(a) ((a)->ioaddr + 0x04) /* Status reg (RO) */
+#define I2C_REG_CTL(a) ((a)->ioaddr + 0x08) /* Ctl reg */
+#define I2C_REG_CKL(a) ((a)->ioaddr + 0x0c) /* Clock divider low */
+#define I2C_REG_CKH(a) ((a)->ioaddr + 0x10) /* Clock divider high */
+#define I2C_REG_ADR(a) ((a)->ioaddr + 0x14) /* I2C address */
+#define I2C_REG_RFL(a) ((a)->ioaddr + 0x18) /* Rx FIFO level (RO) */
+#define I2C_REG_TFL(a) ((a)->ioaddr + 0x1c) /* Tx FIFO level (RO) */
+#define I2C_REG_RXB(a) ((a)->ioaddr + 0x20) /* Num of bytes Rx-ed (RO) */
+#define I2C_REG_TXB(a) ((a)->ioaddr + 0x24) /* Num of bytes Tx-ed (RO) */
+#define I2C_REG_TXS(a) ((a)->ioaddr + 0x28) /* Tx slave FIFO (RO) */
+#define I2C_REG_STFL(a) ((a)->ioaddr + 0x2c) /* Tx slave FIFO level (RO) */
+
+static inline int wait_timeout(struct i2c_pnx_algo_data *data)
{
+ long timeout = data->timeout;
while (timeout > 0 &&
(ioread32(I2C_REG_STS(data)) & mstatus_active)) {
mdelay(1);
@@ -41,8 +86,9 @@ static inline int wait_timeout(long timeout, struct i2c_pnx_algo_data *data)
return (timeout <= 0);
}
-static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data)
+static inline int wait_reset(struct i2c_pnx_algo_data *data)
{
+ long timeout = data->timeout;
while (timeout > 0 &&
(ioread32(I2C_REG_CTL(data)) & mcntrl_reset)) {
mdelay(1);
@@ -54,7 +100,7 @@ static inline int wait_reset(long timeout, struct i2c_pnx_algo_data *data)
static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data)
{
struct timer_list *timer = &alg_data->mif.timer;
- unsigned long expires = msecs_to_jiffies(I2C_PNX_TIMEOUT);
+ unsigned long expires = msecs_to_jiffies(alg_data->timeout);
if (expires <= 1)
expires = 2;
@@ -92,7 +138,7 @@ static int i2c_pnx_start(unsigned char slave_addr,
}
/* First, make sure bus is idle */
- if (wait_timeout(I2C_PNX_TIMEOUT, alg_data)) {
+ if (wait_timeout(alg_data)) {
/* Somebody else is monopolizing the bus */
dev_err(&alg_data->adapter.dev,
"%s: Bus busy. Slave addr = %02x, cntrl = %x, stat = %x\n",
@@ -185,7 +231,7 @@ static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data)
if (alg_data->mif.len == 0) {
if (alg_data->last) {
/* Wait until the STOP is seen. */
- if (wait_timeout(I2C_PNX_TIMEOUT, alg_data))
+ if (wait_timeout(alg_data))
dev_err(&alg_data->adapter.dev,
"The bus is still active after timeout\n");
}
@@ -283,7 +329,7 @@ static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data)
if (alg_data->mif.len == 0) {
if (alg_data->last)
/* Wait until the STOP is seen. */
- if (wait_timeout(I2C_PNX_TIMEOUT, alg_data))
+ if (wait_timeout(alg_data))
dev_err(&alg_data->adapter.dev,
"The bus is still active after timeout\n");
@@ -399,7 +445,7 @@ static void i2c_pnx_timeout(unsigned long data)
ctl |= mcntrl_reset;
iowrite32(ctl, I2C_REG_CTL(alg_data));
- wait_reset(I2C_PNX_TIMEOUT, alg_data);
+ wait_reset(alg_data);
alg_data->mif.ret = -EIO;
complete(&alg_data->mif.complete);
}
@@ -414,18 +460,18 @@ static inline void bus_reset_if_active(struct i2c_pnx_algo_data *alg_data)
alg_data->adapter.name);
iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
I2C_REG_CTL(alg_data));
- wait_reset(I2C_PNX_TIMEOUT, alg_data);
+ wait_reset(alg_data);
} else if (!(stat & mstatus_rfe) || !(stat & mstatus_tfe)) {
/* If there is data in the fifo's after transfer,
* flush fifo's by reset.
*/
iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
I2C_REG_CTL(alg_data));
- wait_reset(I2C_PNX_TIMEOUT, alg_data);
+ wait_reset(alg_data);
} else if (stat & mstatus_nai) {
iowrite32(ioread32(I2C_REG_CTL(alg_data)) | mcntrl_reset,
I2C_REG_CTL(alg_data));
- wait_reset(I2C_PNX_TIMEOUT, alg_data);
+ wait_reset(alg_data);
}
}
@@ -568,14 +614,8 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
int ret = 0;
struct i2c_pnx_algo_data *alg_data;
unsigned long freq;
- struct i2c_pnx_data *i2c_pnx = pdev->dev.platform_data;
-
- if (!i2c_pnx || !i2c_pnx->name) {
- dev_err(&pdev->dev, "%s: no platform data supplied\n",
- __func__);
- ret = -EINVAL;
- goto out;
- }
+ struct resource *res;
+ u32 speed = I2C_PNX_SPEED_KHZ_DEFAULT * 1000;
alg_data = kzalloc(sizeof(*alg_data), GFP_KERNEL);
if (!alg_data) {
@@ -585,14 +625,27 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, alg_data);
- strlcpy(alg_data->adapter.name, i2c_pnx->name,
- sizeof(alg_data->adapter.name));
alg_data->adapter.dev.parent = &pdev->dev;
alg_data->adapter.algo = &pnx_algorithm;
alg_data->adapter.algo_data = alg_data;
alg_data->adapter.nr = pdev->id;
- alg_data->i2c_pnx = i2c_pnx;
+ alg_data->timeout = I2C_PNX_TIMEOUT_DEFAULT;
+#ifdef CONFIG_OF
+ alg_data->adapter.dev.of_node = of_node_get(pdev->dev.of_node);
+ if (pdev->dev.of_node) {
+ of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+ &speed);
+ /*
+ * At this point, it is planned to add an OF timeout property.
+ * As soon as there is a consensus about how to call and handle
+ * this, sth. like the following can be put here:
+ *
+ * of_property_read_u32(pdev->dev.of_node, "timeout",
+ * &alg_data->timeout);
+ */
+ }
+#endif
alg_data->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(alg_data->clk)) {
ret = PTR_ERR(alg_data->clk);
@@ -603,17 +656,27 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
alg_data->mif.timer.function = i2c_pnx_timeout;
alg_data->mif.timer.data = (unsigned long)alg_data;
+ snprintf(alg_data->adapter.name, sizeof(alg_data->adapter.name),
+ "%s", pdev->name);
+
/* Register I/O resource */
- if (!request_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE,
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Unable to get mem resource.\n");
+ ret = -EBUSY;
+ goto out_clkget;
+ }
+ if (!request_mem_region(res->start, I2C_PNX_REGION_SIZE,
pdev->name)) {
dev_err(&pdev->dev,
"I/O region 0x%08x for I2C already in use.\n",
- i2c_pnx->base);
- ret = -ENODEV;
+ res->start);
+ ret = -ENOMEM;
goto out_clkget;
}
- alg_data->ioaddr = ioremap(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+ alg_data->base = res->start;
+ alg_data->ioaddr = ioremap(res->start, I2C_PNX_REGION_SIZE);
if (!alg_data->ioaddr) {
dev_err(&pdev->dev, "Couldn't ioremap I2C I/O region\n");
ret = -ENOMEM;
@@ -637,20 +700,25 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
* the deglitching filter length.
*/
- tmp = ((freq / 1000) / I2C_PNX_SPEED_KHZ) / 2 - 2;
+ tmp = (freq / speed) / 2 - 2;
if (tmp > 0x3FF)
tmp = 0x3FF;
iowrite32(tmp, I2C_REG_CKH(alg_data));
iowrite32(tmp, I2C_REG_CKL(alg_data));
iowrite32(mcntrl_reset, I2C_REG_CTL(alg_data));
- if (wait_reset(I2C_PNX_TIMEOUT, alg_data)) {
+ if (wait_reset(alg_data)) {
ret = -ENODEV;
goto out_clock;
}
init_completion(&alg_data->mif.complete);
- ret = request_irq(i2c_pnx->irq, i2c_pnx_interrupt,
+ alg_data->irq = platform_get_irq(pdev, 0);
+ if (alg_data->irq < 0) {
+ dev_err(&pdev->dev, "Failed to get IRQ from platform resource\n");
+ goto out_irq;
+ }
+ ret = request_irq(alg_data->irq, i2c_pnx_interrupt,
0, pdev->name, alg_data);
if (ret)
goto out_clock;
@@ -662,39 +730,39 @@ static int __devinit i2c_pnx_probe(struct platform_device *pdev)
goto out_irq;
}
+ of_i2c_register_devices(&alg_data->adapter);
+
dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n",
- alg_data->adapter.name, i2c_pnx->base, i2c_pnx->irq);
+ alg_data->adapter.name, res->start, alg_data->irq);
return 0;
out_irq:
- free_irq(i2c_pnx->irq, alg_data);
+ free_irq(alg_data->irq, alg_data);
out_clock:
clk_disable(alg_data->clk);
out_unmap:
iounmap(alg_data->ioaddr);
out_release:
- release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+ release_mem_region(res->start, I2C_PNX_REGION_SIZE);
out_clkget:
clk_put(alg_data->clk);
out_drvdata:
kfree(alg_data);
err_kzalloc:
platform_set_drvdata(pdev, NULL);
-out:
return ret;
}
static int __devexit i2c_pnx_remove(struct platform_device *pdev)
{
struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev);
- struct i2c_pnx_data *i2c_pnx = alg_data->i2c_pnx;
- free_irq(i2c_pnx->irq, alg_data);
+ free_irq(alg_data->irq, alg_data);
i2c_del_adapter(&alg_data->adapter);
clk_disable(alg_data->clk);
iounmap(alg_data->ioaddr);
- release_mem_region(i2c_pnx->base, I2C_PNX_REGION_SIZE);
+ release_mem_region(alg_data->base, I2C_PNX_REGION_SIZE);
clk_put(alg_data->clk);
kfree(alg_data);
platform_set_drvdata(pdev, NULL);
@@ -702,10 +770,19 @@ static int __devexit i2c_pnx_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id i2c_pnx_of_match[] = {
+ { .compatible = "nxp,pnx-i2c" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, i2c_pnx_of_match);
+#endif
+
static struct platform_driver i2c_pnx_driver = {
.driver = {
.name = "pnx-i2c",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(i2c_pnx_of_match),
},
.probe = i2c_pnx_probe,
.remove = __devexit_p(i2c_pnx_remove),
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
index 7b397c6f607e..31c47e18d83c 100644
--- a/drivers/i2c/busses/i2c-powermac.c
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -227,6 +227,72 @@ static int __devexit i2c_powermac_remove(struct platform_device *dev)
return 0;
}
+static void __devinit i2c_powermac_register_devices(struct i2c_adapter *adap,
+ struct pmac_i2c_bus *bus)
+{
+ struct i2c_client *newdev;
+ struct device_node *node;
+
+ for_each_child_of_node(adap->dev.of_node, node) {
+ struct i2c_board_info info = {};
+ struct dev_archdata dev_ad = {};
+ const __be32 *reg;
+ char tmp[16];
+ u32 addr;
+ int len;
+
+ /* Get address & channel */
+ reg = of_get_property(node, "reg", &len);
+ if (!reg || (len < sizeof(int))) {
+ dev_err(&adap->dev, "i2c-powermac: invalid reg on %s\n",
+ node->full_name);
+ continue;
+ }
+ addr = be32_to_cpup(reg);
+
+ /* Multibus setup, check channel */
+ if (!pmac_i2c_match_adapter(node, adap))
+ continue;
+
+ dev_dbg(&adap->dev, "i2c-powermac: register %s\n",
+ node->full_name);
+
+ /* Make up a modalias. Note: we to _NOT_ want the standard
+ * i2c drivers to match with any of our powermac stuff
+ * unless they have been specifically modified to handle
+ * it on a case by case basis. For example, for thermal
+ * control, things like lm75 etc... shall match with their
+ * corresponding windfarm drivers, _NOT_ the generic ones,
+ * so we force a prefix of AAPL, onto the modalias to
+ * make that happen
+ */
+ if (of_modalias_node(node, tmp, sizeof(tmp)) < 0) {
+ dev_err(&adap->dev, "i2c-powermac: modalias failure"
+ " on %s\n", node->full_name);
+ continue;
+ }
+ snprintf(info.type, sizeof(info.type), "MAC,%s", tmp);
+
+ /* Fill out the rest of the info structure */
+ info.addr = (addr & 0xff) >> 1;
+ info.irq = irq_of_parse_and_map(node, 0);
+ info.of_node = of_node_get(node);
+ info.archdata = &dev_ad;
+
+ newdev = i2c_new_device(adap, &info);
+ if (!newdev) {
+ dev_err(&adap->dev, "i2c-powermac: Failure to register"
+ " %s\n", node->full_name);
+ of_node_put(node);
+ /* We do not dispose of the interrupt mapping on
+ * purpose. It's not necessary (interrupt cannot be
+ * re-used) and somebody else might have grabbed it
+ * via direct DT lookup so let's not bother
+ */
+ continue;
+ }
+ }
+}
static int __devinit i2c_powermac_probe(struct platform_device *dev)
{
@@ -272,6 +338,7 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev)
adapter->algo = &i2c_powermac_algorithm;
i2c_set_adapdata(adapter, bus);
adapter->dev.parent = &dev->dev;
+ adapter->dev.of_node = dev->dev.of_node;
rc = i2c_add_adapter(adapter);
if (rc) {
printk(KERN_ERR "i2c-powermac: Adapter %s registration "
@@ -281,33 +348,10 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev)
printk(KERN_INFO "PowerMac i2c bus %s registered\n", adapter->name);
- if (!strncmp(basename, "uni-n", 5)) {
- struct device_node *np;
- const u32 *prop;
- struct i2c_board_info info;
-
- /* Instantiate I2C motion sensor if present */
- np = of_find_node_by_name(NULL, "accelerometer");
- if (np && of_device_is_compatible(np, "AAPL,accelerometer_1") &&
- (prop = of_get_property(np, "reg", NULL))) {
- int i2c_bus;
- const char *tmp_bus;
-
- /* look for bus either using "reg" or by path */
- tmp_bus = strstr(np->full_name, "/i2c-bus@");
- if (tmp_bus)
- i2c_bus = *(tmp_bus + 9) - '0';
- else
- i2c_bus = ((*prop) >> 8) & 0x0f;
-
- if (pmac_i2c_get_channel(bus) == i2c_bus) {
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = ((*prop) & 0xff) >> 1;
- strlcpy(info.type, "ams", I2C_NAME_SIZE);
- i2c_new_device(adapter, &info);
- }
- }
- }
+ /* Cannot use of_i2c_register_devices() due to Apple device-tree
+ * funkyness
+ */
+ i2c_powermac_register_devices(adapter, bus);
return rc;
}
diff --git a/drivers/i2c/busses/i2c-s6000.c b/drivers/i2c/busses/i2c-s6000.c
index c64ba736f480..b76a29d1f8e4 100644
--- a/drivers/i2c/busses/i2c-s6000.c
+++ b/drivers/i2c/busses/i2c-s6000.c
@@ -3,7 +3,7 @@
*
* Description: Driver for S6000 Family I2C Interface
* Copyright (c) 2008 emlix GmbH
- * Author: Oskar Schirmer <os@emlix.com>
+ * Author: Oskar Schirmer <oskar@scara.com>
*
* Partially based on i2c-bfin-twi.c driver by <sonic.zhang@analog.com>
* Copyright (c) 2005-2007 Analog Devices, Inc.
diff --git a/drivers/i2c/busses/i2c-s6000.h b/drivers/i2c/busses/i2c-s6000.h
index ff23b81ded44..4936f9f2256f 100644
--- a/drivers/i2c/busses/i2c-s6000.h
+++ b/drivers/i2c/busses/i2c-s6000.h
@@ -6,7 +6,7 @@
* for more details.
*
* Copyright (C) 2008 Emlix GmbH <info@emlix.com>
- * Author: Oskar Schirmer <os@emlix.com>
+ * Author: Oskar Schirmer <oskar@scara.com>
*/
#ifndef __DRIVERS_I2C_BUSSES_I2C_S6000_H
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
new file mode 100644
index 000000000000..56eecefcec75
--- /dev/null
+++ b/drivers/iio/Kconfig
@@ -0,0 +1,54 @@
+#
+# Industrial I/O subsytem configuration
+#
+
+menuconfig IIO
+ tristate "Industrial I/O support"
+ depends on GENERIC_HARDIRQS
+ help
+ The industrial I/O subsystem provides a unified framework for
+ drivers for many different types of embedded sensors using a
+ number of different physical interfaces (i2c, spi, etc). See
+ Documentation/iio for more information.
+
+if IIO
+
+config IIO_BUFFER
+ bool "Enable buffer support within IIO"
+ help
+ Provide core support for various buffer based data
+ acquisition methods.
+
+if IIO_BUFFER
+
+config IIO_KFIFO_BUF
+ select IIO_TRIGGER
+ tristate "Industrial I/O buffering based on kfifo"
+ help
+ A simple fifo based on kfifo. Use this if you want a fifo
+ rather than a ring buffer. Note that this currently provides
+ no buffer events so it is up to userspace to work out how
+ often to read from the buffer.
+
+endif # IIO_BUFFER
+
+config IIO_TRIGGER
+ boolean "Enable triggered sampling support"
+ help
+ Provides IIO core support for triggers. Currently these
+ are used to initialize capture of samples to push into
+ ring buffers. The triggers are effectively a 'capture
+ data now' interrupt.
+
+config IIO_CONSUMERS_PER_TRIGGER
+ int "Maximum number of consumers per trigger"
+ depends on IIO_TRIGGER
+ default "2"
+ help
+ This value controls the maximum number of consumers that a
+ given trigger may handle. Default is 2.
+
+source "drivers/iio/adc/Kconfig"
+source "drivers/iio/amplifiers/Kconfig"
+
+endif # IIO
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
new file mode 100644
index 000000000000..e425afd1480c
--- /dev/null
+++ b/drivers/iio/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for the industrial I/O core.
+#
+
+obj-$(CONFIG_IIO) += industrialio.o
+industrialio-y := industrialio-core.o industrialio-event.o inkern.o
+industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
+industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
+
+obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
+
+obj-y += adc/
+obj-y += amplifiers/
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
new file mode 100644
index 000000000000..9a0df8123cc4
--- /dev/null
+++ b/drivers/iio/adc/Kconfig
@@ -0,0 +1,16 @@
+#
+# ADC drivers
+#
+menu "Analog to digital converters"
+
+config AT91_ADC
+ tristate "Atmel AT91 ADC"
+ depends on ARCH_AT91
+ select IIO_BUFFER
+ select IIO_KFIFO_BUF
+ select IIO_TRIGGER
+ select SYSFS
+ help
+ Say yes here to build support for Atmel AT91 ADC.
+
+endmenu
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
new file mode 100644
index 000000000000..175c8d41ea99
--- /dev/null
+++ b/drivers/iio/adc/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for IIO ADC drivers
+#
+
+obj-$(CONFIG_AT91_ADC) += at91_adc.o
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
new file mode 100644
index 000000000000..f18a95d80255
--- /dev/null
+++ b/drivers/iio/adc/at91_adc.c
@@ -0,0 +1,802 @@
+/*
+ * Driver for the ADC present in the Atmel AT91 evaluation boards.
+ *
+ * Copyright 2011 Free Electrons
+ *
+ * Licensed under the GPLv2 or later.
+ */
+
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+
+#include <linux/platform_data/at91_adc.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+
+#include <mach/at91_adc.h>
+
+#define AT91_ADC_CHAN(st, ch) \
+ (st->registers->channel_base + (ch * 4))
+#define at91_adc_readl(st, reg) \
+ (readl_relaxed(st->reg_base + reg))
+#define at91_adc_writel(st, reg, val) \
+ (writel_relaxed(val, st->reg_base + reg))
+
+struct at91_adc_state {
+ struct clk *adc_clk;
+ u16 *buffer;
+ unsigned long channels_mask;
+ struct clk *clk;
+ bool done;
+ int irq;
+ bool irq_enabled;
+ u16 last_value;
+ struct mutex lock;
+ u8 num_channels;
+ void __iomem *reg_base;
+ struct at91_adc_reg_desc *registers;
+ u8 startup_time;
+ struct iio_trigger **trig;
+ struct at91_adc_trigger *trigger_list;
+ u32 trigger_number;
+ bool use_external;
+ u32 vref_mv;
+ wait_queue_head_t wq_data_avail;
+};
+
+static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *idev = pf->indio_dev;
+ struct at91_adc_state *st = iio_priv(idev);
+ struct iio_buffer *buffer = idev->buffer;
+ int i, j = 0;
+
+ for (i = 0; i < idev->masklength; i++) {
+ if (!test_bit(i, idev->active_scan_mask))
+ continue;
+ st->buffer[j] = at91_adc_readl(st, AT91_ADC_CHAN(st, i));
+ j++;
+ }
+
+ if (idev->scan_timestamp) {
+ s64 *timestamp = (s64 *)((u8 *)st->buffer +
+ ALIGN(j, sizeof(s64)));
+ *timestamp = pf->timestamp;
+ }
+
+ buffer->access->store_to(buffer, (u8 *)st->buffer, pf->timestamp);
+
+ iio_trigger_notify_done(idev->trig);
+ st->irq_enabled = true;
+
+ /* Needed to ACK the DRDY interruption */
+ at91_adc_readl(st, AT91_ADC_LCDR);
+
+ enable_irq(st->irq);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
+{
+ struct iio_dev *idev = private;
+ struct at91_adc_state *st = iio_priv(idev);
+ u32 status = at91_adc_readl(st, st->registers->status_register);
+
+ if (!(status & st->registers->drdy_mask))
+ return IRQ_HANDLED;
+
+ if (iio_buffer_enabled(idev)) {
+ disable_irq_nosync(irq);
+ st->irq_enabled = false;
+ iio_trigger_poll(idev->trig, iio_get_time_ns());
+ } else {
+ st->last_value = at91_adc_readl(st, AT91_ADC_LCDR);
+ st->done = true;
+ wake_up_interruptible(&st->wq_data_avail);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int at91_adc_channel_init(struct iio_dev *idev)
+{
+ struct at91_adc_state *st = iio_priv(idev);
+ struct iio_chan_spec *chan_array, *timestamp;
+ int bit, idx = 0;
+
+ idev->num_channels = bitmap_weight(&st->channels_mask,
+ st->num_channels) + 1;
+
+ chan_array = devm_kzalloc(&idev->dev,
+ ((idev->num_channels + 1) *
+ sizeof(struct iio_chan_spec)),
+ GFP_KERNEL);
+
+ if (!chan_array)
+ return -ENOMEM;
+
+ for_each_set_bit(bit, &st->channels_mask, st->num_channels) {
+ struct iio_chan_spec *chan = chan_array + idx;
+
+ chan->type = IIO_VOLTAGE;
+ chan->indexed = 1;
+ chan->channel = bit;
+ chan->scan_index = idx;
+ chan->scan_type.sign = 'u';
+ chan->scan_type.realbits = 10;
+ chan->scan_type.storagebits = 16;
+ chan->info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ IIO_CHAN_INFO_RAW_SEPARATE_BIT;
+ idx++;
+ }
+ timestamp = chan_array + idx;
+
+ timestamp->type = IIO_TIMESTAMP;
+ timestamp->channel = -1;
+ timestamp->scan_index = idx;
+ timestamp->scan_type.sign = 's';
+ timestamp->scan_type.realbits = 64;
+ timestamp->scan_type.storagebits = 64;
+
+ idev->channels = chan_array;
+ return idev->num_channels;
+}
+
+static u8 at91_adc_get_trigger_value_by_name(struct iio_dev *idev,
+ struct at91_adc_trigger *triggers,
+ const char *trigger_name)
+{
+ struct at91_adc_state *st = iio_priv(idev);
+ u8 value = 0;
+ int i;
+
+ for (i = 0; i < st->trigger_number; i++) {
+ char *name = kasprintf(GFP_KERNEL,
+ "%s-dev%d-%s",
+ idev->name,
+ idev->id,
+ triggers[i].name);
+ if (!name)
+ return -ENOMEM;
+
+ if (strcmp(trigger_name, name) == 0) {
+ value = triggers[i].value;
+ kfree(name);
+ break;
+ }
+
+ kfree(name);
+ }
+
+ return value;
+}
+
+static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state)
+{
+ struct iio_dev *idev = trig->private_data;
+ struct at91_adc_state *st = iio_priv(idev);
+ struct iio_buffer *buffer = idev->buffer;
+ struct at91_adc_reg_desc *reg = st->registers;
+ u32 status = at91_adc_readl(st, reg->trigger_register);
+ u8 value;
+ u8 bit;
+
+ value = at91_adc_get_trigger_value_by_name(idev,
+ st->trigger_list,
+ idev->trig->name);
+ if (value == 0)
+ return -EINVAL;
+
+ if (state) {
+ st->buffer = kmalloc(idev->scan_bytes, GFP_KERNEL);
+ if (st->buffer == NULL)
+ return -ENOMEM;
+
+ at91_adc_writel(st, reg->trigger_register,
+ status | value);
+
+ for_each_set_bit(bit, buffer->scan_mask,
+ st->num_channels) {
+ struct iio_chan_spec const *chan = idev->channels + bit;
+ at91_adc_writel(st, AT91_ADC_CHER,
+ AT91_ADC_CH(chan->channel));
+ }
+
+ at91_adc_writel(st, AT91_ADC_IER, reg->drdy_mask);
+
+ } else {
+ at91_adc_writel(st, AT91_ADC_IDR, reg->drdy_mask);
+
+ at91_adc_writel(st, reg->trigger_register,
+ status & ~value);
+
+ for_each_set_bit(bit, buffer->scan_mask,
+ st->num_channels) {
+ struct iio_chan_spec const *chan = idev->channels + bit;
+ at91_adc_writel(st, AT91_ADC_CHDR,
+ AT91_ADC_CH(chan->channel));
+ }
+ kfree(st->buffer);
+ }
+
+ return 0;
+}
+
+static const struct iio_trigger_ops at91_adc_trigger_ops = {
+ .owner = THIS_MODULE,
+ .set_trigger_state = &at91_adc_configure_trigger,
+};
+
+static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *idev,
+ struct at91_adc_trigger *trigger)
+{
+ struct iio_trigger *trig;
+ int ret;
+
+ trig = iio_trigger_alloc("%s-dev%d-%s", idev->name,
+ idev->id, trigger->name);
+ if (trig == NULL)
+ return NULL;
+
+ trig->dev.parent = idev->dev.parent;
+ trig->private_data = idev;
+ trig->ops = &at91_adc_trigger_ops;
+
+ ret = iio_trigger_register(trig);
+ if (ret)
+ return NULL;
+
+ return trig;
+}
+
+static int at91_adc_trigger_init(struct iio_dev *idev)
+{
+ struct at91_adc_state *st = iio_priv(idev);
+ int i, ret;
+
+ st->trig = devm_kzalloc(&idev->dev,
+ st->trigger_number * sizeof(st->trig),
+ GFP_KERNEL);
+
+ if (st->trig == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ for (i = 0; i < st->trigger_number; i++) {
+ if (st->trigger_list[i].is_external && !(st->use_external))
+ continue;
+
+ st->trig[i] = at91_adc_allocate_trigger(idev,
+ st->trigger_list + i);
+ if (st->trig[i] == NULL) {
+ dev_err(&idev->dev,
+ "Could not allocate trigger %d\n", i);
+ ret = -ENOMEM;
+ goto error_trigger;
+ }
+ }
+
+ return 0;
+
+error_trigger:
+ for (i--; i >= 0; i--) {
+ iio_trigger_unregister(st->trig[i]);
+ iio_trigger_free(st->trig[i]);
+ }
+error_ret:
+ return ret;
+}
+
+static void at91_adc_trigger_remove(struct iio_dev *idev)
+{
+ struct at91_adc_state *st = iio_priv(idev);
+ int i;
+
+ for (i = 0; i < st->trigger_number; i++) {
+ iio_trigger_unregister(st->trig[i]);
+ iio_trigger_free(st->trig[i]);
+ }
+}
+
+static const struct iio_buffer_setup_ops at91_adc_buffer_ops = {
+ .preenable = &iio_sw_buffer_preenable,
+ .postenable = &iio_triggered_buffer_postenable,
+ .predisable = &iio_triggered_buffer_predisable,
+};
+
+static int at91_adc_buffer_init(struct iio_dev *idev)
+{
+ int ret;
+
+ idev->buffer = iio_kfifo_allocate(idev);
+ if (!idev->buffer) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ idev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
+ &at91_adc_trigger_handler,
+ IRQF_ONESHOT,
+ idev,
+ "%s-consumer%d",
+ idev->name,
+ idev->id);
+ if (idev->pollfunc == NULL) {
+ ret = -ENOMEM;
+ goto error_pollfunc;
+ }
+
+ idev->setup_ops = &at91_adc_buffer_ops;
+ idev->modes |= INDIO_BUFFER_TRIGGERED;
+
+ ret = iio_buffer_register(idev,
+ idev->channels,
+ idev->num_channels);
+ if (ret)
+ goto error_register;
+
+ return 0;
+
+error_register:
+ iio_dealloc_pollfunc(idev->pollfunc);
+error_pollfunc:
+ iio_kfifo_free(idev->buffer);
+error_ret:
+ return ret;
+}
+
+static void at91_adc_buffer_remove(struct iio_dev *idev)
+{
+ iio_buffer_unregister(idev);
+ iio_dealloc_pollfunc(idev->pollfunc);
+ iio_kfifo_free(idev->buffer);
+}
+
+static int at91_adc_read_raw(struct iio_dev *idev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct at91_adc_state *st = iio_priv(idev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&st->lock);
+
+ at91_adc_writel(st, AT91_ADC_CHER,
+ AT91_ADC_CH(chan->channel));
+ at91_adc_writel(st, AT91_ADC_IER, st->registers->drdy_mask);
+ at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_START);
+
+ ret = wait_event_interruptible_timeout(st->wq_data_avail,
+ st->done,
+ msecs_to_jiffies(1000));
+ if (ret == 0)
+ return -ETIMEDOUT;
+ else if (ret < 0)
+ return ret;
+
+ *val = st->last_value;
+
+ at91_adc_writel(st, AT91_ADC_CHDR,
+ AT91_ADC_CH(chan->channel));
+ at91_adc_writel(st, AT91_ADC_IDR, st->registers->drdy_mask);
+
+ st->last_value = 0;
+ st->done = false;
+ mutex_unlock(&st->lock);
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ *val = (st->vref_mv * 1000) >> chan->scan_type.realbits;
+ *val2 = 0;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ break;
+ }
+ return -EINVAL;
+}
+
+static int at91_adc_probe_dt(struct at91_adc_state *st,
+ struct platform_device *pdev)
+{
+ struct iio_dev *idev = iio_priv_to_dev(st);
+ struct device_node *node = pdev->dev.of_node;
+ struct device_node *trig_node;
+ int i = 0, ret;
+ u32 prop;
+
+ if (!node)
+ return -EINVAL;
+
+ st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers");
+
+ if (of_property_read_u32(node, "atmel,adc-channels-used", &prop)) {
+ dev_err(&idev->dev, "Missing adc-channels-used property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ st->channels_mask = prop;
+
+ if (of_property_read_u32(node, "atmel,adc-num-channels", &prop)) {
+ dev_err(&idev->dev, "Missing adc-num-channels property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ st->num_channels = prop;
+
+ if (of_property_read_u32(node, "atmel,adc-startup-time", &prop)) {
+ dev_err(&idev->dev, "Missing adc-startup-time property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ st->startup_time = prop;
+
+
+ if (of_property_read_u32(node, "atmel,adc-vref", &prop)) {
+ dev_err(&idev->dev, "Missing adc-vref property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ st->vref_mv = prop;
+
+ st->registers = devm_kzalloc(&idev->dev,
+ sizeof(struct at91_adc_reg_desc),
+ GFP_KERNEL);
+ if (!st->registers) {
+ dev_err(&idev->dev, "Could not allocate register memory.\n");
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ if (of_property_read_u32(node, "atmel,adc-channel-base", &prop)) {
+ dev_err(&idev->dev, "Missing adc-channel-base property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ st->registers->channel_base = prop;
+
+ if (of_property_read_u32(node, "atmel,adc-drdy-mask", &prop)) {
+ dev_err(&idev->dev, "Missing adc-drdy-mask property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ st->registers->drdy_mask = prop;
+
+ if (of_property_read_u32(node, "atmel,adc-status-register", &prop)) {
+ dev_err(&idev->dev, "Missing adc-status-register property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ st->registers->status_register = prop;
+
+ if (of_property_read_u32(node, "atmel,adc-trigger-register", &prop)) {
+ dev_err(&idev->dev, "Missing adc-trigger-register property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ st->registers->trigger_register = prop;
+
+ st->trigger_number = of_get_child_count(node);
+ st->trigger_list = devm_kzalloc(&idev->dev, st->trigger_number *
+ sizeof(struct at91_adc_trigger),
+ GFP_KERNEL);
+ if (!st->trigger_list) {
+ dev_err(&idev->dev, "Could not allocate trigger list memory.\n");
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ for_each_child_of_node(node, trig_node) {
+ struct at91_adc_trigger *trig = st->trigger_list + i;
+ const char *name;
+
+ if (of_property_read_string(trig_node, "trigger-name", &name)) {
+ dev_err(&idev->dev, "Missing trigger-name property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ trig->name = name;
+
+ if (of_property_read_u32(trig_node, "trigger-value", &prop)) {
+ dev_err(&idev->dev, "Missing trigger-value property in the DT.\n");
+ ret = -EINVAL;
+ goto error_ret;
+ }
+ trig->value = prop;
+ trig->is_external = of_property_read_bool(trig_node, "trigger-external");
+ i++;
+ }
+
+ return 0;
+
+error_ret:
+ return ret;
+}
+
+static int at91_adc_probe_pdata(struct at91_adc_state *st,
+ struct platform_device *pdev)
+{
+ struct at91_adc_data *pdata = pdev->dev.platform_data;
+
+ if (!pdata)
+ return -EINVAL;
+
+ st->use_external = pdata->use_external_triggers;
+ st->vref_mv = pdata->vref;
+ st->channels_mask = pdata->channels_used;
+ st->num_channels = pdata->num_channels;
+ st->startup_time = pdata->startup_time;
+ st->trigger_number = pdata->trigger_number;
+ st->trigger_list = pdata->trigger_list;
+ st->registers = pdata->registers;
+
+ return 0;
+}
+
+static const struct iio_info at91_adc_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = &at91_adc_read_raw,
+};
+
+static int __devinit at91_adc_probe(struct platform_device *pdev)
+{
+ unsigned int prsc, mstrclk, ticks, adc_clk;
+ int ret;
+ struct iio_dev *idev;
+ struct at91_adc_state *st;
+ struct resource *res;
+
+ idev = iio_device_alloc(sizeof(struct at91_adc_state));
+ if (idev == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ st = iio_priv(idev);
+
+ if (pdev->dev.of_node)
+ ret = at91_adc_probe_dt(st, pdev);
+ else
+ ret = at91_adc_probe_pdata(st, pdev);
+
+ if (ret) {
+ dev_err(&pdev->dev, "No platform data available.\n");
+ ret = -EINVAL;
+ goto error_free_device;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "No resource defined\n");
+ ret = -ENXIO;
+ goto error_ret;
+ }
+
+ platform_set_drvdata(pdev, idev);
+
+ idev->dev.parent = &pdev->dev;
+ idev->name = dev_name(&pdev->dev);
+ idev->modes = INDIO_DIRECT_MODE;
+ idev->info = &at91_adc_info;
+
+ st->irq = platform_get_irq(pdev, 0);
+ if (st->irq < 0) {
+ dev_err(&pdev->dev, "No IRQ ID is designated\n");
+ ret = -ENODEV;
+ goto error_free_device;
+ }
+
+ if (!request_mem_region(res->start, resource_size(res),
+ "AT91 adc registers")) {
+ dev_err(&pdev->dev, "Resources are unavailable.\n");
+ ret = -EBUSY;
+ goto error_free_device;
+ }
+
+ st->reg_base = ioremap(res->start, resource_size(res));
+ if (!st->reg_base) {
+ dev_err(&pdev->dev, "Failed to map registers.\n");
+ ret = -ENOMEM;
+ goto error_release_mem;
+ }
+
+ /*
+ * Disable all IRQs before setting up the handler
+ */
+ at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST);
+ at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF);
+ ret = request_irq(st->irq,
+ at91_adc_eoc_trigger,
+ 0,
+ pdev->dev.driver->name,
+ idev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to allocate IRQ.\n");
+ goto error_unmap_reg;
+ }
+
+ st->clk = clk_get(&pdev->dev, "adc_clk");
+ if (IS_ERR(st->clk)) {
+ dev_err(&pdev->dev, "Failed to get the clock.\n");
+ ret = PTR_ERR(st->clk);
+ goto error_free_irq;
+ }
+
+ ret = clk_prepare(st->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not prepare the clock.\n");
+ goto error_free_clk;
+ }
+
+ ret = clk_enable(st->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not enable the clock.\n");
+ goto error_unprepare_clk;
+ }
+
+ st->adc_clk = clk_get(&pdev->dev, "adc_op_clk");
+ if (IS_ERR(st->adc_clk)) {
+ dev_err(&pdev->dev, "Failed to get the ADC clock.\n");
+ ret = PTR_ERR(st->clk);
+ goto error_disable_clk;
+ }
+
+ ret = clk_prepare(st->adc_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not prepare the ADC clock.\n");
+ goto error_free_adc_clk;
+ }
+
+ ret = clk_enable(st->adc_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not enable the ADC clock.\n");
+ goto error_unprepare_adc_clk;
+ }
+
+ /*
+ * Prescaler rate computation using the formula from the Atmel's
+ * datasheet : ADC Clock = MCK / ((Prescaler + 1) * 2), ADC Clock being
+ * specified by the electrical characteristics of the board.
+ */
+ mstrclk = clk_get_rate(st->clk);
+ adc_clk = clk_get_rate(st->adc_clk);
+ prsc = (mstrclk / (2 * adc_clk)) - 1;
+
+ if (!st->startup_time) {
+ dev_err(&pdev->dev, "No startup time available.\n");
+ ret = -EINVAL;
+ goto error_disable_adc_clk;
+ }
+
+ /*
+ * Number of ticks needed to cover the startup time of the ADC as
+ * defined in the electrical characteristics of the board, divided by 8.
+ * The formula thus is : Startup Time = (ticks + 1) * 8 / ADC Clock
+ */
+ ticks = round_up((st->startup_time * adc_clk /
+ 1000000) - 1, 8) / 8;
+ at91_adc_writel(st, AT91_ADC_MR,
+ (AT91_ADC_PRESCAL_(prsc) & AT91_ADC_PRESCAL) |
+ (AT91_ADC_STARTUP_(ticks) & AT91_ADC_STARTUP));
+
+ /* Setup the ADC channels available on the board */
+ ret = at91_adc_channel_init(idev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Couldn't initialize the channels.\n");
+ goto error_disable_adc_clk;
+ }
+
+ init_waitqueue_head(&st->wq_data_avail);
+ mutex_init(&st->lock);
+
+ ret = at91_adc_buffer_init(idev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
+ goto error_disable_adc_clk;
+ }
+
+ ret = at91_adc_trigger_init(idev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
+ goto error_unregister_buffer;
+ }
+
+ ret = iio_device_register(idev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Couldn't register the device.\n");
+ goto error_remove_triggers;
+ }
+
+ return 0;
+
+error_remove_triggers:
+ at91_adc_trigger_remove(idev);
+error_unregister_buffer:
+ at91_adc_buffer_remove(idev);
+error_disable_adc_clk:
+ clk_disable(st->adc_clk);
+error_unprepare_adc_clk:
+ clk_unprepare(st->adc_clk);
+error_free_adc_clk:
+ clk_put(st->adc_clk);
+error_disable_clk:
+ clk_disable(st->clk);
+error_unprepare_clk:
+ clk_unprepare(st->clk);
+error_free_clk:
+ clk_put(st->clk);
+error_free_irq:
+ free_irq(st->irq, idev);
+error_unmap_reg:
+ iounmap(st->reg_base);
+error_release_mem:
+ release_mem_region(res->start, resource_size(res));
+error_free_device:
+ iio_device_free(idev);
+error_ret:
+ return ret;
+}
+
+static int __devexit at91_adc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *idev = platform_get_drvdata(pdev);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct at91_adc_state *st = iio_priv(idev);
+
+ iio_device_unregister(idev);
+ at91_adc_trigger_remove(idev);
+ at91_adc_buffer_remove(idev);
+ clk_disable_unprepare(st->adc_clk);
+ clk_put(st->adc_clk);
+ clk_disable(st->clk);
+ clk_unprepare(st->clk);
+ clk_put(st->clk);
+ free_irq(st->irq, idev);
+ iounmap(st->reg_base);
+ release_mem_region(res->start, resource_size(res));
+ iio_device_free(idev);
+
+ return 0;
+}
+
+static const struct of_device_id at91_adc_dt_ids[] = {
+ { .compatible = "atmel,at91sam9260-adc" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, at91_adc_dt_ids);
+
+static struct platform_driver at91_adc_driver = {
+ .probe = at91_adc_probe,
+ .remove = __devexit_p(at91_adc_remove),
+ .driver = {
+ .name = "at91_adc",
+ .of_match_table = of_match_ptr(at91_adc_dt_ids),
+ },
+};
+
+module_platform_driver(at91_adc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Atmel AT91 ADC Driver");
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
diff --git a/drivers/iio/amplifiers/Kconfig b/drivers/iio/amplifiers/Kconfig
new file mode 100644
index 000000000000..05d707ed7d4f
--- /dev/null
+++ b/drivers/iio/amplifiers/Kconfig
@@ -0,0 +1,17 @@
+#
+# Gain Amplifiers, etc.
+#
+menu "Amplifiers"
+
+config AD8366
+ tristate "Analog Devices AD8366 VGA"
+ depends on SPI
+ select BITREVERSE
+ help
+ Say yes here to build support for Analog Devices AD8366
+ SPI Dual-Digital Variable Gain Amplifier (VGA).
+
+ To compile this driver as a module, choose M here: the
+ module will be called ad8366.
+
+endmenu
diff --git a/drivers/iio/amplifiers/Makefile b/drivers/iio/amplifiers/Makefile
new file mode 100644
index 000000000000..a6ca366908e0
--- /dev/null
+++ b/drivers/iio/amplifiers/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile iio/amplifiers
+#
+
+obj-$(CONFIG_AD8366) += ad8366.o
diff --git a/drivers/iio/amplifiers/ad8366.c b/drivers/iio/amplifiers/ad8366.c
new file mode 100644
index 000000000000..d8281cdbfc4a
--- /dev/null
+++ b/drivers/iio/amplifiers/ad8366.c
@@ -0,0 +1,222 @@
+/*
+ * AD8366 SPI Dual-Digital Variable Gain Amplifier (VGA)
+ *
+ * Copyright 2012 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/spi/spi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/bitrev.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+struct ad8366_state {
+ struct spi_device *spi;
+ struct regulator *reg;
+ unsigned char ch[2];
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ */
+ unsigned char data[2] ____cacheline_aligned;
+};
+
+static int ad8366_write(struct iio_dev *indio_dev,
+ unsigned char ch_a, char unsigned ch_b)
+{
+ struct ad8366_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ch_a = bitrev8(ch_a & 0x3F);
+ ch_b = bitrev8(ch_b & 0x3F);
+
+ st->data[0] = ch_b >> 4;
+ st->data[1] = (ch_b << 4) | (ch_a >> 2);
+
+ ret = spi_write(st->spi, st->data, ARRAY_SIZE(st->data));
+ if (ret < 0)
+ dev_err(&indio_dev->dev, "write failed (%d)", ret);
+
+ return ret;
+}
+
+static int ad8366_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long m)
+{
+ struct ad8366_state *st = iio_priv(indio_dev);
+ int ret;
+ unsigned code;
+
+ mutex_lock(&indio_dev->mlock);
+ switch (m) {
+ case IIO_CHAN_INFO_HARDWAREGAIN:
+ code = st->ch[chan->channel];
+
+ /* Values in dB */
+ code = code * 253 + 4500;
+ *val = code / 1000;
+ *val2 = (code % 1000) * 1000;
+
+ ret = IIO_VAL_INT_PLUS_MICRO_DB;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret;
+};
+
+static int ad8366_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask)
+{
+ struct ad8366_state *st = iio_priv(indio_dev);
+ unsigned code;
+ int ret;
+
+ if (val < 0 || val2 < 0)
+ return -EINVAL;
+
+ /* Values in dB */
+ code = (((u8)val * 1000) + ((u32)val2 / 1000));
+
+ if (code > 20500 || code < 4500)
+ return -EINVAL;
+
+ code = (code - 4500) / 253;
+
+ mutex_lock(&indio_dev->mlock);
+ switch (mask) {
+ case IIO_CHAN_INFO_HARDWAREGAIN:
+ st->ch[chan->channel] = code;
+ ret = ad8366_write(indio_dev, st->ch[0], st->ch[1]);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret;
+}
+
+static const struct iio_info ad8366_info = {
+ .read_raw = &ad8366_read_raw,
+ .write_raw = &ad8366_write_raw,
+ .driver_module = THIS_MODULE,
+};
+
+#define AD8366_CHAN(_channel) { \
+ .type = IIO_VOLTAGE, \
+ .output = 1, \
+ .indexed = 1, \
+ .channel = _channel, \
+ .info_mask = IIO_CHAN_INFO_HARDWAREGAIN_SEPARATE_BIT,\
+}
+
+static const struct iio_chan_spec ad8366_channels[] = {
+ AD8366_CHAN(0),
+ AD8366_CHAN(1),
+};
+
+static int __devinit ad8366_probe(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev;
+ struct ad8366_state *st;
+ int ret;
+
+ indio_dev = iio_device_alloc(sizeof(*st));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ st->reg = regulator_get(&spi->dev, "vcc");
+ if (!IS_ERR(st->reg)) {
+ ret = regulator_enable(st->reg);
+ if (ret)
+ goto error_put_reg;
+ }
+
+ spi_set_drvdata(spi, indio_dev);
+ st->spi = spi;
+
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->name = spi_get_device_id(spi)->name;
+ indio_dev->info = &ad8366_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = ad8366_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ad8366_channels);
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto error_disable_reg;
+
+ ad8366_write(indio_dev, 0 , 0);
+
+ return 0;
+
+error_disable_reg:
+ if (!IS_ERR(st->reg))
+ regulator_disable(st->reg);
+error_put_reg:
+ if (!IS_ERR(st->reg))
+ regulator_put(st->reg);
+
+ iio_device_free(indio_dev);
+
+ return ret;
+}
+
+static int __devexit ad8366_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct ad8366_state *st = iio_priv(indio_dev);
+ struct regulator *reg = st->reg;
+
+ iio_device_unregister(indio_dev);
+
+ if (!IS_ERR(reg)) {
+ regulator_disable(reg);
+ regulator_put(reg);
+ }
+
+ iio_device_free(indio_dev);
+
+ return 0;
+}
+
+static const struct spi_device_id ad8366_id[] = {
+ {"ad8366", 0},
+ {}
+};
+
+static struct spi_driver ad8366_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = ad8366_probe,
+ .remove = __devexit_p(ad8366_remove),
+ .id_table = ad8366_id,
+};
+
+module_spi_driver(ad8366_driver);
+
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("Analog Devices AD8366 VGA");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/iio_core.h b/drivers/iio/iio_core.h
index c9dfcba0bac8..f652e6ae5a35 100644
--- a/drivers/staging/iio/iio_core.h
+++ b/drivers/iio/iio_core.h
@@ -12,6 +12,12 @@
#ifndef _IIO_CORE_H_
#define _IIO_CORE_H_
+#include <linux/kernel.h>
+#include <linux/device.h>
+
+struct iio_chan_spec;
+struct iio_dev;
+
int __iio_add_chan_devattr(const char *postfix,
struct iio_chan_spec const *chan,
diff --git a/drivers/staging/iio/iio_core_trigger.h b/drivers/iio/iio_core_trigger.h
index 6f7c56fcbe78..6f7c56fcbe78 100644
--- a/drivers/staging/iio/iio_core_trigger.h
+++ b/drivers/iio/iio_core_trigger.h
diff --git a/drivers/staging/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index 386ba760f3f1..ac185b8694bd 100644
--- a/drivers/staging/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -21,10 +21,10 @@
#include <linux/slab.h>
#include <linux/poll.h>
-#include "iio.h"
+#include <linux/iio/iio.h>
#include "iio_core.h"
-#include "sysfs.h"
-#include "buffer.h"
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
static const char * const iio_endian_prefix[] = {
[IIO_BE] = "be",
@@ -105,7 +105,7 @@ static ssize_t iio_scan_el_show(struct device *dev,
char *buf)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
ret = test_bit(to_iio_dev_attr(attr)->address,
indio_dev->buffer->scan_mask);
@@ -124,13 +124,15 @@ static ssize_t iio_scan_el_store(struct device *dev,
const char *buf,
size_t len)
{
- int ret = 0;
+ int ret;
bool state;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_buffer *buffer = indio_dev->buffer;
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- state = !(buf[0] == '0');
+ ret = strtobool(buf, &state);
+ if (ret < 0)
+ return ret;
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev)) {
ret = -EBUSY;
@@ -160,7 +162,7 @@ static ssize_t iio_scan_el_ts_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
return sprintf(buf, "%d\n", indio_dev->buffer->scan_timestamp);
}
@@ -169,17 +171,21 @@ static ssize_t iio_scan_el_ts_store(struct device *dev,
const char *buf,
size_t len)
{
- int ret = 0;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ int ret;
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
bool state;
- state = !(buf[0] == '0');
+ ret = strtobool(buf, &state);
+ if (ret < 0)
+ return ret;
+
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev)) {
ret = -EBUSY;
goto error_ret;
}
indio_dev->buffer->scan_timestamp = state;
+ indio_dev->scan_timestamp = state;
error_ret:
mutex_unlock(&indio_dev->mlock);
@@ -291,7 +297,7 @@ int iio_buffer_register(struct iio_dev *indio_dev,
goto error_cleanup_dynamic;
attrcount += ret;
if (channels[i].type == IIO_TIMESTAMP)
- buffer->scan_index_timestamp =
+ indio_dev->scan_index_timestamp =
channels[i].scan_index;
}
if (indio_dev->masklength && buffer->scan_mask == NULL) {
@@ -346,7 +352,7 @@ ssize_t iio_buffer_read_length(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_buffer *buffer = indio_dev->buffer;
if (buffer->access->get_length)
@@ -364,7 +370,7 @@ ssize_t iio_buffer_write_length(struct device *dev,
{
int ret;
ulong val;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_buffer *buffer = indio_dev->buffer;
ret = strict_strtoul(buf, 10, &val);
@@ -397,7 +403,7 @@ ssize_t iio_buffer_store_enable(struct device *dev,
int ret;
bool requested_state, current_state;
int previous_mode;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_buffer *buffer = indio_dev->buffer;
mutex_lock(&indio_dev->mlock);
@@ -483,7 +489,7 @@ ssize_t iio_buffer_show_enable(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
return sprintf(buf, "%d\n", iio_buffer_enabled(indio_dev));
}
EXPORT_SYMBOL(iio_buffer_show_enable);
@@ -503,30 +509,41 @@ static const unsigned long *iio_scan_mask_match(const unsigned long *av_masks,
return NULL;
}
-int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
+static int iio_compute_scan_bytes(struct iio_dev *indio_dev, const long *mask,
+ bool timestamp)
{
- struct iio_buffer *buffer = indio_dev->buffer;
const struct iio_chan_spec *ch;
unsigned bytes = 0;
int length, i;
- dev_dbg(&indio_dev->dev, "%s\n", __func__);
/* How much space will the demuxed element take? */
- for_each_set_bit(i, buffer->scan_mask,
+ for_each_set_bit(i, mask,
indio_dev->masklength) {
ch = iio_find_channel_from_si(indio_dev, i);
- length = ch->scan_type.storagebits/8;
+ length = ch->scan_type.storagebits / 8;
bytes = ALIGN(bytes, length);
bytes += length;
}
- if (buffer->scan_timestamp) {
+ if (timestamp) {
ch = iio_find_channel_from_si(indio_dev,
- buffer->scan_index_timestamp);
- length = ch->scan_type.storagebits/8;
+ indio_dev->scan_index_timestamp);
+ length = ch->scan_type.storagebits / 8;
bytes = ALIGN(bytes, length);
bytes += length;
}
- buffer->access->set_bytes_per_datum(buffer, bytes);
+ return bytes;
+}
+
+int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
+{
+ struct iio_buffer *buffer = indio_dev->buffer;
+ dev_dbg(&indio_dev->dev, "%s\n", __func__);
+
+ /* How much space will the demuxed element take? */
+ indio_dev->scan_bytes =
+ iio_compute_scan_bytes(indio_dev, buffer->scan_mask,
+ buffer->scan_timestamp);
+ buffer->access->set_bytes_per_datum(buffer, indio_dev->scan_bytes);
/* What scan mask do we actually have ?*/
if (indio_dev->available_scan_masks)
@@ -638,19 +655,25 @@ int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data,
}
EXPORT_SYMBOL_GPL(iio_push_to_buffer);
+static void iio_buffer_demux_free(struct iio_buffer *buffer)
+{
+ struct iio_demux_table *p, *q;
+ list_for_each_entry_safe(p, q, &buffer->demux_list, l) {
+ list_del(&p->l);
+ kfree(p);
+ }
+}
+
int iio_update_demux(struct iio_dev *indio_dev)
{
const struct iio_chan_spec *ch;
struct iio_buffer *buffer = indio_dev->buffer;
int ret, in_ind = -1, out_ind, length;
unsigned in_loc = 0, out_loc = 0;
- struct iio_demux_table *p, *q;
+ struct iio_demux_table *p;
/* Clear out any old demux */
- list_for_each_entry_safe(p, q, &buffer->demux_list, l) {
- list_del(&p->l);
- kfree(p);
- }
+ iio_buffer_demux_free(buffer);
kfree(buffer->demux_bounce);
buffer->demux_bounce = NULL;
@@ -704,7 +727,7 @@ int iio_update_demux(struct iio_dev *indio_dev)
goto error_clear_mux_table;
}
ch = iio_find_channel_from_si(indio_dev,
- buffer->scan_index_timestamp);
+ indio_dev->scan_index_timestamp);
length = ch->scan_type.storagebits/8;
if (out_loc % length)
out_loc += length - out_loc % length;
@@ -725,10 +748,8 @@ int iio_update_demux(struct iio_dev *indio_dev)
return 0;
error_clear_mux_table:
- list_for_each_entry_safe(p, q, &buffer->demux_list, l) {
- list_del(&p->l);
- kfree(p);
- }
+ iio_buffer_demux_free(buffer);
+
return ret;
}
EXPORT_SYMBOL_GPL(iio_update_demux);
diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index d303bfbff27f..1ddd8861c71b 100644
--- a/drivers/staging/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -23,11 +23,11 @@
#include <linux/slab.h>
#include <linux/anon_inodes.h>
#include <linux/debugfs.h>
-#include "iio.h"
+#include <linux/iio/iio.h>
#include "iio_core.h"
#include "iio_core_trigger.h"
-#include "sysfs.h"
-#include "events.h"
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
/* IDA to assign each registered device a unique id*/
static DEFINE_IDA(iio_ida);
@@ -42,11 +42,6 @@ EXPORT_SYMBOL(iio_bus_type);
static struct dentry *iio_debugfs_dentry;
-static const char * const iio_data_type_name[] = {
- [IIO_RAW] = "raw",
- [IIO_PROCESSED] = "input",
-};
-
static const char * const iio_direction[] = {
[0] = "in",
[1] = "out",
@@ -68,6 +63,7 @@ static const char * const iio_chan_type_name_spec[] = {
[IIO_ANGL] = "angl",
[IIO_TIMESTAMP] = "timestamp",
[IIO_CAPACITANCE] = "capacitance",
+ [IIO_ALTVOLTAGE] = "altvoltage",
};
static const char * const iio_modifier_names[] = {
@@ -80,6 +76,8 @@ static const char * const iio_modifier_names[] = {
/* relies on pairs of these shared then separate */
static const char * const iio_chan_info_postfix[] = {
+ [IIO_CHAN_INFO_RAW] = "raw",
+ [IIO_CHAN_INFO_PROCESSED] = "input",
[IIO_CHAN_INFO_SCALE] = "scale",
[IIO_CHAN_INFO_OFFSET] = "offset",
[IIO_CHAN_INFO_CALIBSCALE] = "calibscale",
@@ -90,6 +88,10 @@ static const char * const iio_chan_info_postfix[] = {
[IIO_CHAN_INFO_AVERAGE_RAW] = "mean_raw",
[IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY]
= "filter_low_pass_3db_frequency",
+ [IIO_CHAN_INFO_SAMP_FREQ] = "sampling_frequency",
+ [IIO_CHAN_INFO_FREQUENCY] = "frequency",
+ [IIO_CHAN_INFO_PHASE] = "phase",
+ [IIO_CHAN_INFO_HARDWAREGAIN] = "hardwaregain",
};
const struct iio_chan_spec
@@ -151,14 +153,6 @@ static void __exit iio_exit(void)
}
#if defined(CONFIG_DEBUG_FS)
-static int iio_debugfs_open(struct inode *inode, struct file *file)
-{
- if (inode->i_private)
- file->private_data = inode->i_private;
-
- return 0;
-}
-
static ssize_t iio_debugfs_read_reg(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
@@ -217,7 +211,7 @@ static ssize_t iio_debugfs_write_reg(struct file *file,
}
static const struct file_operations iio_debugfs_reg_fops = {
- .open = iio_debugfs_open,
+ .open = simple_open,
.read = iio_debugfs_read_reg,
.write = iio_debugfs_write_reg,
};
@@ -234,15 +228,12 @@ static int iio_device_register_debugfs(struct iio_dev *indio_dev)
if (indio_dev->info->debugfs_reg_access == NULL)
return 0;
- if (IS_ERR(iio_debugfs_dentry))
+ if (!iio_debugfs_dentry)
return 0;
indio_dev->debugfs_dentry =
debugfs_create_dir(dev_name(&indio_dev->dev),
iio_debugfs_dentry);
- if (IS_ERR(indio_dev->debugfs_dentry))
- return PTR_ERR(indio_dev->debugfs_dentry);
-
if (indio_dev->debugfs_dentry == NULL) {
dev_warn(indio_dev->dev.parent,
"Failed to create debugfs directory\n");
@@ -274,13 +265,13 @@ static ssize_t iio_read_channel_ext_info(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
const struct iio_chan_spec_ext_info *ext_info;
ext_info = &this_attr->c->ext_info[this_attr->address];
- return ext_info->read(indio_dev, this_attr->c, buf);
+ return ext_info->read(indio_dev, ext_info->private, this_attr->c, buf);
}
static ssize_t iio_write_channel_ext_info(struct device *dev,
@@ -288,42 +279,50 @@ static ssize_t iio_write_channel_ext_info(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
const struct iio_chan_spec_ext_info *ext_info;
ext_info = &this_attr->c->ext_info[this_attr->address];
- return ext_info->write(indio_dev, this_attr->c, buf, len);
+ return ext_info->write(indio_dev, ext_info->private,
+ this_attr->c, buf, len);
}
static ssize_t iio_read_channel_info(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int val, val2;
+ bool scale_db = false;
int ret = indio_dev->info->read_raw(indio_dev, this_attr->c,
&val, &val2, this_attr->address);
if (ret < 0)
return ret;
- if (ret == IIO_VAL_INT)
+ switch (ret) {
+ case IIO_VAL_INT:
return sprintf(buf, "%d\n", val);
- else if (ret == IIO_VAL_INT_PLUS_MICRO) {
+ case IIO_VAL_INT_PLUS_MICRO_DB:
+ scale_db = true;
+ case IIO_VAL_INT_PLUS_MICRO:
if (val2 < 0)
- return sprintf(buf, "-%d.%06u\n", val, -val2);
+ return sprintf(buf, "-%d.%06u%s\n", val, -val2,
+ scale_db ? " dB" : "");
else
- return sprintf(buf, "%d.%06u\n", val, val2);
- } else if (ret == IIO_VAL_INT_PLUS_NANO) {
+ return sprintf(buf, "%d.%06u%s\n", val, val2,
+ scale_db ? " dB" : "");
+ case IIO_VAL_INT_PLUS_NANO:
if (val2 < 0)
return sprintf(buf, "-%d.%09u\n", val, -val2);
else
return sprintf(buf, "%d.%09u\n", val, val2);
- } else
+ default:
return 0;
+ }
}
static ssize_t iio_write_channel_info(struct device *dev,
@@ -331,7 +330,7 @@ static ssize_t iio_write_channel_info(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret, integer = 0, fract = 0, fract_mult = 100000;
bool integer_part = true, negative = false;
@@ -575,25 +574,12 @@ error_ret:
static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan)
{
- int ret, i, attrcount = 0;
+ int ret, attrcount = 0;
+ int i;
const struct iio_chan_spec_ext_info *ext_info;
if (chan->channel < 0)
return 0;
-
- ret = __iio_add_chan_devattr(iio_data_type_name[chan->processed_val],
- chan,
- &iio_read_channel_info,
- (chan->output ?
- &iio_write_channel_info : NULL),
- 0,
- 0,
- &indio_dev->dev,
- &indio_dev->channel_attr_list);
- if (ret)
- goto error_ret;
- attrcount++;
-
for_each_set_bit(i, &chan->info_mask, sizeof(long)*8) {
ret = __iio_add_chan_devattr(iio_chan_info_postfix[i/2],
chan,
@@ -652,7 +638,7 @@ static ssize_t iio_show_dev_name(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
return sprintf(buf, "%s\n", indio_dev->name);
}
@@ -738,7 +724,7 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
static void iio_dev_release(struct device *device)
{
- struct iio_dev *indio_dev = container_of(device, struct iio_dev, dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(device);
cdev_del(&indio_dev->chrdev);
if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
iio_device_unregister_trigger_consumer(indio_dev);
@@ -752,7 +738,7 @@ static struct device_type iio_dev_type = {
.release = iio_dev_release,
};
-struct iio_dev *iio_allocate_device(int sizeof_priv)
+struct iio_dev *iio_device_alloc(int sizeof_priv)
{
struct iio_dev *dev;
size_t alloc_size;
@@ -788,16 +774,16 @@ struct iio_dev *iio_allocate_device(int sizeof_priv)
return dev;
}
-EXPORT_SYMBOL(iio_allocate_device);
+EXPORT_SYMBOL(iio_device_alloc);
-void iio_free_device(struct iio_dev *dev)
+void iio_device_free(struct iio_dev *dev)
{
if (dev) {
ida_simple_remove(&iio_ida, dev->id);
kfree(dev);
}
}
-EXPORT_SYMBOL(iio_free_device);
+EXPORT_SYMBOL(iio_device_free);
/**
* iio_chrdev_open() - chrdev file open for buffer access and ioctls
diff --git a/drivers/staging/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
index 5fdf739e38f9..b49059de5d02 100644
--- a/drivers/staging/iio/industrialio-event.c
+++ b/drivers/iio/industrialio-event.c
@@ -20,10 +20,10 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/wait.h>
-#include "iio.h"
+#include <linux/iio/iio.h>
#include "iio_core.h"
-#include "sysfs.h"
-#include "events.h"
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
/**
* struct iio_event_interface - chrdev interface for an event line
@@ -186,7 +186,7 @@ static ssize_t iio_ev_state_store(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
bool val;
@@ -205,7 +205,7 @@ static ssize_t iio_ev_state_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int val = indio_dev->info->read_event_config(indio_dev,
this_attr->address);
@@ -220,7 +220,7 @@ static ssize_t iio_ev_value_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int val, ret;
@@ -237,7 +237,7 @@ static ssize_t iio_ev_value_store(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
unsigned long val;
int ret;
diff --git a/drivers/staging/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c
index 47ecadd4818d..0f582df75a19 100644
--- a/drivers/staging/iio/industrialio-trigger.c
+++ b/drivers/iio/industrialio-trigger.c
@@ -15,11 +15,11 @@
#include <linux/list.h>
#include <linux/slab.h>
-#include "iio.h"
-#include "trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
#include "iio_core.h"
#include "iio_core_trigger.h"
-#include "trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
/* RFC - Question of approach
* Make the common case (single sensor single trigger)
@@ -310,7 +310,7 @@ static ssize_t iio_trigger_read_current(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
if (indio_dev->trig)
return sprintf(buf, "%s\n", indio_dev->trig->name);
@@ -329,7 +329,7 @@ static ssize_t iio_trigger_write_current(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_trigger *oldtrig = indio_dev->trig;
struct iio_trigger *trig;
int ret;
@@ -360,9 +360,9 @@ static ssize_t iio_trigger_write_current(struct device *dev,
indio_dev->trig = trig;
if (oldtrig && indio_dev->trig != oldtrig)
- iio_put_trigger(oldtrig);
+ iio_trigger_put(oldtrig);
if (indio_dev->trig)
- iio_get_trigger(indio_dev->trig);
+ iio_trigger_get(indio_dev->trig);
return len;
}
@@ -426,7 +426,7 @@ static void iio_trig_subirqunmask(struct irq_data *d)
trig->subirqs[d->irq - trig->subirq_base].enabled = true;
}
-struct iio_trigger *iio_allocate_trigger(const char *fmt, ...)
+struct iio_trigger *iio_trigger_alloc(const char *fmt, ...)
{
va_list vargs;
struct iio_trigger *trig;
@@ -472,14 +472,14 @@ struct iio_trigger *iio_allocate_trigger(const char *fmt, ...)
}
return trig;
}
-EXPORT_SYMBOL(iio_allocate_trigger);
+EXPORT_SYMBOL(iio_trigger_alloc);
-void iio_free_trigger(struct iio_trigger *trig)
+void iio_trigger_free(struct iio_trigger *trig)
{
if (trig)
put_device(&trig->dev);
}
-EXPORT_SYMBOL(iio_free_trigger);
+EXPORT_SYMBOL(iio_trigger_free);
void iio_device_register_trigger_consumer(struct iio_dev *indio_dev)
{
@@ -491,7 +491,7 @@ void iio_device_unregister_trigger_consumer(struct iio_dev *indio_dev)
{
/* Clean up and associated but not attached triggers references */
if (indio_dev->trig)
- iio_put_trigger(indio_dev->trig);
+ iio_trigger_put(indio_dev->trig);
}
int iio_triggered_buffer_postenable(struct iio_dev *indio_dev)
diff --git a/drivers/staging/iio/inkern.c b/drivers/iio/inkern.c
index ef07a02bf542..922645893dc8 100644
--- a/drivers/staging/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -11,11 +11,11 @@
#include <linux/slab.h>
#include <linux/mutex.h>
-#include "iio.h"
+#include <linux/iio/iio.h>
#include "iio_core.h"
-#include "machine.h"
-#include "driver.h"
-#include "consumer.h"
+#include <linux/iio/machine.h>
+#include <linux/iio/driver.h>
+#include <linux/iio/consumer.h>
struct iio_map_internal {
struct iio_dev *indio_dev;
diff --git a/drivers/staging/iio/kfifo_buf.c b/drivers/iio/kfifo_buf.c
index 9f3bd59c0e72..6bf9d05f4841 100644
--- a/drivers/staging/iio/kfifo_buf.c
+++ b/drivers/iio/kfifo_buf.c
@@ -5,8 +5,7 @@
#include <linux/workqueue.h>
#include <linux/kfifo.h>
#include <linux/mutex.h>
-
-#include "kfifo_buf.h"
+#include <linux/iio/kfifo_buf.h>
struct iio_kfifo {
struct iio_buffer buffer;
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 332597980817..55f7e57d4e42 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -25,10 +25,6 @@ config INPUT
if INPUT
-config INPUT_OF_MATRIX_KEYMAP
- depends on USE_OF
- bool
-
config INPUT_FF_MEMLESS
tristate "Support for memoryless force-feedback devices"
help
@@ -68,6 +64,19 @@ config INPUT_SPARSEKMAP
To compile this driver as a module, choose M here: the
module will be called sparse-keymap.
+config INPUT_MATRIXKMAP
+ tristate "Matrix keymap support library"
+ help
+ Say Y here if you are using a driver for an input
+ device that uses matrix keymap. This option is only
+ useful for out-of-tree drivers since in-tree drivers
+ select it automatically.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called matrix-keymap.
+
comment "Userland interfaces"
config INPUT_MOUSEDEV
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index b173a13a73ca..5ca3f631497f 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -10,6 +10,7 @@ input-core-y := input.o input-compat.o input-mt.o ff-core.o
obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o
obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o
obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o
+obj-$(CONFIG_INPUT_MATRIXKMAP) += matrix-keymap.o
obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
@@ -24,4 +25,3 @@ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/
obj-$(CONFIG_INPUT_MISC) += misc/
obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o
-obj-$(CONFIG_INPUT_OF_MATRIX_KEYMAP) += of_keymap.o
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 4b2e10d5d641..6c58bfff01a3 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -180,7 +180,10 @@ static int evdev_grab(struct evdev *evdev, struct evdev_client *client)
static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client)
{
- if (evdev->grab != client)
+ struct evdev_client *grab = rcu_dereference_protected(evdev->grab,
+ lockdep_is_held(&evdev->mutex));
+
+ if (grab != client)
return -EINVAL;
rcu_assign_pointer(evdev->grab, NULL);
@@ -259,8 +262,7 @@ static int evdev_release(struct inode *inode, struct file *file)
struct evdev *evdev = client->evdev;
mutex_lock(&evdev->mutex);
- if (evdev->grab == client)
- evdev_ungrab(evdev, client);
+ evdev_ungrab(evdev, client);
mutex_unlock(&evdev->mutex);
evdev_detach_client(evdev, client);
@@ -343,7 +345,7 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer,
struct input_event event;
int retval = 0;
- if (count < input_event_size())
+ if (count != 0 && count < input_event_size())
return -EINVAL;
retval = mutex_lock_interruptible(&evdev->mutex);
@@ -355,7 +357,8 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer,
goto out;
}
- do {
+ while (retval + input_event_size() <= count) {
+
if (input_event_from_user(buffer + retval, &event)) {
retval = -EFAULT;
goto out;
@@ -364,7 +367,7 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer,
input_inject_event(&evdev->handle,
event.type, event.code, event.value);
- } while (retval + input_event_size() <= count);
+ }
out:
mutex_unlock(&evdev->mutex);
@@ -395,35 +398,49 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,
struct evdev_client *client = file->private_data;
struct evdev *evdev = client->evdev;
struct input_event event;
- int retval = 0;
+ size_t read = 0;
+ int error;
- if (count < input_event_size())
+ if (count != 0 && count < input_event_size())
return -EINVAL;
- if (!(file->f_flags & O_NONBLOCK)) {
- retval = wait_event_interruptible(evdev->wait,
- client->packet_head != client->tail ||
- !evdev->exist);
- if (retval)
- return retval;
- }
+ for (;;) {
+ if (!evdev->exist)
+ return -ENODEV;
- if (!evdev->exist)
- return -ENODEV;
+ if (client->packet_head == client->tail &&
+ (file->f_flags & O_NONBLOCK))
+ return -EAGAIN;
- while (retval + input_event_size() <= count &&
- evdev_fetch_next_event(client, &event)) {
+ /*
+ * count == 0 is special - no IO is done but we check
+ * for error conditions (see above).
+ */
+ if (count == 0)
+ break;
- if (input_event_to_user(buffer + retval, &event))
- return -EFAULT;
+ while (read + input_event_size() <= count &&
+ evdev_fetch_next_event(client, &event)) {
- retval += input_event_size();
- }
+ if (input_event_to_user(buffer + read, &event))
+ return -EFAULT;
- if (retval == 0 && (file->f_flags & O_NONBLOCK))
- return -EAGAIN;
+ read += input_event_size();
+ }
- return retval;
+ if (read)
+ break;
+
+ if (!(file->f_flags & O_NONBLOCK)) {
+ error = wait_event_interruptible(evdev->wait,
+ client->packet_head != client->tail ||
+ !evdev->exist);
+ if (error)
+ return error;
+ }
+ }
+
+ return read;
}
/* No kernel lock - fine */
diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c
index 117a59aaa70e..5f558851d646 100644
--- a/drivers/input/ff-memless.c
+++ b/drivers/input/ff-memless.c
@@ -31,8 +31,7 @@
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/jiffies.h>
-
-#include "fixp-arith.h"
+#include <linux/fixp-arith.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Anssi Hannula <anssi.hannula@gmail.com>");
diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c
index 422aa0a6b77f..daceafe7ee7d 100644
--- a/drivers/input/gameport/emu10k1-gp.c
+++ b/drivers/input/gameport/emu10k1-gp.c
@@ -125,15 +125,4 @@ static struct pci_driver emu_driver = {
.remove = __devexit_p(emu_remove),
};
-static int __init emu_init(void)
-{
- return pci_register_driver(&emu_driver);
-}
-
-static void __exit emu_exit(void)
-{
- pci_unregister_driver(&emu_driver);
-}
-
-module_init(emu_init);
-module_exit(emu_exit);
+module_pci_driver(emu_driver);
diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c
index a3b70ff21018..48ad3829ff20 100644
--- a/drivers/input/gameport/fm801-gp.c
+++ b/drivers/input/gameport/fm801-gp.c
@@ -144,6 +144,7 @@ static const struct pci_device_id fm801_gp_id_table[] = {
{ PCI_VENDOR_ID_FORTEMEDIA, PCI_DEVICE_ID_FM801_GP, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0 }
};
+MODULE_DEVICE_TABLE(pci, fm801_gp_id_table);
static struct pci_driver fm801_gp_driver = {
.name = "FM801_gameport",
@@ -152,20 +153,7 @@ static struct pci_driver fm801_gp_driver = {
.remove = __devexit_p(fm801_gp_remove),
};
-static int __init fm801_gp_init(void)
-{
- return pci_register_driver(&fm801_gp_driver);
-}
-
-static void __exit fm801_gp_exit(void)
-{
- pci_unregister_driver(&fm801_gp_driver);
-}
-
-module_init(fm801_gp_init);
-module_exit(fm801_gp_exit);
-
-MODULE_DEVICE_TABLE(pci, fm801_gp_id_table);
+module_pci_driver(fm801_gp_driver);
MODULE_DESCRIPTION("FM801 gameport driver");
MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c
index 1639ab2b94b7..85bc8dc07cfc 100644
--- a/drivers/input/joystick/a3d.c
+++ b/drivers/input/joystick/a3d.c
@@ -413,15 +413,4 @@ static struct gameport_driver a3d_drv = {
.disconnect = a3d_disconnect,
};
-static int __init a3d_init(void)
-{
- return gameport_register_driver(&a3d_drv);
-}
-
-static void __exit a3d_exit(void)
-{
- gameport_unregister_driver(&a3d_drv);
-}
-
-module_init(a3d_init);
-module_exit(a3d_exit);
+module_gameport_driver(a3d_drv);
diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
index b992fbf91f2f..0cbfd2dfabf4 100644
--- a/drivers/input/joystick/adi.c
+++ b/drivers/input/joystick/adi.c
@@ -557,10 +557,6 @@ static void adi_disconnect(struct gameport *gameport)
kfree(port);
}
-/*
- * The gameport device structure.
- */
-
static struct gameport_driver adi_drv = {
.driver = {
.name = "adi",
@@ -570,15 +566,4 @@ static struct gameport_driver adi_drv = {
.disconnect = adi_disconnect,
};
-static int __init adi_init(void)
-{
- return gameport_register_driver(&adi_drv);
-}
-
-static void __exit adi_exit(void)
-{
- gameport_unregister_driver(&adi_drv);
-}
-
-module_init(adi_init);
-module_exit(adi_exit);
+module_gameport_driver(adi_drv);
diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c
index 3497b87c3d05..65367e44d715 100644
--- a/drivers/input/joystick/cobra.c
+++ b/drivers/input/joystick/cobra.c
@@ -261,15 +261,4 @@ static struct gameport_driver cobra_drv = {
.disconnect = cobra_disconnect,
};
-static int __init cobra_init(void)
-{
- return gameport_register_driver(&cobra_drv);
-}
-
-static void __exit cobra_exit(void)
-{
- gameport_unregister_driver(&cobra_drv);
-}
-
-module_init(cobra_init);
-module_exit(cobra_exit);
+module_gameport_driver(cobra_drv);
diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
index 0536b1b2f018..ab1cf2882004 100644
--- a/drivers/input/joystick/gf2k.c
+++ b/drivers/input/joystick/gf2k.c
@@ -373,15 +373,4 @@ static struct gameport_driver gf2k_drv = {
.disconnect = gf2k_disconnect,
};
-static int __init gf2k_init(void)
-{
- return gameport_register_driver(&gf2k_drv);
-}
-
-static void __exit gf2k_exit(void)
-{
- gameport_unregister_driver(&gf2k_drv);
-}
-
-module_init(gf2k_init);
-module_exit(gf2k_exit);
+module_gameport_driver(gf2k_drv);
diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c
index fc55899ba6c5..9e1beff57c33 100644
--- a/drivers/input/joystick/grip.c
+++ b/drivers/input/joystick/grip.c
@@ -424,15 +424,4 @@ static struct gameport_driver grip_drv = {
.disconnect = grip_disconnect,
};
-static int __init grip_init(void)
-{
- return gameport_register_driver(&grip_drv);
-}
-
-static void __exit grip_exit(void)
-{
- gameport_unregister_driver(&grip_drv);
-}
-
-module_init(grip_init);
-module_exit(grip_exit);
+module_gameport_driver(grip_drv);
diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c
index 2d47baf47769..c0f9c7b7eb4e 100644
--- a/drivers/input/joystick/grip_mp.c
+++ b/drivers/input/joystick/grip_mp.c
@@ -687,15 +687,4 @@ static struct gameport_driver grip_drv = {
.disconnect = grip_disconnect,
};
-static int __init grip_init(void)
-{
- return gameport_register_driver(&grip_drv);
-}
-
-static void __exit grip_exit(void)
-{
- gameport_unregister_driver(&grip_drv);
-}
-
-module_init(grip_init);
-module_exit(grip_exit);
+module_gameport_driver(grip_drv);
diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c
index 4058d4b272fe..55196f730af6 100644
--- a/drivers/input/joystick/guillemot.c
+++ b/drivers/input/joystick/guillemot.c
@@ -281,15 +281,4 @@ static struct gameport_driver guillemot_drv = {
.disconnect = guillemot_disconnect,
};
-static int __init guillemot_init(void)
-{
- return gameport_register_driver(&guillemot_drv);
-}
-
-static void __exit guillemot_exit(void)
-{
- gameport_unregister_driver(&guillemot_drv);
-}
-
-module_init(guillemot_init);
-module_exit(guillemot_exit);
+module_gameport_driver(guillemot_drv);
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
index 405febd94f24..daeeb4c7e3b0 100644
--- a/drivers/input/joystick/iforce/iforce-main.c
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -317,7 +317,8 @@ int iforce_init_device(struct iforce *iforce)
break;
if (i == 20) { /* 5 seconds */
- err("Timeout waiting for response from device.");
+ dev_err(&input_dev->dev,
+ "Timeout waiting for response from device.\n");
error = -ENODEV;
goto fail;
}
diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c
index a17b50016009..08f98f2eaf88 100644
--- a/drivers/input/joystick/iforce/iforce-packets.c
+++ b/drivers/input/joystick/iforce/iforce-packets.c
@@ -257,7 +257,8 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet)
status = usb_submit_urb(iforce->ctrl, GFP_ATOMIC);
if (status) {
- err("usb_submit_urb failed %d", status);
+ dev_err(&iforce->intf->dev,
+ "usb_submit_urb failed %d\n", status);
return -1;
}
@@ -265,12 +266,14 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet)
iforce->ctrl->status != -EINPROGRESS, HZ);
if (iforce->ctrl->status) {
- dbg("iforce->ctrl->status = %d", iforce->ctrl->status);
+ dev_dbg(&iforce->intf->dev,
+ "iforce->ctrl->status = %d\n",
+ iforce->ctrl->status);
usb_unlink_urb(iforce->ctrl);
return -1;
}
#else
- dbg("iforce_get_id_packet: iforce->bus = USB!");
+ printk(KERN_DEBUG "iforce_get_id_packet: iforce->bus = USB!\n");
#endif
}
break;
@@ -289,12 +292,15 @@ int iforce_get_id_packet(struct iforce *iforce, char *packet)
return -1;
}
#else
- err("iforce_get_id_packet: iforce->bus = SERIO!");
+ dev_err(&iforce->dev->dev,
+ "iforce_get_id_packet: iforce->bus = SERIO!\n");
#endif
break;
default:
- err("iforce_get_id_packet: iforce->bus = %d", iforce->bus);
+ dev_err(&iforce->dev->dev,
+ "iforce_get_id_packet: iforce->bus = %d\n",
+ iforce->bus);
break;
}
diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
index 6c96631ae5d9..d96aa27dfcdc 100644
--- a/drivers/input/joystick/iforce/iforce-usb.c
+++ b/drivers/input/joystick/iforce/iforce-usb.c
@@ -64,7 +64,7 @@ void iforce_usb_xmit(struct iforce *iforce)
if ( (n=usb_submit_urb(iforce->out, GFP_ATOMIC)) ) {
clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
- dev_warn(&iforce->dev->dev, "usb_submit_urb failed %d\n", n);
+ dev_warn(&iforce->intf->dev, "usb_submit_urb failed %d\n", n);
}
/* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended.
@@ -76,6 +76,7 @@ void iforce_usb_xmit(struct iforce *iforce)
static void iforce_usb_irq(struct urb *urb)
{
struct iforce *iforce = urb->context;
+ struct device *dev = &iforce->intf->dev;
int status;
switch (urb->status) {
@@ -86,11 +87,12 @@ static void iforce_usb_irq(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __func__, urb->status);
+ dev_dbg(dev, "%s - urb shutting down with status: %d\n",
+ __func__, urb->status);
return;
default:
- dbg("%s - urb has status of: %d", __func__, urb->status);
+ dev_dbg(dev, "%s - urb has status of: %d\n",
+ __func__, urb->status);
goto exit;
}
@@ -100,8 +102,8 @@ static void iforce_usb_irq(struct urb *urb)
exit:
status = usb_submit_urb (urb, GFP_ATOMIC);
if (status)
- err ("%s - usb_submit_urb failed with result %d",
- __func__, status);
+ dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
+ __func__, status);
}
static void iforce_usb_out(struct urb *urb)
@@ -110,7 +112,8 @@ static void iforce_usb_out(struct urb *urb)
if (urb->status) {
clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
- dbg("urb->status %d, exiting", urb->status);
+ dev_dbg(&iforce->intf->dev, "urb->status %d, exiting\n",
+ urb->status);
return;
}
@@ -155,6 +158,7 @@ static int iforce_usb_probe(struct usb_interface *intf,
iforce->bus = IFORCE_USB;
iforce->usbdev = dev;
+ iforce->intf = intf;
iforce->cr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE;
iforce->cr.wIndex = 0;
diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h
index 9f494b75848a..b1d7d9b0eb86 100644
--- a/drivers/input/joystick/iforce/iforce.h
+++ b/drivers/input/joystick/iforce/iforce.h
@@ -115,6 +115,7 @@ struct iforce {
#endif
#ifdef CONFIG_JOYSTICK_IFORCE_USB
struct usb_device *usbdev; /* USB transfer */
+ struct usb_interface *intf;
struct urb *irq, *out, *ctrl;
struct usb_ctrlrequest cr;
#endif
diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c
index 16fb19d1ca25..88c22623a2e8 100644
--- a/drivers/input/joystick/interact.c
+++ b/drivers/input/joystick/interact.c
@@ -311,15 +311,4 @@ static struct gameport_driver interact_drv = {
.disconnect = interact_disconnect,
};
-static int __init interact_init(void)
-{
- return gameport_register_driver(&interact_drv);
-}
-
-static void __exit interact_exit(void)
-{
- gameport_unregister_driver(&interact_drv);
-}
-
-module_init(interact_init);
-module_exit(interact_exit);
+module_gameport_driver(interact_drv);
diff --git a/drivers/input/joystick/joydump.c b/drivers/input/joystick/joydump.c
index cd894a0564a2..7eb878bab968 100644
--- a/drivers/input/joystick/joydump.c
+++ b/drivers/input/joystick/joydump.c
@@ -159,15 +159,4 @@ static struct gameport_driver joydump_drv = {
.disconnect = joydump_disconnect,
};
-static int __init joydump_init(void)
-{
- return gameport_register_driver(&joydump_drv);
-}
-
-static void __exit joydump_exit(void)
-{
- gameport_unregister_driver(&joydump_drv);
-}
-
-module_init(joydump_init);
-module_exit(joydump_exit);
+module_gameport_driver(joydump_drv);
diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c
index 40e40780747d..9fb153eef2fc 100644
--- a/drivers/input/joystick/magellan.c
+++ b/drivers/input/joystick/magellan.c
@@ -222,19 +222,4 @@ static struct serio_driver magellan_drv = {
.disconnect = magellan_disconnect,
};
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init magellan_init(void)
-{
- return serio_register_driver(&magellan_drv);
-}
-
-static void __exit magellan_exit(void)
-{
- serio_unregister_driver(&magellan_drv);
-}
-
-module_init(magellan_init);
-module_exit(magellan_exit);
+module_serio_driver(magellan_drv);
diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c
index b8d86115644b..04c69af37148 100644
--- a/drivers/input/joystick/sidewinder.c
+++ b/drivers/input/joystick/sidewinder.c
@@ -820,15 +820,4 @@ static struct gameport_driver sw_drv = {
.disconnect = sw_disconnect,
};
-static int __init sw_init(void)
-{
- return gameport_register_driver(&sw_drv);
-}
-
-static void __exit sw_exit(void)
-{
- gameport_unregister_driver(&sw_drv);
-}
-
-module_init(sw_init);
-module_exit(sw_exit);
+module_gameport_driver(sw_drv);
diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
index 0cd9b29356a8..80a7b27a457a 100644
--- a/drivers/input/joystick/spaceball.c
+++ b/drivers/input/joystick/spaceball.c
@@ -296,19 +296,4 @@ static struct serio_driver spaceball_drv = {
.disconnect = spaceball_disconnect,
};
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init spaceball_init(void)
-{
- return serio_register_driver(&spaceball_drv);
-}
-
-static void __exit spaceball_exit(void)
-{
- serio_unregister_driver(&spaceball_drv);
-}
-
-module_init(spaceball_init);
-module_exit(spaceball_exit);
+module_serio_driver(spaceball_drv);
diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c
index a694bf8e557b..a41f291652e6 100644
--- a/drivers/input/joystick/spaceorb.c
+++ b/drivers/input/joystick/spaceorb.c
@@ -237,19 +237,4 @@ static struct serio_driver spaceorb_drv = {
.disconnect = spaceorb_disconnect,
};
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init spaceorb_init(void)
-{
- return serio_register_driver(&spaceorb_drv);
-}
-
-static void __exit spaceorb_exit(void)
-{
- serio_unregister_driver(&spaceorb_drv);
-}
-
-module_init(spaceorb_init);
-module_exit(spaceorb_exit);
+module_serio_driver(spaceorb_drv);
diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c
index e0db9f5e4b41..0f51a60e14a7 100644
--- a/drivers/input/joystick/stinger.c
+++ b/drivers/input/joystick/stinger.c
@@ -208,19 +208,4 @@ static struct serio_driver stinger_drv = {
.disconnect = stinger_disconnect,
};
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init stinger_init(void)
-{
- return serio_register_driver(&stinger_drv);
-}
-
-static void __exit stinger_exit(void)
-{
- serio_unregister_driver(&stinger_drv);
-}
-
-module_init(stinger_init);
-module_exit(stinger_exit);
+module_serio_driver(stinger_drv);
diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c
index d6c609807115..5ef9bcdb0345 100644
--- a/drivers/input/joystick/tmdc.c
+++ b/drivers/input/joystick/tmdc.c
@@ -436,15 +436,4 @@ static struct gameport_driver tmdc_drv = {
.disconnect = tmdc_disconnect,
};
-static int __init tmdc_init(void)
-{
- return gameport_register_driver(&tmdc_drv);
-}
-
-static void __exit tmdc_exit(void)
-{
- gameport_unregister_driver(&tmdc_drv);
-}
-
-module_init(tmdc_init);
-module_exit(tmdc_exit);
+module_gameport_driver(tmdc_drv);
diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c
index 3f4ec73c9553..2556a8193579 100644
--- a/drivers/input/joystick/twidjoy.c
+++ b/drivers/input/joystick/twidjoy.c
@@ -257,19 +257,4 @@ static struct serio_driver twidjoy_drv = {
.disconnect = twidjoy_disconnect,
};
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init twidjoy_init(void)
-{
- return serio_register_driver(&twidjoy_drv);
-}
-
-static void __exit twidjoy_exit(void)
-{
- serio_unregister_driver(&twidjoy_drv);
-}
-
-module_init(twidjoy_init);
-module_exit(twidjoy_exit);
+module_serio_driver(twidjoy_drv);
diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c
index f72c83e15e60..23b3071abb6e 100644
--- a/drivers/input/joystick/warrior.c
+++ b/drivers/input/joystick/warrior.c
@@ -217,19 +217,4 @@ static struct serio_driver warrior_drv = {
.disconnect = warrior_disconnect,
};
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init warrior_init(void)
-{
- return serio_register_driver(&warrior_drv);
-}
-
-static void __exit warrior_exit(void)
-{
- serio_unregister_driver(&warrior_drv);
-}
-
-module_init(warrior_init);
-module_exit(warrior_exit);
+module_serio_driver(warrior_drv);
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index fd7a0d5bc94d..ee16fb67b7ae 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -252,6 +252,7 @@ MODULE_DEVICE_TABLE (usb, xpad_table);
struct usb_xpad {
struct input_dev *dev; /* input device interface */
struct usb_device *udev; /* usb device */
+ struct usb_interface *intf; /* usb interface */
int pad_present;
@@ -457,6 +458,7 @@ static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned cha
static void xpad_irq_in(struct urb *urb)
{
struct usb_xpad *xpad = urb->context;
+ struct device *dev = &xpad->intf->dev;
int retval, status;
status = urb->status;
@@ -469,11 +471,11 @@ static void xpad_irq_in(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
+ dev_dbg(dev, "%s - urb shutting down with status: %d\n",
__func__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d",
+ dev_dbg(dev, "%s - nonzero urb status received: %d\n",
__func__, status);
goto exit;
}
@@ -492,12 +494,15 @@ static void xpad_irq_in(struct urb *urb)
exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
- err ("%s - usb_submit_urb failed with result %d",
- __func__, retval);
+ dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
+ __func__, retval);
}
static void xpad_bulk_out(struct urb *urb)
{
+ struct usb_xpad *xpad = urb->context;
+ struct device *dev = &xpad->intf->dev;
+
switch (urb->status) {
case 0:
/* success */
@@ -506,16 +511,20 @@ static void xpad_bulk_out(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __func__, urb->status);
+ dev_dbg(dev, "%s - urb shutting down with status: %d\n",
+ __func__, urb->status);
break;
default:
- dbg("%s - nonzero urb status received: %d", __func__, urb->status);
+ dev_dbg(dev, "%s - nonzero urb status received: %d\n",
+ __func__, urb->status);
}
}
#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
static void xpad_irq_out(struct urb *urb)
{
+ struct usb_xpad *xpad = urb->context;
+ struct device *dev = &xpad->intf->dev;
int retval, status;
status = urb->status;
@@ -529,19 +538,21 @@ static void xpad_irq_out(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __func__, status);
+ dev_dbg(dev, "%s - urb shutting down with status: %d\n",
+ __func__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __func__, status);
+ dev_dbg(dev, "%s - nonzero urb status received: %d\n",
+ __func__, status);
goto exit;
}
exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
- err("%s - usb_submit_urb failed with result %d",
- __func__, retval);
+ dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
+ __func__, retval);
}
static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
@@ -654,7 +665,8 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
return usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
default:
- dbg("%s - rumble command sent to unsupported xpad type: %d",
+ dev_dbg(&xpad->dev->dev,
+ "%s - rumble command sent to unsupported xpad type: %d\n",
__func__, xpad->xtype);
return -1;
}
@@ -844,6 +856,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
}
xpad->udev = udev;
+ xpad->intf = intf;
xpad->mapping = xpad_device[i].mapping;
xpad->xtype = xpad_device[i].xtype;
diff --git a/drivers/input/joystick/zhenhua.c b/drivers/input/joystick/zhenhua.c
index b5853125c898..c4de4388fd7f 100644
--- a/drivers/input/joystick/zhenhua.c
+++ b/drivers/input/joystick/zhenhua.c
@@ -225,19 +225,4 @@ static struct serio_driver zhenhua_drv = {
.disconnect = zhenhua_disconnect,
};
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init zhenhua_init(void)
-{
- return serio_register_driver(&zhenhua_drv);
-}
-
-static void __exit zhenhua_exit(void)
-{
- serio_unregister_driver(&zhenhua_drv);
-}
-
-module_init(zhenhua_init);
-module_exit(zhenhua_exit);
+module_serio_driver(zhenhua_drv);
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index f354813a13e8..c0e11ecc646f 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -166,6 +166,7 @@ config KEYBOARD_LKKBD
config KEYBOARD_EP93XX
tristate "EP93xx Matrix Keypad support"
depends on ARCH_EP93XX
+ select INPUT_MATRIXKMAP
help
Say Y here to enable the matrix keypad on the Cirrus EP93XX.
@@ -224,6 +225,7 @@ config KEYBOARD_TCA6416
config KEYBOARD_TCA8418
tristate "TCA8418 Keypad Support"
depends on I2C
+ select INPUT_MATRIXKMAP
help
This driver implements basic keypad functionality
for keys connected through TCA8418 keypad decoder.
@@ -240,6 +242,7 @@ config KEYBOARD_TCA8418
config KEYBOARD_MATRIX
tristate "GPIO driven matrix keypad support"
depends on GENERIC_GPIO
+ select INPUT_MATRIXKMAP
help
Enable support for GPIO driven matrix keypad.
@@ -309,6 +312,17 @@ config KEYBOARD_LM8323
To compile this driver as a module, choose M here: the
module will be called lm8323.
+config KEYBOARD_LM8333
+ tristate "LM8333 keypad chip"
+ depends on I2C
+ select INPUT_MATRIXKMAP
+ help
+ If you say yes here you get support for the National Semiconductor
+ LM8333 keypad controller.
+
+ To compile this driver as a module, choose M here: the
+ module will be called lm8333.
+
config KEYBOARD_LOCOMO
tristate "LoCoMo Keyboard Support"
depends on SHARP_LOCOMO
@@ -366,6 +380,7 @@ config KEYBOARD_MPR121
config KEYBOARD_IMX
tristate "IMX keypad support"
depends on ARCH_MXC
+ select INPUT_MATRIXKMAP
help
Enable support for IMX keypad port.
@@ -384,6 +399,7 @@ config KEYBOARD_NEWTON
config KEYBOARD_NOMADIK
tristate "ST-Ericsson Nomadik SKE keyboard"
depends on PLAT_NOMADIK
+ select INPUT_MATRIXKMAP
help
Say Y here if you want to use a keypad provided on the SKE controller
used on the Ux500 and Nomadik platforms
@@ -394,7 +410,7 @@ config KEYBOARD_NOMADIK
config KEYBOARD_TEGRA
tristate "NVIDIA Tegra internal matrix keyboard controller support"
depends on ARCH_TEGRA
- select INPUT_OF_MATRIX_KEYMAP if USE_OF
+ select INPUT_MATRIXKMAP
help
Say Y here if you want to use a matrix keyboard connected directly
to the internal keyboard controller on Tegra SoCs.
@@ -432,6 +448,7 @@ config KEYBOARD_PXA930_ROTARY
config KEYBOARD_PMIC8XXX
tristate "Qualcomm PMIC8XXX keypad support"
depends on MFD_PM8XXX
+ select INPUT_MATRIXKMAP
help
Say Y here if you want to enable the driver for the PMIC8XXX
keypad provided as a reference design from Qualcomm. This is intended
@@ -443,6 +460,7 @@ config KEYBOARD_PMIC8XXX
config KEYBOARD_SAMSUNG
tristate "Samsung keypad support"
depends on HAVE_CLK
+ select INPUT_MATRIXKMAP
help
Say Y here if you want to use the keypad on your Samsung mobile
device.
@@ -485,6 +503,7 @@ config KEYBOARD_SH_KEYSC
config KEYBOARD_STMPE
tristate "STMPE keypad support"
depends on MFD_STMPE
+ select INPUT_MATRIXKMAP
help
Say Y here if you want to use the keypad controller on STMPE I/O
expanders.
@@ -505,6 +524,7 @@ config KEYBOARD_DAVINCI
config KEYBOARD_OMAP
tristate "TI OMAP keypad support"
depends on (ARCH_OMAP1 || ARCH_OMAP2)
+ select INPUT_MATRIXKMAP
help
Say Y here if you want to use the OMAP keypad.
@@ -512,9 +532,10 @@ config KEYBOARD_OMAP
module will be called omap-keypad.
config KEYBOARD_OMAP4
- tristate "TI OMAP4 keypad support"
+ tristate "TI OMAP4+ keypad support"
+ select INPUT_MATRIXKMAP
help
- Say Y here if you want to use the OMAP4 keypad.
+ Say Y here if you want to use the OMAP4+ keypad.
To compile this driver as a module, choose M here: the
module will be called omap4-keypad.
@@ -522,6 +543,7 @@ config KEYBOARD_OMAP4
config KEYBOARD_SPEAR
tristate "ST SPEAR keyboard support"
depends on PLAT_SPEAR
+ select INPUT_MATRIXKMAP
help
Say Y here if you want to use the SPEAR keyboard.
@@ -531,6 +553,7 @@ config KEYBOARD_SPEAR
config KEYBOARD_TC3589X
tristate "TC3589X Keypad support"
depends on MFD_TC3589X
+ select INPUT_MATRIXKMAP
help
Say Y here if you want to use the keypad controller on
TC35892/3 I/O expander.
@@ -541,6 +564,7 @@ config KEYBOARD_TC3589X
config KEYBOARD_TNETV107X
tristate "TI TNETV107X keypad support"
depends on ARCH_DAVINCI_TNETV107X
+ select INPUT_MATRIXKMAP
help
Say Y here if you want to use the TNETV107X keypad.
@@ -550,6 +574,7 @@ config KEYBOARD_TNETV107X
config KEYBOARD_TWL4030
tristate "TI TWL4030/TWL5030/TPS659x0 keypad support"
depends on TWL4030_CORE
+ select INPUT_MATRIXKMAP
help
Say Y here if your board use the keypad controller on
TWL4030 family chips. It's safe to say enable this
@@ -573,6 +598,7 @@ config KEYBOARD_XTKBD
config KEYBOARD_W90P910
tristate "W90P910 Matrix Keypad support"
depends on ARCH_W90X900
+ select INPUT_MATRIXKMAP
help
Say Y here to enable the matrix keypad on evaluation board
based on W90P910.
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index df7061f12918..b03b02456a82 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o
obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o
obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o
obj-$(CONFIG_KEYBOARD_LM8323) += lm8323.o
+obj-$(CONFIG_KEYBOARD_LM8333) += lm8333.o
obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o
obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o
obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c
index 39ebffac207e..b083bf10f139 100644
--- a/drivers/input/keyboard/adp5588-keys.c
+++ b/drivers/input/keyboard/adp5588-keys.c
@@ -197,6 +197,7 @@ static int __devinit adp5588_gpio_add(struct adp5588_kpad *kpad)
kpad->gc.base = gpio_data->gpio_start;
kpad->gc.label = kpad->client->name;
kpad->gc.owner = THIS_MODULE;
+ kpad->gc.names = gpio_data->names;
mutex_init(&kpad->gpio_lock);
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index e05a2e7073c6..add5ffd9fe26 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -433,7 +433,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
if (printk_ratelimit())
dev_warn(&serio->dev,
"Spurious %s on %s. "
- "Some program might be trying access hardware directly.\n",
+ "Some program might be trying to access hardware directly.\n",
data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
goto out;
case ATKBD_RET_ERR:
diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c
index 0ba69f3fcb52..c46fc8185469 100644
--- a/drivers/input/keyboard/ep93xx_keypad.c
+++ b/drivers/input/keyboard/ep93xx_keypad.c
@@ -182,16 +182,10 @@ static void ep93xx_keypad_close(struct input_dev *pdev)
}
-#ifdef CONFIG_PM
-/*
- * NOTE: I don't know if this is correct, or will work on the ep93xx.
- *
- * None of the existing ep93xx drivers have power management support.
- * But, this is basically what the pxa27x_keypad driver does.
- */
-static int ep93xx_keypad_suspend(struct platform_device *pdev,
- pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int ep93xx_keypad_suspend(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
struct input_dev *input_dev = keypad->input_dev;
@@ -210,8 +204,9 @@ static int ep93xx_keypad_suspend(struct platform_device *pdev,
return 0;
}
-static int ep93xx_keypad_resume(struct platform_device *pdev)
+static int ep93xx_keypad_resume(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
struct input_dev *input_dev = keypad->input_dev;
@@ -232,10 +227,10 @@ static int ep93xx_keypad_resume(struct platform_device *pdev)
return 0;
}
-#else /* !CONFIG_PM */
-#define ep93xx_keypad_suspend NULL
-#define ep93xx_keypad_resume NULL
-#endif /* !CONFIG_PM */
+#endif
+
+static SIMPLE_DEV_PM_OPS(ep93xx_keypad_pm_ops,
+ ep93xx_keypad_suspend, ep93xx_keypad_resume);
static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
{
@@ -308,19 +303,16 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
input_dev->open = ep93xx_keypad_open;
input_dev->close = ep93xx_keypad_close;
input_dev->dev.parent = &pdev->dev;
- input_dev->keycode = keypad->keycodes;
- input_dev->keycodesize = sizeof(keypad->keycodes[0]);
- input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
- input_set_drvdata(input_dev, keypad);
+ err = matrix_keypad_build_keymap(keymap_data, NULL,
+ EP93XX_MATRIX_ROWS, EP93XX_MATRIX_COLS,
+ keypad->keycodes, input_dev);
+ if (err)
+ goto failed_free_dev;
- input_dev->evbit[0] = BIT_MASK(EV_KEY);
if (keypad->pdata->flags & EP93XX_KEYPAD_AUTOREPEAT)
- input_dev->evbit[0] |= BIT_MASK(EV_REP);
-
- matrix_keypad_build_keymap(keymap_data, 3,
- input_dev->keycode, input_dev->keybit);
- platform_set_drvdata(pdev, keypad);
+ __set_bit(EV_REP, input_dev->evbit);
+ input_set_drvdata(input_dev, keypad);
err = request_irq(keypad->irq, ep93xx_keypad_irq_handler,
0, pdev->name, keypad);
@@ -331,6 +323,7 @@ static int __devinit ep93xx_keypad_probe(struct platform_device *pdev)
if (err)
goto failed_free_irq;
+ platform_set_drvdata(pdev, keypad);
device_init_wakeup(&pdev->dev, 1);
return 0;
@@ -384,11 +377,10 @@ static struct platform_driver ep93xx_keypad_driver = {
.driver = {
.name = "ep93xx-keypad",
.owner = THIS_MODULE,
+ .pm = &ep93xx_keypad_pm_ops,
},
.probe = ep93xx_keypad_probe,
.remove = __devexit_p(ep93xx_keypad_remove),
- .suspend = ep93xx_keypad_suspend,
- .resume = ep93xx_keypad_resume,
};
module_platform_driver(ep93xx_keypad_driver);
diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c
index fed31e0947a1..589e3c258f3f 100644
--- a/drivers/input/keyboard/hil_kbd.c
+++ b/drivers/input/keyboard/hil_kbd.c
@@ -583,15 +583,4 @@ static struct serio_driver hil_serio_drv = {
.interrupt = hil_dev_interrupt
};
-static int __init hil_dev_init(void)
-{
- return serio_register_driver(&hil_serio_drv);
-}
-
-static void __exit hil_dev_exit(void)
-{
- serio_unregister_driver(&hil_serio_drv);
-}
-
-module_init(hil_dev_init);
-module_exit(hil_dev_exit);
+module_serio_driver(hil_serio_drv);
diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c
index fb87b3bcadb9..6ee7421e2321 100644
--- a/drivers/input/keyboard/imx_keypad.c
+++ b/drivers/input/keyboard/imx_keypad.c
@@ -481,7 +481,7 @@ static int __devinit imx_keypad_probe(struct platform_device *pdev)
}
if (keypad->rows_en_mask > ((1 << MAX_MATRIX_KEY_ROWS) - 1) ||
- keypad->cols_en_mask > ((1 << MAX_MATRIX_KEY_COLS) - 1)) {
+ keypad->cols_en_mask > ((1 << MAX_MATRIX_KEY_COLS) - 1)) {
dev_err(&pdev->dev,
"invalid key data (too many rows or colums)\n");
error = -EINVAL;
@@ -496,14 +496,17 @@ static int __devinit imx_keypad_probe(struct platform_device *pdev)
input_dev->dev.parent = &pdev->dev;
input_dev->open = imx_keypad_open;
input_dev->close = imx_keypad_close;
- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
- input_dev->keycode = keypad->keycodes;
- input_dev->keycodesize = sizeof(keypad->keycodes[0]);
- input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
- matrix_keypad_build_keymap(keymap_data, MATRIX_ROW_SHIFT,
- keypad->keycodes, input_dev->keybit);
+ error = matrix_keypad_build_keymap(keymap_data, NULL,
+ MAX_MATRIX_KEY_ROWS,
+ MAX_MATRIX_KEY_COLS,
+ keypad->keycodes, input_dev);
+ if (error) {
+ dev_err(&pdev->dev, "failed to build keymap\n");
+ goto failed_clock_put;
+ }
+ __set_bit(EV_REP, input_dev->evbit);
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
input_set_drvdata(input_dev, keypad);
diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c
index fa9bb6d235e2..fc0a63c2f278 100644
--- a/drivers/input/keyboard/lkkbd.c
+++ b/drivers/input/keyboard/lkkbd.c
@@ -731,19 +731,4 @@ static struct serio_driver lkkbd_drv = {
.interrupt = lkkbd_interrupt,
};
-/*
- * The functions for insering/removing us as a module.
- */
-static int __init lkkbd_init(void)
-{
- return serio_register_driver(&lkkbd_drv);
-}
-
-static void __exit lkkbd_exit(void)
-{
- serio_unregister_driver(&lkkbd_drv);
-}
-
-module_init(lkkbd_init);
-module_exit(lkkbd_exit);
-
+module_serio_driver(lkkbd_drv);
diff --git a/drivers/input/keyboard/lm8333.c b/drivers/input/keyboard/lm8333.c
new file mode 100644
index 000000000000..ca168a6679de
--- /dev/null
+++ b/drivers/input/keyboard/lm8333.c
@@ -0,0 +1,235 @@
+/*
+ * LM8333 keypad driver
+ * Copyright (C) 2012 Wolfram Sang, Pengutronix <w.sang@pengutronix.de>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/input/lm8333.h>
+
+#define LM8333_FIFO_READ 0x20
+#define LM8333_DEBOUNCE 0x22
+#define LM8333_READ_INT 0xD0
+#define LM8333_ACTIVE 0xE4
+#define LM8333_READ_ERROR 0xF0
+
+#define LM8333_KEYPAD_IRQ (1 << 0)
+#define LM8333_ERROR_IRQ (1 << 3)
+
+#define LM8333_ERROR_KEYOVR 0x04
+#define LM8333_ERROR_FIFOOVR 0x40
+
+#define LM8333_FIFO_TRANSFER_SIZE 16
+
+#define LM8333_NUM_ROWS 8
+#define LM8333_NUM_COLS 16
+#define LM8333_ROW_SHIFT 4
+
+struct lm8333 {
+ struct i2c_client *client;
+ struct input_dev *input;
+ unsigned short keycodes[LM8333_NUM_ROWS << LM8333_ROW_SHIFT];
+};
+
+/* The accessors try twice because the first access may be needed for wakeup */
+#define LM8333_READ_RETRIES 2
+
+int lm8333_read8(struct lm8333 *lm8333, u8 cmd)
+{
+ int retries = 0, ret;
+
+ do {
+ ret = i2c_smbus_read_byte_data(lm8333->client, cmd);
+ } while (ret < 0 && retries++ < LM8333_READ_RETRIES);
+
+ return ret;
+}
+
+int lm8333_write8(struct lm8333 *lm8333, u8 cmd, u8 val)
+{
+ int retries = 0, ret;
+
+ do {
+ ret = i2c_smbus_write_byte_data(lm8333->client, cmd, val);
+ } while (ret < 0 && retries++ < LM8333_READ_RETRIES);
+
+ return ret;
+}
+
+int lm8333_read_block(struct lm8333 *lm8333, u8 cmd, u8 len, u8 *buf)
+{
+ int retries = 0, ret;
+
+ do {
+ ret = i2c_smbus_read_i2c_block_data(lm8333->client,
+ cmd, len, buf);
+ } while (ret < 0 && retries++ < LM8333_READ_RETRIES);
+
+ return ret;
+}
+
+static void lm8333_key_handler(struct lm8333 *lm8333)
+{
+ struct input_dev *input = lm8333->input;
+ u8 keys[LM8333_FIFO_TRANSFER_SIZE];
+ u8 code, pressed;
+ int i, ret;
+
+ ret = lm8333_read_block(lm8333, LM8333_FIFO_READ,
+ LM8333_FIFO_TRANSFER_SIZE, keys);
+ if (ret != LM8333_FIFO_TRANSFER_SIZE) {
+ dev_err(&lm8333->client->dev,
+ "Error %d while reading FIFO\n", ret);
+ return;
+ }
+
+ for (i = 0; keys[i] && i < LM8333_FIFO_TRANSFER_SIZE; i++) {
+ pressed = keys[i] & 0x80;
+ code = keys[i] & 0x7f;
+
+ input_event(input, EV_MSC, MSC_SCAN, code);
+ input_report_key(input, lm8333->keycodes[code], pressed);
+ }
+
+ input_sync(input);
+}
+
+static irqreturn_t lm8333_irq_thread(int irq, void *data)
+{
+ struct lm8333 *lm8333 = data;
+ u8 status = lm8333_read8(lm8333, LM8333_READ_INT);
+
+ if (!status)
+ return IRQ_NONE;
+
+ if (status & LM8333_ERROR_IRQ) {
+ u8 err = lm8333_read8(lm8333, LM8333_READ_ERROR);
+
+ if (err & (LM8333_ERROR_KEYOVR | LM8333_ERROR_FIFOOVR)) {
+ u8 dummy[LM8333_FIFO_TRANSFER_SIZE];
+
+ lm8333_read_block(lm8333, LM8333_FIFO_READ,
+ LM8333_FIFO_TRANSFER_SIZE, dummy);
+ }
+ dev_err(&lm8333->client->dev, "Got error %02x\n", err);
+ }
+
+ if (status & LM8333_KEYPAD_IRQ)
+ lm8333_key_handler(lm8333);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit lm8333_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ const struct lm8333_platform_data *pdata = client->dev.platform_data;
+ struct lm8333 *lm8333;
+ struct input_dev *input;
+ int err, active_time;
+
+ if (!pdata)
+ return -EINVAL;
+
+ active_time = pdata->active_time ?: 500;
+ if (active_time / 3 <= pdata->debounce_time / 3) {
+ dev_err(&client->dev, "Active time not big enough!\n");
+ return -EINVAL;
+ }
+
+ lm8333 = kzalloc(sizeof(*lm8333), GFP_KERNEL);
+ input = input_allocate_device();
+ if (!lm8333 || !input) {
+ err = -ENOMEM;
+ goto free_mem;
+ }
+
+ lm8333->client = client;
+ lm8333->input = input;
+
+ input->name = client->name;
+ input->dev.parent = &client->dev;
+ input->id.bustype = BUS_I2C;
+
+ input_set_capability(input, EV_MSC, MSC_SCAN);
+
+ err = matrix_keypad_build_keymap(pdata->matrix_data, NULL,
+ LM8333_NUM_ROWS, LM8333_NUM_COLS,
+ lm8333->keycodes, input);
+ if (err)
+ goto free_mem;
+
+ if (pdata->debounce_time) {
+ err = lm8333_write8(lm8333, LM8333_DEBOUNCE,
+ pdata->debounce_time / 3);
+ if (err)
+ dev_warn(&client->dev, "Unable to set debounce time\n");
+ }
+
+ if (pdata->active_time) {
+ err = lm8333_write8(lm8333, LM8333_ACTIVE,
+ pdata->active_time / 3);
+ if (err)
+ dev_warn(&client->dev, "Unable to set active time\n");
+ }
+
+ err = request_threaded_irq(client->irq, NULL, lm8333_irq_thread,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "lm8333", lm8333);
+ if (err)
+ goto free_mem;
+
+ err = input_register_device(input);
+ if (err)
+ goto free_irq;
+
+ i2c_set_clientdata(client, lm8333);
+ return 0;
+
+ free_irq:
+ free_irq(client->irq, lm8333);
+ free_mem:
+ input_free_device(input);
+ kfree(lm8333);
+ return err;
+}
+
+static int __devexit lm8333_remove(struct i2c_client *client)
+{
+ struct lm8333 *lm8333 = i2c_get_clientdata(client);
+
+ free_irq(client->irq, lm8333);
+ input_unregister_device(lm8333->input);
+ kfree(lm8333);
+
+ return 0;
+}
+
+static const struct i2c_device_id lm8333_id[] = {
+ { "lm8333", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lm8333_id);
+
+static struct i2c_driver lm8333_driver = {
+ .driver = {
+ .name = "lm8333",
+ .owner = THIS_MODULE,
+ },
+ .probe = lm8333_probe,
+ .remove = __devexit_p(lm8333_remove),
+ .id_table = lm8333_id,
+};
+module_i2c_driver(lm8333_driver);
+
+MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_DESCRIPTION("LM8333 keyboard driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
index 9b223d73de32..18b72372028a 100644
--- a/drivers/input/keyboard/matrix_keypad.c
+++ b/drivers/input/keyboard/matrix_keypad.c
@@ -27,7 +27,6 @@
struct matrix_keypad {
const struct matrix_keypad_platform_data *pdata;
struct input_dev *input_dev;
- unsigned short *keycodes;
unsigned int row_shift;
DECLARE_BITMAP(disabled_gpios, MATRIX_MAX_ROWS);
@@ -38,6 +37,8 @@ struct matrix_keypad {
bool scan_pending;
bool stopped;
bool gpio_all_disabled;
+
+ unsigned short keycodes[];
};
/*
@@ -224,7 +225,7 @@ static void matrix_keypad_stop(struct input_dev *dev)
disable_row_irqs(keypad);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad)
{
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
@@ -293,16 +294,16 @@ static int matrix_keypad_resume(struct device *dev)
return 0;
}
-
-static const SIMPLE_DEV_PM_OPS(matrix_keypad_pm_ops,
- matrix_keypad_suspend, matrix_keypad_resume);
#endif
-static int __devinit init_matrix_gpio(struct platform_device *pdev,
- struct matrix_keypad *keypad)
+static SIMPLE_DEV_PM_OPS(matrix_keypad_pm_ops,
+ matrix_keypad_suspend, matrix_keypad_resume);
+
+static int __devinit matrix_keypad_init_gpio(struct platform_device *pdev,
+ struct matrix_keypad *keypad)
{
const struct matrix_keypad_platform_data *pdata = keypad->pdata;
- int i, err = -EINVAL;
+ int i, err;
/* initialized strobe lines as outputs, activated */
for (i = 0; i < pdata->num_col_gpios; i++) {
@@ -348,8 +349,7 @@ static int __devinit init_matrix_gpio(struct platform_device *pdev,
"matrix-keypad", keypad);
if (err) {
dev_err(&pdev->dev,
- "Unable to acquire interrupt "
- "for GPIO line %i\n",
+ "Unable to acquire interrupt for GPIO line %i\n",
pdata->row_gpios[i]);
goto err_free_irqs;
}
@@ -375,14 +375,33 @@ err_free_cols:
return err;
}
+static void matrix_keypad_free_gpio(struct matrix_keypad *keypad)
+{
+ const struct matrix_keypad_platform_data *pdata = keypad->pdata;
+ int i;
+
+ if (pdata->clustered_irq > 0) {
+ free_irq(pdata->clustered_irq, keypad);
+ } else {
+ for (i = 0; i < pdata->num_row_gpios; i++)
+ free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
+ }
+
+ for (i = 0; i < pdata->num_row_gpios; i++)
+ gpio_free(pdata->row_gpios[i]);
+
+ for (i = 0; i < pdata->num_col_gpios; i++)
+ gpio_free(pdata->col_gpios[i]);
+}
+
static int __devinit matrix_keypad_probe(struct platform_device *pdev)
{
const struct matrix_keypad_platform_data *pdata;
const struct matrix_keymap_data *keymap_data;
struct matrix_keypad *keypad;
struct input_dev *input_dev;
- unsigned short *keycodes;
unsigned int row_shift;
+ size_t keymap_size;
int err;
pdata = pdev->dev.platform_data;
@@ -398,20 +417,18 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev)
}
row_shift = get_count_order(pdata->num_col_gpios);
-
- keypad = kzalloc(sizeof(struct matrix_keypad), GFP_KERNEL);
- keycodes = kzalloc((pdata->num_row_gpios << row_shift) *
- sizeof(*keycodes),
- GFP_KERNEL);
+ keymap_size = (pdata->num_row_gpios << row_shift) *
+ sizeof(keypad->keycodes[0]);
+ keypad = kzalloc(sizeof(struct matrix_keypad) + keymap_size,
+ GFP_KERNEL);
input_dev = input_allocate_device();
- if (!keypad || !keycodes || !input_dev) {
+ if (!keypad || !input_dev) {
err = -ENOMEM;
goto err_free_mem;
}
keypad->input_dev = input_dev;
keypad->pdata = pdata;
- keypad->keycodes = keycodes;
keypad->row_shift = row_shift;
keypad->stopped = true;
INIT_DELAYED_WORK(&keypad->work, matrix_keypad_scan);
@@ -420,38 +437,38 @@ static int __devinit matrix_keypad_probe(struct platform_device *pdev)
input_dev->name = pdev->name;
input_dev->id.bustype = BUS_HOST;
input_dev->dev.parent = &pdev->dev;
- input_dev->evbit[0] = BIT_MASK(EV_KEY);
- if (!pdata->no_autorepeat)
- input_dev->evbit[0] |= BIT_MASK(EV_REP);
input_dev->open = matrix_keypad_start;
input_dev->close = matrix_keypad_stop;
- input_dev->keycode = keycodes;
- input_dev->keycodesize = sizeof(*keycodes);
- input_dev->keycodemax = pdata->num_row_gpios << row_shift;
-
- matrix_keypad_build_keymap(keymap_data, row_shift,
- input_dev->keycode, input_dev->keybit);
+ err = matrix_keypad_build_keymap(keymap_data, NULL,
+ pdata->num_row_gpios,
+ pdata->num_col_gpios,
+ keypad->keycodes, input_dev);
+ if (err)
+ goto err_free_mem;
+ if (!pdata->no_autorepeat)
+ __set_bit(EV_REP, input_dev->evbit);
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
input_set_drvdata(input_dev, keypad);
- err = init_matrix_gpio(pdev, keypad);
+ err = matrix_keypad_init_gpio(pdev, keypad);
if (err)
goto err_free_mem;
err = input_register_device(keypad->input_dev);
if (err)
- goto err_free_mem;
+ goto err_free_gpio;
device_init_wakeup(&pdev->dev, pdata->wakeup);
platform_set_drvdata(pdev, keypad);
return 0;
+err_free_gpio:
+ matrix_keypad_free_gpio(keypad);
err_free_mem:
input_free_device(input_dev);
- kfree(keycodes);
kfree(keypad);
return err;
}
@@ -459,29 +476,15 @@ err_free_mem:
static int __devexit matrix_keypad_remove(struct platform_device *pdev)
{
struct matrix_keypad *keypad = platform_get_drvdata(pdev);
- const struct matrix_keypad_platform_data *pdata = keypad->pdata;
- int i;
device_init_wakeup(&pdev->dev, 0);
- if (pdata->clustered_irq > 0) {
- free_irq(pdata->clustered_irq, keypad);
- } else {
- for (i = 0; i < pdata->num_row_gpios; i++)
- free_irq(gpio_to_irq(pdata->row_gpios[i]), keypad);
- }
-
- for (i = 0; i < pdata->num_row_gpios; i++)
- gpio_free(pdata->row_gpios[i]);
-
- for (i = 0; i < pdata->num_col_gpios; i++)
- gpio_free(pdata->col_gpios[i]);
-
+ matrix_keypad_free_gpio(keypad);
input_unregister_device(keypad->input_dev);
- platform_set_drvdata(pdev, NULL);
- kfree(keypad->keycodes);
kfree(keypad);
+ platform_set_drvdata(pdev, NULL);
+
return 0;
}
@@ -491,9 +494,7 @@ static struct platform_driver matrix_keypad_driver = {
.driver = {
.name = "matrix-keypad",
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
.pm = &matrix_keypad_pm_ops,
-#endif
},
};
module_platform_driver(matrix_keypad_driver);
diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c
index 48d1cab0aa1c..f971898ad591 100644
--- a/drivers/input/keyboard/newtonkbd.c
+++ b/drivers/input/keyboard/newtonkbd.c
@@ -166,15 +166,4 @@ static struct serio_driver nkbd_drv = {
.disconnect = nkbd_disconnect,
};
-static int __init nkbd_init(void)
-{
- return serio_register_driver(&nkbd_drv);
-}
-
-static void __exit nkbd_exit(void)
-{
- serio_unregister_driver(&nkbd_drv);
-}
-
-module_init(nkbd_init);
-module_exit(nkbd_exit);
+module_serio_driver(nkbd_drv);
diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c
index 101e245944e7..4ea4341a68c5 100644
--- a/drivers/input/keyboard/nomadik-ske-keypad.c
+++ b/drivers/input/keyboard/nomadik-ske-keypad.c
@@ -39,7 +39,8 @@
#define SKE_KPRISA (0x1 << 2)
#define SKE_KEYPAD_ROW_SHIFT 3
-#define SKE_KPD_KEYMAP_SIZE (8 * 8)
+#define SKE_KPD_NUM_ROWS 8
+#define SKE_KPD_NUM_COLS 8
/* keypad auto scan registers */
#define SKE_ASR0 0x20
@@ -63,7 +64,7 @@ struct ske_keypad {
void __iomem *reg_base;
struct input_dev *input;
const struct ske_keypad_platform_data *board;
- unsigned short keymap[SKE_KPD_KEYMAP_SIZE];
+ unsigned short keymap[SKE_KPD_NUM_ROWS * SKE_KPD_NUM_COLS];
struct clk *clk;
spinlock_t ske_keypad_lock;
};
@@ -261,19 +262,18 @@ static int __init ske_keypad_probe(struct platform_device *pdev)
input->name = "ux500-ske-keypad";
input->dev.parent = &pdev->dev;
- input->keycode = keypad->keymap;
- input->keycodesize = sizeof(keypad->keymap[0]);
- input->keycodemax = ARRAY_SIZE(keypad->keymap);
+ error = matrix_keypad_build_keymap(plat->keymap_data, NULL,
+ SKE_KPD_NUM_ROWS, SKE_KPD_NUM_COLS,
+ keypad->keymap, input);
+ if (error) {
+ dev_err(&pdev->dev, "Failed to build keymap\n");
+ goto err_iounmap;
+ }
input_set_capability(input, EV_MSC, MSC_SCAN);
-
- __set_bit(EV_KEY, input->evbit);
if (!plat->no_autorepeat)
__set_bit(EV_REP, input->evbit);
- matrix_keypad_build_keymap(plat->keymap_data, SKE_KEYPAD_ROW_SHIFT,
- input->keycode, input->keybit);
-
clk_enable(keypad->clk);
/* go through board initialization helpers */
diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c
index 6b630d9d3dff..a0222db4dc86 100644
--- a/drivers/input/keyboard/omap-keypad.c
+++ b/drivers/input/keyboard/omap-keypad.c
@@ -61,6 +61,7 @@ struct omap_kp {
unsigned int cols;
unsigned long delay;
unsigned int debounce;
+ unsigned short keymap[];
};
static DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0);
@@ -316,13 +317,6 @@ static int __devinit omap_kp_probe(struct platform_device *pdev)
if (!cpu_is_omap24xx())
omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
- input_dev->keycode = &omap_kp[1];
- input_dev->keycodesize = sizeof(unsigned short);
- input_dev->keycodemax = keycodemax;
-
- if (pdata->rep)
- __set_bit(EV_REP, input_dev->evbit);
-
if (pdata->delay)
omap_kp->delay = pdata->delay;
@@ -371,9 +365,6 @@ static int __devinit omap_kp_probe(struct platform_device *pdev)
goto err2;
/* setup input device */
- __set_bit(EV_KEY, input_dev->evbit);
- matrix_keypad_build_keymap(pdata->keymap_data, row_shift,
- input_dev->keycode, input_dev->keybit);
input_dev->name = "omap-keypad";
input_dev->phys = "omap-keypad/input0";
input_dev->dev.parent = &pdev->dev;
@@ -383,6 +374,15 @@ static int __devinit omap_kp_probe(struct platform_device *pdev)
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
+ if (pdata->rep)
+ __set_bit(EV_REP, input_dev->evbit);
+
+ ret = matrix_keypad_build_keymap(pdata->keymap_data, NULL,
+ pdata->rows, pdata->cols,
+ omap_kp->keymap, input_dev);
+ if (ret < 0)
+ goto err3;
+
ret = input_register_device(omap_kp->input);
if (ret < 0) {
printk(KERN_ERR "Unable to register omap-keypad input device\n");
diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c
index e809ac095a38..aed5f6999ce2 100644
--- a/drivers/input/keyboard/omap4-keypad.c
+++ b/drivers/input/keyboard/omap4-keypad.c
@@ -68,19 +68,52 @@
#define OMAP4_MASK_IRQSTATUSDISABLE 0xFFFF
+enum {
+ KBD_REVISION_OMAP4 = 0,
+ KBD_REVISION_OMAP5,
+};
+
struct omap4_keypad {
struct input_dev *input;
void __iomem *base;
- int irq;
+ unsigned int irq;
unsigned int rows;
unsigned int cols;
+ u32 reg_offset;
+ u32 irqreg_offset;
unsigned int row_shift;
unsigned char key_state[8];
unsigned short keymap[];
};
+static int kbd_readl(struct omap4_keypad *keypad_data, u32 offset)
+{
+ return __raw_readl(keypad_data->base +
+ keypad_data->reg_offset + offset);
+}
+
+static void kbd_writel(struct omap4_keypad *keypad_data, u32 offset, u32 value)
+{
+ __raw_writel(value,
+ keypad_data->base + keypad_data->reg_offset + offset);
+}
+
+static int kbd_read_irqreg(struct omap4_keypad *keypad_data, u32 offset)
+{
+ return __raw_readl(keypad_data->base +
+ keypad_data->irqreg_offset + offset);
+}
+
+static void kbd_write_irqreg(struct omap4_keypad *keypad_data,
+ u32 offset, u32 value)
+{
+ __raw_writel(value,
+ keypad_data->base + keypad_data->irqreg_offset + offset);
+}
+
+
/* Interrupt handler */
static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id)
{
@@ -91,12 +124,11 @@ static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id)
u32 *new_state = (u32 *) key_state;
/* Disable interrupts */
- __raw_writel(OMAP4_VAL_IRQDISABLE,
- keypad_data->base + OMAP4_KBD_IRQENABLE);
+ kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
+ OMAP4_VAL_IRQDISABLE);
- *new_state = __raw_readl(keypad_data->base + OMAP4_KBD_FULLCODE31_0);
- *(new_state + 1) = __raw_readl(keypad_data->base
- + OMAP4_KBD_FULLCODE63_32);
+ *new_state = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE31_0);
+ *(new_state + 1) = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE63_32);
for (row = 0; row < keypad_data->rows; row++) {
changed = key_state[row] ^ keypad_data->key_state[row];
@@ -121,12 +153,13 @@ static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id)
sizeof(keypad_data->key_state));
/* clear pending interrupts */
- __raw_writel(__raw_readl(keypad_data->base + OMAP4_KBD_IRQSTATUS),
- keypad_data->base + OMAP4_KBD_IRQSTATUS);
+ kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
+ kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS));
/* enable interrupts */
- __raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY,
- keypad_data->base + OMAP4_KBD_IRQENABLE);
+ kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
+ OMAP4_DEF_IRQENABLE_EVENTEN |
+ OMAP4_DEF_IRQENABLE_LONGKEY);
return IRQ_HANDLED;
}
@@ -139,16 +172,17 @@ static int omap4_keypad_open(struct input_dev *input)
disable_irq(keypad_data->irq);
- __raw_writel(OMAP4_VAL_FUNCTIONALCFG,
- keypad_data->base + OMAP4_KBD_CTRL);
- __raw_writel(OMAP4_VAL_DEBOUNCINGTIME,
- keypad_data->base + OMAP4_KBD_DEBOUNCINGTIME);
- __raw_writel(OMAP4_VAL_IRQDISABLE,
- keypad_data->base + OMAP4_KBD_IRQSTATUS);
- __raw_writel(OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_LONGKEY,
- keypad_data->base + OMAP4_KBD_IRQENABLE);
- __raw_writel(OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA,
- keypad_data->base + OMAP4_KBD_WAKEUPENABLE);
+ kbd_writel(keypad_data, OMAP4_KBD_CTRL,
+ OMAP4_VAL_FUNCTIONALCFG);
+ kbd_writel(keypad_data, OMAP4_KBD_DEBOUNCINGTIME,
+ OMAP4_VAL_DEBOUNCINGTIME);
+ kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
+ OMAP4_VAL_IRQDISABLE);
+ kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
+ OMAP4_DEF_IRQENABLE_EVENTEN |
+ OMAP4_DEF_IRQENABLE_LONGKEY);
+ kbd_writel(keypad_data, OMAP4_KBD_WAKEUPENABLE,
+ OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA);
enable_irq(keypad_data->irq);
@@ -162,12 +196,12 @@ static void omap4_keypad_close(struct input_dev *input)
disable_irq(keypad_data->irq);
/* Disable interrupts */
- __raw_writel(OMAP4_VAL_IRQDISABLE,
- keypad_data->base + OMAP4_KBD_IRQENABLE);
+ kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
+ OMAP4_VAL_IRQDISABLE);
/* clear pending interrupts */
- __raw_writel(__raw_readl(keypad_data->base + OMAP4_KBD_IRQSTATUS),
- keypad_data->base + OMAP4_KBD_IRQSTATUS);
+ kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
+ kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS));
enable_irq(keypad_data->irq);
@@ -182,6 +216,7 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)
struct resource *res;
resource_size_t size;
unsigned int row_shift, max_keys;
+ int rev;
int irq;
int error;
@@ -241,11 +276,40 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)
keypad_data->rows = pdata->rows;
keypad_data->cols = pdata->cols;
+ /*
+ * Enable clocks for the keypad module so that we can read
+ * revision register.
+ */
+ pm_runtime_enable(&pdev->dev);
+ error = pm_runtime_get_sync(&pdev->dev);
+ if (error) {
+ dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n");
+ goto err_unmap;
+ }
+ rev = __raw_readl(keypad_data->base + OMAP4_KBD_REVISION);
+ rev &= 0x03 << 30;
+ rev >>= 30;
+ switch (rev) {
+ case KBD_REVISION_OMAP4:
+ keypad_data->reg_offset = 0x00;
+ keypad_data->irqreg_offset = 0x00;
+ break;
+ case KBD_REVISION_OMAP5:
+ keypad_data->reg_offset = 0x10;
+ keypad_data->irqreg_offset = 0x0c;
+ break;
+ default:
+ dev_err(&pdev->dev,
+ "Keypad reports unsupported revision %d", rev);
+ error = -EINVAL;
+ goto err_pm_put_sync;
+ }
+
/* input device allocation */
keypad_data->input = input_dev = input_allocate_device();
if (!input_dev) {
error = -ENOMEM;
- goto err_unmap;
+ goto err_pm_put_sync;
}
input_dev->name = pdev->name;
@@ -258,20 +322,19 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)
input_dev->open = omap4_keypad_open;
input_dev->close = omap4_keypad_close;
- input_dev->keycode = keypad_data->keymap;
- input_dev->keycodesize = sizeof(keypad_data->keymap[0]);
- input_dev->keycodemax = max_keys;
+ error = matrix_keypad_build_keymap(pdata->keymap_data, NULL,
+ pdata->rows, pdata->cols,
+ keypad_data->keymap, input_dev);
+ if (error) {
+ dev_err(&pdev->dev, "failed to build keymap\n");
+ goto err_free_input;
+ }
- __set_bit(EV_KEY, input_dev->evbit);
__set_bit(EV_REP, input_dev->evbit);
-
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
input_set_drvdata(input_dev, keypad_data);
- matrix_keypad_build_keymap(pdata->keymap_data, row_shift,
- input_dev->keycode, input_dev->keybit);
-
error = request_irq(keypad_data->irq, omap4_keypad_interrupt,
IRQF_TRIGGER_RISING,
"omap4-keypad", keypad_data);
@@ -280,7 +343,7 @@ static int __devinit omap4_keypad_probe(struct platform_device *pdev)
goto err_free_input;
}
- pm_runtime_enable(&pdev->dev);
+ pm_runtime_put_sync(&pdev->dev);
error = input_register_device(keypad_data->input);
if (error < 0) {
@@ -296,6 +359,8 @@ err_pm_disable:
free_irq(keypad_data->irq, keypad_data);
err_free_input:
input_free_device(input_dev);
+err_pm_put_sync:
+ pm_runtime_put_sync(&pdev->dev);
err_unmap:
iounmap(keypad_data->base);
err_release_mem:
diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c
index 01a1c9f8a383..52c34657d301 100644
--- a/drivers/input/keyboard/pmic8xxx-keypad.c
+++ b/drivers/input/keyboard/pmic8xxx-keypad.c
@@ -626,21 +626,21 @@ static int __devinit pmic8xxx_kp_probe(struct platform_device *pdev)
kp->input->id.product = 0x0001;
kp->input->id.vendor = 0x0001;
- kp->input->evbit[0] = BIT_MASK(EV_KEY);
-
- if (pdata->rep)
- __set_bit(EV_REP, kp->input->evbit);
-
- kp->input->keycode = kp->keycodes;
- kp->input->keycodemax = PM8XXX_MATRIX_MAX_SIZE;
- kp->input->keycodesize = sizeof(kp->keycodes);
kp->input->open = pmic8xxx_kp_open;
kp->input->close = pmic8xxx_kp_close;
- matrix_keypad_build_keymap(keymap_data, PM8XXX_ROW_SHIFT,
- kp->input->keycode, kp->input->keybit);
+ rc = matrix_keypad_build_keymap(keymap_data, NULL,
+ PM8XXX_MAX_ROWS, PM8XXX_MAX_COLS,
+ kp->keycodes, kp->input);
+ if (rc) {
+ dev_err(&pdev->dev, "failed to build keymap\n");
+ goto err_get_irq;
+ }
+ if (pdata->rep)
+ __set_bit(EV_REP, kp->input->evbit);
input_set_capability(kp->input, EV_MSC, MSC_SCAN);
+
input_set_drvdata(kp->input, kp);
/* initialize keypad state */
diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c
index 2391ae884fee..a061ba603a29 100644
--- a/drivers/input/keyboard/samsung-keypad.c
+++ b/drivers/input/keyboard/samsung-keypad.c
@@ -454,23 +454,23 @@ static int __devinit samsung_keypad_probe(struct platform_device *pdev)
input_dev->name = pdev->name;
input_dev->id.bustype = BUS_HOST;
input_dev->dev.parent = &pdev->dev;
- input_set_drvdata(input_dev, keypad);
input_dev->open = samsung_keypad_open;
input_dev->close = samsung_keypad_close;
- input_dev->evbit[0] = BIT_MASK(EV_KEY);
- if (!pdata->no_autorepeat)
- input_dev->evbit[0] |= BIT_MASK(EV_REP);
+ error = matrix_keypad_build_keymap(keymap_data, NULL,
+ pdata->rows, pdata->cols,
+ keypad->keycodes, input_dev);
+ if (error) {
+ dev_err(&pdev->dev, "failed to build keymap\n");
+ goto err_put_clk;
+ }
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+ if (!pdata->no_autorepeat)
+ __set_bit(EV_REP, input_dev->evbit);
- input_dev->keycode = keypad->keycodes;
- input_dev->keycodesize = sizeof(keypad->keycodes[0]);
- input_dev->keycodemax = pdata->rows << row_shift;
-
- matrix_keypad_build_keymap(keymap_data, row_shift,
- input_dev->keycode, input_dev->keybit);
+ input_set_drvdata(input_dev, keypad);
keypad->irq = platform_get_irq(pdev, 0);
if (keypad->irq < 0) {
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
index 3b6b528f02fd..6f287f7e1538 100644
--- a/drivers/input/keyboard/spear-keyboard.c
+++ b/drivers/input/keyboard/spear-keyboard.c
@@ -19,6 +19,7 @@
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_wakeup.h>
#include <linux/slab.h>
@@ -49,7 +50,9 @@
#define KEY_VALUE 0x00FFFFFF
#define ROW_MASK 0xF0
#define COLUMN_MASK 0x0F
-#define ROW_SHIFT 4
+#define NUM_ROWS 16
+#define NUM_COLS 16
+
#define KEY_MATRIX_SHIFT 6
struct spear_kbd {
@@ -60,7 +63,8 @@ struct spear_kbd {
unsigned int irq;
unsigned int mode;
unsigned short last_key;
- unsigned short keycodes[256];
+ unsigned short keycodes[NUM_ROWS * NUM_COLS];
+ bool rep;
};
static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id)
@@ -136,27 +140,49 @@ static void spear_kbd_close(struct input_dev *dev)
kbd->last_key = KEY_RESERVED;
}
-static int __devinit spear_kbd_probe(struct platform_device *pdev)
+#ifdef CONFIG_OF
+static int __devinit spear_kbd_parse_dt(struct platform_device *pdev,
+ struct spear_kbd *kbd)
{
- const struct kbd_platform_data *pdata = pdev->dev.platform_data;
- const struct matrix_keymap_data *keymap;
- struct spear_kbd *kbd;
- struct input_dev *input_dev;
- struct resource *res;
- int irq;
+ struct device_node *np = pdev->dev.of_node;
int error;
+ u32 val;
- if (!pdata) {
- dev_err(&pdev->dev, "Invalid platform data\n");
+ if (!np) {
+ dev_err(&pdev->dev, "Missing DT data\n");
return -EINVAL;
}
- keymap = pdata->keymap;
- if (!keymap) {
- dev_err(&pdev->dev, "no keymap defined\n");
- return -EINVAL;
+ if (of_property_read_bool(np, "autorepeat"))
+ kbd->rep = true;
+
+ error = of_property_read_u32(np, "st,mode", &val);
+ if (error) {
+ dev_err(&pdev->dev, "DT: Invalid or missing mode\n");
+ return error;
}
+ kbd->mode = val;
+ return 0;
+}
+#else
+static inline int spear_kbd_parse_dt(struct platform_device *pdev,
+ struct spear_kbd *kbd)
+{
+ return -ENOSYS;
+}
+#endif
+
+static int __devinit spear_kbd_probe(struct platform_device *pdev)
+{
+ struct kbd_platform_data *pdata = dev_get_platdata(&pdev->dev);
+ const struct matrix_keymap_data *keymap = pdata ? pdata->keymap : NULL;
+ struct spear_kbd *kbd;
+ struct input_dev *input_dev;
+ struct resource *res;
+ int irq;
+ int error;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "no keyboard resource defined\n");
@@ -179,7 +205,15 @@ static int __devinit spear_kbd_probe(struct platform_device *pdev)
kbd->input = input_dev;
kbd->irq = irq;
- kbd->mode = pdata->mode;
+
+ if (!pdata) {
+ error = spear_kbd_parse_dt(pdev, kbd);
+ if (error)
+ goto err_free_mem;
+ } else {
+ kbd->mode = pdata->mode;
+ kbd->rep = pdata->rep;
+ }
kbd->res = request_mem_region(res->start, resource_size(res),
pdev->name);
@@ -212,18 +246,17 @@ static int __devinit spear_kbd_probe(struct platform_device *pdev)
input_dev->open = spear_kbd_open;
input_dev->close = spear_kbd_close;
- __set_bit(EV_KEY, input_dev->evbit);
- if (pdata->rep)
+ error = matrix_keypad_build_keymap(keymap, NULL, NUM_ROWS, NUM_COLS,
+ kbd->keycodes, input_dev);
+ if (error) {
+ dev_err(&pdev->dev, "Failed to build keymap\n");
+ goto err_put_clk;
+ }
+
+ if (kbd->rep)
__set_bit(EV_REP, input_dev->evbit);
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
- input_dev->keycode = kbd->keycodes;
- input_dev->keycodesize = sizeof(kbd->keycodes[0]);
- input_dev->keycodemax = ARRAY_SIZE(kbd->keycodes);
-
- matrix_keypad_build_keymap(keymap, ROW_SHIFT,
- input_dev->keycode, input_dev->keybit);
-
input_set_drvdata(input_dev, kbd);
error = request_irq(irq, spear_kbd_interrupt, 0, "keyboard", kbd);
@@ -317,6 +350,14 @@ static int spear_kbd_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(spear_kbd_pm_ops, spear_kbd_suspend, spear_kbd_resume);
+#ifdef CONFIG_OF
+static const struct of_device_id spear_kbd_id_table[] = {
+ { .compatible = "st,spear300-kbd" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, spear_kbd_id_table);
+#endif
+
static struct platform_driver spear_kbd_driver = {
.probe = spear_kbd_probe,
.remove = __devexit_p(spear_kbd_remove),
@@ -324,6 +365,7 @@ static struct platform_driver spear_kbd_driver = {
.name = "keyboard",
.owner = THIS_MODULE,
.pm = &spear_kbd_pm_ops,
+ .of_match_table = of_match_ptr(spear_kbd_id_table),
},
};
module_platform_driver(spear_kbd_driver);
diff --git a/drivers/input/keyboard/stmpe-keypad.c b/drivers/input/keyboard/stmpe-keypad.c
index 9397cf9c625c..470a8778dec1 100644
--- a/drivers/input/keyboard/stmpe-keypad.c
+++ b/drivers/input/keyboard/stmpe-keypad.c
@@ -289,19 +289,17 @@ static int __devinit stmpe_keypad_probe(struct platform_device *pdev)
input->id.bustype = BUS_I2C;
input->dev.parent = &pdev->dev;
- input_set_capability(input, EV_MSC, MSC_SCAN);
+ ret = matrix_keypad_build_keymap(plat->keymap_data, NULL,
+ STMPE_KEYPAD_MAX_ROWS,
+ STMPE_KEYPAD_MAX_COLS,
+ keypad->keymap, input);
+ if (ret)
+ goto out_freeinput;
- __set_bit(EV_KEY, input->evbit);
+ input_set_capability(input, EV_MSC, MSC_SCAN);
if (!plat->no_autorepeat)
__set_bit(EV_REP, input->evbit);
- input->keycode = keypad->keymap;
- input->keycodesize = sizeof(keypad->keymap[0]);
- input->keycodemax = ARRAY_SIZE(keypad->keymap);
-
- matrix_keypad_build_keymap(plat->keymap_data, STMPE_KEYPAD_ROW_SHIFT,
- input->keycode, input->keybit);
-
for (i = 0; i < plat->keymap_data->keymap_size; i++) {
unsigned int key = plat->keymap_data->keymap[i];
diff --git a/drivers/input/keyboard/stowaway.c b/drivers/input/keyboard/stowaway.c
index 7437219370b1..cc612c5d5427 100644
--- a/drivers/input/keyboard/stowaway.c
+++ b/drivers/input/keyboard/stowaway.c
@@ -170,15 +170,4 @@ static struct serio_driver skbd_drv = {
.disconnect = skbd_disconnect,
};
-static int __init skbd_init(void)
-{
- return serio_register_driver(&skbd_drv);
-}
-
-static void __exit skbd_exit(void)
-{
- serio_unregister_driver(&skbd_drv);
-}
-
-module_init(skbd_init);
-module_exit(skbd_exit);
+module_serio_driver(skbd_drv);
diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c
index a99a04b03ee4..5f836b1638c1 100644
--- a/drivers/input/keyboard/sunkbd.c
+++ b/drivers/input/keyboard/sunkbd.c
@@ -369,19 +369,4 @@ static struct serio_driver sunkbd_drv = {
.disconnect = sunkbd_disconnect,
};
-/*
- * The functions for insering/removing us as a module.
- */
-
-static int __init sunkbd_init(void)
-{
- return serio_register_driver(&sunkbd_drv);
-}
-
-static void __exit sunkbd_exit(void)
-{
- serio_unregister_driver(&sunkbd_drv);
-}
-
-module_init(sunkbd_init);
-module_exit(sunkbd_exit);
+module_serio_driver(sunkbd_drv);
diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c
index 2dee3e4e7c6f..7d498e698508 100644
--- a/drivers/input/keyboard/tc3589x-keypad.c
+++ b/drivers/input/keyboard/tc3589x-keypad.c
@@ -78,7 +78,7 @@
* @input: pointer to input device object
* @board: keypad platform device
* @krow: number of rows
- * @kcol: number of coloumns
+ * @kcol: number of columns
* @keymap: matrix scan code table for keycodes
* @keypad_stopped: holds keypad status
*/
@@ -96,21 +96,15 @@ static int tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad)
{
int ret;
struct tc3589x *tc3589x = keypad->tc3589x;
- u8 settle_time = keypad->board->settle_time;
- u8 dbounce_period = keypad->board->debounce_period;
- u8 rows = keypad->board->krow & 0xf; /* mask out the nibble */
- u8 column = keypad->board->kcol & 0xf; /* mask out the nibble */
-
- /* validate platform configurations */
- if (keypad->board->kcol > TC3589x_MAX_KPCOL ||
- keypad->board->krow > TC3589x_MAX_KPROW ||
- keypad->board->debounce_period > TC3589x_MAX_DEBOUNCE_SETTLE ||
- keypad->board->settle_time > TC3589x_MAX_DEBOUNCE_SETTLE)
+ const struct tc3589x_keypad_platform_data *board = keypad->board;
+
+ /* validate platform configuration */
+ if (board->kcol > TC3589x_MAX_KPCOL || board->krow > TC3589x_MAX_KPROW)
return -EINVAL;
/* configure KBDSIZE 4 LSbits for cols and 4 MSbits for rows */
ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSIZE,
- (rows << KP_ROW_SHIFT) | column);
+ (board->krow << KP_ROW_SHIFT) | board->kcol);
if (ret < 0)
return ret;
@@ -124,12 +118,14 @@ static int tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad)
return ret;
/* Configure settle time */
- ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSETTLE_REG, settle_time);
+ ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSETTLE_REG,
+ board->settle_time);
if (ret < 0)
return ret;
/* Configure debounce time */
- ret = tc3589x_reg_write(tc3589x, TC3589x_KBDBOUNCE, dbounce_period);
+ ret = tc3589x_reg_write(tc3589x, TC3589x_KBDBOUNCE,
+ board->debounce_period);
if (ret < 0)
return ret;
@@ -337,23 +333,22 @@ static int __devinit tc3589x_keypad_probe(struct platform_device *pdev)
input->name = pdev->name;
input->dev.parent = &pdev->dev;
- input->keycode = keypad->keymap;
- input->keycodesize = sizeof(keypad->keymap[0]);
- input->keycodemax = ARRAY_SIZE(keypad->keymap);
-
input->open = tc3589x_keypad_open;
input->close = tc3589x_keypad_close;
- input_set_drvdata(input, keypad);
+ error = matrix_keypad_build_keymap(plat->keymap_data, NULL,
+ TC3589x_MAX_KPROW, TC3589x_MAX_KPCOL,
+ keypad->keymap, input);
+ if (error) {
+ dev_err(&pdev->dev, "Failed to build keymap\n");
+ goto err_free_mem;
+ }
input_set_capability(input, EV_MSC, MSC_SCAN);
-
- __set_bit(EV_KEY, input->evbit);
if (!plat->no_autorepeat)
__set_bit(EV_REP, input->evbit);
- matrix_keypad_build_keymap(plat->keymap_data, 0x3,
- input->keycode, input->keybit);
+ input_set_drvdata(input, keypad);
error = request_threaded_irq(irq, NULL,
tc3589x_keypad_irq, plat->irqtype,
diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c
index 958ec107bfbc..5f87b28b3192 100644
--- a/drivers/input/keyboard/tca8418_keypad.c
+++ b/drivers/input/keyboard/tca8418_keypad.c
@@ -342,21 +342,20 @@ static int __devinit tca8418_keypad_probe(struct i2c_client *client,
input->id.product = 0x001;
input->id.version = 0x0001;
- input->keycode = keypad_data->keymap;
- input->keycodesize = sizeof(keypad_data->keymap[0]);
- input->keycodemax = max_keys;
+ error = matrix_keypad_build_keymap(pdata->keymap_data, NULL,
+ pdata->rows, pdata->cols,
+ keypad_data->keymap, input);
+ if (error) {
+ dev_dbg(&client->dev, "Failed to build keymap\n");
+ goto fail2;
+ }
- __set_bit(EV_KEY, input->evbit);
if (pdata->rep)
__set_bit(EV_REP, input->evbit);
-
input_set_capability(input, EV_MSC, MSC_SCAN);
input_set_drvdata(input, keypad_data);
- matrix_keypad_build_keymap(pdata->keymap_data, row_shift,
- input->keycode, input->keybit);
-
if (pdata->irq_is_gpio)
client->irq = gpio_to_irq(client->irq);
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c
index fe4ac95ca6c8..4ffe64d53107 100644
--- a/drivers/input/keyboard/tegra-kbc.c
+++ b/drivers/input/keyboard/tegra-kbc.c
@@ -619,8 +619,8 @@ tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata,
}
#ifdef CONFIG_OF
-static struct tegra_kbc_platform_data * __devinit
-tegra_kbc_dt_parse_pdata(struct platform_device *pdev)
+static struct tegra_kbc_platform_data * __devinit tegra_kbc_dt_parse_pdata(
+ struct platform_device *pdev)
{
struct tegra_kbc_platform_data *pdata;
struct device_node *np = pdev->dev.of_node;
@@ -660,10 +660,6 @@ tegra_kbc_dt_parse_pdata(struct platform_device *pdev)
pdata->pin_cfg[KBC_MAX_ROW + i].type = PIN_CFG_COL;
}
- pdata->keymap_data = matrix_keyboard_of_fill_keymap(np, "linux,keymap");
-
- /* FIXME: Add handling of linux,fn-keymap here */
-
return pdata;
}
#else
@@ -674,10 +670,36 @@ static inline struct tegra_kbc_platform_data *tegra_kbc_dt_parse_pdata(
}
#endif
+static int __devinit tegra_kbd_setup_keymap(struct tegra_kbc *kbc)
+{
+ const struct tegra_kbc_platform_data *pdata = kbc->pdata;
+ const struct matrix_keymap_data *keymap_data = pdata->keymap_data;
+ unsigned int keymap_rows = KBC_MAX_KEY;
+ int retval;
+
+ if (keymap_data && pdata->use_fn_map)
+ keymap_rows *= 2;
+
+ retval = matrix_keypad_build_keymap(keymap_data, NULL,
+ keymap_rows, KBC_MAX_COL,
+ kbc->keycode, kbc->idev);
+ if (retval == -ENOSYS || retval == -ENOENT) {
+ /*
+ * If there is no OF support in kernel or keymap
+ * property is missing, use default keymap.
+ */
+ retval = matrix_keypad_build_keymap(
+ &tegra_kbc_default_keymap_data, NULL,
+ keymap_rows, KBC_MAX_COL,
+ kbc->keycode, kbc->idev);
+ }
+
+ return retval;
+}
+
static int __devinit tegra_kbc_probe(struct platform_device *pdev)
{
const struct tegra_kbc_platform_data *pdata = pdev->dev.platform_data;
- const struct matrix_keymap_data *keymap_data;
struct tegra_kbc *kbc;
struct input_dev *input_dev;
struct resource *res;
@@ -757,29 +779,26 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
kbc->repoll_dly = KBC_ROW_SCAN_DLY + scan_time_rows + pdata->repeat_cnt;
kbc->repoll_dly = DIV_ROUND_UP(kbc->repoll_dly, KBC_CYCLE_MS);
+ kbc->wakeup_key = pdata->wakeup_key;
+ kbc->use_fn_map = pdata->use_fn_map;
+ kbc->use_ghost_filter = pdata->use_ghost_filter;
+
input_dev->name = pdev->name;
input_dev->id.bustype = BUS_HOST;
input_dev->dev.parent = &pdev->dev;
input_dev->open = tegra_kbc_open;
input_dev->close = tegra_kbc_close;
- input_set_drvdata(input_dev, kbc);
+ err = tegra_kbd_setup_keymap(kbc);
+ if (err) {
+ dev_err(&pdev->dev, "failed to setup keymap\n");
+ goto err_put_clk;
+ }
- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+ __set_bit(EV_REP, input_dev->evbit);
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
- input_dev->keycode = kbc->keycode;
- input_dev->keycodesize = sizeof(kbc->keycode[0]);
- input_dev->keycodemax = KBC_MAX_KEY;
- if (pdata->use_fn_map)
- input_dev->keycodemax *= 2;
-
- kbc->use_fn_map = pdata->use_fn_map;
- kbc->use_ghost_filter = pdata->use_ghost_filter;
- keymap_data = pdata->keymap_data ?: &tegra_kbc_default_keymap_data;
- matrix_keypad_build_keymap(keymap_data, KBC_ROW_SHIFT,
- input_dev->keycode, input_dev->keybit);
- kbc->wakeup_key = pdata->wakeup_key;
+ input_set_drvdata(input_dev, kbc);
err = request_irq(kbc->irq, tegra_kbc_isr,
IRQF_NO_SUSPEND | IRQF_TRIGGER_HIGH, pdev->name, kbc);
@@ -799,9 +818,6 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, kbc);
device_init_wakeup(&pdev->dev, pdata->wakeup);
- if (!pdev->dev.platform_data)
- matrix_keyboard_of_free_keymap(pdata->keymap_data);
-
return 0;
err_free_irq:
@@ -816,10 +832,8 @@ err_free_mem:
input_free_device(input_dev);
kfree(kbc);
err_free_pdata:
- if (!pdev->dev.platform_data) {
- matrix_keyboard_of_free_keymap(pdata->keymap_data);
+ if (!pdev->dev.platform_data)
kfree(pdata);
- }
return err;
}
diff --git a/drivers/input/keyboard/tnetv107x-keypad.c b/drivers/input/keyboard/tnetv107x-keypad.c
index fb39c94b6fdd..a4a445fb7020 100644
--- a/drivers/input/keyboard/tnetv107x-keypad.c
+++ b/drivers/input/keyboard/tnetv107x-keypad.c
@@ -247,15 +247,11 @@ static int __devinit keypad_probe(struct platform_device *pdev)
error = -ENOMEM;
goto error_input;
}
- input_set_drvdata(kp->input_dev, kp);
kp->input_dev->name = pdev->name;
kp->input_dev->dev.parent = &pdev->dev;
kp->input_dev->open = keypad_start;
kp->input_dev->close = keypad_stop;
- kp->input_dev->evbit[0] = BIT_MASK(EV_KEY);
- if (!pdata->no_autorepeat)
- kp->input_dev->evbit[0] |= BIT_MASK(EV_REP);
clk_enable(kp->clk);
rev = keypad_read(kp, rev);
@@ -264,15 +260,20 @@ static int __devinit keypad_probe(struct platform_device *pdev)
kp->input_dev->id.version = ((rev >> 16) & 0xfff);
clk_disable(kp->clk);
- kp->input_dev->keycode = kp->keycodes;
- kp->input_dev->keycodesize = sizeof(kp->keycodes[0]);
- kp->input_dev->keycodemax = kp->rows << kp->row_shift;
-
- matrix_keypad_build_keymap(keymap_data, kp->row_shift, kp->keycodes,
- kp->input_dev->keybit);
+ error = matrix_keypad_build_keymap(keymap_data, NULL,
+ kp->rows, kp->cols,
+ kp->keycodes, kp->input_dev);
+ if (error) {
+ dev_err(dev, "Failed to build keymap\n");
+ goto error_reg;
+ }
+ if (!pdata->no_autorepeat)
+ kp->input_dev->evbit[0] |= BIT_MASK(EV_REP);
input_set_capability(kp->input_dev, EV_MSC, MSC_SCAN);
+ input_set_drvdata(kp->input_dev, kp);
+
error = input_register_device(kp->input_dev);
if (error < 0) {
dev_err(dev, "Could not register input device\n");
diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c
index 67bec14e8b96..a2c6f79aa101 100644
--- a/drivers/input/keyboard/twl4030_keypad.c
+++ b/drivers/input/keyboard/twl4030_keypad.c
@@ -361,14 +361,6 @@ static int __devinit twl4030_kp_probe(struct platform_device *pdev)
kp->irq = platform_get_irq(pdev, 0);
/* setup input device */
- __set_bit(EV_KEY, input->evbit);
-
- /* Enable auto repeat feature of Linux input subsystem */
- if (pdata->rep)
- __set_bit(EV_REP, input->evbit);
-
- input_set_capability(input, EV_MSC, MSC_SCAN);
-
input->name = "TWL4030 Keypad";
input->phys = "twl4030_keypad/input0";
input->dev.parent = &pdev->dev;
@@ -378,12 +370,19 @@ static int __devinit twl4030_kp_probe(struct platform_device *pdev)
input->id.product = 0x0001;
input->id.version = 0x0003;
- input->keycode = kp->keymap;
- input->keycodesize = sizeof(kp->keymap[0]);
- input->keycodemax = ARRAY_SIZE(kp->keymap);
+ error = matrix_keypad_build_keymap(keymap_data, NULL,
+ TWL4030_MAX_ROWS,
+ 1 << TWL4030_ROW_SHIFT,
+ kp->keymap, input);
+ if (error) {
+ dev_err(kp->dbg_dev, "Failed to build keymap\n");
+ goto err1;
+ }
- matrix_keypad_build_keymap(keymap_data, TWL4030_ROW_SHIFT,
- input->keycode, input->keybit);
+ input_set_capability(input, EV_MSC, MSC_SCAN);
+ /* Enable auto repeat feature of Linux input subsystem */
+ if (pdata->rep)
+ __set_bit(EV_REP, input->evbit);
error = input_register_device(input);
if (error) {
diff --git a/drivers/input/keyboard/w90p910_keypad.c b/drivers/input/keyboard/w90p910_keypad.c
index 99bbb7e775ae..085ede4d972d 100644
--- a/drivers/input/keyboard/w90p910_keypad.c
+++ b/drivers/input/keyboard/w90p910_keypad.c
@@ -42,7 +42,8 @@
#define KGET_RAW(n) (((n) & KEY0R) >> 3)
#define KGET_COLUMN(n) ((n) & KEY0C)
-#define W90P910_MAX_KEY_NUM (8 * 8)
+#define W90P910_NUM_ROWS 8
+#define W90P910_NUM_COLS 8
#define W90P910_ROW_SHIFT 3
struct w90p910_keypad {
@@ -51,7 +52,7 @@ struct w90p910_keypad {
struct input_dev *input_dev;
void __iomem *mmio_base;
int irq;
- unsigned short keymap[W90P910_MAX_KEY_NUM];
+ unsigned short keymap[W90P910_NUM_ROWS * W90P910_NUM_COLS];
};
static void w90p910_keypad_scan_matrix(struct w90p910_keypad *keypad,
@@ -190,17 +191,13 @@ static int __devinit w90p910_keypad_probe(struct platform_device *pdev)
input_dev->close = w90p910_keypad_close;
input_dev->dev.parent = &pdev->dev;
- input_dev->keycode = keypad->keymap;
- input_dev->keycodesize = sizeof(keypad->keymap[0]);
- input_dev->keycodemax = ARRAY_SIZE(keypad->keymap);
-
- input_set_drvdata(input_dev, keypad);
-
- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
- input_set_capability(input_dev, EV_MSC, MSC_SCAN);
-
- matrix_keypad_build_keymap(keymap_data, W90P910_ROW_SHIFT,
- input_dev->keycode, input_dev->keybit);
+ error = matrix_keypad_build_keymap(keymap_data, NULL,
+ W90P910_NUM_ROWS, W90P910_NUM_COLS,
+ keypad->keymap, input_dev);
+ if (error) {
+ dev_err(&pdev->dev, "failed to build keymap\n");
+ goto failed_put_clk;
+ }
error = request_irq(keypad->irq, w90p910_keypad_irq_handler,
0, pdev->name, keypad);
@@ -209,6 +206,10 @@ static int __devinit w90p910_keypad_probe(struct platform_device *pdev)
goto failed_put_clk;
}
+ __set_bit(EV_REP, input_dev->evbit);
+ input_set_capability(input_dev, EV_MSC, MSC_SCAN);
+ input_set_drvdata(input_dev, keypad);
+
/* Register the input device */
error = input_register_device(input_dev);
if (error) {
diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c
index 37b01d777a4a..d050d9d0011b 100644
--- a/drivers/input/keyboard/xtkbd.c
+++ b/drivers/input/keyboard/xtkbd.c
@@ -169,15 +169,4 @@ static struct serio_driver xtkbd_drv = {
.disconnect = xtkbd_disconnect,
};
-static int __init xtkbd_init(void)
-{
- return serio_register_driver(&xtkbd_drv);
-}
-
-static void __exit xtkbd_exit(void)
-{
- serio_unregister_driver(&xtkbd_drv);
-}
-
-module_init(xtkbd_init);
-module_exit(xtkbd_exit);
+module_serio_driver(xtkbd_drv);
diff --git a/drivers/input/matrix-keymap.c b/drivers/input/matrix-keymap.c
new file mode 100644
index 000000000000..443ad64b7f2a
--- /dev/null
+++ b/drivers/input/matrix-keymap.c
@@ -0,0 +1,163 @@
+/*
+ * Helpers for matrix keyboard bindings
+ *
+ * Copyright (C) 2012 Google, Inc
+ *
+ * Author:
+ * Olof Johansson <olof@lixom.net>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/of.h>
+#include <linux/export.h>
+#include <linux/input/matrix_keypad.h>
+
+static bool matrix_keypad_map_key(struct input_dev *input_dev,
+ unsigned int rows, unsigned int cols,
+ unsigned int row_shift, unsigned int key)
+{
+ unsigned short *keymap = input_dev->keycode;
+ unsigned int row = KEY_ROW(key);
+ unsigned int col = KEY_COL(key);
+ unsigned short code = KEY_VAL(key);
+
+ if (row >= rows || col >= cols) {
+ dev_err(input_dev->dev.parent,
+ "%s: invalid keymap entry 0x%x (row: %d, col: %d, rows: %d, cols: %d)\n",
+ __func__, key, row, col, rows, cols);
+ return false;
+ }
+
+ keymap[MATRIX_SCAN_CODE(row, col, row_shift)] = code;
+ __set_bit(code, input_dev->keybit);
+
+ return true;
+}
+
+#ifdef CONFIG_OF
+static int matrix_keypad_parse_of_keymap(const char *propname,
+ unsigned int rows, unsigned int cols,
+ struct input_dev *input_dev)
+{
+ struct device *dev = input_dev->dev.parent;
+ struct device_node *np = dev->of_node;
+ unsigned int row_shift = get_count_order(cols);
+ unsigned int max_keys = rows << row_shift;
+ unsigned int proplen, i, size;
+ const __be32 *prop;
+
+ if (!np)
+ return -ENOENT;
+
+ if (!propname)
+ propname = "linux,keymap";
+
+ prop = of_get_property(np, propname, &proplen);
+ if (!prop) {
+ dev_err(dev, "OF: %s property not defined in %s\n",
+ propname, np->full_name);
+ return -ENOENT;
+ }
+
+ if (proplen % sizeof(u32)) {
+ dev_err(dev, "OF: Malformed keycode property %s in %s\n",
+ propname, np->full_name);
+ return -EINVAL;
+ }
+
+ size = proplen / sizeof(u32);
+ if (size > max_keys) {
+ dev_err(dev, "OF: %s size overflow\n", propname);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < size; i++) {
+ unsigned int key = be32_to_cpup(prop + i);
+
+ if (!matrix_keypad_map_key(input_dev, rows, cols,
+ row_shift, key))
+ return -EINVAL;
+ }
+
+ return 0;
+}
+#else
+static int matrix_keypad_parse_of_keymap(const char *propname,
+ unsigned int rows, unsigned int cols,
+ struct input_dev *input_dev)
+{
+ return -ENOSYS;
+}
+#endif
+
+/**
+ * matrix_keypad_build_keymap - convert platform keymap into matrix keymap
+ * @keymap_data: keymap supplied by the platform code
+ * @keymap_name: name of device tree property containing keymap (if device
+ * tree support is enabled).
+ * @rows: number of rows in target keymap array
+ * @cols: number of cols in target keymap array
+ * @keymap: expanded version of keymap that is suitable for use by
+ * matrix keyboard driver
+ * @input_dev: input devices for which we are setting up the keymap
+ *
+ * This function converts platform keymap (encoded with KEY() macro) into
+ * an array of keycodes that is suitable for using in a standard matrix
+ * keyboard driver that uses row and col as indices.
+ *
+ * If @keymap_data is not supplied and device tree support is enabled
+ * it will attempt load the keymap from property specified by @keymap_name
+ * argument (or "linux,keymap" if @keymap_name is %NULL).
+ *
+ * Callers are expected to set up input_dev->dev.parent before calling this
+ * function.
+ */
+int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data,
+ const char *keymap_name,
+ unsigned int rows, unsigned int cols,
+ unsigned short *keymap,
+ struct input_dev *input_dev)
+{
+ unsigned int row_shift = get_count_order(cols);
+ int i;
+ int error;
+
+ input_dev->keycode = keymap;
+ input_dev->keycodesize = sizeof(*keymap);
+ input_dev->keycodemax = rows << row_shift;
+
+ __set_bit(EV_KEY, input_dev->evbit);
+
+ if (keymap_data) {
+ for (i = 0; i < keymap_data->keymap_size; i++) {
+ unsigned int key = keymap_data->keymap[i];
+
+ if (!matrix_keypad_map_key(input_dev, rows, cols,
+ row_shift, key))
+ return -EINVAL;
+ }
+ } else {
+ error = matrix_keypad_parse_of_keymap(keymap_name, rows, cols,
+ input_dev);
+ if (error)
+ return error;
+ }
+
+ __clear_bit(KEY_RESERVED, input_dev->keybit);
+
+ return 0;
+}
+EXPORT_SYMBOL(matrix_keypad_build_keymap);
diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c
index ab860511f016..082684e7f390 100644
--- a/drivers/input/misc/cm109.c
+++ b/drivers/input/misc/cm109.c
@@ -327,7 +327,9 @@ static void cm109_submit_buzz_toggle(struct cm109_dev *dev)
error = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC);
if (error)
- err("%s: usb_submit_urb (urb_ctl) failed %d", __func__, error);
+ dev_err(&dev->intf->dev,
+ "%s: usb_submit_urb (urb_ctl) failed %d\n",
+ __func__, error);
}
/*
@@ -339,7 +341,7 @@ static void cm109_urb_irq_callback(struct urb *urb)
const int status = urb->status;
int error;
- dev_dbg(&urb->dev->dev, "### URB IRQ: [0x%02x 0x%02x 0x%02x 0x%02x] keybit=0x%02x\n",
+ dev_dbg(&dev->intf->dev, "### URB IRQ: [0x%02x 0x%02x 0x%02x 0x%02x] keybit=0x%02x\n",
dev->irq_data->byte[0],
dev->irq_data->byte[1],
dev->irq_data->byte[2],
@@ -349,7 +351,7 @@ static void cm109_urb_irq_callback(struct urb *urb)
if (status) {
if (status == -ESHUTDOWN)
return;
- err("%s: urb status %d", __func__, status);
+ dev_err(&dev->intf->dev, "%s: urb status %d\n", __func__, status);
}
/* Special keys */
@@ -396,7 +398,8 @@ static void cm109_urb_irq_callback(struct urb *urb)
error = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC);
if (error)
- err("%s: usb_submit_urb (urb_ctl) failed %d",
+ dev_err(&dev->intf->dev,
+ "%s: usb_submit_urb (urb_ctl) failed %d\n",
__func__, error);
}
@@ -409,14 +412,14 @@ static void cm109_urb_ctl_callback(struct urb *urb)
const int status = urb->status;
int error;
- dev_dbg(&urb->dev->dev, "### URB CTL: [0x%02x 0x%02x 0x%02x 0x%02x]\n",
+ dev_dbg(&dev->intf->dev, "### URB CTL: [0x%02x 0x%02x 0x%02x 0x%02x]\n",
dev->ctl_data->byte[0],
dev->ctl_data->byte[1],
dev->ctl_data->byte[2],
dev->ctl_data->byte[3]);
if (status)
- err("%s: urb status %d", __func__, status);
+ dev_err(&dev->intf->dev, "%s: urb status %d\n", __func__, status);
spin_lock(&dev->ctl_submit_lock);
@@ -433,7 +436,8 @@ static void cm109_urb_ctl_callback(struct urb *urb)
dev->irq_urb_pending = 1;
error = usb_submit_urb(dev->urb_irq, GFP_ATOMIC);
if (error)
- err("%s: usb_submit_urb (urb_irq) failed %d",
+ dev_err(&dev->intf->dev,
+ "%s: usb_submit_urb (urb_irq) failed %d\n",
__func__, error);
}
}
@@ -476,7 +480,8 @@ static void cm109_toggle_buzzer_sync(struct cm109_dev *dev, int on)
dev->ctl_data,
USB_PKT_LEN, USB_CTRL_SET_TIMEOUT);
if (error < 0 && error != -EINTR)
- err("%s: usb_control_msg() failed %d", __func__, error);
+ dev_err(&dev->intf->dev, "%s: usb_control_msg() failed %d\n",
+ __func__, error);
}
static void cm109_stop_traffic(struct cm109_dev *dev)
@@ -518,8 +523,8 @@ static int cm109_input_open(struct input_dev *idev)
error = usb_autopm_get_interface(dev->intf);
if (error < 0) {
- err("%s - cannot autoresume, result %d",
- __func__, error);
+ dev_err(&idev->dev, "%s - cannot autoresume, result %d\n",
+ __func__, error);
return error;
}
@@ -537,7 +542,8 @@ static int cm109_input_open(struct input_dev *idev)
error = usb_submit_urb(dev->urb_ctl, GFP_KERNEL);
if (error)
- err("%s: usb_submit_urb (urb_ctl) failed %d", __func__, error);
+ dev_err(&dev->intf->dev, "%s: usb_submit_urb (urb_ctl) failed %d\n",
+ __func__, error);
else
dev->open = 1;
@@ -573,7 +579,7 @@ static int cm109_input_ev(struct input_dev *idev, unsigned int type,
{
struct cm109_dev *dev = input_get_drvdata(idev);
- dev_dbg(&dev->udev->dev,
+ dev_dbg(&dev->intf->dev,
"input_ev: type=%u code=%u value=%d\n", type, code, value);
if (type != EV_SND)
@@ -710,7 +716,8 @@ static int cm109_usb_probe(struct usb_interface *intf,
pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
if (ret != USB_PKT_LEN)
- err("invalid payload size %d, expected %d", ret, USB_PKT_LEN);
+ dev_err(&intf->dev, "invalid payload size %d, expected %d\n",
+ ret, USB_PKT_LEN);
/* initialise irq urb */
usb_fill_int_urb(dev->urb_irq, udev, pipe, dev->irq_data,
diff --git a/drivers/input/misc/cma3000_d0x.c b/drivers/input/misc/cma3000_d0x.c
index 06517e60e50c..a3735a01e9fd 100644
--- a/drivers/input/misc/cma3000_d0x.c
+++ b/drivers/input/misc/cma3000_d0x.c
@@ -318,7 +318,7 @@ struct cma3000_accl_data *cma3000_init(struct device *dev, int irq,
mutex_init(&data->mutex);
data->mode = pdata->mode;
- if (data->mode < CMAMODE_DEFAULT || data->mode > CMAMODE_POFF) {
+ if (data->mode > CMAMODE_POFF) {
data->mode = CMAMODE_MOTDET;
dev_warn(dev,
"Invalid mode specified, assuming Motion Detect\n");
diff --git a/drivers/input/misc/keyspan_remote.c b/drivers/input/misc/keyspan_remote.c
index d99151a8bf10..290fa5f97ded 100644
--- a/drivers/input/misc/keyspan_remote.c
+++ b/drivers/input/misc/keyspan_remote.c
@@ -157,7 +157,7 @@ static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed)
* though so it's not too big a deal
*/
if (dev->data.pos >= dev->data.len) {
- dev_dbg(&dev->udev->dev,
+ dev_dbg(&dev->interface->dev,
"%s - Error ran out of data. pos: %d, len: %d\n",
__func__, dev->data.pos, dev->data.len);
return -1;
@@ -267,7 +267,9 @@ static void keyspan_check_data(struct usb_keyspan *remote)
remote->data.tester = remote->data.tester >> 6;
remote->data.bits_left -= 6;
} else {
- err("%s - Unknown sequence found in system data.\n", __func__);
+ dev_err(&remote->interface->dev,
+ "%s - Unknown sequence found in system data.\n",
+ __func__);
remote->stage = 0;
return;
}
@@ -286,7 +288,9 @@ static void keyspan_check_data(struct usb_keyspan *remote)
remote->data.tester = remote->data.tester >> 6;
remote->data.bits_left -= 6;
} else {
- err("%s - Unknown sequence found in button data.\n", __func__);
+ dev_err(&remote->interface->dev,
+ "%s - Unknown sequence found in button data.\n",
+ __func__);
remote->stage = 0;
return;
}
@@ -302,7 +306,9 @@ static void keyspan_check_data(struct usb_keyspan *remote)
remote->data.tester = remote->data.tester >> 6;
remote->data.bits_left -= 6;
} else {
- err("%s - Error in message, invalid toggle.\n", __func__);
+ dev_err(&remote->interface->dev,
+ "%s - Error in message, invalid toggle.\n",
+ __func__);
remote->stage = 0;
return;
}
@@ -312,10 +318,11 @@ static void keyspan_check_data(struct usb_keyspan *remote)
remote->data.tester = remote->data.tester >> 5;
remote->data.bits_left -= 5;
} else {
- err("Bad message received, no stop bit found.\n");
+ dev_err(&remote->interface->dev,
+ "Bad message received, no stop bit found.\n");
}
- dev_dbg(&remote->udev->dev,
+ dev_dbg(&remote->interface->dev,
"%s found valid message: system: %d, button: %d, toggle: %d\n",
__func__, message.system, message.button, message.toggle);
@@ -397,7 +404,9 @@ static void keyspan_irq_recv(struct urb *urb)
resubmit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
- err ("%s - usb_submit_urb failed with result: %d", __func__, retval);
+ dev_err(&dev->interface->dev,
+ "%s - usb_submit_urb failed with result: %d\n",
+ __func__, retval);
}
static int keyspan_open(struct input_dev *dev)
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index 5403c571b6a5..306f84c2d8fb 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -367,7 +367,7 @@ static int __devinit mpu3050_probe(struct i2c_client *client,
error = request_threaded_irq(client->irq,
NULL, mpu3050_interrupt_thread,
- IRQF_TRIGGER_RISING,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"mpu3050", sensor);
if (error) {
dev_err(&client->dev,
diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c
index 538f7049ec64..49c0c3ebd321 100644
--- a/drivers/input/misc/powermate.c
+++ b/drivers/input/misc/powermate.c
@@ -65,6 +65,7 @@ struct powermate_device {
struct urb *irq, *config;
struct usb_ctrlrequest *configcr;
struct usb_device *udev;
+ struct usb_interface *intf;
struct input_dev *input;
spinlock_t lock;
int static_brightness;
@@ -85,6 +86,7 @@ static void powermate_config_complete(struct urb *urb);
static void powermate_irq(struct urb *urb)
{
struct powermate_device *pm = urb->context;
+ struct device *dev = &pm->intf->dev;
int retval;
switch (urb->status) {
@@ -95,10 +97,12 @@ static void powermate_irq(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __func__, urb->status);
+ dev_dbg(dev, "%s - urb shutting down with status: %d\n",
+ __func__, urb->status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __func__, urb->status);
+ dev_dbg(dev, "%s - nonzero urb status received: %d\n",
+ __func__, urb->status);
goto exit;
}
@@ -110,8 +114,8 @@ static void powermate_irq(struct urb *urb)
exit:
retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval)
- err ("%s - usb_submit_urb failed with result %d",
- __func__, retval);
+ dev_err(dev, "%s - usb_submit_urb failed with result: %d\n",
+ __func__, retval);
}
/* Decide if we need to issue a control message and do so. Must be called with pm->lock taken */
@@ -330,6 +334,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
goto fail3;
pm->udev = udev;
+ pm->intf = intf;
pm->input = input_dev;
usb_make_path(udev, pm->phys, sizeof(pm->phys));
diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c
index 14e94f56cb7d..c34f6c0371c4 100644
--- a/drivers/input/misc/twl6040-vibra.c
+++ b/drivers/input/misc/twl6040-vibra.c
@@ -27,6 +27,7 @@
*/
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/of.h>
#include <linux/workqueue.h>
#include <linux/input.h>
#include <linux/mfd/twl6040.h>
@@ -258,10 +259,13 @@ static SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops, twl6040_vibra_suspend, NULL);
static int __devinit twl6040_vibra_probe(struct platform_device *pdev)
{
struct twl6040_vibra_data *pdata = pdev->dev.platform_data;
+ struct device_node *node = pdev->dev.of_node;
struct vibra_info *info;
+ int vddvibl_uV = 0;
+ int vddvibr_uV = 0;
int ret;
- if (!pdata) {
+ if (!pdata && !node) {
dev_err(&pdev->dev, "platform_data not available\n");
return -EINVAL;
}
@@ -273,11 +277,26 @@ static int __devinit twl6040_vibra_probe(struct platform_device *pdev)
}
info->dev = &pdev->dev;
+
info->twl6040 = dev_get_drvdata(pdev->dev.parent);
- info->vibldrv_res = pdata->vibldrv_res;
- info->vibrdrv_res = pdata->vibrdrv_res;
- info->viblmotor_res = pdata->viblmotor_res;
- info->vibrmotor_res = pdata->vibrmotor_res;
+ if (pdata) {
+ info->vibldrv_res = pdata->vibldrv_res;
+ info->vibrdrv_res = pdata->vibrdrv_res;
+ info->viblmotor_res = pdata->viblmotor_res;
+ info->vibrmotor_res = pdata->vibrmotor_res;
+ vddvibl_uV = pdata->vddvibl_uV;
+ vddvibr_uV = pdata->vddvibr_uV;
+ } else {
+ of_property_read_u32(node, "vibldrv_res", &info->vibldrv_res);
+ of_property_read_u32(node, "vibrdrv_res", &info->vibrdrv_res);
+ of_property_read_u32(node, "viblmotor_res",
+ &info->viblmotor_res);
+ of_property_read_u32(node, "vibrmotor_res",
+ &info->vibrmotor_res);
+ of_property_read_u32(node, "vddvibl_uV", &vddvibl_uV);
+ of_property_read_u32(node, "vddvibr_uV", &vddvibr_uV);
+ }
+
if ((!info->vibldrv_res && !info->viblmotor_res) ||
(!info->vibrdrv_res && !info->vibrmotor_res)) {
dev_err(info->dev, "invalid vibra driver/motor resistance\n");
@@ -339,10 +358,9 @@ static int __devinit twl6040_vibra_probe(struct platform_device *pdev)
goto err_regulator;
}
- if (pdata->vddvibl_uV) {
+ if (vddvibl_uV) {
ret = regulator_set_voltage(info->supplies[0].consumer,
- pdata->vddvibl_uV,
- pdata->vddvibl_uV);
+ vddvibl_uV, vddvibl_uV);
if (ret) {
dev_err(info->dev, "failed to set VDDVIBL volt %d\n",
ret);
@@ -350,10 +368,9 @@ static int __devinit twl6040_vibra_probe(struct platform_device *pdev)
}
}
- if (pdata->vddvibr_uV) {
+ if (vddvibr_uV) {
ret = regulator_set_voltage(info->supplies[1].consumer,
- pdata->vddvibr_uV,
- pdata->vddvibr_uV);
+ vddvibr_uV, vddvibr_uV);
if (ret) {
dev_err(info->dev, "failed to set VDDVIBR volt %d\n",
ret);
@@ -401,6 +418,12 @@ static int __devexit twl6040_vibra_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id twl6040_vibra_of_match[] = {
+ {.compatible = "ti,twl6040-vibra", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, twl6040_vibra_of_match);
+
static struct platform_driver twl6040_vibra_driver = {
.probe = twl6040_vibra_probe,
.remove = __devexit_p(twl6040_vibra_remove),
@@ -408,6 +431,7 @@ static struct platform_driver twl6040_vibra_driver = {
.name = "twl6040-vibra",
.owner = THIS_MODULE,
.pm = &twl6040_vibra_pm_ops,
+ .of_match_table = twl6040_vibra_of_match,
},
};
module_platform_driver(twl6040_vibra_driver);
diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c
index f4776e7f8c15..285a5bd6cbc9 100644
--- a/drivers/input/misc/yealink.c
+++ b/drivers/input/misc/yealink.c
@@ -101,6 +101,7 @@ static const struct lcd_segment_map {
struct yealink_dev {
struct input_dev *idev; /* input device */
struct usb_device *udev; /* usb device */
+ struct usb_interface *intf; /* usb interface */
/* irq input channel */
struct yld_ctl_packet *irq_data;
@@ -428,7 +429,8 @@ static void urb_irq_callback(struct urb *urb)
int ret, status = urb->status;
if (status)
- err("%s - urb status %d", __func__, status);
+ dev_err(&yld->intf->dev, "%s - urb status %d\n",
+ __func__, status);
switch (yld->irq_data->cmd) {
case CMD_KEYPRESS:
@@ -437,13 +439,15 @@ static void urb_irq_callback(struct urb *urb)
break;
case CMD_SCANCODE:
- dbg("get scancode %x", yld->irq_data->data[0]);
+ dev_dbg(&yld->intf->dev, "get scancode %x\n",
+ yld->irq_data->data[0]);
report_key(yld, map_p1k_to_key(yld->irq_data->data[0]));
break;
default:
- err("unexpected response %x", yld->irq_data->cmd);
+ dev_err(&yld->intf->dev, "unexpected response %x\n",
+ yld->irq_data->cmd);
}
yealink_do_idle_tasks(yld);
@@ -451,7 +455,9 @@ static void urb_irq_callback(struct urb *urb)
if (!yld->shutdown) {
ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
if (ret && ret != -EPERM)
- err("%s - usb_submit_urb failed %d", __func__, ret);
+ dev_err(&yld->intf->dev,
+ "%s - usb_submit_urb failed %d\n",
+ __func__, ret);
}
}
@@ -461,7 +467,8 @@ static void urb_ctl_callback(struct urb *urb)
int ret = 0, status = urb->status;
if (status)
- err("%s - urb status %d", __func__, status);
+ dev_err(&yld->intf->dev, "%s - urb status %d\n",
+ __func__, status);
switch (yld->ctl_data->cmd) {
case CMD_KEYPRESS:
@@ -479,7 +486,8 @@ static void urb_ctl_callback(struct urb *urb)
}
if (ret && ret != -EPERM)
- err("%s - usb_submit_urb failed %d", __func__, ret);
+ dev_err(&yld->intf->dev, "%s - usb_submit_urb failed %d\n",
+ __func__, ret);
}
/*******************************************************************************
@@ -511,7 +519,7 @@ static int input_open(struct input_dev *dev)
struct yealink_dev *yld = input_get_drvdata(dev);
int i, ret;
- dbg("%s", __func__);
+ dev_dbg(&yld->intf->dev, "%s\n", __func__);
/* force updates to device */
for (i = 0; i<sizeof(yld->master); i++)
@@ -526,8 +534,9 @@ static int input_open(struct input_dev *dev)
yld->ctl_data->size = 10;
yld->ctl_data->sum = 0x100-CMD_INIT-10;
if ((ret = usb_submit_urb(yld->urb_ctl, GFP_KERNEL)) != 0) {
- dbg("%s - usb_submit_urb failed with result %d",
- __func__, ret);
+ dev_dbg(&yld->intf->dev,
+ "%s - usb_submit_urb failed with result %d\n",
+ __func__, ret);
return ret;
}
return 0;
@@ -876,6 +885,7 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
return -ENOMEM;
yld->udev = udev;
+ yld->intf = intf;
yld->idev = input_dev = input_allocate_device();
if (!input_dev)
@@ -909,7 +919,8 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
if (ret != USB_PKT_LEN)
- err("invalid payload size %d, expected %zd", ret, USB_PKT_LEN);
+ dev_err(&intf->dev, "invalid payload size %d, expected %zd\n",
+ ret, USB_PKT_LEN);
/* initialise irq urb */
usb_fill_int_urb(yld->urb_irq, udev, pipe, yld->irq_data,
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index 9b8db821d5f0..cd6268cf7cd5 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -339,4 +339,16 @@ config MOUSE_SYNAPTICS_USB
To compile this driver as a module, choose M here: the
module will be called synaptics_usb.
+config MOUSE_NAVPOINT_PXA27x
+ tristate "Synaptics NavPoint (PXA27x SSP/SPI)"
+ depends on PXA27x && PXA_SSP
+ help
+ This driver adds support for the Synaptics NavPoint touchpad connected
+ to a PXA27x SSP port in SPI slave mode. The device emulates a mouse;
+ a tap or tap-and-a-half drag gesture emulates the left mouse button.
+ For example, use the xf86-input-evdev driver for an X pointing device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called navpoint.
+
endif
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index 4718effeb8d9..46ba7556fd4f 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o
obj-$(CONFIG_MOUSE_INPORT) += inport.o
obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o
obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o
+obj-$(CONFIG_MOUSE_NAVPOINT_PXA27x) += navpoint.o
obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o
obj-$(CONFIG_MOUSE_PS2) += psmouse.o
obj-$(CONFIG_MOUSE_PXA930_TRKBALL) += pxa930_trkball.o
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 4c6a72d3d48c..4a1347e91bdc 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -553,10 +553,7 @@ static void alps_process_touchpad_packet_v3(struct psmouse *psmouse)
alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
- input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
- input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
- input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
- input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4);
+ input_mt_report_finger_count(dev, fingers);
input_report_key(dev, BTN_LEFT, left);
input_report_key(dev, BTN_RIGHT, right);
@@ -604,10 +601,54 @@ static void alps_process_packet_v3(struct psmouse *psmouse)
static void alps_process_packet_v4(struct psmouse *psmouse)
{
+ struct alps_data *priv = psmouse->private;
unsigned char *packet = psmouse->packet;
struct input_dev *dev = psmouse->dev;
+ int offset;
int x, y, z;
int left, right;
+ int x1, y1, x2, y2;
+ int fingers = 0;
+ unsigned int x_bitmap, y_bitmap;
+
+ /*
+ * v4 has a 6-byte encoding for bitmap data, but this data is
+ * broken up between 3 normal packets. Use priv->multi_packet to
+ * track our position in the bitmap packet.
+ */
+ if (packet[6] & 0x40) {
+ /* sync, reset position */
+ priv->multi_packet = 0;
+ }
+
+ if (WARN_ON_ONCE(priv->multi_packet > 2))
+ return;
+
+ offset = 2 * priv->multi_packet;
+ priv->multi_data[offset] = packet[6];
+ priv->multi_data[offset + 1] = packet[7];
+
+ if (++priv->multi_packet > 2) {
+ priv->multi_packet = 0;
+
+ x_bitmap = ((priv->multi_data[2] & 0x1f) << 10) |
+ ((priv->multi_data[3] & 0x60) << 3) |
+ ((priv->multi_data[0] & 0x3f) << 2) |
+ ((priv->multi_data[1] & 0x60) >> 5);
+ y_bitmap = ((priv->multi_data[5] & 0x01) << 10) |
+ ((priv->multi_data[3] & 0x1f) << 5) |
+ (priv->multi_data[1] & 0x1f);
+
+ fingers = alps_process_bitmap(x_bitmap, y_bitmap,
+ &x1, &y1, &x2, &y2);
+
+ /* Store MT data.*/
+ priv->fingers = fingers;
+ priv->x1 = x1;
+ priv->x2 = x2;
+ priv->y1 = y1;
+ priv->y2 = y2;
+ }
left = packet[4] & 0x01;
right = packet[4] & 0x02;
@@ -617,21 +658,41 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
z = packet[5] & 0x7f;
+ /*
+ * If there were no contacts in the bitmap, use ST
+ * points in MT reports.
+ * If there were two contacts or more, report MT data.
+ */
+ if (priv->fingers < 2) {
+ x1 = x;
+ y1 = y;
+ fingers = z > 0 ? 1 : 0;
+ } else {
+ fingers = priv->fingers;
+ x1 = priv->x1;
+ x2 = priv->x2;
+ y1 = priv->y1;
+ y2 = priv->y2;
+ }
+
if (z >= 64)
input_report_key(dev, BTN_TOUCH, 1);
else
input_report_key(dev, BTN_TOUCH, 0);
+ alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
+
+ input_mt_report_finger_count(dev, fingers);
+
+ input_report_key(dev, BTN_LEFT, left);
+ input_report_key(dev, BTN_RIGHT, right);
+
if (z > 0) {
input_report_abs(dev, ABS_X, x);
input_report_abs(dev, ABS_Y, y);
}
input_report_abs(dev, ABS_PRESSURE, z);
- input_report_key(dev, BTN_TOOL_FINGER, z > 0);
- input_report_key(dev, BTN_LEFT, left);
- input_report_key(dev, BTN_RIGHT, right);
-
input_sync(dev);
}
@@ -1557,6 +1618,7 @@ int alps_init(struct psmouse *psmouse)
input_set_abs_params(dev1, ABS_Y, 0, 767, 0, 0);
break;
case ALPS_PROTO_V3:
+ case ALPS_PROTO_V4:
set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
input_mt_init_slots(dev1, 2);
input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, ALPS_V3_X_MAX, 0, 0);
@@ -1565,8 +1627,7 @@ int alps_init(struct psmouse *psmouse)
set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit);
set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
- /* fall through */
- case ALPS_PROTO_V4:
+
input_set_abs_params(dev1, ABS_X, 0, ALPS_V3_X_MAX, 0, 0);
input_set_abs_params(dev1, ABS_Y, 0, ALPS_V3_Y_MAX, 0, 0);
break;
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index a00a4ab92a0f..ae1ac354c778 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -39,6 +39,8 @@ struct alps_data {
int prev_fin; /* Finger bit from previous packet */
int multi_packet; /* Multi-packet data in progress */
unsigned char multi_data[6]; /* Saved multi-packet data */
+ int x1, x2, y1, y2; /* Coordinates from last MT report */
+ int fingers; /* Number of fingers from MT report */
u8 quirks;
struct timer_list timer;
};
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index 0acbc7d50d05..e42f1fa8cdc0 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -195,6 +195,7 @@ enum atp_status_bits {
struct atp {
char phys[64];
struct usb_device *udev; /* usb device */
+ struct usb_interface *intf; /* usb interface */
struct urb *urb; /* usb request block */
u8 *data; /* transferred data */
struct input_dev *input; /* input dev */
@@ -253,8 +254,9 @@ MODULE_PARM_DESC(debug, "Activate debugging output");
* packets (Report ID 2). This code changes device mode, so it
* sends raw sensor reports (Report ID 5).
*/
-static int atp_geyser_init(struct usb_device *udev)
+static int atp_geyser_init(struct atp *dev)
{
+ struct usb_device *udev = dev->udev;
char *data;
int size;
int i;
@@ -262,7 +264,7 @@ static int atp_geyser_init(struct usb_device *udev)
data = kmalloc(8, GFP_KERNEL);
if (!data) {
- err("Out of memory");
+ dev_err(&dev->intf->dev, "Out of memory\n");
return -ENOMEM;
}
@@ -277,7 +279,7 @@ static int atp_geyser_init(struct usb_device *udev)
for (i = 0; i < 8; i++)
dprintk("appletouch[%d]: %d\n", i, data[i]);
- err("Failed to read mode from device.");
+ dev_err(&dev->intf->dev, "Failed to read mode from device.\n");
ret = -EIO;
goto out_free;
}
@@ -296,7 +298,7 @@ static int atp_geyser_init(struct usb_device *udev)
for (i = 0; i < 8; i++)
dprintk("appletouch[%d]: %d\n", i, data[i]);
- err("Failed to request geyser raw mode");
+ dev_err(&dev->intf->dev, "Failed to request geyser raw mode\n");
ret = -EIO;
goto out_free;
}
@@ -313,16 +315,16 @@ out_free:
static void atp_reinit(struct work_struct *work)
{
struct atp *dev = container_of(work, struct atp, work);
- struct usb_device *udev = dev->udev;
int retval;
dprintk("appletouch: putting appletouch to sleep (reinit)\n");
- atp_geyser_init(udev);
+ atp_geyser_init(dev);
retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
if (retval)
- err("atp_reinit: usb_submit_urb failed with error %d",
- retval);
+ dev_err(&dev->intf->dev,
+ "atp_reinit: usb_submit_urb failed with error %d\n",
+ retval);
}
static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
@@ -400,6 +402,7 @@ static inline void atp_report_fingers(struct input_dev *input, int fingers)
static int atp_status_check(struct urb *urb)
{
struct atp *dev = urb->context;
+ struct usb_interface *intf = dev->intf;
switch (urb->status) {
case 0:
@@ -407,8 +410,8 @@ static int atp_status_check(struct urb *urb)
break;
case -EOVERFLOW:
if (!dev->overflow_warned) {
- printk(KERN_WARNING "appletouch: OVERFLOW with data "
- "length %d, actual length is %d\n",
+ dev_warn(&intf->dev,
+ "appletouch: OVERFLOW with data length %d, actual length is %d\n",
dev->info->datalen, dev->urb->actual_length);
dev->overflow_warned = true;
}
@@ -416,13 +419,15 @@ static int atp_status_check(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* This urb is terminated, clean up */
- dbg("atp_complete: urb shutting down with status: %d",
- urb->status);
+ dev_dbg(&intf->dev,
+ "atp_complete: urb shutting down with status: %d\n",
+ urb->status);
return ATP_URB_STATUS_ERROR_FATAL;
default:
- dbg("atp_complete: nonzero urb status received: %d",
- urb->status);
+ dev_dbg(&intf->dev,
+ "atp_complete: nonzero urb status received: %d\n",
+ urb->status);
return ATP_URB_STATUS_ERROR;
}
@@ -445,7 +450,8 @@ static void atp_detect_size(struct atp *dev)
for (i = dev->info->xsensors; i < ATP_XSENSORS; i++) {
if (dev->xy_cur[i]) {
- printk(KERN_INFO "appletouch: 17\" model detected.\n");
+ dev_info(&dev->intf->dev,
+ "appletouch: 17\" model detected.\n");
input_set_abs_params(dev->input, ABS_X, 0,
(dev->info->xsensors_17 - 1) *
@@ -588,8 +594,9 @@ static void atp_complete_geyser_1_2(struct urb *urb)
exit:
retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
if (retval)
- err("atp_complete: usb_submit_urb failed with result %d",
- retval);
+ dev_err(&dev->intf->dev,
+ "atp_complete: usb_submit_urb failed with result %d\n",
+ retval);
}
/* Interrupt function for older touchpads: GEYSER3/GEYSER4 */
@@ -722,8 +729,9 @@ static void atp_complete_geyser_3_4(struct urb *urb)
exit:
retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
if (retval)
- err("atp_complete: usb_submit_urb failed with result %d",
- retval);
+ dev_err(&dev->intf->dev,
+ "atp_complete: usb_submit_urb failed with result %d\n",
+ retval);
}
static int atp_open(struct input_dev *input)
@@ -748,14 +756,12 @@ static void atp_close(struct input_dev *input)
static int atp_handle_geyser(struct atp *dev)
{
- struct usb_device *udev = dev->udev;
-
if (dev->info != &fountain_info) {
/* switch to raw sensor mode */
- if (atp_geyser_init(udev))
+ if (atp_geyser_init(dev))
return -EIO;
- printk(KERN_INFO "appletouch: Geyser mode initialized.\n");
+ dev_info(&dev->intf->dev, "Geyser mode initialized.\n");
}
return 0;
@@ -785,7 +791,7 @@ static int atp_probe(struct usb_interface *iface,
}
}
if (!int_in_endpointAddr) {
- err("Could not find int-in endpoint");
+ dev_err(&iface->dev, "Could not find int-in endpoint\n");
return -EIO;
}
@@ -793,11 +799,12 @@ static int atp_probe(struct usb_interface *iface,
dev = kzalloc(sizeof(struct atp), GFP_KERNEL);
input_dev = input_allocate_device();
if (!dev || !input_dev) {
- err("Out of memory");
+ dev_err(&iface->dev, "Out of memory\n");
goto err_free_devs;
}
dev->udev = udev;
+ dev->intf = iface;
dev->input = input_dev;
dev->info = info;
dev->overflow_warned = false;
@@ -886,7 +893,7 @@ static void atp_disconnect(struct usb_interface *iface)
usb_free_urb(dev->urb);
kfree(dev);
}
- printk(KERN_INFO "input: appletouch disconnected\n");
+ dev_info(&iface->dev, "input: appletouch disconnected\n");
}
static int atp_recover(struct atp *dev)
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index f9e2758b9f46..2cf681d98c0d 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -584,7 +584,7 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
int retval = 0, size;
if (!data) {
- err("bcm5974: out of memory");
+ dev_err(&dev->intf->dev, "out of memory\n");
retval = -ENOMEM;
goto out;
}
@@ -597,7 +597,7 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
if (size != 8) {
- err("bcm5974: could not read from device");
+ dev_err(&dev->intf->dev, "could not read from device\n");
retval = -EIO;
goto out;
}
@@ -615,7 +615,7 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
if (size != 8) {
- err("bcm5974: could not write to device");
+ dev_err(&dev->intf->dev, "could not write to device\n");
retval = -EIO;
goto out;
}
@@ -631,6 +631,7 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on)
static void bcm5974_irq_button(struct urb *urb)
{
struct bcm5974 *dev = urb->context;
+ struct usb_interface *intf = dev->intf;
int error;
switch (urb->status) {
@@ -640,10 +641,11 @@ static void bcm5974_irq_button(struct urb *urb)
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
- dbg("bcm5974: button urb shutting down: %d", urb->status);
+ dev_dbg(&intf->dev, "button urb shutting down: %d\n",
+ urb->status);
return;
default:
- dbg("bcm5974: button urb status: %d", urb->status);
+ dev_dbg(&intf->dev, "button urb status: %d\n", urb->status);
goto exit;
}
@@ -654,12 +656,13 @@ static void bcm5974_irq_button(struct urb *urb)
exit:
error = usb_submit_urb(dev->bt_urb, GFP_ATOMIC);
if (error)
- err("bcm5974: button urb failed: %d", error);
+ dev_err(&intf->dev, "button urb failed: %d\n", error);
}
static void bcm5974_irq_trackpad(struct urb *urb)
{
struct bcm5974 *dev = urb->context;
+ struct usb_interface *intf = dev->intf;
int error;
switch (urb->status) {
@@ -669,10 +672,11 @@ static void bcm5974_irq_trackpad(struct urb *urb)
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
- dbg("bcm5974: trackpad urb shutting down: %d", urb->status);
+ dev_dbg(&intf->dev, "trackpad urb shutting down: %d\n",
+ urb->status);
return;
default:
- dbg("bcm5974: trackpad urb status: %d", urb->status);
+ dev_dbg(&intf->dev, "trackpad urb status: %d\n", urb->status);
goto exit;
}
@@ -687,7 +691,7 @@ static void bcm5974_irq_trackpad(struct urb *urb)
exit:
error = usb_submit_urb(dev->tp_urb, GFP_ATOMIC);
if (error)
- err("bcm5974: trackpad urb failed: %d", error);
+ dev_err(&intf->dev, "trackpad urb failed: %d\n", error);
}
/*
@@ -833,7 +837,7 @@ static int bcm5974_probe(struct usb_interface *iface,
dev = kzalloc(sizeof(struct bcm5974), GFP_KERNEL);
input_dev = input_allocate_device();
if (!dev || !input_dev) {
- err("bcm5974: out of memory");
+ dev_err(&iface->dev, "out of memory\n");
goto err_free_devs;
}
diff --git a/drivers/input/mouse/navpoint.c b/drivers/input/mouse/navpoint.c
new file mode 100644
index 000000000000..c29ae7654d5e
--- /dev/null
+++ b/drivers/input/mouse/navpoint.c
@@ -0,0 +1,369 @@
+/*
+ * Synaptics NavPoint (PXA27x SSP/SPI) driver.
+ *
+ * Copyright (C) 2012 Paul Parsons <lost.distance@yahoo.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/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/input/navpoint.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/pxa2xx_ssp.h>
+#include <linux/slab.h>
+
+/*
+ * Synaptics Modular Embedded Protocol: Module Packet Format.
+ * Module header byte 2:0 = Length (# bytes that follow)
+ * Module header byte 4:3 = Control
+ * Module header byte 7:5 = Module Address
+ */
+#define HEADER_LENGTH(byte) ((byte) & 0x07)
+#define HEADER_CONTROL(byte) (((byte) >> 3) & 0x03)
+#define HEADER_ADDRESS(byte) ((byte) >> 5)
+
+struct navpoint {
+ struct ssp_device *ssp;
+ struct input_dev *input;
+ struct device *dev;
+ int gpio;
+ int index;
+ u8 data[1 + HEADER_LENGTH(0xff)];
+};
+
+/*
+ * Initialization values for SSCR0_x, SSCR1_x, SSSR_x.
+ */
+static const u32 sscr0 = 0
+ | SSCR0_TUM /* TIM = 1; No TUR interrupts */
+ | SSCR0_RIM /* RIM = 1; No ROR interrupts */
+ | SSCR0_SSE /* SSE = 1; SSP enabled */
+ | SSCR0_Motorola /* FRF = 0; Motorola SPI */
+ | SSCR0_DataSize(16) /* DSS = 15; Data size = 16-bit */
+ ;
+static const u32 sscr1 = 0
+ | SSCR1_SCFR /* SCFR = 1; SSPSCLK only during transfers */
+ | SSCR1_SCLKDIR /* SCLKDIR = 1; Slave mode */
+ | SSCR1_SFRMDIR /* SFRMDIR = 1; Slave mode */
+ | SSCR1_RWOT /* RWOT = 1; Receive without transmit mode */
+ | SSCR1_RxTresh(1) /* RFT = 0; Receive FIFO threshold = 1 */
+ | SSCR1_SPH /* SPH = 1; SSPSCLK inactive 0.5 + 1 cycles */
+ | SSCR1_RIE /* RIE = 1; Receive FIFO interrupt enabled */
+ ;
+static const u32 sssr = 0
+ | SSSR_BCE /* BCE = 1; Clear BCE */
+ | SSSR_TUR /* TUR = 1; Clear TUR */
+ | SSSR_EOC /* EOC = 1; Clear EOC */
+ | SSSR_TINT /* TINT = 1; Clear TINT */
+ | SSSR_PINT /* PINT = 1; Clear PINT */
+ | SSSR_ROR /* ROR = 1; Clear ROR */
+ ;
+
+/*
+ * MEP Query $22: Touchpad Coordinate Range Query is not supported by
+ * the NavPoint module, so sampled values provide the default limits.
+ */
+#define NAVPOINT_X_MIN 1278
+#define NAVPOINT_X_MAX 5340
+#define NAVPOINT_Y_MIN 1572
+#define NAVPOINT_Y_MAX 4396
+#define NAVPOINT_PRESSURE_MIN 0
+#define NAVPOINT_PRESSURE_MAX 255
+
+static void navpoint_packet(struct navpoint *navpoint)
+{
+ int finger;
+ int gesture;
+ int x, y, z;
+
+ switch (navpoint->data[0]) {
+ case 0xff: /* Garbage (packet?) between reset and Hello packet */
+ case 0x00: /* Module 0, NULL packet */
+ break;
+
+ case 0x0e: /* Module 0, Absolute packet */
+ finger = (navpoint->data[1] & 0x01);
+ gesture = (navpoint->data[1] & 0x02);
+ x = ((navpoint->data[2] & 0x1f) << 8) | navpoint->data[3];
+ y = ((navpoint->data[4] & 0x1f) << 8) | navpoint->data[5];
+ z = navpoint->data[6];
+ input_report_key(navpoint->input, BTN_TOUCH, finger);
+ input_report_abs(navpoint->input, ABS_X, x);
+ input_report_abs(navpoint->input, ABS_Y, y);
+ input_report_abs(navpoint->input, ABS_PRESSURE, z);
+ input_report_key(navpoint->input, BTN_TOOL_FINGER, finger);
+ input_report_key(navpoint->input, BTN_LEFT, gesture);
+ input_sync(navpoint->input);
+ break;
+
+ case 0x19: /* Module 0, Hello packet */
+ if ((navpoint->data[1] & 0xf0) == 0x10)
+ break;
+ /* FALLTHROUGH */
+ default:
+ dev_warn(navpoint->dev,
+ "spurious packet: data=0x%02x,0x%02x,...\n",
+ navpoint->data[0], navpoint->data[1]);
+ break;
+ }
+}
+
+static irqreturn_t navpoint_irq(int irq, void *dev_id)
+{
+ struct navpoint *navpoint = dev_id;
+ struct ssp_device *ssp = navpoint->ssp;
+ irqreturn_t ret = IRQ_NONE;
+ u32 status;
+
+ status = pxa_ssp_read_reg(ssp, SSSR);
+ if (status & sssr) {
+ dev_warn(navpoint->dev,
+ "unexpected interrupt: status=0x%08x\n", status);
+ pxa_ssp_write_reg(ssp, SSSR, (status & sssr));
+ ret = IRQ_HANDLED;
+ }
+
+ while (status & SSSR_RNE) {
+ u32 data;
+
+ data = pxa_ssp_read_reg(ssp, SSDR);
+ navpoint->data[navpoint->index + 0] = (data >> 8);
+ navpoint->data[navpoint->index + 1] = data;
+ navpoint->index += 2;
+ if (HEADER_LENGTH(navpoint->data[0]) < navpoint->index) {
+ navpoint_packet(navpoint);
+ navpoint->index = 0;
+ }
+ status = pxa_ssp_read_reg(ssp, SSSR);
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+static void navpoint_up(struct navpoint *navpoint)
+{
+ struct ssp_device *ssp = navpoint->ssp;
+ int timeout;
+
+ clk_prepare_enable(ssp->clk);
+
+ pxa_ssp_write_reg(ssp, SSCR1, sscr1);
+ pxa_ssp_write_reg(ssp, SSSR, sssr);
+ pxa_ssp_write_reg(ssp, SSTO, 0);
+ pxa_ssp_write_reg(ssp, SSCR0, sscr0); /* SSCR0_SSE written last */
+
+ /* Wait until SSP port is ready for slave clock operations */
+ for (timeout = 100; timeout != 0; --timeout) {
+ if (!(pxa_ssp_read_reg(ssp, SSSR) & SSSR_CSS))
+ break;
+ msleep(1);
+ }
+
+ if (timeout == 0)
+ dev_err(navpoint->dev,
+ "timeout waiting for SSSR[CSS] to clear\n");
+
+ if (gpio_is_valid(navpoint->gpio))
+ gpio_set_value(navpoint->gpio, 1);
+}
+
+static void navpoint_down(struct navpoint *navpoint)
+{
+ struct ssp_device *ssp = navpoint->ssp;
+
+ if (gpio_is_valid(navpoint->gpio))
+ gpio_set_value(navpoint->gpio, 0);
+
+ pxa_ssp_write_reg(ssp, SSCR0, 0);
+
+ clk_disable_unprepare(ssp->clk);
+}
+
+static int navpoint_open(struct input_dev *input)
+{
+ struct navpoint *navpoint = input_get_drvdata(input);
+
+ navpoint_up(navpoint);
+
+ return 0;
+}
+
+static void navpoint_close(struct input_dev *input)
+{
+ struct navpoint *navpoint = input_get_drvdata(input);
+
+ navpoint_down(navpoint);
+}
+
+static int __devinit navpoint_probe(struct platform_device *pdev)
+{
+ const struct navpoint_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
+ struct ssp_device *ssp;
+ struct input_dev *input;
+ struct navpoint *navpoint;
+ int error;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "no platform data\n");
+ return -EINVAL;
+ }
+
+ if (gpio_is_valid(pdata->gpio)) {
+ error = gpio_request_one(pdata->gpio, GPIOF_OUT_INIT_LOW,
+ "SYNAPTICS_ON");
+ if (error)
+ return error;
+ }
+
+ ssp = pxa_ssp_request(pdata->port, pdev->name);
+ if (!ssp) {
+ error = -ENODEV;
+ goto err_free_gpio;
+ }
+
+ /* HaRET does not disable devices before jumping into Linux */
+ if (pxa_ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) {
+ pxa_ssp_write_reg(ssp, SSCR0, 0);
+ dev_warn(&pdev->dev, "ssp%d already enabled\n", pdata->port);
+ }
+
+ navpoint = kzalloc(sizeof(*navpoint), GFP_KERNEL);
+ input = input_allocate_device();
+ if (!navpoint || !input) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ navpoint->ssp = ssp;
+ navpoint->input = input;
+ navpoint->dev = &pdev->dev;
+ navpoint->gpio = pdata->gpio;
+
+ input->name = pdev->name;
+ input->dev.parent = &pdev->dev;
+
+ __set_bit(EV_KEY, input->evbit);
+ __set_bit(EV_ABS, input->evbit);
+ __set_bit(BTN_LEFT, input->keybit);
+ __set_bit(BTN_TOUCH, input->keybit);
+ __set_bit(BTN_TOOL_FINGER, input->keybit);
+
+ input_set_abs_params(input, ABS_X,
+ NAVPOINT_X_MIN, NAVPOINT_X_MAX, 0, 0);
+ input_set_abs_params(input, ABS_Y,
+ NAVPOINT_Y_MIN, NAVPOINT_Y_MAX, 0, 0);
+ input_set_abs_params(input, ABS_PRESSURE,
+ NAVPOINT_PRESSURE_MIN, NAVPOINT_PRESSURE_MAX,
+ 0, 0);
+
+ input->open = navpoint_open;
+ input->close = navpoint_close;
+
+ input_set_drvdata(input, navpoint);
+
+ error = request_irq(ssp->irq, navpoint_irq, 0, pdev->name, navpoint);
+ if (error)
+ goto err_free_mem;
+
+ error = input_register_device(input);
+ if (error)
+ goto err_free_irq;
+
+ platform_set_drvdata(pdev, navpoint);
+ dev_dbg(&pdev->dev, "ssp%d, irq %d\n", pdata->port, ssp->irq);
+
+ return 0;
+
+err_free_irq:
+ free_irq(ssp->irq, &pdev->dev);
+err_free_mem:
+ input_free_device(input);
+ kfree(navpoint);
+ pxa_ssp_free(ssp);
+err_free_gpio:
+ if (gpio_is_valid(pdata->gpio))
+ gpio_free(pdata->gpio);
+
+ return error;
+}
+
+static int __devexit navpoint_remove(struct platform_device *pdev)
+{
+ const struct navpoint_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
+ struct navpoint *navpoint = platform_get_drvdata(pdev);
+ struct ssp_device *ssp = navpoint->ssp;
+
+ free_irq(ssp->irq, navpoint);
+
+ input_unregister_device(navpoint->input);
+ kfree(navpoint);
+
+ pxa_ssp_free(ssp);
+
+ if (gpio_is_valid(pdata->gpio))
+ gpio_free(pdata->gpio);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int navpoint_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct navpoint *navpoint = platform_get_drvdata(pdev);
+ struct input_dev *input = navpoint->input;
+
+ mutex_lock(&input->mutex);
+ if (input->users)
+ navpoint_down(navpoint);
+ mutex_unlock(&input->mutex);
+
+ return 0;
+}
+
+static int navpoint_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct navpoint *navpoint = platform_get_drvdata(pdev);
+ struct input_dev *input = navpoint->input;
+
+ mutex_lock(&input->mutex);
+ if (input->users)
+ navpoint_up(navpoint);
+ mutex_unlock(&input->mutex);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(navpoint_pm_ops, navpoint_suspend, navpoint_resume);
+
+static struct platform_driver navpoint_driver = {
+ .probe = navpoint_probe,
+ .remove = __devexit_p(navpoint_remove),
+ .driver = {
+ .name = "navpoint",
+ .owner = THIS_MODULE,
+ .pm = &navpoint_pm_ops,
+ },
+};
+
+module_platform_driver(navpoint_driver);
+
+MODULE_AUTHOR("Paul Parsons <lost.distance@yahoo.com>");
+MODULE_DESCRIPTION("Synaptics NavPoint (PXA27x SSP/SPI) driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:navpoint");
diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c
index 661a0ca3b3d6..3f5649f19082 100644
--- a/drivers/input/mouse/sentelic.c
+++ b/drivers/input/mouse/sentelic.c
@@ -41,7 +41,7 @@
#define GET_ABS_Y(packet) ((packet[2] << 2) | (packet[3] & 0x03))
/** Driver version. */
-static const char fsp_drv_ver[] = "1.0.0-K";
+static const char fsp_drv_ver[] = "1.1.0-K";
/*
* Make sure that the value being sent to FSP will not conflict with
@@ -303,6 +303,27 @@ static int fsp_get_revision(struct psmouse *psmouse, int *rev)
return 0;
}
+static int fsp_get_sn(struct psmouse *psmouse, int *sn)
+{
+ int v0, v1, v2;
+ int rc = -EIO;
+
+ /* production number since Cx is available at: 0x0b40 ~ 0x0b42 */
+ if (fsp_page_reg_write(psmouse, FSP_PAGE_0B))
+ goto out;
+ if (fsp_reg_read(psmouse, FSP_REG_SN0, &v0))
+ goto out;
+ if (fsp_reg_read(psmouse, FSP_REG_SN1, &v1))
+ goto out;
+ if (fsp_reg_read(psmouse, FSP_REG_SN2, &v2))
+ goto out;
+ *sn = (v0 << 16) | (v1 << 8) | v2;
+ rc = 0;
+out:
+ fsp_page_reg_write(psmouse, FSP_PAGE_DEFAULT);
+ return rc;
+}
+
static int fsp_get_buttons(struct psmouse *psmouse, int *btn)
{
static const int buttons[] = {
@@ -1000,16 +1021,21 @@ static int fsp_reconnect(struct psmouse *psmouse)
int fsp_init(struct psmouse *psmouse)
{
struct fsp_data *priv;
- int ver, rev;
+ int ver, rev, sn = 0;
int error;
if (fsp_get_version(psmouse, &ver) ||
fsp_get_revision(psmouse, &rev)) {
return -ENODEV;
}
+ if (ver >= FSP_VER_STL3888_C0) {
+ /* firmware information is only available since C0 */
+ fsp_get_sn(psmouse, &sn);
+ }
- psmouse_info(psmouse, "Finger Sensing Pad, hw: %d.%d.%d, sw: %s\n",
- ver >> 4, ver & 0x0F, rev, fsp_drv_ver);
+ psmouse_info(psmouse,
+ "Finger Sensing Pad, hw: %d.%d.%d, sn: %x, sw: %s\n",
+ ver >> 4, ver & 0x0F, rev, sn, fsp_drv_ver);
psmouse->private = priv = kzalloc(sizeof(struct fsp_data), GFP_KERNEL);
if (!priv)
diff --git a/drivers/input/mouse/sentelic.h b/drivers/input/mouse/sentelic.h
index 334de19e5ddb..aa697ece405b 100644
--- a/drivers/input/mouse/sentelic.h
+++ b/drivers/input/mouse/sentelic.h
@@ -65,6 +65,14 @@
#define FSP_BIT_SWC1_GST_GRP1 BIT(6)
#define FSP_BIT_SWC1_BX_COMPAT BIT(7)
+#define FSP_PAGE_0B (0x0b)
+#define FSP_PAGE_82 (0x82)
+#define FSP_PAGE_DEFAULT FSP_PAGE_82
+
+#define FSP_REG_SN0 (0x40)
+#define FSP_REG_SN1 (0x41)
+#define FSP_REG_SN2 (0x42)
+
/* Finger-sensing Pad packet formating related definitions */
/* absolute packet type */
diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c
index 17ff137b9bd5..d5928fd0c914 100644
--- a/drivers/input/mouse/sermouse.c
+++ b/drivers/input/mouse/sermouse.c
@@ -355,15 +355,4 @@ static struct serio_driver sermouse_drv = {
.disconnect = sermouse_disconnect,
};
-static int __init sermouse_init(void)
-{
- return serio_register_driver(&sermouse_drv);
-}
-
-static void __exit sermouse_exit(void)
-{
- serio_unregister_driver(&sermouse_drv);
-}
-
-module_init(sermouse_init);
-module_exit(sermouse_exit);
+module_serio_driver(sermouse_drv);
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index a4b14a41cbf4..c703d53be3a0 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -45,16 +45,6 @@
#define YMIN_NOMINAL 1408
#define YMAX_NOMINAL 4448
-/*
- * Synaptics touchpads report the y coordinate from bottom to top, which is
- * opposite from what userspace expects.
- * This function is used to invert y before reporting.
- */
-static int synaptics_invert_y(int y)
-{
- return YMAX_NOMINAL + YMIN_NOMINAL - y;
-}
-
/*****************************************************************************
* Stuff we need even when we do not want native Synaptics support
@@ -112,6 +102,16 @@ void synaptics_reset(struct psmouse *psmouse)
****************************************************************************/
/*
+ * Synaptics touchpads report the y coordinate from bottom to top, which is
+ * opposite from what userspace expects.
+ * This function is used to invert y before reporting.
+ */
+static int synaptics_invert_y(int y)
+{
+ return YMAX_NOMINAL + YMIN_NOMINAL - y;
+}
+
+/*
* Send a command to the synpatics touchpad by special commands
*/
static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param)
diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c
index eb9a3cfbeefa..e900d465aaf6 100644
--- a/drivers/input/mouse/vsxxxaa.c
+++ b/drivers/input/mouse/vsxxxaa.c
@@ -548,16 +548,4 @@ static struct serio_driver vsxxxaa_drv = {
.disconnect = vsxxxaa_disconnect,
};
-static int __init vsxxxaa_init(void)
-{
- return serio_register_driver(&vsxxxaa_drv);
-}
-
-static void __exit vsxxxaa_exit(void)
-{
- serio_unregister_driver(&vsxxxaa_drv);
-}
-
-module_init(vsxxxaa_init);
-module_exit(vsxxxaa_exit);
-
+module_serio_driver(vsxxxaa_drv);
diff --git a/drivers/input/of_keymap.c b/drivers/input/of_keymap.c
deleted file mode 100644
index 061493d57682..000000000000
--- a/drivers/input/of_keymap.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Helpers for open firmware matrix keyboard bindings
- *
- * Copyright (C) 2012 Google, Inc
- *
- * Author:
- * Olof Johansson <olof@lixom.net>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/input.h>
-#include <linux/of.h>
-#include <linux/input/matrix_keypad.h>
-#include <linux/export.h>
-#include <linux/gfp.h>
-#include <linux/slab.h>
-
-struct matrix_keymap_data *
-matrix_keyboard_of_fill_keymap(struct device_node *np,
- const char *propname)
-{
- struct matrix_keymap_data *kd;
- u32 *keymap;
- int proplen, i;
- const __be32 *prop;
-
- if (!np)
- return NULL;
-
- if (!propname)
- propname = "linux,keymap";
-
- prop = of_get_property(np, propname, &proplen);
- if (!prop)
- return NULL;
-
- if (proplen % sizeof(u32)) {
- pr_warn("Malformed keymap property %s in %s\n",
- propname, np->full_name);
- return NULL;
- }
-
- kd = kzalloc(sizeof(*kd), GFP_KERNEL);
- if (!kd)
- return NULL;
-
- kd->keymap = keymap = kzalloc(proplen, GFP_KERNEL);
- if (!kd->keymap) {
- kfree(kd);
- return NULL;
- }
-
- kd->keymap_size = proplen / sizeof(u32);
-
- for (i = 0; i < kd->keymap_size; i++) {
- u32 tmp = be32_to_cpup(prop + i);
- int key_code, row, col;
-
- row = (tmp >> 24) & 0xff;
- col = (tmp >> 16) & 0xff;
- key_code = tmp & 0xffff;
- keymap[i] = KEY(row, col, key_code);
- }
-
- return kd;
-}
-EXPORT_SYMBOL_GPL(matrix_keyboard_of_fill_keymap);
-
-void matrix_keyboard_of_free_keymap(const struct matrix_keymap_data *kd)
-{
- if (kd) {
- kfree(kd->keymap);
- kfree(kd);
- }
-}
-EXPORT_SYMBOL_GPL(matrix_keyboard_of_free_keymap);
diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c
index 43494742541c..0c42497aaaf4 100644
--- a/drivers/input/serio/pcips2.c
+++ b/drivers/input/serio/pcips2.c
@@ -206,6 +206,7 @@ static const struct pci_device_id pcips2_ids[] = {
},
{ 0, }
};
+MODULE_DEVICE_TABLE(pci, pcips2_ids);
static struct pci_driver pcips2_driver = {
.name = "pcips2",
@@ -214,20 +215,8 @@ static struct pci_driver pcips2_driver = {
.remove = __devexit_p(pcips2_remove),
};
-static int __init pcips2_init(void)
-{
- return pci_register_driver(&pcips2_driver);
-}
-
-static void __exit pcips2_exit(void)
-{
- pci_unregister_driver(&pcips2_driver);
-}
-
-module_init(pcips2_init);
-module_exit(pcips2_exit);
+module_pci_driver(pcips2_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
MODULE_DESCRIPTION("PCI PS/2 keyboard/mouse driver");
-MODULE_DEVICE_TABLE(pci, pcips2_ids);
diff --git a/drivers/input/serio/ps2mult.c b/drivers/input/serio/ps2mult.c
index 15aa81c9f1fb..a76fb64f03db 100644
--- a/drivers/input/serio/ps2mult.c
+++ b/drivers/input/serio/ps2mult.c
@@ -304,15 +304,4 @@ static struct serio_driver ps2mult_drv = {
.reconnect = ps2mult_reconnect,
};
-static int __init ps2mult_init(void)
-{
- return serio_register_driver(&ps2mult_drv);
-}
-
-static void __exit ps2mult_exit(void)
-{
- serio_unregister_driver(&ps2mult_drv);
-}
-
-module_init(ps2mult_init);
-module_exit(ps2mult_exit);
+module_serio_driver(ps2mult_drv);
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
index 4494233d331a..59df2e7317a3 100644
--- a/drivers/input/serio/serio_raw.c
+++ b/drivers/input/serio/serio_raw.c
@@ -165,31 +165,38 @@ static ssize_t serio_raw_read(struct file *file, char __user *buffer,
struct serio_raw *serio_raw = client->serio_raw;
char uninitialized_var(c);
ssize_t read = 0;
- int retval;
+ int error;
- if (serio_raw->dead)
- return -ENODEV;
+ for (;;) {
+ if (serio_raw->dead)
+ return -ENODEV;
- if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK))
- return -EAGAIN;
+ if (serio_raw->head == serio_raw->tail &&
+ (file->f_flags & O_NONBLOCK))
+ return -EAGAIN;
- retval = wait_event_interruptible(serio_raw->wait,
- serio_raw->head != serio_raw->tail || serio_raw->dead);
- if (retval)
- return retval;
+ if (count == 0)
+ break;
- if (serio_raw->dead)
- return -ENODEV;
+ while (read < count && serio_raw_fetch_byte(serio_raw, &c)) {
+ if (put_user(c, buffer++))
+ return -EFAULT;
+ read++;
+ }
- while (read < count && serio_raw_fetch_byte(serio_raw, &c)) {
- if (put_user(c, buffer++)) {
- retval = -EFAULT;
+ if (read)
break;
+
+ if (!(file->f_flags & O_NONBLOCK)) {
+ error = wait_event_interruptible(serio_raw->wait,
+ serio_raw->head != serio_raw->tail ||
+ serio_raw->dead);
+ if (error)
+ return error;
}
- read++;
}
- return read ?: retval;
+ return read;
}
static ssize_t serio_raw_write(struct file *file, const char __user *buffer,
@@ -197,8 +204,7 @@ static ssize_t serio_raw_write(struct file *file, const char __user *buffer,
{
struct serio_raw_client *client = file->private_data;
struct serio_raw *serio_raw = client->serio_raw;
- ssize_t written = 0;
- int retval;
+ int retval = 0;
unsigned char c;
retval = mutex_lock_interruptible(&serio_raw_mutex);
@@ -218,16 +224,20 @@ static ssize_t serio_raw_write(struct file *file, const char __user *buffer,
retval = -EFAULT;
goto out;
}
+
if (serio_write(serio_raw->serio, c)) {
- retval = -EIO;
+ /* Either signal error or partial write */
+ if (retval == 0)
+ retval = -EIO;
goto out;
}
- written++;
+
+ retval++;
}
out:
mutex_unlock(&serio_raw_mutex);
- return written ?: retval;
+ return retval;
}
static unsigned int serio_raw_poll(struct file *file, poll_table *wait)
@@ -432,15 +442,4 @@ static struct serio_driver serio_raw_drv = {
.manual_bind = true,
};
-static int __init serio_raw_init(void)
-{
- return serio_register_driver(&serio_raw_drv);
-}
-
-static void __exit serio_raw_exit(void)
-{
- serio_unregister_driver(&serio_raw_drv);
-}
-
-module_init(serio_raw_init);
-module_exit(serio_raw_exit);
+module_serio_driver(serio_raw_drv);
diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c
index d96d4c2a76a9..1e983bec7d86 100644
--- a/drivers/input/serio/xilinx_ps2.c
+++ b/drivers/input/serio/xilinx_ps2.c
@@ -73,7 +73,8 @@ struct xps2data {
spinlock_t lock;
void __iomem *base_address; /* virt. address of control registers */
unsigned int flags;
- struct serio serio; /* serio */
+ struct serio *serio; /* serio */
+ struct device *dev;
};
/************************************/
@@ -119,7 +120,7 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id)
/* Check which interrupt is active */
if (intr_sr & XPS2_IPIXR_RX_OVF)
- dev_warn(drvdata->serio.dev.parent, "receive overrun error\n");
+ dev_warn(drvdata->dev, "receive overrun error\n");
if (intr_sr & XPS2_IPIXR_RX_ERR)
drvdata->flags |= SERIO_PARITY;
@@ -132,10 +133,10 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id)
/* Error, if a byte is not received */
if (status) {
- dev_err(drvdata->serio.dev.parent,
+ dev_err(drvdata->dev,
"wrong rcvd byte count (%d)\n", status);
} else {
- serio_interrupt(&drvdata->serio, c, drvdata->flags);
+ serio_interrupt(drvdata->serio, c, drvdata->flags);
drvdata->flags = 0;
}
}
@@ -193,7 +194,7 @@ static int sxps2_open(struct serio *pserio)
error = request_irq(drvdata->irq, &xps2_interrupt, 0,
DRIVER_NAME, drvdata);
if (error) {
- dev_err(drvdata->serio.dev.parent,
+ dev_err(drvdata->dev,
"Couldn't allocate interrupt %d\n", drvdata->irq);
return error;
}
@@ -259,15 +260,16 @@ static int __devinit xps2_of_probe(struct platform_device *ofdev)
}
drvdata = kzalloc(sizeof(struct xps2data), GFP_KERNEL);
- if (!drvdata) {
- dev_err(dev, "Couldn't allocate device private record\n");
- return -ENOMEM;
+ serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ if (!drvdata || !serio) {
+ error = -ENOMEM;
+ goto failed1;
}
- dev_set_drvdata(dev, drvdata);
-
spin_lock_init(&drvdata->lock);
drvdata->irq = r_irq.start;
+ drvdata->serio = serio;
+ drvdata->dev = dev;
phys_addr = r_mem.start;
remap_size = resource_size(&r_mem);
@@ -298,7 +300,6 @@ static int __devinit xps2_of_probe(struct platform_device *ofdev)
(unsigned long long)phys_addr, drvdata->base_address,
drvdata->irq);
- serio = &drvdata->serio;
serio->id.type = SERIO_8042;
serio->write = sxps2_write;
serio->open = sxps2_open;
@@ -312,13 +313,14 @@ static int __devinit xps2_of_probe(struct platform_device *ofdev)
serio_register_port(serio);
+ platform_set_drvdata(ofdev, drvdata);
return 0; /* success */
failed2:
release_mem_region(phys_addr, remap_size);
failed1:
+ kfree(serio);
kfree(drvdata);
- dev_set_drvdata(dev, NULL);
return error;
}
@@ -333,22 +335,21 @@ failed1:
*/
static int __devexit xps2_of_remove(struct platform_device *of_dev)
{
- struct device *dev = &of_dev->dev;
- struct xps2data *drvdata = dev_get_drvdata(dev);
+ struct xps2data *drvdata = platform_get_drvdata(of_dev);
struct resource r_mem; /* IO mem resources */
- serio_unregister_port(&drvdata->serio);
+ serio_unregister_port(drvdata->serio);
iounmap(drvdata->base_address);
/* Get iospace of the device */
if (of_address_to_resource(of_dev->dev.of_node, 0, &r_mem))
- dev_err(dev, "invalid address\n");
+ dev_err(drvdata->dev, "invalid address\n");
else
release_mem_region(r_mem.start, resource_size(&r_mem));
kfree(drvdata);
- dev_set_drvdata(dev, NULL);
+ platform_set_drvdata(of_dev, NULL);
return 0;
}
diff --git a/drivers/input/tablet/acecad.c b/drivers/input/tablet/acecad.c
index f8b0b1df9138..e062ec899ca1 100644
--- a/drivers/input/tablet/acecad.c
+++ b/drivers/input/tablet/acecad.c
@@ -51,6 +51,7 @@ struct usb_acecad {
char name[128];
char phys[64];
struct usb_device *usbdev;
+ struct usb_interface *intf;
struct input_dev *input;
struct urb *irq;
@@ -63,6 +64,7 @@ static void usb_acecad_irq(struct urb *urb)
struct usb_acecad *acecad = urb->context;
unsigned char *data = acecad->data;
struct input_dev *dev = acecad->input;
+ struct usb_interface *intf = acecad->intf;
int prox, status;
switch (urb->status) {
@@ -73,10 +75,12 @@ static void usb_acecad_irq(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __func__, urb->status);
+ dev_dbg(&intf->dev, "%s - urb shutting down with status: %d\n",
+ __func__, urb->status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __func__, urb->status);
+ dev_dbg(&intf->dev, "%s - nonzero urb status received: %d\n",
+ __func__, urb->status);
goto resubmit;
}
@@ -105,8 +109,10 @@ static void usb_acecad_irq(struct urb *urb)
resubmit:
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status)
- err("can't resubmit intr, %s-%s/input0, status %d",
- acecad->usbdev->bus->bus_name, acecad->usbdev->devpath, status);
+ dev_err(&intf->dev,
+ "can't resubmit intr, %s-%s/input0, status %d\n",
+ acecad->usbdev->bus->bus_name,
+ acecad->usbdev->devpath, status);
}
static int usb_acecad_open(struct input_dev *dev)
@@ -168,6 +174,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
}
acecad->usbdev = dev;
+ acecad->intf = intf;
acecad->input = input_dev;
if (dev->manufacturer)
diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c
index 205d16aab441..ee83c3904ee8 100644
--- a/drivers/input/tablet/aiptek.c
+++ b/drivers/input/tablet/aiptek.c
@@ -309,6 +309,7 @@ struct aiptek_settings {
struct aiptek {
struct input_dev *inputdev; /* input device struct */
struct usb_device *usbdev; /* usb device struct */
+ struct usb_interface *intf; /* usb interface struct */
struct urb *urb; /* urb for incoming reports */
dma_addr_t data_dma; /* our dma stuffage */
struct aiptek_features features; /* tablet's array of features */
@@ -435,6 +436,7 @@ static void aiptek_irq(struct urb *urb)
struct aiptek *aiptek = urb->context;
unsigned char *data = aiptek->data;
struct input_dev *inputdev = aiptek->inputdev;
+ struct usb_interface *intf = aiptek->intf;
int jitterable = 0;
int retval, macro, x, y, z, left, right, middle, p, dv, tip, bs, pck;
@@ -447,13 +449,13 @@ static void aiptek_irq(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* This urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __func__, urb->status);
+ dev_dbg(&intf->dev, "%s - urb shutting down with status: %d\n",
+ __func__, urb->status);
return;
default:
- dbg("%s - nonzero urb status received: %d",
- __func__, urb->status);
+ dev_dbg(&intf->dev, "%s - nonzero urb status received: %d\n",
+ __func__, urb->status);
goto exit;
}
@@ -785,7 +787,7 @@ static void aiptek_irq(struct urb *urb)
1 | AIPTEK_REPORT_TOOL_UNKNOWN);
input_sync(inputdev);
} else {
- dbg("Unknown report %d", data[0]);
+ dev_dbg(&intf->dev, "Unknown report %d\n", data[0]);
}
/* Jitter may occur when the user presses a button on the stlyus
@@ -811,8 +813,9 @@ static void aiptek_irq(struct urb *urb)
exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval != 0) {
- err("%s - usb_submit_urb failed with result %d",
- __func__, retval);
+ dev_err(&intf->dev,
+ "%s - usb_submit_urb failed with result %d\n",
+ __func__, retval);
}
}
@@ -912,8 +915,9 @@ aiptek_command(struct aiptek *aiptek, unsigned char command, unsigned char data)
if ((ret =
aiptek_set_report(aiptek, 3, 2, buf, sizeof_buf)) != sizeof_buf) {
- dbg("aiptek_program: failed, tried to send: 0x%02x 0x%02x",
- command, data);
+ dev_dbg(&aiptek->intf->dev,
+ "aiptek_program: failed, tried to send: 0x%02x 0x%02x\n",
+ command, data);
}
kfree(buf);
return ret < 0 ? ret : 0;
@@ -947,8 +951,9 @@ aiptek_query(struct aiptek *aiptek, unsigned char command, unsigned char data)
if ((ret =
aiptek_get_report(aiptek, 3, 2, buf, sizeof_buf)) != sizeof_buf) {
- dbg("aiptek_query failed: returned 0x%02x 0x%02x 0x%02x",
- buf[0], buf[1], buf[2]);
+ dev_dbg(&aiptek->intf->dev,
+ "aiptek_query failed: returned 0x%02x 0x%02x 0x%02x\n",
+ buf[0], buf[1], buf[2]);
ret = -EIO;
} else {
ret = get_unaligned_le16(buf + 1);
@@ -1726,6 +1731,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
aiptek->inputdev = inputdev;
aiptek->usbdev = usbdev;
+ aiptek->intf = intf;
aiptek->ifnum = intf->altsetting[0].desc.bInterfaceNumber;
aiptek->inDelay = 0;
aiptek->endDelay = 0;
@@ -1856,7 +1862,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
if (i == ARRAY_SIZE(speeds)) {
dev_info(&intf->dev,
"Aiptek tried all speeds, no sane response\n");
- goto fail2;
+ goto fail3;
}
/* Associate this driver's struct with the usb interface.
diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c
index 89a297801dce..29e01ab6859f 100644
--- a/drivers/input/tablet/gtco.c
+++ b/drivers/input/tablet/gtco.c
@@ -2,8 +2,6 @@
GTCO digitizer USB driver
-Use the err() and dbg() macros from usb.h for system logging
-
TO CHECK: Is pressure done right on report 5?
Copyright (C) 2006 GTCO CalComp
@@ -108,6 +106,7 @@ struct gtco {
struct input_dev *inputdevice; /* input device struct pointer */
struct usb_device *usbdev; /* the usb device for this device */
+ struct usb_interface *intf; /* the usb interface for this device */
struct urb *urbinfo; /* urb for incoming reports */
dma_addr_t buf_dma; /* dma addr of the data buffer*/
unsigned char * buffer; /* databuffer for reports */
@@ -202,6 +201,7 @@ struct hid_descriptor
static void parse_hid_report_descriptor(struct gtco *device, char * report,
int length)
{
+ struct device *ddev = &device->intf->dev;
int x, i = 0;
/* Tag primitive vars */
@@ -228,7 +228,7 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
char indentstr[10] = "";
- dbg("======>>>>>>PARSE<<<<<<======");
+ dev_dbg(ddev, "======>>>>>>PARSE<<<<<<======\n");
/* Walk this report and pull out the info we need */
while (i < length) {
@@ -277,11 +277,11 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
else if (data == 3)
strcpy(globtype, "Var|Const");
- dbg("::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits",
- globalval[TAG_GLOB_REPORT_ID], inputnum,
- globalval[TAG_GLOB_LOG_MAX], globalval[TAG_GLOB_LOG_MAX],
- globalval[TAG_GLOB_LOG_MIN], globalval[TAG_GLOB_LOG_MIN],
- globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]);
+ dev_dbg(ddev, "::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits\n",
+ globalval[TAG_GLOB_REPORT_ID], inputnum,
+ globalval[TAG_GLOB_LOG_MAX], globalval[TAG_GLOB_LOG_MAX],
+ globalval[TAG_GLOB_LOG_MIN], globalval[TAG_GLOB_LOG_MIN],
+ globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]);
/*
@@ -292,7 +292,7 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
*/
switch (inputnum) {
case 0: /* X coord */
- dbg("GER: X Usage: 0x%x", usage);
+ dev_dbg(ddev, "GER: X Usage: 0x%x\n", usage);
if (device->max_X == 0) {
device->max_X = globalval[TAG_GLOB_LOG_MAX];
device->min_X = globalval[TAG_GLOB_LOG_MIN];
@@ -300,7 +300,7 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
break;
case 1: /* Y coord */
- dbg("GER: Y Usage: 0x%x", usage);
+ dev_dbg(ddev, "GER: Y Usage: 0x%x\n", usage);
if (device->max_Y == 0) {
device->max_Y = globalval[TAG_GLOB_LOG_MAX];
device->min_Y = globalval[TAG_GLOB_LOG_MIN];
@@ -350,10 +350,10 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
maintype = 'S';
if (data == 0) {
- dbg("======>>>>>> Physical");
+ dev_dbg(ddev, "======>>>>>> Physical\n");
strcpy(globtype, "Physical");
} else
- dbg("======>>>>>>");
+ dev_dbg(ddev, "======>>>>>>\n");
/* Indent the debug output */
indent++;
@@ -368,7 +368,7 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
break;
case TAG_MAIN_COL_END:
- dbg("<<<<<<======");
+ dev_dbg(ddev, "<<<<<<======\n");
maintype = 'E';
indent--;
for (x = 0; x < indent; x++)
@@ -384,18 +384,18 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
switch (size) {
case 1:
- dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
- indentstr, tag, maintype, size, globtype, data);
+ dev_dbg(ddev, "%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x\n",
+ indentstr, tag, maintype, size, globtype, data);
break;
case 2:
- dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
- indentstr, tag, maintype, size, globtype, data16);
+ dev_dbg(ddev, "%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x\n",
+ indentstr, tag, maintype, size, globtype, data16);
break;
case 4:
- dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
- indentstr, tag, maintype, size, globtype, data32);
+ dev_dbg(ddev, "%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x\n",
+ indentstr, tag, maintype, size, globtype, data32);
break;
}
break;
@@ -465,26 +465,26 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
if (tag < TAG_GLOB_MAX) {
switch (size) {
case 1:
- dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",
- indentstr, globtype, tag, size, data);
+ dev_dbg(ddev, "%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x\n",
+ indentstr, globtype, tag, size, data);
globalval[tag] = data;
break;
case 2:
- dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",
- indentstr, globtype, tag, size, data16);
+ dev_dbg(ddev, "%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x\n",
+ indentstr, globtype, tag, size, data16);
globalval[tag] = data16;
break;
case 4:
- dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",
- indentstr, globtype, tag, size, data32);
+ dev_dbg(ddev, "%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x\n",
+ indentstr, globtype, tag, size, data32);
globalval[tag] = data32;
break;
}
} else {
- dbg("%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d ",
- indentstr, tag, size);
+ dev_dbg(ddev, "%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d\n",
+ indentstr, tag, size);
}
break;
@@ -511,18 +511,18 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report,
switch (size) {
case 1:
- dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
- indentstr, tag, globtype, size, data);
+ dev_dbg(ddev, "%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x\n",
+ indentstr, tag, globtype, size, data);
break;
case 2:
- dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
- indentstr, tag, globtype, size, data16);
+ dev_dbg(ddev, "%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x\n",
+ indentstr, tag, globtype, size, data16);
break;
case 4:
- dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
- indentstr, tag, globtype, size, data32);
+ dev_dbg(ddev, "%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x\n",
+ indentstr, tag, globtype, size, data32);
break;
}
@@ -714,8 +714,9 @@ static void gtco_urb_callback(struct urb *urbinfo)
* the rest as 0
*/
val = device->buffer[5] & MASK_BUTTON;
- dbg("======>>>>>>REPORT 1: val 0x%X(%d)",
- val, val);
+ dev_dbg(&device->intf->dev,
+ "======>>>>>>REPORT 1: val 0x%X(%d)\n",
+ val, val);
/*
* We don't apply any meaning to the button
@@ -808,7 +809,8 @@ static void gtco_urb_callback(struct urb *urbinfo)
resubmit:
rc = usb_submit_urb(urbinfo, GFP_ATOMIC);
if (rc != 0)
- err("usb_submit_urb failed rc=0x%x", rc);
+ dev_err(&device->intf->dev,
+ "usb_submit_urb failed rc=0x%x\n", rc);
}
/*
@@ -838,7 +840,7 @@ static int gtco_probe(struct usb_interface *usbinterface,
gtco = kzalloc(sizeof(struct gtco), GFP_KERNEL);
input_dev = input_allocate_device();
if (!gtco || !input_dev) {
- err("No more memory");
+ dev_err(&usbinterface->dev, "No more memory\n");
error = -ENOMEM;
goto err_free_devs;
}
@@ -848,12 +850,13 @@ static int gtco_probe(struct usb_interface *usbinterface,
/* Save interface information */
gtco->usbdev = usb_get_dev(interface_to_usbdev(usbinterface));
+ gtco->intf = usbinterface;
/* Allocate some data for incoming reports */
gtco->buffer = usb_alloc_coherent(gtco->usbdev, REPORT_MAX_SIZE,
GFP_KERNEL, &gtco->buf_dma);
if (!gtco->buffer) {
- err("No more memory for us buffers");
+ dev_err(&usbinterface->dev, "No more memory for us buffers\n");
error = -ENOMEM;
goto err_free_devs;
}
@@ -861,7 +864,7 @@ static int gtco_probe(struct usb_interface *usbinterface,
/* Allocate URB for reports */
gtco->urbinfo = usb_alloc_urb(0, GFP_KERNEL);
if (!gtco->urbinfo) {
- err("Failed to allocate URB");
+ dev_err(&usbinterface->dev, "Failed to allocate URB\n");
error = -ENOMEM;
goto err_free_buf;
}
@@ -873,14 +876,14 @@ static int gtco_probe(struct usb_interface *usbinterface,
endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
/* Some debug */
- dbg("gtco # interfaces: %d", usbinterface->num_altsetting);
- dbg("num endpoints: %d", usbinterface->cur_altsetting->desc.bNumEndpoints);
- dbg("interface class: %d", usbinterface->cur_altsetting->desc.bInterfaceClass);
- dbg("endpoint: attribute:0x%x type:0x%x", endpoint->bmAttributes, endpoint->bDescriptorType);
+ dev_dbg(&usbinterface->dev, "gtco # interfaces: %d\n", usbinterface->num_altsetting);
+ dev_dbg(&usbinterface->dev, "num endpoints: %d\n", usbinterface->cur_altsetting->desc.bNumEndpoints);
+ dev_dbg(&usbinterface->dev, "interface class: %d\n", usbinterface->cur_altsetting->desc.bInterfaceClass);
+ dev_dbg(&usbinterface->dev, "endpoint: attribute:0x%x type:0x%x\n", endpoint->bmAttributes, endpoint->bDescriptorType);
if (usb_endpoint_xfer_int(endpoint))
- dbg("endpoint: we have interrupt endpoint\n");
+ dev_dbg(&usbinterface->dev, "endpoint: we have interrupt endpoint\n");
- dbg("endpoint extra len:%d ", usbinterface->altsetting[0].extralen);
+ dev_dbg(&usbinterface->dev, "endpoint extra len:%d\n", usbinterface->altsetting[0].extralen);
/*
* Find the HID descriptor so we can find out the size of the
@@ -888,17 +891,19 @@ static int gtco_probe(struct usb_interface *usbinterface,
*/
if (usb_get_extra_descriptor(usbinterface->cur_altsetting,
HID_DEVICE_TYPE, &hid_desc) != 0){
- err("Can't retrieve exta USB descriptor to get hid report descriptor length");
+ dev_err(&usbinterface->dev,
+ "Can't retrieve exta USB descriptor to get hid report descriptor length\n");
error = -EIO;
goto err_free_urb;
}
- dbg("Extra descriptor success: type:%d len:%d",
- hid_desc->bDescriptorType, hid_desc->wDescriptorLength);
+ dev_dbg(&usbinterface->dev,
+ "Extra descriptor success: type:%d len:%d\n",
+ hid_desc->bDescriptorType, hid_desc->wDescriptorLength);
report = kzalloc(le16_to_cpu(hid_desc->wDescriptorLength), GFP_KERNEL);
if (!report) {
- err("No more memory for report");
+ dev_err(&usbinterface->dev, "No more memory for report\n");
error = -ENOMEM;
goto err_free_urb;
}
@@ -915,7 +920,7 @@ static int gtco_probe(struct usb_interface *usbinterface,
le16_to_cpu(hid_desc->wDescriptorLength),
5000); /* 5 secs */
- dbg("usb_control_msg result: %d", result);
+ dev_dbg(&usbinterface->dev, "usb_control_msg result: %d\n", result);
if (result == le16_to_cpu(hid_desc->wDescriptorLength)) {
parse_hid_report_descriptor(gtco, report, result);
break;
@@ -926,8 +931,9 @@ static int gtco_probe(struct usb_interface *usbinterface,
/* If we didn't get the report, fail */
if (result != le16_to_cpu(hid_desc->wDescriptorLength)) {
- err("Failed to get HID Report Descriptor of size: %d",
- hid_desc->wDescriptorLength);
+ dev_err(&usbinterface->dev,
+ "Failed to get HID Report Descriptor of size: %d\n",
+ hid_desc->wDescriptorLength);
error = -EIO;
goto err_free_urb;
}
diff --git a/drivers/input/tablet/kbtab.c b/drivers/input/tablet/kbtab.c
index 85a5b40333ac..3fba74b9b602 100644
--- a/drivers/input/tablet/kbtab.c
+++ b/drivers/input/tablet/kbtab.c
@@ -33,6 +33,7 @@ struct kbtab {
dma_addr_t data_dma;
struct input_dev *dev;
struct usb_device *usbdev;
+ struct usb_interface *intf;
struct urb *irq;
char phys[32];
};
@@ -53,10 +54,14 @@ static void kbtab_irq(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __func__, urb->status);
+ dev_dbg(&kbtab->intf->dev,
+ "%s - urb shutting down with status: %d\n",
+ __func__, urb->status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __func__, urb->status);
+ dev_dbg(&kbtab->intf->dev,
+ "%s - nonzero urb status received: %d\n",
+ __func__, urb->status);
goto exit;
}
@@ -80,8 +85,9 @@ static void kbtab_irq(struct urb *urb)
exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
- err("%s - usb_submit_urb failed with result %d",
- __func__, retval);
+ dev_err(&kbtab->intf->dev,
+ "%s - usb_submit_urb failed with result %d\n",
+ __func__, retval);
}
static struct usb_device_id kbtab_ids[] = {
@@ -131,6 +137,7 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i
goto fail2;
kbtab->usbdev = dev;
+ kbtab->intf = intf;
kbtab->dev = input_dev;
usb_make_path(dev, kbtab->phys, sizeof(kbtab->phys));
diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h
index b4842d0e61dd..b79d45198d82 100644
--- a/drivers/input/tablet/wacom.h
+++ b/drivers/input/tablet/wacom.h
@@ -135,6 +135,6 @@ extern const struct usb_device_id wacom_ids[];
void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);
void wacom_setup_device_quirks(struct wacom_features *features);
-void wacom_setup_input_capabilities(struct input_dev *input_dev,
- struct wacom_wac *wacom_wac);
+int wacom_setup_input_capabilities(struct input_dev *input_dev,
+ struct wacom_wac *wacom_wac);
#endif
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index 0d269212931e..cad5602d3ce4 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -28,6 +28,7 @@
#define HID_USAGE_Y_TILT 0x3e
#define HID_USAGE_FINGER 0x22
#define HID_USAGE_STYLUS 0x20
+#define HID_USAGE_CONTACTMAX 0x55
#define HID_COLLECTION 0xa1
#define HID_COLLECTION_LOGICAL 0x02
#define HID_COLLECTION_END 0xc0
@@ -99,6 +100,7 @@ static int wacom_set_report(struct usb_interface *intf, u8 type, u8 id,
static void wacom_sys_irq(struct urb *urb)
{
struct wacom *wacom = urb->context;
+ struct device *dev = &wacom->intf->dev;
int retval;
switch (urb->status) {
@@ -109,10 +111,12 @@ static void wacom_sys_irq(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __func__, urb->status);
+ dev_dbg(dev, "%s - urb shutting down with status: %d\n",
+ __func__, urb->status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __func__, urb->status);
+ dev_dbg(dev, "%s - nonzero urb status received: %d\n",
+ __func__, urb->status);
goto exit;
}
@@ -122,8 +126,8 @@ static void wacom_sys_irq(struct urb *urb)
usb_mark_last_busy(wacom->usbdev);
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
- err ("%s - usb_submit_urb failed with result %d",
- __func__, retval);
+ dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
+ __func__, retval);
}
static int wacom_open(struct input_dev *dev)
@@ -201,6 +205,27 @@ static int wacom_parse_logical_collection(unsigned char *report,
return length;
}
+static void wacom_retrieve_report_data(struct usb_interface *intf,
+ struct wacom_features *features)
+{
+ int result = 0;
+ unsigned char *rep_data;
+
+ rep_data = kmalloc(2, GFP_KERNEL);
+ if (rep_data) {
+
+ rep_data[0] = 12;
+ result = wacom_get_report(intf, WAC_HID_FEATURE_REPORT,
+ rep_data[0], &rep_data, 2,
+ WAC_MSG_RETRIES);
+
+ if (result >= 0 && rep_data[1] > 2)
+ features->touch_max = rep_data[1];
+
+ kfree(rep_data);
+ }
+}
+
/*
* Interface Descriptor of wacom devices can be incomplete and
* inconsistent so wacom_features table is used to store stylus
@@ -233,6 +258,9 @@ static int wacom_parse_logical_collection(unsigned char *report,
* 3rd gen Bamboo Touch no longer define a Digitizer-Finger Pysical
* Collection. Instead they define a Logical Collection with a single
* Logical Maximum for both X and Y.
+ *
+ * Intuos5 touch interface does not contain useful data. We deal with
+ * this after returning from this function.
*/
static int wacom_parse_hid(struct usb_interface *intf,
struct hid_descriptor *hid_desc,
@@ -292,6 +320,10 @@ static int wacom_parse_hid(struct usb_interface *intf,
/* need to reset back */
features->pktlen = WACOM_PKGLEN_TPC2FG;
}
+
+ if (features->type == MTSCREEN)
+ features->pktlen = WACOM_PKGLEN_MTOUCH;
+
if (features->type == BAMBOO_PT) {
/* need to reset back */
features->pktlen = WACOM_PKGLEN_BBTOUCH;
@@ -324,18 +356,15 @@ static int wacom_parse_hid(struct usb_interface *intf,
case HID_USAGE_Y:
if (usage == WCM_DESKTOP) {
if (finger) {
- features->device_type = BTN_TOOL_FINGER;
- if (features->type == TABLETPC2FG) {
- /* need to reset back */
- features->pktlen = WACOM_PKGLEN_TPC2FG;
+ int type = features->type;
+
+ if (type == TABLETPC2FG || type == MTSCREEN) {
features->y_max =
get_unaligned_le16(&report[i + 3]);
features->y_phy =
get_unaligned_le16(&report[i + 6]);
i += 7;
- } else if (features->type == BAMBOO_PT) {
- /* need to reset back */
- features->pktlen = WACOM_PKGLEN_BBTOUCH;
+ } else if (type == BAMBOO_PT) {
features->y_phy =
get_unaligned_le16(&report[i + 3]);
features->y_max =
@@ -349,10 +378,6 @@ static int wacom_parse_hid(struct usb_interface *intf,
i += 4;
}
} else if (pen) {
- /* penabled only accepts exact bytes of data */
- if (features->type == TABLETPC2FG)
- features->pktlen = WACOM_PKGLEN_GRAPHIRE;
- features->device_type = BTN_TOOL_PEN;
features->y_max =
get_unaligned_le16(&report[i + 3]);
i += 4;
@@ -374,6 +399,11 @@ static int wacom_parse_hid(struct usb_interface *intf,
pen = 1;
i++;
break;
+
+ case HID_USAGE_CONTACTMAX:
+ wacom_retrieve_report_data(intf, features);
+ i++;
+ break;
}
break;
@@ -410,22 +440,29 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
if (!rep_data)
return error;
- /* ask to report tablet data if it is MT Tablet PC or
- * not a Tablet PC */
- if (features->type == TABLETPC2FG) {
- do {
- rep_data[0] = 3;
- rep_data[1] = 4;
- rep_data[2] = 0;
- rep_data[3] = 0;
- report_id = 3;
- error = wacom_set_report(intf, WAC_HID_FEATURE_REPORT,
- report_id, rep_data, 4, 1);
- if (error >= 0)
- error = wacom_get_report(intf,
- WAC_HID_FEATURE_REPORT,
- report_id, rep_data, 4, 1);
- } while ((error < 0 || rep_data[1] != 4) && limit++ < WAC_MSG_RETRIES);
+ /* ask to report Wacom data */
+ if (features->device_type == BTN_TOOL_FINGER) {
+ /* if it is an MT Tablet PC touch */
+ if (features->type == TABLETPC2FG ||
+ features->type == MTSCREEN) {
+ do {
+ rep_data[0] = 3;
+ rep_data[1] = 4;
+ rep_data[2] = 0;
+ rep_data[3] = 0;
+ report_id = 3;
+ error = wacom_set_report(intf,
+ WAC_HID_FEATURE_REPORT,
+ report_id,
+ rep_data, 4, 1);
+ if (error >= 0)
+ error = wacom_get_report(intf,
+ WAC_HID_FEATURE_REPORT,
+ report_id,
+ rep_data, 4, 1);
+ } while ((error < 0 || rep_data[1] != 4) &&
+ limit++ < WAC_MSG_RETRIES);
+ }
} else if (features->type != TABLETPC &&
features->type != WIRELESS &&
features->device_type == BTN_TOOL_PEN) {
@@ -447,7 +484,7 @@ static int wacom_query_tablet_data(struct usb_interface *intf, struct wacom_feat
}
static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
- struct wacom_features *features)
+ struct wacom_features *features)
{
int error = 0;
struct usb_host_interface *interface = intf->cur_altsetting;
@@ -475,16 +512,21 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
}
}
- /* only Tablet PCs and Bamboo P&T need to retrieve the info */
- if ((features->type != TABLETPC) && (features->type != TABLETPC2FG) &&
- (features->type != BAMBOO_PT))
+ /* only devices that support touch need to retrieve the info */
+ if (features->type != TABLETPC &&
+ features->type != TABLETPC2FG &&
+ features->type != BAMBOO_PT &&
+ features->type != MTSCREEN) {
goto out;
+ }
- if (usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc)) {
- if (usb_get_extra_descriptor(&interface->endpoint[0],
- HID_DEVICET_REPORT, &hid_desc)) {
- printk("wacom: can not retrieve extra class descriptor\n");
- error = 1;
+ error = usb_get_extra_descriptor(interface, HID_DEVICET_HID, &hid_desc);
+ if (error) {
+ error = usb_get_extra_descriptor(&interface->endpoint[0],
+ HID_DEVICET_REPORT, &hid_desc);
+ if (error) {
+ dev_err(&intf->dev,
+ "can not retrieve extra class descriptor\n");
goto out;
}
}
@@ -574,23 +616,39 @@ static void wacom_remove_shared_data(struct wacom_wac *wacom)
static int wacom_led_control(struct wacom *wacom)
{
unsigned char *buf;
- int retval, led = 0;
+ int retval;
buf = kzalloc(9, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- if (wacom->wacom_wac.features.type == WACOM_21UX2 ||
- wacom->wacom_wac.features.type == WACOM_24HD)
- led = (wacom->led.select[1] << 4) | 0x40;
-
- led |= wacom->led.select[0] | 0x4;
-
- buf[0] = WAC_CMD_LED_CONTROL;
- buf[1] = led;
- buf[2] = wacom->led.llv;
- buf[3] = wacom->led.hlv;
- buf[4] = wacom->led.img_lum;
+ if (wacom->wacom_wac.features.type >= INTUOS5S &&
+ wacom->wacom_wac.features.type <= INTUOS5L) {
+ /*
+ * Touch Ring and crop mark LED luminance may take on
+ * one of four values:
+ * 0 = Low; 1 = Medium; 2 = High; 3 = Off
+ */
+ int ring_led = wacom->led.select[0] & 0x03;
+ int ring_lum = (((wacom->led.llv & 0x60) >> 5) - 1) & 0x03;
+ int crop_lum = 0;
+
+ buf[0] = WAC_CMD_LED_CONTROL;
+ buf[1] = (crop_lum << 4) | (ring_lum << 2) | (ring_led);
+ }
+ else {
+ int led = wacom->led.select[0] | 0x4;
+
+ if (wacom->wacom_wac.features.type == WACOM_21UX2 ||
+ wacom->wacom_wac.features.type == WACOM_24HD)
+ led |= (wacom->led.select[1] << 4) | 0x40;
+
+ buf[0] = WAC_CMD_LED_CONTROL;
+ buf[1] = led;
+ buf[2] = wacom->led.llv;
+ buf[3] = wacom->led.hlv;
+ buf[4] = wacom->led.img_lum;
+ }
retval = wacom_set_report(wacom->intf, 0x03, WAC_CMD_LED_CONTROL,
buf, 9, WAC_CMD_RETRIES);
@@ -783,6 +841,17 @@ static struct attribute_group intuos4_led_attr_group = {
.attrs = intuos4_led_attrs,
};
+static struct attribute *intuos5_led_attrs[] = {
+ &dev_attr_status0_luminance.attr,
+ &dev_attr_status_led0_select.attr,
+ NULL
+};
+
+static struct attribute_group intuos5_led_attr_group = {
+ .name = "wacom_led",
+ .attrs = intuos5_led_attrs,
+};
+
static int wacom_initialize_leds(struct wacom *wacom)
{
int error;
@@ -812,6 +881,19 @@ static int wacom_initialize_leds(struct wacom *wacom)
&cintiq_led_attr_group);
break;
+ case INTUOS5S:
+ case INTUOS5:
+ case INTUOS5L:
+ wacom->led.select[0] = 0;
+ wacom->led.select[1] = 0;
+ wacom->led.llv = 32;
+ wacom->led.hlv = 0;
+ wacom->led.img_lum = 0;
+
+ error = sysfs_create_group(&wacom->intf->dev.kobj,
+ &intuos5_led_attr_group);
+ break;
+
default:
return 0;
}
@@ -840,6 +922,13 @@ static void wacom_destroy_leds(struct wacom *wacom)
sysfs_remove_group(&wacom->intf->dev.kobj,
&cintiq_led_attr_group);
break;
+
+ case INTUOS5S:
+ case INTUOS5:
+ case INTUOS5L:
+ sysfs_remove_group(&wacom->intf->dev.kobj,
+ &intuos5_led_attr_group);
+ break;
}
}
@@ -901,8 +990,10 @@ static int wacom_register_input(struct wacom *wacom)
int error;
input_dev = input_allocate_device();
- if (!input_dev)
- return -ENOMEM;
+ if (!input_dev) {
+ error = -ENOMEM;
+ goto fail1;
+ }
input_dev->name = wacom_wac->name;
input_dev->dev.parent = &intf->dev;
@@ -912,14 +1003,20 @@ static int wacom_register_input(struct wacom *wacom)
input_set_drvdata(input_dev, wacom);
wacom_wac->input = input_dev;
- wacom_setup_input_capabilities(input_dev, wacom_wac);
+ error = wacom_setup_input_capabilities(input_dev, wacom_wac);
+ if (error)
+ goto fail1;
error = input_register_device(input_dev);
- if (error) {
- input_free_device(input_dev);
- wacom_wac->input = NULL;
- }
+ if (error)
+ goto fail2;
+ return 0;
+
+fail2:
+ input_free_device(input_dev);
+ wacom_wac->input = NULL;
+fail1:
return error;
}
@@ -938,22 +1035,22 @@ static void wacom_wireless_work(struct work_struct *work)
wacom = usb_get_intfdata(usbdev->config->interface[1]);
if (wacom->wacom_wac.input)
input_unregister_device(wacom->wacom_wac.input);
- wacom->wacom_wac.input = 0;
+ wacom->wacom_wac.input = NULL;
/* Touch interface */
wacom = usb_get_intfdata(usbdev->config->interface[2]);
if (wacom->wacom_wac.input)
input_unregister_device(wacom->wacom_wac.input);
- wacom->wacom_wac.input = 0;
+ wacom->wacom_wac.input = NULL;
if (wacom_wac->pid == 0) {
- printk(KERN_INFO "wacom: wireless tablet disconnected\n");
+ dev_info(&wacom->intf->dev, "wireless tablet disconnected\n");
} else {
const struct usb_device_id *id = wacom_ids;
- printk(KERN_INFO
- "wacom: wireless tablet connected with PID %x\n",
- wacom_wac->pid);
+ dev_info(&wacom->intf->dev,
+ "wireless tablet connected with PID %x\n",
+ wacom_wac->pid);
while (id->match_flags) {
if (id->idVendor == USB_VENDOR_ID_WACOM &&
@@ -963,8 +1060,8 @@ static void wacom_wireless_work(struct work_struct *work)
}
if (!id->match_flags) {
- printk(KERN_INFO
- "wacom: ignorning unknown PID.\n");
+ dev_info(&wacom->intf->dev,
+ "ignoring unknown PID.\n");
return;
}
@@ -1035,11 +1132,33 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
endpoint = &intf->cur_altsetting->endpoint[0].desc;
- /* Retrieve the physical and logical size for OEM devices */
+ /* Retrieve the physical and logical size for touch devices */
error = wacom_retrieve_hid_descriptor(intf, features);
if (error)
goto fail3;
+ /*
+ * Intuos5 has no useful data about its touch interface in its
+ * HID descriptor. If this is the touch interface (wMaxPacketSize
+ * of WACOM_PKGLEN_BBTOUCH3), override the table values.
+ */
+ if (features->type >= INTUOS5S && features->type <= INTUOS5L) {
+ if (endpoint->wMaxPacketSize == WACOM_PKGLEN_BBTOUCH3) {
+ features->device_type = BTN_TOOL_FINGER;
+ features->pktlen = WACOM_PKGLEN_BBTOUCH3;
+
+ features->x_phy =
+ (features->x_max * 100) / features->x_resolution;
+ features->y_phy =
+ (features->y_max * 100) / features->y_resolution;
+
+ features->x_max = 4096;
+ features->y_max = 4096;
+ } else {
+ features->device_type = BTN_TOOL_PEN;
+ }
+ }
+
wacom_setup_device_quirks(features);
strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name));
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index cecd35c8f0b3..004bc1bb1544 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -61,7 +61,8 @@ static int wacom_penpartner_irq(struct wacom_wac *wacom)
break;
default:
- printk(KERN_INFO "wacom_penpartner_irq: received unknown report #%d\n", data[0]);
+ dev_dbg(input->dev.parent,
+ "%s: received unknown report #%d\n", __func__, data[0]);
return 0;
}
@@ -76,7 +77,8 @@ static int wacom_pl_irq(struct wacom_wac *wacom)
int prox, pressure;
if (data[0] != WACOM_REPORT_PENABLED) {
- dbg("wacom_pl_irq: received unknown report #%d", data[0]);
+ dev_dbg(input->dev.parent,
+ "%s: received unknown report #%d\n", __func__, data[0]);
return 0;
}
@@ -146,7 +148,8 @@ static int wacom_ptu_irq(struct wacom_wac *wacom)
struct input_dev *input = wacom->input;
if (data[0] != WACOM_REPORT_PENABLED) {
- printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]);
+ dev_dbg(input->dev.parent,
+ "%s: received unknown report #%d\n", __func__, data[0]);
return 0;
}
@@ -175,7 +178,8 @@ static int wacom_dtu_irq(struct wacom_wac *wacom)
struct input_dev *input = wacom->input;
int prox = data[1] & 0x20, pressure;
- dbg("wacom_dtu_irq: received report #%d", data[0]);
+ dev_dbg(input->dev.parent,
+ "%s: received report #%d", __func__, data[0]);
if (prox) {
/* Going into proximity select tool */
@@ -211,7 +215,8 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
int retval = 0;
if (data[0] != WACOM_REPORT_PENABLED) {
- dbg("wacom_graphire_irq: received unknown report #%d", data[0]);
+ dev_dbg(input->dev.parent,
+ "%s: received unknown report #%d\n", __func__, data[0]);
goto exit;
}
@@ -321,6 +326,9 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
/* Enter report */
if ((data[1] & 0xfc) == 0xc0) {
+ if (features->type >= INTUOS5S && features->type <= INTUOS5L)
+ wacom->shared->stylus_in_proximity = true;
+
/* serial number of the tool */
wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
(data[4] << 20) + (data[5] << 12) +
@@ -406,6 +414,9 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
/* Exit report */
if ((data[1] & 0xfe) == 0x80) {
+ if (features->type >= INTUOS5S && features->type <= INTUOS5L)
+ wacom->shared->stylus_in_proximity = false;
+
/*
* Reset all states otherwise we lose the initial states
* when in-prox next time
@@ -452,6 +463,7 @@ static void wacom_intuos_general(struct wacom_wac *wacom)
if ((data[1] & 0xb8) == 0xa0) {
t = (data[6] << 2) | ((data[7] >> 6) & 3);
if ((features->type >= INTUOS4S && features->type <= INTUOS4L) ||
+ (features->type >= INTUOS5S && features->type <= INTUOS5L) ||
features->type == WACOM_21UX2 || features->type == WACOM_24HD) {
t = (t << 1) | (data[1] & 1);
}
@@ -482,9 +494,13 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
unsigned int t;
int idx = 0, result;
- if (data[0] != WACOM_REPORT_PENABLED && data[0] != WACOM_REPORT_INTUOSREAD
- && data[0] != WACOM_REPORT_INTUOSWRITE && data[0] != WACOM_REPORT_INTUOSPAD) {
- dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
+ if (data[0] != WACOM_REPORT_PENABLED &&
+ data[0] != WACOM_REPORT_INTUOSREAD &&
+ data[0] != WACOM_REPORT_INTUOSWRITE &&
+ data[0] != WACOM_REPORT_INTUOSPAD &&
+ data[0] != WACOM_REPORT_INTUOS5PAD) {
+ dev_dbg(input->dev.parent,
+ "%s: received unknown report #%d\n", __func__, data[0]);
return 0;
}
@@ -493,7 +509,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
idx = data[1] & 0x01;
/* pad packets. Works as a second tool and is always in prox */
- if (data[0] == WACOM_REPORT_INTUOSPAD) {
+ if (data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD) {
if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
input_report_key(input, BTN_0, (data[2] & 0x01));
input_report_key(input, BTN_1, (data[3] & 0x01));
@@ -569,6 +585,34 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
input_report_key(input, wacom->tool[1], 0);
input_report_abs(input, ABS_MISC, 0);
}
+ } else if (features->type >= INTUOS5S && features->type <= INTUOS5L) {
+ int i;
+
+ /* Touch ring mode switch has no capacitive sensor */
+ input_report_key(input, BTN_0, (data[3] & 0x01));
+
+ /*
+ * ExpressKeys on Intuos5 have a capacitive sensor in
+ * addition to the mechanical switch. Switch data is
+ * stored in data[4], capacitive data in data[5].
+ */
+ for (i = 0; i < 8; i++)
+ input_report_key(input, BTN_1 + i, data[4] & (1 << i));
+
+ if (data[2] & 0x80) {
+ input_report_abs(input, ABS_WHEEL, (data[2] & 0x7f));
+ } else {
+ /* Out of proximity, clear wheel value. */
+ input_report_abs(input, ABS_WHEEL, 0);
+ }
+
+ if (data[2] | (data[3] & 0x01) | data[4]) {
+ input_report_key(input, wacom->tool[1], 1);
+ input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
+ } else {
+ input_report_key(input, wacom->tool[1], 0);
+ input_report_abs(input, ABS_MISC, 0);
+ }
} else {
if (features->type == WACOM_21UX2) {
input_report_key(input, BTN_0, (data[5] & 0x01));
@@ -632,7 +676,9 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
(features->type == INTUOS3 ||
features->type == INTUOS3S ||
features->type == INTUOS4 ||
- features->type == INTUOS4S)) {
+ features->type == INTUOS4S ||
+ features->type == INTUOS5 ||
+ features->type == INTUOS5S)) {
return 0;
}
@@ -685,7 +731,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
} else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
/* I4 mouse */
- if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
+ if ((features->type >= INTUOS4S && features->type <= INTUOS4L) ||
+ (features->type >= INTUOS5S && features->type <= INTUOS5L)) {
input_report_key(input, BTN_LEFT, data[6] & 0x01);
input_report_key(input, BTN_MIDDLE, data[6] & 0x02);
input_report_key(input, BTN_RIGHT, data[6] & 0x04);
@@ -712,7 +759,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
}
}
} else if ((features->type < INTUOS3S || features->type == INTUOS3L ||
- features->type == INTUOS4L) &&
+ features->type == INTUOS4L || features->type == INTUOS5L) &&
wacom->tool[idx] == BTN_TOOL_LENS) {
/* Lens cursor packets */
input_report_key(input, BTN_LEFT, data[8] & 0x01);
@@ -729,6 +776,72 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
return 1;
}
+static int find_slot_from_contactid(struct wacom_wac *wacom, int contactid)
+{
+ int touch_max = wacom->features.touch_max;
+ int i;
+
+ if (!wacom->slots)
+ return -1;
+
+ for (i = 0; i < touch_max; ++i) {
+ if (wacom->slots[i] == contactid)
+ return i;
+ }
+ for (i = 0; i < touch_max; ++i) {
+ if (wacom->slots[i] == -1)
+ return i;
+ }
+ return -1;
+}
+
+static int wacom_mt_touch(struct wacom_wac *wacom)
+{
+ struct input_dev *input = wacom->input;
+ char *data = wacom->data;
+ int i;
+ int current_num_contacts = data[2];
+ int contacts_to_send = 0;
+
+ /*
+ * First packet resets the counter since only the first
+ * packet in series will have non-zero current_num_contacts.
+ */
+ if (current_num_contacts)
+ wacom->num_contacts_left = current_num_contacts;
+
+ /* There are at most 5 contacts per packet */
+ contacts_to_send = min(5, wacom->num_contacts_left);
+
+ for (i = 0; i < contacts_to_send; i++) {
+ int offset = (WACOM_BYTES_PER_MT_PACKET * i) + 3;
+ bool touch = data[offset] & 0x1;
+ int id = le16_to_cpup((__le16 *)&data[offset + 1]);
+ int slot = find_slot_from_contactid(wacom, id);
+
+ if (slot < 0)
+ continue;
+
+ input_mt_slot(input, slot);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
+ if (touch) {
+ int x = le16_to_cpup((__le16 *)&data[offset + 7]);
+ int y = le16_to_cpup((__le16 *)&data[offset + 9]);
+ input_report_abs(input, ABS_MT_POSITION_X, x);
+ input_report_abs(input, ABS_MT_POSITION_Y, y);
+ }
+ wacom->slots[slot] = touch ? id : -1;
+ }
+
+ input_mt_report_pointer_emulation(input, true);
+
+ wacom->num_contacts_left -= contacts_to_send;
+ if (wacom->num_contacts_left < 0)
+ wacom->num_contacts_left = 0;
+
+ return 1;
+}
+
static int wacom_tpc_mt_touch(struct wacom_wac *wacom)
{
struct input_dev *input = wacom->input;
@@ -767,6 +880,9 @@ static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len)
bool prox;
int x = 0, y = 0;
+ if (wacom->features.touch_max > 1 || len > WACOM_PKGLEN_TPC2FG)
+ return 0;
+
if (!wacom->shared->stylus_in_proximity) {
if (len == WACOM_PKGLEN_TPC1FG) {
prox = data[0] & 0x01;
@@ -830,14 +946,15 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
{
char *data = wacom->data;
- dbg("wacom_tpc_irq: received report #%d", data[0]);
+ dev_dbg(wacom->input->dev.parent,
+ "%s: received report #%d\n", __func__, data[0]);
switch (len) {
case WACOM_PKGLEN_TPC1FG:
- return wacom_tpc_single_touch(wacom, len);
+ return wacom_tpc_single_touch(wacom, len);
case WACOM_PKGLEN_TPC2FG:
- return wacom_tpc_mt_touch(wacom);
+ return wacom_tpc_mt_touch(wacom);
default:
switch (data[0]) {
@@ -846,6 +963,9 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
case WACOM_REPORT_TPCST:
return wacom_tpc_single_touch(wacom, len);
+ case WACOM_REPORT_TPCMT:
+ return wacom_mt_touch(wacom);
+
case WACOM_REPORT_PENABLED:
return wacom_tpc_pen(wacom);
}
@@ -1114,8 +1234,18 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
sync = wacom_intuos_irq(wacom_wac);
break;
+ case INTUOS5S:
+ case INTUOS5:
+ case INTUOS5L:
+ if (len == WACOM_PKGLEN_BBTOUCH3)
+ sync = wacom_bpt3_touch(wacom_wac);
+ else
+ sync = wacom_intuos_irq(wacom_wac);
+ break;
+
case TABLETPC:
case TABLETPC2FG:
+ case MTSCREEN:
sync = wacom_tpc_irq(wacom_wac, len);
break;
@@ -1188,7 +1318,9 @@ void wacom_setup_device_quirks(struct wacom_features *features)
/* these device have multiple inputs */
if (features->type == TABLETPC || features->type == TABLETPC2FG ||
- features->type == BAMBOO_PT || features->type == WIRELESS)
+ features->type == BAMBOO_PT || features->type == WIRELESS ||
+ (features->type >= INTUOS5S && features->type <= INTUOS5L) ||
+ features->type == MTSCREEN)
features->quirks |= WACOM_QUIRK_MULTI_INPUT;
/* quirk for bamboo touch with 2 low res touches */
@@ -1219,8 +1351,8 @@ static unsigned int wacom_calculate_touch_res(unsigned int logical_max,
return (logical_max * 100) / physical_max;
}
-void wacom_setup_input_capabilities(struct input_dev *input_dev,
- struct wacom_wac *wacom_wac)
+int wacom_setup_input_capabilities(struct input_dev *input_dev,
+ struct wacom_wac *wacom_wac)
{
struct wacom_features *features = &wacom_wac->features;
int i;
@@ -1355,6 +1487,50 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
wacom_setup_intuos(wacom_wac);
break;
+ case INTUOS5:
+ case INTUOS5L:
+ if (features->device_type == BTN_TOOL_PEN) {
+ __set_bit(BTN_7, input_dev->keybit);
+ __set_bit(BTN_8, input_dev->keybit);
+ }
+ /* fall through */
+
+ case INTUOS5S:
+ __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
+
+ if (features->device_type == BTN_TOOL_PEN) {
+ for (i = 0; i < 7; i++)
+ __set_bit(BTN_0 + i, input_dev->keybit);
+
+ input_set_abs_params(input_dev, ABS_DISTANCE, 0,
+ features->distance_max,
+ 0, 0);
+
+ input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
+
+ wacom_setup_intuos(wacom_wac);
+ } else if (features->device_type == BTN_TOOL_FINGER) {
+ __clear_bit(ABS_MISC, input_dev->absbit);
+
+ __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
+ __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
+ __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
+ __set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
+
+ input_mt_init_slots(input_dev, features->touch_max);
+
+ input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
+ 0, 255, 0, 0);
+
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X,
+ 0, features->x_max,
+ features->x_fuzz, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
+ 0, features->y_max,
+ features->y_fuzz, 0);
+ }
+ break;
+
case INTUOS4:
case INTUOS4L:
__set_bit(BTN_7, input_dev->keybit);
@@ -1372,9 +1548,19 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
break;
case TABLETPC2FG:
+ case MTSCREEN:
if (features->device_type == BTN_TOOL_FINGER) {
- input_mt_init_slots(input_dev, 2);
+ wacom_wac->slots = kmalloc(features->touch_max *
+ sizeof(int),
+ GFP_KERNEL);
+ if (!wacom_wac->slots)
+ return -ENOMEM;
+
+ for (i = 0; i < features->touch_max; i++)
+ wacom_wac->slots[i] = -1;
+
+ input_mt_init_slots(input_dev, features->touch_max);
input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
0, MT_TOOL_MAX, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
@@ -1429,6 +1615,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
+ input_mt_init_slots(input_dev, features->touch_max);
if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
__set_bit(BTN_TOOL_TRIPLETAP,
@@ -1436,13 +1623,9 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(BTN_TOOL_QUADTAP,
input_dev->keybit);
- input_mt_init_slots(input_dev, 16);
-
input_set_abs_params(input_dev,
ABS_MT_TOUCH_MAJOR,
0, 255, 0, 0);
- } else {
- input_mt_init_slots(input_dev, 2);
}
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
@@ -1462,6 +1645,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
}
break;
}
+ return 0;
}
static const struct wacom_features wacom_features_0x00 =
@@ -1629,6 +1813,24 @@ static const struct wacom_features wacom_features_0xBB =
static const struct wacom_features wacom_features_0xBC =
{ "Wacom Intuos4 WL", WACOM_PKGLEN_INTUOS, 40840, 25400, 2047,
63, INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0x26 =
+ { "Wacom Intuos5 touch S", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047,
+ 63, INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+ .touch_max = 16 };
+static const struct wacom_features wacom_features_0x27 =
+ { "Wacom Intuos5 touch M", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047,
+ 63, INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+ .touch_max = 16 };
+static const struct wacom_features wacom_features_0x28 =
+ { "Wacom Intuos5 touch L", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047,
+ 63, INTUOS5L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+ .touch_max = 16 };
+static const struct wacom_features wacom_features_0x29 =
+ { "Wacom Intuos5 S", WACOM_PKGLEN_INTUOS, 31496, 19685, 2047,
+ 63, INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
+static const struct wacom_features wacom_features_0x2A =
+ { "Wacom Intuos5 M", WACOM_PKGLEN_INTUOS, 44704, 27940, 2047,
+ 63, INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
static const struct wacom_features wacom_features_0xF4 =
{ "Wacom Cintiq 24HD", WACOM_PKGLEN_INTUOS, 104480, 65600, 2047,
63, WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
@@ -1670,13 +1872,19 @@ static const struct wacom_features wacom_features_0x9F =
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xE2 =
{ "Wacom ISDv4 E2", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255,
- 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+ 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+ .touch_max = 2 };
static const struct wacom_features wacom_features_0xE3 =
{ "Wacom ISDv4 E3", WACOM_PKGLEN_TPC2FG, 26202, 16325, 255,
- 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+ 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+ .touch_max = 2 };
+static const struct wacom_features wacom_features_0xE5 =
+ { "Wacom ISDv4 E5", WACOM_PKGLEN_MTOUCH, 26202, 16325, 255,
+ 0, MTSCREEN, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xE6 =
{ "Wacom ISDv4 E6", WACOM_PKGLEN_TPC2FG, 27760, 15694, 255,
- 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+ 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+ .touch_max = 2 };
static const struct wacom_features wacom_features_0xEC =
{ "Wacom ISDv4 EC", WACOM_PKGLEN_GRAPHIRE, 25710, 14500, 255,
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -1685,19 +1893,22 @@ static const struct wacom_features wacom_features_0x47 =
31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0x84 =
{ "Wacom Wireless Receiver", WACOM_PKGLEN_WIRELESS, 0, 0, 0,
- 0, WIRELESS, 0, 0 };
+ 0, WIRELESS, 0, 0, .touch_max = 16 };
static const struct wacom_features wacom_features_0xD0 =
{ "Wacom Bamboo 2FG", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
- 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+ 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+ .touch_max = 2 };
static const struct wacom_features wacom_features_0xD1 =
{ "Wacom Bamboo 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
- 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+ 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+ .touch_max = 2 };
static const struct wacom_features wacom_features_0xD2 =
{ "Wacom Bamboo Craft", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xD3 =
{ "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023,
- 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+ 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+ .touch_max = 2 };
static const struct wacom_features wacom_features_0xD4 =
{ "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -1706,28 +1917,35 @@ static const struct wacom_features wacom_features_0xD5 =
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xD6 =
{ "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
- 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+ 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+ .touch_max = 2 };
static const struct wacom_features wacom_features_0xD7 =
{ "Wacom BambooPT 2FG Small", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
- 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+ 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+ .touch_max = 2 };
static const struct wacom_features wacom_features_0xD8 =
{ "Wacom Bamboo Comic 2FG", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023,
- 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+ 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+ .touch_max = 2 };
static const struct wacom_features wacom_features_0xDA =
{ "Wacom Bamboo 2FG 4x5 SE", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
- 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+ 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+ .touch_max = 2 };
static struct wacom_features wacom_features_0xDB =
{ "Wacom Bamboo 2FG 6x8 SE", WACOM_PKGLEN_BBFUN, 21648, 13700, 1023,
- 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+ 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+ .touch_max = 2 };
static const struct wacom_features wacom_features_0xDD =
{ "Wacom Bamboo Connect", WACOM_PKGLEN_BBPEN, 14720, 9200, 1023,
31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xDE =
{ "Wacom Bamboo 16FG 4x5", WACOM_PKGLEN_BBPEN, 14720, 9200, 1023,
- 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+ 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+ .touch_max = 16 };
static const struct wacom_features wacom_features_0xDF =
{ "Wacom Bamboo 16FG 6x8", WACOM_PKGLEN_BBPEN, 21648, 13700, 1023,
- 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+ 31, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES,
+ .touch_max = 16 };
static const struct wacom_features wacom_features_0x6004 =
{ "ISD-V4", WACOM_PKGLEN_GRAPHIRE, 12800, 8000, 255,
0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -1801,6 +2019,11 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0xBA) },
{ USB_DEVICE_WACOM(0xBB) },
{ USB_DEVICE_WACOM(0xBC) },
+ { USB_DEVICE_WACOM(0x26) },
+ { USB_DEVICE_WACOM(0x27) },
+ { USB_DEVICE_WACOM(0x28) },
+ { USB_DEVICE_WACOM(0x29) },
+ { USB_DEVICE_WACOM(0x2A) },
{ USB_DEVICE_WACOM(0x3F) },
{ USB_DEVICE_WACOM(0xC5) },
{ USB_DEVICE_WACOM(0xC6) },
@@ -1836,6 +2059,7 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0x9F) },
{ USB_DEVICE_WACOM(0xE2) },
{ USB_DEVICE_WACOM(0xE3) },
+ { USB_DEVICE_WACOM(0xE5) },
{ USB_DEVICE_WACOM(0xE6) },
{ USB_DEVICE_WACOM(0xEC) },
{ USB_DEVICE_WACOM(0x47) },
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index ba5a334e54d6..78fbd3f42009 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -25,6 +25,10 @@
#define WACOM_PKGLEN_BBTOUCH3 64
#define WACOM_PKGLEN_BBPEN 10
#define WACOM_PKGLEN_WIRELESS 32
+#define WACOM_PKGLEN_MTOUCH 62
+
+/* wacom data size per MT contact */
+#define WACOM_BYTES_PER_MT_PACKET 11
/* device IDs */
#define STYLUS_DEVICE_ID 0x02
@@ -38,8 +42,10 @@
#define WACOM_REPORT_INTUOSREAD 5
#define WACOM_REPORT_INTUOSWRITE 6
#define WACOM_REPORT_INTUOSPAD 12
+#define WACOM_REPORT_INTUOS5PAD 3
#define WACOM_REPORT_TPC1FG 6
#define WACOM_REPORT_TPC2FG 13
+#define WACOM_REPORT_TPCMT 13
#define WACOM_REPORT_TPCHID 15
#define WACOM_REPORT_TPCST 16
@@ -65,6 +71,9 @@ enum {
INTUOS4S,
INTUOS4,
INTUOS4L,
+ INTUOS5S,
+ INTUOS5,
+ INTUOS5L,
WACOM_24HD,
WACOM_21UX2,
CINTIQ,
@@ -72,6 +81,7 @@ enum {
WACOM_MO,
TABLETPC,
TABLETPC2FG,
+ MTSCREEN,
MAX_TYPE
};
@@ -95,6 +105,7 @@ struct wacom_features {
int pressure_fuzz;
int distance_fuzz;
unsigned quirks;
+ unsigned touch_max;
};
struct wacom_shared {
@@ -113,6 +124,8 @@ struct wacom_wac {
struct input_dev *input;
int pid;
int battery_capacity;
+ int num_contacts_left;
+ int *slots;
};
#endif
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 2a2141915aa0..98d263504eea 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -187,6 +187,23 @@ config TOUCHSCREEN_DA9034
Say Y here to enable the support for the touchscreen found
on Dialog Semiconductor DA9034 PMIC.
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called da9034-ts.
+
+config TOUCHSCREEN_DA9052
+ tristate "Dialog DA9052/DA9053 TSI"
+ depends on PMIC_DA9052
+ help
+ Say Y here to support the touchscreen found on Dialog Semiconductor
+ DA9052-BC and DA9053-AA/Bx PMICs.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called da9052_tsi.
+
config TOUCHSCREEN_DYNAPRO
tristate "Dynapro serial touchscreen"
select SERIO
@@ -306,6 +323,18 @@ config TOUCHSCREEN_WACOM_W8001
To compile this driver as a module, choose M here: the
module will be called wacom_w8001.
+config TOUCHSCREEN_WACOM_I2C
+ tristate "Wacom Tablet support (I2C)"
+ depends on I2C
+ help
+ Say Y here if you want to use the I2C version of the Wacom
+ Pen Tablet.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the module
+ will be called wacom_i2c.
+
config TOUCHSCREEN_LPC32XX
tristate "LPC32XX touchscreen controller"
depends on ARCH_LPC32XX
@@ -489,10 +518,10 @@ config TOUCHSCREEN_TI_TSCADC
config TOUCHSCREEN_ATMEL_TSADCC
tristate "Atmel Touchscreen Interface"
- depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
+ depends on ARCH_AT91
help
Say Y here if you have a 4-wire touchscreen connected to the
- ADC Controller on your Atmel SoC (such as the AT91SAM9RL).
+ ADC Controller on your Atmel SoC.
If unsure, say N.
@@ -635,6 +664,7 @@ config TOUCHSCREEN_USB_COMPOSITE
- Zytronic controllers
- Elo TouchSystems 2700 IntelliTouch
- EasyTouch USB Touch Controller from Data Modul
+ - e2i (Mimo monitors)
Have a look at <http://linux.chapter7.ch/touchkit/> for
a usage description and the required user-space stuff.
@@ -721,7 +751,7 @@ config TOUCHSCREEN_USB_ELO
config TOUCHSCREEN_USB_E2I
default y
- bool "e2i Touchscreen controller (e.g. from Mimo 740)"
+ bool "e2i Touchscreen controller (e.g. from Mimo 740)" if EXPERT
depends on TOUCHSCREEN_USB_COMPOSITE
config TOUCHSCREEN_USB_ZYTRONIC
@@ -744,7 +774,7 @@ config TOUCHSCREEN_USB_EASYTOUCH
bool "EasyTouch USB Touch controller device support" if EMBEDDED
depends on TOUCHSCREEN_USB_COMPOSITE
help
- Say Y here if you have a EasyTouch USB Touch controller device support.
+ Say Y here if you have an EasyTouch USB Touch controller.
If unsure, say N.
config TOUCHSCREEN_TOUCHIT213
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 3d5cf8cbf89c..eb8bfe1c1a46 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI) += cyttsp_spi.o
obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o
+obj-$(CONFIG_TOUCHSCREEN_DA9052) += da9052_tsi.o
obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o
obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
@@ -59,6 +60,7 @@ obj-$(CONFIG_TOUCHSCREEN_TSC2005) += tsc2005.o
obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o
obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o
obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o
+obj-$(CONFIG_TOUCHSCREEN_WACOM_I2C) += wacom_i2c.o
obj-$(CONFIG_TOUCHSCREEN_WM831X) += wm831x-ts.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o
wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 19d4ea65ea01..42e645062c20 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -236,7 +236,6 @@ struct mxt_object {
struct mxt_message {
u8 reportid;
u8 message[7];
- u8 checksum;
};
struct mxt_finger {
@@ -326,17 +325,12 @@ static bool mxt_object_writable(unsigned int type)
}
static void mxt_dump_message(struct device *dev,
- struct mxt_message *message)
+ struct mxt_message *message)
{
- dev_dbg(dev, "reportid:\t0x%x\n", message->reportid);
- dev_dbg(dev, "message1:\t0x%x\n", message->message[0]);
- dev_dbg(dev, "message2:\t0x%x\n", message->message[1]);
- dev_dbg(dev, "message3:\t0x%x\n", message->message[2]);
- dev_dbg(dev, "message4:\t0x%x\n", message->message[3]);
- dev_dbg(dev, "message5:\t0x%x\n", message->message[4]);
- dev_dbg(dev, "message6:\t0x%x\n", message->message[5]);
- dev_dbg(dev, "message7:\t0x%x\n", message->message[6]);
- dev_dbg(dev, "checksum:\t0x%x\n", message->checksum);
+ dev_dbg(dev, "reportid: %u\tmessage: %02x %02x %02x %02x %02x %02x %02x\n",
+ message->reportid, message->message[0], message->message[1],
+ message->message[2], message->message[3], message->message[4],
+ message->message[5], message->message[6]);
}
static int mxt_check_bootloader(struct i2c_client *client,
@@ -506,7 +500,7 @@ static int mxt_write_object(struct mxt_data *data,
u16 reg;
object = mxt_get_object(data, type);
- if (!object)
+ if (!object || offset >= object->size + 1)
return -EINVAL;
reg = object->start_address;
@@ -1049,8 +1043,8 @@ static ssize_t mxt_update_fw_store(struct device *dev,
return count;
}
-static DEVICE_ATTR(object, 0444, mxt_object_show, NULL);
-static DEVICE_ATTR(update_fw, 0664, NULL, mxt_update_fw_store);
+static DEVICE_ATTR(object, S_IRUGO, mxt_object_show, NULL);
+static DEVICE_ATTR(update_fw, S_IWUSR, NULL, mxt_update_fw_store);
static struct attribute *mxt_attrs[] = {
&dev_attr_object.attr,
@@ -1201,7 +1195,7 @@ static int __devexit mxt_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int mxt_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -1239,13 +1233,10 @@ static int mxt_resume(struct device *dev)
return 0;
}
-
-static const struct dev_pm_ops mxt_pm_ops = {
- .suspend = mxt_suspend,
- .resume = mxt_resume,
-};
#endif
+static SIMPLE_DEV_PM_OPS(mxt_pm_ops, mxt_suspend, mxt_resume);
+
static const struct i2c_device_id mxt_id[] = {
{ "qt602240_ts", 0 },
{ "atmel_mxt_ts", 0 },
@@ -1258,9 +1249,7 @@ static struct i2c_driver mxt_driver = {
.driver = {
.name = "atmel_mxt_ts",
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
.pm = &mxt_pm_ops,
-#endif
},
.probe = mxt_probe,
.remove = __devexit_p(mxt_remove),
diff --git a/drivers/input/touchscreen/da9052_tsi.c b/drivers/input/touchscreen/da9052_tsi.c
new file mode 100644
index 000000000000..e8df341090c0
--- /dev/null
+++ b/drivers/input/touchscreen/da9052_tsi.c
@@ -0,0 +1,370 @@
+/*
+ * TSI driver for Dialog DA9052
+ *
+ * Copyright(c) 2012 Dialog Semiconductor Ltd.
+ *
+ * Author: David Dajun Chen <dchen@diasemi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+
+#include <linux/mfd/da9052/reg.h>
+#include <linux/mfd/da9052/da9052.h>
+
+#define TSI_PEN_DOWN_STATUS 0x40
+
+struct da9052_tsi {
+ struct da9052 *da9052;
+ struct input_dev *dev;
+ struct delayed_work ts_pen_work;
+ struct mutex mutex;
+ unsigned int irq_pendwn;
+ unsigned int irq_datardy;
+ bool stopped;
+ bool adc_on;
+};
+
+static void da9052_ts_adc_toggle(struct da9052_tsi *tsi, bool on)
+{
+ da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 0, on);
+ tsi->adc_on = on;
+}
+
+static irqreturn_t da9052_ts_pendwn_irq(int irq, void *data)
+{
+ struct da9052_tsi *tsi = data;
+
+ if (!tsi->stopped) {
+ /* Mask PEN_DOWN event and unmask TSI_READY event */
+ disable_irq_nosync(tsi->irq_pendwn);
+ enable_irq(tsi->irq_datardy);
+
+ da9052_ts_adc_toggle(tsi, true);
+
+ schedule_delayed_work(&tsi->ts_pen_work, HZ / 50);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void da9052_ts_read(struct da9052_tsi *tsi)
+{
+ struct input_dev *input = tsi->dev;
+ int ret;
+ u16 x, y, z;
+ u8 v;
+
+ ret = da9052_reg_read(tsi->da9052, DA9052_TSI_X_MSB_REG);
+ if (ret < 0)
+ return;
+
+ x = (u16) ret;
+
+ ret = da9052_reg_read(tsi->da9052, DA9052_TSI_Y_MSB_REG);
+ if (ret < 0)
+ return;
+
+ y = (u16) ret;
+
+ ret = da9052_reg_read(tsi->da9052, DA9052_TSI_Z_MSB_REG);
+ if (ret < 0)
+ return;
+
+ z = (u16) ret;
+
+ ret = da9052_reg_read(tsi->da9052, DA9052_TSI_LSB_REG);
+ if (ret < 0)
+ return;
+
+ v = (u8) ret;
+
+ x = ((x << 2) & 0x3fc) | (v & 0x3);
+ y = ((y << 2) & 0x3fc) | ((v & 0xc) >> 2);
+ z = ((z << 2) & 0x3fc) | ((v & 0x30) >> 4);
+
+ input_report_key(input, BTN_TOUCH, 1);
+ input_report_abs(input, ABS_X, x);
+ input_report_abs(input, ABS_Y, y);
+ input_report_abs(input, ABS_PRESSURE, z);
+ input_sync(input);
+}
+
+static irqreturn_t da9052_ts_datardy_irq(int irq, void *data)
+{
+ struct da9052_tsi *tsi = data;
+
+ da9052_ts_read(tsi);
+
+ return IRQ_HANDLED;
+}
+
+static void da9052_ts_pen_work(struct work_struct *work)
+{
+ struct da9052_tsi *tsi = container_of(work, struct da9052_tsi,
+ ts_pen_work.work);
+ if (!tsi->stopped) {
+ int ret = da9052_reg_read(tsi->da9052, DA9052_TSI_LSB_REG);
+ if (ret < 0 || (ret & TSI_PEN_DOWN_STATUS)) {
+ /* Pen is still DOWN (or read error) */
+ schedule_delayed_work(&tsi->ts_pen_work, HZ / 50);
+ } else {
+ struct input_dev *input = tsi->dev;
+
+ /* Pen UP */
+ da9052_ts_adc_toggle(tsi, false);
+
+ /* Report Pen UP */
+ input_report_key(input, BTN_TOUCH, 0);
+ input_report_abs(input, ABS_PRESSURE, 0);
+ input_sync(input);
+
+ /*
+ * FIXME: Fixes the unhandled irq issue when quick
+ * pen down and pen up events occurs
+ */
+ ret = da9052_reg_update(tsi->da9052,
+ DA9052_EVENT_B_REG, 0xC0, 0xC0);
+ if (ret < 0)
+ return;
+
+ /* Mask TSI_READY event and unmask PEN_DOWN event */
+ disable_irq(tsi->irq_datardy);
+ enable_irq(tsi->irq_pendwn);
+ }
+ }
+}
+
+static int __devinit da9052_ts_configure_gpio(struct da9052 *da9052)
+{
+ int error;
+
+ error = da9052_reg_update(da9052, DA9052_GPIO_2_3_REG, 0x30, 0);
+ if (error < 0)
+ return error;
+
+ error = da9052_reg_update(da9052, DA9052_GPIO_4_5_REG, 0x33, 0);
+ if (error < 0)
+ return error;
+
+ error = da9052_reg_update(da9052, DA9052_GPIO_6_7_REG, 0x33, 0);
+ if (error < 0)
+ return error;
+
+ return 0;
+}
+
+static int __devinit da9052_configure_tsi(struct da9052_tsi *tsi)
+{
+ int error;
+
+ error = da9052_ts_configure_gpio(tsi->da9052);
+ if (error)
+ return error;
+
+ /* Measure TSI sample every 1ms */
+ error = da9052_reg_update(tsi->da9052, DA9052_ADC_CONT_REG,
+ 1 << 6, 1 << 6);
+ if (error < 0)
+ return error;
+
+ /* TSI_DELAY: 3 slots, TSI_SKIP: 0 slots, TSI_MODE: XYZP */
+ error = da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 0xFC, 0xC0);
+ if (error < 0)
+ return error;
+
+ /* Supply TSIRef through LD09 */
+ error = da9052_reg_write(tsi->da9052, DA9052_LDO9_REG, 0x59);
+ if (error < 0)
+ return error;
+
+ return 0;
+}
+
+static int da9052_ts_input_open(struct input_dev *input_dev)
+{
+ struct da9052_tsi *tsi = input_get_drvdata(input_dev);
+
+ tsi->stopped = false;
+ mb();
+
+ /* Unmask PEN_DOWN event */
+ enable_irq(tsi->irq_pendwn);
+
+ /* Enable Pen Detect Circuit */
+ return da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG,
+ 1 << 1, 1 << 1);
+}
+
+static void da9052_ts_input_close(struct input_dev *input_dev)
+{
+ struct da9052_tsi *tsi = input_get_drvdata(input_dev);
+
+ tsi->stopped = true;
+ mb();
+ disable_irq(tsi->irq_pendwn);
+ cancel_delayed_work_sync(&tsi->ts_pen_work);
+
+ if (tsi->adc_on) {
+ disable_irq(tsi->irq_datardy);
+ da9052_ts_adc_toggle(tsi, false);
+
+ /*
+ * If ADC was on that means that pendwn IRQ was disabled
+ * twice and we need to enable it to keep enable/disable
+ * counter balanced. IRQ is still off though.
+ */
+ enable_irq(tsi->irq_pendwn);
+ }
+
+ /* Disable Pen Detect Circuit */
+ da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 1, 0);
+}
+
+static int __devinit da9052_ts_probe(struct platform_device *pdev)
+{
+ struct da9052 *da9052;
+ struct da9052_tsi *tsi;
+ struct input_dev *input_dev;
+ int irq_pendwn;
+ int irq_datardy;
+ int error;
+
+ da9052 = dev_get_drvdata(pdev->dev.parent);
+ if (!da9052)
+ return -EINVAL;
+
+ irq_pendwn = platform_get_irq_byname(pdev, "PENDWN");
+ irq_datardy = platform_get_irq_byname(pdev, "TSIRDY");
+ if (irq_pendwn < 0 || irq_datardy < 0) {
+ dev_err(da9052->dev, "Unable to determine device interrupts\n");
+ return -ENXIO;
+ }
+
+ tsi = kzalloc(sizeof(struct da9052_tsi), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!tsi || !input_dev) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ tsi->da9052 = da9052;
+ tsi->dev = input_dev;
+ tsi->irq_pendwn = da9052->irq_base + irq_pendwn;
+ tsi->irq_datardy = da9052->irq_base + irq_datardy;
+ tsi->stopped = true;
+ INIT_DELAYED_WORK(&tsi->ts_pen_work, da9052_ts_pen_work);
+
+ input_dev->id.version = 0x0101;
+ input_dev->id.vendor = 0x15B6;
+ input_dev->id.product = 0x9052;
+ input_dev->name = "Dialog DA9052 TouchScreen Driver";
+ input_dev->dev.parent = &pdev->dev;
+ input_dev->open = da9052_ts_input_open;
+ input_dev->close = da9052_ts_input_close;
+
+ __set_bit(EV_ABS, input_dev->evbit);
+ __set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(BTN_TOUCH, input_dev->keybit);
+
+ input_set_abs_params(input_dev, ABS_X, 0, 1023, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, 1023, 0, 0);
+ input_set_abs_params(input_dev, ABS_PRESSURE, 0, 1023, 0, 0);
+
+ input_set_drvdata(input_dev, tsi);
+
+ /* Disable Pen Detect Circuit */
+ da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG, 1 << 1, 0);
+
+ /* Disable ADC */
+ da9052_ts_adc_toggle(tsi, false);
+
+ error = request_threaded_irq(tsi->irq_pendwn,
+ NULL, da9052_ts_pendwn_irq,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "PENDWN", tsi);
+ if (error) {
+ dev_err(tsi->da9052->dev,
+ "Failed to register PENDWN IRQ %d, error = %d\n",
+ tsi->irq_pendwn, error);
+ goto err_free_mem;
+ }
+
+ error = request_threaded_irq(tsi->irq_datardy,
+ NULL, da9052_ts_datardy_irq,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "TSIRDY", tsi);
+ if (error) {
+ dev_err(tsi->da9052->dev,
+ "Failed to register TSIRDY IRQ %d, error = %d\n",
+ tsi->irq_datardy, error);
+ goto err_free_pendwn_irq;
+ }
+
+ /* Mask PEN_DOWN and TSI_READY events */
+ disable_irq(tsi->irq_pendwn);
+ disable_irq(tsi->irq_datardy);
+
+ error = da9052_configure_tsi(tsi);
+ if (error)
+ goto err_free_datardy_irq;
+
+ error = input_register_device(tsi->dev);
+ if (error)
+ goto err_free_datardy_irq;
+
+ platform_set_drvdata(pdev, tsi);
+
+ return 0;
+
+err_free_datardy_irq:
+ free_irq(tsi->irq_datardy, tsi);
+err_free_pendwn_irq:
+ free_irq(tsi->irq_pendwn, tsi);
+err_free_mem:
+ kfree(tsi);
+ input_free_device(input_dev);
+
+ return error;
+}
+
+static int __devexit da9052_ts_remove(struct platform_device *pdev)
+{
+ struct da9052_tsi *tsi = platform_get_drvdata(pdev);
+
+ da9052_reg_write(tsi->da9052, DA9052_LDO9_REG, 0x19);
+
+ free_irq(tsi->irq_pendwn, tsi);
+ free_irq(tsi->irq_datardy, tsi);
+
+ input_unregister_device(tsi->dev);
+ kfree(tsi);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver da9052_tsi_driver = {
+ .probe = da9052_ts_probe,
+ .remove = __devexit_p(da9052_ts_remove),
+ .driver = {
+ .name = "da9052-tsi",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(da9052_tsi_driver);
+
+MODULE_DESCRIPTION("Touchscreen driver for Dialog Semiconductor DA9052");
+MODULE_AUTHOR("Anthony Olech <Anthony.Olech@diasemi.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9052-tsi");
diff --git a/drivers/input/touchscreen/dynapro.c b/drivers/input/touchscreen/dynapro.c
index 455353908bdf..1809677a6513 100644
--- a/drivers/input/touchscreen/dynapro.c
+++ b/drivers/input/touchscreen/dynapro.c
@@ -188,19 +188,4 @@ static struct serio_driver dynapro_drv = {
.disconnect = dynapro_disconnect,
};
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init dynapro_init(void)
-{
- return serio_register_driver(&dynapro_drv);
-}
-
-static void __exit dynapro_exit(void)
-{
- serio_unregister_driver(&dynapro_drv);
-}
-
-module_init(dynapro_init);
-module_exit(dynapro_exit);
+module_serio_driver(dynapro_drv);
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c
index 486d31ba9c09..957423d1471d 100644
--- a/drivers/input/touchscreen/elo.c
+++ b/drivers/input/touchscreen/elo.c
@@ -405,19 +405,4 @@ static struct serio_driver elo_drv = {
.disconnect = elo_disconnect,
};
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init elo_init(void)
-{
- return serio_register_driver(&elo_drv);
-}
-
-static void __exit elo_exit(void)
-{
- serio_unregister_driver(&elo_drv);
-}
-
-module_init(elo_init);
-module_exit(elo_exit);
+module_serio_driver(elo_drv);
diff --git a/drivers/input/touchscreen/fujitsu_ts.c b/drivers/input/touchscreen/fujitsu_ts.c
index 80b21800355f..10794ddbdf58 100644
--- a/drivers/input/touchscreen/fujitsu_ts.c
+++ b/drivers/input/touchscreen/fujitsu_ts.c
@@ -175,15 +175,4 @@ static struct serio_driver fujitsu_drv = {
.disconnect = fujitsu_disconnect,
};
-static int __init fujitsu_init(void)
-{
- return serio_register_driver(&fujitsu_drv);
-}
-
-static void __exit fujitsu_exit(void)
-{
- serio_unregister_driver(&fujitsu_drv);
-}
-
-module_init(fujitsu_init);
-module_exit(fujitsu_exit);
+module_serio_driver(fujitsu_drv);
diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c
index a54f90e02ab6..41c71766bf18 100644
--- a/drivers/input/touchscreen/gunze.c
+++ b/drivers/input/touchscreen/gunze.c
@@ -186,19 +186,4 @@ static struct serio_driver gunze_drv = {
.disconnect = gunze_disconnect,
};
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init gunze_init(void)
-{
- return serio_register_driver(&gunze_drv);
-}
-
-static void __exit gunze_exit(void)
-{
- serio_unregister_driver(&gunze_drv);
-}
-
-module_init(gunze_init);
-module_exit(gunze_exit);
+module_serio_driver(gunze_drv);
diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
index 6107e563e681..b9e8686a6f1c 100644
--- a/drivers/input/touchscreen/h3600_ts_input.c
+++ b/drivers/input/touchscreen/h3600_ts_input.c
@@ -476,19 +476,4 @@ static struct serio_driver h3600ts_drv = {
.disconnect = h3600ts_disconnect,
};
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init h3600ts_init(void)
-{
- return serio_register_driver(&h3600ts_drv);
-}
-
-static void __exit h3600ts_exit(void)
-{
- serio_unregister_driver(&h3600ts_drv);
-}
-
-module_init(h3600ts_init);
-module_exit(h3600ts_exit);
+module_serio_driver(h3600ts_drv);
diff --git a/drivers/input/touchscreen/hampshire.c b/drivers/input/touchscreen/hampshire.c
index 2da6cc31bb21..0cc47ea98acf 100644
--- a/drivers/input/touchscreen/hampshire.c
+++ b/drivers/input/touchscreen/hampshire.c
@@ -187,19 +187,4 @@ static struct serio_driver hampshire_drv = {
.disconnect = hampshire_disconnect,
};
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init hampshire_init(void)
-{
- return serio_register_driver(&hampshire_drv);
-}
-
-static void __exit hampshire_exit(void)
-{
- serio_unregister_driver(&hampshire_drv);
-}
-
-module_init(hampshire_init);
-module_exit(hampshire_exit);
+module_serio_driver(hampshire_drv);
diff --git a/drivers/input/touchscreen/inexio.c b/drivers/input/touchscreen/inexio.c
index 192ade0a0fb9..a29c99c32245 100644
--- a/drivers/input/touchscreen/inexio.c
+++ b/drivers/input/touchscreen/inexio.c
@@ -189,19 +189,4 @@ static struct serio_driver inexio_drv = {
.disconnect = inexio_disconnect,
};
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init inexio_init(void)
-{
- return serio_register_driver(&inexio_drv);
-}
-
-static void __exit inexio_exit(void)
-{
- serio_unregister_driver(&inexio_drv);
-}
-
-module_init(inexio_init);
-module_exit(inexio_exit);
+module_serio_driver(inexio_drv);
diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c
index afcd0691ec67..4c2b8ed3bf16 100644
--- a/drivers/input/touchscreen/lpc32xx_ts.c
+++ b/drivers/input/touchscreen/lpc32xx_ts.c
@@ -22,6 +22,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/of.h>
/*
* Touchscreen controller register offsets
@@ -383,6 +384,14 @@ static const struct dev_pm_ops lpc32xx_ts_pm_ops = {
#define LPC32XX_TS_PM_OPS NULL
#endif
+#ifdef CONFIG_OF
+static struct of_device_id lpc32xx_tsc_of_match[] = {
+ { .compatible = "nxp,lpc3220-tsc", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, lpc32xx_tsc_of_match);
+#endif
+
static struct platform_driver lpc32xx_ts_driver = {
.probe = lpc32xx_ts_probe,
.remove = __devexit_p(lpc32xx_ts_remove),
@@ -390,6 +399,7 @@ static struct platform_driver lpc32xx_ts_driver = {
.name = MOD_NAME,
.owner = THIS_MODULE,
.pm = LPC32XX_TS_PM_OPS,
+ .of_match_table = of_match_ptr(lpc32xx_tsc_of_match),
},
};
module_platform_driver(lpc32xx_ts_driver);
diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c
index 9077228418b7..eb66b7c37c2f 100644
--- a/drivers/input/touchscreen/mtouch.c
+++ b/drivers/input/touchscreen/mtouch.c
@@ -202,19 +202,4 @@ static struct serio_driver mtouch_drv = {
.disconnect = mtouch_disconnect,
};
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init mtouch_init(void)
-{
- return serio_register_driver(&mtouch_drv);
-}
-
-static void __exit mtouch_exit(void)
-{
- serio_unregister_driver(&mtouch_drv);
-}
-
-module_init(mtouch_init);
-module_exit(mtouch_exit);
+module_serio_driver(mtouch_drv);
diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c
index 4c012fb2b01e..4ccde45b9da2 100644
--- a/drivers/input/touchscreen/penmount.c
+++ b/drivers/input/touchscreen/penmount.c
@@ -317,19 +317,4 @@ static struct serio_driver pm_drv = {
.disconnect = pm_disconnect,
};
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init pm_init(void)
-{
- return serio_register_driver(&pm_drv);
-}
-
-static void __exit pm_exit(void)
-{
- serio_unregister_driver(&pm_drv);
-}
-
-module_init(pm_init);
-module_exit(pm_exit);
+module_serio_driver(pm_drv);
diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c
index cbbf71b22696..6cb68a1981bf 100644
--- a/drivers/input/touchscreen/st1232.c
+++ b/drivers/input/touchscreen/st1232.c
@@ -218,7 +218,7 @@ static int __devexit st1232_ts_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int st1232_ts_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -243,18 +243,25 @@ static int st1232_ts_resume(struct device *dev)
return 0;
}
-static const struct dev_pm_ops st1232_ts_pm_ops = {
- .suspend = st1232_ts_suspend,
- .resume = st1232_ts_resume,
-};
#endif
+static SIMPLE_DEV_PM_OPS(st1232_ts_pm_ops,
+ st1232_ts_suspend, st1232_ts_resume);
+
static const struct i2c_device_id st1232_ts_id[] = {
{ ST1232_TS_NAME, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, st1232_ts_id);
+#ifdef CONFIG_OF
+static const struct of_device_id st1232_ts_dt_ids[] __devinitconst = {
+ { .compatible = "sitronix,st1232", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, st1232_ts_dt_ids);
+#endif
+
static struct i2c_driver st1232_ts_driver = {
.probe = st1232_ts_probe,
.remove = __devexit_p(st1232_ts_remove),
@@ -262,9 +269,8 @@ static struct i2c_driver st1232_ts_driver = {
.driver = {
.name = ST1232_TS_NAME,
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
+ .of_match_table = of_match_ptr(st1232_ts_dt_ids),
.pm = &st1232_ts_pm_ops,
-#endif
},
};
diff --git a/drivers/input/touchscreen/touchit213.c b/drivers/input/touchscreen/touchit213.c
index d1297ba19daf..5f29e5b8e1c1 100644
--- a/drivers/input/touchscreen/touchit213.c
+++ b/drivers/input/touchscreen/touchit213.c
@@ -216,19 +216,4 @@ static struct serio_driver touchit213_drv = {
.disconnect = touchit213_disconnect,
};
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init touchit213_init(void)
-{
- return serio_register_driver(&touchit213_drv);
-}
-
-static void __exit touchit213_exit(void)
-{
- serio_unregister_driver(&touchit213_drv);
-}
-
-module_init(touchit213_init);
-module_exit(touchit213_exit);
+module_serio_driver(touchit213_drv);
diff --git a/drivers/input/touchscreen/touchright.c b/drivers/input/touchscreen/touchright.c
index 3a5c142c2a78..8a2887daf194 100644
--- a/drivers/input/touchscreen/touchright.c
+++ b/drivers/input/touchscreen/touchright.c
@@ -176,19 +176,4 @@ static struct serio_driver tr_drv = {
.disconnect = tr_disconnect,
};
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init tr_init(void)
-{
- return serio_register_driver(&tr_drv);
-}
-
-static void __exit tr_exit(void)
-{
- serio_unregister_driver(&tr_drv);
-}
-
-module_init(tr_init);
-module_exit(tr_exit);
+module_serio_driver(tr_drv);
diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c
index 763a656a59f8..588cdcb839dd 100644
--- a/drivers/input/touchscreen/touchwin.c
+++ b/drivers/input/touchscreen/touchwin.c
@@ -183,19 +183,4 @@ static struct serio_driver tw_drv = {
.disconnect = tw_disconnect,
};
-/*
- * The functions for inserting/removing us as a module.
- */
-
-static int __init tw_init(void)
-{
- return serio_register_driver(&tw_drv);
-}
-
-static void __exit tw_exit(void)
-{
- serio_unregister_driver(&tw_drv);
-}
-
-module_init(tw_init);
-module_exit(tw_exit);
+module_serio_driver(tw_drv);
diff --git a/drivers/input/touchscreen/tsc40.c b/drivers/input/touchscreen/tsc40.c
index 29d5ed4dd31c..63209aaa55f0 100644
--- a/drivers/input/touchscreen/tsc40.c
+++ b/drivers/input/touchscreen/tsc40.c
@@ -167,17 +167,7 @@ static struct serio_driver tsc_drv = {
.disconnect = tsc_disconnect,
};
-static int __init tsc_ser_init(void)
-{
- return serio_register_driver(&tsc_drv);
-}
-module_init(tsc_ser_init);
-
-static void __exit tsc_exit(void)
-{
- serio_unregister_driver(&tsc_drv);
-}
-module_exit(tsc_exit);
+module_serio_driver(tsc_drv);
MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index 22cd96f58c99..e32709e0dd65 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -269,8 +269,9 @@ static int e2i_init(struct usbtouch_usb *usbtouch)
0x01, 0x02, 0x0000, 0x0081,
NULL, 0, USB_CTRL_SET_TIMEOUT);
- dbg("%s - usb_control_msg - E2I_RESET - bytes|err: %d",
- __func__, ret);
+ dev_dbg(&usbtouch->interface->dev,
+ "%s - usb_control_msg - E2I_RESET - bytes|err: %d\n",
+ __func__, ret);
return ret;
}
@@ -425,8 +426,9 @@ static int mtouch_init(struct usbtouch_usb *usbtouch)
MTOUCHUSB_RESET,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
- dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d",
- __func__, ret);
+ dev_dbg(&usbtouch->interface->dev,
+ "%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d\n",
+ __func__, ret);
if (ret < 0)
return ret;
msleep(150);
@@ -436,8 +438,9 @@ static int mtouch_init(struct usbtouch_usb *usbtouch)
MTOUCHUSB_ASYNC_REPORT,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
- dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
- __func__, ret);
+ dev_dbg(&usbtouch->interface->dev,
+ "%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d\n",
+ __func__, ret);
if (ret >= 0)
break;
if (ret != -EPIPE)
@@ -737,27 +740,29 @@ static int jastec_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
#ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC
static int zytronic_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
{
+ struct usb_interface *intf = dev->interface;
+
switch (pkt[0]) {
case 0x3A: /* command response */
- dbg("%s: Command response %d", __func__, pkt[1]);
+ dev_dbg(&intf->dev, "%s: Command response %d\n", __func__, pkt[1]);
break;
case 0xC0: /* down */
dev->x = (pkt[1] & 0x7f) | ((pkt[2] & 0x07) << 7);
dev->y = (pkt[3] & 0x7f) | ((pkt[4] & 0x07) << 7);
dev->touch = 1;
- dbg("%s: down %d,%d", __func__, dev->x, dev->y);
+ dev_dbg(&intf->dev, "%s: down %d,%d\n", __func__, dev->x, dev->y);
return 1;
case 0x80: /* up */
dev->x = (pkt[1] & 0x7f) | ((pkt[2] & 0x07) << 7);
dev->y = (pkt[3] & 0x7f) | ((pkt[4] & 0x07) << 7);
dev->touch = 0;
- dbg("%s: up %d,%d", __func__, dev->x, dev->y);
+ dev_dbg(&intf->dev, "%s: up %d,%d\n", __func__, dev->x, dev->y);
return 1;
default:
- dbg("%s: Unknown return %d", __func__, pkt[0]);
+ dev_dbg(&intf->dev, "%s: Unknown return %d\n", __func__, pkt[0]);
break;
}
@@ -812,7 +817,8 @@ static int nexio_alloc(struct usbtouch_usb *usbtouch)
priv->ack = usb_alloc_urb(0, GFP_KERNEL);
if (!priv->ack) {
- dbg("%s - usb_alloc_urb failed: usbtouch->ack", __func__);
+ dev_dbg(&usbtouch->interface->dev,
+ "%s - usb_alloc_urb failed: usbtouch->ack\n", __func__);
goto err_ack_buf;
}
@@ -1349,6 +1355,7 @@ out_flush_buf:
static void usbtouch_irq(struct urb *urb)
{
struct usbtouch_usb *usbtouch = urb->context;
+ struct device *dev = &usbtouch->interface->dev;
int retval;
switch (urb->status) {
@@ -1357,20 +1364,21 @@ static void usbtouch_irq(struct urb *urb)
break;
case -ETIME:
/* this urb is timing out */
- dbg("%s - urb timed out - was the device unplugged?",
- __func__);
+ dev_dbg(dev,
+ "%s - urb timed out - was the device unplugged?\n",
+ __func__);
return;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
case -EPIPE:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __func__, urb->status);
+ dev_dbg(dev, "%s - urb shutting down with status: %d\n",
+ __func__, urb->status);
return;
default:
- dbg("%s - nonzero urb status received: %d",
- __func__, urb->status);
+ dev_dbg(dev, "%s - nonzero urb status received: %d\n",
+ __func__, urb->status);
goto exit;
}
@@ -1380,8 +1388,8 @@ exit:
usb_mark_last_busy(interface_to_usbdev(usbtouch->interface));
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
- err("%s - usb_submit_urb failed with result: %d",
- __func__, retval);
+ dev_err(dev, "%s - usb_submit_urb failed with result: %d\n",
+ __func__, retval);
}
static int usbtouch_open(struct input_dev *input)
@@ -1456,8 +1464,9 @@ static int usbtouch_reset_resume(struct usb_interface *intf)
if (usbtouch->type->init) {
err = usbtouch->type->init(usbtouch);
if (err) {
- dbg("%s - type->init() failed, err: %d",
- __func__, err);
+ dev_dbg(&intf->dev,
+ "%s - type->init() failed, err: %d\n",
+ __func__, err);
return err;
}
}
@@ -1532,7 +1541,8 @@ static int usbtouch_probe(struct usb_interface *intf,
usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
if (!usbtouch->irq) {
- dbg("%s - usb_alloc_urb failed: usbtouch->irq", __func__);
+ dev_dbg(&intf->dev,
+ "%s - usb_alloc_urb failed: usbtouch->irq\n", __func__);
goto out_free_buffers;
}
@@ -1594,7 +1604,9 @@ static int usbtouch_probe(struct usb_interface *intf,
if (type->alloc) {
err = type->alloc(usbtouch);
if (err) {
- dbg("%s - type->alloc() failed, err: %d", __func__, err);
+ dev_dbg(&intf->dev,
+ "%s - type->alloc() failed, err: %d\n",
+ __func__, err);
goto out_free_urb;
}
}
@@ -1603,14 +1615,18 @@ static int usbtouch_probe(struct usb_interface *intf,
if (type->init) {
err = type->init(usbtouch);
if (err) {
- dbg("%s - type->init() failed, err: %d", __func__, err);
+ dev_dbg(&intf->dev,
+ "%s - type->init() failed, err: %d\n",
+ __func__, err);
goto out_do_exit;
}
}
err = input_register_device(usbtouch->input);
if (err) {
- dbg("%s - input_register_device failed, err: %d", __func__, err);
+ dev_dbg(&intf->dev,
+ "%s - input_register_device failed, err: %d\n",
+ __func__, err);
goto out_do_exit;
}
@@ -1622,8 +1638,9 @@ static int usbtouch_probe(struct usb_interface *intf,
err = usb_submit_urb(usbtouch->irq, GFP_KERNEL);
if (err) {
usb_autopm_put_interface(intf);
- err("%s - usb_submit_urb failed with result: %d",
- __func__, err);
+ dev_err(&intf->dev,
+ "%s - usb_submit_urb failed with result: %d\n",
+ __func__, err);
goto out_unregister_input;
}
}
@@ -1650,12 +1667,12 @@ static void usbtouch_disconnect(struct usb_interface *intf)
{
struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
- dbg("%s - called", __func__);
-
if (!usbtouch)
return;
- dbg("%s - usbtouch is initialized, cleaning up", __func__);
+ dev_dbg(&intf->dev,
+ "%s - usbtouch is initialized, cleaning up\n", __func__);
+
usb_set_intfdata(intf, NULL);
/* this will stop IO via close */
input_unregister_device(usbtouch->input);
diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c
new file mode 100644
index 000000000000..35572575d34a
--- /dev/null
+++ b/drivers/input/touchscreen/wacom_i2c.c
@@ -0,0 +1,282 @@
+/*
+ * Wacom Penabled Driver for I2C
+ *
+ * Copyright (c) 2011 Tatsunosuke Tobita, Wacom.
+ * <tobita.tatsunosuke@wacom.co.jp>
+ *
+ * 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 of 2 of the License,
+ * or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <asm/unaligned.h>
+
+#define WACOM_CMD_QUERY0 0x04
+#define WACOM_CMD_QUERY1 0x00
+#define WACOM_CMD_QUERY2 0x33
+#define WACOM_CMD_QUERY3 0x02
+#define WACOM_CMD_THROW0 0x05
+#define WACOM_CMD_THROW1 0x00
+#define WACOM_QUERY_SIZE 19
+#define WACOM_RETRY_CNT 100
+
+struct wacom_features {
+ int x_max;
+ int y_max;
+ int pressure_max;
+ char fw_version;
+};
+
+struct wacom_i2c {
+ struct i2c_client *client;
+ struct input_dev *input;
+ u8 data[WACOM_QUERY_SIZE];
+};
+
+static int wacom_query_device(struct i2c_client *client,
+ struct wacom_features *features)
+{
+ int ret;
+ u8 cmd1[] = { WACOM_CMD_QUERY0, WACOM_CMD_QUERY1,
+ WACOM_CMD_QUERY2, WACOM_CMD_QUERY3 };
+ u8 cmd2[] = { WACOM_CMD_THROW0, WACOM_CMD_THROW1 };
+ u8 data[WACOM_QUERY_SIZE];
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = sizeof(cmd1),
+ .buf = cmd1,
+ },
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = sizeof(cmd2),
+ .buf = cmd2,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = sizeof(data),
+ .buf = data,
+ },
+ };
+
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret < 0)
+ return ret;
+ if (ret != ARRAY_SIZE(msgs))
+ return -EIO;
+
+ features->x_max = get_unaligned_le16(&data[3]);
+ features->y_max = get_unaligned_le16(&data[5]);
+ features->pressure_max = get_unaligned_le16(&data[11]);
+ features->fw_version = get_unaligned_le16(&data[13]);
+
+ dev_dbg(&client->dev,
+ "x_max:%d, y_max:%d, pressure:%d, fw:%d\n",
+ features->x_max, features->y_max,
+ features->pressure_max, features->fw_version);
+
+ return 0;
+}
+
+static irqreturn_t wacom_i2c_irq(int irq, void *dev_id)
+{
+ struct wacom_i2c *wac_i2c = dev_id;
+ struct input_dev *input = wac_i2c->input;
+ u8 *data = wac_i2c->data;
+ unsigned int x, y, pressure;
+ unsigned char tsw, f1, f2, ers;
+ int error;
+
+ error = i2c_master_recv(wac_i2c->client,
+ wac_i2c->data, sizeof(wac_i2c->data));
+ if (error < 0)
+ goto out;
+
+ tsw = data[3] & 0x01;
+ ers = data[3] & 0x04;
+ f1 = data[3] & 0x02;
+ f2 = data[3] & 0x10;
+ x = le16_to_cpup((__le16 *)&data[4]);
+ y = le16_to_cpup((__le16 *)&data[6]);
+ pressure = le16_to_cpup((__le16 *)&data[8]);
+
+ input_report_key(input, BTN_TOUCH, tsw || ers);
+ input_report_key(input, BTN_TOOL_PEN, tsw);
+ input_report_key(input, BTN_TOOL_RUBBER, ers);
+ input_report_key(input, BTN_STYLUS, f1);
+ input_report_key(input, BTN_STYLUS2, f2);
+ input_report_abs(input, ABS_X, x);
+ input_report_abs(input, ABS_Y, y);
+ input_report_abs(input, ABS_PRESSURE, pressure);
+ input_sync(input);
+
+out:
+ return IRQ_HANDLED;
+}
+
+static int wacom_i2c_open(struct input_dev *dev)
+{
+ struct wacom_i2c *wac_i2c = input_get_drvdata(dev);
+ struct i2c_client *client = wac_i2c->client;
+
+ enable_irq(client->irq);
+
+ return 0;
+}
+
+static void wacom_i2c_close(struct input_dev *dev)
+{
+ struct wacom_i2c *wac_i2c = input_get_drvdata(dev);
+ struct i2c_client *client = wac_i2c->client;
+
+ disable_irq(client->irq);
+}
+
+static int __devinit wacom_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct wacom_i2c *wac_i2c;
+ struct input_dev *input;
+ struct wacom_features features;
+ int error;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "i2c_check_functionality error\n");
+ return -EIO;
+ }
+
+ error = wacom_query_device(client, &features);
+ if (error)
+ return error;
+
+ wac_i2c = kzalloc(sizeof(*wac_i2c), GFP_KERNEL);
+ input = input_allocate_device();
+ if (!wac_i2c || !input) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ wac_i2c->client = client;
+ wac_i2c->input = input;
+
+ input->name = "Wacom I2C Digitizer";
+ input->id.bustype = BUS_I2C;
+ input->id.vendor = 0x56a;
+ input->id.version = features.fw_version;
+ input->dev.parent = &client->dev;
+ input->open = wacom_i2c_open;
+ input->close = wacom_i2c_close;
+
+ input->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+
+ __set_bit(BTN_TOOL_PEN, input->keybit);
+ __set_bit(BTN_TOOL_RUBBER, input->keybit);
+ __set_bit(BTN_STYLUS, input->keybit);
+ __set_bit(BTN_STYLUS2, input->keybit);
+ __set_bit(BTN_TOUCH, input->keybit);
+
+ input_set_abs_params(input, ABS_X, 0, features.x_max, 0, 0);
+ input_set_abs_params(input, ABS_Y, 0, features.y_max, 0, 0);
+ input_set_abs_params(input, ABS_PRESSURE,
+ 0, features.pressure_max, 0, 0);
+
+ input_set_drvdata(input, wac_i2c);
+
+ error = request_threaded_irq(client->irq, NULL, wacom_i2c_irq,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "wacom_i2c", wac_i2c);
+ if (error) {
+ dev_err(&client->dev,
+ "Failed to enable IRQ, error: %d\n", error);
+ goto err_free_mem;
+ }
+
+ /* Disable the IRQ, we'll enable it in wac_i2c_open() */
+ disable_irq(client->irq);
+
+ error = input_register_device(wac_i2c->input);
+ if (error) {
+ dev_err(&client->dev,
+ "Failed to register input device, error: %d\n", error);
+ goto err_free_irq;
+ }
+
+ i2c_set_clientdata(client, wac_i2c);
+ return 0;
+
+err_free_irq:
+ free_irq(client->irq, wac_i2c);
+err_free_mem:
+ input_free_device(input);
+ kfree(wac_i2c);
+
+ return error;
+}
+
+static int __devexit wacom_i2c_remove(struct i2c_client *client)
+{
+ struct wacom_i2c *wac_i2c = i2c_get_clientdata(client);
+
+ free_irq(client->irq, wac_i2c);
+ input_unregister_device(wac_i2c->input);
+ kfree(wac_i2c);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int wacom_i2c_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ disable_irq(client->irq);
+
+ return 0;
+}
+
+static int wacom_i2c_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ enable_irq(client->irq);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(wacom_i2c_pm, wacom_i2c_suspend, wacom_i2c_resume);
+
+static const struct i2c_device_id wacom_i2c_id[] = {
+ { "WAC_I2C_EMR", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, wacom_i2c_id);
+
+static struct i2c_driver wacom_i2c_driver = {
+ .driver = {
+ .name = "wacom_i2c",
+ .owner = THIS_MODULE,
+ .pm = &wacom_i2c_pm,
+ },
+
+ .probe = wacom_i2c_probe,
+ .remove = __devexit_p(wacom_i2c_remove),
+ .id_table = wacom_i2c_id,
+};
+module_i2c_driver(wacom_i2c_driver);
+
+MODULE_AUTHOR("Tatsunosuke Tobita <tobita.tatsunosuke@wacom.co.jp>");
+MODULE_DESCRIPTION("WACOM EMR I2C Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c
index 1569a3934ab2..8f9ad2f893b8 100644
--- a/drivers/input/touchscreen/wacom_w8001.c
+++ b/drivers/input/touchscreen/wacom_w8001.c
@@ -594,15 +594,4 @@ static struct serio_driver w8001_drv = {
.disconnect = w8001_disconnect,
};
-static int __init w8001_init(void)
-{
- return serio_register_driver(&w8001_drv);
-}
-
-static void __exit w8001_exit(void)
-{
- serio_unregister_driver(&w8001_drv);
-}
-
-module_init(w8001_init);
-module_exit(w8001_exit);
+module_serio_driver(w8001_drv);
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 3bd9fff5c589..c69843742bb0 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -43,7 +43,7 @@ config AMD_IOMMU
With this option you can enable support for AMD IOMMU hardware in
your system. An IOMMU is a hardware component which provides
remapping of DMA memory accesses from devices. With an AMD IOMMU you
- can isolate the the DMA memory of different devices and protect the
+ can isolate the DMA memory of different devices and protect the
system from misbehaving device drivers or hardware.
You can find out if your system has an AMD IOMMU if you look into
@@ -67,7 +67,7 @@ config AMD_IOMMU_V2
---help---
This option enables support for the AMD IOMMUv2 features of the IOMMU
hardware. Select this option if you want to use devices that support
- the the PCI PRI and PASID interface.
+ the PCI PRI and PASID interface.
# Intel IOMMU support
config DMAR_TABLE
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index 3b9278b333ba..527588708948 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -148,6 +148,7 @@ static struct usb_driver gigaset_usb_driver = {
.reset_resume = gigaset_post_reset,
.pre_reset = gigaset_pre_reset,
.post_reset = gigaset_post_reset,
+ .disable_hub_initiated_lpm = 1,
};
/* get message text for usb_submit_urb return code
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c
index bb12d8051732..d0a41cb0cf62 100644
--- a/drivers/isdn/gigaset/usb-gigaset.c
+++ b/drivers/isdn/gigaset/usb-gigaset.c
@@ -124,6 +124,7 @@ static struct usb_driver gigaset_usb_driver = {
.reset_resume = gigaset_resume,
.pre_reset = gigaset_pre_reset,
.post_reset = gigaset_resume,
+ .disable_hub_initiated_lpm = 1,
};
struct usb_cardstate {
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c
index 83206e453d4e..c65c3440cd70 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -2126,6 +2126,7 @@ static struct usb_driver hfcsusb_drv = {
.id_table = hfcsusb_idtab,
.probe = hfcsusb_probe,
.disconnect = hfcsusb_disconnect,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(hfcsusb_drv);
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.h b/drivers/isdn/hardware/mISDN/hfcsusb.h
index cb1231b08f78..4157311d569d 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.h
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.h
@@ -410,6 +410,12 @@ static struct usb_device_id hfcsusb_idtab[] = {
{LED_SCHEME1, {0x88, -64, -32, -16},
"ZyXEL OMNI.NET USB II"}),
},
+ {
+ USB_DEVICE(0x1ae7, 0x0525),
+ .driver_info = (unsigned long) &((struct hfcsusb_vdata)
+ {LED_SCHEME1, {0x88, -64, -32, -16},
+ "X-Tensions USB ISDN TA XC-525"}),
+ },
{ }
};
diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
index 62c65bdefd8a..84f9c8103078 100644
--- a/drivers/isdn/hisax/hfc_usb.c
+++ b/drivers/isdn/hisax/hfc_usb.c
@@ -1568,6 +1568,7 @@ static struct usb_driver hfc_drv = {
.id_table = hfcusb_idtab,
.probe = hfc_usb_probe,
.disconnect = hfc_usb_disconnect,
+ .disable_hub_initiated_lpm = 1,
};
static void __exit
diff --git a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c
index 100296e20dc0..54ef9e4f8cbc 100644
--- a/drivers/isdn/hisax/st5481_init.c
+++ b/drivers/isdn/hisax/st5481_init.c
@@ -182,6 +182,7 @@ static struct usb_driver st5481_usb_driver = {
.probe = probe_st5481,
.disconnect = disconnect_st5481,
.id_table = st5481_ids,
+ .disable_hub_initiated_lpm = 1,
};
static int __init st5481_usb_init(void)
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index d9f5524593fb..8c610fa6782b 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -46,7 +46,6 @@ static DEFINE_MUTEX(isdn_mutex);
static char *isdn_revision = "$Revision: 1.1.2.3 $";
extern char *isdn_net_revision;
-extern char *isdn_tty_revision;
#ifdef CONFIG_ISDN_PPP
extern char *isdn_ppp_revision;
#else
@@ -2327,8 +2326,6 @@ static int __init isdn_init(void)
dev->chanmap[i] = -1;
dev->m_idx[i] = -1;
strcpy(dev->num[i], "???");
- init_waitqueue_head(&dev->mdm.info[i].open_wait);
- init_waitqueue_head(&dev->mdm.info[i].close_wait);
}
if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
printk(KERN_WARNING "isdn: Could not register control devices\n");
@@ -2353,8 +2350,6 @@ static int __init isdn_init(void)
strcpy(tmprev, isdn_revision);
printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(tmprev));
- strcpy(tmprev, isdn_tty_revision);
- printk("%s/", isdn_getrev(tmprev));
strcpy(tmprev, isdn_net_revision);
printk("%s/", isdn_getrev(tmprev));
strcpy(tmprev, isdn_ppp_revision);
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 3831abdbc66f..7bc50670d7d9 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1,5 +1,4 @@
-/* $Id: isdn_tty.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $
- *
+/*
* Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
*
* Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
@@ -12,6 +11,7 @@
#undef ISDN_TTY_STAT_DEBUG
#include <linux/isdn.h>
+#include <linux/serial.h> /* ASYNC_* flags */
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/mutex.h>
@@ -48,9 +48,6 @@ static int bit2si[8] =
static int si2bit[8] =
{4, 1, 4, 4, 4, 4, 4, 4};
-char *isdn_tty_revision = "$Revision: 1.1.2.3 $";
-
-
/* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
* to stuff incoming data directly into a tty's flip-buffer. This
* is done to speed up tty-receiving if the receive-queue is empty.
@@ -68,49 +65,54 @@ isdn_tty_try_read(modem_info *info, struct sk_buff *skb)
struct tty_struct *tty;
char last;
- if (info->online) {
- if ((tty = info->tty)) {
- if (info->mcr & UART_MCR_RTS) {
- len = skb->len
+ if (!info->online)
+ return 0;
+
+ tty = info->port.tty;
+ if (!tty)
+ return 0;
+
+ if (!(info->mcr & UART_MCR_RTS))
+ return 0;
+
+ len = skb->len
#ifdef CONFIG_ISDN_AUDIO
- + ISDN_AUDIO_SKB_DLECOUNT(skb)
+ + ISDN_AUDIO_SKB_DLECOUNT(skb)
#endif
- ;
+ ;
+
+ c = tty_buffer_request_room(tty, len);
+ if (c < len)
+ return 0;
- c = tty_buffer_request_room(tty, len);
- if (c >= len) {
-#ifdef CONFIG_ISDN_AUDIO
- if (ISDN_AUDIO_SKB_DLECOUNT(skb)) {
- int l = skb->len;
- unsigned char *dp = skb->data;
- while (--l) {
- if (*dp == DLE)
- tty_insert_flip_char(tty, DLE, 0);
- tty_insert_flip_char(tty, *dp++, 0);
- }
- if (*dp == DLE)
- tty_insert_flip_char(tty, DLE, 0);
- last = *dp;
- } else {
-#endif
- if (len > 1)
- tty_insert_flip_string(tty, skb->data, len - 1);
- last = skb->data[len - 1];
#ifdef CONFIG_ISDN_AUDIO
- }
+ if (ISDN_AUDIO_SKB_DLECOUNT(skb)) {
+ int l = skb->len;
+ unsigned char *dp = skb->data;
+ while (--l) {
+ if (*dp == DLE)
+ tty_insert_flip_char(tty, DLE, 0);
+ tty_insert_flip_char(tty, *dp++, 0);
+ }
+ if (*dp == DLE)
+ tty_insert_flip_char(tty, DLE, 0);
+ last = *dp;
+ } else {
#endif
- if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP)
- tty_insert_flip_char(tty, last, 0xFF);
- else
- tty_insert_flip_char(tty, last, TTY_NORMAL);
- tty_flip_buffer_push(tty);
- kfree_skb(skb);
- return 1;
- }
- }
- }
+ if (len > 1)
+ tty_insert_flip_string(tty, skb->data, len - 1);
+ last = skb->data[len - 1];
+#ifdef CONFIG_ISDN_AUDIO
}
- return 0;
+#endif
+ if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP)
+ tty_insert_flip_char(tty, last, 0xFF);
+ else
+ tty_insert_flip_char(tty, last, TTY_NORMAL);
+ tty_flip_buffer_push(tty);
+ kfree_skb(skb);
+
+ return 1;
}
/* isdn_tty_readmodem() is called periodically from within timer-interrupt.
@@ -128,35 +130,39 @@ isdn_tty_readmodem(void)
modem_info *info;
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- if ((midx = dev->m_idx[i]) >= 0) {
- info = &dev->mdm.info[midx];
- if (info->online) {
- r = 0;
+ midx = dev->m_idx[i];
+ if (midx < 0)
+ continue;
+
+ info = &dev->mdm.info[midx];
+ if (!info->online)
+ continue;
+
+ r = 0;
#ifdef CONFIG_ISDN_AUDIO
- isdn_audio_eval_dtmf(info);
- if ((info->vonline & 1) && (info->emu.vpar[1]))
- isdn_audio_eval_silence(info);
-#endif
- if ((tty = info->tty)) {
- if (info->mcr & UART_MCR_RTS) {
- /* CISCO AsyncPPP Hack */
- if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
- r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 0);
- else
- r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 1);
- if (r)
- tty_flip_buffer_push(tty);
- } else
- r = 1;
- } else
- r = 1;
- if (r) {
- info->rcvsched = 0;
- resched = 1;
- } else
- info->rcvsched = 1;
- }
- }
+ isdn_audio_eval_dtmf(info);
+ if ((info->vonline & 1) && (info->emu.vpar[1]))
+ isdn_audio_eval_silence(info);
+#endif
+ tty = info->port.tty;
+ if (tty) {
+ if (info->mcr & UART_MCR_RTS) {
+ /* CISCO AsyncPPP Hack */
+ if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP))
+ r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 0);
+ else
+ r = isdn_readbchan_tty(info->isdn_driver, info->isdn_channel, tty, 1);
+ if (r)
+ tty_flip_buffer_push(tty);
+ } else
+ r = 1;
+ } else
+ r = 1;
+ if (r) {
+ info->rcvsched = 0;
+ resched = 1;
+ } else
+ info->rcvsched = 1;
}
if (!resched)
isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0);
@@ -294,7 +300,7 @@ isdn_tty_tint(modem_info *info)
len = skb->len;
if ((slen = isdn_writebuf_skb_stub(info->isdn_driver,
info->isdn_channel, 1, skb)) == len) {
- struct tty_struct *tty = info->tty;
+ struct tty_struct *tty = info->port.tty;
info->send_outstanding++;
info->msr &= ~UART_MSR_CTS;
info->lsr &= ~UART_LSR_TEMT;
@@ -327,7 +333,7 @@ isdn_tty_countDLE(unsigned char *buf, int len)
static int
isdn_tty_handleDLEdown(modem_info *info, atemu *m, int len)
{
- unsigned char *p = &info->xmit_buf[info->xmit_count];
+ unsigned char *p = &info->port.xmit_buf[info->xmit_count];
int count = 0;
while (len > 0) {
@@ -471,7 +477,7 @@ isdn_tty_senddown(modem_info *info)
return;
}
skb_reserve(skb, skb_res);
- memcpy(skb_put(skb, buflen), info->xmit_buf, buflen);
+ memcpy(skb_put(skb, buflen), info->port.xmit_buf, buflen);
info->xmit_count = 0;
#ifdef CONFIG_ISDN_AUDIO
if (info->vonline & 2) {
@@ -699,7 +705,7 @@ isdn_tty_modem_hup(modem_info *info, int local)
printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);
#endif
info->rcvsched = 0;
- isdn_tty_flush_buffer(info->tty);
+ isdn_tty_flush_buffer(info->port.tty);
if (info->online) {
info->last_lhup = local;
info->online = 0;
@@ -997,20 +1003,21 @@ isdn_tty_paranoia_check(modem_info *info, char *name, const char *routine)
static void
isdn_tty_change_speed(modem_info *info)
{
+ struct tty_port *port = &info->port;
uint cflag,
cval,
quot;
int i;
- if (!info->tty || !info->tty->termios)
+ if (!port->tty || !port->tty->termios)
return;
- cflag = info->tty->termios->c_cflag;
+ cflag = port->tty->termios->c_cflag;
quot = i = cflag & CBAUD;
if (i & CBAUDEX) {
i &= ~CBAUDEX;
if (i < 1 || i > 2)
- info->tty->termios->c_cflag &= ~CBAUDEX;
+ port->tty->termios->c_cflag &= ~CBAUDEX;
else
i += 15;
}
@@ -1040,20 +1047,20 @@ isdn_tty_change_speed(modem_info *info)
/* CTS flow control flag and modem status interrupts */
if (cflag & CRTSCTS) {
- info->flags |= ISDN_ASYNC_CTS_FLOW;
+ port->flags |= ASYNC_CTS_FLOW;
} else
- info->flags &= ~ISDN_ASYNC_CTS_FLOW;
+ port->flags &= ~ASYNC_CTS_FLOW;
if (cflag & CLOCAL)
- info->flags &= ~ISDN_ASYNC_CHECK_CD;
+ port->flags &= ~ASYNC_CHECK_CD;
else {
- info->flags |= ISDN_ASYNC_CHECK_CD;
+ port->flags |= ASYNC_CHECK_CD;
}
}
static int
isdn_tty_startup(modem_info *info)
{
- if (info->flags & ISDN_ASYNC_INITIALIZED)
+ if (info->port.flags & ASYNC_INITIALIZED)
return 0;
isdn_lock_drivers();
#ifdef ISDN_DEBUG_MODEM_OPEN
@@ -1063,14 +1070,14 @@ isdn_tty_startup(modem_info *info)
* Now, initialize the UART
*/
info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
- if (info->tty)
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ if (info->port.tty)
+ clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
/*
* and set the speed of the serial port
*/
isdn_tty_change_speed(info);
- info->flags |= ISDN_ASYNC_INITIALIZED;
+ info->port.flags |= ASYNC_INITIALIZED;
info->msr |= (UART_MSR_DSR | UART_MSR_CTS);
info->send_outstanding = 0;
return 0;
@@ -1083,14 +1090,14 @@ isdn_tty_startup(modem_info *info)
static void
isdn_tty_shutdown(modem_info *info)
{
- if (!(info->flags & ISDN_ASYNC_INITIALIZED))
+ if (!(info->port.flags & ASYNC_INITIALIZED))
return;
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line);
#endif
isdn_unlock_drivers();
info->msr &= ~UART_MSR_RI;
- if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+ if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
isdn_tty_modem_reset_regs(info, 0);
@@ -1100,10 +1107,10 @@ isdn_tty_shutdown(modem_info *info)
isdn_tty_modem_hup(info, 1);
}
}
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
+ if (info->port.tty)
+ set_bit(TTY_IO_ERROR, &info->port.tty->flags);
- info->flags &= ~ISDN_ASYNC_INITIALIZED;
+ info->port.flags &= ~ASYNC_INITIALIZED;
}
/* isdn_tty_write() is the main send-routine. It is called from the upper
@@ -1146,7 +1153,7 @@ isdn_tty_write(struct tty_struct *tty, const u_char *buf, int count)
isdn_tty_check_esc(buf, m->mdmreg[REG_ESC], c,
&(m->pluscount),
&(m->lastplus));
- memcpy(&(info->xmit_buf[info->xmit_count]), buf, c);
+ memcpy(&info->port.xmit_buf[info->xmit_count], buf, c);
#ifdef CONFIG_ISDN_AUDIO
if (info->vonline) {
int cc = isdn_tty_handleDLEdown(info, m, c);
@@ -1478,107 +1485,6 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
* isdn_tty_open() and friends
* ------------------------------------------------------------
*/
-static int
-isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info *info)
-{
- DECLARE_WAITQUEUE(wait, NULL);
- int do_clocal = 0;
- int retval;
-
- /*
- * If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (tty_hung_up_p(filp) ||
- (info->flags & ISDN_ASYNC_CLOSING)) {
- if (info->flags & ISDN_ASYNC_CLOSING)
- interruptible_sleep_on(&info->close_wait);
-#ifdef MODEM_DO_RESTART
- if (info->flags & ISDN_ASYNC_HUP_NOTIFY)
- return -EAGAIN;
- else
- return -ERESTARTSYS;
-#else
- return -EAGAIN;
-#endif
- }
- /*
- * If non-blocking mode is set, then make the check up front
- * and then exit.
- */
- if ((filp->f_flags & O_NONBLOCK) ||
- (tty->flags & (1 << TTY_IO_ERROR))) {
- if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
- return -EBUSY;
- info->flags |= ISDN_ASYNC_NORMAL_ACTIVE;
- return 0;
- }
- if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) {
- if (info->normal_termios.c_cflag & CLOCAL)
- do_clocal = 1;
- } else {
- if (tty->termios->c_cflag & CLOCAL)
- do_clocal = 1;
- }
- /*
- * Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, info->count is dropped by one, so that
- * isdn_tty_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
- retval = 0;
- add_wait_queue(&info->open_wait, &wait);
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_block_til_ready before block: ttyi%d, count = %d\n",
- info->line, info->count);
-#endif
- if (!(tty_hung_up_p(filp)))
- info->count--;
- info->blocked_open++;
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp) ||
- !(info->flags & ISDN_ASYNC_INITIALIZED)) {
-#ifdef MODEM_DO_RESTART
- if (info->flags & ISDN_ASYNC_HUP_NOTIFY)
- retval = -EAGAIN;
- else
- retval = -ERESTARTSYS;
-#else
- retval = -EAGAIN;
-#endif
- break;
- }
- if (!(info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
- !(info->flags & ISDN_ASYNC_CLOSING) &&
- (do_clocal || (info->msr & UART_MSR_DCD))) {
- break;
- }
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_block_til_ready blocking: ttyi%d, count = %d\n",
- info->line, info->count);
-#endif
- schedule();
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&info->open_wait, &wait);
- if (!tty_hung_up_p(filp))
- info->count++;
- info->blocked_open--;
-#ifdef ISDN_DEBUG_MODEM_OPEN
- printk(KERN_DEBUG "isdn_tty_block_til_ready after blocking: ttyi%d, count = %d\n",
- info->line, info->count);
-#endif
- if (retval)
- return retval;
- info->flags |= ISDN_ASYNC_NORMAL_ACTIVE;
- return 0;
-}
/*
* This routine is called whenever a serial port is opened. It
@@ -1589,23 +1495,22 @@ isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info *
static int
isdn_tty_open(struct tty_struct *tty, struct file *filp)
{
+ struct tty_port *port;
modem_info *info;
int retval;
info = &dev->mdm.info[tty->index];
if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open"))
return -ENODEV;
- if (!try_module_get(info->owner)) {
- printk(KERN_WARNING "%s: cannot reserve module\n", __func__);
- return -ENODEV;
- }
+ port = &info->port;
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name,
- info->count);
+ port->count);
#endif
- info->count++;
+ port->count++;
tty->driver_data = info;
- info->tty = tty;
+ port->tty = tty;
+ tty->port = port;
/*
* Start up serial port
*/
@@ -1614,15 +1519,13 @@ isdn_tty_open(struct tty_struct *tty, struct file *filp)
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "isdn_tty_open return after startup\n");
#endif
- module_put(info->owner);
return retval;
}
- retval = isdn_tty_block_til_ready(tty, filp, info);
+ retval = tty_port_block_til_ready(port, tty, filp);
if (retval) {
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "isdn_tty_open return after isdn_tty_block_til_ready \n");
#endif
- module_put(info->owner);
return retval;
}
#ifdef ISDN_DEBUG_MODEM_OPEN
@@ -1639,6 +1542,7 @@ static void
isdn_tty_close(struct tty_struct *tty, struct file *filp)
{
modem_info *info = (modem_info *) tty->driver_data;
+ struct tty_port *port = &info->port;
ulong timeout;
if (!info || isdn_tty_paranoia_check(info, tty->name, "isdn_tty_close"))
@@ -1649,7 +1553,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
#endif
return;
}
- if ((tty->count == 1) && (info->count != 1)) {
+ if ((tty->count == 1) && (port->count != 1)) {
/*
* Uh, oh. tty->count is 1, which means that the tty
* structure will be freed. Info->count should always
@@ -1658,30 +1562,21 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
* serial port won't be shutdown.
*/
printk(KERN_ERR "isdn_tty_close: bad port count; tty->count is 1, "
- "info->count is %d\n", info->count);
- info->count = 1;
+ "info->count is %d\n", port->count);
+ port->count = 1;
}
- if (--info->count < 0) {
+ if (--port->count < 0) {
printk(KERN_ERR "isdn_tty_close: bad port count for ttyi%d: %d\n",
- info->line, info->count);
- info->count = 0;
+ info->line, port->count);
+ port->count = 0;
}
- if (info->count) {
+ if (port->count) {
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "isdn_tty_close after info->count != 0\n");
#endif
- module_put(info->owner);
return;
}
- info->flags |= ISDN_ASYNC_CLOSING;
- /*
- * Save the termios structure, since this port may have
- * separate termios for callout and dialin.
- */
- if (info->flags & ISDN_ASYNC_NORMAL_ACTIVE)
- info->normal_termios = *tty->termios;
- if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE)
- info->callout_termios = *tty->termios;
+ port->flags |= ASYNC_CLOSING;
tty->closing = 1;
/*
@@ -1690,7 +1585,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
* interrupt driver to stop checking the data ready bit in the
* line status register.
*/
- if (info->flags & ISDN_ASYNC_INITIALIZED) {
+ if (port->flags & ASYNC_INITIALIZED) {
tty_wait_until_sent_from_close(tty, 3000); /* 30 seconds timeout */
/*
* Before we drop DTR, make sure the UART transmitter
@@ -1708,16 +1603,10 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp)
isdn_tty_shutdown(info);
isdn_tty_flush_buffer(tty);
tty_ldisc_flush(tty);
- info->tty = NULL;
+ port->tty = NULL;
info->ncarrier = 0;
- tty->closing = 0;
- module_put(info->owner);
- if (info->blocked_open) {
- msleep_interruptible(500);
- wake_up_interruptible(&info->open_wait);
- }
- info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CLOSING);
- wake_up_interruptible(&info->close_wait);
+
+ tty_port_close_end(port, tty);
#ifdef ISDN_DEBUG_MODEM_OPEN
printk(KERN_DEBUG "isdn_tty_close normal exit\n");
#endif
@@ -1730,14 +1619,15 @@ static void
isdn_tty_hangup(struct tty_struct *tty)
{
modem_info *info = (modem_info *) tty->driver_data;
+ struct tty_port *port = &info->port;
if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_hangup"))
return;
isdn_tty_shutdown(info);
- info->count = 0;
- info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE);
- info->tty = NULL;
- wake_up_interruptible(&info->open_wait);
+ port->count = 0;
+ port->flags &= ~ASYNC_NORMAL_ACTIVE;
+ port->tty = NULL;
+ wake_up_interruptible(&port->open_wait);
}
/* This routine initializes all emulator-data.
@@ -1864,6 +1754,16 @@ static const struct tty_operations modem_ops = {
.tiocmset = isdn_tty_tiocmset,
};
+static int isdn_tty_carrier_raised(struct tty_port *port)
+{
+ modem_info *info = container_of(port, modem_info, port);
+ return info->msr & UART_MSR_DCD;
+}
+
+static const struct tty_port_operations isdn_tty_port_ops = {
+ .carrier_raised = isdn_tty_carrier_raised,
+};
+
int
isdn_tty_modem_init(void)
{
@@ -1899,9 +1799,8 @@ isdn_tty_modem_init(void)
goto err_unregister;
}
#endif
-#ifdef MODULE
- info->owner = THIS_MODULE;
-#endif
+ tty_port_init(&info->port);
+ info->port.ops = &isdn_tty_port_ops;
spin_lock_init(&info->readlock);
sprintf(info->last_cause, "0000");
sprintf(info->last_num, "none");
@@ -1913,12 +1812,7 @@ isdn_tty_modem_init(void)
isdn_tty_modem_reset_regs(info, 1);
info->magic = ISDN_ASYNC_MAGIC;
info->line = i;
- info->tty = NULL;
info->x_char = 0;
- info->count = 0;
- info->blocked_open = 0;
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
info->isdn_driver = -1;
info->isdn_channel = -1;
info->drv_index = -1;
@@ -1930,13 +1824,15 @@ isdn_tty_modem_init(void)
#ifdef CONFIG_ISDN_AUDIO
skb_queue_head_init(&info->dtmf_queue);
#endif
- if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5, GFP_KERNEL))) {
+ info->port.xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5,
+ GFP_KERNEL);
+ if (!info->port.xmit_buf) {
printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
retval = -ENOMEM;
goto err_unregister;
}
/* Make room for T.70 header */
- info->xmit_buf += 4;
+ info->port.xmit_buf += 4;
}
return 0;
err_unregister:
@@ -1945,7 +1841,7 @@ err_unregister:
#ifdef CONFIG_ISDN_TTY_FAX
kfree(info->fax);
#endif
- kfree(info->xmit_buf - 4);
+ kfree(info->port.xmit_buf - 4);
}
tty_unregister_driver(m->tty_modem);
err:
@@ -1966,7 +1862,7 @@ isdn_tty_exit(void)
#ifdef CONFIG_ISDN_TTY_FAX
kfree(info->fax);
#endif
- kfree(info->xmit_buf - 4);
+ kfree(info->port.xmit_buf - 4);
}
tty_unregister_driver(dev->mdm.tty_modem);
put_tty_driver(dev->mdm.tty_modem);
@@ -2068,7 +1964,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
modem_info *info = &dev->mdm.info[i];
- if (info->count == 0)
+ if (info->port.count == 0)
continue;
if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */
(info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */
@@ -2076,12 +1972,12 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)
#ifdef ISDN_DEBUG_MODEM_ICALL
printk(KERN_DEBUG "m_fi: match1 wret=%d\n", wret);
printk(KERN_DEBUG "m_fi: idx=%d flags=%08lx drv=%d ch=%d usg=%d\n", idx,
- info->flags, info->isdn_driver, info->isdn_channel,
- dev->usage[idx]);
+ info->port.flags, info->isdn_driver,
+ info->isdn_channel, dev->usage[idx]);
#endif
if (
#ifndef FIX_FILE_TRANSFER
- (info->flags & ISDN_ASYNC_NORMAL_ACTIVE) &&
+ (info->port.flags & ASYNC_NORMAL_ACTIVE) &&
#endif
(info->isdn_driver == -1) &&
(info->isdn_channel == -1) &&
@@ -2120,8 +2016,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm *setup)
return (wret == 2) ? 3 : 0;
}
-#define TTY_IS_ACTIVE(info) \
- (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE))
+#define TTY_IS_ACTIVE(info) (info->port.flags & ASYNC_NORMAL_ACTIVE)
int
isdn_tty_stat_callback(int i, isdn_ctrl *c)
@@ -2212,9 +2107,9 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
* for incoming call of this device when
* DCD follow the state of incoming carrier
*/
- if (info->blocked_open &&
+ if (info->port.blocked_open &&
(info->emu.mdmreg[REG_DCD] & BIT_DCD)) {
- wake_up_interruptible(&info->open_wait);
+ wake_up_interruptible(&info->port.open_wait);
}
/* Schedule CONNECT-Message to any tty
@@ -2222,7 +2117,8 @@ isdn_tty_stat_callback(int i, isdn_ctrl *c)
* set DCD-bit of its modem-status.
*/
if (TTY_IS_ACTIVE(info) ||
- (info->blocked_open && (info->emu.mdmreg[REG_DCD] & BIT_DCD))) {
+ (info->port.blocked_open &&
+ (info->emu.mdmreg[REG_DCD] & BIT_DCD))) {
info->msr |= UART_MSR_DCD;
info->emu.charge = 0;
if (info->dialing & 0xf)
@@ -2339,8 +2235,8 @@ isdn_tty_at_cout(char *msg, modem_info *info)
l = strlen(msg);
spin_lock_irqsave(&info->readlock, flags);
- tty = info->tty;
- if ((info->flags & ISDN_ASYNC_CLOSING) || (!tty)) {
+ tty = info->port.tty;
+ if ((info->port.flags & ASYNC_CLOSING) || (!tty)) {
spin_unlock_irqrestore(&info->readlock, flags);
return;
}
@@ -2490,15 +2386,15 @@ isdn_tty_modem_result(int code, modem_info *info)
case RESULT_NO_CARRIER:
#ifdef ISDN_DEBUG_MODEM_HUP
printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n",
- (info->flags & ISDN_ASYNC_CLOSING),
- (!info->tty));
+ (info->port.flags & ASYNC_CLOSING),
+ (!info->port.tty));
#endif
m->mdmreg[REG_RINGCNT] = 0;
del_timer(&info->nc_timer);
info->ncarrier = 0;
- if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
+ if ((info->port.flags & ASYNC_CLOSING) || (!info->port.tty))
return;
- }
+
#ifdef CONFIG_ISDN_AUDIO
if (info->vonline & 1) {
#ifdef ISDN_DEBUG_MODEM_VOICE
@@ -2629,14 +2525,11 @@ isdn_tty_modem_result(int code, modem_info *info)
}
}
if (code == RESULT_NO_CARRIER) {
- if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
+ if ((info->port.flags & ASYNC_CLOSING) || (!info->port.tty))
return;
- }
- if ((info->flags & ISDN_ASYNC_CHECK_CD) &&
- (!((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) &&
- (info->flags & ISDN_ASYNC_CALLOUT_NOHUP)))) {
- tty_hangup(info->tty);
- }
+
+ if (info->port.flags & ASYNC_CHECK_CD)
+ tty_hangup(info->port.tty);
}
}
@@ -3803,19 +3696,19 @@ isdn_tty_modem_escape(void)
int midx;
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
- if (USG_MODEM(dev->usage[i]))
- if ((midx = dev->m_idx[i]) >= 0) {
- modem_info *info = &dev->mdm.info[midx];
- if (info->online) {
- ton = 1;
- if ((info->emu.pluscount == 3) &&
- time_after(jiffies , info->emu.lastplus + PLUSWAIT2)) {
- info->emu.pluscount = 0;
- info->online = 0;
- isdn_tty_modem_result(RESULT_OK, info);
- }
+ if (USG_MODEM(dev->usage[i]) && (midx = dev->m_idx[i]) >= 0) {
+ modem_info *info = &dev->mdm.info[midx];
+ if (info->online) {
+ ton = 1;
+ if ((info->emu.pluscount == 3) &&
+ time_after(jiffies,
+ info->emu.lastplus + PLUSWAIT2)) {
+ info->emu.pluscount = 0;
+ info->online = 0;
+ isdn_tty_modem_result(RESULT_OK, info);
}
}
+ }
isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton);
}
@@ -3873,15 +3766,14 @@ isdn_tty_carrier_timeout(void)
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
modem_info *info = &dev->mdm.info[i];
- if (info->dialing) {
- if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) {
- info->dialing = 0;
- isdn_tty_modem_result(RESULT_NO_CARRIER, info);
- isdn_tty_modem_hup(info, 1);
- }
- else
- ton = 1;
- }
+ if (!info->dialing)
+ continue;
+ if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) {
+ info->dialing = 0;
+ isdn_tty_modem_result(RESULT_NO_CARRIER, info);
+ isdn_tty_modem_hup(info, 1);
+ } else
+ ton = 1;
}
isdn_timer_ctrl(ISDN_TIMER_CARRIER, ton);
}
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index fa51af11c6f1..a555da64224e 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -204,11 +204,14 @@ config THERM_ADT746X
better fan behaviour by default, and some manual control.
config THERM_PM72
- tristate "Support for thermal management on PowerMac G5"
+ tristate "Support for thermal management on PowerMac G5 (AGP)"
depends on I2C && I2C_POWERMAC && PPC_PMAC64
+ default n
help
This driver provides thermostat and fan control for the desktop
- G5 machines.
+ G5 machines.
+
+ This is deprecated, use windfarm instead.
config WINDFARM
tristate "New PowerMac thermal control infrastructure"
@@ -221,6 +224,22 @@ config WINDFARM_PM81
help
This driver provides thermal control for the iMacG5
+config WINDFARM_PM72
+ tristate "Support for thermal management on PowerMac G5 (AGP)"
+ depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && ADB_PMU
+ select I2C_POWERMAC
+ help
+ This driver provides thermal control for the PowerMac G5
+ "AGP" variants (PowerMac 7,2 and 7,3)
+
+config WINDFARM_RM31
+ tristate "Support for thermal management on Xserve G5"
+ depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && ADB_PMU
+ select I2C_POWERMAC
+ help
+ This driver provides thermal control for the Xserve G5
+ (RackMac3,1)
+
config WINDFARM_PM91
tristate "Support for thermal management on PowerMac9,1"
depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
index 6652a6ebb6fa..6753b65f8ede 100644
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -29,6 +29,20 @@ obj-$(CONFIG_THERM_PM72) += therm_pm72.o
obj-$(CONFIG_THERM_WINDTUNNEL) += therm_windtunnel.o
obj-$(CONFIG_THERM_ADT746X) += therm_adt746x.o
obj-$(CONFIG_WINDFARM) += windfarm_core.o
+obj-$(CONFIG_WINDFARM_PM72) += windfarm_fcu_controls.o \
+ windfarm_ad7417_sensor.o \
+ windfarm_lm75_sensor.o \
+ windfarm_max6690_sensor.o \
+ windfarm_pid.o \
+ windfarm_cpufreq_clamp.o \
+ windfarm_pm72.o
+obj-$(CONFIG_WINDFARM_RM31) += windfarm_fcu_controls.o \
+ windfarm_ad7417_sensor.o \
+ windfarm_lm75_sensor.o \
+ windfarm_lm87_sensor.o \
+ windfarm_pid.o \
+ windfarm_cpufreq_clamp.o \
+ windfarm_rm31.o
obj-$(CONFIG_WINDFARM_PM81) += windfarm_smu_controls.o \
windfarm_smu_sensors.o \
windfarm_lm75_sensor.o windfarm_pid.o \
diff --git a/drivers/macintosh/ams/ams-i2c.c b/drivers/macintosh/ams/ams-i2c.c
index abeecd27b484..978eda8d6678 100644
--- a/drivers/macintosh/ams/ams-i2c.c
+++ b/drivers/macintosh/ams/ams-i2c.c
@@ -65,7 +65,7 @@ static int ams_i2c_probe(struct i2c_client *client,
static int ams_i2c_remove(struct i2c_client *client);
static const struct i2c_device_id ams_id[] = {
- { "ams", 0 },
+ { "MAC,accelerometer_1", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ams_id);
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
index fc71723cbc48..f433521a6f9d 100644
--- a/drivers/macintosh/therm_adt746x.c
+++ b/drivers/macintosh/therm_adt746x.c
@@ -47,7 +47,7 @@ static u8 FAN_SPD_SET[2] = {0x30, 0x31};
static u8 default_limits_local[3] = {70, 50, 70}; /* local, sensor1, sensor2 */
static u8 default_limits_chip[3] = {80, 65, 80}; /* local, sensor1, sensor2 */
-static const char *sensor_location[3];
+static const char *sensor_location[3] = { "?", "?", "?" };
static int limit_adjust;
static int fan_speed = -1;
@@ -79,18 +79,16 @@ struct thermostat {
int last_speed[2];
int last_var[2];
int pwm_inv[2];
+ struct task_struct *thread;
+ struct platform_device *pdev;
+ enum {
+ ADT7460,
+ ADT7467
+ } type;
};
-static enum {ADT7460, ADT7467} therm_type;
-static int therm_bus, therm_address;
-static struct platform_device * of_dev;
-static struct thermostat* thermostat;
-static struct task_struct *thread_therm = NULL;
-
static void write_both_fan_speed(struct thermostat *th, int speed);
static void write_fan_speed(struct thermostat *th, int speed, int fan);
-static void thermostat_create_files(void);
-static void thermostat_remove_files(void);
static int
write_reg(struct thermostat* th, int reg, u8 data)
@@ -126,66 +124,6 @@ read_reg(struct thermostat* th, int reg)
return data;
}
-static struct i2c_driver thermostat_driver;
-
-static int
-attach_thermostat(struct i2c_adapter *adapter)
-{
- unsigned long bus_no;
- struct i2c_board_info info;
- struct i2c_client *client;
-
- if (strncmp(adapter->name, "uni-n", 5))
- return -ENODEV;
- bus_no = simple_strtoul(adapter->name + 6, NULL, 10);
- if (bus_no != therm_bus)
- return -ENODEV;
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "therm_adt746x", I2C_NAME_SIZE);
- info.addr = therm_address;
- client = i2c_new_device(adapter, &info);
- if (!client)
- return -ENODEV;
-
- /*
- * Let i2c-core delete that device on driver removal.
- * This is safe because i2c-core holds the core_lock mutex for us.
- */
- list_add_tail(&client->detected, &thermostat_driver.clients);
- return 0;
-}
-
-static int
-remove_thermostat(struct i2c_client *client)
-{
- struct thermostat *th = i2c_get_clientdata(client);
- int i;
-
- thermostat_remove_files();
-
- if (thread_therm != NULL) {
- kthread_stop(thread_therm);
- }
-
- printk(KERN_INFO "adt746x: Putting max temperatures back from "
- "%d, %d, %d to %d, %d, %d\n",
- th->limits[0], th->limits[1], th->limits[2],
- th->initial_limits[0], th->initial_limits[1],
- th->initial_limits[2]);
-
- for (i = 0; i < 3; i++)
- write_reg(th, LIMIT_REG[i], th->initial_limits[i]);
-
- write_both_fan_speed(th, -1);
-
- thermostat = NULL;
-
- kfree(th);
-
- return 0;
-}
-
static int read_fan_speed(struct thermostat *th, u8 addr)
{
u8 tmp[2];
@@ -203,7 +141,7 @@ static int read_fan_speed(struct thermostat *th, u8 addr)
static void write_both_fan_speed(struct thermostat *th, int speed)
{
write_fan_speed(th, speed, 0);
- if (therm_type == ADT7460)
+ if (th->type == ADT7460)
write_fan_speed(th, speed, 1);
}
@@ -216,7 +154,7 @@ static void write_fan_speed(struct thermostat *th, int speed, int fan)
else if (speed < -1)
speed = 0;
- if (therm_type == ADT7467 && fan == 1)
+ if (th->type == ADT7467 && fan == 1)
return;
if (th->last_speed[fan] != speed) {
@@ -239,7 +177,7 @@ static void write_fan_speed(struct thermostat *th, int speed, int fan)
write_reg(th, FAN_SPD_SET[fan], speed);
} else {
/* back to automatic */
- if(therm_type == ADT7460) {
+ if(th->type == ADT7460) {
manual = read_reg(th,
MANUAL_MODE[fan]) & (~MANUAL_MASK);
manual &= ~INVERT_MASK;
@@ -293,7 +231,7 @@ static void update_fans_speed (struct thermostat *th)
/* we don't care about local sensor, so we start at sensor 1 */
for (i = 1; i < 3; i++) {
int started = 0;
- int fan_number = (therm_type == ADT7460 && i == 2);
+ int fan_number = (th->type == ADT7460 && i == 2);
int var = th->temps[i] - th->limits[i];
if (var > -1) {
@@ -370,116 +308,22 @@ static int monitor_task(void *arg)
static void set_limit(struct thermostat *th, int i)
{
- /* Set sensor1 limit higher to avoid powerdowns */
- th->limits[i] = default_limits_chip[i] + limit_adjust;
- write_reg(th, LIMIT_REG[i], th->limits[i]);
+ /* Set sensor1 limit higher to avoid powerdowns */
+ th->limits[i] = default_limits_chip[i] + limit_adjust;
+ write_reg(th, LIMIT_REG[i], th->limits[i]);
- /* set our limits to normal */
- th->limits[i] = default_limits_local[i] + limit_adjust;
+ /* set our limits to normal */
+ th->limits[i] = default_limits_local[i] + limit_adjust;
}
-static int probe_thermostat(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct thermostat* th;
- int rc;
- int i;
-
- if (thermostat)
- return 0;
-
- th = kzalloc(sizeof(struct thermostat), GFP_KERNEL);
- if (!th)
- return -ENOMEM;
-
- i2c_set_clientdata(client, th);
- th->clt = client;
-
- rc = read_reg(th, CONFIG_REG);
- if (rc < 0) {
- dev_err(&client->dev, "Thermostat failed to read config!\n");
- kfree(th);
- return -ENODEV;
- }
-
- /* force manual control to start the fan quieter */
- if (fan_speed == -1)
- fan_speed = 64;
-
- if(therm_type == ADT7460) {
- printk(KERN_INFO "adt746x: ADT7460 initializing\n");
- /* The 7460 needs to be started explicitly */
- write_reg(th, CONFIG_REG, 1);
- } else
- printk(KERN_INFO "adt746x: ADT7467 initializing\n");
-
- for (i = 0; i < 3; i++) {
- th->initial_limits[i] = read_reg(th, LIMIT_REG[i]);
- set_limit(th, i);
- }
-
- printk(KERN_INFO "adt746x: Lowering max temperatures from %d, %d, %d"
- " to %d, %d, %d\n",
- th->initial_limits[0], th->initial_limits[1],
- th->initial_limits[2], th->limits[0], th->limits[1],
- th->limits[2]);
-
- thermostat = th;
-
- /* record invert bit status because fw can corrupt it after suspend */
- th->pwm_inv[0] = read_reg(th, MANUAL_MODE[0]) & INVERT_MASK;
- th->pwm_inv[1] = read_reg(th, MANUAL_MODE[1]) & INVERT_MASK;
-
- /* be sure to really write fan speed the first time */
- th->last_speed[0] = -2;
- th->last_speed[1] = -2;
- th->last_var[0] = -80;
- th->last_var[1] = -80;
-
- if (fan_speed != -1) {
- /* manual mode, stop fans */
- write_both_fan_speed(th, 0);
- } else {
- /* automatic mode */
- write_both_fan_speed(th, -1);
- }
-
- thread_therm = kthread_run(monitor_task, th, "kfand");
-
- if (thread_therm == ERR_PTR(-ENOMEM)) {
- printk(KERN_INFO "adt746x: Kthread creation failed\n");
- thread_therm = NULL;
- return -ENOMEM;
- }
-
- thermostat_create_files();
-
- return 0;
+#define BUILD_SHOW_FUNC_INT(name, data) \
+static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+ struct thermostat *th = dev_get_drvdata(dev); \
+ return sprintf(buf, "%d\n", data); \
}
-static const struct i2c_device_id therm_adt746x_id[] = {
- { "therm_adt746x", 0 },
- { }
-};
-
-static struct i2c_driver thermostat_driver = {
- .driver = {
- .name = "therm_adt746x",
- },
- .attach_adapter = attach_thermostat,
- .probe = probe_thermostat,
- .remove = remove_thermostat,
- .id_table = therm_adt746x_id,
-};
-
-/*
- * Now, unfortunately, sysfs doesn't give us a nice void * we could
- * pass around to the attribute functions, so we don't really have
- * choice but implement a bunch of them...
- *
- * FIXME, it does now...
- */
-#define BUILD_SHOW_FUNC_INT(name, data) \
+#define BUILD_SHOW_FUNC_INT_LITE(name, data) \
static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
return sprintf(buf, "%d\n", data); \
@@ -494,22 +338,24 @@ static ssize_t show_##name(struct device *dev, struct device_attribute *attr, ch
#define BUILD_SHOW_FUNC_FAN(name, data) \
static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
+ struct thermostat *th = dev_get_drvdata(dev); \
return sprintf(buf, "%d (%d rpm)\n", \
- thermostat->last_speed[data], \
- read_fan_speed(thermostat, FAN_SPEED[data]) \
+ th->last_speed[data], \
+ read_fan_speed(th, FAN_SPEED[data]) \
); \
}
#define BUILD_STORE_FUNC_DEG(name, data) \
static ssize_t store_##name(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) \
{ \
+ struct thermostat *th = dev_get_drvdata(dev); \
int val; \
int i; \
val = simple_strtol(buf, NULL, 10); \
printk(KERN_INFO "Adjusting limits by %d degrees\n", val); \
limit_adjust = val; \
for (i=0; i < 3; i++) \
- set_limit(thermostat, i); \
+ set_limit(th, i); \
return n; \
}
@@ -525,20 +371,21 @@ static ssize_t store_##name(struct device *dev, struct device_attribute *attr, c
return n; \
}
-BUILD_SHOW_FUNC_INT(sensor1_temperature, (read_reg(thermostat, TEMP_REG[1])))
-BUILD_SHOW_FUNC_INT(sensor2_temperature, (read_reg(thermostat, TEMP_REG[2])))
-BUILD_SHOW_FUNC_INT(sensor1_limit, thermostat->limits[1])
-BUILD_SHOW_FUNC_INT(sensor2_limit, thermostat->limits[2])
+BUILD_SHOW_FUNC_INT(sensor1_temperature, (read_reg(th, TEMP_REG[1])))
+BUILD_SHOW_FUNC_INT(sensor2_temperature, (read_reg(th, TEMP_REG[2])))
+BUILD_SHOW_FUNC_INT(sensor1_limit, th->limits[1])
+BUILD_SHOW_FUNC_INT(sensor2_limit, th->limits[2])
BUILD_SHOW_FUNC_STR(sensor1_location, sensor_location[1])
BUILD_SHOW_FUNC_STR(sensor2_location, sensor_location[2])
-BUILD_SHOW_FUNC_INT(specified_fan_speed, fan_speed)
+BUILD_SHOW_FUNC_INT_LITE(specified_fan_speed, fan_speed)
+BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed)
+
BUILD_SHOW_FUNC_FAN(sensor1_fan_speed, 0)
BUILD_SHOW_FUNC_FAN(sensor2_fan_speed, 1)
-BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed)
-BUILD_SHOW_FUNC_INT(limit_adjust, limit_adjust)
-BUILD_STORE_FUNC_DEG(limit_adjust, thermostat)
+BUILD_SHOW_FUNC_INT_LITE(limit_adjust, limit_adjust)
+BUILD_STORE_FUNC_DEG(limit_adjust, th)
static DEVICE_ATTR(sensor1_temperature, S_IRUGO,
show_sensor1_temperature,NULL);
@@ -564,53 +411,77 @@ static DEVICE_ATTR(sensor2_fan_speed, S_IRUGO,
static DEVICE_ATTR(limit_adjust, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH,
show_limit_adjust, store_limit_adjust);
-
-static int __init
-thermostat_init(void)
+static void thermostat_create_files(struct thermostat *th)
{
- struct device_node* np;
- const u32 *prop;
- int i = 0, offset = 0;
+ struct device_node *np = th->clt->dev.of_node;
+ struct device *dev;
+ int err;
- np = of_find_node_by_name(NULL, "fan");
- if (!np)
- return -ENODEV;
- if (of_device_is_compatible(np, "adt7460"))
- therm_type = ADT7460;
- else if (of_device_is_compatible(np, "adt7467"))
- therm_type = ADT7467;
- else {
- of_node_put(np);
- return -ENODEV;
- }
+ /* To maintain ABI compatibility with userspace, create
+ * the old style platform driver and attach the attributes
+ * to it here
+ */
+ th->pdev = of_platform_device_create(np, "temperatures", NULL);
+ if (!th->pdev)
+ return;
+ dev = &th->pdev->dev;
+ dev_set_drvdata(dev, th);
+ err = device_create_file(dev, &dev_attr_sensor1_temperature);
+ err |= device_create_file(dev, &dev_attr_sensor2_temperature);
+ err |= device_create_file(dev, &dev_attr_sensor1_limit);
+ err |= device_create_file(dev, &dev_attr_sensor2_limit);
+ err |= device_create_file(dev, &dev_attr_sensor1_location);
+ err |= device_create_file(dev, &dev_attr_sensor2_location);
+ err |= device_create_file(dev, &dev_attr_limit_adjust);
+ err |= device_create_file(dev, &dev_attr_specified_fan_speed);
+ err |= device_create_file(dev, &dev_attr_sensor1_fan_speed);
+ if(th->type == ADT7460)
+ err |= device_create_file(dev, &dev_attr_sensor2_fan_speed);
+ if (err)
+ printk(KERN_WARNING
+ "Failed to create temperature attribute file(s).\n");
+}
- prop = of_get_property(np, "hwsensor-params-version", NULL);
- printk(KERN_INFO "adt746x: version %d (%ssupported)\n", *prop,
- (*prop == 1)?"":"un");
- if (*prop != 1) {
- of_node_put(np);
- return -ENODEV;
- }
+static void thermostat_remove_files(struct thermostat *th)
+{
+ struct device *dev;
- prop = of_get_property(np, "reg", NULL);
- if (!prop) {
- of_node_put(np);
- return -ENODEV;
- }
+ if (!th->pdev)
+ return;
+ dev = &th->pdev->dev;
+ device_remove_file(dev, &dev_attr_sensor1_temperature);
+ device_remove_file(dev, &dev_attr_sensor2_temperature);
+ device_remove_file(dev, &dev_attr_sensor1_limit);
+ device_remove_file(dev, &dev_attr_sensor2_limit);
+ device_remove_file(dev, &dev_attr_sensor1_location);
+ device_remove_file(dev, &dev_attr_sensor2_location);
+ device_remove_file(dev, &dev_attr_limit_adjust);
+ device_remove_file(dev, &dev_attr_specified_fan_speed);
+ device_remove_file(dev, &dev_attr_sensor1_fan_speed);
+ if (th->type == ADT7460)
+ device_remove_file(dev, &dev_attr_sensor2_fan_speed);
+ of_device_unregister(th->pdev);
- /* look for bus either by path or using "reg" */
- if (strstr(np->full_name, "/i2c-bus@") != NULL) {
- const char *tmp_bus = (strstr(np->full_name, "/i2c-bus@") + 9);
- therm_bus = tmp_bus[0]-'0';
- } else {
- therm_bus = ((*prop) >> 8) & 0x0f;
- }
+}
- therm_address = ((*prop) & 0xff) >> 1;
+static int probe_thermostat(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device_node *np = client->dev.of_node;
+ struct thermostat* th;
+ const __be32 *prop;
+ int i, rc, vers, offset = 0;
- printk(KERN_INFO "adt746x: Thermostat bus: %d, address: 0x%02x, "
- "limit_adjust: %d, fan_speed: %d\n",
- therm_bus, therm_address, limit_adjust, fan_speed);
+ if (!np)
+ return -ENXIO;
+ prop = of_get_property(np, "hwsensor-params-version", NULL);
+ if (!prop)
+ return -ENXIO;
+ vers = be32_to_cpup(prop);
+ printk(KERN_INFO "adt746x: version %d (%ssupported)\n",
+ vers, vers == 1 ? "" : "un");
+ if (vers != 1)
+ return -ENXIO;
if (of_get_property(np, "hwsensor-location", NULL)) {
for (i = 0; i < 3; i++) {
@@ -623,72 +494,129 @@ thermostat_init(void)
printk(KERN_INFO "sensor %d: %s\n", i, sensor_location[i]);
offset += strlen(sensor_location[i]) + 1;
}
- } else {
- sensor_location[0] = "?";
- sensor_location[1] = "?";
- sensor_location[2] = "?";
}
- of_dev = of_platform_device_create(np, "temperatures", NULL);
- of_node_put(np);
+ th = kzalloc(sizeof(struct thermostat), GFP_KERNEL);
+ if (!th)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, th);
+ th->clt = client;
+ th->type = id->driver_data;
- if (of_dev == NULL) {
- printk(KERN_ERR "Can't register temperatures device !\n");
+ rc = read_reg(th, CONFIG_REG);
+ if (rc < 0) {
+ dev_err(&client->dev, "Thermostat failed to read config!\n");
+ kfree(th);
return -ENODEV;
}
-#ifndef CONFIG_I2C_POWERMAC
- request_module("i2c-powermac");
-#endif
+ /* force manual control to start the fan quieter */
+ if (fan_speed == -1)
+ fan_speed = 64;
+
+ if (th->type == ADT7460) {
+ printk(KERN_INFO "adt746x: ADT7460 initializing\n");
+ /* The 7460 needs to be started explicitly */
+ write_reg(th, CONFIG_REG, 1);
+ } else
+ printk(KERN_INFO "adt746x: ADT7467 initializing\n");
- return i2c_add_driver(&thermostat_driver);
+ for (i = 0; i < 3; i++) {
+ th->initial_limits[i] = read_reg(th, LIMIT_REG[i]);
+ set_limit(th, i);
+ }
+
+ printk(KERN_INFO "adt746x: Lowering max temperatures from %d, %d, %d"
+ " to %d, %d, %d\n",
+ th->initial_limits[0], th->initial_limits[1],
+ th->initial_limits[2], th->limits[0], th->limits[1],
+ th->limits[2]);
+
+ /* record invert bit status because fw can corrupt it after suspend */
+ th->pwm_inv[0] = read_reg(th, MANUAL_MODE[0]) & INVERT_MASK;
+ th->pwm_inv[1] = read_reg(th, MANUAL_MODE[1]) & INVERT_MASK;
+
+ /* be sure to really write fan speed the first time */
+ th->last_speed[0] = -2;
+ th->last_speed[1] = -2;
+ th->last_var[0] = -80;
+ th->last_var[1] = -80;
+
+ if (fan_speed != -1) {
+ /* manual mode, stop fans */
+ write_both_fan_speed(th, 0);
+ } else {
+ /* automatic mode */
+ write_both_fan_speed(th, -1);
+ }
+
+ th->thread = kthread_run(monitor_task, th, "kfand");
+ if (th->thread == ERR_PTR(-ENOMEM)) {
+ printk(KERN_INFO "adt746x: Kthread creation failed\n");
+ th->thread = NULL;
+ return -ENOMEM;
+ }
+
+ thermostat_create_files(th);
+
+ return 0;
}
-static void thermostat_create_files(void)
+static int remove_thermostat(struct i2c_client *client)
{
- int err;
+ struct thermostat *th = i2c_get_clientdata(client);
+ int i;
+
+ thermostat_remove_files(th);
- err = device_create_file(&of_dev->dev, &dev_attr_sensor1_temperature);
- err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_temperature);
- err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_limit);
- err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_limit);
- err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_location);
- err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_location);
- err |= device_create_file(&of_dev->dev, &dev_attr_limit_adjust);
- err |= device_create_file(&of_dev->dev, &dev_attr_specified_fan_speed);
- err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_fan_speed);
- if(therm_type == ADT7460)
- err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_fan_speed);
- if (err)
- printk(KERN_WARNING
- "Failed to create temperature attribute file(s).\n");
+ if (th->thread != NULL)
+ kthread_stop(th->thread);
+
+ printk(KERN_INFO "adt746x: Putting max temperatures back from "
+ "%d, %d, %d to %d, %d, %d\n",
+ th->limits[0], th->limits[1], th->limits[2],
+ th->initial_limits[0], th->initial_limits[1],
+ th->initial_limits[2]);
+
+ for (i = 0; i < 3; i++)
+ write_reg(th, LIMIT_REG[i], th->initial_limits[i]);
+
+ write_both_fan_speed(th, -1);
+
+ kfree(th);
+
+ return 0;
}
-static void thermostat_remove_files(void)
+static const struct i2c_device_id therm_adt746x_id[] = {
+ { "MAC,adt7460", ADT7460 },
+ { "MAC,adt7467", ADT7467 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, therm_adt746x_id);
+
+static struct i2c_driver thermostat_driver = {
+ .driver = {
+ .name = "therm_adt746x",
+ },
+ .probe = probe_thermostat,
+ .remove = remove_thermostat,
+ .id_table = therm_adt746x_id,
+};
+
+static int __init thermostat_init(void)
{
- if (of_dev) {
- device_remove_file(&of_dev->dev, &dev_attr_sensor1_temperature);
- device_remove_file(&of_dev->dev, &dev_attr_sensor2_temperature);
- device_remove_file(&of_dev->dev, &dev_attr_sensor1_limit);
- device_remove_file(&of_dev->dev, &dev_attr_sensor2_limit);
- device_remove_file(&of_dev->dev, &dev_attr_sensor1_location);
- device_remove_file(&of_dev->dev, &dev_attr_sensor2_location);
- device_remove_file(&of_dev->dev, &dev_attr_limit_adjust);
- device_remove_file(&of_dev->dev, &dev_attr_specified_fan_speed);
- device_remove_file(&of_dev->dev, &dev_attr_sensor1_fan_speed);
-
- if(therm_type == ADT7460)
- device_remove_file(&of_dev->dev,
- &dev_attr_sensor2_fan_speed);
+#ifndef CONFIG_I2C_POWERMAC
+ request_module("i2c-powermac");
+#endif
- }
+ return i2c_add_driver(&thermostat_driver);
}
-static void __exit
-thermostat_exit(void)
+static void __exit thermostat_exit(void)
{
i2c_del_driver(&thermostat_driver);
- of_device_unregister(of_dev);
}
module_init(thermostat_init);
diff --git a/drivers/macintosh/windfarm.h b/drivers/macintosh/windfarm.h
index 7a2482cc26a7..028cdac2d33d 100644
--- a/drivers/macintosh/windfarm.h
+++ b/drivers/macintosh/windfarm.h
@@ -17,7 +17,7 @@
#include <linux/device.h>
/* Display a 16.16 fixed point value */
-#define FIX32TOPRINT(f) ((f) >> 16),((((f) & 0xffff) * 1000) >> 16)
+#define FIX32TOPRINT(f) (((s32)(f)) >> 16),(((((s32)(f)) & 0xffff) * 1000) >> 16)
/*
* Control objects
@@ -35,12 +35,13 @@ struct wf_control_ops {
};
struct wf_control {
- struct list_head link;
- struct wf_control_ops *ops;
- char *name;
- int type;
- struct kref ref;
- struct device_attribute attr;
+ struct list_head link;
+ const struct wf_control_ops *ops;
+ const char *name;
+ int type;
+ struct kref ref;
+ struct device_attribute attr;
+ void *priv;
};
#define WF_CONTROL_TYPE_GENERIC 0
@@ -72,6 +73,26 @@ static inline int wf_control_set_min(struct wf_control *ct)
return ct->ops->set_value(ct, vmin);
}
+static inline int wf_control_set(struct wf_control *ct, s32 val)
+{
+ return ct->ops->set_value(ct, val);
+}
+
+static inline int wf_control_get(struct wf_control *ct, s32 *val)
+{
+ return ct->ops->get_value(ct, val);
+}
+
+static inline s32 wf_control_get_min(struct wf_control *ct)
+{
+ return ct->ops->get_min(ct);
+}
+
+static inline s32 wf_control_get_max(struct wf_control *ct)
+{
+ return ct->ops->get_max(ct);
+}
+
/*
* Sensor objects
*/
@@ -85,11 +106,12 @@ struct wf_sensor_ops {
};
struct wf_sensor {
- struct list_head link;
- struct wf_sensor_ops *ops;
- char *name;
- struct kref ref;
- struct device_attribute attr;
+ struct list_head link;
+ const struct wf_sensor_ops *ops;
+ const char *name;
+ struct kref ref;
+ struct device_attribute attr;
+ void *priv;
};
/* Same lifetime rules as controls */
@@ -99,6 +121,11 @@ extern struct wf_sensor * wf_find_sensor(const char *name);
extern int wf_get_sensor(struct wf_sensor *sr);
extern void wf_put_sensor(struct wf_sensor *sr);
+static inline int wf_sensor_get(struct wf_sensor *sr, s32 *val)
+{
+ return sr->ops->get_value(sr, val);
+}
+
/* For use by clients. Note that we are a bit racy here since
* notifier_block doesn't have a module owner field. I may fix
* it one day ...
diff --git a/drivers/macintosh/windfarm_ad7417_sensor.c b/drivers/macintosh/windfarm_ad7417_sensor.c
new file mode 100644
index 000000000000..ac3f243b9c5a
--- /dev/null
+++ b/drivers/macintosh/windfarm_ad7417_sensor.c
@@ -0,0 +1,347 @@
+/*
+ * Windfarm PowerMac thermal control. AD7417 sensors
+ *
+ * Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Released under the term of the GNU GPL v2.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/i2c.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/sections.h>
+
+#include "windfarm.h"
+#include "windfarm_mpu.h"
+
+#define VERSION "1.0"
+
+struct wf_ad7417_priv {
+ struct kref ref;
+ struct i2c_client *i2c;
+ u8 config;
+ u8 cpu;
+ const struct mpu_data *mpu;
+ struct wf_sensor sensors[5];
+ struct mutex lock;
+};
+
+static int wf_ad7417_temp_get(struct wf_sensor *sr, s32 *value)
+{
+ struct wf_ad7417_priv *pv = sr->priv;
+ u8 buf[2];
+ s16 raw;
+ int rc;
+
+ *value = 0;
+ mutex_lock(&pv->lock);
+
+ /* Read temp register */
+ buf[0] = 0;
+ rc = i2c_master_send(pv->i2c, buf, 1);
+ if (rc < 0)
+ goto error;
+ rc = i2c_master_recv(pv->i2c, buf, 2);
+ if (rc < 0)
+ goto error;
+
+ /* Read a a 16-bit signed value */
+ raw = be16_to_cpup((__le16 *)buf);
+
+ /* Convert 8.8-bit to 16.16 fixed point */
+ *value = ((s32)raw) << 8;
+
+ mutex_unlock(&pv->lock);
+ return 0;
+
+error:
+ mutex_unlock(&pv->lock);
+ return -1;
+}
+
+/*
+ * Scaling factors for the AD7417 ADC converters (except
+ * for the CPU diode which is obtained from the EEPROM).
+ * Those values are obtained from the property list of
+ * the darwin driver
+ */
+#define ADC_12V_CURRENT_SCALE 0x0320 /* _AD2 */
+#define ADC_CPU_VOLTAGE_SCALE 0x00a0 /* _AD3 */
+#define ADC_CPU_CURRENT_SCALE 0x1f40 /* _AD4 */
+
+static void wf_ad7417_adc_convert(struct wf_ad7417_priv *pv,
+ int chan, s32 raw, s32 *value)
+{
+ switch(chan) {
+ case 1: /* Diode */
+ *value = (raw * (s32)pv->mpu->mdiode +
+ ((s32)pv->mpu->bdiode << 12)) >> 2;
+ break;
+ case 2: /* 12v current */
+ *value = raw * ADC_12V_CURRENT_SCALE;
+ break;
+ case 3: /* core voltage */
+ *value = raw * ADC_CPU_VOLTAGE_SCALE;
+ break;
+ case 4: /* core current */
+ *value = raw * ADC_CPU_CURRENT_SCALE;
+ break;
+ }
+}
+
+static int wf_ad7417_adc_get(struct wf_sensor *sr, s32 *value)
+{
+ struct wf_ad7417_priv *pv = sr->priv;
+ int chan = sr - pv->sensors;
+ int i, rc;
+ u8 buf[2];
+ u16 raw;
+
+ *value = 0;
+ mutex_lock(&pv->lock);
+ for (i = 0; i < 10; i++) {
+ /* Set channel */
+ buf[0] = 1;
+ buf[1] = (pv->config & 0x1f) | (chan << 5);
+ rc = i2c_master_send(pv->i2c, buf, 2);
+ if (rc < 0)
+ goto error;
+
+ /* Wait for conversion */
+ msleep(1);
+
+ /* Switch to data register */
+ buf[0] = 4;
+ rc = i2c_master_send(pv->i2c, buf, 1);
+ if (rc < 0)
+ goto error;
+
+ /* Read result */
+ rc = i2c_master_recv(pv->i2c, buf, 2);
+ if (rc < 0)
+ goto error;
+
+ /* Read a a 16-bit signed value */
+ raw = be16_to_cpup((__le16 *)buf) >> 6;
+ wf_ad7417_adc_convert(pv, chan, raw, value);
+
+ dev_vdbg(&pv->i2c->dev, "ADC chan %d [%s]"
+ " raw value: 0x%x, conv to: 0x%08x\n",
+ chan, sr->name, raw, *value);
+
+ mutex_unlock(&pv->lock);
+ return 0;
+
+ error:
+ dev_dbg(&pv->i2c->dev,
+ "Error reading ADC, try %d...\n", i);
+ if (i < 9)
+ msleep(10);
+ }
+ mutex_unlock(&pv->lock);
+ return -1;
+}
+
+static void wf_ad7417_release(struct kref *ref)
+{
+ struct wf_ad7417_priv *pv = container_of(ref,
+ struct wf_ad7417_priv, ref);
+ kfree(pv);
+}
+
+static void wf_ad7417_sensor_release(struct wf_sensor *sr)
+{
+ struct wf_ad7417_priv *pv = sr->priv;
+
+ kfree(sr->name);
+ kref_put(&pv->ref, wf_ad7417_release);
+}
+
+static const struct wf_sensor_ops wf_ad7417_temp_ops = {
+ .get_value = wf_ad7417_temp_get,
+ .release = wf_ad7417_sensor_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct wf_sensor_ops wf_ad7417_adc_ops = {
+ .get_value = wf_ad7417_adc_get,
+ .release = wf_ad7417_sensor_release,
+ .owner = THIS_MODULE,
+};
+
+static void __devinit wf_ad7417_add_sensor(struct wf_ad7417_priv *pv,
+ int index, const char *name,
+ const struct wf_sensor_ops *ops)
+{
+ pv->sensors[index].name = kasprintf(GFP_KERNEL, "%s-%d", name, pv->cpu);
+ pv->sensors[index].priv = pv;
+ pv->sensors[index].ops = ops;
+ if (!wf_register_sensor(&pv->sensors[index]))
+ kref_get(&pv->ref);
+}
+
+static void __devinit wf_ad7417_init_chip(struct wf_ad7417_priv *pv)
+{
+ int rc;
+ u8 buf[2];
+ u8 config = 0;
+
+ /*
+ * Read ADC the configuration register and cache it. We
+ * also make sure Config2 contains proper values, I've seen
+ * cases where we got stale grabage in there, thus preventing
+ * proper reading of conv. values
+ */
+
+ /* Clear Config2 */
+ buf[0] = 5;
+ buf[1] = 0;
+ i2c_master_send(pv->i2c, buf, 2);
+
+ /* Read & cache Config1 */
+ buf[0] = 1;
+ rc = i2c_master_send(pv->i2c, buf, 1);
+ if (rc > 0) {
+ rc = i2c_master_recv(pv->i2c, buf, 1);
+ if (rc > 0) {
+ config = buf[0];
+
+ dev_dbg(&pv->i2c->dev, "ADC config reg: %02x\n",
+ config);
+
+ /* Disable shutdown mode */
+ config &= 0xfe;
+ buf[0] = 1;
+ buf[1] = config;
+ rc = i2c_master_send(pv->i2c, buf, 2);
+ }
+ }
+ if (rc <= 0)
+ dev_err(&pv->i2c->dev, "Error reading ADC config\n");
+
+ pv->config = config;
+}
+
+static int __devinit wf_ad7417_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct wf_ad7417_priv *pv;
+ const struct mpu_data *mpu;
+ const char *loc;
+ int cpu_nr;
+
+ loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL);
+ if (!loc) {
+ dev_warn(&client->dev, "Missing hwsensor-location property!\n");
+ return -ENXIO;
+ }
+
+ /*
+ * Identify which CPU we belong to by looking at the first entry
+ * in the hwsensor-location list
+ */
+ if (!strncmp(loc, "CPU A", 5))
+ cpu_nr = 0;
+ else if (!strncmp(loc, "CPU B", 5))
+ cpu_nr = 1;
+ else {
+ pr_err("wf_ad7417: Can't identify location %s\n", loc);
+ return -ENXIO;
+ }
+ mpu = wf_get_mpu(cpu_nr);
+ if (!mpu) {
+ dev_err(&client->dev, "Failed to retrieve MPU data\n");
+ return -ENXIO;
+ }
+
+ pv = kzalloc(sizeof(struct wf_ad7417_priv), GFP_KERNEL);
+ if (pv == NULL)
+ return -ENODEV;
+
+ kref_init(&pv->ref);
+ mutex_init(&pv->lock);
+ pv->i2c = client;
+ pv->cpu = cpu_nr;
+ pv->mpu = mpu;
+ dev_set_drvdata(&client->dev, pv);
+
+ /* Initialize the chip */
+ wf_ad7417_init_chip(pv);
+
+ /*
+ * We cannot rely on Apple device-tree giving us child
+ * node with the names of the individual sensors so we
+ * just hard code what we know about them
+ */
+ wf_ad7417_add_sensor(pv, 0, "cpu-amb-temp", &wf_ad7417_temp_ops);
+ wf_ad7417_add_sensor(pv, 1, "cpu-diode-temp", &wf_ad7417_adc_ops);
+ wf_ad7417_add_sensor(pv, 2, "cpu-12v-current", &wf_ad7417_adc_ops);
+ wf_ad7417_add_sensor(pv, 3, "cpu-voltage", &wf_ad7417_adc_ops);
+ wf_ad7417_add_sensor(pv, 4, "cpu-current", &wf_ad7417_adc_ops);
+
+ return 0;
+}
+
+static int __devexit wf_ad7417_remove(struct i2c_client *client)
+{
+ struct wf_ad7417_priv *pv = dev_get_drvdata(&client->dev);
+ int i;
+
+ /* Mark client detached */
+ pv->i2c = NULL;
+
+ /* Release sensor */
+ for (i = 0; i < 5; i++)
+ wf_unregister_sensor(&pv->sensors[i]);
+
+ kref_put(&pv->ref, wf_ad7417_release);
+
+ return 0;
+}
+
+static const struct i2c_device_id wf_ad7417_id[] = {
+ { "MAC,ad7417", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wf_ad7417_id);
+
+static struct i2c_driver wf_ad7417_driver = {
+ .driver = {
+ .name = "wf_ad7417",
+ },
+ .probe = wf_ad7417_probe,
+ .remove = wf_ad7417_remove,
+ .id_table = wf_ad7417_id,
+};
+
+static int __devinit wf_ad7417_init(void)
+{
+ /* This is only supported on these machines */
+ if (!of_machine_is_compatible("PowerMac7,2") &&
+ !of_machine_is_compatible("PowerMac7,3") &&
+ !of_machine_is_compatible("RackMac3,1"))
+ return -ENODEV;
+
+ return i2c_add_driver(&wf_ad7417_driver);
+}
+
+static void __devexit wf_ad7417_exit(void)
+{
+ i2c_del_driver(&wf_ad7417_driver);
+}
+
+module_init(wf_ad7417_init);
+module_exit(wf_ad7417_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("ad7417 sensor driver for PowerMacs");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c
index ce8897933a84..3ee198b65843 100644
--- a/drivers/macintosh/windfarm_core.c
+++ b/drivers/macintosh/windfarm_core.c
@@ -164,13 +164,27 @@ static ssize_t wf_show_control(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct wf_control *ctrl = container_of(attr, struct wf_control, attr);
+ const char *typestr;
s32 val = 0;
int err;
err = ctrl->ops->get_value(ctrl, &val);
- if (err < 0)
+ if (err < 0) {
+ if (err == -EFAULT)
+ return sprintf(buf, "<HW FAULT>\n");
return err;
- return sprintf(buf, "%d\n", val);
+ }
+ switch(ctrl->type) {
+ case WF_CONTROL_RPM_FAN:
+ typestr = " RPM";
+ break;
+ case WF_CONTROL_PWM_FAN:
+ typestr = " %";
+ break;
+ default:
+ typestr = "";
+ }
+ return sprintf(buf, "%d%s\n", val, typestr);
}
/* This is really only for debugging... */
@@ -470,11 +484,6 @@ static int __init windfarm_core_init(void)
{
DBG("wf: core loaded\n");
- /* Don't register on old machines that use therm_pm72 for now */
- if (of_machine_is_compatible("PowerMac7,2") ||
- of_machine_is_compatible("PowerMac7,3") ||
- of_machine_is_compatible("RackMac3,1"))
- return -ENODEV;
platform_device_register(&wf_platform_device);
return 0;
}
diff --git a/drivers/macintosh/windfarm_cpufreq_clamp.c b/drivers/macintosh/windfarm_cpufreq_clamp.c
index 1a77a7c97d0e..72d1fdfe02a5 100644
--- a/drivers/macintosh/windfarm_cpufreq_clamp.c
+++ b/drivers/macintosh/windfarm_cpufreq_clamp.c
@@ -75,12 +75,6 @@ static int __init wf_cpufreq_clamp_init(void)
{
struct wf_control *clamp;
- /* Don't register on old machines that use therm_pm72 for now */
- if (of_machine_is_compatible("PowerMac7,2") ||
- of_machine_is_compatible("PowerMac7,3") ||
- of_machine_is_compatible("RackMac3,1"))
- return -ENODEV;
-
clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL);
if (clamp == NULL)
return -ENOMEM;
diff --git a/drivers/macintosh/windfarm_fcu_controls.c b/drivers/macintosh/windfarm_fcu_controls.c
new file mode 100644
index 000000000000..b3411edb324b
--- /dev/null
+++ b/drivers/macintosh/windfarm_fcu_controls.c
@@ -0,0 +1,613 @@
+/*
+ * Windfarm PowerMac thermal control. FCU fan control
+ *
+ * Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Released under the term of the GNU GPL v2.
+ */
+#undef DEBUG
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/i2c.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/sections.h>
+
+#include "windfarm.h"
+#include "windfarm_mpu.h"
+
+#define VERSION "1.0"
+
+#ifdef DEBUG
+#define DBG(args...) printk(args)
+#else
+#define DBG(args...) do { } while(0)
+#endif
+
+/*
+ * This option is "weird" :) Basically, if you define this to 1
+ * the control loop for the RPMs fans (not PWMs) will apply the
+ * correction factor obtained from the PID to the actual RPM
+ * speed read from the FCU.
+ *
+ * If you define the below constant to 0, then it will be
+ * applied to the setpoint RPM speed, that is basically the
+ * speed we proviously "asked" for.
+ *
+ * I'm using 0 for now which is what therm_pm72 used to do and
+ * what Darwin -apparently- does based on observed behaviour.
+ */
+#define RPM_PID_USE_ACTUAL_SPEED 0
+
+/* Default min/max for pumps */
+#define CPU_PUMP_OUTPUT_MAX 3200
+#define CPU_PUMP_OUTPUT_MIN 1250
+
+#define FCU_FAN_RPM 0
+#define FCU_FAN_PWM 1
+
+struct wf_fcu_priv {
+ struct kref ref;
+ struct i2c_client *i2c;
+ struct mutex lock;
+ struct list_head fan_list;
+ int rpm_shift;
+};
+
+struct wf_fcu_fan {
+ struct list_head link;
+ int id;
+ s32 min, max, target;
+ struct wf_fcu_priv *fcu_priv;
+ struct wf_control ctrl;
+};
+
+static void wf_fcu_release(struct kref *ref)
+{
+ struct wf_fcu_priv *pv = container_of(ref, struct wf_fcu_priv, ref);
+
+ kfree(pv);
+}
+
+static void wf_fcu_fan_release(struct wf_control *ct)
+{
+ struct wf_fcu_fan *fan = ct->priv;
+
+ kref_put(&fan->fcu_priv->ref, wf_fcu_release);
+ kfree(fan);
+}
+
+static int wf_fcu_read_reg(struct wf_fcu_priv *pv, int reg,
+ unsigned char *buf, int nb)
+{
+ int tries, nr, nw;
+
+ mutex_lock(&pv->lock);
+
+ buf[0] = reg;
+ tries = 0;
+ for (;;) {
+ nw = i2c_master_send(pv->i2c, buf, 1);
+ if (nw > 0 || (nw < 0 && nw != -EIO) || tries >= 100)
+ break;
+ msleep(10);
+ ++tries;
+ }
+ if (nw <= 0) {
+ pr_err("Failure writing address to FCU: %d", nw);
+ nr = nw;
+ goto bail;
+ }
+ tries = 0;
+ for (;;) {
+ nr = i2c_master_recv(pv->i2c, buf, nb);
+ if (nr > 0 || (nr < 0 && nr != -ENODEV) || tries >= 100)
+ break;
+ msleep(10);
+ ++tries;
+ }
+ if (nr <= 0)
+ pr_err("wf_fcu: Failure reading data from FCU: %d", nw);
+ bail:
+ mutex_unlock(&pv->lock);
+ return nr;
+}
+
+static int wf_fcu_write_reg(struct wf_fcu_priv *pv, int reg,
+ const unsigned char *ptr, int nb)
+{
+ int tries, nw;
+ unsigned char buf[16];
+
+ buf[0] = reg;
+ memcpy(buf+1, ptr, nb);
+ ++nb;
+ tries = 0;
+ for (;;) {
+ nw = i2c_master_send(pv->i2c, buf, nb);
+ if (nw > 0 || (nw < 0 && nw != -EIO) || tries >= 100)
+ break;
+ msleep(10);
+ ++tries;
+ }
+ if (nw < 0)
+ pr_err("wf_fcu: Failure writing to FCU: %d", nw);
+ return nw;
+}
+
+static int wf_fcu_fan_set_rpm(struct wf_control *ct, s32 value)
+{
+ struct wf_fcu_fan *fan = ct->priv;
+ struct wf_fcu_priv *pv = fan->fcu_priv;
+ int rc, shift = pv->rpm_shift;
+ unsigned char buf[2];
+
+ if (value < fan->min)
+ value = fan->min;
+ if (value > fan->max)
+ value = fan->max;
+
+ fan->target = value;
+
+ buf[0] = value >> (8 - shift);
+ buf[1] = value << shift;
+ rc = wf_fcu_write_reg(pv, 0x10 + (fan->id * 2), buf, 2);
+ if (rc < 0)
+ return -EIO;
+ return 0;
+}
+
+static int wf_fcu_fan_get_rpm(struct wf_control *ct, s32 *value)
+{
+ struct wf_fcu_fan *fan = ct->priv;
+ struct wf_fcu_priv *pv = fan->fcu_priv;
+ int rc, reg_base, shift = pv->rpm_shift;
+ unsigned char failure;
+ unsigned char active;
+ unsigned char buf[2];
+
+ rc = wf_fcu_read_reg(pv, 0xb, &failure, 1);
+ if (rc != 1)
+ return -EIO;
+ if ((failure & (1 << fan->id)) != 0)
+ return -EFAULT;
+ rc = wf_fcu_read_reg(pv, 0xd, &active, 1);
+ if (rc != 1)
+ return -EIO;
+ if ((active & (1 << fan->id)) == 0)
+ return -ENXIO;
+
+ /* Programmed value or real current speed */
+#if RPM_PID_USE_ACTUAL_SPEED
+ reg_base = 0x11;
+#else
+ reg_base = 0x10;
+#endif
+ rc = wf_fcu_read_reg(pv, reg_base + (fan->id * 2), buf, 2);
+ if (rc != 2)
+ return -EIO;
+
+ *value = (buf[0] << (8 - shift)) | buf[1] >> shift;
+
+ return 0;
+}
+
+static int wf_fcu_fan_set_pwm(struct wf_control *ct, s32 value)
+{
+ struct wf_fcu_fan *fan = ct->priv;
+ struct wf_fcu_priv *pv = fan->fcu_priv;
+ unsigned char buf[2];
+ int rc;
+
+ if (value < fan->min)
+ value = fan->min;
+ if (value > fan->max)
+ value = fan->max;
+
+ fan->target = value;
+
+ value = (value * 2559) / 1000;
+ buf[0] = value;
+ rc = wf_fcu_write_reg(pv, 0x30 + (fan->id * 2), buf, 1);
+ if (rc < 0)
+ return -EIO;
+ return 0;
+}
+
+static int wf_fcu_fan_get_pwm(struct wf_control *ct, s32 *value)
+{
+ struct wf_fcu_fan *fan = ct->priv;
+ struct wf_fcu_priv *pv = fan->fcu_priv;
+ unsigned char failure;
+ unsigned char active;
+ unsigned char buf[2];
+ int rc;
+
+ rc = wf_fcu_read_reg(pv, 0x2b, &failure, 1);
+ if (rc != 1)
+ return -EIO;
+ if ((failure & (1 << fan->id)) != 0)
+ return -EFAULT;
+ rc = wf_fcu_read_reg(pv, 0x2d, &active, 1);
+ if (rc != 1)
+ return -EIO;
+ if ((active & (1 << fan->id)) == 0)
+ return -ENXIO;
+
+ rc = wf_fcu_read_reg(pv, 0x30 + (fan->id * 2), buf, 1);
+ if (rc != 1)
+ return -EIO;
+
+ *value = (((s32)buf[0]) * 1000) / 2559;
+
+ return 0;
+}
+
+static s32 wf_fcu_fan_min(struct wf_control *ct)
+{
+ struct wf_fcu_fan *fan = ct->priv;
+
+ return fan->min;
+}
+
+static s32 wf_fcu_fan_max(struct wf_control *ct)
+{
+ struct wf_fcu_fan *fan = ct->priv;
+
+ return fan->max;
+}
+
+static const struct wf_control_ops wf_fcu_fan_rpm_ops = {
+ .set_value = wf_fcu_fan_set_rpm,
+ .get_value = wf_fcu_fan_get_rpm,
+ .get_min = wf_fcu_fan_min,
+ .get_max = wf_fcu_fan_max,
+ .release = wf_fcu_fan_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct wf_control_ops wf_fcu_fan_pwm_ops = {
+ .set_value = wf_fcu_fan_set_pwm,
+ .get_value = wf_fcu_fan_get_pwm,
+ .get_min = wf_fcu_fan_min,
+ .get_max = wf_fcu_fan_max,
+ .release = wf_fcu_fan_release,
+ .owner = THIS_MODULE,
+};
+
+static void __devinit wf_fcu_get_pump_minmax(struct wf_fcu_fan *fan)
+{
+ const struct mpu_data *mpu = wf_get_mpu(0);
+ u16 pump_min = 0, pump_max = 0xffff;
+ u16 tmp[4];
+
+ /* Try to fetch pumps min/max infos from eeprom */
+ if (mpu) {
+ memcpy(&tmp, mpu->processor_part_num, 8);
+ if (tmp[0] != 0xffff && tmp[1] != 0xffff) {
+ pump_min = max(pump_min, tmp[0]);
+ pump_max = min(pump_max, tmp[1]);
+ }
+ if (tmp[2] != 0xffff && tmp[3] != 0xffff) {
+ pump_min = max(pump_min, tmp[2]);
+ pump_max = min(pump_max, tmp[3]);
+ }
+ }
+
+ /* Double check the values, this _IS_ needed as the EEPROM on
+ * some dual 2.5Ghz G5s seem, at least, to have both min & max
+ * same to the same value ... (grrrr)
+ */
+ if (pump_min == pump_max || pump_min == 0 || pump_max == 0xffff) {
+ pump_min = CPU_PUMP_OUTPUT_MIN;
+ pump_max = CPU_PUMP_OUTPUT_MAX;
+ }
+
+ fan->min = pump_min;
+ fan->max = pump_max;
+
+ DBG("wf_fcu: pump min/max for %s set to: [%d..%d] RPM\n",
+ fan->ctrl.name, pump_min, pump_max);
+}
+
+static void __devinit wf_fcu_get_rpmfan_minmax(struct wf_fcu_fan *fan)
+{
+ struct wf_fcu_priv *pv = fan->fcu_priv;
+ const struct mpu_data *mpu0 = wf_get_mpu(0);
+ const struct mpu_data *mpu1 = wf_get_mpu(1);
+
+ /* Default */
+ fan->min = 2400 >> pv->rpm_shift;
+ fan->max = 56000 >> pv->rpm_shift;
+
+ /* CPU fans have min/max in MPU */
+ if (mpu0 && !strcmp(fan->ctrl.name, "cpu-front-fan-0")) {
+ fan->min = max(fan->min, (s32)mpu0->rminn_intake_fan);
+ fan->max = min(fan->max, (s32)mpu0->rmaxn_intake_fan);
+ goto bail;
+ }
+ if (mpu1 && !strcmp(fan->ctrl.name, "cpu-front-fan-1")) {
+ fan->min = max(fan->min, (s32)mpu1->rminn_intake_fan);
+ fan->max = min(fan->max, (s32)mpu1->rmaxn_intake_fan);
+ goto bail;
+ }
+ if (mpu0 && !strcmp(fan->ctrl.name, "cpu-rear-fan-0")) {
+ fan->min = max(fan->min, (s32)mpu0->rminn_exhaust_fan);
+ fan->max = min(fan->max, (s32)mpu0->rmaxn_exhaust_fan);
+ goto bail;
+ }
+ if (mpu1 && !strcmp(fan->ctrl.name, "cpu-rear-fan-1")) {
+ fan->min = max(fan->min, (s32)mpu1->rminn_exhaust_fan);
+ fan->max = min(fan->max, (s32)mpu1->rmaxn_exhaust_fan);
+ goto bail;
+ }
+ /* Rackmac variants, we just use mpu0 intake */
+ if (!strncmp(fan->ctrl.name, "cpu-fan", 7)) {
+ fan->min = max(fan->min, (s32)mpu0->rminn_intake_fan);
+ fan->max = min(fan->max, (s32)mpu0->rmaxn_intake_fan);
+ goto bail;
+ }
+ bail:
+ DBG("wf_fcu: fan min/max for %s set to: [%d..%d] RPM\n",
+ fan->ctrl.name, fan->min, fan->max);
+}
+
+static void __devinit wf_fcu_add_fan(struct wf_fcu_priv *pv,
+ const char *name,
+ int type, int id)
+{
+ struct wf_fcu_fan *fan;
+
+ fan = kzalloc(sizeof(*fan), GFP_KERNEL);
+ if (!fan)
+ return;
+ fan->fcu_priv = pv;
+ fan->id = id;
+ fan->ctrl.name = name;
+ fan->ctrl.priv = fan;
+
+ /* min/max is oddball but the code comes from
+ * therm_pm72 which seems to work so ...
+ */
+ if (type == FCU_FAN_RPM) {
+ if (!strncmp(name, "cpu-pump", strlen("cpu-pump")))
+ wf_fcu_get_pump_minmax(fan);
+ else
+ wf_fcu_get_rpmfan_minmax(fan);
+ fan->ctrl.type = WF_CONTROL_RPM_FAN;
+ fan->ctrl.ops = &wf_fcu_fan_rpm_ops;
+ } else {
+ fan->min = 10;
+ fan->max = 100;
+ fan->ctrl.type = WF_CONTROL_PWM_FAN;
+ fan->ctrl.ops = &wf_fcu_fan_pwm_ops;
+ }
+
+ if (wf_register_control(&fan->ctrl)) {
+ pr_err("wf_fcu: Failed to register fan %s\n", name);
+ kfree(fan);
+ return;
+ }
+ list_add(&fan->link, &pv->fan_list);
+ kref_get(&pv->ref);
+}
+
+static void __devinit wf_fcu_lookup_fans(struct wf_fcu_priv *pv)
+{
+ /* Translation of device-tree location properties to
+ * windfarm fan names
+ */
+ static const struct {
+ const char *dt_name; /* Device-tree name */
+ const char *ct_name; /* Control name */
+ } loc_trans[] = {
+ { "BACKSIDE", "backside-fan", },
+ { "SYS CTRLR FAN", "backside-fan", },
+ { "DRIVE BAY", "drive-bay-fan", },
+ { "SLOT", "slots-fan", },
+ { "PCI FAN", "slots-fan", },
+ { "CPU A INTAKE", "cpu-front-fan-0", },
+ { "CPU A EXHAUST", "cpu-rear-fan-0", },
+ { "CPU B INTAKE", "cpu-front-fan-1", },
+ { "CPU B EXHAUST", "cpu-rear-fan-1", },
+ { "CPU A PUMP", "cpu-pump-0", },
+ { "CPU B PUMP", "cpu-pump-1", },
+ { "CPU A 1", "cpu-fan-a-0", },
+ { "CPU A 2", "cpu-fan-b-0", },
+ { "CPU A 3", "cpu-fan-c-0", },
+ { "CPU B 1", "cpu-fan-a-1", },
+ { "CPU B 2", "cpu-fan-b-1", },
+ { "CPU B 3", "cpu-fan-c-1", },
+ };
+ struct device_node *np = NULL, *fcu = pv->i2c->dev.of_node;
+ int i;
+
+ DBG("Looking up FCU controls in device-tree...\n");
+
+ while ((np = of_get_next_child(fcu, np)) != NULL) {
+ int id, type = -1;
+ const char *loc;
+ const char *name;
+ const u32 *reg;
+
+ DBG(" control: %s, type: %s\n", np->name, np->type);
+
+ /* Detect control type */
+ if (!strcmp(np->type, "fan-rpm-control") ||
+ !strcmp(np->type, "fan-rpm"))
+ type = FCU_FAN_RPM;
+ if (!strcmp(np->type, "fan-pwm-control") ||
+ !strcmp(np->type, "fan-pwm"))
+ type = FCU_FAN_PWM;
+ /* Only care about fans for now */
+ if (type == -1)
+ continue;
+
+ /* Lookup for a matching location */
+ loc = of_get_property(np, "location", NULL);
+ reg = of_get_property(np, "reg", NULL);
+ if (loc == NULL || reg == NULL)
+ continue;
+ DBG(" matching location: %s, reg: 0x%08x\n", loc, *reg);
+
+ for (i = 0; i < ARRAY_SIZE(loc_trans); i++) {
+ if (strncmp(loc, loc_trans[i].dt_name,
+ strlen(loc_trans[i].dt_name)))
+ continue;
+ name = loc_trans[i].ct_name;
+
+ DBG(" location match, name: %s\n", name);
+
+ if (type == FCU_FAN_RPM)
+ id = ((*reg) - 0x10) / 2;
+ else
+ id = ((*reg) - 0x30) / 2;
+ if (id > 7) {
+ pr_warning("wf_fcu: Can't parse "
+ "fan ID in device-tree for %s\n",
+ np->full_name);
+ break;
+ }
+ wf_fcu_add_fan(pv, name, type, id);
+ break;
+ }
+ }
+}
+
+static void __devinit wf_fcu_default_fans(struct wf_fcu_priv *pv)
+{
+ /* We only support the default fans for PowerMac7,2 */
+ if (!of_machine_is_compatible("PowerMac7,2"))
+ return;
+
+ wf_fcu_add_fan(pv, "backside-fan", FCU_FAN_PWM, 1);
+ wf_fcu_add_fan(pv, "drive-bay-fan", FCU_FAN_RPM, 2);
+ wf_fcu_add_fan(pv, "slots-fan", FCU_FAN_PWM, 2);
+ wf_fcu_add_fan(pv, "cpu-front-fan-0", FCU_FAN_RPM, 3);
+ wf_fcu_add_fan(pv, "cpu-rear-fan-0", FCU_FAN_RPM, 4);
+ wf_fcu_add_fan(pv, "cpu-front-fan-1", FCU_FAN_RPM, 5);
+ wf_fcu_add_fan(pv, "cpu-rear-fan-1", FCU_FAN_RPM, 6);
+}
+
+static int __devinit wf_fcu_init_chip(struct wf_fcu_priv *pv)
+{
+ unsigned char buf = 0xff;
+ int rc;
+
+ rc = wf_fcu_write_reg(pv, 0xe, &buf, 1);
+ if (rc < 0)
+ return -EIO;
+ rc = wf_fcu_write_reg(pv, 0x2e, &buf, 1);
+ if (rc < 0)
+ return -EIO;
+ rc = wf_fcu_read_reg(pv, 0, &buf, 1);
+ if (rc < 0)
+ return -EIO;
+ pv->rpm_shift = (buf == 1) ? 2 : 3;
+
+ pr_debug("wf_fcu: FCU Initialized, RPM fan shift is %d\n",
+ pv->rpm_shift);
+
+ return 0;
+}
+
+static int __devinit wf_fcu_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct wf_fcu_priv *pv;
+
+ pv = kzalloc(sizeof(*pv), GFP_KERNEL);
+ if (!pv)
+ return -ENOMEM;
+
+ kref_init(&pv->ref);
+ mutex_init(&pv->lock);
+ INIT_LIST_HEAD(&pv->fan_list);
+ pv->i2c = client;
+
+ /*
+ * First we must start the FCU which will query the
+ * shift value to apply to RPMs
+ */
+ if (wf_fcu_init_chip(pv)) {
+ pr_err("wf_fcu: Initialization failed !\n");
+ kfree(pv);
+ return -ENXIO;
+ }
+
+ /* First lookup fans in the device-tree */
+ wf_fcu_lookup_fans(pv);
+
+ /*
+ * Older machines don't have the device-tree entries
+ * we are looking for, just hard code the list
+ */
+ if (list_empty(&pv->fan_list))
+ wf_fcu_default_fans(pv);
+
+ /* Still no fans ? FAIL */
+ if (list_empty(&pv->fan_list)) {
+ pr_err("wf_fcu: Failed to find fans for your machine\n");
+ kfree(pv);
+ return -ENODEV;
+ }
+
+ dev_set_drvdata(&client->dev, pv);
+
+ return 0;
+}
+
+static int __devexit wf_fcu_remove(struct i2c_client *client)
+{
+ struct wf_fcu_priv *pv = dev_get_drvdata(&client->dev);
+ struct wf_fcu_fan *fan;
+
+ while (!list_empty(&pv->fan_list)) {
+ fan = list_first_entry(&pv->fan_list, struct wf_fcu_fan, link);
+ list_del(&fan->link);
+ wf_unregister_control(&fan->ctrl);
+ }
+ kref_put(&pv->ref, wf_fcu_release);
+ return 0;
+}
+
+static const struct i2c_device_id wf_fcu_id[] = {
+ { "MAC,fcu", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wf_fcu_id);
+
+static struct i2c_driver wf_fcu_driver = {
+ .driver = {
+ .name = "wf_fcu",
+ },
+ .probe = wf_fcu_probe,
+ .remove = wf_fcu_remove,
+ .id_table = wf_fcu_id,
+};
+
+static int __init wf_fcu_init(void)
+{
+ return i2c_add_driver(&wf_fcu_driver);
+}
+
+static void __exit wf_fcu_exit(void)
+{
+ i2c_del_driver(&wf_fcu_driver);
+}
+
+
+module_init(wf_fcu_init);
+module_exit(wf_fcu_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("FCU control objects for PowerMacs thermal control");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c
index 4d6a90a1372b..b0c2d3695b34 100644
--- a/drivers/macintosh/windfarm_lm75_sensor.c
+++ b/drivers/macintosh/windfarm_lm75_sensor.c
@@ -23,7 +23,7 @@
#include "windfarm.h"
-#define VERSION "0.2"
+#define VERSION "1.0"
#undef DEBUG
@@ -36,8 +36,8 @@
struct wf_lm75_sensor {
int ds1775 : 1;
int inited : 1;
- struct i2c_client *i2c;
- struct wf_sensor sens;
+ struct i2c_client *i2c;
+ struct wf_sensor sens;
};
#define wf_to_lm75(c) container_of(c, struct wf_lm75_sensor, sens)
@@ -90,40 +90,19 @@ static struct wf_sensor_ops wf_lm75_ops = {
static int wf_lm75_probe(struct i2c_client *client,
const struct i2c_device_id *id)
-{
+{
struct wf_lm75_sensor *lm;
- int rc;
-
- lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
- if (lm == NULL)
- return -ENODEV;
-
- lm->inited = 0;
- lm->ds1775 = id->driver_data;
- lm->i2c = client;
- lm->sens.name = client->dev.platform_data;
- lm->sens.ops = &wf_lm75_ops;
- i2c_set_clientdata(client, lm);
-
- rc = wf_register_sensor(&lm->sens);
- if (rc)
- kfree(lm);
-
- return rc;
-}
-
-static struct i2c_driver wf_lm75_driver;
-
-static struct i2c_client *wf_lm75_create(struct i2c_adapter *adapter,
- u8 addr, int ds1775,
- const char *loc)
-{
- struct i2c_board_info info;
- struct i2c_client *client;
- char *name;
+ int rc, ds1775 = id->driver_data;
+ const char *name, *loc;
DBG("wf_lm75: creating %s device at address 0x%02x\n",
- ds1775 ? "ds1775" : "lm75", addr);
+ ds1775 ? "ds1775" : "lm75", client->addr);
+
+ loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL);
+ if (!loc) {
+ dev_warn(&client->dev, "Missing hwsensor-location property!\n");
+ return -ENXIO;
+ }
/* Usual rant about sensor names not beeing very consistent in
* the device-tree, oh well ...
@@ -137,68 +116,31 @@ static struct i2c_client *wf_lm75_create(struct i2c_adapter *adapter,
name = "optical-drive-temp";
else if (!strcmp(loc, "HD Temp"))
name = "hard-drive-temp";
+ else if (!strcmp(loc, "PCI SLOTS"))
+ name = "slots-temp";
+ else if (!strcmp(loc, "CPU A INLET"))
+ name = "cpu-inlet-temp-0";
+ else if (!strcmp(loc, "CPU B INLET"))
+ name = "cpu-inlet-temp-1";
else
- goto fail;
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = (addr >> 1) & 0x7f;
- info.platform_data = name;
- strlcpy(info.type, ds1775 ? "wf_ds1775" : "wf_lm75", I2C_NAME_SIZE);
-
- client = i2c_new_device(adapter, &info);
- if (client == NULL) {
- printk(KERN_ERR "windfarm: failed to attach %s %s to i2c\n",
- ds1775 ? "ds1775" : "lm75", name);
- goto fail;
- }
-
- /*
- * Let i2c-core delete that device on driver removal.
- * This is safe because i2c-core holds the core_lock mutex for us.
- */
- list_add_tail(&client->detected, &wf_lm75_driver.clients);
- return client;
- fail:
- return NULL;
-}
-
-static int wf_lm75_attach(struct i2c_adapter *adapter)
-{
- struct device_node *busnode, *dev;
- struct pmac_i2c_bus *bus;
+ return -ENXIO;
+
- DBG("wf_lm75: adapter %s detected\n", adapter->name);
-
- bus = pmac_i2c_adapter_to_bus(adapter);
- if (bus == NULL)
+ lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
+ if (lm == NULL)
return -ENODEV;
- busnode = pmac_i2c_get_bus_node(bus);
- DBG("wf_lm75: bus found, looking for device...\n");
-
- /* Now look for lm75(s) in there */
- for (dev = NULL;
- (dev = of_get_next_child(busnode, dev)) != NULL;) {
- const char *loc =
- of_get_property(dev, "hwsensor-location", NULL);
- u8 addr;
+ lm->inited = 0;
+ lm->ds1775 = ds1775;
+ lm->i2c = client;
+ lm->sens.name = (char *)name; /* XXX fix constness in structure */
+ lm->sens.ops = &wf_lm75_ops;
+ i2c_set_clientdata(client, lm);
- /* We must re-match the adapter in order to properly check
- * the channel on multibus setups
- */
- if (!pmac_i2c_match_adapter(dev, adapter))
- continue;
- addr = pmac_i2c_get_dev_addr(dev);
- if (loc == NULL || addr == 0)
- continue;
- /* real lm75 */
- if (of_device_is_compatible(dev, "lm75"))
- wf_lm75_create(adapter, addr, 0, loc);
- /* ds1775 (compatible, better resolution */
- else if (of_device_is_compatible(dev, "ds1775"))
- wf_lm75_create(adapter, addr, 1, loc);
- }
- return 0;
+ rc = wf_register_sensor(&lm->sens);
+ if (rc)
+ kfree(lm);
+ return rc;
}
static int wf_lm75_remove(struct i2c_client *client)
@@ -217,16 +159,16 @@ static int wf_lm75_remove(struct i2c_client *client)
}
static const struct i2c_device_id wf_lm75_id[] = {
- { "wf_lm75", 0 },
- { "wf_ds1775", 1 },
+ { "MAC,lm75", 0 },
+ { "MAC,ds1775", 1 },
{ }
};
+MODULE_DEVICE_TABLE(i2c, wf_lm75_id);
static struct i2c_driver wf_lm75_driver = {
.driver = {
.name = "wf_lm75",
},
- .attach_adapter = wf_lm75_attach,
.probe = wf_lm75_probe,
.remove = wf_lm75_remove,
.id_table = wf_lm75_id,
@@ -234,11 +176,6 @@ static struct i2c_driver wf_lm75_driver = {
static int __init wf_lm75_sensor_init(void)
{
- /* Don't register on old machines that use therm_pm72 for now */
- if (of_machine_is_compatible("PowerMac7,2") ||
- of_machine_is_compatible("PowerMac7,3") ||
- of_machine_is_compatible("RackMac3,1"))
- return -ENODEV;
return i2c_add_driver(&wf_lm75_driver);
}
diff --git a/drivers/macintosh/windfarm_lm87_sensor.c b/drivers/macintosh/windfarm_lm87_sensor.c
new file mode 100644
index 000000000000..c071aab79dd1
--- /dev/null
+++ b/drivers/macintosh/windfarm_lm87_sensor.c
@@ -0,0 +1,201 @@
+/*
+ * Windfarm PowerMac thermal control. LM87 sensor
+ *
+ * Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Released under the term of the GNU GPL v2.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/i2c.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/sections.h>
+#include <asm/pmac_low_i2c.h>
+
+#include "windfarm.h"
+
+#define VERSION "1.0"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(args...) printk(args)
+#else
+#define DBG(args...) do { } while(0)
+#endif
+
+struct wf_lm87_sensor {
+ struct i2c_client *i2c;
+ struct wf_sensor sens;
+};
+#define wf_to_lm87(c) container_of(c, struct wf_lm87_sensor, sens)
+
+
+static int wf_lm87_read_reg(struct i2c_client *chip, int reg)
+{
+ int rc, tries = 0;
+ u8 buf;
+
+ for (;;) {
+ /* Set address */
+ buf = (u8)reg;
+ rc = i2c_master_send(chip, &buf, 1);
+ if (rc <= 0)
+ goto error;
+ rc = i2c_master_recv(chip, &buf, 1);
+ if (rc <= 0)
+ goto error;
+ return (int)buf;
+ error:
+ DBG("wf_lm87: Error reading LM87, retrying...\n");
+ if (++tries > 10) {
+ printk(KERN_ERR "wf_lm87: Error reading LM87 !\n");
+ return -EIO;
+ }
+ msleep(10);
+ }
+}
+
+static int wf_lm87_get(struct wf_sensor *sr, s32 *value)
+{
+ struct wf_lm87_sensor *lm = sr->priv;
+ s32 temp;
+
+ if (lm->i2c == NULL)
+ return -ENODEV;
+
+#define LM87_INT_TEMP 0x27
+
+ /* Read temperature register */
+ temp = wf_lm87_read_reg(lm->i2c, LM87_INT_TEMP);
+ if (temp < 0)
+ return temp;
+ *value = temp << 16;
+
+ return 0;
+}
+
+static void wf_lm87_release(struct wf_sensor *sr)
+{
+ struct wf_lm87_sensor *lm = wf_to_lm87(sr);
+
+ kfree(lm);
+}
+
+static struct wf_sensor_ops wf_lm87_ops = {
+ .get_value = wf_lm87_get,
+ .release = wf_lm87_release,
+ .owner = THIS_MODULE,
+};
+
+static int wf_lm87_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct wf_lm87_sensor *lm;
+ const char *name = NULL, *loc;
+ struct device_node *np = NULL;
+ int rc;
+
+ /*
+ * The lm87 contains a whole pile of sensors, additionally,
+ * the Xserve G5 has several lm87's. However, for now we only
+ * care about the internal temperature sensor
+ */
+ while ((np = of_get_next_child(client->dev.of_node, np)) != NULL) {
+ if (strcmp(np->name, "int-temp"))
+ continue;
+ loc = of_get_property(np, "location", NULL);
+ if (!loc)
+ continue;
+ if (strstr(loc, "DIMM"))
+ name = "dimms-temp";
+ else if (strstr(loc, "Processors"))
+ name = "between-cpus-temp";
+ if (name) {
+ of_node_put(np);
+ break;
+ }
+ }
+ if (!name) {
+ pr_warning("wf_lm87: Unsupported sensor %s\n",
+ client->dev.of_node->full_name);
+ return -ENODEV;
+ }
+
+ lm = kzalloc(sizeof(struct wf_lm87_sensor), GFP_KERNEL);
+ if (lm == NULL)
+ return -ENODEV;
+
+ lm->i2c = client;
+ lm->sens.name = name;
+ lm->sens.ops = &wf_lm87_ops;
+ lm->sens.priv = lm;
+ i2c_set_clientdata(client, lm);
+
+ rc = wf_register_sensor(&lm->sens);
+ if (rc)
+ kfree(lm);
+ return rc;
+}
+
+static int wf_lm87_remove(struct i2c_client *client)
+{
+ struct wf_lm87_sensor *lm = i2c_get_clientdata(client);
+
+ DBG("wf_lm87: i2c detatch called for %s\n", lm->sens.name);
+
+ /* Mark client detached */
+ lm->i2c = NULL;
+
+ /* release sensor */
+ wf_unregister_sensor(&lm->sens);
+
+ return 0;
+}
+
+static const struct i2c_device_id wf_lm87_id[] = {
+ { "MAC,lm87cimt", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wf_lm87_id);
+
+static struct i2c_driver wf_lm87_driver = {
+ .driver = {
+ .name = "wf_lm87",
+ },
+ .probe = wf_lm87_probe,
+ .remove = wf_lm87_remove,
+ .id_table = wf_lm87_id,
+};
+
+static int __init wf_lm87_sensor_init(void)
+{
+ /* We only support this on the Xserve */
+ if (!of_machine_is_compatible("RackMac3,1"))
+ return -ENODEV;
+
+ return i2c_add_driver(&wf_lm87_driver);
+}
+
+static void __exit wf_lm87_sensor_exit(void)
+{
+ i2c_del_driver(&wf_lm87_driver);
+}
+
+
+module_init(wf_lm87_sensor_init);
+module_exit(wf_lm87_sensor_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("LM87 sensor objects for PowerMacs thermal control");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c
index 8204113268f4..371b058d2f7d 100644
--- a/drivers/macintosh/windfarm_max6690_sensor.c
+++ b/drivers/macintosh/windfarm_max6690_sensor.c
@@ -16,7 +16,7 @@
#include "windfarm.h"
-#define VERSION "0.2"
+#define VERSION "1.0"
/* This currently only exports the external temperature sensor,
since that's all the control loops need. */
@@ -64,9 +64,29 @@ static struct wf_sensor_ops wf_max6690_ops = {
static int wf_max6690_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ const char *name, *loc;
struct wf_6690_sensor *max;
int rc;
+ loc = of_get_property(client->dev.of_node, "hwsensor-location", NULL);
+ if (!loc) {
+ dev_warn(&client->dev, "Missing hwsensor-location property!\n");
+ return -ENXIO;
+ }
+
+ /*
+ * We only expose the external temperature register for
+ * now as this is all we need for our control loops
+ */
+ if (!strcmp(loc, "BACKSIDE") || !strcmp(loc, "SYS CTRLR AMBIENT"))
+ name = "backside-temp";
+ else if (!strcmp(loc, "NB Ambient"))
+ name = "north-bridge-temp";
+ else if (!strcmp(loc, "GPU Ambient"))
+ name = "gpu-temp";
+ else
+ return -ENXIO;
+
max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL);
if (max == NULL) {
printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor: "
@@ -75,90 +95,16 @@ static int wf_max6690_probe(struct i2c_client *client,
}
max->i2c = client;
- max->sens.name = client->dev.platform_data;
+ max->sens.name = (char *)name; /* XXX fix constness in structure */
max->sens.ops = &wf_max6690_ops;
i2c_set_clientdata(client, max);
rc = wf_register_sensor(&max->sens);
- if (rc) {
+ if (rc)
kfree(max);
- }
-
return rc;
}
-static struct i2c_driver wf_max6690_driver;
-
-static struct i2c_client *wf_max6690_create(struct i2c_adapter *adapter,
- u8 addr, const char *loc)
-{
- struct i2c_board_info info;
- struct i2c_client *client;
- char *name;
-
- if (!strcmp(loc, "BACKSIDE"))
- name = "backside-temp";
- else if (!strcmp(loc, "NB Ambient"))
- name = "north-bridge-temp";
- else if (!strcmp(loc, "GPU Ambient"))
- name = "gpu-temp";
- else
- goto fail;
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = addr >> 1;
- info.platform_data = name;
- strlcpy(info.type, "wf_max6690", I2C_NAME_SIZE);
-
- client = i2c_new_device(adapter, &info);
- if (client == NULL) {
- printk(KERN_ERR "windfarm: failed to attach MAX6690 sensor\n");
- goto fail;
- }
-
- /*
- * Let i2c-core delete that device on driver removal.
- * This is safe because i2c-core holds the core_lock mutex for us.
- */
- list_add_tail(&client->detected, &wf_max6690_driver.clients);
- return client;
-
- fail:
- return NULL;
-}
-
-static int wf_max6690_attach(struct i2c_adapter *adapter)
-{
- struct device_node *busnode, *dev = NULL;
- struct pmac_i2c_bus *bus;
- const char *loc;
-
- bus = pmac_i2c_adapter_to_bus(adapter);
- if (bus == NULL)
- return -ENODEV;
- busnode = pmac_i2c_get_bus_node(bus);
-
- while ((dev = of_get_next_child(busnode, dev)) != NULL) {
- u8 addr;
-
- /* We must re-match the adapter in order to properly check
- * the channel on multibus setups
- */
- if (!pmac_i2c_match_adapter(dev, adapter))
- continue;
- if (!of_device_is_compatible(dev, "max6690"))
- continue;
- addr = pmac_i2c_get_dev_addr(dev);
- loc = of_get_property(dev, "hwsensor-location", NULL);
- if (loc == NULL || addr == 0)
- continue;
- printk("found max6690, loc=%s addr=0x%02x\n", loc, addr);
- wf_max6690_create(adapter, addr, loc);
- }
-
- return 0;
-}
-
static int wf_max6690_remove(struct i2c_client *client)
{
struct wf_6690_sensor *max = i2c_get_clientdata(client);
@@ -170,15 +116,15 @@ static int wf_max6690_remove(struct i2c_client *client)
}
static const struct i2c_device_id wf_max6690_id[] = {
- { "wf_max6690", 0 },
+ { "MAC,max6690", 0 },
{ }
};
+MODULE_DEVICE_TABLE(i2c, wf_max6690_id);
static struct i2c_driver wf_max6690_driver = {
.driver = {
.name = "wf_max6690",
},
- .attach_adapter = wf_max6690_attach,
.probe = wf_max6690_probe,
.remove = wf_max6690_remove,
.id_table = wf_max6690_id,
@@ -186,11 +132,6 @@ static struct i2c_driver wf_max6690_driver = {
static int __init wf_max6690_sensor_init(void)
{
- /* Don't register on old machines that use therm_pm72 for now */
- if (of_machine_is_compatible("PowerMac7,2") ||
- of_machine_is_compatible("PowerMac7,3") ||
- of_machine_is_compatible("RackMac3,1"))
- return -ENODEV;
return i2c_add_driver(&wf_max6690_driver);
}
diff --git a/drivers/macintosh/windfarm_mpu.h b/drivers/macintosh/windfarm_mpu.h
new file mode 100644
index 000000000000..046edc8c2ec5
--- /dev/null
+++ b/drivers/macintosh/windfarm_mpu.h
@@ -0,0 +1,105 @@
+/*
+ * Windfarm PowerMac thermal control
+ *
+ * Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Released under the term of the GNU GPL v2.
+ */
+
+#ifndef __WINDFARM_MPU_H
+#define __WINDFARM_MPU_H
+
+typedef unsigned short fu16;
+typedef int fs32;
+typedef short fs16;
+
+/* Definition of the MPU data structure which contains per CPU
+ * calibration information (among others) for the G5 machines
+ */
+struct mpu_data
+{
+ u8 signature; /* 0x00 - EEPROM sig. */
+ u8 bytes_used; /* 0x01 - Bytes used in eeprom (160 ?) */
+ u8 size; /* 0x02 - EEPROM size (256 ?) */
+ u8 version; /* 0x03 - EEPROM version */
+ u32 data_revision; /* 0x04 - Dataset revision */
+ u8 processor_bin_code[3]; /* 0x08 - Processor BIN code */
+ u8 bin_code_expansion; /* 0x0b - ??? (padding ?) */
+ u8 processor_num; /* 0x0c - Number of CPUs on this MPU */
+ u8 input_mul_bus_div; /* 0x0d - Clock input multiplier/bus divider */
+ u8 reserved1[2]; /* 0x0e - */
+ u32 input_clk_freq_high; /* 0x10 - Input clock frequency high */
+ u8 cpu_nb_target_cycles; /* 0x14 - ??? */
+ u8 cpu_statlat; /* 0x15 - ??? */
+ u8 cpu_snooplat; /* 0x16 - ??? */
+ u8 cpu_snoopacc; /* 0x17 - ??? */
+ u8 nb_paamwin; /* 0x18 - ??? */
+ u8 nb_statlat; /* 0x19 - ??? */
+ u8 nb_snooplat; /* 0x1a - ??? */
+ u8 nb_snoopwin; /* 0x1b - ??? */
+ u8 api_bus_mode; /* 0x1c - ??? */
+ u8 reserved2[3]; /* 0x1d - */
+ u32 input_clk_freq_low; /* 0x20 - Input clock frequency low */
+ u8 processor_card_slot; /* 0x24 - Processor card slot number */
+ u8 reserved3[2]; /* 0x25 - */
+ u8 padjmax; /* 0x27 - Max power adjustment (Not in OF!) */
+ u8 ttarget; /* 0x28 - Target temperature */
+ u8 tmax; /* 0x29 - Max temperature */
+ u8 pmaxh; /* 0x2a - Max power */
+ u8 tguardband; /* 0x2b - Guardband temp ??? Hist. len in OSX */
+ fs32 pid_gp; /* 0x2c - PID proportional gain */
+ fs32 pid_gr; /* 0x30 - PID reset gain */
+ fs32 pid_gd; /* 0x34 - PID derivative gain */
+ fu16 voph; /* 0x38 - Vop High */
+ fu16 vopl; /* 0x3a - Vop Low */
+ fs16 nactual_die; /* 0x3c - nActual Die */
+ fs16 nactual_heatsink; /* 0x3e - nActual Heatsink */
+ fs16 nactual_system; /* 0x40 - nActual System */
+ u16 calibration_flags; /* 0x42 - Calibration flags */
+ fu16 mdiode; /* 0x44 - Diode M value (scaling factor) */
+ fs16 bdiode; /* 0x46 - Diode B value (offset) */
+ fs32 theta_heat_sink; /* 0x48 - Theta heat sink */
+ u16 rminn_intake_fan; /* 0x4c - Intake fan min RPM */
+ u16 rmaxn_intake_fan; /* 0x4e - Intake fan max RPM */
+ u16 rminn_exhaust_fan; /* 0x50 - Exhaust fan min RPM */
+ u16 rmaxn_exhaust_fan; /* 0x52 - Exhaust fan max RPM */
+ u8 processor_part_num[8]; /* 0x54 - Processor part number XX pumps min/max */
+ u32 processor_lot_num; /* 0x5c - Processor lot number */
+ u8 orig_card_sernum[0x10]; /* 0x60 - Card original serial number */
+ u8 curr_card_sernum[0x10]; /* 0x70 - Card current serial number */
+ u8 mlb_sernum[0x18]; /* 0x80 - MLB serial number */
+ u32 checksum1; /* 0x98 - */
+ u32 checksum2; /* 0x9c - */
+}; /* Total size = 0xa0 */
+
+static inline const struct mpu_data *wf_get_mpu(int cpu)
+{
+ struct device_node *np;
+ char nodename[64];
+ const void *data;
+ int len;
+
+ /*
+ * prom.c routine for finding a node by path is a bit brain dead
+ * and requires exact @xxx unit numbers. This is a bit ugly but
+ * will work for these machines
+ */
+ sprintf(nodename, "/u3@0,f8000000/i2c@f8001000/cpuid@a%d", cpu ? 2 : 0);
+ np = of_find_node_by_path(nodename);
+ if (!np)
+ return NULL;
+ data = of_get_property(np, "cpuid", &len);
+ of_node_put(np);
+ if (!data)
+ return NULL;
+
+ /*
+ * We are naughty, we have dropped the reference to the device
+ * node and still return a pointer to the content. We know we
+ * can do that though as this is only ever called on PowerMac
+ * which cannot remove those nodes
+ */
+ return data;
+}
+
+#endif /* __WINDFARM_MPU_H */
diff --git a/drivers/macintosh/windfarm_pm72.c b/drivers/macintosh/windfarm_pm72.c
new file mode 100644
index 000000000000..84ac913d7e3a
--- /dev/null
+++ b/drivers/macintosh/windfarm_pm72.c
@@ -0,0 +1,847 @@
+/*
+ * Windfarm PowerMac thermal control.
+ * Control loops for PowerMac7,2 and 7,3
+ *
+ * Copyright (C) 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Use and redistribute under the terms of the GNU GPL v2.
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <asm/prom.h>
+#include <asm/smu.h>
+
+#include "windfarm.h"
+#include "windfarm_pid.h"
+#include "windfarm_mpu.h"
+
+#define VERSION "1.0"
+
+#undef DEBUG
+#undef LOTSA_DEBUG
+
+#ifdef DEBUG
+#define DBG(args...) printk(args)
+#else
+#define DBG(args...) do { } while(0)
+#endif
+
+#ifdef LOTSA_DEBUG
+#define DBG_LOTS(args...) printk(args)
+#else
+#define DBG_LOTS(args...) do { } while(0)
+#endif
+
+/* define this to force CPU overtemp to 60 degree, useful for testing
+ * the overtemp code
+ */
+#undef HACKED_OVERTEMP
+
+/* We currently only handle 2 chips */
+#define NR_CHIPS 2
+#define NR_CPU_FANS 3 * NR_CHIPS
+
+/* Controls and sensors */
+static struct wf_sensor *sens_cpu_temp[NR_CHIPS];
+static struct wf_sensor *sens_cpu_volts[NR_CHIPS];
+static struct wf_sensor *sens_cpu_amps[NR_CHIPS];
+static struct wf_sensor *backside_temp;
+static struct wf_sensor *drives_temp;
+
+static struct wf_control *cpu_front_fans[NR_CHIPS];
+static struct wf_control *cpu_rear_fans[NR_CHIPS];
+static struct wf_control *cpu_pumps[NR_CHIPS];
+static struct wf_control *backside_fan;
+static struct wf_control *drives_fan;
+static struct wf_control *slots_fan;
+static struct wf_control *cpufreq_clamp;
+
+/* We keep a temperature history for average calculation of 180s */
+#define CPU_TEMP_HIST_SIZE 180
+
+/* Fixed speed for slot fan */
+#define SLOTS_FAN_DEFAULT_PWM 40
+
+/* Scale value for CPU intake fans */
+#define CPU_INTAKE_SCALE 0x0000f852
+
+/* PID loop state */
+static const struct mpu_data *cpu_mpu_data[NR_CHIPS];
+static struct wf_cpu_pid_state cpu_pid[NR_CHIPS];
+static bool cpu_pid_combined;
+static u32 cpu_thist[CPU_TEMP_HIST_SIZE];
+static int cpu_thist_pt;
+static s64 cpu_thist_total;
+static s32 cpu_all_tmax = 100 << 16;
+static struct wf_pid_state backside_pid;
+static int backside_tick;
+static struct wf_pid_state drives_pid;
+static int drives_tick;
+
+static int nr_chips;
+static bool have_all_controls;
+static bool have_all_sensors;
+static bool started;
+
+static int failure_state;
+#define FAILURE_SENSOR 1
+#define FAILURE_FAN 2
+#define FAILURE_PERM 4
+#define FAILURE_LOW_OVERTEMP 8
+#define FAILURE_HIGH_OVERTEMP 16
+
+/* Overtemp values */
+#define LOW_OVER_AVERAGE 0
+#define LOW_OVER_IMMEDIATE (10 << 16)
+#define LOW_OVER_CLEAR ((-10) << 16)
+#define HIGH_OVER_IMMEDIATE (14 << 16)
+#define HIGH_OVER_AVERAGE (10 << 16)
+#define HIGH_OVER_IMMEDIATE (14 << 16)
+
+
+static void cpu_max_all_fans(void)
+{
+ int i;
+
+ /* We max all CPU fans in case of a sensor error. We also do the
+ * cpufreq clamping now, even if it's supposedly done later by the
+ * generic code anyway, we do it earlier here to react faster
+ */
+ if (cpufreq_clamp)
+ wf_control_set_max(cpufreq_clamp);
+ for (i = 0; i < nr_chips; i++) {
+ if (cpu_front_fans[i])
+ wf_control_set_max(cpu_front_fans[i]);
+ if (cpu_rear_fans[i])
+ wf_control_set_max(cpu_rear_fans[i]);
+ if (cpu_pumps[i])
+ wf_control_set_max(cpu_pumps[i]);
+ }
+}
+
+static int cpu_check_overtemp(s32 temp)
+{
+ int new_state = 0;
+ s32 t_avg, t_old;
+ static bool first = true;
+
+ /* First check for immediate overtemps */
+ if (temp >= (cpu_all_tmax + LOW_OVER_IMMEDIATE)) {
+ new_state |= FAILURE_LOW_OVERTEMP;
+ if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
+ printk(KERN_ERR "windfarm: Overtemp due to immediate CPU"
+ " temperature !\n");
+ }
+ if (temp >= (cpu_all_tmax + HIGH_OVER_IMMEDIATE)) {
+ new_state |= FAILURE_HIGH_OVERTEMP;
+ if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
+ printk(KERN_ERR "windfarm: Critical overtemp due to"
+ " immediate CPU temperature !\n");
+ }
+
+ /*
+ * The first time around, initialize the array with the first
+ * temperature reading
+ */
+ if (first) {
+ int i;
+
+ cpu_thist_total = 0;
+ for (i = 0; i < CPU_TEMP_HIST_SIZE; i++) {
+ cpu_thist[i] = temp;
+ cpu_thist_total += temp;
+ }
+ first = false;
+ }
+
+ /*
+ * We calculate a history of max temperatures and use that for the
+ * overtemp management
+ */
+ t_old = cpu_thist[cpu_thist_pt];
+ cpu_thist[cpu_thist_pt] = temp;
+ cpu_thist_pt = (cpu_thist_pt + 1) % CPU_TEMP_HIST_SIZE;
+ cpu_thist_total -= t_old;
+ cpu_thist_total += temp;
+ t_avg = cpu_thist_total / CPU_TEMP_HIST_SIZE;
+
+ DBG_LOTS(" t_avg = %d.%03d (out: %d.%03d, in: %d.%03d)\n",
+ FIX32TOPRINT(t_avg), FIX32TOPRINT(t_old), FIX32TOPRINT(temp));
+
+ /* Now check for average overtemps */
+ if (t_avg >= (cpu_all_tmax + LOW_OVER_AVERAGE)) {
+ new_state |= FAILURE_LOW_OVERTEMP;
+ if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
+ printk(KERN_ERR "windfarm: Overtemp due to average CPU"
+ " temperature !\n");
+ }
+ if (t_avg >= (cpu_all_tmax + HIGH_OVER_AVERAGE)) {
+ new_state |= FAILURE_HIGH_OVERTEMP;
+ if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
+ printk(KERN_ERR "windfarm: Critical overtemp due to"
+ " average CPU temperature !\n");
+ }
+
+ /* Now handle overtemp conditions. We don't currently use the windfarm
+ * overtemp handling core as it's not fully suited to the needs of those
+ * new machine. This will be fixed later.
+ */
+ if (new_state) {
+ /* High overtemp -> immediate shutdown */
+ if (new_state & FAILURE_HIGH_OVERTEMP)
+ machine_power_off();
+ if ((failure_state & new_state) != new_state)
+ cpu_max_all_fans();
+ failure_state |= new_state;
+ } else if ((failure_state & FAILURE_LOW_OVERTEMP) &&
+ (temp < (cpu_all_tmax + LOW_OVER_CLEAR))) {
+ printk(KERN_ERR "windfarm: Overtemp condition cleared !\n");
+ failure_state &= ~FAILURE_LOW_OVERTEMP;
+ }
+
+ return failure_state & (FAILURE_LOW_OVERTEMP | FAILURE_HIGH_OVERTEMP);
+}
+
+static int read_one_cpu_vals(int cpu, s32 *temp, s32 *power)
+{
+ s32 dtemp, volts, amps;
+ int rc;
+
+ /* Get diode temperature */
+ rc = wf_sensor_get(sens_cpu_temp[cpu], &dtemp);
+ if (rc) {
+ DBG(" CPU%d: temp reading error !\n", cpu);
+ return -EIO;
+ }
+ DBG_LOTS(" CPU%d: temp = %d.%03d\n", cpu, FIX32TOPRINT((dtemp)));
+ *temp = dtemp;
+
+ /* Get voltage */
+ rc = wf_sensor_get(sens_cpu_volts[cpu], &volts);
+ if (rc) {
+ DBG(" CPU%d, volts reading error !\n", cpu);
+ return -EIO;
+ }
+ DBG_LOTS(" CPU%d: volts = %d.%03d\n", cpu, FIX32TOPRINT((volts)));
+
+ /* Get current */
+ rc = wf_sensor_get(sens_cpu_amps[cpu], &amps);
+ if (rc) {
+ DBG(" CPU%d, current reading error !\n", cpu);
+ return -EIO;
+ }
+ DBG_LOTS(" CPU%d: amps = %d.%03d\n", cpu, FIX32TOPRINT((amps)));
+
+ /* Calculate power */
+
+ /* Scale voltage and current raw sensor values according to fixed scales
+ * obtained in Darwin and calculate power from I and V
+ */
+ *power = (((u64)volts) * ((u64)amps)) >> 16;
+
+ DBG_LOTS(" CPU%d: power = %d.%03d\n", cpu, FIX32TOPRINT((*power)));
+
+ return 0;
+
+}
+
+static void cpu_fans_tick_split(void)
+{
+ int err, cpu;
+ s32 intake, temp, power, t_max = 0;
+
+ DBG_LOTS("* cpu fans_tick_split()\n");
+
+ for (cpu = 0; cpu < nr_chips; ++cpu) {
+ struct wf_cpu_pid_state *sp = &cpu_pid[cpu];
+
+ /* Read current speed */
+ wf_control_get(cpu_rear_fans[cpu], &sp->target);
+
+ DBG_LOTS(" CPU%d: cur_target = %d RPM\n", cpu, sp->target);
+
+ err = read_one_cpu_vals(cpu, &temp, &power);
+ if (err) {
+ failure_state |= FAILURE_SENSOR;
+ cpu_max_all_fans();
+ return;
+ }
+
+ /* Keep track of highest temp */
+ t_max = max(t_max, temp);
+
+ /* Handle possible overtemps */
+ if (cpu_check_overtemp(t_max))
+ return;
+
+ /* Run PID */
+ wf_cpu_pid_run(sp, power, temp);
+
+ DBG_LOTS(" CPU%d: target = %d RPM\n", cpu, sp->target);
+
+ /* Apply result directly to exhaust fan */
+ err = wf_control_set(cpu_rear_fans[cpu], sp->target);
+ if (err) {
+ pr_warning("wf_pm72: Fan %s reports error %d\n",
+ cpu_rear_fans[cpu]->name, err);
+ failure_state |= FAILURE_FAN;
+ break;
+ }
+
+ /* Scale result for intake fan */
+ intake = (sp->target * CPU_INTAKE_SCALE) >> 16;
+ DBG_LOTS(" CPU%d: intake = %d RPM\n", cpu, intake);
+ err = wf_control_set(cpu_front_fans[cpu], intake);
+ if (err) {
+ pr_warning("wf_pm72: Fan %s reports error %d\n",
+ cpu_front_fans[cpu]->name, err);
+ failure_state |= FAILURE_FAN;
+ break;
+ }
+ }
+}
+
+static void cpu_fans_tick_combined(void)
+{
+ s32 temp0, power0, temp1, power1, t_max = 0;
+ s32 temp, power, intake, pump;
+ struct wf_control *pump0, *pump1;
+ struct wf_cpu_pid_state *sp = &cpu_pid[0];
+ int err, cpu;
+
+ DBG_LOTS("* cpu fans_tick_combined()\n");
+
+ /* Read current speed from cpu 0 */
+ wf_control_get(cpu_rear_fans[0], &sp->target);
+
+ DBG_LOTS(" CPUs: cur_target = %d RPM\n", sp->target);
+
+ /* Read values for both CPUs */
+ err = read_one_cpu_vals(0, &temp0, &power0);
+ if (err) {
+ failure_state |= FAILURE_SENSOR;
+ cpu_max_all_fans();
+ return;
+ }
+ err = read_one_cpu_vals(1, &temp1, &power1);
+ if (err) {
+ failure_state |= FAILURE_SENSOR;
+ cpu_max_all_fans();
+ return;
+ }
+
+ /* Keep track of highest temp */
+ t_max = max(t_max, max(temp0, temp1));
+
+ /* Handle possible overtemps */
+ if (cpu_check_overtemp(t_max))
+ return;
+
+ /* Use the max temp & power of both */
+ temp = max(temp0, temp1);
+ power = max(power0, power1);
+
+ /* Run PID */
+ wf_cpu_pid_run(sp, power, temp);
+
+ /* Scale result for intake fan */
+ intake = (sp->target * CPU_INTAKE_SCALE) >> 16;
+
+ /* Same deal with pump speed */
+ pump0 = cpu_pumps[0];
+ pump1 = cpu_pumps[1];
+ if (!pump0) {
+ pump0 = pump1;
+ pump1 = NULL;
+ }
+ pump = (sp->target * wf_control_get_max(pump0)) /
+ cpu_mpu_data[0]->rmaxn_exhaust_fan;
+
+ DBG_LOTS(" CPUs: target = %d RPM\n", sp->target);
+ DBG_LOTS(" CPUs: intake = %d RPM\n", intake);
+ DBG_LOTS(" CPUs: pump = %d RPM\n", pump);
+
+ for (cpu = 0; cpu < nr_chips; cpu++) {
+ err = wf_control_set(cpu_rear_fans[cpu], sp->target);
+ if (err) {
+ pr_warning("wf_pm72: Fan %s reports error %d\n",
+ cpu_rear_fans[cpu]->name, err);
+ failure_state |= FAILURE_FAN;
+ }
+ err = wf_control_set(cpu_front_fans[cpu], intake);
+ if (err) {
+ pr_warning("wf_pm72: Fan %s reports error %d\n",
+ cpu_front_fans[cpu]->name, err);
+ failure_state |= FAILURE_FAN;
+ }
+ err = 0;
+ if (cpu_pumps[cpu])
+ err = wf_control_set(cpu_pumps[cpu], pump);
+ if (err) {
+ pr_warning("wf_pm72: Pump %s reports error %d\n",
+ cpu_pumps[cpu]->name, err);
+ failure_state |= FAILURE_FAN;
+ }
+ }
+}
+
+/* Implementation... */
+static int cpu_setup_pid(int cpu)
+{
+ struct wf_cpu_pid_param pid;
+ const struct mpu_data *mpu = cpu_mpu_data[cpu];
+ s32 tmax, ttarget, ptarget;
+ int fmin, fmax, hsize;
+
+ /* Get PID params from the appropriate MPU EEPROM */
+ tmax = mpu->tmax << 16;
+ ttarget = mpu->ttarget << 16;
+ ptarget = ((s32)(mpu->pmaxh - mpu->padjmax)) << 16;
+
+ DBG("wf_72: CPU%d ttarget = %d.%03d, tmax = %d.%03d\n",
+ cpu, FIX32TOPRINT(ttarget), FIX32TOPRINT(tmax));
+
+ /* We keep a global tmax for overtemp calculations */
+ if (tmax < cpu_all_tmax)
+ cpu_all_tmax = tmax;
+
+ /* Set PID min/max by using the rear fan min/max */
+ fmin = wf_control_get_min(cpu_rear_fans[cpu]);
+ fmax = wf_control_get_max(cpu_rear_fans[cpu]);
+ DBG("wf_72: CPU%d max RPM range = [%d..%d]\n", cpu, fmin, fmax);
+
+ /* History size */
+ hsize = min_t(int, mpu->tguardband, WF_PID_MAX_HISTORY);
+ DBG("wf_72: CPU%d history size = %d\n", cpu, hsize);
+
+ /* Initialize PID loop */
+ pid.interval = 1; /* seconds */
+ pid.history_len = hsize;
+ pid.gd = mpu->pid_gd;
+ pid.gp = mpu->pid_gp;
+ pid.gr = mpu->pid_gr;
+ pid.tmax = tmax;
+ pid.ttarget = ttarget;
+ pid.pmaxadj = ptarget;
+ pid.min = fmin;
+ pid.max = fmax;
+
+ wf_cpu_pid_init(&cpu_pid[cpu], &pid);
+ cpu_pid[cpu].target = 1000;
+
+ return 0;
+}
+
+/* Backside/U3 fan */
+static struct wf_pid_param backside_u3_param = {
+ .interval = 5,
+ .history_len = 2,
+ .gd = 40 << 20,
+ .gp = 5 << 20,
+ .gr = 0,
+ .itarget = 65 << 16,
+ .additive = 1,
+ .min = 20,
+ .max = 100,
+};
+
+static struct wf_pid_param backside_u3h_param = {
+ .interval = 5,
+ .history_len = 2,
+ .gd = 20 << 20,
+ .gp = 5 << 20,
+ .gr = 0,
+ .itarget = 75 << 16,
+ .additive = 1,
+ .min = 20,
+ .max = 100,
+};
+
+static void backside_fan_tick(void)
+{
+ s32 temp;
+ int speed;
+ int err;
+
+ if (!backside_fan || !backside_temp || !backside_tick)
+ return;
+ if (--backside_tick > 0)
+ return;
+ backside_tick = backside_pid.param.interval;
+
+ DBG_LOTS("* backside fans tick\n");
+
+ /* Update fan speed from actual fans */
+ err = wf_control_get(backside_fan, &speed);
+ if (!err)
+ backside_pid.target = speed;
+
+ err = wf_sensor_get(backside_temp, &temp);
+ if (err) {
+ printk(KERN_WARNING "windfarm: U4 temp sensor error %d\n",
+ err);
+ failure_state |= FAILURE_SENSOR;
+ wf_control_set_max(backside_fan);
+ return;
+ }
+ speed = wf_pid_run(&backside_pid, temp);
+
+ DBG_LOTS("backside PID temp=%d.%.3d speed=%d\n",
+ FIX32TOPRINT(temp), speed);
+
+ err = wf_control_set(backside_fan, speed);
+ if (err) {
+ printk(KERN_WARNING "windfarm: backside fan error %d\n", err);
+ failure_state |= FAILURE_FAN;
+ }
+}
+
+static void backside_setup_pid(void)
+{
+ /* first time initialize things */
+ s32 fmin = wf_control_get_min(backside_fan);
+ s32 fmax = wf_control_get_max(backside_fan);
+ struct wf_pid_param param;
+ struct device_node *u3;
+ int u3h = 1; /* conservative by default */
+
+ u3 = of_find_node_by_path("/u3@0,f8000000");
+ if (u3 != NULL) {
+ const u32 *vers = of_get_property(u3, "device-rev", NULL);
+ if (vers)
+ if (((*vers) & 0x3f) < 0x34)
+ u3h = 0;
+ of_node_put(u3);
+ }
+
+ param = u3h ? backside_u3h_param : backside_u3_param;
+
+ param.min = max(param.min, fmin);
+ param.max = min(param.max, fmax);
+ wf_pid_init(&backside_pid, &param);
+ backside_tick = 1;
+
+ pr_info("wf_pm72: Backside control loop started.\n");
+}
+
+/* Drive bay fan */
+static const struct wf_pid_param drives_param = {
+ .interval = 5,
+ .history_len = 2,
+ .gd = 30 << 20,
+ .gp = 5 << 20,
+ .gr = 0,
+ .itarget = 40 << 16,
+ .additive = 1,
+ .min = 300,
+ .max = 4000,
+};
+
+static void drives_fan_tick(void)
+{
+ s32 temp;
+ int speed;
+ int err;
+
+ if (!drives_fan || !drives_temp || !drives_tick)
+ return;
+ if (--drives_tick > 0)
+ return;
+ drives_tick = drives_pid.param.interval;
+
+ DBG_LOTS("* drives fans tick\n");
+
+ /* Update fan speed from actual fans */
+ err = wf_control_get(drives_fan, &speed);
+ if (!err)
+ drives_pid.target = speed;
+
+ err = wf_sensor_get(drives_temp, &temp);
+ if (err) {
+ pr_warning("wf_pm72: drive bay temp sensor error %d\n", err);
+ failure_state |= FAILURE_SENSOR;
+ wf_control_set_max(drives_fan);
+ return;
+ }
+ speed = wf_pid_run(&drives_pid, temp);
+
+ DBG_LOTS("drives PID temp=%d.%.3d speed=%d\n",
+ FIX32TOPRINT(temp), speed);
+
+ err = wf_control_set(drives_fan, speed);
+ if (err) {
+ printk(KERN_WARNING "windfarm: drive bay fan error %d\n", err);
+ failure_state |= FAILURE_FAN;
+ }
+}
+
+static void drives_setup_pid(void)
+{
+ /* first time initialize things */
+ s32 fmin = wf_control_get_min(drives_fan);
+ s32 fmax = wf_control_get_max(drives_fan);
+ struct wf_pid_param param = drives_param;
+
+ param.min = max(param.min, fmin);
+ param.max = min(param.max, fmax);
+ wf_pid_init(&drives_pid, &param);
+ drives_tick = 1;
+
+ pr_info("wf_pm72: Drive bay control loop started.\n");
+}
+
+static void set_fail_state(void)
+{
+ cpu_max_all_fans();
+
+ if (backside_fan)
+ wf_control_set_max(backside_fan);
+ if (slots_fan)
+ wf_control_set_max(slots_fan);
+ if (drives_fan)
+ wf_control_set_max(drives_fan);
+}
+
+static void pm72_tick(void)
+{
+ int i, last_failure;
+
+ if (!started) {
+ started = 1;
+ printk(KERN_INFO "windfarm: CPUs control loops started.\n");
+ for (i = 0; i < nr_chips; ++i) {
+ if (cpu_setup_pid(i) < 0) {
+ failure_state = FAILURE_PERM;
+ set_fail_state();
+ break;
+ }
+ }
+ DBG_LOTS("cpu_all_tmax=%d.%03d\n", FIX32TOPRINT(cpu_all_tmax));
+
+ backside_setup_pid();
+ drives_setup_pid();
+
+ /*
+ * We don't have the right stuff to drive the PCI fan
+ * so we fix it to a default value
+ */
+ wf_control_set(slots_fan, SLOTS_FAN_DEFAULT_PWM);
+
+#ifdef HACKED_OVERTEMP
+ cpu_all_tmax = 60 << 16;
+#endif
+ }
+
+ /* Permanent failure, bail out */
+ if (failure_state & FAILURE_PERM)
+ return;
+
+ /*
+ * Clear all failure bits except low overtemp which will be eventually
+ * cleared by the control loop itself
+ */
+ last_failure = failure_state;
+ failure_state &= FAILURE_LOW_OVERTEMP;
+ if (cpu_pid_combined)
+ cpu_fans_tick_combined();
+ else
+ cpu_fans_tick_split();
+ backside_fan_tick();
+ drives_fan_tick();
+
+ DBG_LOTS(" last_failure: 0x%x, failure_state: %x\n",
+ last_failure, failure_state);
+
+ /* Check for failures. Any failure causes cpufreq clamping */
+ if (failure_state && last_failure == 0 && cpufreq_clamp)
+ wf_control_set_max(cpufreq_clamp);
+ if (failure_state == 0 && last_failure && cpufreq_clamp)
+ wf_control_set_min(cpufreq_clamp);
+
+ /* That's it for now, we might want to deal with other failures
+ * differently in the future though
+ */
+}
+
+static void pm72_new_control(struct wf_control *ct)
+{
+ bool all_controls;
+ bool had_pump = cpu_pumps[0] || cpu_pumps[1];
+
+ if (!strcmp(ct->name, "cpu-front-fan-0"))
+ cpu_front_fans[0] = ct;
+ else if (!strcmp(ct->name, "cpu-front-fan-1"))
+ cpu_front_fans[1] = ct;
+ else if (!strcmp(ct->name, "cpu-rear-fan-0"))
+ cpu_rear_fans[0] = ct;
+ else if (!strcmp(ct->name, "cpu-rear-fan-1"))
+ cpu_rear_fans[1] = ct;
+ else if (!strcmp(ct->name, "cpu-pump-0"))
+ cpu_pumps[0] = ct;
+ else if (!strcmp(ct->name, "cpu-pump-1"))
+ cpu_pumps[1] = ct;
+ else if (!strcmp(ct->name, "backside-fan"))
+ backside_fan = ct;
+ else if (!strcmp(ct->name, "slots-fan"))
+ slots_fan = ct;
+ else if (!strcmp(ct->name, "drive-bay-fan"))
+ drives_fan = ct;
+ else if (!strcmp(ct->name, "cpufreq-clamp"))
+ cpufreq_clamp = ct;
+
+ all_controls =
+ cpu_front_fans[0] &&
+ cpu_rear_fans[0] &&
+ backside_fan &&
+ slots_fan &&
+ drives_fan;
+ if (nr_chips > 1)
+ all_controls &=
+ cpu_front_fans[1] &&
+ cpu_rear_fans[1];
+ have_all_controls = all_controls;
+
+ if ((cpu_pumps[0] || cpu_pumps[1]) && !had_pump) {
+ pr_info("wf_pm72: Liquid cooling pump(s) detected,"
+ " using new algorithm !\n");
+ cpu_pid_combined = true;
+ }
+}
+
+
+static void pm72_new_sensor(struct wf_sensor *sr)
+{
+ bool all_sensors;
+
+ if (!strcmp(sr->name, "cpu-diode-temp-0"))
+ sens_cpu_temp[0] = sr;
+ else if (!strcmp(sr->name, "cpu-diode-temp-1"))
+ sens_cpu_temp[1] = sr;
+ else if (!strcmp(sr->name, "cpu-voltage-0"))
+ sens_cpu_volts[0] = sr;
+ else if (!strcmp(sr->name, "cpu-voltage-1"))
+ sens_cpu_volts[1] = sr;
+ else if (!strcmp(sr->name, "cpu-current-0"))
+ sens_cpu_amps[0] = sr;
+ else if (!strcmp(sr->name, "cpu-current-1"))
+ sens_cpu_amps[1] = sr;
+ else if (!strcmp(sr->name, "backside-temp"))
+ backside_temp = sr;
+ else if (!strcmp(sr->name, "hd-temp"))
+ drives_temp = sr;
+
+ all_sensors =
+ sens_cpu_temp[0] &&
+ sens_cpu_volts[0] &&
+ sens_cpu_amps[0] &&
+ backside_temp &&
+ drives_temp;
+ if (nr_chips > 1)
+ all_sensors &=
+ sens_cpu_temp[1] &&
+ sens_cpu_volts[1] &&
+ sens_cpu_amps[1];
+
+ have_all_sensors = all_sensors;
+}
+
+static int pm72_wf_notify(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ switch (event) {
+ case WF_EVENT_NEW_SENSOR:
+ pm72_new_sensor(data);
+ break;
+ case WF_EVENT_NEW_CONTROL:
+ pm72_new_control(data);
+ break;
+ case WF_EVENT_TICK:
+ if (have_all_controls && have_all_sensors)
+ pm72_tick();
+ }
+ return 0;
+}
+
+static struct notifier_block pm72_events = {
+ .notifier_call = pm72_wf_notify,
+};
+
+static int wf_pm72_probe(struct platform_device *dev)
+{
+ wf_register_client(&pm72_events);
+ return 0;
+}
+
+static int __devexit wf_pm72_remove(struct platform_device *dev)
+{
+ wf_unregister_client(&pm72_events);
+
+ /* should release all sensors and controls */
+ return 0;
+}
+
+static struct platform_driver wf_pm72_driver = {
+ .probe = wf_pm72_probe,
+ .remove = wf_pm72_remove,
+ .driver = {
+ .name = "windfarm",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init wf_pm72_init(void)
+{
+ struct device_node *cpu;
+ int i;
+
+ if (!of_machine_is_compatible("PowerMac7,2") &&
+ !of_machine_is_compatible("PowerMac7,3"))
+ return -ENODEV;
+
+ /* Count the number of CPU cores */
+ nr_chips = 0;
+ for (cpu = NULL; (cpu = of_find_node_by_type(cpu, "cpu")) != NULL; )
+ ++nr_chips;
+ if (nr_chips > NR_CHIPS)
+ nr_chips = NR_CHIPS;
+
+ pr_info("windfarm: Initializing for desktop G5 with %d chips\n",
+ nr_chips);
+
+ /* Get MPU data for each CPU */
+ for (i = 0; i < nr_chips; i++) {
+ cpu_mpu_data[i] = wf_get_mpu(i);
+ if (!cpu_mpu_data[i]) {
+ pr_err("wf_pm72: Failed to find MPU data for CPU %d\n", i);
+ return -ENXIO;
+ }
+ }
+
+#ifdef MODULE
+ request_module("windfarm_fcu_controls");
+ request_module("windfarm_lm75_sensor");
+ request_module("windfarm_ad7417_sensor");
+ request_module("windfarm_max6690_sensor");
+ request_module("windfarm_cpufreq_clamp");
+#endif /* MODULE */
+
+ platform_driver_register(&wf_pm72_driver);
+ return 0;
+}
+
+static void __exit wf_pm72_exit(void)
+{
+ platform_driver_unregister(&wf_pm72_driver);
+}
+
+module_init(wf_pm72_init);
+module_exit(wf_pm72_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("Thermal control for AGP PowerMac G5s");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:windfarm");
diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c
index fc13d0f2663b..990c87606be9 100644
--- a/drivers/macintosh/windfarm_pm81.c
+++ b/drivers/macintosh/windfarm_pm81.c
@@ -302,13 +302,13 @@ static void wf_smu_create_sys_fans(void)
pid_param.interval = WF_SMU_SYS_FANS_INTERVAL;
pid_param.history_len = WF_SMU_SYS_FANS_HISTORY_SIZE;
pid_param.itarget = param->itarget;
- pid_param.min = fan_system->ops->get_min(fan_system);
- pid_param.max = fan_system->ops->get_max(fan_system);
+ pid_param.min = wf_control_get_min(fan_system);
+ pid_param.max = wf_control_get_max(fan_system);
if (fan_hd) {
pid_param.min =
- max(pid_param.min,fan_hd->ops->get_min(fan_hd));
+ max(pid_param.min, wf_control_get_min(fan_hd));
pid_param.max =
- min(pid_param.max,fan_hd->ops->get_max(fan_hd));
+ min(pid_param.max, wf_control_get_max(fan_hd));
}
wf_pid_init(&wf_smu_sys_fans->pid, &pid_param);
@@ -337,7 +337,7 @@ static void wf_smu_sys_fans_tick(struct wf_smu_sys_fans_state *st)
}
st->ticks = WF_SMU_SYS_FANS_INTERVAL;
- rc = sensor_hd_temp->ops->get_value(sensor_hd_temp, &temp);
+ rc = wf_sensor_get(sensor_hd_temp, &temp);
if (rc) {
printk(KERN_WARNING "windfarm: HD temp sensor error %d\n",
rc);
@@ -373,7 +373,7 @@ static void wf_smu_sys_fans_tick(struct wf_smu_sys_fans_state *st)
st->hd_setpoint = new_setpoint;
readjust:
if (fan_system && wf_smu_failure_state == 0) {
- rc = fan_system->ops->set_value(fan_system, st->sys_setpoint);
+ rc = wf_control_set(fan_system, st->sys_setpoint);
if (rc) {
printk(KERN_WARNING "windfarm: Sys fan error %d\n",
rc);
@@ -381,7 +381,7 @@ static void wf_smu_sys_fans_tick(struct wf_smu_sys_fans_state *st)
}
}
if (fan_hd && wf_smu_failure_state == 0) {
- rc = fan_hd->ops->set_value(fan_hd, st->hd_setpoint);
+ rc = wf_control_set(fan_hd, st->hd_setpoint);
if (rc) {
printk(KERN_WARNING "windfarm: HD fan error %d\n",
rc);
@@ -447,8 +447,8 @@ static void wf_smu_create_cpu_fans(void)
pid_param.ttarget = tmax - tdelta;
pid_param.pmaxadj = maxpow - powadj;
- pid_param.min = fan_cpu_main->ops->get_min(fan_cpu_main);
- pid_param.max = fan_cpu_main->ops->get_max(fan_cpu_main);
+ pid_param.min = wf_control_get_min(fan_cpu_main);
+ pid_param.max = wf_control_get_max(fan_cpu_main);
wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param);
@@ -481,7 +481,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
}
st->ticks = WF_SMU_CPU_FANS_INTERVAL;
- rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp);
+ rc = wf_sensor_get(sensor_cpu_temp, &temp);
if (rc) {
printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n",
rc);
@@ -489,7 +489,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
return;
}
- rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power);
+ rc = wf_sensor_get(sensor_cpu_power, &power);
if (rc) {
printk(KERN_WARNING "windfarm: CPU power sensor error %d\n",
rc);
@@ -525,8 +525,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
st->cpu_setpoint = new_setpoint;
readjust:
if (fan_cpu_main && wf_smu_failure_state == 0) {
- rc = fan_cpu_main->ops->set_value(fan_cpu_main,
- st->cpu_setpoint);
+ rc = wf_control_set(fan_cpu_main, st->cpu_setpoint);
if (rc) {
printk(KERN_WARNING "windfarm: CPU main fan"
" error %d\n", rc);
diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c
index a9430ed4f36c..7653603cb00e 100644
--- a/drivers/macintosh/windfarm_pm91.c
+++ b/drivers/macintosh/windfarm_pm91.c
@@ -192,8 +192,8 @@ static void wf_smu_create_cpu_fans(void)
pid_param.ttarget = tmax - tdelta;
pid_param.pmaxadj = maxpow - powadj;
- pid_param.min = fan_cpu_main->ops->get_min(fan_cpu_main);
- pid_param.max = fan_cpu_main->ops->get_max(fan_cpu_main);
+ pid_param.min = wf_control_get_min(fan_cpu_main);
+ pid_param.max = wf_control_get_max(fan_cpu_main);
wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param);
@@ -226,7 +226,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
}
st->ticks = WF_SMU_CPU_FANS_INTERVAL;
- rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp);
+ rc = wf_sensor_get(sensor_cpu_temp, &temp);
if (rc) {
printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n",
rc);
@@ -234,7 +234,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
return;
}
- rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power);
+ rc = wf_sensor_get(sensor_cpu_power, &power);
if (rc) {
printk(KERN_WARNING "windfarm: CPU power sensor error %d\n",
rc);
@@ -261,8 +261,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
st->cpu_setpoint = new_setpoint;
readjust:
if (fan_cpu_main && wf_smu_failure_state == 0) {
- rc = fan_cpu_main->ops->set_value(fan_cpu_main,
- st->cpu_setpoint);
+ rc = wf_control_set(fan_cpu_main, st->cpu_setpoint);
if (rc) {
printk(KERN_WARNING "windfarm: CPU main fan"
" error %d\n", rc);
@@ -270,8 +269,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
}
}
if (fan_cpu_second && wf_smu_failure_state == 0) {
- rc = fan_cpu_second->ops->set_value(fan_cpu_second,
- st->cpu_setpoint);
+ rc = wf_control_set(fan_cpu_second, st->cpu_setpoint);
if (rc) {
printk(KERN_WARNING "windfarm: CPU second fan"
" error %d\n", rc);
@@ -279,8 +277,7 @@ static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
}
}
if (fan_cpu_third && wf_smu_failure_state == 0) {
- rc = fan_cpu_main->ops->set_value(fan_cpu_third,
- st->cpu_setpoint);
+ rc = wf_control_set(fan_cpu_third, st->cpu_setpoint);
if (rc) {
printk(KERN_WARNING "windfarm: CPU third fan"
" error %d\n", rc);
@@ -312,8 +309,8 @@ static void wf_smu_create_drive_fans(void)
/* Fill PID params */
param.additive = (fan_hd->type == WF_CONTROL_RPM_FAN);
- param.min = fan_hd->ops->get_min(fan_hd);
- param.max = fan_hd->ops->get_max(fan_hd);
+ param.min = wf_control_get_min(fan_hd);
+ param.max = wf_control_get_max(fan_hd);
wf_pid_init(&wf_smu_drive_fans->pid, &param);
DBG("wf: Drive Fan control initialized.\n");
@@ -338,7 +335,7 @@ static void wf_smu_drive_fans_tick(struct wf_smu_drive_fans_state *st)
}
st->ticks = st->pid.param.interval;
- rc = sensor_hd_temp->ops->get_value(sensor_hd_temp, &temp);
+ rc = wf_sensor_get(sensor_hd_temp, &temp);
if (rc) {
printk(KERN_WARNING "windfarm: HD temp sensor error %d\n",
rc);
@@ -361,7 +358,7 @@ static void wf_smu_drive_fans_tick(struct wf_smu_drive_fans_state *st)
st->setpoint = new_setpoint;
readjust:
if (fan_hd && wf_smu_failure_state == 0) {
- rc = fan_hd->ops->set_value(fan_hd, st->setpoint);
+ rc = wf_control_set(fan_hd, st->setpoint);
if (rc) {
printk(KERN_WARNING "windfarm: HD fan error %d\n",
rc);
@@ -393,8 +390,8 @@ static void wf_smu_create_slots_fans(void)
/* Fill PID params */
param.additive = (fan_slots->type == WF_CONTROL_RPM_FAN);
- param.min = fan_slots->ops->get_min(fan_slots);
- param.max = fan_slots->ops->get_max(fan_slots);
+ param.min = wf_control_get_min(fan_slots);
+ param.max = wf_control_get_max(fan_slots);
wf_pid_init(&wf_smu_slots_fans->pid, &param);
DBG("wf: Slots Fan control initialized.\n");
@@ -419,7 +416,7 @@ static void wf_smu_slots_fans_tick(struct wf_smu_slots_fans_state *st)
}
st->ticks = st->pid.param.interval;
- rc = sensor_slots_power->ops->get_value(sensor_slots_power, &power);
+ rc = wf_sensor_get(sensor_slots_power, &power);
if (rc) {
printk(KERN_WARNING "windfarm: Slots power sensor error %d\n",
rc);
@@ -444,7 +441,7 @@ static void wf_smu_slots_fans_tick(struct wf_smu_slots_fans_state *st)
st->setpoint = new_setpoint;
readjust:
if (fan_slots && wf_smu_failure_state == 0) {
- rc = fan_slots->ops->set_value(fan_slots, st->setpoint);
+ rc = wf_control_set(fan_slots, st->setpoint);
if (rc) {
printk(KERN_WARNING "windfarm: Slots fan error %d\n",
rc);
diff --git a/drivers/macintosh/windfarm_rm31.c b/drivers/macintosh/windfarm_rm31.c
new file mode 100644
index 000000000000..3eca6d4b52fc
--- /dev/null
+++ b/drivers/macintosh/windfarm_rm31.c
@@ -0,0 +1,740 @@
+/*
+ * Windfarm PowerMac thermal control.
+ * Control loops for RackMack3,1 (Xserve G5)
+ *
+ * Copyright (C) 2012 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * Use and redistribute under the terms of the GNU GPL v2.
+ */
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <asm/prom.h>
+#include <asm/smu.h>
+
+#include "windfarm.h"
+#include "windfarm_pid.h"
+#include "windfarm_mpu.h"
+
+#define VERSION "1.0"
+
+#undef DEBUG
+#undef LOTSA_DEBUG
+
+#ifdef DEBUG
+#define DBG(args...) printk(args)
+#else
+#define DBG(args...) do { } while(0)
+#endif
+
+#ifdef LOTSA_DEBUG
+#define DBG_LOTS(args...) printk(args)
+#else
+#define DBG_LOTS(args...) do { } while(0)
+#endif
+
+/* define this to force CPU overtemp to 60 degree, useful for testing
+ * the overtemp code
+ */
+#undef HACKED_OVERTEMP
+
+/* We currently only handle 2 chips */
+#define NR_CHIPS 2
+#define NR_CPU_FANS 3 * NR_CHIPS
+
+/* Controls and sensors */
+static struct wf_sensor *sens_cpu_temp[NR_CHIPS];
+static struct wf_sensor *sens_cpu_volts[NR_CHIPS];
+static struct wf_sensor *sens_cpu_amps[NR_CHIPS];
+static struct wf_sensor *backside_temp;
+static struct wf_sensor *slots_temp;
+static struct wf_sensor *dimms_temp;
+
+static struct wf_control *cpu_fans[NR_CHIPS][3];
+static struct wf_control *backside_fan;
+static struct wf_control *slots_fan;
+static struct wf_control *cpufreq_clamp;
+
+/* We keep a temperature history for average calculation of 180s */
+#define CPU_TEMP_HIST_SIZE 180
+
+/* PID loop state */
+static const struct mpu_data *cpu_mpu_data[NR_CHIPS];
+static struct wf_cpu_pid_state cpu_pid[NR_CHIPS];
+static u32 cpu_thist[CPU_TEMP_HIST_SIZE];
+static int cpu_thist_pt;
+static s64 cpu_thist_total;
+static s32 cpu_all_tmax = 100 << 16;
+static struct wf_pid_state backside_pid;
+static int backside_tick;
+static struct wf_pid_state slots_pid;
+static int slots_tick;
+static int slots_speed;
+static struct wf_pid_state dimms_pid;
+static int dimms_output_clamp;
+
+static int nr_chips;
+static bool have_all_controls;
+static bool have_all_sensors;
+static bool started;
+
+static int failure_state;
+#define FAILURE_SENSOR 1
+#define FAILURE_FAN 2
+#define FAILURE_PERM 4
+#define FAILURE_LOW_OVERTEMP 8
+#define FAILURE_HIGH_OVERTEMP 16
+
+/* Overtemp values */
+#define LOW_OVER_AVERAGE 0
+#define LOW_OVER_IMMEDIATE (10 << 16)
+#define LOW_OVER_CLEAR ((-10) << 16)
+#define HIGH_OVER_IMMEDIATE (14 << 16)
+#define HIGH_OVER_AVERAGE (10 << 16)
+#define HIGH_OVER_IMMEDIATE (14 << 16)
+
+
+static void cpu_max_all_fans(void)
+{
+ int i;
+
+ /* We max all CPU fans in case of a sensor error. We also do the
+ * cpufreq clamping now, even if it's supposedly done later by the
+ * generic code anyway, we do it earlier here to react faster
+ */
+ if (cpufreq_clamp)
+ wf_control_set_max(cpufreq_clamp);
+ for (i = 0; i < nr_chips; i++) {
+ if (cpu_fans[i][0])
+ wf_control_set_max(cpu_fans[i][0]);
+ if (cpu_fans[i][1])
+ wf_control_set_max(cpu_fans[i][1]);
+ if (cpu_fans[i][2])
+ wf_control_set_max(cpu_fans[i][2]);
+ }
+}
+
+static int cpu_check_overtemp(s32 temp)
+{
+ int new_state = 0;
+ s32 t_avg, t_old;
+ static bool first = true;
+
+ /* First check for immediate overtemps */
+ if (temp >= (cpu_all_tmax + LOW_OVER_IMMEDIATE)) {
+ new_state |= FAILURE_LOW_OVERTEMP;
+ if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
+ printk(KERN_ERR "windfarm: Overtemp due to immediate CPU"
+ " temperature !\n");
+ }
+ if (temp >= (cpu_all_tmax + HIGH_OVER_IMMEDIATE)) {
+ new_state |= FAILURE_HIGH_OVERTEMP;
+ if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
+ printk(KERN_ERR "windfarm: Critical overtemp due to"
+ " immediate CPU temperature !\n");
+ }
+
+ /*
+ * The first time around, initialize the array with the first
+ * temperature reading
+ */
+ if (first) {
+ int i;
+
+ cpu_thist_total = 0;
+ for (i = 0; i < CPU_TEMP_HIST_SIZE; i++) {
+ cpu_thist[i] = temp;
+ cpu_thist_total += temp;
+ }
+ first = false;
+ }
+
+ /*
+ * We calculate a history of max temperatures and use that for the
+ * overtemp management
+ */
+ t_old = cpu_thist[cpu_thist_pt];
+ cpu_thist[cpu_thist_pt] = temp;
+ cpu_thist_pt = (cpu_thist_pt + 1) % CPU_TEMP_HIST_SIZE;
+ cpu_thist_total -= t_old;
+ cpu_thist_total += temp;
+ t_avg = cpu_thist_total / CPU_TEMP_HIST_SIZE;
+
+ DBG_LOTS(" t_avg = %d.%03d (out: %d.%03d, in: %d.%03d)\n",
+ FIX32TOPRINT(t_avg), FIX32TOPRINT(t_old), FIX32TOPRINT(temp));
+
+ /* Now check for average overtemps */
+ if (t_avg >= (cpu_all_tmax + LOW_OVER_AVERAGE)) {
+ new_state |= FAILURE_LOW_OVERTEMP;
+ if ((failure_state & FAILURE_LOW_OVERTEMP) == 0)
+ printk(KERN_ERR "windfarm: Overtemp due to average CPU"
+ " temperature !\n");
+ }
+ if (t_avg >= (cpu_all_tmax + HIGH_OVER_AVERAGE)) {
+ new_state |= FAILURE_HIGH_OVERTEMP;
+ if ((failure_state & FAILURE_HIGH_OVERTEMP) == 0)
+ printk(KERN_ERR "windfarm: Critical overtemp due to"
+ " average CPU temperature !\n");
+ }
+
+ /* Now handle overtemp conditions. We don't currently use the windfarm
+ * overtemp handling core as it's not fully suited to the needs of those
+ * new machine. This will be fixed later.
+ */
+ if (new_state) {
+ /* High overtemp -> immediate shutdown */
+ if (new_state & FAILURE_HIGH_OVERTEMP)
+ machine_power_off();
+ if ((failure_state & new_state) != new_state)
+ cpu_max_all_fans();
+ failure_state |= new_state;
+ } else if ((failure_state & FAILURE_LOW_OVERTEMP) &&
+ (temp < (cpu_all_tmax + LOW_OVER_CLEAR))) {
+ printk(KERN_ERR "windfarm: Overtemp condition cleared !\n");
+ failure_state &= ~FAILURE_LOW_OVERTEMP;
+ }
+
+ return failure_state & (FAILURE_LOW_OVERTEMP | FAILURE_HIGH_OVERTEMP);
+}
+
+static int read_one_cpu_vals(int cpu, s32 *temp, s32 *power)
+{
+ s32 dtemp, volts, amps;
+ int rc;
+
+ /* Get diode temperature */
+ rc = wf_sensor_get(sens_cpu_temp[cpu], &dtemp);
+ if (rc) {
+ DBG(" CPU%d: temp reading error !\n", cpu);
+ return -EIO;
+ }
+ DBG_LOTS(" CPU%d: temp = %d.%03d\n", cpu, FIX32TOPRINT((dtemp)));
+ *temp = dtemp;
+
+ /* Get voltage */
+ rc = wf_sensor_get(sens_cpu_volts[cpu], &volts);
+ if (rc) {
+ DBG(" CPU%d, volts reading error !\n", cpu);
+ return -EIO;
+ }
+ DBG_LOTS(" CPU%d: volts = %d.%03d\n", cpu, FIX32TOPRINT((volts)));
+
+ /* Get current */
+ rc = wf_sensor_get(sens_cpu_amps[cpu], &amps);
+ if (rc) {
+ DBG(" CPU%d, current reading error !\n", cpu);
+ return -EIO;
+ }
+ DBG_LOTS(" CPU%d: amps = %d.%03d\n", cpu, FIX32TOPRINT((amps)));
+
+ /* Calculate power */
+
+ /* Scale voltage and current raw sensor values according to fixed scales
+ * obtained in Darwin and calculate power from I and V
+ */
+ *power = (((u64)volts) * ((u64)amps)) >> 16;
+
+ DBG_LOTS(" CPU%d: power = %d.%03d\n", cpu, FIX32TOPRINT((*power)));
+
+ return 0;
+
+}
+
+static void cpu_fans_tick(void)
+{
+ int err, cpu, i;
+ s32 speed, temp, power, t_max = 0;
+
+ DBG_LOTS("* cpu fans_tick_split()\n");
+
+ for (cpu = 0; cpu < nr_chips; ++cpu) {
+ struct wf_cpu_pid_state *sp = &cpu_pid[cpu];
+
+ /* Read current speed */
+ wf_control_get(cpu_fans[cpu][0], &sp->target);
+
+ err = read_one_cpu_vals(cpu, &temp, &power);
+ if (err) {
+ failure_state |= FAILURE_SENSOR;
+ cpu_max_all_fans();
+ return;
+ }
+
+ /* Keep track of highest temp */
+ t_max = max(t_max, temp);
+
+ /* Handle possible overtemps */
+ if (cpu_check_overtemp(t_max))
+ return;
+
+ /* Run PID */
+ wf_cpu_pid_run(sp, power, temp);
+
+ DBG_LOTS(" CPU%d: target = %d RPM\n", cpu, sp->target);
+
+ /* Apply DIMMs clamp */
+ speed = max(sp->target, dimms_output_clamp);
+
+ /* Apply result to all cpu fans */
+ for (i = 0; i < 3; i++) {
+ err = wf_control_set(cpu_fans[cpu][i], speed);
+ if (err) {
+ pr_warning("wf_rm31: Fan %s reports error %d\n",
+ cpu_fans[cpu][i]->name, err);
+ failure_state |= FAILURE_FAN;
+ }
+ }
+ }
+}
+
+/* Implementation... */
+static int cpu_setup_pid(int cpu)
+{
+ struct wf_cpu_pid_param pid;
+ const struct mpu_data *mpu = cpu_mpu_data[cpu];
+ s32 tmax, ttarget, ptarget;
+ int fmin, fmax, hsize;
+
+ /* Get PID params from the appropriate MPU EEPROM */
+ tmax = mpu->tmax << 16;
+ ttarget = mpu->ttarget << 16;
+ ptarget = ((s32)(mpu->pmaxh - mpu->padjmax)) << 16;
+
+ DBG("wf_72: CPU%d ttarget = %d.%03d, tmax = %d.%03d\n",
+ cpu, FIX32TOPRINT(ttarget), FIX32TOPRINT(tmax));
+
+ /* We keep a global tmax for overtemp calculations */
+ if (tmax < cpu_all_tmax)
+ cpu_all_tmax = tmax;
+
+ /* Set PID min/max by using the rear fan min/max */
+ fmin = wf_control_get_min(cpu_fans[cpu][0]);
+ fmax = wf_control_get_max(cpu_fans[cpu][0]);
+ DBG("wf_72: CPU%d max RPM range = [%d..%d]\n", cpu, fmin, fmax);
+
+ /* History size */
+ hsize = min_t(int, mpu->tguardband, WF_PID_MAX_HISTORY);
+ DBG("wf_72: CPU%d history size = %d\n", cpu, hsize);
+
+ /* Initialize PID loop */
+ pid.interval = 1; /* seconds */
+ pid.history_len = hsize;
+ pid.gd = mpu->pid_gd;
+ pid.gp = mpu->pid_gp;
+ pid.gr = mpu->pid_gr;
+ pid.tmax = tmax;
+ pid.ttarget = ttarget;
+ pid.pmaxadj = ptarget;
+ pid.min = fmin;
+ pid.max = fmax;
+
+ wf_cpu_pid_init(&cpu_pid[cpu], &pid);
+ cpu_pid[cpu].target = 4000;
+
+ return 0;
+}
+
+/* Backside/U3 fan */
+static struct wf_pid_param backside_param = {
+ .interval = 1,
+ .history_len = 2,
+ .gd = 0x00500000,
+ .gp = 0x0004cccc,
+ .gr = 0,
+ .itarget = 70 << 16,
+ .additive = 0,
+ .min = 20,
+ .max = 100,
+};
+
+/* DIMMs temperature (clamp the backside fan) */
+static struct wf_pid_param dimms_param = {
+ .interval = 1,
+ .history_len = 20,
+ .gd = 0,
+ .gp = 0,
+ .gr = 0x06553600,
+ .itarget = 50 << 16,
+ .additive = 0,
+ .min = 4000,
+ .max = 14000,
+};
+
+static void backside_fan_tick(void)
+{
+ s32 temp, dtemp;
+ int speed, dspeed, fan_min;
+ int err;
+
+ if (!backside_fan || !backside_temp || !dimms_temp || !backside_tick)
+ return;
+ if (--backside_tick > 0)
+ return;
+ backside_tick = backside_pid.param.interval;
+
+ DBG_LOTS("* backside fans tick\n");
+
+ /* Update fan speed from actual fans */
+ err = wf_control_get(backside_fan, &speed);
+ if (!err)
+ backside_pid.target = speed;
+
+ err = wf_sensor_get(backside_temp, &temp);
+ if (err) {
+ printk(KERN_WARNING "windfarm: U3 temp sensor error %d\n",
+ err);
+ failure_state |= FAILURE_SENSOR;
+ wf_control_set_max(backside_fan);
+ return;
+ }
+ speed = wf_pid_run(&backside_pid, temp);
+
+ DBG_LOTS("backside PID temp=%d.%.3d speed=%d\n",
+ FIX32TOPRINT(temp), speed);
+
+ err = wf_sensor_get(dimms_temp, &dtemp);
+ if (err) {
+ printk(KERN_WARNING "windfarm: DIMMs temp sensor error %d\n",
+ err);
+ failure_state |= FAILURE_SENSOR;
+ wf_control_set_max(backside_fan);
+ return;
+ }
+ dspeed = wf_pid_run(&dimms_pid, dtemp);
+ dimms_output_clamp = dspeed;
+
+ fan_min = (dspeed * 100) / 14000;
+ fan_min = max(fan_min, backside_param.min);
+ speed = max(speed, fan_min);
+
+ err = wf_control_set(backside_fan, speed);
+ if (err) {
+ printk(KERN_WARNING "windfarm: backside fan error %d\n", err);
+ failure_state |= FAILURE_FAN;
+ }
+}
+
+static void backside_setup_pid(void)
+{
+ /* first time initialize things */
+ s32 fmin = wf_control_get_min(backside_fan);
+ s32 fmax = wf_control_get_max(backside_fan);
+ struct wf_pid_param param;
+
+ param = backside_param;
+ param.min = max(param.min, fmin);
+ param.max = min(param.max, fmax);
+ wf_pid_init(&backside_pid, &param);
+
+ param = dimms_param;
+ wf_pid_init(&dimms_pid, &param);
+
+ backside_tick = 1;
+
+ pr_info("wf_rm31: Backside control loop started.\n");
+}
+
+/* Slots fan */
+static const struct wf_pid_param slots_param = {
+ .interval = 5,
+ .history_len = 2,
+ .gd = 30 << 20,
+ .gp = 5 << 20,
+ .gr = 0,
+ .itarget = 40 << 16,
+ .additive = 1,
+ .min = 300,
+ .max = 4000,
+};
+
+static void slots_fan_tick(void)
+{
+ s32 temp;
+ int speed;
+ int err;
+
+ if (!slots_fan || !slots_temp || !slots_tick)
+ return;
+ if (--slots_tick > 0)
+ return;
+ slots_tick = slots_pid.param.interval;
+
+ DBG_LOTS("* slots fans tick\n");
+
+ err = wf_sensor_get(slots_temp, &temp);
+ if (err) {
+ pr_warning("wf_rm31: slots temp sensor error %d\n", err);
+ failure_state |= FAILURE_SENSOR;
+ wf_control_set_max(slots_fan);
+ return;
+ }
+ speed = wf_pid_run(&slots_pid, temp);
+
+ DBG_LOTS("slots PID temp=%d.%.3d speed=%d\n",
+ FIX32TOPRINT(temp), speed);
+
+ slots_speed = speed;
+ err = wf_control_set(slots_fan, speed);
+ if (err) {
+ printk(KERN_WARNING "windfarm: slots bay fan error %d\n", err);
+ failure_state |= FAILURE_FAN;
+ }
+}
+
+static void slots_setup_pid(void)
+{
+ /* first time initialize things */
+ s32 fmin = wf_control_get_min(slots_fan);
+ s32 fmax = wf_control_get_max(slots_fan);
+ struct wf_pid_param param = slots_param;
+
+ param.min = max(param.min, fmin);
+ param.max = min(param.max, fmax);
+ wf_pid_init(&slots_pid, &param);
+ slots_tick = 1;
+
+ pr_info("wf_rm31: Slots control loop started.\n");
+}
+
+static void set_fail_state(void)
+{
+ cpu_max_all_fans();
+
+ if (backside_fan)
+ wf_control_set_max(backside_fan);
+ if (slots_fan)
+ wf_control_set_max(slots_fan);
+}
+
+static void rm31_tick(void)
+{
+ int i, last_failure;
+
+ if (!started) {
+ started = 1;
+ printk(KERN_INFO "windfarm: CPUs control loops started.\n");
+ for (i = 0; i < nr_chips; ++i) {
+ if (cpu_setup_pid(i) < 0) {
+ failure_state = FAILURE_PERM;
+ set_fail_state();
+ break;
+ }
+ }
+ DBG_LOTS("cpu_all_tmax=%d.%03d\n", FIX32TOPRINT(cpu_all_tmax));
+
+ backside_setup_pid();
+ slots_setup_pid();
+
+#ifdef HACKED_OVERTEMP
+ cpu_all_tmax = 60 << 16;
+#endif
+ }
+
+ /* Permanent failure, bail out */
+ if (failure_state & FAILURE_PERM)
+ return;
+
+ /*
+ * Clear all failure bits except low overtemp which will be eventually
+ * cleared by the control loop itself
+ */
+ last_failure = failure_state;
+ failure_state &= FAILURE_LOW_OVERTEMP;
+ backside_fan_tick();
+ slots_fan_tick();
+
+ /* We do CPUs last because they can be clamped high by
+ * DIMM temperature
+ */
+ cpu_fans_tick();
+
+ DBG_LOTS(" last_failure: 0x%x, failure_state: %x\n",
+ last_failure, failure_state);
+
+ /* Check for failures. Any failure causes cpufreq clamping */
+ if (failure_state && last_failure == 0 && cpufreq_clamp)
+ wf_control_set_max(cpufreq_clamp);
+ if (failure_state == 0 && last_failure && cpufreq_clamp)
+ wf_control_set_min(cpufreq_clamp);
+
+ /* That's it for now, we might want to deal with other failures
+ * differently in the future though
+ */
+}
+
+static void rm31_new_control(struct wf_control *ct)
+{
+ bool all_controls;
+
+ if (!strcmp(ct->name, "cpu-fan-a-0"))
+ cpu_fans[0][0] = ct;
+ else if (!strcmp(ct->name, "cpu-fan-b-0"))
+ cpu_fans[0][1] = ct;
+ else if (!strcmp(ct->name, "cpu-fan-c-0"))
+ cpu_fans[0][2] = ct;
+ else if (!strcmp(ct->name, "cpu-fan-a-1"))
+ cpu_fans[1][0] = ct;
+ else if (!strcmp(ct->name, "cpu-fan-b-1"))
+ cpu_fans[1][1] = ct;
+ else if (!strcmp(ct->name, "cpu-fan-c-1"))
+ cpu_fans[1][2] = ct;
+ else if (!strcmp(ct->name, "backside-fan"))
+ backside_fan = ct;
+ else if (!strcmp(ct->name, "slots-fan"))
+ slots_fan = ct;
+ else if (!strcmp(ct->name, "cpufreq-clamp"))
+ cpufreq_clamp = ct;
+
+ all_controls =
+ cpu_fans[0][0] &&
+ cpu_fans[0][1] &&
+ cpu_fans[0][2] &&
+ backside_fan &&
+ slots_fan;
+ if (nr_chips > 1)
+ all_controls &=
+ cpu_fans[1][0] &&
+ cpu_fans[1][1] &&
+ cpu_fans[1][2];
+ have_all_controls = all_controls;
+}
+
+
+static void rm31_new_sensor(struct wf_sensor *sr)
+{
+ bool all_sensors;
+
+ if (!strcmp(sr->name, "cpu-diode-temp-0"))
+ sens_cpu_temp[0] = sr;
+ else if (!strcmp(sr->name, "cpu-diode-temp-1"))
+ sens_cpu_temp[1] = sr;
+ else if (!strcmp(sr->name, "cpu-voltage-0"))
+ sens_cpu_volts[0] = sr;
+ else if (!strcmp(sr->name, "cpu-voltage-1"))
+ sens_cpu_volts[1] = sr;
+ else if (!strcmp(sr->name, "cpu-current-0"))
+ sens_cpu_amps[0] = sr;
+ else if (!strcmp(sr->name, "cpu-current-1"))
+ sens_cpu_amps[1] = sr;
+ else if (!strcmp(sr->name, "backside-temp"))
+ backside_temp = sr;
+ else if (!strcmp(sr->name, "slots-temp"))
+ slots_temp = sr;
+ else if (!strcmp(sr->name, "dimms-temp"))
+ dimms_temp = sr;
+
+ all_sensors =
+ sens_cpu_temp[0] &&
+ sens_cpu_volts[0] &&
+ sens_cpu_amps[0] &&
+ backside_temp &&
+ slots_temp &&
+ dimms_temp;
+ if (nr_chips > 1)
+ all_sensors &=
+ sens_cpu_temp[1] &&
+ sens_cpu_volts[1] &&
+ sens_cpu_amps[1];
+
+ have_all_sensors = all_sensors;
+}
+
+static int rm31_wf_notify(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ switch (event) {
+ case WF_EVENT_NEW_SENSOR:
+ rm31_new_sensor(data);
+ break;
+ case WF_EVENT_NEW_CONTROL:
+ rm31_new_control(data);
+ break;
+ case WF_EVENT_TICK:
+ if (have_all_controls && have_all_sensors)
+ rm31_tick();
+ }
+ return 0;
+}
+
+static struct notifier_block rm31_events = {
+ .notifier_call = rm31_wf_notify,
+};
+
+static int wf_rm31_probe(struct platform_device *dev)
+{
+ wf_register_client(&rm31_events);
+ return 0;
+}
+
+static int __devexit wf_rm31_remove(struct platform_device *dev)
+{
+ wf_unregister_client(&rm31_events);
+
+ /* should release all sensors and controls */
+ return 0;
+}
+
+static struct platform_driver wf_rm31_driver = {
+ .probe = wf_rm31_probe,
+ .remove = wf_rm31_remove,
+ .driver = {
+ .name = "windfarm",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init wf_rm31_init(void)
+{
+ struct device_node *cpu;
+ int i;
+
+ if (!of_machine_is_compatible("RackMac3,1"))
+ return -ENODEV;
+
+ /* Count the number of CPU cores */
+ nr_chips = 0;
+ for (cpu = NULL; (cpu = of_find_node_by_type(cpu, "cpu")) != NULL; )
+ ++nr_chips;
+ if (nr_chips > NR_CHIPS)
+ nr_chips = NR_CHIPS;
+
+ pr_info("windfarm: Initializing for desktop G5 with %d chips\n",
+ nr_chips);
+
+ /* Get MPU data for each CPU */
+ for (i = 0; i < nr_chips; i++) {
+ cpu_mpu_data[i] = wf_get_mpu(i);
+ if (!cpu_mpu_data[i]) {
+ pr_err("wf_rm31: Failed to find MPU data for CPU %d\n", i);
+ return -ENXIO;
+ }
+ }
+
+#ifdef MODULE
+ request_module("windfarm_fcu_controls");
+ request_module("windfarm_lm75_sensor");
+ request_module("windfarm_lm87_sensor");
+ request_module("windfarm_ad7417_sensor");
+ request_module("windfarm_max6690_sensor");
+ request_module("windfarm_cpufreq_clamp");
+#endif /* MODULE */
+
+ platform_driver_register(&wf_rm31_driver);
+ return 0;
+}
+
+static void __exit wf_rm31_exit(void)
+{
+ platform_driver_unregister(&wf_rm31_driver);
+}
+
+module_init(wf_rm31_init);
+module_exit(wf_rm31_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("Thermal control for Xserve G5");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:windfarm");
diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c
index 3c2be5193fd5..c155a54e8638 100644
--- a/drivers/macintosh/windfarm_smu_controls.c
+++ b/drivers/macintosh/windfarm_smu_controls.c
@@ -172,7 +172,6 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node,
fct->fan_type = pwm_fan;
fct->ctrl.type = pwm_fan ? WF_CONTROL_PWM_FAN : WF_CONTROL_RPM_FAN;
- sysfs_attr_init(&fct->ctrl.attr.attr);
/* We use the name & location here the same way we do for SMU sensors,
* see the comment in windfarm_smu_sensors.c. The locations are a bit
diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c
index 65a8ff3e1f8e..426e810233d7 100644
--- a/drivers/macintosh/windfarm_smu_sat.c
+++ b/drivers/macintosh/windfarm_smu_sat.c
@@ -20,7 +20,7 @@
#include "windfarm.h"
-#define VERSION "0.2"
+#define VERSION "1.0"
#define DEBUG
@@ -34,11 +34,12 @@
#define MAX_AGE msecs_to_jiffies(800)
struct wf_sat {
+ struct kref ref;
int nr;
- atomic_t refcnt;
struct mutex mutex;
unsigned long last_read; /* jiffies when cache last updated */
u8 cache[16];
+ struct list_head sensors;
struct i2c_client *i2c;
struct device_node *node;
};
@@ -46,11 +47,12 @@ struct wf_sat {
static struct wf_sat *sats[2];
struct wf_sat_sensor {
- int index;
- int index2; /* used for power sensors */
- int shift;
- struct wf_sat *sat;
- struct wf_sensor sens;
+ struct list_head link;
+ int index;
+ int index2; /* used for power sensors */
+ int shift;
+ struct wf_sat *sat;
+ struct wf_sensor sens;
};
#define wf_to_sat(c) container_of(c, struct wf_sat_sensor, sens)
@@ -142,7 +144,7 @@ static int wf_sat_read_cache(struct wf_sat *sat)
return 0;
}
-static int wf_sat_get(struct wf_sensor *sr, s32 *value)
+static int wf_sat_sensor_get(struct wf_sensor *sr, s32 *value)
{
struct wf_sat_sensor *sens = wf_to_sat(sr);
struct wf_sat *sat = sens->sat;
@@ -175,62 +177,34 @@ static int wf_sat_get(struct wf_sensor *sr, s32 *value)
return err;
}
-static void wf_sat_release(struct wf_sensor *sr)
+static void wf_sat_release(struct kref *ref)
+{
+ struct wf_sat *sat = container_of(ref, struct wf_sat, ref);
+
+ if (sat->nr >= 0)
+ sats[sat->nr] = NULL;
+ kfree(sat);
+}
+
+static void wf_sat_sensor_release(struct wf_sensor *sr)
{
struct wf_sat_sensor *sens = wf_to_sat(sr);
struct wf_sat *sat = sens->sat;
- if (atomic_dec_and_test(&sat->refcnt)) {
- if (sat->nr >= 0)
- sats[sat->nr] = NULL;
- kfree(sat);
- }
kfree(sens);
+ kref_put(&sat->ref, wf_sat_release);
}
static struct wf_sensor_ops wf_sat_ops = {
- .get_value = wf_sat_get,
- .release = wf_sat_release,
+ .get_value = wf_sat_sensor_get,
+ .release = wf_sat_sensor_release,
.owner = THIS_MODULE,
};
-static struct i2c_driver wf_sat_driver;
-
-static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev)
-{
- struct i2c_board_info info;
- struct i2c_client *client;
- const u32 *reg;
- u8 addr;
-
- reg = of_get_property(dev, "reg", NULL);
- if (reg == NULL)
- return;
- addr = *reg;
- DBG(KERN_DEBUG "wf_sat: creating sat at address %x\n", addr);
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = (addr >> 1) & 0x7f;
- info.platform_data = dev;
- strlcpy(info.type, "wf_sat", I2C_NAME_SIZE);
-
- client = i2c_new_device(adapter, &info);
- if (client == NULL) {
- printk(KERN_ERR "windfarm: failed to attach smu-sat to i2c\n");
- return;
- }
-
- /*
- * Let i2c-core delete that device on driver removal.
- * This is safe because i2c-core holds the core_lock mutex for us.
- */
- list_add_tail(&client->detected, &wf_sat_driver.clients);
-}
-
static int wf_sat_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct device_node *dev = client->dev.platform_data;
+ struct device_node *dev = client->dev.of_node;
struct wf_sat *sat;
struct wf_sat_sensor *sens;
const u32 *reg;
@@ -246,9 +220,10 @@ static int wf_sat_probe(struct i2c_client *client,
return -ENOMEM;
sat->nr = -1;
sat->node = of_node_get(dev);
- atomic_set(&sat->refcnt, 0);
+ kref_init(&sat->ref);
mutex_init(&sat->mutex);
sat->i2c = client;
+ INIT_LIST_HEAD(&sat->sensors);
i2c_set_clientdata(client, sat);
vsens[0] = vsens[1] = -1;
@@ -310,14 +285,15 @@ static int wf_sat_probe(struct i2c_client *client,
sens->index2 = -1;
sens->shift = shift;
sens->sat = sat;
- atomic_inc(&sat->refcnt);
sens->sens.ops = &wf_sat_ops;
sens->sens.name = (char *) (sens + 1);
- snprintf(sens->sens.name, 16, "%s-%d", name, cpu);
+ snprintf((char *)sens->sens.name, 16, "%s-%d", name, cpu);
- if (wf_register_sensor(&sens->sens)) {
- atomic_dec(&sat->refcnt);
+ if (wf_register_sensor(&sens->sens))
kfree(sens);
+ else {
+ list_add(&sens->link, &sat->sensors);
+ kref_get(&sat->ref);
}
}
@@ -336,14 +312,15 @@ static int wf_sat_probe(struct i2c_client *client,
sens->index2 = isens[core];
sens->shift = 0;
sens->sat = sat;
- atomic_inc(&sat->refcnt);
sens->sens.ops = &wf_sat_ops;
sens->sens.name = (char *) (sens + 1);
- snprintf(sens->sens.name, 16, "cpu-power-%d", cpu);
+ snprintf((char *)sens->sens.name, 16, "cpu-power-%d", cpu);
- if (wf_register_sensor(&sens->sens)) {
- atomic_dec(&sat->refcnt);
+ if (wf_register_sensor(&sens->sens))
kfree(sens);
+ else {
+ list_add(&sens->link, &sat->sensors);
+ kref_get(&sat->ref);
}
}
@@ -353,42 +330,35 @@ static int wf_sat_probe(struct i2c_client *client,
return 0;
}
-static int wf_sat_attach(struct i2c_adapter *adapter)
-{
- struct device_node *busnode, *dev = NULL;
- struct pmac_i2c_bus *bus;
-
- bus = pmac_i2c_adapter_to_bus(adapter);
- if (bus == NULL)
- return -ENODEV;
- busnode = pmac_i2c_get_bus_node(bus);
-
- while ((dev = of_get_next_child(busnode, dev)) != NULL)
- if (of_device_is_compatible(dev, "smu-sat"))
- wf_sat_create(adapter, dev);
- return 0;
-}
-
static int wf_sat_remove(struct i2c_client *client)
{
struct wf_sat *sat = i2c_get_clientdata(client);
+ struct wf_sat_sensor *sens;
- /* XXX TODO */
-
+ /* release sensors */
+ while(!list_empty(&sat->sensors)) {
+ sens = list_first_entry(&sat->sensors,
+ struct wf_sat_sensor, link);
+ list_del(&sens->link);
+ wf_unregister_sensor(&sens->sens);
+ }
sat->i2c = NULL;
+ i2c_set_clientdata(client, NULL);
+ kref_put(&sat->ref, wf_sat_release);
+
return 0;
}
static const struct i2c_device_id wf_sat_id[] = {
- { "wf_sat", 0 },
+ { "MAC,smu-sat", 0 },
{ }
};
+MODULE_DEVICE_TABLE(i2c, wf_sat_id);
static struct i2c_driver wf_sat_driver = {
.driver = {
.name = "wf_smu_sat",
},
- .attach_adapter = wf_sat_attach,
.probe = wf_sat_probe,
.remove = wf_sat_remove,
.id_table = wf_sat_id,
@@ -399,15 +369,13 @@ static int __init sat_sensors_init(void)
return i2c_add_driver(&wf_sat_driver);
}
-#if 0 /* uncomment when module_exit() below is uncommented */
static void __exit sat_sensors_exit(void)
{
i2c_del_driver(&wf_sat_driver);
}
-#endif
module_init(sat_sensors_init);
-/*module_exit(sat_sensors_exit); Uncomment when cleanup is implemented */
+module_exit(sat_sensors_exit);
MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");
MODULE_DESCRIPTION("SMU satellite sensors for PowerMac thermal control");
diff --git a/drivers/mca/Kconfig b/drivers/mca/Kconfig
deleted file mode 100644
index a7a0220ab4bd..000000000000
--- a/drivers/mca/Kconfig
+++ /dev/null
@@ -1,14 +0,0 @@
-config MCA_LEGACY
- bool "Legacy MCA API Support"
- depends on MCA
- help
- This compiles in support for the old slot based MCA API. If you
- have an unconverted MCA driver, you will need to say Y here. It
- is safe to say Y anyway.
-
-config MCA_PROC_FS
- bool "Support for the mca entry in /proc"
- depends on MCA_LEGACY && PROC_FS
- help
- If you want the old style /proc/mca directory in addition to the
- new style sysfs say Y here.
diff --git a/drivers/mca/Makefile b/drivers/mca/Makefile
deleted file mode 100644
index 0794b122520e..000000000000
--- a/drivers/mca/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# Makefile for the Linux MCA bus support
-
-obj-y := mca-bus.o mca-device.o mca-driver.o
-
-obj-$(CONFIG_MCA_PROC_FS) += mca-proc.o
-obj-$(CONFIG_MCA_LEGACY) += mca-legacy.o
-
diff --git a/drivers/mca/mca-bus.c b/drivers/mca/mca-bus.c
deleted file mode 100644
index ada5ebbaa255..000000000000
--- a/drivers/mca/mca-bus.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8 -*- */
-
-/*
- * MCA bus support functions for sysfs.
- *
- * (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.com>
- *
-**-----------------------------------------------------------------------------
-**
-** This program is free software; you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation; either version 2 of the License, or
-** (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-**
-**-----------------------------------------------------------------------------
- */
-
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/mca.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-
-/* Very few machines have more than one MCA bus. However, there are
- * those that do (Voyager 35xx/5xxx), so we do it this way for future
- * expansion. None that I know have more than 2 */
-static struct mca_bus *mca_root_busses[MAX_MCA_BUSSES];
-
-#define MCA_DEVINFO(i,s) { .pos = i, .name = s }
-
-struct mca_device_info {
- short pos_id; /* the 2 byte pos id for this card */
- char name[50];
-};
-
-static int mca_bus_match (struct device *dev, struct device_driver *drv)
-{
- struct mca_device *mca_dev = to_mca_device (dev);
- struct mca_driver *mca_drv = to_mca_driver (drv);
- const unsigned short *mca_ids = mca_drv->id_table;
- int i = 0;
-
- if (mca_ids) {
- for(i = 0; mca_ids[i]; i++) {
- if (mca_ids[i] == mca_dev->pos_id) {
- mca_dev->index = i;
- return 1;
- }
- }
- }
- /* If the integrated id is present, treat it as though it were an
- * additional id in the id_table (it can't be because by definition,
- * integrated id's overflow a short */
- if (mca_drv->integrated_id && mca_dev->pos_id ==
- mca_drv->integrated_id) {
- mca_dev->index = i;
- return 1;
- }
- return 0;
-}
-
-struct bus_type mca_bus_type = {
- .name = "MCA",
- .match = mca_bus_match,
-};
-EXPORT_SYMBOL (mca_bus_type);
-
-static ssize_t mca_show_pos_id(struct device *dev, struct device_attribute *attr, char *buf)
-{
- /* four digits, \n and trailing \0 */
- struct mca_device *mca_dev = to_mca_device(dev);
- int len;
-
- if(mca_dev->pos_id < MCA_DUMMY_POS_START)
- len = sprintf(buf, "%04x\n", mca_dev->pos_id);
- else
- len = sprintf(buf, "none\n");
- return len;
-}
-static ssize_t mca_show_pos(struct device *dev, struct device_attribute *attr, char *buf)
-{
- /* enough for 8 two byte hex chars plus space and new line */
- int j, len=0;
- struct mca_device *mca_dev = to_mca_device(dev);
-
- for(j=0; j<8; j++)
- len += sprintf(buf+len, "%02x ", mca_dev->pos[j]);
- /* change last trailing space to new line */
- buf[len-1] = '\n';
- return len;
-}
-
-static DEVICE_ATTR(id, S_IRUGO, mca_show_pos_id, NULL);
-static DEVICE_ATTR(pos, S_IRUGO, mca_show_pos, NULL);
-
-int __init mca_register_device(int bus, struct mca_device *mca_dev)
-{
- struct mca_bus *mca_bus = mca_root_busses[bus];
- int rc;
-
- mca_dev->dev.parent = &mca_bus->dev;
- mca_dev->dev.bus = &mca_bus_type;
- dev_set_name(&mca_dev->dev, "%02d:%02X", bus, mca_dev->slot);
- mca_dev->dma_mask = mca_bus->default_dma_mask;
- mca_dev->dev.dma_mask = &mca_dev->dma_mask;
- mca_dev->dev.coherent_dma_mask = mca_dev->dma_mask;
-
- rc = device_register(&mca_dev->dev);
- if (rc)
- goto err_out;
-
- rc = device_create_file(&mca_dev->dev, &dev_attr_id);
- if (rc) goto err_out_devreg;
- rc = device_create_file(&mca_dev->dev, &dev_attr_pos);
- if (rc) goto err_out_id;
-
- return 1;
-
-err_out_id:
- device_remove_file(&mca_dev->dev, &dev_attr_id);
-err_out_devreg:
- device_unregister(&mca_dev->dev);
-err_out:
- return 0;
-}
-
-/* */
-struct mca_bus * __devinit mca_attach_bus(int bus)
-{
- struct mca_bus *mca_bus;
-
- if (unlikely(mca_root_busses[bus] != NULL)) {
- /* This should never happen, but just in case */
- printk(KERN_EMERG "MCA tried to add already existing bus %d\n",
- bus);
- dump_stack();
- return NULL;
- }
-
- mca_bus = kzalloc(sizeof(struct mca_bus), GFP_KERNEL);
- if (!mca_bus)
- return NULL;
-
- dev_set_name(&mca_bus->dev, "mca%d", bus);
- sprintf(mca_bus->name,"Host %s MCA Bridge", bus ? "Secondary" : "Primary");
- if (device_register(&mca_bus->dev)) {
- kfree(mca_bus);
- return NULL;
- }
-
- mca_root_busses[bus] = mca_bus;
-
- return mca_bus;
-}
-
-int __init mca_system_init (void)
-{
- return bus_register(&mca_bus_type);
-}
diff --git a/drivers/mca/mca-device.c b/drivers/mca/mca-device.c
deleted file mode 100644
index e7adf89fae41..000000000000
--- a/drivers/mca/mca-device.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8 -*- */
-
-/*
- * MCA device support functions
- *
- * These functions support the ongoing device access API.
- *
- * (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.com>
- *
-**-----------------------------------------------------------------------------
-**
-** This program is free software; you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation; either version 2 of the License, or
-** (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-**
-**-----------------------------------------------------------------------------
- */
-
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/mca.h>
-#include <linux/string.h>
-
-/**
- * mca_device_read_stored_pos - read POS register from stored data
- * @mca_dev: device to read from
- * @reg: register to read from
- *
- * Fetch a POS value that was stored at boot time by the kernel
- * when it scanned the MCA space. The register value is returned.
- * Missing or invalid registers report 0.
- */
-unsigned char mca_device_read_stored_pos(struct mca_device *mca_dev, int reg)
-{
- if(reg < 0 || reg >= 8)
- return 0;
-
- return mca_dev->pos[reg];
-}
-EXPORT_SYMBOL(mca_device_read_stored_pos);
-
-/**
- * mca_device_read_pos - read POS register from card
- * @mca_dev: device to read from
- * @reg: register to read from
- *
- * Fetch a POS value directly from the hardware to obtain the
- * current value. This is much slower than
- * mca_device_read_stored_pos and may not be invoked from
- * interrupt context. It handles the deep magic required for
- * onboard devices transparently.
- */
-unsigned char mca_device_read_pos(struct mca_device *mca_dev, int reg)
-{
- struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
-
- return mca_bus->f.mca_read_pos(mca_dev, reg);
-
- return mca_dev->pos[reg];
-}
-EXPORT_SYMBOL(mca_device_read_pos);
-
-
-/**
- * mca_device_write_pos - read POS register from card
- * @mca_dev: device to write pos register to
- * @reg: register to write to
- * @byte: byte to write to the POS registers
- *
- * Store a POS value directly to the hardware. You should not
- * normally need to use this function and should have a very good
- * knowledge of MCA bus before you do so. Doing this wrongly can
- * damage the hardware.
- *
- * This function may not be used from interrupt context.
- *
- */
-void mca_device_write_pos(struct mca_device *mca_dev, int reg,
- unsigned char byte)
-{
- struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
-
- mca_bus->f.mca_write_pos(mca_dev, reg, byte);
-}
-EXPORT_SYMBOL(mca_device_write_pos);
-
-/**
- * mca_device_transform_irq - transform the ADF obtained IRQ
- * @mca_device: device whose irq needs transforming
- * @irq: input irq from ADF
- *
- * MCA Adapter Definition Files (ADF) contain irq, ioport, memory
- * etc. definitions. In systems with more than one bus, these need
- * to be transformed through bus mapping functions to get the real
- * system global quantities.
- *
- * This function transforms the interrupt number and returns the
- * transformed system global interrupt
- */
-int mca_device_transform_irq(struct mca_device *mca_dev, int irq)
-{
- struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
-
- return mca_bus->f.mca_transform_irq(mca_dev, irq);
-}
-EXPORT_SYMBOL(mca_device_transform_irq);
-
-/**
- * mca_device_transform_ioport - transform the ADF obtained I/O port
- * @mca_device: device whose port needs transforming
- * @ioport: input I/O port from ADF
- *
- * MCA Adapter Definition Files (ADF) contain irq, ioport, memory
- * etc. definitions. In systems with more than one bus, these need
- * to be transformed through bus mapping functions to get the real
- * system global quantities.
- *
- * This function transforms the I/O port number and returns the
- * transformed system global port number.
- *
- * This transformation can be assumed to be linear for port ranges.
- */
-int mca_device_transform_ioport(struct mca_device *mca_dev, int port)
-{
- struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
-
- return mca_bus->f.mca_transform_ioport(mca_dev, port);
-}
-EXPORT_SYMBOL(mca_device_transform_ioport);
-
-/**
- * mca_device_transform_memory - transform the ADF obtained memory
- * @mca_device: device whose memory region needs transforming
- * @mem: memory region start from ADF
- *
- * MCA Adapter Definition Files (ADF) contain irq, ioport, memory
- * etc. definitions. In systems with more than one bus, these need
- * to be transformed through bus mapping functions to get the real
- * system global quantities.
- *
- * This function transforms the memory region start and returns the
- * transformed system global memory region (physical).
- *
- * This transformation can be assumed to be linear for region ranges.
- */
-void *mca_device_transform_memory(struct mca_device *mca_dev, void *mem)
-{
- struct mca_bus *mca_bus = to_mca_bus(mca_dev->dev.parent);
-
- return mca_bus->f.mca_transform_memory(mca_dev, mem);
-}
-EXPORT_SYMBOL(mca_device_transform_memory);
-
-
-/**
- * mca_device_claimed - check if claimed by driver
- * @mca_dev: device to check
- *
- * Returns 1 if the slot has been claimed by a driver
- */
-
-int mca_device_claimed(struct mca_device *mca_dev)
-{
- return mca_dev->driver_loaded;
-}
-EXPORT_SYMBOL(mca_device_claimed);
-
-/**
- * mca_device_set_claim - set the claim value of the driver
- * @mca_dev: device to set value for
- * @val: claim value to set (1 claimed, 0 unclaimed)
- */
-void mca_device_set_claim(struct mca_device *mca_dev, int val)
-{
- mca_dev->driver_loaded = val;
-}
-EXPORT_SYMBOL(mca_device_set_claim);
-
-/**
- * mca_device_status - get the status of the device
- * @mca_device: device to get
- *
- * returns an enumeration of the device status:
- *
- * MCA_ADAPTER_NORMAL adapter is OK.
- * MCA_ADAPTER_NONE no adapter at device (should never happen).
- * MCA_ADAPTER_DISABLED adapter is disabled.
- * MCA_ADAPTER_ERROR adapter cannot be initialised.
- */
-enum MCA_AdapterStatus mca_device_status(struct mca_device *mca_dev)
-{
- return mca_dev->status;
-}
-EXPORT_SYMBOL(mca_device_status);
-
-/**
- * mca_device_set_name - set the name of the device
- * @mca_device: device to set the name of
- * @name: name to set
- */
-void mca_device_set_name(struct mca_device *mca_dev, const char *name)
-{
- if(!mca_dev)
- return;
-
- strlcpy(mca_dev->name, name, sizeof(mca_dev->name));
-}
-EXPORT_SYMBOL(mca_device_set_name);
diff --git a/drivers/mca/mca-driver.c b/drivers/mca/mca-driver.c
deleted file mode 100644
index 32cd39bcc715..000000000000
--- a/drivers/mca/mca-driver.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8 -*- */
-
-/*
- * MCA driver support functions for sysfs.
- *
- * (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.com>
- *
-**-----------------------------------------------------------------------------
-**
-** This program is free software; you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation; either version 2 of the License, or
-** (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-**
-**-----------------------------------------------------------------------------
- */
-
-#include <linux/device.h>
-#include <linux/mca.h>
-#include <linux/module.h>
-
-int mca_register_driver(struct mca_driver *mca_drv)
-{
- int r;
-
- if (MCA_bus) {
- mca_drv->driver.bus = &mca_bus_type;
- if ((r = driver_register(&mca_drv->driver)) < 0)
- return r;
- mca_drv->integrated_id = 0;
- }
-
- return 0;
-}
-EXPORT_SYMBOL(mca_register_driver);
-
-int mca_register_driver_integrated(struct mca_driver *mca_driver,
- int integrated_id)
-{
- int r = mca_register_driver(mca_driver);
-
- if (!r)
- mca_driver->integrated_id = integrated_id;
-
- return r;
-}
-EXPORT_SYMBOL(mca_register_driver_integrated);
-
-void mca_unregister_driver(struct mca_driver *mca_drv)
-{
- if (MCA_bus)
- driver_unregister(&mca_drv->driver);
-}
-EXPORT_SYMBOL(mca_unregister_driver);
diff --git a/drivers/mca/mca-legacy.c b/drivers/mca/mca-legacy.c
deleted file mode 100644
index 494f0c2001f5..000000000000
--- a/drivers/mca/mca-legacy.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8 -*- */
-
-/*
- * MCA bus support functions for legacy (2.4) API.
- *
- * Legacy API means the API that operates in terms of MCA slot number
- *
- * (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.com>
- *
-**-----------------------------------------------------------------------------
-**
-** This program is free software; you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation; either version 2 of the License, or
-** (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-**
-**-----------------------------------------------------------------------------
- */
-
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/mca-legacy.h>
-#include <asm/io.h>
-
-/* NOTE: This structure is stack allocated */
-struct mca_find_adapter_info {
- int id;
- int slot;
- struct mca_device *mca_dev;
-};
-
-/* The purpose of this iterator is to loop over all the devices and
- * find the one with the smallest slot number that's just greater than
- * or equal to the required slot with a matching id */
-static int mca_find_adapter_callback(struct device *dev, void *data)
-{
- struct mca_find_adapter_info *info = data;
- struct mca_device *mca_dev = to_mca_device(dev);
-
- if(mca_dev->pos_id != info->id)
- return 0;
-
- if(mca_dev->slot < info->slot)
- return 0;
-
- if(!info->mca_dev || info->mca_dev->slot >= mca_dev->slot)
- info->mca_dev = mca_dev;
-
- return 0;
-}
-
-/**
- * mca_find_adapter - scan for adapters
- * @id: MCA identification to search for
- * @start: starting slot
- *
- * Search the MCA configuration for adapters matching the 16bit
- * ID given. The first time it should be called with start as zero
- * and then further calls made passing the return value of the
- * previous call until %MCA_NOTFOUND is returned.
- *
- * Disabled adapters are not reported.
- */
-
-int mca_find_adapter(int id, int start)
-{
- struct mca_find_adapter_info info;
-
- if(id == 0xffff)
- return MCA_NOTFOUND;
-
- info.slot = start;
- info.id = id;
- info.mca_dev = NULL;
-
- for(;;) {
- bus_for_each_dev(&mca_bus_type, NULL, &info, mca_find_adapter_callback);
-
- if(info.mca_dev == NULL)
- return MCA_NOTFOUND;
-
- if(info.mca_dev->status != MCA_ADAPTER_DISABLED)
- break;
-
- /* OK, found adapter but it was disabled. Go around
- * again, excluding the slot we just found */
-
- info.slot = info.mca_dev->slot + 1;
- info.mca_dev = NULL;
- }
-
- return info.mca_dev->slot;
-}
-EXPORT_SYMBOL(mca_find_adapter);
-
-/*--------------------------------------------------------------------*/
-
-/**
- * mca_find_unused_adapter - scan for unused adapters
- * @id: MCA identification to search for
- * @start: starting slot
- *
- * Search the MCA configuration for adapters matching the 16bit
- * ID given. The first time it should be called with start as zero
- * and then further calls made passing the return value of the
- * previous call until %MCA_NOTFOUND is returned.
- *
- * Adapters that have been claimed by drivers and those that
- * are disabled are not reported. This function thus allows a driver
- * to scan for further cards when some may already be driven.
- */
-
-int mca_find_unused_adapter(int id, int start)
-{
- struct mca_find_adapter_info info = { 0 };
-
- if (!MCA_bus || id == 0xffff)
- return MCA_NOTFOUND;
-
- info.slot = start;
- info.id = id;
- info.mca_dev = NULL;
-
- for(;;) {
- bus_for_each_dev(&mca_bus_type, NULL, &info, mca_find_adapter_callback);
-
- if(info.mca_dev == NULL)
- return MCA_NOTFOUND;
-
- if(info.mca_dev->status != MCA_ADAPTER_DISABLED
- && !info.mca_dev->driver_loaded)
- break;
-
- /* OK, found adapter but it was disabled or already in
- * use. Go around again, excluding the slot we just
- * found */
-
- info.slot = info.mca_dev->slot + 1;
- info.mca_dev = NULL;
- }
-
- return info.mca_dev->slot;
-}
-EXPORT_SYMBOL(mca_find_unused_adapter);
-
-/* NOTE: stack allocated structure */
-struct mca_find_device_by_slot_info {
- int slot;
- struct mca_device *mca_dev;
-};
-
-static int mca_find_device_by_slot_callback(struct device *dev, void *data)
-{
- struct mca_find_device_by_slot_info *info = data;
- struct mca_device *mca_dev = to_mca_device(dev);
-
- if(mca_dev->slot == info->slot)
- info->mca_dev = mca_dev;
-
- return 0;
-}
-
-struct mca_device *mca_find_device_by_slot(int slot)
-{
- struct mca_find_device_by_slot_info info;
-
- info.slot = slot;
- info.mca_dev = NULL;
-
- bus_for_each_dev(&mca_bus_type, NULL, &info, mca_find_device_by_slot_callback);
-
- return info.mca_dev;
-}
-
-/**
- * mca_read_stored_pos - read POS register from boot data
- * @slot: slot number to read from
- * @reg: register to read from
- *
- * Fetch a POS value that was stored at boot time by the kernel
- * when it scanned the MCA space. The register value is returned.
- * Missing or invalid registers report 0.
- */
-unsigned char mca_read_stored_pos(int slot, int reg)
-{
- struct mca_device *mca_dev = mca_find_device_by_slot(slot);
-
- if(!mca_dev)
- return 0;
-
- return mca_device_read_stored_pos(mca_dev, reg);
-}
-EXPORT_SYMBOL(mca_read_stored_pos);
-
-
-/**
- * mca_read_pos - read POS register from card
- * @slot: slot number to read from
- * @reg: register to read from
- *
- * Fetch a POS value directly from the hardware to obtain the
- * current value. This is much slower than mca_read_stored_pos and
- * may not be invoked from interrupt context. It handles the
- * deep magic required for onboard devices transparently.
- */
-
-unsigned char mca_read_pos(int slot, int reg)
-{
- struct mca_device *mca_dev = mca_find_device_by_slot(slot);
-
- if(!mca_dev)
- return 0;
-
- return mca_device_read_pos(mca_dev, reg);
-}
-EXPORT_SYMBOL(mca_read_pos);
-
-
-/**
- * mca_write_pos - read POS register from card
- * @slot: slot number to read from
- * @reg: register to read from
- * @byte: byte to write to the POS registers
- *
- * Store a POS value directly from the hardware. You should not
- * normally need to use this function and should have a very good
- * knowledge of MCA bus before you do so. Doing this wrongly can
- * damage the hardware.
- *
- * This function may not be used from interrupt context.
- *
- * Note that this a technically a Bad Thing, as IBM tech stuff says
- * you should only set POS values through their utilities.
- * However, some devices such as the 3c523 recommend that you write
- * back some data to make sure the configuration is consistent.
- * I'd say that IBM is right, but I like my drivers to work.
- *
- * This function can't do checks to see if multiple devices end up
- * with the same resources, so you might see magic smoke if someone
- * screws up.
- */
-
-void mca_write_pos(int slot, int reg, unsigned char byte)
-{
- struct mca_device *mca_dev = mca_find_device_by_slot(slot);
-
- if(!mca_dev)
- return;
-
- mca_device_write_pos(mca_dev, reg, byte);
-}
-EXPORT_SYMBOL(mca_write_pos);
-
-/**
- * mca_set_adapter_name - Set the description of the card
- * @slot: slot to name
- * @name: text string for the namen
- *
- * This function sets the name reported via /proc for this
- * adapter slot. This is for user information only. Setting a
- * name deletes any previous name.
- */
-
-void mca_set_adapter_name(int slot, char* name)
-{
- struct mca_device *mca_dev = mca_find_device_by_slot(slot);
-
- if(!mca_dev)
- return;
-
- mca_device_set_name(mca_dev, name);
-}
-EXPORT_SYMBOL(mca_set_adapter_name);
-
-/**
- * mca_mark_as_used - claim an MCA device
- * @slot: slot to claim
- * FIXME: should we make this threadsafe
- *
- * Claim an MCA slot for a device driver. If the
- * slot is already taken the function returns 1,
- * if it is not taken it is claimed and 0 is
- * returned.
- */
-
-int mca_mark_as_used(int slot)
-{
- struct mca_device *mca_dev = mca_find_device_by_slot(slot);
-
- if(!mca_dev)
- /* FIXME: this is actually a severe error */
- return 1;
-
- if(mca_device_claimed(mca_dev))
- return 1;
-
- mca_device_set_claim(mca_dev, 1);
-
- return 0;
-}
-EXPORT_SYMBOL(mca_mark_as_used);
-
-/**
- * mca_mark_as_unused - release an MCA device
- * @slot: slot to claim
- *
- * Release the slot for other drives to use.
- */
-
-void mca_mark_as_unused(int slot)
-{
- struct mca_device *mca_dev = mca_find_device_by_slot(slot);
-
- if(!mca_dev)
- return;
-
- mca_device_set_claim(mca_dev, 0);
-}
-EXPORT_SYMBOL(mca_mark_as_unused);
-
diff --git a/drivers/mca/mca-proc.c b/drivers/mca/mca-proc.c
deleted file mode 100644
index 81ea0d377bf4..000000000000
--- a/drivers/mca/mca-proc.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8 -*- */
-
-/*
- * MCA bus support functions for the proc fs.
- *
- * NOTE: this code *requires* the legacy MCA api.
- *
- * Legacy API means the API that operates in terms of MCA slot number
- *
- * (C) 2002 James Bottomley <James.Bottomley@HansenPartnership.com>
- *
-**-----------------------------------------------------------------------------
-**
-** This program is free software; you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation; either version 2 of the License, or
-** (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-**
-**-----------------------------------------------------------------------------
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/proc_fs.h>
-#include <linux/mca.h>
-
-static int get_mca_info_helper(struct mca_device *mca_dev, char *page, int len)
-{
- int j;
-
- for(j=0; j<8; j++)
- len += sprintf(page+len, "%02x ",
- mca_dev ? mca_dev->pos[j] : 0xff);
- len += sprintf(page+len, " %s\n", mca_dev ? mca_dev->name : "");
- return len;
-}
-
-static int get_mca_info(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int i, len = 0;
-
- if(MCA_bus) {
- struct mca_device *mca_dev;
- /* Format POS registers of eight MCA slots */
-
- for(i=0; i<MCA_MAX_SLOT_NR; i++) {
- mca_dev = mca_find_device_by_slot(i);
-
- len += sprintf(page+len, "Slot %d: ", i+1);
- len = get_mca_info_helper(mca_dev, page, len);
- }
-
- /* Format POS registers of integrated video subsystem */
-
- mca_dev = mca_find_device_by_slot(MCA_INTEGVIDEO);
- len += sprintf(page+len, "Video : ");
- len = get_mca_info_helper(mca_dev, page, len);
-
- /* Format POS registers of integrated SCSI subsystem */
-
- mca_dev = mca_find_device_by_slot(MCA_INTEGSCSI);
- len += sprintf(page+len, "SCSI : ");
- len = get_mca_info_helper(mca_dev, page, len);
-
- /* Format POS registers of motherboard */
-
- mca_dev = mca_find_device_by_slot(MCA_MOTHERBOARD);
- len += sprintf(page+len, "Planar: ");
- len = get_mca_info_helper(mca_dev, page, len);
- } else {
- /* Leave it empty if MCA not detected - this should *never*
- * happen!
- */
- }
-
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
-}
-
-/*--------------------------------------------------------------------*/
-
-static int mca_default_procfn(char* buf, struct mca_device *mca_dev)
-{
- int len = 0, i;
- int slot = mca_dev->slot;
-
- /* Print out the basic information */
-
- if(slot < MCA_MAX_SLOT_NR) {
- len += sprintf(buf+len, "Slot: %d\n", slot+1);
- } else if(slot == MCA_INTEGSCSI) {
- len += sprintf(buf+len, "Integrated SCSI Adapter\n");
- } else if(slot == MCA_INTEGVIDEO) {
- len += sprintf(buf+len, "Integrated Video Adapter\n");
- } else if(slot == MCA_MOTHERBOARD) {
- len += sprintf(buf+len, "Motherboard\n");
- }
- if (mca_dev->name[0]) {
-
- /* Drivers might register a name without /proc handler... */
-
- len += sprintf(buf+len, "Adapter Name: %s\n",
- mca_dev->name);
- } else {
- len += sprintf(buf+len, "Adapter Name: Unknown\n");
- }
- len += sprintf(buf+len, "Id: %02x%02x\n",
- mca_dev->pos[1], mca_dev->pos[0]);
- len += sprintf(buf+len, "Enabled: %s\nPOS: ",
- mca_device_status(mca_dev) == MCA_ADAPTER_NORMAL ?
- "Yes" : "No");
- for(i=0; i<8; i++) {
- len += sprintf(buf+len, "%02x ", mca_dev->pos[i]);
- }
- len += sprintf(buf+len, "\nDriver Installed: %s",
- mca_device_claimed(mca_dev) ? "Yes" : "No");
- buf[len++] = '\n';
- buf[len] = 0;
-
- return len;
-} /* mca_default_procfn() */
-
-static int get_mca_machine_info(char* page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int len = 0;
-
- len += sprintf(page+len, "Model Id: 0x%x\n", machine_id);
- len += sprintf(page+len, "Submodel Id: 0x%x\n", machine_submodel_id);
- len += sprintf(page+len, "BIOS Revision: 0x%x\n", BIOS_revision);
-
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
-}
-
-static int mca_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- struct mca_device *mca_dev = (struct mca_device *)data;
- int len = 0;
-
- /* Get the standard info */
-
- len = mca_default_procfn(page, mca_dev);
-
- /* Do any device-specific processing, if there is any */
-
- if(mca_dev->procfn) {
- len += mca_dev->procfn(page+len, mca_dev->slot,
- mca_dev->proc_dev);
- }
- if (len <= off+count) *eof = 1;
- *start = page + off;
- len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
- return len;
-} /* mca_read_proc() */
-
-/*--------------------------------------------------------------------*/
-
-void __init mca_do_proc_init(void)
-{
- int i;
- struct proc_dir_entry *proc_mca;
- struct proc_dir_entry* node = NULL;
- struct mca_device *mca_dev;
-
- proc_mca = proc_mkdir("mca", NULL);
- create_proc_read_entry("pos",0,proc_mca,get_mca_info,NULL);
- create_proc_read_entry("machine",0,proc_mca,get_mca_machine_info,NULL);
-
- /* Initialize /proc/mca entries for existing adapters */
-
- for(i = 0; i < MCA_NUMADAPTERS; i++) {
- enum MCA_AdapterStatus status;
- mca_dev = mca_find_device_by_slot(i);
- if(!mca_dev)
- continue;
-
- mca_dev->procfn = NULL;
-
- if(i < MCA_MAX_SLOT_NR) sprintf(mca_dev->procname,"slot%d", i+1);
- else if(i == MCA_INTEGVIDEO) sprintf(mca_dev->procname,"video");
- else if(i == MCA_INTEGSCSI) sprintf(mca_dev->procname,"scsi");
- else if(i == MCA_MOTHERBOARD) sprintf(mca_dev->procname,"planar");
-
- status = mca_device_status(mca_dev);
- if (status != MCA_ADAPTER_NORMAL &&
- status != MCA_ADAPTER_DISABLED)
- continue;
-
- node = create_proc_read_entry(mca_dev->procname, 0, proc_mca,
- mca_read_proc, (void *)mca_dev);
-
- if(node == NULL) {
- printk("Failed to allocate memory for MCA proc-entries!");
- return;
- }
- }
-
-} /* mca_do_proc_init() */
-
-/**
- * mca_set_adapter_procfn - Set the /proc callback
- * @slot: slot to configure
- * @procfn: callback function to call for /proc
- * @dev: device information passed to the callback
- *
- * This sets up an information callback for /proc/mca/slot?. The
- * function is called with the buffer, slot, and device pointer (or
- * some equally informative context information, or nothing, if you
- * prefer), and is expected to put useful information into the
- * buffer. The adapter name, ID, and POS registers get printed
- * before this is called though, so don't do it again.
- *
- * This should be called with a %NULL @procfn when a module
- * unregisters, thus preventing kernel crashes and other such
- * nastiness.
- */
-
-void mca_set_adapter_procfn(int slot, MCA_ProcFn procfn, void* proc_dev)
-{
- struct mca_device *mca_dev = mca_find_device_by_slot(slot);
-
- if(!mca_dev)
- return;
-
- mca_dev->procfn = procfn;
- mca_dev->proc_dev = proc_dev;
-}
-EXPORT_SYMBOL(mca_set_adapter_procfn);
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 17e2b472e16d..15dbe03117e4 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -45,7 +45,7 @@ static inline char *bmname(struct bitmap *bitmap)
* if we find our page, we increment the page's refcount so that it stays
* allocated while we're using it
*/
-static int bitmap_checkpage(struct bitmap *bitmap,
+static int bitmap_checkpage(struct bitmap_counts *bitmap,
unsigned long page, int create)
__releases(bitmap->lock)
__acquires(bitmap->lock)
@@ -76,8 +76,7 @@ __acquires(bitmap->lock)
spin_lock_irq(&bitmap->lock);
if (mappage == NULL) {
- pr_debug("%s: bitmap map page allocation failed, hijacking\n",
- bmname(bitmap));
+ pr_debug("md/bitmap: map page allocation failed, hijacking\n");
/* failed - set the hijacked flag so that we can use the
* pointer as a counter */
if (!bitmap->bp[page].map)
@@ -100,7 +99,7 @@ __acquires(bitmap->lock)
/* if page is completely empty, put it back on the free list, or dealloc it */
/* if page was hijacked, unmark the flag so it might get alloced next time */
/* Note: lock should be held when calling this */
-static void bitmap_checkfree(struct bitmap *bitmap, unsigned long page)
+static void bitmap_checkfree(struct bitmap_counts *bitmap, unsigned long page)
{
char *ptr;
@@ -130,22 +129,14 @@ static void bitmap_checkfree(struct bitmap *bitmap, unsigned long page)
*/
/* IO operations when bitmap is stored near all superblocks */
-static struct page *read_sb_page(struct mddev *mddev, loff_t offset,
- struct page *page,
- unsigned long index, int size)
+static int read_sb_page(struct mddev *mddev, loff_t offset,
+ struct page *page,
+ unsigned long index, int size)
{
/* choose a good rdev and read the page from there */
struct md_rdev *rdev;
sector_t target;
- int did_alloc = 0;
-
- if (!page) {
- page = alloc_page(GFP_KERNEL);
- if (!page)
- return ERR_PTR(-ENOMEM);
- did_alloc = 1;
- }
rdev_for_each(rdev, mddev) {
if (! test_bit(In_sync, &rdev->flags)
@@ -158,15 +149,10 @@ static struct page *read_sb_page(struct mddev *mddev, loff_t offset,
roundup(size, bdev_logical_block_size(rdev->bdev)),
page, READ, true)) {
page->index = index;
- attach_page_buffers(page, NULL); /* so that free_buffer will
- * quietly no-op */
- return page;
+ return 0;
}
}
- if (did_alloc)
- put_page(page);
- return ERR_PTR(-EIO);
-
+ return -EIO;
}
static struct md_rdev *next_active_rdev(struct md_rdev *rdev, struct mddev *mddev)
@@ -208,6 +194,7 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
struct md_rdev *rdev = NULL;
struct block_device *bdev;
struct mddev *mddev = bitmap->mddev;
+ struct bitmap_storage *store = &bitmap->storage;
while ((rdev = next_active_rdev(rdev, mddev)) != NULL) {
int size = PAGE_SIZE;
@@ -215,9 +202,13 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
bdev = (rdev->meta_bdev) ? rdev->meta_bdev : rdev->bdev;
- if (page->index == bitmap->file_pages-1)
- size = roundup(bitmap->last_page_size,
+ if (page->index == store->file_pages-1) {
+ int last_page_size = store->bytes & (PAGE_SIZE-1);
+ if (last_page_size == 0)
+ last_page_size = PAGE_SIZE;
+ size = roundup(last_page_size,
bdev_logical_block_size(bdev));
+ }
/* Just make sure we aren't corrupting data or
* metadata
*/
@@ -276,10 +267,10 @@ static void write_page(struct bitmap *bitmap, struct page *page, int wait)
{
struct buffer_head *bh;
- if (bitmap->file == NULL) {
+ if (bitmap->storage.file == NULL) {
switch (write_sb_page(bitmap, page, wait)) {
case -EINVAL:
- bitmap->flags |= BITMAP_WRITE_ERROR;
+ set_bit(BITMAP_WRITE_ERROR, &bitmap->flags);
}
} else {
@@ -297,20 +288,16 @@ static void write_page(struct bitmap *bitmap, struct page *page, int wait)
wait_event(bitmap->write_wait,
atomic_read(&bitmap->pending_writes)==0);
}
- if (bitmap->flags & BITMAP_WRITE_ERROR)
+ if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags))
bitmap_file_kick(bitmap);
}
static void end_bitmap_write(struct buffer_head *bh, int uptodate)
{
struct bitmap *bitmap = bh->b_private;
- unsigned long flags;
- if (!uptodate) {
- spin_lock_irqsave(&bitmap->lock, flags);
- bitmap->flags |= BITMAP_WRITE_ERROR;
- spin_unlock_irqrestore(&bitmap->lock, flags);
- }
+ if (!uptodate)
+ set_bit(BITMAP_WRITE_ERROR, &bitmap->flags);
if (atomic_dec_and_test(&bitmap->pending_writes))
wake_up(&bitmap->write_wait);
}
@@ -325,8 +312,12 @@ __clear_page_buffers(struct page *page)
}
static void free_buffers(struct page *page)
{
- struct buffer_head *bh = page_buffers(page);
+ struct buffer_head *bh;
+ if (!PagePrivate(page))
+ return;
+
+ bh = page_buffers(page);
while (bh) {
struct buffer_head *next = bh->b_this_page;
free_buffer_head(bh);
@@ -343,11 +334,12 @@ static void free_buffers(struct page *page)
* This usage is similar to how swap files are handled, and allows us
* to write to a file with no concerns of memory allocation failing.
*/
-static struct page *read_page(struct file *file, unsigned long index,
- struct bitmap *bitmap,
- unsigned long count)
+static int read_page(struct file *file, unsigned long index,
+ struct bitmap *bitmap,
+ unsigned long count,
+ struct page *page)
{
- struct page *page = NULL;
+ int ret = 0;
struct inode *inode = file->f_path.dentry->d_inode;
struct buffer_head *bh;
sector_t block;
@@ -355,16 +347,9 @@ static struct page *read_page(struct file *file, unsigned long index,
pr_debug("read bitmap file (%dB @ %llu)\n", (int)PAGE_SIZE,
(unsigned long long)index << PAGE_SHIFT);
- page = alloc_page(GFP_KERNEL);
- if (!page)
- page = ERR_PTR(-ENOMEM);
- if (IS_ERR(page))
- goto out;
-
bh = alloc_page_buffers(page, 1<<inode->i_blkbits, 0);
if (!bh) {
- put_page(page);
- page = ERR_PTR(-ENOMEM);
+ ret = -ENOMEM;
goto out;
}
attach_page_buffers(page, bh);
@@ -376,8 +361,7 @@ static struct page *read_page(struct file *file, unsigned long index,
bh->b_blocknr = bmap(inode, block);
if (bh->b_blocknr == 0) {
/* Cannot use this file! */
- free_buffers(page);
- page = ERR_PTR(-EINVAL);
+ ret = -EINVAL;
goto out;
}
bh->b_bdev = inode->i_sb->s_bdev;
@@ -400,17 +384,15 @@ static struct page *read_page(struct file *file, unsigned long index,
wait_event(bitmap->write_wait,
atomic_read(&bitmap->pending_writes)==0);
- if (bitmap->flags & BITMAP_WRITE_ERROR) {
- free_buffers(page);
- page = ERR_PTR(-EIO);
- }
+ if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags))
+ ret = -EIO;
out:
- if (IS_ERR(page))
- printk(KERN_ALERT "md: bitmap read error: (%dB @ %llu): %ld\n",
+ if (ret)
+ printk(KERN_ALERT "md: bitmap read error: (%dB @ %llu): %d\n",
(int)PAGE_SIZE,
(unsigned long long)index << PAGE_SHIFT,
- PTR_ERR(page));
- return page;
+ ret);
+ return ret;
}
/*
@@ -426,9 +408,9 @@ void bitmap_update_sb(struct bitmap *bitmap)
return;
if (bitmap->mddev->bitmap_info.external)
return;
- if (!bitmap->sb_page) /* no superblock */
+ if (!bitmap->storage.sb_page) /* no superblock */
return;
- sb = kmap_atomic(bitmap->sb_page);
+ sb = kmap_atomic(bitmap->storage.sb_page);
sb->events = cpu_to_le64(bitmap->mddev->events);
if (bitmap->mddev->events < bitmap->events_cleared)
/* rocking back to read-only */
@@ -438,8 +420,13 @@ void bitmap_update_sb(struct bitmap *bitmap)
/* Just in case these have been changed via sysfs: */
sb->daemon_sleep = cpu_to_le32(bitmap->mddev->bitmap_info.daemon_sleep/HZ);
sb->write_behind = cpu_to_le32(bitmap->mddev->bitmap_info.max_write_behind);
+ /* This might have been changed by a reshape */
+ sb->sync_size = cpu_to_le64(bitmap->mddev->resync_max_sectors);
+ sb->chunksize = cpu_to_le32(bitmap->mddev->bitmap_info.chunksize);
+ sb->sectors_reserved = cpu_to_le32(bitmap->mddev->
+ bitmap_info.space);
kunmap_atomic(sb);
- write_page(bitmap, bitmap->sb_page, 1);
+ write_page(bitmap, bitmap->storage.sb_page, 1);
}
/* print out the bitmap file superblock */
@@ -447,9 +434,9 @@ void bitmap_print_sb(struct bitmap *bitmap)
{
bitmap_super_t *sb;
- if (!bitmap || !bitmap->sb_page)
+ if (!bitmap || !bitmap->storage.sb_page)
return;
- sb = kmap_atomic(bitmap->sb_page);
+ sb = kmap_atomic(bitmap->storage.sb_page);
printk(KERN_DEBUG "%s: bitmap file superblock:\n", bmname(bitmap));
printk(KERN_DEBUG " magic: %08x\n", le32_to_cpu(sb->magic));
printk(KERN_DEBUG " version: %d\n", le32_to_cpu(sb->version));
@@ -488,15 +475,15 @@ static int bitmap_new_disk_sb(struct bitmap *bitmap)
unsigned long chunksize, daemon_sleep, write_behind;
int err = -EINVAL;
- bitmap->sb_page = alloc_page(GFP_KERNEL);
- if (IS_ERR(bitmap->sb_page)) {
- err = PTR_ERR(bitmap->sb_page);
- bitmap->sb_page = NULL;
+ bitmap->storage.sb_page = alloc_page(GFP_KERNEL);
+ if (IS_ERR(bitmap->storage.sb_page)) {
+ err = PTR_ERR(bitmap->storage.sb_page);
+ bitmap->storage.sb_page = NULL;
return err;
}
- bitmap->sb_page->index = 0;
+ bitmap->storage.sb_page->index = 0;
- sb = kmap_atomic(bitmap->sb_page);
+ sb = kmap_atomic(bitmap->storage.sb_page);
sb->magic = cpu_to_le32(BITMAP_MAGIC);
sb->version = cpu_to_le32(BITMAP_MAJOR_HI);
@@ -534,8 +521,8 @@ static int bitmap_new_disk_sb(struct bitmap *bitmap)
memcpy(sb->uuid, bitmap->mddev->uuid, 16);
- bitmap->flags |= BITMAP_STALE;
- sb->state |= cpu_to_le32(BITMAP_STALE);
+ set_bit(BITMAP_STALE, &bitmap->flags);
+ sb->state = cpu_to_le32(bitmap->flags);
bitmap->events_cleared = bitmap->mddev->events;
sb->events_cleared = cpu_to_le64(bitmap->mddev->events);
@@ -551,31 +538,45 @@ static int bitmap_read_sb(struct bitmap *bitmap)
bitmap_super_t *sb;
unsigned long chunksize, daemon_sleep, write_behind;
unsigned long long events;
+ unsigned long sectors_reserved = 0;
int err = -EINVAL;
+ struct page *sb_page;
+ if (!bitmap->storage.file && !bitmap->mddev->bitmap_info.offset) {
+ chunksize = 128 * 1024 * 1024;
+ daemon_sleep = 5 * HZ;
+ write_behind = 0;
+ set_bit(BITMAP_STALE, &bitmap->flags);
+ err = 0;
+ goto out_no_sb;
+ }
/* page 0 is the superblock, read it... */
- if (bitmap->file) {
- loff_t isize = i_size_read(bitmap->file->f_mapping->host);
+ sb_page = alloc_page(GFP_KERNEL);
+ if (!sb_page)
+ return -ENOMEM;
+ bitmap->storage.sb_page = sb_page;
+
+ if (bitmap->storage.file) {
+ loff_t isize = i_size_read(bitmap->storage.file->f_mapping->host);
int bytes = isize > PAGE_SIZE ? PAGE_SIZE : isize;
- bitmap->sb_page = read_page(bitmap->file, 0, bitmap, bytes);
+ err = read_page(bitmap->storage.file, 0,
+ bitmap, bytes, sb_page);
} else {
- bitmap->sb_page = read_sb_page(bitmap->mddev,
- bitmap->mddev->bitmap_info.offset,
- NULL,
- 0, sizeof(bitmap_super_t));
+ err = read_sb_page(bitmap->mddev,
+ bitmap->mddev->bitmap_info.offset,
+ sb_page,
+ 0, sizeof(bitmap_super_t));
}
- if (IS_ERR(bitmap->sb_page)) {
- err = PTR_ERR(bitmap->sb_page);
- bitmap->sb_page = NULL;
+ if (err)
return err;
- }
- sb = kmap_atomic(bitmap->sb_page);
+ sb = kmap_atomic(sb_page);
chunksize = le32_to_cpu(sb->chunksize);
daemon_sleep = le32_to_cpu(sb->daemon_sleep) * HZ;
write_behind = le32_to_cpu(sb->write_behind);
+ sectors_reserved = le32_to_cpu(sb->sectors_reserved);
/* verify that the bitmap-specific fields are valid */
if (sb->magic != cpu_to_le32(BITMAP_MAGIC))
@@ -618,60 +619,32 @@ static int bitmap_read_sb(struct bitmap *bitmap)
"-- forcing full recovery\n",
bmname(bitmap), events,
(unsigned long long) bitmap->mddev->events);
- sb->state |= cpu_to_le32(BITMAP_STALE);
+ set_bit(BITMAP_STALE, &bitmap->flags);
}
}
/* assign fields using values from superblock */
- bitmap->mddev->bitmap_info.chunksize = chunksize;
- bitmap->mddev->bitmap_info.daemon_sleep = daemon_sleep;
- bitmap->mddev->bitmap_info.max_write_behind = write_behind;
bitmap->flags |= le32_to_cpu(sb->state);
if (le32_to_cpu(sb->version) == BITMAP_MAJOR_HOSTENDIAN)
- bitmap->flags |= BITMAP_HOSTENDIAN;
+ set_bit(BITMAP_HOSTENDIAN, &bitmap->flags);
bitmap->events_cleared = le64_to_cpu(sb->events_cleared);
- if (bitmap->flags & BITMAP_STALE)
- bitmap->events_cleared = bitmap->mddev->events;
err = 0;
out:
kunmap_atomic(sb);
+out_no_sb:
+ if (test_bit(BITMAP_STALE, &bitmap->flags))
+ bitmap->events_cleared = bitmap->mddev->events;
+ bitmap->mddev->bitmap_info.chunksize = chunksize;
+ bitmap->mddev->bitmap_info.daemon_sleep = daemon_sleep;
+ bitmap->mddev->bitmap_info.max_write_behind = write_behind;
+ if (bitmap->mddev->bitmap_info.space == 0 ||
+ bitmap->mddev->bitmap_info.space > sectors_reserved)
+ bitmap->mddev->bitmap_info.space = sectors_reserved;
if (err)
bitmap_print_sb(bitmap);
return err;
}
-enum bitmap_mask_op {
- MASK_SET,
- MASK_UNSET
-};
-
-/* record the state of the bitmap in the superblock. Return the old value */
-static int bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits,
- enum bitmap_mask_op op)
-{
- bitmap_super_t *sb;
- int old;
-
- if (!bitmap->sb_page) /* can't set the state */
- return 0;
- sb = kmap_atomic(bitmap->sb_page);
- old = le32_to_cpu(sb->state) & bits;
- switch (op) {
- case MASK_SET:
- sb->state |= cpu_to_le32(bits);
- bitmap->flags |= bits;
- break;
- case MASK_UNSET:
- sb->state &= cpu_to_le32(~bits);
- bitmap->flags &= ~bits;
- break;
- default:
- BUG();
- }
- kunmap_atomic(sb);
- return old;
-}
-
/*
* general bitmap file operations
*/
@@ -683,17 +656,19 @@ static int bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits,
* file a page at a time. There's a superblock at the start of the file.
*/
/* calculate the index of the page that contains this bit */
-static inline unsigned long file_page_index(struct bitmap *bitmap, unsigned long chunk)
+static inline unsigned long file_page_index(struct bitmap_storage *store,
+ unsigned long chunk)
{
- if (!bitmap->mddev->bitmap_info.external)
+ if (store->sb_page)
chunk += sizeof(bitmap_super_t) << 3;
return chunk >> PAGE_BIT_SHIFT;
}
/* calculate the (bit) offset of this bit within a page */
-static inline unsigned long file_page_offset(struct bitmap *bitmap, unsigned long chunk)
+static inline unsigned long file_page_offset(struct bitmap_storage *store,
+ unsigned long chunk)
{
- if (!bitmap->mddev->bitmap_info.external)
+ if (store->sb_page)
chunk += sizeof(bitmap_super_t) << 3;
return chunk & (PAGE_BITS - 1);
}
@@ -705,57 +680,86 @@ static inline unsigned long file_page_offset(struct bitmap *bitmap, unsigned lon
* 1 page (e.g., x86) or less than 1 page -- so the bitmap might start on page
* 0 or page 1
*/
-static inline struct page *filemap_get_page(struct bitmap *bitmap,
+static inline struct page *filemap_get_page(struct bitmap_storage *store,
unsigned long chunk)
{
- if (file_page_index(bitmap, chunk) >= bitmap->file_pages)
+ if (file_page_index(store, chunk) >= store->file_pages)
return NULL;
- return bitmap->filemap[file_page_index(bitmap, chunk)
- - file_page_index(bitmap, 0)];
+ return store->filemap[file_page_index(store, chunk)
+ - file_page_index(store, 0)];
}
-static void bitmap_file_unmap(struct bitmap *bitmap)
+static int bitmap_storage_alloc(struct bitmap_storage *store,
+ unsigned long chunks, int with_super)
+{
+ int pnum;
+ unsigned long num_pages;
+ unsigned long bytes;
+
+ bytes = DIV_ROUND_UP(chunks, 8);
+ if (with_super)
+ bytes += sizeof(bitmap_super_t);
+
+ num_pages = DIV_ROUND_UP(bytes, PAGE_SIZE);
+
+ store->filemap = kmalloc(sizeof(struct page *)
+ * num_pages, GFP_KERNEL);
+ if (!store->filemap)
+ return -ENOMEM;
+
+ if (with_super && !store->sb_page) {
+ store->sb_page = alloc_page(GFP_KERNEL|__GFP_ZERO);
+ if (store->sb_page == NULL)
+ return -ENOMEM;
+ store->sb_page->index = 0;
+ }
+ pnum = 0;
+ if (store->sb_page) {
+ store->filemap[0] = store->sb_page;
+ pnum = 1;
+ }
+ for ( ; pnum < num_pages; pnum++) {
+ store->filemap[pnum] = alloc_page(GFP_KERNEL|__GFP_ZERO);
+ if (!store->filemap[pnum]) {
+ store->file_pages = pnum;
+ return -ENOMEM;
+ }
+ store->filemap[pnum]->index = pnum;
+ }
+ store->file_pages = pnum;
+
+ /* We need 4 bits per page, rounded up to a multiple
+ * of sizeof(unsigned long) */
+ store->filemap_attr = kzalloc(
+ roundup(DIV_ROUND_UP(num_pages*4, 8), sizeof(unsigned long)),
+ GFP_KERNEL);
+ if (!store->filemap_attr)
+ return -ENOMEM;
+
+ store->bytes = bytes;
+
+ return 0;
+}
+
+static void bitmap_file_unmap(struct bitmap_storage *store)
{
struct page **map, *sb_page;
- unsigned long *attr;
int pages;
- unsigned long flags;
+ struct file *file;
- spin_lock_irqsave(&bitmap->lock, flags);
- map = bitmap->filemap;
- bitmap->filemap = NULL;
- attr = bitmap->filemap_attr;
- bitmap->filemap_attr = NULL;
- pages = bitmap->file_pages;
- bitmap->file_pages = 0;
- sb_page = bitmap->sb_page;
- bitmap->sb_page = NULL;
- spin_unlock_irqrestore(&bitmap->lock, flags);
+ file = store->file;
+ map = store->filemap;
+ pages = store->file_pages;
+ sb_page = store->sb_page;
while (pages--)
if (map[pages] != sb_page) /* 0 is sb_page, release it below */
free_buffers(map[pages]);
kfree(map);
- kfree(attr);
+ kfree(store->filemap_attr);
if (sb_page)
free_buffers(sb_page);
-}
-
-static void bitmap_file_put(struct bitmap *bitmap)
-{
- struct file *file;
- unsigned long flags;
-
- spin_lock_irqsave(&bitmap->lock, flags);
- file = bitmap->file;
- bitmap->file = NULL;
- spin_unlock_irqrestore(&bitmap->lock, flags);
-
- if (file)
- wait_event(bitmap->write_wait,
- atomic_read(&bitmap->pending_writes)==0);
- bitmap_file_unmap(bitmap);
if (file) {
struct inode *inode = file->f_path.dentry->d_inode;
@@ -773,14 +777,14 @@ static void bitmap_file_kick(struct bitmap *bitmap)
{
char *path, *ptr = NULL;
- if (bitmap_mask_state(bitmap, BITMAP_STALE, MASK_SET) == 0) {
+ if (!test_and_set_bit(BITMAP_STALE, &bitmap->flags)) {
bitmap_update_sb(bitmap);
- if (bitmap->file) {
+ if (bitmap->storage.file) {
path = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (path)
- ptr = d_path(&bitmap->file->f_path, path,
- PAGE_SIZE);
+ ptr = d_path(&bitmap->storage.file->f_path,
+ path, PAGE_SIZE);
printk(KERN_ALERT
"%s: kicking failed bitmap file %s from array!\n",
@@ -792,10 +796,6 @@ static void bitmap_file_kick(struct bitmap *bitmap)
"%s: disabling internal bitmap due to errors\n",
bmname(bitmap));
}
-
- bitmap_file_put(bitmap);
-
- return;
}
enum bitmap_page_attr {
@@ -805,24 +805,30 @@ enum bitmap_page_attr {
BITMAP_PAGE_NEEDWRITE = 2, /* there are cleared bits that need to be synced */
};
-static inline void set_page_attr(struct bitmap *bitmap, struct page *page,
- enum bitmap_page_attr attr)
+static inline void set_page_attr(struct bitmap *bitmap, int pnum,
+ enum bitmap_page_attr attr)
{
- __set_bit((page->index<<2) + attr, bitmap->filemap_attr);
+ set_bit((pnum<<2) + attr, bitmap->storage.filemap_attr);
}
-static inline void clear_page_attr(struct bitmap *bitmap, struct page *page,
- enum bitmap_page_attr attr)
+static inline void clear_page_attr(struct bitmap *bitmap, int pnum,
+ enum bitmap_page_attr attr)
{
- __clear_bit((page->index<<2) + attr, bitmap->filemap_attr);
+ clear_bit((pnum<<2) + attr, bitmap->storage.filemap_attr);
}
-static inline unsigned long test_page_attr(struct bitmap *bitmap, struct page *page,
- enum bitmap_page_attr attr)
+static inline int test_page_attr(struct bitmap *bitmap, int pnum,
+ enum bitmap_page_attr attr)
{
- return test_bit((page->index<<2) + attr, bitmap->filemap_attr);
+ return test_bit((pnum<<2) + attr, bitmap->storage.filemap_attr);
}
+static inline int test_and_clear_page_attr(struct bitmap *bitmap, int pnum,
+ enum bitmap_page_attr attr)
+{
+ return test_and_clear_bit((pnum<<2) + attr,
+ bitmap->storage.filemap_attr);
+}
/*
* bitmap_file_set_bit -- called before performing a write to the md device
* to set (and eventually sync) a particular bit in the bitmap file
@@ -835,26 +841,46 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block)
unsigned long bit;
struct page *page;
void *kaddr;
- unsigned long chunk = block >> bitmap->chunkshift;
+ unsigned long chunk = block >> bitmap->counts.chunkshift;
- if (!bitmap->filemap)
- return;
-
- page = filemap_get_page(bitmap, chunk);
+ page = filemap_get_page(&bitmap->storage, chunk);
if (!page)
return;
- bit = file_page_offset(bitmap, chunk);
+ bit = file_page_offset(&bitmap->storage, chunk);
/* set the bit */
kaddr = kmap_atomic(page);
- if (bitmap->flags & BITMAP_HOSTENDIAN)
+ if (test_bit(BITMAP_HOSTENDIAN, &bitmap->flags))
set_bit(bit, kaddr);
else
- __set_bit_le(bit, kaddr);
+ test_and_set_bit_le(bit, kaddr);
kunmap_atomic(kaddr);
pr_debug("set file bit %lu page %lu\n", bit, page->index);
/* record page number so it gets flushed to disk when unplug occurs */
- set_page_attr(bitmap, page, BITMAP_PAGE_DIRTY);
+ set_page_attr(bitmap, page->index, BITMAP_PAGE_DIRTY);
+}
+
+static void bitmap_file_clear_bit(struct bitmap *bitmap, sector_t block)
+{
+ unsigned long bit;
+ struct page *page;
+ void *paddr;
+ unsigned long chunk = block >> bitmap->counts.chunkshift;
+
+ page = filemap_get_page(&bitmap->storage, chunk);
+ if (!page)
+ return;
+ bit = file_page_offset(&bitmap->storage, chunk);
+ paddr = kmap_atomic(page);
+ if (test_bit(BITMAP_HOSTENDIAN, &bitmap->flags))
+ clear_bit(bit, paddr);
+ else
+ test_and_clear_bit_le(bit, paddr);
+ kunmap_atomic(paddr);
+ if (!test_page_attr(bitmap, page->index, BITMAP_PAGE_NEEDWRITE)) {
+ set_page_attr(bitmap, page->index, BITMAP_PAGE_PENDING);
+ bitmap->allclean = 0;
+ }
}
/* this gets called when the md device is ready to unplug its underlying
@@ -862,42 +888,37 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block)
* sync the dirty pages of the bitmap file to disk */
void bitmap_unplug(struct bitmap *bitmap)
{
- unsigned long i, flags;
+ unsigned long i;
int dirty, need_write;
- struct page *page;
int wait = 0;
- if (!bitmap)
+ if (!bitmap || !bitmap->storage.filemap ||
+ test_bit(BITMAP_STALE, &bitmap->flags))
return;
/* look at each page to see if there are any set bits that need to be
* flushed out to disk */
- for (i = 0; i < bitmap->file_pages; i++) {
- spin_lock_irqsave(&bitmap->lock, flags);
- if (!bitmap->filemap) {
- spin_unlock_irqrestore(&bitmap->lock, flags);
+ for (i = 0; i < bitmap->storage.file_pages; i++) {
+ if (!bitmap->storage.filemap)
return;
+ dirty = test_and_clear_page_attr(bitmap, i, BITMAP_PAGE_DIRTY);
+ need_write = test_and_clear_page_attr(bitmap, i,
+ BITMAP_PAGE_NEEDWRITE);
+ if (dirty || need_write) {
+ clear_page_attr(bitmap, i, BITMAP_PAGE_PENDING);
+ write_page(bitmap, bitmap->storage.filemap[i], 0);
}
- page = bitmap->filemap[i];
- dirty = test_page_attr(bitmap, page, BITMAP_PAGE_DIRTY);
- need_write = test_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
- clear_page_attr(bitmap, page, BITMAP_PAGE_DIRTY);
- clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
if (dirty)
wait = 1;
- spin_unlock_irqrestore(&bitmap->lock, flags);
-
- if (dirty || need_write)
- write_page(bitmap, page, 0);
}
if (wait) { /* if any writes were performed, we need to wait on them */
- if (bitmap->file)
+ if (bitmap->storage.file)
wait_event(bitmap->write_wait,
atomic_read(&bitmap->pending_writes)==0);
else
md_super_wait(bitmap->mddev);
}
- if (bitmap->flags & BITMAP_WRITE_ERROR)
+ if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags))
bitmap_file_kick(bitmap);
}
EXPORT_SYMBOL(bitmap_unplug);
@@ -917,98 +938,77 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int n
static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
{
unsigned long i, chunks, index, oldindex, bit;
- struct page *page = NULL, *oldpage = NULL;
- unsigned long num_pages, bit_cnt = 0;
+ struct page *page = NULL;
+ unsigned long bit_cnt = 0;
struct file *file;
- unsigned long bytes, offset;
+ unsigned long offset;
int outofdate;
int ret = -ENOSPC;
void *paddr;
+ struct bitmap_storage *store = &bitmap->storage;
- chunks = bitmap->chunks;
- file = bitmap->file;
+ chunks = bitmap->counts.chunks;
+ file = store->file;
- BUG_ON(!file && !bitmap->mddev->bitmap_info.offset);
+ if (!file && !bitmap->mddev->bitmap_info.offset) {
+ /* No permanent bitmap - fill with '1s'. */
+ store->filemap = NULL;
+ store->file_pages = 0;
+ for (i = 0; i < chunks ; i++) {
+ /* if the disk bit is set, set the memory bit */
+ int needed = ((sector_t)(i+1) << (bitmap->counts.chunkshift)
+ >= start);
+ bitmap_set_memory_bits(bitmap,
+ (sector_t)i << bitmap->counts.chunkshift,
+ needed);
+ }
+ return 0;
+ }
- outofdate = bitmap->flags & BITMAP_STALE;
+ outofdate = test_bit(BITMAP_STALE, &bitmap->flags);
if (outofdate)
printk(KERN_INFO "%s: bitmap file is out of date, doing full "
"recovery\n", bmname(bitmap));
- bytes = DIV_ROUND_UP(bitmap->chunks, 8);
- if (!bitmap->mddev->bitmap_info.external)
- bytes += sizeof(bitmap_super_t);
-
- num_pages = DIV_ROUND_UP(bytes, PAGE_SIZE);
-
- if (file && i_size_read(file->f_mapping->host) < bytes) {
+ if (file && i_size_read(file->f_mapping->host) < store->bytes) {
printk(KERN_INFO "%s: bitmap file too short %lu < %lu\n",
- bmname(bitmap),
- (unsigned long) i_size_read(file->f_mapping->host),
- bytes);
+ bmname(bitmap),
+ (unsigned long) i_size_read(file->f_mapping->host),
+ store->bytes);
goto err;
}
- ret = -ENOMEM;
-
- bitmap->filemap = kmalloc(sizeof(struct page *) * num_pages, GFP_KERNEL);
- if (!bitmap->filemap)
- goto err;
-
- /* We need 4 bits per page, rounded up to a multiple of sizeof(unsigned long) */
- bitmap->filemap_attr = kzalloc(
- roundup(DIV_ROUND_UP(num_pages*4, 8), sizeof(unsigned long)),
- GFP_KERNEL);
- if (!bitmap->filemap_attr)
- goto err;
-
oldindex = ~0L;
+ offset = 0;
+ if (!bitmap->mddev->bitmap_info.external)
+ offset = sizeof(bitmap_super_t);
for (i = 0; i < chunks; i++) {
int b;
- index = file_page_index(bitmap, i);
- bit = file_page_offset(bitmap, i);
+ index = file_page_index(&bitmap->storage, i);
+ bit = file_page_offset(&bitmap->storage, i);
if (index != oldindex) { /* this is a new page, read it in */
int count;
/* unmap the old page, we're done with it */
- if (index == num_pages-1)
- count = bytes - index * PAGE_SIZE;
+ if (index == store->file_pages-1)
+ count = store->bytes - index * PAGE_SIZE;
else
count = PAGE_SIZE;
- if (index == 0 && bitmap->sb_page) {
- /*
- * if we're here then the superblock page
- * contains some bits (PAGE_SIZE != sizeof sb)
- * we've already read it in, so just use it
- */
- page = bitmap->sb_page;
- offset = sizeof(bitmap_super_t);
- if (!file)
- page = read_sb_page(
- bitmap->mddev,
- bitmap->mddev->bitmap_info.offset,
- page,
- index, count);
- } else if (file) {
- page = read_page(file, index, bitmap, count);
- offset = 0;
- } else {
- page = read_sb_page(bitmap->mddev,
- bitmap->mddev->bitmap_info.offset,
- NULL,
- index, count);
- offset = 0;
- }
- if (IS_ERR(page)) { /* read error */
- ret = PTR_ERR(page);
+ page = store->filemap[index];
+ if (file)
+ ret = read_page(file, index, bitmap,
+ count, page);
+ else
+ ret = read_sb_page(
+ bitmap->mddev,
+ bitmap->mddev->bitmap_info.offset,
+ page,
+ index, count);
+
+ if (ret)
goto err;
- }
oldindex = index;
- oldpage = page;
-
- bitmap->filemap[bitmap->file_pages++] = page;
- bitmap->last_page_size = count;
if (outofdate) {
/*
@@ -1022,39 +1022,33 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
write_page(bitmap, page, 1);
ret = -EIO;
- if (bitmap->flags & BITMAP_WRITE_ERROR)
+ if (test_bit(BITMAP_WRITE_ERROR,
+ &bitmap->flags))
goto err;
}
}
paddr = kmap_atomic(page);
- if (bitmap->flags & BITMAP_HOSTENDIAN)
+ if (test_bit(BITMAP_HOSTENDIAN, &bitmap->flags))
b = test_bit(bit, paddr);
else
b = test_bit_le(bit, paddr);
kunmap_atomic(paddr);
if (b) {
/* if the disk bit is set, set the memory bit */
- int needed = ((sector_t)(i+1) << bitmap->chunkshift
+ int needed = ((sector_t)(i+1) << bitmap->counts.chunkshift
>= start);
bitmap_set_memory_bits(bitmap,
- (sector_t)i << bitmap->chunkshift,
+ (sector_t)i << bitmap->counts.chunkshift,
needed);
bit_cnt++;
}
- }
-
- /* everything went OK */
- ret = 0;
- bitmap_mask_state(bitmap, BITMAP_STALE, MASK_UNSET);
-
- if (bit_cnt) { /* Kick recovery if any bits were set */
- set_bit(MD_RECOVERY_NEEDED, &bitmap->mddev->recovery);
- md_wakeup_thread(bitmap->mddev->thread);
+ offset = 0;
}
printk(KERN_INFO "%s: bitmap initialized from disk: "
- "read %lu/%lu pages, set %lu of %lu bits\n",
- bmname(bitmap), bitmap->file_pages, num_pages, bit_cnt, chunks);
+ "read %lu pages, set %lu of %lu bits\n",
+ bmname(bitmap), store->file_pages,
+ bit_cnt, chunks);
return 0;
@@ -1071,22 +1065,38 @@ void bitmap_write_all(struct bitmap *bitmap)
*/
int i;
- spin_lock_irq(&bitmap->lock);
- for (i = 0; i < bitmap->file_pages; i++)
- set_page_attr(bitmap, bitmap->filemap[i],
+ if (!bitmap || !bitmap->storage.filemap)
+ return;
+ if (bitmap->storage.file)
+ /* Only one copy, so nothing needed */
+ return;
+
+ for (i = 0; i < bitmap->storage.file_pages; i++)
+ set_page_attr(bitmap, i,
BITMAP_PAGE_NEEDWRITE);
bitmap->allclean = 0;
- spin_unlock_irq(&bitmap->lock);
}
-static void bitmap_count_page(struct bitmap *bitmap, sector_t offset, int inc)
+static void bitmap_count_page(struct bitmap_counts *bitmap,
+ sector_t offset, int inc)
{
sector_t chunk = offset >> bitmap->chunkshift;
unsigned long page = chunk >> PAGE_COUNTER_SHIFT;
bitmap->bp[page].count += inc;
bitmap_checkfree(bitmap, page);
}
-static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap,
+
+static void bitmap_set_pending(struct bitmap_counts *bitmap, sector_t offset)
+{
+ sector_t chunk = offset >> bitmap->chunkshift;
+ unsigned long page = chunk >> PAGE_COUNTER_SHIFT;
+ struct bitmap_page *bp = &bitmap->bp[page];
+
+ if (!bp->pending)
+ bp->pending = 1;
+}
+
+static bitmap_counter_t *bitmap_get_counter(struct bitmap_counts *bitmap,
sector_t offset, sector_t *blocks,
int create);
@@ -1099,10 +1109,9 @@ void bitmap_daemon_work(struct mddev *mddev)
{
struct bitmap *bitmap;
unsigned long j;
- unsigned long flags;
- struct page *page = NULL, *lastpage = NULL;
+ unsigned long nextpage;
sector_t blocks;
- void *paddr;
+ struct bitmap_counts *counts;
/* Use a mutex to guard daemon_work against
* bitmap_destroy.
@@ -1124,112 +1133,90 @@ void bitmap_daemon_work(struct mddev *mddev)
}
bitmap->allclean = 1;
- spin_lock_irqsave(&bitmap->lock, flags);
- for (j = 0; j < bitmap->chunks; j++) {
+ /* Any file-page which is PENDING now needs to be written.
+ * So set NEEDWRITE now, then after we make any last-minute changes
+ * we will write it.
+ */
+ for (j = 0; j < bitmap->storage.file_pages; j++)
+ if (test_and_clear_page_attr(bitmap, j,
+ BITMAP_PAGE_PENDING))
+ set_page_attr(bitmap, j,
+ BITMAP_PAGE_NEEDWRITE);
+
+ if (bitmap->need_sync &&
+ mddev->bitmap_info.external == 0) {
+ /* Arrange for superblock update as well as
+ * other changes */
+ bitmap_super_t *sb;
+ bitmap->need_sync = 0;
+ if (bitmap->storage.filemap) {
+ sb = kmap_atomic(bitmap->storage.sb_page);
+ sb->events_cleared =
+ cpu_to_le64(bitmap->events_cleared);
+ kunmap_atomic(sb);
+ set_page_attr(bitmap, 0,
+ BITMAP_PAGE_NEEDWRITE);
+ }
+ }
+ /* Now look at the bitmap counters and if any are '2' or '1',
+ * decrement and handle accordingly.
+ */
+ counts = &bitmap->counts;
+ spin_lock_irq(&counts->lock);
+ nextpage = 0;
+ for (j = 0; j < counts->chunks; j++) {
bitmap_counter_t *bmc;
- if (!bitmap->filemap)
- /* error or shutdown */
- break;
+ sector_t block = (sector_t)j << counts->chunkshift;
- page = filemap_get_page(bitmap, j);
-
- if (page != lastpage) {
- /* skip this page unless it's marked as needing cleaning */
- if (!test_page_attr(bitmap, page, BITMAP_PAGE_PENDING)) {
- int need_write = test_page_attr(bitmap, page,
- BITMAP_PAGE_NEEDWRITE);
- if (need_write)
- clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
-
- spin_unlock_irqrestore(&bitmap->lock, flags);
- if (need_write)
- write_page(bitmap, page, 0);
- spin_lock_irqsave(&bitmap->lock, flags);
- j |= (PAGE_BITS - 1);
+ if (j == nextpage) {
+ nextpage += PAGE_COUNTER_RATIO;
+ if (!counts->bp[j >> PAGE_COUNTER_SHIFT].pending) {
+ j |= PAGE_COUNTER_MASK;
continue;
}
-
- /* grab the new page, sync and release the old */
- if (lastpage != NULL) {
- if (test_page_attr(bitmap, lastpage,
- BITMAP_PAGE_NEEDWRITE)) {
- clear_page_attr(bitmap, lastpage,
- BITMAP_PAGE_NEEDWRITE);
- spin_unlock_irqrestore(&bitmap->lock, flags);
- write_page(bitmap, lastpage, 0);
- } else {
- set_page_attr(bitmap, lastpage,
- BITMAP_PAGE_NEEDWRITE);
- bitmap->allclean = 0;
- spin_unlock_irqrestore(&bitmap->lock, flags);
- }
- } else
- spin_unlock_irqrestore(&bitmap->lock, flags);
- lastpage = page;
-
- /* We are possibly going to clear some bits, so make
- * sure that events_cleared is up-to-date.
- */
- if (bitmap->need_sync &&
- mddev->bitmap_info.external == 0) {
- bitmap_super_t *sb;
- bitmap->need_sync = 0;
- sb = kmap_atomic(bitmap->sb_page);
- sb->events_cleared =
- cpu_to_le64(bitmap->events_cleared);
- kunmap_atomic(sb);
- write_page(bitmap, bitmap->sb_page, 1);
- }
- spin_lock_irqsave(&bitmap->lock, flags);
- if (!bitmap->need_sync)
- clear_page_attr(bitmap, page, BITMAP_PAGE_PENDING);
- else
- bitmap->allclean = 0;
+ counts->bp[j >> PAGE_COUNTER_SHIFT].pending = 0;
}
- bmc = bitmap_get_counter(bitmap,
- (sector_t)j << bitmap->chunkshift,
+ bmc = bitmap_get_counter(counts,
+ block,
&blocks, 0);
- if (!bmc)
+
+ if (!bmc) {
j |= PAGE_COUNTER_MASK;
- else if (*bmc) {
- if (*bmc == 1 && !bitmap->need_sync) {
- /* we can clear the bit */
- *bmc = 0;
- bitmap_count_page(bitmap,
- (sector_t)j << bitmap->chunkshift,
- -1);
-
- /* clear the bit */
- paddr = kmap_atomic(page);
- if (bitmap->flags & BITMAP_HOSTENDIAN)
- clear_bit(file_page_offset(bitmap, j),
- paddr);
- else
- __clear_bit_le(
- file_page_offset(bitmap,
- j),
- paddr);
- kunmap_atomic(paddr);
- } else if (*bmc <= 2) {
- *bmc = 1; /* maybe clear the bit next time */
- set_page_attr(bitmap, page, BITMAP_PAGE_PENDING);
- bitmap->allclean = 0;
- }
+ continue;
}
- }
- spin_unlock_irqrestore(&bitmap->lock, flags);
-
- /* now sync the final page */
- if (lastpage != NULL) {
- spin_lock_irqsave(&bitmap->lock, flags);
- if (test_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE)) {
- clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
- spin_unlock_irqrestore(&bitmap->lock, flags);
- write_page(bitmap, lastpage, 0);
- } else {
- set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
+ if (*bmc == 1 && !bitmap->need_sync) {
+ /* We can clear the bit */
+ *bmc = 0;
+ bitmap_count_page(counts, block, -1);
+ bitmap_file_clear_bit(bitmap, block);
+ } else if (*bmc && *bmc <= 2) {
+ *bmc = 1;
+ bitmap_set_pending(counts, block);
bitmap->allclean = 0;
- spin_unlock_irqrestore(&bitmap->lock, flags);
+ }
+ }
+ spin_unlock_irq(&counts->lock);
+
+ /* Now start writeout on any page in NEEDWRITE that isn't DIRTY.
+ * DIRTY pages need to be written by bitmap_unplug so it can wait
+ * for them.
+ * If we find any DIRTY page we stop there and let bitmap_unplug
+ * handle all the rest. This is important in the case where
+ * the first blocking holds the superblock and it has been updated.
+ * We mustn't write any other blocks before the superblock.
+ */
+ for (j = 0;
+ j < bitmap->storage.file_pages
+ && !test_bit(BITMAP_STALE, &bitmap->flags);
+ j++) {
+
+ if (test_page_attr(bitmap, j,
+ BITMAP_PAGE_DIRTY))
+ /* bitmap_unplug will handle the rest */
+ break;
+ if (test_and_clear_page_attr(bitmap, j,
+ BITMAP_PAGE_NEEDWRITE)) {
+ write_page(bitmap, bitmap->storage.filemap[j], 0);
}
}
@@ -1240,7 +1227,7 @@ void bitmap_daemon_work(struct mddev *mddev)
mutex_unlock(&mddev->bitmap_info.mutex);
}
-static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap,
+static bitmap_counter_t *bitmap_get_counter(struct bitmap_counts *bitmap,
sector_t offset, sector_t *blocks,
int create)
__releases(bitmap->lock)
@@ -1302,10 +1289,10 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect
sector_t blocks;
bitmap_counter_t *bmc;
- spin_lock_irq(&bitmap->lock);
- bmc = bitmap_get_counter(bitmap, offset, &blocks, 1);
+ spin_lock_irq(&bitmap->counts.lock);
+ bmc = bitmap_get_counter(&bitmap->counts, offset, &blocks, 1);
if (!bmc) {
- spin_unlock_irq(&bitmap->lock);
+ spin_unlock_irq(&bitmap->counts.lock);
return 0;
}
@@ -1317,7 +1304,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect
*/
prepare_to_wait(&bitmap->overflow_wait, &__wait,
TASK_UNINTERRUPTIBLE);
- spin_unlock_irq(&bitmap->lock);
+ spin_unlock_irq(&bitmap->counts.lock);
io_schedule();
finish_wait(&bitmap->overflow_wait, &__wait);
continue;
@@ -1326,7 +1313,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect
switch (*bmc) {
case 0:
bitmap_file_set_bit(bitmap, offset);
- bitmap_count_page(bitmap, offset, 1);
+ bitmap_count_page(&bitmap->counts, offset, 1);
/* fall through */
case 1:
*bmc = 2;
@@ -1334,7 +1321,7 @@ int bitmap_startwrite(struct bitmap *bitmap, sector_t offset, unsigned long sect
(*bmc)++;
- spin_unlock_irq(&bitmap->lock);
+ spin_unlock_irq(&bitmap->counts.lock);
offset += blocks;
if (sectors > blocks)
@@ -1364,10 +1351,10 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto
unsigned long flags;
bitmap_counter_t *bmc;
- spin_lock_irqsave(&bitmap->lock, flags);
- bmc = bitmap_get_counter(bitmap, offset, &blocks, 0);
+ spin_lock_irqsave(&bitmap->counts.lock, flags);
+ bmc = bitmap_get_counter(&bitmap->counts, offset, &blocks, 0);
if (!bmc) {
- spin_unlock_irqrestore(&bitmap->lock, flags);
+ spin_unlock_irqrestore(&bitmap->counts.lock, flags);
return;
}
@@ -1386,14 +1373,10 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto
(*bmc)--;
if (*bmc <= 2) {
- set_page_attr(bitmap,
- filemap_get_page(
- bitmap,
- offset >> bitmap->chunkshift),
- BITMAP_PAGE_PENDING);
+ bitmap_set_pending(&bitmap->counts, offset);
bitmap->allclean = 0;
}
- spin_unlock_irqrestore(&bitmap->lock, flags);
+ spin_unlock_irqrestore(&bitmap->counts.lock, flags);
offset += blocks;
if (sectors > blocks)
sectors -= blocks;
@@ -1412,8 +1395,8 @@ static int __bitmap_start_sync(struct bitmap *bitmap, sector_t offset, sector_t
*blocks = 1024;
return 1; /* always resync if no bitmap */
}
- spin_lock_irq(&bitmap->lock);
- bmc = bitmap_get_counter(bitmap, offset, blocks, 0);
+ spin_lock_irq(&bitmap->counts.lock);
+ bmc = bitmap_get_counter(&bitmap->counts, offset, blocks, 0);
rv = 0;
if (bmc) {
/* locked */
@@ -1427,7 +1410,7 @@ static int __bitmap_start_sync(struct bitmap *bitmap, sector_t offset, sector_t
}
}
}
- spin_unlock_irq(&bitmap->lock);
+ spin_unlock_irq(&bitmap->counts.lock);
return rv;
}
@@ -1464,8 +1447,8 @@ void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, sector_t *blocks, i
*blocks = 1024;
return;
}
- spin_lock_irqsave(&bitmap->lock, flags);
- bmc = bitmap_get_counter(bitmap, offset, blocks, 0);
+ spin_lock_irqsave(&bitmap->counts.lock, flags);
+ bmc = bitmap_get_counter(&bitmap->counts, offset, blocks, 0);
if (bmc == NULL)
goto unlock;
/* locked */
@@ -1476,15 +1459,13 @@ void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, sector_t *blocks, i
*bmc |= NEEDED_MASK;
else {
if (*bmc <= 2) {
- set_page_attr(bitmap,
- filemap_get_page(bitmap, offset >> bitmap->chunkshift),
- BITMAP_PAGE_PENDING);
+ bitmap_set_pending(&bitmap->counts, offset);
bitmap->allclean = 0;
}
}
}
unlock:
- spin_unlock_irqrestore(&bitmap->lock, flags);
+ spin_unlock_irqrestore(&bitmap->counts.lock, flags);
}
EXPORT_SYMBOL(bitmap_end_sync);
@@ -1524,7 +1505,7 @@ void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector)
bitmap->mddev->curr_resync_completed = sector;
set_bit(MD_CHANGE_CLEAN, &bitmap->mddev->flags);
- sector &= ~((1ULL << bitmap->chunkshift) - 1);
+ sector &= ~((1ULL << bitmap->counts.chunkshift) - 1);
s = 0;
while (s < sector && s < bitmap->mddev->resync_max_sectors) {
bitmap_end_sync(bitmap, s, &blocks, 0);
@@ -1538,27 +1519,25 @@ EXPORT_SYMBOL(bitmap_cond_end_sync);
static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int needed)
{
/* For each chunk covered by any of these sectors, set the
- * counter to 1 and set resync_needed. They should all
+ * counter to 2 and possibly set resync_needed. They should all
* be 0 at this point
*/
sector_t secs;
bitmap_counter_t *bmc;
- spin_lock_irq(&bitmap->lock);
- bmc = bitmap_get_counter(bitmap, offset, &secs, 1);
+ spin_lock_irq(&bitmap->counts.lock);
+ bmc = bitmap_get_counter(&bitmap->counts, offset, &secs, 1);
if (!bmc) {
- spin_unlock_irq(&bitmap->lock);
+ spin_unlock_irq(&bitmap->counts.lock);
return;
}
if (!*bmc) {
- struct page *page;
*bmc = 2 | (needed ? NEEDED_MASK : 0);
- bitmap_count_page(bitmap, offset, 1);
- page = filemap_get_page(bitmap, offset >> bitmap->chunkshift);
- set_page_attr(bitmap, page, BITMAP_PAGE_PENDING);
+ bitmap_count_page(&bitmap->counts, offset, 1);
+ bitmap_set_pending(&bitmap->counts, offset);
bitmap->allclean = 0;
}
- spin_unlock_irq(&bitmap->lock);
+ spin_unlock_irq(&bitmap->counts.lock);
}
/* dirty the memory and file bits for bitmap chunks "s" to "e" */
@@ -1567,11 +1546,9 @@ void bitmap_dirty_bits(struct bitmap *bitmap, unsigned long s, unsigned long e)
unsigned long chunk;
for (chunk = s; chunk <= e; chunk++) {
- sector_t sec = (sector_t)chunk << bitmap->chunkshift;
+ sector_t sec = (sector_t)chunk << bitmap->counts.chunkshift;
bitmap_set_memory_bits(bitmap, sec, 1);
- spin_lock_irq(&bitmap->lock);
bitmap_file_set_bit(bitmap, sec);
- spin_unlock_irq(&bitmap->lock);
if (sec < bitmap->mddev->recovery_cp)
/* We are asserting that the array is dirty,
* so move the recovery_cp address back so
@@ -1616,11 +1593,15 @@ static void bitmap_free(struct bitmap *bitmap)
if (!bitmap) /* there was no bitmap */
return;
- /* release the bitmap file and kill the daemon */
- bitmap_file_put(bitmap);
+ /* Shouldn't be needed - but just in case.... */
+ wait_event(bitmap->write_wait,
+ atomic_read(&bitmap->pending_writes) == 0);
+
+ /* release the bitmap file */
+ bitmap_file_unmap(&bitmap->storage);
- bp = bitmap->bp;
- pages = bitmap->pages;
+ bp = bitmap->counts.bp;
+ pages = bitmap->counts.pages;
/* free all allocated memory */
@@ -1659,25 +1640,19 @@ int bitmap_create(struct mddev *mddev)
{
struct bitmap *bitmap;
sector_t blocks = mddev->resync_max_sectors;
- unsigned long chunks;
- unsigned long pages;
struct file *file = mddev->bitmap_info.file;
int err;
struct sysfs_dirent *bm = NULL;
BUILD_BUG_ON(sizeof(bitmap_super_t) != 256);
- if (!file
- && !mddev->bitmap_info.offset) /* bitmap disabled, nothing to do */
- return 0;
-
BUG_ON(file && mddev->bitmap_info.offset);
bitmap = kzalloc(sizeof(*bitmap), GFP_KERNEL);
if (!bitmap)
return -ENOMEM;
- spin_lock_init(&bitmap->lock);
+ spin_lock_init(&bitmap->counts.lock);
atomic_set(&bitmap->pending_writes, 0);
init_waitqueue_head(&bitmap->write_wait);
init_waitqueue_head(&bitmap->overflow_wait);
@@ -1693,7 +1668,7 @@ int bitmap_create(struct mddev *mddev)
} else
bitmap->sysfs_can_clear = NULL;
- bitmap->file = file;
+ bitmap->storage.file = file;
if (file) {
get_file(file);
/* As future accesses to this file will use bmap,
@@ -1724,32 +1699,15 @@ int bitmap_create(struct mddev *mddev)
goto error;
bitmap->daemon_lastrun = jiffies;
- bitmap->chunkshift = (ffz(~mddev->bitmap_info.chunksize)
- - BITMAP_BLOCK_SHIFT);
-
- chunks = (blocks + (1 << bitmap->chunkshift) - 1) >>
- bitmap->chunkshift;
- pages = (chunks + PAGE_COUNTER_RATIO - 1) / PAGE_COUNTER_RATIO;
-
- BUG_ON(!pages);
-
- bitmap->chunks = chunks;
- bitmap->pages = pages;
- bitmap->missing_pages = pages;
-
- bitmap->bp = kzalloc(pages * sizeof(*bitmap->bp), GFP_KERNEL);
-
- err = -ENOMEM;
- if (!bitmap->bp)
+ err = bitmap_resize(bitmap, blocks, mddev->bitmap_info.chunksize, 1);
+ if (err)
goto error;
printk(KERN_INFO "created bitmap (%lu pages) for device %s\n",
- pages, bmname(bitmap));
+ bitmap->counts.pages, bmname(bitmap));
mddev->bitmap = bitmap;
-
-
- return (bitmap->flags & BITMAP_WRITE_ERROR) ? -EIO : 0;
+ return test_bit(BITMAP_WRITE_ERROR, &bitmap->flags) ? -EIO : 0;
error:
bitmap_free(bitmap);
@@ -1790,13 +1748,17 @@ int bitmap_load(struct mddev *mddev)
if (err)
goto out;
+ clear_bit(BITMAP_STALE, &bitmap->flags);
+
+ /* Kick recovery in case any bits were set */
+ set_bit(MD_RECOVERY_NEEDED, &bitmap->mddev->recovery);
mddev->thread->timeout = mddev->bitmap_info.daemon_sleep;
md_wakeup_thread(mddev->thread);
bitmap_update_sb(bitmap);
- if (bitmap->flags & BITMAP_WRITE_ERROR)
+ if (test_bit(BITMAP_WRITE_ERROR, &bitmap->flags))
err = -EIO;
out:
return err;
@@ -1806,30 +1768,194 @@ EXPORT_SYMBOL_GPL(bitmap_load);
void bitmap_status(struct seq_file *seq, struct bitmap *bitmap)
{
unsigned long chunk_kb;
- unsigned long flags;
+ struct bitmap_counts *counts;
if (!bitmap)
return;
- spin_lock_irqsave(&bitmap->lock, flags);
+ counts = &bitmap->counts;
+
chunk_kb = bitmap->mddev->bitmap_info.chunksize >> 10;
seq_printf(seq, "bitmap: %lu/%lu pages [%luKB], "
"%lu%s chunk",
- bitmap->pages - bitmap->missing_pages,
- bitmap->pages,
- (bitmap->pages - bitmap->missing_pages)
+ counts->pages - counts->missing_pages,
+ counts->pages,
+ (counts->pages - counts->missing_pages)
<< (PAGE_SHIFT - 10),
chunk_kb ? chunk_kb : bitmap->mddev->bitmap_info.chunksize,
chunk_kb ? "KB" : "B");
- if (bitmap->file) {
+ if (bitmap->storage.file) {
seq_printf(seq, ", file: ");
- seq_path(seq, &bitmap->file->f_path, " \t\n");
+ seq_path(seq, &bitmap->storage.file->f_path, " \t\n");
}
seq_printf(seq, "\n");
- spin_unlock_irqrestore(&bitmap->lock, flags);
}
+int bitmap_resize(struct bitmap *bitmap, sector_t blocks,
+ int chunksize, int init)
+{
+ /* If chunk_size is 0, choose an appropriate chunk size.
+ * Then possibly allocate new storage space.
+ * Then quiesce, copy bits, replace bitmap, and re-start
+ *
+ * This function is called both to set up the initial bitmap
+ * and to resize the bitmap while the array is active.
+ * If this happens as a result of the array being resized,
+ * chunksize will be zero, and we need to choose a suitable
+ * chunksize, otherwise we use what we are given.
+ */
+ struct bitmap_storage store;
+ struct bitmap_counts old_counts;
+ unsigned long chunks;
+ sector_t block;
+ sector_t old_blocks, new_blocks;
+ int chunkshift;
+ int ret = 0;
+ long pages;
+ struct bitmap_page *new_bp;
+
+ if (chunksize == 0) {
+ /* If there is enough space, leave the chunk size unchanged,
+ * else increase by factor of two until there is enough space.
+ */
+ long bytes;
+ long space = bitmap->mddev->bitmap_info.space;
+
+ if (space == 0) {
+ /* We don't know how much space there is, so limit
+ * to current size - in sectors.
+ */
+ bytes = DIV_ROUND_UP(bitmap->counts.chunks, 8);
+ if (!bitmap->mddev->bitmap_info.external)
+ bytes += sizeof(bitmap_super_t);
+ space = DIV_ROUND_UP(bytes, 512);
+ bitmap->mddev->bitmap_info.space = space;
+ }
+ chunkshift = bitmap->counts.chunkshift;
+ chunkshift--;
+ do {
+ /* 'chunkshift' is shift from block size to chunk size */
+ chunkshift++;
+ chunks = DIV_ROUND_UP_SECTOR_T(blocks, 1 << chunkshift);
+ bytes = DIV_ROUND_UP(chunks, 8);
+ if (!bitmap->mddev->bitmap_info.external)
+ bytes += sizeof(bitmap_super_t);
+ } while (bytes > (space << 9));
+ } else
+ chunkshift = ffz(~chunksize) - BITMAP_BLOCK_SHIFT;
+
+ chunks = DIV_ROUND_UP_SECTOR_T(blocks, 1 << chunkshift);
+ memset(&store, 0, sizeof(store));
+ if (bitmap->mddev->bitmap_info.offset || bitmap->mddev->bitmap_info.file)
+ ret = bitmap_storage_alloc(&store, chunks,
+ !bitmap->mddev->bitmap_info.external);
+ if (ret)
+ goto err;
+
+ pages = DIV_ROUND_UP(chunks, PAGE_COUNTER_RATIO);
+
+ new_bp = kzalloc(pages * sizeof(*new_bp), GFP_KERNEL);
+ ret = -ENOMEM;
+ if (!new_bp) {
+ bitmap_file_unmap(&store);
+ goto err;
+ }
+
+ if (!init)
+ bitmap->mddev->pers->quiesce(bitmap->mddev, 1);
+
+ store.file = bitmap->storage.file;
+ bitmap->storage.file = NULL;
+
+ if (store.sb_page && bitmap->storage.sb_page)
+ memcpy(page_address(store.sb_page),
+ page_address(bitmap->storage.sb_page),
+ sizeof(bitmap_super_t));
+ bitmap_file_unmap(&bitmap->storage);
+ bitmap->storage = store;
+
+ old_counts = bitmap->counts;
+ bitmap->counts.bp = new_bp;
+ bitmap->counts.pages = pages;
+ bitmap->counts.missing_pages = pages;
+ bitmap->counts.chunkshift = chunkshift;
+ bitmap->counts.chunks = chunks;
+ bitmap->mddev->bitmap_info.chunksize = 1 << (chunkshift +
+ BITMAP_BLOCK_SHIFT);
+
+ blocks = min(old_counts.chunks << old_counts.chunkshift,
+ chunks << chunkshift);
+
+ spin_lock_irq(&bitmap->counts.lock);
+ for (block = 0; block < blocks; ) {
+ bitmap_counter_t *bmc_old, *bmc_new;
+ int set;
+
+ bmc_old = bitmap_get_counter(&old_counts, block,
+ &old_blocks, 0);
+ set = bmc_old && NEEDED(*bmc_old);
+
+ if (set) {
+ bmc_new = bitmap_get_counter(&bitmap->counts, block,
+ &new_blocks, 1);
+ if (*bmc_new == 0) {
+ /* need to set on-disk bits too. */
+ sector_t end = block + new_blocks;
+ sector_t start = block >> chunkshift;
+ start <<= chunkshift;
+ while (start < end) {
+ bitmap_file_set_bit(bitmap, block);
+ start += 1 << chunkshift;
+ }
+ *bmc_new = 2;
+ bitmap_count_page(&bitmap->counts,
+ block, 1);
+ bitmap_set_pending(&bitmap->counts,
+ block);
+ }
+ *bmc_new |= NEEDED_MASK;
+ if (new_blocks < old_blocks)
+ old_blocks = new_blocks;
+ }
+ block += old_blocks;
+ }
+
+ if (!init) {
+ int i;
+ while (block < (chunks << chunkshift)) {
+ bitmap_counter_t *bmc;
+ bmc = bitmap_get_counter(&bitmap->counts, block,
+ &new_blocks, 1);
+ if (bmc) {
+ /* new space. It needs to be resynced, so
+ * we set NEEDED_MASK.
+ */
+ if (*bmc == 0) {
+ *bmc = NEEDED_MASK | 2;
+ bitmap_count_page(&bitmap->counts,
+ block, 1);
+ bitmap_set_pending(&bitmap->counts,
+ block);
+ }
+ }
+ block += new_blocks;
+ }
+ for (i = 0; i < bitmap->storage.file_pages; i++)
+ set_page_attr(bitmap, i, BITMAP_PAGE_DIRTY);
+ }
+ spin_unlock_irq(&bitmap->counts.lock);
+
+ if (!init) {
+ bitmap_unplug(bitmap);
+ bitmap->mddev->pers->quiesce(bitmap->mddev, 0);
+ }
+ ret = 0;
+err:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(bitmap_resize);
+
static ssize_t
location_show(struct mddev *mddev, char *page)
{
@@ -1923,6 +2049,43 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
static struct md_sysfs_entry bitmap_location =
__ATTR(location, S_IRUGO|S_IWUSR, location_show, location_store);
+/* 'bitmap/space' is the space available at 'location' for the
+ * bitmap. This allows the kernel to know when it is safe to
+ * resize the bitmap to match a resized array.
+ */
+static ssize_t
+space_show(struct mddev *mddev, char *page)
+{
+ return sprintf(page, "%lu\n", mddev->bitmap_info.space);
+}
+
+static ssize_t
+space_store(struct mddev *mddev, const char *buf, size_t len)
+{
+ unsigned long sectors;
+ int rv;
+
+ rv = kstrtoul(buf, 10, &sectors);
+ if (rv)
+ return rv;
+
+ if (sectors == 0)
+ return -EINVAL;
+
+ if (mddev->bitmap &&
+ sectors < (mddev->bitmap->storage.bytes + 511) >> 9)
+ return -EFBIG; /* Bitmap is too big for this small space */
+
+ /* could make sure it isn't too big, but that isn't really
+ * needed - user-space should be careful.
+ */
+ mddev->bitmap_info.space = sectors;
+ return len;
+}
+
+static struct md_sysfs_entry bitmap_space =
+__ATTR(space, S_IRUGO|S_IWUSR, space_show, space_store);
+
static ssize_t
timeout_show(struct mddev *mddev, char *page)
{
@@ -2098,6 +2261,7 @@ __ATTR(max_backlog_used, S_IRUGO | S_IWUSR,
static struct attribute *md_bitmap_attrs[] = {
&bitmap_location.attr,
+ &bitmap_space.attr,
&bitmap_timeout.attr,
&bitmap_backlog.attr,
&bitmap_chunksize.attr,
diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h
index b44b0aba2d47..df4aeb6ac6f0 100644
--- a/drivers/md/bitmap.h
+++ b/drivers/md/bitmap.h
@@ -111,9 +111,9 @@ typedef __u16 bitmap_counter_t;
/* use these for bitmap->flags and bitmap->sb->state bit-fields */
enum bitmap_state {
- BITMAP_STALE = 0x002, /* the bitmap file is out of date or had -EIO */
- BITMAP_WRITE_ERROR = 0x004, /* A write error has occurred */
- BITMAP_HOSTENDIAN = 0x8000,
+ BITMAP_STALE = 1, /* the bitmap file is out of date or had -EIO */
+ BITMAP_WRITE_ERROR = 2, /* A write error has occurred */
+ BITMAP_HOSTENDIAN =15,
};
/* the superblock at the front of the bitmap file -- little endian */
@@ -128,8 +128,10 @@ typedef struct bitmap_super_s {
__le32 chunksize; /* 52 the bitmap chunk size in bytes */
__le32 daemon_sleep; /* 56 seconds between disk flushes */
__le32 write_behind; /* 60 number of outstanding write-behind writes */
+ __le32 sectors_reserved; /* 64 number of 512-byte sectors that are
+ * reserved for the bitmap. */
- __u8 pad[256 - 64]; /* set to zero */
+ __u8 pad[256 - 68]; /* set to zero */
} bitmap_super_t;
/* notes:
@@ -160,35 +162,48 @@ struct bitmap_page {
*/
unsigned int hijacked:1;
/*
+ * If any counter in this page is '1' or '2' - and so could be
+ * cleared then that page is marked as 'pending'
+ */
+ unsigned int pending:1;
+ /*
* count of dirty bits on the page
*/
- unsigned int count:31;
+ unsigned int count:30;
};
/* the main bitmap structure - one per mddev */
struct bitmap {
- struct bitmap_page *bp;
- unsigned long pages; /* total number of pages in the bitmap */
- unsigned long missing_pages; /* number of pages not yet allocated */
- struct mddev *mddev; /* the md device that the bitmap is for */
+ struct bitmap_counts {
+ spinlock_t lock;
+ struct bitmap_page *bp;
+ unsigned long pages; /* total number of pages
+ * in the bitmap */
+ unsigned long missing_pages; /* number of pages
+ * not yet allocated */
+ unsigned long chunkshift; /* chunksize = 2^chunkshift
+ * (for bitops) */
+ unsigned long chunks; /* Total number of data
+ * chunks for the array */
+ } counts;
- /* bitmap chunksize -- how much data does each bit represent? */
- unsigned long chunkshift; /* chunksize = 2^(chunkshift+9) (for bitops) */
- unsigned long chunks; /* total number of data chunks for the array */
+ struct mddev *mddev; /* the md device that the bitmap is for */
__u64 events_cleared;
int need_sync;
- /* bitmap spinlock */
- spinlock_t lock;
-
- struct file *file; /* backing disk file */
- struct page *sb_page; /* cached copy of the bitmap file superblock */
- struct page **filemap; /* list of cache pages for the file */
- unsigned long *filemap_attr; /* attributes associated w/ filemap pages */
- unsigned long file_pages; /* number of pages in the file */
- int last_page_size; /* bytes in the last page */
+ struct bitmap_storage {
+ struct file *file; /* backing disk file */
+ struct page *sb_page; /* cached copy of the bitmap
+ * file superblock */
+ struct page **filemap; /* list of cache pages for
+ * the file */
+ unsigned long *filemap_attr; /* attributes associated
+ * w/ filemap pages */
+ unsigned long file_pages; /* number of pages in the file*/
+ unsigned long bytes; /* total bytes in the bitmap */
+ } storage;
unsigned long flags;
@@ -242,6 +257,9 @@ void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector);
void bitmap_unplug(struct bitmap *bitmap);
void bitmap_daemon_work(struct mddev *mddev);
+
+int bitmap_resize(struct bitmap *bitmap, sector_t blocks,
+ int chunksize, int init);
#endif
#endif
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index 68965e663248..017c34d78d61 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -155,10 +155,7 @@ static void context_free(struct raid_set *rs)
for (i = 0; i < rs->md.raid_disks; i++) {
if (rs->dev[i].meta_dev)
dm_put_device(rs->ti, rs->dev[i].meta_dev);
- if (rs->dev[i].rdev.sb_page)
- put_page(rs->dev[i].rdev.sb_page);
- rs->dev[i].rdev.sb_page = NULL;
- rs->dev[i].rdev.sb_loaded = 0;
+ md_rdev_clear(&rs->dev[i].rdev);
if (rs->dev[i].data_dev)
dm_put_device(rs->ti, rs->dev[i].data_dev);
}
@@ -606,7 +603,7 @@ static int read_disk_sb(struct md_rdev *rdev, int size)
if (!sync_page_io(rdev, 0, size, rdev->sb_page, READ, 1)) {
DMERR("Failed to read superblock of device at position %d",
rdev->raid_disk);
- set_bit(Faulty, &rdev->flags);
+ md_error(rdev->mddev, rdev);
return -EINVAL;
}
@@ -617,16 +614,18 @@ static int read_disk_sb(struct md_rdev *rdev, int size)
static void super_sync(struct mddev *mddev, struct md_rdev *rdev)
{
- struct md_rdev *r;
+ int i;
uint64_t failed_devices;
struct dm_raid_superblock *sb;
+ struct raid_set *rs = container_of(mddev, struct raid_set, md);
sb = page_address(rdev->sb_page);
failed_devices = le64_to_cpu(sb->failed_devices);
- rdev_for_each(r, mddev)
- if ((r->raid_disk >= 0) && test_bit(Faulty, &r->flags))
- failed_devices |= (1ULL << r->raid_disk);
+ for (i = 0; i < mddev->raid_disks; i++)
+ if (!rs->dev[i].data_dev ||
+ test_bit(Faulty, &(rs->dev[i].rdev.flags)))
+ failed_devices |= (1ULL << i);
memset(sb, 0, sizeof(*sb));
@@ -1252,12 +1251,13 @@ static void raid_resume(struct dm_target *ti)
{
struct raid_set *rs = ti->private;
+ set_bit(MD_CHANGE_DEVS, &rs->md.flags);
if (!rs->bitmap_loaded) {
bitmap_load(&rs->md);
rs->bitmap_loaded = 1;
- } else
- md_wakeup_thread(rs->md.thread);
+ }
+ clear_bit(MD_RECOVERY_FROZEN, &rs->md.recovery);
mddev_resume(&rs->md);
}
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 01233d855eb2..1c2f9048e1ae 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -402,6 +402,7 @@ void mddev_resume(struct mddev *mddev)
wake_up(&mddev->sb_wait);
mddev->pers->quiesce(mddev, 0);
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
md_wakeup_thread(mddev->thread);
md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
}
@@ -452,7 +453,7 @@ static void submit_flushes(struct work_struct *ws)
atomic_inc(&rdev->nr_pending);
atomic_inc(&rdev->nr_pending);
rcu_read_unlock();
- bi = bio_alloc_mddev(GFP_KERNEL, 0, mddev);
+ bi = bio_alloc_mddev(GFP_NOIO, 0, mddev);
bi->bi_end_io = md_end_flush;
bi->bi_private = rdev;
bi->bi_bdev = rdev->bdev;
@@ -607,6 +608,7 @@ void mddev_init(struct mddev *mddev)
init_waitqueue_head(&mddev->sb_wait);
init_waitqueue_head(&mddev->recovery_wait);
mddev->reshape_position = MaxSector;
+ mddev->reshape_backwards = 0;
mddev->resync_min = 0;
mddev->resync_max = MaxSector;
mddev->level = LEVEL_NONE;
@@ -802,7 +804,7 @@ static int alloc_disk_sb(struct md_rdev * rdev)
return 0;
}
-static void free_disk_sb(struct md_rdev * rdev)
+void md_rdev_clear(struct md_rdev *rdev)
{
if (rdev->sb_page) {
put_page(rdev->sb_page);
@@ -815,8 +817,10 @@ static void free_disk_sb(struct md_rdev * rdev)
put_page(rdev->bb_page);
rdev->bb_page = NULL;
}
+ kfree(rdev->badblocks.page);
+ rdev->badblocks.page = NULL;
}
-
+EXPORT_SYMBOL_GPL(md_rdev_clear);
static void super_written(struct bio *bio, int error)
{
@@ -887,6 +891,10 @@ int sync_page_io(struct md_rdev *rdev, sector_t sector, int size,
rdev->meta_bdev : rdev->bdev;
if (metadata_op)
bio->bi_sector = sector + rdev->sb_start;
+ else if (rdev->mddev->reshape_position != MaxSector &&
+ (rdev->mddev->reshape_backwards ==
+ (sector >= rdev->mddev->reshape_position)))
+ bio->bi_sector = sector + rdev->new_data_offset;
else
bio->bi_sector = sector + rdev->data_offset;
bio_add_page(bio, page, size, 0);
@@ -1034,12 +1042,17 @@ static unsigned int calc_sb_csum(mdp_super_t * sb)
struct super_type {
char *name;
struct module *owner;
- int (*load_super)(struct md_rdev *rdev, struct md_rdev *refdev,
+ int (*load_super)(struct md_rdev *rdev,
+ struct md_rdev *refdev,
int minor_version);
- int (*validate_super)(struct mddev *mddev, struct md_rdev *rdev);
- void (*sync_super)(struct mddev *mddev, struct md_rdev *rdev);
+ int (*validate_super)(struct mddev *mddev,
+ struct md_rdev *rdev);
+ void (*sync_super)(struct mddev *mddev,
+ struct md_rdev *rdev);
unsigned long long (*rdev_size_change)(struct md_rdev *rdev,
sector_t num_sectors);
+ int (*allow_new_offset)(struct md_rdev *rdev,
+ unsigned long long new_offset);
};
/*
@@ -1111,6 +1124,7 @@ static int super_90_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor
rdev->preferred_minor = sb->md_minor;
rdev->data_offset = 0;
+ rdev->new_data_offset = 0;
rdev->sb_size = MD_SB_BYTES;
rdev->badblocks.shift = -1;
@@ -1184,7 +1198,11 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev)
mddev->dev_sectors = ((sector_t)sb->size) * 2;
mddev->events = ev1;
mddev->bitmap_info.offset = 0;
+ mddev->bitmap_info.space = 0;
+ /* bitmap can use 60 K after the 4K superblocks */
mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;
+ mddev->bitmap_info.default_space = 64*2 - (MD_SB_BYTES >> 9);
+ mddev->reshape_backwards = 0;
if (mddev->minor_version >= 91) {
mddev->reshape_position = sb->reshape_position;
@@ -1192,6 +1210,8 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev)
mddev->new_level = sb->new_level;
mddev->new_layout = sb->new_layout;
mddev->new_chunk_sectors = sb->new_chunk >> 9;
+ if (mddev->delta_disks < 0)
+ mddev->reshape_backwards = 1;
} else {
mddev->reshape_position = MaxSector;
mddev->delta_disks = 0;
@@ -1218,9 +1238,12 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev)
mddev->max_disks = MD_SB_DISKS;
if (sb->state & (1<<MD_SB_BITMAP_PRESENT) &&
- mddev->bitmap_info.file == NULL)
+ mddev->bitmap_info.file == NULL) {
mddev->bitmap_info.offset =
mddev->bitmap_info.default_offset;
+ mddev->bitmap_info.space =
+ mddev->bitmap_info.space;
+ }
} else if (mddev->pers == NULL) {
/* Insist on good event counter while assembling, except
@@ -1434,6 +1457,12 @@ super_90_rdev_size_change(struct md_rdev *rdev, sector_t num_sectors)
return num_sectors;
}
+static int
+super_90_allow_new_offset(struct md_rdev *rdev, unsigned long long new_offset)
+{
+ /* non-zero offset changes not possible with v0.90 */
+ return new_offset == 0;
+}
/*
* version 1 superblock
@@ -1469,6 +1498,7 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
struct mdp_superblock_1 *sb;
int ret;
sector_t sb_start;
+ sector_t sectors;
char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE];
int bmask;
@@ -1523,9 +1553,18 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
bdevname(rdev->bdev,b));
return -EINVAL;
}
+ if (sb->pad0 ||
+ sb->pad3[0] ||
+ memcmp(sb->pad3, sb->pad3+1, sizeof(sb->pad3) - sizeof(sb->pad3[1])))
+ /* Some padding is non-zero, might be a new feature */
+ return -EINVAL;
rdev->preferred_minor = 0xffff;
rdev->data_offset = le64_to_cpu(sb->data_offset);
+ rdev->new_data_offset = rdev->data_offset;
+ if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE) &&
+ (le32_to_cpu(sb->feature_map) & MD_FEATURE_NEW_OFFSET))
+ rdev->new_data_offset += (s32)le32_to_cpu(sb->new_offset);
atomic_set(&rdev->corrected_errors, le32_to_cpu(sb->cnt_corrected_read));
rdev->sb_size = le32_to_cpu(sb->max_dev) * 2 + 256;
@@ -1536,6 +1575,9 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
if (minor_version
&& rdev->data_offset < sb_start + (rdev->sb_size/512))
return -EINVAL;
+ if (minor_version
+ && rdev->new_data_offset < sb_start + (rdev->sb_size/512))
+ return -EINVAL;
if (sb->level == cpu_to_le32(LEVEL_MULTIPATH))
rdev->desc_nr = -1;
@@ -1607,16 +1649,14 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
else
ret = 0;
}
- if (minor_version)
- rdev->sectors = (i_size_read(rdev->bdev->bd_inode) >> 9) -
- le64_to_cpu(sb->data_offset);
- else
- rdev->sectors = rdev->sb_start;
- if (rdev->sectors < le64_to_cpu(sb->data_size))
+ if (minor_version) {
+ sectors = (i_size_read(rdev->bdev->bd_inode) >> 9);
+ sectors -= rdev->data_offset;
+ } else
+ sectors = rdev->sb_start;
+ if (sectors < le64_to_cpu(sb->data_size))
return -EINVAL;
rdev->sectors = le64_to_cpu(sb->data_size);
- if (le64_to_cpu(sb->size) > rdev->sectors)
- return -EINVAL;
return ret;
}
@@ -1644,17 +1684,37 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
mddev->dev_sectors = le64_to_cpu(sb->size);
mddev->events = ev1;
mddev->bitmap_info.offset = 0;
+ mddev->bitmap_info.space = 0;
+ /* Default location for bitmap is 1K after superblock
+ * using 3K - total of 4K
+ */
mddev->bitmap_info.default_offset = 1024 >> 9;
-
+ mddev->bitmap_info.default_space = (4096-1024) >> 9;
+ mddev->reshape_backwards = 0;
+
mddev->recovery_cp = le64_to_cpu(sb->resync_offset);
memcpy(mddev->uuid, sb->set_uuid, 16);
mddev->max_disks = (4096-256)/2;
if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET) &&
- mddev->bitmap_info.file == NULL )
+ mddev->bitmap_info.file == NULL) {
mddev->bitmap_info.offset =
(__s32)le32_to_cpu(sb->bitmap_offset);
+ /* Metadata doesn't record how much space is available.
+ * For 1.0, we assume we can use up to the superblock
+ * if before, else to 4K beyond superblock.
+ * For others, assume no change is possible.
+ */
+ if (mddev->minor_version > 0)
+ mddev->bitmap_info.space = 0;
+ else if (mddev->bitmap_info.offset > 0)
+ mddev->bitmap_info.space =
+ 8 - mddev->bitmap_info.offset;
+ else
+ mddev->bitmap_info.space =
+ -mddev->bitmap_info.offset;
+ }
if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_RESHAPE_ACTIVE)) {
mddev->reshape_position = le64_to_cpu(sb->reshape_position);
@@ -1662,6 +1722,11 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
mddev->new_level = le32_to_cpu(sb->new_level);
mddev->new_layout = le32_to_cpu(sb->new_layout);
mddev->new_chunk_sectors = le32_to_cpu(sb->new_chunk);
+ if (mddev->delta_disks < 0 ||
+ (mddev->delta_disks == 0 &&
+ (le32_to_cpu(sb->feature_map)
+ & MD_FEATURE_RESHAPE_BACKWARDS)))
+ mddev->reshape_backwards = 1;
} else {
mddev->reshape_position = MaxSector;
mddev->delta_disks = 0;
@@ -1735,7 +1800,6 @@ static void super_1_sync(struct mddev *mddev, struct md_rdev *rdev)
sb->feature_map = 0;
sb->pad0 = 0;
sb->recovery_offset = cpu_to_le64(0);
- memset(sb->pad1, 0, sizeof(sb->pad1));
memset(sb->pad3, 0, sizeof(sb->pad3));
sb->utime = cpu_to_le64((__u64)mddev->utime);
@@ -1757,6 +1821,8 @@ static void super_1_sync(struct mddev *mddev, struct md_rdev *rdev)
sb->devflags |= WriteMostly1;
else
sb->devflags &= ~WriteMostly1;
+ sb->data_offset = cpu_to_le64(rdev->data_offset);
+ sb->data_size = cpu_to_le64(rdev->sectors);
if (mddev->bitmap && mddev->bitmap_info.file == NULL) {
sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_info.offset);
@@ -1781,6 +1847,16 @@ static void super_1_sync(struct mddev *mddev, struct md_rdev *rdev)
sb->delta_disks = cpu_to_le32(mddev->delta_disks);
sb->new_level = cpu_to_le32(mddev->new_level);
sb->new_chunk = cpu_to_le32(mddev->new_chunk_sectors);
+ if (mddev->delta_disks == 0 &&
+ mddev->reshape_backwards)
+ sb->feature_map
+ |= cpu_to_le32(MD_FEATURE_RESHAPE_BACKWARDS);
+ if (rdev->new_data_offset != rdev->data_offset) {
+ sb->feature_map
+ |= cpu_to_le32(MD_FEATURE_NEW_OFFSET);
+ sb->new_offset = cpu_to_le32((__u32)(rdev->new_data_offset
+ - rdev->data_offset));
+ }
}
if (rdev->badblocks.count == 0)
@@ -1857,6 +1933,8 @@ super_1_rdev_size_change(struct md_rdev *rdev, sector_t num_sectors)
sector_t max_sectors;
if (num_sectors && num_sectors < rdev->mddev->dev_sectors)
return 0; /* component must fit device */
+ if (rdev->data_offset != rdev->new_data_offset)
+ return 0; /* too confusing */
if (rdev->sb_start < rdev->data_offset) {
/* minor versions 1 and 2; superblock before data */
max_sectors = i_size_read(rdev->bdev->bd_inode) >> 9;
@@ -1884,6 +1962,40 @@ super_1_rdev_size_change(struct md_rdev *rdev, sector_t num_sectors)
rdev->sb_page);
md_super_wait(rdev->mddev);
return num_sectors;
+
+}
+
+static int
+super_1_allow_new_offset(struct md_rdev *rdev,
+ unsigned long long new_offset)
+{
+ /* All necessary checks on new >= old have been done */
+ struct bitmap *bitmap;
+ if (new_offset >= rdev->data_offset)
+ return 1;
+
+ /* with 1.0 metadata, there is no metadata to tread on
+ * so we can always move back */
+ if (rdev->mddev->minor_version == 0)
+ return 1;
+
+ /* otherwise we must be sure not to step on
+ * any metadata, so stay:
+ * 36K beyond start of superblock
+ * beyond end of badblocks
+ * beyond write-intent bitmap
+ */
+ if (rdev->sb_start + (32+4)*2 > new_offset)
+ return 0;
+ bitmap = rdev->mddev->bitmap;
+ if (bitmap && !rdev->mddev->bitmap_info.file &&
+ rdev->sb_start + rdev->mddev->bitmap_info.offset +
+ bitmap->storage.file_pages * (PAGE_SIZE>>9) > new_offset)
+ return 0;
+ if (rdev->badblocks.sector + rdev->badblocks.size > new_offset)
+ return 0;
+
+ return 1;
}
static struct super_type super_types[] = {
@@ -1894,6 +2006,7 @@ static struct super_type super_types[] = {
.validate_super = super_90_validate,
.sync_super = super_90_sync,
.rdev_size_change = super_90_rdev_size_change,
+ .allow_new_offset = super_90_allow_new_offset,
},
[1] = {
.name = "md-1",
@@ -1902,6 +2015,7 @@ static struct super_type super_types[] = {
.validate_super = super_1_validate,
.sync_super = super_1_sync,
.rdev_size_change = super_1_rdev_size_change,
+ .allow_new_offset = super_1_allow_new_offset,
},
};
@@ -2105,9 +2219,7 @@ static void unbind_rdev_from_array(struct md_rdev * rdev)
sysfs_remove_link(&rdev->kobj, "block");
sysfs_put(rdev->sysfs_state);
rdev->sysfs_state = NULL;
- kfree(rdev->badblocks.page);
rdev->badblocks.count = 0;
- rdev->badblocks.page = NULL;
/* We need to delay this, otherwise we can deadlock when
* writing to 'remove' to "dev/state". We also need
* to delay it due to rcu usage.
@@ -2158,7 +2270,7 @@ static void export_rdev(struct md_rdev * rdev)
bdevname(rdev->bdev,b));
if (rdev->mddev)
MD_BUG();
- free_disk_sb(rdev);
+ md_rdev_clear(rdev);
#ifndef MODULE
if (test_bit(AutoDetected, &rdev->flags))
md_autodetect_dev(rdev->bdev->bd_dev);
@@ -2809,9 +2921,8 @@ offset_show(struct md_rdev *rdev, char *page)
static ssize_t
offset_store(struct md_rdev *rdev, const char *buf, size_t len)
{
- char *e;
- unsigned long long offset = simple_strtoull(buf, &e, 10);
- if (e==buf || (*e && *e != '\n'))
+ unsigned long long offset;
+ if (strict_strtoull(buf, 10, &offset) < 0)
return -EINVAL;
if (rdev->mddev->pers && rdev->raid_disk >= 0)
return -EBUSY;
@@ -2826,6 +2937,63 @@ offset_store(struct md_rdev *rdev, const char *buf, size_t len)
static struct rdev_sysfs_entry rdev_offset =
__ATTR(offset, S_IRUGO|S_IWUSR, offset_show, offset_store);
+static ssize_t new_offset_show(struct md_rdev *rdev, char *page)
+{
+ return sprintf(page, "%llu\n",
+ (unsigned long long)rdev->new_data_offset);
+}
+
+static ssize_t new_offset_store(struct md_rdev *rdev,
+ const char *buf, size_t len)
+{
+ unsigned long long new_offset;
+ struct mddev *mddev = rdev->mddev;
+
+ if (strict_strtoull(buf, 10, &new_offset) < 0)
+ return -EINVAL;
+
+ if (mddev->sync_thread)
+ return -EBUSY;
+ if (new_offset == rdev->data_offset)
+ /* reset is always permitted */
+ ;
+ else if (new_offset > rdev->data_offset) {
+ /* must not push array size beyond rdev_sectors */
+ if (new_offset - rdev->data_offset
+ + mddev->dev_sectors > rdev->sectors)
+ return -E2BIG;
+ }
+ /* Metadata worries about other space details. */
+
+ /* decreasing the offset is inconsistent with a backwards
+ * reshape.
+ */
+ if (new_offset < rdev->data_offset &&
+ mddev->reshape_backwards)
+ return -EINVAL;
+ /* Increasing offset is inconsistent with forwards
+ * reshape. reshape_direction should be set to
+ * 'backwards' first.
+ */
+ if (new_offset > rdev->data_offset &&
+ !mddev->reshape_backwards)
+ return -EINVAL;
+
+ if (mddev->pers && mddev->persistent &&
+ !super_types[mddev->major_version]
+ .allow_new_offset(rdev, new_offset))
+ return -E2BIG;
+ rdev->new_data_offset = new_offset;
+ if (new_offset > rdev->data_offset)
+ mddev->reshape_backwards = 1;
+ else if (new_offset < rdev->data_offset)
+ mddev->reshape_backwards = 0;
+
+ return len;
+}
+static struct rdev_sysfs_entry rdev_new_offset =
+__ATTR(new_offset, S_IRUGO|S_IWUSR, new_offset_show, new_offset_store);
+
static ssize_t
rdev_size_show(struct md_rdev *rdev, char *page)
{
@@ -2870,6 +3038,8 @@ rdev_size_store(struct md_rdev *rdev, const char *buf, size_t len)
if (strict_blocks_to_sectors(buf, &sectors) < 0)
return -EINVAL;
+ if (rdev->data_offset != rdev->new_data_offset)
+ return -EINVAL; /* too confusing */
if (my_mddev->pers && rdev->raid_disk >= 0) {
if (my_mddev->persistent) {
sectors = super_types[my_mddev->major_version].
@@ -3006,6 +3176,7 @@ static struct attribute *rdev_default_attrs[] = {
&rdev_errors.attr,
&rdev_slot.attr,
&rdev_offset.attr,
+ &rdev_new_offset.attr,
&rdev_size.attr,
&rdev_recovery_start.attr,
&rdev_bad_blocks.attr,
@@ -3080,6 +3251,7 @@ int md_rdev_init(struct md_rdev *rdev)
rdev->raid_disk = -1;
rdev->flags = 0;
rdev->data_offset = 0;
+ rdev->new_data_offset = 0;
rdev->sb_events = 0;
rdev->last_read_error.tv_sec = 0;
rdev->last_read_error.tv_nsec = 0;
@@ -3178,8 +3350,7 @@ static struct md_rdev *md_import_device(dev_t newdev, int super_format, int supe
abort_free:
if (rdev->bdev)
unlock_rdev(rdev);
- free_disk_sb(rdev);
- kfree(rdev->badblocks.page);
+ md_rdev_clear(rdev);
kfree(rdev);
return ERR_PTR(err);
}
@@ -3419,6 +3590,7 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
mddev->new_chunk_sectors = mddev->chunk_sectors;
mddev->raid_disks -= mddev->delta_disks;
mddev->delta_disks = 0;
+ mddev->reshape_backwards = 0;
module_put(pers->owner);
printk(KERN_WARNING "md: %s: %s would not accept array\n",
mdname(mddev), clevel);
@@ -3492,6 +3664,7 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
mddev->layout = mddev->new_layout;
mddev->chunk_sectors = mddev->new_chunk_sectors;
mddev->delta_disks = 0;
+ mddev->reshape_backwards = 0;
mddev->degraded = 0;
if (mddev->pers->sync_request == NULL) {
/* this is now an array without redundancy, so
@@ -3501,10 +3674,8 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
del_timer_sync(&mddev->safemode_timer);
}
pers->run(mddev);
- mddev_resume(mddev);
set_bit(MD_CHANGE_DEVS, &mddev->flags);
- set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
- md_wakeup_thread(mddev->thread);
+ mddev_resume(mddev);
sysfs_notify(&mddev->kobj, NULL, "level");
md_new_event(mddev);
return rv;
@@ -3582,9 +3753,20 @@ raid_disks_store(struct mddev *mddev, const char *buf, size_t len)
if (mddev->pers)
rv = update_raid_disks(mddev, n);
else if (mddev->reshape_position != MaxSector) {
+ struct md_rdev *rdev;
int olddisks = mddev->raid_disks - mddev->delta_disks;
+
+ rdev_for_each(rdev, mddev) {
+ if (olddisks < n &&
+ rdev->data_offset < rdev->new_data_offset)
+ return -EINVAL;
+ if (olddisks > n &&
+ rdev->data_offset > rdev->new_data_offset)
+ return -EINVAL;
+ }
mddev->delta_disks = n - olddisks;
mddev->raid_disks = n;
+ mddev->reshape_backwards = (mddev->delta_disks < 0);
} else
mddev->raid_disks = n;
return rv ? rv : len;
@@ -4266,7 +4448,8 @@ sync_completed_show(struct mddev *mddev, char *page)
if (!test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
return sprintf(page, "none\n");
- if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
+ if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ||
+ test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
max_sectors = mddev->resync_max_sectors;
else
max_sectors = mddev->dev_sectors;
@@ -4428,6 +4611,7 @@ reshape_position_show(struct mddev *mddev, char *page)
static ssize_t
reshape_position_store(struct mddev *mddev, const char *buf, size_t len)
{
+ struct md_rdev *rdev;
char *e;
unsigned long long new = simple_strtoull(buf, &e, 10);
if (mddev->pers)
@@ -4436,9 +4620,12 @@ reshape_position_store(struct mddev *mddev, const char *buf, size_t len)
return -EINVAL;
mddev->reshape_position = new;
mddev->delta_disks = 0;
+ mddev->reshape_backwards = 0;
mddev->new_level = mddev->level;
mddev->new_layout = mddev->layout;
mddev->new_chunk_sectors = mddev->chunk_sectors;
+ rdev_for_each(rdev, mddev)
+ rdev->new_data_offset = rdev->data_offset;
return len;
}
@@ -4447,6 +4634,42 @@ __ATTR(reshape_position, S_IRUGO|S_IWUSR, reshape_position_show,
reshape_position_store);
static ssize_t
+reshape_direction_show(struct mddev *mddev, char *page)
+{
+ return sprintf(page, "%s\n",
+ mddev->reshape_backwards ? "backwards" : "forwards");
+}
+
+static ssize_t
+reshape_direction_store(struct mddev *mddev, const char *buf, size_t len)
+{
+ int backwards = 0;
+ if (cmd_match(buf, "forwards"))
+ backwards = 0;
+ else if (cmd_match(buf, "backwards"))
+ backwards = 1;
+ else
+ return -EINVAL;
+ if (mddev->reshape_backwards == backwards)
+ return len;
+
+ /* check if we are allowed to change */
+ if (mddev->delta_disks)
+ return -EBUSY;
+
+ if (mddev->persistent &&
+ mddev->major_version == 0)
+ return -EINVAL;
+
+ mddev->reshape_backwards = backwards;
+ return len;
+}
+
+static struct md_sysfs_entry md_reshape_direction =
+__ATTR(reshape_direction, S_IRUGO|S_IWUSR, reshape_direction_show,
+ reshape_direction_store);
+
+static ssize_t
array_size_show(struct mddev *mddev, char *page)
{
if (mddev->external_size)
@@ -4501,6 +4724,7 @@ static struct attribute *md_default_attrs[] = {
&md_safe_delay.attr,
&md_array_state.attr,
&md_reshape_position.attr,
+ &md_reshape_direction.attr,
&md_array_size.attr,
&max_corr_read_errors.attr,
NULL,
@@ -4914,7 +5138,8 @@ int md_run(struct mddev *mddev)
err = -EINVAL;
mddev->pers->stop(mddev);
}
- if (err == 0 && mddev->pers->sync_request) {
+ if (err == 0 && mddev->pers->sync_request &&
+ (mddev->bitmap_info.file || mddev->bitmap_info.offset)) {
err = bitmap_create(mddev);
if (err) {
printk(KERN_ERR "%s: failed to create bitmap (%d)\n",
@@ -5064,6 +5289,7 @@ static void md_clean(struct mddev *mddev)
mddev->events = 0;
mddev->can_decrease_events = 0;
mddev->delta_disks = 0;
+ mddev->reshape_backwards = 0;
mddev->new_level = LEVEL_NONE;
mddev->new_layout = 0;
mddev->new_chunk_sectors = 0;
@@ -5079,6 +5305,7 @@ static void md_clean(struct mddev *mddev)
mddev->merge_check_needed = 0;
mddev->bitmap_info.offset = 0;
mddev->bitmap_info.default_offset = 0;
+ mddev->bitmap_info.default_space = 0;
mddev->bitmap_info.chunksize = 0;
mddev->bitmap_info.daemon_sleep = 0;
mddev->bitmap_info.max_write_behind = 0;
@@ -5421,7 +5648,7 @@ static int get_bitmap_file(struct mddev * mddev, void __user * arg)
goto out;
/* bitmap disabled, zero the first byte and copy out */
- if (!mddev->bitmap || !mddev->bitmap->file) {
+ if (!mddev->bitmap || !mddev->bitmap->storage.file) {
file->pathname[0] = '\0';
goto copy_out;
}
@@ -5430,7 +5657,8 @@ static int get_bitmap_file(struct mddev * mddev, void __user * arg)
if (!buf)
goto out;
- ptr = d_path(&mddev->bitmap->file->f_path, buf, sizeof(file->pathname));
+ ptr = d_path(&mddev->bitmap->storage.file->f_path,
+ buf, sizeof(file->pathname));
if (IS_ERR(ptr))
goto out;
@@ -5875,6 +6103,7 @@ static int set_array_info(struct mddev * mddev, mdu_array_info_t *info)
set_bit(MD_CHANGE_DEVS, &mddev->flags);
mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;
+ mddev->bitmap_info.default_space = 64*2 - (MD_SB_BYTES >> 9);
mddev->bitmap_info.offset = 0;
mddev->reshape_position = MaxSector;
@@ -5888,6 +6117,7 @@ static int set_array_info(struct mddev * mddev, mdu_array_info_t *info)
mddev->new_chunk_sectors = mddev->chunk_sectors;
mddev->new_layout = mddev->layout;
mddev->delta_disks = 0;
+ mddev->reshape_backwards = 0;
return 0;
}
@@ -5922,11 +6152,7 @@ static int update_size(struct mddev *mddev, sector_t num_sectors)
*/
if (mddev->sync_thread)
return -EBUSY;
- if (mddev->bitmap)
- /* Sorry, cannot grow a bitmap yet, just remove it,
- * grow, and re-add.
- */
- return -EBUSY;
+
rdev_for_each(rdev, mddev) {
sector_t avail = rdev->sectors;
@@ -5944,6 +6170,7 @@ static int update_size(struct mddev *mddev, sector_t num_sectors)
static int update_raid_disks(struct mddev *mddev, int raid_disks)
{
int rv;
+ struct md_rdev *rdev;
/* change the number of raid disks */
if (mddev->pers->check_reshape == NULL)
return -EINVAL;
@@ -5952,11 +6179,27 @@ static int update_raid_disks(struct mddev *mddev, int raid_disks)
return -EINVAL;
if (mddev->sync_thread || mddev->reshape_position != MaxSector)
return -EBUSY;
+
+ rdev_for_each(rdev, mddev) {
+ if (mddev->raid_disks < raid_disks &&
+ rdev->data_offset < rdev->new_data_offset)
+ return -EINVAL;
+ if (mddev->raid_disks > raid_disks &&
+ rdev->data_offset > rdev->new_data_offset)
+ return -EINVAL;
+ }
+
mddev->delta_disks = raid_disks - mddev->raid_disks;
+ if (mddev->delta_disks < 0)
+ mddev->reshape_backwards = 1;
+ else if (mddev->delta_disks > 0)
+ mddev->reshape_backwards = 0;
rv = mddev->pers->check_reshape(mddev);
- if (rv < 0)
+ if (rv < 0) {
mddev->delta_disks = 0;
+ mddev->reshape_backwards = 0;
+ }
return rv;
}
@@ -6039,6 +6282,8 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info)
return -EINVAL;
mddev->bitmap_info.offset =
mddev->bitmap_info.default_offset;
+ mddev->bitmap_info.space =
+ mddev->bitmap_info.default_space;
mddev->pers->quiesce(mddev, 1);
rv = bitmap_create(mddev);
if (!rv)
@@ -6050,7 +6295,7 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info)
/* remove the bitmap */
if (!mddev->bitmap)
return -ENOENT;
- if (mddev->bitmap->file)
+ if (mddev->bitmap->storage.file)
return -EINVAL;
mddev->pers->quiesce(mddev, 1);
bitmap_destroy(mddev);
@@ -6373,6 +6618,9 @@ static int md_open(struct block_device *bdev, fmode_t mode)
struct mddev *mddev = mddev_find(bdev->bd_dev);
int err;
+ if (!mddev)
+ return -ENODEV;
+
if (mddev->gendisk != bdev->bd_disk) {
/* we are racing with mddev_put which is discarding this
* bd_disk.
@@ -6584,7 +6832,8 @@ static void status_resync(struct seq_file *seq, struct mddev * mddev)
resync = mddev->curr_resync - atomic_read(&mddev->recovery_active);
- if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
+ if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ||
+ test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
max_sectors = mddev->resync_max_sectors;
else
max_sectors = mddev->dev_sectors;
@@ -7147,7 +7396,7 @@ void md_do_sync(struct mddev *mddev)
j = mddev->recovery_cp;
} else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
- max_sectors = mddev->dev_sectors;
+ max_sectors = mddev->resync_max_sectors;
else {
/* recovery follows the physical size of devices */
max_sectors = mddev->dev_sectors;
@@ -7598,7 +7847,7 @@ void md_check_recovery(struct mddev *mddev)
goto unlock;
if (mddev->pers->sync_request) {
- if (spares && mddev->bitmap && ! mddev->bitmap->file) {
+ if (spares) {
/* We are adding a device or devices to an array
* which has the bitmap stored on all devices.
* So make sure all bitmap pages get written
@@ -7646,6 +7895,20 @@ void md_wait_for_blocked_rdev(struct md_rdev *rdev, struct mddev *mddev)
}
EXPORT_SYMBOL(md_wait_for_blocked_rdev);
+void md_finish_reshape(struct mddev *mddev)
+{
+ /* called be personality module when reshape completes. */
+ struct md_rdev *rdev;
+
+ rdev_for_each(rdev, mddev) {
+ if (rdev->data_offset > rdev->new_data_offset)
+ rdev->sectors += rdev->data_offset - rdev->new_data_offset;
+ else
+ rdev->sectors -= rdev->new_data_offset - rdev->data_offset;
+ rdev->data_offset = rdev->new_data_offset;
+ }
+}
+EXPORT_SYMBOL(md_finish_reshape);
/* Bad block management.
* We can record which blocks on each device are 'bad' and so just
@@ -7894,10 +8157,15 @@ static int md_set_badblocks(struct badblocks *bb, sector_t s, int sectors,
}
int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
- int acknowledged)
+ int is_new)
{
- int rv = md_set_badblocks(&rdev->badblocks,
- s + rdev->data_offset, sectors, acknowledged);
+ int rv;
+ if (is_new)
+ s += rdev->new_data_offset;
+ else
+ s += rdev->data_offset;
+ rv = md_set_badblocks(&rdev->badblocks,
+ s, sectors, 0);
if (rv) {
/* Make sure they get written out promptly */
sysfs_notify_dirent_safe(rdev->sysfs_state);
@@ -8003,11 +8271,15 @@ out:
return rv;
}
-int rdev_clear_badblocks(struct md_rdev *rdev, sector_t s, int sectors)
+int rdev_clear_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
+ int is_new)
{
+ if (is_new)
+ s += rdev->new_data_offset;
+ else
+ s += rdev->data_offset;
return md_clear_badblocks(&rdev->badblocks,
- s + rdev->data_offset,
- sectors);
+ s, sectors);
}
EXPORT_SYMBOL_GPL(rdev_clear_badblocks);
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 1c2063ccf48e..7b4a3c318cae 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -55,6 +55,7 @@ struct md_rdev {
int sb_loaded;
__u64 sb_events;
sector_t data_offset; /* start of data in array */
+ sector_t new_data_offset;/* only relevant while reshaping */
sector_t sb_start; /* offset of the super block (in 512byte sectors) */
int sb_size; /* bytes in the superblock */
int preferred_minor; /* autorun support */
@@ -193,8 +194,9 @@ static inline int is_badblock(struct md_rdev *rdev, sector_t s, int sectors,
return 0;
}
extern int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
- int acknowledged);
-extern int rdev_clear_badblocks(struct md_rdev *rdev, sector_t s, int sectors);
+ int is_new);
+extern int rdev_clear_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
+ int is_new);
extern void md_ack_all_badblocks(struct badblocks *bb);
struct mddev {
@@ -262,6 +264,7 @@ struct mddev {
sector_t reshape_position;
int delta_disks, new_level, new_layout;
int new_chunk_sectors;
+ int reshape_backwards;
atomic_t plug_cnt; /* If device is expecting
* more bios soon.
@@ -390,10 +393,13 @@ struct mddev {
* For external metadata, offset
* from start of device.
*/
+ unsigned long space; /* space available at this offset */
loff_t default_offset; /* this is the offset to use when
* hot-adding a bitmap. It should
* eventually be settable by sysfs.
*/
+ unsigned long default_space; /* space available at
+ * default offset */
struct mutex mutex;
unsigned long chunksize;
unsigned long daemon_sleep; /* how many jiffies between updates? */
@@ -591,6 +597,7 @@ extern void md_write_start(struct mddev *mddev, struct bio *bi);
extern void md_write_end(struct mddev *mddev);
extern void md_done_sync(struct mddev *mddev, int blocks, int ok);
extern void md_error(struct mddev *mddev, struct md_rdev *rdev);
+extern void md_finish_reshape(struct mddev *mddev);
extern int mddev_congested(struct mddev *mddev, int bits);
extern void md_flush_request(struct mddev *mddev, struct bio *bio);
@@ -615,6 +622,7 @@ extern int md_run(struct mddev *mddev);
extern void md_stop(struct mddev *mddev);
extern void md_stop_writes(struct mddev *mddev);
extern int md_rdev_init(struct md_rdev *rdev);
+extern void md_rdev_clear(struct md_rdev *rdev);
extern void mddev_suspend(struct mddev *mddev);
extern void mddev_resume(struct mddev *mddev);
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 15dd59b84e94..835de7168cd3 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1859,7 +1859,9 @@ static void fix_read_error(struct r1conf *conf, int read_disk,
rdev = conf->mirrors[d].rdev;
if (rdev &&
- test_bit(In_sync, &rdev->flags) &&
+ (test_bit(In_sync, &rdev->flags) ||
+ (!test_bit(Faulty, &rdev->flags) &&
+ rdev->recovery_offset >= sect + s)) &&
is_badblock(rdev, sect, s,
&first_bad, &bad_sectors) == 0 &&
sync_page_io(rdev, sect, s<<9,
@@ -2024,7 +2026,7 @@ static void handle_sync_write_finished(struct r1conf *conf, struct r1bio *r1_bio
continue;
if (test_bit(BIO_UPTODATE, &bio->bi_flags) &&
test_bit(R1BIO_MadeGood, &r1_bio->state)) {
- rdev_clear_badblocks(rdev, r1_bio->sector, s);
+ rdev_clear_badblocks(rdev, r1_bio->sector, s, 0);
}
if (!test_bit(BIO_UPTODATE, &bio->bi_flags) &&
test_bit(R1BIO_WriteError, &r1_bio->state)) {
@@ -2044,7 +2046,7 @@ static void handle_write_finished(struct r1conf *conf, struct r1bio *r1_bio)
struct md_rdev *rdev = conf->mirrors[m].rdev;
rdev_clear_badblocks(rdev,
r1_bio->sector,
- r1_bio->sectors);
+ r1_bio->sectors, 0);
rdev_dec_pending(rdev, conf->mddev);
} else if (r1_bio->bios[m] != NULL) {
/* This drive got a write error. We need to
@@ -2598,7 +2600,8 @@ static struct r1conf *setup_conf(struct mddev *mddev)
if (!disk->rdev ||
!test_bit(In_sync, &disk->rdev->flags)) {
disk->head_position = 0;
- if (disk->rdev)
+ if (disk->rdev &&
+ (disk->rdev->saved_raid_disk < 0))
conf->fullsync = 1;
} else if (conf->last_used < 0)
/*
@@ -2750,9 +2753,16 @@ static int raid1_resize(struct mddev *mddev, sector_t sectors)
* any io in the removed space completes, but it hardly seems
* worth it.
*/
- md_set_array_sectors(mddev, raid1_size(mddev, sectors, 0));
- if (mddev->array_sectors > raid1_size(mddev, sectors, 0))
+ sector_t newsize = raid1_size(mddev, sectors, 0);
+ if (mddev->external_size &&
+ mddev->array_sectors > newsize)
return -EINVAL;
+ if (mddev->bitmap) {
+ int ret = bitmap_resize(mddev->bitmap, newsize, 0, 0);
+ if (ret)
+ return ret;
+ }
+ md_set_array_sectors(mddev, newsize);
set_capacity(mddev->gendisk, mddev->array_sectors);
revalidate_disk(mddev->gendisk);
if (sectors > mddev->dev_sectors &&
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 3f91c2e1dfe7..987db37cb875 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -24,6 +24,7 @@
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/ratelimit.h>
+#include <linux/kthread.h>
#include "md.h"
#include "raid10.h"
#include "raid0.h"
@@ -68,6 +69,11 @@ static int max_queued_requests = 1024;
static void allow_barrier(struct r10conf *conf);
static void lower_barrier(struct r10conf *conf);
static int enough(struct r10conf *conf, int ignore);
+static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr,
+ int *skipped);
+static void reshape_request_write(struct mddev *mddev, struct r10bio *r10_bio);
+static void end_reshape_write(struct bio *bio, int error);
+static void end_reshape(struct r10conf *conf);
static void * r10bio_pool_alloc(gfp_t gfp_flags, void *data)
{
@@ -112,7 +118,8 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data)
if (!r10_bio)
return NULL;
- if (test_bit(MD_RECOVERY_SYNC, &conf->mddev->recovery))
+ if (test_bit(MD_RECOVERY_SYNC, &conf->mddev->recovery) ||
+ test_bit(MD_RECOVERY_RESHAPE, &conf->mddev->recovery))
nalloc = conf->copies; /* resync */
else
nalloc = 2; /* recovery */
@@ -140,9 +147,10 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data)
struct bio *rbio = r10_bio->devs[j].repl_bio;
bio = r10_bio->devs[j].bio;
for (i = 0; i < RESYNC_PAGES; i++) {
- if (j == 1 && !test_bit(MD_RECOVERY_SYNC,
- &conf->mddev->recovery)) {
- /* we can share bv_page's during recovery */
+ if (j > 0 && !test_bit(MD_RECOVERY_SYNC,
+ &conf->mddev->recovery)) {
+ /* we can share bv_page's during recovery
+ * and reshape */
struct bio *rbio = r10_bio->devs[0].bio;
page = rbio->bi_io_vec[i].bv_page;
get_page(page);
@@ -165,10 +173,11 @@ out_free_pages:
while (j--)
for (i = 0; i < RESYNC_PAGES ; i++)
safe_put_page(r10_bio->devs[j].bio->bi_io_vec[i].bv_page);
- j = -1;
+ j = 0;
out_free_bio:
- while (++j < nalloc) {
- bio_put(r10_bio->devs[j].bio);
+ for ( ; j < nalloc; j++) {
+ if (r10_bio->devs[j].bio)
+ bio_put(r10_bio->devs[j].bio);
if (r10_bio->devs[j].repl_bio)
bio_put(r10_bio->devs[j].repl_bio);
}
@@ -504,79 +513,96 @@ static void raid10_end_write_request(struct bio *bio, int error)
* sector offset to a virtual address
*/
-static void raid10_find_phys(struct r10conf *conf, struct r10bio *r10bio)
+static void __raid10_find_phys(struct geom *geo, struct r10bio *r10bio)
{
int n,f;
sector_t sector;
sector_t chunk;
sector_t stripe;
int dev;
-
int slot = 0;
/* now calculate first sector/dev */
- chunk = r10bio->sector >> conf->chunk_shift;
- sector = r10bio->sector & conf->chunk_mask;
+ chunk = r10bio->sector >> geo->chunk_shift;
+ sector = r10bio->sector & geo->chunk_mask;
- chunk *= conf->near_copies;
+ chunk *= geo->near_copies;
stripe = chunk;
- dev = sector_div(stripe, conf->raid_disks);
- if (conf->far_offset)
- stripe *= conf->far_copies;
+ dev = sector_div(stripe, geo->raid_disks);
+ if (geo->far_offset)
+ stripe *= geo->far_copies;
- sector += stripe << conf->chunk_shift;
+ sector += stripe << geo->chunk_shift;
/* and calculate all the others */
- for (n=0; n < conf->near_copies; n++) {
+ for (n = 0; n < geo->near_copies; n++) {
int d = dev;
sector_t s = sector;
r10bio->devs[slot].addr = sector;
r10bio->devs[slot].devnum = d;
slot++;
- for (f = 1; f < conf->far_copies; f++) {
- d += conf->near_copies;
- if (d >= conf->raid_disks)
- d -= conf->raid_disks;
- s += conf->stride;
+ for (f = 1; f < geo->far_copies; f++) {
+ d += geo->near_copies;
+ if (d >= geo->raid_disks)
+ d -= geo->raid_disks;
+ s += geo->stride;
r10bio->devs[slot].devnum = d;
r10bio->devs[slot].addr = s;
slot++;
}
dev++;
- if (dev >= conf->raid_disks) {
+ if (dev >= geo->raid_disks) {
dev = 0;
- sector += (conf->chunk_mask + 1);
+ sector += (geo->chunk_mask + 1);
}
}
- BUG_ON(slot != conf->copies);
+}
+
+static void raid10_find_phys(struct r10conf *conf, struct r10bio *r10bio)
+{
+ struct geom *geo = &conf->geo;
+
+ if (conf->reshape_progress != MaxSector &&
+ ((r10bio->sector >= conf->reshape_progress) !=
+ conf->mddev->reshape_backwards)) {
+ set_bit(R10BIO_Previous, &r10bio->state);
+ geo = &conf->prev;
+ } else
+ clear_bit(R10BIO_Previous, &r10bio->state);
+
+ __raid10_find_phys(geo, r10bio);
}
static sector_t raid10_find_virt(struct r10conf *conf, sector_t sector, int dev)
{
sector_t offset, chunk, vchunk;
+ /* Never use conf->prev as this is only called during resync
+ * or recovery, so reshape isn't happening
+ */
+ struct geom *geo = &conf->geo;
- offset = sector & conf->chunk_mask;
- if (conf->far_offset) {
+ offset = sector & geo->chunk_mask;
+ if (geo->far_offset) {
int fc;
- chunk = sector >> conf->chunk_shift;
- fc = sector_div(chunk, conf->far_copies);
- dev -= fc * conf->near_copies;
+ chunk = sector >> geo->chunk_shift;
+ fc = sector_div(chunk, geo->far_copies);
+ dev -= fc * geo->near_copies;
if (dev < 0)
- dev += conf->raid_disks;
+ dev += geo->raid_disks;
} else {
- while (sector >= conf->stride) {
- sector -= conf->stride;
- if (dev < conf->near_copies)
- dev += conf->raid_disks - conf->near_copies;
+ while (sector >= geo->stride) {
+ sector -= geo->stride;
+ if (dev < geo->near_copies)
+ dev += geo->raid_disks - geo->near_copies;
else
- dev -= conf->near_copies;
+ dev -= geo->near_copies;
}
- chunk = sector >> conf->chunk_shift;
+ chunk = sector >> geo->chunk_shift;
}
- vchunk = chunk * conf->raid_disks + dev;
- sector_div(vchunk, conf->near_copies);
- return (vchunk << conf->chunk_shift) + offset;
+ vchunk = chunk * geo->raid_disks + dev;
+ sector_div(vchunk, geo->near_copies);
+ return (vchunk << geo->chunk_shift) + offset;
}
/**
@@ -597,10 +623,17 @@ static int raid10_mergeable_bvec(struct request_queue *q,
struct r10conf *conf = mddev->private;
sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
int max;
- unsigned int chunk_sectors = mddev->chunk_sectors;
+ unsigned int chunk_sectors;
unsigned int bio_sectors = bvm->bi_size >> 9;
+ struct geom *geo = &conf->geo;
+
+ chunk_sectors = (conf->geo.chunk_mask & conf->prev.chunk_mask) + 1;
+ if (conf->reshape_progress != MaxSector &&
+ ((sector >= conf->reshape_progress) !=
+ conf->mddev->reshape_backwards))
+ geo = &conf->prev;
- if (conf->near_copies < conf->raid_disks) {
+ if (geo->near_copies < geo->raid_disks) {
max = (chunk_sectors - ((sector & (chunk_sectors - 1))
+ bio_sectors)) << 9;
if (max < 0)
@@ -614,6 +647,12 @@ static int raid10_mergeable_bvec(struct request_queue *q,
if (mddev->merge_check_needed) {
struct r10bio r10_bio;
int s;
+ if (conf->reshape_progress != MaxSector) {
+ /* Cannot give any guidance during reshape */
+ if (max <= biovec->bv_len && bio_sectors == 0)
+ return biovec->bv_len;
+ return 0;
+ }
r10_bio.sector = sector;
raid10_find_phys(conf, &r10_bio);
rcu_read_lock();
@@ -681,6 +720,7 @@ static struct md_rdev *read_balance(struct r10conf *conf,
struct md_rdev *rdev, *best_rdev;
int do_balance;
int best_slot;
+ struct geom *geo = &conf->geo;
raid10_find_phys(conf, r10_bio);
rcu_read_lock();
@@ -761,11 +801,11 @@ retry:
* sequential read speed for 'far copies' arrays. So only
* keep it for 'near' arrays, and review those later.
*/
- if (conf->near_copies > 1 && !atomic_read(&rdev->nr_pending))
+ if (geo->near_copies > 1 && !atomic_read(&rdev->nr_pending))
break;
/* for far > 1 always use the lowest address */
- if (conf->far_copies > 1)
+ if (geo->far_copies > 1)
new_distance = r10_bio->devs[slot].addr;
else
new_distance = abs(r10_bio->devs[slot].addr -
@@ -812,7 +852,10 @@ static int raid10_congested(void *data, int bits)
if (mddev_congested(mddev, bits))
return 1;
rcu_read_lock();
- for (i = 0; i < conf->raid_disks && ret == 0; i++) {
+ for (i = 0;
+ (i < conf->geo.raid_disks || i < conf->prev.raid_disks)
+ && ret == 0;
+ i++) {
struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev);
if (rdev && !test_bit(Faulty, &rdev->flags)) {
struct request_queue *q = bdev_get_queue(rdev->bdev);
@@ -973,13 +1016,24 @@ static void unfreeze_array(struct r10conf *conf)
spin_unlock_irq(&conf->resync_lock);
}
+static sector_t choose_data_offset(struct r10bio *r10_bio,
+ struct md_rdev *rdev)
+{
+ if (!test_bit(MD_RECOVERY_RESHAPE, &rdev->mddev->recovery) ||
+ test_bit(R10BIO_Previous, &r10_bio->state))
+ return rdev->data_offset;
+ else
+ return rdev->new_data_offset;
+}
+
static void make_request(struct mddev *mddev, struct bio * bio)
{
struct r10conf *conf = mddev->private;
struct r10bio *r10_bio;
struct bio *read_bio;
int i;
- int chunk_sects = conf->chunk_mask + 1;
+ sector_t chunk_mask = (conf->geo.chunk_mask & conf->prev.chunk_mask);
+ int chunk_sects = chunk_mask + 1;
const int rw = bio_data_dir(bio);
const unsigned long do_sync = (bio->bi_rw & REQ_SYNC);
const unsigned long do_fua = (bio->bi_rw & REQ_FUA);
@@ -988,6 +1042,7 @@ static void make_request(struct mddev *mddev, struct bio * bio)
int plugged;
int sectors_handled;
int max_sectors;
+ int sectors;
if (unlikely(bio->bi_rw & REQ_FLUSH)) {
md_flush_request(mddev, bio);
@@ -997,9 +1052,10 @@ static void make_request(struct mddev *mddev, struct bio * bio)
/* If this request crosses a chunk boundary, we need to
* split it. This will only happen for 1 PAGE (or less) requests.
*/
- if (unlikely( (bio->bi_sector & conf->chunk_mask) + (bio->bi_size >> 9)
- > chunk_sects &&
- conf->near_copies < conf->raid_disks)) {
+ if (unlikely((bio->bi_sector & chunk_mask) + (bio->bi_size >> 9)
+ > chunk_sects
+ && (conf->geo.near_copies < conf->geo.raid_disks
+ || conf->prev.near_copies < conf->prev.raid_disks))) {
struct bio_pair *bp;
/* Sanity check -- queue functions should prevent this happening */
if (bio->bi_vcnt != 1 ||
@@ -1051,10 +1107,41 @@ static void make_request(struct mddev *mddev, struct bio * bio)
*/
wait_barrier(conf);
+ sectors = bio->bi_size >> 9;
+ while (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
+ bio->bi_sector < conf->reshape_progress &&
+ bio->bi_sector + sectors > conf->reshape_progress) {
+ /* IO spans the reshape position. Need to wait for
+ * reshape to pass
+ */
+ allow_barrier(conf);
+ wait_event(conf->wait_barrier,
+ conf->reshape_progress <= bio->bi_sector ||
+ conf->reshape_progress >= bio->bi_sector + sectors);
+ wait_barrier(conf);
+ }
+ if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
+ bio_data_dir(bio) == WRITE &&
+ (mddev->reshape_backwards
+ ? (bio->bi_sector < conf->reshape_safe &&
+ bio->bi_sector + sectors > conf->reshape_progress)
+ : (bio->bi_sector + sectors > conf->reshape_safe &&
+ bio->bi_sector < conf->reshape_progress))) {
+ /* Need to update reshape_position in metadata */
+ mddev->reshape_position = conf->reshape_progress;
+ set_bit(MD_CHANGE_DEVS, &mddev->flags);
+ set_bit(MD_CHANGE_PENDING, &mddev->flags);
+ md_wakeup_thread(mddev->thread);
+ wait_event(mddev->sb_wait,
+ !test_bit(MD_CHANGE_PENDING, &mddev->flags));
+
+ conf->reshape_safe = mddev->reshape_position;
+ }
+
r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO);
r10_bio->master_bio = bio;
- r10_bio->sectors = bio->bi_size >> 9;
+ r10_bio->sectors = sectors;
r10_bio->mddev = mddev;
r10_bio->sector = bio->bi_sector;
@@ -1093,7 +1180,7 @@ read_again:
r10_bio->devs[slot].rdev = rdev;
read_bio->bi_sector = r10_bio->devs[slot].addr +
- rdev->data_offset;
+ choose_data_offset(r10_bio, rdev);
read_bio->bi_bdev = rdev->bdev;
read_bio->bi_end_io = raid10_end_read_request;
read_bio->bi_rw = READ | do_sync;
@@ -1297,7 +1384,8 @@ retry_write:
r10_bio->devs[i].bio = mbio;
mbio->bi_sector = (r10_bio->devs[i].addr+
- conf->mirrors[d].rdev->data_offset);
+ choose_data_offset(r10_bio,
+ conf->mirrors[d].rdev));
mbio->bi_bdev = conf->mirrors[d].rdev->bdev;
mbio->bi_end_io = raid10_end_write_request;
mbio->bi_rw = WRITE | do_sync | do_fua;
@@ -1321,8 +1409,10 @@ retry_write:
* so it cannot disappear, so the replacement cannot
* become NULL here
*/
- mbio->bi_sector = (r10_bio->devs[i].addr+
- conf->mirrors[d].replacement->data_offset);
+ mbio->bi_sector = (r10_bio->devs[i].addr +
+ choose_data_offset(
+ r10_bio,
+ conf->mirrors[d].replacement));
mbio->bi_bdev = conf->mirrors[d].replacement->bdev;
mbio->bi_end_io = raid10_end_write_request;
mbio->bi_rw = WRITE | do_sync | do_fua;
@@ -1368,19 +1458,19 @@ static void status(struct seq_file *seq, struct mddev *mddev)
struct r10conf *conf = mddev->private;
int i;
- if (conf->near_copies < conf->raid_disks)
+ if (conf->geo.near_copies < conf->geo.raid_disks)
seq_printf(seq, " %dK chunks", mddev->chunk_sectors / 2);
- if (conf->near_copies > 1)
- seq_printf(seq, " %d near-copies", conf->near_copies);
- if (conf->far_copies > 1) {
- if (conf->far_offset)
- seq_printf(seq, " %d offset-copies", conf->far_copies);
+ if (conf->geo.near_copies > 1)
+ seq_printf(seq, " %d near-copies", conf->geo.near_copies);
+ if (conf->geo.far_copies > 1) {
+ if (conf->geo.far_offset)
+ seq_printf(seq, " %d offset-copies", conf->geo.far_copies);
else
- seq_printf(seq, " %d far-copies", conf->far_copies);
+ seq_printf(seq, " %d far-copies", conf->geo.far_copies);
}
- seq_printf(seq, " [%d/%d] [", conf->raid_disks,
- conf->raid_disks - mddev->degraded);
- for (i = 0; i < conf->raid_disks; i++)
+ seq_printf(seq, " [%d/%d] [", conf->geo.raid_disks,
+ conf->geo.raid_disks - mddev->degraded);
+ for (i = 0; i < conf->geo.raid_disks; i++)
seq_printf(seq, "%s",
conf->mirrors[i].rdev &&
test_bit(In_sync, &conf->mirrors[i].rdev->flags) ? "U" : "_");
@@ -1392,7 +1482,7 @@ static void status(struct seq_file *seq, struct mddev *mddev)
* Don't consider the device numbered 'ignore'
* as we might be about to remove it.
*/
-static int enough(struct r10conf *conf, int ignore)
+static int _enough(struct r10conf *conf, struct geom *geo, int ignore)
{
int first = 0;
@@ -1403,7 +1493,7 @@ static int enough(struct r10conf *conf, int ignore)
if (conf->mirrors[first].rdev &&
first != ignore)
cnt++;
- first = (first+1) % conf->raid_disks;
+ first = (first+1) % geo->raid_disks;
}
if (cnt == 0)
return 0;
@@ -1411,6 +1501,12 @@ static int enough(struct r10conf *conf, int ignore)
return 1;
}
+static int enough(struct r10conf *conf, int ignore)
+{
+ return _enough(conf, &conf->geo, ignore) &&
+ _enough(conf, &conf->prev, ignore);
+}
+
static void error(struct mddev *mddev, struct md_rdev *rdev)
{
char b[BDEVNAME_SIZE];
@@ -1445,7 +1541,7 @@ static void error(struct mddev *mddev, struct md_rdev *rdev)
"md/raid10:%s: Disk failure on %s, disabling device.\n"
"md/raid10:%s: Operation continuing on %d devices.\n",
mdname(mddev), bdevname(rdev->bdev, b),
- mdname(mddev), conf->raid_disks - mddev->degraded);
+ mdname(mddev), conf->geo.raid_disks - mddev->degraded);
}
static void print_conf(struct r10conf *conf)
@@ -1458,10 +1554,10 @@ static void print_conf(struct r10conf *conf)
printk(KERN_DEBUG "(!conf)\n");
return;
}
- printk(KERN_DEBUG " --- wd:%d rd:%d\n", conf->raid_disks - conf->mddev->degraded,
- conf->raid_disks);
+ printk(KERN_DEBUG " --- wd:%d rd:%d\n", conf->geo.raid_disks - conf->mddev->degraded,
+ conf->geo.raid_disks);
- for (i = 0; i < conf->raid_disks; i++) {
+ for (i = 0; i < conf->geo.raid_disks; i++) {
char b[BDEVNAME_SIZE];
tmp = conf->mirrors + i;
if (tmp->rdev)
@@ -1493,7 +1589,7 @@ static int raid10_spare_active(struct mddev *mddev)
* Find all non-in_sync disks within the RAID10 configuration
* and mark them in_sync
*/
- for (i = 0; i < conf->raid_disks; i++) {
+ for (i = 0; i < conf->geo.raid_disks; i++) {
tmp = conf->mirrors + i;
if (tmp->replacement
&& tmp->replacement->recovery_offset == MaxSector
@@ -1535,7 +1631,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)
int err = -EEXIST;
int mirror;
int first = 0;
- int last = conf->raid_disks - 1;
+ int last = conf->geo.raid_disks - 1;
struct request_queue *q = bdev_get_queue(rdev->bdev);
if (mddev->recovery_cp < MaxSector)
@@ -1543,7 +1639,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)
* very different from resync
*/
return -EBUSY;
- if (rdev->saved_raid_disk < 0 && !enough(conf, -1))
+ if (rdev->saved_raid_disk < 0 && !_enough(conf, &conf->prev, -1))
return -EINVAL;
if (rdev->raid_disk >= 0)
@@ -1635,6 +1731,7 @@ static int raid10_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
if (!test_bit(Faulty, &rdev->flags) &&
mddev->recovery_disabled != p->recovery_disabled &&
(!p->replacement || p->replacement == rdev) &&
+ number < conf->geo.raid_disks &&
enough(conf, -1)) {
err = -EBUSY;
goto abort;
@@ -1676,7 +1773,11 @@ static void end_sync_read(struct bio *bio, int error)
struct r10conf *conf = r10_bio->mddev->private;
int d;
- d = find_bio_disk(conf, r10_bio, bio, NULL, NULL);
+ if (bio == r10_bio->master_bio) {
+ /* this is a reshape read */
+ d = r10_bio->read_slot; /* really the read dev */
+ } else
+ d = find_bio_disk(conf, r10_bio, bio, NULL, NULL);
if (test_bit(BIO_UPTODATE, &bio->bi_flags))
set_bit(R10BIO_Uptodate, &r10_bio->state);
@@ -2218,7 +2319,9 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
" (%d sectors at %llu on %s)\n",
mdname(mddev), s,
(unsigned long long)(
- sect + rdev->data_offset),
+ sect +
+ choose_data_offset(r10_bio,
+ rdev)),
bdevname(rdev->bdev, b));
printk(KERN_NOTICE "md/raid10:%s: %s: failing "
"drive\n",
@@ -2256,7 +2359,8 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
" (%d sectors at %llu on %s)\n",
mdname(mddev), s,
(unsigned long long)(
- sect + rdev->data_offset),
+ sect +
+ choose_data_offset(r10_bio, rdev)),
bdevname(rdev->bdev, b));
printk(KERN_NOTICE "md/raid10:%s: %s: failing "
"drive\n",
@@ -2269,7 +2373,8 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
" (%d sectors at %llu on %s)\n",
mdname(mddev), s,
(unsigned long long)(
- sect + rdev->data_offset),
+ sect +
+ choose_data_offset(r10_bio, rdev)),
bdevname(rdev->bdev, b));
atomic_add(s, &rdev->corrected_errors);
}
@@ -2343,7 +2448,7 @@ static int narrow_write_error(struct r10bio *r10_bio, int i)
wbio = bio_clone_mddev(bio, GFP_NOIO, mddev);
md_trim_bio(wbio, sector - bio->bi_sector, sectors);
wbio->bi_sector = (r10_bio->devs[i].addr+
- rdev->data_offset+
+ choose_data_offset(r10_bio, rdev) +
(sector - r10_bio->sector));
wbio->bi_bdev = rdev->bdev;
if (submit_bio_wait(WRITE, wbio) == 0)
@@ -2420,7 +2525,7 @@ read_more:
r10_bio->devs[slot].bio = bio;
r10_bio->devs[slot].rdev = rdev;
bio->bi_sector = r10_bio->devs[slot].addr
- + rdev->data_offset;
+ + choose_data_offset(r10_bio, rdev);
bio->bi_bdev = rdev->bdev;
bio->bi_rw = READ | do_sync;
bio->bi_private = r10_bio;
@@ -2480,7 +2585,7 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
rdev_clear_badblocks(
rdev,
r10_bio->devs[m].addr,
- r10_bio->sectors);
+ r10_bio->sectors, 0);
} else {
if (!rdev_set_badblocks(
rdev,
@@ -2496,7 +2601,7 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
rdev_clear_badblocks(
rdev,
r10_bio->devs[m].addr,
- r10_bio->sectors);
+ r10_bio->sectors, 0);
} else {
if (!rdev_set_badblocks(
rdev,
@@ -2515,7 +2620,7 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
rdev_clear_badblocks(
rdev,
r10_bio->devs[m].addr,
- r10_bio->sectors);
+ r10_bio->sectors, 0);
rdev_dec_pending(rdev, conf->mddev);
} else if (bio != NULL &&
!test_bit(BIO_UPTODATE, &bio->bi_flags)) {
@@ -2532,7 +2637,7 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
rdev_clear_badblocks(
rdev,
r10_bio->devs[m].addr,
- r10_bio->sectors);
+ r10_bio->sectors, 0);
rdev_dec_pending(rdev, conf->mddev);
}
}
@@ -2573,6 +2678,8 @@ static void raid10d(struct mddev *mddev)
if (test_bit(R10BIO_MadeGood, &r10_bio->state) ||
test_bit(R10BIO_WriteError, &r10_bio->state))
handle_write_completed(conf, r10_bio);
+ else if (test_bit(R10BIO_IsReshape, &r10_bio->state))
+ reshape_request_write(mddev, r10_bio);
else if (test_bit(R10BIO_IsSync, &r10_bio->state))
sync_request_write(mddev, r10_bio);
else if (test_bit(R10BIO_IsRecover, &r10_bio->state))
@@ -2603,7 +2710,7 @@ static int init_resync(struct r10conf *conf)
buffs = RESYNC_WINDOW / RESYNC_BLOCK_SIZE;
BUG_ON(conf->r10buf_pool);
conf->have_replacement = 0;
- for (i = 0; i < conf->raid_disks; i++)
+ for (i = 0; i < conf->geo.raid_disks; i++)
if (conf->mirrors[i].replacement)
conf->have_replacement = 1;
conf->r10buf_pool = mempool_create(buffs, r10buf_pool_alloc, r10buf_pool_free, conf);
@@ -2657,6 +2764,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
sector_t sync_blocks;
sector_t sectors_skipped = 0;
int chunks_skipped = 0;
+ sector_t chunk_mask = conf->geo.chunk_mask;
if (!conf->r10buf_pool)
if (init_resync(conf))
@@ -2664,7 +2772,8 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
skipped:
max_sector = mddev->dev_sectors;
- if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
+ if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ||
+ test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
max_sector = mddev->resync_max_sectors;
if (sector_nr >= max_sector) {
/* If we aborted, we need to abort the
@@ -2676,11 +2785,16 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
* we need to convert that to several
* virtual addresses.
*/
+ if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) {
+ end_reshape(conf);
+ return 0;
+ }
+
if (mddev->curr_resync < max_sector) { /* aborted */
if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery))
bitmap_end_sync(mddev->bitmap, mddev->curr_resync,
&sync_blocks, 1);
- else for (i=0; i<conf->raid_disks; i++) {
+ else for (i = 0; i < conf->geo.raid_disks; i++) {
sector_t sect =
raid10_find_virt(conf, mddev->curr_resync, i);
bitmap_end_sync(mddev->bitmap, sect,
@@ -2694,7 +2808,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
/* Completed a full sync so the replacements
* are now fully recovered.
*/
- for (i = 0; i < conf->raid_disks; i++)
+ for (i = 0; i < conf->geo.raid_disks; i++)
if (conf->mirrors[i].replacement)
conf->mirrors[i].replacement
->recovery_offset
@@ -2707,7 +2821,11 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
*skipped = 1;
return sectors_skipped;
}
- if (chunks_skipped >= conf->raid_disks) {
+
+ if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
+ return reshape_request(mddev, sector_nr, skipped);
+
+ if (chunks_skipped >= conf->geo.raid_disks) {
/* if there has been nothing to do on any drive,
* then there is nothing to do at all..
*/
@@ -2721,9 +2839,9 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
/* make sure whole request will fit in a chunk - if chunks
* are meaningful
*/
- if (conf->near_copies < conf->raid_disks &&
- max_sector > (sector_nr | conf->chunk_mask))
- max_sector = (sector_nr | conf->chunk_mask) + 1;
+ if (conf->geo.near_copies < conf->geo.raid_disks &&
+ max_sector > (sector_nr | chunk_mask))
+ max_sector = (sector_nr | chunk_mask) + 1;
/*
* If there is non-resync activity waiting for us then
* put in a delay to throttle resync.
@@ -2752,7 +2870,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
int j;
r10_bio = NULL;
- for (i=0 ; i<conf->raid_disks; i++) {
+ for (i = 0 ; i < conf->geo.raid_disks; i++) {
int still_degraded;
struct r10bio *rb2;
sector_t sect;
@@ -2806,7 +2924,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
/* Need to check if the array will still be
* degraded
*/
- for (j=0; j<conf->raid_disks; j++)
+ for (j = 0; j < conf->geo.raid_disks; j++)
if (conf->mirrors[j].rdev == NULL ||
test_bit(Faulty, &conf->mirrors[j].rdev->flags)) {
still_degraded = 1;
@@ -2984,9 +3102,9 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
r10_bio->sector = sector_nr;
set_bit(R10BIO_IsSync, &r10_bio->state);
raid10_find_phys(conf, r10_bio);
- r10_bio->sectors = (sector_nr | conf->chunk_mask) - sector_nr +1;
+ r10_bio->sectors = (sector_nr | chunk_mask) - sector_nr + 1;
- for (i=0; i<conf->copies; i++) {
+ for (i = 0; i < conf->copies; i++) {
int d = r10_bio->devs[i].devnum;
sector_t first_bad, sector;
int bad_sectors;
@@ -3152,16 +3270,17 @@ raid10_size(struct mddev *mddev, sector_t sectors, int raid_disks)
struct r10conf *conf = mddev->private;
if (!raid_disks)
- raid_disks = conf->raid_disks;
+ raid_disks = min(conf->geo.raid_disks,
+ conf->prev.raid_disks);
if (!sectors)
sectors = conf->dev_sectors;
- size = sectors >> conf->chunk_shift;
- sector_div(size, conf->far_copies);
+ size = sectors >> conf->geo.chunk_shift;
+ sector_div(size, conf->geo.far_copies);
size = size * raid_disks;
- sector_div(size, conf->near_copies);
+ sector_div(size, conf->geo.near_copies);
- return size << conf->chunk_shift;
+ return size << conf->geo.chunk_shift;
}
static void calc_sectors(struct r10conf *conf, sector_t size)
@@ -3171,10 +3290,10 @@ static void calc_sectors(struct r10conf *conf, sector_t size)
* conf->stride
*/
- size = size >> conf->chunk_shift;
- sector_div(size, conf->far_copies);
- size = size * conf->raid_disks;
- sector_div(size, conf->near_copies);
+ size = size >> conf->geo.chunk_shift;
+ sector_div(size, conf->geo.far_copies);
+ size = size * conf->geo.raid_disks;
+ sector_div(size, conf->geo.near_copies);
/* 'size' is now the number of chunks in the array */
/* calculate "used chunks per device" */
size = size * conf->copies;
@@ -3182,38 +3301,76 @@ static void calc_sectors(struct r10conf *conf, sector_t size)
/* We need to round up when dividing by raid_disks to
* get the stride size.
*/
- size = DIV_ROUND_UP_SECTOR_T(size, conf->raid_disks);
+ size = DIV_ROUND_UP_SECTOR_T(size, conf->geo.raid_disks);
- conf->dev_sectors = size << conf->chunk_shift;
+ conf->dev_sectors = size << conf->geo.chunk_shift;
- if (conf->far_offset)
- conf->stride = 1 << conf->chunk_shift;
+ if (conf->geo.far_offset)
+ conf->geo.stride = 1 << conf->geo.chunk_shift;
else {
- sector_div(size, conf->far_copies);
- conf->stride = size << conf->chunk_shift;
+ sector_div(size, conf->geo.far_copies);
+ conf->geo.stride = size << conf->geo.chunk_shift;
}
}
+enum geo_type {geo_new, geo_old, geo_start};
+static int setup_geo(struct geom *geo, struct mddev *mddev, enum geo_type new)
+{
+ int nc, fc, fo;
+ int layout, chunk, disks;
+ switch (new) {
+ case geo_old:
+ layout = mddev->layout;
+ chunk = mddev->chunk_sectors;
+ disks = mddev->raid_disks - mddev->delta_disks;
+ break;
+ case geo_new:
+ layout = mddev->new_layout;
+ chunk = mddev->new_chunk_sectors;
+ disks = mddev->raid_disks;
+ break;
+ default: /* avoid 'may be unused' warnings */
+ case geo_start: /* new when starting reshape - raid_disks not
+ * updated yet. */
+ layout = mddev->new_layout;
+ chunk = mddev->new_chunk_sectors;
+ disks = mddev->raid_disks + mddev->delta_disks;
+ break;
+ }
+ if (layout >> 17)
+ return -1;
+ if (chunk < (PAGE_SIZE >> 9) ||
+ !is_power_of_2(chunk))
+ return -2;
+ nc = layout & 255;
+ fc = (layout >> 8) & 255;
+ fo = layout & (1<<16);
+ geo->raid_disks = disks;
+ geo->near_copies = nc;
+ geo->far_copies = fc;
+ geo->far_offset = fo;
+ geo->chunk_mask = chunk - 1;
+ geo->chunk_shift = ffz(~chunk);
+ return nc*fc;
+}
+
static struct r10conf *setup_conf(struct mddev *mddev)
{
struct r10conf *conf = NULL;
- int nc, fc, fo;
int err = -EINVAL;
+ struct geom geo;
+ int copies;
+
+ copies = setup_geo(&geo, mddev, geo_new);
- if (mddev->new_chunk_sectors < (PAGE_SIZE >> 9) ||
- !is_power_of_2(mddev->new_chunk_sectors)) {
+ if (copies == -2) {
printk(KERN_ERR "md/raid10:%s: chunk size must be "
"at least PAGE_SIZE(%ld) and be a power of 2.\n",
mdname(mddev), PAGE_SIZE);
goto out;
}
- nc = mddev->new_layout & 255;
- fc = (mddev->new_layout >> 8) & 255;
- fo = mddev->new_layout & (1<<16);
-
- if ((nc*fc) <2 || (nc*fc) > mddev->raid_disks ||
- (mddev->new_layout >> 17)) {
+ if (copies < 2 || copies > mddev->raid_disks) {
printk(KERN_ERR "md/raid10:%s: unsupported raid10 layout: 0x%8x\n",
mdname(mddev), mddev->new_layout);
goto out;
@@ -3224,7 +3381,9 @@ static struct r10conf *setup_conf(struct mddev *mddev)
if (!conf)
goto out;
- conf->mirrors = kzalloc(sizeof(struct mirror_info)*mddev->raid_disks,
+ /* FIXME calc properly */
+ conf->mirrors = kzalloc(sizeof(struct mirror_info)*(mddev->raid_disks +
+ max(0,mddev->delta_disks)),
GFP_KERNEL);
if (!conf->mirrors)
goto out;
@@ -3233,22 +3392,29 @@ static struct r10conf *setup_conf(struct mddev *mddev)
if (!conf->tmppage)
goto out;
-
- conf->raid_disks = mddev->raid_disks;
- conf->near_copies = nc;
- conf->far_copies = fc;
- conf->copies = nc*fc;
- conf->far_offset = fo;
- conf->chunk_mask = mddev->new_chunk_sectors - 1;
- conf->chunk_shift = ffz(~mddev->new_chunk_sectors);
-
+ conf->geo = geo;
+ conf->copies = copies;
conf->r10bio_pool = mempool_create(NR_RAID10_BIOS, r10bio_pool_alloc,
r10bio_pool_free, conf);
if (!conf->r10bio_pool)
goto out;
calc_sectors(conf, mddev->dev_sectors);
-
+ if (mddev->reshape_position == MaxSector) {
+ conf->prev = conf->geo;
+ conf->reshape_progress = MaxSector;
+ } else {
+ if (setup_geo(&conf->prev, mddev, geo_old) != conf->copies) {
+ err = -EINVAL;
+ goto out;
+ }
+ conf->reshape_progress = mddev->reshape_position;
+ if (conf->prev.far_offset)
+ conf->prev.stride = 1 << conf->prev.chunk_shift;
+ else
+ /* far_copies must be 1 */
+ conf->prev.stride = conf->dev_sectors;
+ }
spin_lock_init(&conf->device_lock);
INIT_LIST_HEAD(&conf->retry_list);
@@ -3263,8 +3429,9 @@ static struct r10conf *setup_conf(struct mddev *mddev)
return conf;
out:
- printk(KERN_ERR "md/raid10:%s: couldn't allocate memory.\n",
- mdname(mddev));
+ if (err == -ENOMEM)
+ printk(KERN_ERR "md/raid10:%s: couldn't allocate memory.\n",
+ mdname(mddev));
if (conf) {
if (conf->r10bio_pool)
mempool_destroy(conf->r10bio_pool);
@@ -3282,12 +3449,8 @@ static int run(struct mddev *mddev)
struct mirror_info *disk;
struct md_rdev *rdev;
sector_t size;
-
- /*
- * copy the already verified devices into our private RAID10
- * bookkeeping area. [whatever we allocate in run(),
- * should be freed in stop()]
- */
+ sector_t min_offset_diff = 0;
+ int first = 1;
if (mddev->private == NULL) {
conf = setup_conf(mddev);
@@ -3304,17 +3467,20 @@ static int run(struct mddev *mddev)
chunk_size = mddev->chunk_sectors << 9;
blk_queue_io_min(mddev->queue, chunk_size);
- if (conf->raid_disks % conf->near_copies)
- blk_queue_io_opt(mddev->queue, chunk_size * conf->raid_disks);
+ if (conf->geo.raid_disks % conf->geo.near_copies)
+ blk_queue_io_opt(mddev->queue, chunk_size * conf->geo.raid_disks);
else
blk_queue_io_opt(mddev->queue, chunk_size *
- (conf->raid_disks / conf->near_copies));
+ (conf->geo.raid_disks / conf->geo.near_copies));
rdev_for_each(rdev, mddev) {
+ long long diff;
disk_idx = rdev->raid_disk;
- if (disk_idx >= conf->raid_disks
- || disk_idx < 0)
+ if (disk_idx < 0)
+ continue;
+ if (disk_idx >= conf->geo.raid_disks &&
+ disk_idx >= conf->prev.raid_disks)
continue;
disk = conf->mirrors + disk_idx;
@@ -3327,12 +3493,20 @@ static int run(struct mddev *mddev)
goto out_free_conf;
disk->rdev = rdev;
}
+ diff = (rdev->new_data_offset - rdev->data_offset);
+ if (!mddev->reshape_backwards)
+ diff = -diff;
+ if (diff < 0)
+ diff = 0;
+ if (first || diff < min_offset_diff)
+ min_offset_diff = diff;
disk_stack_limits(mddev->gendisk, rdev->bdev,
rdev->data_offset << 9);
disk->head_position = 0;
}
+
/* need to check that every block has at least one working mirror */
if (!enough(conf, -1)) {
printk(KERN_ERR "md/raid10:%s: not enough operational mirrors.\n",
@@ -3340,8 +3514,21 @@ static int run(struct mddev *mddev)
goto out_free_conf;
}
+ if (conf->reshape_progress != MaxSector) {
+ /* must ensure that shape change is supported */
+ if (conf->geo.far_copies != 1 &&
+ conf->geo.far_offset == 0)
+ goto out_free_conf;
+ if (conf->prev.far_copies != 1 &&
+ conf->geo.far_offset == 0)
+ goto out_free_conf;
+ }
+
mddev->degraded = 0;
- for (i = 0; i < conf->raid_disks; i++) {
+ for (i = 0;
+ i < conf->geo.raid_disks
+ || i < conf->prev.raid_disks;
+ i++) {
disk = conf->mirrors + i;
@@ -3368,8 +3555,8 @@ static int run(struct mddev *mddev)
mdname(mddev));
printk(KERN_INFO
"md/raid10:%s: active with %d out of %d devices\n",
- mdname(mddev), conf->raid_disks - mddev->degraded,
- conf->raid_disks);
+ mdname(mddev), conf->geo.raid_disks - mddev->degraded,
+ conf->geo.raid_disks);
/*
* Ok, everything is just fine now
*/
@@ -3386,11 +3573,11 @@ static int run(struct mddev *mddev)
* maybe...
*/
{
- int stripe = conf->raid_disks *
+ int stripe = conf->geo.raid_disks *
((mddev->chunk_sectors << 9) / PAGE_SIZE);
- stripe /= conf->near_copies;
- if (mddev->queue->backing_dev_info.ra_pages < 2* stripe)
- mddev->queue->backing_dev_info.ra_pages = 2* stripe;
+ stripe /= conf->geo.near_copies;
+ if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
+ mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
}
blk_queue_merge_bvec(mddev->queue, raid10_mergeable_bvec);
@@ -3398,6 +3585,30 @@ static int run(struct mddev *mddev)
if (md_integrity_register(mddev))
goto out_free_conf;
+ if (conf->reshape_progress != MaxSector) {
+ unsigned long before_length, after_length;
+
+ before_length = ((1 << conf->prev.chunk_shift) *
+ conf->prev.far_copies);
+ after_length = ((1 << conf->geo.chunk_shift) *
+ conf->geo.far_copies);
+
+ if (max(before_length, after_length) > min_offset_diff) {
+ /* This cannot work */
+ printk("md/raid10: offset difference not enough to continue reshape\n");
+ goto out_free_conf;
+ }
+ conf->offset_diff = min_offset_diff;
+
+ conf->reshape_safe = conf->reshape_progress;
+ clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+ clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
+ set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
+ set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
+ mddev->sync_thread = md_register_thread(md_do_sync, mddev,
+ "reshape");
+ }
+
return 0;
out_free_conf:
@@ -3460,14 +3671,23 @@ static int raid10_resize(struct mddev *mddev, sector_t sectors)
struct r10conf *conf = mddev->private;
sector_t oldsize, size;
- if (conf->far_copies > 1 && !conf->far_offset)
+ if (mddev->reshape_position != MaxSector)
+ return -EBUSY;
+
+ if (conf->geo.far_copies > 1 && !conf->geo.far_offset)
return -EINVAL;
oldsize = raid10_size(mddev, 0, 0);
size = raid10_size(mddev, sectors, 0);
- md_set_array_sectors(mddev, size);
- if (mddev->array_sectors > size)
+ if (mddev->external_size &&
+ mddev->array_sectors > size)
return -EINVAL;
+ if (mddev->bitmap) {
+ int ret = bitmap_resize(mddev->bitmap, size, 0, 0);
+ if (ret)
+ return ret;
+ }
+ md_set_array_sectors(mddev, size);
set_capacity(mddev->gendisk, mddev->array_sectors);
revalidate_disk(mddev->gendisk);
if (sectors > mddev->dev_sectors &&
@@ -3534,6 +3754,758 @@ static void *raid10_takeover(struct mddev *mddev)
return ERR_PTR(-EINVAL);
}
+static int raid10_check_reshape(struct mddev *mddev)
+{
+ /* Called when there is a request to change
+ * - layout (to ->new_layout)
+ * - chunk size (to ->new_chunk_sectors)
+ * - raid_disks (by delta_disks)
+ * or when trying to restart a reshape that was ongoing.
+ *
+ * We need to validate the request and possibly allocate
+ * space if that might be an issue later.
+ *
+ * Currently we reject any reshape of a 'far' mode array,
+ * allow chunk size to change if new is generally acceptable,
+ * allow raid_disks to increase, and allow
+ * a switch between 'near' mode and 'offset' mode.
+ */
+ struct r10conf *conf = mddev->private;
+ struct geom geo;
+
+ if (conf->geo.far_copies != 1 && !conf->geo.far_offset)
+ return -EINVAL;
+
+ if (setup_geo(&geo, mddev, geo_start) != conf->copies)
+ /* mustn't change number of copies */
+ return -EINVAL;
+ if (geo.far_copies > 1 && !geo.far_offset)
+ /* Cannot switch to 'far' mode */
+ return -EINVAL;
+
+ if (mddev->array_sectors & geo.chunk_mask)
+ /* not factor of array size */
+ return -EINVAL;
+
+ if (!enough(conf, -1))
+ return -EINVAL;
+
+ kfree(conf->mirrors_new);
+ conf->mirrors_new = NULL;
+ if (mddev->delta_disks > 0) {
+ /* allocate new 'mirrors' list */
+ conf->mirrors_new = kzalloc(
+ sizeof(struct mirror_info)
+ *(mddev->raid_disks +
+ mddev->delta_disks),
+ GFP_KERNEL);
+ if (!conf->mirrors_new)
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+/*
+ * Need to check if array has failed when deciding whether to:
+ * - start an array
+ * - remove non-faulty devices
+ * - add a spare
+ * - allow a reshape
+ * This determination is simple when no reshape is happening.
+ * However if there is a reshape, we need to carefully check
+ * both the before and after sections.
+ * This is because some failed devices may only affect one
+ * of the two sections, and some non-in_sync devices may
+ * be insync in the section most affected by failed devices.
+ */
+static int calc_degraded(struct r10conf *conf)
+{
+ int degraded, degraded2;
+ int i;
+
+ rcu_read_lock();
+ degraded = 0;
+ /* 'prev' section first */
+ for (i = 0; i < conf->prev.raid_disks; i++) {
+ struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev);
+ if (!rdev || test_bit(Faulty, &rdev->flags))
+ degraded++;
+ else if (!test_bit(In_sync, &rdev->flags))
+ /* When we can reduce the number of devices in
+ * an array, this might not contribute to
+ * 'degraded'. It does now.
+ */
+ degraded++;
+ }
+ rcu_read_unlock();
+ if (conf->geo.raid_disks == conf->prev.raid_disks)
+ return degraded;
+ rcu_read_lock();
+ degraded2 = 0;
+ for (i = 0; i < conf->geo.raid_disks; i++) {
+ struct md_rdev *rdev = rcu_dereference(conf->mirrors[i].rdev);
+ if (!rdev || test_bit(Faulty, &rdev->flags))
+ degraded2++;
+ else if (!test_bit(In_sync, &rdev->flags)) {
+ /* If reshape is increasing the number of devices,
+ * this section has already been recovered, so
+ * it doesn't contribute to degraded.
+ * else it does.
+ */
+ if (conf->geo.raid_disks <= conf->prev.raid_disks)
+ degraded2++;
+ }
+ }
+ rcu_read_unlock();
+ if (degraded2 > degraded)
+ return degraded2;
+ return degraded;
+}
+
+static int raid10_start_reshape(struct mddev *mddev)
+{
+ /* A 'reshape' has been requested. This commits
+ * the various 'new' fields and sets MD_RECOVER_RESHAPE
+ * This also checks if there are enough spares and adds them
+ * to the array.
+ * We currently require enough spares to make the final
+ * array non-degraded. We also require that the difference
+ * between old and new data_offset - on each device - is
+ * enough that we never risk over-writing.
+ */
+
+ unsigned long before_length, after_length;
+ sector_t min_offset_diff = 0;
+ int first = 1;
+ struct geom new;
+ struct r10conf *conf = mddev->private;
+ struct md_rdev *rdev;
+ int spares = 0;
+ int ret;
+
+ if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
+ return -EBUSY;
+
+ if (setup_geo(&new, mddev, geo_start) != conf->copies)
+ return -EINVAL;
+
+ before_length = ((1 << conf->prev.chunk_shift) *
+ conf->prev.far_copies);
+ after_length = ((1 << conf->geo.chunk_shift) *
+ conf->geo.far_copies);
+
+ rdev_for_each(rdev, mddev) {
+ if (!test_bit(In_sync, &rdev->flags)
+ && !test_bit(Faulty, &rdev->flags))
+ spares++;
+ if (rdev->raid_disk >= 0) {
+ long long diff = (rdev->new_data_offset
+ - rdev->data_offset);
+ if (!mddev->reshape_backwards)
+ diff = -diff;
+ if (diff < 0)
+ diff = 0;
+ if (first || diff < min_offset_diff)
+ min_offset_diff = diff;
+ }
+ }
+
+ if (max(before_length, after_length) > min_offset_diff)
+ return -EINVAL;
+
+ if (spares < mddev->delta_disks)
+ return -EINVAL;
+
+ conf->offset_diff = min_offset_diff;
+ spin_lock_irq(&conf->device_lock);
+ if (conf->mirrors_new) {
+ memcpy(conf->mirrors_new, conf->mirrors,
+ sizeof(struct mirror_info)*conf->prev.raid_disks);
+ smp_mb();
+ kfree(conf->mirrors_old); /* FIXME and elsewhere */
+ conf->mirrors_old = conf->mirrors;
+ conf->mirrors = conf->mirrors_new;
+ conf->mirrors_new = NULL;
+ }
+ setup_geo(&conf->geo, mddev, geo_start);
+ smp_mb();
+ if (mddev->reshape_backwards) {
+ sector_t size = raid10_size(mddev, 0, 0);
+ if (size < mddev->array_sectors) {
+ spin_unlock_irq(&conf->device_lock);
+ printk(KERN_ERR "md/raid10:%s: array size must be reduce before number of disks\n",
+ mdname(mddev));
+ return -EINVAL;
+ }
+ mddev->resync_max_sectors = size;
+ conf->reshape_progress = size;
+ } else
+ conf->reshape_progress = 0;
+ spin_unlock_irq(&conf->device_lock);
+
+ if (mddev->delta_disks && mddev->bitmap) {
+ ret = bitmap_resize(mddev->bitmap,
+ raid10_size(mddev, 0,
+ conf->geo.raid_disks),
+ 0, 0);
+ if (ret)
+ goto abort;
+ }
+ if (mddev->delta_disks > 0) {
+ rdev_for_each(rdev, mddev)
+ if (rdev->raid_disk < 0 &&
+ !test_bit(Faulty, &rdev->flags)) {
+ if (raid10_add_disk(mddev, rdev) == 0) {
+ if (rdev->raid_disk >=
+ conf->prev.raid_disks)
+ set_bit(In_sync, &rdev->flags);
+ else
+ rdev->recovery_offset = 0;
+
+ if (sysfs_link_rdev(mddev, rdev))
+ /* Failure here is OK */;
+ }
+ } else if (rdev->raid_disk >= conf->prev.raid_disks
+ && !test_bit(Faulty, &rdev->flags)) {
+ /* This is a spare that was manually added */
+ set_bit(In_sync, &rdev->flags);
+ }
+ }
+ /* When a reshape changes the number of devices,
+ * ->degraded is measured against the larger of the
+ * pre and post numbers.
+ */
+ spin_lock_irq(&conf->device_lock);
+ mddev->degraded = calc_degraded(conf);
+ spin_unlock_irq(&conf->device_lock);
+ mddev->raid_disks = conf->geo.raid_disks;
+ mddev->reshape_position = conf->reshape_progress;
+ set_bit(MD_CHANGE_DEVS, &mddev->flags);
+
+ clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+ clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
+ set_bit(MD_RECOVERY_RESHAPE, &mddev->recovery);
+ set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
+
+ mddev->sync_thread = md_register_thread(md_do_sync, mddev,
+ "reshape");
+ if (!mddev->sync_thread) {
+ ret = -EAGAIN;
+ goto abort;
+ }
+ conf->reshape_checkpoint = jiffies;
+ md_wakeup_thread(mddev->sync_thread);
+ md_new_event(mddev);
+ return 0;
+
+abort:
+ mddev->recovery = 0;
+ spin_lock_irq(&conf->device_lock);
+ conf->geo = conf->prev;
+ mddev->raid_disks = conf->geo.raid_disks;
+ rdev_for_each(rdev, mddev)
+ rdev->new_data_offset = rdev->data_offset;
+ smp_wmb();
+ conf->reshape_progress = MaxSector;
+ mddev->reshape_position = MaxSector;
+ spin_unlock_irq(&conf->device_lock);
+ return ret;
+}
+
+/* Calculate the last device-address that could contain
+ * any block from the chunk that includes the array-address 's'
+ * and report the next address.
+ * i.e. the address returned will be chunk-aligned and after
+ * any data that is in the chunk containing 's'.
+ */
+static sector_t last_dev_address(sector_t s, struct geom *geo)
+{
+ s = (s | geo->chunk_mask) + 1;
+ s >>= geo->chunk_shift;
+ s *= geo->near_copies;
+ s = DIV_ROUND_UP_SECTOR_T(s, geo->raid_disks);
+ s *= geo->far_copies;
+ s <<= geo->chunk_shift;
+ return s;
+}
+
+/* Calculate the first device-address that could contain
+ * any block from the chunk that includes the array-address 's'.
+ * This too will be the start of a chunk
+ */
+static sector_t first_dev_address(sector_t s, struct geom *geo)
+{
+ s >>= geo->chunk_shift;
+ s *= geo->near_copies;
+ sector_div(s, geo->raid_disks);
+ s *= geo->far_copies;
+ s <<= geo->chunk_shift;
+ return s;
+}
+
+static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr,
+ int *skipped)
+{
+ /* We simply copy at most one chunk (smallest of old and new)
+ * at a time, possibly less if that exceeds RESYNC_PAGES,
+ * or we hit a bad block or something.
+ * This might mean we pause for normal IO in the middle of
+ * a chunk, but that is not a problem was mddev->reshape_position
+ * can record any location.
+ *
+ * If we will want to write to a location that isn't
+ * yet recorded as 'safe' (i.e. in metadata on disk) then
+ * we need to flush all reshape requests and update the metadata.
+ *
+ * When reshaping forwards (e.g. to more devices), we interpret
+ * 'safe' as the earliest block which might not have been copied
+ * down yet. We divide this by previous stripe size and multiply
+ * by previous stripe length to get lowest device offset that we
+ * cannot write to yet.
+ * We interpret 'sector_nr' as an address that we want to write to.
+ * From this we use last_device_address() to find where we might
+ * write to, and first_device_address on the 'safe' position.
+ * If this 'next' write position is after the 'safe' position,
+ * we must update the metadata to increase the 'safe' position.
+ *
+ * When reshaping backwards, we round in the opposite direction
+ * and perform the reverse test: next write position must not be
+ * less than current safe position.
+ *
+ * In all this the minimum difference in data offsets
+ * (conf->offset_diff - always positive) allows a bit of slack,
+ * so next can be after 'safe', but not by more than offset_disk
+ *
+ * We need to prepare all the bios here before we start any IO
+ * to ensure the size we choose is acceptable to all devices.
+ * The means one for each copy for write-out and an extra one for
+ * read-in.
+ * We store the read-in bio in ->master_bio and the others in
+ * ->devs[x].bio and ->devs[x].repl_bio.
+ */
+ struct r10conf *conf = mddev->private;
+ struct r10bio *r10_bio;
+ sector_t next, safe, last;
+ int max_sectors;
+ int nr_sectors;
+ int s;
+ struct md_rdev *rdev;
+ int need_flush = 0;
+ struct bio *blist;
+ struct bio *bio, *read_bio;
+ int sectors_done = 0;
+
+ if (sector_nr == 0) {
+ /* If restarting in the middle, skip the initial sectors */
+ if (mddev->reshape_backwards &&
+ conf->reshape_progress < raid10_size(mddev, 0, 0)) {
+ sector_nr = (raid10_size(mddev, 0, 0)
+ - conf->reshape_progress);
+ } else if (!mddev->reshape_backwards &&
+ conf->reshape_progress > 0)
+ sector_nr = conf->reshape_progress;
+ if (sector_nr) {
+ mddev->curr_resync_completed = sector_nr;
+ sysfs_notify(&mddev->kobj, NULL, "sync_completed");
+ *skipped = 1;
+ return sector_nr;
+ }
+ }
+
+ /* We don't use sector_nr to track where we are up to
+ * as that doesn't work well for ->reshape_backwards.
+ * So just use ->reshape_progress.
+ */
+ if (mddev->reshape_backwards) {
+ /* 'next' is the earliest device address that we might
+ * write to for this chunk in the new layout
+ */
+ next = first_dev_address(conf->reshape_progress - 1,
+ &conf->geo);
+
+ /* 'safe' is the last device address that we might read from
+ * in the old layout after a restart
+ */
+ safe = last_dev_address(conf->reshape_safe - 1,
+ &conf->prev);
+
+ if (next + conf->offset_diff < safe)
+ need_flush = 1;
+
+ last = conf->reshape_progress - 1;
+ sector_nr = last & ~(sector_t)(conf->geo.chunk_mask
+ & conf->prev.chunk_mask);
+ if (sector_nr + RESYNC_BLOCK_SIZE/512 < last)
+ sector_nr = last + 1 - RESYNC_BLOCK_SIZE/512;
+ } else {
+ /* 'next' is after the last device address that we
+ * might write to for this chunk in the new layout
+ */
+ next = last_dev_address(conf->reshape_progress, &conf->geo);
+
+ /* 'safe' is the earliest device address that we might
+ * read from in the old layout after a restart
+ */
+ safe = first_dev_address(conf->reshape_safe, &conf->prev);
+
+ /* Need to update metadata if 'next' might be beyond 'safe'
+ * as that would possibly corrupt data
+ */
+ if (next > safe + conf->offset_diff)
+ need_flush = 1;
+
+ sector_nr = conf->reshape_progress;
+ last = sector_nr | (conf->geo.chunk_mask
+ & conf->prev.chunk_mask);
+
+ if (sector_nr + RESYNC_BLOCK_SIZE/512 <= last)
+ last = sector_nr + RESYNC_BLOCK_SIZE/512 - 1;
+ }
+
+ if (need_flush ||
+ time_after(jiffies, conf->reshape_checkpoint + 10*HZ)) {
+ /* Need to update reshape_position in metadata */
+ wait_barrier(conf);
+ mddev->reshape_position = conf->reshape_progress;
+ if (mddev->reshape_backwards)
+ mddev->curr_resync_completed = raid10_size(mddev, 0, 0)
+ - conf->reshape_progress;
+ else
+ mddev->curr_resync_completed = conf->reshape_progress;
+ conf->reshape_checkpoint = jiffies;
+ set_bit(MD_CHANGE_DEVS, &mddev->flags);
+ md_wakeup_thread(mddev->thread);
+ wait_event(mddev->sb_wait, mddev->flags == 0 ||
+ kthread_should_stop());
+ conf->reshape_safe = mddev->reshape_position;
+ allow_barrier(conf);
+ }
+
+read_more:
+ /* Now schedule reads for blocks from sector_nr to last */
+ r10_bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO);
+ raise_barrier(conf, sectors_done != 0);
+ atomic_set(&r10_bio->remaining, 0);
+ r10_bio->mddev = mddev;
+ r10_bio->sector = sector_nr;
+ set_bit(R10BIO_IsReshape, &r10_bio->state);
+ r10_bio->sectors = last - sector_nr + 1;
+ rdev = read_balance(conf, r10_bio, &max_sectors);
+ BUG_ON(!test_bit(R10BIO_Previous, &r10_bio->state));
+
+ if (!rdev) {
+ /* Cannot read from here, so need to record bad blocks
+ * on all the target devices.
+ */
+ // FIXME
+ set_bit(MD_RECOVERY_INTR, &mddev->recovery);
+ return sectors_done;
+ }
+
+ read_bio = bio_alloc_mddev(GFP_KERNEL, RESYNC_PAGES, mddev);
+
+ read_bio->bi_bdev = rdev->bdev;
+ read_bio->bi_sector = (r10_bio->devs[r10_bio->read_slot].addr
+ + rdev->data_offset);
+ read_bio->bi_private = r10_bio;
+ read_bio->bi_end_io = end_sync_read;
+ read_bio->bi_rw = READ;
+ read_bio->bi_flags &= ~(BIO_POOL_MASK - 1);
+ read_bio->bi_flags |= 1 << BIO_UPTODATE;
+ read_bio->bi_vcnt = 0;
+ read_bio->bi_idx = 0;
+ read_bio->bi_size = 0;
+ r10_bio->master_bio = read_bio;
+ r10_bio->read_slot = r10_bio->devs[r10_bio->read_slot].devnum;
+
+ /* Now find the locations in the new layout */
+ __raid10_find_phys(&conf->geo, r10_bio);
+
+ blist = read_bio;
+ read_bio->bi_next = NULL;
+
+ for (s = 0; s < conf->copies*2; s++) {
+ struct bio *b;
+ int d = r10_bio->devs[s/2].devnum;
+ struct md_rdev *rdev2;
+ if (s&1) {
+ rdev2 = conf->mirrors[d].replacement;
+ b = r10_bio->devs[s/2].repl_bio;
+ } else {
+ rdev2 = conf->mirrors[d].rdev;
+ b = r10_bio->devs[s/2].bio;
+ }
+ if (!rdev2 || test_bit(Faulty, &rdev2->flags))
+ continue;
+ b->bi_bdev = rdev2->bdev;
+ b->bi_sector = r10_bio->devs[s/2].addr + rdev2->new_data_offset;
+ b->bi_private = r10_bio;
+ b->bi_end_io = end_reshape_write;
+ b->bi_rw = WRITE;
+ b->bi_flags &= ~(BIO_POOL_MASK - 1);
+ b->bi_flags |= 1 << BIO_UPTODATE;
+ b->bi_next = blist;
+ b->bi_vcnt = 0;
+ b->bi_idx = 0;
+ b->bi_size = 0;
+ blist = b;
+ }
+
+ /* Now add as many pages as possible to all of these bios. */
+
+ nr_sectors = 0;
+ for (s = 0 ; s < max_sectors; s += PAGE_SIZE >> 9) {
+ struct page *page = r10_bio->devs[0].bio->bi_io_vec[s/(PAGE_SIZE>>9)].bv_page;
+ int len = (max_sectors - s) << 9;
+ if (len > PAGE_SIZE)
+ len = PAGE_SIZE;
+ for (bio = blist; bio ; bio = bio->bi_next) {
+ struct bio *bio2;
+ if (bio_add_page(bio, page, len, 0))
+ continue;
+
+ /* Didn't fit, must stop */
+ for (bio2 = blist;
+ bio2 && bio2 != bio;
+ bio2 = bio2->bi_next) {
+ /* Remove last page from this bio */
+ bio2->bi_vcnt--;
+ bio2->bi_size -= len;
+ bio2->bi_flags &= ~(1<<BIO_SEG_VALID);
+ }
+ goto bio_full;
+ }
+ sector_nr += len >> 9;
+ nr_sectors += len >> 9;
+ }
+bio_full:
+ r10_bio->sectors = nr_sectors;
+
+ /* Now submit the read */
+ md_sync_acct(read_bio->bi_bdev, r10_bio->sectors);
+ atomic_inc(&r10_bio->remaining);
+ read_bio->bi_next = NULL;
+ generic_make_request(read_bio);
+ sector_nr += nr_sectors;
+ sectors_done += nr_sectors;
+ if (sector_nr <= last)
+ goto read_more;
+
+ /* Now that we have done the whole section we can
+ * update reshape_progress
+ */
+ if (mddev->reshape_backwards)
+ conf->reshape_progress -= sectors_done;
+ else
+ conf->reshape_progress += sectors_done;
+
+ return sectors_done;
+}
+
+static void end_reshape_request(struct r10bio *r10_bio);
+static int handle_reshape_read_error(struct mddev *mddev,
+ struct r10bio *r10_bio);
+static void reshape_request_write(struct mddev *mddev, struct r10bio *r10_bio)
+{
+ /* Reshape read completed. Hopefully we have a block
+ * to write out.
+ * If we got a read error then we do sync 1-page reads from
+ * elsewhere until we find the data - or give up.
+ */
+ struct r10conf *conf = mddev->private;
+ int s;
+
+ if (!test_bit(R10BIO_Uptodate, &r10_bio->state))
+ if (handle_reshape_read_error(mddev, r10_bio) < 0) {
+ /* Reshape has been aborted */
+ md_done_sync(mddev, r10_bio->sectors, 0);
+ return;
+ }
+
+ /* We definitely have the data in the pages, schedule the
+ * writes.
+ */
+ atomic_set(&r10_bio->remaining, 1);
+ for (s = 0; s < conf->copies*2; s++) {
+ struct bio *b;
+ int d = r10_bio->devs[s/2].devnum;
+ struct md_rdev *rdev;
+ if (s&1) {
+ rdev = conf->mirrors[d].replacement;
+ b = r10_bio->devs[s/2].repl_bio;
+ } else {
+ rdev = conf->mirrors[d].rdev;
+ b = r10_bio->devs[s/2].bio;
+ }
+ if (!rdev || test_bit(Faulty, &rdev->flags))
+ continue;
+ atomic_inc(&rdev->nr_pending);
+ md_sync_acct(b->bi_bdev, r10_bio->sectors);
+ atomic_inc(&r10_bio->remaining);
+ b->bi_next = NULL;
+ generic_make_request(b);
+ }
+ end_reshape_request(r10_bio);
+}
+
+static void end_reshape(struct r10conf *conf)
+{
+ if (test_bit(MD_RECOVERY_INTR, &conf->mddev->recovery))
+ return;
+
+ spin_lock_irq(&conf->device_lock);
+ conf->prev = conf->geo;
+ md_finish_reshape(conf->mddev);
+ smp_wmb();
+ conf->reshape_progress = MaxSector;
+ spin_unlock_irq(&conf->device_lock);
+
+ /* read-ahead size must cover two whole stripes, which is
+ * 2 * (datadisks) * chunksize where 'n' is the number of raid devices
+ */
+ if (conf->mddev->queue) {
+ int stripe = conf->geo.raid_disks *
+ ((conf->mddev->chunk_sectors << 9) / PAGE_SIZE);
+ stripe /= conf->geo.near_copies;
+ if (conf->mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
+ conf->mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
+ }
+ conf->fullsync = 0;
+}
+
+
+static int handle_reshape_read_error(struct mddev *mddev,
+ struct r10bio *r10_bio)
+{
+ /* Use sync reads to get the blocks from somewhere else */
+ int sectors = r10_bio->sectors;
+ struct r10bio r10b;
+ struct r10conf *conf = mddev->private;
+ int slot = 0;
+ int idx = 0;
+ struct bio_vec *bvec = r10_bio->master_bio->bi_io_vec;
+
+ r10b.sector = r10_bio->sector;
+ __raid10_find_phys(&conf->prev, &r10b);
+
+ while (sectors) {
+ int s = sectors;
+ int success = 0;
+ int first_slot = slot;
+
+ if (s > (PAGE_SIZE >> 9))
+ s = PAGE_SIZE >> 9;
+
+ while (!success) {
+ int d = r10b.devs[slot].devnum;
+ struct md_rdev *rdev = conf->mirrors[d].rdev;
+ sector_t addr;
+ if (rdev == NULL ||
+ test_bit(Faulty, &rdev->flags) ||
+ !test_bit(In_sync, &rdev->flags))
+ goto failed;
+
+ addr = r10b.devs[slot].addr + idx * PAGE_SIZE;
+ success = sync_page_io(rdev,
+ addr,
+ s << 9,
+ bvec[idx].bv_page,
+ READ, false);
+ if (success)
+ break;
+ failed:
+ slot++;
+ if (slot >= conf->copies)
+ slot = 0;
+ if (slot == first_slot)
+ break;
+ }
+ if (!success) {
+ /* couldn't read this block, must give up */
+ set_bit(MD_RECOVERY_INTR,
+ &mddev->recovery);
+ return -EIO;
+ }
+ sectors -= s;
+ idx++;
+ }
+ return 0;
+}
+
+static void end_reshape_write(struct bio *bio, int error)
+{
+ int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
+ struct r10bio *r10_bio = bio->bi_private;
+ struct mddev *mddev = r10_bio->mddev;
+ struct r10conf *conf = mddev->private;
+ int d;
+ int slot;
+ int repl;
+ struct md_rdev *rdev = NULL;
+
+ d = find_bio_disk(conf, r10_bio, bio, &slot, &repl);
+ if (repl)
+ rdev = conf->mirrors[d].replacement;
+ if (!rdev) {
+ smp_mb();
+ rdev = conf->mirrors[d].rdev;
+ }
+
+ if (!uptodate) {
+ /* FIXME should record badblock */
+ md_error(mddev, rdev);
+ }
+
+ rdev_dec_pending(rdev, mddev);
+ end_reshape_request(r10_bio);
+}
+
+static void end_reshape_request(struct r10bio *r10_bio)
+{
+ if (!atomic_dec_and_test(&r10_bio->remaining))
+ return;
+ md_done_sync(r10_bio->mddev, r10_bio->sectors, 1);
+ bio_put(r10_bio->master_bio);
+ put_buf(r10_bio);
+}
+
+static void raid10_finish_reshape(struct mddev *mddev)
+{
+ struct r10conf *conf = mddev->private;
+
+ if (test_bit(MD_RECOVERY_INTR, &mddev->recovery))
+ return;
+
+ if (mddev->delta_disks > 0) {
+ sector_t size = raid10_size(mddev, 0, 0);
+ md_set_array_sectors(mddev, size);
+ if (mddev->recovery_cp > mddev->resync_max_sectors) {
+ mddev->recovery_cp = mddev->resync_max_sectors;
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ }
+ mddev->resync_max_sectors = size;
+ set_capacity(mddev->gendisk, mddev->array_sectors);
+ revalidate_disk(mddev->gendisk);
+ } else {
+ int d;
+ for (d = conf->geo.raid_disks ;
+ d < conf->geo.raid_disks - mddev->delta_disks;
+ d++) {
+ struct md_rdev *rdev = conf->mirrors[d].rdev;
+ if (rdev)
+ clear_bit(In_sync, &rdev->flags);
+ rdev = conf->mirrors[d].replacement;
+ if (rdev)
+ clear_bit(In_sync, &rdev->flags);
+ }
+ }
+ mddev->layout = mddev->new_layout;
+ mddev->chunk_sectors = 1 << conf->geo.chunk_shift;
+ mddev->reshape_position = MaxSector;
+ mddev->delta_disks = 0;
+ mddev->reshape_backwards = 0;
+}
+
static struct md_personality raid10_personality =
{
.name = "raid10",
@@ -3552,6 +4524,9 @@ static struct md_personality raid10_personality =
.size = raid10_size,
.resize = raid10_resize,
.takeover = raid10_takeover,
+ .check_reshape = raid10_check_reshape,
+ .start_reshape = raid10_start_reshape,
+ .finish_reshape = raid10_finish_reshape,
};
static int __init raid_init(void)
diff --git a/drivers/md/raid10.h b/drivers/md/raid10.h
index 7c615613c381..135b1b0a1554 100644
--- a/drivers/md/raid10.h
+++ b/drivers/md/raid10.h
@@ -14,32 +14,38 @@ struct mirror_info {
struct r10conf {
struct mddev *mddev;
struct mirror_info *mirrors;
- int raid_disks;
+ struct mirror_info *mirrors_new, *mirrors_old;
spinlock_t device_lock;
/* geometry */
- int near_copies; /* number of copies laid out
+ struct geom {
+ int raid_disks;
+ int near_copies; /* number of copies laid out
* raid0 style */
- int far_copies; /* number of copies laid out
+ int far_copies; /* number of copies laid out
* at large strides across drives
*/
- int far_offset; /* far_copies are offset by 1
+ int far_offset; /* far_copies are offset by 1
* stripe instead of many
*/
- int copies; /* near_copies * far_copies.
- * must be <= raid_disks
- */
- sector_t stride; /* distance between far copies.
+ sector_t stride; /* distance between far copies.
* This is size / far_copies unless
* far_offset, in which case it is
* 1 stripe.
*/
+ int chunk_shift; /* shift from chunks to sectors */
+ sector_t chunk_mask;
+ } prev, geo;
+ int copies; /* near_copies * far_copies.
+ * must be <= raid_disks
+ */
sector_t dev_sectors; /* temp copy of
* mddev->dev_sectors */
-
- int chunk_shift; /* shift from chunks to sectors */
- sector_t chunk_mask;
+ sector_t reshape_progress;
+ sector_t reshape_safe;
+ unsigned long reshape_checkpoint;
+ sector_t offset_diff;
struct list_head retry_list;
/* queue pending writes and submit them on unplug */
@@ -136,6 +142,7 @@ enum r10bio_state {
R10BIO_Uptodate,
R10BIO_IsSync,
R10BIO_IsRecover,
+ R10BIO_IsReshape,
R10BIO_Degraded,
/* Set ReadError on bios that experience a read error
* so that raid10d knows what to do with them.
@@ -146,5 +153,10 @@ enum r10bio_state {
*/
R10BIO_MadeGood,
R10BIO_WriteError,
+/* During a reshape we might be performing IO on the
+ * 'previous' part of the array, in which case this
+ * flag is set
+ */
+ R10BIO_Previous,
};
#endif
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index f351422938e0..d26767246d26 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -488,6 +488,27 @@ get_active_stripe(struct r5conf *conf, sector_t sector,
return sh;
}
+/* Determine if 'data_offset' or 'new_data_offset' should be used
+ * in this stripe_head.
+ */
+static int use_new_offset(struct r5conf *conf, struct stripe_head *sh)
+{
+ sector_t progress = conf->reshape_progress;
+ /* Need a memory barrier to make sure we see the value
+ * of conf->generation, or ->data_offset that was set before
+ * reshape_progress was updated.
+ */
+ smp_rmb();
+ if (progress == MaxSector)
+ return 0;
+ if (sh->generation == conf->generation - 1)
+ return 0;
+ /* We are in a reshape, and this is a new-generation stripe,
+ * so use new_data_offset.
+ */
+ return 1;
+}
+
static void
raid5_end_read_request(struct bio *bi, int error);
static void
@@ -518,6 +539,8 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
replace_only = 1;
} else
continue;
+ if (test_and_clear_bit(R5_SyncIO, &sh->dev[i].flags))
+ rw |= REQ_SYNC;
bi = &sh->dev[i].req;
rbi = &sh->dev[i].rreq; /* For writing to replacement */
@@ -603,7 +626,12 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
__func__, (unsigned long long)sh->sector,
bi->bi_rw, i);
atomic_inc(&sh->count);
- bi->bi_sector = sh->sector + rdev->data_offset;
+ if (use_new_offset(conf, sh))
+ bi->bi_sector = (sh->sector
+ + rdev->new_data_offset);
+ else
+ bi->bi_sector = (sh->sector
+ + rdev->data_offset);
bi->bi_flags = 1 << BIO_UPTODATE;
bi->bi_idx = 0;
bi->bi_io_vec[0].bv_len = STRIPE_SIZE;
@@ -627,7 +655,12 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
__func__, (unsigned long long)sh->sector,
rbi->bi_rw, i);
atomic_inc(&sh->count);
- rbi->bi_sector = sh->sector + rrdev->data_offset;
+ if (use_new_offset(conf, sh))
+ rbi->bi_sector = (sh->sector
+ + rrdev->new_data_offset);
+ else
+ rbi->bi_sector = (sh->sector
+ + rrdev->data_offset);
rbi->bi_flags = 1 << BIO_UPTODATE;
rbi->bi_idx = 0;
rbi->bi_io_vec[0].bv_len = STRIPE_SIZE;
@@ -1114,6 +1147,8 @@ ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx)
dev->sector + STRIPE_SECTORS) {
if (wbi->bi_rw & REQ_FUA)
set_bit(R5_WantFUA, &dev->flags);
+ if (wbi->bi_rw & REQ_SYNC)
+ set_bit(R5_SyncIO, &dev->flags);
tx = async_copy_data(1, wbi, dev->page,
dev->sector, tx);
wbi = r5_next_bio(wbi, dev->sector);
@@ -1131,13 +1166,15 @@ static void ops_complete_reconstruct(void *stripe_head_ref)
int pd_idx = sh->pd_idx;
int qd_idx = sh->qd_idx;
int i;
- bool fua = false;
+ bool fua = false, sync = false;
pr_debug("%s: stripe %llu\n", __func__,
(unsigned long long)sh->sector);
- for (i = disks; i--; )
+ for (i = disks; i--; ) {
fua |= test_bit(R5_WantFUA, &sh->dev[i].flags);
+ sync |= test_bit(R5_SyncIO, &sh->dev[i].flags);
+ }
for (i = disks; i--; ) {
struct r5dev *dev = &sh->dev[i];
@@ -1146,6 +1183,8 @@ static void ops_complete_reconstruct(void *stripe_head_ref)
set_bit(R5_UPTODATE, &dev->flags);
if (fua)
set_bit(R5_WantFUA, &dev->flags);
+ if (sync)
+ set_bit(R5_SyncIO, &dev->flags);
}
}
@@ -1648,7 +1687,7 @@ static void raid5_end_read_request(struct bio * bi, int error)
int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
char b[BDEVNAME_SIZE];
struct md_rdev *rdev = NULL;
-
+ sector_t s;
for (i=0 ; i<disks; i++)
if (bi == &sh->dev[i].req)
@@ -1671,6 +1710,10 @@ static void raid5_end_read_request(struct bio * bi, int error)
if (!rdev)
rdev = conf->disks[i].rdev;
+ if (use_new_offset(conf, sh))
+ s = sh->sector + rdev->new_data_offset;
+ else
+ s = sh->sector + rdev->data_offset;
if (uptodate) {
set_bit(R5_UPTODATE, &sh->dev[i].flags);
if (test_bit(R5_ReadError, &sh->dev[i].flags)) {
@@ -1683,8 +1726,7 @@ static void raid5_end_read_request(struct bio * bi, int error)
"md/raid:%s: read error corrected"
" (%lu sectors at %llu on %s)\n",
mdname(conf->mddev), STRIPE_SECTORS,
- (unsigned long long)(sh->sector
- + rdev->data_offset),
+ (unsigned long long)s,
bdevname(rdev->bdev, b));
atomic_add(STRIPE_SECTORS, &rdev->corrected_errors);
clear_bit(R5_ReadError, &sh->dev[i].flags);
@@ -1704,8 +1746,7 @@ static void raid5_end_read_request(struct bio * bi, int error)
"md/raid:%s: read error on replacement device "
"(sector %llu on %s).\n",
mdname(conf->mddev),
- (unsigned long long)(sh->sector
- + rdev->data_offset),
+ (unsigned long long)s,
bdn);
else if (conf->mddev->degraded >= conf->max_degraded)
printk_ratelimited(
@@ -1713,8 +1754,7 @@ static void raid5_end_read_request(struct bio * bi, int error)
"md/raid:%s: read error not correctable "
"(sector %llu on %s).\n",
mdname(conf->mddev),
- (unsigned long long)(sh->sector
- + rdev->data_offset),
+ (unsigned long long)s,
bdn);
else if (test_bit(R5_ReWrite, &sh->dev[i].flags))
/* Oh, no!!! */
@@ -1723,8 +1763,7 @@ static void raid5_end_read_request(struct bio * bi, int error)
"md/raid:%s: read error NOT corrected!! "
"(sector %llu on %s).\n",
mdname(conf->mddev),
- (unsigned long long)(sh->sector
- + rdev->data_offset),
+ (unsigned long long)s,
bdn);
else if (atomic_read(&rdev->read_errors)
> conf->max_nr_stripes)
@@ -3561,7 +3600,7 @@ finish:
if (test_and_clear_bit(R5_MadeGood, &dev->flags)) {
rdev = conf->disks[i].rdev;
rdev_clear_badblocks(rdev, sh->sector,
- STRIPE_SECTORS);
+ STRIPE_SECTORS, 0);
rdev_dec_pending(rdev, conf->mddev);
}
if (test_and_clear_bit(R5_MadeGoodRepl, &dev->flags)) {
@@ -3570,7 +3609,7 @@ finish:
/* rdev have been moved down */
rdev = conf->disks[i].rdev;
rdev_clear_badblocks(rdev, sh->sector,
- STRIPE_SECTORS);
+ STRIPE_SECTORS, 0);
rdev_dec_pending(rdev, conf->mddev);
}
}
@@ -3842,6 +3881,7 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio)
raid_bio->bi_next = (void*)rdev;
align_bi->bi_bdev = rdev->bdev;
align_bi->bi_flags &= ~(1 << BIO_SEG_VALID);
+ /* No reshape active, so we can trust rdev->data_offset */
align_bi->bi_sector += rdev->data_offset;
if (!bio_fits_rdev(align_bi) ||
@@ -3953,12 +3993,10 @@ static void make_request(struct mddev *mddev, struct bio * bi)
plugged = mddev_check_plugged(mddev);
for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) {
DEFINE_WAIT(w);
- int disks, data_disks;
int previous;
retry:
previous = 0;
- disks = conf->raid_disks;
prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE);
if (unlikely(conf->reshape_progress != MaxSector)) {
/* spinlock is needed as reshape_progress may be
@@ -3970,13 +4008,12 @@ static void make_request(struct mddev *mddev, struct bio * bi)
* to check again.
*/
spin_lock_irq(&conf->device_lock);
- if (mddev->delta_disks < 0
+ if (mddev->reshape_backwards
? logical_sector < conf->reshape_progress
: logical_sector >= conf->reshape_progress) {
- disks = conf->previous_raid_disks;
previous = 1;
} else {
- if (mddev->delta_disks < 0
+ if (mddev->reshape_backwards
? logical_sector < conf->reshape_safe
: logical_sector >= conf->reshape_safe) {
spin_unlock_irq(&conf->device_lock);
@@ -3986,7 +4023,6 @@ static void make_request(struct mddev *mddev, struct bio * bi)
}
spin_unlock_irq(&conf->device_lock);
}
- data_disks = disks - conf->max_degraded;
new_sector = raid5_compute_sector(conf, logical_sector,
previous,
@@ -4009,7 +4045,7 @@ static void make_request(struct mddev *mddev, struct bio * bi)
*/
int must_retry = 0;
spin_lock_irq(&conf->device_lock);
- if (mddev->delta_disks < 0
+ if (mddev->reshape_backwards
? logical_sector >= conf->reshape_progress
: logical_sector < conf->reshape_progress)
/* mismatch, need to try again */
@@ -4108,11 +4144,11 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk
if (sector_nr == 0) {
/* If restarting in the middle, skip the initial sectors */
- if (mddev->delta_disks < 0 &&
+ if (mddev->reshape_backwards &&
conf->reshape_progress < raid5_size(mddev, 0, 0)) {
sector_nr = raid5_size(mddev, 0, 0)
- conf->reshape_progress;
- } else if (mddev->delta_disks >= 0 &&
+ } else if (!mddev->reshape_backwards &&
conf->reshape_progress > 0)
sector_nr = conf->reshape_progress;
sector_div(sector_nr, new_data_disks);
@@ -4133,13 +4169,11 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk
else
reshape_sectors = mddev->chunk_sectors;
- /* we update the metadata when there is more than 3Meg
- * in the block range (that is rather arbitrary, should
- * probably be time based) or when the data about to be
- * copied would over-write the source of the data at
- * the front of the range.
- * i.e. one new_stripe along from reshape_progress new_maps
- * to after where reshape_safe old_maps to
+ /* We update the metadata at least every 10 seconds, or when
+ * the data about to be copied would over-write the source of
+ * the data at the front of the range. i.e. one new_stripe
+ * along from reshape_progress new_maps to after where
+ * reshape_safe old_maps to
*/
writepos = conf->reshape_progress;
sector_div(writepos, new_data_disks);
@@ -4147,7 +4181,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk
sector_div(readpos, data_disks);
safepos = conf->reshape_safe;
sector_div(safepos, data_disks);
- if (mddev->delta_disks < 0) {
+ if (mddev->reshape_backwards) {
writepos -= min_t(sector_t, reshape_sectors, writepos);
readpos += reshape_sectors;
safepos += reshape_sectors;
@@ -4157,11 +4191,29 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk
safepos -= min_t(sector_t, reshape_sectors, safepos);
}
+ /* Having calculated the 'writepos' possibly use it
+ * to set 'stripe_addr' which is where we will write to.
+ */
+ if (mddev->reshape_backwards) {
+ BUG_ON(conf->reshape_progress == 0);
+ stripe_addr = writepos;
+ BUG_ON((mddev->dev_sectors &
+ ~((sector_t)reshape_sectors - 1))
+ - reshape_sectors - stripe_addr
+ != sector_nr);
+ } else {
+ BUG_ON(writepos != sector_nr + reshape_sectors);
+ stripe_addr = sector_nr;
+ }
+
/* 'writepos' is the most advanced device address we might write.
* 'readpos' is the least advanced device address we might read.
* 'safepos' is the least address recorded in the metadata as having
* been reshaped.
- * If 'readpos' is behind 'writepos', then there is no way that we can
+ * If there is a min_offset_diff, these are adjusted either by
+ * increasing the safepos/readpos if diff is negative, or
+ * increasing writepos if diff is positive.
+ * If 'readpos' is then behind 'writepos', there is no way that we can
* ensure safety in the face of a crash - that must be done by userspace
* making a backup of the data. So in that case there is no particular
* rush to update metadata.
@@ -4174,7 +4226,13 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk
* Maybe that number should be configurable, but I'm not sure it is
* worth it.... maybe it could be a multiple of safemode_delay???
*/
- if ((mddev->delta_disks < 0
+ if (conf->min_offset_diff < 0) {
+ safepos += -conf->min_offset_diff;
+ readpos += -conf->min_offset_diff;
+ } else
+ writepos += conf->min_offset_diff;
+
+ if ((mddev->reshape_backwards
? (safepos > writepos && readpos < writepos)
: (safepos < writepos && readpos > writepos)) ||
time_after(jiffies, conf->reshape_checkpoint + 10*HZ)) {
@@ -4195,17 +4253,6 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk
sysfs_notify(&mddev->kobj, NULL, "sync_completed");
}
- if (mddev->delta_disks < 0) {
- BUG_ON(conf->reshape_progress == 0);
- stripe_addr = writepos;
- BUG_ON((mddev->dev_sectors &
- ~((sector_t)reshape_sectors - 1))
- - reshape_sectors - stripe_addr
- != sector_nr);
- } else {
- BUG_ON(writepos != sector_nr + reshape_sectors);
- stripe_addr = sector_nr;
- }
INIT_LIST_HEAD(&stripes);
for (i = 0; i < reshape_sectors; i += STRIPE_SECTORS) {
int j;
@@ -4239,7 +4286,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk
list_add(&sh->lru, &stripes);
}
spin_lock_irq(&conf->device_lock);
- if (mddev->delta_disks < 0)
+ if (mddev->reshape_backwards)
conf->reshape_progress -= reshape_sectors * new_data_disks;
else
conf->reshape_progress += reshape_sectors * new_data_disks;
@@ -4952,16 +4999,42 @@ static int run(struct mddev *mddev)
struct md_rdev *rdev;
sector_t reshape_offset = 0;
int i;
+ long long min_offset_diff = 0;
+ int first = 1;
if (mddev->recovery_cp != MaxSector)
printk(KERN_NOTICE "md/raid:%s: not clean"
" -- starting background reconstruction\n",
mdname(mddev));
+
+ rdev_for_each(rdev, mddev) {
+ long long diff;
+ if (rdev->raid_disk < 0)
+ continue;
+ diff = (rdev->new_data_offset - rdev->data_offset);
+ if (first) {
+ min_offset_diff = diff;
+ first = 0;
+ } else if (mddev->reshape_backwards &&
+ diff < min_offset_diff)
+ min_offset_diff = diff;
+ else if (!mddev->reshape_backwards &&
+ diff > min_offset_diff)
+ min_offset_diff = diff;
+ }
+
if (mddev->reshape_position != MaxSector) {
/* Check that we can continue the reshape.
- * Currently only disks can change, it must
- * increase, and we must be past the point where
- * a stripe over-writes itself
+ * Difficulties arise if the stripe we would write to
+ * next is at or after the stripe we would read from next.
+ * For a reshape that changes the number of devices, this
+ * is only possible for a very short time, and mdadm makes
+ * sure that time appears to have past before assembling
+ * the array. So we fail if that time hasn't passed.
+ * For a reshape that keeps the number of devices the same
+ * mdadm must be monitoring the reshape can keeping the
+ * critical areas read-only and backed up. It will start
+ * the array in read-only mode, so we check for that.
*/
sector_t here_new, here_old;
int old_disks;
@@ -4993,26 +5066,34 @@ static int run(struct mddev *mddev)
/* here_old is the first stripe that we might need to read
* from */
if (mddev->delta_disks == 0) {
+ if ((here_new * mddev->new_chunk_sectors !=
+ here_old * mddev->chunk_sectors)) {
+ printk(KERN_ERR "md/raid:%s: reshape position is"
+ " confused - aborting\n", mdname(mddev));
+ return -EINVAL;
+ }
/* We cannot be sure it is safe to start an in-place
- * reshape. It is only safe if user-space if monitoring
+ * reshape. It is only safe if user-space is monitoring
* and taking constant backups.
* mdadm always starts a situation like this in
* readonly mode so it can take control before
* allowing any writes. So just check for that.
*/
- if ((here_new * mddev->new_chunk_sectors !=
- here_old * mddev->chunk_sectors) ||
- mddev->ro == 0) {
- printk(KERN_ERR "md/raid:%s: in-place reshape must be started"
- " in read-only mode - aborting\n",
+ if (abs(min_offset_diff) >= mddev->chunk_sectors &&
+ abs(min_offset_diff) >= mddev->new_chunk_sectors)
+ /* not really in-place - so OK */;
+ else if (mddev->ro == 0) {
+ printk(KERN_ERR "md/raid:%s: in-place reshape "
+ "must be started in read-only mode "
+ "- aborting\n",
mdname(mddev));
return -EINVAL;
}
- } else if (mddev->delta_disks < 0
- ? (here_new * mddev->new_chunk_sectors <=
+ } else if (mddev->reshape_backwards
+ ? (here_new * mddev->new_chunk_sectors + min_offset_diff <=
here_old * mddev->chunk_sectors)
: (here_new * mddev->new_chunk_sectors >=
- here_old * mddev->chunk_sectors)) {
+ here_old * mddev->chunk_sectors + (-min_offset_diff))) {
/* Reading from the same stripe as writing to - bad */
printk(KERN_ERR "md/raid:%s: reshape_position too early for "
"auto-recovery - aborting.\n",
@@ -5037,6 +5118,7 @@ static int run(struct mddev *mddev)
if (IS_ERR(conf))
return PTR_ERR(conf);
+ conf->min_offset_diff = min_offset_diff;
mddev->thread = conf->thread;
conf->thread = NULL;
mddev->private = conf;
@@ -5182,9 +5264,12 @@ static int run(struct mddev *mddev)
blk_queue_io_opt(mddev->queue, chunk_size *
(conf->raid_disks - conf->max_degraded));
- rdev_for_each(rdev, mddev)
+ rdev_for_each(rdev, mddev) {
disk_stack_limits(mddev->gendisk, rdev->bdev,
rdev->data_offset << 9);
+ disk_stack_limits(mddev->gendisk, rdev->bdev,
+ rdev->new_data_offset << 9);
+ }
}
return 0;
@@ -5418,12 +5503,18 @@ static int raid5_resize(struct mddev *mddev, sector_t sectors)
* any io in the removed space completes, but it hardly seems
* worth it.
*/
+ sector_t newsize;
sectors &= ~((sector_t)mddev->chunk_sectors - 1);
- md_set_array_sectors(mddev, raid5_size(mddev, sectors,
- mddev->raid_disks));
- if (mddev->array_sectors >
- raid5_size(mddev, sectors, mddev->raid_disks))
+ newsize = raid5_size(mddev, sectors, mddev->raid_disks);
+ if (mddev->external_size &&
+ mddev->array_sectors > newsize)
return -EINVAL;
+ if (mddev->bitmap) {
+ int ret = bitmap_resize(mddev->bitmap, sectors, 0, 0);
+ if (ret)
+ return ret;
+ }
+ md_set_array_sectors(mddev, newsize);
set_capacity(mddev->gendisk, mddev->array_sectors);
revalidate_disk(mddev->gendisk);
if (sectors > mddev->dev_sectors &&
@@ -5468,9 +5559,6 @@ static int check_reshape(struct mddev *mddev)
mddev->new_layout == mddev->layout &&
mddev->new_chunk_sectors == mddev->chunk_sectors)
return 0; /* nothing to do */
- if (mddev->bitmap)
- /* Cannot grow a bitmap yet */
- return -EBUSY;
if (has_failed(conf))
return -EINVAL;
if (mddev->delta_disks < 0) {
@@ -5505,10 +5593,14 @@ static int raid5_start_reshape(struct mddev *mddev)
if (!check_stripe_cache(mddev))
return -ENOSPC;
- rdev_for_each(rdev, mddev)
+ if (has_failed(conf))
+ return -EINVAL;
+
+ rdev_for_each(rdev, mddev) {
if (!test_bit(In_sync, &rdev->flags)
&& !test_bit(Faulty, &rdev->flags))
spares++;
+ }
if (spares - mddev->degraded < mddev->delta_disks - conf->max_degraded)
/* Not enough devices even to make a degraded array
@@ -5535,12 +5627,16 @@ static int raid5_start_reshape(struct mddev *mddev)
conf->chunk_sectors = mddev->new_chunk_sectors;
conf->prev_algo = conf->algorithm;
conf->algorithm = mddev->new_layout;
- if (mddev->delta_disks < 0)
+ conf->generation++;
+ /* Code that selects data_offset needs to see the generation update
+ * if reshape_progress has been set - so a memory barrier needed.
+ */
+ smp_mb();
+ if (mddev->reshape_backwards)
conf->reshape_progress = raid5_size(mddev, 0, 0);
else
conf->reshape_progress = 0;
conf->reshape_safe = conf->reshape_progress;
- conf->generation++;
spin_unlock_irq(&conf->device_lock);
/* Add some new drives, as many as will fit.
@@ -5592,6 +5688,9 @@ static int raid5_start_reshape(struct mddev *mddev)
mddev->recovery = 0;
spin_lock_irq(&conf->device_lock);
mddev->raid_disks = conf->raid_disks = conf->previous_raid_disks;
+ rdev_for_each(rdev, mddev)
+ rdev->new_data_offset = rdev->data_offset;
+ smp_wmb();
conf->reshape_progress = MaxSector;
mddev->reshape_position = MaxSector;
spin_unlock_irq(&conf->device_lock);
@@ -5610,9 +5709,13 @@ static void end_reshape(struct r5conf *conf)
{
if (!test_bit(MD_RECOVERY_INTR, &conf->mddev->recovery)) {
+ struct md_rdev *rdev;
spin_lock_irq(&conf->device_lock);
conf->previous_raid_disks = conf->raid_disks;
+ rdev_for_each(rdev, conf->mddev)
+ rdev->data_offset = rdev->new_data_offset;
+ smp_wmb();
conf->reshape_progress = MaxSector;
spin_unlock_irq(&conf->device_lock);
wake_up(&conf->wait_for_overlap);
@@ -5652,17 +5755,18 @@ static void raid5_finish_reshape(struct mddev *mddev)
d < conf->raid_disks - mddev->delta_disks;
d++) {
struct md_rdev *rdev = conf->disks[d].rdev;
- if (rdev &&
- raid5_remove_disk(mddev, rdev) == 0) {
- sysfs_unlink_rdev(mddev, rdev);
- rdev->raid_disk = -1;
- }
+ if (rdev)
+ clear_bit(In_sync, &rdev->flags);
+ rdev = conf->disks[d].replacement;
+ if (rdev)
+ clear_bit(In_sync, &rdev->flags);
}
}
mddev->layout = conf->algorithm;
mddev->chunk_sectors = conf->chunk_sectors;
mddev->reshape_position = MaxSector;
mddev->delta_disks = 0;
+ mddev->reshape_backwards = 0;
}
}
diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h
index 8d8e13934a48..2164021f3b5f 100644
--- a/drivers/md/raid5.h
+++ b/drivers/md/raid5.h
@@ -285,6 +285,7 @@ enum r5dev_flags {
*/
R5_Wantdrain, /* dev->towrite needs to be drained */
R5_WantFUA, /* Write should be FUA */
+ R5_SyncIO, /* The IO is sync */
R5_WriteError, /* got a write error - need to record it */
R5_MadeGood, /* A bad block has been fixed by writing to it */
R5_ReadRepl, /* Will/did read from replacement rather than orig */
@@ -385,6 +386,12 @@ struct r5conf {
short generation; /* increments with every reshape */
unsigned long reshape_checkpoint; /* Time we last updated
* metadata */
+ long long min_offset_diff; /* minimum difference between
+ * data_offset and
+ * new_data_offset across all
+ * devices. May be negative,
+ * but is closest to zero.
+ */
struct list_head handle_list; /* stripes needing handling */
struct list_head hold_list; /* preread ready stripes */
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index 71f8e018e564..7d42c11c8684 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -198,7 +198,6 @@ static int fops_open(struct file *file)
struct saa7146_dev *dev = video_drvdata(file);
struct saa7146_fh *fh = NULL;
int result = 0;
-
enum v4l2_buf_type type;
DEB_EE("file:%p, dev:%s\n", file, video_device_node_name(vdev));
@@ -227,11 +226,12 @@ static int fops_open(struct file *file)
goto out;
}
- file->private_data = fh;
+ v4l2_fh_init(&fh->fh, vdev);
+
+ file->private_data = &fh->fh;
fh->dev = dev;
- fh->type = type;
- if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ if (vdev->vfl_type == VFL_TYPE_VBI) {
DEB_S("initializing vbi...\n");
if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
result = saa7146_vbi_uops.open(dev,file);
@@ -252,6 +252,7 @@ static int fops_open(struct file *file)
}
result = 0;
+ v4l2_fh_add(&fh->fh);
out:
if (fh && result != 0) {
kfree(fh);
@@ -263,6 +264,7 @@ out:
static int fops_release(struct file *file)
{
+ struct video_device *vdev = video_devdata(file);
struct saa7146_fh *fh = file->private_data;
struct saa7146_dev *dev = fh->dev;
@@ -271,7 +273,7 @@ static int fops_release(struct file *file)
if (mutex_lock_interruptible(&saa7146_devices_lock))
return -ERESTARTSYS;
- if( fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ if (vdev->vfl_type == VFL_TYPE_VBI) {
if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
saa7146_vbi_uops.release(dev,file);
if (dev->ext_vv_data->vbi_fops.release)
@@ -280,6 +282,8 @@ static int fops_release(struct file *file)
saa7146_video_uops.release(dev,file);
}
+ v4l2_fh_del(&fh->fh);
+ v4l2_fh_exit(&fh->fh);
module_put(dev->ext->module);
file->private_data = NULL;
kfree(fh);
@@ -291,19 +295,22 @@ static int fops_release(struct file *file)
static int fops_mmap(struct file *file, struct vm_area_struct * vma)
{
+ struct video_device *vdev = video_devdata(file);
struct saa7146_fh *fh = file->private_data;
struct videobuf_queue *q;
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+ switch (vdev->vfl_type) {
+ case VFL_TYPE_GRABBER: {
DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p\n",
file, vma);
q = &fh->video_q;
break;
}
- case V4L2_BUF_TYPE_VBI_CAPTURE: {
+ case VFL_TYPE_VBI: {
DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p\n",
file, vma);
+ if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
+ return -ENODEV;
q = &fh->vbi_q;
break;
}
@@ -317,15 +324,19 @@ static int fops_mmap(struct file *file, struct vm_area_struct * vma)
static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait)
{
+ struct video_device *vdev = video_devdata(file);
struct saa7146_fh *fh = file->private_data;
struct videobuf_buffer *buf = NULL;
struct videobuf_queue *q;
+ unsigned int res = v4l2_ctrl_poll(file, wait);
DEB_EE("file:%p, poll:%p\n", file, wait);
- if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
+ if (vdev->vfl_type == VFL_TYPE_VBI) {
+ if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_SLICED_VBI_OUTPUT)
+ return res | POLLOUT | POLLWRNORM;
if( 0 == fh->vbi_q.streaming )
- return videobuf_poll_stream(file, &fh->vbi_q, wait);
+ return res | videobuf_poll_stream(file, &fh->vbi_q, wait);
q = &fh->vbi_q;
} else {
DEB_D("using video queue\n");
@@ -337,31 +348,32 @@ static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait)
if (!buf) {
DEB_D("buf == NULL!\n");
- return POLLERR;
+ return res | POLLERR;
}
poll_wait(file, &buf->done, wait);
if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR) {
DEB_D("poll succeeded!\n");
- return POLLIN|POLLRDNORM;
+ return res | POLLIN | POLLRDNORM;
}
DEB_D("nothing to poll for, buf->state:%d\n", buf->state);
- return 0;
+ return res;
}
static ssize_t fops_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{
+ struct video_device *vdev = video_devdata(file);
struct saa7146_fh *fh = file->private_data;
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ switch (vdev->vfl_type) {
+ case VFL_TYPE_GRABBER:
/*
DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun",
file, data, (unsigned long)count);
*/
return saa7146_video_uops.read(file,data,count,ppos);
- case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case VFL_TYPE_VBI:
/*
DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n",
file, data, (unsigned long)count);
@@ -377,12 +389,13 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof
static ssize_t fops_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
{
+ struct video_device *vdev = video_devdata(file);
struct saa7146_fh *fh = file->private_data;
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ switch (vdev->vfl_type) {
+ case VFL_TYPE_GRABBER:
return -EINVAL;
- case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case VFL_TYPE_VBI:
if (fh->dev->ext_vv_data->vbi_fops.write)
return fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos);
else
@@ -429,8 +442,15 @@ static void vv_callback(struct saa7146_dev *dev, unsigned long status)
}
}
+static const struct v4l2_ctrl_ops saa7146_ctrl_ops = {
+ .s_ctrl = saa7146_s_ctrl,
+};
+
int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
{
+ struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
+ struct v4l2_pix_format *fmt;
+ struct v4l2_vbi_format *vbi;
struct saa7146_vv *vv;
int err;
@@ -438,12 +458,32 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
if (err)
return err;
+ v4l2_ctrl_handler_init(hdl, 6);
+ v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+ v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 127, 1, 64);
+ v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 127, 1, 64);
+ v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(hdl, &saa7146_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ if (hdl->error) {
+ err = hdl->error;
+ v4l2_ctrl_handler_free(hdl);
+ return err;
+ }
+ dev->v4l2_dev.ctrl_handler = hdl;
+
vv = kzalloc(sizeof(struct saa7146_vv), GFP_KERNEL);
if (vv == NULL) {
ERR("out of memory. aborting.\n");
+ v4l2_ctrl_handler_free(hdl);
return -ENOMEM;
}
- ext_vv->ops = saa7146_video_ioctl_ops;
+ ext_vv->vid_ops = saa7146_video_ioctl_ops;
+ ext_vv->vbi_ops = saa7146_vbi_ioctl_ops;
ext_vv->core_ops = &saa7146_video_ioctl_ops;
DEB_EE("dev:%p\n", dev);
@@ -463,6 +503,7 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
if( NULL == vv->d_clipping.cpu_addr ) {
ERR("out of memory. aborting.\n");
kfree(vv);
+ v4l2_ctrl_handler_free(hdl);
return -1;
}
memset(vv->d_clipping.cpu_addr, 0x0, SAA7146_CLIPPING_MEM);
@@ -471,6 +512,39 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
saa7146_vbi_uops.init(dev,vv);
+ fmt = &vv->ov_fb.fmt;
+ fmt->width = vv->standard->h_max_out;
+ fmt->height = vv->standard->v_max_out;
+ fmt->pixelformat = V4L2_PIX_FMT_RGB565;
+ fmt->bytesperline = 2 * fmt->width;
+ fmt->sizeimage = fmt->bytesperline * fmt->height;
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
+
+ fmt = &vv->video_fmt;
+ fmt->width = 384;
+ fmt->height = 288;
+ fmt->pixelformat = V4L2_PIX_FMT_BGR24;
+ fmt->field = V4L2_FIELD_ANY;
+ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ fmt->bytesperline = 3 * fmt->width;
+ fmt->sizeimage = fmt->bytesperline * fmt->height;
+
+ vbi = &vv->vbi_fmt;
+ vbi->sampling_rate = 27000000;
+ vbi->offset = 248; /* todo */
+ vbi->samples_per_line = 720 * 2;
+ vbi->sample_format = V4L2_PIX_FMT_GREY;
+
+ /* fixme: this only works for PAL */
+ vbi->start[0] = 5;
+ vbi->count[0] = 16;
+ vbi->start[1] = 312;
+ vbi->count[1] = 16;
+
+ init_timer(&vv->vbi_read_timeout);
+
+ vv->ov_fb.capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+ vv->ov_fb.flags = V4L2_FBUF_FLAG_PRIMARY;
dev->vv_data = vv;
dev->vv_callback = &vv_callback;
@@ -486,6 +560,7 @@ int saa7146_vv_release(struct saa7146_dev* dev)
v4l2_device_unregister(&dev->v4l2_dev);
pci_free_consistent(dev->pci, SAA7146_CLIPPING_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle);
+ v4l2_ctrl_handler_free(&dev->ctrl_handler);
kfree(vv);
dev->vv_data = NULL;
dev->vv_callback = NULL;
@@ -509,10 +584,19 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
return -ENOMEM;
vfd->fops = &video_fops;
- vfd->ioctl_ops = &dev->ext_vv_data->ops;
+ if (type == VFL_TYPE_GRABBER)
+ vfd->ioctl_ops = &dev->ext_vv_data->vid_ops;
+ else
+ vfd->ioctl_ops = &dev->ext_vv_data->vbi_ops;
vfd->release = video_device_release;
+ /* Locking in file operations other than ioctl should be done by
+ the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
vfd->lock = &dev->v4l2_lock;
+ vfd->v4l2_dev = &dev->v4l2_dev;
vfd->tvnorms = 0;
+ set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
for (i = 0; i < dev->ext_vv_data->num_stds; i++)
vfd->tvnorms |= dev->ext_vv_data->stds[i].id;
strlcpy(vfd->name, name, sizeof(vfd->name));
diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c
index bc1f545c95cb..be746d1aee9a 100644
--- a/drivers/media/common/saa7146_hlp.c
+++ b/drivers/media/common/saa7146_hlp.c
@@ -343,9 +343,9 @@ static void calculate_clipping_registers_rect(struct saa7146_dev *dev, struct sa
struct saa7146_vv *vv = dev->vv_data;
__le32 *clipping = vv->d_clipping.cpu_addr;
- int width = fh->ov.win.w.width;
- int height = fh->ov.win.w.height;
- int clipcount = fh->ov.nclips;
+ int width = vv->ov.win.w.width;
+ int height = vv->ov.win.w.height;
+ int clipcount = vv->ov.nclips;
u32 line_list[32];
u32 pixel_list[32];
@@ -365,10 +365,10 @@ static void calculate_clipping_registers_rect(struct saa7146_dev *dev, struct sa
for(i = 0; i < clipcount; i++) {
int l = 0, r = 0, t = 0, b = 0;
- x[i] = fh->ov.clips[i].c.left;
- y[i] = fh->ov.clips[i].c.top;
- w[i] = fh->ov.clips[i].c.width;
- h[i] = fh->ov.clips[i].c.height;
+ x[i] = vv->ov.clips[i].c.left;
+ y[i] = vv->ov.clips[i].c.top;
+ w[i] = vv->ov.clips[i].c.width;
+ h[i] = vv->ov.clips[i].c.height;
if( w[i] < 0) {
x[i] += w[i]; w[i] = -w[i];
@@ -485,13 +485,14 @@ static void saa7146_disable_clipping(struct saa7146_dev *dev)
static void saa7146_set_clipping_rect(struct saa7146_fh *fh)
{
struct saa7146_dev *dev = fh->dev;
- enum v4l2_field field = fh->ov.win.field;
+ struct saa7146_vv *vv = dev->vv_data;
+ enum v4l2_field field = vv->ov.win.field;
struct saa7146_video_dma vdma2;
u32 clip_format;
u32 arbtr_ctrl;
/* check clipcount, disable clipping if clipcount == 0*/
- if( fh->ov.nclips == 0 ) {
+ if (vv->ov.nclips == 0) {
saa7146_disable_clipping(dev);
return;
}
@@ -651,8 +652,8 @@ int saa7146_enable_overlay(struct saa7146_fh *fh)
struct saa7146_dev *dev = fh->dev;
struct saa7146_vv *vv = dev->vv_data;
- saa7146_set_window(dev, fh->ov.win.w.width, fh->ov.win.w.height, fh->ov.win.field);
- saa7146_set_position(dev, fh->ov.win.w.left, fh->ov.win.w.top, fh->ov.win.w.height, fh->ov.win.field, vv->ov_fmt->pixelformat);
+ saa7146_set_window(dev, vv->ov.win.w.width, vv->ov.win.w.height, vv->ov.win.field);
+ saa7146_set_position(dev, vv->ov.win.w.left, vv->ov.win.w.top, vv->ov.win.w.height, vv->ov.win.field, vv->ov_fmt->pixelformat);
saa7146_set_output_format(dev, vv->ov_fmt->trans);
saa7146_set_clipping_rect(fh);
diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c
index b2e718343739..1e71e374bbfe 100644
--- a/drivers/media/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146_vbi.c
@@ -211,7 +211,7 @@ static int buffer_activate(struct saa7146_dev *dev,
DEB_VBI("dev:%p, buf:%p, next:%p\n", dev, buf, next);
saa7146_set_vbi_capture(dev,buf,next);
- mod_timer(&vv->vbi_q.timeout, jiffies+BUFFER_TIMEOUT);
+ mod_timer(&vv->vbi_dmaq.timeout, jiffies+BUFFER_TIMEOUT);
return 0;
}
@@ -294,7 +294,7 @@ static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
struct saa7146_buf *buf = (struct saa7146_buf *)vb;
DEB_VBI("vb:%p\n", vb);
- saa7146_buffer_queue(dev,&vv->vbi_q,buf);
+ saa7146_buffer_queue(dev, &vv->vbi_dmaq, buf);
}
static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
@@ -335,16 +335,15 @@ static void vbi_stop(struct saa7146_fh *fh, struct file *file)
/* shut down dma 3 transfers */
saa7146_write(dev, MC1, MASK_20);
- if (vv->vbi_q.curr) {
- saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE);
- }
+ if (vv->vbi_dmaq.curr)
+ saa7146_buffer_finish(dev, &vv->vbi_dmaq, VIDEOBUF_DONE);
videobuf_queue_cancel(&fh->vbi_q);
vv->vbi_streaming = NULL;
- del_timer(&vv->vbi_q.timeout);
- del_timer(&fh->vbi_read_timeout);
+ del_timer(&vv->vbi_dmaq.timeout);
+ del_timer(&vv->vbi_read_timeout);
spin_unlock_irqrestore(&dev->slock, flags);
}
@@ -364,12 +363,12 @@ static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
{
DEB_VBI("dev:%p\n", dev);
- INIT_LIST_HEAD(&vv->vbi_q.queue);
+ INIT_LIST_HEAD(&vv->vbi_dmaq.queue);
- init_timer(&vv->vbi_q.timeout);
- vv->vbi_q.timeout.function = saa7146_buffer_timeout;
- vv->vbi_q.timeout.data = (unsigned long)(&vv->vbi_q);
- vv->vbi_q.dev = dev;
+ init_timer(&vv->vbi_dmaq.timeout);
+ vv->vbi_dmaq.timeout.function = saa7146_buffer_timeout;
+ vv->vbi_dmaq.timeout.data = (unsigned long)(&vv->vbi_dmaq);
+ vv->vbi_dmaq.dev = dev;
init_waitqueue_head(&vv->vbi_wq);
}
@@ -377,6 +376,7 @@ static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
static int vbi_open(struct saa7146_dev *dev, struct file *file)
{
struct saa7146_fh *fh = file->private_data;
+ struct saa7146_vv *vv = fh->dev->vv_data;
u32 arbtr_ctrl = saa7146_read(dev, PCI_BT_V1);
int ret = 0;
@@ -395,19 +395,6 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
saa7146_write(dev, PCI_BT_V1, arbtr_ctrl);
saa7146_write(dev, MC2, (MASK_04|MASK_20));
- memset(&fh->vbi_fmt,0,sizeof(fh->vbi_fmt));
-
- fh->vbi_fmt.sampling_rate = 27000000;
- fh->vbi_fmt.offset = 248; /* todo */
- fh->vbi_fmt.samples_per_line = vbi_pixel_to_capture;
- fh->vbi_fmt.sample_format = V4L2_PIX_FMT_GREY;
-
- /* fixme: this only works for PAL */
- fh->vbi_fmt.start[0] = 5;
- fh->vbi_fmt.count[0] = 16;
- fh->vbi_fmt.start[1] = 312;
- fh->vbi_fmt.count[1] = 16;
-
videobuf_queue_sg_init(&fh->vbi_q, &vbi_qops,
&dev->pci->dev, &dev->slock,
V4L2_BUF_TYPE_VBI_CAPTURE,
@@ -415,9 +402,8 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
sizeof(struct saa7146_buf),
file, &dev->v4l2_lock);
- init_timer(&fh->vbi_read_timeout);
- fh->vbi_read_timeout.function = vbi_read_timeout;
- fh->vbi_read_timeout.data = (unsigned long)file;
+ vv->vbi_read_timeout.function = vbi_read_timeout;
+ vv->vbi_read_timeout.data = (unsigned long)file;
/* initialize the brs */
if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {
@@ -453,16 +439,16 @@ static void vbi_irq_done(struct saa7146_dev *dev, unsigned long status)
struct saa7146_vv *vv = dev->vv_data;
spin_lock(&dev->slock);
- if (vv->vbi_q.curr) {
- DEB_VBI("dev:%p, curr:%p\n", dev, vv->vbi_q.curr);
+ if (vv->vbi_dmaq.curr) {
+ DEB_VBI("dev:%p, curr:%p\n", dev, vv->vbi_dmaq.curr);
/* this must be += 2, one count for each field */
vv->vbi_fieldcount+=2;
- vv->vbi_q.curr->vb.field_count = vv->vbi_fieldcount;
- saa7146_buffer_finish(dev,&vv->vbi_q,VIDEOBUF_DONE);
+ vv->vbi_dmaq.curr->vb.field_count = vv->vbi_fieldcount;
+ saa7146_buffer_finish(dev, &vv->vbi_dmaq, VIDEOBUF_DONE);
} else {
DEB_VBI("dev:%p\n", dev);
}
- saa7146_buffer_next(dev,&vv->vbi_q,1);
+ saa7146_buffer_next(dev, &vv->vbi_dmaq, 1);
spin_unlock(&dev->slock);
}
@@ -488,7 +474,7 @@ static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff
return -EBUSY;
}
- mod_timer(&fh->vbi_read_timeout, jiffies+BUFFER_TIMEOUT);
+ mod_timer(&vv->vbi_read_timeout, jiffies+BUFFER_TIMEOUT);
ret = videobuf_read_stream(&fh->vbi_q, data, count, ppos, 1,
file->f_flags & O_NONBLOCK);
/*
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index ce30533fd972..6d14785d4747 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -2,6 +2,8 @@
#include <media/saa7146_vv.h>
#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ctrls.h>
#include <linux/module.h>
static int max_memory = 32;
@@ -112,8 +114,8 @@ int saa7146_start_preview(struct saa7146_fh *fh)
DEB_EE("dev:%p, fh:%p\n", dev, fh);
- /* check if we have overlay informations */
- if( NULL == fh->ov.fh ) {
+ /* check if we have overlay information */
+ if (vv->ov.fh == NULL) {
DEB_D("no overlay data available. try S_FMT first.\n");
return -EAGAIN;
}
@@ -139,19 +141,18 @@ int saa7146_start_preview(struct saa7146_fh *fh)
return -EBUSY;
}
- fmt.fmt.win = fh->ov.win;
+ fmt.fmt.win = vv->ov.win;
err = vidioc_try_fmt_vid_overlay(NULL, fh, &fmt);
if (0 != err) {
saa7146_res_free(vv->video_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP);
return -EBUSY;
}
- fh->ov.win = fmt.fmt.win;
- vv->ov_data = &fh->ov;
+ vv->ov.win = fmt.fmt.win;
DEB_D("%dx%d+%d+%d %s field=%s\n",
- fh->ov.win.w.width, fh->ov.win.w.height,
- fh->ov.win.w.left, fh->ov.win.w.top,
- vv->ov_fmt->name, v4l2_field_names[fh->ov.win.field]);
+ vv->ov.win.w.width, vv->ov.win.w.height,
+ vv->ov.win.w.left, vv->ov.win.w.top,
+ vv->ov_fmt->name, v4l2_field_names[vv->ov.win.field]);
if (0 != (ret = saa7146_enable_overlay(fh))) {
DEB_D("enabling overlay failed: %d\n", ret);
@@ -202,65 +203,6 @@ int saa7146_stop_preview(struct saa7146_fh *fh)
EXPORT_SYMBOL_GPL(saa7146_stop_preview);
/********************************************************************************/
-/* device controls */
-
-static struct v4l2_queryctrl controls[] = {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 128,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .flags = V4L2_CTRL_FLAG_SLIDER,
- },{
- .id = V4L2_CID_CONTRAST,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 64,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .flags = V4L2_CTRL_FLAG_SLIDER,
- },{
- .id = V4L2_CID_SATURATION,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 64,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .flags = V4L2_CTRL_FLAG_SLIDER,
- },{
- .id = V4L2_CID_VFLIP,
- .name = "Vertical Flip",
- .minimum = 0,
- .maximum = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },{
- .id = V4L2_CID_HFLIP,
- .name = "Horizontal Flip",
- .minimum = 0,
- .maximum = 1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },
-};
-static int NUM_CONTROLS = sizeof(controls)/sizeof(struct v4l2_queryctrl);
-
-#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 0)
-
-static struct v4l2_queryctrl* ctrl_by_id(int id)
-{
- int i;
-
- for (i = 0; i < NUM_CONTROLS; i++)
- if (controls[i].id == id)
- return controls+i;
- return NULL;
-}
-
-/********************************************************************************/
/* common pagetable functions */
static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf)
@@ -413,7 +355,7 @@ static int video_begin(struct saa7146_fh *fh)
}
}
- fmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat);
+ fmt = saa7146_format_by_fourcc(dev, vv->video_fmt.pixelformat);
/* we need to have a valid format set here */
BUG_ON(NULL == fmt);
@@ -465,7 +407,7 @@ static int video_end(struct saa7146_fh *fh, struct file *file)
return -EBUSY;
}
- fmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat);
+ fmt = saa7146_format_by_fourcc(dev, vv->video_fmt.pixelformat);
/* we need to have a valid format set here */
BUG_ON(NULL == fmt);
@@ -504,18 +446,25 @@ static int video_end(struct saa7146_fh *fh, struct file *file)
static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
{
+ struct video_device *vdev = video_devdata(file);
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
strcpy((char *)cap->driver, "saa7146 v4l2");
strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci));
- cap->version = SAA7146_VERSION_CODE;
- cap->capabilities =
+ cap->device_caps =
V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_VIDEO_OVERLAY |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING;
- cap->capabilities |= dev->ext_vv_data->capabilities;
+ cap->device_caps |= dev->ext_vv_data->capabilities;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ if (vdev->vfl_type == VFL_TYPE_GRABBER)
+ cap->device_caps &=
+ ~(V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT);
+ else
+ cap->device_caps &=
+ ~(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_AUDIO);
return 0;
}
@@ -526,6 +475,7 @@ static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *f
*fb = vv->ov_fb;
fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+ fb->flags = V4L2_FBUF_FLAG_PRIMARY;
return 0;
}
@@ -579,135 +529,58 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtd
return 0;
}
-static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c)
+int saa7146_s_ctrl(struct v4l2_ctrl *ctrl)
{
- const struct v4l2_queryctrl *ctrl;
-
- if ((c->id < V4L2_CID_BASE ||
- c->id >= V4L2_CID_LASTP1) &&
- (c->id < V4L2_CID_PRIVATE_BASE ||
- c->id >= V4L2_CID_PRIVATE_LASTP1))
- return -EINVAL;
-
- ctrl = ctrl_by_id(c->id);
- if (ctrl == NULL)
- return -EINVAL;
-
- DEB_EE("VIDIOC_QUERYCTRL: id:%d\n", c->id);
- *c = *ctrl;
- return 0;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
-{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_dev *dev = container_of(ctrl->handler,
+ struct saa7146_dev, ctrl_handler);
struct saa7146_vv *vv = dev->vv_data;
- const struct v4l2_queryctrl *ctrl;
- u32 value = 0;
+ u32 val;
- ctrl = ctrl_by_id(c->id);
- if (NULL == ctrl)
- return -EINVAL;
- switch (c->id) {
+ switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- value = saa7146_read(dev, BCS_CTRL);
- c->value = 0xff & (value >> 24);
- DEB_D("V4L2_CID_BRIGHTNESS: %d\n", c->value);
- break;
- case V4L2_CID_CONTRAST:
- value = saa7146_read(dev, BCS_CTRL);
- c->value = 0x7f & (value >> 16);
- DEB_D("V4L2_CID_CONTRAST: %d\n", c->value);
- break;
- case V4L2_CID_SATURATION:
- value = saa7146_read(dev, BCS_CTRL);
- c->value = 0x7f & (value >> 0);
- DEB_D("V4L2_CID_SATURATION: %d\n", c->value);
- break;
- case V4L2_CID_VFLIP:
- c->value = vv->vflip;
- DEB_D("V4L2_CID_VFLIP: %d\n", c->value);
- break;
- case V4L2_CID_HFLIP:
- c->value = vv->hflip;
- DEB_D("V4L2_CID_HFLIP: %d\n", c->value);
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
-{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
- struct saa7146_vv *vv = dev->vv_data;
- const struct v4l2_queryctrl *ctrl;
-
- ctrl = ctrl_by_id(c->id);
- if (NULL == ctrl) {
- DEB_D("unknown control %d\n", c->id);
- return -EINVAL;
- }
-
- switch (ctrl->type) {
- case V4L2_CTRL_TYPE_BOOLEAN:
- case V4L2_CTRL_TYPE_MENU:
- case V4L2_CTRL_TYPE_INTEGER:
- if (c->value < ctrl->minimum)
- c->value = ctrl->minimum;
- if (c->value > ctrl->maximum)
- c->value = ctrl->maximum;
- break;
- default:
- /* nothing */;
- }
-
- switch (c->id) {
- case V4L2_CID_BRIGHTNESS: {
- u32 value = saa7146_read(dev, BCS_CTRL);
- value &= 0x00ffffff;
- value |= (c->value << 24);
- saa7146_write(dev, BCS_CTRL, value);
+ val = saa7146_read(dev, BCS_CTRL);
+ val &= 0x00ffffff;
+ val |= (ctrl->val << 24);
+ saa7146_write(dev, BCS_CTRL, val);
saa7146_write(dev, MC2, MASK_22 | MASK_06);
break;
- }
- case V4L2_CID_CONTRAST: {
- u32 value = saa7146_read(dev, BCS_CTRL);
- value &= 0xff00ffff;
- value |= (c->value << 16);
- saa7146_write(dev, BCS_CTRL, value);
+
+ case V4L2_CID_CONTRAST:
+ val = saa7146_read(dev, BCS_CTRL);
+ val &= 0xff00ffff;
+ val |= (ctrl->val << 16);
+ saa7146_write(dev, BCS_CTRL, val);
saa7146_write(dev, MC2, MASK_22 | MASK_06);
break;
- }
- case V4L2_CID_SATURATION: {
- u32 value = saa7146_read(dev, BCS_CTRL);
- value &= 0xffffff00;
- value |= (c->value << 0);
- saa7146_write(dev, BCS_CTRL, value);
+
+ case V4L2_CID_SATURATION:
+ val = saa7146_read(dev, BCS_CTRL);
+ val &= 0xffffff00;
+ val |= (ctrl->val << 0);
+ saa7146_write(dev, BCS_CTRL, val);
saa7146_write(dev, MC2, MASK_22 | MASK_06);
break;
- }
+
case V4L2_CID_HFLIP:
/* fixme: we can support changing VFLIP and HFLIP here... */
- if (IS_CAPTURE_ACTIVE(fh) != 0) {
- DEB_D("V4L2_CID_HFLIP while active capture\n");
+ if ((vv->video_status & STATUS_CAPTURE))
return -EBUSY;
- }
- vv->hflip = c->value;
+ vv->hflip = ctrl->val;
break;
+
case V4L2_CID_VFLIP:
- if (IS_CAPTURE_ACTIVE(fh) != 0) {
- DEB_D("V4L2_CID_VFLIP while active capture\n");
+ if ((vv->video_status & STATUS_CAPTURE))
return -EBUSY;
- }
- vv->vflip = c->value;
+ vv->vflip = ctrl->val;
break;
+
default:
return -EINVAL;
}
- if (IS_OVERLAY_ACTIVE(fh) != 0) {
+ if ((vv->video_status & STATUS_OVERLAY) != 0) { /* CHECK: && (vv->video_fh == fh)) */
+ struct saa7146_fh *fh = vv->video_fh;
+
saa7146_stop_preview(fh);
saa7146_start_preview(fh);
}
@@ -720,6 +593,8 @@ static int vidioc_g_parm(struct file *file, void *fh,
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct saa7146_vv *vv = dev->vv_data;
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
parm->parm.capture.readbuffers = 1;
v4l2_video_std_frame_period(vv->standard->id,
&parm->parm.capture.timeperframe);
@@ -728,19 +603,28 @@ static int vidioc_g_parm(struct file *file, void *fh,
static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
{
- f->fmt.pix = ((struct saa7146_fh *)fh)->video_fmt;
+ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_vv *vv = dev->vv_data;
+
+ f->fmt.pix = vv->video_fmt;
return 0;
}
static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f)
{
- f->fmt.win = ((struct saa7146_fh *)fh)->ov.win;
+ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_vv *vv = dev->vv_data;
+
+ f->fmt.win = vv->ov.win;
return 0;
}
static int vidioc_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f)
{
- f->fmt.vbi = ((struct saa7146_fh *)fh)->vbi_fmt;
+ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct saa7146_vv *vv = dev->vv_data;
+
+ f->fmt.vbi = vv->vbi_fmt;
return 0;
}
@@ -787,6 +671,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_forma
}
f->fmt.pix.field = field;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
if (f->fmt.pix.width > maxw)
f->fmt.pix.width = maxw;
if (f->fmt.pix.height > maxh)
@@ -883,9 +768,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *__fh, struct v4l2_forma
err = vidioc_try_fmt_vid_cap(file, fh, f);
if (0 != err)
return err;
- fh->video_fmt = f->fmt.pix;
+ vv->video_fmt = f->fmt.pix;
DEB_EE("set to pixelformat '%4.4s'\n",
- (char *)&fh->video_fmt.pixelformat);
+ (char *)&vv->video_fmt.pixelformat);
return 0;
}
@@ -900,17 +785,17 @@ static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_f
err = vidioc_try_fmt_vid_overlay(file, fh, f);
if (0 != err)
return err;
- fh->ov.win = f->fmt.win;
- fh->ov.nclips = f->fmt.win.clipcount;
- if (fh->ov.nclips > 16)
- fh->ov.nclips = 16;
- if (copy_from_user(fh->ov.clips, f->fmt.win.clips,
- sizeof(struct v4l2_clip) * fh->ov.nclips)) {
+ vv->ov.win = f->fmt.win;
+ vv->ov.nclips = f->fmt.win.clipcount;
+ if (vv->ov.nclips > 16)
+ vv->ov.nclips = 16;
+ if (copy_from_user(vv->ov.clips, f->fmt.win.clips,
+ sizeof(struct v4l2_clip) * vv->ov.nclips)) {
return -EFAULT;
}
- /* fh->ov.fh is used to indicate that we have valid overlay informations, too */
- fh->ov.fh = fh;
+ /* vv->ov.fh is used to indicate that we have valid overlay informations, too */
+ vv->ov.fh = fh;
/* check if our current overlay is active */
if (IS_OVERLAY_ACTIVE(fh) != 0) {
@@ -1111,10 +996,14 @@ static int vidioc_g_chip_ident(struct file *file, void *__fh,
chip->ident = V4L2_IDENT_NONE;
chip->revision = 0;
- if (chip->match.type == V4L2_CHIP_MATCH_HOST && !chip->match.addr) {
- chip->ident = V4L2_IDENT_SAA7146;
+ if (chip->match.type == V4L2_CHIP_MATCH_HOST) {
+ if (v4l2_chip_match_host(&chip->match))
+ chip->ident = V4L2_IDENT_SAA7146;
return 0;
}
+ if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
+ chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+ return -EINVAL;
return v4l2_device_call_until_err(&dev->v4l2_dev, 0,
core, g_chip_ident, chip);
}
@@ -1129,7 +1018,6 @@ const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
.vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay,
.vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay,
.vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay,
- .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_g_chip_ident = vidioc_g_chip_ident,
.vidioc_overlay = vidioc_overlay,
@@ -1141,12 +1029,29 @@ const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_g_std = vidioc_g_std,
.vidioc_s_std = vidioc_s_std,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
.vidioc_g_parm = vidioc_g_parm,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+const struct v4l2_ioctl_ops saa7146_vbi_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
+ .vidioc_g_chip_ident = vidioc_g_chip_ident,
+
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_g_std = vidioc_g_std,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_g_parm = vidioc_g_parm,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
/*********************************************************************************/
@@ -1161,7 +1066,7 @@ static int buffer_activate (struct saa7146_dev *dev,
buf->vb.state = VIDEOBUF_ACTIVE;
saa7146_set_capture(dev,buf,next);
- mod_timer(&vv->video_q.timeout, jiffies+BUFFER_TIMEOUT);
+ mod_timer(&vv->video_dmaq.timeout, jiffies+BUFFER_TIMEOUT);
return 0;
}
@@ -1185,44 +1090,44 @@ static int buffer_prepare(struct videobuf_queue *q,
DEB_CAP("vbuf:%p\n", vb);
/* sanity checks */
- if (fh->video_fmt.width < 48 ||
- fh->video_fmt.height < 32 ||
- fh->video_fmt.width > vv->standard->h_max_out ||
- fh->video_fmt.height > vv->standard->v_max_out) {
+ if (vv->video_fmt.width < 48 ||
+ vv->video_fmt.height < 32 ||
+ vv->video_fmt.width > vv->standard->h_max_out ||
+ vv->video_fmt.height > vv->standard->v_max_out) {
DEB_D("w (%d) / h (%d) out of bounds\n",
- fh->video_fmt.width, fh->video_fmt.height);
+ vv->video_fmt.width, vv->video_fmt.height);
return -EINVAL;
}
- size = fh->video_fmt.sizeimage;
+ size = vv->video_fmt.sizeimage;
if (0 != buf->vb.baddr && buf->vb.bsize < size) {
DEB_D("size mismatch\n");
return -EINVAL;
}
DEB_CAP("buffer_prepare [size=%dx%d,bytes=%d,fields=%s]\n",
- fh->video_fmt.width, fh->video_fmt.height,
- size, v4l2_field_names[fh->video_fmt.field]);
- if (buf->vb.width != fh->video_fmt.width ||
- buf->vb.bytesperline != fh->video_fmt.bytesperline ||
- buf->vb.height != fh->video_fmt.height ||
+ vv->video_fmt.width, vv->video_fmt.height,
+ size, v4l2_field_names[vv->video_fmt.field]);
+ if (buf->vb.width != vv->video_fmt.width ||
+ buf->vb.bytesperline != vv->video_fmt.bytesperline ||
+ buf->vb.height != vv->video_fmt.height ||
buf->vb.size != size ||
buf->vb.field != field ||
- buf->vb.field != fh->video_fmt.field ||
- buf->fmt != &fh->video_fmt) {
+ buf->vb.field != vv->video_fmt.field ||
+ buf->fmt != &vv->video_fmt) {
saa7146_dma_free(dev,q,buf);
}
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
struct saa7146_format *sfmt;
- buf->vb.bytesperline = fh->video_fmt.bytesperline;
- buf->vb.width = fh->video_fmt.width;
- buf->vb.height = fh->video_fmt.height;
+ buf->vb.bytesperline = vv->video_fmt.bytesperline;
+ buf->vb.width = vv->video_fmt.width;
+ buf->vb.height = vv->video_fmt.height;
buf->vb.size = size;
buf->vb.field = field;
- buf->fmt = &fh->video_fmt;
- buf->vb.field = fh->video_fmt.field;
+ buf->fmt = &vv->video_fmt;
+ buf->vb.field = vv->video_fmt.field;
sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
@@ -1258,11 +1163,12 @@ static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned
{
struct file *file = q->priv_data;
struct saa7146_fh *fh = file->private_data;
+ struct saa7146_vv *vv = fh->dev->vv_data;
if (0 == *count || *count > MAX_SAA7146_CAPTURE_BUFFERS)
*count = MAX_SAA7146_CAPTURE_BUFFERS;
- *size = fh->video_fmt.sizeimage;
+ *size = vv->video_fmt.sizeimage;
/* check if we exceed the "max_memory" parameter */
if( (*count * *size) > (max_memory*1048576) ) {
@@ -1283,7 +1189,7 @@ static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
struct saa7146_buf *buf = (struct saa7146_buf *)vb;
DEB_CAP("vbuf:%p\n", vb);
- saa7146_buffer_queue(fh->dev,&vv->video_q,buf);
+ saa7146_buffer_queue(fh->dev, &vv->video_dmaq, buf);
}
static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
@@ -1312,12 +1218,12 @@ static struct videobuf_queue_ops video_qops = {
static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
{
- INIT_LIST_HEAD(&vv->video_q.queue);
+ INIT_LIST_HEAD(&vv->video_dmaq.queue);
- init_timer(&vv->video_q.timeout);
- vv->video_q.timeout.function = saa7146_buffer_timeout;
- vv->video_q.timeout.data = (unsigned long)(&vv->video_q);
- vv->video_q.dev = dev;
+ init_timer(&vv->video_dmaq.timeout);
+ vv->video_dmaq.timeout.function = saa7146_buffer_timeout;
+ vv->video_dmaq.timeout.data = (unsigned long)(&vv->video_dmaq);
+ vv->video_dmaq.dev = dev;
/* set some default values */
vv->standard = &dev->ext_vv_data->stds[0];
@@ -1331,15 +1237,6 @@ static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
static int video_open(struct saa7146_dev *dev, struct file *file)
{
struct saa7146_fh *fh = file->private_data;
- struct saa7146_format *sfmt;
-
- fh->video_fmt.width = 384;
- fh->video_fmt.height = 288;
- fh->video_fmt.pixelformat = V4L2_PIX_FMT_BGR24;
- fh->video_fmt.bytesperline = 0;
- fh->video_fmt.field = V4L2_FIELD_ANY;
- sfmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat);
- fh->video_fmt.sizeimage = (fh->video_fmt.width * fh->video_fmt.height * sfmt->depth)/8;
videobuf_queue_sg_init(&fh->video_q, &video_qops,
&dev->pci->dev, &dev->slock,
@@ -1371,7 +1268,7 @@ static void video_close(struct saa7146_dev *dev, struct file *file)
static void video_irq_done(struct saa7146_dev *dev, unsigned long st)
{
struct saa7146_vv *vv = dev->vv_data;
- struct saa7146_dmaqueue *q = &vv->video_q;
+ struct saa7146_dmaqueue *q = &vv->video_dmaq;
spin_lock(&dev->slock);
DEB_CAP("called\n");
diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig
index 4a6d5cef3964..bbf4945149a9 100644
--- a/drivers/media/common/tuners/Kconfig
+++ b/drivers/media/common/tuners/Kconfig
@@ -204,6 +204,27 @@ config MEDIA_TUNER_TDA18218
help
NXP TDA18218 silicon tuner driver.
+config MEDIA_TUNER_FC0011
+ tristate "Fitipower FC0011 silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ Fitipower FC0011 silicon tuner driver.
+
+config MEDIA_TUNER_FC0012
+ tristate "Fitipower FC0012 silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ Fitipower FC0012 silicon tuner driver.
+
+config MEDIA_TUNER_FC0013
+ tristate "Fitipower FC0013 silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ Fitipower FC0013 silicon tuner driver.
+
config MEDIA_TUNER_TDA18212
tristate "NXP TDA18212 silicon tuner"
depends on VIDEO_MEDIA && I2C
@@ -211,4 +232,10 @@ config MEDIA_TUNER_TDA18212
help
NXP TDA18212 silicon tuner driver.
+config MEDIA_TUNER_TUA9001
+ tristate "Infineon TUA 9001 silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ Infineon TUA 9001 silicon tuner driver.
endmenu
diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile
index f80407eb8998..891b80e60808 100644
--- a/drivers/media/common/tuners/Makefile
+++ b/drivers/media/common/tuners/Makefile
@@ -28,6 +28,10 @@ obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o
obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o
obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o
obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o
+obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o
+obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o
+obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o
+obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o
ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
diff --git a/drivers/media/common/tuners/fc0011.c b/drivers/media/common/tuners/fc0011.c
new file mode 100644
index 000000000000..e4882546c283
--- /dev/null
+++ b/drivers/media/common/tuners/fc0011.c
@@ -0,0 +1,524 @@
+/*
+ * Fitipower FC0011 tuner driver
+ *
+ * Copyright (C) 2012 Michael Buesch <m@bues.ch>
+ *
+ * Derived from FC0012 tuner driver:
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "fc0011.h"
+
+
+/* Tuner registers */
+enum {
+ FC11_REG_0,
+ FC11_REG_FA, /* FA */
+ FC11_REG_FP, /* FP */
+ FC11_REG_XINHI, /* XIN high 8 bit */
+ FC11_REG_XINLO, /* XIN low 8 bit */
+ FC11_REG_VCO, /* VCO */
+ FC11_REG_VCOSEL, /* VCO select */
+ FC11_REG_7, /* Unknown tuner reg 7 */
+ FC11_REG_8, /* Unknown tuner reg 8 */
+ FC11_REG_9,
+ FC11_REG_10, /* Unknown tuner reg 10 */
+ FC11_REG_11, /* Unknown tuner reg 11 */
+ FC11_REG_12,
+ FC11_REG_RCCAL, /* RC calibrate */
+ FC11_REG_VCOCAL, /* VCO calibrate */
+ FC11_REG_15,
+ FC11_REG_16, /* Unknown tuner reg 16 */
+ FC11_REG_17,
+
+ FC11_NR_REGS, /* Number of registers */
+};
+
+enum FC11_REG_VCOSEL_bits {
+ FC11_VCOSEL_2 = 0x08, /* VCO select 2 */
+ FC11_VCOSEL_1 = 0x10, /* VCO select 1 */
+ FC11_VCOSEL_CLKOUT = 0x20, /* Fix clock out */
+ FC11_VCOSEL_BW7M = 0x40, /* 7MHz bw */
+ FC11_VCOSEL_BW6M = 0x80, /* 6MHz bw */
+};
+
+enum FC11_REG_RCCAL_bits {
+ FC11_RCCAL_FORCE = 0x10, /* force */
+};
+
+enum FC11_REG_VCOCAL_bits {
+ FC11_VCOCAL_RUN = 0, /* VCO calibration run */
+ FC11_VCOCAL_VALUEMASK = 0x3F, /* VCO calibration value mask */
+ FC11_VCOCAL_OK = 0x40, /* VCO calibration Ok */
+ FC11_VCOCAL_RESET = 0x80, /* VCO calibration reset */
+};
+
+
+struct fc0011_priv {
+ struct i2c_adapter *i2c;
+ u8 addr;
+
+ u32 frequency;
+ u32 bandwidth;
+};
+
+
+static int fc0011_writereg(struct fc0011_priv *priv, u8 reg, u8 val)
+{
+ u8 buf[2] = { reg, val };
+ struct i2c_msg msg = { .addr = priv->addr,
+ .flags = 0, .buf = buf, .len = 2 };
+
+ if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+ dev_err(&priv->i2c->dev,
+ "I2C write reg failed, reg: %02x, val: %02x\n",
+ reg, val);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int fc0011_readreg(struct fc0011_priv *priv, u8 reg, u8 *val)
+{
+ u8 dummy;
+ struct i2c_msg msg[2] = {
+ { .addr = priv->addr,
+ .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = priv->addr,
+ .flags = I2C_M_RD, .buf = val ? : &dummy, .len = 1 },
+ };
+
+ if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+ dev_err(&priv->i2c->dev,
+ "I2C read failed, reg: %02x\n", reg);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int fc0011_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+
+ return 0;
+}
+
+static int fc0011_init(struct dvb_frontend *fe)
+{
+ struct fc0011_priv *priv = fe->tuner_priv;
+ int err;
+
+ if (WARN_ON(!fe->callback))
+ return -EINVAL;
+
+ err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
+ FC0011_FE_CALLBACK_POWER, priv->addr);
+ if (err) {
+ dev_err(&priv->i2c->dev, "Power-on callback failed\n");
+ return err;
+ }
+ err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
+ FC0011_FE_CALLBACK_RESET, priv->addr);
+ if (err) {
+ dev_err(&priv->i2c->dev, "Reset callback failed\n");
+ return err;
+ }
+
+ return 0;
+}
+
+/* Initiate VCO calibration */
+static int fc0011_vcocal_trigger(struct fc0011_priv *priv)
+{
+ int err;
+
+ err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RESET);
+ if (err)
+ return err;
+ err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+/* Read VCO calibration value */
+static int fc0011_vcocal_read(struct fc0011_priv *priv, u8 *value)
+{
+ int err;
+
+ err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN);
+ if (err)
+ return err;
+ usleep_range(10000, 20000);
+ err = fc0011_readreg(priv, FC11_REG_VCOCAL, value);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int fc0011_set_params(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ struct fc0011_priv *priv = fe->tuner_priv;
+ int err;
+ unsigned int i, vco_retries;
+ u32 freq = p->frequency / 1000;
+ u32 bandwidth = p->bandwidth_hz / 1000;
+ u32 fvco, xin, xdiv, xdivr;
+ u16 frac;
+ u8 fa, fp, vco_sel, vco_cal;
+ u8 regs[FC11_NR_REGS] = { };
+
+ regs[FC11_REG_7] = 0x0F;
+ regs[FC11_REG_8] = 0x3E;
+ regs[FC11_REG_10] = 0xB8;
+ regs[FC11_REG_11] = 0x80;
+ regs[FC11_REG_RCCAL] = 0x04;
+ err = fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]);
+ err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]);
+ err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]);
+ err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]);
+ err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]);
+ if (err)
+ return -EIO;
+
+ /* Set VCO freq and VCO div */
+ if (freq < 54000) {
+ fvco = freq * 64;
+ regs[FC11_REG_VCO] = 0x82;
+ } else if (freq < 108000) {
+ fvco = freq * 32;
+ regs[FC11_REG_VCO] = 0x42;
+ } else if (freq < 216000) {
+ fvco = freq * 16;
+ regs[FC11_REG_VCO] = 0x22;
+ } else if (freq < 432000) {
+ fvco = freq * 8;
+ regs[FC11_REG_VCO] = 0x12;
+ } else {
+ fvco = freq * 4;
+ regs[FC11_REG_VCO] = 0x0A;
+ }
+
+ /* Calc XIN. The PLL reference frequency is 18 MHz. */
+ xdiv = fvco / 18000;
+ frac = fvco - xdiv * 18000;
+ frac = (frac << 15) / 18000;
+ if (frac >= 16384)
+ frac += 32786;
+ if (!frac)
+ xin = 0;
+ else if (frac < 511)
+ xin = 512;
+ else if (frac < 65026)
+ xin = frac;
+ else
+ xin = 65024;
+ regs[FC11_REG_XINHI] = xin >> 8;
+ regs[FC11_REG_XINLO] = xin;
+
+ /* Calc FP and FA */
+ xdivr = xdiv;
+ if (fvco - xdiv * 18000 >= 9000)
+ xdivr += 1; /* round */
+ fp = xdivr / 8;
+ fa = xdivr - fp * 8;
+ if (fa < 2) {
+ fp -= 1;
+ fa += 8;
+ }
+ if (fp > 0x1F) {
+ fp &= 0x1F;
+ fa &= 0xF;
+ }
+ if (fa >= fp) {
+ dev_warn(&priv->i2c->dev,
+ "fa %02X >= fp %02X, but trying to continue\n",
+ (unsigned int)(u8)fa, (unsigned int)(u8)fp);
+ }
+ regs[FC11_REG_FA] = fa;
+ regs[FC11_REG_FP] = fp;
+
+ /* Select bandwidth */
+ switch (bandwidth) {
+ case 8000:
+ break;
+ case 7000:
+ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW7M;
+ break;
+ default:
+ dev_warn(&priv->i2c->dev, "Unsupported bandwidth %u kHz. "
+ "Using 6000 kHz.\n",
+ bandwidth);
+ bandwidth = 6000;
+ /* fallthrough */
+ case 6000:
+ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW6M;
+ break;
+ }
+
+ /* Pre VCO select */
+ if (fvco < 2320000) {
+ vco_sel = 0;
+ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+ } else if (fvco < 3080000) {
+ vco_sel = 1;
+ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
+ } else {
+ vco_sel = 2;
+ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2;
+ }
+
+ /* Fix for low freqs */
+ if (freq < 45000) {
+ regs[FC11_REG_FA] = 0x6;
+ regs[FC11_REG_FP] = 0x11;
+ }
+
+ /* Clock out fix */
+ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_CLKOUT;
+
+ /* Write the cached registers */
+ for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++) {
+ err = fc0011_writereg(priv, i, regs[i]);
+ if (err)
+ return err;
+ }
+
+ /* VCO calibration */
+ err = fc0011_vcocal_trigger(priv);
+ if (err)
+ return err;
+ err = fc0011_vcocal_read(priv, &vco_cal);
+ if (err)
+ return err;
+ vco_retries = 0;
+ while (!(vco_cal & FC11_VCOCAL_OK) && vco_retries < 3) {
+ /* Reset the tuner and try again */
+ err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
+ FC0011_FE_CALLBACK_RESET, priv->addr);
+ if (err) {
+ dev_err(&priv->i2c->dev, "Failed to reset tuner\n");
+ return err;
+ }
+ /* Reinit tuner config */
+ err = 0;
+ for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++)
+ err |= fc0011_writereg(priv, i, regs[i]);
+ err |= fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]);
+ err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]);
+ err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]);
+ err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]);
+ err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]);
+ if (err)
+ return -EIO;
+ /* VCO calibration */
+ err = fc0011_vcocal_trigger(priv);
+ if (err)
+ return err;
+ err = fc0011_vcocal_read(priv, &vco_cal);
+ if (err)
+ return err;
+ vco_retries++;
+ }
+ if (!(vco_cal & FC11_VCOCAL_OK)) {
+ dev_err(&priv->i2c->dev,
+ "Failed to read VCO calibration value (got %02X)\n",
+ (unsigned int)vco_cal);
+ return -EIO;
+ }
+ vco_cal &= FC11_VCOCAL_VALUEMASK;
+
+ switch (vco_sel) {
+ case 0:
+ if (vco_cal < 8) {
+ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
+ err = fc0011_writereg(priv, FC11_REG_VCOSEL,
+ regs[FC11_REG_VCOSEL]);
+ if (err)
+ return err;
+ err = fc0011_vcocal_trigger(priv);
+ if (err)
+ return err;
+ } else {
+ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+ err = fc0011_writereg(priv, FC11_REG_VCOSEL,
+ regs[FC11_REG_VCOSEL]);
+ if (err)
+ return err;
+ }
+ break;
+ case 1:
+ if (vco_cal < 5) {
+ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2;
+ err = fc0011_writereg(priv, FC11_REG_VCOSEL,
+ regs[FC11_REG_VCOSEL]);
+ if (err)
+ return err;
+ err = fc0011_vcocal_trigger(priv);
+ if (err)
+ return err;
+ } else if (vco_cal <= 48) {
+ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
+ err = fc0011_writereg(priv, FC11_REG_VCOSEL,
+ regs[FC11_REG_VCOSEL]);
+ if (err)
+ return err;
+ } else {
+ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+ err = fc0011_writereg(priv, FC11_REG_VCOSEL,
+ regs[FC11_REG_VCOSEL]);
+ if (err)
+ return err;
+ err = fc0011_vcocal_trigger(priv);
+ if (err)
+ return err;
+ }
+ break;
+ case 2:
+ if (vco_cal > 53) {
+ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1;
+ err = fc0011_writereg(priv, FC11_REG_VCOSEL,
+ regs[FC11_REG_VCOSEL]);
+ if (err)
+ return err;
+ err = fc0011_vcocal_trigger(priv);
+ if (err)
+ return err;
+ } else {
+ regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2);
+ regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2;
+ err = fc0011_writereg(priv, FC11_REG_VCOSEL,
+ regs[FC11_REG_VCOSEL]);
+ if (err)
+ return err;
+ }
+ break;
+ }
+ err = fc0011_vcocal_read(priv, NULL);
+ if (err)
+ return err;
+ usleep_range(10000, 50000);
+
+ err = fc0011_readreg(priv, FC11_REG_RCCAL, &regs[FC11_REG_RCCAL]);
+ if (err)
+ return err;
+ regs[FC11_REG_RCCAL] |= FC11_RCCAL_FORCE;
+ err = fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]);
+ if (err)
+ return err;
+ err = fc0011_writereg(priv, FC11_REG_16, 0xB);
+ if (err)
+ return err;
+
+ dev_dbg(&priv->i2c->dev, "Tuned to "
+ "fa=%02X fp=%02X xin=%02X%02X vco=%02X vcosel=%02X "
+ "vcocal=%02X(%u) bw=%u\n",
+ (unsigned int)regs[FC11_REG_FA],
+ (unsigned int)regs[FC11_REG_FP],
+ (unsigned int)regs[FC11_REG_XINHI],
+ (unsigned int)regs[FC11_REG_XINLO],
+ (unsigned int)regs[FC11_REG_VCO],
+ (unsigned int)regs[FC11_REG_VCOSEL],
+ (unsigned int)vco_cal, vco_retries,
+ (unsigned int)bandwidth);
+
+ priv->frequency = p->frequency;
+ priv->bandwidth = p->bandwidth_hz;
+
+ return 0;
+}
+
+static int fc0011_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct fc0011_priv *priv = fe->tuner_priv;
+
+ *frequency = priv->frequency;
+
+ return 0;
+}
+
+static int fc0011_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ *frequency = 0;
+
+ return 0;
+}
+
+static int fc0011_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+ struct fc0011_priv *priv = fe->tuner_priv;
+
+ *bandwidth = priv->bandwidth;
+
+ return 0;
+}
+
+static const struct dvb_tuner_ops fc0011_tuner_ops = {
+ .info = {
+ .name = "Fitipower FC0011",
+
+ .frequency_min = 45000000,
+ .frequency_max = 1000000000,
+ },
+
+ .release = fc0011_release,
+ .init = fc0011_init,
+
+ .set_params = fc0011_set_params,
+
+ .get_frequency = fc0011_get_frequency,
+ .get_if_frequency = fc0011_get_if_frequency,
+ .get_bandwidth = fc0011_get_bandwidth,
+};
+
+struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ const struct fc0011_config *config)
+{
+ struct fc0011_priv *priv;
+
+ priv = kzalloc(sizeof(struct fc0011_priv), GFP_KERNEL);
+ if (!priv)
+ return NULL;
+
+ priv->i2c = i2c;
+ priv->addr = config->i2c_address;
+
+ fe->tuner_priv = priv;
+ fe->ops.tuner_ops = fc0011_tuner_ops;
+
+ dev_info(&priv->i2c->dev, "Fitipower FC0011 tuner attached\n");
+
+ return fe;
+}
+EXPORT_SYMBOL(fc0011_attach);
+
+MODULE_DESCRIPTION("Fitipower FC0011 silicon tuner driver");
+MODULE_AUTHOR("Michael Buesch <m@bues.ch>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/fc0011.h b/drivers/media/common/tuners/fc0011.h
new file mode 100644
index 000000000000..0ee581f122d2
--- /dev/null
+++ b/drivers/media/common/tuners/fc0011.h
@@ -0,0 +1,41 @@
+#ifndef LINUX_FC0011_H_
+#define LINUX_FC0011_H_
+
+#include "dvb_frontend.h"
+
+
+/** struct fc0011_config - fc0011 hardware config
+ *
+ * @i2c_address: I2C bus address.
+ */
+struct fc0011_config {
+ u8 i2c_address;
+};
+
+/** enum fc0011_fe_callback_commands - Frontend callbacks
+ *
+ * @FC0011_FE_CALLBACK_POWER: Power on tuner hardware.
+ * @FC0011_FE_CALLBACK_RESET: Request a tuner reset.
+ */
+enum fc0011_fe_callback_commands {
+ FC0011_FE_CALLBACK_POWER,
+ FC0011_FE_CALLBACK_RESET,
+};
+
+#if defined(CONFIG_MEDIA_TUNER_FC0011) ||\
+ defined(CONFIG_MEDIA_TUNER_FC0011_MODULE)
+struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ const struct fc0011_config *config);
+#else
+static inline
+struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ const struct fc0011_config *config)
+{
+ dev_err(&i2c->dev, "fc0011 driver disabled in Kconfig\n");
+ return NULL;
+}
+#endif
+
+#endif /* LINUX_FC0011_H_ */
diff --git a/drivers/media/common/tuners/fc0012-priv.h b/drivers/media/common/tuners/fc0012-priv.h
new file mode 100644
index 000000000000..4577c917e616
--- /dev/null
+++ b/drivers/media/common/tuners/fc0012-priv.h
@@ -0,0 +1,43 @@
+/*
+ * Fitipower FC0012 tuner driver - private includes
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _FC0012_PRIV_H_
+#define _FC0012_PRIV_H_
+
+#define LOG_PREFIX "fc0012"
+
+#undef err
+#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+struct fc0012_priv {
+ struct i2c_adapter *i2c;
+ u8 addr;
+ u8 dual_master;
+ u8 xtal_freq;
+
+ u32 frequency;
+ u32 bandwidth;
+};
+
+#endif
diff --git a/drivers/media/common/tuners/fc0012.c b/drivers/media/common/tuners/fc0012.c
new file mode 100644
index 000000000000..308135abd54c
--- /dev/null
+++ b/drivers/media/common/tuners/fc0012.c
@@ -0,0 +1,467 @@
+/*
+ * Fitipower FC0012 tuner driver
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "fc0012.h"
+#include "fc0012-priv.h"
+
+static int fc0012_writereg(struct fc0012_priv *priv, u8 reg, u8 val)
+{
+ u8 buf[2] = {reg, val};
+ struct i2c_msg msg = {
+ .addr = priv->addr, .flags = 0, .buf = buf, .len = 2
+ };
+
+ if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+ err("I2C write reg failed, reg: %02x, val: %02x", reg, val);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int fc0012_readreg(struct fc0012_priv *priv, u8 reg, u8 *val)
+{
+ struct i2c_msg msg[2] = {
+ { .addr = priv->addr, .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 },
+ };
+
+ if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+ err("I2C read reg failed, reg: %02x", reg);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int fc0012_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static int fc0012_init(struct dvb_frontend *fe)
+{
+ struct fc0012_priv *priv = fe->tuner_priv;
+ int i, ret = 0;
+ unsigned char reg[] = {
+ 0x00, /* dummy reg. 0 */
+ 0x05, /* reg. 0x01 */
+ 0x10, /* reg. 0x02 */
+ 0x00, /* reg. 0x03 */
+ 0x00, /* reg. 0x04 */
+ 0x0f, /* reg. 0x05: may also be 0x0a */
+ 0x00, /* reg. 0x06: divider 2, VCO slow */
+ 0x00, /* reg. 0x07: may also be 0x0f */
+ 0xff, /* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256,
+ Loop Bw 1/8 */
+ 0x6e, /* reg. 0x09: Disable LoopThrough, Enable LoopThrough: 0x6f */
+ 0xb8, /* reg. 0x0a: Disable LO Test Buffer */
+ 0x82, /* reg. 0x0b: Output Clock is same as clock frequency,
+ may also be 0x83 */
+ 0xfc, /* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */
+ 0x02, /* reg. 0x0d: AGC Not Forcing & LNA Forcing, 0x02 for DVB-T */
+ 0x00, /* reg. 0x0e */
+ 0x00, /* reg. 0x0f */
+ 0x00, /* reg. 0x10: may also be 0x0d */
+ 0x00, /* reg. 0x11 */
+ 0x1f, /* reg. 0x12: Set to maximum gain */
+ 0x08, /* reg. 0x13: Set to Middle Gain: 0x08,
+ Low Gain: 0x00, High Gain: 0x10, enable IX2: 0x80 */
+ 0x00, /* reg. 0x14 */
+ 0x04, /* reg. 0x15: Enable LNA COMPS */
+ };
+
+ switch (priv->xtal_freq) {
+ case FC_XTAL_27_MHZ:
+ case FC_XTAL_28_8_MHZ:
+ reg[0x07] |= 0x20;
+ break;
+ case FC_XTAL_36_MHZ:
+ default:
+ break;
+ }
+
+ if (priv->dual_master)
+ reg[0x0c] |= 0x02;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ for (i = 1; i < sizeof(reg); i++) {
+ ret = fc0012_writereg(priv, i, reg[i]);
+ if (ret)
+ break;
+ }
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+ if (ret)
+ err("fc0012_writereg failed: %d", ret);
+
+ return ret;
+}
+
+static int fc0012_sleep(struct dvb_frontend *fe)
+{
+ /* nothing to do here */
+ return 0;
+}
+
+static int fc0012_set_params(struct dvb_frontend *fe)
+{
+ struct fc0012_priv *priv = fe->tuner_priv;
+ int i, ret = 0;
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ u32 freq = p->frequency / 1000;
+ u32 delsys = p->delivery_system;
+ unsigned char reg[7], am, pm, multi, tmp;
+ unsigned long f_vco;
+ unsigned short xtal_freq_khz_2, xin, xdiv;
+ int vco_select = false;
+
+ if (fe->callback) {
+ ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
+ FC_FE_CALLBACK_VHF_ENABLE, (freq > 300000 ? 0 : 1));
+ if (ret)
+ goto exit;
+ }
+
+ switch (priv->xtal_freq) {
+ case FC_XTAL_27_MHZ:
+ xtal_freq_khz_2 = 27000 / 2;
+ break;
+ case FC_XTAL_36_MHZ:
+ xtal_freq_khz_2 = 36000 / 2;
+ break;
+ case FC_XTAL_28_8_MHZ:
+ default:
+ xtal_freq_khz_2 = 28800 / 2;
+ break;
+ }
+
+ /* select frequency divider and the frequency of VCO */
+ if (freq < 37084) { /* freq * 96 < 3560000 */
+ multi = 96;
+ reg[5] = 0x82;
+ reg[6] = 0x00;
+ } else if (freq < 55625) { /* freq * 64 < 3560000 */
+ multi = 64;
+ reg[5] = 0x82;
+ reg[6] = 0x02;
+ } else if (freq < 74167) { /* freq * 48 < 3560000 */
+ multi = 48;
+ reg[5] = 0x42;
+ reg[6] = 0x00;
+ } else if (freq < 111250) { /* freq * 32 < 3560000 */
+ multi = 32;
+ reg[5] = 0x42;
+ reg[6] = 0x02;
+ } else if (freq < 148334) { /* freq * 24 < 3560000 */
+ multi = 24;
+ reg[5] = 0x22;
+ reg[6] = 0x00;
+ } else if (freq < 222500) { /* freq * 16 < 3560000 */
+ multi = 16;
+ reg[5] = 0x22;
+ reg[6] = 0x02;
+ } else if (freq < 296667) { /* freq * 12 < 3560000 */
+ multi = 12;
+ reg[5] = 0x12;
+ reg[6] = 0x00;
+ } else if (freq < 445000) { /* freq * 8 < 3560000 */
+ multi = 8;
+ reg[5] = 0x12;
+ reg[6] = 0x02;
+ } else if (freq < 593334) { /* freq * 6 < 3560000 */
+ multi = 6;
+ reg[5] = 0x0a;
+ reg[6] = 0x00;
+ } else {
+ multi = 4;
+ reg[5] = 0x0a;
+ reg[6] = 0x02;
+ }
+
+ f_vco = freq * multi;
+
+ if (f_vco >= 3060000) {
+ reg[6] |= 0x08;
+ vco_select = true;
+ }
+
+ if (freq >= 45000) {
+ /* From divided value (XDIV) determined the FA and FP value */
+ xdiv = (unsigned short)(f_vco / xtal_freq_khz_2);
+ if ((f_vco - xdiv * xtal_freq_khz_2) >= (xtal_freq_khz_2 / 2))
+ xdiv++;
+
+ pm = (unsigned char)(xdiv / 8);
+ am = (unsigned char)(xdiv - (8 * pm));
+
+ if (am < 2) {
+ reg[1] = am + 8;
+ reg[2] = pm - 1;
+ } else {
+ reg[1] = am;
+ reg[2] = pm;
+ }
+ } else {
+ /* fix for frequency less than 45 MHz */
+ reg[1] = 0x06;
+ reg[2] = 0x11;
+ }
+
+ /* fix clock out */
+ reg[6] |= 0x20;
+
+ /* From VCO frequency determines the XIN ( fractional part of Delta
+ Sigma PLL) and divided value (XDIV) */
+ xin = (unsigned short)(f_vco - (f_vco / xtal_freq_khz_2) * xtal_freq_khz_2);
+ xin = (xin << 15) / xtal_freq_khz_2;
+ if (xin >= 16384)
+ xin += 32768;
+
+ reg[3] = xin >> 8; /* xin with 9 bit resolution */
+ reg[4] = xin & 0xff;
+
+ if (delsys == SYS_DVBT) {
+ reg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */
+ switch (p->bandwidth_hz) {
+ case 6000000:
+ reg[6] |= 0x80;
+ break;
+ case 7000000:
+ reg[6] |= 0x40;
+ break;
+ case 8000000:
+ default:
+ break;
+ }
+ } else {
+ err("%s: modulation type not supported!", __func__);
+ return -EINVAL;
+ }
+
+ /* modified for Realtek demod */
+ reg[5] |= 0x07;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ for (i = 1; i <= 6; i++) {
+ ret = fc0012_writereg(priv, i, reg[i]);
+ if (ret)
+ goto exit;
+ }
+
+ /* VCO Calibration */
+ ret = fc0012_writereg(priv, 0x0e, 0x80);
+ if (!ret)
+ ret = fc0012_writereg(priv, 0x0e, 0x00);
+
+ /* VCO Re-Calibration if needed */
+ if (!ret)
+ ret = fc0012_writereg(priv, 0x0e, 0x00);
+
+ if (!ret) {
+ msleep(10);
+ ret = fc0012_readreg(priv, 0x0e, &tmp);
+ }
+ if (ret)
+ goto exit;
+
+ /* vco selection */
+ tmp &= 0x3f;
+
+ if (vco_select) {
+ if (tmp > 0x3c) {
+ reg[6] &= ~0x08;
+ ret = fc0012_writereg(priv, 0x06, reg[6]);
+ if (!ret)
+ ret = fc0012_writereg(priv, 0x0e, 0x80);
+ if (!ret)
+ ret = fc0012_writereg(priv, 0x0e, 0x00);
+ }
+ } else {
+ if (tmp < 0x02) {
+ reg[6] |= 0x08;
+ ret = fc0012_writereg(priv, 0x06, reg[6]);
+ if (!ret)
+ ret = fc0012_writereg(priv, 0x0e, 0x80);
+ if (!ret)
+ ret = fc0012_writereg(priv, 0x0e, 0x00);
+ }
+ }
+
+ priv->frequency = p->frequency;
+ priv->bandwidth = p->bandwidth_hz;
+
+exit:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+ if (ret)
+ warn("%s: failed: %d", __func__, ret);
+ return ret;
+}
+
+static int fc0012_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct fc0012_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static int fc0012_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ /* CHECK: always ? */
+ *frequency = 0;
+ return 0;
+}
+
+static int fc0012_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+ struct fc0012_priv *priv = fe->tuner_priv;
+ *bandwidth = priv->bandwidth;
+ return 0;
+}
+
+#define INPUT_ADC_LEVEL -8
+
+static int fc0012_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ struct fc0012_priv *priv = fe->tuner_priv;
+ int ret;
+ unsigned char tmp;
+ int int_temp, lna_gain, int_lna, tot_agc_gain, power;
+ const int fc0012_lna_gain_table[] = {
+ /* low gain */
+ -63, -58, -99, -73,
+ -63, -65, -54, -60,
+ /* middle gain */
+ 71, 70, 68, 67,
+ 65, 63, 61, 58,
+ /* high gain */
+ 197, 191, 188, 186,
+ 184, 182, 181, 179,
+ };
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ ret = fc0012_writereg(priv, 0x12, 0x00);
+ if (ret)
+ goto err;
+
+ ret = fc0012_readreg(priv, 0x12, &tmp);
+ if (ret)
+ goto err;
+ int_temp = tmp;
+
+ ret = fc0012_readreg(priv, 0x13, &tmp);
+ if (ret)
+ goto err;
+ lna_gain = tmp & 0x1f;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+ if (lna_gain < ARRAY_SIZE(fc0012_lna_gain_table)) {
+ int_lna = fc0012_lna_gain_table[lna_gain];
+ tot_agc_gain = (abs((int_temp >> 5) - 7) - 2 +
+ (int_temp & 0x1f)) * 2;
+ power = INPUT_ADC_LEVEL - tot_agc_gain - int_lna / 10;
+
+ if (power >= 45)
+ *strength = 255; /* 100% */
+ else if (power < -95)
+ *strength = 0;
+ else
+ *strength = (power + 95) * 255 / 140;
+
+ *strength |= *strength << 8;
+ } else {
+ ret = -1;
+ }
+
+ goto exit;
+
+err:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+exit:
+ if (ret)
+ warn("%s: failed: %d", __func__, ret);
+ return ret;
+}
+
+static const struct dvb_tuner_ops fc0012_tuner_ops = {
+ .info = {
+ .name = "Fitipower FC0012",
+
+ .frequency_min = 37000000, /* estimate */
+ .frequency_max = 862000000, /* estimate */
+ .frequency_step = 0,
+ },
+
+ .release = fc0012_release,
+
+ .init = fc0012_init,
+ .sleep = fc0012_sleep,
+
+ .set_params = fc0012_set_params,
+
+ .get_frequency = fc0012_get_frequency,
+ .get_if_frequency = fc0012_get_if_frequency,
+ .get_bandwidth = fc0012_get_bandwidth,
+
+ .get_rf_strength = fc0012_get_rf_strength,
+};
+
+struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, u8 i2c_address, int dual_master,
+ enum fc001x_xtal_freq xtal_freq)
+{
+ struct fc0012_priv *priv = NULL;
+
+ priv = kzalloc(sizeof(struct fc0012_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->i2c = i2c;
+ priv->dual_master = dual_master;
+ priv->addr = i2c_address;
+ priv->xtal_freq = xtal_freq;
+
+ info("Fitipower FC0012 successfully attached.");
+
+ fe->tuner_priv = priv;
+
+ memcpy(&fe->ops.tuner_ops, &fc0012_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ return fe;
+}
+EXPORT_SYMBOL(fc0012_attach);
+
+MODULE_DESCRIPTION("Fitipower FC0012 silicon tuner driver");
+MODULE_AUTHOR("Hans-Frieder Vogt <hfvogt@gmx.net>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.6");
diff --git a/drivers/media/common/tuners/fc0012.h b/drivers/media/common/tuners/fc0012.h
new file mode 100644
index 000000000000..4dbd5efe8845
--- /dev/null
+++ b/drivers/media/common/tuners/fc0012.h
@@ -0,0 +1,44 @@
+/*
+ * Fitipower FC0012 tuner driver - include
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _FC0012_H_
+#define _FC0012_H_
+
+#include "dvb_frontend.h"
+#include "fc001x-common.h"
+
+#if defined(CONFIG_MEDIA_TUNER_FC0012) || \
+ (defined(CONFIG_MEDIA_TUNER_FC0012_MODULE) && defined(MODULE))
+extern struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ u8 i2c_address, int dual_master,
+ enum fc001x_xtal_freq xtal_freq);
+#else
+static inline struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ u8 i2c_address, int dual_master,
+ enum fc001x_xtal_freq xtal_freq)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/common/tuners/fc0013-priv.h b/drivers/media/common/tuners/fc0013-priv.h
new file mode 100644
index 000000000000..bfd49dedea22
--- /dev/null
+++ b/drivers/media/common/tuners/fc0013-priv.h
@@ -0,0 +1,44 @@
+/*
+ * Fitipower FC0013 tuner driver
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _FC0013_PRIV_H_
+#define _FC0013_PRIV_H_
+
+#define LOG_PREFIX "fc0013"
+
+#undef err
+#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+struct fc0013_priv {
+ struct i2c_adapter *i2c;
+ u8 addr;
+ u8 dual_master;
+ u8 xtal_freq;
+
+ u32 frequency;
+ u32 bandwidth;
+};
+
+#endif
diff --git a/drivers/media/common/tuners/fc0013.c b/drivers/media/common/tuners/fc0013.c
new file mode 100644
index 000000000000..bd8f0f1e8f3b
--- /dev/null
+++ b/drivers/media/common/tuners/fc0013.c
@@ -0,0 +1,634 @@
+/*
+ * Fitipower FC0013 tuner driver
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
+ * partially based on driver code from Fitipower
+ * Copyright (C) 2010 Fitipower Integrated Technology 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "fc0013.h"
+#include "fc0013-priv.h"
+
+static int fc0013_writereg(struct fc0013_priv *priv, u8 reg, u8 val)
+{
+ u8 buf[2] = {reg, val};
+ struct i2c_msg msg = {
+ .addr = priv->addr, .flags = 0, .buf = buf, .len = 2
+ };
+
+ if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+ err("I2C write reg failed, reg: %02x, val: %02x", reg, val);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int fc0013_readreg(struct fc0013_priv *priv, u8 reg, u8 *val)
+{
+ struct i2c_msg msg[2] = {
+ { .addr = priv->addr, .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 },
+ };
+
+ if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+ err("I2C read reg failed, reg: %02x", reg);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int fc0013_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static int fc0013_init(struct dvb_frontend *fe)
+{
+ struct fc0013_priv *priv = fe->tuner_priv;
+ int i, ret = 0;
+ unsigned char reg[] = {
+ 0x00, /* reg. 0x00: dummy */
+ 0x09, /* reg. 0x01 */
+ 0x16, /* reg. 0x02 */
+ 0x00, /* reg. 0x03 */
+ 0x00, /* reg. 0x04 */
+ 0x17, /* reg. 0x05 */
+ 0x02, /* reg. 0x06 */
+ 0x0a, /* reg. 0x07: CHECK */
+ 0xff, /* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256,
+ Loop Bw 1/8 */
+ 0x6f, /* reg. 0x09: enable LoopThrough */
+ 0xb8, /* reg. 0x0a: Disable LO Test Buffer */
+ 0x82, /* reg. 0x0b: CHECK */
+ 0xfc, /* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */
+ 0x01, /* reg. 0x0d: AGC Not Forcing & LNA Forcing, may need 0x02 */
+ 0x00, /* reg. 0x0e */
+ 0x00, /* reg. 0x0f */
+ 0x00, /* reg. 0x10 */
+ 0x00, /* reg. 0x11 */
+ 0x00, /* reg. 0x12 */
+ 0x00, /* reg. 0x13 */
+ 0x50, /* reg. 0x14: DVB-t High Gain, UHF.
+ Middle Gain: 0x48, Low Gain: 0x40 */
+ 0x01, /* reg. 0x15 */
+ };
+
+ switch (priv->xtal_freq) {
+ case FC_XTAL_27_MHZ:
+ case FC_XTAL_28_8_MHZ:
+ reg[0x07] |= 0x20;
+ break;
+ case FC_XTAL_36_MHZ:
+ default:
+ break;
+ }
+
+ if (priv->dual_master)
+ reg[0x0c] |= 0x02;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ for (i = 1; i < sizeof(reg); i++) {
+ ret = fc0013_writereg(priv, i, reg[i]);
+ if (ret)
+ break;
+ }
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+ if (ret)
+ err("fc0013_writereg failed: %d", ret);
+
+ return ret;
+}
+
+static int fc0013_sleep(struct dvb_frontend *fe)
+{
+ /* nothing to do here */
+ return 0;
+}
+
+int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val)
+{
+ struct fc0013_priv *priv = fe->tuner_priv;
+ int ret;
+ u8 rc_cal;
+ int val;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ /* push rc_cal value, get rc_cal value */
+ ret = fc0013_writereg(priv, 0x10, 0x00);
+ if (ret)
+ goto error_out;
+
+ /* get rc_cal value */
+ ret = fc0013_readreg(priv, 0x10, &rc_cal);
+ if (ret)
+ goto error_out;
+
+ rc_cal &= 0x0f;
+
+ val = (int)rc_cal + rc_val;
+
+ /* forcing rc_cal */
+ ret = fc0013_writereg(priv, 0x0d, 0x11);
+ if (ret)
+ goto error_out;
+
+ /* modify rc_cal value */
+ if (val > 15)
+ ret = fc0013_writereg(priv, 0x10, 0x0f);
+ else if (val < 0)
+ ret = fc0013_writereg(priv, 0x10, 0x00);
+ else
+ ret = fc0013_writereg(priv, 0x10, (u8)val);
+
+error_out:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+ return ret;
+}
+EXPORT_SYMBOL(fc0013_rc_cal_add);
+
+int fc0013_rc_cal_reset(struct dvb_frontend *fe)
+{
+ struct fc0013_priv *priv = fe->tuner_priv;
+ int ret;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ ret = fc0013_writereg(priv, 0x0d, 0x01);
+ if (!ret)
+ ret = fc0013_writereg(priv, 0x10, 0x00);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+ return ret;
+}
+EXPORT_SYMBOL(fc0013_rc_cal_reset);
+
+static int fc0013_set_vhf_track(struct fc0013_priv *priv, u32 freq)
+{
+ int ret;
+ u8 tmp;
+
+ ret = fc0013_readreg(priv, 0x1d, &tmp);
+ if (ret)
+ goto error_out;
+ tmp &= 0xe3;
+ if (freq <= 177500) { /* VHF Track: 7 */
+ ret = fc0013_writereg(priv, 0x1d, tmp | 0x1c);
+ } else if (freq <= 184500) { /* VHF Track: 6 */
+ ret = fc0013_writereg(priv, 0x1d, tmp | 0x18);
+ } else if (freq <= 191500) { /* VHF Track: 5 */
+ ret = fc0013_writereg(priv, 0x1d, tmp | 0x14);
+ } else if (freq <= 198500) { /* VHF Track: 4 */
+ ret = fc0013_writereg(priv, 0x1d, tmp | 0x10);
+ } else if (freq <= 205500) { /* VHF Track: 3 */
+ ret = fc0013_writereg(priv, 0x1d, tmp | 0x0c);
+ } else if (freq <= 219500) { /* VHF Track: 2 */
+ ret = fc0013_writereg(priv, 0x1d, tmp | 0x08);
+ } else if (freq < 300000) { /* VHF Track: 1 */
+ ret = fc0013_writereg(priv, 0x1d, tmp | 0x04);
+ } else { /* UHF and GPS */
+ ret = fc0013_writereg(priv, 0x1d, tmp | 0x1c);
+ }
+ if (ret)
+ goto error_out;
+error_out:
+ return ret;
+}
+
+static int fc0013_set_params(struct dvb_frontend *fe)
+{
+ struct fc0013_priv *priv = fe->tuner_priv;
+ int i, ret = 0;
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ u32 freq = p->frequency / 1000;
+ u32 delsys = p->delivery_system;
+ unsigned char reg[7], am, pm, multi, tmp;
+ unsigned long f_vco;
+ unsigned short xtal_freq_khz_2, xin, xdiv;
+ int vco_select = false;
+
+ if (fe->callback) {
+ ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
+ FC_FE_CALLBACK_VHF_ENABLE, (freq > 300000 ? 0 : 1));
+ if (ret)
+ goto exit;
+ }
+
+ switch (priv->xtal_freq) {
+ case FC_XTAL_27_MHZ:
+ xtal_freq_khz_2 = 27000 / 2;
+ break;
+ case FC_XTAL_36_MHZ:
+ xtal_freq_khz_2 = 36000 / 2;
+ break;
+ case FC_XTAL_28_8_MHZ:
+ default:
+ xtal_freq_khz_2 = 28800 / 2;
+ break;
+ }
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ /* set VHF track */
+ ret = fc0013_set_vhf_track(priv, freq);
+ if (ret)
+ goto exit;
+
+ if (freq < 300000) {
+ /* enable VHF filter */
+ ret = fc0013_readreg(priv, 0x07, &tmp);
+ if (ret)
+ goto exit;
+ ret = fc0013_writereg(priv, 0x07, tmp | 0x10);
+ if (ret)
+ goto exit;
+
+ /* disable UHF & disable GPS */
+ ret = fc0013_readreg(priv, 0x14, &tmp);
+ if (ret)
+ goto exit;
+ ret = fc0013_writereg(priv, 0x14, tmp & 0x1f);
+ if (ret)
+ goto exit;
+ } else if (freq <= 862000) {
+ /* disable VHF filter */
+ ret = fc0013_readreg(priv, 0x07, &tmp);
+ if (ret)
+ goto exit;
+ ret = fc0013_writereg(priv, 0x07, tmp & 0xef);
+ if (ret)
+ goto exit;
+
+ /* enable UHF & disable GPS */
+ ret = fc0013_readreg(priv, 0x14, &tmp);
+ if (ret)
+ goto exit;
+ ret = fc0013_writereg(priv, 0x14, (tmp & 0x1f) | 0x40);
+ if (ret)
+ goto exit;
+ } else {
+ /* disable VHF filter */
+ ret = fc0013_readreg(priv, 0x07, &tmp);
+ if (ret)
+ goto exit;
+ ret = fc0013_writereg(priv, 0x07, tmp & 0xef);
+ if (ret)
+ goto exit;
+
+ /* disable UHF & enable GPS */
+ ret = fc0013_readreg(priv, 0x14, &tmp);
+ if (ret)
+ goto exit;
+ ret = fc0013_writereg(priv, 0x14, (tmp & 0x1f) | 0x20);
+ if (ret)
+ goto exit;
+ }
+
+ /* select frequency divider and the frequency of VCO */
+ if (freq < 37084) { /* freq * 96 < 3560000 */
+ multi = 96;
+ reg[5] = 0x82;
+ reg[6] = 0x00;
+ } else if (freq < 55625) { /* freq * 64 < 3560000 */
+ multi = 64;
+ reg[5] = 0x02;
+ reg[6] = 0x02;
+ } else if (freq < 74167) { /* freq * 48 < 3560000 */
+ multi = 48;
+ reg[5] = 0x42;
+ reg[6] = 0x00;
+ } else if (freq < 111250) { /* freq * 32 < 3560000 */
+ multi = 32;
+ reg[5] = 0x82;
+ reg[6] = 0x02;
+ } else if (freq < 148334) { /* freq * 24 < 3560000 */
+ multi = 24;
+ reg[5] = 0x22;
+ reg[6] = 0x00;
+ } else if (freq < 222500) { /* freq * 16 < 3560000 */
+ multi = 16;
+ reg[5] = 0x42;
+ reg[6] = 0x02;
+ } else if (freq < 296667) { /* freq * 12 < 3560000 */
+ multi = 12;
+ reg[5] = 0x12;
+ reg[6] = 0x00;
+ } else if (freq < 445000) { /* freq * 8 < 3560000 */
+ multi = 8;
+ reg[5] = 0x22;
+ reg[6] = 0x02;
+ } else if (freq < 593334) { /* freq * 6 < 3560000 */
+ multi = 6;
+ reg[5] = 0x0a;
+ reg[6] = 0x00;
+ } else if (freq < 950000) { /* freq * 4 < 3800000 */
+ multi = 4;
+ reg[5] = 0x12;
+ reg[6] = 0x02;
+ } else {
+ multi = 2;
+ reg[5] = 0x0a;
+ reg[6] = 0x02;
+ }
+
+ f_vco = freq * multi;
+
+ if (f_vco >= 3060000) {
+ reg[6] |= 0x08;
+ vco_select = true;
+ }
+
+ if (freq >= 45000) {
+ /* From divided value (XDIV) determined the FA and FP value */
+ xdiv = (unsigned short)(f_vco / xtal_freq_khz_2);
+ if ((f_vco - xdiv * xtal_freq_khz_2) >= (xtal_freq_khz_2 / 2))
+ xdiv++;
+
+ pm = (unsigned char)(xdiv / 8);
+ am = (unsigned char)(xdiv - (8 * pm));
+
+ if (am < 2) {
+ reg[1] = am + 8;
+ reg[2] = pm - 1;
+ } else {
+ reg[1] = am;
+ reg[2] = pm;
+ }
+ } else {
+ /* fix for frequency less than 45 MHz */
+ reg[1] = 0x06;
+ reg[2] = 0x11;
+ }
+
+ /* fix clock out */
+ reg[6] |= 0x20;
+
+ /* From VCO frequency determines the XIN ( fractional part of Delta
+ Sigma PLL) and divided value (XDIV) */
+ xin = (unsigned short)(f_vco - (f_vco / xtal_freq_khz_2) * xtal_freq_khz_2);
+ xin = (xin << 15) / xtal_freq_khz_2;
+ if (xin >= 16384)
+ xin += 32768;
+
+ reg[3] = xin >> 8;
+ reg[4] = xin & 0xff;
+
+ if (delsys == SYS_DVBT) {
+ reg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */
+ switch (p->bandwidth_hz) {
+ case 6000000:
+ reg[6] |= 0x80;
+ break;
+ case 7000000:
+ reg[6] |= 0x40;
+ break;
+ case 8000000:
+ default:
+ break;
+ }
+ } else {
+ err("%s: modulation type not supported!", __func__);
+ return -EINVAL;
+ }
+
+ /* modified for Realtek demod */
+ reg[5] |= 0x07;
+
+ for (i = 1; i <= 6; i++) {
+ ret = fc0013_writereg(priv, i, reg[i]);
+ if (ret)
+ goto exit;
+ }
+
+ ret = fc0013_readreg(priv, 0x11, &tmp);
+ if (ret)
+ goto exit;
+ if (multi == 64)
+ ret = fc0013_writereg(priv, 0x11, tmp | 0x04);
+ else
+ ret = fc0013_writereg(priv, 0x11, tmp & 0xfb);
+ if (ret)
+ goto exit;
+
+ /* VCO Calibration */
+ ret = fc0013_writereg(priv, 0x0e, 0x80);
+ if (!ret)
+ ret = fc0013_writereg(priv, 0x0e, 0x00);
+
+ /* VCO Re-Calibration if needed */
+ if (!ret)
+ ret = fc0013_writereg(priv, 0x0e, 0x00);
+
+ if (!ret) {
+ msleep(10);
+ ret = fc0013_readreg(priv, 0x0e, &tmp);
+ }
+ if (ret)
+ goto exit;
+
+ /* vco selection */
+ tmp &= 0x3f;
+
+ if (vco_select) {
+ if (tmp > 0x3c) {
+ reg[6] &= ~0x08;
+ ret = fc0013_writereg(priv, 0x06, reg[6]);
+ if (!ret)
+ ret = fc0013_writereg(priv, 0x0e, 0x80);
+ if (!ret)
+ ret = fc0013_writereg(priv, 0x0e, 0x00);
+ }
+ } else {
+ if (tmp < 0x02) {
+ reg[6] |= 0x08;
+ ret = fc0013_writereg(priv, 0x06, reg[6]);
+ if (!ret)
+ ret = fc0013_writereg(priv, 0x0e, 0x80);
+ if (!ret)
+ ret = fc0013_writereg(priv, 0x0e, 0x00);
+ }
+ }
+
+ priv->frequency = p->frequency;
+ priv->bandwidth = p->bandwidth_hz;
+
+exit:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+ if (ret)
+ warn("%s: failed: %d", __func__, ret);
+ return ret;
+}
+
+static int fc0013_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct fc0013_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static int fc0013_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ /* always ? */
+ *frequency = 0;
+ return 0;
+}
+
+static int fc0013_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+ struct fc0013_priv *priv = fe->tuner_priv;
+ *bandwidth = priv->bandwidth;
+ return 0;
+}
+
+#define INPUT_ADC_LEVEL -8
+
+static int fc0013_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ struct fc0013_priv *priv = fe->tuner_priv;
+ int ret;
+ unsigned char tmp;
+ int int_temp, lna_gain, int_lna, tot_agc_gain, power;
+ const int fc0013_lna_gain_table[] = {
+ /* low gain */
+ -63, -58, -99, -73,
+ -63, -65, -54, -60,
+ /* middle gain */
+ 71, 70, 68, 67,
+ 65, 63, 61, 58,
+ /* high gain */
+ 197, 191, 188, 186,
+ 184, 182, 181, 179,
+ };
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ ret = fc0013_writereg(priv, 0x13, 0x00);
+ if (ret)
+ goto err;
+
+ ret = fc0013_readreg(priv, 0x13, &tmp);
+ if (ret)
+ goto err;
+ int_temp = tmp;
+
+ ret = fc0013_readreg(priv, 0x14, &tmp);
+ if (ret)
+ goto err;
+ lna_gain = tmp & 0x1f;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+ if (lna_gain < ARRAY_SIZE(fc0013_lna_gain_table)) {
+ int_lna = fc0013_lna_gain_table[lna_gain];
+ tot_agc_gain = (abs((int_temp >> 5) - 7) - 2 +
+ (int_temp & 0x1f)) * 2;
+ power = INPUT_ADC_LEVEL - tot_agc_gain - int_lna / 10;
+
+ if (power >= 45)
+ *strength = 255; /* 100% */
+ else if (power < -95)
+ *strength = 0;
+ else
+ *strength = (power + 95) * 255 / 140;
+
+ *strength |= *strength << 8;
+ } else {
+ ret = -1;
+ }
+
+ goto exit;
+
+err:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+exit:
+ if (ret)
+ warn("%s: failed: %d", __func__, ret);
+ return ret;
+}
+
+static const struct dvb_tuner_ops fc0013_tuner_ops = {
+ .info = {
+ .name = "Fitipower FC0013",
+
+ .frequency_min = 37000000, /* estimate */
+ .frequency_max = 1680000000, /* CHECK */
+ .frequency_step = 0,
+ },
+
+ .release = fc0013_release,
+
+ .init = fc0013_init,
+ .sleep = fc0013_sleep,
+
+ .set_params = fc0013_set_params,
+
+ .get_frequency = fc0013_get_frequency,
+ .get_if_frequency = fc0013_get_if_frequency,
+ .get_bandwidth = fc0013_get_bandwidth,
+
+ .get_rf_strength = fc0013_get_rf_strength,
+};
+
+struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, u8 i2c_address, int dual_master,
+ enum fc001x_xtal_freq xtal_freq)
+{
+ struct fc0013_priv *priv = NULL;
+
+ priv = kzalloc(sizeof(struct fc0013_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->i2c = i2c;
+ priv->dual_master = dual_master;
+ priv->addr = i2c_address;
+ priv->xtal_freq = xtal_freq;
+
+ info("Fitipower FC0013 successfully attached.");
+
+ fe->tuner_priv = priv;
+
+ memcpy(&fe->ops.tuner_ops, &fc0013_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ return fe;
+}
+EXPORT_SYMBOL(fc0013_attach);
+
+MODULE_DESCRIPTION("Fitipower FC0013 silicon tuner driver");
+MODULE_AUTHOR("Hans-Frieder Vogt <hfvogt@gmx.net>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.2");
diff --git a/drivers/media/common/tuners/fc0013.h b/drivers/media/common/tuners/fc0013.h
new file mode 100644
index 000000000000..594efd64aeec
--- /dev/null
+++ b/drivers/media/common/tuners/fc0013.h
@@ -0,0 +1,57 @@
+/*
+ * Fitipower FC0013 tuner driver
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _FC0013_H_
+#define _FC0013_H_
+
+#include "dvb_frontend.h"
+#include "fc001x-common.h"
+
+#if defined(CONFIG_MEDIA_TUNER_FC0013) || \
+ (defined(CONFIG_MEDIA_TUNER_FC0013_MODULE) && defined(MODULE))
+extern struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ u8 i2c_address, int dual_master,
+ enum fc001x_xtal_freq xtal_freq);
+extern int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val);
+extern int fc0013_rc_cal_reset(struct dvb_frontend *fe);
+#else
+static inline struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c,
+ u8 i2c_address, int dual_master,
+ enum fc001x_xtal_freq xtal_freq)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+
+static inline int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val)
+{
+ return 0;
+}
+
+static inline int fc0013_rc_cal_reset(struct dvb_frontend *fe)
+{
+ return 0;
+}
+#endif
+
+#endif
diff --git a/arch/arm/include/asm/hardware/ep7211.h b/drivers/media/common/tuners/fc001x-common.h
index 654d5f625c49..718818156934 100644
--- a/arch/arm/include/asm/hardware/ep7211.h
+++ b/drivers/media/common/tuners/fc001x-common.h
@@ -1,10 +1,7 @@
/*
- * arch/arm/include/asm/hardware/ep7211.h
+ * Fitipower FC0012 & FC0013 tuner driver - common defines
*
- * This file contains the hardware definitions of the EP7211 internal
- * registers.
- *
- * Copyright (C) 2001 Blue Mug, Inc. All Rights Reserved.
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net>
*
* 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
@@ -18,23 +15,25 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#ifndef __ASM_HARDWARE_EP7211_H
-#define __ASM_HARDWARE_EP7211_H
-#include <asm/hardware/clps7111.h>
+#ifndef _FC001X_COMMON_H_
+#define _FC001X_COMMON_H_
-/*
- * define EP7211_BASE to be the base address of the region
- * you want to access.
- */
-
-#define EP7211_PHYS_BASE (0x80000000)
+enum fc001x_xtal_freq {
+ FC_XTAL_27_MHZ, /* 27000000 */
+ FC_XTAL_28_8_MHZ, /* 28800000 */
+ FC_XTAL_36_MHZ, /* 36000000 */
+};
/*
- * XXX miket@bluemug.com: need to introduce EP7211 registers (those not
- * present in 7212) here.
+ * enum fc001x_fe_callback_commands - Frontend callbacks
+ *
+ * @FC_FE_CALLBACK_VHF_ENABLE: enable VHF or UHF
*/
+enum fc001x_fe_callback_commands {
+ FC_FE_CALLBACK_VHF_ENABLE,
+};
-#endif /* __ASM_HARDWARE_EP7211_H */
+#endif
diff --git a/drivers/media/common/tuners/tua9001.c b/drivers/media/common/tuners/tua9001.c
new file mode 100644
index 000000000000..de2607084672
--- /dev/null
+++ b/drivers/media/common/tuners/tua9001.c
@@ -0,0 +1,215 @@
+/*
+ * Infineon TUA 9001 silicon tuner driver
+ *
+ * Copyright (C) 2009 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "tua9001.h"
+#include "tua9001_priv.h"
+
+/* write register */
+static int tua9001_wr_reg(struct tua9001_priv *priv, u8 reg, u16 val)
+{
+ int ret;
+ u8 buf[3] = { reg, (val >> 8) & 0xff, (val >> 0) & 0xff };
+ struct i2c_msg msg[1] = {
+ {
+ .addr = priv->cfg->i2c_addr,
+ .flags = 0,
+ .len = sizeof(buf),
+ .buf = buf,
+ }
+ };
+
+ ret = i2c_transfer(priv->i2c, msg, 1);
+ if (ret == 1) {
+ ret = 0;
+ } else {
+ printk(KERN_WARNING "%s: I2C wr failed=%d reg=%02x\n",
+ __func__, ret, reg);
+ ret = -EREMOTEIO;
+ }
+
+ return ret;
+}
+
+static int tua9001_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+
+ return 0;
+}
+
+static int tua9001_init(struct dvb_frontend *fe)
+{
+ struct tua9001_priv *priv = fe->tuner_priv;
+ int ret = 0;
+ u8 i;
+ struct reg_val data[] = {
+ { 0x1e, 0x6512 },
+ { 0x25, 0xb888 },
+ { 0x39, 0x5460 },
+ { 0x3b, 0x00c0 },
+ { 0x3a, 0xf000 },
+ { 0x08, 0x0000 },
+ { 0x32, 0x0030 },
+ { 0x41, 0x703a },
+ { 0x40, 0x1c78 },
+ { 0x2c, 0x1c00 },
+ { 0x36, 0xc013 },
+ { 0x37, 0x6f18 },
+ { 0x27, 0x0008 },
+ { 0x2a, 0x0001 },
+ { 0x34, 0x0a40 },
+ };
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c-gate */
+
+ for (i = 0; i < ARRAY_SIZE(data); i++) {
+ ret = tua9001_wr_reg(priv, data[i].reg, data[i].val);
+ if (ret)
+ break;
+ }
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c-gate */
+
+ if (ret < 0)
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int tua9001_set_params(struct dvb_frontend *fe)
+{
+ struct tua9001_priv *priv = fe->tuner_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret, i;
+ u16 val;
+ u32 frequency;
+ struct reg_val data[2];
+
+ pr_debug("%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n",
+ __func__, c->delivery_system, c->frequency,
+ c->bandwidth_hz);
+
+ switch (c->delivery_system) {
+ case SYS_DVBT:
+ switch (c->bandwidth_hz) {
+ case 8000000:
+ val = 0x0000;
+ break;
+ case 7000000:
+ val = 0x1000;
+ break;
+ case 6000000:
+ val = 0x2000;
+ break;
+ case 5000000:
+ val = 0x3000;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+
+ data[0].reg = 0x04;
+ data[0].val = val;
+
+ frequency = (c->frequency - 150000000);
+ frequency /= 100;
+ frequency *= 48;
+ frequency /= 10000;
+
+ data[1].reg = 0x1f;
+ data[1].val = frequency;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c-gate */
+
+ for (i = 0; i < ARRAY_SIZE(data); i++) {
+ ret = tua9001_wr_reg(priv, data[i].reg, data[i].val);
+ if (ret < 0)
+ break;
+ }
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c-gate */
+
+err:
+ if (ret < 0)
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int tua9001_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ *frequency = 0; /* Zero-IF */
+
+ return 0;
+}
+
+static const struct dvb_tuner_ops tua9001_tuner_ops = {
+ .info = {
+ .name = "Infineon TUA 9001",
+
+ .frequency_min = 170000000,
+ .frequency_max = 862000000,
+ .frequency_step = 0,
+ },
+
+ .release = tua9001_release,
+
+ .init = tua9001_init,
+ .set_params = tua9001_set_params,
+
+ .get_if_frequency = tua9001_get_if_frequency,
+};
+
+struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, struct tua9001_config *cfg)
+{
+ struct tua9001_priv *priv = NULL;
+
+ priv = kzalloc(sizeof(struct tua9001_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->cfg = cfg;
+ priv->i2c = i2c;
+
+ printk(KERN_INFO "Infineon TUA 9001 successfully attached.");
+
+ memcpy(&fe->ops.tuner_ops, &tua9001_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ fe->tuner_priv = priv;
+ return fe;
+}
+EXPORT_SYMBOL(tua9001_attach);
+
+MODULE_DESCRIPTION("Infineon TUA 9001 silicon tuner driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/tua9001.h b/drivers/media/common/tuners/tua9001.h
new file mode 100644
index 000000000000..38d6ae76b1d6
--- /dev/null
+++ b/drivers/media/common/tuners/tua9001.h
@@ -0,0 +1,46 @@
+/*
+ * Infineon TUA 9001 silicon tuner driver
+ *
+ * Copyright (C) 2009 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef TUA9001_H
+#define TUA9001_H
+
+#include "dvb_frontend.h"
+
+struct tua9001_config {
+ /*
+ * I2C address
+ */
+ u8 i2c_addr;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_TUA9001) || \
+ (defined(CONFIG_MEDIA_TUNER_TUA9001_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, struct tua9001_config *cfg);
+#else
+static inline struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, struct tua9001_config *cfg)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/common/tuners/tua9001_priv.h b/drivers/media/common/tuners/tua9001_priv.h
new file mode 100644
index 000000000000..73cc1ce0575c
--- /dev/null
+++ b/drivers/media/common/tuners/tua9001_priv.h
@@ -0,0 +1,34 @@
+/*
+ * Infineon TUA 9001 silicon tuner driver
+ *
+ * Copyright (C) 2009 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef TUA9001_PRIV_H
+#define TUA9001_PRIV_H
+
+struct reg_val {
+ u8 reg;
+ u16 val;
+};
+
+struct tua9001_priv {
+ struct tua9001_config *cfg;
+ struct i2c_adapter *i2c;
+};
+
+#endif
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c
index eab2ea424200..dcca42ca57be 100644
--- a/drivers/media/common/tuners/xc5000.c
+++ b/drivers/media/common/tuners/xc5000.c
@@ -54,7 +54,7 @@ struct xc5000_priv {
struct list_head hybrid_tuner_instance_list;
u32 if_khz;
- u32 xtal_khz;
+ u16 xtal_khz;
u32 freq_hz;
u32 bandwidth;
u8 video_standard;
@@ -631,7 +631,10 @@ static int xc5000_fwupload(struct dvb_frontend *fe)
ret = xc_load_i2c_sequence(fe, fw->data);
if (XC_RESULT_SUCCESS == ret)
ret = xc_set_xtal(fe);
- printk(KERN_INFO "xc5000: firmware upload complete...\n");
+ if (XC_RESULT_SUCCESS == ret)
+ printk(KERN_INFO "xc5000: firmware upload complete...\n");
+ else
+ printk(KERN_ERR "xc5000: firmware upload failed...\n");
}
out:
diff --git a/drivers/media/common/tuners/xc5000.h b/drivers/media/common/tuners/xc5000.h
index 39a73bf01406..b1a547494625 100644
--- a/drivers/media/common/tuners/xc5000.h
+++ b/drivers/media/common/tuners/xc5000.h
@@ -34,7 +34,7 @@ struct xc5000_config {
u8 i2c_address;
u32 if_khz;
u8 radio_input;
- u32 xtal_khz;
+ u16 xtal_khz;
int chip_id;
};
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
index 48e48e8af55a..66f52f116b60 100644
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ b/drivers/media/dvb/bt8xx/dst_ca.c
@@ -477,7 +477,6 @@ static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message
static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, void __user *arg)
{
int i = 0;
- unsigned int ca_message_header_len;
u32 command = 0;
struct ca_msg *hw_buffer;
@@ -496,7 +495,6 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message,
if (p_ca_message->msg) {
- ca_message_header_len = p_ca_message->length; /* Restore it back when you are done */
/* EN50221 tag */
command = 0;
diff --git a/drivers/media/dvb/ddbridge/ddbridge-core.c b/drivers/media/dvb/ddbridge/ddbridge-core.c
index d88c4aa7d24d..131b938e9e81 100644
--- a/drivers/media/dvb/ddbridge/ddbridge-core.c
+++ b/drivers/media/dvb/ddbridge/ddbridge-core.c
@@ -31,7 +31,6 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/timer.h>
-#include <linux/version.h>
#include <linux/i2c.h>
#include <linux/swab.h>
#include <linux/vmalloc.h>
@@ -1696,7 +1695,7 @@ static struct pci_driver ddb_pci_driver = {
.name = "DDBridge",
.id_table = ddb_id_tbl,
.probe = ddb_probe,
- .remove = ddb_remove,
+ .remove = __devexit_p(ddb_remove),
};
static __init int module_init_ddbridge(void)
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index faa3671b649e..d82469f842e2 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -568,6 +568,16 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
}
EXPORT_SYMBOL(dvb_dmx_swfilter_204);
+void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count)
+{
+ spin_lock(&demux->lock);
+
+ demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts, DMX_OK);
+
+ spin_unlock(&demux->lock);
+}
+EXPORT_SYMBOL(dvb_dmx_swfilter_raw);
+
static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux)
{
int i;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index a7d876fd02dd..fa7188a253aa 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -145,5 +145,7 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf,
void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count);
void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf,
size_t count);
+void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf,
+ size_t count);
#endif /* _DVB_DEMUX_H_ */
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index cb888d835a89..aebcdf221dda 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -182,13 +182,13 @@ static enum dvbv3_emulation_type dvbv3_type(u32 delivery_system)
case SYS_DMBTH:
return DVBV3_OFDM;
case SYS_ATSC:
+ case SYS_ATSCMH:
case SYS_DVBC_ANNEX_B:
return DVBV3_ATSC;
case SYS_UNDEFINED:
case SYS_ISDBC:
case SYS_DVBH:
case SYS_DAB:
- case SYS_ATSCMH:
default:
/*
* Doesn't know how to emulate those types and/or
@@ -1030,6 +1030,25 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
_DTV_CMD(DTV_HIERARCHY, 0, 0),
_DTV_CMD(DTV_ENUM_DELSYS, 0, 0),
+
+ _DTV_CMD(DTV_ATSCMH_PARADE_ID, 1, 0),
+ _DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 1, 0),
+
+ _DTV_CMD(DTV_ATSCMH_FIC_VER, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_PARADE_ID, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_NOG, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_TNOG, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_SGN, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_PRC, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_RS_FRAME_MODE, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_PRI, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_SEC, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_SCCC_BLOCK_MODE, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_A, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_B, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_C, 0, 0),
+ _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_D, 0, 0),
};
static void dtv_property_dump(struct dtv_property *tvp)
@@ -1121,6 +1140,8 @@ static int dtv_property_cache_sync(struct dvb_frontend *fe,
case DVBV3_ATSC:
dprintk("%s() Preparing ATSC req\n", __func__);
c->modulation = p->u.vsb.modulation;
+ if (c->delivery_system == SYS_ATSCMH)
+ break;
if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
c->delivery_system = SYS_ATSC;
else
@@ -1367,6 +1388,54 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
case DTV_DVBT2_PLP_ID:
tvp->u.data = c->dvbt2_plp_id;
break;
+
+ /* ATSC-MH */
+ case DTV_ATSCMH_FIC_VER:
+ tvp->u.data = fe->dtv_property_cache.atscmh_fic_ver;
+ break;
+ case DTV_ATSCMH_PARADE_ID:
+ tvp->u.data = fe->dtv_property_cache.atscmh_parade_id;
+ break;
+ case DTV_ATSCMH_NOG:
+ tvp->u.data = fe->dtv_property_cache.atscmh_nog;
+ break;
+ case DTV_ATSCMH_TNOG:
+ tvp->u.data = fe->dtv_property_cache.atscmh_tnog;
+ break;
+ case DTV_ATSCMH_SGN:
+ tvp->u.data = fe->dtv_property_cache.atscmh_sgn;
+ break;
+ case DTV_ATSCMH_PRC:
+ tvp->u.data = fe->dtv_property_cache.atscmh_prc;
+ break;
+ case DTV_ATSCMH_RS_FRAME_MODE:
+ tvp->u.data = fe->dtv_property_cache.atscmh_rs_frame_mode;
+ break;
+ case DTV_ATSCMH_RS_FRAME_ENSEMBLE:
+ tvp->u.data = fe->dtv_property_cache.atscmh_rs_frame_ensemble;
+ break;
+ case DTV_ATSCMH_RS_CODE_MODE_PRI:
+ tvp->u.data = fe->dtv_property_cache.atscmh_rs_code_mode_pri;
+ break;
+ case DTV_ATSCMH_RS_CODE_MODE_SEC:
+ tvp->u.data = fe->dtv_property_cache.atscmh_rs_code_mode_sec;
+ break;
+ case DTV_ATSCMH_SCCC_BLOCK_MODE:
+ tvp->u.data = fe->dtv_property_cache.atscmh_sccc_block_mode;
+ break;
+ case DTV_ATSCMH_SCCC_CODE_MODE_A:
+ tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_a;
+ break;
+ case DTV_ATSCMH_SCCC_CODE_MODE_B:
+ tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_b;
+ break;
+ case DTV_ATSCMH_SCCC_CODE_MODE_C:
+ tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_c;
+ break;
+ case DTV_ATSCMH_SCCC_CODE_MODE_D:
+ tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_d;
+ break;
+
default:
return -EINVAL;
}
@@ -1708,6 +1777,15 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
case DTV_DVBT2_PLP_ID:
c->dvbt2_plp_id = tvp->u.data;
break;
+
+ /* ATSC-MH */
+ case DTV_ATSCMH_PARADE_ID:
+ fe->dtv_property_cache.atscmh_parade_id = tvp->u.data;
+ break;
+ case DTV_ATSCMH_RS_FRAME_ENSEMBLE:
+ fe->dtv_property_cache.atscmh_rs_frame_ensemble = tvp->u.data;
+ break;
+
default:
return -EINVAL;
}
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index d63a8215fe03..e929d5697b87 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -372,6 +372,24 @@ struct dtv_frontend_properties {
/* DVB-T2 specifics */
u32 dvbt2_plp_id;
+
+ /* ATSC-MH specifics */
+ u8 atscmh_fic_ver;
+ u8 atscmh_parade_id;
+ u8 atscmh_nog;
+ u8 atscmh_tnog;
+ u8 atscmh_sgn;
+ u8 atscmh_prc;
+
+ u8 atscmh_rs_frame_mode;
+ u8 atscmh_rs_frame_ensemble;
+ u8 atscmh_rs_code_mode_pri;
+ u8 atscmh_rs_code_mode_sec;
+ u8 atscmh_sccc_block_mode;
+ u8 atscmh_sccc_code_mode_a;
+ u8 atscmh_sccc_code_mode_b;
+ u8 atscmh_sccc_code_mode_c;
+ u8 atscmh_sccc_code_mode_d;
};
struct dvb_frontend {
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 63bf45679f98..a26949336b3d 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -409,6 +409,7 @@ config DVB_USB_MXL111SF
tristate "MxL111SF DTV USB2.0 support"
depends on DVB_USB
select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
+ select DVB_LG2160 if !DVB_FE_CUSTOMISE
select VIDEO_TVEEPROM
help
Say Y here to support the MxL111SF USB2.0 DTV receiver.
@@ -422,3 +423,15 @@ config DVB_USB_RTL28XXU
select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
help
Say Y here to support the Realtek RTL28xxU DVB USB receiver.
+
+config DVB_USB_AF9035
+ tristate "Afatech AF9035 DVB-T USB2.0 support"
+ depends on DVB_USB
+ select DVB_AF9033
+ select MEDIA_TUNER_TUA9001 if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_FC0011 if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE
+ help
+ Say Y here to support the Afatech AF9035 based DVB USB receiver.
+
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index b76acb5387e6..b667ac39a4e3 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -110,6 +110,9 @@ obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o
dvb-usb-rtl28xxu-objs = rtl28xxu.o
obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o
+dvb-usb-af9035-objs = af9035.o
+obj-$(CONFIG_DVB_USB_AF9035) += dvb-usb-af9035.o
+
ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
ccflags-y += -I$(srctree)/drivers/media/dvb/frontends/
# due to tuner-xc3028
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
index 7e70ea50ef26..677fed79b01e 100644
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ b/drivers/media/dvb/dvb-usb/af9015.c
@@ -244,8 +244,7 @@ static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
u8 uninitialized_var(mbox), addr_len;
struct req_t req;
-/* TODO: implement bus lock
-
+/*
The bus lock is needed because there is two tuners both using same I2C-address.
Due to that the only way to select correct tuner is use demodulator I2C-gate.
@@ -789,7 +788,7 @@ static void af9015_set_remote_config(struct usb_device *udev,
/* try to load remote based USB ID */
if (!props->rc.core.rc_codes)
props->rc.core.rc_codes = af9015_rc_setup_match(
- (vid << 16) + pid, af9015_rc_setup_usbids);
+ (vid << 16) | pid, af9015_rc_setup_usbids);
/* try to load remote based USB iManufacturer string */
if (!props->rc.core.rc_codes && vid == USB_VID_AFATECH) {
@@ -1220,8 +1219,8 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
}
/* attach demodulator */
- adap->fe_adap[0].fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id],
- &adap->dev->i2c_adap);
+ adap->fe_adap[0].fe = dvb_attach(af9013_attach,
+ &af9015_af9013_config[adap->id], &adap->dev->i2c_adap);
/*
* AF9015 firmware does not like if it gets interrupted by I2C adapter
@@ -1324,14 +1323,15 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
switch (af9015_af9013_config[adap->id].tuner) {
case AF9013_TUNER_MT2060:
case AF9013_TUNER_MT2060_2:
- ret = dvb_attach(mt2060_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap,
- &af9015_mt2060_config,
+ ret = dvb_attach(mt2060_attach, adap->fe_adap[0].fe,
+ &adap->dev->i2c_adap, &af9015_mt2060_config,
af9015_config.mt2060_if1[adap->id])
== NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_QT1010:
case AF9013_TUNER_QT1010A:
- ret = dvb_attach(qt1010_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap,
+ ret = dvb_attach(qt1010_attach, adap->fe_adap[0].fe,
+ &adap->dev->i2c_adap,
&af9015_qt1010_config) == NULL ? -ENODEV : 0;
break;
case AF9013_TUNER_TDA18271:
@@ -1434,69 +1434,85 @@ enum af9015_usb_table_entry {
};
static struct usb_device_id af9015_usb_table[] = {
- [AFATECH_9015] =
- {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015)},
- [AFATECH_9016] =
- {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016)},
- [WINFAST_DTV_GOLD] =
- {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD)},
- [PINNACLE_PCTV_71E] =
- {USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E)},
- [KWORLD_PLUSTV_399U] =
- {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U)},
- [TINYTWIN] = {USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TINYTWIN)},
- [AZUREWAVE_TU700] =
- {USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_AD_TU700)},
- [TERRATEC_AF9015] = {USB_DEVICE(USB_VID_TERRATEC,
+ [AFATECH_9015] = {
+ USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015)},
+ [AFATECH_9016] = {
+ USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016)},
+ [WINFAST_DTV_GOLD] = {
+ USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD)},
+ [PINNACLE_PCTV_71E] = {
+ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E)},
+ [KWORLD_PLUSTV_399U] = {
+ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U)},
+ [TINYTWIN] = {
+ USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TINYTWIN)},
+ [AZUREWAVE_TU700] = {
+ USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_AD_TU700)},
+ [TERRATEC_AF9015] = {
+ USB_DEVICE(USB_VID_TERRATEC,
USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2)},
- [KWORLD_PLUSTV_PC160] =
- {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T)},
- [AVERTV_VOLAR_X] =
- {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X)},
- [XTENSIONS_380U] =
- {USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)},
- [MSI_DIGIVOX_DUO] =
- {USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO)},
- [AVERTV_VOLAR_X_REV2] =
- {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)},
- [TELESTAR_STARSTICK_2] =
- {USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2)},
- [AVERMEDIA_A309_USB] =
- {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)},
- [MSI_DIGIVOX_MINI_III] =
- {USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)},
- [KWORLD_E396] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)},
- [KWORLD_E39B] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2)},
- [KWORLD_E395] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3)},
- [TREKSTOR_DVBT] = {USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT)},
- [AVERTV_A850] = {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)},
- [AVERTV_A805] = {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)},
- [CONCEPTRONIC_CTVDIGRCU] =
- {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU)},
- [KWORLD_MC810] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810)},
- [GENIUS_TVGO_DVB_T03] =
- {USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03)},
- [KWORLD_399U_2] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2)},
- [KWORLD_PC160_T] =
- {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T)},
- [SVEON_STV20] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20)},
- [TINYTWIN_2] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2)},
- [WINFAST_DTV2000DS] =
- {USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS)},
- [KWORLD_UB383_T] =
- {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T)},
- [KWORLD_E39A] =
- {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4)},
- [AVERMEDIA_A815M] =
- {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)},
- [CINERGY_T_STICK_RC] = {USB_DEVICE(USB_VID_TERRATEC,
+ [KWORLD_PLUSTV_PC160] = {
+ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T)},
+ [AVERTV_VOLAR_X] = {
+ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X)},
+ [XTENSIONS_380U] = {
+ USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)},
+ [MSI_DIGIVOX_DUO] = {
+ USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO)},
+ [AVERTV_VOLAR_X_REV2] = {
+ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)},
+ [TELESTAR_STARSTICK_2] = {
+ USB_DEVICE(USB_VID_TELESTAR, USB_PID_TELESTAR_STARSTICK_2)},
+ [AVERMEDIA_A309_USB] = {
+ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)},
+ [MSI_DIGIVOX_MINI_III] = {
+ USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)},
+ [KWORLD_E396] = {
+ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)},
+ [KWORLD_E39B] = {
+ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2)},
+ [KWORLD_E395] = {
+ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3)},
+ [TREKSTOR_DVBT] = {
+ USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT)},
+ [AVERTV_A850] = {
+ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)},
+ [AVERTV_A805] = {
+ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)},
+ [CONCEPTRONIC_CTVDIGRCU] = {
+ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU)},
+ [KWORLD_MC810] = {
+ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810)},
+ [GENIUS_TVGO_DVB_T03] = {
+ USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03)},
+ [KWORLD_399U_2] = {
+ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2)},
+ [KWORLD_PC160_T] = {
+ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T)},
+ [SVEON_STV20] = {
+ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20)},
+ [TINYTWIN_2] = {
+ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2)},
+ [WINFAST_DTV2000DS] = {
+ USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS)},
+ [KWORLD_UB383_T] = {
+ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T)},
+ [KWORLD_E39A] = {
+ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4)},
+ [AVERMEDIA_A815M] = {
+ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)},
+ [CINERGY_T_STICK_RC] = {
+ USB_DEVICE(USB_VID_TERRATEC,
USB_PID_TERRATEC_CINERGY_T_STICK_RC)},
- [CINERGY_T_DUAL_RC] = {USB_DEVICE(USB_VID_TERRATEC,
+ [CINERGY_T_DUAL_RC] = {
+ USB_DEVICE(USB_VID_TERRATEC,
USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC)},
- [AVERTV_A850T] =
- {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)},
- [TINYTWIN_3] = {USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3)},
- [SVEON_STV22] = {USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22)},
+ [AVERTV_A850T] = {
+ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)},
+ [TINYTWIN_3] = {
+ USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3)},
+ [SVEON_STV22] = {
+ USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22)},
{ }
};
MODULE_DEVICE_TABLE(usb, af9015_usb_table);
@@ -1516,43 +1532,44 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.num_adapters = 2,
.adapter = {
{
- .num_frontends = 1,
- .fe = {{
- .caps = DVB_USB_ADAP_HAS_PID_FILTER |
- DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-
- .pid_filter_count = 32,
- .pid_filter = af9015_pid_filter,
- .pid_filter_ctrl = af9015_pid_filter_ctrl,
-
- .frontend_attach =
- af9015_af9013_frontend_attach,
- .tuner_attach = af9015_tuner_attach,
- .stream = {
- .type = USB_BULK,
- .count = 6,
- .endpoint = 0x84,
+ .num_frontends = 1,
+ .fe = {
+ {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+ .pid_filter_count = 32,
+ .pid_filter = af9015_pid_filter,
+ .pid_filter_ctrl = af9015_pid_filter_ctrl,
+
+ .frontend_attach = af9015_af9013_frontend_attach,
+ .tuner_attach = af9015_tuner_attach,
+ .stream = {
+ .type = USB_BULK,
+ .count = 6,
+ .endpoint = 0x84,
+ },
+ }
},
- }},
},
{
- .num_frontends = 1,
- .fe = {{
- .frontend_attach =
- af9015_af9013_frontend_attach,
- .tuner_attach = af9015_tuner_attach,
- .stream = {
- .type = USB_BULK,
- .count = 6,
- .endpoint = 0x85,
- .u = {
- .bulk = {
- .buffersize =
- TS_USB20_FRAME_SIZE,
- }
+ .num_frontends = 1,
+ .fe = {
+ {
+ .frontend_attach = af9015_af9013_frontend_attach,
+ .tuner_attach = af9015_tuner_attach,
+ .stream = {
+ .type = USB_BULK,
+ .count = 6,
+ .endpoint = 0x85,
+ .u = {
+ .bulk = {
+ .buffersize = TS_USB20_FRAME_SIZE,
+ }
+ }
+ },
}
},
- }},
}
},
@@ -1575,102 +1592,67 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.cold_ids = {
&af9015_usb_table[AFATECH_9015],
&af9015_usb_table[AFATECH_9016],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "Leadtek WinFast DTV Dongle Gold",
.cold_ids = {
&af9015_usb_table[WINFAST_DTV_GOLD],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "Pinnacle PCTV 71e",
.cold_ids = {
&af9015_usb_table[PINNACLE_PCTV_71E],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "KWorld PlusTV Dual DVB-T Stick " \
"(DVB-T 399U)",
.cold_ids = {
&af9015_usb_table[KWORLD_PLUSTV_399U],
&af9015_usb_table[KWORLD_399U_2],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "DigitalNow TinyTwin DVB-T Receiver",
.cold_ids = {
&af9015_usb_table[TINYTWIN],
&af9015_usb_table[TINYTWIN_2],
&af9015_usb_table[TINYTWIN_3],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "TwinHan AzureWave AD-TU700(704J)",
.cold_ids = {
&af9015_usb_table[AZUREWAVE_TU700],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "TerraTec Cinergy T USB XE",
.cold_ids = {
&af9015_usb_table[TERRATEC_AF9015],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "KWorld PlusTV Dual DVB-T PCI " \
"(DVB-T PC160-2T)",
.cold_ids = {
&af9015_usb_table[KWORLD_PLUSTV_PC160],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "AVerMedia AVerTV DVB-T Volar X",
.cold_ids = {
&af9015_usb_table[AVERTV_VOLAR_X],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "TerraTec Cinergy T Stick RC",
.cold_ids = {
&af9015_usb_table[CINERGY_T_STICK_RC],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "TerraTec Cinergy T Stick Dual RC",
.cold_ids = {
&af9015_usb_table[CINERGY_T_DUAL_RC],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "AverMedia AVerTV Red HD+ (A850T)",
.cold_ids = {
&af9015_usb_table[AVERTV_A850T],
- NULL
},
- .warm_ids = {NULL},
},
}
}, {
@@ -1686,43 +1668,44 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.num_adapters = 2,
.adapter = {
{
- .num_frontends = 1,
- .fe = {{
- .caps = DVB_USB_ADAP_HAS_PID_FILTER |
- DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-
- .pid_filter_count = 32,
- .pid_filter = af9015_pid_filter,
- .pid_filter_ctrl = af9015_pid_filter_ctrl,
-
- .frontend_attach =
- af9015_af9013_frontend_attach,
- .tuner_attach = af9015_tuner_attach,
- .stream = {
- .type = USB_BULK,
- .count = 6,
- .endpoint = 0x84,
+ .num_frontends = 1,
+ .fe = {
+ {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+ .pid_filter_count = 32,
+ .pid_filter = af9015_pid_filter,
+ .pid_filter_ctrl = af9015_pid_filter_ctrl,
+
+ .frontend_attach = af9015_af9013_frontend_attach,
+ .tuner_attach = af9015_tuner_attach,
+ .stream = {
+ .type = USB_BULK,
+ .count = 6,
+ .endpoint = 0x84,
+ },
+ }
},
- }},
},
{
- .num_frontends = 1,
- .fe = {{
- .frontend_attach =
- af9015_af9013_frontend_attach,
- .tuner_attach = af9015_tuner_attach,
- .stream = {
- .type = USB_BULK,
- .count = 6,
- .endpoint = 0x85,
- .u = {
- .bulk = {
- .buffersize =
- TS_USB20_FRAME_SIZE,
- }
+ .num_frontends = 1,
+ .fe = {
+ {
+ .frontend_attach = af9015_af9013_frontend_attach,
+ .tuner_attach = af9015_tuner_attach,
+ .stream = {
+ .type = USB_BULK,
+ .count = 6,
+ .endpoint = 0x85,
+ .u = {
+ .bulk = {
+ .buffersize = TS_USB20_FRAME_SIZE,
+ }
+ }
+ },
}
},
- }},
}
},
@@ -1744,51 +1727,33 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.name = "Xtensions XD-380",
.cold_ids = {
&af9015_usb_table[XTENSIONS_380U],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "MSI DIGIVOX Duo",
.cold_ids = {
&af9015_usb_table[MSI_DIGIVOX_DUO],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "Fujitsu-Siemens Slim Mobile USB DVB-T",
.cold_ids = {
&af9015_usb_table[AVERTV_VOLAR_X_REV2],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "Telestar Starstick 2",
.cold_ids = {
&af9015_usb_table[TELESTAR_STARSTICK_2],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "AVerMedia A309",
.cold_ids = {
&af9015_usb_table[AVERMEDIA_A309_USB],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "MSI Digi VOX mini III",
.cold_ids = {
&af9015_usb_table[MSI_DIGIVOX_MINI_III],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "KWorld USB DVB-T TV Stick II " \
"(VS-DVB-T 395U)",
.cold_ids = {
@@ -1796,34 +1761,23 @@ static struct dvb_usb_device_properties af9015_properties[] = {
&af9015_usb_table[KWORLD_E39B],
&af9015_usb_table[KWORLD_E395],
&af9015_usb_table[KWORLD_E39A],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "TrekStor DVB-T USB Stick",
.cold_ids = {
&af9015_usb_table[TREKSTOR_DVBT],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "AverMedia AVerTV Volar Black HD " \
"(A850)",
.cold_ids = {
&af9015_usb_table[AVERTV_A850],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "Sveon STV22 Dual USB DVB-T Tuner HDTV",
.cold_ids = {
&af9015_usb_table[SVEON_STV22],
- NULL
},
- .warm_ids = {NULL},
},
}
}, {
@@ -1839,43 +1793,44 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.num_adapters = 2,
.adapter = {
{
- .num_frontends = 1,
- .fe = {{
- .caps = DVB_USB_ADAP_HAS_PID_FILTER |
- DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-
- .pid_filter_count = 32,
- .pid_filter = af9015_pid_filter,
- .pid_filter_ctrl = af9015_pid_filter_ctrl,
-
- .frontend_attach =
- af9015_af9013_frontend_attach,
- .tuner_attach = af9015_tuner_attach,
- .stream = {
- .type = USB_BULK,
- .count = 6,
- .endpoint = 0x84,
+ .num_frontends = 1,
+ .fe = {
+ {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+ .pid_filter_count = 32,
+ .pid_filter = af9015_pid_filter,
+ .pid_filter_ctrl = af9015_pid_filter_ctrl,
+
+ .frontend_attach = af9015_af9013_frontend_attach,
+ .tuner_attach = af9015_tuner_attach,
+ .stream = {
+ .type = USB_BULK,
+ .count = 6,
+ .endpoint = 0x84,
+ },
+ }
},
- }},
},
{
- .num_frontends = 1,
- .fe = {{
- .frontend_attach =
- af9015_af9013_frontend_attach,
- .tuner_attach = af9015_tuner_attach,
- .stream = {
- .type = USB_BULK,
- .count = 6,
- .endpoint = 0x85,
- .u = {
- .bulk = {
- .buffersize =
- TS_USB20_FRAME_SIZE,
- }
+ .num_frontends = 1,
+ .fe = {
+ {
+ .frontend_attach = af9015_af9013_frontend_attach,
+ .tuner_attach = af9015_tuner_attach,
+ .stream = {
+ .type = USB_BULK,
+ .count = 6,
+ .endpoint = 0x85,
+ .u = {
+ .bulk = {
+ .buffersize = TS_USB20_FRAME_SIZE,
+ }
+ }
+ },
}
},
- }},
}
},
@@ -1897,76 +1852,50 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.name = "AverMedia AVerTV Volar GPS 805 (A805)",
.cold_ids = {
&af9015_usb_table[AVERTV_A805],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "Conceptronic USB2.0 DVB-T CTVDIGRCU " \
"V3.0",
.cold_ids = {
&af9015_usb_table[CONCEPTRONIC_CTVDIGRCU],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "KWorld Digial MC-810",
.cold_ids = {
&af9015_usb_table[KWORLD_MC810],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "Genius TVGo DVB-T03",
.cold_ids = {
&af9015_usb_table[GENIUS_TVGO_DVB_T03],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "KWorld PlusTV DVB-T PCI Pro Card " \
"(DVB-T PC160-T)",
.cold_ids = {
&af9015_usb_table[KWORLD_PC160_T],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "Sveon STV20 Tuner USB DVB-T HDTV",
.cold_ids = {
&af9015_usb_table[SVEON_STV20],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "Leadtek WinFast DTV2000DS",
.cold_ids = {
&af9015_usb_table[WINFAST_DTV2000DS],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "KWorld USB DVB-T Stick Mobile " \
"(UB383-T)",
.cold_ids = {
&af9015_usb_table[KWORLD_UB383_T],
- NULL
},
- .warm_ids = {NULL},
- },
- {
+ }, {
.name = "AverMedia AVerTV Volar M (A815Mac)",
.cold_ids = {
&af9015_usb_table[AVERMEDIA_A815M],
- NULL
},
- .warm_ids = {NULL},
},
}
},
@@ -2019,5 +1948,5 @@ static struct usb_driver af9015_usb_driver = {
module_usb_driver(af9015_usb_driver);
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("Driver for Afatech AF9015 DVB-T");
+MODULE_DESCRIPTION("Afatech AF9015 driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9035.c b/drivers/media/dvb/dvb-usb/af9035.c
new file mode 100644
index 000000000000..e83b39d3993c
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9035.c
@@ -0,0 +1,1242 @@
+/*
+ * Afatech AF9035 DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2012 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "af9035.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+static DEFINE_MUTEX(af9035_usb_mutex);
+static struct dvb_usb_device_properties af9035_properties[2];
+static int af9035_properties_count = ARRAY_SIZE(af9035_properties);
+
+static u16 af9035_checksum(const u8 *buf, size_t len)
+{
+ size_t i;
+ u16 checksum = 0;
+
+ for (i = 1; i < len; i++) {
+ if (i % 2)
+ checksum += buf[i] << 8;
+ else
+ checksum += buf[i];
+ }
+ checksum = ~checksum;
+
+ return checksum;
+}
+
+static int af9035_ctrl_msg(struct usb_device *udev, struct usb_req *req)
+{
+#define BUF_LEN 64
+#define REQ_HDR_LEN 4 /* send header size */
+#define ACK_HDR_LEN 3 /* rece header size */
+#define CHECKSUM_LEN 2
+#define USB_TIMEOUT 2000
+
+ int ret, msg_len, act_len;
+ u8 buf[BUF_LEN];
+ static u8 seq; /* packet sequence number */
+ u16 checksum, tmp_checksum;
+
+ /* buffer overflow check */
+ if (req->wlen > (BUF_LEN - REQ_HDR_LEN - CHECKSUM_LEN) ||
+ req->rlen > (BUF_LEN - ACK_HDR_LEN - CHECKSUM_LEN)) {
+ pr_debug("%s: too much data wlen=%d rlen=%d\n", __func__,
+ req->wlen, req->rlen);
+ return -EINVAL;
+ }
+
+ if (mutex_lock_interruptible(&af9035_usb_mutex) < 0)
+ return -EAGAIN;
+
+ buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1;
+ buf[1] = req->mbox;
+ buf[2] = req->cmd;
+ buf[3] = seq++;
+ if (req->wlen)
+ memcpy(&buf[4], req->wbuf, req->wlen);
+
+ /* calc and add checksum */
+ checksum = af9035_checksum(buf, buf[0] - 1);
+ buf[buf[0] - 1] = (checksum >> 8);
+ buf[buf[0] - 0] = (checksum & 0xff);
+
+ msg_len = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN ;
+
+ /* send req */
+ ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len,
+ &act_len, USB_TIMEOUT);
+ if (ret < 0)
+ err("bulk message failed=%d (%d/%d)", ret, msg_len, act_len);
+ else
+ if (act_len != msg_len)
+ ret = -EIO; /* all data is not send */
+ if (ret < 0)
+ goto err_mutex_unlock;
+
+ /* no ack for those packets */
+ if (req->cmd == CMD_FW_DL)
+ goto exit_mutex_unlock;
+
+ /* receive ack and data if read req */
+ msg_len = ACK_HDR_LEN + req->rlen + CHECKSUM_LEN;
+ ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len,
+ &act_len, USB_TIMEOUT);
+ if (ret < 0) {
+ err("recv bulk message failed=%d", ret);
+ ret = -EIO;
+ goto err_mutex_unlock;
+ }
+
+ if (act_len != msg_len) {
+ err("recv bulk message truncated (%d != %d)", act_len, msg_len);
+ ret = -EIO;
+ goto err_mutex_unlock;
+ }
+
+ /* verify checksum */
+ checksum = af9035_checksum(buf, act_len - 2);
+ tmp_checksum = (buf[act_len - 2] << 8) | buf[act_len - 1];
+ if (tmp_checksum != checksum) {
+ err("%s: command=%02x checksum mismatch (%04x != %04x)",
+ __func__, req->cmd, tmp_checksum, checksum);
+ ret = -EIO;
+ goto err_mutex_unlock;
+ }
+
+ /* check status */
+ if (buf[2]) {
+ pr_debug("%s: command=%02x failed fw error=%d\n", __func__,
+ req->cmd, buf[2]);
+ ret = -EIO;
+ goto err_mutex_unlock;
+ }
+
+ /* read request, copy returned data to return buf */
+ if (req->rlen)
+ memcpy(req->rbuf, &buf[ACK_HDR_LEN], req->rlen);
+
+err_mutex_unlock:
+exit_mutex_unlock:
+ mutex_unlock(&af9035_usb_mutex);
+
+ return ret;
+}
+
+/* write multiple registers */
+static int af9035_wr_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len)
+{
+ u8 wbuf[6 + len];
+ u8 mbox = (reg >> 16) & 0xff;
+ struct usb_req req = { CMD_MEM_WR, mbox, sizeof(wbuf), wbuf, 0, NULL };
+
+ wbuf[0] = len;
+ wbuf[1] = 2;
+ wbuf[2] = 0;
+ wbuf[3] = 0;
+ wbuf[4] = (reg >> 8) & 0xff;
+ wbuf[5] = (reg >> 0) & 0xff;
+ memcpy(&wbuf[6], val, len);
+
+ return af9035_ctrl_msg(d->udev, &req);
+}
+
+/* read multiple registers */
+static int af9035_rd_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len)
+{
+ u8 wbuf[] = { len, 2, 0, 0, (reg >> 8) & 0xff, reg & 0xff };
+ u8 mbox = (reg >> 16) & 0xff;
+ struct usb_req req = { CMD_MEM_RD, mbox, sizeof(wbuf), wbuf, len, val };
+
+ return af9035_ctrl_msg(d->udev, &req);
+}
+
+/* write single register */
+static int af9035_wr_reg(struct dvb_usb_device *d, u32 reg, u8 val)
+{
+ return af9035_wr_regs(d, reg, &val, 1);
+}
+
+/* read single register */
+static int af9035_rd_reg(struct dvb_usb_device *d, u32 reg, u8 *val)
+{
+ return af9035_rd_regs(d, reg, val, 1);
+}
+
+/* write single register with mask */
+static int af9035_wr_reg_mask(struct dvb_usb_device *d, u32 reg, u8 val,
+ u8 mask)
+{
+ int ret;
+ u8 tmp;
+
+ /* no need for read if whole reg is written */
+ if (mask != 0xff) {
+ ret = af9035_rd_regs(d, reg, &tmp, 1);
+ if (ret)
+ return ret;
+
+ val &= mask;
+ tmp &= ~mask;
+ val |= tmp;
+ }
+
+ return af9035_wr_regs(d, reg, &val, 1);
+}
+
+static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg msg[], int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ struct state *state = d->priv;
+ int ret;
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ /*
+ * I2C sub header is 5 bytes long. Meaning of those bytes are:
+ * 0: data len
+ * 1: I2C addr << 1
+ * 2: reg addr len
+ * byte 3 and 4 can be used as reg addr
+ * 3: reg addr MSB
+ * used when reg addr len is set to 2
+ * 4: reg addr LSB
+ * used when reg addr len is set to 1 or 2
+ *
+ * For the simplify we do not use register addr at all.
+ * NOTE: As a firmware knows tuner type there is very small possibility
+ * there could be some tuner I2C hacks done by firmware and this may
+ * lead problems if firmware expects those bytes are used.
+ */
+ if (num == 2 && !(msg[0].flags & I2C_M_RD) &&
+ (msg[1].flags & I2C_M_RD)) {
+ if (msg[0].len > 40 || msg[1].len > 40) {
+ /* TODO: correct limits > 40 */
+ ret = -EOPNOTSUPP;
+ } else if (msg[0].addr == state->af9033_config[0].i2c_addr) {
+ /* integrated demod */
+ u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
+ msg[0].buf[2];
+ ret = af9035_rd_regs(d, reg, &msg[1].buf[0],
+ msg[1].len);
+ } else {
+ /* I2C */
+ u8 buf[5 + msg[0].len];
+ struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf),
+ buf, msg[1].len, msg[1].buf };
+ buf[0] = msg[1].len;
+ buf[1] = msg[0].addr << 1;
+ buf[2] = 0x00; /* reg addr len */
+ buf[3] = 0x00; /* reg addr MSB */
+ buf[4] = 0x00; /* reg addr LSB */
+ memcpy(&buf[5], msg[0].buf, msg[0].len);
+ ret = af9035_ctrl_msg(d->udev, &req);
+ }
+ } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
+ if (msg[0].len > 40) {
+ /* TODO: correct limits > 40 */
+ ret = -EOPNOTSUPP;
+ } else if (msg[0].addr == state->af9033_config[0].i2c_addr) {
+ /* integrated demod */
+ u32 reg = msg[0].buf[0] << 16 | msg[0].buf[1] << 8 |
+ msg[0].buf[2];
+ ret = af9035_wr_regs(d, reg, &msg[0].buf[3],
+ msg[0].len - 3);
+ } else {
+ /* I2C */
+ u8 buf[5 + msg[0].len];
+ struct usb_req req = { CMD_I2C_WR, 0, sizeof(buf), buf,
+ 0, NULL };
+ buf[0] = msg[0].len;
+ buf[1] = msg[0].addr << 1;
+ buf[2] = 0x00; /* reg addr len */
+ buf[3] = 0x00; /* reg addr MSB */
+ buf[4] = 0x00; /* reg addr LSB */
+ memcpy(&buf[5], msg[0].buf, msg[0].len);
+ ret = af9035_ctrl_msg(d->udev, &req);
+ }
+ } else {
+ /*
+ * We support only two kind of I2C transactions:
+ * 1) 1 x read + 1 x write
+ * 2) 1 x write
+ */
+ ret = -EOPNOTSUPP;
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+
+ if (ret < 0)
+ return ret;
+ else
+ return num;
+}
+
+static u32 af9035_i2c_functionality(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm af9035_i2c_algo = {
+ .master_xfer = af9035_i2c_master_xfer,
+ .functionality = af9035_i2c_functionality,
+};
+
+#define AF9035_POLL 250
+static int af9035_rc_query(struct dvb_usb_device *d)
+{
+ unsigned int key;
+ unsigned char b[4];
+ int ret;
+ struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, b };
+
+ ret = af9035_ctrl_msg(d->udev, &req);
+ if (ret < 0)
+ goto err;
+
+ if ((b[2] + b[3]) == 0xff) {
+ if ((b[0] + b[1]) == 0xff) {
+ /* NEC */
+ key = b[0] << 8 | b[2];
+ } else {
+ /* ext. NEC */
+ key = b[0] << 16 | b[1] << 8 | b[2];
+ }
+ } else {
+ key = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];
+ }
+
+ rc_keydown(d->rc_dev, key, 0);
+
+err:
+ /* ignore errors */
+ return 0;
+}
+
+static int af9035_init(struct dvb_usb_device *d)
+{
+ struct state *state = d->priv;
+ int ret, i;
+ u16 frame_size = 87 * 188 / 4;
+ u8 packet_size = 512 / 4;
+ struct reg_val_mask tab[] = {
+ { 0x80f99d, 0x01, 0x01 },
+ { 0x80f9a4, 0x01, 0x01 },
+ { 0x00dd11, 0x00, 0x20 },
+ { 0x00dd11, 0x00, 0x40 },
+ { 0x00dd13, 0x00, 0x20 },
+ { 0x00dd13, 0x00, 0x40 },
+ { 0x00dd11, 0x20, 0x20 },
+ { 0x00dd88, (frame_size >> 0) & 0xff, 0xff},
+ { 0x00dd89, (frame_size >> 8) & 0xff, 0xff},
+ { 0x00dd0c, packet_size, 0xff},
+ { 0x00dd11, state->dual_mode << 6, 0x40 },
+ { 0x00dd8a, (frame_size >> 0) & 0xff, 0xff},
+ { 0x00dd8b, (frame_size >> 8) & 0xff, 0xff},
+ { 0x00dd0d, packet_size, 0xff },
+ { 0x80f9a3, 0x00, 0x01 },
+ { 0x80f9cd, 0x00, 0x01 },
+ { 0x80f99d, 0x00, 0x01 },
+ { 0x80f9a4, 0x00, 0x01 },
+ };
+
+ pr_debug("%s: USB speed=%d frame_size=%04x packet_size=%02x\n",
+ __func__, d->udev->speed, frame_size, packet_size);
+
+ /* init endpoints */
+ for (i = 0; i < ARRAY_SIZE(tab); i++) {
+ ret = af9035_wr_reg_mask(d, tab[i].reg, tab[i].val,
+ tab[i].mask);
+ if (ret < 0)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9035_identify_state(struct usb_device *udev,
+ struct dvb_usb_device_properties *props,
+ struct dvb_usb_device_description **desc,
+ int *cold)
+{
+ int ret;
+ u8 wbuf[1] = { 1 };
+ u8 rbuf[4];
+ struct usb_req req = { CMD_FW_QUERYINFO, 0, sizeof(wbuf), wbuf,
+ sizeof(rbuf), rbuf };
+
+ ret = af9035_ctrl_msg(udev, &req);
+ if (ret < 0)
+ goto err;
+
+ pr_debug("%s: reply=%02x %02x %02x %02x\n", __func__,
+ rbuf[0], rbuf[1], rbuf[2], rbuf[3]);
+ if (rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])
+ *cold = 0;
+ else
+ *cold = 1;
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9035_download_firmware(struct usb_device *udev,
+ const struct firmware *fw)
+{
+ int ret, i, j, len;
+ u8 wbuf[1];
+ u8 rbuf[4];
+ struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
+ struct usb_req req_fw_dl = { CMD_FW_DL, 0, 0, wbuf, 0, NULL };
+ struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ;
+ u8 hdr_core;
+ u16 hdr_addr, hdr_data_len, hdr_checksum;
+ #define MAX_DATA 58
+ #define HDR_SIZE 7
+
+ /*
+ * Thanks to Daniel Glöckner <daniel-gl@gmx.net> about that info!
+ *
+ * byte 0: MCS 51 core
+ * There are two inside the AF9035 (1=Link and 2=OFDM) with separate
+ * address spaces
+ * byte 1-2: Big endian destination address
+ * byte 3-4: Big endian number of data bytes following the header
+ * byte 5-6: Big endian header checksum, apparently ignored by the chip
+ * Calculated as ~(h[0]*256+h[1]+h[2]*256+h[3]+h[4]*256)
+ */
+
+ for (i = fw->size; i > HDR_SIZE;) {
+ hdr_core = fw->data[fw->size - i + 0];
+ hdr_addr = fw->data[fw->size - i + 1] << 8;
+ hdr_addr |= fw->data[fw->size - i + 2] << 0;
+ hdr_data_len = fw->data[fw->size - i + 3] << 8;
+ hdr_data_len |= fw->data[fw->size - i + 4] << 0;
+ hdr_checksum = fw->data[fw->size - i + 5] << 8;
+ hdr_checksum |= fw->data[fw->size - i + 6] << 0;
+
+ pr_debug("%s: core=%d addr=%04x data_len=%d checksum=%04x\n",
+ __func__, hdr_core, hdr_addr, hdr_data_len,
+ hdr_checksum);
+
+ if (((hdr_core != 1) && (hdr_core != 2)) ||
+ (hdr_data_len > i)) {
+ pr_debug("%s: bad firmware\n", __func__);
+ break;
+ }
+
+ /* download begin packet */
+ req.cmd = CMD_FW_DL_BEGIN;
+ ret = af9035_ctrl_msg(udev, &req);
+ if (ret < 0)
+ goto err;
+
+ /* download firmware packet(s) */
+ for (j = HDR_SIZE + hdr_data_len; j > 0; j -= MAX_DATA) {
+ len = j;
+ if (len > MAX_DATA)
+ len = MAX_DATA;
+ req_fw_dl.wlen = len;
+ req_fw_dl.wbuf = (u8 *) &fw->data[fw->size - i +
+ HDR_SIZE + hdr_data_len - j];
+ ret = af9035_ctrl_msg(udev, &req_fw_dl);
+ if (ret < 0)
+ goto err;
+ }
+
+ /* download end packet */
+ req.cmd = CMD_FW_DL_END;
+ ret = af9035_ctrl_msg(udev, &req);
+ if (ret < 0)
+ goto err;
+
+ i -= hdr_data_len + HDR_SIZE;
+
+ pr_debug("%s: data uploaded=%zu\n", __func__, fw->size - i);
+ }
+
+ /* firmware loaded, request boot */
+ req.cmd = CMD_FW_BOOT;
+ ret = af9035_ctrl_msg(udev, &req);
+ if (ret < 0)
+ goto err;
+
+ /* ensure firmware starts */
+ wbuf[0] = 1;
+ ret = af9035_ctrl_msg(udev, &req_fw_ver);
+ if (ret < 0)
+ goto err;
+
+ if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) {
+ info("firmware did not run");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ info("firmware version=%d.%d.%d.%d", rbuf[0], rbuf[1], rbuf[2],
+ rbuf[3]);
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9035_download_firmware_it9135(struct usb_device *udev,
+ const struct firmware *fw)
+{
+ int ret, i, i_prev;
+ u8 wbuf[1];
+ u8 rbuf[4];
+ struct usb_req req = { 0, 0, 0, NULL, 0, NULL };
+ struct usb_req req_fw_dl = { CMD_FW_SCATTER_WR, 0, 0, NULL, 0, NULL };
+ struct usb_req req_fw_ver = { CMD_FW_QUERYINFO, 0, 1, wbuf, 4, rbuf } ;
+ #define HDR_SIZE 7
+
+ /*
+ * There seems to be following firmware header. Meaning of bytes 0-3
+ * is unknown.
+ *
+ * 0: 3
+ * 1: 0, 1
+ * 2: 0
+ * 3: 1, 2, 3
+ * 4: addr MSB
+ * 5: addr LSB
+ * 6: count of data bytes ?
+ */
+
+ for (i = HDR_SIZE, i_prev = 0; i <= fw->size; i++) {
+ if (i == fw->size ||
+ (fw->data[i + 0] == 0x03 &&
+ (fw->data[i + 1] == 0x00 ||
+ fw->data[i + 1] == 0x01) &&
+ fw->data[i + 2] == 0x00)) {
+ req_fw_dl.wlen = i - i_prev;
+ req_fw_dl.wbuf = (u8 *) &fw->data[i_prev];
+ i_prev = i;
+ ret = af9035_ctrl_msg(udev, &req_fw_dl);
+ if (ret < 0)
+ goto err;
+
+ pr_debug("%s: data uploaded=%d\n", __func__, i);
+ }
+ }
+
+ /* firmware loaded, request boot */
+ req.cmd = CMD_FW_BOOT;
+ ret = af9035_ctrl_msg(udev, &req);
+ if (ret < 0)
+ goto err;
+
+ /* ensure firmware starts */
+ wbuf[0] = 1;
+ ret = af9035_ctrl_msg(udev, &req_fw_ver);
+ if (ret < 0)
+ goto err;
+
+ if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) {
+ info("firmware did not run");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ info("firmware version=%d.%d.%d.%d", rbuf[0], rbuf[1], rbuf[2],
+ rbuf[3]);
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+/* abuse that callback as there is no better one for reading eeprom */
+static int af9035_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
+{
+ struct state *state = d->priv;
+ int ret, i, eeprom_shift = 0;
+ u8 tmp;
+ u16 tmp16;
+
+ /* check if there is dual tuners */
+ ret = af9035_rd_reg(d, EEPROM_DUAL_MODE, &tmp);
+ if (ret < 0)
+ goto err;
+
+ state->dual_mode = tmp;
+ pr_debug("%s: dual mode=%d\n", __func__, state->dual_mode);
+
+ for (i = 0; i < af9035_properties[0].num_adapters; i++) {
+ /* tuner */
+ ret = af9035_rd_reg(d, EEPROM_1_TUNER_ID + eeprom_shift, &tmp);
+ if (ret < 0)
+ goto err;
+
+ state->af9033_config[i].tuner = tmp;
+ pr_debug("%s: [%d]tuner=%02x\n", __func__, i, tmp);
+
+ switch (tmp) {
+ case AF9033_TUNER_TUA9001:
+ case AF9033_TUNER_FC0011:
+ case AF9033_TUNER_MXL5007T:
+ case AF9033_TUNER_TDA18218:
+ state->af9033_config[i].spec_inv = 1;
+ break;
+ default:
+ warn("tuner ID=%02x not supported, please report!",
+ tmp);
+ };
+
+ /* tuner IF frequency */
+ ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_L + eeprom_shift, &tmp);
+ if (ret < 0)
+ goto err;
+
+ tmp16 = tmp;
+
+ ret = af9035_rd_reg(d, EEPROM_1_IFFREQ_H + eeprom_shift, &tmp);
+ if (ret < 0)
+ goto err;
+
+ tmp16 |= tmp << 8;
+
+ pr_debug("%s: [%d]IF=%d\n", __func__, i, tmp16);
+
+ eeprom_shift = 0x10; /* shift for the 2nd tuner params */
+ }
+
+ /* get demod clock */
+ ret = af9035_rd_reg(d, 0x00d800, &tmp);
+ if (ret < 0)
+ goto err;
+
+ tmp = (tmp >> 0) & 0x0f;
+
+ for (i = 0; i < af9035_properties[0].num_adapters; i++)
+ state->af9033_config[i].clock = clock_lut[tmp];
+
+ ret = af9035_rd_reg(d, EEPROM_IR_MODE, &tmp);
+ if (ret < 0)
+ goto err;
+ pr_debug("%s: ir_mode=%02x\n", __func__, tmp);
+
+ /* don't activate rc if in HID mode or if not available */
+ if (tmp == 5) {
+ ret = af9035_rd_reg(d, EEPROM_IR_TYPE, &tmp);
+ if (ret < 0)
+ goto err;
+ pr_debug("%s: ir_type=%02x\n", __func__, tmp);
+
+ switch (tmp) {
+ case 0: /* NEC */
+ default:
+ d->props.rc.core.protocol = RC_TYPE_NEC;
+ d->props.rc.core.allowed_protos = RC_TYPE_NEC;
+ break;
+ case 1: /* RC6 */
+ d->props.rc.core.protocol = RC_TYPE_RC6;
+ d->props.rc.core.allowed_protos = RC_TYPE_RC6;
+ break;
+ }
+ d->props.rc.core.rc_query = af9035_rc_query;
+ }
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+/* abuse that callback as there is no better one for reading eeprom */
+static int af9035_read_mac_address_it9135(struct dvb_usb_device *d, u8 mac[6])
+{
+ struct state *state = d->priv;
+ int ret, i;
+ u8 tmp;
+
+ state->dual_mode = false;
+
+ /* get demod clock */
+ ret = af9035_rd_reg(d, 0x00d800, &tmp);
+ if (ret < 0)
+ goto err;
+
+ tmp = (tmp >> 0) & 0x0f;
+
+ for (i = 0; i < af9035_properties[0].num_adapters; i++)
+ state->af9033_config[i].clock = clock_lut_it9135[tmp];
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9035_fc0011_tuner_callback(struct dvb_usb_device *d,
+ int cmd, int arg)
+{
+ int ret;
+
+ switch (cmd) {
+ case FC0011_FE_CALLBACK_POWER:
+ /* Tuner enable */
+ ret = af9035_wr_reg_mask(d, 0xd8eb, 1, 1);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg_mask(d, 0xd8ec, 1, 1);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg_mask(d, 0xd8ed, 1, 1);
+ if (ret < 0)
+ goto err;
+
+ /* LED */
+ ret = af9035_wr_reg_mask(d, 0xd8d0, 1, 1);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg_mask(d, 0xd8d1, 1, 1);
+ if (ret < 0)
+ goto err;
+
+ usleep_range(10000, 50000);
+ break;
+ case FC0011_FE_CALLBACK_RESET:
+ ret = af9035_wr_reg(d, 0xd8e9, 1);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg(d, 0xd8e8, 1);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg(d, 0xd8e7, 1);
+ if (ret < 0)
+ goto err;
+
+ usleep_range(10000, 20000);
+
+ ret = af9035_wr_reg(d, 0xd8e7, 0);
+ if (ret < 0)
+ goto err;
+
+ usleep_range(10000, 20000);
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9035_tuner_callback(struct dvb_usb_device *d, int cmd, int arg)
+{
+ struct state *state = d->priv;
+
+ switch (state->af9033_config[0].tuner) {
+ case AF9033_TUNER_FC0011:
+ return af9035_fc0011_tuner_callback(d, cmd, arg);
+ default:
+ break;
+ }
+
+ return -ENODEV;
+}
+
+static int af9035_frontend_callback(void *adapter_priv, int component,
+ int cmd, int arg)
+{
+ struct i2c_adapter *adap = adapter_priv;
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+
+ switch (component) {
+ case DVB_FRONTEND_COMPONENT_TUNER:
+ return af9035_tuner_callback(d, cmd, arg);
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ struct state *state = adap->dev->priv;
+ int ret;
+
+ if (!state->af9033_config[adap->id].tuner) {
+ /* unsupported tuner */
+ ret = -ENODEV;
+ goto err;
+ }
+
+ if (adap->id == 0) {
+ state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB;
+ state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL;
+
+ ret = af9035_wr_reg(adap->dev, 0x00417f,
+ state->af9033_config[1].i2c_addr);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg(adap->dev, 0x00d81a,
+ state->dual_mode);
+ if (ret < 0)
+ goto err;
+ }
+
+ /* attach demodulator */
+ adap->fe_adap[0].fe = dvb_attach(af9033_attach,
+ &state->af9033_config[adap->id], &adap->dev->i2c_adap);
+ if (adap->fe_adap[0].fe == NULL) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ /* disable I2C-gate */
+ adap->fe_adap[0].fe->ops.i2c_gate_ctrl = NULL;
+ adap->fe_adap[0].fe->callback = af9035_frontend_callback;
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static struct tua9001_config af9035_tua9001_config = {
+ .i2c_addr = 0x60,
+};
+
+static const struct fc0011_config af9035_fc0011_config = {
+ .i2c_address = 0x60,
+};
+
+static struct mxl5007t_config af9035_mxl5007t_config = {
+ .xtal_freq_hz = MxL_XTAL_24_MHZ,
+ .if_freq_hz = MxL_IF_4_57_MHZ,
+ .invert_if = 0,
+ .loop_thru_enable = 0,
+ .clk_out_enable = 0,
+ .clk_out_amp = MxL_CLKOUT_AMP_0_94V,
+};
+
+static struct tda18218_config af9035_tda18218_config = {
+ .i2c_address = 0x60,
+ .i2c_wr_max = 21,
+};
+
+static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ struct state *state = adap->dev->priv;
+ int ret;
+ struct dvb_frontend *fe;
+
+ switch (state->af9033_config[adap->id].tuner) {
+ case AF9033_TUNER_TUA9001:
+ /* AF9035 gpiot3 = TUA9001 RESETN
+ AF9035 gpiot2 = TUA9001 RXEN */
+
+ /* configure gpiot2 and gpiot2 as output */
+ ret = af9035_wr_reg_mask(adap->dev, 0x00d8ec, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg_mask(adap->dev, 0x00d8ed, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg_mask(adap->dev, 0x00d8e8, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ ret = af9035_wr_reg_mask(adap->dev, 0x00d8e9, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ /* reset tuner */
+ ret = af9035_wr_reg_mask(adap->dev, 0x00d8e7, 0x00, 0x01);
+ if (ret < 0)
+ goto err;
+
+ usleep_range(2000, 20000);
+
+ ret = af9035_wr_reg_mask(adap->dev, 0x00d8e7, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ /* activate tuner RX */
+ /* TODO: use callback for TUA9001 RXEN */
+ ret = af9035_wr_reg_mask(adap->dev, 0x00d8eb, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+
+ /* attach tuner */
+ fe = dvb_attach(tua9001_attach, adap->fe_adap[0].fe,
+ &adap->dev->i2c_adap, &af9035_tua9001_config);
+ break;
+ case AF9033_TUNER_FC0011:
+ fe = dvb_attach(fc0011_attach, adap->fe_adap[0].fe,
+ &adap->dev->i2c_adap, &af9035_fc0011_config);
+ break;
+ case AF9033_TUNER_MXL5007T:
+ ret = af9035_wr_reg(adap->dev, 0x00d8e0, 1);
+ if (ret < 0)
+ goto err;
+ ret = af9035_wr_reg(adap->dev, 0x00d8e1, 1);
+ if (ret < 0)
+ goto err;
+ ret = af9035_wr_reg(adap->dev, 0x00d8df, 0);
+ if (ret < 0)
+ goto err;
+
+ msleep(30);
+
+ ret = af9035_wr_reg(adap->dev, 0x00d8df, 1);
+ if (ret < 0)
+ goto err;
+
+ msleep(300);
+
+ ret = af9035_wr_reg(adap->dev, 0x00d8c0, 1);
+ if (ret < 0)
+ goto err;
+ ret = af9035_wr_reg(adap->dev, 0x00d8c1, 1);
+ if (ret < 0)
+ goto err;
+ ret = af9035_wr_reg(adap->dev, 0x00d8bf, 0);
+ if (ret < 0)
+ goto err;
+ ret = af9035_wr_reg(adap->dev, 0x00d8b4, 1);
+ if (ret < 0)
+ goto err;
+ ret = af9035_wr_reg(adap->dev, 0x00d8b5, 1);
+ if (ret < 0)
+ goto err;
+ ret = af9035_wr_reg(adap->dev, 0x00d8b3, 1);
+ if (ret < 0)
+ goto err;
+
+ /* attach tuner */
+ fe = dvb_attach(mxl5007t_attach, adap->fe_adap[0].fe,
+ &adap->dev->i2c_adap, 0x60, &af9035_mxl5007t_config);
+ break;
+ case AF9033_TUNER_TDA18218:
+ /* attach tuner */
+ fe = dvb_attach(tda18218_attach, adap->fe_adap[0].fe,
+ &adap->dev->i2c_adap, &af9035_tda18218_config);
+ break;
+ default:
+ fe = NULL;
+ }
+
+ if (fe == NULL) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+enum af9035_id_entry {
+ AF9035_15A4_9035,
+ AF9035_15A4_1000,
+ AF9035_15A4_1001,
+ AF9035_15A4_1002,
+ AF9035_15A4_1003,
+ AF9035_0CCD_0093,
+ AF9035_07CA_A835,
+ AF9035_07CA_B835,
+ AF9035_07CA_1867,
+ AF9035_07CA_A867,
+ AF9035_07CA_0825,
+};
+
+static struct usb_device_id af9035_id[] = {
+ [AF9035_15A4_9035] = {
+ USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035)},
+ [AF9035_15A4_1000] = {
+ USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1000)},
+ [AF9035_15A4_1001] = {
+ USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1001)},
+ [AF9035_15A4_1002] = {
+ USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1002)},
+ [AF9035_15A4_1003] = {
+ USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1003)},
+ [AF9035_0CCD_0093] = {
+ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK)},
+ [AF9035_07CA_A835] = {
+ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835)},
+ [AF9035_07CA_B835] = {
+ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_B835)},
+ [AF9035_07CA_1867] = {
+ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_1867)},
+ [AF9035_07CA_A867] = {
+ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A867)},
+ [AF9035_07CA_0825] = {
+ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TWINSTAR)},
+ {},
+};
+
+MODULE_DEVICE_TABLE(usb, af9035_id);
+
+static struct dvb_usb_device_properties af9035_properties[] = {
+ {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = DEVICE_SPECIFIC,
+ .download_firmware = af9035_download_firmware,
+ .firmware = "dvb-usb-af9035-02.fw",
+ .no_reconnect = 1,
+
+ .size_of_priv = sizeof(struct state),
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .num_frontends = 1,
+ .fe = {
+ {
+ .frontend_attach = af9035_frontend_attach,
+ .tuner_attach = af9035_tuner_attach,
+ .stream = {
+ .type = USB_BULK,
+ .count = 6,
+ .endpoint = 0x84,
+ .u = {
+ .bulk = {
+ .buffersize = (87 * 188),
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+
+ .identify_state = af9035_identify_state,
+ .read_mac_address = af9035_read_mac_address,
+
+ .i2c_algo = &af9035_i2c_algo,
+
+ .rc.core = {
+ .protocol = RC_TYPE_UNKNOWN,
+ .module_name = "af9035",
+ .rc_query = NULL,
+ .rc_interval = AF9035_POLL,
+ .allowed_protos = RC_TYPE_UNKNOWN,
+ .rc_codes = RC_MAP_EMPTY,
+ },
+ .num_device_descs = 5,
+ .devices = {
+ {
+ .name = "Afatech AF9035 reference design",
+ .cold_ids = {
+ &af9035_id[AF9035_15A4_9035],
+ &af9035_id[AF9035_15A4_1000],
+ &af9035_id[AF9035_15A4_1001],
+ &af9035_id[AF9035_15A4_1002],
+ &af9035_id[AF9035_15A4_1003],
+ },
+ }, {
+ .name = "TerraTec Cinergy T Stick",
+ .cold_ids = {
+ &af9035_id[AF9035_0CCD_0093],
+ },
+ }, {
+ .name = "AVerMedia AVerTV Volar HD/PRO (A835)",
+ .cold_ids = {
+ &af9035_id[AF9035_07CA_A835],
+ &af9035_id[AF9035_07CA_B835],
+ },
+ }, {
+ .name = "AVerMedia HD Volar (A867)",
+ .cold_ids = {
+ &af9035_id[AF9035_07CA_1867],
+ &af9035_id[AF9035_07CA_A867],
+ },
+ }, {
+ .name = "AVerMedia Twinstar (A825)",
+ .cold_ids = {
+ &af9035_id[AF9035_07CA_0825],
+ },
+ },
+ }
+ },
+ {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = DEVICE_SPECIFIC,
+ .download_firmware = af9035_download_firmware_it9135,
+ .firmware = "dvb-usb-it9135-01.fw",
+ .no_reconnect = 1,
+
+ .size_of_priv = sizeof(struct state),
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .num_frontends = 1,
+ .fe = {
+ {
+ .frontend_attach = af9035_frontend_attach,
+ .tuner_attach = af9035_tuner_attach,
+ .stream = {
+ .type = USB_BULK,
+ .count = 6,
+ .endpoint = 0x84,
+ .u = {
+ .bulk = {
+ .buffersize = (87 * 188),
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+
+ .identify_state = af9035_identify_state,
+ .read_mac_address = af9035_read_mac_address_it9135,
+
+ .i2c_algo = &af9035_i2c_algo,
+
+ .num_device_descs = 0, /* disabled as no support for IT9135 */
+ .devices = {
+ {
+ .name = "ITE Tech. IT9135 reference design",
+ },
+ }
+ },
+};
+
+static int af9035_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ int ret, i;
+ struct dvb_usb_device *d = NULL;
+ struct usb_device *udev;
+ bool found;
+
+ pr_debug("%s: interface=%d\n", __func__,
+ intf->cur_altsetting->desc.bInterfaceNumber);
+
+ /* interface 0 is used by DVB-T receiver and
+ interface 1 is for remote controller (HID) */
+ if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
+ return 0;
+
+ /* Dynamic USB ID support. Replaces first device ID with current one. */
+ udev = interface_to_usbdev(intf);
+
+ for (i = 0, found = false; i < ARRAY_SIZE(af9035_id) - 1; i++) {
+ if (af9035_id[i].idVendor ==
+ le16_to_cpu(udev->descriptor.idVendor) &&
+ af9035_id[i].idProduct ==
+ le16_to_cpu(udev->descriptor.idProduct)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ pr_debug("%s: using dynamic ID %04x:%04x\n", __func__,
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct));
+ af9035_properties[0].devices[0].cold_ids[0]->idVendor =
+ le16_to_cpu(udev->descriptor.idVendor);
+ af9035_properties[0].devices[0].cold_ids[0]->idProduct =
+ le16_to_cpu(udev->descriptor.idProduct);
+ }
+
+
+ for (i = 0; i < af9035_properties_count; i++) {
+ ret = dvb_usb_device_init(intf, &af9035_properties[i],
+ THIS_MODULE, &d, adapter_nr);
+
+ if (ret == -ENODEV)
+ continue;
+ else
+ break;
+ }
+
+ if (ret < 0)
+ goto err;
+
+ if (d) {
+ ret = af9035_init(d);
+ if (ret < 0)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver af9035_usb_driver = {
+ .name = "dvb_usb_af9035",
+ .probe = af9035_usb_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = af9035_id,
+};
+
+module_usb_driver(af9035_usb_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Afatech AF9035 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9035.h b/drivers/media/dvb/dvb-usb/af9035.h
new file mode 100644
index 000000000000..481a1a43dd2a
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9035.h
@@ -0,0 +1,113 @@
+/*
+ * Afatech AF9035 DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2012 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef AF9035_H
+#define AF9035_H
+
+/* prefix for dvb-usb log writings */
+#define DVB_USB_LOG_PREFIX "af9035"
+
+#include "dvb-usb.h"
+#include "af9033.h"
+#include "tua9001.h"
+#include "fc0011.h"
+#include "mxl5007t.h"
+#include "tda18218.h"
+
+struct reg_val {
+ u32 reg;
+ u8 val;
+};
+
+struct reg_val_mask {
+ u32 reg;
+ u8 val;
+ u8 mask;
+};
+
+struct usb_req {
+ u8 cmd;
+ u8 mbox;
+ u8 wlen;
+ u8 *wbuf;
+ u8 rlen;
+ u8 *rbuf;
+};
+
+struct state {
+ bool dual_mode;
+
+ struct af9033_config af9033_config[2];
+};
+
+u32 clock_lut[] = {
+ 20480000, /* FPGA */
+ 16384000, /* 16.38 MHz */
+ 20480000, /* 20.48 MHz */
+ 36000000, /* 36.00 MHz */
+ 30000000, /* 30.00 MHz */
+ 26000000, /* 26.00 MHz */
+ 28000000, /* 28.00 MHz */
+ 32000000, /* 32.00 MHz */
+ 34000000, /* 34.00 MHz */
+ 24000000, /* 24.00 MHz */
+ 22000000, /* 22.00 MHz */
+ 12000000, /* 12.00 MHz */
+};
+
+u32 clock_lut_it9135[] = {
+ 12000000, /* 12.00 MHz */
+ 20480000, /* 20.48 MHz */
+ 36000000, /* 36.00 MHz */
+ 30000000, /* 30.00 MHz */
+ 26000000, /* 26.00 MHz */
+ 28000000, /* 28.00 MHz */
+ 32000000, /* 32.00 MHz */
+ 34000000, /* 34.00 MHz */
+ 24000000, /* 24.00 MHz */
+ 22000000, /* 22.00 MHz */
+};
+
+/* EEPROM locations */
+#define EEPROM_IR_MODE 0x430d
+#define EEPROM_DUAL_MODE 0x4326
+#define EEPROM_IR_TYPE 0x4329
+#define EEPROM_1_IFFREQ_L 0x432d
+#define EEPROM_1_IFFREQ_H 0x432e
+#define EEPROM_1_TUNER_ID 0x4331
+#define EEPROM_2_IFFREQ_L 0x433d
+#define EEPROM_2_IFFREQ_H 0x433e
+#define EEPROM_2_TUNER_ID 0x4341
+
+/* USB commands */
+#define CMD_MEM_RD 0x00
+#define CMD_MEM_WR 0x01
+#define CMD_I2C_RD 0x02
+#define CMD_I2C_WR 0x03
+#define CMD_IR_GET 0x18
+#define CMD_FW_DL 0x21
+#define CMD_FW_QUERYINFO 0x22
+#define CMD_FW_BOOT 0x23
+#define CMD_FW_DL_BEGIN 0x24
+#define CMD_FW_DL_END 0x25
+#define CMD_FW_SCATTER_WR 0x29
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index 02290c60f72f..7e9e00fae04e 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -32,7 +32,7 @@ int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
err("could not acquire lock");
- return 0;
+ return -EINTR;
}
ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
@@ -118,7 +118,7 @@ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
err("could not acquire lock");
- return 0;
+ return -EINTR;
}
st->buf[0] = REQUEST_SET_GPIO;
@@ -139,7 +139,7 @@ static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets)
if (st->fw_version >= 0x10201) {
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
err("could not acquire lock");
- return 0;
+ return -EINTR;
}
st->buf[0] = REQUEST_SET_USB_XFER_LEN;
@@ -178,7 +178,7 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
/* Ensure nobody else hits the i2c bus while we're sending our
sequence of messages, (such as the remote control thread) */
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
- return -EAGAIN;
+ return -EINTR;
for (i = 0; i < num; i++) {
if (i == 0) {
@@ -228,7 +228,8 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
/* Write request */
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
err("could not acquire lock");
- return 0;
+ mutex_unlock(&d->i2c_mutex);
+ return -EINTR;
}
st->buf[0] = REQUEST_NEW_I2C_WRITE;
st->buf[1] = msg[i].addr << 1;
@@ -271,10 +272,11 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
int i,len;
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
- return -EAGAIN;
+ return -EINTR;
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
err("could not acquire lock");
- return 0;
+ mutex_unlock(&d->i2c_mutex);
+ return -EINTR;
}
for (i = 0; i < num; i++) {
@@ -369,7 +371,7 @@ static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll,
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
err("could not acquire lock");
- return 0;
+ return -EINTR;
}
st->buf[0] = REQUEST_SET_CLOCK;
@@ -401,7 +403,7 @@ int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz)
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
err("could not acquire lock");
- return 0;
+ return -EINTR;
}
st->buf[0] = REQUEST_SET_I2C_PARAM;
@@ -561,7 +563,7 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
if (mutex_lock_interruptible(&adap->dev->usb_mutex) < 0) {
err("could not acquire lock");
- return 0;
+ return -EINTR;
}
st->buf[0] = REQUEST_ENABLE_VIDEO;
@@ -611,7 +613,7 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
err("could not acquire lock");
- return 0;
+ return -EINTR;
}
st->buf[0] = REQUEST_SET_RC;
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index f9e966aa26e7..510001da6e83 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -3569,6 +3569,7 @@ struct usb_device_id dib0700_usb_id_table[] = {
{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7090E) },
{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7790E) },
/* 80 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE8096P) },
+ { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_2) },
{ 0 } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -3832,7 +3833,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
},
- .num_device_descs = 11,
+ .num_device_descs = 12,
.devices = {
{ "DiBcom STK7070P reference design",
{ &dib0700_usb_id_table[15], NULL },
@@ -3878,6 +3879,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ &dib0700_usb_id_table[50], NULL },
{ NULL },
},
+ { "Elgato EyeTV DTT rev. 2",
+ { &dib0700_usb_id_table[81], NULL },
+ { NULL },
+ },
},
.rc.core = {
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 397d8f232731..7a6160bf54ba 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -76,6 +76,11 @@
#define USB_PID_AFATECH_AF9005 0x9020
#define USB_PID_AFATECH_AF9015_9015 0x9015
#define USB_PID_AFATECH_AF9015_9016 0x9016
+#define USB_PID_AFATECH_AF9035_1000 0x1000
+#define USB_PID_AFATECH_AF9035_1001 0x1001
+#define USB_PID_AFATECH_AF9035_1002 0x1002
+#define USB_PID_AFATECH_AF9035_1003 0x1003
+#define USB_PID_AFATECH_AF9035_9035 0x9035
#define USB_PID_TREKSTOR_DVBT 0x901b
#define USB_VID_ALINK_DTU 0xf170
#define USB_PID_ANSONIC_DVBT_USB 0x6000
@@ -152,6 +157,7 @@
#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
#define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055
#define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2 0x0069
+#define USB_PID_TERRATEC_CINERGY_T_STICK 0x0093
#define USB_PID_TERRATEC_CINERGY_T_STICK_RC 0x0097
#define USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC 0x0099
#define USB_PID_TWINHAN_VP7041_COLD 0x3201
@@ -221,6 +227,11 @@
#define USB_PID_AVERMEDIA_A850T 0x850b
#define USB_PID_AVERMEDIA_A805 0xa805
#define USB_PID_AVERMEDIA_A815M 0x815a
+#define USB_PID_AVERMEDIA_A835 0xa835
+#define USB_PID_AVERMEDIA_B835 0xb835
+#define USB_PID_AVERMEDIA_1867 0x1867
+#define USB_PID_AVERMEDIA_A867 0xa867
+#define USB_PID_AVERMEDIA_TWINSTAR 0x0825
#define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006
#define USB_PID_TECHNOTREND_CONNECT_CT3650 0x300d
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a
@@ -327,6 +338,7 @@
#define USB_PID_MYGICA_D689 0xd811
#define USB_PID_ELGATO_EYETV_DIVERSITY 0x0011
#define USB_PID_ELGATO_EYETV_DTT 0x0021
+#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_DVB_T_USB_STICK_HIGH_SPEED_COLD 0x5000
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
index 53a5c30b51b2..5c8f651344fc 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
@@ -80,6 +80,14 @@ static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buffer
dvb_dmx_swfilter_204(&adap->demux, buffer, length);
}
+static void dvb_usb_data_complete_raw(struct usb_data_stream *stream,
+ u8 *buffer, size_t length)
+{
+ struct dvb_usb_adapter *adap = stream->user_priv;
+ if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
+ dvb_dmx_swfilter_raw(&adap->demux, buffer, length);
+}
+
int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap)
{
int i, ret = 0;
@@ -90,6 +98,10 @@ int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap)
adap->fe_adap[i].stream.complete =
dvb_usb_data_complete_204;
else
+ if (adap->props.fe[i].caps & DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD)
+ adap->fe_adap[i].stream.complete =
+ dvb_usb_data_complete_raw;
+ else
adap->fe_adap[i].stream.complete = dvb_usb_data_complete;
adap->fe_adap[i].stream.user_priv = adap;
ret = usb_urb_init(&adap->fe_adap[i].stream,
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index 6d7d13f9ce68..99f94409efa1 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -141,6 +141,7 @@ struct dvb_usb_adapter_fe_properties {
#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02
#define DVB_USB_ADAP_NEED_PID_FILTERING 0x04
#define DVB_USB_ADAP_RECEIVES_204_BYTE_TS 0x08
+#define DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD 0x10
int caps;
int pid_filter_count;
@@ -156,7 +157,7 @@ struct dvb_usb_adapter_fe_properties {
int size_of_priv;
};
-#define MAX_NO_OF_FE_PER_ADAP 2
+#define MAX_NO_OF_FE_PER_ADAP 3
struct dvb_usb_adapter_properties {
int size_of_priv;
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c
index 451c5a7adfb2..9382895b1b88 100644
--- a/drivers/media/dvb/dvb-usb/dw2102.c
+++ b/drivers/media/dvb/dvb-usb/dw2102.c
@@ -148,7 +148,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
- int i = 0, ret = 0;
+ int i = 0;
u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0};
u16 value;
@@ -162,7 +162,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
/* read stv0299 register */
value = msg[0].buf[0];/* register */
for (i = 0; i < msg[1].len; i++) {
- ret = dw210x_op_rw(d->udev, 0xb5, value + i, 0,
+ dw210x_op_rw(d->udev, 0xb5, value + i, 0,
buf6, 2, DW210X_READ_MSG);
msg[1].buf[i] = buf6[0];
}
@@ -174,7 +174,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
buf6[0] = 0x2a;
buf6[1] = msg[0].buf[0];
buf6[2] = msg[0].buf[1];
- ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+ dw210x_op_rw(d->udev, 0xb2, 0, 0,
buf6, 3, DW210X_WRITE_MSG);
break;
case 0x60:
@@ -187,17 +187,17 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
buf6[4] = msg[0].buf[1];
buf6[5] = msg[0].buf[2];
buf6[6] = msg[0].buf[3];
- ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+ dw210x_op_rw(d->udev, 0xb2, 0, 0,
buf6, 7, DW210X_WRITE_MSG);
} else {
/* read from tuner */
- ret = dw210x_op_rw(d->udev, 0xb5, 0, 0,
+ dw210x_op_rw(d->udev, 0xb5, 0, 0,
buf6, 1, DW210X_READ_MSG);
msg[0].buf[0] = buf6[0];
}
break;
case (DW2102_RC_QUERY):
- ret = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+ dw210x_op_rw(d->udev, 0xb8, 0, 0,
buf6, 2, DW210X_READ_MSG);
msg[0].buf[0] = buf6[0];
msg[0].buf[1] = buf6[1];
@@ -205,7 +205,7 @@ static int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
case (DW2102_VOLTAGE_CTRL):
buf6[0] = 0x30;
buf6[1] = msg[0].buf[0];
- ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+ dw210x_op_rw(d->udev, 0xb2, 0, 0,
buf6, 2, DW210X_WRITE_MSG);
break;
}
@@ -221,7 +221,6 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
struct i2c_msg msg[], int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
- int ret = 0;
u8 buf6[] = {0, 0, 0, 0, 0, 0, 0};
if (!d)
@@ -235,10 +234,10 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
buf6[0] = msg[0].addr << 1;
buf6[1] = msg[0].len;
buf6[2] = msg[0].buf[0];
- ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+ dw210x_op_rw(d->udev, 0xc2, 0, 0,
buf6, msg[0].len + 2, DW210X_WRITE_MSG);
/* read si2109 register */
- ret = dw210x_op_rw(d->udev, 0xc3, 0xd0, 0,
+ dw210x_op_rw(d->udev, 0xc3, 0xd0, 0,
buf6, msg[1].len + 2, DW210X_READ_MSG);
memcpy(msg[1].buf, buf6 + 2, msg[1].len);
@@ -250,11 +249,11 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
buf6[0] = msg[0].addr << 1;
buf6[1] = msg[0].len;
memcpy(buf6 + 2, msg[0].buf, msg[0].len);
- ret = dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6,
+ dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6,
msg[0].len + 2, DW210X_WRITE_MSG);
break;
case(DW2102_RC_QUERY):
- ret = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+ dw210x_op_rw(d->udev, 0xb8, 0, 0,
buf6, 2, DW210X_READ_MSG);
msg[0].buf[0] = buf6[0];
msg[0].buf[1] = buf6[1];
@@ -262,7 +261,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
case(DW2102_VOLTAGE_CTRL):
buf6[0] = 0x30;
buf6[1] = msg[0].buf[0];
- ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+ dw210x_op_rw(d->udev, 0xb2, 0, 0,
buf6, 2, DW210X_WRITE_MSG);
break;
}
@@ -276,7 +275,6 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
- int ret = 0;
if (!d)
return -ENODEV;
@@ -291,10 +289,10 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
obuf[0] = msg[0].addr << 1;
obuf[1] = msg[0].len;
obuf[2] = msg[0].buf[0];
- ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+ dw210x_op_rw(d->udev, 0xc2, 0, 0,
obuf, msg[0].len + 2, DW210X_WRITE_MSG);
/* second read registers */
- ret = dw210x_op_rw(d->udev, 0xc3, 0xd1 , 0,
+ dw210x_op_rw(d->udev, 0xc3, 0xd1 , 0,
ibuf, msg[1].len + 2, DW210X_READ_MSG);
memcpy(msg[1].buf, ibuf + 2, msg[1].len);
@@ -308,7 +306,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
obuf[0] = msg[0].addr << 1;
obuf[1] = msg[0].len;
memcpy(obuf + 2, msg[0].buf, msg[0].len);
- ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+ dw210x_op_rw(d->udev, 0xc2, 0, 0,
obuf, msg[0].len + 2, DW210X_WRITE_MSG);
break;
}
@@ -318,13 +316,13 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
obuf[0] = msg[0].addr << 1;
obuf[1] = msg[0].len;
memcpy(obuf + 2, msg[0].buf, msg[0].len);
- ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+ dw210x_op_rw(d->udev, 0xc2, 0, 0,
obuf, msg[0].len + 2, DW210X_WRITE_MSG);
break;
}
case(DW2102_RC_QUERY): {
u8 ibuf[2];
- ret = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+ dw210x_op_rw(d->udev, 0xb8, 0, 0,
ibuf, 2, DW210X_READ_MSG);
memcpy(msg[0].buf, ibuf , 2);
break;
@@ -333,7 +331,7 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
u8 obuf[2];
obuf[0] = 0x30;
obuf[1] = msg[0].buf[0];
- ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+ dw210x_op_rw(d->udev, 0xb2, 0, 0,
obuf, 2, DW210X_WRITE_MSG);
break;
}
@@ -349,7 +347,6 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
- int ret = 0;
int len, i, j;
if (!d)
@@ -361,7 +358,7 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
switch (msg[j].addr) {
case(DW2102_RC_QUERY): {
u8 ibuf[2];
- ret = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+ dw210x_op_rw(d->udev, 0xb8, 0, 0,
ibuf, 2, DW210X_READ_MSG);
memcpy(msg[j].buf, ibuf , 2);
break;
@@ -370,7 +367,7 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
u8 obuf[2];
obuf[0] = 0x30;
obuf[1] = msg[j].buf[0];
- ret = dw210x_op_rw(d->udev, 0xb2, 0, 0,
+ dw210x_op_rw(d->udev, 0xb2, 0, 0,
obuf, 2, DW210X_WRITE_MSG);
break;
}
@@ -382,7 +379,7 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
if (msg[j].flags == I2C_M_RD) {
/* read registers */
u8 ibuf[msg[j].len + 2];
- ret = dw210x_op_rw(d->udev, 0xc3,
+ dw210x_op_rw(d->udev, 0xc3,
(msg[j].addr << 1) + 1, 0,
ibuf, msg[j].len + 2,
DW210X_READ_MSG);
@@ -402,7 +399,7 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
do {
memcpy(obuf + 3, msg[j].buf + i,
(len > 16 ? 16 : len));
- ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+ dw210x_op_rw(d->udev, 0xc2, 0, 0,
obuf, (len > 16 ? 16 : len) + 3,
DW210X_WRITE_MSG);
i += 16;
@@ -414,7 +411,7 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
obuf[0] = msg[j].addr << 1;
obuf[1] = msg[j].len;
memcpy(obuf + 2, msg[j].buf, msg[j].len);
- ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+ dw210x_op_rw(d->udev, 0xc2, 0, 0,
obuf, msg[j].len + 2,
DW210X_WRITE_MSG);
}
@@ -432,7 +429,7 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
- int ret = 0, i;
+ int i;
if (!d)
return -ENODEV;
@@ -447,10 +444,10 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
obuf[0] = msg[0].addr << 1;
obuf[1] = msg[0].len;
obuf[2] = msg[0].buf[0];
- ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+ dw210x_op_rw(d->udev, 0xc2, 0, 0,
obuf, msg[0].len + 2, DW210X_WRITE_MSG);
/* second read registers */
- ret = dw210x_op_rw(d->udev, 0xc3, 0x19 , 0,
+ dw210x_op_rw(d->udev, 0xc3, 0x19 , 0,
ibuf, msg[1].len + 2, DW210X_READ_MSG);
memcpy(msg[1].buf, ibuf + 2, msg[1].len);
@@ -465,13 +462,13 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
obuf[0] = msg[0].addr << 1;
obuf[1] = msg[0].len;
memcpy(obuf + 2, msg[0].buf, msg[0].len);
- ret = dw210x_op_rw(d->udev, 0xc2, 0, 0,
+ dw210x_op_rw(d->udev, 0xc2, 0, 0,
obuf, msg[0].len + 2, DW210X_WRITE_MSG);
break;
}
case(DW2102_RC_QUERY): {
u8 ibuf[2];
- ret = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+ dw210x_op_rw(d->udev, 0xb8, 0, 0,
ibuf, 2, DW210X_READ_MSG);
memcpy(msg[0].buf, ibuf , 2);
break;
@@ -496,7 +493,6 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
struct usb_device *udev;
- int ret = 0;
int len, i, j;
if (!d)
@@ -509,7 +505,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
switch (msg[j].addr) {
case (DW2102_RC_QUERY): {
u8 ibuf[5];
- ret = dw210x_op_rw(d->udev, 0xb8, 0, 0,
+ dw210x_op_rw(d->udev, 0xb8, 0, 0,
ibuf, 5, DW210X_READ_MSG);
memcpy(msg[j].buf, ibuf + 3, 2);
break;
@@ -519,11 +515,11 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
obuf[0] = 1;
obuf[1] = msg[j].buf[1];/* off-on */
- ret = dw210x_op_rw(d->udev, 0x8a, 0, 0,
+ dw210x_op_rw(d->udev, 0x8a, 0, 0,
obuf, 2, DW210X_WRITE_MSG);
obuf[0] = 3;
obuf[1] = msg[j].buf[0];/* 13v-18v */
- ret = dw210x_op_rw(d->udev, 0x8a, 0, 0,
+ dw210x_op_rw(d->udev, 0x8a, 0, 0,
obuf, 2, DW210X_WRITE_MSG);
break;
}
@@ -532,7 +528,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
obuf[0] = 5;
obuf[1] = msg[j].buf[0];
- ret = dw210x_op_rw(d->udev, 0x8a, 0, 0,
+ dw210x_op_rw(d->udev, 0x8a, 0, 0,
obuf, 2, DW210X_WRITE_MSG);
break;
}
@@ -545,7 +541,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
if (msg[j].flags == I2C_M_RD) {
/* read registers */
u8 ibuf[msg[j].len];
- ret = dw210x_op_rw(d->udev, 0x91, 0, 0,
+ dw210x_op_rw(d->udev, 0x91, 0, 0,
ibuf, msg[j].len,
DW210X_READ_MSG);
memcpy(msg[j].buf, ibuf, msg[j].len);
@@ -563,7 +559,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
do {
memcpy(obuf + 3, msg[j].buf + i,
(len > 16 ? 16 : len));
- ret = dw210x_op_rw(d->udev, 0x80, 0, 0,
+ dw210x_op_rw(d->udev, 0x80, 0, 0,
obuf, (len > 16 ? 16 : len) + 3,
DW210X_WRITE_MSG);
i += 16;
@@ -575,7 +571,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
obuf[0] = msg[j + 1].len;
obuf[1] = (msg[j].addr << 1);
memcpy(obuf + 2, msg[j].buf, msg[j].len);
- ret = dw210x_op_rw(d->udev,
+ dw210x_op_rw(d->udev,
udev->descriptor.idProduct ==
0x7500 ? 0x92 : 0x90, 0, 0,
obuf, msg[j].len + 2,
@@ -587,7 +583,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
obuf[0] = msg[j].len + 1;
obuf[1] = (msg[j].addr << 1);
memcpy(obuf + 2, msg[j].buf, msg[j].len);
- ret = dw210x_op_rw(d->udev, 0x80, 0, 0,
+ dw210x_op_rw(d->udev, 0x80, 0, 0,
obuf, msg[j].len + 2,
DW210X_WRITE_MSG);
break;
diff --git a/drivers/media/dvb/dvb-usb/it913x.c b/drivers/media/dvb/dvb-usb/it913x.c
index 482d249ca7f3..6244fe9d1a3a 100644
--- a/drivers/media/dvb/dvb-usb/it913x.c
+++ b/drivers/media/dvb/dvb-usb/it913x.c
@@ -81,7 +81,7 @@ static int it913x_bulk_write(struct usb_device *dev,
for (i = 0; i < IT913X_RETRY; i++) {
ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe),
snd, len , &actual_l, IT913X_SND_TIMEOUT);
- if (ret == 0 || ret != -EBUSY || ret != -ETIMEDOUT)
+ if (ret != -EBUSY && ret != -ETIMEDOUT)
break;
}
@@ -99,7 +99,7 @@ static int it913x_bulk_read(struct usb_device *dev,
for (i = 0; i < IT913X_RETRY; i++) {
ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe),
rev, len , &actual_l, IT913X_RCV_TIMEOUT);
- if (ret == 0 || ret != -EBUSY || ret != -ETIMEDOUT)
+ if (ret != -EBUSY && ret != -ETIMEDOUT)
break;
}
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c
index 5dde06d066ff..25d1031460f8 100644
--- a/drivers/media/dvb/dvb-usb/lmedm04.c
+++ b/drivers/media/dvb/dvb-usb/lmedm04.c
@@ -373,7 +373,7 @@ static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
struct lme2510_state *st = adap->dev->priv;
static u8 clear_pid_reg[] = LME_ALL_PIDS;
static u8 rbuf[1];
- int ret;
+ int ret = 0;
deb_info(1, "PID Clearing Filter");
@@ -1205,14 +1205,13 @@ static int lme2510_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(intf);
- int ret = 0;
usb_reset_configuration(udev);
usb_set_interface(udev, intf->cur_altsetting->desc.bInterfaceNumber, 1);
if (udev->speed != USB_SPEED_HIGH) {
- ret = usb_reset_device(udev);
+ usb_reset_device(udev);
info("DEV Failed to connect in HIGH SPEED mode");
return -ENODEV;
}
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c
index 72db6eef4b9c..74da5bb1ce99 100644
--- a/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c
+++ b/drivers/media/dvb/dvb-usb/mxl111sf-tuner.c
@@ -284,6 +284,7 @@ static int mxl111sf_tuner_set_params(struct dvb_frontend *fe)
switch (delsys) {
case SYS_ATSC:
+ case SYS_ATSCMH:
bw = 0; /* ATSC */
break;
case SYS_DVBC_ANNEX_B:
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.c b/drivers/media/dvb/dvb-usb/mxl111sf.c
index 81305de2fea5..cd842798f5af 100644
--- a/drivers/media/dvb/dvb-usb/mxl111sf.c
+++ b/drivers/media/dvb/dvb-usb/mxl111sf.c
@@ -21,6 +21,7 @@
#include "mxl111sf-tuner.h"
#include "lgdt3305.h"
+#include "lg2160.h"
int dvb_usb_mxl111sf_debug;
module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644);
@@ -31,6 +32,10 @@ int dvb_usb_mxl111sf_isoc;
module_param_named(isoc, dvb_usb_mxl111sf_isoc, int, 0644);
MODULE_PARM_DESC(isoc, "enable usb isoc xfer (0=bulk, 1=isoc).");
+int dvb_usb_mxl111sf_spi;
+module_param_named(spi, dvb_usb_mxl111sf_spi, int, 0644);
+MODULE_PARM_DESC(spi, "use spi rather than tp for data xfer (0=tp, 1=spi).");
+
#define ANT_PATH_AUTO 0
#define ANT_PATH_EXTERNAL 1
#define ANT_PATH_INTERNAL 2
@@ -340,7 +345,6 @@ static int mxl111sf_ep6_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
struct mxl111sf_state *state = d->priv;
struct mxl111sf_adap_state *adap_state = adap->fe_adap[adap->active_fe].priv;
int ret = 0;
- u8 tmp;
deb_info("%s(%d)\n", __func__, onoff);
@@ -361,6 +365,33 @@ static int mxl111sf_ep6_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
return ret;
}
+static int mxl111sf_ep5_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+ struct dvb_usb_device *d = adap->dev;
+ struct mxl111sf_state *state = d->priv;
+ int ret = 0;
+
+ deb_info("%s(%d)\n", __func__, onoff);
+
+ if (onoff) {
+ ret = mxl111sf_enable_usb_output(state);
+ mxl_fail(ret);
+
+ ret = mxl111sf_init_i2s_port(state, 200);
+ mxl_fail(ret);
+ ret = mxl111sf_config_i2s(state, 0, 15);
+ mxl_fail(ret);
+ } else {
+ ret = mxl111sf_disable_i2s_port(state);
+ mxl_fail(ret);
+ }
+ if (state->chip_rev > MXL111SF_V6)
+ ret = mxl111sf_config_spi(state, onoff);
+ mxl_fail(ret);
+
+ return ret;
+}
+
static int mxl111sf_ep4_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
struct dvb_usb_device *d = adap->dev;
@@ -453,6 +484,255 @@ fail:
return ret;
}
+static struct lg2160_config hauppauge_lg2160_config = {
+ .lg_chip = LG2160,
+ .i2c_addr = 0x1c >> 1,
+ .deny_i2c_rptr = 1,
+ .spectral_inversion = 0,
+ .if_khz = 6000,
+};
+
+static int mxl111sf_lg2160_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ struct dvb_usb_device *d = adap->dev;
+ struct mxl111sf_state *state = d->priv;
+ int fe_id = adap->num_frontends_initialized;
+ struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
+ int ret;
+
+ deb_adv("%s()\n", __func__);
+
+ /* save a pointer to the dvb_usb_device in device state */
+ state->d = d;
+ adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
+ state->alt_mode = adap_state->alt_mode;
+
+ if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
+ err("set interface failed");
+
+ state->gpio_mode = MXL111SF_GPIO_MOD_MH;
+ adap_state->gpio_mode = state->gpio_mode;
+ adap_state->device_mode = MXL_TUNER_MODE;
+ adap_state->ep6_clockphase = 1;
+
+ ret = mxl1x1sf_soft_reset(state);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl111sf_init_tuner_demod(state);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl111sf_enable_usb_output(state);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl1x1sf_top_master_ctrl(state, 1);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl111sf_init_port_expander(state);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = get_chip_info(state);
+ if (mxl_fail(ret))
+ goto fail;
+
+ adap->fe_adap[fe_id].fe = dvb_attach(lg2160_attach,
+ &hauppauge_lg2160_config,
+ &adap->dev->i2c_adap);
+ if (adap->fe_adap[fe_id].fe) {
+ adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
+ adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
+ adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
+ adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
+ return 0;
+ }
+ ret = -EIO;
+fail:
+ return ret;
+}
+
+static struct lg2160_config hauppauge_lg2161_1019_config = {
+ .lg_chip = LG2161_1019,
+ .i2c_addr = 0x1c >> 1,
+ .deny_i2c_rptr = 1,
+ .spectral_inversion = 0,
+ .if_khz = 6000,
+ .output_if = 2, /* LG2161_OIF_SPI_MAS */
+};
+
+static struct lg2160_config hauppauge_lg2161_1040_config = {
+ .lg_chip = LG2161_1040,
+ .i2c_addr = 0x1c >> 1,
+ .deny_i2c_rptr = 1,
+ .spectral_inversion = 0,
+ .if_khz = 6000,
+ .output_if = 4, /* LG2161_OIF_SPI_MAS */
+};
+
+static int mxl111sf_lg2161_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ struct dvb_usb_device *d = adap->dev;
+ struct mxl111sf_state *state = d->priv;
+ int fe_id = adap->num_frontends_initialized;
+ struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
+ int ret;
+
+ deb_adv("%s()\n", __func__);
+
+ /* save a pointer to the dvb_usb_device in device state */
+ state->d = d;
+ adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
+ state->alt_mode = adap_state->alt_mode;
+
+ if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
+ err("set interface failed");
+
+ state->gpio_mode = MXL111SF_GPIO_MOD_MH;
+ adap_state->gpio_mode = state->gpio_mode;
+ adap_state->device_mode = MXL_TUNER_MODE;
+ adap_state->ep6_clockphase = 1;
+
+ ret = mxl1x1sf_soft_reset(state);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl111sf_init_tuner_demod(state);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl111sf_enable_usb_output(state);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl1x1sf_top_master_ctrl(state, 1);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl111sf_init_port_expander(state);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = get_chip_info(state);
+ if (mxl_fail(ret))
+ goto fail;
+
+ adap->fe_adap[fe_id].fe = dvb_attach(lg2160_attach,
+ (MXL111SF_V8_200 == state->chip_rev) ?
+ &hauppauge_lg2161_1040_config :
+ &hauppauge_lg2161_1019_config,
+ &adap->dev->i2c_adap);
+ if (adap->fe_adap[fe_id].fe) {
+ adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
+ adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
+ adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
+ adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
+ return 0;
+ }
+ ret = -EIO;
+fail:
+ return ret;
+}
+
+static struct lg2160_config hauppauge_lg2161_1019_ep6_config = {
+ .lg_chip = LG2161_1019,
+ .i2c_addr = 0x1c >> 1,
+ .deny_i2c_rptr = 1,
+ .spectral_inversion = 0,
+ .if_khz = 6000,
+ .output_if = 1, /* LG2161_OIF_SERIAL_TS */
+};
+
+static struct lg2160_config hauppauge_lg2161_1040_ep6_config = {
+ .lg_chip = LG2161_1040,
+ .i2c_addr = 0x1c >> 1,
+ .deny_i2c_rptr = 1,
+ .spectral_inversion = 0,
+ .if_khz = 6000,
+ .output_if = 7, /* LG2161_OIF_SERIAL_TS */
+};
+
+static int mxl111sf_lg2161_ep6_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ struct dvb_usb_device *d = adap->dev;
+ struct mxl111sf_state *state = d->priv;
+ int fe_id = adap->num_frontends_initialized;
+ struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
+ int ret;
+
+ deb_adv("%s()\n", __func__);
+
+ /* save a pointer to the dvb_usb_device in device state */
+ state->d = d;
+ adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
+ state->alt_mode = adap_state->alt_mode;
+
+ if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
+ err("set interface failed");
+
+ state->gpio_mode = MXL111SF_GPIO_MOD_MH;
+ adap_state->gpio_mode = state->gpio_mode;
+ adap_state->device_mode = MXL_TUNER_MODE;
+ adap_state->ep6_clockphase = 0;
+
+ ret = mxl1x1sf_soft_reset(state);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl111sf_init_tuner_demod(state);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl111sf_enable_usb_output(state);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl1x1sf_top_master_ctrl(state, 1);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = mxl111sf_init_port_expander(state);
+ if (mxl_fail(ret))
+ goto fail;
+ ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
+ if (mxl_fail(ret))
+ goto fail;
+
+ ret = get_chip_info(state);
+ if (mxl_fail(ret))
+ goto fail;
+
+ adap->fe_adap[fe_id].fe = dvb_attach(lg2160_attach,
+ (MXL111SF_V8_200 == state->chip_rev) ?
+ &hauppauge_lg2161_1040_ep6_config :
+ &hauppauge_lg2161_1019_ep6_config,
+ &adap->dev->i2c_adap);
+ if (adap->fe_adap[fe_id].fe) {
+ adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
+ adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
+ adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
+ adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
+ return 0;
+ }
+ ret = -EIO;
+fail:
+ return ret;
+}
+
static struct mxl111sf_demod_config mxl_demod_config = {
.read_reg = mxl111sf_read_reg,
.write_reg = mxl111sf_write_reg,
@@ -650,6 +930,18 @@ static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties;
static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties;
static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties;
static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties;
+static struct dvb_usb_device_properties mxl111sf_atsc_mh_bulk_properties;
+static struct dvb_usb_device_properties mxl111sf_atsc_mh_isoc_properties;
+static struct dvb_usb_device_properties mxl111sf_mh_bulk_properties;
+static struct dvb_usb_device_properties mxl111sf_mh_isoc_properties;
+static struct dvb_usb_device_properties mxl111sf_mercury_spi_bulk_properties;
+static struct dvb_usb_device_properties mxl111sf_mercury_spi_isoc_properties;
+static struct dvb_usb_device_properties mxl111sf_mercury_tp_bulk_properties;
+static struct dvb_usb_device_properties mxl111sf_mercury_tp_isoc_properties;
+static struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_bulk_properties;
+static struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_isoc_properties;
+static struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_bulk_properties;
+static struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_isoc_properties;
static int mxl111sf_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -664,12 +956,50 @@ static int mxl111sf_probe(struct usb_interface *intf,
THIS_MODULE, &d, adapter_nr) ||
0 == dvb_usb_device_init(intf,
&mxl111sf_atsc_isoc_properties,
+ THIS_MODULE, &d, adapter_nr) ||
+ 0 == dvb_usb_device_init(intf,
+ &mxl111sf_atsc_mh_isoc_properties,
+ THIS_MODULE, &d, adapter_nr) ||
+ 0 == dvb_usb_device_init(intf,
+ &mxl111sf_mh_isoc_properties,
+ THIS_MODULE, &d, adapter_nr) ||
+ ((dvb_usb_mxl111sf_spi) &&
+ (0 == dvb_usb_device_init(intf,
+ &mxl111sf_mercury_spi_isoc_properties,
+ THIS_MODULE, &d, adapter_nr) ||
+ 0 == dvb_usb_device_init(intf,
+ &mxl111sf_mercury_mh_spi_isoc_properties,
+ THIS_MODULE, &d, adapter_nr))) ||
+ 0 == dvb_usb_device_init(intf,
+ &mxl111sf_mercury_tp_isoc_properties,
+ THIS_MODULE, &d, adapter_nr) ||
+ 0 == dvb_usb_device_init(intf,
+ &mxl111sf_mercury_mh_tp_isoc_properties,
THIS_MODULE, &d, adapter_nr))) ||
0 == dvb_usb_device_init(intf,
&mxl111sf_dvbt_bulk_properties,
THIS_MODULE, &d, adapter_nr) ||
0 == dvb_usb_device_init(intf,
&mxl111sf_atsc_bulk_properties,
+ THIS_MODULE, &d, adapter_nr) ||
+ 0 == dvb_usb_device_init(intf,
+ &mxl111sf_atsc_mh_bulk_properties,
+ THIS_MODULE, &d, adapter_nr) ||
+ 0 == dvb_usb_device_init(intf,
+ &mxl111sf_mh_bulk_properties,
+ THIS_MODULE, &d, adapter_nr) ||
+ ((dvb_usb_mxl111sf_spi) &&
+ (0 == dvb_usb_device_init(intf,
+ &mxl111sf_mercury_spi_bulk_properties,
+ THIS_MODULE, &d, adapter_nr) ||
+ 0 == dvb_usb_device_init(intf,
+ &mxl111sf_mercury_mh_spi_bulk_properties,
+ THIS_MODULE, &d, adapter_nr))) ||
+ 0 == dvb_usb_device_init(intf,
+ &mxl111sf_mercury_tp_bulk_properties,
+ THIS_MODULE, &d, adapter_nr) ||
+ 0 == dvb_usb_device_init(intf,
+ &mxl111sf_mercury_mh_tp_bulk_properties,
THIS_MODULE, &d, adapter_nr) || 0) {
struct mxl111sf_state *state = d->priv;
@@ -787,6 +1117,36 @@ MODULE_DEVICE_TABLE(usb, mxl111sf_table);
} \
}
+#define MXL111SF_EP5_BULK_STREAMING_CONFIG \
+ .size_of_priv = sizeof(struct mxl111sf_adap_state), \
+ .streaming_ctrl = mxl111sf_ep5_streaming_ctrl, \
+ .stream = { \
+ .type = USB_BULK, \
+ .count = 5, \
+ .endpoint = 0x05, \
+ .u = { \
+ .bulk = { \
+ .buffersize = 8192, \
+ } \
+ } \
+ }
+
+#define MXL111SF_EP5_ISOC_STREAMING_CONFIG \
+ .size_of_priv = sizeof(struct mxl111sf_adap_state), \
+ .streaming_ctrl = mxl111sf_ep5_streaming_ctrl, \
+ .stream = { \
+ .type = USB_ISOC, \
+ .count = 5, \
+ .endpoint = 0x05, \
+ .u = { \
+ .isoc = { \
+ .framesperurb = 96, \
+ .framesize = 200, \
+ .interval = 1, \
+ } \
+ } \
+ }
+
#define MXL111SF_EP6_BULK_STREAMING_CONFIG \
.size_of_priv = sizeof(struct mxl111sf_adap_state), \
.streaming_ctrl = mxl111sf_ep6_streaming_ctrl, \
@@ -848,7 +1208,7 @@ static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties = {
} },
},
},
- .num_device_descs = 4,
+ .num_device_descs = 3,
.devices = {
{ "Hauppauge 126xxx DVBT (bulk)",
{ NULL },
@@ -866,11 +1226,6 @@ static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties = {
&mxl111sf_table[24], &mxl111sf_table[26],
NULL },
},
- { "Hauppauge 126xxx (tp-bulk)",
- { NULL },
- { &mxl111sf_table[28], &mxl111sf_table[30],
- NULL },
- },
}
};
@@ -890,7 +1245,7 @@ static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties = {
} },
},
},
- .num_device_descs = 4,
+ .num_device_descs = 3,
.devices = {
{ "Hauppauge 126xxx DVBT (isoc)",
{ NULL },
@@ -908,11 +1263,6 @@ static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties = {
&mxl111sf_table[24], &mxl111sf_table[26],
NULL },
},
- { "Hauppauge 126xxx (tp-isoc)",
- { NULL },
- { &mxl111sf_table[28], &mxl111sf_table[30],
- NULL },
- },
}
};
@@ -923,33 +1273,159 @@ static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = {
.adapter = {
{
.fe_ioctl_override = mxl111sf_fe_ioctl_override,
- .num_frontends = 2,
+ .num_frontends = 1,
.fe = {{
.frontend_attach = mxl111sf_lgdt3305_frontend_attach,
.tuner_attach = mxl111sf_attach_tuner,
MXL111SF_EP6_BULK_STREAMING_CONFIG,
+ }},
},
+ },
+ .num_device_descs = 2,
+ .devices = {
+ { "Hauppauge 126xxx ATSC (bulk)",
+ { NULL },
+ { &mxl111sf_table[1], &mxl111sf_table[5],
+ NULL },
+ },
+ { "Hauppauge 117xxx ATSC (bulk)",
+ { NULL },
+ { &mxl111sf_table[12],
+ NULL },
+ },
+ }
+};
+
+static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = {
+ MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 1,
+ .adapter = {
{
- .frontend_attach = mxl111sf_attach_demod,
+ .fe_ioctl_override = mxl111sf_fe_ioctl_override,
+ .num_frontends = 1,
+ .fe = {{
+ .frontend_attach = mxl111sf_lgdt3305_frontend_attach,
.tuner_attach = mxl111sf_attach_tuner,
- MXL111SF_EP4_BULK_STREAMING_CONFIG,
+ MXL111SF_EP6_ISOC_STREAMING_CONFIG,
}},
},
},
- .num_device_descs = 6,
+ .num_device_descs = 2,
.devices = {
- { "Hauppauge 126xxx ATSC (bulk)",
+ { "Hauppauge 126xxx ATSC (isoc)",
{ NULL },
{ &mxl111sf_table[1], &mxl111sf_table[5],
NULL },
},
- { "Hauppauge 117xxx ATSC (bulk)",
+ { "Hauppauge 117xxx ATSC (isoc)",
{ NULL },
{ &mxl111sf_table[12],
NULL },
},
+ }
+};
+
+static struct dvb_usb_device_properties mxl111sf_mh_bulk_properties = {
+ MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .fe_ioctl_override = mxl111sf_fe_ioctl_override,
+ .num_frontends = 1,
+ .fe = {{
+ .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+ .frontend_attach = mxl111sf_lg2160_frontend_attach,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP5_BULK_STREAMING_CONFIG,
+ }},
+ },
+ },
+ .num_device_descs = 2,
+ .devices = {
+ { "HCW 126xxx (bulk)",
+ { NULL },
+ { &mxl111sf_table[2], &mxl111sf_table[6],
+ NULL },
+ },
+ { "HCW 117xxx (bulk)",
+ { NULL },
+ { &mxl111sf_table[13],
+ NULL },
+ },
+ }
+};
+
+static struct dvb_usb_device_properties mxl111sf_mh_isoc_properties = {
+ MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .fe_ioctl_override = mxl111sf_fe_ioctl_override,
+ .num_frontends = 1,
+ .fe = {{
+ .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+ .frontend_attach = mxl111sf_lg2160_frontend_attach,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP5_ISOC_STREAMING_CONFIG,
+ }},
+ },
+ },
+ .num_device_descs = 2,
+ .devices = {
+ { "HCW 126xxx (isoc)",
+ { NULL },
+ { &mxl111sf_table[2], &mxl111sf_table[6],
+ NULL },
+ },
+ { "HCW 117xxx (isoc)",
+ { NULL },
+ { &mxl111sf_table[13],
+ NULL },
+ },
+ }
+};
+
+static struct dvb_usb_device_properties mxl111sf_atsc_mh_bulk_properties = {
+ MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .fe_ioctl_override = mxl111sf_fe_ioctl_override,
+ .num_frontends = 3,
+ .fe = {{
+ .frontend_attach = mxl111sf_lgdt3305_frontend_attach,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP6_BULK_STREAMING_CONFIG,
+ },
+ {
+ .frontend_attach = mxl111sf_attach_demod,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP4_BULK_STREAMING_CONFIG,
+ },
+ {
+ .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+ .frontend_attach = mxl111sf_lg2160_frontend_attach,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP5_BULK_STREAMING_CONFIG,
+ }},
+ },
+ },
+ .num_device_descs = 2,
+ .devices = {
{ "Hauppauge 126xxx ATSC+ (bulk)",
{ NULL },
{ &mxl111sf_table[0], &mxl111sf_table[3],
@@ -963,13 +1439,96 @@ static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = {
&mxl111sf_table[32], &mxl111sf_table[33],
NULL },
},
- { "Hauppauge Mercury (tp-bulk)",
+ }
+};
+
+static struct dvb_usb_device_properties mxl111sf_atsc_mh_isoc_properties = {
+ MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .fe_ioctl_override = mxl111sf_fe_ioctl_override,
+ .num_frontends = 3,
+ .fe = {{
+ .frontend_attach = mxl111sf_lgdt3305_frontend_attach,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP6_ISOC_STREAMING_CONFIG,
+ },
+ {
+ .frontend_attach = mxl111sf_attach_demod,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP4_ISOC_STREAMING_CONFIG,
+ },
+ {
+ .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+ .frontend_attach = mxl111sf_lg2160_frontend_attach,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP5_ISOC_STREAMING_CONFIG,
+ }},
+ },
+ },
+ .num_device_descs = 2,
+ .devices = {
+ { "Hauppauge 126xxx ATSC+ (isoc)",
+ { NULL },
+ { &mxl111sf_table[0], &mxl111sf_table[3],
+ &mxl111sf_table[7], &mxl111sf_table[9],
+ &mxl111sf_table[10], NULL },
+ },
+ { "Hauppauge 117xxx ATSC+ (isoc)",
+ { NULL },
+ { &mxl111sf_table[11], &mxl111sf_table[14],
+ &mxl111sf_table[16], &mxl111sf_table[17],
+ &mxl111sf_table[32], &mxl111sf_table[33],
+ NULL },
+ },
+ }
+};
+
+static struct dvb_usb_device_properties mxl111sf_mercury_spi_bulk_properties = {
+ MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .fe_ioctl_override = mxl111sf_fe_ioctl_override,
+ .num_frontends = 3,
+ .fe = {{
+ .frontend_attach = mxl111sf_lgdt3305_frontend_attach,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP6_BULK_STREAMING_CONFIG,
+ },
+ {
+ .frontend_attach = mxl111sf_attach_demod,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP4_BULK_STREAMING_CONFIG,
+ },
+ {
+ .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+ .frontend_attach = mxl111sf_lg2161_frontend_attach,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP5_BULK_STREAMING_CONFIG,
+ }},
+ },
+ },
+ .num_device_descs = 2,
+ .devices = {
+ { "Hauppauge Mercury (spi-bulk)",
{ NULL },
{ &mxl111sf_table[19], &mxl111sf_table[21],
&mxl111sf_table[23], &mxl111sf_table[25],
- &mxl111sf_table[27], NULL },
+ NULL },
},
- { "Hauppauge WinTV-Aero-M",
+ { "Hauppauge WinTV-Aero-M (spi-bulk)",
{ NULL },
{ &mxl111sf_table[29], &mxl111sf_table[31],
NULL },
@@ -977,14 +1536,14 @@ static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = {
}
};
-static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = {
+static struct dvb_usb_device_properties mxl111sf_mercury_spi_isoc_properties = {
MXL111SF_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
.adapter = {
{
.fe_ioctl_override = mxl111sf_fe_ioctl_override,
- .num_frontends = 2,
+ .num_frontends = 3,
.fe = {{
.frontend_attach = mxl111sf_lgdt3305_frontend_attach,
.tuner_attach = mxl111sf_attach_tuner,
@@ -996,34 +1555,111 @@ static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = {
.tuner_attach = mxl111sf_attach_tuner,
MXL111SF_EP4_ISOC_STREAMING_CONFIG,
+ },
+ {
+ .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+ .frontend_attach = mxl111sf_lg2161_frontend_attach,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP5_ISOC_STREAMING_CONFIG,
}},
},
},
- .num_device_descs = 6,
+ .num_device_descs = 2,
.devices = {
- { "Hauppauge 126xxx ATSC (isoc)",
+ { "Hauppauge Mercury (spi-isoc)",
{ NULL },
- { &mxl111sf_table[1], &mxl111sf_table[5],
+ { &mxl111sf_table[19], &mxl111sf_table[21],
+ &mxl111sf_table[23], &mxl111sf_table[25],
NULL },
},
- { "Hauppauge 117xxx ATSC (isoc)",
+ { "Hauppauge WinTV-Aero-M (spi-isoc)",
{ NULL },
- { &mxl111sf_table[12],
+ { &mxl111sf_table[29], &mxl111sf_table[31],
NULL },
},
- { "Hauppauge 126xxx ATSC+ (isoc)",
+ }
+};
+
+static struct dvb_usb_device_properties mxl111sf_mercury_tp_bulk_properties = {
+ MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .fe_ioctl_override = mxl111sf_fe_ioctl_override,
+ .num_frontends = 3,
+ .fe = {{
+ .frontend_attach = mxl111sf_lgdt3305_frontend_attach,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP6_BULK_STREAMING_CONFIG,
+ },
+ {
+ .frontend_attach = mxl111sf_attach_demod,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP4_BULK_STREAMING_CONFIG,
+ },
+ {
+ .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+ .frontend_attach = mxl111sf_lg2161_ep6_frontend_attach,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP6_BULK_STREAMING_CONFIG,
+ }},
+ },
+ },
+ .num_device_descs = 2,
+ .devices = {
+ { "Hauppauge Mercury (tp-bulk)",
{ NULL },
- { &mxl111sf_table[0], &mxl111sf_table[3],
- &mxl111sf_table[7], &mxl111sf_table[9],
- &mxl111sf_table[10], NULL },
+ { &mxl111sf_table[19], &mxl111sf_table[21],
+ &mxl111sf_table[23], &mxl111sf_table[25],
+ &mxl111sf_table[27], NULL },
},
- { "Hauppauge 117xxx ATSC+ (isoc)",
+ { "Hauppauge WinTV-Aero-M",
{ NULL },
- { &mxl111sf_table[11], &mxl111sf_table[14],
- &mxl111sf_table[16], &mxl111sf_table[17],
- &mxl111sf_table[32], &mxl111sf_table[33],
+ { &mxl111sf_table[29], &mxl111sf_table[31],
NULL },
},
+ }
+};
+
+static struct dvb_usb_device_properties mxl111sf_mercury_tp_isoc_properties = {
+ MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .fe_ioctl_override = mxl111sf_fe_ioctl_override,
+ .num_frontends = 3,
+ .fe = {{
+ .frontend_attach = mxl111sf_lgdt3305_frontend_attach,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP6_ISOC_STREAMING_CONFIG,
+ },
+ {
+ .frontend_attach = mxl111sf_attach_demod,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP4_ISOC_STREAMING_CONFIG,
+ },
+ {
+ .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+ .frontend_attach = mxl111sf_lg2161_ep6_frontend_attach,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP6_ISOC_STREAMING_CONFIG,
+ }},
+ },
+ },
+ .num_device_descs = 2,
+ .devices = {
{ "Hauppauge Mercury (tp-isoc)",
{ NULL },
{ &mxl111sf_table[19], &mxl111sf_table[21],
@@ -1038,6 +1674,146 @@ static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = {
}
};
+static
+struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_bulk_properties = {
+ MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .fe_ioctl_override = mxl111sf_fe_ioctl_override,
+ .num_frontends = 2,
+ .fe = {{
+ .frontend_attach = mxl111sf_attach_demod,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP4_BULK_STREAMING_CONFIG,
+ },
+ {
+ .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+ .frontend_attach = mxl111sf_lg2161_ep6_frontend_attach,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP6_BULK_STREAMING_CONFIG,
+ }},
+ },
+ },
+ .num_device_descs = 1,
+ .devices = {
+ { "Hauppauge 126xxx (tp-bulk)",
+ { NULL },
+ { &mxl111sf_table[28], &mxl111sf_table[30],
+ NULL },
+ },
+ }
+};
+
+static
+struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_isoc_properties = {
+ MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .fe_ioctl_override = mxl111sf_fe_ioctl_override,
+ .num_frontends = 2,
+ .fe = {{
+ .frontend_attach = mxl111sf_attach_demod,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP4_ISOC_STREAMING_CONFIG,
+ },
+ {
+ .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+ .frontend_attach = mxl111sf_lg2161_ep6_frontend_attach,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP6_ISOC_STREAMING_CONFIG,
+ }},
+ },
+ },
+ .num_device_descs = 1,
+ .devices = {
+ { "Hauppauge 126xxx (tp-isoc)",
+ { NULL },
+ { &mxl111sf_table[28], &mxl111sf_table[30],
+ NULL },
+ },
+ }
+};
+
+static
+struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_bulk_properties = {
+ MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .fe_ioctl_override = mxl111sf_fe_ioctl_override,
+ .num_frontends = 2,
+ .fe = {{
+ .frontend_attach = mxl111sf_attach_demod,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP4_BULK_STREAMING_CONFIG,
+ },
+ {
+ .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+ .frontend_attach = mxl111sf_lg2161_frontend_attach,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP5_BULK_STREAMING_CONFIG,
+ }},
+ },
+ },
+ .num_device_descs = 1,
+ .devices = {
+ { "Hauppauge 126xxx (spi-bulk)",
+ { NULL },
+ { &mxl111sf_table[28], &mxl111sf_table[30],
+ NULL },
+ },
+ }
+};
+
+static
+struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_isoc_properties = {
+ MXL111SF_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .fe_ioctl_override = mxl111sf_fe_ioctl_override,
+ .num_frontends = 2,
+ .fe = {{
+ .frontend_attach = mxl111sf_attach_demod,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP4_ISOC_STREAMING_CONFIG,
+ },
+ {
+ .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
+
+ .frontend_attach = mxl111sf_lg2161_frontend_attach,
+ .tuner_attach = mxl111sf_attach_tuner,
+
+ MXL111SF_EP5_ISOC_STREAMING_CONFIG,
+ }},
+ },
+ },
+ .num_device_descs = 1,
+ .devices = {
+ { "Hauppauge 126xxx (spi-isoc)",
+ { NULL },
+ { &mxl111sf_table[28], &mxl111sf_table[30],
+ NULL },
+ },
+ }
+};
+
static struct usb_driver mxl111sf_driver = {
.name = "dvb_usb_mxl111sf",
.probe = mxl111sf_probe,
diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.c b/drivers/media/dvb/dvb-usb/rtl28xxu.c
index 8f4736a10fc8..41e1f5537f44 100644
--- a/drivers/media/dvb/dvb-usb/rtl28xxu.c
+++ b/drivers/media/dvb/dvb-usb/rtl28xxu.c
@@ -322,6 +322,9 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
* since there is some demod params needed to set according to tuner.
*/
+ /* demod needs some time to wake up */
+ msleep(20);
+
/* open demod I2C gate */
ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate);
if (ret)
@@ -909,6 +912,8 @@ static int rtl28xxu_probe(struct usb_interface *intf,
int ret, i;
int properties_count = ARRAY_SIZE(rtl28xxu_properties);
struct dvb_usb_device *d;
+ struct usb_device *udev;
+ bool found;
deb_info("%s: interface=%d\n", __func__,
intf->cur_altsetting->desc.bInterfaceNumber);
@@ -916,6 +921,29 @@ static int rtl28xxu_probe(struct usb_interface *intf,
if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
return 0;
+ /* Dynamic USB ID support. Replaces first device ID with current one .*/
+ udev = interface_to_usbdev(intf);
+
+ for (i = 0, found = false; i < ARRAY_SIZE(rtl28xxu_table) - 1; i++) {
+ if (rtl28xxu_table[i].idVendor ==
+ le16_to_cpu(udev->descriptor.idVendor) &&
+ rtl28xxu_table[i].idProduct ==
+ le16_to_cpu(udev->descriptor.idProduct)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ deb_info("%s: using dynamic ID %04x:%04x\n", __func__,
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct));
+ rtl28xxu_properties[0].devices[0].warm_ids[0]->idVendor =
+ le16_to_cpu(udev->descriptor.idVendor);
+ rtl28xxu_properties[0].devices[0].warm_ids[0]->idProduct =
+ le16_to_cpu(udev->descriptor.idProduct);
+ }
+
for (i = 0; i < properties_count; i++) {
ret = dvb_usb_device_init(intf, &rtl28xxu_properties[i],
THIS_MODULE, &d, adapter_nr);
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 21246707fbfb..b98ebb264e29 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -531,6 +531,14 @@ config DVB_LGDT3305
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
+config DVB_LG2160
+ tristate "LG Electronics LG216x based"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ An ATSC/MH demodulator module. Say Y when you want
+ to support this frontend.
+
config DVB_S5H1409
tristate "Samsung S5H1409 based"
depends on DVB_CORE && I2C
@@ -540,12 +548,26 @@ config DVB_S5H1409
to support this frontend.
config DVB_AU8522
- tristate "Auvitek AU8522 based"
- depends on DVB_CORE && I2C && VIDEO_V4L2
+ depends on I2C
+ tristate
+
+config DVB_AU8522_DTV
+ tristate "Auvitek AU8522 based DTV demod"
+ depends on DVB_CORE && I2C
+ select DVB_AU8522
default m if DVB_FE_CUSTOMISE
help
- An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
- to support this frontend.
+ An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when
+ you want to enable DTV demodulation support for this frontend.
+
+config DVB_AU8522_V4L
+ tristate "Auvitek AU8522 based ATV demod"
+ depends on VIDEO_V4L2 && I2C
+ select DVB_AU8522
+ default m if DVB_FE_CUSTOMISE
+ help
+ An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when
+ you want to enable ATV demodulation support for this frontend.
config DVB_S5H1411
tristate "Samsung S5H1411 based"
@@ -713,6 +735,11 @@ config DVB_M88RS2000
A DVB-S tuner module.
Say Y when you want to support this frontend.
+config DVB_AF9033
+ tristate "Afatech AF9033 DVB-T demodulator"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+
comment "Tools to develop new frontends"
config DVB_DUMMY_FE
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 86fa808bf589..cd1ac2fd5774 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -7,7 +7,6 @@ ccflags-y += -I$(srctree)/drivers/media/common/tuners/
stb0899-objs = stb0899_drv.o stb0899_algo.o
stv0900-objs = stv0900_core.o stv0900_sw.o
-au8522-objs = au8522_dig.o au8522_decoder.o
drxd-objs = drxd_firm.o drxd_hard.o
cxd2820r-objs = cxd2820r_core.o cxd2820r_c.o cxd2820r_t.o cxd2820r_t2.o
drxk-objs := drxk_hard.o
@@ -50,6 +49,7 @@ obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
+obj-$(CONFIG_DVB_LG2160) += lg2160.o
obj-$(CONFIG_DVB_CX24123) += cx24123.o
obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
obj-$(CONFIG_DVB_LNBP22) += lnbp22.o
@@ -63,7 +63,9 @@ obj-$(CONFIG_DVB_TUNER_DIB0090) += dib0090.o
obj-$(CONFIG_DVB_TUA6100) += tua6100.o
obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
-obj-$(CONFIG_DVB_AU8522) += au8522.o
+obj-$(CONFIG_DVB_AU8522) += au8522_common.o
+obj-$(CONFIG_DVB_AU8522_DTV) += au8522_dig.o
+obj-$(CONFIG_DVB_AU8522_V4L) += au8522_decoder.o
obj-$(CONFIG_DVB_TDA10048) += tda10048.o
obj-$(CONFIG_DVB_TUNER_CX24113) += cx24113.o
obj-$(CONFIG_DVB_S5H1411) += s5h1411.o
@@ -98,4 +100,5 @@ obj-$(CONFIG_DVB_A8293) += a8293.o
obj-$(CONFIG_DVB_TDA10071) += tda10071.o
obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
+obj-$(CONFIG_DVB_AF9033) += af9033.o
diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c
index 6bcbcf543b38..5bc570d77846 100644
--- a/drivers/media/dvb/frontends/af9013.c
+++ b/drivers/media/dvb/frontends/af9013.c
@@ -514,7 +514,6 @@ err:
static void af9013_statistics_work(struct work_struct *work)
{
- int ret;
struct af9013_state *state = container_of(work,
struct af9013_state, statistics_work.work);
unsigned int next_msec;
@@ -530,27 +529,27 @@ static void af9013_statistics_work(struct work_struct *work)
default:
state->statistics_step = 0;
case 0:
- ret = af9013_statistics_signal_strength(&state->fe);
+ af9013_statistics_signal_strength(&state->fe);
state->statistics_step++;
next_msec = 300;
break;
case 1:
- ret = af9013_statistics_snr_start(&state->fe);
+ af9013_statistics_snr_start(&state->fe);
state->statistics_step++;
next_msec = 200;
break;
case 2:
- ret = af9013_statistics_ber_unc_start(&state->fe);
+ af9013_statistics_ber_unc_start(&state->fe);
state->statistics_step++;
next_msec = 1000;
break;
case 3:
- ret = af9013_statistics_snr_result(&state->fe);
+ af9013_statistics_snr_result(&state->fe);
state->statistics_step++;
next_msec = 400;
break;
case 4:
- ret = af9013_statistics_ber_unc_result(&state->fe);
+ af9013_statistics_ber_unc_result(&state->fe);
state->statistics_step++;
next_msec = 100;
break;
@@ -558,8 +557,6 @@ static void af9013_statistics_work(struct work_struct *work)
schedule_delayed_work(&state->statistics_work,
msecs_to_jiffies(next_msec));
-
- return;
}
static int af9013_get_tune_settings(struct dvb_frontend *fe,
diff --git a/drivers/media/dvb/frontends/af9033.c b/drivers/media/dvb/frontends/af9033.c
new file mode 100644
index 000000000000..a38998286260
--- /dev/null
+++ b/drivers/media/dvb/frontends/af9033.c
@@ -0,0 +1,980 @@
+/*
+ * Afatech AF9033 demodulator driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2012 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "af9033_priv.h"
+
+struct af9033_state {
+ struct i2c_adapter *i2c;
+ struct dvb_frontend fe;
+ struct af9033_config cfg;
+
+ u32 bandwidth_hz;
+ bool ts_mode_parallel;
+ bool ts_mode_serial;
+
+ u32 ber;
+ u32 ucb;
+ unsigned long last_stat_check;
+};
+
+/* write multiple registers */
+static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val,
+ int len)
+{
+ int ret;
+ u8 buf[3 + len];
+ struct i2c_msg msg[1] = {
+ {
+ .addr = state->cfg.i2c_addr,
+ .flags = 0,
+ .len = sizeof(buf),
+ .buf = buf,
+ }
+ };
+
+ buf[0] = (reg >> 16) & 0xff;
+ buf[1] = (reg >> 8) & 0xff;
+ buf[2] = (reg >> 0) & 0xff;
+ memcpy(&buf[3], val, len);
+
+ ret = i2c_transfer(state->i2c, msg, 1);
+ if (ret == 1) {
+ ret = 0;
+ } else {
+ printk(KERN_WARNING "%s: i2c wr failed=%d reg=%06x len=%d\n",
+ __func__, ret, reg, len);
+ ret = -EREMOTEIO;
+ }
+
+ return ret;
+}
+
+/* read multiple registers */
+static int af9033_rd_regs(struct af9033_state *state, u32 reg, u8 *val, int len)
+{
+ int ret;
+ u8 buf[3] = { (reg >> 16) & 0xff, (reg >> 8) & 0xff,
+ (reg >> 0) & 0xff };
+ struct i2c_msg msg[2] = {
+ {
+ .addr = state->cfg.i2c_addr,
+ .flags = 0,
+ .len = sizeof(buf),
+ .buf = buf
+ }, {
+ .addr = state->cfg.i2c_addr,
+ .flags = I2C_M_RD,
+ .len = len,
+ .buf = val
+ }
+ };
+
+ ret = i2c_transfer(state->i2c, msg, 2);
+ if (ret == 2) {
+ ret = 0;
+ } else {
+ printk(KERN_WARNING "%s: i2c rd failed=%d reg=%06x len=%d\n",
+ __func__, ret, reg, len);
+ ret = -EREMOTEIO;
+ }
+
+ return ret;
+}
+
+
+/* write single register */
+static int af9033_wr_reg(struct af9033_state *state, u32 reg, u8 val)
+{
+ return af9033_wr_regs(state, reg, &val, 1);
+}
+
+/* read single register */
+static int af9033_rd_reg(struct af9033_state *state, u32 reg, u8 *val)
+{
+ return af9033_rd_regs(state, reg, val, 1);
+}
+
+/* write single register with mask */
+static int af9033_wr_reg_mask(struct af9033_state *state, u32 reg, u8 val,
+ u8 mask)
+{
+ int ret;
+ u8 tmp;
+
+ /* no need for read if whole reg is written */
+ if (mask != 0xff) {
+ ret = af9033_rd_regs(state, reg, &tmp, 1);
+ if (ret)
+ return ret;
+
+ val &= mask;
+ tmp &= ~mask;
+ val |= tmp;
+ }
+
+ return af9033_wr_regs(state, reg, &val, 1);
+}
+
+/* read single register with mask */
+static int af9033_rd_reg_mask(struct af9033_state *state, u32 reg, u8 *val,
+ u8 mask)
+{
+ int ret, i;
+ u8 tmp;
+
+ ret = af9033_rd_regs(state, reg, &tmp, 1);
+ if (ret)
+ return ret;
+
+ tmp &= mask;
+
+ /* find position of the first bit */
+ for (i = 0; i < 8; i++) {
+ if ((mask >> i) & 0x01)
+ break;
+ }
+ *val = tmp >> i;
+
+ return 0;
+}
+
+static u32 af9033_div(u32 a, u32 b, u32 x)
+{
+ u32 r = 0, c = 0, i;
+
+ pr_debug("%s: a=%d b=%d x=%d\n", __func__, a, b, x);
+
+ if (a > b) {
+ c = a / b;
+ a = a - c * b;
+ }
+
+ for (i = 0; i < x; i++) {
+ if (a >= b) {
+ r += 1;
+ a -= b;
+ }
+ a <<= 1;
+ r <<= 1;
+ }
+ r = (c << (u32)x) + r;
+
+ pr_debug("%s: a=%d b=%d x=%d r=%d r=%x\n", __func__, a, b, x, r, r);
+
+ return r;
+}
+
+static void af9033_release(struct dvb_frontend *fe)
+{
+ struct af9033_state *state = fe->demodulator_priv;
+
+ kfree(state);
+}
+
+static int af9033_init(struct dvb_frontend *fe)
+{
+ struct af9033_state *state = fe->demodulator_priv;
+ int ret, i, len;
+ const struct reg_val *init;
+ u8 buf[4];
+ u32 adc_cw, clock_cw;
+ struct reg_val_mask tab[] = {
+ { 0x80fb24, 0x00, 0x08 },
+ { 0x80004c, 0x00, 0xff },
+ { 0x00f641, state->cfg.tuner, 0xff },
+ { 0x80f5ca, 0x01, 0x01 },
+ { 0x80f715, 0x01, 0x01 },
+ { 0x00f41f, 0x04, 0x04 },
+ { 0x00f41a, 0x01, 0x01 },
+ { 0x80f731, 0x00, 0x01 },
+ { 0x00d91e, 0x00, 0x01 },
+ { 0x00d919, 0x00, 0x01 },
+ { 0x80f732, 0x00, 0x01 },
+ { 0x00d91f, 0x00, 0x01 },
+ { 0x00d91a, 0x00, 0x01 },
+ { 0x80f730, 0x00, 0x01 },
+ { 0x80f778, 0x00, 0xff },
+ { 0x80f73c, 0x01, 0x01 },
+ { 0x80f776, 0x00, 0x01 },
+ { 0x00d8fd, 0x01, 0xff },
+ { 0x00d830, 0x01, 0xff },
+ { 0x00d831, 0x00, 0xff },
+ { 0x00d832, 0x00, 0xff },
+ { 0x80f985, state->ts_mode_serial, 0x01 },
+ { 0x80f986, state->ts_mode_parallel, 0x01 },
+ { 0x00d827, 0x00, 0xff },
+ { 0x00d829, 0x00, 0xff },
+ };
+
+ /* program clock control */
+ clock_cw = af9033_div(state->cfg.clock, 1000000ul, 19ul);
+ buf[0] = (clock_cw >> 0) & 0xff;
+ buf[1] = (clock_cw >> 8) & 0xff;
+ buf[2] = (clock_cw >> 16) & 0xff;
+ buf[3] = (clock_cw >> 24) & 0xff;
+
+ pr_debug("%s: clock=%d clock_cw=%08x\n", __func__, state->cfg.clock,
+ clock_cw);
+
+ ret = af9033_wr_regs(state, 0x800025, buf, 4);
+ if (ret < 0)
+ goto err;
+
+ /* program ADC control */
+ for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) {
+ if (clock_adc_lut[i].clock == state->cfg.clock)
+ break;
+ }
+
+ adc_cw = af9033_div(clock_adc_lut[i].adc, 1000000ul, 19ul);
+ buf[0] = (adc_cw >> 0) & 0xff;
+ buf[1] = (adc_cw >> 8) & 0xff;
+ buf[2] = (adc_cw >> 16) & 0xff;
+
+ pr_debug("%s: adc=%d adc_cw=%06x\n", __func__, clock_adc_lut[i].adc,
+ adc_cw);
+
+ ret = af9033_wr_regs(state, 0x80f1cd, buf, 3);
+ if (ret < 0)
+ goto err;
+
+ /* program register table */
+ for (i = 0; i < ARRAY_SIZE(tab); i++) {
+ ret = af9033_wr_reg_mask(state, tab[i].reg, tab[i].val,
+ tab[i].mask);
+ if (ret < 0)
+ goto err;
+ }
+
+ /* settings for TS interface */
+ if (state->cfg.ts_mode == AF9033_TS_MODE_USB) {
+ ret = af9033_wr_reg_mask(state, 0x80f9a5, 0x00, 0x01);
+ if (ret < 0)
+ goto err;
+
+ ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+ } else {
+ ret = af9033_wr_reg_mask(state, 0x80f990, 0x00, 0x01);
+ if (ret < 0)
+ goto err;
+
+ ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x00, 0x01);
+ if (ret < 0)
+ goto err;
+ }
+
+ /* load OFSM settings */
+ pr_debug("%s: load ofsm settings\n", __func__);
+ len = ARRAY_SIZE(ofsm_init);
+ init = ofsm_init;
+ for (i = 0; i < len; i++) {
+ ret = af9033_wr_reg(state, init[i].reg, init[i].val);
+ if (ret < 0)
+ goto err;
+ }
+
+ /* load tuner specific settings */
+ pr_debug("%s: load tuner specific settings\n",
+ __func__);
+ switch (state->cfg.tuner) {
+ case AF9033_TUNER_TUA9001:
+ len = ARRAY_SIZE(tuner_init_tua9001);
+ init = tuner_init_tua9001;
+ break;
+ case AF9033_TUNER_FC0011:
+ len = ARRAY_SIZE(tuner_init_fc0011);
+ init = tuner_init_fc0011;
+ break;
+ case AF9033_TUNER_MXL5007T:
+ len = ARRAY_SIZE(tuner_init_mxl5007t);
+ init = tuner_init_mxl5007t;
+ break;
+ case AF9033_TUNER_TDA18218:
+ len = ARRAY_SIZE(tuner_init_tda18218);
+ init = tuner_init_tda18218;
+ break;
+ default:
+ pr_debug("%s: unsupported tuner ID=%d\n", __func__,
+ state->cfg.tuner);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ for (i = 0; i < len; i++) {
+ ret = af9033_wr_reg(state, init[i].reg, init[i].val);
+ if (ret < 0)
+ goto err;
+ }
+
+ state->bandwidth_hz = 0; /* force to program all parameters */
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9033_sleep(struct dvb_frontend *fe)
+{
+ struct af9033_state *state = fe->demodulator_priv;
+ int ret, i;
+ u8 tmp;
+
+ ret = af9033_wr_reg(state, 0x80004c, 1);
+ if (ret < 0)
+ goto err;
+
+ ret = af9033_wr_reg(state, 0x800000, 0);
+ if (ret < 0)
+ goto err;
+
+ for (i = 100, tmp = 1; i && tmp; i--) {
+ ret = af9033_rd_reg(state, 0x80004c, &tmp);
+ if (ret < 0)
+ goto err;
+
+ usleep_range(200, 10000);
+ }
+
+ pr_debug("%s: loop=%d\n", __func__, i);
+
+ if (i == 0) {
+ ret = -ETIMEDOUT;
+ goto err;
+ }
+
+ ret = af9033_wr_reg_mask(state, 0x80fb24, 0x08, 0x08);
+ if (ret < 0)
+ goto err;
+
+ /* prevent current leak (?) */
+ if (state->cfg.ts_mode == AF9033_TS_MODE_SERIAL) {
+ /* enable parallel TS */
+ ret = af9033_wr_reg_mask(state, 0x00d917, 0x00, 0x01);
+ if (ret < 0)
+ goto err;
+
+ ret = af9033_wr_reg_mask(state, 0x00d916, 0x01, 0x01);
+ if (ret < 0)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9033_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *fesettings)
+{
+ fesettings->min_delay_ms = 800;
+ fesettings->step_size = 0;
+ fesettings->max_drift = 0;
+
+ return 0;
+}
+
+static int af9033_set_frontend(struct dvb_frontend *fe)
+{
+ struct af9033_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret, i, spec_inv;
+ u8 tmp, buf[3], bandwidth_reg_val;
+ u32 if_frequency, freq_cw, adc_freq;
+
+ pr_debug("%s: frequency=%d bandwidth_hz=%d\n", __func__, c->frequency,
+ c->bandwidth_hz);
+
+ /* check bandwidth */
+ switch (c->bandwidth_hz) {
+ case 6000000:
+ bandwidth_reg_val = 0x00;
+ break;
+ case 7000000:
+ bandwidth_reg_val = 0x01;
+ break;
+ case 8000000:
+ bandwidth_reg_val = 0x02;
+ break;
+ default:
+ pr_debug("%s: invalid bandwidth_hz\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* program tuner */
+ if (fe->ops.tuner_ops.set_params)
+ fe->ops.tuner_ops.set_params(fe);
+
+ /* program CFOE coefficients */
+ if (c->bandwidth_hz != state->bandwidth_hz) {
+ for (i = 0; i < ARRAY_SIZE(coeff_lut); i++) {
+ if (coeff_lut[i].clock == state->cfg.clock &&
+ coeff_lut[i].bandwidth_hz == c->bandwidth_hz) {
+ break;
+ }
+ }
+ ret = af9033_wr_regs(state, 0x800001,
+ coeff_lut[i].val, sizeof(coeff_lut[i].val));
+ }
+
+ /* program frequency control */
+ if (c->bandwidth_hz != state->bandwidth_hz) {
+ spec_inv = state->cfg.spec_inv ? -1 : 1;
+
+ for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) {
+ if (clock_adc_lut[i].clock == state->cfg.clock)
+ break;
+ }
+ adc_freq = clock_adc_lut[i].adc;
+
+ /* get used IF frequency */
+ if (fe->ops.tuner_ops.get_if_frequency)
+ fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency);
+ else
+ if_frequency = 0;
+
+ while (if_frequency > (adc_freq / 2))
+ if_frequency -= adc_freq;
+
+ if (if_frequency >= 0)
+ spec_inv *= -1;
+ else
+ if_frequency *= -1;
+
+ freq_cw = af9033_div(if_frequency, adc_freq, 23ul);
+
+ if (spec_inv == -1)
+ freq_cw *= -1;
+
+ /* get adc multiplies */
+ ret = af9033_rd_reg(state, 0x800045, &tmp);
+ if (ret < 0)
+ goto err;
+
+ if (tmp == 1)
+ freq_cw /= 2;
+
+ buf[0] = (freq_cw >> 0) & 0xff;
+ buf[1] = (freq_cw >> 8) & 0xff;
+ buf[2] = (freq_cw >> 16) & 0x7f;
+ ret = af9033_wr_regs(state, 0x800029, buf, 3);
+ if (ret < 0)
+ goto err;
+
+ state->bandwidth_hz = c->bandwidth_hz;
+ }
+
+ ret = af9033_wr_reg_mask(state, 0x80f904, bandwidth_reg_val, 0x03);
+ if (ret < 0)
+ goto err;
+
+ ret = af9033_wr_reg(state, 0x800040, 0x00);
+ if (ret < 0)
+ goto err;
+
+ ret = af9033_wr_reg(state, 0x800047, 0x00);
+ if (ret < 0)
+ goto err;
+
+ ret = af9033_wr_reg_mask(state, 0x80f999, 0x00, 0x01);
+ if (ret < 0)
+ goto err;
+
+ if (c->frequency <= 230000000)
+ tmp = 0x00; /* VHF */
+ else
+ tmp = 0x01; /* UHF */
+
+ ret = af9033_wr_reg(state, 0x80004b, tmp);
+ if (ret < 0)
+ goto err;
+
+ ret = af9033_wr_reg(state, 0x800000, 0x00);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9033_get_frontend(struct dvb_frontend *fe)
+{
+ struct af9033_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret;
+ u8 buf[8];
+
+ pr_debug("%s\n", __func__);
+
+ /* read all needed registers */
+ ret = af9033_rd_regs(state, 0x80f900, buf, sizeof(buf));
+ if (ret < 0)
+ goto err;
+
+ switch ((buf[0] >> 0) & 3) {
+ case 0:
+ c->transmission_mode = TRANSMISSION_MODE_2K;
+ break;
+ case 1:
+ c->transmission_mode = TRANSMISSION_MODE_8K;
+ break;
+ }
+
+ switch ((buf[1] >> 0) & 3) {
+ case 0:
+ c->guard_interval = GUARD_INTERVAL_1_32;
+ break;
+ case 1:
+ c->guard_interval = GUARD_INTERVAL_1_16;
+ break;
+ case 2:
+ c->guard_interval = GUARD_INTERVAL_1_8;
+ break;
+ case 3:
+ c->guard_interval = GUARD_INTERVAL_1_4;
+ break;
+ }
+
+ switch ((buf[2] >> 0) & 7) {
+ case 0:
+ c->hierarchy = HIERARCHY_NONE;
+ break;
+ case 1:
+ c->hierarchy = HIERARCHY_1;
+ break;
+ case 2:
+ c->hierarchy = HIERARCHY_2;
+ break;
+ case 3:
+ c->hierarchy = HIERARCHY_4;
+ break;
+ }
+
+ switch ((buf[3] >> 0) & 3) {
+ case 0:
+ c->modulation = QPSK;
+ break;
+ case 1:
+ c->modulation = QAM_16;
+ break;
+ case 2:
+ c->modulation = QAM_64;
+ break;
+ }
+
+ switch ((buf[4] >> 0) & 3) {
+ case 0:
+ c->bandwidth_hz = 6000000;
+ break;
+ case 1:
+ c->bandwidth_hz = 7000000;
+ break;
+ case 2:
+ c->bandwidth_hz = 8000000;
+ break;
+ }
+
+ switch ((buf[6] >> 0) & 7) {
+ case 0:
+ c->code_rate_HP = FEC_1_2;
+ break;
+ case 1:
+ c->code_rate_HP = FEC_2_3;
+ break;
+ case 2:
+ c->code_rate_HP = FEC_3_4;
+ break;
+ case 3:
+ c->code_rate_HP = FEC_5_6;
+ break;
+ case 4:
+ c->code_rate_HP = FEC_7_8;
+ break;
+ case 5:
+ c->code_rate_HP = FEC_NONE;
+ break;
+ }
+
+ switch ((buf[7] >> 0) & 7) {
+ case 0:
+ c->code_rate_LP = FEC_1_2;
+ break;
+ case 1:
+ c->code_rate_LP = FEC_2_3;
+ break;
+ case 2:
+ c->code_rate_LP = FEC_3_4;
+ break;
+ case 3:
+ c->code_rate_LP = FEC_5_6;
+ break;
+ case 4:
+ c->code_rate_LP = FEC_7_8;
+ break;
+ case 5:
+ c->code_rate_LP = FEC_NONE;
+ break;
+ }
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct af9033_state *state = fe->demodulator_priv;
+ int ret;
+ u8 tmp;
+
+ *status = 0;
+
+ /* radio channel status, 0=no result, 1=has signal, 2=no signal */
+ ret = af9033_rd_reg(state, 0x800047, &tmp);
+ if (ret < 0)
+ goto err;
+
+ /* has signal */
+ if (tmp == 0x01)
+ *status |= FE_HAS_SIGNAL;
+
+ if (tmp != 0x02) {
+ /* TPS lock */
+ ret = af9033_rd_reg_mask(state, 0x80f5a9, &tmp, 0x01);
+ if (ret < 0)
+ goto err;
+
+ if (tmp)
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI;
+
+ /* full lock */
+ ret = af9033_rd_reg_mask(state, 0x80f999, &tmp, 0x01);
+ if (ret < 0)
+ goto err;
+
+ if (tmp)
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI | FE_HAS_SYNC |
+ FE_HAS_LOCK;
+ }
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9033_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct af9033_state *state = fe->demodulator_priv;
+ int ret, i, len;
+ u8 buf[3], tmp;
+ u32 snr_val;
+ const struct val_snr *uninitialized_var(snr_lut);
+
+ /* read value */
+ ret = af9033_rd_regs(state, 0x80002c, buf, 3);
+ if (ret < 0)
+ goto err;
+
+ snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0];
+
+ /* read current modulation */
+ ret = af9033_rd_reg(state, 0x80f903, &tmp);
+ if (ret < 0)
+ goto err;
+
+ switch ((tmp >> 0) & 3) {
+ case 0:
+ len = ARRAY_SIZE(qpsk_snr_lut);
+ snr_lut = qpsk_snr_lut;
+ break;
+ case 1:
+ len = ARRAY_SIZE(qam16_snr_lut);
+ snr_lut = qam16_snr_lut;
+ break;
+ case 2:
+ len = ARRAY_SIZE(qam64_snr_lut);
+ snr_lut = qam64_snr_lut;
+ break;
+ default:
+ goto err;
+ }
+
+ for (i = 0; i < len; i++) {
+ tmp = snr_lut[i].snr;
+
+ if (snr_val < snr_lut[i].val)
+ break;
+ }
+
+ *snr = tmp * 10; /* dB/10 */
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ struct af9033_state *state = fe->demodulator_priv;
+ int ret;
+ u8 strength2;
+
+ /* read signal strength of 0-100 scale */
+ ret = af9033_rd_reg(state, 0x800048, &strength2);
+ if (ret < 0)
+ goto err;
+
+ /* scale value to 0x0000-0xffff */
+ *strength = strength2 * 0xffff / 100;
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int af9033_update_ch_stat(struct af9033_state *state)
+{
+ int ret = 0;
+ u32 err_cnt, bit_cnt;
+ u16 abort_cnt;
+ u8 buf[7];
+
+ /* only update data every half second */
+ if (time_after(jiffies, state->last_stat_check + msecs_to_jiffies(500))) {
+ ret = af9033_rd_regs(state, 0x800032, buf, sizeof(buf));
+ if (ret < 0)
+ goto err;
+ /* in 8 byte packets? */
+ abort_cnt = (buf[1] << 8) + buf[0];
+ /* in bits */
+ err_cnt = (buf[4] << 16) + (buf[3] << 8) + buf[2];
+ /* in 8 byte packets? always(?) 0x2710 = 10000 */
+ bit_cnt = (buf[6] << 8) + buf[5];
+
+ if (bit_cnt < abort_cnt) {
+ abort_cnt = 1000;
+ state->ber = 0xffffffff;
+ } else {
+ /* 8 byte packets, that have not been rejected already */
+ bit_cnt -= (u32)abort_cnt;
+ if (bit_cnt == 0) {
+ state->ber = 0xffffffff;
+ } else {
+ err_cnt -= (u32)abort_cnt * 8 * 8;
+ bit_cnt *= 8 * 8;
+ state->ber = err_cnt * (0xffffffff / bit_cnt);
+ }
+ }
+ state->ucb += abort_cnt;
+ state->last_stat_check = jiffies;
+ }
+
+ return 0;
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int af9033_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ struct af9033_state *state = fe->demodulator_priv;
+ int ret;
+
+ ret = af9033_update_ch_stat(state);
+ if (ret < 0)
+ return ret;
+
+ *ber = state->ber;
+
+ return 0;
+}
+
+static int af9033_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ struct af9033_state *state = fe->demodulator_priv;
+ int ret;
+
+ ret = af9033_update_ch_stat(state);
+ if (ret < 0)
+ return ret;
+
+ *ucblocks = state->ucb;
+
+ return 0;
+}
+
+static int af9033_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+ struct af9033_state *state = fe->demodulator_priv;
+ int ret;
+
+ pr_debug("%s: enable=%d\n", __func__, enable);
+
+ ret = af9033_wr_reg_mask(state, 0x00fa04, enable, 0x01);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+
+err:
+ pr_debug("%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static struct dvb_frontend_ops af9033_ops;
+
+struct dvb_frontend *af9033_attach(const struct af9033_config *config,
+ struct i2c_adapter *i2c)
+{
+ int ret;
+ struct af9033_state *state;
+ u8 buf[8];
+
+ pr_debug("%s:\n", __func__);
+
+ /* allocate memory for the internal state */
+ state = kzalloc(sizeof(struct af9033_state), GFP_KERNEL);
+ if (state == NULL)
+ goto err;
+
+ /* setup the state */
+ state->i2c = i2c;
+ memcpy(&state->cfg, config, sizeof(struct af9033_config));
+
+ if (state->cfg.clock != 12000000) {
+ printk(KERN_INFO "af9033: unsupported clock=%d, only " \
+ "12000000 Hz is supported currently\n",
+ state->cfg.clock);
+ goto err;
+ }
+
+ /* firmware version */
+ ret = af9033_rd_regs(state, 0x0083e9, &buf[0], 4);
+ if (ret < 0)
+ goto err;
+
+ ret = af9033_rd_regs(state, 0x804191, &buf[4], 4);
+ if (ret < 0)
+ goto err;
+
+ printk(KERN_INFO "af9033: firmware version: LINK=%d.%d.%d.%d " \
+ "OFDM=%d.%d.%d.%d\n", buf[0], buf[1], buf[2], buf[3],
+ buf[4], buf[5], buf[6], buf[7]);
+
+ /* configure internal TS mode */
+ switch (state->cfg.ts_mode) {
+ case AF9033_TS_MODE_PARALLEL:
+ state->ts_mode_parallel = true;
+ break;
+ case AF9033_TS_MODE_SERIAL:
+ state->ts_mode_serial = true;
+ break;
+ case AF9033_TS_MODE_USB:
+ /* usb mode for AF9035 */
+ default:
+ break;
+ }
+
+ /* create dvb_frontend */
+ memcpy(&state->fe.ops, &af9033_ops, sizeof(struct dvb_frontend_ops));
+ state->fe.demodulator_priv = state;
+
+ return &state->fe;
+
+err:
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(af9033_attach);
+
+static struct dvb_frontend_ops af9033_ops = {
+ .delsys = { SYS_DVBT },
+ .info = {
+ .name = "Afatech AF9033 (DVB-T)",
+ .frequency_min = 174000000,
+ .frequency_max = 862000000,
+ .frequency_stepsize = 250000,
+ .frequency_tolerance = 0,
+ .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_64 |
+ FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO |
+ FE_CAN_RECOVER |
+ FE_CAN_MUTE_TS
+ },
+
+ .release = af9033_release,
+
+ .init = af9033_init,
+ .sleep = af9033_sleep,
+
+ .get_tune_settings = af9033_get_tune_settings,
+ .set_frontend = af9033_set_frontend,
+ .get_frontend = af9033_get_frontend,
+
+ .read_status = af9033_read_status,
+ .read_snr = af9033_read_snr,
+ .read_signal_strength = af9033_read_signal_strength,
+ .read_ber = af9033_read_ber,
+ .read_ucblocks = af9033_read_ucblocks,
+
+ .i2c_gate_ctrl = af9033_i2c_gate_ctrl,
+};
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Afatech AF9033 DVB-T demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/af9033.h b/drivers/media/dvb/frontends/af9033.h
new file mode 100644
index 000000000000..9e302c3f0f7d
--- /dev/null
+++ b/drivers/media/dvb/frontends/af9033.h
@@ -0,0 +1,75 @@
+/*
+ * Afatech AF9033 demodulator driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2012 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef AF9033_H
+#define AF9033_H
+
+struct af9033_config {
+ /*
+ * I2C address
+ */
+ u8 i2c_addr;
+
+ /*
+ * clock Hz
+ * 12000000, 22000000, 24000000, 34000000, 32000000, 28000000, 26000000,
+ * 30000000, 36000000, 20480000, 16384000
+ */
+ u32 clock;
+
+ /*
+ * tuner
+ */
+#define AF9033_TUNER_TUA9001 0x27 /* Infineon TUA 9001 */
+#define AF9033_TUNER_FC0011 0x28 /* Fitipower FC0011 */
+#define AF9033_TUNER_MXL5007T 0xa0 /* MaxLinear MxL5007T */
+#define AF9033_TUNER_TDA18218 0xa1 /* NXP TDA 18218HN */
+ u8 tuner;
+
+ /*
+ * TS settings
+ */
+#define AF9033_TS_MODE_USB 0
+#define AF9033_TS_MODE_PARALLEL 1
+#define AF9033_TS_MODE_SERIAL 2
+ u8 ts_mode:2;
+
+ /*
+ * input spectrum inversion
+ */
+ bool spec_inv;
+};
+
+
+#if defined(CONFIG_DVB_AF9033) || \
+ (defined(CONFIG_DVB_AF9033_MODULE) && defined(MODULE))
+extern struct dvb_frontend *af9033_attach(const struct af9033_config *config,
+ struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *af9033_attach(
+ const struct af9033_config *config, struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
+#endif /* AF9033_H */
diff --git a/drivers/media/dvb/frontends/af9033_priv.h b/drivers/media/dvb/frontends/af9033_priv.h
new file mode 100644
index 000000000000..0b783b9ed75e
--- /dev/null
+++ b/drivers/media/dvb/frontends/af9033_priv.h
@@ -0,0 +1,470 @@
+/*
+ * Afatech AF9033 demodulator driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2012 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef AF9033_PRIV_H
+#define AF9033_PRIV_H
+
+#include "dvb_frontend.h"
+#include "af9033.h"
+
+struct reg_val {
+ u32 reg;
+ u8 val;
+};
+
+struct reg_val_mask {
+ u32 reg;
+ u8 val;
+ u8 mask;
+};
+
+struct coeff {
+ u32 clock;
+ u32 bandwidth_hz;
+ u8 val[36];
+};
+
+struct clock_adc {
+ u32 clock;
+ u32 adc;
+};
+
+struct val_snr {
+ u32 val;
+ u8 snr;
+};
+
+/* Xtal clock vs. ADC clock lookup table */
+static const struct clock_adc clock_adc_lut[] = {
+ { 16384000, 20480000 },
+ { 20480000, 20480000 },
+ { 36000000, 20250000 },
+ { 30000000, 20156250 },
+ { 26000000, 20583333 },
+ { 28000000, 20416667 },
+ { 32000000, 20500000 },
+ { 34000000, 20187500 },
+ { 24000000, 20500000 },
+ { 22000000, 20625000 },
+ { 12000000, 20250000 },
+};
+
+/* pre-calculated coeff lookup table */
+static const struct coeff coeff_lut[] = {
+ /* 12.000 MHz */
+ { 12000000, 8000000, {
+ 0x01, 0xce, 0x55, 0xc9, 0x00, 0xe7, 0x2a, 0xe4, 0x00, 0x73,
+ 0x99, 0x0f, 0x00, 0x73, 0x95, 0x72, 0x00, 0x73, 0x91, 0xd5,
+ 0x00, 0x39, 0xca, 0xb9, 0x00, 0xe7, 0x2a, 0xe4, 0x00, 0x73,
+ 0x95, 0x72, 0x37, 0x02, 0xce, 0x01 }
+ },
+ { 12000000, 7000000, {
+ 0x01, 0x94, 0x8b, 0x10, 0x00, 0xca, 0x45, 0x88, 0x00, 0x65,
+ 0x25, 0xed, 0x00, 0x65, 0x22, 0xc4, 0x00, 0x65, 0x1f, 0x9b,
+ 0x00, 0x32, 0x91, 0x62, 0x00, 0xca, 0x45, 0x88, 0x00, 0x65,
+ 0x22, 0xc4, 0x88, 0x02, 0x95, 0x01 }
+ },
+ { 12000000, 6000000, {
+ 0x01, 0x5a, 0xc0, 0x56, 0x00, 0xad, 0x60, 0x2b, 0x00, 0x56,
+ 0xb2, 0xcb, 0x00, 0x56, 0xb0, 0x15, 0x00, 0x56, 0xad, 0x60,
+ 0x00, 0x2b, 0x58, 0x0b, 0x00, 0xad, 0x60, 0x2b, 0x00, 0x56,
+ 0xb0, 0x15, 0xf4, 0x02, 0x5b, 0x01 }
+ },
+};
+
+/* QPSK SNR lookup table */
+static const struct val_snr qpsk_snr_lut[] = {
+ { 0x0b4771, 0 },
+ { 0x0c1aed, 1 },
+ { 0x0d0d27, 2 },
+ { 0x0e4d19, 3 },
+ { 0x0e5da8, 4 },
+ { 0x107097, 5 },
+ { 0x116975, 6 },
+ { 0x1252d9, 7 },
+ { 0x131fa4, 8 },
+ { 0x13d5e1, 9 },
+ { 0x148e53, 10 },
+ { 0x15358b, 11 },
+ { 0x15dd29, 12 },
+ { 0x168112, 13 },
+ { 0x170b61, 14 },
+ { 0x17a532, 15 },
+ { 0x180f94, 16 },
+ { 0x186ed2, 17 },
+ { 0x18b271, 18 },
+ { 0x18e118, 19 },
+ { 0x18ff4b, 20 },
+ { 0x190af1, 21 },
+ { 0x191451, 22 },
+ { 0xffffff, 23 },
+};
+
+/* QAM16 SNR lookup table */
+static const struct val_snr qam16_snr_lut[] = {
+ { 0x04f0d5, 0 },
+ { 0x05387a, 1 },
+ { 0x0573a4, 2 },
+ { 0x05a99e, 3 },
+ { 0x05cc80, 4 },
+ { 0x05eb62, 5 },
+ { 0x05fecf, 6 },
+ { 0x060b80, 7 },
+ { 0x062501, 8 },
+ { 0x064865, 9 },
+ { 0x069604, 10 },
+ { 0x06f356, 11 },
+ { 0x07706a, 12 },
+ { 0x0804d3, 13 },
+ { 0x089d1a, 14 },
+ { 0x093e3d, 15 },
+ { 0x09e35d, 16 },
+ { 0x0a7c3c, 17 },
+ { 0x0afaf8, 18 },
+ { 0x0b719d, 19 },
+ { 0x0bda6a, 20 },
+ { 0x0c0c75, 21 },
+ { 0x0c3f7d, 22 },
+ { 0x0c5e62, 23 },
+ { 0x0c6c31, 24 },
+ { 0x0c7925, 25 },
+ { 0xffffff, 26 },
+};
+
+/* QAM64 SNR lookup table */
+static const struct val_snr qam64_snr_lut[] = {
+ { 0x0256d0, 0 },
+ { 0x027a65, 1 },
+ { 0x029873, 2 },
+ { 0x02b7fe, 3 },
+ { 0x02cf1e, 4 },
+ { 0x02e234, 5 },
+ { 0x02f409, 6 },
+ { 0x030046, 7 },
+ { 0x030844, 8 },
+ { 0x030a02, 9 },
+ { 0x030cde, 10 },
+ { 0x031031, 11 },
+ { 0x03144c, 12 },
+ { 0x0315dd, 13 },
+ { 0x031920, 14 },
+ { 0x0322d0, 15 },
+ { 0x0339fc, 16 },
+ { 0x0364a1, 17 },
+ { 0x038bcc, 18 },
+ { 0x03c7d3, 19 },
+ { 0x0408cc, 20 },
+ { 0x043bed, 21 },
+ { 0x048061, 22 },
+ { 0x04be95, 23 },
+ { 0x04fa7d, 24 },
+ { 0x052405, 25 },
+ { 0x05570d, 26 },
+ { 0x059feb, 27 },
+ { 0x05bf38, 28 },
+ { 0xffffff, 29 },
+};
+
+static const struct reg_val ofsm_init[] = {
+ { 0x800051, 0x01 },
+ { 0x800070, 0x0a },
+ { 0x80007e, 0x04 },
+ { 0x800081, 0x0a },
+ { 0x80008a, 0x01 },
+ { 0x80008e, 0x01 },
+ { 0x800092, 0x06 },
+ { 0x800099, 0x01 },
+ { 0x80009f, 0xe1 },
+ { 0x8000a0, 0xcf },
+ { 0x8000a3, 0x01 },
+ { 0x8000a5, 0x01 },
+ { 0x8000a6, 0x01 },
+ { 0x8000a9, 0x00 },
+ { 0x8000aa, 0x01 },
+ { 0x8000ab, 0x01 },
+ { 0x8000b0, 0x01 },
+ { 0x8000c0, 0x05 },
+ { 0x8000c4, 0x19 },
+ { 0x80f000, 0x0f },
+ { 0x80f016, 0x10 },
+ { 0x80f017, 0x04 },
+ { 0x80f018, 0x05 },
+ { 0x80f019, 0x04 },
+ { 0x80f01a, 0x05 },
+ { 0x80f021, 0x03 },
+ { 0x80f022, 0x0a },
+ { 0x80f023, 0x0a },
+ { 0x80f02b, 0x00 },
+ { 0x80f02c, 0x01 },
+ { 0x80f064, 0x03 },
+ { 0x80f065, 0xf9 },
+ { 0x80f066, 0x03 },
+ { 0x80f067, 0x01 },
+ { 0x80f06f, 0xe0 },
+ { 0x80f070, 0x03 },
+ { 0x80f072, 0x0f },
+ { 0x80f073, 0x03 },
+ { 0x80f078, 0x00 },
+ { 0x80f087, 0x00 },
+ { 0x80f09b, 0x3f },
+ { 0x80f09c, 0x00 },
+ { 0x80f09d, 0x20 },
+ { 0x80f09e, 0x00 },
+ { 0x80f09f, 0x0c },
+ { 0x80f0a0, 0x00 },
+ { 0x80f130, 0x04 },
+ { 0x80f132, 0x04 },
+ { 0x80f144, 0x1a },
+ { 0x80f146, 0x00 },
+ { 0x80f14a, 0x01 },
+ { 0x80f14c, 0x00 },
+ { 0x80f14d, 0x00 },
+ { 0x80f14f, 0x04 },
+ { 0x80f158, 0x7f },
+ { 0x80f15a, 0x00 },
+ { 0x80f15b, 0x08 },
+ { 0x80f15d, 0x03 },
+ { 0x80f15e, 0x05 },
+ { 0x80f163, 0x05 },
+ { 0x80f166, 0x01 },
+ { 0x80f167, 0x40 },
+ { 0x80f168, 0x0f },
+ { 0x80f17a, 0x00 },
+ { 0x80f17b, 0x00 },
+ { 0x80f183, 0x01 },
+ { 0x80f19d, 0x40 },
+ { 0x80f1bc, 0x36 },
+ { 0x80f1bd, 0x00 },
+ { 0x80f1cb, 0xa0 },
+ { 0x80f1cc, 0x01 },
+ { 0x80f204, 0x10 },
+ { 0x80f214, 0x00 },
+ { 0x80f40e, 0x0a },
+ { 0x80f40f, 0x40 },
+ { 0x80f410, 0x08 },
+ { 0x80f55f, 0x0a },
+ { 0x80f561, 0x15 },
+ { 0x80f562, 0x20 },
+ { 0x80f5df, 0xfb },
+ { 0x80f5e0, 0x00 },
+ { 0x80f5e3, 0x09 },
+ { 0x80f5e4, 0x01 },
+ { 0x80f5e5, 0x01 },
+ { 0x80f5f8, 0x01 },
+ { 0x80f5fd, 0x01 },
+ { 0x80f600, 0x05 },
+ { 0x80f601, 0x08 },
+ { 0x80f602, 0x0b },
+ { 0x80f603, 0x0e },
+ { 0x80f604, 0x11 },
+ { 0x80f605, 0x14 },
+ { 0x80f606, 0x17 },
+ { 0x80f607, 0x1f },
+ { 0x80f60e, 0x00 },
+ { 0x80f60f, 0x04 },
+ { 0x80f610, 0x32 },
+ { 0x80f611, 0x10 },
+ { 0x80f707, 0xfc },
+ { 0x80f708, 0x00 },
+ { 0x80f709, 0x37 },
+ { 0x80f70a, 0x00 },
+ { 0x80f78b, 0x01 },
+ { 0x80f80f, 0x40 },
+ { 0x80f810, 0x54 },
+ { 0x80f811, 0x5a },
+ { 0x80f905, 0x01 },
+ { 0x80fb06, 0x03 },
+ { 0x80fd8b, 0x00 },
+};
+
+/* Infineon TUA 9001 tuner init
+ AF9033_TUNER_TUA9001 = 0x27 */
+static const struct reg_val tuner_init_tua9001[] = {
+ { 0x800046, 0x27 },
+ { 0x800057, 0x00 },
+ { 0x800058, 0x01 },
+ { 0x80005f, 0x00 },
+ { 0x800060, 0x00 },
+ { 0x80006d, 0x00 },
+ { 0x800071, 0x05 },
+ { 0x800072, 0x02 },
+ { 0x800074, 0x01 },
+ { 0x800075, 0x03 },
+ { 0x800076, 0x02 },
+ { 0x800077, 0x00 },
+ { 0x800078, 0x01 },
+ { 0x800079, 0x00 },
+ { 0x80007a, 0x7e },
+ { 0x80007b, 0x3e },
+ { 0x800093, 0x00 },
+ { 0x800094, 0x01 },
+ { 0x800095, 0x02 },
+ { 0x800096, 0x01 },
+ { 0x800098, 0x0a },
+ { 0x80009b, 0x05 },
+ { 0x80009c, 0x80 },
+ { 0x8000b3, 0x00 },
+ { 0x8000c1, 0x01 },
+ { 0x8000c2, 0x00 },
+ { 0x80f007, 0x00 },
+ { 0x80f01f, 0x82 },
+ { 0x80f020, 0x00 },
+ { 0x80f029, 0x82 },
+ { 0x80f02a, 0x00 },
+ { 0x80f047, 0x00 },
+ { 0x80f054, 0x00 },
+ { 0x80f055, 0x00 },
+ { 0x80f077, 0x01 },
+ { 0x80f1e6, 0x00 },
+};
+
+/* Fitipower fc0011 tuner init
+ AF9033_TUNER_FC0011 = 0x28 */
+static const struct reg_val tuner_init_fc0011[] = {
+ { 0x800046, AF9033_TUNER_FC0011 },
+ { 0x800057, 0x00 },
+ { 0x800058, 0x01 },
+ { 0x80005f, 0x00 },
+ { 0x800060, 0x00 },
+ { 0x800068, 0xa5 },
+ { 0x80006e, 0x01 },
+ { 0x800071, 0x0A },
+ { 0x800072, 0x02 },
+ { 0x800074, 0x01 },
+ { 0x800079, 0x01 },
+ { 0x800093, 0x00 },
+ { 0x800094, 0x00 },
+ { 0x800095, 0x00 },
+ { 0x800096, 0x00 },
+ { 0x80009b, 0x2D },
+ { 0x80009c, 0x60 },
+ { 0x80009d, 0x23 },
+ { 0x8000a4, 0x50 },
+ { 0x8000ad, 0x50 },
+ { 0x8000b3, 0x01 },
+ { 0x8000b7, 0x88 },
+ { 0x8000b8, 0xa6 },
+ { 0x8000c3, 0x01 },
+ { 0x8000c4, 0x01 },
+ { 0x8000c7, 0x69 },
+ { 0x80F007, 0x00 },
+ { 0x80F00A, 0x1B },
+ { 0x80F00B, 0x1B },
+ { 0x80F00C, 0x1B },
+ { 0x80F00D, 0x1B },
+ { 0x80F00E, 0xFF },
+ { 0x80F00F, 0x01 },
+ { 0x80F010, 0x00 },
+ { 0x80F011, 0x02 },
+ { 0x80F012, 0xFF },
+ { 0x80F013, 0x01 },
+ { 0x80F014, 0x00 },
+ { 0x80F015, 0x02 },
+ { 0x80F01B, 0xEF },
+ { 0x80F01C, 0x01 },
+ { 0x80F01D, 0x0f },
+ { 0x80F01E, 0x02 },
+ { 0x80F01F, 0x6E },
+ { 0x80F020, 0x00 },
+ { 0x80F025, 0xDE },
+ { 0x80F026, 0x00 },
+ { 0x80F027, 0x0A },
+ { 0x80F028, 0x03 },
+ { 0x80F029, 0x6E },
+ { 0x80F02A, 0x00 },
+ { 0x80F047, 0x00 },
+ { 0x80F054, 0x00 },
+ { 0x80F055, 0x00 },
+ { 0x80F077, 0x01 },
+ { 0x80F1E6, 0x00 },
+};
+
+/* MaxLinear MxL5007T tuner init
+ AF9033_TUNER_MXL5007T = 0xa0 */
+static const struct reg_val tuner_init_mxl5007t[] = {
+ { 0x800046, 0x1b },
+ { 0x800057, 0x01 },
+ { 0x800058, 0x01 },
+ { 0x80005f, 0x00 },
+ { 0x800060, 0x00 },
+ { 0x800068, 0x96 },
+ { 0x800071, 0x05 },
+ { 0x800072, 0x02 },
+ { 0x800074, 0x01 },
+ { 0x800079, 0x01 },
+ { 0x800093, 0x00 },
+ { 0x800094, 0x00 },
+ { 0x800095, 0x00 },
+ { 0x800096, 0x00 },
+ { 0x8000b3, 0x01 },
+ { 0x8000c1, 0x01 },
+ { 0x8000c2, 0x00 },
+ { 0x80f007, 0x00 },
+ { 0x80f00c, 0x19 },
+ { 0x80f00d, 0x1a },
+ { 0x80f012, 0xda },
+ { 0x80f013, 0x00 },
+ { 0x80f014, 0x00 },
+ { 0x80f015, 0x02 },
+ { 0x80f01f, 0x82 },
+ { 0x80f020, 0x00 },
+ { 0x80f029, 0x82 },
+ { 0x80f02a, 0x00 },
+ { 0x80f077, 0x02 },
+ { 0x80f1e6, 0x00 },
+};
+
+/* NXP TDA 18218HN tuner init
+ AF9033_TUNER_TDA18218 = 0xa1 */
+static const struct reg_val tuner_init_tda18218[] = {
+ {0x800046, 0xa1},
+ {0x800057, 0x01},
+ {0x800058, 0x01},
+ {0x80005f, 0x00},
+ {0x800060, 0x00},
+ {0x800071, 0x05},
+ {0x800072, 0x02},
+ {0x800074, 0x01},
+ {0x800079, 0x01},
+ {0x800093, 0x00},
+ {0x800094, 0x00},
+ {0x800095, 0x00},
+ {0x800096, 0x00},
+ {0x8000b3, 0x01},
+ {0x8000c3, 0x01},
+ {0x8000c4, 0x00},
+ {0x80f007, 0x00},
+ {0x80f00c, 0x19},
+ {0x80f00d, 0x1a},
+ {0x80f012, 0xda},
+ {0x80f013, 0x00},
+ {0x80f014, 0x00},
+ {0x80f015, 0x02},
+ {0x80f01f, 0x82},
+ {0x80f020, 0x00},
+ {0x80f029, 0x82},
+ {0x80f02a, 0x00},
+ {0x80f077, 0x02},
+ {0x80f1e6, 0x00},
+};
+
+#endif /* AF9033_PRIV_H */
+
diff --git a/drivers/media/dvb/frontends/au8522_common.c b/drivers/media/dvb/frontends/au8522_common.c
new file mode 100644
index 000000000000..5cfe151ee394
--- /dev/null
+++ b/drivers/media/dvb/frontends/au8522_common.c
@@ -0,0 +1,259 @@
+/*
+ Auvitek AU8522 QAM/8VSB demodulator driver
+
+ Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
+ Copyright (C) 2008 Devin Heitmueller <dheitmueller@linuxtv.org>
+ Copyright (C) 2005-2008 Auvitek International, Ltd.
+ Copyright (C) 2012 Michael Krufky <mkrufky@linuxtv.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+#include "au8522_priv.h"
+
+MODULE_LICENSE("GPL");
+
+static int debug;
+
+#define dprintk(arg...)\
+ do { if (debug)\
+ printk(arg);\
+ } while (0)
+
+/* Despite the name "hybrid_tuner", the framework works just as well for
+ hybrid demodulators as well... */
+static LIST_HEAD(hybrid_tuner_instance_list);
+static DEFINE_MUTEX(au8522_list_mutex);
+
+/* 16 bit registers, 8 bit values */
+int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
+{
+ int ret;
+ u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data };
+
+ struct i2c_msg msg = { .addr = state->config->demod_address,
+ .flags = 0, .buf = buf, .len = 3 };
+
+ ret = i2c_transfer(state->i2c, &msg, 1);
+
+ if (ret != 1)
+ printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
+ "ret == %i)\n", __func__, reg, data, ret);
+
+ return (ret != 1) ? -1 : 0;
+}
+EXPORT_SYMBOL(au8522_writereg);
+
+u8 au8522_readreg(struct au8522_state *state, u16 reg)
+{
+ int ret;
+ u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff };
+ u8 b1[] = { 0 };
+
+ struct i2c_msg msg[] = {
+ { .addr = state->config->demod_address, .flags = 0,
+ .buf = b0, .len = 2 },
+ { .addr = state->config->demod_address, .flags = I2C_M_RD,
+ .buf = b1, .len = 1 } };
+
+ ret = i2c_transfer(state->i2c, msg, 2);
+
+ if (ret != 2)
+ printk(KERN_ERR "%s: readreg error (ret == %i)\n",
+ __func__, ret);
+ return b1[0];
+}
+EXPORT_SYMBOL(au8522_readreg);
+
+int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+
+ dprintk("%s(%d)\n", __func__, enable);
+
+ if (state->operational_mode == AU8522_ANALOG_MODE) {
+ /* We're being asked to manage the gate even though we're
+ not in digital mode. This can occur if we get switched
+ over to analog mode before the dvb_frontend kernel thread
+ has completely shutdown */
+ return 0;
+ }
+
+ if (enable)
+ return au8522_writereg(state, 0x106, 1);
+ else
+ return au8522_writereg(state, 0x106, 0);
+}
+EXPORT_SYMBOL(au8522_i2c_gate_ctrl);
+
+/* Reset the demod hardware and reset all of the configuration registers
+ to a default state. */
+int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
+ u8 client_address)
+{
+ int ret;
+
+ mutex_lock(&au8522_list_mutex);
+ ret = hybrid_tuner_request_state(struct au8522_state, (*state),
+ hybrid_tuner_instance_list,
+ i2c, client_address, "au8522");
+ mutex_unlock(&au8522_list_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL(au8522_get_state);
+
+void au8522_release_state(struct au8522_state *state)
+{
+ mutex_lock(&au8522_list_mutex);
+ if (state != NULL)
+ hybrid_tuner_release_state(state);
+ mutex_unlock(&au8522_list_mutex);
+}
+EXPORT_SYMBOL(au8522_release_state);
+
+static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
+{
+ struct au8522_led_config *led_config = state->config->led_cfg;
+ u8 val;
+
+ /* bail out if we can't control an LED */
+ if (!led_config || !led_config->gpio_output ||
+ !led_config->gpio_output_enable || !led_config->gpio_output_disable)
+ return 0;
+
+ val = au8522_readreg(state, 0x4000 |
+ (led_config->gpio_output & ~0xc000));
+ if (onoff) {
+ /* enable GPIO output */
+ val &= ~((led_config->gpio_output_enable >> 8) & 0xff);
+ val |= (led_config->gpio_output_enable & 0xff);
+ } else {
+ /* disable GPIO output */
+ val &= ~((led_config->gpio_output_disable >> 8) & 0xff);
+ val |= (led_config->gpio_output_disable & 0xff);
+ }
+ return au8522_writereg(state, 0x8000 |
+ (led_config->gpio_output & ~0xc000), val);
+}
+
+/* led = 0 | off
+ * led = 1 | signal ok
+ * led = 2 | signal strong
+ * led < 0 | only light led if leds are currently off
+ */
+int au8522_led_ctrl(struct au8522_state *state, int led)
+{
+ struct au8522_led_config *led_config = state->config->led_cfg;
+ int i, ret = 0;
+
+ /* bail out if we can't control an LED */
+ if (!led_config || !led_config->gpio_leds ||
+ !led_config->num_led_states || !led_config->led_states)
+ return 0;
+
+ if (led < 0) {
+ /* if LED is already lit, then leave it as-is */
+ if (state->led_state)
+ return 0;
+ else
+ led *= -1;
+ }
+
+ /* toggle LED if changing state */
+ if (state->led_state != led) {
+ u8 val;
+
+ dprintk("%s: %d\n", __func__, led);
+
+ au8522_led_gpio_enable(state, 1);
+
+ val = au8522_readreg(state, 0x4000 |
+ (led_config->gpio_leds & ~0xc000));
+
+ /* start with all leds off */
+ for (i = 0; i < led_config->num_led_states; i++)
+ val &= ~led_config->led_states[i];
+
+ /* set selected LED state */
+ if (led < led_config->num_led_states)
+ val |= led_config->led_states[led];
+ else if (led_config->num_led_states)
+ val |=
+ led_config->led_states[led_config->num_led_states - 1];
+
+ ret = au8522_writereg(state, 0x8000 |
+ (led_config->gpio_leds & ~0xc000), val);
+ if (ret < 0)
+ return ret;
+
+ state->led_state = led;
+
+ if (led == 0)
+ au8522_led_gpio_enable(state, 0);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(au8522_led_ctrl);
+
+int au8522_init(struct dvb_frontend *fe)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+ dprintk("%s()\n", __func__);
+
+ state->operational_mode = AU8522_DIGITAL_MODE;
+
+ /* Clear out any state associated with the digital side of the
+ chip, so that when it gets powered back up it won't think
+ that it is already tuned */
+ state->current_frequency = 0;
+
+ au8522_writereg(state, 0xa4, 1 << 5);
+
+ au8522_i2c_gate_ctrl(fe, 1);
+
+ return 0;
+}
+EXPORT_SYMBOL(au8522_init);
+
+int au8522_sleep(struct dvb_frontend *fe)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+ dprintk("%s()\n", __func__);
+
+ /* Only power down if the digital side is currently using the chip */
+ if (state->operational_mode == AU8522_ANALOG_MODE) {
+ /* We're not in one of the expected power modes, which means
+ that the DVB thread is probably telling us to go to sleep
+ even though the analog frontend has already started using
+ the chip. So ignore the request */
+ return 0;
+ }
+
+ /* turn off led */
+ au8522_led_ctrl(state, 0);
+
+ /* Power down the chip */
+ au8522_writereg(state, 0xa4, 1 << 5);
+
+ state->current_frequency = 0;
+
+ return 0;
+}
+EXPORT_SYMBOL(au8522_sleep);
diff --git a/drivers/media/dvb/frontends/au8522_dig.c b/drivers/media/dvb/frontends/au8522_dig.c
index 25f650934c73..5fc70d6cd04f 100644
--- a/drivers/media/dvb/frontends/au8522_dig.c
+++ b/drivers/media/dvb/frontends/au8522_dig.c
@@ -30,74 +30,11 @@
static int debug;
-/* Despite the name "hybrid_tuner", the framework works just as well for
- hybrid demodulators as well... */
-static LIST_HEAD(hybrid_tuner_instance_list);
-static DEFINE_MUTEX(au8522_list_mutex);
-
#define dprintk(arg...)\
do { if (debug)\
printk(arg);\
} while (0)
-/* 16 bit registers, 8 bit values */
-int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
-{
- int ret;
- u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data };
-
- struct i2c_msg msg = { .addr = state->config->demod_address,
- .flags = 0, .buf = buf, .len = 3 };
-
- ret = i2c_transfer(state->i2c, &msg, 1);
-
- if (ret != 1)
- printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
- "ret == %i)\n", __func__, reg, data, ret);
-
- return (ret != 1) ? -1 : 0;
-}
-
-u8 au8522_readreg(struct au8522_state *state, u16 reg)
-{
- int ret;
- u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff };
- u8 b1[] = { 0 };
-
- struct i2c_msg msg[] = {
- { .addr = state->config->demod_address, .flags = 0,
- .buf = b0, .len = 2 },
- { .addr = state->config->demod_address, .flags = I2C_M_RD,
- .buf = b1, .len = 1 } };
-
- ret = i2c_transfer(state->i2c, msg, 2);
-
- if (ret != 2)
- printk(KERN_ERR "%s: readreg error (ret == %i)\n",
- __func__, ret);
- return b1[0];
-}
-
-static int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
- struct au8522_state *state = fe->demodulator_priv;
-
- dprintk("%s(%d)\n", __func__, enable);
-
- if (state->operational_mode == AU8522_ANALOG_MODE) {
- /* We're being asked to manage the gate even though we're
- not in digital mode. This can occur if we get switched
- over to analog mode before the dvb_frontend kernel thread
- has completely shutdown */
- return 0;
- }
-
- if (enable)
- return au8522_writereg(state, 0x106, 1);
- else
- return au8522_writereg(state, 0x106, 0);
-}
-
struct mse2snr_tab {
u16 val;
u16 data;
@@ -609,136 +546,6 @@ static int au8522_set_frontend(struct dvb_frontend *fe)
return 0;
}
-/* Reset the demod hardware and reset all of the configuration registers
- to a default state. */
-int au8522_init(struct dvb_frontend *fe)
-{
- struct au8522_state *state = fe->demodulator_priv;
- dprintk("%s()\n", __func__);
-
- state->operational_mode = AU8522_DIGITAL_MODE;
-
- /* Clear out any state associated with the digital side of the
- chip, so that when it gets powered back up it won't think
- that it is already tuned */
- state->current_frequency = 0;
-
- au8522_writereg(state, 0xa4, 1 << 5);
-
- au8522_i2c_gate_ctrl(fe, 1);
-
- return 0;
-}
-
-static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
-{
- struct au8522_led_config *led_config = state->config->led_cfg;
- u8 val;
-
- /* bail out if we can't control an LED */
- if (!led_config || !led_config->gpio_output ||
- !led_config->gpio_output_enable || !led_config->gpio_output_disable)
- return 0;
-
- val = au8522_readreg(state, 0x4000 |
- (led_config->gpio_output & ~0xc000));
- if (onoff) {
- /* enable GPIO output */
- val &= ~((led_config->gpio_output_enable >> 8) & 0xff);
- val |= (led_config->gpio_output_enable & 0xff);
- } else {
- /* disable GPIO output */
- val &= ~((led_config->gpio_output_disable >> 8) & 0xff);
- val |= (led_config->gpio_output_disable & 0xff);
- }
- return au8522_writereg(state, 0x8000 |
- (led_config->gpio_output & ~0xc000), val);
-}
-
-/* led = 0 | off
- * led = 1 | signal ok
- * led = 2 | signal strong
- * led < 0 | only light led if leds are currently off
- */
-static int au8522_led_ctrl(struct au8522_state *state, int led)
-{
- struct au8522_led_config *led_config = state->config->led_cfg;
- int i, ret = 0;
-
- /* bail out if we can't control an LED */
- if (!led_config || !led_config->gpio_leds ||
- !led_config->num_led_states || !led_config->led_states)
- return 0;
-
- if (led < 0) {
- /* if LED is already lit, then leave it as-is */
- if (state->led_state)
- return 0;
- else
- led *= -1;
- }
-
- /* toggle LED if changing state */
- if (state->led_state != led) {
- u8 val;
-
- dprintk("%s: %d\n", __func__, led);
-
- au8522_led_gpio_enable(state, 1);
-
- val = au8522_readreg(state, 0x4000 |
- (led_config->gpio_leds & ~0xc000));
-
- /* start with all leds off */
- for (i = 0; i < led_config->num_led_states; i++)
- val &= ~led_config->led_states[i];
-
- /* set selected LED state */
- if (led < led_config->num_led_states)
- val |= led_config->led_states[led];
- else if (led_config->num_led_states)
- val |=
- led_config->led_states[led_config->num_led_states - 1];
-
- ret = au8522_writereg(state, 0x8000 |
- (led_config->gpio_leds & ~0xc000), val);
- if (ret < 0)
- return ret;
-
- state->led_state = led;
-
- if (led == 0)
- au8522_led_gpio_enable(state, 0);
- }
-
- return 0;
-}
-
-int au8522_sleep(struct dvb_frontend *fe)
-{
- struct au8522_state *state = fe->demodulator_priv;
- dprintk("%s()\n", __func__);
-
- /* Only power down if the digital side is currently using the chip */
- if (state->operational_mode == AU8522_ANALOG_MODE) {
- /* We're not in one of the expected power modes, which means
- that the DVB thread is probably telling us to go to sleep
- even though the analog frontend has already started using
- the chip. So ignore the request */
- return 0;
- }
-
- /* turn off led */
- au8522_led_ctrl(state, 0);
-
- /* Power down the chip */
- au8522_writereg(state, 0xa4, 1 << 5);
-
- state->current_frequency = 0;
-
- return 0;
-}
-
static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
struct au8522_state *state = fe->demodulator_priv;
@@ -931,28 +738,6 @@ static int au8522_get_tune_settings(struct dvb_frontend *fe,
static struct dvb_frontend_ops au8522_ops;
-int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
- u8 client_address)
-{
- int ret;
-
- mutex_lock(&au8522_list_mutex);
- ret = hybrid_tuner_request_state(struct au8522_state, (*state),
- hybrid_tuner_instance_list,
- i2c, client_address, "au8522");
- mutex_unlock(&au8522_list_mutex);
-
- return ret;
-}
-
-void au8522_release_state(struct au8522_state *state)
-{
- mutex_lock(&au8522_list_mutex);
- if (state != NULL)
- hybrid_tuner_release_state(state);
- mutex_unlock(&au8522_list_mutex);
-}
-
static void au8522_release(struct dvb_frontend *fe)
{
diff --git a/drivers/media/dvb/frontends/au8522_priv.h b/drivers/media/dvb/frontends/au8522_priv.h
index 751e17d692a9..6e4a438732b5 100644
--- a/drivers/media/dvb/frontends/au8522_priv.h
+++ b/drivers/media/dvb/frontends/au8522_priv.h
@@ -81,6 +81,8 @@ int au8522_sleep(struct dvb_frontend *fe);
int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
u8 client_address);
void au8522_release_state(struct au8522_state *state);
+int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable);
+int au8522_led_ctrl(struct au8522_state *state, int led);
/* REGISTERS */
#define AU8522_INPUT_CONTROL_REG081H 0x081
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index 5101f10f2d7a..98ecaf0900d6 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -512,14 +512,13 @@ static int cx24110_read_snr(struct dvb_frontend* fe, u16* snr)
static int cx24110_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
{
struct cx24110_state *state = fe->demodulator_priv;
- u32 lastbyer;
if(cx24110_readreg(state,0x10)&0x40) {
/* the RS error counter has finished one counting window */
cx24110_writereg(state,0x10,0x60); /* select the byer reg */
- lastbyer=cx24110_readreg(state,0x12)|
- (cx24110_readreg(state,0x13)<<8)|
- (cx24110_readreg(state,0x14)<<16);
+ cx24110_readreg(state, 0x12) |
+ (cx24110_readreg(state, 0x13) << 8) |
+ (cx24110_readreg(state, 0x14) << 16);
cx24110_writereg(state,0x10,0x70); /* select the bler reg */
state->lastbler=cx24110_readreg(state,0x12)|
(cx24110_readreg(state,0x13)<<8)|
diff --git a/drivers/media/dvb/frontends/cxd2820r_core.c b/drivers/media/dvb/frontends/cxd2820r_core.c
index 5c7c2aaf9bf5..3bba37d74f57 100644
--- a/drivers/media/dvb/frontends/cxd2820r_core.c
+++ b/drivers/media/dvb/frontends/cxd2820r_core.c
@@ -526,12 +526,12 @@ static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe)
if (ret)
goto error;
- if (status & FE_HAS_SIGNAL)
+ if (status & FE_HAS_LOCK)
break;
}
/* check if we have a valid signal */
- if (status) {
+ if (status & FE_HAS_LOCK) {
priv->last_tune_failed = 0;
return DVBFE_ALGO_SEARCH_SUCCESS;
} else {
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
index 5ceadc285b3a..3e1eefada0e8 100644
--- a/drivers/media/dvb/frontends/dib7000p.c
+++ b/drivers/media/dvb/frontends/dib7000p.c
@@ -2396,11 +2396,6 @@ struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
more common) */
st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
- /* FIXME: make sure the dev.parent field is initialized, or else
- request_firmware() will hit an OOPS (this should be moved somewhere
- more common) */
- st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
-
dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
/* init 7090 tuner adapter */
diff --git a/drivers/media/dvb/frontends/dib9000.c b/drivers/media/dvb/frontends/dib9000.c
index 80848b4c15d4..6201c59a78dd 100644
--- a/drivers/media/dvb/frontends/dib9000.c
+++ b/drivers/media/dvb/frontends/dib9000.c
@@ -31,13 +31,6 @@ struct i2c_device {
u8 *i2c_write_buffer;
};
-/* lock */
-#define DIB_LOCK struct mutex
-#define DibAcquireLock(lock) mutex_lock_interruptible(lock)
-#define DibReleaseLock(lock) mutex_unlock(lock)
-#define DibInitLock(lock) mutex_init(lock)
-#define DibFreeLock(lock)
-
struct dib9000_pid_ctrl {
#define DIB9000_PID_FILTER_CTRL 0
#define DIB9000_PID_FILTER 1
@@ -82,11 +75,11 @@ struct dib9000_state {
} fe_mm[18];
u8 memcmd;
- DIB_LOCK mbx_if_lock; /* to protect read/write operations */
- DIB_LOCK mbx_lock; /* to protect the whole mailbox handling */
+ struct mutex mbx_if_lock; /* to protect read/write operations */
+ struct mutex mbx_lock; /* to protect the whole mailbox handling */
- DIB_LOCK mem_lock; /* to protect the memory accesses */
- DIB_LOCK mem_mbx_lock; /* to protect the memory-based mailbox */
+ struct mutex mem_lock; /* to protect the memory accesses */
+ struct mutex mem_mbx_lock; /* to protect the memory-based mailbox */
#define MBX_MAX_WORDS (256 - 200 - 2)
#define DIB9000_MSG_CACHE_SIZE 2
@@ -108,7 +101,7 @@ struct dib9000_state {
struct i2c_msg msg[2];
u8 i2c_write_buffer[255];
u8 i2c_read_buffer[255];
- DIB_LOCK demod_lock;
+ struct mutex demod_lock;
u8 get_frontend_internal;
struct dib9000_pid_ctrl pid_ctrl[10];
s8 pid_ctrl_index; /* -1: empty list; -2: do not use the list */
@@ -446,13 +439,13 @@ static int dib9000_risc_mem_read(struct dib9000_state *state, u8 cmd, u8 * b, u1
if (!state->platform.risc.fw_is_running)
return -EIO;
- if (DibAcquireLock(&state->platform.risc.mem_lock) < 0) {
+ if (mutex_lock_interruptible(&state->platform.risc.mem_lock) < 0) {
dprintk("could not get the lock");
return -EINTR;
}
dib9000_risc_mem_setup(state, cmd | 0x80);
dib9000_risc_mem_read_chunks(state, b, len);
- DibReleaseLock(&state->platform.risc.mem_lock);
+ mutex_unlock(&state->platform.risc.mem_lock);
return 0;
}
@@ -462,13 +455,13 @@ static int dib9000_risc_mem_write(struct dib9000_state *state, u8 cmd, const u8
if (!state->platform.risc.fw_is_running)
return -EIO;
- if (DibAcquireLock(&state->platform.risc.mem_lock) < 0) {
+ if (mutex_lock_interruptible(&state->platform.risc.mem_lock) < 0) {
dprintk("could not get the lock");
return -EINTR;
}
dib9000_risc_mem_setup(state, cmd);
dib9000_risc_mem_write_chunks(state, b, m->size);
- DibReleaseLock(&state->platform.risc.mem_lock);
+ mutex_unlock(&state->platform.risc.mem_lock);
return 0;
}
@@ -537,7 +530,7 @@ static int dib9000_mbx_send_attr(struct dib9000_state *state, u8 id, u16 * data,
if (!state->platform.risc.fw_is_running)
return -EINVAL;
- if (DibAcquireLock(&state->platform.risc.mbx_if_lock) < 0) {
+ if (mutex_lock_interruptible(&state->platform.risc.mbx_if_lock) < 0) {
dprintk("could not get the lock");
return -EINTR;
}
@@ -584,7 +577,7 @@ static int dib9000_mbx_send_attr(struct dib9000_state *state, u8 id, u16 * data,
ret = (u8) dib9000_write_word_attr(state, 1043, 1 << 14, attr);
out:
- DibReleaseLock(&state->platform.risc.mbx_if_lock);
+ mutex_unlock(&state->platform.risc.mbx_if_lock);
return ret;
}
@@ -602,7 +595,7 @@ static u8 dib9000_mbx_read(struct dib9000_state *state, u16 * data, u8 risc_id,
if (!state->platform.risc.fw_is_running)
return 0;
- if (DibAcquireLock(&state->platform.risc.mbx_if_lock) < 0) {
+ if (mutex_lock_interruptible(&state->platform.risc.mbx_if_lock) < 0) {
dprintk("could not get the lock");
return 0;
}
@@ -643,7 +636,7 @@ static u8 dib9000_mbx_read(struct dib9000_state *state, u16 * data, u8 risc_id,
/* Update register nb_mes_in_TX */
dib9000_write_word_attr(state, 1028 + mc_base, 1 << 14, attr);
- DibReleaseLock(&state->platform.risc.mbx_if_lock);
+ mutex_unlock(&state->platform.risc.mbx_if_lock);
return size + 1;
}
@@ -708,12 +701,11 @@ static u8 dib9000_mbx_count(struct dib9000_state *state, u8 risc_id, u16 attr)
static int dib9000_mbx_process(struct dib9000_state *state, u16 attr)
{
int ret = 0;
- u16 tmp;
if (!state->platform.risc.fw_is_running)
return -1;
- if (DibAcquireLock(&state->platform.risc.mbx_lock) < 0) {
+ if (mutex_lock_interruptible(&state->platform.risc.mbx_lock) < 0) {
dprintk("could not get the lock");
return -1;
}
@@ -721,10 +713,10 @@ static int dib9000_mbx_process(struct dib9000_state *state, u16 attr)
if (dib9000_mbx_count(state, 1, attr)) /* 1=RiscB */
ret = dib9000_mbx_fetch_to_cache(state, attr);
- tmp = dib9000_read_word_attr(state, 1229, attr); /* Clear the IRQ */
+ dib9000_read_word_attr(state, 1229, attr); /* Clear the IRQ */
/* if (tmp) */
/* dprintk( "cleared IRQ: %x", tmp); */
- DibReleaseLock(&state->platform.risc.mbx_lock);
+ mutex_unlock(&state->platform.risc.mbx_lock);
return ret;
}
@@ -1193,7 +1185,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe)
struct dibDVBTChannel *ch;
int ret = 0;
- if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+ if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
dprintk("could not get the lock");
return -EINTR;
}
@@ -1323,7 +1315,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe)
}
error:
- DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+ mutex_unlock(&state->platform.risc.mem_mbx_lock);
return ret;
}
@@ -1678,7 +1670,7 @@ static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2
p[12] = 0;
}
- if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+ if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
dprintk("could not get the lock");
return 0;
}
@@ -1692,7 +1684,7 @@ static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2
/* do the transaction */
if (dib9000_fw_memmbx_sync(state, FE_SYNC_COMPONENT_ACCESS) < 0) {
- DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+ mutex_unlock(&state->platform.risc.mem_mbx_lock);
return 0;
}
@@ -1700,7 +1692,7 @@ static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2
if ((num > 1) && (msg[1].flags & I2C_M_RD))
dib9000_risc_mem_read(state, FE_MM_RW_COMPONENT_ACCESS_BUFFER, msg[1].buf, msg[1].len);
- DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+ mutex_unlock(&state->platform.risc.mem_mbx_lock);
return num;
}
@@ -1789,7 +1781,7 @@ int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
return 0;
}
- if (DibAcquireLock(&state->demod_lock) < 0) {
+ if (mutex_lock_interruptible(&state->demod_lock) < 0) {
dprintk("could not get the lock");
return -EINTR;
}
@@ -1799,7 +1791,7 @@ int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
dprintk("PID filter enabled %d", onoff);
ret = dib9000_write_word(state, 294 + 1, val);
- DibReleaseLock(&state->demod_lock);
+ mutex_unlock(&state->demod_lock);
return ret;
}
@@ -1824,14 +1816,14 @@ int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
return 0;
}
- if (DibAcquireLock(&state->demod_lock) < 0) {
+ if (mutex_lock_interruptible(&state->demod_lock) < 0) {
dprintk("could not get the lock");
return -EINTR;
}
dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
ret = dib9000_write_word(state, 300 + 1 + id,
onoff ? (1 << 13) | pid : 0);
- DibReleaseLock(&state->demod_lock);
+ mutex_unlock(&state->demod_lock);
return ret;
}
EXPORT_SYMBOL(dib9000_fw_pid_filter);
@@ -1851,11 +1843,6 @@ static void dib9000_release(struct dvb_frontend *demod)
for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (st->fe[index_frontend] != NULL); index_frontend++)
dvb_frontend_detach(st->fe[index_frontend]);
- DibFreeLock(&state->platform.risc.mbx_if_lock);
- DibFreeLock(&state->platform.risc.mbx_lock);
- DibFreeLock(&state->platform.risc.mem_lock);
- DibFreeLock(&state->platform.risc.mem_mbx_lock);
- DibFreeLock(&state->demod_lock);
dibx000_exit_i2c_master(&st->i2c_master);
i2c_del_adapter(&st->tuner_adap);
@@ -1875,7 +1862,7 @@ static int dib9000_sleep(struct dvb_frontend *fe)
u8 index_frontend;
int ret = 0;
- if (DibAcquireLock(&state->demod_lock) < 0) {
+ if (mutex_lock_interruptible(&state->demod_lock) < 0) {
dprintk("could not get the lock");
return -EINTR;
}
@@ -1887,7 +1874,7 @@ static int dib9000_sleep(struct dvb_frontend *fe)
ret = dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0);
error:
- DibReleaseLock(&state->demod_lock);
+ mutex_unlock(&state->demod_lock);
return ret;
}
@@ -1905,7 +1892,7 @@ static int dib9000_get_frontend(struct dvb_frontend *fe)
int ret = 0;
if (state->get_frontend_internal == 0) {
- if (DibAcquireLock(&state->demod_lock) < 0) {
+ if (mutex_lock_interruptible(&state->demod_lock) < 0) {
dprintk("could not get the lock");
return -EINTR;
}
@@ -1964,7 +1951,7 @@ static int dib9000_get_frontend(struct dvb_frontend *fe)
return_value:
if (state->get_frontend_internal == 0)
- DibReleaseLock(&state->demod_lock);
+ mutex_unlock(&state->demod_lock);
return ret;
}
@@ -2012,7 +1999,7 @@ static int dib9000_set_frontend(struct dvb_frontend *fe)
}
state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */
- if (DibAcquireLock(&state->demod_lock) < 0) {
+ if (mutex_lock_interruptible(&state->demod_lock) < 0) {
dprintk("could not get the lock");
return 0;
}
@@ -2081,7 +2068,7 @@ static int dib9000_set_frontend(struct dvb_frontend *fe)
/* check the tune result */
if (exit_condition == 1) { /* tune failed */
dprintk("tune failed");
- DibReleaseLock(&state->demod_lock);
+ mutex_unlock(&state->demod_lock);
/* tune failed; put all the pid filtering cmd to junk */
state->pid_ctrl_index = -1;
return 0;
@@ -2137,7 +2124,7 @@ static int dib9000_set_frontend(struct dvb_frontend *fe)
/* turn off the diversity for the last frontend */
dib9000_fw_set_diversity_in(state->fe[index_frontend - 1], 0);
- DibReleaseLock(&state->demod_lock);
+ mutex_unlock(&state->demod_lock);
if (state->pid_ctrl_index >= 0) {
u8 index_pid_filter_cmd;
u8 pid_ctrl_index = state->pid_ctrl_index;
@@ -2175,7 +2162,7 @@ static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
u8 index_frontend;
u16 lock = 0, lock_slave = 0;
- if (DibAcquireLock(&state->demod_lock) < 0) {
+ if (mutex_lock_interruptible(&state->demod_lock) < 0) {
dprintk("could not get the lock");
return -EINTR;
}
@@ -2197,7 +2184,7 @@ static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
if ((lock & 0x0008) || (lock_slave & 0x0008))
*stat |= FE_HAS_LOCK;
- DibReleaseLock(&state->demod_lock);
+ mutex_unlock(&state->demod_lock);
return 0;
}
@@ -2208,30 +2195,30 @@ static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber)
u16 *c;
int ret = 0;
- if (DibAcquireLock(&state->demod_lock) < 0) {
+ if (mutex_lock_interruptible(&state->demod_lock) < 0) {
dprintk("could not get the lock");
return -EINTR;
}
- if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+ if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
dprintk("could not get the lock");
ret = -EINTR;
goto error;
}
if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
- DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+ mutex_unlock(&state->platform.risc.mem_mbx_lock);
ret = -EIO;
goto error;
}
dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR,
state->i2c_read_buffer, 16 * 2);
- DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+ mutex_unlock(&state->platform.risc.mem_mbx_lock);
c = (u16 *)state->i2c_read_buffer;
*ber = c[10] << 16 | c[11];
error:
- DibReleaseLock(&state->demod_lock);
+ mutex_unlock(&state->demod_lock);
return ret;
}
@@ -2243,7 +2230,7 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
u16 val;
int ret = 0;
- if (DibAcquireLock(&state->demod_lock) < 0) {
+ if (mutex_lock_interruptible(&state->demod_lock) < 0) {
dprintk("could not get the lock");
return -EINTR;
}
@@ -2256,18 +2243,18 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
*strength += val;
}
- if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+ if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
dprintk("could not get the lock");
ret = -EINTR;
goto error;
}
if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
- DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+ mutex_unlock(&state->platform.risc.mem_mbx_lock);
ret = -EIO;
goto error;
}
dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
- DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+ mutex_unlock(&state->platform.risc.mem_mbx_lock);
val = 65535 - c[4];
if (val > 65535 - *strength)
@@ -2276,7 +2263,7 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
*strength += val;
error:
- DibReleaseLock(&state->demod_lock);
+ mutex_unlock(&state->demod_lock);
return ret;
}
@@ -2287,16 +2274,16 @@ static u32 dib9000_get_snr(struct dvb_frontend *fe)
u32 n, s, exp;
u16 val;
- if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+ if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
dprintk("could not get the lock");
return 0;
}
if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
- DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+ mutex_unlock(&state->platform.risc.mem_mbx_lock);
return 0;
}
dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
- DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+ mutex_unlock(&state->platform.risc.mem_mbx_lock);
val = c[7];
n = (val >> 4) & 0xff;
@@ -2326,7 +2313,7 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr)
u8 index_frontend;
u32 snr_master;
- if (DibAcquireLock(&state->demod_lock) < 0) {
+ if (mutex_lock_interruptible(&state->demod_lock) < 0) {
dprintk("could not get the lock");
return -EINTR;
}
@@ -2340,7 +2327,7 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr)
} else
*snr = 0;
- DibReleaseLock(&state->demod_lock);
+ mutex_unlock(&state->demod_lock);
return 0;
}
@@ -2351,27 +2338,27 @@ static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
u16 *c = (u16 *)state->i2c_read_buffer;
int ret = 0;
- if (DibAcquireLock(&state->demod_lock) < 0) {
+ if (mutex_lock_interruptible(&state->demod_lock) < 0) {
dprintk("could not get the lock");
return -EINTR;
}
- if (DibAcquireLock(&state->platform.risc.mem_mbx_lock) < 0) {
+ if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) {
dprintk("could not get the lock");
ret = -EINTR;
goto error;
}
if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
- DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+ mutex_unlock(&state->platform.risc.mem_mbx_lock);
ret = -EIO;
goto error;
}
dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
- DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+ mutex_unlock(&state->platform.risc.mem_mbx_lock);
*unc = c[12];
error:
- DibReleaseLock(&state->demod_lock);
+ mutex_unlock(&state->demod_lock);
return ret;
}
@@ -2514,11 +2501,11 @@ struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, c
st->gpio_val = DIB9000_GPIO_DEFAULT_VALUES;
st->gpio_pwm_pos = DIB9000_GPIO_DEFAULT_PWM_POS;
- DibInitLock(&st->platform.risc.mbx_if_lock);
- DibInitLock(&st->platform.risc.mbx_lock);
- DibInitLock(&st->platform.risc.mem_lock);
- DibInitLock(&st->platform.risc.mem_mbx_lock);
- DibInitLock(&st->demod_lock);
+ mutex_init(&st->platform.risc.mbx_if_lock);
+ mutex_init(&st->platform.risc.mbx_lock);
+ mutex_init(&st->platform.risc.mem_lock);
+ mutex_init(&st->platform.risc.mem_mbx_lock);
+ mutex_init(&st->demod_lock);
st->get_frontend_internal = 0;
st->pid_ctrl_index = -2;
diff --git a/drivers/media/dvb/frontends/drxd.h b/drivers/media/dvb/frontends/drxd.h
index 34398738f9bc..216c8c3702f8 100644
--- a/drivers/media/dvb/frontends/drxd.h
+++ b/drivers/media/dvb/frontends/drxd.h
@@ -51,9 +51,23 @@ struct drxd_config {
s16(*osc_deviation) (void *priv, s16 dev, int flag);
};
+#if defined(CONFIG_DVB_DRXD) || \
+ (defined(CONFIG_DVB_DRXD_MODULE) && defined(MODULE))
extern
struct dvb_frontend *drxd_attach(const struct drxd_config *config,
void *priv, struct i2c_adapter *i2c,
struct device *dev);
+#else
+static inline
+struct dvb_frontend *drxd_attach(const struct drxd_config *config,
+ void *priv, struct i2c_adapter *i2c,
+ struct device *dev)
+{
+ printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
+ __func__);
+ return NULL;
+}
+#endif
+
extern int drxd_config_i2c(struct dvb_frontend *, int);
#endif
diff --git a/drivers/media/dvb/frontends/drxk_hard.c b/drivers/media/dvb/frontends/drxk_hard.c
index a414b1f2b6a5..60b868faeacf 100644
--- a/drivers/media/dvb/frontends/drxk_hard.c
+++ b/drivers/media/dvb/frontends/drxk_hard.c
@@ -1380,20 +1380,20 @@ static int DownloadMicrocode(struct drxk_state *state,
const u8 pMCImage[], u32 Length)
{
const u8 *pSrc = pMCImage;
- u16 Flags;
- u16 Drain;
u32 Address;
u16 nBlocks;
u16 BlockSize;
- u16 BlockCRC;
u32 offset = 0;
u32 i;
int status = 0;
dprintk(1, "\n");
- /* down the drain (we don care about MAGIC_WORD) */
+ /* down the drain (we don't care about MAGIC_WORD) */
+#if 0
+ /* For future reference */
Drain = (pSrc[0] << 8) | pSrc[1];
+#endif
pSrc += sizeof(u16);
offset += sizeof(u16);
nBlocks = (pSrc[0] << 8) | pSrc[1];
@@ -1410,11 +1410,17 @@ static int DownloadMicrocode(struct drxk_state *state,
pSrc += sizeof(u16);
offset += sizeof(u16);
+#if 0
+ /* For future reference */
Flags = (pSrc[0] << 8) | pSrc[1];
+#endif
pSrc += sizeof(u16);
offset += sizeof(u16);
+#if 0
+ /* For future reference */
BlockCRC = (pSrc[0] << 8) | pSrc[1];
+#endif
pSrc += sizeof(u16);
offset += sizeof(u16);
@@ -5829,7 +5835,7 @@ static int WriteGPIO(struct drxk_state *state)
}
if (state->UIO_mask & 0x0002) { /* UIO-2 */
/* write to io pad configuration register - output mode */
- status = write16(state, SIO_PDR_SMA_TX_CFG__A, state->m_GPIOCfg);
+ status = write16(state, SIO_PDR_SMA_RX_CFG__A, state->m_GPIOCfg);
if (status < 0)
goto error;
@@ -5848,7 +5854,7 @@ static int WriteGPIO(struct drxk_state *state)
}
if (state->UIO_mask & 0x0004) { /* UIO-3 */
/* write to io pad configuration register - output mode */
- status = write16(state, SIO_PDR_SMA_TX_CFG__A, state->m_GPIOCfg);
+ status = write16(state, SIO_PDR_GPIO_CFG__A, state->m_GPIOCfg);
if (status < 0)
goto error;
diff --git a/drivers/media/dvb/frontends/drxk_map.h b/drivers/media/dvb/frontends/drxk_map.h
index 9b11a8328869..23e16c12f234 100644
--- a/drivers/media/dvb/frontends/drxk_map.h
+++ b/drivers/media/dvb/frontends/drxk_map.h
@@ -432,6 +432,7 @@
#define SIO_PDR_UIO_OUT_LO__A 0x7F0016
#define SIO_PDR_OHW_CFG__A 0x7F001F
#define SIO_PDR_OHW_CFG_FREF_SEL__M 0x3
+#define SIO_PDR_GPIO_CFG__A 0x7F0021
#define SIO_PDR_MSTRT_CFG__A 0x7F0025
#define SIO_PDR_MERR_CFG__A 0x7F0026
#define SIO_PDR_MCLK_CFG__A 0x7F0028
@@ -446,4 +447,5 @@
#define SIO_PDR_MD5_CFG__A 0x7F0030
#define SIO_PDR_MD6_CFG__A 0x7F0031
#define SIO_PDR_MD7_CFG__A 0x7F0032
+#define SIO_PDR_SMA_RX_CFG__A 0x7F0037
#define SIO_PDR_SMA_TX_CFG__A 0x7F0038
diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c
index af65d013db11..4c8ac2657c4a 100644
--- a/drivers/media/dvb/frontends/ds3000.c
+++ b/drivers/media/dvb/frontends/ds3000.c
@@ -1114,7 +1114,10 @@ static int ds3000_set_frontend(struct dvb_frontend *fe)
ds3000_writereg(state,
ds3000_dvbs2_init_tab[i],
ds3000_dvbs2_init_tab[i + 1]);
- ds3000_writereg(state, 0xfe, 0x98);
+ if (c->symbol_rate >= 30000000)
+ ds3000_writereg(state, 0xfe, 0x54);
+ else
+ ds3000_writereg(state, 0xfe, 0x98);
break;
default:
return 1;
diff --git a/drivers/media/dvb/frontends/it913x-fe.c b/drivers/media/dvb/frontends/it913x-fe.c
index 84df03c29179..708cbf197913 100644
--- a/drivers/media/dvb/frontends/it913x-fe.c
+++ b/drivers/media/dvb/frontends/it913x-fe.c
@@ -633,10 +633,9 @@ static int it913x_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
static int it913x_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
{
struct it913x_fe_state *state = fe->demodulator_priv;
- int ret;
u8 reg[5];
/* Read Aborted Packets and Pre-Viterbi error rate 5 bytes */
- ret = it913x_read_reg(state, RSD_ABORT_PKT_LSB, reg, sizeof(reg));
+ it913x_read_reg(state, RSD_ABORT_PKT_LSB, reg, sizeof(reg));
state->ucblocks += (u32)(reg[1] << 8) | reg[0];
*ber = (u32)(reg[4] << 16) | (reg[3] << 8) | reg[2];
return 0;
@@ -658,10 +657,9 @@ static int it913x_fe_get_frontend(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct it913x_fe_state *state = fe->demodulator_priv;
- int ret;
u8 reg[8];
- ret = it913x_read_reg(state, REG_TPSD_TX_MODE, reg, sizeof(reg));
+ it913x_read_reg(state, REG_TPSD_TX_MODE, reg, sizeof(reg));
if (reg[3] < 3)
p->modulation = fe_con[reg[3]];
@@ -691,25 +689,25 @@ static int it913x_fe_set_frontend(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct it913x_fe_state *state = fe->demodulator_priv;
- int ret, i;
+ int i;
u8 empty_ch, last_ch;
state->it913x_status = 0;
/* Set bw*/
- ret = it913x_fe_select_bw(state, p->bandwidth_hz,
+ it913x_fe_select_bw(state, p->bandwidth_hz,
state->adcFrequency);
/* Training Mode Off */
- ret = it913x_write_reg(state, PRO_LINK, TRAINING_MODE, 0x0);
+ it913x_write_reg(state, PRO_LINK, TRAINING_MODE, 0x0);
/* Clear Empty Channel */
- ret = it913x_write_reg(state, PRO_DMOD, EMPTY_CHANNEL_STATUS, 0x0);
+ it913x_write_reg(state, PRO_DMOD, EMPTY_CHANNEL_STATUS, 0x0);
/* Clear bits */
- ret = it913x_write_reg(state, PRO_DMOD, MP2IF_SYNC_LK, 0x0);
+ it913x_write_reg(state, PRO_DMOD, MP2IF_SYNC_LK, 0x0);
/* LED on */
- ret = it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1);
+ it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x1);
/* Select Band*/
if ((p->frequency >= 51000000) && (p->frequency <= 230000000))
i = 0;
@@ -720,7 +718,7 @@ static int it913x_fe_set_frontend(struct dvb_frontend *fe)
else
return -EOPNOTSUPP;
- ret = it913x_write_reg(state, PRO_DMOD, FREE_BAND, i);
+ it913x_write_reg(state, PRO_DMOD, FREE_BAND, i);
deb_info("Frontend Set Tuner Type %02x", state->tuner_type);
switch (state->tuner_type) {
@@ -730,7 +728,7 @@ static int it913x_fe_set_frontend(struct dvb_frontend *fe)
case IT9135_60:
case IT9135_61:
case IT9135_62:
- ret = it9137_set_tuner(state,
+ it9137_set_tuner(state,
p->bandwidth_hz, p->frequency);
break;
default:
@@ -742,9 +740,9 @@ static int it913x_fe_set_frontend(struct dvb_frontend *fe)
break;
}
/* LED off */
- ret = it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0);
+ it913x_write_reg(state, PRO_LINK, GPIOH3_O, 0x0);
/* Trigger ofsm */
- ret = it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0);
+ it913x_write_reg(state, PRO_DMOD, TRIGGER_OFSM, 0x0);
last_ch = 2;
for (i = 0; i < 40; ++i) {
empty_ch = it913x_read_reg_u8(state, EMPTY_CHANNEL_STATUS);
diff --git a/drivers/media/dvb/frontends/lg2160.c b/drivers/media/dvb/frontends/lg2160.c
new file mode 100644
index 000000000000..a3ab1a5b6597
--- /dev/null
+++ b/drivers/media/dvb/frontends/lg2160.c
@@ -0,0 +1,1468 @@
+/*
+ * Support for LG2160 - ATSC/MH
+ *
+ * Copyright (C) 2010 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/jiffies.h>
+#include <linux/dvb/frontend.h>
+#include "lg2160.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))");
+
+#define DBG_INFO 1
+#define DBG_REG 2
+
+#define lg_printk(kern, fmt, arg...) \
+ printk(kern "%s: " fmt, __func__, ##arg)
+
+#define lg_info(fmt, arg...) printk(KERN_INFO "lg2160: " fmt, ##arg)
+#define lg_warn(fmt, arg...) lg_printk(KERN_WARNING, fmt, ##arg)
+#define lg_err(fmt, arg...) lg_printk(KERN_ERR, fmt, ##arg)
+#define lg_dbg(fmt, arg...) if (debug & DBG_INFO) \
+ lg_printk(KERN_DEBUG, fmt, ##arg)
+#define lg_reg(fmt, arg...) if (debug & DBG_REG) \
+ lg_printk(KERN_DEBUG, fmt, ##arg)
+
+#define lg_fail(ret) \
+({ \
+ int __ret; \
+ __ret = (ret < 0); \
+ if (__ret) \
+ lg_err("error %d on line %d\n", ret, __LINE__); \
+ __ret; \
+})
+
+struct lg216x_state {
+ struct i2c_adapter *i2c_adap;
+ const struct lg2160_config *cfg;
+
+ struct dvb_frontend frontend;
+
+ u32 current_frequency;
+ u8 parade_id;
+ u8 fic_ver;
+ unsigned int last_reset;
+};
+
+/* ------------------------------------------------------------------------ */
+
+static int lg216x_write_reg(struct lg216x_state *state, u16 reg, u8 val)
+{
+ int ret;
+ u8 buf[] = { reg >> 8, reg & 0xff, val };
+ struct i2c_msg msg = {
+ .addr = state->cfg->i2c_addr, .flags = 0,
+ .buf = buf, .len = 3,
+ };
+
+ lg_reg("reg: 0x%04x, val: 0x%02x\n", reg, val);
+
+ ret = i2c_transfer(state->i2c_adap, &msg, 1);
+
+ if (ret != 1) {
+ lg_err("error (addr %02x %02x <- %02x, err = %i)\n",
+ msg.buf[0], msg.buf[1], msg.buf[2], ret);
+ if (ret < 0)
+ return ret;
+ else
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int lg216x_read_reg(struct lg216x_state *state, u16 reg, u8 *val)
+{
+ int ret;
+ u8 reg_buf[] = { reg >> 8, reg & 0xff };
+ struct i2c_msg msg[] = {
+ { .addr = state->cfg->i2c_addr,
+ .flags = 0, .buf = reg_buf, .len = 2 },
+ { .addr = state->cfg->i2c_addr,
+ .flags = I2C_M_RD, .buf = val, .len = 1 },
+ };
+
+ lg_reg("reg: 0x%04x\n", reg);
+
+ ret = i2c_transfer(state->i2c_adap, msg, 2);
+
+ if (ret != 2) {
+ lg_err("error (addr %02x reg %04x error (ret == %i)\n",
+ state->cfg->i2c_addr, reg, ret);
+ if (ret < 0)
+ return ret;
+ else
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+struct lg216x_reg {
+ u16 reg;
+ u8 val;
+};
+
+static int lg216x_write_regs(struct lg216x_state *state,
+ struct lg216x_reg *regs, int len)
+{
+ int i, ret;
+
+ lg_reg("writing %d registers...\n", len);
+
+ for (i = 0; i < len - 1; i++) {
+ ret = lg216x_write_reg(state, regs[i].reg, regs[i].val);
+ if (lg_fail(ret))
+ return ret;
+ }
+ return 0;
+}
+
+static int lg216x_set_reg_bit(struct lg216x_state *state,
+ u16 reg, int bit, int onoff)
+{
+ u8 val;
+ int ret;
+
+ lg_reg("reg: 0x%04x, bit: %d, level: %d\n", reg, bit, onoff);
+
+ ret = lg216x_read_reg(state, reg, &val);
+ if (lg_fail(ret))
+ goto fail;
+
+ val &= ~(1 << bit);
+ val |= (onoff & 1) << bit;
+
+ ret = lg216x_write_reg(state, reg, val);
+ lg_fail(ret);
+fail:
+ return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg216x_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+ struct lg216x_state *state = fe->demodulator_priv;
+ int ret;
+
+ if (state->cfg->deny_i2c_rptr)
+ return 0;
+
+ lg_dbg("(%d)\n", enable);
+
+ ret = lg216x_set_reg_bit(state, 0x0000, 0, enable ? 0 : 1);
+
+ msleep(1);
+
+ return ret;
+}
+
+static int lg216x_soft_reset(struct lg216x_state *state)
+{
+ int ret;
+
+ lg_dbg("\n");
+
+ ret = lg216x_write_reg(state, 0x0002, 0x00);
+ if (lg_fail(ret))
+ goto fail;
+
+ msleep(20);
+ ret = lg216x_write_reg(state, 0x0002, 0x01);
+ if (lg_fail(ret))
+ goto fail;
+
+ state->last_reset = jiffies_to_msecs(jiffies);
+fail:
+ return ret;
+}
+
+static int lg216x_initialize(struct lg216x_state *state)
+{
+ int ret;
+
+ static struct lg216x_reg lg2160_init[] = {
+#if 0
+ { .reg = 0x0015, .val = 0xe6 },
+#else
+ { .reg = 0x0015, .val = 0xf7 },
+ { .reg = 0x001b, .val = 0x52 },
+ { .reg = 0x0208, .val = 0x00 },
+ { .reg = 0x0209, .val = 0x82 },
+ { .reg = 0x0210, .val = 0xf9 },
+ { .reg = 0x020a, .val = 0x00 },
+ { .reg = 0x020b, .val = 0x82 },
+ { .reg = 0x020d, .val = 0x28 },
+ { .reg = 0x020f, .val = 0x14 },
+#endif
+ };
+
+ static struct lg216x_reg lg2161_init[] = {
+ { .reg = 0x0000, .val = 0x41 },
+ { .reg = 0x0001, .val = 0xfb },
+ { .reg = 0x0216, .val = 0x00 },
+ { .reg = 0x0219, .val = 0x00 },
+ { .reg = 0x021b, .val = 0x55 },
+ { .reg = 0x0606, .val = 0x0a },
+ };
+
+ switch (state->cfg->lg_chip) {
+ case LG2160:
+ ret = lg216x_write_regs(state,
+ lg2160_init, ARRAY_SIZE(lg2160_init));
+ break;
+ case LG2161:
+ ret = lg216x_write_regs(state,
+ lg2161_init, ARRAY_SIZE(lg2161_init));
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (lg_fail(ret))
+ goto fail;
+
+ ret = lg216x_soft_reset(state);
+ lg_fail(ret);
+fail:
+ return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg216x_set_if(struct lg216x_state *state)
+{
+ u8 val;
+ int ret;
+
+ lg_dbg("%d KHz\n", state->cfg->if_khz);
+
+ ret = lg216x_read_reg(state, 0x0132, &val);
+ if (lg_fail(ret))
+ goto fail;
+
+ val &= 0xfb;
+ val |= (0 == state->cfg->if_khz) ? 0x04 : 0x00;
+
+ ret = lg216x_write_reg(state, 0x0132, val);
+ lg_fail(ret);
+
+ /* if NOT zero IF, 6 MHz is the default */
+fail:
+ return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg2160_agc_fix(struct lg216x_state *state,
+ int if_agc_fix, int rf_agc_fix)
+{
+ u8 val;
+ int ret;
+
+ ret = lg216x_read_reg(state, 0x0100, &val);
+ if (lg_fail(ret))
+ goto fail;
+
+ val &= 0xf3;
+ val |= (if_agc_fix) ? 0x08 : 0x00;
+ val |= (rf_agc_fix) ? 0x04 : 0x00;
+
+ ret = lg216x_write_reg(state, 0x0100, val);
+ lg_fail(ret);
+fail:
+ return ret;
+}
+
+#if 0
+static int lg2160_agc_freeze(struct lg216x_state *state,
+ int if_agc_freeze, int rf_agc_freeze)
+{
+ u8 val;
+ int ret;
+
+ ret = lg216x_read_reg(state, 0x0100, &val);
+ if (lg_fail(ret))
+ goto fail;
+
+ val &= 0xcf;
+ val |= (if_agc_freeze) ? 0x20 : 0x00;
+ val |= (rf_agc_freeze) ? 0x10 : 0x00;
+
+ ret = lg216x_write_reg(state, 0x0100, val);
+ lg_fail(ret);
+fail:
+ return ret;
+}
+#endif
+
+static int lg2160_agc_polarity(struct lg216x_state *state,
+ int if_agc_polarity, int rf_agc_polarity)
+{
+ u8 val;
+ int ret;
+
+ ret = lg216x_read_reg(state, 0x0100, &val);
+ if (lg_fail(ret))
+ goto fail;
+
+ val &= 0xfc;
+ val |= (if_agc_polarity) ? 0x02 : 0x00;
+ val |= (rf_agc_polarity) ? 0x01 : 0x00;
+
+ ret = lg216x_write_reg(state, 0x0100, val);
+ lg_fail(ret);
+fail:
+ return ret;
+}
+
+static int lg2160_tuner_pwr_save_polarity(struct lg216x_state *state,
+ int polarity)
+{
+ u8 val;
+ int ret;
+
+ ret = lg216x_read_reg(state, 0x0008, &val);
+ if (lg_fail(ret))
+ goto fail;
+
+ val &= 0xfe;
+ val |= (polarity) ? 0x01 : 0x00;
+
+ ret = lg216x_write_reg(state, 0x0008, val);
+ lg_fail(ret);
+fail:
+ return ret;
+}
+
+static int lg2160_spectrum_polarity(struct lg216x_state *state,
+ int inverted)
+{
+ u8 val;
+ int ret;
+
+ ret = lg216x_read_reg(state, 0x0132, &val);
+ if (lg_fail(ret))
+ goto fail;
+
+ val &= 0xfd;
+ val |= (inverted) ? 0x02 : 0x00;
+
+ ret = lg216x_write_reg(state, 0x0132, val);
+ lg_fail(ret);
+fail:
+ return lg216x_soft_reset(state);
+}
+
+static int lg2160_tuner_pwr_save(struct lg216x_state *state, int onoff)
+{
+ u8 val;
+ int ret;
+
+ ret = lg216x_read_reg(state, 0x0007, &val);
+ if (lg_fail(ret))
+ goto fail;
+
+ val &= 0xbf;
+ val |= (onoff) ? 0x40 : 0x00;
+
+ ret = lg216x_write_reg(state, 0x0007, val);
+ lg_fail(ret);
+fail:
+ return ret;
+}
+
+static int lg216x_set_parade(struct lg216x_state *state, int id)
+{
+ int ret;
+
+ ret = lg216x_write_reg(state, 0x013e, id & 0x7f);
+ if (lg_fail(ret))
+ goto fail;
+
+ state->parade_id = id & 0x7f;
+fail:
+ return ret;
+}
+
+static int lg216x_set_ensemble(struct lg216x_state *state, int id)
+{
+ int ret;
+ u16 reg;
+ u8 val;
+
+ switch (state->cfg->lg_chip) {
+ case LG2160:
+ reg = 0x0400;
+ break;
+ case LG2161:
+ default:
+ reg = 0x0500;
+ break;
+ }
+
+ ret = lg216x_read_reg(state, reg, &val);
+ if (lg_fail(ret))
+ goto fail;
+
+ val &= 0xfe;
+ val |= (id) ? 0x01 : 0x00;
+
+ ret = lg216x_write_reg(state, reg, val);
+ lg_fail(ret);
+fail:
+ return ret;
+}
+
+static int lg2160_set_spi_clock(struct lg216x_state *state)
+{
+ u8 val;
+ int ret;
+
+ ret = lg216x_read_reg(state, 0x0014, &val);
+ if (lg_fail(ret))
+ goto fail;
+
+ val &= 0xf3;
+ val |= (state->cfg->spi_clock << 2);
+
+ ret = lg216x_write_reg(state, 0x0014, val);
+ lg_fail(ret);
+fail:
+ return ret;
+}
+
+static int lg2161_set_output_interface(struct lg216x_state *state)
+{
+ u8 val;
+ int ret;
+
+ ret = lg216x_read_reg(state, 0x0014, &val);
+ if (lg_fail(ret))
+ goto fail;
+
+ val &= ~0x07;
+ val |= state->cfg->output_if; /* FIXME: needs sanity check */
+
+ ret = lg216x_write_reg(state, 0x0014, val);
+ lg_fail(ret);
+fail:
+ return ret;
+}
+
+static int lg216x_enable_fic(struct lg216x_state *state, int onoff)
+{
+ int ret;
+
+ ret = lg216x_write_reg(state, 0x0017, 0x23);
+ if (lg_fail(ret))
+ goto fail;
+
+ ret = lg216x_write_reg(state, 0x0016, 0xfc);
+ if (lg_fail(ret))
+ goto fail;
+
+ switch (state->cfg->lg_chip) {
+ case LG2160:
+ ret = lg216x_write_reg(state, 0x0016,
+ 0xfc | ((onoff) ? 0x02 : 0x00));
+ break;
+ case LG2161:
+ ret = lg216x_write_reg(state, 0x0016, (onoff) ? 0x10 : 0x00);
+ break;
+ }
+ if (lg_fail(ret))
+ goto fail;
+
+ ret = lg216x_initialize(state);
+ if (lg_fail(ret))
+ goto fail;
+
+ if (onoff) {
+ ret = lg216x_write_reg(state, 0x0017, 0x03);
+ lg_fail(ret);
+ }
+fail:
+ return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg216x_get_fic_version(struct lg216x_state *state, u8 *ficver)
+{
+ u8 val;
+ int ret;
+
+ *ficver = 0xff; /* invalid value */
+
+ ret = lg216x_read_reg(state, 0x0128, &val);
+ if (lg_fail(ret))
+ goto fail;
+
+ *ficver = (val >> 3) & 0x1f;
+fail:
+ return ret;
+}
+
+#if 0
+static int lg2160_get_parade_id(struct lg216x_state *state, u8 *id)
+{
+ u8 val;
+ int ret;
+
+ *id = 0xff; /* invalid value */
+
+ ret = lg216x_read_reg(state, 0x0123, &val);
+ if (lg_fail(ret))
+ goto fail;
+
+ *id = val & 0x7f;
+fail:
+ return ret;
+}
+#endif
+
+static int lg216x_get_nog(struct lg216x_state *state, u8 *nog)
+{
+ u8 val;
+ int ret;
+
+ *nog = 0xff; /* invalid value */
+
+ ret = lg216x_read_reg(state, 0x0124, &val);
+ if (lg_fail(ret))
+ goto fail;
+
+ *nog = ((val >> 4) & 0x07) + 1;
+fail:
+ return ret;
+}
+
+static int lg216x_get_tnog(struct lg216x_state *state, u8 *tnog)
+{
+ u8 val;
+ int ret;
+
+ *tnog = 0xff; /* invalid value */
+
+ ret = lg216x_read_reg(state, 0x0125, &val);
+ if (lg_fail(ret))
+ goto fail;
+
+ *tnog = val & 0x1f;
+fail:
+ return ret;
+}
+
+static int lg216x_get_sgn(struct lg216x_state *state, u8 *sgn)
+{
+ u8 val;
+ int ret;
+
+ *sgn = 0xff; /* invalid value */
+
+ ret = lg216x_read_reg(state, 0x0124, &val);
+ if (lg_fail(ret))
+ goto fail;
+
+ *sgn = val & 0x0f;
+fail:
+ return ret;
+}
+
+static int lg216x_get_prc(struct lg216x_state *state, u8 *prc)
+{
+ u8 val;
+ int ret;
+
+ *prc = 0xff; /* invalid value */
+
+ ret = lg216x_read_reg(state, 0x0125, &val);
+ if (lg_fail(ret))
+ goto fail;
+
+ *prc = ((val >> 5) & 0x07) + 1;
+fail:
+ return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg216x_get_rs_frame_mode(struct lg216x_state *state,
+ enum atscmh_rs_frame_mode *rs_framemode)
+{
+ u8 val;
+ int ret;
+
+ switch (state->cfg->lg_chip) {
+ case LG2160:
+ ret = lg216x_read_reg(state, 0x0410, &val);
+ break;
+ case LG2161:
+ ret = lg216x_read_reg(state, 0x0513, &val);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ if (lg_fail(ret))
+ goto fail;
+
+ switch ((val >> 4) & 0x03) {
+#if 1
+ default:
+#endif
+ case 0x00:
+ *rs_framemode = ATSCMH_RSFRAME_PRI_ONLY;
+ break;
+ case 0x01:
+ *rs_framemode = ATSCMH_RSFRAME_PRI_SEC;
+ break;
+#if 0
+ default:
+ *rs_framemode = ATSCMH_RSFRAME_RES;
+ break;
+#endif
+ }
+fail:
+ return ret;
+}
+
+static
+int lg216x_get_rs_frame_ensemble(struct lg216x_state *state,
+ enum atscmh_rs_frame_ensemble *rs_frame_ens)
+{
+ u8 val;
+ int ret;
+
+ switch (state->cfg->lg_chip) {
+ case LG2160:
+ ret = lg216x_read_reg(state, 0x0400, &val);
+ break;
+ case LG2161:
+ ret = lg216x_read_reg(state, 0x0500, &val);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ if (lg_fail(ret))
+ goto fail;
+
+ val &= 0x01;
+ *rs_frame_ens = (enum atscmh_rs_frame_ensemble) val;
+fail:
+ return ret;
+}
+
+static int lg216x_get_rs_code_mode(struct lg216x_state *state,
+ enum atscmh_rs_code_mode *rs_code_pri,
+ enum atscmh_rs_code_mode *rs_code_sec)
+{
+ u8 val;
+ int ret;
+
+ switch (state->cfg->lg_chip) {
+ case LG2160:
+ ret = lg216x_read_reg(state, 0x0410, &val);
+ break;
+ case LG2161:
+ ret = lg216x_read_reg(state, 0x0513, &val);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ if (lg_fail(ret))
+ goto fail;
+
+ *rs_code_pri = (enum atscmh_rs_code_mode) ((val >> 2) & 0x03);
+ *rs_code_sec = (enum atscmh_rs_code_mode) (val & 0x03);
+fail:
+ return ret;
+}
+
+static int lg216x_get_sccc_block_mode(struct lg216x_state *state,
+ enum atscmh_sccc_block_mode *sccc_block)
+{
+ u8 val;
+ int ret;
+
+ switch (state->cfg->lg_chip) {
+ case LG2160:
+ ret = lg216x_read_reg(state, 0x0315, &val);
+ break;
+ case LG2161:
+ ret = lg216x_read_reg(state, 0x0511, &val);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ if (lg_fail(ret))
+ goto fail;
+
+ switch (val & 0x03) {
+ case 0x00:
+ *sccc_block = ATSCMH_SCCC_BLK_SEP;
+ break;
+ case 0x01:
+ *sccc_block = ATSCMH_SCCC_BLK_COMB;
+ break;
+ default:
+ *sccc_block = ATSCMH_SCCC_BLK_RES;
+ break;
+ }
+fail:
+ return ret;
+}
+
+static int lg216x_get_sccc_code_mode(struct lg216x_state *state,
+ enum atscmh_sccc_code_mode *mode_a,
+ enum atscmh_sccc_code_mode *mode_b,
+ enum atscmh_sccc_code_mode *mode_c,
+ enum atscmh_sccc_code_mode *mode_d)
+{
+ u8 val;
+ int ret;
+
+ switch (state->cfg->lg_chip) {
+ case LG2160:
+ ret = lg216x_read_reg(state, 0x0316, &val);
+ break;
+ case LG2161:
+ ret = lg216x_read_reg(state, 0x0512, &val);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ if (lg_fail(ret))
+ goto fail;
+
+ switch ((val >> 6) & 0x03) {
+ case 0x00:
+ *mode_a = ATSCMH_SCCC_CODE_HLF;
+ break;
+ case 0x01:
+ *mode_a = ATSCMH_SCCC_CODE_QTR;
+ break;
+ default:
+ *mode_a = ATSCMH_SCCC_CODE_RES;
+ break;
+ }
+
+ switch ((val >> 4) & 0x03) {
+ case 0x00:
+ *mode_b = ATSCMH_SCCC_CODE_HLF;
+ break;
+ case 0x01:
+ *mode_b = ATSCMH_SCCC_CODE_QTR;
+ break;
+ default:
+ *mode_b = ATSCMH_SCCC_CODE_RES;
+ break;
+ }
+
+ switch ((val >> 2) & 0x03) {
+ case 0x00:
+ *mode_c = ATSCMH_SCCC_CODE_HLF;
+ break;
+ case 0x01:
+ *mode_c = ATSCMH_SCCC_CODE_QTR;
+ break;
+ default:
+ *mode_c = ATSCMH_SCCC_CODE_RES;
+ break;
+ }
+
+ switch (val & 0x03) {
+ case 0x00:
+ *mode_d = ATSCMH_SCCC_CODE_HLF;
+ break;
+ case 0x01:
+ *mode_d = ATSCMH_SCCC_CODE_QTR;
+ break;
+ default:
+ *mode_d = ATSCMH_SCCC_CODE_RES;
+ break;
+ }
+fail:
+ return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+#if 0
+static int lg216x_read_fic_err_count(struct lg216x_state *state, u8 *err)
+{
+ u8 fic_err;
+ int ret;
+
+ *err = 0;
+
+ switch (state->cfg->lg_chip) {
+ case LG2160:
+ ret = lg216x_read_reg(state, 0x0012, &fic_err);
+ break;
+ case LG2161:
+ ret = lg216x_read_reg(state, 0x001e, &fic_err);
+ break;
+ }
+ if (lg_fail(ret))
+ goto fail;
+
+ *err = fic_err;
+fail:
+ return ret;
+}
+
+static int lg2160_read_crc_err_count(struct lg216x_state *state, u16 *err)
+{
+ u8 crc_err1, crc_err2;
+ int ret;
+
+ *err = 0;
+
+ ret = lg216x_read_reg(state, 0x0411, &crc_err1);
+ if (lg_fail(ret))
+ goto fail;
+
+ ret = lg216x_read_reg(state, 0x0412, &crc_err2);
+ if (lg_fail(ret))
+ goto fail;
+
+ *err = (u16)(((crc_err2 & 0x0f) << 8) | crc_err1);
+fail:
+ return ret;
+}
+
+static int lg2161_read_crc_err_count(struct lg216x_state *state, u16 *err)
+{
+ u8 crc_err;
+ int ret;
+
+ *err = 0;
+
+ ret = lg216x_read_reg(state, 0x0612, &crc_err);
+ if (lg_fail(ret))
+ goto fail;
+
+ *err = (u16)crc_err;
+fail:
+ return ret;
+}
+
+static int lg216x_read_crc_err_count(struct lg216x_state *state, u16 *err)
+{
+ int ret;
+ switch (state->cfg->lg_chip) {
+ case LG2160:
+ ret = lg2160_read_crc_err_count(state, err);
+ break;
+ case LG2161:
+ ret = lg2161_read_crc_err_count(state, err);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+static int lg2160_read_rs_err_count(struct lg216x_state *state, u16 *err)
+{
+ u8 rs_err1, rs_err2;
+ int ret;
+
+ *err = 0;
+
+ ret = lg216x_read_reg(state, 0x0413, &rs_err1);
+ if (lg_fail(ret))
+ goto fail;
+
+ ret = lg216x_read_reg(state, 0x0414, &rs_err2);
+ if (lg_fail(ret))
+ goto fail;
+
+ *err = (u16)(((rs_err2 & 0x0f) << 8) | rs_err1);
+fail:
+ return ret;
+}
+
+static int lg2161_read_rs_err_count(struct lg216x_state *state, u16 *err)
+{
+ u8 rs_err1, rs_err2;
+ int ret;
+
+ *err = 0;
+
+ ret = lg216x_read_reg(state, 0x0613, &rs_err1);
+ if (lg_fail(ret))
+ goto fail;
+
+ ret = lg216x_read_reg(state, 0x0614, &rs_err2);
+ if (lg_fail(ret))
+ goto fail;
+
+ *err = (u16)((rs_err1 << 8) | rs_err2);
+fail:
+ return ret;
+}
+
+static int lg216x_read_rs_err_count(struct lg216x_state *state, u16 *err)
+{
+ int ret;
+ switch (state->cfg->lg_chip) {
+ case LG2160:
+ ret = lg2160_read_rs_err_count(state, err);
+ break;
+ case LG2161:
+ ret = lg2161_read_rs_err_count(state, err);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static int lg216x_get_frontend(struct dvb_frontend *fe)
+{
+ struct lg216x_state *state = fe->demodulator_priv;
+ int ret;
+
+ lg_dbg("\n");
+
+ fe->dtv_property_cache.modulation = VSB_8;
+ fe->dtv_property_cache.frequency = state->current_frequency;
+ fe->dtv_property_cache.delivery_system = SYS_ATSCMH;
+
+ ret = lg216x_get_fic_version(state,
+ &fe->dtv_property_cache.atscmh_fic_ver);
+ if (lg_fail(ret))
+ goto fail;
+ if (state->fic_ver != fe->dtv_property_cache.atscmh_fic_ver) {
+ state->fic_ver = fe->dtv_property_cache.atscmh_fic_ver;
+
+#if 0
+ ret = lg2160_get_parade_id(state,
+ &fe->dtv_property_cache.atscmh_parade_id);
+ if (lg_fail(ret))
+ goto fail;
+/* #else */
+ fe->dtv_property_cache.atscmh_parade_id = state->parade_id;
+#endif
+ ret = lg216x_get_nog(state,
+ &fe->dtv_property_cache.atscmh_nog);
+ if (lg_fail(ret))
+ goto fail;
+ ret = lg216x_get_tnog(state,
+ &fe->dtv_property_cache.atscmh_tnog);
+ if (lg_fail(ret))
+ goto fail;
+ ret = lg216x_get_sgn(state,
+ &fe->dtv_property_cache.atscmh_sgn);
+ if (lg_fail(ret))
+ goto fail;
+ ret = lg216x_get_prc(state,
+ &fe->dtv_property_cache.atscmh_prc);
+ if (lg_fail(ret))
+ goto fail;
+
+ ret = lg216x_get_rs_frame_mode(state,
+ (enum atscmh_rs_frame_mode *)
+ &fe->dtv_property_cache.atscmh_rs_frame_mode);
+ if (lg_fail(ret))
+ goto fail;
+ ret = lg216x_get_rs_frame_ensemble(state,
+ (enum atscmh_rs_frame_ensemble *)
+ &fe->dtv_property_cache.atscmh_rs_frame_ensemble);
+ if (lg_fail(ret))
+ goto fail;
+ ret = lg216x_get_rs_code_mode(state,
+ (enum atscmh_rs_code_mode *)
+ &fe->dtv_property_cache.atscmh_rs_code_mode_pri,
+ (enum atscmh_rs_code_mode *)
+ &fe->dtv_property_cache.atscmh_rs_code_mode_sec);
+ if (lg_fail(ret))
+ goto fail;
+ ret = lg216x_get_sccc_block_mode(state,
+ (enum atscmh_sccc_block_mode *)
+ &fe->dtv_property_cache.atscmh_sccc_block_mode);
+ if (lg_fail(ret))
+ goto fail;
+ ret = lg216x_get_sccc_code_mode(state,
+ (enum atscmh_sccc_code_mode *)
+ &fe->dtv_property_cache.atscmh_sccc_code_mode_a,
+ (enum atscmh_sccc_code_mode *)
+ &fe->dtv_property_cache.atscmh_sccc_code_mode_b,
+ (enum atscmh_sccc_code_mode *)
+ &fe->dtv_property_cache.atscmh_sccc_code_mode_c,
+ (enum atscmh_sccc_code_mode *)
+ &fe->dtv_property_cache.atscmh_sccc_code_mode_d);
+ if (lg_fail(ret))
+ goto fail;
+ }
+#if 0
+ ret = lg216x_read_fic_err_count(state,
+ (u8 *)&fe->dtv_property_cache.atscmh_fic_err);
+ if (lg_fail(ret))
+ goto fail;
+ ret = lg216x_read_crc_err_count(state,
+ &fe->dtv_property_cache.atscmh_crc_err);
+ if (lg_fail(ret))
+ goto fail;
+ ret = lg216x_read_rs_err_count(state,
+ &fe->dtv_property_cache.atscmh_rs_err);
+ if (lg_fail(ret))
+ goto fail;
+
+ switch (state->cfg->lg_chip) {
+ case LG2160:
+ if (((fe->dtv_property_cache.atscmh_rs_err >= 240) &&
+ (fe->dtv_property_cache.atscmh_crc_err >= 240)) &&
+ ((jiffies_to_msecs(jiffies) - state->last_reset) > 6000))
+ ret = lg216x_soft_reset(state);
+ break;
+ case LG2161:
+ /* no fix needed here (as far as we know) */
+ ret = 0;
+ break;
+ }
+ lg_fail(ret);
+#endif
+fail:
+ return ret;
+}
+
+static int lg216x_get_property(struct dvb_frontend *fe,
+ struct dtv_property *tvp)
+{
+ return (DTV_ATSCMH_FIC_VER == tvp->cmd) ?
+ lg216x_get_frontend(fe) : 0;
+}
+
+
+static int lg2160_set_frontend(struct dvb_frontend *fe)
+{
+ struct lg216x_state *state = fe->demodulator_priv;
+ int ret;
+
+ lg_dbg("(%d)\n", fe->dtv_property_cache.frequency);
+
+ if (fe->ops.tuner_ops.set_params) {
+ ret = fe->ops.tuner_ops.set_params(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ if (lg_fail(ret))
+ goto fail;
+ state->current_frequency = fe->dtv_property_cache.frequency;
+ }
+
+ ret = lg2160_agc_fix(state, 0, 0);
+ if (lg_fail(ret))
+ goto fail;
+ ret = lg2160_agc_polarity(state, 0, 0);
+ if (lg_fail(ret))
+ goto fail;
+ ret = lg2160_tuner_pwr_save_polarity(state, 1);
+ if (lg_fail(ret))
+ goto fail;
+ ret = lg216x_set_if(state);
+ if (lg_fail(ret))
+ goto fail;
+ ret = lg2160_spectrum_polarity(state, state->cfg->spectral_inversion);
+ if (lg_fail(ret))
+ goto fail;
+
+ /* be tuned before this point */
+ ret = lg216x_soft_reset(state);
+ if (lg_fail(ret))
+ goto fail;
+
+ ret = lg2160_tuner_pwr_save(state, 0);
+ if (lg_fail(ret))
+ goto fail;
+
+ switch (state->cfg->lg_chip) {
+ case LG2160:
+ ret = lg2160_set_spi_clock(state);
+ if (lg_fail(ret))
+ goto fail;
+ break;
+ case LG2161:
+ ret = lg2161_set_output_interface(state);
+ if (lg_fail(ret))
+ goto fail;
+ break;
+ }
+
+ ret = lg216x_set_parade(state, fe->dtv_property_cache.atscmh_parade_id);
+ if (lg_fail(ret))
+ goto fail;
+
+ ret = lg216x_set_ensemble(state,
+ fe->dtv_property_cache.atscmh_rs_frame_ensemble);
+ if (lg_fail(ret))
+ goto fail;
+
+ ret = lg216x_initialize(state);
+ if (lg_fail(ret))
+ goto fail;
+
+ ret = lg216x_enable_fic(state, 1);
+ lg_fail(ret);
+
+ lg216x_get_frontend(fe);
+fail:
+ return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg2160_read_lock_status(struct lg216x_state *state,
+ int *acq_lock, int *sync_lock)
+{
+ u8 val;
+ int ret;
+
+ *acq_lock = 0;
+ *sync_lock = 0;
+
+ ret = lg216x_read_reg(state, 0x011b, &val);
+ if (lg_fail(ret))
+ goto fail;
+
+ *sync_lock = (val & 0x20) ? 0 : 1;
+ *acq_lock = (val & 0x40) ? 0 : 1;
+fail:
+ return ret;
+}
+
+#ifdef USE_LG2161_LOCK_BITS
+static int lg2161_read_lock_status(struct lg216x_state *state,
+ int *acq_lock, int *sync_lock)
+{
+ u8 val;
+ int ret;
+
+ *acq_lock = 0;
+ *sync_lock = 0;
+
+ ret = lg216x_read_reg(state, 0x0304, &val);
+ if (lg_fail(ret))
+ goto fail;
+
+ *sync_lock = (val & 0x80) ? 0 : 1;
+
+ ret = lg216x_read_reg(state, 0x011b, &val);
+ if (lg_fail(ret))
+ goto fail;
+
+ *acq_lock = (val & 0x40) ? 0 : 1;
+fail:
+ return ret;
+}
+#endif
+
+static int lg216x_read_lock_status(struct lg216x_state *state,
+ int *acq_lock, int *sync_lock)
+{
+#ifdef USE_LG2161_LOCK_BITS
+ int ret;
+ switch (state->cfg->lg_chip) {
+ case LG2160:
+ ret = lg2160_read_lock_status(state, acq_lock, sync_lock);
+ break;
+ case LG2161:
+ ret = lg2161_read_lock_status(state, acq_lock, sync_lock);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+#else
+ return lg2160_read_lock_status(state, acq_lock, sync_lock);
+#endif
+}
+
+static int lg216x_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct lg216x_state *state = fe->demodulator_priv;
+ int ret, acq_lock, sync_lock;
+
+ *status = 0;
+
+ ret = lg216x_read_lock_status(state, &acq_lock, &sync_lock);
+ if (lg_fail(ret))
+ goto fail;
+
+ lg_dbg("%s%s\n",
+ acq_lock ? "SIGNALEXIST " : "",
+ sync_lock ? "SYNCLOCK" : "");
+
+ if (acq_lock)
+ *status |= FE_HAS_SIGNAL;
+ if (sync_lock)
+ *status |= FE_HAS_SYNC;
+
+ if (*status)
+ *status |= FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_LOCK;
+
+fail:
+ return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg2160_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct lg216x_state *state = fe->demodulator_priv;
+ u8 snr1, snr2;
+ int ret;
+
+ *snr = 0;
+
+ ret = lg216x_read_reg(state, 0x0202, &snr1);
+ if (lg_fail(ret))
+ goto fail;
+
+ ret = lg216x_read_reg(state, 0x0203, &snr2);
+ if (lg_fail(ret))
+ goto fail;
+
+ if ((snr1 == 0xba) || (snr2 == 0xdf))
+ *snr = 0;
+ else
+#if 1
+ *snr = ((snr1 >> 4) * 100) + ((snr1 & 0x0f) * 10) + (snr2 >> 4);
+#else /* BCD */
+ *snr = (snr2 | (snr1 << 8));
+#endif
+fail:
+ return ret;
+}
+
+static int lg2161_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct lg216x_state *state = fe->demodulator_priv;
+ u8 snr1, snr2;
+ int ret;
+
+ *snr = 0;
+
+ ret = lg216x_read_reg(state, 0x0302, &snr1);
+ if (lg_fail(ret))
+ goto fail;
+
+ ret = lg216x_read_reg(state, 0x0303, &snr2);
+ if (lg_fail(ret))
+ goto fail;
+
+ if ((snr1 == 0xba) || (snr2 == 0xfd))
+ *snr = 0;
+ else
+
+ *snr = ((snr1 >> 4) * 100) + ((snr1 & 0x0f) * 10) + (snr2 & 0x0f);
+fail:
+ return ret;
+}
+
+static int lg216x_read_signal_strength(struct dvb_frontend *fe,
+ u16 *strength)
+{
+#if 0
+ /* borrowed from lgdt330x.c
+ *
+ * Calculate strength from SNR up to 35dB
+ * Even though the SNR can go higher than 35dB,
+ * there is some comfort factor in having a range of
+ * strong signals that can show at 100%
+ */
+ struct lg216x_state *state = fe->demodulator_priv;
+ u16 snr;
+ int ret;
+#endif
+ *strength = 0;
+#if 0
+ ret = fe->ops.read_snr(fe, &snr);
+ if (lg_fail(ret))
+ goto fail;
+ /* Rather than use the 8.8 value snr, use state->snr which is 8.24 */
+ /* scale the range 0 - 35*2^24 into 0 - 65535 */
+ if (state->snr >= 8960 * 0x10000)
+ *strength = 0xffff;
+ else
+ *strength = state->snr / 8960;
+fail:
+ return ret;
+#else
+ return 0;
+#endif
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int lg216x_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+#if 0
+ struct lg216x_state *state = fe->demodulator_priv;
+ int ret;
+
+ ret = lg216x_read_rs_err_count(state,
+ &fe->dtv_property_cache.atscmh_rs_err);
+ if (lg_fail(ret))
+ goto fail;
+
+ *ucblocks = fe->dtv_property_cache.atscmh_rs_err;
+fail:
+#else
+ *ucblocks = 0;
+#endif
+ return 0;
+}
+
+static int lg216x_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings
+ *fe_tune_settings)
+{
+ fe_tune_settings->min_delay_ms = 500;
+ lg_dbg("\n");
+ return 0;
+}
+
+static void lg216x_release(struct dvb_frontend *fe)
+{
+ struct lg216x_state *state = fe->demodulator_priv;
+ lg_dbg("\n");
+ kfree(state);
+}
+
+static struct dvb_frontend_ops lg2160_ops = {
+ .delsys = { SYS_ATSCMH },
+ .info = {
+ .name = "LG Electronics LG2160 ATSC/MH Frontend",
+ .frequency_min = 54000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 62500,
+ },
+ .i2c_gate_ctrl = lg216x_i2c_gate_ctrl,
+#if 0
+ .init = lg216x_init,
+ .sleep = lg216x_sleep,
+#endif
+ .get_property = lg216x_get_property,
+
+ .set_frontend = lg2160_set_frontend,
+ .get_frontend = lg216x_get_frontend,
+ .get_tune_settings = lg216x_get_tune_settings,
+ .read_status = lg216x_read_status,
+#if 0
+ .read_ber = lg216x_read_ber,
+#endif
+ .read_signal_strength = lg216x_read_signal_strength,
+ .read_snr = lg2160_read_snr,
+ .read_ucblocks = lg216x_read_ucblocks,
+ .release = lg216x_release,
+};
+
+static struct dvb_frontend_ops lg2161_ops = {
+ .delsys = { SYS_ATSCMH },
+ .info = {
+ .name = "LG Electronics LG2161 ATSC/MH Frontend",
+ .frequency_min = 54000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 62500,
+ },
+ .i2c_gate_ctrl = lg216x_i2c_gate_ctrl,
+#if 0
+ .init = lg216x_init,
+ .sleep = lg216x_sleep,
+#endif
+ .get_property = lg216x_get_property,
+
+ .set_frontend = lg2160_set_frontend,
+ .get_frontend = lg216x_get_frontend,
+ .get_tune_settings = lg216x_get_tune_settings,
+ .read_status = lg216x_read_status,
+#if 0
+ .read_ber = lg216x_read_ber,
+#endif
+ .read_signal_strength = lg216x_read_signal_strength,
+ .read_snr = lg2161_read_snr,
+ .read_ucblocks = lg216x_read_ucblocks,
+ .release = lg216x_release,
+};
+
+struct dvb_frontend *lg2160_attach(const struct lg2160_config *config,
+ struct i2c_adapter *i2c_adap)
+{
+ struct lg216x_state *state = NULL;
+
+ lg_dbg("(%d-%04x)\n",
+ i2c_adap ? i2c_adapter_id(i2c_adap) : 0,
+ config ? config->i2c_addr : 0);
+
+ state = kzalloc(sizeof(struct lg216x_state), GFP_KERNEL);
+ if (state == NULL)
+ goto fail;
+
+ state->cfg = config;
+ state->i2c_adap = i2c_adap;
+ state->fic_ver = 0xff;
+ state->parade_id = 0xff;
+
+ switch (config->lg_chip) {
+ default:
+ lg_warn("invalid chip requested, defaulting to LG2160");
+ /* fall-thru */
+ case LG2160:
+ memcpy(&state->frontend.ops, &lg2160_ops,
+ sizeof(struct dvb_frontend_ops));
+ break;
+ case LG2161:
+ memcpy(&state->frontend.ops, &lg2161_ops,
+ sizeof(struct dvb_frontend_ops));
+ break;
+ }
+
+ state->frontend.demodulator_priv = state;
+ state->current_frequency = -1;
+ /* parade 1 by default */
+ state->frontend.dtv_property_cache.atscmh_parade_id = 1;
+
+ return &state->frontend;
+fail:
+ lg_warn("unable to detect LG216x hardware\n");
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(lg2160_attach);
+
+MODULE_DESCRIPTION("LG Electronics LG216x ATSC/MH Demodulator Driver");
+MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.3");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/lg2160.h b/drivers/media/dvb/frontends/lg2160.h
new file mode 100644
index 000000000000..9e2c0f41199a
--- /dev/null
+++ b/drivers/media/dvb/frontends/lg2160.h
@@ -0,0 +1,84 @@
+/*
+ * Support for LG2160 - ATSC/MH
+ *
+ * Copyright (C) 2010 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _LG2160_H_
+#define _LG2160_H_
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+enum lg_chip_type {
+ LG2160 = 0,
+ LG2161 = 1,
+};
+
+#define LG2161_1019 LG2161
+#define LG2161_1040 LG2161
+
+enum lg2160_spi_clock {
+ LG2160_SPI_3_125_MHZ = 0,
+ LG2160_SPI_6_25_MHZ = 1,
+ LG2160_SPI_12_5_MHZ = 2,
+};
+
+#if 0
+enum lg2161_oif {
+ LG2161_OIF_EBI2_SLA = 1,
+ LG2161_OIF_SDIO_SLA = 2,
+ LG2161_OIF_SPI_SLA = 3,
+ LG2161_OIF_SPI_MAS = 4,
+ LG2161_OIF_SERIAL_TS = 7,
+};
+#endif
+
+struct lg2160_config {
+ u8 i2c_addr;
+
+ /* user defined IF frequency in KHz */
+ u16 if_khz;
+
+ /* disable i2c repeater - 0:repeater enabled 1:repeater disabled */
+ int deny_i2c_rptr:1;
+
+ /* spectral inversion - 0:disabled 1:enabled */
+ int spectral_inversion:1;
+
+ unsigned int output_if;
+ enum lg2160_spi_clock spi_clock;
+ enum lg_chip_type lg_chip;
+};
+
+#if defined(CONFIG_DVB_LG2160) || (defined(CONFIG_DVB_LG2160_MODULE) && \
+ defined(MODULE))
+extern
+struct dvb_frontend *lg2160_attach(const struct lg2160_config *config,
+ struct i2c_adapter *i2c_adap);
+#else
+static inline
+struct dvb_frontend *lg2160_attach(const struct lg2160_config *config,
+ struct i2c_adapter *i2c_adap)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_LG2160 */
+
+#endif /* _LG2160_H_ */
diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c
index 4de1d3520cd2..568363a10a31 100644
--- a/drivers/media/dvb/frontends/lgs8gxx.c
+++ b/drivers/media/dvb/frontends/lgs8gxx.c
@@ -262,7 +262,6 @@ static int lgs8gxx_set_mode_auto(struct lgs8gxx_state *priv)
static int lgs8gxx_set_mode_manual(struct lgs8gxx_state *priv)
{
- int ret = 0;
u8 t;
if (priv->config->prod == LGS8GXX_PROD_LGS8G75) {
@@ -296,7 +295,7 @@ static int lgs8gxx_set_mode_manual(struct lgs8gxx_state *priv)
if (priv->config->prod == LGS8GXX_PROD_LGS8913)
lgs8gxx_write_reg(priv, 0xC1, 0);
- ret = lgs8gxx_read_reg(priv, 0xC5, &t);
+ lgs8gxx_read_reg(priv, 0xC5, &t);
t = (t & 0xE0) | 0x06;
lgs8gxx_write_reg(priv, 0xC5, t);
diff --git a/drivers/media/dvb/frontends/m88rs2000.c b/drivers/media/dvb/frontends/m88rs2000.c
index 045ee5a6f7ae..312588e84dae 100644
--- a/drivers/media/dvb/frontends/m88rs2000.c
+++ b/drivers/media/dvb/frontends/m88rs2000.c
@@ -416,9 +416,25 @@ static int m88rs2000_tab_set(struct m88rs2000_state *state,
static int m88rs2000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t volt)
{
- deb_info("%s: %s\n", __func__,
- volt == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
- volt == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "??");
+ struct m88rs2000_state *state = fe->demodulator_priv;
+ u8 data;
+
+ data = m88rs2000_demod_read(state, 0xb2);
+ data |= 0x03; /* bit0 V/H, bit1 off/on */
+
+ switch (volt) {
+ case SEC_VOLTAGE_18:
+ data &= ~0x03;
+ break;
+ case SEC_VOLTAGE_13:
+ data &= ~0x03;
+ data |= 0x01;
+ break;
+ case SEC_VOLTAGE_OFF:
+ break;
+ }
+
+ m88rs2000_demod_write(state, 0xb2, data);
return 0;
}
@@ -654,7 +670,6 @@ static int m88rs2000_set_tuner(struct dvb_frontend *fe, u16 *offset)
static int m88rs2000_set_fec(struct m88rs2000_state *state,
fe_code_rate_t fec)
{
- int ret;
u16 fec_set;
switch (fec) {
/* This is not confirmed kept for reference */
@@ -677,7 +692,7 @@ static int m88rs2000_set_fec(struct m88rs2000_state *state,
default:
fec_set = 0x08;
}
- ret = m88rs2000_demod_write(state, 0x76, fec_set);
+ m88rs2000_demod_write(state, 0x76, fec_set);
return 0;
}
@@ -772,13 +787,13 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe)
return -ENODEV;
for (i = 0; i < 25; i++) {
- u8 reg = m88rs2000_demod_read(state, 0x8c);
+ reg = m88rs2000_demod_read(state, 0x8c);
if ((reg & 0x7) == 0x7) {
status = FE_HAS_LOCK;
break;
}
state->no_lock_count++;
- if (state->no_lock_count > 15) {
+ if (state->no_lock_count == 15) {
reg = m88rs2000_demod_read(state, 0x70);
reg ^= 0x4;
m88rs2000_demod_write(state, 0x70, reg);
diff --git a/drivers/media/dvb/frontends/rtl2830.c b/drivers/media/dvb/frontends/rtl2830.c
index 45196c5b0736..93612ebac519 100644
--- a/drivers/media/dvb/frontends/rtl2830.c
+++ b/drivers/media/dvb/frontends/rtl2830.c
@@ -374,6 +374,118 @@ err:
return ret;
}
+static int rtl2830_get_frontend(struct dvb_frontend *fe)
+{
+ struct rtl2830_priv *priv = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret;
+ u8 buf[3];
+
+ if (priv->sleeping)
+ return 0;
+
+ ret = rtl2830_rd_regs(priv, 0x33c, buf, 2);
+ if (ret)
+ goto err;
+
+ ret = rtl2830_rd_reg(priv, 0x351, &buf[2]);
+ if (ret)
+ goto err;
+
+ dbg("%s: TPS=%02x %02x %02x", __func__, buf[0], buf[1], buf[2]);
+
+ switch ((buf[0] >> 2) & 3) {
+ case 0:
+ c->modulation = QPSK;
+ break;
+ case 1:
+ c->modulation = QAM_16;
+ break;
+ case 2:
+ c->modulation = QAM_64;
+ break;
+ }
+
+ switch ((buf[2] >> 2) & 1) {
+ case 0:
+ c->transmission_mode = TRANSMISSION_MODE_2K;
+ break;
+ case 1:
+ c->transmission_mode = TRANSMISSION_MODE_8K;
+ }
+
+ switch ((buf[2] >> 0) & 3) {
+ case 0:
+ c->guard_interval = GUARD_INTERVAL_1_32;
+ break;
+ case 1:
+ c->guard_interval = GUARD_INTERVAL_1_16;
+ break;
+ case 2:
+ c->guard_interval = GUARD_INTERVAL_1_8;
+ break;
+ case 3:
+ c->guard_interval = GUARD_INTERVAL_1_4;
+ break;
+ }
+
+ switch ((buf[0] >> 4) & 7) {
+ case 0:
+ c->hierarchy = HIERARCHY_NONE;
+ break;
+ case 1:
+ c->hierarchy = HIERARCHY_1;
+ break;
+ case 2:
+ c->hierarchy = HIERARCHY_2;
+ break;
+ case 3:
+ c->hierarchy = HIERARCHY_4;
+ break;
+ }
+
+ switch ((buf[1] >> 3) & 7) {
+ case 0:
+ c->code_rate_HP = FEC_1_2;
+ break;
+ case 1:
+ c->code_rate_HP = FEC_2_3;
+ break;
+ case 2:
+ c->code_rate_HP = FEC_3_4;
+ break;
+ case 3:
+ c->code_rate_HP = FEC_5_6;
+ break;
+ case 4:
+ c->code_rate_HP = FEC_7_8;
+ break;
+ }
+
+ switch ((buf[1] >> 0) & 7) {
+ case 0:
+ c->code_rate_LP = FEC_1_2;
+ break;
+ case 1:
+ c->code_rate_LP = FEC_2_3;
+ break;
+ case 2:
+ c->code_rate_LP = FEC_3_4;
+ break;
+ case 3:
+ c->code_rate_LP = FEC_5_6;
+ break;
+ case 4:
+ c->code_rate_LP = FEC_7_8;
+ break;
+ }
+
+ return 0;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
+}
+
static int rtl2830_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
struct rtl2830_priv *priv = fe->demodulator_priv;
@@ -404,14 +516,72 @@ err:
static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr)
{
- *snr = 0;
+ struct rtl2830_priv *priv = fe->demodulator_priv;
+ int ret, hierarchy, constellation;
+ u8 buf[2], tmp;
+ u16 tmp16;
+#define CONSTELLATION_NUM 3
+#define HIERARCHY_NUM 4
+ static const u32 snr_constant[CONSTELLATION_NUM][HIERARCHY_NUM] = {
+ { 70705899, 70705899, 70705899, 70705899 },
+ { 82433173, 82433173, 87483115, 94445660 },
+ { 92888734, 92888734, 95487525, 99770748 },
+ };
+
+ if (priv->sleeping)
+ return 0;
+
+ /* reports SNR in resolution of 0.1 dB */
+
+ ret = rtl2830_rd_reg(priv, 0x33c, &tmp);
+ if (ret)
+ goto err;
+
+ constellation = (tmp >> 2) & 0x03; /* [3:2] */
+ if (constellation > CONSTELLATION_NUM - 1)
+ goto err;
+
+ hierarchy = (tmp >> 4) & 0x07; /* [6:4] */
+ if (hierarchy > HIERARCHY_NUM - 1)
+ goto err;
+
+ ret = rtl2830_rd_regs(priv, 0x40c, buf, 2);
+ if (ret)
+ goto err;
+
+ tmp16 = buf[0] << 8 | buf[1];
+
+ if (tmp16)
+ *snr = (snr_constant[constellation][hierarchy] -
+ intlog10(tmp16)) / ((1 << 24) / 100);
+ else
+ *snr = 0;
+
return 0;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
}
static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber)
{
- *ber = 0;
+ struct rtl2830_priv *priv = fe->demodulator_priv;
+ int ret;
+ u8 buf[2];
+
+ if (priv->sleeping)
+ return 0;
+
+ ret = rtl2830_rd_regs(priv, 0x34e, buf, 2);
+ if (ret)
+ goto err;
+
+ *ber = buf[0] << 8 | buf[1];
+
return 0;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
}
static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
@@ -422,8 +592,32 @@ static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
{
- *strength = 0;
+ struct rtl2830_priv *priv = fe->demodulator_priv;
+ int ret;
+ u8 buf[2];
+ u16 if_agc_raw, if_agc;
+
+ if (priv->sleeping)
+ return 0;
+
+ ret = rtl2830_rd_regs(priv, 0x359, buf, 2);
+ if (ret)
+ goto err;
+
+ if_agc_raw = (buf[0] << 8 | buf[1]) & 0x3fff;
+
+ if (if_agc_raw & (1 << 9))
+ if_agc = -(~(if_agc_raw - 1) & 0x1ff);
+ else
+ if_agc = if_agc_raw;
+
+ *strength = (u8) (55 - if_agc / 182);
+ *strength |= *strength << 8;
+
return 0;
+err:
+ dbg("%s: failed=%d", __func__, ret);
+ return ret;
}
static struct dvb_frontend_ops rtl2830_ops;
@@ -549,6 +743,7 @@ static struct dvb_frontend_ops rtl2830_ops = {
.get_tune_settings = rtl2830_get_tune_settings,
.set_frontend = rtl2830_set_frontend,
+ .get_frontend = rtl2830_get_frontend,
.read_status = rtl2830_read_status,
.read_snr = rtl2830_read_snr,
diff --git a/drivers/media/dvb/frontends/rtl2830_priv.h b/drivers/media/dvb/frontends/rtl2830_priv.h
index 4a464761b5b8..9b20557ccf6c 100644
--- a/drivers/media/dvb/frontends/rtl2830_priv.h
+++ b/drivers/media/dvb/frontends/rtl2830_priv.h
@@ -22,6 +22,7 @@
#define RTL2830_PRIV_H
#include "dvb_frontend.h"
+#include "dvb_math.h"
#include "rtl2830.h"
#define LOG_PREFIX "rtl2830"
diff --git a/drivers/media/dvb/frontends/stb0899_drv.c b/drivers/media/dvb/frontends/stb0899_drv.c
index dd08f4ac64a8..8b0dc74a3298 100644
--- a/drivers/media/dvb/frontends/stb0899_drv.c
+++ b/drivers/media/dvb/frontends/stb0899_drv.c
@@ -637,11 +637,9 @@ static void stb0899_init_calc(struct stb0899_state *state)
struct stb0899_internal *internal = &state->internal;
int master_clk;
u8 agc[2];
- u8 agc1cn;
u32 reg;
/* Read registers (in burst mode) */
- agc1cn = stb0899_read_reg(state, STB0899_AGC1CN);
stb0899_read_regs(state, STB0899_AGC1REF, agc, 2); /* AGC1R and AGC2O */
/* Initial calculations */
@@ -823,15 +821,12 @@ static int stb0899_send_diseqc_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t
static int stb0899_diseqc_init(struct stb0899_state *state)
{
- struct dvb_diseqc_master_cmd tx_data;
/*
struct dvb_diseqc_slave_reply rx_data;
*/
- u8 f22_tx, f22_rx, reg;
+ u8 f22_tx, reg;
u32 mclk, tx_freq = 22000;/* count = 0, i; */
- tx_data.msg[0] = 0xe2;
- tx_data.msg_len = 3;
reg = stb0899_read_reg(state, STB0899_DISCNTRL2);
STB0899_SETFIELD_VAL(ONECHIP_TRX, reg, 0);
stb0899_write_reg(state, STB0899_DISCNTRL2, reg);
@@ -849,7 +844,6 @@ static int stb0899_diseqc_init(struct stb0899_state *state)
f22_tx = mclk / (tx_freq * 32);
stb0899_write_reg(state, STB0899_DISF22, f22_tx); /* DiSEqC Tx freq */
state->rx_freq = 20000;
- f22_rx = mclk / (state->rx_freq * 32);
return 0;
}
diff --git a/drivers/media/dvb/frontends/stb6100.c b/drivers/media/dvb/frontends/stb6100.c
index def88abb30bf..2e93e65d2cdb 100644
--- a/drivers/media/dvb/frontends/stb6100.c
+++ b/drivers/media/dvb/frontends/stb6100.c
@@ -158,7 +158,6 @@ static int stb6100_read_regs(struct stb6100_state *state, u8 regs[])
static int stb6100_read_reg(struct stb6100_state *state, u8 reg)
{
u8 regs[STB6100_NUMREGS];
- int rc;
struct i2c_msg msg = {
.addr = state->config->tuner_address + reg,
@@ -167,7 +166,7 @@ static int stb6100_read_reg(struct stb6100_state *state, u8 reg)
.len = 1
};
- rc = i2c_transfer(state->i2c, &msg, 1);
+ i2c_transfer(state->i2c, &msg, 1);
if (unlikely(reg >= STB6100_NUMREGS)) {
dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg);
diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c
index 85c157a1fe5e..d40f226160ef 100644
--- a/drivers/media/dvb/frontends/stv0297.c
+++ b/drivers/media/dvb/frontends/stv0297.c
@@ -414,7 +414,6 @@ static int stv0297_set_frontend(struct dvb_frontend *fe)
int delay;
int sweeprate;
int carrieroffset;
- unsigned long starttime;
unsigned long timeout;
fe_spectral_inversion_t inversion;
@@ -543,7 +542,6 @@ static int stv0297_set_frontend(struct dvb_frontend *fe)
stv0297_writereg_mask(state, 0x43, 0x10, 0x10);
/* wait for WGAGC lock */
- starttime = jiffies;
timeout = jiffies + msecs_to_jiffies(2000);
while (time_before(jiffies, timeout)) {
msleep(10);
diff --git a/drivers/media/dvb/frontends/stv0900_sw.c b/drivers/media/dvb/frontends/stv0900_sw.c
index ba0709b2d433..4af20780fb9c 100644
--- a/drivers/media/dvb/frontends/stv0900_sw.c
+++ b/drivers/media/dvb/frontends/stv0900_sw.c
@@ -835,7 +835,6 @@ static void stv0900_track_optimization(struct dvb_frontend *fe)
blind_tun_sw = 0,
modulation;
- enum fe_stv0900_rolloff rolloff;
enum fe_stv0900_modcode foundModcod;
dprintk("%s\n", __func__);
@@ -940,7 +939,6 @@ static void stv0900_track_optimization(struct dvb_frontend *fe)
freq1 = stv0900_read_reg(intp, CFR2);
freq0 = stv0900_read_reg(intp, CFR1);
- rolloff = stv0900_get_bits(intp, ROLLOFF_STATUS);
if (intp->srch_algo[demod] == STV0900_BLIND_SEARCH) {
stv0900_write_reg(intp, SFRSTEP, 0x00);
stv0900_write_bits(intp, SCAN_ENABLE, 0);
diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c
index 4aef1877ed42..d79e69f65cbb 100644
--- a/drivers/media/dvb/frontends/stv090x.c
+++ b/drivers/media/dvb/frontends/stv090x.c
@@ -2842,7 +2842,6 @@ static int stv090x_optimize_track(struct stv090x_state *state)
{
struct dvb_frontend *fe = &state->frontend;
- enum stv090x_rolloff rolloff;
enum stv090x_modcod modcod;
s32 srate, pilots, aclc, f_1, f_0, i = 0, blind_tune = 0;
@@ -2966,7 +2965,6 @@ static int stv090x_optimize_track(struct stv090x_state *state)
f_1 = STV090x_READ_DEMOD(state, CFR2);
f_0 = STV090x_READ_DEMOD(state, CFR1);
reg = STV090x_READ_DEMOD(state, TMGOBS);
- rolloff = STV090x_GETFIELD_Px(reg, ROLLOFF_STATUS_FIELD);
if (state->algo == STV090x_BLIND_SEARCH) {
STV090x_WRITE_DEMOD(state, SFRSTEP, 0x00);
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
index ac7237891374..82946cd517f5 100644
--- a/drivers/media/dvb/frontends/zl10353.c
+++ b/drivers/media/dvb/frontends/zl10353.c
@@ -525,7 +525,7 @@ static int zl10353_read_snr(struct dvb_frontend *fe, u16 *snr)
zl10353_dump_regs(fe);
_snr = zl10353_read_register(state, SNR);
- *snr = (_snr << 8) | _snr;
+ *snr = 10 * _snr / 8;
return 0;
}
@@ -559,7 +559,6 @@ static int zl10353_init(struct dvb_frontend *fe)
{
struct zl10353_state *state = fe->demodulator_priv;
u8 zl10353_reset_attach[6] = { 0x50, 0x03, 0x64, 0x46, 0x15, 0x0F };
- int rc = 0;
if (debug_regs)
zl10353_dump_regs(fe);
@@ -573,7 +572,7 @@ static int zl10353_init(struct dvb_frontend *fe)
/* Do a "hard" reset if not already done */
if (zl10353_read_register(state, 0x50) != zl10353_reset_attach[1] ||
zl10353_read_register(state, 0x51) != zl10353_reset_attach[2]) {
- rc = zl10353_write(fe, zl10353_reset_attach,
+ zl10353_write(fe, zl10353_reset_attach,
sizeof(zl10353_reset_attach));
if (debug_regs)
zl10353_dump_regs(fe);
diff --git a/drivers/media/dvb/mantis/hopper_cards.c b/drivers/media/dvb/mantis/hopper_cards.c
index 71622f65c037..cc0251e01077 100644
--- a/drivers/media/dvb/mantis/hopper_cards.c
+++ b/drivers/media/dvb/mantis/hopper_cards.c
@@ -65,7 +65,7 @@ static int devs;
static irqreturn_t hopper_irq_handler(int irq, void *dev_id)
{
- u32 stat = 0, mask = 0, lstat = 0;
+ u32 stat = 0, mask = 0;
u32 rst_stat = 0, rst_mask = 0;
struct mantis_pci *mantis;
@@ -80,7 +80,6 @@ static irqreturn_t hopper_irq_handler(int irq, void *dev_id)
stat = mmread(MANTIS_INT_STAT);
mask = mmread(MANTIS_INT_MASK);
- lstat = stat & ~MANTIS_INT_RISCSTAT;
if (!(stat & mask))
return IRQ_NONE;
diff --git a/drivers/media/dvb/mantis/mantis_cards.c b/drivers/media/dvb/mantis/mantis_cards.c
index c2bb90b3e529..095cf3a994e2 100644
--- a/drivers/media/dvb/mantis/mantis_cards.c
+++ b/drivers/media/dvb/mantis/mantis_cards.c
@@ -73,7 +73,7 @@ static char *label[10] = {
static irqreturn_t mantis_irq_handler(int irq, void *dev_id)
{
- u32 stat = 0, mask = 0, lstat = 0;
+ u32 stat = 0, mask = 0;
u32 rst_stat = 0, rst_mask = 0;
struct mantis_pci *mantis;
@@ -88,7 +88,6 @@ static irqreturn_t mantis_irq_handler(int irq, void *dev_id)
stat = mmread(MANTIS_INT_STAT);
mask = mmread(MANTIS_INT_MASK);
- lstat = stat & ~MANTIS_INT_RISCSTAT;
if (!(stat & mask))
return IRQ_NONE;
diff --git a/drivers/media/dvb/mantis/mantis_dma.c b/drivers/media/dvb/mantis/mantis_dma.c
index c61ca7d3daea..566c407175a4 100644
--- a/drivers/media/dvb/mantis/mantis_dma.c
+++ b/drivers/media/dvb/mantis/mantis_dma.c
@@ -199,10 +199,6 @@ void mantis_dma_start(struct mantis_pci *mantis)
void mantis_dma_stop(struct mantis_pci *mantis)
{
- u32 stat = 0, mask = 0;
-
- stat = mmread(MANTIS_INT_STAT);
- mask = mmread(MANTIS_INT_MASK);
dprintk(MANTIS_DEBUG, 1, "Mantis Stop DMA engine");
mmwrite((mmread(MANTIS_GPIF_ADDR) & (~(MANTIS_GPIF_HIFRDWRN))), MANTIS_GPIF_ADDR);
diff --git a/drivers/media/dvb/mantis/mantis_evm.c b/drivers/media/dvb/mantis/mantis_evm.c
index 36f2256ebb0e..71ce52875c38 100644
--- a/drivers/media/dvb/mantis/mantis_evm.c
+++ b/drivers/media/dvb/mantis/mantis_evm.c
@@ -41,10 +41,9 @@ static void mantis_hifevm_work(struct work_struct *work)
struct mantis_ca *ca = container_of(work, struct mantis_ca, hif_evm_work);
struct mantis_pci *mantis = ca->ca_priv;
- u32 gpif_stat, gpif_mask;
+ u32 gpif_stat;
gpif_stat = mmread(MANTIS_GPIF_STATUS);
- gpif_mask = mmread(MANTIS_GPIF_IRQCFG);
if (gpif_stat & MANTIS_GPIF_DETSTAT) {
if (gpif_stat & MANTIS_CARD_PLUGIN) {
diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c
index f129a9303f80..39857384af10 100644
--- a/drivers/media/dvb/ngene/ngene-core.c
+++ b/drivers/media/dvb/ngene/ngene-core.c
@@ -1409,10 +1409,8 @@ static int ngene_start(struct ngene *dev)
if (stat < 0)
goto fail;
- if (!stat)
- return stat;
+ return 0;
- /* otherwise error: fall through */
fail:
ngwritel(0, NGENE_INT_ENABLE);
free_irq(dev->pci_dev->irq, dev);
diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c
index e1f20c236989..f148b19a206a 100644
--- a/drivers/media/dvb/pluto2/pluto2.c
+++ b/drivers/media/dvb/pluto2/pluto2.c
@@ -481,14 +481,6 @@ static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe)
if (p->bandwidth_hz == 8000000)
buf[3] |= 0x08;
- if (sizeof(buf) == 6) {
- buf[4] = buf[2];
- buf[4] &= ~0x1c;
- buf[4] |= 0x18;
-
- buf[5] = (0 << 7) | (2 << 4);
- }
-
msg.addr = I2C_ADDR_TUA6034 >> 1;
msg.flags = 0;
msg.buf = buf;
diff --git a/drivers/media/dvb/siano/smssdio.c b/drivers/media/dvb/siano/smssdio.c
index 91f8c8291e2b..d6f3f100699a 100644
--- a/drivers/media/dvb/siano/smssdio.c
+++ b/drivers/media/dvb/siano/smssdio.c
@@ -114,7 +114,7 @@ out:
static void smssdio_interrupt(struct sdio_func *func)
{
- int ret, isr;
+ int ret;
struct smssdio_device *smsdev;
struct smscore_buffer_t *cb;
@@ -127,7 +127,7 @@ static void smssdio_interrupt(struct sdio_func *func)
* The interrupt register has no defined meaning. It is just
* a way of turning of the level triggered interrupt.
*/
- isr = sdio_readb(func, SMSSDIO_INT, &ret);
+ (void)sdio_readb(func, SMSSDIO_INT, &ret);
if (ret) {
sms_err("Unable to read interrupt register!\n");
return;
diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c
index b1fe5137df09..63c004a25e0b 100644
--- a/drivers/media/dvb/siano/smsusb.c
+++ b/drivers/media/dvb/siano/smsusb.c
@@ -542,6 +542,8 @@ static const struct usb_device_id smsusb_id_table[] __devinitconst = {
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
{ USB_DEVICE(0x2040, 0xc090),
.driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
+ { USB_DEVICE(0x2040, 0xc0a0),
+ .driver_info = SMS1XXX_BOARD_HAUPPAUGE_WINDHAM },
{ } /* Terminating entry */
};
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index ee8ee1d481fa..1b2d15140a1d 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -107,7 +107,7 @@ static struct v4l2_input inputs[4] = {
.index = 1,
.name = "Television",
.type = V4L2_INPUT_TYPE_TUNER,
- .audioset = 2,
+ .audioset = 1,
.tuner = 0,
.std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
.status = 0,
@@ -494,7 +494,7 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
dprintk(2, "VIDIOC_S_INPUT: %d\n", input);
if (!av7110->analog_tuner_flags)
- return 0;
+ return input ? -EINVAL : 0;
if (input >= 4)
return -EINVAL;
@@ -503,19 +503,38 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
return av7110_dvb_c_switch(fh);
}
+static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+ dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index);
+ if (a->index != 0)
+ return -EINVAL;
+ *a = msp3400_v4l2_audio;
+ return 0;
+}
+
static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
{
+ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+
dprintk(2, "VIDIOC_G_AUDIO: %d\n", a->index);
if (a->index != 0)
return -EINVAL;
- memcpy(a, &msp3400_v4l2_audio, sizeof(struct v4l2_audio));
+ if (av7110->current_input >= 2)
+ return -EINVAL;
+ *a = msp3400_v4l2_audio;
return 0;
}
static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
{
+ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
+
dprintk(2, "VIDIOC_S_AUDIO: %d\n", a->index);
- return 0;
+ if (av7110->current_input >= 2)
+ return -EINVAL;
+ return a->index ? -EINVAL : 0;
}
static int vidioc_g_sliced_vbi_cap(struct file *file, void *fh,
@@ -802,26 +821,39 @@ int av7110_init_v4l(struct av7110 *av7110)
ERR("cannot init capture device. skipping\n");
return -ENODEV;
}
- vv_data->ops.vidioc_enum_input = vidioc_enum_input;
- vv_data->ops.vidioc_g_input = vidioc_g_input;
- vv_data->ops.vidioc_s_input = vidioc_s_input;
- vv_data->ops.vidioc_g_tuner = vidioc_g_tuner;
- vv_data->ops.vidioc_s_tuner = vidioc_s_tuner;
- vv_data->ops.vidioc_g_frequency = vidioc_g_frequency;
- vv_data->ops.vidioc_s_frequency = vidioc_s_frequency;
- vv_data->ops.vidioc_g_audio = vidioc_g_audio;
- vv_data->ops.vidioc_s_audio = vidioc_s_audio;
- vv_data->ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap;
- vv_data->ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out;
- vv_data->ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out;
+ vv_data->vid_ops.vidioc_enum_input = vidioc_enum_input;
+ vv_data->vid_ops.vidioc_g_input = vidioc_g_input;
+ vv_data->vid_ops.vidioc_s_input = vidioc_s_input;
+ vv_data->vid_ops.vidioc_g_tuner = vidioc_g_tuner;
+ vv_data->vid_ops.vidioc_s_tuner = vidioc_s_tuner;
+ vv_data->vid_ops.vidioc_g_frequency = vidioc_g_frequency;
+ vv_data->vid_ops.vidioc_s_frequency = vidioc_s_frequency;
+ vv_data->vid_ops.vidioc_enumaudio = vidioc_enumaudio;
+ vv_data->vid_ops.vidioc_g_audio = vidioc_g_audio;
+ vv_data->vid_ops.vidioc_s_audio = vidioc_s_audio;
+ vv_data->vid_ops.vidioc_g_fmt_vbi_cap = NULL;
+
+ vv_data->vbi_ops.vidioc_g_tuner = vidioc_g_tuner;
+ vv_data->vbi_ops.vidioc_s_tuner = vidioc_s_tuner;
+ vv_data->vbi_ops.vidioc_g_frequency = vidioc_g_frequency;
+ vv_data->vbi_ops.vidioc_s_frequency = vidioc_s_frequency;
+ vv_data->vbi_ops.vidioc_g_fmt_vbi_cap = NULL;
+ vv_data->vbi_ops.vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap;
+ vv_data->vbi_ops.vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out;
+ vv_data->vbi_ops.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out;
+
+ if (FW_VERSION(av7110->arm_app) < 0x2623)
+ vv_data->capabilities &= ~V4L2_CAP_SLICED_VBI_OUTPUT;
if (saa7146_register_device(&av7110->v4l_dev, dev, "av7110", VFL_TYPE_GRABBER)) {
ERR("cannot register capture device. skipping\n");
saa7146_vv_release(dev);
return -ENODEV;
}
- if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI))
- ERR("cannot register vbi v4l2 device. skipping\n");
+ if (FW_VERSION(av7110->arm_app) >= 0x2623) {
+ if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI))
+ ERR("cannot register vbi v4l2 device. skipping\n");
+ }
return 0;
}
@@ -905,7 +937,7 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
static struct saa7146_ext_vv av7110_vv_data_st = {
.inputs = 1,
.audios = 1,
- .capabilities = V4L2_CAP_SLICED_VBI_OUTPUT,
+ .capabilities = V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO,
.flags = 0,
.stds = &standard[0],
@@ -920,7 +952,7 @@ static struct saa7146_ext_vv av7110_vv_data_st = {
static struct saa7146_ext_vv av7110_vv_data_c = {
.inputs = 1,
.audios = 1,
- .capabilities = V4L2_CAP_TUNER | V4L2_CAP_SLICED_VBI_OUTPUT,
+ .capabilities = V4L2_CAP_TUNER | V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_AUDIO,
.flags = SAA7146_USE_PORT_B_FOR_VBI,
.stds = &standard[0],
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 8b32e282bf5d..12ddb53c58dc 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -1483,9 +1483,9 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
ERR("cannot init vv subsystem\n");
return err;
}
- vv_data.ops.vidioc_enum_input = vidioc_enum_input;
- vv_data.ops.vidioc_g_input = vidioc_g_input;
- vv_data.ops.vidioc_s_input = vidioc_s_input;
+ vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
+ vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
+ vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) {
/* fixme: proper cleanup here */
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 056138f63c7d..e1cd13283407 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -214,23 +214,76 @@ EXPORT_SYMBOL_GPL(media_entity_graph_walk_next);
* pipeline pointer must be identical for all nested calls to
* media_entity_pipeline_start().
*/
-void media_entity_pipeline_start(struct media_entity *entity,
- struct media_pipeline *pipe)
+__must_check int media_entity_pipeline_start(struct media_entity *entity,
+ struct media_pipeline *pipe)
{
struct media_device *mdev = entity->parent;
struct media_entity_graph graph;
+ struct media_entity *entity_err = entity;
+ int ret;
mutex_lock(&mdev->graph_mutex);
media_entity_graph_walk_start(&graph, entity);
while ((entity = media_entity_graph_walk_next(&graph))) {
+ unsigned int i;
+
entity->stream_count++;
WARN_ON(entity->pipe && entity->pipe != pipe);
entity->pipe = pipe;
+
+ /* Already streaming --- no need to check. */
+ if (entity->stream_count > 1)
+ continue;
+
+ if (!entity->ops || !entity->ops->link_validate)
+ continue;
+
+ for (i = 0; i < entity->num_links; i++) {
+ struct media_link *link = &entity->links[i];
+
+ /* Is this pad part of an enabled link? */
+ if (!(link->flags & MEDIA_LNK_FL_ENABLED))
+ continue;
+
+ /* Are we the sink or not? */
+ if (link->sink->entity != entity)
+ continue;
+
+ ret = entity->ops->link_validate(link);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ goto error;
+ }
}
mutex_unlock(&mdev->graph_mutex);
+
+ return 0;
+
+error:
+ /*
+ * Link validation on graph failed. We revert what we did and
+ * return the error.
+ */
+ media_entity_graph_walk_start(&graph, entity_err);
+
+ while ((entity_err = media_entity_graph_walk_next(&graph))) {
+ entity_err->stream_count--;
+ if (entity_err->stream_count == 0)
+ entity_err->pipe = NULL;
+
+ /*
+ * We haven't increased stream_count further than this
+ * so we quit here.
+ */
+ if (entity_err == entity)
+ break;
+ }
+
+ mutex_unlock(&mdev->graph_mutex);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(media_entity_pipeline_start);
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 8db2d7f4b52a..c257da13d766 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -320,7 +320,7 @@ config RADIO_MIROPCM20
module will be called radio-miropcm20.
config RADIO_SF16FMI
- tristate "SF16-FMI/SF16-FMP Radio"
+ tristate "SF16-FMI/SF16-FMP/SF16-FMD Radio"
depends on ISA && VIDEO_V4L2
---help---
Choose Y here if you have one of these FM radio cards.
@@ -329,7 +329,7 @@ config RADIO_SF16FMI
module will be called radio-sf16fmi.
config RADIO_SF16FMR2
- tristate "SF16FMR2 Radio"
+ tristate "SF16-FMR2/SF16-FMD2 Radio"
depends on ISA && VIDEO_V4L2 && SND
---help---
Choose Y here if you have one of these FM radio cards.
diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
index f36905b63645..63b112b555b2 100644
--- a/drivers/media/radio/dsbr100.c
+++ b/drivers/media/radio/dsbr100.c
@@ -1,92 +1,37 @@
/* A driver for the D-Link DSB-R100 USB radio and Gemtek USB Radio 21.
- The device plugs into both the USB and an analog audio input, so this thing
- only deals with initialisation and frequency setting, the
- audio data has to be handled by a sound driver.
-
- Major issue: I can't find out where the device reports the signal
- strength, and indeed the windows software appearantly just looks
- at the stereo indicator as well. So, scanning will only find
- stereo stations. Sad, but I can't help it.
-
- Also, the windows program sends oodles of messages over to the
- device, and I couldn't figure out their meaning. My suspicion
- is that they don't have any:-)
-
- You might find some interesting stuff about this module at
- http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr
-
- Copyright (c) 2000 Markus Demleitner <msdemlei@cl.uni-heidelberg.de>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
- History:
-
- Version 0.46:
- Removed usb_dsbr100_open/close calls and radio->users counter. Also,
- radio->muted changed to radio->status and suspend/resume calls updated.
-
- Version 0.45:
- Converted to v4l2_device.
-
- Version 0.44:
- Add suspend/resume functions, fix unplug of device,
- a lot of cleanups and fixes by Alexey Klimov <klimov.linux@gmail.com>
-
- Version 0.43:
- Oliver Neukum: avoided DMA coherency issue
-
- Version 0.42:
- Converted dsbr100 to use video_ioctl2
- by Douglas Landgraf <dougsland@gmail.com>
-
- Version 0.41-ac1:
- Alan Cox: Some cleanups and fixes
-
- Version 0.41:
- Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
-
- Version 0.40:
- Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
-
- Version 0.30:
- Markus: Updates for 2.5.x kernel and more ISO compliant source
-
- Version 0.25:
- PSL and Markus: Cleanup, radio now doesn't stop on device close
-
- Version 0.24:
- Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
- right. Some minor cleanup, improved standalone compilation
-
- Version 0.23:
- Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
-
- Version 0.22:
- Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns,
- thanks to Mike Cox for pointing the problem out.
-
- Version 0.21:
- Markus: Minor cleanup, warnings if something goes wrong, lame attempt
- to adhere to Documentation/CodingStyle
-
- Version 0.2:
- Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
- Markus: Copyright clarification
-
- Version 0.01: Markus: initial release
-
+ * The device plugs into both the USB and an analog audio input, so this thing
+ * only deals with initialisation and frequency setting, the
+ * audio data has to be handled by a sound driver.
+ *
+ * Major issue: I can't find out where the device reports the signal
+ * strength, and indeed the windows software appearantly just looks
+ * at the stereo indicator as well. So, scanning will only find
+ * stereo stations. Sad, but I can't help it.
+ *
+ * Also, the windows program sends oodles of messages over to the
+ * device, and I couldn't figure out their meaning. My suspicion
+ * is that they don't have any:-)
+ *
+ * You might find some interesting stuff about this module at
+ * http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr
+ *
+ * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool.
+ *
+ * Copyright (c) 2000 Markus Demleitner <msdemlei@cl.uni-heidelberg.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
@@ -95,17 +40,19 @@
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/videodev2.h>
+#include <linux/usb.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
-#include <linux/usb.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
/*
* Version Information
*/
-#define DRIVER_VERSION "0.4.7"
-
-#define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
-#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
+MODULE_AUTHOR("Markus Demleitner <msdemlei@tucana.harvard.edu>");
+MODULE_DESCRIPTION("D-Link DSB-R100 USB FM radio driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.1.0");
#define DSB100_VENDOR 0x04b4
#define DSB100_PRODUCT 0x1002
@@ -122,19 +69,8 @@ devices, that would be 76 and 91. */
#define FREQ_MAX 108.0
#define FREQ_MUL 16000
-/* defines for radio->status */
-#define STARTED 0
-#define STOPPED 1
-
#define v4l2_dev_to_radio(d) container_of(d, struct dsbr100_device, v4l2_dev)
-static int usb_dsbr100_probe(struct usb_interface *intf,
- const struct usb_device_id *id);
-static void usb_dsbr100_disconnect(struct usb_interface *intf);
-static int usb_dsbr100_suspend(struct usb_interface *intf,
- pm_message_t message);
-static int usb_dsbr100_resume(struct usb_interface *intf);
-
static int radio_nr = -1;
module_param(radio_nr, int, 0);
@@ -143,179 +79,92 @@ struct dsbr100_device {
struct usb_device *usbdev;
struct video_device videodev;
struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler hdl;
u8 *transfer_buffer;
struct mutex v4l2_lock;
int curfreq;
- int stereo;
- int status;
-};
-
-static struct usb_device_id usb_dsbr100_device_table [] = {
- { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
- { } /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
-
-/* USB subsystem interface */
-static struct usb_driver usb_dsbr100_driver = {
- .name = "dsbr100",
- .probe = usb_dsbr100_probe,
- .disconnect = usb_dsbr100_disconnect,
- .id_table = usb_dsbr100_device_table,
- .suspend = usb_dsbr100_suspend,
- .resume = usb_dsbr100_resume,
- .reset_resume = usb_dsbr100_resume,
- .supports_autosuspend = 0,
+ bool stereo;
+ bool muted;
};
/* Low-level device interface begins here */
-/* switch on radio */
-static int dsbr100_start(struct dsbr100_device *radio)
+/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
+static int dsbr100_setfreq(struct dsbr100_device *radio, unsigned freq)
{
- int retval;
- int request;
-
- retval = usb_control_msg(radio->usbdev,
- usb_rcvctrlpipe(radio->usbdev, 0),
- USB_REQ_GET_STATUS,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x00, 0xC7, radio->transfer_buffer, 8, 300);
-
- if (retval < 0) {
- request = USB_REQ_GET_STATUS;
- goto usb_control_msg_failed;
+ unsigned f = (freq / 16 * 80) / 1000 + 856;
+ int retval = 0;
+
+ if (!radio->muted) {
+ retval = usb_control_msg(radio->usbdev,
+ usb_rcvctrlpipe(radio->usbdev, 0),
+ DSB100_TUNE,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ (f >> 8) & 0x00ff, f & 0xff,
+ radio->transfer_buffer, 8, 300);
+ if (retval >= 0)
+ mdelay(1);
}
- retval = usb_control_msg(radio->usbdev,
- usb_rcvctrlpipe(radio->usbdev, 0),
- DSB100_ONOFF,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x01, 0x00, radio->transfer_buffer, 8, 300);
-
- if (retval < 0) {
- request = DSB100_ONOFF;
- goto usb_control_msg_failed;
+ if (retval >= 0) {
+ radio->curfreq = freq;
+ return 0;
}
-
- radio->status = STARTED;
- return (radio->transfer_buffer)[0];
-
-usb_control_msg_failed:
dev_err(&radio->usbdev->dev,
"%s - usb_control_msg returned %i, request %i\n",
- __func__, retval, request);
+ __func__, retval, DSB100_TUNE);
return retval;
-
}
-/* switch off radio */
-static int dsbr100_stop(struct dsbr100_device *radio)
+/* switch on radio */
+static int dsbr100_start(struct dsbr100_device *radio)
{
- int retval;
- int request;
-
- retval = usb_control_msg(radio->usbdev,
- usb_rcvctrlpipe(radio->usbdev, 0),
- USB_REQ_GET_STATUS,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x16, 0x1C, radio->transfer_buffer, 8, 300);
-
- if (retval < 0) {
- request = USB_REQ_GET_STATUS;
- goto usb_control_msg_failed;
- }
-
- retval = usb_control_msg(radio->usbdev,
+ int retval = usb_control_msg(radio->usbdev,
usb_rcvctrlpipe(radio->usbdev, 0),
DSB100_ONOFF,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x00, 0x00, radio->transfer_buffer, 8, 300);
-
- if (retval < 0) {
- request = DSB100_ONOFF;
- goto usb_control_msg_failed;
- }
-
- radio->status = STOPPED;
- return (radio->transfer_buffer)[0];
+ 0x01, 0x00, radio->transfer_buffer, 8, 300);
-usb_control_msg_failed:
+ if (retval >= 0)
+ return dsbr100_setfreq(radio, radio->curfreq);
dev_err(&radio->usbdev->dev,
"%s - usb_control_msg returned %i, request %i\n",
- __func__, retval, request);
+ __func__, retval, DSB100_ONOFF);
return retval;
}
-/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
-static int dsbr100_setfreq(struct dsbr100_device *radio)
+/* switch off radio */
+static int dsbr100_stop(struct dsbr100_device *radio)
{
- int retval;
- int request;
- int freq = (radio->curfreq / 16 * 80) / 1000 + 856;
-
- retval = usb_control_msg(radio->usbdev,
- usb_rcvctrlpipe(radio->usbdev, 0),
- DSB100_TUNE,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- (freq >> 8) & 0x00ff, freq & 0xff,
- radio->transfer_buffer, 8, 300);
-
- if (retval < 0) {
- request = DSB100_TUNE;
- goto usb_control_msg_failed;
- }
-
- retval = usb_control_msg(radio->usbdev,
+ int retval = usb_control_msg(radio->usbdev,
usb_rcvctrlpipe(radio->usbdev, 0),
- USB_REQ_GET_STATUS,
+ DSB100_ONOFF,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x96, 0xB7, radio->transfer_buffer, 8, 300);
-
- if (retval < 0) {
- request = USB_REQ_GET_STATUS;
- goto usb_control_msg_failed;
- }
-
- retval = usb_control_msg(radio->usbdev,
- usb_rcvctrlpipe(radio->usbdev, 0),
- USB_REQ_GET_STATUS,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x00, 0x24, radio->transfer_buffer, 8, 300);
-
- if (retval < 0) {
- request = USB_REQ_GET_STATUS;
- goto usb_control_msg_failed;
- }
-
- radio->stereo = !((radio->transfer_buffer)[0] & 0x01);
- return (radio->transfer_buffer)[0];
+ 0x00, 0x00, radio->transfer_buffer, 8, 300);
-usb_control_msg_failed:
- radio->stereo = -1;
+ if (retval >= 0)
+ return 0;
dev_err(&radio->usbdev->dev,
"%s - usb_control_msg returned %i, request %i\n",
- __func__, retval, request);
+ __func__, retval, DSB100_ONOFF);
return retval;
+
}
/* return the device status. This is, in effect, just whether it
sees a stereo signal or not. Pity. */
static void dsbr100_getstat(struct dsbr100_device *radio)
{
- int retval;
-
- retval = usb_control_msg(radio->usbdev,
+ int retval = usb_control_msg(radio->usbdev,
usb_rcvctrlpipe(radio->usbdev, 0),
USB_REQ_GET_STATUS,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x00 , 0x24, radio->transfer_buffer, 8, 300);
+ 0x00, 0x24, radio->transfer_buffer, 8, 300);
if (retval < 0) {
- radio->stereo = -1;
+ radio->stereo = false;
dev_err(&radio->usbdev->dev,
"%s - usb_control_msg returned %i, request %i\n",
__func__, retval, USB_REQ_GET_STATUS);
@@ -332,7 +181,8 @@ static int vidioc_querycap(struct file *file, void *priv,
strlcpy(v->driver, "dsbr100", sizeof(v->driver));
strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card));
usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
- v->capabilities = V4L2_CAP_TUNER;
+ v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
+ v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -349,13 +199,11 @@ static int vidioc_g_tuner(struct file *file, void *priv,
v->type = V4L2_TUNER_RADIO;
v->rangelow = FREQ_MIN * FREQ_MUL;
v->rangehigh = FREQ_MAX * FREQ_MUL;
- v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
- v->capability = V4L2_TUNER_CAP_LOW;
- if(radio->stereo)
- v->audmode = V4L2_TUNER_MODE_STEREO;
- else
- v->audmode = V4L2_TUNER_MODE_MONO;
- v->signal = 0xffff; /* We can't get the signal strength */
+ v->rxsubchans = radio->stereo ? V4L2_TUNER_SUB_STEREO :
+ V4L2_TUNER_SUB_MONO;
+ v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+ v->audmode = V4L2_TUNER_MODE_STEREO;
+ v->signal = radio->stereo ? 0xffff : 0; /* We can't get the signal strength */
return 0;
}
@@ -369,14 +217,12 @@ static int vidioc_s_frequency(struct file *file, void *priv,
struct v4l2_frequency *f)
{
struct dsbr100_device *radio = video_drvdata(file);
- int retval;
- radio->curfreq = f->frequency;
+ if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+ return -EINVAL;
- retval = dsbr100_setfreq(radio);
- if (retval < 0)
- dev_warn(&radio->usbdev->dev, "Set frequency failed\n");
- return 0;
+ return dsbr100_setfreq(radio, clamp_t(unsigned, f->frequency,
+ FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL));
}
static int vidioc_g_frequency(struct file *file, void *priv,
@@ -384,90 +230,26 @@ static int vidioc_g_frequency(struct file *file, void *priv,
{
struct dsbr100_device *radio = video_drvdata(file);
+ if (f->tuner)
+ return -EINVAL;
f->type = V4L2_TUNER_RADIO;
f->frequency = radio->curfreq;
return 0;
}
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- switch (qc->id) {
- case V4L2_CID_AUDIO_MUTE:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
- }
-
- return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
+static int usb_dsbr100_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct dsbr100_device *radio = video_drvdata(file);
+ struct dsbr100_device *radio =
+ container_of(ctrl->handler, struct dsbr100_device, hdl);
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
- ctrl->value = radio->status;
- return 0;
+ radio->muted = ctrl->val;
+ return radio->muted ? dsbr100_stop(radio) : dsbr100_start(radio);
}
return -EINVAL;
}
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct dsbr100_device *radio = video_drvdata(file);
- int retval;
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- if (ctrl->value) {
- retval = dsbr100_stop(radio);
- if (retval < 0) {
- dev_warn(&radio->usbdev->dev,
- "Radio did not respond properly\n");
- return -EBUSY;
- }
- } else {
- retval = dsbr100_start(radio);
- if (retval < 0) {
- dev_warn(&radio->usbdev->dev,
- "Radio did not respond properly\n");
- return -EBUSY;
- }
- }
- return 0;
- }
- return -EINVAL;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- if (a->index > 1)
- return -EINVAL;
-
- strcpy(a->name, "Radio");
- a->capability = V4L2_AUDCAP_STEREO;
- return 0;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
- return i ? -EINVAL : 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- return a->index ? -EINVAL : 0;
-}
/* USB subsystem interface begins here */
@@ -481,8 +263,17 @@ static void usb_dsbr100_disconnect(struct usb_interface *intf)
{
struct dsbr100_device *radio = usb_get_intfdata(intf);
- v4l2_device_get(&radio->v4l2_dev);
mutex_lock(&radio->v4l2_lock);
+ /*
+ * Disconnect is also called on unload, and in that case we need to
+ * mute the device. This call will silently fail if it is called
+ * after a physical disconnect.
+ */
+ usb_control_msg(radio->usbdev,
+ usb_rcvctrlpipe(radio->usbdev, 0),
+ DSB100_ONOFF,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0x00, 0x00, radio->transfer_buffer, 8, 300);
usb_set_intfdata(intf, NULL);
video_unregister_device(&radio->videodev);
v4l2_device_disconnect(&radio->v4l2_dev);
@@ -495,25 +286,13 @@ static void usb_dsbr100_disconnect(struct usb_interface *intf)
static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message)
{
struct dsbr100_device *radio = usb_get_intfdata(intf);
- int retval;
mutex_lock(&radio->v4l2_lock);
- if (radio->status == STARTED) {
- retval = dsbr100_stop(radio);
- if (retval < 0)
- dev_warn(&intf->dev, "dsbr100_stop failed\n");
-
- /* After dsbr100_stop() status set to STOPPED.
- * If we want driver to start radio on resume
- * we set status equal to STARTED.
- * On resume we will check status and run radio if needed.
- */
- radio->status = STARTED;
- }
+ if (!radio->muted && dsbr100_stop(radio) < 0)
+ dev_warn(&intf->dev, "dsbr100_stop failed\n");
mutex_unlock(&radio->v4l2_lock);
dev_info(&intf->dev, "going into suspend..\n");
-
return 0;
}
@@ -521,18 +300,13 @@ static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message)
static int usb_dsbr100_resume(struct usb_interface *intf)
{
struct dsbr100_device *radio = usb_get_intfdata(intf);
- int retval;
mutex_lock(&radio->v4l2_lock);
- if (radio->status == STARTED) {
- retval = dsbr100_start(radio);
- if (retval < 0)
- dev_warn(&intf->dev, "dsbr100_start failed\n");
- }
+ if (!radio->muted && dsbr100_start(radio) < 0)
+ dev_warn(&intf->dev, "dsbr100_start failed\n");
mutex_unlock(&radio->v4l2_lock);
dev_info(&intf->dev, "coming out of suspend..\n");
-
return 0;
}
@@ -541,15 +315,23 @@ static void usb_dsbr100_release(struct v4l2_device *v4l2_dev)
{
struct dsbr100_device *radio = v4l2_dev_to_radio(v4l2_dev);
+ v4l2_ctrl_handler_free(&radio->hdl);
v4l2_device_unregister(&radio->v4l2_dev);
kfree(radio->transfer_buffer);
kfree(radio);
}
+static const struct v4l2_ctrl_ops usb_dsbr100_ctrl_ops = {
+ .s_ctrl = usb_dsbr100_s_ctrl,
+};
+
/* File system interface */
static const struct v4l2_file_operations usb_dsbr100_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = video_ioctl2,
+ .open = v4l2_fh_open,
+ .release = v4l2_fh_release,
+ .poll = v4l2_ctrl_poll,
};
static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = {
@@ -558,13 +340,9 @@ static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = {
.vidioc_s_tuner = vidioc_s_tuner,
.vidioc_g_frequency = vidioc_g_frequency,
.vidioc_s_frequency = vidioc_s_frequency,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
/* check if the device is present and register with v4l and usb if it is */
@@ -593,11 +371,17 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
retval = v4l2_device_register(&intf->dev, v4l2_dev);
if (retval < 0) {
v4l2_err(v4l2_dev, "couldn't register v4l2_device\n");
- kfree(radio->transfer_buffer);
- kfree(radio);
- return retval;
+ goto err_reg_dev;
}
+ v4l2_ctrl_handler_init(&radio->hdl, 1);
+ v4l2_ctrl_new_std(&radio->hdl, &usb_dsbr100_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+ if (radio->hdl.error) {
+ retval = radio->hdl.error;
+ v4l2_err(v4l2_dev, "couldn't register control\n");
+ goto err_reg_ctrl;
+ }
mutex_init(&radio->v4l2_lock);
strlcpy(radio->videodev.name, v4l2_dev->name, sizeof(radio->videodev.name));
radio->videodev.v4l2_dev = v4l2_dev;
@@ -605,28 +389,46 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
radio->videodev.ioctl_ops = &usb_dsbr100_ioctl_ops;
radio->videodev.release = video_device_release_empty;
radio->videodev.lock = &radio->v4l2_lock;
+ radio->videodev.ctrl_handler = &radio->hdl;
+ set_bit(V4L2_FL_USE_FH_PRIO, &radio->videodev.flags);
radio->usbdev = interface_to_usbdev(intf);
radio->curfreq = FREQ_MIN * FREQ_MUL;
- radio->status = STOPPED;
+ radio->muted = true;
video_set_drvdata(&radio->videodev, radio);
+ usb_set_intfdata(intf, radio);
retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr);
- if (retval < 0) {
- v4l2_err(v4l2_dev, "couldn't register video device\n");
- v4l2_device_unregister(v4l2_dev);
- kfree(radio->transfer_buffer);
- kfree(radio);
- return -EIO;
- }
- usb_set_intfdata(intf, radio);
- return 0;
+ if (retval == 0)
+ return 0;
+ v4l2_err(v4l2_dev, "couldn't register video device\n");
+
+err_reg_ctrl:
+ v4l2_ctrl_handler_free(&radio->hdl);
+ v4l2_device_unregister(v4l2_dev);
+err_reg_dev:
+ kfree(radio->transfer_buffer);
+ kfree(radio);
+ return retval;
}
-module_usb_driver(usb_dsbr100_driver);
+static struct usb_device_id usb_dsbr100_device_table[] = {
+ { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
+ { } /* Terminating entry */
+};
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRIVER_VERSION);
+MODULE_DEVICE_TABLE(usb, usb_dsbr100_device_table);
+
+/* USB subsystem interface */
+static struct usb_driver usb_dsbr100_driver = {
+ .name = "dsbr100",
+ .probe = usb_dsbr100_probe,
+ .disconnect = usb_dsbr100_disconnect,
+ .id_table = usb_dsbr100_device_table,
+ .suspend = usb_dsbr100_suspend,
+ .resume = usb_dsbr100_resume,
+ .reset_resume = usb_dsbr100_resume,
+};
+
+module_usb_driver(usb_dsbr100_driver);
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index 2e639ce6f256..235c0e349820 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -29,6 +29,7 @@
#include <linux/videodev2.h> /* kernel radio structs */
#include <linux/mutex.h>
#include <linux/io.h> /* outb, outb_p */
+#include <linux/pnp.h>
#include <linux/slab.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
@@ -283,6 +284,16 @@ static const struct radio_isa_ops gemtek_ops = {
static const int gemtek_ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c };
+#ifdef CONFIG_PNP
+static struct pnp_device_id gemtek_pnp_devices[] = {
+ /* AOpen FX-3D/Pro Radio */
+ {.id = "ADS7183", .driver_data = 0},
+ {.id = ""}
+};
+
+MODULE_DEVICE_TABLE(pnp, gemtek_pnp_devices);
+#endif
+
static struct radio_isa_driver gemtek_driver = {
.driver = {
.match = radio_isa_match,
@@ -292,6 +303,14 @@ static struct radio_isa_driver gemtek_driver = {
.name = "radio-gemtek",
},
},
+#ifdef CONFIG_PNP
+ .pnp_driver = {
+ .name = "radio-gemtek",
+ .id_table = gemtek_pnp_devices,
+ .probe = radio_isa_pnp_probe,
+ .remove = radio_isa_pnp_remove,
+ },
+#endif
.io_params = io,
.radio_nr_params = radio_nr,
.io_ports = gemtek_ioports,
@@ -305,12 +324,18 @@ static struct radio_isa_driver gemtek_driver = {
static int __init gemtek_init(void)
{
gemtek_driver.probe = probe;
+#ifdef CONFIG_PNP
+ pnp_register_driver(&gemtek_driver.pnp_driver);
+#endif
return isa_register_driver(&gemtek_driver.driver, GEMTEK_MAX);
}
static void __exit gemtek_exit(void)
{
hardmute = 1; /* Turn off PLL */
+#ifdef CONFIG_PNP
+ pnp_unregister_driver(&gemtek_driver.pnp_driver);
+#endif
isa_unregister_driver(&gemtek_driver.driver);
}
diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c
index 06f906351fad..3c0067de4324 100644
--- a/drivers/media/radio/radio-isa.c
+++ b/drivers/media/radio/radio-isa.c
@@ -150,14 +150,6 @@ static int radio_isa_log_status(struct file *file, void *priv)
return 0;
}
-static int radio_isa_subscribe_event(struct v4l2_fh *fh,
- struct v4l2_event_subscription *sub)
-{
- if (sub->type == V4L2_EVENT_CTRL)
- return v4l2_event_subscribe(fh, sub, 0);
- return -EINVAL;
-}
-
static const struct v4l2_ctrl_ops radio_isa_ctrl_ops = {
.s_ctrl = radio_isa_s_ctrl,
};
@@ -177,7 +169,7 @@ static const struct v4l2_ioctl_ops radio_isa_ioctl_ops = {
.vidioc_g_frequency = radio_isa_g_frequency,
.vidioc_s_frequency = radio_isa_s_frequency,
.vidioc_log_status = radio_isa_log_status,
- .vidioc_subscribe_event = radio_isa_subscribe_event,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
@@ -199,56 +191,31 @@ static bool radio_isa_valid_io(const struct radio_isa_driver *drv, int io)
return false;
}
-int radio_isa_probe(struct device *pdev, unsigned int dev)
+struct radio_isa_card *radio_isa_alloc(struct radio_isa_driver *drv,
+ struct device *pdev)
{
- struct radio_isa_driver *drv = pdev->platform_data;
- const struct radio_isa_ops *ops = drv->ops;
struct v4l2_device *v4l2_dev;
- struct radio_isa_card *isa;
- int res;
+ struct radio_isa_card *isa = drv->ops->alloc();
+ if (!isa)
+ return NULL;
- isa = drv->ops->alloc();
- if (isa == NULL)
- return -ENOMEM;
dev_set_drvdata(pdev, isa);
isa->drv = drv;
- isa->io = drv->io_params[dev];
v4l2_dev = &isa->v4l2_dev;
strlcpy(v4l2_dev->name, dev_name(pdev), sizeof(v4l2_dev->name));
- if (drv->probe && ops->probe) {
- int i;
-
- for (i = 0; i < drv->num_of_io_ports; ++i) {
- int io = drv->io_ports[i];
-
- if (request_region(io, drv->region_size, v4l2_dev->name)) {
- bool found = ops->probe(isa, io);
-
- release_region(io, drv->region_size);
- if (found) {
- isa->io = io;
- break;
- }
- }
- }
- }
-
- if (!radio_isa_valid_io(drv, isa->io)) {
- int i;
+ return isa;
+}
- if (isa->io < 0)
- return -ENODEV;
- v4l2_err(v4l2_dev, "you must set an I/O address with io=0x%03x",
- drv->io_ports[0]);
- for (i = 1; i < drv->num_of_io_ports; i++)
- printk(KERN_CONT "/0x%03x", drv->io_ports[i]);
- printk(KERN_CONT ".\n");
- kfree(isa);
- return -EINVAL;
- }
+int radio_isa_common_probe(struct radio_isa_card *isa, struct device *pdev,
+ int radio_nr, unsigned region_size)
+{
+ const struct radio_isa_driver *drv = isa->drv;
+ const struct radio_isa_ops *ops = drv->ops;
+ struct v4l2_device *v4l2_dev = &isa->v4l2_dev;
+ int res;
- if (!request_region(isa->io, drv->region_size, v4l2_dev->name)) {
+ if (!request_region(isa->io, region_size, v4l2_dev->name)) {
v4l2_err(v4l2_dev, "port 0x%x already in use\n", isa->io);
kfree(isa);
return -EBUSY;
@@ -299,42 +266,126 @@ int radio_isa_probe(struct device *pdev, unsigned int dev)
res = ops->s_stereo(isa, isa->stereo);
if (res < 0) {
v4l2_err(v4l2_dev, "Could not setup card\n");
- goto err_node_reg;
+ goto err_hdl;
}
- res = video_register_device(&isa->vdev, VFL_TYPE_RADIO,
- drv->radio_nr_params[dev]);
+ res = video_register_device(&isa->vdev, VFL_TYPE_RADIO, radio_nr);
+
if (res < 0) {
v4l2_err(v4l2_dev, "Could not register device node\n");
- goto err_node_reg;
+ goto err_hdl;
}
v4l2_info(v4l2_dev, "Initialized radio card %s on port 0x%03x\n",
drv->card, isa->io);
return 0;
-err_node_reg:
- v4l2_ctrl_handler_free(&isa->hdl);
err_hdl:
- v4l2_device_unregister(&isa->v4l2_dev);
+ v4l2_ctrl_handler_free(&isa->hdl);
err_dev_reg:
- release_region(isa->io, drv->region_size);
+ release_region(isa->io, region_size);
kfree(isa);
return res;
}
-EXPORT_SYMBOL_GPL(radio_isa_probe);
-int radio_isa_remove(struct device *pdev, unsigned int dev)
+int radio_isa_common_remove(struct radio_isa_card *isa, unsigned region_size)
{
- struct radio_isa_card *isa = dev_get_drvdata(pdev);
const struct radio_isa_ops *ops = isa->drv->ops;
ops->s_mute_volume(isa, true, isa->volume ? isa->volume->cur.val : 0);
video_unregister_device(&isa->vdev);
v4l2_ctrl_handler_free(&isa->hdl);
v4l2_device_unregister(&isa->v4l2_dev);
- release_region(isa->io, isa->drv->region_size);
+ release_region(isa->io, region_size);
v4l2_info(&isa->v4l2_dev, "Removed radio card %s\n", isa->drv->card);
kfree(isa);
return 0;
}
+
+int radio_isa_probe(struct device *pdev, unsigned int dev)
+{
+ struct radio_isa_driver *drv = pdev->platform_data;
+ const struct radio_isa_ops *ops = drv->ops;
+ struct v4l2_device *v4l2_dev;
+ struct radio_isa_card *isa;
+
+ isa = radio_isa_alloc(drv, pdev);
+ if (!isa)
+ return -ENOMEM;
+ isa->io = drv->io_params[dev];
+ v4l2_dev = &isa->v4l2_dev;
+
+ if (drv->probe && ops->probe) {
+ int i;
+
+ for (i = 0; i < drv->num_of_io_ports; ++i) {
+ int io = drv->io_ports[i];
+
+ if (request_region(io, drv->region_size, v4l2_dev->name)) {
+ bool found = ops->probe(isa, io);
+
+ release_region(io, drv->region_size);
+ if (found) {
+ isa->io = io;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!radio_isa_valid_io(drv, isa->io)) {
+ int i;
+
+ if (isa->io < 0)
+ return -ENODEV;
+ v4l2_err(v4l2_dev, "you must set an I/O address with io=0x%03x",
+ drv->io_ports[0]);
+ for (i = 1; i < drv->num_of_io_ports; i++)
+ printk(KERN_CONT "/0x%03x", drv->io_ports[i]);
+ printk(KERN_CONT ".\n");
+ kfree(isa);
+ return -EINVAL;
+ }
+
+ return radio_isa_common_probe(isa, pdev, drv->radio_nr_params[dev],
+ drv->region_size);
+}
+EXPORT_SYMBOL_GPL(radio_isa_probe);
+
+int radio_isa_remove(struct device *pdev, unsigned int dev)
+{
+ struct radio_isa_card *isa = dev_get_drvdata(pdev);
+
+ return radio_isa_common_remove(isa, isa->drv->region_size);
+}
EXPORT_SYMBOL_GPL(radio_isa_remove);
+
+#ifdef CONFIG_PNP
+int radio_isa_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
+{
+ struct pnp_driver *pnp_drv = to_pnp_driver(dev->dev.driver);
+ struct radio_isa_driver *drv = container_of(pnp_drv,
+ struct radio_isa_driver, pnp_driver);
+ struct radio_isa_card *isa;
+
+ if (!pnp_port_valid(dev, 0))
+ return -ENODEV;
+
+ isa = radio_isa_alloc(drv, &dev->dev);
+ if (!isa)
+ return -ENOMEM;
+
+ isa->io = pnp_port_start(dev, 0);
+
+ return radio_isa_common_probe(isa, &dev->dev, drv->radio_nr_params[0],
+ pnp_port_len(dev, 0));
+}
+EXPORT_SYMBOL_GPL(radio_isa_pnp_probe);
+
+void radio_isa_pnp_remove(struct pnp_dev *dev)
+{
+ struct radio_isa_card *isa = dev_get_drvdata(&dev->dev);
+
+ radio_isa_common_remove(isa, pnp_port_len(dev, 0));
+}
+EXPORT_SYMBOL_GPL(radio_isa_pnp_remove);
+#endif
diff --git a/drivers/media/radio/radio-isa.h b/drivers/media/radio/radio-isa.h
index 8a0ea84d86de..ba4c01f1bd0c 100644
--- a/drivers/media/radio/radio-isa.h
+++ b/drivers/media/radio/radio-isa.h
@@ -24,6 +24,7 @@
#define _RADIO_ISA_H_
#include <linux/isa.h>
+#include <linux/pnp.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
@@ -76,6 +77,9 @@ struct radio_isa_ops {
/* Top level structure needed to instantiate the cards */
struct radio_isa_driver {
struct isa_driver driver;
+#ifdef CONFIG_PNP
+ struct pnp_driver pnp_driver;
+#endif
const struct radio_isa_ops *ops;
/* The module_param_array with the specified I/O ports */
int *io_params;
@@ -101,5 +105,10 @@ struct radio_isa_driver {
int radio_isa_match(struct device *pdev, unsigned int dev);
int radio_isa_probe(struct device *pdev, unsigned int dev);
int radio_isa_remove(struct device *pdev, unsigned int dev);
+#ifdef CONFIG_PNP
+int radio_isa_pnp_probe(struct pnp_dev *dev,
+ const struct pnp_device_id *dev_id);
+void radio_isa_pnp_remove(struct pnp_dev *dev);
+#endif
#endif
diff --git a/drivers/media/radio/radio-keene.c b/drivers/media/radio/radio-keene.c
index 55bd1d2937c8..79adf3e654e5 100644
--- a/drivers/media/radio/radio-keene.c
+++ b/drivers/media/radio/radio-keene.c
@@ -28,7 +28,6 @@
#include <media/v4l2-ctrls.h>
#include <media/v4l2-event.h>
#include <linux/usb.h>
-#include <linux/version.h>
#include <linux/mutex.h>
/* driver and module definitions */
@@ -149,7 +148,6 @@ static void usb_keene_disconnect(struct usb_interface *intf)
{
struct keene_device *radio = to_keene_dev(usb_get_intfdata(intf));
- v4l2_device_get(&radio->v4l2_dev);
mutex_lock(&radio->lock);
usb_set_intfdata(intf, NULL);
video_unregister_device(&radio->vdev);
@@ -158,6 +156,23 @@ static void usb_keene_disconnect(struct usb_interface *intf)
v4l2_device_put(&radio->v4l2_dev);
}
+static int usb_keene_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct keene_device *radio = to_keene_dev(usb_get_intfdata(intf));
+
+ return keene_cmd_main(radio, 0, false);
+}
+
+static int usb_keene_resume(struct usb_interface *intf)
+{
+ struct keene_device *radio = to_keene_dev(usb_get_intfdata(intf));
+
+ mdelay(50);
+ keene_cmd_set(radio);
+ keene_cmd_main(radio, radio->curfreq, true);
+ return 0;
+}
+
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *v)
{
@@ -256,18 +271,6 @@ static int keene_s_ctrl(struct v4l2_ctrl *ctrl)
return -EINVAL;
}
-static int vidioc_subscribe_event(struct v4l2_fh *fh,
- struct v4l2_event_subscription *sub)
-{
- switch (sub->type) {
- case V4L2_EVENT_CTRL:
- return v4l2_event_subscribe(fh, sub, 0);
- default:
- return -EINVAL;
- }
-}
-
-
/* File system interface */
static const struct v4l2_file_operations usb_keene_fops = {
.owner = THIS_MODULE,
@@ -288,7 +291,7 @@ static const struct v4l2_ioctl_ops usb_keene_ioctl_ops = {
.vidioc_g_frequency = vidioc_g_frequency,
.vidioc_s_frequency = vidioc_s_frequency,
.vidioc_log_status = v4l2_ctrl_log_status,
- .vidioc_subscribe_event = vidioc_subscribe_event,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
@@ -404,6 +407,9 @@ static struct usb_driver usb_keene_driver = {
.probe = usb_keene_probe,
.disconnect = usb_keene_disconnect,
.id_table = usb_keene_device_table,
+ .suspend = usb_keene_suspend,
+ .resume = usb_keene_resume,
+ .reset_resume = usb_keene_resume,
};
static int __init keene_init(void)
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c
index a860a72a58ec..94cb6bc690f5 100644
--- a/drivers/media/radio/radio-mr800.c
+++ b/drivers/media/radio/radio-mr800.c
@@ -62,6 +62,8 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
#include <linux/usb.h>
#include <linux/mutex.h>
@@ -101,12 +103,17 @@ devices, that would be 76 and 91. */
* List isn't full and will be updated with implementation of new functions
*/
#define AMRADIO_SET_FREQ 0xa4
+#define AMRADIO_GET_READY_FLAG 0xa5
+#define AMRADIO_GET_SIGNAL 0xa7
+#define AMRADIO_GET_FREQ 0xa8
+#define AMRADIO_SET_SEARCH_UP 0xa9
+#define AMRADIO_SET_SEARCH_DOWN 0xaa
#define AMRADIO_SET_MUTE 0xab
+#define AMRADIO_SET_RIGHT_MUTE 0xac
+#define AMRADIO_SET_LEFT_MUTE 0xad
#define AMRADIO_SET_MONO 0xae
-
-/* Comfortable defines for amradio_set_mute */
-#define AMRADIO_START 0x00
-#define AMRADIO_STOP 0x01
+#define AMRADIO_SET_SEARCH_LVL 0xb0
+#define AMRADIO_STOP_SEARCH 0xb1
/* Comfortable defines for amradio_set_stereo */
#define WANT_STEREO 0x00
@@ -117,29 +124,20 @@ static int radio_nr = -1;
module_param(radio_nr, int, 0);
MODULE_PARM_DESC(radio_nr, "Radio Nr");
-static int usb_amradio_probe(struct usb_interface *intf,
- const struct usb_device_id *id);
-static void usb_amradio_disconnect(struct usb_interface *intf);
-static int usb_amradio_open(struct file *file);
-static int usb_amradio_close(struct file *file);
-static int usb_amradio_suspend(struct usb_interface *intf,
- pm_message_t message);
-static int usb_amradio_resume(struct usb_interface *intf);
-
/* Data for one (physical) device */
struct amradio_device {
/* reference to USB and video device */
struct usb_device *usbdev;
struct usb_interface *intf;
- struct video_device videodev;
+ struct video_device vdev;
struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler hdl;
- unsigned char *buffer;
+ u8 *buffer;
struct mutex lock; /* buffer locking */
int curfreq;
int stereo;
int muted;
- int initialized;
};
static inline struct amradio_device *to_amradio_dev(struct v4l2_device *v4l2_dev)
@@ -147,29 +145,8 @@ static inline struct amradio_device *to_amradio_dev(struct v4l2_device *v4l2_dev
return container_of(v4l2_dev, struct amradio_device, v4l2_dev);
}
-/* USB Device ID List */
-static struct usb_device_id usb_amradio_device_table[] = {
- {USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT,
- USB_CLASS_HID, 0, 0) },
- { } /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, usb_amradio_device_table);
-
-/* USB subsystem interface */
-static struct usb_driver usb_amradio_driver = {
- .name = MR800_DRIVER_NAME,
- .probe = usb_amradio_probe,
- .disconnect = usb_amradio_disconnect,
- .suspend = usb_amradio_suspend,
- .resume = usb_amradio_resume,
- .reset_resume = usb_amradio_resume,
- .id_table = usb_amradio_device_table,
- .supports_autosuspend = 1,
-};
-
-/* switch on/off the radio. Send 8 bytes to device */
-static int amradio_set_mute(struct amradio_device *radio, char argument)
+static int amradio_send_cmd(struct amradio_device *radio, u8 cmd, u8 arg,
+ u8 *extra, u8 extralen, bool reply)
{
int retval;
int size;
@@ -177,99 +154,92 @@ static int amradio_set_mute(struct amradio_device *radio, char argument)
radio->buffer[0] = 0x00;
radio->buffer[1] = 0x55;
radio->buffer[2] = 0xaa;
- radio->buffer[3] = 0x00;
- radio->buffer[4] = AMRADIO_SET_MUTE;
- radio->buffer[5] = argument;
+ radio->buffer[3] = extralen;
+ radio->buffer[4] = cmd;
+ radio->buffer[5] = arg;
radio->buffer[6] = 0x00;
- radio->buffer[7] = 0x00;
+ radio->buffer[7] = extra || reply ? 8 : 0;
retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
- (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
+ radio->buffer, BUFFER_LENGTH, &size, USB_TIMEOUT);
if (retval < 0 || size != BUFFER_LENGTH) {
- amradio_dev_warn(&radio->videodev.dev, "set mute failed\n");
- return retval;
+ if (video_is_registered(&radio->vdev))
+ amradio_dev_warn(&radio->vdev.dev,
+ "cmd %02x failed\n", cmd);
+ return retval ? retval : -EIO;
}
+ if (!extra && !reply)
+ return 0;
- radio->muted = argument;
+ if (extra) {
+ memcpy(radio->buffer, extra, extralen);
+ memset(radio->buffer + extralen, 0, 8 - extralen);
+ retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
+ radio->buffer, BUFFER_LENGTH, &size, USB_TIMEOUT);
+ } else {
+ memset(radio->buffer, 0, 8);
+ retval = usb_bulk_msg(radio->usbdev, usb_rcvbulkpipe(radio->usbdev, 0x81),
+ radio->buffer, BUFFER_LENGTH, &size, USB_TIMEOUT);
+ }
+ if (retval == 0 && size == BUFFER_LENGTH)
+ return 0;
+ if (video_is_registered(&radio->vdev) && cmd != AMRADIO_GET_READY_FLAG)
+ amradio_dev_warn(&radio->vdev.dev, "follow-up to cmd %02x failed\n", cmd);
+ return retval ? retval : -EIO;
+}
- return retval;
+/* switch on/off the radio. Send 8 bytes to device */
+static int amradio_set_mute(struct amradio_device *radio, bool mute)
+{
+ int ret = amradio_send_cmd(radio,
+ AMRADIO_SET_MUTE, mute, NULL, 0, false);
+
+ if (!ret)
+ radio->muted = mute;
+ return ret;
}
/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
-static int amradio_setfreq(struct amradio_device *radio, int freq)
+static int amradio_set_freq(struct amradio_device *radio, int freq)
{
- int retval;
- int size;
unsigned short freq_send = 0x10 + (freq >> 3) / 25;
-
- radio->buffer[0] = 0x00;
- radio->buffer[1] = 0x55;
- radio->buffer[2] = 0xaa;
- radio->buffer[3] = 0x03;
- radio->buffer[4] = AMRADIO_SET_FREQ;
- radio->buffer[5] = 0x00;
- radio->buffer[6] = 0x00;
- radio->buffer[7] = 0x08;
-
- retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
- (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
-
- if (retval < 0 || size != BUFFER_LENGTH)
- goto out_err;
+ u8 buf[3];
+ int retval;
/* frequency is calculated from freq_send and placed in first 2 bytes */
- radio->buffer[0] = (freq_send >> 8) & 0xff;
- radio->buffer[1] = freq_send & 0xff;
- radio->buffer[2] = 0x01;
- radio->buffer[3] = 0x00;
- radio->buffer[4] = 0x00;
- /* 5 and 6 bytes of buffer already = 0x00 */
- radio->buffer[7] = 0x00;
-
- retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
- (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
-
- if (retval < 0 || size != BUFFER_LENGTH)
- goto out_err;
+ buf[0] = (freq_send >> 8) & 0xff;
+ buf[1] = freq_send & 0xff;
+ buf[2] = 0x01;
+ retval = amradio_send_cmd(radio, AMRADIO_SET_FREQ, 0, buf, 3, false);
+ if (retval)
+ return retval;
radio->curfreq = freq;
- goto out;
-
-out_err:
- amradio_dev_warn(&radio->videodev.dev, "set frequency failed\n");
-out:
- return retval;
+ msleep(40);
+ return 0;
}
-static int amradio_set_stereo(struct amradio_device *radio, char argument)
+static int amradio_set_stereo(struct amradio_device *radio, bool stereo)
{
- int retval;
- int size;
+ int ret = amradio_send_cmd(radio,
+ AMRADIO_SET_MONO, !stereo, NULL, 0, false);
- radio->buffer[0] = 0x00;
- radio->buffer[1] = 0x55;
- radio->buffer[2] = 0xaa;
- radio->buffer[3] = 0x00;
- radio->buffer[4] = AMRADIO_SET_MONO;
- radio->buffer[5] = argument;
- radio->buffer[6] = 0x00;
- radio->buffer[7] = 0x00;
-
- retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
- (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT);
-
- if (retval < 0 || size != BUFFER_LENGTH) {
- amradio_dev_warn(&radio->videodev.dev, "set stereo failed\n");
- return retval;
- }
+ if (!ret)
+ radio->stereo = stereo;
+ return ret;
+}
- if (argument == WANT_STEREO)
- radio->stereo = 1;
- else
- radio->stereo = 0;
+static int amradio_get_stat(struct amradio_device *radio, bool *is_stereo, u32 *signal)
+{
+ int ret = amradio_send_cmd(radio,
+ AMRADIO_GET_SIGNAL, 0, NULL, 0, true);
- return retval;
+ if (ret)
+ return ret;
+ *is_stereo = radio->buffer[2] >> 7;
+ *signal = (radio->buffer[3] & 0xf0) << 8;
+ return 0;
}
/* Handle unplugging the device.
@@ -282,25 +252,26 @@ static void usb_amradio_disconnect(struct usb_interface *intf)
struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
mutex_lock(&radio->lock);
- /* increase the device node's refcount */
- get_device(&radio->videodev.dev);
+ video_unregister_device(&radio->vdev);
+ amradio_set_mute(radio, true);
+ usb_set_intfdata(intf, NULL);
v4l2_device_disconnect(&radio->v4l2_dev);
- video_unregister_device(&radio->videodev);
mutex_unlock(&radio->lock);
- /* decrease the device node's refcount, allowing it to be released */
- put_device(&radio->videodev.dev);
+ v4l2_device_put(&radio->v4l2_dev);
}
/* vidioc_querycap - query device capabilities */
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *v)
{
- struct amradio_device *radio = file->private_data;
+ struct amradio_device *radio = video_drvdata(file);
strlcpy(v->driver, "radio-mr800", sizeof(v->driver));
strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
- v->capabilities = V4L2_CAP_TUNER;
+ v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER |
+ V4L2_CAP_HW_FREQ_SEEK;
+ v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -308,44 +279,34 @@ static int vidioc_querycap(struct file *file, void *priv,
static int vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *v)
{
- struct amradio_device *radio = file->private_data;
+ struct amradio_device *radio = video_drvdata(file);
+ bool is_stereo = false;
int retval;
if (v->index > 0)
return -EINVAL;
-/* TODO: Add function which look is signal stereo or not
- * amradio_getstat(radio);
- */
-
-/* we call amradio_set_stereo to set radio->stereo
- * Honestly, amradio_getstat should cover this in future and
- * amradio_set_stereo shouldn't be here
- */
- retval = amradio_set_stereo(radio, WANT_STEREO);
+ v->signal = 0;
+ retval = amradio_get_stat(radio, &is_stereo, &v->signal);
+ if (retval)
+ return retval;
strcpy(v->name, "FM");
v->type = V4L2_TUNER_RADIO;
v->rangelow = FREQ_MIN * FREQ_MUL;
v->rangehigh = FREQ_MAX * FREQ_MUL;
- v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
- v->capability = V4L2_TUNER_CAP_LOW;
- if (radio->stereo)
- v->audmode = V4L2_TUNER_MODE_STEREO;
- else
- v->audmode = V4L2_TUNER_MODE_MONO;
- v->signal = 0xffff; /* Can't get the signal strength, sad.. */
- v->afc = 0; /* Don't know what is this */
-
- return retval;
+ v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+ v->rxsubchans = is_stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+ v->audmode = radio->stereo ?
+ V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO;
+ return 0;
}
/* vidioc_s_tuner - set tuner attributes */
static int vidioc_s_tuner(struct file *file, void *priv,
struct v4l2_tuner *v)
{
- struct amradio_device *radio = file->private_data;
- int retval = -EINVAL;
+ struct amradio_device *radio = video_drvdata(file);
if (v->index > 0)
return -EINVAL;
@@ -353,34 +314,31 @@ static int vidioc_s_tuner(struct file *file, void *priv,
/* mono/stereo selector */
switch (v->audmode) {
case V4L2_TUNER_MODE_MONO:
- retval = amradio_set_stereo(radio, WANT_MONO);
- break;
- case V4L2_TUNER_MODE_STEREO:
- retval = amradio_set_stereo(radio, WANT_STEREO);
- break;
+ return amradio_set_stereo(radio, WANT_MONO);
+ default:
+ return amradio_set_stereo(radio, WANT_STEREO);
}
-
- return retval;
}
/* vidioc_s_frequency - set tuner radio frequency */
static int vidioc_s_frequency(struct file *file, void *priv,
struct v4l2_frequency *f)
{
- struct amradio_device *radio = file->private_data;
+ struct amradio_device *radio = video_drvdata(file);
- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+ if (f->tuner != 0)
return -EINVAL;
- return amradio_setfreq(radio, f->frequency);
+ return amradio_set_freq(radio, clamp_t(unsigned, f->frequency,
+ FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL));
}
/* vidioc_g_frequency - get tuner radio frequency */
static int vidioc_g_frequency(struct file *file, void *priv,
struct v4l2_frequency *f)
{
- struct amradio_device *radio = file->private_data;
+ struct amradio_device *radio = video_drvdata(file);
- if (f->tuner != 0)
+ if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
return -EINVAL;
f->type = V4L2_TUNER_RADIO;
f->frequency = radio->curfreq;
@@ -388,148 +346,101 @@ static int vidioc_g_frequency(struct file *file, void *priv,
return 0;
}
-/* vidioc_queryctrl - enumerate control items */
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
+static int vidioc_s_hw_freq_seek(struct file *file, void *priv,
+ struct v4l2_hw_freq_seek *seek)
{
- switch (qc->id) {
- case V4L2_CID_AUDIO_MUTE:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
- }
-
- return -EINVAL;
-}
+ static u8 buf[8] = {
+ 0x3d, 0x32, 0x0f, 0x08, 0x3d, 0x32, 0x0f, 0x08
+ };
+ struct amradio_device *radio = video_drvdata(file);
+ unsigned long timeout;
+ int retval;
-/* vidioc_g_ctrl - get the value of a control */
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct amradio_device *radio = file->private_data;
+ if (seek->tuner != 0 || !seek->wrap_around)
+ return -EINVAL;
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- ctrl->value = radio->muted;
- return 0;
+ retval = amradio_send_cmd(radio,
+ AMRADIO_SET_SEARCH_LVL, 0, buf, 8, false);
+ if (retval)
+ return retval;
+ amradio_set_freq(radio, radio->curfreq);
+ retval = amradio_send_cmd(radio,
+ seek->seek_upward ? AMRADIO_SET_SEARCH_UP : AMRADIO_SET_SEARCH_DOWN,
+ 0, NULL, 0, false);
+ if (retval)
+ return retval;
+ timeout = jiffies + msecs_to_jiffies(30000);
+ for (;;) {
+ if (time_after(jiffies, timeout)) {
+ retval = -EAGAIN;
+ break;
+ }
+ if (schedule_timeout_interruptible(msecs_to_jiffies(10))) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ retval = amradio_send_cmd(radio, AMRADIO_GET_READY_FLAG,
+ 0, NULL, 0, true);
+ if (retval)
+ continue;
+ amradio_send_cmd(radio, AMRADIO_GET_FREQ, 0, NULL, 0, true);
+ if (radio->buffer[1] || radio->buffer[2]) {
+ radio->curfreq = (radio->buffer[1] << 8) | radio->buffer[2];
+ radio->curfreq = (radio->curfreq - 0x10) * 200;
+ amradio_send_cmd(radio, AMRADIO_STOP_SEARCH,
+ 0, NULL, 0, false);
+ amradio_set_freq(radio, radio->curfreq);
+ retval = 0;
+ break;
+ }
}
-
- return -EINVAL;
+ amradio_send_cmd(radio, AMRADIO_STOP_SEARCH, 0, NULL, 0, false);
+ amradio_set_freq(radio, radio->curfreq);
+ return retval;
}
-/* vidioc_s_ctrl - set the value of a control */
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
+static int usb_amradio_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct amradio_device *radio = file->private_data;
- int retval = -EINVAL;
+ struct amradio_device *radio =
+ container_of(ctrl->handler, struct amradio_device, hdl);
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
- if (ctrl->value)
- retval = amradio_set_mute(radio, AMRADIO_STOP);
- else
- retval = amradio_set_mute(radio, AMRADIO_START);
-
- break;
+ return amradio_set_mute(radio, ctrl->val);
}
- return retval;
-}
-
-/* vidioc_g_audio - get audio attributes */
-static int vidioc_g_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- if (a->index > 1)
- return -EINVAL;
-
- strcpy(a->name, "Radio");
- a->capability = V4L2_AUDCAP_STEREO;
- return 0;
-}
-
-/* vidioc_s_audio - set audio attributes */
-static int vidioc_s_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- if (a->index != 0)
- return -EINVAL;
- return 0;
-}
-
-/* vidioc_g_input - get input */
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-
-/* vidioc_s_input - set input */
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
- if (i != 0)
- return -EINVAL;
- return 0;
+ return -EINVAL;
}
static int usb_amradio_init(struct amradio_device *radio)
{
int retval;
- retval = amradio_set_mute(radio, AMRADIO_STOP);
+ retval = amradio_set_mute(radio, true);
if (retval)
goto out_err;
-
- retval = amradio_set_stereo(radio, WANT_STEREO);
+ retval = amradio_set_stereo(radio, true);
if (retval)
goto out_err;
-
- radio->initialized = 1;
- goto out;
-
-out_err:
- amradio_dev_err(&radio->videodev.dev, "initialization failed\n");
-out:
- return retval;
-}
-
-/* open device - amradio_start() and amradio_setfreq() */
-static int usb_amradio_open(struct file *file)
-{
- struct amradio_device *radio = video_drvdata(file);
- int retval;
-
- file->private_data = radio;
- retval = usb_autopm_get_interface(radio->intf);
+ retval = amradio_set_freq(radio, radio->curfreq);
if (retval)
- return retval;
+ goto out_err;
+ return 0;
- if (unlikely(!radio->initialized)) {
- retval = usb_amradio_init(radio);
- if (retval)
- usb_autopm_put_interface(radio->intf);
- }
+out_err:
+ amradio_dev_err(&radio->vdev.dev, "initialization failed\n");
return retval;
}
-/*close device */
-static int usb_amradio_close(struct file *file)
-{
- struct amradio_device *radio = file->private_data;
-
- if (video_is_registered(&radio->videodev))
- usb_autopm_put_interface(radio->intf);
- return 0;
-}
-
/* Suspend device - stop device. Need to be checked and fixed */
static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
{
struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
mutex_lock(&radio->lock);
- if (!radio->muted && radio->initialized) {
- amradio_set_mute(radio, AMRADIO_STOP);
- radio->muted = 0;
+ if (!radio->muted) {
+ amradio_set_mute(radio, true);
+ radio->muted = false;
}
mutex_unlock(&radio->lock);
@@ -543,31 +454,28 @@ static int usb_amradio_resume(struct usb_interface *intf)
struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
mutex_lock(&radio->lock);
- if (unlikely(!radio->initialized))
- goto unlock;
-
- if (radio->stereo)
- amradio_set_stereo(radio, WANT_STEREO);
- else
- amradio_set_stereo(radio, WANT_MONO);
-
- amradio_setfreq(radio, radio->curfreq);
+ amradio_set_stereo(radio, radio->stereo);
+ amradio_set_freq(radio, radio->curfreq);
if (!radio->muted)
- amradio_set_mute(radio, AMRADIO_START);
+ amradio_set_mute(radio, false);
-unlock:
mutex_unlock(&radio->lock);
dev_info(&intf->dev, "coming out of suspend..\n");
return 0;
}
+static const struct v4l2_ctrl_ops usb_amradio_ctrl_ops = {
+ .s_ctrl = usb_amradio_s_ctrl,
+};
+
/* File system interface */
static const struct v4l2_file_operations usb_amradio_fops = {
.owner = THIS_MODULE,
- .open = usb_amradio_open,
- .release = usb_amradio_close,
+ .open = v4l2_fh_open,
+ .release = v4l2_fh_release,
+ .poll = v4l2_ctrl_poll,
.unlocked_ioctl = video_ioctl2,
};
@@ -577,20 +485,19 @@ static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
.vidioc_s_tuner = vidioc_s_tuner,
.vidioc_g_frequency = vidioc_g_frequency,
.vidioc_s_frequency = vidioc_s_frequency,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
+ .vidioc_s_hw_freq_seek = vidioc_s_hw_freq_seek,
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
-static void usb_amradio_video_device_release(struct video_device *videodev)
+static void usb_amradio_release(struct v4l2_device *v4l2_dev)
{
- struct amradio_device *radio = video_get_drvdata(videodev);
+ struct amradio_device *radio = to_amradio_dev(v4l2_dev);
/* free rest memory */
+ v4l2_ctrl_handler_free(&radio->hdl);
+ v4l2_device_unregister(&radio->v4l2_dev);
kfree(radio->buffer);
kfree(radio);
}
@@ -624,23 +531,38 @@ static int usb_amradio_probe(struct usb_interface *intf,
goto err_v4l2;
}
+ v4l2_ctrl_handler_init(&radio->hdl, 1);
+ v4l2_ctrl_new_std(&radio->hdl, &usb_amradio_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+ if (radio->hdl.error) {
+ retval = radio->hdl.error;
+ dev_err(&intf->dev, "couldn't register control\n");
+ goto err_ctrl;
+ }
mutex_init(&radio->lock);
- strlcpy(radio->videodev.name, radio->v4l2_dev.name,
- sizeof(radio->videodev.name));
- radio->videodev.v4l2_dev = &radio->v4l2_dev;
- radio->videodev.fops = &usb_amradio_fops;
- radio->videodev.ioctl_ops = &usb_amradio_ioctl_ops;
- radio->videodev.release = usb_amradio_video_device_release;
- radio->videodev.lock = &radio->lock;
+ radio->v4l2_dev.ctrl_handler = &radio->hdl;
+ radio->v4l2_dev.release = usb_amradio_release;
+ strlcpy(radio->vdev.name, radio->v4l2_dev.name,
+ sizeof(radio->vdev.name));
+ radio->vdev.v4l2_dev = &radio->v4l2_dev;
+ radio->vdev.fops = &usb_amradio_fops;
+ radio->vdev.ioctl_ops = &usb_amradio_ioctl_ops;
+ radio->vdev.release = video_device_release_empty;
+ radio->vdev.lock = &radio->lock;
+ set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags);
radio->usbdev = interface_to_usbdev(intf);
radio->intf = intf;
+ usb_set_intfdata(intf, &radio->v4l2_dev);
radio->curfreq = 95.16 * FREQ_MUL;
- video_set_drvdata(&radio->videodev, radio);
+ video_set_drvdata(&radio->vdev, radio);
+ retval = usb_amradio_init(radio);
+ if (retval)
+ goto err_vdev;
- retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO,
+ retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO,
radio_nr);
if (retval < 0) {
dev_err(&intf->dev, "could not register video device\n");
@@ -650,6 +572,8 @@ static int usb_amradio_probe(struct usb_interface *intf,
return 0;
err_vdev:
+ v4l2_ctrl_handler_free(&radio->hdl);
+err_ctrl:
v4l2_device_unregister(&radio->v4l2_dev);
err_v4l2:
kfree(radio->buffer);
@@ -659,4 +583,24 @@ err:
return retval;
}
+/* USB Device ID List */
+static struct usb_device_id usb_amradio_device_table[] = {
+ { USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT,
+ USB_CLASS_HID, 0, 0) },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, usb_amradio_device_table);
+
+/* USB subsystem interface */
+static struct usb_driver usb_amradio_driver = {
+ .name = MR800_DRIVER_NAME,
+ .probe = usb_amradio_probe,
+ .disconnect = usb_amradio_disconnect,
+ .suspend = usb_amradio_suspend,
+ .resume = usb_amradio_resume,
+ .reset_resume = usb_amradio_resume,
+ .id_table = usb_amradio_device_table,
+};
+
module_usb_driver(usb_amradio_driver);
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index b275c5d0fe9a..b1f844c64fde 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -17,6 +17,7 @@
#include <linux/videodev2.h> /* kernel radio structs */
#include <linux/mutex.h>
#include <linux/io.h> /* outb, outb_p */
+#include <linux/slab.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include "radio-isa.h"
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 22c5743bf9db..a81d723b8c77 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -1,4 +1,4 @@
-/* SF16-FMI and SF16-FMP radio driver for Linux radio support
+/* SF16-FMI, SF16-FMP and SF16-FMD radio driver for Linux radio support
* heavily based on rtrack driver...
* (c) 1997 M. Kirkwood
* (c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz
@@ -11,7 +11,7 @@
*
* Frequency control is done digitally -- ie out(port,encodefreq(95.8));
* No volume control - only mute/unmute - you have to use line volume
- * control on SB-part of SF16-FMI/SF16-FMP
+ * control on SB-part of SF16-FMI/SF16-FMP/SF16-FMD
*
* Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
*/
@@ -29,7 +29,7 @@
#include <media/v4l2-ioctl.h>
MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood");
-MODULE_DESCRIPTION("A driver for the SF16-FMI and SF16-FMP radio.");
+MODULE_DESCRIPTION("A driver for the SF16-FMI, SF16-FMP and SF16-FMD radio.");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.0.3");
@@ -37,7 +37,7 @@ static int io = -1;
static int radio_nr = -1;
module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the SF16-FMI or SF16-FMP card (0x284 or 0x384)");
+MODULE_PARM_DESC(io, "I/O address of the SF16-FMI/SF16-FMP/SF16-FMD card (0x284 or 0x384)");
module_param(radio_nr, int, 0);
struct fmi
@@ -130,7 +130,7 @@ static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *v)
{
strlcpy(v->driver, "radio-sf16fmi", sizeof(v->driver));
- strlcpy(v->card, "SF16-FMx radio", sizeof(v->card));
+ strlcpy(v->card, "SF16-FMI/FMP/FMD radio", sizeof(v->card));
strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
return 0;
@@ -277,8 +277,12 @@ static const struct v4l2_ioctl_ops fmi_ioctl_ops = {
/* ladis: this is my card. does any other types exist? */
static struct isapnp_device_id id_table[] __devinitdata = {
+ /* SF16-FMI */
{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,
ISAPNP_VENDOR('M','F','R'), ISAPNP_FUNCTION(0xad10), 0},
+ /* SF16-FMD */
+ { ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+ ISAPNP_VENDOR('M','F','R'), ISAPNP_FUNCTION(0xad12), 0},
{ ISAPNP_CARD_END, },
};
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index 7c69214334bf..52b8011f1b23 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -1,4 +1,4 @@
-/* SF16-FMR2 radio driver for Linux
+/* SF16-FMR2 and SF16-FMD2 radio driver for Linux
* Copyright (c) 2011 Ondrej Zary
*
* Original driver was (c) 2000-2002 Ziglio Frediano, freddy77@angelfire.com
@@ -13,15 +13,19 @@
#include <linux/ioport.h> /* request_region */
#include <linux/io.h> /* outb, outb_p */
#include <linux/isa.h>
+#include <linux/pnp.h>
#include <sound/tea575x-tuner.h>
MODULE_AUTHOR("Ondrej Zary");
-MODULE_DESCRIPTION("MediaForte SF16-FMR2 FM radio card driver");
+MODULE_DESCRIPTION("MediaForte SF16-FMR2 and SF16-FMD2 FM radio card driver");
MODULE_LICENSE("GPL");
-static int radio_nr = -1;
-module_param(radio_nr, int, 0444);
-MODULE_PARM_DESC(radio_nr, "Radio device number");
+/* these cards can only use two different ports (0x384 and 0x284) */
+#define FMR2_MAX 2
+
+static int radio_nr[FMR2_MAX] = { [0 ... (FMR2_MAX - 1)] = -1 };
+module_param_array(radio_nr, int, NULL, 0444);
+MODULE_PARM_DESC(radio_nr, "Radio device numbers");
struct fmr2 {
int io;
@@ -29,9 +33,15 @@ struct fmr2 {
struct snd_tea575x tea;
struct v4l2_ctrl *volume;
struct v4l2_ctrl *balance;
+ bool is_fmd2;
};
-/* the port is hardwired so no need to support multiple cards */
+static int num_fmr2_cards;
+static struct fmr2 *fmr2_cards[FMR2_MAX];
+static bool isa_registered;
+static bool pnp_registered;
+
+/* the port is hardwired on SF16-FMR2 */
#define FMR2_PORT 0x384
/* TEA575x tuner pins */
@@ -174,7 +184,8 @@ static int fmr2_tea_ext_init(struct snd_tea575x *tea)
{
struct fmr2 *fmr2 = tea->private_data;
- if (inb(fmr2->io) & FMR2_HASVOL) {
+ /* FMR2 can have volume control, FMD2 can't (uses SB16 mixer) */
+ if (!fmr2->is_fmd2 && inb(fmr2->io) & FMR2_HASVOL) {
fmr2->volume = v4l2_ctrl_new_std(&tea->ctrl_handler, &fmr2_ctrl_ops, V4L2_CID_AUDIO_VOLUME, 0, 68, 2, 56);
fmr2->balance = v4l2_ctrl_new_std(&tea->ctrl_handler, &fmr2_ctrl_ops, V4L2_CID_AUDIO_BALANCE, -68, 68, 2, 0);
if (tea->ctrl_handler.error) {
@@ -186,22 +197,28 @@ static int fmr2_tea_ext_init(struct snd_tea575x *tea)
return 0;
}
-static int __devinit fmr2_probe(struct device *pdev, unsigned int dev)
+static struct pnp_device_id fmr2_pnp_ids[] __devinitdata = {
+ { .id = "MFRad13" }, /* tuner subdevice of SF16-FMD2 */
+ { .id = "" }
+};
+MODULE_DEVICE_TABLE(pnp, fmr2_pnp_ids);
+
+static int __devinit fmr2_probe(struct fmr2 *fmr2, struct device *pdev, int io)
{
- struct fmr2 *fmr2;
- int err;
+ int err, i;
+ char *card_name = fmr2->is_fmd2 ? "SF16-FMD2" : "SF16-FMR2";
- fmr2 = kzalloc(sizeof(*fmr2), GFP_KERNEL);
- if (fmr2 == NULL)
- return -ENOMEM;
+ /* avoid errors if a card was already registered at given port */
+ for (i = 0; i < num_fmr2_cards; i++)
+ if (io == fmr2_cards[i]->io)
+ return -EBUSY;
- strlcpy(fmr2->v4l2_dev.name, dev_name(pdev),
- sizeof(fmr2->v4l2_dev.name));
- fmr2->io = FMR2_PORT;
+ strlcpy(fmr2->v4l2_dev.name, "radio-sf16fmr2",
+ sizeof(fmr2->v4l2_dev.name)),
+ fmr2->io = io;
if (!request_region(fmr2->io, 2, fmr2->v4l2_dev.name)) {
printk(KERN_ERR "radio-sf16fmr2: I/O port 0x%x already in use\n", fmr2->io);
- kfree(fmr2);
return -EBUSY;
}
@@ -210,56 +227,121 @@ static int __devinit fmr2_probe(struct device *pdev, unsigned int dev)
if (err < 0) {
v4l2_err(&fmr2->v4l2_dev, "Could not register v4l2_device\n");
release_region(fmr2->io, 2);
- kfree(fmr2);
return err;
}
fmr2->tea.v4l2_dev = &fmr2->v4l2_dev;
fmr2->tea.private_data = fmr2;
- fmr2->tea.radio_nr = radio_nr;
+ fmr2->tea.radio_nr = radio_nr[num_fmr2_cards];
fmr2->tea.ops = &fmr2_tea_ops;
fmr2->tea.ext_init = fmr2_tea_ext_init;
- strlcpy(fmr2->tea.card, "SF16-FMR2", sizeof(fmr2->tea.card));
- snprintf(fmr2->tea.bus_info, sizeof(fmr2->tea.bus_info), "ISA:%s",
- fmr2->v4l2_dev.name);
+ strlcpy(fmr2->tea.card, card_name, sizeof(fmr2->tea.card));
+ snprintf(fmr2->tea.bus_info, sizeof(fmr2->tea.bus_info), "%s:%s",
+ fmr2->is_fmd2 ? "PnP" : "ISA", dev_name(pdev));
if (snd_tea575x_init(&fmr2->tea)) {
printk(KERN_ERR "radio-sf16fmr2: Unable to detect TEA575x tuner\n");
release_region(fmr2->io, 2);
- kfree(fmr2);
return -ENODEV;
}
- printk(KERN_INFO "radio-sf16fmr2: SF16-FMR2 radio card at 0x%x.\n", fmr2->io);
+ printk(KERN_INFO "radio-sf16fmr2: %s radio card at 0x%x.\n",
+ card_name, fmr2->io);
return 0;
}
-static int __exit fmr2_remove(struct device *pdev, unsigned int dev)
+static int __devinit fmr2_isa_match(struct device *pdev, unsigned int ndev)
+{
+ struct fmr2 *fmr2 = kzalloc(sizeof(*fmr2), GFP_KERNEL);
+ if (!fmr2)
+ return 0;
+
+ if (fmr2_probe(fmr2, pdev, FMR2_PORT)) {
+ kfree(fmr2);
+ return 0;
+ }
+ dev_set_drvdata(pdev, fmr2);
+ fmr2_cards[num_fmr2_cards++] = fmr2;
+
+ return 1;
+}
+
+static int __devinit fmr2_pnp_probe(struct pnp_dev *pdev,
+ const struct pnp_device_id *id)
{
- struct fmr2 *fmr2 = dev_get_drvdata(pdev);
+ int ret;
+ struct fmr2 *fmr2 = kzalloc(sizeof(*fmr2), GFP_KERNEL);
+ if (!fmr2)
+ return -ENOMEM;
+ fmr2->is_fmd2 = true;
+ ret = fmr2_probe(fmr2, &pdev->dev, pnp_port_start(pdev, 0));
+ if (ret) {
+ kfree(fmr2);
+ return ret;
+ }
+ pnp_set_drvdata(pdev, fmr2);
+ fmr2_cards[num_fmr2_cards++] = fmr2;
+
+ return 0;
+}
+
+static void __devexit fmr2_remove(struct fmr2 *fmr2)
+{
snd_tea575x_exit(&fmr2->tea);
release_region(fmr2->io, 2);
v4l2_device_unregister(&fmr2->v4l2_dev);
kfree(fmr2);
+}
+
+static int __devexit fmr2_isa_remove(struct device *pdev, unsigned int ndev)
+{
+ fmr2_remove(dev_get_drvdata(pdev));
+ dev_set_drvdata(pdev, NULL);
+
return 0;
}
-struct isa_driver fmr2_driver = {
- .probe = fmr2_probe,
- .remove = fmr2_remove,
+static void __devexit fmr2_pnp_remove(struct pnp_dev *pdev)
+{
+ fmr2_remove(pnp_get_drvdata(pdev));
+ pnp_set_drvdata(pdev, NULL);
+}
+
+struct isa_driver fmr2_isa_driver = {
+ .match = fmr2_isa_match,
+ .remove = __devexit_p(fmr2_isa_remove),
.driver = {
.name = "radio-sf16fmr2",
},
};
+struct pnp_driver fmr2_pnp_driver = {
+ .name = "radio-sf16fmr2",
+ .id_table = fmr2_pnp_ids,
+ .probe = fmr2_pnp_probe,
+ .remove = __devexit_p(fmr2_pnp_remove),
+};
+
static int __init fmr2_init(void)
{
- return isa_register_driver(&fmr2_driver, 1);
+ int ret;
+
+ ret = pnp_register_driver(&fmr2_pnp_driver);
+ if (!ret)
+ pnp_registered = true;
+ ret = isa_register_driver(&fmr2_isa_driver, 1);
+ if (!ret)
+ isa_registered = true;
+
+ return (pnp_registered || isa_registered) ? 0 : ret;
}
static void __exit fmr2_exit(void)
{
- isa_unregister_driver(&fmr2_driver);
+ if (pnp_registered)
+ pnp_unregister_driver(&fmr2_pnp_driver);
+ if (isa_registered)
+ isa_unregister_driver(&fmr2_isa_driver);
}
module_init(fmr2_init);
diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c
index 5d9a90ac3a1c..7052adc0c0b0 100644
--- a/drivers/media/radio/radio-timb.c
+++ b/drivers/media/radio/radio-timb.c
@@ -223,7 +223,7 @@ static struct platform_driver timbradio_platform_driver = {
.owner = THIS_MODULE,
},
.probe = timbradio_probe,
- .remove = timbradio_remove,
+ .remove = __devexit_p(timbradio_remove),
};
module_platform_driver(timbradio_platform_driver);
diff --git a/drivers/media/radio/saa7706h.c b/drivers/media/radio/saa7706h.c
index 9474706350f8..bb953ef75f61 100644
--- a/drivers/media/radio/saa7706h.c
+++ b/drivers/media/radio/saa7706h.c
@@ -430,7 +430,7 @@ static struct i2c_driver saa7706h_driver = {
.name = DRIVER_NAME,
},
.probe = saa7706h_probe,
- .remove = saa7706h_remove,
+ .remove = __devexit_p(saa7706h_remove),
.id_table = saa7706h_id,
};
diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c
index 0e740c98786c..969cf494d85b 100644
--- a/drivers/media/radio/si470x/radio-si470x-common.c
+++ b/drivers/media/radio/si470x/radio-si470x-common.c
@@ -196,9 +196,9 @@ static int si470x_set_chan(struct si470x_device *radio, unsigned short chan)
}
if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
- dev_warn(&radio->videodev->dev, "tune does not complete\n");
+ dev_warn(&radio->videodev.dev, "tune does not complete\n");
if (timed_out)
- dev_warn(&radio->videodev->dev,
+ dev_warn(&radio->videodev.dev,
"tune timed out after %u ms\n", tune_timeout);
stop:
@@ -262,7 +262,7 @@ static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq)
*/
int si470x_set_freq(struct si470x_device *radio, unsigned int freq)
{
- unsigned int spacing, band_bottom;
+ unsigned int spacing, band_bottom, band_top;
unsigned short chan;
/* Spacing (kHz) */
@@ -278,19 +278,26 @@ int si470x_set_freq(struct si470x_device *radio, unsigned int freq)
spacing = 0.050 * FREQ_MUL; break;
};
- /* Bottom of Band (MHz) */
+ /* Bottom/Top of Band (MHz) */
switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
/* 0: 87.5 - 108 MHz (USA, Europe) */
case 0:
- band_bottom = 87.5 * FREQ_MUL; break;
+ band_bottom = 87.5 * FREQ_MUL;
+ band_top = 108 * FREQ_MUL;
+ break;
/* 1: 76 - 108 MHz (Japan wide band) */
default:
- band_bottom = 76 * FREQ_MUL; break;
+ band_bottom = 76 * FREQ_MUL;
+ band_top = 108 * FREQ_MUL;
+ break;
/* 2: 76 - 90 MHz (Japan) */
case 2:
- band_bottom = 76 * FREQ_MUL; break;
+ band_bottom = 76 * FREQ_MUL;
+ band_top = 90 * FREQ_MUL;
+ break;
};
+ freq = clamp(freq, band_bottom, band_top);
/* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */
chan = (freq - band_bottom) / spacing;
@@ -320,7 +327,7 @@ static int si470x_set_seek(struct si470x_device *radio,
radio->registers[POWERCFG] &= ~POWERCFG_SEEKUP;
retval = si470x_set_register(radio, POWERCFG);
if (retval < 0)
- goto done;
+ return retval;
/* currently I2C driver only uses interrupt way to seek */
if (radio->stci_enabled) {
@@ -344,24 +351,19 @@ static int si470x_set_seek(struct si470x_device *radio,
}
if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
- dev_warn(&radio->videodev->dev, "seek does not complete\n");
+ dev_warn(&radio->videodev.dev, "seek does not complete\n");
if (radio->registers[STATUSRSSI] & STATUSRSSI_SF)
- dev_warn(&radio->videodev->dev,
+ dev_warn(&radio->videodev.dev,
"seek failed / band limit reached\n");
- if (timed_out)
- dev_warn(&radio->videodev->dev,
- "seek timed out after %u ms\n", seek_timeout);
stop:
/* stop seeking */
radio->registers[POWERCFG] &= ~POWERCFG_SEEK;
retval = si470x_set_register(radio, POWERCFG);
-done:
/* try again, if timed out */
- if ((retval == 0) && timed_out)
- retval = -EAGAIN;
-
+ if (retval == 0 && timed_out)
+ return -EAGAIN;
return retval;
}
@@ -463,7 +465,6 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf,
unsigned int block_count = 0;
/* switch on rds reception */
- mutex_lock(&radio->lock);
if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
si470x_rds_on(radio);
@@ -505,7 +506,6 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf,
}
done:
- mutex_unlock(&radio->lock);
return retval;
}
@@ -517,19 +517,19 @@ static unsigned int si470x_fops_poll(struct file *file,
struct poll_table_struct *pts)
{
struct si470x_device *radio = video_drvdata(file);
- int retval = 0;
+ unsigned long req_events = poll_requested_events(pts);
+ int retval = v4l2_ctrl_poll(file, pts);
- /* switch on rds reception */
-
- mutex_lock(&radio->lock);
- if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
- si470x_rds_on(radio);
- mutex_unlock(&radio->lock);
+ if (req_events & (POLLIN | POLLRDNORM)) {
+ /* switch on rds reception */
+ if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
+ si470x_rds_on(radio);
- poll_wait(file, &radio->read_queue, pts);
+ poll_wait(file, &radio->read_queue, pts);
- if (radio->rd_index != radio->wr_index)
- retval = POLLIN | POLLRDNORM;
+ if (radio->rd_index != radio->wr_index)
+ retval |= POLLIN | POLLRDNORM;
+ }
return retval;
}
@@ -553,134 +553,26 @@ static const struct v4l2_file_operations si470x_fops = {
* Video4Linux Interface
**************************************************************************/
-/*
- * si470x_vidioc_queryctrl - enumerate control items
- */
-static int si470x_vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- struct si470x_device *radio = video_drvdata(file);
- int retval = -EINVAL;
-
- /* abort if qc->id is below V4L2_CID_BASE */
- if (qc->id < V4L2_CID_BASE)
- goto done;
-
- /* search video control */
- switch (qc->id) {
- case V4L2_CID_AUDIO_VOLUME:
- return v4l2_ctrl_query_fill(qc, 0, 15, 1, 15);
- case V4L2_CID_AUDIO_MUTE:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
- }
-
- /* disable unsupported base controls */
- /* to satisfy kradio and such apps */
- if ((retval == -EINVAL) && (qc->id < V4L2_CID_LASTP1)) {
- qc->flags = V4L2_CTRL_FLAG_DISABLED;
- retval = 0;
- }
-done:
- if (retval < 0)
- dev_warn(&radio->videodev->dev,
- "query controls failed with %d\n", retval);
- return retval;
-}
-
-
-/*
- * si470x_vidioc_g_ctrl - get the value of a control
- */
-static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct si470x_device *radio = video_drvdata(file);
- int retval = 0;
-
- mutex_lock(&radio->lock);
- /* safety checks */
- retval = si470x_disconnect_check(radio);
- if (retval)
- goto done;
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_VOLUME:
- ctrl->value = radio->registers[SYSCONFIG2] &
- SYSCONFIG2_VOLUME;
- break;
- case V4L2_CID_AUDIO_MUTE:
- ctrl->value = ((radio->registers[POWERCFG] &
- POWERCFG_DMUTE) == 0) ? 1 : 0;
- break;
- default:
- retval = -EINVAL;
- }
-
-done:
- if (retval < 0)
- dev_warn(&radio->videodev->dev,
- "get control failed with %d\n", retval);
-
- mutex_unlock(&radio->lock);
- return retval;
-}
-
-
-/*
- * si470x_vidioc_s_ctrl - set the value of a control
- */
-static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
+static int si470x_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct si470x_device *radio = video_drvdata(file);
- int retval = 0;
-
- mutex_lock(&radio->lock);
- /* safety checks */
- retval = si470x_disconnect_check(radio);
- if (retval)
- goto done;
+ struct si470x_device *radio =
+ container_of(ctrl->handler, struct si470x_device, hdl);
switch (ctrl->id) {
case V4L2_CID_AUDIO_VOLUME:
radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME;
- radio->registers[SYSCONFIG2] |= ctrl->value;
- retval = si470x_set_register(radio, SYSCONFIG2);
- break;
+ radio->registers[SYSCONFIG2] |= ctrl->val;
+ return si470x_set_register(radio, SYSCONFIG2);
case V4L2_CID_AUDIO_MUTE:
- if (ctrl->value == 1)
+ if (ctrl->val)
radio->registers[POWERCFG] &= ~POWERCFG_DMUTE;
else
radio->registers[POWERCFG] |= POWERCFG_DMUTE;
- retval = si470x_set_register(radio, POWERCFG);
- break;
+ return si470x_set_register(radio, POWERCFG);
default:
- retval = -EINVAL;
+ return -EINVAL;
}
-
-done:
- if (retval < 0)
- dev_warn(&radio->videodev->dev,
- "set control failed with %d\n", retval);
- mutex_unlock(&radio->lock);
- return retval;
-}
-
-
-/*
- * si470x_vidioc_g_audio - get audio attributes
- */
-static int si470x_vidioc_g_audio(struct file *file, void *priv,
- struct v4l2_audio *audio)
-{
- /* driver constants */
- audio->index = 0;
- strcpy(audio->name, "Radio");
- audio->capability = V4L2_AUDCAP_STEREO;
- audio->mode = 0;
-
- return 0;
}
@@ -691,22 +583,14 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *tuner)
{
struct si470x_device *radio = video_drvdata(file);
- int retval = 0;
-
- mutex_lock(&radio->lock);
- /* safety checks */
- retval = si470x_disconnect_check(radio);
- if (retval)
- goto done;
+ int retval;
- if (tuner->index != 0) {
- retval = -EINVAL;
- goto done;
- }
+ if (tuner->index != 0)
+ return -EINVAL;
retval = si470x_get_register(radio, STATUSRSSI);
if (retval < 0)
- goto done;
+ return retval;
/* driver constants */
strcpy(tuner->name, "FM");
@@ -737,7 +621,7 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 0)
tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
else
- tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+ tuner->rxsubchans = V4L2_TUNER_SUB_STEREO;
/* If there is a reliable method of detecting an RDS channel,
then this code should check for that before setting this
RDS subchannel. */
@@ -754,16 +638,13 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI);
/* the ideal factor is 0xffff/75 = 873,8 */
tuner->signal = (tuner->signal * 873) + (8 * tuner->signal / 10);
+ if (tuner->signal > 0xffff)
+ tuner->signal = 0xffff;
/* automatic frequency control: -1: freq to low, 1 freq to high */
/* AFCRL does only indicate that freq. differs, not if too low/high */
tuner->afc = (radio->registers[STATUSRSSI] & STATUSRSSI_AFCRL) ? 1 : 0;
-done:
- if (retval < 0)
- dev_warn(&radio->videodev->dev,
- "get tuner failed with %d\n", retval);
- mutex_unlock(&radio->lock);
return retval;
}
@@ -775,16 +656,9 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv,
struct v4l2_tuner *tuner)
{
struct si470x_device *radio = video_drvdata(file);
- int retval = 0;
-
- mutex_lock(&radio->lock);
- /* safety checks */
- retval = si470x_disconnect_check(radio);
- if (retval)
- goto done;
if (tuner->index != 0)
- goto done;
+ return -EINVAL;
/* mono/stereo selector */
switch (tuner->audmode) {
@@ -792,20 +666,12 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv,
radio->registers[POWERCFG] |= POWERCFG_MONO; /* force mono */
break;
case V4L2_TUNER_MODE_STEREO:
+ default:
radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */
break;
- default:
- goto done;
}
- retval = si470x_set_register(radio, POWERCFG);
-
-done:
- if (retval < 0)
- dev_warn(&radio->videodev->dev,
- "set tuner failed with %d\n", retval);
- mutex_unlock(&radio->lock);
- return retval;
+ return si470x_set_register(radio, POWERCFG);
}
@@ -816,28 +682,12 @@ static int si470x_vidioc_g_frequency(struct file *file, void *priv,
struct v4l2_frequency *freq)
{
struct si470x_device *radio = video_drvdata(file);
- int retval = 0;
-
- /* safety checks */
- mutex_lock(&radio->lock);
- retval = si470x_disconnect_check(radio);
- if (retval)
- goto done;
- if (freq->tuner != 0) {
- retval = -EINVAL;
- goto done;
- }
+ if (freq->tuner != 0)
+ return -EINVAL;
freq->type = V4L2_TUNER_RADIO;
- retval = si470x_get_freq(radio, &freq->frequency);
-
-done:
- if (retval < 0)
- dev_warn(&radio->videodev->dev,
- "get frequency failed with %d\n", retval);
- mutex_unlock(&radio->lock);
- return retval;
+ return si470x_get_freq(radio, &freq->frequency);
}
@@ -848,27 +698,11 @@ static int si470x_vidioc_s_frequency(struct file *file, void *priv,
struct v4l2_frequency *freq)
{
struct si470x_device *radio = video_drvdata(file);
- int retval = 0;
-
- mutex_lock(&radio->lock);
- /* safety checks */
- retval = si470x_disconnect_check(radio);
- if (retval)
- goto done;
- if (freq->tuner != 0) {
- retval = -EINVAL;
- goto done;
- }
+ if (freq->tuner != 0)
+ return -EINVAL;
- retval = si470x_set_freq(radio, freq->frequency);
-
-done:
- if (retval < 0)
- dev_warn(&radio->videodev->dev,
- "set frequency failed with %d\n", retval);
- mutex_unlock(&radio->lock);
- return retval;
+ return si470x_set_freq(radio, freq->frequency);
}
@@ -879,44 +713,29 @@ static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
struct v4l2_hw_freq_seek *seek)
{
struct si470x_device *radio = video_drvdata(file);
- int retval = 0;
-
- mutex_lock(&radio->lock);
- /* safety checks */
- retval = si470x_disconnect_check(radio);
- if (retval)
- goto done;
-
- if (seek->tuner != 0) {
- retval = -EINVAL;
- goto done;
- }
- retval = si470x_set_seek(radio, seek->wrap_around, seek->seek_upward);
+ if (seek->tuner != 0)
+ return -EINVAL;
-done:
- if (retval < 0)
- dev_warn(&radio->videodev->dev,
- "set hardware frequency seek failed with %d\n", retval);
- mutex_unlock(&radio->lock);
- return retval;
+ return si470x_set_seek(radio, seek->wrap_around, seek->seek_upward);
}
+const struct v4l2_ctrl_ops si470x_ctrl_ops = {
+ .s_ctrl = si470x_s_ctrl,
+};
/*
* si470x_ioctl_ops - video device ioctl operations
*/
static const struct v4l2_ioctl_ops si470x_ioctl_ops = {
.vidioc_querycap = si470x_vidioc_querycap,
- .vidioc_queryctrl = si470x_vidioc_queryctrl,
- .vidioc_g_ctrl = si470x_vidioc_g_ctrl,
- .vidioc_s_ctrl = si470x_vidioc_s_ctrl,
- .vidioc_g_audio = si470x_vidioc_g_audio,
.vidioc_g_tuner = si470x_vidioc_g_tuner,
.vidioc_s_tuner = si470x_vidioc_s_tuner,
.vidioc_g_frequency = si470x_vidioc_g_frequency,
.vidioc_s_frequency = si470x_vidioc_s_frequency,
.vidioc_s_hw_freq_seek = si470x_vidioc_s_hw_freq_seek,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
@@ -926,6 +745,6 @@ static const struct v4l2_ioctl_ops si470x_ioctl_ops = {
struct video_device si470x_viddev_template = {
.fops = &si470x_fops,
.name = DRIVER_NAME,
- .release = video_device_release,
+ .release = video_device_release_empty,
.ioctl_ops = &si470x_ioctl_ops,
};
diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c
index 9b546a5523f3..a80044c5874e 100644
--- a/drivers/media/radio/si470x/radio-si470x-i2c.c
+++ b/drivers/media/radio/si470x/radio-si470x-i2c.c
@@ -162,20 +162,6 @@ static int si470x_get_all_registers(struct si470x_device *radio)
/**************************************************************************
- * General Driver Functions - DISCONNECT_CHECK
- **************************************************************************/
-
-/*
- * si470x_disconnect_check - check whether radio disconnects
- */
-int si470x_disconnect_check(struct si470x_device *radio)
-{
- return 0;
-}
-
-
-
-/**************************************************************************
* File Operations Interface
**************************************************************************/
@@ -185,12 +171,12 @@ int si470x_disconnect_check(struct si470x_device *radio)
int si470x_fops_open(struct file *file)
{
struct si470x_device *radio = video_drvdata(file);
- int retval = 0;
+ int retval = v4l2_fh_open(file);
- mutex_lock(&radio->lock);
- radio->users++;
+ if (retval)
+ return retval;
- if (radio->users == 1) {
+ if (v4l2_fh_is_singular_file(file)) {
/* start radio */
retval = si470x_start(radio);
if (retval < 0)
@@ -205,7 +191,8 @@ int si470x_fops_open(struct file *file)
}
done:
- mutex_unlock(&radio->lock);
+ if (retval)
+ v4l2_fh_release(file);
return retval;
}
@@ -216,21 +203,12 @@ done:
int si470x_fops_release(struct file *file)
{
struct si470x_device *radio = video_drvdata(file);
- int retval = 0;
-
- /* safety check */
- if (!radio)
- return -ENODEV;
- mutex_lock(&radio->lock);
- radio->users--;
- if (radio->users == 0)
+ if (v4l2_fh_is_singular_file(file))
/* stop radio */
- retval = si470x_stop(radio);
+ si470x_stop(radio);
- mutex_unlock(&radio->lock);
-
- return retval;
+ return v4l2_fh_release(file);
}
@@ -371,32 +349,25 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client,
goto err_initial;
}
- radio->users = 0;
radio->client = client;
mutex_init(&radio->lock);
- /* video device allocation and initialization */
- radio->videodev = video_device_alloc();
- if (!radio->videodev) {
- retval = -ENOMEM;
- goto err_radio;
- }
- memcpy(radio->videodev, &si470x_viddev_template,
- sizeof(si470x_viddev_template));
- video_set_drvdata(radio->videodev, radio);
+ /* video device initialization */
+ radio->videodev = si470x_viddev_template;
+ video_set_drvdata(&radio->videodev, radio);
/* power up : need 110ms */
radio->registers[POWERCFG] = POWERCFG_ENABLE;
if (si470x_set_register(radio, POWERCFG) < 0) {
retval = -EIO;
- goto err_video;
+ goto err_radio;
}
msleep(110);
/* get device and chip versions */
if (si470x_get_all_registers(radio) < 0) {
retval = -EIO;
- goto err_video;
+ goto err_radio;
}
dev_info(&client->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n",
radio->registers[DEVICEID], radio->registers[CHIPID]);
@@ -427,7 +398,7 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client,
radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
if (!radio->buffer) {
retval = -EIO;
- goto err_video;
+ goto err_radio;
}
/* rds buffer configuration */
@@ -447,7 +418,7 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client,
}
/* register video device */
- retval = video_register_device(radio->videodev, VFL_TYPE_RADIO,
+ retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO,
radio_nr);
if (retval) {
dev_warn(&client->dev, "Could not register video device\n");
@@ -460,8 +431,6 @@ err_all:
free_irq(client->irq, radio);
err_rds:
kfree(radio->buffer);
-err_video:
- video_device_release(radio->videodev);
err_radio:
kfree(radio);
err_initial:
@@ -477,7 +446,7 @@ static __devexit int si470x_i2c_remove(struct i2c_client *client)
struct si470x_device *radio = i2c_get_clientdata(client);
free_irq(client->irq, radio);
- video_unregister_device(radio->videodev);
+ video_unregister_device(&radio->videodev);
kfree(radio);
return 0;
diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c
index b7debb67932a..e9f638761296 100644
--- a/drivers/media/radio/si470x/radio-si470x-usb.c
+++ b/drivers/media/radio/si470x/radio-si470x-usb.c
@@ -367,23 +367,6 @@ static int si470x_get_scratch_page_versions(struct si470x_device *radio)
/**************************************************************************
- * General Driver Functions - DISCONNECT_CHECK
- **************************************************************************/
-
-/*
- * si470x_disconnect_check - check whether radio disconnects
- */
-int si470x_disconnect_check(struct si470x_device *radio)
-{
- if (radio->disconnected)
- return -EIO;
- else
- return 0;
-}
-
-
-
-/**************************************************************************
* RDS Driver Functions
**************************************************************************/
@@ -414,9 +397,6 @@ static void si470x_int_in_callback(struct urb *urb)
}
}
- /* safety checks */
- if (radio->disconnected)
- return;
if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
goto resubmit;
@@ -501,112 +481,30 @@ resubmit:
}
-
-/**************************************************************************
- * File Operations Interface
- **************************************************************************/
-
-/*
- * si470x_fops_open - file open
- */
int si470x_fops_open(struct file *file)
{
- struct si470x_device *radio = video_drvdata(file);
- int retval;
-
- mutex_lock(&radio->lock);
- radio->users++;
-
- retval = usb_autopm_get_interface(radio->intf);
- if (retval < 0) {
- radio->users--;
- retval = -EIO;
- goto done;
- }
-
- if (radio->users == 1) {
- /* start radio */
- retval = si470x_start(radio);
- if (retval < 0) {
- usb_autopm_put_interface(radio->intf);
- goto done;
- }
-
- /* initialize interrupt urb */
- usb_fill_int_urb(radio->int_in_urb, radio->usbdev,
- usb_rcvintpipe(radio->usbdev,
- radio->int_in_endpoint->bEndpointAddress),
- radio->int_in_buffer,
- le16_to_cpu(radio->int_in_endpoint->wMaxPacketSize),
- si470x_int_in_callback,
- radio,
- radio->int_in_endpoint->bInterval);
-
- radio->int_in_running = 1;
- mb();
-
- retval = usb_submit_urb(radio->int_in_urb, GFP_KERNEL);
- if (retval) {
- dev_info(&radio->intf->dev,
- "submitting int urb failed (%d)\n", retval);
- radio->int_in_running = 0;
- usb_autopm_put_interface(radio->intf);
- }
- }
-
-done:
- mutex_unlock(&radio->lock);
- return retval;
+ return v4l2_fh_open(file);
}
-
-/*
- * si470x_fops_release - file release
- */
int si470x_fops_release(struct file *file)
{
- struct si470x_device *radio = video_drvdata(file);
- int retval = 0;
-
- /* safety check */
- if (!radio) {
- retval = -ENODEV;
- goto done;
- }
-
- mutex_lock(&radio->lock);
- radio->users--;
- if (radio->users == 0) {
- /* shutdown interrupt handler */
- if (radio->int_in_running) {
- radio->int_in_running = 0;
- if (radio->int_in_urb)
- usb_kill_urb(radio->int_in_urb);
- }
-
- if (radio->disconnected) {
- video_unregister_device(radio->videodev);
- kfree(radio->int_in_buffer);
- kfree(radio->buffer);
- mutex_unlock(&radio->lock);
- kfree(radio);
- goto done;
- }
+ return v4l2_fh_release(file);
+}
- /* cancel read processes */
- wake_up_interruptible(&radio->read_queue);
+static void si470x_usb_release(struct v4l2_device *v4l2_dev)
+{
+ struct si470x_device *radio =
+ container_of(v4l2_dev, struct si470x_device, v4l2_dev);
- /* stop radio */
- retval = si470x_stop(radio);
- usb_autopm_put_interface(radio->intf);
- }
- mutex_unlock(&radio->lock);
-done:
- return retval;
+ usb_free_urb(radio->int_in_urb);
+ v4l2_ctrl_handler_free(&radio->hdl);
+ v4l2_device_unregister(&radio->v4l2_dev);
+ kfree(radio->int_in_buffer);
+ kfree(radio->buffer);
+ kfree(radio);
}
-
/**************************************************************************
* Video4Linux Interface
**************************************************************************/
@@ -623,13 +521,45 @@ int si470x_vidioc_querycap(struct file *file, void *priv,
strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
usb_make_path(radio->usbdev, capability->bus_info,
sizeof(capability->bus_info));
- capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
+ capability->device_caps = V4L2_CAP_HW_FREQ_SEEK |
V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
-
+ capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
+static int si470x_start_usb(struct si470x_device *radio)
+{
+ int retval;
+
+ /* start radio */
+ retval = si470x_start(radio);
+ if (retval < 0)
+ return retval;
+
+ v4l2_ctrl_handler_setup(&radio->hdl);
+
+ /* initialize interrupt urb */
+ usb_fill_int_urb(radio->int_in_urb, radio->usbdev,
+ usb_rcvintpipe(radio->usbdev,
+ radio->int_in_endpoint->bEndpointAddress),
+ radio->int_in_buffer,
+ le16_to_cpu(radio->int_in_endpoint->wMaxPacketSize),
+ si470x_int_in_callback,
+ radio,
+ radio->int_in_endpoint->bInterval);
+
+ radio->int_in_running = 1;
+ mb();
+
+ retval = usb_submit_urb(radio->int_in_urb, GFP_KERNEL);
+ if (retval) {
+ dev_info(&radio->intf->dev,
+ "submitting int urb failed (%d)\n", retval);
+ radio->int_in_running = 0;
+ }
+ return retval;
+}
/**************************************************************************
* USB Interface
@@ -653,8 +583,6 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
retval = -ENOMEM;
goto err_initial;
}
- radio->users = 0;
- radio->disconnected = 0;
radio->usbdev = interface_to_usbdev(intf);
radio->intf = intf;
mutex_init(&radio->lock);
@@ -691,20 +619,35 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
goto err_intbuffer;
}
- /* video device allocation and initialization */
- radio->videodev = video_device_alloc();
- if (!radio->videodev) {
- retval = -ENOMEM;
+ radio->v4l2_dev.release = si470x_usb_release;
+ retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
+ if (retval < 0) {
+ dev_err(&intf->dev, "couldn't register v4l2_device\n");
goto err_urb;
}
- memcpy(radio->videodev, &si470x_viddev_template,
- sizeof(si470x_viddev_template));
- video_set_drvdata(radio->videodev, radio);
+
+ v4l2_ctrl_handler_init(&radio->hdl, 2);
+ v4l2_ctrl_new_std(&radio->hdl, &si470x_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+ v4l2_ctrl_new_std(&radio->hdl, &si470x_ctrl_ops,
+ V4L2_CID_AUDIO_VOLUME, 0, 15, 1, 15);
+ if (radio->hdl.error) {
+ retval = radio->hdl.error;
+ dev_err(&intf->dev, "couldn't register control\n");
+ goto err_dev;
+ }
+ radio->videodev = si470x_viddev_template;
+ radio->videodev.ctrl_handler = &radio->hdl;
+ radio->videodev.lock = &radio->lock;
+ radio->videodev.v4l2_dev = &radio->v4l2_dev;
+ radio->videodev.release = video_device_release_empty;
+ set_bit(V4L2_FL_USE_FH_PRIO, &radio->videodev.flags);
+ video_set_drvdata(&radio->videodev, radio);
/* get device and chip versions */
if (si470x_get_all_registers(radio) < 0) {
retval = -EIO;
- goto err_video;
+ goto err_ctrl;
}
dev_info(&intf->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n",
radio->registers[DEVICEID], radio->registers[CHIPID]);
@@ -721,7 +664,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
/* get software and hardware versions */
if (si470x_get_scratch_page_versions(radio) < 0) {
retval = -EIO;
- goto err_video;
+ goto err_ctrl;
}
dev_info(&intf->dev, "software version %d, hardware version %d\n",
radio->software_version, radio->hardware_version);
@@ -764,28 +707,35 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
if (!radio->buffer) {
retval = -EIO;
- goto err_video;
+ goto err_ctrl;
}
/* rds buffer configuration */
radio->wr_index = 0;
radio->rd_index = 0;
init_waitqueue_head(&radio->read_queue);
+ usb_set_intfdata(intf, radio);
+
+ /* start radio */
+ retval = si470x_start_usb(radio);
+ if (retval < 0)
+ goto err_all;
/* register video device */
- retval = video_register_device(radio->videodev, VFL_TYPE_RADIO,
+ retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO,
radio_nr);
if (retval) {
- dev_warn(&intf->dev, "Could not register video device\n");
+ dev_err(&intf->dev, "Could not register video device\n");
goto err_all;
}
- usb_set_intfdata(intf, radio);
return 0;
err_all:
kfree(radio->buffer);
-err_video:
- video_device_release(radio->videodev);
+err_ctrl:
+ v4l2_ctrl_handler_free(&radio->hdl);
+err_dev:
+ v4l2_device_unregister(&radio->v4l2_dev);
err_urb:
usb_free_urb(radio->int_in_urb);
err_intbuffer:
@@ -803,8 +753,22 @@ err_initial:
static int si470x_usb_driver_suspend(struct usb_interface *intf,
pm_message_t message)
{
+ struct si470x_device *radio = usb_get_intfdata(intf);
+
dev_info(&intf->dev, "suspending now...\n");
+ /* shutdown interrupt handler */
+ if (radio->int_in_running) {
+ radio->int_in_running = 0;
+ if (radio->int_in_urb)
+ usb_kill_urb(radio->int_in_urb);
+ }
+
+ /* cancel read processes */
+ wake_up_interruptible(&radio->read_queue);
+
+ /* stop radio */
+ si470x_stop(radio);
return 0;
}
@@ -814,9 +778,12 @@ static int si470x_usb_driver_suspend(struct usb_interface *intf,
*/
static int si470x_usb_driver_resume(struct usb_interface *intf)
{
+ struct si470x_device *radio = usb_get_intfdata(intf);
+
dev_info(&intf->dev, "resuming now...\n");
- return 0;
+ /* start radio */
+ return si470x_start_usb(radio);
}
@@ -828,28 +795,22 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf)
struct si470x_device *radio = usb_get_intfdata(intf);
mutex_lock(&radio->lock);
- radio->disconnected = 1;
+ v4l2_device_disconnect(&radio->v4l2_dev);
+ video_unregister_device(&radio->videodev);
usb_set_intfdata(intf, NULL);
- if (radio->users == 0) {
- /* set led to disconnect state */
- si470x_set_led_state(radio, BLINK_ORANGE_LED);
-
- /* Free data structures. */
- usb_free_urb(radio->int_in_urb);
-
- kfree(radio->int_in_buffer);
- video_unregister_device(radio->videodev);
- kfree(radio->buffer);
- mutex_unlock(&radio->lock);
- kfree(radio);
- } else {
- mutex_unlock(&radio->lock);
- }
+ mutex_unlock(&radio->lock);
+ v4l2_device_put(&radio->v4l2_dev);
}
/*
* si470x_usb_driver - usb driver interface
+ *
+ * A note on suspend/resume: this driver had only empty suspend/resume
+ * functions, and when I tried to test suspend/resume it always disconnected
+ * instead of resuming (using my ADS InstantFM stick). So I've decided to
+ * remove these callbacks until someone else with better hardware can
+ * implement and test this.
*/
static struct usb_driver si470x_usb_driver = {
.name = DRIVER_NAME,
@@ -857,8 +818,8 @@ static struct usb_driver si470x_usb_driver = {
.disconnect = si470x_usb_driver_disconnect,
.suspend = si470x_usb_driver_suspend,
.resume = si470x_usb_driver_resume,
+ .reset_resume = si470x_usb_driver_resume,
.id_table = si470x_usb_driver_id_table,
- .supports_autosuspend = 1,
};
module_usb_driver(si470x_usb_driver);
diff --git a/drivers/media/radio/si470x/radio-si470x.h b/drivers/media/radio/si470x/radio-si470x.h
index f300a55ed85c..4921cab8e0fa 100644
--- a/drivers/media/radio/si470x/radio-si470x.h
+++ b/drivers/media/radio/si470x/radio-si470x.h
@@ -36,6 +36,9 @@
#include <linux/mutex.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-device.h>
#include <asm/unaligned.h>
@@ -141,10 +144,9 @@
* si470x_device - private data
*/
struct si470x_device {
- struct video_device *videodev;
-
- /* driver management */
- unsigned int users;
+ struct v4l2_device v4l2_dev;
+ struct video_device videodev;
+ struct v4l2_ctrl_handler hdl;
/* Silabs internal registers (0..15) */
unsigned short registers[RADIO_REGISTER_NUM];
@@ -174,9 +176,6 @@ struct si470x_device {
/* scratch page */
unsigned char software_version;
unsigned char hardware_version;
-
- /* driver management */
- unsigned char disconnected;
#endif
#if defined(CONFIG_I2C_SI470X) || defined(CONFIG_I2C_SI470X_MODULE)
@@ -213,6 +212,7 @@ struct si470x_device {
* Common Functions
**************************************************************************/
extern struct video_device si470x_viddev_template;
+extern const struct v4l2_ctrl_ops si470x_ctrl_ops;
int si470x_get_register(struct si470x_device *radio, int regnr);
int si470x_set_register(struct si470x_device *radio, int regnr);
int si470x_disconnect_check(struct si470x_device *radio);
diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c
index 6418c4c9faf1..06d47e5cce9f 100644
--- a/drivers/media/radio/tef6862.c
+++ b/drivers/media/radio/tef6862.c
@@ -211,7 +211,7 @@ static struct i2c_driver tef6862_driver = {
.name = DRIVER_NAME,
},
.probe = tef6862_probe,
- .remove = tef6862_remove,
+ .remove = __devexit_p(tef6862_remove),
.id_table = tef6862_id,
};
diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c
index 077d369a0173..080b96a61f1a 100644
--- a/drivers/media/radio/wl128x/fmdrv_v4l2.c
+++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c
@@ -518,6 +518,10 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr)
video_set_drvdata(gradio_dev, fmdev);
gradio_dev->lock = &fmdev->mutex;
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &gradio_dev->flags);
/* Register with V4L2 subsystem as RADIO device */
if (video_register_device(gradio_dev, VFL_TYPE_RADIO, radio_nr)) {
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index a3fbb21350e9..f97eeb870455 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -69,6 +69,7 @@ config IR_JVC_DECODER
config IR_SONY_DECODER
tristate "Enable IR raw decoder for the Sony protocol"
depends on RC_CORE
+ select BITREVERSE
default y
---help---
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index baf907b3ce76..7be377fc1be8 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -1,7 +1,7 @@
/*
* USB ATI Remote support
*
- * Copyright (c) 2011 Anssi Hannula <anssi.hannula@iki.fi>
+ * Copyright (c) 2011, 2012 Anssi Hannula <anssi.hannula@iki.fi>
* Version 2.2.0 Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net>
* Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev
*
@@ -151,13 +151,57 @@ MODULE_PARM_DESC(mouse, "Enable mouse device, default = yes");
#undef err
#define err(format, arg...) printk(KERN_ERR format , ## arg)
+struct ati_receiver_type {
+ /* either default_keymap or get_default_keymap should be set */
+ const char *default_keymap;
+ const char *(*get_default_keymap)(struct usb_interface *interface);
+};
+
+static const char *get_medion_keymap(struct usb_interface *interface)
+{
+ struct usb_device *udev = interface_to_usbdev(interface);
+
+ /*
+ * There are many different Medion remotes shipped with a receiver
+ * with the same usb id, but the receivers have subtle differences
+ * in the USB descriptors allowing us to detect them.
+ */
+
+ if (udev->manufacturer && udev->product) {
+ if (udev->actconfig->desc.bmAttributes & USB_CONFIG_ATT_WAKEUP) {
+
+ if (!strcmp(udev->manufacturer, "X10 Wireless Technology Inc")
+ && !strcmp(udev->product, "USB Receiver"))
+ return RC_MAP_MEDION_X10_DIGITAINER;
+
+ if (!strcmp(udev->manufacturer, "X10 WTI")
+ && !strcmp(udev->product, "RF receiver"))
+ return RC_MAP_MEDION_X10_OR2X;
+ } else {
+
+ if (!strcmp(udev->manufacturer, "X10 Wireless Technology Inc")
+ && !strcmp(udev->product, "USB Receiver"))
+ return RC_MAP_MEDION_X10;
+ }
+ }
+
+ dev_info(&interface->dev,
+ "Unknown Medion X10 receiver, using default ati_remote Medion keymap\n");
+
+ return RC_MAP_MEDION_X10;
+}
+
+static const struct ati_receiver_type type_ati = { .default_keymap = RC_MAP_ATI_X10 };
+static const struct ati_receiver_type type_medion = { .get_default_keymap = get_medion_keymap };
+static const struct ati_receiver_type type_firefly = { .default_keymap = RC_MAP_SNAPSTREAM_FIREFLY };
+
static struct usb_device_id ati_remote_table[] = {
- { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_ATI_X10 },
- { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_ATI_X10 },
- { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_ATI_X10 },
- { USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_ATI_X10 },
- { USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_MEDION_X10 },
- { USB_DEVICE(ATI_REMOTE_VENDOR_ID, FIREFLY_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)RC_MAP_SNAPSTREAM_FIREFLY },
+ { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)&type_ati },
+ { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA2_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)&type_ati },
+ { USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)&type_ati },
+ { USB_DEVICE(ATI_REMOTE_VENDOR_ID, NVIDIA_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)&type_ati },
+ { USB_DEVICE(ATI_REMOTE_VENDOR_ID, MEDION_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)&type_medion },
+ { USB_DEVICE(ATI_REMOTE_VENDOR_ID, FIREFLY_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)&type_firefly },
{} /* Terminating entry */
};
@@ -445,6 +489,7 @@ static void ati_remote_input_report(struct urb *urb)
int acc;
int remote_num;
unsigned char scancode;
+ u32 wheel_keycode = KEY_RESERVED;
int i;
/*
@@ -484,26 +529,33 @@ static void ati_remote_input_report(struct urb *urb)
*/
scancode = data[2] & 0x7f;
- /* Look up event code index in the mouse translation table. */
- for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) {
- if (scancode == ati_remote_tbl[i].data) {
- index = i;
- break;
+ dbginfo(&ati_remote->interface->dev,
+ "channel 0x%02x; key data %02x, scancode %02x\n",
+ remote_num, data[2], scancode);
+
+ if (scancode >= 0x70) {
+ /*
+ * This is either a mouse or scrollwheel event, depending on
+ * the remote/keymap.
+ * Get the keycode assigned to scancode 0x78/0x70. If it is
+ * set, assume this is a scrollwheel up/down event.
+ */
+ wheel_keycode = rc_g_keycode_from_table(ati_remote->rdev,
+ scancode & 0x78);
+
+ if (wheel_keycode == KEY_RESERVED) {
+ /* scrollwheel was not mapped, assume mouse */
+
+ /* Look up event code index in the mouse translation table. */
+ for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) {
+ if (scancode == ati_remote_tbl[i].data) {
+ index = i;
+ break;
+ }
+ }
}
}
- if (index >= 0) {
- dbginfo(&ati_remote->interface->dev,
- "channel 0x%02x; mouse data %02x; index %d; keycode %d\n",
- remote_num, data[2], index, ati_remote_tbl[index].code);
- if (!dev)
- return; /* no mouse device */
- } else
- dbginfo(&ati_remote->interface->dev,
- "channel 0x%02x; key data %02x, scancode %02x\n",
- remote_num, data[2], scancode);
-
-
if (index >= 0 && ati_remote_tbl[index].kind == KIND_LITERAL) {
input_event(dev, ati_remote_tbl[index].type,
ati_remote_tbl[index].code,
@@ -542,15 +594,29 @@ static void ati_remote_input_report(struct urb *urb)
if (index < 0) {
/* Not a mouse event, hand it to rc-core. */
-
- /*
- * We don't use the rc-core repeat handling yet as
- * it would cause ghost repeats which would be a
- * regression for this driver.
- */
- rc_keydown_notimeout(ati_remote->rdev, scancode,
- data[2]);
- rc_keyup(ati_remote->rdev);
+ int count = 1;
+
+ if (wheel_keycode != KEY_RESERVED) {
+ /*
+ * This is a scrollwheel event, send the
+ * scroll up (0x78) / down (0x70) scancode
+ * repeatedly as many times as indicated by
+ * rest of the scancode.
+ */
+ count = (scancode & 0x07) + 1;
+ scancode &= 0x78;
+ }
+
+ while (count--) {
+ /*
+ * We don't use the rc-core repeat handling yet as
+ * it would cause ghost repeats which would be a
+ * regression for this driver.
+ */
+ rc_keydown_notimeout(ati_remote->rdev, scancode,
+ data[2]);
+ rc_keyup(ati_remote->rdev);
+ }
return;
}
@@ -766,6 +832,7 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
struct usb_device *udev = interface_to_usbdev(interface);
struct usb_host_interface *iface_host = interface->cur_altsetting;
struct usb_endpoint_descriptor *endpoint_in, *endpoint_out;
+ struct ati_receiver_type *type = (struct ati_receiver_type *)id->driver_info;
struct ati_remote *ati_remote;
struct input_dev *input_dev;
struct rc_dev *rc_dev;
@@ -827,10 +894,15 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
snprintf(ati_remote->mouse_name, sizeof(ati_remote->mouse_name),
"%s mouse", ati_remote->rc_name);
- if (id->driver_info)
- rc_dev->map_name = (const char *)id->driver_info;
- else
- rc_dev->map_name = RC_MAP_ATI_X10;
+ rc_dev->map_name = RC_MAP_ATI_X10; /* default map */
+
+ /* set default keymap according to receiver model */
+ if (type) {
+ if (type->default_keymap)
+ rc_dev->map_name = type->default_keymap;
+ else if (type->get_default_keymap)
+ rc_dev->map_name = type->get_default_keymap(interface);
+ }
ati_remote_rc_init(ati_remote);
mutex_init(&ati_remote->open_mutex);
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
index 4a3a238bcfbc..6aabf7ae3a31 100644
--- a/drivers/media/rc/fintek-cir.c
+++ b/drivers/media/rc/fintek-cir.c
@@ -556,11 +556,11 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id
if (request_irq(fintek->cir_irq, fintek_cir_isr, IRQF_SHARED,
FINTEK_DRIVER_NAME, (void *)fintek))
- goto failure;
+ goto failure2;
ret = rc_register_device(rdev);
if (ret)
- goto failure;
+ goto failure3;
device_init_wakeup(&pdev->dev, true);
fintek->rdev = rdev;
@@ -570,12 +570,11 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id
return 0;
+failure3:
+ free_irq(fintek->cir_irq, fintek);
+failure2:
+ release_region(fintek->cir_addr, fintek->cir_port_len);
failure:
- if (fintek->cir_irq)
- free_irq(fintek->cir_irq, fintek);
- if (fintek->cir_addr)
- release_region(fintek->cir_addr, fintek->cir_port_len);
-
rc_free_device(rdev);
kfree(fintek);
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index 7f26fdf2e54e..5dd0386604f0 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -255,7 +255,7 @@ static struct usb_device_id imon_usb_id_table[] = {
static struct usb_driver imon_driver = {
.name = MOD_NAME,
.probe = imon_probe,
- .disconnect = imon_disconnect,
+ .disconnect = __devexit_p(imon_disconnect),
.suspend = imon_suspend,
.resume = imon_resume,
.id_table = imon_usb_id_table,
diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
index 95e630998aaf..a82025121345 100644
--- a/drivers/media/rc/ir-raw.c
+++ b/drivers/media/rc/ir-raw.c
@@ -46,9 +46,9 @@ static int ir_raw_event_thread(void *data)
while (!kthread_should_stop()) {
spin_lock_irq(&raw->lock);
- retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev));
+ retval = kfifo_len(&raw->kfifo);
- if (!retval) {
+ if (retval < sizeof(ev)) {
set_current_state(TASK_INTERRUPTIBLE);
if (kthread_should_stop())
@@ -59,11 +59,9 @@ static int ir_raw_event_thread(void *data)
continue;
}
+ retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev));
spin_unlock_irq(&raw->lock);
-
- BUG_ON(retval != sizeof(ev));
-
mutex_lock(&ir_raw_handler_lock);
list_for_each_entry(handler, &ir_raw_handler_list, list)
handler->decode(raw->dev, ev);
diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c
index d38fbdd0b25a..7e54ec57bcf9 100644
--- a/drivers/media/rc/ir-sanyo-decoder.c
+++ b/drivers/media/rc/ir-sanyo-decoder.c
@@ -56,7 +56,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
struct sanyo_dec *data = &dev->raw->sanyo;
u32 scancode;
- u8 address, not_address, command, not_command;
+ u8 address, command, not_command;
if (!(dev->raw->enabled_protocols & RC_TYPE_SANYO))
return 0;
@@ -154,7 +154,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
break;
address = bitrev16((data->bits >> 29) & 0x1fff) >> 3;
- not_address = bitrev16((data->bits >> 16) & 0x1fff) >> 3;
+ /* not_address = bitrev16((data->bits >> 16) & 0x1fff) >> 3; */
command = bitrev8((data->bits >> 8) & 0xff);
not_command = bitrev8((data->bits >> 0) & 0xff);
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index 0e49c99abf68..36fe5a349b95 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -1598,24 +1598,22 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
if (request_irq(itdev->cir_irq, ite_cir_isr, IRQF_SHARED,
ITE_DRIVER_NAME, (void *)itdev))
- goto failure;
+ goto failure2;
ret = rc_register_device(rdev);
if (ret)
- goto failure;
+ goto failure3;
itdev->rdev = rdev;
ite_pr(KERN_NOTICE, "driver has been successfully loaded\n");
return 0;
+failure3:
+ free_irq(itdev->cir_irq, itdev);
+failure2:
+ release_region(itdev->cir_addr, itdev->params.io_region_size);
failure:
- if (itdev->cir_irq)
- free_irq(itdev->cir_irq, itdev);
-
- if (itdev->cir_addr)
- release_region(itdev->cir_addr, itdev->params.io_region_size);
-
rc_free_device(rdev);
kfree(itdev);
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index 49ce2662f56b..ab84d66c67c1 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -3,6 +3,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-anysee.o \
rc-apac-viewcomp.o \
rc-asus-pc39.o \
+ rc-asus-ps3-100.o \
rc-ati-tv-wonder-hd-600.o \
rc-ati-x10.o \
rc-avermedia-a16d.o \
@@ -52,6 +53,8 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-lme2510.o \
rc-manli.o \
rc-medion-x10.o \
+ rc-medion-x10-digitainer.o \
+ rc-medion-x10-or2x.o \
rc-msi-digivox-ii.o \
rc-msi-digivox-iii.o \
rc-msi-tvanywhere.o \
diff --git a/drivers/media/rc/keymaps/rc-asus-ps3-100.c b/drivers/media/rc/keymaps/rc-asus-ps3-100.c
new file mode 100644
index 000000000000..ba76609c5936
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-asus-ps3-100.c
@@ -0,0 +1,91 @@
+/* asus-ps3-100.h - Keytable for asus_ps3_100 Remote Controller
+ *
+ * Copyright (c) 2012 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * Based on a previous patch from Remi Schwartz <remi.schwartz@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
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+static struct rc_map_table asus_ps3_100[] = {
+ { 0x081c, KEY_HOME }, /* home */
+ { 0x081e, KEY_TV }, /* tv */
+ { 0x0803, KEY_TEXT }, /* teletext */
+ { 0x0829, KEY_POWER }, /* close */
+
+ { 0x080b, KEY_RED }, /* red */
+ { 0x080d, KEY_YELLOW }, /* yellow */
+ { 0x0806, KEY_BLUE }, /* blue */
+ { 0x0807, KEY_GREEN }, /* green */
+
+ /* Keys 0 to 9 */
+ { 0x082a, KEY_0 },
+ { 0x0816, KEY_1 },
+ { 0x0812, KEY_2 },
+ { 0x0814, KEY_3 },
+ { 0x0836, KEY_4 },
+ { 0x0832, KEY_5 },
+ { 0x0834, KEY_6 },
+ { 0x080e, KEY_7 },
+ { 0x080a, KEY_8 },
+ { 0x080c, KEY_9 },
+
+ { 0x0815, KEY_VOLUMEUP },
+ { 0x0826, KEY_VOLUMEDOWN },
+ { 0x0835, KEY_CHANNELUP }, /* channel / program + */
+ { 0x0824, KEY_CHANNELDOWN }, /* channel / program - */
+
+ { 0x0808, KEY_UP },
+ { 0x0804, KEY_DOWN },
+ { 0x0818, KEY_LEFT },
+ { 0x0810, KEY_RIGHT },
+ { 0x0825, KEY_ENTER }, /* enter */
+
+ { 0x0822, KEY_EXIT }, /* back */
+ { 0x082c, KEY_AB }, /* recall */
+
+ { 0x0820, KEY_AUDIO }, /* TV audio */
+ { 0x0837, KEY_SCREEN }, /* snapshot */
+ { 0x082e, KEY_ZOOM }, /* full screen */
+ { 0x0802, KEY_MUTE }, /* mute */
+
+ { 0x0831, KEY_REWIND }, /* backward << */
+ { 0x0811, KEY_RECORD }, /* recording */
+ { 0x0809, KEY_STOP },
+ { 0x0805, KEY_FASTFORWARD }, /* forward >> */
+ { 0x0821, KEY_PREVIOUS }, /* rew */
+ { 0x081a, KEY_PAUSE }, /* pause */
+ { 0x0839, KEY_PLAY }, /* play */
+ { 0x0819, KEY_NEXT }, /* forward */
+};
+
+static struct rc_map_list asus_ps3_100_map = {
+.map = {
+ .scan = asus_ps3_100,
+ .size = ARRAY_SIZE(asus_ps3_100),
+ .rc_type = RC_TYPE_RC5,
+ .name = RC_MAP_ASUS_PS3_100,
+}
+};
+
+static int __init init_rc_map_asus_ps3_100(void)
+{
+return rc_map_register(&asus_ps3_100_map);
+}
+
+static void __exit exit_rc_map_asus_ps3_100(void)
+{
+rc_map_unregister(&asus_ps3_100_map);
+}
+
+module_init(init_rc_map_asus_ps3_100)
+module_exit(exit_rc_map_asus_ps3_100)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-it913x-v2.c b/drivers/media/rc/keymaps/rc-it913x-v2.c
index 28e376e18b99..bd42a30ec06f 100644
--- a/drivers/media/rc/keymaps/rc-it913x-v2.c
+++ b/drivers/media/rc/keymaps/rc-it913x-v2.c
@@ -40,7 +40,7 @@ static struct rc_map_table it913x_v2_rc[] = {
/* Type 2 */
/* keys stereo, snapshot unassigned */
{ 0x866b00, KEY_0 },
- { 0x866b1b, KEY_1 },
+ { 0x866b01, KEY_1 },
{ 0x866b02, KEY_2 },
{ 0x866b03, KEY_3 },
{ 0x866b04, KEY_4 },
diff --git a/drivers/media/rc/keymaps/rc-medion-x10-digitainer.c b/drivers/media/rc/keymaps/rc-medion-x10-digitainer.c
new file mode 100644
index 000000000000..966f9b3c71da
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-medion-x10-digitainer.c
@@ -0,0 +1,123 @@
+/*
+ * Medion X10 RF remote keytable (Digitainer variant)
+ *
+ * Copyright (C) 2012 Anssi Hannula <anssi.hannula@iki.fi>
+ *
+ * This keymap is for a variant that has a distinctive scrollwheel instead of
+ * up/down buttons (tested with P/N 40009936 / 20018268), reportedly
+ * originally shipped with Medion Digitainer but now sold separately simply as
+ * an "X10" remote.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <media/rc-map.h>
+
+static struct rc_map_table medion_x10_digitainer[] = {
+ { 0x02, KEY_POWER },
+
+ { 0x2c, KEY_TV },
+ { 0x2d, KEY_VIDEO },
+ { 0x04, KEY_DVD }, /* CD/DVD */
+ { 0x16, KEY_TEXT }, /* "teletext" icon, i.e. a screen with lines */
+ { 0x06, KEY_AUDIO },
+ { 0x2e, KEY_RADIO },
+ { 0x31, KEY_EPG }, /* a screen with an open book */
+ { 0x05, KEY_IMAGES }, /* Photo */
+ { 0x2f, KEY_INFO },
+
+ { 0x78, KEY_UP }, /* scrollwheel up 1 notch */
+ /* 0x79..0x7f: 2-8 notches, driver repeats 0x78 entry */
+
+ { 0x70, KEY_DOWN }, /* scrollwheel down 1 notch */
+ /* 0x71..0x77: 2-8 notches, driver repeats 0x70 entry */
+
+ { 0x19, KEY_MENU },
+ { 0x1d, KEY_LEFT },
+ { 0x1e, KEY_OK }, /* scrollwheel press */
+ { 0x1f, KEY_RIGHT },
+ { 0x20, KEY_BACK },
+
+ { 0x09, KEY_VOLUMEUP },
+ { 0x08, KEY_VOLUMEDOWN },
+ { 0x00, KEY_MUTE },
+
+ { 0x1b, KEY_SELECT }, /* also has "U" rotated 90 degrees CCW */
+
+ { 0x0b, KEY_CHANNELUP },
+ { 0x0c, KEY_CHANNELDOWN },
+ { 0x1c, KEY_LAST },
+
+ { 0x32, KEY_RED }, /* also Audio */
+ { 0x33, KEY_GREEN }, /* also Subtitle */
+ { 0x34, KEY_YELLOW }, /* also Angle */
+ { 0x35, KEY_BLUE }, /* also Title */
+
+ { 0x28, KEY_STOP },
+ { 0x29, KEY_PAUSE },
+ { 0x25, KEY_PLAY },
+ { 0x21, KEY_PREVIOUS },
+ { 0x18, KEY_CAMERA },
+ { 0x23, KEY_NEXT },
+ { 0x24, KEY_REWIND },
+ { 0x27, KEY_RECORD },
+ { 0x26, KEY_FORWARD },
+
+ { 0x0d, KEY_1 },
+ { 0x0e, KEY_2 },
+ { 0x0f, KEY_3 },
+ { 0x10, KEY_4 },
+ { 0x11, KEY_5 },
+ { 0x12, KEY_6 },
+ { 0x13, KEY_7 },
+ { 0x14, KEY_8 },
+ { 0x15, KEY_9 },
+ { 0x17, KEY_0 },
+
+ /* these do not actually exist on this remote, but these scancodes
+ * exist on all other Medion X10 remotes and adding them here allows
+ * such remotes to be adequately usable with this keymap in case
+ * this keymap is wrongly used with them (which is quite possible as
+ * there are lots of different Medion X10 remotes): */
+ { 0x1a, KEY_UP },
+ { 0x22, KEY_DOWN },
+};
+
+static struct rc_map_list medion_x10_digitainer_map = {
+ .map = {
+ .scan = medion_x10_digitainer,
+ .size = ARRAY_SIZE(medion_x10_digitainer),
+ .rc_type = RC_TYPE_OTHER,
+ .name = RC_MAP_MEDION_X10_DIGITAINER,
+ }
+};
+
+static int __init init_rc_map_medion_x10_digitainer(void)
+{
+ return rc_map_register(&medion_x10_digitainer_map);
+}
+
+static void __exit exit_rc_map_medion_x10_digitainer(void)
+{
+ rc_map_unregister(&medion_x10_digitainer_map);
+}
+
+module_init(init_rc_map_medion_x10_digitainer)
+module_exit(exit_rc_map_medion_x10_digitainer)
+
+MODULE_DESCRIPTION("Medion X10 RF remote keytable (Digitainer variant)");
+MODULE_AUTHOR("Anssi Hannula <anssi.hannula@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/rc/keymaps/rc-medion-x10-or2x.c b/drivers/media/rc/keymaps/rc-medion-x10-or2x.c
new file mode 100644
index 000000000000..b077300ecb5c
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-medion-x10-or2x.c
@@ -0,0 +1,108 @@
+/*
+ * Medion X10 OR22/OR24 RF remote keytable
+ *
+ * Copyright (C) 2012 Anssi Hannula <anssi.hannula@iki.fi>
+ *
+ * This keymap is for several Medion X10 remotes that have the Windows MCE
+ * button. This has been tested with a "RF VISTA Remote Control", OR24V,
+ * P/N 20035335, but should work with other variants that have the same
+ * buttons, such as OR22V and OR24E.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <media/rc-map.h>
+
+static struct rc_map_table medion_x10_or2x[] = {
+ { 0x02, KEY_POWER },
+ { 0x16, KEY_TEXT }, /* "T" in a box, for teletext */
+
+ { 0x09, KEY_VOLUMEUP },
+ { 0x08, KEY_VOLUMEDOWN },
+ { 0x00, KEY_MUTE },
+ { 0x0b, KEY_CHANNELUP },
+ { 0x0c, KEY_CHANNELDOWN },
+
+ { 0x32, KEY_RED },
+ { 0x33, KEY_GREEN },
+ { 0x34, KEY_YELLOW },
+ { 0x35, KEY_BLUE },
+
+ { 0x18, KEY_PVR }, /* record symbol inside a tv symbol */
+ { 0x04, KEY_DVD }, /* disc symbol */
+ { 0x31, KEY_EPG }, /* a tv schedule symbol */
+ { 0x1c, KEY_TV }, /* play symbol inside a tv symbol */
+ { 0x20, KEY_BACK },
+ { 0x2f, KEY_INFO },
+
+ { 0x1a, KEY_UP },
+ { 0x22, KEY_DOWN },
+ { 0x1d, KEY_LEFT },
+ { 0x1f, KEY_RIGHT },
+ { 0x1e, KEY_OK },
+
+ { 0x1b, KEY_MEDIA }, /* Windows MCE button */
+
+ { 0x21, KEY_PREVIOUS },
+ { 0x23, KEY_NEXT },
+ { 0x24, KEY_REWIND },
+ { 0x26, KEY_FORWARD },
+ { 0x25, KEY_PLAY },
+ { 0x28, KEY_STOP },
+ { 0x29, KEY_PAUSE },
+ { 0x27, KEY_RECORD },
+
+ { 0x0d, KEY_1 },
+ { 0x0e, KEY_2 },
+ { 0x0f, KEY_3 },
+ { 0x10, KEY_4 },
+ { 0x11, KEY_5 },
+ { 0x12, KEY_6 },
+ { 0x13, KEY_7 },
+ { 0x14, KEY_8 },
+ { 0x15, KEY_9 },
+ { 0x17, KEY_0 },
+ { 0x30, KEY_CLEAR },
+ { 0x36, KEY_ENTER },
+ { 0x37, KEY_NUMERIC_STAR },
+ { 0x38, KEY_NUMERIC_POUND },
+};
+
+static struct rc_map_list medion_x10_or2x_map = {
+ .map = {
+ .scan = medion_x10_or2x,
+ .size = ARRAY_SIZE(medion_x10_or2x),
+ .rc_type = RC_TYPE_OTHER,
+ .name = RC_MAP_MEDION_X10_OR2X,
+ }
+};
+
+static int __init init_rc_map_medion_x10_or2x(void)
+{
+ return rc_map_register(&medion_x10_or2x_map);
+}
+
+static void __exit exit_rc_map_medion_x10_or2x(void)
+{
+ rc_map_unregister(&medion_x10_or2x_map);
+}
+
+module_init(init_rc_map_medion_x10_or2x)
+module_exit(exit_rc_map_medion_x10_or2x)
+
+MODULE_DESCRIPTION("Medion X10 OR22/OR24 RF remote keytable");
+MODULE_AUTHOR("Anssi Hannula <anssi.hannula@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index e150a2e29a4b..84e06d3aa696 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -520,7 +520,7 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
{
char codes[USB_BUFLEN * 3 + 1];
char inout[9];
- u8 cmd, subcmd, data1, data2, data3, data4, data5;
+ u8 cmd, subcmd, data1, data2, data3, data4;
struct device *dev = ir->dev;
int i, start, skip = 0;
u32 carrier, period;
@@ -553,7 +553,6 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
data2 = buf[start + 3] & 0xff;
data3 = buf[start + 4] & 0xff;
data4 = buf[start + 5] & 0xff;
- data5 = buf[start + 6] & 0xff;
switch (cmd) {
case MCE_CMD_NULL:
@@ -1443,7 +1442,7 @@ static int mceusb_dev_resume(struct usb_interface *intf)
static struct usb_driver mceusb_dev_driver = {
.name = DRIVER_NAME,
.probe = mceusb_dev_probe,
- .disconnect = mceusb_dev_disconnect,
+ .disconnect = __devexit_p(mceusb_dev_disconnect),
.suspend = mceusb_dev_suspend,
.resume = mceusb_dev_resume,
.reset_resume = mceusb_dev_resume,
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index 8b2c071ac0ab..dc8a7dddccd4 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -1075,19 +1075,19 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
if (request_irq(nvt->cir_irq, nvt_cir_isr, IRQF_SHARED,
NVT_DRIVER_NAME, (void *)nvt))
- goto failure;
+ goto failure2;
if (!request_region(nvt->cir_wake_addr,
CIR_IOREG_LENGTH, NVT_DRIVER_NAME))
- goto failure;
+ goto failure3;
if (request_irq(nvt->cir_wake_irq, nvt_cir_wake_isr, IRQF_SHARED,
NVT_DRIVER_NAME, (void *)nvt))
- goto failure;
+ goto failure4;
ret = rc_register_device(rdev);
if (ret)
- goto failure;
+ goto failure5;
device_init_wakeup(&pdev->dev, true);
nvt->rdev = rdev;
@@ -1099,17 +1099,15 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
return 0;
+failure5:
+ free_irq(nvt->cir_wake_irq, nvt);
+failure4:
+ release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
+failure3:
+ free_irq(nvt->cir_irq, nvt);
+failure2:
+ release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
failure:
- if (nvt->cir_irq)
- free_irq(nvt->cir_irq, nvt);
- if (nvt->cir_addr)
- release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
-
- if (nvt->cir_wake_irq)
- free_irq(nvt->cir_wake_irq, nvt);
- if (nvt->cir_wake_addr)
- release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
-
rc_free_device(rdev);
kfree(nvt);
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index efc6a514348a..fae1615e0ff2 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -221,7 +221,6 @@ static int __init loop_init(void)
rc->s_idle = loop_set_idle;
rc->s_learning_mode = loop_set_learning_mode;
rc->s_carrier_report = loop_set_carrier_report;
- rc->priv = &loopdev;
loopdev.txmask = RXMASK_REGULAR;
loopdev.txcarrier = 36000;
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index ad95c67a4dba..2878b0ed9741 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -1277,7 +1277,7 @@ static int redrat3_dev_resume(struct usb_interface *intf)
static struct usb_driver redrat3_dev_driver = {
.name = DRIVER_NAME,
.probe = redrat3_dev_probe,
- .disconnect = redrat3_dev_disconnect,
+ .disconnect = __devexit_p(redrat3_dev_disconnect),
.suspend = redrat3_dev_suspend,
.resume = redrat3_dev_resume,
.reset_resume = redrat3_dev_resume,
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index ce1e7ba940f6..99937c94d7df 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -472,6 +472,9 @@ comment "Camera sensor devices"
config VIDEO_APTINA_PLL
tristate
+config VIDEO_SMIAPP_PLL
+ tristate
+
config VIDEO_OV7670
tristate "OmniVision OV7670 sensor support"
depends on I2C && VIDEO_V4L2
@@ -556,6 +559,8 @@ config VIDEO_S5K6AA
This is a V4L2 sensor-level driver for Samsung S5K6AA(FX) 1.3M
camera sensor with an embedded SoC image signal processor.
+source "drivers/media/video/smiapp/Kconfig"
+
comment "Flash devices"
config VIDEO_ADP1653
@@ -644,6 +649,8 @@ menuconfig V4L_USB_DRIVERS
if V4L_USB_DRIVERS
+source "drivers/media/video/au0828/Kconfig"
+
source "drivers/media/video/uvc/Kconfig"
source "drivers/media/video/gspca/Kconfig"
@@ -662,8 +669,6 @@ source "drivers/media/video/tm6000/Kconfig"
source "drivers/media/video/usbvision/Kconfig"
-source "drivers/media/video/et61x251/Kconfig"
-
source "drivers/media/video/sn9c102/Kconfig"
source "drivers/media/video/pwc/Kconfig"
@@ -721,8 +726,6 @@ menuconfig V4L_PCI_DRIVERS
if V4L_PCI_DRIVERS
-source "drivers/media/video/au0828/Kconfig"
-
source "drivers/media/video/bt8xx/Kconfig"
source "drivers/media/video/cx18/Kconfig"
@@ -794,6 +797,19 @@ source "drivers/media/video/saa7164/Kconfig"
source "drivers/media/video/zoran/Kconfig"
+config STA2X11_VIP
+ tristate "STA2X11 VIP Video For Linux"
+ depends on STA2X11
+ select VIDEO_ADV7180 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEOBUF_DMA_CONTIG
+ depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS
+ help
+ Say Y for support for STA2X11 VIP (Video Input Port) capture
+ device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called sta2x11_vip.
+
endif # V4L_PCI_DRIVERS
#
@@ -1127,19 +1143,6 @@ config VIDEO_MX2
This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor
Interface
-config VIDEO_SAMSUNG_S5P_FIMC
- tristate "Samsung S5P and EXYNOS4 camera interface driver (EXPERIMENTAL)"
- depends on VIDEO_V4L2 && I2C && PLAT_S5P && PM_RUNTIME && \
- VIDEO_V4L2_SUBDEV_API && EXPERIMENTAL
- select VIDEOBUF2_DMA_CONTIG
- select V4L2_MEM2MEM_DEV
- ---help---
- This is a v4l2 driver for Samsung S5P and EXYNOS4 camera
- host interface and video postprocessor.
-
- To compile this driver as a module, choose M here: the
- module will be called s5p-fimc.
-
config VIDEO_ATMEL_ISI
tristate "ATMEL Image Sensor Interface (ISI) support"
depends on VIDEO_DEV && SOC_CAMERA && ARCH_AT91
@@ -1148,16 +1151,7 @@ config VIDEO_ATMEL_ISI
This module makes the ATMEL Image Sensor Interface available
as a v4l2 device.
-config VIDEO_S5P_MIPI_CSIS
- tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver"
- depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P
- depends on VIDEO_V4L2_SUBDEV_API && REGULATOR
- ---help---
- This is a v4l2 driver for Samsung S5P/EXYNOS4 MIPI-CSI receiver.
-
- To compile this driver as a module, choose M here: the
- module will be called s5p-csis.
-
+source "drivers/media/video/s5p-fimc/Kconfig"
source "drivers/media/video/s5p-tv/Kconfig"
endif # V4L_PLATFORM_DRIVERS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index a6282a3a6a82..d209de0e0ca8 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -79,9 +79,12 @@ obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o
obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o
obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/
obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o
+obj-$(CONFIG_VIDEO_SMIAPP) += smiapp/
obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o
obj-$(CONFIG_VIDEO_AS3645A) += as3645a.o
+obj-$(CONFIG_VIDEO_SMIAPP_PLL) += smiapp-pll.o
+
obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o
obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o
@@ -120,6 +123,7 @@ obj-$(CONFIG_VIDEO_TM6000) += tm6000/
obj-$(CONFIG_VIDEO_MXB) += mxb.o
obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
+obj-$(CONFIG_STA2X11_VIP) += sta2x11_vip.o
obj-$(CONFIG_VIDEO_TIMBERDALE) += timblogiw.o
obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
@@ -152,7 +156,6 @@ obj-$(CONFIG_USB_ZR364XX) += zr364xx.o
obj-$(CONFIG_USB_STKWEBCAM) += stkwebcam.o
obj-$(CONFIG_USB_SN9C102) += sn9c102/
-obj-$(CONFIG_USB_ET61X251) += et61x251/
obj-$(CONFIG_USB_PWC) += pwc/
obj-$(CONFIG_USB_GSPCA) += gspca/
diff --git a/drivers/media/video/adp1653.c b/drivers/media/video/adp1653.c
index 5b045b4a66fe..57e87090388d 100644
--- a/drivers/media/video/adp1653.c
+++ b/drivers/media/video/adp1653.c
@@ -34,7 +34,6 @@
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/slab.h>
-#include <linux/version.h>
#include <media/adp1653.h>
#include <media/v4l2-device.h>
@@ -282,19 +281,19 @@ adp1653_init_device(struct adp1653_flash *flash)
return -EIO;
}
- mutex_lock(&flash->ctrls.lock);
+ mutex_lock(flash->ctrls.lock);
/* Reset faults before reading new ones. */
flash->fault = 0;
rval = adp1653_get_fault(flash);
- mutex_unlock(&flash->ctrls.lock);
+ mutex_unlock(flash->ctrls.lock);
if (rval > 0) {
dev_err(&client->dev, "faults detected: 0x%1.1x\n", rval);
return -EIO;
}
- mutex_lock(&flash->ctrls.lock);
+ mutex_lock(flash->ctrls.lock);
rval = adp1653_update_hw(flash);
- mutex_unlock(&flash->ctrls.lock);
+ mutex_unlock(flash->ctrls.lock);
if (rval) {
dev_err(&client->dev,
"adp1653_update_hw failed at %s\n", __func__);
diff --git a/drivers/media/video/adv7180.c b/drivers/media/video/adv7180.c
index b8b6c4b0cad4..174bffacf117 100644
--- a/drivers/media/video/adv7180.c
+++ b/drivers/media/video/adv7180.c
@@ -48,6 +48,7 @@
#define ADV7180_INPUT_CONTROL_PAL_COMB_N_PED 0xd0
#define ADV7180_INPUT_CONTROL_PAL_SECAM 0xe0
#define ADV7180_INPUT_CONTROL_PAL_SECAM_PED 0xf0
+#define ADV7180_INPUT_CONTROL_INSEL_MASK 0x0f
#define ADV7180_EXTENDED_OUTPUT_CONTROL_REG 0x04
#define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS 0xC5
@@ -55,9 +56,29 @@
#define ADV7180_AUTODETECT_ENABLE_REG 0x07
#define ADV7180_AUTODETECT_DEFAULT 0x7f
+#define ADV7180_CON_REG 0x08 /*Unsigned */
+#define CON_REG_MIN 0
+#define CON_REG_DEF 128
+#define CON_REG_MAX 255
+
+#define ADV7180_BRI_REG 0x0a /*Signed */
+#define BRI_REG_MIN -128
+#define BRI_REG_DEF 0
+#define BRI_REG_MAX 127
+
+#define ADV7180_HUE_REG 0x0b /*Signed, inverted */
+#define HUE_REG_MIN -127
+#define HUE_REG_DEF 0
+#define HUE_REG_MAX 128
+
#define ADV7180_ADI_CTRL_REG 0x0e
#define ADV7180_ADI_CTRL_IRQ_SPACE 0x20
+#define ADV7180_PWR_MAN_REG 0x0f
+#define ADV7180_PWR_MAN_ON 0x04
+#define ADV7180_PWR_MAN_OFF 0x24
+#define ADV7180_PWR_MAN_RES 0x80
+
#define ADV7180_STATUS1_REG 0x10
#define ADV7180_STATUS1_IN_LOCK 0x01
#define ADV7180_STATUS1_AUTOD_MASK 0x70
@@ -78,6 +99,12 @@
#define ADV7180_ICONF1_PSYNC_ONLY 0x10
#define ADV7180_ICONF1_ACTIVE_TO_CLR 0xC0
+#define ADV7180_SD_SAT_CB_REG 0xe3 /*Unsigned */
+#define ADV7180_SD_SAT_CR_REG 0xe4 /*Unsigned */
+#define SAT_REG_MIN 0
+#define SAT_REG_DEF 128
+#define SAT_REG_MAX 255
+
#define ADV7180_IRQ1_LOCK 0x01
#define ADV7180_IRQ1_UNLOCK 0x02
#define ADV7180_ISR1_ADI 0x42
@@ -90,6 +117,9 @@
#define ADV7180_IMR3_ADI 0x4C
#define ADV7180_IMR4_ADI 0x50
+#define ADV7180_NTSC_V_BIT_END_REG 0xE6
+#define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND 0x4F
+
struct adv7180_state {
struct v4l2_subdev sd;
struct work_struct work;
@@ -97,6 +127,11 @@ struct adv7180_state {
int irq;
v4l2_std_id curr_norm;
bool autodetect;
+ s8 brightness;
+ s16 hue;
+ u8 contrast;
+ u8 saturation;
+ u8 input;
};
static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
@@ -155,7 +190,7 @@ static u32 adv7180_status_to_v4l2(u8 status1)
}
static int __adv7180_status(struct i2c_client *client, u32 *status,
- v4l2_std_id *std)
+ v4l2_std_id *std)
{
int status1 = i2c_smbus_read_byte_data(client, ADV7180_STATUS1_REG);
@@ -192,6 +227,36 @@ static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
return err;
}
+static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input,
+ u32 output, u32 config)
+{
+ struct adv7180_state *state = to_state(sd);
+ int ret = mutex_lock_interruptible(&state->mutex);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (ret)
+ return ret;
+
+ /*We cannot discriminate between LQFP and 40-pin LFCSP, so accept
+ * all inputs and let the card driver take care of validation
+ */
+ if ((input & ADV7180_INPUT_CONTROL_INSEL_MASK) != input)
+ goto out;
+
+ ret = i2c_smbus_read_byte_data(client, ADV7180_INPUT_CONTROL_REG);
+
+ if (ret < 0)
+ goto out;
+
+ ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK;
+ ret = i2c_smbus_write_byte_data(client,
+ ADV7180_INPUT_CONTROL_REG, ret | input);
+ state->input = input;
+out:
+ mutex_unlock(&state->mutex);
+ return ret;
+}
+
static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status)
{
struct adv7180_state *state = to_state(sd);
@@ -205,7 +270,7 @@ static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status)
}
static int adv7180_g_chip_ident(struct v4l2_subdev *sd,
- struct v4l2_dbg_chip_ident *chip)
+ struct v4l2_dbg_chip_ident *chip)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -222,9 +287,10 @@ static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
/* all standards -> autodetect */
if (std == V4L2_STD_ALL) {
- ret = i2c_smbus_write_byte_data(client,
- ADV7180_INPUT_CONTROL_REG,
- ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM);
+ ret =
+ i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
+ ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
+ | state->input);
if (ret < 0)
goto out;
@@ -236,7 +302,8 @@ static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
goto out;
ret = i2c_smbus_write_byte_data(client,
- ADV7180_INPUT_CONTROL_REG, ret);
+ ADV7180_INPUT_CONTROL_REG,
+ ret | state->input);
if (ret < 0)
goto out;
@@ -249,14 +316,138 @@ out:
return ret;
}
+static int adv7180_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ return v4l2_ctrl_query_fill(qc, BRI_REG_MIN, BRI_REG_MAX,
+ 1, BRI_REG_DEF);
+ case V4L2_CID_HUE:
+ return v4l2_ctrl_query_fill(qc, HUE_REG_MIN, HUE_REG_MAX,
+ 1, HUE_REG_DEF);
+ case V4L2_CID_CONTRAST:
+ return v4l2_ctrl_query_fill(qc, CON_REG_MIN, CON_REG_MAX,
+ 1, CON_REG_DEF);
+ case V4L2_CID_SATURATION:
+ return v4l2_ctrl_query_fill(qc, SAT_REG_MIN, SAT_REG_MAX,
+ 1, SAT_REG_DEF);
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int adv7180_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct adv7180_state *state = to_state(sd);
+ int ret = mutex_lock_interruptible(&state->mutex);
+ if (ret)
+ return ret;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = state->brightness;
+ break;
+ case V4L2_CID_HUE:
+ ctrl->value = state->hue;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = state->contrast;
+ break;
+ case V4L2_CID_SATURATION:
+ ctrl->value = state->saturation;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ mutex_unlock(&state->mutex);
+ return ret;
+}
+
+static int adv7180_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct adv7180_state *state = to_state(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = mutex_lock_interruptible(&state->mutex);
+ if (ret)
+ return ret;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ if ((ctrl->value > BRI_REG_MAX)
+ || (ctrl->value < BRI_REG_MIN)) {
+ ret = -ERANGE;
+ break;
+ }
+ state->brightness = ctrl->value;
+ ret = i2c_smbus_write_byte_data(client,
+ ADV7180_BRI_REG,
+ state->brightness);
+ break;
+ case V4L2_CID_HUE:
+ if ((ctrl->value > HUE_REG_MAX)
+ || (ctrl->value < HUE_REG_MIN)) {
+ ret = -ERANGE;
+ break;
+ }
+ state->hue = ctrl->value;
+ /*Hue is inverted according to HSL chart */
+ ret = i2c_smbus_write_byte_data(client,
+ ADV7180_HUE_REG, -state->hue);
+ break;
+ case V4L2_CID_CONTRAST:
+ if ((ctrl->value > CON_REG_MAX)
+ || (ctrl->value < CON_REG_MIN)) {
+ ret = -ERANGE;
+ break;
+ }
+ state->contrast = ctrl->value;
+ ret = i2c_smbus_write_byte_data(client,
+ ADV7180_CON_REG,
+ state->contrast);
+ break;
+ case V4L2_CID_SATURATION:
+ if ((ctrl->value > SAT_REG_MAX)
+ || (ctrl->value < SAT_REG_MIN)) {
+ ret = -ERANGE;
+ break;
+ }
+ /*
+ *This could be V4L2_CID_BLUE_BALANCE/V4L2_CID_RED_BALANCE
+ *Let's not confuse the user, everybody understands saturation
+ */
+ state->saturation = ctrl->value;
+ ret = i2c_smbus_write_byte_data(client,
+ ADV7180_SD_SAT_CB_REG,
+ state->saturation);
+ if (ret < 0)
+ break;
+ ret = i2c_smbus_write_byte_data(client,
+ ADV7180_SD_SAT_CR_REG,
+ state->saturation);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ mutex_unlock(&state->mutex);
+ return ret;
+}
+
static const struct v4l2_subdev_video_ops adv7180_video_ops = {
.querystd = adv7180_querystd,
.g_input_status = adv7180_g_input_status,
+ .s_routing = adv7180_s_routing,
};
static const struct v4l2_subdev_core_ops adv7180_core_ops = {
.g_chip_ident = adv7180_g_chip_ident,
.s_std = adv7180_s_std,
+ .queryctrl = adv7180_queryctrl,
+ .g_ctrl = adv7180_g_ctrl,
+ .s_ctrl = adv7180_s_ctrl,
};
static const struct v4l2_subdev_ops adv7180_ops = {
@@ -267,13 +458,13 @@ static const struct v4l2_subdev_ops adv7180_ops = {
static void adv7180_work(struct work_struct *work)
{
struct adv7180_state *state = container_of(work, struct adv7180_state,
- work);
+ work);
struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
u8 isr3;
mutex_lock(&state->mutex);
i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
- ADV7180_ADI_CTRL_IRQ_SPACE);
+ ADV7180_ADI_CTRL_IRQ_SPACE);
isr3 = i2c_smbus_read_byte_data(client, ADV7180_ISR3_ADI);
/* clear */
i2c_smbus_write_byte_data(client, ADV7180_ICR3_ADI, isr3);
@@ -297,56 +488,51 @@ static irqreturn_t adv7180_irq(int irq, void *devid)
return IRQ_HANDLED;
}
-/*
- * Generic i2c probe
- * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
- */
-
-static __devinit int adv7180_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int init_device(struct i2c_client *client, struct adv7180_state *state)
{
- struct adv7180_state *state;
- struct v4l2_subdev *sd;
int ret;
- /* Check if the adapter supports the needed features */
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
- return -EIO;
-
- v4l_info(client, "chip found @ 0x%02x (%s)\n",
- client->addr << 1, client->adapter->name);
-
- state = kzalloc(sizeof(struct adv7180_state), GFP_KERNEL);
- if (state == NULL) {
- ret = -ENOMEM;
- goto err;
- }
-
- state->irq = client->irq;
- INIT_WORK(&state->work, adv7180_work);
- mutex_init(&state->mutex);
- state->autodetect = true;
- sd = &state->sd;
- v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
-
/* Initialize adv7180 */
/* Enable autodetection */
- ret = i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
- ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM);
- if (ret < 0)
- goto err_unreg_subdev;
+ if (state->autodetect) {
+ ret =
+ i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
+ ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
+ | state->input);
+ if (ret < 0)
+ return ret;
- ret = i2c_smbus_write_byte_data(client, ADV7180_AUTODETECT_ENABLE_REG,
- ADV7180_AUTODETECT_DEFAULT);
- if (ret < 0)
- goto err_unreg_subdev;
+ ret =
+ i2c_smbus_write_byte_data(client,
+ ADV7180_AUTODETECT_ENABLE_REG,
+ ADV7180_AUTODETECT_DEFAULT);
+ if (ret < 0)
+ return ret;
+ } else {
+ ret = v4l2_std_to_adv7180(state->curr_norm);
+ if (ret < 0)
+ return ret;
+ ret =
+ i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
+ ret | state->input);
+ if (ret < 0)
+ return ret;
+
+ }
/* ITU-R BT.656-4 compatible */
ret = i2c_smbus_write_byte_data(client,
- ADV7180_EXTENDED_OUTPUT_CONTROL_REG,
- ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
+ ADV7180_EXTENDED_OUTPUT_CONTROL_REG,
+ ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
if (ret < 0)
- goto err_unreg_subdev;
+ return ret;
+
+ /* Manually set V bit end position in NTSC mode */
+ ret = i2c_smbus_write_byte_data(client,
+ ADV7180_NTSC_V_BIT_END_REG,
+ ADV7180_NTSC_V_BIT_END_MANUAL_NVEND);
+ if (ret < 0)
+ return ret;
/* read current norm */
__adv7180_status(client, NULL, &state->curr_norm);
@@ -354,45 +540,109 @@ static __devinit int adv7180_probe(struct i2c_client *client,
/* register for interrupts */
if (state->irq > 0) {
ret = request_irq(state->irq, adv7180_irq, 0, DRIVER_NAME,
- state);
+ state);
if (ret)
- goto err_unreg_subdev;
+ return ret;
ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
- ADV7180_ADI_CTRL_IRQ_SPACE);
+ ADV7180_ADI_CTRL_IRQ_SPACE);
if (ret < 0)
- goto err_unreg_subdev;
+ return ret;
/* config the Interrupt pin to be active low */
ret = i2c_smbus_write_byte_data(client, ADV7180_ICONF1_ADI,
- ADV7180_ICONF1_ACTIVE_LOW | ADV7180_ICONF1_PSYNC_ONLY);
+ ADV7180_ICONF1_ACTIVE_LOW |
+ ADV7180_ICONF1_PSYNC_ONLY);
if (ret < 0)
- goto err_unreg_subdev;
+ return ret;
ret = i2c_smbus_write_byte_data(client, ADV7180_IMR1_ADI, 0);
if (ret < 0)
- goto err_unreg_subdev;
+ return ret;
ret = i2c_smbus_write_byte_data(client, ADV7180_IMR2_ADI, 0);
if (ret < 0)
- goto err_unreg_subdev;
+ return ret;
/* enable AD change interrupts interrupts */
ret = i2c_smbus_write_byte_data(client, ADV7180_IMR3_ADI,
- ADV7180_IRQ3_AD_CHANGE);
+ ADV7180_IRQ3_AD_CHANGE);
if (ret < 0)
- goto err_unreg_subdev;
+ return ret;
ret = i2c_smbus_write_byte_data(client, ADV7180_IMR4_ADI, 0);
if (ret < 0)
- goto err_unreg_subdev;
+ return ret;
ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
- 0);
+ 0);
if (ret < 0)
- goto err_unreg_subdev;
+ return ret;
}
+ /*Set default value for controls */
+ ret = i2c_smbus_write_byte_data(client, ADV7180_BRI_REG,
+ state->brightness);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, ADV7180_HUE_REG, state->hue);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, ADV7180_CON_REG,
+ state->contrast);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CB_REG,
+ state->saturation);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CR_REG,
+ state->saturation);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static __devinit int adv7180_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct adv7180_state *state;
+ struct v4l2_subdev *sd;
+ int ret;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+ v4l_info(client, "chip found @ 0x%02x (%s)\n",
+ client->addr, client->adapter->name);
+
+ state = kzalloc(sizeof(struct adv7180_state), GFP_KERNEL);
+ if (state == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ state->irq = client->irq;
+ INIT_WORK(&state->work, adv7180_work);
+ mutex_init(&state->mutex);
+ state->autodetect = true;
+ state->brightness = BRI_REG_DEF;
+ state->hue = HUE_REG_DEF;
+ state->contrast = CON_REG_DEF;
+ state->saturation = SAT_REG_DEF;
+ state->input = 0;
+ sd = &state->sd;
+ v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
+
+ ret = init_device(client, state);
+ if (0 != ret)
+ goto err_unreg_subdev;
return 0;
err_unreg_subdev:
@@ -432,16 +682,49 @@ static const struct i2c_device_id adv7180_id[] = {
{},
};
+#ifdef CONFIG_PM
+static int adv7180_suspend(struct i2c_client *client, pm_message_t state)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG,
+ ADV7180_PWR_MAN_OFF);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int adv7180_resume(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct adv7180_state *state = to_state(sd);
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG,
+ ADV7180_PWR_MAN_ON);
+ if (ret < 0)
+ return ret;
+ ret = init_device(client, state);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+#endif
+
MODULE_DEVICE_TABLE(i2c, adv7180_id);
static struct i2c_driver adv7180_driver = {
.driver = {
- .owner = THIS_MODULE,
- .name = DRIVER_NAME,
- },
- .probe = adv7180_probe,
- .remove = __devexit_p(adv7180_remove),
- .id_table = adv7180_id,
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ },
+ .probe = adv7180_probe,
+ .remove = __devexit_p(adv7180_remove),
+#ifdef CONFIG_PM
+ .suspend = adv7180_suspend,
+ .resume = adv7180_resume,
+#endif
+ .id_table = adv7180_id,
};
module_i2c_driver(adv7180_driver);
diff --git a/drivers/media/video/adv7343.c b/drivers/media/video/adv7343.c
index 119b60401bf3..2b5aa676a84e 100644
--- a/drivers/media/video/adv7343.c
+++ b/drivers/media/video/adv7343.c
@@ -130,14 +130,12 @@ static int adv7343_setstd(struct v4l2_subdev *sd, v4l2_std_id std)
{
struct adv7343_state *state = to_state(sd);
struct adv7343_std_info *std_info;
- int output_idx, num_std;
+ int num_std;
char *fsc_ptr;
u8 reg, val;
int err = 0;
int i = 0;
- output_idx = state->output;
-
std_info = (struct adv7343_std_info *)stdinfo;
num_std = ARRAY_SIZE(stdinfo);
diff --git a/drivers/media/video/aptina-pll.c b/drivers/media/video/aptina-pll.c
index 0bd3813bb59d..8153a449846b 100644
--- a/drivers/media/video/aptina-pll.c
+++ b/drivers/media/video/aptina-pll.c
@@ -148,9 +148,8 @@ int aptina_pll_calculate(struct device *dev,
unsigned int mf_high;
unsigned int mf_low;
- mf_low = max(roundup(mf_min, mf_inc),
- DIV_ROUND_UP(pll->ext_clock * p1,
- limits->int_clock_max * div));
+ mf_low = roundup(max(mf_min, DIV_ROUND_UP(pll->ext_clock * p1,
+ limits->int_clock_max * div)), mf_inc);
mf_high = min(mf_max, pll->ext_clock * p1 /
(limits->int_clock_min * div));
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index b6ed44aebe30..e346d32d08ce 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -31,6 +31,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
@@ -403,7 +404,8 @@ static int ar_querycap(struct file *file, void *priv,
strlcpy(vcap->driver, ar->vdev.name, sizeof(vcap->driver));
strlcpy(vcap->card, "Colour AR VGA", sizeof(vcap->card));
strlcpy(vcap->bus_info, "Platform", sizeof(vcap->bus_info));
- vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -709,6 +711,8 @@ static int ar_initialize(struct ar *ar)
static const struct v4l2_file_operations ar_fops = {
.owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = v4l2_fh_release,
.read = ar_read,
.unlocked_ioctl = video_ioctl2,
};
@@ -769,6 +773,7 @@ static int __init ar_init(void)
ar->vdev.fops = &ar_fops;
ar->vdev.ioctl_ops = &ar_ioctl_ops;
ar->vdev.release = video_device_release_empty;
+ set_bit(V4L2_FL_USE_FH_PRIO, &ar->vdev.flags);
video_set_drvdata(&ar->vdev, ar);
if (vga) {
diff --git a/drivers/media/video/as3645a.c b/drivers/media/video/as3645a.c
index 7a3371f044fc..c4b03572dce8 100644
--- a/drivers/media/video/as3645a.c
+++ b/drivers/media/video/as3645a.c
@@ -713,7 +713,7 @@ static int as3645a_resume(struct device *dev)
* The number of LEDs reported in platform data is used to compute default
* limits. Parameters passed through platform data can override those limits.
*/
-static int as3645a_init_controls(struct as3645a *flash)
+static int __devinit as3645a_init_controls(struct as3645a *flash)
{
const struct as3645a_platform_data *pdata = flash->pdata;
struct v4l2_ctrl *ctrl;
@@ -804,8 +804,8 @@ static int as3645a_init_controls(struct as3645a *flash)
return flash->ctrls.error;
}
-static int as3645a_probe(struct i2c_client *client,
- const struct i2c_device_id *devid)
+static int __devinit as3645a_probe(struct i2c_client *client,
+ const struct i2c_device_id *devid)
{
struct as3645a *flash;
int ret;
@@ -846,7 +846,7 @@ done:
return ret;
}
-static int __exit as3645a_remove(struct i2c_client *client)
+static int __devexit as3645a_remove(struct i2c_client *client)
{
struct v4l2_subdev *subdev = i2c_get_clientdata(client);
struct as3645a *flash = to_as3645a(subdev);
@@ -877,7 +877,7 @@ static struct i2c_driver as3645a_i2c_driver = {
.pm = &as3645a_pm_ops,
},
.probe = as3645a_probe,
- .remove = __exit_p(as3645a_remove),
+ .remove = __devexit_p(as3645a_remove),
.id_table = as3645a_id_table,
};
diff --git a/drivers/media/video/atmel-isi.c b/drivers/media/video/atmel-isi.c
index ec3f6a06f9c3..6274a91c25c7 100644
--- a/drivers/media/video/atmel-isi.c
+++ b/drivers/media/video/atmel-isi.c
@@ -260,7 +260,7 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct atmel_isi *isi = ici->priv;
unsigned long size;
- int ret, bytes_per_line;
+ int ret;
/* Reset ISI */
ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET);
@@ -271,13 +271,7 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
/* Disable all interrupts */
isi_writel(isi, ISI_INTDIS, ~0UL);
- bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
- icd->current_fmt->host_fmt);
-
- if (bytes_per_line < 0)
- return bytes_per_line;
-
- size = bytes_per_line * icd->user_height;
+ size = icd->sizeimage;
if (!*nbuffers || *nbuffers > MAX_BUFFER_NUM)
*nbuffers = MAX_BUFFER_NUM;
@@ -316,13 +310,8 @@ static int buffer_prepare(struct vb2_buffer *vb)
struct atmel_isi *isi = ici->priv;
unsigned long size;
struct isi_dma_desc *desc;
- int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
- icd->current_fmt->host_fmt);
-
- if (bytes_per_line < 0)
- return bytes_per_line;
- size = bytes_per_line * icd->user_height;
+ size = icd->sizeimage;
if (vb2_plane_size(vb, 0) < size) {
dev_err(icd->parent, "%s data will not fit into plane (%lu < %lu)\n",
@@ -638,6 +627,7 @@ static const struct soc_mbus_pixelfmt isi_camera_formats[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
};
diff --git a/drivers/media/video/au0828/Kconfig b/drivers/media/video/au0828/Kconfig
index 81ba9d9d1b52..23f7fd22f0eb 100644
--- a/drivers/media/video/au0828/Kconfig
+++ b/drivers/media/video/au0828/Kconfig
@@ -6,7 +6,8 @@ config VIDEO_AU0828
select I2C_ALGOBIT
select VIDEO_TVEEPROM
select VIDEOBUF_VMALLOC
- select DVB_AU8522 if !DVB_FE_CUSTOMISE
+ select DVB_AU8522_DTV if !DVB_FE_CUSTOMISE
+ select DVB_AU8522_V4L if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c
index 1c6015a04f96..e3fe9a6637f6 100644
--- a/drivers/media/video/au0828/au0828-cards.c
+++ b/drivers/media/video/au0828/au0828-cards.c
@@ -325,6 +325,8 @@ struct usb_device_id au0828_usb_id_table[] = {
.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
{ USB_DEVICE(0x2040, 0x7281),
.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
+ { USB_DEVICE(0x05e1, 0x0480),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
{ USB_DEVICE(0x2040, 0x8200),
.driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
{ USB_DEVICE(0x2040, 0x7260),
diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c
index 518216743c9c..39ece8e24985 100644
--- a/drivers/media/video/au0828/au0828-dvb.c
+++ b/drivers/media/video/au0828/au0828-dvb.c
@@ -25,6 +25,7 @@
#include <linux/device.h>
#include <linux/suspend.h>
#include <media/v4l2-common.h>
+#include <media/tuner.h>
#include "au0828.h"
#include "au8522.h"
@@ -79,9 +80,16 @@ static struct au8522_config hauppauge_woodbury_config = {
.vsb_if = AU8522_IF_3_25MHZ,
};
-static struct xc5000_config hauppauge_hvr950q_tunerconfig = {
+static struct xc5000_config hauppauge_xc5000a_config = {
.i2c_address = 0x61,
.if_khz = 6000,
+ .chip_id = XC5000A,
+};
+
+static struct xc5000_config hauppauge_xc5000c_config = {
+ .i2c_address = 0x61,
+ .if_khz = 6000,
+ .chip_id = XC5000C,
};
static struct mxl5007t_config mxl5007t_hvr950q_config = {
@@ -383,8 +391,19 @@ int au0828_dvb_register(struct au0828_dev *dev)
&hauppauge_hvr950q_config,
&dev->i2c_adap);
if (dvb->frontend != NULL)
- dvb_attach(xc5000_attach, dvb->frontend, &dev->i2c_adap,
- &hauppauge_hvr950q_tunerconfig);
+ switch (dev->board.tuner_type) {
+ default:
+ case TUNER_XC5000:
+ dvb_attach(xc5000_attach, dvb->frontend,
+ &dev->i2c_adap,
+ &hauppauge_xc5000a_config);
+ break;
+ case TUNER_XC5000C:
+ dvb_attach(xc5000_attach, dvb->frontend,
+ &dev->i2c_adap,
+ &hauppauge_xc5000c_config);
+ break;
+ }
break;
case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
dvb->frontend = dvb_attach(au8522_attach,
@@ -411,7 +430,7 @@ int au0828_dvb_register(struct au0828_dev *dev)
if (dvb->frontend != NULL) {
dvb_attach(xc5000_attach, dvb->frontend,
&dev->i2c_adap,
- &hauppauge_hvr950q_tunerconfig);
+ &hauppauge_xc5000a_config);
}
break;
default:
diff --git a/drivers/media/video/au0828/au0828-video.c b/drivers/media/video/au0828/au0828-video.c
index 0b3e481ffe8c..ac3dd733ab81 100644
--- a/drivers/media/video/au0828/au0828-video.c
+++ b/drivers/media/video/au0828/au0828-video.c
@@ -120,7 +120,7 @@ static void au0828_irq_callback(struct urb *urb)
struct au0828_dmaqueue *dma_q = urb->context;
struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq);
unsigned long flags = 0;
- int rc, i;
+ int i;
switch (urb->status) {
case 0: /* success */
@@ -138,7 +138,7 @@ static void au0828_irq_callback(struct urb *urb)
/* Copy data from URB */
spin_lock_irqsave(&dev->slock, flags);
- rc = dev->isoc_ctl.isoc_copy(dev, urb);
+ dev->isoc_ctl.isoc_copy(dev, urb);
spin_unlock_irqrestore(&dev->slock, flags);
/* Reset urb buffers */
@@ -1881,7 +1881,7 @@ int au0828_analog_register(struct au0828_dev *dev,
int retval = -ENOMEM;
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
- int i;
+ int i, ret;
dprintk(1, "au0828_analog_register called!\n");
@@ -1951,8 +1951,8 @@ int au0828_analog_register(struct au0828_dev *dev,
dev->vbi_dev = video_device_alloc();
if (NULL == dev->vbi_dev) {
dprintk(1, "Can't allocate vbi_device.\n");
- kfree(dev->vdev);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_vdev;
}
/* Fill the video capture device struct */
@@ -1971,8 +1971,8 @@ int au0828_analog_register(struct au0828_dev *dev,
if (retval != 0) {
dprintk(1, "unable to register video device (error = %d).\n",
retval);
- video_device_release(dev->vdev);
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_vbi_dev;
}
/* Register the vbi device */
@@ -1981,13 +1981,18 @@ int au0828_analog_register(struct au0828_dev *dev,
if (retval != 0) {
dprintk(1, "unable to register vbi device (error = %d).\n",
retval);
- video_device_release(dev->vbi_dev);
- video_device_release(dev->vdev);
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_vbi_dev;
}
dprintk(1, "%s completed!\n", __func__);
return 0;
+
+err_vbi_dev:
+ video_device_release(dev->vbi_dev);
+err_vdev:
+ video_device_release(dev->vdev);
+ return ret;
}
diff --git a/drivers/media/video/blackfin/bfin_capture.c b/drivers/media/video/blackfin/bfin_capture.c
index 514fcf742f5a..0aba45e34f70 100644
--- a/drivers/media/video/blackfin/bfin_capture.c
+++ b/drivers/media/video/blackfin/bfin_capture.c
@@ -942,6 +942,10 @@ static int __devinit bcap_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&bcap_dev->dma_queue);
vfd->lock = &bcap_dev->mutex;
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
/* register video device */
ret = video_register_device(bcap_dev->video_dev, VFL_TYPE_GRABBER, -1);
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index e581b37be789..a9cfb0f4be48 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -663,7 +663,7 @@ static const struct v4l2_queryctrl bttv_ctls[] = {
.minimum = 0,
.maximum = 65535,
.step = 128,
- .default_value = 32768,
+ .default_value = 27648,
.type = V4L2_CTRL_TYPE_INTEGER,
},{
.id = V4L2_CID_SATURATION,
@@ -4394,7 +4394,7 @@ static int __devinit bttv_probe(struct pci_dev *dev,
if (!bttv_tvcards[btv->c.type].no_video) {
bttv_register_video(btv);
bt848_bright(btv,32768);
- bt848_contrast(btv,32768);
+ bt848_contrast(btv, 27648);
bt848_hue(btv,32768);
bt848_sat(btv,32768);
audio_mute(btv, 1);
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index f09df9dffaae..2520219f01ba 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -77,6 +77,9 @@ OTHER DEALINGS IN THE SOFTWARE.
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
/* One from column A... */
#define QC_NOTSET 0
@@ -103,6 +106,7 @@ OTHER DEALINGS IN THE SOFTWARE.
struct qcam {
struct v4l2_device v4l2_dev;
struct video_device vdev;
+ struct v4l2_ctrl_handler hdl;
struct pardevice *pdev;
struct parport *pport;
struct mutex lock;
@@ -646,7 +650,8 @@ static int qcam_querycap(struct file *file, void *priv,
strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
strlcpy(vcap->card, "B&W Quickcam", sizeof(vcap->card));
strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
- vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -674,72 +679,6 @@ static int qcam_s_input(struct file *file, void *fh, unsigned int inp)
return (inp > 0) ? -EINVAL : 0;
}
-static int qcam_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- switch (qc->id) {
- case V4L2_CID_BRIGHTNESS:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 180);
- case V4L2_CID_CONTRAST:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 192);
- case V4L2_CID_GAMMA:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 105);
- }
- return -EINVAL;
-}
-
-static int qcam_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct qcam *qcam = video_drvdata(file);
- int ret = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- ctrl->value = qcam->brightness;
- break;
- case V4L2_CID_CONTRAST:
- ctrl->value = qcam->contrast;
- break;
- case V4L2_CID_GAMMA:
- ctrl->value = qcam->whitebal;
- break;
- default:
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-static int qcam_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct qcam *qcam = video_drvdata(file);
- int ret = 0;
-
- mutex_lock(&qcam->lock);
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- qcam->brightness = ctrl->value;
- break;
- case V4L2_CID_CONTRAST:
- qcam->contrast = ctrl->value;
- break;
- case V4L2_CID_GAMMA:
- qcam->whitebal = ctrl->value;
- break;
- default:
- ret = -EINVAL;
- break;
- }
- if (ret == 0) {
- qc_setscanmode(qcam);
- qcam->status |= QC_PARAM_CHANGE;
- }
- mutex_unlock(&qcam->lock);
- return ret;
-}
-
static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
{
struct qcam *qcam = video_drvdata(file);
@@ -856,8 +795,40 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
return len;
}
+static int qcam_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct qcam *qcam =
+ container_of(ctrl->handler, struct qcam, hdl);
+ int ret = 0;
+
+ mutex_lock(&qcam->lock);
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ qcam->brightness = ctrl->val;
+ break;
+ case V4L2_CID_CONTRAST:
+ qcam->contrast = ctrl->val;
+ break;
+ case V4L2_CID_GAMMA:
+ qcam->whitebal = ctrl->val;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret == 0) {
+ qc_setscanmode(qcam);
+ qcam->status |= QC_PARAM_CHANGE;
+ }
+ mutex_unlock(&qcam->lock);
+ return ret;
+}
+
static const struct v4l2_file_operations qcam_fops = {
.owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = v4l2_fh_release,
+ .poll = v4l2_ctrl_poll,
.unlocked_ioctl = video_ioctl2,
.read = qcam_read,
};
@@ -867,13 +838,17 @@ static const struct v4l2_ioctl_ops qcam_ioctl_ops = {
.vidioc_g_input = qcam_g_input,
.vidioc_s_input = qcam_s_input,
.vidioc_enum_input = qcam_enum_input,
- .vidioc_queryctrl = qcam_queryctrl,
- .vidioc_g_ctrl = qcam_g_ctrl,
- .vidioc_s_ctrl = qcam_s_ctrl,
.vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap,
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_ctrl_ops qcam_ctrl_ops = {
+ .s_ctrl = qcam_s_ctrl,
};
/* Initialize the QuickCam driver control structure. This is where
@@ -897,19 +872,35 @@ static struct qcam *qcam_init(struct parport *port)
return NULL;
}
+ v4l2_ctrl_handler_init(&qcam->hdl, 3);
+ v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 180);
+ v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1, 192);
+ v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
+ V4L2_CID_GAMMA, 0, 255, 1, 105);
+ if (qcam->hdl.error) {
+ v4l2_err(v4l2_dev, "couldn't register controls\n");
+ v4l2_ctrl_handler_free(&qcam->hdl);
+ kfree(qcam);
+ return NULL;
+ }
qcam->pport = port;
qcam->pdev = parport_register_device(port, "bw-qcam", NULL, NULL,
NULL, 0, NULL);
if (qcam->pdev == NULL) {
v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name);
+ v4l2_ctrl_handler_free(&qcam->hdl);
kfree(qcam);
return NULL;
}
strlcpy(qcam->vdev.name, "Connectix QuickCam", sizeof(qcam->vdev.name));
qcam->vdev.v4l2_dev = v4l2_dev;
+ qcam->vdev.ctrl_handler = &qcam->hdl;
qcam->vdev.fops = &qcam_fops;
qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
+ set_bit(V4L2_FL_USE_FH_PRIO, &qcam->vdev.flags);
qcam->vdev.release = video_device_release_empty;
video_set_drvdata(&qcam->vdev, qcam);
@@ -1003,6 +994,7 @@ static int init_bwqcam(struct parport *port)
static void close_bwqcam(struct qcam *qcam)
{
video_unregister_device(&qcam->vdev);
+ v4l2_ctrl_handler_free(&qcam->hdl);
parport_unregister_device(qcam->pdev);
kfree(qcam);
}
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index fda32f52554a..ec51e1f12e82 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -40,10 +40,14 @@
#include <media/v4l2-device.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
struct qcam {
struct v4l2_device v4l2_dev;
struct video_device vdev;
+ struct v4l2_ctrl_handler hdl;
struct pardevice *pdev;
struct parport *pport;
int width, height;
@@ -378,7 +382,7 @@ get_fragment:
static long qc_capture(struct qcam *qcam, char __user *buf, unsigned long len)
{
struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
- unsigned lines, pixelsperline, bitsperxfer;
+ unsigned lines, pixelsperline;
unsigned int is_bi_dir = qcam->bidirectional;
size_t wantlen, outptr = 0;
char tmpbuf[BUFSZ];
@@ -404,7 +408,6 @@ static long qc_capture(struct qcam *qcam, char __user *buf, unsigned long len)
lines = qcam->height;
pixelsperline = qcam->width;
- bitsperxfer = (is_bi_dir) ? 24 : 8;
if (is_bi_dir) {
/* Turn the port around */
@@ -516,7 +519,8 @@ static int qcam_querycap(struct file *file, void *priv,
strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
strlcpy(vcap->card, "Color Quickcam", sizeof(vcap->card));
strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
- vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -544,73 +548,6 @@ static int qcam_s_input(struct file *file, void *fh, unsigned int inp)
return (inp > 0) ? -EINVAL : 0;
}
-static int qcam_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- switch (qc->id) {
- case V4L2_CID_BRIGHTNESS:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 240);
- case V4L2_CID_CONTRAST:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 192);
- case V4L2_CID_GAMMA:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
- }
- return -EINVAL;
-}
-
-static int qcam_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct qcam *qcam = video_drvdata(file);
- int ret = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- ctrl->value = qcam->brightness;
- break;
- case V4L2_CID_CONTRAST:
- ctrl->value = qcam->contrast;
- break;
- case V4L2_CID_GAMMA:
- ctrl->value = qcam->whitebal;
- break;
- default:
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-static int qcam_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct qcam *qcam = video_drvdata(file);
- int ret = 0;
-
- mutex_lock(&qcam->lock);
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- qcam->brightness = ctrl->value;
- break;
- case V4L2_CID_CONTRAST:
- qcam->contrast = ctrl->value;
- break;
- case V4L2_CID_GAMMA:
- qcam->whitebal = ctrl->value;
- break;
- default:
- ret = -EINVAL;
- break;
- }
- if (ret == 0) {
- parport_claim_or_block(qcam->pdev);
- qc_setup(qcam);
- parport_release(qcam->pdev);
- }
- mutex_unlock(&qcam->lock);
- return ret;
-}
-
static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
{
struct qcam *qcam = video_drvdata(file);
@@ -714,8 +651,41 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
return len;
}
+static int qcam_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct qcam *qcam =
+ container_of(ctrl->handler, struct qcam, hdl);
+ int ret = 0;
+
+ mutex_lock(&qcam->lock);
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ qcam->brightness = ctrl->val;
+ break;
+ case V4L2_CID_CONTRAST:
+ qcam->contrast = ctrl->val;
+ break;
+ case V4L2_CID_GAMMA:
+ qcam->whitebal = ctrl->val;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret == 0) {
+ parport_claim_or_block(qcam->pdev);
+ qc_setup(qcam);
+ parport_release(qcam->pdev);
+ }
+ mutex_unlock(&qcam->lock);
+ return ret;
+}
+
static const struct v4l2_file_operations qcam_fops = {
.owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = v4l2_fh_release,
+ .poll = v4l2_ctrl_poll,
.unlocked_ioctl = video_ioctl2,
.read = qcam_read,
};
@@ -725,13 +695,17 @@ static const struct v4l2_ioctl_ops qcam_ioctl_ops = {
.vidioc_g_input = qcam_g_input,
.vidioc_s_input = qcam_s_input,
.vidioc_enum_input = qcam_enum_input,
- .vidioc_queryctrl = qcam_queryctrl,
- .vidioc_g_ctrl = qcam_g_ctrl,
- .vidioc_s_ctrl = qcam_s_ctrl,
- .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap,
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_ctrl_ops qcam_ctrl_ops = {
+ .s_ctrl = qcam_s_ctrl,
};
/* Initialize the QuickCam driver control structure. */
@@ -754,6 +728,20 @@ static struct qcam *qcam_init(struct parport *port)
return NULL;
}
+ v4l2_ctrl_handler_init(&qcam->hdl, 3);
+ v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 240);
+ v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1, 192);
+ v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
+ V4L2_CID_GAMMA, 0, 255, 1, 128);
+ if (qcam->hdl.error) {
+ v4l2_err(v4l2_dev, "couldn't register controls\n");
+ v4l2_ctrl_handler_free(&qcam->hdl);
+ kfree(qcam);
+ return NULL;
+ }
+
qcam->pport = port;
qcam->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
NULL, 0, NULL);
@@ -762,6 +750,7 @@ static struct qcam *qcam_init(struct parport *port)
if (qcam->pdev == NULL) {
v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name);
+ v4l2_ctrl_handler_free(&qcam->hdl);
kfree(qcam);
return NULL;
}
@@ -771,6 +760,8 @@ static struct qcam *qcam_init(struct parport *port)
qcam->vdev.fops = &qcam_fops;
qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
qcam->vdev.release = video_device_release_empty;
+ qcam->vdev.ctrl_handler = &qcam->hdl;
+ set_bit(V4L2_FL_USE_FH_PRIO, &qcam->vdev.flags);
video_set_drvdata(&qcam->vdev, qcam);
mutex_init(&qcam->lock);
@@ -845,6 +836,7 @@ static int init_cqcam(struct parport *port)
static void close_cqcam(struct qcam *qcam)
{
video_unregister_device(&qcam->vdev);
+ v4l2_ctrl_handler_free(&qcam->hdl);
parport_unregister_device(qcam->pdev);
kfree(qcam);
}
diff --git a/drivers/media/video/cpia2/cpia2.h b/drivers/media/video/cpia2/cpia2.h
index ab252188981b..cdef677d57ec 100644
--- a/drivers/media/video/cpia2/cpia2.h
+++ b/drivers/media/video/cpia2/cpia2.h
@@ -32,11 +32,12 @@
#define __CPIA2_H__
#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
#include <linux/usb.h>
#include <linux/poll.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
-#include "cpia2dev.h"
#include "cpia2_registers.h"
/* define for verbose debug output */
@@ -65,7 +66,6 @@
/* Flicker Modes */
#define NEVER_FLICKER 0
-#define ANTI_FLICKER_ON 1
#define FLICKER_60 60
#define FLICKER_50 50
@@ -148,7 +148,6 @@ enum {
#define DEFAULT_BRIGHTNESS 0x46
#define DEFAULT_CONTRAST 0x93
#define DEFAULT_SATURATION 0x7f
-#define DEFAULT_TARGET_KB 0x30
/* Power state */
#define HI_POWER_MODE CPIA2_SYSTEM_CONTROL_HIGH_POWER
@@ -287,7 +286,6 @@ struct camera_params {
struct {
u8 cam_register;
u8 flicker_mode_req; /* 1 if flicker on, else never flicker */
- int mains_frequency;
} flicker_control;
struct {
@@ -337,7 +335,7 @@ struct camera_params {
u8 vc_control;
u8 vc_mp_direction;
u8 vc_mp_data;
- u8 target_kb;
+ u8 quality;
} vc_params;
struct {
@@ -366,23 +364,23 @@ struct framebuf {
struct framebuf *next;
};
-struct cpia2_fh {
- enum v4l2_priority prio;
- u8 mmapped;
-};
-
struct camera_data {
/* locks */
+ struct v4l2_device v4l2_dev;
struct mutex v4l2_lock; /* serialize file operations */
- struct v4l2_prio_state prio;
+ struct v4l2_ctrl_handler hdl;
+ struct {
+ /* Lights control cluster */
+ struct v4l2_ctrl *top_light;
+ struct v4l2_ctrl *bottom_light;
+ };
+ struct v4l2_ctrl *usb_alt;
/* camera status */
- volatile int present; /* Is the camera still present? */
- int open_count; /* # of process that have camera open */
int first_image_seen;
- u8 mains_freq; /* for flicker control */
enum sensors sensor_type;
u8 flush;
+ struct v4l2_fh *stream_fh;
u8 mmapped;
int streaming; /* 0 = no, 1 = yes */
int xfer_mode; /* XFER_BULK or XFER_ISOC */
@@ -390,7 +388,7 @@ struct camera_data {
/* v4l */
int video_size; /* VIDEO_SIZE_ */
- struct video_device *vdev; /* v4l videodev */
+ struct video_device vdev; /* v4l videodev */
u32 width;
u32 height; /* Its size */
__u32 pixelformat; /* Format fourcc */
@@ -425,6 +423,7 @@ struct camera_data {
/* v4l */
int cpia2_register_camera(struct camera_data *cam);
void cpia2_unregister_camera(struct camera_data *cam);
+void cpia2_camera_release(struct v4l2_device *v4l2_dev);
/* core */
int cpia2_reset_camera(struct camera_data *cam);
@@ -443,7 +442,7 @@ int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd);
int cpia2_do_command(struct camera_data *cam,
unsigned int command,
unsigned char direction, unsigned char param);
-struct camera_data *cpia2_init_camera_struct(void);
+struct camera_data *cpia2_init_camera_struct(struct usb_interface *intf);
int cpia2_init_camera(struct camera_data *cam);
int cpia2_allocate_buffers(struct camera_data *cam);
void cpia2_free_buffers(struct camera_data *cam);
@@ -454,7 +453,6 @@ unsigned int cpia2_poll(struct camera_data *cam,
int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma);
void cpia2_set_property_flip(struct camera_data *cam, int prop_val);
void cpia2_set_property_mirror(struct camera_data *cam, int prop_val);
-int cpia2_set_target_kb(struct camera_data *cam, unsigned char value);
int cpia2_set_gpio(struct camera_data *cam, unsigned char setting);
int cpia2_set_fps(struct camera_data *cam, int framerate);
diff --git a/drivers/media/video/cpia2/cpia2_core.c b/drivers/media/video/cpia2/cpia2_core.c
index ee91e295c90a..17188e234770 100644
--- a/drivers/media/video/cpia2/cpia2_core.c
+++ b/drivers/media/video/cpia2/cpia2_core.c
@@ -66,7 +66,6 @@ static int config_sensor_410(struct camera_data *cam,
static int config_sensor_500(struct camera_data *cam,
int reqwidth, int reqheight);
static int set_all_properties(struct camera_data *cam);
-static void get_color_params(struct camera_data *cam);
static void wake_system(struct camera_data *cam);
static void set_lowlight_boost(struct camera_data *cam);
static void reset_camera_struct(struct camera_data *cam);
@@ -453,15 +452,6 @@ int cpia2_do_command(struct camera_data *cam,
cam->params.version.vp_device_hi = cmd.buffer.block_data[0];
cam->params.version.vp_device_lo = cmd.buffer.block_data[1];
break;
- case CPIA2_CMD_GET_VP_BRIGHTNESS:
- cam->params.color_params.brightness = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_CONTRAST:
- cam->params.color_params.contrast = cmd.buffer.block_data[0];
- break;
- case CPIA2_CMD_GET_VP_SATURATION:
- cam->params.color_params.saturation = cmd.buffer.block_data[0];
- break;
case CPIA2_CMD_GET_VP_GPIO_DATA:
cam->params.vp_params.gpio_data = cmd.buffer.block_data[0];
break;
@@ -617,6 +607,7 @@ int cpia2_reset_camera(struct camera_data *cam)
{
u8 tmp_reg;
int retval = 0;
+ int target_kb;
int i;
struct cpia2_command cmd;
@@ -800,9 +791,16 @@ int cpia2_reset_camera(struct camera_data *cam)
}
cpia2_do_command(cam, CPIA2_CMD_SET_VC_CONTROL, TRANSFER_WRITE,tmp_reg);
- /* Set target size (kb) on vc */
+ /* Set target size (kb) on vc
+ This is a heuristic based on the quality parameter and the raw
+ framesize in kB divided by 16 (the compression factor when the
+ quality is 100%) */
+ target_kb = (cam->width * cam->height * 2 / 16384) *
+ cam->params.vc_params.quality / 100;
+ if (target_kb < 1)
+ target_kb = 1;
cpia2_do_command(cam, CPIA2_CMD_SET_TARGET_KB,
- TRANSFER_WRITE, cam->params.vc_params.target_kb);
+ TRANSFER_WRITE, target_kb);
/* Wiggle VC Reset */
/***
@@ -1538,23 +1536,17 @@ static int set_all_properties(struct camera_data *cam)
* framerate and user_mode were already set (set_default_user_mode).
**/
- cpia2_set_color_params(cam);
-
cpia2_usb_change_streaming_alternate(cam,
cam->params.camera_state.stream_mode);
- cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
- cam->params.vp_params.user_effects);
-
- cpia2_set_flicker_mode(cam,
- cam->params.flicker_control.flicker_mode_req);
-
cpia2_do_command(cam,
CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION,
TRANSFER_WRITE, cam->params.vp_params.gpio_direction);
cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA, TRANSFER_WRITE,
cam->params.vp_params.gpio_data);
+ v4l2_ctrl_handler_setup(&cam->hdl);
+
wake_system(cam);
set_lowlight_boost(cam);
@@ -1569,7 +1561,6 @@ static int set_all_properties(struct camera_data *cam)
*****************************************************************************/
void cpia2_save_camera_state(struct camera_data *cam)
{
- get_color_params(cam);
cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0);
cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION, TRANSFER_READ,
0);
@@ -1577,30 +1568,6 @@ void cpia2_save_camera_state(struct camera_data *cam)
/* Don't get framerate or target_kb. Trust the values we already have */
}
-/******************************************************************************
- *
- * get_color_params
- *
- *****************************************************************************/
-static void get_color_params(struct camera_data *cam)
-{
- cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS, TRANSFER_READ, 0);
- cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION, TRANSFER_READ, 0);
- cpia2_do_command(cam, CPIA2_CMD_GET_CONTRAST, TRANSFER_READ, 0);
-}
-
-/******************************************************************************
- *
- * cpia2_set_color_params
- *
- *****************************************************************************/
-void cpia2_set_color_params(struct camera_data *cam)
-{
- DBG("Setting color params\n");
- cpia2_set_brightness(cam, cam->params.color_params.brightness);
- cpia2_set_contrast(cam, cam->params.color_params.contrast);
- cpia2_set_saturation(cam, cam->params.color_params.saturation);
-}
/******************************************************************************
*
@@ -1664,15 +1631,9 @@ int cpia2_set_flicker_mode(struct camera_data *cam, int mode)
switch(mode) {
case NEVER_FLICKER:
- cam->params.flicker_control.flicker_mode_req = mode;
- break;
case FLICKER_60:
- cam->params.flicker_control.flicker_mode_req = mode;
- cam->params.flicker_control.mains_frequency = 60;
- break;
case FLICKER_50:
cam->params.flicker_control.flicker_mode_req = mode;
- cam->params.flicker_control.mains_frequency = 50;
break;
default:
err = -EINVAL;
@@ -1701,6 +1662,7 @@ void cpia2_set_property_flip(struct camera_data *cam, int prop_val)
{
cam_reg &= ~CPIA2_VP_USER_EFFECTS_FLIP;
}
+ cam->params.vp_params.user_effects = cam_reg;
cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
cam_reg);
}
@@ -1725,37 +1687,13 @@ void cpia2_set_property_mirror(struct camera_data *cam, int prop_val)
{
cam_reg &= ~CPIA2_VP_USER_EFFECTS_MIRROR;
}
+ cam->params.vp_params.user_effects = cam_reg;
cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
cam_reg);
}
/******************************************************************************
*
- * set_target_kb
- *
- * The new Target KB is set in cam->params.vc_params.target_kb and
- * activates on reset.
- *****************************************************************************/
-
-int cpia2_set_target_kb(struct camera_data *cam, unsigned char value)
-{
- DBG("Requested target_kb = %d\n", value);
- if (value != cam->params.vc_params.target_kb) {
-
- cpia2_usb_stream_pause(cam);
-
- /* reset camera for new target_kb */
- cam->params.vc_params.target_kb = value;
- cpia2_reset_camera(cam);
-
- cpia2_usb_stream_resume(cam);
- }
-
- return 0;
-}
-
-/******************************************************************************
- *
* cpia2_set_gpio
*
*****************************************************************************/
@@ -1843,7 +1781,7 @@ void cpia2_set_brightness(struct camera_data *cam, unsigned char value)
if (cam->params.pnp_id.device_type == DEVICE_STV_672 && value == 0)
value++;
DBG("Setting brightness to %d (0x%0x)\n", value, value);
- cpia2_do_command(cam,CPIA2_CMD_SET_VP_BRIGHTNESS, TRANSFER_WRITE,value);
+ cpia2_do_command(cam, CPIA2_CMD_SET_VP_BRIGHTNESS, TRANSFER_WRITE, value);
}
/******************************************************************************
@@ -1854,7 +1792,6 @@ void cpia2_set_brightness(struct camera_data *cam, unsigned char value)
void cpia2_set_contrast(struct camera_data *cam, unsigned char value)
{
DBG("Setting contrast to %d (0x%0x)\n", value, value);
- cam->params.color_params.contrast = value;
cpia2_do_command(cam, CPIA2_CMD_SET_CONTRAST, TRANSFER_WRITE, value);
}
@@ -1866,7 +1803,6 @@ void cpia2_set_contrast(struct camera_data *cam, unsigned char value)
void cpia2_set_saturation(struct camera_data *cam, unsigned char value)
{
DBG("Setting saturation to %d (0x%0x)\n", value, value);
- cam->params.color_params.saturation = value;
cpia2_do_command(cam,CPIA2_CMD_SET_VP_SATURATION, TRANSFER_WRITE,value);
}
@@ -2168,14 +2104,10 @@ static void reset_camera_struct(struct camera_data *cam)
/***
* The following parameter values are the defaults from the register map.
***/
- cam->params.color_params.brightness = DEFAULT_BRIGHTNESS;
- cam->params.color_params.contrast = DEFAULT_CONTRAST;
- cam->params.color_params.saturation = DEFAULT_SATURATION;
cam->params.vp_params.lowlight_boost = 0;
/* FlickerModes */
cam->params.flicker_control.flicker_mode_req = NEVER_FLICKER;
- cam->params.flicker_control.mains_frequency = 60;
/* jpeg params */
cam->params.compression.jpeg_options = CPIA2_VC_VC_JPEG_OPT_DEFAULT;
@@ -2188,7 +2120,7 @@ static void reset_camera_struct(struct camera_data *cam)
cam->params.vp_params.gpio_data = 0;
/* Target kb params */
- cam->params.vc_params.target_kb = DEFAULT_TARGET_KB;
+ cam->params.vc_params.quality = 100;
/***
* Set Sensor FPS as fast as possible.
@@ -2228,7 +2160,7 @@ static void reset_camera_struct(struct camera_data *cam)
*
* Initializes camera struct, does not call reset to fill in defaults.
*****************************************************************************/
-struct camera_data *cpia2_init_camera_struct(void)
+struct camera_data *cpia2_init_camera_struct(struct usb_interface *intf)
{
struct camera_data *cam;
@@ -2239,8 +2171,13 @@ struct camera_data *cpia2_init_camera_struct(void)
return NULL;
}
+ cam->v4l2_dev.release = cpia2_camera_release;
+ if (v4l2_device_register(&intf->dev, &cam->v4l2_dev) < 0) {
+ v4l2_err(&cam->v4l2_dev, "couldn't register v4l2_device\n");
+ kfree(cam);
+ return NULL;
+ }
- cam->present = 1;
mutex_init(&cam->v4l2_lock);
init_waitqueue_head(&cam->wq_stream);
@@ -2373,11 +2310,6 @@ long cpia2_read(struct camera_data *cam,
return -EINVAL;
}
- if (!cam->present) {
- LOG("%s: camera removed\n",__func__);
- return 0; /* EOF */
- }
-
if (!cam->streaming) {
/* Start streaming */
cpia2_usb_stream_start(cam,
@@ -2393,12 +2325,12 @@ long cpia2_read(struct camera_data *cam,
if (frame->status != FRAME_READY) {
mutex_unlock(&cam->v4l2_lock);
wait_event_interruptible(cam->wq_stream,
- !cam->present ||
+ !video_is_registered(&cam->vdev) ||
(frame = cam->curbuff)->status == FRAME_READY);
mutex_lock(&cam->v4l2_lock);
if (signal_pending(current))
return -ERESTARTSYS;
- if (!cam->present)
+ if (!video_is_registered(&cam->vdev))
return 0;
}
@@ -2423,17 +2355,10 @@ long cpia2_read(struct camera_data *cam,
unsigned int cpia2_poll(struct camera_data *cam, struct file *filp,
poll_table *wait)
{
- unsigned int status=0;
+ unsigned int status = v4l2_ctrl_poll(filp, wait);
- if (!cam) {
- ERR("%s: Internal error, camera_data not found!\n",__func__);
- return POLLERR;
- }
-
- if (!cam->present)
- return POLLHUP;
-
- if(!cam->streaming) {
+ if ((poll_requested_events(wait) & (POLLIN | POLLRDNORM)) &&
+ !cam->streaming) {
/* Start streaming */
cpia2_usb_stream_start(cam,
cam->params.camera_state.stream_mode);
@@ -2441,10 +2366,8 @@ unsigned int cpia2_poll(struct camera_data *cam, struct file *filp,
poll_wait(filp, &cam->wq_stream, wait);
- if(!cam->present)
- status = POLLHUP;
- else if(cam->curbuff->status == FRAME_READY)
- status = POLLIN | POLLRDNORM;
+ if (cam->curbuff->status == FRAME_READY)
+ status |= POLLIN | POLLRDNORM;
return status;
}
@@ -2462,12 +2385,9 @@ int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma)
unsigned long start = (unsigned long) adr;
unsigned long page, pos;
- if (!cam)
- return -ENODEV;
-
DBG("mmap offset:%ld size:%ld\n", start_offset, size);
- if (!cam->present)
+ if (!video_is_registered(&cam->vdev))
return -ENODEV;
if (size > cam->frame_size*cam->num_frames ||
diff --git a/drivers/media/video/cpia2/cpia2_usb.c b/drivers/media/video/cpia2/cpia2_usb.c
index 59c797c15277..95b5d6e7cdc4 100644
--- a/drivers/media/video/cpia2/cpia2_usb.c
+++ b/drivers/media/video/cpia2/cpia2_usb.c
@@ -54,6 +54,8 @@ static void cpia2_usb_complete(struct urb *urb);
static int cpia2_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id);
static void cpia2_usb_disconnect(struct usb_interface *intf);
+static int cpia2_usb_suspend(struct usb_interface *intf, pm_message_t message);
+static int cpia2_usb_resume(struct usb_interface *intf);
static void free_sbufs(struct camera_data *cam);
static void add_APPn(struct camera_data *cam);
@@ -74,6 +76,9 @@ static struct usb_driver cpia2_driver = {
.name = "cpia2",
.probe = cpia2_usb_probe,
.disconnect = cpia2_usb_disconnect,
+ .suspend = cpia2_usb_suspend,
+ .resume = cpia2_usb_resume,
+ .reset_resume = cpia2_usb_resume,
.id_table = cpia2_id_table
};
@@ -218,10 +223,9 @@ static void cpia2_usb_complete(struct urb *urb)
return;
}
- if (!cam->streaming || !cam->present || cam->open_count == 0) {
- LOG("Will now stop the streaming: streaming = %d, "
- "present=%d, open_count=%d\n",
- cam->streaming, cam->present, cam->open_count);
+ if (!cam->streaming || !video_is_registered(&cam->vdev)) {
+ LOG("Will now stop the streaming: streaming = %d, present=%d\n",
+ cam->streaming, video_is_registered(&cam->vdev));
return;
}
@@ -392,7 +396,7 @@ static int configure_transfer_mode(struct camera_data *cam, unsigned int alt)
struct cpia2_command cmd;
unsigned char reg;
- if(!cam->present)
+ if (!video_is_registered(&cam->vdev))
return -ENODEV;
/***
@@ -752,8 +756,8 @@ int cpia2_usb_stream_pause(struct camera_data *cam)
{
int ret = 0;
if(cam->streaming) {
- ret = set_alternate(cam, USBIF_CMDONLY);
free_sbufs(cam);
+ ret = set_alternate(cam, USBIF_CMDONLY);
}
return ret;
}
@@ -770,6 +774,10 @@ int cpia2_usb_stream_resume(struct camera_data *cam)
cam->first_image_seen = 0;
ret = set_alternate(cam, cam->params.camera_state.stream_mode);
if(ret == 0) {
+ /* for some reason the user effects need to be set
+ again when starting streaming. */
+ cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE,
+ cam->params.vp_params.user_effects);
ret = submit_urbs(cam);
}
}
@@ -784,6 +792,7 @@ int cpia2_usb_stream_resume(struct camera_data *cam)
int cpia2_usb_stream_stop(struct camera_data *cam)
{
int ret;
+
ret = cpia2_usb_stream_pause(cam);
cam->streaming = 0;
configure_transfer_mode(cam, 0);
@@ -812,7 +821,8 @@ static int cpia2_usb_probe(struct usb_interface *intf,
/* If we get to this point, we found a CPiA2 camera */
LOG("CPiA2 USB camera found\n");
- if((cam = cpia2_init_camera_struct()) == NULL)
+ cam = cpia2_init_camera_struct(intf);
+ if (cam == NULL)
return -ENOMEM;
cam->dev = udev;
@@ -825,16 +835,9 @@ static int cpia2_usb_probe(struct usb_interface *intf,
return ret;
}
- if ((ret = cpia2_register_camera(cam)) < 0) {
- ERR("%s: Failed to register cpia2 camera (ret = %d)\n", __func__, ret);
- kfree(cam);
- return ret;
- }
-
if((ret = cpia2_init_camera(cam)) < 0) {
ERR("%s: failed to initialize cpia2 camera (ret = %d)\n", __func__, ret);
- cpia2_unregister_camera(cam);
kfree(cam);
return ret;
}
@@ -853,6 +856,13 @@ static int cpia2_usb_probe(struct usb_interface *intf,
usb_set_intfdata(intf, cam);
+ ret = cpia2_register_camera(cam);
+ if (ret < 0) {
+ ERR("%s: Failed to register cpia2 camera (ret = %d)\n", __func__, ret);
+ kfree(cam);
+ return ret;
+ }
+
return 0;
}
@@ -865,13 +875,16 @@ static void cpia2_usb_disconnect(struct usb_interface *intf)
{
struct camera_data *cam = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL);
- cam->present = 0;
DBG("Stopping stream\n");
cpia2_usb_stream_stop(cam);
+ mutex_lock(&cam->v4l2_lock);
DBG("Unregistering camera\n");
cpia2_unregister_camera(cam);
+ v4l2_device_disconnect(&cam->v4l2_dev);
+ mutex_unlock(&cam->v4l2_lock);
+ v4l2_device_put(&cam->v4l2_dev);
if(cam->buffers) {
DBG("Wakeup waiting processes\n");
@@ -884,14 +897,41 @@ static void cpia2_usb_disconnect(struct usb_interface *intf)
DBG("Releasing interface\n");
usb_driver_release_interface(&cpia2_driver, intf);
- if (cam->open_count == 0) {
- DBG("Freeing camera structure\n");
- kfree(cam);
+ LOG("CPiA2 camera disconnected.\n");
+}
+
+static int cpia2_usb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct camera_data *cam = usb_get_intfdata(intf);
+
+ mutex_lock(&cam->v4l2_lock);
+ if (cam->streaming) {
+ cpia2_usb_stream_stop(cam);
+ cam->streaming = 1;
}
+ mutex_unlock(&cam->v4l2_lock);
- LOG("CPiA2 camera disconnected.\n");
+ dev_info(&intf->dev, "going into suspend..\n");
+ return 0;
}
+/* Resume device - start device. */
+static int cpia2_usb_resume(struct usb_interface *intf)
+{
+ struct camera_data *cam = usb_get_intfdata(intf);
+
+ mutex_lock(&cam->v4l2_lock);
+ v4l2_ctrl_handler_setup(&cam->hdl);
+ if (cam->streaming) {
+ cam->streaming = 0;
+ cpia2_usb_stream_start(cam,
+ cam->params.camera_state.stream_mode);
+ }
+ mutex_unlock(&cam->v4l2_lock);
+
+ dev_info(&intf->dev, "coming out of suspend..\n");
+ return 0;
+}
/******************************************************************************
*
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index 077eb1db80a1..55e92902a76c 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -39,15 +39,15 @@
#include <linux/videodev2.h>
#include <linux/stringify.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
#include "cpia2.h"
-#include "cpia2dev.h"
static int video_nr = -1;
module_param(video_nr, int, 0);
-MODULE_PARM_DESC(video_nr,"video device to register (0=/dev/video0, etc)");
+MODULE_PARM_DESC(video_nr, "video device to register (0=/dev/video0, etc)");
-static int buffer_size = 68*1024;
+static int buffer_size = 68 * 1024;
module_param(buffer_size, int, 0);
MODULE_PARM_DESC(buffer_size, "Size for each frame buffer in bytes (default 68k)");
@@ -62,18 +62,10 @@ MODULE_PARM_DESC(alternate, "USB Alternate (" __stringify(USBIF_ISO_1) "-"
__stringify(USBIF_ISO_6) ", default "
__stringify(DEFAULT_ALT) ")");
-static int flicker_freq = 60;
-module_param(flicker_freq, int, 0);
-MODULE_PARM_DESC(flicker_freq, "Flicker frequency (" __stringify(50) "or"
- __stringify(60) ", default "
- __stringify(60) ")");
-
-static int flicker_mode = NEVER_FLICKER;
+static int flicker_mode;
module_param(flicker_mode, int, 0);
-MODULE_PARM_DESC(flicker_mode,
- "Flicker supression (" __stringify(NEVER_FLICKER) "or"
- __stringify(ANTI_FLICKER_ON) ", default "
- __stringify(NEVER_FLICKER) ")");
+MODULE_PARM_DESC(flicker_mode, "Flicker frequency (0 (disabled), " __stringify(50) " or "
+ __stringify(60) ", default 0)");
MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>");
MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras");
@@ -82,153 +74,7 @@ MODULE_LICENSE("GPL");
MODULE_VERSION(CPIA_VERSION);
#define ABOUT "V4L-Driver for Vision CPiA2 based cameras"
-
-struct control_menu_info {
- int value;
- char name[32];
-};
-
-static struct control_menu_info framerate_controls[] =
-{
- { CPIA2_VP_FRAMERATE_6_25, "6.25 fps" },
- { CPIA2_VP_FRAMERATE_7_5, "7.5 fps" },
- { CPIA2_VP_FRAMERATE_12_5, "12.5 fps" },
- { CPIA2_VP_FRAMERATE_15, "15 fps" },
- { CPIA2_VP_FRAMERATE_25, "25 fps" },
- { CPIA2_VP_FRAMERATE_30, "30 fps" },
-};
-#define NUM_FRAMERATE_CONTROLS (ARRAY_SIZE(framerate_controls))
-
-static struct control_menu_info flicker_controls[] =
-{
- { NEVER_FLICKER, "Off" },
- { FLICKER_50, "50 Hz" },
- { FLICKER_60, "60 Hz" },
-};
-#define NUM_FLICKER_CONTROLS (ARRAY_SIZE(flicker_controls))
-
-static struct control_menu_info lights_controls[] =
-{
- { 0, "Off" },
- { 64, "Top" },
- { 128, "Bottom" },
- { 192, "Both" },
-};
-#define NUM_LIGHTS_CONTROLS (ARRAY_SIZE(lights_controls))
-#define GPIO_LIGHTS_MASK 192
-
-static struct v4l2_queryctrl controls[] = {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = DEFAULT_BRIGHTNESS,
- },
- {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = DEFAULT_CONTRAST,
- },
- {
- .id = V4L2_CID_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = DEFAULT_SATURATION,
- },
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Mirror Horizontally",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Flip Vertically",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = CPIA2_CID_TARGET_KB,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Target KB",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = DEFAULT_TARGET_KB,
- },
- {
- .id = CPIA2_CID_GPIO,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "GPIO",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = CPIA2_CID_FLICKER_MODE,
- .type = V4L2_CTRL_TYPE_MENU,
- .name = "Flicker Reduction",
- .minimum = 0,
- .maximum = NUM_FLICKER_CONTROLS-1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = CPIA2_CID_FRAMERATE,
- .type = V4L2_CTRL_TYPE_MENU,
- .name = "Framerate",
- .minimum = 0,
- .maximum = NUM_FRAMERATE_CONTROLS-1,
- .step = 1,
- .default_value = NUM_FRAMERATE_CONTROLS-1,
- },
- {
- .id = CPIA2_CID_USB_ALT,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "USB Alternate",
- .minimum = USBIF_ISO_1,
- .maximum = USBIF_ISO_6,
- .step = 1,
- .default_value = DEFAULT_ALT,
- },
- {
- .id = CPIA2_CID_LIGHTS,
- .type = V4L2_CTRL_TYPE_MENU,
- .name = "Lights",
- .minimum = 0,
- .maximum = NUM_LIGHTS_CONTROLS-1,
- .step = 1,
- .default_value = 0,
- },
- {
- .id = CPIA2_CID_RESET_CAMERA,
- .type = V4L2_CTRL_TYPE_BUTTON,
- .name = "Reset Camera",
- .minimum = 0,
- .maximum = 0,
- .step = 0,
- .default_value = 0,
- },
-};
-#define NUM_CONTROLS (ARRAY_SIZE(controls))
-
+#define CPIA2_CID_USB_ALT (V4L2_CID_USER_BASE | 0xf000)
/******************************************************************************
*
@@ -238,38 +84,27 @@ static struct v4l2_queryctrl controls[] = {
static int cpia2_open(struct file *file)
{
struct camera_data *cam = video_drvdata(file);
- struct cpia2_fh *fh;
-
- if (!cam) {
- ERR("Internal error, camera_data not found!\n");
- return -ENODEV;
- }
+ int retval = v4l2_fh_open(file);
- if (!cam->present)
- return -ENODEV;
+ if (retval)
+ return retval;
- if (cam->open_count == 0) {
- if (cpia2_allocate_buffers(cam))
+ if (v4l2_fh_is_singular_file(file)) {
+ if (cpia2_allocate_buffers(cam)) {
+ v4l2_fh_release(file);
return -ENOMEM;
+ }
/* reset the camera */
- if (cpia2_reset_camera(cam) < 0)
+ if (cpia2_reset_camera(cam) < 0) {
+ v4l2_fh_release(file);
return -EIO;
+ }
cam->APP_len = 0;
cam->COM_len = 0;
}
- fh = kmalloc(sizeof(*fh), GFP_KERNEL);
- if (!fh)
- return -ENOMEM;
- file->private_data = fh;
- fh->prio = V4L2_PRIORITY_UNSET;
- v4l2_prio_open(&cam->prio, &fh->prio);
- fh->mmapped = 0;
-
- ++cam->open_count;
-
cpia2_dbg_dump_registers(cam);
return 0;
}
@@ -283,37 +118,22 @@ static int cpia2_close(struct file *file)
{
struct video_device *dev = video_devdata(file);
struct camera_data *cam = video_get_drvdata(dev);
- struct cpia2_fh *fh = file->private_data;
- if (cam->present &&
- (cam->open_count == 1 || fh->prio == V4L2_PRIORITY_RECORD)) {
+ if (video_is_registered(&cam->vdev) && v4l2_fh_is_singular_file(file)) {
cpia2_usb_stream_stop(cam);
- if (cam->open_count == 1) {
- /* save camera state for later open */
- cpia2_save_camera_state(cam);
+ /* save camera state for later open */
+ cpia2_save_camera_state(cam);
- cpia2_set_low_power(cam);
- cpia2_free_buffers(cam);
- }
+ cpia2_set_low_power(cam);
+ cpia2_free_buffers(cam);
}
- if (fh->mmapped)
+ if (cam->stream_fh == file->private_data) {
+ cam->stream_fh = NULL;
cam->mmapped = 0;
- v4l2_prio_close(&cam->prio, fh->prio);
- file->private_data = NULL;
- kfree(fh);
-
- if (--cam->open_count == 0) {
- cpia2_free_buffers(cam);
- if (!cam->present) {
- video_unregister_device(dev);
- kfree(cam);
- return 0;
- }
}
-
- return 0;
+ return v4l2_fh_release(file);
}
/******************************************************************************
@@ -327,16 +147,9 @@ static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count,
struct camera_data *cam = video_drvdata(file);
int noblock = file->f_flags&O_NONBLOCK;
- struct cpia2_fh *fh = file->private_data;
-
if(!cam)
return -EINVAL;
- /* Priority check */
- if(fh->prio != V4L2_PRIORITY_RECORD) {
- return -EBUSY;
- }
-
return cpia2_read(cam, buf, count, noblock);
}
@@ -349,15 +162,6 @@ static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count,
static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait)
{
struct camera_data *cam = video_drvdata(filp);
- struct cpia2_fh *fh = filp->private_data;
-
- if(!cam)
- return POLLERR;
-
- /* Priority check */
- if(fh->prio != V4L2_PRIORITY_RECORD) {
- return POLLERR;
- }
return cpia2_poll(cam, filp, wait);
}
@@ -384,36 +188,13 @@ static int sync(struct camera_data *cam, int frame_nr)
mutex_lock(&cam->v4l2_lock);
if (signal_pending(current))
return -ERESTARTSYS;
- if(!cam->present)
+ if (!video_is_registered(&cam->vdev))
return -ENOTTY;
}
}
/******************************************************************************
*
- * ioctl_set_gpio
- *
- *****************************************************************************/
-
-static long cpia2_default(struct file *file, void *fh, bool valid_prio,
- int cmd, void *arg)
-{
- struct camera_data *cam = video_drvdata(file);
- __u32 gpio_val;
-
- if (cmd != CPIA2_CID_GPIO)
- return -EINVAL;
-
- gpio_val = *(__u32*) arg;
-
- if (gpio_val &~ 0xFFU)
- return -EINVAL;
-
- return cpia2_set_gpio(cam, (unsigned char)gpio_val);
-}
-
-/******************************************************************************
- *
* ioctl_querycap
*
* V4L2 device capabilities
@@ -465,9 +246,11 @@ static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *v
if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0)
memset(vc->bus_info,0, sizeof(vc->bus_info));
- vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ vc->device_caps = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING;
+ vc->capabilities = vc->device_caps |
+ V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -610,22 +393,12 @@ static int cpia2_s_fmt_vid_cap(struct file *file, void *_fh,
struct v4l2_format *f)
{
struct camera_data *cam = video_drvdata(file);
- struct cpia2_fh *fh = _fh;
int err, frame;
- err = v4l2_prio_check(&cam->prio, fh->prio);
- if (err)
- return err;
err = cpia2_try_fmt_vid_cap(file, _fh, f);
if(err != 0)
return err;
- /* Ensure that only this process can change the format. */
- err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD);
- if(err != 0) {
- return err;
- }
-
cam->pixelformat = f->fmt.pix.pixelformat;
/* NOTE: This should be set to 1 for MJPEG, but some apps don't handle
@@ -713,240 +486,126 @@ static int cpia2_cropcap(struct file *file, void *fh, struct v4l2_cropcap *c)
return 0;
}
-/******************************************************************************
- *
- * ioctl_queryctrl
- *
- * V4L2 query possible control variables
- *
- *****************************************************************************/
+struct framerate_info {
+ int value;
+ struct v4l2_fract period;
+};
-static int cpia2_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c)
+static const struct framerate_info framerate_controls[] = {
+ { CPIA2_VP_FRAMERATE_6_25, { 4, 25 } },
+ { CPIA2_VP_FRAMERATE_7_5, { 2, 15 } },
+ { CPIA2_VP_FRAMERATE_12_5, { 2, 25 } },
+ { CPIA2_VP_FRAMERATE_15, { 1, 15 } },
+ { CPIA2_VP_FRAMERATE_25, { 1, 25 } },
+ { CPIA2_VP_FRAMERATE_30, { 1, 30 } },
+};
+
+static int cpia2_g_parm(struct file *file, void *fh, struct v4l2_streamparm *p)
{
struct camera_data *cam = video_drvdata(file);
+ struct v4l2_captureparm *cap = &p->parm.capture;
int i;
- for(i=0; i<NUM_CONTROLS; ++i) {
- if(c->id == controls[i].id) {
- memcpy(c, controls+i, sizeof(*c));
- break;
- }
- }
-
- if(i == NUM_CONTROLS)
+ if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- /* Some devices have additional limitations */
- switch(c->id) {
- case V4L2_CID_BRIGHTNESS:
- /***
- * Don't let the register be set to zero - bug in VP4
- * flash of full brightness
- ***/
- if (cam->params.pnp_id.device_type == DEVICE_STV_672)
- c->minimum = 1;
- break;
- case V4L2_CID_VFLIP:
- // VP5 Only
- if(cam->params.pnp_id.device_type == DEVICE_STV_672)
- c->flags |= V4L2_CTRL_FLAG_DISABLED;
- break;
- case CPIA2_CID_FRAMERATE:
- if(cam->params.pnp_id.device_type == DEVICE_STV_672 &&
- cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){
- // Maximum 15fps
- for(i=0; i<c->maximum; ++i) {
- if(framerate_controls[i].value ==
- CPIA2_VP_FRAMERATE_15) {
- c->maximum = i;
- c->default_value = i;
- }
- }
+ cap->capability = V4L2_CAP_TIMEPERFRAME;
+ cap->readbuffers = cam->num_frames;
+ for (i = 0; i < ARRAY_SIZE(framerate_controls); i++)
+ if (cam->params.vp_params.frame_rate == framerate_controls[i].value) {
+ cap->timeperframe = framerate_controls[i].period;
+ break;
}
- break;
- case CPIA2_CID_FLICKER_MODE:
- // Flicker control only valid for 672.
- if(cam->params.pnp_id.device_type != DEVICE_STV_672)
- c->flags |= V4L2_CTRL_FLAG_DISABLED;
- break;
- case CPIA2_CID_LIGHTS:
- // Light control only valid for the QX5 Microscope.
- if(cam->params.pnp_id.product != 0x151)
- c->flags |= V4L2_CTRL_FLAG_DISABLED;
- break;
- default:
- break;
- }
-
return 0;
}
-/******************************************************************************
- *
- * ioctl_querymenu
- *
- * V4L2 query possible control variables
- *
- *****************************************************************************/
-
-static int cpia2_querymenu(struct file *file, void *fh, struct v4l2_querymenu *m)
+static int cpia2_s_parm(struct file *file, void *fh, struct v4l2_streamparm *p)
{
struct camera_data *cam = video_drvdata(file);
+ struct v4l2_captureparm *cap = &p->parm.capture;
+ struct v4l2_fract tpf = cap->timeperframe;
+ int max = ARRAY_SIZE(framerate_controls) - 1;
+ int ret;
+ int i;
- switch(m->id) {
- case CPIA2_CID_FLICKER_MODE:
- if (m->index >= NUM_FLICKER_CONTROLS)
- return -EINVAL;
+ ret = cpia2_g_parm(file, fh, p);
+ if (ret || !tpf.denominator || !tpf.numerator)
+ return ret;
+
+ /* Maximum 15 fps for this model */
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+ cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500)
+ max -= 2;
+ for (i = 0; i <= max; i++) {
+ struct v4l2_fract f1 = tpf;
+ struct v4l2_fract f2 = framerate_controls[i].period;
+
+ f1.numerator *= f2.denominator;
+ f2.numerator *= f1.denominator;
+ if (f1.numerator >= f2.numerator)
+ break;
+ }
+ if (i > max)
+ i = max;
+ cap->timeperframe = framerate_controls[i].period;
+ return cpia2_set_fps(cam, framerate_controls[i].value);
+}
- strcpy(m->name, flicker_controls[m->index].name);
- break;
- case CPIA2_CID_FRAMERATE:
- {
- int maximum = NUM_FRAMERATE_CONTROLS - 1;
- if(cam->params.pnp_id.device_type == DEVICE_STV_672 &&
- cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){
- // Maximum 15fps
- int i;
- for(i=0; i<maximum; ++i) {
- if(framerate_controls[i].value ==
- CPIA2_VP_FRAMERATE_15)
- maximum = i;
- }
- }
- if (m->index > maximum)
- return -EINVAL;
+static const struct {
+ u32 width;
+ u32 height;
+} cpia2_framesizes[] = {
+ { 640, 480 },
+ { 352, 288 },
+ { 320, 240 },
+ { 288, 216 },
+ { 256, 192 },
+ { 224, 168 },
+ { 192, 144 },
+ { 176, 144 },
+};
- strcpy(m->name, framerate_controls[m->index].name);
- break;
- }
- case CPIA2_CID_LIGHTS:
- if (m->index >= NUM_LIGHTS_CONTROLS)
- return -EINVAL;
+static int cpia2_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
- strcpy(m->name, lights_controls[m->index].name);
- break;
- default:
+ if (fsize->pixel_format != V4L2_PIX_FMT_MJPEG &&
+ fsize->pixel_format != V4L2_PIX_FMT_JPEG)
return -EINVAL;
- }
+ if (fsize->index >= ARRAY_SIZE(cpia2_framesizes))
+ return -EINVAL;
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ fsize->discrete.width = cpia2_framesizes[fsize->index].width;
+ fsize->discrete.height = cpia2_framesizes[fsize->index].height;
return 0;
}
-/******************************************************************************
- *
- * ioctl_g_ctrl
- *
- * V4L2 get the value of a control variable
- *
- *****************************************************************************/
-
-static int cpia2_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+static int cpia2_enum_frameintervals(struct file *file, void *fh,
+ struct v4l2_frmivalenum *fival)
{
struct camera_data *cam = video_drvdata(file);
+ int max = ARRAY_SIZE(framerate_controls) - 1;
+ int i;
- switch(c->id) {
- case V4L2_CID_BRIGHTNESS:
- cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS,
- TRANSFER_READ, 0);
- c->value = cam->params.color_params.brightness;
- break;
- case V4L2_CID_CONTRAST:
- cpia2_do_command(cam, CPIA2_CMD_GET_CONTRAST,
- TRANSFER_READ, 0);
- c->value = cam->params.color_params.contrast;
- break;
- case V4L2_CID_SATURATION:
- cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION,
- TRANSFER_READ, 0);
- c->value = cam->params.color_params.saturation;
- break;
- case V4L2_CID_HFLIP:
- cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS,
- TRANSFER_READ, 0);
- c->value = (cam->params.vp_params.user_effects &
- CPIA2_VP_USER_EFFECTS_MIRROR) != 0;
- break;
- case V4L2_CID_VFLIP:
- cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS,
- TRANSFER_READ, 0);
- c->value = (cam->params.vp_params.user_effects &
- CPIA2_VP_USER_EFFECTS_FLIP) != 0;
- break;
- case CPIA2_CID_TARGET_KB:
- c->value = cam->params.vc_params.target_kb;
- break;
- case CPIA2_CID_GPIO:
- cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA,
- TRANSFER_READ, 0);
- c->value = cam->params.vp_params.gpio_data;
- break;
- case CPIA2_CID_FLICKER_MODE:
- {
- int i, mode;
- cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES,
- TRANSFER_READ, 0);
- if(cam->params.flicker_control.cam_register &
- CPIA2_VP_FLICKER_MODES_NEVER_FLICKER) {
- mode = NEVER_FLICKER;
- } else {
- if(cam->params.flicker_control.cam_register &
- CPIA2_VP_FLICKER_MODES_50HZ) {
- mode = FLICKER_50;
- } else {
- mode = FLICKER_60;
- }
- }
- for(i=0; i<NUM_FLICKER_CONTROLS; i++) {
- if(flicker_controls[i].value == mode) {
- c->value = i;
- break;
- }
- }
- if(i == NUM_FLICKER_CONTROLS)
- return -EINVAL;
- break;
- }
- case CPIA2_CID_FRAMERATE:
- {
- int maximum = NUM_FRAMERATE_CONTROLS - 1;
- int i;
- for(i=0; i<= maximum; i++) {
- if(cam->params.vp_params.frame_rate ==
- framerate_controls[i].value)
- break;
- }
- if(i > maximum)
- return -EINVAL;
- c->value = i;
- break;
- }
- case CPIA2_CID_USB_ALT:
- c->value = cam->params.camera_state.stream_mode;
- break;
- case CPIA2_CID_LIGHTS:
- {
- int i;
- cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA,
- TRANSFER_READ, 0);
- for(i=0; i<NUM_LIGHTS_CONTROLS; i++) {
- if((cam->params.vp_params.gpio_data&GPIO_LIGHTS_MASK) ==
- lights_controls[i].value) {
- break;
- }
- }
- if(i == NUM_LIGHTS_CONTROLS)
- return -EINVAL;
- c->value = i;
- break;
- }
- case CPIA2_CID_RESET_CAMERA:
+ if (fival->pixel_format != V4L2_PIX_FMT_MJPEG &&
+ fival->pixel_format != V4L2_PIX_FMT_JPEG)
return -EINVAL;
- default:
- return -EINVAL;
- }
-
- DBG("Get control id:%d, value:%d\n", c->id, c->value);
+ /* Maximum 15 fps for this model */
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672 &&
+ cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500)
+ max -= 2;
+ if (fival->index > max)
+ return -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(cpia2_framesizes); i++)
+ if (fival->width == cpia2_framesizes[i].width &&
+ fival->height == cpia2_framesizes[i].height)
+ break;
+ if (i == ARRAY_SIZE(cpia2_framesizes))
+ return -EINVAL;
+ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ fival->discrete = framerate_controls[fival->index].period;
return 0;
}
@@ -958,72 +617,54 @@ static int cpia2_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
*
*****************************************************************************/
-static int cpia2_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+static int cpia2_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct camera_data *cam = video_drvdata(file);
- int i;
- int retval = 0;
+ struct camera_data *cam =
+ container_of(ctrl->handler, struct camera_data, hdl);
+ static const int flicker_table[] = {
+ NEVER_FLICKER,
+ FLICKER_50,
+ FLICKER_60,
+ };
- DBG("Set control id:%d, value:%d\n", c->id, c->value);
-
- /* Check that the value is in range */
- for(i=0; i<NUM_CONTROLS; i++) {
- if(c->id == controls[i].id) {
- if(c->value < controls[i].minimum ||
- c->value > controls[i].maximum) {
- return -EINVAL;
- }
- break;
- }
- }
- if(i == NUM_CONTROLS)
- return -EINVAL;
+ DBG("Set control id:%d, value:%d\n", ctrl->id, ctrl->val);
- switch(c->id) {
+ switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- cpia2_set_brightness(cam, c->value);
+ cpia2_set_brightness(cam, ctrl->val);
break;
case V4L2_CID_CONTRAST:
- cpia2_set_contrast(cam, c->value);
+ cpia2_set_contrast(cam, ctrl->val);
break;
case V4L2_CID_SATURATION:
- cpia2_set_saturation(cam, c->value);
+ cpia2_set_saturation(cam, ctrl->val);
break;
case V4L2_CID_HFLIP:
- cpia2_set_property_mirror(cam, c->value);
+ cpia2_set_property_mirror(cam, ctrl->val);
break;
case V4L2_CID_VFLIP:
- cpia2_set_property_flip(cam, c->value);
+ cpia2_set_property_flip(cam, ctrl->val);
break;
- case CPIA2_CID_TARGET_KB:
- retval = cpia2_set_target_kb(cam, c->value);
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ return cpia2_set_flicker_mode(cam, flicker_table[ctrl->val]);
+ case V4L2_CID_ILLUMINATORS_1:
+ return cpia2_set_gpio(cam, (cam->top_light->val << 6) |
+ (cam->bottom_light->val << 7));
+ case V4L2_CID_JPEG_ACTIVE_MARKER:
+ cam->params.compression.inhibit_htables =
+ !(ctrl->val & V4L2_JPEG_ACTIVE_MARKER_DHT);
break;
- case CPIA2_CID_GPIO:
- retval = cpia2_set_gpio(cam, c->value);
- break;
- case CPIA2_CID_FLICKER_MODE:
- retval = cpia2_set_flicker_mode(cam,
- flicker_controls[c->value].value);
- break;
- case CPIA2_CID_FRAMERATE:
- retval = cpia2_set_fps(cam, framerate_controls[c->value].value);
+ case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+ cam->params.vc_params.quality = ctrl->val;
break;
case CPIA2_CID_USB_ALT:
- retval = cpia2_usb_change_streaming_alternate(cam, c->value);
- break;
- case CPIA2_CID_LIGHTS:
- retval = cpia2_set_gpio(cam, lights_controls[c->value].value);
- break;
- case CPIA2_CID_RESET_CAMERA:
- cpia2_usb_stream_pause(cam);
- cpia2_reset_camera(cam);
- cpia2_usb_stream_resume(cam);
+ cam->params.camera_state.stream_mode = ctrl->val;
break;
default:
- retval = -EINVAL;
+ return -EINVAL;
}
- return retval;
+ return 0;
}
/******************************************************************************
@@ -1084,6 +725,8 @@ static int cpia2_s_jpegcomp(struct file *file, void *fh, struct v4l2_jpegcompres
cam->params.compression.inhibit_htables =
!(parms->jpeg_markers & V4L2_JPEG_MARKER_DHT);
+ parms->jpeg_markers &= V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI |
+ V4L2_JPEG_MARKER_DHT;
if(parms->APP_len != 0) {
if(parms->APP_len > 0 &&
@@ -1270,12 +913,12 @@ static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
struct framebuf *cb=cam->curbuff;
mutex_unlock(&cam->v4l2_lock);
wait_event_interruptible(cam->wq_stream,
- !cam->present ||
+ !video_is_registered(&cam->vdev) ||
(cb=cam->curbuff)->status == FRAME_READY);
mutex_lock(&cam->v4l2_lock);
if (signal_pending(current))
return -ERESTARTSYS;
- if(!cam->present)
+ if (!video_is_registered(&cam->vdev))
return -ENOTTY;
frame = cb->num;
}
@@ -1299,56 +942,39 @@ static int cpia2_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
return 0;
}
-static int cpia2_g_priority(struct file *file, void *_fh, enum v4l2_priority *p)
-{
- struct cpia2_fh *fh = _fh;
-
- *p = fh->prio;
- return 0;
-}
-
-static int cpia2_s_priority(struct file *file, void *_fh, enum v4l2_priority prio)
-{
- struct camera_data *cam = video_drvdata(file);
- struct cpia2_fh *fh = _fh;
-
- if (cam->streaming && prio != fh->prio &&
- fh->prio == V4L2_PRIORITY_RECORD)
- /* Can't drop record priority while streaming */
- return -EBUSY;
-
- if (prio == V4L2_PRIORITY_RECORD && prio != fh->prio &&
- v4l2_prio_max(&cam->prio) == V4L2_PRIORITY_RECORD)
- /* Only one program can record at a time */
- return -EBUSY;
- return v4l2_prio_change(&cam->prio, &fh->prio, prio);
-}
-
static int cpia2_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
{
struct camera_data *cam = video_drvdata(file);
+ int ret = -EINVAL;
DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming);
if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- if (!cam->streaming)
- return cpia2_usb_stream_start(cam,
+ if (!cam->streaming) {
+ ret = cpia2_usb_stream_start(cam,
cam->params.camera_state.stream_mode);
- return -EINVAL;
+ if (!ret)
+ v4l2_ctrl_grab(cam->usb_alt, true);
+ }
+ return ret;
}
static int cpia2_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
{
struct camera_data *cam = video_drvdata(file);
+ int ret = -EINVAL;
DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming);
if (!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- if (cam->streaming)
- return cpia2_usb_stream_stop(cam);
- return -EINVAL;
+ if (cam->streaming) {
+ ret = cpia2_usb_stream_stop(cam);
+ if (!ret)
+ v4l2_ctrl_grab(cam->usb_alt, false);
+ }
+ return ret;
}
/******************************************************************************
@@ -1361,16 +987,10 @@ static int cpia2_mmap(struct file *file, struct vm_area_struct *area)
struct camera_data *cam = video_drvdata(file);
int retval;
- /* Priority check */
- struct cpia2_fh *fh = file->private_data;
- if(fh->prio != V4L2_PRIORITY_RECORD) {
- return -EBUSY;
- }
-
retval = cpia2_remap_buffer(cam, area);
if(!retval)
- fh->mmapped = 1;
+ cam->stream_fh = file->private_data;
return retval;
}
@@ -1388,15 +1008,13 @@ static void reset_camera_struct_v4l(struct camera_data *cam)
cam->frame_size = buffer_size;
cam->num_frames = num_buffers;
- /* FlickerModes */
+ /* Flicker modes */
cam->params.flicker_control.flicker_mode_req = flicker_mode;
- cam->params.flicker_control.mains_frequency = flicker_freq;
- /* streamMode */
+ /* stream modes */
cam->params.camera_state.stream_mode = alternate;
cam->pixelformat = V4L2_PIX_FMT_JPEG;
- v4l2_prio_init(&cam->prio);
}
static const struct v4l2_ioctl_ops cpia2_ioctl_ops = {
@@ -1408,10 +1026,6 @@ static const struct v4l2_ioctl_ops cpia2_ioctl_ops = {
.vidioc_g_fmt_vid_cap = cpia2_g_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = cpia2_s_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = cpia2_try_fmt_vid_cap,
- .vidioc_queryctrl = cpia2_queryctrl,
- .vidioc_querymenu = cpia2_querymenu,
- .vidioc_g_ctrl = cpia2_g_ctrl,
- .vidioc_s_ctrl = cpia2_s_ctrl,
.vidioc_g_jpegcomp = cpia2_g_jpegcomp,
.vidioc_s_jpegcomp = cpia2_s_jpegcomp,
.vidioc_cropcap = cpia2_cropcap,
@@ -1421,9 +1035,12 @@ static const struct v4l2_ioctl_ops cpia2_ioctl_ops = {
.vidioc_dqbuf = cpia2_dqbuf,
.vidioc_streamon = cpia2_streamon,
.vidioc_streamoff = cpia2_streamoff,
- .vidioc_g_priority = cpia2_g_priority,
- .vidioc_s_priority = cpia2_s_priority,
- .vidioc_default = cpia2_default,
+ .vidioc_s_parm = cpia2_s_parm,
+ .vidioc_g_parm = cpia2_g_parm,
+ .vidioc_enum_framesizes = cpia2_enum_framesizes,
+ .vidioc_enum_frameintervals = cpia2_enum_frameintervals,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
/***
@@ -1444,7 +1061,21 @@ static struct video_device cpia2_template = {
.name = "CPiA2 Camera",
.fops = &cpia2_fops,
.ioctl_ops = &cpia2_ioctl_ops,
- .release = video_device_release,
+ .release = video_device_release_empty,
+};
+
+void cpia2_camera_release(struct v4l2_device *v4l2_dev)
+{
+ struct camera_data *cam =
+ container_of(v4l2_dev, struct camera_data, v4l2_dev);
+
+ v4l2_ctrl_handler_free(&cam->hdl);
+ v4l2_device_unregister(&cam->v4l2_dev);
+ kfree(cam);
+}
+
+static const struct v4l2_ctrl_ops cpia2_ctrl_ops = {
+ .s_ctrl = cpia2_s_ctrl,
};
/******************************************************************************
@@ -1454,20 +1085,78 @@ static struct video_device cpia2_template = {
*****************************************************************************/
int cpia2_register_camera(struct camera_data *cam)
{
- cam->vdev = video_device_alloc();
- if(!cam->vdev)
- return -ENOMEM;
+ struct v4l2_ctrl_handler *hdl = &cam->hdl;
+ struct v4l2_ctrl_config cpia2_usb_alt = {
+ .ops = &cpia2_ctrl_ops,
+ .id = CPIA2_CID_USB_ALT,
+ .name = "USB Alternate",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = USBIF_ISO_1,
+ .max = USBIF_ISO_6,
+ .step = 1,
+ };
+ int ret;
+
+ v4l2_ctrl_handler_init(hdl, 12);
+ v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+ V4L2_CID_BRIGHTNESS,
+ cam->params.pnp_id.device_type == DEVICE_STV_672 ? 1 : 0,
+ 255, 1, DEFAULT_BRIGHTNESS);
+ v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1, DEFAULT_CONTRAST);
+ v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 255, 1, DEFAULT_SATURATION);
+ v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+ V4L2_CID_JPEG_ACTIVE_MARKER, 0,
+ V4L2_JPEG_ACTIVE_MARKER_DHT, 0,
+ V4L2_JPEG_ACTIVE_MARKER_DHT);
+ v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+ V4L2_CID_JPEG_COMPRESSION_QUALITY, 1,
+ 100, 1, 100);
+ cpia2_usb_alt.def = alternate;
+ cam->usb_alt = v4l2_ctrl_new_custom(hdl, &cpia2_usb_alt, NULL);
+ /* VP5 Only */
+ if (cam->params.pnp_id.device_type != DEVICE_STV_672)
+ v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ /* Flicker control only valid for 672 */
+ if (cam->params.pnp_id.device_type == DEVICE_STV_672)
+ v4l2_ctrl_new_std_menu(hdl, &cpia2_ctrl_ops,
+ V4L2_CID_POWER_LINE_FREQUENCY,
+ V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0, 0);
+ /* Light control only valid for the QX5 Microscope */
+ if (cam->params.pnp_id.product == 0x151) {
+ cam->top_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+ V4L2_CID_ILLUMINATORS_1, 0, 1, 1, 0);
+ cam->bottom_light = v4l2_ctrl_new_std(hdl, &cpia2_ctrl_ops,
+ V4L2_CID_ILLUMINATORS_2, 0, 1, 1, 0);
+ v4l2_ctrl_cluster(2, &cam->top_light);
+ }
- memcpy(cam->vdev, &cpia2_template, sizeof(cpia2_template));
- video_set_drvdata(cam->vdev, cam);
- cam->vdev->lock = &cam->v4l2_lock;
+ if (hdl->error) {
+ ret = hdl->error;
+ v4l2_ctrl_handler_free(hdl);
+ return ret;
+ }
+
+ cam->vdev = cpia2_template;
+ video_set_drvdata(&cam->vdev, cam);
+ cam->vdev.lock = &cam->v4l2_lock;
+ cam->vdev.ctrl_handler = hdl;
+ cam->vdev.v4l2_dev = &cam->v4l2_dev;
+ set_bit(V4L2_FL_USE_FH_PRIO, &cam->vdev.flags);
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &cam->vdev.flags);
reset_camera_struct_v4l(cam);
/* register v4l device */
- if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
+ if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
ERR("video_register_device failed\n");
- video_device_release(cam->vdev);
return -ENODEV;
}
@@ -1481,13 +1170,7 @@ int cpia2_register_camera(struct camera_data *cam)
*****************************************************************************/
void cpia2_unregister_camera(struct camera_data *cam)
{
- if (!cam->open_count) {
- video_unregister_device(cam->vdev);
- } else {
- LOG("%s removed while open, deferring "
- "video_unregister_device\n",
- video_device_node_name(cam->vdev));
- }
+ video_unregister_device(&cam->vdev);
}
/******************************************************************************
@@ -1524,23 +1207,12 @@ static void __init check_parameters(void)
LOG("alternate specified is invalid, using %d\n", alternate);
}
- if (flicker_mode != NEVER_FLICKER && flicker_mode != ANTI_FLICKER_ON) {
- flicker_mode = NEVER_FLICKER;
+ if (flicker_mode != 0 && flicker_mode != FLICKER_50 && flicker_mode != FLICKER_60) {
+ flicker_mode = 0;
LOG("Flicker mode specified is invalid, using %d\n",
flicker_mode);
}
- if (flicker_freq != FLICKER_50 && flicker_freq != FLICKER_60) {
- flicker_freq = FLICKER_60;
- LOG("Flicker mode specified is invalid, using %d\n",
- flicker_freq);
- }
-
- if(video_nr < -1 || video_nr > 64) {
- video_nr = -1;
- LOG("invalid video_nr specified, must be -1 to 64\n");
- }
-
DBG("Using %d buffers, each %d bytes, alternate=%d\n",
num_buffers, buffer_size, alternate);
}
diff --git a/drivers/media/video/cpia2/cpia2dev.h b/drivers/media/video/cpia2/cpia2dev.h
deleted file mode 100644
index f66691fe5a35..000000000000
--- a/drivers/media/video/cpia2/cpia2dev.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/****************************************************************************
- *
- * Filename: cpia2dev.h
- *
- * Copyright 2001, STMicrolectronics, Inc.
- *
- * Contact: steve.miller@st.com
- *
- * Description:
- * This file provides definitions for applications wanting to use the
- * cpia2 driver beyond the generic v4l capabilities.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- ****************************************************************************/
-
-#ifndef CPIA2_DEV_HEADER
-#define CPIA2_DEV_HEADER
-
-#include <linux/videodev2.h>
-
-/***
- * The following defines are ioctl numbers based on video4linux private ioctls,
- * which can range from 192 (BASE_VIDIOCPRIVATE) to 255. All of these take int
- * args
- */
-#define CPIA2_IOC_SET_GPIO _IOW('v', BASE_VIDIOC_PRIVATE + 17, __u32)
-
-/* V4L2 driver specific controls */
-#define CPIA2_CID_TARGET_KB (V4L2_CID_PRIVATE_BASE+0)
-#define CPIA2_CID_GPIO (V4L2_CID_PRIVATE_BASE+1)
-#define CPIA2_CID_FLICKER_MODE (V4L2_CID_PRIVATE_BASE+2)
-#define CPIA2_CID_FRAMERATE (V4L2_CID_PRIVATE_BASE+3)
-#define CPIA2_CID_USB_ALT (V4L2_CID_PRIVATE_BASE+4)
-#define CPIA2_CID_LIGHTS (V4L2_CID_PRIVATE_BASE+5)
-#define CPIA2_CID_RESET_CAMERA (V4L2_CID_PRIVATE_BASE+6)
-
-#endif
diff --git a/drivers/media/video/cx18/cx18-alsa-main.c b/drivers/media/video/cx18/cx18-alsa-main.c
index e118361c2e7b..6d2a98246b6d 100644
--- a/drivers/media/video/cx18/cx18-alsa-main.c
+++ b/drivers/media/video/cx18/cx18-alsa-main.c
@@ -285,6 +285,7 @@ static void __exit cx18_alsa_exit(void)
drv = driver_find("cx18", &pci_bus_type);
ret = driver_for_each_device(drv, NULL, NULL, cx18_alsa_exit_callback);
+ (void)ret; /* suppress compiler warning */
cx18_ext_init = NULL;
printk(KERN_INFO "cx18-alsa: module unload complete\n");
diff --git a/drivers/media/video/cx18/cx18-alsa-pcm.c b/drivers/media/video/cx18/cx18-alsa-pcm.c
index 82d195be9197..7a5b84a86bb3 100644
--- a/drivers/media/video/cx18/cx18-alsa-pcm.c
+++ b/drivers/media/video/cx18/cx18-alsa-pcm.c
@@ -190,7 +190,7 @@ static int snd_cx18_pcm_capture_open(struct snd_pcm_substream *substream)
ret = cx18_start_v4l2_encode_stream(s);
snd_cx18_unlock(cxsc);
- return 0;
+ return ret;
}
static int snd_cx18_pcm_capture_close(struct snd_pcm_substream *substream)
@@ -199,12 +199,11 @@ static int snd_cx18_pcm_capture_close(struct snd_pcm_substream *substream)
struct v4l2_device *v4l2_dev = cxsc->v4l2_dev;
struct cx18 *cx = to_cx18(v4l2_dev);
struct cx18_stream *s;
- int ret;
/* Instruct the cx18 to stop sending packets */
snd_cx18_lock(cxsc);
s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM];
- ret = cx18_stop_v4l2_encode_stream(s, 0);
+ cx18_stop_v4l2_encode_stream(s, 0);
clear_bit(CX18_F_S_STREAMING, &s->s_flags);
cx18_release_stream(s);
@@ -252,13 +251,10 @@ static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
static int snd_cx18_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- int ret;
-
dprintk("%s called\n", __func__);
- ret = snd_pcm_alloc_vmalloc_buffer(substream,
+ return snd_pcm_alloc_vmalloc_buffer(substream,
params_buffer_bytes(params));
- return 0;
}
static int snd_cx18_pcm_hw_free(struct snd_pcm_substream *substream)
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index be49f68ddf37..35fde4e931f5 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -1137,7 +1137,7 @@ static long cx18_default(struct file *file, void *fh, bool valid_prio,
}
default:
- return -EINVAL;
+ return -ENOTTY;
}
return 0;
}
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
index 0c7796e76ac0..ed8118390b02 100644
--- a/drivers/media/video/cx18/cx18-mailbox.c
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -595,9 +595,8 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
{
const struct cx18_api_info *info = find_api_info(cmd);
- u32 state, irq, req, ack, err;
+ u32 irq, req, ack, err;
struct cx18_mailbox __iomem *mb;
- u32 __iomem *xpu_state;
wait_queue_head_t *waitq;
struct mutex *mb_lock;
unsigned long int t0, timeout, ret;
@@ -628,14 +627,12 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
mb_lock = &cx->epu2apu_mb_lock;
irq = IRQ_EPU_TO_APU;
mb = &cx->scb->epu2apu_mb;
- xpu_state = &cx->scb->apu_state;
break;
case CPU:
waitq = &cx->mb_cpu_waitq;
mb_lock = &cx->epu2cpu_mb_lock;
irq = IRQ_EPU_TO_CPU;
mb = &cx->scb->epu2cpu_mb;
- xpu_state = &cx->scb->cpu_state;
break;
default:
CX18_WARN("Unknown RPU (%d) for API call\n", info->rpu);
@@ -653,7 +650,6 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
* by a signal, we may get here and find a busy mailbox. After waiting,
* mark it "not busy" from our end, if the XPU hasn't ack'ed it still.
*/
- state = cx18_readl(cx, xpu_state);
req = cx18_readl(cx, &mb->request);
timeout = msecs_to_jiffies(10);
ret = wait_event_timeout(*waitq,
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index 638cca156b58..4185bcb80ca3 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -980,7 +980,6 @@ void cx18_stop_all_captures(struct cx18 *cx)
int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
{
struct cx18 *cx = s->cx;
- unsigned long then;
if (!cx18_stream_enabled(s))
return -EINVAL;
@@ -999,8 +998,6 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
else
cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle);
- then = jiffies;
-
if (s->type == CX18_ENC_STREAM_TYPE_MPG && gop_end) {
CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n");
}
diff --git a/drivers/media/video/cx231xx/cx231xx-417.c b/drivers/media/video/cx231xx/cx231xx-417.c
index d4327dab5a36..ce2f62238a19 100644
--- a/drivers/media/video/cx231xx/cx231xx-417.c
+++ b/drivers/media/video/cx231xx/cx231xx-417.c
@@ -1095,7 +1095,7 @@ static int cx231xx_initialize_codec(struct cx231xx *dev)
{
int version;
int retval;
- u32 i, data[7];
+ u32 i;
u32 val = 0;
dprintk(1, "%s()\n", __func__);
@@ -1154,6 +1154,11 @@ static int cx231xx_initialize_codec(struct cx231xx *dev)
CX231xx_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0);
*/
+
+#if 0
+ /* TODO */
+ u32 data[7];
+
/* Setup to capture VBI */
data[0] = 0x0001BD00;
data[1] = 1; /* frames per interrupt */
@@ -1162,7 +1167,7 @@ static int cx231xx_initialize_codec(struct cx231xx *dev)
data[4] = 0x206080C0; /* stop codes */
data[5] = 6; /* lines */
data[6] = 64; /* BPL */
-/*
+
cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1],
data[2], data[3], data[4], data[5], data[6]);
@@ -1175,7 +1180,7 @@ static int cx231xx_initialize_codec(struct cx231xx *dev)
cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0,
i | 0x80000000, valid, 0, 0, 0);
}
-*/
+#endif
/* cx231xx_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX231xx_UNMUTE);
msleep(60);
*/
@@ -1792,17 +1797,16 @@ static int vidioc_streamon(struct file *file, void *priv,
struct cx231xx_fh *fh = file->private_data;
struct cx231xx *dev = fh->dev;
- int rc = 0;
dprintk(3, "enter vidioc_streamon()\n");
cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
- rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+ cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
if (dev->USE_ISO)
- rc = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
+ cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
CX231XX_NUM_BUFS,
dev->video_mode.max_pkt_size,
cx231xx_isoc_copy);
else {
- rc = cx231xx_init_bulk(dev, 320,
+ cx231xx_init_bulk(dev, 320,
5,
dev->ts1_mode.max_pkt_size,
cx231xx_bulk_copy);
diff --git a/drivers/media/video/cx231xx/cx231xx-audio.c b/drivers/media/video/cx231xx/cx231xx-audio.c
index a2c2b7d343ec..068f78dc5d13 100644
--- a/drivers/media/video/cx231xx/cx231xx-audio.c
+++ b/drivers/media/video/cx231xx/cx231xx-audio.c
@@ -523,21 +523,24 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
static int snd_cx231xx_hw_capture_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
- unsigned int channels, rate, format;
int ret;
dprintk("Setting capture parameters\n");
ret = snd_pcm_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
+#if 0
+ /* TODO: set up cx231xx audio chip to deliver the correct audio format,
+ current default is 48000hz multiplexed => 96000hz mono
+ which shouldn't matter since analogue TV only supports mono */
+ unsigned int channels, rate, format;
+
format = params_format(hw_params);
rate = params_rate(hw_params);
channels = params_channels(hw_params);
+#endif
- /* TODO: set up cx231xx audio chip to deliver the correct audio format,
- current default is 48000hz multiplexed => 96000hz mono
- which shouldn't matter since analogue TV only supports mono */
- return 0;
+ return ret;
}
static int snd_cx231xx_hw_capture_free(struct snd_pcm_substream *substream)
@@ -586,7 +589,7 @@ static int snd_cx231xx_capture_trigger(struct snd_pcm_substream *substream,
int cmd)
{
struct cx231xx *dev = snd_pcm_substream_chip(substream);
- int retval;
+ int retval = 0;
if (dev->state & DEV_DISCONNECTED)
return -ENODEV;
@@ -601,12 +604,13 @@ static int snd_cx231xx_capture_trigger(struct snd_pcm_substream *substream,
break;
default:
retval = -EINVAL;
+ break;
}
spin_unlock(&dev->adev.slock);
schedule_work(&dev->wq_trigger);
- return 0;
+ return retval;
}
static snd_pcm_uframes_t snd_cx231xx_capture_pointer(struct snd_pcm_substream
diff --git a/drivers/media/video/cx231xx/cx231xx-avcore.c b/drivers/media/video/cx231xx/cx231xx-avcore.c
index 53ff26e7abf7..b085a3c6dc04 100644
--- a/drivers/media/video/cx231xx/cx231xx-avcore.c
+++ b/drivers/media/video/cx231xx/cx231xx-avcore.c
@@ -934,33 +934,29 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev,
void cx231xx_enable656(struct cx231xx *dev)
{
u8 temp = 0;
- int status;
/*enable TS1 data[0:7] as output to export 656*/
- status = vid_blk_write_byte(dev, TS1_PIN_CTL0, 0xFF);
+ vid_blk_write_byte(dev, TS1_PIN_CTL0, 0xFF);
/*enable TS1 clock as output to export 656*/
- status = vid_blk_read_byte(dev, TS1_PIN_CTL1, &temp);
+ vid_blk_read_byte(dev, TS1_PIN_CTL1, &temp);
temp = temp|0x04;
- status = vid_blk_write_byte(dev, TS1_PIN_CTL1, temp);
-
+ vid_blk_write_byte(dev, TS1_PIN_CTL1, temp);
}
EXPORT_SYMBOL_GPL(cx231xx_enable656);
void cx231xx_disable656(struct cx231xx *dev)
{
u8 temp = 0;
- int status;
-
- status = vid_blk_write_byte(dev, TS1_PIN_CTL0, 0x00);
+ vid_blk_write_byte(dev, TS1_PIN_CTL0, 0x00);
- status = vid_blk_read_byte(dev, TS1_PIN_CTL1, &temp);
+ vid_blk_read_byte(dev, TS1_PIN_CTL1, &temp);
temp = temp&0xFB;
- status = vid_blk_write_byte(dev, TS1_PIN_CTL1, temp);
+ vid_blk_write_byte(dev, TS1_PIN_CTL1, temp);
}
EXPORT_SYMBOL_GPL(cx231xx_disable656);
@@ -1320,117 +1316,115 @@ void update_HH_register_after_set_DIF(struct cx231xx *dev)
void cx231xx_dump_HH_reg(struct cx231xx *dev)
{
- u8 status = 0;
u32 value = 0;
u16 i = 0;
value = 0x45005390;
- status = vid_blk_write_word(dev, 0x104, value);
+ vid_blk_write_word(dev, 0x104, value);
for (i = 0x100; i < 0x140; i++) {
- status = vid_blk_read_word(dev, i, &value);
+ vid_blk_read_word(dev, i, &value);
cx231xx_info("reg0x%x=0x%x\n", i, value);
i = i+3;
}
for (i = 0x300; i < 0x400; i++) {
- status = vid_blk_read_word(dev, i, &value);
+ vid_blk_read_word(dev, i, &value);
cx231xx_info("reg0x%x=0x%x\n", i, value);
i = i+3;
}
for (i = 0x400; i < 0x440; i++) {
- status = vid_blk_read_word(dev, i, &value);
+ vid_blk_read_word(dev, i, &value);
cx231xx_info("reg0x%x=0x%x\n", i, value);
i = i+3;
}
- status = vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
+ vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
cx231xx_info("AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value);
vid_blk_write_word(dev, AFE_CTRL_C2HH_SRC_CTRL, 0x4485D390);
- status = vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
+ vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
cx231xx_info("AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value);
}
void cx231xx_dump_SC_reg(struct cx231xx *dev)
{
u8 value[4] = { 0, 0, 0, 0 };
- int status = 0;
cx231xx_info("cx231xx_dump_SC_reg!\n");
- status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT,
+ cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT,
value, 4);
cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", BOARD_CFG_STAT, value[0],
value[1], value[2], value[3]);
- status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS_MODE_REG,
+ cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS_MODE_REG,
value, 4);
cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS_MODE_REG, value[0],
value[1], value[2], value[3]);
- status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS1_CFG_REG,
+ cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS1_CFG_REG,
value, 4);
cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS1_CFG_REG, value[0],
value[1], value[2], value[3]);
- status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS1_LENGTH_REG,
+ cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS1_LENGTH_REG,
value, 4);
cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS1_LENGTH_REG, value[0],
value[1], value[2], value[3]);
- status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS2_CFG_REG,
+ cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS2_CFG_REG,
value, 4);
cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS2_CFG_REG, value[0],
value[1], value[2], value[3]);
- status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS2_LENGTH_REG,
+ cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS2_LENGTH_REG,
value, 4);
cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS2_LENGTH_REG, value[0],
value[1], value[2], value[3]);
- status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, EP_MODE_SET,
+ cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, EP_MODE_SET,
value, 4);
cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", EP_MODE_SET, value[0],
value[1], value[2], value[3]);
- status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN1,
+ cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN1,
value, 4);
cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN1, value[0],
value[1], value[2], value[3]);
- status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN2,
+ cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN2,
value, 4);
cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN2, value[0],
value[1], value[2], value[3]);
- status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN3,
+ cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN3,
value, 4);
cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN3, value[0],
value[1], value[2], value[3]);
- status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK0,
+ cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK0,
value, 4);
cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK0, value[0],
value[1], value[2], value[3]);
- status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK1,
+ cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK1,
value, 4);
cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK1, value[0],
value[1], value[2], value[3]);
- status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK2,
+ cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK2,
value, 4);
cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK2, value[0],
value[1], value[2], value[3]);
- status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_GAIN,
+ cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_GAIN,
value, 4);
cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_GAIN, value[0],
value[1], value[2], value[3]);
- status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_CAR_REG,
+ cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_CAR_REG,
value, 4);
cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_CAR_REG, value[0],
value[1], value[2], value[3]);
- status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_OT_CFG1,
+ cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_OT_CFG1,
value, 4);
cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_OT_CFG1, value[0],
value[1], value[2], value[3]);
- status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_OT_CFG2,
+ cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_OT_CFG2,
value, 4);
cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_OT_CFG2, value[0],
value[1], value[2], value[3]);
- status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN,
+ cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN,
value, 4);
cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", PWR_CTL_EN, value[0],
value[1], value[2], value[3]);
@@ -1441,18 +1435,15 @@ void cx231xx_dump_SC_reg(struct cx231xx *dev)
void cx231xx_Setup_AFE_for_LowIF(struct cx231xx *dev)
{
- u8 status = 0;
u8 value = 0;
-
-
- status = afe_read_byte(dev, ADC_STATUS2_CH3, &value);
+ afe_read_byte(dev, ADC_STATUS2_CH3, &value);
value = (value & 0xFE)|0x01;
- status = afe_write_byte(dev, ADC_STATUS2_CH3, value);
+ afe_write_byte(dev, ADC_STATUS2_CH3, value);
- status = afe_read_byte(dev, ADC_STATUS2_CH3, &value);
+ afe_read_byte(dev, ADC_STATUS2_CH3, &value);
value = (value & 0xFE)|0x00;
- status = afe_write_byte(dev, ADC_STATUS2_CH3, value);
+ afe_write_byte(dev, ADC_STATUS2_CH3, value);
/*
@@ -1464,44 +1455,43 @@ void cx231xx_Setup_AFE_for_LowIF(struct cx231xx *dev)
for low-if agc defect
*/
- status = afe_read_byte(dev, ADC_NTF_PRECLMP_EN_CH3, &value);
+ afe_read_byte(dev, ADC_NTF_PRECLMP_EN_CH3, &value);
value = (value & 0xFC)|0x00;
- status = afe_write_byte(dev, ADC_NTF_PRECLMP_EN_CH3, value);
+ afe_write_byte(dev, ADC_NTF_PRECLMP_EN_CH3, value);
- status = afe_read_byte(dev, ADC_INPUT_CH3, &value);
+ afe_read_byte(dev, ADC_INPUT_CH3, &value);
value = (value & 0xF9)|0x02;
- status = afe_write_byte(dev, ADC_INPUT_CH3, value);
+ afe_write_byte(dev, ADC_INPUT_CH3, value);
- status = afe_read_byte(dev, ADC_FB_FRCRST_CH3, &value);
+ afe_read_byte(dev, ADC_FB_FRCRST_CH3, &value);
value = (value & 0xFB)|0x04;
- status = afe_write_byte(dev, ADC_FB_FRCRST_CH3, value);
+ afe_write_byte(dev, ADC_FB_FRCRST_CH3, value);
- status = afe_read_byte(dev, ADC_DCSERVO_DEM_CH3, &value);
+ afe_read_byte(dev, ADC_DCSERVO_DEM_CH3, &value);
value = (value & 0xFC)|0x03;
- status = afe_write_byte(dev, ADC_DCSERVO_DEM_CH3, value);
+ afe_write_byte(dev, ADC_DCSERVO_DEM_CH3, value);
- status = afe_read_byte(dev, ADC_CTRL_DAC1_CH3, &value);
+ afe_read_byte(dev, ADC_CTRL_DAC1_CH3, &value);
value = (value & 0xFB)|0x04;
- status = afe_write_byte(dev, ADC_CTRL_DAC1_CH3, value);
+ afe_write_byte(dev, ADC_CTRL_DAC1_CH3, value);
- status = afe_read_byte(dev, ADC_CTRL_DAC23_CH3, &value);
+ afe_read_byte(dev, ADC_CTRL_DAC23_CH3, &value);
value = (value & 0xF8)|0x06;
- status = afe_write_byte(dev, ADC_CTRL_DAC23_CH3, value);
+ afe_write_byte(dev, ADC_CTRL_DAC23_CH3, value);
- status = afe_read_byte(dev, ADC_CTRL_DAC23_CH3, &value);
+ afe_read_byte(dev, ADC_CTRL_DAC23_CH3, &value);
value = (value & 0x8F)|0x40;
- status = afe_write_byte(dev, ADC_CTRL_DAC23_CH3, value);
+ afe_write_byte(dev, ADC_CTRL_DAC23_CH3, value);
- status = afe_read_byte(dev, ADC_PWRDN_CLAMP_CH3, &value);
+ afe_read_byte(dev, ADC_PWRDN_CLAMP_CH3, &value);
value = (value & 0xDF)|0x20;
- status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, value);
+ afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, value);
}
void cx231xx_set_Colibri_For_LowIF(struct cx231xx *dev, u32 if_freq,
u8 spectral_invert, u32 mode)
{
u32 colibri_carrier_offset = 0;
- u8 status = 0;
u32 func_mode = 0x01; /* Device has a DIF if this function is called */
u32 standard = 0;
u8 value[4] = { 0, 0, 0, 0 };
@@ -1511,15 +1501,15 @@ void cx231xx_set_Colibri_For_LowIF(struct cx231xx *dev, u32 if_freq,
value[1] = (u8) 0x6F;
value[2] = (u8) 0x6F;
value[3] = (u8) 0x6F;
- status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
PWR_CTL_EN, value, 4);
/*Set colibri for low IF*/
- status = cx231xx_afe_set_mode(dev, AFE_MODE_LOW_IF);
+ cx231xx_afe_set_mode(dev, AFE_MODE_LOW_IF);
/* Set C2HH for low IF operation.*/
standard = dev->norm;
- status = cx231xx_dif_configure_C2HH_for_low_IF(dev, dev->active_mode,
+ cx231xx_dif_configure_C2HH_for_low_IF(dev, dev->active_mode,
func_mode, standard);
/* Get colibri offsets.*/
@@ -1556,7 +1546,6 @@ void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq,
u8 spectral_invert, u32 mode)
{
unsigned long pll_freq_word;
- int status = 0;
u32 dif_misc_ctrl_value = 0;
u64 pll_freq_u64 = 0;
u32 i = 0;
@@ -1567,7 +1556,7 @@ void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq,
if (mode == TUNER_MODE_FM_RADIO) {
pll_freq_word = 0x905A1CAC;
- status = vid_blk_write_word(dev, DIF_PLL_FREQ_WORD, pll_freq_word);
+ vid_blk_write_word(dev, DIF_PLL_FREQ_WORD, pll_freq_word);
} else /*KSPROPERTY_TUNER_MODE_TV*/{
/* Calculate the PLL frequency word based on the adjusted if_freq*/
@@ -1576,23 +1565,23 @@ void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq,
do_div(pll_freq_u64, 50000000);
pll_freq_word = (u32)pll_freq_u64;
/*pll_freq_word = 0x3463497;*/
- status = vid_blk_write_word(dev, DIF_PLL_FREQ_WORD, pll_freq_word);
+ vid_blk_write_word(dev, DIF_PLL_FREQ_WORD, pll_freq_word);
if (spectral_invert) {
if_freq -= 400000;
/* Enable Spectral Invert*/
- status = vid_blk_read_word(dev, DIF_MISC_CTRL,
+ vid_blk_read_word(dev, DIF_MISC_CTRL,
&dif_misc_ctrl_value);
dif_misc_ctrl_value = dif_misc_ctrl_value | 0x00200000;
- status = vid_blk_write_word(dev, DIF_MISC_CTRL,
+ vid_blk_write_word(dev, DIF_MISC_CTRL,
dif_misc_ctrl_value);
} else {
if_freq += 400000;
/* Disable Spectral Invert*/
- status = vid_blk_read_word(dev, DIF_MISC_CTRL,
+ vid_blk_read_word(dev, DIF_MISC_CTRL,
&dif_misc_ctrl_value);
dif_misc_ctrl_value = dif_misc_ctrl_value & 0xFFDFFFFF;
- status = vid_blk_write_word(dev, DIF_MISC_CTRL,
+ vid_blk_write_word(dev, DIF_MISC_CTRL,
dif_misc_ctrl_value);
}
@@ -1606,10 +1595,10 @@ void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq,
}
cx231xx_info("Enter IF=%zd\n",
- sizeof(Dif_set_array)/sizeof(struct dif_settings));
- for (i = 0; i < sizeof(Dif_set_array)/sizeof(struct dif_settings); i++) {
+ ARRAY_SIZE(Dif_set_array));
+ for (i = 0; i < ARRAY_SIZE(Dif_set_array); i++) {
if (Dif_set_array[i].if_freq == if_freq) {
- status = vid_blk_write_word(dev,
+ vid_blk_write_word(dev,
Dif_set_array[i].register_address, Dif_set_array[i].value);
}
}
@@ -3090,31 +3079,30 @@ int cx231xx_gpio_i2c_read(struct cx231xx *dev, u8 dev_addr, u8 *buf, u8 len)
*/
int cx231xx_gpio_i2c_write(struct cx231xx *dev, u8 dev_addr, u8 *buf, u8 len)
{
- int status = 0;
int i = 0;
/* get the lock */
mutex_lock(&dev->gpio_i2c_lock);
/* start */
- status = cx231xx_gpio_i2c_start(dev);
+ cx231xx_gpio_i2c_start(dev);
/* write dev_addr */
- status = cx231xx_gpio_i2c_write_byte(dev, dev_addr << 1);
+ cx231xx_gpio_i2c_write_byte(dev, dev_addr << 1);
/* read Ack */
- status = cx231xx_gpio_i2c_read_ack(dev);
+ cx231xx_gpio_i2c_read_ack(dev);
for (i = 0; i < len; i++) {
/* Write data */
- status = cx231xx_gpio_i2c_write_byte(dev, buf[i]);
+ cx231xx_gpio_i2c_write_byte(dev, buf[i]);
/* read Ack */
- status = cx231xx_gpio_i2c_read_ack(dev);
+ cx231xx_gpio_i2c_read_ack(dev);
}
/* write End */
- status = cx231xx_gpio_i2c_end(dev);
+ cx231xx_gpio_i2c_end(dev);
/* release the lock */
mutex_unlock(&dev->gpio_i2c_lock);
diff --git a/drivers/media/video/cx231xx/cx231xx-core.c b/drivers/media/video/cx231xx/cx231xx-core.c
index 08dd930f882a..05358d486135 100644
--- a/drivers/media/video/cx231xx/cx231xx-core.c
+++ b/drivers/media/video/cx231xx/cx231xx-core.c
@@ -754,7 +754,7 @@ int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode)
}
}
- return 0;
+ return errCode ? -EINVAL : 0;
}
EXPORT_SYMBOL_GPL(cx231xx_set_mode);
@@ -764,7 +764,7 @@ int cx231xx_ep5_bulkout(struct cx231xx *dev, u8 *firmware, u16 size)
int actlen, ret = -ENOMEM;
u32 *buffer;
-buffer = kzalloc(4096, GFP_KERNEL);
+ buffer = kzalloc(4096, GFP_KERNEL);
if (buffer == NULL) {
cx231xx_info("out of mem\n");
return -ENOMEM;
@@ -772,16 +772,16 @@ buffer = kzalloc(4096, GFP_KERNEL);
memcpy(&buffer[0], firmware, 4096);
ret = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 5),
- buffer, 4096, &actlen, 2000);
+ buffer, 4096, &actlen, 2000);
if (ret)
cx231xx_info("bulk message failed: %d (%d/%d)", ret,
- size, actlen);
+ size, actlen);
else {
errCode = actlen != size ? -1 : 0;
}
-kfree(buffer);
- return 0;
+ kfree(buffer);
+ return errCode;
}
/*****************************************************************
@@ -797,7 +797,7 @@ static void cx231xx_isoc_irq_callback(struct urb *urb)
struct cx231xx_video_mode *vmode =
container_of(dma_q, struct cx231xx_video_mode, vidq);
struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode);
- int rc, i;
+ int i;
switch (urb->status) {
case 0: /* success */
@@ -814,7 +814,7 @@ static void cx231xx_isoc_irq_callback(struct urb *urb)
/* Copy data from URB */
spin_lock(&dev->video_mode.slock);
- rc = dev->video_mode.isoc_ctl.isoc_copy(dev, urb);
+ dev->video_mode.isoc_ctl.isoc_copy(dev, urb);
spin_unlock(&dev->video_mode.slock);
/* Reset urb buffers */
@@ -822,7 +822,6 @@ static void cx231xx_isoc_irq_callback(struct urb *urb)
urb->iso_frame_desc[i].status = 0;
urb->iso_frame_desc[i].actual_length = 0;
}
- urb->status = 0;
urb->status = usb_submit_urb(urb, GFP_ATOMIC);
if (urb->status) {
@@ -843,7 +842,6 @@ static void cx231xx_bulk_irq_callback(struct urb *urb)
struct cx231xx_video_mode *vmode =
container_of(dma_q, struct cx231xx_video_mode, vidq);
struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode);
- int rc;
switch (urb->status) {
case 0: /* success */
@@ -860,12 +858,10 @@ static void cx231xx_bulk_irq_callback(struct urb *urb)
/* Copy data from URB */
spin_lock(&dev->video_mode.slock);
- rc = dev->video_mode.bulk_ctl.bulk_copy(dev, urb);
+ dev->video_mode.bulk_ctl.bulk_copy(dev, urb);
spin_unlock(&dev->video_mode.slock);
/* Reset urb buffers */
- urb->status = 0;
-
urb->status = usb_submit_urb(urb, GFP_ATOMIC);
if (urb->status) {
cx231xx_isocdbg("urb resubmit failed (error=%i)\n",
@@ -1231,42 +1227,40 @@ int cx231xx_init_bulk(struct cx231xx *dev, int max_packets,
EXPORT_SYMBOL_GPL(cx231xx_init_bulk);
void cx231xx_stop_TS1(struct cx231xx *dev)
{
- int status = 0;
u8 val[4] = { 0, 0, 0, 0 };
- val[0] = 0x00;
- val[1] = 0x03;
- val[2] = 0x00;
- val[3] = 0x00;
- status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
- TS_MODE_REG, val, 4);
-
- val[0] = 0x00;
- val[1] = 0x70;
- val[2] = 0x04;
- val[3] = 0x00;
- status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
- TS1_CFG_REG, val, 4);
+ val[0] = 0x00;
+ val[1] = 0x03;
+ val[2] = 0x00;
+ val[3] = 0x00;
+ cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ TS_MODE_REG, val, 4);
+
+ val[0] = 0x00;
+ val[1] = 0x70;
+ val[2] = 0x04;
+ val[3] = 0x00;
+ cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ TS1_CFG_REG, val, 4);
}
/* EXPORT_SYMBOL_GPL(cx231xx_stop_TS1); */
void cx231xx_start_TS1(struct cx231xx *dev)
{
- int status = 0;
u8 val[4] = { 0, 0, 0, 0 };
- val[0] = 0x03;
- val[1] = 0x03;
- val[2] = 0x00;
- val[3] = 0x00;
- status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
- TS_MODE_REG, val, 4);
-
- val[0] = 0x04;
- val[1] = 0xA3;
- val[2] = 0x3B;
- val[3] = 0x00;
- status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
- TS1_CFG_REG, val, 4);
+ val[0] = 0x03;
+ val[1] = 0x03;
+ val[2] = 0x00;
+ val[3] = 0x00;
+ cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ TS_MODE_REG, val, 4);
+
+ val[0] = 0x04;
+ val[1] = 0xA3;
+ val[2] = 0x3B;
+ val[3] = 0x00;
+ cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ TS1_CFG_REG, val, 4);
}
/* EXPORT_SYMBOL_GPL(cx231xx_start_TS1); */
/*****************************************************************
diff --git a/drivers/media/video/cx231xx/cx231xx-vbi.c b/drivers/media/video/cx231xx/cx231xx-vbi.c
index 8cdee5f78f13..3d15314e1f88 100644
--- a/drivers/media/video/cx231xx/cx231xx-vbi.c
+++ b/drivers/media/video/cx231xx/cx231xx-vbi.c
@@ -83,7 +83,6 @@ static inline void print_err_status(struct cx231xx *dev, int packet, int status)
*/
static inline int cx231xx_isoc_vbi_copy(struct cx231xx *dev, struct urb *urb)
{
- struct cx231xx_buffer *buf;
struct cx231xx_dmaqueue *dma_q = urb->context;
int rc = 1;
unsigned char *p_buffer;
@@ -102,8 +101,6 @@ static inline int cx231xx_isoc_vbi_copy(struct cx231xx *dev, struct urb *urb)
return 0;
}
- buf = dev->vbi_mode.bulk_ctl.buf;
-
/* get buffer pointer and length */
p_buffer = urb->transfer_buffer;
buffer_size = urb->actual_length;
@@ -310,7 +307,6 @@ static void cx231xx_irq_vbi_callback(struct urb *urb)
struct cx231xx_video_mode *vmode =
container_of(dma_q, struct cx231xx_video_mode, vidq);
struct cx231xx *dev = container_of(vmode, struct cx231xx, vbi_mode);
- int rc;
switch (urb->status) {
case 0: /* success */
@@ -328,7 +324,7 @@ static void cx231xx_irq_vbi_callback(struct urb *urb)
/* Copy data from URB */
spin_lock(&dev->vbi_mode.slock);
- rc = dev->vbi_mode.bulk_ctl.bulk_copy(dev, urb);
+ dev->vbi_mode.bulk_ctl.bulk_copy(dev, urb);
spin_unlock(&dev->vbi_mode.slock);
/* Reset status */
diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c
index 7f916f0685e9..523aa49d6b86 100644
--- a/drivers/media/video/cx231xx/cx231xx-video.c
+++ b/drivers/media/video/cx231xx/cx231xx-video.c
@@ -326,9 +326,7 @@ static inline void get_next_buf(struct cx231xx_dmaqueue *dma_q,
*/
static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
{
- struct cx231xx_buffer *buf;
struct cx231xx_dmaqueue *dma_q = urb->context;
- unsigned char *outp = NULL;
int i, rc = 1;
unsigned char *p_buffer;
u32 bytes_parsed = 0, buffer_size = 0;
@@ -346,10 +344,6 @@ static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
return 0;
}
- buf = dev->video_mode.isoc_ctl.buf;
- if (buf != NULL)
- outp = videobuf_to_vmalloc(&buf->vb);
-
for (i = 0; i < urb->number_of_packets; i++) {
int status = urb->iso_frame_desc[i].status;
@@ -429,9 +423,7 @@ static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
{
- struct cx231xx_buffer *buf;
struct cx231xx_dmaqueue *dma_q = urb->context;
- unsigned char *outp = NULL;
int rc = 1;
unsigned char *p_buffer;
u32 bytes_parsed = 0, buffer_size = 0;
@@ -449,10 +441,6 @@ static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
return 0;
}
- buf = dev->video_mode.bulk_ctl.buf;
- if (buf != NULL)
- outp = videobuf_to_vmalloc(&buf->vb);
-
if (1) {
/* get buffer pointer and length */
@@ -701,13 +689,9 @@ void cx231xx_reset_video_buffer(struct cx231xx *dev,
buf = dev->video_mode.bulk_ctl.buf;
if (buf == NULL) {
- u8 *outp = NULL;
/* first try to get the buffer */
get_next_buf(dma_q, &buf);
- if (buf)
- outp = videobuf_to_vmalloc(&buf->vb);
-
dma_q->pos = 0;
dma_q->field1_done = 0;
dma_q->current_field = -1;
@@ -2561,6 +2545,10 @@ static struct video_device *cx231xx_vdev_init(struct cx231xx *dev,
vfd->release = video_device_release;
vfd->debug = video_debug;
vfd->lock = &dev->lock;
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index 19b5499d2624..13739e002a63 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -497,6 +497,10 @@ struct cx23885_board cx23885_boards[] = {
.name = "TerraTec Cinergy T PCIe Dual",
.portb = CX23885_MPEG_DVB,
.portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_TEVII_S471] = {
+ .name = "TeVii S471",
+ .portb = CX23885_MPEG_DVB,
}
};
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -705,6 +709,10 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x153b,
.subdevice = 0x117e,
.card = CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL,
+ }, {
+ .subvendor = 0xd471,
+ .subdevice = 0x9022,
+ .card = CX23885_BOARD_TEVII_S471,
},
};
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -1460,6 +1468,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
break;
case CX23885_BOARD_TEVII_S470:
+ case CX23885_BOARD_TEVII_S471:
case CX23885_BOARD_DVBWORLD_2005:
ts1->gen_ctrl_val = 0x5; /* Parallel */
ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
index 6ad227029a0f..697728f09430 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -1046,6 +1046,13 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
if (cx23885_boards[dev->board].ci_type > 0)
cx_clear(RDR_RDRCTL1, 1 << 8);
+ switch (dev->board) {
+ case CX23885_BOARD_TEVII_S470:
+ case CX23885_BOARD_TEVII_S471:
+ cx_clear(RDR_RDRCTL1, 1 << 8);
+ break;
+ }
+
return 0;
}
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index 6835eb1fc093..a80a92c47455 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -1173,6 +1173,13 @@ static int dvb_register(struct cx23885_tsport *port)
break;
}
break;
+ case CX23885_BOARD_TEVII_S471:
+ i2c_bus = &dev->i2c_bus[1];
+
+ fe0->dvb.frontend = dvb_attach(ds3000_attach,
+ &tevii_ds3000_config,
+ &i2c_bus->i2c_adap);
+ break;
default:
printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
" isn't supported yet\n",
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
index f020f0568df4..d884784a1c85 100644
--- a/drivers/media/video/cx23885/cx23885.h
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -89,6 +89,7 @@
#define CX23885_BOARD_MPX885 32
#define CX23885_BOARD_MYGICA_X8507 33
#define CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL 34
+#define CX23885_BOARD_TEVII_S471 35
#define GPIO_0 0x00000001
#define GPIO_1 0x00000002
diff --git a/drivers/media/video/cx23885/cx23888-ir.c b/drivers/media/video/cx23885/cx23888-ir.c
index bb1ce346425d..c2bc39c58f82 100644
--- a/drivers/media/video/cx23885/cx23888-ir.c
+++ b/drivers/media/video/cx23885/cx23888-ir.c
@@ -331,9 +331,7 @@ static u64 ns_to_pulse_clocks(u32 ns)
static u16 pulse_clocks_to_clock_divider(u64 count)
{
- u32 rem;
-
- rem = do_div(count, (FIFO_RXTX << 2) | 0x3);
+ do_div(count, (FIFO_RXTX << 2) | 0x3);
/* net result needs to be rounded down and decremented by 1 */
if (count > RXCLK_RCD + 1)
diff --git a/drivers/media/video/cx25821/cx25821-alsa.c b/drivers/media/video/cx25821/cx25821-alsa.c
index 03cfac476b03..1858a45dd081 100644
--- a/drivers/media/video/cx25821/cx25821-alsa.c
+++ b/drivers/media/video/cx25821/cx25821-alsa.c
@@ -290,11 +290,9 @@ static irqreturn_t cx25821_irq(int irq, void *dev_id)
u32 status, pci_status;
u32 audint_status, audint_mask;
int loop, handled = 0;
- int audint_count = 0;
audint_status = cx_read(AUD_A_INT_STAT);
audint_mask = cx_read(AUD_A_INT_MSK);
- audint_count = cx_read(AUD_A_GPCNT);
status = cx_read(PCI_INT_STAT);
for (loop = 0; loop < 1; loop++) {
diff --git a/drivers/media/video/cx25821/cx25821-audio-upstream.c b/drivers/media/video/cx25821/cx25821-audio-upstream.c
index 20c7ca3351a8..8b2a99975c23 100644
--- a/drivers/media/video/cx25821/cx25821-audio-upstream.c
+++ b/drivers/media/video/cx25821/cx25821-audio-upstream.c
@@ -585,7 +585,7 @@ int cx25821_audio_upstream_irq(struct cx25821_dev *dev, int chan_num,
static irqreturn_t cx25821_upstream_irq_audio(int irq, void *dev_id)
{
struct cx25821_dev *dev = dev_id;
- u32 msk_stat, audio_status;
+ u32 audio_status;
int handled = 0;
struct sram_channel *sram_ch;
@@ -594,7 +594,6 @@ static irqreturn_t cx25821_upstream_irq_audio(int irq, void *dev_id)
sram_ch = dev->channels[dev->_audio_upstream_channel].sram_channels;
- msk_stat = cx_read(sram_ch->int_mstat);
audio_status = cx_read(sram_ch->int_stat);
/* Only deal with our interrupt */
diff --git a/drivers/media/video/cx25821/cx25821-core.c b/drivers/media/video/cx25821/cx25821-core.c
index 7930ca58349f..83c1aa6b2e6c 100644
--- a/drivers/media/video/cx25821/cx25821-core.c
+++ b/drivers/media/video/cx25821/cx25821-core.c
@@ -379,14 +379,6 @@ static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap)
return cx_read(bus->reg_stat) & 0x01;
}
-void cx_i2c_read_print(struct cx25821_dev *dev, u32 reg, const char *reg_string)
-{
- int tmp = 0;
- u32 value = 0;
-
- value = cx25821_i2c_read(&dev->i2c_bus[0], reg, &tmp);
-}
-
static void cx25821_registers_init(struct cx25821_dev *dev)
{
u32 tmp;
@@ -895,7 +887,7 @@ static void cx25821_iounmap(struct cx25821_dev *dev)
static int cx25821_dev_setup(struct cx25821_dev *dev)
{
- int io_size = 0, i;
+ int i;
pr_info("\n***********************************\n");
pr_info("cx25821 set up\n");
@@ -960,7 +952,6 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
/* PCIe stuff */
dev->base_io_addr = pci_resource_start(dev->pci, 0);
- io_size = pci_resource_len(dev->pci, 0);
if (!dev->base_io_addr) {
CX25821_ERR("No PCI Memory resources, exiting!\n");
@@ -1317,13 +1308,12 @@ void cx25821_free_buffer(struct videobuf_queue *q, struct cx25821_buffer *buf)
static irqreturn_t cx25821_irq(int irq, void *dev_id)
{
struct cx25821_dev *dev = dev_id;
- u32 pci_status, pci_mask;
+ u32 pci_status;
u32 vid_status;
int i, handled = 0;
u32 mask[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
pci_status = cx_read(PCI_INT_STAT);
- pci_mask = cx_read(PCI_INT_MSK);
if (pci_status == 0)
goto out;
diff --git a/drivers/media/video/cx25821/cx25821-i2c.c b/drivers/media/video/cx25821/cx25821-i2c.c
index 12d7300fa1e9..6311180f430c 100644
--- a/drivers/media/video/cx25821/cx25821-i2c.c
+++ b/drivers/media/video/cx25821/cx25821-i2c.c
@@ -361,7 +361,6 @@ void cx25821_av_clk(struct cx25821_dev *dev, int enable)
int cx25821_i2c_read(struct cx25821_i2c *bus, u16 reg_addr, int *value)
{
struct i2c_client *client = &bus->i2c_client;
- int retval = 0;
int v = 0;
u8 addr[2] = { 0, 0 };
u8 buf[4] = { 0, 0, 0, 0 };
@@ -385,7 +384,7 @@ int cx25821_i2c_read(struct cx25821_i2c *bus, u16 reg_addr, int *value)
msgs[0].addr = 0x44;
msgs[1].addr = 0x44;
- retval = i2c_xfer(client->adapter, msgs, 2);
+ i2c_xfer(client->adapter, msgs, 2);
v = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
*value = v;
diff --git a/drivers/media/video/cx25821/cx25821-medusa-video.c b/drivers/media/video/cx25821/cx25821-medusa-video.c
index 298a68d98c2f..313fb20a0b47 100644
--- a/drivers/media/video/cx25821/cx25821-medusa-video.c
+++ b/drivers/media/video/cx25821/cx25821-medusa-video.c
@@ -35,7 +35,6 @@
static void medusa_enable_bluefield_output(struct cx25821_dev *dev, int channel,
int enable)
{
- int ret_val = 1;
u32 value = 0;
u32 tmp = 0;
int out_ctrl = OUT_CTRL1;
@@ -79,13 +78,13 @@ static void medusa_enable_bluefield_output(struct cx25821_dev *dev, int channel,
value &= 0xFFFFFF7F; /* clear BLUE_FIELD_EN */
if (enable)
value |= 0x00000080; /* set BLUE_FIELD_EN */
- ret_val = cx25821_i2c_write(&dev->i2c_bus[0], out_ctrl, value);
+ cx25821_i2c_write(&dev->i2c_bus[0], out_ctrl, value);
value = cx25821_i2c_read(&dev->i2c_bus[0], out_ctrl_ns, &tmp);
value &= 0xFFFFFF7F;
if (enable)
value |= 0x00000080; /* set BLUE_FIELD_EN */
- ret_val = cx25821_i2c_write(&dev->i2c_bus[0], out_ctrl_ns, value);
+ cx25821_i2c_write(&dev->i2c_bus[0], out_ctrl_ns, value);
}
static int medusa_initialize_ntsc(struct cx25821_dev *dev)
@@ -431,7 +430,6 @@ void medusa_set_resolution(struct cx25821_dev *dev, int width,
{
int decoder = 0;
int decoder_count = 0;
- int ret_val = 0;
u32 hscale = 0x0;
u32 vscale = 0x0;
const int MAX_WIDTH = 720;
@@ -482,9 +480,9 @@ void medusa_set_resolution(struct cx25821_dev *dev, int width,
for (; decoder < decoder_count; decoder++) {
/* write scaling values for each decoder */
- ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ cx25821_i2c_write(&dev->i2c_bus[0],
HSCALE_CTRL + (0x200 * decoder), hscale);
- ret_val = cx25821_i2c_write(&dev->i2c_bus[0],
+ cx25821_i2c_write(&dev->i2c_bus[0],
VSCALE_CTRL + (0x200 * decoder), vscale);
}
@@ -494,7 +492,6 @@ void medusa_set_resolution(struct cx25821_dev *dev, int width,
static void medusa_set_decoderduration(struct cx25821_dev *dev, int decoder,
int duration)
{
- int ret_val = 0;
u32 fld_cnt = 0;
u32 tmp = 0;
u32 disp_cnt_reg = DISP_AB_CNT;
@@ -537,7 +534,7 @@ static void medusa_set_decoderduration(struct cx25821_dev *dev, int decoder,
fld_cnt |= ((u32) duration) << 16;
}
- ret_val = cx25821_i2c_write(&dev->i2c_bus[0], disp_cnt_reg, fld_cnt);
+ cx25821_i2c_write(&dev->i2c_bus[0], disp_cnt_reg, fld_cnt);
mutex_unlock(&dev->lock);
}
diff --git a/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c b/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c
index 5a157cf4a95e..c8c94fbf5d8d 100644
--- a/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c
+++ b/drivers/media/video/cx25821/cx25821-video-upstream-ch2.c
@@ -587,7 +587,7 @@ int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num,
static irqreturn_t cx25821_upstream_irq_ch2(int irq, void *dev_id)
{
struct cx25821_dev *dev = dev_id;
- u32 msk_stat, vid_status;
+ u32 vid_status;
int handled = 0;
int channel_num = 0;
struct sram_channel *sram_ch;
@@ -598,7 +598,6 @@ static irqreturn_t cx25821_upstream_irq_ch2(int irq, void *dev_id)
channel_num = VID_UPSTREAM_SRAM_CHANNEL_J;
sram_ch = dev->channels[channel_num].sram_channels;
- msk_stat = cx_read(sram_ch->int_mstat);
vid_status = cx_read(sram_ch->int_stat);
/* Only deal with our interrupt */
diff --git a/drivers/media/video/cx25821/cx25821-video-upstream.c b/drivers/media/video/cx25821/cx25821-video-upstream.c
index 21e7d657f049..52c13e0b6492 100644
--- a/drivers/media/video/cx25821/cx25821-video-upstream.c
+++ b/drivers/media/video/cx25821/cx25821-video-upstream.c
@@ -637,7 +637,7 @@ int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num,
static irqreturn_t cx25821_upstream_irq(int irq, void *dev_id)
{
struct cx25821_dev *dev = dev_id;
- u32 msk_stat, vid_status;
+ u32 vid_status;
int handled = 0;
int channel_num = 0;
struct sram_channel *sram_ch;
@@ -649,7 +649,6 @@ static irqreturn_t cx25821_upstream_irq(int irq, void *dev_id)
sram_ch = dev->channels[channel_num].sram_channels;
- msk_stat = cx_read(sram_ch->int_mstat);
vid_status = cx_read(sram_ch->int_stat);
/* Only deal with our interrupt */
diff --git a/drivers/media/video/cx25821/cx25821-video.c b/drivers/media/video/cx25821/cx25821-video.c
index ffd8bc79c02e..b38d4379cc36 100644
--- a/drivers/media/video/cx25821/cx25821-video.c
+++ b/drivers/media/video/cx25821/cx25821-video.c
@@ -109,25 +109,6 @@ struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc)
return NULL;
}
-void cx25821_dump_video_queue(struct cx25821_dev *dev,
- struct cx25821_dmaqueue *q)
-{
- struct cx25821_buffer *buf;
- struct list_head *item;
- dprintk(1, "%s()\n", __func__);
-
- if (!list_empty(&q->active)) {
- list_for_each(item, &q->active)
- buf = list_entry(item, struct cx25821_buffer, vb.queue);
- }
-
- if (!list_empty(&q->queued)) {
- list_for_each(item, &q->queued)
- buf = list_entry(item, struct cx25821_buffer, vb.queue);
- }
-
-}
-
void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q,
u32 count)
{
@@ -557,7 +538,7 @@ int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
struct cx25821_buffer *buf =
container_of(vb, struct cx25821_buffer, vb);
int rc, init_buffer = 0;
- u32 line0_offset, line1_offset;
+ u32 line0_offset;
struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
int bpl_local = LINE_SIZE_D1;
int channel_opened = fh->channel_id;
@@ -639,7 +620,6 @@ int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
case V4L2_FIELD_INTERLACED:
/* All other formats are top field first */
line0_offset = 0;
- line1_offset = buf->bpl;
dprintk(1, "top field first\n");
cx25821_risc_buffer(dev->pci, &buf->risc,
@@ -1830,7 +1810,6 @@ static long video_ioctl_set(struct file *file, unsigned int cmd,
int i = 0;
int cif_enable = 0;
int cif_width = 0;
- u32 value = 0;
data_from_user = (struct downstream_user_struct *)arg;
@@ -1914,7 +1893,7 @@ static long video_ioctl_set(struct file *file, unsigned int cmd,
cx_write(data_from_user->reg_address, data_from_user->reg_data);
break;
case MEDUSA_READ:
- value = cx25821_i2c_read(&dev->i2c_bus[0],
+ cx25821_i2c_read(&dev->i2c_bus[0],
(u16) data_from_user->reg_address,
&data_from_user->reg_data);
break;
diff --git a/drivers/media/video/cx25821/cx25821-video.h b/drivers/media/video/cx25821/cx25821-video.h
index d0d9538ca5b3..9652a5e35ba2 100644
--- a/drivers/media/video/cx25821/cx25821-video.h
+++ b/drivers/media/video/cx25821/cx25821-video.h
@@ -86,8 +86,6 @@ extern struct cx25821_fmt formats[];
extern struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc);
extern struct cx25821_data timeout_data[MAX_VID_CHANNEL_NUM];
-extern void cx25821_dump_video_queue(struct cx25821_dev *dev,
- struct cx25821_dmaqueue *q);
extern void cx25821_video_wakeup(struct cx25821_dev *dev,
struct cx25821_dmaqueue *q, u32 count);
diff --git a/drivers/media/video/cx25840/cx25840-ir.c b/drivers/media/video/cx25840/cx25840-ir.c
index 13c380ebb562..38ce76ed1924 100644
--- a/drivers/media/video/cx25840/cx25840-ir.c
+++ b/drivers/media/video/cx25840/cx25840-ir.c
@@ -316,9 +316,7 @@ static u64 ns_to_pulse_clocks(u32 ns)
static u16 pulse_clocks_to_clock_divider(u64 count)
{
- u32 rem;
-
- rem = do_div(count, (FIFO_RXTX << 2) | 0x3);
+ do_div(count, (FIFO_RXTX << 2) | 0x3);
/* net result needs to be rounded down and decremented by 1 */
if (count > RXCLK_RCD + 1)
@@ -860,12 +858,10 @@ static int cx25840_ir_tx_write(struct v4l2_subdev *sd, u8 *buf, size_t count,
ssize_t *num)
{
struct cx25840_ir_state *ir_state = to_ir_state(sd);
- struct i2c_client *c;
if (ir_state == NULL)
return -ENODEV;
- c = ir_state->c;
#if 0
/*
* FIXME - the code below is an incomplete and untested sketch of what
diff --git a/drivers/media/video/davinci/Kconfig b/drivers/media/video/davinci/Kconfig
index 60a456ebdc7c..9337b5605c90 100644
--- a/drivers/media/video/davinci/Kconfig
+++ b/drivers/media/video/davinci/Kconfig
@@ -40,6 +40,7 @@ config VIDEO_VPSS_SYSTEM
config VIDEO_VPFE_CAPTURE
tristate "VPFE Video Capture Driver"
depends on VIDEO_V4L2 && (ARCH_DAVINCI || ARCH_OMAP3)
+ depends on I2C
select VIDEOBUF_DMA_CONTIG
help
Support for DMx/AMx VPFE based frame grabber. This is the
diff --git a/drivers/media/video/davinci/vpbe_display.c b/drivers/media/video/davinci/vpbe_display.c
index 1f3b1c729252..e106b72810a9 100644
--- a/drivers/media/video/davinci/vpbe_display.c
+++ b/drivers/media/video/davinci/vpbe_display.c
@@ -1618,6 +1618,10 @@ static __devinit int init_vpbe_layer(int i, struct vpbe_display *disp_dev,
vbd->ioctl_ops = &vpbe_ioctl_ops;
vbd->minor = -1;
vbd->v4l2_dev = &disp_dev->vpbe_dev->v4l2_dev;
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &vbd->flags);
vbd->lock = &vpbe_display_layer->opslock;
if (disp_dev->vpbe_dev->current_timings.timings_type &
diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c
index 20cf271a774b..49a845fb804a 100644
--- a/drivers/media/video/davinci/vpfe_capture.c
+++ b/drivers/media/video/davinci/vpfe_capture.c
@@ -1761,7 +1761,7 @@ static long vpfe_param_handler(struct file *file, void *priv,
}
break;
default:
- ret = -EINVAL;
+ ret = -ENOTTY;
}
unlock_out:
mutex_unlock(&vpfe_dev->lock);
diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c
index 6504e40a31dd..96046957bf21 100644
--- a/drivers/media/video/davinci/vpif_capture.c
+++ b/drivers/media/video/davinci/vpif_capture.c
@@ -2228,6 +2228,10 @@ static __init int vpif_probe(struct platform_device *pdev)
common = &(ch->common[VPIF_VIDEO_INDEX]);
spin_lock_init(&common->irqlock);
mutex_init(&common->lock);
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &ch->video_dev->flags);
ch->video_dev->lock = &common->lock;
/* Initialize prio member of channel object */
v4l2_prio_init(&ch->prio);
diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c
index 7fa34b4fae26..e6488ee7db18 100644
--- a/drivers/media/video/davinci/vpif_display.c
+++ b/drivers/media/video/davinci/vpif_display.c
@@ -1778,6 +1778,10 @@ static __init int vpif_probe(struct platform_device *pdev)
v4l2_prio_init(&ch->prio);
ch->common[VPIF_VIDEO_INDEX].fmt.type =
V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &ch->video_dev->flags);
ch->video_dev->lock = &common->lock;
/* register video device */
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
index f6f622e123bd..928ef0d0429f 100644
--- a/drivers/media/video/em28xx/Kconfig
+++ b/drivers/media/video/em28xx/Kconfig
@@ -49,10 +49,10 @@ config VIDEO_EM28XX_DVB
Empiatech em28xx chips.
config VIDEO_EM28XX_RC
- bool "EM28XX Remote Controller support"
+ tristate "EM28XX Remote Controller support"
depends on RC_CORE
depends on VIDEO_EM28XX
depends on !(RC_CORE=m && VIDEO_EM28XX=y)
- default y
+ default VIDEO_EM28XX
---help---
Enables Remote Controller support on em28xx driver.
diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile
index 2abdf76c5203..c8b338d4be05 100644
--- a/drivers/media/video/em28xx/Makefile
+++ b/drivers/media/video/em28xx/Makefile
@@ -1,16 +1,15 @@
em28xx-y := em28xx-video.o em28xx-i2c.o em28xx-cards.o
em28xx-y += em28xx-core.o em28xx-vbi.o
-em28xx-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-input.o
-
em28xx-alsa-objs := em28xx-audio.o
+em28xx-rc-objs := em28xx-input.o
obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
+obj-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-rc.o
ccflags-y += -Idrivers/media/video
ccflags-y += -Idrivers/media/common/tuners
ccflags-y += -Idrivers/media/dvb/dvb-core
ccflags-y += -Idrivers/media/dvb/frontends
-
diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c
index e2a7b77c39c7..d7e2a3dc5525 100644
--- a/drivers/media/video/em28xx/em28xx-audio.c
+++ b/drivers/media/video/em28xx/em28xx-audio.c
@@ -343,7 +343,6 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
- unsigned int channels, rate, format;
int ret;
dprintk("Setting capture parameters\n");
@@ -352,13 +351,17 @@ static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream,
params_buffer_bytes(hw_params));
if (ret < 0)
return ret;
+#if 0
+ /* TODO: set up em28xx audio chip to deliver the correct audio format,
+ current default is 48000hz multiplexed => 96000hz mono
+ which shouldn't matter since analogue TV only supports mono */
+ unsigned int channels, rate, format;
+
format = params_format(hw_params);
rate = params_rate(hw_params);
channels = params_channels(hw_params);
+#endif
- /* TODO: set up em28xx audio chip to deliver the correct audio format,
- current default is 48000hz multiplexed => 96000hz mono
- which shouldn't matter since analogue TV only supports mono */
return 0;
}
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 9fd8cc7dbb23..20a7e24de6fb 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -69,6 +69,8 @@ struct em28xx_hash_table {
unsigned int tuner;
};
+static void em28xx_pre_card_setup(struct em28xx *dev);
+
/*
* Reset sequences for analog/digital modes
*/
@@ -2361,7 +2363,7 @@ static int em28xx_hint_sensor(struct em28xx *dev)
/* Since em28xx_pre_card_setup() requires a proper dev->model,
* this won't work for boards with generic PCI IDs
*/
-void em28xx_pre_card_setup(struct em28xx *dev)
+static void em28xx_pre_card_setup(struct em28xx *dev)
{
/* Set the initial XCLK and I2C clock values based on the board
definition */
@@ -2661,55 +2663,7 @@ static int em28xx_hint_board(struct em28xx *dev)
return -1;
}
-/* ----------------------------------------------------------------------- */
-void em28xx_register_i2c_ir(struct em28xx *dev)
-{
- /* Leadtek winfast tv USBII deluxe can find a non working IR-device */
- /* at address 0x18, so if that address is needed for another board in */
- /* the future, please put it after 0x1f. */
- struct i2c_board_info info;
- const unsigned short addr_list[] = {
- 0x1f, 0x30, 0x47, I2C_CLIENT_END
- };
-
- if (disable_ir)
- return;
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- memset(&dev->init_data, 0, sizeof(dev->init_data));
- strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
-
- /* detect & configure */
- switch (dev->model) {
- case EM2800_BOARD_TERRATEC_CINERGY_200:
- case EM2820_BOARD_TERRATEC_CINERGY_250:
- dev->init_data.ir_codes = RC_MAP_EM_TERRATEC;
- dev->init_data.get_key = em28xx_get_key_terratec;
- dev->init_data.name = "i2c IR (EM28XX Terratec)";
- break;
- case EM2820_BOARD_PINNACLE_USB_2:
- dev->init_data.ir_codes = RC_MAP_PINNACLE_GREY;
- dev->init_data.get_key = em28xx_get_key_pinnacle_usb_grey;
- dev->init_data.name = "i2c IR (EM28XX Pinnacle PCTV)";
- break;
- case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
- dev->init_data.ir_codes = RC_MAP_HAUPPAUGE;
- dev->init_data.get_key = em28xx_get_key_em_haup;
- dev->init_data.name = "i2c IR (EM2840 Hauppauge)";
- break;
- case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE:
- dev->init_data.ir_codes = RC_MAP_WINFAST_USBII_DELUXE;
- dev->init_data.get_key = em28xx_get_key_winfast_usbii_deluxe;
- dev->init_data.name = "i2c IR (EM2820 Winfast TV USBII Deluxe)";
- break;
- }
-
- if (dev->init_data.name)
- info.platform_data = &dev->init_data;
- i2c_new_probed_device(&dev->i2c_adap, &info, addr_list, NULL);
-}
-
-void em28xx_card_setup(struct em28xx *dev)
+static void em28xx_card_setup(struct em28xx *dev)
{
/*
* If the device can be a webcam, seek for a sensor.
@@ -2849,13 +2803,6 @@ void em28xx_card_setup(struct em28xx *dev)
break;
}
-#if defined(CONFIG_MODULES) && defined(MODULE)
- if (dev->board.has_ir_i2c && !disable_ir)
- request_module("ir-kbd-i2c");
-#endif
- if (dev->board.has_snapshot_button)
- em28xx_register_snapshot_button(dev);
-
if (dev->board.valid == EM28XX_BOARD_NOT_VALIDATED) {
em28xx_errdev("\n\n");
em28xx_errdev("The support for this board weren't "
@@ -2929,9 +2876,6 @@ void em28xx_card_setup(struct em28xx *dev)
}
em28xx_tuner_setup(dev);
-
- if(!disable_ir)
- em28xx_ir_init(dev);
}
@@ -2948,6 +2892,8 @@ static void request_module_async(struct work_struct *work)
if (dev->board.has_dvb)
request_module("em28xx-dvb");
+ if (dev->board.has_ir_i2c && !disable_ir)
+ request_module("em28xx-rc");
}
static void request_modules(struct em28xx *dev)
@@ -2972,12 +2918,6 @@ static void flush_request_modules(struct em28xx *dev)
*/
void em28xx_release_resources(struct em28xx *dev)
{
- if (dev->sbutton_input_dev)
- em28xx_deregister_snapshot_button(dev);
-
- if (dev->ir)
- em28xx_ir_fini(dev);
-
/*FIXME: I2C IR should be disconnected */
em28xx_release_analog_resources(dev);
@@ -3005,9 +2945,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
dev->udev = udev;
mutex_init(&dev->ctrl_urb_lock);
spin_lock_init(&dev->slock);
- init_waitqueue_head(&dev->open);
- init_waitqueue_head(&dev->wait_frame);
- init_waitqueue_head(&dev->wait_stream);
dev->em28xx_write_regs = em28xx_write_regs;
dev->em28xx_read_reg = em28xx_read_reg;
@@ -3140,9 +3077,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
/* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
- INIT_LIST_HEAD(&dev->vidq.queued);
INIT_LIST_HEAD(&dev->vbiq.active);
- INIT_LIST_HEAD(&dev->vbiq.queued);
if (dev->board.has_msp34xx) {
/* Send a reset to other chips via gpio */
@@ -3447,8 +3382,6 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
resources */
mutex_lock(&dev->lock);
- wake_up_interruptible_all(&dev->open);
-
v4l2_device_disconnect(&dev->v4l2_dev);
if (dev->users) {
@@ -3460,8 +3393,6 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
dev->state |= DEV_MISCONFIGURED;
em28xx_uninit_isoc(dev, dev->mode);
dev->state |= DEV_DISCONNECTED;
- wake_up_interruptible(&dev->wait_frame);
- wake_up_interruptible(&dev->wait_stream);
} else {
dev->state |= DEV_DISCONNECTED;
em28xx_release_resources(dev);
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index 53a9fb91e97e..5717bdee8f1b 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -139,6 +139,7 @@ int em28xx_read_reg(struct em28xx *dev, u16 reg)
{
return em28xx_read_reg_req(dev, USB_REQ_GET_STATUS, reg);
}
+EXPORT_SYMBOL_GPL(em28xx_read_reg);
/*
* em28xx_write_regs_req()
@@ -205,6 +206,7 @@ int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len)
return rc;
}
+EXPORT_SYMBOL_GPL(em28xx_write_regs);
/* Write a single register */
int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val)
@@ -239,6 +241,7 @@ int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
return em28xx_write_regs(dev, reg, &newval, 1);
}
+EXPORT_SYMBOL_GPL(em28xx_write_reg_bits);
/*
* em28xx_is_ac97_ready()
@@ -666,7 +669,6 @@ int em28xx_capture_start(struct em28xx *dev, int start)
return rc;
}
-EXPORT_SYMBOL_GPL(em28xx_capture_start);
int em28xx_vbi_supported(struct em28xx *dev)
{
@@ -975,7 +977,6 @@ void em28xx_uninit_isoc(struct em28xx *dev, enum em28xx_mode mode)
else
isoc_bufs = &dev->isoc_ctl.analog_bufs;
- dev->isoc_ctl.nfields = -1;
for (i = 0; i < isoc_bufs->num_bufs; i++) {
urb = isoc_bufs->urb[i];
if (urb) {
@@ -1008,6 +1009,31 @@ void em28xx_uninit_isoc(struct em28xx *dev, enum em28xx_mode mode)
EXPORT_SYMBOL_GPL(em28xx_uninit_isoc);
/*
+ * Stop URBs
+ */
+void em28xx_stop_urbs(struct em28xx *dev)
+{
+ int i;
+ struct urb *urb;
+ struct em28xx_usb_isoc_bufs *isoc_bufs = &dev->isoc_ctl.digital_bufs;
+
+ em28xx_isocdbg("em28xx: called em28xx_stop_urbs\n");
+
+ for (i = 0; i < isoc_bufs->num_bufs; i++) {
+ urb = isoc_bufs->urb[i];
+ if (urb) {
+ if (!irqs_disabled())
+ usb_kill_urb(urb);
+ else
+ usb_unlink_urb(urb);
+ }
+ }
+
+ em28xx_capture_start(dev, 0);
+}
+EXPORT_SYMBOL_GPL(em28xx_stop_urbs);
+
+/*
* Allocate URBs
*/
int em28xx_alloc_isoc(struct em28xx *dev, enum em28xx_mode mode,
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
index 503a8d5b5382..16410ac20092 100644
--- a/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -183,7 +183,7 @@ static int em28xx_stop_streaming(struct em28xx_dvb *dvb)
{
struct em28xx *dev = dvb->adapter.priv;
- em28xx_capture_start(dev, 0);
+ em28xx_stop_urbs(dev);
em28xx_set_mode(dev, EM28XX_SUSPEND);
@@ -336,6 +336,8 @@ struct drxk_config pctv_520e_drxk = {
.single_master = 1,
.microcode_name = "dvb-demod-drxk-pctv.fw",
.chunk_size = 58,
+ .antenna_dvbt = true, /* disable LNA */
+ .antenna_gpio = (1 << 2), /* disable LNA */
};
static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
@@ -474,8 +476,8 @@ static void terratec_h5_init(struct em28xx *dev)
static void pctv_520e_init(struct em28xx *dev)
{
/*
- * Init TDA8295(?) analog demodulator. Looks like I2C traffic to
- * digital demodulator and tuner are routed via TDA8295.
+ * Init AVF4910B analog decoder. Looks like I2C traffic to
+ * digital demodulator and tuner are routed via AVF4910B.
*/
int i;
struct {
@@ -542,7 +544,8 @@ static struct cxd2820r_config em28xx_cxd2820r_config = {
.i2c_address = (0xd8 >> 1),
.ts_mode = CXD2820R_TS_SERIAL,
- /* enable LNA for DVB-T2 and DVB-C */
+ /* enable LNA for DVB-T, DVB-T2 and DVB-C */
+ .gpio_dvbt[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L,
.gpio_dvbt2[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L,
.gpio_dvbc[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L,
};
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index a88e169dba23..185db65b766e 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -553,9 +553,6 @@ int em28xx_i2c_register(struct em28xx *dev)
if (i2c_scan)
em28xx_do_i2c_scan(dev);
- /* Instantiate the IR receiver device, if present */
- em28xx_register_i2c_ir(dev);
-
return 0;
}
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 2630b265b0e8..fce5f7680c99 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -80,7 +80,7 @@ struct em28xx_IR {
I2C IR based get keycodes - should be used with ir-kbd-i2c
**********************************************************/
-int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
unsigned char b;
@@ -108,7 +108,7 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
-int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
unsigned char buf[2];
u16 code;
@@ -157,7 +157,7 @@ int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
-int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
+static int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
u32 *ir_raw)
{
unsigned char buf[3];
@@ -179,7 +179,8 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
return 1;
}
-int em28xx_get_key_winfast_usbii_deluxe(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int em28xx_get_key_winfast_usbii_deluxe(struct IR_i2c *ir, u32 *ir_key,
+ u32 *ir_raw)
{
unsigned char subaddr, keydetect, key;
@@ -387,7 +388,138 @@ int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type)
return rc;
}
-int em28xx_ir_init(struct em28xx *dev)
+static void em28xx_register_i2c_ir(struct em28xx *dev)
+{
+ /* Leadtek winfast tv USBII deluxe can find a non working IR-device */
+ /* at address 0x18, so if that address is needed for another board in */
+ /* the future, please put it after 0x1f. */
+ struct i2c_board_info info;
+ const unsigned short addr_list[] = {
+ 0x1f, 0x30, 0x47, I2C_CLIENT_END
+ };
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ memset(&dev->init_data, 0, sizeof(dev->init_data));
+ strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+
+ /* detect & configure */
+ switch (dev->model) {
+ case EM2800_BOARD_TERRATEC_CINERGY_200:
+ case EM2820_BOARD_TERRATEC_CINERGY_250:
+ dev->init_data.ir_codes = RC_MAP_EM_TERRATEC;
+ dev->init_data.get_key = em28xx_get_key_terratec;
+ dev->init_data.name = "i2c IR (EM28XX Terratec)";
+ break;
+ case EM2820_BOARD_PINNACLE_USB_2:
+ dev->init_data.ir_codes = RC_MAP_PINNACLE_GREY;
+ dev->init_data.get_key = em28xx_get_key_pinnacle_usb_grey;
+ dev->init_data.name = "i2c IR (EM28XX Pinnacle PCTV)";
+ break;
+ case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
+ dev->init_data.ir_codes = RC_MAP_HAUPPAUGE;
+ dev->init_data.get_key = em28xx_get_key_em_haup;
+ dev->init_data.name = "i2c IR (EM2840 Hauppauge)";
+ break;
+ case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE:
+ dev->init_data.ir_codes = RC_MAP_WINFAST_USBII_DELUXE;
+ dev->init_data.get_key = em28xx_get_key_winfast_usbii_deluxe;
+ dev->init_data.name = "i2c IR (EM2820 Winfast TV USBII Deluxe)";
+ break;
+ }
+
+ if (dev->init_data.name)
+ info.platform_data = &dev->init_data;
+ i2c_new_probed_device(&dev->i2c_adap, &info, addr_list, NULL);
+}
+
+/**********************************************************
+ Handle Webcam snapshot button
+ **********************************************************/
+
+static void em28xx_query_sbutton(struct work_struct *work)
+{
+ /* Poll the register and see if the button is depressed */
+ struct em28xx *dev =
+ container_of(work, struct em28xx, sbutton_query_work.work);
+ int ret;
+
+ ret = em28xx_read_reg(dev, EM28XX_R0C_USBSUSP);
+
+ if (ret & EM28XX_R0C_USBSUSP_SNAPSHOT) {
+ u8 cleared;
+ /* Button is depressed, clear the register */
+ cleared = ((u8) ret) & ~EM28XX_R0C_USBSUSP_SNAPSHOT;
+ em28xx_write_regs(dev, EM28XX_R0C_USBSUSP, &cleared, 1);
+
+ /* Not emulate the keypress */
+ input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY,
+ 1);
+ /* Now unpress the key */
+ input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY,
+ 0);
+ }
+
+ /* Schedule next poll */
+ schedule_delayed_work(&dev->sbutton_query_work,
+ msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL));
+}
+
+static void em28xx_register_snapshot_button(struct em28xx *dev)
+{
+ struct input_dev *input_dev;
+ int err;
+
+ em28xx_info("Registering snapshot button...\n");
+ input_dev = input_allocate_device();
+ if (!input_dev) {
+ em28xx_errdev("input_allocate_device failed\n");
+ return;
+ }
+
+ usb_make_path(dev->udev, dev->snapshot_button_path,
+ sizeof(dev->snapshot_button_path));
+ strlcat(dev->snapshot_button_path, "/sbutton",
+ sizeof(dev->snapshot_button_path));
+ INIT_DELAYED_WORK(&dev->sbutton_query_work, em28xx_query_sbutton);
+
+ input_dev->name = "em28xx snapshot button";
+ input_dev->phys = dev->snapshot_button_path;
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+ set_bit(EM28XX_SNAPSHOT_KEY, input_dev->keybit);
+ input_dev->keycodesize = 0;
+ input_dev->keycodemax = 0;
+ input_dev->id.bustype = BUS_USB;
+ input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+ input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+ input_dev->id.version = 1;
+ input_dev->dev.parent = &dev->udev->dev;
+
+ err = input_register_device(input_dev);
+ if (err) {
+ em28xx_errdev("input_register_device failed\n");
+ input_free_device(input_dev);
+ return;
+ }
+
+ dev->sbutton_input_dev = input_dev;
+ schedule_delayed_work(&dev->sbutton_query_work,
+ msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL));
+ return;
+
+}
+
+static void em28xx_deregister_snapshot_button(struct em28xx *dev)
+{
+ if (dev->sbutton_input_dev != NULL) {
+ em28xx_info("Deregistering snapshot button\n");
+ cancel_delayed_work_sync(&dev->sbutton_query_work);
+ input_unregister_device(dev->sbutton_input_dev);
+ dev->sbutton_input_dev = NULL;
+ }
+ return;
+}
+
+static int em28xx_ir_init(struct em28xx *dev)
{
struct em28xx_IR *ir;
struct rc_dev *rc;
@@ -448,6 +580,15 @@ int em28xx_ir_init(struct em28xx *dev)
if (err)
goto err_out_stop;
+ em28xx_register_i2c_ir(dev);
+
+#if defined(CONFIG_MODULES) && defined(MODULE)
+ if (dev->board.has_ir_i2c)
+ request_module("ir-kbd-i2c");
+#endif
+ if (dev->board.has_snapshot_button)
+ em28xx_register_snapshot_button(dev);
+
return 0;
err_out_stop:
@@ -458,10 +599,12 @@ int em28xx_ir_init(struct em28xx *dev)
return err;
}
-int em28xx_ir_fini(struct em28xx *dev)
+static int em28xx_ir_fini(struct em28xx *dev)
{
struct em28xx_IR *ir = dev->ir;
+ em28xx_deregister_snapshot_button(dev);
+
/* skip detach on non attached boards */
if (!ir)
return 0;
@@ -475,89 +618,26 @@ int em28xx_ir_fini(struct em28xx *dev)
return 0;
}
-/**********************************************************
- Handle Webcam snapshot button
- **********************************************************/
+static struct em28xx_ops rc_ops = {
+ .id = EM28XX_RC,
+ .name = "Em28xx Input Extension",
+ .init = em28xx_ir_init,
+ .fini = em28xx_ir_fini,
+};
-static void em28xx_query_sbutton(struct work_struct *work)
+static int __init em28xx_rc_register(void)
{
- /* Poll the register and see if the button is depressed */
- struct em28xx *dev =
- container_of(work, struct em28xx, sbutton_query_work.work);
- int ret;
-
- ret = em28xx_read_reg(dev, EM28XX_R0C_USBSUSP);
-
- if (ret & EM28XX_R0C_USBSUSP_SNAPSHOT) {
- u8 cleared;
- /* Button is depressed, clear the register */
- cleared = ((u8) ret) & ~EM28XX_R0C_USBSUSP_SNAPSHOT;
- em28xx_write_regs(dev, EM28XX_R0C_USBSUSP, &cleared, 1);
-
- /* Not emulate the keypress */
- input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY,
- 1);
- /* Now unpress the key */
- input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY,
- 0);
- }
-
- /* Schedule next poll */
- schedule_delayed_work(&dev->sbutton_query_work,
- msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL));
+ return em28xx_register_extension(&rc_ops);
}
-void em28xx_register_snapshot_button(struct em28xx *dev)
+static void __exit em28xx_rc_unregister(void)
{
- struct input_dev *input_dev;
- int err;
-
- em28xx_info("Registering snapshot button...\n");
- input_dev = input_allocate_device();
- if (!input_dev) {
- em28xx_errdev("input_allocate_device failed\n");
- return;
- }
-
- usb_make_path(dev->udev, dev->snapshot_button_path,
- sizeof(dev->snapshot_button_path));
- strlcat(dev->snapshot_button_path, "/sbutton",
- sizeof(dev->snapshot_button_path));
- INIT_DELAYED_WORK(&dev->sbutton_query_work, em28xx_query_sbutton);
-
- input_dev->name = "em28xx snapshot button";
- input_dev->phys = dev->snapshot_button_path;
- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
- set_bit(EM28XX_SNAPSHOT_KEY, input_dev->keybit);
- input_dev->keycodesize = 0;
- input_dev->keycodemax = 0;
- input_dev->id.bustype = BUS_USB;
- input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
- input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
- input_dev->id.version = 1;
- input_dev->dev.parent = &dev->udev->dev;
-
- err = input_register_device(input_dev);
- if (err) {
- em28xx_errdev("input_register_device failed\n");
- input_free_device(input_dev);
- return;
- }
-
- dev->sbutton_input_dev = input_dev;
- schedule_delayed_work(&dev->sbutton_query_work,
- msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL));
- return;
-
+ em28xx_unregister_extension(&rc_ops);
}
-void em28xx_deregister_snapshot_button(struct em28xx *dev)
-{
- if (dev->sbutton_input_dev != NULL) {
- em28xx_info("Deregistering snapshot button\n");
- cancel_delayed_work_sync(&dev->sbutton_query_work);
- input_unregister_device(dev->sbutton_input_dev);
- dev->sbutton_input_dev = NULL;
- }
- return;
-}
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_DESCRIPTION("Em28xx Input driver");
+
+module_init(em28xx_rc_register);
+module_exit(em28xx_rc_unregister);
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 324b695c0724..50f5f4fc2148 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -1305,9 +1305,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
if (0 == INPUT(i)->type)
return -EINVAL;
- dev->ctl_input = i;
-
- video_mux(dev, dev->ctl_input);
+ video_mux(dev, i);
return 0;
}
@@ -2262,6 +2260,7 @@ static int em28xx_v4l2_close(struct file *filp)
em28xx_release_resources(dev);
kfree(dev->alt_max_pkt_size);
kfree(dev);
+ kfree(fh);
return 0;
}
@@ -2286,7 +2285,6 @@ static int em28xx_v4l2_close(struct file *filp)
videobuf_mmap_free(&fh->vb_vbiq);
kfree(fh);
dev->users--;
- wake_up_interruptible_nr(&dev->open, 1);
return 0;
}
@@ -2497,6 +2495,10 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
vfd->release = video_device_release;
vfd->debug = video_debug;
vfd->lock = &dev->lock;
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
snprintf(vfd->name, sizeof(vfd->name), "%s %s",
dev->name, type_name);
@@ -2518,7 +2520,6 @@ int em28xx_register_analog_devices(struct em28xx *dev)
dev->norm = em28xx_video_template.current_norm;
v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
dev->interlaced = EM28XX_INTERLACED_DEFAULT;
- dev->ctl_input = 0;
/* Analog specific initialization */
dev->format = &format[0];
@@ -2532,7 +2533,7 @@ int em28xx_register_analog_devices(struct em28xx *dev)
em28xx_set_video_format(dev, format[0].fourcc,
maxw, norm_maxh(dev));
- video_mux(dev, dev->ctl_input);
+ video_mux(dev, 0);
/* Audio defaults */
dev->mute = 1;
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index 2868b19f8b54..8757523e6863 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -226,24 +226,10 @@ struct em28xx_usb_isoc_ctl {
/* isoc transfer buffers for digital mode */
struct em28xx_usb_isoc_bufs digital_bufs;
- /* Last buffer command and region */
- u8 cmd;
- int pos, size, pktsize;
-
- /* Last field: ODD or EVEN? */
- int field;
-
- /* Stores incomplete commands */
- u32 tmp_buf;
- int tmp_buf_len;
-
/* Stores already requested buffers */
struct em28xx_buffer *vid_buf;
struct em28xx_buffer *vbi_buf;
- /* Stores the number of received fields */
- int nfields;
-
/* isoc urb callback */
int (*isoc_copy) (struct em28xx *dev, struct urb *urb);
@@ -264,12 +250,10 @@ struct em28xx_buffer {
struct list_head frame;
int top_field;
- int receiving;
};
struct em28xx_dmaqueue {
struct list_head active;
- struct list_head queued;
wait_queue_head_t wq;
@@ -277,13 +261,6 @@ struct em28xx_dmaqueue {
int pos;
};
-/* io methods */
-enum em28xx_io_method {
- IO_NONE,
- IO_READ,
- IO_MMAP,
-};
-
/* inputs */
#define MAX_EM28XX_INPUT 4
@@ -467,6 +444,7 @@ enum em28xx_dev_state {
/* em28xx extensions */
#define EM28XX_AUDIO 0x10
#define EM28XX_DVB 0x20
+#define EM28XX_RC 0x30
/* em28xx resource types (used for res_get/res_lock etc */
#define EM28XX_RESOURCE_VIDEO 0x01
@@ -577,7 +555,6 @@ struct em28xx {
/* states */
enum em28xx_dev_state state;
- enum em28xx_io_method io;
/* vbi related state tracking */
int capture_type;
@@ -593,7 +570,6 @@ struct em28xx {
struct mutex ctrl_urb_lock; /* protects urb_buf */
/* spinlock_t queue_lock; */
struct list_head inqueue, outqueue;
- wait_queue_head_t open, wait_frame, wait_stream;
struct video_device *vbi_dev;
struct video_device *radio_dev;
@@ -695,6 +671,7 @@ int em28xx_init_isoc(struct em28xx *dev, enum em28xx_mode mode,
int max_packets, int num_bufs, int max_pkt_size,
int (*isoc_copy) (struct em28xx *dev, struct urb *urb));
void em28xx_uninit_isoc(struct em28xx *dev, enum em28xx_mode mode);
+void em28xx_stop_urbs(struct em28xx *dev);
int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev);
int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
@@ -710,45 +687,12 @@ void em28xx_release_analog_resources(struct em28xx *dev);
/* Provided by em28xx-cards.c */
extern int em2800_variant_detect(struct usb_device *udev, int model);
-extern void em28xx_pre_card_setup(struct em28xx *dev);
-extern void em28xx_card_setup(struct em28xx *dev);
extern struct em28xx_board em28xx_boards[];
extern struct usb_device_id em28xx_id_table[];
extern const unsigned int em28xx_bcount;
-void em28xx_register_i2c_ir(struct em28xx *dev);
int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
void em28xx_release_resources(struct em28xx *dev);
-/* Provided by em28xx-input.c */
-
-#ifdef CONFIG_VIDEO_EM28XX_RC
-
-int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
-int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
-int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
- u32 *ir_raw);
-int em28xx_get_key_winfast_usbii_deluxe(struct IR_i2c *ir, u32 *ir_key,
- u32 *ir_raw);
-void em28xx_register_snapshot_button(struct em28xx *dev);
-void em28xx_deregister_snapshot_button(struct em28xx *dev);
-
-int em28xx_ir_init(struct em28xx *dev);
-int em28xx_ir_fini(struct em28xx *dev);
-
-#else
-
-#define em28xx_get_key_terratec NULL
-#define em28xx_get_key_em_haup NULL
-#define em28xx_get_key_pinnacle_usb_grey NULL
-#define em28xx_get_key_winfast_usbii_deluxe NULL
-
-static inline void em28xx_register_snapshot_button(struct em28xx *dev) {}
-static inline void em28xx_deregister_snapshot_button(struct em28xx *dev) {}
-static inline int em28xx_ir_init(struct em28xx *dev) { return 0; }
-static inline int em28xx_ir_fini(struct em28xx *dev) { return 0; }
-
-#endif
-
/* Provided by em28xx-vbi.c */
extern struct videobuf_queue_ops em28xx_vbi_qops;
diff --git a/drivers/media/video/et61x251/Kconfig b/drivers/media/video/et61x251/Kconfig
deleted file mode 100644
index 87981b078fe6..000000000000
--- a/drivers/media/video/et61x251/Kconfig
+++ /dev/null
@@ -1,18 +0,0 @@
-config USB_ET61X251
- tristate "USB ET61X[12]51 PC Camera Controller support (DEPRECATED)"
- depends on VIDEO_V4L2
- default n
- ---help---
- This driver is DEPRECATED please use the gspca zc3xx module
- instead.
-
- Say Y here if you want support for cameras based on Etoms ET61X151
- or ET61X251 PC Camera Controllers.
-
- See <file:Documentation/video4linux/et61x251.txt> for more info.
-
- This driver uses the Video For Linux API. You must say Y or M to
- "Video For Linux" to use this driver.
-
- To compile this driver as a module, choose M here: the
- module will be called et61x251.
diff --git a/drivers/media/video/et61x251/Makefile b/drivers/media/video/et61x251/Makefile
deleted file mode 100644
index 2ff4db9ec882..000000000000
--- a/drivers/media/video/et61x251/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-et61x251-objs := et61x251_core.o et61x251_tas5130d1b.o
-
-obj-$(CONFIG_USB_ET61X251) += et61x251.o
-
diff --git a/drivers/media/video/et61x251/et61x251.h b/drivers/media/video/et61x251/et61x251.h
deleted file mode 100644
index 337ded4a6388..000000000000
--- a/drivers/media/video/et61x251/et61x251.h
+++ /dev/null
@@ -1,213 +0,0 @@
-/***************************************************************************
- * V4L2 driver for ET61X[12]51 PC Camera Controllers *
- * *
- * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#ifndef _ET61X251_H_
-#define _ET61X251_H_
-
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-#include <linux/types.h>
-#include <linux/param.h>
-#include <linux/rwsem.h>
-#include <linux/mutex.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-#include <linux/kref.h>
-
-#include "et61x251_sensor.h"
-
-/*****************************************************************************/
-
-#define ET61X251_DEBUG
-#define ET61X251_DEBUG_LEVEL 2
-#define ET61X251_MAX_DEVICES 64
-#define ET61X251_PRESERVE_IMGSCALE 0
-#define ET61X251_FORCE_MUNMAP 0
-#define ET61X251_MAX_FRAMES 32
-#define ET61X251_COMPRESSION_QUALITY 0
-#define ET61X251_URBS 2
-#define ET61X251_ISO_PACKETS 7
-#define ET61X251_ALTERNATE_SETTING 13
-#define ET61X251_URB_TIMEOUT msecs_to_jiffies(2 * ET61X251_ISO_PACKETS)
-#define ET61X251_CTRL_TIMEOUT 100
-#define ET61X251_FRAME_TIMEOUT 2
-
-/*****************************************************************************/
-
-static const struct usb_device_id et61x251_id_table[] = {
- { USB_DEVICE(0x102c, 0x6251), },
- { }
-};
-
-ET61X251_SENSOR_TABLE
-
-/*****************************************************************************/
-
-enum et61x251_frame_state {
- F_UNUSED,
- F_QUEUED,
- F_GRABBING,
- F_DONE,
- F_ERROR,
-};
-
-struct et61x251_frame_t {
- void* bufmem;
- struct v4l2_buffer buf;
- enum et61x251_frame_state state;
- struct list_head frame;
- unsigned long vma_use_count;
-};
-
-enum et61x251_dev_state {
- DEV_INITIALIZED = 0x01,
- DEV_DISCONNECTED = 0x02,
- DEV_MISCONFIGURED = 0x04,
-};
-
-enum et61x251_io_method {
- IO_NONE,
- IO_READ,
- IO_MMAP,
-};
-
-enum et61x251_stream_state {
- STREAM_OFF,
- STREAM_INTERRUPT,
- STREAM_ON,
-};
-
-struct et61x251_sysfs_attr {
- u8 reg, i2c_reg;
-};
-
-struct et61x251_module_param {
- u8 force_munmap;
- u16 frame_timeout;
-};
-
-static DEFINE_MUTEX(et61x251_sysfs_lock);
-static DECLARE_RWSEM(et61x251_dev_lock);
-
-struct et61x251_device {
- struct video_device* v4ldev;
-
- struct et61x251_sensor sensor;
-
- struct usb_device* usbdev;
- struct urb* urb[ET61X251_URBS];
- void* transfer_buffer[ET61X251_URBS];
- u8* control_buffer;
-
- struct et61x251_frame_t *frame_current, frame[ET61X251_MAX_FRAMES];
- struct list_head inqueue, outqueue;
- u32 frame_count, nbuffers, nreadbuffers;
-
- enum et61x251_io_method io;
- enum et61x251_stream_state stream;
-
- struct v4l2_jpegcompression compression;
-
- struct et61x251_sysfs_attr sysfs;
- struct et61x251_module_param module_param;
-
- struct kref kref;
- enum et61x251_dev_state state;
- u8 users;
-
- struct completion probe;
- struct mutex open_mutex, fileop_mutex;
- spinlock_t queue_lock;
- wait_queue_head_t wait_open, wait_frame, wait_stream;
-};
-
-/*****************************************************************************/
-
-struct et61x251_device*
-et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id)
-{
- return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
-}
-
-
-void
-et61x251_attach_sensor(struct et61x251_device* cam,
- const struct et61x251_sensor* sensor)
-{
- memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor));
-}
-
-/*****************************************************************************/
-
-#undef DBG
-#undef KDBG
-#ifdef ET61X251_DEBUG
-#define DBG(level, fmt, ...) \
-do { \
- if (debug >= (level)) { \
- if ((level) == 1) \
- dev_err(&cam->usbdev->dev, fmt "\n", \
- ##__VA_ARGS__); \
- else if ((level) == 2) \
- dev_info(&cam->usbdev->dev, fmt "\n", \
- ##__VA_ARGS__); \
- else if ((level) >= 3) \
- dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \
- __FILE__, __func__, __LINE__, \
- ##__VA_ARGS__); \
- } \
-} while (0)
-#define KDBG(level, fmt, ...) \
-do { \
- if (debug >= (level)) { \
- if ((level) == 1 || (level) == 2) \
- pr_info(fmt "\n", ##__VA_ARGS__); \
- else if ((level) == 3) \
- pr_debug("[%s:%s:%d] " fmt "\n", \
- __FILE__, __func__, __LINE__, \
- ##__VA_ARGS__); \
- } \
-} while (0)
-#define V4LDBG(level, name, cmd) \
-do { \
- if (debug >= (level)) \
- v4l_print_ioctl(name, cmd); \
-} while (0)
-#else
-#define DBG(level, fmt, ...) do {;} while(0)
-#define KDBG(level, fmt, ...) do {;} while(0)
-#define V4LDBG(level, name, cmd) do {;} while(0)
-#endif
-
-#undef PDBG
-#define PDBG(fmt, ...) \
- dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \
- __FILE__, __func__, __LINE__, ##__VA_ARGS__)
-
-#undef PDBGG
-#define PDBGG(fmt, args...) do {;} while (0) /* placeholder */
-
-#endif /* _ET61X251_H_ */
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
deleted file mode 100644
index 5539f09440ac..000000000000
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ /dev/null
@@ -1,2683 +0,0 @@
-/***************************************************************************
- * V4L2 driver for ET61X[12]51 PC Camera Controllers *
- * *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/version.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/compiler.h>
-#include <linux/ioctl.h>
-#include <linux/poll.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/page-flags.h>
-#include <media/v4l2-ioctl.h>
-#include <asm/byteorder.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#include "et61x251.h"
-
-/*****************************************************************************/
-
-#define ET61X251_MODULE_NAME "V4L2 driver for ET61X[12]51 " \
- "PC Camera Controllers"
-#define ET61X251_MODULE_AUTHOR "(C) 2006-2007 Luca Risolia"
-#define ET61X251_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
-#define ET61X251_MODULE_LICENSE "GPL"
-#define ET61X251_MODULE_VERSION "1.1.10"
-
-/*****************************************************************************/
-
-MODULE_DEVICE_TABLE(usb, et61x251_id_table);
-
-MODULE_AUTHOR(ET61X251_MODULE_AUTHOR " " ET61X251_AUTHOR_EMAIL);
-MODULE_DESCRIPTION(ET61X251_MODULE_NAME);
-MODULE_VERSION(ET61X251_MODULE_VERSION);
-MODULE_LICENSE(ET61X251_MODULE_LICENSE);
-
-static short video_nr[] = {[0 ... ET61X251_MAX_DEVICES-1] = -1};
-module_param_array(video_nr, short, NULL, 0444);
-MODULE_PARM_DESC(video_nr,
- "\n<-1|n[,...]> Specify V4L2 minor mode number."
- "\n -1 = use next available (default)"
- "\n n = use minor number n (integer >= 0)"
- "\nYou can specify up to "
- __MODULE_STRING(ET61X251_MAX_DEVICES) " cameras this way."
- "\nFor example:"
- "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
- "\nthe second registered camera and use auto for the first"
- "\none and for every other camera."
- "\n");
-
-static bool force_munmap[] = {[0 ... ET61X251_MAX_DEVICES-1] =
- ET61X251_FORCE_MUNMAP};
-module_param_array(force_munmap, bool, NULL, 0444);
-MODULE_PARM_DESC(force_munmap,
- "\n<0|1[,...]> Force the application to unmap previously"
- "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
- "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
- "\nthis feature. This parameter is specific for each"
- "\ndetected camera."
- "\n 0 = do not force memory unmapping"
- "\n 1 = force memory unmapping (save memory)"
- "\nDefault value is "__MODULE_STRING(ET61X251_FORCE_MUNMAP)"."
- "\n");
-
-static unsigned int frame_timeout[] = {[0 ... ET61X251_MAX_DEVICES-1] =
- ET61X251_FRAME_TIMEOUT};
-module_param_array(frame_timeout, uint, NULL, 0644);
-MODULE_PARM_DESC(frame_timeout,
- "\n<n[,...]> Timeout for a video frame in seconds."
- "\nThis parameter is specific for each detected camera."
- "\nDefault value is "
- __MODULE_STRING(ET61X251_FRAME_TIMEOUT)"."
- "\n");
-
-#ifdef ET61X251_DEBUG
-static unsigned short debug = ET61X251_DEBUG_LEVEL;
-module_param(debug, ushort, 0644);
-MODULE_PARM_DESC(debug,
- "\n<n> Debugging information level, from 0 to 3:"
- "\n0 = none (use carefully)"
- "\n1 = critical errors"
- "\n2 = significant informations"
- "\n3 = more verbose messages"
- "\nLevel 3 is useful for testing only, when only "
- "one device is used."
- "\nDefault value is "__MODULE_STRING(ET61X251_DEBUG_LEVEL)"."
- "\n");
-#endif
-
-/*****************************************************************************/
-
-static u32
-et61x251_request_buffers(struct et61x251_device* cam, u32 count,
- enum et61x251_io_method io)
-{
- struct v4l2_pix_format* p = &(cam->sensor.pix_format);
- struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
- const 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;
- u32 i;
-
- if (count > ET61X251_MAX_FRAMES)
- count = ET61X251_MAX_FRAMES;
-
- cam->nbuffers = count;
- while (cam->nbuffers > 0) {
- if ((buff = vmalloc_32_user(cam->nbuffers *
- PAGE_ALIGN(imagesize))))
- break;
- cam->nbuffers--;
- }
-
- for (i = 0; i < cam->nbuffers; i++) {
- cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
- cam->frame[i].buf.index = i;
- cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
- cam->frame[i].buf.length = imagesize;
- cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- cam->frame[i].buf.sequence = 0;
- cam->frame[i].buf.field = V4L2_FIELD_NONE;
- cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
- cam->frame[i].buf.flags = 0;
- }
-
- return cam->nbuffers;
-}
-
-
-static void et61x251_release_buffers(struct et61x251_device* cam)
-{
- if (cam->nbuffers) {
- vfree(cam->frame[0].bufmem);
- cam->nbuffers = 0;
- }
- cam->frame_current = NULL;
-}
-
-
-static void et61x251_empty_framequeues(struct et61x251_device* cam)
-{
- u32 i;
-
- INIT_LIST_HEAD(&cam->inqueue);
- INIT_LIST_HEAD(&cam->outqueue);
-
- for (i = 0; i < ET61X251_MAX_FRAMES; i++) {
- cam->frame[i].state = F_UNUSED;
- cam->frame[i].buf.bytesused = 0;
- }
-}
-
-
-static void et61x251_requeue_outqueue(struct et61x251_device* cam)
-{
- struct et61x251_frame_t *i;
-
- list_for_each_entry(i, &cam->outqueue, frame) {
- i->state = F_QUEUED;
- list_add(&i->frame, &cam->inqueue);
- }
-
- INIT_LIST_HEAD(&cam->outqueue);
-}
-
-
-static void et61x251_queue_unusedframes(struct et61x251_device* cam)
-{
- unsigned long lock_flags;
- u32 i;
-
- for (i = 0; i < cam->nbuffers; i++)
- if (cam->frame[i].state == F_UNUSED) {
- cam->frame[i].state = F_QUEUED;
- spin_lock_irqsave(&cam->queue_lock, lock_flags);
- list_add_tail(&cam->frame[i].frame, &cam->inqueue);
- spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
- }
-}
-
-/*****************************************************************************/
-
-int et61x251_write_reg(struct et61x251_device* cam, u8 value, u16 index)
-{
- struct usb_device* udev = cam->usbdev;
- u8* buff = cam->control_buffer;
- int res;
-
- *buff = value;
-
- res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
- 0, index, buff, 1, ET61X251_CTRL_TIMEOUT);
- if (res < 0) {
- DBG(3, "Failed to write a register (value 0x%02X, index "
- "0x%02X, error %d)", value, index, res);
- return -1;
- }
-
- return 0;
-}
-
-
-static int et61x251_read_reg(struct et61x251_device* cam, u16 index)
-{
- struct usb_device* udev = cam->usbdev;
- u8* buff = cam->control_buffer;
- int res;
-
- res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
- 0, index, buff, 1, ET61X251_CTRL_TIMEOUT);
- if (res < 0)
- DBG(3, "Failed to read a register (index 0x%02X, error %d)",
- index, res);
-
- return (res >= 0) ? (int)(*buff) : -1;
-}
-
-
-static int
-et61x251_i2c_wait(struct et61x251_device* cam,
- const struct et61x251_sensor* sensor)
-{
- int i, r;
-
- for (i = 1; i <= 8; i++) {
- if (sensor->interface == ET61X251_I2C_3WIRES) {
- r = et61x251_read_reg(cam, 0x8e);
- if (!(r & 0x02) && (r >= 0))
- return 0;
- } else {
- r = et61x251_read_reg(cam, 0x8b);
- if (!(r & 0x01) && (r >= 0))
- return 0;
- }
- if (r < 0)
- return -EIO;
- udelay(8*8); /* minimum for sensors at 400kHz */
- }
-
- return -EBUSY;
-}
-
-
-int
-et61x251_i2c_raw_write(struct et61x251_device* cam, u8 n, u8 data1, u8 data2,
- u8 data3, u8 data4, u8 data5, u8 data6, u8 data7,
- u8 data8, u8 address)
-{
- struct usb_device* udev = cam->usbdev;
- u8* data = cam->control_buffer;
- int err = 0, res;
-
- data[0] = data2;
- data[1] = data3;
- data[2] = data4;
- data[3] = data5;
- data[4] = data6;
- data[5] = data7;
- data[6] = data8;
- res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
- 0, 0x81, data, n-1, ET61X251_CTRL_TIMEOUT);
- if (res < 0)
- err += res;
-
- data[0] = address;
- data[1] = cam->sensor.i2c_slave_id;
- data[2] = cam->sensor.rsta | 0x02 | (n << 4);
- res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
- 0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
- if (res < 0)
- err += res;
-
- /* Start writing through the serial interface */
- data[0] = data1;
- res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
- 0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);
- if (res < 0)
- err += res;
-
- err += et61x251_i2c_wait(cam, &cam->sensor);
-
- if (err)
- DBG(3, "I2C raw write failed for %s image sensor",
- cam->sensor.name);
-
- PDBGG("I2C raw write: %u bytes, address = 0x%02X, data1 = 0x%02X, "
- "data2 = 0x%02X, data3 = 0x%02X, data4 = 0x%02X, data5 = 0x%02X,"
- " data6 = 0x%02X, data7 = 0x%02X, data8 = 0x%02X", n, address,
- data1, data2, data3, data4, data5, data6, data7, data8);
-
- return err ? -1 : 0;
-
-}
-
-
-/*****************************************************************************/
-
-static void et61x251_urb_complete(struct urb *urb)
-{
- struct et61x251_device* cam = urb->context;
- struct et61x251_frame_t** f;
- size_t imagesize;
- u8 i;
- int err = 0;
-
- if (urb->status == -ENOENT)
- return;
-
- f = &cam->frame_current;
-
- if (cam->stream == STREAM_INTERRUPT) {
- cam->stream = STREAM_OFF;
- if ((*f))
- (*f)->state = F_QUEUED;
- DBG(3, "Stream interrupted");
- wake_up(&cam->wait_stream);
- }
-
- if (cam->state & DEV_DISCONNECTED)
- return;
-
- if (cam->state & DEV_MISCONFIGURED) {
- wake_up_interruptible(&cam->wait_frame);
- return;
- }
-
- if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
- goto resubmit_urb;
-
- if (!(*f))
- (*f) = list_entry(cam->inqueue.next, struct et61x251_frame_t,
- frame);
-
- imagesize = (cam->sensor.pix_format.width *
- cam->sensor.pix_format.height *
- cam->sensor.pix_format.priv) / 8;
-
- for (i = 0; i < urb->number_of_packets; i++) {
- unsigned int len, status;
- void *pos;
- u8* b1, * b2, sof;
- const u8 VOID_BYTES = 6;
- size_t imglen;
-
- len = urb->iso_frame_desc[i].actual_length;
- status = urb->iso_frame_desc[i].status;
- pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
-
- if (status) {
- DBG(3, "Error in isochronous frame");
- (*f)->state = F_ERROR;
- continue;
- }
-
- b1 = pos++;
- b2 = pos++;
- sof = ((*b1 & 0x3f) == 63);
- imglen = ((*b1 & 0xc0) << 2) | *b2;
-
- PDBGG("Isochrnous frame: length %u, #%u i, image length %zu",
- len, i, imglen);
-
- if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR)
-start_of_frame:
- if (sof) {
- (*f)->state = F_GRABBING;
- (*f)->buf.bytesused = 0;
- do_gettimeofday(&(*f)->buf.timestamp);
- pos += 22;
- DBG(3, "SOF detected: new video frame");
- }
-
- if ((*f)->state == F_GRABBING) {
- if (sof && (*f)->buf.bytesused) {
- if (cam->sensor.pix_format.pixelformat ==
- V4L2_PIX_FMT_ET61X251)
- goto end_of_frame;
- else {
- DBG(3, "Not expected SOF detected "
- "after %lu bytes",
- (unsigned long)(*f)->buf.bytesused);
- (*f)->state = F_ERROR;
- continue;
- }
- }
-
- if ((*f)->buf.bytesused + imglen > imagesize) {
- DBG(3, "Video frame size exceeded");
- (*f)->state = F_ERROR;
- continue;
- }
-
- pos += VOID_BYTES;
-
- memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, imglen);
- (*f)->buf.bytesused += imglen;
-
- if ((*f)->buf.bytesused == imagesize) {
- u32 b;
-end_of_frame:
- b = (*f)->buf.bytesused;
- (*f)->state = F_DONE;
- (*f)->buf.sequence= ++cam->frame_count;
- spin_lock(&cam->queue_lock);
- list_move_tail(&(*f)->frame, &cam->outqueue);
- if (!list_empty(&cam->inqueue))
- (*f) = list_entry(cam->inqueue.next,
- struct et61x251_frame_t,
- frame);
- else
- (*f) = NULL;
- spin_unlock(&cam->queue_lock);
- DBG(3, "Video frame captured: : %lu bytes",
- (unsigned long)(b));
-
- if (!(*f))
- goto resubmit_urb;
-
- if (sof &&
- cam->sensor.pix_format.pixelformat ==
- V4L2_PIX_FMT_ET61X251)
- goto start_of_frame;
- }
- }
- }
-
-resubmit_urb:
- urb->dev = cam->usbdev;
- err = usb_submit_urb(urb, GFP_ATOMIC);
- if (err < 0 && err != -EPERM) {
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "usb_submit_urb() failed");
- }
-
- wake_up_interruptible(&cam->wait_frame);
-}
-
-
-static int et61x251_start_transfer(struct et61x251_device* cam)
-{
- struct usb_device *udev = cam->usbdev;
- struct urb* urb;
- struct usb_host_interface* altsetting = usb_altnum_to_altsetting(
- usb_ifnum_to_if(udev, 0),
- ET61X251_ALTERNATE_SETTING);
- const unsigned int psz = le16_to_cpu(altsetting->
- endpoint[0].desc.wMaxPacketSize);
- s8 i, j;
- int err = 0;
-
- for (i = 0; i < ET61X251_URBS; i++) {
- cam->transfer_buffer[i] = kzalloc(ET61X251_ISO_PACKETS * psz,
- GFP_KERNEL);
- if (!cam->transfer_buffer[i]) {
- err = -ENOMEM;
- DBG(1, "Not enough memory");
- goto free_buffers;
- }
- }
-
- for (i = 0; i < ET61X251_URBS; i++) {
- urb = usb_alloc_urb(ET61X251_ISO_PACKETS, GFP_KERNEL);
- cam->urb[i] = urb;
- if (!urb) {
- err = -ENOMEM;
- DBG(1, "usb_alloc_urb() failed");
- goto free_urbs;
- }
- urb->dev = udev;
- urb->context = cam;
- urb->pipe = usb_rcvisocpipe(udev, 1);
- urb->transfer_flags = URB_ISO_ASAP;
- urb->number_of_packets = ET61X251_ISO_PACKETS;
- urb->complete = et61x251_urb_complete;
- urb->transfer_buffer = cam->transfer_buffer[i];
- urb->transfer_buffer_length = psz * ET61X251_ISO_PACKETS;
- urb->interval = 1;
- for (j = 0; j < ET61X251_ISO_PACKETS; j++) {
- urb->iso_frame_desc[j].offset = psz * j;
- urb->iso_frame_desc[j].length = psz;
- }
- }
-
- err = et61x251_write_reg(cam, 0x01, 0x03);
- err = et61x251_write_reg(cam, 0x00, 0x03);
- err = et61x251_write_reg(cam, 0x08, 0x03);
- if (err) {
- err = -EIO;
- DBG(1, "I/O hardware error");
- goto free_urbs;
- }
-
- err = usb_set_interface(udev, 0, ET61X251_ALTERNATE_SETTING);
- if (err) {
- DBG(1, "usb_set_interface() failed");
- goto free_urbs;
- }
-
- cam->frame_current = NULL;
-
- for (i = 0; i < ET61X251_URBS; i++) {
- err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
- if (err) {
- for (j = i-1; j >= 0; j--)
- usb_kill_urb(cam->urb[j]);
- DBG(1, "usb_submit_urb() failed, error %d", err);
- goto free_urbs;
- }
- }
-
- return 0;
-
-free_urbs:
- for (i = 0; (i < ET61X251_URBS) && cam->urb[i]; i++)
- usb_free_urb(cam->urb[i]);
-
-free_buffers:
- for (i = 0; (i < ET61X251_URBS) && cam->transfer_buffer[i]; i++)
- kfree(cam->transfer_buffer[i]);
-
- return err;
-}
-
-
-static int et61x251_stop_transfer(struct et61x251_device* cam)
-{
- struct usb_device *udev = cam->usbdev;
- s8 i;
- int err = 0;
-
- if (cam->state & DEV_DISCONNECTED)
- return 0;
-
- for (i = ET61X251_URBS-1; i >= 0; i--) {
- usb_kill_urb(cam->urb[i]);
- usb_free_urb(cam->urb[i]);
- kfree(cam->transfer_buffer[i]);
- }
-
- err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
- if (err)
- DBG(3, "usb_set_interface() failed");
-
- return err;
-}
-
-
-static int et61x251_stream_interrupt(struct et61x251_device* cam)
-{
- long timeout;
-
- cam->stream = STREAM_INTERRUPT;
- timeout = wait_event_timeout(cam->wait_stream,
- (cam->stream == STREAM_OFF) ||
- (cam->state & DEV_DISCONNECTED),
- ET61X251_URB_TIMEOUT);
- if (cam->state & DEV_DISCONNECTED)
- return -ENODEV;
- else if (cam->stream != STREAM_OFF) {
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "URB timeout reached. The camera is misconfigured. To "
- "use it, close and open %s again.",
- video_device_node_name(cam->v4ldev));
- return -EIO;
- }
-
- return 0;
-}
-
-/*****************************************************************************/
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-
-static int et61x251_i2c_try_read(struct et61x251_device* cam,
- const struct et61x251_sensor* sensor,
- u8 address)
-{
- struct usb_device* udev = cam->usbdev;
- u8* data = cam->control_buffer;
- int err = 0, res;
-
- data[0] = address;
- data[1] = cam->sensor.i2c_slave_id;
- data[2] = cam->sensor.rsta | 0x10;
- data[3] = !(et61x251_read_reg(cam, 0x8b) & 0x02);
- res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
- 0, 0x88, data, 4, ET61X251_CTRL_TIMEOUT);
- if (res < 0)
- err += res;
-
- err += et61x251_i2c_wait(cam, sensor);
-
- res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
- 0, 0x80, data, 8, ET61X251_CTRL_TIMEOUT);
- if (res < 0)
- err += res;
-
- if (err)
- DBG(3, "I2C read failed for %s image sensor", sensor->name);
-
- PDBGG("I2C read: address 0x%02X, value: 0x%02X", address, data[0]);
-
- return err ? -1 : (int)data[0];
-}
-
-
-static int et61x251_i2c_try_write(struct et61x251_device* cam,
- const struct et61x251_sensor* sensor,
- u8 address, u8 value)
-{
- struct usb_device* udev = cam->usbdev;
- u8* data = cam->control_buffer;
- int err = 0, res;
-
- data[0] = address;
- data[1] = cam->sensor.i2c_slave_id;
- data[2] = cam->sensor.rsta | 0x12;
- res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
- 0, 0x88, data, 3, ET61X251_CTRL_TIMEOUT);
- if (res < 0)
- err += res;
-
- data[0] = value;
- res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x41,
- 0, 0x80, data, 1, ET61X251_CTRL_TIMEOUT);
- if (res < 0)
- err += res;
-
- err += et61x251_i2c_wait(cam, sensor);
-
- if (err)
- DBG(3, "I2C write failed for %s image sensor", sensor->name);
-
- PDBGG("I2C write: address 0x%02X, value: 0x%02X", address, value);
-
- return err ? -1 : 0;
-}
-
-static int et61x251_i2c_read(struct et61x251_device* cam, u8 address)
-{
- return et61x251_i2c_try_read(cam, &cam->sensor, address);
-}
-
-static int et61x251_i2c_write(struct et61x251_device* cam,
- u8 address, u8 value)
-{
- return et61x251_i2c_try_write(cam, &cam->sensor, address, value);
-}
-
-static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count)
-{
- char str[5];
- char* endp;
- unsigned long val;
-
- if (len < 4) {
- strncpy(str, buff, len);
- str[len] = '\0';
- } else {
- strncpy(str, buff, 4);
- str[4] = '\0';
- }
-
- val = simple_strtoul(str, &endp, 0);
-
- *count = 0;
- if (val <= 0xff)
- *count = (ssize_t)(endp - str);
- if ((*count) && (len == *count+1) && (buff[*count] == '\n'))
- *count += 1;
-
- return (u8)val;
-}
-
-/*
- NOTE 1: being inside one of the following methods implies that the v4l
- device exists for sure (see kobjects and reference counters)
- NOTE 2: buffers are PAGE_SIZE long
-*/
-
-static ssize_t et61x251_show_reg(struct device* cd,
- struct device_attribute *attr, char* buf)
-{
- struct et61x251_device* cam;
- ssize_t count;
-
- if (mutex_lock_interruptible(&et61x251_sysfs_lock))
- return -ERESTARTSYS;
-
- cam = video_get_drvdata(to_video_device(cd));
- if (!cam) {
- mutex_unlock(&et61x251_sysfs_lock);
- return -ENODEV;
- }
-
- count = sprintf(buf, "%u\n", cam->sysfs.reg);
-
- mutex_unlock(&et61x251_sysfs_lock);
-
- return count;
-}
-
-
-static ssize_t
-et61x251_store_reg(struct device* cd,
- struct device_attribute *attr, const char* buf, size_t len)
-{
- struct et61x251_device* cam;
- u8 index;
- ssize_t count;
-
- if (mutex_lock_interruptible(&et61x251_sysfs_lock))
- return -ERESTARTSYS;
-
- cam = video_get_drvdata(to_video_device(cd));
- if (!cam) {
- mutex_unlock(&et61x251_sysfs_lock);
- return -ENODEV;
- }
-
- index = et61x251_strtou8(buf, len, &count);
- if (index > 0x8e || !count) {
- mutex_unlock(&et61x251_sysfs_lock);
- return -EINVAL;
- }
-
- cam->sysfs.reg = index;
-
- DBG(2, "Moved ET61X[12]51 register index to 0x%02X", cam->sysfs.reg);
- DBG(3, "Written bytes: %zd", count);
-
- mutex_unlock(&et61x251_sysfs_lock);
-
- return count;
-}
-
-
-static ssize_t et61x251_show_val(struct device* cd,
- struct device_attribute *attr, char* buf)
-{
- struct et61x251_device* cam;
- ssize_t count;
- int val;
-
- if (mutex_lock_interruptible(&et61x251_sysfs_lock))
- return -ERESTARTSYS;
-
- cam = video_get_drvdata(to_video_device(cd));
- if (!cam) {
- mutex_unlock(&et61x251_sysfs_lock);
- return -ENODEV;
- }
-
- if ((val = et61x251_read_reg(cam, cam->sysfs.reg)) < 0) {
- mutex_unlock(&et61x251_sysfs_lock);
- return -EIO;
- }
-
- count = sprintf(buf, "%d\n", val);
-
- DBG(3, "Read bytes: %zd", count);
-
- mutex_unlock(&et61x251_sysfs_lock);
-
- return count;
-}
-
-
-static ssize_t
-et61x251_store_val(struct device* cd, struct device_attribute *attr,
- const char* buf, size_t len)
-{
- struct et61x251_device* cam;
- u8 value;
- ssize_t count;
- int err;
-
- if (mutex_lock_interruptible(&et61x251_sysfs_lock))
- return -ERESTARTSYS;
-
- cam = video_get_drvdata(to_video_device(cd));
- if (!cam) {
- mutex_unlock(&et61x251_sysfs_lock);
- return -ENODEV;
- }
-
- value = et61x251_strtou8(buf, len, &count);
- if (!count) {
- mutex_unlock(&et61x251_sysfs_lock);
- return -EINVAL;
- }
-
- err = et61x251_write_reg(cam, value, cam->sysfs.reg);
- if (err) {
- mutex_unlock(&et61x251_sysfs_lock);
- return -EIO;
- }
-
- DBG(2, "Written ET61X[12]51 reg. 0x%02X, val. 0x%02X",
- cam->sysfs.reg, value);
- DBG(3, "Written bytes: %zd", count);
-
- mutex_unlock(&et61x251_sysfs_lock);
-
- return count;
-}
-
-
-static ssize_t et61x251_show_i2c_reg(struct device* cd,
- struct device_attribute *attr, char* buf)
-{
- struct et61x251_device* cam;
- ssize_t count;
-
- if (mutex_lock_interruptible(&et61x251_sysfs_lock))
- return -ERESTARTSYS;
-
- cam = video_get_drvdata(to_video_device(cd));
- if (!cam) {
- mutex_unlock(&et61x251_sysfs_lock);
- return -ENODEV;
- }
-
- count = sprintf(buf, "%u\n", cam->sysfs.i2c_reg);
-
- DBG(3, "Read bytes: %zd", count);
-
- mutex_unlock(&et61x251_sysfs_lock);
-
- return count;
-}
-
-
-static ssize_t
-et61x251_store_i2c_reg(struct device* cd, struct device_attribute *attr,
- const char* buf, size_t len)
-{
- struct et61x251_device* cam;
- u8 index;
- ssize_t count;
-
- if (mutex_lock_interruptible(&et61x251_sysfs_lock))
- return -ERESTARTSYS;
-
- cam = video_get_drvdata(to_video_device(cd));
- if (!cam) {
- mutex_unlock(&et61x251_sysfs_lock);
- return -ENODEV;
- }
-
- index = et61x251_strtou8(buf, len, &count);
- if (!count) {
- mutex_unlock(&et61x251_sysfs_lock);
- return -EINVAL;
- }
-
- cam->sysfs.i2c_reg = index;
-
- DBG(2, "Moved sensor register index to 0x%02X", cam->sysfs.i2c_reg);
- DBG(3, "Written bytes: %zd", count);
-
- mutex_unlock(&et61x251_sysfs_lock);
-
- return count;
-}
-
-
-static ssize_t et61x251_show_i2c_val(struct device* cd,
- struct device_attribute *attr, char* buf)
-{
- struct et61x251_device* cam;
- ssize_t count;
- int val;
-
- if (mutex_lock_interruptible(&et61x251_sysfs_lock))
- return -ERESTARTSYS;
-
- cam = video_get_drvdata(to_video_device(cd));
- if (!cam) {
- mutex_unlock(&et61x251_sysfs_lock);
- return -ENODEV;
- }
-
- if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) {
- mutex_unlock(&et61x251_sysfs_lock);
- return -ENOSYS;
- }
-
- if ((val = et61x251_i2c_read(cam, cam->sysfs.i2c_reg)) < 0) {
- mutex_unlock(&et61x251_sysfs_lock);
- return -EIO;
- }
-
- count = sprintf(buf, "%d\n", val);
-
- DBG(3, "Read bytes: %zd", count);
-
- mutex_unlock(&et61x251_sysfs_lock);
-
- return count;
-}
-
-
-static ssize_t
-et61x251_store_i2c_val(struct device* cd, struct device_attribute *attr,
- const char* buf, size_t len)
-{
- struct et61x251_device* cam;
- u8 value;
- ssize_t count;
- int err;
-
- if (mutex_lock_interruptible(&et61x251_sysfs_lock))
- return -ERESTARTSYS;
-
- cam = video_get_drvdata(to_video_device(cd));
- if (!cam) {
- mutex_unlock(&et61x251_sysfs_lock);
- return -ENODEV;
- }
-
- if (!(cam->sensor.sysfs_ops & ET61X251_I2C_READ)) {
- mutex_unlock(&et61x251_sysfs_lock);
- return -ENOSYS;
- }
-
- value = et61x251_strtou8(buf, len, &count);
- if (!count) {
- mutex_unlock(&et61x251_sysfs_lock);
- return -EINVAL;
- }
-
- err = et61x251_i2c_write(cam, cam->sysfs.i2c_reg, value);
- if (err) {
- mutex_unlock(&et61x251_sysfs_lock);
- return -EIO;
- }
-
- DBG(2, "Written sensor reg. 0x%02X, val. 0x%02X",
- cam->sysfs.i2c_reg, value);
- DBG(3, "Written bytes: %zd", count);
-
- mutex_unlock(&et61x251_sysfs_lock);
-
- return count;
-}
-
-
-static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,
- et61x251_show_reg, et61x251_store_reg);
-static DEVICE_ATTR(val, S_IRUGO | S_IWUSR,
- et61x251_show_val, et61x251_store_val);
-static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
- et61x251_show_i2c_reg, et61x251_store_i2c_reg);
-static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
- et61x251_show_i2c_val, et61x251_store_i2c_val);
-
-
-static int et61x251_create_sysfs(struct et61x251_device* cam)
-{
- struct device *classdev = &(cam->v4ldev->dev);
- int err = 0;
-
- if ((err = device_create_file(classdev, &dev_attr_reg)))
- goto err_out;
- if ((err = device_create_file(classdev, &dev_attr_val)))
- goto err_reg;
-
- if (cam->sensor.sysfs_ops) {
- if ((err = device_create_file(classdev, &dev_attr_i2c_reg)))
- goto err_val;
- if ((err = device_create_file(classdev, &dev_attr_i2c_val)))
- goto err_i2c_reg;
- }
-
-err_i2c_reg:
- if (cam->sensor.sysfs_ops)
- device_remove_file(classdev, &dev_attr_i2c_reg);
-err_val:
- device_remove_file(classdev, &dev_attr_val);
-err_reg:
- device_remove_file(classdev, &dev_attr_reg);
-err_out:
- return err;
-}
-#endif /* CONFIG_VIDEO_ADV_DEBUG */
-
-/*****************************************************************************/
-
-static int
-et61x251_set_pix_format(struct et61x251_device* cam,
- struct v4l2_pix_format* pix)
-{
- int r, err = 0;
-
- if ((r = et61x251_read_reg(cam, 0x12)) < 0)
- err += r;
- if (pix->pixelformat == V4L2_PIX_FMT_ET61X251)
- err += et61x251_write_reg(cam, r & 0xfd, 0x12);
- else
- err += et61x251_write_reg(cam, r | 0x02, 0x12);
-
- return err ? -EIO : 0;
-}
-
-
-static int
-et61x251_set_compression(struct et61x251_device* cam,
- struct v4l2_jpegcompression* compression)
-{
- int r, err = 0;
-
- if ((r = et61x251_read_reg(cam, 0x12)) < 0)
- err += r;
- if (compression->quality == 0)
- err += et61x251_write_reg(cam, r & 0xfb, 0x12);
- else
- err += et61x251_write_reg(cam, r | 0x04, 0x12);
-
- return err ? -EIO : 0;
-}
-
-
-static int et61x251_set_scale(struct et61x251_device* cam, u8 scale)
-{
- int r = 0, err = 0;
-
- r = et61x251_read_reg(cam, 0x12);
- if (r < 0)
- err += r;
-
- if (scale == 1)
- err += et61x251_write_reg(cam, r & ~0x01, 0x12);
- else if (scale == 2)
- err += et61x251_write_reg(cam, r | 0x01, 0x12);
-
- if (err)
- return -EIO;
-
- PDBGG("Scaling factor: %u", scale);
-
- return 0;
-}
-
-
-static int
-et61x251_set_crop(struct et61x251_device* cam, struct v4l2_rect* rect)
-{
- struct et61x251_sensor* s = &cam->sensor;
- u16 fmw_sx = (u16)(rect->left - s->cropcap.bounds.left +
- s->active_pixel.left),
- fmw_sy = (u16)(rect->top - s->cropcap.bounds.top +
- s->active_pixel.top),
- fmw_length = (u16)(rect->width),
- fmw_height = (u16)(rect->height);
- int err = 0;
-
- err += et61x251_write_reg(cam, fmw_sx & 0xff, 0x69);
- err += et61x251_write_reg(cam, fmw_sy & 0xff, 0x6a);
- err += et61x251_write_reg(cam, fmw_length & 0xff, 0x6b);
- err += et61x251_write_reg(cam, fmw_height & 0xff, 0x6c);
- err += et61x251_write_reg(cam, (fmw_sx >> 8) | ((fmw_sy & 0x300) >> 6)
- | ((fmw_length & 0x300) >> 4)
- | ((fmw_height & 0x300) >> 2), 0x6d);
- if (err)
- return -EIO;
-
- PDBGG("fmw_sx, fmw_sy, fmw_length, fmw_height: %u %u %u %u",
- fmw_sx, fmw_sy, fmw_length, fmw_height);
-
- return 0;
-}
-
-
-static int et61x251_init(struct et61x251_device* cam)
-{
- struct et61x251_sensor* s = &cam->sensor;
- struct v4l2_control ctrl;
- struct v4l2_queryctrl *qctrl;
- struct v4l2_rect* rect;
- u8 i = 0;
- int err = 0;
-
- if (!(cam->state & DEV_INITIALIZED)) {
- mutex_init(&cam->open_mutex);
- init_waitqueue_head(&cam->wait_open);
- qctrl = s->qctrl;
- rect = &(s->cropcap.defrect);
- cam->compression.quality = ET61X251_COMPRESSION_QUALITY;
- } else { /* use current values */
- qctrl = s->_qctrl;
- rect = &(s->_rect);
- }
-
- err += et61x251_set_scale(cam, rect->width / s->pix_format.width);
- err += et61x251_set_crop(cam, rect);
- if (err)
- return err;
-
- if (s->init) {
- err = s->init(cam);
- if (err) {
- DBG(3, "Sensor initialization failed");
- return err;
- }
- }
-
- err += et61x251_set_compression(cam, &cam->compression);
- err += et61x251_set_pix_format(cam, &s->pix_format);
- if (s->set_pix_format)
- err += s->set_pix_format(cam, &s->pix_format);
- if (err)
- return err;
-
- if (s->pix_format.pixelformat == V4L2_PIX_FMT_ET61X251)
- DBG(3, "Compressed video format is active, quality %d",
- cam->compression.quality);
- else
- DBG(3, "Uncompressed video format is active");
-
- if (s->set_crop)
- if ((err = s->set_crop(cam, rect))) {
- DBG(3, "set_crop() failed");
- return err;
- }
-
- if (s->set_ctrl) {
- for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
- if (s->qctrl[i].id != 0 &&
- !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
- ctrl.id = s->qctrl[i].id;
- ctrl.value = qctrl[i].default_value;
- err = s->set_ctrl(cam, &ctrl);
- if (err) {
- DBG(3, "Set %s control failed",
- s->qctrl[i].name);
- return err;
- }
- DBG(3, "Image sensor supports '%s' control",
- s->qctrl[i].name);
- }
- }
-
- if (!(cam->state & DEV_INITIALIZED)) {
- mutex_init(&cam->fileop_mutex);
- spin_lock_init(&cam->queue_lock);
- init_waitqueue_head(&cam->wait_frame);
- init_waitqueue_head(&cam->wait_stream);
- cam->nreadbuffers = 2;
- memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
- memcpy(&(s->_rect), &(s->cropcap.defrect),
- sizeof(struct v4l2_rect));
- cam->state |= DEV_INITIALIZED;
- }
-
- DBG(2, "Initialization succeeded");
- return 0;
-}
-
-/*****************************************************************************/
-
-static void et61x251_release_resources(struct kref *kref)
-{
- struct et61x251_device *cam;
-
- mutex_lock(&et61x251_sysfs_lock);
-
- cam = container_of(kref, struct et61x251_device, kref);
-
- DBG(2, "V4L2 device %s deregistered",
- video_device_node_name(cam->v4ldev));
- video_set_drvdata(cam->v4ldev, NULL);
- video_unregister_device(cam->v4ldev);
- usb_put_dev(cam->usbdev);
- kfree(cam->control_buffer);
- kfree(cam);
-
- mutex_unlock(&et61x251_sysfs_lock);
-}
-
-
-static int et61x251_open(struct file *filp)
-{
- struct et61x251_device* cam;
- int err = 0;
-
- if (!down_read_trylock(&et61x251_dev_lock))
- return -ERESTARTSYS;
-
- cam = video_drvdata(filp);
-
- if (wait_for_completion_interruptible(&cam->probe)) {
- up_read(&et61x251_dev_lock);
- return -ERESTARTSYS;
- }
-
- kref_get(&cam->kref);
-
- if (mutex_lock_interruptible(&cam->open_mutex)) {
- kref_put(&cam->kref, et61x251_release_resources);
- up_read(&et61x251_dev_lock);
- return -ERESTARTSYS;
- }
-
- if (cam->state & DEV_DISCONNECTED) {
- DBG(1, "Device not present");
- err = -ENODEV;
- goto out;
- }
-
- if (cam->users) {
- DBG(2, "Device %s is already in use",
- video_device_node_name(cam->v4ldev));
- DBG(3, "Simultaneous opens are not supported");
- if ((filp->f_flags & O_NONBLOCK) ||
- (filp->f_flags & O_NDELAY)) {
- err = -EWOULDBLOCK;
- goto out;
- }
- DBG(2, "A blocking open() has been requested. Wait for the "
- "device to be released...");
- up_read(&et61x251_dev_lock);
- err = wait_event_interruptible_exclusive(cam->wait_open,
- (cam->state & DEV_DISCONNECTED)
- || !cam->users);
- down_read(&et61x251_dev_lock);
- if (err)
- goto out;
- if (cam->state & DEV_DISCONNECTED) {
- err = -ENODEV;
- goto out;
- }
- }
-
- if (cam->state & DEV_MISCONFIGURED) {
- err = et61x251_init(cam);
- if (err) {
- DBG(1, "Initialization failed again. "
- "I will retry on next open().");
- goto out;
- }
- cam->state &= ~DEV_MISCONFIGURED;
- }
-
- if ((err = et61x251_start_transfer(cam)))
- goto out;
-
- filp->private_data = cam;
- cam->users++;
- cam->io = IO_NONE;
- cam->stream = STREAM_OFF;
- cam->nbuffers = 0;
- cam->frame_count = 0;
- et61x251_empty_framequeues(cam);
-
- DBG(3, "Video device %s is open",
- video_device_node_name(cam->v4ldev));
-
-out:
- mutex_unlock(&cam->open_mutex);
- if (err)
- kref_put(&cam->kref, et61x251_release_resources);
- up_read(&et61x251_dev_lock);
- return err;
-}
-
-
-static int et61x251_release(struct file *filp)
-{
- struct et61x251_device* cam;
-
- down_write(&et61x251_dev_lock);
-
- cam = video_drvdata(filp);
-
- et61x251_stop_transfer(cam);
- et61x251_release_buffers(cam);
- cam->users--;
- wake_up_interruptible_nr(&cam->wait_open, 1);
-
- DBG(3, "Video device %s closed",
- video_device_node_name(cam->v4ldev));
-
- kref_put(&cam->kref, et61x251_release_resources);
-
- up_write(&et61x251_dev_lock);
-
- return 0;
-}
-
-
-static ssize_t
-et61x251_read(struct file* filp, char __user * buf,
- size_t count, loff_t* f_pos)
-{
- struct et61x251_device *cam = video_drvdata(filp);
- struct et61x251_frame_t* f, * i;
- unsigned long lock_flags;
- long timeout;
- int err = 0;
-
- if (mutex_lock_interruptible(&cam->fileop_mutex))
- return -ERESTARTSYS;
-
- if (cam->state & DEV_DISCONNECTED) {
- DBG(1, "Device not present");
- mutex_unlock(&cam->fileop_mutex);
- return -ENODEV;
- }
-
- if (cam->state & DEV_MISCONFIGURED) {
- DBG(1, "The camera is misconfigured. Close and open it "
- "again.");
- mutex_unlock(&cam->fileop_mutex);
- return -EIO;
- }
-
- if (cam->io == IO_MMAP) {
- DBG(3, "Close and open the device again to choose the read "
- "method");
- mutex_unlock(&cam->fileop_mutex);
- return -EBUSY;
- }
-
- if (cam->io == IO_NONE) {
- if (!et61x251_request_buffers(cam, cam->nreadbuffers,
- IO_READ)) {
- DBG(1, "read() failed, not enough memory");
- mutex_unlock(&cam->fileop_mutex);
- return -ENOMEM;
- }
- cam->io = IO_READ;
- cam->stream = STREAM_ON;
- }
-
- if (list_empty(&cam->inqueue)) {
- if (!list_empty(&cam->outqueue))
- et61x251_empty_framequeues(cam);
- et61x251_queue_unusedframes(cam);
- }
-
- if (!count) {
- mutex_unlock(&cam->fileop_mutex);
- return 0;
- }
-
- if (list_empty(&cam->outqueue)) {
- if (filp->f_flags & O_NONBLOCK) {
- mutex_unlock(&cam->fileop_mutex);
- return -EAGAIN;
- }
- timeout = wait_event_interruptible_timeout
- ( cam->wait_frame,
- (!list_empty(&cam->outqueue)) ||
- (cam->state & DEV_DISCONNECTED) ||
- (cam->state & DEV_MISCONFIGURED),
- msecs_to_jiffies(
- cam->module_param.frame_timeout * 1000
- )
- );
- if (timeout < 0) {
- mutex_unlock(&cam->fileop_mutex);
- return timeout;
- }
- if (cam->state & DEV_DISCONNECTED) {
- mutex_unlock(&cam->fileop_mutex);
- return -ENODEV;
- }
- if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
- mutex_unlock(&cam->fileop_mutex);
- return -EIO;
- }
- }
-
- f = list_entry(cam->outqueue.prev, struct et61x251_frame_t, frame);
-
- if (count > f->buf.bytesused)
- count = f->buf.bytesused;
-
- if (copy_to_user(buf, f->bufmem, count)) {
- err = -EFAULT;
- goto exit;
- }
- *f_pos += count;
-
-exit:
- spin_lock_irqsave(&cam->queue_lock, lock_flags);
- list_for_each_entry(i, &cam->outqueue, frame)
- i->state = F_UNUSED;
- INIT_LIST_HEAD(&cam->outqueue);
- spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
- et61x251_queue_unusedframes(cam);
-
- PDBGG("Frame #%lu, bytes read: %zu",
- (unsigned long)f->buf.index, count);
-
- mutex_unlock(&cam->fileop_mutex);
-
- return err ? err : count;
-}
-
-
-static unsigned int et61x251_poll(struct file *filp, poll_table *wait)
-{
- struct et61x251_device *cam = video_drvdata(filp);
- struct et61x251_frame_t* f;
- unsigned long lock_flags;
- unsigned int mask = 0;
-
- if (mutex_lock_interruptible(&cam->fileop_mutex))
- return POLLERR;
-
- if (cam->state & DEV_DISCONNECTED) {
- DBG(1, "Device not present");
- goto error;
- }
-
- if (cam->state & DEV_MISCONFIGURED) {
- DBG(1, "The camera is misconfigured. Close and open it "
- "again.");
- goto error;
- }
-
- if (cam->io == IO_NONE) {
- if (!et61x251_request_buffers(cam, cam->nreadbuffers,
- IO_READ)) {
- DBG(1, "poll() failed, not enough memory");
- goto error;
- }
- cam->io = IO_READ;
- cam->stream = STREAM_ON;
- }
-
- if (cam->io == IO_READ) {
- spin_lock_irqsave(&cam->queue_lock, lock_flags);
- list_for_each_entry(f, &cam->outqueue, frame)
- f->state = F_UNUSED;
- INIT_LIST_HEAD(&cam->outqueue);
- spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
- et61x251_queue_unusedframes(cam);
- }
-
- poll_wait(filp, &cam->wait_frame, wait);
-
- if (!list_empty(&cam->outqueue))
- mask |= POLLIN | POLLRDNORM;
-
- mutex_unlock(&cam->fileop_mutex);
-
- return mask;
-
-error:
- mutex_unlock(&cam->fileop_mutex);
- return POLLERR;
-}
-
-
-static void et61x251_vm_open(struct vm_area_struct* vma)
-{
- struct et61x251_frame_t* f = vma->vm_private_data;
- f->vma_use_count++;
-}
-
-
-static void et61x251_vm_close(struct vm_area_struct* vma)
-{
- /* NOTE: buffers are not freed here */
- struct et61x251_frame_t* f = vma->vm_private_data;
- f->vma_use_count--;
-}
-
-
-static const struct vm_operations_struct et61x251_vm_ops = {
- .open = et61x251_vm_open,
- .close = et61x251_vm_close,
-};
-
-
-static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
-{
- struct et61x251_device *cam = video_drvdata(filp);
- unsigned long size = vma->vm_end - vma->vm_start,
- start = vma->vm_start;
- void *pos;
- u32 i;
-
- if (mutex_lock_interruptible(&cam->fileop_mutex))
- return -ERESTARTSYS;
-
- if (cam->state & DEV_DISCONNECTED) {
- DBG(1, "Device not present");
- mutex_unlock(&cam->fileop_mutex);
- return -ENODEV;
- }
-
- if (cam->state & DEV_MISCONFIGURED) {
- DBG(1, "The camera is misconfigured. Close and open it "
- "again.");
- mutex_unlock(&cam->fileop_mutex);
- return -EIO;
- }
-
- if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {
- mutex_unlock(&cam->fileop_mutex);
- return -EACCES;
- }
-
- if (cam->io != IO_MMAP ||
- size != PAGE_ALIGN(cam->frame[0].buf.length)) {
- mutex_unlock(&cam->fileop_mutex);
- return -EINVAL;
- }
-
- for (i = 0; i < cam->nbuffers; i++) {
- if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
- break;
- }
- if (i == cam->nbuffers) {
- mutex_unlock(&cam->fileop_mutex);
- return -EINVAL;
- }
-
- vma->vm_flags |= VM_IO;
- vma->vm_flags |= VM_RESERVED;
-
- pos = cam->frame[i].bufmem;
- while (size > 0) { /* size is page-aligned */
- if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
- mutex_unlock(&cam->fileop_mutex);
- return -EAGAIN;
- }
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- vma->vm_ops = &et61x251_vm_ops;
- vma->vm_private_data = &cam->frame[i];
- et61x251_vm_open(vma);
-
- mutex_unlock(&cam->fileop_mutex);
-
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-et61x251_vidioc_querycap(struct et61x251_device* cam, void __user * arg)
-{
- struct v4l2_capability cap = {
- .driver = "et61x251",
- .version = LINUX_VERSION_CODE,
- .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING,
- };
-
- strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
- if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
- strlcpy(cap.bus_info, dev_name(&cam->usbdev->dev),
- sizeof(cap.bus_info));
-
- if (copy_to_user(arg, &cap, sizeof(cap)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg)
-{
- struct v4l2_input i;
-
- if (copy_from_user(&i, arg, sizeof(i)))
- return -EFAULT;
-
- if (i.index)
- return -EINVAL;
-
- memset(&i, 0, sizeof(i));
- strcpy(i.name, "Camera");
- i.type = V4L2_INPUT_TYPE_CAMERA;
- i.capabilities = V4L2_IN_CAP_STD;
-
- if (copy_to_user(arg, &i, sizeof(i)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-et61x251_vidioc_g_input(struct et61x251_device* cam, void __user * arg)
-{
- int index = 0;
-
- if (copy_to_user(arg, &index, sizeof(index)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-et61x251_vidioc_s_input(struct et61x251_device* cam, void __user * arg)
-{
- int index;
-
- if (copy_from_user(&index, arg, sizeof(index)))
- return -EFAULT;
-
- if (index != 0)
- return -EINVAL;
-
- return 0;
-}
-
-
-static int
-et61x251_vidioc_query_ctrl(struct et61x251_device* cam, void __user * arg)
-{
- struct et61x251_sensor* s = &cam->sensor;
- struct v4l2_queryctrl qc;
- u8 i;
-
- if (copy_from_user(&qc, arg, sizeof(qc)))
- return -EFAULT;
-
- for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
- if (qc.id && qc.id == s->qctrl[i].id) {
- memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
- if (copy_to_user(arg, &qc, sizeof(qc)))
- return -EFAULT;
- return 0;
- }
-
- return -EINVAL;
-}
-
-
-static int
-et61x251_vidioc_g_ctrl(struct et61x251_device* cam, void __user * arg)
-{
- struct et61x251_sensor* s = &cam->sensor;
- struct v4l2_control ctrl;
- int err = 0;
- u8 i;
-
- if (!s->get_ctrl && !s->set_ctrl)
- return -EINVAL;
-
- if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
- return -EFAULT;
-
- if (!s->get_ctrl) {
- for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
- if (ctrl.id == s->qctrl[i].id) {
- ctrl.value = s->_qctrl[i].default_value;
- goto exit;
- }
- return -EINVAL;
- } else
- err = s->get_ctrl(cam, &ctrl);
-
-exit:
- if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
- return -EFAULT;
-
- return err;
-}
-
-
-static int
-et61x251_vidioc_s_ctrl(struct et61x251_device* cam, void __user * arg)
-{
- struct et61x251_sensor* s = &cam->sensor;
- struct v4l2_control ctrl;
- u8 i;
- int err = 0;
-
- if (!s->set_ctrl)
- return -EINVAL;
-
- if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
- return -EFAULT;
-
- for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) {
- if (ctrl.id == s->qctrl[i].id) {
- if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
- return -EINVAL;
- if (ctrl.value < s->qctrl[i].minimum ||
- ctrl.value > s->qctrl[i].maximum)
- return -ERANGE;
- ctrl.value -= ctrl.value % s->qctrl[i].step;
- break;
- }
- }
- if (i == ARRAY_SIZE(s->qctrl))
- return -EINVAL;
- if ((err = s->set_ctrl(cam, &ctrl)))
- return err;
-
- s->_qctrl[i].default_value = ctrl.value;
-
- return 0;
-}
-
-
-static int
-et61x251_vidioc_cropcap(struct et61x251_device* cam, void __user * arg)
-{
- struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
-
- cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- cc->pixelaspect.numerator = 1;
- cc->pixelaspect.denominator = 1;
-
- if (copy_to_user(arg, cc, sizeof(*cc)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-et61x251_vidioc_g_crop(struct et61x251_device* cam, void __user * arg)
-{
- struct et61x251_sensor* s = &cam->sensor;
- struct v4l2_crop crop = {
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- };
-
- memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
-
- if (copy_to_user(arg, &crop, sizeof(crop)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
-{
- struct et61x251_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);
- u8 scale;
- const enum et61x251_stream_state stream = cam->stream;
- const u32 nbuffers = cam->nbuffers;
- u32 i;
- int err = 0;
-
- if (copy_from_user(&crop, arg, sizeof(crop)))
- return -EFAULT;
-
- rect = &(crop.c);
-
- if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (cam->module_param.force_munmap)
- for (i = 0; i < cam->nbuffers; i++)
- if (cam->frame[i].vma_use_count) {
- DBG(3, "VIDIOC_S_CROP failed. "
- "Unmap the buffers first.");
- return -EBUSY;
- }
-
- /* Preserve R,G or B origin */
- rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L;
- rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L;
-
- if (rect->width < 16)
- rect->width = 16;
- if (rect->height < 16)
- rect->height = 16;
- if (rect->width > bounds->width)
- rect->width = bounds->width;
- if (rect->height > bounds->height)
- rect->height = bounds->height;
- if (rect->left < bounds->left)
- rect->left = bounds->left;
- if (rect->top < bounds->top)
- rect->top = bounds->top;
- if (rect->left + rect->width > bounds->left + bounds->width)
- rect->left = bounds->left+bounds->width - rect->width;
- if (rect->top + rect->height > bounds->top + bounds->height)
- rect->top = bounds->top+bounds->height - rect->height;
-
- rect->width &= ~15L;
- rect->height &= ~15L;
-
- if (ET61X251_PRESERVE_IMGSCALE) {
- /* Calculate the actual scaling factor */
- u32 a, b;
- a = rect->width * rect->height;
- b = pix_format->width * pix_format->height;
- scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;
- } else
- scale = 1;
-
- if (cam->stream == STREAM_ON)
- if ((err = et61x251_stream_interrupt(cam)))
- return err;
-
- if (copy_to_user(arg, &crop, sizeof(crop))) {
- cam->stream = stream;
- return -EFAULT;
- }
-
- if (cam->module_param.force_munmap || cam->io == IO_READ)
- et61x251_release_buffers(cam);
-
- err = et61x251_set_crop(cam, rect);
- if (s->set_crop)
- err += s->set_crop(cam, rect);
- err += et61x251_set_scale(cam, scale);
-
- if (err) { /* atomic, no rollback in ioctl() */
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
- "use the camera, close and open %s again.",
- video_device_node_name(cam->v4ldev));
- return -EIO;
- }
-
- s->pix_format.width = rect->width/scale;
- s->pix_format.height = rect->height/scale;
- memcpy(&(s->_rect), rect, sizeof(*rect));
-
- if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
- nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) {
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
- "use the camera, close and open %s again.",
- video_device_node_name(cam->v4ldev));
- return -ENOMEM;
- }
-
- if (cam->io == IO_READ)
- et61x251_empty_framequeues(cam);
- else if (cam->module_param.force_munmap)
- et61x251_requeue_outqueue(cam);
-
- cam->stream = stream;
-
- return 0;
-}
-
-
-static int
-et61x251_vidioc_enum_framesizes(struct et61x251_device* cam, void __user * arg)
-{
- struct v4l2_frmsizeenum frmsize;
-
- if (copy_from_user(&frmsize, arg, sizeof(frmsize)))
- return -EFAULT;
-
- if (frmsize.index != 0)
- return -EINVAL;
-
- if (frmsize.pixel_format != V4L2_PIX_FMT_ET61X251 &&
- frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8)
- return -EINVAL;
-
- frmsize.type = V4L2_FRMSIZE_TYPE_STEPWISE;
- frmsize.stepwise.min_width = frmsize.stepwise.step_width = 16;
- frmsize.stepwise.min_height = frmsize.stepwise.step_height = 16;
- frmsize.stepwise.max_width = cam->sensor.cropcap.bounds.width;
- frmsize.stepwise.max_height = cam->sensor.cropcap.bounds.height;
- memset(&frmsize.reserved, 0, sizeof(frmsize.reserved));
-
- if (copy_to_user(arg, &frmsize, sizeof(frmsize)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-et61x251_vidioc_enum_fmt(struct et61x251_device* cam, void __user * arg)
-{
- struct v4l2_fmtdesc fmtd;
-
- if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
- return -EFAULT;
-
- if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (fmtd.index == 0) {
- strcpy(fmtd.description, "bayer rgb");
- fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
- } else if (fmtd.index == 1) {
- strcpy(fmtd.description, "compressed");
- fmtd.pixelformat = V4L2_PIX_FMT_ET61X251;
- fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
- } else
- return -EINVAL;
-
- fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
-
- if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg)
-{
- struct v4l2_format format;
- struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
-
- if (copy_from_user(&format, arg, sizeof(format)))
- return -EFAULT;
-
- if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_ET61X251) ?
- 0 : V4L2_COLORSPACE_SRGB;
- pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_ET61X251)
- ? 0 : (pfmt->width * pfmt->priv) / 8;
- pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
- pfmt->field = V4L2_FIELD_NONE;
- memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
-
- if (copy_to_user(arg, &format, sizeof(format)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
- void __user * arg)
-{
- struct et61x251_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_rect rect;
- u8 scale;
- const enum et61x251_stream_state stream = cam->stream;
- const u32 nbuffers = cam->nbuffers;
- u32 i;
- int err = 0;
-
- if (copy_from_user(&format, arg, sizeof(format)))
- return -EFAULT;
-
- pix = &(format.fmt.pix);
-
- if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- memcpy(&rect, &(s->_rect), sizeof(rect));
-
- { /* calculate the actual scaling factor */
- u32 a, b;
- a = rect.width * rect.height;
- b = pix->width * pix->height;
- scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;
- }
-
- rect.width = scale * pix->width;
- rect.height = scale * pix->height;
-
- if (rect.width < 16)
- rect.width = 16;
- if (rect.height < 16)
- rect.height = 16;
- if (rect.width > bounds->left + bounds->width - rect.left)
- rect.width = bounds->left + bounds->width - rect.left;
- if (rect.height > bounds->top + bounds->height - rect.top)
- rect.height = bounds->top + bounds->height - rect.top;
-
- rect.width &= ~15L;
- rect.height &= ~15L;
-
- { /* adjust the scaling factor */
- u32 a, b;
- a = rect.width * rect.height;
- b = pix->width * pix->height;
- scale = b ? (u8)((a / b) < 4 ? 1 : 2) : 1;
- }
-
- pix->width = rect.width / scale;
- pix->height = rect.height / scale;
-
- if (pix->pixelformat != V4L2_PIX_FMT_ET61X251 &&
- pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
- pix->pixelformat = pfmt->pixelformat;
- pix->priv = pfmt->priv; /* bpp */
- pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_ET61X251) ?
- 0 : V4L2_COLORSPACE_SRGB;
- pix->colorspace = pfmt->colorspace;
- pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_ET61X251)
- ? 0 : (pix->width * pix->priv) / 8;
- pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
- pix->field = V4L2_FIELD_NONE;
-
- if (cmd == VIDIOC_TRY_FMT) {
- if (copy_to_user(arg, &format, sizeof(format)))
- return -EFAULT;
- return 0;
- }
-
- if (cam->module_param.force_munmap)
- for (i = 0; i < cam->nbuffers; i++)
- if (cam->frame[i].vma_use_count) {
- DBG(3, "VIDIOC_S_FMT failed. "
- "Unmap the buffers first.");
- return -EBUSY;
- }
-
- if (cam->stream == STREAM_ON)
- if ((err = et61x251_stream_interrupt(cam)))
- return err;
-
- if (copy_to_user(arg, &format, sizeof(format))) {
- cam->stream = stream;
- return -EFAULT;
- }
-
- if (cam->module_param.force_munmap || cam->io == IO_READ)
- et61x251_release_buffers(cam);
-
- err += et61x251_set_pix_format(cam, pix);
- err += et61x251_set_crop(cam, &rect);
- if (s->set_pix_format)
- err += s->set_pix_format(cam, pix);
- if (s->set_crop)
- err += s->set_crop(cam, &rect);
- err += et61x251_set_scale(cam, scale);
-
- if (err) { /* atomic, no rollback in ioctl() */
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
- "use the camera, close and open %s again.",
- video_device_node_name(cam->v4ldev));
- return -EIO;
- }
-
- memcpy(pfmt, pix, sizeof(*pix));
- memcpy(&(s->_rect), &rect, sizeof(rect));
-
- if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
- nbuffers != et61x251_request_buffers(cam, nbuffers, cam->io)) {
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
- "use the camera, close and open %s again.",
- video_device_node_name(cam->v4ldev));
- return -ENOMEM;
- }
-
- if (cam->io == IO_READ)
- et61x251_empty_framequeues(cam);
- else if (cam->module_param.force_munmap)
- et61x251_requeue_outqueue(cam);
-
- cam->stream = stream;
-
- return 0;
-}
-
-
-static int
-et61x251_vidioc_g_jpegcomp(struct et61x251_device* cam, void __user * arg)
-{
- if (copy_to_user(arg, &cam->compression,
- sizeof(cam->compression)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-et61x251_vidioc_s_jpegcomp(struct et61x251_device* cam, void __user * arg)
-{
- struct v4l2_jpegcompression jc;
- const enum et61x251_stream_state stream = cam->stream;
- int err = 0;
-
- if (copy_from_user(&jc, arg, sizeof(jc)))
- return -EFAULT;
-
- if (jc.quality != 0 && jc.quality != 1)
- return -EINVAL;
-
- if (cam->stream == STREAM_ON)
- if ((err = et61x251_stream_interrupt(cam)))
- return err;
-
- err += et61x251_set_compression(cam, &jc);
- if (err) { /* atomic, no rollback in ioctl() */
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
- "problems. To use the camera, close and open "
- "%s again.", video_device_node_name(cam->v4ldev));
- return -EIO;
- }
-
- cam->compression.quality = jc.quality;
-
- cam->stream = stream;
-
- return 0;
-}
-
-
-static int
-et61x251_vidioc_reqbufs(struct et61x251_device* cam, void __user * arg)
-{
- struct v4l2_requestbuffers rb;
- u32 i;
- int err;
-
- if (copy_from_user(&rb, arg, sizeof(rb)))
- return -EFAULT;
-
- if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- rb.memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
-
- if (cam->io == IO_READ) {
- DBG(3, "Close and open the device again to choose the mmap "
- "I/O method");
- return -EBUSY;
- }
-
- for (i = 0; i < cam->nbuffers; i++)
- if (cam->frame[i].vma_use_count) {
- DBG(3, "VIDIOC_REQBUFS failed. "
- "Previous buffers are still mapped.");
- return -EBUSY;
- }
-
- if (cam->stream == STREAM_ON)
- if ((err = et61x251_stream_interrupt(cam)))
- return err;
-
- et61x251_empty_framequeues(cam);
-
- et61x251_release_buffers(cam);
- if (rb.count)
- rb.count = et61x251_request_buffers(cam, rb.count, IO_MMAP);
-
- if (copy_to_user(arg, &rb, sizeof(rb))) {
- et61x251_release_buffers(cam);
- cam->io = IO_NONE;
- return -EFAULT;
- }
-
- cam->io = rb.count ? IO_MMAP : IO_NONE;
-
- return 0;
-}
-
-
-static int
-et61x251_vidioc_querybuf(struct et61x251_device* cam, void __user * arg)
-{
- struct v4l2_buffer b;
-
- if (copy_from_user(&b, arg, sizeof(b)))
- return -EFAULT;
-
- if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- b.index >= cam->nbuffers || cam->io != IO_MMAP)
- return -EINVAL;
-
- memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
-
- if (cam->frame[b.index].vma_use_count)
- b.flags |= V4L2_BUF_FLAG_MAPPED;
-
- if (cam->frame[b.index].state == F_DONE)
- b.flags |= V4L2_BUF_FLAG_DONE;
- else if (cam->frame[b.index].state != F_UNUSED)
- b.flags |= V4L2_BUF_FLAG_QUEUED;
-
- if (copy_to_user(arg, &b, sizeof(b)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-et61x251_vidioc_qbuf(struct et61x251_device* cam, void __user * arg)
-{
- struct v4l2_buffer b;
- unsigned long lock_flags;
-
- if (copy_from_user(&b, arg, sizeof(b)))
- return -EFAULT;
-
- if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- b.index >= cam->nbuffers || cam->io != IO_MMAP)
- return -EINVAL;
-
- if (cam->frame[b.index].state != F_UNUSED)
- return -EINVAL;
-
- cam->frame[b.index].state = F_QUEUED;
-
- spin_lock_irqsave(&cam->queue_lock, lock_flags);
- list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
- spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
- PDBGG("Frame #%lu queued", (unsigned long)b.index);
-
- return 0;
-}
-
-
-static int
-et61x251_vidioc_dqbuf(struct et61x251_device* cam, struct file* filp,
- void __user * arg)
-{
- struct v4l2_buffer b;
- struct et61x251_frame_t *f;
- unsigned long lock_flags;
- long timeout;
-
- if (copy_from_user(&b, arg, sizeof(b)))
- return -EFAULT;
-
- if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP)
- return -EINVAL;
-
- if (list_empty(&cam->outqueue)) {
- if (cam->stream == STREAM_OFF)
- return -EINVAL;
- if (filp->f_flags & O_NONBLOCK)
- return -EAGAIN;
- timeout = wait_event_interruptible_timeout
- ( 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) );
- if (timeout < 0)
- return timeout;
- if (cam->state & DEV_DISCONNECTED)
- return -ENODEV;
- if (!timeout || (cam->state & DEV_MISCONFIGURED))
- return -EIO;
- }
-
- spin_lock_irqsave(&cam->queue_lock, lock_flags);
- f = list_entry(cam->outqueue.next, struct et61x251_frame_t, frame);
- list_del(cam->outqueue.next);
- spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
- f->state = F_UNUSED;
-
- memcpy(&b, &f->buf, sizeof(b));
- if (f->vma_use_count)
- b.flags |= V4L2_BUF_FLAG_MAPPED;
-
- if (copy_to_user(arg, &b, sizeof(b)))
- return -EFAULT;
-
- PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
-
- return 0;
-}
-
-
-static int
-et61x251_vidioc_streamon(struct et61x251_device* cam, void __user * arg)
-{
- int type;
-
- if (copy_from_user(&type, arg, sizeof(type)))
- return -EFAULT;
-
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
- return -EINVAL;
-
- cam->stream = STREAM_ON;
-
- DBG(3, "Stream on");
-
- return 0;
-}
-
-
-static int
-et61x251_vidioc_streamoff(struct et61x251_device* cam, void __user * arg)
-{
- int type, err;
-
- if (copy_from_user(&type, arg, sizeof(type)))
- return -EFAULT;
-
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
- return -EINVAL;
-
- if (cam->stream == STREAM_ON)
- if ((err = et61x251_stream_interrupt(cam)))
- return err;
-
- et61x251_empty_framequeues(cam);
-
- DBG(3, "Stream off");
-
- return 0;
-}
-
-
-static int
-et61x251_vidioc_g_parm(struct et61x251_device* cam, void __user * arg)
-{
- struct v4l2_streamparm sp;
-
- if (copy_from_user(&sp, arg, sizeof(sp)))
- return -EFAULT;
-
- if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- sp.parm.capture.extendedmode = 0;
- sp.parm.capture.readbuffers = cam->nreadbuffers;
-
- if (copy_to_user(arg, &sp, sizeof(sp)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-et61x251_vidioc_s_parm(struct et61x251_device* cam, void __user * arg)
-{
- struct v4l2_streamparm sp;
-
- if (copy_from_user(&sp, arg, sizeof(sp)))
- return -EFAULT;
-
- if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- sp.parm.capture.extendedmode = 0;
-
- if (sp.parm.capture.readbuffers == 0)
- sp.parm.capture.readbuffers = cam->nreadbuffers;
-
- if (sp.parm.capture.readbuffers > ET61X251_MAX_FRAMES)
- sp.parm.capture.readbuffers = ET61X251_MAX_FRAMES;
-
- if (copy_to_user(arg, &sp, sizeof(sp)))
- return -EFAULT;
-
- cam->nreadbuffers = sp.parm.capture.readbuffers;
-
- return 0;
-}
-
-
-static long et61x251_ioctl_v4l2(struct file *filp,
- unsigned int cmd, void __user *arg)
-{
- struct et61x251_device *cam = video_drvdata(filp);
-
- switch (cmd) {
-
- case VIDIOC_QUERYCAP:
- return et61x251_vidioc_querycap(cam, arg);
-
- case VIDIOC_ENUMINPUT:
- return et61x251_vidioc_enuminput(cam, arg);
-
- case VIDIOC_G_INPUT:
- return et61x251_vidioc_g_input(cam, arg);
-
- case VIDIOC_S_INPUT:
- return et61x251_vidioc_s_input(cam, arg);
-
- case VIDIOC_QUERYCTRL:
- return et61x251_vidioc_query_ctrl(cam, arg);
-
- case VIDIOC_G_CTRL:
- return et61x251_vidioc_g_ctrl(cam, arg);
-
- case VIDIOC_S_CTRL:
- return et61x251_vidioc_s_ctrl(cam, arg);
-
- case VIDIOC_CROPCAP:
- return et61x251_vidioc_cropcap(cam, arg);
-
- case VIDIOC_G_CROP:
- return et61x251_vidioc_g_crop(cam, arg);
-
- case VIDIOC_S_CROP:
- return et61x251_vidioc_s_crop(cam, arg);
-
- case VIDIOC_ENUM_FMT:
- return et61x251_vidioc_enum_fmt(cam, arg);
-
- case VIDIOC_G_FMT:
- return et61x251_vidioc_g_fmt(cam, arg);
-
- case VIDIOC_TRY_FMT:
- case VIDIOC_S_FMT:
- return et61x251_vidioc_try_s_fmt(cam, cmd, arg);
-
- case VIDIOC_ENUM_FRAMESIZES:
- return et61x251_vidioc_enum_framesizes(cam, arg);
-
- case VIDIOC_G_JPEGCOMP:
- return et61x251_vidioc_g_jpegcomp(cam, arg);
-
- case VIDIOC_S_JPEGCOMP:
- return et61x251_vidioc_s_jpegcomp(cam, arg);
-
- case VIDIOC_REQBUFS:
- return et61x251_vidioc_reqbufs(cam, arg);
-
- case VIDIOC_QUERYBUF:
- return et61x251_vidioc_querybuf(cam, arg);
-
- case VIDIOC_QBUF:
- return et61x251_vidioc_qbuf(cam, arg);
-
- case VIDIOC_DQBUF:
- return et61x251_vidioc_dqbuf(cam, filp, arg);
-
- case VIDIOC_STREAMON:
- return et61x251_vidioc_streamon(cam, arg);
-
- case VIDIOC_STREAMOFF:
- return et61x251_vidioc_streamoff(cam, arg);
-
- case VIDIOC_G_PARM:
- return et61x251_vidioc_g_parm(cam, arg);
-
- case VIDIOC_S_PARM:
- return et61x251_vidioc_s_parm(cam, arg);
-
- default:
- return -ENOTTY;
-
- }
-}
-
-
-static long et61x251_ioctl(struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct et61x251_device *cam = video_drvdata(filp);
- long err = 0;
-
- if (mutex_lock_interruptible(&cam->fileop_mutex))
- return -ERESTARTSYS;
-
- if (cam->state & DEV_DISCONNECTED) {
- DBG(1, "Device not present");
- mutex_unlock(&cam->fileop_mutex);
- return -ENODEV;
- }
-
- if (cam->state & DEV_MISCONFIGURED) {
- DBG(1, "The camera is misconfigured. Close and open it "
- "again.");
- mutex_unlock(&cam->fileop_mutex);
- return -EIO;
- }
-
- V4LDBG(3, "et61x251", cmd);
-
- err = et61x251_ioctl_v4l2(filp, cmd, (void __user *)arg);
-
- mutex_unlock(&cam->fileop_mutex);
-
- return err;
-}
-
-
-static const struct v4l2_file_operations et61x251_fops = {
- .owner = THIS_MODULE,
- .open = et61x251_open,
- .release = et61x251_release,
- .unlocked_ioctl = et61x251_ioctl,
- .read = et61x251_read,
- .poll = et61x251_poll,
- .mmap = et61x251_mmap,
-};
-
-/*****************************************************************************/
-
-/* It exists a single interface only. We do not need to validate anything. */
-static int
-et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
-{
- struct usb_device *udev = interface_to_usbdev(intf);
- struct et61x251_device* cam;
- static unsigned int dev_nr;
- unsigned int i;
- int err = 0;
-
- if (!(cam = kzalloc(sizeof(struct et61x251_device), GFP_KERNEL)))
- return -ENOMEM;
-
- cam->usbdev = udev;
-
- if (!(cam->control_buffer = kzalloc(8, GFP_KERNEL))) {
- DBG(1, "kmalloc() failed");
- err = -ENOMEM;
- goto fail;
- }
-
- if (!(cam->v4ldev = video_device_alloc())) {
- DBG(1, "video_device_alloc() failed");
- err = -ENOMEM;
- goto fail;
- }
-
- DBG(2, "ET61X[12]51 PC Camera Controller detected "
- "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
-
- for (i = 0; et61x251_sensor_table[i]; i++) {
- err = et61x251_sensor_table[i](cam);
- if (!err)
- break;
- }
-
- if (!err)
- DBG(2, "%s image sensor detected", cam->sensor.name);
- else {
- DBG(1, "No supported image sensor detected");
- err = -ENODEV;
- goto fail;
- }
-
- if (et61x251_init(cam)) {
- DBG(1, "Initialization failed. I will retry on open().");
- cam->state |= DEV_MISCONFIGURED;
- }
-
- strcpy(cam->v4ldev->name, "ET61X[12]51 PC Camera");
- cam->v4ldev->fops = &et61x251_fops;
- cam->v4ldev->release = video_device_release;
- cam->v4ldev->parent = &udev->dev;
- video_set_drvdata(cam->v4ldev, cam);
-
- init_completion(&cam->probe);
-
- err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
- video_nr[dev_nr]);
- if (err) {
- DBG(1, "V4L2 device registration failed");
- if (err == -ENFILE && video_nr[dev_nr] == -1)
- DBG(1, "Free /dev/videoX node not found");
- video_nr[dev_nr] = -1;
- dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
- complete_all(&cam->probe);
- goto fail;
- }
-
- DBG(2, "V4L2 device registered as %s",
- video_device_node_name(cam->v4ldev));
-
- cam->module_param.force_munmap = force_munmap[dev_nr];
- cam->module_param.frame_timeout = frame_timeout[dev_nr];
-
- dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- err = et61x251_create_sysfs(cam);
- if (!err)
- DBG(2, "Optional device control through 'sysfs' "
- "interface ready");
- else
- DBG(2, "Failed to create 'sysfs' interface for optional "
- "device controlling. Error #%d", err);
-#else
- DBG(2, "Optional device control through 'sysfs' interface disabled");
- DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' "
- "configuration option to enable it.");
-#endif
-
- usb_set_intfdata(intf, cam);
- kref_init(&cam->kref);
- usb_get_dev(cam->usbdev);
-
- complete_all(&cam->probe);
-
- return 0;
-
-fail:
- if (cam) {
- kfree(cam->control_buffer);
- if (cam->v4ldev)
- video_device_release(cam->v4ldev);
- kfree(cam);
- }
- return err;
-}
-
-
-static void et61x251_usb_disconnect(struct usb_interface* intf)
-{
- struct et61x251_device* cam;
-
- down_write(&et61x251_dev_lock);
-
- cam = usb_get_intfdata(intf);
-
- DBG(2, "Disconnecting %s...", cam->v4ldev->name);
-
- if (cam->users) {
- DBG(2, "Device %s is open! Deregistration and memory "
- "deallocation are deferred.",
- video_device_node_name(cam->v4ldev));
- cam->state |= DEV_MISCONFIGURED;
- et61x251_stop_transfer(cam);
- cam->state |= DEV_DISCONNECTED;
- wake_up_interruptible(&cam->wait_frame);
- wake_up(&cam->wait_stream);
- } else
- cam->state |= DEV_DISCONNECTED;
-
- wake_up_interruptible_all(&cam->wait_open);
-
- kref_put(&cam->kref, et61x251_release_resources);
-
- up_write(&et61x251_dev_lock);
-}
-
-
-static struct usb_driver et61x251_usb_driver = {
- .name = "et61x251",
- .id_table = et61x251_id_table,
- .probe = et61x251_usb_probe,
- .disconnect = et61x251_usb_disconnect,
-};
-
-module_usb_driver(et61x251_usb_driver);
diff --git a/drivers/media/video/et61x251/et61x251_sensor.h b/drivers/media/video/et61x251/et61x251_sensor.h
deleted file mode 100644
index 71a03148cb09..000000000000
--- a/drivers/media/video/et61x251/et61x251_sensor.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/***************************************************************************
- * API for image sensors connected to ET61X[12]51 PC Camera Controllers *
- * *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#ifndef _ET61X251_SENSOR_H_
-#define _ET61X251_SENSOR_H_
-
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <linux/device.h>
-#include <linux/stddef.h>
-#include <linux/errno.h>
-#include <asm/types.h>
-
-struct et61x251_device;
-struct et61x251_sensor;
-
-/*****************************************************************************/
-
-extern int et61x251_probe_tas5130d1b(struct et61x251_device* cam);
-
-#define ET61X251_SENSOR_TABLE \
-/* Weak detections must go at the end of the list */ \
-static int (*et61x251_sensor_table[])(struct et61x251_device*) = { \
- &et61x251_probe_tas5130d1b, \
- NULL, \
-};
-
-extern struct et61x251_device*
-et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id);
-
-extern void
-et61x251_attach_sensor(struct et61x251_device* cam,
- const struct et61x251_sensor* sensor);
-
-/*****************************************************************************/
-
-extern int et61x251_write_reg(struct et61x251_device*, u8 value, u16 index);
-extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1,
- u8 data2, u8 data3, u8 data4, u8 data5,
- u8 data6, u8 data7, u8 data8, u8 address);
-
-/*****************************************************************************/
-
-enum et61x251_i2c_sysfs_ops {
- ET61X251_I2C_READ = 0x01,
- ET61X251_I2C_WRITE = 0x02,
-};
-
-enum et61x251_i2c_interface {
- ET61X251_I2C_2WIRES,
- ET61X251_I2C_3WIRES,
-};
-
-/* Repeat start condition when RSTA is high */
-enum et61x251_i2c_rsta {
- ET61X251_I2C_RSTA_STOP = 0x00, /* stop then start */
- ET61X251_I2C_RSTA_REPEAT = 0x01, /* repeat start */
-};
-
-#define ET61X251_MAX_CTRLS (V4L2_CID_LASTP1-V4L2_CID_BASE+10)
-
-struct et61x251_sensor {
- char name[32];
-
- enum et61x251_i2c_sysfs_ops sysfs_ops;
-
- enum et61x251_i2c_interface interface;
- u8 i2c_slave_id;
- enum et61x251_i2c_rsta rsta;
- struct v4l2_rect active_pixel; /* left and top define FVSX and FVSY */
-
- struct v4l2_queryctrl qctrl[ET61X251_MAX_CTRLS];
- struct v4l2_cropcap cropcap;
- struct v4l2_pix_format pix_format;
-
- int (*init)(struct et61x251_device* cam);
- int (*get_ctrl)(struct et61x251_device* cam,
- struct v4l2_control* ctrl);
- int (*set_ctrl)(struct et61x251_device* cam,
- const struct v4l2_control* ctrl);
- int (*set_crop)(struct et61x251_device* cam,
- const struct v4l2_rect* rect);
- int (*set_pix_format)(struct et61x251_device* cam,
- const struct v4l2_pix_format* pix);
-
- /* Private */
- struct v4l2_queryctrl _qctrl[ET61X251_MAX_CTRLS];
- struct v4l2_rect _rect;
-};
-
-#endif /* _ET61X251_SENSOR_H_ */
diff --git a/drivers/media/video/et61x251/et61x251_tas5130d1b.c b/drivers/media/video/et61x251/et61x251_tas5130d1b.c
deleted file mode 100644
index ced2e167935d..000000000000
--- a/drivers/media/video/et61x251/et61x251_tas5130d1b.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/***************************************************************************
- * Plug-in for TAS5130D1B image sensor connected to the ET61X[12]51 *
- * PC Camera Controllers *
- * *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include "et61x251_sensor.h"
-
-
-static int tas5130d1b_init(struct et61x251_device* cam)
-{
- int err = 0;
-
- err += et61x251_write_reg(cam, 0x14, 0x01);
- err += et61x251_write_reg(cam, 0x1b, 0x02);
- err += et61x251_write_reg(cam, 0x02, 0x12);
- err += et61x251_write_reg(cam, 0x0e, 0x60);
- err += et61x251_write_reg(cam, 0x80, 0x61);
- err += et61x251_write_reg(cam, 0xf0, 0x62);
- err += et61x251_write_reg(cam, 0x03, 0x63);
- err += et61x251_write_reg(cam, 0x14, 0x64);
- err += et61x251_write_reg(cam, 0xf4, 0x65);
- err += et61x251_write_reg(cam, 0x01, 0x66);
- err += et61x251_write_reg(cam, 0x05, 0x67);
- err += et61x251_write_reg(cam, 0x8f, 0x68);
- err += et61x251_write_reg(cam, 0x0f, 0x8d);
- err += et61x251_write_reg(cam, 0x08, 0x8e);
-
- return err;
-}
-
-
-static int tas5130d1b_set_ctrl(struct et61x251_device* cam,
- const struct v4l2_control* ctrl)
-{
- int err = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_GAIN:
- err += et61x251_i2c_raw_write(cam, 2, 0x20,
- 0xf6-ctrl->value, 0, 0, 0,
- 0, 0, 0, 0);
- break;
- case V4L2_CID_EXPOSURE:
- err += et61x251_i2c_raw_write(cam, 2, 0x40,
- 0x47-ctrl->value, 0, 0, 0,
- 0, 0, 0, 0);
- break;
- default:
- return -EINVAL;
- }
-
- return err ? -EIO : 0;
-}
-
-
-static const struct et61x251_sensor tas5130d1b = {
- .name = "TAS5130D1B",
- .interface = ET61X251_I2C_3WIRES,
- .rsta = ET61X251_I2C_RSTA_STOP,
- .active_pixel = {
- .left = 106,
- .top = 13,
- },
- .init = &tas5130d1b_init,
- .qctrl = {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "global gain",
- .minimum = 0x00,
- .maximum = 0xf6,
- .step = 0x02,
- .default_value = 0x0d,
- .flags = 0,
- },
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x00,
- .maximum = 0x47,
- .step = 0x01,
- .default_value = 0x23,
- .flags = 0,
- },
- },
- .set_ctrl = &tas5130d1b_set_ctrl,
- .cropcap = {
- .bounds = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- .defrect = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- },
- .pix_format = {
- .width = 640,
- .height = 480,
- .pixelformat = V4L2_PIX_FMT_SBGGR8,
- .priv = 8,
- },
-};
-
-
-int et61x251_probe_tas5130d1b(struct et61x251_device* cam)
-{
- const struct usb_device_id tas5130d1b_id_table[] = {
- { USB_DEVICE(0x102c, 0x6251), },
- { }
- };
-
- /* Sensor detection is based on USB pid/vid */
- if (!et61x251_match_id(cam, tas5130d1b_id_table))
- return -ENODEV;
-
- et61x251_attach_sensor(cam, &tas5130d1b);
-
- return 0;
-}
diff --git a/drivers/media/video/fsl-viu.c b/drivers/media/video/fsl-viu.c
index 27e3e0c0b219..777486f7cadb 100644
--- a/drivers/media/video/fsl-viu.c
+++ b/drivers/media/video/fsl-viu.c
@@ -1544,6 +1544,10 @@ static int __devinit viu_of_probe(struct platform_device *op)
/* initialize locks */
mutex_init(&viu_dev->lock);
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &viu_dev->vdev->flags);
viu_dev->vdev->lock = &viu_dev->lock;
spin_lock_init(&viu_dev->slock);
diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile
index 79ebe46e1ad7..c901da0bd657 100644
--- a/drivers/media/video/gspca/Makefile
+++ b/drivers/media/video/gspca/Makefile
@@ -43,7 +43,7 @@ obj-$(CONFIG_USB_GSPCA_VICAM) += gspca_vicam.o
obj-$(CONFIG_USB_GSPCA_XIRLINK_CIT) += gspca_xirlink_cit.o
obj-$(CONFIG_USB_GSPCA_ZC3XX) += gspca_zc3xx.o
-gspca_main-objs := gspca.o
+gspca_main-objs := gspca.o autogain_functions.o
gspca_benq-objs := benq.o
gspca_conex-objs := conex.o
gspca_cpia1-objs := cpia1.o
diff --git a/drivers/media/video/gspca/autogain_functions.c b/drivers/media/video/gspca/autogain_functions.c
new file mode 100644
index 000000000000..67db674bb044
--- /dev/null
+++ b/drivers/media/video/gspca/autogain_functions.c
@@ -0,0 +1,178 @@
+/*
+ * Functions for auto gain.
+ *
+ * Copyright (C) 2010-2012 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include "gspca.h"
+
+/* auto gain and exposure algorithm based on the knee algorithm described here:
+ http://ytse.tricolour.net/docs/LowLightOptimization.html
+
+ Returns 0 if no changes were made, 1 if the gain and or exposure settings
+ where changed. */
+int gspca_expo_autogain(
+ struct gspca_dev *gspca_dev,
+ int avg_lum,
+ int desired_avg_lum,
+ int deadzone,
+ int gain_knee,
+ int exposure_knee)
+{
+ s32 gain, orig_gain, exposure, orig_exposure;
+ int i, steps, retval = 0;
+
+ if (v4l2_ctrl_g_ctrl(gspca_dev->autogain) == 0)
+ return 0;
+
+ orig_gain = gain = v4l2_ctrl_g_ctrl(gspca_dev->gain);
+ orig_exposure = exposure = v4l2_ctrl_g_ctrl(gspca_dev->exposure);
+
+ /* If we are of a multiple of deadzone, do multiple steps to reach the
+ desired lumination fast (with the risc of a slight overshoot) */
+ steps = abs(desired_avg_lum - avg_lum) / deadzone;
+
+ PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d",
+ avg_lum, desired_avg_lum, steps);
+
+ for (i = 0; i < steps; i++) {
+ if (avg_lum > desired_avg_lum) {
+ if (gain > gain_knee)
+ gain--;
+ else if (exposure > exposure_knee)
+ exposure--;
+ else if (gain > gspca_dev->gain->default_value)
+ gain--;
+ else if (exposure > gspca_dev->exposure->minimum)
+ exposure--;
+ else if (gain > gspca_dev->gain->minimum)
+ gain--;
+ else
+ break;
+ } else {
+ if (gain < gspca_dev->gain->default_value)
+ gain++;
+ else if (exposure < exposure_knee)
+ exposure++;
+ else if (gain < gain_knee)
+ gain++;
+ else if (exposure < gspca_dev->exposure->maximum)
+ exposure++;
+ else if (gain < gspca_dev->gain->maximum)
+ gain++;
+ else
+ break;
+ }
+ }
+
+ if (gain != orig_gain) {
+ v4l2_ctrl_s_ctrl(gspca_dev->gain, gain);
+ retval = 1;
+ }
+ if (exposure != orig_exposure) {
+ v4l2_ctrl_s_ctrl(gspca_dev->exposure, exposure);
+ retval = 1;
+ }
+
+ if (retval)
+ PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d",
+ gain, exposure);
+ return retval;
+}
+EXPORT_SYMBOL(gspca_expo_autogain);
+
+/* Autogain + exposure algorithm for cameras with a coarse exposure control
+ (usually this means we can only control the clockdiv to change exposure)
+ As changing the clockdiv so that the fps drops from 30 to 15 fps for
+ example, will lead to a huge exposure change (it effectively doubles),
+ this algorithm normally tries to only adjust the gain (between 40 and
+ 80 %) and if that does not help, only then changes exposure. This leads
+ to a much more stable image then using the knee algorithm which at
+ certain points of the knee graph will only try to adjust exposure,
+ which leads to oscilating as one exposure step is huge.
+
+ Returns 0 if no changes were made, 1 if the gain and or exposure settings
+ where changed. */
+int gspca_coarse_grained_expo_autogain(
+ struct gspca_dev *gspca_dev,
+ int avg_lum,
+ int desired_avg_lum,
+ int deadzone)
+{
+ s32 gain_low, gain_high, gain, orig_gain, exposure, orig_exposure;
+ int steps, retval = 0;
+
+ if (v4l2_ctrl_g_ctrl(gspca_dev->autogain) == 0)
+ return 0;
+
+ orig_gain = gain = v4l2_ctrl_g_ctrl(gspca_dev->gain);
+ orig_exposure = exposure = v4l2_ctrl_g_ctrl(gspca_dev->exposure);
+
+ gain_low = (gspca_dev->gain->maximum - gspca_dev->gain->minimum) /
+ 5 * 2 + gspca_dev->gain->minimum;
+ gain_high = (gspca_dev->gain->maximum - gspca_dev->gain->minimum) /
+ 5 * 4 + gspca_dev->gain->minimum;
+
+ /* If we are of a multiple of deadzone, do multiple steps to reach the
+ desired lumination fast (with the risc of a slight overshoot) */
+ steps = (desired_avg_lum - avg_lum) / deadzone;
+
+ PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d",
+ avg_lum, desired_avg_lum, steps);
+
+ if ((gain + steps) > gain_high &&
+ exposure < gspca_dev->exposure->maximum) {
+ gain = gain_high;
+ gspca_dev->exp_too_low_cnt++;
+ gspca_dev->exp_too_high_cnt = 0;
+ } else if ((gain + steps) < gain_low &&
+ exposure > gspca_dev->exposure->minimum) {
+ gain = gain_low;
+ gspca_dev->exp_too_high_cnt++;
+ gspca_dev->exp_too_low_cnt = 0;
+ } else {
+ gain += steps;
+ if (gain > gspca_dev->gain->maximum)
+ gain = gspca_dev->gain->maximum;
+ else if (gain < gspca_dev->gain->minimum)
+ gain = gspca_dev->gain->minimum;
+ gspca_dev->exp_too_high_cnt = 0;
+ gspca_dev->exp_too_low_cnt = 0;
+ }
+
+ if (gspca_dev->exp_too_high_cnt > 3) {
+ exposure--;
+ gspca_dev->exp_too_high_cnt = 0;
+ } else if (gspca_dev->exp_too_low_cnt > 3) {
+ exposure++;
+ gspca_dev->exp_too_low_cnt = 0;
+ }
+
+ if (gain != orig_gain) {
+ v4l2_ctrl_s_ctrl(gspca_dev->gain, gain);
+ retval = 1;
+ }
+ if (exposure != orig_exposure) {
+ v4l2_ctrl_s_ctrl(gspca_dev->exposure, exposure);
+ retval = 1;
+ }
+
+ if (retval)
+ PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d",
+ gain, exposure);
+ return retval;
+}
+EXPORT_SYMBOL(gspca_coarse_grained_expo_autogain);
diff --git a/drivers/media/video/gspca/autogain_functions.h b/drivers/media/video/gspca/autogain_functions.h
index 46777eee678b..d625eafe63eb 100644
--- a/drivers/media/video/gspca/autogain_functions.h
+++ b/drivers/media/video/gspca/autogain_functions.h
@@ -18,6 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifdef WANT_REGULAR_AUTOGAIN
/* auto gain and exposure algorithm based on the knee algorithm described here:
http://ytse.tricolour.net/docs/LowLightOptimization.html
@@ -91,7 +92,9 @@ static inline int auto_gain_n_exposure(
gain, exposure);
return retval;
}
+#endif
+#ifdef WANT_COARSE_EXPO_AUTOGAIN
/* Autogain + exposure algorithm for cameras with a coarse exposure control
(usually this means we can only control the clockdiv to change exposure)
As changing the clockdiv so that the fps drops from 30 to 15 fps for
@@ -103,7 +106,7 @@ static inline int auto_gain_n_exposure(
which leads to oscilating as one exposure step is huge.
Note this assumes that the sd struct for the cam in question has
- exp_too_high_cnt and exp_too_high_cnt int members for use by this function.
+ exp_too_low_cnt and exp_too_high_cnt int members for use by this function.
Returns 0 if no changes were made, 1 if the gain and or exposure settings
where changed. */
@@ -177,3 +180,4 @@ static inline int coarse_grained_expo_autogain(
gain, exposure);
return retval;
}
+#endif
diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c
index ea17b5d94ea4..f39fee0fd10f 100644
--- a/drivers/media/video/gspca/conex.c
+++ b/drivers/media/video/gspca/conex.c
@@ -306,7 +306,7 @@ static void cx_sensor(struct gspca_dev*gspca_dev)
reg_w(gspca_dev, 0x0020, reg20, 8);
reg_w(gspca_dev, 0x0028, reg28, 8);
- reg_w(gspca_dev, 0x0010, reg10, 8);
+ reg_w(gspca_dev, 0x0010, reg10, 2);
reg_w_val(gspca_dev, 0x0092, 0x03);
switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
@@ -326,7 +326,7 @@ static void cx_sensor(struct gspca_dev*gspca_dev)
}
reg_w(gspca_dev, 0x007b, reg7b, 6);
reg_w_val(gspca_dev, 0x00f8, 0x00);
- reg_w(gspca_dev, 0x0010, reg10, 8);
+ reg_w(gspca_dev, 0x0010, reg10, 2);
reg_w_val(gspca_dev, 0x0098, 0x41);
for (i = 0; i < 11; i++) {
if (i == 3 || i == 5 || i == 8)
diff --git a/drivers/media/video/gspca/finepix.c b/drivers/media/video/gspca/finepix.c
index 0107513cd728..6e26c93b4656 100644
--- a/drivers/media/video/gspca/finepix.c
+++ b/drivers/media/video/gspca/finepix.c
@@ -94,7 +94,11 @@ static void dostream(struct work_struct *work)
/* loop reading a frame */
again:
- while (gspca_dev->present && gspca_dev->streaming) {
+ while (gspca_dev->dev && gspca_dev->streaming) {
+#ifdef CONFIG_PM
+ if (gspca_dev->frozen)
+ break;
+#endif
/* request a frame */
mutex_lock(&gspca_dev->usb_lock);
@@ -102,7 +106,11 @@ again:
mutex_unlock(&gspca_dev->usb_lock);
if (ret < 0)
break;
- if (!gspca_dev->present || !gspca_dev->streaming)
+#ifdef CONFIG_PM
+ if (gspca_dev->frozen)
+ break;
+#endif
+ if (!gspca_dev->dev || !gspca_dev->streaming)
break;
/* the frame comes in parts */
@@ -117,7 +125,11 @@ again:
* error. Just restart. */
goto again;
}
- if (!gspca_dev->present || !gspca_dev->streaming)
+#ifdef CONFIG_PM
+ if (gspca_dev->frozen)
+ goto out;
+#endif
+ if (!gspca_dev->dev || !gspca_dev->streaming)
goto out;
if (len < FPIX_MAX_TRANSFER ||
(data[len - 2] == 0xff &&
diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c
index c84e26006fc3..c549574c1c7e 100644
--- a/drivers/media/video/gspca/gl860/gl860.c
+++ b/drivers/media/video/gspca/gl860/gl860.c
@@ -405,6 +405,9 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ if (!sd->gspca_dev.present)
+ return;
+
return sd->dev_post_unset_alt(gspca_dev);
}
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index ca5a2b139d0b..137166d73945 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -38,6 +38,9 @@
#include <linux/uaccess.h>
#include <linux/ktime.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
#include "gspca.h"
@@ -592,16 +595,13 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev)
static void gspca_stream_off(struct gspca_dev *gspca_dev)
{
gspca_dev->streaming = 0;
- if (gspca_dev->present) {
- if (gspca_dev->sd_desc->stopN)
- gspca_dev->sd_desc->stopN(gspca_dev);
- destroy_urbs(gspca_dev);
- gspca_input_destroy_urb(gspca_dev);
- gspca_set_alt0(gspca_dev);
- gspca_input_create_urb(gspca_dev);
- }
-
- /* always call stop0 to free the subdriver's resources */
+ gspca_dev->usb_err = 0;
+ if (gspca_dev->sd_desc->stopN)
+ gspca_dev->sd_desc->stopN(gspca_dev);
+ destroy_urbs(gspca_dev);
+ gspca_input_destroy_urb(gspca_dev);
+ gspca_set_alt0(gspca_dev);
+ gspca_input_create_urb(gspca_dev);
if (gspca_dev->sd_desc->stop0)
gspca_dev->sd_desc->stop0(gspca_dev);
PDEBUG(D_STREAM, "stream off OK");
@@ -847,14 +847,6 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
struct ep_tb_s ep_tb[MAX_ALT];
int n, ret, xfer, alt, alt_idx;
- if (mutex_lock_interruptible(&gspca_dev->usb_lock))
- return -ERESTARTSYS;
-
- if (!gspca_dev->present) {
- ret = -ENODEV;
- goto unlock;
- }
-
/* reset the streaming variables */
gspca_dev->image = NULL;
gspca_dev->image_len = 0;
@@ -869,7 +861,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
if (gspca_dev->sd_desc->isoc_init) {
ret = gspca_dev->sd_desc->isoc_init(gspca_dev);
if (ret < 0)
- goto unlock;
+ return ret;
}
xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK
: USB_ENDPOINT_XFER_ISOC;
@@ -880,8 +872,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
ep = alt_xfer(&intf->altsetting[gspca_dev->alt], xfer);
if (ep == NULL) {
pr_err("bad altsetting %d\n", gspca_dev->alt);
- ret = -EIO;
- goto out;
+ return -EIO;
}
ep_tb[0].alt = gspca_dev->alt;
alt_idx = 1;
@@ -892,8 +883,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
alt_idx = build_isoc_ep_tb(gspca_dev, intf, ep_tb);
if (alt_idx <= 0) {
pr_err("no transfer endpoint found\n");
- ret = -EIO;
- goto unlock;
+ return -EIO;
}
}
@@ -988,8 +978,6 @@ retry:
}
out:
gspca_input_create_urb(gspca_dev);
-unlock:
- mutex_unlock(&gspca_dev->usb_lock);
return ret;
}
@@ -1006,6 +994,8 @@ static void gspca_set_default_mode(struct gspca_dev *gspca_dev)
/* set the current control values to their default values
* which may have changed in sd_init() */
+ /* does nothing if ctrl_handler == NULL */
+ v4l2_ctrl_handler_setup(gspca_dev->vdev.ctrl_handler);
ctrl = gspca_dev->cam.ctrls;
if (ctrl != NULL) {
for (i = 0;
@@ -1057,77 +1047,50 @@ static int gspca_get_mode(struct gspca_dev *gspca_dev,
static int vidioc_g_register(struct file *file, void *priv,
struct v4l2_dbg_register *reg)
{
- int ret;
- struct gspca_dev *gspca_dev = priv;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
if (!gspca_dev->sd_desc->get_chip_ident)
- return -EINVAL;
+ return -ENOTTY;
if (!gspca_dev->sd_desc->get_register)
- return -EINVAL;
+ return -ENOTTY;
- if (mutex_lock_interruptible(&gspca_dev->usb_lock))
- return -ERESTARTSYS;
gspca_dev->usb_err = 0;
- if (gspca_dev->present)
- ret = gspca_dev->sd_desc->get_register(gspca_dev, reg);
- else
- ret = -ENODEV;
- mutex_unlock(&gspca_dev->usb_lock);
-
- return ret;
+ return gspca_dev->sd_desc->get_register(gspca_dev, reg);
}
static int vidioc_s_register(struct file *file, void *priv,
struct v4l2_dbg_register *reg)
{
- int ret;
- struct gspca_dev *gspca_dev = priv;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
if (!gspca_dev->sd_desc->get_chip_ident)
- return -EINVAL;
+ return -ENOTTY;
if (!gspca_dev->sd_desc->set_register)
- return -EINVAL;
+ return -ENOTTY;
- if (mutex_lock_interruptible(&gspca_dev->usb_lock))
- return -ERESTARTSYS;
gspca_dev->usb_err = 0;
- if (gspca_dev->present)
- ret = gspca_dev->sd_desc->set_register(gspca_dev, reg);
- else
- ret = -ENODEV;
- mutex_unlock(&gspca_dev->usb_lock);
-
- return ret;
+ return gspca_dev->sd_desc->set_register(gspca_dev, reg);
}
#endif
static int vidioc_g_chip_ident(struct file *file, void *priv,
struct v4l2_dbg_chip_ident *chip)
{
- int ret;
- struct gspca_dev *gspca_dev = priv;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
if (!gspca_dev->sd_desc->get_chip_ident)
- return -EINVAL;
+ return -ENOTTY;
- if (mutex_lock_interruptible(&gspca_dev->usb_lock))
- return -ERESTARTSYS;
gspca_dev->usb_err = 0;
- if (gspca_dev->present)
- ret = gspca_dev->sd_desc->get_chip_ident(gspca_dev, chip);
- else
- ret = -ENODEV;
- mutex_unlock(&gspca_dev->usb_lock);
-
- return ret;
+ return gspca_dev->sd_desc->get_chip_ident(gspca_dev, chip);
}
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *fmtdesc)
{
- struct gspca_dev *gspca_dev = priv;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
int i, j, index;
__u32 fmt_tb[8];
@@ -1169,7 +1132,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *fmt)
{
- struct gspca_dev *gspca_dev = priv;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
int mode;
mode = gspca_dev->curr_mode;
@@ -1214,7 +1177,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file,
void *priv,
struct v4l2_format *fmt)
{
- struct gspca_dev *gspca_dev = priv;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
int ret;
ret = try_fmt_vid_cap(gspca_dev, fmt);
@@ -1226,7 +1189,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file,
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *fmt)
{
- struct gspca_dev *gspca_dev = priv;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
int ret;
if (mutex_lock_interruptible(&gspca_dev->queue_lock))
@@ -1265,7 +1228,7 @@ out:
static int vidioc_enum_framesizes(struct file *file, void *priv,
struct v4l2_frmsizeenum *fsize)
{
- struct gspca_dev *gspca_dev = priv;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
int i;
__u32 index = 0;
@@ -1291,7 +1254,7 @@ static int vidioc_enum_framesizes(struct file *file, void *priv,
static int vidioc_enum_frameintervals(struct file *filp, void *priv,
struct v4l2_frmivalenum *fival)
{
- struct gspca_dev *gspca_dev = priv;
+ struct gspca_dev *gspca_dev = video_drvdata(filp);
int mode = wxh_to_mode(gspca_dev, fival->width, fival->height);
__u32 i;
@@ -1316,31 +1279,30 @@ static int vidioc_enum_frameintervals(struct file *filp, void *priv,
return -EINVAL;
}
-static void gspca_release(struct video_device *vfd)
+static void gspca_release(struct v4l2_device *v4l2_device)
{
- struct gspca_dev *gspca_dev = container_of(vfd, struct gspca_dev, vdev);
+ struct gspca_dev *gspca_dev =
+ container_of(v4l2_device, struct gspca_dev, v4l2_dev);
PDEBUG(D_PROBE, "%s released",
video_device_node_name(&gspca_dev->vdev));
+ v4l2_ctrl_handler_free(gspca_dev->vdev.ctrl_handler);
+ v4l2_device_unregister(&gspca_dev->v4l2_dev);
kfree(gspca_dev->usb_buf);
kfree(gspca_dev);
}
static int dev_open(struct file *file)
{
- struct gspca_dev *gspca_dev;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
PDEBUG(D_STREAM, "[%s] open", current->comm);
- gspca_dev = (struct gspca_dev *) video_devdata(file);
- if (!gspca_dev->present)
- return -ENODEV;
/* protect the subdriver against rmmod */
if (!try_module_get(gspca_dev->module))
return -ENODEV;
- file->private_data = gspca_dev;
#ifdef GSPCA_DEBUG
/* activate the v4l2 debug */
if (gspca_debug & D_V4L2)
@@ -1350,49 +1312,44 @@ static int dev_open(struct file *file)
gspca_dev->vdev.debug &= ~(V4L2_DEBUG_IOCTL
| V4L2_DEBUG_IOCTL_ARG);
#endif
- return 0;
+ return v4l2_fh_open(file);
}
static int dev_close(struct file *file)
{
- struct gspca_dev *gspca_dev = file->private_data;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
PDEBUG(D_STREAM, "[%s] close", current->comm);
- if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+
+ /* Needed for gspca_stream_off, always lock before queue_lock! */
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
return -ERESTARTSYS;
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock)) {
+ mutex_unlock(&gspca_dev->usb_lock);
+ return -ERESTARTSYS;
+ }
+
/* if the file did the capture, free the streaming resources */
if (gspca_dev->capt_file == file) {
- if (gspca_dev->streaming) {
- mutex_lock(&gspca_dev->usb_lock);
- gspca_dev->usb_err = 0;
+ if (gspca_dev->streaming)
gspca_stream_off(gspca_dev);
- mutex_unlock(&gspca_dev->usb_lock);
- }
frame_free(gspca_dev);
}
- file->private_data = NULL;
module_put(gspca_dev->module);
mutex_unlock(&gspca_dev->queue_lock);
+ mutex_unlock(&gspca_dev->usb_lock);
PDEBUG(D_STREAM, "close done");
- return 0;
+ return v4l2_fh_release(file);
}
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct gspca_dev *gspca_dev = priv;
- int ret;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
- /* protect the access to the usb device */
- if (mutex_lock_interruptible(&gspca_dev->usb_lock))
- return -ERESTARTSYS;
- if (!gspca_dev->present) {
- ret = -ENODEV;
- goto out;
- }
strlcpy((char *) cap->driver, gspca_dev->sd_desc->name,
sizeof cap->driver);
if (gspca_dev->dev->product != NULL) {
@@ -1406,13 +1363,11 @@ static int vidioc_querycap(struct file *file, void *priv,
}
usb_make_path(gspca_dev->dev, (char *) cap->bus_info,
sizeof(cap->bus_info));
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE
| V4L2_CAP_STREAMING
| V4L2_CAP_READWRITE;
- ret = 0;
-out:
- mutex_unlock(&gspca_dev->usb_lock);
- return ret;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ return 0;
}
static int get_ctrl(struct gspca_dev *gspca_dev,
@@ -1435,7 +1390,7 @@ static int get_ctrl(struct gspca_dev *gspca_dev,
static int vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *q_ctrl)
{
- struct gspca_dev *gspca_dev = priv;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
const struct ctrl *ctrls;
struct gspca_ctrl *gspca_ctrl;
int i, idx;
@@ -1478,10 +1433,10 @@ static int vidioc_queryctrl(struct file *file, void *priv,
static int vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
- struct gspca_dev *gspca_dev = priv;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
const struct ctrl *ctrls;
struct gspca_ctrl *gspca_ctrl;
- int idx, ret;
+ int idx;
idx = get_ctrl(gspca_dev, ctrl->id);
if (idx < 0)
@@ -1501,74 +1456,52 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
return -ERANGE;
}
PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value);
- if (mutex_lock_interruptible(&gspca_dev->usb_lock))
- return -ERESTARTSYS;
- if (!gspca_dev->present) {
- ret = -ENODEV;
- goto out;
- }
gspca_dev->usb_err = 0;
- if (ctrls->set != NULL) {
- ret = ctrls->set(gspca_dev, ctrl->value);
- goto out;
- }
+ if (ctrls->set != NULL)
+ return ctrls->set(gspca_dev, ctrl->value);
if (gspca_ctrl != NULL) {
gspca_ctrl->val = ctrl->value;
if (ctrls->set_control != NULL
&& gspca_dev->streaming)
ctrls->set_control(gspca_dev);
}
- ret = gspca_dev->usb_err;
-out:
- mutex_unlock(&gspca_dev->usb_lock);
- return ret;
+ return gspca_dev->usb_err;
}
static int vidioc_g_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
- struct gspca_dev *gspca_dev = priv;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
const struct ctrl *ctrls;
- int idx, ret;
+ int idx;
idx = get_ctrl(gspca_dev, ctrl->id);
if (idx < 0)
return -EINVAL;
ctrls = &gspca_dev->sd_desc->ctrls[idx];
- if (mutex_lock_interruptible(&gspca_dev->usb_lock))
- return -ERESTARTSYS;
- if (!gspca_dev->present) {
- ret = -ENODEV;
- goto out;
- }
gspca_dev->usb_err = 0;
- if (ctrls->get != NULL) {
- ret = ctrls->get(gspca_dev, &ctrl->value);
- goto out;
- }
+ if (ctrls->get != NULL)
+ return ctrls->get(gspca_dev, &ctrl->value);
if (gspca_dev->cam.ctrls != NULL)
ctrl->value = gspca_dev->cam.ctrls[idx].val;
- ret = 0;
-out:
- mutex_unlock(&gspca_dev->usb_lock);
- return ret;
+ return 0;
}
static int vidioc_querymenu(struct file *file, void *priv,
struct v4l2_querymenu *qmenu)
{
- struct gspca_dev *gspca_dev = priv;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
if (!gspca_dev->sd_desc->querymenu)
- return -EINVAL;
+ return -ENOTTY;
return gspca_dev->sd_desc->querymenu(gspca_dev, qmenu);
}
static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *input)
{
- struct gspca_dev *gspca_dev = priv;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
if (input->index != 0)
return -EINVAL;
@@ -1595,7 +1528,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
static int vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *rb)
{
- struct gspca_dev *gspca_dev = priv;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
int i, ret = 0, streaming;
i = rb->memory; /* (avoid compilation warning) */
@@ -1635,10 +1568,7 @@ static int vidioc_reqbufs(struct file *file, void *priv,
/* stop streaming */
streaming = gspca_dev->streaming;
if (streaming) {
- mutex_lock(&gspca_dev->usb_lock);
- gspca_dev->usb_err = 0;
gspca_stream_off(gspca_dev);
- mutex_unlock(&gspca_dev->usb_lock);
/* Don't restart the stream when switching from read
* to mmap mode */
@@ -1666,7 +1596,7 @@ out:
static int vidioc_querybuf(struct file *file, void *priv,
struct v4l2_buffer *v4l2_buf)
{
- struct gspca_dev *gspca_dev = priv;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
struct gspca_frame *frame;
if (v4l2_buf->index < 0
@@ -1681,7 +1611,7 @@ static int vidioc_querybuf(struct file *file, void *priv,
static int vidioc_streamon(struct file *file, void *priv,
enum v4l2_buf_type buf_type)
{
- struct gspca_dev *gspca_dev = priv;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
int ret;
if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -1722,7 +1652,7 @@ out:
static int vidioc_streamoff(struct file *file, void *priv,
enum v4l2_buf_type buf_type)
{
- struct gspca_dev *gspca_dev = priv;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
int ret;
if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -1743,13 +1673,7 @@ static int vidioc_streamoff(struct file *file, void *priv,
}
/* stop streaming */
- if (mutex_lock_interruptible(&gspca_dev->usb_lock)) {
- ret = -ERESTARTSYS;
- goto out;
- }
- gspca_dev->usb_err = 0;
gspca_stream_off(gspca_dev);
- mutex_unlock(&gspca_dev->usb_lock);
/* In case another thread is waiting in dqbuf */
wake_up_interruptible(&gspca_dev->wq);
@@ -1766,71 +1690,44 @@ out:
static int vidioc_g_jpegcomp(struct file *file, void *priv,
struct v4l2_jpegcompression *jpegcomp)
{
- struct gspca_dev *gspca_dev = priv;
- int ret;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
if (!gspca_dev->sd_desc->get_jcomp)
- return -EINVAL;
- if (mutex_lock_interruptible(&gspca_dev->usb_lock))
- return -ERESTARTSYS;
+ return -ENOTTY;
gspca_dev->usb_err = 0;
- if (gspca_dev->present)
- ret = gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp);
- else
- ret = -ENODEV;
- mutex_unlock(&gspca_dev->usb_lock);
- return ret;
+ return gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp);
}
static int vidioc_s_jpegcomp(struct file *file, void *priv,
struct v4l2_jpegcompression *jpegcomp)
{
- struct gspca_dev *gspca_dev = priv;
- int ret;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
if (!gspca_dev->sd_desc->set_jcomp)
- return -EINVAL;
- if (mutex_lock_interruptible(&gspca_dev->usb_lock))
- return -ERESTARTSYS;
+ return -ENOTTY;
gspca_dev->usb_err = 0;
- if (gspca_dev->present)
- ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp);
- else
- ret = -ENODEV;
- mutex_unlock(&gspca_dev->usb_lock);
- return ret;
+ return gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp);
}
static int vidioc_g_parm(struct file *filp, void *priv,
struct v4l2_streamparm *parm)
{
- struct gspca_dev *gspca_dev = priv;
+ struct gspca_dev *gspca_dev = video_drvdata(filp);
parm->parm.capture.readbuffers = gspca_dev->nbufread;
if (gspca_dev->sd_desc->get_streamparm) {
- int ret;
-
- if (mutex_lock_interruptible(&gspca_dev->usb_lock))
- return -ERESTARTSYS;
- if (gspca_dev->present) {
- gspca_dev->usb_err = 0;
- gspca_dev->sd_desc->get_streamparm(gspca_dev, parm);
- ret = gspca_dev->usb_err;
- } else {
- ret = -ENODEV;
- }
- mutex_unlock(&gspca_dev->usb_lock);
- return ret;
+ gspca_dev->usb_err = 0;
+ gspca_dev->sd_desc->get_streamparm(gspca_dev, parm);
+ return gspca_dev->usb_err;
}
-
return 0;
}
static int vidioc_s_parm(struct file *filp, void *priv,
struct v4l2_streamparm *parm)
{
- struct gspca_dev *gspca_dev = priv;
+ struct gspca_dev *gspca_dev = video_drvdata(filp);
int n;
n = parm->parm.capture.readbuffers;
@@ -1840,19 +1737,9 @@ static int vidioc_s_parm(struct file *filp, void *priv,
gspca_dev->nbufread = n;
if (gspca_dev->sd_desc->set_streamparm) {
- int ret;
-
- if (mutex_lock_interruptible(&gspca_dev->usb_lock))
- return -ERESTARTSYS;
- if (gspca_dev->present) {
- gspca_dev->usb_err = 0;
- gspca_dev->sd_desc->set_streamparm(gspca_dev, parm);
- ret = gspca_dev->usb_err;
- } else {
- ret = -ENODEV;
- }
- mutex_unlock(&gspca_dev->usb_lock);
- return ret;
+ gspca_dev->usb_err = 0;
+ gspca_dev->sd_desc->set_streamparm(gspca_dev, parm);
+ return gspca_dev->usb_err;
}
return 0;
@@ -1860,7 +1747,7 @@ static int vidioc_s_parm(struct file *filp, void *priv,
static int dev_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct gspca_dev *gspca_dev = file->private_data;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
struct gspca_frame *frame;
struct page *page;
unsigned long addr, start, size;
@@ -1872,10 +1759,6 @@ static int dev_mmap(struct file *file, struct vm_area_struct *vma)
if (mutex_lock_interruptible(&gspca_dev->queue_lock))
return -ERESTARTSYS;
- if (!gspca_dev->present) {
- ret = -ENODEV;
- goto out;
- }
if (gspca_dev->capt_file != file) {
ret = -EINVAL;
goto out;
@@ -1963,7 +1846,7 @@ static int frame_ready(struct gspca_dev *gspca_dev, struct file *file,
static int vidioc_dqbuf(struct file *file, void *priv,
struct v4l2_buffer *v4l2_buf)
{
- struct gspca_dev *gspca_dev = priv;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
struct gspca_frame *frame;
int i, j, ret;
@@ -2003,14 +1886,6 @@ static int vidioc_dqbuf(struct file *file, void *priv,
gspca_dev->fr_o = (i + 1) % GSPCA_MAX_FRAMES;
- if (gspca_dev->sd_desc->dq_callback) {
- mutex_lock(&gspca_dev->usb_lock);
- gspca_dev->usb_err = 0;
- if (gspca_dev->present)
- gspca_dev->sd_desc->dq_callback(gspca_dev);
- mutex_unlock(&gspca_dev->usb_lock);
- }
-
frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE;
memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf);
PDEBUG(D_FRAM, "dqbuf %d", j);
@@ -2027,6 +1902,15 @@ static int vidioc_dqbuf(struct file *file, void *priv,
}
out:
mutex_unlock(&gspca_dev->queue_lock);
+
+ if (ret == 0 && gspca_dev->sd_desc->dq_callback) {
+ mutex_lock(&gspca_dev->usb_lock);
+ gspca_dev->usb_err = 0;
+ if (gspca_dev->present)
+ gspca_dev->sd_desc->dq_callback(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
+ }
+
return ret;
}
@@ -2039,7 +1923,7 @@ out:
static int vidioc_qbuf(struct file *file, void *priv,
struct v4l2_buffer *v4l2_buf)
{
- struct gspca_dev *gspca_dev = priv;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
struct gspca_frame *frame;
int i, index, ret;
@@ -2098,6 +1982,10 @@ static int read_alloc(struct gspca_dev *gspca_dev,
int i, ret;
PDEBUG(D_STREAM, "read alloc");
+
+ if (mutex_lock_interruptible(&gspca_dev->usb_lock))
+ return -ERESTARTSYS;
+
if (gspca_dev->nframes == 0) {
struct v4l2_requestbuffers rb;
@@ -2108,7 +1996,7 @@ static int read_alloc(struct gspca_dev *gspca_dev,
ret = vidioc_reqbufs(file, gspca_dev, &rb);
if (ret != 0) {
PDEBUG(D_STREAM, "read reqbuf err %d", ret);
- return ret;
+ goto out;
}
memset(&v4l2_buf, 0, sizeof v4l2_buf);
v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -2118,61 +2006,69 @@ static int read_alloc(struct gspca_dev *gspca_dev,
ret = vidioc_qbuf(file, gspca_dev, &v4l2_buf);
if (ret != 0) {
PDEBUG(D_STREAM, "read qbuf err: %d", ret);
- return ret;
+ goto out;
}
}
- gspca_dev->memory = GSPCA_MEMORY_READ;
}
/* start streaming */
ret = vidioc_streamon(file, gspca_dev, V4L2_BUF_TYPE_VIDEO_CAPTURE);
if (ret != 0)
PDEBUG(D_STREAM, "read streamon err %d", ret);
+out:
+ mutex_unlock(&gspca_dev->usb_lock);
return ret;
}
static unsigned int dev_poll(struct file *file, poll_table *wait)
{
- struct gspca_dev *gspca_dev = file->private_data;
- int ret;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
+ unsigned long req_events = poll_requested_events(wait);
+ int ret = 0;
PDEBUG(D_FRAM, "poll");
- poll_wait(file, &gspca_dev->wq, wait);
+ if (req_events & POLLPRI)
+ ret |= v4l2_ctrl_poll(file, wait);
- /* if reqbufs is not done, the user would use read() */
- if (gspca_dev->memory == GSPCA_MEMORY_NO) {
- ret = read_alloc(gspca_dev, file);
- if (ret != 0)
- return POLLERR;
- }
+ if (req_events & (POLLIN | POLLRDNORM)) {
+ /* if reqbufs is not done, the user would use read() */
+ if (gspca_dev->memory == GSPCA_MEMORY_NO) {
+ if (read_alloc(gspca_dev, file) != 0) {
+ ret |= POLLERR;
+ goto out;
+ }
+ }
- if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0)
- return POLLERR;
+ poll_wait(file, &gspca_dev->wq, wait);
- /* check if an image has been received */
- if (gspca_dev->fr_o != atomic_read(&gspca_dev->fr_i))
- ret = POLLIN | POLLRDNORM; /* yes */
- else
- ret = 0;
- mutex_unlock(&gspca_dev->queue_lock);
+ /* check if an image has been received */
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0) {
+ ret |= POLLERR;
+ goto out;
+ }
+ if (gspca_dev->fr_o != atomic_read(&gspca_dev->fr_i))
+ ret |= POLLIN | POLLRDNORM;
+ mutex_unlock(&gspca_dev->queue_lock);
+ }
+
+out:
if (!gspca_dev->present)
- return POLLHUP;
+ ret |= POLLHUP;
+
return ret;
}
static ssize_t dev_read(struct file *file, char __user *data,
size_t count, loff_t *ppos)
{
- struct gspca_dev *gspca_dev = file->private_data;
+ struct gspca_dev *gspca_dev = video_drvdata(file);
struct gspca_frame *frame;
struct v4l2_buffer v4l2_buf;
struct timeval timestamp;
int n, ret, ret2;
PDEBUG(D_FRAM, "read (%zd)", count);
- if (!gspca_dev->present)
- return -ENODEV;
if (gspca_dev->memory == GSPCA_MEMORY_NO) { /* first time ? */
ret = read_alloc(gspca_dev, file);
if (ret != 0)
@@ -2266,13 +2162,15 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = {
.vidioc_s_register = vidioc_s_register,
#endif
.vidioc_g_chip_ident = vidioc_g_chip_ident,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static const struct video_device gspca_template = {
.name = "gspca main driver",
.fops = &dev_fops,
.ioctl_ops = &dev_ioctl_ops,
- .release = gspca_release,
+ .release = video_device_release_empty, /* We use v4l2_dev.release */
};
/* initialize the controls */
@@ -2344,9 +2242,24 @@ int gspca_dev_probe2(struct usb_interface *intf,
}
}
+ gspca_dev->v4l2_dev.release = gspca_release;
+ ret = v4l2_device_register(&intf->dev, &gspca_dev->v4l2_dev);
+ if (ret)
+ goto out;
gspca_dev->sd_desc = sd_desc;
gspca_dev->nbufread = 2;
gspca_dev->empty_packet = -1; /* don't check the empty packets */
+ gspca_dev->vdev = gspca_template;
+ gspca_dev->vdev.v4l2_dev = &gspca_dev->v4l2_dev;
+ video_set_drvdata(&gspca_dev->vdev, gspca_dev);
+ set_bit(V4L2_FL_USE_FH_PRIO, &gspca_dev->vdev.flags);
+ gspca_dev->module = module;
+ gspca_dev->present = 1;
+
+ mutex_init(&gspca_dev->usb_lock);
+ gspca_dev->vdev.lock = &gspca_dev->usb_lock;
+ mutex_init(&gspca_dev->queue_lock);
+ init_waitqueue_head(&gspca_dev->wq);
/* configure the subdriver and initialize the USB device */
ret = sd_desc->config(gspca_dev, id);
@@ -2357,21 +2270,26 @@ int gspca_dev_probe2(struct usb_interface *intf,
ret = sd_desc->init(gspca_dev);
if (ret < 0)
goto out;
+ if (sd_desc->init_controls)
+ ret = sd_desc->init_controls(gspca_dev);
+ if (ret < 0)
+ goto out;
gspca_set_default_mode(gspca_dev);
ret = gspca_input_connect(gspca_dev);
if (ret)
goto out;
- mutex_init(&gspca_dev->usb_lock);
- mutex_init(&gspca_dev->queue_lock);
- init_waitqueue_head(&gspca_dev->wq);
+ /*
+ * Don't take usb_lock for these ioctls. This improves latency if
+ * usb_lock is taken for a long time, e.g. when changing a control
+ * value, and a new frame is ready to be dequeued.
+ */
+ v4l2_disable_ioctl_locking(&gspca_dev->vdev, VIDIOC_DQBUF);
+ v4l2_disable_ioctl_locking(&gspca_dev->vdev, VIDIOC_QBUF);
+ v4l2_disable_ioctl_locking(&gspca_dev->vdev, VIDIOC_QUERYBUF);
/* init video stuff */
- memcpy(&gspca_dev->vdev, &gspca_template, sizeof gspca_template);
- gspca_dev->vdev.parent = &intf->dev;
- gspca_dev->module = module;
- gspca_dev->present = 1;
ret = video_register_device(&gspca_dev->vdev,
VFL_TYPE_GRABBER,
-1);
@@ -2391,6 +2309,7 @@ out:
if (gspca_dev->input_dev)
input_unregister_device(gspca_dev->input_dev);
#endif
+ v4l2_ctrl_handler_free(gspca_dev->vdev.ctrl_handler);
kfree(gspca_dev->usb_buf);
kfree(gspca_dev);
return ret;
@@ -2437,11 +2356,12 @@ void gspca_disconnect(struct usb_interface *intf)
PDEBUG(D_PROBE, "%s disconnect",
video_device_node_name(&gspca_dev->vdev));
+
mutex_lock(&gspca_dev->usb_lock);
+ usb_set_intfdata(intf, NULL);
+ gspca_dev->dev = NULL;
gspca_dev->present = 0;
- wake_up_interruptible(&gspca_dev->wq);
-
destroy_urbs(gspca_dev);
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
@@ -2452,18 +2372,19 @@ void gspca_disconnect(struct usb_interface *intf)
input_unregister_device(input_dev);
}
#endif
+ /* Free subdriver's streaming resources / stop sd workqueue(s) */
+ if (gspca_dev->sd_desc->stop0 && gspca_dev->streaming)
+ gspca_dev->sd_desc->stop0(gspca_dev);
+ gspca_dev->streaming = 0;
+ wake_up_interruptible(&gspca_dev->wq);
- /* the device is freed at exit of this function */
- gspca_dev->dev = NULL;
- mutex_unlock(&gspca_dev->usb_lock);
+ v4l2_device_disconnect(&gspca_dev->v4l2_dev);
+ video_unregister_device(&gspca_dev->vdev);
- usb_set_intfdata(intf, NULL);
+ mutex_unlock(&gspca_dev->usb_lock);
- /* release the device */
/* (this will call gspca_release() immediately or on last close) */
- video_unregister_device(&gspca_dev->vdev);
-
-/* PDEBUG(D_PROBE, "disconnect complete"); */
+ v4l2_device_put(&gspca_dev->v4l2_dev);
}
EXPORT_SYMBOL(gspca_disconnect);
@@ -2474,7 +2395,9 @@ int gspca_suspend(struct usb_interface *intf, pm_message_t message)
if (!gspca_dev->streaming)
return 0;
+ mutex_lock(&gspca_dev->usb_lock);
gspca_dev->frozen = 1; /* avoid urb error messages */
+ gspca_dev->usb_err = 0;
if (gspca_dev->sd_desc->stopN)
gspca_dev->sd_desc->stopN(gspca_dev);
destroy_urbs(gspca_dev);
@@ -2482,6 +2405,7 @@ int gspca_suspend(struct usb_interface *intf, pm_message_t message)
gspca_set_alt0(gspca_dev);
if (gspca_dev->sd_desc->stop0)
gspca_dev->sd_desc->stop0(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
return 0;
}
EXPORT_SYMBOL(gspca_suspend);
@@ -2489,105 +2413,28 @@ EXPORT_SYMBOL(gspca_suspend);
int gspca_resume(struct usb_interface *intf)
{
struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
+ int streaming, ret = 0;
+ mutex_lock(&gspca_dev->usb_lock);
gspca_dev->frozen = 0;
+ gspca_dev->usb_err = 0;
gspca_dev->sd_desc->init(gspca_dev);
gspca_input_create_urb(gspca_dev);
- if (gspca_dev->streaming)
- return gspca_init_transfer(gspca_dev);
- return 0;
+ /*
+ * Most subdrivers send all ctrl values on sd_start and thus
+ * only write to the device registers on s_ctrl when streaming ->
+ * Clear streaming to avoid setting all ctrls twice.
+ */
+ streaming = gspca_dev->streaming;
+ gspca_dev->streaming = 0;
+ v4l2_ctrl_handler_setup(gspca_dev->vdev.ctrl_handler);
+ if (streaming)
+ ret = gspca_init_transfer(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
+ return ret;
}
EXPORT_SYMBOL(gspca_resume);
#endif
-/* -- cam driver utility functions -- */
-
-/* auto gain and exposure algorithm based on the knee algorithm described here:
- http://ytse.tricolour.net/docs/LowLightOptimization.html
-
- Returns 0 if no changes were made, 1 if the gain and or exposure settings
- where changed. */
-int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum,
- int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee)
-{
- int i, steps, gain, orig_gain, exposure, orig_exposure, autogain;
- const struct ctrl *gain_ctrl = NULL;
- const struct ctrl *exposure_ctrl = NULL;
- const struct ctrl *autogain_ctrl = NULL;
- int retval = 0;
-
- for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
- if (gspca_dev->ctrl_dis & (1 << i))
- continue;
- if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_GAIN)
- gain_ctrl = &gspca_dev->sd_desc->ctrls[i];
- if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_EXPOSURE)
- exposure_ctrl = &gspca_dev->sd_desc->ctrls[i];
- if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_AUTOGAIN)
- autogain_ctrl = &gspca_dev->sd_desc->ctrls[i];
- }
- if (!gain_ctrl || !exposure_ctrl || !autogain_ctrl) {
- PDEBUG(D_ERR, "Error: gspca_auto_gain_n_exposure called "
- "on cam without (auto)gain/exposure");
- return 0;
- }
-
- if (gain_ctrl->get(gspca_dev, &gain) ||
- exposure_ctrl->get(gspca_dev, &exposure) ||
- autogain_ctrl->get(gspca_dev, &autogain) || !autogain)
- return 0;
-
- orig_gain = gain;
- orig_exposure = exposure;
-
- /* If we are of a multiple of deadzone, do multiple steps to reach the
- desired lumination fast (with the risc of a slight overshoot) */
- steps = abs(desired_avg_lum - avg_lum) / deadzone;
-
- PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d",
- avg_lum, desired_avg_lum, steps);
-
- for (i = 0; i < steps; i++) {
- if (avg_lum > desired_avg_lum) {
- if (gain > gain_knee)
- gain--;
- else if (exposure > exposure_knee)
- exposure--;
- else if (gain > gain_ctrl->qctrl.default_value)
- gain--;
- else if (exposure > exposure_ctrl->qctrl.minimum)
- exposure--;
- else if (gain > gain_ctrl->qctrl.minimum)
- gain--;
- else
- break;
- } else {
- if (gain < gain_ctrl->qctrl.default_value)
- gain++;
- else if (exposure < exposure_knee)
- exposure++;
- else if (gain < gain_knee)
- gain++;
- else if (exposure < exposure_ctrl->qctrl.maximum)
- exposure++;
- else if (gain < gain_ctrl->qctrl.maximum)
- gain++;
- else
- break;
- }
- }
-
- if (gain != orig_gain) {
- gain_ctrl->set(gspca_dev, gain);
- retval = 1;
- }
- if (exposure != orig_exposure) {
- exposure_ctrl->set(gspca_dev, exposure);
- retval = 1;
- }
-
- return retval;
-}
-EXPORT_SYMBOL(gspca_auto_gain_n_exposure);
/* -- module insert / remove -- */
static int __init gspca_init(void)
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index 589009f4496f..dc688c7f5e48 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -6,6 +6,8 @@
#include <linux/usb.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
#include <linux/mutex.h>
/* compilation option */
@@ -115,6 +117,7 @@ struct sd_desc {
/* mandatory operations */
cam_cf_op config; /* called on probe */
cam_op init; /* called on probe and resume */
+ cam_op init_controls; /* called on probe */
cam_op start; /* called on stream on after URBs creation */
cam_pkt_op pkt_scan;
/* optional operations */
@@ -158,8 +161,10 @@ struct gspca_frame {
struct gspca_dev {
struct video_device vdev; /* !! must be the first item */
struct module *module; /* subdriver handling the device */
+ struct v4l2_device v4l2_dev;
struct usb_device *dev;
struct file *capt_file; /* file doing video capture */
+ /* protected by queue_lock */
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
struct input_dev *input_dev;
char phys[64]; /* physical device path */
@@ -169,6 +174,16 @@ struct gspca_dev {
const struct sd_desc *sd_desc; /* subdriver description */
unsigned ctrl_dis; /* disabled controls (bit map) */
unsigned ctrl_inac; /* inactive controls (bit map) */
+ struct v4l2_ctrl_handler ctrl_handler;
+
+ /* autogain and exposure or gain control cluster, these are global as
+ the autogain/exposure functions in autogain_functions.c use them */
+ struct {
+ struct v4l2_ctrl *autogain;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *gain;
+ int exp_too_low_cnt, exp_too_high_cnt;
+ };
#define USB_BUF_SZ 64
__u8 *usb_buf; /* buffer for USB exchanges */
@@ -189,7 +204,7 @@ struct gspca_dev {
u8 fr_o; /* next frame to dequeue */
__u8 last_packet_type;
__s8 empty_packet; /* if (-1) don't check empty packets */
- __u8 streaming;
+ __u8 streaming; /* protected by both mutexes (*) */
__u8 curr_mode; /* current camera mode */
__u32 pixfmt; /* current mode parameters */
@@ -211,6 +226,10 @@ struct gspca_dev {
__u8 iface; /* USB interface number */
__u8 alt; /* USB alternate setting */
u8 audio; /* presence of audio device */
+
+ /* (*) These variables are proteced by both usb_lock and queue_lock,
+ that is any code setting them is holding *both*, which means that
+ any code getting them needs to hold at least one of them */
};
int gspca_dev_probe(struct usb_interface *intf,
@@ -232,6 +251,9 @@ void gspca_frame_add(struct gspca_dev *gspca_dev,
int gspca_suspend(struct usb_interface *intf, pm_message_t message);
int gspca_resume(struct usb_interface *intf);
#endif
-int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum,
+int gspca_expo_autogain(struct gspca_dev *gspca_dev, int avg_lum,
int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee);
+int gspca_coarse_grained_expo_autogain(struct gspca_dev *gspca_dev,
+ int avg_lum, int desired_avg_lum, int deadzone);
+
#endif /* GSPCAV2_H */
diff --git a/drivers/media/video/gspca/jl2005bcd.c b/drivers/media/video/gspca/jl2005bcd.c
index 53f58ef367cf..9c591c7c6f54 100644
--- a/drivers/media/video/gspca/jl2005bcd.c
+++ b/drivers/media/video/gspca/jl2005bcd.c
@@ -335,7 +335,11 @@ static void jl2005c_dostream(struct work_struct *work)
goto quit_stream;
}
- while (gspca_dev->present && gspca_dev->streaming) {
+ while (gspca_dev->dev && gspca_dev->streaming) {
+#ifdef CONFIG_PM
+ if (gspca_dev->frozen)
+ break;
+#endif
/* Check if this is a new frame. If so, start the frame first */
if (!header_read) {
mutex_lock(&gspca_dev->usb_lock);
@@ -367,7 +371,7 @@ static void jl2005c_dostream(struct work_struct *work)
buffer, act_len);
header_read = 1;
}
- while (bytes_left > 0 && gspca_dev->present) {
+ while (bytes_left > 0 && gspca_dev->dev) {
data_len = bytes_left > JL2005C_MAX_TRANSFER ?
JL2005C_MAX_TRANSFER : bytes_left;
ret = usb_bulk_msg(gspca_dev->dev,
@@ -390,7 +394,7 @@ static void jl2005c_dostream(struct work_struct *work)
}
}
quit_stream:
- if (gspca_dev->present) {
+ if (gspca_dev->dev) {
mutex_lock(&gspca_dev->usb_lock);
jl2005c_stop(gspca_dev);
mutex_unlock(&gspca_dev->usb_lock);
diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c
index b0231465afae..ec7b21ee79fb 100644
--- a/drivers/media/video/gspca/mars.c
+++ b/drivers/media/video/gspca/mars.c
@@ -30,22 +30,19 @@ MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver");
MODULE_LICENSE("GPL");
-/* controls */
-enum e_ctrl {
- BRIGHTNESS,
- COLORS,
- GAMMA,
- SHARPNESS,
- ILLUM_TOP,
- ILLUM_BOT,
- NCTRLS /* number of controls */
-};
-
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- struct gspca_ctrl ctrls[NCTRLS];
+ struct v4l2_ctrl *brightness;
+ struct v4l2_ctrl *saturation;
+ struct v4l2_ctrl *sharpness;
+ struct v4l2_ctrl *gamma;
+ struct { /* illuminator control cluster */
+ struct v4l2_ctrl *illum_top;
+ struct v4l2_ctrl *illum_bottom;
+ };
+ struct v4l2_ctrl *jpegqual;
u8 quality;
#define QUALITY_MIN 40
@@ -56,89 +53,10 @@ struct sd {
};
/* V4L2 controls supported by the driver */
-static void setbrightness(struct gspca_dev *gspca_dev);
-static void setcolors(struct gspca_dev *gspca_dev);
-static void setgamma(struct gspca_dev *gspca_dev);
-static void setsharpness(struct gspca_dev *gspca_dev);
-static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val);
-
-static const struct ctrl sd_ctrls[NCTRLS] = {
-[BRIGHTNESS] = {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 30,
- .step = 1,
- .default_value = 15,
- },
- .set_control = setbrightness
- },
-[COLORS] = {
- {
- .id = V4L2_CID_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Color",
- .minimum = 1,
- .maximum = 255,
- .step = 1,
- .default_value = 200,
- },
- .set_control = setcolors
- },
-[GAMMA] = {
- {
- .id = V4L2_CID_GAMMA,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gamma",
- .minimum = 0,
- .maximum = 3,
- .step = 1,
- .default_value = 1,
- },
- .set_control = setgamma
- },
-[SHARPNESS] = {
- {
- .id = V4L2_CID_SHARPNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Sharpness",
- .minimum = 0,
- .maximum = 2,
- .step = 1,
- .default_value = 1,
- },
- .set_control = setsharpness
- },
-[ILLUM_TOP] = {
- {
- .id = V4L2_CID_ILLUMINATORS_1,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Top illuminator",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- .flags = V4L2_CTRL_FLAG_UPDATE,
- },
- .set = sd_setilluminator1
- },
-[ILLUM_BOT] = {
- {
- .id = V4L2_CID_ILLUMINATORS_2,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Bottom illuminator",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- .flags = V4L2_CTRL_FLAG_UPDATE,
- },
- .set = sd_setilluminator2
- },
-};
+static void setbrightness(struct gspca_dev *gspca_dev, s32 val);
+static void setcolors(struct gspca_dev *gspca_dev, s32 val);
+static void setgamma(struct gspca_dev *gspca_dev, s32 val);
+static void setsharpness(struct gspca_dev *gspca_dev, s32 val);
static const struct v4l2_pix_format vga_mode[] = {
{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
@@ -198,59 +116,130 @@ static void mi_w(struct gspca_dev *gspca_dev,
reg_w(gspca_dev, 4);
}
-static void setbrightness(struct gspca_dev *gspca_dev)
+static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
{
- struct sd *sd = (struct sd *) gspca_dev;
-
gspca_dev->usb_buf[0] = 0x61;
- gspca_dev->usb_buf[1] = sd->ctrls[BRIGHTNESS].val;
+ gspca_dev->usb_buf[1] = val;
reg_w(gspca_dev, 2);
}
-static void setcolors(struct gspca_dev *gspca_dev)
+static void setcolors(struct gspca_dev *gspca_dev, s32 val)
{
- struct sd *sd = (struct sd *) gspca_dev;
- s16 val;
-
- val = sd->ctrls[COLORS].val;
gspca_dev->usb_buf[0] = 0x5f;
gspca_dev->usb_buf[1] = val << 3;
gspca_dev->usb_buf[2] = ((val >> 2) & 0xf8) | 0x04;
reg_w(gspca_dev, 3);
}
-static void setgamma(struct gspca_dev *gspca_dev)
+static void setgamma(struct gspca_dev *gspca_dev, s32 val)
{
- struct sd *sd = (struct sd *) gspca_dev;
-
gspca_dev->usb_buf[0] = 0x06;
- gspca_dev->usb_buf[1] = sd->ctrls[GAMMA].val * 0x40;
+ gspca_dev->usb_buf[1] = val * 0x40;
reg_w(gspca_dev, 2);
}
-static void setsharpness(struct gspca_dev *gspca_dev)
+static void setsharpness(struct gspca_dev *gspca_dev, s32 val)
{
- struct sd *sd = (struct sd *) gspca_dev;
-
gspca_dev->usb_buf[0] = 0x67;
- gspca_dev->usb_buf[1] = sd->ctrls[SHARPNESS].val * 4 + 3;
+ gspca_dev->usb_buf[1] = val * 4 + 3;
reg_w(gspca_dev, 2);
}
-static void setilluminators(struct gspca_dev *gspca_dev)
+static void setilluminators(struct gspca_dev *gspca_dev, bool top, bool bottom)
{
- struct sd *sd = (struct sd *) gspca_dev;
-
+ /* both are off if not streaming */
gspca_dev->usb_buf[0] = 0x22;
- if (sd->ctrls[ILLUM_TOP].val)
+ if (top)
gspca_dev->usb_buf[1] = 0x76;
- else if (sd->ctrls[ILLUM_BOT].val)
+ else if (bottom)
gspca_dev->usb_buf[1] = 0x7a;
else
gspca_dev->usb_buf[1] = 0x7e;
reg_w(gspca_dev, 2);
}
+static int mars_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 (ctrl->id == V4L2_CID_ILLUMINATORS_1) {
+ /* only one can be on at a time */
+ if (ctrl->is_new && ctrl->val)
+ sd->illum_bottom->val = 0;
+ if (sd->illum_bottom->is_new && sd->illum_bottom->val)
+ sd->illum_top->val = 0;
+ }
+
+ if (!gspca_dev->streaming)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ setbrightness(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_SATURATION:
+ setcolors(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_GAMMA:
+ setgamma(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_ILLUMINATORS_1:
+ setilluminators(gspca_dev, sd->illum_top->val,
+ sd->illum_bottom->val);
+ break;
+ case V4L2_CID_SHARPNESS:
+ setsharpness(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+ jpeg_set_qual(sd->jpeg_hdr, ctrl->val);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return gspca_dev->usb_err;
+}
+
+static const struct v4l2_ctrl_ops mars_ctrl_ops = {
+ .s_ctrl = mars_s_ctrl,
+};
+
+/* this function is called at probe time */
+static int sd_init_controls(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
+
+ gspca_dev->vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 7);
+ sd->brightness = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 30, 1, 15);
+ sd->saturation = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 255, 1, 200);
+ sd->gamma = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops,
+ V4L2_CID_GAMMA, 0, 3, 1, 1);
+ sd->sharpness = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops,
+ V4L2_CID_SHARPNESS, 0, 2, 1, 1);
+ sd->illum_top = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops,
+ V4L2_CID_ILLUMINATORS_1, 0, 1, 1, 0);
+ sd->illum_top->flags |= V4L2_CTRL_FLAG_UPDATE;
+ sd->illum_bottom = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops,
+ V4L2_CID_ILLUMINATORS_2, 0, 1, 1, 0);
+ sd->illum_bottom->flags |= V4L2_CTRL_FLAG_UPDATE;
+ sd->jpegqual = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops,
+ V4L2_CID_JPEG_COMPRESSION_QUALITY,
+ QUALITY_MIN, QUALITY_MAX, 1, QUALITY_DEF);
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
+ v4l2_ctrl_cluster(2, &sd->illum_top);
+ return 0;
+}
+
/* this function is called at probe time */
static int sd_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id)
@@ -261,7 +250,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam = &gspca_dev->cam;
cam->cam_mode = vga_mode;
cam->nmodes = ARRAY_SIZE(vga_mode);
- cam->ctrls = sd->ctrls;
sd->quality = QUALITY_DEF;
return 0;
}
@@ -269,7 +257,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
- gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT);
return 0;
}
@@ -282,7 +269,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* create the JPEG header */
jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x21); /* JPEG 422 */
- jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+ jpeg_set_qual(sd->jpeg_hdr, v4l2_ctrl_g_ctrl(sd->jpegqual));
data = gspca_dev->usb_buf;
@@ -301,7 +288,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
data[5] = 0x30; /* reg 4, MI, PAS5101 :
* 0x30 for 24mhz , 0x28 for 12mhz */
data[6] = 0x02; /* reg 5, H start - was 0x04 */
- data[7] = sd->ctrls[GAMMA].val * 0x40; /* reg 0x06: gamma */
+ data[7] = v4l2_ctrl_g_ctrl(sd->gamma) * 0x40; /* reg 0x06: gamma */
data[8] = 0x01; /* reg 7, V start - was 0x03 */
/* if (h_size == 320 ) */
/* data[9]= 0x56; * reg 8, 24MHz, 2:1 scale down */
@@ -333,16 +320,16 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* reg 0x5f/0x60 (LE) = saturation */
/* h (60): xxxx x100
* l (5f): xxxx x000 */
- data[2] = sd->ctrls[COLORS].val << 3;
- data[3] = ((sd->ctrls[COLORS].val >> 2) & 0xf8) | 0x04;
- data[4] = sd->ctrls[BRIGHTNESS].val; /* reg 0x61 = brightness */
+ data[2] = v4l2_ctrl_g_ctrl(sd->saturation) << 3;
+ data[3] = ((v4l2_ctrl_g_ctrl(sd->saturation) >> 2) & 0xf8) | 0x04;
+ data[4] = v4l2_ctrl_g_ctrl(sd->brightness); /* reg 0x61 = brightness */
data[5] = 0x00;
reg_w(gspca_dev, 6);
data[0] = 0x67;
/*jfm: from win trace*/
- data[1] = sd->ctrls[SHARPNESS].val * 4 + 3;
+ data[1] = v4l2_ctrl_g_ctrl(sd->sharpness) * 4 + 3;
data[2] = 0x14;
reg_w(gspca_dev, 3);
@@ -365,7 +352,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
data[1] = 0x4d; /* ISOC transferring enable... */
reg_w(gspca_dev, 2);
- gspca_dev->ctrl_inac = 0; /* activate the illuminator controls */
+ setilluminators(gspca_dev, v4l2_ctrl_g_ctrl(sd->illum_top),
+ v4l2_ctrl_g_ctrl(sd->illum_bottom));
+
return gspca_dev->usb_err;
}
@@ -373,11 +362,9 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT);
- if (sd->ctrls[ILLUM_TOP].val || sd->ctrls[ILLUM_BOT].val) {
- sd->ctrls[ILLUM_TOP].val = 0;
- sd->ctrls[ILLUM_BOT].val = 0;
- setilluminators(gspca_dev);
+ if (v4l2_ctrl_g_ctrl(sd->illum_top) ||
+ v4l2_ctrl_g_ctrl(sd->illum_bottom)) {
+ setilluminators(gspca_dev, false, false);
msleep(20);
}
@@ -424,43 +411,16 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
-static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- /* only one illuminator may be on */
- sd->ctrls[ILLUM_TOP].val = val;
- if (val)
- sd->ctrls[ILLUM_BOT].val = 0;
- setilluminators(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- /* only one illuminator may be on */
- sd->ctrls[ILLUM_BOT].val = val;
- if (val)
- sd->ctrls[ILLUM_TOP].val = 0;
- setilluminators(gspca_dev);
- return gspca_dev->usb_err;
-}
-
static int sd_set_jcomp(struct gspca_dev *gspca_dev,
struct v4l2_jpegcompression *jcomp)
{
struct sd *sd = (struct sd *) gspca_dev;
+ int ret;
- if (jcomp->quality < QUALITY_MIN)
- sd->quality = QUALITY_MIN;
- else if (jcomp->quality > QUALITY_MAX)
- sd->quality = QUALITY_MAX;
- else
- sd->quality = jcomp->quality;
- if (gspca_dev->streaming)
- jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+ ret = v4l2_ctrl_s_ctrl(sd->jpegqual, jcomp->quality);
+ if (ret)
+ return ret;
+ jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual);
return 0;
}
@@ -470,7 +430,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
struct sd *sd = (struct sd *) gspca_dev;
memset(jcomp, 0, sizeof *jcomp);
- jcomp->quality = sd->quality;
+ jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual);
jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
| V4L2_JPEG_MARKER_DQT;
return 0;
@@ -479,10 +439,9 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
/* sub-driver description */
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
- .ctrls = sd_ctrls,
- .nctrls = NCTRLS,
.config = sd_config,
.init = sd_init,
+ .init_controls = sd_init_controls,
.start = sd_start,
.stopN = sd_stopN,
.pkt_scan = sd_pkt_scan,
@@ -513,6 +472,7 @@ static struct usb_driver sd_driver = {
#ifdef CONFIG_PM
.suspend = gspca_suspend,
.resume = gspca_resume,
+ .reset_resume = gspca_resume,
#endif
};
diff --git a/drivers/media/video/gspca/nw80x.c b/drivers/media/video/gspca/nw80x.c
index 7167cac7359c..42e021931e60 100644
--- a/drivers/media/video/gspca/nw80x.c
+++ b/drivers/media/video/gspca/nw80x.c
@@ -2001,6 +2001,8 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
return gspca_dev->usb_err;
}
+#define WANT_REGULAR_AUTOGAIN
+#define WANT_COARSE_EXPO_AUTOGAIN
#include "autogain_functions.h"
static void do_autogain(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c
index 739e8a2a2d30..183457c5cfdb 100644
--- a/drivers/media/video/gspca/ov519.c
+++ b/drivers/media/video/gspca/ov519.c
@@ -2804,7 +2804,7 @@ static void ov7xx0_configure(struct sd *sd)
/* add OV7670 here
* it appears to be wrongly detected as a 7610 by default */
if (rc < 0) {
- PDEBUG(D_ERR, "Error detecting sensor type");
+ pr_err("Error detecting sensor type\n");
return;
}
if ((rc & 3) == 3) {
@@ -2832,12 +2832,12 @@ static void ov7xx0_configure(struct sd *sd)
/* try to read product id registers */
high = i2c_r(sd, 0x0a);
if (high < 0) {
- PDEBUG(D_ERR, "Error detecting camera chip PID");
+ pr_err("Error detecting camera chip PID\n");
return;
}
low = i2c_r(sd, 0x0b);
if (low < 0) {
- PDEBUG(D_ERR, "Error detecting camera chip VER");
+ pr_err("Error detecting camera chip VER\n");
return;
}
if (high == 0x76) {
@@ -2863,7 +2863,7 @@ static void ov7xx0_configure(struct sd *sd)
sd->sensor = SEN_OV7660;
break;
default:
- PDEBUG(D_PROBE, "Unknown sensor: 0x76%x", low);
+ pr_err("Unknown sensor: 0x76%02x\n", low);
return;
}
} else {
@@ -2884,7 +2884,7 @@ static void ov6xx0_configure(struct sd *sd)
/* Detect sensor (sub)type */
rc = i2c_r(sd, OV7610_REG_COM_I);
if (rc < 0) {
- PDEBUG(D_ERR, "Error detecting sensor type");
+ pr_err("Error detecting sensor type\n");
return;
}
diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c
index 04753391de3e..b5acb1e4b4e7 100644
--- a/drivers/media/video/gspca/ov534.c
+++ b/drivers/media/video/gspca/ov534.c
@@ -34,6 +34,8 @@
#include "gspca.h"
+#include <linux/fixp-arith.h>
+
#define OV534_REG_ADDRESS 0xf1 /* sensor address */
#define OV534_REG_SUBADDR 0xf2
#define OV534_REG_WRITE 0xf3
@@ -53,6 +55,8 @@ MODULE_LICENSE("GPL");
/* controls */
enum e_ctrl {
+ HUE,
+ SATURATION,
BRIGHTNESS,
CONTRAST,
GAIN,
@@ -63,7 +67,6 @@ enum e_ctrl {
SHARPNESS,
HFLIP,
VFLIP,
- COLORS,
LIGHTFREQ,
NCTRLS /* number of controls */
};
@@ -87,6 +90,8 @@ enum sensors {
};
/* V4L2 controls supported by the driver */
+static void sethue(struct gspca_dev *gspca_dev);
+static void setsaturation(struct gspca_dev *gspca_dev);
static void setbrightness(struct gspca_dev *gspca_dev);
static void setcontrast(struct gspca_dev *gspca_dev);
static void setgain(struct gspca_dev *gspca_dev);
@@ -96,13 +101,36 @@ static void setawb(struct gspca_dev *gspca_dev);
static void setaec(struct gspca_dev *gspca_dev);
static void setsharpness(struct gspca_dev *gspca_dev);
static void sethvflip(struct gspca_dev *gspca_dev);
-static void setcolors(struct gspca_dev *gspca_dev);
static void setlightfreq(struct gspca_dev *gspca_dev);
static int sd_start(struct gspca_dev *gspca_dev);
static void sd_stopN(struct gspca_dev *gspca_dev);
static const struct ctrl sd_ctrls[] = {
+[HUE] = {
+ {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = -90,
+ .maximum = 90,
+ .step = 1,
+ .default_value = 0,
+ },
+ .set_control = sethue
+ },
+[SATURATION] = {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 64,
+ },
+ .set_control = setsaturation
+ },
[BRIGHTNESS] = {
{
.id = V4L2_CID_BRIGHTNESS,
@@ -223,18 +251,6 @@ static const struct ctrl sd_ctrls[] = {
},
.set_control = sethvflip
},
-[COLORS] = {
- {
- .id = V4L2_CID_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 6,
- .step = 1,
- .default_value = 3,
- },
- .set_control = setcolors
- },
[LIGHTFREQ] = {
{
.id = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -684,7 +700,7 @@ static const u8 sensor_init_772x[][2] = {
{ 0x9c, 0x20 },
{ 0x9e, 0x81 },
- { 0xa6, 0x04 },
+ { 0xa6, 0x07 },
{ 0x7e, 0x0c },
{ 0x7f, 0x16 },
{ 0x80, 0x2a },
@@ -955,6 +971,74 @@ static void set_frame_rate(struct gspca_dev *gspca_dev)
PDEBUG(D_PROBE, "frame_rate: %d", r->fps);
}
+static void sethue(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int val;
+
+ val = sd->ctrls[HUE].val;
+ if (sd->sensor == SENSOR_OV767x) {
+ /* TBD */
+ } else {
+ s16 huesin;
+ s16 huecos;
+
+ /* fixp_sin and fixp_cos accept only positive values, while
+ * our val is between -90 and 90
+ */
+ val += 360;
+
+ /* According to the datasheet the registers expect HUESIN and
+ * HUECOS to be the result of the trigonometric functions,
+ * scaled by 0x80.
+ *
+ * The 0x100 here represents the maximun absolute value
+ * returned byt fixp_sin and fixp_cos, so the scaling will
+ * consider the result like in the interval [-1.0, 1.0].
+ */
+ huesin = fixp_sin(val) * 0x80 / 0x100;
+ huecos = fixp_cos(val) * 0x80 / 0x100;
+
+ if (huesin < 0) {
+ sccb_reg_write(gspca_dev, 0xab,
+ sccb_reg_read(gspca_dev, 0xab) | 0x2);
+ huesin = -huesin;
+ } else {
+ sccb_reg_write(gspca_dev, 0xab,
+ sccb_reg_read(gspca_dev, 0xab) & ~0x2);
+
+ }
+ sccb_reg_write(gspca_dev, 0xa9, (u8)huecos);
+ sccb_reg_write(gspca_dev, 0xaa, (u8)huesin);
+ }
+}
+
+static void setsaturation(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int val;
+
+ val = sd->ctrls[SATURATION].val;
+ if (sd->sensor == SENSOR_OV767x) {
+ int i;
+ static u8 color_tb[][6] = {
+ {0x42, 0x42, 0x00, 0x11, 0x30, 0x41},
+ {0x52, 0x52, 0x00, 0x16, 0x3c, 0x52},
+ {0x66, 0x66, 0x00, 0x1b, 0x4b, 0x66},
+ {0x80, 0x80, 0x00, 0x22, 0x5e, 0x80},
+ {0x9a, 0x9a, 0x00, 0x29, 0x71, 0x9a},
+ {0xb8, 0xb8, 0x00, 0x31, 0x87, 0xb8},
+ {0xdd, 0xdd, 0x00, 0x3b, 0xa2, 0xdd},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(color_tb[0]); i++)
+ sccb_reg_write(gspca_dev, 0x4f + i, color_tb[val][i]);
+ } else {
+ sccb_reg_write(gspca_dev, 0xa7, val); /* U saturation */
+ sccb_reg_write(gspca_dev, 0xa8, val); /* V saturation */
+ }
+}
+
static void setbrightness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -1132,26 +1216,6 @@ static void sethvflip(struct gspca_dev *gspca_dev)
}
}
-static void setcolors(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- u8 val;
- int i;
- static u8 color_tb[][6] = {
- {0x42, 0x42, 0x00, 0x11, 0x30, 0x41},
- {0x52, 0x52, 0x00, 0x16, 0x3c, 0x52},
- {0x66, 0x66, 0x00, 0x1b, 0x4b, 0x66},
- {0x80, 0x80, 0x00, 0x22, 0x5e, 0x80},
- {0x9a, 0x9a, 0x00, 0x29, 0x71, 0x9a},
- {0xb8, 0xb8, 0x00, 0x31, 0x87, 0xb8},
- {0xdd, 0xdd, 0x00, 0x3b, 0xa2, 0xdd},
- };
-
- val = sd->ctrls[COLORS].val;
- for (i = 0; i < ARRAY_SIZE(color_tb[0]); i++)
- sccb_reg_write(gspca_dev, 0x4f + i, color_tb[val][i]);
-}
-
static void setlightfreq(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -1225,9 +1289,13 @@ static int sd_init(struct gspca_dev *gspca_dev)
if ((sensor_id & 0xfff0) == 0x7670) {
sd->sensor = SENSOR_OV767x;
- gspca_dev->ctrl_dis = (1 << GAIN) |
+ gspca_dev->ctrl_dis = (1 << HUE) |
+ (1 << GAIN) |
(1 << AGC) |
(1 << SHARPNESS); /* auto */
+ sd->ctrls[SATURATION].min = 0,
+ sd->ctrls[SATURATION].max = 6,
+ sd->ctrls[SATURATION].def = 3,
sd->ctrls[BRIGHTNESS].min = -127;
sd->ctrls[BRIGHTNESS].max = 127;
sd->ctrls[BRIGHTNESS].def = 0;
@@ -1243,7 +1311,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
gspca_dev->cam.nmodes = ARRAY_SIZE(ov767x_mode);
} else {
sd->sensor = SENSOR_OV772x;
- gspca_dev->ctrl_dis = (1 << COLORS);
gspca_dev->cam.bulk = 1;
gspca_dev->cam.bulk_size = 16384;
gspca_dev->cam.bulk_nurbs = 2;
@@ -1302,6 +1369,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
set_frame_rate(gspca_dev);
+ if (!(gspca_dev->ctrl_dis & (1 << HUE)))
+ sethue(gspca_dev);
+ setsaturation(gspca_dev);
if (!(gspca_dev->ctrl_dis & (1 << AGC)))
setagc(gspca_dev);
setawb(gspca_dev);
@@ -1314,8 +1384,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
if (!(gspca_dev->ctrl_dis & (1 << SHARPNESS)))
setsharpness(gspca_dev);
sethvflip(gspca_dev);
- if (!(gspca_dev->ctrl_dis & (1 << COLORS)))
- setcolors(gspca_dev);
setlightfreq(gspca_dev);
ov534_set_led(gspca_dev, 1);
diff --git a/drivers/media/video/gspca/ov534_9.c b/drivers/media/video/gspca/ov534_9.c
index e6601b886032..b5797308a39b 100644
--- a/drivers/media/video/gspca/ov534_9.c
+++ b/drivers/media/video/gspca/ov534_9.c
@@ -1376,7 +1376,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
ARRAY_SIZE(ov562x_init_2));
reg_w(gspca_dev, 0xe0, 0x00);
} else {
- err("Unknown sensor %04x", sensor_id);
+ pr_err("Unknown sensor %04x", sensor_id);
return -EINVAL;
}
diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c
index 3844c49f269c..fa661c6d6d55 100644
--- a/drivers/media/video/gspca/pac207.c
+++ b/drivers/media/video/gspca/pac207.c
@@ -29,6 +29,8 @@
#include <linux/input.h>
#include "gspca.h"
+/* Include pac common sof detection functions */
+#include "pac_common.h"
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_DESCRIPTION("Pixart PAC207");
@@ -39,16 +41,17 @@ MODULE_LICENSE("GPL");
#define PAC207_BRIGHTNESS_MIN 0
#define PAC207_BRIGHTNESS_MAX 255
#define PAC207_BRIGHTNESS_DEFAULT 46
+#define PAC207_BRIGHTNESS_REG 0x08
#define PAC207_EXPOSURE_MIN 3
#define PAC207_EXPOSURE_MAX 90 /* 1 sec expo time / 1 fps */
#define PAC207_EXPOSURE_DEFAULT 5 /* power on default: 3 */
-#define PAC207_EXPOSURE_KNEE 9 /* fps: 90 / exposure -> 9: 10 fps */
+#define PAC207_EXPOSURE_REG 0x02
#define PAC207_GAIN_MIN 0
#define PAC207_GAIN_MAX 31
#define PAC207_GAIN_DEFAULT 7 /* power on default: 9 */
-#define PAC207_GAIN_KNEE 15
+#define PAC207_GAIN_REG 0x0e
#define PAC207_AUTOGAIN_DEADZONE 30
@@ -56,13 +59,9 @@ MODULE_LICENSE("GPL");
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- u8 mode;
-
- u8 brightness;
- u8 exposure;
- u8 autogain;
- u8 gain;
+ struct v4l2_ctrl *brightness;
+ u8 mode;
u8 sof_read;
u8 header_read;
u8 autogain_ignore_frames;
@@ -70,80 +69,6 @@ struct sd {
atomic_t avg_lum;
};
-/* V4L2 controls supported by the driver */
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
-
-static const struct ctrl sd_ctrls[] = {
-#define SD_BRIGHTNESS 0
- {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = PAC207_BRIGHTNESS_MIN,
- .maximum = PAC207_BRIGHTNESS_MAX,
- .step = 1,
- .default_value = PAC207_BRIGHTNESS_DEFAULT,
- .flags = 0,
- },
- .set = sd_setbrightness,
- .get = sd_getbrightness,
- },
-#define SD_EXPOSURE 1
- {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Exposure",
- .minimum = PAC207_EXPOSURE_MIN,
- .maximum = PAC207_EXPOSURE_MAX,
- .step = 1,
- .default_value = PAC207_EXPOSURE_DEFAULT,
- .flags = 0,
- },
- .set = sd_setexposure,
- .get = sd_getexposure,
- },
-#define SD_AUTOGAIN 2
- {
- {
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Auto Gain",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
-#define AUTOGAIN_DEF 1
- .default_value = AUTOGAIN_DEF,
- .flags = 0,
- },
- .set = sd_setautogain,
- .get = sd_getautogain,
- },
-#define SD_GAIN 3
- {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain",
- .minimum = PAC207_GAIN_MIN,
- .maximum = PAC207_GAIN_MAX,
- .step = 1,
- .default_value = PAC207_GAIN_DEFAULT,
- .flags = 0,
- },
- .set = sd_setgain,
- .get = sd_getgain,
- },
-};
-
static const struct v4l2_pix_format sif_mode[] = {
{176, 144, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
.bytesperline = 176,
@@ -167,39 +92,44 @@ static const __u8 pac207_sensor_init[][8] = {
{0x32, 0x00, 0x96, 0x00, 0xa2, 0x02, 0xaf, 0x00},
};
-static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
+static void pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
const u8 *buffer, u16 length)
{
struct usb_device *udev = gspca_dev->dev;
int err;
+ if (gspca_dev->usb_err < 0)
+ return;
+
memcpy(gspca_dev->usb_buf, buffer, length);
err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
0x00, index,
gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT);
- if (err < 0)
+ if (err < 0) {
pr_err("Failed to write registers to index 0x%04X, error %d\n",
index, err);
-
- return err;
+ gspca_dev->usb_err = err;
+ }
}
-
-static int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value)
+static void pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value)
{
struct usb_device *udev = gspca_dev->dev;
int err;
+ if (gspca_dev->usb_err < 0)
+ return;
+
err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
value, index, NULL, 0, PAC207_CTRL_TIMEOUT);
- if (err)
+ if (err) {
pr_err("Failed to write a register (index 0x%04X, value 0x%02X, error %d)\n",
index, value, err);
-
- return err;
+ gspca_dev->usb_err = err;
+ }
}
static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index)
@@ -207,6 +137,9 @@ static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index)
struct usb_device *udev = gspca_dev->dev;
int res;
+ if (gspca_dev->usb_err < 0)
+ return 0;
+
res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
0x00, index,
@@ -214,7 +147,8 @@ static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index)
if (res < 0) {
pr_err("Failed to read a register (index 0x%04X, error %d)\n",
index, res);
- return res;
+ gspca_dev->usb_err = res;
+ return 0;
}
return gspca_dev->usb_buf[0];
@@ -224,7 +158,6 @@ static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index)
static int sd_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id)
{
- struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam;
u8 idreg[2];
@@ -247,10 +180,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam = &gspca_dev->cam;
cam->cam_mode = sif_mode;
cam->nmodes = ARRAY_SIZE(sif_mode);
- sd->brightness = PAC207_BRIGHTNESS_DEFAULT;
- sd->exposure = PAC207_EXPOSURE_DEFAULT;
- sd->gain = PAC207_GAIN_DEFAULT;
- sd->autogain = AUTOGAIN_DEF;
return 0;
}
@@ -264,6 +193,87 @@ static int sd_init(struct gspca_dev *gspca_dev)
* Bit_2=Compression test mode enable */
pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
+ return gspca_dev->usb_err;
+}
+
+static void setcontrol(struct gspca_dev *gspca_dev, u16 reg, u16 val)
+{
+ pac207_write_reg(gspca_dev, reg, val);
+ pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
+ pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
+}
+
+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 (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) {
+ /* when switching to autogain set defaults to make sure
+ we are on a valid point of the autogain gain /
+ exposure knee graph, and give this change time to
+ take effect before doing autogain. */
+ gspca_dev->exposure->val = PAC207_EXPOSURE_DEFAULT;
+ gspca_dev->gain->val = PAC207_GAIN_DEFAULT;
+ sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
+ }
+
+ if (!gspca_dev->streaming)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ setcontrol(gspca_dev, PAC207_BRIGHTNESS_REG, ctrl->val);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val))
+ setcontrol(gspca_dev, PAC207_EXPOSURE_REG,
+ gspca_dev->exposure->val);
+ if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val))
+ setcontrol(gspca_dev, PAC207_GAIN_REG,
+ gspca_dev->gain->val);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return gspca_dev->usb_err;
+}
+
+static const struct v4l2_ctrl_ops sd_ctrl_ops = {
+ .s_ctrl = sd_s_ctrl,
+};
+
+/* this function is called at probe time */
+static int sd_init_controls(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
+
+ gspca_dev->vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 4);
+
+ sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_BRIGHTNESS,
+ PAC207_BRIGHTNESS_MIN, PAC207_BRIGHTNESS_MAX,
+ 1, PAC207_BRIGHTNESS_DEFAULT);
+ gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+ gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_EXPOSURE,
+ PAC207_EXPOSURE_MIN, PAC207_EXPOSURE_MAX,
+ 1, PAC207_EXPOSURE_DEFAULT);
+ gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_GAIN,
+ PAC207_GAIN_MIN, PAC207_GAIN_MAX,
+ 1, PAC207_GAIN_DEFAULT);
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
+ v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false);
return 0;
}
@@ -285,11 +295,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
else
pac207_write_reg(gspca_dev, 0x4a, 0x30);
pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */
- pac207_write_reg(gspca_dev, 0x08, sd->brightness);
+ pac207_write_reg(gspca_dev, 0x08, v4l2_ctrl_g_ctrl(sd->brightness));
/* PGA global gain (Bit 4-0) */
- pac207_write_reg(gspca_dev, 0x0e, sd->gain);
- pac207_write_reg(gspca_dev, 0x02, sd->exposure); /* PXCK = 12MHz /n */
+ pac207_write_reg(gspca_dev, 0x0e,
+ v4l2_ctrl_g_ctrl(gspca_dev->gain));
+ pac207_write_reg(gspca_dev, 0x02,
+ v4l2_ctrl_g_ctrl(gspca_dev->exposure)); /* PXCK = 12MHz /n */
mode = 0x02; /* Image Format (Bit 0), LED (1), Compr. test mode (2) */
if (gspca_dev->width == 176) { /* 176x144 */
@@ -308,7 +320,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
sd->sof_read = 0;
sd->autogain_ignore_frames = 0;
atomic_set(&sd->avg_lum, -1);
- return 0;
+ return gspca_dev->usb_err;
}
static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -318,8 +330,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
}
-/* Include pac common sof detection functions */
-#include "pac_common.h"
static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
{
@@ -331,9 +341,8 @@ static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
if (sd->autogain_ignore_frames > 0)
sd->autogain_ignore_frames--;
- else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
- 90, PAC207_AUTOGAIN_DEADZONE,
- PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
+ else if (gspca_coarse_grained_expo_autogain(gspca_dev, avg_lum,
+ 90, PAC207_AUTOGAIN_DEADZONE))
sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
}
@@ -384,118 +393,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
-static void setbrightness(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- pac207_write_reg(gspca_dev, 0x08, sd->brightness);
- pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
- pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
-}
-
-static void setexposure(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- pac207_write_reg(gspca_dev, 0x02, sd->exposure);
- pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
- pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
-}
-
-static void setgain(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- pac207_write_reg(gspca_dev, 0x0e, sd->gain);
- pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
- pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
-}
-
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->brightness = val;
- if (gspca_dev->streaming)
- setbrightness(gspca_dev);
- return 0;
-}
-
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->brightness;
- return 0;
-}
-
-static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->exposure = val;
- if (gspca_dev->streaming)
- setexposure(gspca_dev);
- return 0;
-}
-
-static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->exposure;
- return 0;
-}
-
-static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->gain = val;
- if (gspca_dev->streaming)
- setgain(gspca_dev);
- return 0;
-}
-
-static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->gain;
- return 0;
-}
-
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->autogain = val;
- /* when switching to autogain set defaults to make sure
- we are on a valid point of the autogain gain /
- exposure knee graph, and give this change time to
- take effect before doing autogain. */
- if (sd->autogain) {
- sd->exposure = PAC207_EXPOSURE_DEFAULT;
- sd->gain = PAC207_GAIN_DEFAULT;
- if (gspca_dev->streaming) {
- sd->autogain_ignore_frames =
- PAC_AUTOGAIN_IGNORE_FRAMES;
- setexposure(gspca_dev);
- setgain(gspca_dev);
- }
- }
-
- return 0;
-}
-
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->autogain;
- return 0;
-}
-
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet data */
@@ -518,10 +415,9 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
/* sub-driver description */
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
- .ctrls = sd_ctrls,
- .nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
.init = sd_init,
+ .init_controls = sd_init_controls,
.start = sd_start,
.stopN = sd_stopN,
.dq_callback = pac207_do_auto_gain,
diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c
index 30662fccb0cf..a0369a58c4bb 100644
--- a/drivers/media/video/gspca/pac7302.c
+++ b/drivers/media/video/gspca/pac7302.c
@@ -23,43 +23,58 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-/* Some documentation about various registers as determined by trial and error.
-
- Register page 1:
-
- Address Description
- 0x78 Global control, bit 6 controls the LED (inverted)
-
- Register page 3:
-
- Address Description
- 0x02 Clock divider 3-63, fps = 90 / val. Must be a multiple of 3 on
- the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
- 0x03 Variable framerate ctrl reg2==3: 0 -> ~30 fps, 255 -> ~22fps
- 0x04 Another var framerate ctrl reg2==3, reg3==0: 0 -> ~30 fps,
- 63 -> ~27 fps, the 2 msb's must always be 1 !!
- 0x05 Another var framerate ctrl reg2==3, reg3==0, reg4==0xc0:
- 1 -> ~30 fps, 2 -> ~20 fps
- 0x0e Exposure bits 0-7, 0-448, 0 = use full frame time
- 0x0f Exposure bit 8, 0-448, 448 = no exposure at all
- 0x10 Master gain 0-31
- 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
-
- The registers are accessed in the following functions:
-
- Page | Register | Function
- -----+------------+---------------------------------------------------
- 0 | 0x0f..0x20 | setcolors()
- 0 | 0xa2..0xab | setbrightcont()
- 0 | 0xc5 | setredbalance()
- 0 | 0xc6 | setwhitebalance()
- 0 | 0xc7 | setbluebalance()
- 0 | 0xdc | setbrightcont(), setcolors()
- 3 | 0x02 | setexposure()
- 3 | 0x10 | setgain()
- 3 | 0x11 | setcolors(), setgain(), setexposure(), sethvflip()
- 3 | 0x21 | sethvflip()
-*/
+/*
+ * Some documentation about various registers as determined by trial and error.
+ *
+ * Register page 1:
+ *
+ * Address Description
+ * 0x78 Global control, bit 6 controls the LED (inverted)
+ * 0x80 Compression balance, 2 interesting settings:
+ * 0x0f Default
+ * 0x50 Values >= this switch the camera to a lower compression,
+ * using the same table for both luminance and chrominance.
+ * This gives a sharper picture. Only usable when running
+ * at < 15 fps! Note currently the driver does not use this
+ * as the quality gain is small and the generated JPG-s are
+ * only understood by v4l-utils >= 0.8.9
+ *
+ * Register page 3:
+ *
+ * Address Description
+ * 0x02 Clock divider 3-63, fps = 90 / val. Must be a multiple of 3 on
+ * the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
+ * 0x03 Variable framerate ctrl reg2==3: 0 -> ~30 fps, 255 -> ~22fps
+ * 0x04 Another var framerate ctrl reg2==3, reg3==0: 0 -> ~30 fps,
+ * 63 -> ~27 fps, the 2 msb's must always be 1 !!
+ * 0x05 Another var framerate ctrl reg2==3, reg3==0, reg4==0xc0:
+ * 1 -> ~30 fps, 2 -> ~20 fps
+ * 0x0e Exposure bits 0-7, 0-448, 0 = use full frame time
+ * 0x0f Exposure bit 8, 0-448, 448 = no exposure at all
+ * 0x10 Gain 0-31
+ * 0x12 Another gain 0-31, unlike 0x10 this one seems to start with an
+ * amplification value of 1 rather then 0 at its lowest setting
+ * 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
+ * 0x80 Another framerate control, best left at 1, moving it from 1 to
+ * 2 causes the framerate to become 3/4th of what it was, and
+ * also seems to cause pixel averaging, resulting in an effective
+ * resolution of 320x240 and thus a much blockier image
+ *
+ * The registers are accessed in the following functions:
+ *
+ * Page | Register | Function
+ * -----+------------+---------------------------------------------------
+ * 0 | 0x0f..0x20 | setcolors()
+ * 0 | 0xa2..0xab | setbrightcont()
+ * 0 | 0xc5 | setredbalance()
+ * 0 | 0xc6 | setwhitebalance()
+ * 0 | 0xc7 | setbluebalance()
+ * 0 | 0xdc | setbrightcont(), setcolors()
+ * 3 | 0x02 | setexposure()
+ * 3 | 0x10, 0x12 | setgain()
+ * 3 | 0x11 | setcolors(), setgain(), setexposure(), sethvflip()
+ * 3 | 0x21 | sethvflip()
+ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -89,7 +104,6 @@ enum e_ctrl {
NCTRLS /* number of controls */
};
-/* specific webcam descriptor for pac7302 */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
@@ -198,10 +212,10 @@ static const struct ctrl sd_ctrls[] = {
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Gain",
.minimum = 0,
- .maximum = 255,
+ .maximum = 62,
.step = 1,
-#define GAIN_DEF 127
-#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
+#define GAIN_DEF 15
+#define GAIN_KNEE 46
.default_value = GAIN_DEF,
},
.set_control = setgain
@@ -270,7 +284,6 @@ static const struct v4l2_pix_format vga_mode[] = {
#define LOAD_PAGE3 255
#define END_OF_SEQUENCE 0
-/* pac 7302 */
static const u8 init_7302[] = {
/* index,value */
0xff, 0x01, /* page 1 */
@@ -509,7 +522,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
return 0;
}
-/* This function is used by pac7302 only */
static void setbrightcont(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -536,7 +548,6 @@ static void setbrightcont(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0xdc, 0x01);
}
-/* This function is used by pac7302 only */
static void setcolors(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -590,9 +601,19 @@ static void setbluebalance(struct gspca_dev *gspca_dev)
static void setgain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ u8 reg10, reg12;
+
+ if (sd->ctrls[GAIN].val < 32) {
+ reg10 = sd->ctrls[GAIN].val;
+ reg12 = 0;
+ } else {
+ reg10 = 31;
+ reg12 = sd->ctrls[GAIN].val - 31;
+ }
reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
- reg_w(gspca_dev, 0x10, sd->ctrls[GAIN].val >> 3);
+ reg_w(gspca_dev, 0x10, reg10);
+ reg_w(gspca_dev, 0x12, reg12);
/* load registers to sensor (Bit 0, auto clear) */
reg_w(gspca_dev, 0x11, 0x01);
@@ -604,28 +625,36 @@ static void setexposure(struct gspca_dev *gspca_dev)
u8 clockdiv;
u16 exposure;
- /* register 2 of frame 3 contains the clock divider configuring the
- no fps according to the formula: 90 / reg. sd->exposure is the
- desired exposure time in 0.5 ms. */
+ /*
+ * Register 2 of frame 3 contains the clock divider configuring the
+ * no fps according to the formula: 90 / reg. sd->exposure is the
+ * desired exposure time in 0.5 ms.
+ */
clockdiv = (90 * sd->ctrls[EXPOSURE].val + 1999) / 2000;
- /* Note clockdiv = 3 also works, but when running at 30 fps, depending
- on the scene being recorded, the camera switches to another
- quantization table for certain JPEG blocks, and we don't know how
- to decompress these blocks. So we cap the framerate at 15 fps */
+ /*
+ * Note clockdiv = 3 also works, but when running at 30 fps, depending
+ * on the scene being recorded, the camera switches to another
+ * quantization table for certain JPEG blocks, and we don't know how
+ * to decompress these blocks. So we cap the framerate at 15 fps.
+ */
if (clockdiv < 6)
clockdiv = 6;
else if (clockdiv > 63)
clockdiv = 63;
- /* reg2 MUST be a multiple of 3, except when between 6 and 12?
- Always round up, otherwise we cannot get the desired frametime
- using the partial frame time exposure control */
+ /*
+ * Register 2 MUST be a multiple of 3, except when between 6 and 12?
+ * Always round up, otherwise we cannot get the desired frametime
+ * using the partial frame time exposure control.
+ */
if (clockdiv < 6 || clockdiv > 12)
clockdiv = ((clockdiv + 2) / 3) * 3;
- /* frame exposure time in ms = 1000 * clockdiv / 90 ->
- exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */
+ /*
+ * frame exposure time in ms = 1000 * clockdiv / 90 ->
+ * exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90)
+ */
exposure = (sd->ctrls[EXPOSURE].val * 45 * 448) / (1000 * clockdiv);
/* 0 = use full frametime, 448 = no exposure, reverse it */
exposure = 448 - exposure;
@@ -643,10 +672,12 @@ static void setautogain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- /* when switching to autogain set defaults to make sure
- we are on a valid point of the autogain gain /
- exposure knee graph, and give this change time to
- take effect before doing autogain. */
+ /*
+ * When switching to autogain set defaults to make sure
+ * we are on a valid point of the autogain gain /
+ * exposure knee graph, and give this change time to
+ * take effect before doing autogain.
+ */
if (sd->ctrls[AUTOGAIN].val) {
sd->ctrls[EXPOSURE].val = EXPOSURE_DEF;
sd->ctrls[GAIN].val = GAIN_DEF;
@@ -700,8 +731,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
setautogain(gspca_dev);
sethvflip(gspca_dev);
- /* only resolution 640x480 is supported for pac7302 */
-
sd->sof_read = 0;
atomic_set(&sd->avg_lum, 270 + sd->ctrls[BRIGHTNESS].val);
@@ -729,9 +758,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x78, 0x40);
}
-/* !! coarse_grained_expo_autogain is not used !! */
-#define exp_too_low_cnt flags
-#define exp_too_high_cnt sof_read
+#define WANT_REGULAR_AUTOGAIN
#include "autogain_functions.h"
static void do_autogain(struct gspca_dev *gspca_dev)
@@ -792,10 +819,12 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
if (sof) {
int n, lum_offset, footer_length;
- /* 6 bytes after the FF D9 EOF marker a number of lumination
- bytes are send corresponding to different parts of the
- image, the 14th and 15th byte after the EOF seem to
- correspond to the center of the image */
+ /*
+ * 6 bytes after the FF D9 EOF marker a number of lumination
+ * bytes are send corresponding to different parts of the
+ * image, the 14th and 15th byte after the EOF seem to
+ * correspond to the center of the image.
+ */
lum_offset = 61 + sizeof pac_sof_marker;
footer_length = 74;
@@ -839,9 +868,10 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
u8 index;
u8 value;
- /* reg->reg: bit0..15: reserved for register index (wIndex is 16bit
- long on the USB bus)
- */
+ /*
+ * reg->reg: bit0..15: reserved for register index (wIndex is 16bit
+ * long on the USB bus)
+ */
if (reg->match.type == V4L2_CHIP_MATCH_HOST &&
reg->match.addr == 0 &&
(reg->reg < 0x000000ff) &&
@@ -852,9 +882,11 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
index = reg->reg;
value = reg->val;
- /* Note that there shall be no access to other page
- by any other function between the page swith and
- the actual register write */
+ /*
+ * Note that there shall be no access to other page
+ * by any other function between the page switch and
+ * the actual register write.
+ */
reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
reg_w(gspca_dev, index, value);
@@ -940,6 +972,7 @@ static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP},
{USB_DEVICE(0x093a, 0x2625)},
{USB_DEVICE(0x093a, 0x2626)},
+ {USB_DEVICE(0x093a, 0x2627), .driver_info = FL_VFLIP},
{USB_DEVICE(0x093a, 0x2628)},
{USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
{USB_DEVICE(0x093a, 0x262a)},
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c
index 1ac111176ffa..2cb7d95f7be7 100644
--- a/drivers/media/video/gspca/pac7311.c
+++ b/drivers/media/video/gspca/pac7311.c
@@ -20,34 +20,42 @@
*/
/* Some documentation about various registers as determined by trial and error.
- When the register addresses differ between the 7202 and the 7311 the 2
- different addresses are written as 7302addr/7311addr, when one of the 2
- addresses is a - sign that register description is not valid for the
- matching IC.
-
- Register page 1:
-
- Address Description
- -/0x08 Unknown compressor related, must always be 8 except when not
- in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 !
- -/0x1b Auto white balance related, bit 0 is AWB enable (inverted)
- bits 345 seem to toggle per color gains on/off (inverted)
- 0x78 Global control, bit 6 controls the LED (inverted)
- -/0x80 JPEG compression ratio ? Best not touched
-
- Register page 3/4:
-
- Address Description
- 0x02 Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on
- the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
- -/0x0f Master gain 1-245, low value = high gain
- 0x10/- Master gain 0-31
- -/0x10 Another gain 0-15, limited influence (1-2x gain I guess)
- 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
- -/0x27 Seems to toggle various gains on / off, Setting bit 7 seems to
- completely disable the analog amplification block. Set to 0x68
- for max gain, 0x14 for minimal gain.
-*/
+ *
+ * Register page 1:
+ *
+ * Address Description
+ * 0x08 Unknown compressor related, must always be 8 except when not
+ * in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 !
+ * 0x1b Auto white balance related, bit 0 is AWB enable (inverted)
+ * bits 345 seem to toggle per color gains on/off (inverted)
+ * 0x78 Global control, bit 6 controls the LED (inverted)
+ * 0x80 Compression balance, interesting settings:
+ * 0x01 Use this to allow the camera to switch to higher compr.
+ * on the fly. Needed to stay within bandwidth @ 640x480@30
+ * 0x1c From usb captures under Windows for 640x480
+ * 0x2a Values >= this switch the camera to a lower compression,
+ * using the same table for both luminance and chrominance.
+ * This gives a sharper picture. Usable only at 640x480@ <
+ * 15 fps or 320x240 / 160x120. Note currently the driver
+ * does not use this as the quality gain is small and the
+ * generated JPG-s are only understood by v4l-utils >= 0.8.9
+ * 0x3f From usb captures under Windows for 320x240
+ * 0x69 From usb captures under Windows for 160x120
+ *
+ * Register page 4:
+ *
+ * Address Description
+ * 0x02 Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on
+ * the 7302, so one of 3, 6, 9, ..., except when between 6 and 12?
+ * 0x0f Master gain 1-245, low value = high gain
+ * 0x10 Another gain 0-15, limited influence (1-2x gain I guess)
+ * 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused
+ * Note setting vflip disabled leads to a much lower image quality,
+ * so we always vflip, and tell userspace to flip it back
+ * 0x27 Seems to toggle various gains on / off, Setting bit 7 seems to
+ * completely disable the analog amplification block. Set to 0x68
+ * for max gain, 0x14 for minimal gain.
+ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -55,21 +63,21 @@
#include <linux/input.h>
#include "gspca.h"
+/* Include pac common sof detection functions */
+#include "pac_common.h"
+
+#define PAC7311_GAIN_DEFAULT 122
+#define PAC7311_EXPOSURE_DEFAULT 3 /* 20 fps, avoid using high compr. */
MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
MODULE_DESCRIPTION("Pixart PAC7311");
MODULE_LICENSE("GPL");
-/* specific webcam descriptor for pac7311 */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- unsigned char contrast;
- unsigned char gain;
- unsigned char exposure;
- unsigned char autogain;
- __u8 hflip;
- __u8 vflip;
+ struct v4l2_ctrl *contrast;
+ struct v4l2_ctrl *hflip;
u8 sof_read;
u8 autogain_ignore_frames;
@@ -77,114 +85,6 @@ struct sd {
atomic_t avg_lum;
};
-/* V4L2 controls supported by the driver */
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
-
-static const struct ctrl sd_ctrls[] = {
-/* This control is for both the 7302 and the 7311 */
- {
- {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0,
-#define CONTRAST_MAX 255
- .maximum = CONTRAST_MAX,
- .step = 1,
-#define CONTRAST_DEF 127
- .default_value = CONTRAST_DEF,
- },
- .set = sd_setcontrast,
- .get = sd_getcontrast,
- },
-/* All controls below are for both the 7302 and the 7311 */
- {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain",
- .minimum = 0,
-#define GAIN_MAX 255
- .maximum = GAIN_MAX,
- .step = 1,
-#define GAIN_DEF 127
-#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
- .default_value = GAIN_DEF,
- },
- .set = sd_setgain,
- .get = sd_getgain,
- },
- {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Exposure",
- .minimum = 0,
-#define EXPOSURE_MAX 255
- .maximum = EXPOSURE_MAX,
- .step = 1,
-#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */
-#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */
- .default_value = EXPOSURE_DEF,
- },
- .set = sd_setexposure,
- .get = sd_getexposure,
- },
- {
- {
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Auto Gain",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
-#define AUTOGAIN_DEF 1
- .default_value = AUTOGAIN_DEF,
- },
- .set = sd_setautogain,
- .get = sd_getautogain,
- },
- {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Mirror",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
-#define HFLIP_DEF 0
- .default_value = HFLIP_DEF,
- },
- .set = sd_sethflip,
- .get = sd_gethflip,
- },
- {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Vflip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
-#define VFLIP_DEF 0
- .default_value = VFLIP_DEF,
- },
- .set = sd_setvflip,
- .get = sd_getvflip,
- },
-};
-
static const struct v4l2_pix_format vga_mode[] = {
{160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
.bytesperline = 160,
@@ -206,8 +106,8 @@ static const struct v4l2_pix_format vga_mode[] = {
#define LOAD_PAGE4 254
#define END_OF_SEQUENCE 0
-/* pac 7311 */
static const __u8 init_7311[] = {
+ 0xff, 0x01,
0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */
0x78, 0x44, /* Bit_0=start stream, Bit_6=LED */
@@ -387,90 +287,73 @@ static void reg_w_var(struct gspca_dev *gspca_dev,
static int sd_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id)
{
- struct sd *sd = (struct sd *) gspca_dev;
- struct cam *cam;
+ struct cam *cam = &gspca_dev->cam;
- cam = &gspca_dev->cam;
-
- PDEBUG(D_CONF, "Find Sensor PAC7311");
cam->cam_mode = vga_mode;
cam->nmodes = ARRAY_SIZE(vga_mode);
+ cam->input_flags = V4L2_IN_ST_VFLIP;
- sd->contrast = CONTRAST_DEF;
- sd->gain = GAIN_DEF;
- sd->exposure = EXPOSURE_DEF;
- sd->autogain = AUTOGAIN_DEF;
- sd->hflip = HFLIP_DEF;
- sd->vflip = VFLIP_DEF;
return 0;
}
-/* This function is used by pac7311 only */
-static void setcontrast(struct gspca_dev *gspca_dev)
+static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
{
- struct sd *sd = (struct sd *) gspca_dev;
-
reg_w(gspca_dev, 0xff, 0x04);
- reg_w(gspca_dev, 0x10, sd->contrast >> 4);
+ reg_w(gspca_dev, 0x10, val);
/* load registers to sensor (Bit 0, auto clear) */
reg_w(gspca_dev, 0x11, 0x01);
}
-static void setgain(struct gspca_dev *gspca_dev)
+static void setgain(struct gspca_dev *gspca_dev, s32 val)
{
- struct sd *sd = (struct sd *) gspca_dev;
- int gain = GAIN_MAX - sd->gain;
-
- if (gain < 1)
- gain = 1;
- else if (gain > 245)
- gain = 245;
reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
reg_w(gspca_dev, 0x0e, 0x00);
- reg_w(gspca_dev, 0x0f, gain);
+ reg_w(gspca_dev, 0x0f, gspca_dev->gain->maximum - val + 1);
/* load registers to sensor (Bit 0, auto clear) */
reg_w(gspca_dev, 0x11, 0x01);
}
-static void setexposure(struct gspca_dev *gspca_dev)
+static void setexposure(struct gspca_dev *gspca_dev, s32 val)
{
- struct sd *sd = (struct sd *) gspca_dev;
- __u8 reg;
-
- /* register 2 of frame 3/4 contains the clock divider configuring the
- no fps according to the formula: 60 / reg. sd->exposure is the
- desired exposure time in ms. */
- reg = 120 * sd->exposure / 1000;
- if (reg < 2)
- reg = 2;
- else if (reg > 63)
- reg = 63;
-
reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
- reg_w(gspca_dev, 0x02, reg);
+ reg_w(gspca_dev, 0x02, val);
- /* Page 1 register 8 must always be 0x08 except when not in
- 640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */
+ /* load registers to sensor (Bit 0, auto clear) */
+ reg_w(gspca_dev, 0x11, 0x01);
+
+ /*
+ * Page 1 register 8 must always be 0x08 except when not in
+ * 640x480 mode and page 4 reg 2 <= 3 then it must be 9
+ */
reg_w(gspca_dev, 0xff, 0x01);
- if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
- reg <= 3) {
+ if (gspca_dev->width != 640 && val <= 3)
reg_w(gspca_dev, 0x08, 0x09);
- } else {
+ else
reg_w(gspca_dev, 0x08, 0x08);
- }
+
+ /*
+ * Page1 register 80 sets the compression balance, normally we
+ * want / use 0x1c, but for 640x480@30fps we must allow the
+ * camera to use higher compression or we may run out of
+ * bandwidth.
+ */
+ if (gspca_dev->width == 640 && val == 2)
+ reg_w(gspca_dev, 0x80, 0x01);
+ else
+ reg_w(gspca_dev, 0x80, 0x1c);
/* load registers to sensor (Bit 0, auto clear) */
reg_w(gspca_dev, 0x11, 0x01);
}
-static void sethvflip(struct gspca_dev *gspca_dev)
+static void sethvflip(struct gspca_dev *gspca_dev, s32 hflip, s32 vflip)
{
- struct sd *sd = (struct sd *) gspca_dev;
__u8 data;
reg_w(gspca_dev, 0xff, 0x04); /* page 4 */
- data = (sd->hflip ? 0x04 : 0x00) | (sd->vflip ? 0x08 : 0x00);
+ data = (hflip ? 0x04 : 0x00) |
+ (vflip ? 0x08 : 0x00);
reg_w(gspca_dev, 0x21, data);
/* load registers to sensor (Bit 0, auto clear) */
@@ -484,6 +367,82 @@ static int sd_init(struct gspca_dev *gspca_dev)
return gspca_dev->usb_err;
}
+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 (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) {
+ /* when switching to autogain set defaults to make sure
+ we are on a valid point of the autogain gain /
+ exposure knee graph, and give this change time to
+ take effect before doing autogain. */
+ gspca_dev->exposure->val = PAC7311_EXPOSURE_DEFAULT;
+ gspca_dev->gain->val = PAC7311_GAIN_DEFAULT;
+ sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
+ }
+
+ if (!gspca_dev->streaming)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_CONTRAST:
+ setcontrast(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val))
+ setexposure(gspca_dev, gspca_dev->exposure->val);
+ if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val))
+ setgain(gspca_dev, gspca_dev->gain->val);
+ break;
+ case V4L2_CID_HFLIP:
+ sethvflip(gspca_dev, sd->hflip->val, 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return gspca_dev->usb_err;
+}
+
+static const struct v4l2_ctrl_ops sd_ctrl_ops = {
+ .s_ctrl = sd_s_ctrl,
+};
+
+/* this function is called at probe time */
+static int sd_init_controls(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
+
+ gspca_dev->vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 4);
+
+ sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 15, 1, 7);
+ gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+ gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_EXPOSURE, 2, 63, 1,
+ PAC7311_EXPOSURE_DEFAULT);
+ gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_GAIN, 0, 244, 1,
+ PAC7311_GAIN_DEFAULT);
+ sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
+
+ v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false);
+ return 0;
+}
+
+/* -- start the camera -- */
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -492,19 +451,19 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w_var(gspca_dev, start_7311,
page4_7311, sizeof(page4_7311));
- setcontrast(gspca_dev);
- setgain(gspca_dev);
- setexposure(gspca_dev);
- sethvflip(gspca_dev);
+ setcontrast(gspca_dev, v4l2_ctrl_g_ctrl(sd->contrast));
+ setgain(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->gain));
+ setexposure(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure));
+ sethvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip), 1);
/* set correct resolution */
switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
- case 2: /* 160x120 pac7311 */
+ case 2: /* 160x120 */
reg_w(gspca_dev, 0xff, 0x01);
reg_w(gspca_dev, 0x17, 0x20);
reg_w(gspca_dev, 0x87, 0x10);
break;
- case 1: /* 320x240 pac7311 */
+ case 1: /* 320x240 */
reg_w(gspca_dev, 0xff, 0x01);
reg_w(gspca_dev, 0x17, 0x30);
reg_w(gspca_dev, 0x87, 0x11);
@@ -541,14 +500,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */
}
-/* called on streamoff with alt 0 and on disconnect for 7311 */
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
-}
-
-/* Include pac common sof detection functions */
-#include "pac_common.h"
-
static void do_autogain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -558,13 +509,13 @@ static void do_autogain(struct gspca_dev *gspca_dev)
if (avg_lum == -1)
return;
- desired_lum = 200;
+ desired_lum = 170;
deadzone = 20;
if (sd->autogain_ignore_frames > 0)
sd->autogain_ignore_frames--;
- else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
- deadzone, GAIN_KNEE, EXPOSURE_KNEE))
+ else if (gspca_coarse_grained_expo_autogain(gspca_dev, avg_lum,
+ desired_lum, deadzone))
sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
}
@@ -628,10 +579,12 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
if (sof) {
int n, lum_offset, footer_length;
- /* 6 bytes after the FF D9 EOF marker a number of lumination
- bytes are send corresponding to different parts of the
- image, the 14th and 15th byte after the EOF seem to
- correspond to the center of the image */
+ /*
+ * 6 bytes after the FF D9 EOF marker a number of lumination
+ * bytes are send corresponding to different parts of the
+ * image, the 14th and 15th byte after the EOF seem to
+ * correspond to the center of the image.
+ */
lum_offset = 24 + sizeof pac_sof_marker;
footer_length = 26;
@@ -668,127 +621,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->contrast = val;
- if (gspca_dev->streaming)
- setcontrast(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->contrast;
- return 0;
-}
-
-static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->gain = val;
- if (gspca_dev->streaming)
- setgain(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->gain;
- return 0;
-}
-
-static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->exposure = val;
- if (gspca_dev->streaming)
- setexposure(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->exposure;
- return 0;
-}
-
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->autogain = val;
- /* when switching to autogain set defaults to make sure
- we are on a valid point of the autogain gain /
- exposure knee graph, and give this change time to
- take effect before doing autogain. */
- if (sd->autogain) {
- sd->exposure = EXPOSURE_DEF;
- sd->gain = GAIN_DEF;
- if (gspca_dev->streaming) {
- sd->autogain_ignore_frames =
- PAC_AUTOGAIN_IGNORE_FRAMES;
- setexposure(gspca_dev);
- setgain(gspca_dev);
- }
- }
-
- return gspca_dev->usb_err;
-}
-
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->autogain;
- return 0;
-}
-
-static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->hflip = val;
- if (gspca_dev->streaming)
- sethvflip(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->hflip;
- return 0;
-}
-
-static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->vflip = val;
- if (gspca_dev->streaming)
- sethvflip(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->vflip;
- return 0;
-}
-
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet data */
@@ -820,16 +652,13 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
}
#endif
-/* sub-driver description for pac7311 */
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
- .ctrls = sd_ctrls,
- .nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
.init = sd_init,
+ .init_controls = sd_init_controls,
.start = sd_start,
.stopN = sd_stopN,
- .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
.dq_callback = do_autogain,
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c
index 7e71aa2d2522..ad098202d7f0 100644
--- a/drivers/media/video/gspca/sn9c20x.c
+++ b/drivers/media/video/gspca/sn9c20x.c
@@ -59,35 +59,38 @@ MODULE_LICENSE("GPL");
#define SENSOR_MT9M111 9
#define SENSOR_MT9M112 10
#define SENSOR_HV7131R 11
-#define SENSOR_MT9VPRB 20
+#define SENSOR_MT9VPRB 12
/* camera flags */
#define HAS_NO_BUTTON 0x1
#define LED_REVERSE 0x2 /* some cameras unset gpio to turn on leds */
#define FLIP_DETECT 0x4
-enum e_ctrl {
- BRIGHTNESS,
- CONTRAST,
- SATURATION,
- HUE,
- GAMMA,
- BLUE,
- RED,
- VFLIP,
- HFLIP,
- EXPOSURE,
- GAIN,
- AUTOGAIN,
- QUALITY,
- NCTRLS /* number of controls */
-};
-
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev;
- struct gspca_ctrl ctrls[NCTRLS];
+ struct { /* color control cluster */
+ struct v4l2_ctrl *brightness;
+ struct v4l2_ctrl *contrast;
+ struct v4l2_ctrl *saturation;
+ struct v4l2_ctrl *hue;
+ };
+ struct { /* blue/red balance control cluster */
+ struct v4l2_ctrl *blue;
+ struct v4l2_ctrl *red;
+ };
+ struct { /* h/vflip control cluster */
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+ };
+ struct v4l2_ctrl *gamma;
+ struct { /* autogain and exposure or gain control cluster */
+ struct v4l2_ctrl *autogain;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *gain;
+ };
+ struct v4l2_ctrl *jpegqual;
struct work_struct work;
struct workqueue_struct *work_thread;
@@ -105,6 +108,7 @@ struct sd {
u8 exposure_step;
u8 i2c_addr;
+ u8 i2c_intf;
u8 sensor;
u8 hstart;
u8 vstart;
@@ -166,175 +170,6 @@ static const struct dmi_system_id flip_dmi_table[] = {
{}
};
-static void set_cmatrix(struct gspca_dev *gspca_dev);
-static void set_gamma(struct gspca_dev *gspca_dev);
-static void set_redblue(struct gspca_dev *gspca_dev);
-static void set_hvflip(struct gspca_dev *gspca_dev);
-static void set_exposure(struct gspca_dev *gspca_dev);
-static void set_gain(struct gspca_dev *gspca_dev);
-static void set_quality(struct gspca_dev *gspca_dev);
-
-static const struct ctrl sd_ctrls[NCTRLS] = {
-[BRIGHTNESS] = {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 0xff,
- .step = 1,
- .default_value = 0x7f
- },
- .set_control = set_cmatrix
- },
-[CONTRAST] = {
- {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 0xff,
- .step = 1,
- .default_value = 0x7f
- },
- .set_control = set_cmatrix
- },
-[SATURATION] = {
- {
- .id = V4L2_CID_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 0xff,
- .step = 1,
- .default_value = 0x7f
- },
- .set_control = set_cmatrix
- },
-[HUE] = {
- {
- .id = V4L2_CID_HUE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hue",
- .minimum = -180,
- .maximum = 180,
- .step = 1,
- .default_value = 0
- },
- .set_control = set_cmatrix
- },
-[GAMMA] = {
- {
- .id = V4L2_CID_GAMMA,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gamma",
- .minimum = 0,
- .maximum = 0xff,
- .step = 1,
- .default_value = 0x10
- },
- .set_control = set_gamma
- },
-[BLUE] = {
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Blue Balance",
- .minimum = 0,
- .maximum = 0x7f,
- .step = 1,
- .default_value = 0x28
- },
- .set_control = set_redblue
- },
-[RED] = {
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Red Balance",
- .minimum = 0,
- .maximum = 0x7f,
- .step = 1,
- .default_value = 0x28
- },
- .set_control = set_redblue
- },
-[HFLIP] = {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Horizontal Flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .set_control = set_hvflip
- },
-[VFLIP] = {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Vertical Flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .set_control = set_hvflip
- },
-[EXPOSURE] = {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Exposure",
- .minimum = 0,
- .maximum = 0x1780,
- .step = 1,
- .default_value = 0x33,
- },
- .set_control = set_exposure
- },
-[GAIN] = {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain",
- .minimum = 0,
- .maximum = 28,
- .step = 1,
- .default_value = 0,
- },
- .set_control = set_gain
- },
-[AUTOGAIN] = {
- {
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Auto Exposure",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- },
- },
-[QUALITY] = {
- {
- .id = V4L2_CID_JPEG_COMPRESSION_QUALITY,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Compression Quality",
-#define QUALITY_MIN 50
-#define QUALITY_MAX 90
-#define QUALITY_DEF 80
- .minimum = QUALITY_MIN,
- .maximum = QUALITY_MAX,
- .step = 1,
- .default_value = QUALITY_DEF,
- },
- .set_control = set_quality
- },
-};
-
static const struct v4l2_pix_format vga_mode[] = {
{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 160,
@@ -747,7 +582,7 @@ static const s16 hsv_blue_y[] = {
4, 2, 0, -1, -3, -5, -7, -9, -11
};
-static u16 i2c_ident[] = {
+static const u16 i2c_ident[] = {
V4L2_IDENT_OV9650,
V4L2_IDENT_OV9655,
V4L2_IDENT_SOI968,
@@ -760,9 +595,10 @@ static u16 i2c_ident[] = {
V4L2_IDENT_MT9M111,
V4L2_IDENT_MT9M112,
V4L2_IDENT_HV7131R,
+[SENSOR_MT9VPRB] = V4L2_IDENT_UNKNOWN,
};
-static u16 bridge_init[][2] = {
+static const u16 bridge_init[][2] = {
{0x1000, 0x78}, {0x1001, 0x40}, {0x1002, 0x1c},
{0x1020, 0x80}, {0x1061, 0x01}, {0x1067, 0x40},
{0x1068, 0x30}, {0x1069, 0x20}, {0x106a, 0x10},
@@ -786,7 +622,7 @@ static u16 bridge_init[][2] = {
};
/* Gain = (bit[3:0] / 16 + 1) * (bit[4] + 1) * (bit[5] + 1) * (bit[6] + 1) */
-static u8 ov_gain[] = {
+static const u8 ov_gain[] = {
0x00 /* 1x */, 0x04 /* 1.25x */, 0x08 /* 1.5x */, 0x0c /* 1.75x */,
0x10 /* 2x */, 0x12 /* 2.25x */, 0x14 /* 2.5x */, 0x16 /* 2.75x */,
0x18 /* 3x */, 0x1a /* 3.25x */, 0x1c /* 3.5x */, 0x1e /* 3.75x */,
@@ -798,7 +634,7 @@ static u8 ov_gain[] = {
};
/* Gain = (bit[8] + 1) * (bit[7] + 1) * (bit[6:0] * 0.03125) */
-static u16 micron1_gain[] = {
+static const u16 micron1_gain[] = {
/* 1x 1.25x 1.5x 1.75x */
0x0020, 0x0028, 0x0030, 0x0038,
/* 2x 2.25x 2.5x 2.75x */
@@ -819,7 +655,7 @@ static u16 micron1_gain[] = {
/* mt9m001 sensor uses a different gain formula then other micron sensors */
/* Gain = (bit[6] + 1) * (bit[5-0] * 0.125) */
-static u16 micron2_gain[] = {
+static const u16 micron2_gain[] = {
/* 1x 1.25x 1.5x 1.75x */
0x0008, 0x000a, 0x000c, 0x000e,
/* 2x 2.25x 2.5x 2.75x */
@@ -839,7 +675,7 @@ static u16 micron2_gain[] = {
};
/* Gain = .5 + bit[7:0] / 16 */
-static u8 hv7131r_gain[] = {
+static const u8 hv7131r_gain[] = {
0x08 /* 1x */, 0x0c /* 1.25x */, 0x10 /* 1.5x */, 0x14 /* 1.75x */,
0x18 /* 2x */, 0x1c /* 2.25x */, 0x20 /* 2.5x */, 0x24 /* 2.75x */,
0x28 /* 3x */, 0x2c /* 3.25x */, 0x30 /* 3.5x */, 0x34 /* 3.75x */,
@@ -850,7 +686,7 @@ static u8 hv7131r_gain[] = {
0x78 /* 8x */
};
-static struct i2c_reg_u8 soi968_init[] = {
+static const struct i2c_reg_u8 soi968_init[] = {
{0x0c, 0x00}, {0x0f, 0x1f},
{0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00},
{0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c},
@@ -864,7 +700,7 @@ static struct i2c_reg_u8 soi968_init[] = {
{0x00, 0x00}, {0x01, 0x80}, {0x02, 0x80},
};
-static struct i2c_reg_u8 ov7660_init[] = {
+static const struct i2c_reg_u8 ov7660_init[] = {
{0x0e, 0x80}, {0x0d, 0x08}, {0x0f, 0xc3},
{0x04, 0xc3}, {0x10, 0x40}, {0x11, 0x40},
{0x12, 0x05}, {0x13, 0xba}, {0x14, 0x2a},
@@ -872,11 +708,11 @@ static struct i2c_reg_u8 ov7660_init[] = {
0x10, 0x61 and sd->hstart, vstart = 3, fixes ugly colored borders */
{0x17, 0x10}, {0x18, 0x61},
{0x37, 0x0f}, {0x38, 0x02}, {0x39, 0x43},
- {0x3a, 0x00}, {0x69, 0x90}, {0x2d, 0xf6},
- {0x2e, 0x0b}, {0x01, 0x78}, {0x02, 0x50},
+ {0x3a, 0x00}, {0x69, 0x90}, {0x2d, 0x00},
+ {0x2e, 0x00}, {0x01, 0x78}, {0x02, 0x50},
};
-static struct i2c_reg_u8 ov7670_init[] = {
+static const struct i2c_reg_u8 ov7670_init[] = {
{0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
{0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00},
{0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0},
@@ -933,7 +769,7 @@ static struct i2c_reg_u8 ov7670_init[] = {
{0x93, 0x00},
};
-static struct i2c_reg_u8 ov9650_init[] = {
+static const struct i2c_reg_u8 ov9650_init[] = {
{0x00, 0x00}, {0x01, 0x78},
{0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03},
{0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00},
@@ -963,7 +799,7 @@ static struct i2c_reg_u8 ov9650_init[] = {
{0xaa, 0x92}, {0xab, 0x0a},
};
-static struct i2c_reg_u8 ov9655_init[] = {
+static const struct i2c_reg_u8 ov9655_init[] = {
{0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba},
{0x14, 0x2e}, {0x16, 0x24}, {0x1e, 0x04}, {0x27, 0x08},
{0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x34, 0x3d},
@@ -990,7 +826,7 @@ static struct i2c_reg_u8 ov9655_init[] = {
{0x04, 0x03}, {0x00, 0x13},
};
-static struct i2c_reg_u16 mt9v112_init[] = {
+static const struct i2c_reg_u16 mt9v112_init[] = {
{0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0020},
{0x34, 0xc019}, {0x0a, 0x0011}, {0x0b, 0x000b},
{0x20, 0x0703}, {0x35, 0x2022}, {0xf0, 0x0001},
@@ -1009,7 +845,7 @@ static struct i2c_reg_u16 mt9v112_init[] = {
{0x2c, 0x00ae}, {0x2d, 0x00ae}, {0x2e, 0x00ae},
};
-static struct i2c_reg_u16 mt9v111_init[] = {
+static const struct i2c_reg_u16 mt9v111_init[] = {
{0x01, 0x0004}, {0x0d, 0x0001}, {0x0d, 0x0000},
{0x01, 0x0001}, {0x05, 0x0004}, {0x2d, 0xe0a0},
{0x2e, 0x0c64}, {0x2f, 0x0064}, {0x06, 0x600e},
@@ -1019,7 +855,7 @@ static struct i2c_reg_u16 mt9v111_init[] = {
{0x0e, 0x0008}, {0x20, 0x0000}
};
-static struct i2c_reg_u16 mt9v011_init[] = {
+static const struct i2c_reg_u16 mt9v011_init[] = {
{0x07, 0x0002}, {0x0d, 0x0001}, {0x0d, 0x0000},
{0x01, 0x0008}, {0x02, 0x0016}, {0x03, 0x01e1},
{0x04, 0x0281}, {0x05, 0x0083}, {0x06, 0x0006},
@@ -1046,7 +882,7 @@ static struct i2c_reg_u16 mt9v011_init[] = {
{0x06, 0x0029}, {0x05, 0x0009},
};
-static struct i2c_reg_u16 mt9m001_init[] = {
+static const struct i2c_reg_u16 mt9m001_init[] = {
{0x0d, 0x0001},
{0x0d, 0x0000},
{0x04, 0x0500}, /* hres = 1280 */
@@ -1062,21 +898,21 @@ static struct i2c_reg_u16 mt9m001_init[] = {
{0x35, 0x0057},
};
-static struct i2c_reg_u16 mt9m111_init[] = {
+static const struct i2c_reg_u16 mt9m111_init[] = {
{0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
{0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
{0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
{0xf0, 0x0000},
};
-static struct i2c_reg_u16 mt9m112_init[] = {
+static const struct i2c_reg_u16 mt9m112_init[] = {
{0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008},
{0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300},
{0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e},
{0xf0, 0x0000},
};
-static struct i2c_reg_u8 hv7131r_init[] = {
+static const struct i2c_reg_u8 hv7131r_init[] = {
{0x02, 0x08}, {0x02, 0x00}, {0x01, 0x08},
{0x02, 0x00}, {0x20, 0x00}, {0x21, 0xd0},
{0x22, 0x00}, {0x23, 0x09}, {0x01, 0x08},
@@ -1167,7 +1003,7 @@ static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
* from the point of view of the bridge, the length
* includes the address
*/
- row[0] = 0x81 | (2 << 4);
+ row[0] = sd->i2c_intf | (2 << 4);
row[1] = sd->i2c_addr;
row[2] = reg;
row[3] = val;
@@ -1180,7 +1016,7 @@ static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
}
static void i2c_w1_buf(struct gspca_dev *gspca_dev,
- struct i2c_reg_u8 *buf, int sz)
+ const struct i2c_reg_u8 *buf, int sz)
{
while (--sz >= 0) {
i2c_w1(gspca_dev, buf->reg, buf->val);
@@ -1197,7 +1033,7 @@ static void i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
* from the point of view of the bridge, the length
* includes the address
*/
- row[0] = 0x81 | (3 << 4);
+ row[0] = sd->i2c_intf | (3 << 4);
row[1] = sd->i2c_addr;
row[2] = reg;
row[3] = val >> 8;
@@ -1210,7 +1046,7 @@ static void i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
}
static void i2c_w2_buf(struct gspca_dev *gspca_dev,
- struct i2c_reg_u16 *buf, int sz)
+ const struct i2c_reg_u16 *buf, int sz)
{
while (--sz >= 0) {
i2c_w2(gspca_dev, buf->reg, buf->val);
@@ -1223,7 +1059,7 @@ static void i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
struct sd *sd = (struct sd *) gspca_dev;
u8 row[8];
- row[0] = 0x81 | (1 << 4);
+ row[0] = sd->i2c_intf | (1 << 4);
row[1] = sd->i2c_addr;
row[2] = reg;
row[3] = 0;
@@ -1232,7 +1068,7 @@ static void i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
row[6] = 0;
row[7] = 0x10;
i2c_w(gspca_dev, row);
- row[0] = 0x81 | (1 << 4) | 0x02;
+ row[0] = sd->i2c_intf | (1 << 4) | 0x02;
row[2] = 0;
i2c_w(gspca_dev, row);
reg_r(gspca_dev, 0x10c2, 5);
@@ -1244,7 +1080,7 @@ static void i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
struct sd *sd = (struct sd *) gspca_dev;
u8 row[8];
- row[0] = 0x81 | (1 << 4);
+ row[0] = sd->i2c_intf | (1 << 4);
row[1] = sd->i2c_addr;
row[2] = reg;
row[3] = 0;
@@ -1253,7 +1089,7 @@ static void i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
row[6] = 0;
row[7] = 0x10;
i2c_w(gspca_dev, row);
- row[0] = 0x81 | (2 << 4) | 0x02;
+ row[0] = sd->i2c_intf | (2 << 4) | 0x02;
row[2] = 0;
i2c_w(gspca_dev, row);
reg_r(gspca_dev, 0x10c2, 5);
@@ -1294,8 +1130,6 @@ static void ov9655_init_sensor(struct gspca_dev *gspca_dev)
if (gspca_dev->usb_err < 0)
pr_err("OV9655 sensor initialization failed\n");
- /* disable hflip and vflip */
- gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
sd->hstart = 1;
sd->vstart = 2;
}
@@ -1310,9 +1144,6 @@ static void soi968_init_sensor(struct gspca_dev *gspca_dev)
if (gspca_dev->usb_err < 0)
pr_err("SOI968 sensor initialization failed\n");
- /* disable hflip and vflip */
- gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP)
- | (1 << EXPOSURE);
sd->hstart = 60;
sd->vstart = 11;
}
@@ -1340,8 +1171,6 @@ static void ov7670_init_sensor(struct gspca_dev *gspca_dev)
if (gspca_dev->usb_err < 0)
pr_err("OV7670 sensor initialization failed\n");
- /* disable hflip and vflip */
- gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
sd->hstart = 0;
sd->vstart = 1;
}
@@ -1378,9 +1207,6 @@ static void mt9v_init_sensor(struct gspca_dev *gspca_dev)
pr_err("MT9V111 sensor initialization failed\n");
return;
}
- gspca_dev->ctrl_dis = (1 << EXPOSURE)
- | (1 << AUTOGAIN)
- | (1 << GAIN);
sd->hstart = 2;
sd->vstart = 2;
sd->sensor = SENSOR_MT9V111;
@@ -1422,8 +1248,6 @@ static void mt9m112_init_sensor(struct gspca_dev *gspca_dev)
if (gspca_dev->usb_err < 0)
pr_err("MT9M112 sensor initialization failed\n");
- gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN)
- | (1 << GAIN);
sd->hstart = 0;
sd->vstart = 2;
}
@@ -1436,8 +1260,6 @@ static void mt9m111_init_sensor(struct gspca_dev *gspca_dev)
if (gspca_dev->usb_err < 0)
pr_err("MT9M111 sensor initialization failed\n");
- gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN)
- | (1 << GAIN);
sd->hstart = 0;
sd->vstart = 2;
}
@@ -1470,8 +1292,6 @@ static void mt9m001_init_sensor(struct gspca_dev *gspca_dev)
if (gspca_dev->usb_err < 0)
pr_err("MT9M001 sensor initialization failed\n");
- /* disable hflip and vflip */
- gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
sd->hstart = 1;
sd->vstart = 1;
}
@@ -1488,20 +1308,18 @@ static void hv7131r_init_sensor(struct gspca_dev *gspca_dev)
sd->vstart = 1;
}
-static void set_cmatrix(struct gspca_dev *gspca_dev)
+static void set_cmatrix(struct gspca_dev *gspca_dev,
+ s32 brightness, s32 contrast, s32 satur, s32 hue)
{
- struct sd *sd = (struct sd *) gspca_dev;
- int satur;
- s32 hue_coord, hue_index = 180 + sd->ctrls[HUE].val;
+ s32 hue_coord, hue_index = 180 + hue;
u8 cmatrix[21];
memset(cmatrix, 0, sizeof cmatrix);
- cmatrix[2] = (sd->ctrls[CONTRAST].val * 0x25 / 0x100) + 0x26;
+ cmatrix[2] = (contrast * 0x25 / 0x100) + 0x26;
cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
- cmatrix[18] = sd->ctrls[BRIGHTNESS].val - 0x80;
+ cmatrix[18] = brightness - 0x80;
- satur = sd->ctrls[SATURATION].val;
hue_coord = (hsv_red_x[hue_index] * satur) >> 8;
cmatrix[6] = hue_coord;
cmatrix[7] = (hue_coord >> 8) & 0x0f;
@@ -1529,11 +1347,10 @@ static void set_cmatrix(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x10e1, cmatrix, 21);
}
-static void set_gamma(struct gspca_dev *gspca_dev)
+static void set_gamma(struct gspca_dev *gspca_dev, s32 val)
{
- struct sd *sd = (struct sd *) gspca_dev;
u8 gamma[17];
- u8 gval = sd->ctrls[GAMMA].val * 0xb8 / 0x100;
+ u8 gval = val * 0xb8 / 0x100;
gamma[0] = 0x0a;
gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8);
@@ -1556,26 +1373,21 @@ static void set_gamma(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x1190, gamma, 17);
}
-static void set_redblue(struct gspca_dev *gspca_dev)
+static void set_redblue(struct gspca_dev *gspca_dev, s32 blue, s32 red)
{
- struct sd *sd = (struct sd *) gspca_dev;
-
- reg_w1(gspca_dev, 0x118c, sd->ctrls[RED].val);
- reg_w1(gspca_dev, 0x118f, sd->ctrls[BLUE].val);
+ reg_w1(gspca_dev, 0x118c, red);
+ reg_w1(gspca_dev, 0x118f, blue);
}
-static void set_hvflip(struct gspca_dev *gspca_dev)
+static void set_hvflip(struct gspca_dev *gspca_dev, s32 hflip, s32 vflip)
{
- u8 value, tslb, hflip, vflip;
+ u8 value, tslb;
u16 value2;
struct sd *sd = (struct sd *) gspca_dev;
if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) {
- hflip = !sd->ctrls[HFLIP].val;
- vflip = !sd->ctrls[VFLIP].val;
- } else {
- hflip = sd->ctrls[HFLIP].val;
- vflip = sd->ctrls[VFLIP].val;
+ hflip = !hflip;
+ vflip = !vflip;
}
switch (sd->sensor) {
@@ -1638,20 +1450,38 @@ static void set_hvflip(struct gspca_dev *gspca_dev)
}
}
-static void set_exposure(struct gspca_dev *gspca_dev)
+static void set_exposure(struct gspca_dev *gspca_dev, s32 expo)
{
struct sd *sd = (struct sd *) gspca_dev;
- u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e};
- int expo;
+ u8 exp[8] = {sd->i2c_intf, sd->i2c_addr,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
+ int expo2;
+
+ if (gspca_dev->streaming)
+ exp[7] = 0x1e;
- expo = sd->ctrls[EXPOSURE].val;
switch (sd->sensor) {
case SENSOR_OV7660:
case SENSOR_OV7670:
case SENSOR_OV9655:
case SENSOR_OV9650:
+ if (expo > 547)
+ expo2 = 547;
+ else
+ expo2 = expo;
+ exp[0] |= (2 << 4);
+ exp[2] = 0x10; /* AECH */
+ exp[3] = expo2 >> 2;
+ exp[7] = 0x10;
+ i2c_w(gspca_dev, exp);
+ exp[2] = 0x04; /* COM1 */
+ exp[3] = expo2 & 0x0003;
+ exp[7] = 0x10;
+ i2c_w(gspca_dev, exp);
+ expo -= expo2;
+ exp[7] = 0x1e;
exp[0] |= (3 << 4);
- exp[2] = 0x2d;
+ exp[2] = 0x2d; /* ADVFL & ADVFH */
exp[3] = expo;
exp[4] = expo >> 8;
break;
@@ -1676,13 +1506,15 @@ static void set_exposure(struct gspca_dev *gspca_dev)
i2c_w(gspca_dev, exp);
}
-static void set_gain(struct gspca_dev *gspca_dev)
+static void set_gain(struct gspca_dev *gspca_dev, s32 g)
{
struct sd *sd = (struct sd *) gspca_dev;
- u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d};
- int g;
+ u8 gain[8] = {sd->i2c_intf, sd->i2c_addr,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
+
+ if (gspca_dev->streaming)
+ gain[7] = 0x15; /* or 1d ? */
- g = sd->ctrls[GAIN].val;
switch (sd->sensor) {
case SENSOR_OV7660:
case SENSOR_OV7670:
@@ -1721,11 +1553,11 @@ static void set_gain(struct gspca_dev *gspca_dev)
i2c_w(gspca_dev, gain);
}
-static void set_quality(struct gspca_dev *gspca_dev)
+static void set_quality(struct gspca_dev *gspca_dev, s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val);
+ jpeg_set_qual(sd->jpeg_hdr, val);
reg_w1(gspca_dev, 0x1061, 0x01); /* stop transfer */
reg_w1(gspca_dev, 0x10e0, sd->fmt | 0x20); /* write QTAB */
reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
@@ -1827,6 +1659,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->sensor = id->driver_info >> 8;
sd->i2c_addr = id->driver_info;
sd->flags = id->driver_info >> 16;
+ sd->i2c_intf = 0x80; /* i2c 100 Kb/s */
switch (sd->sensor) {
case SENSOR_MT9M112:
@@ -1840,6 +1673,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->cam_mode = mono_mode;
cam->nmodes = ARRAY_SIZE(mono_mode);
break;
+ case SENSOR_HV7131R:
+ sd->i2c_intf = 0x81; /* i2c 400 Kb/s */
+ /* fall thru */
default:
cam->cam_mode = vga_mode;
cam->nmodes = ARRAY_SIZE(vga_mode);
@@ -1850,13 +1686,133 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->older_step = 0;
sd->exposure_step = 16;
- gspca_dev->cam.ctrls = sd->ctrls;
-
INIT_WORK(&sd->work, qual_upd);
return 0;
}
+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) {
+ /* color control cluster */
+ case V4L2_CID_BRIGHTNESS:
+ set_cmatrix(gspca_dev, sd->brightness->val,
+ sd->contrast->val, sd->saturation->val, sd->hue->val);
+ break;
+ case V4L2_CID_GAMMA:
+ set_gamma(gspca_dev, ctrl->val);
+ break;
+ /* blue/red balance cluster */
+ case V4L2_CID_BLUE_BALANCE:
+ set_redblue(gspca_dev, sd->blue->val, sd->red->val);
+ break;
+ /* h/vflip cluster */
+ case V4L2_CID_HFLIP:
+ set_hvflip(gspca_dev, sd->hflip->val, sd->vflip->val);
+ break;
+ /* standalone exposure control */
+ case V4L2_CID_EXPOSURE:
+ set_exposure(gspca_dev, ctrl->val);
+ break;
+ /* standalone gain control */
+ case V4L2_CID_GAIN:
+ set_gain(gspca_dev, ctrl->val);
+ break;
+ /* autogain + exposure or gain control cluster */
+ case V4L2_CID_AUTOGAIN:
+ if (sd->sensor == SENSOR_SOI968)
+ set_gain(gspca_dev, sd->gain->val);
+ else
+ set_exposure(gspca_dev, sd->exposure->val);
+ break;
+ case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+ set_quality(gspca_dev, ctrl->val);
+ break;
+ }
+ return gspca_dev->usb_err;
+}
+
+static const struct v4l2_ctrl_ops sd_ctrl_ops = {
+ .s_ctrl = sd_s_ctrl,
+};
+
+static int sd_init_controls(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
+
+ gspca_dev->vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 13);
+
+ sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
+ sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1, 127);
+ sd->saturation = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 255, 1, 127);
+ sd->hue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_HUE, -180, 180, 1, 0);
+ v4l2_ctrl_cluster(4, &sd->brightness);
+
+ sd->gamma = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_GAMMA, 0, 255, 1, 0x10);
+
+ sd->blue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_BLUE_BALANCE, 0, 127, 1, 0x28);
+ sd->red = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_RED_BALANCE, 0, 127, 1, 0x28);
+ v4l2_ctrl_cluster(2, &sd->blue);
+
+ if (sd->sensor != SENSOR_OV9655 && sd->sensor != SENSOR_SOI968 &&
+ sd->sensor != SENSOR_OV7670 && sd->sensor != SENSOR_MT9M001 &&
+ sd->sensor != SENSOR_MT9VPRB) {
+ sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_cluster(2, &sd->hflip);
+ }
+
+ if (sd->sensor != SENSOR_SOI968 && sd->sensor != SENSOR_MT9VPRB &&
+ sd->sensor != SENSOR_MT9M112 && sd->sensor != SENSOR_MT9M111 &&
+ sd->sensor != SENSOR_MT9V111)
+ sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_EXPOSURE, 0, 0x1780, 1, 0x33);
+
+ if (sd->sensor != SENSOR_MT9VPRB && sd->sensor != SENSOR_MT9M112 &&
+ sd->sensor != SENSOR_MT9M111 && sd->sensor != SENSOR_MT9V111) {
+ sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_GAIN, 0, 28, 1, 0);
+ sd->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+ if (sd->sensor == SENSOR_SOI968)
+ /* this sensor doesn't have the exposure control and
+ autogain is clustered with gain instead. This works
+ because sd->exposure == NULL. */
+ v4l2_ctrl_auto_cluster(3, &sd->autogain, 0, false);
+ else
+ /* Otherwise autogain is clustered with exposure. */
+ v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false);
+ }
+
+ sd->jpegqual = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_JPEG_COMPRESSION_QUALITY, 50, 90, 1, 80);
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
+ return 0;
+}
+
static int sd_init(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -1949,7 +1905,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
pr_err("Unsupported sensor\n");
gspca_dev->usb_err = -ENODEV;
}
-
return gspca_dev->usb_err;
}
@@ -2025,8 +1980,8 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev)
if (intf->num_altsetting != 9) {
pr_warn("sn9c20x camera with unknown number of alt "
- "settings (%d), please report!\n",
- intf->num_altsetting);
+ "settings (%d), please report!\n",
+ intf->num_altsetting);
gspca_dev->alt = intf->num_altsetting;
return 0;
}
@@ -2067,7 +2022,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
jpeg_define(sd->jpeg_hdr, height, width,
0x21);
- jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val);
+ jpeg_set_qual(sd->jpeg_hdr, v4l2_ctrl_g_ctrl(sd->jpegqual));
if (mode & MODE_RAW)
fmt = 0x2d;
@@ -2104,12 +2059,17 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0x1189, scale);
reg_w1(gspca_dev, 0x10e0, fmt);
- set_cmatrix(gspca_dev);
- set_gamma(gspca_dev);
- set_redblue(gspca_dev);
- set_gain(gspca_dev);
- set_exposure(gspca_dev);
- set_hvflip(gspca_dev);
+ set_cmatrix(gspca_dev, v4l2_ctrl_g_ctrl(sd->brightness),
+ v4l2_ctrl_g_ctrl(sd->contrast),
+ v4l2_ctrl_g_ctrl(sd->saturation),
+ v4l2_ctrl_g_ctrl(sd->hue));
+ set_gamma(gspca_dev, v4l2_ctrl_g_ctrl(sd->gamma));
+ set_redblue(gspca_dev, v4l2_ctrl_g_ctrl(sd->blue),
+ v4l2_ctrl_g_ctrl(sd->red));
+ set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain));
+ set_exposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure));
+ set_hvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip),
+ v4l2_ctrl_g_ctrl(sd->vflip));
reg_w1(gspca_dev, 0x1007, 0x20);
reg_w1(gspca_dev, 0x1061, 0x03);
@@ -2148,6 +2108,9 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
{
struct sd *sd = (struct sd *) gspca_dev;
+ s32 cur_exp = v4l2_ctrl_g_ctrl(sd->exposure);
+ s32 max = sd->exposure->maximum - sd->exposure_step;
+ s32 min = sd->exposure->minimum + sd->exposure_step;
s16 new_exp;
/*
@@ -2156,16 +2119,15 @@ static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
* and exposure steps
*/
if (avg_lum < MIN_AVG_LUM) {
- if (sd->ctrls[EXPOSURE].val > 0x1770)
+ if (cur_exp > max)
return;
- new_exp = sd->ctrls[EXPOSURE].val + sd->exposure_step;
- if (new_exp > 0x1770)
- new_exp = 0x1770;
- if (new_exp < 0x10)
- new_exp = 0x10;
- sd->ctrls[EXPOSURE].val = new_exp;
- set_exposure(gspca_dev);
+ new_exp = cur_exp + sd->exposure_step;
+ if (new_exp > max)
+ new_exp = max;
+ if (new_exp < min)
+ new_exp = min;
+ v4l2_ctrl_s_ctrl(sd->exposure, new_exp);
sd->older_step = sd->old_step;
sd->old_step = 1;
@@ -2176,15 +2138,14 @@ static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
sd->exposure_step += 2;
}
if (avg_lum > MAX_AVG_LUM) {
- if (sd->ctrls[EXPOSURE].val < 0x10)
+ if (cur_exp < min)
return;
- new_exp = sd->ctrls[EXPOSURE].val - sd->exposure_step;
- if (new_exp > 0x1700)
- new_exp = 0x1770;
- if (new_exp < 0x10)
- new_exp = 0x10;
- sd->ctrls[EXPOSURE].val = new_exp;
- set_exposure(gspca_dev);
+ new_exp = cur_exp - sd->exposure_step;
+ if (new_exp > max)
+ new_exp = max;
+ if (new_exp < min)
+ new_exp = min;
+ v4l2_ctrl_s_ctrl(sd->exposure, new_exp);
sd->older_step = sd->old_step;
sd->old_step = 0;
@@ -2198,19 +2159,12 @@ static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum)
{
struct sd *sd = (struct sd *) gspca_dev;
+ s32 cur_gain = v4l2_ctrl_g_ctrl(sd->gain);
- if (avg_lum < MIN_AVG_LUM) {
- if (sd->ctrls[GAIN].val + 1 <= 28) {
- sd->ctrls[GAIN].val++;
- set_gain(gspca_dev);
- }
- }
- if (avg_lum > MAX_AVG_LUM) {
- if (sd->ctrls[GAIN].val > 0) {
- sd->ctrls[GAIN].val--;
- set_gain(gspca_dev);
- }
- }
+ if (avg_lum < MIN_AVG_LUM && cur_gain < sd->gain->maximum)
+ v4l2_ctrl_s_ctrl(sd->gain, cur_gain + 1);
+ if (avg_lum > MAX_AVG_LUM && cur_gain > sd->gain->minimum)
+ v4l2_ctrl_s_ctrl(sd->gain, cur_gain - 1);
}
static void sd_dqcallback(struct gspca_dev *gspca_dev)
@@ -2218,7 +2172,7 @@ static void sd_dqcallback(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
int avg_lum;
- if (!sd->ctrls[AUTOGAIN].val)
+ if (!v4l2_ctrl_g_ctrl(sd->autogain))
return;
avg_lum = atomic_read(&sd->avg_lum);
@@ -2234,10 +2188,11 @@ static void qual_upd(struct work_struct *work)
{
struct sd *sd = container_of(work, struct sd, work);
struct gspca_dev *gspca_dev = &sd->gspca_dev;
+ s32 qual = v4l2_ctrl_g_ctrl(sd->jpegqual);
mutex_lock(&gspca_dev->usb_lock);
- PDEBUG(D_STREAM, "qual_upd %d%%", sd->ctrls[QUALITY].val);
- set_quality(gspca_dev);
+ PDEBUG(D_STREAM, "qual_upd %d%%", qual);
+ set_quality(gspca_dev, qual);
mutex_unlock(&gspca_dev->usb_lock);
}
@@ -2286,14 +2241,18 @@ static void transfer_check(struct gspca_dev *gspca_dev,
if (new_qual != 0) {
sd->nchg += new_qual;
if (sd->nchg < -6 || sd->nchg >= 12) {
+ /* Note: we are in interrupt context, so we can't
+ use v4l2_ctrl_g/s_ctrl here. Access the value
+ directly instead. */
+ s32 curqual = sd->jpegqual->cur.val;
sd->nchg = 0;
- new_qual += sd->ctrls[QUALITY].val;
- if (new_qual < QUALITY_MIN)
- new_qual = QUALITY_MIN;
- else if (new_qual > QUALITY_MAX)
- new_qual = QUALITY_MAX;
- if (new_qual != sd->ctrls[QUALITY].val) {
- sd->ctrls[QUALITY].val = new_qual;
+ new_qual += curqual;
+ if (new_qual < sd->jpegqual->minimum)
+ new_qual = sd->jpegqual->minimum;
+ else if (new_qual > sd->jpegqual->maximum)
+ new_qual = sd->jpegqual->maximum;
+ if (new_qual != curqual) {
+ sd->jpegqual->cur.val = new_qual;
queue_work(sd->work_thread, &sd->work);
}
}
@@ -2309,7 +2268,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
{
struct sd *sd = (struct sd *) gspca_dev;
int avg_lum, is_jpeg;
- static u8 frame_header[] =
+ static const u8 frame_header[] =
{0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
is_jpeg = (sd->fmt & 0x03) == 0;
@@ -2373,10 +2332,9 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
/* sub-driver description */
static const struct sd_desc sd_desc = {
.name = KBUILD_MODNAME,
- .ctrls = sd_ctrls,
- .nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
.init = sd_init,
+ .init_controls = sd_init_controls,
.isoc_init = sd_isoc_init,
.start = sd_start,
.stopN = sd_stopN,
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
index 6a1148d7fe92..e2bdf8f632f4 100644
--- a/drivers/media/video/gspca/sonixb.c
+++ b/drivers/media/video/gspca/sonixb.c
@@ -1000,6 +1000,8 @@ static void setfreq(struct gspca_dev *gspca_dev)
}
}
+#define WANT_REGULAR_AUTOGAIN
+#define WANT_COARSE_EXPO_AUTOGAIN
#include "autogain_functions.h"
static void do_autogain(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index 863c755dd2b7..4d1696d1a7f4 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -2800,10 +2800,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
}
}
-/* !! coarse_grained_expo_autogain is not used !! */
-#define exp_too_low_cnt bridge
-#define exp_too_high_cnt sensor
-
+#define WANT_REGULAR_AUTOGAIN
#include "autogain_functions.h"
static void do_autogain(struct gspca_dev *gspca_dev)
diff --git a/drivers/media/video/gspca/sq905.c b/drivers/media/video/gspca/sq905.c
index 2fe3c29bd6b7..04f54654a026 100644
--- a/drivers/media/video/gspca/sq905.c
+++ b/drivers/media/video/gspca/sq905.c
@@ -232,7 +232,11 @@ static void sq905_dostream(struct work_struct *work)
frame_sz = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].sizeimage
+ FRAME_HEADER_LEN;
- while (gspca_dev->present && gspca_dev->streaming) {
+ while (gspca_dev->dev && gspca_dev->streaming) {
+#ifdef CONFIG_PM
+ if (gspca_dev->frozen)
+ break;
+#endif
/* request some data and then read it until we have
* a complete frame. */
bytes_left = frame_sz;
@@ -242,7 +246,7 @@ static void sq905_dostream(struct work_struct *work)
we must finish reading an entire frame, otherwise the
next time we stream we start reading in the middle of a
frame. */
- while (bytes_left > 0 && gspca_dev->present) {
+ while (bytes_left > 0 && gspca_dev->dev) {
data_len = bytes_left > SQ905_MAX_TRANSFER ?
SQ905_MAX_TRANSFER : bytes_left;
ret = sq905_read_data(gspca_dev, buffer, data_len, 1);
@@ -274,7 +278,7 @@ static void sq905_dostream(struct work_struct *work)
gspca_frame_add(gspca_dev, LAST_PACKET,
NULL, 0);
}
- if (gspca_dev->present) {
+ if (gspca_dev->dev) {
/* acknowledge the frame */
mutex_lock(&gspca_dev->usb_lock);
ret = sq905_ack_frame(gspca_dev);
@@ -284,7 +288,7 @@ static void sq905_dostream(struct work_struct *work)
}
}
quit_stream:
- if (gspca_dev->present) {
+ if (gspca_dev->dev) {
mutex_lock(&gspca_dev->usb_lock);
sq905_command(gspca_dev, SQ905_CLEAR);
mutex_unlock(&gspca_dev->usb_lock);
diff --git a/drivers/media/video/gspca/sq905c.c b/drivers/media/video/gspca/sq905c.c
index ae783634712f..f34ddb0570c8 100644
--- a/drivers/media/video/gspca/sq905c.c
+++ b/drivers/media/video/gspca/sq905c.c
@@ -150,7 +150,11 @@ static void sq905c_dostream(struct work_struct *work)
goto quit_stream;
}
- while (gspca_dev->present && gspca_dev->streaming) {
+ while (gspca_dev->dev && gspca_dev->streaming) {
+#ifdef CONFIG_PM
+ if (gspca_dev->frozen)
+ break;
+#endif
/* Request the header, which tells the size to download */
ret = usb_bulk_msg(gspca_dev->dev,
usb_rcvbulkpipe(gspca_dev->dev, 0x81),
@@ -169,7 +173,7 @@ static void sq905c_dostream(struct work_struct *work)
packet_type = FIRST_PACKET;
gspca_frame_add(gspca_dev, packet_type,
buffer, FRAME_HEADER_LEN);
- while (bytes_left > 0 && gspca_dev->present) {
+ while (bytes_left > 0 && gspca_dev->dev) {
data_len = bytes_left > SQ905C_MAX_TRANSFER ?
SQ905C_MAX_TRANSFER : bytes_left;
ret = usb_bulk_msg(gspca_dev->dev,
@@ -191,7 +195,7 @@ static void sq905c_dostream(struct work_struct *work)
}
}
quit_stream:
- if (gspca_dev->present) {
+ if (gspca_dev->dev) {
mutex_lock(&gspca_dev->usb_lock);
sq905c_command(gspca_dev, SQ905C_CLEAR, 0);
mutex_unlock(&gspca_dev->usb_lock);
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c
index 91d99b4cc57b..999ec7764449 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx.c
@@ -261,6 +261,17 @@ static int stv06xx_init(struct gspca_dev *gspca_dev)
return (err < 0) ? err : 0;
}
+/* this function is called at probe time */
+static int stv06xx_init_controls(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ PDEBUG(D_PROBE, "Initializing controls");
+
+ gspca_dev->vdev.ctrl_handler = &gspca_dev->ctrl_handler;
+ return sd->sensor->init_controls(sd);
+}
+
/* Start the camera */
static int stv06xx_start(struct gspca_dev *gspca_dev)
{
@@ -512,6 +523,7 @@ static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
.config = stv06xx_config,
.init = stv06xx_init,
+ .init_controls = stv06xx_init_controls,
.start = stv06xx_start,
.stopN = stv06xx_stopN,
.pkt_scan = stv06xx_pkt_scan,
@@ -530,9 +542,8 @@ static int stv06xx_config(struct gspca_dev *gspca_dev,
PDEBUG(D_PROBE, "Configuring camera");
- sd->desc = sd_desc;
sd->bridge = id->driver_info;
- gspca_dev->sd_desc = &sd->desc;
+ gspca_dev->sd_desc = &sd_desc;
if (dump_bridge)
stv06xx_dump_bridge(sd);
@@ -594,11 +605,12 @@ static void sd_disconnect(struct usb_interface *intf)
{
struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
struct sd *sd = (struct sd *) gspca_dev;
+ void *priv = sd->sensor_priv;
PDEBUG(D_PROBE, "Disconnecting the stv06xx device");
- if (sd->sensor->disconnect)
- sd->sensor->disconnect(sd);
+ sd->sensor = NULL;
gspca_disconnect(intf);
+ kfree(priv);
}
static struct usb_driver sd_driver = {
@@ -609,6 +621,7 @@ static struct usb_driver sd_driver = {
#ifdef CONFIG_PM
.suspend = gspca_suspend,
.resume = gspca_resume,
+ .reset_resume = gspca_resume,
#endif
};
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.h b/drivers/media/video/gspca/stv06xx/stv06xx.h
index d270a5981afe..34957a4ec150 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx.h
@@ -89,9 +89,6 @@ struct sd {
/* A pointer to the currently connected sensor */
const struct stv06xx_sensor *sensor;
- /* A pointer to the sd_desc struct */
- struct sd_desc desc;
-
/* Sensor private data */
void *sensor_priv;
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
index a8698b7a7566..06fa54c5efb2 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
@@ -32,36 +32,6 @@
#include "stv06xx_hdcs.h"
-static const struct ctrl hdcs1x00_ctrl[] = {
- {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = HDCS_DEFAULT_EXPOSURE,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = hdcs_set_exposure,
- .get = hdcs_get_exposure
- }, {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "gain",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = HDCS_DEFAULT_GAIN,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = hdcs_set_gain,
- .get = hdcs_get_gain
- }
-};
-
static struct v4l2_pix_format hdcs1x00_mode[] = {
{
HDCS_1X00_DEF_WIDTH,
@@ -76,36 +46,6 @@ static struct v4l2_pix_format hdcs1x00_mode[] = {
}
};
-static const struct ctrl hdcs1020_ctrl[] = {
- {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x00,
- .maximum = 0xffff,
- .step = 0x1,
- .default_value = HDCS_DEFAULT_EXPOSURE,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = hdcs_set_exposure,
- .get = hdcs_get_exposure
- }, {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "gain",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = HDCS_DEFAULT_GAIN,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = hdcs_set_gain,
- .get = hdcs_get_gain
- }
-};
-
static struct v4l2_pix_format hdcs1020_mode[] = {
{
HDCS_1020_DEF_WIDTH,
@@ -150,7 +90,6 @@ struct hdcs {
} exp;
int psmp;
- u8 exp_cache, gain_cache;
};
static int hdcs_reg_write_seq(struct sd *sd, u8 reg, u8 *vals, u8 len)
@@ -232,16 +171,6 @@ static int hdcs_reset(struct sd *sd)
return err;
}
-static int hdcs_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- struct hdcs *hdcs = sd->sensor_priv;
-
- *val = hdcs->exp_cache;
-
- return 0;
-}
-
static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -260,9 +189,6 @@ static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
int cycles, err;
u8 exp[14];
- val &= 0xff;
- hdcs->exp_cache = val;
-
cycles = val * HDCS_CLK_FREQ_MHZ * 257;
ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2);
@@ -336,12 +262,9 @@ static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
static int hdcs_set_gains(struct sd *sd, u8 g)
{
- struct hdcs *hdcs = sd->sensor_priv;
int err;
u8 gains[4];
- hdcs->gain_cache = g;
-
/* the voltage gain Av = (1 + 19 * val / 127) * (1 + bit7) */
if (g > 127)
g = 0x80 | (g / 2);
@@ -352,17 +275,7 @@ static int hdcs_set_gains(struct sd *sd, u8 g)
gains[3] = g;
err = hdcs_reg_write_seq(sd, HDCS_ERECPGA, gains, 4);
- return err;
-}
-
-static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- struct hdcs *hdcs = sd->sensor_priv;
-
- *val = hdcs->gain_cache;
-
- return 0;
+ return err;
}
static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val)
@@ -420,6 +333,39 @@ static int hdcs_set_size(struct sd *sd,
return err;
}
+static int hdcs_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+ int err = -EINVAL;
+
+ switch (ctrl->id) {
+ case V4L2_CID_GAIN:
+ err = hdcs_set_gain(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_EXPOSURE:
+ err = hdcs_set_exposure(gspca_dev, ctrl->val);
+ break;
+ }
+ return err;
+}
+
+static const struct v4l2_ctrl_ops hdcs_ctrl_ops = {
+ .s_ctrl = hdcs_s_ctrl,
+};
+
+static int hdcs_init_controls(struct sd *sd)
+{
+ struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
+
+ v4l2_ctrl_handler_init(hdl, 2);
+ v4l2_ctrl_new_std(hdl, &hdcs_ctrl_ops,
+ V4L2_CID_EXPOSURE, 0, 0xff, 1, HDCS_DEFAULT_EXPOSURE);
+ v4l2_ctrl_new_std(hdl, &hdcs_ctrl_ops,
+ V4L2_CID_GAIN, 0, 0xff, 1, HDCS_DEFAULT_GAIN);
+ return hdl->error;
+}
+
static int hdcs_probe_1x00(struct sd *sd)
{
struct hdcs *hdcs;
@@ -434,8 +380,6 @@ static int hdcs_probe_1x00(struct sd *sd)
sd->gspca_dev.cam.cam_mode = hdcs1x00_mode;
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1x00_mode);
- sd->desc.ctrls = hdcs1x00_ctrl;
- sd->desc.nctrls = ARRAY_SIZE(hdcs1x00_ctrl);
hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL);
if (!hdcs)
@@ -493,8 +437,6 @@ static int hdcs_probe_1020(struct sd *sd)
sd->gspca_dev.cam.cam_mode = hdcs1020_mode;
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1020_mode);
- sd->desc.ctrls = hdcs1020_ctrl;
- sd->desc.nctrls = ARRAY_SIZE(hdcs1020_ctrl);
hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL);
if (!hdcs)
@@ -537,12 +479,6 @@ static int hdcs_stop(struct sd *sd)
return hdcs_set_state(sd, HDCS_STATE_SLEEP);
}
-static void hdcs_disconnect(struct sd *sd)
-{
- PDEBUG(D_PROBE, "Disconnecting the sensor");
- kfree(sd->sensor_priv);
-}
-
static int hdcs_init(struct sd *sd)
{
struct hdcs *hdcs = sd->sensor_priv;
@@ -587,16 +523,7 @@ static int hdcs_init(struct sd *sd)
if (err < 0)
return err;
- err = hdcs_set_gains(sd, HDCS_DEFAULT_GAIN);
- if (err < 0)
- return err;
-
- err = hdcs_set_size(sd, hdcs->array.width, hdcs->array.height);
- if (err < 0)
- return err;
-
- err = hdcs_set_exposure(&sd->gspca_dev, HDCS_DEFAULT_EXPOSURE);
- return err;
+ return hdcs_set_size(sd, hdcs->array.width, hdcs->array.height);
}
static int hdcs_dump(struct sd *sd)
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
index a14a84a5079b..1ba9158d0102 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
@@ -131,14 +131,12 @@ static int hdcs_probe_1x00(struct sd *sd);
static int hdcs_probe_1020(struct sd *sd);
static int hdcs_start(struct sd *sd);
static int hdcs_init(struct sd *sd);
+static int hdcs_init_controls(struct sd *sd);
static int hdcs_stop(struct sd *sd);
static int hdcs_dump(struct sd *sd);
-static void hdcs_disconnect(struct sd *sd);
-static int hdcs_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
const struct stv06xx_sensor stv06xx_sensor_hdcs1x00 = {
.name = "HP HDCS-1000/1100",
@@ -152,10 +150,10 @@ const struct stv06xx_sensor stv06xx_sensor_hdcs1x00 = {
.max_packet_size = { 847 },
.init = hdcs_init,
+ .init_controls = hdcs_init_controls,
.probe = hdcs_probe_1x00,
.start = hdcs_start,
.stop = hdcs_stop,
- .disconnect = hdcs_disconnect,
.dump = hdcs_dump,
};
@@ -171,6 +169,7 @@ const struct stv06xx_sensor stv06xx_sensor_hdcs1020 = {
.max_packet_size = { 847 },
.init = hdcs_init,
+ .init_controls = hdcs_init_controls,
.probe = hdcs_probe_1020,
.start = hdcs_start,
.stop = hdcs_stop,
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
index 26f14fc4a135..cdfc3d05ab6b 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
@@ -48,105 +48,16 @@
#include "stv06xx_pb0100.h"
-static const struct ctrl pb0100_ctrl[] = {
-#define GAIN_IDX 0
- {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 128
- },
- .set = pb0100_set_gain,
- .get = pb0100_get_gain
- },
-#define RED_BALANCE_IDX 1
- {
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Red Balance",
- .minimum = -255,
- .maximum = 255,
- .step = 1,
- .default_value = 0
- },
- .set = pb0100_set_red_balance,
- .get = pb0100_get_red_balance
- },
-#define BLUE_BALANCE_IDX 2
- {
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Blue Balance",
- .minimum = -255,
- .maximum = 255,
- .step = 1,
- .default_value = 0
- },
- .set = pb0100_set_blue_balance,
- .get = pb0100_get_blue_balance
- },
-#define EXPOSURE_IDX 3
- {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Exposure",
- .minimum = 0,
- .maximum = 511,
- .step = 1,
- .default_value = 12
- },
- .set = pb0100_set_exposure,
- .get = pb0100_get_exposure
- },
-#define AUTOGAIN_IDX 4
- {
- {
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Automatic Gain and Exposure",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1
- },
- .set = pb0100_set_autogain,
- .get = pb0100_get_autogain
- },
-#define AUTOGAIN_TARGET_IDX 5
- {
- {
- .id = V4L2_CTRL_CLASS_USER + 0x1000,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Automatic Gain Target",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 128
- },
- .set = pb0100_set_autogain_target,
- .get = pb0100_get_autogain_target
- },
-#define NATURAL_IDX 6
- {
- {
- .id = V4L2_CTRL_CLASS_USER + 0x1001,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Natural Light Source",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1
- },
- .set = pb0100_set_natural,
- .get = pb0100_get_natural
- }
+struct pb0100_ctrls {
+ struct { /* one big happy control cluster... */
+ struct v4l2_ctrl *autogain;
+ struct v4l2_ctrl *gain;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *red;
+ struct v4l2_ctrl *blue;
+ struct v4l2_ctrl *natural;
+ };
+ struct v4l2_ctrl *target;
};
static struct v4l2_pix_format pb0100_mode[] = {
@@ -174,38 +85,104 @@ static struct v4l2_pix_format pb0100_mode[] = {
}
};
+static int pb0100_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;
+ struct pb0100_ctrls *ctrls = sd->sensor_priv;
+ int err = -EINVAL;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTOGAIN:
+ err = pb0100_set_autogain(gspca_dev, ctrl->val);
+ if (err)
+ break;
+ if (ctrl->val)
+ break;
+ err = pb0100_set_gain(gspca_dev, ctrls->gain->val);
+ if (err)
+ break;
+ err = pb0100_set_exposure(gspca_dev, ctrls->exposure->val);
+ break;
+ case V4L2_CTRL_CLASS_USER + 0x1001:
+ err = pb0100_set_autogain_target(gspca_dev, ctrl->val);
+ break;
+ }
+ return err;
+}
+
+static const struct v4l2_ctrl_ops pb0100_ctrl_ops = {
+ .s_ctrl = pb0100_s_ctrl,
+};
+
+static int pb0100_init_controls(struct sd *sd)
+{
+ struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
+ struct pb0100_ctrls *ctrls;
+ static const struct v4l2_ctrl_config autogain_target = {
+ .ops = &pb0100_ctrl_ops,
+ .id = V4L2_CTRL_CLASS_USER + 0x1000,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Automatic Gain Target",
+ .max = 255,
+ .step = 1,
+ .def = 128,
+ };
+ static const struct v4l2_ctrl_config natural_light = {
+ .ops = &pb0100_ctrl_ops,
+ .id = V4L2_CTRL_CLASS_USER + 0x1001,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Natural Light Source",
+ .max = 1,
+ .step = 1,
+ .def = 1,
+ };
+
+ ctrls = kzalloc(sizeof(*ctrls), GFP_KERNEL);
+ if (!ctrls)
+ return -ENOMEM;
+
+ v4l2_ctrl_handler_init(hdl, 6);
+ ctrls->autogain = v4l2_ctrl_new_std(hdl, &pb0100_ctrl_ops,
+ V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+ ctrls->exposure = v4l2_ctrl_new_std(hdl, &pb0100_ctrl_ops,
+ V4L2_CID_EXPOSURE, 0, 511, 1, 12);
+ ctrls->gain = v4l2_ctrl_new_std(hdl, &pb0100_ctrl_ops,
+ V4L2_CID_GAIN, 0, 255, 1, 128);
+ ctrls->red = v4l2_ctrl_new_std(hdl, &pb0100_ctrl_ops,
+ V4L2_CID_RED_BALANCE, -255, 255, 1, 0);
+ ctrls->blue = v4l2_ctrl_new_std(hdl, &pb0100_ctrl_ops,
+ V4L2_CID_BLUE_BALANCE, -255, 255, 1, 0);
+ ctrls->natural = v4l2_ctrl_new_custom(hdl, &natural_light, NULL);
+ ctrls->target = v4l2_ctrl_new_custom(hdl, &autogain_target, NULL);
+ if (hdl->error) {
+ kfree(ctrls);
+ return hdl->error;
+ }
+ sd->sensor_priv = ctrls;
+ v4l2_ctrl_auto_cluster(5, &ctrls->autogain, 0, false);
+ return 0;
+}
+
static int pb0100_probe(struct sd *sd)
{
u16 sensor;
- int i, err;
- s32 *sensor_settings;
+ int err;
err = stv06xx_read_sensor(sd, PB_IDENT, &sensor);
if (err < 0)
return -ENODEV;
+ if ((sensor >> 8) != 0x64)
+ return -ENODEV;
- if ((sensor >> 8) == 0x64) {
- sensor_settings = kmalloc(
- ARRAY_SIZE(pb0100_ctrl) * sizeof(s32),
- GFP_KERNEL);
- if (!sensor_settings)
- return -ENOMEM;
-
- pr_info("Photobit pb0100 sensor detected\n");
-
- sd->gspca_dev.cam.cam_mode = pb0100_mode;
- sd->gspca_dev.cam.nmodes = ARRAY_SIZE(pb0100_mode);
- sd->desc.ctrls = pb0100_ctrl;
- sd->desc.nctrls = ARRAY_SIZE(pb0100_ctrl);
- for (i = 0; i < sd->desc.nctrls; i++)
- sensor_settings[i] = pb0100_ctrl[i].qctrl.default_value;
- sd->sensor_priv = sensor_settings;
+ pr_info("Photobit pb0100 sensor detected\n");
- return 0;
- }
+ sd->gspca_dev.cam.cam_mode = pb0100_mode;
+ sd->gspca_dev.cam.nmodes = ARRAY_SIZE(pb0100_mode);
- return -ENODEV;
+ return 0;
}
static int pb0100_start(struct sd *sd)
@@ -214,7 +191,6 @@ static int pb0100_start(struct sd *sd)
struct usb_host_interface *alt;
struct usb_interface *intf;
struct cam *cam = &sd->gspca_dev.cam;
- s32 *sensor_settings = sd->sensor_priv;
u32 mode = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
@@ -255,13 +231,6 @@ static int pb0100_start(struct sd *sd)
stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20);
}
- /* set_gain also sets red and blue balance */
- pb0100_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
- pb0100_set_exposure(&sd->gspca_dev, sensor_settings[EXPOSURE_IDX]);
- pb0100_set_autogain_target(&sd->gspca_dev,
- sensor_settings[AUTOGAIN_TARGET_IDX]);
- pb0100_set_autogain(&sd->gspca_dev, sensor_settings[AUTOGAIN_IDX]);
-
err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3)|BIT(1));
PDEBUG(D_STREAM, "Started stream, status: %d", err);
@@ -285,12 +254,6 @@ out:
return (err < 0) ? err : 0;
}
-static void pb0100_disconnect(struct sd *sd)
-{
- sd->sensor = NULL;
- kfree(sd->sensor_priv);
-}
-
/* FIXME: Sort the init commands out and put them into tables,
this is only for getting the camera to work */
/* FIXME: No error handling for now,
@@ -362,62 +325,32 @@ static int pb0100_dump(struct sd *sd)
return 0;
}
-static int pb0100_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[GAIN_IDX];
-
- return 0;
-}
-
static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
+ struct pb0100_ctrls *ctrls = sd->sensor_priv;
- if (sensor_settings[AUTOGAIN_IDX])
- return -EBUSY;
-
- sensor_settings[GAIN_IDX] = val;
err = stv06xx_write_sensor(sd, PB_G1GAIN, val);
if (!err)
err = stv06xx_write_sensor(sd, PB_G2GAIN, val);
PDEBUG(D_V4L2, "Set green gain to %d, status: %d", val, err);
if (!err)
- err = pb0100_set_red_balance(gspca_dev,
- sensor_settings[RED_BALANCE_IDX]);
+ err = pb0100_set_red_balance(gspca_dev, ctrls->red->val);
if (!err)
- err = pb0100_set_blue_balance(gspca_dev,
- sensor_settings[BLUE_BALANCE_IDX]);
+ err = pb0100_set_blue_balance(gspca_dev, ctrls->blue->val);
return err;
}
-static int pb0100_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[RED_BALANCE_IDX];
-
- return 0;
-}
-
static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
+ struct pb0100_ctrls *ctrls = sd->sensor_priv;
- if (sensor_settings[AUTOGAIN_IDX])
- return -EBUSY;
-
- sensor_settings[RED_BALANCE_IDX] = val;
- val += sensor_settings[GAIN_IDX];
+ val += ctrls->gain->val;
if (val < 0)
val = 0;
else if (val > 255)
@@ -429,27 +362,13 @@ static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
return err;
}
-static int pb0100_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[BLUE_BALANCE_IDX];
-
- return 0;
-}
-
static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
+ struct pb0100_ctrls *ctrls = sd->sensor_priv;
- if (sensor_settings[AUTOGAIN_IDX])
- return -EBUSY;
-
- sensor_settings[BLUE_BALANCE_IDX] = val;
- val += sensor_settings[GAIN_IDX];
+ val += ctrls->gain->val;
if (val < 0)
val = 0;
else if (val > 255)
@@ -461,51 +380,25 @@ static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
return err;
}
-static int pb0100_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[EXPOSURE_IDX];
-
- return 0;
-}
-
static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
{
- int err;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- if (sensor_settings[AUTOGAIN_IDX])
- return -EBUSY;
+ int err;
- sensor_settings[EXPOSURE_IDX] = val;
err = stv06xx_write_sensor(sd, PB_RINTTIME, val);
PDEBUG(D_V4L2, "Set exposure to %d, status: %d", val, err);
return err;
}
-static int pb0100_get_autogain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[AUTOGAIN_IDX];
-
- return 0;
-}
-
static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
+ struct pb0100_ctrls *ctrls = sd->sensor_priv;
- sensor_settings[AUTOGAIN_IDX] = val;
- if (sensor_settings[AUTOGAIN_IDX]) {
- if (sensor_settings[NATURAL_IDX])
+ if (val) {
+ if (ctrls->natural->val)
val = BIT(6)|BIT(4)|BIT(0);
else
val = BIT(4)|BIT(0);
@@ -514,29 +407,15 @@ static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val)
err = stv06xx_write_sensor(sd, PB_EXPGAIN, val);
PDEBUG(D_V4L2, "Set autogain to %d (natural: %d), status: %d",
- sensor_settings[AUTOGAIN_IDX], sensor_settings[NATURAL_IDX],
- err);
+ val, ctrls->natural->val, err);
return err;
}
-static int pb0100_get_autogain_target(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[AUTOGAIN_TARGET_IDX];
-
- return 0;
-}
-
static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val)
{
int err, totalpixels, brightpixels, darkpixels;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- sensor_settings[AUTOGAIN_TARGET_IDX] = val;
/* Number of pixels counted by the sensor when subsampling the pixels.
* Slightly larger than the real value to avoid oscillation */
@@ -553,23 +432,3 @@ static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val)
return err;
}
-
-static int pb0100_get_natural(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[NATURAL_IDX];
-
- return 0;
-}
-
-static int pb0100_set_natural(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- sensor_settings[NATURAL_IDX] = val;
-
- return pb0100_set_autogain(gspca_dev, sensor_settings[AUTOGAIN_IDX]);
-}
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
index 757de246dc75..5071e5353fd3 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
@@ -112,25 +112,17 @@
static int pb0100_probe(struct sd *sd);
static int pb0100_start(struct sd *sd);
static int pb0100_init(struct sd *sd);
+static int pb0100_init_controls(struct sd *sd);
static int pb0100_stop(struct sd *sd);
static int pb0100_dump(struct sd *sd);
-static void pb0100_disconnect(struct sd *sd);
/* V4L2 controls supported by the driver */
-static int pb0100_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int pb0100_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int pb0100_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int pb0100_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
-static int pb0100_get_autogain(struct gspca_dev *gspca_dev, __s32 *val);
static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val);
-static int pb0100_get_autogain_target(struct gspca_dev *gspca_dev, __s32 *val);
static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val);
-static int pb0100_get_natural(struct gspca_dev *gspca_dev, __s32 *val);
-static int pb0100_set_natural(struct gspca_dev *gspca_dev, __s32 val);
const struct stv06xx_sensor stv06xx_sensor_pb0100 = {
.name = "PB-0100",
@@ -142,11 +134,11 @@ const struct stv06xx_sensor stv06xx_sensor_pb0100 = {
.max_packet_size = { 847, 923 },
.init = pb0100_init,
+ .init_controls = pb0100_init_controls,
.probe = pb0100_probe,
.start = pb0100_start,
.stop = pb0100_stop,
.dump = pb0100_dump,
- .disconnect = pb0100_disconnect,
};
#endif
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h b/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
index fb229d8ded58..3a498c2495c6 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
@@ -63,8 +63,8 @@ struct stv06xx_sensor {
/* Performs a initialization sequence */
int (*init)(struct sd *sd);
- /* Executed at device disconnect */
- void (*disconnect)(struct sd *sd);
+ /* Initializes the controls */
+ int (*init_controls)(struct sd *sd);
/* Reads a sensor register */
int (*read_sensor)(struct sd *sd, const u8 address,
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
index 9940e035b3ab..8a57990dfe0f 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
@@ -30,20 +30,6 @@
#include "stv06xx_st6422.h"
-/* controls */
-enum e_ctrl {
- BRIGHTNESS,
- CONTRAST,
- GAIN,
- EXPOSURE,
- NCTRLS /* number of controls */
-};
-
-/* sensor settings */
-struct st6422_settings {
- struct gspca_ctrl ctrls[NCTRLS];
-};
-
static struct v4l2_pix_format st6422_mode[] = {
/* Note we actually get 124 lines of data, of which we skip the 4st
4 as they are garbage */
@@ -74,83 +60,70 @@ static struct v4l2_pix_format st6422_mode[] = {
};
/* V4L2 controls supported by the driver */
-static void st6422_set_brightness(struct gspca_dev *gspca_dev);
-static void st6422_set_contrast(struct gspca_dev *gspca_dev);
-static void st6422_set_gain(struct gspca_dev *gspca_dev);
-static void st6422_set_exposure(struct gspca_dev *gspca_dev);
-
-static const struct ctrl st6422_ctrl[NCTRLS] = {
-[BRIGHTNESS] = {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 31,
- .step = 1,
- .default_value = 3
- },
- .set_control = st6422_set_brightness
- },
-[CONTRAST] = {
- {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 15,
- .step = 1,
- .default_value = 11
- },
- .set_control = st6422_set_contrast
- },
-[GAIN] = {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 64
- },
- .set_control = st6422_set_gain
- },
-[EXPOSURE] = {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Exposure",
- .minimum = 0,
-#define EXPOSURE_MAX 1023
- .maximum = EXPOSURE_MAX,
- .step = 1,
- .default_value = 256
- },
- .set_control = st6422_set_exposure
- },
+static int setbrightness(struct sd *sd, s32 val);
+static int setcontrast(struct sd *sd, s32 val);
+static int setgain(struct sd *sd, u8 gain);
+static int setexposure(struct sd *sd, s16 expo);
+
+static int st6422_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;
+ int err = -EINVAL;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ err = setbrightness(sd, ctrl->val);
+ break;
+ case V4L2_CID_CONTRAST:
+ err = setcontrast(sd, ctrl->val);
+ break;
+ case V4L2_CID_GAIN:
+ err = setgain(sd, ctrl->val);
+ break;
+ case V4L2_CID_EXPOSURE:
+ err = setexposure(sd, ctrl->val);
+ break;
+ }
+
+ /* commit settings */
+ if (err >= 0)
+ err = stv06xx_write_bridge(sd, 0x143f, 0x01);
+ sd->gspca_dev.usb_err = err;
+ return err;
+}
+
+static const struct v4l2_ctrl_ops st6422_ctrl_ops = {
+ .s_ctrl = st6422_s_ctrl,
};
-static int st6422_probe(struct sd *sd)
+static int st6422_init_controls(struct sd *sd)
{
- struct st6422_settings *sensor_settings;
+ struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
+
+ v4l2_ctrl_handler_init(hdl, 4);
+ v4l2_ctrl_new_std(hdl, &st6422_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 31, 1, 3);
+ v4l2_ctrl_new_std(hdl, &st6422_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 15, 1, 11);
+ v4l2_ctrl_new_std(hdl, &st6422_ctrl_ops,
+ V4L2_CID_EXPOSURE, 0, 1023, 1, 256);
+ v4l2_ctrl_new_std(hdl, &st6422_ctrl_ops,
+ V4L2_CID_GAIN, 0, 255, 1, 64);
+
+ return hdl->error;
+}
+static int st6422_probe(struct sd *sd)
+{
if (sd->bridge != BRIDGE_ST6422)
return -ENODEV;
pr_info("st6422 sensor detected\n");
- sensor_settings = kmalloc(sizeof *sensor_settings, GFP_KERNEL);
- if (!sensor_settings)
- return -ENOMEM;
-
sd->gspca_dev.cam.cam_mode = st6422_mode;
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(st6422_mode);
- sd->gspca_dev.cam.ctrls = sensor_settings->ctrls;
- sd->desc.ctrls = st6422_ctrl;
- sd->desc.nctrls = ARRAY_SIZE(st6422_ctrl);
- sd->sensor_priv = sensor_settings;
-
return 0;
}
@@ -239,38 +212,22 @@ static int st6422_init(struct sd *sd)
return err;
}
-static void st6422_disconnect(struct sd *sd)
-{
- sd->sensor = NULL;
- kfree(sd->sensor_priv);
-}
-
-static int setbrightness(struct sd *sd)
+static int setbrightness(struct sd *sd, s32 val)
{
- struct st6422_settings *sensor_settings = sd->sensor_priv;
-
/* val goes from 0 -> 31 */
- return stv06xx_write_bridge(sd, 0x1432,
- sensor_settings->ctrls[BRIGHTNESS].val);
+ return stv06xx_write_bridge(sd, 0x1432, val);
}
-static int setcontrast(struct sd *sd)
+static int setcontrast(struct sd *sd, s32 val)
{
- struct st6422_settings *sensor_settings = sd->sensor_priv;
-
/* Val goes from 0 -> 15 */
- return stv06xx_write_bridge(sd, 0x143a,
- sensor_settings->ctrls[CONTRAST].val | 0xf0);
+ return stv06xx_write_bridge(sd, 0x143a, val | 0xf0);
}
-static int setgain(struct sd *sd)
+static int setgain(struct sd *sd, u8 gain)
{
- struct st6422_settings *sensor_settings = sd->sensor_priv;
- u8 gain;
int err;
- gain = sensor_settings->ctrls[GAIN].val;
-
/* Set red, green, blue, gain */
err = stv06xx_write_bridge(sd, 0x0509, gain);
if (err < 0)
@@ -292,13 +249,10 @@ static int setgain(struct sd *sd)
return stv06xx_write_bridge(sd, 0x050d, 0x01);
}
-static int setexposure(struct sd *sd)
+static int setexposure(struct sd *sd, s16 expo)
{
- struct st6422_settings *sensor_settings = sd->sensor_priv;
- u16 expo;
int err;
- expo = sensor_settings->ctrls[EXPOSURE].val;
err = stv06xx_write_bridge(sd, 0x143d, expo & 0xff);
if (err < 0)
return err;
@@ -318,22 +272,6 @@ static int st6422_start(struct sd *sd)
if (err < 0)
return err;
- err = setbrightness(sd);
- if (err < 0)
- return err;
-
- err = setcontrast(sd);
- if (err < 0)
- return err;
-
- err = setexposure(sd);
- if (err < 0)
- return err;
-
- err = setgain(sd);
- if (err < 0)
- return err;
-
/* commit settings */
err = stv06xx_write_bridge(sd, 0x143f, 0x01);
return (err < 0) ? err : 0;
@@ -345,59 +283,3 @@ static int st6422_stop(struct sd *sd)
return 0;
}
-
-static void st6422_set_brightness(struct gspca_dev *gspca_dev)
-{
- int err;
- struct sd *sd = (struct sd *) gspca_dev;
-
- err = setbrightness(sd);
-
- /* commit settings */
- if (err >= 0)
- err = stv06xx_write_bridge(sd, 0x143f, 0x01);
-
- gspca_dev->usb_err = err;
-}
-
-static void st6422_set_contrast(struct gspca_dev *gspca_dev)
-{
- int err;
- struct sd *sd = (struct sd *) gspca_dev;
-
- err = setcontrast(sd);
-
- /* commit settings */
- if (err >= 0)
- err = stv06xx_write_bridge(sd, 0x143f, 0x01);
-
- gspca_dev->usb_err = err;
-}
-
-static void st6422_set_gain(struct gspca_dev *gspca_dev)
-{
- int err;
- struct sd *sd = (struct sd *) gspca_dev;
-
- err = setgain(sd);
-
- /* commit settings */
- if (err >= 0)
- err = stv06xx_write_bridge(sd, 0x143f, 0x01);
-
- gspca_dev->usb_err = err;
-}
-
-static void st6422_set_exposure(struct gspca_dev *gspca_dev)
-{
- int err;
- struct sd *sd = (struct sd *) gspca_dev;
-
- err = setexposure(sd);
-
- /* commit settings */
- if (err >= 0)
- err = stv06xx_write_bridge(sd, 0x143f, 0x01);
-
- gspca_dev->usb_err = err;
-}
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h
index d7498e06432b..8f20fbf30f33 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h
@@ -34,8 +34,8 @@
static int st6422_probe(struct sd *sd);
static int st6422_start(struct sd *sd);
static int st6422_init(struct sd *sd);
+static int st6422_init_controls(struct sd *sd);
static int st6422_stop(struct sd *sd);
-static void st6422_disconnect(struct sd *sd);
const struct stv06xx_sensor stv06xx_sensor_st6422 = {
.name = "ST6422",
@@ -43,10 +43,10 @@ const struct stv06xx_sensor stv06xx_sensor_st6422 = {
.min_packet_size = { 300, 847 },
.max_packet_size = { 300, 847 },
.init = st6422_init,
+ .init_controls = st6422_init_controls,
.probe = st6422_probe,
.start = st6422_start,
.stop = st6422_stop,
- .disconnect = st6422_disconnect,
};
#endif
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
index a5c69d9ebdd4..748e1421d6d8 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
@@ -44,130 +44,83 @@ static struct v4l2_pix_format vv6410_mode[] = {
}
};
-static const struct ctrl vv6410_ctrl[] = {
-#define HFLIP_IDX 0
- {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = vv6410_set_hflip,
- .get = vv6410_get_hflip
- },
-#define VFLIP_IDX 1
- {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = vv6410_set_vflip,
- .get = vv6410_get_vflip
- },
-#define GAIN_IDX 2
- {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "analog gain",
- .minimum = 0,
- .maximum = 15,
- .step = 1,
- .default_value = 10
- },
- .set = vv6410_set_analog_gain,
- .get = vv6410_get_analog_gain
- },
-#define EXPOSURE_IDX 3
- {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0,
- .maximum = 32768,
- .step = 1,
- .default_value = 20000
- },
- .set = vv6410_set_exposure,
- .get = vv6410_get_exposure
+static int vv6410_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+ int err = -EINVAL;
+
+ switch (ctrl->id) {
+ case V4L2_CID_HFLIP:
+ err = vv6410_set_hflip(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_VFLIP:
+ err = vv6410_set_vflip(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_GAIN:
+ err = vv6410_set_analog_gain(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_EXPOSURE:
+ err = vv6410_set_exposure(gspca_dev, ctrl->val);
+ break;
}
- };
+ return err;
+}
+
+static const struct v4l2_ctrl_ops vv6410_ctrl_ops = {
+ .s_ctrl = vv6410_s_ctrl,
+};
static int vv6410_probe(struct sd *sd)
{
u16 data;
- int err, i;
- s32 *sensor_settings;
+ int err;
err = stv06xx_read_sensor(sd, VV6410_DEVICEH, &data);
if (err < 0)
return -ENODEV;
- if (data == 0x19) {
- pr_info("vv6410 sensor detected\n");
+ if (data != 0x19)
+ return -ENODEV;
- sensor_settings = kmalloc(ARRAY_SIZE(vv6410_ctrl) * sizeof(s32),
- GFP_KERNEL);
- if (!sensor_settings)
- return -ENOMEM;
+ pr_info("vv6410 sensor detected\n");
- sd->gspca_dev.cam.cam_mode = vv6410_mode;
- sd->gspca_dev.cam.nmodes = ARRAY_SIZE(vv6410_mode);
- sd->desc.ctrls = vv6410_ctrl;
- sd->desc.nctrls = ARRAY_SIZE(vv6410_ctrl);
+ sd->gspca_dev.cam.cam_mode = vv6410_mode;
+ sd->gspca_dev.cam.nmodes = ARRAY_SIZE(vv6410_mode);
+ return 0;
+}
- for (i = 0; i < sd->desc.nctrls; i++)
- sensor_settings[i] = vv6410_ctrl[i].qctrl.default_value;
- sd->sensor_priv = sensor_settings;
- return 0;
- }
- return -ENODEV;
+static int vv6410_init_controls(struct sd *sd)
+{
+ struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
+
+ v4l2_ctrl_handler_init(hdl, 4);
+ v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops,
+ V4L2_CID_EXPOSURE, 0, 32768, 1, 20000);
+ v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops,
+ V4L2_CID_GAIN, 0, 15, 1, 10);
+ return hdl->error;
}
static int vv6410_init(struct sd *sd)
{
int err = 0, i;
- s32 *sensor_settings = sd->sensor_priv;
- for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) {
+ for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++)
stv06xx_write_bridge(sd, stv_bridge_init[i].addr, stv_bridge_init[i].data);
- }
if (err < 0)
return err;
err = stv06xx_write_sensor_bytes(sd, (u8 *) vv6410_sensor_init,
ARRAY_SIZE(vv6410_sensor_init));
- if (err < 0)
- return err;
-
- err = vv6410_set_exposure(&sd->gspca_dev,
- sensor_settings[EXPOSURE_IDX]);
- if (err < 0)
- return err;
-
- err = vv6410_set_analog_gain(&sd->gspca_dev,
- sensor_settings[GAIN_IDX]);
-
return (err < 0) ? err : 0;
}
-static void vv6410_disconnect(struct sd *sd)
-{
- sd->sensor = NULL;
- kfree(sd->sensor_priv);
-}
-
static int vv6410_start(struct sd *sd)
{
int err;
@@ -233,25 +186,12 @@ static int vv6410_dump(struct sd *sd)
return (err < 0) ? err : 0;
}
-static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[HFLIP_IDX];
- PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
-
- return 0;
-}
-
static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u16 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- sensor_settings[HFLIP_IDX] = val;
err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
if (err < 0)
return err;
@@ -267,25 +207,12 @@ static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
return (err < 0) ? err : 0;
}
-static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[VFLIP_IDX];
- PDEBUG(D_V4L2, "Read vertical flip %d", *val);
-
- return 0;
-}
-
static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u16 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- sensor_settings[VFLIP_IDX] = val;
err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data);
if (err < 0)
return err;
@@ -301,52 +228,23 @@ static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
return (err < 0) ? err : 0;
}
-static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[GAIN_IDX];
-
- PDEBUG(D_V4L2, "Read analog gain %d", *val);
-
- return 0;
-}
-
static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- sensor_settings[GAIN_IDX] = val;
PDEBUG(D_V4L2, "Set analog gain to %d", val);
err = stv06xx_write_sensor(sd, VV6410_ANALOGGAIN, 0xf0 | (val & 0xf));
return (err < 0) ? err : 0;
}
-static int vv6410_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[EXPOSURE_IDX];
-
- PDEBUG(D_V4L2, "Read exposure %d", *val);
-
- return 0;
-}
-
static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
unsigned int fine, coarse;
- sensor_settings[EXPOSURE_IDX] = val;
-
val = (val * val >> 14) + val / 4;
fine = val % VV6410_CIF_LINELENGTH;
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
index a25b8873f2e6..53e67b40ca05 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
@@ -178,18 +178,14 @@
static int vv6410_probe(struct sd *sd);
static int vv6410_start(struct sd *sd);
static int vv6410_init(struct sd *sd);
+static int vv6410_init_controls(struct sd *sd);
static int vv6410_stop(struct sd *sd);
static int vv6410_dump(struct sd *sd);
-static void vv6410_disconnect(struct sd *sd);
/* V4L2 controls supported by the driver */
-static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val);
static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int vv6410_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
const struct stv06xx_sensor stv06xx_sensor_vv6410 = {
@@ -202,11 +198,11 @@ const struct stv06xx_sensor stv06xx_sensor_vv6410 = {
.min_packet_size = { 1023 },
.max_packet_size = { 1023 },
.init = vv6410_init,
+ .init_controls = vv6410_init_controls,
.probe = vv6410_probe,
.start = vv6410_start,
.stop = vv6410_stop,
.dump = vv6410_dump,
- .disconnect = vv6410_disconnect,
};
/* If NULL, only single value to write, stored in len */
diff --git a/drivers/media/video/gspca/topro.c b/drivers/media/video/gspca/topro.c
index 444d3c5b9079..c6326d177a3d 100644
--- a/drivers/media/video/gspca/topro.c
+++ b/drivers/media/video/gspca/topro.c
@@ -4675,11 +4675,9 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
/* -- do autogain -- */
/* gain setting is done in setexposure() for tp6810 */
static void setgain(struct gspca_dev *gspca_dev) {}
-/* !! coarse_grained_expo_autogain is not used !! */
-#define exp_too_low_cnt bridge
-#define exp_too_high_cnt sensor
-
+#define WANT_REGULAR_AUTOGAIN
#include "autogain_functions.h"
+
static void sd_dq_callback(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
diff --git a/drivers/media/video/gspca/vicam.c b/drivers/media/video/gspca/vicam.c
index 911152e169d6..15a30f7a4b2a 100644
--- a/drivers/media/video/gspca/vicam.c
+++ b/drivers/media/video/gspca/vicam.c
@@ -37,9 +37,12 @@
#include <linux/ihex.h>
#include "gspca.h"
+#define VICAM_FIRMWARE "vicam/firmware.fw"
+
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_DESCRIPTION("GSPCA ViCam USB Camera Driver");
MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(VICAM_FIRMWARE);
enum e_ctrl {
GAIN,
@@ -222,7 +225,11 @@ static void vicam_dostream(struct work_struct *work)
goto exit;
}
- while (gspca_dev->present && gspca_dev->streaming) {
+ while (gspca_dev->dev && gspca_dev->streaming) {
+#ifdef CONFIG_PM
+ if (gspca_dev->frozen)
+ break;
+#endif
ret = vicam_read_frame(gspca_dev, buffer, frame_sz);
if (ret < 0)
break;
@@ -268,7 +275,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
const struct firmware *uninitialized_var(fw);
u8 *firmware_buf;
- ret = request_ihex_firmware(&fw, "vicam/firmware.fw",
+ ret = request_ihex_firmware(&fw, VICAM_FIRMWARE,
&gspca_dev->dev->dev);
if (ret) {
pr_err("Failed to load \"vicam/firmware.fw\": %d\n", ret);
@@ -324,7 +331,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
dev->work_thread = NULL;
mutex_lock(&gspca_dev->usb_lock);
- if (gspca_dev->present)
+ if (gspca_dev->dev)
vicam_set_camera_power(gspca_dev, 0);
}
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index 7d9a4f1be9dc..f0bacee33ef9 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -32,29 +32,25 @@ MODULE_LICENSE("GPL");
static int force_sensor = -1;
-#define REG08_DEF 3 /* default JPEG compression (70%) */
+#define REG08_DEF 3 /* default JPEG compression (75%) */
#include "zc3xx-reg.h"
-/* controls */
-enum e_ctrl {
- BRIGHTNESS,
- CONTRAST,
- EXPOSURE,
- GAMMA,
- AUTOGAIN,
- LIGHTFREQ,
- SHARPNESS,
- QUALITY,
- NCTRLS /* number of controls */
-};
-
-#define AUTOGAIN_DEF 1
-
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- struct gspca_ctrl ctrls[NCTRLS];
+ struct { /* gamma/brightness/contrast control cluster */
+ struct v4l2_ctrl *gamma;
+ struct v4l2_ctrl *brightness;
+ struct v4l2_ctrl *contrast;
+ };
+ struct { /* autogain/exposure control cluster */
+ struct v4l2_ctrl *autogain;
+ struct v4l2_ctrl *exposure;
+ };
+ struct v4l2_ctrl *plfreq;
+ struct v4l2_ctrl *sharpness;
+ struct v4l2_ctrl *jpegqual;
struct work_struct work;
struct workqueue_struct *work_thread;
@@ -94,114 +90,6 @@ enum sensors {
SENSOR_MAX
};
-/* V4L2 controls supported by the driver */
-static void setcontrast(struct gspca_dev *gspca_dev);
-static void setexposure(struct gspca_dev *gspca_dev);
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static void setlightfreq(struct gspca_dev *gspca_dev);
-static void setsharpness(struct gspca_dev *gspca_dev);
-static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val);
-
-static const struct ctrl sd_ctrls[NCTRLS] = {
-[BRIGHTNESS] = {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 128,
- },
- .set_control = setcontrast
- },
-[CONTRAST] = {
- {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 128,
- },
- .set_control = setcontrast
- },
-[EXPOSURE] = {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Exposure",
- .minimum = 0x30d,
- .maximum = 0x493e,
- .step = 1,
- .default_value = 0x927
- },
- .set_control = setexposure
- },
-[GAMMA] = {
- {
- .id = V4L2_CID_GAMMA,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gamma",
- .minimum = 1,
- .maximum = 6,
- .step = 1,
- .default_value = 4,
- },
- .set_control = setcontrast
- },
-[AUTOGAIN] = {
- {
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Auto Gain",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = AUTOGAIN_DEF,
- .flags = V4L2_CTRL_FLAG_UPDATE
- },
- .set = sd_setautogain
- },
-[LIGHTFREQ] = {
- {
- .id = V4L2_CID_POWER_LINE_FREQUENCY,
- .type = V4L2_CTRL_TYPE_MENU,
- .name = "Light frequency filter",
- .minimum = 0,
- .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
- .step = 1,
- .default_value = 0,
- },
- .set_control = setlightfreq
- },
-[SHARPNESS] = {
- {
- .id = V4L2_CID_SHARPNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Sharpness",
- .minimum = 0,
- .maximum = 3,
- .step = 1,
- .default_value = 2,
- },
- .set_control = setsharpness
- },
-[QUALITY] = {
- {
- .id = V4L2_CID_JPEG_COMPRESSION_QUALITY,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Compression Quality",
- .minimum = 40,
- .maximum = 70,
- .step = 1,
- .default_value = 70 /* updated in sd_init() */
- },
- .set = sd_setquality
- },
-};
-
static const struct v4l2_pix_format vga_mode[] = {
{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 320,
@@ -241,8 +129,11 @@ static const struct v4l2_pix_format sif_mode[] = {
.priv = 0},
};
-/* bridge reg08 -> JPEG quality conversion table */
-static u8 jpeg_qual[] = {40, 50, 60, 70, /*80*/};
+/*
+ * Bridge reg08 bits 1-2 -> JPEG quality conversion table. Note the highest
+ * quality setting is not usable as USB 1 does not have enough bandwidth.
+ */
+static u8 jpeg_qual[] = {50, 75, 87, /* 94 */};
/* usb exchanges */
struct usb_action {
@@ -5818,10 +5709,8 @@ static void setmatrix(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, matrix[i], 0x010a + i);
}
-static void setsharpness(struct gspca_dev *gspca_dev)
+static void setsharpness(struct gspca_dev *gspca_dev, s32 val)
{
- struct sd *sd = (struct sd *) gspca_dev;
- int sharpness;
static const u8 sharpness_tb[][2] = {
{0x02, 0x03},
{0x04, 0x07},
@@ -5829,19 +5718,18 @@ static void setsharpness(struct gspca_dev *gspca_dev)
{0x10, 0x1e}
};
- sharpness = sd->ctrls[SHARPNESS].val;
- reg_w(gspca_dev, sharpness_tb[sharpness][0], 0x01c6);
+ reg_w(gspca_dev, sharpness_tb[val][0], 0x01c6);
reg_r(gspca_dev, 0x01c8);
reg_r(gspca_dev, 0x01c9);
reg_r(gspca_dev, 0x01ca);
- reg_w(gspca_dev, sharpness_tb[sharpness][1], 0x01cb);
+ reg_w(gspca_dev, sharpness_tb[val][1], 0x01cb);
}
-static void setcontrast(struct gspca_dev *gspca_dev)
+static void setcontrast(struct gspca_dev *gspca_dev,
+ s32 gamma, s32 brightness, s32 contrast)
{
- struct sd *sd = (struct sd *) gspca_dev;
const u8 *Tgamma;
- int g, i, brightness, contrast, adj, gp1, gp2;
+ int g, i, adj, gp1, gp2;
u8 gr[16];
static const u8 delta_b[16] = /* delta for brightness */
{0x50, 0x38, 0x2d, 0x28, 0x24, 0x21, 0x1e, 0x1d,
@@ -5864,10 +5752,10 @@ static void setcontrast(struct gspca_dev *gspca_dev)
0xe0, 0xeb, 0xf4, 0xff, 0xff, 0xff, 0xff, 0xff},
};
- Tgamma = gamma_tb[sd->ctrls[GAMMA].val - 1];
+ Tgamma = gamma_tb[gamma - 1];
- contrast = ((int) sd->ctrls[CONTRAST].val - 128); /* -128 / 127 */
- brightness = ((int) sd->ctrls[BRIGHTNESS].val - 128); /* -128 / 92 */
+ contrast -= 128; /* -128 / 127 */
+ brightness -= 128; /* -128 / 92 */
adj = 0;
gp1 = gp2 = 0;
for (i = 0; i < 16; i++) {
@@ -5894,25 +5782,15 @@ static void setcontrast(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, gr[i], 0x0130 + i); /* gradient */
}
-static void getexposure(struct gspca_dev *gspca_dev)
+static s32 getexposure(struct gspca_dev *gspca_dev)
{
- struct sd *sd = (struct sd *) gspca_dev;
-
- if (sd->sensor != SENSOR_HV7131R)
- return;
- sd->ctrls[EXPOSURE].val = (i2c_read(gspca_dev, 0x25) << 9)
+ return (i2c_read(gspca_dev, 0x25) << 9)
| (i2c_read(gspca_dev, 0x26) << 1)
| (i2c_read(gspca_dev, 0x27) >> 7);
}
-static void setexposure(struct gspca_dev *gspca_dev)
+static void setexposure(struct gspca_dev *gspca_dev, s32 val)
{
- struct sd *sd = (struct sd *) gspca_dev;
- int val;
-
- if (sd->sensor != SENSOR_HV7131R)
- return;
- val = sd->ctrls[EXPOSURE].val;
i2c_write(gspca_dev, 0x25, val >> 9, 0x00);
i2c_write(gspca_dev, 0x26, val >> 1, 0x00);
i2c_write(gspca_dev, 0x27, val << 7, 0x00);
@@ -5921,20 +5799,8 @@ static void setexposure(struct gspca_dev *gspca_dev)
static void setquality(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- s8 reg07;
-
- reg07 = 0;
- switch (sd->sensor) {
- case SENSOR_OV7620:
- reg07 = 0x30;
- break;
- case SENSOR_HV7131R:
- case SENSOR_PAS202B:
- return; /* done by work queue */
- }
+ jpeg_set_qual(sd->jpeg_hdr, jpeg_qual[sd->reg08 >> 1]);
reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING);
- if (reg07 != 0)
- reg_w(gspca_dev, reg07, 0x0007);
}
/* Matches the sensor's internal frame rate to the lighting frequency.
@@ -5943,7 +5809,7 @@ static void setquality(struct gspca_dev *gspca_dev)
* 60Hz, for American lighting
* 0 = No Fliker (for outdoore usage)
*/
-static void setlightfreq(struct gspca_dev *gspca_dev)
+static void setlightfreq(struct gspca_dev *gspca_dev, s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
int i, mode;
@@ -6027,7 +5893,7 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
tas5130c_60HZ, tas5130c_60HZScale},
};
- i = sd->ctrls[LIGHTFREQ].val * 2;
+ i = val * 2;
mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
if (mode)
i++; /* 320x240 */
@@ -6037,14 +5903,14 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
usb_exchange(gspca_dev, zc3_freq);
switch (sd->sensor) {
case SENSOR_GC0305:
- if (mode /* if 320x240 */
- && sd->ctrls[LIGHTFREQ].val == 1) /* and 50Hz */
+ if (mode /* if 320x240 */
+ && val == 1) /* and 50Hz */
reg_w(gspca_dev, 0x85, 0x018d);
/* win: 0x80, 0x018d */
break;
case SENSOR_OV7620:
- if (!mode) { /* if 640x480 */
- if (sd->ctrls[LIGHTFREQ].val != 0) /* and filter */
+ if (!mode) { /* if 640x480 */
+ if (val != 0) /* and filter */
reg_w(gspca_dev, 0x40, 0x0002);
else
reg_w(gspca_dev, 0x44, 0x0002);
@@ -6056,22 +5922,15 @@ static void setlightfreq(struct gspca_dev *gspca_dev)
}
}
-static void setautogain(struct gspca_dev *gspca_dev)
+static void setautogain(struct gspca_dev *gspca_dev, s32 val)
{
- struct sd *sd = (struct sd *) gspca_dev;
- u8 autoval;
-
- if (sd->ctrls[AUTOGAIN].val)
- autoval = 0x42;
- else
- autoval = 0x02;
- reg_w(gspca_dev, autoval, 0x0180);
+ reg_w(gspca_dev, val ? 0x42 : 0x02, 0x0180);
}
-/* update the transfer parameters */
-/* This function is executed from a work queue. */
-/* The exact use of the bridge registers 07 and 08 is not known.
- * The following algorithm has been adapted from ms-win traces */
+/*
+ * Update the transfer parameters.
+ * This function is executed from a work queue.
+ */
static void transfer_update(struct work_struct *work)
{
struct sd *sd = container_of(work, struct sd, work);
@@ -6079,96 +5938,55 @@ static void transfer_update(struct work_struct *work)
int change, good;
u8 reg07, reg11;
- /* synchronize with the main driver and initialize the registers */
- mutex_lock(&gspca_dev->usb_lock);
- reg07 = 0; /* max */
- reg_w(gspca_dev, reg07, 0x0007);
- reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING);
- mutex_unlock(&gspca_dev->usb_lock);
+ /* reg07 gets set to 0 by sd_start before starting us */
+ reg07 = 0;
good = 0;
for (;;) {
msleep(100);
- /* get the transfer status */
- /* the bit 0 of the bridge register 11 indicates overflow */
mutex_lock(&gspca_dev->usb_lock);
- if (!gspca_dev->present || !gspca_dev->streaming)
+#ifdef CONFIG_PM
+ if (gspca_dev->frozen)
goto err;
+#endif
+ if (!gspca_dev->dev || !gspca_dev->streaming)
+ goto err;
+
+ /* Bit 0 of register 11 indicates FIFO overflow */
+ gspca_dev->usb_err = 0;
reg11 = reg_r(gspca_dev, 0x0011);
- if (gspca_dev->usb_err < 0
- || !gspca_dev->present || !gspca_dev->streaming)
+ if (gspca_dev->usb_err)
goto err;
change = reg11 & 0x01;
if (change) { /* overflow */
- switch (reg07) {
- case 0: /* max */
- reg07 = sd->sensor == SENSOR_HV7131R
- ? 0x30 : 0x32;
- if (sd->reg08 != 0) {
- change = 3;
- sd->reg08--;
- }
- break;
- case 0x32:
- reg07 -= 4;
- break;
- default:
- reg07 -= 2;
- break;
- case 2:
- change = 0; /* already min */
- break;
- }
good = 0;
+
+ if (reg07 == 0) /* Bit Rate Control not enabled? */
+ reg07 = 0x32; /* Allow 98 bytes / unit */
+ else if (reg07 > 2)
+ reg07 -= 2; /* Decrease allowed bytes / unit */
+ else
+ change = 0;
} else { /* no overflow */
- if (reg07 != 0) { /* if not max */
- good++;
- if (good >= 10) {
- good = 0;
+ good++;
+ if (good >= 10) {
+ good = 0;
+ if (reg07) { /* BRC enabled? */
change = 1;
- reg07 += 2;
- switch (reg07) {
- case 0x30:
- if (sd->sensor == SENSOR_PAS202B)
- reg07 += 2;
- break;
- case 0x32:
- case 0x34:
+ if (reg07 < 0x32)
+ reg07 += 2;
+ else
reg07 = 0;
- break;
- }
- }
- } else { /* reg07 max */
- if (sd->reg08 < sizeof jpeg_qual - 1) {
- good++;
- if (good > 10) {
- sd->reg08++;
- change = 2;
- }
}
}
}
if (change) {
- if (change & 1) {
- reg_w(gspca_dev, reg07, 0x0007);
- if (gspca_dev->usb_err < 0
- || !gspca_dev->present
- || !gspca_dev->streaming)
- goto err;
- }
- if (change & 2) {
- reg_w(gspca_dev, sd->reg08,
- ZC3XX_R008_CLOCKSETTING);
- if (gspca_dev->usb_err < 0
- || !gspca_dev->present
- || !gspca_dev->streaming)
- goto err;
- sd->ctrls[QUALITY].val = jpeg_qual[sd->reg08];
- jpeg_set_qual(sd->jpeg_hdr,
- jpeg_qual[sd->reg08]);
- }
+ gspca_dev->usb_err = 0;
+ reg_w(gspca_dev, reg07, 0x0007);
+ if (gspca_dev->usb_err)
+ goto err;
}
mutex_unlock(&gspca_dev->usb_lock);
}
@@ -6503,7 +6321,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
/* define some sensors from the vendor/product */
sd->sensor = id->driver_info;
- gspca_dev->cam.ctrls = sd->ctrls;
sd->reg08 = REG08_DEF;
INIT_WORK(&sd->work, transfer_update);
@@ -6511,12 +6328,87 @@ static int sd_config(struct gspca_dev *gspca_dev,
return 0;
}
-/* this function is called at probe and resume time */
-static int sd_init(struct gspca_dev *gspca_dev)
+static int zcxx_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
- struct sd *sd = (struct sd *) gspca_dev;
- struct cam *cam;
- int sensor;
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+ struct sd *sd = (struct sd *)gspca_dev;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTOGAIN:
+ gspca_dev->usb_err = 0;
+ if (ctrl->val && sd->exposure && gspca_dev->streaming)
+ sd->exposure->val = getexposure(gspca_dev);
+ return gspca_dev->usb_err;
+ }
+ return -EINVAL;
+}
+
+static int zcxx_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;
+ int i, qual;
+
+ gspca_dev->usb_err = 0;
+
+ if (ctrl->id == V4L2_CID_JPEG_COMPRESSION_QUALITY) {
+ qual = sd->reg08 >> 1;
+
+ for (i = 0; i < ARRAY_SIZE(jpeg_qual); i++) {
+ if (ctrl->val <= jpeg_qual[i])
+ break;
+ }
+ if (i > 0 && i == qual && ctrl->val < jpeg_qual[i])
+ i--;
+
+ /* With high quality settings we need max bandwidth */
+ if (i >= 2 && gspca_dev->streaming &&
+ !gspca_dev->cam.needs_full_bandwidth)
+ return -EBUSY;
+
+ sd->reg08 = (i << 1) | 1;
+ ctrl->val = jpeg_qual[i];
+ }
+
+ if (!gspca_dev->streaming)
+ return 0;
+
+ switch (ctrl->id) {
+ /* gamma/brightness/contrast cluster */
+ case V4L2_CID_GAMMA:
+ setcontrast(gspca_dev, sd->gamma->val,
+ sd->brightness->val, sd->contrast->val);
+ break;
+ /* autogain/exposure cluster */
+ case V4L2_CID_AUTOGAIN:
+ setautogain(gspca_dev, ctrl->val);
+ if (!gspca_dev->usb_err && !ctrl->val && sd->exposure)
+ setexposure(gspca_dev, sd->exposure->val);
+ break;
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ setlightfreq(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_SHARPNESS:
+ setsharpness(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+ setquality(gspca_dev);
+ break;
+ }
+ return gspca_dev->usb_err;
+}
+
+static const struct v4l2_ctrl_ops zcxx_ctrl_ops = {
+ .g_volatile_ctrl = zcxx_g_volatile_ctrl,
+ .s_ctrl = zcxx_s_ctrl,
+};
+
+static int sd_init_controls(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *)gspca_dev;
+ struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
static const u8 gamma[SENSOR_MAX] = {
[SENSOR_ADCM2700] = 4,
[SENSOR_CS2102] = 4,
@@ -6538,6 +6430,48 @@ static int sd_init(struct gspca_dev *gspca_dev)
[SENSOR_PO2030] = 4,
[SENSOR_TAS5130C] = 3,
};
+
+ gspca_dev->vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 8);
+ sd->brightness = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+ sd->contrast = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1, 128);
+ sd->gamma = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops,
+ V4L2_CID_GAMMA, 1, 6, 1, gamma[sd->sensor]);
+ if (sd->sensor == SENSOR_HV7131R)
+ sd->exposure = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops,
+ V4L2_CID_EXPOSURE, 0x30d, 0x493e, 1, 0x927);
+ sd->autogain = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops,
+ V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+ if (sd->sensor != SENSOR_OV7630C)
+ sd->plfreq = v4l2_ctrl_new_std_menu(hdl, &zcxx_ctrl_ops,
+ V4L2_CID_POWER_LINE_FREQUENCY,
+ V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0,
+ V4L2_CID_POWER_LINE_FREQUENCY_DISABLED);
+ sd->sharpness = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops,
+ V4L2_CID_SHARPNESS, 0, 3, 1,
+ sd->sensor == SENSOR_PO2030 ? 0 : 2);
+ sd->jpegqual = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops,
+ V4L2_CID_JPEG_COMPRESSION_QUALITY,
+ jpeg_qual[0], jpeg_qual[ARRAY_SIZE(jpeg_qual) - 1], 1,
+ jpeg_qual[REG08_DEF >> 1]);
+ if (hdl->error) {
+ pr_err("Could not initialize controls\n");
+ return hdl->error;
+ }
+ v4l2_ctrl_cluster(3, &sd->gamma);
+ if (sd->sensor == SENSOR_HV7131R)
+ v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, true);
+ return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam;
+ int sensor;
static const u8 mode_tb[SENSOR_MAX] = {
[SENSOR_ADCM2700] = 2,
[SENSOR_CS2102] = 1,
@@ -6559,27 +6493,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
[SENSOR_PO2030] = 1,
[SENSOR_TAS5130C] = 1,
};
- static const u8 reg08_tb[SENSOR_MAX] = {
- [SENSOR_ADCM2700] = 1,
- [SENSOR_CS2102] = 3,
- [SENSOR_CS2102K] = 3,
- [SENSOR_GC0303] = 2,
- [SENSOR_GC0305] = 3,
- [SENSOR_HDCS2020] = 1,
- [SENSOR_HV7131B] = 3,
- [SENSOR_HV7131R] = 3,
- [SENSOR_ICM105A] = 3,
- [SENSOR_MC501CB] = 3,
- [SENSOR_MT9V111_1] = 3,
- [SENSOR_MT9V111_3] = 3,
- [SENSOR_OV7620] = 1,
- [SENSOR_OV7630C] = 3,
- [SENSOR_PAS106] = 3,
- [SENSOR_PAS202B] = 3,
- [SENSOR_PB0330] = 3,
- [SENSOR_PO2030] = 2,
- [SENSOR_TAS5130C] = 3,
- };
sensor = zcxx_probeSensor(gspca_dev);
if (sensor >= 0)
@@ -6688,7 +6601,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
case 0x2030:
PDEBUG(D_PROBE, "Find Sensor PO2030");
sd->sensor = SENSOR_PO2030;
- sd->ctrls[SHARPNESS].def = 0; /* from win traces */
break;
case 0x7620:
PDEBUG(D_PROBE, "Find Sensor OV7620");
@@ -6730,36 +6642,18 @@ static int sd_init(struct gspca_dev *gspca_dev)
break;
}
- sd->ctrls[GAMMA].def = gamma[sd->sensor];
- sd->reg08 = reg08_tb[sd->sensor];
- sd->ctrls[QUALITY].def = jpeg_qual[sd->reg08];
- sd->ctrls[QUALITY].min = jpeg_qual[0];
- sd->ctrls[QUALITY].max = jpeg_qual[ARRAY_SIZE(jpeg_qual) - 1];
-
- switch (sd->sensor) {
- case SENSOR_HV7131R:
- gspca_dev->ctrl_dis = (1 << QUALITY);
- break;
- case SENSOR_OV7630C:
- gspca_dev->ctrl_dis = (1 << LIGHTFREQ) | (1 << EXPOSURE);
- break;
- case SENSOR_PAS202B:
- gspca_dev->ctrl_dis = (1 << QUALITY) | (1 << EXPOSURE);
- break;
- default:
- gspca_dev->ctrl_dis = (1 << EXPOSURE);
- break;
- }
-#if AUTOGAIN_DEF
- if (sd->ctrls[AUTOGAIN].val)
- gspca_dev->ctrl_inac = (1 << EXPOSURE);
-#endif
-
/* switch off the led */
reg_w(gspca_dev, 0x01, 0x0000);
return gspca_dev->usb_err;
}
+static int sd_pre_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ gspca_dev->cam.needs_full_bandwidth = (sd->reg08 >= 4) ? 1 : 0;
+ return 0;
+}
+
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -6864,7 +6758,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x03, 0x0008);
break;
}
- setsharpness(gspca_dev);
+ setsharpness(gspca_dev, v4l2_ctrl_g_ctrl(sd->sharpness));
/* set the gamma tables when not set */
switch (sd->sensor) {
@@ -6873,7 +6767,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
case SENSOR_OV7630C:
break;
default:
- setcontrast(gspca_dev);
+ setcontrast(gspca_dev, v4l2_ctrl_g_ctrl(sd->gamma),
+ v4l2_ctrl_g_ctrl(sd->brightness),
+ v4l2_ctrl_g_ctrl(sd->contrast));
break;
}
setmatrix(gspca_dev); /* one more time? */
@@ -6885,8 +6781,10 @@ static int sd_start(struct gspca_dev *gspca_dev)
break;
}
setquality(gspca_dev);
- jpeg_set_qual(sd->jpeg_hdr, jpeg_qual[sd->reg08]);
- setlightfreq(gspca_dev);
+ /* Start with BRC disabled, transfer_update will enable it if needed */
+ reg_w(gspca_dev, 0x00, 0x0007);
+ if (sd->plfreq)
+ setlightfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->plfreq));
switch (sd->sensor) {
case SENSOR_ADCM2700:
@@ -6897,7 +6795,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x40, 0x0117);
break;
case SENSOR_HV7131R:
- setexposure(gspca_dev);
+ setexposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure));
reg_w(gspca_dev, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN);
break;
case SENSOR_GC0305:
@@ -6921,21 +6819,16 @@ static int sd_start(struct gspca_dev *gspca_dev)
break;
}
- setautogain(gspca_dev);
+ setautogain(gspca_dev, v4l2_ctrl_g_ctrl(sd->autogain));
- /* start the transfer update thread if needed */
- if (gspca_dev->usb_err >= 0) {
- switch (sd->sensor) {
- case SENSOR_HV7131R:
- case SENSOR_PAS202B:
- sd->work_thread =
- create_singlethread_workqueue(KBUILD_MODNAME);
- queue_work(sd->work_thread, &sd->work);
- break;
- }
- }
+ if (gspca_dev->usb_err < 0)
+ return gspca_dev->usb_err;
- return gspca_dev->usb_err;
+ /* Start the transfer parameters update thread */
+ sd->work_thread = create_singlethread_workqueue(KBUILD_MODNAME);
+ queue_work(sd->work_thread, &sd->work);
+
+ return 0;
}
/* called on streamoff with alt 0 and on disconnect */
@@ -6949,7 +6842,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
mutex_lock(&gspca_dev->usb_lock);
sd->work_thread = NULL;
}
- if (!gspca_dev->present)
+ if (!gspca_dev->dev)
return;
send_unknown(gspca_dev, sd->sensor);
}
@@ -6987,72 +6880,17 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->ctrls[AUTOGAIN].val = val;
- if (val) {
- gspca_dev->ctrl_inac |= (1 << EXPOSURE);
- } else {
- gspca_dev->ctrl_inac &= ~(1 << EXPOSURE);
- if (gspca_dev->streaming)
- getexposure(gspca_dev);
- }
- if (gspca_dev->streaming)
- setautogain(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_querymenu(struct gspca_dev *gspca_dev,
- struct v4l2_querymenu *menu)
-{
- switch (menu->id) {
- case V4L2_CID_POWER_LINE_FREQUENCY:
- switch (menu->index) {
- case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
- strcpy((char *) menu->name, "NoFliker");
- return 0;
- case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
- strcpy((char *) menu->name, "50 Hz");
- return 0;
- case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
- strcpy((char *) menu->name, "60 Hz");
- return 0;
- }
- break;
- }
- return -EINVAL;
-}
-
-static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(jpeg_qual) - 1; i++) {
- if (val <= jpeg_qual[i])
- break;
- }
- if (i > 0
- && i == sd->reg08
- && val < jpeg_qual[sd->reg08])
- i--;
- sd->reg08 = i;
- sd->ctrls[QUALITY].val = jpeg_qual[i];
- if (gspca_dev->streaming)
- jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val);
- return gspca_dev->usb_err;
-}
-
static int sd_set_jcomp(struct gspca_dev *gspca_dev,
struct v4l2_jpegcompression *jcomp)
{
struct sd *sd = (struct sd *) gspca_dev;
+ int ret;
- sd_setquality(gspca_dev, jcomp->quality);
- jcomp->quality = sd->ctrls[QUALITY].val;
- return gspca_dev->usb_err;
+ ret = v4l2_ctrl_s_ctrl(sd->jpegqual, jcomp->quality);
+ if (ret)
+ return ret;
+ jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual);
+ return 0;
}
static int sd_get_jcomp(struct gspca_dev *gspca_dev,
@@ -7061,7 +6899,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
struct sd *sd = (struct sd *) gspca_dev;
memset(jcomp, 0, sizeof *jcomp);
- jcomp->quality = sd->ctrls[QUALITY].val;
+ jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual);
jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
| V4L2_JPEG_MARKER_DQT;
return 0;
@@ -7085,14 +6923,13 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
static const struct sd_desc sd_desc = {
.name = KBUILD_MODNAME,
- .ctrls = sd_ctrls,
- .nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
.init = sd_init,
+ .init_controls = sd_init_controls,
+ .isoc_init = sd_pre_start,
.start = sd_start,
.stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
- .querymenu = sd_querymenu,
.get_jcomp = sd_get_jcomp,
.set_jcomp = sd_set_jcomp,
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
@@ -7176,6 +7013,7 @@ static struct usb_driver sd_driver = {
#ifdef CONFIG_PM
.suspend = gspca_suspend,
.resume = gspca_resume,
+ .reset_resume = gspca_resume,
#endif
};
diff --git a/drivers/media/video/hdpvr/hdpvr-control.c b/drivers/media/video/hdpvr/hdpvr-control.c
index 068df4ba3f51..ae8f229d1141 100644
--- a/drivers/media/video/hdpvr/hdpvr-control.c
+++ b/drivers/media/video/hdpvr/hdpvr-control.c
@@ -113,6 +113,8 @@ int get_input_lines_info(struct hdpvr_device *dev)
"get input lines info returned: %d, %s\n", ret,
print_buf);
}
+#else
+ (void)ret; /* suppress compiler warning */
#endif
lines = dev->usbc_buf[1] << 8 | dev->usbc_buf[0];
mutex_unlock(&dev->usbc_mutex);
diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c
index 6510110f53d0..304f43ef59eb 100644
--- a/drivers/media/video/hdpvr/hdpvr-core.c
+++ b/drivers/media/video/hdpvr/hdpvr-core.c
@@ -303,7 +303,7 @@ static int hdpvr_probe(struct usb_interface *interface,
/* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) {
- err("Out of memory");
+ dev_err(&interface->dev, "Out of memory\n");
goto error;
}
@@ -311,7 +311,7 @@ static int hdpvr_probe(struct usb_interface *interface,
/* register v4l2_device early so it can be used for printks */
if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) {
- err("v4l2_device_register failed");
+ dev_err(&interface->dev, "v4l2_device_register failed\n");
goto error;
}
diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c
index 11ffe9cc1780..0e9e156bb2aa 100644
--- a/drivers/media/video/hdpvr/hdpvr-video.c
+++ b/drivers/media/video/hdpvr/hdpvr-video.c
@@ -994,7 +994,7 @@ static int hdpvr_try_ctrl(struct v4l2_ext_control *ctrl, int ac3)
default:
return -EINVAL;
}
- return 0;
+ return ret;
}
static int vidioc_try_ext_ctrls(struct file *file, void *priv,
diff --git a/drivers/media/video/hexium_gemini.c b/drivers/media/video/hexium_gemini.c
index a62322d5c0d8..366434f5647e 100644
--- a/drivers/media/video/hexium_gemini.c
+++ b/drivers/media/video/hexium_gemini.c
@@ -40,15 +40,15 @@ static int hexium_num;
#define HEXIUM_INPUTS 9
static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
- { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
- { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
- { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
- { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
- { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
- { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
- { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
- { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
- { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+ { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+ { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+ { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+ { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+ { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+ { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+ { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+ { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
};
#define HEXIUM_AUDIOS 0
@@ -59,11 +59,6 @@ struct hexium_data
u8 byte;
};
-#define HEXIUM_CONTROLS 1
-static struct v4l2_queryctrl hexium_controls[] = {
- { V4L2_CID_PRIVATE_BASE, V4L2_CTRL_TYPE_BOOLEAN, "B/W", 0, 1, 1, 0, 0 },
-};
-
#define HEXIUM_GEMINI_V_1_0 1
#define HEXIUM_GEMINI_DUAL_V_1_0 2
@@ -76,7 +71,6 @@ struct hexium
int cur_input; /* current input */
v4l2_std_id cur_std; /* current standard */
- int cur_bw; /* current black/white status */
};
/* Samsung KS0127B decoder default registers */
@@ -119,18 +113,10 @@ static struct hexium_data hexium_pal[] = {
{ 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
};
-static struct hexium_data hexium_pal_bw[] = {
- { 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
-};
-
static struct hexium_data hexium_ntsc[] = {
{ 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
};
-static struct hexium_data hexium_ntsc_bw[] = {
- { 0x01, 0x53 }, { 0x12, 0x04 }, { 0x2D, 0x23 }, { 0x2E, 0x81 }, { -1 , 0xFF }
-};
-
static struct hexium_data hexium_secam[] = {
{ 0x01, 0x52 }, { 0x12, 0x64 }, { 0x2D, 0x2C }, { 0x2E, 0x9B }, { -1 , 0xFF }
};
@@ -264,93 +250,6 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
return 0;
}
-/* the saa7146 provides some controls (brightness, contrast, saturation)
- which gets registered *after* this function. because of this we have
- to return with a value != 0 even if the function succeeded.. */
-static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc)
-{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
- int i;
-
- for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
- if (hexium_controls[i].id == qc->id) {
- *qc = hexium_controls[i];
- DEB_D("VIDIOC_QUERYCTRL %d\n", qc->id);
- return 0;
- }
- }
- return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc);
-}
-
-static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
-{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
- struct hexium *hexium = (struct hexium *) dev->ext_priv;
- int i;
-
- for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
- if (hexium_controls[i].id == vc->id)
- break;
- }
-
- if (i < 0)
- return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc);
-
- if (vc->id == V4L2_CID_PRIVATE_BASE) {
- vc->value = hexium->cur_bw;
- DEB_D("VIDIOC_G_CTRL BW:%d\n", vc->value);
- return 0;
- }
- return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
-{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
- struct hexium *hexium = (struct hexium *) dev->ext_priv;
- int i = 0;
-
- for (i = HEXIUM_CONTROLS - 1; i >= 0; i--) {
- if (hexium_controls[i].id == vc->id)
- break;
- }
-
- if (i < 0)
- return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc);
-
- if (vc->id == V4L2_CID_PRIVATE_BASE)
- hexium->cur_bw = vc->value;
-
- DEB_D("VIDIOC_S_CTRL BW:%d\n", hexium->cur_bw);
-
- if (0 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
- hexium_set_standard(hexium, hexium_pal);
- return 0;
- }
- if (0 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
- hexium_set_standard(hexium, hexium_ntsc);
- return 0;
- }
- if (0 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std) {
- hexium_set_standard(hexium, hexium_secam);
- return 0;
- }
- if (1 == hexium->cur_bw && V4L2_STD_PAL == hexium->cur_std) {
- hexium_set_standard(hexium, hexium_pal_bw);
- return 0;
- }
- if (1 == hexium->cur_bw && V4L2_STD_NTSC == hexium->cur_std) {
- hexium_set_standard(hexium, hexium_ntsc_bw);
- return 0;
- }
- if (1 == hexium->cur_bw && V4L2_STD_SECAM == hexium->cur_std)
- /* fixme: is there no bw secam mode? */
- return -EINVAL;
-
- return -EINVAL;
-}
-
-
static struct saa7146_ext_vv vv_data;
/* this function only gets called when the probing was successful */
@@ -399,12 +298,10 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d
hexium->cur_input = 0;
saa7146_vv_init(dev, &vv_data);
- vv_data.ops.vidioc_queryctrl = vidioc_queryctrl;
- vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl;
- vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl;
- vv_data.ops.vidioc_enum_input = vidioc_enum_input;
- vv_data.ops.vidioc_g_input = vidioc_g_input;
- vv_data.ops.vidioc_s_input = vidioc_s_input;
+
+ vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
+ vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
+ vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
ret = saa7146_register_device(&hexium->video_dev, dev, "hexium gemini", VFL_TYPE_GRABBER);
if (ret < 0) {
pr_err("cannot register capture v4l2 device. skipping.\n");
diff --git a/drivers/media/video/hexium_orion.c b/drivers/media/video/hexium_orion.c
index 23debc967d94..a1eb26d11070 100644
--- a/drivers/media/video/hexium_orion.c
+++ b/drivers/media/video/hexium_orion.c
@@ -41,15 +41,15 @@ static int hexium_num;
#define HEXIUM_INPUTS 9
static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
- { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
- { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
- { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
- { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
- { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
- { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
- { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
- { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
- { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+ { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+ { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+ { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+ { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+ { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+ { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+ { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+ { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 0, 0, V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
};
#define HEXIUM_AUDIOS 0
@@ -371,9 +371,9 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d
DEB_EE("\n");
saa7146_vv_init(dev, &vv_data);
- vv_data.ops.vidioc_enum_input = vidioc_enum_input;
- vv_data.ops.vidioc_g_input = vidioc_g_input;
- vv_data.ops.vidioc_s_input = vidioc_s_input;
+ vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
+ vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
+ vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
if (0 != saa7146_register_device(&hexium->video_dev, dev, "hexium orion", VFL_TYPE_GRABBER)) {
pr_err("cannot register capture v4l2 device. skipping.\n");
return -1;
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 679262ed13bc..057929e165ab 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -1201,9 +1201,9 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
struct v4l2_ctrl_handler *hdl = itv->v4l2_dev.ctrl_handler;
itv->ctrl_pts = v4l2_ctrl_new_std(hdl, &ivtv_hdl_out_ops,
- V4L2_CID_MPEG_VIDEO_DEC_PTS, 0, 0, 1, 0);
+ V4L2_CID_MPEG_VIDEO_DEC_PTS, 0, 0, 0, 0);
itv->ctrl_frame = v4l2_ctrl_new_std(hdl, &ivtv_hdl_out_ops,
- V4L2_CID_MPEG_VIDEO_DEC_FRAME, 0, 0x7fffffff, 1, 0);
+ V4L2_CID_MPEG_VIDEO_DEC_FRAME, 0, 0, 0, 0);
/* Note: V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO is not supported,
mask that menu item. */
itv->ctrl_audio_playback =
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index c9663e885b9f..9ff69b5a87e2 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -746,8 +746,9 @@ unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait)
return res;
}
-unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait)
+unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table *wait)
{
+ unsigned long req_events = poll_requested_events(wait);
struct ivtv_open_id *id = fh2id(filp->private_data);
struct ivtv *itv = id->itv;
struct ivtv_stream *s = &itv->streams[id->type];
@@ -755,7 +756,8 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait)
unsigned res = 0;
/* Start a capture if there is none */
- if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
+ if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags) &&
+ (req_events & (POLLIN | POLLRDNORM))) {
int rc;
rc = ivtv_start_capture(id);
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index 989e556913ed..f7d57b3f2842 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -135,7 +135,6 @@ void ivtv_set_osd_alpha(struct ivtv *itv)
int ivtv_set_speed(struct ivtv *itv, int speed)
{
u32 data[CX2341X_MBOX_MAX_DATA];
- struct ivtv_stream *s;
int single_step = (speed == 1 || speed == -1);
DEFINE_WAIT(wait);
@@ -145,8 +144,6 @@ int ivtv_set_speed(struct ivtv *itv, int speed)
if (speed == itv->speed && !single_step)
return 0;
- s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
-
if (single_step && (speed < 0) == (itv->speed < 0)) {
/* Single step video and no need to change direction */
ivtv_vapi(itv, CX2341X_DEC_STEP_VIDEO, 1, 0);
@@ -1468,8 +1465,9 @@ static int ivtv_subscribe_event(struct v4l2_fh *fh, struct v4l2_event_subscripti
switch (sub->type) {
case V4L2_EVENT_VSYNC:
case V4L2_EVENT_EOS:
+ return v4l2_event_subscribe(fh, sub, 0, NULL);
case V4L2_EVENT_CTRL:
- return v4l2_event_subscribe(fh, sub, 0);
+ return v4l2_event_subscribe(fh, sub, 0, &v4l2_ctrl_sub_ev_ops);
default:
return -EINVAL;
}
@@ -1827,7 +1825,7 @@ static long ivtv_default(struct file *file, void *fh, bool valid_prio,
return ivtv_decoder_ioctls(file, cmd, (void *)arg);
default:
- return -EINVAL;
+ return -ENOTTY;
}
return 0;
}
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index 7ea5ca7f012b..6738592aa35d 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -228,6 +228,10 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
s->vdev->release = video_device_release;
s->vdev->tvnorms = V4L2_STD_ALL;
s->vdev->lock = &itv->serialize_lock;
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &s->vdev->flags);
set_bit(V4L2_FL_USE_FH_PRIO, &s->vdev->flags);
ivtv_set_funcs(s->vdev);
return 0;
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index e5e7fa9e737b..05b94aa8ba32 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -1293,6 +1293,7 @@ static int __init ivtvfb_init(void)
drv = driver_find("ivtv", &pci_bus_type);
err = driver_for_each_device(drv, NULL, &registered, ivtvfb_callback_init);
+ (void)err; /* suppress compiler warning */
if (!registered) {
printk(KERN_ERR "ivtvfb: no cards found\n");
return -ENODEV;
@@ -1309,6 +1310,7 @@ static void ivtvfb_cleanup(void)
drv = driver_find("ivtv", &pci_bus_type);
err = driver_for_each_device(drv, NULL, NULL, ivtvfb_callback_cleanup);
+ (void)err; /* suppress compiler warning */
}
module_init(ivtvfb_init);
diff --git a/drivers/media/video/m5mols/m5mols.h b/drivers/media/video/m5mols/m5mols.h
index 4b021e1ee5f2..bb589917b65b 100644
--- a/drivers/media/video/m5mols/m5mols.h
+++ b/drivers/media/video/m5mols/m5mols.h
@@ -21,11 +21,6 @@
extern int m5mols_debug;
-#define to_m5mols(__sd) container_of(__sd, struct m5mols_info, sd)
-
-#define to_sd(__ctrl) \
- (&container_of(__ctrl->handler, struct m5mols_info, handle)->sd)
-
enum m5mols_restype {
M5MOLS_RESTYPE_MONITOR,
M5MOLS_RESTYPE_CAPTURE,
@@ -163,21 +158,27 @@ struct m5mols_version {
* @ffmt: current fmt according to resolution type
* @res_type: current resolution type
* @irq_waitq: waitqueue for the capture
- * @flags: state variable for the interrupt handler
+ * @irq_done: set to 1 in the interrupt handler
* @handle: control handler
- * @autoexposure: Auto Exposure control
- * @exposure: Exposure control
- * @autowb: Auto White Balance control
- * @colorfx: Color effect control
- * @saturation: Saturation control
- * @zoom: Zoom control
+ * @auto_exposure: auto/manual exposure control
+ * @exposure_bias: exposure compensation control
+ * @exposure: manual exposure control
+ * @metering: exposure metering control
+ * @auto_iso: auto/manual ISO sensitivity control
+ * @iso: manual ISO sensitivity control
+ * @auto_wb: auto white balance control
+ * @lock_3a: 3A lock control
+ * @colorfx: color effect control
+ * @saturation: saturation control
+ * @zoom: zoom control
+ * @wdr: wide dynamic range control
+ * @stabilization: image stabilization control
+ * @jpeg_quality: JPEG compression quality control
* @ver: information of the version
* @cap: the capture mode attributes
- * @power: current sensor's power status
* @isp_ready: 1 when the ISP controller has completed booting
+ * @power: current sensor's power status
* @ctrl_sync: 1 when the control handler state is restored in H/W
- * @lock_ae: true means the Auto Exposure is locked
- * @lock_awb: true means the Aut WhiteBalance is locked
* @resolution: register value for current resolution
* @mode: register value for current operation mode
* @set_power: optional power callback to the board code
@@ -193,15 +194,27 @@ struct m5mols_info {
atomic_t irq_done;
struct v4l2_ctrl_handler handle;
+ struct {
+ /* exposure/exposure bias/auto exposure cluster */
+ struct v4l2_ctrl *auto_exposure;
+ struct v4l2_ctrl *exposure_bias;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *metering;
+ };
+ struct {
+ /* iso/auto iso cluster */
+ struct v4l2_ctrl *auto_iso;
+ struct v4l2_ctrl *iso;
+ };
+ struct v4l2_ctrl *auto_wb;
- /* Autoexposure/exposure control cluster */
- struct v4l2_ctrl *autoexposure;
- struct v4l2_ctrl *exposure;
-
- struct v4l2_ctrl *autowb;
+ struct v4l2_ctrl *lock_3a;
struct v4l2_ctrl *colorfx;
struct v4l2_ctrl *saturation;
struct v4l2_ctrl *zoom;
+ struct v4l2_ctrl *wdr;
+ struct v4l2_ctrl *stabilization;
+ struct v4l2_ctrl *jpeg_quality;
struct m5mols_version ver;
struct m5mols_capture cap;
@@ -210,8 +223,6 @@ struct m5mols_info {
unsigned int power:1;
unsigned int ctrl_sync:1;
- bool lock_ae;
- bool lock_awb;
u8 resolution;
u8 mode;
@@ -282,7 +293,7 @@ int m5mols_busy_wait(struct v4l2_subdev *sd, u32 reg, u32 value, u32 mask,
* The available executing order between each modes are as follows:
* PARAMETER <---> MONITOR <---> CAPTURE
*/
-int m5mols_mode(struct m5mols_info *info, u8 mode);
+int m5mols_set_mode(struct m5mols_info *info, u8 mode);
int m5mols_enable_interrupt(struct v4l2_subdev *sd, u8 reg);
int m5mols_wait_interrupt(struct v4l2_subdev *sd, u8 condition, u32 timeout);
@@ -291,9 +302,33 @@ int m5mols_start_capture(struct m5mols_info *info);
int m5mols_do_scenemode(struct m5mols_info *info, u8 mode);
int m5mols_lock_3a(struct m5mols_info *info, bool lock);
int m5mols_set_ctrl(struct v4l2_ctrl *ctrl);
+int m5mols_init_controls(struct v4l2_subdev *sd);
/* The firmware function */
int m5mols_update_fw(struct v4l2_subdev *sd,
int (*set_power)(struct m5mols_info *, bool));
+static inline struct m5mols_info *to_m5mols(struct v4l2_subdev *subdev)
+{
+ return container_of(subdev, struct m5mols_info, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+ struct m5mols_info *info = container_of(ctrl->handler,
+ struct m5mols_info, handle);
+ return &info->sd;
+}
+
+static inline void m5mols_set_ctrl_mode(struct v4l2_ctrl *ctrl,
+ unsigned int mode)
+{
+ ctrl->priv = (void *)mode;
+}
+
+static inline unsigned int m5mols_get_ctrl_mode(struct v4l2_ctrl *ctrl)
+{
+ return (unsigned int)ctrl->priv;
+}
+
#endif /* M5MOLS_H */
diff --git a/drivers/media/video/m5mols/m5mols_capture.c b/drivers/media/video/m5mols/m5mols_capture.c
index ba25e8e2ba4c..cb243bd278ce 100644
--- a/drivers/media/video/m5mols/m5mols_capture.c
+++ b/drivers/media/video/m5mols/m5mols_capture.c
@@ -106,7 +106,6 @@ static int m5mols_capture_info(struct m5mols_info *info)
int m5mols_start_capture(struct m5mols_info *info)
{
struct v4l2_subdev *sd = &info->sd;
- u8 resolution = info->resolution;
int ret;
/*
@@ -114,22 +113,18 @@ int m5mols_start_capture(struct m5mols_info *info)
* format. The frame capture is initiated during switching from Monitor
* to Capture mode.
*/
- ret = m5mols_mode(info, REG_MONITOR);
+ ret = m5mols_set_mode(info, REG_MONITOR);
if (!ret)
ret = m5mols_restore_controls(info);
if (!ret)
ret = m5mols_write(sd, CAPP_YUVOUT_MAIN, REG_JPEG);
if (!ret)
- ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, resolution);
+ ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, info->resolution);
if (!ret)
- ret = m5mols_lock_3a(info, true);
- if (!ret)
- ret = m5mols_mode(info, REG_CAPTURE);
+ ret = m5mols_set_mode(info, REG_CAPTURE);
if (!ret)
/* Wait until a frame is captured to ISP internal memory */
ret = m5mols_wait_interrupt(sd, REG_INT_CAPTURE, 2000);
- if (!ret)
- ret = m5mols_lock_3a(info, false);
if (ret)
return ret;
diff --git a/drivers/media/video/m5mols/m5mols_controls.c b/drivers/media/video/m5mols/m5mols_controls.c
index d135d20d09cf..392a028730e2 100644
--- a/drivers/media/video/m5mols/m5mols_controls.c
+++ b/drivers/media/video/m5mols/m5mols_controls.c
@@ -139,7 +139,7 @@ int m5mols_do_scenemode(struct m5mols_info *info, u8 mode)
if (mode > REG_SCENE_CANDLE)
return -EINVAL;
- ret = m5mols_lock_3a(info, false);
+ ret = v4l2_ctrl_s_ctrl(info->lock_3a, 0);
if (!ret)
ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, mode);
if (!ret)
@@ -169,7 +169,7 @@ int m5mols_do_scenemode(struct m5mols_info *info, u8 mode)
if (!ret)
ret = m5mols_write(sd, AE_ISO, scenemode.iso);
if (!ret)
- ret = m5mols_mode(info, REG_CAPTURE);
+ ret = m5mols_set_mode(info, REG_CAPTURE);
if (!ret)
ret = m5mols_write(sd, CAPP_WDR_EN, scenemode.wdr);
if (!ret)
@@ -181,119 +181,448 @@ int m5mols_do_scenemode(struct m5mols_info *info, u8 mode)
if (!ret)
ret = m5mols_write(sd, CAPC_MODE, scenemode.capt_mode);
if (!ret)
- ret = m5mols_mode(info, REG_MONITOR);
+ ret = m5mols_set_mode(info, REG_MONITOR);
return ret;
}
-static int m5mols_lock_ae(struct m5mols_info *info, bool lock)
+static int m5mols_3a_lock(struct m5mols_info *info, struct v4l2_ctrl *ctrl)
{
+ bool af_lock = ctrl->val & V4L2_LOCK_FOCUS;
int ret = 0;
- if (info->lock_ae != lock)
- ret = m5mols_write(&info->sd, AE_LOCK,
- lock ? REG_AE_LOCK : REG_AE_UNLOCK);
- if (!ret)
- info->lock_ae = lock;
+ if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_EXPOSURE) {
+ bool ae_lock = ctrl->val & V4L2_LOCK_EXPOSURE;
+
+ ret = m5mols_write(&info->sd, AE_LOCK, ae_lock ?
+ REG_AE_LOCK : REG_AE_UNLOCK);
+ if (ret)
+ return ret;
+ }
+
+ if (((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_WHITE_BALANCE)
+ && info->auto_wb->val) {
+ bool awb_lock = ctrl->val & V4L2_LOCK_WHITE_BALANCE;
+
+ ret = m5mols_write(&info->sd, AWB_LOCK, awb_lock ?
+ REG_AWB_LOCK : REG_AWB_UNLOCK);
+ if (ret)
+ return ret;
+ }
+
+ if (!info->ver.af || !af_lock)
+ return ret;
+
+ if ((ctrl->val ^ ctrl->cur.val) & V4L2_LOCK_FOCUS)
+ ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP);
+
+ return ret;
+}
+
+static int m5mols_set_metering_mode(struct m5mols_info *info, int mode)
+{
+ unsigned int metering;
+
+ switch (mode) {
+ case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED:
+ metering = REG_AE_CENTER;
+ break;
+ case V4L2_EXPOSURE_METERING_SPOT:
+ metering = REG_AE_SPOT;
+ break;
+ default:
+ metering = REG_AE_ALL;
+ break;
+ }
+
+ return m5mols_write(&info->sd, AE_MODE, metering);
+}
+
+static int m5mols_set_exposure(struct m5mols_info *info, int exposure)
+{
+ struct v4l2_subdev *sd = &info->sd;
+ int ret = 0;
+
+ if (exposure == V4L2_EXPOSURE_AUTO) {
+ /* Unlock auto exposure */
+ info->lock_3a->val &= ~V4L2_LOCK_EXPOSURE;
+ m5mols_3a_lock(info, info->lock_3a);
+
+ ret = m5mols_set_metering_mode(info, info->metering->val);
+ if (ret < 0)
+ return ret;
+
+ v4l2_dbg(1, m5mols_debug, sd,
+ "%s: exposure bias: %#x, metering: %#x\n",
+ __func__, info->exposure_bias->val,
+ info->metering->val);
+
+ return m5mols_write(sd, AE_INDEX, info->exposure_bias->val);
+ }
+
+ if (exposure == V4L2_EXPOSURE_MANUAL) {
+ ret = m5mols_write(sd, AE_MODE, REG_AE_OFF);
+ if (ret == 0)
+ ret = m5mols_write(sd, AE_MAN_GAIN_MON,
+ info->exposure->val);
+ if (ret == 0)
+ ret = m5mols_write(sd, AE_MAN_GAIN_CAP,
+ info->exposure->val);
+
+ v4l2_dbg(1, m5mols_debug, sd, "%s: exposure: %#x\n",
+ __func__, info->exposure->val);
+ }
+
+ return ret;
+}
+
+static int m5mols_set_white_balance(struct m5mols_info *info, int val)
+{
+ static const unsigned short wb[][2] = {
+ { V4L2_WHITE_BALANCE_INCANDESCENT, REG_AWB_INCANDESCENT },
+ { V4L2_WHITE_BALANCE_FLUORESCENT, REG_AWB_FLUORESCENT_1 },
+ { V4L2_WHITE_BALANCE_FLUORESCENT_H, REG_AWB_FLUORESCENT_2 },
+ { V4L2_WHITE_BALANCE_HORIZON, REG_AWB_HORIZON },
+ { V4L2_WHITE_BALANCE_DAYLIGHT, REG_AWB_DAYLIGHT },
+ { V4L2_WHITE_BALANCE_FLASH, REG_AWB_LEDLIGHT },
+ { V4L2_WHITE_BALANCE_CLOUDY, REG_AWB_CLOUDY },
+ { V4L2_WHITE_BALANCE_SHADE, REG_AWB_SHADE },
+ { V4L2_WHITE_BALANCE_AUTO, REG_AWB_AUTO },
+ };
+ int i;
+ struct v4l2_subdev *sd = &info->sd;
+ int ret = -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(wb); i++) {
+ int awb;
+ if (wb[i][0] != val)
+ continue;
+
+ v4l2_dbg(1, m5mols_debug, sd,
+ "Setting white balance to: %#x\n", wb[i][0]);
+
+ awb = wb[i][0] == V4L2_WHITE_BALANCE_AUTO;
+ ret = m5mols_write(sd, AWB_MODE, awb ? REG_AWB_AUTO :
+ REG_AWB_PRESET);
+ if (ret < 0)
+ return ret;
+
+ if (!awb)
+ ret = m5mols_write(sd, AWB_MANUAL, wb[i][1]);
+ }
return ret;
}
-static int m5mols_lock_awb(struct m5mols_info *info, bool lock)
+static int m5mols_set_saturation(struct m5mols_info *info, int val)
+{
+ int ret = m5mols_write(&info->sd, MON_CHROMA_LVL, val);
+ if (ret < 0)
+ return ret;
+
+ return m5mols_write(&info->sd, MON_CHROMA_EN, REG_CHROMA_ON);
+}
+
+static int m5mols_set_color_effect(struct m5mols_info *info, int val)
{
+ unsigned int m_effect = REG_COLOR_EFFECT_OFF;
+ unsigned int p_effect = REG_EFFECT_OFF;
+ unsigned int cfix_r = 0, cfix_b = 0;
+ struct v4l2_subdev *sd = &info->sd;
int ret = 0;
- if (info->lock_awb != lock)
- ret = m5mols_write(&info->sd, AWB_LOCK,
- lock ? REG_AWB_LOCK : REG_AWB_UNLOCK);
+ switch (val) {
+ case V4L2_COLORFX_BW:
+ m_effect = REG_COLOR_EFFECT_ON;
+ break;
+ case V4L2_COLORFX_NEGATIVE:
+ p_effect = REG_EFFECT_NEGA;
+ break;
+ case V4L2_COLORFX_EMBOSS:
+ p_effect = REG_EFFECT_EMBOSS;
+ break;
+ case V4L2_COLORFX_SEPIA:
+ m_effect = REG_COLOR_EFFECT_ON;
+ cfix_r = REG_CFIXR_SEPIA;
+ cfix_b = REG_CFIXB_SEPIA;
+ break;
+ }
+
+ ret = m5mols_write(sd, PARM_EFFECT, p_effect);
if (!ret)
- info->lock_awb = lock;
+ ret = m5mols_write(sd, MON_EFFECT, m_effect);
+
+ if (ret == 0 && m_effect == REG_COLOR_EFFECT_ON) {
+ ret = m5mols_write(sd, MON_CFIXR, cfix_r);
+ if (!ret)
+ ret = m5mols_write(sd, MON_CFIXB, cfix_b);
+ }
+
+ v4l2_dbg(1, m5mols_debug, sd,
+ "p_effect: %#x, m_effect: %#x, r: %#x, b: %#x (%d)\n",
+ p_effect, m_effect, cfix_r, cfix_b, ret);
return ret;
}
-/* m5mols_lock_3a() - Lock 3A(Auto Exposure, Auto Whitebalance, Auto Focus) */
-int m5mols_lock_3a(struct m5mols_info *info, bool lock)
+static int m5mols_set_iso(struct m5mols_info *info, int auto_iso)
+{
+ u32 iso = auto_iso ? 0 : info->iso->val + 1;
+
+ return m5mols_write(&info->sd, AE_ISO, iso);
+}
+
+static int m5mols_set_wdr(struct m5mols_info *info, int wdr)
{
int ret;
- ret = m5mols_lock_ae(info, lock);
- if (!ret)
- ret = m5mols_lock_awb(info, lock);
- /* Don't need to handle unlocking AF */
- if (!ret && is_available_af(info) && lock)
- ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP);
+ ret = m5mols_write(&info->sd, MON_TONE_CTL, wdr ? 9 : 5);
+ if (ret < 0)
+ return ret;
+
+ ret = m5mols_set_mode(info, REG_CAPTURE);
+ if (ret < 0)
+ return ret;
+
+ return m5mols_write(&info->sd, CAPP_WDR_EN, wdr);
+}
+
+static int m5mols_set_stabilization(struct m5mols_info *info, int val)
+{
+ struct v4l2_subdev *sd = &info->sd;
+ unsigned int evp = val ? 0xe : 0x0;
+ int ret;
+
+ ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, evp);
+ if (ret < 0)
+ return ret;
+
+ return m5mols_write(sd, AE_EV_PRESET_CAPTURE, evp);
+}
+
+static int m5mols_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = to_sd(ctrl);
+ struct m5mols_info *info = to_m5mols(sd);
+ int ret = 0;
+ u8 status;
+
+ v4l2_dbg(1, m5mols_debug, sd, "%s: ctrl: %s (%d)\n",
+ __func__, ctrl->name, info->isp_ready);
+
+ if (!info->isp_ready)
+ return -EBUSY;
+
+ switch (ctrl->id) {
+ case V4L2_CID_ISO_SENSITIVITY_AUTO:
+ ret = m5mols_read_u8(sd, AE_ISO, &status);
+ if (ret == 0)
+ ctrl->val = !status;
+ if (status != REG_ISO_AUTO)
+ info->iso->val = status - 1;
+ break;
+
+ case V4L2_CID_3A_LOCK:
+ ctrl->val &= ~0x7;
+
+ ret = m5mols_read_u8(sd, AE_LOCK, &status);
+ if (ret)
+ return ret;
+ if (status)
+ info->lock_3a->val |= V4L2_LOCK_EXPOSURE;
+
+ ret = m5mols_read_u8(sd, AWB_LOCK, &status);
+ if (ret)
+ return ret;
+ if (status)
+ info->lock_3a->val |= V4L2_LOCK_EXPOSURE;
+
+ ret = m5mols_read_u8(sd, AF_EXECUTE, &status);
+ if (!status)
+ info->lock_3a->val |= V4L2_LOCK_EXPOSURE;
+ break;
+ }
return ret;
}
-/* m5mols_set_ctrl() - The main s_ctrl function called by m5mols_set_ctrl() */
-int m5mols_set_ctrl(struct v4l2_ctrl *ctrl)
+static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl)
{
+ unsigned int ctrl_mode = m5mols_get_ctrl_mode(ctrl);
struct v4l2_subdev *sd = to_sd(ctrl);
struct m5mols_info *info = to_m5mols(sd);
- int ret;
+ int last_mode = info->mode;
+ int ret = 0;
+
+ /*
+ * If needed, defer restoring the controls until
+ * the device is fully initialized.
+ */
+ if (!info->isp_ready) {
+ info->ctrl_sync = 0;
+ return 0;
+ }
+
+ v4l2_dbg(1, m5mols_debug, sd, "%s: %s, val: %d, priv: %#x\n",
+ __func__, ctrl->name, ctrl->val, (int)ctrl->priv);
+
+ if (ctrl_mode && ctrl_mode != info->mode) {
+ ret = m5mols_set_mode(info, ctrl_mode);
+ if (ret < 0)
+ return ret;
+ }
switch (ctrl->id) {
+ case V4L2_CID_3A_LOCK:
+ ret = m5mols_3a_lock(info, ctrl);
+ break;
+
case V4L2_CID_ZOOM_ABSOLUTE:
- return m5mols_write(sd, MON_ZOOM, ctrl->val);
+ ret = m5mols_write(sd, MON_ZOOM, ctrl->val);
+ break;
case V4L2_CID_EXPOSURE_AUTO:
- ret = m5mols_lock_ae(info,
- ctrl->val == V4L2_EXPOSURE_AUTO ? false : true);
- if (!ret && ctrl->val == V4L2_EXPOSURE_AUTO)
- ret = m5mols_write(sd, AE_MODE, REG_AE_ALL);
- if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) {
- int val = info->exposure->val;
- ret = m5mols_write(sd, AE_MODE, REG_AE_OFF);
- if (!ret)
- ret = m5mols_write(sd, AE_MAN_GAIN_MON, val);
- if (!ret)
- ret = m5mols_write(sd, AE_MAN_GAIN_CAP, val);
- }
- return ret;
+ ret = m5mols_set_exposure(info, ctrl->val);
+ break;
- case V4L2_CID_AUTO_WHITE_BALANCE:
- ret = m5mols_lock_awb(info, ctrl->val ? false : true);
- if (!ret)
- ret = m5mols_write(sd, AWB_MODE, ctrl->val ?
- REG_AWB_AUTO : REG_AWB_PRESET);
- return ret;
+ case V4L2_CID_ISO_SENSITIVITY:
+ ret = m5mols_set_iso(info, ctrl->val);
+ break;
+
+ case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
+ ret = m5mols_set_white_balance(info, ctrl->val);
+ break;
case V4L2_CID_SATURATION:
- ret = m5mols_write(sd, MON_CHROMA_LVL, ctrl->val);
- if (!ret)
- ret = m5mols_write(sd, MON_CHROMA_EN, REG_CHROMA_ON);
- return ret;
+ ret = m5mols_set_saturation(info, ctrl->val);
+ break;
case V4L2_CID_COLORFX:
- /*
- * This control uses two kinds of registers: normal & color.
- * The normal effect belongs to category 1, while the color
- * one belongs to category 2.
- *
- * The normal effect uses one register: CAT1_EFFECT.
- * The color effect uses three registers:
- * CAT2_COLOR_EFFECT, CAT2_CFIXR, CAT2_CFIXB.
- */
- ret = m5mols_write(sd, PARM_EFFECT,
- ctrl->val == V4L2_COLORFX_NEGATIVE ? REG_EFFECT_NEGA :
- ctrl->val == V4L2_COLORFX_EMBOSS ? REG_EFFECT_EMBOSS :
- REG_EFFECT_OFF);
- if (!ret)
- ret = m5mols_write(sd, MON_EFFECT,
- ctrl->val == V4L2_COLORFX_SEPIA ?
- REG_COLOR_EFFECT_ON : REG_COLOR_EFFECT_OFF);
- if (!ret)
- ret = m5mols_write(sd, MON_CFIXR,
- ctrl->val == V4L2_COLORFX_SEPIA ?
- REG_CFIXR_SEPIA : 0);
- if (!ret)
- ret = m5mols_write(sd, MON_CFIXB,
- ctrl->val == V4L2_COLORFX_SEPIA ?
- REG_CFIXB_SEPIA : 0);
+ ret = m5mols_set_color_effect(info, ctrl->val);
+ break;
+
+ case V4L2_CID_WIDE_DYNAMIC_RANGE:
+ ret = m5mols_set_wdr(info, ctrl->val);
+ break;
+
+ case V4L2_CID_IMAGE_STABILIZATION:
+ ret = m5mols_set_stabilization(info, ctrl->val);
+ break;
+
+ case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+ ret = m5mols_write(sd, CAPP_JPEG_RATIO, ctrl->val);
+ break;
+ }
+
+ if (ret == 0 && info->mode != last_mode)
+ ret = m5mols_set_mode(info, last_mode);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops m5mols_ctrl_ops = {
+ .g_volatile_ctrl = m5mols_g_volatile_ctrl,
+ .s_ctrl = m5mols_s_ctrl,
+};
+
+/* Supported manual ISO values */
+static const s64 iso_qmenu[] = {
+ /* AE_ISO: 0x01...0x07 */
+ 50, 100, 200, 400, 800, 1600, 3200
+};
+
+/* Supported Exposure Bias values, -2.0EV...+2.0EV */
+static const s64 ev_bias_qmenu[] = {
+ /* AE_INDEX: 0x00...0x08 */
+ -2000, -1500, -1000, -500, 0, 500, 1000, 1500, 2000
+};
+
+int m5mols_init_controls(struct v4l2_subdev *sd)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+ u16 exposure_max;
+ u16 zoom_step;
+ int ret;
+
+ /* Determine the firmware dependant control range and step values */
+ ret = m5mols_read_u16(sd, AE_MAX_GAIN_MON, &exposure_max);
+ if (ret < 0)
+ return ret;
+
+ zoom_step = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1;
+ v4l2_ctrl_handler_init(&info->handle, 20);
+
+ info->auto_wb = v4l2_ctrl_new_std_menu(&info->handle,
+ &m5mols_ctrl_ops, V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
+ 9, ~0x3fe, V4L2_WHITE_BALANCE_AUTO);
+
+ /* Exposure control cluster */
+ info->auto_exposure = v4l2_ctrl_new_std_menu(&info->handle,
+ &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
+ 1, ~0x03, V4L2_EXPOSURE_AUTO);
+
+ info->exposure = v4l2_ctrl_new_std(&info->handle,
+ &m5mols_ctrl_ops, V4L2_CID_EXPOSURE,
+ 0, exposure_max, 1, exposure_max / 2);
+
+ info->exposure_bias = v4l2_ctrl_new_int_menu(&info->handle,
+ &m5mols_ctrl_ops, V4L2_CID_AUTO_EXPOSURE_BIAS,
+ ARRAY_SIZE(ev_bias_qmenu) - 1,
+ ARRAY_SIZE(ev_bias_qmenu)/2 - 1,
+ ev_bias_qmenu);
+
+ info->metering = v4l2_ctrl_new_std_menu(&info->handle,
+ &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_METERING,
+ 2, ~0x7, V4L2_EXPOSURE_METERING_AVERAGE);
+
+ /* ISO control cluster */
+ info->auto_iso = v4l2_ctrl_new_std_menu(&info->handle, &m5mols_ctrl_ops,
+ V4L2_CID_ISO_SENSITIVITY_AUTO, 1, ~0x03, 1);
+
+ info->iso = v4l2_ctrl_new_int_menu(&info->handle, &m5mols_ctrl_ops,
+ V4L2_CID_ISO_SENSITIVITY, ARRAY_SIZE(iso_qmenu) - 1,
+ ARRAY_SIZE(iso_qmenu)/2 - 1, iso_qmenu);
+
+ info->saturation = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
+ V4L2_CID_SATURATION, 1, 5, 1, 3);
+
+ info->zoom = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
+ V4L2_CID_ZOOM_ABSOLUTE, 1, 70, zoom_step, 1);
+
+ info->colorfx = v4l2_ctrl_new_std_menu(&info->handle, &m5mols_ctrl_ops,
+ V4L2_CID_COLORFX, 4, 0, V4L2_COLORFX_NONE);
+
+ info->wdr = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
+ V4L2_CID_WIDE_DYNAMIC_RANGE, 0, 1, 1, 0);
+
+ info->stabilization = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
+ V4L2_CID_IMAGE_STABILIZATION, 0, 1, 1, 0);
+
+ info->jpeg_quality = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
+ V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, 100, 1, 80);
+
+ info->lock_3a = v4l2_ctrl_new_std(&info->handle, &m5mols_ctrl_ops,
+ V4L2_CID_3A_LOCK, 0, 0x7, 0, 0);
+
+ if (info->handle.error) {
+ int ret = info->handle.error;
+ v4l2_err(sd, "Failed to initialize controls: %d\n", ret);
+ v4l2_ctrl_handler_free(&info->handle);
return ret;
}
- return -EINVAL;
+ v4l2_ctrl_auto_cluster(4, &info->auto_exposure, 1, false);
+ info->auto_iso->flags |= V4L2_CTRL_FLAG_VOLATILE |
+ V4L2_CTRL_FLAG_UPDATE;
+ v4l2_ctrl_auto_cluster(2, &info->auto_iso, 0, false);
+
+ info->lock_3a->flags |= V4L2_CTRL_FLAG_VOLATILE;
+
+ m5mols_set_ctrl_mode(info->auto_exposure, REG_PARAMETER);
+ m5mols_set_ctrl_mode(info->auto_wb, REG_PARAMETER);
+ m5mols_set_ctrl_mode(info->colorfx, REG_MONITOR);
+
+ sd->ctrl_handler = &info->handle;
+
+ return 0;
}
diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c
index d718aee01c77..ac7d28b6ddf2 100644
--- a/drivers/media/video/m5mols/m5mols_core.c
+++ b/drivers/media/video/m5mols/m5mols_core.c
@@ -362,14 +362,14 @@ static int m5mols_reg_mode(struct v4l2_subdev *sd, u8 mode)
}
/**
- * m5mols_mode - manage the M-5MOLS's mode
+ * m5mols_set_mode - set the M-5MOLS controller mode
* @mode: the required operation mode
*
* The commands of M-5MOLS are grouped into specific modes. Each functionality
- * can be guaranteed only when the sensor is operating in mode which which
- * a command belongs to.
+ * can be guaranteed only when the sensor is operating in mode which a command
+ * belongs to.
*/
-int m5mols_mode(struct m5mols_info *info, u8 mode)
+int m5mols_set_mode(struct m5mols_info *info, u8 mode)
{
struct v4l2_subdev *sd = &info->sd;
int ret = -EINVAL;
@@ -645,13 +645,13 @@ static int m5mols_start_monitor(struct m5mols_info *info)
struct v4l2_subdev *sd = &info->sd;
int ret;
- ret = m5mols_mode(info, REG_PARAMETER);
+ ret = m5mols_set_mode(info, REG_PARAMETER);
if (!ret)
ret = m5mols_write(sd, PARM_MON_SIZE, info->resolution);
if (!ret)
ret = m5mols_write(sd, PARM_MON_FPS, REG_FPS_30);
if (!ret)
- ret = m5mols_mode(info, REG_MONITOR);
+ ret = m5mols_set_mode(info, REG_MONITOR);
if (!ret)
ret = m5mols_restore_controls(info);
@@ -674,42 +674,13 @@ static int m5mols_s_stream(struct v4l2_subdev *sd, int enable)
return ret;
}
- return m5mols_mode(info, REG_PARAMETER);
+ return m5mols_set_mode(info, REG_PARAMETER);
}
static const struct v4l2_subdev_video_ops m5mols_video_ops = {
.s_stream = m5mols_s_stream,
};
-static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct v4l2_subdev *sd = to_sd(ctrl);
- struct m5mols_info *info = to_m5mols(sd);
- int ispstate = info->mode;
- int ret;
-
- /*
- * If needed, defer restoring the controls until
- * the device is fully initialized.
- */
- if (!info->isp_ready) {
- info->ctrl_sync = 0;
- return 0;
- }
-
- ret = m5mols_mode(info, REG_PARAMETER);
- if (ret < 0)
- return ret;
- ret = m5mols_set_ctrl(ctrl);
- if (ret < 0)
- return ret;
- return m5mols_mode(info, ispstate);
-}
-
-static const struct v4l2_ctrl_ops m5mols_ctrl_ops = {
- .s_ctrl = m5mols_s_ctrl,
-};
-
static int m5mols_sensor_power(struct m5mols_info *info, bool enable)
{
struct v4l2_subdev *sd = &info->sd;
@@ -802,52 +773,6 @@ static int m5mols_fw_start(struct v4l2_subdev *sd)
return ret;
}
-static int m5mols_init_controls(struct m5mols_info *info)
-{
- struct v4l2_subdev *sd = &info->sd;
- u16 max_exposure;
- u16 step_zoom;
- int ret;
-
- /* Determine value's range & step of controls for various FW version */
- ret = m5mols_read_u16(sd, AE_MAX_GAIN_MON, &max_exposure);
- if (!ret)
- step_zoom = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1;
- if (ret)
- return ret;
-
- v4l2_ctrl_handler_init(&info->handle, 6);
- info->autowb = v4l2_ctrl_new_std(&info->handle,
- &m5mols_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE,
- 0, 1, 1, 0);
- info->saturation = v4l2_ctrl_new_std(&info->handle,
- &m5mols_ctrl_ops, V4L2_CID_SATURATION,
- 1, 5, 1, 3);
- info->zoom = v4l2_ctrl_new_std(&info->handle,
- &m5mols_ctrl_ops, V4L2_CID_ZOOM_ABSOLUTE,
- 1, 70, step_zoom, 1);
- info->exposure = v4l2_ctrl_new_std(&info->handle,
- &m5mols_ctrl_ops, V4L2_CID_EXPOSURE,
- 0, max_exposure, 1, (int)max_exposure/2);
- info->colorfx = v4l2_ctrl_new_std_menu(&info->handle,
- &m5mols_ctrl_ops, V4L2_CID_COLORFX,
- 4, (1 << V4L2_COLORFX_BW), V4L2_COLORFX_NONE);
- info->autoexposure = v4l2_ctrl_new_std_menu(&info->handle,
- &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
- 1, 0, V4L2_EXPOSURE_AUTO);
-
- sd->ctrl_handler = &info->handle;
- if (info->handle.error) {
- v4l2_err(sd, "Failed to initialize controls: %d\n", ret);
- v4l2_ctrl_handler_free(&info->handle);
- return info->handle.error;
- }
-
- v4l2_ctrl_cluster(2, &info->autoexposure);
-
- return 0;
-}
-
/**
* m5mols_s_power - Main sensor power control function
*
@@ -868,7 +793,7 @@ static int m5mols_s_power(struct v4l2_subdev *sd, int on)
}
if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) {
- ret = m5mols_mode(info, REG_MONITOR);
+ ret = m5mols_set_mode(info, REG_MONITOR);
if (!ret)
ret = m5mols_write(sd, AF_EXECUTE, REG_AF_STOP);
if (!ret)
@@ -1010,7 +935,7 @@ static int __devinit m5mols_probe(struct i2c_client *client,
ret = m5mols_fw_start(sd);
if (!ret)
- ret = m5mols_init_controls(info);
+ ret = m5mols_init_controls(sd);
m5mols_sensor_power(info, false);
if (!ret)
diff --git a/drivers/media/video/m5mols/m5mols_reg.h b/drivers/media/video/m5mols/m5mols_reg.h
index ae4aced0f9b2..14d4be72aeff 100644
--- a/drivers/media/video/m5mols/m5mols_reg.h
+++ b/drivers/media/video/m5mols/m5mols_reg.h
@@ -310,6 +310,7 @@
#define REG_JPEG 0x10
#define CAPP_MAIN_IMAGE_SIZE I2C_REG(CAT_CAPT_PARM, 0x01, 1)
+#define CAPP_JPEG_RATIO I2C_REG(CAT_CAPT_PARM, 0x17, 1)
#define CAPP_MCC_MODE I2C_REG(CAT_CAPT_PARM, 0x1d, 1)
#define REG_MCC_OFF 0x00
diff --git a/drivers/media/video/marvell-ccic/mcam-core.c b/drivers/media/video/marvell-ccic/mcam-core.c
index 996ac34d9a89..ce2b7b4788d6 100644
--- a/drivers/media/video/marvell-ccic/mcam-core.c
+++ b/drivers/media/video/marvell-ccic/mcam-core.c
@@ -1356,7 +1356,6 @@ static int mcam_vidioc_s_fmt_vid_cap(struct file *filp, void *priv,
goto out;
}
mcam_set_config_needed(cam, 1);
- ret = 0;
out:
mutex_unlock(&cam->s_mutex);
return ret;
diff --git a/drivers/media/video/mem2mem_testdev.c b/drivers/media/video/mem2mem_testdev.c
index 12897e8a3314..d2dec585e61b 100644
--- a/drivers/media/video/mem2mem_testdev.c
+++ b/drivers/media/video/mem2mem_testdev.c
@@ -40,7 +40,7 @@ MODULE_VERSION("0.1.1");
#define MIN_H 32
#define MAX_W 640
#define MAX_H 480
-#define DIM_ALIGN_MASK 0x08 /* 8-alignment for dimensions */
+#define DIM_ALIGN_MASK 7 /* 8-byte alignment for line length */
/* Flags that indicate a format can be used for capture/output */
#define MEM2MEM_CAPTURE (1 << 0)
@@ -958,6 +958,10 @@ static int m2mtest_probe(struct platform_device *pdev)
}
*vfd = m2mtest_videodev;
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
vfd->lock = &dev->dev_mutex;
ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index b09a3c80a15e..7bc775219f97 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -1570,7 +1570,7 @@ static long vidioc_default(struct file *file, void *fh, bool valid_prio,
return meyeioc_stilljcapt((int *) arg);
default:
- return -EINVAL;
+ return -ENOTTY;
}
}
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index 82ce50721de3..aeb22be7dcbd 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -597,19 +597,23 @@ static int msp_log_status(struct v4l2_subdev *sd)
return 0;
}
-static int msp_suspend(struct i2c_client *client, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int msp_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
v4l_dbg(1, msp_debug, client, "suspend\n");
msp_reset(client);
return 0;
}
-static int msp_resume(struct i2c_client *client)
+static int msp_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
v4l_dbg(1, msp_debug, client, "resume\n");
msp_wake_thread(client);
return 0;
}
+#endif
/* ----------------------------------------------------------------------- */
@@ -863,6 +867,10 @@ static int msp_remove(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+static const struct dev_pm_ops msp3400_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(msp_suspend, msp_resume)
+};
+
static const struct i2c_device_id msp_id[] = {
{ "msp3400", 0 },
{ }
@@ -873,11 +881,10 @@ static struct i2c_driver msp_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "msp3400",
+ .pm = &msp3400_pm_ops,
},
.probe = msp_probe,
.remove = msp_remove,
- .suspend = msp_suspend,
- .resume = msp_resume,
.id_table = msp_id,
};
diff --git a/drivers/media/video/mt9m032.c b/drivers/media/video/mt9m032.c
index 645973c5feb0..3c1e626139b7 100644
--- a/drivers/media/video/mt9m032.c
+++ b/drivers/media/video/mt9m032.c
@@ -838,9 +838,9 @@ static int mt9m032_remove(struct i2c_client *client)
struct v4l2_subdev *subdev = i2c_get_clientdata(client);
struct mt9m032 *sensor = to_mt9m032(subdev);
- v4l2_device_unregister_subdev(&sensor->subdev);
+ v4l2_device_unregister_subdev(subdev);
v4l2_ctrl_handler_free(&sensor->ctrls);
- media_entity_cleanup(&sensor->subdev.entity);
+ media_entity_cleanup(&subdev->entity);
mutex_destroy(&sensor->lock);
kfree(sensor);
return 0;
diff --git a/drivers/media/video/mt9p031.c b/drivers/media/video/mt9p031.c
index c81eaf4fbe01..8f061d9ac443 100644
--- a/drivers/media/video/mt9p031.c
+++ b/drivers/media/video/mt9p031.c
@@ -14,6 +14,7 @@
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/log2.h>
@@ -90,7 +91,14 @@
#define MT9P031_GLOBAL_GAIN_MAX 1024
#define MT9P031_GLOBAL_GAIN_DEF 8
#define MT9P031_GLOBAL_GAIN_MULT (1 << 6)
+#define MT9P031_ROW_BLACK_TARGET 0x49
#define MT9P031_ROW_BLACK_DEF_OFFSET 0x4b
+#define MT9P031_GREEN1_OFFSET 0x60
+#define MT9P031_GREEN2_OFFSET 0x61
+#define MT9P031_BLACK_LEVEL_CALIBRATION 0x62
+#define MT9P031_BLC_MANUAL_BLC (1 << 0)
+#define MT9P031_RED_OFFSET 0x63
+#define MT9P031_BLUE_OFFSET 0x64
#define MT9P031_TEST_PATTERN 0xa0
#define MT9P031_TEST_PATTERN_SHIFT 3
#define MT9P031_TEST_PATTERN_ENABLE (1 << 0)
@@ -99,17 +107,27 @@
#define MT9P031_TEST_PATTERN_RED 0xa2
#define MT9P031_TEST_PATTERN_BLUE 0xa3
+enum mt9p031_model {
+ MT9P031_MODEL_COLOR,
+ MT9P031_MODEL_MONOCHROME,
+};
+
struct mt9p031 {
struct v4l2_subdev subdev;
struct media_pad pad;
struct v4l2_rect crop; /* Sensor window */
struct v4l2_mbus_framefmt format;
- struct v4l2_ctrl_handler ctrls;
struct mt9p031_platform_data *pdata;
struct mutex power_lock; /* lock to protect power_count */
int power_count;
+ enum mt9p031_model model;
struct aptina_pll pll;
+ int reset;
+
+ struct v4l2_ctrl_handler ctrls;
+ struct v4l2_ctrl *blc_auto;
+ struct v4l2_ctrl *blc_offset;
/* Registers cache */
u16 output_control;
@@ -241,8 +259,8 @@ static inline int mt9p031_pll_disable(struct mt9p031 *mt9p031)
static int mt9p031_power_on(struct mt9p031 *mt9p031)
{
/* Ensure RESET_BAR is low */
- if (mt9p031->pdata->reset) {
- mt9p031->pdata->reset(&mt9p031->subdev, 1);
+ if (mt9p031->reset != -1) {
+ gpio_set_value(mt9p031->reset, 0);
usleep_range(1000, 2000);
}
@@ -252,8 +270,8 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031)
mt9p031->pdata->ext_freq);
/* Now RESET_BAR must be high */
- if (mt9p031->pdata->reset) {
- mt9p031->pdata->reset(&mt9p031->subdev, 0);
+ if (mt9p031->reset != -1) {
+ gpio_set_value(mt9p031->reset, 1);
usleep_range(1000, 2000);
}
@@ -262,8 +280,8 @@ static int mt9p031_power_on(struct mt9p031 *mt9p031)
static void mt9p031_power_off(struct mt9p031 *mt9p031)
{
- if (mt9p031->pdata->reset) {
- mt9p031->pdata->reset(&mt9p031->subdev, 1);
+ if (mt9p031->reset != -1) {
+ gpio_set_value(mt9p031->reset, 0);
usleep_range(1000, 2000);
}
@@ -557,6 +575,10 @@ static int mt9p031_set_crop(struct v4l2_subdev *subdev,
*/
#define V4L2_CID_TEST_PATTERN (V4L2_CID_USER_BASE | 0x1001)
+#define V4L2_CID_BLC_AUTO (V4L2_CID_USER_BASE | 0x1002)
+#define V4L2_CID_BLC_TARGET_LEVEL (V4L2_CID_USER_BASE | 0x1003)
+#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_s_ctrl(struct v4l2_ctrl *ctrl)
{
@@ -621,11 +643,17 @@ static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_TEST_PATTERN:
if (!ctrl->val) {
- ret = mt9p031_set_mode2(mt9p031,
- 0, MT9P031_READ_MODE_2_ROW_BLC);
- if (ret < 0)
- return ret;
-
+ /* 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;
+ }
return mt9p031_write(client, MT9P031_TEST_PATTERN,
MT9P031_TEST_PATTERN_DISABLE);
}
@@ -640,10 +668,14 @@ static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
if (ret < 0)
return ret;
+ /* Disable digital black level compensation when using a test
+ * pattern.
+ */
ret = mt9p031_set_mode2(mt9p031, MT9P031_READ_MODE_2_ROW_BLC,
0);
if (ret < 0)
return ret;
+
ret = mt9p031_write(client, MT9P031_ROW_BLACK_DEF_OFFSET, 0);
if (ret < 0)
return ret;
@@ -651,7 +683,40 @@ static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
return mt9p031_write(client, MT9P031_TEST_PATTERN,
((ctrl->val - 1) << MT9P031_TEST_PATTERN_SHIFT)
| MT9P031_TEST_PATTERN_ENABLE);
+
+ case V4L2_CID_BLC_AUTO:
+ ret = mt9p031_set_mode2(mt9p031,
+ ctrl->val ? 0 : MT9P031_READ_MODE_2_ROW_BLC,
+ ctrl->val ? MT9P031_READ_MODE_2_ROW_BLC : 0);
+ if (ret < 0)
+ return ret;
+
+ return mt9p031_write(client, MT9P031_BLACK_LEVEL_CALIBRATION,
+ ctrl->val ? 0 : MT9P031_BLC_MANUAL_BLC);
+
+ case V4L2_CID_BLC_TARGET_LEVEL:
+ return mt9p031_write(client, MT9P031_ROW_BLACK_TARGET,
+ ctrl->val);
+
+ case V4L2_CID_BLC_ANALOG_OFFSET:
+ data = ctrl->val & ((1 << 9) - 1);
+
+ ret = mt9p031_write(client, MT9P031_GREEN1_OFFSET, data);
+ if (ret < 0)
+ return ret;
+ ret = mt9p031_write(client, MT9P031_GREEN2_OFFSET, data);
+ if (ret < 0)
+ return ret;
+ ret = mt9p031_write(client, MT9P031_RED_OFFSET, data);
+ if (ret < 0)
+ return ret;
+ return mt9p031_write(client, MT9P031_BLUE_OFFSET, data);
+
+ case V4L2_CID_BLC_DIGITAL_OFFSET:
+ return mt9p031_write(client, MT9P031_ROW_BLACK_DEF_OFFSET,
+ ctrl->val & ((1 << 12) - 1));
}
+
return 0;
}
@@ -685,6 +750,46 @@ static const struct v4l2_ctrl_config mt9p031_ctrls[] = {
.flags = 0,
.menu_skip_mask = 0,
.qmenu = mt9p031_test_pattern_menu,
+ }, {
+ .ops = &mt9p031_ctrl_ops,
+ .id = V4L2_CID_BLC_AUTO,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "BLC, Auto",
+ .min = 0,
+ .max = 1,
+ .step = 1,
+ .def = 1,
+ .flags = 0,
+ }, {
+ .ops = &mt9p031_ctrl_ops,
+ .id = V4L2_CID_BLC_TARGET_LEVEL,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "BLC Target Level",
+ .min = 0,
+ .max = 4095,
+ .step = 1,
+ .def = 168,
+ .flags = 0,
+ }, {
+ .ops = &mt9p031_ctrl_ops,
+ .id = V4L2_CID_BLC_ANALOG_OFFSET,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "BLC Analog Offset",
+ .min = -255,
+ .max = 255,
+ .step = 1,
+ .def = 32,
+ .flags = 0,
+ }, {
+ .ops = &mt9p031_ctrl_ops,
+ .id = V4L2_CID_BLC_DIGITAL_OFFSET,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "BLC Digital Offset",
+ .min = -2048,
+ .max = 2047,
+ .step = 1,
+ .def = 40,
+ .flags = 0,
}
};
@@ -764,7 +869,7 @@ static int mt9p031_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
format = v4l2_subdev_get_try_format(fh, 0);
- if (mt9p031->pdata->version == MT9P031_MONOCHROME_VERSION)
+ if (mt9p031->model == MT9P031_MODEL_MONOCHROME)
format->code = V4L2_MBUS_FMT_Y12_1X12;
else
format->code = V4L2_MBUS_FMT_SGRBG12_1X12;
@@ -842,6 +947,8 @@ static int mt9p031_probe(struct i2c_client *client,
mt9p031->pdata = pdata;
mt9p031->output_control = MT9P031_OUTPUT_CONTROL_DEF;
mt9p031->mode2 = MT9P031_READ_MODE_2_ROW_BLC;
+ mt9p031->model = did->driver_data;
+ mt9p031->reset = -1;
v4l2_ctrl_handler_init(&mt9p031->ctrls, ARRAY_SIZE(mt9p031_ctrls) + 4);
@@ -862,9 +969,16 @@ static int mt9p031_probe(struct i2c_client *client,
mt9p031->subdev.ctrl_handler = &mt9p031->ctrls;
- if (mt9p031->ctrls.error)
+ if (mt9p031->ctrls.error) {
printk(KERN_INFO "%s: control initialization error %d\n",
__func__, mt9p031->ctrls.error);
+ ret = mt9p031->ctrls.error;
+ goto done;
+ }
+
+ mt9p031->blc_auto = v4l2_ctrl_find(&mt9p031->ctrls, V4L2_CID_BLC_AUTO);
+ mt9p031->blc_offset = v4l2_ctrl_find(&mt9p031->ctrls,
+ V4L2_CID_BLC_DIGITAL_OFFSET);
mutex_init(&mt9p031->power_lock);
v4l2_i2c_subdev_init(&mt9p031->subdev, client, &mt9p031_subdev_ops);
@@ -882,7 +996,7 @@ static int mt9p031_probe(struct i2c_client *client,
mt9p031->crop.left = MT9P031_COLUMN_START_DEF;
mt9p031->crop.top = MT9P031_ROW_START_DEF;
- if (mt9p031->pdata->version == MT9P031_MONOCHROME_VERSION)
+ if (mt9p031->model == MT9P031_MODEL_MONOCHROME)
mt9p031->format.code = V4L2_MBUS_FMT_Y12_1X12;
else
mt9p031->format.code = V4L2_MBUS_FMT_SGRBG12_1X12;
@@ -892,10 +1006,22 @@ static int mt9p031_probe(struct i2c_client *client,
mt9p031->format.field = V4L2_FIELD_NONE;
mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB;
+ if (pdata->reset != -1) {
+ ret = gpio_request_one(pdata->reset, GPIOF_OUT_INIT_LOW,
+ "mt9p031_rst");
+ if (ret < 0)
+ goto done;
+
+ mt9p031->reset = pdata->reset;
+ }
+
ret = mt9p031_pll_setup(mt9p031);
done:
if (ret < 0) {
+ if (mt9p031->reset != -1)
+ gpio_free(mt9p031->reset);
+
v4l2_ctrl_handler_free(&mt9p031->ctrls);
media_entity_cleanup(&mt9p031->subdev.entity);
kfree(mt9p031);
@@ -912,13 +1038,16 @@ static int mt9p031_remove(struct i2c_client *client)
v4l2_ctrl_handler_free(&mt9p031->ctrls);
v4l2_device_unregister_subdev(subdev);
media_entity_cleanup(&subdev->entity);
+ if (mt9p031->reset != -1)
+ gpio_free(mt9p031->reset);
kfree(mt9p031);
return 0;
}
static const struct i2c_device_id mt9p031_id[] = {
- { "mt9p031", 0 },
+ { "mt9p031", MT9P031_MODEL_COLOR },
+ { "mt9p031m", MT9P031_MODEL_MONOCHROME },
{ }
};
MODULE_DEVICE_TABLE(i2c, mt9p031_id);
diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c
index 8d1445f12708..e1ae46a7ee96 100644
--- a/drivers/media/video/mt9t112.c
+++ b/drivers/media/video/mt9t112.c
@@ -453,6 +453,7 @@ static int mt9t112_init_pll(const struct i2c_client *client)
* I2C Master Clock Divider
*/
mt9t112_reg_write(ret, client, 0x0014, 0x3046);
+ mt9t112_reg_write(ret, client, 0x0016, 0x0400); /* JPEG initialization workaround */
mt9t112_reg_write(ret, client, 0x0022, 0x0190);
mt9t112_reg_write(ret, client, 0x3B84, 0x0212);
diff --git a/drivers/media/video/mt9v032.c b/drivers/media/video/mt9v032.c
index 75e253a343c5..4ba4884c016e 100644
--- a/drivers/media/video/mt9v032.c
+++ b/drivers/media/video/mt9v032.c
@@ -481,7 +481,7 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_EXPOSURE_AUTO:
return mt9v032_update_aec_agc(mt9v032, MT9V032_AEC_ENABLE,
- ctrl->val);
+ !ctrl->val);
case V4L2_CID_EXPOSURE:
return mt9v032_write(client, MT9V032_TOTAL_SHUTTER_WIDTH,
diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c
index 055d11ddb038..4296a8350298 100644
--- a/drivers/media/video/mx1_camera.c
+++ b/drivers/media/video/mx1_camera.c
@@ -126,13 +126,8 @@ static int mx1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
unsigned int *size)
{
struct soc_camera_device *icd = vq->priv_data;
- int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
- icd->current_fmt->host_fmt);
- if (bytes_per_line < 0)
- return bytes_per_line;
-
- *size = bytes_per_line * icd->user_height;
+ *size = icd->sizeimage;
if (!*count)
*count = 32;
@@ -171,11 +166,6 @@ static int mx1_videobuf_prepare(struct videobuf_queue *vq,
struct soc_camera_device *icd = vq->priv_data;
struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb);
int ret;
- int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
- icd->current_fmt->host_fmt);
-
- if (bytes_per_line < 0)
- return bytes_per_line;
dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
@@ -202,7 +192,7 @@ static int mx1_videobuf_prepare(struct videobuf_queue *vq,
vb->state = VIDEOBUF_NEEDS_INIT;
}
- vb->size = bytes_per_line * vb->height;
+ vb->size = icd->sizeimage;
if (0 != vb->baddr && vb->bsize < vb->size) {
ret = -EINVAL;
goto out;
diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c
index 18afaeeadb7b..ded26b7286fa 100644
--- a/drivers/media/video/mx2_camera.c
+++ b/drivers/media/video/mx2_camera.c
@@ -22,6 +22,7 @@
#include <linux/gcd.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
+#include <linux/math64.h>
#include <linux/mm.h>
#include <linux/moduleparam.h>
#include <linux/time.h>
@@ -344,6 +345,19 @@ static struct mx2_fmt_cfg mx27_emma_prp_table[] = {
PRP_INTR_CH2OVF,
}
},
+ {
+ .in_fmt = V4L2_MBUS_FMT_UYVY8_2X8,
+ .out_fmt = V4L2_PIX_FMT_YUV420,
+ .cfg = {
+ .channel = 2,
+ .in_fmt = PRP_CNTL_DATA_IN_YUV422,
+ .out_fmt = PRP_CNTL_CH2_OUT_YUV420,
+ .src_pixel = 0x22000888, /* YUV422 (YUYV) */
+ .irq_flags = PRP_INTR_RDERR | PRP_INTR_CH2WERR |
+ PRP_INTR_CH2FC | PRP_INTR_LBOVF |
+ PRP_INTR_CH2OVF,
+ }
+ },
};
static struct mx2_fmt_cfg *mx27_emma_prp_get_format(
@@ -525,8 +539,6 @@ static int mx2_videobuf_setup(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);
struct mx2_camera_dev *pcdev = ici->priv;
- int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
- icd->current_fmt->host_fmt);
dev_dbg(icd->parent, "count=%d, size=%d\n", *count, sizes[0]);
@@ -534,12 +546,9 @@ static int mx2_videobuf_setup(struct vb2_queue *vq,
if (fmt != NULL)
return -ENOTTY;
- if (bytes_per_line < 0)
- return bytes_per_line;
-
alloc_ctxs[0] = pcdev->alloc_ctx;
- sizes[0] = bytes_per_line * icd->user_height;
+ sizes[0] = icd->sizeimage;
if (0 == *count)
*count = 32;
@@ -555,16 +564,11 @@ static int mx2_videobuf_setup(struct vb2_queue *vq,
static int mx2_videobuf_prepare(struct vb2_buffer *vb)
{
struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
- int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
- icd->current_fmt->host_fmt);
int ret = 0;
dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
- if (bytes_per_line < 0)
- return bytes_per_line;
-
#ifdef DEBUG
/*
* This can be useful if you want to see if we actually fill
@@ -574,7 +578,7 @@ static int mx2_videobuf_prepare(struct vb2_buffer *vb)
0xaa, vb2_get_plane_payload(vb, 0));
#endif
- vb2_set_plane_payload(vb, 0, bytes_per_line * icd->user_height);
+ vb2_set_plane_payload(vb, 0, icd->sizeimage);
if (vb2_plane_vaddr(vb, 0) &&
vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
ret = -EINVAL;
@@ -980,6 +984,7 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd)
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct mx2_camera_dev *pcdev = ici->priv;
struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
+ const struct soc_camera_format_xlate *xlate;
unsigned long common_flags;
int ret;
int bytesperline;
@@ -1024,14 +1029,31 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd)
return ret;
}
+ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+ if (!xlate) {
+ dev_warn(icd->parent, "Format %x not found\n", pixfmt);
+ return -EINVAL;
+ }
+
+ if (xlate->code == V4L2_MBUS_FMT_YUYV8_2X8) {
+ csicr1 |= CSICR1_PACK_DIR;
+ csicr1 &= ~CSICR1_SWAP16_EN;
+ dev_dbg(icd->parent, "already yuyv format, don't convert\n");
+ } else if (xlate->code == V4L2_MBUS_FMT_UYVY8_2X8) {
+ csicr1 &= ~CSICR1_PACK_DIR;
+ csicr1 |= CSICR1_SWAP16_EN;
+ dev_dbg(icd->parent, "convert uyvy mbus format into yuyv\n");
+ } else {
+ dev_warn(icd->parent, "mbus format not supported\n");
+ return -EINVAL;
+ }
+
if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
csicr1 |= CSICR1_REDGE;
if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
csicr1 |= CSICR1_SOF_POL;
if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
csicr1 |= CSICR1_HSYNC_POL;
- if (pcdev->platform_flags & MX2_CAMERA_SWAP16)
- csicr1 |= CSICR1_SWAP16_EN;
if (pcdev->platform_flags & MX2_CAMERA_EXT_VSYNC)
csicr1 |= CSICR1_EXT_VSYNC;
if (pcdev->platform_flags & MX2_CAMERA_CCIR)
@@ -1042,8 +1064,6 @@ static int mx2_camera_set_bus_param(struct soc_camera_device *icd)
csicr1 |= CSICR1_GCLK_MODE;
if (pcdev->platform_flags & MX2_CAMERA_INV_DATA)
csicr1 |= CSICR1_INV_DATA;
- if (pcdev->platform_flags & MX2_CAMERA_PACK_DIR_MSB)
- csicr1 |= CSICR1_PACK_DIR;
pcdev->csicr1 = csicr1;
@@ -1118,7 +1138,8 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd,
return 0;
}
- if (code == V4L2_MBUS_FMT_YUYV8_2X8) {
+ if (code == V4L2_MBUS_FMT_YUYV8_2X8 ||
+ code == V4L2_MBUS_FMT_UYVY8_2X8) {
formats++;
if (xlate) {
/*
@@ -1134,6 +1155,18 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd,
}
}
+ if (code == V4L2_MBUS_FMT_UYVY8_2X8) {
+ formats++;
+ if (xlate) {
+ xlate->host_fmt =
+ soc_mbus_get_fmtdesc(V4L2_MBUS_FMT_YUYV8_2X8);
+ xlate->code = code;
+ dev_dbg(dev, "Providing host format %s for sensor code %d\n",
+ xlate->host_fmt->name, code);
+ xlate++;
+ }
+ }
+
/* Generic pass-trough */
formats++;
if (xlate) {
@@ -1363,17 +1396,20 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd,
xlate->host_fmt);
if (pix->bytesperline < 0)
return pix->bytesperline;
- pix->sizeimage = pix->height * pix->bytesperline;
+ pix->sizeimage = soc_mbus_image_size(xlate->host_fmt,
+ pix->bytesperline, pix->height);
/* Check against the CSIRXCNT limit */
if (pix->sizeimage > 4 * 0x3ffff) {
/* Adjust geometry, preserve aspect ratio */
- unsigned int new_height = int_sqrt(4 * 0x3ffff *
- pix->height / pix->bytesperline);
+ unsigned int new_height = int_sqrt(div_u64(0x3ffffULL *
+ 4 * pix->height, pix->bytesperline));
pix->width = new_height * pix->width / pix->height;
pix->height = new_height;
pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
xlate->host_fmt);
BUG_ON(pix->bytesperline < 0);
+ pix->sizeimage = soc_mbus_image_size(xlate->host_fmt,
+ pix->bytesperline, pix->height);
}
}
@@ -1752,6 +1788,8 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
pcdev->soc_host.priv = pcdev;
pcdev->soc_host.v4l2_dev.dev = &pdev->dev;
pcdev->soc_host.nr = pdev->id;
+ if (cpu_is_mx25())
+ pcdev->soc_host.capabilities = SOCAM_HOST_CAP_STRIDE;
pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
if (IS_ERR(pcdev->alloc_ctx)) {
diff --git a/drivers/media/video/mx2_emmaprp.c b/drivers/media/video/mx2_emmaprp.c
index ba89a7401c8c..0bd5815de369 100644
--- a/drivers/media/video/mx2_emmaprp.c
+++ b/drivers/media/video/mx2_emmaprp.c
@@ -755,7 +755,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;
- src_vq->io_modes = VB2_MMAP;
+ src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
src_vq->drv_priv = ctx;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &emmaprp_qops;
@@ -767,7 +767,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;
- dst_vq->io_modes = VB2_MMAP;
+ dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
dst_vq->drv_priv = ctx;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &emmaprp_qops;
@@ -904,6 +904,10 @@ static int emmaprp_probe(struct platform_device *pdev)
}
*vfd = emmaprp_videodev;
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
vfd->lock = &pcdev->dev_mutex;
video_set_drvdata(vfd, pcdev);
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c
index 93c35ef5f0ad..02d54a057b60 100644
--- a/drivers/media/video/mx3_camera.c
+++ b/drivers/media/video/mx3_camera.c
@@ -199,8 +199,6 @@ static int mx3_videobuf_setup(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);
struct mx3_camera_dev *mx3_cam = ici->priv;
- int bytes_per_line;
- unsigned int height;
if (!mx3_cam->idmac_channel[0])
return -EINVAL;
@@ -208,21 +206,29 @@ static int mx3_videobuf_setup(struct vb2_queue *vq,
if (fmt) {
const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd,
fmt->fmt.pix.pixelformat);
+ unsigned int bytes_per_line;
+ int ret;
+
if (!xlate)
return -EINVAL;
- bytes_per_line = soc_mbus_bytes_per_line(fmt->fmt.pix.width,
- xlate->host_fmt);
- height = fmt->fmt.pix.height;
+
+ ret = soc_mbus_bytes_per_line(fmt->fmt.pix.width,
+ xlate->host_fmt);
+ if (ret < 0)
+ return ret;
+
+ bytes_per_line = max_t(u32, fmt->fmt.pix.bytesperline, ret);
+
+ ret = soc_mbus_image_size(xlate->host_fmt, bytes_per_line,
+ fmt->fmt.pix.height);
+ if (ret < 0)
+ return ret;
+
+ sizes[0] = max_t(u32, fmt->fmt.pix.sizeimage, ret);
} else {
/* Called from VIDIOC_REQBUFS or in compatibility mode */
- bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
- icd->current_fmt->host_fmt);
- height = icd->user_height;
+ sizes[0] = icd->sizeimage;
}
- if (bytes_per_line < 0)
- return bytes_per_line;
-
- sizes[0] = bytes_per_line * height;
alloc_ctxs[0] = mx3_cam->alloc_ctx;
@@ -267,14 +273,11 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb)
struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
struct idmac_video_param *video = &ichan->params.video;
const struct soc_mbus_pixelfmt *host_fmt = icd->current_fmt->host_fmt;
- int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width, host_fmt);
unsigned long flags;
dma_cookie_t cookie;
size_t new_size;
- BUG_ON(bytes_per_line <= 0);
-
- new_size = bytes_per_line * icd->user_height;
+ new_size = icd->sizeimage;
if (vb2_plane_size(vb, 0) < new_size) {
dev_err(icd->parent, "Buffer #%d too small (%lu < %zu)\n",
@@ -314,9 +317,9 @@ static void mx3_videobuf_queue(struct vb2_buffer *vb)
* horizontal parameters in this case are expressed in bytes,
* not in pixels.
*/
- video->out_width = bytes_per_line;
+ video->out_width = icd->bytesperline;
video->out_height = icd->user_height;
- video->out_stride = bytes_per_line;
+ video->out_stride = icd->bytesperline;
} else {
/*
* For IPU known formats the pixel unit will be managed
@@ -642,12 +645,14 @@ static const struct soc_mbus_pixelfmt mx3_camera_formats[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_NONE,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
}, {
.fourcc = V4L2_PIX_FMT_GREY,
.name = "Monochrome 8 bit",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_NONE,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
};
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index 2e4131748438..b520a45cb3f3 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -31,10 +31,11 @@
#include <media/saa7115.h>
#include <linux/module.h>
-#include "mxb.h"
#include "tea6415c.h"
#include "tea6420.h"
+#define MXB_AUDIOS 6
+
#define I2C_SAA7111A 0x24
#define I2C_TDA9840 0x42
#define I2C_TEA6415C 0x43
@@ -62,10 +63,14 @@ MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
enum { TUNER, AUX1, AUX3, AUX3_YC };
static struct v4l2_input mxb_inputs[MXB_INPUTS] = {
- { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
- { AUX1, "AUX1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
- { AUX3, "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
- { AUX3_YC, "AUX3 S-Video", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 0x3f, 0,
+ V4L2_STD_PAL_BG | V4L2_STD_PAL_I, 0, V4L2_IN_CAP_STD },
+ { AUX1, "AUX1", V4L2_INPUT_TYPE_CAMERA, 0x3f, 0,
+ V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+ { AUX3, "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 0x3f, 0,
+ V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
+ { AUX3_YC, "AUX3 S-Video", V4L2_INPUT_TYPE_CAMERA, 0x3f, 0,
+ V4L2_STD_ALL, 0, V4L2_IN_CAP_STD },
};
/* this array holds the information, which port of the saa7146 each
@@ -90,6 +95,36 @@ struct mxb_routing {
u32 output;
};
+/* these are the available audio sources, which can switched
+ to the line- and cd-output individually */
+static struct v4l2_audio mxb_audios[MXB_AUDIOS] = {
+ {
+ .index = 0,
+ .name = "Tuner",
+ .capability = V4L2_AUDCAP_STEREO,
+ } , {
+ .index = 1,
+ .name = "AUX1",
+ .capability = V4L2_AUDCAP_STEREO,
+ } , {
+ .index = 2,
+ .name = "AUX2",
+ .capability = V4L2_AUDCAP_STEREO,
+ } , {
+ .index = 3,
+ .name = "AUX3",
+ .capability = V4L2_AUDCAP_STEREO,
+ } , {
+ .index = 4,
+ .name = "Radio (X9)",
+ .capability = V4L2_AUDCAP_STEREO,
+ } , {
+ .index = 5,
+ .name = "CD-ROM (X10)",
+ .capability = V4L2_AUDCAP_STEREO,
+ }
+};
+
/* These are the necessary input-output-pins for bringing one audio source
(see above) to the CD-output. Note that gain is set to 0 in this table. */
static struct mxb_routing TEA6420_cd[MXB_AUDIOS + 1][2] = {
@@ -114,11 +149,6 @@ static struct mxb_routing TEA6420_line[MXB_AUDIOS + 1][2] = {
{ { 6, 3 }, { 6, 2 } } /* Mute */
};
-#define MAXCONTROLS 1
-static struct v4l2_queryctrl mxb_controls[] = {
- { V4L2_CID_AUDIO_MUTE, V4L2_CTRL_TYPE_BOOLEAN, "Mute", 0, 1, 1, 0, 0 },
-};
-
struct mxb
{
struct video_device *video_dev;
@@ -135,6 +165,7 @@ struct mxb
int cur_mode; /* current audio mode (mono, stereo, ...) */
int cur_input; /* current input */
+ int cur_audinput; /* current audio input */
int cur_mute; /* current mute status */
struct v4l2_frequency cur_freq; /* current frequency the tuner is tuned to */
};
@@ -150,16 +181,21 @@ struct mxb
#define call_all(dev, o, f, args...) \
v4l2_device_call_until_err(&dev->v4l2_dev, 0, o, f, ##args)
-static inline void tea6420_route_cd(struct mxb *mxb, int idx)
+static void mxb_update_audmode(struct mxb *mxb)
+{
+ struct v4l2_tuner t = {
+ .audmode = mxb->cur_mode,
+ };
+
+ tda9840_call(mxb, tuner, s_tuner, &t);
+}
+
+static inline void tea6420_route(struct mxb *mxb, int idx)
{
v4l2_subdev_call(mxb->tea6420_1, audio, s_routing,
TEA6420_cd[idx][0].input, TEA6420_cd[idx][0].output, 0);
v4l2_subdev_call(mxb->tea6420_2, audio, s_routing,
TEA6420_cd[idx][1].input, TEA6420_cd[idx][1].output, 0);
-}
-
-static inline void tea6420_route_line(struct mxb *mxb, int idx)
-{
v4l2_subdev_call(mxb->tea6420_1, audio, s_routing,
TEA6420_line[idx][0].input, TEA6420_line[idx][0].output, 0);
v4l2_subdev_call(mxb->tea6420_2, audio, s_routing,
@@ -168,16 +204,45 @@ static inline void tea6420_route_line(struct mxb *mxb, int idx)
static struct saa7146_extension extension;
+static int mxb_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct saa7146_dev *dev = container_of(ctrl->handler,
+ struct saa7146_dev, ctrl_handler);
+ struct mxb *mxb = dev->ext_priv;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ mxb->cur_mute = ctrl->val;
+ /* switch the audio-source */
+ tea6420_route(mxb, ctrl->val ? 6 :
+ video_audio_connect[mxb->cur_input]);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops mxb_ctrl_ops = {
+ .s_ctrl = mxb_s_ctrl,
+};
+
static int mxb_probe(struct saa7146_dev *dev)
{
+ struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
struct mxb *mxb = NULL;
+ v4l2_ctrl_new_std(hdl, &mxb_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+ if (hdl->error)
+ return hdl->error;
mxb = kzalloc(sizeof(struct mxb), GFP_KERNEL);
if (mxb == NULL) {
DEB_D("not enough kernel memory\n");
return -ENOMEM;
}
+
snprintf(mxb->i2c_adapter.name, sizeof(mxb->i2c_adapter.name), "mxb%d", mxb_num);
saa7146_i2c_adapter_prepare(dev, &mxb->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
@@ -214,6 +279,8 @@ static int mxb_probe(struct saa7146_dev *dev)
/* we store the pointer in our private data field */
dev->ext_priv = mxb;
+ v4l2_ctrl_handler_setup(hdl);
+
return 0;
}
@@ -286,6 +353,9 @@ static int mxb_init_done(struct saa7146_dev* dev)
int i = 0, err = 0;
+ /* mute audio on tea6420s */
+ tea6420_route(mxb, 6);
+
/* select video mode in saa7111a */
saa7111a_call(mxb, core, s_std, std);
@@ -306,12 +376,12 @@ static int mxb_init_done(struct saa7146_dev* dev)
tuner_call(mxb, tuner, s_frequency, &mxb->cur_freq);
/* set a default video standard */
+ /* 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);
- /* mute audio on tea6420s */
- tea6420_route_line(mxb, 6);
- tea6420_route_cd(mxb, 6);
-
/* switch to tuner-channel on tea6415c */
tea6415c_call(mxb, video, s_routing, 3, 17, 0);
@@ -320,9 +390,11 @@ static int mxb_init_done(struct saa7146_dev* dev)
/* the rest for mxb */
mxb->cur_input = 0;
+ mxb->cur_audinput = video_audio_connect[mxb->cur_input];
mxb->cur_mute = 1;
mxb->cur_mode = V4L2_TUNER_MODE_STEREO;
+ mxb_update_audmode(mxb);
/* check if the saa7740 (aka 'sound arena module') is present
on the mxb. if so, we must initialize it. due to lack of
@@ -385,69 +457,6 @@ void mxb_irq_bh(struct saa7146_dev* dev, u32* irq_mask)
}
*/
-static int vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qc)
-{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
- int i;
-
- for (i = MAXCONTROLS - 1; i >= 0; i--) {
- if (mxb_controls[i].id == qc->id) {
- *qc = mxb_controls[i];
- DEB_D("VIDIOC_QUERYCTRL %d\n", qc->id);
- return 0;
- }
- }
- return dev->ext_vv_data->core_ops->vidioc_queryctrl(file, fh, qc);
-}
-
-static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
-{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
- struct mxb *mxb = (struct mxb *)dev->ext_priv;
- int i;
-
- for (i = MAXCONTROLS - 1; i >= 0; i--) {
- if (mxb_controls[i].id == vc->id)
- break;
- }
-
- if (i < 0)
- return dev->ext_vv_data->core_ops->vidioc_g_ctrl(file, fh, vc);
-
- if (vc->id == V4L2_CID_AUDIO_MUTE) {
- vc->value = mxb->cur_mute;
- DEB_D("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d\n", vc->value);
- return 0;
- }
-
- DEB_EE("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d\n", vc->value);
- return 0;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *vc)
-{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
- struct mxb *mxb = (struct mxb *)dev->ext_priv;
- int i = 0;
-
- for (i = MAXCONTROLS - 1; i >= 0; i--) {
- if (mxb_controls[i].id == vc->id)
- break;
- }
-
- if (i < 0)
- return dev->ext_vv_data->core_ops->vidioc_s_ctrl(file, fh, vc);
-
- if (vc->id == V4L2_CID_AUDIO_MUTE) {
- mxb->cur_mute = vc->value;
- /* switch the audio-source */
- tea6420_route_line(mxb, vc->value ? 6 :
- video_audio_connect[mxb->cur_input]);
- DEB_EE("VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d\n", vc->value);
- }
- return 0;
-}
-
static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
{
DEB_EE("VIDIOC_ENUMINPUT %d\n", i->index);
@@ -519,9 +528,12 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int input)
if (saa7111a_call(mxb, video, s_routing, i, SAA7111_FMT_CCIR, 0))
pr_err("VIDIOC_S_INPUT: could not address saa7111a\n");
+ mxb->cur_audinput = video_audio_connect[input];
/* switch the audio-source only if necessary */
if (0 == mxb->cur_mute)
- tea6420_route_line(mxb, video_audio_connect[input]);
+ tea6420_route(mxb, mxb->cur_audinput);
+ if (mxb->cur_audinput == 0)
+ mxb_update_audmode(mxb);
return 0;
}
@@ -563,17 +575,20 @@ static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
return call_all(dev, tuner, s_tuner, t);
}
+static int vidioc_querystd(struct file *file, void *fh, v4l2_std_id *norm)
+{
+ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+
+ return call_all(dev, video, querystd, norm);
+}
+
static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *f)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct mxb *mxb = (struct mxb *)dev->ext_priv;
- if (mxb->cur_input) {
- DEB_D("VIDIOC_G_FREQ: channel %d does not have a tuner!\n",
- mxb->cur_input);
+ if (f->tuner)
return -EINVAL;
- }
-
*f = mxb->cur_freq;
DEB_EE("VIDIOC_G_FREQ: freq:0x%08x\n", mxb->cur_freq.frequency);
@@ -592,17 +607,18 @@ static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency
if (V4L2_TUNER_ANALOG_TV != f->type)
return -EINVAL;
- if (mxb->cur_input) {
- DEB_D("VIDIOC_S_FREQ: channel %d does not have a tuner!\n",
- mxb->cur_input);
- return -EINVAL;
- }
-
- mxb->cur_freq = *f;
DEB_EE("VIDIOC_S_FREQUENCY: freq:0x%08x\n", mxb->cur_freq.frequency);
/* tune in desired frequency */
- tuner_call(mxb, tuner, s_frequency, &mxb->cur_freq);
+ tuner_call(mxb, tuner, s_frequency, f);
+ /* let the tuner subdev clamp the frequency to the tuner range */
+ tuner_call(mxb, tuner, g_frequency, f);
+ mxb->cur_freq = *f;
+ if (mxb->cur_audinput == 0)
+ mxb_update_audmode(mxb);
+
+ if (mxb->cur_input)
+ return 0;
/* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
spin_lock(&dev->slock);
@@ -612,25 +628,40 @@ static int vidioc_s_frequency(struct file *file, void *fh, struct v4l2_frequency
return 0;
}
+static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a)
+{
+ if (a->index >= MXB_AUDIOS)
+ return -EINVAL;
+ *a = mxb_audios[a->index];
+ return 0;
+}
+
static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
struct mxb *mxb = (struct mxb *)dev->ext_priv;
- if (a->index > MXB_INPUTS) {
- DEB_D("VIDIOC_G_AUDIO %d out of range\n", a->index);
- return -EINVAL;
- }
-
- DEB_EE("VIDIOC_G_AUDIO %d\n", a->index);
- memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio));
+ DEB_EE("VIDIOC_G_AUDIO\n");
+ *a = mxb_audios[mxb->cur_audinput];
return 0;
}
static int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
{
+ struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
+ struct mxb *mxb = (struct mxb *)dev->ext_priv;
+
DEB_D("VIDIOC_S_AUDIO %d\n", a->index);
- return 0;
+ if (mxb_inputs[mxb->cur_input].audioset & (1 << a->index)) {
+ if (mxb->cur_audinput != a->index) {
+ mxb->cur_audinput = a->index;
+ tea6420_route(mxb, a->index);
+ if (mxb->cur_audinput == 0)
+ mxb_update_audmode(mxb);
+ }
+ return 0;
+ }
+ return -EINVAL;
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -638,60 +669,31 @@ static int vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_regist
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
- return call_all(dev, core, g_register, reg);
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (v4l2_chip_match_host(&reg->match)) {
+ reg->val = saa7146_read(dev, reg->reg);
+ reg->size = 4;
+ return 0;
+ }
+ call_all(dev, core, g_register, reg);
+ return 0;
}
static int vidioc_s_register(struct file *file, void *fh, struct v4l2_dbg_register *reg)
{
struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
- return call_all(dev, core, s_register, reg);
-}
-#endif
-
-static long vidioc_default(struct file *file, void *fh, bool valid_prio,
- int cmd, void *arg)
-{
- struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev;
- struct mxb *mxb = (struct mxb *)dev->ext_priv;
-
- switch (cmd) {
- case MXB_S_AUDIO_CD:
- {
- int i = *(int *)arg;
-
- if (i < 0 || i >= MXB_AUDIOS) {
- DEB_D("invalid argument to MXB_S_AUDIO_CD: i:%d\n", i);
- return -EINVAL;
- }
-
- DEB_EE("MXB_S_AUDIO_CD: i:%d\n", i);
-
- tea6420_route_cd(mxb, i);
- return 0;
- }
- case MXB_S_AUDIO_LINE:
- {
- int i = *(int *)arg;
-
- if (i < 0 || i >= MXB_AUDIOS) {
- DEB_D("invalid argument to MXB_S_AUDIO_LINE: i:%d\n",
- i);
- return -EINVAL;
- }
-
- DEB_EE("MXB_S_AUDIO_LINE: i:%d\n", i);
- tea6420_route_line(mxb, i);
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (v4l2_chip_match_host(&reg->match)) {
+ saa7146_write(dev, reg->reg, reg->val);
+ reg->size = 4;
return 0;
}
- default:
-/*
- DEB2(pr_err("does not handle this ioctl\n"));
-*/
- return -ENOIOCTLCMD;
- }
- return 0;
+ return call_all(dev, core, s_register, reg);
}
+#endif
static struct saa7146_ext_vv vv_data;
@@ -709,23 +711,21 @@ static int mxb_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data
}
mxb = (struct mxb *)dev->ext_priv;
- vv_data.ops.vidioc_queryctrl = vidioc_queryctrl;
- vv_data.ops.vidioc_g_ctrl = vidioc_g_ctrl;
- vv_data.ops.vidioc_s_ctrl = vidioc_s_ctrl;
- vv_data.ops.vidioc_enum_input = vidioc_enum_input;
- vv_data.ops.vidioc_g_input = vidioc_g_input;
- vv_data.ops.vidioc_s_input = vidioc_s_input;
- vv_data.ops.vidioc_g_tuner = vidioc_g_tuner;
- vv_data.ops.vidioc_s_tuner = vidioc_s_tuner;
- vv_data.ops.vidioc_g_frequency = vidioc_g_frequency;
- vv_data.ops.vidioc_s_frequency = vidioc_s_frequency;
- vv_data.ops.vidioc_g_audio = vidioc_g_audio;
- vv_data.ops.vidioc_s_audio = vidioc_s_audio;
+ vv_data.vid_ops.vidioc_enum_input = vidioc_enum_input;
+ vv_data.vid_ops.vidioc_g_input = vidioc_g_input;
+ vv_data.vid_ops.vidioc_s_input = vidioc_s_input;
+ vv_data.vid_ops.vidioc_querystd = vidioc_querystd;
+ vv_data.vid_ops.vidioc_g_tuner = vidioc_g_tuner;
+ vv_data.vid_ops.vidioc_s_tuner = vidioc_s_tuner;
+ vv_data.vid_ops.vidioc_g_frequency = vidioc_g_frequency;
+ vv_data.vid_ops.vidioc_s_frequency = vidioc_s_frequency;
+ vv_data.vid_ops.vidioc_enumaudio = vidioc_enumaudio;
+ vv_data.vid_ops.vidioc_g_audio = vidioc_g_audio;
+ vv_data.vid_ops.vidioc_s_audio = vidioc_s_audio;
#ifdef CONFIG_VIDEO_ADV_DEBUG
- vv_data.ops.vidioc_g_register = vidioc_g_register;
- vv_data.ops.vidioc_s_register = vidioc_s_register;
+ vv_data.vid_ops.vidioc_g_register = vidioc_g_register;
+ vv_data.vid_ops.vidioc_s_register = vidioc_s_register;
#endif
- vv_data.ops.vidioc_default = vidioc_default;
if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) {
ERR("cannot register capture v4l2 device. skipping.\n");
saa7146_vv_release(dev);
@@ -752,6 +752,9 @@ static int mxb_detach(struct saa7146_dev *dev)
DEB_EE("dev:%p\n", dev);
+ /* mute audio on tea6420s */
+ tea6420_route(mxb, 6);
+
saa7146_unregister_device(&mxb->video_dev,dev);
if (MXB_BOARD_CAN_DO_VBI(dev))
saa7146_unregister_device(&mxb->vbi_dev, dev);
@@ -773,20 +776,24 @@ static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standa
v4l2_std_id std = V4L2_STD_PAL_I;
DEB_D("VIDIOC_S_STD: setting mxb for PAL_I\n");
- /* set the 7146 gpio register -- I don't know what this does exactly */
+ /* These two gpio calls set the GPIO pins that control the tda9820 */
saa7146_write(dev, GPIO_CTRL, 0x00404050);
- /* unset the 7111 gpio register -- I don't know what this does exactly */
saa7111a_call(mxb, core, s_gpio, 0);
- tuner_call(mxb, core, s_std, std);
+ saa7111a_call(mxb, core, s_std, std);
+ if (mxb->cur_input == 0)
+ tuner_call(mxb, core, s_std, std);
} else {
v4l2_std_id std = V4L2_STD_PAL_BG;
+ if (mxb->cur_input)
+ std = standard->id;
DEB_D("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM\n");
- /* set the 7146 gpio register -- I don't know what this does exactly */
+ /* These two gpio calls set the GPIO pins that control the tda9820 */
saa7146_write(dev, GPIO_CTRL, 0x00404050);
- /* set the 7111 gpio register -- I don't know what this does exactly */
saa7111a_call(mxb, core, s_gpio, 1);
- tuner_call(mxb, core, s_std, std);
+ saa7111a_call(mxb, core, s_std, std);
+ if (mxb->cur_input == 0)
+ tuner_call(mxb, core, s_std, std);
}
return 0;
}
@@ -836,14 +843,14 @@ MODULE_DEVICE_TABLE(pci, pci_tbl);
static struct saa7146_ext_vv vv_data = {
.inputs = MXB_INPUTS,
- .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE,
+ .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_AUDIO,
.stds = &standard[0],
.num_stds = sizeof(standard)/sizeof(struct saa7146_standard),
.std_callback = &std_callback,
};
static struct saa7146_extension extension = {
- .name = MXB_IDENTIFIER,
+ .name = "Multimedia eXtension Board",
.flags = SAA7146_USE_I2C_IRQ,
.pci_tbl = &pci_tbl[0],
diff --git a/drivers/media/video/mxb.h b/drivers/media/video/mxb.h
deleted file mode 100644
index 400a57ba62ec..000000000000
--- a/drivers/media/video/mxb.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef __MXB__
-#define __MXB__
-
-#define BASE_VIDIOC_MXB 10
-
-#define MXB_S_AUDIO_CD _IOW ('V', BASE_VIDIOC_PRIVATE+BASE_VIDIOC_MXB+0, int)
-#define MXB_S_AUDIO_LINE _IOW ('V', BASE_VIDIOC_PRIVATE+BASE_VIDIOC_MXB+1, int)
-
-#define MXB_IDENTIFIER "Multimedia eXtension Board"
-
-#define MXB_AUDIOS 6
-
-/* these are the available audio sources, which can switched
- to the line- and cd-output individually */
-static struct v4l2_audio mxb_audios[MXB_AUDIOS] = {
- {
- .index = 0,
- .name = "Tuner",
- .capability = V4L2_AUDCAP_STEREO,
- } , {
- .index = 1,
- .name = "AUX1",
- .capability = V4L2_AUDCAP_STEREO,
- } , {
- .index = 2,
- .name = "AUX2",
- .capability = V4L2_AUDCAP_STEREO,
- } , {
- .index = 3,
- .name = "AUX3",
- .capability = V4L2_AUDCAP_STEREO,
- } , {
- .index = 4,
- .name = "Radio (X9)",
- .capability = V4L2_AUDCAP_STEREO,
- } , {
- .index = 5,
- .name = "CD-ROM (X10)",
- .capability = V4L2_AUDCAP_STEREO,
- }
-};
-#endif
diff --git a/drivers/media/video/omap1_camera.c b/drivers/media/video/omap1_camera.c
index c20f5ecd6790..c7e41145041f 100644
--- a/drivers/media/video/omap1_camera.c
+++ b/drivers/media/video/omap1_camera.c
@@ -206,15 +206,10 @@ static int omap1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
unsigned int *size)
{
struct soc_camera_device *icd = vq->priv_data;
- int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
- icd->current_fmt->host_fmt);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct omap1_cam_dev *pcdev = ici->priv;
- if (bytes_per_line < 0)
- return bytes_per_line;
-
- *size = bytes_per_line * icd->user_height;
+ *size = icd->sizeimage;
if (!*count || *count < OMAP1_CAMERA_MIN_BUF_COUNT(pcdev->vb_mode))
*count = OMAP1_CAMERA_MIN_BUF_COUNT(pcdev->vb_mode);
@@ -256,15 +251,10 @@ static int omap1_videobuf_prepare(struct videobuf_queue *vq,
{
struct soc_camera_device *icd = vq->priv_data;
struct omap1_cam_buf *buf = container_of(vb, struct omap1_cam_buf, vb);
- int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
- icd->current_fmt->host_fmt);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct omap1_cam_dev *pcdev = ici->priv;
int ret;
- if (bytes_per_line < 0)
- return bytes_per_line;
-
WARN_ON(!list_empty(&vb->queue));
BUG_ON(NULL == icd->current_fmt);
@@ -281,7 +271,7 @@ static int omap1_videobuf_prepare(struct videobuf_queue *vq,
vb->state = VIDEOBUF_NEEDS_INIT;
}
- vb->size = bytes_per_line * vb->height;
+ vb->size = icd->sizeimage;
if (vb->baddr && vb->bsize < vb->size) {
ret = -EINVAL;
@@ -999,6 +989,7 @@ static const struct soc_mbus_lookup omap1_cam_formats[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_VYUY8_2X8,
@@ -1008,6 +999,7 @@ static const struct soc_mbus_lookup omap1_cam_formats[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_YUYV8_2X8,
@@ -1017,6 +1009,7 @@ static const struct soc_mbus_lookup omap1_cam_formats[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_YVYU8_2X8,
@@ -1026,6 +1019,7 @@ static const struct soc_mbus_lookup omap1_cam_formats[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
@@ -1035,6 +1029,7 @@ static const struct soc_mbus_lookup omap1_cam_formats[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
@@ -1044,6 +1039,7 @@ static const struct soc_mbus_lookup omap1_cam_formats[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_RGB565_2X8_BE,
@@ -1053,6 +1049,7 @@ static const struct soc_mbus_lookup omap1_cam_formats[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_RGB565_2X8_LE,
@@ -1062,6 +1059,7 @@ static const struct soc_mbus_lookup omap1_cam_formats[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
},
};
diff --git a/drivers/media/video/omap24xxcam-dma.c b/drivers/media/video/omap24xxcam-dma.c
index 3ea38a8def8e..b5ae170de4a5 100644
--- a/drivers/media/video/omap24xxcam-dma.c
+++ b/drivers/media/video/omap24xxcam-dma.c
@@ -38,7 +38,7 @@
*/
/* Ack all interrupt on CSR and IRQSTATUS_L0 */
-static void omap24xxcam_dmahw_ack_all(unsigned long base)
+static void omap24xxcam_dmahw_ack_all(void __iomem *base)
{
u32 csr;
int i;
@@ -52,7 +52,7 @@ static void omap24xxcam_dmahw_ack_all(unsigned long base)
}
/* Ack dmach on CSR and IRQSTATUS_L0 */
-static u32 omap24xxcam_dmahw_ack_ch(unsigned long base, int dmach)
+static u32 omap24xxcam_dmahw_ack_ch(void __iomem *base, int dmach)
{
u32 csr;
@@ -65,12 +65,12 @@ static u32 omap24xxcam_dmahw_ack_ch(unsigned long base, int dmach)
return csr;
}
-static int omap24xxcam_dmahw_running(unsigned long base, int dmach)
+static int omap24xxcam_dmahw_running(void __iomem *base, int dmach)
{
return omap24xxcam_reg_in(base, CAMDMA_CCR(dmach)) & CAMDMA_CCR_ENABLE;
}
-static void omap24xxcam_dmahw_transfer_setup(unsigned long base, int dmach,
+static void omap24xxcam_dmahw_transfer_setup(void __iomem *base, int dmach,
dma_addr_t start, u32 len)
{
omap24xxcam_reg_out(base, CAMDMA_CCR(dmach),
@@ -112,7 +112,7 @@ static void omap24xxcam_dmahw_transfer_setup(unsigned long base, int dmach,
| CAMDMA_CICR_DROP_IE);
}
-static void omap24xxcam_dmahw_transfer_start(unsigned long base, int dmach)
+static void omap24xxcam_dmahw_transfer_start(void __iomem *base, int dmach)
{
omap24xxcam_reg_out(base, CAMDMA_CCR(dmach),
CAMDMA_CCR_SEL_SRC_DST_SYNC
@@ -124,7 +124,7 @@ static void omap24xxcam_dmahw_transfer_start(unsigned long base, int dmach)
| CAMDMA_CCR_SYNCHRO_CAMERA);
}
-static void omap24xxcam_dmahw_transfer_chain(unsigned long base, int dmach,
+static void omap24xxcam_dmahw_transfer_chain(void __iomem *base, int dmach,
int free_dmach)
{
int prev_dmach, ch;
@@ -160,7 +160,7 @@ static void omap24xxcam_dmahw_transfer_chain(unsigned long base, int dmach,
* controller may not be idle after this routine completes, because
* the completion routines might start new transfers.
*/
-static void omap24xxcam_dmahw_abort_ch(unsigned long base, int dmach)
+static void omap24xxcam_dmahw_abort_ch(void __iomem *base, int dmach)
{
/* mask all interrupts from this channel */
omap24xxcam_reg_out(base, CAMDMA_CICR(dmach), 0);
@@ -171,7 +171,7 @@ static void omap24xxcam_dmahw_abort_ch(unsigned long base, int dmach)
omap24xxcam_reg_merge(base, CAMDMA_CCR(dmach), 0, CAMDMA_CCR_ENABLE);
}
-static void omap24xxcam_dmahw_init(unsigned long base)
+static void omap24xxcam_dmahw_init(void __iomem *base)
{
omap24xxcam_reg_out(base, CAMDMA_OCP_SYSCONFIG,
CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY
@@ -362,7 +362,7 @@ void omap24xxcam_dma_hwinit(struct omap24xxcam_dma *dma)
}
static void omap24xxcam_dma_init(struct omap24xxcam_dma *dma,
- unsigned long base)
+ void __iomem *base)
{
int ch;
@@ -577,7 +577,7 @@ void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma)
}
void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma,
- unsigned long base,
+ void __iomem *base,
void (*reset_callback)(unsigned long data),
unsigned long reset_callback_data)
{
diff --git a/drivers/media/video/omap24xxcam.c b/drivers/media/video/omap24xxcam.c
index 7d3864144368..e5015b0d5508 100644
--- a/drivers/media/video/omap24xxcam.c
+++ b/drivers/media/video/omap24xxcam.c
@@ -1776,8 +1776,7 @@ static int __devinit omap24xxcam_probe(struct platform_device *pdev)
cam->mmio_size = resource_size(mem);
/* map the region */
- cam->mmio_base = (unsigned long)
- ioremap_nocache(cam->mmio_base_phys, cam->mmio_size);
+ cam->mmio_base = ioremap_nocache(cam->mmio_base_phys, cam->mmio_size);
if (!cam->mmio_base) {
dev_err(cam->dev, "cannot map camera register I/O region\n");
goto err;
diff --git a/drivers/media/video/omap24xxcam.h b/drivers/media/video/omap24xxcam.h
index 2ce67f5a48d5..d59727afe894 100644
--- a/drivers/media/video/omap24xxcam.h
+++ b/drivers/media/video/omap24xxcam.h
@@ -429,7 +429,7 @@ struct sgdma_state {
struct omap24xxcam_dma {
spinlock_t lock; /* Lock for the whole structure. */
- unsigned long base; /* base address for dma controller */
+ void __iomem *base; /* base address for dma controller */
/* While dma_stop!=0, an attempt to start a new DMA transfer will
* fail.
@@ -491,7 +491,7 @@ struct omap24xxcam_device {
/*** hardware resources ***/
unsigned int irq;
- unsigned long mmio_base;
+ void __iomem *mmio_base;
unsigned long mmio_base_phys;
unsigned long mmio_size;
@@ -544,22 +544,22 @@ struct omap24xxcam_fh {
*
*/
-static inline u32 omap24xxcam_reg_in(unsigned long base, u32 offset)
+static inline u32 omap24xxcam_reg_in(u32 __iomem *base, u32 offset)
{
return readl(base + offset);
}
-static inline u32 omap24xxcam_reg_out(unsigned long base, u32 offset,
+static inline u32 omap24xxcam_reg_out(u32 __iomem *base, u32 offset,
u32 val)
{
writel(val, base + offset);
return val;
}
-static inline u32 omap24xxcam_reg_merge(unsigned long base, u32 offset,
+static inline u32 omap24xxcam_reg_merge(u32 __iomem *base, u32 offset,
u32 val, u32 mask)
{
- u32 addr = base + offset;
+ u32 __iomem *addr = base + offset;
u32 new_val = (readl(addr) & ~mask) | (val & mask);
writel(new_val, addr);
@@ -585,7 +585,7 @@ int omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma *sgdma,
int len, sgdma_callback_t callback, void *arg);
void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma);
void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma,
- unsigned long base,
+ void __iomem *base,
void (*reset_callback)(unsigned long data),
unsigned long reset_callback_data);
void omap24xxcam_sgdma_exit(struct omap24xxcam_sgdma *sgdma);
diff --git a/drivers/media/video/omap3isp/isp.c b/drivers/media/video/omap3isp/isp.c
index 12d5f923e1d0..1c347633e663 100644
--- a/drivers/media/video/omap3isp/isp.c
+++ b/drivers/media/video/omap3isp/isp.c
@@ -329,19 +329,6 @@ void omap3isp_configure_bridge(struct isp_device *isp,
isp_reg_writel(isp, ispctrl_val, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
}
-/**
- * isp_set_pixel_clock - Configures the ISP pixel clock
- * @isp: OMAP3 ISP device
- * @pixelclk: Average pixel clock in Hz
- *
- * Set the average pixel clock required by the sensor. The ISP will use the
- * lowest possible memory bandwidth settings compatible with the clock.
- **/
-static void isp_set_pixel_clock(struct isp_device *isp, unsigned int pixelclk)
-{
- isp->isp_ccdc.vpcfg.pixelclk = pixelclk;
-}
-
void omap3isp_hist_dma_done(struct isp_device *isp)
{
if (omap3isp_ccdc_busy(&isp->isp_ccdc) ||
@@ -739,6 +726,17 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe,
unsigned long flags;
int ret;
+ /* If the preview engine crashed it might not respond to read/write
+ * operations on the L4 bus. This would result in a bus fault and a
+ * kernel oops. Refuse to start streaming in that case. This check must
+ * be performed before the loop below to avoid starting entities if the
+ * pipeline won't start anyway (those entities would then likely fail to
+ * stop, making the problem worse).
+ */
+ if ((pipe->entities & isp->crashed) &
+ (1U << isp->isp_prev.subdev.entity.id))
+ return -EIO;
+
spin_lock_irqsave(&pipe->lock, flags);
pipe->state &= ~(ISP_PIPELINE_IDLE_INPUT | ISP_PIPELINE_IDLE_OUTPUT);
spin_unlock_irqrestore(&pipe->lock, flags);
@@ -774,14 +772,6 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe,
}
}
- /* Frame number propagation. In continuous streaming mode the number
- * is incremented in the frame start ISR. In mem-to-mem mode
- * singleshot is used and frame start IRQs are not available.
- * Thus we have to increment the number here.
- */
- if (pipe->do_propagation && mode == ISP_PIPELINE_STREAM_SINGLESHOT)
- atomic_inc(&pipe->frame_number);
-
return 0;
}
@@ -879,13 +869,15 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe)
if (ret) {
dev_info(isp->dev, "Unable to stop %s\n", subdev->name);
+ /* If the entity failed to stopped, assume it has
+ * crashed. Mark it as such, the ISP will be reset when
+ * applications will release it.
+ */
+ isp->crashed |= 1U << subdev->entity.id;
failure = -ETIMEDOUT;
}
}
- if (failure < 0)
- isp->needs_reset = true;
-
return failure;
}
@@ -1069,6 +1061,7 @@ static int isp_reset(struct isp_device *isp)
udelay(1);
}
+ isp->crashed = 0;
return 0;
}
@@ -1495,11 +1488,13 @@ void omap3isp_put(struct isp_device *isp)
BUG_ON(isp->ref_count == 0);
if (--isp->ref_count == 0) {
isp_disable_interrupts(isp);
- isp_save_ctx(isp);
- if (isp->needs_reset) {
+ if (isp->domain)
+ isp_save_ctx(isp);
+ /* Reset the ISP if an entity has failed to stop. This is the
+ * only way to recover from such conditions.
+ */
+ if (isp->crashed)
isp_reset(isp);
- isp->needs_reset = false;
- }
isp_disable_clocks(isp);
}
mutex_unlock(&isp->isp_mutex);
@@ -1970,7 +1965,7 @@ error_csiphy:
*
* Always returns 0.
*/
-static int isp_remove(struct platform_device *pdev)
+static int __devexit isp_remove(struct platform_device *pdev)
{
struct isp_device *isp = platform_get_drvdata(pdev);
int i;
@@ -1981,6 +1976,7 @@ static int isp_remove(struct platform_device *pdev)
omap3isp_get(isp);
iommu_detach_device(isp->domain, &pdev->dev);
iommu_domain_free(isp->domain);
+ isp->domain = NULL;
omap3isp_put(isp);
free_irq(isp->irq_num, isp);
@@ -2050,7 +2046,7 @@ static int isp_map_mem_resource(struct platform_device *pdev,
* -EINVAL if couldn't install ISR,
* or clk_get return error value.
*/
-static int isp_probe(struct platform_device *pdev)
+static int __devinit isp_probe(struct platform_device *pdev)
{
struct isp_platform_data *pdata = pdev->dev.platform_data;
struct isp_device *isp;
@@ -2068,7 +2064,6 @@ static int isp_probe(struct platform_device *pdev)
isp->autoidle = autoidle;
isp->platform_cb.set_xclk = isp_set_xclk;
- isp->platform_cb.set_pixel_clock = isp_set_pixel_clock;
mutex_init(&isp->isp_mutex);
spin_lock_init(&isp->stat_lock);
@@ -2218,7 +2213,7 @@ MODULE_DEVICE_TABLE(platform, omap3isp_id_table);
static struct platform_driver omap3isp_driver = {
.probe = isp_probe,
- .remove = isp_remove,
+ .remove = __devexit_p(isp_remove),
.id_table = omap3isp_id_table,
.driver = {
.owner = THIS_MODULE,
diff --git a/drivers/media/video/omap3isp/isp.h b/drivers/media/video/omap3isp/isp.h
index d96603eb0d17..fc7af3e32efd 100644
--- a/drivers/media/video/omap3isp/isp.h
+++ b/drivers/media/video/omap3isp/isp.h
@@ -129,7 +129,6 @@ struct isp_platform_callback {
int (*csiphy_config)(struct isp_csiphy *phy,
struct isp_csiphy_dphy_cfg *dphy,
struct isp_csiphy_lanes_cfg *lanes);
- void (*set_pixel_clock)(struct isp_device *isp, unsigned int pixelclk);
};
/*
@@ -145,6 +144,7 @@ struct isp_platform_callback {
* @raw_dmamask: Raw DMA mask
* @stat_lock: Spinlock for handling statistics
* @isp_mutex: Mutex for serializing requests to ISP.
+ * @crashed: Bitmask of crashed entities (indexed by entity ID)
* @has_context: Context has been saved at least once and can be restored.
* @ref_count: Reference count for handling multiple ISP requests.
* @cam_ick: Pointer to camera interface clock structure.
@@ -184,7 +184,7 @@ struct isp_device {
/* ISP Obj */
spinlock_t stat_lock; /* common lock for statistic drivers */
struct mutex isp_mutex; /* For handling ref_count field */
- bool needs_reset;
+ u32 crashed;
int has_context;
int ref_count;
unsigned int autoidle;
@@ -237,10 +237,6 @@ void omap3isp_configure_bridge(struct isp_device *isp,
const struct isp_parallel_platform_data *pdata,
unsigned int shift);
-#define ISP_XCLK_NONE 0
-#define ISP_XCLK_A 1
-#define ISP_XCLK_B 2
-
struct isp_device *omap3isp_get(struct isp_device *isp);
void omap3isp_put(struct isp_device *isp);
diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c
index eaabc27f0fa2..7e32331b60fb 100644
--- a/drivers/media/video/omap3isp/ispccdc.c
+++ b/drivers/media/video/omap3isp/ispccdc.c
@@ -38,6 +38,9 @@
#include "ispreg.h"
#include "ispccdc.h"
+#define CCDC_MIN_WIDTH 32
+#define CCDC_MIN_HEIGHT 32
+
static struct v4l2_mbus_framefmt *
__ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
unsigned int pad, enum v4l2_subdev_format_whence which);
@@ -836,8 +839,8 @@ static void ccdc_config_vp(struct isp_ccdc_device *ccdc)
if (pipe->input)
div = DIV_ROUND_UP(l3_ick, pipe->max_rate);
- else if (ccdc->vpcfg.pixelclk)
- div = l3_ick / ccdc->vpcfg.pixelclk;
+ else if (pipe->external_rate)
+ div = l3_ick / pipe->external_rate;
div = clamp(div, 2U, max_div);
fmtcfg_vp |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT;
@@ -1118,6 +1121,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
struct isp_parallel_platform_data *pdata = NULL;
struct v4l2_subdev *sensor;
struct v4l2_mbus_framefmt *format;
+ const struct v4l2_rect *crop;
const struct isp_format_info *fmt_info;
struct v4l2_subdev_format fmt_src;
unsigned int depth_out;
@@ -1211,14 +1215,14 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VDINT);
/* CCDC_PAD_SOURCE_OF */
- format = &ccdc->formats[CCDC_PAD_SOURCE_OF];
+ crop = &ccdc->crop;
- isp_reg_writel(isp, (0 << ISPCCDC_HORZ_INFO_SPH_SHIFT) |
- ((format->width - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT),
+ isp_reg_writel(isp, (crop->left << ISPCCDC_HORZ_INFO_SPH_SHIFT) |
+ ((crop->width - 1) << ISPCCDC_HORZ_INFO_NPH_SHIFT),
OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO);
- isp_reg_writel(isp, 0 << ISPCCDC_VERT_START_SLV0_SHIFT,
+ isp_reg_writel(isp, crop->top << ISPCCDC_VERT_START_SLV0_SHIFT,
OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_START);
- isp_reg_writel(isp, (format->height - 1)
+ isp_reg_writel(isp, (crop->height - 1)
<< ISPCCDC_VERT_LINES_NLV_SHIFT,
OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VERT_LINES);
@@ -1410,6 +1414,9 @@ static void ccdc_hs_vs_isr(struct isp_ccdc_device *ccdc)
struct video_device *vdev = ccdc->subdev.devnode;
struct v4l2_event event;
+ /* Frame number propagation */
+ atomic_inc(&pipe->frame_number);
+
memset(&event, 0, sizeof(event));
event.type = V4L2_EVENT_FRAME_SYNC;
event.u.frame_sync.frame_sequence = atomic_read(&pipe->frame_number);
@@ -1703,7 +1710,7 @@ static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
if (sub->id != 0)
return -EINVAL;
- return v4l2_event_subscribe(fh, sub, OMAP3ISP_CCDC_NEVENTS);
+ return v4l2_event_subscribe(fh, sub, OMAP3ISP_CCDC_NEVENTS, NULL);
}
static int ccdc_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
@@ -1790,6 +1797,16 @@ __ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
return &ccdc->formats[pad];
}
+static struct v4l2_rect *
+__ccdc_get_crop(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
+ enum v4l2_subdev_format_whence which)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_get_try_crop(fh, CCDC_PAD_SOURCE_OF);
+ else
+ return &ccdc->crop;
+}
+
/*
* ccdc_try_format - Try video format on a pad
* @ccdc: ISP CCDC device
@@ -1806,6 +1823,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
const struct isp_format_info *info;
unsigned int width = fmt->width;
unsigned int height = fmt->height;
+ struct v4l2_rect *crop;
unsigned int i;
switch (pad) {
@@ -1831,14 +1849,10 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
memcpy(fmt, format, sizeof(*fmt));
- /* The data formatter truncates the number of horizontal output
- * pixels to a multiple of 16. To avoid clipping data, allow
- * callers to request an output size bigger than the input size
- * up to the nearest multiple of 16.
- */
- fmt->width = clamp_t(u32, width, 32, fmt->width + 15);
- fmt->width &= ~15;
- fmt->height = clamp_t(u32, height, 32, fmt->height);
+ /* Hardcode the output size to the crop rectangle size. */
+ crop = __ccdc_get_crop(ccdc, fh, which);
+ fmt->width = crop->width;
+ fmt->height = crop->height;
break;
case CCDC_PAD_SOURCE_VP:
@@ -1866,6 +1880,49 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
}
/*
+ * ccdc_try_crop - Validate a crop rectangle
+ * @ccdc: ISP CCDC device
+ * @sink: format on the sink pad
+ * @crop: crop rectangle to be validated
+ */
+static void ccdc_try_crop(struct isp_ccdc_device *ccdc,
+ const struct v4l2_mbus_framefmt *sink,
+ struct v4l2_rect *crop)
+{
+ const struct isp_format_info *info;
+ unsigned int max_width;
+
+ /* For Bayer formats, restrict left/top and width/height to even values
+ * to keep the Bayer pattern.
+ */
+ info = omap3isp_video_format_info(sink->code);
+ if (info->flavor != V4L2_MBUS_FMT_Y8_1X8) {
+ crop->left &= ~1;
+ crop->top &= ~1;
+ }
+
+ crop->left = clamp_t(u32, crop->left, 0, sink->width - CCDC_MIN_WIDTH);
+ crop->top = clamp_t(u32, crop->top, 0, sink->height - CCDC_MIN_HEIGHT);
+
+ /* The data formatter truncates the number of horizontal output pixels
+ * to a multiple of 16. To avoid clipping data, allow callers to request
+ * an output size bigger than the input size up to the nearest multiple
+ * of 16.
+ */
+ max_width = (sink->width - crop->left + 15) & ~15;
+ crop->width = clamp_t(u32, crop->width, CCDC_MIN_WIDTH, max_width)
+ & ~15;
+ crop->height = clamp_t(u32, crop->height, CCDC_MIN_HEIGHT,
+ sink->height - crop->top);
+
+ /* Odd width/height values don't make sense for Bayer formats. */
+ if (info->flavor != V4L2_MBUS_FMT_Y8_1X8) {
+ crop->width &= ~1;
+ crop->height &= ~1;
+ }
+}
+
+/*
* ccdc_enum_mbus_code - Handle pixel format enumeration
* @sd : pointer to v4l2 subdev structure
* @fh : V4L2 subdev file handle
@@ -1937,6 +1994,93 @@ static int ccdc_enum_frame_size(struct v4l2_subdev *sd,
}
/*
+ * ccdc_get_selection - Retrieve a selection rectangle on a pad
+ * @sd: ISP CCDC V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangles are the crop rectangles on the output formatter
+ * source pad.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static int ccdc_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
+{
+ struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format;
+
+ if (sel->pad != CCDC_PAD_SOURCE_OF)
+ return -EINVAL;
+
+ switch (sel->target) {
+ case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = INT_MAX;
+ sel->r.height = INT_MAX;
+
+ format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, sel->which);
+ ccdc_try_crop(ccdc, format, &sel->r);
+ break;
+
+ case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+ sel->r = *__ccdc_get_crop(ccdc, fh, sel->which);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * ccdc_set_selection - Set a selection rectangle on a pad
+ * @sd: ISP CCDC V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangle is the actual crop rectangle on the output
+ * formatter source pad.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static int ccdc_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
+{
+ struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format;
+
+ if (sel->target != V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL ||
+ sel->pad != CCDC_PAD_SOURCE_OF)
+ return -EINVAL;
+
+ /* The crop rectangle can't be changed while streaming. */
+ if (ccdc->state != ISP_PIPELINE_STREAM_STOPPED)
+ return -EBUSY;
+
+ /* Modifying the crop rectangle always changes the format on the source
+ * pad. If the KEEP_CONFIG flag is set, just return the current crop
+ * rectangle.
+ */
+ if (sel->flags & V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG) {
+ sel->r = *__ccdc_get_crop(ccdc, fh, sel->which);
+ return 0;
+ }
+
+ format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, sel->which);
+ ccdc_try_crop(ccdc, format, &sel->r);
+ *__ccdc_get_crop(ccdc, fh, sel->which) = sel->r;
+
+ /* Update the source format. */
+ format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF, sel->which);
+ ccdc_try_format(ccdc, fh, CCDC_PAD_SOURCE_OF, format, sel->which);
+
+ return 0;
+}
+
+/*
* ccdc_get_format - Retrieve the video format on a pad
* @sd : ISP CCDC V4L2 subdevice
* @fh : V4L2 subdev file handle
@@ -1973,6 +2117,7 @@ static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
{
struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
+ struct v4l2_rect *crop;
format = __ccdc_get_format(ccdc, fh, fmt->pad, fmt->which);
if (format == NULL)
@@ -1983,6 +2128,16 @@ static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
/* Propagate the format from sink to source */
if (fmt->pad == CCDC_PAD_SINK) {
+ /* Reset the crop rectangle. */
+ crop = __ccdc_get_crop(ccdc, fh, fmt->which);
+ crop->left = 0;
+ crop->top = 0;
+ crop->width = fmt->format.width;
+ crop->height = fmt->format.height;
+
+ ccdc_try_crop(ccdc, &fmt->format, crop);
+
+ /* Update the source formats. */
format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SOURCE_OF,
fmt->which);
*format = fmt->format;
@@ -2000,6 +2155,69 @@ static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
}
/*
+ * Decide whether desired output pixel code can be obtained with
+ * the lane shifter by shifting the input pixel code.
+ * @in: input pixelcode to shifter
+ * @out: output pixelcode from shifter
+ * @additional_shift: # of bits the sensor's LSB is offset from CAMEXT[0]
+ *
+ * return true if the combination is possible
+ * return false otherwise
+ */
+static bool ccdc_is_shiftable(enum v4l2_mbus_pixelcode in,
+ enum v4l2_mbus_pixelcode out,
+ unsigned int additional_shift)
+{
+ const struct isp_format_info *in_info, *out_info;
+
+ if (in == out)
+ return true;
+
+ in_info = omap3isp_video_format_info(in);
+ out_info = omap3isp_video_format_info(out);
+
+ if ((in_info->flavor == 0) || (out_info->flavor == 0))
+ return false;
+
+ if (in_info->flavor != out_info->flavor)
+ return false;
+
+ return in_info->bpp - out_info->bpp + additional_shift <= 6;
+}
+
+static int ccdc_link_validate(struct v4l2_subdev *sd,
+ struct media_link *link,
+ struct v4l2_subdev_format *source_fmt,
+ struct v4l2_subdev_format *sink_fmt)
+{
+ struct isp_ccdc_device *ccdc = v4l2_get_subdevdata(sd);
+ unsigned long parallel_shift;
+
+ /* Check if the two ends match */
+ if (source_fmt->format.width != sink_fmt->format.width ||
+ source_fmt->format.height != sink_fmt->format.height)
+ return -EPIPE;
+
+ /* We've got a parallel sensor here. */
+ if (ccdc->input == CCDC_INPUT_PARALLEL) {
+ struct isp_parallel_platform_data *pdata =
+ &((struct isp_v4l2_subdevs_group *)
+ media_entity_to_v4l2_subdev(link->source->entity)
+ ->host_priv)->bus.parallel;
+ parallel_shift = pdata->data_lane_shift * 2;
+ } else {
+ parallel_shift = 0;
+ }
+
+ /* Lane shifter may be used to drop bits on CCDC sink pad */
+ if (!ccdc_is_shiftable(source_fmt->format.code,
+ sink_fmt->format.code, parallel_shift))
+ return -EPIPE;
+
+ return 0;
+}
+
+/*
* ccdc_init_formats - Initialize formats on all pads
* @sd: ISP CCDC V4L2 subdevice
* @fh: V4L2 subdev file handle
@@ -2041,6 +2259,9 @@ static const struct v4l2_subdev_pad_ops ccdc_v4l2_pad_ops = {
.enum_frame_size = ccdc_enum_frame_size,
.get_fmt = ccdc_get_format,
.set_fmt = ccdc_set_format,
+ .get_selection = ccdc_get_selection,
+ .set_selection = ccdc_set_selection,
+ .link_validate = ccdc_link_validate,
};
/* V4L2 subdev operations */
@@ -2150,6 +2371,7 @@ static int ccdc_link_setup(struct media_entity *entity,
/* media operations */
static const struct media_entity_operations ccdc_media_ops = {
.link_setup = ccdc_link_setup,
+ .link_validate = v4l2_subdev_link_validate,
};
void omap3isp_ccdc_unregister_entities(struct isp_ccdc_device *ccdc)
@@ -2276,8 +2498,6 @@ int omap3isp_ccdc_init(struct isp_device *isp)
ccdc->clamp.oblen = 0;
ccdc->clamp.dcsubval = 0;
- ccdc->vpcfg.pixelclk = 0;
-
ccdc->update = OMAP3ISP_CCDC_BLCLAMP;
ccdc_apply_controls(ccdc);
diff --git a/drivers/media/video/omap3isp/ispccdc.h b/drivers/media/video/omap3isp/ispccdc.h
index 6d0264bab75b..890f6b3a68fd 100644
--- a/drivers/media/video/omap3isp/ispccdc.h
+++ b/drivers/media/video/omap3isp/ispccdc.h
@@ -80,14 +80,6 @@ struct ispccdc_syncif {
u8 bt_r656_en;
};
-/*
- * struct ispccdc_vp - Structure for Video Port parameters
- * @pixelclk: Input pixel clock in Hz
- */
-struct ispccdc_vp {
- unsigned int pixelclk;
-};
-
enum ispccdc_lsc_state {
LSC_STATE_STOPPED = 0,
LSC_STATE_STOPPING = 1,
@@ -147,6 +139,7 @@ struct ispccdc_lsc {
* @subdev: V4L2 subdevice
* @pads: Sink and source media entity pads
* @formats: Active video formats
+ * @crop: Active crop rectangle on the OF source pad
* @input: Active input
* @output: Active outputs
* @video_out: Output video node
@@ -161,7 +154,6 @@ struct ispccdc_lsc {
* @update: Bitmask of controls to update during the next interrupt
* @shadow_update: Controls update in progress by userspace
* @syncif: Interface synchronization configuration
- * @vpcfg: Video port configuration
* @underrun: A buffer underrun occurred and a new buffer has been queued
* @state: Streaming state
* @lock: Serializes shadow_update with interrupt handler
@@ -173,6 +165,7 @@ struct isp_ccdc_device {
struct v4l2_subdev subdev;
struct media_pad pads[CCDC_PADS_NUM];
struct v4l2_mbus_framefmt formats[CCDC_PADS_NUM];
+ struct v4l2_rect crop;
enum ccdc_input_entity input;
unsigned int output;
@@ -190,7 +183,6 @@ struct isp_ccdc_device {
unsigned int shadow_update;
struct ispccdc_syncif syncif;
- struct ispccdc_vp vpcfg;
unsigned int underrun:1;
enum isp_pipeline_stream_state state;
diff --git a/drivers/media/video/omap3isp/ispccp2.c b/drivers/media/video/omap3isp/ispccp2.c
index 70ddbf35b223..85f0de85f37c 100644
--- a/drivers/media/video/omap3isp/ispccp2.c
+++ b/drivers/media/video/omap3isp/ispccp2.c
@@ -161,7 +161,6 @@ static void ccp2_pwr_cfg(struct isp_ccp2_device *ccp2)
static void ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable)
{
struct isp_device *isp = to_isp_device(ccp2);
- struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity);
int i;
if (enable && ccp2->vdds_csib)
@@ -178,19 +177,6 @@ static void ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable)
ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN,
enable ? (ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN) : 0);
- /* For frame count propagation */
- if (pipe->do_propagation) {
- /* We may want the Frame Start IRQ from LC0 */
- if (enable)
- isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2,
- ISPCCP2_LC01_IRQENABLE,
- ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ);
- else
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCP2,
- ISPCCP2_LC01_IRQENABLE,
- ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ);
- }
-
if (!enable && ccp2->vdds_csib)
regulator_disable(ccp2->vdds_csib);
}
@@ -350,7 +336,6 @@ static void ccp2_lcx_config(struct isp_ccp2_device *ccp2,
ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ |
ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ |
ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ |
- ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ |
ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ |
ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ;
@@ -613,14 +598,6 @@ void omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2)
if (omap3isp_module_sync_is_stopping(&ccp2->wait, &ccp2->stopping))
return;
- /* Frame number propagation */
- if (lcx_irqstatus & ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ) {
- struct isp_pipeline *pipe =
- to_isp_pipeline(&ccp2->subdev.entity);
- if (pipe->do_propagation)
- atomic_inc(&pipe->frame_number);
- }
-
/* Handle queued buffers on frame end interrupts */
if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_EOF_IRQ)
ccp2_isr_buffer(ccp2);
@@ -1021,6 +998,7 @@ static int ccp2_link_setup(struct media_entity *entity,
/* media operations */
static const struct media_entity_operations ccp2_media_ops = {
.link_setup = ccp2_link_setup,
+ .link_validate = v4l2_subdev_link_validate,
};
/*
diff --git a/drivers/media/video/omap3isp/ispcsi2.c b/drivers/media/video/omap3isp/ispcsi2.c
index fcb5168996a7..a1724362b6d5 100644
--- a/drivers/media/video/omap3isp/ispcsi2.c
+++ b/drivers/media/video/omap3isp/ispcsi2.c
@@ -378,21 +378,17 @@ static void csi2_timing_config(struct isp_device *isp,
static void csi2_irq_ctx_set(struct isp_device *isp,
struct isp_csi2_device *csi2, int enable)
{
- u32 reg = ISPCSI2_CTX_IRQSTATUS_FE_IRQ;
int i;
- if (csi2->use_fs_irq)
- reg |= ISPCSI2_CTX_IRQSTATUS_FS_IRQ;
-
for (i = 0; i < 8; i++) {
- isp_reg_writel(isp, reg, csi2->regs1,
+ isp_reg_writel(isp, ISPCSI2_CTX_IRQSTATUS_FE_IRQ, csi2->regs1,
ISPCSI2_CTX_IRQSTATUS(i));
if (enable)
isp_reg_set(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i),
- reg);
+ ISPCSI2_CTX_IRQSTATUS_FE_IRQ);
else
isp_reg_clr(isp, csi2->regs1, ISPCSI2_CTX_IRQENABLE(i),
- reg);
+ ISPCSI2_CTX_IRQSTATUS_FE_IRQ);
}
}
@@ -690,14 +686,6 @@ static void csi2_isr_ctx(struct isp_csi2_device *csi2,
status = isp_reg_readl(isp, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n));
isp_reg_writel(isp, status, csi2->regs1, ISPCSI2_CTX_IRQSTATUS(n));
- /* Propagate frame number */
- if (status & ISPCSI2_CTX_IRQSTATUS_FS_IRQ) {
- struct isp_pipeline *pipe =
- to_isp_pipeline(&csi2->subdev.entity);
- if (pipe->do_propagation)
- atomic_inc(&pipe->frame_number);
- }
-
if (!(status & ISPCSI2_CTX_IRQSTATUS_FE_IRQ))
return;
@@ -1047,14 +1035,12 @@ static int csi2_set_stream(struct v4l2_subdev *sd, int enable)
{
struct isp_csi2_device *csi2 = v4l2_get_subdevdata(sd);
struct isp_device *isp = csi2->isp;
- struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity);
struct isp_video *video_out = &csi2->video_out;
switch (enable) {
case ISP_PIPELINE_STREAM_CONTINUOUS:
if (omap3isp_csiphy_acquire(csi2->phy) < 0)
return -ENODEV;
- csi2->use_fs_irq = pipe->do_propagation;
if (csi2->output & CSI2_OUTPUT_MEMORY)
omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CSI2A_WRITE);
csi2_configure(csi2);
@@ -1181,6 +1167,7 @@ static int csi2_link_setup(struct media_entity *entity,
/* media operations */
static const struct media_entity_operations csi2_media_ops = {
.link_setup = csi2_link_setup,
+ .link_validate = v4l2_subdev_link_validate,
};
void omap3isp_csi2_unregister_entities(struct isp_csi2_device *csi2)
diff --git a/drivers/media/video/omap3isp/ispcsi2.h b/drivers/media/video/omap3isp/ispcsi2.h
index 885ad79a7678..c57729b7e86e 100644
--- a/drivers/media/video/omap3isp/ispcsi2.h
+++ b/drivers/media/video/omap3isp/ispcsi2.h
@@ -145,7 +145,6 @@ struct isp_csi2_device {
u32 output; /* output to CCDC, memory or both? */
bool dpcm_decompress;
unsigned int frame_skip;
- bool use_fs_irq;
struct isp_csiphy *phy;
struct isp_csi2_ctx_cfg contexts[ISP_CSI2_MAX_CTX_NUM + 1];
diff --git a/drivers/media/video/omap3isp/ispcsiphy.c b/drivers/media/video/omap3isp/ispcsiphy.c
index 5be37ce7d0c2..348f67ebbbc9 100644
--- a/drivers/media/video/omap3isp/ispcsiphy.c
+++ b/drivers/media/video/omap3isp/ispcsiphy.c
@@ -186,7 +186,9 @@ int omap3isp_csiphy_acquire(struct isp_csiphy *phy)
if (rval < 0)
goto done;
- omap3isp_csi2_reset(phy->csi2);
+ rval = omap3isp_csi2_reset(phy->csi2);
+ if (rval < 0)
+ goto done;
csiphy_dphy_config(phy);
csiphy_lanes_config(phy);
diff --git a/drivers/media/video/omap3isp/ispcsiphy.h b/drivers/media/video/omap3isp/ispcsiphy.h
index 9596dc6830a6..e93a661e65d9 100644
--- a/drivers/media/video/omap3isp/ispcsiphy.h
+++ b/drivers/media/video/omap3isp/ispcsiphy.h
@@ -27,22 +27,11 @@
#ifndef OMAP3_ISP_CSI_PHY_H
#define OMAP3_ISP_CSI_PHY_H
+#include <media/omap3isp.h>
+
struct isp_csi2_device;
struct regulator;
-struct csiphy_lane {
- u8 pos;
- u8 pol;
-};
-
-#define ISP_CSIPHY2_NUM_DATA_LANES 2
-#define ISP_CSIPHY1_NUM_DATA_LANES 1
-
-struct isp_csiphy_lanes_cfg {
- struct csiphy_lane data[ISP_CSIPHY2_NUM_DATA_LANES];
- struct csiphy_lane clk;
-};
-
struct isp_csiphy_dphy_cfg {
u8 ths_term;
u8 ths_settle;
diff --git a/drivers/media/video/omap3isp/isppreview.c b/drivers/media/video/omap3isp/isppreview.c
index 6d0fb2c8c26d..8a4935ecc655 100644
--- a/drivers/media/video/omap3isp/isppreview.c
+++ b/drivers/media/video/omap3isp/isppreview.c
@@ -441,23 +441,6 @@ preview_enable_dcor(struct isp_prev_device *prev, u8 enable)
}
/*
- * preview_enable_cfa - Enable/Disable the CFA Interpolation.
- * @enable: 1 - Enables the CFA.
- */
-static void
-preview_enable_cfa(struct isp_prev_device *prev, u8 enable)
-{
- struct isp_device *isp = to_isp_device(prev);
-
- if (enable)
- isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_CFAEN);
- else
- isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
- ISPPRV_PCR_CFAEN);
-}
-
-/*
* preview_enable_gammabypass - Enables/Disables the GammaByPass
* @enable: 1 - Bypasses Gamma - 10bit input is cropped to 8MSB.
* 0 - Goes through Gamma Correction. input and output is 10bit.
@@ -608,12 +591,12 @@ preview_config_rgb_blending(struct isp_prev_device *prev, const void *rgb2rgb)
}
/*
- * Configures the RGB-YCbYCr conversion matrix
+ * Configures the color space conversion (RGB toYCbYCr) matrix
* @prev_csc: Structure containing the RGB to YCbYCr matrix and the
* YCbCr offset.
*/
static void
-preview_config_rgb_to_ycbcr(struct isp_prev_device *prev, const void *prev_csc)
+preview_config_csc(struct isp_prev_device *prev, const void *prev_csc)
{
struct isp_device *isp = to_isp_device(prev);
const struct omap3isp_prev_csc *csc = prev_csc;
@@ -649,12 +632,18 @@ preview_config_rgb_to_ycbcr(struct isp_prev_device *prev, const void *prev_csc)
static void
preview_update_contrast(struct isp_prev_device *prev, u8 contrast)
{
- struct prev_params *params = &prev->params;
+ struct prev_params *params;
+ unsigned long flags;
+
+ spin_lock_irqsave(&prev->params.lock, flags);
+ params = (prev->params.active & OMAP3ISP_PREV_CONTRAST)
+ ? &prev->params.params[0] : &prev->params.params[1];
if (params->contrast != (contrast * ISPPRV_CONTRAST_UNITS)) {
params->contrast = contrast * ISPPRV_CONTRAST_UNITS;
- prev->update |= PREV_CONTRAST;
+ params->update |= OMAP3ISP_PREV_CONTRAST;
}
+ spin_unlock_irqrestore(&prev->params.lock, flags);
}
/*
@@ -681,12 +670,18 @@ preview_config_contrast(struct isp_prev_device *prev, const void *params)
static void
preview_update_brightness(struct isp_prev_device *prev, u8 brightness)
{
- struct prev_params *params = &prev->params;
+ struct prev_params *params;
+ unsigned long flags;
+
+ spin_lock_irqsave(&prev->params.lock, flags);
+ params = (prev->params.active & OMAP3ISP_PREV_BRIGHTNESS)
+ ? &prev->params.params[0] : &prev->params.params[1];
if (params->brightness != (brightness * ISPPRV_BRIGHT_UNITS)) {
params->brightness = brightness * ISPPRV_BRIGHT_UNITS;
- prev->update |= PREV_BRIGHTNESS;
+ params->update |= OMAP3ISP_PREV_BRIGHTNESS;
}
+ spin_unlock_irqrestore(&prev->params.lock, flags);
}
/*
@@ -721,159 +716,188 @@ preview_config_yc_range(struct isp_prev_device *prev, const void *yclimit)
OMAP3_ISP_IOMEM_PREV, ISPPRV_SETUP_YC);
}
+static u32
+preview_params_lock(struct isp_prev_device *prev, u32 update, bool shadow)
+{
+ u32 active = prev->params.active;
+
+ if (shadow) {
+ /* Mark all shadow parameters we are going to touch as busy. */
+ prev->params.params[0].busy |= ~active & update;
+ prev->params.params[1].busy |= active & update;
+ } else {
+ /* Mark all active parameters we are going to touch as busy. */
+ update = (prev->params.params[0].update & active)
+ | (prev->params.params[1].update & ~active);
+
+ prev->params.params[0].busy |= active & update;
+ prev->params.params[1].busy |= ~active & update;
+ }
+
+ return update;
+}
+
+static void
+preview_params_unlock(struct isp_prev_device *prev, u32 update, bool shadow)
+{
+ u32 active = prev->params.active;
+
+ if (shadow) {
+ /* Set the update flag for shadow parameters that have been
+ * updated and clear the busy flag for all shadow parameters.
+ */
+ prev->params.params[0].update |= (~active & update);
+ prev->params.params[1].update |= (active & update);
+ prev->params.params[0].busy &= active;
+ prev->params.params[1].busy &= ~active;
+ } else {
+ /* Clear the update flag for active parameters that have been
+ * applied and the busy flag for all active parameters.
+ */
+ prev->params.params[0].update &= ~(active & update);
+ prev->params.params[1].update &= ~(~active & update);
+ prev->params.params[0].busy &= ~active;
+ prev->params.params[1].busy &= active;
+ }
+}
+
+static void preview_params_switch(struct isp_prev_device *prev)
+{
+ u32 to_switch;
+
+ /* Switch active parameters with updated shadow parameters when the
+ * shadow parameter has been updated and neither the active not the
+ * shadow parameter is busy.
+ */
+ to_switch = (prev->params.params[0].update & ~prev->params.active)
+ | (prev->params.params[1].update & prev->params.active);
+ to_switch &= ~(prev->params.params[0].busy |
+ prev->params.params[1].busy);
+ if (to_switch == 0)
+ return;
+
+ prev->params.active ^= to_switch;
+
+ /* Remove the update flag for the shadow copy of parameters we have
+ * switched.
+ */
+ prev->params.params[0].update &= ~(~prev->params.active & to_switch);
+ prev->params.params[1].update &= ~(prev->params.active & to_switch);
+}
+
/* preview parameters update structure */
struct preview_update {
- int cfg_bit;
- int feature_bit;
void (*config)(struct isp_prev_device *, const void *);
void (*enable)(struct isp_prev_device *, u8);
+ unsigned int param_offset;
+ unsigned int param_size;
+ unsigned int config_offset;
+ bool skip;
};
-static struct preview_update update_attrs[] = {
- {OMAP3ISP_PREV_LUMAENH, PREV_LUMA_ENHANCE,
+/* Keep the array indexed by the OMAP3ISP_PREV_* bit number. */
+static const struct preview_update update_attrs[] = {
+ /* OMAP3ISP_PREV_LUMAENH */ {
preview_config_luma_enhancement,
- preview_enable_luma_enhancement},
- {OMAP3ISP_PREV_INVALAW, PREV_INVERSE_ALAW,
+ preview_enable_luma_enhancement,
+ offsetof(struct prev_params, luma),
+ FIELD_SIZEOF(struct prev_params, luma),
+ offsetof(struct omap3isp_prev_update_config, luma),
+ }, /* OMAP3ISP_PREV_INVALAW */ {
NULL,
- preview_enable_invalaw},
- {OMAP3ISP_PREV_HRZ_MED, PREV_HORZ_MEDIAN_FILTER,
+ preview_enable_invalaw,
+ }, /* OMAP3ISP_PREV_HRZ_MED */ {
preview_config_hmed,
- preview_enable_hmed},
- {OMAP3ISP_PREV_CFA, PREV_CFA,
+ preview_enable_hmed,
+ offsetof(struct prev_params, hmed),
+ FIELD_SIZEOF(struct prev_params, hmed),
+ offsetof(struct omap3isp_prev_update_config, hmed),
+ }, /* OMAP3ISP_PREV_CFA */ {
preview_config_cfa,
- preview_enable_cfa},
- {OMAP3ISP_PREV_CHROMA_SUPP, PREV_CHROMA_SUPPRESS,
+ NULL,
+ offsetof(struct prev_params, cfa),
+ FIELD_SIZEOF(struct prev_params, cfa),
+ offsetof(struct omap3isp_prev_update_config, cfa),
+ }, /* OMAP3ISP_PREV_CHROMA_SUPP */ {
preview_config_chroma_suppression,
- preview_enable_chroma_suppression},
- {OMAP3ISP_PREV_WB, PREV_WB,
+ preview_enable_chroma_suppression,
+ offsetof(struct prev_params, csup),
+ FIELD_SIZEOF(struct prev_params, csup),
+ offsetof(struct omap3isp_prev_update_config, csup),
+ }, /* OMAP3ISP_PREV_WB */ {
preview_config_whitebalance,
- NULL},
- {OMAP3ISP_PREV_BLKADJ, PREV_BLKADJ,
+ NULL,
+ offsetof(struct prev_params, wbal),
+ FIELD_SIZEOF(struct prev_params, wbal),
+ offsetof(struct omap3isp_prev_update_config, wbal),
+ }, /* OMAP3ISP_PREV_BLKADJ */ {
preview_config_blkadj,
- NULL},
- {OMAP3ISP_PREV_RGB2RGB, PREV_RGB2RGB,
+ NULL,
+ offsetof(struct prev_params, blkadj),
+ FIELD_SIZEOF(struct prev_params, blkadj),
+ offsetof(struct omap3isp_prev_update_config, blkadj),
+ }, /* OMAP3ISP_PREV_RGB2RGB */ {
preview_config_rgb_blending,
- NULL},
- {OMAP3ISP_PREV_COLOR_CONV, PREV_COLOR_CONV,
- preview_config_rgb_to_ycbcr,
- NULL},
- {OMAP3ISP_PREV_YC_LIMIT, PREV_YCLIMITS,
+ NULL,
+ offsetof(struct prev_params, rgb2rgb),
+ FIELD_SIZEOF(struct prev_params, rgb2rgb),
+ offsetof(struct omap3isp_prev_update_config, rgb2rgb),
+ }, /* OMAP3ISP_PREV_COLOR_CONV */ {
+ preview_config_csc,
+ NULL,
+ offsetof(struct prev_params, csc),
+ FIELD_SIZEOF(struct prev_params, csc),
+ offsetof(struct omap3isp_prev_update_config, csc),
+ }, /* OMAP3ISP_PREV_YC_LIMIT */ {
preview_config_yc_range,
- NULL},
- {OMAP3ISP_PREV_DEFECT_COR, PREV_DEFECT_COR,
+ NULL,
+ offsetof(struct prev_params, yclimit),
+ FIELD_SIZEOF(struct prev_params, yclimit),
+ offsetof(struct omap3isp_prev_update_config, yclimit),
+ }, /* OMAP3ISP_PREV_DEFECT_COR */ {
preview_config_dcor,
- preview_enable_dcor},
- {OMAP3ISP_PREV_GAMMABYPASS, PREV_GAMMA_BYPASS,
+ preview_enable_dcor,
+ offsetof(struct prev_params, dcor),
+ FIELD_SIZEOF(struct prev_params, dcor),
+ offsetof(struct omap3isp_prev_update_config, dcor),
+ }, /* OMAP3ISP_PREV_GAMMABYPASS */ {
NULL,
- preview_enable_gammabypass},
- {OMAP3ISP_PREV_DRK_FRM_CAPTURE, PREV_DARK_FRAME_CAPTURE,
+ preview_enable_gammabypass,
+ }, /* OMAP3ISP_PREV_DRK_FRM_CAPTURE */ {
NULL,
- preview_enable_drkframe_capture},
- {OMAP3ISP_PREV_DRK_FRM_SUBTRACT, PREV_DARK_FRAME_SUBTRACT,
+ preview_enable_drkframe_capture,
+ }, /* OMAP3ISP_PREV_DRK_FRM_SUBTRACT */ {
NULL,
- preview_enable_drkframe},
- {OMAP3ISP_PREV_LENS_SHADING, PREV_LENS_SHADING,
+ preview_enable_drkframe,
+ }, /* OMAP3ISP_PREV_LENS_SHADING */ {
preview_config_drkf_shadcomp,
- preview_enable_drkframe},
- {OMAP3ISP_PREV_NF, PREV_NOISE_FILTER,
+ preview_enable_drkframe,
+ }, /* OMAP3ISP_PREV_NF */ {
preview_config_noisefilter,
- preview_enable_noisefilter},
- {OMAP3ISP_PREV_GAMMA, PREV_GAMMA,
+ preview_enable_noisefilter,
+ offsetof(struct prev_params, nf),
+ FIELD_SIZEOF(struct prev_params, nf),
+ offsetof(struct omap3isp_prev_update_config, nf),
+ }, /* OMAP3ISP_PREV_GAMMA */ {
preview_config_gammacorrn,
- NULL},
- {-1, PREV_CONTRAST,
+ NULL,
+ offsetof(struct prev_params, gamma),
+ FIELD_SIZEOF(struct prev_params, gamma),
+ offsetof(struct omap3isp_prev_update_config, gamma),
+ }, /* OMAP3ISP_PREV_CONTRAST */ {
preview_config_contrast,
- NULL},
- {-1, PREV_BRIGHTNESS,
+ NULL,
+ offsetof(struct prev_params, contrast),
+ 0, true,
+ }, /* OMAP3ISP_PREV_BRIGHTNESS */ {
preview_config_brightness,
- NULL},
+ NULL,
+ offsetof(struct prev_params, brightness),
+ 0, true,
+ },
};
/*
- * __preview_get_ptrs - helper function which return pointers to members
- * of params and config structures.
- * @params - pointer to preview_params structure.
- * @param - return pointer to appropriate structure field.
- * @configs - pointer to update config structure.
- * @config - return pointer to appropriate structure field.
- * @bit - for which feature to return pointers.
- * Return size of corresponding prev_params member
- */
-static u32
-__preview_get_ptrs(struct prev_params *params, void **param,
- struct omap3isp_prev_update_config *configs,
- void __user **config, u32 bit)
-{
-#define CHKARG(cfgs, cfg, field) \
- if (cfgs && cfg) { \
- *(cfg) = (cfgs)->field; \
- }
-
- switch (bit) {
- case PREV_HORZ_MEDIAN_FILTER:
- *param = &params->hmed;
- CHKARG(configs, config, hmed)
- return sizeof(params->hmed);
- case PREV_NOISE_FILTER:
- *param = &params->nf;
- CHKARG(configs, config, nf)
- return sizeof(params->nf);
- break;
- case PREV_CFA:
- *param = &params->cfa;
- CHKARG(configs, config, cfa)
- return sizeof(params->cfa);
- case PREV_LUMA_ENHANCE:
- *param = &params->luma;
- CHKARG(configs, config, luma)
- return sizeof(params->luma);
- case PREV_CHROMA_SUPPRESS:
- *param = &params->csup;
- CHKARG(configs, config, csup)
- return sizeof(params->csup);
- case PREV_DEFECT_COR:
- *param = &params->dcor;
- CHKARG(configs, config, dcor)
- return sizeof(params->dcor);
- case PREV_BLKADJ:
- *param = &params->blk_adj;
- CHKARG(configs, config, blkadj)
- return sizeof(params->blk_adj);
- case PREV_YCLIMITS:
- *param = &params->yclimit;
- CHKARG(configs, config, yclimit)
- return sizeof(params->yclimit);
- case PREV_RGB2RGB:
- *param = &params->rgb2rgb;
- CHKARG(configs, config, rgb2rgb)
- return sizeof(params->rgb2rgb);
- case PREV_COLOR_CONV:
- *param = &params->rgb2ycbcr;
- CHKARG(configs, config, csc)
- return sizeof(params->rgb2ycbcr);
- case PREV_WB:
- *param = &params->wbal;
- CHKARG(configs, config, wbal)
- return sizeof(params->wbal);
- case PREV_GAMMA:
- *param = &params->gamma;
- CHKARG(configs, config, gamma)
- return sizeof(params->gamma);
- case PREV_CONTRAST:
- *param = &params->contrast;
- return 0;
- case PREV_BRIGHTNESS:
- *param = &params->brightness;
- return 0;
- default:
- *param = NULL;
- *config = NULL;
- break;
- }
- return 0;
-}
-
-/*
* preview_config - Copy and update local structure with userspace preview
* configuration.
* @prev: ISP preview engine
@@ -885,84 +909,103 @@ __preview_get_ptrs(struct prev_params *params, void **param,
static int preview_config(struct isp_prev_device *prev,
struct omap3isp_prev_update_config *cfg)
{
- struct prev_params *params;
- struct preview_update *attr;
- int i, bit, rval = 0;
+ unsigned long flags;
+ unsigned int i;
+ int rval = 0;
+ u32 update;
+ u32 active;
- params = &prev->params;
+ if (cfg->update == 0)
+ return 0;
- if (prev->state != ISP_PIPELINE_STREAM_STOPPED) {
- unsigned long flags;
+ /* Mark the shadow parameters we're going to update as busy. */
+ spin_lock_irqsave(&prev->params.lock, flags);
+ preview_params_lock(prev, cfg->update, true);
+ active = prev->params.active;
+ spin_unlock_irqrestore(&prev->params.lock, flags);
- spin_lock_irqsave(&prev->lock, flags);
- prev->shadow_update = 1;
- spin_unlock_irqrestore(&prev->lock, flags);
- }
+ update = 0;
for (i = 0; i < ARRAY_SIZE(update_attrs); i++) {
- attr = &update_attrs[i];
- bit = 0;
+ const struct preview_update *attr = &update_attrs[i];
+ struct prev_params *params;
+ unsigned int bit = 1 << i;
- if (!(cfg->update & attr->cfg_bit))
+ if (attr->skip || !(cfg->update & bit))
continue;
- bit = cfg->flag & attr->cfg_bit;
- if (bit) {
- void *to = NULL, __user *from = NULL;
- unsigned long sz = 0;
+ params = &prev->params.params[!!(active & bit)];
+
+ if (cfg->flag & bit) {
+ void __user *from = *(void * __user *)
+ ((void *)cfg + attr->config_offset);
+ void *to = (void *)params + attr->param_offset;
+ size_t size = attr->param_size;
- sz = __preview_get_ptrs(params, &to, cfg, &from,
- bit);
- if (to && from && sz) {
- if (copy_from_user(to, from, sz)) {
+ if (to && from && size) {
+ if (copy_from_user(to, from, size)) {
rval = -EFAULT;
break;
}
}
- params->features |= attr->feature_bit;
+ params->features |= bit;
} else {
- params->features &= ~attr->feature_bit;
+ params->features &= ~bit;
}
- prev->update |= attr->feature_bit;
+ update |= bit;
}
- prev->shadow_update = 0;
+ spin_lock_irqsave(&prev->params.lock, flags);
+ preview_params_unlock(prev, update, true);
+ preview_params_switch(prev);
+ spin_unlock_irqrestore(&prev->params.lock, flags);
+
return rval;
}
/*
* preview_setup_hw - Setup preview registers and/or internal memory
* @prev: pointer to preview private structure
+ * @update: Bitmask of parameters to setup
+ * @active: Bitmask of parameters active in set 0
* Note: can be called from interrupt context
* Return none
*/
-static void preview_setup_hw(struct isp_prev_device *prev)
+static void preview_setup_hw(struct isp_prev_device *prev, u32 update,
+ u32 active)
{
- struct prev_params *params = &prev->params;
- struct preview_update *attr;
- int i, bit;
- void *param_ptr;
+ unsigned int i;
+ u32 features;
+
+ if (update == 0)
+ return;
+
+ features = (prev->params.params[0].features & active)
+ | (prev->params.params[1].features & ~active);
for (i = 0; i < ARRAY_SIZE(update_attrs); i++) {
- attr = &update_attrs[i];
+ const struct preview_update *attr = &update_attrs[i];
+ struct prev_params *params;
+ unsigned int bit = 1 << i;
+ void *param_ptr;
- if (!(prev->update & attr->feature_bit))
+ if (!(update & bit))
continue;
- bit = params->features & attr->feature_bit;
- if (bit) {
+
+ params = &prev->params.params[!(active & bit)];
+
+ if (params->features & bit) {
if (attr->config) {
- __preview_get_ptrs(params, &param_ptr, NULL,
- NULL, bit);
+ param_ptr = (void *)params + attr->param_offset;
attr->config(prev, param_ptr);
}
if (attr->enable)
attr->enable(prev, 1);
- } else
+ } else {
if (attr->enable)
attr->enable(prev, 0);
-
- prev->update &= ~attr->feature_bit;
+ }
}
}
@@ -1000,13 +1043,17 @@ preview_config_ycpos(struct isp_prev_device *prev,
static void preview_config_averager(struct isp_prev_device *prev, u8 average)
{
struct isp_device *isp = to_isp_device(prev);
+ struct prev_params *params;
int reg = 0;
- if (prev->params.cfa.format == OMAP3ISP_CFAFMT_BAYER)
+ params = (prev->params.active & OMAP3ISP_PREV_CFA)
+ ? &prev->params.params[0] : &prev->params.params[1];
+
+ if (params->cfa.format == OMAP3ISP_CFAFMT_BAYER)
reg = ISPPRV_AVE_EVENDIST_2 << ISPPRV_AVE_EVENDIST_SHIFT |
ISPPRV_AVE_ODDDIST_2 << ISPPRV_AVE_ODDDIST_SHIFT |
average;
- else if (prev->params.cfa.format == OMAP3ISP_CFAFMT_RGBFOVEON)
+ else if (params->cfa.format == OMAP3ISP_CFAFMT_RGBFOVEON)
reg = ISPPRV_AVE_EVENDIST_3 << ISPPRV_AVE_EVENDIST_SHIFT |
ISPPRV_AVE_ODDDIST_3 << ISPPRV_AVE_ODDDIST_SHIFT |
average;
@@ -1014,6 +1061,27 @@ static void preview_config_averager(struct isp_prev_device *prev, u8 average)
}
/*
+ * preview_config_input_format - Configure the input format
+ * @prev: The preview engine
+ * @format: Format on the preview engine sink pad
+ *
+ * Enable CFA interpolation for Bayer formats and disable it for greyscale
+ * formats.
+ */
+static void preview_config_input_format(struct isp_prev_device *prev,
+ const struct v4l2_mbus_framefmt *format)
+{
+ struct isp_device *isp = to_isp_device(prev);
+
+ if (format->code != V4L2_MBUS_FMT_Y10_1X10)
+ isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_CFAEN);
+ else
+ isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+ ISPPRV_PCR_CFAEN);
+}
+
+/*
* preview_config_input_size - Configure the input frame size
*
* The preview engine crops several rows and columns internally depending on
@@ -1024,32 +1092,37 @@ static void preview_config_averager(struct isp_prev_device *prev, u8 average)
*
* See the explanation at the PREV_MARGIN_* definitions for more details.
*/
-static void preview_config_input_size(struct isp_prev_device *prev)
+static void preview_config_input_size(struct isp_prev_device *prev, u32 active)
{
+ const struct v4l2_mbus_framefmt *format = &prev->formats[PREV_PAD_SINK];
struct isp_device *isp = to_isp_device(prev);
- struct prev_params *params = &prev->params;
unsigned int sph = prev->crop.left;
unsigned int eph = prev->crop.left + prev->crop.width - 1;
unsigned int slv = prev->crop.top;
unsigned int elv = prev->crop.top + prev->crop.height - 1;
+ u32 features;
- if (params->features & PREV_CFA) {
+ if (format->code == V4L2_MBUS_FMT_Y10_1X10) {
sph -= 2;
eph += 2;
slv -= 2;
elv += 2;
}
- if (params->features & (PREV_DEFECT_COR | PREV_NOISE_FILTER)) {
+
+ features = (prev->params.params[0].features & active)
+ | (prev->params.params[1].features & ~active);
+
+ if (features & (OMAP3ISP_PREV_DEFECT_COR | OMAP3ISP_PREV_NF)) {
sph -= 2;
eph += 2;
slv -= 2;
elv += 2;
}
- if (params->features & PREV_HORZ_MEDIAN_FILTER) {
+ if (features & OMAP3ISP_PREV_HRZ_MED) {
sph -= 2;
eph += 2;
}
- if (params->features & (PREV_CHROMA_SUPPRESS | PREV_LUMA_ENHANCE))
+ if (features & (OMAP3ISP_PREV_CHROMA_SUPP | OMAP3ISP_PREV_LUMAENH))
sph -= 2;
isp_reg_writel(isp, (sph << ISPPRV_HORZ_INFO_SPH_SHIFT) | eph,
@@ -1184,8 +1257,16 @@ int omap3isp_preview_busy(struct isp_prev_device *prev)
*/
void omap3isp_preview_restore_context(struct isp_device *isp)
{
- isp->isp_prev.update = PREV_FEATURES_END - 1;
- preview_setup_hw(&isp->isp_prev);
+ struct isp_prev_device *prev = &isp->isp_prev;
+ const u32 update = OMAP3ISP_PREV_FEATURES_END - 1;
+
+ prev->params.params[0].update = prev->params.active & update;
+ prev->params.params[1].update = ~prev->params.active & update;
+
+ preview_setup_hw(prev, update, prev->params.active);
+
+ prev->params.params[0].update = 0;
+ prev->params.params[1].update = 0;
}
/*
@@ -1244,12 +1325,21 @@ static void preview_print_status(struct isp_prev_device *prev)
/*
* preview_init_params - init image processing parameters.
* @prev: pointer to previewer private structure
- * return none
*/
static void preview_init_params(struct isp_prev_device *prev)
{
- struct prev_params *params = &prev->params;
- int i = 0;
+ struct prev_params *params;
+ unsigned int i;
+
+ spin_lock_init(&prev->params.lock);
+
+ prev->params.active = ~0;
+ prev->params.params[0].busy = 0;
+ prev->params.params[0].update = OMAP3ISP_PREV_FEATURES_END - 1;
+ prev->params.params[1].busy = 0;
+ prev->params.params[1].update = 0;
+
+ params = &prev->params.params[0];
/* Init values */
params->contrast = ISPPRV_CONTRAST_DEF * ISPPRV_CONTRAST_UNITS;
@@ -1277,22 +1367,22 @@ static void preview_init_params(struct isp_prev_device *prev)
params->wbal.coef1 = FLR_WBAL_COEF;
params->wbal.coef2 = FLR_WBAL_COEF;
params->wbal.coef3 = FLR_WBAL_COEF;
- params->blk_adj.red = FLR_BLKADJ_RED;
- params->blk_adj.green = FLR_BLKADJ_GREEN;
- params->blk_adj.blue = FLR_BLKADJ_BLUE;
+ params->blkadj.red = FLR_BLKADJ_RED;
+ params->blkadj.green = FLR_BLKADJ_GREEN;
+ params->blkadj.blue = FLR_BLKADJ_BLUE;
params->rgb2rgb = flr_rgb2rgb;
- params->rgb2ycbcr = flr_prev_csc;
+ params->csc = flr_prev_csc;
params->yclimit.minC = ISPPRV_YC_MIN;
params->yclimit.maxC = ISPPRV_YC_MAX;
params->yclimit.minY = ISPPRV_YC_MIN;
params->yclimit.maxY = ISPPRV_YC_MAX;
- params->features = PREV_CFA | PREV_DEFECT_COR | PREV_NOISE_FILTER
- | PREV_GAMMA | PREV_BLKADJ | PREV_YCLIMITS
- | PREV_RGB2RGB | PREV_COLOR_CONV | PREV_WB
- | PREV_BRIGHTNESS | PREV_CONTRAST;
-
- prev->update = PREV_FEATURES_END - 1;
+ params->features = OMAP3ISP_PREV_CFA | OMAP3ISP_PREV_DEFECT_COR
+ | OMAP3ISP_PREV_NF | OMAP3ISP_PREV_GAMMA
+ | OMAP3ISP_PREV_BLKADJ | OMAP3ISP_PREV_YC_LIMIT
+ | OMAP3ISP_PREV_RGB2RGB | OMAP3ISP_PREV_COLOR_CONV
+ | OMAP3ISP_PREV_WB | OMAP3ISP_PREV_BRIGHTNESS
+ | OMAP3ISP_PREV_CONTRAST;
}
/*
@@ -1321,8 +1411,17 @@ static void preview_configure(struct isp_prev_device *prev)
{
struct isp_device *isp = to_isp_device(prev);
struct v4l2_mbus_framefmt *format;
+ unsigned long flags;
+ u32 update;
+ u32 active;
- preview_setup_hw(prev);
+ spin_lock_irqsave(&prev->params.lock, flags);
+ /* Mark all active parameters we are going to touch as busy. */
+ update = preview_params_lock(prev, 0, false);
+ active = prev->params.active;
+ spin_unlock_irqrestore(&prev->params.lock, flags);
+
+ preview_setup_hw(prev, update, active);
if (prev->output & PREVIEW_OUTPUT_MEMORY)
isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
@@ -1343,7 +1442,8 @@ static void preview_configure(struct isp_prev_device *prev)
preview_adjust_bandwidth(prev);
- preview_config_input_size(prev);
+ preview_config_input_format(prev, format);
+ preview_config_input_size(prev, active);
if (prev->input == PREVIEW_INPUT_CCDC)
preview_config_inlineoffset(prev, 0);
@@ -1360,6 +1460,10 @@ static void preview_configure(struct isp_prev_device *prev)
preview_config_averager(prev, 0);
preview_config_ycpos(prev, format->code);
+
+ spin_lock_irqsave(&prev->params.lock, flags);
+ preview_params_unlock(prev, update, false);
+ spin_unlock_irqrestore(&prev->params.lock, flags);
}
/* -----------------------------------------------------------------------------
@@ -1448,25 +1552,30 @@ static void preview_isr_buffer(struct isp_prev_device *prev)
void omap3isp_preview_isr(struct isp_prev_device *prev)
{
unsigned long flags;
+ u32 update;
+ u32 active;
if (omap3isp_module_sync_is_stopping(&prev->wait, &prev->stopping))
return;
- spin_lock_irqsave(&prev->lock, flags);
- if (prev->shadow_update)
- goto done;
+ spin_lock_irqsave(&prev->params.lock, flags);
+ preview_params_switch(prev);
+ update = preview_params_lock(prev, 0, false);
+ active = prev->params.active;
+ spin_unlock_irqrestore(&prev->params.lock, flags);
- preview_setup_hw(prev);
- preview_config_input_size(prev);
-
-done:
- spin_unlock_irqrestore(&prev->lock, flags);
+ preview_setup_hw(prev, update, active);
+ preview_config_input_size(prev, active);
if (prev->input == PREVIEW_INPUT_MEMORY ||
prev->output & PREVIEW_OUTPUT_MEMORY)
preview_isr_buffer(prev);
else if (prev->state == ISP_PIPELINE_STREAM_CONTINUOUS)
preview_enable_oneshot(prev);
+
+ spin_lock_irqsave(&prev->params.lock, flags);
+ preview_params_unlock(prev, update, false);
+ spin_unlock_irqrestore(&prev->params.lock, flags);
}
/* -----------------------------------------------------------------------------
@@ -1552,7 +1661,6 @@ static int preview_set_stream(struct v4l2_subdev *sd, int enable)
struct isp_video *video_out = &prev->video_out;
struct isp_device *isp = to_isp_device(prev);
struct device *dev = to_device(prev);
- unsigned long flags;
if (prev->state == ISP_PIPELINE_STREAM_STOPPED) {
if (enable == ISP_PIPELINE_STREAM_STOPPED)
@@ -1589,11 +1697,9 @@ static int preview_set_stream(struct v4l2_subdev *sd, int enable)
if (omap3isp_module_sync_idle(&sd->entity, &prev->wait,
&prev->stopping))
dev_dbg(dev, "%s: stop timeout.\n", sd->name);
- spin_lock_irqsave(&prev->lock, flags);
omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_READ);
omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_PREVIEW_WRITE);
omap3isp_subclk_disable(isp, OMAP3_ISP_SUBCLK_PREVIEW);
- spin_unlock_irqrestore(&prev->lock, flags);
isp_video_dmaqueue_flags_clr(video_out);
break;
}
@@ -1624,6 +1730,7 @@ __preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh,
/* previewer format descriptions */
static const unsigned int preview_input_fmts[] = {
+ V4L2_MBUS_FMT_Y10_1X10,
V4L2_MBUS_FMT_SGRBG10_1X10,
V4L2_MBUS_FMT_SRGGB10_1X10,
V4L2_MBUS_FMT_SBGGR10_1X10,
@@ -1822,55 +1929,89 @@ static int preview_enum_frame_size(struct v4l2_subdev *sd,
}
/*
- * preview_get_crop - Retrieve the crop rectangle on a pad
+ * preview_get_selection - Retrieve a selection rectangle on a pad
* @sd: ISP preview V4L2 subdevice
* @fh: V4L2 subdev file handle
- * @crop: crop rectangle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangles are the crop rectangles on the sink pad.
*
* Return 0 on success or a negative error code otherwise.
*/
-static int preview_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_crop *crop)
+static int preview_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
{
struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format;
+
+ if (sel->pad != PREV_PAD_SINK)
+ return -EINVAL;
+
+ switch (sel->target) {
+ case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = INT_MAX;
+ sel->r.height = INT_MAX;
+
+ format = __preview_get_format(prev, fh, PREV_PAD_SINK,
+ sel->which);
+ preview_try_crop(prev, format, &sel->r);
+ break;
+
+ case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+ sel->r = *__preview_get_crop(prev, fh, sel->which);
+ break;
- /* Cropping is only supported on the sink pad. */
- if (crop->pad != PREV_PAD_SINK)
+ default:
return -EINVAL;
+ }
- crop->rect = *__preview_get_crop(prev, fh, crop->which);
return 0;
}
/*
- * preview_set_crop - Retrieve the crop rectangle on a pad
+ * preview_set_selection - Set a selection rectangle on a pad
* @sd: ISP preview V4L2 subdevice
* @fh: V4L2 subdev file handle
- * @crop: crop rectangle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangle is the actual crop rectangle on the sink pad.
*
* Return 0 on success or a negative error code otherwise.
*/
-static int preview_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_crop *crop)
+static int preview_set_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
{
struct isp_prev_device *prev = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- /* Cropping is only supported on the sink pad. */
- if (crop->pad != PREV_PAD_SINK)
+ if (sel->target != V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL ||
+ sel->pad != PREV_PAD_SINK)
return -EINVAL;
/* The crop rectangle can't be changed while streaming. */
if (prev->state != ISP_PIPELINE_STREAM_STOPPED)
return -EBUSY;
- format = __preview_get_format(prev, fh, PREV_PAD_SINK, crop->which);
- preview_try_crop(prev, format, &crop->rect);
- *__preview_get_crop(prev, fh, crop->which) = crop->rect;
+ /* Modifying the crop rectangle always changes the format on the source
+ * pad. If the KEEP_CONFIG flag is set, just return the current crop
+ * rectangle.
+ */
+ if (sel->flags & V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG) {
+ sel->r = *__preview_get_crop(prev, fh, sel->which);
+ return 0;
+ }
+
+ format = __preview_get_format(prev, fh, PREV_PAD_SINK, sel->which);
+ preview_try_crop(prev, format, &sel->r);
+ *__preview_get_crop(prev, fh, sel->which) = sel->r;
/* Update the source format. */
- format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, crop->which);
- preview_try_format(prev, fh, PREV_PAD_SOURCE, format, crop->which);
+ format = __preview_get_format(prev, fh, PREV_PAD_SOURCE, sel->which);
+ preview_try_format(prev, fh, PREV_PAD_SOURCE, format, sel->which);
return 0;
}
@@ -1979,8 +2120,8 @@ static const struct v4l2_subdev_pad_ops preview_v4l2_pad_ops = {
.enum_frame_size = preview_enum_frame_size,
.get_fmt = preview_get_format,
.set_fmt = preview_set_format,
- .get_crop = preview_get_crop,
- .set_crop = preview_set_crop,
+ .get_selection = preview_get_selection,
+ .set_selection = preview_set_selection,
};
/* subdev operations */
@@ -2076,6 +2217,7 @@ static int preview_link_setup(struct media_entity *entity,
/* media operations */
static const struct media_entity_operations preview_media_ops = {
.link_setup = preview_link_setup,
+ .link_validate = v4l2_subdev_link_validate,
};
void omap3isp_preview_unregister_entities(struct isp_prev_device *prev)
@@ -2201,7 +2343,7 @@ error_video_in:
}
/*
- * isp_preview_init - Previewer initialization.
+ * omap3isp_preview_init - Previewer initialization.
* @dev : Pointer to ISP device
* return -ENOMEM or zero on success
*/
@@ -2209,8 +2351,8 @@ int omap3isp_preview_init(struct isp_device *isp)
{
struct isp_prev_device *prev = &isp->isp_prev;
- spin_lock_init(&prev->lock);
init_waitqueue_head(&prev->wait);
+
preview_init_params(prev);
return preview_init_entities(prev);
diff --git a/drivers/media/video/omap3isp/isppreview.h b/drivers/media/video/omap3isp/isppreview.h
index 09686607973c..6663ab64e4b1 100644
--- a/drivers/media/video/omap3isp/isppreview.h
+++ b/drivers/media/video/omap3isp/isppreview.h
@@ -45,29 +45,10 @@
#define ISPPRV_CONTRAST_HIGH 0xFF
#define ISPPRV_CONTRAST_UNITS 0x1
-/* Features list */
-#define PREV_LUMA_ENHANCE OMAP3ISP_PREV_LUMAENH
-#define PREV_INVERSE_ALAW OMAP3ISP_PREV_INVALAW
-#define PREV_HORZ_MEDIAN_FILTER OMAP3ISP_PREV_HRZ_MED
-#define PREV_CFA OMAP3ISP_PREV_CFA
-#define PREV_CHROMA_SUPPRESS OMAP3ISP_PREV_CHROMA_SUPP
-#define PREV_WB OMAP3ISP_PREV_WB
-#define PREV_BLKADJ OMAP3ISP_PREV_BLKADJ
-#define PREV_RGB2RGB OMAP3ISP_PREV_RGB2RGB
-#define PREV_COLOR_CONV OMAP3ISP_PREV_COLOR_CONV
-#define PREV_YCLIMITS OMAP3ISP_PREV_YC_LIMIT
-#define PREV_DEFECT_COR OMAP3ISP_PREV_DEFECT_COR
-#define PREV_GAMMA_BYPASS OMAP3ISP_PREV_GAMMABYPASS
-#define PREV_DARK_FRAME_CAPTURE OMAP3ISP_PREV_DRK_FRM_CAPTURE
-#define PREV_DARK_FRAME_SUBTRACT OMAP3ISP_PREV_DRK_FRM_SUBTRACT
-#define PREV_LENS_SHADING OMAP3ISP_PREV_LENS_SHADING
-#define PREV_NOISE_FILTER OMAP3ISP_PREV_NF
-#define PREV_GAMMA OMAP3ISP_PREV_GAMMA
-
-#define PREV_CONTRAST (1 << 17)
-#define PREV_BRIGHTNESS (1 << 18)
-#define PREV_AVERAGER (1 << 19)
-#define PREV_FEATURES_END (1 << 20)
+/* Additional features not listed in linux/omap3isp.h */
+#define OMAP3ISP_PREV_CONTRAST (1 << 17)
+#define OMAP3ISP_PREV_BRIGHTNESS (1 << 18)
+#define OMAP3ISP_PREV_FEATURES_END (1 << 19)
enum preview_input_entity {
PREVIEW_INPUT_NONE,
@@ -88,6 +69,8 @@ enum preview_ycpos_mode {
/*
* struct prev_params - Structure for all configuration
+ * @busy: Bitmask of busy parameters (being updated or used)
+ * @update: Bitmask of the parameters to be updated
* @features: Set of features enabled.
* @cfa: CFA coefficients.
* @csup: Chroma suppression coefficients.
@@ -96,15 +79,17 @@ enum preview_ycpos_mode {
* @dcor: Noise filter coefficients.
* @gamma: Gamma coefficients.
* @wbal: White Balance parameters.
- * @blk_adj: Black adjustment parameters.
+ * @blkadj: Black adjustment parameters.
* @rgb2rgb: RGB blending parameters.
- * @rgb2ycbcr: RGB to ycbcr parameters.
+ * @csc: Color space conversion (RGB to YCbCr) parameters.
* @hmed: Horizontal median filter.
* @yclimit: YC limits parameters.
* @contrast: Contrast.
* @brightness: Brightness.
*/
struct prev_params {
+ u32 busy;
+ u32 update;
u32 features;
struct omap3isp_prev_cfa cfa;
struct omap3isp_prev_csup csup;
@@ -113,35 +98,15 @@ struct prev_params {
struct omap3isp_prev_dcor dcor;
struct omap3isp_prev_gtables gamma;
struct omap3isp_prev_wbal wbal;
- struct omap3isp_prev_blkadj blk_adj;
+ struct omap3isp_prev_blkadj blkadj;
struct omap3isp_prev_rgbtorgb rgb2rgb;
- struct omap3isp_prev_csc rgb2ycbcr;
+ struct omap3isp_prev_csc csc;
struct omap3isp_prev_hmed hmed;
struct omap3isp_prev_yclimit yclimit;
u8 contrast;
u8 brightness;
};
-/*
- * struct isptables_update - Structure for Table Configuration.
- * @update: Specifies which tables should be updated.
- * @flag: Specifies which tables should be enabled.
- * @nf: Pointer to structure for Noise Filter
- * @lsc: Pointer to LSC gain table. (currently not used)
- * @gamma: Pointer to gamma correction tables.
- * @cfa: Pointer to color filter array configuration.
- * @wbal: Pointer to colour and digital gain configuration.
- */
-struct isptables_update {
- u32 update;
- u32 flag;
- struct omap3isp_prev_nf *nf;
- u32 *lsc;
- struct omap3isp_prev_gtables *gamma;
- struct omap3isp_prev_cfa *cfa;
- struct omap3isp_prev_wbal *wbal;
-};
-
/* Sink and source previewer pads */
#define PREV_PAD_SINK 0
#define PREV_PAD_SOURCE 1
@@ -157,12 +122,11 @@ struct isptables_update {
* @output: Bitmask of the active output
* @video_in: Input video entity
* @video_out: Output video entity
- * @params: Module configuration data
- * @shadow_update: If set, update the hardware configured in the next interrupt
+ * @params.params : Active and shadow parameters sets
+ * @params.active: Bitmask of parameters active in set 0
+ * @params.lock: Parameters lock, protects params.active and params.shadow
* @underrun: Whether the preview entity has queued buffers on the output
* @state: Current preview pipeline state
- * @lock: Shadow update lock
- * @update: Bitmask of the parameters to be updated
*
* This structure is used to store the OMAP ISP Preview module Information.
*/
@@ -179,13 +143,15 @@ struct isp_prev_device {
struct isp_video video_in;
struct isp_video video_out;
- struct prev_params params;
- unsigned int shadow_update:1;
+ struct {
+ struct prev_params params[2];
+ u32 active;
+ spinlock_t lock;
+ } params;
+
enum isp_pipeline_stream_state state;
wait_queue_head_t wait;
atomic_t stopping;
- spinlock_t lock;
- u32 update;
};
struct isp_device;
diff --git a/drivers/media/video/omap3isp/ispqueue.h b/drivers/media/video/omap3isp/ispqueue.h
index 92c5a12157d5..908dfd712e8e 100644
--- a/drivers/media/video/omap3isp/ispqueue.h
+++ b/drivers/media/video/omap3isp/ispqueue.h
@@ -90,7 +90,7 @@ struct isp_video_buffer {
void *vaddr;
/* For userspace buffers. */
- unsigned long vm_flags;
+ vm_flags_t vm_flags;
unsigned long offset;
unsigned int npages;
struct page **pages;
diff --git a/drivers/media/video/omap3isp/ispresizer.c b/drivers/media/video/omap3isp/ispresizer.c
index 6958a9e3dc22..14041c9c8643 100644
--- a/drivers/media/video/omap3isp/ispresizer.c
+++ b/drivers/media/video/omap3isp/ispresizer.c
@@ -1188,32 +1188,6 @@ static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
}
/*
- * resizer_g_crop - handle get crop subdev operation
- * @sd : pointer to v4l2 subdev structure
- * @pad : subdev pad
- * @crop : pointer to crop structure
- * @which : active or try format
- * return zero
- */
-static int resizer_g_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_crop *crop)
-{
- struct isp_res_device *res = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *format;
- struct resizer_ratio ratio;
-
- /* Only sink pad has crop capability */
- if (crop->pad != RESZ_PAD_SINK)
- return -EINVAL;
-
- format = __resizer_get_format(res, fh, RESZ_PAD_SOURCE, crop->which);
- crop->rect = *__resizer_get_crop(res, fh, crop->which);
- resizer_calc_ratios(res, &crop->rect, format, &ratio);
-
- return 0;
-}
-
-/*
* resizer_try_crop - mangles crop parameters.
*/
static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
@@ -1223,7 +1197,7 @@ static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
const unsigned int spv = DEFAULT_PHASE;
const unsigned int sph = DEFAULT_PHASE;
- /* Crop rectangle is constrained to the output size so that zoom ratio
+ /* Crop rectangle is constrained by the output size so that zoom ratio
* cannot exceed +/-4.0.
*/
unsigned int min_width =
@@ -1248,51 +1222,115 @@ static void resizer_try_crop(const struct v4l2_mbus_framefmt *sink,
}
/*
- * resizer_s_crop - handle set crop subdev operation
- * @sd : pointer to v4l2 subdev structure
- * @pad : subdev pad
- * @crop : pointer to crop structure
- * @which : active or try format
- * return -EINVAL or zero when succeed
+ * resizer_get_selection - Retrieve a selection rectangle on a pad
+ * @sd: ISP resizer V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangles are the crop rectangles on the sink pad.
+ *
+ * Return 0 on success or a negative error code otherwise.
*/
-static int resizer_s_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_crop *crop)
+static int resizer_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
+{
+ struct isp_res_device *res = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *format_source;
+ struct v4l2_mbus_framefmt *format_sink;
+ struct resizer_ratio ratio;
+
+ if (sel->pad != RESZ_PAD_SINK)
+ return -EINVAL;
+
+ format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
+ sel->which);
+ format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
+ sel->which);
+
+ switch (sel->target) {
+ case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = INT_MAX;
+ sel->r.height = INT_MAX;
+
+ resizer_try_crop(format_sink, format_source, &sel->r);
+ resizer_calc_ratios(res, &sel->r, format_source, &ratio);
+ break;
+
+ case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+ sel->r = *__resizer_get_crop(res, fh, sel->which);
+ resizer_calc_ratios(res, &sel->r, format_source, &ratio);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * resizer_set_selection - Set a selection rectangle on a pad
+ * @sd: ISP resizer V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ * @sel: Selection rectangle
+ *
+ * The only supported rectangle is the actual crop rectangle on the sink pad.
+ *
+ * FIXME: This function currently behaves as if the KEEP_CONFIG selection flag
+ * was always set.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static int resizer_set_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
{
struct isp_res_device *res = v4l2_get_subdevdata(sd);
struct isp_device *isp = to_isp_device(res);
struct v4l2_mbus_framefmt *format_sink, *format_source;
struct resizer_ratio ratio;
- /* Only sink pad has crop capability */
- if (crop->pad != RESZ_PAD_SINK)
+ if (sel->target != V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL ||
+ sel->pad != RESZ_PAD_SINK)
return -EINVAL;
format_sink = __resizer_get_format(res, fh, RESZ_PAD_SINK,
- crop->which);
+ sel->which);
format_source = __resizer_get_format(res, fh, RESZ_PAD_SOURCE,
- crop->which);
+ sel->which);
dev_dbg(isp->dev, "%s: L=%d,T=%d,W=%d,H=%d,which=%d\n", __func__,
- crop->rect.left, crop->rect.top, crop->rect.width,
- crop->rect.height, crop->which);
+ sel->r.left, sel->r.top, sel->r.width, sel->r.height,
+ sel->which);
dev_dbg(isp->dev, "%s: input=%dx%d, output=%dx%d\n", __func__,
format_sink->width, format_sink->height,
format_source->width, format_source->height);
- resizer_try_crop(format_sink, format_source, &crop->rect);
- *__resizer_get_crop(res, fh, crop->which) = crop->rect;
- resizer_calc_ratios(res, &crop->rect, format_source, &ratio);
+ /* Clamp the crop rectangle to the bounds, and then mangle it further to
+ * fulfill the TRM equations. Store the clamped but otherwise unmangled
+ * rectangle to avoid cropping the input multiple times: when an
+ * application sets the output format, the current crop rectangle is
+ * mangled during crop rectangle computation, which would lead to a new,
+ * smaller input crop rectangle every time the output size is set if we
+ * stored the mangled rectangle.
+ */
+ resizer_try_crop(format_sink, format_source, &sel->r);
+ *__resizer_get_crop(res, fh, sel->which) = sel->r;
+ resizer_calc_ratios(res, &sel->r, format_source, &ratio);
- if (crop->which == V4L2_SUBDEV_FORMAT_TRY)
+ if (sel->which == V4L2_SUBDEV_FORMAT_TRY)
return 0;
res->ratio = ratio;
- res->crop.active = crop->rect;
+ res->crop.active = sel->r;
/*
- * s_crop can be called while streaming is on. In this case
- * the crop values will be set in the next IRQ.
+ * set_selection can be called while streaming is on. In this case the
+ * crop values will be set in the next IRQ.
*/
if (res->state != ISP_PIPELINE_STREAM_STOPPED)
res->applycrop = 1;
@@ -1530,8 +1568,8 @@ static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
.enum_frame_size = resizer_enum_frame_size,
.get_fmt = resizer_get_format,
.set_fmt = resizer_set_format,
- .get_crop = resizer_g_crop,
- .set_crop = resizer_s_crop,
+ .get_selection = resizer_get_selection,
+ .set_selection = resizer_set_selection,
};
/* subdev operations */
@@ -1603,6 +1641,7 @@ static int resizer_link_setup(struct media_entity *entity,
/* media operations */
static const struct media_entity_operations resizer_media_ops = {
.link_setup = resizer_link_setup,
+ .link_validate = v4l2_subdev_link_validate,
};
void omap3isp_resizer_unregister_entities(struct isp_res_device *res)
diff --git a/drivers/media/video/omap3isp/ispstat.c b/drivers/media/video/omap3isp/ispstat.c
index 11871ecc6d25..b8640be692f1 100644
--- a/drivers/media/video/omap3isp/ispstat.c
+++ b/drivers/media/video/omap3isp/ispstat.c
@@ -1032,7 +1032,7 @@ int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev,
if (sub->type != stat->event_type)
return -EINVAL;
- return v4l2_event_subscribe(fh, sub, STAT_NEVENTS);
+ return v4l2_event_subscribe(fh, sub, STAT_NEVENTS, NULL);
}
int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev,
diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c
index b02070057724..b37379d39cdd 100644
--- a/drivers/media/video/omap3isp/ispvideo.c
+++ b/drivers/media/video/omap3isp/ispvideo.c
@@ -46,6 +46,10 @@
* Helper functions
*/
+/*
+ * NOTE: When adding new media bus codes, always remember to add
+ * corresponding in-memory formats to the table below!!!
+ */
static struct isp_format_info formats[] = {
{ V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
@@ -68,9 +72,18 @@ static struct isp_format_info formats[] = {
{ V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
V4L2_PIX_FMT_SRGGB8, 8, },
+ { V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8, V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8,
+ V4L2_MBUS_FMT_SBGGR10_1X10, 0,
+ V4L2_PIX_FMT_SBGGR10DPCM8, 8, },
+ { V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8, V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8,
+ V4L2_MBUS_FMT_SGBRG10_1X10, 0,
+ V4L2_PIX_FMT_SGBRG10DPCM8, 8, },
{ V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
V4L2_MBUS_FMT_SGRBG10_1X10, 0,
V4L2_PIX_FMT_SGRBG10DPCM8, 8, },
+ { V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8, V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8,
+ V4L2_MBUS_FMT_SRGGB10_1X10, 0,
+ V4L2_PIX_FMT_SRGGB10DPCM8, 8, },
{ V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10,
V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR8_1X8,
V4L2_PIX_FMT_SBGGR10, 10, },
@@ -117,37 +130,6 @@ omap3isp_video_format_info(enum v4l2_mbus_pixelcode code)
}
/*
- * Decide whether desired output pixel code can be obtained with
- * the lane shifter by shifting the input pixel code.
- * @in: input pixelcode to shifter
- * @out: output pixelcode from shifter
- * @additional_shift: # of bits the sensor's LSB is offset from CAMEXT[0]
- *
- * return true if the combination is possible
- * return false otherwise
- */
-static bool isp_video_is_shiftable(enum v4l2_mbus_pixelcode in,
- enum v4l2_mbus_pixelcode out,
- unsigned int additional_shift)
-{
- const struct isp_format_info *in_info, *out_info;
-
- if (in == out)
- return true;
-
- in_info = omap3isp_video_format_info(in);
- out_info = omap3isp_video_format_info(out);
-
- if ((in_info->flavor == 0) || (out_info->flavor == 0))
- return false;
-
- if (in_info->flavor != out_info->flavor)
- return false;
-
- return in_info->bpp - out_info->bpp + additional_shift <= 6;
-}
-
-/*
* isp_video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format
* @video: ISP video instance
* @mbus: v4l2_mbus_framefmt format (input)
@@ -242,8 +224,8 @@ isp_video_remote_subdev(struct isp_video *video, u32 *pad)
}
/* Return a pointer to the ISP video instance at the far end of the pipeline. */
-static struct isp_video *
-isp_video_far_end(struct isp_video *video)
+static int isp_video_get_graph_data(struct isp_video *video,
+ struct isp_pipeline *pipe)
{
struct media_entity_graph graph;
struct media_entity *entity = &video->video.entity;
@@ -254,21 +236,38 @@ isp_video_far_end(struct isp_video *video)
media_entity_graph_walk_start(&graph, entity);
while ((entity = media_entity_graph_walk_next(&graph))) {
+ struct isp_video *__video;
+
+ pipe->entities |= 1 << entity->id;
+
+ if (far_end != NULL)
+ continue;
+
if (entity == &video->video.entity)
continue;
if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
continue;
- far_end = to_isp_video(media_entity_to_video_device(entity));
- if (far_end->type != video->type)
- break;
-
- far_end = NULL;
+ __video = to_isp_video(media_entity_to_video_device(entity));
+ if (__video->type != video->type)
+ far_end = __video;
}
mutex_unlock(&mdev->graph_mutex);
- return far_end;
+
+ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ pipe->input = far_end;
+ pipe->output = video;
+ } else {
+ if (far_end == NULL)
+ return -EPIPE;
+
+ pipe->input = video;
+ pipe->output = far_end;
+ }
+
+ return 0;
}
/*
@@ -285,52 +284,24 @@ isp_video_far_end(struct isp_video *video)
static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
{
struct isp_device *isp = pipe->output->isp;
- struct v4l2_subdev_format fmt_source;
- struct v4l2_subdev_format fmt_sink;
struct media_pad *pad;
struct v4l2_subdev *subdev;
- int ret;
-
- pipe->max_rate = pipe->l3_ick;
subdev = isp_video_remote_subdev(pipe->output, NULL);
if (subdev == NULL)
return -EPIPE;
while (1) {
- unsigned int shifter_link;
/* Retrieve the sink format */
pad = &subdev->entity.pads[0];
if (!(pad->flags & MEDIA_PAD_FL_SINK))
break;
- fmt_sink.pad = pad->index;
- fmt_sink.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_sink);
- if (ret < 0 && ret != -ENOIOCTLCMD)
- return -EPIPE;
-
/* Update the maximum frame rate */
if (subdev == &isp->isp_res.subdev)
omap3isp_resizer_max_rate(&isp->isp_res,
&pipe->max_rate);
- /* Check ccdc maximum data rate when data comes from sensor
- * TODO: Include ccdc rate in pipe->max_rate and compare the
- * total pipe rate with the input data rate from sensor.
- */
- if (subdev == &isp->isp_ccdc.subdev && pipe->input == NULL) {
- unsigned int rate = UINT_MAX;
-
- omap3isp_ccdc_max_rate(&isp->isp_ccdc, &rate);
- if (isp->isp_ccdc.vpcfg.pixelclk > rate)
- return -ENOSPC;
- }
-
- /* If sink pad is on CCDC, the link has the lane shifter
- * in the middle of it. */
- shifter_link = subdev == &isp->isp_ccdc.subdev;
-
/* Retrieve the source format. Return an error if no source
* entity can be found, and stop checking the pipeline if the
* source entity isn't a subdev.
@@ -343,32 +314,6 @@ static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
break;
subdev = media_entity_to_v4l2_subdev(pad->entity);
-
- fmt_source.pad = pad->index;
- fmt_source.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_source);
- if (ret < 0 && ret != -ENOIOCTLCMD)
- return -EPIPE;
-
- /* Check if the two ends match */
- if (fmt_source.format.width != fmt_sink.format.width ||
- fmt_source.format.height != fmt_sink.format.height)
- return -EPIPE;
-
- if (shifter_link) {
- unsigned int parallel_shift = 0;
- if (isp->isp_ccdc.input == CCDC_INPUT_PARALLEL) {
- struct isp_parallel_platform_data *pdata =
- &((struct isp_v4l2_subdevs_group *)
- subdev->host_priv)->bus.parallel;
- parallel_shift = pdata->data_lane_shift * 2;
- }
- if (!isp_video_is_shiftable(fmt_source.format.code,
- fmt_sink.format.code,
- parallel_shift))
- return -EPIPE;
- } else if (fmt_source.format.code != fmt_sink.format.code)
- return -EPIPE;
}
return 0;
@@ -923,6 +868,92 @@ isp_video_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
file->f_flags & O_NONBLOCK);
}
+static int isp_video_check_external_subdevs(struct isp_video *video,
+ struct isp_pipeline *pipe)
+{
+ struct isp_device *isp = video->isp;
+ struct media_entity *ents[] = {
+ &isp->isp_csi2a.subdev.entity,
+ &isp->isp_csi2c.subdev.entity,
+ &isp->isp_ccp2.subdev.entity,
+ &isp->isp_ccdc.subdev.entity
+ };
+ struct media_pad *source_pad;
+ struct media_entity *source = NULL;
+ struct media_entity *sink;
+ struct v4l2_subdev_format fmt;
+ struct v4l2_ext_controls ctrls;
+ struct v4l2_ext_control ctrl;
+ unsigned int i;
+ int ret = 0;
+
+ for (i = 0; i < ARRAY_SIZE(ents); i++) {
+ /* Is the entity part of the pipeline? */
+ if (!(pipe->entities & (1 << ents[i]->id)))
+ continue;
+
+ /* ISP entities have always sink pad == 0. Find source. */
+ source_pad = media_entity_remote_source(&ents[i]->pads[0]);
+ if (source_pad == NULL)
+ continue;
+
+ source = source_pad->entity;
+ sink = ents[i];
+ break;
+ }
+
+ if (!source) {
+ dev_warn(isp->dev, "can't find source, failing now\n");
+ return ret;
+ }
+
+ if (media_entity_type(source) != MEDIA_ENT_T_V4L2_SUBDEV)
+ return 0;
+
+ pipe->external = media_entity_to_v4l2_subdev(source);
+
+ fmt.pad = source_pad->index;
+ fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ ret = v4l2_subdev_call(media_entity_to_v4l2_subdev(sink),
+ pad, get_fmt, NULL, &fmt);
+ if (unlikely(ret < 0)) {
+ dev_warn(isp->dev, "get_fmt returned null!\n");
+ return ret;
+ }
+
+ pipe->external_bpp = omap3isp_video_format_info(fmt.format.code)->bpp;
+
+ memset(&ctrls, 0, sizeof(ctrls));
+ memset(&ctrl, 0, sizeof(ctrl));
+
+ ctrl.id = V4L2_CID_PIXEL_RATE;
+
+ ctrls.count = 1;
+ ctrls.controls = &ctrl;
+
+ ret = v4l2_g_ext_ctrls(pipe->external->ctrl_handler, &ctrls);
+ if (ret < 0) {
+ dev_warn(isp->dev, "no pixel rate control in subdev %s\n",
+ pipe->external->name);
+ return ret;
+ }
+
+ pipe->external_rate = ctrl.value64;
+
+ if (pipe->entities & (1 << isp->isp_ccdc.subdev.entity.id)) {
+ unsigned int rate = UINT_MAX;
+ /*
+ * Check that maximum allowed CCDC pixel rate isn't
+ * exceeded by the pixel rate.
+ */
+ omap3isp_ccdc_max_rate(&isp->isp_ccdc, &rate);
+ if (pipe->external_rate > rate)
+ return -ENOSPC;
+ }
+
+ return 0;
+}
+
/*
* Stream management
*
@@ -961,7 +992,6 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
struct isp_video *video = video_drvdata(file);
enum isp_pipeline_state state;
struct isp_pipeline *pipe;
- struct isp_video *far_end;
unsigned long flags;
int ret;
@@ -980,46 +1010,45 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
*/
pipe = video->video.entity.pipe
? to_isp_pipeline(&video->video.entity) : &video->pipe;
- media_entity_pipeline_start(&video->video.entity, &pipe->pipe);
+
+ pipe->entities = 0;
+
+ if (video->isp->pdata->set_constraints)
+ video->isp->pdata->set_constraints(video->isp, true);
+ pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]);
+ pipe->max_rate = pipe->l3_ick;
+
+ ret = media_entity_pipeline_start(&video->video.entity, &pipe->pipe);
+ if (ret < 0)
+ goto err_pipeline_start;
/* Verify that the currently configured format matches the output of
* the connected subdev.
*/
ret = isp_video_check_format(video, vfh);
if (ret < 0)
- goto error;
+ goto err_check_format;
video->bpl_padding = ret;
video->bpl_value = vfh->format.fmt.pix.bytesperline;
- /* Find the ISP video node connected at the far end of the pipeline and
- * update the pipeline.
- */
- far_end = isp_video_far_end(video);
+ ret = isp_video_get_graph_data(video, pipe);
+ if (ret < 0)
+ goto err_check_format;
- if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
state = ISP_PIPELINE_STREAM_OUTPUT | ISP_PIPELINE_IDLE_OUTPUT;
- pipe->input = far_end;
- pipe->output = video;
- } else {
- if (far_end == NULL) {
- ret = -EPIPE;
- goto error;
- }
-
+ else
state = ISP_PIPELINE_STREAM_INPUT | ISP_PIPELINE_IDLE_INPUT;
- pipe->input = video;
- pipe->output = far_end;
- }
- if (video->isp->pdata->set_constraints)
- video->isp->pdata->set_constraints(video->isp, true);
- pipe->l3_ick = clk_get_rate(video->isp->clock[ISP_CLK_L3_ICK]);
+ ret = isp_video_check_external_subdevs(video, pipe);
+ if (ret < 0)
+ goto err_check_format;
/* Validate the pipeline and update its state. */
ret = isp_video_validate_pipeline(pipe);
if (ret < 0)
- goto error;
+ goto err_check_format;
pipe->error = false;
@@ -1041,7 +1070,7 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
ret = omap3isp_video_queue_streamon(&vfh->queue);
if (ret < 0)
- goto error;
+ goto err_check_format;
/* In sensor-to-memory mode, the stream can be started synchronously
* to the stream on command. In memory-to-memory mode, it will be
@@ -1051,32 +1080,34 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
ret = omap3isp_pipeline_set_stream(pipe,
ISP_PIPELINE_STREAM_CONTINUOUS);
if (ret < 0)
- goto error;
+ goto err_set_stream;
spin_lock_irqsave(&video->queue->irqlock, flags);
if (list_empty(&video->dmaqueue))
video->dmaqueue_flags |= ISP_VIDEO_DMAQUEUE_UNDERRUN;
spin_unlock_irqrestore(&video->queue->irqlock, flags);
}
-error:
- if (ret < 0) {
- omap3isp_video_queue_streamoff(&vfh->queue);
- if (video->isp->pdata->set_constraints)
- video->isp->pdata->set_constraints(video->isp, false);
- media_entity_pipeline_stop(&video->video.entity);
- /* The DMA queue must be emptied here, otherwise CCDC interrupts
- * that will get triggered the next time the CCDC is powered up
- * will try to access buffers that might have been freed but
- * still present in the DMA queue. This can easily get triggered
- * if the above omap3isp_pipeline_set_stream() call fails on a
- * system with a free-running sensor.
- */
- INIT_LIST_HEAD(&video->dmaqueue);
- video->queue = NULL;
- }
+ video->streaming = 1;
+
+ mutex_unlock(&video->stream_lock);
+ return 0;
- if (!ret)
- video->streaming = 1;
+err_set_stream:
+ omap3isp_video_queue_streamoff(&vfh->queue);
+err_check_format:
+ media_entity_pipeline_stop(&video->video.entity);
+err_pipeline_start:
+ if (video->isp->pdata->set_constraints)
+ video->isp->pdata->set_constraints(video->isp, false);
+ /* The DMA queue must be emptied here, otherwise CCDC interrupts that
+ * will get triggered the next time the CCDC is powered up will try to
+ * access buffers that might have been freed but still present in the
+ * DMA queue. This can easily get triggered if the above
+ * omap3isp_pipeline_set_stream() call fails on a system with a
+ * free-running sensor.
+ */
+ INIT_LIST_HEAD(&video->dmaqueue);
+ video->queue = NULL;
mutex_unlock(&video->stream_lock);
return ret;
diff --git a/drivers/media/video/omap3isp/ispvideo.h b/drivers/media/video/omap3isp/ispvideo.h
index d91bdb919be0..5acc909500ec 100644
--- a/drivers/media/video/omap3isp/ispvideo.h
+++ b/drivers/media/video/omap3isp/ispvideo.h
@@ -88,6 +88,7 @@ enum isp_pipeline_state {
/*
* struct isp_pipeline - An ISP hardware pipeline
* @error: A hardware error occurred during capture
+ * @entities: Bitmask of entities in the pipeline (indexed by entity ID)
*/
struct isp_pipeline {
struct media_pipeline pipe;
@@ -96,12 +97,16 @@ struct isp_pipeline {
enum isp_pipeline_stream_state stream_state;
struct isp_video *input;
struct isp_video *output;
+ u32 entities;
unsigned long l3_ick;
unsigned int max_rate;
atomic_t frame_number;
bool do_propagation; /* of frame number */
bool error;
struct v4l2_fract max_timeperframe;
+ struct v4l2_subdev *external;
+ unsigned int external_rate;
+ unsigned int external_bpp;
};
#define to_isp_pipeline(__e) \
diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c
index 80e07794ac8e..0bc93313d37a 100644
--- a/drivers/media/video/ov5642.c
+++ b/drivers/media/video/ov5642.c
@@ -1025,8 +1025,6 @@ static int ov5642_probe(struct i2c_client *client,
priv->crop_rect.height = OV5642_DEFAULT_HEIGHT;
priv->crop_rect.left = (OV5642_MAX_WIDTH - OV5642_DEFAULT_WIDTH) / 2;
priv->crop_rect.top = (OV5642_MAX_HEIGHT - OV5642_DEFAULT_HEIGHT) / 2;
- priv->crop_rect.width = OV5642_DEFAULT_WIDTH;
- priv->crop_rect.height = OV5642_DEFAULT_HEIGHT;
priv->total_width = OV5642_DEFAULT_WIDTH + BLANKING_EXTRA_WIDTH;
priv->total_height = BLANKING_MIN_HEIGHT;
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
index e753b5e4d2ce..af2d9086d7e8 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/video/pms.c
@@ -30,15 +30,19 @@
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
+#include <linux/isa.h>
#include <asm/io.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
#include <media/v4l2-device.h>
MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.4");
+MODULE_VERSION("0.0.5");
#define MOTOROLA 1
#define PHILIPS2 2 /* SAA7191 */
@@ -55,11 +59,11 @@ struct i2c_info {
struct pms {
struct v4l2_device v4l2_dev;
struct video_device vdev;
+ struct v4l2_ctrl_handler hdl;
int height;
int width;
int depth;
int input;
- s32 brightness, saturation, hue, contrast;
struct mutex lock;
int i2c_count;
struct i2c_info i2cinfo[64];
@@ -72,8 +76,6 @@ struct pms {
void __iomem *mem;
};
-static struct pms pms_card;
-
/*
* I/O ports and Shared Memory
*/
@@ -676,8 +678,10 @@ static int pms_querycap(struct file *file, void *priv,
strlcpy(vcap->driver, dev->v4l2_dev.name, sizeof(vcap->driver));
strlcpy(vcap->card, "Mediavision PMS", sizeof(vcap->card));
- strlcpy(vcap->bus_info, "ISA", sizeof(vcap->bus_info));
- vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ snprintf(vcap->bus_info, sizeof(vcap->bus_info),
+ "ISA:%s", dev->v4l2_dev.name);
+ vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -716,11 +720,9 @@ static int pms_s_input(struct file *file, void *fh, unsigned int inp)
if (inp > 3)
return -EINVAL;
- mutex_lock(&dev->lock);
dev->input = inp;
pms_videosource(dev, inp & 1);
pms_vcrinput(dev, inp >> 1);
- mutex_unlock(&dev->lock);
return 0;
}
@@ -738,7 +740,6 @@ static int pms_s_std(struct file *file, void *fh, v4l2_std_id *std)
int ret = 0;
dev->std = *std;
- mutex_lock(&dev->lock);
if (dev->std & V4L2_STD_NTSC) {
pms_framerate(dev, 30);
pms_secamcross(dev, 0);
@@ -762,81 +763,31 @@ static int pms_s_std(struct file *file, void *fh, v4l2_std_id *std)
pms_format(dev, 0);
break;
}*/
- mutex_unlock(&dev->lock);
- return 0;
-}
-
-static int pms_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- switch (qc->id) {
- case V4L2_CID_BRIGHTNESS:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 139);
- case V4L2_CID_CONTRAST:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 70);
- case V4L2_CID_SATURATION:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 64);
- case V4L2_CID_HUE:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 0);
- }
- return -EINVAL;
-}
-
-static int pms_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct pms *dev = video_drvdata(file);
- int ret = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- ctrl->value = dev->brightness;
- break;
- case V4L2_CID_CONTRAST:
- ctrl->value = dev->contrast;
- break;
- case V4L2_CID_SATURATION:
- ctrl->value = dev->saturation;
- break;
- case V4L2_CID_HUE:
- ctrl->value = dev->hue;
- break;
- default:
- ret = -EINVAL;
- break;
- }
return ret;
}
-static int pms_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
+static int pms_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct pms *dev = video_drvdata(file);
+ struct pms *dev = container_of(ctrl->handler, struct pms, hdl);
int ret = 0;
- mutex_lock(&dev->lock);
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- dev->brightness = ctrl->value;
- pms_brightness(dev, dev->brightness);
+ pms_brightness(dev, ctrl->val);
break;
case V4L2_CID_CONTRAST:
- dev->contrast = ctrl->value;
- pms_contrast(dev, dev->contrast);
+ pms_contrast(dev, ctrl->val);
break;
case V4L2_CID_SATURATION:
- dev->saturation = ctrl->value;
- pms_saturation(dev, dev->saturation);
+ pms_saturation(dev, ctrl->val);
break;
case V4L2_CID_HUE:
- dev->hue = ctrl->value;
- pms_hue(dev, dev->hue);
+ pms_hue(dev, ctrl->val);
break;
default:
ret = -EINVAL;
break;
}
- mutex_unlock(&dev->lock);
return ret;
}
@@ -884,13 +835,11 @@ static int pms_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fm
if (ret)
return ret;
- mutex_lock(&dev->lock);
dev->width = pix->width;
dev->height = pix->height;
dev->depth = (pix->pixelformat == V4L2_PIX_FMT_RGB555) ? 15 : 16;
pms_resolution(dev, dev->width, dev->height);
/* Ok we figured out what to use from our wide choice */
- mutex_unlock(&dev->lock);
return 0;
}
@@ -901,7 +850,7 @@ static int pms_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc
"RGB 5:5:5", V4L2_PIX_FMT_RGB555,
{ 0, 0, 0, 0 }
},
- { 0, 0, 0,
+ { 1, 0, 0,
"RGB 5:6:5", V4L2_PIX_FMT_RGB565,
{ 0, 0, 0, 0 }
},
@@ -922,32 +871,43 @@ static ssize_t pms_read(struct file *file, char __user *buf,
struct pms *dev = video_drvdata(file);
int len;
- mutex_lock(&dev->lock);
len = pms_capture(dev, buf, (dev->depth == 15), count);
- mutex_unlock(&dev->lock);
return len;
}
+static unsigned int pms_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct v4l2_fh *fh = file->private_data;
+ unsigned int res = POLLIN | POLLRDNORM;
+
+ if (v4l2_event_pending(fh))
+ res |= POLLPRI;
+ poll_wait(file, &fh->wait, wait);
+ return res;
+}
+
static const struct v4l2_file_operations pms_fops = {
.owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = v4l2_fh_release,
+ .poll = pms_poll,
.unlocked_ioctl = video_ioctl2,
.read = pms_read,
};
static const struct v4l2_ioctl_ops pms_ioctl_ops = {
- .vidioc_querycap = pms_querycap,
- .vidioc_g_input = pms_g_input,
- .vidioc_s_input = pms_s_input,
- .vidioc_enum_input = pms_enum_input,
- .vidioc_g_std = pms_g_std,
- .vidioc_s_std = pms_s_std,
- .vidioc_queryctrl = pms_queryctrl,
- .vidioc_g_ctrl = pms_g_ctrl,
- .vidioc_s_ctrl = pms_s_ctrl,
- .vidioc_enum_fmt_vid_cap = pms_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = pms_g_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = pms_s_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = pms_try_fmt_vid_cap,
+ .vidioc_querycap = pms_querycap,
+ .vidioc_g_input = pms_g_input,
+ .vidioc_s_input = pms_s_input,
+ .vidioc_enum_input = pms_enum_input,
+ .vidioc_g_std = pms_g_std,
+ .vidioc_s_std = pms_s_std,
+ .vidioc_enum_fmt_vid_cap = pms_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = pms_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = pms_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = pms_try_fmt_vid_cap,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
/*
@@ -956,7 +916,6 @@ static const struct v4l2_ioctl_ops pms_ioctl_ops = {
static int init_mediavision(struct pms *dev)
{
- int id;
int idec, decst;
int i;
static const unsigned char i2c_defs[] = {
@@ -988,7 +947,6 @@ static int init_mediavision(struct pms *dev)
outb(dev->io >> 4, 0x9a01); /* Set IO port */
- id = mvv_read(dev, 3);
decst = pms_i2c_stat(dev, 0x43);
if (decst != -1)
@@ -1068,76 +1026,125 @@ static int enable;
module_param(enable, int, 0);
#endif
-static int __init pms_init(void)
+static const struct v4l2_ctrl_ops pms_ctrl_ops = {
+ .s_ctrl = pms_s_ctrl,
+};
+
+static int pms_probe(struct device *pdev, unsigned int card)
{
- struct pms *dev = &pms_card;
- struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
+ struct pms *dev;
+ struct v4l2_device *v4l2_dev;
+ struct v4l2_ctrl_handler *hdl;
int res;
- strlcpy(v4l2_dev->name, "pms", sizeof(v4l2_dev->name));
-
- v4l2_info(v4l2_dev, "Mediavision Pro Movie Studio driver 0.03\n");
-
#ifndef MODULE
if (!enable) {
- v4l2_err(v4l2_dev,
- "PMS: not enabled, use pms.enable=1 to probe\n");
+ pr_err("PMS: not enabled, use pms.enable=1 to probe\n");
return -ENODEV;
}
#endif
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL)
+ return -ENOMEM;
+
dev->decoder = PHILIPS2;
dev->io = io_port;
dev->data = io_port + 1;
+ v4l2_dev = &dev->v4l2_dev;
+ hdl = &dev->hdl;
- if (init_mediavision(dev)) {
+ res = v4l2_device_register(pdev, v4l2_dev);
+ if (res < 0) {
+ v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+ goto free_dev;
+ }
+ v4l2_info(v4l2_dev, "Mediavision Pro Movie Studio driver 0.05\n");
+
+ res = init_mediavision(dev);
+ if (res) {
v4l2_err(v4l2_dev, "Board not found.\n");
- return -ENODEV;
+ goto free_io;
}
- res = v4l2_device_register(NULL, v4l2_dev);
- if (res < 0) {
- v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
- return res;
+ v4l2_ctrl_handler_init(hdl, 4);
+ v4l2_ctrl_new_std(hdl, &pms_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 139);
+ v4l2_ctrl_new_std(hdl, &pms_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1, 70);
+ v4l2_ctrl_new_std(hdl, &pms_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 255, 1, 64);
+ v4l2_ctrl_new_std(hdl, &pms_ctrl_ops,
+ V4L2_CID_HUE, 0, 255, 1, 0);
+ if (hdl->error) {
+ res = hdl->error;
+ goto free_hdl;
}
+ mutex_init(&dev->lock);
strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
dev->vdev.v4l2_dev = v4l2_dev;
+ dev->vdev.ctrl_handler = hdl;
dev->vdev.fops = &pms_fops;
dev->vdev.ioctl_ops = &pms_ioctl_ops;
dev->vdev.release = video_device_release_empty;
+ dev->vdev.lock = &dev->lock;
+ dev->vdev.tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
+ set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev.flags);
video_set_drvdata(&dev->vdev, dev);
- mutex_init(&dev->lock);
dev->std = V4L2_STD_NTSC_M;
dev->height = 240;
dev->width = 320;
- dev->depth = 15;
- dev->brightness = 139;
- dev->contrast = 70;
- dev->hue = 0;
- dev->saturation = 64;
+ dev->depth = 16;
pms_swsense(dev, 75);
pms_resolution(dev, 320, 240);
pms_videosource(dev, 0);
pms_vcrinput(dev, 0);
- if (video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
- v4l2_device_unregister(&dev->v4l2_dev);
- release_region(dev->io, 3);
- release_region(0x9a01, 1);
- iounmap(dev->mem);
- return -EINVAL;
- }
- return 0;
+ v4l2_ctrl_handler_setup(hdl);
+ res = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr);
+ if (res >= 0)
+ return 0;
+
+free_hdl:
+ v4l2_ctrl_handler_free(hdl);
+ v4l2_device_unregister(&dev->v4l2_dev);
+free_io:
+ release_region(dev->io, 3);
+ release_region(0x9a01, 1);
+ iounmap(dev->mem);
+free_dev:
+ kfree(dev);
+ return res;
}
-static void __exit pms_exit(void)
+static int pms_remove(struct device *pdev, unsigned int card)
{
- struct pms *dev = &pms_card;
+ struct pms *dev = dev_get_drvdata(pdev);
video_unregister_device(&dev->vdev);
+ v4l2_ctrl_handler_free(&dev->hdl);
release_region(dev->io, 3);
release_region(0x9a01, 1);
iounmap(dev->mem);
+ return 0;
+}
+
+static struct isa_driver pms_driver = {
+ .probe = pms_probe,
+ .remove = pms_remove,
+ .driver = {
+ .name = "pms",
+ },
+};
+
+static int __init pms_init(void)
+{
+ return isa_register_driver(&pms_driver, 1);
+}
+
+static void __exit pms_exit(void)
+{
+ isa_unregister_driver(&pms_driver);
}
module_init(pms_init);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index 305e6aaa844a..036952f2a3cb 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -317,18 +317,16 @@ struct pvr2_hdw {
v4l2_std_id std_mask_eeprom; // Hardware supported selections
v4l2_std_id std_mask_avail; // Which standards we may select from
v4l2_std_id std_mask_cur; // Currently selected standard(s)
- unsigned int std_enum_cnt; // # of enumerated standards
int std_enum_cur; // selected standard enumeration value
int std_dirty; // True if std_mask_cur has changed
struct pvr2_ctl_info std_info_enum;
struct pvr2_ctl_info std_info_avail;
struct pvr2_ctl_info std_info_cur;
- struct v4l2_standard *std_defs;
- const char **std_enum_names;
+ struct pvr2_ctl_info std_info_detect;
// Generated string names, one per actual V4L2 standard
const char *std_mask_ptrs[32];
- char std_mask_names[32][10];
+ char std_mask_names[32][16];
int unit_number; /* ID for driver instance */
unsigned long serial_number; /* ID for hardware itself */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index ebc2c7e39233..fb828ba1dbbe 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -334,8 +334,6 @@ static void pvr2_hdw_state_log_state(struct pvr2_hdw *);
static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl);
static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw);
static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw);
-static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw);
-static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw);
static void pvr2_hdw_quiescent_timeout(unsigned long);
static void pvr2_hdw_decoder_stabilization_timeout(unsigned long);
static void pvr2_hdw_encoder_wait_timeout(unsigned long);
@@ -346,7 +344,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
void *write_data,unsigned int write_len,
void *read_data,unsigned int read_len);
static int pvr2_hdw_check_cropcap(struct pvr2_hdw *hdw);
-
+static v4l2_std_id pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw);
static void trace_stbit(const char *name,int val)
{
@@ -840,6 +838,12 @@ static int ctrl_hsm_get(struct pvr2_ctrl *cptr,int *vp)
return 0;
}
+static int ctrl_stddetect_get(struct pvr2_ctrl *cptr, int *vp)
+{
+ *vp = pvr2_hdw_get_detected_std(cptr->hdw);
+ return 0;
+}
+
static int ctrl_stdavail_get(struct pvr2_ctrl *cptr,int *vp)
{
*vp = cptr->hdw->std_mask_avail;
@@ -854,8 +858,7 @@ static int ctrl_stdavail_set(struct pvr2_ctrl *cptr,int m,int v)
ns = (ns & ~m) | (v & m);
if (ns == hdw->std_mask_avail) return 0;
hdw->std_mask_avail = ns;
- pvr2_hdw_internal_set_std_avail(hdw);
- pvr2_hdw_internal_find_stdenum(hdw);
+ hdw->std_info_cur.def.type_bitmask.valid_bits = hdw->std_mask_avail;
return 0;
}
@@ -895,7 +898,6 @@ static int ctrl_stdcur_set(struct pvr2_ctrl *cptr,int m,int v)
if (ns == hdw->std_mask_cur) return 0;
hdw->std_mask_cur = ns;
hdw->std_dirty = !0;
- pvr2_hdw_internal_find_stdenum(hdw);
return 0;
}
@@ -941,40 +943,6 @@ static int ctrl_audio_modes_present_get(struct pvr2_ctrl *cptr,int *vp)
}
-static int ctrl_stdenumcur_set(struct pvr2_ctrl *cptr,int m,int v)
-{
- struct pvr2_hdw *hdw = cptr->hdw;
- if (v < 0) return -EINVAL;
- if (v > hdw->std_enum_cnt) return -EINVAL;
- hdw->std_enum_cur = v;
- if (!v) return 0;
- v--;
- if (hdw->std_mask_cur == hdw->std_defs[v].id) return 0;
- hdw->std_mask_cur = hdw->std_defs[v].id;
- hdw->std_dirty = !0;
- return 0;
-}
-
-
-static int ctrl_stdenumcur_get(struct pvr2_ctrl *cptr,int *vp)
-{
- *vp = cptr->hdw->std_enum_cur;
- return 0;
-}
-
-
-static int ctrl_stdenumcur_is_dirty(struct pvr2_ctrl *cptr)
-{
- return cptr->hdw->std_dirty != 0;
-}
-
-
-static void ctrl_stdenumcur_clear_dirty(struct pvr2_ctrl *cptr)
-{
- cptr->hdw->std_dirty = 0;
-}
-
-
#define DEFINT(vmin,vmax) \
.type = pvr2_ctl_int, \
.def.type_int.min_value = vmin, \
@@ -1293,15 +1261,14 @@ static const struct pvr2_ctl_info control_defs[] = {
.sym_to_val = ctrl_std_sym_to_val,
.type = pvr2_ctl_bitmask,
},{
- .desc = "Video Standard Name",
- .name = "video_standard",
- .internal_id = PVR2_CID_STDENUM,
+ .desc = "Video Standards Detected Mask",
+ .name = "video_standard_mask_detected",
+ .internal_id = PVR2_CID_STDDETECT,
.skip_init = !0,
- .get_value = ctrl_stdenumcur_get,
- .set_value = ctrl_stdenumcur_set,
- .is_dirty = ctrl_stdenumcur_is_dirty,
- .clear_dirty = ctrl_stdenumcur_clear_dirty,
- .type = pvr2_ctl_enum,
+ .get_value = ctrl_stddetect_get,
+ .val_to_sym = ctrl_std_val_to_sym,
+ .sym_to_val = ctrl_std_sym_to_val,
+ .type = pvr2_ctl_bitmask,
}
};
@@ -1936,7 +1903,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
hdw->std_mask_avail |= std2;
}
- pvr2_hdw_internal_set_std_avail(hdw);
+ hdw->std_info_cur.def.type_bitmask.valid_bits = hdw->std_mask_avail;
if (std1) {
bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std1);
@@ -1945,7 +1912,6 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
bcnt,buf);
hdw->std_mask_cur = std1;
hdw->std_dirty = !0;
- pvr2_hdw_internal_find_stdenum(hdw);
return;
}
if (std3) {
@@ -1955,7 +1921,6 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
" (determined by device type): %.*s",bcnt,buf);
hdw->std_mask_cur = std3;
hdw->std_dirty = !0;
- pvr2_hdw_internal_find_stdenum(hdw);
return;
}
@@ -1975,24 +1940,10 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
bcnt,buf);
hdw->std_mask_cur = std_eeprom_maps[idx].std;
hdw->std_dirty = !0;
- pvr2_hdw_internal_find_stdenum(hdw);
return;
}
}
- if (hdw->std_enum_cnt > 1) {
- // Autoselect the first listed standard
- hdw->std_enum_cur = 1;
- hdw->std_mask_cur = hdw->std_defs[hdw->std_enum_cur-1].id;
- hdw->std_dirty = !0;
- pvr2_trace(PVR2_TRACE_STD,
- "Initial video standard auto-selected to %s",
- hdw->std_defs[hdw->std_enum_cur-1].name);
- return;
- }
-
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Unable to select a viable initial video standard");
}
@@ -2594,14 +2545,6 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
cptr->info = ciptr;
}
- // Initialize video standard enum dynamic control
- cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDENUM);
- if (cptr) {
- memcpy(&hdw->std_info_enum,cptr->info,
- sizeof(hdw->std_info_enum));
- cptr->info = &hdw->std_info_enum;
-
- }
// Initialize control data regarding video standard masks
valid_std_mask = pvr2_std_get_usable();
for (idx = 0; idx < 32; idx++) {
@@ -2629,7 +2572,17 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
cptr->info = &hdw->std_info_cur;
hdw->std_info_cur.def.type_bitmask.bit_names =
hdw->std_mask_ptrs;
- hdw->std_info_avail.def.type_bitmask.valid_bits =
+ hdw->std_info_cur.def.type_bitmask.valid_bits =
+ valid_std_mask;
+ }
+ cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDDETECT);
+ if (cptr) {
+ memcpy(&hdw->std_info_detect,cptr->info,
+ sizeof(hdw->std_info_detect));
+ cptr->info = &hdw->std_info_detect;
+ hdw->std_info_detect.def.type_bitmask.bit_names =
+ hdw->std_mask_ptrs;
+ hdw->std_info_detect.def.type_bitmask.valid_bits =
valid_std_mask;
}
@@ -2711,8 +2664,6 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
kfree(hdw->ctl_write_buffer);
kfree(hdw->controls);
kfree(hdw->mpeg_ctrl_info);
- kfree(hdw->std_defs);
- kfree(hdw->std_enum_names);
kfree(hdw);
}
return NULL;
@@ -2788,8 +2739,6 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
} while (0); mutex_unlock(&pvr2_unit_mtx);
kfree(hdw->controls);
kfree(hdw->mpeg_ctrl_info);
- kfree(hdw->std_defs);
- kfree(hdw->std_enum_names);
kfree(hdw);
}
@@ -2812,86 +2761,6 @@ void pvr2_hdw_disconnect(struct pvr2_hdw *hdw)
}
-// Attempt to autoselect an appropriate value for std_enum_cur given
-// whatever is currently in std_mask_cur
-static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw)
-{
- unsigned int idx;
- for (idx = 1; idx < hdw->std_enum_cnt; idx++) {
- if (hdw->std_defs[idx-1].id == hdw->std_mask_cur) {
- hdw->std_enum_cur = idx;
- return;
- }
- }
- hdw->std_enum_cur = 0;
-}
-
-
-// Calculate correct set of enumerated standards based on currently known
-// set of available standards bits.
-static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw)
-{
- struct v4l2_standard *newstd;
- unsigned int std_cnt;
- unsigned int idx;
-
- newstd = pvr2_std_create_enum(&std_cnt,hdw->std_mask_avail);
-
- if (hdw->std_defs) {
- kfree(hdw->std_defs);
- hdw->std_defs = NULL;
- }
- hdw->std_enum_cnt = 0;
- if (hdw->std_enum_names) {
- kfree(hdw->std_enum_names);
- hdw->std_enum_names = NULL;
- }
-
- if (!std_cnt) {
- pvr2_trace(
- PVR2_TRACE_ERROR_LEGS,
- "WARNING: Failed to identify any viable standards");
- }
-
- /* Set up the dynamic control for this standard */
- hdw->std_enum_names = kmalloc(sizeof(char *)*(std_cnt+1),GFP_KERNEL);
- if (hdw->std_enum_names) {
- hdw->std_enum_names[0] = "none";
- for (idx = 0; idx < std_cnt; idx++)
- hdw->std_enum_names[idx+1] = newstd[idx].name;
- hdw->std_info_enum.def.type_enum.value_names =
- hdw->std_enum_names;
- hdw->std_info_enum.def.type_enum.count = std_cnt+1;
- } else {
- pvr2_trace(
- PVR2_TRACE_ERROR_LEGS,
- "WARNING: Failed to alloc memory for names");
- hdw->std_info_enum.def.type_enum.value_names = NULL;
- hdw->std_info_enum.def.type_enum.count = 0;
- }
- hdw->std_defs = newstd;
- hdw->std_enum_cnt = std_cnt+1;
- hdw->std_enum_cur = 0;
- hdw->std_info_cur.def.type_bitmask.valid_bits = hdw->std_mask_avail;
-}
-
-
-int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,
- struct v4l2_standard *std,
- unsigned int idx)
-{
- int ret = -EINVAL;
- if (!idx) return ret;
- LOCK_TAKE(hdw->big_lock); do {
- if (idx >= hdw->std_enum_cnt) break;
- idx--;
- memcpy(std,hdw->std_defs+idx,sizeof(*std));
- ret = 0;
- } while (0); LOCK_GIVE(hdw->big_lock);
- return ret;
-}
-
-
/* Get the number of defined controls */
unsigned int pvr2_hdw_get_ctrl_count(struct pvr2_hdw *hdw)
{
@@ -2995,11 +2864,13 @@ static void pvr2_subdev_set_control(struct pvr2_hdw *hdw, int id,
pvr2_subdev_set_control(hdw, id, #lab, (hdw)->lab##_val); \
}
-int pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw, v4l2_std_id *std)
+v4l2_std_id pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw)
{
+ v4l2_std_id std;
+ std = (v4l2_std_id)hdw->std_mask_avail;
v4l2_device_call_all(&hdw->v4l2_dev, 0,
- video, querystd, std);
- return 0;
+ video, querystd, &std);
+ return std;
}
/* Execute whatever commands are required to update the state of all the
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index 66546580b17d..8060fc666eeb 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -28,7 +28,6 @@
/* Private internal control ids, look these up with
pvr2_hdw_get_ctrl_by_id() - these are NOT visible in V4L */
-#define PVR2_CID_STDENUM 1
#define PVR2_CID_STDCUR 2
#define PVR2_CID_STDAVAIL 3
#define PVR2_CID_INPUT 4
@@ -46,6 +45,7 @@
#define PVR2_CID_CROPCAPBT 16
#define PVR2_CID_CROPCAPBW 17
#define PVR2_CID_CROPCAPBH 18
+#define PVR2_CID_STDDETECT 19
/* Legal values for the INPUT state variable */
#define PVR2_CVAL_INPUT_TV 0
@@ -210,13 +210,6 @@ int pvr2_hdw_set_stream_type(struct pvr2_hdw *, enum pvr2_config);
/* Get handle to video output stream */
struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *);
-/* Emit a video standard struct */
-int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,struct v4l2_standard *std,
- unsigned int idx);
-
-/* Get the detected video standard */
-int pvr2_hdw_get_detected_std(struct pvr2_hdw *hdw, v4l2_std_id *std);
-
/* Enable / disable retrieval of CPU firmware or prom contents. This must
be enabled before pvr2_hdw_cpufw_get() will function. Note that doing
this may prevent the device from running (and leaving this mode may
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index e1111d968a3d..7bddfaeeafc3 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -107,7 +107,6 @@ static struct v4l2_fmtdesc pvr_fmtdesc [] = {
// This should really be V4L2_PIX_FMT_MPEG, but xawtv
// breaks when I do that.
.pixelformat = 0, // V4L2_PIX_FMT_MPEG,
- .reserved = { 0, 0, 0, 0 }
}
};
@@ -145,740 +144,739 @@ static struct v4l2_format pvr_format [] = {
.start = { 0, 0 },
.count = { 0, 0 },
.flags = 0,
- .reserved = { 0, 0 }
}
}
}
};
+
/*
- * pvr_ioctl()
- *
- * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
- *
+ * This is part of Video 4 Linux API. These procedures handle ioctl() calls.
*/
-static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static int pvr2_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
{
struct pvr2_v4l2_fh *fh = file->private_data;
- struct pvr2_v4l2 *vp = fh->vhead;
- struct pvr2_v4l2_dev *pdi = fh->pdi;
struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
- long ret = -EINVAL;
- if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
- v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),cmd);
- }
+ memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
+ strlcpy(cap->bus_info, pvr2_hdw_get_bus_info(hdw),
+ sizeof(cap->bus_info));
+ strlcpy(cap->card, pvr2_hdw_get_desc(hdw), sizeof(cap->card));
+ return 0;
+}
- if (!pvr2_hdw_dev_ok(hdw)) {
- pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "ioctl failed - bad or no context");
- return -EFAULT;
- }
+static int pvr2_g_priority(struct file *file, void *priv, enum v4l2_priority *p)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_v4l2 *vp = fh->vhead;
- /* check priority */
- switch (cmd) {
- case VIDIOC_S_CTRL:
- case VIDIOC_S_STD:
- case VIDIOC_S_INPUT:
- case VIDIOC_S_TUNER:
- case VIDIOC_S_FREQUENCY:
- ret = v4l2_prio_check(&vp->prio, fh->prio);
- if (ret)
- return ret;
- }
+ *p = v4l2_prio_max(&vp->prio);
+ return 0;
+}
- switch (cmd) {
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *cap = arg;
+static int pvr2_s_priority(struct file *file, void *priv, enum v4l2_priority prio)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_v4l2 *vp = fh->vhead;
- memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
- strlcpy(cap->bus_info,pvr2_hdw_get_bus_info(hdw),
- sizeof(cap->bus_info));
- strlcpy(cap->card,pvr2_hdw_get_desc(hdw),sizeof(cap->card));
+ return v4l2_prio_change(&vp->prio, &fh->prio, prio);
+}
- ret = 0;
- break;
- }
+static int pvr2_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ int val = 0;
+ int ret;
- case VIDIOC_G_PRIORITY:
- {
- enum v4l2_priority *p = arg;
+ ret = pvr2_ctrl_get_value(
+ pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_STDCUR), &val);
+ *std = val;
+ return ret;
+}
- *p = v4l2_prio_max(&vp->prio);
- ret = 0;
- break;
- }
+int pvr2_s_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
- case VIDIOC_S_PRIORITY:
- {
- enum v4l2_priority *prio = arg;
+ return pvr2_ctrl_set_value(
+ pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_STDCUR), *std);
+}
- ret = v4l2_prio_change(&vp->prio, &fh->prio, *prio);
- break;
- }
+static int pvr2_querystd(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ int val = 0;
+ int ret;
- case VIDIOC_ENUMSTD:
- {
- struct v4l2_standard *vs = (struct v4l2_standard *)arg;
- int idx = vs->index;
- ret = pvr2_hdw_get_stdenum_value(hdw,vs,idx+1);
- break;
- }
+ ret = pvr2_ctrl_get_value(
+ pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_STDDETECT), &val);
+ *std = val;
+ return ret;
+}
- case VIDIOC_QUERYSTD:
- {
- v4l2_std_id *std = arg;
- *std = V4L2_STD_ALL;
- ret = pvr2_hdw_get_detected_std(hdw, std);
- break;
- }
+static int pvr2_enum_input(struct file *file, void *priv, struct v4l2_input *vi)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ struct pvr2_ctrl *cptr;
+ struct v4l2_input tmp;
+ unsigned int cnt;
+ int val;
+ int ret;
- case VIDIOC_G_STD:
- {
- int val = 0;
- ret = pvr2_ctrl_get_value(
- pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),&val);
- *(v4l2_std_id *)arg = val;
+ cptr = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT);
+
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.index = vi->index;
+ ret = 0;
+ if (vi->index >= fh->input_cnt)
+ return -EINVAL;
+ val = fh->input_map[vi->index];
+ switch (val) {
+ case PVR2_CVAL_INPUT_TV:
+ case PVR2_CVAL_INPUT_DTV:
+ case PVR2_CVAL_INPUT_RADIO:
+ tmp.type = V4L2_INPUT_TYPE_TUNER;
break;
- }
-
- case VIDIOC_S_STD:
- {
- ret = pvr2_ctrl_set_value(
- pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),
- *(v4l2_std_id *)arg);
+ case PVR2_CVAL_INPUT_SVIDEO:
+ case PVR2_CVAL_INPUT_COMPOSITE:
+ tmp.type = V4L2_INPUT_TYPE_CAMERA;
break;
+ default:
+ return -EINVAL;
}
- case VIDIOC_ENUMINPUT:
- {
- struct pvr2_ctrl *cptr;
- struct v4l2_input *vi = (struct v4l2_input *)arg;
- struct v4l2_input tmp;
- unsigned int cnt;
- int val;
+ cnt = 0;
+ pvr2_ctrl_get_valname(cptr, val,
+ tmp.name, sizeof(tmp.name) - 1, &cnt);
+ tmp.name[cnt] = 0;
- cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+ /* Don't bother with audioset, since this driver currently
+ always switches the audio whenever the video is
+ switched. */
- memset(&tmp,0,sizeof(tmp));
- tmp.index = vi->index;
- ret = 0;
- if (vi->index >= fh->input_cnt) {
- ret = -EINVAL;
- break;
- }
- val = fh->input_map[vi->index];
- switch (val) {
- case PVR2_CVAL_INPUT_TV:
- case PVR2_CVAL_INPUT_DTV:
- case PVR2_CVAL_INPUT_RADIO:
- tmp.type = V4L2_INPUT_TYPE_TUNER;
- break;
- case PVR2_CVAL_INPUT_SVIDEO:
- case PVR2_CVAL_INPUT_COMPOSITE:
- tmp.type = V4L2_INPUT_TYPE_CAMERA;
- break;
- default:
- ret = -EINVAL;
- break;
- }
- if (ret < 0) break;
-
- cnt = 0;
- pvr2_ctrl_get_valname(cptr,val,
- tmp.name,sizeof(tmp.name)-1,&cnt);
- tmp.name[cnt] = 0;
-
- /* Don't bother with audioset, since this driver currently
- always switches the audio whenever the video is
- switched. */
-
- /* Handling std is a tougher problem. It doesn't make
- sense in cases where a device might be multi-standard.
- We could just copy out the current value for the
- standard, but it can change over time. For now just
- leave it zero. */
-
- memcpy(vi, &tmp, sizeof(tmp));
-
- ret = 0;
- break;
- }
+ /* Handling std is a tougher problem. It doesn't make
+ sense in cases where a device might be multi-standard.
+ We could just copy out the current value for the
+ standard, but it can change over time. For now just
+ leave it zero. */
+ *vi = tmp;
+ return 0;
+}
- case VIDIOC_G_INPUT:
- {
- unsigned int idx;
- struct pvr2_ctrl *cptr;
- struct v4l2_input *vi = (struct v4l2_input *)arg;
- int val;
- cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
- val = 0;
- ret = pvr2_ctrl_get_value(cptr,&val);
- vi->index = 0;
- for (idx = 0; idx < fh->input_cnt; idx++) {
- if (fh->input_map[idx] == val) {
- vi->index = idx;
- break;
- }
- }
- break;
- }
+static int pvr2_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ unsigned int idx;
+ struct pvr2_ctrl *cptr;
+ int val;
+ int ret;
- case VIDIOC_S_INPUT:
- {
- struct v4l2_input *vi = (struct v4l2_input *)arg;
- if (vi->index >= fh->input_cnt) {
- ret = -ERANGE;
+ cptr = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT);
+ val = 0;
+ ret = pvr2_ctrl_get_value(cptr, &val);
+ *i = 0;
+ for (idx = 0; idx < fh->input_cnt; idx++) {
+ if (fh->input_map[idx] == val) {
+ *i = idx;
break;
}
- ret = pvr2_ctrl_set_value(
- pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
- fh->input_map[vi->index]);
- break;
}
+ return ret;
+}
- case VIDIOC_ENUMAUDIO:
- {
- /* pkt: FIXME: We are returning one "fake" input here
- which could very well be called "whatever_we_like".
- This is for apps that want to see an audio input
- just to feel comfortable, as well as to test if
- it can do stereo or sth. There is actually no guarantee
- that the actual audio input cannot change behind the app's
- back, but most applications should not mind that either.
-
- Hopefully, mplayer people will work with us on this (this
- whole mess is to support mplayer pvr://), or Hans will come
- up with a more standard way to say "we have inputs but we
- don 't want you to change them independent of video" which
- will sort this mess.
- */
- struct v4l2_audio *vin = arg;
- ret = -EINVAL;
- if (vin->index > 0) break;
- strncpy(vin->name, "PVRUSB2 Audio",14);
- vin->capability = V4L2_AUDCAP_STEREO;
- ret = 0;
- break;
- break;
- }
+static int pvr2_s_input(struct file *file, void *priv, unsigned int inp)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
- case VIDIOC_G_AUDIO:
- {
- /* pkt: FIXME: see above comment (VIDIOC_ENUMAUDIO) */
- struct v4l2_audio *vin = arg;
- memset(vin,0,sizeof(*vin));
- vin->index = 0;
- strncpy(vin->name, "PVRUSB2 Audio",14);
- vin->capability = V4L2_AUDCAP_STEREO;
- ret = 0;
- break;
- }
+ if (inp >= fh->input_cnt)
+ return -EINVAL;
+ return pvr2_ctrl_set_value(
+ pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT),
+ fh->input_map[inp]);
+}
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
+static int pvr2_enumaudio(struct file *file, void *priv, struct v4l2_audio *vin)
+{
+ /* pkt: FIXME: We are returning one "fake" input here
+ which could very well be called "whatever_we_like".
+ This is for apps that want to see an audio input
+ just to feel comfortable, as well as to test if
+ it can do stereo or sth. There is actually no guarantee
+ that the actual audio input cannot change behind the app's
+ back, but most applications should not mind that either.
+
+ Hopefully, mplayer people will work with us on this (this
+ whole mess is to support mplayer pvr://), or Hans will come
+ up with a more standard way to say "we have inputs but we
+ don 't want you to change them independent of video" which
+ will sort this mess.
+ */
+
+ if (vin->index > 0)
+ return -EINVAL;
+ strncpy(vin->name, "PVRUSB2 Audio", 14);
+ vin->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+}
- if (vt->index != 0) break; /* Only answer for the 1st tuner */
+static int pvr2_g_audio(struct file *file, void *priv, struct v4l2_audio *vin)
+{
+ /* pkt: FIXME: see above comment (VIDIOC_ENUMAUDIO) */
+ vin->index = 0;
+ strncpy(vin->name, "PVRUSB2 Audio", 14);
+ vin->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+}
- pvr2_hdw_execute_tuner_poll(hdw);
- ret = pvr2_hdw_get_tuner_status(hdw,vt);
- break;
- }
+static int pvr2_s_audio(struct file *file, void *priv, struct v4l2_audio *vout)
+{
+ if (vout->index)
+ return -EINVAL;
+ return 0;
+}
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *vt=(struct v4l2_tuner *)arg;
+static int pvr2_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
- if (vt->index != 0)
- break;
+ if (vt->index != 0)
+ return -EINVAL; /* Only answer for the 1st tuner */
- ret = pvr2_ctrl_set_value(
- pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
+ pvr2_hdw_execute_tuner_poll(hdw);
+ return pvr2_hdw_get_tuner_status(hdw, vt);
+}
+
+static int pvr2_s_tuner(struct file *file, void *priv, struct v4l2_tuner *vt)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+
+ if (vt->index != 0)
+ return -EINVAL;
+
+ return pvr2_ctrl_set_value(
+ pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_AUDIOMODE),
vt->audmode);
- break;
- }
+}
- case VIDIOC_S_FREQUENCY:
- {
- const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
- unsigned long fv;
- struct v4l2_tuner vt;
- int cur_input;
- struct pvr2_ctrl *ctrlp;
- ret = pvr2_hdw_get_tuner_status(hdw,&vt);
- if (ret != 0) break;
- ctrlp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
- ret = pvr2_ctrl_get_value(ctrlp,&cur_input);
- if (ret != 0) break;
- if (vf->type == V4L2_TUNER_RADIO) {
- if (cur_input != PVR2_CVAL_INPUT_RADIO) {
- pvr2_ctrl_set_value(ctrlp,
- PVR2_CVAL_INPUT_RADIO);
- }
- } else {
- if (cur_input == PVR2_CVAL_INPUT_RADIO) {
- pvr2_ctrl_set_value(ctrlp,
- PVR2_CVAL_INPUT_TV);
- }
- }
- fv = vf->frequency;
- if (vt.capability & V4L2_TUNER_CAP_LOW) {
- fv = (fv * 125) / 2;
- } else {
- fv = fv * 62500;
- }
- ret = pvr2_ctrl_set_value(
+int pvr2_s_frequency(struct file *file, void *priv, struct v4l2_frequency *vf)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ unsigned long fv;
+ struct v4l2_tuner vt;
+ int cur_input;
+ struct pvr2_ctrl *ctrlp;
+ int ret;
+
+ ret = pvr2_hdw_get_tuner_status(hdw, &vt);
+ if (ret != 0)
+ return ret;
+ ctrlp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT);
+ ret = pvr2_ctrl_get_value(ctrlp, &cur_input);
+ if (ret != 0)
+ return ret;
+ if (vf->type == V4L2_TUNER_RADIO) {
+ if (cur_input != PVR2_CVAL_INPUT_RADIO)
+ pvr2_ctrl_set_value(ctrlp, PVR2_CVAL_INPUT_RADIO);
+ } else {
+ if (cur_input == PVR2_CVAL_INPUT_RADIO)
+ pvr2_ctrl_set_value(ctrlp, PVR2_CVAL_INPUT_TV);
+ }
+ fv = vf->frequency;
+ if (vt.capability & V4L2_TUNER_CAP_LOW)
+ fv = (fv * 125) / 2;
+ else
+ fv = fv * 62500;
+ return pvr2_ctrl_set_value(
pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),fv);
- break;
- }
+}
- case VIDIOC_G_FREQUENCY:
- {
- struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
- int val = 0;
- int cur_input;
- struct v4l2_tuner vt;
- ret = pvr2_hdw_get_tuner_status(hdw,&vt);
- if (ret != 0) break;
- ret = pvr2_ctrl_get_value(
- pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
+static int pvr2_g_frequency(struct file *file, void *priv, struct v4l2_frequency *vf)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ int val = 0;
+ int cur_input;
+ struct v4l2_tuner vt;
+ int ret;
+
+ ret = pvr2_hdw_get_tuner_status(hdw, &vt);
+ if (ret != 0)
+ return ret;
+ ret = pvr2_ctrl_get_value(
+ pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_FREQUENCY),
&val);
- if (ret != 0) break;
- pvr2_ctrl_get_value(
- pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
+ if (ret != 0)
+ return ret;
+ pvr2_ctrl_get_value(
+ pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_INPUT),
&cur_input);
- if (cur_input == PVR2_CVAL_INPUT_RADIO) {
- vf->type = V4L2_TUNER_RADIO;
- } else {
- vf->type = V4L2_TUNER_ANALOG_TV;
- }
- if (vt.capability & V4L2_TUNER_CAP_LOW) {
- val = (val * 2) / 125;
- } else {
- val /= 62500;
- }
- vf->frequency = val;
- break;
- }
+ if (cur_input == PVR2_CVAL_INPUT_RADIO)
+ vf->type = V4L2_TUNER_RADIO;
+ else
+ vf->type = V4L2_TUNER_ANALOG_TV;
+ if (vt.capability & V4L2_TUNER_CAP_LOW)
+ val = (val * 2) / 125;
+ else
+ val /= 62500;
+ vf->frequency = val;
+ return 0;
+}
- case VIDIOC_ENUM_FMT:
- {
- struct v4l2_fmtdesc *fd = (struct v4l2_fmtdesc *)arg;
+static int pvr2_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *fd)
+{
+ /* Only one format is supported : mpeg.*/
+ if (fd->index != 0)
+ return -EINVAL;
- /* Only one format is supported : mpeg.*/
- if (fd->index != 0)
- break;
+ memcpy(fd, pvr_fmtdesc, sizeof(struct v4l2_fmtdesc));
+ return 0;
+}
- memcpy(fd, pvr_fmtdesc, sizeof(struct v4l2_fmtdesc));
- ret = 0;
- break;
- }
+static int pvr2_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ int val;
- case VIDIOC_G_FMT:
- {
- struct v4l2_format *vf = (struct v4l2_format *)arg;
- int val;
- switch(vf->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
- sizeof(struct v4l2_format));
- val = 0;
- pvr2_ctrl_get_value(
- pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES),
- &val);
- vf->fmt.pix.width = val;
- val = 0;
- pvr2_ctrl_get_value(
- pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES),
- &val);
- vf->fmt.pix.height = val;
- ret = 0;
- break;
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- // ????? Still need to figure out to do VBI correctly
- ret = -EINVAL;
- break;
- default:
- ret = -EINVAL;
- break;
- }
- break;
- }
+ memcpy(vf, &pvr_format[PVR_FORMAT_PIX], sizeof(struct v4l2_format));
+ val = 0;
+ pvr2_ctrl_get_value(
+ pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_HRES),
+ &val);
+ vf->fmt.pix.width = val;
+ val = 0;
+ pvr2_ctrl_get_value(
+ pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_VRES),
+ &val);
+ vf->fmt.pix.height = val;
+ return 0;
+}
- case VIDIOC_TRY_FMT:
- case VIDIOC_S_FMT:
- {
- struct v4l2_format *vf = (struct v4l2_format *)arg;
-
- ret = 0;
- switch(vf->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
- int lmin,lmax,ldef;
- struct pvr2_ctrl *hcp,*vcp;
- int h = vf->fmt.pix.height;
- int w = vf->fmt.pix.width;
- hcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES);
- vcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES);
-
- lmin = pvr2_ctrl_get_min(hcp);
- lmax = pvr2_ctrl_get_max(hcp);
- pvr2_ctrl_get_def(hcp, &ldef);
- if (w == -1) {
- w = ldef;
- } else if (w < lmin) {
- w = lmin;
- } else if (w > lmax) {
- w = lmax;
- }
- lmin = pvr2_ctrl_get_min(vcp);
- lmax = pvr2_ctrl_get_max(vcp);
- pvr2_ctrl_get_def(vcp, &ldef);
- if (h == -1) {
- h = ldef;
- } else if (h < lmin) {
- h = lmin;
- } else if (h > lmax) {
- h = lmax;
- }
+static int pvr2_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ int lmin, lmax, ldef;
+ struct pvr2_ctrl *hcp, *vcp;
+ int h = vf->fmt.pix.height;
+ int w = vf->fmt.pix.width;
+
+ hcp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_HRES);
+ vcp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_VRES);
+
+ lmin = pvr2_ctrl_get_min(hcp);
+ lmax = pvr2_ctrl_get_max(hcp);
+ pvr2_ctrl_get_def(hcp, &ldef);
+ if (w == -1)
+ w = ldef;
+ else if (w < lmin)
+ w = lmin;
+ else if (w > lmax)
+ w = lmax;
+ lmin = pvr2_ctrl_get_min(vcp);
+ lmax = pvr2_ctrl_get_max(vcp);
+ pvr2_ctrl_get_def(vcp, &ldef);
+ if (h == -1)
+ h = ldef;
+ else if (h < lmin)
+ h = lmin;
+ else if (h > lmax)
+ h = lmax;
+
+ memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
+ sizeof(struct v4l2_format));
+ vf->fmt.pix.width = w;
+ vf->fmt.pix.height = h;
+ return 0;
+}
- memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
- sizeof(struct v4l2_format));
- vf->fmt.pix.width = w;
- vf->fmt.pix.height = h;
+static int pvr2_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ struct pvr2_ctrl *hcp, *vcp;
+ int ret = pvr2_try_fmt_vid_cap(file, fh, vf);
- if (cmd == VIDIOC_S_FMT) {
- pvr2_ctrl_set_value(hcp,vf->fmt.pix.width);
- pvr2_ctrl_set_value(vcp,vf->fmt.pix.height);
- }
- } break;
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- // ????? Still need to figure out to do VBI correctly
- ret = -EINVAL;
- break;
- default:
- ret = -EINVAL;
- break;
- }
- break;
- }
+ if (ret)
+ return ret;
+ hcp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_HRES);
+ vcp = pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_VRES);
+ pvr2_ctrl_set_value(hcp, vf->fmt.pix.width);
+ pvr2_ctrl_set_value(vcp, vf->fmt.pix.height);
+ return 0;
+}
- case VIDIOC_STREAMON:
- {
- if (!fh->pdi->stream) {
- /* No stream defined for this node. This means
- that we're not currently allowed to stream from
- this node. */
- ret = -EPERM;
- break;
- }
- ret = pvr2_hdw_set_stream_type(hdw,pdi->config);
- if (ret < 0) return ret;
- ret = pvr2_hdw_set_streaming(hdw,!0);
- break;
+static int pvr2_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ struct pvr2_v4l2_dev *pdi = fh->pdi;
+ int ret;
+
+ if (!fh->pdi->stream) {
+ /* No stream defined for this node. This means
+ that we're not currently allowed to stream from
+ this node. */
+ return -EPERM;
}
+ ret = pvr2_hdw_set_stream_type(hdw, pdi->config);
+ if (ret < 0)
+ return ret;
+ return pvr2_hdw_set_streaming(hdw, !0);
+}
- case VIDIOC_STREAMOFF:
- {
- if (!fh->pdi->stream) {
- /* No stream defined for this node. This means
- that we're not currently allowed to stream from
- this node. */
- ret = -EPERM;
- break;
- }
- ret = pvr2_hdw_set_streaming(hdw,0);
- break;
+static int pvr2_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+
+ if (!fh->pdi->stream) {
+ /* No stream defined for this node. This means
+ that we're not currently allowed to stream from
+ this node. */
+ return -EPERM;
}
+ return pvr2_hdw_set_streaming(hdw, 0);
+}
- case VIDIOC_QUERYCTRL:
- {
- struct pvr2_ctrl *cptr;
- int val;
- struct v4l2_queryctrl *vc = (struct v4l2_queryctrl *)arg;
- ret = 0;
- if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
- cptr = pvr2_hdw_get_ctrl_nextv4l(
- hdw,(vc->id & ~V4L2_CTRL_FLAG_NEXT_CTRL));
- if (cptr) vc->id = pvr2_ctrl_get_v4lid(cptr);
- } else {
- cptr = pvr2_hdw_get_ctrl_v4l(hdw,vc->id);
- }
- if (!cptr) {
- pvr2_trace(PVR2_TRACE_V4LIOCTL,
- "QUERYCTRL id=0x%x not implemented here",
- vc->id);
- ret = -EINVAL;
- break;
- }
+static int pvr2_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *vc)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ struct pvr2_ctrl *cptr;
+ int val;
+ int ret;
+ ret = 0;
+ if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
+ cptr = pvr2_hdw_get_ctrl_nextv4l(
+ hdw, (vc->id & ~V4L2_CTRL_FLAG_NEXT_CTRL));
+ if (cptr)
+ vc->id = pvr2_ctrl_get_v4lid(cptr);
+ } else {
+ cptr = pvr2_hdw_get_ctrl_v4l(hdw, vc->id);
+ }
+ if (!cptr) {
pvr2_trace(PVR2_TRACE_V4LIOCTL,
- "QUERYCTRL id=0x%x mapping name=%s (%s)",
- vc->id,pvr2_ctrl_get_name(cptr),
- pvr2_ctrl_get_desc(cptr));
- strlcpy(vc->name,pvr2_ctrl_get_desc(cptr),sizeof(vc->name));
- vc->flags = pvr2_ctrl_get_v4lflags(cptr);
- pvr2_ctrl_get_def(cptr, &val);
- vc->default_value = val;
- switch (pvr2_ctrl_get_type(cptr)) {
- case pvr2_ctl_enum:
- vc->type = V4L2_CTRL_TYPE_MENU;
- vc->minimum = 0;
- vc->maximum = pvr2_ctrl_get_cnt(cptr) - 1;
- vc->step = 1;
- break;
- case pvr2_ctl_bool:
- vc->type = V4L2_CTRL_TYPE_BOOLEAN;
- vc->minimum = 0;
- vc->maximum = 1;
- vc->step = 1;
- break;
- case pvr2_ctl_int:
- vc->type = V4L2_CTRL_TYPE_INTEGER;
- vc->minimum = pvr2_ctrl_get_min(cptr);
- vc->maximum = pvr2_ctrl_get_max(cptr);
- vc->step = 1;
- break;
- default:
- pvr2_trace(PVR2_TRACE_V4LIOCTL,
- "QUERYCTRL id=0x%x name=%s not mappable",
- vc->id,pvr2_ctrl_get_name(cptr));
- ret = -EINVAL;
- break;
- }
+ "QUERYCTRL id=0x%x not implemented here",
+ vc->id);
+ return -EINVAL;
+ }
+
+ pvr2_trace(PVR2_TRACE_V4LIOCTL,
+ "QUERYCTRL id=0x%x mapping name=%s (%s)",
+ vc->id, pvr2_ctrl_get_name(cptr),
+ pvr2_ctrl_get_desc(cptr));
+ strlcpy(vc->name, pvr2_ctrl_get_desc(cptr), sizeof(vc->name));
+ vc->flags = pvr2_ctrl_get_v4lflags(cptr);
+ pvr2_ctrl_get_def(cptr, &val);
+ vc->default_value = val;
+ switch (pvr2_ctrl_get_type(cptr)) {
+ case pvr2_ctl_enum:
+ vc->type = V4L2_CTRL_TYPE_MENU;
+ vc->minimum = 0;
+ vc->maximum = pvr2_ctrl_get_cnt(cptr) - 1;
+ vc->step = 1;
break;
- }
-
- case VIDIOC_QUERYMENU:
- {
- struct v4l2_querymenu *vm = (struct v4l2_querymenu *)arg;
- unsigned int cnt = 0;
- ret = pvr2_ctrl_get_valname(pvr2_hdw_get_ctrl_v4l(hdw,vm->id),
- vm->index,
- vm->name,sizeof(vm->name)-1,
- &cnt);
- vm->name[cnt] = 0;
+ case pvr2_ctl_bool:
+ vc->type = V4L2_CTRL_TYPE_BOOLEAN;
+ vc->minimum = 0;
+ vc->maximum = 1;
+ vc->step = 1;
break;
- }
-
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *vc = (struct v4l2_control *)arg;
- int val = 0;
- ret = pvr2_ctrl_get_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
- &val);
- vc->value = val;
+ case pvr2_ctl_int:
+ vc->type = V4L2_CTRL_TYPE_INTEGER;
+ vc->minimum = pvr2_ctrl_get_min(cptr);
+ vc->maximum = pvr2_ctrl_get_max(cptr);
+ vc->step = 1;
break;
+ default:
+ pvr2_trace(PVR2_TRACE_V4LIOCTL,
+ "QUERYCTRL id=0x%x name=%s not mappable",
+ vc->id, pvr2_ctrl_get_name(cptr));
+ return -EINVAL;
}
+ return 0;
+}
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *vc = (struct v4l2_control *)arg;
- ret = pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
- vc->value);
- break;
- }
+static int pvr2_querymenu(struct file *file, void *priv, struct v4l2_querymenu *vm)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ unsigned int cnt = 0;
+ int ret;
- case VIDIOC_G_EXT_CTRLS:
- {
- struct v4l2_ext_controls *ctls =
- (struct v4l2_ext_controls *)arg;
- struct v4l2_ext_control *ctrl;
- unsigned int idx;
- int val;
- ret = 0;
- for (idx = 0; idx < ctls->count; idx++) {
- ctrl = ctls->controls + idx;
- ret = pvr2_ctrl_get_value(
- pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),&val);
- if (ret) {
- ctls->error_idx = idx;
- break;
- }
- /* Ensure that if read as a 64 bit value, the user
- will still get a hopefully sane value */
- ctrl->value64 = 0;
- ctrl->value = val;
+ ret = pvr2_ctrl_get_valname(pvr2_hdw_get_ctrl_v4l(hdw, vm->id),
+ vm->index,
+ vm->name, sizeof(vm->name) - 1,
+ &cnt);
+ vm->name[cnt] = 0;
+ return ret;
+}
+
+static int pvr2_g_ctrl(struct file *file, void *priv, struct v4l2_control *vc)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ int val = 0;
+ int ret;
+
+ ret = pvr2_ctrl_get_value(pvr2_hdw_get_ctrl_v4l(hdw, vc->id),
+ &val);
+ vc->value = val;
+ return ret;
+}
+
+static int pvr2_s_ctrl(struct file *file, void *priv, struct v4l2_control *vc)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+
+ return pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_v4l(hdw, vc->id),
+ vc->value);
+}
+
+static int pvr2_g_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *ctls)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ struct v4l2_ext_control *ctrl;
+ unsigned int idx;
+ int val;
+ int ret;
+
+ ret = 0;
+ for (idx = 0; idx < ctls->count; idx++) {
+ ctrl = ctls->controls + idx;
+ ret = pvr2_ctrl_get_value(
+ pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id), &val);
+ if (ret) {
+ ctls->error_idx = idx;
+ return ret;
}
- break;
+ /* Ensure that if read as a 64 bit value, the user
+ will still get a hopefully sane value */
+ ctrl->value64 = 0;
+ ctrl->value = val;
}
+ return 0;
+}
- case VIDIOC_S_EXT_CTRLS:
- {
- struct v4l2_ext_controls *ctls =
- (struct v4l2_ext_controls *)arg;
- struct v4l2_ext_control *ctrl;
- unsigned int idx;
- ret = 0;
- for (idx = 0; idx < ctls->count; idx++) {
- ctrl = ctls->controls + idx;
- ret = pvr2_ctrl_set_value(
- pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),
+static int pvr2_s_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *ctls)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ struct v4l2_ext_control *ctrl;
+ unsigned int idx;
+ int ret;
+
+ ret = 0;
+ for (idx = 0; idx < ctls->count; idx++) {
+ ctrl = ctls->controls + idx;
+ ret = pvr2_ctrl_set_value(
+ pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id),
ctrl->value);
- if (ret) {
- ctls->error_idx = idx;
- break;
- }
+ if (ret) {
+ ctls->error_idx = idx;
+ return ret;
}
- break;
}
+ return 0;
+}
- case VIDIOC_TRY_EXT_CTRLS:
- {
- struct v4l2_ext_controls *ctls =
- (struct v4l2_ext_controls *)arg;
- struct v4l2_ext_control *ctrl;
- struct pvr2_ctrl *pctl;
- unsigned int idx;
- /* For the moment just validate that the requested control
- actually exists. */
- ret = 0;
- for (idx = 0; idx < ctls->count; idx++) {
- ctrl = ctls->controls + idx;
- pctl = pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id);
- if (!pctl) {
- ret = -EINVAL;
- ctls->error_idx = idx;
- break;
- }
- }
- break;
- }
+static int pvr2_try_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *ctls)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ struct v4l2_ext_control *ctrl;
+ struct pvr2_ctrl *pctl;
+ unsigned int idx;
+ int ret;
- case VIDIOC_CROPCAP:
- {
- struct v4l2_cropcap *cap = (struct v4l2_cropcap *)arg;
- if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret = -EINVAL;
- break;
+ /* For the moment just validate that the requested control
+ actually exists. */
+ ret = 0;
+ for (idx = 0; idx < ctls->count; idx++) {
+ ctrl = ctls->controls + idx;
+ pctl = pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id);
+ if (!pctl) {
+ ctls->error_idx = idx;
+ return -EINVAL;
}
- ret = pvr2_hdw_get_cropcap(hdw, cap);
- cap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* paranoia */
- break;
}
- case VIDIOC_G_CROP:
- {
- struct v4l2_crop *crop = (struct v4l2_crop *)arg;
- int val = 0;
- if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret = -EINVAL;
- break;
- }
- ret = pvr2_ctrl_get_value(
+ return 0;
+}
+
+static int pvr2_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cap)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ int ret;
+
+ if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ ret = pvr2_hdw_get_cropcap(hdw, cap);
+ cap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* paranoia */
+ return ret;
+}
+
+static int pvr2_g_crop(struct file *file, void *priv, struct v4l2_crop *crop)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ int val = 0;
+ int ret;
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ ret = pvr2_ctrl_get_value(
pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), &val);
- if (ret != 0) {
- ret = -EINVAL;
- break;
- }
- crop->c.left = val;
- ret = pvr2_ctrl_get_value(
+ if (ret != 0)
+ return -EINVAL;
+ crop->c.left = val;
+ ret = pvr2_ctrl_get_value(
pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), &val);
- if (ret != 0) {
- ret = -EINVAL;
- break;
- }
- crop->c.top = val;
- ret = pvr2_ctrl_get_value(
+ if (ret != 0)
+ return -EINVAL;
+ crop->c.top = val;
+ ret = pvr2_ctrl_get_value(
pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), &val);
- if (ret != 0) {
- ret = -EINVAL;
- break;
- }
- crop->c.width = val;
- ret = pvr2_ctrl_get_value(
+ if (ret != 0)
+ return -EINVAL;
+ crop->c.width = val;
+ ret = pvr2_ctrl_get_value(
pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), &val);
- if (ret != 0) {
- ret = -EINVAL;
- break;
- }
- crop->c.height = val;
- }
- case VIDIOC_S_CROP:
- {
- struct v4l2_crop *crop = (struct v4l2_crop *)arg;
- if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret = -EINVAL;
- break;
- }
- ret = pvr2_ctrl_set_value(
+ if (ret != 0)
+ return -EINVAL;
+ crop->c.height = val;
+ return 0;
+}
+
+static int pvr2_s_crop(struct file *file, void *priv, struct v4l2_crop *crop)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ struct v4l2_cropcap cap;
+ int ret;
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ ret = pvr2_ctrl_set_value(
pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL),
crop->c.left);
- if (ret != 0) {
- ret = -EINVAL;
- break;
- }
- ret = pvr2_ctrl_set_value(
+ if (ret != 0)
+ return -EINVAL;
+ ret = pvr2_ctrl_set_value(
pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT),
crop->c.top);
- if (ret != 0) {
- ret = -EINVAL;
- break;
- }
- ret = pvr2_ctrl_set_value(
+ if (ret != 0)
+ return -EINVAL;
+ ret = pvr2_ctrl_set_value(
pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW),
crop->c.width);
- if (ret != 0) {
- ret = -EINVAL;
- break;
- }
- ret = pvr2_ctrl_set_value(
+ if (ret != 0)
+ return -EINVAL;
+ ret = pvr2_ctrl_set_value(
pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH),
crop->c.height);
- if (ret != 0) {
- ret = -EINVAL;
- break;
- }
- }
- case VIDIOC_LOG_STATUS:
- {
- pvr2_hdw_trigger_module_log(hdw);
- ret = 0;
- break;
- }
+ if (ret != 0)
+ return -EINVAL;
+ return 0;
+}
+
+static int pvr2_log_status(struct file *file, void *priv)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+
+ pvr2_hdw_trigger_module_log(hdw);
+ return 0;
+}
+
#ifdef CONFIG_VIDEO_ADV_DEBUG
- case VIDIOC_DBG_S_REGISTER:
- case VIDIOC_DBG_G_REGISTER:
- {
- u64 val;
- struct v4l2_dbg_register *req = (struct v4l2_dbg_register *)arg;
- if (cmd == VIDIOC_DBG_S_REGISTER) val = req->val;
- ret = pvr2_hdw_register_access(
- hdw, &req->match, req->reg,
- cmd == VIDIOC_DBG_S_REGISTER, &val);
- if (cmd == VIDIOC_DBG_G_REGISTER) req->val = val;
- break;
- }
-#endif
+static int pvr2_g_register(struct file *file, void *priv, struct v4l2_dbg_register *req)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ u64 val;
+ int ret;
- default :
- ret = -ENOTTY;
- break;
- }
+ ret = pvr2_hdw_register_access(
+ hdw, &req->match, req->reg,
+ 0, &val);
+ req->val = val;
+ return ret;
+}
- pvr2_hdw_commit_ctl(hdw);
+static int pvr2_s_register(struct file *file, void *priv, struct v4l2_dbg_register *req)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ u64 val;
+ int ret;
- if (ret < 0) {
- if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
- pvr2_trace(PVR2_TRACE_V4LIOCTL,
- "pvr2_v4l2_do_ioctl failure, ret=%ld", ret);
- } else {
- if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
- pvr2_trace(PVR2_TRACE_V4LIOCTL,
- "pvr2_v4l2_do_ioctl failure, ret=%ld"
- " command was:", ret);
- v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),
- cmd);
- }
- }
- } else {
- pvr2_trace(PVR2_TRACE_V4LIOCTL,
- "pvr2_v4l2_do_ioctl complete, ret=%ld (0x%lx)",
- ret, ret);
- }
+ val = req->val;
+ ret = pvr2_hdw_register_access(
+ hdw, &req->match, req->reg,
+ 1, &val);
return ret;
}
+#endif
+
+static const struct v4l2_ioctl_ops pvr2_ioctl_ops = {
+ .vidioc_querycap = pvr2_querycap,
+ .vidioc_g_priority = pvr2_g_priority,
+ .vidioc_s_priority = pvr2_s_priority,
+ .vidioc_s_audio = pvr2_s_audio,
+ .vidioc_g_audio = pvr2_g_audio,
+ .vidioc_enumaudio = pvr2_enumaudio,
+ .vidioc_enum_input = pvr2_enum_input,
+ .vidioc_cropcap = pvr2_cropcap,
+ .vidioc_s_crop = pvr2_s_crop,
+ .vidioc_g_crop = pvr2_g_crop,
+ .vidioc_g_input = pvr2_g_input,
+ .vidioc_s_input = pvr2_s_input,
+ .vidioc_g_frequency = pvr2_g_frequency,
+ .vidioc_s_frequency = pvr2_s_frequency,
+ .vidioc_s_tuner = pvr2_s_tuner,
+ .vidioc_g_tuner = pvr2_g_tuner,
+ .vidioc_g_std = pvr2_g_std,
+ .vidioc_s_std = pvr2_s_std,
+ .vidioc_querystd = pvr2_querystd,
+ .vidioc_log_status = pvr2_log_status,
+ .vidioc_enum_fmt_vid_cap = pvr2_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = pvr2_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = pvr2_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = pvr2_try_fmt_vid_cap,
+ .vidioc_streamon = pvr2_streamon,
+ .vidioc_streamoff = pvr2_streamoff,
+ .vidioc_queryctrl = pvr2_queryctrl,
+ .vidioc_querymenu = pvr2_querymenu,
+ .vidioc_g_ctrl = pvr2_g_ctrl,
+ .vidioc_s_ctrl = pvr2_s_ctrl,
+ .vidioc_g_ext_ctrls = pvr2_g_ext_ctrls,
+ .vidioc_s_ext_ctrls = pvr2_s_ext_ctrls,
+ .vidioc_try_ext_ctrls = pvr2_try_ext_ctrls,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = pvr2_g_register,
+ .vidioc_s_register = pvr2_s_register,
+#endif
+};
static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
{
@@ -961,7 +959,56 @@ static long pvr2_v4l2_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
- return video_usercopy(file, cmd, arg, pvr2_v4l2_do_ioctl);
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_v4l2 *vp = fh->vhead;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ long ret = -EINVAL;
+
+ if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL)
+ v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw), cmd);
+
+ if (!pvr2_hdw_dev_ok(hdw)) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "ioctl failed - bad or no context");
+ return -EFAULT;
+ }
+
+ /* check priority */
+ switch (cmd) {
+ case VIDIOC_S_CTRL:
+ case VIDIOC_S_STD:
+ case VIDIOC_S_INPUT:
+ case VIDIOC_S_TUNER:
+ case VIDIOC_S_FREQUENCY:
+ ret = v4l2_prio_check(&vp->prio, fh->prio);
+ if (ret)
+ return ret;
+ }
+
+ ret = video_ioctl2(file, cmd, arg);
+
+ pvr2_hdw_commit_ctl(hdw);
+
+ if (ret < 0) {
+ if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
+ pvr2_trace(PVR2_TRACE_V4LIOCTL,
+ "pvr2_v4l2_do_ioctl failure, ret=%ld", ret);
+ } else {
+ if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
+ pvr2_trace(PVR2_TRACE_V4LIOCTL,
+ "pvr2_v4l2_do_ioctl failure, ret=%ld"
+ " command was:", ret);
+ v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),
+ cmd);
+ }
+ }
+ } else {
+ pvr2_trace(PVR2_TRACE_V4LIOCTL,
+ "pvr2_v4l2_do_ioctl complete, ret=%ld (0x%lx)",
+ ret, ret);
+ }
+ return ret;
+
}
@@ -1262,10 +1309,12 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
struct usb_device *usbdev;
int mindevnum;
int unit_number;
+ struct pvr2_hdw *hdw;
int *nr_ptr = NULL;
dip->v4lp = vp;
- usbdev = pvr2_hdw_get_dev(vp->channel.mc_head->hdw);
+ hdw = vp->channel.mc_head->hdw;
+ usbdev = pvr2_hdw_get_dev(hdw);
dip->v4l_type = v4l_type;
switch (v4l_type) {
case VFL_TYPE_GRABBER:
@@ -1300,9 +1349,17 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
memcpy(&dip->devbase,&vdev_template,sizeof(vdev_template));
dip->devbase.release = pvr2_video_device_release;
+ dip->devbase.ioctl_ops = &pvr2_ioctl_ops;
+ {
+ int val;
+ pvr2_ctrl_get_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,
+ PVR2_CID_STDAVAIL), &val);
+ dip->devbase.tvnorms = (v4l2_std_id)val;
+ }
mindevnum = -1;
- unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw);
+ unit_number = pvr2_hdw_get_unit_number(hdw);
if (nr_ptr && (unit_number >= 0) && (unit_number < PVR_NUM)) {
mindevnum = nr_ptr[unit_number];
}
@@ -1319,7 +1376,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
video_device_node_name(&dip->devbase),
pvr2_config_get_name(dip->config));
- pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
+ pvr2_hdw_v4l_store_minor_number(hdw,
dip->minor_type,dip->devbase.minor);
}
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index 122fbd0081eb..ec4e2ef54e65 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -357,6 +357,7 @@ handler_end:
PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
}
+/* Both v4l2_lock and vb_queue_lock should be locked when calling this */
static int pwc_isoc_init(struct pwc_device *pdev)
{
struct usb_device *udev;
@@ -366,9 +367,6 @@ static int pwc_isoc_init(struct pwc_device *pdev)
struct usb_host_interface *idesc = NULL;
int compression = 0; /* 0..3 = uncompressed..high */
- if (pdev->iso_init)
- return 0;
-
pdev->vsync = 0;
pdev->vlast_packet_size = 0;
pdev->fill_buf = NULL;
@@ -418,7 +416,6 @@ retry:
urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
if (urb == NULL) {
PWC_ERROR("Failed to allocate urb %d\n", i);
- pdev->iso_init = 1;
pwc_isoc_cleanup(pdev);
return -ENOMEM;
}
@@ -435,7 +432,6 @@ retry:
&urb->transfer_dma);
if (urb->transfer_buffer == NULL) {
PWC_ERROR("Failed to allocate urb buffer %d\n", i);
- pdev->iso_init = 1;
pwc_isoc_cleanup(pdev);
return -ENOMEM;
}
@@ -455,13 +451,11 @@ retry:
ret = usb_submit_urb(pdev->urbs[i], GFP_KERNEL);
if (ret == -ENOSPC && compression < 3) {
compression++;
- pdev->iso_init = 1;
pwc_isoc_cleanup(pdev);
goto retry;
}
if (ret) {
PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);
- pdev->iso_init = 1;
pwc_isoc_cleanup(pdev);
return ret;
}
@@ -469,7 +463,6 @@ retry:
}
/* All is done... */
- pdev->iso_init = 1;
PWC_DEBUG_OPEN("<< pwc_isoc_init()\n");
return 0;
}
@@ -507,21 +500,19 @@ static void pwc_iso_free(struct pwc_device *pdev)
}
}
+/* Both v4l2_lock and vb_queue_lock should be locked when calling this */
static void pwc_isoc_cleanup(struct pwc_device *pdev)
{
PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
- if (pdev->iso_init == 0)
- return;
-
pwc_iso_stop(pdev);
pwc_iso_free(pdev);
usb_set_interface(pdev->udev, 0, 0);
- pdev->iso_init = 0;
PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n");
}
+/* Must be called with vb_queue_lock hold */
static void pwc_cleanup_queued_bufs(struct pwc_device *pdev)
{
unsigned long flags = 0;
@@ -573,18 +564,13 @@ static const char *pwc_sensor_type_to_string(unsigned int sensor_type)
int pwc_test_n_set_capt_file(struct pwc_device *pdev, struct file *file)
{
- int r = 0;
-
- mutex_lock(&pdev->capt_file_lock);
if (pdev->capt_file != NULL &&
- pdev->capt_file != file) {
- r = -EBUSY;
- goto leave;
- }
+ pdev->capt_file != file)
+ return -EBUSY;
+
pdev->capt_file = file;
-leave:
- mutex_unlock(&pdev->capt_file_lock);
- return r;
+
+ return 0;
}
static void pwc_video_release(struct v4l2_device *v)
@@ -592,6 +578,7 @@ static void pwc_video_release(struct v4l2_device *v)
struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev);
v4l2_ctrl_handler_free(&pdev->ctrl_handler);
+ v4l2_device_unregister(&pdev->v4l2_dev);
kfree(pdev->ctrl_buf);
kfree(pdev);
}
@@ -600,10 +587,25 @@ static int pwc_video_close(struct file *file)
{
struct pwc_device *pdev = video_drvdata(file);
+ /*
+ * If we're still streaming vb2_queue_release will call stream_stop
+ * so we must take both the v4l2_lock and the vb_queue_lock.
+ */
+ if (mutex_lock_interruptible(&pdev->v4l2_lock))
+ return -ERESTARTSYS;
+ if (mutex_lock_interruptible(&pdev->vb_queue_lock)) {
+ mutex_unlock(&pdev->v4l2_lock);
+ return -ERESTARTSYS;
+ }
+
if (pdev->capt_file == file) {
vb2_queue_release(&pdev->vb_queue);
pdev->capt_file = NULL;
}
+
+ mutex_unlock(&pdev->vb_queue_lock);
+ mutex_unlock(&pdev->v4l2_lock);
+
return v4l2_fh_release(file);
}
@@ -611,35 +613,81 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
struct pwc_device *pdev = video_drvdata(file);
+ int lock_v4l2 = 0;
+ ssize_t ret;
- if (!pdev->udev)
- return -ENODEV;
+ if (mutex_lock_interruptible(&pdev->vb_queue_lock))
+ return -ERESTARTSYS;
- if (pwc_test_n_set_capt_file(pdev, file))
- return -EBUSY;
+ ret = pwc_test_n_set_capt_file(pdev, file);
+ if (ret)
+ goto out;
- return vb2_read(&pdev->vb_queue, buf, count, ppos,
- file->f_flags & O_NONBLOCK);
+ /* stream_start will get called so we must take the v4l2_lock */
+ if (pdev->vb_queue.fileio == NULL)
+ lock_v4l2 = 1;
+
+ /* Use try_lock, since we're taking the locks in the *wrong* order! */
+ if (lock_v4l2 && !mutex_trylock(&pdev->v4l2_lock)) {
+ ret = -ERESTARTSYS;
+ goto out;
+ }
+ ret = vb2_read(&pdev->vb_queue, buf, count, ppos,
+ file->f_flags & O_NONBLOCK);
+ if (lock_v4l2)
+ mutex_unlock(&pdev->v4l2_lock);
+out:
+ mutex_unlock(&pdev->vb_queue_lock);
+ return ret;
}
static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
{
struct pwc_device *pdev = video_drvdata(file);
+ struct vb2_queue *q = &pdev->vb_queue;
+ unsigned long req_events = poll_requested_events(wait);
+ unsigned int ret = POLL_ERR;
+ int lock_v4l2 = 0;
- if (!pdev->udev)
+ if (mutex_lock_interruptible(&pdev->vb_queue_lock))
return POLL_ERR;
- return vb2_poll(&pdev->vb_queue, file, wait);
+ /* Will this start fileio and thus call start_stream? */
+ if ((req_events & (POLLIN | POLLRDNORM)) &&
+ q->num_buffers == 0 && !q->streaming && q->fileio == NULL) {
+ if (pwc_test_n_set_capt_file(pdev, file))
+ goto out;
+ lock_v4l2 = 1;
+ }
+
+ /* Use try_lock, since we're taking the locks in the *wrong* order! */
+ if (lock_v4l2 && !mutex_trylock(&pdev->v4l2_lock))
+ goto out;
+ ret = vb2_poll(&pdev->vb_queue, file, wait);
+ if (lock_v4l2)
+ mutex_unlock(&pdev->v4l2_lock);
+
+out:
+ if (!pdev->udev)
+ ret |= POLLHUP;
+ mutex_unlock(&pdev->vb_queue_lock);
+ return ret;
}
static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
{
struct pwc_device *pdev = video_drvdata(file);
+ int ret;
- if (pdev->capt_file != file)
- return -EBUSY;
+ if (mutex_lock_interruptible(&pdev->vb_queue_lock))
+ return -ERESTARTSYS;
- return vb2_mmap(&pdev->vb_queue, vma);
+ ret = pwc_test_n_set_capt_file(pdev, file);
+ if (ret == 0)
+ ret = vb2_mmap(&pdev->vb_queue, vma);
+
+ mutex_unlock(&pdev->vb_queue_lock);
+ return ret;
}
/***************************************************************************/
@@ -715,12 +763,14 @@ static void buffer_queue(struct vb2_buffer *vb)
struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
unsigned long flags = 0;
- spin_lock_irqsave(&pdev->queued_bufs_lock, flags);
/* Check the device has not disconnected between prep and queuing */
- if (pdev->udev)
- list_add_tail(&buf->list, &pdev->queued_bufs);
- else
+ if (!pdev->udev) {
vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ return;
+ }
+
+ spin_lock_irqsave(&pdev->queued_bufs_lock, flags);
+ list_add_tail(&buf->list, &pdev->queued_bufs);
spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags);
}
@@ -729,11 +779,8 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
struct pwc_device *pdev = vb2_get_drv_priv(vq);
int r;
- mutex_lock(&pdev->udevlock);
- if (!pdev->udev) {
- r = -ENODEV;
- goto leave;
- }
+ if (!pdev->udev)
+ return -ENODEV;
/* Turn on camera and set LEDS on */
pwc_camera_power(pdev, 1);
@@ -747,8 +794,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
/* And cleanup any queued bufs!! */
pwc_cleanup_queued_bufs(pdev);
}
-leave:
- mutex_unlock(&pdev->udevlock);
+
return r;
}
@@ -756,19 +802,29 @@ static int stop_streaming(struct vb2_queue *vq)
{
struct pwc_device *pdev = vb2_get_drv_priv(vq);
- mutex_lock(&pdev->udevlock);
if (pdev->udev) {
pwc_set_leds(pdev, 0, 0);
pwc_camera_power(pdev, 0);
pwc_isoc_cleanup(pdev);
}
- mutex_unlock(&pdev->udevlock);
pwc_cleanup_queued_bufs(pdev);
return 0;
}
+static void wait_prepare(struct vb2_queue *vq)
+{
+ struct pwc_device *pdev = vb2_get_drv_priv(vq);
+ mutex_unlock(&pdev->vb_queue_lock);
+}
+
+static void wait_finish(struct vb2_queue *vq)
+{
+ struct pwc_device *pdev = vb2_get_drv_priv(vq);
+ mutex_lock(&pdev->vb_queue_lock);
+}
+
static struct vb2_ops pwc_vb_queue_ops = {
.queue_setup = queue_setup,
.buf_init = buffer_init,
@@ -778,6 +834,8 @@ static struct vb2_ops pwc_vb_queue_ops = {
.buf_queue = buffer_queue,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
+ .wait_prepare = wait_prepare,
+ .wait_finish = wait_finish,
};
/***************************************************************************/
@@ -1057,8 +1115,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->features = features;
pwc_construct(pdev); /* set min/max sizes correct */
- mutex_init(&pdev->capt_file_lock);
- mutex_init(&pdev->udevlock);
+ mutex_init(&pdev->v4l2_lock);
+ mutex_init(&pdev->vb_queue_lock);
spin_lock_init(&pdev->queued_bufs_lock);
INIT_LIST_HEAD(&pdev->queued_bufs);
@@ -1130,6 +1188,16 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->v4l2_dev.ctrl_handler = &pdev->ctrl_handler;
pdev->vdev.v4l2_dev = &pdev->v4l2_dev;
+ pdev->vdev.lock = &pdev->v4l2_lock;
+
+ /*
+ * Don't take v4l2_lock for these ioctls. This improves latency if
+ * v4l2_lock is taken for a long time, e.g. when changing a control
+ * value, and a new frame is ready to be dequeued.
+ */
+ v4l2_disable_ioctl_locking(&pdev->vdev, VIDIOC_DQBUF);
+ v4l2_disable_ioctl_locking(&pdev->vdev, VIDIOC_QBUF);
+ v4l2_disable_ioctl_locking(&pdev->vdev, VIDIOC_QUERYBUF);
rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, -1);
if (rc < 0) {
@@ -1185,16 +1253,20 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
struct v4l2_device *v = usb_get_intfdata(intf);
struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev);
- mutex_lock(&pdev->udevlock);
+ mutex_lock(&pdev->v4l2_lock);
+
+ mutex_lock(&pdev->vb_queue_lock);
/* No need to keep the urbs around after disconnection */
- pwc_isoc_cleanup(pdev);
+ if (pdev->vb_queue.streaming)
+ pwc_isoc_cleanup(pdev);
pdev->udev = NULL;
- mutex_unlock(&pdev->udevlock);
-
pwc_cleanup_queued_bufs(pdev);
+ mutex_unlock(&pdev->vb_queue_lock);
+ v4l2_device_disconnect(&pdev->v4l2_dev);
video_unregister_device(&pdev->vdev);
- v4l2_device_unregister(&pdev->v4l2_dev);
+
+ mutex_unlock(&pdev->v4l2_lock);
#ifdef CONFIG_USB_PWC_INPUT_EVDEV
if (pdev->button_dev)
@@ -1229,15 +1301,4 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS("pwcx");
MODULE_VERSION( PWC_VERSION );
-static int __init usb_pwc_init(void)
-{
- return usb_register(&pwc_driver);
-}
-
-static void __exit usb_pwc_exit(void)
-{
- usb_deregister(&pwc_driver);
-}
-
-module_init(usb_pwc_init);
-module_exit(usb_pwc_exit);
+module_usb_driver(pwc_driver);
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
index 2834e3e65b39..c691e29cc36e 100644
--- a/drivers/media/video/pwc/pwc-v4l.c
+++ b/drivers/media/video/pwc/pwc-v4l.c
@@ -464,26 +464,24 @@ static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
struct pwc_device *pdev = video_drvdata(file);
int ret, pixelformat, compression = 0;
- if (pwc_test_n_set_capt_file(pdev, file))
- return -EBUSY;
-
ret = pwc_vidioc_try_fmt(pdev, f);
if (ret < 0)
return ret;
- pixelformat = f->fmt.pix.pixelformat;
+ if (mutex_lock_interruptible(&pdev->vb_queue_lock))
+ return -ERESTARTSYS;
- mutex_lock(&pdev->udevlock);
- if (!pdev->udev) {
- ret = -ENODEV;
+ ret = pwc_test_n_set_capt_file(pdev, file);
+ if (ret)
goto leave;
- }
- if (pdev->iso_init) {
+ if (pdev->vb_queue.streaming) {
ret = -EBUSY;
goto leave;
}
+ pixelformat = f->fmt.pix.pixelformat;
+
PWC_DEBUG_IOCTL("Trying to set format to: width=%d height=%d fps=%d "
"format=%c%c%c%c\n",
f->fmt.pix.width, f->fmt.pix.height, pdev->vframes,
@@ -499,7 +497,7 @@ static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
pwc_vidioc_fill_fmt(f, pdev->width, pdev->height, pdev->pixfmt);
leave:
- mutex_unlock(&pdev->udevlock);
+ mutex_unlock(&pdev->vb_queue_lock);
return ret;
}
@@ -507,9 +505,6 @@ static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap
{
struct pwc_device *pdev = video_drvdata(file);
- if (!pdev->udev)
- return -ENODEV;
-
strcpy(cap->driver, PWC_NAME);
strlcpy(cap->card, pdev->vdev.name, sizeof(cap->card));
usb_make_path(pdev->udev, cap->bus_info, sizeof(cap->bus_info));
@@ -540,15 +535,12 @@ static int pwc_s_input(struct file *file, void *fh, unsigned int i)
return i ? -EINVAL : 0;
}
-static int pwc_g_volatile_ctrl_unlocked(struct v4l2_ctrl *ctrl)
+static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
struct pwc_device *pdev =
container_of(ctrl->handler, struct pwc_device, ctrl_handler);
int ret = 0;
- if (!pdev->udev)
- return -ENODEV;
-
switch (ctrl->id) {
case V4L2_CID_AUTO_WHITE_BALANCE:
if (pdev->color_bal_valid &&
@@ -615,18 +607,6 @@ static int pwc_g_volatile_ctrl_unlocked(struct v4l2_ctrl *ctrl)
return ret;
}
-static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct pwc_device *pdev =
- container_of(ctrl->handler, struct pwc_device, ctrl_handler);
- int ret;
-
- mutex_lock(&pdev->udevlock);
- ret = pwc_g_volatile_ctrl_unlocked(ctrl);
- mutex_unlock(&pdev->udevlock);
- return ret;
-}
-
static int pwc_set_awb(struct pwc_device *pdev)
{
int ret;
@@ -648,7 +628,7 @@ static int pwc_set_awb(struct pwc_device *pdev)
if (pdev->auto_white_balance->val == awb_indoor ||
pdev->auto_white_balance->val == awb_outdoor ||
pdev->auto_white_balance->val == awb_fl)
- pwc_g_volatile_ctrl_unlocked(pdev->auto_white_balance);
+ pwc_g_volatile_ctrl(pdev->auto_white_balance);
}
if (pdev->auto_white_balance->val != awb_manual)
return 0;
@@ -812,13 +792,6 @@ static int pwc_s_ctrl(struct v4l2_ctrl *ctrl)
container_of(ctrl->handler, struct pwc_device, ctrl_handler);
int ret = 0;
- mutex_lock(&pdev->udevlock);
-
- if (!pdev->udev) {
- ret = -ENODEV;
- goto leave;
- }
-
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
@@ -915,8 +888,6 @@ static int pwc_s_ctrl(struct v4l2_ctrl *ctrl)
if (ret)
PWC_ERROR("s_ctrl %s error %d\n", ctrl->name, ret);
-leave:
- mutex_unlock(&pdev->udevlock);
return ret;
}
@@ -949,11 +920,9 @@ static int pwc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- mutex_lock(&pdev->udevlock); /* To avoid race with s_fmt */
PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",
pdev->width, pdev->height);
pwc_vidioc_fill_fmt(f, pdev->width, pdev->height, pdev->pixfmt);
- mutex_unlock(&pdev->udevlock);
return 0;
}
@@ -968,70 +937,98 @@ static int pwc_reqbufs(struct file *file, void *fh,
struct v4l2_requestbuffers *rb)
{
struct pwc_device *pdev = video_drvdata(file);
+ int ret;
- if (pwc_test_n_set_capt_file(pdev, file))
- return -EBUSY;
+ if (mutex_lock_interruptible(&pdev->vb_queue_lock))
+ return -ERESTARTSYS;
- return vb2_reqbufs(&pdev->vb_queue, rb);
+ ret = pwc_test_n_set_capt_file(pdev, file);
+ if (ret == 0)
+ ret = vb2_reqbufs(&pdev->vb_queue, rb);
+
+ mutex_unlock(&pdev->vb_queue_lock);
+ return ret;
}
static int pwc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
{
struct pwc_device *pdev = video_drvdata(file);
+ int ret;
- return vb2_querybuf(&pdev->vb_queue, buf);
+ if (mutex_lock_interruptible(&pdev->vb_queue_lock))
+ return -ERESTARTSYS;
+
+ ret = pwc_test_n_set_capt_file(pdev, file);
+ if (ret == 0)
+ ret = vb2_querybuf(&pdev->vb_queue, buf);
+
+ mutex_unlock(&pdev->vb_queue_lock);
+ return ret;
}
static int pwc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
{
struct pwc_device *pdev = video_drvdata(file);
+ int ret;
- if (!pdev->udev)
- return -ENODEV;
+ if (mutex_lock_interruptible(&pdev->vb_queue_lock))
+ return -ERESTARTSYS;
- if (pdev->capt_file != file)
- return -EBUSY;
+ ret = pwc_test_n_set_capt_file(pdev, file);
+ if (ret == 0)
+ ret = vb2_qbuf(&pdev->vb_queue, buf);
- return vb2_qbuf(&pdev->vb_queue, buf);
+ mutex_unlock(&pdev->vb_queue_lock);
+ return ret;
}
static int pwc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
{
struct pwc_device *pdev = video_drvdata(file);
+ int ret;
- if (!pdev->udev)
- return -ENODEV;
+ if (mutex_lock_interruptible(&pdev->vb_queue_lock))
+ return -ERESTARTSYS;
- if (pdev->capt_file != file)
- return -EBUSY;
+ ret = pwc_test_n_set_capt_file(pdev, file);
+ if (ret == 0)
+ ret = vb2_dqbuf(&pdev->vb_queue, buf,
+ file->f_flags & O_NONBLOCK);
- return vb2_dqbuf(&pdev->vb_queue, buf, file->f_flags & O_NONBLOCK);
+ mutex_unlock(&pdev->vb_queue_lock);
+ return ret;
}
static int pwc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
{
struct pwc_device *pdev = video_drvdata(file);
+ int ret;
- if (!pdev->udev)
- return -ENODEV;
+ if (mutex_lock_interruptible(&pdev->vb_queue_lock))
+ return -ERESTARTSYS;
- if (pdev->capt_file != file)
- return -EBUSY;
+ ret = pwc_test_n_set_capt_file(pdev, file);
+ if (ret == 0)
+ ret = vb2_streamon(&pdev->vb_queue, i);
- return vb2_streamon(&pdev->vb_queue, i);
+ mutex_unlock(&pdev->vb_queue_lock);
+ return ret;
}
static int pwc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
{
struct pwc_device *pdev = video_drvdata(file);
+ int ret;
- if (!pdev->udev)
- return -ENODEV;
+ if (mutex_lock_interruptible(&pdev->vb_queue_lock))
+ return -ERESTARTSYS;
- if (pdev->capt_file != file)
- return -EBUSY;
+ ret = pwc_test_n_set_capt_file(pdev, file);
+ if (ret == 0)
+ ret = vb2_streamoff(&pdev->vb_queue, i);
- return vb2_streamoff(&pdev->vb_queue, i);
+ mutex_unlock(&pdev->vb_queue_lock);
+ return ret;
}
static int pwc_enum_framesizes(struct file *file, void *fh,
@@ -1119,19 +1116,17 @@ static int pwc_s_parm(struct file *file, void *fh,
parm->parm.capture.timeperframe.numerator == 0)
return -EINVAL;
- if (pwc_test_n_set_capt_file(pdev, file))
- return -EBUSY;
-
fps = parm->parm.capture.timeperframe.denominator /
parm->parm.capture.timeperframe.numerator;
- mutex_lock(&pdev->udevlock);
- if (!pdev->udev) {
- ret = -ENODEV;
+ if (mutex_lock_interruptible(&pdev->vb_queue_lock))
+ return -ERESTARTSYS;
+
+ ret = pwc_test_n_set_capt_file(pdev, file);
+ if (ret)
goto leave;
- }
- if (pdev->iso_init) {
+ if (pdev->vb_queue.streaming) {
ret = -EBUSY;
goto leave;
}
@@ -1142,7 +1137,7 @@ static int pwc_s_parm(struct file *file, void *fh,
pwc_g_parm(file, fh, parm);
leave:
- mutex_unlock(&pdev->udevlock);
+ mutex_unlock(&pdev->vb_queue_lock);
return ret;
}
@@ -1166,4 +1161,6 @@ const struct v4l2_ioctl_ops pwc_ioctl_ops = {
.vidioc_enum_frameintervals = pwc_enum_frameintervals,
.vidioc_g_parm = pwc_g_parm,
.vidioc_s_parm = pwc_s_parm,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h
index e4d4d711dd1f..d6b5b216b9d6 100644
--- a/drivers/media/video/pwc/pwc.h
+++ b/drivers/media/video/pwc/pwc.h
@@ -221,9 +221,17 @@ struct pwc_device
struct video_device vdev;
struct v4l2_device v4l2_dev;
- /* Pointer to our usb_device, may be NULL after unplug */
- struct usb_device *udev;
- struct mutex udevlock;
+ /* videobuf2 queue and queued buffers list */
+ struct vb2_queue vb_queue;
+ struct list_head queued_bufs;
+ spinlock_t queued_bufs_lock; /* Protects queued_bufs */
+
+ /* Note if taking both locks v4l2_lock must always be locked first! */
+ struct mutex v4l2_lock; /* Protects everything else */
+ struct mutex vb_queue_lock; /* Protects vb_queue and capt_file */
+
+ /* Pointer to our usb_device, will be NULL after unplug */
+ struct usb_device *udev; /* Both mutexes most be hold when setting! */
/* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */
int type;
@@ -232,7 +240,6 @@ struct pwc_device
/*** Video data ***/
struct file *capt_file; /* file doing video capture */
- struct mutex capt_file_lock;
int vendpoint; /* video isoc endpoint */
int vcinterface; /* video control interface */
int valternate; /* alternate interface needed */
@@ -251,12 +258,6 @@ struct pwc_device
unsigned char *ctrl_buf;
struct urb *urbs[MAX_ISO_BUFS];
- char iso_init;
-
- /* videobuf2 queue and queued buffers list */
- struct vb2_queue vb_queue;
- struct list_head queued_bufs;
- spinlock_t queued_bufs_lock;
/*
* Frame currently being filled, this only gets touched by the
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index 5a413f4427e0..9c21e01f2c24 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -241,15 +241,10 @@ static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
unsigned int *size)
{
struct soc_camera_device *icd = vq->priv_data;
- int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
- icd->current_fmt->host_fmt);
-
- if (bytes_per_line < 0)
- return bytes_per_line;
dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size);
- *size = bytes_per_line * icd->user_height;
+ *size = icd->sizeimage;
if (0 == *count)
*count = 32;
@@ -435,11 +430,6 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
int ret;
int size_y, size_u = 0, size_v = 0;
- int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
- icd->current_fmt->host_fmt);
-
- if (bytes_per_line < 0)
- return bytes_per_line;
dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
vb, vb->baddr, vb->bsize);
@@ -474,7 +464,7 @@ static int pxa_videobuf_prepare(struct videobuf_queue *vq,
vb->state = VIDEOBUF_NEEDS_INIT;
}
- vb->size = bytes_per_line * vb->height;
+ vb->size = icd->sizeimage;
if (0 != vb->baddr && vb->bsize < vb->size) {
ret = -EINVAL;
goto out;
@@ -1244,6 +1234,7 @@ static const struct soc_mbus_pixelfmt pxa_camera_formats[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PLANAR_2Y_U_V,
},
};
diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c
index 4894cbb1c547..01c2179f0520 100644
--- a/drivers/media/video/s2255drv.c
+++ b/drivers/media/video/s2255drv.c
@@ -634,13 +634,11 @@ static void s2255_fillbuff(struct s2255_channel *channel,
const char *tmpbuf;
char *vbuf = videobuf_to_vmalloc(&buf->vb);
unsigned long last_frame;
- struct s2255_framei *frm;
if (!vbuf)
return;
last_frame = channel->last_frame;
if (last_frame != -1) {
- frm = &channel->buffer.frame[last_frame];
tmpbuf =
(const char *)channel->buffer.frame[last_frame].lpvbits;
switch (buf->fmt->fourcc) {
@@ -987,7 +985,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct videobuf_queue *q = &fh->vb_vidq;
struct s2255_mode mode;
int ret;
- int norm;
ret = vidioc_try_fmt_vid_cap(file, fh, f);
@@ -1018,7 +1015,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
channel->height = f->fmt.pix.height;
fh->vb_vidq.field = f->fmt.pix.field;
fh->type = f->type;
- norm = norm_minw(&channel->vdev);
if (channel->width > norm_minw(&channel->vdev)) {
if (channel->height > norm_minh(&channel->vdev)) {
if (channel->cap_parm.capturemode &
@@ -1826,8 +1822,7 @@ static void s2255_destroy(struct s2255_dev *dev)
usb_free_urb(dev->fw_data->fw_urb);
dev->fw_data->fw_urb = NULL;
}
- if (dev->fw_data->fw)
- release_firmware(dev->fw_data->fw);
+ release_firmware(dev->fw_data->fw);
kfree(dev->fw_data->pfw_data);
kfree(dev->fw_data);
/* reset the DSP so firmware can be reloaded next time */
@@ -1949,6 +1944,10 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
/* register 4 video devices */
channel->vdev = template;
channel->vdev.lock = &dev->lock;
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &channel->vdev.flags);
channel->vdev.v4l2_dev = &dev->v4l2_dev;
video_set_drvdata(&channel->vdev, channel);
if (video_nr == -1)
diff --git a/drivers/media/video/s5p-fimc/Kconfig b/drivers/media/video/s5p-fimc/Kconfig
new file mode 100644
index 000000000000..a564f7eeb064
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/Kconfig
@@ -0,0 +1,48 @@
+
+config VIDEO_SAMSUNG_S5P_FIMC
+ bool "Samsung S5P/EXYNOS SoC camera interface driver (experimental)"
+ depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && PLAT_S5P && PM_RUNTIME
+ depends on EXPERIMENTAL
+ help
+ Say Y here to enable camera host interface devices for
+ Samsung S5P and EXYNOS SoC series.
+
+if VIDEO_SAMSUNG_S5P_FIMC
+
+config VIDEO_S5P_FIMC
+ tristate "S5P/EXYNOS4 FIMC/CAMIF camera interface driver"
+ depends on I2C
+ select VIDEOBUF2_DMA_CONTIG
+ select V4L2_MEM2MEM_DEV
+ help
+ This is a V4L2 driver for Samsung S5P and EXYNOS4 SoC camera host
+ interface and video postprocessor (FIMC and FIMC-LITE) devices.
+
+ To compile this driver as a module, choose M here: the
+ module will be called s5p-fimc.
+
+config VIDEO_S5P_MIPI_CSIS
+ tristate "S5P/EXYNOS MIPI-CSI2 receiver (MIPI-CSIS) driver"
+ depends on REGULATOR
+ help
+ This is a V4L2 driver for Samsung S5P and EXYNOS4 SoC MIPI-CSI2
+ receiver (MIPI-CSIS) devices.
+
+ To compile this driver as a module, choose M here: the
+ module will be called s5p-csis.
+
+if ARCH_EXYNOS
+
+config VIDEO_EXYNOS_FIMC_LITE
+ tristate "EXYNOS FIMC-LITE camera interface driver"
+ depends on I2C
+ select VIDEOBUF2_DMA_CONTIG
+ help
+ This is a V4L2 driver for Samsung EXYNOS4/5 SoC FIMC-LITE camera
+ host interface.
+
+ To compile this driver as a module, choose M here: the
+ module will be called exynos-fimc-lite.
+endif
+
+endif # VIDEO_SAMSUNG_S5P_FIMC
diff --git a/drivers/media/video/s5p-fimc/Makefile b/drivers/media/video/s5p-fimc/Makefile
index 33dec7f890e7..46485143e1ca 100644
--- a/drivers/media/video/s5p-fimc/Makefile
+++ b/drivers/media/video/s5p-fimc/Makefile
@@ -1,5 +1,7 @@
-s5p-fimc-objs := fimc-core.o fimc-reg.o fimc-capture.o fimc-mdevice.o
+s5p-fimc-objs := fimc-core.o fimc-reg.o fimc-m2m.o fimc-capture.o fimc-mdevice.o
+exynos-fimc-lite-objs += fimc-lite-reg.o fimc-lite.o
s5p-csis-objs := mipi-csis.o
obj-$(CONFIG_VIDEO_S5P_MIPI_CSIS) += s5p-csis.o
-obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc.o
+obj-$(CONFIG_VIDEO_EXYNOS_FIMC_LITE) += exynos-fimc-lite.o
+obj-$(CONFIG_VIDEO_S5P_FIMC) += s5p-fimc.o
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c
index 7e9b2c612b03..354574591908 100644
--- a/drivers/media/video/s5p-fimc/fimc-capture.c
+++ b/drivers/media/video/s5p-fimc/fimc-capture.c
@@ -1,8 +1,8 @@
/*
* Samsung S5P/EXYNOS4 SoC series camera interface (camera capture) driver
*
- * Copyright (C) 2010 - 2011 Samsung Electronics Co., Ltd.
- * Author: Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@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
@@ -29,20 +29,22 @@
#include "fimc-mdevice.h"
#include "fimc-core.h"
+#include "fimc-reg.h"
-static int fimc_init_capture(struct fimc_dev *fimc)
+static int fimc_capture_hw_init(struct fimc_dev *fimc)
{
struct fimc_ctx *ctx = fimc->vid_cap.ctx;
+ struct fimc_pipeline *p = &fimc->pipeline;
struct fimc_sensor_info *sensor;
unsigned long flags;
int ret = 0;
- if (fimc->pipeline.sensor == NULL || ctx == NULL)
+ if (p->subdevs[IDX_SENSOR] == NULL || ctx == NULL)
return -ENXIO;
if (ctx->s_frame.fmt == NULL)
return -EINVAL;
- sensor = v4l2_get_subdev_hostdata(fimc->pipeline.sensor);
+ sensor = v4l2_get_subdev_hostdata(p->subdevs[IDX_SENSOR]);
spin_lock_irqsave(&fimc->slock, flags);
fimc_prepare_dma_offset(ctx, &ctx->d_frame);
@@ -60,7 +62,7 @@ static int fimc_init_capture(struct fimc_dev *fimc)
fimc_hw_set_mainscaler(ctx);
fimc_hw_set_target_format(ctx);
fimc_hw_set_rotation(ctx);
- fimc_hw_set_effect(ctx, false);
+ fimc_hw_set_effect(ctx);
fimc_hw_set_output_path(ctx);
fimc_hw_set_out_dma(ctx);
if (fimc->variant->has_alpha)
@@ -71,6 +73,14 @@ static int fimc_init_capture(struct fimc_dev *fimc)
return ret;
}
+/*
+ * Reinitialize the driver so it is ready to start the streaming again.
+ * Set fimc->state to indicate stream off and the hardware shut down state.
+ * If not suspending (@suspend is false), return any buffers to videobuf2.
+ * Otherwise put any owned buffers onto the pending buffers queue, so they
+ * can be re-spun when the device is being resumed. Also perform FIMC
+ * software reset and disable streaming on the whole pipeline if required.
+ */
static int fimc_capture_state_cleanup(struct fimc_dev *fimc, bool suspend)
{
struct fimc_vid_cap *cap = &fimc->vid_cap;
@@ -83,7 +93,9 @@ static int fimc_capture_state_cleanup(struct fimc_dev *fimc, bool suspend)
fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_SHUT |
1 << ST_CAPT_STREAM | 1 << ST_CAPT_ISP_STREAM);
- if (!suspend)
+ if (suspend)
+ fimc->state |= (1 << ST_CAPT_SUSPENDED);
+ else
fimc->state &= ~(1 << ST_CAPT_PEND | 1 << ST_CAPT_SUSPENDED);
/* Release unused buffers */
@@ -99,7 +111,6 @@ static int fimc_capture_state_cleanup(struct fimc_dev *fimc, bool suspend)
else
vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
}
- set_bit(ST_CAPT_SUSPENDED, &fimc->state);
fimc_hw_reset(fimc);
cap->buf_index = 0;
@@ -107,7 +118,7 @@ static int fimc_capture_state_cleanup(struct fimc_dev *fimc, bool suspend)
spin_unlock_irqrestore(&fimc->slock, flags);
if (streaming)
- return fimc_pipeline_s_stream(fimc, 0);
+ return fimc_pipeline_s_stream(&fimc->pipeline, 0);
else
return 0;
}
@@ -138,32 +149,96 @@ static int fimc_stop_capture(struct fimc_dev *fimc, bool suspend)
* spinlock held. It updates the camera pixel crop, rotation and
* image flip in H/W.
*/
-int fimc_capture_config_update(struct fimc_ctx *ctx)
+static int fimc_capture_config_update(struct fimc_ctx *ctx)
{
struct fimc_dev *fimc = ctx->fimc_dev;
int ret;
- if (!test_bit(ST_CAPT_APPLY_CFG, &fimc->state))
- return 0;
-
- spin_lock(&ctx->slock);
fimc_hw_set_camera_offset(fimc, &ctx->s_frame);
+
ret = fimc_set_scaler_info(ctx);
- if (ret == 0) {
- fimc_hw_set_prescaler(ctx);
- fimc_hw_set_mainscaler(ctx);
- fimc_hw_set_target_format(ctx);
- fimc_hw_set_rotation(ctx);
- fimc_prepare_dma_offset(ctx, &ctx->d_frame);
- fimc_hw_set_out_dma(ctx);
- if (fimc->variant->has_alpha)
- fimc_hw_set_rgb_alpha(ctx);
- clear_bit(ST_CAPT_APPLY_CFG, &fimc->state);
- }
- spin_unlock(&ctx->slock);
+ if (ret)
+ return ret;
+
+ fimc_hw_set_prescaler(ctx);
+ fimc_hw_set_mainscaler(ctx);
+ fimc_hw_set_target_format(ctx);
+ fimc_hw_set_rotation(ctx);
+ fimc_hw_set_effect(ctx);
+ fimc_prepare_dma_offset(ctx, &ctx->d_frame);
+ fimc_hw_set_out_dma(ctx);
+ if (fimc->variant->has_alpha)
+ fimc_hw_set_rgb_alpha(ctx);
+
+ clear_bit(ST_CAPT_APPLY_CFG, &fimc->state);
return ret;
}
+void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf)
+{
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ struct fimc_vid_buffer *v_buf;
+ struct timeval *tv;
+ struct timespec ts;
+
+ if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) {
+ wake_up(&fimc->irq_queue);
+ goto done;
+ }
+
+ if (!list_empty(&cap->active_buf_q) &&
+ test_bit(ST_CAPT_RUN, &fimc->state) && deq_buf) {
+ ktime_get_real_ts(&ts);
+
+ v_buf = fimc_active_queue_pop(cap);
+
+ tv = &v_buf->vb.v4l2_buf.timestamp;
+ tv->tv_sec = ts.tv_sec;
+ tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+ v_buf->vb.v4l2_buf.sequence = cap->frame_count++;
+
+ vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE);
+ }
+
+ if (!list_empty(&cap->pending_buf_q)) {
+
+ v_buf = fimc_pending_queue_pop(cap);
+ fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index);
+ v_buf->index = cap->buf_index;
+
+ /* Move the buffer to the capture active queue */
+ fimc_active_queue_add(cap, v_buf);
+
+ dbg("next frame: %d, done frame: %d",
+ fimc_hw_get_frame_index(fimc), v_buf->index);
+
+ if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
+ cap->buf_index = 0;
+ }
+
+ if (cap->active_buf_cnt == 0) {
+ if (deq_buf)
+ clear_bit(ST_CAPT_RUN, &fimc->state);
+
+ if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
+ cap->buf_index = 0;
+ } else {
+ set_bit(ST_CAPT_RUN, &fimc->state);
+ }
+
+ if (test_bit(ST_CAPT_APPLY_CFG, &fimc->state))
+ fimc_capture_config_update(cap->ctx);
+done:
+ if (cap->active_buf_cnt == 1) {
+ fimc_deactivate_capture(fimc);
+ clear_bit(ST_CAPT_STREAM, &fimc->state);
+ }
+
+ dbg("frame: %d, active_buf_cnt: %d",
+ fimc_hw_get_frame_index(fimc), cap->active_buf_cnt);
+}
+
+
static int start_streaming(struct vb2_queue *q, unsigned int count)
{
struct fimc_ctx *ctx = q->drv_priv;
@@ -174,9 +249,11 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
vid_cap->frame_count = 0;
- ret = fimc_init_capture(fimc);
- if (ret)
- goto error;
+ ret = fimc_capture_hw_init(fimc);
+ if (ret) {
+ fimc_capture_state_cleanup(fimc, false);
+ return ret;
+ }
set_bit(ST_CAPT_PEND, &fimc->state);
@@ -187,13 +264,10 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
fimc_activate_capture(ctx);
if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state))
- fimc_pipeline_s_stream(fimc, 1);
+ fimc_pipeline_s_stream(&fimc->pipeline, 1);
}
return 0;
-error:
- fimc_capture_state_cleanup(fimc, false);
- return ret;
}
static int stop_streaming(struct vb2_queue *q)
@@ -214,7 +288,7 @@ int fimc_capture_suspend(struct fimc_dev *fimc)
int ret = fimc_stop_capture(fimc, suspend);
if (ret)
return ret;
- return fimc_pipeline_shutdown(fimc);
+ return fimc_pipeline_shutdown(&fimc->pipeline);
}
static void buffer_queue(struct vb2_buffer *vb);
@@ -230,9 +304,9 @@ int fimc_capture_resume(struct fimc_dev *fimc)
INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q);
vid_cap->buf_index = 0;
- fimc_pipeline_initialize(fimc, &fimc->vid_cap.vfd->entity,
+ fimc_pipeline_initialize(&fimc->pipeline, &vid_cap->vfd->entity,
false);
- fimc_init_capture(fimc);
+ fimc_capture_hw_init(fimc);
clear_bit(ST_CAPT_SUSPENDED, &fimc->state);
@@ -347,7 +421,7 @@ static void buffer_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(&fimc->slock, flags);
if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state))
- fimc_pipeline_s_stream(fimc, 1);
+ fimc_pipeline_s_stream(&fimc->pipeline, 1);
return;
}
spin_unlock_irqrestore(&fimc->slock, flags);
@@ -389,15 +463,15 @@ int fimc_capture_ctrls_create(struct fimc_dev *fimc)
if (WARN_ON(vid_cap->ctx == NULL))
return -ENXIO;
- if (vid_cap->ctx->ctrls_rdy)
+ if (vid_cap->ctx->ctrls.ready)
return 0;
ret = fimc_ctrls_create(vid_cap->ctx);
- if (ret || vid_cap->user_subdev_api)
+ if (ret || vid_cap->user_subdev_api || !vid_cap->ctx->ctrls.ready)
return ret;
- return v4l2_ctrl_add_handler(&vid_cap->ctx->ctrl_handler,
- fimc->pipeline.sensor->ctrl_handler);
+ return v4l2_ctrl_add_handler(&vid_cap->ctx->ctrls.handler,
+ fimc->pipeline.subdevs[IDX_SENSOR]->ctrl_handler);
}
static int fimc_capture_set_default_format(struct fimc_dev *fimc);
@@ -420,7 +494,7 @@ static int fimc_capture_open(struct file *file)
pm_runtime_get_sync(&fimc->pdev->dev);
if (++fimc->vid_cap.refcnt == 1) {
- ret = fimc_pipeline_initialize(fimc,
+ ret = fimc_pipeline_initialize(&fimc->pipeline,
&fimc->vid_cap.vfd->entity, true);
if (ret < 0) {
dev_err(&fimc->pdev->dev,
@@ -448,7 +522,7 @@ static int fimc_capture_close(struct file *file)
if (--fimc->vid_cap.refcnt == 0) {
clear_bit(ST_CAPT_BUSY, &fimc->state);
fimc_stop_capture(fimc, false);
- fimc_pipeline_shutdown(fimc);
+ fimc_pipeline_shutdown(&fimc->pipeline);
clear_bit(ST_CAPT_SUSPENDED, &fimc->state);
}
@@ -495,7 +569,7 @@ static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx,
{
bool rotation = ctx->rotation == 90 || ctx->rotation == 270;
struct fimc_dev *fimc = ctx->fimc_dev;
- struct samsung_fimc_variant *var = fimc->variant;
+ struct fimc_variant *var = fimc->variant;
struct fimc_pix_limit *pl = var->pix_limit;
struct fimc_frame *dst = &ctx->d_frame;
u32 depth, min_w, max_w, min_h, align_h = 3;
@@ -537,8 +611,13 @@ static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx,
}
/* Apply the scaler and the output DMA constraints */
max_w = rotation ? pl->out_rot_en_w : pl->out_rot_dis_w;
- min_w = ctx->state & FIMC_DST_CROP ? dst->width : var->min_out_pixsize;
- min_h = ctx->state & FIMC_DST_CROP ? dst->height : var->min_out_pixsize;
+ if (ctx->state & FIMC_COMPOSE) {
+ min_w = dst->offs_h + dst->width;
+ min_h = dst->offs_v + dst->height;
+ } else {
+ min_w = var->min_out_pixsize;
+ min_h = var->min_out_pixsize;
+ }
if (var->min_vsize_align == 1 && !rotation)
align_h = fimc_fmt_is_rgb(ffmt->color) ? 0 : 1;
@@ -556,12 +635,13 @@ static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx,
return ffmt;
}
-static void fimc_capture_try_crop(struct fimc_ctx *ctx, struct v4l2_rect *r,
- int pad)
+static void fimc_capture_try_selection(struct fimc_ctx *ctx,
+ struct v4l2_rect *r,
+ int target)
{
bool rotate = ctx->rotation == 90 || ctx->rotation == 270;
struct fimc_dev *fimc = ctx->fimc_dev;
- struct samsung_fimc_variant *var = fimc->variant;
+ struct fimc_variant *var = fimc->variant;
struct fimc_pix_limit *pl = var->pix_limit;
struct fimc_frame *sink = &ctx->s_frame;
u32 max_w, max_h, min_w = 0, min_h = 0, min_sz;
@@ -575,7 +655,7 @@ static void fimc_capture_try_crop(struct fimc_ctx *ctx, struct v4l2_rect *r,
r->left = r->top = 0;
return;
}
- if (pad == FIMC_SD_PAD_SOURCE) {
+ if (target == V4L2_SEL_TGT_COMPOSE_ACTIVE) {
if (ctx->rotation != 90 && ctx->rotation != 270)
align_h = 1;
max_sc_h = min(SCALER_MAX_HRATIO, 1 << (ffs(sink->width) - 3));
@@ -589,8 +669,7 @@ static void fimc_capture_try_crop(struct fimc_ctx *ctx, struct v4l2_rect *r,
max_sc_h = max_sc_v = 1;
}
/*
- * For the crop rectangle at source pad the following constraints
- * must be met:
+ * For the compose rectangle the following constraints must be met:
* - it must fit in the sink pad format rectangle (f_width/f_height);
* - maximum downscaling ratio is 64;
* - maximum crop size depends if the rotator is used or not;
@@ -602,7 +681,8 @@ static void fimc_capture_try_crop(struct fimc_ctx *ctx, struct v4l2_rect *r,
rotate ? pl->out_rot_en_w : pl->out_rot_dis_w,
rotate ? sink->f_height : sink->f_width);
max_h = min_t(u32, FIMC_CAMIF_MAX_HEIGHT, sink->f_height);
- if (pad == FIMC_SD_PAD_SOURCE) {
+
+ if (target == V4L2_SEL_TGT_COMPOSE_ACTIVE) {
min_w = min_t(u32, max_w, sink->f_width / max_sc_h);
min_h = min_t(u32, max_h, sink->f_height / max_sc_v);
if (rotate) {
@@ -613,13 +693,13 @@ static void fimc_capture_try_crop(struct fimc_ctx *ctx, struct v4l2_rect *r,
v4l_bound_align_image(&r->width, min_w, max_w, ffs(min_sz) - 1,
&r->height, min_h, max_h, align_h,
align_sz);
- /* Adjust left/top if cropping rectangle is out of bounds */
+ /* Adjust left/top if crop/compose rectangle is out of bounds */
r->left = clamp_t(u32, r->left, 0, sink->f_width - r->width);
r->top = clamp_t(u32, r->top, 0, sink->f_height - r->height);
r->left = round_down(r->left, var->hor_offs_align);
- dbg("pad%d: (%d,%d)/%dx%d, sink fmt: %dx%d",
- pad, r->left, r->top, r->width, r->height,
+ dbg("target %#x: (%d,%d)/%dx%d, sink fmt: %dx%d",
+ target, r->left, r->top, r->width, r->height,
sink->f_width, sink->f_height);
}
@@ -669,8 +749,8 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx,
bool set)
{
struct fimc_dev *fimc = ctx->fimc_dev;
- struct v4l2_subdev *sd = fimc->pipeline.sensor;
- struct v4l2_subdev *csis = fimc->pipeline.csis;
+ struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
+ struct v4l2_subdev *csis = fimc->pipeline.subdevs[IDX_CSIS];
struct v4l2_subdev_format sfmt;
struct v4l2_mbus_framefmt *mf = &sfmt.format;
struct fimc_fmt *ffmt = NULL;
@@ -851,7 +931,7 @@ static int fimc_capture_set_format(struct fimc_dev *fimc, struct v4l2_format *f)
set_frame_bounds(ff, pix->width, pix->height);
/* Reset the composition rectangle if not yet configured */
- if (!(ctx->state & FIMC_DST_CROP))
+ if (!(ctx->state & FIMC_COMPOSE))
set_frame_crop(ff, 0, 0, pix->width, pix->height);
fimc_capture_mark_jpeg_xfer(ctx, fimc_fmt_is_jpeg(ff->fmt->color));
@@ -878,7 +958,7 @@ static int fimc_cap_enum_input(struct file *file, void *priv,
struct v4l2_input *i)
{
struct fimc_dev *fimc = video_drvdata(file);
- struct v4l2_subdev *sd = fimc->pipeline.sensor;
+ struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
if (i->index != 0)
return -EINVAL;
@@ -927,7 +1007,7 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc)
if (!(pad->flags & MEDIA_PAD_FL_SINK))
break;
/* Don't call FIMC subdev operation to avoid nested locking */
- if (sd == fimc->vid_cap.subdev) {
+ if (sd == &fimc->vid_cap.subdev) {
struct fimc_frame *ff = &vid_cap->ctx->s_frame;
sink_fmt.format.width = ff->f_width;
sink_fmt.format.height = ff->f_height;
@@ -970,7 +1050,8 @@ static int fimc_cap_streamon(struct file *file, void *priv,
if (fimc_capture_active(fimc))
return -EBUSY;
- media_entity_pipeline_start(&p->sensor->entity, p->pipe);
+ media_entity_pipeline_start(&p->subdevs[IDX_SENSOR]->entity,
+ p->m_pipeline);
if (fimc->vid_cap.user_subdev_api) {
ret = fimc_pipeline_validate(fimc);
@@ -984,7 +1065,7 @@ static int fimc_cap_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct fimc_dev *fimc = video_drvdata(file);
- struct v4l2_subdev *sd = fimc->pipeline.sensor;
+ struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
int ret;
ret = vb2_streamoff(&fimc->vid_cap.vbq, type);
@@ -1100,29 +1181,18 @@ static int fimc_cap_s_selection(struct file *file, void *fh,
struct v4l2_rect rect = s->r;
struct fimc_frame *f;
unsigned long flags;
- unsigned int pad;
if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
return -EINVAL;
- switch (s->target) {
- case V4L2_SEL_TGT_COMPOSE_DEFAULT:
- case V4L2_SEL_TGT_COMPOSE_BOUNDS:
- case V4L2_SEL_TGT_COMPOSE_ACTIVE:
+ if (s->target == V4L2_SEL_TGT_COMPOSE_ACTIVE)
f = &ctx->d_frame;
- pad = FIMC_SD_PAD_SOURCE;
- break;
- case V4L2_SEL_TGT_CROP_BOUNDS:
- case V4L2_SEL_TGT_CROP_DEFAULT:
- case V4L2_SEL_TGT_CROP_ACTIVE:
+ else if (s->target == V4L2_SEL_TGT_CROP_ACTIVE)
f = &ctx->s_frame;
- pad = FIMC_SD_PAD_SINK;
- break;
- default:
+ else
return -EINVAL;
- }
- fimc_capture_try_crop(ctx, &rect, pad);
+ fimc_capture_try_selection(ctx, &rect, s->target);
if (s->flags & V4L2_SEL_FLAG_LE &&
!enclosed_rectangle(&rect, &s->r))
@@ -1243,7 +1313,7 @@ void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification,
struct fimc_vid_buffer, list);
vb2_set_plane_payload(&buf->vb, 0, *((u32 *)arg));
}
- fimc_capture_irq_handler(fimc, true);
+ fimc_capture_irq_handler(fimc, 1);
fimc_deactivate_capture(fimc);
spin_unlock_irqrestore(&fimc->slock, irq_flags);
}
@@ -1334,77 +1404,122 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd,
ff->fmt = ffmt;
/* Reset the crop rectangle if required. */
- if (!(fmt->pad == FIMC_SD_PAD_SOURCE && (ctx->state & FIMC_DST_CROP)))
+ if (!(fmt->pad == FIMC_SD_PAD_SOURCE && (ctx->state & FIMC_COMPOSE)))
set_frame_crop(ff, 0, 0, mf->width, mf->height);
if (fmt->pad == FIMC_SD_PAD_SINK)
- ctx->state &= ~FIMC_DST_CROP;
+ ctx->state &= ~FIMC_COMPOSE;
mutex_unlock(&fimc->lock);
return 0;
}
-static int fimc_subdev_get_crop(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_crop *crop)
+static int fimc_subdev_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
{
struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
struct fimc_ctx *ctx = fimc->vid_cap.ctx;
- struct v4l2_rect *r = &crop->rect;
- struct fimc_frame *ff;
+ struct fimc_frame *f = &ctx->s_frame;
+ struct v4l2_rect *r = &sel->r;
+ struct v4l2_rect *try_sel;
- if (crop->which == V4L2_SUBDEV_FORMAT_TRY) {
- crop->rect = *v4l2_subdev_get_try_crop(fh, crop->pad);
+ if (sel->pad != FIMC_SD_PAD_SINK)
+ return -EINVAL;
+
+ mutex_lock(&fimc->lock);
+
+ switch (sel->target) {
+ case V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS:
+ f = &ctx->d_frame;
+ case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
+ r->width = f->o_width;
+ r->height = f->o_height;
+ r->left = 0;
+ r->top = 0;
+ mutex_unlock(&fimc->lock);
return 0;
+
+ case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+ try_sel = v4l2_subdev_get_try_crop(fh, sel->pad);
+ break;
+ case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL:
+ try_sel = v4l2_subdev_get_try_compose(fh, sel->pad);
+ f = &ctx->d_frame;
+ break;
+ default:
+ mutex_unlock(&fimc->lock);
+ return -EINVAL;
}
- ff = crop->pad == FIMC_SD_PAD_SINK ?
- &ctx->s_frame : &ctx->d_frame;
- mutex_lock(&fimc->lock);
- r->left = ff->offs_h;
- r->top = ff->offs_v;
- r->width = ff->width;
- r->height = ff->height;
- mutex_unlock(&fimc->lock);
+ if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
+ sel->r = *try_sel;
+ } else {
+ r->left = f->offs_h;
+ r->top = f->offs_v;
+ r->width = f->width;
+ r->height = f->height;
+ }
- dbg("ff:%p, pad%d: l:%d, t:%d, %dx%d, f_w: %d, f_h: %d",
- ff, crop->pad, r->left, r->top, r->width, r->height,
- ff->f_width, ff->f_height);
+ dbg("target %#x: l:%d, t:%d, %dx%d, f_w: %d, f_h: %d",
+ sel->pad, r->left, r->top, r->width, r->height,
+ f->f_width, f->f_height);
+ mutex_unlock(&fimc->lock);
return 0;
}
-static int fimc_subdev_set_crop(struct v4l2_subdev *sd,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_crop *crop)
+static int fimc_subdev_set_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
{
struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
struct fimc_ctx *ctx = fimc->vid_cap.ctx;
- struct v4l2_rect *r = &crop->rect;
- struct fimc_frame *ff;
+ struct fimc_frame *f = &ctx->s_frame;
+ struct v4l2_rect *r = &sel->r;
+ struct v4l2_rect *try_sel;
unsigned long flags;
- dbg("(%d,%d)/%dx%d", r->left, r->top, r->width, r->height);
-
- ff = crop->pad == FIMC_SD_PAD_SOURCE ?
- &ctx->d_frame : &ctx->s_frame;
+ if (sel->pad != FIMC_SD_PAD_SINK)
+ return -EINVAL;
mutex_lock(&fimc->lock);
- fimc_capture_try_crop(ctx, r, crop->pad);
+ fimc_capture_try_selection(ctx, r, V4L2_SEL_TGT_CROP_ACTIVE);
- if (crop->which == V4L2_SUBDEV_FORMAT_TRY) {
+ switch (sel->target) {
+ case V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS:
+ f = &ctx->d_frame;
+ case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
+ r->width = f->o_width;
+ r->height = f->o_height;
+ r->left = 0;
+ r->top = 0;
mutex_unlock(&fimc->lock);
- *v4l2_subdev_get_try_crop(fh, crop->pad) = *r;
return 0;
+
+ case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+ try_sel = v4l2_subdev_get_try_crop(fh, sel->pad);
+ break;
+ case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL:
+ try_sel = v4l2_subdev_get_try_compose(fh, sel->pad);
+ f = &ctx->d_frame;
+ break;
+ default:
+ mutex_unlock(&fimc->lock);
+ return -EINVAL;
}
- spin_lock_irqsave(&fimc->slock, flags);
- set_frame_crop(ff, r->left, r->top, r->width, r->height);
- if (crop->pad == FIMC_SD_PAD_SOURCE)
- ctx->state |= FIMC_DST_CROP;
- set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
- spin_unlock_irqrestore(&fimc->slock, flags);
+ if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
+ *try_sel = sel->r;
+ } else {
+ spin_lock_irqsave(&fimc->slock, flags);
+ set_frame_crop(f, r->left, r->top, r->width, r->height);
+ set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
+ spin_unlock_irqrestore(&fimc->slock, flags);
+ if (sel->target == V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL)
+ ctx->state |= FIMC_COMPOSE;
+ }
- dbg("pad%d: (%d,%d)/%dx%d", crop->pad, r->left, r->top,
+ dbg("target %#x: (%d,%d)/%dx%d", sel->target, r->left, r->top,
r->width, r->height);
mutex_unlock(&fimc->lock);
@@ -1413,63 +1528,16 @@ static int fimc_subdev_set_crop(struct v4l2_subdev *sd,
static struct v4l2_subdev_pad_ops fimc_subdev_pad_ops = {
.enum_mbus_code = fimc_subdev_enum_mbus_code,
+ .get_selection = fimc_subdev_get_selection,
+ .set_selection = fimc_subdev_set_selection,
.get_fmt = fimc_subdev_get_fmt,
.set_fmt = fimc_subdev_set_fmt,
- .get_crop = fimc_subdev_get_crop,
- .set_crop = fimc_subdev_set_crop,
};
static struct v4l2_subdev_ops fimc_subdev_ops = {
.pad = &fimc_subdev_pad_ops,
};
-static int fimc_create_capture_subdev(struct fimc_dev *fimc,
- struct v4l2_device *v4l2_dev)
-{
- struct v4l2_subdev *sd;
- int ret;
-
- sd = kzalloc(sizeof(*sd), GFP_KERNEL);
- if (!sd)
- return -ENOMEM;
-
- v4l2_subdev_init(sd, &fimc_subdev_ops);
- sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
- snprintf(sd->name, sizeof(sd->name), "FIMC.%d", fimc->pdev->id);
-
- fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
- fimc->vid_cap.sd_pads[FIMC_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_init(&sd->entity, FIMC_SD_PADS_NUM,
- fimc->vid_cap.sd_pads, 0);
- if (ret)
- goto me_err;
- ret = v4l2_device_register_subdev(v4l2_dev, sd);
- if (ret)
- goto sd_err;
-
- fimc->vid_cap.subdev = sd;
- v4l2_set_subdevdata(sd, fimc);
- sd->entity.ops = &fimc_sd_media_ops;
- return 0;
-sd_err:
- media_entity_cleanup(&sd->entity);
-me_err:
- kfree(sd);
- return ret;
-}
-
-static void fimc_destroy_capture_subdev(struct fimc_dev *fimc)
-{
- struct v4l2_subdev *sd = fimc->vid_cap.subdev;
-
- if (!sd)
- return;
- media_entity_cleanup(&sd->entity);
- v4l2_device_unregister_subdev(sd);
- kfree(sd);
- fimc->vid_cap.subdev = NULL;
-}
-
/* Set default format at the sensor and host interface */
static int fimc_capture_set_default_format(struct fimc_dev *fimc)
{
@@ -1488,7 +1556,7 @@ static int fimc_capture_set_default_format(struct fimc_dev *fimc)
}
/* fimc->lock must be already initialized */
-int fimc_register_capture_device(struct fimc_dev *fimc,
+static int fimc_register_capture_device(struct fimc_dev *fimc,
struct v4l2_device *v4l2_dev)
{
struct video_device *vfd;
@@ -1502,11 +1570,11 @@ int fimc_register_capture_device(struct fimc_dev *fimc,
return -ENOMEM;
ctx->fimc_dev = fimc;
- ctx->in_path = FIMC_CAMERA;
- ctx->out_path = FIMC_DMA;
+ ctx->in_path = FIMC_IO_CAMERA;
+ ctx->out_path = FIMC_IO_DMA;
ctx->state = FIMC_CTX_CAP;
ctx->s_frame.fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, 0);
- ctx->d_frame.fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, 0);
+ ctx->d_frame.fmt = ctx->s_frame.fmt;
vfd = video_device_alloc();
if (!vfd) {
@@ -1514,8 +1582,7 @@ int fimc_register_capture_device(struct fimc_dev *fimc,
goto err_vd_alloc;
}
- snprintf(vfd->name, sizeof(vfd->name), "%s.capture",
- dev_name(&fimc->pdev->dev));
+ snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.capture", fimc->id);
vfd->fops = &fimc_capture_fops;
vfd->ioctl_ops = &fimc_capture_ioctl_ops;
@@ -1523,6 +1590,10 @@ int fimc_register_capture_device(struct fimc_dev *fimc,
vfd->minor = -1;
vfd->release = video_device_release;
vfd->lock = &fimc->lock;
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
video_set_drvdata(vfd, fimc);
vid_cap = &fimc->vid_cap;
@@ -1533,7 +1604,6 @@ int fimc_register_capture_device(struct fimc_dev *fimc,
INIT_LIST_HEAD(&vid_cap->pending_buf_q);
INIT_LIST_HEAD(&vid_cap->active_buf_q);
- spin_lock_init(&ctx->slock);
vid_cap->ctx = ctx;
q = &fimc->vid_cap.vbq;
@@ -1547,18 +1617,22 @@ int fimc_register_capture_device(struct fimc_dev *fimc,
vb2_queue_init(q);
- fimc->vid_cap.vd_pad.flags = MEDIA_PAD_FL_SINK;
- ret = media_entity_init(&vfd->entity, 1, &fimc->vid_cap.vd_pad, 0);
+ vid_cap->vd_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_init(&vfd->entity, 1, &vid_cap->vd_pad, 0);
if (ret)
goto err_ent;
- ret = fimc_create_capture_subdev(fimc, v4l2_dev);
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
if (ret)
- goto err_sd_reg;
+ goto err_vd;
- vfd->ctrl_handler = &ctx->ctrl_handler;
+ v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n",
+ vfd->name, video_device_node_name(vfd));
+
+ vfd->ctrl_handler = &ctx->ctrls.handler;
return 0;
-err_sd_reg:
+err_vd:
media_entity_cleanup(&vfd->entity);
err_ent:
video_device_release(vfd);
@@ -1567,17 +1641,73 @@ err_vd_alloc:
return ret;
}
-void fimc_unregister_capture_device(struct fimc_dev *fimc)
+static int fimc_capture_subdev_registered(struct v4l2_subdev *sd)
{
- struct video_device *vfd = fimc->vid_cap.vfd;
+ struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
+ int ret;
+
+ ret = fimc_register_m2m_device(fimc, sd->v4l2_dev);
+ if (ret)
+ return ret;
- if (vfd) {
- media_entity_cleanup(&vfd->entity);
- /* Can also be called if video device was
- not registered */
- video_unregister_device(vfd);
+ ret = fimc_register_capture_device(fimc, sd->v4l2_dev);
+ if (ret)
+ fimc_unregister_m2m_device(fimc);
+
+ return ret;
+}
+
+static void fimc_capture_subdev_unregistered(struct v4l2_subdev *sd)
+{
+ struct fimc_dev *fimc = v4l2_get_subdevdata(sd);
+
+ if (fimc == NULL)
+ return;
+
+ fimc_unregister_m2m_device(fimc);
+
+ if (fimc->vid_cap.vfd) {
+ media_entity_cleanup(&fimc->vid_cap.vfd->entity);
+ video_unregister_device(fimc->vid_cap.vfd);
+ fimc->vid_cap.vfd = NULL;
}
- fimc_destroy_capture_subdev(fimc);
+
kfree(fimc->vid_cap.ctx);
fimc->vid_cap.ctx = NULL;
}
+
+static const struct v4l2_subdev_internal_ops fimc_capture_sd_internal_ops = {
+ .registered = fimc_capture_subdev_registered,
+ .unregistered = fimc_capture_subdev_unregistered,
+};
+
+int fimc_initialize_capture_subdev(struct fimc_dev *fimc)
+{
+ struct v4l2_subdev *sd = &fimc->vid_cap.subdev;
+ int ret;
+
+ v4l2_subdev_init(sd, &fimc_subdev_ops);
+ sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(sd->name, sizeof(sd->name), "FIMC.%d", fimc->pdev->id);
+
+ fimc->vid_cap.sd_pads[FIMC_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ fimc->vid_cap.sd_pads[FIMC_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&sd->entity, FIMC_SD_PADS_NUM,
+ fimc->vid_cap.sd_pads, 0);
+ if (ret)
+ return ret;
+
+ sd->entity.ops = &fimc_sd_media_ops;
+ sd->internal_ops = &fimc_capture_sd_internal_ops;
+ v4l2_set_subdevdata(sd, fimc);
+ return 0;
+}
+
+void fimc_unregister_capture_subdev(struct fimc_dev *fimc)
+{
+ struct v4l2_subdev *sd = &fimc->vid_cap.subdev;
+
+ v4l2_device_unregister_subdev(sd);
+ media_entity_cleanup(&sd->entity);
+ v4l2_set_subdevdata(sd, NULL);
+}
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
index e09ba7b0076e..fedcd561ba27 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.c
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -1,8 +1,8 @@
/*
- * Samsung S5P/EXYNOS4 SoC series camera interface (video postprocessor) driver
+ * Samsung S5P/EXYNOS4 SoC series FIMC (CAMIF) driver
*
- * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd.
- * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ * Copyright (C) 2010-2012 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
@@ -28,6 +28,7 @@
#include <media/videobuf2-dma-contig.h>
#include "fimc-core.h"
+#include "fimc-reg.h"
#include "fimc-mdevice.h"
static char *fimc_clocks[MAX_FIMC_CLOCKS] = {
@@ -39,7 +40,7 @@ static struct fimc_fmt fimc_formats[] = {
.name = "RGB565",
.fourcc = V4L2_PIX_FMT_RGB565,
.depth = { 16 },
- .color = S5P_FIMC_RGB565,
+ .color = FIMC_FMT_RGB565,
.memplanes = 1,
.colplanes = 1,
.flags = FMT_FLAGS_M2M,
@@ -47,7 +48,7 @@ static struct fimc_fmt fimc_formats[] = {
.name = "BGR666",
.fourcc = V4L2_PIX_FMT_BGR666,
.depth = { 32 },
- .color = S5P_FIMC_RGB666,
+ .color = FIMC_FMT_RGB666,
.memplanes = 1,
.colplanes = 1,
.flags = FMT_FLAGS_M2M,
@@ -55,7 +56,7 @@ static struct fimc_fmt fimc_formats[] = {
.name = "ARGB8888, 32 bpp",
.fourcc = V4L2_PIX_FMT_RGB32,
.depth = { 32 },
- .color = S5P_FIMC_RGB888,
+ .color = FIMC_FMT_RGB888,
.memplanes = 1,
.colplanes = 1,
.flags = FMT_FLAGS_M2M | FMT_HAS_ALPHA,
@@ -63,7 +64,7 @@ static struct fimc_fmt fimc_formats[] = {
.name = "ARGB1555",
.fourcc = V4L2_PIX_FMT_RGB555,
.depth = { 16 },
- .color = S5P_FIMC_RGB555,
+ .color = FIMC_FMT_RGB555,
.memplanes = 1,
.colplanes = 1,
.flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
@@ -71,7 +72,7 @@ static struct fimc_fmt fimc_formats[] = {
.name = "ARGB4444",
.fourcc = V4L2_PIX_FMT_RGB444,
.depth = { 16 },
- .color = S5P_FIMC_RGB444,
+ .color = FIMC_FMT_RGB444,
.memplanes = 1,
.colplanes = 1,
.flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
@@ -79,7 +80,7 @@ static struct fimc_fmt fimc_formats[] = {
.name = "YUV 4:2:2 packed, YCbYCr",
.fourcc = V4L2_PIX_FMT_YUYV,
.depth = { 16 },
- .color = S5P_FIMC_YCBYCR422,
+ .color = FIMC_FMT_YCBYCR422,
.memplanes = 1,
.colplanes = 1,
.mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
@@ -88,7 +89,7 @@ static struct fimc_fmt fimc_formats[] = {
.name = "YUV 4:2:2 packed, CbYCrY",
.fourcc = V4L2_PIX_FMT_UYVY,
.depth = { 16 },
- .color = S5P_FIMC_CBYCRY422,
+ .color = FIMC_FMT_CBYCRY422,
.memplanes = 1,
.colplanes = 1,
.mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
@@ -97,7 +98,7 @@ static struct fimc_fmt fimc_formats[] = {
.name = "YUV 4:2:2 packed, CrYCbY",
.fourcc = V4L2_PIX_FMT_VYUY,
.depth = { 16 },
- .color = S5P_FIMC_CRYCBY422,
+ .color = FIMC_FMT_CRYCBY422,
.memplanes = 1,
.colplanes = 1,
.mbus_code = V4L2_MBUS_FMT_VYUY8_2X8,
@@ -106,7 +107,7 @@ static struct fimc_fmt fimc_formats[] = {
.name = "YUV 4:2:2 packed, YCrYCb",
.fourcc = V4L2_PIX_FMT_YVYU,
.depth = { 16 },
- .color = S5P_FIMC_YCRYCB422,
+ .color = FIMC_FMT_YCRYCB422,
.memplanes = 1,
.colplanes = 1,
.mbus_code = V4L2_MBUS_FMT_YVYU8_2X8,
@@ -115,7 +116,7 @@ static struct fimc_fmt fimc_formats[] = {
.name = "YUV 4:2:2 planar, Y/Cb/Cr",
.fourcc = V4L2_PIX_FMT_YUV422P,
.depth = { 12 },
- .color = S5P_FIMC_YCBYCR422,
+ .color = FIMC_FMT_YCBYCR422,
.memplanes = 1,
.colplanes = 3,
.flags = FMT_FLAGS_M2M,
@@ -123,7 +124,7 @@ static struct fimc_fmt fimc_formats[] = {
.name = "YUV 4:2:2 planar, Y/CbCr",
.fourcc = V4L2_PIX_FMT_NV16,
.depth = { 16 },
- .color = S5P_FIMC_YCBYCR422,
+ .color = FIMC_FMT_YCBYCR422,
.memplanes = 1,
.colplanes = 2,
.flags = FMT_FLAGS_M2M,
@@ -131,7 +132,7 @@ static struct fimc_fmt fimc_formats[] = {
.name = "YUV 4:2:2 planar, Y/CrCb",
.fourcc = V4L2_PIX_FMT_NV61,
.depth = { 16 },
- .color = S5P_FIMC_YCRYCB422,
+ .color = FIMC_FMT_YCRYCB422,
.memplanes = 1,
.colplanes = 2,
.flags = FMT_FLAGS_M2M,
@@ -139,7 +140,7 @@ static struct fimc_fmt fimc_formats[] = {
.name = "YUV 4:2:0 planar, YCbCr",
.fourcc = V4L2_PIX_FMT_YUV420,
.depth = { 12 },
- .color = S5P_FIMC_YCBCR420,
+ .color = FIMC_FMT_YCBCR420,
.memplanes = 1,
.colplanes = 3,
.flags = FMT_FLAGS_M2M,
@@ -147,14 +148,14 @@ static struct fimc_fmt fimc_formats[] = {
.name = "YUV 4:2:0 planar, Y/CbCr",
.fourcc = V4L2_PIX_FMT_NV12,
.depth = { 12 },
- .color = S5P_FIMC_YCBCR420,
+ .color = FIMC_FMT_YCBCR420,
.memplanes = 1,
.colplanes = 2,
.flags = FMT_FLAGS_M2M,
}, {
.name = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr",
.fourcc = V4L2_PIX_FMT_NV12M,
- .color = S5P_FIMC_YCBCR420,
+ .color = FIMC_FMT_YCBCR420,
.depth = { 8, 4 },
.memplanes = 2,
.colplanes = 2,
@@ -162,7 +163,7 @@ static struct fimc_fmt fimc_formats[] = {
}, {
.name = "YUV 4:2:0 non-contiguous 3-planar, Y/Cb/Cr",
.fourcc = V4L2_PIX_FMT_YUV420M,
- .color = S5P_FIMC_YCBCR420,
+ .color = FIMC_FMT_YCBCR420,
.depth = { 8, 2, 2 },
.memplanes = 3,
.colplanes = 3,
@@ -170,7 +171,7 @@ static struct fimc_fmt fimc_formats[] = {
}, {
.name = "YUV 4:2:0 non-contiguous 2-planar, Y/CbCr, tiled",
.fourcc = V4L2_PIX_FMT_NV12MT,
- .color = S5P_FIMC_YCBCR420,
+ .color = FIMC_FMT_YCBCR420,
.depth = { 8, 4 },
.memplanes = 2,
.colplanes = 2,
@@ -178,7 +179,7 @@ static struct fimc_fmt fimc_formats[] = {
}, {
.name = "JPEG encoded data",
.fourcc = V4L2_PIX_FMT_JPEG,
- .color = S5P_FIMC_JPEG,
+ .color = FIMC_FMT_JPEG,
.depth = { 8 },
.memplanes = 1,
.colplanes = 1,
@@ -187,12 +188,12 @@ static struct fimc_fmt fimc_formats[] = {
},
};
-static unsigned int get_m2m_fmt_flags(unsigned int stream_type)
+struct fimc_fmt *fimc_get_format(unsigned int index)
{
- if (stream_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- return FMT_FLAGS_M2M_IN;
- else
- return FMT_FLAGS_M2M_OUT;
+ if (index >= ARRAY_SIZE(fimc_formats))
+ return NULL;
+
+ return &fimc_formats[index];
}
int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh,
@@ -230,7 +231,7 @@ static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift)
int fimc_set_scaler_info(struct fimc_ctx *ctx)
{
- struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
+ struct fimc_variant *variant = ctx->fimc_dev->variant;
struct device *dev = &ctx->fimc_dev->pdev->dev;
struct fimc_scaler *sc = &ctx->scaler;
struct fimc_frame *s_frame = &ctx->s_frame;
@@ -293,126 +294,9 @@ int fimc_set_scaler_info(struct fimc_ctx *ctx)
return 0;
}
-static void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state)
-{
- struct vb2_buffer *src_vb, *dst_vb;
-
- if (!ctx || !ctx->m2m_ctx)
- return;
-
- src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
- dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
-
- if (src_vb && dst_vb) {
- v4l2_m2m_buf_done(src_vb, vb_state);
- v4l2_m2m_buf_done(dst_vb, vb_state);
- v4l2_m2m_job_finish(ctx->fimc_dev->m2m.m2m_dev,
- ctx->m2m_ctx);
- }
-}
-
-/* Complete the transaction which has been scheduled for execution. */
-static int fimc_m2m_shutdown(struct fimc_ctx *ctx)
-{
- struct fimc_dev *fimc = ctx->fimc_dev;
- int ret;
-
- if (!fimc_m2m_pending(fimc))
- return 0;
-
- fimc_ctx_state_lock_set(FIMC_CTX_SHUT, ctx);
-
- ret = wait_event_timeout(fimc->irq_queue,
- !fimc_ctx_state_is_set(FIMC_CTX_SHUT, ctx),
- FIMC_SHUTDOWN_TIMEOUT);
-
- return ret == 0 ? -ETIMEDOUT : ret;
-}
-
-static int start_streaming(struct vb2_queue *q, unsigned int count)
-{
- struct fimc_ctx *ctx = q->drv_priv;
- int ret;
-
- ret = pm_runtime_get_sync(&ctx->fimc_dev->pdev->dev);
- return ret > 0 ? 0 : ret;
-}
-
-static int stop_streaming(struct vb2_queue *q)
-{
- struct fimc_ctx *ctx = q->drv_priv;
- int ret;
-
- ret = fimc_m2m_shutdown(ctx);
- if (ret == -ETIMEDOUT)
- fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
-
- pm_runtime_put(&ctx->fimc_dev->pdev->dev);
- return 0;
-}
-
-void fimc_capture_irq_handler(struct fimc_dev *fimc, bool final)
-{
- struct fimc_vid_cap *cap = &fimc->vid_cap;
- struct fimc_vid_buffer *v_buf;
- struct timeval *tv;
- struct timespec ts;
-
- if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) {
- wake_up(&fimc->irq_queue);
- return;
- }
-
- if (!list_empty(&cap->active_buf_q) &&
- test_bit(ST_CAPT_RUN, &fimc->state) && final) {
- ktime_get_real_ts(&ts);
-
- v_buf = fimc_active_queue_pop(cap);
-
- tv = &v_buf->vb.v4l2_buf.timestamp;
- tv->tv_sec = ts.tv_sec;
- tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
- v_buf->vb.v4l2_buf.sequence = cap->frame_count++;
-
- vb2_buffer_done(&v_buf->vb, VB2_BUF_STATE_DONE);
- }
-
- if (!list_empty(&cap->pending_buf_q)) {
-
- v_buf = fimc_pending_queue_pop(cap);
- fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index);
- v_buf->index = cap->buf_index;
-
- /* Move the buffer to the capture active queue */
- fimc_active_queue_add(cap, v_buf);
-
- dbg("next frame: %d, done frame: %d",
- fimc_hw_get_frame_index(fimc), v_buf->index);
-
- if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
- cap->buf_index = 0;
- }
-
- if (cap->active_buf_cnt == 0) {
- if (final)
- clear_bit(ST_CAPT_RUN, &fimc->state);
-
- if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
- cap->buf_index = 0;
- } else {
- set_bit(ST_CAPT_RUN, &fimc->state);
- }
-
- fimc_capture_config_update(cap->ctx);
-
- dbg("frame: %d, active_buf_cnt: %d",
- fimc_hw_get_frame_index(fimc), cap->active_buf_cnt);
-}
-
static irqreturn_t fimc_irq_handler(int irq, void *priv)
{
struct fimc_dev *fimc = priv;
- struct fimc_vid_cap *cap = &fimc->vid_cap;
struct fimc_ctx *ctx;
fimc_hw_clear_irq(fimc);
@@ -430,21 +314,16 @@ static irqreturn_t fimc_irq_handler(int irq, void *priv)
spin_unlock(&fimc->slock);
fimc_m2m_job_finish(ctx, VB2_BUF_STATE_DONE);
- spin_lock(&ctx->slock);
if (ctx->state & FIMC_CTX_SHUT) {
ctx->state &= ~FIMC_CTX_SHUT;
wake_up(&fimc->irq_queue);
}
- spin_unlock(&ctx->slock);
+ return IRQ_HANDLED;
}
- return IRQ_HANDLED;
} else if (test_bit(ST_CAPT_PEND, &fimc->state)) {
- fimc_capture_irq_handler(fimc,
- !test_bit(ST_CAPT_JPEG, &fimc->state));
- if (cap->active_buf_cnt == 1) {
- fimc_deactivate_capture(fimc);
- clear_bit(ST_CAPT_STREAM, &fimc->state);
- }
+ int last_buf = test_bit(ST_CAPT_JPEG, &fimc->state) &&
+ fimc->vid_cap.reqbufs_count == 1;
+ fimc_capture_irq_handler(fimc, !last_buf);
}
out:
spin_unlock(&fimc->slock);
@@ -482,7 +361,7 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb,
case 3:
paddr->cb = (u32)(paddr->y + pix_size);
/* decompose Y into Y/Cb/Cr */
- if (S5P_FIMC_YCBCR420 == frame->fmt->color)
+ if (FIMC_FMT_YCBCR420 == frame->fmt->color)
paddr->cr = (u32)(paddr->cb
+ (pix_size >> 2));
else /* 422 */
@@ -510,40 +389,40 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb,
void fimc_set_yuv_order(struct fimc_ctx *ctx)
{
/* The one only mode supported in SoC. */
- ctx->in_order_2p = S5P_FIMC_LSB_CRCB;
- ctx->out_order_2p = S5P_FIMC_LSB_CRCB;
+ ctx->in_order_2p = FIMC_REG_CIOCTRL_ORDER422_2P_LSB_CRCB;
+ ctx->out_order_2p = FIMC_REG_CIOCTRL_ORDER422_2P_LSB_CRCB;
/* Set order for 1 plane input formats. */
switch (ctx->s_frame.fmt->color) {
- case S5P_FIMC_YCRYCB422:
- ctx->in_order_1p = S5P_MSCTRL_ORDER422_CBYCRY;
+ case FIMC_FMT_YCRYCB422:
+ ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CBYCRY;
break;
- case S5P_FIMC_CBYCRY422:
- ctx->in_order_1p = S5P_MSCTRL_ORDER422_YCRYCB;
+ case FIMC_FMT_CBYCRY422:
+ ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCRYCB;
break;
- case S5P_FIMC_CRYCBY422:
- ctx->in_order_1p = S5P_MSCTRL_ORDER422_YCBYCR;
+ case FIMC_FMT_CRYCBY422:
+ ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_YCBYCR;
break;
- case S5P_FIMC_YCBYCR422:
+ case FIMC_FMT_YCBYCR422:
default:
- ctx->in_order_1p = S5P_MSCTRL_ORDER422_CRYCBY;
+ ctx->in_order_1p = FIMC_REG_MSCTRL_ORDER422_CRYCBY;
break;
}
dbg("ctx->in_order_1p= %d", ctx->in_order_1p);
switch (ctx->d_frame.fmt->color) {
- case S5P_FIMC_YCRYCB422:
- ctx->out_order_1p = S5P_CIOCTRL_ORDER422_CBYCRY;
+ case FIMC_FMT_YCRYCB422:
+ ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CBYCRY;
break;
- case S5P_FIMC_CBYCRY422:
- ctx->out_order_1p = S5P_CIOCTRL_ORDER422_YCRYCB;
+ case FIMC_FMT_CBYCRY422:
+ ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCRYCB;
break;
- case S5P_FIMC_CRYCBY422:
- ctx->out_order_1p = S5P_CIOCTRL_ORDER422_YCBYCR;
+ case FIMC_FMT_CRYCBY422:
+ ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_YCBYCR;
break;
- case S5P_FIMC_YCBYCR422:
+ case FIMC_FMT_YCBYCR422:
default:
- ctx->out_order_1p = S5P_CIOCTRL_ORDER422_CRYCBY;
+ ctx->out_order_1p = FIMC_REG_CIOCTRL_ORDER422_CRYCBY;
break;
}
dbg("ctx->out_order_1p= %d", ctx->out_order_1p);
@@ -551,7 +430,7 @@ void fimc_set_yuv_order(struct fimc_ctx *ctx)
void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
{
- struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
+ struct fimc_variant *variant = ctx->fimc_dev->variant;
u32 i, depth = 0;
for (i = 0; i < f->fmt->colplanes; i++)
@@ -574,7 +453,7 @@ void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
f->dma_offset.cb_h >>= 1;
f->dma_offset.cr_h >>= 1;
}
- if (f->fmt->color == S5P_FIMC_YCBCR420) {
+ if (f->fmt->color == FIMC_FMT_YCBCR420) {
f->dma_offset.cb_v >>= 1;
f->dma_offset.cr_v >>= 1;
}
@@ -584,203 +463,58 @@ void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
f->fmt->color, f->dma_offset.y_h, f->dma_offset.y_v);
}
-/**
- * fimc_prepare_config - check dimensions, operation and color mode
- * and pre-calculate offset and the scaling coefficients.
- *
- * @ctx: hardware context information
- * @flags: flags indicating which parameters to check/update
- *
- * Return: 0 if dimensions are valid or non zero otherwise.
- */
-int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags)
-{
- struct fimc_frame *s_frame, *d_frame;
- struct vb2_buffer *vb = NULL;
- int ret = 0;
-
- s_frame = &ctx->s_frame;
- d_frame = &ctx->d_frame;
-
- if (flags & FIMC_PARAMS) {
- /* Prepare the DMA offset ratios for scaler. */
- fimc_prepare_dma_offset(ctx, &ctx->s_frame);
- fimc_prepare_dma_offset(ctx, &ctx->d_frame);
-
- if (s_frame->height > (SCALER_MAX_VRATIO * d_frame->height) ||
- s_frame->width > (SCALER_MAX_HRATIO * d_frame->width)) {
- err("out of scaler range");
- return -EINVAL;
- }
- fimc_set_yuv_order(ctx);
- }
-
- if (flags & FIMC_SRC_ADDR) {
- vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
- ret = fimc_prepare_addr(ctx, vb, s_frame, &s_frame->paddr);
- if (ret)
- return ret;
- }
-
- if (flags & FIMC_DST_ADDR) {
- vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
- ret = fimc_prepare_addr(ctx, vb, d_frame, &d_frame->paddr);
- }
-
- return ret;
-}
-
-static void fimc_dma_run(void *priv)
-{
- struct fimc_ctx *ctx = priv;
- struct fimc_dev *fimc;
- unsigned long flags;
- u32 ret;
-
- if (WARN(!ctx, "null hardware context\n"))
- return;
-
- fimc = ctx->fimc_dev;
- spin_lock_irqsave(&fimc->slock, flags);
- set_bit(ST_M2M_PEND, &fimc->state);
-
- spin_lock(&ctx->slock);
- ctx->state |= (FIMC_SRC_ADDR | FIMC_DST_ADDR);
- ret = fimc_prepare_config(ctx, ctx->state);
- if (ret)
- goto dma_unlock;
-
- /* Reconfigure hardware if the context has changed. */
- if (fimc->m2m.ctx != ctx) {
- ctx->state |= FIMC_PARAMS;
- fimc->m2m.ctx = ctx;
- }
- fimc_hw_set_input_addr(fimc, &ctx->s_frame.paddr);
-
- if (ctx->state & FIMC_PARAMS) {
- fimc_hw_set_input_path(ctx);
- fimc_hw_set_in_dma(ctx);
- ret = fimc_set_scaler_info(ctx);
- if (ret) {
- spin_unlock(&fimc->slock);
- goto dma_unlock;
- }
- fimc_hw_set_prescaler(ctx);
- fimc_hw_set_mainscaler(ctx);
- fimc_hw_set_target_format(ctx);
- fimc_hw_set_rotation(ctx);
- fimc_hw_set_effect(ctx, false);
- }
-
- fimc_hw_set_output_path(ctx);
- if (ctx->state & (FIMC_DST_ADDR | FIMC_PARAMS))
- fimc_hw_set_output_addr(fimc, &ctx->d_frame.paddr, -1);
-
- if (ctx->state & FIMC_PARAMS) {
- fimc_hw_set_out_dma(ctx);
- if (fimc->variant->has_alpha)
- fimc_hw_set_rgb_alpha(ctx);
- }
-
- fimc_activate_capture(ctx);
-
- ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP |
- FIMC_SRC_FMT | FIMC_DST_FMT);
- fimc_hw_activate_input_dma(fimc, true);
-dma_unlock:
- spin_unlock(&ctx->slock);
- spin_unlock_irqrestore(&fimc->slock, flags);
-}
-
-static void fimc_job_abort(void *priv)
+int fimc_set_color_effect(struct fimc_ctx *ctx, enum v4l2_colorfx colorfx)
{
- fimc_m2m_shutdown(priv);
-}
-
-static int fimc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
- unsigned int *num_buffers, unsigned int *num_planes,
- unsigned int sizes[], void *allocators[])
-{
- struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
- struct fimc_frame *f;
- int i;
+ struct fimc_effect *effect = &ctx->effect;
- f = ctx_get_frame(ctx, vq->type);
- if (IS_ERR(f))
- return PTR_ERR(f);
- /*
- * Return number of non-contigous planes (plane buffers)
- * depending on the configured color format.
- */
- if (!f->fmt)
+ switch (colorfx) {
+ case V4L2_COLORFX_NONE:
+ effect->type = FIMC_REG_CIIMGEFF_FIN_BYPASS;
+ break;
+ case V4L2_COLORFX_BW:
+ effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY;
+ effect->pat_cb = 128;
+ effect->pat_cr = 128;
+ break;
+ case V4L2_COLORFX_SEPIA:
+ effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY;
+ effect->pat_cb = 115;
+ effect->pat_cr = 145;
+ break;
+ case V4L2_COLORFX_NEGATIVE:
+ effect->type = FIMC_REG_CIIMGEFF_FIN_NEGATIVE;
+ break;
+ case V4L2_COLORFX_EMBOSS:
+ effect->type = FIMC_REG_CIIMGEFF_FIN_EMBOSSING;
+ break;
+ case V4L2_COLORFX_ART_FREEZE:
+ effect->type = FIMC_REG_CIIMGEFF_FIN_ARTFREEZE;
+ break;
+ case V4L2_COLORFX_SILHOUETTE:
+ effect->type = FIMC_REG_CIIMGEFF_FIN_SILHOUETTE;
+ break;
+ case V4L2_COLORFX_SET_CBCR:
+ effect->type = FIMC_REG_CIIMGEFF_FIN_ARBITRARY;
+ effect->pat_cb = ctx->ctrls.colorfx_cbcr->val >> 8;
+ effect->pat_cr = ctx->ctrls.colorfx_cbcr->val & 0xff;
+ break;
+ default:
return -EINVAL;
-
- *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;
- allocators[i] = ctx->fimc_dev->alloc_ctx;
}
- return 0;
-}
-
-static int fimc_buf_prepare(struct vb2_buffer *vb)
-{
- struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
- struct fimc_frame *frame;
- int i;
-
- frame = ctx_get_frame(ctx, vb->vb2_queue->type);
- if (IS_ERR(frame))
- return PTR_ERR(frame);
-
- for (i = 0; i < frame->fmt->memplanes; i++)
- vb2_set_plane_payload(vb, i, frame->payload[i]);
return 0;
}
-static void fimc_buf_queue(struct vb2_buffer *vb)
-{
- struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-
- dbg("ctx: %p, ctx->state: 0x%x", ctx, ctx->state);
-
- if (ctx->m2m_ctx)
- v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
-}
-
-static void fimc_lock(struct vb2_queue *vq)
-{
- struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
- mutex_lock(&ctx->fimc_dev->lock);
-}
-
-static void fimc_unlock(struct vb2_queue *vq)
-{
- struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
- mutex_unlock(&ctx->fimc_dev->lock);
-}
-
-static struct vb2_ops fimc_qops = {
- .queue_setup = fimc_queue_setup,
- .buf_prepare = fimc_buf_prepare,
- .buf_queue = fimc_buf_queue,
- .wait_prepare = fimc_unlock,
- .wait_finish = fimc_lock,
- .stop_streaming = stop_streaming,
- .start_streaming = start_streaming,
-};
-
/*
* V4L2 controls handling
*/
#define ctrl_to_ctx(__ctrl) \
- container_of((__ctrl)->handler, struct fimc_ctx, ctrl_handler)
+ container_of((__ctrl)->handler, struct fimc_ctx, ctrls.handler)
static int __fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_ctrl *ctrl)
{
struct fimc_dev *fimc = ctx->fimc_dev;
- struct samsung_fimc_variant *variant = fimc->variant;
+ struct fimc_variant *variant = fimc->variant;
unsigned int flags = FIMC_DST_FMT | FIMC_SRC_FMT;
int ret = 0;
@@ -815,7 +549,14 @@ static int __fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_ctrl *ctrl)
case V4L2_CID_ALPHA_COMPONENT:
ctx->d_frame.alpha = ctrl->val;
break;
+
+ case V4L2_CID_COLORFX:
+ ret = fimc_set_color_effect(ctx, ctrl->val);
+ if (ret)
+ return ret;
+ break;
}
+
ctx->state |= FIMC_PARAMS;
set_bit(ST_CAPT_APPLY_CFG, &fimc->state);
return 0;
@@ -827,9 +568,9 @@ static int fimc_s_ctrl(struct v4l2_ctrl *ctrl)
unsigned long flags;
int ret;
- spin_lock_irqsave(&ctx->slock, flags);
+ spin_lock_irqsave(&ctx->fimc_dev->slock, flags);
ret = __fimc_s_ctrl(ctx, ctrl);
- spin_unlock_irqrestore(&ctx->slock, flags);
+ spin_unlock_irqrestore(&ctx->fimc_dev->slock, flags);
return ret;
}
@@ -840,71 +581,93 @@ static const struct v4l2_ctrl_ops fimc_ctrl_ops = {
int fimc_ctrls_create(struct fimc_ctx *ctx)
{
- struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
+ struct fimc_variant *variant = ctx->fimc_dev->variant;
unsigned int max_alpha = fimc_get_alpha_mask(ctx->d_frame.fmt);
+ struct fimc_ctrls *ctrls = &ctx->ctrls;
+ struct v4l2_ctrl_handler *handler = &ctrls->handler;
- if (ctx->ctrls_rdy)
+ if (ctx->ctrls.ready)
return 0;
- v4l2_ctrl_handler_init(&ctx->ctrl_handler, 4);
- ctx->ctrl_rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops,
+ v4l2_ctrl_handler_init(handler, 6);
+
+ ctrls->rotate = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
V4L2_CID_ROTATE, 0, 270, 90, 0);
- ctx->ctrl_hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops,
+ ctrls->hflip = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
V4L2_CID_HFLIP, 0, 1, 1, 0);
- ctx->ctrl_vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, &fimc_ctrl_ops,
+ ctrls->vflip = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
+
if (variant->has_alpha)
- ctx->ctrl_alpha = v4l2_ctrl_new_std(&ctx->ctrl_handler,
- &fimc_ctrl_ops, V4L2_CID_ALPHA_COMPONENT,
- 0, max_alpha, 1, 0);
+ ctrls->alpha = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
+ V4L2_CID_ALPHA_COMPONENT,
+ 0, max_alpha, 1, 0);
else
- ctx->ctrl_alpha = NULL;
+ ctrls->alpha = NULL;
- ctx->ctrls_rdy = ctx->ctrl_handler.error == 0;
+ ctrls->colorfx = v4l2_ctrl_new_std_menu(handler, &fimc_ctrl_ops,
+ V4L2_CID_COLORFX, V4L2_COLORFX_SET_CBCR,
+ ~0x983f, V4L2_COLORFX_NONE);
- return ctx->ctrl_handler.error;
+ ctrls->colorfx_cbcr = v4l2_ctrl_new_std(handler, &fimc_ctrl_ops,
+ V4L2_CID_COLORFX_CBCR, 0, 0xffff, 1, 0);
+
+ ctx->effect.type = FIMC_REG_CIIMGEFF_FIN_BYPASS;
+
+ if (!handler->error) {
+ v4l2_ctrl_cluster(3, &ctrls->colorfx);
+ ctrls->ready = true;
+ }
+
+ return handler->error;
}
void fimc_ctrls_delete(struct fimc_ctx *ctx)
{
- if (ctx->ctrls_rdy) {
- v4l2_ctrl_handler_free(&ctx->ctrl_handler);
- ctx->ctrls_rdy = false;
- ctx->ctrl_alpha = NULL;
+ struct fimc_ctrls *ctrls = &ctx->ctrls;
+
+ if (ctrls->ready) {
+ v4l2_ctrl_handler_free(&ctrls->handler);
+ ctrls->ready = false;
+ ctrls->alpha = NULL;
}
}
void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active)
{
unsigned int has_alpha = ctx->d_frame.fmt->flags & FMT_HAS_ALPHA;
+ struct fimc_ctrls *ctrls = &ctx->ctrls;
- if (!ctx->ctrls_rdy)
+ if (!ctrls->ready)
return;
- mutex_lock(&ctx->ctrl_handler.lock);
- v4l2_ctrl_activate(ctx->ctrl_rotate, active);
- v4l2_ctrl_activate(ctx->ctrl_hflip, active);
- v4l2_ctrl_activate(ctx->ctrl_vflip, active);
- if (ctx->ctrl_alpha)
- v4l2_ctrl_activate(ctx->ctrl_alpha, active && has_alpha);
+ mutex_lock(&ctrls->handler.lock);
+ v4l2_ctrl_activate(ctrls->rotate, active);
+ v4l2_ctrl_activate(ctrls->hflip, active);
+ v4l2_ctrl_activate(ctrls->vflip, active);
+ v4l2_ctrl_activate(ctrls->colorfx, active);
+ if (ctrls->alpha)
+ v4l2_ctrl_activate(ctrls->alpha, active && has_alpha);
if (active) {
- ctx->rotation = ctx->ctrl_rotate->val;
- ctx->hflip = ctx->ctrl_hflip->val;
- ctx->vflip = ctx->ctrl_vflip->val;
+ fimc_set_color_effect(ctx, ctrls->colorfx->cur.val);
+ ctx->rotation = ctrls->rotate->val;
+ ctx->hflip = ctrls->hflip->val;
+ ctx->vflip = ctrls->vflip->val;
} else {
+ ctx->effect.type = FIMC_REG_CIIMGEFF_FIN_BYPASS;
ctx->rotation = 0;
ctx->hflip = 0;
ctx->vflip = 0;
}
- mutex_unlock(&ctx->ctrl_handler.lock);
+ mutex_unlock(&ctrls->handler.lock);
}
/* Update maximum value of the alpha color control */
void fimc_alpha_ctrl_update(struct fimc_ctx *ctx)
{
struct fimc_dev *fimc = ctx->fimc_dev;
- struct v4l2_ctrl *ctrl = ctx->ctrl_alpha;
+ struct v4l2_ctrl *ctrl = ctx->ctrls.alpha;
if (ctrl == NULL || !fimc->variant->has_alpha)
return;
@@ -918,39 +681,6 @@ void fimc_alpha_ctrl_update(struct fimc_ctx *ctx)
v4l2_ctrl_unlock(ctrl);
}
-/*
- * V4L2 ioctl handlers
- */
-static int fimc_m2m_querycap(struct file *file, void *fh,
- struct v4l2_capability *cap)
-{
- struct fimc_ctx *ctx = fh_to_ctx(fh);
- struct fimc_dev *fimc = ctx->fimc_dev;
-
- strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1);
- strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);
- cap->bus_info[0] = 0;
- cap->capabilities = V4L2_CAP_STREAMING |
- V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
-
- return 0;
-}
-
-static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
-{
- struct fimc_fmt *fmt;
-
- fmt = fimc_find_format(NULL, NULL, get_m2m_fmt_flags(f->type),
- f->index);
- if (!fmt)
- return -EINVAL;
-
- strncpy(f->description, fmt->name, sizeof(f->description) - 1);
- f->pixelformat = fmt->fourcc;
- return 0;
-}
-
int fimc_fill_format(struct fimc_frame *frame, struct v4l2_format *f)
{
struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
@@ -1029,18 +759,6 @@ void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height,
}
}
-static int fimc_m2m_g_fmt_mplane(struct file *file, void *fh,
- struct v4l2_format *f)
-{
- struct fimc_ctx *ctx = fh_to_ctx(fh);
- struct fimc_frame *frame = ctx_get_frame(ctx, f->type);
-
- if (IS_ERR(frame))
- return PTR_ERR(frame);
-
- return fimc_fill_format(frame, f);
-}
-
/**
* fimc_find_format - lookup fimc color format by fourcc or media bus format
* @pixelformat: fourcc to match, ignored if null
@@ -1073,535 +791,10 @@ struct fimc_fmt *fimc_find_format(const u32 *pixelformat, const u32 *mbus_code,
return def_fmt;
}
-static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f)
-{
- struct fimc_dev *fimc = ctx->fimc_dev;
- struct samsung_fimc_variant *variant = fimc->variant;
- struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
- struct fimc_fmt *fmt;
- u32 max_w, mod_x, mod_y;
-
- if (!IS_M2M(f->type))
- return -EINVAL;
-
- dbg("w: %d, h: %d", pix->width, pix->height);
-
- fmt = fimc_find_format(&pix->pixelformat, NULL,
- get_m2m_fmt_flags(f->type), 0);
- if (WARN(fmt == NULL, "Pixel format lookup failed"))
- return -EINVAL;
-
- if (pix->field == V4L2_FIELD_ANY)
- pix->field = V4L2_FIELD_NONE;
- else if (pix->field != V4L2_FIELD_NONE)
- return -EINVAL;
-
- if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- max_w = variant->pix_limit->scaler_dis_w;
- mod_x = ffs(variant->min_inp_pixsize) - 1;
- } else {
- max_w = variant->pix_limit->out_rot_dis_w;
- mod_x = ffs(variant->min_out_pixsize) - 1;
- }
-
- if (tiled_fmt(fmt)) {
- mod_x = 6; /* 64 x 32 pixels tile */
- mod_y = 5;
- } else {
- if (variant->min_vsize_align == 1)
- mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1;
- else
- mod_y = ffs(variant->min_vsize_align) - 1;
- }
-
- v4l_bound_align_image(&pix->width, 16, max_w, mod_x,
- &pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0);
-
- fimc_adjust_mplane_format(fmt, pix->width, pix->height, &f->fmt.pix_mp);
- return 0;
-}
-
-static int fimc_m2m_try_fmt_mplane(struct file *file, void *fh,
- struct v4l2_format *f)
-{
- struct fimc_ctx *ctx = fh_to_ctx(fh);
-
- return fimc_try_fmt_mplane(ctx, f);
-}
-
-static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
- struct v4l2_format *f)
-{
- struct fimc_ctx *ctx = fh_to_ctx(fh);
- struct fimc_dev *fimc = ctx->fimc_dev;
- struct vb2_queue *vq;
- struct fimc_frame *frame;
- struct v4l2_pix_format_mplane *pix;
- int i, ret = 0;
-
- ret = fimc_try_fmt_mplane(ctx, f);
- if (ret)
- return ret;
-
- vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
-
- if (vb2_is_busy(vq)) {
- v4l2_err(fimc->m2m.vfd, "queue (%d) busy\n", f->type);
- return -EBUSY;
- }
-
- if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- frame = &ctx->s_frame;
- else
- frame = &ctx->d_frame;
-
- pix = &f->fmt.pix_mp;
- frame->fmt = fimc_find_format(&pix->pixelformat, NULL,
- get_m2m_fmt_flags(f->type), 0);
- if (!frame->fmt)
- return -EINVAL;
-
- /* Update RGB Alpha control state and value range */
- fimc_alpha_ctrl_update(ctx);
-
- for (i = 0; i < frame->fmt->colplanes; i++) {
- frame->payload[i] =
- (pix->width * pix->height * frame->fmt->depth[i]) / 8;
- }
-
- fimc_fill_frame(frame, f);
-
- ctx->scaler.enabled = 1;
-
- if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
- fimc_ctx_state_lock_set(FIMC_PARAMS | FIMC_DST_FMT, ctx);
- else
- fimc_ctx_state_lock_set(FIMC_PARAMS | FIMC_SRC_FMT, ctx);
-
- dbg("f_w: %d, f_h: %d", frame->f_width, frame->f_height);
-
- return 0;
-}
-
-static int fimc_m2m_reqbufs(struct file *file, void *fh,
- struct v4l2_requestbuffers *reqbufs)
-{
- struct fimc_ctx *ctx = fh_to_ctx(fh);
-
- return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
-}
-
-static int fimc_m2m_querybuf(struct file *file, void *fh,
- struct v4l2_buffer *buf)
-{
- struct fimc_ctx *ctx = fh_to_ctx(fh);
-
- return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
-}
-
-static int fimc_m2m_qbuf(struct file *file, void *fh,
- struct v4l2_buffer *buf)
-{
- struct fimc_ctx *ctx = fh_to_ctx(fh);
-
- return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
-}
-
-static int fimc_m2m_dqbuf(struct file *file, void *fh,
- struct v4l2_buffer *buf)
-{
- struct fimc_ctx *ctx = fh_to_ctx(fh);
-
- return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
-}
-
-static int fimc_m2m_streamon(struct file *file, void *fh,
- enum v4l2_buf_type type)
-{
- struct fimc_ctx *ctx = fh_to_ctx(fh);
-
- /* The source and target color format need to be set */
- if (V4L2_TYPE_IS_OUTPUT(type)) {
- if (!fimc_ctx_state_is_set(FIMC_SRC_FMT, ctx))
- return -EINVAL;
- } else if (!fimc_ctx_state_is_set(FIMC_DST_FMT, ctx)) {
- return -EINVAL;
- }
-
- return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
-}
-
-static int fimc_m2m_streamoff(struct file *file, void *fh,
- enum v4l2_buf_type type)
-{
- struct fimc_ctx *ctx = fh_to_ctx(fh);
-
- return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
-}
-
-static int fimc_m2m_cropcap(struct file *file, void *fh,
- struct v4l2_cropcap *cr)
-{
- struct fimc_ctx *ctx = fh_to_ctx(fh);
- struct fimc_frame *frame;
-
- frame = ctx_get_frame(ctx, cr->type);
- if (IS_ERR(frame))
- return PTR_ERR(frame);
-
- cr->bounds.left = 0;
- cr->bounds.top = 0;
- cr->bounds.width = frame->o_width;
- cr->bounds.height = frame->o_height;
- cr->defrect = cr->bounds;
-
- return 0;
-}
-
-static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
-{
- struct fimc_ctx *ctx = fh_to_ctx(fh);
- struct fimc_frame *frame;
-
- frame = ctx_get_frame(ctx, cr->type);
- if (IS_ERR(frame))
- return PTR_ERR(frame);
-
- cr->c.left = frame->offs_h;
- cr->c.top = frame->offs_v;
- cr->c.width = frame->width;
- cr->c.height = frame->height;
-
- return 0;
-}
-
-static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
-{
- struct fimc_dev *fimc = ctx->fimc_dev;
- struct fimc_frame *f;
- u32 min_size, halign, depth = 0;
- int i;
-
- if (cr->c.top < 0 || cr->c.left < 0) {
- v4l2_err(fimc->m2m.vfd,
- "doesn't support negative values for top & left\n");
- return -EINVAL;
- }
- if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
- f = &ctx->d_frame;
- else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- f = &ctx->s_frame;
- else
- return -EINVAL;
-
- min_size = (f == &ctx->s_frame) ?
- fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize;
-
- /* Get pixel alignment constraints. */
- if (fimc->variant->min_vsize_align == 1)
- halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1;
- else
- halign = ffs(fimc->variant->min_vsize_align) - 1;
-
- for (i = 0; i < f->fmt->colplanes; i++)
- depth += f->fmt->depth[i];
-
- v4l_bound_align_image(&cr->c.width, min_size, f->o_width,
- ffs(min_size) - 1,
- &cr->c.height, min_size, f->o_height,
- halign, 64/(ALIGN(depth, 8)));
-
- /* adjust left/top if cropping rectangle is out of bounds */
- if (cr->c.left + cr->c.width > f->o_width)
- cr->c.left = f->o_width - cr->c.width;
- if (cr->c.top + cr->c.height > f->o_height)
- cr->c.top = f->o_height - cr->c.height;
-
- cr->c.left = round_down(cr->c.left, min_size);
- cr->c.top = round_down(cr->c.top, fimc->variant->hor_offs_align);
-
- dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
- cr->c.left, cr->c.top, cr->c.width, cr->c.height,
- f->f_width, f->f_height);
-
- return 0;
-}
-
-static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
-{
- struct fimc_ctx *ctx = fh_to_ctx(fh);
- struct fimc_dev *fimc = ctx->fimc_dev;
- struct fimc_frame *f;
- int ret;
-
- ret = fimc_m2m_try_crop(ctx, cr);
- if (ret)
- return ret;
-
- f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ?
- &ctx->s_frame : &ctx->d_frame;
-
- /* Check to see if scaling ratio is within supported range */
- if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) {
- if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- ret = fimc_check_scaler_ratio(ctx, cr->c.width,
- cr->c.height, ctx->d_frame.width,
- ctx->d_frame.height, ctx->rotation);
- } else {
- ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
- ctx->s_frame.height, cr->c.width,
- cr->c.height, ctx->rotation);
- }
- if (ret) {
- v4l2_err(fimc->m2m.vfd, "Out of scaler range\n");
- return -EINVAL;
- }
- }
-
- f->offs_h = cr->c.left;
- f->offs_v = cr->c.top;
- f->width = cr->c.width;
- f->height = cr->c.height;
-
- fimc_ctx_state_lock_set(FIMC_PARAMS, ctx);
-
- return 0;
-}
-
-static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
- .vidioc_querycap = fimc_m2m_querycap,
-
- .vidioc_enum_fmt_vid_cap_mplane = fimc_m2m_enum_fmt_mplane,
- .vidioc_enum_fmt_vid_out_mplane = fimc_m2m_enum_fmt_mplane,
-
- .vidioc_g_fmt_vid_cap_mplane = fimc_m2m_g_fmt_mplane,
- .vidioc_g_fmt_vid_out_mplane = fimc_m2m_g_fmt_mplane,
-
- .vidioc_try_fmt_vid_cap_mplane = fimc_m2m_try_fmt_mplane,
- .vidioc_try_fmt_vid_out_mplane = fimc_m2m_try_fmt_mplane,
-
- .vidioc_s_fmt_vid_cap_mplane = fimc_m2m_s_fmt_mplane,
- .vidioc_s_fmt_vid_out_mplane = fimc_m2m_s_fmt_mplane,
-
- .vidioc_reqbufs = fimc_m2m_reqbufs,
- .vidioc_querybuf = fimc_m2m_querybuf,
-
- .vidioc_qbuf = fimc_m2m_qbuf,
- .vidioc_dqbuf = fimc_m2m_dqbuf,
-
- .vidioc_streamon = fimc_m2m_streamon,
- .vidioc_streamoff = fimc_m2m_streamoff,
-
- .vidioc_g_crop = fimc_m2m_g_crop,
- .vidioc_s_crop = fimc_m2m_s_crop,
- .vidioc_cropcap = fimc_m2m_cropcap
-
-};
-
-static int queue_init(void *priv, struct vb2_queue *src_vq,
- struct vb2_queue *dst_vq)
-{
- struct fimc_ctx *ctx = priv;
- int ret;
-
- memset(src_vq, 0, sizeof(*src_vq));
- src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
- src_vq->drv_priv = ctx;
- src_vq->ops = &fimc_qops;
- src_vq->mem_ops = &vb2_dma_contig_memops;
- src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
-
- ret = vb2_queue_init(src_vq);
- if (ret)
- return ret;
-
- memset(dst_vq, 0, sizeof(*dst_vq));
- dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
- dst_vq->drv_priv = ctx;
- dst_vq->ops = &fimc_qops;
- dst_vq->mem_ops = &vb2_dma_contig_memops;
- dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
-
- return vb2_queue_init(dst_vq);
-}
-
-static int fimc_m2m_open(struct file *file)
-{
- struct fimc_dev *fimc = video_drvdata(file);
- struct fimc_ctx *ctx;
- int ret;
-
- dbg("pid: %d, state: 0x%lx, refcnt: %d",
- task_pid_nr(current), fimc->state, fimc->vid_cap.refcnt);
-
- /*
- * Return if the corresponding video capture node
- * is already opened.
- */
- if (fimc->vid_cap.refcnt > 0)
- return -EBUSY;
-
- ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
- v4l2_fh_init(&ctx->fh, fimc->m2m.vfd);
- ctx->fimc_dev = fimc;
-
- /* Default color format */
- ctx->s_frame.fmt = &fimc_formats[0];
- ctx->d_frame.fmt = &fimc_formats[0];
-
- ret = fimc_ctrls_create(ctx);
- if (ret)
- goto error_fh;
-
- /* Use separate control handler per file handle */
- ctx->fh.ctrl_handler = &ctx->ctrl_handler;
- file->private_data = &ctx->fh;
- v4l2_fh_add(&ctx->fh);
-
- /* Setup the device context for memory-to-memory mode */
- ctx->state = FIMC_CTX_M2M;
- ctx->flags = 0;
- ctx->in_path = FIMC_DMA;
- ctx->out_path = FIMC_DMA;
- spin_lock_init(&ctx->slock);
-
- ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init);
- if (IS_ERR(ctx->m2m_ctx)) {
- ret = PTR_ERR(ctx->m2m_ctx);
- goto error_c;
- }
-
- if (fimc->m2m.refcnt++ == 0)
- set_bit(ST_M2M_RUN, &fimc->state);
- return 0;
-
-error_c:
- fimc_ctrls_delete(ctx);
-error_fh:
- v4l2_fh_del(&ctx->fh);
- v4l2_fh_exit(&ctx->fh);
- kfree(ctx);
- return ret;
-}
-
-static int fimc_m2m_release(struct file *file)
-{
- struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
- struct fimc_dev *fimc = ctx->fimc_dev;
-
- dbg("pid: %d, state: 0x%lx, refcnt= %d",
- task_pid_nr(current), fimc->state, fimc->m2m.refcnt);
-
- v4l2_m2m_ctx_release(ctx->m2m_ctx);
- fimc_ctrls_delete(ctx);
- v4l2_fh_del(&ctx->fh);
- v4l2_fh_exit(&ctx->fh);
-
- if (--fimc->m2m.refcnt <= 0)
- clear_bit(ST_M2M_RUN, &fimc->state);
- kfree(ctx);
- return 0;
-}
-
-static unsigned int fimc_m2m_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
-
- return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
-}
-
-
-static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
-
- return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
-}
-
-static const struct v4l2_file_operations fimc_m2m_fops = {
- .owner = THIS_MODULE,
- .open = fimc_m2m_open,
- .release = fimc_m2m_release,
- .poll = fimc_m2m_poll,
- .unlocked_ioctl = video_ioctl2,
- .mmap = fimc_m2m_mmap,
-};
-
-static struct v4l2_m2m_ops m2m_ops = {
- .device_run = fimc_dma_run,
- .job_abort = fimc_job_abort,
-};
-
-int fimc_register_m2m_device(struct fimc_dev *fimc,
- struct v4l2_device *v4l2_dev)
-{
- struct video_device *vfd;
- struct platform_device *pdev;
- int ret = 0;
-
- if (!fimc)
- return -ENODEV;
-
- pdev = fimc->pdev;
- fimc->v4l2_dev = v4l2_dev;
-
- vfd = video_device_alloc();
- if (!vfd) {
- v4l2_err(v4l2_dev, "Failed to allocate video device\n");
- return -ENOMEM;
- }
-
- vfd->fops = &fimc_m2m_fops;
- vfd->ioctl_ops = &fimc_m2m_ioctl_ops;
- vfd->v4l2_dev = v4l2_dev;
- vfd->minor = -1;
- vfd->release = video_device_release;
- vfd->lock = &fimc->lock;
-
- snprintf(vfd->name, sizeof(vfd->name), "%s.m2m", dev_name(&pdev->dev));
- video_set_drvdata(vfd, fimc);
-
- fimc->m2m.vfd = vfd;
- fimc->m2m.m2m_dev = v4l2_m2m_init(&m2m_ops);
- if (IS_ERR(fimc->m2m.m2m_dev)) {
- v4l2_err(v4l2_dev, "failed to initialize v4l2-m2m device\n");
- ret = PTR_ERR(fimc->m2m.m2m_dev);
- goto err_init;
- }
-
- ret = media_entity_init(&vfd->entity, 0, NULL, 0);
- if (!ret)
- return 0;
-
- v4l2_m2m_release(fimc->m2m.m2m_dev);
-err_init:
- video_device_release(fimc->m2m.vfd);
- return ret;
-}
-
-void fimc_unregister_m2m_device(struct fimc_dev *fimc)
-{
- if (!fimc)
- return;
-
- if (fimc->m2m.m2m_dev)
- v4l2_m2m_release(fimc->m2m.m2m_dev);
- if (fimc->m2m.vfd) {
- media_entity_cleanup(&fimc->m2m.vfd->entity);
- /* Can also be called if video device wasn't registered */
- video_unregister_device(fimc->m2m.vfd);
- }
-}
-
static void fimc_clk_put(struct fimc_dev *fimc)
{
int i;
- for (i = 0; i < fimc->num_clocks; i++) {
+ for (i = 0; i < MAX_FIMC_CLOCKS; i++) {
if (IS_ERR_OR_NULL(fimc->clock[i]))
continue;
clk_unprepare(fimc->clock[i]);
@@ -1614,7 +807,7 @@ static int fimc_clk_get(struct fimc_dev *fimc)
{
int i, ret;
- for (i = 0; i < fimc->num_clocks; i++) {
+ for (i = 0; i < MAX_FIMC_CLOCKS; i++) {
fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]);
if (IS_ERR(fimc->clock[i]))
goto err;
@@ -1672,15 +865,12 @@ static int fimc_m2m_resume(struct fimc_dev *fimc)
static int fimc_probe(struct platform_device *pdev)
{
+ struct fimc_drvdata *drv_data = fimc_get_drvdata(pdev);
+ struct s5p_platform_fimc *pdata;
struct fimc_dev *fimc;
struct resource *res;
- struct samsung_fimc_driverdata *drv_data;
- struct s5p_platform_fimc *pdata;
int ret = 0;
- drv_data = (struct samsung_fimc_driverdata *)
- platform_get_device_id(pdev)->driver_data;
-
if (pdev->id >= drv_data->num_entities) {
dev_err(&pdev->dev, "Invalid platform device id: %d\n",
pdev->id);
@@ -1714,28 +904,29 @@ static int fimc_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Failed to get IRQ resource\n");
return -ENXIO;
}
- fimc->irq = res->start;
- fimc->num_clocks = MAX_FIMC_CLOCKS;
ret = fimc_clk_get(fimc);
if (ret)
return ret;
clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency);
clk_enable(fimc->clock[CLK_BUS]);
- platform_set_drvdata(pdev, fimc);
-
- ret = devm_request_irq(&pdev->dev, fimc->irq, fimc_irq_handler,
- 0, pdev->name, fimc);
+ ret = devm_request_irq(&pdev->dev, res->start, fimc_irq_handler,
+ 0, dev_name(&pdev->dev), fimc);
if (ret) {
dev_err(&pdev->dev, "failed to install irq (%d)\n", ret);
goto err_clk;
}
+ ret = fimc_initialize_capture_subdev(fimc);
+ if (ret)
+ goto err_clk;
+
+ platform_set_drvdata(pdev, fimc);
pm_runtime_enable(&pdev->dev);
ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0)
- goto err_clk;
+ goto err_sd;
/* Initialize contiguous memory allocator */
fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
if (IS_ERR(fimc->alloc_ctx)) {
@@ -1747,9 +938,10 @@ static int fimc_probe(struct platform_device *pdev)
pm_runtime_put(&pdev->dev);
return 0;
-
err_pm:
pm_runtime_put(&pdev->dev);
+err_sd:
+ fimc_unregister_capture_subdev(fimc);
err_clk:
fimc_clk_put(fimc);
return ret;
@@ -1834,6 +1026,7 @@ static int __devexit fimc_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
+ fimc_unregister_capture_subdev(fimc);
vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx);
clk_disable(fimc->clock[CLK_BUS]);
@@ -1879,7 +1072,7 @@ static struct fimc_pix_limit s5p_pix_limit[4] = {
},
};
-static struct samsung_fimc_variant fimc0_variant_s5p = {
+static struct fimc_variant fimc0_variant_s5p = {
.has_inp_rot = 1,
.has_out_rot = 1,
.has_cam_if = 1,
@@ -1891,17 +1084,17 @@ static struct samsung_fimc_variant fimc0_variant_s5p = {
.pix_limit = &s5p_pix_limit[0],
};
-static struct samsung_fimc_variant fimc2_variant_s5p = {
+static struct fimc_variant fimc2_variant_s5p = {
.has_cam_if = 1,
.min_inp_pixsize = 16,
.min_out_pixsize = 16,
.hor_offs_align = 8,
.min_vsize_align = 16,
.out_buf_count = 4,
- .pix_limit = &s5p_pix_limit[1],
+ .pix_limit = &s5p_pix_limit[1],
};
-static struct samsung_fimc_variant fimc0_variant_s5pv210 = {
+static struct fimc_variant fimc0_variant_s5pv210 = {
.pix_hoff = 1,
.has_inp_rot = 1,
.has_out_rot = 1,
@@ -1914,7 +1107,7 @@ static struct samsung_fimc_variant fimc0_variant_s5pv210 = {
.pix_limit = &s5p_pix_limit[1],
};
-static struct samsung_fimc_variant fimc1_variant_s5pv210 = {
+static struct fimc_variant fimc1_variant_s5pv210 = {
.pix_hoff = 1,
.has_inp_rot = 1,
.has_out_rot = 1,
@@ -1928,7 +1121,7 @@ static struct samsung_fimc_variant fimc1_variant_s5pv210 = {
.pix_limit = &s5p_pix_limit[2],
};
-static struct samsung_fimc_variant fimc2_variant_s5pv210 = {
+static struct fimc_variant fimc2_variant_s5pv210 = {
.has_cam_if = 1,
.pix_hoff = 1,
.min_inp_pixsize = 16,
@@ -1939,7 +1132,7 @@ static struct samsung_fimc_variant fimc2_variant_s5pv210 = {
.pix_limit = &s5p_pix_limit[2],
};
-static struct samsung_fimc_variant fimc0_variant_exynos4 = {
+static struct fimc_variant fimc0_variant_exynos4 = {
.pix_hoff = 1,
.has_inp_rot = 1,
.has_out_rot = 1,
@@ -1955,7 +1148,7 @@ static struct samsung_fimc_variant fimc0_variant_exynos4 = {
.pix_limit = &s5p_pix_limit[1],
};
-static struct samsung_fimc_variant fimc3_variant_exynos4 = {
+static struct fimc_variant fimc3_variant_exynos4 = {
.pix_hoff = 1,
.has_cam_if = 1,
.has_cistatus2 = 1,
@@ -1970,7 +1163,7 @@ static struct samsung_fimc_variant fimc3_variant_exynos4 = {
};
/* S5PC100 */
-static struct samsung_fimc_driverdata fimc_drvdata_s5p = {
+static struct fimc_drvdata fimc_drvdata_s5p = {
.variant = {
[0] = &fimc0_variant_s5p,
[1] = &fimc0_variant_s5p,
@@ -1981,7 +1174,7 @@ static struct samsung_fimc_driverdata fimc_drvdata_s5p = {
};
/* S5PV210, S5PC110 */
-static struct samsung_fimc_driverdata fimc_drvdata_s5pv210 = {
+static struct fimc_drvdata fimc_drvdata_s5pv210 = {
.variant = {
[0] = &fimc0_variant_s5pv210,
[1] = &fimc1_variant_s5pv210,
@@ -1991,8 +1184,8 @@ static struct samsung_fimc_driverdata fimc_drvdata_s5pv210 = {
.lclk_frequency = 166000000UL,
};
-/* S5PV310, S5PC210 */
-static struct samsung_fimc_driverdata fimc_drvdata_exynos4 = {
+/* EXYNOS4210, S5PV310, S5PC210 */
+static struct fimc_drvdata fimc_drvdata_exynos4 = {
.variant = {
[0] = &fimc0_variant_exynos4,
[1] = &fimc0_variant_exynos4,
@@ -2036,7 +1229,7 @@ static struct platform_driver fimc_driver = {
int __init fimc_register_driver(void)
{
- return platform_driver_probe(&fimc_driver, fimc_probe);
+ return platform_driver_register(&fimc_driver);
}
void __exit fimc_unregister_driver(void)
diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h
index 84fd83550bd7..95b27ae5cf27 100644
--- a/drivers/media/video/s5p-fimc/fimc-core.h
+++ b/drivers/media/video/s5p-fimc/fimc-core.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 - 2011 Samsung Electronics Co., Ltd.
+ * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd.
*
* 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
@@ -17,6 +17,7 @@
#include <linux/types.h>
#include <linux/videodev2.h>
#include <linux/io.h>
+#include <asm/sizes.h>
#include <media/media-entity.h>
#include <media/videobuf2-core.h>
@@ -26,8 +27,6 @@
#include <media/v4l2-mediabus.h>
#include <media/s5p_fimc.h>
-#include "regs-fimc.h"
-
#define err(fmt, args...) \
printk(KERN_ERR "%s:%d: " fmt "\n", __func__, __LINE__, ##args)
@@ -78,26 +77,31 @@ enum fimc_dev_flags {
#define fimc_capture_busy(dev) test_bit(ST_CAPT_BUSY, &(dev)->state)
enum fimc_datapath {
- FIMC_CAMERA,
- FIMC_DMA,
- FIMC_LCDFIFO,
- FIMC_WRITEBACK
+ FIMC_IO_NONE,
+ FIMC_IO_CAMERA,
+ FIMC_IO_DMA,
+ FIMC_IO_LCDFIFO,
+ FIMC_IO_WRITEBACK,
+ FIMC_IO_ISP,
};
enum fimc_color_fmt {
- S5P_FIMC_RGB444 = 0x10,
- S5P_FIMC_RGB555,
- S5P_FIMC_RGB565,
- S5P_FIMC_RGB666,
- S5P_FIMC_RGB888,
- S5P_FIMC_RGB30_LOCAL,
- S5P_FIMC_YCBCR420 = 0x20,
- S5P_FIMC_YCBYCR422,
- S5P_FIMC_YCRYCB422,
- S5P_FIMC_CBYCRY422,
- S5P_FIMC_CRYCBY422,
- S5P_FIMC_YCBCR444_LOCAL,
- S5P_FIMC_JPEG = 0x40,
+ FIMC_FMT_RGB444 = 0x10,
+ FIMC_FMT_RGB555,
+ FIMC_FMT_RGB565,
+ FIMC_FMT_RGB666,
+ FIMC_FMT_RGB888,
+ FIMC_FMT_RGB30_LOCAL,
+ FIMC_FMT_YCBCR420 = 0x20,
+ FIMC_FMT_YCBYCR422,
+ FIMC_FMT_YCRYCB422,
+ FIMC_FMT_CBYCRY422,
+ FIMC_FMT_CRYCBY422,
+ FIMC_FMT_YCBCR444_LOCAL,
+ FIMC_FMT_JPEG = 0x40,
+ FIMC_FMT_RAW8 = 0x80,
+ FIMC_FMT_RAW10,
+ FIMC_FMT_RAW12,
};
#define fimc_fmt_is_rgb(x) (!!((x) & 0x10))
@@ -106,24 +110,11 @@ enum fimc_color_fmt {
#define IS_M2M(__strt) ((__strt) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE || \
__strt == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
-/* Cb/Cr chrominance components order for 2 plane Y/CbCr 4:2:2 formats. */
-#define S5P_FIMC_LSB_CRCB S5P_CIOCTRL_ORDER422_2P_LSB_CRCB
-
-/* The embedded image effect selection */
-#define S5P_FIMC_EFFECT_ORIGINAL S5P_CIIMGEFF_FIN_BYPASS
-#define S5P_FIMC_EFFECT_ARBITRARY S5P_CIIMGEFF_FIN_ARBITRARY
-#define S5P_FIMC_EFFECT_NEGATIVE S5P_CIIMGEFF_FIN_NEGATIVE
-#define S5P_FIMC_EFFECT_ARTFREEZE S5P_CIIMGEFF_FIN_ARTFREEZE
-#define S5P_FIMC_EFFECT_EMBOSSING S5P_CIIMGEFF_FIN_EMBOSSING
-#define S5P_FIMC_EFFECT_SIKHOUETTE S5P_CIIMGEFF_FIN_SILHOUETTE
-
/* The hardware context state. */
#define FIMC_PARAMS (1 << 0)
-#define FIMC_SRC_ADDR (1 << 1)
-#define FIMC_DST_ADDR (1 << 2)
#define FIMC_SRC_FMT (1 << 3)
#define FIMC_DST_FMT (1 << 4)
-#define FIMC_DST_CROP (1 << 5)
+#define FIMC_COMPOSE (1 << 5)
#define FIMC_CTX_M2M (1 << 16)
#define FIMC_CTX_CAP (1 << 17)
#define FIMC_CTX_SHUT (1 << 18)
@@ -333,7 +324,7 @@ struct fimc_vid_cap {
struct fimc_ctx *ctx;
struct vb2_alloc_ctx *alloc_ctx;
struct video_device *vfd;
- struct v4l2_subdev *subdev;
+ struct v4l2_subdev subdev;
struct media_pad vd_pad;
struct v4l2_mbus_framefmt mf;
struct media_pad sd_pads[FIMC_SD_PADS_NUM];
@@ -370,8 +361,7 @@ struct fimc_pix_limit {
};
/**
- * struct samsung_fimc_variant - camera interface variant information
- *
+ * struct fimc_variant - FIMC device variant information
* @pix_hoff: indicate whether horizontal offset is in pixels or in bytes
* @has_inp_rot: set if has input rotator
* @has_out_rot: set if has output rotator
@@ -386,7 +376,7 @@ struct fimc_pix_limit {
* @min_vsize_align: minimum vertical pixel size alignment
* @out_buf_count: the number of buffers in output DMA sequence
*/
-struct samsung_fimc_variant {
+struct fimc_variant {
unsigned int pix_hoff:1;
unsigned int has_inp_rot:1;
unsigned int has_out_rot:1;
@@ -403,23 +393,19 @@ struct samsung_fimc_variant {
};
/**
- * struct samsung_fimc_driverdata - per device type driver data for init time.
- *
- * @variant: the variant information for this driver.
- * @dev_cnt: number of fimc sub-devices available in SoC
- * @lclk_frequency: fimc bus clock frequency
+ * struct fimc_drvdata - per device type driver data
+ * @variant: variant information for this device
+ * @num_entities: number of fimc instances available in a SoC
+ * @lclk_frequency: local bus clock frequency
*/
-struct samsung_fimc_driverdata {
- struct samsung_fimc_variant *variant[FIMC_MAX_DEVS];
- unsigned long lclk_frequency;
- int num_entities;
+struct fimc_drvdata {
+ struct fimc_variant *variant[FIMC_MAX_DEVS];
+ int num_entities;
+ unsigned long lclk_frequency;
};
-struct fimc_pipeline {
- struct media_pipeline *pipe;
- struct v4l2_subdev *sensor;
- struct v4l2_subdev *csis;
-};
+#define fimc_get_drvdata(_pdev) \
+ ((struct fimc_drvdata *) platform_get_device_id(_pdev)->driver_data)
struct fimc_ctx;
@@ -431,10 +417,8 @@ struct fimc_ctx;
* @pdata: pointer to the device platform data
* @variant: the IP variant information
* @id: FIMC device index (0..FIMC_MAX_DEVS)
- * @num_clocks: the number of clocks managed by this device instance
* @clock: clocks required for FIMC operation
* @regs: the mapped hardware registers
- * @irq: FIMC interrupt number
* @irq_queue: interrupt handler waitqueue
* @v4l2_dev: root v4l2_device
* @m2m: memory-to-memory V4L2 device information
@@ -448,12 +432,10 @@ struct fimc_dev {
struct mutex lock;
struct platform_device *pdev;
struct s5p_platform_fimc *pdata;
- struct samsung_fimc_variant *variant;
+ struct fimc_variant *variant;
u16 id;
- u16 num_clocks;
struct clk *clock[MAX_FIMC_CLOCKS];
void __iomem *regs;
- int irq;
wait_queue_head_t irq_queue;
struct v4l2_device *v4l2_dev;
struct fimc_m2m_device m2m;
@@ -464,8 +446,31 @@ struct fimc_dev {
};
/**
+ * struct fimc_ctrls - v4l2 controls structure
+ * @handler: the control handler
+ * @colorfx: image effect control
+ * @colorfx_cbcr: Cb/Cr coefficients control
+ * @rotate: image rotation control
+ * @hflip: horizontal flip control
+ * @vflip: vertical flip control
+ * @alpha: RGB alpha control
+ * @ready: true if @handler is initialized
+ */
+struct fimc_ctrls {
+ struct v4l2_ctrl_handler handler;
+ struct {
+ struct v4l2_ctrl *colorfx;
+ struct v4l2_ctrl *colorfx_cbcr;
+ };
+ struct v4l2_ctrl *rotate;
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+ struct v4l2_ctrl *alpha;
+ bool ready;
+};
+
+/**
* fimc_ctx - the device context data
- * @slock: spinlock protecting this data structure
* @s_frame: source frame properties
* @d_frame: destination frame properties
* @out_order_1p: output 1-plane YCBCR order
@@ -484,15 +489,9 @@ struct fimc_dev {
* @fimc_dev: the FIMC device this context applies to
* @m2m_ctx: memory-to-memory device context
* @fh: v4l2 file handle
- * @ctrl_handler: v4l2 controls handler
- * @ctrl_rotate image rotation control
- * @ctrl_hflip horizontal flip control
- * @ctrl_vflip vertical flip control
- * @ctrl_alpha RGB alpha control
- * @ctrls_rdy: true if the control handler is initialized
+ * @ctrls: v4l2 controls structure
*/
struct fimc_ctx {
- spinlock_t slock;
struct fimc_frame s_frame;
struct fimc_frame d_frame;
u32 out_order_1p;
@@ -511,12 +510,7 @@ struct fimc_ctx {
struct fimc_dev *fimc_dev;
struct v4l2_m2m_ctx *m2m_ctx;
struct v4l2_fh fh;
- struct v4l2_ctrl_handler ctrl_handler;
- struct v4l2_ctrl *ctrl_rotate;
- struct v4l2_ctrl *ctrl_hflip;
- struct v4l2_ctrl *ctrl_vflip;
- struct v4l2_ctrl *ctrl_alpha;
- bool ctrls_rdy;
+ struct fimc_ctrls ctrls;
};
#define fh_to_ctx(__fh) container_of(__fh, struct fimc_ctx, fh)
@@ -560,13 +554,13 @@ static inline bool fimc_capture_active(struct fimc_dev *fimc)
return ret;
}
-static inline void fimc_ctx_state_lock_set(u32 state, struct fimc_ctx *ctx)
+static inline void fimc_ctx_state_set(u32 state, struct fimc_ctx *ctx)
{
unsigned long flags;
- spin_lock_irqsave(&ctx->slock, flags);
+ spin_lock_irqsave(&ctx->fimc_dev->slock, flags);
ctx->state |= state;
- spin_unlock_irqrestore(&ctx->slock, flags);
+ spin_unlock_irqrestore(&ctx->fimc_dev->slock, flags);
}
static inline bool fimc_ctx_state_is_set(u32 mask, struct fimc_ctx *ctx)
@@ -574,9 +568,9 @@ static inline bool fimc_ctx_state_is_set(u32 mask, struct fimc_ctx *ctx)
unsigned long flags;
bool ret;
- spin_lock_irqsave(&ctx->slock, flags);
+ spin_lock_irqsave(&ctx->fimc_dev->slock, flags);
ret = (ctx->state & mask) == mask;
- spin_unlock_irqrestore(&ctx->slock, flags);
+ spin_unlock_irqrestore(&ctx->fimc_dev->slock, flags);
return ret;
}
@@ -589,61 +583,13 @@ static inline int tiled_fmt(struct fimc_fmt *fmt)
static inline int fimc_get_alpha_mask(struct fimc_fmt *fmt)
{
switch (fmt->color) {
- case S5P_FIMC_RGB444: return 0x0f;
- case S5P_FIMC_RGB555: return 0x01;
- case S5P_FIMC_RGB888: return 0xff;
+ case FIMC_FMT_RGB444: return 0x0f;
+ case FIMC_FMT_RGB555: return 0x01;
+ case FIMC_FMT_RGB888: return 0xff;
default: return 0;
};
}
-static inline void fimc_hw_clear_irq(struct fimc_dev *dev)
-{
- u32 cfg = readl(dev->regs + S5P_CIGCTRL);
- cfg |= S5P_CIGCTRL_IRQ_CLR;
- writel(cfg, dev->regs + S5P_CIGCTRL);
-}
-
-static inline void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on)
-{
- u32 cfg = readl(dev->regs + S5P_CISCCTRL);
- if (on)
- cfg |= S5P_CISCCTRL_SCALERSTART;
- else
- cfg &= ~S5P_CISCCTRL_SCALERSTART;
- writel(cfg, dev->regs + S5P_CISCCTRL);
-}
-
-static inline void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on)
-{
- u32 cfg = readl(dev->regs + S5P_MSCTRL);
- if (on)
- cfg |= S5P_MSCTRL_ENVID;
- else
- cfg &= ~S5P_MSCTRL_ENVID;
- writel(cfg, dev->regs + S5P_MSCTRL);
-}
-
-static inline void fimc_hw_dis_capture(struct fimc_dev *dev)
-{
- u32 cfg = readl(dev->regs + S5P_CIIMGCPT);
- cfg &= ~(S5P_CIIMGCPT_IMGCPTEN | S5P_CIIMGCPT_IMGCPTEN_SC);
- writel(cfg, dev->regs + S5P_CIIMGCPT);
-}
-
-/**
- * fimc_hw_set_dma_seq - configure output DMA buffer sequence
- * @mask: each bit corresponds to one of 32 output buffer registers set
- * 1 to include buffer in the sequence, 0 to disable
- *
- * This function mask output DMA ring buffers, i.e. it allows to configure
- * which of the output buffer address registers will be used by the DMA
- * engine.
- */
-static inline void fimc_hw_set_dma_seq(struct fimc_dev *dev, u32 mask)
-{
- writel(mask, dev->regs + S5P_CIFCNTSEQ);
-}
-
static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
enum v4l2_buf_type type)
{
@@ -665,48 +611,6 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
return frame;
}
-/* Return an index to the buffer actually being written. */
-static inline u32 fimc_hw_get_frame_index(struct fimc_dev *dev)
-{
- u32 reg;
-
- if (dev->variant->has_cistatus2) {
- reg = readl(dev->regs + S5P_CISTATUS2) & 0x3F;
- return reg > 0 ? --reg : reg;
- } else {
- reg = readl(dev->regs + S5P_CISTATUS);
- return (reg & S5P_CISTATUS_FRAMECNT_MASK) >>
- S5P_CISTATUS_FRAMECNT_SHIFT;
- }
-}
-
-/* -----------------------------------------------------*/
-/* fimc-reg.c */
-void fimc_hw_reset(struct fimc_dev *fimc);
-void fimc_hw_set_rotation(struct fimc_ctx *ctx);
-void fimc_hw_set_target_format(struct fimc_ctx *ctx);
-void fimc_hw_set_out_dma(struct fimc_ctx *ctx);
-void fimc_hw_en_lastirq(struct fimc_dev *fimc, int enable);
-void fimc_hw_en_irq(struct fimc_dev *fimc, int enable);
-void fimc_hw_set_prescaler(struct fimc_ctx *ctx);
-void fimc_hw_set_mainscaler(struct fimc_ctx *ctx);
-void fimc_hw_en_capture(struct fimc_ctx *ctx);
-void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active);
-void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx);
-void fimc_hw_set_in_dma(struct fimc_ctx *ctx);
-void fimc_hw_set_input_path(struct fimc_ctx *ctx);
-void fimc_hw_set_output_path(struct fimc_ctx *ctx);
-void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *paddr);
-void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *paddr,
- int index);
-int fimc_hw_set_camera_source(struct fimc_dev *fimc,
- struct s5p_fimc_isp_info *cam);
-int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f);
-int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
- struct s5p_fimc_isp_info *cam);
-int fimc_hw_set_camera_type(struct fimc_dev *fimc,
- struct s5p_fimc_isp_info *cam);
-
/* -----------------------------------------------------*/
/* fimc-core.c */
int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv,
@@ -720,6 +624,7 @@ void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height,
struct v4l2_pix_format_mplane *pix);
struct fimc_fmt *fimc_find_format(const u32 *pixelformat, const u32 *mbus_code,
unsigned int mask, int index);
+struct fimc_fmt *fimc_get_format(unsigned int index);
int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh,
int dw, int dh, int rotation);
@@ -730,7 +635,7 @@ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb,
void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f);
void fimc_set_yuv_order(struct fimc_ctx *ctx);
void fimc_fill_frame(struct fimc_frame *frame, struct v4l2_format *f);
-void fimc_capture_irq_handler(struct fimc_dev *fimc, bool done);
+void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf);
int fimc_register_m2m_device(struct fimc_dev *fimc,
struct v4l2_device *v4l2_dev);
@@ -739,33 +644,18 @@ int fimc_register_driver(void);
void fimc_unregister_driver(void);
/* -----------------------------------------------------*/
+/* fimc-m2m.c */
+void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state);
+
+/* -----------------------------------------------------*/
/* fimc-capture.c */
-int fimc_register_capture_device(struct fimc_dev *fimc,
- struct v4l2_device *v4l2_dev);
-void fimc_unregister_capture_device(struct fimc_dev *fimc);
+int fimc_initialize_capture_subdev(struct fimc_dev *fimc);
+void fimc_unregister_capture_subdev(struct fimc_dev *fimc);
int fimc_capture_ctrls_create(struct fimc_dev *fimc);
-int fimc_vid_cap_buf_queue(struct fimc_dev *fimc,
- struct fimc_vid_buffer *fimc_vb);
void fimc_sensor_notify(struct v4l2_subdev *sd, unsigned int notification,
void *arg);
int fimc_capture_suspend(struct fimc_dev *fimc);
int fimc_capture_resume(struct fimc_dev *fimc);
-int fimc_capture_config_update(struct fimc_ctx *ctx);
-
-/* Locking: the caller holds fimc->slock */
-static inline void fimc_activate_capture(struct fimc_ctx *ctx)
-{
- fimc_hw_enable_scaler(ctx->fimc_dev, ctx->scaler.enabled);
- fimc_hw_en_capture(ctx);
-}
-
-static inline void fimc_deactivate_capture(struct fimc_dev *fimc)
-{
- fimc_hw_en_lastirq(fimc, true);
- fimc_hw_dis_capture(fimc);
- fimc_hw_enable_scaler(fimc, false);
- fimc_hw_en_lastirq(fimc, false);
-}
/*
* Buffer list manipulation functions. Must be called with fimc.slock held.
diff --git a/drivers/media/video/s5p-fimc/fimc-lite-reg.c b/drivers/media/video/s5p-fimc/fimc-lite-reg.c
new file mode 100644
index 000000000000..419adfb7cdf9
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/fimc-lite-reg.c
@@ -0,0 +1,300 @@
+/*
+ * Register interface file for EXYNOS FIMC-LITE (camera interface) driver
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@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.
+*/
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <media/s5p_fimc.h>
+
+#include "fimc-lite-reg.h"
+#include "fimc-lite.h"
+#include "fimc-core.h"
+
+#define FLITE_RESET_TIMEOUT 50 /* in ms */
+
+void flite_hw_reset(struct fimc_lite *dev)
+{
+ unsigned long end = jiffies + msecs_to_jiffies(FLITE_RESET_TIMEOUT);
+ u32 cfg;
+
+ cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+ cfg |= FLITE_REG_CIGCTRL_SWRST_REQ;
+ writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+
+ while (time_is_after_jiffies(end)) {
+ cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+ if (cfg & FLITE_REG_CIGCTRL_SWRST_RDY)
+ break;
+ usleep_range(1000, 5000);
+ }
+
+ cfg |= FLITE_REG_CIGCTRL_SWRST;
+ writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+}
+
+void flite_hw_clear_pending_irq(struct fimc_lite *dev)
+{
+ u32 cfg = readl(dev->regs + FLITE_REG_CISTATUS);
+ cfg &= ~FLITE_REG_CISTATUS_IRQ_CAM;
+ writel(cfg, dev->regs + FLITE_REG_CISTATUS);
+}
+
+u32 flite_hw_get_interrupt_source(struct fimc_lite *dev)
+{
+ u32 intsrc = readl(dev->regs + FLITE_REG_CISTATUS);
+ return intsrc & FLITE_REG_CISTATUS_IRQ_MASK;
+}
+
+void flite_hw_clear_last_capture_end(struct fimc_lite *dev)
+{
+
+ u32 cfg = readl(dev->regs + FLITE_REG_CISTATUS2);
+ cfg &= ~FLITE_REG_CISTATUS2_LASTCAPEND;
+ writel(cfg, dev->regs + FLITE_REG_CISTATUS2);
+}
+
+void flite_hw_set_interrupt_mask(struct fimc_lite *dev)
+{
+ u32 cfg, intsrc;
+
+ /* Select interrupts to be enabled for each output mode */
+ if (dev->out_path == FIMC_IO_DMA) {
+ intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN |
+ FLITE_REG_CIGCTRL_IRQ_LASTEN |
+ FLITE_REG_CIGCTRL_IRQ_STARTEN;
+ } else {
+ /* An output to the FIMC-IS */
+ intsrc = FLITE_REG_CIGCTRL_IRQ_OVFEN |
+ FLITE_REG_CIGCTRL_IRQ_LASTEN;
+ }
+
+ cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+ cfg |= FLITE_REG_CIGCTRL_IRQ_DISABLE_MASK;
+ cfg &= ~intsrc;
+ writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+}
+
+void flite_hw_capture_start(struct fimc_lite *dev)
+{
+ u32 cfg = readl(dev->regs + FLITE_REG_CIIMGCPT);
+ cfg |= FLITE_REG_CIIMGCPT_IMGCPTEN;
+ writel(cfg, dev->regs + FLITE_REG_CIIMGCPT);
+}
+
+void flite_hw_capture_stop(struct fimc_lite *dev)
+{
+ u32 cfg = readl(dev->regs + FLITE_REG_CIIMGCPT);
+ cfg &= ~FLITE_REG_CIIMGCPT_IMGCPTEN;
+ writel(cfg, dev->regs + FLITE_REG_CIIMGCPT);
+}
+
+/*
+ * Test pattern (color bars) enable/disable. External sensor
+ * pixel clock must be active for the test pattern to work.
+ */
+void flite_hw_set_test_pattern(struct fimc_lite *dev, bool on)
+{
+ u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+ if (on)
+ cfg |= FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR;
+ else
+ cfg &= ~FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR;
+ writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+}
+
+static const u32 src_pixfmt_map[8][3] = {
+ { V4L2_MBUS_FMT_YUYV8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR,
+ FLITE_REG_CIGCTRL_YUV422_1P },
+ { V4L2_MBUS_FMT_YVYU8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB,
+ FLITE_REG_CIGCTRL_YUV422_1P },
+ { V4L2_MBUS_FMT_UYVY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY,
+ FLITE_REG_CIGCTRL_YUV422_1P },
+ { V4L2_MBUS_FMT_VYUY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY,
+ FLITE_REG_CIGCTRL_YUV422_1P },
+ { V4L2_PIX_FMT_SGRBG8, 0, FLITE_REG_CIGCTRL_RAW8 },
+ { V4L2_PIX_FMT_SGRBG10, 0, FLITE_REG_CIGCTRL_RAW10 },
+ { V4L2_PIX_FMT_SGRBG12, 0, FLITE_REG_CIGCTRL_RAW12 },
+ { V4L2_MBUS_FMT_JPEG_1X8, 0, FLITE_REG_CIGCTRL_USER(1) },
+};
+
+/* Set camera input pixel format and resolution */
+void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f)
+{
+ enum v4l2_mbus_pixelcode pixelcode = dev->fmt->mbus_code;
+ unsigned int i = ARRAY_SIZE(src_pixfmt_map);
+ u32 cfg;
+
+ while (i-- >= 0) {
+ if (src_pixfmt_map[i][0] == pixelcode)
+ break;
+ }
+
+ if (i == 0 && src_pixfmt_map[i][0] != pixelcode) {
+ v4l2_err(dev->vfd,
+ "Unsupported pixel code, falling back to %#08x\n",
+ src_pixfmt_map[i][0]);
+ }
+
+ cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+ cfg &= ~FLITE_REG_CIGCTRL_FMT_MASK;
+ cfg |= src_pixfmt_map[i][2];
+ writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+
+ cfg = readl(dev->regs + FLITE_REG_CISRCSIZE);
+ cfg &= ~(FLITE_REG_CISRCSIZE_ORDER422_MASK |
+ FLITE_REG_CISRCSIZE_SIZE_CAM_MASK);
+ cfg |= (f->f_width << 16) | f->f_height;
+ cfg |= src_pixfmt_map[i][1];
+ writel(cfg, dev->regs + FLITE_REG_CISRCSIZE);
+}
+
+/* Set the camera host input window offsets (cropping) */
+void flite_hw_set_window_offset(struct fimc_lite *dev, struct flite_frame *f)
+{
+ u32 hoff2, voff2;
+ u32 cfg;
+
+ cfg = readl(dev->regs + FLITE_REG_CIWDOFST);
+ cfg &= ~FLITE_REG_CIWDOFST_OFST_MASK;
+ cfg |= (f->rect.left << 16) | f->rect.top;
+ cfg |= FLITE_REG_CIWDOFST_WINOFSEN;
+ writel(cfg, dev->regs + FLITE_REG_CIWDOFST);
+
+ hoff2 = f->f_width - f->rect.width - f->rect.left;
+ voff2 = f->f_height - f->rect.height - f->rect.top;
+
+ cfg = (hoff2 << 16) | voff2;
+ writel(cfg, dev->regs + FLITE_REG_CIWDOFST2);
+}
+
+/* Select camera port (A, B) */
+static void flite_hw_set_camera_port(struct fimc_lite *dev, int id)
+{
+ u32 cfg = readl(dev->regs + FLITE_REG_CIGENERAL);
+ if (id == 0)
+ cfg &= ~FLITE_REG_CIGENERAL_CAM_B;
+ else
+ cfg |= FLITE_REG_CIGENERAL_CAM_B;
+ writel(cfg, dev->regs + FLITE_REG_CIGENERAL);
+}
+
+/* Select serial or parallel bus, camera port (A,B) and set signals polarity */
+void flite_hw_set_camera_bus(struct fimc_lite *dev,
+ struct s5p_fimc_isp_info *s_info)
+{
+ u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+ unsigned int flags = s_info->flags;
+
+ if (s_info->bus_type != FIMC_MIPI_CSI2) {
+ cfg &= ~(FLITE_REG_CIGCTRL_SELCAM_MIPI |
+ FLITE_REG_CIGCTRL_INVPOLPCLK |
+ FLITE_REG_CIGCTRL_INVPOLVSYNC |
+ FLITE_REG_CIGCTRL_INVPOLHREF);
+
+ if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
+ cfg |= FLITE_REG_CIGCTRL_INVPOLPCLK;
+
+ if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+ cfg |= FLITE_REG_CIGCTRL_INVPOLVSYNC;
+
+ if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+ cfg |= FLITE_REG_CIGCTRL_INVPOLHREF;
+ } else {
+ cfg |= FLITE_REG_CIGCTRL_SELCAM_MIPI;
+ }
+
+ writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+
+ flite_hw_set_camera_port(dev, s_info->mux_id);
+}
+
+void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f)
+{
+ static const u32 pixcode[4][2] = {
+ { V4L2_MBUS_FMT_YUYV8_2X8, FLITE_REG_CIODMAFMT_YCBYCR },
+ { V4L2_MBUS_FMT_YVYU8_2X8, FLITE_REG_CIODMAFMT_YCRYCB },
+ { V4L2_MBUS_FMT_UYVY8_2X8, FLITE_REG_CIODMAFMT_CBYCRY },
+ { V4L2_MBUS_FMT_VYUY8_2X8, FLITE_REG_CIODMAFMT_CRYCBY },
+ };
+ u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT);
+ unsigned int i = ARRAY_SIZE(pixcode);
+
+ while (i-- >= 0)
+ if (pixcode[i][0] == dev->fmt->mbus_code)
+ break;
+ cfg &= ~FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK;
+ writel(cfg | pixcode[i][1], dev->regs + FLITE_REG_CIODMAFMT);
+}
+
+void flite_hw_set_dma_window(struct fimc_lite *dev, struct flite_frame *f)
+{
+ u32 cfg;
+
+ /* Maximum output pixel size */
+ cfg = readl(dev->regs + FLITE_REG_CIOCAN);
+ cfg &= ~FLITE_REG_CIOCAN_MASK;
+ cfg = (f->f_height << 16) | f->f_width;
+ writel(cfg, dev->regs + FLITE_REG_CIOCAN);
+
+ /* DMA offsets */
+ cfg = readl(dev->regs + FLITE_REG_CIOOFF);
+ cfg &= ~FLITE_REG_CIOOFF_MASK;
+ cfg |= (f->rect.top << 16) | f->rect.left;
+ writel(cfg, dev->regs + FLITE_REG_CIOOFF);
+}
+
+/* Enable/disable output DMA, set output pixel size and offsets (composition) */
+void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f,
+ bool enable)
+{
+ u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL);
+
+ if (!enable) {
+ cfg |= FLITE_REG_CIGCTRL_ODMA_DISABLE;
+ writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+ return;
+ }
+
+ cfg &= ~FLITE_REG_CIGCTRL_ODMA_DISABLE;
+ writel(cfg, dev->regs + FLITE_REG_CIGCTRL);
+
+ flite_hw_set_out_order(dev, f);
+ flite_hw_set_dma_window(dev, f);
+}
+
+void flite_hw_dump_regs(struct fimc_lite *dev, const char *label)
+{
+ struct {
+ u32 offset;
+ const char * const name;
+ } registers[] = {
+ { 0x00, "CISRCSIZE" },
+ { 0x04, "CIGCTRL" },
+ { 0x08, "CIIMGCPT" },
+ { 0x0c, "CICPTSEQ" },
+ { 0x10, "CIWDOFST" },
+ { 0x14, "CIWDOFST2" },
+ { 0x18, "CIODMAFMT" },
+ { 0x20, "CIOCAN" },
+ { 0x24, "CIOOFF" },
+ { 0x30, "CIOSA" },
+ { 0x40, "CISTATUS" },
+ { 0x44, "CISTATUS2" },
+ { 0xf0, "CITHOLD" },
+ { 0xfc, "CIGENERAL" },
+ };
+ u32 i;
+
+ pr_info("--- %s ---\n", label);
+ for (i = 0; i < ARRAY_SIZE(registers); i++) {
+ u32 cfg = readl(dev->regs + registers[i].offset);
+ pr_info("%s: %s:\t0x%08x\n", __func__, registers[i].name, cfg);
+ }
+}
diff --git a/drivers/media/video/s5p-fimc/fimc-lite-reg.h b/drivers/media/video/s5p-fimc/fimc-lite-reg.h
new file mode 100644
index 000000000000..adb9e9e6f3c2
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/fimc-lite-reg.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ *
+ * 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 FIMC_LITE_REG_H_
+#define FIMC_LITE_REG_H_
+
+#include "fimc-lite.h"
+
+/* Camera Source size */
+#define FLITE_REG_CISRCSIZE 0x00
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR (0 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB (1 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY (2 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY (3 << 14)
+#define FLITE_REG_CISRCSIZE_ORDER422_MASK (0x3 << 14)
+#define FLITE_REG_CISRCSIZE_SIZE_CAM_MASK (0x3fff << 16 | 0x3fff)
+
+/* Global control */
+#define FLITE_REG_CIGCTRL 0x04
+#define FLITE_REG_CIGCTRL_YUV422_1P (0x1e << 24)
+#define FLITE_REG_CIGCTRL_RAW8 (0x2a << 24)
+#define FLITE_REG_CIGCTRL_RAW10 (0x2b << 24)
+#define FLITE_REG_CIGCTRL_RAW12 (0x2c << 24)
+#define FLITE_REG_CIGCTRL_RAW14 (0x2d << 24)
+/* User defined formats. x = 0...15 */
+#define FLITE_REG_CIGCTRL_USER(x) ((0x30 + x - 1) << 24)
+#define FLITE_REG_CIGCTRL_FMT_MASK (0x3f << 24)
+#define FLITE_REG_CIGCTRL_SHADOWMASK_DISABLE (1 << 21)
+#define FLITE_REG_CIGCTRL_ODMA_DISABLE (1 << 20)
+#define FLITE_REG_CIGCTRL_SWRST_REQ (1 << 19)
+#define FLITE_REG_CIGCTRL_SWRST_RDY (1 << 18)
+#define FLITE_REG_CIGCTRL_SWRST (1 << 17)
+#define FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR (1 << 15)
+#define FLITE_REG_CIGCTRL_INVPOLPCLK (1 << 14)
+#define FLITE_REG_CIGCTRL_INVPOLVSYNC (1 << 13)
+#define FLITE_REG_CIGCTRL_INVPOLHREF (1 << 12)
+/* Interrupts mask bits (1 disables an interrupt) */
+#define FLITE_REG_CIGCTRL_IRQ_LASTEN (1 << 8)
+#define FLITE_REG_CIGCTRL_IRQ_ENDEN (1 << 7)
+#define FLITE_REG_CIGCTRL_IRQ_STARTEN (1 << 6)
+#define FLITE_REG_CIGCTRL_IRQ_OVFEN (1 << 5)
+#define FLITE_REG_CIGCTRL_IRQ_DISABLE_MASK (0xf << 5)
+#define FLITE_REG_CIGCTRL_SELCAM_MIPI (1 << 3)
+
+/* Image Capture Enable */
+#define FLITE_REG_CIIMGCPT 0x08
+#define FLITE_REG_CIIMGCPT_IMGCPTEN (1 << 31)
+#define FLITE_REG_CIIMGCPT_CPT_FREN (1 << 25)
+#define FLITE_REG_CIIMGCPT_CPT_MOD_FRCNT (1 << 18)
+#define FLITE_REG_CIIMGCPT_CPT_MOD_FREN (0 << 18)
+
+/* Capture Sequence */
+#define FLITE_REG_CICPTSEQ 0x0c
+
+/* Camera Window Offset */
+#define FLITE_REG_CIWDOFST 0x10
+#define FLITE_REG_CIWDOFST_WINOFSEN (1 << 31)
+#define FLITE_REG_CIWDOFST_CLROVIY (1 << 31)
+#define FLITE_REG_CIWDOFST_CLROVFICB (1 << 15)
+#define FLITE_REG_CIWDOFST_CLROVFICR (1 << 14)
+#define FLITE_REG_CIWDOFST_OFST_MASK ((0x1fff << 16) | 0x1fff)
+
+/* Camera Window Offset2 */
+#define FLITE_REG_CIWDOFST2 0x14
+
+/* Camera Output DMA Format */
+#define FLITE_REG_CIODMAFMT 0x18
+#define FLITE_REG_CIODMAFMT_RAW_CON (1 << 15)
+#define FLITE_REG_CIODMAFMT_PACK12 (1 << 14)
+#define FLITE_REG_CIODMAFMT_CRYCBY (0 << 4)
+#define FLITE_REG_CIODMAFMT_CBYCRY (1 << 4)
+#define FLITE_REG_CIODMAFMT_YCRYCB (2 << 4)
+#define FLITE_REG_CIODMAFMT_YCBYCR (3 << 4)
+#define FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK (0x3 << 4)
+
+/* Camera Output Canvas */
+#define FLITE_REG_CIOCAN 0x20
+#define FLITE_REG_CIOCAN_MASK ((0x3fff << 16) | 0x3fff)
+
+/* Camera Output DMA Offset */
+#define FLITE_REG_CIOOFF 0x24
+#define FLITE_REG_CIOOFF_MASK ((0x3fff << 16) | 0x3fff)
+
+/* Camera Output DMA Start Address */
+#define FLITE_REG_CIOSA 0x30
+
+/* Camera Status */
+#define FLITE_REG_CISTATUS 0x40
+#define FLITE_REG_CISTATUS_MIPI_VVALID (1 << 22)
+#define FLITE_REG_CISTATUS_MIPI_HVALID (1 << 21)
+#define FLITE_REG_CISTATUS_MIPI_DVALID (1 << 20)
+#define FLITE_REG_CISTATUS_ITU_VSYNC (1 << 14)
+#define FLITE_REG_CISTATUS_ITU_HREFF (1 << 13)
+#define FLITE_REG_CISTATUS_OVFIY (1 << 10)
+#define FLITE_REG_CISTATUS_OVFICB (1 << 9)
+#define FLITE_REG_CISTATUS_OVFICR (1 << 8)
+#define FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW (1 << 7)
+#define FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND (1 << 6)
+#define FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART (1 << 5)
+#define FLITE_REG_CISTATUS_IRQ_SRC_FRMEND (1 << 4)
+#define FLITE_REG_CISTATUS_IRQ_CAM (1 << 0)
+#define FLITE_REG_CISTATUS_IRQ_MASK (0xf << 4)
+
+/* Camera Status2 */
+#define FLITE_REG_CISTATUS2 0x44
+#define FLITE_REG_CISTATUS2_LASTCAPEND (1 << 1)
+#define FLITE_REG_CISTATUS2_FRMEND (1 << 0)
+
+/* Qos Threshold */
+#define FLITE_REG_CITHOLD 0xf0
+#define FLITE_REG_CITHOLD_W_QOS_EN (1 << 30)
+
+/* Camera General Purpose */
+#define FLITE_REG_CIGENERAL 0xfc
+/* b0: 1 - camera B, 0 - camera A */
+#define FLITE_REG_CIGENERAL_CAM_B (1 << 0)
+
+/* ----------------------------------------------------------------------------
+ * Function declarations
+ */
+void flite_hw_reset(struct fimc_lite *dev);
+void flite_hw_clear_pending_irq(struct fimc_lite *dev);
+u32 flite_hw_get_interrupt_source(struct fimc_lite *dev);
+void flite_hw_clear_last_capture_end(struct fimc_lite *dev);
+void flite_hw_set_interrupt_mask(struct fimc_lite *dev);
+void flite_hw_capture_start(struct fimc_lite *dev);
+void flite_hw_capture_stop(struct fimc_lite *dev);
+void flite_hw_set_camera_bus(struct fimc_lite *dev,
+ struct s5p_fimc_isp_info *s_info);
+void flite_hw_set_camera_polarity(struct fimc_lite *dev,
+ struct s5p_fimc_isp_info *cam);
+void flite_hw_set_window_offset(struct fimc_lite *dev, struct flite_frame *f);
+void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f);
+
+void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f,
+ bool enable);
+void flite_hw_set_dma_window(struct fimc_lite *dev, struct flite_frame *f);
+void flite_hw_set_test_pattern(struct fimc_lite *dev, bool on);
+void flite_hw_dump_regs(struct fimc_lite *dev, const char *label);
+
+static inline void flite_hw_set_output_addr(struct fimc_lite *dev, u32 paddr)
+{
+ writel(paddr, dev->regs + FLITE_REG_CIOSA);
+}
+#endif /* FIMC_LITE_REG_H */
diff --git a/drivers/media/video/s5p-fimc/fimc-lite.c b/drivers/media/video/s5p-fimc/fimc-lite.c
new file mode 100644
index 000000000000..400d701aef04
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/fimc-lite.c
@@ -0,0 +1,1576 @@
+/*
+ * Samsung EXYNOS FIMC-LITE (camera host interface) driver
+*
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@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.
+ */
+#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
+
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "fimc-mdevice.h"
+#include "fimc-core.h"
+#include "fimc-lite-reg.h"
+
+static int debug;
+module_param(debug, int, 0644);
+
+static const struct fimc_fmt fimc_lite_formats[] = {
+ {
+ .name = "YUV 4:2:2 packed, YCbYCr",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = { 16 },
+ .color = FIMC_FMT_YCBYCR422,
+ .memplanes = 1,
+ .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ }, {
+ .name = "YUV 4:2:2 packed, CbYCrY",
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .depth = { 16 },
+ .color = FIMC_FMT_CBYCRY422,
+ .memplanes = 1,
+ .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
+ }, {
+ .name = "YUV 4:2:2 packed, CrYCbY",
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .depth = { 16 },
+ .color = FIMC_FMT_CRYCBY422,
+ .memplanes = 1,
+ .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8,
+ }, {
+ .name = "YUV 4:2:2 packed, YCrYCb",
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .depth = { 16 },
+ .color = FIMC_FMT_YCRYCB422,
+ .memplanes = 1,
+ .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8,
+ }, {
+ .name = "RAW8 (GRBG)",
+ .fourcc = V4L2_PIX_FMT_SGRBG8,
+ .depth = { 8 },
+ .color = FIMC_FMT_RAW8,
+ .memplanes = 1,
+ .mbus_code = V4L2_MBUS_FMT_SGRBG8_1X8,
+ }, {
+ .name = "RAW10 (GRBG)",
+ .fourcc = V4L2_PIX_FMT_SGRBG10,
+ .depth = { 10 },
+ .color = FIMC_FMT_RAW10,
+ .memplanes = 1,
+ .mbus_code = V4L2_MBUS_FMT_SGRBG10_1X10,
+ }, {
+ .name = "RAW12 (GRBG)",
+ .fourcc = V4L2_PIX_FMT_SGRBG12,
+ .depth = { 12 },
+ .color = FIMC_FMT_RAW12,
+ .memplanes = 1,
+ .mbus_code = V4L2_MBUS_FMT_SGRBG12_1X12,
+ },
+};
+
+/**
+ * fimc_lite_find_format - lookup fimc color format by fourcc or media bus code
+ * @pixelformat: fourcc to match, ignored if null
+ * @mbus_code: media bus code to match, ignored if null
+ * @index: index to the fimc_lite_formats array, ignored if negative
+ */
+static const struct fimc_fmt *fimc_lite_find_format(const u32 *pixelformat,
+ const u32 *mbus_code, int index)
+{
+ const struct fimc_fmt *fmt, *def_fmt = NULL;
+ unsigned int i;
+ int id = 0;
+
+ if (index >= (int)ARRAY_SIZE(fimc_lite_formats))
+ return NULL;
+
+ for (i = 0; i < ARRAY_SIZE(fimc_lite_formats); ++i) {
+ fmt = &fimc_lite_formats[i];
+ if (pixelformat && fmt->fourcc == *pixelformat)
+ return fmt;
+ if (mbus_code && fmt->mbus_code == *mbus_code)
+ return fmt;
+ if (index == id)
+ def_fmt = fmt;
+ id++;
+ }
+ return def_fmt;
+}
+
+static int fimc_lite_hw_init(struct fimc_lite *fimc)
+{
+ struct fimc_pipeline *pipeline = &fimc->pipeline;
+ struct fimc_sensor_info *sensor;
+ unsigned long flags;
+
+ if (pipeline->subdevs[IDX_SENSOR] == NULL)
+ return -ENXIO;
+
+ if (fimc->fmt == NULL)
+ return -EINVAL;
+
+ sensor = v4l2_get_subdev_hostdata(pipeline->subdevs[IDX_SENSOR]);
+ spin_lock_irqsave(&fimc->slock, flags);
+
+ flite_hw_set_camera_bus(fimc, sensor->pdata);
+ flite_hw_set_source_format(fimc, &fimc->inp_frame);
+ flite_hw_set_window_offset(fimc, &fimc->inp_frame);
+ flite_hw_set_output_dma(fimc, &fimc->out_frame, true);
+ flite_hw_set_interrupt_mask(fimc);
+ flite_hw_set_test_pattern(fimc, fimc->test_pattern->val);
+
+ if (debug > 0)
+ flite_hw_dump_regs(fimc, __func__);
+
+ spin_unlock_irqrestore(&fimc->slock, flags);
+ return 0;
+}
+
+/*
+ * Reinitialize the driver so it is ready to start the streaming again.
+ * Set fimc->state to indicate stream off and the hardware shut down state.
+ * If not suspending (@suspend is false), return any buffers to videobuf2.
+ * Otherwise put any owned buffers onto the pending buffers queue, so they
+ * can be re-spun when the device is being resumed. Also perform FIMC
+ * software reset and disable streaming on the whole pipeline if required.
+ */
+static int fimc_lite_reinit(struct fimc_lite *fimc, bool suspend)
+{
+ struct flite_buffer *buf;
+ unsigned long flags;
+ bool streaming;
+
+ spin_lock_irqsave(&fimc->slock, flags);
+ streaming = fimc->state & (1 << ST_SENSOR_STREAM);
+
+ fimc->state &= ~(1 << ST_FLITE_RUN | 1 << ST_FLITE_OFF |
+ 1 << ST_FLITE_STREAM | 1 << ST_SENSOR_STREAM);
+ if (suspend)
+ fimc->state |= (1 << ST_FLITE_SUSPENDED);
+ else
+ fimc->state &= ~(1 << ST_FLITE_PENDING |
+ 1 << ST_FLITE_SUSPENDED);
+
+ /* Release unused buffers */
+ while (!suspend && !list_empty(&fimc->pending_buf_q)) {
+ buf = fimc_lite_pending_queue_pop(fimc);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ }
+ /* If suspending put unused buffers onto pending queue */
+ while (!list_empty(&fimc->active_buf_q)) {
+ buf = fimc_lite_active_queue_pop(fimc);
+ if (suspend)
+ fimc_lite_pending_queue_add(fimc, buf);
+ else
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ }
+
+ spin_unlock_irqrestore(&fimc->slock, flags);
+
+ flite_hw_reset(fimc);
+
+ if (!streaming)
+ return 0;
+
+ return fimc_pipeline_s_stream(&fimc->pipeline, 0);
+}
+
+static int fimc_lite_stop_capture(struct fimc_lite *fimc, bool suspend)
+{
+ unsigned long flags;
+
+ if (!fimc_lite_active(fimc))
+ return 0;
+
+ spin_lock_irqsave(&fimc->slock, flags);
+ set_bit(ST_FLITE_OFF, &fimc->state);
+ flite_hw_capture_stop(fimc);
+ spin_unlock_irqrestore(&fimc->slock, flags);
+
+ wait_event_timeout(fimc->irq_queue,
+ !test_bit(ST_FLITE_OFF, &fimc->state),
+ (2*HZ/10)); /* 200 ms */
+
+ return fimc_lite_reinit(fimc, suspend);
+}
+
+/* Must be called with fimc.slock spinlock held. */
+static void fimc_lite_config_update(struct fimc_lite *fimc)
+{
+ flite_hw_set_window_offset(fimc, &fimc->inp_frame);
+ flite_hw_set_dma_window(fimc, &fimc->out_frame);
+ flite_hw_set_test_pattern(fimc, fimc->test_pattern->val);
+ clear_bit(ST_FLITE_CONFIG, &fimc->state);
+}
+
+static irqreturn_t flite_irq_handler(int irq, void *priv)
+{
+ struct fimc_lite *fimc = priv;
+ struct flite_buffer *vbuf;
+ unsigned long flags;
+ struct timeval *tv;
+ struct timespec ts;
+ u32 intsrc;
+
+ spin_lock_irqsave(&fimc->slock, flags);
+
+ intsrc = flite_hw_get_interrupt_source(fimc);
+ flite_hw_clear_pending_irq(fimc);
+
+ if (test_and_clear_bit(ST_FLITE_OFF, &fimc->state)) {
+ wake_up(&fimc->irq_queue);
+ goto done;
+ }
+
+ if (intsrc & FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW) {
+ clear_bit(ST_FLITE_RUN, &fimc->state);
+ fimc->events.data_overflow++;
+ }
+
+ if (intsrc & FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND) {
+ flite_hw_clear_last_capture_end(fimc);
+ clear_bit(ST_FLITE_STREAM, &fimc->state);
+ wake_up(&fimc->irq_queue);
+ }
+
+ if (fimc->out_path != FIMC_IO_DMA)
+ goto done;
+
+ if ((intsrc & FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART) &&
+ test_bit(ST_FLITE_RUN, &fimc->state) &&
+ !list_empty(&fimc->active_buf_q) &&
+ !list_empty(&fimc->pending_buf_q)) {
+ vbuf = fimc_lite_active_queue_pop(fimc);
+ ktime_get_ts(&ts);
+ tv = &vbuf->vb.v4l2_buf.timestamp;
+ tv->tv_sec = ts.tv_sec;
+ tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+ vbuf->vb.v4l2_buf.sequence = fimc->frame_count++;
+ vb2_buffer_done(&vbuf->vb, VB2_BUF_STATE_DONE);
+
+ vbuf = fimc_lite_pending_queue_pop(fimc);
+ flite_hw_set_output_addr(fimc, vbuf->paddr);
+ fimc_lite_active_queue_add(fimc, vbuf);
+ }
+
+ if (test_bit(ST_FLITE_CONFIG, &fimc->state))
+ fimc_lite_config_update(fimc);
+
+ if (list_empty(&fimc->pending_buf_q)) {
+ flite_hw_capture_stop(fimc);
+ clear_bit(ST_FLITE_STREAM, &fimc->state);
+ }
+done:
+ set_bit(ST_FLITE_RUN, &fimc->state);
+ spin_unlock_irqrestore(&fimc->slock, flags);
+ return IRQ_HANDLED;
+}
+
+static int start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct fimc_lite *fimc = q->drv_priv;
+ int ret;
+
+ fimc->frame_count = 0;
+
+ ret = fimc_lite_hw_init(fimc);
+ if (ret) {
+ fimc_lite_reinit(fimc, false);
+ return ret;
+ }
+
+ set_bit(ST_FLITE_PENDING, &fimc->state);
+
+ if (!list_empty(&fimc->active_buf_q) &&
+ !test_and_set_bit(ST_FLITE_STREAM, &fimc->state)) {
+ flite_hw_capture_start(fimc);
+
+ if (!test_and_set_bit(ST_SENSOR_STREAM, &fimc->state))
+ fimc_pipeline_s_stream(&fimc->pipeline, 1);
+ }
+ if (debug > 0)
+ flite_hw_dump_regs(fimc, __func__);
+
+ return 0;
+}
+
+static int stop_streaming(struct vb2_queue *q)
+{
+ struct fimc_lite *fimc = q->drv_priv;
+
+ if (!fimc_lite_active(fimc))
+ return -EINVAL;
+
+ return fimc_lite_stop_capture(fimc, false);
+}
+
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[], void *allocators[])
+{
+ const struct v4l2_pix_format_mplane *pixm = NULL;
+ struct fimc_lite *fimc = vq->drv_priv;
+ struct flite_frame *frame = &fimc->out_frame;
+ const struct fimc_fmt *fmt = fimc->fmt;
+ unsigned long wh;
+ int i;
+
+ if (pfmt) {
+ pixm = &pfmt->fmt.pix_mp;
+ fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, -1);
+ wh = pixm->width * pixm->height;
+ } else {
+ wh = frame->f_width * frame->f_height;
+ }
+
+ if (fmt == NULL)
+ return -EINVAL;
+
+ *num_planes = fmt->memplanes;
+
+ for (i = 0; i < fmt->memplanes; i++) {
+ unsigned int size = (wh * fmt->depth[i]) / 8;
+ if (pixm)
+ sizes[i] = max(size, pixm->plane_fmt[i].sizeimage);
+ else
+ sizes[i] = size;
+ allocators[i] = fimc->alloc_ctx;
+ }
+
+ return 0;
+}
+
+static int buffer_prepare(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct fimc_lite *fimc = vq->drv_priv;
+ int i;
+
+ if (fimc->fmt == NULL)
+ return -EINVAL;
+
+ for (i = 0; i < fimc->fmt->memplanes; i++) {
+ unsigned long size = fimc->payload[i];
+
+ if (vb2_plane_size(vb, i) < size) {
+ v4l2_err(fimc->vfd,
+ "User buffer too small (%ld < %ld)\n",
+ vb2_plane_size(vb, i), size);
+ return -EINVAL;
+ }
+ vb2_set_plane_payload(vb, i, size);
+ }
+
+ return 0;
+}
+
+static void buffer_queue(struct vb2_buffer *vb)
+{
+ struct flite_buffer *buf
+ = container_of(vb, struct flite_buffer, vb);
+ struct fimc_lite *fimc = vb2_get_drv_priv(vb->vb2_queue);
+ unsigned long flags;
+
+ spin_lock_irqsave(&fimc->slock, flags);
+ buf->paddr = vb2_dma_contig_plane_dma_addr(vb, 0);
+
+ if (!test_bit(ST_FLITE_SUSPENDED, &fimc->state) &&
+ !test_bit(ST_FLITE_STREAM, &fimc->state) &&
+ list_empty(&fimc->active_buf_q)) {
+ flite_hw_set_output_addr(fimc, buf->paddr);
+ fimc_lite_active_queue_add(fimc, buf);
+ } else {
+ fimc_lite_pending_queue_add(fimc, buf);
+ }
+
+ if (vb2_is_streaming(&fimc->vb_queue) &&
+ !list_empty(&fimc->pending_buf_q) &&
+ !test_and_set_bit(ST_FLITE_STREAM, &fimc->state)) {
+ flite_hw_capture_start(fimc);
+ spin_unlock_irqrestore(&fimc->slock, flags);
+
+ if (!test_and_set_bit(ST_SENSOR_STREAM, &fimc->state))
+ fimc_pipeline_s_stream(&fimc->pipeline, 1);
+ return;
+ }
+ spin_unlock_irqrestore(&fimc->slock, flags);
+}
+
+static void fimc_lock(struct vb2_queue *vq)
+{
+ struct fimc_lite *fimc = vb2_get_drv_priv(vq);
+ mutex_lock(&fimc->lock);
+}
+
+static void fimc_unlock(struct vb2_queue *vq)
+{
+ struct fimc_lite *fimc = vb2_get_drv_priv(vq);
+ mutex_unlock(&fimc->lock);
+}
+
+static const struct vb2_ops fimc_lite_qops = {
+ .queue_setup = queue_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .wait_prepare = fimc_unlock,
+ .wait_finish = fimc_lock,
+ .start_streaming = start_streaming,
+ .stop_streaming = stop_streaming,
+};
+
+static void fimc_lite_clear_event_counters(struct fimc_lite *fimc)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&fimc->slock, flags);
+ memset(&fimc->events, 0, sizeof(fimc->events));
+ spin_unlock_irqrestore(&fimc->slock, flags);
+}
+
+static int fimc_lite_open(struct file *file)
+{
+ struct fimc_lite *fimc = video_drvdata(file);
+ int ret = v4l2_fh_open(file);
+
+ if (ret)
+ return ret;
+
+ set_bit(ST_FLITE_IN_USE, &fimc->state);
+ pm_runtime_get_sync(&fimc->pdev->dev);
+
+ if (++fimc->ref_count != 1 || fimc->out_path != FIMC_IO_DMA)
+ return ret;
+
+ ret = fimc_pipeline_initialize(&fimc->pipeline, &fimc->vfd->entity,
+ true);
+ if (ret < 0) {
+ v4l2_err(fimc->vfd, "Video pipeline initialization failed\n");
+ pm_runtime_put_sync(&fimc->pdev->dev);
+ fimc->ref_count--;
+ v4l2_fh_release(file);
+ clear_bit(ST_FLITE_IN_USE, &fimc->state);
+ }
+
+ fimc_lite_clear_event_counters(fimc);
+ return ret;
+}
+
+static int fimc_lite_close(struct file *file)
+{
+ struct fimc_lite *fimc = video_drvdata(file);
+
+ if (--fimc->ref_count == 0 && fimc->out_path == FIMC_IO_DMA) {
+ clear_bit(ST_FLITE_IN_USE, &fimc->state);
+ fimc_lite_stop_capture(fimc, false);
+ fimc_pipeline_shutdown(&fimc->pipeline);
+ clear_bit(ST_FLITE_SUSPENDED, &fimc->state);
+ }
+
+ pm_runtime_put(&fimc->pdev->dev);
+
+ if (fimc->ref_count == 0)
+ vb2_queue_release(&fimc->vb_queue);
+
+ return v4l2_fh_release(file);
+}
+
+static unsigned int fimc_lite_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct fimc_lite *fimc = video_drvdata(file);
+ return vb2_poll(&fimc->vb_queue, file, wait);
+}
+
+static int fimc_lite_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct fimc_lite *fimc = video_drvdata(file);
+ return vb2_mmap(&fimc->vb_queue, vma);
+}
+
+static const struct v4l2_file_operations fimc_lite_fops = {
+ .owner = THIS_MODULE,
+ .open = fimc_lite_open,
+ .release = fimc_lite_close,
+ .poll = fimc_lite_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = fimc_lite_mmap,
+};
+
+/*
+ * Format and crop negotiation helpers
+ */
+
+static const struct fimc_fmt *fimc_lite_try_format(struct fimc_lite *fimc,
+ u32 *width, u32 *height,
+ u32 *code, u32 *fourcc, int pad)
+{
+ struct flite_variant *variant = fimc->variant;
+ const struct fimc_fmt *fmt;
+
+ fmt = fimc_lite_find_format(fourcc, code, 0);
+ if (WARN_ON(!fmt))
+ return NULL;
+
+ if (code)
+ *code = fmt->mbus_code;
+ if (fourcc)
+ *fourcc = fmt->fourcc;
+
+ if (pad == FLITE_SD_PAD_SINK) {
+ v4l_bound_align_image(width, 8, variant->max_width,
+ ffs(variant->out_width_align) - 1,
+ height, 0, variant->max_height, 0, 0);
+ } else {
+ v4l_bound_align_image(width, 8, fimc->inp_frame.rect.width,
+ ffs(variant->out_width_align) - 1,
+ height, 0, fimc->inp_frame.rect.height,
+ 0, 0);
+ }
+
+ v4l2_dbg(1, debug, &fimc->subdev, "code: 0x%x, %dx%d\n",
+ code ? *code : 0, *width, *height);
+
+ return fmt;
+}
+
+static void fimc_lite_try_crop(struct fimc_lite *fimc, struct v4l2_rect *r)
+{
+ struct flite_frame *frame = &fimc->inp_frame;
+
+ v4l_bound_align_image(&r->width, 0, frame->f_width, 0,
+ &r->height, 0, frame->f_height, 0, 0);
+
+ /* Adjust left/top if cropping rectangle got out of bounds */
+ r->left = clamp_t(u32, r->left, 0, frame->f_width - r->width);
+ r->left = round_down(r->left, fimc->variant->win_hor_offs_align);
+ r->top = clamp_t(u32, r->top, 0, frame->f_height - r->height);
+
+ v4l2_dbg(1, debug, &fimc->subdev, "(%d,%d)/%dx%d, sink fmt: %dx%d",
+ r->left, r->top, r->width, r->height,
+ frame->f_width, frame->f_height);
+}
+
+static void fimc_lite_try_compose(struct fimc_lite *fimc, struct v4l2_rect *r)
+{
+ struct flite_frame *frame = &fimc->out_frame;
+ struct v4l2_rect *crop_rect = &fimc->inp_frame.rect;
+
+ /* Scaling is not supported so we enforce compose rectangle size
+ same as size of the sink crop rectangle. */
+ r->width = crop_rect->width;
+ r->height = crop_rect->height;
+
+ /* Adjust left/top if the composing rectangle got out of bounds */
+ r->left = clamp_t(u32, r->left, 0, frame->f_width - r->width);
+ r->left = round_down(r->left, fimc->variant->out_hor_offs_align);
+ r->top = clamp_t(u32, r->top, 0, fimc->out_frame.f_height - r->height);
+
+ v4l2_dbg(1, debug, &fimc->subdev, "(%d,%d)/%dx%d, source fmt: %dx%d",
+ r->left, r->top, r->width, r->height,
+ frame->f_width, frame->f_height);
+}
+
+/*
+ * Video node ioctl operations
+ */
+static int fimc_vidioc_querycap_capture(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strlcpy(cap->driver, FIMC_LITE_DRV_NAME, sizeof(cap->driver));
+ cap->bus_info[0] = 0;
+ cap->card[0] = 0;
+ cap->capabilities = V4L2_CAP_STREAMING;
+ return 0;
+}
+
+static int fimc_lite_enum_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ const struct fimc_fmt *fmt;
+
+ if (f->index >= ARRAY_SIZE(fimc_lite_formats))
+ return -EINVAL;
+
+ fmt = &fimc_lite_formats[f->index];
+ strlcpy(f->description, fmt->name, sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+
+ return 0;
+}
+
+static int fimc_lite_g_fmt_mplane(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct fimc_lite *fimc = video_drvdata(file);
+ struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
+ struct v4l2_plane_pix_format *plane_fmt = &pixm->plane_fmt[0];
+ struct flite_frame *frame = &fimc->out_frame;
+ const struct fimc_fmt *fmt = fimc->fmt;
+
+ plane_fmt->bytesperline = (frame->f_width * fmt->depth[0]) / 8;
+ plane_fmt->sizeimage = plane_fmt->bytesperline * frame->f_height;
+
+ pixm->num_planes = fmt->memplanes;
+ pixm->pixelformat = fmt->fourcc;
+ pixm->width = frame->f_width;
+ pixm->height = frame->f_height;
+ pixm->field = V4L2_FIELD_NONE;
+ pixm->colorspace = V4L2_COLORSPACE_JPEG;
+ return 0;
+}
+
+static int fimc_lite_try_fmt(struct fimc_lite *fimc,
+ struct v4l2_pix_format_mplane *pixm,
+ const struct fimc_fmt **ffmt)
+{
+ struct flite_variant *variant = fimc->variant;
+ u32 bpl = pixm->plane_fmt[0].bytesperline;
+ const struct fimc_fmt *fmt;
+
+ fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, 0);
+ if (WARN_ON(fmt == NULL))
+ return -EINVAL;
+ if (ffmt)
+ *ffmt = fmt;
+ v4l_bound_align_image(&pixm->width, 8, variant->max_width,
+ ffs(variant->out_width_align) - 1,
+ &pixm->height, 0, variant->max_height, 0, 0);
+
+ if ((bpl == 0 || ((bpl * 8) / fmt->depth[0]) < pixm->width))
+ pixm->plane_fmt[0].bytesperline = (pixm->width *
+ fmt->depth[0]) / 8;
+
+ if (pixm->plane_fmt[0].sizeimage == 0)
+ pixm->plane_fmt[0].sizeimage = (pixm->width * pixm->height *
+ fmt->depth[0]) / 8;
+ pixm->num_planes = fmt->memplanes;
+ pixm->pixelformat = fmt->fourcc;
+ pixm->colorspace = V4L2_COLORSPACE_JPEG;
+ pixm->field = V4L2_FIELD_NONE;
+ return 0;
+}
+
+static int fimc_lite_try_fmt_mplane(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct fimc_lite *fimc = video_drvdata(file);
+
+ return fimc_lite_try_fmt(fimc, &f->fmt.pix_mp, NULL);
+}
+
+static int fimc_lite_s_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp;
+ struct fimc_lite *fimc = video_drvdata(file);
+ struct flite_frame *frame = &fimc->out_frame;
+ const struct fimc_fmt *fmt = NULL;
+ int ret;
+
+ if (vb2_is_busy(&fimc->vb_queue))
+ return -EBUSY;
+
+ ret = fimc_lite_try_fmt(fimc, &f->fmt.pix_mp, &fmt);
+ if (ret < 0)
+ return ret;
+
+ fimc->fmt = fmt;
+ fimc->payload[0] = max((pixm->width * pixm->height * fmt->depth[0]) / 8,
+ pixm->plane_fmt[0].sizeimage);
+ frame->f_width = pixm->width;
+ frame->f_height = pixm->height;
+
+ return 0;
+}
+
+static int fimc_pipeline_validate(struct fimc_lite *fimc)
+{
+ struct v4l2_subdev *sd = &fimc->subdev;
+ struct v4l2_subdev_format sink_fmt, src_fmt;
+ struct media_pad *pad;
+ int ret;
+
+ while (1) {
+ /* Retrieve format at the sink pad */
+ pad = &sd->entity.pads[0];
+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
+ break;
+ /* Don't call FIMC subdev operation to avoid nested locking */
+ if (sd == &fimc->subdev) {
+ struct flite_frame *ff = &fimc->out_frame;
+ sink_fmt.format.width = ff->f_width;
+ sink_fmt.format.height = ff->f_height;
+ sink_fmt.format.code = fimc->fmt->mbus_code;
+ } else {
+ sink_fmt.pad = pad->index;
+ sink_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ ret = v4l2_subdev_call(sd, pad, get_fmt, NULL,
+ &sink_fmt);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return -EPIPE;
+ }
+ /* Retrieve format at the source pad */
+ pad = media_entity_remote_source(pad);
+ if (pad == NULL ||
+ media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ break;
+
+ sd = media_entity_to_v4l2_subdev(pad->entity);
+ src_fmt.pad = pad->index;
+ src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &src_fmt);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return -EPIPE;
+
+ if (src_fmt.format.width != sink_fmt.format.width ||
+ src_fmt.format.height != sink_fmt.format.height ||
+ src_fmt.format.code != sink_fmt.format.code)
+ return -EPIPE;
+ }
+ return 0;
+}
+
+static int fimc_lite_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct fimc_lite *fimc = video_drvdata(file);
+ struct v4l2_subdev *sensor = fimc->pipeline.subdevs[IDX_SENSOR];
+ struct fimc_pipeline *p = &fimc->pipeline;
+ int ret;
+
+ if (fimc_lite_active(fimc))
+ return -EBUSY;
+
+ media_entity_pipeline_start(&sensor->entity, p->m_pipeline);
+
+ ret = fimc_pipeline_validate(fimc);
+ if (ret) {
+ media_entity_pipeline_stop(&sensor->entity);
+ return ret;
+ }
+
+ return vb2_streamon(&fimc->vb_queue, type);
+}
+
+static int fimc_lite_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct fimc_lite *fimc = video_drvdata(file);
+ struct v4l2_subdev *sd = fimc->pipeline.subdevs[IDX_SENSOR];
+ int ret;
+
+ ret = vb2_streamoff(&fimc->vb_queue, type);
+ if (ret == 0)
+ media_entity_pipeline_stop(&sd->entity);
+ return ret;
+}
+
+static int fimc_lite_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct fimc_lite *fimc = video_drvdata(file);
+ int ret;
+
+ reqbufs->count = max_t(u32, FLITE_REQ_BUFS_MIN, reqbufs->count);
+ ret = vb2_reqbufs(&fimc->vb_queue, reqbufs);
+ if (!ret < 0)
+ fimc->reqbufs_count = reqbufs->count;
+
+ return ret;
+}
+
+static int fimc_lite_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct fimc_lite *fimc = video_drvdata(file);
+
+ return vb2_querybuf(&fimc->vb_queue, buf);
+}
+
+static int fimc_lite_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct fimc_lite *fimc = video_drvdata(file);
+
+ return vb2_qbuf(&fimc->vb_queue, buf);
+}
+
+static int fimc_lite_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct fimc_lite *fimc = video_drvdata(file);
+
+ return vb2_dqbuf(&fimc->vb_queue, buf, file->f_flags & O_NONBLOCK);
+}
+
+static int fimc_lite_create_bufs(struct file *file, void *priv,
+ struct v4l2_create_buffers *create)
+{
+ struct fimc_lite *fimc = video_drvdata(file);
+
+ return vb2_create_bufs(&fimc->vb_queue, create);
+}
+
+static int fimc_lite_prepare_buf(struct file *file, void *priv,
+ struct v4l2_buffer *b)
+{
+ struct fimc_lite *fimc = video_drvdata(file);
+
+ return vb2_prepare_buf(&fimc->vb_queue, b);
+}
+
+/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */
+static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
+{
+ if (a->left < b->left || a->top < b->top)
+ return 0;
+ if (a->left + a->width > b->left + b->width)
+ return 0;
+ if (a->top + a->height > b->top + b->height)
+ return 0;
+
+ return 1;
+}
+
+static int fimc_lite_g_selection(struct file *file, void *fh,
+ struct v4l2_selection *sel)
+{
+ struct fimc_lite *fimc = video_drvdata(file);
+ struct flite_frame *f = &fimc->out_frame;
+
+ if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return -EINVAL;
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = f->f_width;
+ sel->r.height = f->f_height;
+ return 0;
+
+ case V4L2_SEL_TGT_COMPOSE_ACTIVE:
+ sel->r = f->rect;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int fimc_lite_s_selection(struct file *file, void *fh,
+ struct v4l2_selection *sel)
+{
+ struct fimc_lite *fimc = video_drvdata(file);
+ struct flite_frame *f = &fimc->out_frame;
+ struct v4l2_rect rect = sel->r;
+ unsigned long flags;
+
+ if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
+ sel->target != V4L2_SEL_TGT_COMPOSE_ACTIVE)
+ return -EINVAL;
+
+ fimc_lite_try_compose(fimc, &rect);
+
+ if ((sel->flags & V4L2_SEL_FLAG_LE) &&
+ !enclosed_rectangle(&rect, &sel->r))
+ return -ERANGE;
+
+ if ((sel->flags & V4L2_SEL_FLAG_GE) &&
+ !enclosed_rectangle(&sel->r, &rect))
+ return -ERANGE;
+
+ sel->r = rect;
+ spin_lock_irqsave(&fimc->slock, flags);
+ f->rect = rect;
+ set_bit(ST_FLITE_CONFIG, &fimc->state);
+ spin_unlock_irqrestore(&fimc->slock, flags);
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops fimc_lite_ioctl_ops = {
+ .vidioc_querycap = fimc_vidioc_querycap_capture,
+ .vidioc_enum_fmt_vid_cap_mplane = fimc_lite_enum_fmt_mplane,
+ .vidioc_try_fmt_vid_cap_mplane = fimc_lite_try_fmt_mplane,
+ .vidioc_s_fmt_vid_cap_mplane = fimc_lite_s_fmt_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = fimc_lite_g_fmt_mplane,
+ .vidioc_g_selection = fimc_lite_g_selection,
+ .vidioc_s_selection = fimc_lite_s_selection,
+ .vidioc_reqbufs = fimc_lite_reqbufs,
+ .vidioc_querybuf = fimc_lite_querybuf,
+ .vidioc_prepare_buf = fimc_lite_prepare_buf,
+ .vidioc_create_bufs = fimc_lite_create_bufs,
+ .vidioc_qbuf = fimc_lite_qbuf,
+ .vidioc_dqbuf = fimc_lite_dqbuf,
+ .vidioc_streamon = fimc_lite_streamon,
+ .vidioc_streamoff = fimc_lite_streamoff,
+};
+
+/* Capture subdev media entity operations */
+static int fimc_lite_link_setup(struct media_entity *entity,
+ const struct media_pad *local,
+ const struct media_pad *remote, u32 flags)
+{
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+ unsigned int remote_ent_type = media_entity_type(remote->entity);
+
+ if (WARN_ON(fimc == NULL))
+ return 0;
+
+ v4l2_dbg(1, debug, sd, "%s: %s --> %s, flags: 0x%x. source_id: 0x%x",
+ __func__, local->entity->name, remote->entity->name,
+ flags, fimc->source_subdev_grp_id);
+
+ switch (local->index) {
+ case FIMC_SD_PAD_SINK:
+ if (remote_ent_type != MEDIA_ENT_T_V4L2_SUBDEV)
+ return -EINVAL;
+
+ if (flags & MEDIA_LNK_FL_ENABLED) {
+ if (fimc->source_subdev_grp_id != 0)
+ return -EBUSY;
+ fimc->source_subdev_grp_id = sd->grp_id;
+ return 0;
+ }
+
+ fimc->source_subdev_grp_id = 0;
+ break;
+
+ case FIMC_SD_PAD_SOURCE:
+ if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+ fimc->out_path = FIMC_IO_NONE;
+ return 0;
+ }
+ if (remote_ent_type == MEDIA_ENT_T_V4L2_SUBDEV)
+ fimc->out_path = FIMC_IO_ISP;
+ else
+ fimc->out_path = FIMC_IO_DMA;
+ break;
+
+ default:
+ v4l2_err(sd, "Invalid pad index\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct media_entity_operations fimc_lite_subdev_media_ops = {
+ .link_setup = fimc_lite_link_setup,
+};
+
+static int fimc_lite_subdev_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ const struct fimc_fmt *fmt;
+
+ fmt = fimc_lite_find_format(NULL, NULL, code->index);
+ if (!fmt)
+ return -EINVAL;
+ code->code = fmt->mbus_code;
+ return 0;
+}
+
+static int fimc_lite_subdev_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *mf = &fmt->format;
+ struct flite_frame *f = &fimc->out_frame;
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+ fmt->format = *mf;
+ return 0;
+ }
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+
+ mutex_lock(&fimc->lock);
+ mf->code = fimc->fmt->mbus_code;
+
+ if (fmt->pad == FLITE_SD_PAD_SINK) {
+ /* full camera input frame size */
+ mf->width = f->f_width;
+ mf->height = f->f_height;
+ } else {
+ /* crop size */
+ mf->width = f->rect.width;
+ mf->height = f->rect.height;
+ }
+ mutex_unlock(&fimc->lock);
+ return 0;
+}
+
+static int fimc_lite_subdev_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *mf = &fmt->format;
+ struct flite_frame *sink = &fimc->inp_frame;
+ const struct fimc_fmt *ffmt;
+
+ v4l2_dbg(1, debug, sd, "pad%d: code: 0x%x, %dx%d",
+ fmt->pad, mf->code, mf->width, mf->height);
+
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+ mutex_lock(&fimc->lock);
+
+ if ((fimc->out_path == FIMC_IO_ISP && sd->entity.stream_count > 0) ||
+ (fimc->out_path == FIMC_IO_DMA && vb2_is_busy(&fimc->vb_queue))) {
+ mutex_unlock(&fimc->lock);
+ return -EBUSY;
+ }
+
+ ffmt = fimc_lite_try_format(fimc, &mf->width, &mf->height,
+ &mf->code, NULL, fmt->pad);
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+ *mf = fmt->format;
+ mutex_unlock(&fimc->lock);
+ return 0;
+ }
+
+ if (fmt->pad == FLITE_SD_PAD_SINK) {
+ sink->f_width = mf->width;
+ sink->f_height = mf->height;
+ fimc->fmt = ffmt;
+ /* Set sink crop rectangle */
+ sink->rect.width = mf->width;
+ sink->rect.height = mf->height;
+ sink->rect.left = 0;
+ sink->rect.top = 0;
+ /* Reset source crop rectangle */
+ fimc->out_frame.rect = sink->rect;
+ } else {
+ /* Allow changing format only on sink pad */
+ mf->code = fimc->fmt->mbus_code;
+ mf->width = sink->rect.width;
+ mf->height = sink->rect.height;
+ }
+
+ mutex_unlock(&fimc->lock);
+ return 0;
+}
+
+static int fimc_lite_subdev_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
+{
+ struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+ struct flite_frame *f = &fimc->inp_frame;
+
+ if ((sel->target != V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL &&
+ sel->target != V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS) ||
+ sel->pad != FLITE_SD_PAD_SINK)
+ return -EINVAL;
+
+ if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
+ sel->r = *v4l2_subdev_get_try_crop(fh, sel->pad);
+ return 0;
+ }
+
+ mutex_lock(&fimc->lock);
+ if (sel->target == V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL) {
+ sel->r = f->rect;
+ } else {
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = f->f_width;
+ sel->r.height = f->f_height;
+ }
+ mutex_unlock(&fimc->lock);
+
+ v4l2_dbg(1, debug, sd, "%s: (%d,%d) %dx%d, f_w: %d, f_h: %d",
+ __func__, f->rect.left, f->rect.top, f->rect.width,
+ f->rect.height, f->f_width, f->f_height);
+
+ return 0;
+}
+
+static int fimc_lite_subdev_set_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
+{
+ struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+ struct flite_frame *f = &fimc->inp_frame;
+ int ret = 0;
+
+ if (sel->target != V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL ||
+ sel->pad != FLITE_SD_PAD_SINK)
+ return -EINVAL;
+
+ mutex_lock(&fimc->lock);
+ fimc_lite_try_crop(fimc, &sel->r);
+
+ if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
+ *v4l2_subdev_get_try_crop(fh, sel->pad) = sel->r;
+ } else {
+ unsigned long flags;
+ spin_lock_irqsave(&fimc->slock, flags);
+ f->rect = sel->r;
+ /* Same crop rectangle on the source pad */
+ fimc->out_frame.rect = sel->r;
+ set_bit(ST_FLITE_CONFIG, &fimc->state);
+ spin_unlock_irqrestore(&fimc->slock, flags);
+ }
+ mutex_unlock(&fimc->lock);
+
+ v4l2_dbg(1, debug, sd, "%s: (%d,%d) %dx%d, f_w: %d, f_h: %d",
+ __func__, f->rect.left, f->rect.top, f->rect.width,
+ f->rect.height, f->f_width, f->f_height);
+
+ return ret;
+}
+
+static int fimc_lite_subdev_s_stream(struct v4l2_subdev *sd, int on)
+{
+ struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+
+ if (fimc->out_path == FIMC_IO_DMA)
+ return -ENOIOCTLCMD;
+
+ /* TODO: */
+
+ return 0;
+}
+
+static int fimc_lite_subdev_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+
+ if (fimc->out_path == FIMC_IO_DMA)
+ return -ENOIOCTLCMD;
+
+ /* TODO: */
+
+ return 0;
+}
+
+static int fimc_lite_log_status(struct v4l2_subdev *sd)
+{
+ struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+
+ flite_hw_dump_regs(fimc, __func__);
+ return 0;
+}
+
+static int fimc_lite_subdev_registered(struct v4l2_subdev *sd)
+{
+ struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+ struct vb2_queue *q = &fimc->vb_queue;
+ struct video_device *vfd;
+ int ret;
+
+ fimc->fmt = &fimc_lite_formats[0];
+ fimc->out_path = FIMC_IO_DMA;
+
+ vfd = video_device_alloc();
+ if (!vfd) {
+ v4l2_err(sd->v4l2_dev, "Failed to allocate video device\n");
+ return -ENOMEM;
+ }
+
+ snprintf(vfd->name, sizeof(vfd->name), "fimc-lite.%d.capture",
+ fimc->index);
+
+ vfd->fops = &fimc_lite_fops;
+ vfd->ioctl_ops = &fimc_lite_ioctl_ops;
+ vfd->v4l2_dev = sd->v4l2_dev;
+ vfd->minor = -1;
+ vfd->release = video_device_release;
+ vfd->lock = &fimc->lock;
+ fimc->vfd = vfd;
+ fimc->ref_count = 0;
+ fimc->reqbufs_count = 0;
+
+ INIT_LIST_HEAD(&fimc->pending_buf_q);
+ INIT_LIST_HEAD(&fimc->active_buf_q);
+
+ memset(q, 0, sizeof(*q));
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR;
+ q->ops = &fimc_lite_qops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->buf_struct_size = sizeof(struct flite_buffer);
+ q->drv_priv = fimc;
+
+ vb2_queue_init(q);
+
+ fimc->vd_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_init(&vfd->entity, 1, &fimc->vd_pad, 0);
+ if (ret)
+ goto err;
+
+ video_set_drvdata(vfd, fimc);
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+ if (ret)
+ goto err_vd;
+
+ v4l2_info(sd->v4l2_dev, "Registered %s as /dev/%s\n",
+ vfd->name, video_device_node_name(vfd));
+ return 0;
+
+ err_vd:
+ media_entity_cleanup(&vfd->entity);
+ err:
+ video_device_release(vfd);
+ return ret;
+}
+
+static void fimc_lite_subdev_unregistered(struct v4l2_subdev *sd)
+{
+ struct fimc_lite *fimc = v4l2_get_subdevdata(sd);
+
+ if (fimc == NULL)
+ return;
+
+ if (fimc->vfd) {
+ video_unregister_device(fimc->vfd);
+ media_entity_cleanup(&fimc->vfd->entity);
+ fimc->vfd = NULL;
+ }
+}
+
+static const struct v4l2_subdev_internal_ops fimc_lite_subdev_internal_ops = {
+ .registered = fimc_lite_subdev_registered,
+ .unregistered = fimc_lite_subdev_unregistered,
+};
+
+static const struct v4l2_subdev_pad_ops fimc_lite_subdev_pad_ops = {
+ .enum_mbus_code = fimc_lite_subdev_enum_mbus_code,
+ .get_selection = fimc_lite_subdev_get_selection,
+ .set_selection = fimc_lite_subdev_set_selection,
+ .get_fmt = fimc_lite_subdev_get_fmt,
+ .set_fmt = fimc_lite_subdev_set_fmt,
+};
+
+static const struct v4l2_subdev_video_ops fimc_lite_subdev_video_ops = {
+ .s_stream = fimc_lite_subdev_s_stream,
+};
+
+static const struct v4l2_subdev_core_ops fimc_lite_core_ops = {
+ .s_power = fimc_lite_subdev_s_power,
+ .log_status = fimc_lite_log_status,
+};
+
+static struct v4l2_subdev_ops fimc_lite_subdev_ops = {
+ .core = &fimc_lite_core_ops,
+ .video = &fimc_lite_subdev_video_ops,
+ .pad = &fimc_lite_subdev_pad_ops,
+};
+
+static int fimc_lite_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct fimc_lite *fimc = container_of(ctrl->handler, struct fimc_lite,
+ ctrl_handler);
+ set_bit(ST_FLITE_CONFIG, &fimc->state);
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops fimc_lite_ctrl_ops = {
+ .s_ctrl = fimc_lite_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config fimc_lite_ctrl = {
+ .ops = &fimc_lite_ctrl_ops,
+ .id = V4L2_CTRL_CLASS_USER | 0x1001,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Test Pattern 640x480",
+};
+
+static int fimc_lite_create_capture_subdev(struct fimc_lite *fimc)
+{
+ struct v4l2_ctrl_handler *handler = &fimc->ctrl_handler;
+ struct v4l2_subdev *sd = &fimc->subdev;
+ int ret;
+
+ v4l2_subdev_init(sd, &fimc_lite_subdev_ops);
+ sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(sd->name, sizeof(sd->name), "FIMC-LITE.%d", fimc->index);
+
+ fimc->subdev_pads[FIMC_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ fimc->subdev_pads[FIMC_SD_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&sd->entity, FIMC_SD_PADS_NUM,
+ fimc->subdev_pads, 0);
+ if (ret)
+ return ret;
+
+ v4l2_ctrl_handler_init(handler, 1);
+ fimc->test_pattern = v4l2_ctrl_new_custom(handler, &fimc_lite_ctrl,
+ NULL);
+ if (handler->error) {
+ media_entity_cleanup(&sd->entity);
+ return handler->error;
+ }
+
+ sd->ctrl_handler = handler;
+ sd->internal_ops = &fimc_lite_subdev_internal_ops;
+ sd->entity.ops = &fimc_lite_subdev_media_ops;
+ v4l2_set_subdevdata(sd, fimc);
+
+ return 0;
+}
+
+static void fimc_lite_unregister_capture_subdev(struct fimc_lite *fimc)
+{
+ struct v4l2_subdev *sd = &fimc->subdev;
+
+ v4l2_device_unregister_subdev(sd);
+ media_entity_cleanup(&sd->entity);
+ v4l2_ctrl_handler_free(&fimc->ctrl_handler);
+ v4l2_set_subdevdata(sd, NULL);
+}
+
+static void fimc_lite_clk_put(struct fimc_lite *fimc)
+{
+ if (IS_ERR_OR_NULL(fimc->clock))
+ return;
+
+ clk_unprepare(fimc->clock);
+ clk_put(fimc->clock);
+ fimc->clock = NULL;
+}
+
+static int fimc_lite_clk_get(struct fimc_lite *fimc)
+{
+ int ret;
+
+ fimc->clock = clk_get(&fimc->pdev->dev, FLITE_CLK_NAME);
+ if (IS_ERR(fimc->clock))
+ return PTR_ERR(fimc->clock);
+
+ ret = clk_prepare(fimc->clock);
+ if (ret < 0) {
+ clk_put(fimc->clock);
+ fimc->clock = NULL;
+ }
+ return ret;
+}
+
+static int __devinit fimc_lite_probe(struct platform_device *pdev)
+{
+ struct flite_drvdata *drv_data = fimc_lite_get_drvdata(pdev);
+ struct fimc_lite *fimc;
+ struct resource *res;
+ int ret;
+
+ fimc = devm_kzalloc(&pdev->dev, sizeof(*fimc), GFP_KERNEL);
+ if (!fimc)
+ return -ENOMEM;
+
+ fimc->index = pdev->id;
+ fimc->variant = drv_data->variant[fimc->index];
+ fimc->pdev = pdev;
+
+ init_waitqueue_head(&fimc->irq_queue);
+ spin_lock_init(&fimc->slock);
+ mutex_init(&fimc->lock);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ fimc->regs = devm_request_and_ioremap(&pdev->dev, res);
+ if (fimc->regs == NULL) {
+ dev_err(&pdev->dev, "Failed to obtain io memory\n");
+ return -ENOENT;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "Failed to get IRQ resource\n");
+ return -ENXIO;
+ }
+
+ ret = fimc_lite_clk_get(fimc);
+ if (ret)
+ return ret;
+
+ ret = devm_request_irq(&pdev->dev, res->start, flite_irq_handler,
+ 0, dev_name(&pdev->dev), fimc);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to install irq (%d)\n", ret);
+ goto err_clk;
+ }
+
+ /* The video node will be created within the subdev's registered() op */
+ ret = fimc_lite_create_capture_subdev(fimc);
+ if (ret)
+ goto err_clk;
+
+ platform_set_drvdata(pdev, fimc);
+ pm_runtime_enable(&pdev->dev);
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0)
+ goto err_sd;
+
+ fimc->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+ if (IS_ERR(fimc->alloc_ctx)) {
+ ret = PTR_ERR(fimc->alloc_ctx);
+ goto err_pm;
+ }
+ pm_runtime_put(&pdev->dev);
+
+ dev_dbg(&pdev->dev, "FIMC-LITE.%d registered successfully\n",
+ fimc->index);
+ return 0;
+err_pm:
+ pm_runtime_put(&pdev->dev);
+err_sd:
+ fimc_lite_unregister_capture_subdev(fimc);
+err_clk:
+ fimc_lite_clk_put(fimc);
+ return ret;
+}
+
+static int fimc_lite_runtime_resume(struct device *dev)
+{
+ struct fimc_lite *fimc = dev_get_drvdata(dev);
+
+ clk_enable(fimc->clock);
+ return 0;
+}
+
+static int fimc_lite_runtime_suspend(struct device *dev)
+{
+ struct fimc_lite *fimc = dev_get_drvdata(dev);
+
+ clk_disable(fimc->clock);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int fimc_lite_resume(struct device *dev)
+{
+ struct fimc_lite *fimc = dev_get_drvdata(dev);
+ struct flite_buffer *buf;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&fimc->slock, flags);
+ if (!test_and_clear_bit(ST_LPM, &fimc->state) ||
+ !test_bit(ST_FLITE_IN_USE, &fimc->state)) {
+ spin_unlock_irqrestore(&fimc->slock, flags);
+ return 0;
+ }
+ flite_hw_reset(fimc);
+ spin_unlock_irqrestore(&fimc->slock, flags);
+
+ if (!test_and_clear_bit(ST_FLITE_SUSPENDED, &fimc->state))
+ return 0;
+
+ INIT_LIST_HEAD(&fimc->active_buf_q);
+ fimc_pipeline_initialize(&fimc->pipeline, &fimc->vfd->entity, false);
+ fimc_lite_hw_init(fimc);
+ clear_bit(ST_FLITE_SUSPENDED, &fimc->state);
+
+ for (i = 0; i < fimc->reqbufs_count; i++) {
+ if (list_empty(&fimc->pending_buf_q))
+ break;
+ buf = fimc_lite_pending_queue_pop(fimc);
+ buffer_queue(&buf->vb);
+ }
+ return 0;
+}
+
+static int fimc_lite_suspend(struct device *dev)
+{
+ struct fimc_lite *fimc = dev_get_drvdata(dev);
+ bool suspend = test_bit(ST_FLITE_IN_USE, &fimc->state);
+ int ret;
+
+ if (test_and_set_bit(ST_LPM, &fimc->state))
+ return 0;
+
+ ret = fimc_lite_stop_capture(fimc, suspend);
+ if (ret)
+ return ret;
+
+ return fimc_pipeline_shutdown(&fimc->pipeline);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static int __devexit fimc_lite_remove(struct platform_device *pdev)
+{
+ struct fimc_lite *fimc = platform_get_drvdata(pdev);
+ struct device *dev = &pdev->dev;
+
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ fimc_lite_unregister_capture_subdev(fimc);
+ vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx);
+ fimc_lite_clk_put(fimc);
+
+ dev_info(dev, "Driver unloaded\n");
+ return 0;
+}
+
+static struct flite_variant fimc_lite0_variant_exynos4 = {
+ .max_width = 8192,
+ .max_height = 8192,
+ .out_width_align = 8,
+ .win_hor_offs_align = 2,
+ .out_hor_offs_align = 8,
+};
+
+/* EXYNOS4212, EXYNOS4412 */
+static struct flite_drvdata fimc_lite_drvdata_exynos4 = {
+ .variant = {
+ [0] = &fimc_lite0_variant_exynos4,
+ [1] = &fimc_lite0_variant_exynos4,
+ },
+};
+
+static struct platform_device_id fimc_lite_driver_ids[] = {
+ {
+ .name = "exynos-fimc-lite",
+ .driver_data = (unsigned long)&fimc_lite_drvdata_exynos4,
+ },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, fimc_lite_driver_ids);
+
+static const struct dev_pm_ops fimc_lite_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(fimc_lite_suspend, fimc_lite_resume)
+ SET_RUNTIME_PM_OPS(fimc_lite_runtime_suspend, fimc_lite_runtime_resume,
+ NULL)
+};
+
+static struct platform_driver fimc_lite_driver = {
+ .probe = fimc_lite_probe,
+ .remove = __devexit_p(fimc_lite_remove),
+ .id_table = fimc_lite_driver_ids,
+ .driver = {
+ .name = FIMC_LITE_DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &fimc_lite_pm_ops,
+ }
+};
+module_platform_driver(fimc_lite_driver);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" FIMC_LITE_DRV_NAME);
diff --git a/drivers/media/video/s5p-fimc/fimc-lite.h b/drivers/media/video/s5p-fimc/fimc-lite.h
new file mode 100644
index 000000000000..44424eee81d8
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/fimc-lite.h
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ *
+ * 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 FIMC_LITE_H_
+#define FIMC_LITE_H_
+
+#include <asm/sizes.h>
+#include <linux/io.h>
+#include <linux/irqreturn.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/media-entity.h>
+#include <media/videobuf2-core.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+#include <media/s5p_fimc.h>
+
+#include "fimc-core.h"
+
+#define FIMC_LITE_DRV_NAME "exynos-fimc-lite"
+#define FLITE_CLK_NAME "flite"
+#define FIMC_LITE_MAX_DEVS 2
+#define FLITE_REQ_BUFS_MIN 2
+
+/* Bit index definitions for struct fimc_lite::state */
+enum {
+ ST_FLITE_LPM,
+ ST_FLITE_PENDING,
+ ST_FLITE_RUN,
+ ST_FLITE_STREAM,
+ ST_FLITE_SUSPENDED,
+ ST_FLITE_OFF,
+ ST_FLITE_IN_USE,
+ ST_FLITE_CONFIG,
+ ST_SENSOR_STREAM,
+};
+
+#define FLITE_SD_PAD_SINK 0
+#define FLITE_SD_PAD_SOURCE 1
+#define FLITE_SD_PADS_NUM 2
+
+struct flite_variant {
+ unsigned short max_width;
+ unsigned short max_height;
+ unsigned short out_width_align;
+ unsigned short win_hor_offs_align;
+ unsigned short out_hor_offs_align;
+};
+
+struct flite_drvdata {
+ struct flite_variant *variant[FIMC_LITE_MAX_DEVS];
+};
+
+#define fimc_lite_get_drvdata(_pdev) \
+ ((struct flite_drvdata *) platform_get_device_id(_pdev)->driver_data)
+
+struct fimc_lite_events {
+ unsigned int data_overflow;
+};
+
+#define FLITE_MAX_PLANES 1
+
+/**
+ * struct flite_frame - source/target frame properties
+ * @f_width: full pixel width
+ * @f_height: full pixel height
+ * @rect: crop/composition rectangle
+ */
+struct flite_frame {
+ u16 f_width;
+ u16 f_height;
+ struct v4l2_rect rect;
+};
+
+/**
+ * struct flite_buffer - video buffer structure
+ * @vb: vb2 buffer
+ * @list: list head for the buffers queue
+ * @paddr: precalculated physical address
+ */
+struct flite_buffer {
+ struct vb2_buffer vb;
+ struct list_head list;
+ dma_addr_t paddr;
+};
+
+/**
+ * struct fimc_lite - fimc lite structure
+ * @pdev: pointer to FIMC-LITE platform device
+ * @variant: variant information for this IP
+ * @v4l2_dev: pointer to top the level v4l2_device
+ * @vfd: video device node
+ * @fh: v4l2 file handle
+ * @alloc_ctx: videobuf2 memory allocator context
+ * @subdev: FIMC-LITE subdev
+ * @vd_pad: media (sink) pad for the capture video node
+ * @subdev_pads: the subdev media pads
+ * @ctrl_handler: v4l2 control handler
+ * @test_pattern: test pattern controls
+ * @index: FIMC-LITE platform device index
+ * @pipeline: video capture pipeline data structure
+ * @slock: spinlock protecting this data structure and the hw registers
+ * @lock: mutex serializing video device and the subdev operations
+ * @clock: FIMC-LITE gate clock
+ * @regs: memory mapped io registers
+ * @irq_queue: interrupt handler waitqueue
+ * @fmt: pointer to color format description structure
+ * @payload: image size in bytes (w x h x bpp)
+ * @inp_frame: camera input frame structure
+ * @out_frame: DMA output frame structure
+ * @out_path: output data path (DMA or FIFO)
+ * @source_subdev_grp_id: source subdev group id
+ * @state: driver state flags
+ * @pending_buf_q: pending buffers queue head
+ * @active_buf_q: the queue head of buffers scheduled in hardware
+ * @vb_queue: vb2 buffers queue
+ * @active_buf_count: number of video buffers scheduled in hardware
+ * @frame_count: the captured frames counter
+ * @reqbufs_count: the number of buffers requested with REQBUFS ioctl
+ * @ref_count: driver's private reference counter
+ */
+struct fimc_lite {
+ struct platform_device *pdev;
+ struct flite_variant *variant;
+ struct v4l2_device *v4l2_dev;
+ struct video_device *vfd;
+ struct v4l2_fh fh;
+ struct vb2_alloc_ctx *alloc_ctx;
+ struct v4l2_subdev subdev;
+ struct media_pad vd_pad;
+ struct media_pad subdev_pads[FLITE_SD_PADS_NUM];
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_ctrl *test_pattern;
+ u32 index;
+ struct fimc_pipeline pipeline;
+
+ struct mutex lock;
+ spinlock_t slock;
+
+ struct clk *clock;
+ void __iomem *regs;
+ wait_queue_head_t irq_queue;
+
+ const struct fimc_fmt *fmt;
+ unsigned long payload[FLITE_MAX_PLANES];
+ struct flite_frame inp_frame;
+ struct flite_frame out_frame;
+ enum fimc_datapath out_path;
+ unsigned int source_subdev_grp_id;
+
+ unsigned long state;
+ struct list_head pending_buf_q;
+ struct list_head active_buf_q;
+ struct vb2_queue vb_queue;
+ unsigned int frame_count;
+ unsigned int reqbufs_count;
+ int ref_count;
+
+ struct fimc_lite_events events;
+};
+
+static inline bool fimc_lite_active(struct fimc_lite *fimc)
+{
+ unsigned long flags;
+ bool ret;
+
+ spin_lock_irqsave(&fimc->slock, flags);
+ ret = fimc->state & (1 << ST_FLITE_RUN) ||
+ fimc->state & (1 << ST_FLITE_PENDING);
+ spin_unlock_irqrestore(&fimc->slock, flags);
+ return ret;
+}
+
+static inline void fimc_lite_active_queue_add(struct fimc_lite *dev,
+ struct flite_buffer *buf)
+{
+ list_add_tail(&buf->list, &dev->active_buf_q);
+}
+
+static inline struct flite_buffer *fimc_lite_active_queue_pop(
+ struct fimc_lite *dev)
+{
+ struct flite_buffer *buf = list_entry(dev->active_buf_q.next,
+ struct flite_buffer, list);
+ list_del(&buf->list);
+ return buf;
+}
+
+static inline void fimc_lite_pending_queue_add(struct fimc_lite *dev,
+ struct flite_buffer *buf)
+{
+ list_add_tail(&buf->list, &dev->pending_buf_q);
+}
+
+static inline struct flite_buffer *fimc_lite_pending_queue_pop(
+ struct fimc_lite *dev)
+{
+ struct flite_buffer *buf = list_entry(dev->pending_buf_q.next,
+ struct flite_buffer, list);
+ list_del(&buf->list);
+ return buf;
+}
+
+#endif /* FIMC_LITE_H_ */
diff --git a/drivers/media/video/s5p-fimc/fimc-m2m.c b/drivers/media/video/s5p-fimc/fimc-m2m.c
new file mode 100644
index 000000000000..4c58e0570962
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/fimc-m2m.c
@@ -0,0 +1,824 @@
+/*
+ * Samsung S5P/EXYNOS4 SoC series FIMC (video postprocessor) driver
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 2 of the License,
+ * or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/bug.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "fimc-core.h"
+#include "fimc-reg.h"
+#include "fimc-mdevice.h"
+
+
+static unsigned int get_m2m_fmt_flags(unsigned int stream_type)
+{
+ if (stream_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return FMT_FLAGS_M2M_IN;
+ else
+ return FMT_FLAGS_M2M_OUT;
+}
+
+void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state)
+{
+ struct vb2_buffer *src_vb, *dst_vb;
+
+ if (!ctx || !ctx->m2m_ctx)
+ return;
+
+ src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+ dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+
+ if (src_vb && dst_vb) {
+ v4l2_m2m_buf_done(src_vb, vb_state);
+ v4l2_m2m_buf_done(dst_vb, vb_state);
+ v4l2_m2m_job_finish(ctx->fimc_dev->m2m.m2m_dev,
+ ctx->m2m_ctx);
+ }
+}
+
+/* Complete the transaction which has been scheduled for execution. */
+static int fimc_m2m_shutdown(struct fimc_ctx *ctx)
+{
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ int ret;
+
+ if (!fimc_m2m_pending(fimc))
+ return 0;
+
+ fimc_ctx_state_set(FIMC_CTX_SHUT, ctx);
+
+ ret = wait_event_timeout(fimc->irq_queue,
+ !fimc_ctx_state_is_set(FIMC_CTX_SHUT, ctx),
+ FIMC_SHUTDOWN_TIMEOUT);
+
+ return ret == 0 ? -ETIMEDOUT : ret;
+}
+
+static int start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct fimc_ctx *ctx = q->drv_priv;
+ int ret;
+
+ ret = pm_runtime_get_sync(&ctx->fimc_dev->pdev->dev);
+ return ret > 0 ? 0 : ret;
+}
+
+static int stop_streaming(struct vb2_queue *q)
+{
+ struct fimc_ctx *ctx = q->drv_priv;
+ int ret;
+
+ ret = fimc_m2m_shutdown(ctx);
+ if (ret == -ETIMEDOUT)
+ 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)
+{
+ struct vb2_buffer *vb = NULL;
+ struct fimc_ctx *ctx = priv;
+ struct fimc_frame *sf, *df;
+ struct fimc_dev *fimc;
+ unsigned long flags;
+ u32 ret;
+
+ if (WARN(!ctx, "Null context\n"))
+ return;
+
+ fimc = ctx->fimc_dev;
+ spin_lock_irqsave(&fimc->slock, flags);
+
+ set_bit(ST_M2M_PEND, &fimc->state);
+ sf = &ctx->s_frame;
+ df = &ctx->d_frame;
+
+ if (ctx->state & FIMC_PARAMS) {
+ /* Prepare the DMA offsets for scaler */
+ fimc_prepare_dma_offset(ctx, sf);
+ fimc_prepare_dma_offset(ctx, df);
+ }
+
+ vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+ ret = fimc_prepare_addr(ctx, vb, sf, &sf->paddr);
+ if (ret)
+ goto dma_unlock;
+
+ vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+ ret = fimc_prepare_addr(ctx, vb, df, &df->paddr);
+ if (ret)
+ goto dma_unlock;
+
+ /* Reconfigure hardware if the context has changed. */
+ if (fimc->m2m.ctx != ctx) {
+ ctx->state |= FIMC_PARAMS;
+ fimc->m2m.ctx = ctx;
+ }
+
+ if (ctx->state & FIMC_PARAMS) {
+ fimc_set_yuv_order(ctx);
+ fimc_hw_set_input_path(ctx);
+ fimc_hw_set_in_dma(ctx);
+ ret = fimc_set_scaler_info(ctx);
+ if (ret)
+ goto dma_unlock;
+ fimc_hw_set_prescaler(ctx);
+ fimc_hw_set_mainscaler(ctx);
+ fimc_hw_set_target_format(ctx);
+ fimc_hw_set_rotation(ctx);
+ fimc_hw_set_effect(ctx);
+ fimc_hw_set_out_dma(ctx);
+ if (fimc->variant->has_alpha)
+ fimc_hw_set_rgb_alpha(ctx);
+ fimc_hw_set_output_path(ctx);
+ }
+ fimc_hw_set_input_addr(fimc, &sf->paddr);
+ fimc_hw_set_output_addr(fimc, &df->paddr, -1);
+
+ fimc_activate_capture(ctx);
+ ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP |
+ FIMC_SRC_FMT | FIMC_DST_FMT);
+ fimc_hw_activate_input_dma(fimc, true);
+
+dma_unlock:
+ spin_unlock_irqrestore(&fimc->slock, flags);
+}
+
+static void fimc_job_abort(void *priv)
+{
+ fimc_m2m_shutdown(priv);
+}
+
+static int fimc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[], void *allocators[])
+{
+ struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
+ struct fimc_frame *f;
+ int i;
+
+ f = ctx_get_frame(ctx, vq->type);
+ if (IS_ERR(f))
+ return PTR_ERR(f);
+ /*
+ * Return number of non-contigous planes (plane buffers)
+ * depending on the configured color format.
+ */
+ if (!f->fmt)
+ return -EINVAL;
+
+ *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;
+ allocators[i] = ctx->fimc_dev->alloc_ctx;
+ }
+ return 0;
+}
+
+static int fimc_buf_prepare(struct vb2_buffer *vb)
+{
+ struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct fimc_frame *frame;
+ int i;
+
+ frame = ctx_get_frame(ctx, vb->vb2_queue->type);
+ if (IS_ERR(frame))
+ return PTR_ERR(frame);
+
+ for (i = 0; i < frame->fmt->memplanes; i++)
+ vb2_set_plane_payload(vb, i, frame->payload[i]);
+
+ return 0;
+}
+
+static void fimc_buf_queue(struct vb2_buffer *vb)
+{
+ struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ dbg("ctx: %p, ctx->state: 0x%x", ctx, ctx->state);
+
+ if (ctx->m2m_ctx)
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+static void fimc_lock(struct vb2_queue *vq)
+{
+ struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
+ mutex_lock(&ctx->fimc_dev->lock);
+}
+
+static void fimc_unlock(struct vb2_queue *vq)
+{
+ struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
+ mutex_unlock(&ctx->fimc_dev->lock);
+}
+
+static struct vb2_ops fimc_qops = {
+ .queue_setup = fimc_queue_setup,
+ .buf_prepare = fimc_buf_prepare,
+ .buf_queue = fimc_buf_queue,
+ .wait_prepare = fimc_unlock,
+ .wait_finish = fimc_lock,
+ .stop_streaming = stop_streaming,
+ .start_streaming = start_streaming,
+};
+
+/*
+ * V4L2 ioctl handlers
+ */
+static int fimc_m2m_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct fimc_ctx *ctx = fh_to_ctx(fh);
+ struct fimc_dev *fimc = ctx->fimc_dev;
+
+ strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1);
+ strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->capabilities = V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+
+ return 0;
+}
+
+static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct fimc_fmt *fmt;
+
+ fmt = fimc_find_format(NULL, NULL, get_m2m_fmt_flags(f->type),
+ f->index);
+ if (!fmt)
+ return -EINVAL;
+
+ strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+ f->pixelformat = fmt->fourcc;
+ return 0;
+}
+
+static int fimc_m2m_g_fmt_mplane(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct fimc_ctx *ctx = fh_to_ctx(fh);
+ struct fimc_frame *frame = ctx_get_frame(ctx, f->type);
+
+ if (IS_ERR(frame))
+ return PTR_ERR(frame);
+
+ return fimc_fill_format(frame, f);
+}
+
+static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f)
+{
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_variant *variant = fimc->variant;
+ struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
+ struct fimc_fmt *fmt;
+ u32 max_w, mod_x, mod_y;
+
+ if (!IS_M2M(f->type))
+ return -EINVAL;
+
+ dbg("w: %d, h: %d", pix->width, pix->height);
+
+ fmt = fimc_find_format(&pix->pixelformat, NULL,
+ get_m2m_fmt_flags(f->type), 0);
+ if (WARN(fmt == NULL, "Pixel format lookup failed"))
+ return -EINVAL;
+
+ if (pix->field == V4L2_FIELD_ANY)
+ pix->field = V4L2_FIELD_NONE;
+ else if (pix->field != V4L2_FIELD_NONE)
+ return -EINVAL;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ max_w = variant->pix_limit->scaler_dis_w;
+ mod_x = ffs(variant->min_inp_pixsize) - 1;
+ } else {
+ max_w = variant->pix_limit->out_rot_dis_w;
+ mod_x = ffs(variant->min_out_pixsize) - 1;
+ }
+
+ if (tiled_fmt(fmt)) {
+ mod_x = 6; /* 64 x 32 pixels tile */
+ mod_y = 5;
+ } else {
+ if (variant->min_vsize_align == 1)
+ mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1;
+ else
+ mod_y = ffs(variant->min_vsize_align) - 1;
+ }
+
+ v4l_bound_align_image(&pix->width, 16, max_w, mod_x,
+ &pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0);
+
+ fimc_adjust_mplane_format(fmt, pix->width, pix->height, &f->fmt.pix_mp);
+ return 0;
+}
+
+static int fimc_m2m_try_fmt_mplane(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct fimc_ctx *ctx = fh_to_ctx(fh);
+
+ return fimc_try_fmt_mplane(ctx, f);
+}
+
+static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct fimc_ctx *ctx = fh_to_ctx(fh);
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct vb2_queue *vq;
+ struct fimc_frame *frame;
+ struct v4l2_pix_format_mplane *pix;
+ int i, ret = 0;
+
+ ret = fimc_try_fmt_mplane(ctx, f);
+ if (ret)
+ return ret;
+
+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+
+ if (vb2_is_busy(vq)) {
+ v4l2_err(fimc->m2m.vfd, "queue (%d) busy\n", f->type);
+ return -EBUSY;
+ }
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ frame = &ctx->s_frame;
+ else
+ frame = &ctx->d_frame;
+
+ pix = &f->fmt.pix_mp;
+ frame->fmt = fimc_find_format(&pix->pixelformat, NULL,
+ get_m2m_fmt_flags(f->type), 0);
+ if (!frame->fmt)
+ return -EINVAL;
+
+ /* Update RGB Alpha control state and value range */
+ fimc_alpha_ctrl_update(ctx);
+
+ for (i = 0; i < frame->fmt->colplanes; i++) {
+ frame->payload[i] =
+ (pix->width * pix->height * frame->fmt->depth[i]) / 8;
+ }
+
+ fimc_fill_frame(frame, f);
+
+ ctx->scaler.enabled = 1;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ fimc_ctx_state_set(FIMC_PARAMS | FIMC_DST_FMT, ctx);
+ else
+ fimc_ctx_state_set(FIMC_PARAMS | FIMC_SRC_FMT, ctx);
+
+ dbg("f_w: %d, f_h: %d", frame->f_width, frame->f_height);
+
+ return 0;
+}
+
+static int fimc_m2m_reqbufs(struct file *file, void *fh,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct fimc_ctx *ctx = fh_to_ctx(fh);
+
+ return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int fimc_m2m_querybuf(struct file *file, void *fh,
+ struct v4l2_buffer *buf)
+{
+ struct fimc_ctx *ctx = fh_to_ctx(fh);
+
+ return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int fimc_m2m_qbuf(struct file *file, void *fh,
+ struct v4l2_buffer *buf)
+{
+ struct fimc_ctx *ctx = fh_to_ctx(fh);
+
+ return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int fimc_m2m_dqbuf(struct file *file, void *fh,
+ struct v4l2_buffer *buf)
+{
+ struct fimc_ctx *ctx = fh_to_ctx(fh);
+
+ return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int fimc_m2m_streamon(struct file *file, void *fh,
+ enum v4l2_buf_type type)
+{
+ struct fimc_ctx *ctx = fh_to_ctx(fh);
+
+ /* The source and target color format need to be set */
+ if (V4L2_TYPE_IS_OUTPUT(type)) {
+ if (!fimc_ctx_state_is_set(FIMC_SRC_FMT, ctx))
+ return -EINVAL;
+ } else if (!fimc_ctx_state_is_set(FIMC_DST_FMT, ctx)) {
+ return -EINVAL;
+ }
+
+ return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int fimc_m2m_streamoff(struct file *file, void *fh,
+ enum v4l2_buf_type type)
+{
+ struct fimc_ctx *ctx = fh_to_ctx(fh);
+
+ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static int fimc_m2m_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cr)
+{
+ struct fimc_ctx *ctx = fh_to_ctx(fh);
+ struct fimc_frame *frame;
+
+ frame = ctx_get_frame(ctx, cr->type);
+ if (IS_ERR(frame))
+ return PTR_ERR(frame);
+
+ cr->bounds.left = 0;
+ cr->bounds.top = 0;
+ cr->bounds.width = frame->o_width;
+ cr->bounds.height = frame->o_height;
+ cr->defrect = cr->bounds;
+
+ return 0;
+}
+
+static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+{
+ struct fimc_ctx *ctx = fh_to_ctx(fh);
+ struct fimc_frame *frame;
+
+ frame = ctx_get_frame(ctx, cr->type);
+ if (IS_ERR(frame))
+ return PTR_ERR(frame);
+
+ cr->c.left = frame->offs_h;
+ cr->c.top = frame->offs_v;
+ cr->c.width = frame->width;
+ cr->c.height = frame->height;
+
+ return 0;
+}
+
+static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
+{
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_frame *f;
+ u32 min_size, halign, depth = 0;
+ int i;
+
+ if (cr->c.top < 0 || cr->c.left < 0) {
+ v4l2_err(fimc->m2m.vfd,
+ "doesn't support negative values for top & left\n");
+ return -EINVAL;
+ }
+ if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ f = &ctx->d_frame;
+ else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ f = &ctx->s_frame;
+ else
+ return -EINVAL;
+
+ min_size = (f == &ctx->s_frame) ?
+ fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize;
+
+ /* Get pixel alignment constraints. */
+ if (fimc->variant->min_vsize_align == 1)
+ halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1;
+ else
+ halign = ffs(fimc->variant->min_vsize_align) - 1;
+
+ for (i = 0; i < f->fmt->colplanes; i++)
+ depth += f->fmt->depth[i];
+
+ v4l_bound_align_image(&cr->c.width, min_size, f->o_width,
+ ffs(min_size) - 1,
+ &cr->c.height, min_size, f->o_height,
+ halign, 64/(ALIGN(depth, 8)));
+
+ /* adjust left/top if cropping rectangle is out of bounds */
+ if (cr->c.left + cr->c.width > f->o_width)
+ cr->c.left = f->o_width - cr->c.width;
+ if (cr->c.top + cr->c.height > f->o_height)
+ cr->c.top = f->o_height - cr->c.height;
+
+ cr->c.left = round_down(cr->c.left, min_size);
+ cr->c.top = round_down(cr->c.top, fimc->variant->hor_offs_align);
+
+ dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
+ cr->c.left, cr->c.top, cr->c.width, cr->c.height,
+ f->f_width, f->f_height);
+
+ return 0;
+}
+
+static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+{
+ struct fimc_ctx *ctx = fh_to_ctx(fh);
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_frame *f;
+ int ret;
+
+ ret = fimc_m2m_try_crop(ctx, cr);
+ if (ret)
+ return ret;
+
+ f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ?
+ &ctx->s_frame : &ctx->d_frame;
+
+ /* Check to see if scaling ratio is within supported range */
+ if (fimc_ctx_state_is_set(FIMC_DST_FMT | FIMC_SRC_FMT, ctx)) {
+ if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ ret = fimc_check_scaler_ratio(ctx, cr->c.width,
+ cr->c.height, ctx->d_frame.width,
+ ctx->d_frame.height, ctx->rotation);
+ } else {
+ ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
+ ctx->s_frame.height, cr->c.width,
+ cr->c.height, ctx->rotation);
+ }
+ if (ret) {
+ v4l2_err(fimc->m2m.vfd, "Out of scaler range\n");
+ return -EINVAL;
+ }
+ }
+
+ f->offs_h = cr->c.left;
+ f->offs_v = cr->c.top;
+ f->width = cr->c.width;
+ f->height = cr->c.height;
+
+ fimc_ctx_state_set(FIMC_PARAMS, ctx);
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
+ .vidioc_querycap = fimc_m2m_querycap,
+ .vidioc_enum_fmt_vid_cap_mplane = fimc_m2m_enum_fmt_mplane,
+ .vidioc_enum_fmt_vid_out_mplane = fimc_m2m_enum_fmt_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = fimc_m2m_g_fmt_mplane,
+ .vidioc_g_fmt_vid_out_mplane = fimc_m2m_g_fmt_mplane,
+ .vidioc_try_fmt_vid_cap_mplane = fimc_m2m_try_fmt_mplane,
+ .vidioc_try_fmt_vid_out_mplane = fimc_m2m_try_fmt_mplane,
+ .vidioc_s_fmt_vid_cap_mplane = fimc_m2m_s_fmt_mplane,
+ .vidioc_s_fmt_vid_out_mplane = fimc_m2m_s_fmt_mplane,
+ .vidioc_reqbufs = fimc_m2m_reqbufs,
+ .vidioc_querybuf = fimc_m2m_querybuf,
+ .vidioc_qbuf = fimc_m2m_qbuf,
+ .vidioc_dqbuf = fimc_m2m_dqbuf,
+ .vidioc_streamon = fimc_m2m_streamon,
+ .vidioc_streamoff = fimc_m2m_streamoff,
+ .vidioc_g_crop = fimc_m2m_g_crop,
+ .vidioc_s_crop = fimc_m2m_s_crop,
+ .vidioc_cropcap = fimc_m2m_cropcap
+
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ struct fimc_ctx *ctx = priv;
+ int ret;
+
+ memset(src_vq, 0, sizeof(*src_vq));
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ src_vq->drv_priv = ctx;
+ src_vq->ops = &fimc_qops;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+
+ memset(dst_vq, 0, sizeof(*dst_vq));
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ dst_vq->drv_priv = ctx;
+ dst_vq->ops = &fimc_qops;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+
+ return vb2_queue_init(dst_vq);
+}
+
+static int fimc_m2m_open(struct file *file)
+{
+ struct fimc_dev *fimc = video_drvdata(file);
+ struct fimc_ctx *ctx;
+ int ret;
+
+ dbg("pid: %d, state: 0x%lx, refcnt: %d",
+ task_pid_nr(current), fimc->state, fimc->vid_cap.refcnt);
+
+ /*
+ * Return if the corresponding video capture node
+ * is already opened.
+ */
+ if (fimc->vid_cap.refcnt > 0)
+ return -EBUSY;
+
+ ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+ v4l2_fh_init(&ctx->fh, fimc->m2m.vfd);
+ ctx->fimc_dev = fimc;
+
+ /* Default color format */
+ ctx->s_frame.fmt = fimc_get_format(0);
+ ctx->d_frame.fmt = fimc_get_format(0);
+
+ ret = fimc_ctrls_create(ctx);
+ if (ret)
+ goto error_fh;
+
+ /* Use separate control handler per file handle */
+ ctx->fh.ctrl_handler = &ctx->ctrls.handler;
+ file->private_data = &ctx->fh;
+ v4l2_fh_add(&ctx->fh);
+
+ /* Setup the device context for memory-to-memory mode */
+ ctx->state = FIMC_CTX_M2M;
+ ctx->flags = 0;
+ ctx->in_path = FIMC_IO_DMA;
+ ctx->out_path = FIMC_IO_DMA;
+
+ ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init);
+ if (IS_ERR(ctx->m2m_ctx)) {
+ ret = PTR_ERR(ctx->m2m_ctx);
+ goto error_c;
+ }
+
+ if (fimc->m2m.refcnt++ == 0)
+ set_bit(ST_M2M_RUN, &fimc->state);
+ return 0;
+
+error_c:
+ fimc_ctrls_delete(ctx);
+error_fh:
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ kfree(ctx);
+ return ret;
+}
+
+static int fimc_m2m_release(struct file *file)
+{
+ struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
+ struct fimc_dev *fimc = ctx->fimc_dev;
+
+ dbg("pid: %d, state: 0x%lx, refcnt= %d",
+ task_pid_nr(current), fimc->state, fimc->m2m.refcnt);
+
+ v4l2_m2m_ctx_release(ctx->m2m_ctx);
+ fimc_ctrls_delete(ctx);
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+
+ if (--fimc->m2m.refcnt <= 0)
+ clear_bit(ST_M2M_RUN, &fimc->state);
+ kfree(ctx);
+ return 0;
+}
+
+static unsigned int fimc_m2m_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
+
+ return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+}
+
+
+static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
+
+ return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+}
+
+static const struct v4l2_file_operations fimc_m2m_fops = {
+ .owner = THIS_MODULE,
+ .open = fimc_m2m_open,
+ .release = fimc_m2m_release,
+ .poll = fimc_m2m_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = fimc_m2m_mmap,
+};
+
+static struct v4l2_m2m_ops m2m_ops = {
+ .device_run = fimc_device_run,
+ .job_abort = fimc_job_abort,
+};
+
+int fimc_register_m2m_device(struct fimc_dev *fimc,
+ struct v4l2_device *v4l2_dev)
+{
+ struct video_device *vfd;
+ struct platform_device *pdev;
+ int ret = 0;
+
+ if (!fimc)
+ return -ENODEV;
+
+ pdev = fimc->pdev;
+ fimc->v4l2_dev = v4l2_dev;
+
+ vfd = video_device_alloc();
+ if (!vfd) {
+ v4l2_err(v4l2_dev, "Failed to allocate video device\n");
+ return -ENOMEM;
+ }
+
+ vfd->fops = &fimc_m2m_fops;
+ vfd->ioctl_ops = &fimc_m2m_ioctl_ops;
+ vfd->v4l2_dev = v4l2_dev;
+ vfd->minor = -1;
+ vfd->release = video_device_release;
+ vfd->lock = &fimc->lock;
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
+
+ snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.m2m", fimc->id);
+ video_set_drvdata(vfd, fimc);
+
+ fimc->m2m.vfd = vfd;
+ fimc->m2m.m2m_dev = v4l2_m2m_init(&m2m_ops);
+ if (IS_ERR(fimc->m2m.m2m_dev)) {
+ v4l2_err(v4l2_dev, "failed to initialize v4l2-m2m device\n");
+ ret = PTR_ERR(fimc->m2m.m2m_dev);
+ goto err_init;
+ }
+
+ ret = media_entity_init(&vfd->entity, 0, NULL, 0);
+ if (ret)
+ goto err_me;
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+ if (ret)
+ goto err_vd;
+
+ v4l2_info(v4l2_dev, "Registered %s as /dev/%s\n",
+ vfd->name, video_device_node_name(vfd));
+ return 0;
+
+err_vd:
+ media_entity_cleanup(&vfd->entity);
+err_me:
+ v4l2_m2m_release(fimc->m2m.m2m_dev);
+err_init:
+ video_device_release(fimc->m2m.vfd);
+ return ret;
+}
+
+void fimc_unregister_m2m_device(struct fimc_dev *fimc)
+{
+ if (!fimc)
+ return;
+
+ if (fimc->m2m.m2m_dev)
+ v4l2_m2m_release(fimc->m2m.m2m_dev);
+ if (fimc->m2m.vfd) {
+ media_entity_cleanup(&fimc->m2m.vfd->entity);
+ /* Can also be called if video device wasn't registered */
+ video_unregister_device(fimc->m2m.vfd);
+ }
+}
diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/video/s5p-fimc/fimc-mdevice.c
index 62ed37e40149..6753c45631b8 100644
--- a/drivers/media/video/s5p-fimc/fimc-mdevice.c
+++ b/drivers/media/video/s5p-fimc/fimc-mdevice.c
@@ -25,6 +25,7 @@
#include <media/media-device.h>
#include "fimc-core.h"
+#include "fimc-lite.h"
#include "fimc-mdevice.h"
#include "mipi-csis.h"
@@ -37,22 +38,46 @@ static int __fimc_md_set_camclk(struct fimc_md *fmd,
*
* Caller holds the graph mutex.
*/
-void fimc_pipeline_prepare(struct fimc_dev *fimc, struct media_entity *me)
+void fimc_pipeline_prepare(struct fimc_pipeline *p, struct media_entity *me)
{
- struct media_entity_graph graph;
+ struct media_pad *pad = &me->pads[0];
struct v4l2_subdev *sd;
+ int i;
- media_entity_graph_walk_start(&graph, me);
+ for (i = 0; i < IDX_MAX; i++)
+ p->subdevs[i] = NULL;
- while ((me = media_entity_graph_walk_next(&graph))) {
- if (media_entity_type(me) != MEDIA_ENT_T_V4L2_SUBDEV)
- continue;
- sd = media_entity_to_v4l2_subdev(me);
+ while (1) {
+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
+ break;
+
+ /* source pad */
+ pad = media_entity_remote_source(pad);
+ if (pad == NULL ||
+ media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ break;
+
+ sd = media_entity_to_v4l2_subdev(pad->entity);
- if (sd->grp_id == SENSOR_GROUP_ID)
- fimc->pipeline.sensor = sd;
- else if (sd->grp_id == CSIS_GROUP_ID)
- fimc->pipeline.csis = sd;
+ switch (sd->grp_id) {
+ case SENSOR_GROUP_ID:
+ p->subdevs[IDX_SENSOR] = sd;
+ break;
+ case CSIS_GROUP_ID:
+ p->subdevs[IDX_CSIS] = sd;
+ break;
+ case FLITE_GROUP_ID:
+ p->subdevs[IDX_FLITE] = sd;
+ break;
+ case FIMC_GROUP_ID:
+ /* No need to control FIMC subdev through subdev ops */
+ break;
+ default:
+ pr_warn("%s: Unknown subdev grp_id: %#x\n",
+ __func__, sd->grp_id);
+ }
+ /* sink pad */
+ pad = &sd->entity.pads[0];
}
}
@@ -85,30 +110,27 @@ static int __subdev_set_power(struct v4l2_subdev *sd, int on)
/**
* fimc_pipeline_s_power - change power state of all pipeline subdevs
* @fimc: fimc device terminating the pipeline
- * @state: 1 to enable power or 0 for power down
+ * @state: true to power on, false to power off
*
- * Need to be called with the graph mutex held.
+ * Needs to be called with the graph mutex held.
*/
-int fimc_pipeline_s_power(struct fimc_dev *fimc, int state)
+int fimc_pipeline_s_power(struct fimc_pipeline *p, bool state)
{
- int ret = 0;
+ unsigned int i;
+ int ret;
- if (fimc->pipeline.sensor == NULL)
+ if (p->subdevs[IDX_SENSOR] == NULL)
return -ENXIO;
- if (state) {
- ret = __subdev_set_power(fimc->pipeline.csis, 1);
- if (ret && ret != -ENXIO)
+ for (i = 0; i < IDX_MAX; i++) {
+ unsigned int idx = state ? (IDX_MAX - 1) - i : i;
+
+ ret = __subdev_set_power(p->subdevs[idx], state);
+ if (ret < 0 && ret != -ENXIO)
return ret;
- return __subdev_set_power(fimc->pipeline.sensor, 1);
}
- ret = __subdev_set_power(fimc->pipeline.sensor, 0);
- if (ret)
- return ret;
- ret = __subdev_set_power(fimc->pipeline.csis, 0);
-
- return ret == -ENXIO ? 0 : ret;
+ return 0;
}
/**
@@ -119,32 +141,36 @@ int fimc_pipeline_s_power(struct fimc_dev *fimc, int state)
*
* This function must be called with the graph mutex held.
*/
-static int __fimc_pipeline_initialize(struct fimc_dev *fimc,
+static int __fimc_pipeline_initialize(struct fimc_pipeline *p,
struct media_entity *me, bool prep)
{
int ret;
if (prep)
- fimc_pipeline_prepare(fimc, me);
- if (fimc->pipeline.sensor == NULL)
+ fimc_pipeline_prepare(p, me);
+
+ if (p->subdevs[IDX_SENSOR] == NULL)
return -EINVAL;
- ret = fimc_md_set_camclk(fimc->pipeline.sensor, true);
+
+ ret = fimc_md_set_camclk(p->subdevs[IDX_SENSOR], true);
if (ret)
return ret;
- return fimc_pipeline_s_power(fimc, 1);
+
+ return fimc_pipeline_s_power(p, 1);
}
-int fimc_pipeline_initialize(struct fimc_dev *fimc, struct media_entity *me,
+int fimc_pipeline_initialize(struct fimc_pipeline *p, struct media_entity *me,
bool prep)
{
int ret;
mutex_lock(&me->parent->graph_mutex);
- ret = __fimc_pipeline_initialize(fimc, me, prep);
+ ret = __fimc_pipeline_initialize(p, me, prep);
mutex_unlock(&me->parent->graph_mutex);
return ret;
}
+EXPORT_SYMBOL_GPL(fimc_pipeline_initialize);
/**
* __fimc_pipeline_shutdown - disable the sensor clock and pipeline power
@@ -154,52 +180,55 @@ int fimc_pipeline_initialize(struct fimc_dev *fimc, struct media_entity *me,
* sensor clock.
* Called with the graph mutex held.
*/
-int __fimc_pipeline_shutdown(struct fimc_dev *fimc)
+int __fimc_pipeline_shutdown(struct fimc_pipeline *p)
{
int ret = 0;
- if (fimc->pipeline.sensor) {
- ret = fimc_pipeline_s_power(fimc, 0);
- fimc_md_set_camclk(fimc->pipeline.sensor, false);
+ if (p->subdevs[IDX_SENSOR]) {
+ ret = fimc_pipeline_s_power(p, 0);
+ fimc_md_set_camclk(p->subdevs[IDX_SENSOR], false);
}
return ret == -ENXIO ? 0 : ret;
}
-int fimc_pipeline_shutdown(struct fimc_dev *fimc)
+int fimc_pipeline_shutdown(struct fimc_pipeline *p)
{
- struct media_entity *me = &fimc->vid_cap.vfd->entity;
+ struct media_entity *me = &p->subdevs[IDX_SENSOR]->entity;
int ret;
mutex_lock(&me->parent->graph_mutex);
- ret = __fimc_pipeline_shutdown(fimc);
+ ret = __fimc_pipeline_shutdown(p);
mutex_unlock(&me->parent->graph_mutex);
return ret;
}
+EXPORT_SYMBOL_GPL(fimc_pipeline_shutdown);
/**
* fimc_pipeline_s_stream - invoke s_stream on pipeline subdevs
- * @fimc: fimc device terminating the pipeline
+ * @pipeline: video pipeline structure
* @on: passed as the s_stream call argument
*/
-int fimc_pipeline_s_stream(struct fimc_dev *fimc, int on)
+int fimc_pipeline_s_stream(struct fimc_pipeline *p, bool on)
{
- struct fimc_pipeline *p = &fimc->pipeline;
- int ret = 0;
+ int i, ret;
- if (p->sensor == NULL)
+ if (p->subdevs[IDX_SENSOR] == NULL)
return -ENODEV;
- if ((on && p->csis) || !on)
- ret = v4l2_subdev_call(on ? p->csis : p->sensor,
- video, s_stream, on);
- if (ret < 0 && ret != -ENOIOCTLCMD)
- return ret;
- if ((!on && p->csis) || on)
- ret = v4l2_subdev_call(on ? p->sensor : p->csis,
- video, s_stream, on);
- return ret == -ENOIOCTLCMD ? 0 : ret;
+ for (i = 0; i < IDX_MAX; i++) {
+ unsigned int idx = on ? (IDX_MAX - 1) - i : i;
+
+ ret = v4l2_subdev_call(p->subdevs[idx], video, s_stream, on);
+
+ if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
+ return ret;
+ }
+
+ return 0;
+
}
+EXPORT_SYMBOL_GPL(fimc_pipeline_s_stream);
/*
* Sensor subdevice helper functions
@@ -214,14 +243,20 @@ static struct v4l2_subdev *fimc_md_register_sensor(struct fimc_md *fmd,
return NULL;
adapter = i2c_get_adapter(s_info->pdata->i2c_bus_num);
- if (!adapter)
- return NULL;
+ if (!adapter) {
+ v4l2_warn(&fmd->v4l2_dev,
+ "Failed to get I2C adapter %d, deferring probe\n",
+ s_info->pdata->i2c_bus_num);
+ return ERR_PTR(-EPROBE_DEFER);
+ }
sd = v4l2_i2c_new_subdev_board(&fmd->v4l2_dev, adapter,
s_info->pdata->board_info, NULL);
if (IS_ERR_OR_NULL(sd)) {
i2c_put_adapter(adapter);
- v4l2_err(&fmd->v4l2_dev, "Failed to acquire subdev\n");
- return NULL;
+ v4l2_warn(&fmd->v4l2_dev,
+ "Failed to acquire subdev %s, deferring probe\n",
+ s_info->pdata->board_info->type);
+ return ERR_PTR(-EPROBE_DEFER);
}
v4l2_set_subdev_hostdata(sd, s_info);
sd->grp_id = SENSOR_GROUP_ID;
@@ -269,13 +304,22 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
fmd->num_sensors = num_clients;
for (i = 0; i < num_clients; i++) {
+ struct v4l2_subdev *sd;
+
fmd->sensor[i].pdata = &pdata->isp_info[i];
ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], true);
if (ret)
break;
- fmd->sensor[i].subdev =
- fimc_md_register_sensor(fmd, &fmd->sensor[i]);
+ sd = fimc_md_register_sensor(fmd, &fmd->sensor[i]);
ret = __fimc_md_set_camclk(fmd, &fmd->sensor[i], false);
+
+ if (!IS_ERR(sd)) {
+ fmd->sensor[i].subdev = sd;
+ } else {
+ fmd->sensor[i].subdev = NULL;
+ ret = PTR_ERR(sd);
+ break;
+ }
if (ret)
break;
}
@@ -289,21 +333,50 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
static int fimc_register_callback(struct device *dev, void *p)
{
struct fimc_dev *fimc = dev_get_drvdata(dev);
+ struct v4l2_subdev *sd = &fimc->vid_cap.subdev;
struct fimc_md *fmd = p;
- int ret;
+ int ret = 0;
if (!fimc || !fimc->pdev)
return 0;
+
if (fimc->pdev->id < 0 || fimc->pdev->id >= FIMC_MAX_DEVS)
return 0;
fmd->fimc[fimc->pdev->id] = fimc;
- ret = fimc_register_m2m_device(fimc, &fmd->v4l2_dev);
- if (ret)
- return ret;
- ret = fimc_register_capture_device(fimc, &fmd->v4l2_dev);
- if (!ret)
- fimc->vid_cap.user_subdev_api = fmd->user_subdev_api;
+ sd->grp_id = FIMC_GROUP_ID;
+
+ ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
+ if (ret) {
+ v4l2_err(&fmd->v4l2_dev, "Failed to register FIMC.%d (%d)\n",
+ fimc->id, ret);
+ }
+
+ return ret;
+}
+
+static int fimc_lite_register_callback(struct device *dev, void *p)
+{
+ struct fimc_lite *fimc = dev_get_drvdata(dev);
+ struct v4l2_subdev *sd = &fimc->subdev;
+ struct fimc_md *fmd = p;
+ int ret;
+
+ if (fimc == NULL)
+ return 0;
+
+ if (fimc->index >= FIMC_LITE_MAX_DEVS)
+ return 0;
+
+ fmd->fimc_lite[fimc->index] = fimc;
+ sd->grp_id = FLITE_GROUP_ID;
+
+ ret = v4l2_device_register_subdev(&fmd->v4l2_dev, sd);
+ if (ret) {
+ v4l2_err(&fmd->v4l2_dev,
+ "Failed to register FIMC-LITE.%d (%d)\n",
+ fimc->index, ret);
+ }
return ret;
}
@@ -336,22 +409,56 @@ static int csis_register_callback(struct device *dev, void *p)
*/
static int fimc_md_register_platform_entities(struct fimc_md *fmd)
{
+ struct s5p_platform_fimc *pdata = fmd->pdev->dev.platform_data;
struct device_driver *driver;
- int ret;
+ int ret, i;
driver = driver_find(FIMC_MODULE_NAME, &platform_bus_type);
- if (!driver)
- return -ENODEV;
+ if (!driver) {
+ v4l2_warn(&fmd->v4l2_dev,
+ "%s driver not found, deffering probe\n",
+ FIMC_MODULE_NAME);
+ return -EPROBE_DEFER;
+ }
+
ret = driver_for_each_device(driver, NULL, fmd,
fimc_register_callback);
if (ret)
return ret;
- driver = driver_find(CSIS_DRIVER_NAME, &platform_bus_type);
- if (driver)
+ driver = driver_find(FIMC_LITE_DRV_NAME, &platform_bus_type);
+ if (driver && try_module_get(driver->owner)) {
ret = driver_for_each_device(driver, NULL, fmd,
- csis_register_callback);
- return ret;
+ fimc_lite_register_callback);
+ if (ret)
+ return ret;
+ module_put(driver->owner);
+ }
+ /*
+ * Check if there is any sensor on the MIPI-CSI2 bus and
+ * if not skip the s5p-csis module loading.
+ */
+ if (pdata == NULL)
+ return 0;
+ for (i = 0; i < pdata->num_clients; i++) {
+ if (pdata->isp_info[i].bus_type == FIMC_MIPI_CSI2) {
+ ret = 1;
+ break;
+ }
+ }
+ if (!ret)
+ return 0;
+
+ driver = driver_find(CSIS_DRIVER_NAME, &platform_bus_type);
+ if (!driver || !try_module_get(driver->owner)) {
+ v4l2_warn(&fmd->v4l2_dev,
+ "%s driver not found, deffering probe\n",
+ CSIS_DRIVER_NAME);
+ return -EPROBE_DEFER;
+ }
+
+ return driver_for_each_device(driver, NULL, fmd,
+ csis_register_callback);
}
static void fimc_md_unregister_entities(struct fimc_md *fmd)
@@ -361,14 +468,20 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd)
for (i = 0; i < FIMC_MAX_DEVS; i++) {
if (fmd->fimc[i] == NULL)
continue;
- fimc_unregister_m2m_device(fmd->fimc[i]);
- fimc_unregister_capture_device(fmd->fimc[i]);
+ v4l2_device_unregister_subdev(&fmd->fimc[i]->vid_cap.subdev);
fmd->fimc[i] = NULL;
}
+ for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
+ if (fmd->fimc_lite[i] == NULL)
+ continue;
+ v4l2_device_unregister_subdev(&fmd->fimc_lite[i]->subdev);
+ fmd->fimc_lite[i] = NULL;
+ }
for (i = 0; i < CSIS_MAX_ENTITIES; i++) {
if (fmd->csis[i].sd == NULL)
continue;
v4l2_device_unregister_subdev(fmd->csis[i].sd);
+ module_put(fmd->csis[i].sd->owner);
fmd->csis[i].sd = NULL;
}
for (i = 0; i < fmd->num_sensors; i++) {
@@ -379,35 +492,6 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd)
}
}
-static int fimc_md_register_video_nodes(struct fimc_md *fmd)
-{
- struct video_device *vdev;
- int i, ret = 0;
-
- for (i = 0; i < FIMC_MAX_DEVS && !ret; i++) {
- if (!fmd->fimc[i])
- continue;
-
- vdev = fmd->fimc[i]->m2m.vfd;
- if (vdev) {
- ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
- if (ret)
- break;
- v4l2_info(&fmd->v4l2_dev, "Registered %s as /dev/%s\n",
- vdev->name, video_device_node_name(vdev));
- }
-
- vdev = fmd->fimc[i]->vid_cap.vfd;
- if (vdev == NULL)
- continue;
- ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
- v4l2_info(&fmd->v4l2_dev, "Registered %s as /dev/%s\n",
- vdev->name, video_device_node_name(vdev));
- }
-
- return ret;
-}
-
/**
* __fimc_md_create_fimc_links - create links to all FIMC entities
* @fmd: fimc media device
@@ -416,29 +500,29 @@ static int fimc_md_register_video_nodes(struct fimc_md *fmd)
* @pad: the source entity pad index
* @fimc_id: index of the fimc device for which link should be enabled
*/
-static int __fimc_md_create_fimc_links(struct fimc_md *fmd,
- struct media_entity *source,
- struct v4l2_subdev *sensor,
- int pad, int fimc_id)
+static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd,
+ struct media_entity *source,
+ struct v4l2_subdev *sensor,
+ int pad, int fimc_id)
{
struct fimc_sensor_info *s_info;
struct media_entity *sink;
- unsigned int flags;
+ unsigned int flags = 0;
int ret, i;
for (i = 0; i < FIMC_MAX_DEVS; i++) {
if (!fmd->fimc[i])
- break;
+ continue;
/*
* Some FIMC variants are not fitted with camera capture
* interface. Skip creating a link from sensor for those.
*/
- if (sensor->grp_id == SENSOR_GROUP_ID &&
- !fmd->fimc[i]->variant->has_cam_if)
+ if (!fmd->fimc[i]->variant->has_cam_if)
continue;
flags = (i == fimc_id) ? MEDIA_LNK_FL_ENABLED : 0;
- sink = &fmd->fimc[i]->vid_cap.subdev->entity;
+
+ sink = &fmd->fimc[i]->vid_cap.subdev.entity;
ret = media_entity_create_link(source, pad, sink,
FIMC_SD_PAD_SINK, flags);
if (ret)
@@ -453,7 +537,7 @@ static int __fimc_md_create_fimc_links(struct fimc_md *fmd,
v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]",
source->name, flags ? '=' : '-', sink->name);
- if (flags == 0)
+ if (flags == 0 || sensor == NULL)
continue;
s_info = v4l2_get_subdev_hostdata(sensor);
if (!WARN_ON(s_info == NULL)) {
@@ -463,9 +547,55 @@ static int __fimc_md_create_fimc_links(struct fimc_md *fmd,
spin_unlock_irqrestore(&fmd->slock, irq_flags);
}
}
+
+ for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
+ if (!fmd->fimc_lite[i])
+ continue;
+
+ flags = (i == fimc_id) ? MEDIA_LNK_FL_ENABLED : 0;
+
+ sink = &fmd->fimc_lite[i]->subdev.entity;
+ ret = media_entity_create_link(source, pad, sink,
+ FLITE_SD_PAD_SINK, flags);
+ if (ret)
+ return ret;
+
+ /* Notify FIMC-LITE subdev entity */
+ ret = media_entity_call(sink, link_setup, &sink->pads[0],
+ &source->pads[pad], flags);
+ if (ret)
+ break;
+
+ v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]",
+ source->name, flags ? '=' : '-', sink->name);
+ }
return 0;
}
+/* Create links from FIMC-LITE source pads to other entities */
+static int __fimc_md_create_flite_source_links(struct fimc_md *fmd)
+{
+ struct media_entity *source, *sink;
+ unsigned int flags = MEDIA_LNK_FL_ENABLED;
+ int i, ret;
+
+ for (i = 0; i < FIMC_LITE_MAX_DEVS; i++) {
+ struct fimc_lite *fimc = fmd->fimc_lite[i];
+ if (fimc == NULL)
+ continue;
+ source = &fimc->subdev.entity;
+ sink = &fimc->vfd->entity;
+ /* FIMC-LITE's subdev and video node */
+ ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE,
+ sink, 0, flags);
+ if (ret)
+ break;
+ /* TODO: create links to other entities */
+ }
+
+ return ret;
+}
+
/**
* fimc_md_create_links - create default links between registered entities
*
@@ -522,8 +652,7 @@ static int fimc_md_create_links(struct fimc_md *fmd)
v4l2_info(&fmd->v4l2_dev, "created link [%s] => [%s]",
sensor->entity.name, csis->entity.name);
- source = &csis->entity;
- pad = CSIS_PAD_SOURCE;
+ source = NULL;
break;
case FIMC_ITU_601...FIMC_ITU_656:
@@ -539,15 +668,27 @@ static int fimc_md_create_links(struct fimc_md *fmd)
if (source == NULL)
continue;
- ret = __fimc_md_create_fimc_links(fmd, source, sensor, pad,
- fimc_id++);
+ ret = __fimc_md_create_fimc_sink_links(fmd, source, sensor,
+ pad, fimc_id++);
}
+
+ fimc_id = 0;
+ for (i = 0; i < ARRAY_SIZE(fmd->csis); i++) {
+ if (fmd->csis[i].sd == NULL)
+ continue;
+ source = &fmd->csis[i].sd->entity;
+ pad = CSIS_PAD_SOURCE;
+
+ ret = __fimc_md_create_fimc_sink_links(fmd, source, NULL,
+ pad, fimc_id++);
+ }
+
/* Create immutable links between each FIMC's subdev and video node */
flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED;
for (i = 0; i < FIMC_MAX_DEVS; i++) {
if (!fmd->fimc[i])
continue;
- source = &fmd->fimc[i]->vid_cap.subdev->entity;
+ source = &fmd->fimc[i]->vid_cap.subdev.entity;
sink = &fmd->fimc[i]->vid_cap.vfd->entity;
ret = media_entity_create_link(source, FIMC_SD_PAD_SOURCE,
sink, 0, flags);
@@ -555,7 +696,7 @@ static int fimc_md_create_links(struct fimc_md *fmd)
break;
}
- return ret;
+ return __fimc_md_create_flite_source_links(fmd);
}
/*
@@ -663,24 +804,40 @@ int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on)
static int fimc_md_link_notify(struct media_pad *source,
struct media_pad *sink, u32 flags)
{
+ struct fimc_lite *fimc_lite = NULL;
+ struct fimc_dev *fimc = NULL;
+ struct fimc_pipeline *pipeline;
struct v4l2_subdev *sd;
- struct fimc_dev *fimc;
int ret = 0;
if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
return 0;
sd = media_entity_to_v4l2_subdev(sink->entity);
- fimc = v4l2_get_subdevdata(sd);
- if (!(flags & MEDIA_LNK_FL_ENABLED)) {
- ret = __fimc_pipeline_shutdown(fimc);
- fimc->pipeline.sensor = NULL;
- fimc->pipeline.csis = NULL;
+ switch (sd->grp_id) {
+ case FLITE_GROUP_ID:
+ fimc_lite = v4l2_get_subdevdata(sd);
+ pipeline = &fimc_lite->pipeline;
+ break;
+ case FIMC_GROUP_ID:
+ fimc = v4l2_get_subdevdata(sd);
+ pipeline = &fimc->pipeline;
+ break;
+ default:
+ return 0;
+ }
- mutex_lock(&fimc->lock);
- fimc_ctrls_delete(fimc->vid_cap.ctx);
- mutex_unlock(&fimc->lock);
+ if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+ ret = __fimc_pipeline_shutdown(pipeline);
+ pipeline->subdevs[IDX_SENSOR] = NULL;
+ pipeline->subdevs[IDX_CSIS] = NULL;
+
+ if (fimc) {
+ mutex_lock(&fimc->lock);
+ fimc_ctrls_delete(fimc->vid_cap.ctx);
+ mutex_unlock(&fimc->lock);
+ }
return ret;
}
/*
@@ -688,14 +845,23 @@ static int fimc_md_link_notify(struct media_pad *source,
* pipeline is already in use, i.e. its video node is opened.
* Recreate the controls destroyed during the link deactivation.
*/
- mutex_lock(&fimc->lock);
- if (fimc->vid_cap.refcnt > 0) {
- ret = __fimc_pipeline_initialize(fimc, source->entity, true);
+ if (fimc) {
+ mutex_lock(&fimc->lock);
+ if (fimc->vid_cap.refcnt > 0) {
+ ret = __fimc_pipeline_initialize(pipeline,
+ source->entity, true);
if (!ret)
ret = fimc_capture_ctrls_create(fimc);
+ }
+ mutex_unlock(&fimc->lock);
+ } else {
+ mutex_lock(&fimc_lite->lock);
+ if (fimc_lite->ref_count > 0) {
+ ret = __fimc_pipeline_initialize(pipeline,
+ source->entity, true);
+ }
+ mutex_unlock(&fimc_lite->lock);
}
- mutex_unlock(&fimc->lock);
-
return ret ? -EPIPE : ret;
}
@@ -744,7 +910,7 @@ static ssize_t fimc_md_sysfs_store(struct device *dev,
static DEVICE_ATTR(subdev_conf_mode, S_IWUSR | S_IRUGO,
fimc_md_sysfs_show, fimc_md_sysfs_store);
-static int __devinit fimc_md_probe(struct platform_device *pdev)
+static int fimc_md_probe(struct platform_device *pdev)
{
struct v4l2_device *v4l2_dev;
struct fimc_md *fmd;
@@ -776,42 +942,48 @@ static int __devinit fimc_md_probe(struct platform_device *pdev)
ret = media_device_register(&fmd->media_dev);
if (ret < 0) {
v4l2_err(v4l2_dev, "Failed to register media device: %d\n", ret);
- goto err2;
+ goto err_md;
}
ret = fimc_md_get_clocks(fmd);
if (ret)
- goto err3;
+ goto err_clk;
fmd->user_subdev_api = false;
+
+ /* Protect the media graph while we're registering entities */
+ mutex_lock(&fmd->media_dev.graph_mutex);
+
ret = fimc_md_register_platform_entities(fmd);
if (ret)
- goto err3;
+ goto err_unlock;
if (pdev->dev.platform_data) {
ret = fimc_md_register_sensor_entities(fmd);
if (ret)
- goto err3;
+ goto err_unlock;
}
ret = fimc_md_create_links(fmd);
if (ret)
- goto err3;
+ goto err_unlock;
ret = v4l2_device_register_subdev_nodes(&fmd->v4l2_dev);
if (ret)
- goto err3;
- ret = fimc_md_register_video_nodes(fmd);
- if (ret)
- goto err3;
+ goto err_unlock;
ret = device_create_file(&pdev->dev, &dev_attr_subdev_conf_mode);
- if (!ret) {
- platform_set_drvdata(pdev, fmd);
- return 0;
- }
-err3:
+ if (ret)
+ goto err_unlock;
+
+ platform_set_drvdata(pdev, fmd);
+ mutex_unlock(&fmd->media_dev.graph_mutex);
+ return 0;
+
+err_unlock:
+ mutex_unlock(&fmd->media_dev.graph_mutex);
+err_clk:
media_device_unregister(&fmd->media_dev);
fimc_md_put_clocks(fmd);
fimc_md_unregister_entities(fmd);
-err2:
+err_md:
v4l2_device_unregister(&fmd->v4l2_dev);
return ret;
}
@@ -841,10 +1013,12 @@ static struct platform_driver fimc_md_driver = {
int __init fimc_md_init(void)
{
int ret;
+
request_module("s5p-csis");
ret = fimc_register_driver();
if (ret)
return ret;
+
return platform_driver_register(&fimc_md_driver);
}
void __exit fimc_md_exit(void)
diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.h b/drivers/media/video/s5p-fimc/fimc-mdevice.h
index da3780823e7d..3b8a3492a176 100644
--- a/drivers/media/video/s5p-fimc/fimc-mdevice.h
+++ b/drivers/media/video/s5p-fimc/fimc-mdevice.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd.
*
* 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
@@ -18,12 +18,15 @@
#include <media/v4l2-subdev.h>
#include "fimc-core.h"
+#include "fimc-lite.h"
#include "mipi-csis.h"
-/* Group IDs of sensor, MIPI CSIS and the writeback subdevs. */
+/* Group IDs of sensor, MIPI-CSIS, FIMC-LITE and the writeback subdevs. */
#define SENSOR_GROUP_ID (1 << 8)
#define CSIS_GROUP_ID (1 << 9)
#define WRITEBACK_GROUP_ID (1 << 10)
+#define FIMC_GROUP_ID (1 << 11)
+#define FLITE_GROUP_ID (1 << 12)
#define FIMC_MAX_SENSORS 8
#define FIMC_MAX_CAMCLKS 2
@@ -73,6 +76,7 @@ struct fimc_md {
struct fimc_sensor_info sensor[FIMC_MAX_SENSORS];
int num_sensors;
struct fimc_camclk_info camclk[FIMC_MAX_CAMCLKS];
+ struct fimc_lite *fimc_lite[FIMC_LITE_MAX_DEVS];
struct fimc_dev *fimc[FIMC_MAX_DEVS];
struct media_device media_dev;
struct v4l2_device v4l2_dev;
@@ -108,11 +112,11 @@ static inline void fimc_md_graph_unlock(struct fimc_dev *fimc)
}
int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on);
-void fimc_pipeline_prepare(struct fimc_dev *fimc, struct media_entity *me);
-int fimc_pipeline_initialize(struct fimc_dev *fimc, struct media_entity *me,
+void fimc_pipeline_prepare(struct fimc_pipeline *p, struct media_entity *me);
+int fimc_pipeline_initialize(struct fimc_pipeline *p, struct media_entity *me,
bool resume);
-int fimc_pipeline_shutdown(struct fimc_dev *fimc);
-int fimc_pipeline_s_power(struct fimc_dev *fimc, int state);
-int fimc_pipeline_s_stream(struct fimc_dev *fimc, int state);
+int fimc_pipeline_shutdown(struct fimc_pipeline *p);
+int fimc_pipeline_s_power(struct fimc_pipeline *p, bool state);
+int fimc_pipeline_s_stream(struct fimc_pipeline *p, bool state);
#endif
diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c
index 15466d0529c1..1fc4ce8446f5 100644
--- a/drivers/media/video/s5p-fimc/fimc-reg.c
+++ b/drivers/media/video/s5p-fimc/fimc-reg.c
@@ -1,9 +1,8 @@
/*
* Register interface file for Samsung Camera Interface (FIMC) driver
*
- * Copyright (c) 2010 Samsung Electronics
- *
- * Sylwester Nawrocki, s.nawrocki@samsung.com
+ * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki, <s.nawrocki@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
@@ -12,9 +11,9 @@
#include <linux/io.h>
#include <linux/delay.h>
-#include <mach/map.h>
#include <media/s5p_fimc.h>
+#include "fimc-reg.h"
#include "fimc-core.h"
@@ -22,19 +21,19 @@ void fimc_hw_reset(struct fimc_dev *dev)
{
u32 cfg;
- cfg = readl(dev->regs + S5P_CISRCFMT);
- cfg |= S5P_CISRCFMT_ITU601_8BIT;
- writel(cfg, dev->regs + S5P_CISRCFMT);
+ cfg = readl(dev->regs + FIMC_REG_CISRCFMT);
+ cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT;
+ writel(cfg, dev->regs + FIMC_REG_CISRCFMT);
/* Software reset. */
- cfg = readl(dev->regs + S5P_CIGCTRL);
- cfg |= (S5P_CIGCTRL_SWRST | S5P_CIGCTRL_IRQ_LEVEL);
- writel(cfg, dev->regs + S5P_CIGCTRL);
+ cfg = readl(dev->regs + FIMC_REG_CIGCTRL);
+ cfg |= (FIMC_REG_CIGCTRL_SWRST | FIMC_REG_CIGCTRL_IRQ_LEVEL);
+ writel(cfg, dev->regs + FIMC_REG_CIGCTRL);
udelay(10);
- cfg = readl(dev->regs + S5P_CIGCTRL);
- cfg &= ~S5P_CIGCTRL_SWRST;
- writel(cfg, dev->regs + S5P_CIGCTRL);
+ cfg = readl(dev->regs + FIMC_REG_CIGCTRL);
+ cfg &= ~FIMC_REG_CIGCTRL_SWRST;
+ writel(cfg, dev->regs + FIMC_REG_CIGCTRL);
if (dev->variant->out_buf_count > 4)
fimc_hw_set_dma_seq(dev, 0xF);
@@ -42,32 +41,32 @@ void fimc_hw_reset(struct fimc_dev *dev)
static u32 fimc_hw_get_in_flip(struct fimc_ctx *ctx)
{
- u32 flip = S5P_MSCTRL_FLIP_NORMAL;
+ u32 flip = FIMC_REG_MSCTRL_FLIP_NORMAL;
if (ctx->hflip)
- flip = S5P_MSCTRL_FLIP_X_MIRROR;
+ flip = FIMC_REG_MSCTRL_FLIP_X_MIRROR;
if (ctx->vflip)
- flip = S5P_MSCTRL_FLIP_Y_MIRROR;
+ flip = FIMC_REG_MSCTRL_FLIP_Y_MIRROR;
if (ctx->rotation <= 90)
return flip;
- return (flip ^ S5P_MSCTRL_FLIP_180) & S5P_MSCTRL_FLIP_180;
+ return (flip ^ FIMC_REG_MSCTRL_FLIP_180) & FIMC_REG_MSCTRL_FLIP_180;
}
static u32 fimc_hw_get_target_flip(struct fimc_ctx *ctx)
{
- u32 flip = S5P_CITRGFMT_FLIP_NORMAL;
+ u32 flip = FIMC_REG_CITRGFMT_FLIP_NORMAL;
if (ctx->hflip)
- flip |= S5P_CITRGFMT_FLIP_X_MIRROR;
+ flip |= FIMC_REG_CITRGFMT_FLIP_X_MIRROR;
if (ctx->vflip)
- flip |= S5P_CITRGFMT_FLIP_Y_MIRROR;
+ flip |= FIMC_REG_CITRGFMT_FLIP_Y_MIRROR;
if (ctx->rotation <= 90)
return flip;
- return (flip ^ S5P_CITRGFMT_FLIP_180) & S5P_CITRGFMT_FLIP_180;
+ return (flip ^ FIMC_REG_CITRGFMT_FLIP_180) & FIMC_REG_CITRGFMT_FLIP_180;
}
void fimc_hw_set_rotation(struct fimc_ctx *ctx)
@@ -75,9 +74,9 @@ void fimc_hw_set_rotation(struct fimc_ctx *ctx)
u32 cfg, flip;
struct fimc_dev *dev = ctx->fimc_dev;
- cfg = readl(dev->regs + S5P_CITRGFMT);
- cfg &= ~(S5P_CITRGFMT_INROT90 | S5P_CITRGFMT_OUTROT90 |
- S5P_CITRGFMT_FLIP_180);
+ cfg = readl(dev->regs + FIMC_REG_CITRGFMT);
+ cfg &= ~(FIMC_REG_CITRGFMT_INROT90 | FIMC_REG_CITRGFMT_OUTROT90 |
+ FIMC_REG_CITRGFMT_FLIP_180);
/*
* The input and output rotator cannot work simultaneously.
@@ -85,21 +84,21 @@ void fimc_hw_set_rotation(struct fimc_ctx *ctx)
* in direct fifo output mode.
*/
if (ctx->rotation == 90 || ctx->rotation == 270) {
- if (ctx->out_path == FIMC_LCDFIFO)
- cfg |= S5P_CITRGFMT_INROT90;
+ if (ctx->out_path == FIMC_IO_LCDFIFO)
+ cfg |= FIMC_REG_CITRGFMT_INROT90;
else
- cfg |= S5P_CITRGFMT_OUTROT90;
+ cfg |= FIMC_REG_CITRGFMT_OUTROT90;
}
- if (ctx->out_path == FIMC_DMA) {
+ if (ctx->out_path == FIMC_IO_DMA) {
cfg |= fimc_hw_get_target_flip(ctx);
- writel(cfg, dev->regs + S5P_CITRGFMT);
+ writel(cfg, dev->regs + FIMC_REG_CITRGFMT);
} else {
/* LCD FIFO path */
- flip = readl(dev->regs + S5P_MSCTRL);
- flip &= ~S5P_MSCTRL_FLIP_MASK;
+ flip = readl(dev->regs + FIMC_REG_MSCTRL);
+ flip &= ~FIMC_REG_MSCTRL_FLIP_MASK;
flip |= fimc_hw_get_in_flip(ctx);
- writel(flip, dev->regs + S5P_MSCTRL);
+ writel(flip, dev->regs + FIMC_REG_MSCTRL);
}
}
@@ -110,43 +109,40 @@ void fimc_hw_set_target_format(struct fimc_ctx *ctx)
struct fimc_frame *frame = &ctx->d_frame;
dbg("w= %d, h= %d color: %d", frame->width,
- frame->height, frame->fmt->color);
+ frame->height, frame->fmt->color);
- cfg = readl(dev->regs + S5P_CITRGFMT);
- cfg &= ~(S5P_CITRGFMT_FMT_MASK | S5P_CITRGFMT_HSIZE_MASK |
- S5P_CITRGFMT_VSIZE_MASK);
+ cfg = readl(dev->regs + FIMC_REG_CITRGFMT);
+ cfg &= ~(FIMC_REG_CITRGFMT_FMT_MASK | FIMC_REG_CITRGFMT_HSIZE_MASK |
+ FIMC_REG_CITRGFMT_VSIZE_MASK);
switch (frame->fmt->color) {
- case S5P_FIMC_RGB444...S5P_FIMC_RGB888:
- cfg |= S5P_CITRGFMT_RGB;
+ case FIMC_FMT_RGB444...FIMC_FMT_RGB888:
+ cfg |= FIMC_REG_CITRGFMT_RGB;
break;
- case S5P_FIMC_YCBCR420:
- cfg |= S5P_CITRGFMT_YCBCR420;
+ case FIMC_FMT_YCBCR420:
+ cfg |= FIMC_REG_CITRGFMT_YCBCR420;
break;
- case S5P_FIMC_YCBYCR422...S5P_FIMC_CRYCBY422:
+ case FIMC_FMT_YCBYCR422...FIMC_FMT_CRYCBY422:
if (frame->fmt->colplanes == 1)
- cfg |= S5P_CITRGFMT_YCBCR422_1P;
+ cfg |= FIMC_REG_CITRGFMT_YCBCR422_1P;
else
- cfg |= S5P_CITRGFMT_YCBCR422;
+ cfg |= FIMC_REG_CITRGFMT_YCBCR422;
break;
default:
break;
}
- if (ctx->rotation == 90 || ctx->rotation == 270) {
- cfg |= S5P_CITRGFMT_HSIZE(frame->height);
- cfg |= S5P_CITRGFMT_VSIZE(frame->width);
- } else {
-
- cfg |= S5P_CITRGFMT_HSIZE(frame->width);
- cfg |= S5P_CITRGFMT_VSIZE(frame->height);
- }
+ if (ctx->rotation == 90 || ctx->rotation == 270)
+ cfg |= (frame->height << 16) | frame->width;
+ else
+ cfg |= (frame->width << 16) | frame->height;
- writel(cfg, dev->regs + S5P_CITRGFMT);
+ writel(cfg, dev->regs + FIMC_REG_CITRGFMT);
- cfg = readl(dev->regs + S5P_CITAREA) & ~S5P_CITAREA_MASK;
+ cfg = readl(dev->regs + FIMC_REG_CITAREA);
+ cfg &= ~FIMC_REG_CITAREA_MASK;
cfg |= (frame->width * frame->height);
- writel(cfg, dev->regs + S5P_CITAREA);
+ writel(cfg, dev->regs + FIMC_REG_CITAREA);
}
static void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx)
@@ -155,87 +151,82 @@ static void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx)
struct fimc_frame *frame = &ctx->d_frame;
u32 cfg;
- cfg = S5P_ORIG_SIZE_HOR(frame->f_width);
- cfg |= S5P_ORIG_SIZE_VER(frame->f_height);
- writel(cfg, dev->regs + S5P_ORGOSIZE);
+ cfg = (frame->f_height << 16) | frame->f_width;
+ writel(cfg, dev->regs + FIMC_REG_ORGOSIZE);
/* Select color space conversion equation (HD/SD size).*/
- cfg = readl(dev->regs + S5P_CIGCTRL);
+ cfg = readl(dev->regs + FIMC_REG_CIGCTRL);
if (frame->f_width >= 1280) /* HD */
- cfg |= S5P_CIGCTRL_CSC_ITU601_709;
+ cfg |= FIMC_REG_CIGCTRL_CSC_ITU601_709;
else /* SD */
- cfg &= ~S5P_CIGCTRL_CSC_ITU601_709;
- writel(cfg, dev->regs + S5P_CIGCTRL);
+ cfg &= ~FIMC_REG_CIGCTRL_CSC_ITU601_709;
+ writel(cfg, dev->regs + FIMC_REG_CIGCTRL);
}
void fimc_hw_set_out_dma(struct fimc_ctx *ctx)
{
- u32 cfg;
struct fimc_dev *dev = ctx->fimc_dev;
struct fimc_frame *frame = &ctx->d_frame;
struct fimc_dma_offset *offset = &frame->dma_offset;
struct fimc_fmt *fmt = frame->fmt;
+ u32 cfg;
/* Set the input dma offsets. */
- cfg = 0;
- cfg |= S5P_CIO_OFFS_HOR(offset->y_h);
- cfg |= S5P_CIO_OFFS_VER(offset->y_v);
- writel(cfg, dev->regs + S5P_CIOYOFF);
+ cfg = (offset->y_v << 16) | offset->y_h;
+ writel(cfg, dev->regs + FIMC_REG_CIOYOFF);
- cfg = 0;
- cfg |= S5P_CIO_OFFS_HOR(offset->cb_h);
- cfg |= S5P_CIO_OFFS_VER(offset->cb_v);
- writel(cfg, dev->regs + S5P_CIOCBOFF);
+ cfg = (offset->cb_v << 16) | offset->cb_h;
+ writel(cfg, dev->regs + FIMC_REG_CIOCBOFF);
- cfg = 0;
- cfg |= S5P_CIO_OFFS_HOR(offset->cr_h);
- cfg |= S5P_CIO_OFFS_VER(offset->cr_v);
- writel(cfg, dev->regs + S5P_CIOCROFF);
+ cfg = (offset->cr_v << 16) | offset->cr_h;
+ writel(cfg, dev->regs + FIMC_REG_CIOCROFF);
fimc_hw_set_out_dma_size(ctx);
/* Configure chroma components order. */
- cfg = readl(dev->regs + S5P_CIOCTRL);
+ cfg = readl(dev->regs + FIMC_REG_CIOCTRL);
- cfg &= ~(S5P_CIOCTRL_ORDER2P_MASK | S5P_CIOCTRL_ORDER422_MASK |
- S5P_CIOCTRL_YCBCR_PLANE_MASK | S5P_CIOCTRL_RGB16FMT_MASK);
+ cfg &= ~(FIMC_REG_CIOCTRL_ORDER2P_MASK |
+ FIMC_REG_CIOCTRL_ORDER422_MASK |
+ FIMC_REG_CIOCTRL_YCBCR_PLANE_MASK |
+ FIMC_REG_CIOCTRL_RGB16FMT_MASK);
if (fmt->colplanes == 1)
cfg |= ctx->out_order_1p;
else if (fmt->colplanes == 2)
- cfg |= ctx->out_order_2p | S5P_CIOCTRL_YCBCR_2PLANE;
+ cfg |= ctx->out_order_2p | FIMC_REG_CIOCTRL_YCBCR_2PLANE;
else if (fmt->colplanes == 3)
- cfg |= S5P_CIOCTRL_YCBCR_3PLANE;
+ cfg |= FIMC_REG_CIOCTRL_YCBCR_3PLANE;
- if (fmt->color == S5P_FIMC_RGB565)
- cfg |= S5P_CIOCTRL_RGB565;
- else if (fmt->color == S5P_FIMC_RGB555)
- cfg |= S5P_CIOCTRL_ARGB1555;
- else if (fmt->color == S5P_FIMC_RGB444)
- cfg |= S5P_CIOCTRL_ARGB4444;
+ if (fmt->color == FIMC_FMT_RGB565)
+ cfg |= FIMC_REG_CIOCTRL_RGB565;
+ else if (fmt->color == FIMC_FMT_RGB555)
+ cfg |= FIMC_REG_CIOCTRL_ARGB1555;
+ else if (fmt->color == FIMC_FMT_RGB444)
+ cfg |= FIMC_REG_CIOCTRL_ARGB4444;
- writel(cfg, dev->regs + S5P_CIOCTRL);
+ writel(cfg, dev->regs + FIMC_REG_CIOCTRL);
}
static void fimc_hw_en_autoload(struct fimc_dev *dev, int enable)
{
- u32 cfg = readl(dev->regs + S5P_ORGISIZE);
+ u32 cfg = readl(dev->regs + FIMC_REG_ORGISIZE);
if (enable)
- cfg |= S5P_CIREAL_ISIZE_AUTOLOAD_EN;
+ cfg |= FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN;
else
- cfg &= ~S5P_CIREAL_ISIZE_AUTOLOAD_EN;
- writel(cfg, dev->regs + S5P_ORGISIZE);
+ cfg &= ~FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN;
+ writel(cfg, dev->regs + FIMC_REG_ORGISIZE);
}
void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable)
{
- u32 cfg = readl(dev->regs + S5P_CIOCTRL);
+ u32 cfg = readl(dev->regs + FIMC_REG_CIOCTRL);
if (enable)
- cfg |= S5P_CIOCTRL_LASTIRQ_ENABLE;
+ cfg |= FIMC_REG_CIOCTRL_LASTIRQ_ENABLE;
else
- cfg &= ~S5P_CIOCTRL_LASTIRQ_ENABLE;
- writel(cfg, dev->regs + S5P_CIOCTRL);
+ cfg &= ~FIMC_REG_CIOCTRL_LASTIRQ_ENABLE;
+ writel(cfg, dev->regs + FIMC_REG_CIOCTRL);
}
void fimc_hw_set_prescaler(struct fimc_ctx *ctx)
@@ -245,15 +236,13 @@ void fimc_hw_set_prescaler(struct fimc_ctx *ctx)
u32 cfg, shfactor;
shfactor = 10 - (sc->hfactor + sc->vfactor);
+ cfg = shfactor << 28;
- cfg = S5P_CISCPRERATIO_SHFACTOR(shfactor);
- cfg |= S5P_CISCPRERATIO_HOR(sc->pre_hratio);
- cfg |= S5P_CISCPRERATIO_VER(sc->pre_vratio);
- writel(cfg, dev->regs + S5P_CISCPRERATIO);
+ cfg |= (sc->pre_hratio << 16) | sc->pre_vratio;
+ writel(cfg, dev->regs + FIMC_REG_CISCPRERATIO);
- cfg = S5P_CISCPREDST_WIDTH(sc->pre_dst_width);
- cfg |= S5P_CISCPREDST_HEIGHT(sc->pre_dst_height);
- writel(cfg, dev->regs + S5P_CISCPREDST);
+ cfg = (sc->pre_dst_width << 16) | sc->pre_dst_height;
+ writel(cfg, dev->regs + FIMC_REG_CISCPREDST);
}
static void fimc_hw_set_scaler(struct fimc_ctx *ctx)
@@ -263,93 +252,95 @@ static void fimc_hw_set_scaler(struct fimc_ctx *ctx)
struct fimc_frame *src_frame = &ctx->s_frame;
struct fimc_frame *dst_frame = &ctx->d_frame;
- u32 cfg = readl(dev->regs + S5P_CISCCTRL);
+ u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL);
- cfg &= ~(S5P_CISCCTRL_CSCR2Y_WIDE | S5P_CISCCTRL_CSCY2R_WIDE |
- S5P_CISCCTRL_SCALEUP_H | S5P_CISCCTRL_SCALEUP_V |
- S5P_CISCCTRL_SCALERBYPASS | S5P_CISCCTRL_ONE2ONE |
- S5P_CISCCTRL_INRGB_FMT_MASK | S5P_CISCCTRL_OUTRGB_FMT_MASK |
- S5P_CISCCTRL_INTERLACE | S5P_CISCCTRL_RGB_EXT);
+ cfg &= ~(FIMC_REG_CISCCTRL_CSCR2Y_WIDE | FIMC_REG_CISCCTRL_CSCY2R_WIDE |
+ FIMC_REG_CISCCTRL_SCALEUP_H | FIMC_REG_CISCCTRL_SCALEUP_V |
+ FIMC_REG_CISCCTRL_SCALERBYPASS | FIMC_REG_CISCCTRL_ONE2ONE |
+ FIMC_REG_CISCCTRL_INRGB_FMT_MASK | FIMC_REG_CISCCTRL_OUTRGB_FMT_MASK |
+ FIMC_REG_CISCCTRL_INTERLACE | FIMC_REG_CISCCTRL_RGB_EXT);
if (!(ctx->flags & FIMC_COLOR_RANGE_NARROW))
- cfg |= (S5P_CISCCTRL_CSCR2Y_WIDE | S5P_CISCCTRL_CSCY2R_WIDE);
+ cfg |= (FIMC_REG_CISCCTRL_CSCR2Y_WIDE |
+ FIMC_REG_CISCCTRL_CSCY2R_WIDE);
if (!sc->enabled)
- cfg |= S5P_CISCCTRL_SCALERBYPASS;
+ cfg |= FIMC_REG_CISCCTRL_SCALERBYPASS;
if (sc->scaleup_h)
- cfg |= S5P_CISCCTRL_SCALEUP_H;
+ cfg |= FIMC_REG_CISCCTRL_SCALEUP_H;
if (sc->scaleup_v)
- cfg |= S5P_CISCCTRL_SCALEUP_V;
+ cfg |= FIMC_REG_CISCCTRL_SCALEUP_V;
if (sc->copy_mode)
- cfg |= S5P_CISCCTRL_ONE2ONE;
+ cfg |= FIMC_REG_CISCCTRL_ONE2ONE;
- if (ctx->in_path == FIMC_DMA) {
+ if (ctx->in_path == FIMC_IO_DMA) {
switch (src_frame->fmt->color) {
- case S5P_FIMC_RGB565:
- cfg |= S5P_CISCCTRL_INRGB_FMT_RGB565;
+ case FIMC_FMT_RGB565:
+ cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB565;
break;
- case S5P_FIMC_RGB666:
- cfg |= S5P_CISCCTRL_INRGB_FMT_RGB666;
+ case FIMC_FMT_RGB666:
+ cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB666;
break;
- case S5P_FIMC_RGB888:
- cfg |= S5P_CISCCTRL_INRGB_FMT_RGB888;
+ case FIMC_FMT_RGB888:
+ cfg |= FIMC_REG_CISCCTRL_INRGB_FMT_RGB888;
break;
}
}
- if (ctx->out_path == FIMC_DMA) {
+ if (ctx->out_path == FIMC_IO_DMA) {
u32 color = dst_frame->fmt->color;
- if (color >= S5P_FIMC_RGB444 && color <= S5P_FIMC_RGB565)
- cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB565;
- else if (color == S5P_FIMC_RGB666)
- cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB666;
- else if (color == S5P_FIMC_RGB888)
- cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888;
+ if (color >= FIMC_FMT_RGB444 && color <= FIMC_FMT_RGB565)
+ cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB565;
+ else if (color == FIMC_FMT_RGB666)
+ cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB666;
+ else if (color == FIMC_FMT_RGB888)
+ cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888;
} else {
- cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888;
+ cfg |= FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888;
if (ctx->flags & FIMC_SCAN_MODE_INTERLACED)
- cfg |= S5P_CISCCTRL_INTERLACE;
+ cfg |= FIMC_REG_CISCCTRL_INTERLACE;
}
- writel(cfg, dev->regs + S5P_CISCCTRL);
+ writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
}
void fimc_hw_set_mainscaler(struct fimc_ctx *ctx)
{
struct fimc_dev *dev = ctx->fimc_dev;
- struct samsung_fimc_variant *variant = dev->variant;
+ struct fimc_variant *variant = dev->variant;
struct fimc_scaler *sc = &ctx->scaler;
u32 cfg;
dbg("main_hratio= 0x%X main_vratio= 0x%X",
- sc->main_hratio, sc->main_vratio);
+ sc->main_hratio, sc->main_vratio);
fimc_hw_set_scaler(ctx);
- cfg = readl(dev->regs + S5P_CISCCTRL);
- cfg &= ~(S5P_CISCCTRL_MHRATIO_MASK | S5P_CISCCTRL_MVRATIO_MASK);
+ cfg = readl(dev->regs + FIMC_REG_CISCCTRL);
+ cfg &= ~(FIMC_REG_CISCCTRL_MHRATIO_MASK |
+ FIMC_REG_CISCCTRL_MVRATIO_MASK);
if (variant->has_mainscaler_ext) {
- cfg |= S5P_CISCCTRL_MHRATIO_EXT(sc->main_hratio);
- cfg |= S5P_CISCCTRL_MVRATIO_EXT(sc->main_vratio);
- writel(cfg, dev->regs + S5P_CISCCTRL);
+ cfg |= FIMC_REG_CISCCTRL_MHRATIO_EXT(sc->main_hratio);
+ cfg |= FIMC_REG_CISCCTRL_MVRATIO_EXT(sc->main_vratio);
+ writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
- cfg = readl(dev->regs + S5P_CIEXTEN);
+ cfg = readl(dev->regs + FIMC_REG_CIEXTEN);
- cfg &= ~(S5P_CIEXTEN_MVRATIO_EXT_MASK |
- S5P_CIEXTEN_MHRATIO_EXT_MASK);
- cfg |= S5P_CIEXTEN_MHRATIO_EXT(sc->main_hratio);
- cfg |= S5P_CIEXTEN_MVRATIO_EXT(sc->main_vratio);
- writel(cfg, dev->regs + S5P_CIEXTEN);
+ cfg &= ~(FIMC_REG_CIEXTEN_MVRATIO_EXT_MASK |
+ FIMC_REG_CIEXTEN_MHRATIO_EXT_MASK);
+ cfg |= FIMC_REG_CIEXTEN_MHRATIO_EXT(sc->main_hratio);
+ cfg |= FIMC_REG_CIEXTEN_MVRATIO_EXT(sc->main_vratio);
+ writel(cfg, dev->regs + FIMC_REG_CIEXTEN);
} else {
- cfg |= S5P_CISCCTRL_MHRATIO(sc->main_hratio);
- cfg |= S5P_CISCCTRL_MVRATIO(sc->main_vratio);
- writel(cfg, dev->regs + S5P_CISCCTRL);
+ cfg |= FIMC_REG_CISCCTRL_MHRATIO(sc->main_hratio);
+ cfg |= FIMC_REG_CISCCTRL_MVRATIO(sc->main_vratio);
+ writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
}
}
@@ -357,40 +348,41 @@ void fimc_hw_en_capture(struct fimc_ctx *ctx)
{
struct fimc_dev *dev = ctx->fimc_dev;
- u32 cfg = readl(dev->regs + S5P_CIIMGCPT);
+ u32 cfg = readl(dev->regs + FIMC_REG_CIIMGCPT);
- if (ctx->out_path == FIMC_DMA) {
+ if (ctx->out_path == FIMC_IO_DMA) {
/* one shot mode */
- cfg |= S5P_CIIMGCPT_CPT_FREN_ENABLE | S5P_CIIMGCPT_IMGCPTEN;
+ cfg |= FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE |
+ FIMC_REG_CIIMGCPT_IMGCPTEN;
} else {
/* Continuous frame capture mode (freerun). */
- cfg &= ~(S5P_CIIMGCPT_CPT_FREN_ENABLE |
- S5P_CIIMGCPT_CPT_FRMOD_CNT);
- cfg |= S5P_CIIMGCPT_IMGCPTEN;
+ cfg &= ~(FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE |
+ FIMC_REG_CIIMGCPT_CPT_FRMOD_CNT);
+ cfg |= FIMC_REG_CIIMGCPT_IMGCPTEN;
}
if (ctx->scaler.enabled)
- cfg |= S5P_CIIMGCPT_IMGCPTEN_SC;
+ cfg |= FIMC_REG_CIIMGCPT_IMGCPTEN_SC;
- writel(cfg | S5P_CIIMGCPT_IMGCPTEN, dev->regs + S5P_CIIMGCPT);
+ cfg |= FIMC_REG_CIIMGCPT_IMGCPTEN;
+ writel(cfg, dev->regs + FIMC_REG_CIIMGCPT);
}
-void fimc_hw_set_effect(struct fimc_ctx *ctx, bool active)
+void fimc_hw_set_effect(struct fimc_ctx *ctx)
{
struct fimc_dev *dev = ctx->fimc_dev;
struct fimc_effect *effect = &ctx->effect;
u32 cfg = 0;
- if (active) {
- cfg |= S5P_CIIMGEFF_IE_SC_AFTER | S5P_CIIMGEFF_IE_ENABLE;
+ if (effect->type != FIMC_REG_CIIMGEFF_FIN_BYPASS) {
+ cfg |= FIMC_REG_CIIMGEFF_IE_SC_AFTER |
+ FIMC_REG_CIIMGEFF_IE_ENABLE;
cfg |= effect->type;
- if (effect->type == S5P_FIMC_EFFECT_ARBITRARY) {
- cfg |= S5P_CIIMGEFF_PAT_CB(effect->pat_cb);
- cfg |= S5P_CIIMGEFF_PAT_CR(effect->pat_cr);
- }
+ if (effect->type == FIMC_REG_CIIMGEFF_FIN_ARBITRARY)
+ cfg |= (effect->pat_cb << 13) | effect->pat_cr;
}
- writel(cfg, dev->regs + S5P_CIIMGEFF);
+ writel(cfg, dev->regs + FIMC_REG_CIIMGEFF);
}
void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx)
@@ -402,10 +394,10 @@ void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx)
if (!(frame->fmt->flags & FMT_HAS_ALPHA))
return;
- cfg = readl(dev->regs + S5P_CIOCTRL);
- cfg &= ~S5P_CIOCTRL_ALPHA_OUT_MASK;
+ cfg = readl(dev->regs + FIMC_REG_CIOCTRL);
+ cfg &= ~FIMC_REG_CIOCTRL_ALPHA_OUT_MASK;
cfg |= (frame->alpha << 4);
- writel(cfg, dev->regs + S5P_CIOCTRL);
+ writel(cfg, dev->regs + FIMC_REG_CIOCTRL);
}
static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx)
@@ -415,16 +407,14 @@ static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx)
u32 cfg_o = 0;
u32 cfg_r = 0;
- if (FIMC_LCDFIFO == ctx->out_path)
- cfg_r |= S5P_CIREAL_ISIZE_AUTOLOAD_EN;
+ if (FIMC_IO_LCDFIFO == ctx->out_path)
+ cfg_r |= FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN;
- cfg_o |= S5P_ORIG_SIZE_HOR(frame->f_width);
- cfg_o |= S5P_ORIG_SIZE_VER(frame->f_height);
- cfg_r |= S5P_CIREAL_ISIZE_WIDTH(frame->width);
- cfg_r |= S5P_CIREAL_ISIZE_HEIGHT(frame->height);
+ cfg_o |= (frame->f_height << 16) | frame->f_width;
+ cfg_r |= (frame->height << 16) | frame->width;
- writel(cfg_o, dev->regs + S5P_ORGISIZE);
- writel(cfg_r, dev->regs + S5P_CIREAL_ISIZE);
+ writel(cfg_o, dev->regs + FIMC_REG_ORGISIZE);
+ writel(cfg_r, dev->regs + FIMC_REG_CIREAL_ISIZE);
}
void fimc_hw_set_in_dma(struct fimc_ctx *ctx)
@@ -435,80 +425,77 @@ void fimc_hw_set_in_dma(struct fimc_ctx *ctx)
u32 cfg;
/* Set the pixel offsets. */
- cfg = S5P_CIO_OFFS_HOR(offset->y_h);
- cfg |= S5P_CIO_OFFS_VER(offset->y_v);
- writel(cfg, dev->regs + S5P_CIIYOFF);
+ cfg = (offset->y_v << 16) | offset->y_h;
+ writel(cfg, dev->regs + FIMC_REG_CIIYOFF);
- cfg = S5P_CIO_OFFS_HOR(offset->cb_h);
- cfg |= S5P_CIO_OFFS_VER(offset->cb_v);
- writel(cfg, dev->regs + S5P_CIICBOFF);
+ cfg = (offset->cb_v << 16) | offset->cb_h;
+ writel(cfg, dev->regs + FIMC_REG_CIICBOFF);
- cfg = S5P_CIO_OFFS_HOR(offset->cr_h);
- cfg |= S5P_CIO_OFFS_VER(offset->cr_v);
- writel(cfg, dev->regs + S5P_CIICROFF);
+ cfg = (offset->cr_v << 16) | offset->cr_h;
+ writel(cfg, dev->regs + FIMC_REG_CIICROFF);
/* Input original and real size. */
fimc_hw_set_in_dma_size(ctx);
/* Use DMA autoload only in FIFO mode. */
- fimc_hw_en_autoload(dev, ctx->out_path == FIMC_LCDFIFO);
+ fimc_hw_en_autoload(dev, ctx->out_path == FIMC_IO_LCDFIFO);
/* Set the input DMA to process single frame only. */
- cfg = readl(dev->regs + S5P_MSCTRL);
- cfg &= ~(S5P_MSCTRL_INFORMAT_MASK
- | S5P_MSCTRL_IN_BURST_COUNT_MASK
- | S5P_MSCTRL_INPUT_MASK
- | S5P_MSCTRL_C_INT_IN_MASK
- | S5P_MSCTRL_2P_IN_ORDER_MASK);
+ cfg = readl(dev->regs + FIMC_REG_MSCTRL);
+ cfg &= ~(FIMC_REG_MSCTRL_INFORMAT_MASK
+ | FIMC_REG_MSCTRL_IN_BURST_COUNT_MASK
+ | FIMC_REG_MSCTRL_INPUT_MASK
+ | FIMC_REG_MSCTRL_C_INT_IN_MASK
+ | FIMC_REG_MSCTRL_2P_IN_ORDER_MASK);
- cfg |= (S5P_MSCTRL_IN_BURST_COUNT(4)
- | S5P_MSCTRL_INPUT_MEMORY
- | S5P_MSCTRL_FIFO_CTRL_FULL);
+ cfg |= (FIMC_REG_MSCTRL_IN_BURST_COUNT(4)
+ | FIMC_REG_MSCTRL_INPUT_MEMORY
+ | FIMC_REG_MSCTRL_FIFO_CTRL_FULL);
switch (frame->fmt->color) {
- case S5P_FIMC_RGB565...S5P_FIMC_RGB888:
- cfg |= S5P_MSCTRL_INFORMAT_RGB;
+ case FIMC_FMT_RGB565...FIMC_FMT_RGB888:
+ cfg |= FIMC_REG_MSCTRL_INFORMAT_RGB;
break;
- case S5P_FIMC_YCBCR420:
- cfg |= S5P_MSCTRL_INFORMAT_YCBCR420;
+ case FIMC_FMT_YCBCR420:
+ cfg |= FIMC_REG_MSCTRL_INFORMAT_YCBCR420;
if (frame->fmt->colplanes == 2)
- cfg |= ctx->in_order_2p | S5P_MSCTRL_C_INT_IN_2PLANE;
+ cfg |= ctx->in_order_2p | FIMC_REG_MSCTRL_C_INT_IN_2PLANE;
else
- cfg |= S5P_MSCTRL_C_INT_IN_3PLANE;
+ cfg |= FIMC_REG_MSCTRL_C_INT_IN_3PLANE;
break;
- case S5P_FIMC_YCBYCR422...S5P_FIMC_CRYCBY422:
+ case FIMC_FMT_YCBYCR422...FIMC_FMT_CRYCBY422:
if (frame->fmt->colplanes == 1) {
cfg |= ctx->in_order_1p
- | S5P_MSCTRL_INFORMAT_YCBCR422_1P;
+ | FIMC_REG_MSCTRL_INFORMAT_YCBCR422_1P;
} else {
- cfg |= S5P_MSCTRL_INFORMAT_YCBCR422;
+ cfg |= FIMC_REG_MSCTRL_INFORMAT_YCBCR422;
if (frame->fmt->colplanes == 2)
cfg |= ctx->in_order_2p
- | S5P_MSCTRL_C_INT_IN_2PLANE;
+ | FIMC_REG_MSCTRL_C_INT_IN_2PLANE;
else
- cfg |= S5P_MSCTRL_C_INT_IN_3PLANE;
+ cfg |= FIMC_REG_MSCTRL_C_INT_IN_3PLANE;
}
break;
default:
break;
}
- writel(cfg, dev->regs + S5P_MSCTRL);
+ writel(cfg, dev->regs + FIMC_REG_MSCTRL);
/* Input/output DMA linear/tiled mode. */
- cfg = readl(dev->regs + S5P_CIDMAPARAM);
- cfg &= ~S5P_CIDMAPARAM_TILE_MASK;
+ cfg = readl(dev->regs + FIMC_REG_CIDMAPARAM);
+ cfg &= ~FIMC_REG_CIDMAPARAM_TILE_MASK;
if (tiled_fmt(ctx->s_frame.fmt))
- cfg |= S5P_CIDMAPARAM_R_64X32;
+ cfg |= FIMC_REG_CIDMAPARAM_R_64X32;
if (tiled_fmt(ctx->d_frame.fmt))
- cfg |= S5P_CIDMAPARAM_W_64X32;
+ cfg |= FIMC_REG_CIDMAPARAM_W_64X32;
- writel(cfg, dev->regs + S5P_CIDMAPARAM);
+ writel(cfg, dev->regs + FIMC_REG_CIDMAPARAM);
}
@@ -516,40 +503,40 @@ void fimc_hw_set_input_path(struct fimc_ctx *ctx)
{
struct fimc_dev *dev = ctx->fimc_dev;
- u32 cfg = readl(dev->regs + S5P_MSCTRL);
- cfg &= ~S5P_MSCTRL_INPUT_MASK;
+ u32 cfg = readl(dev->regs + FIMC_REG_MSCTRL);
+ cfg &= ~FIMC_REG_MSCTRL_INPUT_MASK;
- if (ctx->in_path == FIMC_DMA)
- cfg |= S5P_MSCTRL_INPUT_MEMORY;
+ if (ctx->in_path == FIMC_IO_DMA)
+ cfg |= FIMC_REG_MSCTRL_INPUT_MEMORY;
else
- cfg |= S5P_MSCTRL_INPUT_EXTCAM;
+ cfg |= FIMC_REG_MSCTRL_INPUT_EXTCAM;
- writel(cfg, dev->regs + S5P_MSCTRL);
+ writel(cfg, dev->regs + FIMC_REG_MSCTRL);
}
void fimc_hw_set_output_path(struct fimc_ctx *ctx)
{
struct fimc_dev *dev = ctx->fimc_dev;
- u32 cfg = readl(dev->regs + S5P_CISCCTRL);
- cfg &= ~S5P_CISCCTRL_LCDPATHEN_FIFO;
- if (ctx->out_path == FIMC_LCDFIFO)
- cfg |= S5P_CISCCTRL_LCDPATHEN_FIFO;
- writel(cfg, dev->regs + S5P_CISCCTRL);
+ u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL);
+ cfg &= ~FIMC_REG_CISCCTRL_LCDPATHEN_FIFO;
+ if (ctx->out_path == FIMC_IO_LCDFIFO)
+ cfg |= FIMC_REG_CISCCTRL_LCDPATHEN_FIFO;
+ writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
}
void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr)
{
- u32 cfg = readl(dev->regs + S5P_CIREAL_ISIZE);
- cfg |= S5P_CIREAL_ISIZE_ADDR_CH_DIS;
- writel(cfg, dev->regs + S5P_CIREAL_ISIZE);
+ u32 cfg = readl(dev->regs + FIMC_REG_CIREAL_ISIZE);
+ cfg |= FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS;
+ writel(cfg, dev->regs + FIMC_REG_CIREAL_ISIZE);
- writel(paddr->y, dev->regs + S5P_CIIYSA(0));
- writel(paddr->cb, dev->regs + S5P_CIICBSA(0));
- writel(paddr->cr, dev->regs + S5P_CIICRSA(0));
+ writel(paddr->y, dev->regs + FIMC_REG_CIIYSA(0));
+ writel(paddr->cb, dev->regs + FIMC_REG_CIICBSA(0));
+ writel(paddr->cr, dev->regs + FIMC_REG_CIICRSA(0));
- cfg &= ~S5P_CIREAL_ISIZE_ADDR_CH_DIS;
- writel(cfg, dev->regs + S5P_CIREAL_ISIZE);
+ cfg &= ~FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS;
+ writel(cfg, dev->regs + FIMC_REG_CIREAL_ISIZE);
}
void fimc_hw_set_output_addr(struct fimc_dev *dev,
@@ -557,9 +544,9 @@ void fimc_hw_set_output_addr(struct fimc_dev *dev,
{
int i = (index == -1) ? 0 : index;
do {
- writel(paddr->y, dev->regs + S5P_CIOYSA(i));
- writel(paddr->cb, dev->regs + S5P_CIOCBSA(i));
- writel(paddr->cr, dev->regs + S5P_CIOCRSA(i));
+ writel(paddr->y, dev->regs + FIMC_REG_CIOYSA(i));
+ writel(paddr->cb, dev->regs + FIMC_REG_CIOCBSA(i));
+ writel(paddr->cr, dev->regs + FIMC_REG_CIOCRSA(i));
dbg("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X",
i, paddr->y, paddr->cb, paddr->cr);
} while (index == -1 && ++i < FIMC_MAX_OUT_BUFS);
@@ -568,32 +555,45 @@ void fimc_hw_set_output_addr(struct fimc_dev *dev,
int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
struct s5p_fimc_isp_info *cam)
{
- u32 cfg = readl(fimc->regs + S5P_CIGCTRL);
+ u32 cfg = readl(fimc->regs + FIMC_REG_CIGCTRL);
- cfg &= ~(S5P_CIGCTRL_INVPOLPCLK | S5P_CIGCTRL_INVPOLVSYNC |
- S5P_CIGCTRL_INVPOLHREF | S5P_CIGCTRL_INVPOLHSYNC |
- S5P_CIGCTRL_INVPOLFIELD);
+ cfg &= ~(FIMC_REG_CIGCTRL_INVPOLPCLK | FIMC_REG_CIGCTRL_INVPOLVSYNC |
+ FIMC_REG_CIGCTRL_INVPOLHREF | FIMC_REG_CIGCTRL_INVPOLHSYNC |
+ FIMC_REG_CIGCTRL_INVPOLFIELD);
if (cam->flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
- cfg |= S5P_CIGCTRL_INVPOLPCLK;
+ cfg |= FIMC_REG_CIGCTRL_INVPOLPCLK;
if (cam->flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
- cfg |= S5P_CIGCTRL_INVPOLVSYNC;
+ cfg |= FIMC_REG_CIGCTRL_INVPOLVSYNC;
if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
- cfg |= S5P_CIGCTRL_INVPOLHREF;
+ cfg |= FIMC_REG_CIGCTRL_INVPOLHREF;
if (cam->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
- cfg |= S5P_CIGCTRL_INVPOLHSYNC;
+ cfg |= FIMC_REG_CIGCTRL_INVPOLHSYNC;
if (cam->flags & V4L2_MBUS_FIELD_EVEN_LOW)
- cfg |= S5P_CIGCTRL_INVPOLFIELD;
+ cfg |= FIMC_REG_CIGCTRL_INVPOLFIELD;
- writel(cfg, fimc->regs + S5P_CIGCTRL);
+ writel(cfg, fimc->regs + FIMC_REG_CIGCTRL);
return 0;
}
+struct mbus_pixfmt_desc {
+ u32 pixelcode;
+ u32 cisrcfmt;
+ u16 bus_width;
+};
+
+static const struct mbus_pixfmt_desc pix_desc[] = {
+ { V4L2_MBUS_FMT_YUYV8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCBYCR, 8 },
+ { V4L2_MBUS_FMT_YVYU8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCRYCB, 8 },
+ { V4L2_MBUS_FMT_VYUY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CRYCBY, 8 },
+ { V4L2_MBUS_FMT_UYVY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CBYCRY, 8 },
+};
+
int fimc_hw_set_camera_source(struct fimc_dev *fimc,
struct s5p_fimc_isp_info *cam)
{
@@ -602,18 +602,6 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc,
u32 bus_width;
int i;
- static const struct {
- u32 pixelcode;
- u32 cisrcfmt;
- u16 bus_width;
- } pix_desc[] = {
- { V4L2_MBUS_FMT_YUYV8_2X8, S5P_CISRCFMT_ORDER422_YCBYCR, 8 },
- { V4L2_MBUS_FMT_YVYU8_2X8, S5P_CISRCFMT_ORDER422_YCRYCB, 8 },
- { V4L2_MBUS_FMT_VYUY8_2X8, S5P_CISRCFMT_ORDER422_CRYCBY, 8 },
- { V4L2_MBUS_FMT_UYVY8_2X8, S5P_CISRCFMT_ORDER422_CBYCRY, 8 },
- /* TODO: Add pixel codes for 16-bit bus width */
- };
-
if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) {
for (i = 0; i < ARRAY_SIZE(pix_desc); i++) {
if (fimc->vid_cap.mf.code == pix_desc[i].pixelcode) {
@@ -632,41 +620,37 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc,
if (cam->bus_type == FIMC_ITU_601) {
if (bus_width == 8)
- cfg |= S5P_CISRCFMT_ITU601_8BIT;
+ cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT;
else if (bus_width == 16)
- cfg |= S5P_CISRCFMT_ITU601_16BIT;
+ cfg |= FIMC_REG_CISRCFMT_ITU601_16BIT;
} /* else defaults to ITU-R BT.656 8-bit */
} else if (cam->bus_type == FIMC_MIPI_CSI2) {
if (fimc_fmt_is_jpeg(f->fmt->color))
- cfg |= S5P_CISRCFMT_ITU601_8BIT;
+ cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT;
}
- cfg |= S5P_CISRCFMT_HSIZE(f->o_width) | S5P_CISRCFMT_VSIZE(f->o_height);
- writel(cfg, fimc->regs + S5P_CISRCFMT);
+ cfg |= (f->o_width << 16) | f->o_height;
+ writel(cfg, fimc->regs + FIMC_REG_CISRCFMT);
return 0;
}
-
-int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f)
+void fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f)
{
u32 hoff2, voff2;
- u32 cfg = readl(fimc->regs + S5P_CIWDOFST);
+ u32 cfg = readl(fimc->regs + FIMC_REG_CIWDOFST);
- cfg &= ~(S5P_CIWDOFST_HOROFF_MASK | S5P_CIWDOFST_VEROFF_MASK);
- cfg |= S5P_CIWDOFST_OFF_EN |
- S5P_CIWDOFST_HOROFF(f->offs_h) |
- S5P_CIWDOFST_VEROFF(f->offs_v);
+ cfg &= ~(FIMC_REG_CIWDOFST_HOROFF_MASK | FIMC_REG_CIWDOFST_VEROFF_MASK);
+ cfg |= FIMC_REG_CIWDOFST_OFF_EN |
+ (f->offs_h << 16) | f->offs_v;
- writel(cfg, fimc->regs + S5P_CIWDOFST);
+ writel(cfg, fimc->regs + FIMC_REG_CIWDOFST);
/* See CIWDOFSTn register description in the datasheet for details. */
hoff2 = f->o_width - f->width - f->offs_h;
voff2 = f->o_height - f->height - f->offs_v;
- cfg = S5P_CIWDOFST2_HOROFF(hoff2) | S5P_CIWDOFST2_VEROFF(voff2);
-
- writel(cfg, fimc->regs + S5P_CIWDOFST2);
- return 0;
+ cfg = (hoff2 << 16) | voff2;
+ writel(cfg, fimc->regs + FIMC_REG_CIWDOFST2);
}
int fimc_hw_set_camera_type(struct fimc_dev *fimc,
@@ -674,28 +658,29 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
{
u32 cfg, tmp;
struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+ u32 csis_data_alignment = 32;
- cfg = readl(fimc->regs + S5P_CIGCTRL);
+ cfg = readl(fimc->regs + FIMC_REG_CIGCTRL);
/* Select ITU B interface, disable Writeback path and test pattern. */
- cfg &= ~(S5P_CIGCTRL_TESTPAT_MASK | S5P_CIGCTRL_SELCAM_ITU_A |
- S5P_CIGCTRL_SELCAM_MIPI | S5P_CIGCTRL_CAMIF_SELWB |
- S5P_CIGCTRL_SELCAM_MIPI_A | S5P_CIGCTRL_CAM_JPEG);
+ cfg &= ~(FIMC_REG_CIGCTRL_TESTPAT_MASK | FIMC_REG_CIGCTRL_SELCAM_ITU_A |
+ FIMC_REG_CIGCTRL_SELCAM_MIPI | FIMC_REG_CIGCTRL_CAMIF_SELWB |
+ FIMC_REG_CIGCTRL_SELCAM_MIPI_A | FIMC_REG_CIGCTRL_CAM_JPEG);
if (cam->bus_type == FIMC_MIPI_CSI2) {
- cfg |= S5P_CIGCTRL_SELCAM_MIPI;
+ cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI;
if (cam->mux_id == 0)
- cfg |= S5P_CIGCTRL_SELCAM_MIPI_A;
+ cfg |= FIMC_REG_CIGCTRL_SELCAM_MIPI_A;
/* TODO: add remaining supported formats. */
switch (vid_cap->mf.code) {
case V4L2_MBUS_FMT_VYUY8_2X8:
- tmp = S5P_CSIIMGFMT_YCBCR422_8BIT;
+ tmp = FIMC_REG_CSIIMGFMT_YCBCR422_8BIT;
break;
case V4L2_MBUS_FMT_JPEG_1X8:
- tmp = S5P_CSIIMGFMT_USER(1);
- cfg |= S5P_CIGCTRL_CAM_JPEG;
+ tmp = FIMC_REG_CSIIMGFMT_USER(1);
+ cfg |= FIMC_REG_CIGCTRL_CAM_JPEG;
break;
default:
v4l2_err(fimc->vid_cap.vfd,
@@ -703,21 +688,86 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
vid_cap->mf.code);
return -EINVAL;
}
- tmp |= (cam->csi_data_align == 32) << 8;
+ tmp |= (csis_data_alignment == 32) << 8;
- writel(tmp, fimc->regs + S5P_CSIIMGFMT);
+ writel(tmp, fimc->regs + FIMC_REG_CSIIMGFMT);
} else if (cam->bus_type == FIMC_ITU_601 ||
cam->bus_type == FIMC_ITU_656) {
if (cam->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */
- cfg |= S5P_CIGCTRL_SELCAM_ITU_A;
+ cfg |= FIMC_REG_CIGCTRL_SELCAM_ITU_A;
} else if (cam->bus_type == FIMC_LCD_WB) {
- cfg |= S5P_CIGCTRL_CAMIF_SELWB;
+ cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB;
} else {
err("invalid camera bus type selected\n");
return -EINVAL;
}
- writel(cfg, fimc->regs + S5P_CIGCTRL);
+ writel(cfg, fimc->regs + FIMC_REG_CIGCTRL);
return 0;
}
+
+void fimc_hw_clear_irq(struct fimc_dev *dev)
+{
+ u32 cfg = readl(dev->regs + FIMC_REG_CIGCTRL);
+ cfg |= FIMC_REG_CIGCTRL_IRQ_CLR;
+ writel(cfg, dev->regs + FIMC_REG_CIGCTRL);
+}
+
+void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on)
+{
+ u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL);
+ if (on)
+ cfg |= FIMC_REG_CISCCTRL_SCALERSTART;
+ else
+ cfg &= ~FIMC_REG_CISCCTRL_SCALERSTART;
+ writel(cfg, dev->regs + FIMC_REG_CISCCTRL);
+}
+
+void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on)
+{
+ u32 cfg = readl(dev->regs + FIMC_REG_MSCTRL);
+ if (on)
+ cfg |= FIMC_REG_MSCTRL_ENVID;
+ else
+ cfg &= ~FIMC_REG_MSCTRL_ENVID;
+ writel(cfg, dev->regs + FIMC_REG_MSCTRL);
+}
+
+void fimc_hw_dis_capture(struct fimc_dev *dev)
+{
+ u32 cfg = readl(dev->regs + FIMC_REG_CIIMGCPT);
+ cfg &= ~(FIMC_REG_CIIMGCPT_IMGCPTEN | FIMC_REG_CIIMGCPT_IMGCPTEN_SC);
+ writel(cfg, dev->regs + FIMC_REG_CIIMGCPT);
+}
+
+/* Return an index to the buffer actually being written. */
+u32 fimc_hw_get_frame_index(struct fimc_dev *dev)
+{
+ u32 reg;
+
+ if (dev->variant->has_cistatus2) {
+ reg = readl(dev->regs + FIMC_REG_CISTATUS2) & 0x3F;
+ return reg > 0 ? --reg : reg;
+ }
+
+ reg = readl(dev->regs + FIMC_REG_CISTATUS);
+
+ return (reg & FIMC_REG_CISTATUS_FRAMECNT_MASK) >>
+ FIMC_REG_CISTATUS_FRAMECNT_SHIFT;
+}
+
+/* Locking: the caller holds fimc->slock */
+void fimc_activate_capture(struct fimc_ctx *ctx)
+{
+ fimc_hw_enable_scaler(ctx->fimc_dev, ctx->scaler.enabled);
+ fimc_hw_en_capture(ctx);
+}
+
+void fimc_deactivate_capture(struct fimc_dev *fimc)
+{
+ fimc_hw_en_lastirq(fimc, true);
+ fimc_hw_dis_capture(fimc);
+ fimc_hw_enable_scaler(fimc, false);
+ fimc_hw_en_lastirq(fimc, false);
+}
diff --git a/drivers/media/video/s5p-fimc/fimc-reg.h b/drivers/media/video/s5p-fimc/fimc-reg.h
new file mode 100644
index 000000000000..579ac8ac03de
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/fimc-reg.h
@@ -0,0 +1,326 @@
+/*
+ * Samsung camera host interface (FIMC) registers definition
+ *
+ * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd.
+ *
+ * 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 FIMC_REG_H_
+#define FIMC_REG_H_
+
+#include "fimc-core.h"
+
+/* Input source format */
+#define FIMC_REG_CISRCFMT 0x00
+#define FIMC_REG_CISRCFMT_ITU601_8BIT (1 << 31)
+#define FIMC_REG_CISRCFMT_ITU601_16BIT (1 << 29)
+#define FIMC_REG_CISRCFMT_ORDER422_YCBYCR (0 << 14)
+#define FIMC_REG_CISRCFMT_ORDER422_YCRYCB (1 << 14)
+#define FIMC_REG_CISRCFMT_ORDER422_CBYCRY (2 << 14)
+#define FIMC_REG_CISRCFMT_ORDER422_CRYCBY (3 << 14)
+
+/* Window offset */
+#define FIMC_REG_CIWDOFST 0x04
+#define FIMC_REG_CIWDOFST_OFF_EN (1 << 31)
+#define FIMC_REG_CIWDOFST_CLROVFIY (1 << 30)
+#define FIMC_REG_CIWDOFST_CLROVRLB (1 << 29)
+#define FIMC_REG_CIWDOFST_HOROFF_MASK (0x7ff << 16)
+#define FIMC_REG_CIWDOFST_CLROVFICB (1 << 15)
+#define FIMC_REG_CIWDOFST_CLROVFICR (1 << 14)
+#define FIMC_REG_CIWDOFST_VEROFF_MASK (0xfff << 0)
+
+/* Global control */
+#define FIMC_REG_CIGCTRL 0x08
+#define FIMC_REG_CIGCTRL_SWRST (1 << 31)
+#define FIMC_REG_CIGCTRL_CAMRST_A (1 << 30)
+#define FIMC_REG_CIGCTRL_SELCAM_ITU_A (1 << 29)
+#define FIMC_REG_CIGCTRL_TESTPAT_NORMAL (0 << 27)
+#define FIMC_REG_CIGCTRL_TESTPAT_COLOR_BAR (1 << 27)
+#define FIMC_REG_CIGCTRL_TESTPAT_HOR_INC (2 << 27)
+#define FIMC_REG_CIGCTRL_TESTPAT_VER_INC (3 << 27)
+#define FIMC_REG_CIGCTRL_TESTPAT_MASK (3 << 27)
+#define FIMC_REG_CIGCTRL_TESTPAT_SHIFT 27
+#define FIMC_REG_CIGCTRL_INVPOLPCLK (1 << 26)
+#define FIMC_REG_CIGCTRL_INVPOLVSYNC (1 << 25)
+#define FIMC_REG_CIGCTRL_INVPOLHREF (1 << 24)
+#define FIMC_REG_CIGCTRL_IRQ_OVFEN (1 << 22)
+#define FIMC_REG_CIGCTRL_HREF_MASK (1 << 21)
+#define FIMC_REG_CIGCTRL_IRQ_LEVEL (1 << 20)
+#define FIMC_REG_CIGCTRL_IRQ_CLR (1 << 19)
+#define FIMC_REG_CIGCTRL_IRQ_ENABLE (1 << 16)
+#define FIMC_REG_CIGCTRL_SHDW_DISABLE (1 << 12)
+#define FIMC_REG_CIGCTRL_CAM_JPEG (1 << 8)
+#define FIMC_REG_CIGCTRL_SELCAM_MIPI_A (1 << 7)
+#define FIMC_REG_CIGCTRL_CAMIF_SELWB (1 << 6)
+/* 0 - ITU601; 1 - ITU709 */
+#define FIMC_REG_CIGCTRL_CSC_ITU601_709 (1 << 5)
+#define FIMC_REG_CIGCTRL_INVPOLHSYNC (1 << 4)
+#define FIMC_REG_CIGCTRL_SELCAM_MIPI (1 << 3)
+#define FIMC_REG_CIGCTRL_INVPOLFIELD (1 << 1)
+#define FIMC_REG_CIGCTRL_INTERLACE (1 << 0)
+
+/* Window offset 2 */
+#define FIMC_REG_CIWDOFST2 0x14
+#define FIMC_REG_CIWDOFST2_HOROFF_MASK (0xfff << 16)
+#define FIMC_REG_CIWDOFST2_VEROFF_MASK (0xfff << 0)
+
+/* Output DMA Y/Cb/Cr plane start addresses */
+#define FIMC_REG_CIOYSA(n) (0x18 + (n) * 4)
+#define FIMC_REG_CIOCBSA(n) (0x28 + (n) * 4)
+#define FIMC_REG_CIOCRSA(n) (0x38 + (n) * 4)
+
+/* Target image format */
+#define FIMC_REG_CITRGFMT 0x48
+#define FIMC_REG_CITRGFMT_INROT90 (1 << 31)
+#define FIMC_REG_CITRGFMT_YCBCR420 (0 << 29)
+#define FIMC_REG_CITRGFMT_YCBCR422 (1 << 29)
+#define FIMC_REG_CITRGFMT_YCBCR422_1P (2 << 29)
+#define FIMC_REG_CITRGFMT_RGB (3 << 29)
+#define FIMC_REG_CITRGFMT_FMT_MASK (3 << 29)
+#define FIMC_REG_CITRGFMT_HSIZE_MASK (0xfff << 16)
+#define FIMC_REG_CITRGFMT_FLIP_SHIFT 14
+#define FIMC_REG_CITRGFMT_FLIP_NORMAL (0 << 14)
+#define FIMC_REG_CITRGFMT_FLIP_X_MIRROR (1 << 14)
+#define FIMC_REG_CITRGFMT_FLIP_Y_MIRROR (2 << 14)
+#define FIMC_REG_CITRGFMT_FLIP_180 (3 << 14)
+#define FIMC_REG_CITRGFMT_FLIP_MASK (3 << 14)
+#define FIMC_REG_CITRGFMT_OUTROT90 (1 << 13)
+#define FIMC_REG_CITRGFMT_VSIZE_MASK (0xfff << 0)
+
+/* Output DMA control */
+#define FIMC_REG_CIOCTRL 0x4c
+#define FIMC_REG_CIOCTRL_ORDER422_MASK (3 << 0)
+#define FIMC_REG_CIOCTRL_ORDER422_CRYCBY (0 << 0)
+#define FIMC_REG_CIOCTRL_ORDER422_CBYCRY (1 << 0)
+#define FIMC_REG_CIOCTRL_ORDER422_YCRYCB (2 << 0)
+#define FIMC_REG_CIOCTRL_ORDER422_YCBYCR (3 << 0)
+#define FIMC_REG_CIOCTRL_LASTIRQ_ENABLE (1 << 2)
+#define FIMC_REG_CIOCTRL_YCBCR_3PLANE (0 << 3)
+#define FIMC_REG_CIOCTRL_YCBCR_2PLANE (1 << 3)
+#define FIMC_REG_CIOCTRL_YCBCR_PLANE_MASK (1 << 3)
+#define FIMC_REG_CIOCTRL_ALPHA_OUT_MASK (0xff << 4)
+#define FIMC_REG_CIOCTRL_RGB16FMT_MASK (3 << 16)
+#define FIMC_REG_CIOCTRL_RGB565 (0 << 16)
+#define FIMC_REG_CIOCTRL_ARGB1555 (1 << 16)
+#define FIMC_REG_CIOCTRL_ARGB4444 (2 << 16)
+#define FIMC_REG_CIOCTRL_ORDER2P_SHIFT 24
+#define FIMC_REG_CIOCTRL_ORDER2P_MASK (3 << 24)
+#define FIMC_REG_CIOCTRL_ORDER422_2P_LSB_CRCB (0 << 24)
+
+/* Pre-scaler control 1 */
+#define FIMC_REG_CISCPRERATIO 0x50
+
+#define FIMC_REG_CISCPREDST 0x54
+
+/* Main scaler control */
+#define FIMC_REG_CISCCTRL 0x58
+#define FIMC_REG_CISCCTRL_SCALERBYPASS (1 << 31)
+#define FIMC_REG_CISCCTRL_SCALEUP_H (1 << 30)
+#define FIMC_REG_CISCCTRL_SCALEUP_V (1 << 29)
+#define FIMC_REG_CISCCTRL_CSCR2Y_WIDE (1 << 28)
+#define FIMC_REG_CISCCTRL_CSCY2R_WIDE (1 << 27)
+#define FIMC_REG_CISCCTRL_LCDPATHEN_FIFO (1 << 26)
+#define FIMC_REG_CISCCTRL_INTERLACE (1 << 25)
+#define FIMC_REG_CISCCTRL_SCALERSTART (1 << 15)
+#define FIMC_REG_CISCCTRL_INRGB_FMT_RGB565 (0 << 13)
+#define FIMC_REG_CISCCTRL_INRGB_FMT_RGB666 (1 << 13)
+#define FIMC_REG_CISCCTRL_INRGB_FMT_RGB888 (2 << 13)
+#define FIMC_REG_CISCCTRL_INRGB_FMT_MASK (3 << 13)
+#define FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB565 (0 << 11)
+#define FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB666 (1 << 11)
+#define FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888 (2 << 11)
+#define FIMC_REG_CISCCTRL_OUTRGB_FMT_MASK (3 << 11)
+#define FIMC_REG_CISCCTRL_RGB_EXT (1 << 10)
+#define FIMC_REG_CISCCTRL_ONE2ONE (1 << 9)
+#define FIMC_REG_CISCCTRL_MHRATIO(x) ((x) << 16)
+#define FIMC_REG_CISCCTRL_MVRATIO(x) ((x) << 0)
+#define FIMC_REG_CISCCTRL_MHRATIO_MASK (0x1ff << 16)
+#define FIMC_REG_CISCCTRL_MVRATIO_MASK (0x1ff << 0)
+#define FIMC_REG_CISCCTRL_MHRATIO_EXT(x) (((x) >> 6) << 16)
+#define FIMC_REG_CISCCTRL_MVRATIO_EXT(x) (((x) >> 6) << 0)
+
+/* Target area */
+#define FIMC_REG_CITAREA 0x5c
+#define FIMC_REG_CITAREA_MASK 0x0fffffff
+
+/* General status */
+#define FIMC_REG_CISTATUS 0x64
+#define FIMC_REG_CISTATUS_OVFIY (1 << 31)
+#define FIMC_REG_CISTATUS_OVFICB (1 << 30)
+#define FIMC_REG_CISTATUS_OVFICR (1 << 29)
+#define FIMC_REG_CISTATUS_VSYNC (1 << 28)
+#define FIMC_REG_CISTATUS_FRAMECNT_MASK (3 << 26)
+#define FIMC_REG_CISTATUS_FRAMECNT_SHIFT 26
+#define FIMC_REG_CISTATUS_WINOFF_EN (1 << 25)
+#define FIMC_REG_CISTATUS_IMGCPT_EN (1 << 22)
+#define FIMC_REG_CISTATUS_IMGCPT_SCEN (1 << 21)
+#define FIMC_REG_CISTATUS_VSYNC_A (1 << 20)
+#define FIMC_REG_CISTATUS_VSYNC_B (1 << 19)
+#define FIMC_REG_CISTATUS_OVRLB (1 << 18)
+#define FIMC_REG_CISTATUS_FRAME_END (1 << 17)
+#define FIMC_REG_CISTATUS_LASTCAPT_END (1 << 16)
+#define FIMC_REG_CISTATUS_VVALID_A (1 << 15)
+#define FIMC_REG_CISTATUS_VVALID_B (1 << 14)
+
+/* Indexes to the last and the currently processed buffer. */
+#define FIMC_REG_CISTATUS2 0x68
+
+/* Image capture control */
+#define FIMC_REG_CIIMGCPT 0xc0
+#define FIMC_REG_CIIMGCPT_IMGCPTEN (1 << 31)
+#define FIMC_REG_CIIMGCPT_IMGCPTEN_SC (1 << 30)
+#define FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE (1 << 25)
+#define FIMC_REG_CIIMGCPT_CPT_FRMOD_CNT (1 << 18)
+
+/* Frame capture sequence */
+#define FIMC_REG_CICPTSEQ 0xc4
+
+/* Image effect */
+#define FIMC_REG_CIIMGEFF 0xd0
+#define FIMC_REG_CIIMGEFF_IE_ENABLE (1 << 30)
+#define FIMC_REG_CIIMGEFF_IE_SC_BEFORE (0 << 29)
+#define FIMC_REG_CIIMGEFF_IE_SC_AFTER (1 << 29)
+#define FIMC_REG_CIIMGEFF_FIN_BYPASS (0 << 26)
+#define FIMC_REG_CIIMGEFF_FIN_ARBITRARY (1 << 26)
+#define FIMC_REG_CIIMGEFF_FIN_NEGATIVE (2 << 26)
+#define FIMC_REG_CIIMGEFF_FIN_ARTFREEZE (3 << 26)
+#define FIMC_REG_CIIMGEFF_FIN_EMBOSSING (4 << 26)
+#define FIMC_REG_CIIMGEFF_FIN_SILHOUETTE (5 << 26)
+#define FIMC_REG_CIIMGEFF_FIN_MASK (7 << 26)
+#define FIMC_REG_CIIMGEFF_PAT_CBCR_MASK ((0xff << 13) | 0xff)
+
+/* Input DMA Y/Cb/Cr plane start address 0/1 */
+#define FIMC_REG_CIIYSA(n) (0xd4 + (n) * 0x70)
+#define FIMC_REG_CIICBSA(n) (0xd8 + (n) * 0x70)
+#define FIMC_REG_CIICRSA(n) (0xdc + (n) * 0x70)
+
+/* Real input DMA image size */
+#define FIMC_REG_CIREAL_ISIZE 0xf8
+#define FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN (1 << 31)
+#define FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS (1 << 30)
+
+/* Input DMA control */
+#define FIMC_REG_MSCTRL 0xfc
+#define FIMC_REG_MSCTRL_IN_BURST_COUNT_MASK (0xf << 24)
+#define FIMC_REG_MSCTRL_2P_IN_ORDER_MASK (3 << 16)
+#define FIMC_REG_MSCTRL_2P_IN_ORDER_SHIFT 16
+#define FIMC_REG_MSCTRL_C_INT_IN_3PLANE (0 << 15)
+#define FIMC_REG_MSCTRL_C_INT_IN_2PLANE (1 << 15)
+#define FIMC_REG_MSCTRL_C_INT_IN_MASK (1 << 15)
+#define FIMC_REG_MSCTRL_FLIP_SHIFT 13
+#define FIMC_REG_MSCTRL_FLIP_MASK (3 << 13)
+#define FIMC_REG_MSCTRL_FLIP_NORMAL (0 << 13)
+#define FIMC_REG_MSCTRL_FLIP_X_MIRROR (1 << 13)
+#define FIMC_REG_MSCTRL_FLIP_Y_MIRROR (2 << 13)
+#define FIMC_REG_MSCTRL_FLIP_180 (3 << 13)
+#define FIMC_REG_MSCTRL_FIFO_CTRL_FULL (1 << 12)
+#define FIMC_REG_MSCTRL_ORDER422_SHIFT 4
+#define FIMC_REG_MSCTRL_ORDER422_YCBYCR (0 << 4)
+#define FIMC_REG_MSCTRL_ORDER422_CBYCRY (1 << 4)
+#define FIMC_REG_MSCTRL_ORDER422_YCRYCB (2 << 4)
+#define FIMC_REG_MSCTRL_ORDER422_CRYCBY (3 << 4)
+#define FIMC_REG_MSCTRL_ORDER422_MASK (3 << 4)
+#define FIMC_REG_MSCTRL_INPUT_EXTCAM (0 << 3)
+#define FIMC_REG_MSCTRL_INPUT_MEMORY (1 << 3)
+#define FIMC_REG_MSCTRL_INPUT_MASK (1 << 3)
+#define FIMC_REG_MSCTRL_INFORMAT_YCBCR420 (0 << 1)
+#define FIMC_REG_MSCTRL_INFORMAT_YCBCR422 (1 << 1)
+#define FIMC_REG_MSCTRL_INFORMAT_YCBCR422_1P (2 << 1)
+#define FIMC_REG_MSCTRL_INFORMAT_RGB (3 << 1)
+#define FIMC_REG_MSCTRL_INFORMAT_MASK (3 << 1)
+#define FIMC_REG_MSCTRL_ENVID (1 << 0)
+#define FIMC_REG_MSCTRL_IN_BURST_COUNT(x) ((x) << 24)
+
+/* Output DMA Y/Cb/Cr offset */
+#define FIMC_REG_CIOYOFF 0x168
+#define FIMC_REG_CIOCBOFF 0x16c
+#define FIMC_REG_CIOCROFF 0x170
+
+/* Input DMA Y/Cb/Cr offset */
+#define FIMC_REG_CIIYOFF 0x174
+#define FIMC_REG_CIICBOFF 0x178
+#define FIMC_REG_CIICROFF 0x17c
+
+/* Input DMA original image size */
+#define FIMC_REG_ORGISIZE 0x180
+
+/* Output DMA original image size */
+#define FIMC_REG_ORGOSIZE 0x184
+
+/* Real output DMA image size (extension register) */
+#define FIMC_REG_CIEXTEN 0x188
+#define FIMC_REG_CIEXTEN_MHRATIO_EXT(x) (((x) & 0x3f) << 10)
+#define FIMC_REG_CIEXTEN_MVRATIO_EXT(x) ((x) & 0x3f)
+#define FIMC_REG_CIEXTEN_MHRATIO_EXT_MASK (0x3f << 10)
+#define FIMC_REG_CIEXTEN_MVRATIO_EXT_MASK 0x3f
+
+#define FIMC_REG_CIDMAPARAM 0x18c
+#define FIMC_REG_CIDMAPARAM_R_LINEAR (0 << 29)
+#define FIMC_REG_CIDMAPARAM_R_64X32 (3 << 29)
+#define FIMC_REG_CIDMAPARAM_W_LINEAR (0 << 13)
+#define FIMC_REG_CIDMAPARAM_W_64X32 (3 << 13)
+#define FIMC_REG_CIDMAPARAM_TILE_MASK ((3 << 29) | (3 << 13))
+
+/* MIPI CSI image format */
+#define FIMC_REG_CSIIMGFMT 0x194
+#define FIMC_REG_CSIIMGFMT_YCBCR422_8BIT 0x1e
+#define FIMC_REG_CSIIMGFMT_RAW8 0x2a
+#define FIMC_REG_CSIIMGFMT_RAW10 0x2b
+#define FIMC_REG_CSIIMGFMT_RAW12 0x2c
+/* User defined formats. x = 0...16. */
+#define FIMC_REG_CSIIMGFMT_USER(x) (0x30 + x - 1)
+
+/* Output frame buffer sequence mask */
+#define FIMC_REG_CIFCNTSEQ 0x1fc
+
+/*
+ * Function declarations
+ */
+void fimc_hw_reset(struct fimc_dev *fimc);
+void fimc_hw_set_rotation(struct fimc_ctx *ctx);
+void fimc_hw_set_target_format(struct fimc_ctx *ctx);
+void fimc_hw_set_out_dma(struct fimc_ctx *ctx);
+void fimc_hw_en_lastirq(struct fimc_dev *fimc, int enable);
+void fimc_hw_en_irq(struct fimc_dev *fimc, int enable);
+void fimc_hw_set_prescaler(struct fimc_ctx *ctx);
+void fimc_hw_set_mainscaler(struct fimc_ctx *ctx);
+void fimc_hw_en_capture(struct fimc_ctx *ctx);
+void fimc_hw_set_effect(struct fimc_ctx *ctx);
+void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx);
+void fimc_hw_set_in_dma(struct fimc_ctx *ctx);
+void fimc_hw_set_input_path(struct fimc_ctx *ctx);
+void fimc_hw_set_output_path(struct fimc_ctx *ctx);
+void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *paddr);
+void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *paddr,
+ int index);
+int fimc_hw_set_camera_source(struct fimc_dev *fimc,
+ struct s5p_fimc_isp_info *cam);
+void fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f);
+int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
+ struct s5p_fimc_isp_info *cam);
+int fimc_hw_set_camera_type(struct fimc_dev *fimc,
+ struct s5p_fimc_isp_info *cam);
+void fimc_hw_clear_irq(struct fimc_dev *dev);
+void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on);
+void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on);
+void fimc_hw_dis_capture(struct fimc_dev *dev);
+u32 fimc_hw_get_frame_index(struct fimc_dev *dev);
+void fimc_activate_capture(struct fimc_ctx *ctx);
+void fimc_deactivate_capture(struct fimc_dev *fimc);
+
+/**
+ * fimc_hw_set_dma_seq - configure output DMA buffer sequence
+ * @mask: bitmask for the DMA output buffer registers, set to 0 to skip buffer
+ * This function masks output DMA ring buffers, it allows to select which of
+ * the 32 available output buffer address registers will be used by the DMA
+ * engine.
+ */
+static inline void fimc_hw_set_dma_seq(struct fimc_dev *dev, u32 mask)
+{
+ writel(mask, dev->regs + FIMC_REG_CIFCNTSEQ);
+}
+
+#endif /* FIMC_REG_H_ */
diff --git a/drivers/media/video/s5p-fimc/mipi-csis.c b/drivers/media/video/s5p-fimc/mipi-csis.c
index f44f690397f7..2f73d9e3d0b7 100644
--- a/drivers/media/video/s5p-fimc/mipi-csis.c
+++ b/drivers/media/video/s5p-fimc/mipi-csis.c
@@ -127,20 +127,24 @@ struct csis_state {
* multiple of 2^pix_width_alignment
* @code: corresponding media bus code
* @fmt_reg: S5PCSIS_CONFIG register value
+ * @data_alignment: MIPI-CSI data alignment in bits
*/
struct csis_pix_format {
unsigned int pix_width_alignment;
enum v4l2_mbus_pixelcode code;
u32 fmt_reg;
+ u8 data_alignment;
};
static const struct csis_pix_format s5pcsis_formats[] = {
{
.code = V4L2_MBUS_FMT_VYUY8_2X8,
.fmt_reg = S5PCSIS_CFG_FMT_YCBCR422_8BIT,
+ .data_alignment = 32,
}, {
.code = V4L2_MBUS_FMT_JPEG_1X8,
.fmt_reg = S5PCSIS_CFG_FMT_USER(1),
+ .data_alignment = 32,
},
};
@@ -239,7 +243,7 @@ static void s5pcsis_set_params(struct csis_state *state)
s5pcsis_set_hsync_settle(state, pdata->hs_settle);
val = s5pcsis_read(state, S5PCSIS_CTRL);
- if (pdata->alignment == 32)
+ if (state->csis_fmt->data_alignment == 32)
val |= S5PCSIS_CTRL_ALIGN_32BIT;
else /* 24-bits */
val &= ~S5PCSIS_CTRL_ALIGN_32BIT;
@@ -711,19 +715,8 @@ static struct platform_driver s5pcsis_driver = {
},
};
-static int __init s5pcsis_init(void)
-{
- return platform_driver_probe(&s5pcsis_driver, s5pcsis_probe);
-}
-
-static void __exit s5pcsis_exit(void)
-{
- platform_driver_unregister(&s5pcsis_driver);
-}
-
-module_init(s5pcsis_init);
-module_exit(s5pcsis_exit);
+module_platform_driver(s5pcsis_driver);
MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
-MODULE_DESCRIPTION("S5P/EXYNOS4 MIPI CSI receiver driver");
+MODULE_DESCRIPTION("Samsung S5P/EXYNOS SoC MIPI-CSI2 receiver driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/s5p-fimc/regs-fimc.h b/drivers/media/video/s5p-fimc/regs-fimc.h
deleted file mode 100644
index c7a5bc51d571..000000000000
--- a/drivers/media/video/s5p-fimc/regs-fimc.h
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Register definition file for Samsung Camera Interface (FIMC) driver
- *
- * Copyright (c) 2010 Samsung Electronics
- *
- * 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_FIMC_H_
-#define REGS_FIMC_H_
-
-/* Input source format */
-#define S5P_CISRCFMT 0x00
-#define S5P_CISRCFMT_ITU601_8BIT (1 << 31)
-#define S5P_CISRCFMT_ITU601_16BIT (1 << 29)
-#define S5P_CISRCFMT_ORDER422_YCBYCR (0 << 14)
-#define S5P_CISRCFMT_ORDER422_YCRYCB (1 << 14)
-#define S5P_CISRCFMT_ORDER422_CBYCRY (2 << 14)
-#define S5P_CISRCFMT_ORDER422_CRYCBY (3 << 14)
-#define S5P_CISRCFMT_HSIZE(x) ((x) << 16)
-#define S5P_CISRCFMT_VSIZE(x) ((x) << 0)
-
-/* Window offset */
-#define S5P_CIWDOFST 0x04
-#define S5P_CIWDOFST_OFF_EN (1 << 31)
-#define S5P_CIWDOFST_CLROVFIY (1 << 30)
-#define S5P_CIWDOFST_CLROVRLB (1 << 29)
-#define S5P_CIWDOFST_HOROFF_MASK (0x7ff << 16)
-#define S5P_CIWDOFST_CLROVFICB (1 << 15)
-#define S5P_CIWDOFST_CLROVFICR (1 << 14)
-#define S5P_CIWDOFST_HOROFF(x) ((x) << 16)
-#define S5P_CIWDOFST_VEROFF(x) ((x) << 0)
-#define S5P_CIWDOFST_VEROFF_MASK (0xfff << 0)
-
-/* Global control */
-#define S5P_CIGCTRL 0x08
-#define S5P_CIGCTRL_SWRST (1 << 31)
-#define S5P_CIGCTRL_CAMRST_A (1 << 30)
-#define S5P_CIGCTRL_SELCAM_ITU_A (1 << 29)
-#define S5P_CIGCTRL_TESTPAT_NORMAL (0 << 27)
-#define S5P_CIGCTRL_TESTPAT_COLOR_BAR (1 << 27)
-#define S5P_CIGCTRL_TESTPAT_HOR_INC (2 << 27)
-#define S5P_CIGCTRL_TESTPAT_VER_INC (3 << 27)
-#define S5P_CIGCTRL_TESTPAT_MASK (3 << 27)
-#define S5P_CIGCTRL_TESTPAT_SHIFT (27)
-#define S5P_CIGCTRL_INVPOLPCLK (1 << 26)
-#define S5P_CIGCTRL_INVPOLVSYNC (1 << 25)
-#define S5P_CIGCTRL_INVPOLHREF (1 << 24)
-#define S5P_CIGCTRL_IRQ_OVFEN (1 << 22)
-#define S5P_CIGCTRL_HREF_MASK (1 << 21)
-#define S5P_CIGCTRL_IRQ_LEVEL (1 << 20)
-#define S5P_CIGCTRL_IRQ_CLR (1 << 19)
-#define S5P_CIGCTRL_IRQ_ENABLE (1 << 16)
-#define S5P_CIGCTRL_SHDW_DISABLE (1 << 12)
-#define S5P_CIGCTRL_CAM_JPEG (1 << 8)
-#define S5P_CIGCTRL_SELCAM_MIPI_A (1 << 7)
-#define S5P_CIGCTRL_CAMIF_SELWB (1 << 6)
-/* 0 - ITU601; 1 - ITU709 */
-#define S5P_CIGCTRL_CSC_ITU601_709 (1 << 5)
-#define S5P_CIGCTRL_INVPOLHSYNC (1 << 4)
-#define S5P_CIGCTRL_SELCAM_MIPI (1 << 3)
-#define S5P_CIGCTRL_INVPOLFIELD (1 << 1)
-#define S5P_CIGCTRL_INTERLACE (1 << 0)
-
-/* Window offset 2 */
-#define S5P_CIWDOFST2 0x14
-#define S5P_CIWDOFST2_HOROFF_MASK (0xfff << 16)
-#define S5P_CIWDOFST2_VEROFF_MASK (0xfff << 0)
-#define S5P_CIWDOFST2_HOROFF(x) ((x) << 16)
-#define S5P_CIWDOFST2_VEROFF(x) ((x) << 0)
-
-/* Output DMA Y/Cb/Cr plane start addresses */
-#define S5P_CIOYSA(n) (0x18 + (n) * 4)
-#define S5P_CIOCBSA(n) (0x28 + (n) * 4)
-#define S5P_CIOCRSA(n) (0x38 + (n) * 4)
-
-/* Target image format */
-#define S5P_CITRGFMT 0x48
-#define S5P_CITRGFMT_INROT90 (1 << 31)
-#define S5P_CITRGFMT_YCBCR420 (0 << 29)
-#define S5P_CITRGFMT_YCBCR422 (1 << 29)
-#define S5P_CITRGFMT_YCBCR422_1P (2 << 29)
-#define S5P_CITRGFMT_RGB (3 << 29)
-#define S5P_CITRGFMT_FMT_MASK (3 << 29)
-#define S5P_CITRGFMT_HSIZE_MASK (0xfff << 16)
-#define S5P_CITRGFMT_FLIP_SHIFT (14)
-#define S5P_CITRGFMT_FLIP_NORMAL (0 << 14)
-#define S5P_CITRGFMT_FLIP_X_MIRROR (1 << 14)
-#define S5P_CITRGFMT_FLIP_Y_MIRROR (2 << 14)
-#define S5P_CITRGFMT_FLIP_180 (3 << 14)
-#define S5P_CITRGFMT_FLIP_MASK (3 << 14)
-#define S5P_CITRGFMT_OUTROT90 (1 << 13)
-#define S5P_CITRGFMT_VSIZE_MASK (0xfff << 0)
-#define S5P_CITRGFMT_HSIZE(x) ((x) << 16)
-#define S5P_CITRGFMT_VSIZE(x) ((x) << 0)
-
-/* Output DMA control */
-#define S5P_CIOCTRL 0x4c
-#define S5P_CIOCTRL_ORDER422_MASK (3 << 0)
-#define S5P_CIOCTRL_ORDER422_CRYCBY (0 << 0)
-#define S5P_CIOCTRL_ORDER422_CBYCRY (1 << 0)
-#define S5P_CIOCTRL_ORDER422_YCRYCB (2 << 0)
-#define S5P_CIOCTRL_ORDER422_YCBYCR (3 << 0)
-#define S5P_CIOCTRL_LASTIRQ_ENABLE (1 << 2)
-#define S5P_CIOCTRL_YCBCR_3PLANE (0 << 3)
-#define S5P_CIOCTRL_YCBCR_2PLANE (1 << 3)
-#define S5P_CIOCTRL_YCBCR_PLANE_MASK (1 << 3)
-#define S5P_CIOCTRL_ALPHA_OUT_MASK (0xff << 4)
-#define S5P_CIOCTRL_RGB16FMT_MASK (3 << 16)
-#define S5P_CIOCTRL_RGB565 (0 << 16)
-#define S5P_CIOCTRL_ARGB1555 (1 << 16)
-#define S5P_CIOCTRL_ARGB4444 (2 << 16)
-#define S5P_CIOCTRL_ORDER2P_SHIFT (24)
-#define S5P_CIOCTRL_ORDER2P_MASK (3 << 24)
-#define S5P_CIOCTRL_ORDER422_2P_LSB_CRCB (0 << 24)
-
-/* Pre-scaler control 1 */
-#define S5P_CISCPRERATIO 0x50
-#define S5P_CISCPRERATIO_SHFACTOR(x) ((x) << 28)
-#define S5P_CISCPRERATIO_HOR(x) ((x) << 16)
-#define S5P_CISCPRERATIO_VER(x) ((x) << 0)
-
-#define S5P_CISCPREDST 0x54
-#define S5P_CISCPREDST_WIDTH(x) ((x) << 16)
-#define S5P_CISCPREDST_HEIGHT(x) ((x) << 0)
-
-/* Main scaler control */
-#define S5P_CISCCTRL 0x58
-#define S5P_CISCCTRL_SCALERBYPASS (1 << 31)
-#define S5P_CISCCTRL_SCALEUP_H (1 << 30)
-#define S5P_CISCCTRL_SCALEUP_V (1 << 29)
-#define S5P_CISCCTRL_CSCR2Y_WIDE (1 << 28)
-#define S5P_CISCCTRL_CSCY2R_WIDE (1 << 27)
-#define S5P_CISCCTRL_LCDPATHEN_FIFO (1 << 26)
-#define S5P_CISCCTRL_INTERLACE (1 << 25)
-#define S5P_CISCCTRL_SCALERSTART (1 << 15)
-#define S5P_CISCCTRL_INRGB_FMT_RGB565 (0 << 13)
-#define S5P_CISCCTRL_INRGB_FMT_RGB666 (1 << 13)
-#define S5P_CISCCTRL_INRGB_FMT_RGB888 (2 << 13)
-#define S5P_CISCCTRL_INRGB_FMT_MASK (3 << 13)
-#define S5P_CISCCTRL_OUTRGB_FMT_RGB565 (0 << 11)
-#define S5P_CISCCTRL_OUTRGB_FMT_RGB666 (1 << 11)
-#define S5P_CISCCTRL_OUTRGB_FMT_RGB888 (2 << 11)
-#define S5P_CISCCTRL_OUTRGB_FMT_MASK (3 << 11)
-#define S5P_CISCCTRL_RGB_EXT (1 << 10)
-#define S5P_CISCCTRL_ONE2ONE (1 << 9)
-#define S5P_CISCCTRL_MHRATIO(x) ((x) << 16)
-#define S5P_CISCCTRL_MVRATIO(x) ((x) << 0)
-#define S5P_CISCCTRL_MHRATIO_MASK (0x1ff << 16)
-#define S5P_CISCCTRL_MVRATIO_MASK (0x1ff << 0)
-#define S5P_CISCCTRL_MHRATIO_EXT(x) (((x) >> 6) << 16)
-#define S5P_CISCCTRL_MVRATIO_EXT(x) (((x) >> 6) << 0)
-
-/* Target area */
-#define S5P_CITAREA 0x5c
-#define S5P_CITAREA_MASK 0x0fffffff
-
-/* General status */
-#define S5P_CISTATUS 0x64
-#define S5P_CISTATUS_OVFIY (1 << 31)
-#define S5P_CISTATUS_OVFICB (1 << 30)
-#define S5P_CISTATUS_OVFICR (1 << 29)
-#define S5P_CISTATUS_VSYNC (1 << 28)
-#define S5P_CISTATUS_FRAMECNT_MASK (3 << 26)
-#define S5P_CISTATUS_FRAMECNT_SHIFT 26
-#define S5P_CISTATUS_WINOFF_EN (1 << 25)
-#define S5P_CISTATUS_IMGCPT_EN (1 << 22)
-#define S5P_CISTATUS_IMGCPT_SCEN (1 << 21)
-#define S5P_CISTATUS_VSYNC_A (1 << 20)
-#define S5P_CISTATUS_VSYNC_B (1 << 19)
-#define S5P_CISTATUS_OVRLB (1 << 18)
-#define S5P_CISTATUS_FRAME_END (1 << 17)
-#define S5P_CISTATUS_LASTCAPT_END (1 << 16)
-#define S5P_CISTATUS_VVALID_A (1 << 15)
-#define S5P_CISTATUS_VVALID_B (1 << 14)
-
-/* Indexes to the last and the currently processed buffer. */
-#define S5P_CISTATUS2 0x68
-
-/* Image capture control */
-#define S5P_CIIMGCPT 0xc0
-#define S5P_CIIMGCPT_IMGCPTEN (1 << 31)
-#define S5P_CIIMGCPT_IMGCPTEN_SC (1 << 30)
-#define S5P_CIIMGCPT_CPT_FREN_ENABLE (1 << 25)
-#define S5P_CIIMGCPT_CPT_FRMOD_CNT (1 << 18)
-
-/* Frame capture sequence */
-#define S5P_CICPTSEQ 0xc4
-
-/* Image effect */
-#define S5P_CIIMGEFF 0xd0
-#define S5P_CIIMGEFF_IE_ENABLE (1 << 30)
-#define S5P_CIIMGEFF_IE_SC_BEFORE (0 << 29)
-#define S5P_CIIMGEFF_IE_SC_AFTER (1 << 29)
-#define S5P_CIIMGEFF_FIN_BYPASS (0 << 26)
-#define S5P_CIIMGEFF_FIN_ARBITRARY (1 << 26)
-#define S5P_CIIMGEFF_FIN_NEGATIVE (2 << 26)
-#define S5P_CIIMGEFF_FIN_ARTFREEZE (3 << 26)
-#define S5P_CIIMGEFF_FIN_EMBOSSING (4 << 26)
-#define S5P_CIIMGEFF_FIN_SILHOUETTE (5 << 26)
-#define S5P_CIIMGEFF_FIN_MASK (7 << 26)
-#define S5P_CIIMGEFF_PAT_CBCR_MASK ((0xff < 13) | (0xff < 0))
-#define S5P_CIIMGEFF_PAT_CB(x) ((x) << 13)
-#define S5P_CIIMGEFF_PAT_CR(x) ((x) << 0)
-
-/* Input DMA Y/Cb/Cr plane start address 0/1 */
-#define S5P_CIIYSA(n) (0xd4 + (n) * 0x70)
-#define S5P_CIICBSA(n) (0xd8 + (n) * 0x70)
-#define S5P_CIICRSA(n) (0xdc + (n) * 0x70)
-
-/* Real input DMA image size */
-#define S5P_CIREAL_ISIZE 0xf8
-#define S5P_CIREAL_ISIZE_AUTOLOAD_EN (1 << 31)
-#define S5P_CIREAL_ISIZE_ADDR_CH_DIS (1 << 30)
-#define S5P_CIREAL_ISIZE_HEIGHT(x) ((x) << 16)
-#define S5P_CIREAL_ISIZE_WIDTH(x) ((x) << 0)
-
-
-/* Input DMA control */
-#define S5P_MSCTRL 0xfc
-#define S5P_MSCTRL_IN_BURST_COUNT_MASK (0xF << 24)
-#define S5P_MSCTRL_2P_IN_ORDER_MASK (3 << 16)
-#define S5P_MSCTRL_2P_IN_ORDER_SHIFT 16
-#define S5P_MSCTRL_C_INT_IN_3PLANE (0 << 15)
-#define S5P_MSCTRL_C_INT_IN_2PLANE (1 << 15)
-#define S5P_MSCTRL_C_INT_IN_MASK (1 << 15)
-#define S5P_MSCTRL_FLIP_SHIFT 13
-#define S5P_MSCTRL_FLIP_MASK (3 << 13)
-#define S5P_MSCTRL_FLIP_NORMAL (0 << 13)
-#define S5P_MSCTRL_FLIP_X_MIRROR (1 << 13)
-#define S5P_MSCTRL_FLIP_Y_MIRROR (2 << 13)
-#define S5P_MSCTRL_FLIP_180 (3 << 13)
-#define S5P_MSCTRL_FIFO_CTRL_FULL (1 << 12)
-#define S5P_MSCTRL_ORDER422_SHIFT 4
-#define S5P_MSCTRL_ORDER422_YCBYCR (0 << 4)
-#define S5P_MSCTRL_ORDER422_CBYCRY (1 << 4)
-#define S5P_MSCTRL_ORDER422_YCRYCB (2 << 4)
-#define S5P_MSCTRL_ORDER422_CRYCBY (3 << 4)
-#define S5P_MSCTRL_ORDER422_MASK (3 << 4)
-#define S5P_MSCTRL_INPUT_EXTCAM (0 << 3)
-#define S5P_MSCTRL_INPUT_MEMORY (1 << 3)
-#define S5P_MSCTRL_INPUT_MASK (1 << 3)
-#define S5P_MSCTRL_INFORMAT_YCBCR420 (0 << 1)
-#define S5P_MSCTRL_INFORMAT_YCBCR422 (1 << 1)
-#define S5P_MSCTRL_INFORMAT_YCBCR422_1P (2 << 1)
-#define S5P_MSCTRL_INFORMAT_RGB (3 << 1)
-#define S5P_MSCTRL_INFORMAT_MASK (3 << 1)
-#define S5P_MSCTRL_ENVID (1 << 0)
-#define S5P_MSCTRL_IN_BURST_COUNT(x) ((x) << 24)
-
-/* Output DMA Y/Cb/Cr offset */
-#define S5P_CIOYOFF 0x168
-#define S5P_CIOCBOFF 0x16c
-#define S5P_CIOCROFF 0x170
-
-/* Input DMA Y/Cb/Cr offset */
-#define S5P_CIIYOFF 0x174
-#define S5P_CIICBOFF 0x178
-#define S5P_CIICROFF 0x17c
-
-#define S5P_CIO_OFFS_VER(x) ((x) << 16)
-#define S5P_CIO_OFFS_HOR(x) ((x) << 0)
-
-/* Input DMA original image size */
-#define S5P_ORGISIZE 0x180
-
-/* Output DMA original image size */
-#define S5P_ORGOSIZE 0x184
-
-#define S5P_ORIG_SIZE_VER(x) ((x) << 16)
-#define S5P_ORIG_SIZE_HOR(x) ((x) << 0)
-
-/* Real output DMA image size (extension register) */
-#define S5P_CIEXTEN 0x188
-#define S5P_CIEXTEN_MHRATIO_EXT(x) (((x) & 0x3f) << 10)
-#define S5P_CIEXTEN_MVRATIO_EXT(x) ((x) & 0x3f)
-#define S5P_CIEXTEN_MHRATIO_EXT_MASK (0x3f << 10)
-#define S5P_CIEXTEN_MVRATIO_EXT_MASK 0x3f
-
-#define S5P_CIDMAPARAM 0x18c
-#define S5P_CIDMAPARAM_R_LINEAR (0 << 29)
-#define S5P_CIDMAPARAM_R_64X32 (3 << 29)
-#define S5P_CIDMAPARAM_W_LINEAR (0 << 13)
-#define S5P_CIDMAPARAM_W_64X32 (3 << 13)
-#define S5P_CIDMAPARAM_TILE_MASK ((3 << 29) | (3 << 13))
-
-/* MIPI CSI image format */
-#define S5P_CSIIMGFMT 0x194
-#define S5P_CSIIMGFMT_YCBCR422_8BIT 0x1e
-#define S5P_CSIIMGFMT_RAW8 0x2a
-#define S5P_CSIIMGFMT_RAW10 0x2b
-#define S5P_CSIIMGFMT_RAW12 0x2c
-/* User defined formats. x = 0...16. */
-#define S5P_CSIIMGFMT_USER(x) (0x30 + x - 1)
-
-/* Output frame buffer sequence mask */
-#define S5P_CIFCNTSEQ 0x1FC
-
-#endif /* REGS_FIMC_H_ */
diff --git a/drivers/media/video/s5p-g2d/g2d.c b/drivers/media/video/s5p-g2d/g2d.c
index 789de74014e5..7c98ee7377ee 100644
--- a/drivers/media/video/s5p-g2d/g2d.c
+++ b/drivers/media/video/s5p-g2d/g2d.c
@@ -65,7 +65,7 @@ static struct g2d_fmt formats[] = {
};
#define NUM_FORMATS ARRAY_SIZE(formats)
-struct g2d_frame def_frame = {
+static struct g2d_frame def_frame = {
.width = DEFAULT_WIDTH,
.height = DEFAULT_HEIGHT,
.c_width = DEFAULT_WIDTH,
@@ -77,7 +77,7 @@ struct g2d_frame def_frame = {
.bottom = DEFAULT_HEIGHT,
};
-struct g2d_fmt *find_fmt(struct v4l2_format *f)
+static struct g2d_fmt *find_fmt(struct v4l2_format *f)
{
unsigned int i;
for (i = 0; i < NUM_FORMATS; i++) {
@@ -202,7 +202,7 @@ static const struct v4l2_ctrl_ops g2d_ctrl_ops = {
.s_ctrl = g2d_s_ctrl,
};
-int g2d_setup_ctrls(struct g2d_ctx *ctx)
+static int g2d_setup_ctrls(struct g2d_ctx *ctx)
{
struct g2d_dev *dev = ctx->dev;
@@ -546,11 +546,11 @@ static void job_abort(void *prv)
struct g2d_dev *dev = ctx->dev;
int ret;
- if (dev->curr == 0) /* No job currently running */
+ if (dev->curr == NULL) /* No job currently running */
return;
ret = wait_event_timeout(dev->irq_queue,
- dev->curr == 0,
+ dev->curr == NULL,
msecs_to_jiffies(G2D_TIMEOUT));
}
@@ -599,19 +599,19 @@ static irqreturn_t g2d_isr(int irq, void *prv)
g2d_clear_int(dev);
clk_disable(dev->gate);
- BUG_ON(ctx == 0);
+ BUG_ON(ctx == NULL);
src = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
dst = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
- BUG_ON(src == 0);
- BUG_ON(dst == 0);
+ BUG_ON(src == NULL);
+ BUG_ON(dst == NULL);
v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE);
v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE);
v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx);
- dev->curr = 0;
+ dev->curr = NULL;
wake_up(&dev->irq_queue);
return IRQ_HANDLED;
}
@@ -674,42 +674,27 @@ static int g2d_probe(struct platform_device *pdev)
struct resource *res;
int ret = 0;
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
+
spin_lock_init(&dev->ctrl_lock);
mutex_init(&dev->mutex);
atomic_set(&dev->num_inst, 0);
init_waitqueue_head(&dev->irq_queue);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "failed to find registers\n");
- ret = -ENOENT;
- goto free_dev;
- }
- dev->res_regs = request_mem_region(res->start, resource_size(res),
- dev_name(&pdev->dev));
-
- if (!dev->res_regs) {
- dev_err(&pdev->dev, "failed to obtain register region\n");
- ret = -ENOENT;
- goto free_dev;
- }
-
- dev->regs = ioremap(res->start, resource_size(res));
- if (!dev->regs) {
- dev_err(&pdev->dev, "failed to map registers\n");
- ret = -ENOENT;
- goto rel_res_regs;
+ dev->regs = devm_request_and_ioremap(&pdev->dev, res);
+ if (dev->regs == NULL) {
+ dev_err(&pdev->dev, "Failed to obtain io memory\n");
+ return -ENOENT;
}
dev->clk = clk_get(&pdev->dev, "sclk_fimg2d");
if (IS_ERR_OR_NULL(dev->clk)) {
dev_err(&pdev->dev, "failed to get g2d clock\n");
- ret = -ENXIO;
- goto unmap_regs;
+ return -ENXIO;
}
ret = clk_prepare(dev->clk);
@@ -740,7 +725,8 @@ static int g2d_probe(struct platform_device *pdev)
dev->irq = res->start;
- ret = request_irq(dev->irq, g2d_isr, 0, pdev->name, dev);
+ ret = devm_request_irq(&pdev->dev, dev->irq, g2d_isr,
+ 0, pdev->name, dev);
if (ret) {
dev_err(&pdev->dev, "failed to install IRQ\n");
goto put_clk_gate;
@@ -749,7 +735,7 @@ static int g2d_probe(struct platform_device *pdev)
dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
if (IS_ERR(dev->alloc_ctx)) {
ret = PTR_ERR(dev->alloc_ctx);
- goto rel_irq;
+ goto unprep_clk_gate;
}
ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
@@ -762,6 +748,10 @@ static int g2d_probe(struct platform_device *pdev)
goto unreg_v4l2_dev;
}
*vfd = g2d_videodev;
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
vfd->lock = &dev->mutex;
ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
if (ret) {
@@ -793,8 +783,6 @@ unreg_v4l2_dev:
v4l2_device_unregister(&dev->v4l2_dev);
alloc_ctx_cleanup:
vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
-rel_irq:
- free_irq(dev->irq, dev);
unprep_clk_gate:
clk_unprepare(dev->gate);
put_clk_gate:
@@ -803,12 +791,7 @@ unprep_clk:
clk_unprepare(dev->clk);
put_clk:
clk_put(dev->clk);
-unmap_regs:
- iounmap(dev->regs);
-rel_res_regs:
- release_resource(dev->res_regs);
-free_dev:
- kfree(dev);
+
return ret;
}
@@ -821,14 +804,10 @@ static int g2d_remove(struct platform_device *pdev)
video_unregister_device(dev->vfd);
v4l2_device_unregister(&dev->v4l2_dev);
vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
- free_irq(dev->irq, dev);
clk_unprepare(dev->gate);
clk_put(dev->gate);
clk_unprepare(dev->clk);
clk_put(dev->clk);
- iounmap(dev->regs);
- release_resource(dev->res_regs);
- kfree(dev);
return 0;
}
diff --git a/drivers/media/video/s5p-g2d/g2d.h b/drivers/media/video/s5p-g2d/g2d.h
index 1b82065aeaef..6b765b0216c5 100644
--- a/drivers/media/video/s5p-g2d/g2d.h
+++ b/drivers/media/video/s5p-g2d/g2d.h
@@ -23,7 +23,6 @@ struct g2d_dev {
spinlock_t ctrl_lock;
atomic_t num_inst;
struct vb2_alloc_ctx *alloc_ctx;
- struct resource *res_regs;
void __iomem *regs;
struct clk *clk;
struct clk *gate;
diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.c b/drivers/media/video/s5p-jpeg/jpeg-core.c
index 5a49c307f9c1..28b5225d94f5 100644
--- a/drivers/media/video/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/video/s5p-jpeg/jpeg-core.c
@@ -813,7 +813,7 @@ static int s5p_jpeg_streamoff(struct file *file, void *priv,
return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
}
-int s5p_jpeg_g_selection(struct file *file, void *priv,
+static int s5p_jpeg_g_selection(struct file *file, void *priv,
struct v4l2_selection *s)
{
struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
@@ -1290,7 +1290,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
int ret;
/* JPEG IP abstraction struct */
- jpeg = kzalloc(sizeof(struct s5p_jpeg), GFP_KERNEL);
+ jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL);
if (!jpeg)
return -ENOMEM;
@@ -1300,43 +1300,25 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
/* memory-mapped registers */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "cannot find IO resource\n");
- ret = -ENOENT;
- goto jpeg_alloc_rollback;
- }
-
- jpeg->ioarea = request_mem_region(res->start, resource_size(res),
- pdev->name);
- if (!jpeg->ioarea) {
- dev_err(&pdev->dev, "cannot request IO\n");
- ret = -ENXIO;
- goto jpeg_alloc_rollback;
- }
- jpeg->regs = ioremap(res->start, resource_size(res));
- if (!jpeg->regs) {
- dev_err(&pdev->dev, "cannot map IO\n");
- ret = -ENXIO;
- goto mem_region_rollback;
+ jpeg->regs = devm_request_and_ioremap(&pdev->dev, res);
+ if (jpeg->regs == NULL) {
+ dev_err(&pdev->dev, "Failed to obtain io memory\n");
+ return -ENOENT;
}
- dev_dbg(&pdev->dev, "registers %p (%p, %p)\n",
- jpeg->regs, jpeg->ioarea, res);
-
/* interrupt service routine registration */
jpeg->irq = ret = platform_get_irq(pdev, 0);
if (ret < 0) {
dev_err(&pdev->dev, "cannot find IRQ\n");
- goto ioremap_rollback;
+ return ret;
}
- ret = request_irq(jpeg->irq, s5p_jpeg_irq, 0,
- dev_name(&pdev->dev), jpeg);
-
+ ret = devm_request_irq(&pdev->dev, jpeg->irq, s5p_jpeg_irq, 0,
+ dev_name(&pdev->dev), jpeg);
if (ret) {
dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
- goto ioremap_rollback;
+ return ret;
}
/* clocks */
@@ -1344,7 +1326,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
if (IS_ERR(jpeg->clk)) {
dev_err(&pdev->dev, "cannot get clock\n");
ret = PTR_ERR(jpeg->clk);
- goto request_irq_rollback;
+ return ret;
}
dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk);
clk_enable(jpeg->clk);
@@ -1386,6 +1368,10 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
jpeg->vfd_encoder->release = video_device_release;
jpeg->vfd_encoder->lock = &jpeg->lock;
jpeg->vfd_encoder->v4l2_dev = &jpeg->v4l2_dev;
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &jpeg->vfd_encoder->flags);
ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
if (ret) {
@@ -1413,6 +1399,10 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
jpeg->vfd_decoder->release = video_device_release;
jpeg->vfd_decoder->lock = &jpeg->lock;
jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev;
+ /* Locking in file operations other than ioctl should be done by the driver,
+ not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &jpeg->vfd_decoder->flags);
ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
if (ret) {
@@ -1456,18 +1446,6 @@ clk_get_rollback:
clk_disable(jpeg->clk);
clk_put(jpeg->clk);
-request_irq_rollback:
- free_irq(jpeg->irq, jpeg);
-
-ioremap_rollback:
- iounmap(jpeg->regs);
-
-mem_region_rollback:
- release_resource(jpeg->ioarea);
- release_mem_region(jpeg->ioarea->start, resource_size(jpeg->ioarea));
-
-jpeg_alloc_rollback:
- kfree(jpeg);
return ret;
}
@@ -1488,14 +1466,6 @@ static int s5p_jpeg_remove(struct platform_device *pdev)
clk_disable(jpeg->clk);
clk_put(jpeg->clk);
- free_irq(jpeg->irq, jpeg);
-
- iounmap(jpeg->regs);
-
- release_resource(jpeg->ioarea);
- release_mem_region(jpeg->ioarea->start, resource_size(jpeg->ioarea));
- kfree(jpeg);
-
return 0;
}
diff --git a/drivers/media/video/s5p-jpeg/jpeg-core.h b/drivers/media/video/s5p-jpeg/jpeg-core.h
index 38d7367f7a6d..9d0cd2b76f61 100644
--- a/drivers/media/video/s5p-jpeg/jpeg-core.h
+++ b/drivers/media/video/s5p-jpeg/jpeg-core.h
@@ -54,7 +54,6 @@
* @vfd_encoder: video device node for encoder mem2mem mode
* @vfd_decoder: video device node for decoder mem2mem mode
* @m2m_dev: v4l2 mem2mem device data
- * @ioarea: JPEG IP memory region
* @regs: JPEG IP registers mapping
* @irq: JPEG IP irq
* @clk: JPEG IP clock
@@ -70,7 +69,6 @@ struct s5p_jpeg {
struct video_device *vfd_decoder;
struct v4l2_m2m_dev *m2m_dev;
- struct resource *ioarea;
void __iomem *regs;
unsigned int irq;
struct clk *clk;
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc.c b/drivers/media/video/s5p-mfc/s5p_mfc.c
index 83fe461af263..9bb68e7b5ae8 100644
--- a/drivers/media/video/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/video/s5p-mfc/s5p_mfc.c
@@ -70,7 +70,7 @@ static void wake_up_dev(struct s5p_mfc_dev *dev, unsigned int reason,
wake_up(&dev->queue);
}
-void s5p_mfc_watchdog(unsigned long arg)
+static void s5p_mfc_watchdog(unsigned long arg)
{
struct s5p_mfc_dev *dev = (struct s5p_mfc_dev *)arg;
@@ -373,7 +373,7 @@ static void s5p_mfc_handle_error(struct s5p_mfc_ctx *ctx,
/* If no context is available then all necessary
* processing has been done. */
- if (ctx == 0)
+ if (ctx == NULL)
return;
dev = ctx->dev;
@@ -429,7 +429,7 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
struct s5p_mfc_dev *dev;
unsigned int guard_width, guard_height;
- if (ctx == 0)
+ if (ctx == NULL)
return;
dev = ctx->dev;
if (ctx->c_ops->post_seq_start) {
@@ -496,7 +496,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx,
struct s5p_mfc_dev *dev;
unsigned long flags;
- if (ctx == 0)
+ if (ctx == NULL)
return;
dev = ctx->dev;
s5p_mfc_clear_int_flags(dev);
@@ -772,7 +772,7 @@ err_queue_init:
err_init_hw:
s5p_mfc_release_firmware(dev);
err_alloc_fw:
- dev->ctx[ctx->num] = 0;
+ dev->ctx[ctx->num] = NULL;
del_timer_sync(&dev->watchdog_timer);
s5p_mfc_clock_off();
err_pwr_enable:
@@ -849,7 +849,7 @@ static int s5p_mfc_release(struct file *file)
}
mfc_debug(2, "Shutting down clock\n");
s5p_mfc_clock_off();
- dev->ctx[ctx->num] = 0;
+ dev->ctx[ctx->num] = NULL;
s5p_mfc_dec_ctrls_delete(ctx);
v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh);
@@ -948,7 +948,7 @@ static int s5p_mfc_probe(struct platform_device *pdev)
int ret;
pr_debug("%s++\n", __func__);
- dev = kzalloc(sizeof *dev, GFP_KERNEL);
+ dev = devm_kzalloc(&pdev->dev, sizeof *dev, GFP_KERNEL);
if (!dev) {
dev_err(&pdev->dev, "Not enough memory for MFC device\n");
return -ENOMEM;
@@ -959,49 +959,35 @@ static int s5p_mfc_probe(struct platform_device *pdev)
dev->plat_dev = pdev;
if (!dev->plat_dev) {
dev_err(&pdev->dev, "No platform data specified\n");
- ret = -ENODEV;
- goto err_dev;
+ return -ENODEV;
}
ret = s5p_mfc_init_pm(dev);
if (ret < 0) {
dev_err(&pdev->dev, "failed to get mfc clock source\n");
- goto err_clk;
+ return ret;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "failed to get memory region resource\n");
- ret = -ENOENT;
- goto err_res;
- }
- dev->mfc_mem = request_mem_region(res->start, resource_size(res),
- pdev->name);
- if (dev->mfc_mem == NULL) {
- dev_err(&pdev->dev, "failed to get memory region\n");
- ret = -ENOENT;
- goto err_mem_reg;
- }
- dev->regs_base = ioremap(dev->mfc_mem->start, resource_size(dev->mfc_mem));
+ dev->regs_base = devm_request_and_ioremap(&pdev->dev, res);
if (dev->regs_base == NULL) {
- dev_err(&pdev->dev, "failed to ioremap address region\n");
- ret = -ENOENT;
- goto err_ioremap;
+ dev_err(&pdev->dev, "Failed to obtain io memory\n");
+ return -ENOENT;
}
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL) {
dev_err(&pdev->dev, "failed to get irq resource\n");
ret = -ENOENT;
- goto err_get_res;
+ goto err_res;
}
dev->irq = res->start;
- ret = request_irq(dev->irq, s5p_mfc_irq, IRQF_DISABLED, pdev->name,
- dev);
+ ret = devm_request_irq(&pdev->dev, dev->irq, s5p_mfc_irq,
+ IRQF_DISABLED, pdev->name, dev);
if (ret) {
dev_err(&pdev->dev, "Failed to install irq (%d)\n", ret);
- goto err_req_irq;
+ goto err_res;
}
dev->mem_dev_l = device_find_child(&dev->plat_dev->dev, "s5p-mfc-l",
@@ -1009,20 +995,20 @@ static int s5p_mfc_probe(struct platform_device *pdev)
if (!dev->mem_dev_l) {
mfc_err("Mem child (L) device get failed\n");
ret = -ENODEV;
- goto err_find_child;
+ goto err_res;
}
dev->mem_dev_r = device_find_child(&dev->plat_dev->dev, "s5p-mfc-r",
match_child);
if (!dev->mem_dev_r) {
mfc_err("Mem child (R) device get failed\n");
ret = -ENODEV;
- goto err_find_child;
+ goto err_res;
}
dev->alloc_ctx[0] = vb2_dma_contig_init_ctx(dev->mem_dev_l);
if (IS_ERR_OR_NULL(dev->alloc_ctx[0])) {
ret = PTR_ERR(dev->alloc_ctx[0]);
- goto err_mem_init_ctx_0;
+ goto err_res;
}
dev->alloc_ctx[1] = vb2_dma_contig_init_ctx(dev->mem_dev_r);
if (IS_ERR_OR_NULL(dev->alloc_ctx[1])) {
@@ -1048,6 +1034,10 @@ static int s5p_mfc_probe(struct platform_device *pdev)
vfd->ioctl_ops = get_dec_v4l2_ioctl_ops();
vfd->release = video_device_release,
vfd->lock = &dev->mfc_mutex;
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
vfd->v4l2_dev = &dev->v4l2_dev;
snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_DEC_NAME);
dev->vfd_dec = vfd;
@@ -1072,6 +1062,8 @@ static int s5p_mfc_probe(struct platform_device *pdev)
vfd->ioctl_ops = get_enc_v4l2_ioctl_ops();
vfd->release = video_device_release,
vfd->lock = &dev->mfc_mutex;
+ /* This should not be necessary */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
vfd->v4l2_dev = &dev->v4l2_dev;
snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_ENC_NAME);
dev->vfd_enc = vfd;
@@ -1110,22 +1102,9 @@ err_v4l2_dev_reg:
vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]);
err_mem_init_ctx_1:
vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]);
-err_mem_init_ctx_0:
-err_find_child:
- free_irq(dev->irq, dev);
-err_req_irq:
-err_get_res:
- iounmap(dev->regs_base);
- dev->regs_base = NULL;
-err_ioremap:
- release_resource(dev->mfc_mem);
- kfree(dev->mfc_mem);
-err_mem_reg:
err_res:
s5p_mfc_final_pm(dev);
-err_clk:
-err_dev:
- kfree(dev);
+
pr_debug("%s-- with error\n", __func__);
return ret;
@@ -1148,15 +1127,7 @@ static int __devexit s5p_mfc_remove(struct platform_device *pdev)
vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]);
vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]);
- free_irq(dev->irq, dev);
- iounmap(dev->regs_base);
- if (dev->mfc_mem) {
- release_resource(dev->mfc_mem);
- kfree(dev->mfc_mem);
- dev->mfc_mem = NULL;
- }
s5p_mfc_final_pm(dev);
- kfree(dev);
return 0;
}
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_common.h b/drivers/media/video/s5p-mfc/s5p_mfc_common.h
index 91146fa622e4..bd5706a6bad1 100644
--- a/drivers/media/video/s5p-mfc/s5p_mfc_common.h
+++ b/drivers/media/video/s5p-mfc/s5p_mfc_common.h
@@ -185,7 +185,6 @@ struct s5p_mfc_pm {
* @mem_dev_r: child device of the right memory bank (1)
* @regs_base: base address of the MFC hw registers
* @irq: irq resource
- * @mfc_mem: MFC registers memory resource
* @dec_ctrl_handler: control framework handler for decoding
* @enc_ctrl_handler: control framework handler for encoding
* @pm: power management control
@@ -221,7 +220,6 @@ struct s5p_mfc_dev {
struct device *mem_dev_r;
void __iomem *regs_base;
int irq;
- struct resource *mfc_mem;
struct v4l2_ctrl_handler dec_ctrl_handler;
struct v4l2_ctrl_handler enc_ctrl_handler;
struct s5p_mfc_pm pm;
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c
index f2481a85e0a2..08a5cfeaa59e 100644
--- a/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c
+++ b/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c
@@ -52,7 +52,7 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev)
s5p_mfc_bitproc_buf = vb2_dma_contig_memops.alloc(
dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], dev->fw_size);
if (IS_ERR(s5p_mfc_bitproc_buf)) {
- s5p_mfc_bitproc_buf = 0;
+ s5p_mfc_bitproc_buf = NULL;
mfc_err("Allocating bitprocessor buffer failed\n");
release_firmware(fw_blob);
return -ENOMEM;
@@ -63,7 +63,7 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev)
mfc_err("The base memory for bank 1 is not aligned to 128KB\n");
vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
s5p_mfc_bitproc_phys = 0;
- s5p_mfc_bitproc_buf = 0;
+ s5p_mfc_bitproc_buf = NULL;
release_firmware(fw_blob);
return -EIO;
}
@@ -72,7 +72,7 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev)
mfc_err("Bitprocessor memory remap failed\n");
vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
s5p_mfc_bitproc_phys = 0;
- s5p_mfc_bitproc_buf = 0;
+ s5p_mfc_bitproc_buf = NULL;
release_firmware(fw_blob);
return -EIO;
}
@@ -82,7 +82,7 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev)
if (IS_ERR(b_base)) {
vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
s5p_mfc_bitproc_phys = 0;
- s5p_mfc_bitproc_buf = 0;
+ s5p_mfc_bitproc_buf = NULL;
mfc_err("Allocating bank2 base failed\n");
release_firmware(fw_blob);
return -ENOMEM;
@@ -94,7 +94,7 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev)
mfc_err("The base memory for bank 2 is not aligned to 128KB\n");
vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
s5p_mfc_bitproc_phys = 0;
- s5p_mfc_bitproc_buf = 0;
+ s5p_mfc_bitproc_buf = NULL;
release_firmware(fw_blob);
return -EIO;
}
@@ -126,7 +126,7 @@ int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev)
release_firmware(fw_blob);
return -ENOMEM;
}
- if (s5p_mfc_bitproc_buf == 0 || s5p_mfc_bitproc_phys == 0) {
+ if (s5p_mfc_bitproc_buf == NULL || s5p_mfc_bitproc_phys == 0) {
mfc_err("MFC firmware is not allocated or was not mapped correctly\n");
release_firmware(fw_blob);
return -EINVAL;
@@ -146,9 +146,9 @@ int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev)
if (!s5p_mfc_bitproc_buf)
return -EINVAL;
vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
- s5p_mfc_bitproc_virt = 0;
+ s5p_mfc_bitproc_virt = NULL;
s5p_mfc_bitproc_phys = 0;
- s5p_mfc_bitproc_buf = 0;
+ s5p_mfc_bitproc_buf = NULL;
return 0;
}
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c
index dff9dc798795..acedb2004be3 100644
--- a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c
@@ -1436,7 +1436,8 @@ static const struct v4l2_ctrl_ops s5p_mfc_enc_ctrl_ops = {
.s_ctrl = s5p_mfc_enc_s_ctrl,
};
-int vidioc_s_parm(struct file *file, void *priv, struct v4l2_streamparm *a)
+static int vidioc_s_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *a)
{
struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
@@ -1452,7 +1453,8 @@ int vidioc_s_parm(struct file *file, void *priv, struct v4l2_streamparm *a)
return 0;
}
-int vidioc_g_parm(struct file *file, void *priv, struct v4l2_streamparm *a)
+static int vidioc_g_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *a)
{
struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_opr.c b/drivers/media/video/s5p-mfc/s5p_mfc_opr.c
index e08b21c50ebf..e6217cbfa4a3 100644
--- a/drivers/media/video/s5p-mfc/s5p_mfc_opr.c
+++ b/drivers/media/video/s5p-mfc/s5p_mfc_opr.c
@@ -43,7 +43,7 @@ int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx)
ctx->desc_buf = vb2_dma_contig_memops.alloc(
dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], DESC_BUF_SIZE);
if (IS_ERR_VALUE((int)ctx->desc_buf)) {
- ctx->desc_buf = 0;
+ ctx->desc_buf = NULL;
mfc_err("Allocating DESC buffer failed\n");
return -ENOMEM;
}
@@ -54,7 +54,7 @@ int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx)
if (desc_virt == NULL) {
vb2_dma_contig_memops.put(ctx->desc_buf);
ctx->desc_phys = 0;
- ctx->desc_buf = 0;
+ ctx->desc_buf = NULL;
mfc_err("Remapping DESC buffer failed\n");
return -ENOMEM;
}
@@ -69,7 +69,7 @@ void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx)
if (ctx->desc_phys) {
vb2_dma_contig_memops.put(ctx->desc_buf);
ctx->desc_phys = 0;
- ctx->desc_buf = 0;
+ ctx->desc_buf = NULL;
}
}
@@ -186,7 +186,7 @@ int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx)
ctx->bank1_buf = vb2_dma_contig_memops.alloc(
dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_size);
if (IS_ERR(ctx->bank1_buf)) {
- ctx->bank1_buf = 0;
+ ctx->bank1_buf = NULL;
printk(KERN_ERR
"Buf alloc for decoding failed (port A)\n");
return -ENOMEM;
@@ -200,7 +200,7 @@ int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx)
ctx->bank2_buf = vb2_dma_contig_memops.alloc(
dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_size);
if (IS_ERR(ctx->bank2_buf)) {
- ctx->bank2_buf = 0;
+ ctx->bank2_buf = NULL;
mfc_err("Buf alloc for decoding failed (port B)\n");
return -ENOMEM;
}
@@ -216,13 +216,13 @@ void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx)
{
if (ctx->bank1_buf) {
vb2_dma_contig_memops.put(ctx->bank1_buf);
- ctx->bank1_buf = 0;
+ ctx->bank1_buf = NULL;
ctx->bank1_phys = 0;
ctx->bank1_size = 0;
}
if (ctx->bank2_buf) {
vb2_dma_contig_memops.put(ctx->bank2_buf);
- ctx->bank2_buf = 0;
+ ctx->bank2_buf = NULL;
ctx->bank2_phys = 0;
ctx->bank2_size = 0;
}
@@ -244,7 +244,7 @@ int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx)
if (IS_ERR(ctx->ctx_buf)) {
mfc_err("Allocating context buffer failed\n");
ctx->ctx_phys = 0;
- ctx->ctx_buf = 0;
+ ctx->ctx_buf = NULL;
return -ENOMEM;
}
ctx->ctx_phys = s5p_mfc_mem_cookie(
@@ -256,7 +256,7 @@ int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx)
mfc_err("Remapping instance buffer failed\n");
vb2_dma_contig_memops.put(ctx->ctx_buf);
ctx->ctx_phys = 0;
- ctx->ctx_buf = 0;
+ ctx->ctx_buf = NULL;
return -ENOMEM;
}
/* Zero content of the allocated memory */
@@ -265,7 +265,7 @@ int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx)
if (s5p_mfc_init_shm(ctx) < 0) {
vb2_dma_contig_memops.put(ctx->ctx_buf);
ctx->ctx_phys = 0;
- ctx->ctx_buf = 0;
+ ctx->ctx_buf = NULL;
return -ENOMEM;
}
return 0;
@@ -277,12 +277,12 @@ void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx)
if (ctx->ctx_buf) {
vb2_dma_contig_memops.put(ctx->ctx_buf);
ctx->ctx_phys = 0;
- ctx->ctx_buf = 0;
+ ctx->ctx_buf = NULL;
}
if (ctx->shm_alloc) {
vb2_dma_contig_memops.put(ctx->shm_alloc);
- ctx->shm_alloc = 0;
- ctx->shm = 0;
+ ctx->shm_alloc = NULL;
+ ctx->shm = NULL;
}
}
@@ -296,7 +296,7 @@ void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx)
}
/* Set registers for shared buffer */
-void s5p_mfc_set_shared_buffer(struct s5p_mfc_ctx *ctx)
+static void s5p_mfc_set_shared_buffer(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
mfc_write(dev, ctx->shm_ofs, S5P_FIMV_SI_CH0_HOST_WR_ADR);
diff --git a/drivers/media/video/s5p-tv/hdmi_drv.c b/drivers/media/video/s5p-tv/hdmi_drv.c
index 4865d25a0e57..20cb6eef2979 100644
--- a/drivers/media/video/s5p-tv/hdmi_drv.c
+++ b/drivers/media/video/s5p-tv/hdmi_drv.c
@@ -42,7 +42,23 @@ MODULE_DESCRIPTION("Samsung HDMI");
MODULE_LICENSE("GPL");
/* default preset configured on probe */
-#define HDMI_DEFAULT_PRESET V4L2_DV_1080P60
+#define HDMI_DEFAULT_PRESET V4L2_DV_480P59_94
+
+struct hdmi_pulse {
+ u32 beg;
+ u32 end;
+};
+
+struct hdmi_timings {
+ struct hdmi_pulse hact;
+ u32 hsyn_pol; /* 0 - high, 1 - low */
+ struct hdmi_pulse hsyn;
+ u32 interlaced;
+ struct hdmi_pulse vact[2];
+ u32 vsyn_pol; /* 0 - high, 1 - low */
+ u32 vsyn_off;
+ struct hdmi_pulse vsyn[2];
+};
struct hdmi_resources {
struct clk *hdmi;
@@ -70,64 +86,15 @@ struct hdmi_device {
/** subdev of MHL interface */
struct v4l2_subdev *mhl_sd;
/** configuration of current graphic mode */
- const struct hdmi_preset_conf *cur_conf;
+ const struct hdmi_timings *cur_conf;
+ /** flag indicating that timings are dirty */
+ int cur_conf_dirty;
/** current preset */
u32 cur_preset;
/** other resources */
struct hdmi_resources res;
};
-struct hdmi_tg_regs {
- u8 cmd;
- u8 h_fsz_l;
- u8 h_fsz_h;
- u8 hact_st_l;
- u8 hact_st_h;
- u8 hact_sz_l;
- u8 hact_sz_h;
- u8 v_fsz_l;
- u8 v_fsz_h;
- u8 vsync_l;
- u8 vsync_h;
- u8 vsync2_l;
- u8 vsync2_h;
- u8 vact_st_l;
- u8 vact_st_h;
- u8 vact_sz_l;
- u8 vact_sz_h;
- u8 field_chg_l;
- u8 field_chg_h;
- u8 vact_st2_l;
- u8 vact_st2_h;
- u8 vsync_top_hdmi_l;
- u8 vsync_top_hdmi_h;
- u8 vsync_bot_hdmi_l;
- u8 vsync_bot_hdmi_h;
- u8 field_top_hdmi_l;
- u8 field_top_hdmi_h;
- u8 field_bot_hdmi_l;
- u8 field_bot_hdmi_h;
-};
-
-struct hdmi_core_regs {
- u8 h_blank[2];
- u8 v_blank[3];
- u8 h_v_line[3];
- u8 vsync_pol[1];
- u8 int_pro_mode[1];
- u8 v_blank_f[3];
- u8 h_sync_gen[3];
- u8 v_sync_gen1[3];
- u8 v_sync_gen2[3];
- u8 v_sync_gen3[3];
-};
-
-struct hdmi_preset_conf {
- struct hdmi_core_regs core;
- struct hdmi_tg_regs tg;
- struct v4l2_mbus_framefmt mbus_fmt;
-};
-
static struct platform_device_id hdmi_driver_types[] = {
{
.name = "s5pv210-hdmi",
@@ -165,6 +132,21 @@ void hdmi_writeb(struct hdmi_device *hdev, u32 reg_id, u8 value)
writeb(value, hdev->regs + reg_id);
}
+static inline
+void hdmi_writebn(struct hdmi_device *hdev, u32 reg_id, int n, u32 value)
+{
+ switch (n) {
+ default:
+ writeb(value >> 24, hdev->regs + reg_id + 12);
+ case 3:
+ writeb(value >> 16, hdev->regs + reg_id + 8);
+ case 2:
+ writeb(value >> 8, hdev->regs + reg_id + 4);
+ case 1:
+ writeb(value >> 0, hdev->regs + reg_id + 0);
+ }
+}
+
static inline u32 hdmi_read(struct hdmi_device *hdev, u32 reg_id)
{
return readl(hdev->regs + reg_id);
@@ -211,77 +193,72 @@ static void hdmi_reg_init(struct hdmi_device *hdev)
}
static void hdmi_timing_apply(struct hdmi_device *hdev,
- const struct hdmi_preset_conf *conf)
+ const struct hdmi_timings *t)
{
- const struct hdmi_core_regs *core = &conf->core;
- const struct hdmi_tg_regs *tg = &conf->tg;
-
/* setting core registers */
- hdmi_writeb(hdev, HDMI_H_BLANK_0, core->h_blank[0]);
- hdmi_writeb(hdev, HDMI_H_BLANK_1, core->h_blank[1]);
- hdmi_writeb(hdev, HDMI_V_BLANK_0, core->v_blank[0]);
- hdmi_writeb(hdev, HDMI_V_BLANK_1, core->v_blank[1]);
- hdmi_writeb(hdev, HDMI_V_BLANK_2, core->v_blank[2]);
- hdmi_writeb(hdev, HDMI_H_V_LINE_0, core->h_v_line[0]);
- hdmi_writeb(hdev, HDMI_H_V_LINE_1, core->h_v_line[1]);
- hdmi_writeb(hdev, HDMI_H_V_LINE_2, core->h_v_line[2]);
- hdmi_writeb(hdev, HDMI_VSYNC_POL, core->vsync_pol[0]);
- hdmi_writeb(hdev, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
- hdmi_writeb(hdev, HDMI_V_BLANK_F_0, core->v_blank_f[0]);
- hdmi_writeb(hdev, HDMI_V_BLANK_F_1, core->v_blank_f[1]);
- hdmi_writeb(hdev, HDMI_V_BLANK_F_2, core->v_blank_f[2]);
- hdmi_writeb(hdev, HDMI_H_SYNC_GEN_0, core->h_sync_gen[0]);
- hdmi_writeb(hdev, HDMI_H_SYNC_GEN_1, core->h_sync_gen[1]);
- hdmi_writeb(hdev, HDMI_H_SYNC_GEN_2, core->h_sync_gen[2]);
- hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
- hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
- hdmi_writeb(hdev, HDMI_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
- hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
- hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
- hdmi_writeb(hdev, HDMI_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
- hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
- hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
- hdmi_writeb(hdev, HDMI_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
+ hdmi_writebn(hdev, HDMI_H_BLANK_0, 2, t->hact.beg);
+ hdmi_writebn(hdev, HDMI_H_SYNC_GEN_0, 3,
+ (t->hsyn_pol << 20) | (t->hsyn.end << 10) | t->hsyn.beg);
+ hdmi_writeb(hdev, HDMI_VSYNC_POL, t->vsyn_pol);
+ hdmi_writebn(hdev, HDMI_V_BLANK_0, 3,
+ (t->vact[0].beg << 11) | t->vact[0].end);
+ hdmi_writebn(hdev, HDMI_V_SYNC_GEN_1_0, 3,
+ (t->vsyn[0].beg << 12) | t->vsyn[0].end);
+ if (t->interlaced) {
+ u32 vsyn_trans = t->hsyn.beg + t->vsyn_off;
+
+ hdmi_writeb(hdev, HDMI_INT_PRO_MODE, 1);
+ hdmi_writebn(hdev, HDMI_H_V_LINE_0, 3,
+ (t->hact.end << 12) | t->vact[1].end);
+ hdmi_writebn(hdev, HDMI_V_BLANK_F_0, 3,
+ (t->vact[1].end << 11) | t->vact[1].beg);
+ hdmi_writebn(hdev, HDMI_V_SYNC_GEN_2_0, 3,
+ (t->vsyn[1].beg << 12) | t->vsyn[1].end);
+ hdmi_writebn(hdev, HDMI_V_SYNC_GEN_3_0, 3,
+ (vsyn_trans << 12) | vsyn_trans);
+ } else {
+ hdmi_writeb(hdev, HDMI_INT_PRO_MODE, 0);
+ hdmi_writebn(hdev, HDMI_H_V_LINE_0, 3,
+ (t->hact.end << 12) | t->vact[0].end);
+ }
+
/* Timing generator registers */
- hdmi_writeb(hdev, HDMI_TG_H_FSZ_L, tg->h_fsz_l);
- hdmi_writeb(hdev, HDMI_TG_H_FSZ_H, tg->h_fsz_h);
- hdmi_writeb(hdev, HDMI_TG_HACT_ST_L, tg->hact_st_l);
- hdmi_writeb(hdev, HDMI_TG_HACT_ST_H, tg->hact_st_h);
- hdmi_writeb(hdev, HDMI_TG_HACT_SZ_L, tg->hact_sz_l);
- hdmi_writeb(hdev, HDMI_TG_HACT_SZ_H, tg->hact_sz_h);
- hdmi_writeb(hdev, HDMI_TG_V_FSZ_L, tg->v_fsz_l);
- hdmi_writeb(hdev, HDMI_TG_V_FSZ_H, tg->v_fsz_h);
- hdmi_writeb(hdev, HDMI_TG_VSYNC_L, tg->vsync_l);
- hdmi_writeb(hdev, HDMI_TG_VSYNC_H, tg->vsync_h);
- hdmi_writeb(hdev, HDMI_TG_VSYNC2_L, tg->vsync2_l);
- hdmi_writeb(hdev, HDMI_TG_VSYNC2_H, tg->vsync2_h);
- hdmi_writeb(hdev, HDMI_TG_VACT_ST_L, tg->vact_st_l);
- hdmi_writeb(hdev, HDMI_TG_VACT_ST_H, tg->vact_st_h);
- hdmi_writeb(hdev, HDMI_TG_VACT_SZ_L, tg->vact_sz_l);
- hdmi_writeb(hdev, HDMI_TG_VACT_SZ_H, tg->vact_sz_h);
- hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_L, tg->field_chg_l);
- hdmi_writeb(hdev, HDMI_TG_FIELD_CHG_H, tg->field_chg_h);
- hdmi_writeb(hdev, HDMI_TG_VACT_ST2_L, tg->vact_st2_l);
- hdmi_writeb(hdev, HDMI_TG_VACT_ST2_H, tg->vact_st2_h);
- hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi_l);
- hdmi_writeb(hdev, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi_h);
- hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi_l);
- hdmi_writeb(hdev, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi_h);
- hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi_l);
- hdmi_writeb(hdev, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi_h);
- hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi_l);
- hdmi_writeb(hdev, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi_h);
+ hdmi_writebn(hdev, HDMI_TG_H_FSZ_L, 2, t->hact.end);
+ hdmi_writebn(hdev, HDMI_TG_HACT_ST_L, 2, t->hact.beg);
+ hdmi_writebn(hdev, HDMI_TG_HACT_SZ_L, 2, t->hact.end - t->hact.beg);
+ hdmi_writebn(hdev, HDMI_TG_VSYNC_L, 2, t->vsyn[0].beg);
+ hdmi_writebn(hdev, HDMI_TG_VACT_ST_L, 2, t->vact[0].beg);
+ hdmi_writebn(hdev, HDMI_TG_VACT_SZ_L, 2,
+ t->vact[0].end - t->vact[0].beg);
+ hdmi_writebn(hdev, HDMI_TG_VSYNC_TOP_HDMI_L, 2, t->vsyn[0].beg);
+ hdmi_writebn(hdev, HDMI_TG_FIELD_TOP_HDMI_L, 2, t->vsyn[0].beg);
+ if (t->interlaced) {
+ hdmi_write_mask(hdev, HDMI_TG_CMD, ~0, HDMI_TG_FIELD_EN);
+ hdmi_writebn(hdev, HDMI_TG_V_FSZ_L, 2, t->vact[1].end);
+ hdmi_writebn(hdev, HDMI_TG_VSYNC2_L, 2, t->vsyn[1].beg);
+ hdmi_writebn(hdev, HDMI_TG_FIELD_CHG_L, 2, t->vact[0].end);
+ hdmi_writebn(hdev, HDMI_TG_VACT_ST2_L, 2, t->vact[1].beg);
+ hdmi_writebn(hdev, HDMI_TG_VSYNC_BOT_HDMI_L, 2, t->vsyn[1].beg);
+ hdmi_writebn(hdev, HDMI_TG_FIELD_BOT_HDMI_L, 2, t->vsyn[1].beg);
+ } else {
+ hdmi_write_mask(hdev, HDMI_TG_CMD, 0, HDMI_TG_FIELD_EN);
+ hdmi_writebn(hdev, HDMI_TG_V_FSZ_L, 2, t->vact[0].end);
+ }
}
static int hdmi_conf_apply(struct hdmi_device *hdmi_dev)
{
struct device *dev = hdmi_dev->dev;
- const struct hdmi_preset_conf *conf = hdmi_dev->cur_conf;
+ const struct hdmi_timings *conf = hdmi_dev->cur_conf;
struct v4l2_dv_preset preset;
int ret;
dev_dbg(dev, "%s\n", __func__);
+ /* skip if conf is already synchronized with HW */
+ if (!hdmi_dev->cur_conf_dirty)
+ return 0;
+
/* reset hdmiphy */
hdmi_write_mask(hdmi_dev, HDMI_PHY_RSTOUT, ~0, HDMI_PHY_SW_RSTOUT);
mdelay(10);
@@ -307,6 +284,8 @@ static int hdmi_conf_apply(struct hdmi_device *hdmi_dev)
/* setting core registers */
hdmi_timing_apply(hdmi_dev, conf);
+ hdmi_dev->cur_conf_dirty = 0;
+
return 0;
}
@@ -398,156 +377,126 @@ static void hdmi_dumpregs(struct hdmi_device *hdev, char *prefix)
#undef DUMPREG
}
-static const struct hdmi_preset_conf hdmi_conf_480p = {
- .core = {
- .h_blank = {0x8a, 0x00},
- .v_blank = {0x0d, 0x6a, 0x01},
- .h_v_line = {0x0d, 0xa2, 0x35},
- .vsync_pol = {0x01},
- .int_pro_mode = {0x00},
- .v_blank_f = {0x00, 0x00, 0x00},
- .h_sync_gen = {0x0e, 0x30, 0x11},
- .v_sync_gen1 = {0x0f, 0x90, 0x00},
- /* other don't care */
- },
- .tg = {
- 0x00, /* cmd */
- 0x5a, 0x03, /* h_fsz */
- 0x8a, 0x00, 0xd0, 0x02, /* hact */
- 0x0d, 0x02, /* v_fsz */
- 0x01, 0x00, 0x33, 0x02, /* vsync */
- 0x2d, 0x00, 0xe0, 0x01, /* vact */
- 0x33, 0x02, /* field_chg */
- 0x49, 0x02, /* vact_st2 */
- 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
- 0x01, 0x00, 0x33, 0x02, /* field top/bot */
- },
- .mbus_fmt = {
- .width = 720,
- .height = 480,
- .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
- .field = V4L2_FIELD_NONE,
- .colorspace = V4L2_COLORSPACE_SRGB,
- },
+static const struct hdmi_timings hdmi_timings_480p = {
+ .hact = { .beg = 138, .end = 858 },
+ .hsyn_pol = 1,
+ .hsyn = { .beg = 16, .end = 16 + 62 },
+ .interlaced = 0,
+ .vact[0] = { .beg = 42 + 3, .end = 522 + 3 },
+ .vsyn_pol = 1,
+ .vsyn[0] = { .beg = 6 + 3, .end = 12 + 3},
};
-static const struct hdmi_preset_conf hdmi_conf_720p60 = {
- .core = {
- .h_blank = {0x72, 0x01},
- .v_blank = {0xee, 0xf2, 0x00},
- .h_v_line = {0xee, 0x22, 0x67},
- .vsync_pol = {0x00},
- .int_pro_mode = {0x00},
- .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
- .h_sync_gen = {0x6c, 0x50, 0x02},
- .v_sync_gen1 = {0x0a, 0x50, 0x00},
- /* other don't care */
- },
- .tg = {
- 0x00, /* cmd */
- 0x72, 0x06, /* h_fsz */
- 0x72, 0x01, 0x00, 0x05, /* hact */
- 0xee, 0x02, /* v_fsz */
- 0x01, 0x00, 0x33, 0x02, /* vsync */
- 0x1e, 0x00, 0xd0, 0x02, /* vact */
- 0x33, 0x02, /* field_chg */
- 0x49, 0x02, /* vact_st2 */
- 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
- 0x01, 0x00, 0x33, 0x02, /* field top/bot */
- },
- .mbus_fmt = {
- .width = 1280,
- .height = 720,
- .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
- .field = V4L2_FIELD_NONE,
- .colorspace = V4L2_COLORSPACE_SRGB,
- },
+static const struct hdmi_timings hdmi_timings_576p50 = {
+ .hact = { .beg = 144, .end = 864 },
+ .hsyn_pol = 1,
+ .hsyn = { .beg = 12, .end = 12 + 64 },
+ .interlaced = 0,
+ .vact[0] = { .beg = 44 + 5, .end = 620 + 5 },
+ .vsyn_pol = 1,
+ .vsyn[0] = { .beg = 0 + 5, .end = 5 + 5},
};
-static const struct hdmi_preset_conf hdmi_conf_1080p50 = {
- .core = {
- .h_blank = {0xd0, 0x02},
- .v_blank = {0x65, 0x6c, 0x01},
- .h_v_line = {0x65, 0x04, 0xa5},
- .vsync_pol = {0x00},
- .int_pro_mode = {0x00},
- .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
- .h_sync_gen = {0x0e, 0xea, 0x08},
- .v_sync_gen1 = {0x09, 0x40, 0x00},
- /* other don't care */
- },
- .tg = {
- 0x00, /* cmd */
- 0x98, 0x08, /* h_fsz */
- 0x18, 0x01, 0x80, 0x07, /* hact */
- 0x65, 0x04, /* v_fsz */
- 0x01, 0x00, 0x33, 0x02, /* vsync */
- 0x2d, 0x00, 0x38, 0x04, /* vact */
- 0x33, 0x02, /* field_chg */
- 0x49, 0x02, /* vact_st2 */
- 0x01, 0x00, 0x33, 0x02, /* vsync top/bot */
- 0x01, 0x00, 0x33, 0x02, /* field top/bot */
- },
- .mbus_fmt = {
- .width = 1920,
- .height = 1080,
- .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
- .field = V4L2_FIELD_NONE,
- .colorspace = V4L2_COLORSPACE_SRGB,
- },
+static const struct hdmi_timings hdmi_timings_720p60 = {
+ .hact = { .beg = 370, .end = 1650 },
+ .hsyn_pol = 0,
+ .hsyn = { .beg = 110, .end = 110 + 40 },
+ .interlaced = 0,
+ .vact[0] = { .beg = 25 + 5, .end = 745 + 5 },
+ .vsyn_pol = 0,
+ .vsyn[0] = { .beg = 0 + 5, .end = 5 + 5},
};
-static const struct hdmi_preset_conf hdmi_conf_1080p60 = {
- .core = {
- .h_blank = {0x18, 0x01},
- .v_blank = {0x65, 0x6c, 0x01},
- .h_v_line = {0x65, 0x84, 0x89},
- .vsync_pol = {0x00},
- .int_pro_mode = {0x00},
- .v_blank_f = {0x00, 0x00, 0x00}, /* don't care */
- .h_sync_gen = {0x56, 0x08, 0x02},
- .v_sync_gen1 = {0x09, 0x40, 0x00},
- /* other don't care */
- },
- .tg = {
- 0x00, /* cmd */
- 0x98, 0x08, /* h_fsz */
- 0x18, 0x01, 0x80, 0x07, /* hact */
- 0x65, 0x04, /* v_fsz */
- 0x01, 0x00, 0x33, 0x02, /* vsync */
- 0x2d, 0x00, 0x38, 0x04, /* vact */
- 0x33, 0x02, /* field_chg */
- 0x48, 0x02, /* vact_st2 */
- 0x01, 0x00, 0x01, 0x00, /* vsync top/bot */
- 0x01, 0x00, 0x33, 0x02, /* field top/bot */
- },
- .mbus_fmt = {
- .width = 1920,
- .height = 1080,
- .code = V4L2_MBUS_FMT_FIXED, /* means RGB888 */
- .field = V4L2_FIELD_NONE,
- .colorspace = V4L2_COLORSPACE_SRGB,
- },
+static const struct hdmi_timings hdmi_timings_720p50 = {
+ .hact = { .beg = 700, .end = 1980 },
+ .hsyn_pol = 0,
+ .hsyn = { .beg = 440, .end = 440 + 40 },
+ .interlaced = 0,
+ .vact[0] = { .beg = 25 + 5, .end = 745 + 5 },
+ .vsyn_pol = 0,
+ .vsyn[0] = { .beg = 0 + 5, .end = 5 + 5},
+};
+
+static const struct hdmi_timings hdmi_timings_1080p24 = {
+ .hact = { .beg = 830, .end = 2750 },
+ .hsyn_pol = 0,
+ .hsyn = { .beg = 638, .end = 638 + 44 },
+ .interlaced = 0,
+ .vact[0] = { .beg = 41 + 4, .end = 1121 + 4 },
+ .vsyn_pol = 0,
+ .vsyn[0] = { .beg = 0 + 4, .end = 5 + 4},
+};
+
+static const struct hdmi_timings hdmi_timings_1080p60 = {
+ .hact = { .beg = 280, .end = 2200 },
+ .hsyn_pol = 0,
+ .hsyn = { .beg = 88, .end = 88 + 44 },
+ .interlaced = 0,
+ .vact[0] = { .beg = 41 + 4, .end = 1121 + 4 },
+ .vsyn_pol = 0,
+ .vsyn[0] = { .beg = 0 + 4, .end = 5 + 4},
+};
+
+static const struct hdmi_timings hdmi_timings_1080i60 = {
+ .hact = { .beg = 280, .end = 2200 },
+ .hsyn_pol = 0,
+ .hsyn = { .beg = 88, .end = 88 + 44 },
+ .interlaced = 1,
+ .vact[0] = { .beg = 20 + 2, .end = 560 + 2 },
+ .vact[1] = { .beg = 583 + 2, .end = 1123 + 2 },
+ .vsyn_pol = 0,
+ .vsyn_off = 1100,
+ .vsyn[0] = { .beg = 0 + 2, .end = 5 + 2},
+ .vsyn[1] = { .beg = 562 + 2, .end = 567 + 2},
+};
+
+static const struct hdmi_timings hdmi_timings_1080i50 = {
+ .hact = { .beg = 720, .end = 2640 },
+ .hsyn_pol = 0,
+ .hsyn = { .beg = 528, .end = 528 + 44 },
+ .interlaced = 1,
+ .vact[0] = { .beg = 20 + 2, .end = 560 + 2 },
+ .vact[1] = { .beg = 583 + 2, .end = 1123 + 2 },
+ .vsyn_pol = 0,
+ .vsyn_off = 1320,
+ .vsyn[0] = { .beg = 0 + 2, .end = 5 + 2},
+ .vsyn[1] = { .beg = 562 + 2, .end = 567 + 2},
+};
+
+static const struct hdmi_timings hdmi_timings_1080p50 = {
+ .hact = { .beg = 720, .end = 2640 },
+ .hsyn_pol = 0,
+ .hsyn = { .beg = 528, .end = 528 + 44 },
+ .interlaced = 0,
+ .vact[0] = { .beg = 41 + 4, .end = 1121 + 4 },
+ .vsyn_pol = 0,
+ .vsyn[0] = { .beg = 0 + 4, .end = 5 + 4},
};
static const struct {
u32 preset;
- const struct hdmi_preset_conf *conf;
-} hdmi_conf[] = {
- { V4L2_DV_480P59_94, &hdmi_conf_480p },
- { V4L2_DV_720P59_94, &hdmi_conf_720p60 },
- { V4L2_DV_1080P50, &hdmi_conf_1080p50 },
- { V4L2_DV_1080P30, &hdmi_conf_1080p60 },
- { V4L2_DV_1080P60, &hdmi_conf_1080p60 },
+ const struct hdmi_timings *timings;
+} hdmi_timings[] = {
+ { V4L2_DV_480P59_94, &hdmi_timings_480p },
+ { V4L2_DV_576P50, &hdmi_timings_576p50 },
+ { V4L2_DV_720P50, &hdmi_timings_720p50 },
+ { V4L2_DV_720P59_94, &hdmi_timings_720p60 },
+ { V4L2_DV_720P60, &hdmi_timings_720p60 },
+ { V4L2_DV_1080P24, &hdmi_timings_1080p24 },
+ { V4L2_DV_1080P30, &hdmi_timings_1080p60 },
+ { V4L2_DV_1080P50, &hdmi_timings_1080p50 },
+ { V4L2_DV_1080I50, &hdmi_timings_1080i50 },
+ { V4L2_DV_1080I60, &hdmi_timings_1080i60 },
+ { V4L2_DV_1080P60, &hdmi_timings_1080p60 },
};
-static const struct hdmi_preset_conf *hdmi_preset2conf(u32 preset)
+static const struct hdmi_timings *hdmi_preset2timings(u32 preset)
{
int i;
- for (i = 0; i < ARRAY_SIZE(hdmi_conf); ++i)
- if (hdmi_conf[i].preset == preset)
- return hdmi_conf[i].conf;
+ for (i = 0; i < ARRAY_SIZE(hdmi_timings); ++i)
+ if (hdmi_timings[i].preset == preset)
+ return hdmi_timings[i].timings;
return NULL;
}
@@ -559,6 +508,10 @@ static int hdmi_streamon(struct hdmi_device *hdev)
dev_dbg(dev, "%s\n", __func__);
+ ret = hdmi_conf_apply(hdev);
+ if (ret)
+ return ret;
+
ret = v4l2_subdev_call(hdev->phy_sd, video, s_stream, 1);
if (ret)
return ret;
@@ -671,14 +624,15 @@ static int hdmi_s_dv_preset(struct v4l2_subdev *sd,
{
struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
struct device *dev = hdev->dev;
- const struct hdmi_preset_conf *conf;
+ const struct hdmi_timings *conf;
- conf = hdmi_preset2conf(preset->preset);
+ conf = hdmi_preset2timings(preset->preset);
if (conf == NULL) {
dev_err(dev, "preset (%u) not supported\n", preset->preset);
return -EINVAL;
}
hdev->cur_conf = conf;
+ hdev->cur_conf_dirty = 1;
hdev->cur_preset = preset->preset;
return 0;
}
@@ -695,21 +649,32 @@ static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *fmt)
{
struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
- struct device *dev = hdev->dev;
+ const struct hdmi_timings *t = hdev->cur_conf;
- dev_dbg(dev, "%s\n", __func__);
+ dev_dbg(hdev->dev, "%s\n", __func__);
if (!hdev->cur_conf)
return -EINVAL;
- *fmt = hdev->cur_conf->mbus_fmt;
+ memset(fmt, 0, sizeof *fmt);
+ fmt->width = t->hact.end - t->hact.beg;
+ fmt->height = t->vact[0].end - t->vact[0].beg;
+ fmt->code = V4L2_MBUS_FMT_FIXED; /* means RGB888 */
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
+ if (t->interlaced) {
+ fmt->field = V4L2_FIELD_INTERLACED;
+ fmt->height *= 2;
+ } else {
+ fmt->field = V4L2_FIELD_NONE;
+ }
return 0;
}
static int hdmi_enum_dv_presets(struct v4l2_subdev *sd,
struct v4l2_dv_enum_preset *preset)
{
- if (preset->index >= ARRAY_SIZE(hdmi_conf))
+ if (preset->index >= ARRAY_SIZE(hdmi_timings))
return -EINVAL;
- return v4l_fill_dv_preset_info(hdmi_conf[preset->index].preset, preset);
+ return v4l_fill_dv_preset_info(hdmi_timings[preset->index].preset,
+ preset);
}
static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = {
@@ -737,6 +702,8 @@ static int hdmi_runtime_suspend(struct device *dev)
dev_dbg(dev, "%s\n", __func__);
v4l2_subdev_call(hdev->mhl_sd, core, s_power, 0);
hdmi_resource_poweroff(&hdev->res);
+ /* flag that device context is lost */
+ hdev->cur_conf_dirty = 1;
return 0;
}
@@ -750,10 +717,6 @@ static int hdmi_runtime_resume(struct device *dev)
hdmi_resource_poweron(&hdev->res);
- ret = hdmi_conf_apply(hdev);
- if (ret)
- goto fail;
-
/* starting MHL */
ret = v4l2_subdev_call(hdev->mhl_sd, core, s_power, 1);
if (hdev->mhl_sd && ret)
@@ -993,7 +956,8 @@ static int __devinit hdmi_probe(struct platform_device *pdev)
strlcpy(sd->name, "s5p-hdmi", sizeof sd->name);
hdmi_dev->cur_preset = HDMI_DEFAULT_PRESET;
/* FIXME: missing fail preset is not supported */
- hdmi_dev->cur_conf = hdmi_preset2conf(hdmi_dev->cur_preset);
+ hdmi_dev->cur_conf = hdmi_preset2timings(hdmi_dev->cur_preset);
+ hdmi_dev->cur_conf_dirty = 1;
/* storing subdev for call that have only access to struct device */
dev_set_drvdata(dev, sd);
diff --git a/drivers/media/video/s5p-tv/hdmiphy_drv.c b/drivers/media/video/s5p-tv/hdmiphy_drv.c
index 0afef77747e5..f67b38631801 100644
--- a/drivers/media/video/s5p-tv/hdmiphy_drv.c
+++ b/drivers/media/video/s5p-tv/hdmiphy_drv.c
@@ -26,53 +26,188 @@ MODULE_DESCRIPTION("Samsung HDMI Physical interface driver");
MODULE_LICENSE("GPL");
struct hdmiphy_conf {
- u32 preset;
+ unsigned long pixclk;
const u8 *data;
};
-static const u8 hdmiphy_conf27[32] = {
- 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
- 0x6B, 0x10, 0x02, 0x51, 0xDf, 0xF2, 0x54, 0x87,
- 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
- 0x22, 0x40, 0xe3, 0x26, 0x00, 0x00, 0x00, 0x00,
+struct hdmiphy_ctx {
+ struct v4l2_subdev sd;
+ const struct hdmiphy_conf *conf_tab;
};
-static const u8 hdmiphy_conf74_175[32] = {
- 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
- 0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
- 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
- 0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x00,
+static const struct hdmiphy_conf hdmiphy_conf_s5pv210[] = {
+ { .pixclk = 27000000, .data = (u8 [32]) {
+ 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
+ 0x6B, 0x10, 0x02, 0x52, 0xDF, 0xF2, 0x54, 0x87,
+ 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+ 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00, }
+ },
+ { .pixclk = 27027000, .data = (u8 [32]) {
+ 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
+ 0x6B, 0x10, 0x02, 0x52, 0xDF, 0xF2, 0x54, 0x87,
+ 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+ 0x22, 0x40, 0xE2, 0x26, 0x00, 0x00, 0x00, 0x00, }
+ },
+ { .pixclk = 74176000, .data = (u8 [32]) {
+ 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xEF, 0x5B,
+ 0x6D, 0x10, 0x01, 0x52, 0xEF, 0xF3, 0x54, 0xB9,
+ 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+ 0x22, 0x40, 0xA5, 0x26, 0x01, 0x00, 0x00, 0x00, }
+ },
+ { .pixclk = 74250000, .data = (u8 [32]) {
+ 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xF8, 0x40,
+ 0x6A, 0x10, 0x01, 0x52, 0xFF, 0xF1, 0x54, 0xBA,
+ 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
+ 0x22, 0x40, 0xA4, 0x26, 0x01, 0x00, 0x00, 0x00, }
+ },
+ { /* end marker */ }
};
-static const u8 hdmiphy_conf74_25[32] = {
- 0x01, 0x05, 0x00, 0xd8, 0x10, 0x9c, 0xf8, 0x40,
- 0x6a, 0x10, 0x01, 0x51, 0xff, 0xf1, 0x54, 0xba,
- 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xe0,
- 0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x00,
+static const struct hdmiphy_conf hdmiphy_conf_exynos4210[] = {
+ { .pixclk = 27000000, .data = (u8 [32]) {
+ 0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
+ 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
+ 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+ 0x22, 0x40, 0xE3, 0x26, 0x00, 0x00, 0x00, 0x00, }
+ },
+ { .pixclk = 27027000, .data = (u8 [32]) {
+ 0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
+ 0x6B, 0x10, 0x02, 0x51, 0xDF, 0xF2, 0x54, 0x87,
+ 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+ 0x22, 0x40, 0xE2, 0x26, 0x00, 0x00, 0x00, 0x00, }
+ },
+ { .pixclk = 74176000, .data = (u8 [32]) {
+ 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xEF, 0x5B,
+ 0x6D, 0x10, 0x01, 0x51, 0xEF, 0xF3, 0x54, 0xB9,
+ 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+ 0x22, 0x40, 0xA5, 0x26, 0x01, 0x00, 0x00, 0x00, }
+ },
+ { .pixclk = 74250000, .data = (u8 [32]) {
+ 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xF8, 0x40,
+ 0x6A, 0x10, 0x01, 0x51, 0xFF, 0xF1, 0x54, 0xBA,
+ 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
+ 0x22, 0x40, 0xA4, 0x26, 0x01, 0x00, 0x00, 0x00, }
+ },
+ { .pixclk = 148352000, .data = (u8 [32]) {
+ 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xEF, 0x5B,
+ 0x6D, 0x18, 0x00, 0x51, 0xEF, 0xF3, 0x54, 0xB9,
+ 0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
+ 0x11, 0x40, 0xA5, 0x26, 0x02, 0x00, 0x00, 0x00, }
+ },
+ { .pixclk = 148500000, .data = (u8 [32]) {
+ 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xF8, 0x40,
+ 0x6A, 0x18, 0x00, 0x51, 0xFF, 0xF1, 0x54, 0xBA,
+ 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
+ 0x11, 0x40, 0xA4, 0x26, 0x02, 0x00, 0x00, 0x00, }
+ },
+ { /* end marker */ }
};
-static const u8 hdmiphy_conf148_5[32] = {
- 0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
- 0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
- 0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
- 0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x00,
+static const struct hdmiphy_conf hdmiphy_conf_exynos4212[] = {
+ { .pixclk = 27000000, .data = (u8 [32]) {
+ 0x01, 0x11, 0x2D, 0x75, 0x00, 0x01, 0x00, 0x08,
+ 0x82, 0x00, 0x0E, 0xD9, 0x45, 0xA0, 0x34, 0xC0,
+ 0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0x71,
+ 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, }
+ },
+ { .pixclk = 27027000, .data = (u8 [32]) {
+ 0x01, 0x91, 0x2D, 0x72, 0x00, 0x64, 0x12, 0x08,
+ 0x43, 0x20, 0x0E, 0xD9, 0x45, 0xA0, 0x34, 0xC0,
+ 0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0x71,
+ 0x54, 0xE2, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, }
+ },
+ { .pixclk = 74176000, .data = (u8 [32]) {
+ 0x01, 0x91, 0x3E, 0x35, 0x00, 0x5B, 0xDE, 0x08,
+ 0x82, 0x20, 0x73, 0xD9, 0x45, 0xA0, 0x34, 0xC0,
+ 0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0x52,
+ 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, }
+ },
+ { .pixclk = 74250000, .data = (u8 [32]) {
+ 0x01, 0x91, 0x3E, 0x35, 0x00, 0x40, 0xF0, 0x08,
+ 0x82, 0x20, 0x73, 0xD9, 0x45, 0xA0, 0x34, 0xC0,
+ 0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0x52,
+ 0x54, 0xA4, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, }
+ },
+ { .pixclk = 148500000, .data = (u8 [32]) {
+ 0x01, 0x91, 0x3E, 0x15, 0x00, 0x40, 0xF0, 0x08,
+ 0x82, 0x20, 0x73, 0xD9, 0x45, 0xA0, 0x34, 0xC0,
+ 0x0B, 0x80, 0x12, 0x87, 0x08, 0x24, 0x24, 0xA4,
+ 0x54, 0x4A, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00, }
+ },
+ { /* end marker */ }
};
-static const struct hdmiphy_conf hdmiphy_conf[] = {
- { V4L2_DV_480P59_94, hdmiphy_conf27 },
- { V4L2_DV_1080P30, hdmiphy_conf74_175 },
- { V4L2_DV_720P59_94, hdmiphy_conf74_175 },
- { V4L2_DV_720P60, hdmiphy_conf74_25 },
- { V4L2_DV_1080P50, hdmiphy_conf148_5 },
- { V4L2_DV_1080P60, hdmiphy_conf148_5 },
+static const struct hdmiphy_conf hdmiphy_conf_exynos4412[] = {
+ { .pixclk = 27000000, .data = (u8 [32]) {
+ 0x01, 0x11, 0x2D, 0x75, 0x40, 0x01, 0x00, 0x08,
+ 0x82, 0x00, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
+ 0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86,
+ 0x54, 0xE4, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, }
+ },
+ { .pixclk = 27027000, .data = (u8 [32]) {
+ 0x01, 0x91, 0x2D, 0x72, 0x40, 0x64, 0x12, 0x08,
+ 0x43, 0x20, 0x0E, 0xD9, 0x45, 0xA0, 0xAC, 0x80,
+ 0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86,
+ 0x54, 0xE3, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, }
+ },
+ { .pixclk = 74176000, .data = (u8 [32]) {
+ 0x01, 0x91, 0x1F, 0x10, 0x40, 0x5B, 0xEF, 0x08,
+ 0x81, 0x20, 0xB9, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
+ 0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86,
+ 0x54, 0xA6, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, }
+ },
+ { .pixclk = 74250000, .data = (u8 [32]) {
+ 0x01, 0x91, 0x1F, 0x10, 0x40, 0x40, 0xF8, 0x08,
+ 0x81, 0x20, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
+ 0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86,
+ 0x54, 0xA5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x00, }
+ },
+ { .pixclk = 148500000, .data = (u8 [32]) {
+ 0x01, 0x91, 0x1F, 0x00, 0x40, 0x40, 0xF8, 0x08,
+ 0x81, 0x20, 0xBA, 0xD8, 0x45, 0xA0, 0xAC, 0x80,
+ 0x08, 0x80, 0x11, 0x84, 0x02, 0x22, 0x44, 0x86,
+ 0x54, 0x4B, 0x25, 0x03, 0x00, 0x00, 0x01, 0x00, }
+ },
+ { /* end marker */ }
};
-const u8 *hdmiphy_preset2conf(u32 preset)
+static inline struct hdmiphy_ctx *sd_to_ctx(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct hdmiphy_ctx, sd);
+}
+
+static unsigned long hdmiphy_preset_to_pixclk(u32 preset)
+{
+ static const unsigned long pixclk[] = {
+ [V4L2_DV_480P59_94] = 27000000,
+ [V4L2_DV_576P50] = 27000000,
+ [V4L2_DV_720P59_94] = 74176000,
+ [V4L2_DV_720P50] = 74250000,
+ [V4L2_DV_720P60] = 74250000,
+ [V4L2_DV_1080P24] = 74250000,
+ [V4L2_DV_1080P30] = 74250000,
+ [V4L2_DV_1080I50] = 74250000,
+ [V4L2_DV_1080I60] = 74250000,
+ [V4L2_DV_1080P50] = 148500000,
+ [V4L2_DV_1080P60] = 148500000,
+ };
+ if (preset < ARRAY_SIZE(pixclk))
+ return pixclk[preset];
+ else
+ return 0;
+}
+
+static const u8 *hdmiphy_find_conf(u32 preset, const struct hdmiphy_conf *conf)
{
- int i;
- for (i = 0; i < ARRAY_SIZE(hdmiphy_conf); ++i)
- if (hdmiphy_conf[i].preset == preset)
- return hdmiphy_conf[i].data;
+ unsigned long pixclk;
+
+ pixclk = hdmiphy_preset_to_pixclk(preset);
+ if (!pixclk)
+ return NULL;
+
+ for (; conf->pixclk; ++conf)
+ if (conf->pixclk == pixclk)
+ return conf->data;
return NULL;
}
@@ -88,11 +223,12 @@ static int hdmiphy_s_dv_preset(struct v4l2_subdev *sd,
const u8 *data;
u8 buffer[32];
int ret;
+ struct hdmiphy_ctx *ctx = sd_to_ctx(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct device *dev = &client->dev;
dev_info(dev, "s_dv_preset(preset = %d)\n", preset->preset);
- data = hdmiphy_preset2conf(preset->preset);
+ data = hdmiphy_find_conf(preset->preset, ctx->conf_tab);
if (!data) {
dev_err(dev, "format not supported\n");
return -EINVAL;
@@ -146,21 +282,36 @@ static const struct v4l2_subdev_ops hdmiphy_ops = {
static int __devinit hdmiphy_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- static struct v4l2_subdev sd;
+ struct hdmiphy_ctx *ctx;
+
+ ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->conf_tab = (struct hdmiphy_conf *)id->driver_data;
+ v4l2_i2c_subdev_init(&ctx->sd, client, &hdmiphy_ops);
- v4l2_i2c_subdev_init(&sd, client, &hdmiphy_ops);
dev_info(&client->dev, "probe successful\n");
return 0;
}
static int __devexit hdmiphy_remove(struct i2c_client *client)
{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct hdmiphy_ctx *ctx = sd_to_ctx(sd);
+
+ kfree(ctx);
dev_info(&client->dev, "remove successful\n");
+
return 0;
}
static const struct i2c_device_id hdmiphy_id[] = {
- { "hdmiphy", 0 },
+ { "hdmiphy", (unsigned long)hdmiphy_conf_exynos4210 },
+ { "hdmiphy-s5pv210", (unsigned long)hdmiphy_conf_s5pv210 },
+ { "hdmiphy-exynos4210", (unsigned long)hdmiphy_conf_exynos4210 },
+ { "hdmiphy-exynos4212", (unsigned long)hdmiphy_conf_exynos4212 },
+ { "hdmiphy-exynos4412", (unsigned long)hdmiphy_conf_exynos4412 },
{ },
};
MODULE_DEVICE_TABLE(i2c, hdmiphy_id);
diff --git a/drivers/media/video/s5p-tv/mixer.h b/drivers/media/video/s5p-tv/mixer.h
index 1597078c4a50..ddb422e23550 100644
--- a/drivers/media/video/s5p-tv/mixer.h
+++ b/drivers/media/video/s5p-tv/mixer.h
@@ -226,6 +226,7 @@ struct mxr_resources {
/* event flags used */
enum mxr_devide_flags {
MXR_EVENT_VSYNC = 0,
+ MXR_EVENT_TOP = 1,
};
/** drivers instance */
@@ -293,7 +294,7 @@ int __devinit mxr_acquire_video(struct mxr_device *mdev,
struct mxr_output_conf *output_cont, int output_count);
/** releasing common video resources */
-void __devexit mxr_release_video(struct mxr_device *mdev);
+void mxr_release_video(struct mxr_device *mdev);
struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx);
struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx);
diff --git a/drivers/media/video/s5p-tv/mixer_drv.c b/drivers/media/video/s5p-tv/mixer_drv.c
index a2c0c25ad130..edca06592883 100644
--- a/drivers/media/video/s5p-tv/mixer_drv.c
+++ b/drivers/media/video/s5p-tv/mixer_drv.c
@@ -461,7 +461,7 @@ static struct platform_driver mxr_driver __refdata = {
static int __init mxr_init(void)
{
int i, ret;
- static const char banner[] __initdata = KERN_INFO
+ static const char banner[] __initconst = KERN_INFO
"Samsung TV Mixer driver, "
"(c) 2010-2011 Samsung Electronics Co., Ltd.\n";
printk(banner);
diff --git a/drivers/media/video/s5p-tv/mixer_reg.c b/drivers/media/video/s5p-tv/mixer_reg.c
index 4800a3cbb297..3b1670a045f4 100644
--- a/drivers/media/video/s5p-tv/mixer_reg.c
+++ b/drivers/media/video/s5p-tv/mixer_reg.c
@@ -296,21 +296,25 @@ irqreturn_t mxr_irq_handler(int irq, void *dev_data)
/* wake up process waiting for VSYNC */
if (val & MXR_INT_STATUS_VSYNC) {
set_bit(MXR_EVENT_VSYNC, &mdev->event_flags);
+ /* toggle TOP field event if working in interlaced mode */
+ if (~mxr_read(mdev, MXR_CFG) & MXR_CFG_SCAN_PROGRASSIVE)
+ change_bit(MXR_EVENT_TOP, &mdev->event_flags);
wake_up(&mdev->event_queue);
- }
-
- /* clear interrupts */
- if (~val & MXR_INT_EN_VSYNC) {
/* vsync interrupt use different bit for read and clear */
- val &= ~MXR_INT_EN_VSYNC;
+ val &= ~MXR_INT_STATUS_VSYNC;
val |= MXR_INT_CLEAR_VSYNC;
}
+
+ /* clear interrupts */
mxr_write(mdev, MXR_INT_STATUS, val);
spin_unlock(&mdev->reg_slock);
/* leave on non-vsync event */
if (~val & MXR_INT_CLEAR_VSYNC)
return IRQ_HANDLED;
+ /* skip layer update on bottom field */
+ if (!test_bit(MXR_EVENT_TOP, &mdev->event_flags))
+ return IRQ_HANDLED;
for (i = 0; i < MXR_MAX_LAYERS; ++i)
mxr_irq_layer_handle(mdev->layer[i]);
return IRQ_HANDLED;
@@ -333,6 +337,7 @@ void mxr_reg_streamon(struct mxr_device *mdev)
/* start MIXER */
mxr_write_mask(mdev, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
+ set_bit(MXR_EVENT_TOP, &mdev->event_flags);
spin_unlock_irqrestore(&mdev->reg_slock, flags);
}
diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c
index f7ca5cc143c6..33fde2a763ec 100644
--- a/drivers/media/video/s5p-tv/mixer_video.c
+++ b/drivers/media/video/s5p-tv/mixer_video.c
@@ -140,7 +140,7 @@ fail:
return ret;
}
-void __devexit mxr_release_video(struct mxr_device *mdev)
+void mxr_release_video(struct mxr_device *mdev)
{
int i;
@@ -853,8 +853,8 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt,
*nplanes = fmt->num_subframes;
for (i = 0; i < fmt->num_subframes; ++i) {
alloc_ctxs[i] = layer->mdev->alloc_ctx;
- sizes[i] = PAGE_ALIGN(planes[i].sizeimage);
- mxr_dbg(mdev, "size[%d] = %08lx\n", i, sizes[i]);
+ sizes[i] = planes[i].sizeimage;
+ mxr_dbg(mdev, "size[%d] = %08x\n", i, sizes[i]);
}
if (*nbuffers == 0)
@@ -1069,6 +1069,10 @@ struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
set_bit(V4L2_FL_USE_FH_PRIO, &layer->vfd.flags);
video_set_drvdata(&layer->vfd, layer);
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &layer->vfd.flags);
layer->vfd.lock = &layer->mutex;
layer->vfd.v4l2_dev = &mdev->v4l2_dev;
diff --git a/drivers/media/video/s5p-tv/regs-hdmi.h b/drivers/media/video/s5p-tv/regs-hdmi.h
index 33247d13e4c0..a889d1f57f28 100644
--- a/drivers/media/video/s5p-tv/regs-hdmi.h
+++ b/drivers/media/video/s5p-tv/regs-hdmi.h
@@ -140,6 +140,7 @@
#define HDMI_MODE_MASK (3 << 0)
/* HDMI_TG_CMD */
+#define HDMI_TG_FIELD_EN (1 << 1)
#define HDMI_TG_EN (1 << 0)
#endif /* SAMSUNG_REGS_HDMI_H */
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 53aae5968ffb..bc08f1dbc293 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -5080,6 +5080,36 @@ struct saa7134_board saa7134_boards[] = {
.gpio = 0x0200000,
},
},
+ [SAA7134_BOARD_ASUSTeK_PS3_100] = {
+ .name = "Asus My Cinema PS3-100",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tuner_config = 2,
+ .gpiomask = 1 << 21,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ }, {
+ .name = name_comp,
+ .vmux = 0,
+ .amux = LINE2,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ .gpio = 0x0200000,
+ },
+ },
[SAA7134_BOARD_REAL_ANGEL_220] = {
.name = "Zogis Real Angel 220",
.audio_clock = 0x00187de7,
@@ -6877,6 +6907,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
.driver_data = SAA7134_BOARD_ASUSTeK_TIGER_3IN1,
}, {
.vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1043,
+ .subdevice = 0x48cd,
+ .driver_data = SAA7134_BOARD_ASUSTeK_PS3_100,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
.subvendor = 0x17de,
.subdevice = 0x7128,
@@ -7347,6 +7383,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_KWORLD_TERMINATOR:
case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
case SAA7134_BOARD_FLYDVBT_LR301:
+ case SAA7134_BOARD_ASUSTeK_PS3_100:
case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
@@ -7811,6 +7848,14 @@ int saa7134_board_init2(struct saa7134_dev *dev)
i2c_transfer(&dev->i2c_adap, &msg, 1);
break;
}
+ case SAA7134_BOARD_ASUSTeK_PS3_100:
+ {
+ u8 data[] = { 0x3c, 0x33, 0x60};
+ struct i2c_msg msg = {.addr = 0x0b, .flags = 0, .buf = data,
+ .len = sizeof(data)};
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ break;
+ }
case SAA7134_BOARD_FLYDVB_TRIO:
{
u8 temp = 0;
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index aaa5c97a7216..5dfd826d734e 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -881,6 +881,20 @@ static struct tda1004x_config asus_tiger_3in1_config = {
.request_firmware = philips_tda1004x_request_firmware
};
+static struct tda1004x_config asus_ps3_100_config = {
+ .demod_address = 0x0b,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .gpio_config = TDA10046_GP11_I,
+ .if_freq = TDA10046_FREQ_045,
+ .i2c_gate = 0x4b,
+ .tuner_address = 0x61,
+ .antenna_switch = 1,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
/* ------------------------------------------------------------------
* special case: this card uses saa713x GPIO22 for the mode switch
*/
@@ -1647,6 +1661,31 @@ static int dvb_init(struct saa7134_dev *dev)
&dev->i2c_adap, 0, 0) == NULL) {
wprintk("%s: Asus Tiger 3in1, no lnbp21"
" found!\n", __func__);
+ goto dettach_frontend;
+ }
+ }
+ }
+ break;
+ case SAA7134_BOARD_ASUSTeK_PS3_100:
+ if (!use_frontend) { /* terrestrial */
+ if (configure_tda827x_fe(dev, &asus_ps3_100_config,
+ &tda827x_cfg_2) < 0)
+ goto dettach_frontend;
+ } else { /* satellite */
+ fe0->dvb.frontend = dvb_attach(tda10086_attach,
+ &flydvbs, &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ if (dvb_attach(tda826x_attach,
+ fe0->dvb.frontend, 0x60,
+ &dev->i2c_adap, 0) == NULL) {
+ wprintk("%s: Asus My Cinema PS3-100, no "
+ "tda826x found!\n", __func__);
+ goto dettach_frontend;
+ }
+ if (dvb_attach(lnbp21_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0, 0) == NULL) {
+ wprintk("%s: Asus My Cinema PS3-100, no lnbp21"
+ " found!\n", __func__);
goto dettach_frontend;
}
}
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 48d2878699b7..05c6e217d8a7 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -753,6 +753,13 @@ int saa7134_input_init1(struct saa7134_dev *dev)
mask_keycode = 0xffff;
raw_decode = true;
break;
+ case SAA7134_BOARD_ASUSTeK_PS3_100:
+ ir_codes = RC_MAP_ASUS_PS3_100;
+ mask_keydown = 0x0040000;
+ mask_keyup = 0x0040000;
+ mask_keycode = 0xffff;
+ raw_decode = true;
+ break;
case SAA7134_BOARD_ENCORE_ENLTV:
case SAA7134_BOARD_ENCORE_ENLTV_FM:
ir_codes = RC_MAP_ENCORE_ENLTV;
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index 417034eb6ad2..6de10b1e7251 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -2036,7 +2036,7 @@ static int saa7134_s_tuner(struct file *file, void *priv,
mode = dev->thread.mode;
if (UNSET == mode) {
rx = saa7134_tvaudio_getstereo(dev);
- mode = saa7134_tvaudio_rx2mode(t->rxsubchans);
+ mode = saa7134_tvaudio_rx2mode(rx);
}
if (mode != t->audmode)
dev->thread.mode = t->audmode;
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index f625060e6a0f..89c8333736a2 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -332,6 +332,7 @@ struct saa7134_card_ir {
#define SAA7134_BOARD_BEHOLD_503FM 187
#define SAA7134_BOARD_SENSORAY811_911 188
#define SAA7134_BOARD_KWORLD_PC150U 189
+#define SAA7134_BOARD_ASUSTeK_PS3_100 190
#define SAA7134_MAXBOARDS 32
#define SAA7134_INPUT_MAX 8
diff --git a/drivers/media/video/saa7164/saa7164-vbi.c b/drivers/media/video/saa7164/saa7164-vbi.c
index 273cf807401c..d8e6c8f14079 100644
--- a/drivers/media/video/saa7164/saa7164-vbi.c
+++ b/drivers/media/video/saa7164/saa7164-vbi.c
@@ -952,7 +952,7 @@ static int saa7164_vbi_start_streaming(struct saa7164_port *port)
/* Stop the hardware, regardless */
result = saa7164_vbi_stop_port(port);
- if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+ if (result != SAA_OK) {
printk(KERN_ERR "%s() pause/forced stop transition "
"failed, res = 0x%x\n", __func__, result);
}
@@ -971,7 +971,7 @@ static int saa7164_vbi_start_streaming(struct saa7164_port *port)
/* Stop the hardware, regardless */
result = saa7164_vbi_acquire_port(port);
result = saa7164_vbi_stop_port(port);
- if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+ if (result != SAA_OK) {
printk(KERN_ERR "%s() run/forced stop transition "
"failed, res = 0x%x\n", __func__, result);
}
diff --git a/drivers/media/video/saa7164/saa7164.h b/drivers/media/video/saa7164/saa7164.h
index 742b34103b5d..8d120e3baf70 100644
--- a/drivers/media/video/saa7164/saa7164.h
+++ b/drivers/media/video/saa7164/saa7164.h
@@ -611,11 +611,6 @@ extern unsigned int saa_debug;
printk(KERN_WARNING "%s: " fmt, dev->name, ## arg);\
} while (0)
-#define log_err(fmt, arg...)\
- do { \
- printk(KERN_ERROR "%s: " fmt, dev->name, ## arg);\
- } while (0)
-
#define saa7164_readl(reg) readl(dev->lmmio + ((reg) >> 2))
#define saa7164_writel(reg, value) writel((value), dev->lmmio + ((reg) >> 2))
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 424dfacd263a..0baaf94db7e0 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -210,27 +210,33 @@ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq,
struct soc_camera_device *icd = container_of(vq, struct soc_camera_device, vb2_vidq);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
- int bytes_per_line;
- unsigned int height;
if (fmt) {
const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd,
fmt->fmt.pix.pixelformat);
+ unsigned int bytes_per_line;
+ int ret;
+
if (!xlate)
return -EINVAL;
- bytes_per_line = soc_mbus_bytes_per_line(fmt->fmt.pix.width,
- xlate->host_fmt);
- height = fmt->fmt.pix.height;
+
+ ret = soc_mbus_bytes_per_line(fmt->fmt.pix.width,
+ xlate->host_fmt);
+ if (ret < 0)
+ return ret;
+
+ bytes_per_line = max_t(u32, fmt->fmt.pix.bytesperline, ret);
+
+ ret = soc_mbus_image_size(xlate->host_fmt, bytes_per_line,
+ fmt->fmt.pix.height);
+ if (ret < 0)
+ return ret;
+
+ sizes[0] = max_t(u32, fmt->fmt.pix.sizeimage, ret);
} else {
/* Called from VIDIOC_REQBUFS or in compatibility mode */
- bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
- icd->current_fmt->host_fmt);
- height = icd->user_height;
+ sizes[0] = icd->sizeimage;
}
- if (bytes_per_line < 0)
- return bytes_per_line;
-
- sizes[0] = bytes_per_line * height;
alloc_ctxs[0] = pcdev->alloc_ctx;
@@ -336,21 +342,15 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
ceu_write(pcdev, top1, phys_addr_top);
if (V4L2_FIELD_NONE != pcdev->field) {
- if (planar)
- phys_addr_bottom = phys_addr_top + icd->user_width;
- else
- phys_addr_bottom = phys_addr_top +
- soc_mbus_bytes_per_line(icd->user_width,
- icd->current_fmt->host_fmt);
+ phys_addr_bottom = phys_addr_top + icd->bytesperline;
ceu_write(pcdev, bottom1, phys_addr_bottom);
}
if (planar) {
- phys_addr_top += icd->user_width *
- icd->user_height;
+ phys_addr_top += icd->bytesperline * icd->user_height;
ceu_write(pcdev, top2, phys_addr_top);
if (V4L2_FIELD_NONE != pcdev->field) {
- phys_addr_bottom = phys_addr_top + icd->user_width;
+ phys_addr_bottom = phys_addr_top + icd->bytesperline;
ceu_write(pcdev, bottom2, phys_addr_bottom);
}
}
@@ -377,13 +377,8 @@ static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb)
struct sh_mobile_ceu_dev *pcdev = ici->priv;
struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb);
unsigned long size;
- int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
- icd->current_fmt->host_fmt);
- if (bytes_per_line < 0)
- goto error;
-
- size = icd->user_height * bytes_per_line;
+ size = icd->sizeimage;
if (vb2_plane_size(vb, 0) < size) {
dev_err(icd->parent, "Buffer #%d too small (%lu < %lu)\n",
@@ -682,10 +677,7 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd)
in_width *= 2;
left_offset *= 2;
}
- cdwdr_width = width;
} else {
- int bytes_per_line = soc_mbus_bytes_per_line(width,
- icd->current_fmt->host_fmt);
unsigned int w_factor;
switch (icd->current_fmt->host_fmt->packing) {
@@ -698,13 +690,10 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd)
in_width = cam->width * w_factor;
left_offset *= w_factor;
-
- if (bytes_per_line < 0)
- cdwdr_width = width;
- else
- cdwdr_width = bytes_per_line;
}
+ cdwdr_width = icd->bytesperline;
+
height = icd->user_height;
in_height = cam->height;
if (V4L2_FIELD_NONE != pcdev->field) {
@@ -881,11 +870,13 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd)
value |= common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ? 1 << 1 : 0;
value |= common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ? 1 << 0 : 0;
- value |= pcdev->is_16bit ? 1 << 12 : 0;
- /* CSI2 mode */
- if (pcdev->pdata->csi2)
+ if (pcdev->pdata->csi2) /* CSI2 mode */
value |= 3 << 12;
+ else if (pcdev->is_16bit)
+ value |= 1 << 12;
+ else if (pcdev->pdata->flags & SH_CEU_FLAG_LOWER_8BIT)
+ value |= 2 << 12;
ceu_write(pcdev, CAMCR, value);
@@ -964,24 +955,28 @@ static const struct soc_mbus_pixelfmt sh_mobile_ceu_formats[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_1_5X8,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PLANAR_2Y_C,
}, {
.fourcc = V4L2_PIX_FMT_NV21,
.name = "NV21",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_1_5X8,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PLANAR_2Y_C,
}, {
.fourcc = V4L2_PIX_FMT_NV16,
.name = "NV16",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PLANAR_Y_C,
}, {
.fourcc = V4L2_PIX_FMT_NV61,
.name = "NV61",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PLANAR_Y_C,
},
};
@@ -1845,6 +1840,8 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
return 0;
}
+#define CEU_CHDW_MAX 8188U /* Maximum line stride */
+
static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
@@ -1863,8 +1860,12 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
if (!xlate) {
- dev_warn(icd->parent, "Format %x not found\n", pixfmt);
- return -EINVAL;
+ xlate = icd->current_fmt;
+ dev_dbg(icd->parent, "Format %x not found, keeping %x\n",
+ pixfmt, xlate->host_fmt->fourcc);
+ pixfmt = xlate->host_fmt->fourcc;
+ pix->pixelformat = pixfmt;
+ pix->colorspace = icd->colorspace;
}
/* FIXME: calculate using depth and bus width */
@@ -1923,10 +1924,20 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
pix->width = width;
if (mf.height > height)
pix->height = height;
+
+ pix->bytesperline = max(pix->bytesperline, pix->width);
+ pix->bytesperline = min(pix->bytesperline, CEU_CHDW_MAX);
+ pix->bytesperline &= ~3;
+ break;
+
+ default:
+ /* Configurable stride isn't supported in pass-through mode. */
+ pix->bytesperline = 0;
}
pix->width &= ~3;
pix->height &= ~3;
+ pix->sizeimage = 0;
dev_geo(icd->parent, "%s(): return %d, fmt 0x%x, %ux%u\n",
__func__, ret, pix->pixelformat, pix->width, pix->height);
@@ -2145,6 +2156,7 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
pcdev->ici.nr = pdev->id;
pcdev->ici.drv_name = dev_name(&pdev->dev);
pcdev->ici.ops = &sh_mobile_ceu_host_ops;
+ pcdev->ici.capabilities = SOCAM_HOST_CAP_STRIDE;
pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
if (IS_ERR(pcdev->alloc_ctx)) {
diff --git a/drivers/media/video/sh_vou.c b/drivers/media/video/sh_vou.c
index 9644bd861abc..8fd1874382c6 100644
--- a/drivers/media/video/sh_vou.c
+++ b/drivers/media/video/sh_vou.c
@@ -1390,6 +1390,10 @@ static int __devinit sh_vou_probe(struct platform_device *pdev)
vdev->v4l2_dev = &vou_dev->v4l2_dev;
vdev->release = video_device_release;
vdev->lock = &vou_dev->fop_lock;
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags);
vou_dev->vdev = vdev;
video_set_drvdata(vdev, vou_dev);
diff --git a/drivers/media/video/smiapp-pll.c b/drivers/media/video/smiapp-pll.c
new file mode 100644
index 000000000000..a2e41a21dc65
--- /dev/null
+++ b/drivers/media/video/smiapp-pll.c
@@ -0,0 +1,418 @@
+/*
+ * drivers/media/video/smiapp-pll.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/gcd.h>
+#include <linux/lcm.h>
+#include <linux/module.h>
+
+#include "smiapp-pll.h"
+
+/* Return an even number or one. */
+static inline uint32_t clk_div_even(uint32_t a)
+{
+ return max_t(uint32_t, 1, a & ~1);
+}
+
+/* Return an even number or one. */
+static inline uint32_t clk_div_even_up(uint32_t a)
+{
+ if (a == 1)
+ return 1;
+ return (a + 1) & ~1;
+}
+
+static inline uint32_t is_one_or_even(uint32_t a)
+{
+ if (a == 1)
+ return 1;
+ if (a & 1)
+ return 0;
+
+ return 1;
+}
+
+static int bounds_check(struct device *dev, uint32_t val,
+ uint32_t min, uint32_t max, char *str)
+{
+ if (val >= min && val <= max)
+ return 0;
+
+ dev_warn(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max);
+
+ return -EINVAL;
+}
+
+static void print_pll(struct device *dev, struct smiapp_pll *pll)
+{
+ dev_dbg(dev, "pre_pll_clk_div\t%d\n", pll->pre_pll_clk_div);
+ dev_dbg(dev, "pll_multiplier \t%d\n", pll->pll_multiplier);
+ if (pll->flags != SMIAPP_PLL_FLAG_NO_OP_CLOCKS) {
+ dev_dbg(dev, "op_sys_clk_div \t%d\n", pll->op_sys_clk_div);
+ dev_dbg(dev, "op_pix_clk_div \t%d\n", pll->op_pix_clk_div);
+ }
+ dev_dbg(dev, "vt_sys_clk_div \t%d\n", pll->vt_sys_clk_div);
+ dev_dbg(dev, "vt_pix_clk_div \t%d\n", pll->vt_pix_clk_div);
+
+ dev_dbg(dev, "ext_clk_freq_hz \t%d\n", pll->ext_clk_freq_hz);
+ dev_dbg(dev, "pll_ip_clk_freq_hz \t%d\n", pll->pll_ip_clk_freq_hz);
+ dev_dbg(dev, "pll_op_clk_freq_hz \t%d\n", pll->pll_op_clk_freq_hz);
+ if (pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS) {
+ dev_dbg(dev, "op_sys_clk_freq_hz \t%d\n",
+ pll->op_sys_clk_freq_hz);
+ dev_dbg(dev, "op_pix_clk_freq_hz \t%d\n",
+ pll->op_pix_clk_freq_hz);
+ }
+ dev_dbg(dev, "vt_sys_clk_freq_hz \t%d\n", pll->vt_sys_clk_freq_hz);
+ dev_dbg(dev, "vt_pix_clk_freq_hz \t%d\n", pll->vt_pix_clk_freq_hz);
+}
+
+int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits,
+ struct smiapp_pll *pll)
+{
+ uint32_t sys_div;
+ uint32_t best_pix_div = INT_MAX >> 1;
+ uint32_t vt_op_binning_div;
+ uint32_t lane_op_clock_ratio;
+ uint32_t mul, div;
+ uint32_t more_mul_min, more_mul_max;
+ uint32_t more_mul_factor;
+ uint32_t min_vt_div, max_vt_div, vt_div;
+ uint32_t min_sys_div, max_sys_div;
+ unsigned int i;
+ int rval;
+
+ if (pll->flags & SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE)
+ lane_op_clock_ratio = pll->lanes;
+ else
+ lane_op_clock_ratio = 1;
+ dev_dbg(dev, "lane_op_clock_ratio: %d\n", lane_op_clock_ratio);
+
+ dev_dbg(dev, "binning: %dx%d\n", pll->binning_horizontal,
+ pll->binning_vertical);
+
+ /* CSI transfers 2 bits per clock per lane; thus times 2 */
+ pll->pll_op_clk_freq_hz = pll->link_freq * 2
+ * (pll->lanes / lane_op_clock_ratio);
+
+ /* Figure out limits for pre-pll divider based on extclk */
+ dev_dbg(dev, "min / max pre_pll_clk_div: %d / %d\n",
+ limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
+ limits->max_pre_pll_clk_div =
+ min_t(uint16_t, limits->max_pre_pll_clk_div,
+ clk_div_even(pll->ext_clk_freq_hz /
+ limits->min_pll_ip_freq_hz));
+ limits->min_pre_pll_clk_div =
+ max_t(uint16_t, limits->min_pre_pll_clk_div,
+ clk_div_even_up(
+ DIV_ROUND_UP(pll->ext_clk_freq_hz,
+ limits->max_pll_ip_freq_hz)));
+ dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %d / %d\n",
+ limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
+
+ i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz);
+ mul = div_u64(pll->pll_op_clk_freq_hz, i);
+ div = pll->ext_clk_freq_hz / i;
+ dev_dbg(dev, "mul %d / div %d\n", mul, div);
+
+ limits->min_pre_pll_clk_div =
+ max_t(uint16_t, limits->min_pre_pll_clk_div,
+ clk_div_even_up(
+ DIV_ROUND_UP(mul * pll->ext_clk_freq_hz,
+ limits->max_pll_op_freq_hz)));
+ dev_dbg(dev, "pll_op check: min / max pre_pll_clk_div: %d / %d\n",
+ limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
+
+ if (limits->min_pre_pll_clk_div > limits->max_pre_pll_clk_div) {
+ dev_err(dev, "unable to compute pre_pll divisor\n");
+ return -EINVAL;
+ }
+
+ pll->pre_pll_clk_div = limits->min_pre_pll_clk_div;
+
+ /*
+ * Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be
+ * too high.
+ */
+ dev_dbg(dev, "pre_pll_clk_div %d\n", pll->pre_pll_clk_div);
+
+ /* Don't go above max pll multiplier. */
+ more_mul_max = limits->max_pll_multiplier / mul;
+ dev_dbg(dev, "more_mul_max: max_pll_multiplier check: %d\n",
+ more_mul_max);
+ /* Don't go above max pll op frequency. */
+ more_mul_max =
+ min_t(int,
+ more_mul_max,
+ limits->max_pll_op_freq_hz
+ / (pll->ext_clk_freq_hz / pll->pre_pll_clk_div * mul));
+ dev_dbg(dev, "more_mul_max: max_pll_op_freq_hz check: %d\n",
+ more_mul_max);
+ /* Don't go above the division capability of op sys clock divider. */
+ more_mul_max = min(more_mul_max,
+ limits->max_op_sys_clk_div * pll->pre_pll_clk_div
+ / div);
+ dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %d\n",
+ more_mul_max);
+ /* Ensure we won't go above min_pll_multiplier. */
+ more_mul_max = min(more_mul_max,
+ DIV_ROUND_UP(limits->max_pll_multiplier, mul));
+ dev_dbg(dev, "more_mul_max: min_pll_multiplier check: %d\n",
+ more_mul_max);
+
+ /* Ensure we won't go below min_pll_op_freq_hz. */
+ more_mul_min = DIV_ROUND_UP(limits->min_pll_op_freq_hz,
+ pll->ext_clk_freq_hz / pll->pre_pll_clk_div
+ * mul);
+ dev_dbg(dev, "more_mul_min: min_pll_op_freq_hz check: %d\n",
+ more_mul_min);
+ /* Ensure we won't go below min_pll_multiplier. */
+ more_mul_min = max(more_mul_min,
+ DIV_ROUND_UP(limits->min_pll_multiplier, mul));
+ dev_dbg(dev, "more_mul_min: min_pll_multiplier check: %d\n",
+ more_mul_min);
+
+ if (more_mul_min > more_mul_max) {
+ dev_warn(dev,
+ "unable to compute more_mul_min and more_mul_max");
+ return -EINVAL;
+ }
+
+ more_mul_factor = lcm(div, pll->pre_pll_clk_div) / div;
+ dev_dbg(dev, "more_mul_factor: %d\n", more_mul_factor);
+ more_mul_factor = lcm(more_mul_factor, limits->min_op_sys_clk_div);
+ dev_dbg(dev, "more_mul_factor: min_op_sys_clk_div: %d\n",
+ more_mul_factor);
+ i = roundup(more_mul_min, more_mul_factor);
+ if (!is_one_or_even(i))
+ i <<= 1;
+
+ dev_dbg(dev, "final more_mul: %d\n", i);
+ if (i > more_mul_max) {
+ dev_warn(dev, "final more_mul is bad, max %d", more_mul_max);
+ return -EINVAL;
+ }
+
+ pll->pll_multiplier = mul * i;
+ pll->op_sys_clk_div = div * i / pll->pre_pll_clk_div;
+ dev_dbg(dev, "op_sys_clk_div: %d\n", pll->op_sys_clk_div);
+
+ pll->pll_ip_clk_freq_hz = pll->ext_clk_freq_hz
+ / pll->pre_pll_clk_div;
+
+ pll->pll_op_clk_freq_hz = pll->pll_ip_clk_freq_hz
+ * pll->pll_multiplier;
+
+ /* Derive pll_op_clk_freq_hz. */
+ pll->op_sys_clk_freq_hz =
+ pll->pll_op_clk_freq_hz / pll->op_sys_clk_div;
+
+ pll->op_pix_clk_div = pll->bits_per_pixel;
+ dev_dbg(dev, "op_pix_clk_div: %d\n", pll->op_pix_clk_div);
+
+ pll->op_pix_clk_freq_hz =
+ pll->op_sys_clk_freq_hz / pll->op_pix_clk_div;
+
+ /*
+ * Some sensors perform analogue binning and some do this
+ * digitally. The ones doing this digitally can be roughly be
+ * found out using this formula. The ones doing this digitally
+ * should run at higher clock rate, so smaller divisor is used
+ * on video timing side.
+ */
+ if (limits->min_line_length_pck_bin > limits->min_line_length_pck
+ / pll->binning_horizontal)
+ vt_op_binning_div = pll->binning_horizontal;
+ else
+ vt_op_binning_div = 1;
+ dev_dbg(dev, "vt_op_binning_div: %d\n", vt_op_binning_div);
+
+ /*
+ * Profile 2 supports vt_pix_clk_div E [4, 10]
+ *
+ * Horizontal binning can be used as a base for difference in
+ * divisors. One must make sure that horizontal blanking is
+ * enough to accommodate the CSI-2 sync codes.
+ *
+ * Take scaling factor into account as well.
+ *
+ * Find absolute limits for the factor of vt divider.
+ */
+ dev_dbg(dev, "scale_m: %d\n", pll->scale_m);
+ min_vt_div = DIV_ROUND_UP(pll->op_pix_clk_div * pll->op_sys_clk_div
+ * pll->scale_n,
+ lane_op_clock_ratio * vt_op_binning_div
+ * pll->scale_m);
+
+ /* Find smallest and biggest allowed vt divisor. */
+ dev_dbg(dev, "min_vt_div: %d\n", min_vt_div);
+ min_vt_div = max(min_vt_div,
+ DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
+ limits->max_vt_pix_clk_freq_hz));
+ dev_dbg(dev, "min_vt_div: max_vt_pix_clk_freq_hz: %d\n",
+ min_vt_div);
+ min_vt_div = max_t(uint32_t, min_vt_div,
+ limits->min_vt_pix_clk_div
+ * limits->min_vt_sys_clk_div);
+ dev_dbg(dev, "min_vt_div: min_vt_clk_div: %d\n", min_vt_div);
+
+ max_vt_div = limits->max_vt_sys_clk_div * limits->max_vt_pix_clk_div;
+ dev_dbg(dev, "max_vt_div: %d\n", max_vt_div);
+ max_vt_div = min(max_vt_div,
+ DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
+ limits->min_vt_pix_clk_freq_hz));
+ dev_dbg(dev, "max_vt_div: min_vt_pix_clk_freq_hz: %d\n",
+ max_vt_div);
+
+ /*
+ * Find limitsits for sys_clk_div. Not all values are possible
+ * with all values of pix_clk_div.
+ */
+ min_sys_div = limits->min_vt_sys_clk_div;
+ dev_dbg(dev, "min_sys_div: %d\n", min_sys_div);
+ min_sys_div = max(min_sys_div,
+ DIV_ROUND_UP(min_vt_div,
+ limits->max_vt_pix_clk_div));
+ dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %d\n", min_sys_div);
+ min_sys_div = max(min_sys_div,
+ pll->pll_op_clk_freq_hz
+ / limits->max_vt_sys_clk_freq_hz);
+ dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %d\n", min_sys_div);
+ min_sys_div = clk_div_even_up(min_sys_div);
+ dev_dbg(dev, "min_sys_div: one or even: %d\n", min_sys_div);
+
+ max_sys_div = limits->max_vt_sys_clk_div;
+ dev_dbg(dev, "max_sys_div: %d\n", max_sys_div);
+ max_sys_div = min(max_sys_div,
+ DIV_ROUND_UP(max_vt_div,
+ limits->min_vt_pix_clk_div));
+ dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %d\n", max_sys_div);
+ max_sys_div = min(max_sys_div,
+ DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
+ limits->min_vt_pix_clk_freq_hz));
+ dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %d\n", max_sys_div);
+
+ /*
+ * Find pix_div such that a legal pix_div * sys_div results
+ * into a value which is not smaller than div, the desired
+ * divisor.
+ */
+ for (vt_div = min_vt_div; vt_div <= max_vt_div;
+ vt_div += 2 - (vt_div & 1)) {
+ for (sys_div = min_sys_div;
+ sys_div <= max_sys_div;
+ sys_div += 2 - (sys_div & 1)) {
+ int pix_div = DIV_ROUND_UP(vt_div, sys_div);
+
+ if (pix_div < limits->min_vt_pix_clk_div
+ || pix_div > limits->max_vt_pix_clk_div) {
+ dev_dbg(dev,
+ "pix_div %d too small or too big (%d--%d)\n",
+ pix_div,
+ limits->min_vt_pix_clk_div,
+ limits->max_vt_pix_clk_div);
+ continue;
+ }
+
+ /* Check if this one is better. */
+ if (pix_div * sys_div
+ <= roundup(min_vt_div, best_pix_div))
+ best_pix_div = pix_div;
+ }
+ if (best_pix_div < INT_MAX >> 1)
+ break;
+ }
+
+ pll->vt_sys_clk_div = DIV_ROUND_UP(min_vt_div, best_pix_div);
+ pll->vt_pix_clk_div = best_pix_div;
+
+ pll->vt_sys_clk_freq_hz =
+ pll->pll_op_clk_freq_hz / pll->vt_sys_clk_div;
+ pll->vt_pix_clk_freq_hz =
+ pll->vt_sys_clk_freq_hz / pll->vt_pix_clk_div;
+
+ pll->pixel_rate_csi =
+ pll->op_pix_clk_freq_hz * lane_op_clock_ratio;
+
+ print_pll(dev, pll);
+
+ rval = bounds_check(dev, pll->pre_pll_clk_div,
+ limits->min_pre_pll_clk_div,
+ limits->max_pre_pll_clk_div, "pre_pll_clk_div");
+ if (!rval)
+ rval = bounds_check(
+ dev, pll->pll_ip_clk_freq_hz,
+ limits->min_pll_ip_freq_hz, limits->max_pll_ip_freq_hz,
+ "pll_ip_clk_freq_hz");
+ if (!rval)
+ rval = bounds_check(
+ dev, pll->pll_multiplier,
+ limits->min_pll_multiplier, limits->max_pll_multiplier,
+ "pll_multiplier");
+ if (!rval)
+ rval = bounds_check(
+ dev, pll->pll_op_clk_freq_hz,
+ limits->min_pll_op_freq_hz, limits->max_pll_op_freq_hz,
+ "pll_op_clk_freq_hz");
+ if (!rval)
+ rval = bounds_check(
+ dev, pll->op_sys_clk_div,
+ limits->min_op_sys_clk_div, limits->max_op_sys_clk_div,
+ "op_sys_clk_div");
+ if (!rval)
+ rval = bounds_check(
+ dev, pll->op_pix_clk_div,
+ limits->min_op_pix_clk_div, limits->max_op_pix_clk_div,
+ "op_pix_clk_div");
+ if (!rval)
+ rval = bounds_check(
+ dev, pll->op_sys_clk_freq_hz,
+ limits->min_op_sys_clk_freq_hz,
+ limits->max_op_sys_clk_freq_hz,
+ "op_sys_clk_freq_hz");
+ if (!rval)
+ rval = bounds_check(
+ dev, pll->op_pix_clk_freq_hz,
+ limits->min_op_pix_clk_freq_hz,
+ limits->max_op_pix_clk_freq_hz,
+ "op_pix_clk_freq_hz");
+ if (!rval)
+ rval = bounds_check(
+ dev, pll->vt_sys_clk_freq_hz,
+ limits->min_vt_sys_clk_freq_hz,
+ limits->max_vt_sys_clk_freq_hz,
+ "vt_sys_clk_freq_hz");
+ if (!rval)
+ rval = bounds_check(
+ dev, pll->vt_pix_clk_freq_hz,
+ limits->min_vt_pix_clk_freq_hz,
+ limits->max_vt_pix_clk_freq_hz,
+ "vt_pix_clk_freq_hz");
+
+ return rval;
+}
+EXPORT_SYMBOL_GPL(smiapp_pll_calculate);
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>");
+MODULE_DESCRIPTION("Generic SMIA/SMIA++ PLL calculator");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/smiapp-pll.h b/drivers/media/video/smiapp-pll.h
new file mode 100644
index 000000000000..9eab63f23afb
--- /dev/null
+++ b/drivers/media/video/smiapp-pll.h
@@ -0,0 +1,103 @@
+/*
+ * drivers/media/video/smiapp-pll.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SMIAPP_PLL_H
+#define SMIAPP_PLL_H
+
+#include <linux/device.h>
+
+struct smiapp_pll {
+ uint8_t lanes;
+ uint8_t binning_horizontal;
+ uint8_t binning_vertical;
+ uint8_t scale_m;
+ uint8_t scale_n;
+ uint8_t bits_per_pixel;
+ uint16_t flags;
+ uint32_t link_freq;
+
+ uint16_t pre_pll_clk_div;
+ uint16_t pll_multiplier;
+ uint16_t op_sys_clk_div;
+ uint16_t op_pix_clk_div;
+ uint16_t vt_sys_clk_div;
+ uint16_t vt_pix_clk_div;
+
+ uint32_t ext_clk_freq_hz;
+ uint32_t pll_ip_clk_freq_hz;
+ uint32_t pll_op_clk_freq_hz;
+ uint32_t op_sys_clk_freq_hz;
+ uint32_t op_pix_clk_freq_hz;
+ uint32_t vt_sys_clk_freq_hz;
+ uint32_t vt_pix_clk_freq_hz;
+
+ uint32_t pixel_rate_csi;
+};
+
+struct smiapp_pll_limits {
+ /* Strict PLL limits */
+ uint32_t min_ext_clk_freq_hz;
+ uint32_t max_ext_clk_freq_hz;
+ uint16_t min_pre_pll_clk_div;
+ uint16_t max_pre_pll_clk_div;
+ uint32_t min_pll_ip_freq_hz;
+ uint32_t max_pll_ip_freq_hz;
+ uint16_t min_pll_multiplier;
+ uint16_t max_pll_multiplier;
+ uint32_t min_pll_op_freq_hz;
+ uint32_t max_pll_op_freq_hz;
+
+ uint16_t min_vt_sys_clk_div;
+ uint16_t max_vt_sys_clk_div;
+ uint32_t min_vt_sys_clk_freq_hz;
+ uint32_t max_vt_sys_clk_freq_hz;
+ uint16_t min_vt_pix_clk_div;
+ uint16_t max_vt_pix_clk_div;
+ uint32_t min_vt_pix_clk_freq_hz;
+ uint32_t max_vt_pix_clk_freq_hz;
+
+ uint16_t min_op_sys_clk_div;
+ uint16_t max_op_sys_clk_div;
+ uint32_t min_op_sys_clk_freq_hz;
+ uint32_t max_op_sys_clk_freq_hz;
+ uint16_t min_op_pix_clk_div;
+ uint16_t max_op_pix_clk_div;
+ uint32_t min_op_pix_clk_freq_hz;
+ uint32_t max_op_pix_clk_freq_hz;
+
+ /* Other relevant limits */
+ uint32_t min_line_length_pck_bin;
+ uint32_t min_line_length_pck;
+};
+
+/* op pix clock is for all lanes in total normally */
+#define SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE (1 << 0)
+#define SMIAPP_PLL_FLAG_NO_OP_CLOCKS (1 << 1)
+
+struct device;
+
+int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits,
+ struct smiapp_pll *pll);
+
+#endif /* SMIAPP_PLL_H */
diff --git a/drivers/media/video/smiapp/Kconfig b/drivers/media/video/smiapp/Kconfig
new file mode 100644
index 000000000000..f7b35ff443bf
--- /dev/null
+++ b/drivers/media/video/smiapp/Kconfig
@@ -0,0 +1,6 @@
+config VIDEO_SMIAPP
+ tristate "SMIA++/SMIA sensor support"
+ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ select VIDEO_SMIAPP_PLL
+ ---help---
+ This is a generic driver for SMIA++/SMIA camera modules.
diff --git a/drivers/media/video/smiapp/Makefile b/drivers/media/video/smiapp/Makefile
new file mode 100644
index 000000000000..36b0cfa2c541
--- /dev/null
+++ b/drivers/media/video/smiapp/Makefile
@@ -0,0 +1,5 @@
+smiapp-objs += smiapp-core.o smiapp-regs.o \
+ smiapp-quirk.o smiapp-limits.o
+obj-$(CONFIG_VIDEO_SMIAPP) += smiapp.o
+
+ccflags-y += -Idrivers/media/video
diff --git a/drivers/media/video/smiapp/smiapp-core.c b/drivers/media/video/smiapp/smiapp-core.c
new file mode 100644
index 000000000000..f518026cb67b
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-core.c
@@ -0,0 +1,2894 @@
+/*
+ * drivers/media/video/smiapp/smiapp-core.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2010--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
+ *
+ * Based on smiapp driver by Vimarsh Zutshi
+ * Based on jt8ev1.c by Vimarsh Zutshi
+ * Based on smia-sensor.c by Tuukka Toivonen <tuukkat76@gmail.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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/v4l2-mediabus.h>
+#include <media/v4l2-device.h>
+
+#include "smiapp.h"
+
+#define SMIAPP_ALIGN_DIM(dim, flags) \
+ ((flags) & V4L2_SUBDEV_SEL_FLAG_SIZE_GE \
+ ? ALIGN((dim), 2) \
+ : (dim) & ~1)
+
+/*
+ * smiapp_module_idents - supported camera modules
+ */
+static const struct smiapp_module_ident smiapp_module_idents[] = {
+ SMIAPP_IDENT_L(0x01, 0x022b, -1, "vs6555"),
+ SMIAPP_IDENT_L(0x01, 0x022e, -1, "vw6558"),
+ SMIAPP_IDENT_L(0x07, 0x7698, -1, "ovm7698"),
+ SMIAPP_IDENT_L(0x0b, 0x4242, -1, "smiapp-003"),
+ SMIAPP_IDENT_L(0x0c, 0x208a, -1, "tcm8330md"),
+ SMIAPP_IDENT_LQ(0x0c, 0x2134, -1, "tcm8500md", &smiapp_tcm8500md_quirk),
+ SMIAPP_IDENT_L(0x0c, 0x213e, -1, "et8en2"),
+ SMIAPP_IDENT_L(0x0c, 0x2184, -1, "tcm8580md"),
+ SMIAPP_IDENT_LQ(0x0c, 0x560f, -1, "jt8ew9", &smiapp_jt8ew9_quirk),
+ SMIAPP_IDENT_LQ(0x10, 0x4141, -1, "jt8ev1", &smiapp_jt8ev1_quirk),
+ SMIAPP_IDENT_LQ(0x10, 0x4241, -1, "imx125es", &smiapp_imx125es_quirk),
+};
+
+/*
+ *
+ * Dynamic Capability Identification
+ *
+ */
+
+static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ u32 fmt_model_type, fmt_model_subtype, ncol_desc, nrow_desc;
+ unsigned int i;
+ int rval;
+ int line_count = 0;
+ int embedded_start = -1, embedded_end = -1;
+ int image_start = 0;
+
+ rval = smiapp_read(sensor, SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE,
+ &fmt_model_type);
+ if (rval)
+ return rval;
+
+ rval = smiapp_read(sensor, SMIAPP_REG_U8_FRAME_FORMAT_MODEL_SUBTYPE,
+ &fmt_model_subtype);
+ if (rval)
+ return rval;
+
+ ncol_desc = (fmt_model_subtype
+ & SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_MASK)
+ >> SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_SHIFT;
+ nrow_desc = fmt_model_subtype
+ & SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NROWS_MASK;
+
+ dev_dbg(&client->dev, "format_model_type %s\n",
+ fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE
+ ? "2 byte" :
+ fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE
+ ? "4 byte" : "is simply bad");
+
+ for (i = 0; i < ncol_desc + nrow_desc; i++) {
+ u32 desc;
+ u32 pixelcode;
+ u32 pixels;
+ char *which;
+ char *what;
+
+ if (fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE) {
+ rval = smiapp_read(
+ sensor,
+ SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(i),
+ &desc);
+ if (rval)
+ return rval;
+
+ pixelcode =
+ (desc
+ & SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_MASK)
+ >> SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_SHIFT;
+ pixels = desc & SMIAPP_FRAME_FORMAT_DESC_2_PIXELS_MASK;
+ } else if (fmt_model_type
+ == SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE) {
+ rval = smiapp_read(
+ sensor,
+ SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(i),
+ &desc);
+ if (rval)
+ return rval;
+
+ pixelcode =
+ (desc
+ & SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_MASK)
+ >> SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_SHIFT;
+ pixels = desc & SMIAPP_FRAME_FORMAT_DESC_4_PIXELS_MASK;
+ } else {
+ dev_dbg(&client->dev,
+ "invalid frame format model type %d\n",
+ fmt_model_type);
+ return -EINVAL;
+ }
+
+ if (i < ncol_desc)
+ which = "columns";
+ else
+ which = "rows";
+
+ switch (pixelcode) {
+ case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED:
+ what = "embedded";
+ break;
+ case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DUMMY:
+ what = "dummy";
+ break;
+ case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_BLACK:
+ what = "black";
+ break;
+ case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DARK:
+ what = "dark";
+ break;
+ case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE:
+ what = "visible";
+ break;
+ default:
+ what = "invalid";
+ dev_dbg(&client->dev, "pixelcode %d\n", pixelcode);
+ break;
+ }
+
+ dev_dbg(&client->dev, "%s pixels: %d %s\n",
+ what, pixels, which);
+
+ if (i < ncol_desc)
+ continue;
+
+ /* Handle row descriptors */
+ if (pixelcode
+ == SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED) {
+ embedded_start = line_count;
+ } else {
+ if (pixelcode == SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE
+ || pixels >= sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES] / 2)
+ image_start = line_count;
+ if (embedded_start != -1 && embedded_end == -1)
+ embedded_end = line_count;
+ }
+ line_count += pixels;
+ }
+
+ if (embedded_start == -1 || embedded_end == -1) {
+ embedded_start = 0;
+ embedded_end = 0;
+ }
+
+ dev_dbg(&client->dev, "embedded data from lines %d to %d\n",
+ embedded_start, embedded_end);
+ dev_dbg(&client->dev, "image data starts at line %d\n", image_start);
+
+ return 0;
+}
+
+static int smiapp_pll_configure(struct smiapp_sensor *sensor)
+{
+ struct smiapp_pll *pll = &sensor->pll;
+ int rval;
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_VT_PIX_CLK_DIV, pll->vt_pix_clk_div);
+ if (rval < 0)
+ return rval;
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_VT_SYS_CLK_DIV, pll->vt_sys_clk_div);
+ if (rval < 0)
+ return rval;
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_PRE_PLL_CLK_DIV, pll->pre_pll_clk_div);
+ if (rval < 0)
+ return rval;
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_PLL_MULTIPLIER, pll->pll_multiplier);
+ if (rval < 0)
+ return rval;
+
+ /* Lane op clock ratio does not apply here. */
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS,
+ DIV_ROUND_UP(pll->op_sys_clk_freq_hz, 1000000 / 256 / 256));
+ if (rval < 0 || sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0)
+ return rval;
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_OP_PIX_CLK_DIV, pll->op_pix_clk_div);
+ if (rval < 0)
+ return rval;
+
+ return smiapp_write(
+ sensor, SMIAPP_REG_U16_OP_SYS_CLK_DIV, pll->op_sys_clk_div);
+}
+
+static int smiapp_pll_update(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ struct smiapp_pll_limits lim = {
+ .min_pre_pll_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_PRE_PLL_CLK_DIV],
+ .max_pre_pll_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_PRE_PLL_CLK_DIV],
+ .min_pll_ip_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ],
+ .max_pll_ip_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_PLL_IP_FREQ_HZ],
+ .min_pll_multiplier = sensor->limits[SMIAPP_LIMIT_MIN_PLL_MULTIPLIER],
+ .max_pll_multiplier = sensor->limits[SMIAPP_LIMIT_MAX_PLL_MULTIPLIER],
+ .min_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_PLL_OP_FREQ_HZ],
+ .max_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_PLL_OP_FREQ_HZ],
+
+ .min_op_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV],
+ .max_op_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV],
+ .min_op_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV],
+ .max_op_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV],
+ .min_op_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_FREQ_HZ],
+ .max_op_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_FREQ_HZ],
+ .min_op_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_FREQ_HZ],
+ .max_op_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_FREQ_HZ],
+
+ .min_vt_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV],
+ .max_vt_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV],
+ .min_vt_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV],
+ .max_vt_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV],
+ .min_vt_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_FREQ_HZ],
+ .max_vt_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ],
+ .min_vt_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ],
+ .max_vt_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ],
+
+ .min_line_length_pck_bin = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN],
+ .min_line_length_pck = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK],
+ };
+ struct smiapp_pll *pll = &sensor->pll;
+ int rval;
+
+ memset(&sensor->pll, 0, sizeof(sensor->pll));
+
+ pll->lanes = sensor->platform_data->lanes;
+ pll->ext_clk_freq_hz = sensor->platform_data->ext_clk;
+
+ if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) {
+ /*
+ * Fill in operational clock divisors limits from the
+ * video timing ones. On profile 0 sensors the
+ * requirements regarding them are essentially the
+ * same as on VT ones.
+ */
+ lim.min_op_sys_clk_div = lim.min_vt_sys_clk_div;
+ lim.max_op_sys_clk_div = lim.max_vt_sys_clk_div;
+ lim.min_op_pix_clk_div = lim.min_vt_pix_clk_div;
+ lim.max_op_pix_clk_div = lim.max_vt_pix_clk_div;
+ lim.min_op_sys_clk_freq_hz = lim.min_vt_sys_clk_freq_hz;
+ lim.max_op_sys_clk_freq_hz = lim.max_vt_sys_clk_freq_hz;
+ lim.min_op_pix_clk_freq_hz = lim.min_vt_pix_clk_freq_hz;
+ lim.max_op_pix_clk_freq_hz = lim.max_vt_pix_clk_freq_hz;
+ /* Profile 0 sensors have no separate OP clock branch. */
+ 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->binning_horizontal = sensor->binning_horizontal;
+ pll->binning_vertical = sensor->binning_vertical;
+ pll->link_freq =
+ sensor->link_freq->qmenu_int[sensor->link_freq->val];
+ pll->scale_m = sensor->scale_m;
+ pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
+ pll->bits_per_pixel = sensor->csi_format->compressed;
+
+ rval = smiapp_pll_calculate(&client->dev, &lim, pll);
+ if (rval < 0)
+ return rval;
+
+ sensor->pixel_rate_parray->cur.val64 = pll->vt_pix_clk_freq_hz;
+ sensor->pixel_rate_csi->cur.val64 = pll->pixel_rate_csi;
+
+ return 0;
+}
+
+
+/*
+ *
+ * V4L2 Controls handling
+ *
+ */
+
+static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor)
+{
+ struct v4l2_ctrl *ctrl = sensor->exposure;
+ int max;
+
+ max = sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height
+ + sensor->vblank->val
+ - sensor->limits[SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN];
+
+ ctrl->maximum = max;
+ if (ctrl->default_value > max)
+ ctrl->default_value = max;
+ if (ctrl->val > max)
+ ctrl->val = max;
+ if (ctrl->cur.val > max)
+ ctrl->cur.val = max;
+}
+
+/*
+ * Order matters.
+ *
+ * 1. Bits-per-pixel, descending.
+ * 2. Bits-per-pixel compressed, descending.
+ * 3. Pixel order, same as in pixel_order_str. Formats for all four pixel
+ * orders must be defined.
+ */
+static const struct smiapp_csi_data_format smiapp_csi_data_formats[] = {
+ { V4L2_MBUS_FMT_SGRBG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GRBG, },
+ { V4L2_MBUS_FMT_SRGGB12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_RGGB, },
+ { V4L2_MBUS_FMT_SBGGR12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_BGGR, },
+ { V4L2_MBUS_FMT_SGBRG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GBRG, },
+ { V4L2_MBUS_FMT_SGRBG10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_GRBG, },
+ { V4L2_MBUS_FMT_SRGGB10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_RGGB, },
+ { V4L2_MBUS_FMT_SBGGR10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_BGGR, },
+ { V4L2_MBUS_FMT_SGBRG10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_GBRG, },
+ { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_GRBG, },
+ { V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_RGGB, },
+ { V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_BGGR, },
+ { V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_GBRG, },
+ { V4L2_MBUS_FMT_SGRBG8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_GRBG, },
+ { V4L2_MBUS_FMT_SRGGB8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_RGGB, },
+ { V4L2_MBUS_FMT_SBGGR8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_BGGR, },
+ { V4L2_MBUS_FMT_SGBRG8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_GBRG, },
+};
+
+const char *pixel_order_str[] = { "GRBG", "RGGB", "BGGR", "GBRG" };
+
+#define to_csi_format_idx(fmt) (((unsigned long)(fmt) \
+ - (unsigned long)smiapp_csi_data_formats) \
+ / sizeof(*smiapp_csi_data_formats))
+
+static u32 smiapp_pixel_order(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ int flip = 0;
+
+ if (sensor->hflip) {
+ if (sensor->hflip->val)
+ flip |= SMIAPP_IMAGE_ORIENTATION_HFLIP;
+
+ if (sensor->vflip->val)
+ flip |= SMIAPP_IMAGE_ORIENTATION_VFLIP;
+ }
+
+ flip ^= sensor->hvflip_inv_mask;
+
+ dev_dbg(&client->dev, "flip %d\n", flip);
+ return sensor->default_pixel_order ^ flip;
+}
+
+static void smiapp_update_mbus_formats(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ unsigned int csi_format_idx =
+ to_csi_format_idx(sensor->csi_format) & ~3;
+ unsigned int internal_csi_format_idx =
+ to_csi_format_idx(sensor->internal_csi_format) & ~3;
+ unsigned int pixel_order = smiapp_pixel_order(sensor);
+
+ sensor->mbus_frame_fmts =
+ sensor->default_mbus_frame_fmts << pixel_order;
+ sensor->csi_format =
+ &smiapp_csi_data_formats[csi_format_idx + pixel_order];
+ sensor->internal_csi_format =
+ &smiapp_csi_data_formats[internal_csi_format_idx
+ + pixel_order];
+
+ BUG_ON(max(internal_csi_format_idx, csi_format_idx) + pixel_order
+ >= ARRAY_SIZE(smiapp_csi_data_formats));
+ BUG_ON(min(internal_csi_format_idx, csi_format_idx) < 0);
+
+ dev_dbg(&client->dev, "new pixel order %s\n",
+ pixel_order_str[pixel_order]);
+}
+
+static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct smiapp_sensor *sensor =
+ container_of(ctrl->handler, struct smiapp_subdev, ctrl_handler)
+ ->sensor;
+ u32 orient = 0;
+ int exposure;
+ int rval;
+
+ switch (ctrl->id) {
+ case V4L2_CID_ANALOGUE_GAIN:
+ return smiapp_write(
+ sensor,
+ SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL, ctrl->val);
+
+ case V4L2_CID_EXPOSURE:
+ return smiapp_write(
+ sensor,
+ SMIAPP_REG_U16_COARSE_INTEGRATION_TIME, ctrl->val);
+
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ if (sensor->streaming)
+ return -EBUSY;
+
+ if (sensor->hflip->val)
+ orient |= SMIAPP_IMAGE_ORIENTATION_HFLIP;
+
+ if (sensor->vflip->val)
+ orient |= SMIAPP_IMAGE_ORIENTATION_VFLIP;
+
+ orient ^= sensor->hvflip_inv_mask;
+ rval = smiapp_write(sensor,
+ SMIAPP_REG_U8_IMAGE_ORIENTATION,
+ orient);
+ if (rval < 0)
+ return rval;
+
+ smiapp_update_mbus_formats(sensor);
+
+ return 0;
+
+ case V4L2_CID_VBLANK:
+ exposure = sensor->exposure->val;
+
+ __smiapp_update_exposure_limits(sensor);
+
+ if (exposure > sensor->exposure->maximum) {
+ sensor->exposure->val =
+ sensor->exposure->maximum;
+ rval = smiapp_set_ctrl(
+ sensor->exposure);
+ if (rval < 0)
+ return rval;
+ }
+
+ return smiapp_write(
+ sensor, SMIAPP_REG_U16_FRAME_LENGTH_LINES,
+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height
+ + ctrl->val);
+
+ case V4L2_CID_HBLANK:
+ return smiapp_write(
+ sensor, SMIAPP_REG_U16_LINE_LENGTH_PCK,
+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width
+ + ctrl->val);
+
+ case V4L2_CID_LINK_FREQ:
+ if (sensor->streaming)
+ return -EBUSY;
+
+ return smiapp_pll_update(sensor);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct v4l2_ctrl_ops smiapp_ctrl_ops = {
+ .s_ctrl = smiapp_set_ctrl,
+};
+
+static int smiapp_init_controls(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ unsigned int max;
+ int rval;
+
+ rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 7);
+ if (rval)
+ return rval;
+ sensor->pixel_array->ctrl_handler.lock = &sensor->mutex;
+
+ sensor->analog_gain = v4l2_ctrl_new_std(
+ &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+ V4L2_CID_ANALOGUE_GAIN,
+ sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN],
+ sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX],
+ max(sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_STEP], 1U),
+ sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN]);
+
+ /* Exposure limits will be updated soon, use just something here. */
+ sensor->exposure = v4l2_ctrl_new_std(
+ &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+ V4L2_CID_EXPOSURE, 0, 0, 1, 0);
+
+ sensor->hflip = v4l2_ctrl_new_std(
+ &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ sensor->vflip = v4l2_ctrl_new_std(
+ &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+ sensor->vblank = v4l2_ctrl_new_std(
+ &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+ V4L2_CID_VBLANK, 0, 1, 1, 0);
+
+ if (sensor->vblank)
+ sensor->vblank->flags |= V4L2_CTRL_FLAG_UPDATE;
+
+ sensor->hblank = v4l2_ctrl_new_std(
+ &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+ V4L2_CID_HBLANK, 0, 1, 1, 0);
+
+ if (sensor->hblank)
+ sensor->hblank->flags |= V4L2_CTRL_FLAG_UPDATE;
+
+ sensor->pixel_rate_parray = v4l2_ctrl_new_std(
+ &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
+ V4L2_CID_PIXEL_RATE, 0, 0, 1, 0);
+
+ if (sensor->pixel_array->ctrl_handler.error) {
+ dev_err(&client->dev,
+ "pixel array controls initialization failed (%d)\n",
+ sensor->pixel_array->ctrl_handler.error);
+ rval = sensor->pixel_array->ctrl_handler.error;
+ goto error;
+ }
+
+ sensor->pixel_array->sd.ctrl_handler =
+ &sensor->pixel_array->ctrl_handler;
+
+ v4l2_ctrl_cluster(2, &sensor->hflip);
+
+ rval = v4l2_ctrl_handler_init(&sensor->src->ctrl_handler, 0);
+ if (rval)
+ goto error;
+ sensor->src->ctrl_handler.lock = &sensor->mutex;
+
+ for (max = 0; sensor->platform_data->op_sys_clock[max + 1]; max++);
+
+ sensor->link_freq = v4l2_ctrl_new_int_menu(
+ &sensor->src->ctrl_handler, &smiapp_ctrl_ops,
+ V4L2_CID_LINK_FREQ, max, 0,
+ sensor->platform_data->op_sys_clock);
+
+ sensor->pixel_rate_csi = v4l2_ctrl_new_std(
+ &sensor->src->ctrl_handler, &smiapp_ctrl_ops,
+ V4L2_CID_PIXEL_RATE, 0, 0, 1, 0);
+
+ if (sensor->src->ctrl_handler.error) {
+ dev_err(&client->dev,
+ "src controls initialization failed (%d)\n",
+ sensor->src->ctrl_handler.error);
+ rval = sensor->src->ctrl_handler.error;
+ goto error;
+ }
+
+ sensor->src->sd.ctrl_handler =
+ &sensor->src->ctrl_handler;
+
+ return 0;
+
+error:
+ v4l2_ctrl_handler_free(&sensor->pixel_array->ctrl_handler);
+ v4l2_ctrl_handler_free(&sensor->src->ctrl_handler);
+
+ return rval;
+}
+
+static void smiapp_free_controls(struct smiapp_sensor *sensor)
+{
+ unsigned int i;
+
+ for (i = 0; i < sensor->ssds_used; i++)
+ v4l2_ctrl_handler_free(&sensor->ssds[i].ctrl_handler);
+}
+
+static int smiapp_get_limits(struct smiapp_sensor *sensor, int const *limit,
+ unsigned int n)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ unsigned int i;
+ u32 val;
+ int rval;
+
+ for (i = 0; i < n; i++) {
+ rval = smiapp_read(
+ sensor, smiapp_reg_limits[limit[i]].addr, &val);
+ if (rval)
+ return rval;
+ sensor->limits[limit[i]] = val;
+ dev_dbg(&client->dev, "0x%8.8x \"%s\" = %d, 0x%x\n",
+ smiapp_reg_limits[limit[i]].addr,
+ smiapp_reg_limits[limit[i]].what, val, val);
+ }
+
+ return 0;
+}
+
+static int smiapp_get_all_limits(struct smiapp_sensor *sensor)
+{
+ unsigned int i;
+ int rval;
+
+ for (i = 0; i < SMIAPP_LIMIT_LAST; i++) {
+ rval = smiapp_get_limits(sensor, &i, 1);
+ if (rval < 0)
+ return rval;
+ }
+
+ if (sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] == 0)
+ smiapp_replace_limit(sensor, SMIAPP_LIMIT_SCALER_N_MIN, 16);
+
+ return 0;
+}
+
+static int smiapp_get_limits_binning(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ static u32 const limits[] = {
+ SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN,
+ SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN,
+ SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN,
+ SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN,
+ SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN,
+ SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN_BIN,
+ SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN,
+ };
+ static u32 const limits_replace[] = {
+ SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES,
+ SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES,
+ SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK,
+ SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK,
+ SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK,
+ SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN,
+ SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN,
+ };
+ unsigned int i;
+ int rval;
+
+ if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY] ==
+ SMIAPP_BINNING_CAPABILITY_NO) {
+ for (i = 0; i < ARRAY_SIZE(limits); i++)
+ sensor->limits[limits[i]] =
+ sensor->limits[limits_replace[i]];
+
+ return 0;
+ }
+
+ rval = smiapp_get_limits(sensor, limits, ARRAY_SIZE(limits));
+ if (rval < 0)
+ return rval;
+
+ /*
+ * Sanity check whether the binning limits are valid. If not,
+ * use the non-binning ones.
+ */
+ if (sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN]
+ && sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN]
+ && sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN])
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(limits); i++) {
+ dev_dbg(&client->dev,
+ "replace limit 0x%8.8x \"%s\" = %d, 0x%x\n",
+ smiapp_reg_limits[limits[i]].addr,
+ smiapp_reg_limits[limits[i]].what,
+ sensor->limits[limits_replace[i]],
+ sensor->limits[limits_replace[i]]);
+ sensor->limits[limits[i]] =
+ sensor->limits[limits_replace[i]];
+ }
+
+ return 0;
+}
+
+static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ unsigned int type, n;
+ unsigned int i, pixel_order;
+ int rval;
+
+ rval = smiapp_read(
+ sensor, SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE, &type);
+ if (rval)
+ return rval;
+
+ dev_dbg(&client->dev, "data_format_model_type %d\n", type);
+
+ rval = smiapp_read(sensor, SMIAPP_REG_U8_PIXEL_ORDER,
+ &pixel_order);
+ if (rval)
+ return rval;
+
+ if (pixel_order >= ARRAY_SIZE(pixel_order_str)) {
+ dev_dbg(&client->dev, "bad pixel order %d\n", pixel_order);
+ return -EINVAL;
+ }
+
+ dev_dbg(&client->dev, "pixel order %d (%s)\n", pixel_order,
+ pixel_order_str[pixel_order]);
+
+ switch (type) {
+ case SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL:
+ n = SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N;
+ break;
+ case SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED:
+ n = SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED_N;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ sensor->default_pixel_order = pixel_order;
+ sensor->mbus_frame_fmts = 0;
+
+ for (i = 0; i < n; i++) {
+ unsigned int fmt, j;
+
+ rval = smiapp_read(
+ sensor,
+ SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(i), &fmt);
+ if (rval)
+ return rval;
+
+ dev_dbg(&client->dev, "bpp %d, compressed %d\n",
+ fmt >> 8, (u8)fmt);
+
+ for (j = 0; j < ARRAY_SIZE(smiapp_csi_data_formats); j++) {
+ const struct smiapp_csi_data_format *f =
+ &smiapp_csi_data_formats[j];
+
+ if (f->pixel_order != SMIAPP_PIXEL_ORDER_GRBG)
+ continue;
+
+ if (f->width != fmt >> 8 || f->compressed != (u8)fmt)
+ continue;
+
+ dev_dbg(&client->dev, "jolly good! %d\n", j);
+
+ sensor->default_mbus_frame_fmts |= 1 << j;
+ if (!sensor->csi_format) {
+ sensor->csi_format = f;
+ sensor->internal_csi_format = f;
+ }
+ }
+ }
+
+ if (!sensor->csi_format) {
+ dev_err(&client->dev, "no supported mbus code found\n");
+ return -EINVAL;
+ }
+
+ smiapp_update_mbus_formats(sensor);
+
+ return 0;
+}
+
+static void smiapp_update_blanking(struct smiapp_sensor *sensor)
+{
+ struct v4l2_ctrl *vblank = sensor->vblank;
+ struct v4l2_ctrl *hblank = sensor->hblank;
+
+ vblank->minimum =
+ max_t(int,
+ sensor->limits[SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES],
+ sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN] -
+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height);
+ vblank->maximum =
+ sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN] -
+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height;
+
+ vblank->val = clamp_t(int, vblank->val,
+ vblank->minimum, vblank->maximum);
+ vblank->default_value = vblank->minimum;
+ vblank->val = vblank->val;
+ vblank->cur.val = vblank->val;
+
+ hblank->minimum =
+ max_t(int,
+ sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] -
+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width,
+ sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]);
+ hblank->maximum =
+ sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN] -
+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width;
+
+ hblank->val = clamp_t(int, hblank->val,
+ hblank->minimum, hblank->maximum);
+ hblank->default_value = hblank->minimum;
+ hblank->val = hblank->val;
+ hblank->cur.val = hblank->val;
+
+ __smiapp_update_exposure_limits(sensor);
+}
+
+static int smiapp_update_mode(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ unsigned int binning_mode;
+ int rval;
+
+ dev_dbg(&client->dev, "frame size: %dx%d\n",
+ sensor->src->crop[SMIAPP_PAD_SRC].width,
+ sensor->src->crop[SMIAPP_PAD_SRC].height);
+ dev_dbg(&client->dev, "csi format width: %d\n",
+ sensor->csi_format->width);
+
+ /* Binning has to be set up here; it affects limits */
+ if (sensor->binning_horizontal == 1 &&
+ sensor->binning_vertical == 1) {
+ binning_mode = 0;
+ } else {
+ u8 binning_type =
+ (sensor->binning_horizontal << 4)
+ | sensor->binning_vertical;
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U8_BINNING_TYPE, binning_type);
+ if (rval < 0)
+ return rval;
+
+ binning_mode = 1;
+ }
+ rval = smiapp_write(sensor, SMIAPP_REG_U8_BINNING_MODE, binning_mode);
+ if (rval < 0)
+ return rval;
+
+ /* Get updated limits due to binning */
+ rval = smiapp_get_limits_binning(sensor);
+ if (rval < 0)
+ return rval;
+
+ rval = smiapp_pll_update(sensor);
+ if (rval < 0)
+ return rval;
+
+ /* Output from pixel array, including blanking */
+ smiapp_update_blanking(sensor);
+
+ dev_dbg(&client->dev, "vblank\t\t%d\n", sensor->vblank->val);
+ dev_dbg(&client->dev, "hblank\t\t%d\n", sensor->hblank->val);
+
+ dev_dbg(&client->dev, "real timeperframe\t100/%d\n",
+ sensor->pll.vt_pix_clk_freq_hz /
+ ((sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width
+ + sensor->hblank->val) *
+ (sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height
+ + sensor->vblank->val) / 100));
+
+ return 0;
+}
+
+/*
+ *
+ * SMIA++ NVM handling
+ *
+ */
+static int smiapp_read_nvm(struct smiapp_sensor *sensor,
+ unsigned char *nvm)
+{
+ u32 i, s, p, np, v;
+ int rval = 0, rval2;
+
+ np = sensor->nvm_size / SMIAPP_NVM_PAGE_SIZE;
+ for (p = 0; p < np; p++) {
+ rval = smiapp_write(
+ sensor,
+ SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT, p);
+ if (rval)
+ goto out;
+
+ rval = smiapp_write(sensor,
+ SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL,
+ SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN |
+ SMIAPP_DATA_TRANSFER_IF_1_CTRL_RD_EN);
+ if (rval)
+ goto out;
+
+ for (i = 0; i < 1000; i++) {
+ rval = smiapp_read(
+ sensor,
+ SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS, &s);
+
+ if (rval)
+ goto out;
+
+ if (s & SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY)
+ break;
+
+ if (--i == 0) {
+ rval = -ETIMEDOUT;
+ goto out;
+ }
+
+ }
+
+ for (i = 0; i < SMIAPP_NVM_PAGE_SIZE; i++) {
+ rval = smiapp_read(
+ sensor,
+ SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0 + i,
+ &v);
+ if (rval)
+ goto out;
+
+ *nvm++ = v;
+ }
+ }
+
+out:
+ rval2 = smiapp_write(sensor, SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL, 0);
+ if (rval < 0)
+ return rval;
+ else
+ return rval2;
+}
+
+/*
+ *
+ * SMIA++ CCI address control
+ *
+ */
+static int smiapp_change_cci_addr(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ int rval;
+ u32 val;
+
+ client->addr = sensor->platform_data->i2c_addr_dfl;
+
+ rval = smiapp_write(sensor,
+ SMIAPP_REG_U8_CCI_ADDRESS_CONTROL,
+ sensor->platform_data->i2c_addr_alt << 1);
+ if (rval)
+ return rval;
+
+ client->addr = sensor->platform_data->i2c_addr_alt;
+
+ /* verify addr change went ok */
+ rval = smiapp_read(sensor, SMIAPP_REG_U8_CCI_ADDRESS_CONTROL, &val);
+ if (rval)
+ return rval;
+
+ if (val != sensor->platform_data->i2c_addr_alt << 1)
+ return -ENODEV;
+
+ return 0;
+}
+
+/*
+ *
+ * SMIA++ Mode Control
+ *
+ */
+static int smiapp_setup_flash_strobe(struct smiapp_sensor *sensor)
+{
+ struct smiapp_flash_strobe_parms *strobe_setup;
+ unsigned int ext_freq = sensor->platform_data->ext_clk;
+ u32 tmp;
+ u32 strobe_adjustment;
+ u32 strobe_width_high_rs;
+ int rval;
+
+ strobe_setup = sensor->platform_data->strobe_setup;
+
+ /*
+ * How to calculate registers related to strobe length. Please
+ * do not change, or if you do at least know what you're
+ * doing. :-)
+ *
+ * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> 2010-10-25
+ *
+ * flash_strobe_length [us] / 10^6 = (tFlash_strobe_width_ctrl
+ * / EXTCLK freq [Hz]) * flash_strobe_adjustment
+ *
+ * tFlash_strobe_width_ctrl E N, [1 - 0xffff]
+ * flash_strobe_adjustment E N, [1 - 0xff]
+ *
+ * The formula above is written as below to keep it on one
+ * line:
+ *
+ * l / 10^6 = w / e * a
+ *
+ * Let's mark w * a by x:
+ *
+ * x = w * a
+ *
+ * Thus, we get:
+ *
+ * x = l * e / 10^6
+ *
+ * The strobe width must be at least as long as requested,
+ * thus rounding upwards is needed.
+ *
+ * x = (l * e + 10^6 - 1) / 10^6
+ * -----------------------------
+ *
+ * Maximum possible accuracy is wanted at all times. Thus keep
+ * a as small as possible.
+ *
+ * Calculate a, assuming maximum w, with rounding upwards:
+ *
+ * a = (x + (2^16 - 1) - 1) / (2^16 - 1)
+ * -------------------------------------
+ *
+ * Thus, we also get w, with that a, with rounding upwards:
+ *
+ * w = (x + a - 1) / a
+ * -------------------
+ *
+ * To get limits:
+ *
+ * x E [1, (2^16 - 1) * (2^8 - 1)]
+ *
+ * Substituting maximum x to the original formula (with rounding),
+ * the maximum l is thus
+ *
+ * (2^16 - 1) * (2^8 - 1) * 10^6 = l * e + 10^6 - 1
+ *
+ * l = (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / e
+ * --------------------------------------------------
+ *
+ * flash_strobe_length must be clamped between 1 and
+ * (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / EXTCLK freq.
+ *
+ * Then,
+ *
+ * flash_strobe_adjustment = ((flash_strobe_length *
+ * EXTCLK freq + 10^6 - 1) / 10^6 + (2^16 - 1) - 1) / (2^16 - 1)
+ *
+ * tFlash_strobe_width_ctrl = ((flash_strobe_length *
+ * EXTCLK freq + 10^6 - 1) / 10^6 +
+ * flash_strobe_adjustment - 1) / flash_strobe_adjustment
+ */
+ tmp = div_u64(1000000ULL * ((1 << 16) - 1) * ((1 << 8) - 1) -
+ 1000000 + 1, ext_freq);
+ strobe_setup->strobe_width_high_us =
+ clamp_t(u32, strobe_setup->strobe_width_high_us, 1, tmp);
+
+ tmp = div_u64(((u64)strobe_setup->strobe_width_high_us * (u64)ext_freq +
+ 1000000 - 1), 1000000ULL);
+ strobe_adjustment = (tmp + (1 << 16) - 1 - 1) / ((1 << 16) - 1);
+ strobe_width_high_rs = (tmp + strobe_adjustment - 1) /
+ strobe_adjustment;
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U8_FLASH_MODE_RS,
+ strobe_setup->mode);
+ if (rval < 0)
+ goto out;
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT,
+ strobe_adjustment);
+ if (rval < 0)
+ goto out;
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL,
+ strobe_width_high_rs);
+ if (rval < 0)
+ goto out;
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL,
+ strobe_setup->strobe_delay);
+ if (rval < 0)
+ goto out;
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U16_FLASH_STROBE_START_POINT,
+ strobe_setup->stobe_start_point);
+ if (rval < 0)
+ goto out;
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U8_FLASH_TRIGGER_RS,
+ strobe_setup->trigger);
+
+out:
+ sensor->platform_data->strobe_setup->trigger = 0;
+
+ return rval;
+}
+
+/* -----------------------------------------------------------------------------
+ * Power management
+ */
+
+static int smiapp_power_on(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ unsigned int sleep;
+ int rval;
+
+ rval = regulator_enable(sensor->vana);
+ if (rval) {
+ dev_err(&client->dev, "failed to enable vana regulator\n");
+ return rval;
+ }
+ usleep_range(1000, 1000);
+
+ if (sensor->platform_data->set_xclk)
+ rval = sensor->platform_data->set_xclk(
+ &sensor->src->sd, sensor->platform_data->ext_clk);
+ else
+ rval = clk_enable(sensor->ext_clk);
+ if (rval < 0) {
+ dev_dbg(&client->dev, "failed to set xclk\n");
+ goto out_xclk_fail;
+ }
+ usleep_range(1000, 1000);
+
+ if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+ gpio_set_value(sensor->platform_data->xshutdown, 1);
+
+ sleep = SMIAPP_RESET_DELAY(sensor->platform_data->ext_clk);
+ usleep_range(sleep, sleep);
+
+ /*
+ * Failures to respond to the address change command have been noticed.
+ * Those failures seem to be caused by the sensor requiring a longer
+ * boot time than advertised. An additional 10ms delay seems to work
+ * around the issue, but the SMIA++ I2C write retry hack makes the delay
+ * unnecessary. The failures need to be investigated to find a proper
+ * fix, and a delay will likely need to be added here if the I2C write
+ * retry hack is reverted before the root cause of the boot time issue
+ * is found.
+ */
+
+ if (sensor->platform_data->i2c_addr_alt) {
+ rval = smiapp_change_cci_addr(sensor);
+ if (rval) {
+ dev_err(&client->dev, "cci address change error\n");
+ goto out_cci_addr_fail;
+ }
+ }
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U8_SOFTWARE_RESET,
+ SMIAPP_SOFTWARE_RESET);
+ if (rval < 0) {
+ dev_err(&client->dev, "software reset failed\n");
+ goto out_cci_addr_fail;
+ }
+
+ if (sensor->platform_data->i2c_addr_alt) {
+ rval = smiapp_change_cci_addr(sensor);
+ if (rval) {
+ dev_err(&client->dev, "cci address change error\n");
+ goto out_cci_addr_fail;
+ }
+ }
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U16_COMPRESSION_MODE,
+ SMIAPP_COMPRESSION_MODE_SIMPLE_PREDICTOR);
+ if (rval) {
+ dev_err(&client->dev, "compression mode set failed\n");
+ goto out_cci_addr_fail;
+ }
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ,
+ sensor->platform_data->ext_clk / (1000000 / (1 << 8)));
+ if (rval) {
+ dev_err(&client->dev, "extclk frequency set failed\n");
+ goto out_cci_addr_fail;
+ }
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U8_CSI_LANE_MODE,
+ sensor->platform_data->lanes - 1);
+ if (rval) {
+ dev_err(&client->dev, "csi lane mode set failed\n");
+ goto out_cci_addr_fail;
+ }
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U8_FAST_STANDBY_CTRL,
+ SMIAPP_FAST_STANDBY_CTRL_IMMEDIATE);
+ if (rval) {
+ dev_err(&client->dev, "fast standby set failed\n");
+ goto out_cci_addr_fail;
+ }
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U8_CSI_SIGNALLING_MODE,
+ sensor->platform_data->csi_signalling_mode);
+ if (rval) {
+ dev_err(&client->dev, "csi signalling mode set failed\n");
+ goto out_cci_addr_fail;
+ }
+
+ /* DPHY control done by sensor based on requested link rate */
+ rval = smiapp_write(sensor, SMIAPP_REG_U8_DPHY_CTRL,
+ SMIAPP_DPHY_CTRL_UI);
+ if (rval < 0)
+ return rval;
+
+ rval = smiapp_call_quirk(sensor, post_poweron);
+ if (rval) {
+ dev_err(&client->dev, "post_poweron quirks failed\n");
+ goto out_cci_addr_fail;
+ }
+
+ /* Are we still initialising...? If yes, return here. */
+ if (!sensor->pixel_array)
+ return 0;
+
+ rval = v4l2_ctrl_handler_setup(
+ &sensor->pixel_array->ctrl_handler);
+ if (rval)
+ goto out_cci_addr_fail;
+
+ rval = v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler);
+ if (rval)
+ goto out_cci_addr_fail;
+
+ mutex_lock(&sensor->mutex);
+ rval = smiapp_update_mode(sensor);
+ mutex_unlock(&sensor->mutex);
+ if (rval < 0)
+ goto out_cci_addr_fail;
+
+ return 0;
+
+out_cci_addr_fail:
+ if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+ gpio_set_value(sensor->platform_data->xshutdown, 0);
+ if (sensor->platform_data->set_xclk)
+ sensor->platform_data->set_xclk(&sensor->src->sd, 0);
+ else
+ clk_disable(sensor->ext_clk);
+
+out_xclk_fail:
+ regulator_disable(sensor->vana);
+ return rval;
+}
+
+static void smiapp_power_off(struct smiapp_sensor *sensor)
+{
+ /*
+ * Currently power/clock to lens are enable/disabled separately
+ * but they are essentially the same signals. So if the sensor is
+ * powered off while the lens is powered on the sensor does not
+ * really see a power off and next time the cci address change
+ * will fail. So do a soft reset explicitly here.
+ */
+ if (sensor->platform_data->i2c_addr_alt)
+ smiapp_write(sensor,
+ SMIAPP_REG_U8_SOFTWARE_RESET,
+ SMIAPP_SOFTWARE_RESET);
+
+ if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+ gpio_set_value(sensor->platform_data->xshutdown, 0);
+ if (sensor->platform_data->set_xclk)
+ sensor->platform_data->set_xclk(&sensor->src->sd, 0);
+ else
+ clk_disable(sensor->ext_clk);
+ usleep_range(5000, 5000);
+ regulator_disable(sensor->vana);
+ sensor->streaming = 0;
+}
+
+static int smiapp_set_power(struct v4l2_subdev *subdev, int on)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ int ret = 0;
+
+ mutex_lock(&sensor->power_mutex);
+
+ /*
+ * If the power count is modified from 0 to != 0 or from != 0
+ * to 0, update the power state.
+ */
+ if (!sensor->power_count == !on)
+ goto out;
+
+ if (on) {
+ /* Power on and perform initialisation. */
+ ret = smiapp_power_on(sensor);
+ if (ret < 0)
+ goto out;
+ } else {
+ smiapp_power_off(sensor);
+ }
+
+ /* Update the power count. */
+ sensor->power_count += on ? 1 : -1;
+ WARN_ON(sensor->power_count < 0);
+
+out:
+ mutex_unlock(&sensor->power_mutex);
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Video stream management
+ */
+
+static int smiapp_start_streaming(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ int rval;
+
+ mutex_lock(&sensor->mutex);
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U16_CSI_DATA_FORMAT,
+ (sensor->csi_format->width << 8) |
+ sensor->csi_format->compressed);
+ if (rval)
+ goto out;
+
+ rval = smiapp_pll_configure(sensor);
+ if (rval)
+ goto out;
+
+ /* Analog crop start coordinates */
+ rval = smiapp_write(sensor, SMIAPP_REG_U16_X_ADDR_START,
+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].left);
+ if (rval < 0)
+ goto out;
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U16_Y_ADDR_START,
+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].top);
+ if (rval < 0)
+ goto out;
+
+ /* Analog crop end coordinates */
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_X_ADDR_END,
+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].left
+ + sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width - 1);
+ if (rval < 0)
+ goto out;
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_Y_ADDR_END,
+ sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].top
+ + sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height - 1);
+ if (rval < 0)
+ goto out;
+
+ /*
+ * Output from pixel array, including blanking, is set using
+ * controls below. No need to set here.
+ */
+
+ /* Digital crop */
+ if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
+ == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) {
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET,
+ sensor->scaler->crop[SMIAPP_PAD_SINK].left);
+ if (rval < 0)
+ goto out;
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET,
+ sensor->scaler->crop[SMIAPP_PAD_SINK].top);
+ if (rval < 0)
+ goto out;
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH,
+ sensor->scaler->crop[SMIAPP_PAD_SINK].width);
+ if (rval < 0)
+ goto out;
+
+ rval = smiapp_write(
+ sensor, SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT,
+ sensor->scaler->crop[SMIAPP_PAD_SINK].height);
+ if (rval < 0)
+ goto out;
+ }
+
+ /* Scaling */
+ if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+ != SMIAPP_SCALING_CAPABILITY_NONE) {
+ rval = smiapp_write(sensor, SMIAPP_REG_U16_SCALING_MODE,
+ sensor->scaling_mode);
+ if (rval < 0)
+ goto out;
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U16_SCALE_M,
+ sensor->scale_m);
+ if (rval < 0)
+ goto out;
+ }
+
+ /* Output size from sensor */
+ rval = smiapp_write(sensor, SMIAPP_REG_U16_X_OUTPUT_SIZE,
+ sensor->src->crop[SMIAPP_PAD_SRC].width);
+ if (rval < 0)
+ goto out;
+ rval = smiapp_write(sensor, SMIAPP_REG_U16_Y_OUTPUT_SIZE,
+ sensor->src->crop[SMIAPP_PAD_SRC].height);
+ if (rval < 0)
+ goto out;
+
+ if ((sensor->flash_capability &
+ (SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE |
+ SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE)) &&
+ sensor->platform_data->strobe_setup != NULL &&
+ sensor->platform_data->strobe_setup->trigger != 0) {
+ rval = smiapp_setup_flash_strobe(sensor);
+ if (rval)
+ goto out;
+ }
+
+ rval = smiapp_call_quirk(sensor, pre_streamon);
+ if (rval) {
+ dev_err(&client->dev, "pre_streamon quirks failed\n");
+ goto out;
+ }
+
+ rval = smiapp_write(sensor, SMIAPP_REG_U8_MODE_SELECT,
+ SMIAPP_MODE_SELECT_STREAMING);
+
+out:
+ mutex_unlock(&sensor->mutex);
+
+ return rval;
+}
+
+static int smiapp_stop_streaming(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ int rval;
+
+ mutex_lock(&sensor->mutex);
+ rval = smiapp_write(sensor, SMIAPP_REG_U8_MODE_SELECT,
+ SMIAPP_MODE_SELECT_SOFTWARE_STANDBY);
+ if (rval)
+ goto out;
+
+ rval = smiapp_call_quirk(sensor, post_streamoff);
+ if (rval)
+ dev_err(&client->dev, "post_streamoff quirks failed\n");
+
+out:
+ mutex_unlock(&sensor->mutex);
+ return rval;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev video operations
+ */
+
+static int smiapp_set_stream(struct v4l2_subdev *subdev, int enable)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ int rval;
+
+ if (sensor->streaming == enable)
+ return 0;
+
+ if (enable) {
+ sensor->streaming = 1;
+ rval = smiapp_start_streaming(sensor);
+ if (rval < 0)
+ sensor->streaming = 0;
+ } else {
+ rval = smiapp_stop_streaming(sensor);
+ sensor->streaming = 0;
+ }
+
+ return rval;
+}
+
+static int smiapp_enum_mbus_code(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ unsigned int i;
+ int idx = -1;
+ int rval = -EINVAL;
+
+ mutex_lock(&sensor->mutex);
+
+ dev_err(&client->dev, "subdev %s, pad %d, index %d\n",
+ subdev->name, code->pad, code->index);
+
+ if (subdev != &sensor->src->sd || code->pad != SMIAPP_PAD_SRC) {
+ if (code->index)
+ goto out;
+
+ code->code = sensor->internal_csi_format->code;
+ rval = 0;
+ goto out;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) {
+ if (sensor->mbus_frame_fmts & (1 << i))
+ idx++;
+
+ if (idx == code->index) {
+ code->code = smiapp_csi_data_formats[i].code;
+ dev_err(&client->dev, "found index %d, i %d, code %x\n",
+ code->index, i, code->code);
+ rval = 0;
+ break;
+ }
+ }
+
+out:
+ mutex_unlock(&sensor->mutex);
+
+ return rval;
+}
+
+static u32 __smiapp_get_mbus_code(struct v4l2_subdev *subdev,
+ unsigned int pad)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+
+ if (subdev == &sensor->src->sd && pad == SMIAPP_PAD_SRC)
+ return sensor->csi_format->code;
+ else
+ return sensor->internal_csi_format->code;
+}
+
+static int __smiapp_get_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+ fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad);
+ } else {
+ struct v4l2_rect *r;
+
+ if (fmt->pad == ssd->source_pad)
+ r = &ssd->crop[ssd->source_pad];
+ else
+ r = &ssd->sink_fmt;
+
+ fmt->format.code = __smiapp_get_mbus_code(subdev, fmt->pad);
+ fmt->format.width = r->width;
+ fmt->format.height = r->height;
+ }
+
+ return 0;
+}
+
+static int smiapp_get_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ int rval;
+
+ mutex_lock(&sensor->mutex);
+ rval = __smiapp_get_format(subdev, fh, fmt);
+ mutex_unlock(&sensor->mutex);
+
+ return rval;
+}
+
+static void smiapp_get_crop_compose(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_rect **crops,
+ struct v4l2_rect **comps, int which)
+{
+ struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+ unsigned int i;
+
+ if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ if (crops)
+ for (i = 0; i < subdev->entity.num_pads; i++)
+ crops[i] = &ssd->crop[i];
+ if (comps)
+ *comps = &ssd->compose;
+ } else {
+ if (crops) {
+ for (i = 0; i < subdev->entity.num_pads; i++) {
+ crops[i] = v4l2_subdev_get_try_crop(fh, i);
+ BUG_ON(!crops[i]);
+ }
+ }
+ if (comps) {
+ *comps = v4l2_subdev_get_try_compose(fh,
+ SMIAPP_PAD_SINK);
+ BUG_ON(!*comps);
+ }
+ }
+}
+
+/* Changes require propagation only on sink pad. */
+static void smiapp_propagate(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh, int which,
+ int target)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+ struct v4l2_rect *comp, *crops[SMIAPP_PADS];
+
+ smiapp_get_crop_compose(subdev, fh, crops, &comp, which);
+
+ switch (target) {
+ case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+ comp->width = crops[SMIAPP_PAD_SINK]->width;
+ comp->height = crops[SMIAPP_PAD_SINK]->height;
+ if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ if (ssd == sensor->scaler) {
+ sensor->scale_m =
+ sensor->limits[
+ SMIAPP_LIMIT_SCALER_N_MIN];
+ sensor->scaling_mode =
+ SMIAPP_SCALING_MODE_NONE;
+ } else if (ssd == sensor->binner) {
+ sensor->binning_horizontal = 1;
+ sensor->binning_vertical = 1;
+ }
+ }
+ /* Fall through */
+ case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL:
+ *crops[SMIAPP_PAD_SRC] = *comp;
+ break;
+ default:
+ BUG();
+ }
+}
+
+static const struct smiapp_csi_data_format
+*smiapp_validate_csi_data_format(struct smiapp_sensor *sensor, u32 code)
+{
+ const struct smiapp_csi_data_format *csi_format = sensor->csi_format;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) {
+ if (sensor->mbus_frame_fmts & (1 << i)
+ && smiapp_csi_data_formats[i].code == code)
+ return &smiapp_csi_data_formats[i];
+ }
+
+ return csi_format;
+}
+
+static int smiapp_set_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+ struct v4l2_rect *crops[SMIAPP_PADS];
+
+ mutex_lock(&sensor->mutex);
+
+ /*
+ * Media bus code is changeable on src subdev's source pad. On
+ * other source pads we just get format here.
+ */
+ if (fmt->pad == ssd->source_pad) {
+ u32 code = fmt->format.code;
+ int rval = __smiapp_get_format(subdev, fh, fmt);
+
+ if (!rval && subdev == &sensor->src->sd) {
+ const struct smiapp_csi_data_format *csi_format =
+ smiapp_validate_csi_data_format(sensor, code);
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ sensor->csi_format = csi_format;
+ fmt->format.code = csi_format->code;
+ }
+
+ mutex_unlock(&sensor->mutex);
+ return rval;
+ }
+
+ /* Sink pad. Width and height are changeable here. */
+ fmt->format.code = __smiapp_get_mbus_code(subdev, fmt->pad);
+ fmt->format.width &= ~1;
+ fmt->format.height &= ~1;
+
+ fmt->format.width =
+ clamp(fmt->format.width,
+ sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE],
+ sensor->limits[SMIAPP_LIMIT_MAX_X_OUTPUT_SIZE]);
+ fmt->format.height =
+ clamp(fmt->format.height,
+ sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE],
+ sensor->limits[SMIAPP_LIMIT_MAX_Y_OUTPUT_SIZE]);
+
+ smiapp_get_crop_compose(subdev, fh, crops, NULL, fmt->which);
+
+ crops[ssd->sink_pad]->left = 0;
+ crops[ssd->sink_pad]->top = 0;
+ crops[ssd->sink_pad]->width = fmt->format.width;
+ crops[ssd->sink_pad]->height = fmt->format.height;
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ ssd->sink_fmt = *crops[ssd->sink_pad];
+ smiapp_propagate(subdev, fh, fmt->which,
+ V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL);
+
+ mutex_unlock(&sensor->mutex);
+
+ return 0;
+}
+
+/*
+ * Calculate goodness of scaled image size compared to expected image
+ * size and flags provided.
+ */
+#define SCALING_GOODNESS 100000
+#define SCALING_GOODNESS_EXTREME 100000000
+static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w,
+ int h, int ask_h, u32 flags)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ int val = 0;
+
+ w &= ~1;
+ ask_w &= ~1;
+ h &= ~1;
+ ask_h &= ~1;
+
+ if (flags & V4L2_SUBDEV_SEL_FLAG_SIZE_GE) {
+ if (w < ask_w)
+ val -= SCALING_GOODNESS;
+ if (h < ask_h)
+ val -= SCALING_GOODNESS;
+ }
+
+ if (flags & V4L2_SUBDEV_SEL_FLAG_SIZE_LE) {
+ if (w > ask_w)
+ val -= SCALING_GOODNESS;
+ if (h > ask_h)
+ val -= SCALING_GOODNESS;
+ }
+
+ val -= abs(w - ask_w);
+ val -= abs(h - ask_h);
+
+ if (w < sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE])
+ val -= SCALING_GOODNESS_EXTREME;
+
+ dev_dbg(&client->dev, "w %d ask_w %d h %d ask_h %d goodness %d\n",
+ w, ask_h, h, ask_h, val);
+
+ return val;
+}
+
+static void smiapp_set_compose_binner(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel,
+ struct v4l2_rect **crops,
+ struct v4l2_rect *comp)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ unsigned int i;
+ unsigned int binh = 1, binv = 1;
+ unsigned int best = scaling_goodness(
+ subdev,
+ crops[SMIAPP_PAD_SINK]->width, sel->r.width,
+ crops[SMIAPP_PAD_SINK]->height, sel->r.height, sel->flags);
+
+ for (i = 0; i < sensor->nbinning_subtypes; i++) {
+ int this = scaling_goodness(
+ subdev,
+ crops[SMIAPP_PAD_SINK]->width
+ / sensor->binning_subtypes[i].horizontal,
+ sel->r.width,
+ crops[SMIAPP_PAD_SINK]->height
+ / sensor->binning_subtypes[i].vertical,
+ sel->r.height, sel->flags);
+
+ if (this > best) {
+ binh = sensor->binning_subtypes[i].horizontal;
+ binv = sensor->binning_subtypes[i].vertical;
+ best = this;
+ }
+ }
+ if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ sensor->binning_vertical = binv;
+ sensor->binning_horizontal = binh;
+ }
+
+ sel->r.width = (crops[SMIAPP_PAD_SINK]->width / binh) & ~1;
+ sel->r.height = (crops[SMIAPP_PAD_SINK]->height / binv) & ~1;
+}
+
+/*
+ * Calculate best scaling ratio and mode for given output resolution.
+ *
+ * Try all of these: horizontal ratio, vertical ratio and smallest
+ * size possible (horizontally).
+ *
+ * Also try whether horizontal scaler or full scaler gives a better
+ * result.
+ */
+static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel,
+ struct v4l2_rect **crops,
+ struct v4l2_rect *comp)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ u32 min, max, a, b, max_m;
+ u32 scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
+ int mode = SMIAPP_SCALING_MODE_HORIZONTAL;
+ u32 try[4];
+ u32 ntry = 0;
+ unsigned int i;
+ int best = INT_MIN;
+
+ sel->r.width = min_t(unsigned int, sel->r.width,
+ crops[SMIAPP_PAD_SINK]->width);
+ sel->r.height = min_t(unsigned int, sel->r.height,
+ crops[SMIAPP_PAD_SINK]->height);
+
+ a = crops[SMIAPP_PAD_SINK]->width
+ * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] / sel->r.width;
+ b = crops[SMIAPP_PAD_SINK]->height
+ * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] / sel->r.height;
+ max_m = crops[SMIAPP_PAD_SINK]->width
+ * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]
+ / sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE];
+
+ a = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
+ max(a, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
+ b = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
+ max(b, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
+ max_m = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
+ max(max_m, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
+
+ dev_dbg(&client->dev, "scaling: a %d b %d max_m %d\n", a, b, max_m);
+
+ min = min(max_m, min(a, b));
+ max = min(max_m, max(a, b));
+
+ try[ntry] = min;
+ ntry++;
+ if (min != max) {
+ try[ntry] = max;
+ ntry++;
+ }
+ if (max != max_m) {
+ try[ntry] = min + 1;
+ ntry++;
+ if (min != max) {
+ try[ntry] = max + 1;
+ ntry++;
+ }
+ }
+
+ for (i = 0; i < ntry; i++) {
+ int this = scaling_goodness(
+ subdev,
+ crops[SMIAPP_PAD_SINK]->width
+ / try[i]
+ * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
+ sel->r.width,
+ crops[SMIAPP_PAD_SINK]->height,
+ sel->r.height,
+ sel->flags);
+
+ dev_dbg(&client->dev, "trying factor %d (%d)\n", try[i], i);
+
+ if (this > best) {
+ scale_m = try[i];
+ mode = SMIAPP_SCALING_MODE_HORIZONTAL;
+ best = this;
+ }
+
+ if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+ == SMIAPP_SCALING_CAPABILITY_HORIZONTAL)
+ continue;
+
+ this = scaling_goodness(
+ subdev, crops[SMIAPP_PAD_SINK]->width
+ / try[i]
+ * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
+ sel->r.width,
+ crops[SMIAPP_PAD_SINK]->height
+ / try[i]
+ * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
+ sel->r.height,
+ sel->flags);
+
+ if (this > best) {
+ scale_m = try[i];
+ mode = SMIAPP_SCALING_MODE_BOTH;
+ best = this;
+ }
+ }
+
+ sel->r.width =
+ (crops[SMIAPP_PAD_SINK]->width
+ / scale_m
+ * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]) & ~1;
+ if (mode == SMIAPP_SCALING_MODE_BOTH)
+ sel->r.height =
+ (crops[SMIAPP_PAD_SINK]->height
+ / scale_m
+ * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN])
+ & ~1;
+ else
+ sel->r.height = crops[SMIAPP_PAD_SINK]->height;
+
+ if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ sensor->scale_m = scale_m;
+ sensor->scaling_mode = mode;
+ }
+}
+/* We're only called on source pads. This function sets scaling. */
+static int smiapp_set_compose(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+ struct v4l2_rect *comp, *crops[SMIAPP_PADS];
+
+ smiapp_get_crop_compose(subdev, fh, crops, &comp, sel->which);
+
+ sel->r.top = 0;
+ sel->r.left = 0;
+
+ if (ssd == sensor->binner)
+ smiapp_set_compose_binner(subdev, fh, sel, crops, comp);
+ else
+ smiapp_set_compose_scaler(subdev, fh, sel, crops, comp);
+
+ *comp = sel->r;
+ smiapp_propagate(subdev, fh, sel->which,
+ V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL);
+
+ if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ return smiapp_update_mode(sensor);
+
+ return 0;
+}
+
+static int __smiapp_sel_supported(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_selection *sel)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+
+ /* We only implement crop in three places. */
+ switch (sel->target) {
+ case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+ case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
+ if (ssd == sensor->pixel_array
+ && sel->pad == SMIAPP_PA_PAD_SRC)
+ return 0;
+ if (ssd == sensor->src
+ && sel->pad == SMIAPP_PAD_SRC)
+ return 0;
+ if (ssd == sensor->scaler
+ && sel->pad == SMIAPP_PAD_SINK
+ && sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
+ == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP)
+ return 0;
+ return -EINVAL;
+ case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL:
+ case V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS:
+ if (sel->pad == ssd->source_pad)
+ return -EINVAL;
+ if (ssd == sensor->binner)
+ return 0;
+ if (ssd == sensor->scaler
+ && sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+ != SMIAPP_SCALING_CAPABILITY_NONE)
+ return 0;
+ /* Fall through */
+ default:
+ return -EINVAL;
+ }
+}
+
+static int smiapp_set_crop(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+ struct v4l2_rect *src_size, *crops[SMIAPP_PADS];
+ struct v4l2_rect _r;
+
+ smiapp_get_crop_compose(subdev, fh, crops, NULL, sel->which);
+
+ if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ if (sel->pad == ssd->sink_pad)
+ src_size = &ssd->sink_fmt;
+ else
+ src_size = &ssd->compose;
+ } else {
+ if (sel->pad == ssd->sink_pad) {
+ _r.left = 0;
+ _r.top = 0;
+ _r.width = v4l2_subdev_get_try_format(fh, sel->pad)
+ ->width;
+ _r.height = v4l2_subdev_get_try_format(fh, sel->pad)
+ ->height;
+ src_size = &_r;
+ } else {
+ src_size =
+ v4l2_subdev_get_try_compose(
+ fh, ssd->sink_pad);
+ }
+ }
+
+ if (ssd == sensor->src && sel->pad == SMIAPP_PAD_SRC) {
+ sel->r.left = 0;
+ sel->r.top = 0;
+ }
+
+ sel->r.width = min(sel->r.width, src_size->width);
+ sel->r.height = min(sel->r.height, src_size->height);
+
+ sel->r.left = min(sel->r.left, src_size->width - sel->r.width);
+ sel->r.top = min(sel->r.top, src_size->height - sel->r.height);
+
+ *crops[sel->pad] = sel->r;
+
+ if (ssd != sensor->pixel_array && sel->pad == SMIAPP_PAD_SINK)
+ smiapp_propagate(subdev, fh, sel->which,
+ V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL);
+
+ return 0;
+}
+
+static int __smiapp_get_selection(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+ struct v4l2_rect *comp, *crops[SMIAPP_PADS];
+ struct v4l2_rect sink_fmt;
+ int ret;
+
+ ret = __smiapp_sel_supported(subdev, sel);
+ if (ret)
+ return ret;
+
+ smiapp_get_crop_compose(subdev, fh, crops, &comp, sel->which);
+
+ if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ sink_fmt = ssd->sink_fmt;
+ } else {
+ struct v4l2_mbus_framefmt *fmt =
+ v4l2_subdev_get_try_format(fh, ssd->sink_pad);
+
+ sink_fmt.left = 0;
+ sink_fmt.top = 0;
+ sink_fmt.width = fmt->width;
+ sink_fmt.height = fmt->height;
+ }
+
+ switch (sel->target) {
+ case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
+ if (ssd == sensor->pixel_array) {
+ sel->r.width =
+ sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
+ sel->r.height =
+ sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
+ } else if (sel->pad == ssd->sink_pad) {
+ sel->r = sink_fmt;
+ } else {
+ sel->r = *comp;
+ }
+ break;
+ case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+ case V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS:
+ sel->r = *crops[sel->pad];
+ break;
+ case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL:
+ sel->r = *comp;
+ break;
+ }
+
+ return 0;
+}
+
+static int smiapp_get_selection(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ int rval;
+
+ mutex_lock(&sensor->mutex);
+ rval = __smiapp_get_selection(subdev, fh, sel);
+ mutex_unlock(&sensor->mutex);
+
+ return rval;
+}
+static int smiapp_set_selection(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ int ret;
+
+ ret = __smiapp_sel_supported(subdev, sel);
+ if (ret)
+ return ret;
+
+ mutex_lock(&sensor->mutex);
+
+ sel->r.left = max(0, sel->r.left & ~1);
+ sel->r.top = max(0, sel->r.top & ~1);
+ sel->r.width = max(0, SMIAPP_ALIGN_DIM(sel->r.width, sel->flags));
+ sel->r.height = max(0, SMIAPP_ALIGN_DIM(sel->r.height, sel->flags));
+
+ sel->r.width = max_t(unsigned int,
+ sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE],
+ sel->r.width);
+ sel->r.height = max_t(unsigned int,
+ sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE],
+ sel->r.height);
+
+ switch (sel->target) {
+ case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
+ ret = smiapp_set_crop(subdev, fh, sel);
+ break;
+ case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL:
+ ret = smiapp_set_compose(subdev, fh, sel);
+ break;
+ default:
+ BUG();
+ }
+
+ mutex_unlock(&sensor->mutex);
+ return ret;
+}
+
+static int smiapp_get_skip_frames(struct v4l2_subdev *subdev, u32 *frames)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+
+ *frames = sensor->frame_skip;
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * sysfs attributes
+ */
+
+static ssize_t
+smiapp_sysfs_nvm_read(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev));
+ struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ unsigned int nbytes;
+
+ if (!sensor->dev_init_done)
+ return -EBUSY;
+
+ if (!sensor->nvm_size) {
+ /* NVM not read yet - read it now */
+ sensor->nvm_size = sensor->platform_data->nvm_size;
+ if (smiapp_set_power(subdev, 1) < 0)
+ return -ENODEV;
+ if (smiapp_read_nvm(sensor, sensor->nvm)) {
+ dev_err(&client->dev, "nvm read failed\n");
+ return -ENODEV;
+ }
+ smiapp_set_power(subdev, 0);
+ }
+ /*
+ * NVM is still way below a PAGE_SIZE, so we can safely
+ * assume this for now.
+ */
+ nbytes = min_t(unsigned int, sensor->nvm_size, PAGE_SIZE);
+ memcpy(buf, sensor->nvm, nbytes);
+
+ return nbytes;
+}
+static DEVICE_ATTR(nvm, S_IRUGO, smiapp_sysfs_nvm_read, NULL);
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev core operations
+ */
+
+static int smiapp_identify_module(struct v4l2_subdev *subdev)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ struct smiapp_module_info *minfo = &sensor->minfo;
+ unsigned int i;
+ int rval = 0;
+
+ minfo->name = SMIAPP_NAME;
+
+ /* Module info */
+ rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_MANUFACTURER_ID,
+ &minfo->manufacturer_id);
+ if (!rval)
+ rval = smiapp_read_8only(sensor, SMIAPP_REG_U16_MODEL_ID,
+ &minfo->model_id);
+ if (!rval)
+ rval = smiapp_read_8only(sensor,
+ SMIAPP_REG_U8_REVISION_NUMBER_MAJOR,
+ &minfo->revision_number_major);
+ if (!rval)
+ rval = smiapp_read_8only(sensor,
+ SMIAPP_REG_U8_REVISION_NUMBER_MINOR,
+ &minfo->revision_number_minor);
+ if (!rval)
+ rval = smiapp_read_8only(sensor,
+ SMIAPP_REG_U8_MODULE_DATE_YEAR,
+ &minfo->module_year);
+ if (!rval)
+ rval = smiapp_read_8only(sensor,
+ SMIAPP_REG_U8_MODULE_DATE_MONTH,
+ &minfo->module_month);
+ if (!rval)
+ rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_MODULE_DATE_DAY,
+ &minfo->module_day);
+
+ /* Sensor info */
+ if (!rval)
+ rval = smiapp_read_8only(sensor,
+ SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID,
+ &minfo->sensor_manufacturer_id);
+ if (!rval)
+ rval = smiapp_read_8only(sensor,
+ SMIAPP_REG_U16_SENSOR_MODEL_ID,
+ &minfo->sensor_model_id);
+ if (!rval)
+ rval = smiapp_read_8only(sensor,
+ SMIAPP_REG_U8_SENSOR_REVISION_NUMBER,
+ &minfo->sensor_revision_number);
+ if (!rval)
+ rval = smiapp_read_8only(sensor,
+ SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION,
+ &minfo->sensor_firmware_version);
+
+ /* SMIA */
+ if (!rval)
+ rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_SMIA_VERSION,
+ &minfo->smia_version);
+ if (!rval)
+ rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_SMIAPP_VERSION,
+ &minfo->smiapp_version);
+
+ if (rval) {
+ dev_err(&client->dev, "sensor detection failed\n");
+ return -ENODEV;
+ }
+
+ dev_dbg(&client->dev, "module 0x%2.2x-0x%4.4x\n",
+ minfo->manufacturer_id, minfo->model_id);
+
+ dev_dbg(&client->dev,
+ "module revision 0x%2.2x-0x%2.2x date %2.2d-%2.2d-%2.2d\n",
+ minfo->revision_number_major, minfo->revision_number_minor,
+ minfo->module_year, minfo->module_month, minfo->module_day);
+
+ dev_dbg(&client->dev, "sensor 0x%2.2x-0x%4.4x\n",
+ minfo->sensor_manufacturer_id, minfo->sensor_model_id);
+
+ dev_dbg(&client->dev,
+ "sensor revision 0x%2.2x firmware version 0x%2.2x\n",
+ minfo->sensor_revision_number, minfo->sensor_firmware_version);
+
+ dev_dbg(&client->dev, "smia version %2.2d smiapp version %2.2d\n",
+ minfo->smia_version, minfo->smiapp_version);
+
+ /*
+ * Some modules have bad data in the lvalues below. Hope the
+ * rvalues have better stuff. The lvalues are module
+ * parameters whereas the rvalues are sensor parameters.
+ */
+ if (!minfo->manufacturer_id && !minfo->model_id) {
+ minfo->manufacturer_id = minfo->sensor_manufacturer_id;
+ minfo->model_id = minfo->sensor_model_id;
+ minfo->revision_number_major = minfo->sensor_revision_number;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(smiapp_module_idents); i++) {
+ if (smiapp_module_idents[i].manufacturer_id
+ != minfo->manufacturer_id)
+ continue;
+ if (smiapp_module_idents[i].model_id != minfo->model_id)
+ continue;
+ if (smiapp_module_idents[i].flags
+ & SMIAPP_MODULE_IDENT_FLAG_REV_LE) {
+ if (smiapp_module_idents[i].revision_number_major
+ < minfo->revision_number_major)
+ continue;
+ } else {
+ if (smiapp_module_idents[i].revision_number_major
+ != minfo->revision_number_major)
+ continue;
+ }
+
+ minfo->name = smiapp_module_idents[i].name;
+ minfo->quirk = smiapp_module_idents[i].quirk;
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(smiapp_module_idents))
+ dev_warn(&client->dev,
+ "no quirks for this module; let's hope it's fully compliant\n");
+
+ dev_dbg(&client->dev, "the sensor is called %s, ident %2.2x%4.4x%2.2x\n",
+ minfo->name, minfo->manufacturer_id, minfo->model_id,
+ minfo->revision_number_major);
+
+ strlcpy(subdev->name, sensor->minfo.name, sizeof(subdev->name));
+
+ return 0;
+}
+
+static const struct v4l2_subdev_ops smiapp_ops;
+static const struct v4l2_subdev_internal_ops smiapp_internal_ops;
+static const struct media_entity_operations smiapp_entity_ops;
+
+static int smiapp_registered(struct v4l2_subdev *subdev)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ struct smiapp_subdev *last = NULL;
+ u32 tmp;
+ unsigned int i;
+ int rval;
+
+ sensor->vana = regulator_get(&client->dev, "VANA");
+ if (IS_ERR(sensor->vana)) {
+ dev_err(&client->dev, "could not get regulator for vana\n");
+ return -ENODEV;
+ }
+
+ if (!sensor->platform_data->set_xclk) {
+ sensor->ext_clk = clk_get(&client->dev,
+ sensor->platform_data->ext_clk_name);
+ if (IS_ERR(sensor->ext_clk)) {
+ dev_err(&client->dev, "could not get clock %s\n",
+ sensor->platform_data->ext_clk_name);
+ rval = -ENODEV;
+ goto out_clk_get;
+ }
+
+ rval = clk_set_rate(sensor->ext_clk,
+ sensor->platform_data->ext_clk);
+ if (rval < 0) {
+ dev_err(&client->dev,
+ "unable to set clock %s freq to %u\n",
+ sensor->platform_data->ext_clk_name,
+ sensor->platform_data->ext_clk);
+ rval = -ENODEV;
+ goto out_clk_set_rate;
+ }
+ }
+
+ if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN) {
+ if (gpio_request_one(sensor->platform_data->xshutdown, 0,
+ "SMIA++ xshutdown") != 0) {
+ dev_err(&client->dev,
+ "unable to acquire reset gpio %d\n",
+ sensor->platform_data->xshutdown);
+ rval = -ENODEV;
+ goto out_clk_set_rate;
+ }
+ }
+
+ rval = smiapp_power_on(sensor);
+ if (rval) {
+ rval = -ENODEV;
+ goto out_smiapp_power_on;
+ }
+
+ rval = smiapp_identify_module(subdev);
+ if (rval) {
+ rval = -ENODEV;
+ goto out_power_off;
+ }
+
+ rval = smiapp_get_all_limits(sensor);
+ if (rval) {
+ rval = -ENODEV;
+ goto out_power_off;
+ }
+
+ /*
+ * Handle Sensor Module orientation on the board.
+ *
+ * The application of H-FLIP and V-FLIP on the sensor is modified by
+ * the sensor orientation on the board.
+ *
+ * For SMIAPP_BOARD_SENSOR_ORIENT_180 the default behaviour is to set
+ * both H-FLIP and V-FLIP for normal operation which also implies
+ * that a set/unset operation for user space HFLIP and VFLIP v4l2
+ * controls will need to be internally inverted.
+ *
+ * Rotation also changes the bayer pattern.
+ */
+ if (sensor->platform_data->module_board_orient ==
+ SMIAPP_MODULE_BOARD_ORIENT_180)
+ sensor->hvflip_inv_mask = SMIAPP_IMAGE_ORIENTATION_HFLIP |
+ SMIAPP_IMAGE_ORIENTATION_VFLIP;
+
+ rval = smiapp_get_mbus_formats(sensor);
+ if (rval) {
+ rval = -ENODEV;
+ goto out_power_off;
+ }
+
+ if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY]) {
+ u32 val;
+
+ rval = smiapp_read(sensor,
+ SMIAPP_REG_U8_BINNING_SUBTYPES, &val);
+ if (rval < 0) {
+ rval = -ENODEV;
+ goto out_power_off;
+ }
+ sensor->nbinning_subtypes = min_t(u8, val,
+ SMIAPP_BINNING_SUBTYPES);
+
+ for (i = 0; i < sensor->nbinning_subtypes; i++) {
+ rval = smiapp_read(
+ sensor, SMIAPP_REG_U8_BINNING_TYPE_n(i), &val);
+ if (rval < 0) {
+ rval = -ENODEV;
+ goto out_power_off;
+ }
+ sensor->binning_subtypes[i] =
+ *(struct smiapp_binning_subtype *)&val;
+
+ dev_dbg(&client->dev, "binning %xx%x\n",
+ sensor->binning_subtypes[i].horizontal,
+ sensor->binning_subtypes[i].vertical);
+ }
+ }
+ sensor->binning_horizontal = 1;
+ sensor->binning_vertical = 1;
+
+ /* SMIA++ NVM initialization - it will be read from the sensor
+ * when it is first requested by userspace.
+ */
+ if (sensor->minfo.smiapp_version && sensor->platform_data->nvm_size) {
+ sensor->nvm = kzalloc(sensor->platform_data->nvm_size,
+ GFP_KERNEL);
+ if (sensor->nvm == NULL) {
+ dev_err(&client->dev, "nvm buf allocation failed\n");
+ rval = -ENOMEM;
+ goto out_power_off;
+ }
+
+ if (device_create_file(&client->dev, &dev_attr_nvm) != 0) {
+ dev_err(&client->dev, "sysfs nvm entry failed\n");
+ rval = -EBUSY;
+ goto out_power_off;
+ }
+ }
+
+ 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] ||
+ !sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV] ||
+ !sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV]) {
+ sensor->minfo.smiapp_profile = SMIAPP_PROFILE_0;
+ } else if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+ != SMIAPP_SCALING_CAPABILITY_NONE) {
+ if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+ == SMIAPP_SCALING_CAPABILITY_HORIZONTAL)
+ sensor->minfo.smiapp_profile = SMIAPP_PROFILE_1;
+ else
+ sensor->minfo.smiapp_profile = SMIAPP_PROFILE_2;
+ sensor->scaler = &sensor->ssds[sensor->ssds_used];
+ sensor->ssds_used++;
+ } else if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
+ == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) {
+ sensor->scaler = &sensor->ssds[sensor->ssds_used];
+ sensor->ssds_used++;
+ }
+ sensor->binner = &sensor->ssds[sensor->ssds_used];
+ sensor->ssds_used++;
+ sensor->pixel_array = &sensor->ssds[sensor->ssds_used];
+ sensor->ssds_used++;
+
+ sensor->scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
+
+ for (i = 0; i < SMIAPP_SUBDEVS; i++) {
+ struct {
+ struct smiapp_subdev *ssd;
+ char *name;
+ } const __this[] = {
+ { sensor->scaler, "scaler", },
+ { sensor->binner, "binner", },
+ { sensor->pixel_array, "pixel array", },
+ }, *_this = &__this[i];
+ struct smiapp_subdev *this = _this->ssd;
+
+ if (!this)
+ continue;
+
+ if (this != sensor->src)
+ v4l2_subdev_init(&this->sd, &smiapp_ops);
+
+ this->sensor = sensor;
+
+ if (this == sensor->pixel_array) {
+ this->npads = 1;
+ } else {
+ this->npads = 2;
+ this->source_pad = 1;
+ }
+
+ snprintf(this->sd.name,
+ sizeof(this->sd.name), "%s %s",
+ sensor->minfo.name, _this->name);
+
+ this->sink_fmt.width =
+ sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
+ this->sink_fmt.height =
+ sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
+ this->compose.width = this->sink_fmt.width;
+ this->compose.height = this->sink_fmt.height;
+ this->crop[this->source_pad] = this->compose;
+ this->pads[this->source_pad].flags = MEDIA_PAD_FL_SOURCE;
+ if (this != sensor->pixel_array) {
+ this->crop[this->sink_pad] = this->compose;
+ this->pads[this->sink_pad].flags = MEDIA_PAD_FL_SINK;
+ }
+
+ this->sd.entity.ops = &smiapp_entity_ops;
+
+ if (last == NULL) {
+ last = this;
+ continue;
+ }
+
+ this->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ this->sd.internal_ops = &smiapp_internal_ops;
+ this->sd.owner = NULL;
+ v4l2_set_subdevdata(&this->sd, client);
+
+ rval = media_entity_init(&this->sd.entity,
+ this->npads, this->pads, 0);
+ if (rval) {
+ dev_err(&client->dev,
+ "media_entity_init failed\n");
+ goto out_nvm_release;
+ }
+
+ rval = media_entity_create_link(&this->sd.entity,
+ this->source_pad,
+ &last->sd.entity,
+ last->sink_pad,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+ if (rval) {
+ dev_err(&client->dev,
+ "media_entity_create_link failed\n");
+ goto out_nvm_release;
+ }
+
+ rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev,
+ &this->sd);
+ if (rval) {
+ dev_err(&client->dev,
+ "v4l2_device_register_subdev failed\n");
+ goto out_nvm_release;
+ }
+
+ last = this;
+ }
+
+ dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile);
+
+ sensor->pixel_array->sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
+
+ /* final steps */
+ smiapp_read_frame_fmt(sensor);
+ rval = smiapp_init_controls(sensor);
+ if (rval < 0)
+ goto out_nvm_release;
+
+ rval = smiapp_update_mode(sensor);
+ if (rval) {
+ dev_err(&client->dev, "update mode failed\n");
+ goto out_nvm_release;
+ }
+
+ sensor->streaming = false;
+ sensor->dev_init_done = true;
+
+ /* check flash capability */
+ rval = smiapp_read(sensor, SMIAPP_REG_U8_FLASH_MODE_CAPABILITY, &tmp);
+ sensor->flash_capability = tmp;
+ if (rval)
+ goto out_nvm_release;
+
+ smiapp_power_off(sensor);
+
+ return 0;
+
+out_nvm_release:
+ device_remove_file(&client->dev, &dev_attr_nvm);
+
+out_power_off:
+ kfree(sensor->nvm);
+ sensor->nvm = NULL;
+ smiapp_power_off(sensor);
+
+out_smiapp_power_on:
+ if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+ gpio_free(sensor->platform_data->xshutdown);
+
+out_clk_set_rate:
+ clk_put(sensor->ext_clk);
+ sensor->ext_clk = NULL;
+
+out_clk_get:
+ regulator_put(sensor->vana);
+ sensor->vana = NULL;
+ return rval;
+}
+
+static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ struct smiapp_subdev *ssd = to_smiapp_subdev(sd);
+ struct smiapp_sensor *sensor = ssd->sensor;
+ u32 mbus_code =
+ smiapp_csi_data_formats[smiapp_pixel_order(sensor)].code;
+ unsigned int i;
+
+ mutex_lock(&sensor->mutex);
+
+ for (i = 0; i < ssd->npads; i++) {
+ struct v4l2_mbus_framefmt *try_fmt =
+ v4l2_subdev_get_try_format(fh, i);
+ struct v4l2_rect *try_crop = v4l2_subdev_get_try_crop(fh, i);
+ struct v4l2_rect *try_comp;
+
+ try_fmt->width = sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
+ try_fmt->height = sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
+ try_fmt->code = mbus_code;
+
+ try_crop->top = 0;
+ try_crop->left = 0;
+ try_crop->width = try_fmt->width;
+ try_crop->height = try_fmt->height;
+
+ if (ssd != sensor->pixel_array)
+ continue;
+
+ try_comp = v4l2_subdev_get_try_compose(fh, i);
+ *try_comp = *try_crop;
+ }
+
+ mutex_unlock(&sensor->mutex);
+
+ return smiapp_set_power(sd, 1);
+}
+
+static int smiapp_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ return smiapp_set_power(sd, 0);
+}
+
+static const struct v4l2_subdev_video_ops smiapp_video_ops = {
+ .s_stream = smiapp_set_stream,
+};
+
+static const struct v4l2_subdev_core_ops smiapp_core_ops = {
+ .s_power = smiapp_set_power,
+};
+
+static const struct v4l2_subdev_pad_ops smiapp_pad_ops = {
+ .enum_mbus_code = smiapp_enum_mbus_code,
+ .get_fmt = smiapp_get_format,
+ .set_fmt = smiapp_set_format,
+ .get_selection = smiapp_get_selection,
+ .set_selection = smiapp_set_selection,
+};
+
+static const struct v4l2_subdev_sensor_ops smiapp_sensor_ops = {
+ .g_skip_frames = smiapp_get_skip_frames,
+};
+
+static const struct v4l2_subdev_ops smiapp_ops = {
+ .core = &smiapp_core_ops,
+ .video = &smiapp_video_ops,
+ .pad = &smiapp_pad_ops,
+ .sensor = &smiapp_sensor_ops,
+};
+
+static const struct media_entity_operations smiapp_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static const struct v4l2_subdev_internal_ops smiapp_internal_src_ops = {
+ .registered = smiapp_registered,
+ .open = smiapp_open,
+ .close = smiapp_close,
+};
+
+static const struct v4l2_subdev_internal_ops smiapp_internal_ops = {
+ .open = smiapp_open,
+ .close = smiapp_close,
+};
+
+/* -----------------------------------------------------------------------------
+ * I2C Driver
+ */
+
+#ifdef CONFIG_PM
+
+static int smiapp_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ bool streaming;
+
+ BUG_ON(mutex_is_locked(&sensor->mutex));
+
+ if (sensor->power_count == 0)
+ return 0;
+
+ if (sensor->streaming)
+ smiapp_stop_streaming(sensor);
+
+ streaming = sensor->streaming;
+
+ smiapp_power_off(sensor);
+
+ /* save state for resume */
+ sensor->streaming = streaming;
+
+ return 0;
+}
+
+static int smiapp_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ int rval;
+
+ if (sensor->power_count == 0)
+ return 0;
+
+ rval = smiapp_power_on(sensor);
+ if (rval)
+ return rval;
+
+ if (sensor->streaming)
+ rval = smiapp_start_streaming(sensor);
+
+ return rval;
+}
+
+#else
+
+#define smiapp_suspend NULL
+#define smiapp_resume NULL
+
+#endif /* CONFIG_PM */
+
+static int smiapp_probe(struct i2c_client *client,
+ const struct i2c_device_id *devid)
+{
+ struct smiapp_sensor *sensor;
+ int rval;
+
+ if (client->dev.platform_data == NULL)
+ return -ENODEV;
+
+ sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
+ if (sensor == NULL)
+ return -ENOMEM;
+
+ sensor->platform_data = client->dev.platform_data;
+ mutex_init(&sensor->mutex);
+ mutex_init(&sensor->power_mutex);
+ sensor->src = &sensor->ssds[sensor->ssds_used];
+
+ v4l2_i2c_subdev_init(&sensor->src->sd, client, &smiapp_ops);
+ sensor->src->sd.internal_ops = &smiapp_internal_src_ops;
+ sensor->src->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sensor->src->sensor = sensor;
+
+ sensor->src->pads[0].flags = MEDIA_PAD_FL_SOURCE;
+ rval = media_entity_init(&sensor->src->sd.entity, 2,
+ sensor->src->pads, 0);
+ if (rval < 0)
+ kfree(sensor);
+
+ return rval;
+}
+
+static int __exit smiapp_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ unsigned int i;
+
+ if (sensor->power_count) {
+ if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+ gpio_set_value(sensor->platform_data->xshutdown, 0);
+ if (sensor->platform_data->set_xclk)
+ sensor->platform_data->set_xclk(&sensor->src->sd, 0);
+ else
+ clk_disable(sensor->ext_clk);
+ sensor->power_count = 0;
+ }
+
+ if (sensor->nvm) {
+ device_remove_file(&client->dev, &dev_attr_nvm);
+ kfree(sensor->nvm);
+ }
+
+ for (i = 0; i < sensor->ssds_used; i++) {
+ media_entity_cleanup(&sensor->ssds[i].sd.entity);
+ v4l2_device_unregister_subdev(&sensor->ssds[i].sd);
+ }
+ smiapp_free_controls(sensor);
+ if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+ gpio_free(sensor->platform_data->xshutdown);
+ if (sensor->ext_clk)
+ clk_put(sensor->ext_clk);
+ if (sensor->vana)
+ regulator_put(sensor->vana);
+
+ kfree(sensor);
+
+ return 0;
+}
+
+static const struct i2c_device_id smiapp_id_table[] = {
+ { SMIAPP_NAME, 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, smiapp_id_table);
+
+static const struct dev_pm_ops smiapp_pm_ops = {
+ .suspend = smiapp_suspend,
+ .resume = smiapp_resume,
+};
+
+static struct i2c_driver smiapp_i2c_driver = {
+ .driver = {
+ .name = SMIAPP_NAME,
+ .pm = &smiapp_pm_ops,
+ },
+ .probe = smiapp_probe,
+ .remove = __exit_p(smiapp_remove),
+ .id_table = smiapp_id_table,
+};
+
+module_i2c_driver(smiapp_i2c_driver);
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>");
+MODULE_DESCRIPTION("Generic SMIA/SMIA++ camera module driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/smiapp/smiapp-limits.c b/drivers/media/video/smiapp/smiapp-limits.c
new file mode 100644
index 000000000000..0800e095724e
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-limits.c
@@ -0,0 +1,132 @@
+/*
+ * drivers/media/video/smiapp/smiapp-limits.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "smiapp.h"
+
+struct smiapp_reg_limits smiapp_reg_limits[] = {
+ { SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY, "analogue_gain_capability" }, /* 0 */
+ { SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN, "analogue_gain_code_min" },
+ { SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX, "analogue_gain_code_max" },
+ { SMIAPP_REG_U8_THS_ZERO_MIN, "ths_zero_min" },
+ { SMIAPP_REG_U8_TCLK_TRAIL_MIN, "tclk_trail_min" },
+ { SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY, "integration_time_capability" }, /* 5 */
+ { SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN, "coarse_integration_time_min" },
+ { SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN, "coarse_integration_time_max_margin" },
+ { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN, "fine_integration_time_min" },
+ { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN, "fine_integration_time_max_margin" },
+ { SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY, "digital_gain_capability" }, /* 10 */
+ { SMIAPP_REG_U16_DIGITAL_GAIN_MIN, "digital_gain_min" },
+ { SMIAPP_REG_U16_DIGITAL_GAIN_MAX, "digital_gain_max" },
+ { SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ, "min_ext_clk_freq_hz" },
+ { SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ, "max_ext_clk_freq_hz" },
+ { SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV, "min_pre_pll_clk_div" }, /* 15 */
+ { SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV, "max_pre_pll_clk_div" },
+ { SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ, "min_pll_ip_freq_hz" },
+ { SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ, "max_pll_ip_freq_hz" },
+ { SMIAPP_REG_U16_MIN_PLL_MULTIPLIER, "min_pll_multiplier" },
+ { SMIAPP_REG_U16_MAX_PLL_MULTIPLIER, "max_pll_multiplier" }, /* 20 */
+ { SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ, "min_pll_op_freq_hz" },
+ { SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ, "max_pll_op_freq_hz" },
+ { SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV, "min_vt_sys_clk_div" },
+ { SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV, "max_vt_sys_clk_div" },
+ { SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ, "min_vt_sys_clk_freq_hz" }, /* 25 */
+ { SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ, "max_vt_sys_clk_freq_hz" },
+ { SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ, "min_vt_pix_clk_freq_hz" },
+ { SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ, "max_vt_pix_clk_freq_hz" },
+ { SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV, "min_vt_pix_clk_div" },
+ { SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV, "max_vt_pix_clk_div" }, /* 30 */
+ { SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES, "min_frame_length_lines" },
+ { SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES, "max_frame_length_lines" },
+ { SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK, "min_line_length_pck" },
+ { SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK, "max_line_length_pck" },
+ { SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK, "min_line_blanking_pck" }, /* 35 */
+ { SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES, "min_frame_blanking_lines" },
+ { SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE, "min_line_length_pck_step_size" },
+ { SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV, "min_op_sys_clk_div" },
+ { SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV, "max_op_sys_clk_div" },
+ { SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ, "min_op_sys_clk_freq_hz" }, /* 40 */
+ { SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ, "max_op_sys_clk_freq_hz" },
+ { SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV, "min_op_pix_clk_div" },
+ { SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV, "max_op_pix_clk_div" },
+ { SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ, "min_op_pix_clk_freq_hz" },
+ { SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ, "max_op_pix_clk_freq_hz" }, /* 45 */
+ { SMIAPP_REG_U16_X_ADDR_MIN, "x_addr_min" },
+ { SMIAPP_REG_U16_Y_ADDR_MIN, "y_addr_min" },
+ { SMIAPP_REG_U16_X_ADDR_MAX, "x_addr_max" },
+ { SMIAPP_REG_U16_Y_ADDR_MAX, "y_addr_max" },
+ { SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE, "min_x_output_size" }, /* 50 */
+ { SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE, "min_y_output_size" },
+ { SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE, "max_x_output_size" },
+ { SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE, "max_y_output_size" },
+ { SMIAPP_REG_U16_MIN_EVEN_INC, "min_even_inc" },
+ { SMIAPP_REG_U16_MAX_EVEN_INC, "max_even_inc" }, /* 55 */
+ { SMIAPP_REG_U16_MIN_ODD_INC, "min_odd_inc" },
+ { SMIAPP_REG_U16_MAX_ODD_INC, "max_odd_inc" },
+ { SMIAPP_REG_U16_SCALING_CAPABILITY, "scaling_capability" },
+ { SMIAPP_REG_U16_SCALER_M_MIN, "scaler_m_min" },
+ { SMIAPP_REG_U16_SCALER_M_MAX, "scaler_m_max" }, /* 60 */
+ { SMIAPP_REG_U16_SCALER_N_MIN, "scaler_n_min" },
+ { SMIAPP_REG_U16_SCALER_N_MAX, "scaler_n_max" },
+ { SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY, "spatial_sampling_capability" },
+ { SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY, "digital_crop_capability" },
+ { SMIAPP_REG_U16_COMPRESSION_CAPABILITY, "compression_capability" }, /* 65 */
+ { SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY, "fifo_support_capability" },
+ { SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY, "dphy_ctrl_capability" },
+ { SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY, "csi_lane_mode_capability" },
+ { SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY, "csi_signalling_mode_capability" },
+ { SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY, "fast_standby_capability" }, /* 70 */
+ { SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY, "cci_address_control_capability" },
+ { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS, "max_per_lane_bitrate_1_lane_mode_mbps" },
+ { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS, "max_per_lane_bitrate_2_lane_mode_mbps" },
+ { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS, "max_per_lane_bitrate_3_lane_mode_mbps" },
+ { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS, "max_per_lane_bitrate_4_lane_mode_mbps" }, /* 75 */
+ { SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY, "temp_sensor_capability" },
+ { SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN, "min_frame_length_lines_bin" },
+ { SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN, "max_frame_length_lines_bin" },
+ { SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN, "min_line_length_pck_bin" },
+ { SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN, "max_line_length_pck_bin" }, /* 80 */
+ { SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN, "min_line_blanking_pck_bin" },
+ { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN, "fine_integration_time_min_bin" },
+ { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN, "fine_integration_time_max_margin_bin" },
+ { SMIAPP_REG_U8_BINNING_CAPABILITY, "binning_capability" },
+ { SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY, "binning_weighting_capability" }, /* 85 */
+ { SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY, "data_transfer_if_capability" },
+ { SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY, "shading_correction_capability" },
+ { SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY, "green_imbalance_capability" },
+ { SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY, "black_level_capability" },
+ { SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY, "module_specific_correction_capability" }, /* 90 */
+ { SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY, "defect_correction_capability" },
+ { SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2, "defect_correction_capability_2" },
+ { SMIAPP_REG_U8_EDOF_CAPABILITY, "edof_capability" },
+ { SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY, "colour_feedback_capability" },
+ { SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY, "estimation_mode_capability" }, /* 95 */
+ { SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY, "estimation_zone_capability" },
+ { SMIAPP_REG_U16_CAPABILITY_TRDY_MIN, "capability_trdy_min" },
+ { SMIAPP_REG_U8_FLASH_MODE_CAPABILITY, "flash_mode_capability" },
+ { SMIAPP_REG_U8_ACTUATOR_CAPABILITY, "actuator_capability" },
+ { SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1, "bracketing_lut_capability_1" }, /* 100 */
+ { SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2, "bracketing_lut_capability_2" },
+ { SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP, "analogue_gain_code_step" },
+ { 0, NULL },
+};
diff --git a/drivers/media/video/smiapp/smiapp-limits.h b/drivers/media/video/smiapp/smiapp-limits.h
new file mode 100644
index 000000000000..7f4836bb78db
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-limits.h
@@ -0,0 +1,128 @@
+/*
+ * drivers/media/video/smiapp/smiapp-limits.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#define SMIAPP_LIMIT_ANALOGUE_GAIN_CAPABILITY 0
+#define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN 1
+#define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX 2
+#define SMIAPP_LIMIT_THS_ZERO_MIN 3
+#define SMIAPP_LIMIT_TCLK_TRAIL_MIN 4
+#define SMIAPP_LIMIT_INTEGRATION_TIME_CAPABILITY 5
+#define SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MIN 6
+#define SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN 7
+#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN 8
+#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN 9
+#define SMIAPP_LIMIT_DIGITAL_GAIN_CAPABILITY 10
+#define SMIAPP_LIMIT_DIGITAL_GAIN_MIN 11
+#define SMIAPP_LIMIT_DIGITAL_GAIN_MAX 12
+#define SMIAPP_LIMIT_MIN_EXT_CLK_FREQ_HZ 13
+#define SMIAPP_LIMIT_MAX_EXT_CLK_FREQ_HZ 14
+#define SMIAPP_LIMIT_MIN_PRE_PLL_CLK_DIV 15
+#define SMIAPP_LIMIT_MAX_PRE_PLL_CLK_DIV 16
+#define SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ 17
+#define SMIAPP_LIMIT_MAX_PLL_IP_FREQ_HZ 18
+#define SMIAPP_LIMIT_MIN_PLL_MULTIPLIER 19
+#define SMIAPP_LIMIT_MAX_PLL_MULTIPLIER 20
+#define SMIAPP_LIMIT_MIN_PLL_OP_FREQ_HZ 21
+#define SMIAPP_LIMIT_MAX_PLL_OP_FREQ_HZ 22
+#define SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV 23
+#define SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV 24
+#define SMIAPP_LIMIT_MIN_VT_SYS_CLK_FREQ_HZ 25
+#define SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ 26
+#define SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ 27
+#define SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ 28
+#define SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV 29
+#define SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV 30
+#define SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES 31
+#define SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES 32
+#define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK 33
+#define SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK 34
+#define SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK 35
+#define SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES 36
+#define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_STEP_SIZE 37
+#define SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV 38
+#define SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV 39
+#define SMIAPP_LIMIT_MIN_OP_SYS_CLK_FREQ_HZ 40
+#define SMIAPP_LIMIT_MAX_OP_SYS_CLK_FREQ_HZ 41
+#define SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV 42
+#define SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV 43
+#define SMIAPP_LIMIT_MIN_OP_PIX_CLK_FREQ_HZ 44
+#define SMIAPP_LIMIT_MAX_OP_PIX_CLK_FREQ_HZ 45
+#define SMIAPP_LIMIT_X_ADDR_MIN 46
+#define SMIAPP_LIMIT_Y_ADDR_MIN 47
+#define SMIAPP_LIMIT_X_ADDR_MAX 48
+#define SMIAPP_LIMIT_Y_ADDR_MAX 49
+#define SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE 50
+#define SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE 51
+#define SMIAPP_LIMIT_MAX_X_OUTPUT_SIZE 52
+#define SMIAPP_LIMIT_MAX_Y_OUTPUT_SIZE 53
+#define SMIAPP_LIMIT_MIN_EVEN_INC 54
+#define SMIAPP_LIMIT_MAX_EVEN_INC 55
+#define SMIAPP_LIMIT_MIN_ODD_INC 56
+#define SMIAPP_LIMIT_MAX_ODD_INC 57
+#define SMIAPP_LIMIT_SCALING_CAPABILITY 58
+#define SMIAPP_LIMIT_SCALER_M_MIN 59
+#define SMIAPP_LIMIT_SCALER_M_MAX 60
+#define SMIAPP_LIMIT_SCALER_N_MIN 61
+#define SMIAPP_LIMIT_SCALER_N_MAX 62
+#define SMIAPP_LIMIT_SPATIAL_SAMPLING_CAPABILITY 63
+#define SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY 64
+#define SMIAPP_LIMIT_COMPRESSION_CAPABILITY 65
+#define SMIAPP_LIMIT_FIFO_SUPPORT_CAPABILITY 66
+#define SMIAPP_LIMIT_DPHY_CTRL_CAPABILITY 67
+#define SMIAPP_LIMIT_CSI_LANE_MODE_CAPABILITY 68
+#define SMIAPP_LIMIT_CSI_SIGNALLING_MODE_CAPABILITY 69
+#define SMIAPP_LIMIT_FAST_STANDBY_CAPABILITY 70
+#define SMIAPP_LIMIT_CCI_ADDRESS_CONTROL_CAPABILITY 71
+#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS 72
+#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS 73
+#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS 74
+#define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS 75
+#define SMIAPP_LIMIT_TEMP_SENSOR_CAPABILITY 76
+#define SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN 77
+#define SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN 78
+#define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN 79
+#define SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN 80
+#define SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN 81
+#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN_BIN 82
+#define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN 83
+#define SMIAPP_LIMIT_BINNING_CAPABILITY 84
+#define SMIAPP_LIMIT_BINNING_WEIGHTING_CAPABILITY 85
+#define SMIAPP_LIMIT_DATA_TRANSFER_IF_CAPABILITY 86
+#define SMIAPP_LIMIT_SHADING_CORRECTION_CAPABILITY 87
+#define SMIAPP_LIMIT_GREEN_IMBALANCE_CAPABILITY 88
+#define SMIAPP_LIMIT_BLACK_LEVEL_CAPABILITY 89
+#define SMIAPP_LIMIT_MODULE_SPECIFIC_CORRECTION_CAPABILITY 90
+#define SMIAPP_LIMIT_DEFECT_CORRECTION_CAPABILITY 91
+#define SMIAPP_LIMIT_DEFECT_CORRECTION_CAPABILITY_2 92
+#define SMIAPP_LIMIT_EDOF_CAPABILITY 93
+#define SMIAPP_LIMIT_COLOUR_FEEDBACK_CAPABILITY 94
+#define SMIAPP_LIMIT_ESTIMATION_MODE_CAPABILITY 95
+#define SMIAPP_LIMIT_ESTIMATION_ZONE_CAPABILITY 96
+#define SMIAPP_LIMIT_CAPABILITY_TRDY_MIN 97
+#define SMIAPP_LIMIT_FLASH_MODE_CAPABILITY 98
+#define SMIAPP_LIMIT_ACTUATOR_CAPABILITY 99
+#define SMIAPP_LIMIT_BRACKETING_LUT_CAPABILITY_1 100
+#define SMIAPP_LIMIT_BRACKETING_LUT_CAPABILITY_2 101
+#define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_STEP 102
+#define SMIAPP_LIMIT_LAST 103
diff --git a/drivers/media/video/smiapp/smiapp-quirk.c b/drivers/media/video/smiapp/smiapp-quirk.c
new file mode 100644
index 000000000000..55e87950dcea
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-quirk.c
@@ -0,0 +1,306 @@
+/*
+ * drivers/media/video/smiapp/smiapp-quirk.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/delay.h>
+
+#include "smiapp.h"
+
+static int smiapp_write_8(struct smiapp_sensor *sensor, u16 reg, u8 val)
+{
+ return smiapp_write(sensor, (SMIA_REG_8BIT << 16) | reg, val);
+}
+
+static int smiapp_write_8s(struct smiapp_sensor *sensor,
+ struct smiapp_reg_8 *regs, int len)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ int rval;
+
+ for (; len > 0; len--, regs++) {
+ rval = smiapp_write_8(sensor, regs->reg, regs->val);
+ if (rval < 0) {
+ dev_err(&client->dev,
+ "error %d writing reg 0x%4.4x, val 0x%2.2x",
+ rval, regs->reg, regs->val);
+ return rval;
+ }
+ }
+
+ return 0;
+}
+
+void smiapp_replace_limit(struct smiapp_sensor *sensor,
+ u32 limit, u32 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+
+ dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" = %d, 0x%x\n",
+ smiapp_reg_limits[limit].addr,
+ smiapp_reg_limits[limit].what, val, val);
+ sensor->limits[limit] = val;
+}
+
+int smiapp_replace_limit_at(struct smiapp_sensor *sensor,
+ u32 reg, u32 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ int i;
+
+ for (i = 0; smiapp_reg_limits[i].addr; i++) {
+ if ((smiapp_reg_limits[i].addr & 0xffff) != reg)
+ continue;
+
+ smiapp_replace_limit(sensor, i, val);
+
+ return 0;
+ }
+
+ dev_dbg(&client->dev, "quirk: bad register 0x%4.4x\n", reg);
+
+ return -EINVAL;
+}
+
+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)
+ sensor->frame_skip = 1;
+
+ /* Below 24 gain doesn't have effect at all, */
+ /* but ~59 is needed for full dynamic range */
+ smiapp_replace_limit(sensor, SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN, 59);
+ smiapp_replace_limit(
+ sensor, SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX, 6000);
+
+ return 0;
+}
+
+static int jt8ew9_post_poweron(struct smiapp_sensor *sensor)
+{
+ struct smiapp_reg_8 regs[] = {
+ { 0x30a3, 0xd8 }, /* Output port control : LVDS ports only */
+ { 0x30ae, 0x00 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */
+ { 0x30af, 0xd0 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */
+ { 0x322d, 0x04 }, /* Adjusting Processing Image Size to Scaler Toshiba Recommendation Setting */
+ { 0x3255, 0x0f }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
+ { 0x3256, 0x15 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
+ { 0x3258, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */
+ { 0x3259, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */
+ { 0x325f, 0x7c }, /* Analog Gain Control Toshiba Recommendation Setting */
+ { 0x3302, 0x06 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
+ { 0x3304, 0x00 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
+ { 0x3307, 0x22 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
+ { 0x3308, 0x8d }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
+ { 0x331e, 0x0f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+ { 0x3320, 0x30 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+ { 0x3321, 0x11 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+ { 0x3322, 0x98 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+ { 0x3323, 0x64 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+ { 0x3325, 0x83 }, /* Read Out Timing Control Toshiba Recommendation Setting */
+ { 0x3330, 0x18 }, /* Read Out Timing Control Toshiba Recommendation Setting */
+ { 0x333c, 0x01 }, /* Read Out Timing Control Toshiba Recommendation Setting */
+ { 0x3345, 0x2f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
+ { 0x33de, 0x38 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
+ /* Taken from v03. No idea what the rest are. */
+ { 0x32e0, 0x05 },
+ { 0x32e1, 0x05 },
+ { 0x32e2, 0x04 },
+ { 0x32e5, 0x04 },
+ { 0x32e6, 0x04 },
+
+ };
+
+ return smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs));
+}
+
+const struct smiapp_quirk smiapp_jt8ew9_quirk = {
+ .limits = jt8ew9_limits,
+ .post_poweron = jt8ew9_post_poweron,
+};
+
+static int imx125es_post_poweron(struct smiapp_sensor *sensor)
+{
+ /* Taken from v02. No idea what the other two are. */
+ struct smiapp_reg_8 regs[] = {
+ /*
+ * 0x3302: clk during frame blanking:
+ * 0x00 - HS mode, 0x01 - LP11
+ */
+ { 0x3302, 0x01 },
+ { 0x302d, 0x00 },
+ { 0x3b08, 0x8c },
+ };
+
+ return smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs));
+}
+
+const struct smiapp_quirk smiapp_imx125es_quirk = {
+ .post_poweron = imx125es_post_poweron,
+};
+
+static int jt8ev1_limits(struct smiapp_sensor *sensor)
+{
+ smiapp_replace_limit(sensor, SMIAPP_LIMIT_X_ADDR_MAX, 4271);
+ smiapp_replace_limit(sensor,
+ SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN, 184);
+
+ return 0;
+}
+
+static int jt8ev1_post_poweron(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ int rval;
+
+ struct smiapp_reg_8 regs[] = {
+ { 0x3031, 0xcd }, /* For digital binning (EQ_MONI) */
+ { 0x30a3, 0xd0 }, /* FLASH STROBE enable */
+ { 0x3237, 0x00 }, /* For control of pulse timing for ADC */
+ { 0x3238, 0x43 },
+ { 0x3301, 0x06 }, /* For analog bias for sensor */
+ { 0x3302, 0x06 },
+ { 0x3304, 0x00 },
+ { 0x3305, 0x88 },
+ { 0x332a, 0x14 },
+ { 0x332c, 0x6b },
+ { 0x3336, 0x01 },
+ { 0x333f, 0x1f },
+ { 0x3355, 0x00 },
+ { 0x3356, 0x20 },
+ { 0x33bf, 0x20 }, /* Adjust the FBC speed */
+ { 0x33c9, 0x20 },
+ { 0x33ce, 0x30 }, /* Adjust the parameter for logic function */
+ { 0x33cf, 0xec }, /* For Black sun */
+ { 0x3328, 0x80 }, /* Ugh. No idea what's this. */
+ };
+
+ struct smiapp_reg_8 regs_96[] = {
+ { 0x30ae, 0x00 }, /* For control of ADC clock */
+ { 0x30af, 0xd0 },
+ { 0x30b0, 0x01 },
+ };
+
+ rval = smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs));
+ if (rval < 0)
+ return rval;
+
+ switch (sensor->platform_data->ext_clk) {
+ case 9600000:
+ return smiapp_write_8s(sensor, regs_96,
+ ARRAY_SIZE(regs_96));
+ default:
+ dev_warn(&client->dev, "no MSRs for %d Hz ext_clk\n",
+ sensor->platform_data->ext_clk);
+ return 0;
+ }
+}
+
+static int jt8ev1_pre_streamon(struct smiapp_sensor *sensor)
+{
+ return smiapp_write_8(sensor, 0x3328, 0x00);
+}
+
+static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor)
+{
+ int rval;
+
+ /* Workaround: allows fast standby to work properly */
+ rval = smiapp_write_8(sensor, 0x3205, 0x04);
+ if (rval < 0)
+ return rval;
+
+ /* Wait for 1 ms + one line => 2 ms is likely enough */
+ usleep_range(2000, 2000);
+
+ /* Restore it */
+ rval = smiapp_write_8(sensor, 0x3205, 0x00);
+ if (rval < 0)
+ return rval;
+
+ return smiapp_write_8(sensor, 0x3328, 0x80);
+}
+
+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,
+};
+
+static int tcm8500md_limits(struct smiapp_sensor *sensor)
+{
+ smiapp_replace_limit(sensor, SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ, 2700000);
+
+ return 0;
+}
+
+const struct smiapp_quirk smiapp_tcm8500md_quirk = {
+ .limits = tcm8500md_limits,
+};
diff --git a/drivers/media/video/smiapp/smiapp-quirk.h b/drivers/media/video/smiapp/smiapp-quirk.h
new file mode 100644
index 000000000000..f4dcaabaefe7
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-quirk.h
@@ -0,0 +1,83 @@
+/*
+ * drivers/media/video/smiapp/smiapp-quirk.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __SMIAPP_QUIRK__
+#define __SMIAPP_QUIRK__
+
+struct smiapp_sensor;
+
+/**
+ * struct smiapp_quirk - quirks for sensors that deviate from SMIA++ standard
+ *
+ * @limits: Replace sensor->limits with values which can't be read from
+ * sensor registers. Called the first time the sensor is powered up.
+ * @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.
+ */
+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 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)
+
+struct smiapp_reg_8 {
+ u16 reg;
+ u8 val;
+};
+
+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) \
+ { \
+ .type = (_reg >> 16), \
+ .reg = (u16)_reg, \
+ .val = _val, \
+ }
+
+#define smiapp_call_quirk(_sensor, _quirk, ...) \
+ (_sensor->minfo.quirk && \
+ _sensor->minfo.quirk->_quirk ? \
+ _sensor->minfo.quirk->_quirk(_sensor, ##__VA_ARGS__) : 0)
+
+#define smiapp_needs_quirk(_sensor, _quirk) \
+ (_sensor->minfo.quirk ? \
+ _sensor->minfo.quirk->flags & _quirk : 0)
+
+extern const struct smiapp_quirk smiapp_jt8ev1_quirk;
+extern const struct smiapp_quirk smiapp_imx125es_quirk;
+extern const struct smiapp_quirk smiapp_jt8ew9_quirk;
+extern const struct smiapp_quirk smiapp_tcm8500md_quirk;
+
+#endif /* __SMIAPP_QUIRK__ */
diff --git a/drivers/media/video/smiapp/smiapp-reg-defs.h b/drivers/media/video/smiapp/smiapp-reg-defs.h
new file mode 100644
index 000000000000..a089eb8161e1
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-reg-defs.h
@@ -0,0 +1,503 @@
+/*
+ * drivers/media/video/smiapp/smiapp-reg-defs.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 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_F32(r) (SMIA_REG_FLAG_FLOAT | (SMIA_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)
+#define SMIAPP_REG_U8_MANUFACTURER_ID SMIAPP_REG_MK_U8(0x0003)
+#define SMIAPP_REG_U8_SMIA_VERSION SMIAPP_REG_MK_U8(0x0004)
+#define SMIAPP_REG_U8_FRAME_COUNT SMIAPP_REG_MK_U8(0x0005)
+#define SMIAPP_REG_U8_PIXEL_ORDER SMIAPP_REG_MK_U8(0x0006)
+#define SMIAPP_REG_U16_DATA_PEDESTAL SMIAPP_REG_MK_U16(0x0008)
+#define SMIAPP_REG_U8_PIXEL_DEPTH SMIAPP_REG_MK_U8(0x000c)
+#define SMIAPP_REG_U8_REVISION_NUMBER_MINOR SMIAPP_REG_MK_U8(0x0010)
+#define SMIAPP_REG_U8_SMIAPP_VERSION SMIAPP_REG_MK_U8(0x0011)
+#define SMIAPP_REG_U8_MODULE_DATE_YEAR SMIAPP_REG_MK_U8(0x0012)
+#define SMIAPP_REG_U8_MODULE_DATE_MONTH SMIAPP_REG_MK_U8(0x0013)
+#define SMIAPP_REG_U8_MODULE_DATE_DAY SMIAPP_REG_MK_U8(0x0014)
+#define SMIAPP_REG_U8_MODULE_DATE_PHASE SMIAPP_REG_MK_U8(0x0015)
+#define SMIAPP_REG_U16_SENSOR_MODEL_ID SMIAPP_REG_MK_U16(0x0016)
+#define SMIAPP_REG_U8_SENSOR_REVISION_NUMBER SMIAPP_REG_MK_U8(0x0018)
+#define SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID SMIAPP_REG_MK_U8(0x0019)
+#define SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION SMIAPP_REG_MK_U8(0x001a)
+#define SMIAPP_REG_U32_SERIAL_NUMBER SMIAPP_REG_MK_U32(0x001c)
+#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE SMIAPP_REG_MK_U8(0x0040)
+#define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_SUBTYPE SMIAPP_REG_MK_U8(0x0041)
+#define SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(n) SMIAPP_REG_MK_U16(0x0042 + ((n) << 1)) /* 0 <= n <= 14 */
+#define SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(n) SMIAPP_REG_MK_U32(0x0060 + ((n) << 2)) /* 0 <= n <= 7 */
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY SMIAPP_REG_MK_U16(0x0080)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN SMIAPP_REG_MK_U16(0x0084)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX SMIAPP_REG_MK_U16(0x0086)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP SMIAPP_REG_MK_U16(0x0088)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_TYPE SMIAPP_REG_MK_U16(0x008a)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_M0 SMIAPP_REG_MK_U16(0x008c)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_C0 SMIAPP_REG_MK_U16(0x008e)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_M1 SMIAPP_REG_MK_U16(0x0090)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_C1 SMIAPP_REG_MK_U16(0x0092)
+#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE SMIAPP_REG_MK_U8(0x00c0)
+#define SMIAPP_REG_U8_DATA_FORMAT_MODEL_SUBTYPE SMIAPP_REG_MK_U8(0x00c1)
+#define SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(n) SMIAPP_REG_MK_U16(0x00c2 + ((n) << 1))
+#define SMIAPP_REG_U8_MODE_SELECT SMIAPP_REG_MK_U8(0x0100)
+#define SMIAPP_REG_U8_IMAGE_ORIENTATION SMIAPP_REG_MK_U8(0x0101)
+#define SMIAPP_REG_U8_SOFTWARE_RESET SMIAPP_REG_MK_U8(0x0103)
+#define SMIAPP_REG_U8_GROUPED_PARAMETER_HOLD SMIAPP_REG_MK_U8(0x0104)
+#define SMIAPP_REG_U8_MASK_CORRUPTED_FRAMES SMIAPP_REG_MK_U8(0x0105)
+#define SMIAPP_REG_U8_FAST_STANDBY_CTRL SMIAPP_REG_MK_U8(0x0106)
+#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL SMIAPP_REG_MK_U8(0x0107)
+#define SMIAPP_REG_U8_2ND_CCI_IF_CONTROL SMIAPP_REG_MK_U8(0x0108)
+#define SMIAPP_REG_U8_2ND_CCI_ADDRESS_CONTROL SMIAPP_REG_MK_U8(0x0109)
+#define SMIAPP_REG_U8_CSI_CHANNEL_IDENTIFIER SMIAPP_REG_MK_U8(0x0110)
+#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE SMIAPP_REG_MK_U8(0x0111)
+#define SMIAPP_REG_U16_CSI_DATA_FORMAT SMIAPP_REG_MK_U16(0x0112)
+#define SMIAPP_REG_U8_CSI_LANE_MODE SMIAPP_REG_MK_U8(0x0114)
+#define SMIAPP_REG_U8_CSI2_10_TO_8_DT SMIAPP_REG_MK_U8(0x0115)
+#define SMIAPP_REG_U8_CSI2_10_TO_7_DT SMIAPP_REG_MK_U8(0x0116)
+#define SMIAPP_REG_U8_CSI2_10_TO_6_DT SMIAPP_REG_MK_U8(0x0117)
+#define SMIAPP_REG_U8_CSI2_12_TO_8_DT SMIAPP_REG_MK_U8(0x0118)
+#define SMIAPP_REG_U8_CSI2_12_TO_7_DT SMIAPP_REG_MK_U8(0x0119)
+#define SMIAPP_REG_U8_CSI2_12_TO_6_DT SMIAPP_REG_MK_U8(0x011a)
+#define SMIAPP_REG_U8_CSI2_14_TO_10_DT SMIAPP_REG_MK_U8(0x011b)
+#define SMIAPP_REG_U8_CSI2_14_TO_8_DT SMIAPP_REG_MK_U8(0x011c)
+#define SMIAPP_REG_U8_CSI2_16_TO_10_DT SMIAPP_REG_MK_U8(0x011d)
+#define SMIAPP_REG_U8_CSI2_16_TO_8_DT SMIAPP_REG_MK_U8(0x011e)
+#define SMIAPP_REG_U8_GAIN_MODE SMIAPP_REG_MK_U8(0x0120)
+#define SMIAPP_REG_U16_VANA_VOLTAGE SMIAPP_REG_MK_U16(0x0130)
+#define SMIAPP_REG_U16_VDIG_VOLTAGE SMIAPP_REG_MK_U16(0x0132)
+#define SMIAPP_REG_U16_VIO_VOLTAGE SMIAPP_REG_MK_U16(0x0134)
+#define SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ SMIAPP_REG_MK_U16(0x0136)
+#define SMIAPP_REG_U8_TEMP_SENSOR_CONTROL SMIAPP_REG_MK_U8(0x0138)
+#define SMIAPP_REG_U8_TEMP_SENSOR_MODE SMIAPP_REG_MK_U8(0x0139)
+#define SMIAPP_REG_U8_TEMP_SENSOR_OUTPUT SMIAPP_REG_MK_U8(0x013a)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME SMIAPP_REG_MK_U16(0x0200)
+#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME SMIAPP_REG_MK_U16(0x0202)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL SMIAPP_REG_MK_U16(0x0204)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENR SMIAPP_REG_MK_U16(0x0206)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_RED SMIAPP_REG_MK_U16(0x0208)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_BLUE SMIAPP_REG_MK_U16(0x020a)
+#define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENB SMIAPP_REG_MK_U16(0x020c)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENR SMIAPP_REG_MK_U16(0x020e)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_RED SMIAPP_REG_MK_U16(0x0210)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_BLUE SMIAPP_REG_MK_U16(0x0212)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_GREENB SMIAPP_REG_MK_U16(0x0214)
+#define SMIAPP_REG_U16_VT_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x0300)
+#define SMIAPP_REG_U16_VT_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x0302)
+#define SMIAPP_REG_U16_PRE_PLL_CLK_DIV SMIAPP_REG_MK_U16(0x0304)
+#define SMIAPP_REG_U16_PLL_MULTIPLIER SMIAPP_REG_MK_U16(0x0306)
+#define SMIAPP_REG_U16_OP_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x0308)
+#define SMIAPP_REG_U16_OP_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x030a)
+#define SMIAPP_REG_U16_FRAME_LENGTH_LINES SMIAPP_REG_MK_U16(0x0340)
+#define SMIAPP_REG_U16_LINE_LENGTH_PCK SMIAPP_REG_MK_U16(0x0342)
+#define SMIAPP_REG_U16_X_ADDR_START SMIAPP_REG_MK_U16(0x0344)
+#define SMIAPP_REG_U16_Y_ADDR_START SMIAPP_REG_MK_U16(0x0346)
+#define SMIAPP_REG_U16_X_ADDR_END SMIAPP_REG_MK_U16(0x0348)
+#define SMIAPP_REG_U16_Y_ADDR_END SMIAPP_REG_MK_U16(0x034a)
+#define SMIAPP_REG_U16_X_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x034c)
+#define SMIAPP_REG_U16_Y_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x034e)
+#define SMIAPP_REG_U16_X_EVEN_INC SMIAPP_REG_MK_U16(0x0380)
+#define SMIAPP_REG_U16_X_ODD_INC SMIAPP_REG_MK_U16(0x0382)
+#define SMIAPP_REG_U16_Y_EVEN_INC SMIAPP_REG_MK_U16(0x0384)
+#define SMIAPP_REG_U16_Y_ODD_INC SMIAPP_REG_MK_U16(0x0386)
+#define SMIAPP_REG_U16_SCALING_MODE SMIAPP_REG_MK_U16(0x0400)
+#define SMIAPP_REG_U16_SPATIAL_SAMPLING SMIAPP_REG_MK_U16(0x0402)
+#define SMIAPP_REG_U16_SCALE_M SMIAPP_REG_MK_U16(0x0404)
+#define SMIAPP_REG_U16_SCALE_N SMIAPP_REG_MK_U16(0x0406)
+#define SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET SMIAPP_REG_MK_U16(0x0408)
+#define SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET SMIAPP_REG_MK_U16(0x040a)
+#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH SMIAPP_REG_MK_U16(0x040c)
+#define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT SMIAPP_REG_MK_U16(0x040e)
+#define SMIAPP_REG_U16_COMPRESSION_MODE SMIAPP_REG_MK_U16(0x0500)
+#define SMIAPP_REG_U16_TEST_PATTERN_MODE SMIAPP_REG_MK_U16(0x0600)
+#define SMIAPP_REG_U16_TEST_DATA_RED SMIAPP_REG_MK_U16(0x0602)
+#define SMIAPP_REG_U16_TEST_DATA_GREENR SMIAPP_REG_MK_U16(0x0604)
+#define SMIAPP_REG_U16_TEST_DATA_BLUE SMIAPP_REG_MK_U16(0x0606)
+#define SMIAPP_REG_U16_TEST_DATA_GREENB SMIAPP_REG_MK_U16(0x0608)
+#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_WIDTH SMIAPP_REG_MK_U16(0x060a)
+#define SMIAPP_REG_U16_HORIZONTAL_CURSOR_POSITION SMIAPP_REG_MK_U16(0x060c)
+#define SMIAPP_REG_U16_VERTICAL_CURSOR_WIDTH SMIAPP_REG_MK_U16(0x060e)
+#define SMIAPP_REG_U16_VERTICAL_CURSOR_POSITION SMIAPP_REG_MK_U16(0x0610)
+#define SMIAPP_REG_U16_FIFO_WATER_MARK_PIXELS SMIAPP_REG_MK_U16(0x0700)
+#define SMIAPP_REG_U8_TCLK_POST SMIAPP_REG_MK_U8(0x0800)
+#define SMIAPP_REG_U8_THS_PREPARE SMIAPP_REG_MK_U8(0x0801)
+#define SMIAPP_REG_U8_THS_ZERO_MIN SMIAPP_REG_MK_U8(0x0802)
+#define SMIAPP_REG_U8_THS_TRAIL SMIAPP_REG_MK_U8(0x0803)
+#define SMIAPP_REG_U8_TCLK_TRAIL_MIN SMIAPP_REG_MK_U8(0x0804)
+#define SMIAPP_REG_U8_TCLK_PREPARE SMIAPP_REG_MK_U8(0x0805)
+#define SMIAPP_REG_U8_TCLK_ZERO SMIAPP_REG_MK_U8(0x0806)
+#define SMIAPP_REG_U8_TLPX SMIAPP_REG_MK_U8(0x0807)
+#define SMIAPP_REG_U8_DPHY_CTRL SMIAPP_REG_MK_U8(0x0808)
+#define SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS SMIAPP_REG_MK_U32(0x0820)
+#define SMIAPP_REG_U8_BINNING_MODE SMIAPP_REG_MK_U8(0x0900)
+#define SMIAPP_REG_U8_BINNING_TYPE SMIAPP_REG_MK_U8(0x0901)
+#define SMIAPP_REG_U8_BINNING_WEIGHTING SMIAPP_REG_MK_U8(0x0902)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL SMIAPP_REG_MK_U8(0x0a00)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS SMIAPP_REG_MK_U8(0x0a01)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT SMIAPP_REG_MK_U8(0x0a02)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0 SMIAPP_REG_MK_U8(0x0a04)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_1 SMIAPP_REG_MK_U8(0x0a05)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_2 SMIAPP_REG_MK_U8(0x0a06)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_3 SMIAPP_REG_MK_U8(0x0a07)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_4 SMIAPP_REG_MK_U8(0x0a08)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_5 SMIAPP_REG_MK_U8(0x0a09)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_12 SMIAPP_REG_MK_U8(0x0a10)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_13 SMIAPP_REG_MK_U8(0x0a11)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_14 SMIAPP_REG_MK_U8(0x0a12)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_15 SMIAPP_REG_MK_U8(0x0a13)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_16 SMIAPP_REG_MK_U8(0x0a14)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_17 SMIAPP_REG_MK_U8(0x0a15)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_18 SMIAPP_REG_MK_U8(0x0a16)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_19 SMIAPP_REG_MK_U8(0x0a17)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_20 SMIAPP_REG_MK_U8(0x0a18)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_21 SMIAPP_REG_MK_U8(0x0a19)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_22 SMIAPP_REG_MK_U8(0x0a1a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_23 SMIAPP_REG_MK_U8(0x0a1b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_24 SMIAPP_REG_MK_U8(0x0a1c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_25 SMIAPP_REG_MK_U8(0x0a1d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_26 SMIAPP_REG_MK_U8(0x0a1e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_27 SMIAPP_REG_MK_U8(0x0a1f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_28 SMIAPP_REG_MK_U8(0x0a20)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_29 SMIAPP_REG_MK_U8(0x0a21)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_30 SMIAPP_REG_MK_U8(0x0a22)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_31 SMIAPP_REG_MK_U8(0x0a23)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_32 SMIAPP_REG_MK_U8(0x0a24)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_33 SMIAPP_REG_MK_U8(0x0a25)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_34 SMIAPP_REG_MK_U8(0x0a26)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_35 SMIAPP_REG_MK_U8(0x0a27)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_36 SMIAPP_REG_MK_U8(0x0a28)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_37 SMIAPP_REG_MK_U8(0x0a29)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_38 SMIAPP_REG_MK_U8(0x0a2a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_39 SMIAPP_REG_MK_U8(0x0a2b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_40 SMIAPP_REG_MK_U8(0x0a2c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_41 SMIAPP_REG_MK_U8(0x0a2d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_42 SMIAPP_REG_MK_U8(0x0a2e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_43 SMIAPP_REG_MK_U8(0x0a2f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_44 SMIAPP_REG_MK_U8(0x0a30)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_45 SMIAPP_REG_MK_U8(0x0a31)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_46 SMIAPP_REG_MK_U8(0x0a32)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_47 SMIAPP_REG_MK_U8(0x0a33)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_48 SMIAPP_REG_MK_U8(0x0a34)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_49 SMIAPP_REG_MK_U8(0x0a35)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_50 SMIAPP_REG_MK_U8(0x0a36)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_51 SMIAPP_REG_MK_U8(0x0a37)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_52 SMIAPP_REG_MK_U8(0x0a38)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_53 SMIAPP_REG_MK_U8(0x0a39)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_54 SMIAPP_REG_MK_U8(0x0a3a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_55 SMIAPP_REG_MK_U8(0x0a3b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_56 SMIAPP_REG_MK_U8(0x0a3c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_57 SMIAPP_REG_MK_U8(0x0a3d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_58 SMIAPP_REG_MK_U8(0x0a3e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_59 SMIAPP_REG_MK_U8(0x0a3f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_60 SMIAPP_REG_MK_U8(0x0a40)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_61 SMIAPP_REG_MK_U8(0x0a41)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_62 SMIAPP_REG_MK_U8(0x0a42)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_63 SMIAPP_REG_MK_U8(0x0a43)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_CTRL SMIAPP_REG_MK_U8(0x0a44)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_STATUS SMIAPP_REG_MK_U8(0x0a45)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_PAGE_SELECT SMIAPP_REG_MK_U8(0x0a46)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_0 SMIAPP_REG_MK_U8(0x0a48)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_1 SMIAPP_REG_MK_U8(0x0a49)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_2 SMIAPP_REG_MK_U8(0x0a4a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_3 SMIAPP_REG_MK_U8(0x0a4b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_4 SMIAPP_REG_MK_U8(0x0a4c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_5 SMIAPP_REG_MK_U8(0x0a4d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_6 SMIAPP_REG_MK_U8(0x0a4e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_7 SMIAPP_REG_MK_U8(0x0a4f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_8 SMIAPP_REG_MK_U8(0x0a50)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_9 SMIAPP_REG_MK_U8(0x0a51)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_10 SMIAPP_REG_MK_U8(0x0a52)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_11 SMIAPP_REG_MK_U8(0x0a53)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_12 SMIAPP_REG_MK_U8(0x0a54)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_13 SMIAPP_REG_MK_U8(0x0a55)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_14 SMIAPP_REG_MK_U8(0x0a56)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_15 SMIAPP_REG_MK_U8(0x0a57)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_16 SMIAPP_REG_MK_U8(0x0a58)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_17 SMIAPP_REG_MK_U8(0x0a59)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_18 SMIAPP_REG_MK_U8(0x0a5a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_19 SMIAPP_REG_MK_U8(0x0a5b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_20 SMIAPP_REG_MK_U8(0x0a5c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_21 SMIAPP_REG_MK_U8(0x0a5d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_22 SMIAPP_REG_MK_U8(0x0a5e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_23 SMIAPP_REG_MK_U8(0x0a5f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_24 SMIAPP_REG_MK_U8(0x0a60)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_25 SMIAPP_REG_MK_U8(0x0a61)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_26 SMIAPP_REG_MK_U8(0x0a62)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_27 SMIAPP_REG_MK_U8(0x0a63)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_28 SMIAPP_REG_MK_U8(0x0a64)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_29 SMIAPP_REG_MK_U8(0x0a65)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_30 SMIAPP_REG_MK_U8(0x0a66)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_31 SMIAPP_REG_MK_U8(0x0a67)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_32 SMIAPP_REG_MK_U8(0x0a68)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_33 SMIAPP_REG_MK_U8(0x0a69)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_34 SMIAPP_REG_MK_U8(0x0a6a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_35 SMIAPP_REG_MK_U8(0x0a6b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_36 SMIAPP_REG_MK_U8(0x0a6c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_37 SMIAPP_REG_MK_U8(0x0a6d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_38 SMIAPP_REG_MK_U8(0x0a6e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_39 SMIAPP_REG_MK_U8(0x0a6f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_40 SMIAPP_REG_MK_U8(0x0a70)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_41 SMIAPP_REG_MK_U8(0x0a71)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_42 SMIAPP_REG_MK_U8(0x0a72)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_43 SMIAPP_REG_MK_U8(0x0a73)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_44 SMIAPP_REG_MK_U8(0x0a74)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_45 SMIAPP_REG_MK_U8(0x0a75)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_46 SMIAPP_REG_MK_U8(0x0a76)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_47 SMIAPP_REG_MK_U8(0x0a77)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_48 SMIAPP_REG_MK_U8(0x0a78)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_49 SMIAPP_REG_MK_U8(0x0a79)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_50 SMIAPP_REG_MK_U8(0x0a7a)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_51 SMIAPP_REG_MK_U8(0x0a7b)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_52 SMIAPP_REG_MK_U8(0x0a7c)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_53 SMIAPP_REG_MK_U8(0x0a7d)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_54 SMIAPP_REG_MK_U8(0x0a7e)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_55 SMIAPP_REG_MK_U8(0x0a7f)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_56 SMIAPP_REG_MK_U8(0x0a80)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_57 SMIAPP_REG_MK_U8(0x0a81)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_58 SMIAPP_REG_MK_U8(0x0a82)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_59 SMIAPP_REG_MK_U8(0x0a83)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_60 SMIAPP_REG_MK_U8(0x0a84)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_61 SMIAPP_REG_MK_U8(0x0a85)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_62 SMIAPP_REG_MK_U8(0x0a86)
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_63 SMIAPP_REG_MK_U8(0x0a87)
+#define SMIAPP_REG_U8_SHADING_CORRECTION_ENABLE SMIAPP_REG_MK_U8(0x0b00)
+#define SMIAPP_REG_U8_LUMINANCE_CORRECTION_LEVEL SMIAPP_REG_MK_U8(0x0b01)
+#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_ENABLE SMIAPP_REG_MK_U8(0x0b02)
+#define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_WEIGHT SMIAPP_REG_MK_U8(0x0b03)
+#define SMIAPP_REG_U8_BLACK_LEVEL_CORRECTION_ENABLE SMIAPP_REG_MK_U8(0x0b04)
+#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b05)
+#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b06)
+#define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_WEIGHT SMIAPP_REG_MK_U8(0x0b07)
+#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b08)
+#define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_WEIGHT SMIAPP_REG_MK_U8(0x0b09)
+#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b0a)
+#define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_WEIGHT SMIAPP_REG_MK_U8(0x0b0b)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_ENABLE SMIAPP_REG_MK_U8(0x0b0c)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_WEIGHT SMIAPP_REG_MK_U8(0x0b0d)
+#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b0e)
+#define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b0f)
+#define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b10)
+#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b11)
+#define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b12)
+#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b13)
+#define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b14)
+#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b15)
+#define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b16)
+#define SMIAPP_REG_U8_EDOF_MODE SMIAPP_REG_MK_U8(0x0b80)
+#define SMIAPP_REG_U8_SHARPNESS SMIAPP_REG_MK_U8(0x0b83)
+#define SMIAPP_REG_U8_DENOISING SMIAPP_REG_MK_U8(0x0b84)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC SMIAPP_REG_MK_U8(0x0b85)
+#define SMIAPP_REG_U16_DEPTH_OF_FIELD SMIAPP_REG_MK_U16(0x0b86)
+#define SMIAPP_REG_U16_FOCUS_DISTANCE SMIAPP_REG_MK_U16(0x0b88)
+#define SMIAPP_REG_U8_ESTIMATION_MODE_CTRL SMIAPP_REG_MK_U8(0x0b8a)
+#define SMIAPP_REG_U16_COLOUR_TEMPERATURE SMIAPP_REG_MK_U16(0x0b8c)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENR SMIAPP_REG_MK_U16(0x0b8e)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_RED SMIAPP_REG_MK_U16(0x0b90)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_BLUE SMIAPP_REG_MK_U16(0x0b92)
+#define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENB SMIAPP_REG_MK_U16(0x0b94)
+#define SMIAPP_REG_U8_ESTIMATION_ZONE_MODE SMIAPP_REG_MK_U8(0x0bc0)
+#define SMIAPP_REG_U16_FIXED_ZONE_WEIGHTING SMIAPP_REG_MK_U16(0x0bc2)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_X_START SMIAPP_REG_MK_U16(0x0bc4)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_Y_START SMIAPP_REG_MK_U16(0x0bc6)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_WIDTH SMIAPP_REG_MK_U16(0x0bc8)
+#define SMIAPP_REG_U16_CUSTOM_ZONE_HEIGHT SMIAPP_REG_MK_U16(0x0bca)
+#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL1 SMIAPP_REG_MK_U8(0x0c00)
+#define SMIAPP_REG_U8_GLOBAL_RESET_CTRL2 SMIAPP_REG_MK_U8(0x0c01)
+#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_1 SMIAPP_REG_MK_U8(0x0c02)
+#define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_2 SMIAPP_REG_MK_U8(0x0c03)
+#define SMIAPP_REG_U16_TRDY_CTRL SMIAPP_REG_MK_U16(0x0c04)
+#define SMIAPP_REG_U16_TRDOUT_CTRL SMIAPP_REG_MK_U16(0x0c06)
+#define SMIAPP_REG_U16_TSHUTTER_STROBE_DELAY_CTRL SMIAPP_REG_MK_U16(0x0c08)
+#define SMIAPP_REG_U16_TSHUTTER_STROBE_WIDTH_CTRL SMIAPP_REG_MK_U16(0x0c0a)
+#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_CTRL SMIAPP_REG_MK_U16(0x0c0c)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_CTRL SMIAPP_REG_MK_U16(0x0c0e)
+#define SMIAPP_REG_U16_TGRST_INTERVAL_CTRL SMIAPP_REG_MK_U16(0x0c10)
+#define SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT SMIAPP_REG_MK_U8(0x0c12)
+#define SMIAPP_REG_U16_FLASH_STROBE_START_POINT SMIAPP_REG_MK_U16(0x0c14)
+#define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL SMIAPP_REG_MK_U16(0x0c16)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL SMIAPP_REG_MK_U16(0x0c18)
+#define SMIAPP_REG_U8_FLASH_MODE_RS SMIAPP_REG_MK_U8(0x0c1a)
+#define SMIAPP_REG_U8_FLASH_TRIGGER_RS SMIAPP_REG_MK_U8(0x0c1b)
+#define SMIAPP_REG_U8_FLASH_STATUS SMIAPP_REG_MK_U8(0x0c1c)
+#define SMIAPP_REG_U8_SA_STROBE_MODE SMIAPP_REG_MK_U8(0x0c1d)
+#define SMIAPP_REG_U16_SA_STROBE_START_POINT SMIAPP_REG_MK_U16(0x0c1e)
+#define SMIAPP_REG_U16_TSA_STROBE_DELAY_CTRL SMIAPP_REG_MK_U16(0x0c20)
+#define SMIAPP_REG_U16_TSA_STROBE_WIDTH_CTRL SMIAPP_REG_MK_U16(0x0c22)
+#define SMIAPP_REG_U8_SA_STROBE_TRIGGER SMIAPP_REG_MK_U8(0x0c24)
+#define SMIAPP_REG_U8_SPECIAL_ACTUATOR_STATUS SMIAPP_REG_MK_U8(0x0c25)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_RS_CTRL SMIAPP_REG_MK_U16(0x0c26)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_RS_CTRL SMIAPP_REG_MK_U16(0x0c28)
+#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_RS_CTRL SMIAPP_REG_MK_U8(0x0c2a)
+#define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_CTRL SMIAPP_REG_MK_U8(0x0c2b)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_CTRL SMIAPP_REG_MK_U16(0x0c2c)
+#define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_CTRL SMIAPP_REG_MK_U16(0x0c2e)
+#define SMIAPP_REG_U8_LOW_LEVEL_CTRL SMIAPP_REG_MK_U8(0x0c80)
+#define SMIAPP_REG_U16_MAIN_TRIGGER_REF_POINT SMIAPP_REG_MK_U16(0x0c82)
+#define SMIAPP_REG_U16_MAIN_TRIGGER_T3 SMIAPP_REG_MK_U16(0x0c84)
+#define SMIAPP_REG_U8_MAIN_TRIGGER_COUNT SMIAPP_REG_MK_U8(0x0c86)
+#define SMIAPP_REG_U16_PHASE1_TRIGGER_T3 SMIAPP_REG_MK_U16(0x0c88)
+#define SMIAPP_REG_U8_PHASE1_TRIGGER_COUNT SMIAPP_REG_MK_U8(0x0c8a)
+#define SMIAPP_REG_U16_PHASE2_TRIGGER_T3 SMIAPP_REG_MK_U16(0x0c8c)
+#define SMIAPP_REG_U8_PHASE2_TRIGGER_COUNT SMIAPP_REG_MK_U8(0x0c8e)
+#define SMIAPP_REG_U8_MECH_SHUTTER_CTRL SMIAPP_REG_MK_U8(0x0d00)
+#define SMIAPP_REG_U8_OPERATION_MODE SMIAPP_REG_MK_U8(0x0d01)
+#define SMIAPP_REG_U8_ACT_STATE1 SMIAPP_REG_MK_U8(0x0d02)
+#define SMIAPP_REG_U8_ACT_STATE2 SMIAPP_REG_MK_U8(0x0d03)
+#define SMIAPP_REG_U16_FOCUS_CHANGE SMIAPP_REG_MK_U16(0x0d80)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_CONTROL SMIAPP_REG_MK_U16(0x0d82)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE1 SMIAPP_REG_MK_U16(0x0d84)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE2 SMIAPP_REG_MK_U16(0x0d86)
+#define SMIAPP_REG_U8_STROBE_COUNT_PHASE1 SMIAPP_REG_MK_U8(0x0d88)
+#define SMIAPP_REG_U8_STROBE_COUNT_PHASE2 SMIAPP_REG_MK_U8(0x0d89)
+#define SMIAPP_REG_U8_POSITION SMIAPP_REG_MK_U8(0x0d8a)
+#define SMIAPP_REG_U8_BRACKETING_LUT_CONTROL SMIAPP_REG_MK_U8(0x0e00)
+#define SMIAPP_REG_U8_BRACKETING_LUT_MODE SMIAPP_REG_MK_U8(0x0e01)
+#define SMIAPP_REG_U8_BRACKETING_LUT_ENTRY_CONTROL SMIAPP_REG_MK_U8(0x0e02)
+#define SMIAPP_REG_U8_LUT_PARAMETERS_START SMIAPP_REG_MK_U8(0x0e10)
+#define SMIAPP_REG_U8_LUT_PARAMETERS_END SMIAPP_REG_MK_U8(0x0eff)
+#define SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY SMIAPP_REG_MK_U16(0x1000)
+#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN SMIAPP_REG_MK_U16(0x1004)
+#define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN SMIAPP_REG_MK_U16(0x1006)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN SMIAPP_REG_MK_U16(0x1008)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN SMIAPP_REG_MK_U16(0x100a)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY SMIAPP_REG_MK_U16(0x1080)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_MIN SMIAPP_REG_MK_U16(0x1084)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_MAX SMIAPP_REG_MK_U16(0x1086)
+#define SMIAPP_REG_U16_DIGITAL_GAIN_STEP_SIZE SMIAPP_REG_MK_U16(0x1088)
+#define SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1100)
+#define SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1104)
+#define SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV SMIAPP_REG_MK_U16(0x1108)
+#define SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV SMIAPP_REG_MK_U16(0x110a)
+#define SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ SMIAPP_REG_MK_F32(0x110c)
+#define SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ SMIAPP_REG_MK_F32(0x1110)
+#define SMIAPP_REG_U16_MIN_PLL_MULTIPLIER SMIAPP_REG_MK_U16(0x1114)
+#define SMIAPP_REG_U16_MAX_PLL_MULTIPLIER SMIAPP_REG_MK_U16(0x1116)
+#define SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ SMIAPP_REG_MK_F32(0x1118)
+#define SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ SMIAPP_REG_MK_F32(0x111c)
+#define SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x1120)
+#define SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x1122)
+#define SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1124)
+#define SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1128)
+#define SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x112c)
+#define SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1130)
+#define SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x1134)
+#define SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x1136)
+#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES SMIAPP_REG_MK_U16(0x1140)
+#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES SMIAPP_REG_MK_U16(0x1142)
+#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK SMIAPP_REG_MK_U16(0x1144)
+#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK SMIAPP_REG_MK_U16(0x1146)
+#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK SMIAPP_REG_MK_U16(0x1148)
+#define SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES SMIAPP_REG_MK_U16(0x114a)
+#define SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE SMIAPP_REG_MK_U8(0x114c)
+#define SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x1160)
+#define SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x1162)
+#define SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1164)
+#define SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1168)
+#define SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x116c)
+#define SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x116e)
+#define SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1170)
+#define SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1174)
+#define SMIAPP_REG_U16_X_ADDR_MIN SMIAPP_REG_MK_U16(0x1180)
+#define SMIAPP_REG_U16_Y_ADDR_MIN SMIAPP_REG_MK_U16(0x1182)
+#define SMIAPP_REG_U16_X_ADDR_MAX SMIAPP_REG_MK_U16(0x1184)
+#define SMIAPP_REG_U16_Y_ADDR_MAX SMIAPP_REG_MK_U16(0x1186)
+#define SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x1188)
+#define SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x118a)
+#define SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x118c)
+#define SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x118e)
+#define SMIAPP_REG_U16_MIN_EVEN_INC SMIAPP_REG_MK_U16(0x11c0)
+#define SMIAPP_REG_U16_MAX_EVEN_INC SMIAPP_REG_MK_U16(0x11c2)
+#define SMIAPP_REG_U16_MIN_ODD_INC SMIAPP_REG_MK_U16(0x11c4)
+#define SMIAPP_REG_U16_MAX_ODD_INC SMIAPP_REG_MK_U16(0x11c6)
+#define SMIAPP_REG_U16_SCALING_CAPABILITY SMIAPP_REG_MK_U16(0x1200)
+#define SMIAPP_REG_U16_SCALER_M_MIN SMIAPP_REG_MK_U16(0x1204)
+#define SMIAPP_REG_U16_SCALER_M_MAX SMIAPP_REG_MK_U16(0x1206)
+#define SMIAPP_REG_U16_SCALER_N_MIN SMIAPP_REG_MK_U16(0x1208)
+#define SMIAPP_REG_U16_SCALER_N_MAX SMIAPP_REG_MK_U16(0x120a)
+#define SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY SMIAPP_REG_MK_U16(0x120c)
+#define SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY SMIAPP_REG_MK_U8(0x120e)
+#define SMIAPP_REG_U16_COMPRESSION_CAPABILITY SMIAPP_REG_MK_U16(0x1300)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINRED SMIAPP_REG_MK_U16(0x1400)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINRED SMIAPP_REG_MK_U16(0x1402)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINRED SMIAPP_REG_MK_U16(0x1404)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINGREEN SMIAPP_REG_MK_U16(0x1406)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINGREEN SMIAPP_REG_MK_U16(0x1408)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINGREEN SMIAPP_REG_MK_U16(0x140a)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINBLUE SMIAPP_REG_MK_U16(0x140c)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINBLUE SMIAPP_REG_MK_U16(0x140e)
+#define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINBLUE SMIAPP_REG_MK_U16(0x1410)
+#define SMIAPP_REG_U16_FIFO_SIZE_PIXELS SMIAPP_REG_MK_U16(0x1500)
+#define SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY SMIAPP_REG_MK_U8(0x1502)
+#define SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY SMIAPP_REG_MK_U8(0x1600)
+#define SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY SMIAPP_REG_MK_U8(0x1601)
+#define SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY SMIAPP_REG_MK_U8(0x1602)
+#define SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY SMIAPP_REG_MK_U8(0x1603)
+#define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY SMIAPP_REG_MK_U8(0x1604)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS SMIAPP_REG_MK_U32(0x1608)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS SMIAPP_REG_MK_U32(0x160c)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS SMIAPP_REG_MK_U32(0x1610)
+#define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS SMIAPP_REG_MK_U32(0x1614)
+#define SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY SMIAPP_REG_MK_U8(0x1618)
+#define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN SMIAPP_REG_MK_U16(0x1700)
+#define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN SMIAPP_REG_MK_U16(0x1702)
+#define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN SMIAPP_REG_MK_U16(0x1704)
+#define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN SMIAPP_REG_MK_U16(0x1706)
+#define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN SMIAPP_REG_MK_U16(0x1708)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN SMIAPP_REG_MK_U16(0x170a)
+#define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN SMIAPP_REG_MK_U16(0x170c)
+#define SMIAPP_REG_U8_BINNING_CAPABILITY SMIAPP_REG_MK_U8(0x1710)
+#define SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY SMIAPP_REG_MK_U8(0x1711)
+#define SMIAPP_REG_U8_BINNING_SUBTYPES SMIAPP_REG_MK_U8(0x1712)
+#define SMIAPP_REG_U8_BINNING_TYPE_n(n) SMIAPP_REG_MK_U8(0x1713 + (n)) /* 1 <= n <= 237 */
+#define SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY SMIAPP_REG_MK_U8(0x1800)
+#define SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY SMIAPP_REG_MK_U8(0x1900)
+#define SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY SMIAPP_REG_MK_U8(0x1901)
+#define SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY SMIAPP_REG_MK_U8(0x1902)
+#define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY SMIAPP_REG_MK_U8(0x1903)
+#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY SMIAPP_REG_MK_U16(0x1904)
+#define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2 SMIAPP_REG_MK_U16(0x1906)
+#define SMIAPP_REG_U8_EDOF_CAPABILITY SMIAPP_REG_MK_U8(0x1980)
+#define SMIAPP_REG_U8_ESTIMATION_FRAMES SMIAPP_REG_MK_U8(0x1981)
+#define SMIAPP_REG_U8_SUPPORTS_SHARPNESS_ADJ SMIAPP_REG_MK_U8(0x1982)
+#define SMIAPP_REG_U8_SUPPORTS_DENOISING_ADJ SMIAPP_REG_MK_U8(0x1983)
+#define SMIAPP_REG_U8_SUPPORTS_MODULE_SPECIFIC_ADJ SMIAPP_REG_MK_U8(0x1984)
+#define SMIAPP_REG_U8_SUPPORTS_DEPTH_OF_FIELD_ADJ SMIAPP_REG_MK_U8(0x1985)
+#define SMIAPP_REG_U8_SUPPORTS_FOCUS_DISTANCE_ADJ SMIAPP_REG_MK_U8(0x1986)
+#define SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY SMIAPP_REG_MK_U8(0x1987)
+#define SMIAPP_REG_U8_EDOF_SUPPORT_AB_NXM SMIAPP_REG_MK_U8(0x1988)
+#define SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY SMIAPP_REG_MK_U8(0x19c0)
+#define SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY SMIAPP_REG_MK_U8(0x19c1)
+#define SMIAPP_REG_U16_EST_DEPTH_OF_FIELD SMIAPP_REG_MK_U16(0x19c2)
+#define SMIAPP_REG_U16_EST_FOCUS_DISTANCE SMIAPP_REG_MK_U16(0x19c4)
+#define SMIAPP_REG_U16_CAPABILITY_TRDY_MIN SMIAPP_REG_MK_U16(0x1a00)
+#define SMIAPP_REG_U8_FLASH_MODE_CAPABILITY SMIAPP_REG_MK_U8(0x1a02)
+#define SMIAPP_REG_U16_MECH_SHUT_AND_ACT_START_ADDR SMIAPP_REG_MK_U16(0x1b02)
+#define SMIAPP_REG_U8_ACTUATOR_CAPABILITY SMIAPP_REG_MK_U8(0x1b04)
+#define SMIAPP_REG_U16_ACTUATOR_TYPE SMIAPP_REG_MK_U16(0x1b40)
+#define SMIAPP_REG_U8_AF_DEVICE_ADDRESS SMIAPP_REG_MK_U8(0x1b42)
+#define SMIAPP_REG_U16_FOCUS_CHANGE_ADDRESS SMIAPP_REG_MK_U16(0x1b44)
+#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1 SMIAPP_REG_MK_U8(0x1c00)
+#define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2 SMIAPP_REG_MK_U8(0x1c01)
+#define SMIAPP_REG_U8_BRACKETING_LUT_SIZE SMIAPP_REG_MK_U8(0x1c02)
diff --git a/drivers/media/video/smiapp/smiapp-reg.h b/drivers/media/video/smiapp/smiapp-reg.h
new file mode 100644
index 000000000000..d0167aa17534
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-reg.h
@@ -0,0 +1,122 @@
+/*
+ * drivers/media/video/smiapp/smiapp-reg.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __SMIAPP_REG_H_
+#define __SMIAPP_REG_H_
+
+#include "smiapp-reg-defs.h"
+
+/* Bits for above register */
+#define SMIAPP_IMAGE_ORIENTATION_HFLIP (1 << 0)
+#define SMIAPP_IMAGE_ORIENTATION_VFLIP (1 << 1)
+
+#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN (1 << 0)
+#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_RD_EN (0 << 1)
+#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_WR_EN (1 << 1)
+#define SMIAPP_DATA_TRANSFER_IF_1_CTRL_ERR_CLEAR (1 << 2)
+#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY (1 << 0)
+#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_WR_READY (1 << 1)
+#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EDATA (1 << 2)
+#define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EUSAGE (1 << 3)
+
+#define SMIAPP_SOFTWARE_RESET (1 << 0)
+
+#define SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE (1 << 0)
+#define SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE (1 << 1)
+
+#define SMIAPP_DPHY_CTRL_AUTOMATIC 0
+/* DPHY control based on REQUESTED_LINK_BIT_RATE_MBPS */
+#define SMIAPP_DPHY_CTRL_UI 1
+#define SMIAPP_DPHY_CTRL_REGISTER 2
+
+#define SMIAPP_COMPRESSION_MODE_SIMPLE_PREDICTOR 1
+#define SMIAPP_COMPRESSION_MODE_ADVANCED_PREDICTOR 2
+
+#define SMIAPP_MODE_SELECT_SOFTWARE_STANDBY 0
+#define SMIAPP_MODE_SELECT_STREAMING 1
+
+#define SMIAPP_SCALING_MODE_NONE 0
+#define SMIAPP_SCALING_MODE_HORIZONTAL 1
+#define SMIAPP_SCALING_MODE_BOTH 2
+
+#define SMIAPP_SCALING_CAPABILITY_NONE 0
+#define SMIAPP_SCALING_CAPABILITY_HORIZONTAL 1
+#define SMIAPP_SCALING_CAPABILITY_BOTH 2 /* horizontal/both */
+
+/* digital crop right before scaler */
+#define SMIAPP_DIGITAL_CROP_CAPABILITY_NONE 0
+#define SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP 1
+
+#define SMIAPP_BINNING_CAPABILITY_NO 0
+#define SMIAPP_BINNING_CAPABILITY_YES 1
+
+/* Maximum number of binning subtypes */
+#define SMIAPP_BINNING_SUBTYPES 253
+
+#define SMIAPP_PIXEL_ORDER_GRBG 0
+#define SMIAPP_PIXEL_ORDER_RGGB 1
+#define SMIAPP_PIXEL_ORDER_BGGR 2
+#define SMIAPP_PIXEL_ORDER_GBRG 3
+
+#define SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL 1
+#define SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED 2
+#define SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N 8
+#define SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED_N 16
+
+#define SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE 0x01
+#define SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE 0x02
+#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NROWS_MASK 0x0f
+#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_MASK 0xf0
+#define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_SHIFT 4
+
+#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_MASK 0xf000
+#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_SHIFT 12
+#define SMIAPP_FRAME_FORMAT_DESC_2_PIXELS_MASK 0x0fff
+
+#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_MASK 0xf0000000
+#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_SHIFT 28
+#define SMIAPP_FRAME_FORMAT_DESC_4_PIXELS_MASK 0x0000ffff
+
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED 1
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DUMMY 2
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_BLACK 3
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DARK 4
+#define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE 5
+
+#define SMIAPP_FAST_STANDBY_CTRL_COMPLETE_FRAMES 0
+#define SMIAPP_FAST_STANDBY_CTRL_IMMEDIATE 1
+
+/* Scaling N factor */
+#define SMIAPP_SCALE_N 16
+
+/* Image statistics registers */
+/* Registers 0x2000 to 0x2fff are reserved for future
+ * use for statistics features.
+ */
+
+/* Manufacturer Specific Registers: 0x3000 to 0x3fff
+ * The manufacturer specifies these as a black box.
+ */
+
+#endif /* __SMIAPP_REG_H_ */
diff --git a/drivers/media/video/smiapp/smiapp-regs.c b/drivers/media/video/smiapp/smiapp-regs.c
new file mode 100644
index 000000000000..b1812b17a407
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-regs.c
@@ -0,0 +1,273 @@
+/*
+ * drivers/media/video/smiapp/smiapp-regs.c
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+
+#include "smiapp.h"
+#include "smiapp-regs.h"
+
+static uint32_t float_to_u32_mul_1000000(struct i2c_client *client,
+ uint32_t phloat)
+{
+ int32_t exp;
+ uint64_t man;
+
+ if (phloat >= 0x80000000) {
+ dev_err(&client->dev, "this is a negative number\n");
+ return 0;
+ }
+
+ if (phloat == 0x7f800000)
+ return ~0; /* Inf. */
+
+ if ((phloat & 0x7f800000) == 0x7f800000) {
+ dev_err(&client->dev, "NaN or other special number\n");
+ return 0;
+ }
+
+ /* Valid cases begin here */
+ if (phloat == 0)
+ return 0; /* Valid zero */
+
+ if (phloat > 0x4f800000)
+ return ~0; /* larger than 4294967295 */
+
+ /*
+ * Unbias exponent (note how phloat is now guaranteed to
+ * have 0 in the high bit)
+ */
+ exp = ((int32_t)phloat >> 23) - 127;
+
+ /* Extract mantissa, add missing '1' bit and it's in MHz */
+ man = ((phloat & 0x7fffff) | 0x800000) * 1000000ULL;
+
+ if (exp < 0)
+ man >>= -exp;
+ else
+ man <<= exp;
+
+ man >>= 23; /* Remove mantissa bias */
+
+ return man & 0xffffffff;
+}
+
+
+/*
+ * Read a 8/16/32-bit i2c register. The value is returned in 'val'.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int ____smiapp_read(struct smiapp_sensor *sensor, u16 reg,
+ u16 len, u32 *val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ struct i2c_msg msg;
+ unsigned char data[4];
+ u16 offset = reg;
+ int r;
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = 2;
+ msg.buf = data;
+
+ /* high byte goes out first */
+ data[0] = (u8) (offset >> 8);
+ data[1] = (u8) offset;
+ r = i2c_transfer(client->adapter, &msg, 1);
+ if (r != 1) {
+ if (r >= 0)
+ r = -EBUSY;
+ goto err;
+ }
+
+ msg.len = len;
+ msg.flags = I2C_M_RD;
+ r = i2c_transfer(client->adapter, &msg, 1);
+ if (r != 1) {
+ if (r >= 0)
+ r = -EBUSY;
+ goto err;
+ }
+
+ *val = 0;
+ /* high byte comes first */
+ switch (len) {
+ case SMIA_REG_32BIT:
+ *val = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) +
+ data[3];
+ break;
+ case SMIA_REG_16BIT:
+ *val = (data[0] << 8) + data[1];
+ break;
+ case SMIA_REG_8BIT:
+ *val = data[0];
+ break;
+ default:
+ BUG();
+ }
+
+ return 0;
+
+err:
+ dev_err(&client->dev, "read from offset 0x%x error %d\n", offset, r);
+
+ return r;
+}
+
+/* Read a register using 8-bit access only. */
+static int ____smiapp_read_8only(struct smiapp_sensor *sensor, u16 reg,
+ u16 len, u32 *val)
+{
+ unsigned int i;
+ int rval;
+
+ *val = 0;
+
+ for (i = 0; i < len; i++) {
+ u32 val8;
+
+ rval = ____smiapp_read(sensor, reg + i, 1, &val8);
+ if (rval < 0)
+ return rval;
+ *val |= val8 << ((len - i - 1) << 3);
+ }
+
+ return 0;
+}
+
+/*
+ * Read a 8/16/32-bit i2c register. The value is returned in 'val'.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+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);
+ int rval;
+
+ if (len != SMIA_REG_8BIT && len != SMIA_REG_16BIT
+ && len != SMIA_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);
+ else
+ rval = ____smiapp_read_8only(sensor, (u16)reg, len, val);
+ if (rval < 0)
+ return rval;
+
+found_quirk:
+ if (reg & SMIA_REG_FLAG_FLOAT)
+ *val = float_to_u32_mul_1000000(client, *val);
+
+ return 0;
+}
+
+int smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val)
+{
+ return __smiapp_read(
+ sensor, reg, val,
+ smiapp_needs_quirk(sensor,
+ SMIAPP_QUIRK_FLAG_8BIT_READ_ONLY));
+}
+
+int smiapp_read_8only(struct smiapp_sensor *sensor, u32 reg, u32 *val)
+{
+ 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)
+{
+ 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;
+ int r;
+
+ if ((len != SMIA_REG_8BIT && len != SMIA_REG_16BIT &&
+ len != SMIA_REG_32BIT) || flags)
+ return -EINVAL;
+
+ msg.addr = client->addr;
+ msg.flags = 0; /* Write */
+ msg.len = 2 + len;
+ msg.buf = data;
+
+ /* high byte goes out first */
+ data[0] = (u8) (reg >> 8);
+ data[1] = (u8) (reg & 0xff);
+
+ switch (len) {
+ case SMIA_REG_8BIT:
+ data[2] = val;
+ break;
+ case SMIA_REG_16BIT:
+ data[2] = val >> 8;
+ data[3] = val;
+ break;
+ case SMIA_REG_32BIT:
+ data[2] = val >> 24;
+ data[3] = val >> 16;
+ data[4] = val >> 8;
+ data[5] = val;
+ break;
+ default:
+ BUG();
+ }
+
+ for (retries = 0; retries < 5; retries++) {
+ /*
+ * Due to unknown reason sensor stops responding. This
+ * loop is a temporaty solution until the root cause
+ * is found.
+ */
+ r = i2c_transfer(client->adapter, &msg, 1);
+ if (r == 1) {
+ if (retries)
+ dev_err(&client->dev,
+ "sensor i2c stall encountered. "
+ "retries: %d\n", retries);
+ return 0;
+ }
+
+ usleep_range(2000, 2000);
+ }
+
+ dev_err(&client->dev,
+ "wrote 0x%x to offset 0x%x error %d\n", val, offset, r);
+
+ return r;
+}
diff --git a/drivers/media/video/smiapp/smiapp-regs.h b/drivers/media/video/smiapp/smiapp-regs.h
new file mode 100644
index 000000000000..7f9013b47971
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-regs.h
@@ -0,0 +1,49 @@
+/*
+ * include/media/smiapp/smiapp-regs.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef SMIAPP_REGS_H
+#define SMIAPP_REGS_H
+
+#include <linux/i2c.h>
+#include <linux/types.h>
+
+/* Use upper 8 bits of the type field for flags */
+#define SMIA_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 */
+};
+
+struct smiapp_sensor;
+
+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(struct smiapp_sensor *sensor, u32 reg, u32 val);
+
+#endif
diff --git a/drivers/media/video/smiapp/smiapp.h b/drivers/media/video/smiapp/smiapp.h
new file mode 100644
index 000000000000..587f7f11238d
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp.h
@@ -0,0 +1,252 @@
+/*
+ * drivers/media/video/smiapp/smiapp.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2010--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __SMIAPP_PRIV_H_
+#define __SMIAPP_PRIV_H_
+
+#include <linux/mutex.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+#include <media/smiapp.h>
+
+#include "smiapp-pll.h"
+#include "smiapp-reg.h"
+#include "smiapp-regs.h"
+#include "smiapp-quirk.h"
+
+/*
+ * Standard SMIA++ constants
+ */
+#define SMIA_VERSION_1 10
+#define SMIAPP_VERSION_0_8 8 /* Draft 0.8 */
+#define SMIAPP_VERSION_0_9 9 /* Draft 0.9 */
+#define SMIAPP_VERSION_1 10
+
+#define SMIAPP_PROFILE_0 0
+#define SMIAPP_PROFILE_1 1
+#define SMIAPP_PROFILE_2 2
+
+#define SMIAPP_NVM_PAGE_SIZE 64 /* bytes */
+
+#define SMIAPP_RESET_DELAY_CLOCKS 2400
+#define SMIAPP_RESET_DELAY(clk) \
+ (1000 + (SMIAPP_RESET_DELAY_CLOCKS * 1000 \
+ + (clk) / 1000 - 1) / ((clk) / 1000))
+
+#include "smiapp-limits.h"
+
+struct smiapp_quirk;
+
+#define SMIAPP_MODULE_IDENT_FLAG_REV_LE (1 << 0)
+
+struct smiapp_module_ident {
+ u8 manufacturer_id;
+ u16 model_id;
+ u8 revision_number_major;
+
+ u8 flags;
+
+ char *name;
+ const struct smiapp_quirk *quirk;
+};
+
+struct smiapp_module_info {
+ u32 manufacturer_id;
+ u32 model_id;
+ u32 revision_number_major;
+ u32 revision_number_minor;
+
+ u32 module_year;
+ u32 module_month;
+ u32 module_day;
+
+ u32 sensor_manufacturer_id;
+ u32 sensor_model_id;
+ u32 sensor_revision_number;
+ u32 sensor_firmware_version;
+
+ u32 smia_version;
+ u32 smiapp_version;
+
+ u32 smiapp_profile;
+
+ char *name;
+ const struct smiapp_quirk *quirk;
+};
+
+#define SMIAPP_IDENT_FQ(manufacturer, model, rev, fl, _name, _quirk) \
+ { .manufacturer_id = manufacturer, \
+ .model_id = model, \
+ .revision_number_major = rev, \
+ .flags = fl, \
+ .name = _name, \
+ .quirk = _quirk, }
+
+#define SMIAPP_IDENT_LQ(manufacturer, model, rev, _name, _quirk) \
+ { .manufacturer_id = manufacturer, \
+ .model_id = model, \
+ .revision_number_major = rev, \
+ .flags = SMIAPP_MODULE_IDENT_FLAG_REV_LE, \
+ .name = _name, \
+ .quirk = _quirk, }
+
+#define SMIAPP_IDENT_L(manufacturer, model, rev, _name) \
+ { .manufacturer_id = manufacturer, \
+ .model_id = model, \
+ .revision_number_major = rev, \
+ .flags = SMIAPP_MODULE_IDENT_FLAG_REV_LE, \
+ .name = _name, }
+
+#define SMIAPP_IDENT_Q(manufacturer, model, rev, _name, _quirk) \
+ { .manufacturer_id = manufacturer, \
+ .model_id = model, \
+ .revision_number_major = rev, \
+ .flags = 0, \
+ .name = _name, \
+ .quirk = _quirk, }
+
+#define SMIAPP_IDENT(manufacturer, model, rev, _name) \
+ { .manufacturer_id = manufacturer, \
+ .model_id = model, \
+ .revision_number_major = rev, \
+ .flags = 0, \
+ .name = _name, }
+
+struct smiapp_reg_limits {
+ u32 addr;
+ char *what;
+};
+
+extern struct smiapp_reg_limits smiapp_reg_limits[];
+
+struct smiapp_csi_data_format {
+ u32 code;
+ u8 width;
+ u8 compressed;
+ u8 pixel_order;
+};
+
+#define SMIAPP_SUBDEVS 3
+
+#define SMIAPP_PA_PAD_SRC 0
+#define SMIAPP_PAD_SINK 0
+#define SMIAPP_PAD_SRC 1
+#define SMIAPP_PADS 2
+
+struct smiapp_binning_subtype {
+ u8 horizontal:4;
+ u8 vertical:4;
+} __packed;
+
+struct smiapp_subdev {
+ struct v4l2_subdev sd;
+ struct media_pad pads[2];
+ struct v4l2_rect sink_fmt;
+ struct v4l2_rect crop[2];
+ struct v4l2_rect compose; /* compose on sink */
+ unsigned short sink_pad;
+ unsigned short source_pad;
+ int npads;
+ struct smiapp_sensor *sensor;
+ struct v4l2_ctrl_handler ctrl_handler;
+};
+
+/*
+ * struct smiapp_sensor - Main device structure
+ */
+struct smiapp_sensor {
+ /*
+ * "mutex" is used to serialise access to all fields here
+ * except v4l2_ctrls at the end of the struct. "mutex" is also
+ * used to serialise access to file handle specific
+ * information. The exception to this rule is the power_mutex
+ * below.
+ */
+ struct mutex mutex;
+ /*
+ * power_mutex is used to serialise power management related
+ * activities. Acquiring "mutex" at that time isn't necessary
+ * since there are no other users anyway.
+ */
+ struct mutex power_mutex;
+ struct smiapp_subdev ssds[SMIAPP_SUBDEVS];
+ u32 ssds_used;
+ struct smiapp_subdev *src;
+ struct smiapp_subdev *binner;
+ struct smiapp_subdev *scaler;
+ struct smiapp_subdev *pixel_array;
+ struct smiapp_platform_data *platform_data;
+ struct regulator *vana;
+ struct clk *ext_clk;
+ u32 limits[SMIAPP_LIMIT_LAST];
+ u8 nbinning_subtypes;
+ struct smiapp_binning_subtype binning_subtypes[SMIAPP_BINNING_SUBTYPES];
+ u32 mbus_frame_fmts;
+ const struct smiapp_csi_data_format *csi_format;
+ const struct smiapp_csi_data_format *internal_csi_format;
+ u32 default_mbus_frame_fmts;
+ int default_pixel_order;
+
+ u8 binning_horizontal;
+ u8 binning_vertical;
+
+ u8 scale_m;
+ u8 scaling_mode;
+
+ u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */
+ u8 flash_capability;
+ u8 frame_skip;
+
+ int power_count;
+
+ bool streaming;
+ bool dev_init_done;
+
+ u8 *nvm; /* nvm memory buffer */
+ unsigned int nvm_size; /* bytes */
+
+ struct smiapp_module_info minfo;
+
+ struct smiapp_pll pll;
+
+ /* Pixel array controls */
+ struct v4l2_ctrl *analog_gain;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+ struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *pixel_rate_parray;
+ /* src controls */
+ struct v4l2_ctrl *link_freq;
+ struct v4l2_ctrl *pixel_rate_csi;
+};
+
+#define to_smiapp_subdev(_sd) \
+ container_of(_sd, struct smiapp_subdev, sd)
+
+#define to_smiapp_sensor(_sd) \
+ (to_smiapp_subdev(_sd)->sensor)
+
+#endif /* __SMIAPP_PRIV_H_ */
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index c2882fa5be85..19ea780b16ff 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -995,10 +995,8 @@ static int sn9c102_stop_transfer(struct sn9c102_device* cam)
static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
{
- long timeout;
-
cam->stream = STREAM_INTERRUPT;
- timeout = wait_event_timeout(cam->wait_stream,
+ wait_event_timeout(cam->wait_stream,
(cam->stream == STREAM_OFF) ||
(cam->state & DEV_DISCONNECTED),
SN9C102_URB_TIMEOUT);
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index aedb970d13f6..0421bf9453b4 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -164,35 +164,38 @@ static int soc_camera_try_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ const struct soc_camera_format_xlate *xlate;
struct v4l2_pix_format *pix = &f->fmt.pix;
int ret;
dev_dbg(icd->pdev, "TRY_FMT(%c%c%c%c, %ux%u)\n",
pixfmtstr(pix->pixelformat), pix->width, pix->height);
- pix->bytesperline = 0;
- pix->sizeimage = 0;
+ if (!(ici->capabilities & SOCAM_HOST_CAP_STRIDE)) {
+ pix->bytesperline = 0;
+ pix->sizeimage = 0;
+ }
ret = ici->ops->try_fmt(icd, f);
if (ret < 0)
return ret;
- if (!pix->sizeimage) {
- if (!pix->bytesperline) {
- const struct soc_camera_format_xlate *xlate;
+ xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+ if (!xlate)
+ return -EINVAL;
+
+ ret = soc_mbus_bytes_per_line(pix->width, xlate->host_fmt);
+ if (ret < 0)
+ return ret;
+
+ pix->bytesperline = max_t(u32, pix->bytesperline, ret);
- xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
- if (!xlate)
- return -EINVAL;
+ ret = soc_mbus_image_size(xlate->host_fmt, pix->bytesperline,
+ pix->height);
+ if (ret < 0)
+ return ret;
- ret = soc_mbus_bytes_per_line(pix->width,
- xlate->host_fmt);
- if (ret > 0)
- pix->bytesperline = ret;
- }
- if (pix->bytesperline)
- pix->sizeimage = pix->bytesperline * pix->height;
- }
+ pix->sizeimage = max_t(u32, pix->sizeimage, ret);
return 0;
}
@@ -257,13 +260,13 @@ static int soc_camera_g_std(struct file *file, void *priv, v4l2_std_id *a)
return v4l2_subdev_call(sd, core, g_std, a);
}
-static int soc_camera_enum_fsizes(struct file *file, void *fh,
+static int soc_camera_enum_framesizes(struct file *file, void *fh,
struct v4l2_frmsizeenum *fsize)
{
struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- return ici->ops->enum_fsizes(icd, fsize);
+ return ici->ops->enum_framesizes(icd, fsize);
}
static int soc_camera_reqbufs(struct file *file, void *priv,
@@ -1244,8 +1247,8 @@ static int default_s_parm(struct soc_camera_device *icd,
return v4l2_subdev_call(sd, video, s_parm, parm);
}
-static int default_enum_fsizes(struct soc_camera_device *icd,
- struct v4l2_frmsizeenum *fsize)
+static int default_enum_framesizes(struct soc_camera_device *icd,
+ struct v4l2_frmsizeenum *fsize)
{
int ret;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
@@ -1259,7 +1262,7 @@ static int default_enum_fsizes(struct soc_camera_device *icd,
/* map xlate-code to pixel_format, sensor only handle xlate-code*/
fsize_mbus.pixel_format = xlate->code;
- ret = v4l2_subdev_call(sd, video, enum_mbus_fsizes, &fsize_mbus);
+ ret = v4l2_subdev_call(sd, video, enum_framesizes, &fsize_mbus);
if (ret < 0)
return ret;
@@ -1298,8 +1301,8 @@ int soc_camera_host_register(struct soc_camera_host *ici)
ici->ops->set_parm = default_s_parm;
if (!ici->ops->get_parm)
ici->ops->get_parm = default_g_parm;
- if (!ici->ops->enum_fsizes)
- ici->ops->enum_fsizes = default_enum_fsizes;
+ if (!ici->ops->enum_framesizes)
+ ici->ops->enum_framesizes = default_enum_framesizes;
mutex_lock(&list_lock);
list_for_each_entry(ix, &hosts, list) {
@@ -1390,7 +1393,7 @@ static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {
.vidioc_s_input = soc_camera_s_input,
.vidioc_s_std = soc_camera_s_std,
.vidioc_g_std = soc_camera_g_std,
- .vidioc_enum_framesizes = soc_camera_enum_fsizes,
+ .vidioc_enum_framesizes = soc_camera_enum_framesizes,
.vidioc_reqbufs = soc_camera_reqbufs,
.vidioc_querybuf = soc_camera_querybuf,
.vidioc_qbuf = soc_camera_qbuf,
@@ -1429,6 +1432,10 @@ static int video_dev_create(struct soc_camera_device *icd)
vdev->tvnorms = V4L2_STD_UNKNOWN;
vdev->ctrl_handler = &icd->ctrl_handler;
vdev->lock = &icd->video_lock;
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags);
icd->vdev = vdev;
diff --git a/drivers/media/video/soc_mediabus.c b/drivers/media/video/soc_mediabus.c
index cf7f2194ded4..89dce097a827 100644
--- a/drivers/media/video/soc_mediabus.c
+++ b/drivers/media/video/soc_mediabus.c
@@ -24,6 +24,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_YVYU8_2X8,
@@ -33,6 +34,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_UYVY8_2X8,
@@ -42,6 +44,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_VYUY8_2X8,
@@ -51,6 +54,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
@@ -60,6 +64,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
@@ -69,6 +74,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_RGB565_2X8_LE,
@@ -78,6 +84,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_RGB565_2X8_BE,
@@ -87,6 +94,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_SBGGR8_1X8,
@@ -96,6 +104,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_NONE,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_SBGGR10_1X10,
@@ -105,6 +114,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 10,
.packing = SOC_MBUS_PACKING_EXTEND16,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_Y8_1X8,
@@ -114,6 +124,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_NONE,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_Y10_1X10,
@@ -123,6 +134,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 10,
.packing = SOC_MBUS_PACKING_EXTEND16,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,
@@ -132,6 +144,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
@@ -141,6 +154,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADLO,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
@@ -150,6 +164,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
@@ -159,6 +174,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADLO,
.order = SOC_MBUS_ORDER_BE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_JPEG_1X8,
@@ -168,6 +184,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_VARIABLE,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE,
@@ -177,6 +194,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_YUYV8_1_5X8,
@@ -186,6 +204,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_1_5X8,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_YVYU8_1_5X8,
@@ -195,6 +214,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_1_5X8,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_UYVY8_1X16,
@@ -204,6 +224,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 16,
.packing = SOC_MBUS_PACKING_EXTEND16,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_VYUY8_1X16,
@@ -213,6 +234,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 16,
.packing = SOC_MBUS_PACKING_EXTEND16,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_YUYV8_1X16,
@@ -222,6 +244,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 16,
.packing = SOC_MBUS_PACKING_EXTEND16,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_YVYU8_1X16,
@@ -231,6 +254,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 16,
.packing = SOC_MBUS_PACKING_EXTEND16,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_SGRBG8_1X8,
@@ -240,6 +264,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_NONE,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
@@ -249,6 +274,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_NONE,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_SGBRG10_1X10,
@@ -258,6 +284,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 10,
.packing = SOC_MBUS_PACKING_EXTEND16,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_SGRBG10_1X10,
@@ -267,6 +294,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 10,
.packing = SOC_MBUS_PACKING_EXTEND16,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_SRGGB10_1X10,
@@ -276,6 +304,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 10,
.packing = SOC_MBUS_PACKING_EXTEND16,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_SBGGR12_1X12,
@@ -285,6 +314,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 12,
.packing = SOC_MBUS_PACKING_EXTEND16,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_SGBRG12_1X12,
@@ -294,6 +324,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 12,
.packing = SOC_MBUS_PACKING_EXTEND16,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_SGRBG12_1X12,
@@ -303,6 +334,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 12,
.packing = SOC_MBUS_PACKING_EXTEND16,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
.code = V4L2_MBUS_FMT_SRGGB12_1X12,
@@ -312,6 +344,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.bits_per_sample = 12,
.packing = SOC_MBUS_PACKING_EXTEND16,
.order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
},
},
};
@@ -345,6 +378,9 @@ EXPORT_SYMBOL(soc_mbus_samples_per_pixel);
s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
{
+ if (mf->layout != SOC_MBUS_LAYOUT_PACKED)
+ return width * mf->bits_per_sample / 8;
+
switch (mf->packing) {
case SOC_MBUS_PACKING_NONE:
return width * mf->bits_per_sample / 8;
@@ -361,6 +397,24 @@ s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
}
EXPORT_SYMBOL(soc_mbus_bytes_per_line);
+s32 soc_mbus_image_size(const struct soc_mbus_pixelfmt *mf,
+ u32 bytes_per_line, u32 height)
+{
+ if (mf->layout == SOC_MBUS_LAYOUT_PACKED)
+ return bytes_per_line * height;
+
+ switch (mf->packing) {
+ case SOC_MBUS_PACKING_2X8_PADHI:
+ case SOC_MBUS_PACKING_2X8_PADLO:
+ return bytes_per_line * height * 2;
+ case SOC_MBUS_PACKING_1_5X8:
+ return bytes_per_line * height * 3 / 2;
+ default:
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(soc_mbus_image_size);
+
const struct soc_mbus_pixelfmt *soc_mbus_find_fmtdesc(
enum v4l2_mbus_pixelcode code,
const struct soc_mbus_lookup *lookup,
diff --git a/drivers/media/video/sta2x11_vip.c b/drivers/media/video/sta2x11_vip.c
new file mode 100644
index 000000000000..4c10205264d4
--- /dev/null
+++ b/drivers/media/video/sta2x11_vip.c
@@ -0,0 +1,1550 @@
+/*
+ * This is the driver for the STA2x11 Video Input Port.
+ *
+ * Copyright (C) 2010 WindRiver Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Author: Andreas Kies <andreas.kies@windriver.com>
+ * Vlad Lungu <vlad.lungu@windriver.com>
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+
+#include <linux/videodev2.h>
+
+#include <linux/kmod.h>
+
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf-dma-contig.h>
+
+#include "sta2x11_vip.h"
+
+#define DRV_NAME "sta2x11_vip"
+#define DRV_VERSION "1.3"
+
+#ifndef PCI_DEVICE_ID_STMICRO_VIP
+#define PCI_DEVICE_ID_STMICRO_VIP 0xCC0D
+#endif
+
+#define MAX_FRAMES 4
+
+/*Register offsets*/
+#define DVP_CTL 0x00
+#define DVP_TFO 0x04
+#define DVP_TFS 0x08
+#define DVP_BFO 0x0C
+#define DVP_BFS 0x10
+#define DVP_VTP 0x14
+#define DVP_VBP 0x18
+#define DVP_VMP 0x1C
+#define DVP_ITM 0x98
+#define DVP_ITS 0x9C
+#define DVP_STA 0xA0
+#define DVP_HLFLN 0xA8
+#define DVP_RGB 0xC0
+#define DVP_PKZ 0xF0
+
+/*Register fields*/
+#define DVP_CTL_ENA 0x00000001
+#define DVP_CTL_RST 0x80000000
+#define DVP_CTL_DIS (~0x00040001)
+
+#define DVP_IT_VSB 0x00000008
+#define DVP_IT_VST 0x00000010
+#define DVP_IT_FIFO 0x00000020
+
+#define DVP_HLFLN_SD 0x00000001
+
+#define REG_WRITE(vip, reg, value) iowrite32((value), (vip->iomem)+(reg))
+#define REG_READ(vip, reg) ioread32((vip->iomem)+(reg))
+
+#define SAVE_COUNT 8
+#define AUX_COUNT 3
+#define IRQ_COUNT 1
+
+/**
+ * struct sta2x11_vip - All internal data for one instance of device
+ * @v4l2_dev: device registered in v4l layer
+ * @video_dev: properties of our device
+ * @pdev: PCI device
+ * @adapter: contains I2C adapter information
+ * @register_save_area: All relevant register are saved here during suspend
+ * @decoder: contains information about video DAC
+ * @format: pixel format, fixed UYVY
+ * @std: video standard (e.g. PAL/NTSC)
+ * @input: input line for video signal ( 0 or 1 )
+ * @users: Number of open of device ( max. 1 )
+ * @disabled: Device is in power down state
+ * @mutex: ensures exclusive opening of device
+ * @slock: for excluse acces of registers
+ * @vb_vidq: queue maintained by videobuf layer
+ * @capture: linked list of capture buffer
+ * @active: struct videobuf_buffer currently beingg filled
+ * @started: device is ready to capture frame
+ * @closing: device will be shut down
+ * @tcount: Number of top frames
+ * @bcount: Number of bottom frames
+ * @overflow: Number of FIFO overflows
+ * @mem_spare: small buffer of unused frame
+ * @dma_spare: dma addres of mem_spare
+ * @iomem: hardware base address
+ * @config: I2C and gpio config from platform
+ *
+ * All non-local data is accessed via this structure.
+ */
+
+struct sta2x11_vip {
+ struct v4l2_device v4l2_dev;
+ struct video_device *video_dev;
+ struct pci_dev *pdev;
+ struct i2c_adapter *adapter;
+ unsigned int register_save_area[IRQ_COUNT + SAVE_COUNT + AUX_COUNT];
+ struct v4l2_subdev *decoder;
+ struct v4l2_pix_format format;
+ v4l2_std_id std;
+ unsigned int input;
+ int users;
+ int disabled;
+ struct mutex mutex; /* exclusive access during open */
+ spinlock_t slock; /* spin lock for hardware and queue access */
+ struct videobuf_queue vb_vidq;
+ struct list_head capture;
+ struct videobuf_buffer *active;
+ int started, closing, tcount, bcount;
+ int overflow;
+ void *mem_spare;
+ dma_addr_t dma_spare;
+ void *iomem;
+ struct vip_config *config;
+};
+
+static const unsigned int registers_to_save[AUX_COUNT] = {
+ DVP_HLFLN, DVP_RGB, DVP_PKZ
+};
+
+static struct v4l2_pix_format formats_50[] = {
+ { /*PAL interlaced */
+ .width = 720,
+ .height = 576,
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .field = V4L2_FIELD_INTERLACED,
+ .bytesperline = 720 * 2,
+ .sizeimage = 720 * 2 * 576,
+ .colorspace = V4L2_COLORSPACE_SMPTE170M},
+ { /*PAL top */
+ .width = 720,
+ .height = 288,
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .field = V4L2_FIELD_TOP,
+ .bytesperline = 720 * 2,
+ .sizeimage = 720 * 2 * 288,
+ .colorspace = V4L2_COLORSPACE_SMPTE170M},
+ { /*PAL bottom */
+ .width = 720,
+ .height = 288,
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .field = V4L2_FIELD_BOTTOM,
+ .bytesperline = 720 * 2,
+ .sizeimage = 720 * 2 * 288,
+ .colorspace = V4L2_COLORSPACE_SMPTE170M},
+
+};
+
+static struct v4l2_pix_format formats_60[] = {
+ { /*NTSC interlaced */
+ .width = 720,
+ .height = 480,
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .field = V4L2_FIELD_INTERLACED,
+ .bytesperline = 720 * 2,
+ .sizeimage = 720 * 2 * 480,
+ .colorspace = V4L2_COLORSPACE_SMPTE170M},
+ { /*NTSC top */
+ .width = 720,
+ .height = 240,
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .field = V4L2_FIELD_TOP,
+ .bytesperline = 720 * 2,
+ .sizeimage = 720 * 2 * 240,
+ .colorspace = V4L2_COLORSPACE_SMPTE170M},
+ { /*NTSC bottom */
+ .width = 720,
+ .height = 240,
+ .pixelformat = V4L2_PIX_FMT_UYVY,
+ .field = V4L2_FIELD_BOTTOM,
+ .bytesperline = 720 * 2,
+ .sizeimage = 720 * 2 * 240,
+ .colorspace = V4L2_COLORSPACE_SMPTE170M},
+};
+
+/**
+ * buf_setup - Get size and number of video buffer
+ * @vq: queue in videobuf
+ * @count: Number of buffers (1..MAX_FRAMES).
+ * 0 use default value.
+ * @size: size of buffer in bytes
+ *
+ * returns size and number of buffers
+ * a preset value of 0 returns the default number.
+ * return value: 0, always succesfull.
+ */
+static int buf_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct sta2x11_vip *vip = vq->priv_data;
+
+ *size = vip->format.width * vip->format.height * 2;
+ if (0 == *count || MAX_FRAMES < *count)
+ *count = MAX_FRAMES;
+ return 0;
+};
+
+/**
+ * buf_prepare - prepare buffer for usage
+ * @vq: queue in videobuf layer
+ * @vb: buffer to be prepared
+ * @field: type of video data (interlaced/non-interlaced)
+ *
+ * Allocate or realloc buffer
+ * return value: 0, successful.
+ *
+ * -EINVAL, supplied buffer is too small.
+ *
+ * other, buffer could not be locked.
+ */
+static int buf_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct sta2x11_vip *vip = vq->priv_data;
+ int ret;
+
+ vb->size = vip->format.width * vip->format.height * 2;
+ if ((0 != vb->baddr) && (vb->bsize < vb->size))
+ return -EINVAL;
+ vb->width = vip->format.width;
+ vb->height = vip->format.height;
+ vb->field = field;
+
+ if (VIDEOBUF_NEEDS_INIT == vb->state) {
+ ret = videobuf_iolock(vq, vb, NULL);
+ if (ret)
+ goto fail;
+ }
+ vb->state = VIDEOBUF_PREPARED;
+ return 0;
+fail:
+ videobuf_dma_contig_free(vq, vb);
+ vb->state = VIDEOBUF_NEEDS_INIT;
+ return ret;
+}
+
+/**
+ * buf_queu - queue buffer for filling
+ * @vq: queue in videobuf layer
+ * @vb: buffer to be queued
+ *
+ * if capturing is already running, the buffer will be queued. Otherwise
+ * capture is started and the buffer is used directly.
+ */
+static void buf_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct sta2x11_vip *vip = vq->priv_data;
+ u32 dma;
+
+ vb->state = VIDEOBUF_QUEUED;
+
+ if (vip->active) {
+ list_add_tail(&vb->queue, &vip->capture);
+ return;
+ }
+
+ vip->started = 1;
+ vip->tcount = 0;
+ vip->bcount = 0;
+ vip->active = vb;
+ vb->state = VIDEOBUF_ACTIVE;
+
+ dma = videobuf_to_dma_contig(vb);
+
+ REG_WRITE(vip, DVP_TFO, (0 << 16) | (0));
+ /* despite of interlace mode, upper and lower frames start at zero */
+ REG_WRITE(vip, DVP_BFO, (0 << 16) | (0));
+
+ switch (vip->format.field) {
+ case V4L2_FIELD_INTERLACED:
+ REG_WRITE(vip, DVP_TFS,
+ ((vip->format.height / 2 - 1) << 16) |
+ (2 * vip->format.width - 1));
+ REG_WRITE(vip, DVP_BFS, ((vip->format.height / 2 - 1) << 16) |
+ (2 * vip->format.width - 1));
+ REG_WRITE(vip, DVP_VTP, dma);
+ REG_WRITE(vip, DVP_VBP, dma + vip->format.width * 2);
+ REG_WRITE(vip, DVP_VMP, 4 * vip->format.width);
+ break;
+ case V4L2_FIELD_TOP:
+ REG_WRITE(vip, DVP_TFS,
+ ((vip->format.height - 1) << 16) |
+ (2 * vip->format.width - 1));
+ REG_WRITE(vip, DVP_BFS, ((0) << 16) |
+ (2 * vip->format.width - 1));
+ REG_WRITE(vip, DVP_VTP, dma);
+ REG_WRITE(vip, DVP_VBP, dma);
+ REG_WRITE(vip, DVP_VMP, 2 * vip->format.width);
+ break;
+ case V4L2_FIELD_BOTTOM:
+ REG_WRITE(vip, DVP_TFS, ((0) << 16) |
+ (2 * vip->format.width - 1));
+ REG_WRITE(vip, DVP_BFS,
+ ((vip->format.height) << 16) |
+ (2 * vip->format.width - 1));
+ REG_WRITE(vip, DVP_VTP, dma);
+ REG_WRITE(vip, DVP_VBP, dma);
+ REG_WRITE(vip, DVP_VMP, 2 * vip->format.width);
+ break;
+
+ default:
+ pr_warning("VIP: unknown field format\n");
+ return;
+ }
+
+ REG_WRITE(vip, DVP_CTL, DVP_CTL_ENA);
+}
+
+/**
+ * buff_release - release buffer
+ * @vq: queue in videobuf layer
+ * @vb: buffer to be released
+ *
+ * release buffer in videobuf layer
+ */
+static void buf_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+
+ videobuf_dma_contig_free(vq, vb);
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static struct videobuf_queue_ops vip_qops = {
+ .buf_setup = buf_setup,
+ .buf_prepare = buf_prepare,
+ .buf_queue = buf_queue,
+ .buf_release = buf_release,
+};
+
+/**
+ * vip_open - open video device
+ * @file: descriptor of device
+ *
+ * open device, make sure it is only opened once.
+ * return value: 0, no error.
+ *
+ * -EBUSY, device is already opened
+ *
+ * -ENOMEM, no memory for auxiliary DMA buffer
+ */
+static int vip_open(struct file *file)
+{
+ struct video_device *dev = video_devdata(file);
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+ mutex_lock(&vip->mutex);
+ vip->users++;
+
+ if (vip->users > 1) {
+ vip->users--;
+ mutex_unlock(&vip->mutex);
+ return -EBUSY;
+ }
+
+ file->private_data = dev;
+ vip->overflow = 0;
+ vip->started = 0;
+ vip->closing = 0;
+ vip->active = NULL;
+
+ INIT_LIST_HEAD(&vip->capture);
+ vip->mem_spare = dma_alloc_coherent(&vip->pdev->dev, 64,
+ &vip->dma_spare, GFP_KERNEL);
+ if (!vip->mem_spare) {
+ vip->users--;
+ mutex_unlock(&vip->mutex);
+ return -ENOMEM;
+ }
+
+ mutex_unlock(&vip->mutex);
+ videobuf_queue_dma_contig_init_cached(&vip->vb_vidq,
+ &vip_qops,
+ &vip->pdev->dev,
+ &vip->slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_INTERLACED,
+ sizeof(struct videobuf_buffer),
+ vip, NULL);
+ REG_READ(vip, DVP_ITS);
+ REG_WRITE(vip, DVP_HLFLN, DVP_HLFLN_SD);
+ REG_WRITE(vip, DVP_ITM, DVP_IT_VSB | DVP_IT_VST);
+ REG_WRITE(vip, DVP_CTL, DVP_CTL_RST);
+ REG_WRITE(vip, DVP_CTL, 0);
+ REG_READ(vip, DVP_ITS);
+ return 0;
+}
+
+/**
+ * vip_close - close video device
+ * @file: descriptor of device
+ *
+ * close video device, wait until all pending operations are finished
+ * ( maximum FRAME_MAX buffers pending )
+ * Turn off interrupts.
+ *
+ * return value: 0, always succesful.
+ */
+static int vip_close(struct file *file)
+{
+ struct video_device *dev = video_devdata(file);
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+ vip->closing = 1;
+ if (vip->active)
+ videobuf_waiton(&vip->vb_vidq, vip->active, 0, 0);
+ spin_lock_irq(&vip->slock);
+
+ REG_WRITE(vip, DVP_ITM, 0);
+ REG_WRITE(vip, DVP_CTL, DVP_CTL_RST);
+ REG_WRITE(vip, DVP_CTL, 0);
+ REG_READ(vip, DVP_ITS);
+
+ vip->started = 0;
+ vip->active = NULL;
+
+ spin_unlock_irq(&vip->slock);
+
+ videobuf_stop(&vip->vb_vidq);
+ videobuf_mmap_free(&vip->vb_vidq);
+
+ dma_free_coherent(&vip->pdev->dev, 64, vip->mem_spare, vip->dma_spare);
+ file->private_data = NULL;
+ mutex_lock(&vip->mutex);
+ vip->users--;
+ mutex_unlock(&vip->mutex);
+ return 0;
+}
+
+/**
+ * vip_read - read from video input
+ * @file: descriptor of device
+ * @data: user buffer
+ * @count: number of bytes to be read
+ * @ppos: position within stream
+ *
+ * read video data from video device.
+ * handling is done in generic videobuf layer
+ * return value: provided by videobuf layer
+ */
+static ssize_t vip_read(struct file *file, char __user *data,
+ size_t count, loff_t *ppos)
+{
+ struct video_device *dev = file->private_data;
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+ return videobuf_read_stream(&vip->vb_vidq, data, count, ppos, 0,
+ file->f_flags & O_NONBLOCK);
+}
+
+/**
+ * vip_mmap - map user buffer
+ * @file: descriptor of device
+ * @vma: user buffer
+ *
+ * map user space buffer into kernel mode, including DMA address.
+ * handling is done in generic videobuf layer.
+ * return value: provided by videobuf layer
+ */
+static int vip_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct video_device *dev = file->private_data;
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+ return videobuf_mmap_mapper(&vip->vb_vidq, vma);
+}
+
+/**
+ * vip_poll - poll for event
+ * @file: descriptor of device
+ * @wait: contains events to be waited for
+ *
+ * wait for event related to video device.
+ * handling is done in generic videobuf layer.
+ * return value: provided by videobuf layer
+ */
+static unsigned int vip_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct video_device *dev = file->private_data;
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+ return videobuf_poll_stream(file, &vip->vb_vidq, wait);
+}
+
+/**
+ * vidioc_querycap - return capabilities of device
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @cap: contains return values
+ *
+ * the capabilities of the device are returned
+ *
+ * return value: 0, no error.
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct video_device *dev = priv;
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+ memset(cap, 0, sizeof(struct v4l2_capability));
+ strcpy(cap->driver, DRV_NAME);
+ strcpy(cap->card, DRV_NAME);
+ cap->version = 0;
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
+ pci_name(vip->pdev));
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING;
+
+ return 0;
+}
+
+/**
+ * vidioc_s_std - set video standard
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @std: contains standard to be set
+ *
+ * the video standard is set
+ *
+ * return value: 0, no error.
+ *
+ * -EIO, no input signal detected
+ *
+ * other, returned from video DAC.
+ */
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct video_device *dev = priv;
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+ v4l2_std_id oldstd = vip->std, newstd;
+ int status;
+
+ if (V4L2_STD_ALL == *std) {
+ v4l2_subdev_call(vip->decoder, core, s_std, *std);
+ ssleep(2);
+ v4l2_subdev_call(vip->decoder, video, querystd, &newstd);
+ v4l2_subdev_call(vip->decoder, video, g_input_status, &status);
+ if (status & V4L2_IN_ST_NO_SIGNAL)
+ return -EIO;
+ *std = vip->std = newstd;
+ if (oldstd != *std) {
+ if (V4L2_STD_525_60 & (*std))
+ vip->format = formats_60[0];
+ else
+ vip->format = formats_50[0];
+ }
+ return 0;
+ }
+
+ if (oldstd != *std) {
+ if (V4L2_STD_525_60 & (*std))
+ vip->format = formats_60[0];
+ else
+ vip->format = formats_50[0];
+ }
+
+ return v4l2_subdev_call(vip->decoder, core, s_std, *std);
+}
+
+/**
+ * vidioc_g_std - get video standard
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @std: contains return values
+ *
+ * the current video standard is returned
+ *
+ * return value: 0, no error.
+ */
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct video_device *dev = priv;
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+ *std = vip->std;
+ return 0;
+}
+
+/**
+ * vidioc_querystd - get possible video standards
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @std: contains return values
+ *
+ * all possible video standards are returned
+ *
+ * return value: delivered by video DAC routine.
+ */
+static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct video_device *dev = priv;
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+ return v4l2_subdev_call(vip->decoder, video, querystd, std);
+
+}
+
+/**
+ * vidioc_queryctl - get possible control settings
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @ctrl: contains return values
+ *
+ * return possible values for a control
+ * return value: delivered by video DAC routine.
+ */
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *ctrl)
+{
+ struct video_device *dev = priv;
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+ return v4l2_subdev_call(vip->decoder, core, queryctrl, ctrl);
+}
+
+/**
+ * vidioc_g_ctl - get control value
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @ctrl: contains return values
+ *
+ * return setting for a control value
+ * return value: delivered by video DAC routine.
+ */
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct video_device *dev = priv;
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+ return v4l2_subdev_call(vip->decoder, core, g_ctrl, ctrl);
+}
+
+/**
+ * vidioc_s_ctl - set control value
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @ctrl: contains value to be set
+ *
+ * set value for a specific control
+ * return value: delivered by video DAC routine.
+ */
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct video_device *dev = priv;
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+ return v4l2_subdev_call(vip->decoder, core, s_ctrl, ctrl);
+}
+
+/**
+ * vidioc_enum_input - return name of input line
+ * @file: descriptor of device (not used)
+ * @priv: points to current videodevice
+ * @inp: contains return values
+ *
+ * the user friendly name of the input line is returned
+ *
+ * return value: 0, no error.
+ *
+ * -EINVAL, input line number out of range
+ */
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ if (inp->index > 1)
+ return -EINVAL;
+
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ inp->std = V4L2_STD_ALL;
+ sprintf(inp->name, "Camera %u", inp->index);
+
+ return 0;
+}
+
+/**
+ * vidioc_s_input - set input line
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @i: new input line number
+ *
+ * the current active input line is set
+ *
+ * return value: 0, no error.
+ *
+ * -EINVAL, line number out of range
+ */
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct video_device *dev = priv;
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+ int ret;
+
+ if (i > 1)
+ return -EINVAL;
+ ret = v4l2_subdev_call(vip->decoder, video, s_routing, i, 0, 0);
+
+ if (!ret)
+ vip->input = i;
+
+ return 0;
+}
+
+/**
+ * vidioc_g_input - return input line
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @i: returned input line number
+ *
+ * the current active input line is returned
+ *
+ * return value: always 0.
+ */
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ struct video_device *dev = priv;
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+ *i = vip->input;
+ return 0;
+}
+
+/**
+ * vidioc_enum_fmt_vid_cap - return video capture format
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @f: returned format information
+ *
+ * returns name and format of video capture
+ * Only UYVY is supported by hardware.
+ *
+ * return value: always 0.
+ */
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+
+ if (f->index != 0)
+ return -EINVAL;
+
+ strcpy(f->description, "4:2:2, packed, UYVY");
+ f->pixelformat = V4L2_PIX_FMT_UYVY;
+ f->flags = 0;
+ return 0;
+}
+
+/**
+ * vidioc_try_fmt_vid_cap - set video capture format
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @f: new format
+ *
+ * new video format is set which includes width and
+ * field type. width is fixed to 720, no scaling.
+ * Only UYVY is supported by this hardware.
+ * the minimum height is 200, the maximum is 576 (PAL)
+ *
+ * return value: 0, no error
+ *
+ * -EINVAL, pixel or field format not supported
+ *
+ */
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct video_device *dev = priv;
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+ int interlace_lim;
+
+ if (V4L2_PIX_FMT_UYVY != f->fmt.pix.pixelformat)
+ return -EINVAL;
+
+ if (V4L2_STD_525_60 & vip->std)
+ interlace_lim = 240;
+ else
+ interlace_lim = 288;
+
+ switch (f->fmt.pix.field) {
+ case V4L2_FIELD_ANY:
+ if (interlace_lim < f->fmt.pix.height)
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ else
+ f->fmt.pix.field = V4L2_FIELD_BOTTOM;
+ break;
+ case V4L2_FIELD_TOP:
+ case V4L2_FIELD_BOTTOM:
+ if (interlace_lim < f->fmt.pix.height)
+ f->fmt.pix.height = interlace_lim;
+ break;
+ case V4L2_FIELD_INTERLACED:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ f->fmt.pix.height &= ~1;
+ if (2 * interlace_lim < f->fmt.pix.height)
+ f->fmt.pix.height = 2 * interlace_lim;
+ if (200 > f->fmt.pix.height)
+ f->fmt.pix.height = 200;
+ f->fmt.pix.width = 720;
+ f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+ f->fmt.pix.sizeimage = f->fmt.pix.width * 2 * f->fmt.pix.height;
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ f->fmt.pix.priv = 0;
+ return 0;
+}
+
+/**
+ * vidioc_s_fmt_vid_cap - set current video format parameters
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @f: returned format information
+ *
+ * set new capture format
+ * return value: 0, no error
+ *
+ * other, delivered by video DAC routine.
+ */
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct video_device *dev = priv;
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+ int ret;
+
+ ret = vidioc_try_fmt_vid_cap(file, priv, f);
+ if (ret)
+ return ret;
+
+ memcpy(&vip->format, &f->fmt.pix, sizeof(struct v4l2_pix_format));
+ return 0;
+}
+
+/**
+ * vidioc_g_fmt_vid_cap - get current video format parameters
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @f: contains format information
+ *
+ * returns current video format parameters
+ *
+ * return value: 0, always successful
+ */
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct video_device *dev = priv;
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+ memcpy(&f->fmt.pix, &vip->format, sizeof(struct v4l2_pix_format));
+ return 0;
+}
+
+/**
+ * vidioc_reqfs - request buffer
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @p: video buffer
+ *
+ * Handling is done in generic videobuf layer.
+ */
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ struct video_device *dev = priv;
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+ return videobuf_reqbufs(&vip->vb_vidq, p);
+}
+
+/**
+ * vidioc_querybuf - query buffer
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @p: video buffer
+ *
+ * query buffer state.
+ * Handling is done in generic videobuf layer.
+ */
+static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct video_device *dev = priv;
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+ return videobuf_querybuf(&vip->vb_vidq, p);
+}
+
+/**
+ * vidioc_qbuf - queue a buffer
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @p: video buffer
+ *
+ * Handling is done in generic videobuf layer.
+ */
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct video_device *dev = priv;
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+ return videobuf_qbuf(&vip->vb_vidq, p);
+}
+
+/**
+ * vidioc_dqbuf - dequeue a buffer
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @p: video buffer
+ *
+ * Handling is done in generic videobuf layer.
+ */
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct video_device *dev = priv;
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+ return videobuf_dqbuf(&vip->vb_vidq, p, file->f_flags & O_NONBLOCK);
+}
+
+/**
+ * vidioc_streamon - turn on streaming
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @type: type of capture
+ *
+ * turn on streaming.
+ * Handling is done in generic videobuf layer.
+ */
+static int vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct video_device *dev = priv;
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+ return videobuf_streamon(&vip->vb_vidq);
+}
+
+/**
+ * vidioc_streamoff - turn off streaming
+ * @file: descriptor of device ( not used)
+ * @priv: points to current videodevice
+ * @type: type of capture
+ *
+ * turn off streaming.
+ * Handling is done in generic videobuf layer.
+ */
+static int vidioc_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct video_device *dev = priv;
+ struct sta2x11_vip *vip = video_get_drvdata(dev);
+
+ return videobuf_streamoff(&vip->vb_vidq);
+}
+
+static const struct v4l2_file_operations vip_fops = {
+ .owner = THIS_MODULE,
+ .open = vip_open,
+ .release = vip_close,
+ .ioctl = video_ioctl2,
+ .read = vip_read,
+ .mmap = vip_mmap,
+ .poll = vip_poll
+};
+
+static const struct v4l2_ioctl_ops vip_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_g_std = vidioc_g_std,
+ .vidioc_querystd = vidioc_querystd,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+};
+
+static struct video_device video_dev_template = {
+ .name = DRV_NAME,
+ .release = video_device_release,
+ .fops = &vip_fops,
+ .ioctl_ops = &vip_ioctl_ops,
+ .tvnorms = V4L2_STD_ALL,
+};
+
+/**
+ * vip_irq - interrupt routine
+ * @irq: Number of interrupt ( not used, correct number is assumed )
+ * @vip: local data structure containing all information
+ *
+ * check for both frame interrupts set ( top and bottom ).
+ * check FIFO overflow, but limit number of log messages after open.
+ * signal a complete buffer if done.
+ * dequeue a new buffer if available.
+ * disable VIP if no buffer available.
+ *
+ * return value: IRQ_NONE, interrupt was not generated by VIP
+ *
+ * IRQ_HANDLED, interrupt done.
+ */
+static irqreturn_t vip_irq(int irq, struct sta2x11_vip *vip)
+{
+ u32 status, dma;
+ unsigned long flags;
+ struct videobuf_buffer *vb;
+
+ status = REG_READ(vip, DVP_ITS);
+
+ if (!status) {
+ pr_debug("VIP: irq ignored\n");
+ return IRQ_NONE;
+ }
+
+ if (!vip->started)
+ return IRQ_HANDLED;
+
+ if (status & DVP_IT_VSB)
+ vip->bcount++;
+
+ if (status & DVP_IT_VST)
+ vip->tcount++;
+
+ if ((DVP_IT_VSB | DVP_IT_VST) == (status & (DVP_IT_VST | DVP_IT_VSB))) {
+ /* this is bad, we are too slow, hope the condition is gone
+ * on the next frame */
+ pr_info("VIP: both irqs\n");
+ return IRQ_HANDLED;
+ }
+
+ if (status & DVP_IT_FIFO) {
+ if (5 > vip->overflow++)
+ pr_info("VIP: fifo overflow\n");
+ }
+
+ if (2 > vip->tcount)
+ return IRQ_HANDLED;
+
+ if (status & DVP_IT_VSB)
+ return IRQ_HANDLED;
+
+ spin_lock_irqsave(&vip->slock, flags);
+
+ REG_WRITE(vip, DVP_CTL, REG_READ(vip, DVP_CTL) & ~DVP_CTL_ENA);
+ if (vip->active) {
+ do_gettimeofday(&vip->active->ts);
+ vip->active->field_count++;
+ vip->active->state = VIDEOBUF_DONE;
+ wake_up(&vip->active->done);
+ vip->active = NULL;
+ }
+ if (!vip->closing) {
+ if (list_empty(&vip->capture))
+ goto done;
+
+ vb = list_first_entry(&vip->capture, struct videobuf_buffer,
+ queue);
+ if (NULL == vb) {
+ pr_info("VIP: no buffer\n");
+ goto done;
+ }
+ vb->state = VIDEOBUF_ACTIVE;
+ list_del(&vb->queue);
+ vip->active = vb;
+ dma = videobuf_to_dma_contig(vb);
+ switch (vip->format.field) {
+ case V4L2_FIELD_INTERLACED:
+ REG_WRITE(vip, DVP_VTP, dma);
+ REG_WRITE(vip, DVP_VBP, dma + vip->format.width * 2);
+ break;
+ case V4L2_FIELD_TOP:
+ case V4L2_FIELD_BOTTOM:
+ REG_WRITE(vip, DVP_VTP, dma);
+ REG_WRITE(vip, DVP_VBP, dma);
+ break;
+ default:
+ pr_warning("VIP: unknown field format\n");
+ goto done;
+ break;
+ }
+ REG_WRITE(vip, DVP_CTL, REG_READ(vip, DVP_CTL) | DVP_CTL_ENA);
+ }
+done:
+ spin_unlock_irqrestore(&vip->slock, flags);
+ return IRQ_HANDLED;
+}
+
+/**
+ * vip_gpio_reserve - reserve gpio pin
+ * @dev: device
+ * @pin: GPIO pin number
+ * @dir: direction, input or output
+ * @name: GPIO pin name
+ *
+ */
+static int vip_gpio_reserve(struct device *dev, int pin, int dir,
+ const char *name)
+{
+ int ret;
+
+ if (pin == -1)
+ return 0;
+
+ ret = gpio_request(pin, name);
+ if (ret) {
+ dev_err(dev, "Failed to allocate pin %d (%s)\n", pin, name);
+ return ret;
+ }
+
+ ret = gpio_direction_output(pin, dir);
+ if (ret) {
+ dev_err(dev, "Failed to set direction for pin %d (%s)\n",
+ pin, name);
+ gpio_free(pin);
+ return ret;
+ }
+
+ ret = gpio_export(pin, false);
+ if (ret) {
+ dev_err(dev, "Failed to export pin %d (%s)\n", pin, name);
+ gpio_free(pin);
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * vip_gpio_release - release gpio pin
+ * @dev: device
+ * @pin: GPIO pin number
+ * @name: GPIO pin name
+ *
+ */
+static void vip_gpio_release(struct device *dev, int pin, const char *name)
+{
+ if (pin != -1) {
+ dev_dbg(dev, "releasing pin %d (%s)\n", pin, name);
+ gpio_unexport(pin);
+ gpio_free(pin);
+ }
+}
+
+/**
+ * sta2x11_vip_init_one - init one instance of video device
+ * @pdev: PCI device
+ * @ent: (not used)
+ *
+ * allocate reset pins for DAC.
+ * Reset video DAC, this is done via reset line.
+ * allocate memory for managing device
+ * request interrupt
+ * map IO region
+ * register device
+ * find and initialize video DAC
+ *
+ * return value: 0, no error
+ *
+ * -ENOMEM, no memory
+ *
+ * -ENODEV, device could not be detected or registered
+ */
+static int __devinit sta2x11_vip_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int ret;
+ struct sta2x11_vip *vip;
+ struct vip_config *config;
+
+ ret = pci_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ config = dev_get_platdata(&pdev->dev);
+ if (!config) {
+ dev_info(&pdev->dev, "VIP slot disabled\n");
+ ret = -EINVAL;
+ goto disable;
+ }
+
+ ret = vip_gpio_reserve(&pdev->dev, config->pwr_pin, 0,
+ config->pwr_name);
+ if (ret)
+ goto disable;
+
+ if (config->reset_pin >= 0) {
+ ret = vip_gpio_reserve(&pdev->dev, config->reset_pin, 0,
+ config->reset_name);
+ if (ret) {
+ vip_gpio_release(&pdev->dev, config->pwr_pin,
+ config->pwr_name);
+ goto disable;
+ }
+ }
+
+ if (config->pwr_pin != -1) {
+ /* Datasheet says 5ms between PWR and RST */
+ usleep_range(5000, 25000);
+ ret = gpio_direction_output(config->pwr_pin, 1);
+ }
+
+ if (config->reset_pin != -1) {
+ /* Datasheet says 5ms between PWR and RST */
+ usleep_range(5000, 25000);
+ ret = gpio_direction_output(config->reset_pin, 1);
+ }
+ usleep_range(5000, 25000);
+
+ vip = kzalloc(sizeof(struct sta2x11_vip), GFP_KERNEL);
+ if (!vip) {
+ ret = -ENOMEM;
+ goto release_gpios;
+ }
+
+ vip->pdev = pdev;
+ vip->std = V4L2_STD_PAL;
+ vip->format = formats_50[0];
+ vip->config = config;
+
+ if (v4l2_device_register(&pdev->dev, &vip->v4l2_dev))
+ goto free_mem;
+
+ dev_dbg(&pdev->dev, "BAR #0 at 0x%lx 0x%lx irq %d\n",
+ (unsigned long)pci_resource_start(pdev, 0),
+ (unsigned long)pci_resource_len(pdev, 0), pdev->irq);
+
+ pci_set_master(pdev);
+
+ ret = pci_request_regions(pdev, DRV_NAME);
+ if (ret)
+ goto unreg;
+
+ vip->iomem = pci_iomap(pdev, 0, 0x100);
+ if (!vip->iomem) {
+ ret = -ENOMEM; /* FIXME */
+ goto release;
+ }
+
+ pci_enable_msi(pdev);
+
+ INIT_LIST_HEAD(&vip->capture);
+ spin_lock_init(&vip->slock);
+ mutex_init(&vip->mutex);
+ vip->started = 0;
+ vip->disabled = 0;
+
+ ret = request_irq(pdev->irq,
+ (irq_handler_t) vip_irq,
+ IRQF_SHARED, DRV_NAME, vip);
+ if (ret) {
+ dev_err(&pdev->dev, "request_irq failed\n");
+ ret = -ENODEV;
+ goto unmap;
+ }
+
+ vip->video_dev = video_device_alloc();
+ if (!vip->video_dev) {
+ ret = -ENOMEM;
+ goto release_irq;
+ }
+
+ *(vip->video_dev) = video_dev_template;
+ video_set_drvdata(vip->video_dev, vip);
+
+ ret = video_register_device(vip->video_dev, VFL_TYPE_GRABBER, -1);
+ if (ret)
+ goto vrelease;
+
+ vip->adapter = i2c_get_adapter(vip->config->i2c_id);
+ if (!vip->adapter) {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "no I2C adapter found\n");
+ goto vunreg;
+ }
+
+ vip->decoder = v4l2_i2c_new_subdev(&vip->v4l2_dev, vip->adapter,
+ "adv7180", vip->config->i2c_addr,
+ NULL);
+ if (!vip->decoder) {
+ ret = -ENODEV;
+ dev_err(&pdev->dev, "no decoder found\n");
+ goto vunreg;
+ }
+
+ i2c_put_adapter(vip->adapter);
+
+ v4l2_subdev_call(vip->decoder, core, init, 0);
+
+ pr_info("STA2X11 Video Input Port (VIP) loaded\n");
+ return 0;
+
+vunreg:
+ video_set_drvdata(vip->video_dev, NULL);
+vrelease:
+ if (video_is_registered(vip->video_dev))
+ video_unregister_device(vip->video_dev);
+ else
+ video_device_release(vip->video_dev);
+release_irq:
+ free_irq(pdev->irq, vip);
+ pci_disable_msi(pdev);
+unmap:
+ pci_iounmap(pdev, vip->iomem);
+ mutex_destroy(&vip->mutex);
+release:
+ pci_release_regions(pdev);
+unreg:
+ v4l2_device_unregister(&vip->v4l2_dev);
+free_mem:
+ kfree(vip);
+release_gpios:
+ vip_gpio_release(&pdev->dev, config->reset_pin, config->reset_name);
+ vip_gpio_release(&pdev->dev, config->pwr_pin, config->pwr_name);
+disable:
+ /*
+ * do not call pci_disable_device on sta2x11 because it break all
+ * other Bus masters on this EP
+ */
+ return ret;
+}
+
+/**
+ * sta2x11_vip_remove_one - release device
+ * @pdev: PCI device
+ *
+ * Undo everything done in .._init_one
+ *
+ * unregister video device
+ * free interrupt
+ * unmap ioadresses
+ * free memory
+ * free GPIO pins
+ */
+static void __devexit sta2x11_vip_remove_one(struct pci_dev *pdev)
+{
+ struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
+ struct sta2x11_vip *vip =
+ container_of(v4l2_dev, struct sta2x11_vip, v4l2_dev);
+
+ video_set_drvdata(vip->video_dev, NULL);
+ video_unregister_device(vip->video_dev);
+ /*do not call video_device_release() here, is already done */
+ free_irq(pdev->irq, vip);
+ pci_disable_msi(pdev);
+ pci_iounmap(pdev, vip->iomem);
+ pci_release_regions(pdev);
+
+ v4l2_device_unregister(&vip->v4l2_dev);
+ mutex_destroy(&vip->mutex);
+
+ vip_gpio_release(&pdev->dev, vip->config->pwr_pin,
+ vip->config->pwr_name);
+ vip_gpio_release(&pdev->dev, vip->config->reset_pin,
+ vip->config->reset_name);
+
+ kfree(vip);
+ /*
+ * do not call pci_disable_device on sta2x11 because it break all
+ * other Bus masters on this EP
+ */
+}
+
+#ifdef CONFIG_PM
+
+/**
+ * sta2x11_vip_suspend - set device into power save mode
+ * @pdev: PCI device
+ * @state: new state of device
+ *
+ * all relevant registers are saved and an attempt to set a new state is made.
+ *
+ * return value: 0 always indicate success,
+ * even if device could not be disabled. (workaround for hardware problem)
+ *
+ * reurn value : 0, always succesful, even if hardware does not not support
+ * power down mode.
+ */
+static int sta2x11_vip_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
+ struct sta2x11_vip *vip =
+ container_of(v4l2_dev, struct sta2x11_vip, v4l2_dev);
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&vip->slock, flags);
+ vip->register_save_area[0] = REG_READ(vip, DVP_CTL);
+ REG_WRITE(vip, DVP_CTL, vip->register_save_area[0] & DVP_CTL_DIS);
+ vip->register_save_area[SAVE_COUNT] = REG_READ(vip, DVP_ITM);
+ REG_WRITE(vip, DVP_ITM, 0);
+ for (i = 1; i < SAVE_COUNT; i++)
+ vip->register_save_area[i] = REG_READ(vip, 4 * i);
+ for (i = 0; i < AUX_COUNT; i++)
+ vip->register_save_area[SAVE_COUNT + IRQ_COUNT + i] =
+ REG_READ(vip, registers_to_save[i]);
+ spin_unlock_irqrestore(&vip->slock, flags);
+ /* save pci state */
+ pci_save_state(pdev);
+ if (pci_set_power_state(pdev, pci_choose_state(pdev, state))) {
+ /*
+ * do not call pci_disable_device on sta2x11 because it
+ * break all other Bus masters on this EP
+ */
+ vip->disabled = 1;
+ }
+
+ pr_info("VIP: suspend\n");
+ return 0;
+}
+
+/**
+ * sta2x11_vip_resume - resume device operation
+ * @pdev : PCI device
+ *
+ * re-enable device, set PCI state to powered and restore registers.
+ * resume normal device operation afterwards.
+ *
+ * return value: 0, no error.
+ *
+ * other, could not set device to power on state.
+ */
+static int sta2x11_vip_resume(struct pci_dev *pdev)
+{
+ struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
+ struct sta2x11_vip *vip =
+ container_of(v4l2_dev, struct sta2x11_vip, v4l2_dev);
+ unsigned long flags;
+ int ret, i;
+
+ pr_info("VIP: resume\n");
+ /* restore pci state */
+ if (vip->disabled) {
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ pr_warning("VIP: Can't enable device.\n");
+ return ret;
+ }
+ vip->disabled = 0;
+ }
+ ret = pci_set_power_state(pdev, PCI_D0);
+ if (ret) {
+ /*
+ * do not call pci_disable_device on sta2x11 because it
+ * break all other Bus masters on this EP
+ */
+ pr_warning("VIP: Can't enable device.\n");
+ vip->disabled = 1;
+ return ret;
+ }
+
+ pci_restore_state(pdev);
+
+ spin_lock_irqsave(&vip->slock, flags);
+ for (i = 1; i < SAVE_COUNT; i++)
+ REG_WRITE(vip, 4 * i, vip->register_save_area[i]);
+ for (i = 0; i < AUX_COUNT; i++)
+ REG_WRITE(vip, registers_to_save[i],
+ vip->register_save_area[SAVE_COUNT + IRQ_COUNT + i]);
+ REG_WRITE(vip, DVP_CTL, vip->register_save_area[0]);
+ REG_WRITE(vip, DVP_ITM, vip->register_save_area[SAVE_COUNT]);
+ spin_unlock_irqrestore(&vip->slock, flags);
+ return 0;
+}
+
+#endif
+
+static DEFINE_PCI_DEVICE_TABLE(sta2x11_vip_pci_tbl) = {
+ {PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_VIP)},
+ {0,}
+};
+
+static struct pci_driver sta2x11_vip_driver = {
+ .name = DRV_NAME,
+ .probe = sta2x11_vip_init_one,
+ .remove = __devexit_p(sta2x11_vip_remove_one),
+ .id_table = sta2x11_vip_pci_tbl,
+#ifdef CONFIG_PM
+ .suspend = sta2x11_vip_suspend,
+ .resume = sta2x11_vip_resume,
+#endif
+};
+
+static int __init sta2x11_vip_init_module(void)
+{
+ return pci_register_driver(&sta2x11_vip_driver);
+}
+
+static void __exit sta2x11_vip_exit_module(void)
+{
+ pci_unregister_driver(&sta2x11_vip_driver);
+}
+
+#ifdef MODULE
+module_init(sta2x11_vip_init_module);
+module_exit(sta2x11_vip_exit_module);
+#else
+late_initcall_sync(sta2x11_vip_init_module);
+#endif
+
+MODULE_DESCRIPTION("STA2X11 Video Input Port driver");
+MODULE_AUTHOR("Wind River");
+MODULE_LICENSE("GPL v2");
+MODULE_SUPPORTED_DEVICE("sta2x11 video input");
+MODULE_VERSION(DRV_VERSION);
+MODULE_DEVICE_TABLE(pci, sta2x11_vip_pci_tbl);
diff --git a/drivers/media/video/sta2x11_vip.h b/drivers/media/video/sta2x11_vip.h
new file mode 100644
index 000000000000..4f81a13666eb
--- /dev/null
+++ b/drivers/media/video/sta2x11_vip.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2011 Wind River Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Anders Wallin <anders.wallin@windriver.com>
+ *
+ */
+
+#ifndef __STA2X11_VIP_H
+#define __STA2X11_VIP_H
+
+/**
+ * struct vip_config - video input configuration data
+ * @pwr_name: ADV powerdown name
+ * @pwr_pin: ADV powerdown pin
+ * @reset_name: ADV reset name
+ * @reset_pin: ADV reset pin
+ */
+struct vip_config {
+ const char *pwr_name;
+ int pwr_pin;
+ const char *reset_name;
+ int reset_pin;
+ int i2c_id;
+ int i2c_addr;
+};
+
+#endif /* __STA2X11_VIP_H */
diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c
index d427f8436c70..86a0fc56c330 100644
--- a/drivers/media/video/stk-webcam.c
+++ b/drivers/media/video/stk-webcam.c
@@ -38,13 +38,13 @@
#include "stk-webcam.h"
-static bool hflip = 1;
+static bool hflip;
module_param(hflip, bool, 0444);
-MODULE_PARM_DESC(hflip, "Horizontal image flip (mirror). Defaults to 1");
+MODULE_PARM_DESC(hflip, "Horizontal image flip (mirror). Defaults to 0");
-static bool vflip = 1;
+static bool vflip;
module_param(vflip, bool, 0444);
-MODULE_PARM_DESC(vflip, "Vertical image flip. Defaults to 1");
+MODULE_PARM_DESC(vflip, "Vertical image flip. Defaults to 0");
static int debug;
module_param(debug, int, 0444);
diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c
index 465d7086babf..3d7ddd93282d 100644
--- a/drivers/media/video/tda9840.c
+++ b/drivers/media/video/tda9840.c
@@ -66,29 +66,53 @@ static void tda9840_write(struct v4l2_subdev *sd, u8 reg, u8 val)
val, reg);
}
+static int tda9840_status(struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 byte;
+
+ if (1 != i2c_master_recv(client, &byte, 1)) {
+ v4l2_dbg(1, debug, sd,
+ "i2c_master_recv() failed\n");
+ return -EIO;
+ }
+
+ if (byte & 0x80) {
+ v4l2_dbg(1, debug, sd,
+ "TDA9840_DETECT: register contents invalid\n");
+ return -EINVAL;
+ }
+
+ v4l2_dbg(1, debug, sd, "TDA9840_DETECT: byte: 0x%02x\n", byte);
+ return byte & 0x60;
+}
+
static int tda9840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t)
{
+ int stat = tda9840_status(sd);
int byte;
if (t->index)
return -EINVAL;
- switch (t->audmode) {
- case V4L2_TUNER_MODE_STEREO:
- byte = TDA9840_SET_STEREO;
- break;
- case V4L2_TUNER_MODE_LANG1_LANG2:
- byte = TDA9840_SET_BOTH;
- break;
- case V4L2_TUNER_MODE_LANG1:
- byte = TDA9840_SET_LANG1;
- break;
- case V4L2_TUNER_MODE_LANG2:
- byte = TDA9840_SET_LANG2;
- break;
- default:
+ stat = stat < 0 ? 0 : stat;
+ if (stat == 0 || stat == 0x60) /* mono input */
byte = TDA9840_SET_MONO;
- break;
+ else if (stat == 0x40) /* stereo input */
+ byte = (t->audmode == V4L2_TUNER_MODE_MONO) ?
+ TDA9840_SET_MONO : TDA9840_SET_STEREO;
+ else { /* bilingual */
+ switch (t->audmode) {
+ case V4L2_TUNER_MODE_LANG1_LANG2:
+ byte = TDA9840_SET_BOTH;
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ byte = TDA9840_SET_LANG2;
+ break;
+ default:
+ byte = TDA9840_SET_LANG1;
+ break;
+ }
}
v4l2_dbg(1, debug, sd, "TDA9840_SWITCH: 0x%02x\n", byte);
tda9840_write(sd, SWITCH, byte);
@@ -97,25 +121,14 @@ static int tda9840_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t)
static int tda9840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *t)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- u8 byte;
-
- t->rxsubchans = V4L2_TUNER_SUB_MONO;
- if (1 != i2c_master_recv(client, &byte, 1)) {
- v4l2_dbg(1, debug, sd,
- "i2c_master_recv() failed\n");
- return -EIO;
- }
+ int stat = tda9840_status(sd);
- if (byte & 0x80) {
- v4l2_dbg(1, debug, sd,
- "TDA9840_DETECT: register contents invalid\n");
- return -EINVAL;
- }
+ if (stat < 0)
+ return stat;
- v4l2_dbg(1, debug, sd, "TDA9840_DETECT: byte: 0x%02x\n", byte);
+ t->rxsubchans = V4L2_TUNER_SUB_MONO;
- switch (byte & 0x60) {
+ switch (stat & 0x60) {
case 0x00:
t->rxsubchans = V4L2_TUNER_SUB_MONO;
break;
diff --git a/drivers/media/video/tlg2300/pd-video.c b/drivers/media/video/tlg2300/pd-video.c
index a794ae62aebf..bfbf9e56b0a4 100644
--- a/drivers/media/video/tlg2300/pd-video.c
+++ b/drivers/media/video/tlg2300/pd-video.c
@@ -150,7 +150,6 @@ static int vidioc_querycap(struct file *file, void *fh,
strcpy(cap->driver, "tele-video");
strcpy(cap->card, "Telegent Poseidon");
usb_make_path(p->udev, cap->bus_info, sizeof(cap->bus_info));
- cap->version = KERNEL_VERSION(0, 0, 1);
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
V4L2_CAP_AUDIO | V4L2_CAP_STREAMING |
V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE;
diff --git a/drivers/media/video/tm6000/tm6000-input.c b/drivers/media/video/tm6000/tm6000-input.c
index 859eb90e4d56..e80b7e190471 100644
--- a/drivers/media/video/tm6000/tm6000-input.c
+++ b/drivers/media/video/tm6000/tm6000-input.c
@@ -168,7 +168,6 @@ static void tm6000_ir_urb_received(struct urb *urb)
struct tm6000_IR *ir = dev->ir;
struct tm6000_ir_poll_result poll_result;
char *buf;
- int rc;
dprintk(2, "%s\n",__func__);
if (urb->status < 0 || urb->actual_length <= 0) {
@@ -192,7 +191,7 @@ static void tm6000_ir_urb_received(struct urb *urb)
dprintk(1, "%s, scancode: 0x%04x\n",__func__, poll_result.rc_data);
rc_keydown(ir->rc, poll_result.rc_data, 0);
- rc = usb_submit_urb(urb, GFP_ATOMIC);
+ usb_submit_urb(urb, GFP_ATOMIC);
/*
* Flash the led. We can't do it here, as it is running on IRQ context.
* So, use the scheduler to do it, in a few ms.
diff --git a/drivers/media/video/tm6000/tm6000-stds.c b/drivers/media/video/tm6000/tm6000-stds.c
index 9dc0831d813f..5e28d6a2412f 100644
--- a/drivers/media/video/tm6000/tm6000-stds.c
+++ b/drivers/media/video/tm6000/tm6000-stds.c
@@ -338,7 +338,6 @@ static int tm6000_set_audio_std(struct tm6000_core *dev)
uint8_t areg_02 = 0x04; /* GC1 Fixed gain 0dB */
uint8_t areg_05 = 0x01; /* Auto 4.5 = M Japan, Auto 6.5 = DK */
uint8_t areg_06 = 0x02; /* Auto de-emphasis, mannual channel mode */
- uint8_t nicam_flag = 0; /* No NICAM */
if (dev->radio) {
tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00);
@@ -398,7 +397,6 @@ static int tm6000_set_audio_std(struct tm6000_core *dev)
} else {
areg_05 = 0x07;
}
- nicam_flag = 1;
break;
/* other */
case 3:
diff --git a/drivers/media/video/tm6000/tm6000-video.c b/drivers/media/video/tm6000/tm6000-video.c
index bc13db736e24..f7034df94e0a 100644
--- a/drivers/media/video/tm6000/tm6000-video.c
+++ b/drivers/media/video/tm6000/tm6000-video.c
@@ -169,7 +169,6 @@ static inline void get_next_buf(struct tm6000_dmaqueue *dma_q,
struct tm6000_buffer **buf)
{
struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
- char *outp;
if (list_empty(&dma_q->active)) {
dprintk(dev, V4L2_DEBUG_QUEUE, "No active queue to serve\n");
@@ -179,11 +178,6 @@ static inline void get_next_buf(struct tm6000_dmaqueue *dma_q,
*buf = list_entry(dma_q->active.next,
struct tm6000_buffer, vb.queue);
-
- /* Cleans up buffer - Useful for testing for frame/URB loss */
- outp = videobuf_to_vmalloc(&(*buf)->vb);
-
- return;
}
/*
@@ -211,7 +205,7 @@ static int copy_streams(u8 *data, unsigned long len,
{
struct tm6000_dmaqueue *dma_q = urb->context;
struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
- u8 *ptr = data, *endp = data+len, c;
+ u8 *ptr = data, *endp = data+len;
unsigned long header = 0;
int rc = 0;
unsigned int cmd, cpysize, pktsize, size, field, block, line, pos = 0;
@@ -264,7 +258,6 @@ static int copy_streams(u8 *data, unsigned long len,
}
/* split the header fields */
- c = (header >> 24) & 0xff;
size = ((header & 0x7e) << 1);
if (size > 0)
size -= 4;
@@ -889,7 +882,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strlcpy(cap->driver, "tm6000", sizeof(cap->driver));
strlcpy(cap->card, "Trident TVMaster TM5600/6000/6010", sizeof(cap->card));
- cap->version = TM6000_VERSION;
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_STREAMING |
V4L2_CAP_AUDIO |
@@ -1732,6 +1724,10 @@ static struct video_device *vdev_init(struct tm6000_core *dev,
vfd->release = video_device_release;
vfd->debug = tm6000_debug;
vfd->lock = &dev->lock;
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
diff --git a/drivers/media/video/tm6000/tm6000.h b/drivers/media/video/tm6000/tm6000.h
index 27ba659cfa85..6df418658c9c 100644
--- a/drivers/media/video/tm6000/tm6000.h
+++ b/drivers/media/video/tm6000/tm6000.h
@@ -33,8 +33,6 @@
#include "dvb_frontend.h"
#include "dmxdev.h"
-#define TM6000_VERSION KERNEL_VERSION(0, 0, 2)
-
/* Inputs */
enum tm6000_itype {
TM6000_INPUT_TV = 1,
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index a5c6397ad591..3e050e12153b 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -1241,8 +1241,10 @@ static int tuner_log_status(struct v4l2_subdev *sd)
return 0;
}
-static int tuner_suspend(struct i2c_client *c, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int tuner_suspend(struct device *dev)
{
+ struct i2c_client *c = to_i2c_client(dev);
struct tuner *t = to_tuner(i2c_get_clientdata(c));
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
@@ -1254,8 +1256,9 @@ static int tuner_suspend(struct i2c_client *c, pm_message_t state)
return 0;
}
-static int tuner_resume(struct i2c_client *c)
+static int tuner_resume(struct device *dev)
{
+ struct i2c_client *c = to_i2c_client(dev);
struct tuner *t = to_tuner(i2c_get_clientdata(c));
tuner_dbg("resume\n");
@@ -1266,6 +1269,7 @@ static int tuner_resume(struct i2c_client *c)
return 0;
}
+#endif
static int tuner_command(struct i2c_client *client, unsigned cmd, void *arg)
{
@@ -1310,6 +1314,10 @@ static const struct v4l2_subdev_ops tuner_ops = {
* I2C structs and module init functions
*/
+static const struct dev_pm_ops tuner_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(tuner_suspend, tuner_resume)
+};
+
static const struct i2c_device_id tuner_id[] = {
{ "tuner", }, /* autodetect */
{ }
@@ -1320,12 +1328,11 @@ static struct i2c_driver tuner_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "tuner",
+ .pm = &tuner_pm_ops,
},
.probe = tuner_probe,
.remove = tuner_remove,
.command = tuner_command,
- .suspend = tuner_suspend,
- .resume = tuner_resume,
.id_table = tuner_id,
};
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index 1326e11cf4a9..b7867427e5c4 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -822,7 +822,7 @@ static int tvp5150_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
if (index)
return -EINVAL;
- *code = V4L2_MBUS_FMT_YUYV8_2X8;
+ *code = V4L2_MBUS_FMT_UYVY8_2X8;
return 0;
}
@@ -830,23 +830,16 @@ static int tvp5150_mbus_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *f)
{
struct tvp5150 *decoder = to_tvp5150(sd);
- v4l2_std_id std;
if (f == NULL)
return -EINVAL;
tvp5150_reset(sd, 0);
- /* Calculate height and width based on current standard */
- if (decoder->norm == V4L2_STD_ALL)
- std = tvp5150_read_std(sd);
- else
- std = decoder->norm;
-
f->width = decoder->rect.width;
f->height = decoder->rect.height;
- f->code = V4L2_MBUS_FMT_YUYV8_2X8;
+ f->code = V4L2_MBUS_FMT_UYVY8_2X8;
f->field = V4L2_FIELD_SEQ_TB;
f->colorspace = V4L2_COLORSPACE_SMPTE170M;
diff --git a/drivers/media/video/tvp7002.c b/drivers/media/video/tvp7002.c
index d7676d85c4df..fb6a5b57eb83 100644
--- a/drivers/media/video/tvp7002.c
+++ b/drivers/media/video/tvp7002.c
@@ -29,6 +29,7 @@
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <linux/module.h>
+#include <linux/v4l2-dv-timings.h>
#include <media/tvp7002.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
@@ -328,6 +329,7 @@ static const struct i2c_reg_value tvp7002_parms_720P50[] = {
/* Preset definition for handling device operation */
struct tvp7002_preset_definition {
u32 preset;
+ struct v4l2_dv_timings timings;
const struct i2c_reg_value *p_settings;
enum v4l2_colorspace color_space;
enum v4l2_field scanmode;
@@ -341,6 +343,7 @@ struct tvp7002_preset_definition {
static const struct tvp7002_preset_definition tvp7002_presets[] = {
{
V4L2_DV_720P60,
+ V4L2_DV_BT_CEA_1280X720P60,
tvp7002_parms_720P60,
V4L2_COLORSPACE_REC709,
V4L2_FIELD_NONE,
@@ -351,6 +354,7 @@ static const struct tvp7002_preset_definition tvp7002_presets[] = {
},
{
V4L2_DV_1080I60,
+ V4L2_DV_BT_CEA_1920X1080I60,
tvp7002_parms_1080I60,
V4L2_COLORSPACE_REC709,
V4L2_FIELD_INTERLACED,
@@ -361,6 +365,7 @@ static const struct tvp7002_preset_definition tvp7002_presets[] = {
},
{
V4L2_DV_1080I50,
+ V4L2_DV_BT_CEA_1920X1080I50,
tvp7002_parms_1080I50,
V4L2_COLORSPACE_REC709,
V4L2_FIELD_INTERLACED,
@@ -371,6 +376,7 @@ static const struct tvp7002_preset_definition tvp7002_presets[] = {
},
{
V4L2_DV_720P50,
+ V4L2_DV_BT_CEA_1280X720P50,
tvp7002_parms_720P50,
V4L2_COLORSPACE_REC709,
V4L2_FIELD_NONE,
@@ -381,6 +387,7 @@ static const struct tvp7002_preset_definition tvp7002_presets[] = {
},
{
V4L2_DV_1080P60,
+ V4L2_DV_BT_CEA_1920X1080P60,
tvp7002_parms_1080P60,
V4L2_COLORSPACE_REC709,
V4L2_FIELD_NONE,
@@ -391,6 +398,7 @@ static const struct tvp7002_preset_definition tvp7002_presets[] = {
},
{
V4L2_DV_480P59_94,
+ V4L2_DV_BT_CEA_720X480P59_94,
tvp7002_parms_480P,
V4L2_COLORSPACE_SMPTE170M,
V4L2_FIELD_NONE,
@@ -401,6 +409,7 @@ static const struct tvp7002_preset_definition tvp7002_presets[] = {
},
{
V4L2_DV_576P50,
+ V4L2_DV_BT_CEA_720X576P50,
tvp7002_parms_576P,
V4L2_COLORSPACE_SMPTE170M,
V4L2_FIELD_NONE,
@@ -605,6 +614,35 @@ static int tvp7002_s_dv_preset(struct v4l2_subdev *sd,
return -EINVAL;
}
+static int tvp7002_s_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings *dv_timings)
+{
+ struct tvp7002 *device = to_tvp7002(sd);
+ const struct v4l2_bt_timings *bt = &dv_timings->bt;
+ int i;
+
+ if (dv_timings->type != V4L2_DV_BT_656_1120)
+ return -EINVAL;
+ for (i = 0; i < NUM_PRESETS; i++) {
+ const struct v4l2_bt_timings *t = &tvp7002_presets[i].timings.bt;
+
+ if (!memcmp(bt, t, &bt->standards - &bt->width)) {
+ device->current_preset = &tvp7002_presets[i];
+ return tvp7002_write_inittab(sd, tvp7002_presets[i].p_settings);
+ }
+ }
+ return -EINVAL;
+}
+
+static int tvp7002_g_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings *dv_timings)
+{
+ struct tvp7002 *device = to_tvp7002(sd);
+
+ *dv_timings = device->current_preset->timings;
+ return 0;
+}
+
/*
* tvp7002_s_ctrl() - Set a control
* @ctrl: ptr to v4l2_ctrl struct
@@ -666,11 +704,9 @@ static int tvp7002_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f
* Returns the current DV preset by TVP7002. If no active input is
* detected, returns -EINVAL
*/
-static int tvp7002_query_dv_preset(struct v4l2_subdev *sd,
- struct v4l2_dv_preset *qpreset)
+static int tvp7002_query_dv(struct v4l2_subdev *sd, int *index)
{
const struct tvp7002_preset_definition *presets = tvp7002_presets;
- struct tvp7002 *device;
u8 progressive;
u32 lpfr;
u32 cpln;
@@ -679,12 +715,9 @@ static int tvp7002_query_dv_preset(struct v4l2_subdev *sd,
u8 lpf_msb;
u8 cpl_lsb;
u8 cpl_msb;
- int index;
-
- /* Return invalid preset if no active input is detected */
- qpreset->preset = V4L2_DV_INVALID;
- device = to_tvp7002(sd);
+ /* Return invalid index if no active input is detected */
+ *index = NUM_PRESETS;
/* Read standards from device registers */
tvp7002_read_err(sd, TVP7002_L_FRAME_STAT_LSBS, &lpf_lsb, &error);
@@ -705,8 +738,8 @@ static int tvp7002_query_dv_preset(struct v4l2_subdev *sd,
progressive = (lpf_msb & TVP7002_INPR_MASK) >> TVP7002_IP_SHIFT;
/* Do checking of video modes */
- for (index = 0; index < NUM_PRESETS; index++, presets++)
- if (lpfr == presets->lines_per_frame &&
+ for (*index = 0; *index < NUM_PRESETS; (*index)++, presets++)
+ if (lpfr == presets->lines_per_frame &&
progressive == presets->progressive) {
if (presets->cpl_min == 0xffff)
break;
@@ -714,17 +747,42 @@ static int tvp7002_query_dv_preset(struct v4l2_subdev *sd,
break;
}
- if (index == NUM_PRESETS) {
+ if (*index == NUM_PRESETS) {
v4l2_dbg(1, debug, sd, "detection failed: lpf = %x, cpl = %x\n",
lpfr, cpln);
- return 0;
+ return -ENOLINK;
}
- /* Set values in found preset */
- qpreset->preset = presets->preset;
-
/* Update lines per frame and clocks per line info */
- v4l2_dbg(1, debug, sd, "detected preset: %d\n", presets->preset);
+ v4l2_dbg(1, debug, sd, "detected preset: %d\n", *index);
+ return 0;
+}
+
+static int tvp7002_query_dv_preset(struct v4l2_subdev *sd,
+ struct v4l2_dv_preset *qpreset)
+{
+ int index;
+ int err = tvp7002_query_dv(sd, &index);
+
+ if (err || index == NUM_PRESETS) {
+ qpreset->preset = V4L2_DV_INVALID;
+ if (err == -ENOLINK)
+ err = 0;
+ return err;
+ }
+ qpreset->preset = tvp7002_presets[index].preset;
+ return 0;
+}
+
+static int tvp7002_query_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings *timings)
+{
+ int index;
+ int err = tvp7002_query_dv(sd, &index);
+
+ if (err)
+ return err;
+ *timings = tvp7002_presets[index].timings;
return 0;
}
@@ -894,6 +952,17 @@ static int tvp7002_enum_dv_presets(struct v4l2_subdev *sd,
return v4l_fill_dv_preset_info(tvp7002_presets[preset->index].preset, preset);
}
+static int tvp7002_enum_dv_timings(struct v4l2_subdev *sd,
+ struct v4l2_enum_dv_timings *timings)
+{
+ /* Check requested format index is within range */
+ if (timings->index >= NUM_PRESETS)
+ return -EINVAL;
+
+ timings->timings = tvp7002_presets[timings->index].timings;
+ return 0;
+}
+
static const struct v4l2_ctrl_ops tvp7002_ctrl_ops = {
.s_ctrl = tvp7002_s_ctrl,
};
@@ -920,6 +989,10 @@ static const struct v4l2_subdev_video_ops tvp7002_video_ops = {
.enum_dv_presets = tvp7002_enum_dv_presets,
.s_dv_preset = tvp7002_s_dv_preset,
.query_dv_preset = tvp7002_query_dv_preset,
+ .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,
.try_mbus_fmt = tvp7002_mbus_fmt,
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
index f344411a4578..c9b2042f8bdf 100644
--- a/drivers/media/video/usbvision/usbvision-core.c
+++ b/drivers/media/video/usbvision/usbvision-core.c
@@ -601,13 +601,12 @@ static int usbvision_decompress(struct usb_usbvision *usbvision, unsigned char *
unsigned char *decompressed, int *start_pos,
int *block_typestart_pos, int len)
{
- int rest_pixel, idx, max_pos, pos, extra_pos, block_len, block_type_pos, block_type_len;
+ int rest_pixel, idx, pos, extra_pos, block_len, block_type_pos, block_type_len;
unsigned char block_byte, block_code, block_type, block_type_byte, integrator;
integrator = 0;
pos = *start_pos;
block_type_pos = *block_typestart_pos;
- max_pos = 396; /* pos + len; */
extra_pos = pos;
block_len = 0;
block_byte = 0;
@@ -702,7 +701,7 @@ static enum parse_state usbvision_parse_compress(struct usb_usbvision *usbvision
unsigned char strip_data[USBVISION_STRIP_LEN_MAX];
unsigned char strip_header[USBVISION_STRIP_HEADER_LEN];
int idx, idx_end, strip_len, strip_ptr, startblock_pos, block_pos, block_type_pos;
- int clipmask_index, bytes_per_pixel, rc;
+ int clipmask_index;
int image_size;
unsigned char rv, gv, bv;
static unsigned char *Y, *U, *V;
@@ -769,7 +768,6 @@ static enum parse_state usbvision_parse_compress(struct usb_usbvision *usbvision
return parse_state_next_frame;
}
- bytes_per_pixel = frame->v4l2_format.bytes_per_pixel;
clipmask_index = frame->curline * MAX_FRAME_WIDTH;
scratch_get(usbvision, strip_data, strip_len);
@@ -781,14 +779,14 @@ static enum parse_state usbvision_parse_compress(struct usb_usbvision *usbvision
usbvision->block_pos = block_pos;
- rc = usbvision_decompress(usbvision, strip_data, Y, &block_pos, &block_type_pos, idx_end);
+ usbvision_decompress(usbvision, strip_data, Y, &block_pos, &block_type_pos, idx_end);
if (strip_len > usbvision->max_strip_len)
usbvision->max_strip_len = strip_len;
if (frame->curline % 2)
- rc = usbvision_decompress(usbvision, strip_data, V, &block_pos, &block_type_pos, idx_end / 2);
+ usbvision_decompress(usbvision, strip_data, V, &block_pos, &block_type_pos, idx_end / 2);
else
- rc = usbvision_decompress(usbvision, strip_data, U, &block_pos, &block_type_pos, idx_end / 2);
+ usbvision_decompress(usbvision, strip_data, U, &block_pos, &block_type_pos, idx_end / 2);
if (block_pos > usbvision->comprblock_pos)
usbvision->comprblock_pos = block_pos;
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index 5a74f5e07d7d..9bd8f084f348 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -1296,6 +1296,10 @@ static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision,
if (NULL == vdev)
return NULL;
*vdev = *vdev_template;
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags);
vdev->lock = &usbvision->v4l2_lock;
vdev->v4l2_dev = &usbvision->v4l2_dev;
snprintf(vdev->name, sizeof(vdev->name), "%s", name);
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index 0efd3b10b353..af26bbe6f76e 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -21,6 +21,7 @@
#include <linux/vmalloc.h>
#include <linux/wait.h>
#include <linux/atomic.h>
+#include <media/v4l2-ctrls.h>
#include "uvcvideo.h"
@@ -420,6 +421,8 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
.data_type = UVC_CTRL_DATA_TYPE_SIGNED,
+ .master_id = V4L2_CID_HUE_AUTO,
+ .master_manual = 0,
},
{
.id = V4L2_CID_SATURATION,
@@ -492,6 +495,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
.data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
+ .slave_ids = { V4L2_CID_HUE, },
},
{
.id = V4L2_CID_EXPOSURE_AUTO,
@@ -504,6 +508,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.data_type = UVC_CTRL_DATA_TYPE_BITMASK,
.menu_info = exposure_auto_controls,
.menu_count = ARRAY_SIZE(exposure_auto_controls),
+ .slave_ids = { V4L2_CID_EXPOSURE_ABSOLUTE, },
},
{
.id = V4L2_CID_EXPOSURE_AUTO_PRIORITY,
@@ -524,6 +529,8 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
.data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ .master_id = V4L2_CID_EXPOSURE_AUTO,
+ .master_manual = V4L2_EXPOSURE_MANUAL,
},
{
.id = V4L2_CID_AUTO_WHITE_BALANCE,
@@ -534,6 +541,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
.data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
+ .slave_ids = { V4L2_CID_WHITE_BALANCE_TEMPERATURE, },
},
{
.id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
@@ -544,6 +552,8 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
.data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ .master_id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .master_manual = 0,
},
{
.id = V4L2_CID_AUTO_WHITE_BALANCE,
@@ -554,6 +564,8 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
.data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
+ .slave_ids = { V4L2_CID_BLUE_BALANCE,
+ V4L2_CID_RED_BALANCE },
},
{
.id = V4L2_CID_BLUE_BALANCE,
@@ -564,6 +576,8 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
.data_type = UVC_CTRL_DATA_TYPE_SIGNED,
+ .master_id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .master_manual = 0,
},
{
.id = V4L2_CID_RED_BALANCE,
@@ -574,6 +588,8 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.offset = 16,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
.data_type = UVC_CTRL_DATA_TYPE_SIGNED,
+ .master_id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .master_manual = 0,
},
{
.id = V4L2_CID_FOCUS_ABSOLUTE,
@@ -584,6 +600,8 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_INTEGER,
.data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ .master_id = V4L2_CID_FOCUS_AUTO,
+ .master_manual = 0,
},
{
.id = V4L2_CID_FOCUS_AUTO,
@@ -594,6 +612,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.offset = 0,
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
.data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
+ .slave_ids = { V4L2_CID_FOCUS_ABSOLUTE, },
},
{
.id = V4L2_CID_IRIS_ABSOLUTE,
@@ -899,25 +918,54 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
return 0;
}
-int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
- struct v4l2_queryctrl *v4l2_ctrl)
+static int __uvc_ctrl_get(struct uvc_video_chain *chain,
+ struct uvc_control *ctrl, struct uvc_control_mapping *mapping,
+ s32 *value)
{
- struct uvc_control *ctrl;
- struct uvc_control_mapping *mapping;
struct uvc_menu_info *menu;
unsigned int i;
int ret;
- ret = mutex_lock_interruptible(&chain->ctrl_mutex);
- if (ret < 0)
- return -ERESTARTSYS;
+ if ((ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0)
+ return -EINVAL;
- ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping);
- if (ctrl == NULL) {
- ret = -EINVAL;
- goto done;
+ if (!ctrl->loaded) {
+ ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info.selector,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
+ ctrl->info.size);
+ if (ret < 0)
+ return ret;
+
+ ctrl->loaded = 1;
}
+ *value = mapping->get(mapping, UVC_GET_CUR,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
+
+ if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
+ menu = mapping->menu_info;
+ for (i = 0; i < mapping->menu_count; ++i, ++menu) {
+ if (menu->value == *value) {
+ *value = i;
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
+ struct uvc_control *ctrl,
+ struct uvc_control_mapping *mapping,
+ struct v4l2_queryctrl *v4l2_ctrl)
+{
+ struct uvc_control_mapping *master_map = NULL;
+ struct uvc_control *master_ctrl = NULL;
+ struct uvc_menu_info *menu;
+ unsigned int i;
+
memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl);
v4l2_ctrl->id = mapping->id;
v4l2_ctrl->type = mapping->v4l2_type;
@@ -929,10 +977,23 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ if (mapping->master_id)
+ __uvc_find_control(ctrl->entity, mapping->master_id,
+ &master_map, &master_ctrl, 0);
+ if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) {
+ s32 val;
+ int ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
+ if (ret < 0)
+ return ret;
+
+ if (val != mapping->master_manual)
+ v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ }
+
if (!ctrl->cached) {
- ret = uvc_ctrl_populate_cache(chain, ctrl);
+ int ret = uvc_ctrl_populate_cache(chain, ctrl);
if (ret < 0)
- goto done;
+ return ret;
}
if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) {
@@ -954,19 +1015,19 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
}
}
- goto done;
+ return 0;
case V4L2_CTRL_TYPE_BOOLEAN:
v4l2_ctrl->minimum = 0;
v4l2_ctrl->maximum = 1;
v4l2_ctrl->step = 1;
- goto done;
+ return 0;
case V4L2_CTRL_TYPE_BUTTON:
v4l2_ctrl->minimum = 0;
v4l2_ctrl->maximum = 0;
v4l2_ctrl->step = 0;
- goto done;
+ return 0;
default:
break;
@@ -984,6 +1045,27 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
+ return 0;
+}
+
+int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
+ struct v4l2_queryctrl *v4l2_ctrl)
+{
+ struct uvc_control *ctrl;
+ struct uvc_control_mapping *mapping;
+ int ret;
+
+ ret = mutex_lock_interruptible(&chain->ctrl_mutex);
+ if (ret < 0)
+ return -ERESTARTSYS;
+
+ ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping);
+ if (ctrl == NULL) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = __uvc_query_v4l2_ctrl(chain, ctrl, mapping, v4l2_ctrl);
done:
mutex_unlock(&chain->ctrl_mutex);
return ret;
@@ -1054,6 +1136,174 @@ done:
return ret;
}
+/* --------------------------------------------------------------------------
+ * Ctrl event handling
+ */
+
+static void uvc_ctrl_fill_event(struct uvc_video_chain *chain,
+ struct v4l2_event *ev,
+ struct uvc_control *ctrl,
+ struct uvc_control_mapping *mapping,
+ s32 value, u32 changes)
+{
+ struct v4l2_queryctrl v4l2_ctrl;
+
+ __uvc_query_v4l2_ctrl(chain, ctrl, mapping, &v4l2_ctrl);
+
+ memset(ev->reserved, 0, sizeof(ev->reserved));
+ ev->type = V4L2_EVENT_CTRL;
+ ev->id = v4l2_ctrl.id;
+ ev->u.ctrl.value = value;
+ ev->u.ctrl.changes = changes;
+ ev->u.ctrl.type = v4l2_ctrl.type;
+ ev->u.ctrl.flags = v4l2_ctrl.flags;
+ ev->u.ctrl.minimum = v4l2_ctrl.minimum;
+ ev->u.ctrl.maximum = v4l2_ctrl.maximum;
+ ev->u.ctrl.step = v4l2_ctrl.step;
+ ev->u.ctrl.default_value = v4l2_ctrl.default_value;
+}
+
+static void uvc_ctrl_send_event(struct uvc_fh *handle,
+ struct uvc_control *ctrl, struct uvc_control_mapping *mapping,
+ s32 value, u32 changes)
+{
+ struct v4l2_subscribed_event *sev;
+ struct v4l2_event ev;
+
+ if (list_empty(&mapping->ev_subs))
+ return;
+
+ uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, value, changes);
+
+ list_for_each_entry(sev, &mapping->ev_subs, node) {
+ if (sev->fh && (sev->fh != &handle->vfh ||
+ (sev->flags & V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK) ||
+ (changes & V4L2_EVENT_CTRL_CH_FLAGS)))
+ v4l2_event_queue_fh(sev->fh, &ev);
+ }
+}
+
+static void uvc_ctrl_send_slave_event(struct uvc_fh *handle,
+ struct uvc_control *master, u32 slave_id,
+ const struct v4l2_ext_control *xctrls, unsigned int xctrls_count)
+{
+ struct uvc_control_mapping *mapping = NULL;
+ struct uvc_control *ctrl = NULL;
+ u32 changes = V4L2_EVENT_CTRL_CH_FLAGS;
+ unsigned int i;
+ s32 val = 0;
+
+ /*
+ * We can skip sending an event for the slave if the slave
+ * is being modified in the same transaction.
+ */
+ for (i = 0; i < xctrls_count; i++) {
+ if (xctrls[i].id == slave_id)
+ return;
+ }
+
+ __uvc_find_control(master->entity, slave_id, &mapping, &ctrl, 0);
+ if (ctrl == NULL)
+ return;
+
+ if (__uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0)
+ changes |= V4L2_EVENT_CTRL_CH_VALUE;
+
+ uvc_ctrl_send_event(handle, ctrl, mapping, val, changes);
+}
+
+static void uvc_ctrl_send_events(struct uvc_fh *handle,
+ const struct v4l2_ext_control *xctrls, unsigned int xctrls_count)
+{
+ struct uvc_control_mapping *mapping;
+ struct uvc_control *ctrl;
+ u32 changes = V4L2_EVENT_CTRL_CH_VALUE;
+ unsigned int i;
+ unsigned int j;
+
+ for (i = 0; i < xctrls_count; ++i) {
+ ctrl = uvc_find_control(handle->chain, xctrls[i].id, &mapping);
+
+ for (j = 0; j < ARRAY_SIZE(mapping->slave_ids); ++j) {
+ if (!mapping->slave_ids[j])
+ break;
+ uvc_ctrl_send_slave_event(handle, ctrl,
+ mapping->slave_ids[j],
+ xctrls, xctrls_count);
+ }
+
+ /*
+ * If the master is being modified in the same transaction
+ * flags may change too.
+ */
+ if (mapping->master_id) {
+ for (j = 0; j < xctrls_count; j++) {
+ if (xctrls[j].id == mapping->master_id) {
+ changes |= V4L2_EVENT_CTRL_CH_FLAGS;
+ break;
+ }
+ }
+ }
+
+ uvc_ctrl_send_event(handle, ctrl, mapping, xctrls[i].value,
+ changes);
+ }
+}
+
+static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems)
+{
+ struct uvc_fh *handle = container_of(sev->fh, struct uvc_fh, vfh);
+ struct uvc_control_mapping *mapping;
+ struct uvc_control *ctrl;
+ int ret;
+
+ ret = mutex_lock_interruptible(&handle->chain->ctrl_mutex);
+ if (ret < 0)
+ return -ERESTARTSYS;
+
+ ctrl = uvc_find_control(handle->chain, sev->id, &mapping);
+ if (ctrl == NULL) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ list_add_tail(&sev->node, &mapping->ev_subs);
+ if (sev->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL) {
+ struct v4l2_event ev;
+ u32 changes = V4L2_EVENT_CTRL_CH_FLAGS;
+ s32 val = 0;
+
+ if (__uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0)
+ changes |= V4L2_EVENT_CTRL_CH_VALUE;
+
+ uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, val,
+ changes);
+ /* Mark the queue as active, allowing this initial
+ event to be accepted. */
+ sev->elems = elems;
+ v4l2_event_queue_fh(sev->fh, &ev);
+ }
+
+done:
+ mutex_unlock(&handle->chain->ctrl_mutex);
+ return ret;
+}
+
+static void uvc_ctrl_del_event(struct v4l2_subscribed_event *sev)
+{
+ struct uvc_fh *handle = container_of(sev->fh, struct uvc_fh, vfh);
+
+ mutex_lock(&handle->chain->ctrl_mutex);
+ list_del(&sev->node);
+ mutex_unlock(&handle->chain->ctrl_mutex);
+}
+
+const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops = {
+ .add = uvc_ctrl_add_event,
+ .del = uvc_ctrl_del_event,
+ .replace = v4l2_ctrl_replace,
+ .merge = v4l2_ctrl_merge,
+};
/* --------------------------------------------------------------------------
* Control transactions
@@ -1101,9 +1351,12 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
/* Reset the loaded flag for auto-update controls that were
* marked as loaded in uvc_ctrl_get/uvc_ctrl_set to prevent
- * uvc_ctrl_get from using the cached value.
+ * uvc_ctrl_get from using the cached value, and for write-only
+ * controls to prevent uvc_ctrl_set from setting bits not
+ * explicitly set by the user.
*/
- if (ctrl->info.flags & UVC_CTRL_FLAG_AUTO_UPDATE)
+ if (ctrl->info.flags & UVC_CTRL_FLAG_AUTO_UPDATE ||
+ !(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
ctrl->loaded = 0;
if (!ctrl->dirty)
@@ -1131,8 +1384,11 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
return 0;
}
-int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback)
+int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
+ const struct v4l2_ext_control *xctrls,
+ unsigned int xctrls_count)
{
+ struct uvc_video_chain *chain = handle->chain;
struct uvc_entity *entity;
int ret = 0;
@@ -1143,6 +1399,8 @@ int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback)
goto done;
}
+ if (!rollback)
+ uvc_ctrl_send_events(handle, xctrls, xctrls_count);
done:
mutex_unlock(&chain->ctrl_mutex);
return ret;
@@ -1153,39 +1411,12 @@ int uvc_ctrl_get(struct uvc_video_chain *chain,
{
struct uvc_control *ctrl;
struct uvc_control_mapping *mapping;
- struct uvc_menu_info *menu;
- unsigned int i;
- int ret;
ctrl = uvc_find_control(chain, xctrl->id, &mapping);
- if (ctrl == NULL || (ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0)
+ if (ctrl == NULL)
return -EINVAL;
- if (!ctrl->loaded) {
- ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info.selector,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
- ctrl->info.size);
- if (ret < 0)
- return ret;
-
- ctrl->loaded = 1;
- }
-
- xctrl->value = mapping->get(mapping, UVC_GET_CUR,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
-
- if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
- menu = mapping->menu_info;
- for (i = 0; i < mapping->menu_count; ++i, ++menu) {
- if (menu->value == xctrl->value) {
- xctrl->value = i;
- break;
- }
- }
- }
-
- return 0;
+ return __uvc_ctrl_get(chain, ctrl, mapping, &xctrl->value);
}
int uvc_ctrl_set(struct uvc_video_chain *chain,
@@ -1641,6 +1872,8 @@ static int __uvc_ctrl_add_mapping(struct uvc_device *dev,
if (map == NULL)
return -ENOMEM;
+ INIT_LIST_HEAD(&map->ev_subs);
+
size = sizeof(*mapping->menu_info) * mapping->menu_count;
map->menu_info = kmemdup(mapping->menu_info, size, GFP_KERNEL);
if (map->menu_info == NULL) {
@@ -1653,7 +1886,6 @@ static int __uvc_ctrl_add_mapping(struct uvc_device *dev,
if (map->set == NULL)
map->set = uvc_set_le_value;
- map->ctrl = &ctrl->info;
list_add_tail(&map->list, &ctrl->info.mappings);
uvc_trace(UVC_TRACE_CONTROL,
"Adding mapping '%s' to control %pUl/%u.\n",
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c
index 8f54e24e3f35..9288fbd5001b 100644
--- a/drivers/media/video/uvc/uvc_queue.c
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -207,6 +207,19 @@ int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
return ret;
}
+#ifndef CONFIG_MMU
+unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
+ unsigned long pgoff)
+{
+ unsigned long ret;
+
+ mutex_lock(&queue->mutex);
+ ret = vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0);
+ mutex_unlock(&queue->mutex);
+ return ret;
+}
+#endif
+
unsigned int uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
poll_table *wait)
{
@@ -237,36 +250,6 @@ int uvc_queue_allocated(struct uvc_video_queue *queue)
return allocated;
}
-#ifndef CONFIG_MMU
-/*
- * Get unmapped area.
- *
- * NO-MMU arch need this function to make mmap() work correctly.
- */
-unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
- unsigned long pgoff)
-{
- struct uvc_buffer *buffer;
- unsigned int i;
- unsigned long ret;
-
- mutex_lock(&queue->mutex);
- for (i = 0; i < queue->count; ++i) {
- buffer = &queue->buffer[i];
- if ((buffer->buf.m.offset >> PAGE_SHIFT) == pgoff)
- break;
- }
- if (i == queue->count) {
- ret = -EINVAL;
- goto done;
- }
- ret = (unsigned long)buf->mem;
-done:
- mutex_unlock(&queue->mutex);
- return ret;
-}
-#endif
-
/*
* Enable or disable the video buffers queue.
*
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index ff2cdddf9bc6..759bef8897e9 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -25,6 +25,8 @@
#include <linux/atomic.h>
#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
#include <media/v4l2-ioctl.h>
#include "uvcvideo.h"
@@ -505,6 +507,8 @@ static int uvc_v4l2_open(struct file *file)
}
}
+ v4l2_fh_init(&handle->vfh, stream->vdev);
+ v4l2_fh_add(&handle->vfh);
handle->chain = stream->chain;
handle->stream = stream;
handle->state = UVC_HANDLE_PASSIVE;
@@ -528,6 +532,8 @@ static int uvc_v4l2_release(struct file *file)
/* Release the file handle. */
uvc_dismiss_privileges(handle);
+ v4l2_fh_del(&handle->vfh);
+ v4l2_fh_exit(&handle->vfh);
kfree(handle);
file->private_data = NULL;
@@ -584,7 +590,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return ret;
ret = uvc_ctrl_get(chain, &xctrl);
- uvc_ctrl_rollback(chain);
+ uvc_ctrl_rollback(handle);
if (ret >= 0)
ctrl->value = xctrl.value;
break;
@@ -605,10 +611,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
ret = uvc_ctrl_set(chain, &xctrl);
if (ret < 0) {
- uvc_ctrl_rollback(chain);
+ uvc_ctrl_rollback(handle);
return ret;
}
- ret = uvc_ctrl_commit(chain);
+ ret = uvc_ctrl_commit(handle, &xctrl, 1);
if (ret == 0)
ctrl->value = xctrl.value;
break;
@@ -630,13 +636,13 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
for (i = 0; i < ctrls->count; ++ctrl, ++i) {
ret = uvc_ctrl_get(chain, ctrl);
if (ret < 0) {
- uvc_ctrl_rollback(chain);
+ uvc_ctrl_rollback(handle);
ctrls->error_idx = i;
return ret;
}
}
ctrls->error_idx = 0;
- ret = uvc_ctrl_rollback(chain);
+ ret = uvc_ctrl_rollback(handle);
break;
}
@@ -654,7 +660,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
for (i = 0; i < ctrls->count; ++ctrl, ++i) {
ret = uvc_ctrl_set(chain, ctrl);
if (ret < 0) {
- uvc_ctrl_rollback(chain);
+ uvc_ctrl_rollback(handle);
ctrls->error_idx = i;
return ret;
}
@@ -663,9 +669,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
ctrls->error_idx = 0;
if (cmd == VIDIOC_S_EXT_CTRLS)
- ret = uvc_ctrl_commit(chain);
+ ret = uvc_ctrl_commit(handle,
+ ctrls->controls, ctrls->count);
else
- ret = uvc_ctrl_rollback(chain);
+ ret = uvc_ctrl_rollback(handle);
break;
}
@@ -687,7 +694,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
break;
}
pin = iterm->id;
- } else if (pin < selector->bNrInPins) {
+ } else if (index < selector->bNrInPins) {
pin = selector->baSourceID[index];
list_for_each_entry(iterm, &chain->entities, chain) {
if (!UVC_ENTITY_IS_ITERM(iterm))
@@ -990,6 +997,26 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return uvc_video_enable(stream, 0);
}
+ case VIDIOC_SUBSCRIBE_EVENT:
+ {
+ struct v4l2_event_subscription *sub = arg;
+
+ switch (sub->type) {
+ case V4L2_EVENT_CTRL:
+ return v4l2_event_subscribe(&handle->vfh, sub, 0,
+ &uvc_ctrl_sub_ev_ops);
+ default:
+ return -EINVAL;
+ }
+ }
+
+ case VIDIOC_UNSUBSCRIBE_EVENT:
+ return v4l2_event_unsubscribe(&handle->vfh, arg);
+
+ case VIDIOC_DQEVENT:
+ return v4l2_event_dequeue(&handle->vfh, arg,
+ file->f_flags & O_NONBLOCK);
+
/* Analog video standards make no sense for digital cameras. */
case VIDIOC_ENUMSTD:
case VIDIOC_QUERYSTD:
@@ -1097,7 +1124,8 @@ static int uvc_v4l2_put_xu_mapping(const struct uvc_xu_control_mapping *kp,
__put_user(kp->menu_count, &up->menu_count))
return -EFAULT;
- __clear_user(up->reserved, sizeof(up->reserved));
+ if (__clear_user(up->reserved, sizeof(up->reserved)))
+ return -EFAULT;
if (kp->menu_count == 0)
return 0;
@@ -1105,8 +1133,6 @@ static int uvc_v4l2_put_xu_mapping(const struct uvc_xu_control_mapping *kp,
if (get_user(p, &up->menu_info))
return -EFAULT;
umenus = compat_ptr(p);
- if (!access_ok(VERIFY_WRITE, umenus, kp->menu_count * sizeof(*umenus)))
- return -EFAULT;
if (copy_in_user(umenus, kmenus, kp->menu_count * sizeof(*umenus)))
return -EFAULT;
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index 67f88d85bb16..7c3d082505b7 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -13,6 +13,8 @@
#include <linux/videodev2.h>
#include <media/media-device.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fh.h>
#include <media/videobuf2-core.h>
/* --------------------------------------------------------------------------
@@ -153,8 +155,7 @@ struct uvc_control_info {
struct uvc_control_mapping {
struct list_head list;
-
- struct uvc_control_info *ctrl;
+ struct list_head ev_subs;
__u32 id;
__u8 name[32];
@@ -169,6 +170,10 @@ struct uvc_control_mapping {
struct uvc_menu_info *menu_info;
__u32 menu_count;
+ __u32 master_id;
+ __s32 master_manual;
+ __u32 slave_ids[2];
+
__s32 (*get) (struct uvc_control_mapping *mapping, __u8 query,
const __u8 *data);
void (*set) (struct uvc_control_mapping *mapping, __s32 value,
@@ -524,6 +529,7 @@ enum uvc_handle_state {
};
struct uvc_fh {
+ struct v4l2_fh vfh;
struct uvc_video_chain *chain;
struct uvc_streaming *stream;
enum uvc_handle_state state;
@@ -643,6 +649,8 @@ extern int uvc_status_suspend(struct uvc_device *dev);
extern int uvc_status_resume(struct uvc_device *dev);
/* Controls */
+extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops;
+
extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
struct v4l2_queryctrl *v4l2_ctrl);
extern int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
@@ -655,14 +663,18 @@ extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
extern int uvc_ctrl_resume_device(struct uvc_device *dev);
extern int uvc_ctrl_begin(struct uvc_video_chain *chain);
-extern int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback);
-static inline int uvc_ctrl_commit(struct uvc_video_chain *chain)
+extern int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
+ const struct v4l2_ext_control *xctrls,
+ unsigned int xctrls_count);
+static inline int uvc_ctrl_commit(struct uvc_fh *handle,
+ const struct v4l2_ext_control *xctrls,
+ unsigned int xctrls_count)
{
- return __uvc_ctrl_commit(chain, 0);
+ return __uvc_ctrl_commit(handle, 0, xctrls, xctrls_count);
}
-static inline int uvc_ctrl_rollback(struct uvc_video_chain *chain)
+static inline int uvc_ctrl_rollback(struct uvc_fh *handle)
{
- return __uvc_ctrl_commit(chain, 1);
+ return __uvc_ctrl_commit(handle, 1, NULL, 0);
}
extern int uvc_ctrl_get(struct uvc_video_chain *chain,
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
index 2829d256e4b7..5327ad3a6390 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/video/v4l2-compat-ioctl32.c
@@ -37,7 +37,7 @@ struct v4l2_clip32 {
struct v4l2_window32 {
struct v4l2_rect w;
- enum v4l2_field field;
+ __u32 field; /* enum v4l2_field */
__u32 chromakey;
compat_caddr_t clips; /* actually struct v4l2_clip32 * */
__u32 clipcount;
@@ -147,7 +147,7 @@ static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp,
}
struct v4l2_format32 {
- enum v4l2_buf_type type;
+ __u32 type; /* enum v4l2_buf_type */
union {
struct v4l2_pix_format pix;
struct v4l2_pix_format_mplane pix_mp;
@@ -170,7 +170,7 @@ struct v4l2_format32 {
struct v4l2_create_buffers32 {
__u32 index;
__u32 count;
- enum v4l2_memory memory;
+ __u32 memory; /* enum v4l2_memory */
struct v4l2_format32 format;
__u32 reserved[8];
};
@@ -311,16 +311,16 @@ struct v4l2_plane32 {
struct v4l2_buffer32 {
__u32 index;
- enum v4l2_buf_type type;
+ __u32 type; /* enum v4l2_buf_type */
__u32 bytesused;
__u32 flags;
- enum v4l2_field field;
+ __u32 field; /* enum v4l2_field */
struct compat_timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
/* memory location */
- enum v4l2_memory memory;
+ __u32 memory; /* enum v4l2_memory */
union {
__u32 offset;
compat_long_t userptr;
@@ -1023,6 +1023,9 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
case VIDIOC_UNSUBSCRIBE_EVENT:
case VIDIOC_CREATE_BUFS32:
case VIDIOC_PREPARE_BUF32:
+ case VIDIOC_ENUM_DV_TIMINGS:
+ case VIDIOC_QUERY_DV_TIMINGS:
+ case VIDIOC_DV_TIMINGS_CAP:
ret = do_video_ioctl(file, cmd, arg);
break;
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 18015c0a8d31..9abd9abd4502 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -230,6 +230,19 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
"Aperture Priority Mode",
NULL
};
+ static const char * const camera_exposure_metering[] = {
+ "Average",
+ "Center Weighted",
+ "Spot",
+ NULL
+ };
+ static const char * const camera_auto_focus_range[] = {
+ "Auto",
+ "Normal",
+ "Macro",
+ "Infinity",
+ NULL
+ };
static const char * const colorfx[] = {
"None",
"Black & White",
@@ -241,6 +254,47 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
"Grass Green",
"Skin Whiten",
"Vivid",
+ "Aqua",
+ "Art Freeze",
+ "Silhouette",
+ "Solarization",
+ "Antique",
+ "Set Cb/Cr",
+ NULL
+ };
+ static const char * const auto_n_preset_white_balance[] = {
+ "Manual",
+ "Auto",
+ "Incandescent",
+ "Fluorescent",
+ "Fluorescent H",
+ "Horizon",
+ "Daylight",
+ "Flash",
+ "Cloudy",
+ "Shade",
+ NULL,
+ };
+ static const char * const camera_iso_sensitivity_auto[] = {
+ "Manual",
+ "Auto",
+ NULL
+ };
+ static const char * const scene_mode[] = {
+ "None",
+ "Backlight",
+ "Beach/Snow",
+ "Candle Light",
+ "Dusk/Dawn",
+ "Fall Colors",
+ "Fireworks",
+ "Landscape",
+ "Night",
+ "Party/Indoor",
+ "Portrait",
+ "Sports",
+ "Sunset",
+ "Text",
NULL
};
static const char * const tune_preemphasis[] = {
@@ -410,8 +464,18 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
return camera_power_line_frequency;
case V4L2_CID_EXPOSURE_AUTO:
return camera_exposure_auto;
+ case V4L2_CID_EXPOSURE_METERING:
+ return camera_exposure_metering;
+ case V4L2_CID_AUTO_FOCUS_RANGE:
+ return camera_auto_focus_range;
case V4L2_CID_COLORFX:
return colorfx;
+ case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
+ return auto_n_preset_white_balance;
+ case V4L2_CID_ISO_SENSITIVITY_AUTO:
+ return camera_iso_sensitivity_auto;
+ case V4L2_CID_SCENE_MODE:
+ return scene_mode;
case V4L2_CID_TUNE_PREEMPHASIS:
return tune_preemphasis;
case V4L2_CID_FLASH_LED_MODE:
@@ -493,6 +557,7 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: return "Min Number of Capture Buffers";
case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: return "Min Number of Output Buffers";
case V4L2_CID_ALPHA_COMPONENT: return "Alpha Component";
+ case V4L2_CID_COLORFX_CBCR: return "Color Effects, CbCr";
/* MPEG controls */
/* Keep the order of the 'case's the same as in videodev2.h! */
@@ -590,13 +655,26 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_TILT_ABSOLUTE: return "Tilt, Absolute";
case V4L2_CID_FOCUS_ABSOLUTE: return "Focus, Absolute";
case V4L2_CID_FOCUS_RELATIVE: return "Focus, Relative";
- case V4L2_CID_FOCUS_AUTO: return "Focus, Automatic";
+ case V4L2_CID_FOCUS_AUTO: return "Focus, Automatic Continuous";
case V4L2_CID_ZOOM_ABSOLUTE: return "Zoom, Absolute";
case V4L2_CID_ZOOM_RELATIVE: return "Zoom, Relative";
case V4L2_CID_ZOOM_CONTINUOUS: return "Zoom, Continuous";
case V4L2_CID_PRIVACY: return "Privacy";
case V4L2_CID_IRIS_ABSOLUTE: return "Iris, Absolute";
case V4L2_CID_IRIS_RELATIVE: return "Iris, Relative";
+ case V4L2_CID_AUTO_EXPOSURE_BIAS: return "Auto Exposure, Bias";
+ case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: return "White Balance, Auto & Preset";
+ case V4L2_CID_WIDE_DYNAMIC_RANGE: return "Wide Dynamic Range";
+ case V4L2_CID_IMAGE_STABILIZATION: return "Image Stabilization";
+ case V4L2_CID_ISO_SENSITIVITY: return "ISO Sensitivity";
+ case V4L2_CID_ISO_SENSITIVITY_AUTO: return "ISO Sensitivity, Auto";
+ case V4L2_CID_EXPOSURE_METERING: return "Exposure, Metering Mode";
+ case V4L2_CID_SCENE_MODE: return "Scene Mode";
+ case V4L2_CID_3A_LOCK: return "3A Lock";
+ case V4L2_CID_AUTO_FOCUS_START: return "Auto Focus, Start";
+ case V4L2_CID_AUTO_FOCUS_STOP: return "Auto Focus, Stop";
+ case V4L2_CID_AUTO_FOCUS_STATUS: return "Auto Focus, Status";
+ case V4L2_CID_AUTO_FOCUS_RANGE: return "Auto Focus, Range";
/* FM Radio Modulator control */
/* Keep the order of the 'case's the same as in videodev2.h! */
@@ -644,6 +722,17 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_JPEG_COMPRESSION_QUALITY: return "Compression Quality";
case V4L2_CID_JPEG_ACTIVE_MARKER: return "Active Markers";
+ /* Image source controls */
+ case V4L2_CID_IMAGE_SOURCE_CLASS: return "Image Source Controls";
+ case V4L2_CID_VBLANK: return "Vertical Blanking";
+ case V4L2_CID_HBLANK: return "Horizontal Blanking";
+ case V4L2_CID_ANALOGUE_GAIN: return "Analogue Gain";
+
+ /* Image processing controls */
+ case V4L2_CID_IMAGE_PROC_CLASS: return "Image Processing Controls";
+ case V4L2_CID_LINK_FREQ: return "Link Frequency";
+ case V4L2_CID_PIXEL_RATE: return "Pixel Rate";
+
default:
return NULL;
}
@@ -688,6 +777,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:
+ case V4L2_CID_WIDE_DYNAMIC_RANGE:
+ case V4L2_CID_IMAGE_STABILIZATION:
*type = V4L2_CTRL_TYPE_BOOLEAN;
*min = 0;
*max = *step = 1;
@@ -696,6 +787,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_TILT_RESET:
case V4L2_CID_FLASH_STROBE:
case V4L2_CID_FLASH_STROBE_STOP:
+ case V4L2_CID_AUTO_FOCUS_START:
+ case V4L2_CID_AUTO_FOCUS_STOP:
*type = V4L2_CTRL_TYPE_BUTTON;
*flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
*min = *max = *step = *def = 0;
@@ -719,7 +812,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_MPEG_STREAM_TYPE:
case V4L2_CID_MPEG_STREAM_VBI_FMT:
case V4L2_CID_EXPOSURE_AUTO:
+ case V4L2_CID_AUTO_FOCUS_RANGE:
case V4L2_CID_COLORFX:
+ case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
case V4L2_CID_TUNE_PREEMPHASIS:
case V4L2_CID_FLASH_LED_MODE:
case V4L2_CID_FLASH_STROBE_SOURCE:
@@ -733,18 +828,30 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
+ case V4L2_CID_ISO_SENSITIVITY_AUTO:
+ case V4L2_CID_EXPOSURE_METERING:
+ case V4L2_CID_SCENE_MODE:
*type = V4L2_CTRL_TYPE_MENU;
break;
+ case V4L2_CID_LINK_FREQ:
+ *type = V4L2_CTRL_TYPE_INTEGER_MENU;
+ break;
case V4L2_CID_RDS_TX_PS_NAME:
case V4L2_CID_RDS_TX_RADIO_TEXT:
*type = V4L2_CTRL_TYPE_STRING;
break;
+ case V4L2_CID_ISO_SENSITIVITY:
+ case V4L2_CID_AUTO_EXPOSURE_BIAS:
+ *type = V4L2_CTRL_TYPE_INTEGER_MENU;
+ break;
case V4L2_CID_USER_CLASS:
case V4L2_CID_CAMERA_CLASS:
case V4L2_CID_MPEG_CLASS:
case V4L2_CID_FM_TX_CLASS:
case V4L2_CID_FLASH_CLASS:
case V4L2_CID_JPEG_CLASS:
+ case V4L2_CID_IMAGE_SOURCE_CLASS:
+ case V4L2_CID_IMAGE_PROC_CLASS:
*type = V4L2_CTRL_TYPE_CTRL_CLASS;
/* You can neither read not write these */
*flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
@@ -759,6 +866,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
break;
case V4L2_CID_FLASH_FAULT:
case V4L2_CID_JPEG_ACTIVE_MARKER:
+ case V4L2_CID_3A_LOCK:
+ case V4L2_CID_AUTO_FOCUS_STATUS:
*type = V4L2_CTRL_TYPE_BITMASK;
break;
case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
@@ -768,8 +877,12 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
break;
case V4L2_CID_MPEG_VIDEO_DEC_FRAME:
case V4L2_CID_MPEG_VIDEO_DEC_PTS:
+ *flags |= V4L2_CTRL_FLAG_VOLATILE;
+ /* Fall through */
+ case V4L2_CID_PIXEL_RATE:
*type = V4L2_CTRL_TYPE_INTEGER64;
- *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE;
+ *flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ *min = *max = *step = *def = 0;
break;
default:
*type = V4L2_CTRL_TYPE_INTEGER;
@@ -817,6 +930,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
*flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
break;
case V4L2_CID_FLASH_STROBE_STATUS:
+ case V4L2_CID_AUTO_FOCUS_STATUS:
case V4L2_CID_FLASH_READY:
*flags |= V4L2_CTRL_FLAG_READ_ONLY;
break;
@@ -852,7 +966,8 @@ static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 change
ev->u.ctrl.value64 = ctrl->cur.val64;
ev->u.ctrl.minimum = ctrl->minimum;
ev->u.ctrl.maximum = ctrl->maximum;
- if (ctrl->type == V4L2_CTRL_TYPE_MENU)
+ if (ctrl->type == V4L2_CTRL_TYPE_MENU
+ || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
ev->u.ctrl.step = 1;
else
ev->u.ctrl.step = ctrl->step;
@@ -1083,10 +1198,13 @@ static int validate_new_int(const struct v4l2_ctrl *ctrl, s32 *pval)
return 0;
case V4L2_CTRL_TYPE_MENU:
+ case V4L2_CTRL_TYPE_INTEGER_MENU:
if (val < ctrl->minimum || val > ctrl->maximum)
return -ERANGE;
- if (ctrl->qmenu[val][0] == '\0' ||
- (ctrl->menu_skip_mask & (1 << val)))
+ if (ctrl->menu_skip_mask & (1 << val))
+ return -EINVAL;
+ if (ctrl->type == V4L2_CTRL_TYPE_MENU &&
+ ctrl->qmenu[val][0] == '\0')
return -EINVAL;
return 0;
@@ -1114,6 +1232,7 @@ static int validate_new(const struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c
case V4L2_CTRL_TYPE_INTEGER:
case V4L2_CTRL_TYPE_BOOLEAN:
case V4L2_CTRL_TYPE_MENU:
+ case V4L2_CTRL_TYPE_INTEGER_MENU:
case V4L2_CTRL_TYPE_BITMASK:
case V4L2_CTRL_TYPE_BUTTON:
case V4L2_CTRL_TYPE_CTRL_CLASS:
@@ -1152,7 +1271,8 @@ static inline int handler_set_err(struct v4l2_ctrl_handler *hdl, int err)
int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl,
unsigned nr_of_controls_hint)
{
- mutex_init(&hdl->lock);
+ hdl->lock = &hdl->_lock;
+ mutex_init(hdl->lock);
INIT_LIST_HEAD(&hdl->ctrls);
INIT_LIST_HEAD(&hdl->ctrl_refs);
hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8;
@@ -1173,7 +1293,7 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
if (hdl == NULL || hdl->buckets == NULL)
return;
- mutex_lock(&hdl->lock);
+ mutex_lock(hdl->lock);
/* Free all nodes */
list_for_each_entry_safe(ref, next_ref, &hdl->ctrl_refs, node) {
list_del(&ref->node);
@@ -1190,7 +1310,7 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
hdl->buckets = NULL;
hdl->cached = NULL;
hdl->error = 0;
- mutex_unlock(&hdl->lock);
+ mutex_unlock(hdl->lock);
}
EXPORT_SYMBOL(v4l2_ctrl_handler_free);
@@ -1255,9 +1375,9 @@ static struct v4l2_ctrl_ref *find_ref_lock(
struct v4l2_ctrl_ref *ref = NULL;
if (hdl) {
- mutex_lock(&hdl->lock);
+ mutex_lock(hdl->lock);
ref = find_ref(hdl, id);
- mutex_unlock(&hdl->lock);
+ mutex_unlock(hdl->lock);
}
return ref;
}
@@ -1304,7 +1424,7 @@ static int handler_new_ref(struct v4l2_ctrl_handler *hdl,
INIT_LIST_HEAD(&new_ref->node);
- mutex_lock(&hdl->lock);
+ mutex_lock(hdl->lock);
/* Add immediately at the end of the list if the list is empty, or if
the last element in the list has a lower ID.
@@ -1334,7 +1454,7 @@ insert_in_hash:
hdl->buckets[bucket] = new_ref;
unlock:
- mutex_unlock(&hdl->lock);
+ mutex_unlock(hdl->lock);
return 0;
}
@@ -1343,7 +1463,8 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
const struct v4l2_ctrl_ops *ops,
u32 id, const char *name, enum v4l2_ctrl_type type,
s32 min, s32 max, u32 step, s32 def,
- u32 flags, const char * const *qmenu, void *priv)
+ u32 flags, const char * const *qmenu,
+ const s64 *qmenu_int, void *priv)
{
struct v4l2_ctrl *ctrl;
unsigned sz_extra = 0;
@@ -1356,6 +1477,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
(type == V4L2_CTRL_TYPE_INTEGER && step == 0) ||
(type == V4L2_CTRL_TYPE_BITMASK && max == 0) ||
(type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) ||
+ (type == V4L2_CTRL_TYPE_INTEGER_MENU && qmenu_int == NULL) ||
(type == V4L2_CTRL_TYPE_STRING && max == 0)) {
handler_set_err(hdl, -ERANGE);
return NULL;
@@ -1366,6 +1488,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
}
if ((type == V4L2_CTRL_TYPE_INTEGER ||
type == V4L2_CTRL_TYPE_MENU ||
+ type == V4L2_CTRL_TYPE_INTEGER_MENU ||
type == V4L2_CTRL_TYPE_BOOLEAN) &&
(def < min || def > max)) {
handler_set_err(hdl, -ERANGE);
@@ -1400,7 +1523,10 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
ctrl->minimum = min;
ctrl->maximum = max;
ctrl->step = step;
- ctrl->qmenu = qmenu;
+ if (type == V4L2_CTRL_TYPE_MENU)
+ ctrl->qmenu = qmenu;
+ else if (type == V4L2_CTRL_TYPE_INTEGER_MENU)
+ ctrl->qmenu_int = qmenu_int;
ctrl->priv = priv;
ctrl->cur.val = ctrl->val = ctrl->default_value = def;
@@ -1414,9 +1540,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
kfree(ctrl);
return NULL;
}
- mutex_lock(&hdl->lock);
+ mutex_lock(hdl->lock);
list_add_tail(&ctrl->node, &hdl->ctrls);
- mutex_unlock(&hdl->lock);
+ mutex_unlock(hdl->lock);
return ctrl;
}
@@ -1427,6 +1553,7 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
struct v4l2_ctrl *ctrl;
const char *name = cfg->name;
const char * const *qmenu = cfg->qmenu;
+ const s64 *qmenu_int = cfg->qmenu_int;
enum v4l2_ctrl_type type = cfg->type;
u32 flags = cfg->flags;
s32 min = cfg->min;
@@ -1438,18 +1565,24 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step,
&def, &flags);
- is_menu = (cfg->type == V4L2_CTRL_TYPE_MENU);
+ is_menu = (cfg->type == V4L2_CTRL_TYPE_MENU ||
+ cfg->type == V4L2_CTRL_TYPE_INTEGER_MENU);
if (is_menu)
WARN_ON(step);
else
WARN_ON(cfg->menu_skip_mask);
- if (is_menu && qmenu == NULL)
+ if (cfg->type == V4L2_CTRL_TYPE_MENU && qmenu == NULL)
qmenu = v4l2_ctrl_get_menu(cfg->id);
+ else if (cfg->type == V4L2_CTRL_TYPE_INTEGER_MENU &&
+ qmenu_int == NULL) {
+ handler_set_err(hdl, -EINVAL);
+ return NULL;
+ }
ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->id, name,
type, min, max,
is_menu ? cfg->menu_skip_mask : step,
- def, flags, qmenu, priv);
+ def, flags, qmenu, qmenu_int, priv);
if (ctrl)
ctrl->is_private = cfg->is_private;
return ctrl;
@@ -1466,12 +1599,13 @@ struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
u32 flags;
v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
- if (type == V4L2_CTRL_TYPE_MENU) {
+ if (type == V4L2_CTRL_TYPE_MENU
+ || type == V4L2_CTRL_TYPE_INTEGER_MENU) {
handler_set_err(hdl, -EINVAL);
return NULL;
}
return v4l2_ctrl_new(hdl, ops, id, name, type,
- min, max, step, def, flags, NULL, NULL);
+ min, max, step, def, flags, NULL, NULL, NULL);
}
EXPORT_SYMBOL(v4l2_ctrl_new_std);
@@ -1493,10 +1627,31 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
return NULL;
}
return v4l2_ctrl_new(hdl, ops, id, name, type,
- 0, max, mask, def, flags, qmenu, NULL);
+ 0, max, mask, def, flags, qmenu, NULL, NULL);
}
EXPORT_SYMBOL(v4l2_ctrl_new_std_menu);
+/* Helper function for standard integer menu controls */
+struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_ops *ops,
+ u32 id, s32 max, s32 def, const s64 *qmenu_int)
+{
+ const char *name;
+ enum v4l2_ctrl_type type;
+ s32 min;
+ s32 step;
+ u32 flags;
+
+ v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
+ if (type != V4L2_CTRL_TYPE_INTEGER_MENU) {
+ handler_set_err(hdl, -EINVAL);
+ return NULL;
+ }
+ return v4l2_ctrl_new(hdl, ops, id, name, type,
+ 0, max, 0, def, flags, NULL, qmenu_int, NULL);
+}
+EXPORT_SYMBOL(v4l2_ctrl_new_int_menu);
+
/* Add a control from another handler to this handler */
struct v4l2_ctrl *v4l2_ctrl_add_ctrl(struct v4l2_ctrl_handler *hdl,
struct v4l2_ctrl *ctrl)
@@ -1525,7 +1680,7 @@ int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
return 0;
if (hdl->error)
return hdl->error;
- mutex_lock(&add->lock);
+ mutex_lock(add->lock);
list_for_each_entry(ref, &add->ctrl_refs, node) {
struct v4l2_ctrl *ctrl = ref->ctrl;
@@ -1539,7 +1694,7 @@ int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
if (ret)
break;
}
- mutex_unlock(&add->lock);
+ mutex_unlock(add->lock);
return ret;
}
EXPORT_SYMBOL(v4l2_ctrl_add_handler);
@@ -1659,6 +1814,9 @@ static void log_ctrl(const struct v4l2_ctrl *ctrl,
case V4L2_CTRL_TYPE_MENU:
printk(KERN_CONT "%s", ctrl->qmenu[ctrl->cur.val]);
break;
+ case V4L2_CTRL_TYPE_INTEGER_MENU:
+ printk(KERN_CONT "%lld", ctrl->qmenu_int[ctrl->cur.val]);
+ break;
case V4L2_CTRL_TYPE_BITMASK:
printk(KERN_CONT "0x%08x", ctrl->cur.val);
break;
@@ -1700,11 +1858,11 @@ void v4l2_ctrl_handler_log_status(struct v4l2_ctrl_handler *hdl,
len = strlen(prefix);
if (len && prefix[len - 1] != ' ')
colon = ": ";
- mutex_lock(&hdl->lock);
+ mutex_lock(hdl->lock);
list_for_each_entry(ctrl, &hdl->ctrls, node)
if (!(ctrl->flags & V4L2_CTRL_FLAG_DISABLED))
log_ctrl(ctrl, prefix, colon);
- mutex_unlock(&hdl->lock);
+ mutex_unlock(hdl->lock);
}
EXPORT_SYMBOL(v4l2_ctrl_handler_log_status);
@@ -1716,7 +1874,7 @@ int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
if (hdl == NULL)
return 0;
- mutex_lock(&hdl->lock);
+ mutex_lock(hdl->lock);
list_for_each_entry(ctrl, &hdl->ctrls, node)
ctrl->done = false;
@@ -1741,7 +1899,7 @@ int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
if (ret)
break;
}
- mutex_unlock(&hdl->lock);
+ mutex_unlock(hdl->lock);
return ret;
}
EXPORT_SYMBOL(v4l2_ctrl_handler_setup);
@@ -1756,7 +1914,7 @@ int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
if (hdl == NULL)
return -EINVAL;
- mutex_lock(&hdl->lock);
+ mutex_lock(hdl->lock);
/* Try to find it */
ref = find_ref(hdl, id);
@@ -1781,7 +1939,7 @@ int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
break;
}
}
- mutex_unlock(&hdl->lock);
+ mutex_unlock(hdl->lock);
if (!ref)
return -EINVAL;
@@ -1795,7 +1953,8 @@ int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
qc->minimum = ctrl->minimum;
qc->maximum = ctrl->maximum;
qc->default_value = ctrl->default_value;
- if (ctrl->type == V4L2_CTRL_TYPE_MENU)
+ if (ctrl->type == V4L2_CTRL_TYPE_MENU
+ || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
qc->step = 1;
else
qc->step = ctrl->step;
@@ -1825,16 +1984,33 @@ int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm)
qm->reserved = 0;
/* Sanity checks */
- if (ctrl->qmenu == NULL ||
- i < ctrl->minimum || i > ctrl->maximum)
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_MENU:
+ if (ctrl->qmenu == NULL)
+ return -EINVAL;
+ break;
+ case V4L2_CTRL_TYPE_INTEGER_MENU:
+ if (ctrl->qmenu_int == NULL)
+ return -EINVAL;
+ break;
+ default:
return -EINVAL;
+ }
+
+ if (i < ctrl->minimum || i > ctrl->maximum)
+ return -EINVAL;
+
/* Use mask to see if this menu item should be skipped */
if (ctrl->menu_skip_mask & (1 << i))
return -EINVAL;
/* Empty menu items should also be skipped */
- if (ctrl->qmenu[i] == NULL || ctrl->qmenu[i][0] == '\0')
- return -EINVAL;
- strlcpy(qm->name, ctrl->qmenu[i], sizeof(qm->name));
+ if (ctrl->type == V4L2_CTRL_TYPE_MENU) {
+ if (ctrl->qmenu[i] == NULL || ctrl->qmenu[i][0] == '\0')
+ return -EINVAL;
+ strlcpy(qm->name, ctrl->qmenu[i], sizeof(qm->name));
+ } else {
+ qm->value = ctrl->qmenu_int[i];
+ }
return 0;
}
EXPORT_SYMBOL(v4l2_querymenu);
@@ -1940,7 +2116,7 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
belong to the same cluster. */
/* This has to be done with the handler lock taken. */
- mutex_lock(&hdl->lock);
+ mutex_lock(hdl->lock);
/* First zero the helper field in the master control references */
for (i = 0; i < cs->count; i++)
@@ -1962,7 +2138,7 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
/* Point the mref helper to the current helper struct. */
mref->helper = h;
}
- mutex_unlock(&hdl->lock);
+ mutex_unlock(hdl->lock);
return 0;
}
@@ -1996,7 +2172,8 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
return class_check(hdl, cs->ctrl_class);
if (cs->count > ARRAY_SIZE(helper)) {
- helpers = kmalloc(sizeof(helper[0]) * cs->count, GFP_KERNEL);
+ helpers = kmalloc_array(cs->count, sizeof(helper[0]),
+ GFP_KERNEL);
if (helpers == NULL)
return -ENOMEM;
}
@@ -2218,7 +2395,8 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
return class_check(hdl, cs->ctrl_class);
if (cs->count > ARRAY_SIZE(helper)) {
- helpers = kmalloc(sizeof(helper[0]) * cs->count, GFP_KERNEL);
+ helpers = kmalloc_array(cs->count, sizeof(helper[0]),
+ GFP_KERNEL);
if (!helpers)
return -ENOMEM;
}
@@ -2381,9 +2559,13 @@ int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)
}
EXPORT_SYMBOL(v4l2_ctrl_s_ctrl);
-void v4l2_ctrl_add_event(struct v4l2_ctrl *ctrl,
- struct v4l2_subscribed_event *sev)
+static int v4l2_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems)
{
+ struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id);
+
+ if (ctrl == NULL)
+ return -EINVAL;
+
v4l2_ctrl_lock(ctrl);
list_add_tail(&sev->node, &ctrl->ev_subs);
if (ctrl->type != V4L2_CTRL_TYPE_CTRL_CLASS &&
@@ -2394,20 +2576,46 @@ void v4l2_ctrl_add_event(struct v4l2_ctrl *ctrl,
if (!(ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY))
changes |= V4L2_EVENT_CTRL_CH_VALUE;
fill_event(&ev, ctrl, changes);
+ /* Mark the queue as active, allowing this initial
+ event to be accepted. */
+ sev->elems = elems;
v4l2_event_queue_fh(sev->fh, &ev);
}
v4l2_ctrl_unlock(ctrl);
+ return 0;
}
-EXPORT_SYMBOL(v4l2_ctrl_add_event);
-void v4l2_ctrl_del_event(struct v4l2_ctrl *ctrl,
- struct v4l2_subscribed_event *sev)
+static void v4l2_ctrl_del_event(struct v4l2_subscribed_event *sev)
{
+ struct v4l2_ctrl *ctrl = v4l2_ctrl_find(sev->fh->ctrl_handler, sev->id);
+
v4l2_ctrl_lock(ctrl);
list_del(&sev->node);
v4l2_ctrl_unlock(ctrl);
}
-EXPORT_SYMBOL(v4l2_ctrl_del_event);
+
+void v4l2_ctrl_replace(struct v4l2_event *old, const struct v4l2_event *new)
+{
+ u32 old_changes = old->u.ctrl.changes;
+
+ old->u.ctrl = new->u.ctrl;
+ old->u.ctrl.changes |= old_changes;
+}
+EXPORT_SYMBOL(v4l2_ctrl_replace);
+
+void v4l2_ctrl_merge(const struct v4l2_event *old, struct v4l2_event *new)
+{
+ new->u.ctrl.changes |= old->u.ctrl.changes;
+}
+EXPORT_SYMBOL(v4l2_ctrl_merge);
+
+const struct v4l2_subscribed_event_ops v4l2_ctrl_sub_ev_ops = {
+ .add = v4l2_ctrl_add_event,
+ .del = v4l2_ctrl_del_event,
+ .replace = v4l2_ctrl_replace,
+ .merge = v4l2_ctrl_merge,
+};
+EXPORT_SYMBOL(v4l2_ctrl_sub_ev_ops);
int v4l2_ctrl_log_status(struct file *file, void *fh)
{
@@ -2425,7 +2633,7 @@ int v4l2_ctrl_subscribe_event(struct v4l2_fh *fh,
struct v4l2_event_subscription *sub)
{
if (sub->type == V4L2_EVENT_CTRL)
- return v4l2_event_subscribe(fh, sub, 0);
+ return v4l2_event_subscribe(fh, sub, 0, &v4l2_ctrl_sub_ev_ops);
return -EINVAL;
}
EXPORT_SYMBOL(v4l2_ctrl_subscribe_event);
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 70bec548d904..5ccbd4629f9c 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -274,11 +274,12 @@ static ssize_t v4l2_read(struct file *filp, char __user *buf,
if (!vdev->fops->read)
return -EINVAL;
- if (vdev->lock && mutex_lock_interruptible(vdev->lock))
+ if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) &&
+ mutex_lock_interruptible(vdev->lock))
return -ERESTARTSYS;
if (video_is_registered(vdev))
ret = vdev->fops->read(filp, buf, sz, off);
- if (vdev->lock)
+ if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
mutex_unlock(vdev->lock);
return ret;
}
@@ -291,11 +292,12 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf,
if (!vdev->fops->write)
return -EINVAL;
- if (vdev->lock && mutex_lock_interruptible(vdev->lock))
+ if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) &&
+ mutex_lock_interruptible(vdev->lock))
return -ERESTARTSYS;
if (video_is_registered(vdev))
ret = vdev->fops->write(filp, buf, sz, off);
- if (vdev->lock)
+ if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
mutex_unlock(vdev->lock);
return ret;
}
@@ -307,11 +309,11 @@ static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll)
if (!vdev->fops->poll)
return DEFAULT_POLLMASK;
- if (vdev->lock)
+ if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
mutex_lock(vdev->lock);
if (video_is_registered(vdev))
ret = vdev->fops->poll(filp, poll);
- if (vdev->lock)
+ if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
mutex_unlock(vdev->lock);
return ret;
}
@@ -322,11 +324,19 @@ static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
int ret = -ENODEV;
if (vdev->fops->unlocked_ioctl) {
- if (vdev->lock && mutex_lock_interruptible(vdev->lock))
- return -ERESTARTSYS;
+ bool locked = false;
+
+ if (vdev->lock) {
+ /* always lock unless the cmd is marked as "don't use lock" */
+ locked = !v4l2_is_known_ioctl(cmd) ||
+ !test_bit(_IOC_NR(cmd), vdev->disable_locking);
+
+ if (locked && mutex_lock_interruptible(vdev->lock))
+ return -ERESTARTSYS;
+ }
if (video_is_registered(vdev))
ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
- if (vdev->lock)
+ if (locked)
mutex_unlock(vdev->lock);
} else if (vdev->fops->ioctl) {
/* This code path is a replacement for the BKL. It is a major
@@ -391,11 +401,12 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
if (!vdev->fops->mmap)
return ret;
- if (vdev->lock && mutex_lock_interruptible(vdev->lock))
+ if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) &&
+ mutex_lock_interruptible(vdev->lock))
return -ERESTARTSYS;
if (video_is_registered(vdev))
ret = vdev->fops->mmap(filp, vm);
- if (vdev->lock)
+ if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
mutex_unlock(vdev->lock);
return ret;
}
@@ -418,7 +429,8 @@ static int v4l2_open(struct inode *inode, struct file *filp)
video_get(vdev);
mutex_unlock(&videodev_lock);
if (vdev->fops->open) {
- if (vdev->lock && mutex_lock_interruptible(vdev->lock)) {
+ if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) &&
+ mutex_lock_interruptible(vdev->lock)) {
ret = -ERESTARTSYS;
goto err;
}
@@ -426,7 +438,7 @@ static int v4l2_open(struct inode *inode, struct file *filp)
ret = vdev->fops->open(filp);
else
ret = -ENODEV;
- if (vdev->lock)
+ if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
mutex_unlock(vdev->lock);
}
@@ -444,10 +456,10 @@ static int v4l2_release(struct inode *inode, struct file *filp)
int ret = 0;
if (vdev->fops->release) {
- if (vdev->lock)
+ if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
mutex_lock(vdev->lock);
vdev->fops->release(filp);
- if (vdev->lock)
+ if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
mutex_unlock(vdev->lock);
}
/* decrease the refcount unconditionally since the release()
@@ -508,6 +520,175 @@ static int get_index(struct video_device *vdev)
return find_first_zero_bit(used, VIDEO_NUM_DEVICES);
}
+#define SET_VALID_IOCTL(ops, cmd, op) \
+ if (ops->op) \
+ set_bit(_IOC_NR(cmd), valid_ioctls)
+
+/* This determines which ioctls are actually implemented in the driver.
+ It's a one-time thing which simplifies video_ioctl2 as it can just do
+ a bit test.
+
+ Note that drivers can override this by setting bits to 1 in
+ vdev->valid_ioctls. If an ioctl is marked as 1 when this function is
+ called, then that ioctl will actually be marked as unimplemented.
+
+ It does that by first setting up the local valid_ioctls bitmap, and
+ at the end do a:
+
+ vdev->valid_ioctls = valid_ioctls & ~(vdev->valid_ioctls)
+ */
+static void determine_valid_ioctls(struct video_device *vdev)
+{
+ DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE);
+ const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops;
+
+ bitmap_zero(valid_ioctls, BASE_VIDIOC_PRIVATE);
+
+ SET_VALID_IOCTL(ops, VIDIOC_QUERYCAP, vidioc_querycap);
+ if (ops->vidioc_g_priority ||
+ test_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags))
+ set_bit(_IOC_NR(VIDIOC_G_PRIORITY), valid_ioctls);
+ if (ops->vidioc_s_priority ||
+ test_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags))
+ set_bit(_IOC_NR(VIDIOC_S_PRIORITY), valid_ioctls);
+ if (ops->vidioc_enum_fmt_vid_cap ||
+ ops->vidioc_enum_fmt_vid_out ||
+ ops->vidioc_enum_fmt_vid_cap_mplane ||
+ ops->vidioc_enum_fmt_vid_out_mplane ||
+ ops->vidioc_enum_fmt_vid_overlay ||
+ ops->vidioc_enum_fmt_type_private)
+ set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls);
+ if (ops->vidioc_g_fmt_vid_cap ||
+ ops->vidioc_g_fmt_vid_out ||
+ ops->vidioc_g_fmt_vid_cap_mplane ||
+ ops->vidioc_g_fmt_vid_out_mplane ||
+ ops->vidioc_g_fmt_vid_overlay ||
+ ops->vidioc_g_fmt_vbi_cap ||
+ ops->vidioc_g_fmt_vid_out_overlay ||
+ ops->vidioc_g_fmt_vbi_out ||
+ ops->vidioc_g_fmt_sliced_vbi_cap ||
+ ops->vidioc_g_fmt_sliced_vbi_out ||
+ ops->vidioc_g_fmt_type_private)
+ set_bit(_IOC_NR(VIDIOC_G_FMT), valid_ioctls);
+ if (ops->vidioc_s_fmt_vid_cap ||
+ ops->vidioc_s_fmt_vid_out ||
+ ops->vidioc_s_fmt_vid_cap_mplane ||
+ ops->vidioc_s_fmt_vid_out_mplane ||
+ ops->vidioc_s_fmt_vid_overlay ||
+ ops->vidioc_s_fmt_vbi_cap ||
+ ops->vidioc_s_fmt_vid_out_overlay ||
+ ops->vidioc_s_fmt_vbi_out ||
+ ops->vidioc_s_fmt_sliced_vbi_cap ||
+ ops->vidioc_s_fmt_sliced_vbi_out ||
+ ops->vidioc_s_fmt_type_private)
+ set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls);
+ if (ops->vidioc_try_fmt_vid_cap ||
+ ops->vidioc_try_fmt_vid_out ||
+ ops->vidioc_try_fmt_vid_cap_mplane ||
+ ops->vidioc_try_fmt_vid_out_mplane ||
+ ops->vidioc_try_fmt_vid_overlay ||
+ ops->vidioc_try_fmt_vbi_cap ||
+ ops->vidioc_try_fmt_vid_out_overlay ||
+ ops->vidioc_try_fmt_vbi_out ||
+ ops->vidioc_try_fmt_sliced_vbi_cap ||
+ ops->vidioc_try_fmt_sliced_vbi_out ||
+ ops->vidioc_try_fmt_type_private)
+ set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls);
+ SET_VALID_IOCTL(ops, VIDIOC_REQBUFS, vidioc_reqbufs);
+ SET_VALID_IOCTL(ops, VIDIOC_QUERYBUF, vidioc_querybuf);
+ SET_VALID_IOCTL(ops, VIDIOC_QBUF, vidioc_qbuf);
+ SET_VALID_IOCTL(ops, VIDIOC_DQBUF, vidioc_dqbuf);
+ SET_VALID_IOCTL(ops, VIDIOC_OVERLAY, vidioc_overlay);
+ SET_VALID_IOCTL(ops, VIDIOC_G_FBUF, vidioc_g_fbuf);
+ SET_VALID_IOCTL(ops, VIDIOC_S_FBUF, vidioc_s_fbuf);
+ SET_VALID_IOCTL(ops, VIDIOC_STREAMON, vidioc_streamon);
+ SET_VALID_IOCTL(ops, VIDIOC_STREAMOFF, vidioc_streamoff);
+ if (vdev->tvnorms)
+ set_bit(_IOC_NR(VIDIOC_ENUMSTD), valid_ioctls);
+ if (ops->vidioc_g_std || vdev->current_norm)
+ set_bit(_IOC_NR(VIDIOC_G_STD), valid_ioctls);
+ SET_VALID_IOCTL(ops, VIDIOC_S_STD, vidioc_s_std);
+ SET_VALID_IOCTL(ops, VIDIOC_QUERYSTD, vidioc_querystd);
+ SET_VALID_IOCTL(ops, VIDIOC_ENUMINPUT, vidioc_enum_input);
+ SET_VALID_IOCTL(ops, VIDIOC_G_INPUT, vidioc_g_input);
+ SET_VALID_IOCTL(ops, VIDIOC_S_INPUT, vidioc_s_input);
+ SET_VALID_IOCTL(ops, VIDIOC_ENUMOUTPUT, vidioc_enum_output);
+ SET_VALID_IOCTL(ops, VIDIOC_G_OUTPUT, vidioc_g_output);
+ SET_VALID_IOCTL(ops, VIDIOC_S_OUTPUT, vidioc_s_output);
+ /* Note: the control handler can also be passed through the filehandle,
+ and that can't be tested here. If the bit for these control ioctls
+ is set, then the ioctl is valid. But if it is 0, then it can still
+ be valid if the filehandle passed the control handler. */
+ if (vdev->ctrl_handler || ops->vidioc_queryctrl)
+ set_bit(_IOC_NR(VIDIOC_QUERYCTRL), valid_ioctls);
+ if (vdev->ctrl_handler || ops->vidioc_g_ctrl || ops->vidioc_g_ext_ctrls)
+ set_bit(_IOC_NR(VIDIOC_G_CTRL), valid_ioctls);
+ if (vdev->ctrl_handler || ops->vidioc_s_ctrl || ops->vidioc_s_ext_ctrls)
+ set_bit(_IOC_NR(VIDIOC_S_CTRL), valid_ioctls);
+ if (vdev->ctrl_handler || ops->vidioc_g_ext_ctrls)
+ set_bit(_IOC_NR(VIDIOC_G_EXT_CTRLS), valid_ioctls);
+ if (vdev->ctrl_handler || ops->vidioc_s_ext_ctrls)
+ set_bit(_IOC_NR(VIDIOC_S_EXT_CTRLS), valid_ioctls);
+ if (vdev->ctrl_handler || ops->vidioc_try_ext_ctrls)
+ set_bit(_IOC_NR(VIDIOC_TRY_EXT_CTRLS), valid_ioctls);
+ if (vdev->ctrl_handler || ops->vidioc_querymenu)
+ set_bit(_IOC_NR(VIDIOC_QUERYMENU), valid_ioctls);
+ SET_VALID_IOCTL(ops, VIDIOC_ENUMAUDIO, vidioc_enumaudio);
+ SET_VALID_IOCTL(ops, VIDIOC_G_AUDIO, vidioc_g_audio);
+ SET_VALID_IOCTL(ops, VIDIOC_S_AUDIO, vidioc_s_audio);
+ SET_VALID_IOCTL(ops, VIDIOC_ENUMAUDOUT, vidioc_enumaudout);
+ SET_VALID_IOCTL(ops, VIDIOC_G_AUDOUT, vidioc_g_audout);
+ SET_VALID_IOCTL(ops, VIDIOC_S_AUDOUT, vidioc_s_audout);
+ SET_VALID_IOCTL(ops, VIDIOC_G_MODULATOR, vidioc_g_modulator);
+ SET_VALID_IOCTL(ops, VIDIOC_S_MODULATOR, vidioc_s_modulator);
+ if (ops->vidioc_g_crop || ops->vidioc_g_selection)
+ set_bit(_IOC_NR(VIDIOC_G_CROP), valid_ioctls);
+ if (ops->vidioc_s_crop || ops->vidioc_s_selection)
+ set_bit(_IOC_NR(VIDIOC_S_CROP), valid_ioctls);
+ SET_VALID_IOCTL(ops, VIDIOC_G_SELECTION, vidioc_g_selection);
+ SET_VALID_IOCTL(ops, VIDIOC_S_SELECTION, vidioc_s_selection);
+ if (ops->vidioc_cropcap || ops->vidioc_g_selection)
+ set_bit(_IOC_NR(VIDIOC_CROPCAP), valid_ioctls);
+ SET_VALID_IOCTL(ops, VIDIOC_G_JPEGCOMP, vidioc_g_jpegcomp);
+ SET_VALID_IOCTL(ops, VIDIOC_S_JPEGCOMP, vidioc_s_jpegcomp);
+ SET_VALID_IOCTL(ops, VIDIOC_G_ENC_INDEX, vidioc_g_enc_index);
+ SET_VALID_IOCTL(ops, VIDIOC_ENCODER_CMD, vidioc_encoder_cmd);
+ SET_VALID_IOCTL(ops, VIDIOC_TRY_ENCODER_CMD, vidioc_try_encoder_cmd);
+ SET_VALID_IOCTL(ops, VIDIOC_DECODER_CMD, vidioc_decoder_cmd);
+ SET_VALID_IOCTL(ops, VIDIOC_TRY_DECODER_CMD, vidioc_try_decoder_cmd);
+ if (ops->vidioc_g_parm || vdev->current_norm)
+ set_bit(_IOC_NR(VIDIOC_G_PARM), valid_ioctls);
+ SET_VALID_IOCTL(ops, VIDIOC_S_PARM, vidioc_s_parm);
+ SET_VALID_IOCTL(ops, VIDIOC_G_TUNER, vidioc_g_tuner);
+ SET_VALID_IOCTL(ops, VIDIOC_S_TUNER, vidioc_s_tuner);
+ SET_VALID_IOCTL(ops, VIDIOC_G_FREQUENCY, vidioc_g_frequency);
+ SET_VALID_IOCTL(ops, VIDIOC_S_FREQUENCY, vidioc_s_frequency);
+ SET_VALID_IOCTL(ops, VIDIOC_G_SLICED_VBI_CAP, vidioc_g_sliced_vbi_cap);
+ SET_VALID_IOCTL(ops, VIDIOC_LOG_STATUS, vidioc_log_status);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ SET_VALID_IOCTL(ops, VIDIOC_DBG_G_REGISTER, vidioc_g_register);
+ SET_VALID_IOCTL(ops, VIDIOC_DBG_S_REGISTER, vidioc_s_register);
+#endif
+ SET_VALID_IOCTL(ops, VIDIOC_DBG_G_CHIP_IDENT, vidioc_g_chip_ident);
+ SET_VALID_IOCTL(ops, VIDIOC_S_HW_FREQ_SEEK, vidioc_s_hw_freq_seek);
+ SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMESIZES, vidioc_enum_framesizes);
+ SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMEINTERVALS, vidioc_enum_frameintervals);
+ SET_VALID_IOCTL(ops, VIDIOC_ENUM_DV_PRESETS, vidioc_enum_dv_presets);
+ SET_VALID_IOCTL(ops, VIDIOC_S_DV_PRESET, vidioc_s_dv_preset);
+ SET_VALID_IOCTL(ops, VIDIOC_G_DV_PRESET, vidioc_g_dv_preset);
+ SET_VALID_IOCTL(ops, VIDIOC_QUERY_DV_PRESET, vidioc_query_dv_preset);
+ SET_VALID_IOCTL(ops, VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings);
+ SET_VALID_IOCTL(ops, VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings);
+ /* yes, really vidioc_subscribe_event */
+ SET_VALID_IOCTL(ops, VIDIOC_DQEVENT, vidioc_subscribe_event);
+ SET_VALID_IOCTL(ops, VIDIOC_SUBSCRIBE_EVENT, vidioc_subscribe_event);
+ SET_VALID_IOCTL(ops, VIDIOC_UNSUBSCRIBE_EVENT, vidioc_unsubscribe_event);
+ SET_VALID_IOCTL(ops, VIDIOC_CREATE_BUFS, vidioc_create_bufs);
+ SET_VALID_IOCTL(ops, VIDIOC_PREPARE_BUF, vidioc_prepare_buf);
+ bitmap_andnot(vdev->valid_ioctls, valid_ioctls, vdev->valid_ioctls,
+ BASE_VIDIOC_PRIVATE);
+}
+
/**
* __video_register_device - register video4linux devices
* @vdev: video device structure we want to register
@@ -654,6 +835,13 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
WARN_ON(video_device[vdev->minor] != NULL);
vdev->index = get_index(vdev);
mutex_unlock(&videodev_lock);
+ /* if no lock was passed, then make sure the LOCK_ALL_FOPS bit is
+ clear and warn if it wasn't. */
+ if (vdev->lock == NULL)
+ WARN_ON(test_and_clear_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags));
+
+ if (vdev->ioctl_ops)
+ determine_valid_ioctls(vdev);
/* Part 3: Initialize the character device */
vdev->cdev = cdev_alloc();
diff --git a/drivers/media/video/v4l2-event.c b/drivers/media/video/v4l2-event.c
index c26ad9637143..ef2a33c94045 100644
--- a/drivers/media/video/v4l2-event.c
+++ b/drivers/media/video/v4l2-event.c
@@ -25,7 +25,6 @@
#include <media/v4l2-dev.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-event.h>
-#include <media/v4l2-ctrls.h>
#include <linux/sched.h>
#include <linux/slab.h>
@@ -120,6 +119,14 @@ static void __v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *e
if (sev == NULL)
return;
+ /*
+ * If the event has been added to the fh->subscribed list, but its
+ * add op has not completed yet elems will be 0, treat this as
+ * not being subscribed.
+ */
+ if (!sev->elems)
+ return;
+
/* Increase event sequence number on fh. */
fh->sequence++;
@@ -132,14 +139,14 @@ static void __v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *e
sev->first = sev_pos(sev, 1);
fh->navailable--;
if (sev->elems == 1) {
- if (sev->replace) {
- sev->replace(&kev->event, ev);
+ if (sev->ops && sev->ops->replace) {
+ sev->ops->replace(&kev->event, ev);
copy_payload = false;
}
- } else if (sev->merge) {
+ } else if (sev->ops && sev->ops->merge) {
struct v4l2_kevent *second_oldest =
sev->events + sev_pos(sev, 0);
- sev->merge(&kev->event, &second_oldest->event);
+ sev->ops->merge(&kev->event, &second_oldest->event);
}
}
@@ -195,24 +202,11 @@ int v4l2_event_pending(struct v4l2_fh *fh)
}
EXPORT_SYMBOL_GPL(v4l2_event_pending);
-static void ctrls_replace(struct v4l2_event *old, const struct v4l2_event *new)
-{
- u32 old_changes = old->u.ctrl.changes;
-
- old->u.ctrl = new->u.ctrl;
- old->u.ctrl.changes |= old_changes;
-}
-
-static void ctrls_merge(const struct v4l2_event *old, struct v4l2_event *new)
-{
- new->u.ctrl.changes |= old->u.ctrl.changes;
-}
-
int v4l2_event_subscribe(struct v4l2_fh *fh,
- struct v4l2_event_subscription *sub, unsigned elems)
+ struct v4l2_event_subscription *sub, unsigned elems,
+ const struct v4l2_subscribed_event_ops *ops)
{
struct v4l2_subscribed_event *sev, *found_ev;
- struct v4l2_ctrl *ctrl = NULL;
unsigned long flags;
unsigned i;
@@ -221,11 +215,6 @@ int v4l2_event_subscribe(struct v4l2_fh *fh,
if (elems < 1)
elems = 1;
- if (sub->type == V4L2_EVENT_CTRL) {
- ctrl = v4l2_ctrl_find(fh->ctrl_handler, sub->id);
- if (ctrl == NULL)
- return -EINVAL;
- }
sev = kzalloc(sizeof(*sev) + sizeof(struct v4l2_kevent) * elems, GFP_KERNEL);
if (!sev)
@@ -236,11 +225,7 @@ int v4l2_event_subscribe(struct v4l2_fh *fh,
sev->id = sub->id;
sev->flags = sub->flags;
sev->fh = fh;
- sev->elems = elems;
- if (ctrl) {
- sev->replace = ctrls_replace;
- sev->merge = ctrls_merge;
- }
+ sev->ops = ops;
spin_lock_irqsave(&fh->vdev->fh_lock, flags);
found_ev = v4l2_event_subscribed(fh, sub->type, sub->id);
@@ -248,11 +233,22 @@ int v4l2_event_subscribe(struct v4l2_fh *fh,
list_add(&sev->list, &fh->subscribed);
spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
- /* v4l2_ctrl_add_event uses a mutex, so do this outside the spin lock */
- if (found_ev)
+ if (found_ev) {
kfree(sev);
- else if (ctrl)
- v4l2_ctrl_add_event(ctrl, sev);
+ return 0; /* Already listening */
+ }
+
+ if (sev->ops && sev->ops->add) {
+ int ret = sev->ops->add(sev, elems);
+ if (ret) {
+ sev->ops = NULL;
+ v4l2_event_unsubscribe(fh, sub);
+ return ret;
+ }
+ }
+
+ /* Mark as ready for use */
+ sev->elems = elems;
return 0;
}
@@ -306,12 +302,9 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh,
}
spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
- if (sev && sev->type == V4L2_EVENT_CTRL) {
- struct v4l2_ctrl *ctrl = v4l2_ctrl_find(fh->ctrl_handler, sev->id);
- if (ctrl)
- v4l2_ctrl_del_event(ctrl, sev);
- }
+ if (sev && sev->ops && sev->ops->del)
+ sev->ops->del(sev);
kfree(sev);
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 5b2ec1fd2d0a..91be4e871f43 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -55,19 +55,6 @@
memset((u8 *)(p) + offsetof(typeof(*(p)), field) + sizeof((p)->field), \
0, sizeof(*(p)) - offsetof(typeof(*(p)), field) - sizeof((p)->field))
-#define have_fmt_ops(foo) ( \
- ops->vidioc_##foo##_fmt_vid_cap || \
- ops->vidioc_##foo##_fmt_vid_out || \
- ops->vidioc_##foo##_fmt_vid_cap_mplane || \
- ops->vidioc_##foo##_fmt_vid_out_mplane || \
- ops->vidioc_##foo##_fmt_vid_overlay || \
- ops->vidioc_##foo##_fmt_vbi_cap || \
- ops->vidioc_##foo##_fmt_vid_out_overlay || \
- ops->vidioc_##foo##_fmt_vbi_out || \
- ops->vidioc_##foo##_fmt_sliced_vbi_cap || \
- ops->vidioc_##foo##_fmt_sliced_vbi_out || \
- ops->vidioc_##foo##_fmt_type_private)
-
struct std_descr {
v4l2_std_id std;
const char *descr;
@@ -195,93 +182,118 @@ static const char *v4l2_memory_names[] = {
/* ------------------------------------------------------------------ */
/* debug help functions */
-static const char *v4l2_ioctls[] = {
- [_IOC_NR(VIDIOC_QUERYCAP)] = "VIDIOC_QUERYCAP",
- [_IOC_NR(VIDIOC_RESERVED)] = "VIDIOC_RESERVED",
- [_IOC_NR(VIDIOC_ENUM_FMT)] = "VIDIOC_ENUM_FMT",
- [_IOC_NR(VIDIOC_G_FMT)] = "VIDIOC_G_FMT",
- [_IOC_NR(VIDIOC_S_FMT)] = "VIDIOC_S_FMT",
- [_IOC_NR(VIDIOC_REQBUFS)] = "VIDIOC_REQBUFS",
- [_IOC_NR(VIDIOC_QUERYBUF)] = "VIDIOC_QUERYBUF",
- [_IOC_NR(VIDIOC_G_FBUF)] = "VIDIOC_G_FBUF",
- [_IOC_NR(VIDIOC_S_FBUF)] = "VIDIOC_S_FBUF",
- [_IOC_NR(VIDIOC_OVERLAY)] = "VIDIOC_OVERLAY",
- [_IOC_NR(VIDIOC_QBUF)] = "VIDIOC_QBUF",
- [_IOC_NR(VIDIOC_DQBUF)] = "VIDIOC_DQBUF",
- [_IOC_NR(VIDIOC_STREAMON)] = "VIDIOC_STREAMON",
- [_IOC_NR(VIDIOC_STREAMOFF)] = "VIDIOC_STREAMOFF",
- [_IOC_NR(VIDIOC_G_PARM)] = "VIDIOC_G_PARM",
- [_IOC_NR(VIDIOC_S_PARM)] = "VIDIOC_S_PARM",
- [_IOC_NR(VIDIOC_G_STD)] = "VIDIOC_G_STD",
- [_IOC_NR(VIDIOC_S_STD)] = "VIDIOC_S_STD",
- [_IOC_NR(VIDIOC_ENUMSTD)] = "VIDIOC_ENUMSTD",
- [_IOC_NR(VIDIOC_ENUMINPUT)] = "VIDIOC_ENUMINPUT",
- [_IOC_NR(VIDIOC_G_CTRL)] = "VIDIOC_G_CTRL",
- [_IOC_NR(VIDIOC_S_CTRL)] = "VIDIOC_S_CTRL",
- [_IOC_NR(VIDIOC_G_TUNER)] = "VIDIOC_G_TUNER",
- [_IOC_NR(VIDIOC_S_TUNER)] = "VIDIOC_S_TUNER",
- [_IOC_NR(VIDIOC_G_AUDIO)] = "VIDIOC_G_AUDIO",
- [_IOC_NR(VIDIOC_S_AUDIO)] = "VIDIOC_S_AUDIO",
- [_IOC_NR(VIDIOC_QUERYCTRL)] = "VIDIOC_QUERYCTRL",
- [_IOC_NR(VIDIOC_QUERYMENU)] = "VIDIOC_QUERYMENU",
- [_IOC_NR(VIDIOC_G_INPUT)] = "VIDIOC_G_INPUT",
- [_IOC_NR(VIDIOC_S_INPUT)] = "VIDIOC_S_INPUT",
- [_IOC_NR(VIDIOC_G_OUTPUT)] = "VIDIOC_G_OUTPUT",
- [_IOC_NR(VIDIOC_S_OUTPUT)] = "VIDIOC_S_OUTPUT",
- [_IOC_NR(VIDIOC_ENUMOUTPUT)] = "VIDIOC_ENUMOUTPUT",
- [_IOC_NR(VIDIOC_G_AUDOUT)] = "VIDIOC_G_AUDOUT",
- [_IOC_NR(VIDIOC_S_AUDOUT)] = "VIDIOC_S_AUDOUT",
- [_IOC_NR(VIDIOC_G_MODULATOR)] = "VIDIOC_G_MODULATOR",
- [_IOC_NR(VIDIOC_S_MODULATOR)] = "VIDIOC_S_MODULATOR",
- [_IOC_NR(VIDIOC_G_FREQUENCY)] = "VIDIOC_G_FREQUENCY",
- [_IOC_NR(VIDIOC_S_FREQUENCY)] = "VIDIOC_S_FREQUENCY",
- [_IOC_NR(VIDIOC_CROPCAP)] = "VIDIOC_CROPCAP",
- [_IOC_NR(VIDIOC_G_CROP)] = "VIDIOC_G_CROP",
- [_IOC_NR(VIDIOC_S_CROP)] = "VIDIOC_S_CROP",
- [_IOC_NR(VIDIOC_G_SELECTION)] = "VIDIOC_G_SELECTION",
- [_IOC_NR(VIDIOC_S_SELECTION)] = "VIDIOC_S_SELECTION",
- [_IOC_NR(VIDIOC_G_JPEGCOMP)] = "VIDIOC_G_JPEGCOMP",
- [_IOC_NR(VIDIOC_S_JPEGCOMP)] = "VIDIOC_S_JPEGCOMP",
- [_IOC_NR(VIDIOC_QUERYSTD)] = "VIDIOC_QUERYSTD",
- [_IOC_NR(VIDIOC_TRY_FMT)] = "VIDIOC_TRY_FMT",
- [_IOC_NR(VIDIOC_ENUMAUDIO)] = "VIDIOC_ENUMAUDIO",
- [_IOC_NR(VIDIOC_ENUMAUDOUT)] = "VIDIOC_ENUMAUDOUT",
- [_IOC_NR(VIDIOC_G_PRIORITY)] = "VIDIOC_G_PRIORITY",
- [_IOC_NR(VIDIOC_S_PRIORITY)] = "VIDIOC_S_PRIORITY",
- [_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP",
- [_IOC_NR(VIDIOC_LOG_STATUS)] = "VIDIOC_LOG_STATUS",
- [_IOC_NR(VIDIOC_G_EXT_CTRLS)] = "VIDIOC_G_EXT_CTRLS",
- [_IOC_NR(VIDIOC_S_EXT_CTRLS)] = "VIDIOC_S_EXT_CTRLS",
- [_IOC_NR(VIDIOC_TRY_EXT_CTRLS)] = "VIDIOC_TRY_EXT_CTRLS",
-#if 1
- [_IOC_NR(VIDIOC_ENUM_FRAMESIZES)] = "VIDIOC_ENUM_FRAMESIZES",
- [_IOC_NR(VIDIOC_ENUM_FRAMEINTERVALS)] = "VIDIOC_ENUM_FRAMEINTERVALS",
- [_IOC_NR(VIDIOC_G_ENC_INDEX)] = "VIDIOC_G_ENC_INDEX",
- [_IOC_NR(VIDIOC_ENCODER_CMD)] = "VIDIOC_ENCODER_CMD",
- [_IOC_NR(VIDIOC_TRY_ENCODER_CMD)] = "VIDIOC_TRY_ENCODER_CMD",
-
- [_IOC_NR(VIDIOC_DECODER_CMD)] = "VIDIOC_DECODER_CMD",
- [_IOC_NR(VIDIOC_TRY_DECODER_CMD)] = "VIDIOC_TRY_DECODER_CMD",
- [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER",
- [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER",
-
- [_IOC_NR(VIDIOC_DBG_G_CHIP_IDENT)] = "VIDIOC_DBG_G_CHIP_IDENT",
- [_IOC_NR(VIDIOC_S_HW_FREQ_SEEK)] = "VIDIOC_S_HW_FREQ_SEEK",
+
+struct v4l2_ioctl_info {
+ unsigned int ioctl;
+ u16 flags;
+ const char * const name;
+};
+
+/* This control needs a priority check */
+#define INFO_FL_PRIO (1 << 0)
+/* This control can be valid if the filehandle passes a control handler. */
+#define INFO_FL_CTRL (1 << 1)
+
+#define IOCTL_INFO(_ioctl, _flags) [_IOC_NR(_ioctl)] = { \
+ .ioctl = _ioctl, \
+ .flags = _flags, \
+ .name = #_ioctl, \
+}
+
+static struct v4l2_ioctl_info v4l2_ioctls[] = {
+ IOCTL_INFO(VIDIOC_QUERYCAP, 0),
+ IOCTL_INFO(VIDIOC_ENUM_FMT, 0),
+ IOCTL_INFO(VIDIOC_G_FMT, 0),
+ IOCTL_INFO(VIDIOC_S_FMT, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_REQBUFS, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_QUERYBUF, 0),
+ IOCTL_INFO(VIDIOC_G_FBUF, 0),
+ IOCTL_INFO(VIDIOC_S_FBUF, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_OVERLAY, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_QBUF, 0),
+ IOCTL_INFO(VIDIOC_DQBUF, 0),
+ IOCTL_INFO(VIDIOC_STREAMON, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_STREAMOFF, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_G_PARM, 0),
+ IOCTL_INFO(VIDIOC_S_PARM, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_G_STD, 0),
+ IOCTL_INFO(VIDIOC_S_STD, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_ENUMSTD, 0),
+ IOCTL_INFO(VIDIOC_ENUMINPUT, 0),
+ IOCTL_INFO(VIDIOC_G_CTRL, INFO_FL_CTRL),
+ IOCTL_INFO(VIDIOC_S_CTRL, INFO_FL_PRIO | INFO_FL_CTRL),
+ IOCTL_INFO(VIDIOC_G_TUNER, 0),
+ IOCTL_INFO(VIDIOC_S_TUNER, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_G_AUDIO, 0),
+ IOCTL_INFO(VIDIOC_S_AUDIO, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_QUERYCTRL, INFO_FL_CTRL),
+ IOCTL_INFO(VIDIOC_QUERYMENU, INFO_FL_CTRL),
+ IOCTL_INFO(VIDIOC_G_INPUT, 0),
+ IOCTL_INFO(VIDIOC_S_INPUT, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_G_OUTPUT, 0),
+ IOCTL_INFO(VIDIOC_S_OUTPUT, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_ENUMOUTPUT, 0),
+ IOCTL_INFO(VIDIOC_G_AUDOUT, 0),
+ IOCTL_INFO(VIDIOC_S_AUDOUT, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_G_MODULATOR, 0),
+ IOCTL_INFO(VIDIOC_S_MODULATOR, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_G_FREQUENCY, 0),
+ IOCTL_INFO(VIDIOC_S_FREQUENCY, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_CROPCAP, 0),
+ IOCTL_INFO(VIDIOC_G_CROP, 0),
+ IOCTL_INFO(VIDIOC_S_CROP, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_G_SELECTION, 0),
+ IOCTL_INFO(VIDIOC_S_SELECTION, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_G_JPEGCOMP, 0),
+ IOCTL_INFO(VIDIOC_S_JPEGCOMP, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_QUERYSTD, 0),
+ IOCTL_INFO(VIDIOC_TRY_FMT, 0),
+ IOCTL_INFO(VIDIOC_ENUMAUDIO, 0),
+ IOCTL_INFO(VIDIOC_ENUMAUDOUT, 0),
+ IOCTL_INFO(VIDIOC_G_PRIORITY, 0),
+ IOCTL_INFO(VIDIOC_S_PRIORITY, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_G_SLICED_VBI_CAP, 0),
+ IOCTL_INFO(VIDIOC_LOG_STATUS, 0),
+ IOCTL_INFO(VIDIOC_G_EXT_CTRLS, INFO_FL_CTRL),
+ IOCTL_INFO(VIDIOC_S_EXT_CTRLS, INFO_FL_PRIO | INFO_FL_CTRL),
+ IOCTL_INFO(VIDIOC_TRY_EXT_CTRLS, 0),
+ IOCTL_INFO(VIDIOC_ENUM_FRAMESIZES, 0),
+ IOCTL_INFO(VIDIOC_ENUM_FRAMEINTERVALS, 0),
+ IOCTL_INFO(VIDIOC_G_ENC_INDEX, 0),
+ IOCTL_INFO(VIDIOC_ENCODER_CMD, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_TRY_ENCODER_CMD, 0),
+ IOCTL_INFO(VIDIOC_DECODER_CMD, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_TRY_DECODER_CMD, 0),
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ IOCTL_INFO(VIDIOC_DBG_S_REGISTER, 0),
+ IOCTL_INFO(VIDIOC_DBG_G_REGISTER, 0),
#endif
- [_IOC_NR(VIDIOC_ENUM_DV_PRESETS)] = "VIDIOC_ENUM_DV_PRESETS",
- [_IOC_NR(VIDIOC_S_DV_PRESET)] = "VIDIOC_S_DV_PRESET",
- [_IOC_NR(VIDIOC_G_DV_PRESET)] = "VIDIOC_G_DV_PRESET",
- [_IOC_NR(VIDIOC_QUERY_DV_PRESET)] = "VIDIOC_QUERY_DV_PRESET",
- [_IOC_NR(VIDIOC_S_DV_TIMINGS)] = "VIDIOC_S_DV_TIMINGS",
- [_IOC_NR(VIDIOC_G_DV_TIMINGS)] = "VIDIOC_G_DV_TIMINGS",
- [_IOC_NR(VIDIOC_DQEVENT)] = "VIDIOC_DQEVENT",
- [_IOC_NR(VIDIOC_SUBSCRIBE_EVENT)] = "VIDIOC_SUBSCRIBE_EVENT",
- [_IOC_NR(VIDIOC_UNSUBSCRIBE_EVENT)] = "VIDIOC_UNSUBSCRIBE_EVENT",
- [_IOC_NR(VIDIOC_CREATE_BUFS)] = "VIDIOC_CREATE_BUFS",
- [_IOC_NR(VIDIOC_PREPARE_BUF)] = "VIDIOC_PREPARE_BUF",
+ IOCTL_INFO(VIDIOC_DBG_G_CHIP_IDENT, 0),
+ IOCTL_INFO(VIDIOC_S_HW_FREQ_SEEK, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_ENUM_DV_PRESETS, 0),
+ IOCTL_INFO(VIDIOC_S_DV_PRESET, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_G_DV_PRESET, 0),
+ IOCTL_INFO(VIDIOC_QUERY_DV_PRESET, 0),
+ IOCTL_INFO(VIDIOC_S_DV_TIMINGS, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_G_DV_TIMINGS, 0),
+ IOCTL_INFO(VIDIOC_DQEVENT, 0),
+ IOCTL_INFO(VIDIOC_SUBSCRIBE_EVENT, 0),
+ IOCTL_INFO(VIDIOC_UNSUBSCRIBE_EVENT, 0),
+ IOCTL_INFO(VIDIOC_CREATE_BUFS, INFO_FL_PRIO),
+ IOCTL_INFO(VIDIOC_PREPARE_BUF, 0),
+ IOCTL_INFO(VIDIOC_ENUM_DV_TIMINGS, 0),
+ IOCTL_INFO(VIDIOC_QUERY_DV_TIMINGS, 0),
+ IOCTL_INFO(VIDIOC_DV_TIMINGS_CAP, 0),
};
#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
+bool v4l2_is_known_ioctl(unsigned int cmd)
+{
+ if (_IOC_NR(cmd) >= V4L2_IOCTLS)
+ return false;
+ return v4l2_ioctls[_IOC_NR(cmd)].ioctl == cmd;
+}
+
/* Common ioctl debug function. This function can be used by
external ioctl messages as well as internal V4L ioctl */
void v4l_printk_ioctl(unsigned int cmd)
@@ -297,7 +309,7 @@ void v4l_printk_ioctl(unsigned int cmd)
type = "v4l2";
break;
}
- printk("%s", v4l2_ioctls[_IOC_NR(cmd)]);
+ printk("%s", v4l2_ioctls[_IOC_NR(cmd)].name);
return;
default:
type = "unknown";
@@ -359,6 +371,34 @@ static inline void dbgrect(struct video_device *vfd, char *s,
r->width, r->height);
};
+static void dbgtimings(struct video_device *vfd,
+ const struct v4l2_dv_timings *p)
+{
+ switch (p->type) {
+ case V4L2_DV_BT_656_1120:
+ dbgarg2("bt-656/1120:interlaced=%d,"
+ " pixelclock=%lld,"
+ " width=%d, height=%d, polarities=%x,"
+ " hfrontporch=%d, hsync=%d,"
+ " hbackporch=%d, vfrontporch=%d,"
+ " vsync=%d, vbackporch=%d,"
+ " il_vfrontporch=%d, il_vsync=%d,"
+ " il_vbackporch=%d, standards=%x, flags=%x\n",
+ p->bt.interlaced, p->bt.pixelclock,
+ p->bt.width, p->bt.height,
+ p->bt.polarities, p->bt.hfrontporch,
+ p->bt.hsync, p->bt.hbackporch,
+ p->bt.vfrontporch, p->bt.vsync,
+ p->bt.vbackporch, p->bt.il_vfrontporch,
+ p->bt.il_vsync, p->bt.il_vbackporch,
+ p->bt.standards, p->bt.flags);
+ break;
+ default:
+ dbgarg2("Unknown type %d!\n", p->type);
+ break;
+ }
+}
+
static inline void v4l_print_pix_fmt(struct video_device *vfd,
struct v4l2_pix_format *fmt)
{
@@ -504,7 +544,6 @@ static long __video_do_ioctl(struct file *file,
void *fh = file->private_data;
struct v4l2_fh *vfh = NULL;
int use_fh_prio = 0;
- long ret_prio = 0;
long ret = -ENOTTY;
if (ops == NULL) {
@@ -513,19 +552,30 @@ static long __video_do_ioctl(struct file *file,
return ret;
}
- if ((vfd->debug & V4L2_DEBUG_IOCTL) &&
- !(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) {
- v4l_print_ioctl(vfd->name, cmd);
- printk(KERN_CONT "\n");
- }
-
if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) {
vfh = file->private_data;
use_fh_prio = test_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
}
- if (use_fh_prio)
- ret_prio = v4l2_prio_check(vfd->prio, vfh->prio);
+ if (v4l2_is_known_ioctl(cmd)) {
+ struct v4l2_ioctl_info *info = &v4l2_ioctls[_IOC_NR(cmd)];
+
+ if (!test_bit(_IOC_NR(cmd), vfd->valid_ioctls) &&
+ !((info->flags & INFO_FL_CTRL) && vfh && vfh->ctrl_handler))
+ return -ENOTTY;
+
+ if (use_fh_prio && (info->flags & INFO_FL_PRIO)) {
+ ret = v4l2_prio_check(vfd->prio, vfh->prio);
+ if (ret)
+ return ret;
+ }
+ }
+
+ if ((vfd->debug & V4L2_DEBUG_IOCTL) &&
+ !(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) {
+ v4l_print_ioctl(vfd->name, cmd);
+ printk(KERN_CONT "\n");
+ }
switch (cmd) {
@@ -534,9 +584,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_capability *cap = (struct v4l2_capability *)arg;
- if (!ops->vidioc_querycap)
- break;
-
cap->version = LINUX_VERSION_CODE;
ret = ops->vidioc_querycap(file, fh, cap);
if (!ret)
@@ -570,14 +617,11 @@ static long __video_do_ioctl(struct file *file,
{
enum v4l2_priority *p = arg;
- if (!ops->vidioc_s_priority && !use_fh_prio)
- break;
dbgarg(cmd, "setting priority to %d\n", *p);
if (ops->vidioc_s_priority)
ret = ops->vidioc_s_priority(file, fh, *p);
else
- ret = ret_prio ? ret_prio :
- v4l2_prio_change(&vfd->v4l2_dev->prio,
+ ret = v4l2_prio_change(&vfd->v4l2_dev->prio,
&vfh->prio, *p);
break;
}
@@ -587,6 +631,7 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_fmtdesc *f = arg;
+ ret = -EINVAL;
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
if (likely(ops->vidioc_enum_fmt_vid_cap))
@@ -619,7 +664,7 @@ static long __video_do_ioctl(struct file *file,
default:
break;
}
- if (likely (!ret))
+ if (likely(!ret))
dbgarg(cmd, "index=%d, type=%d, flags=%d, "
"pixelformat=%c%c%c%c, description='%s'\n",
f->index, f->type, f->flags,
@@ -628,14 +673,6 @@ static long __video_do_ioctl(struct file *file,
(f->pixelformat >> 16) & 0xff,
(f->pixelformat >> 24) & 0xff,
f->description);
- else if (ret == -ENOTTY &&
- (ops->vidioc_enum_fmt_vid_cap ||
- ops->vidioc_enum_fmt_vid_out ||
- ops->vidioc_enum_fmt_vid_cap_mplane ||
- ops->vidioc_enum_fmt_vid_out_mplane ||
- ops->vidioc_enum_fmt_vid_overlay ||
- ops->vidioc_enum_fmt_type_private))
- ret = -EINVAL;
break;
}
case VIDIOC_G_FMT:
@@ -645,6 +682,7 @@ static long __video_do_ioctl(struct file *file,
/* FIXME: Should be one dump per type */
dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names));
+ ret = -EINVAL;
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
if (ops->vidioc_g_fmt_vid_cap)
@@ -706,21 +744,12 @@ static long __video_do_ioctl(struct file *file,
fh, f);
break;
}
- if (unlikely(ret == -ENOTTY && have_fmt_ops(g)))
- ret = -EINVAL;
-
break;
}
case VIDIOC_S_FMT:
{
struct v4l2_format *f = (struct v4l2_format *)arg;
- if (!have_fmt_ops(s))
- break;
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
ret = -EINVAL;
/* FIXME: Should be one dump per type */
@@ -804,6 +833,7 @@ static long __video_do_ioctl(struct file *file,
/* FIXME: Should be one dump per type */
dbgarg(cmd, "type=%s\n", prt_names(f->type,
v4l2_type_names));
+ ret = -EINVAL;
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
CLEAR_AFTER_FIELD(f, fmt.pix);
@@ -876,8 +906,6 @@ static long __video_do_ioctl(struct file *file,
fh, f);
break;
}
- if (unlikely(ret == -ENOTTY && have_fmt_ops(try)))
- ret = -EINVAL;
break;
}
/* FIXME: Those buf reqs could be handled here,
@@ -888,12 +916,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_requestbuffers *p = arg;
- if (!ops->vidioc_reqbufs)
- break;
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
ret = check_fmt(ops, p->type);
if (ret)
break;
@@ -912,8 +934,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_buffer *p = arg;
- if (!ops->vidioc_querybuf)
- break;
ret = check_fmt(ops, p->type);
if (ret)
break;
@@ -927,8 +947,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_buffer *p = arg;
- if (!ops->vidioc_qbuf)
- break;
ret = check_fmt(ops, p->type);
if (ret)
break;
@@ -942,8 +960,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_buffer *p = arg;
- if (!ops->vidioc_dqbuf)
- break;
ret = check_fmt(ops, p->type);
if (ret)
break;
@@ -957,12 +973,6 @@ static long __video_do_ioctl(struct file *file,
{
int *i = arg;
- if (!ops->vidioc_overlay)
- break;
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
dbgarg(cmd, "value=%d\n", *i);
ret = ops->vidioc_overlay(file, fh, *i);
break;
@@ -971,8 +981,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_framebuffer *p = arg;
- if (!ops->vidioc_g_fbuf)
- break;
ret = ops->vidioc_g_fbuf(file, fh, arg);
if (!ret) {
dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n",
@@ -986,12 +994,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_framebuffer *p = arg;
- if (!ops->vidioc_s_fbuf)
- break;
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n",
p->capability, p->flags, (unsigned long)p->base);
v4l_print_pix_fmt(vfd, &p->fmt);
@@ -1002,12 +1004,6 @@ static long __video_do_ioctl(struct file *file,
{
enum v4l2_buf_type i = *(int *)arg;
- if (!ops->vidioc_streamon)
- break;
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names));
ret = ops->vidioc_streamon(file, fh, i);
break;
@@ -1016,12 +1012,6 @@ static long __video_do_ioctl(struct file *file,
{
enum v4l2_buf_type i = *(int *)arg;
- if (!ops->vidioc_streamoff)
- break;
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names));
ret = ops->vidioc_streamoff(file, fh, i);
break;
@@ -1091,13 +1081,6 @@ static long __video_do_ioctl(struct file *file,
dbgarg(cmd, "std=%08Lx\n", (long long unsigned)*id);
- if (!ops->vidioc_s_std)
- break;
-
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
ret = -EINVAL;
norm = (*id) & vfd->tvnorms;
if (vfd->tvnorms && !norm) /* Check if std is supported */
@@ -1115,8 +1098,6 @@ static long __video_do_ioctl(struct file *file,
{
v4l2_std_id *p = arg;
- if (!ops->vidioc_querystd)
- break;
/*
* If nothing detected, it should return all supported
* Drivers just need to mask the std argument, in order
@@ -1150,9 +1131,6 @@ static long __video_do_ioctl(struct file *file,
if (ops->vidioc_s_dv_timings)
p->capabilities |= V4L2_IN_CAP_CUSTOM_TIMINGS;
- if (!ops->vidioc_enum_input)
- break;
-
ret = ops->vidioc_enum_input(file, fh, p);
if (!ret)
dbgarg(cmd, "index=%d, name=%s, type=%d, "
@@ -1168,8 +1146,6 @@ static long __video_do_ioctl(struct file *file,
{
unsigned int *i = arg;
- if (!ops->vidioc_g_input)
- break;
ret = ops->vidioc_g_input(file, fh, i);
if (!ret)
dbgarg(cmd, "value=%d\n", *i);
@@ -1179,12 +1155,6 @@ static long __video_do_ioctl(struct file *file,
{
unsigned int *i = arg;
- if (!ops->vidioc_s_input)
- break;
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
dbgarg(cmd, "value=%d\n", *i);
ret = ops->vidioc_s_input(file, fh, *i);
break;
@@ -1195,9 +1165,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_output *p = arg;
- if (!ops->vidioc_enum_output)
- break;
-
/*
* We set the flags for CAP_PRESETS, CAP_CUSTOM_TIMINGS &
* CAP_STD here based on ioctl handler provided by the
@@ -1224,8 +1191,6 @@ static long __video_do_ioctl(struct file *file,
{
unsigned int *i = arg;
- if (!ops->vidioc_g_output)
- break;
ret = ops->vidioc_g_output(file, fh, i);
if (!ret)
dbgarg(cmd, "value=%d\n", *i);
@@ -1235,12 +1200,6 @@ static long __video_do_ioctl(struct file *file,
{
unsigned int *i = arg;
- if (!ops->vidioc_s_output)
- break;
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
dbgarg(cmd, "value=%d\n", *i);
ret = ops->vidioc_s_output(file, fh, *i);
break;
@@ -1310,10 +1269,6 @@ static long __video_do_ioctl(struct file *file,
if (!(vfh && vfh->ctrl_handler) && !vfd->ctrl_handler &&
!ops->vidioc_s_ctrl && !ops->vidioc_s_ext_ctrls)
break;
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value);
@@ -1369,10 +1324,6 @@ static long __video_do_ioctl(struct file *file,
if (!(vfh && vfh->ctrl_handler) && !vfd->ctrl_handler &&
!ops->vidioc_s_ext_ctrls)
break;
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
v4l_print_ext_ctrls(cmd, vfd, p, 1);
if (vfh && vfh->ctrl_handler)
ret = v4l2_s_ext_ctrls(vfh, vfh->ctrl_handler, p);
@@ -1428,8 +1379,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_audio *p = arg;
- if (!ops->vidioc_enumaudio)
- break;
ret = ops->vidioc_enumaudio(file, fh, p);
if (!ret)
dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
@@ -1443,9 +1392,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_audio *p = arg;
- if (!ops->vidioc_g_audio)
- break;
-
ret = ops->vidioc_g_audio(file, fh, p);
if (!ret)
dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
@@ -1459,12 +1405,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_audio *p = arg;
- if (!ops->vidioc_s_audio)
- break;
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
dbgarg(cmd, "index=%d, name=%s, capability=0x%x, "
"mode=0x%x\n", p->index, p->name,
p->capability, p->mode);
@@ -1475,8 +1415,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_audioout *p = arg;
- if (!ops->vidioc_enumaudout)
- break;
dbgarg(cmd, "Enum for index=%d\n", p->index);
ret = ops->vidioc_enumaudout(file, fh, p);
if (!ret)
@@ -1489,9 +1427,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_audioout *p = arg;
- if (!ops->vidioc_g_audout)
- break;
-
ret = ops->vidioc_g_audout(file, fh, p);
if (!ret)
dbgarg2("index=%d, name=%s, capability=%d, "
@@ -1503,12 +1438,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_audioout *p = arg;
- if (!ops->vidioc_s_audout)
- break;
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
dbgarg(cmd, "index=%d, name=%s, capability=%d, "
"mode=%d\n", p->index, p->name,
p->capability, p->mode);
@@ -1520,8 +1449,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_modulator *p = arg;
- if (!ops->vidioc_g_modulator)
- break;
ret = ops->vidioc_g_modulator(file, fh, p);
if (!ret)
dbgarg(cmd, "index=%d, name=%s, "
@@ -1536,12 +1463,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_modulator *p = arg;
- if (!ops->vidioc_s_modulator)
- break;
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
dbgarg(cmd, "index=%d, name=%s, capability=%d, "
"rangelow=%d, rangehigh=%d, txsubchans=%d\n",
p->index, p->name, p->capability, p->rangelow,
@@ -1553,9 +1474,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_crop *p = arg;
- if (!ops->vidioc_g_crop && !ops->vidioc_g_selection)
- break;
-
dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
if (ops->vidioc_g_crop) {
@@ -1587,13 +1505,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_crop *p = arg;
- if (!ops->vidioc_s_crop && !ops->vidioc_s_selection)
- break;
-
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
dbgrect(vfd, "", &p->c);
@@ -1620,9 +1531,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_selection *p = arg;
- if (!ops->vidioc_g_selection)
- break;
-
dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
ret = ops->vidioc_g_selection(file, fh, p);
@@ -1634,13 +1542,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_selection *p = arg;
- if (!ops->vidioc_s_selection)
- break;
-
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
dbgrect(vfd, "", &p->r);
@@ -1653,9 +1554,6 @@ static long __video_do_ioctl(struct file *file,
struct v4l2_cropcap *p = arg;
/*FIXME: Should also show v4l2_fract pixelaspect */
- if (!ops->vidioc_cropcap && !ops->vidioc_g_selection)
- break;
-
dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names));
if (ops->vidioc_cropcap) {
ret = ops->vidioc_cropcap(file, fh, p);
@@ -1699,9 +1597,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_jpegcompression *p = arg;
- if (!ops->vidioc_g_jpegcomp)
- break;
-
ret = ops->vidioc_g_jpegcomp(file, fh, p);
if (!ret)
dbgarg(cmd, "quality=%d, APPn=%d, "
@@ -1715,12 +1610,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_jpegcompression *p = arg;
- if (!ops->vidioc_g_jpegcomp)
- break;
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
dbgarg(cmd, "quality=%d, APPn=%d, APP_len=%d, "
"COM_len=%d, jpeg_markers=%d\n",
p->quality, p->APPn, p->APP_len,
@@ -1732,8 +1621,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_enc_idx *p = arg;
- if (!ops->vidioc_g_enc_index)
- break;
ret = ops->vidioc_g_enc_index(file, fh, p);
if (!ret)
dbgarg(cmd, "entries=%d, entries_cap=%d\n",
@@ -1744,12 +1631,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_encoder_cmd *p = arg;
- if (!ops->vidioc_encoder_cmd)
- break;
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
ret = ops->vidioc_encoder_cmd(file, fh, p);
if (!ret)
dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
@@ -1759,8 +1640,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_encoder_cmd *p = arg;
- if (!ops->vidioc_try_encoder_cmd)
- break;
ret = ops->vidioc_try_encoder_cmd(file, fh, p);
if (!ret)
dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
@@ -1770,12 +1649,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_decoder_cmd *p = arg;
- if (!ops->vidioc_decoder_cmd)
- break;
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
ret = ops->vidioc_decoder_cmd(file, fh, p);
if (!ret)
dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
@@ -1785,8 +1658,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_decoder_cmd *p = arg;
- if (!ops->vidioc_try_decoder_cmd)
- break;
ret = ops->vidioc_try_decoder_cmd(file, fh, p);
if (!ret)
dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags);
@@ -1796,8 +1667,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_streamparm *p = arg;
- if (!ops->vidioc_g_parm && !vfd->current_norm)
- break;
if (ops->vidioc_g_parm) {
ret = check_fmt(ops, p->type);
if (ret)
@@ -1825,12 +1694,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_streamparm *p = arg;
- if (!ops->vidioc_s_parm)
- break;
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
ret = check_fmt(ops, p->type);
if (ret)
break;
@@ -1843,9 +1706,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_tuner *p = arg;
- if (!ops->vidioc_g_tuner)
- break;
-
p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
ret = ops->vidioc_g_tuner(file, fh, p);
@@ -1864,12 +1724,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_tuner *p = arg;
- if (!ops->vidioc_s_tuner)
- break;
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
dbgarg(cmd, "index=%d, name=%s, type=%d, "
@@ -1887,9 +1741,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_frequency *p = arg;
- if (!ops->vidioc_g_frequency)
- break;
-
p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
ret = ops->vidioc_g_frequency(file, fh, p);
@@ -1903,12 +1754,6 @@ static long __video_do_ioctl(struct file *file,
struct v4l2_frequency *p = arg;
enum v4l2_tuner_type type;
- if (!ops->vidioc_s_frequency)
- break;
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n",
@@ -1923,9 +1768,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_sliced_vbi_cap *p = arg;
- if (!ops->vidioc_g_sliced_vbi_cap)
- break;
-
/* Clear up to type, everything after type is zerod already */
memset(p, 0, offsetof(struct v4l2_sliced_vbi_cap, type));
@@ -1937,8 +1779,6 @@ static long __video_do_ioctl(struct file *file,
}
case VIDIOC_LOG_STATUS:
{
- if (!ops->vidioc_log_status)
- break;
if (vfd->v4l2_dev)
pr_info("%s: ================= START STATUS =================\n",
vfd->v4l2_dev->name);
@@ -1948,38 +1788,34 @@ static long __video_do_ioctl(struct file *file,
vfd->v4l2_dev->name);
break;
}
-#ifdef CONFIG_VIDEO_ADV_DEBUG
case VIDIOC_DBG_G_REGISTER:
{
+#ifdef CONFIG_VIDEO_ADV_DEBUG
struct v4l2_dbg_register *p = arg;
- if (ops->vidioc_g_register) {
- if (!capable(CAP_SYS_ADMIN))
- ret = -EPERM;
- else
- ret = ops->vidioc_g_register(file, fh, p);
- }
+ if (!capable(CAP_SYS_ADMIN))
+ ret = -EPERM;
+ else
+ ret = ops->vidioc_g_register(file, fh, p);
+#endif
break;
}
case VIDIOC_DBG_S_REGISTER:
{
+#ifdef CONFIG_VIDEO_ADV_DEBUG
struct v4l2_dbg_register *p = arg;
- if (ops->vidioc_s_register) {
- if (!capable(CAP_SYS_ADMIN))
- ret = -EPERM;
- else
- ret = ops->vidioc_s_register(file, fh, p);
- }
+ if (!capable(CAP_SYS_ADMIN))
+ ret = -EPERM;
+ else
+ ret = ops->vidioc_s_register(file, fh, p);
+#endif
break;
}
-#endif
case VIDIOC_DBG_G_CHIP_IDENT:
{
struct v4l2_dbg_chip_ident *p = arg;
- if (!ops->vidioc_g_chip_ident)
- break;
p->ident = V4L2_IDENT_NONE;
p->revision = 0;
ret = ops->vidioc_g_chip_ident(file, fh, p);
@@ -1992,12 +1828,6 @@ static long __video_do_ioctl(struct file *file,
struct v4l2_hw_freq_seek *p = arg;
enum v4l2_tuner_type type;
- if (!ops->vidioc_s_hw_freq_seek)
- break;
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
dbgarg(cmd,
@@ -2013,9 +1843,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_frmsizeenum *p = arg;
- if (!ops->vidioc_enum_framesizes)
- break;
-
ret = ops->vidioc_enum_framesizes(file, fh, p);
dbgarg(cmd,
"index=%d, pixelformat=%c%c%c%c, type=%d ",
@@ -2049,9 +1876,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_frmivalenum *p = arg;
- if (!ops->vidioc_enum_frameintervals)
- break;
-
ret = ops->vidioc_enum_frameintervals(file, fh, p);
dbgarg(cmd,
"index=%d, pixelformat=%d, width=%d, height=%d, type=%d ",
@@ -2084,9 +1908,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_dv_enum_preset *p = arg;
- if (!ops->vidioc_enum_dv_presets)
- break;
-
ret = ops->vidioc_enum_dv_presets(file, fh, p);
if (!ret)
dbgarg(cmd,
@@ -2100,13 +1921,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_dv_preset *p = arg;
- if (!ops->vidioc_s_dv_preset)
- break;
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
-
dbgarg(cmd, "preset=%d\n", p->preset);
ret = ops->vidioc_s_dv_preset(file, fh, p);
break;
@@ -2115,9 +1929,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_dv_preset *p = arg;
- if (!ops->vidioc_g_dv_preset)
- break;
-
ret = ops->vidioc_g_dv_preset(file, fh, p);
if (!ret)
dbgarg(cmd, "preset=%d\n", p->preset);
@@ -2127,9 +1938,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_dv_preset *p = arg;
- if (!ops->vidioc_query_dv_preset)
- break;
-
ret = ops->vidioc_query_dv_preset(file, fh, p);
if (!ret)
dbgarg(cmd, "preset=%d\n", p->preset);
@@ -2139,32 +1947,13 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_dv_timings *p = arg;
- if (!ops->vidioc_s_dv_timings)
- break;
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
-
+ dbgtimings(vfd, p);
switch (p->type) {
case V4L2_DV_BT_656_1120:
- dbgarg2("bt-656/1120:interlaced=%d, pixelclock=%lld,"
- " width=%d, height=%d, polarities=%x,"
- " hfrontporch=%d, hsync=%d, hbackporch=%d,"
- " vfrontporch=%d, vsync=%d, vbackporch=%d,"
- " il_vfrontporch=%d, il_vsync=%d,"
- " il_vbackporch=%d\n",
- p->bt.interlaced, p->bt.pixelclock,
- p->bt.width, p->bt.height, p->bt.polarities,
- p->bt.hfrontporch, p->bt.hsync,
- p->bt.hbackporch, p->bt.vfrontporch,
- p->bt.vsync, p->bt.vbackporch,
- p->bt.il_vfrontporch, p->bt.il_vsync,
- p->bt.il_vbackporch);
ret = ops->vidioc_s_dv_timings(file, fh, p);
break;
default:
- dbgarg2("Unknown type %d!\n", p->type);
+ ret = -EINVAL;
break;
}
break;
@@ -2173,43 +1962,68 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_dv_timings *p = arg;
- if (!ops->vidioc_g_dv_timings)
+ ret = ops->vidioc_g_dv_timings(file, fh, p);
+ if (!ret)
+ dbgtimings(vfd, p);
+ break;
+ }
+ case VIDIOC_ENUM_DV_TIMINGS:
+ {
+ struct v4l2_enum_dv_timings *p = arg;
+
+ if (!ops->vidioc_enum_dv_timings)
break;
- ret = ops->vidioc_g_dv_timings(file, fh, p);
+ ret = ops->vidioc_enum_dv_timings(file, fh, p);
if (!ret) {
- switch (p->type) {
- case V4L2_DV_BT_656_1120:
- dbgarg2("bt-656/1120:interlaced=%d,"
- " pixelclock=%lld,"
- " width=%d, height=%d, polarities=%x,"
- " hfrontporch=%d, hsync=%d,"
- " hbackporch=%d, vfrontporch=%d,"
- " vsync=%d, vbackporch=%d,"
- " il_vfrontporch=%d, il_vsync=%d,"
- " il_vbackporch=%d\n",
- p->bt.interlaced, p->bt.pixelclock,
- p->bt.width, p->bt.height,
- p->bt.polarities, p->bt.hfrontporch,
- p->bt.hsync, p->bt.hbackporch,
- p->bt.vfrontporch, p->bt.vsync,
- p->bt.vbackporch, p->bt.il_vfrontporch,
- p->bt.il_vsync, p->bt.il_vbackporch);
- break;
- default:
- dbgarg2("Unknown type %d!\n", p->type);
- break;
- }
+ dbgarg(cmd, "index=%d: ", p->index);
+ dbgtimings(vfd, &p->timings);
}
break;
}
- case VIDIOC_DQEVENT:
+ case VIDIOC_QUERY_DV_TIMINGS:
{
- struct v4l2_event *ev = arg;
+ struct v4l2_dv_timings *p = arg;
+
+ if (!ops->vidioc_query_dv_timings)
+ break;
- if (!ops->vidioc_subscribe_event)
+ ret = ops->vidioc_query_dv_timings(file, fh, p);
+ if (!ret)
+ dbgtimings(vfd, p);
+ break;
+ }
+ case VIDIOC_DV_TIMINGS_CAP:
+ {
+ struct v4l2_dv_timings_cap *p = arg;
+
+ if (!ops->vidioc_dv_timings_cap)
break;
+ ret = ops->vidioc_dv_timings_cap(file, fh, p);
+ if (ret)
+ break;
+ switch (p->type) {
+ case V4L2_DV_BT_656_1120:
+ dbgarg(cmd,
+ "type=%d, width=%u-%u, height=%u-%u, "
+ "pixelclock=%llu-%llu, standards=%x, capabilities=%x ",
+ p->type,
+ p->bt.min_width, p->bt.max_width,
+ p->bt.min_height, p->bt.max_height,
+ p->bt.min_pixelclock, p->bt.max_pixelclock,
+ p->bt.standards, p->bt.capabilities);
+ break;
+ default:
+ dbgarg(cmd, "unknown type ");
+ break;
+ }
+ break;
+ }
+ case VIDIOC_DQEVENT:
+ {
+ struct v4l2_event *ev = arg;
+
ret = v4l2_event_dequeue(fh, ev, file->f_flags & O_NONBLOCK);
if (ret < 0) {
dbgarg(cmd, "no pending events?");
@@ -2226,9 +2040,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_event_subscription *sub = arg;
- if (!ops->vidioc_subscribe_event)
- break;
-
ret = ops->vidioc_subscribe_event(fh, sub);
if (ret < 0) {
dbgarg(cmd, "failed, ret=%ld", ret);
@@ -2241,9 +2052,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_event_subscription *sub = arg;
- if (!ops->vidioc_unsubscribe_event)
- break;
-
ret = ops->vidioc_unsubscribe_event(fh, sub);
if (ret < 0) {
dbgarg(cmd, "failed, ret=%ld", ret);
@@ -2256,12 +2064,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_create_buffers *create = arg;
- if (!ops->vidioc_create_bufs)
- break;
- if (ret_prio) {
- ret = ret_prio;
- break;
- }
ret = check_fmt(ops, create->format.type);
if (ret)
break;
@@ -2275,8 +2077,6 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_buffer *b = arg;
- if (!ops->vidioc_prepare_buf)
- break;
ret = check_fmt(ops, b->type);
if (ret)
break;
@@ -2289,7 +2089,9 @@ static long __video_do_ioctl(struct file *file,
default:
if (!ops->vidioc_default)
break;
- ret = ops->vidioc_default(file, fh, ret_prio >= 0, cmd, arg);
+ ret = ops->vidioc_default(file, fh, use_fh_prio ?
+ v4l2_prio_check(vfd->prio, vfh->prio) >= 0 : 0,
+ cmd, arg);
break;
} /* switch */
@@ -2463,7 +2265,9 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
err = -EFAULT;
goto out_array_args;
}
- if (err < 0)
+ /* VIDIOC_QUERY_DV_TIMINGS can return an error, but still have valid
+ results that must be returned. */
+ if (err < 0 && cmd != VIDIOC_QUERY_DV_TIMINGS)
goto out;
out_array_args:
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
index 6fe88e965a8c..db6e859b93d4 100644
--- a/drivers/media/video/v4l2-subdev.c
+++ b/drivers/media/video/v4l2-subdev.c
@@ -35,14 +35,9 @@
static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
{
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
- /* Allocate try format and crop in the same memory block */
- fh->try_fmt = kzalloc((sizeof(*fh->try_fmt) + sizeof(*fh->try_crop))
- * sd->entity.num_pads, GFP_KERNEL);
- if (fh->try_fmt == NULL)
+ fh->pad = kzalloc(sizeof(*fh->pad) * sd->entity.num_pads, GFP_KERNEL);
+ if (fh->pad == NULL)
return -ENOMEM;
-
- fh->try_crop = (struct v4l2_rect *)
- (fh->try_fmt + sd->entity.num_pads);
#endif
return 0;
}
@@ -50,9 +45,8 @@ static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
static void subdev_fh_free(struct v4l2_subdev_fh *fh)
{
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
- kfree(fh->try_fmt);
- fh->try_fmt = NULL;
- fh->try_crop = NULL;
+ kfree(fh->pad);
+ fh->pad = NULL;
#endif
}
@@ -234,6 +228,8 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_SUBDEV_G_CROP: {
struct v4l2_subdev_crop *crop = arg;
+ struct v4l2_subdev_selection sel;
+ int rval;
if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
@@ -242,11 +238,27 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (crop->pad >= sd->entity.num_pads)
return -EINVAL;
- return v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop);
+ rval = v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop);
+ if (rval != -ENOIOCTLCMD)
+ return rval;
+
+ memset(&sel, 0, sizeof(sel));
+ sel.which = crop->which;
+ sel.pad = crop->pad;
+ sel.target = V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL;
+
+ rval = v4l2_subdev_call(
+ sd, pad, get_selection, subdev_fh, &sel);
+
+ crop->rect = sel.r;
+
+ return rval;
}
case VIDIOC_SUBDEV_S_CROP: {
struct v4l2_subdev_crop *crop = arg;
+ struct v4l2_subdev_selection sel;
+ int rval;
if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
@@ -255,7 +267,22 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (crop->pad >= sd->entity.num_pads)
return -EINVAL;
- return v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop);
+ rval = v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop);
+ if (rval != -ENOIOCTLCMD)
+ return rval;
+
+ memset(&sel, 0, sizeof(sel));
+ sel.which = crop->which;
+ sel.pad = crop->pad;
+ sel.target = V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL;
+ sel.r = crop->rect;
+
+ rval = v4l2_subdev_call(
+ sd, pad, set_selection, subdev_fh, &sel);
+
+ crop->rect = sel.r;
+
+ return rval;
}
case VIDIOC_SUBDEV_ENUM_MBUS_CODE: {
@@ -293,6 +320,34 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh,
fie);
}
+
+ case VIDIOC_SUBDEV_G_SELECTION: {
+ struct v4l2_subdev_selection *sel = arg;
+
+ if (sel->which != V4L2_SUBDEV_FORMAT_TRY &&
+ sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
+ if (sel->pad >= sd->entity.num_pads)
+ return -EINVAL;
+
+ return v4l2_subdev_call(
+ sd, pad, get_selection, subdev_fh, sel);
+ }
+
+ case VIDIOC_SUBDEV_S_SELECTION: {
+ struct v4l2_subdev_selection *sel = arg;
+
+ if (sel->which != V4L2_SUBDEV_FORMAT_TRY &&
+ sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
+ if (sel->pad >= sd->entity.num_pads)
+ return -EINVAL;
+
+ return v4l2_subdev_call(
+ sd, pad, set_selection, subdev_fh, sel);
+ }
#endif
default:
return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
@@ -332,6 +387,70 @@ const struct v4l2_file_operations v4l2_subdev_fops = {
.poll = subdev_poll,
};
+#ifdef CONFIG_MEDIA_CONTROLLER
+int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
+ struct media_link *link,
+ struct v4l2_subdev_format *source_fmt,
+ struct v4l2_subdev_format *sink_fmt)
+{
+ if (source_fmt->format.width != sink_fmt->format.width
+ || source_fmt->format.height != sink_fmt->format.height
+ || source_fmt->format.code != sink_fmt->format.code)
+ return -EINVAL;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default);
+
+static int
+v4l2_subdev_link_validate_get_format(struct media_pad *pad,
+ struct v4l2_subdev_format *fmt)
+{
+ switch (media_entity_type(pad->entity)) {
+ case MEDIA_ENT_T_V4L2_SUBDEV:
+ fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ fmt->pad = pad->index;
+ return v4l2_subdev_call(media_entity_to_v4l2_subdev(
+ pad->entity),
+ pad, get_fmt, NULL, fmt);
+ default:
+ WARN(1, "Driver bug! Wrong media entity type %d, entity %s\n",
+ media_entity_type(pad->entity), pad->entity->name);
+ /* Fall through */
+ case MEDIA_ENT_T_DEVNODE_V4L:
+ return -EINVAL;
+ }
+}
+
+int v4l2_subdev_link_validate(struct media_link *link)
+{
+ struct v4l2_subdev *sink;
+ struct v4l2_subdev_format sink_fmt, source_fmt;
+ int rval;
+
+ rval = v4l2_subdev_link_validate_get_format(
+ link->source, &source_fmt);
+ if (rval < 0)
+ return 0;
+
+ rval = v4l2_subdev_link_validate_get_format(
+ link->sink, &sink_fmt);
+ if (rval < 0)
+ return 0;
+
+ sink = media_entity_to_v4l2_subdev(link->sink->entity);
+
+ rval = v4l2_subdev_call(sink, pad, link_validate, link,
+ &source_fmt, &sink_fmt);
+ if (rval != -ENOIOCTLCMD)
+ return rval;
+
+ return v4l2_subdev_link_validate_default(
+ sink, link, &source_fmt, &sink_fmt);
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate);
+#endif /* CONFIG_MEDIA_CONTROLLER */
+
void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
{
INIT_LIST_HEAD(&sd->list);
diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c
index 20f7237b8242..308e150a39bc 100644
--- a/drivers/media/video/via-camera.c
+++ b/drivers/media/video/via-camera.c
@@ -18,6 +18,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-chip-ident.h>
+#include <media/ov7670.h>
#include <media/videobuf-dma-sg.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
@@ -1347,11 +1348,21 @@ static __devinit bool viacam_serial_is_enabled(void)
return false;
}
+static struct ov7670_config sensor_cfg = {
+ /* The XO-1.5 (only known user) clocks the camera at 90MHz. */
+ .clock_speed = 90,
+};
+
static __devinit int viacam_probe(struct platform_device *pdev)
{
int ret;
struct i2c_adapter *sensor_adapter;
struct viafb_dev *viadev = pdev->dev.platform_data;
+ struct i2c_board_info ov7670_info = {
+ .type = "ov7670",
+ .addr = 0x42 >> 1,
+ .platform_data = &sensor_cfg,
+ };
/*
* Note that there are actually two capture channels on
@@ -1433,8 +1444,8 @@ static __devinit int viacam_probe(struct platform_device *pdev)
* is OLPC-specific. 0x42 assumption is ov7670-specific.
*/
sensor_adapter = viafb_find_i2c_adapter(VIA_PORT_31);
- cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev, sensor_adapter,
- "ov7670", 0x42 >> 1, NULL);
+ cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev, sensor_adapter,
+ &ov7670_info, NULL);
if (cam->sensor == NULL) {
dev_err(&pdev->dev, "Unable to find the sensor!\n");
ret = -ENODEV;
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
index de4fa4eb8844..ffdf59cfe405 100644
--- a/drivers/media/video/videobuf-core.c
+++ b/drivers/media/video/videobuf-core.c
@@ -1129,6 +1129,7 @@ unsigned int videobuf_poll_stream(struct file *file,
struct videobuf_queue *q,
poll_table *wait)
{
+ unsigned long req_events = poll_requested_events(wait);
struct videobuf_buffer *buf = NULL;
unsigned int rc = 0;
@@ -1137,7 +1138,7 @@ unsigned int videobuf_poll_stream(struct file *file,
if (!list_empty(&q->stream))
buf = list_entry(q->stream.next,
struct videobuf_buffer, stream);
- } else {
+ } else if (req_events & (POLLIN | POLLRDNORM)) {
if (!q->reading)
__videobuf_read_start(q);
if (!q->reading) {
diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c
index c9691115f2d2..b6b5cc1a43cb 100644
--- a/drivers/media/video/videobuf-dma-contig.c
+++ b/drivers/media/video/videobuf-dma-contig.c
@@ -27,6 +27,7 @@ struct videobuf_dma_contig_memory {
u32 magic;
void *vaddr;
dma_addr_t dma_handle;
+ bool cached;
unsigned long size;
};
@@ -37,8 +38,58 @@ struct videobuf_dma_contig_memory {
BUG(); \
}
-static void
-videobuf_vm_open(struct vm_area_struct *vma)
+static int __videobuf_dc_alloc(struct device *dev,
+ struct videobuf_dma_contig_memory *mem,
+ unsigned long size, unsigned long flags)
+{
+ mem->size = size;
+ if (mem->cached) {
+ mem->vaddr = alloc_pages_exact(mem->size, flags | GFP_DMA);
+ if (mem->vaddr) {
+ int err;
+
+ mem->dma_handle = dma_map_single(dev, mem->vaddr,
+ mem->size,
+ DMA_FROM_DEVICE);
+ err = dma_mapping_error(dev, mem->dma_handle);
+ if (err) {
+ dev_err(dev, "dma_map_single failed\n");
+
+ free_pages_exact(mem->vaddr, mem->size);
+ mem->vaddr = 0;
+ return err;
+ }
+ }
+ } else
+ mem->vaddr = dma_alloc_coherent(dev, mem->size,
+ &mem->dma_handle, flags);
+
+ if (!mem->vaddr) {
+ dev_err(dev, "memory alloc size %ld failed\n", mem->size);
+ return -ENOMEM;
+ }
+
+ dev_dbg(dev, "dma mapped data is at %p (%ld)\n", mem->vaddr, mem->size);
+
+ return 0;
+}
+
+static void __videobuf_dc_free(struct device *dev,
+ struct videobuf_dma_contig_memory *mem)
+{
+ if (mem->cached) {
+ if (!mem->vaddr)
+ return;
+ dma_unmap_single(dev, mem->dma_handle, mem->size,
+ DMA_FROM_DEVICE);
+ free_pages_exact(mem->vaddr, mem->size);
+ } else
+ dma_free_coherent(dev, mem->size, mem->vaddr, mem->dma_handle);
+
+ mem->vaddr = NULL;
+}
+
+static void videobuf_vm_open(struct vm_area_struct *vma)
{
struct videobuf_mapping *map = vma->vm_private_data;
@@ -91,12 +142,11 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
dev_dbg(q->dev, "buf[%d] freeing %p\n",
i, mem->vaddr);
- dma_free_coherent(q->dev, mem->size,
- mem->vaddr, mem->dma_handle);
+ __videobuf_dc_free(q->dev, mem);
mem->vaddr = NULL;
}
- q->bufs[i]->map = NULL;
+ q->bufs[i]->map = NULL;
q->bufs[i]->baddr = 0;
}
@@ -107,8 +157,8 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
}
static const struct vm_operations_struct videobuf_vm_ops = {
- .open = videobuf_vm_open,
- .close = videobuf_vm_close,
+ .open = videobuf_vm_open,
+ .close = videobuf_vm_close,
};
/**
@@ -178,26 +228,38 @@ static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
pages_done++;
}
- out_up:
+out_up:
up_read(&current->mm->mmap_sem);
return ret;
}
-static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
+static struct videobuf_buffer *__videobuf_alloc_vb(size_t size, bool cached)
{
struct videobuf_dma_contig_memory *mem;
struct videobuf_buffer *vb;
vb = kzalloc(size + sizeof(*mem), GFP_KERNEL);
if (vb) {
- mem = vb->priv = ((char *)vb) + size;
+ vb->priv = ((char *)vb) + size;
+ mem = vb->priv;
mem->magic = MAGIC_DC_MEM;
+ mem->cached = cached;
}
return vb;
}
+static struct videobuf_buffer *__videobuf_alloc_uncached(size_t size)
+{
+ return __videobuf_alloc_vb(size, false);
+}
+
+static struct videobuf_buffer *__videobuf_alloc_cached(size_t size)
+{
+ return __videobuf_alloc_vb(size, true);
+}
+
static void *__videobuf_to_vaddr(struct videobuf_buffer *buf)
{
struct videobuf_dma_contig_memory *mem = buf->priv;
@@ -235,28 +297,32 @@ static int __videobuf_iolock(struct videobuf_queue *q,
return videobuf_dma_contig_user_get(mem, vb);
/* allocate memory for the read() method */
- mem->size = PAGE_ALIGN(vb->size);
- mem->vaddr = dma_alloc_coherent(q->dev, mem->size,
- &mem->dma_handle, GFP_KERNEL);
- if (!mem->vaddr) {
- dev_err(q->dev, "dma_alloc_coherent %ld failed\n",
- mem->size);
+ if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(vb->size),
+ GFP_KERNEL))
return -ENOMEM;
- }
-
- dev_dbg(q->dev, "dma_alloc_coherent data is at %p (%ld)\n",
- mem->vaddr, mem->size);
break;
case V4L2_MEMORY_OVERLAY:
default:
- dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n",
- __func__);
+ dev_dbg(q->dev, "%s memory method OVERLAY/unknown\n", __func__);
return -EINVAL;
}
return 0;
}
+static int __videobuf_sync(struct videobuf_queue *q,
+ struct videobuf_buffer *buf)
+{
+ struct videobuf_dma_contig_memory *mem = buf->priv;
+ BUG_ON(!mem);
+ MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
+
+ dma_sync_single_for_cpu(q->dev, mem->dma_handle, mem->size,
+ DMA_FROM_DEVICE);
+
+ return 0;
+}
+
static int __videobuf_mmap_mapper(struct videobuf_queue *q,
struct videobuf_buffer *buf,
struct vm_area_struct *vma)
@@ -265,6 +331,8 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
struct videobuf_mapping *map;
int retval;
unsigned long size;
+ unsigned long pos, start = vma->vm_start;
+ struct page *page;
dev_dbg(q->dev, "%s\n", __func__);
@@ -282,41 +350,50 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
BUG_ON(!mem);
MAGIC_CHECK(mem->magic, MAGIC_DC_MEM);
- mem->size = PAGE_ALIGN(buf->bsize);
- mem->vaddr = dma_alloc_coherent(q->dev, mem->size,
- &mem->dma_handle, GFP_KERNEL);
- if (!mem->vaddr) {
- dev_err(q->dev, "dma_alloc_coherent size %ld failed\n",
- mem->size);
+ if (__videobuf_dc_alloc(q->dev, mem, PAGE_ALIGN(buf->bsize),
+ GFP_KERNEL | __GFP_COMP))
goto error;
- }
- dev_dbg(q->dev, "dma_alloc_coherent data is at addr %p (size %ld)\n",
- mem->vaddr, mem->size);
/* Try to remap memory */
size = vma->vm_end - vma->vm_start;
size = (size < mem->size) ? size : mem->size;
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- retval = remap_pfn_range(vma, vma->vm_start,
- mem->dma_handle >> PAGE_SHIFT,
- size, vma->vm_page_prot);
- if (retval) {
- dev_err(q->dev, "mmap: remap failed with error %d. ", retval);
- dma_free_coherent(q->dev, mem->size,
- mem->vaddr, mem->dma_handle);
- goto error;
+ if (!mem->cached)
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ pos = (unsigned long)mem->vaddr;
+
+ while (size > 0) {
+ page = virt_to_page((void *)pos);
+ if (NULL == page) {
+ dev_err(q->dev, "mmap: virt_to_page failed\n");
+ __videobuf_dc_free(q->dev, mem);
+ goto error;
+ }
+ retval = vm_insert_page(vma, start, page);
+ if (retval) {
+ dev_err(q->dev, "mmap: insert failed with error %d\n",
+ retval);
+ __videobuf_dc_free(q->dev, mem);
+ goto error;
+ }
+ start += PAGE_SIZE;
+ pos += PAGE_SIZE;
+
+ if (size > PAGE_SIZE)
+ size -= PAGE_SIZE;
+ else
+ size = 0;
}
- vma->vm_ops = &videobuf_vm_ops;
- vma->vm_flags |= VM_DONTEXPAND;
+ vma->vm_ops = &videobuf_vm_ops;
+ vma->vm_flags |= VM_DONTEXPAND;
vma->vm_private_data = map;
dev_dbg(q->dev, "mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
map, q, vma->vm_start, vma->vm_end,
- (long int)buf->bsize,
- vma->vm_pgoff, buf->i);
+ (long int)buf->bsize, vma->vm_pgoff, buf->i);
videobuf_vm_open(vma);
@@ -328,12 +405,20 @@ error:
}
static struct videobuf_qtype_ops qops = {
- .magic = MAGIC_QTYPE_OPS,
+ .magic = MAGIC_QTYPE_OPS,
+ .alloc_vb = __videobuf_alloc_uncached,
+ .iolock = __videobuf_iolock,
+ .mmap_mapper = __videobuf_mmap_mapper,
+ .vaddr = __videobuf_to_vaddr,
+};
- .alloc_vb = __videobuf_alloc_vb,
- .iolock = __videobuf_iolock,
- .mmap_mapper = __videobuf_mmap_mapper,
- .vaddr = __videobuf_to_vaddr,
+static struct videobuf_qtype_ops qops_cached = {
+ .magic = MAGIC_QTYPE_OPS,
+ .alloc_vb = __videobuf_alloc_cached,
+ .iolock = __videobuf_iolock,
+ .sync = __videobuf_sync,
+ .mmap_mapper = __videobuf_mmap_mapper,
+ .vaddr = __videobuf_to_vaddr,
};
void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
@@ -351,6 +436,20 @@ void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
}
EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init);
+void videobuf_queue_dma_contig_init_cached(struct videobuf_queue *q,
+ const struct videobuf_queue_ops *ops,
+ struct device *dev,
+ spinlock_t *irqlock,
+ enum v4l2_buf_type type,
+ enum v4l2_field field,
+ unsigned int msize,
+ void *priv, struct mutex *ext_lock)
+{
+ videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
+ priv, &qops_cached, ext_lock);
+}
+EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init_cached);
+
dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf)
{
struct videobuf_dma_contig_memory *mem = buf->priv;
@@ -389,7 +488,7 @@ void videobuf_dma_contig_free(struct videobuf_queue *q,
/* read() method */
if (mem->vaddr) {
- dma_free_coherent(q->dev, mem->size, mem->vaddr, mem->dma_handle);
+ __videobuf_dc_free(q->dev, mem);
mem->vaddr = NULL;
}
}
diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c
index 59cb54aa2946..94d83a41381b 100644
--- a/drivers/media/video/videobuf-dvb.c
+++ b/drivers/media/video/videobuf-dvb.c
@@ -45,7 +45,6 @@ static int videobuf_dvb_thread(void *data)
struct videobuf_dvb *dvb = data;
struct videobuf_buffer *buf;
unsigned long flags;
- int err;
void *outp;
dprintk("dvb thread started\n");
@@ -57,7 +56,7 @@ static int videobuf_dvb_thread(void *data)
buf = list_entry(dvb->dvbq.stream.next,
struct videobuf_buffer, stream);
list_del(&buf->stream);
- err = videobuf_waiton(&dvb->dvbq, buf, 0, 1);
+ videobuf_waiton(&dvb->dvbq, buf, 0, 1);
/* no more feeds left or stop_feed() asked us to quit */
if (0 == dvb->nfeeds)
diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c
index 2e8f1df775b6..9d4e9edbd2e7 100644
--- a/drivers/media/video/videobuf2-core.c
+++ b/drivers/media/video/videobuf2-core.c
@@ -19,6 +19,9 @@
#include <linux/slab.h>
#include <linux/sched.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
#include <media/videobuf2-core.h>
static int debug;
@@ -1642,32 +1645,46 @@ static int __vb2_cleanup_fileio(struct vb2_queue *q);
* For OUTPUT queues, if a buffer is ready to be dequeued, the file descriptor
* will be reported as available for writing.
*
+ * If the driver uses struct v4l2_fh, then vb2_poll() will also check for any
+ * pending events.
+ *
* The return values from this function are intended to be directly returned
* from poll handler in driver.
*/
unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait)
{
- unsigned long flags;
- unsigned int ret;
+ struct video_device *vfd = video_devdata(file);
+ unsigned long req_events = poll_requested_events(wait);
struct vb2_buffer *vb = NULL;
+ unsigned int res = 0;
+ unsigned long flags;
+
+ if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) {
+ struct v4l2_fh *fh = file->private_data;
+
+ if (v4l2_event_pending(fh))
+ res = POLLPRI;
+ else if (req_events & POLLPRI)
+ poll_wait(file, &fh->wait, wait);
+ }
/*
* Start file I/O emulator only if streaming API has not been used yet.
*/
if (q->num_buffers == 0 && q->fileio == NULL) {
- if (!V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_READ)) {
- ret = __vb2_init_fileio(q, 1);
- if (ret)
- return POLLERR;
+ if (!V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_READ) &&
+ (req_events & (POLLIN | POLLRDNORM))) {
+ if (__vb2_init_fileio(q, 1))
+ return res | POLLERR;
}
- if (V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_WRITE)) {
- ret = __vb2_init_fileio(q, 0);
- if (ret)
- return POLLERR;
+ if (V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_WRITE) &&
+ (req_events & (POLLOUT | POLLWRNORM))) {
+ if (__vb2_init_fileio(q, 0))
+ return res | POLLERR;
/*
* Write to OUTPUT queue can be done immediately.
*/
- return POLLOUT | POLLWRNORM;
+ return res | POLLOUT | POLLWRNORM;
}
}
@@ -1675,7 +1692,7 @@ unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait)
* There is nothing to wait for if no buffers have already been queued.
*/
if (list_empty(&q->queued_list))
- return POLLERR;
+ return res | POLLERR;
poll_wait(file, &q->done_wq, wait);
@@ -1690,10 +1707,11 @@ unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait)
if (vb && (vb->state == VB2_BUF_STATE_DONE
|| vb->state == VB2_BUF_STATE_ERROR)) {
- return (V4L2_TYPE_IS_OUTPUT(q->type)) ? POLLOUT | POLLWRNORM :
- POLLIN | POLLRDNORM;
+ return (V4L2_TYPE_IS_OUTPUT(q->type)) ?
+ res | POLLOUT | POLLWRNORM :
+ res | POLLIN | POLLRDNORM;
}
- return 0;
+ return res;
}
EXPORT_SYMBOL_GPL(vb2_poll);
@@ -1839,7 +1857,6 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
* (multiplane buffers are not supported).
*/
if (q->bufs[0]->num_planes != 1) {
- fileio->req.count = 0;
ret = -EBUSY;
goto err_reqbufs;
}
@@ -1886,6 +1903,7 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
return ret;
err_reqbufs:
+ fileio->req.count = 0;
vb2_reqbufs(q, &fileio->req);
err_kfree:
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 5e8b0710105b..0960d7f0d394 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -95,6 +95,16 @@ static struct vivi_fmt formats[] = {
.depth = 16,
},
{
+ .name = "4:2:2, packed, YVYU",
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .depth = 16,
+ },
+ {
+ .name = "4:2:2, packed, VYUY",
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .depth = 16,
+ },
+ {
.name = "RGB565 (LE)",
.fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
.depth = 16,
@@ -114,6 +124,26 @@ static struct vivi_fmt formats[] = {
.fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
.depth = 16,
},
+ {
+ .name = "RGB24 (LE)",
+ .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */
+ .depth = 24,
+ },
+ {
+ .name = "RGB24 (BE)",
+ .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */
+ .depth = 24,
+ },
+ {
+ .name = "RGB32 (LE)",
+ .fourcc = V4L2_PIX_FMT_RGB32, /* argb */
+ .depth = 32,
+ },
+ {
+ .name = "RGB32 (BE)",
+ .fourcc = V4L2_PIX_FMT_BGR32, /* bgra */
+ .depth = 32,
+ },
};
static struct vivi_fmt *get_format(struct v4l2_format *f)
@@ -170,6 +200,7 @@ struct vivi_dev {
struct v4l2_ctrl *gain;
};
struct v4l2_ctrl *volume;
+ struct v4l2_ctrl *alpha;
struct v4l2_ctrl *button;
struct v4l2_ctrl *boolean;
struct v4l2_ctrl *int32;
@@ -177,6 +208,7 @@ struct vivi_dev {
struct v4l2_ctrl *menu;
struct v4l2_ctrl *string;
struct v4l2_ctrl *bitmask;
+ struct v4l2_ctrl *int_menu;
spinlock_t slock;
struct mutex mutex;
@@ -203,8 +235,10 @@ struct vivi_dev {
enum v4l2_field field;
unsigned int field_count;
- u8 bars[9][3];
- u8 line[MAX_WIDTH * 4];
+ u8 bars[9][3];
+ u8 line[MAX_WIDTH * 8];
+ unsigned int pixelsize;
+ u8 alpha_component;
};
/* ------------------------------------------------------------------
@@ -283,6 +317,8 @@ static void precalculate_bars(struct vivi_dev *dev)
switch (dev->fmt->fourcc) {
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_VYUY:
is_yuv = 1;
break;
case V4L2_PIX_FMT_RGB565:
@@ -297,6 +333,11 @@ static void precalculate_bars(struct vivi_dev *dev)
g >>= 3;
b >>= 3;
break;
+ case V4L2_PIX_FMT_RGB24:
+ case V4L2_PIX_FMT_BGR24:
+ case V4L2_PIX_FMT_RGB32:
+ case V4L2_PIX_FMT_BGR32:
+ break;
}
if (is_yuv) {
@@ -316,9 +357,11 @@ static void precalculate_bars(struct vivi_dev *dev)
#define TSTAMP_INPUT_X 10
#define TSTAMP_MIN_X (54 + TSTAMP_INPUT_X)
-static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos)
+/* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */
+static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos, bool odd)
{
u8 r_y, g_u, b_v;
+ u8 alpha = dev->alpha_component;
int color;
u8 *p;
@@ -326,46 +369,56 @@ static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos)
g_u = dev->bars[colorpos][1]; /* G or precalculated U */
b_v = dev->bars[colorpos][2]; /* B or precalculated V */
- for (color = 0; color < 4; color++) {
+ for (color = 0; color < dev->pixelsize; color++) {
p = buf + color;
switch (dev->fmt->fourcc) {
case V4L2_PIX_FMT_YUYV:
switch (color) {
case 0:
- case 2:
*p = r_y;
break;
case 1:
- *p = g_u;
- break;
- case 3:
- *p = b_v;
+ *p = odd ? b_v : g_u;
break;
}
break;
case V4L2_PIX_FMT_UYVY:
switch (color) {
+ case 0:
+ *p = odd ? b_v : g_u;
+ break;
case 1:
- case 3:
*p = r_y;
break;
+ }
+ break;
+ case V4L2_PIX_FMT_YVYU:
+ switch (color) {
case 0:
- *p = g_u;
+ *p = r_y;
break;
- case 2:
- *p = b_v;
+ case 1:
+ *p = odd ? g_u : b_v;
+ break;
+ }
+ break;
+ case V4L2_PIX_FMT_VYUY:
+ switch (color) {
+ case 0:
+ *p = odd ? g_u : b_v;
+ break;
+ case 1:
+ *p = r_y;
break;
}
break;
case V4L2_PIX_FMT_RGB565:
switch (color) {
case 0:
- case 2:
*p = (g_u << 5) | b_v;
break;
case 1:
- case 3:
*p = (r_y << 3) | (g_u >> 3);
break;
}
@@ -373,11 +426,9 @@ static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos)
case V4L2_PIX_FMT_RGB565X:
switch (color) {
case 0:
- case 2:
*p = (r_y << 3) | (g_u >> 3);
break;
case 1:
- case 3:
*p = (g_u << 5) | b_v;
break;
}
@@ -385,24 +436,78 @@ static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos)
case V4L2_PIX_FMT_RGB555:
switch (color) {
case 0:
- case 2:
*p = (g_u << 5) | b_v;
break;
case 1:
- case 3:
- *p = (r_y << 2) | (g_u >> 3);
+ *p = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
break;
}
break;
case V4L2_PIX_FMT_RGB555X:
switch (color) {
case 0:
+ *p = (alpha & 0x80) | (r_y << 2) | (g_u >> 3);
+ break;
+ case 1:
+ *p = (g_u << 5) | b_v;
+ break;
+ }
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ switch (color) {
+ case 0:
+ *p = r_y;
+ break;
+ case 1:
+ *p = g_u;
+ break;
case 2:
- *p = (r_y << 2) | (g_u >> 3);
+ *p = b_v;
+ break;
+ }
+ break;
+ case V4L2_PIX_FMT_BGR24:
+ switch (color) {
+ case 0:
+ *p = b_v;
break;
case 1:
+ *p = g_u;
+ break;
+ case 2:
+ *p = r_y;
+ break;
+ }
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ switch (color) {
+ case 0:
+ *p = alpha;
+ break;
+ case 1:
+ *p = r_y;
+ break;
+ case 2:
+ *p = g_u;
+ break;
case 3:
- *p = (g_u << 5) | b_v;
+ *p = b_v;
+ break;
+ }
+ break;
+ case V4L2_PIX_FMT_BGR32:
+ switch (color) {
+ case 0:
+ *p = b_v;
+ break;
+ case 1:
+ *p = g_u;
+ break;
+ case 2:
+ *p = r_y;
+ break;
+ case 3:
+ *p = alpha;
break;
}
break;
@@ -414,10 +519,10 @@ static void precalculate_line(struct vivi_dev *dev)
{
int w;
- for (w = 0; w < dev->width * 2; w += 2) {
- int colorpos = (w / (dev->width / 8) % 8);
+ for (w = 0; w < dev->width * 2; w++) {
+ int colorpos = w / (dev->width / 8) % 8;
- gen_twopix(dev, dev->line + w * 2, colorpos);
+ gen_twopix(dev, dev->line + w * dev->pixelsize, colorpos, w & 1);
}
}
@@ -433,7 +538,7 @@ static void gen_text(struct vivi_dev *dev, char *basep,
/* Print stream time */
for (line = y; line < y + 16; line++) {
int j = 0;
- char *pos = basep + line * dev->width * 2 + x * 2;
+ char *pos = basep + line * dev->width * dev->pixelsize + x * dev->pixelsize;
char *s;
for (s = text; *s; s++) {
@@ -443,9 +548,9 @@ static void gen_text(struct vivi_dev *dev, char *basep,
for (i = 0; i < 7; i++, j++) {
/* Draw white font on black background */
if (chr & (1 << (7 - i)))
- gen_twopix(dev, pos + j * 2, WHITE);
+ gen_twopix(dev, pos + j * dev->pixelsize, WHITE, (x+y) & 1);
else
- gen_twopix(dev, pos + j * 2, TEXT_BLACK);
+ gen_twopix(dev, pos + j * dev->pixelsize, TEXT_BLACK, (x+y) & 1);
}
}
}
@@ -466,7 +571,9 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
return;
for (h = 0; h < hmax; h++)
- memcpy(vbuf + h * wmax * 2, dev->line + (dev->mv_count % wmax) * 2, wmax * 2);
+ memcpy(vbuf + h * wmax * dev->pixelsize,
+ dev->line + (dev->mv_count % wmax) * dev->pixelsize,
+ wmax * dev->pixelsize);
/* Updates stream time */
@@ -484,15 +591,16 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
gen_text(dev, vbuf, line++ * 16, 16, str);
gain = v4l2_ctrl_g_ctrl(dev->gain);
- mutex_lock(&dev->ctrl_handler.lock);
+ mutex_lock(dev->ctrl_handler.lock);
snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ",
dev->brightness->cur.val,
dev->contrast->cur.val,
dev->saturation->cur.val,
dev->hue->cur.val);
gen_text(dev, vbuf, line++ * 16, 16, str);
- snprintf(str, sizeof(str), " autogain %d, gain %3d, volume %3d ",
- dev->autogain->cur.val, gain, dev->volume->cur.val);
+ snprintf(str, sizeof(str), " autogain %d, gain %3d, volume %3d, alpha 0x%02x ",
+ dev->autogain->cur.val, gain, dev->volume->cur.val,
+ dev->alpha->cur.val);
gen_text(dev, vbuf, line++ * 16, 16, str);
snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ",
dev->int32->cur.val,
@@ -503,8 +611,12 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
dev->boolean->cur.val,
dev->menu->qmenu[dev->menu->cur.val],
dev->string->cur.string);
- mutex_unlock(&dev->ctrl_handler.lock);
gen_text(dev, vbuf, line++ * 16, 16, str);
+ snprintf(str, sizeof(str), " integer_menu %lld, value %d ",
+ dev->int_menu->qmenu_int[dev->int_menu->cur.val],
+ dev->int_menu->cur.val);
+ gen_text(dev, vbuf, line++ * 16, 16, str);
+ mutex_unlock(dev->ctrl_handler.lock);
if (dev->button_pressed) {
dev->button_pressed--;
snprintf(str, sizeof(str), " button pressed!");
@@ -657,7 +769,7 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
struct vivi_dev *dev = vb2_get_drv_priv(vq);
unsigned long size;
- size = dev->width * dev->height * 2;
+ size = dev->width * dev->height * dev->pixelsize;
if (0 == *nbuffers)
*nbuffers = 32;
@@ -721,7 +833,7 @@ static int buffer_prepare(struct vb2_buffer *vb)
dev->height < 32 || dev->height > MAX_HEIGHT)
return -EINVAL;
- size = dev->width * dev->height * 2;
+ size = dev->width * dev->height * dev->pixelsize;
if (vb2_plane_size(vb, 0) < size) {
dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n",
__func__, vb2_plane_size(vb, 0), size);
@@ -915,6 +1027,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
}
dev->fmt = get_format(f);
+ dev->pixelsize = dev->fmt->depth / 8;
dev->width = f->fmt.pix.width;
dev->height = f->fmt.pix.height;
dev->field = f->fmt.pix.field;
@@ -1016,8 +1129,15 @@ static int vivi_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
- if (ctrl == dev->button)
- dev->button_pressed = 30;
+ switch (ctrl->id) {
+ case V4L2_CID_ALPHA_COMPONENT:
+ dev->alpha_component = ctrl->val;
+ break;
+ default:
+ if (ctrl == dev->button)
+ dev->button_pressed = 30;
+ break;
+ }
return 0;
}
@@ -1039,17 +1159,10 @@ static unsigned int
vivi_poll(struct file *file, struct poll_table_struct *wait)
{
struct vivi_dev *dev = video_drvdata(file);
- struct v4l2_fh *fh = file->private_data;
struct vb2_queue *q = &dev->vb_vidq;
- unsigned int res;
dprintk(dev, 1, "%s\n", __func__);
- res = vb2_poll(q, file, wait);
- if (v4l2_event_pending(fh))
- res |= POLLPRI;
- else
- poll_wait(file, &fh->wait, wait);
- return res;
+ return vb2_poll(q, file, wait);
}
static int vivi_close(struct file *file)
@@ -1165,6 +1278,22 @@ static const struct v4l2_ctrl_config vivi_ctrl_bitmask = {
.step = 0,
};
+static const s64 vivi_ctrl_int_menu_values[] = {
+ 1, 1, 2, 3, 5, 8, 13, 21, 42,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_int_menu = {
+ .ops = &vivi_ctrl_ops,
+ .id = VIVI_CID_CUSTOM_BASE + 7,
+ .name = "Integer menu",
+ .type = V4L2_CTRL_TYPE_INTEGER_MENU,
+ .min = 1,
+ .max = 8,
+ .def = 4,
+ .menu_skip_mask = 0x02,
+ .qmenu_int = vivi_ctrl_int_menu_values,
+};
+
static const struct v4l2_file_operations vivi_fops = {
.owner = THIS_MODULE,
.open = v4l2_fh_open,
@@ -1252,6 +1381,7 @@ static int __init vivi_create_instance(int inst)
dev->fmt = &formats[0];
dev->width = 640;
dev->height = 480;
+ dev->pixelsize = dev->fmt->depth / 8;
hdl = &dev->ctrl_handler;
v4l2_ctrl_handler_init(hdl, 11);
dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
@@ -1268,6 +1398,8 @@ static int __init vivi_create_instance(int inst)
V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
dev->gain = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
V4L2_CID_GAIN, 0, 255, 1, 100);
+ dev->alpha = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+ V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0);
dev->button = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL);
dev->int32 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int32, NULL);
dev->int64 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int64, NULL);
@@ -1275,6 +1407,7 @@ static int __init vivi_create_instance(int inst)
dev->menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_menu, NULL);
dev->string = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_string, NULL);
dev->bitmask = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_bitmask, NULL);
+ dev->int_menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int_menu, NULL);
if (hdl->error) {
ret = hdl->error;
goto unreg_dev;
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c
index 7fd7ac567e1a..db2a6003a1c3 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -62,6 +62,9 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
#include <linux/parport.h>
/*#define DEBUG*/ /* Undef me for production */
@@ -104,6 +107,7 @@
struct w9966 {
struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler hdl;
unsigned char dev_state;
unsigned char i2c_state;
unsigned short ppmode;
@@ -567,7 +571,8 @@ static int cam_querycap(struct file *file, void *priv,
strlcpy(vcap->driver, cam->v4l2_dev.name, sizeof(vcap->driver));
strlcpy(vcap->card, W9966_DRIVERNAME, sizeof(vcap->card));
strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
- vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -595,67 +600,25 @@ static int cam_s_input(struct file *file, void *fh, unsigned int inp)
return (inp > 0) ? -EINVAL : 0;
}
-static int cam_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
+static int cam_s_ctrl(struct v4l2_ctrl *ctrl)
{
- switch (qc->id) {
- case V4L2_CID_BRIGHTNESS:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
- case V4L2_CID_CONTRAST:
- return v4l2_ctrl_query_fill(qc, -64, 64, 1, 64);
- case V4L2_CID_SATURATION:
- return v4l2_ctrl_query_fill(qc, -64, 64, 1, 64);
- case V4L2_CID_HUE:
- return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
- }
- return -EINVAL;
-}
-
-static int cam_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct w9966 *cam = video_drvdata(file);
- int ret = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- ctrl->value = cam->brightness;
- break;
- case V4L2_CID_CONTRAST:
- ctrl->value = cam->contrast;
- break;
- case V4L2_CID_SATURATION:
- ctrl->value = cam->color;
- break;
- case V4L2_CID_HUE:
- ctrl->value = cam->hue;
- break;
- default:
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-static int cam_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct w9966 *cam = video_drvdata(file);
+ struct w9966 *cam =
+ container_of(ctrl->handler, struct w9966, hdl);
int ret = 0;
mutex_lock(&cam->lock);
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- cam->brightness = ctrl->value;
+ cam->brightness = ctrl->val;
break;
case V4L2_CID_CONTRAST:
- cam->contrast = ctrl->value;
+ cam->contrast = ctrl->val;
break;
case V4L2_CID_SATURATION:
- cam->color = ctrl->value;
+ cam->color = ctrl->val;
break;
case V4L2_CID_HUE:
- cam->hue = ctrl->value;
+ cam->hue = ctrl->val;
break;
default:
ret = -EINVAL;
@@ -813,6 +776,9 @@ out:
static const struct v4l2_file_operations w9966_fops = {
.owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = v4l2_fh_release,
+ .poll = v4l2_ctrl_poll,
.unlocked_ioctl = video_ioctl2,
.read = w9966_v4l_read,
};
@@ -822,13 +788,17 @@ static const struct v4l2_ioctl_ops w9966_ioctl_ops = {
.vidioc_g_input = cam_g_input,
.vidioc_s_input = cam_s_input,
.vidioc_enum_input = cam_enum_input,
- .vidioc_queryctrl = cam_queryctrl,
- .vidioc_g_ctrl = cam_g_ctrl,
- .vidioc_s_ctrl = cam_s_ctrl,
.vidioc_enum_fmt_vid_cap = cam_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = cam_g_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = cam_s_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = cam_try_fmt_vid_cap,
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_ctrl_ops cam_ctrl_ops = {
+ .s_ctrl = cam_s_ctrl,
};
@@ -849,6 +819,20 @@ static int w9966_init(struct w9966 *cam, struct parport *port)
v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
return -1;
}
+
+ v4l2_ctrl_handler_init(&cam->hdl, 4);
+ v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+ v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops,
+ V4L2_CID_CONTRAST, -64, 64, 1, 64);
+ v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops,
+ V4L2_CID_SATURATION, -64, 64, 1, 64);
+ v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops,
+ V4L2_CID_HUE, -128, 127, 1, 0);
+ if (cam->hdl.error) {
+ v4l2_err(v4l2_dev, "couldn't register controls\n");
+ return -1;
+ }
cam->pport = port;
cam->brightness = 128;
cam->contrast = 64;
@@ -898,6 +882,8 @@ static int w9966_init(struct w9966 *cam, struct parport *port)
cam->vdev.fops = &w9966_fops;
cam->vdev.ioctl_ops = &w9966_ioctl_ops;
cam->vdev.release = video_device_release_empty;
+ cam->vdev.ctrl_handler = &cam->hdl;
+ set_bit(V4L2_FL_USE_FH_PRIO, &cam->vdev.flags);
video_set_drvdata(&cam->vdev, cam);
mutex_init(&cam->lock);
@@ -923,6 +909,8 @@ static void w9966_term(struct w9966 *cam)
w9966_set_state(cam, W9966_STATE_VDEV, 0);
}
+ v4l2_ctrl_handler_free(&cam->hdl);
+
/* Terminate from IEEE1284 mode and release pdev block */
if (w9966_get_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
w9966_pdev_claim(cam);
diff --git a/drivers/media/video/zoran/zoran_device.c b/drivers/media/video/zoran/zoran_device.c
index e86173bd1327..a4cd504b8eee 100644
--- a/drivers/media/video/zoran/zoran_device.c
+++ b/drivers/media/video/zoran/zoran_device.c
@@ -542,11 +542,9 @@ void write_overlay_mask(struct zoran_fh *fh, struct v4l2_clip *vp, int count)
u32 *mask;
int x, y, width, height;
unsigned i, j, k;
- u32 reg;
/* fill mask with one bits */
memset(fh->overlay_mask, ~0, mask_line_size * 4 * BUZ_MAX_HEIGHT);
- reg = 0;
for (i = 0; i < count; ++i) {
/* pick up local copy of clip */
diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c
index 4c09ab781ec3..c57310931810 100644
--- a/drivers/media/video/zoran/zoran_driver.c
+++ b/drivers/media/video/zoran/zoran_driver.c
@@ -1131,8 +1131,14 @@ static int setup_fbuffer(struct zoran_fh *fh,
}
-static int setup_window(struct zoran_fh *fh, int x, int y, int width, int height,
- struct v4l2_clip __user *clips, int clipcount, void __user *bitmap)
+static int setup_window(struct zoran_fh *fh,
+ int x,
+ int y,
+ int width,
+ int height,
+ struct v4l2_clip __user *clips,
+ unsigned int clipcount,
+ void __user *bitmap)
{
struct zoran *zr = fh->zr;
struct v4l2_clip *vcp = NULL;
@@ -1155,6 +1161,14 @@ static int setup_window(struct zoran_fh *fh, int x, int y, int width, int height
return -EINVAL;
}
+ if (clipcount > 2048) {
+ dprintk(1,
+ KERN_ERR
+ "%s: %s - invalid clipcount\n",
+ ZR_DEVNAME(zr), __func__);
+ return -EINVAL;
+ }
+
/*
* The video front end needs 4-byte alinged line sizes, we correct that
* silently here if necessary
@@ -1218,7 +1232,7 @@ static int setup_window(struct zoran_fh *fh, int x, int y, int width, int height
(width * height + 7) / 8)) {
return -EFAULT;
}
- } else if (clipcount > 0) {
+ } else if (clipcount) {
/* write our own bitmap from the clips */
vcp = vmalloc(sizeof(struct v4l2_clip) * (clipcount + 4));
if (vcp == NULL) {
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
index cd2e39fc4bf0..e44cb330bbc8 100644
--- a/drivers/media/video/zr364xx.c
+++ b/drivers/media/video/zr364xx.c
@@ -507,14 +507,12 @@ static void zr364xx_fillbuff(struct zr364xx_camera *cam,
const char *tmpbuf;
char *vbuf = videobuf_to_vmalloc(&buf->vb);
unsigned long last_frame;
- struct zr364xx_framei *frm;
if (!vbuf)
return;
last_frame = cam->last_frame;
if (last_frame != -1) {
- frm = &cam->buffer.frame[last_frame];
tmpbuf = (const char *)cam->buffer.frame[last_frame].lpvbits;
switch (buf->fmt->fourcc) {
case V4L2_PIX_FMT_JPEG:
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
new file mode 100644
index 000000000000..067f31174a0e
--- /dev/null
+++ b/drivers/memory/Kconfig
@@ -0,0 +1,43 @@
+#
+# Memory devices
+#
+
+menuconfig MEMORY
+ bool "Memory Controller drivers"
+
+if MEMORY
+
+config TI_EMIF
+ tristate "Texas Instruments EMIF driver"
+ depends on ARCH_OMAP2PLUS
+ select DDR
+ help
+ This driver is for the EMIF module available in Texas Instruments
+ SoCs. EMIF is an SDRAM controller that, based on its revision,
+ supports one or more of DDR2, DDR3, and LPDDR2 SDRAM protocols.
+ This driver takes care of only LPDDR2 memories presently. The
+ functions of the driver includes re-configuring AC timing
+ parameters and other settings during frequency, voltage and
+ temperature changes
+
+config TEGRA20_MC
+ bool "Tegra20 Memory Controller(MC) driver"
+ default y
+ depends on ARCH_TEGRA_2x_SOC
+ help
+ This driver is for the Memory Controller(MC) module available
+ in Tegra20 SoCs, mainly for a address translation fault
+ analysis, especially for IOMMU/GART(Graphics Address
+ Relocation Table) module.
+
+config TEGRA30_MC
+ bool "Tegra30 Memory Controller(MC) driver"
+ default y
+ depends on ARCH_TEGRA_3x_SOC
+ help
+ This driver is for the Memory Controller(MC) module available
+ in Tegra30 SoCs, mainly for a address translation fault
+ analysis, especially for IOMMU/SMMU(System Memory Management
+ Unit) module.
+
+endif
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
new file mode 100644
index 000000000000..42b3ce9d80fc
--- /dev/null
+++ b/drivers/memory/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for memory devices
+#
+
+obj-$(CONFIG_TI_EMIF) += emif.o
+obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o
+obj-$(CONFIG_TEGRA30_MC) += tegra30-mc.o
diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c
new file mode 100644
index 000000000000..33a4396b24cb
--- /dev/null
+++ b/drivers/memory/emif.c
@@ -0,0 +1,1670 @@
+/*
+ * EMIF driver
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Aneesh V <aneesh@ti.com>
+ * Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/platform_data/emif_plat.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <memory/jedec_ddr.h>
+#include "emif.h"
+
+/**
+ * struct emif_data - Per device static data for driver's use
+ * @duplicate: Whether the DDR devices attached to this EMIF
+ * instance are exactly same as that on EMIF1. In
+ * this case we can save some memory and processing
+ * @temperature_level: Maximum temperature of LPDDR2 devices attached
+ * to this EMIF - read from MR4 register. If there
+ * are two devices attached to this EMIF, this
+ * value is the maximum of the two temperature
+ * levels.
+ * @node: node in the device list
+ * @base: base address of memory-mapped IO registers.
+ * @dev: device pointer.
+ * @addressing table with addressing information from the spec
+ * @regs_cache: An array of 'struct emif_regs' that stores
+ * calculated register values for different
+ * frequencies, to avoid re-calculating them on
+ * each DVFS transition.
+ * @curr_regs: The set of register values used in the last
+ * frequency change (i.e. corresponding to the
+ * frequency in effect at the moment)
+ * @plat_data: Pointer to saved platform data.
+ * @debugfs_root: dentry to the root folder for EMIF in debugfs
+ */
+struct emif_data {
+ u8 duplicate;
+ u8 temperature_level;
+ u8 lpmode;
+ struct list_head node;
+ unsigned long irq_state;
+ void __iomem *base;
+ struct device *dev;
+ const struct lpddr2_addressing *addressing;
+ struct emif_regs *regs_cache[EMIF_MAX_NUM_FREQUENCIES];
+ struct emif_regs *curr_regs;
+ struct emif_platform_data *plat_data;
+ struct dentry *debugfs_root;
+};
+
+static struct emif_data *emif1;
+static spinlock_t emif_lock;
+static unsigned long irq_state;
+static u32 t_ck; /* DDR clock period in ps */
+static LIST_HEAD(device_list);
+
+static void do_emif_regdump_show(struct seq_file *s, struct emif_data *emif,
+ struct emif_regs *regs)
+{
+ u32 type = emif->plat_data->device_info->type;
+ u32 ip_rev = emif->plat_data->ip_rev;
+
+ seq_printf(s, "EMIF register cache dump for %dMHz\n",
+ regs->freq/1000000);
+
+ seq_printf(s, "ref_ctrl_shdw\t: 0x%08x\n", regs->ref_ctrl_shdw);
+ seq_printf(s, "sdram_tim1_shdw\t: 0x%08x\n", regs->sdram_tim1_shdw);
+ seq_printf(s, "sdram_tim2_shdw\t: 0x%08x\n", regs->sdram_tim2_shdw);
+ seq_printf(s, "sdram_tim3_shdw\t: 0x%08x\n", regs->sdram_tim3_shdw);
+
+ if (ip_rev == EMIF_4D) {
+ seq_printf(s, "read_idle_ctrl_shdw_normal\t: 0x%08x\n",
+ regs->read_idle_ctrl_shdw_normal);
+ seq_printf(s, "read_idle_ctrl_shdw_volt_ramp\t: 0x%08x\n",
+ regs->read_idle_ctrl_shdw_volt_ramp);
+ } else if (ip_rev == EMIF_4D5) {
+ seq_printf(s, "dll_calib_ctrl_shdw_normal\t: 0x%08x\n",
+ regs->dll_calib_ctrl_shdw_normal);
+ seq_printf(s, "dll_calib_ctrl_shdw_volt_ramp\t: 0x%08x\n",
+ regs->dll_calib_ctrl_shdw_volt_ramp);
+ }
+
+ if (type == DDR_TYPE_LPDDR2_S2 || type == DDR_TYPE_LPDDR2_S4) {
+ seq_printf(s, "ref_ctrl_shdw_derated\t: 0x%08x\n",
+ regs->ref_ctrl_shdw_derated);
+ seq_printf(s, "sdram_tim1_shdw_derated\t: 0x%08x\n",
+ regs->sdram_tim1_shdw_derated);
+ seq_printf(s, "sdram_tim3_shdw_derated\t: 0x%08x\n",
+ regs->sdram_tim3_shdw_derated);
+ }
+}
+
+static int emif_regdump_show(struct seq_file *s, void *unused)
+{
+ struct emif_data *emif = s->private;
+ struct emif_regs **regs_cache;
+ int i;
+
+ if (emif->duplicate)
+ regs_cache = emif1->regs_cache;
+ else
+ regs_cache = emif->regs_cache;
+
+ for (i = 0; i < EMIF_MAX_NUM_FREQUENCIES && regs_cache[i]; i++) {
+ do_emif_regdump_show(s, emif, regs_cache[i]);
+ seq_printf(s, "\n");
+ }
+
+ return 0;
+}
+
+static int emif_regdump_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, emif_regdump_show, inode->i_private);
+}
+
+static const struct file_operations emif_regdump_fops = {
+ .open = emif_regdump_open,
+ .read = seq_read,
+ .release = single_release,
+};
+
+static int emif_mr4_show(struct seq_file *s, void *unused)
+{
+ struct emif_data *emif = s->private;
+
+ seq_printf(s, "MR4=%d\n", emif->temperature_level);
+ return 0;
+}
+
+static int emif_mr4_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, emif_mr4_show, inode->i_private);
+}
+
+static const struct file_operations emif_mr4_fops = {
+ .open = emif_mr4_open,
+ .read = seq_read,
+ .release = single_release,
+};
+
+static int __init_or_module emif_debugfs_init(struct emif_data *emif)
+{
+ struct dentry *dentry;
+ int ret;
+
+ dentry = debugfs_create_dir(dev_name(emif->dev), NULL);
+ if (IS_ERR(dentry)) {
+ ret = PTR_ERR(dentry);
+ goto err0;
+ }
+ emif->debugfs_root = dentry;
+
+ dentry = debugfs_create_file("regcache_dump", S_IRUGO,
+ emif->debugfs_root, emif, &emif_regdump_fops);
+ if (IS_ERR(dentry)) {
+ ret = PTR_ERR(dentry);
+ goto err1;
+ }
+
+ dentry = debugfs_create_file("mr4", S_IRUGO,
+ emif->debugfs_root, emif, &emif_mr4_fops);
+ if (IS_ERR(dentry)) {
+ ret = PTR_ERR(dentry);
+ goto err1;
+ }
+
+ return 0;
+err1:
+ debugfs_remove_recursive(emif->debugfs_root);
+err0:
+ return ret;
+}
+
+static void __exit emif_debugfs_exit(struct emif_data *emif)
+{
+ debugfs_remove_recursive(emif->debugfs_root);
+ emif->debugfs_root = NULL;
+}
+
+/*
+ * Calculate the period of DDR clock from frequency value
+ */
+static void set_ddr_clk_period(u32 freq)
+{
+ /* Divide 10^12 by frequency to get period in ps */
+ t_ck = (u32)DIV_ROUND_UP_ULL(1000000000000ull, freq);
+}
+
+/*
+ * Get bus width used by EMIF. Note that this may be different from the
+ * bus width of the DDR devices used. For instance two 16-bit DDR devices
+ * may be connected to a given CS of EMIF. In this case bus width as far
+ * as EMIF is concerned is 32, where as the DDR bus width is 16 bits.
+ */
+static u32 get_emif_bus_width(struct emif_data *emif)
+{
+ u32 width;
+ void __iomem *base = emif->base;
+
+ width = (readl(base + EMIF_SDRAM_CONFIG) & NARROW_MODE_MASK)
+ >> NARROW_MODE_SHIFT;
+ width = width == 0 ? 32 : 16;
+
+ return width;
+}
+
+/*
+ * Get the CL from SDRAM_CONFIG register
+ */
+static u32 get_cl(struct emif_data *emif)
+{
+ u32 cl;
+ void __iomem *base = emif->base;
+
+ cl = (readl(base + EMIF_SDRAM_CONFIG) & CL_MASK) >> CL_SHIFT;
+
+ return cl;
+}
+
+static void set_lpmode(struct emif_data *emif, u8 lpmode)
+{
+ u32 temp;
+ void __iomem *base = emif->base;
+
+ temp = readl(base + EMIF_POWER_MANAGEMENT_CONTROL);
+ temp &= ~LP_MODE_MASK;
+ temp |= (lpmode << LP_MODE_SHIFT);
+ writel(temp, base + EMIF_POWER_MANAGEMENT_CONTROL);
+}
+
+static void do_freq_update(void)
+{
+ struct emif_data *emif;
+
+ /*
+ * Workaround for errata i728: Disable LPMODE during FREQ_UPDATE
+ *
+ * i728 DESCRIPTION:
+ * The EMIF automatically puts the SDRAM into self-refresh mode
+ * after the EMIF has not performed accesses during
+ * EMIF_PWR_MGMT_CTRL[7:4] REG_SR_TIM number of DDR clock cycles
+ * and the EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE bit field is set
+ * to 0x2. If during a small window the following three events
+ * occur:
+ * - The SR_TIMING counter expires
+ * - And frequency change is requested
+ * - And OCP access is requested
+ * Then it causes instable clock on the DDR interface.
+ *
+ * WORKAROUND
+ * To avoid the occurrence of the three events, the workaround
+ * is to disable the self-refresh when requesting a frequency
+ * change. Before requesting a frequency change the software must
+ * program EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE to 0x0. When the
+ * frequency change has been done, the software can reprogram
+ * EMIF_PWR_MGMT_CTRL[10:8] REG_LP_MODE to 0x2
+ */
+ list_for_each_entry(emif, &device_list, node) {
+ if (emif->lpmode == EMIF_LP_MODE_SELF_REFRESH)
+ set_lpmode(emif, EMIF_LP_MODE_DISABLE);
+ }
+
+ /*
+ * TODO: Do FREQ_UPDATE here when an API
+ * is available for this as part of the new
+ * clock framework
+ */
+
+ list_for_each_entry(emif, &device_list, node) {
+ if (emif->lpmode == EMIF_LP_MODE_SELF_REFRESH)
+ set_lpmode(emif, EMIF_LP_MODE_SELF_REFRESH);
+ }
+}
+
+/* Find addressing table entry based on the device's type and density */
+static const struct lpddr2_addressing *get_addressing_table(
+ const struct ddr_device_info *device_info)
+{
+ u32 index, type, density;
+
+ type = device_info->type;
+ density = device_info->density;
+
+ switch (type) {
+ case DDR_TYPE_LPDDR2_S4:
+ index = density - 1;
+ break;
+ case DDR_TYPE_LPDDR2_S2:
+ switch (density) {
+ case DDR_DENSITY_1Gb:
+ case DDR_DENSITY_2Gb:
+ index = density + 3;
+ break;
+ default:
+ index = density - 1;
+ }
+ break;
+ default:
+ return NULL;
+ }
+
+ return &lpddr2_jedec_addressing_table[index];
+}
+
+/*
+ * Find the the right timing table from the array of timing
+ * tables of the device using DDR clock frequency
+ */
+static const struct lpddr2_timings *get_timings_table(struct emif_data *emif,
+ u32 freq)
+{
+ u32 i, min, max, freq_nearest;
+ const struct lpddr2_timings *timings = NULL;
+ const struct lpddr2_timings *timings_arr = emif->plat_data->timings;
+ struct device *dev = emif->dev;
+
+ /* Start with a very high frequency - 1GHz */
+ freq_nearest = 1000000000;
+
+ /*
+ * Find the timings table such that:
+ * 1. the frequency range covers the required frequency(safe) AND
+ * 2. the max_freq is closest to the required frequency(optimal)
+ */
+ for (i = 0; i < emif->plat_data->timings_arr_size; i++) {
+ max = timings_arr[i].max_freq;
+ min = timings_arr[i].min_freq;
+ if ((freq >= min) && (freq <= max) && (max < freq_nearest)) {
+ freq_nearest = max;
+ timings = &timings_arr[i];
+ }
+ }
+
+ if (!timings)
+ dev_err(dev, "%s: couldn't find timings for - %dHz\n",
+ __func__, freq);
+
+ dev_dbg(dev, "%s: timings table: freq %d, speed bin freq %d\n",
+ __func__, freq, freq_nearest);
+
+ return timings;
+}
+
+static u32 get_sdram_ref_ctrl_shdw(u32 freq,
+ const struct lpddr2_addressing *addressing)
+{
+ u32 ref_ctrl_shdw = 0, val = 0, freq_khz, t_refi;
+
+ /* Scale down frequency and t_refi to avoid overflow */
+ freq_khz = freq / 1000;
+ t_refi = addressing->tREFI_ns / 100;
+
+ /*
+ * refresh rate to be set is 'tREFI(in us) * freq in MHz
+ * division by 10000 to account for change in units
+ */
+ val = t_refi * freq_khz / 10000;
+ ref_ctrl_shdw |= val << REFRESH_RATE_SHIFT;
+
+ return ref_ctrl_shdw;
+}
+
+static u32 get_sdram_tim_1_shdw(const struct lpddr2_timings *timings,
+ const struct lpddr2_min_tck *min_tck,
+ const struct lpddr2_addressing *addressing)
+{
+ u32 tim1 = 0, val = 0;
+
+ val = max(min_tck->tWTR, DIV_ROUND_UP(timings->tWTR, t_ck)) - 1;
+ tim1 |= val << T_WTR_SHIFT;
+
+ if (addressing->num_banks == B8)
+ val = DIV_ROUND_UP(timings->tFAW, t_ck*4);
+ else
+ val = max(min_tck->tRRD, DIV_ROUND_UP(timings->tRRD, t_ck));
+ tim1 |= (val - 1) << T_RRD_SHIFT;
+
+ val = DIV_ROUND_UP(timings->tRAS_min + timings->tRPab, t_ck) - 1;
+ tim1 |= val << T_RC_SHIFT;
+
+ val = max(min_tck->tRASmin, DIV_ROUND_UP(timings->tRAS_min, t_ck));
+ tim1 |= (val - 1) << T_RAS_SHIFT;
+
+ val = max(min_tck->tWR, DIV_ROUND_UP(timings->tWR, t_ck)) - 1;
+ tim1 |= val << T_WR_SHIFT;
+
+ val = max(min_tck->tRCD, DIV_ROUND_UP(timings->tRCD, t_ck)) - 1;
+ tim1 |= val << T_RCD_SHIFT;
+
+ val = max(min_tck->tRPab, DIV_ROUND_UP(timings->tRPab, t_ck)) - 1;
+ tim1 |= val << T_RP_SHIFT;
+
+ return tim1;
+}
+
+static u32 get_sdram_tim_1_shdw_derated(const struct lpddr2_timings *timings,
+ const struct lpddr2_min_tck *min_tck,
+ const struct lpddr2_addressing *addressing)
+{
+ u32 tim1 = 0, val = 0;
+
+ val = max(min_tck->tWTR, DIV_ROUND_UP(timings->tWTR, t_ck)) - 1;
+ tim1 = val << T_WTR_SHIFT;
+
+ /*
+ * tFAW is approximately 4 times tRRD. So add 1875*4 = 7500ps
+ * to tFAW for de-rating
+ */
+ if (addressing->num_banks == B8) {
+ val = DIV_ROUND_UP(timings->tFAW + 7500, 4 * t_ck) - 1;
+ } else {
+ val = DIV_ROUND_UP(timings->tRRD + 1875, t_ck);
+ val = max(min_tck->tRRD, val) - 1;
+ }
+ tim1 |= val << T_RRD_SHIFT;
+
+ val = DIV_ROUND_UP(timings->tRAS_min + timings->tRPab + 1875, t_ck);
+ tim1 |= (val - 1) << T_RC_SHIFT;
+
+ val = DIV_ROUND_UP(timings->tRAS_min + 1875, t_ck);
+ val = max(min_tck->tRASmin, val) - 1;
+ tim1 |= val << T_RAS_SHIFT;
+
+ val = max(min_tck->tWR, DIV_ROUND_UP(timings->tWR, t_ck)) - 1;
+ tim1 |= val << T_WR_SHIFT;
+
+ val = max(min_tck->tRCD, DIV_ROUND_UP(timings->tRCD + 1875, t_ck));
+ tim1 |= (val - 1) << T_RCD_SHIFT;
+
+ val = max(min_tck->tRPab, DIV_ROUND_UP(timings->tRPab + 1875, t_ck));
+ tim1 |= (val - 1) << T_RP_SHIFT;
+
+ return tim1;
+}
+
+static u32 get_sdram_tim_2_shdw(const struct lpddr2_timings *timings,
+ const struct lpddr2_min_tck *min_tck,
+ const struct lpddr2_addressing *addressing,
+ u32 type)
+{
+ u32 tim2 = 0, val = 0;
+
+ val = min_tck->tCKE - 1;
+ tim2 |= val << T_CKE_SHIFT;
+
+ val = max(min_tck->tRTP, DIV_ROUND_UP(timings->tRTP, t_ck)) - 1;
+ tim2 |= val << T_RTP_SHIFT;
+
+ /* tXSNR = tRFCab_ps + 10 ns(tRFCab_ps for LPDDR2). */
+ val = DIV_ROUND_UP(addressing->tRFCab_ps + 10000, t_ck) - 1;
+ tim2 |= val << T_XSNR_SHIFT;
+
+ /* XSRD same as XSNR for LPDDR2 */
+ tim2 |= val << T_XSRD_SHIFT;
+
+ val = max(min_tck->tXP, DIV_ROUND_UP(timings->tXP, t_ck)) - 1;
+ tim2 |= val << T_XP_SHIFT;
+
+ return tim2;
+}
+
+static u32 get_sdram_tim_3_shdw(const struct lpddr2_timings *timings,
+ const struct lpddr2_min_tck *min_tck,
+ const struct lpddr2_addressing *addressing,
+ u32 type, u32 ip_rev, u32 derated)
+{
+ u32 tim3 = 0, val = 0, t_dqsck;
+
+ val = timings->tRAS_max_ns / addressing->tREFI_ns - 1;
+ val = val > 0xF ? 0xF : val;
+ tim3 |= val << T_RAS_MAX_SHIFT;
+
+ val = DIV_ROUND_UP(addressing->tRFCab_ps, t_ck) - 1;
+ tim3 |= val << T_RFC_SHIFT;
+
+ t_dqsck = (derated == EMIF_DERATED_TIMINGS) ?
+ timings->tDQSCK_max_derated : timings->tDQSCK_max;
+ if (ip_rev == EMIF_4D5)
+ val = DIV_ROUND_UP(t_dqsck + 1000, t_ck) - 1;
+ else
+ val = DIV_ROUND_UP(t_dqsck, t_ck) - 1;
+
+ tim3 |= val << T_TDQSCKMAX_SHIFT;
+
+ val = DIV_ROUND_UP(timings->tZQCS, t_ck) - 1;
+ tim3 |= val << ZQ_ZQCS_SHIFT;
+
+ val = DIV_ROUND_UP(timings->tCKESR, t_ck);
+ val = max(min_tck->tCKESR, val) - 1;
+ tim3 |= val << T_CKESR_SHIFT;
+
+ if (ip_rev == EMIF_4D5) {
+ tim3 |= (EMIF_T_CSTA - 1) << T_CSTA_SHIFT;
+
+ val = DIV_ROUND_UP(EMIF_T_PDLL_UL, 128) - 1;
+ tim3 |= val << T_PDLL_UL_SHIFT;
+ }
+
+ return tim3;
+}
+
+static u32 get_zq_config_reg(const struct lpddr2_addressing *addressing,
+ bool cs1_used, bool cal_resistors_per_cs)
+{
+ u32 zq = 0, val = 0;
+
+ val = EMIF_ZQCS_INTERVAL_US * 1000 / addressing->tREFI_ns;
+ zq |= val << ZQ_REFINTERVAL_SHIFT;
+
+ val = DIV_ROUND_UP(T_ZQCL_DEFAULT_NS, T_ZQCS_DEFAULT_NS) - 1;
+ zq |= val << ZQ_ZQCL_MULT_SHIFT;
+
+ val = DIV_ROUND_UP(T_ZQINIT_DEFAULT_NS, T_ZQCL_DEFAULT_NS) - 1;
+ zq |= val << ZQ_ZQINIT_MULT_SHIFT;
+
+ zq |= ZQ_SFEXITEN_ENABLE << ZQ_SFEXITEN_SHIFT;
+
+ if (cal_resistors_per_cs)
+ zq |= ZQ_DUALCALEN_ENABLE << ZQ_DUALCALEN_SHIFT;
+ else
+ zq |= ZQ_DUALCALEN_DISABLE << ZQ_DUALCALEN_SHIFT;
+
+ zq |= ZQ_CS0EN_MASK; /* CS0 is used for sure */
+
+ val = cs1_used ? 1 : 0;
+ zq |= val << ZQ_CS1EN_SHIFT;
+
+ return zq;
+}
+
+static u32 get_temp_alert_config(const struct lpddr2_addressing *addressing,
+ const struct emif_custom_configs *custom_configs, bool cs1_used,
+ u32 sdram_io_width, u32 emif_bus_width)
+{
+ u32 alert = 0, interval, devcnt;
+
+ if (custom_configs && (custom_configs->mask &
+ EMIF_CUSTOM_CONFIG_TEMP_ALERT_POLL_INTERVAL))
+ interval = custom_configs->temp_alert_poll_interval_ms;
+ else
+ interval = TEMP_ALERT_POLL_INTERVAL_DEFAULT_MS;
+
+ interval *= 1000000; /* Convert to ns */
+ interval /= addressing->tREFI_ns; /* Convert to refresh cycles */
+ alert |= (interval << TA_REFINTERVAL_SHIFT);
+
+ /*
+ * sdram_io_width is in 'log2(x) - 1' form. Convert emif_bus_width
+ * also to this form and subtract to get TA_DEVCNT, which is
+ * in log2(x) form.
+ */
+ emif_bus_width = __fls(emif_bus_width) - 1;
+ devcnt = emif_bus_width - sdram_io_width;
+ alert |= devcnt << TA_DEVCNT_SHIFT;
+
+ /* DEVWDT is in 'log2(x) - 3' form */
+ alert |= (sdram_io_width - 2) << TA_DEVWDT_SHIFT;
+
+ alert |= 1 << TA_SFEXITEN_SHIFT;
+ alert |= 1 << TA_CS0EN_SHIFT;
+ alert |= (cs1_used ? 1 : 0) << TA_CS1EN_SHIFT;
+
+ return alert;
+}
+
+static u32 get_read_idle_ctrl_shdw(u8 volt_ramp)
+{
+ u32 idle = 0, val = 0;
+
+ /*
+ * Maximum value in normal conditions and increased frequency
+ * when voltage is ramping
+ */
+ if (volt_ramp)
+ val = READ_IDLE_INTERVAL_DVFS / t_ck / 64 - 1;
+ else
+ val = 0x1FF;
+
+ /*
+ * READ_IDLE_CTRL register in EMIF4D has same offset and fields
+ * as DLL_CALIB_CTRL in EMIF4D5, so use the same shifts
+ */
+ idle |= val << DLL_CALIB_INTERVAL_SHIFT;
+ idle |= EMIF_READ_IDLE_LEN_VAL << ACK_WAIT_SHIFT;
+
+ return idle;
+}
+
+static u32 get_dll_calib_ctrl_shdw(u8 volt_ramp)
+{
+ u32 calib = 0, val = 0;
+
+ if (volt_ramp == DDR_VOLTAGE_RAMPING)
+ val = DLL_CALIB_INTERVAL_DVFS / t_ck / 16 - 1;
+ else
+ val = 0; /* Disabled when voltage is stable */
+
+ calib |= val << DLL_CALIB_INTERVAL_SHIFT;
+ calib |= DLL_CALIB_ACK_WAIT_VAL << ACK_WAIT_SHIFT;
+
+ return calib;
+}
+
+static u32 get_ddr_phy_ctrl_1_attilaphy_4d(const struct lpddr2_timings *timings,
+ u32 freq, u8 RL)
+{
+ u32 phy = EMIF_DDR_PHY_CTRL_1_BASE_VAL_ATTILAPHY, val = 0;
+
+ val = RL + DIV_ROUND_UP(timings->tDQSCK_max, t_ck) - 1;
+ phy |= val << READ_LATENCY_SHIFT_4D;
+
+ if (freq <= 100000000)
+ val = EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS_ATTILAPHY;
+ else if (freq <= 200000000)
+ val = EMIF_DLL_SLAVE_DLY_CTRL_200_MHZ_ATTILAPHY;
+ else
+ val = EMIF_DLL_SLAVE_DLY_CTRL_400_MHZ_ATTILAPHY;
+
+ phy |= val << DLL_SLAVE_DLY_CTRL_SHIFT_4D;
+
+ return phy;
+}
+
+static u32 get_phy_ctrl_1_intelliphy_4d5(u32 freq, u8 cl)
+{
+ u32 phy = EMIF_DDR_PHY_CTRL_1_BASE_VAL_INTELLIPHY, half_delay;
+
+ /*
+ * DLL operates at 266 MHz. If DDR frequency is near 266 MHz,
+ * half-delay is not needed else set half-delay
+ */
+ if (freq >= 265000000 && freq < 267000000)
+ half_delay = 0;
+ else
+ half_delay = 1;
+
+ phy |= half_delay << DLL_HALF_DELAY_SHIFT_4D5;
+ phy |= ((cl + DIV_ROUND_UP(EMIF_PHY_TOTAL_READ_LATENCY_INTELLIPHY_PS,
+ t_ck) - 1) << READ_LATENCY_SHIFT_4D5);
+
+ return phy;
+}
+
+static u32 get_ext_phy_ctrl_2_intelliphy_4d5(void)
+{
+ u32 fifo_we_slave_ratio;
+
+ fifo_we_slave_ratio = DIV_ROUND_CLOSEST(
+ EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256 , t_ck);
+
+ return fifo_we_slave_ratio | fifo_we_slave_ratio << 11 |
+ fifo_we_slave_ratio << 22;
+}
+
+static u32 get_ext_phy_ctrl_3_intelliphy_4d5(void)
+{
+ u32 fifo_we_slave_ratio;
+
+ fifo_we_slave_ratio = DIV_ROUND_CLOSEST(
+ EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256 , t_ck);
+
+ return fifo_we_slave_ratio >> 10 | fifo_we_slave_ratio << 1 |
+ fifo_we_slave_ratio << 12 | fifo_we_slave_ratio << 23;
+}
+
+static u32 get_ext_phy_ctrl_4_intelliphy_4d5(void)
+{
+ u32 fifo_we_slave_ratio;
+
+ fifo_we_slave_ratio = DIV_ROUND_CLOSEST(
+ EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS * 256 , t_ck);
+
+ return fifo_we_slave_ratio >> 9 | fifo_we_slave_ratio << 2 |
+ fifo_we_slave_ratio << 13;
+}
+
+static u32 get_pwr_mgmt_ctrl(u32 freq, struct emif_data *emif, u32 ip_rev)
+{
+ u32 pwr_mgmt_ctrl = 0, timeout;
+ u32 lpmode = EMIF_LP_MODE_SELF_REFRESH;
+ u32 timeout_perf = EMIF_LP_MODE_TIMEOUT_PERFORMANCE;
+ u32 timeout_pwr = EMIF_LP_MODE_TIMEOUT_POWER;
+ u32 freq_threshold = EMIF_LP_MODE_FREQ_THRESHOLD;
+
+ struct emif_custom_configs *cust_cfgs = emif->plat_data->custom_configs;
+
+ if (cust_cfgs && (cust_cfgs->mask & EMIF_CUSTOM_CONFIG_LPMODE)) {
+ lpmode = cust_cfgs->lpmode;
+ timeout_perf = cust_cfgs->lpmode_timeout_performance;
+ timeout_pwr = cust_cfgs->lpmode_timeout_power;
+ freq_threshold = cust_cfgs->lpmode_freq_threshold;
+ }
+
+ /* Timeout based on DDR frequency */
+ timeout = freq >= freq_threshold ? timeout_perf : timeout_pwr;
+
+ /* The value to be set in register is "log2(timeout) - 3" */
+ if (timeout < 16) {
+ timeout = 0;
+ } else {
+ timeout = __fls(timeout) - 3;
+ if (timeout & (timeout - 1))
+ timeout++;
+ }
+
+ switch (lpmode) {
+ case EMIF_LP_MODE_CLOCK_STOP:
+ pwr_mgmt_ctrl = (timeout << CS_TIM_SHIFT) |
+ SR_TIM_MASK | PD_TIM_MASK;
+ break;
+ case EMIF_LP_MODE_SELF_REFRESH:
+ /* Workaround for errata i735 */
+ if (timeout < 6)
+ timeout = 6;
+
+ pwr_mgmt_ctrl = (timeout << SR_TIM_SHIFT) |
+ CS_TIM_MASK | PD_TIM_MASK;
+ break;
+ case EMIF_LP_MODE_PWR_DN:
+ pwr_mgmt_ctrl = (timeout << PD_TIM_SHIFT) |
+ CS_TIM_MASK | SR_TIM_MASK;
+ break;
+ case EMIF_LP_MODE_DISABLE:
+ default:
+ pwr_mgmt_ctrl = CS_TIM_MASK |
+ PD_TIM_MASK | SR_TIM_MASK;
+ }
+
+ /* No CS_TIM in EMIF_4D5 */
+ if (ip_rev == EMIF_4D5)
+ pwr_mgmt_ctrl &= ~CS_TIM_MASK;
+
+ pwr_mgmt_ctrl |= lpmode << LP_MODE_SHIFT;
+
+ return pwr_mgmt_ctrl;
+}
+
+/*
+ * Get the temperature level of the EMIF instance:
+ * Reads the MR4 register of attached SDRAM parts to find out the temperature
+ * level. If there are two parts attached(one on each CS), then the temperature
+ * level for the EMIF instance is the higher of the two temperatures.
+ */
+static void get_temperature_level(struct emif_data *emif)
+{
+ u32 temp, temperature_level;
+ void __iomem *base;
+
+ base = emif->base;
+
+ /* Read mode register 4 */
+ writel(DDR_MR4, base + EMIF_LPDDR2_MODE_REG_CONFIG);
+ temperature_level = readl(base + EMIF_LPDDR2_MODE_REG_DATA);
+ temperature_level = (temperature_level & MR4_SDRAM_REF_RATE_MASK) >>
+ MR4_SDRAM_REF_RATE_SHIFT;
+
+ if (emif->plat_data->device_info->cs1_used) {
+ writel(DDR_MR4 | CS_MASK, base + EMIF_LPDDR2_MODE_REG_CONFIG);
+ temp = readl(base + EMIF_LPDDR2_MODE_REG_DATA);
+ temp = (temp & MR4_SDRAM_REF_RATE_MASK)
+ >> MR4_SDRAM_REF_RATE_SHIFT;
+ temperature_level = max(temp, temperature_level);
+ }
+
+ /* treat everything less than nominal(3) in MR4 as nominal */
+ if (unlikely(temperature_level < SDRAM_TEMP_NOMINAL))
+ temperature_level = SDRAM_TEMP_NOMINAL;
+
+ /* if we get reserved value in MR4 persist with the existing value */
+ if (likely(temperature_level != SDRAM_TEMP_RESERVED_4))
+ emif->temperature_level = temperature_level;
+}
+
+/*
+ * Program EMIF shadow registers that are not dependent on temperature
+ * or voltage
+ */
+static void setup_registers(struct emif_data *emif, struct emif_regs *regs)
+{
+ void __iomem *base = emif->base;
+
+ writel(regs->sdram_tim2_shdw, base + EMIF_SDRAM_TIMING_2_SHDW);
+ writel(regs->phy_ctrl_1_shdw, base + EMIF_DDR_PHY_CTRL_1_SHDW);
+
+ /* Settings specific for EMIF4D5 */
+ if (emif->plat_data->ip_rev != EMIF_4D5)
+ return;
+ writel(regs->ext_phy_ctrl_2_shdw, base + EMIF_EXT_PHY_CTRL_2_SHDW);
+ writel(regs->ext_phy_ctrl_3_shdw, base + EMIF_EXT_PHY_CTRL_3_SHDW);
+ writel(regs->ext_phy_ctrl_4_shdw, base + EMIF_EXT_PHY_CTRL_4_SHDW);
+}
+
+/*
+ * When voltage ramps dll calibration and forced read idle should
+ * happen more often
+ */
+static void setup_volt_sensitive_regs(struct emif_data *emif,
+ struct emif_regs *regs, u32 volt_state)
+{
+ u32 calib_ctrl;
+ void __iomem *base = emif->base;
+
+ /*
+ * EMIF_READ_IDLE_CTRL in EMIF4D refers to the same register as
+ * EMIF_DLL_CALIB_CTRL in EMIF4D5 and dll_calib_ctrl_shadow_*
+ * is an alias of the respective read_idle_ctrl_shdw_* (members of
+ * a union). So, the below code takes care of both cases
+ */
+ if (volt_state == DDR_VOLTAGE_RAMPING)
+ calib_ctrl = regs->dll_calib_ctrl_shdw_volt_ramp;
+ else
+ calib_ctrl = regs->dll_calib_ctrl_shdw_normal;
+
+ writel(calib_ctrl, base + EMIF_DLL_CALIB_CTRL_SHDW);
+}
+
+/*
+ * setup_temperature_sensitive_regs() - set the timings for temperature
+ * sensitive registers. This happens once at initialisation time based
+ * on the temperature at boot time and subsequently based on the temperature
+ * alert interrupt. Temperature alert can happen when the temperature
+ * increases or drops. So this function can have the effect of either
+ * derating the timings or going back to nominal values.
+ */
+static void setup_temperature_sensitive_regs(struct emif_data *emif,
+ struct emif_regs *regs)
+{
+ u32 tim1, tim3, ref_ctrl, type;
+ void __iomem *base = emif->base;
+ u32 temperature;
+
+ type = emif->plat_data->device_info->type;
+
+ tim1 = regs->sdram_tim1_shdw;
+ tim3 = regs->sdram_tim3_shdw;
+ ref_ctrl = regs->ref_ctrl_shdw;
+
+ /* No de-rating for non-lpddr2 devices */
+ if (type != DDR_TYPE_LPDDR2_S2 && type != DDR_TYPE_LPDDR2_S4)
+ goto out;
+
+ temperature = emif->temperature_level;
+ if (temperature == SDRAM_TEMP_HIGH_DERATE_REFRESH) {
+ ref_ctrl = regs->ref_ctrl_shdw_derated;
+ } else if (temperature == SDRAM_TEMP_HIGH_DERATE_REFRESH_AND_TIMINGS) {
+ tim1 = regs->sdram_tim1_shdw_derated;
+ tim3 = regs->sdram_tim3_shdw_derated;
+ ref_ctrl = regs->ref_ctrl_shdw_derated;
+ }
+
+out:
+ writel(tim1, base + EMIF_SDRAM_TIMING_1_SHDW);
+ writel(tim3, base + EMIF_SDRAM_TIMING_3_SHDW);
+ writel(ref_ctrl, base + EMIF_SDRAM_REFRESH_CTRL_SHDW);
+}
+
+static irqreturn_t handle_temp_alert(void __iomem *base, struct emif_data *emif)
+{
+ u32 old_temp_level;
+ irqreturn_t ret = IRQ_HANDLED;
+
+ spin_lock_irqsave(&emif_lock, irq_state);
+ old_temp_level = emif->temperature_level;
+ get_temperature_level(emif);
+
+ if (unlikely(emif->temperature_level == old_temp_level)) {
+ goto out;
+ } else if (!emif->curr_regs) {
+ dev_err(emif->dev, "temperature alert before registers are calculated, not de-rating timings\n");
+ goto out;
+ }
+
+ if (emif->temperature_level < old_temp_level ||
+ emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) {
+ /*
+ * Temperature coming down - defer handling to thread OR
+ * Temperature far too high - do kernel_power_off() from
+ * thread context
+ */
+ ret = IRQ_WAKE_THREAD;
+ } else {
+ /* Temperature is going up - handle immediately */
+ setup_temperature_sensitive_regs(emif, emif->curr_regs);
+ do_freq_update();
+ }
+
+out:
+ spin_unlock_irqrestore(&emif_lock, irq_state);
+ return ret;
+}
+
+static irqreturn_t emif_interrupt_handler(int irq, void *dev_id)
+{
+ u32 interrupts;
+ struct emif_data *emif = dev_id;
+ void __iomem *base = emif->base;
+ struct device *dev = emif->dev;
+ irqreturn_t ret = IRQ_HANDLED;
+
+ /* Save the status and clear it */
+ interrupts = readl(base + EMIF_SYSTEM_OCP_INTERRUPT_STATUS);
+ writel(interrupts, base + EMIF_SYSTEM_OCP_INTERRUPT_STATUS);
+
+ /*
+ * Handle temperature alert
+ * Temperature alert should be same for all ports
+ * So, it's enough to process it only for one of the ports
+ */
+ if (interrupts & TA_SYS_MASK)
+ ret = handle_temp_alert(base, emif);
+
+ if (interrupts & ERR_SYS_MASK)
+ dev_err(dev, "Access error from SYS port - %x\n", interrupts);
+
+ if (emif->plat_data->hw_caps & EMIF_HW_CAPS_LL_INTERFACE) {
+ /* Save the status and clear it */
+ interrupts = readl(base + EMIF_LL_OCP_INTERRUPT_STATUS);
+ writel(interrupts, base + EMIF_LL_OCP_INTERRUPT_STATUS);
+
+ if (interrupts & ERR_LL_MASK)
+ dev_err(dev, "Access error from LL port - %x\n",
+ interrupts);
+ }
+
+ return ret;
+}
+
+static irqreturn_t emif_threaded_isr(int irq, void *dev_id)
+{
+ struct emif_data *emif = dev_id;
+
+ if (emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN) {
+ dev_emerg(emif->dev, "SDRAM temperature exceeds operating limit.. Needs shut down!!!\n");
+ kernel_power_off();
+ return IRQ_HANDLED;
+ }
+
+ spin_lock_irqsave(&emif_lock, irq_state);
+
+ if (emif->curr_regs) {
+ setup_temperature_sensitive_regs(emif, emif->curr_regs);
+ do_freq_update();
+ } else {
+ dev_err(emif->dev, "temperature alert before registers are calculated, not de-rating timings\n");
+ }
+
+ spin_unlock_irqrestore(&emif_lock, irq_state);
+
+ return IRQ_HANDLED;
+}
+
+static void clear_all_interrupts(struct emif_data *emif)
+{
+ void __iomem *base = emif->base;
+
+ writel(readl(base + EMIF_SYSTEM_OCP_INTERRUPT_STATUS),
+ base + EMIF_SYSTEM_OCP_INTERRUPT_STATUS);
+ if (emif->plat_data->hw_caps & EMIF_HW_CAPS_LL_INTERFACE)
+ writel(readl(base + EMIF_LL_OCP_INTERRUPT_STATUS),
+ base + EMIF_LL_OCP_INTERRUPT_STATUS);
+}
+
+static void disable_and_clear_all_interrupts(struct emif_data *emif)
+{
+ void __iomem *base = emif->base;
+
+ /* Disable all interrupts */
+ writel(readl(base + EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_SET),
+ base + EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_CLEAR);
+ if (emif->plat_data->hw_caps & EMIF_HW_CAPS_LL_INTERFACE)
+ writel(readl(base + EMIF_LL_OCP_INTERRUPT_ENABLE_SET),
+ base + EMIF_LL_OCP_INTERRUPT_ENABLE_CLEAR);
+
+ /* Clear all interrupts */
+ clear_all_interrupts(emif);
+}
+
+static int __init_or_module setup_interrupts(struct emif_data *emif, u32 irq)
+{
+ u32 interrupts, type;
+ void __iomem *base = emif->base;
+
+ type = emif->plat_data->device_info->type;
+
+ clear_all_interrupts(emif);
+
+ /* Enable interrupts for SYS interface */
+ interrupts = EN_ERR_SYS_MASK;
+ if (type == DDR_TYPE_LPDDR2_S2 || type == DDR_TYPE_LPDDR2_S4)
+ interrupts |= EN_TA_SYS_MASK;
+ writel(interrupts, base + EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_SET);
+
+ /* Enable interrupts for LL interface */
+ if (emif->plat_data->hw_caps & EMIF_HW_CAPS_LL_INTERFACE) {
+ /* TA need not be enabled for LL */
+ interrupts = EN_ERR_LL_MASK;
+ writel(interrupts, base + EMIF_LL_OCP_INTERRUPT_ENABLE_SET);
+ }
+
+ /* setup IRQ handlers */
+ return devm_request_threaded_irq(emif->dev, irq,
+ emif_interrupt_handler,
+ emif_threaded_isr,
+ 0, dev_name(emif->dev),
+ emif);
+
+}
+
+static void __init_or_module emif_onetime_settings(struct emif_data *emif)
+{
+ u32 pwr_mgmt_ctrl, zq, temp_alert_cfg;
+ void __iomem *base = emif->base;
+ const struct lpddr2_addressing *addressing;
+ const struct ddr_device_info *device_info;
+
+ device_info = emif->plat_data->device_info;
+ addressing = get_addressing_table(device_info);
+
+ /*
+ * Init power management settings
+ * We don't know the frequency yet. Use a high frequency
+ * value for a conservative timeout setting
+ */
+ pwr_mgmt_ctrl = get_pwr_mgmt_ctrl(1000000000, emif,
+ emif->plat_data->ip_rev);
+ emif->lpmode = (pwr_mgmt_ctrl & LP_MODE_MASK) >> LP_MODE_SHIFT;
+ writel(pwr_mgmt_ctrl, base + EMIF_POWER_MANAGEMENT_CONTROL);
+
+ /* Init ZQ calibration settings */
+ zq = get_zq_config_reg(addressing, device_info->cs1_used,
+ device_info->cal_resistors_per_cs);
+ writel(zq, base + EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG);
+
+ /* Check temperature level temperature level*/
+ get_temperature_level(emif);
+ if (emif->temperature_level == SDRAM_TEMP_VERY_HIGH_SHUTDOWN)
+ dev_emerg(emif->dev, "SDRAM temperature exceeds operating limit.. Needs shut down!!!\n");
+
+ /* Init temperature polling */
+ temp_alert_cfg = get_temp_alert_config(addressing,
+ emif->plat_data->custom_configs, device_info->cs1_used,
+ device_info->io_width, get_emif_bus_width(emif));
+ writel(temp_alert_cfg, base + EMIF_TEMPERATURE_ALERT_CONFIG);
+
+ /*
+ * Program external PHY control registers that are not frequency
+ * dependent
+ */
+ if (emif->plat_data->phy_type != EMIF_PHY_TYPE_INTELLIPHY)
+ return;
+ writel(EMIF_EXT_PHY_CTRL_1_VAL, base + EMIF_EXT_PHY_CTRL_1_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_5_VAL, base + EMIF_EXT_PHY_CTRL_5_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_6_VAL, base + EMIF_EXT_PHY_CTRL_6_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_7_VAL, base + EMIF_EXT_PHY_CTRL_7_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_8_VAL, base + EMIF_EXT_PHY_CTRL_8_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_9_VAL, base + EMIF_EXT_PHY_CTRL_9_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_10_VAL, base + EMIF_EXT_PHY_CTRL_10_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_11_VAL, base + EMIF_EXT_PHY_CTRL_11_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_12_VAL, base + EMIF_EXT_PHY_CTRL_12_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_13_VAL, base + EMIF_EXT_PHY_CTRL_13_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_14_VAL, base + EMIF_EXT_PHY_CTRL_14_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_15_VAL, base + EMIF_EXT_PHY_CTRL_15_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_16_VAL, base + EMIF_EXT_PHY_CTRL_16_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_17_VAL, base + EMIF_EXT_PHY_CTRL_17_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_18_VAL, base + EMIF_EXT_PHY_CTRL_18_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_19_VAL, base + EMIF_EXT_PHY_CTRL_19_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_20_VAL, base + EMIF_EXT_PHY_CTRL_20_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_21_VAL, base + EMIF_EXT_PHY_CTRL_21_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_22_VAL, base + EMIF_EXT_PHY_CTRL_22_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_23_VAL, base + EMIF_EXT_PHY_CTRL_23_SHDW);
+ writel(EMIF_EXT_PHY_CTRL_24_VAL, base + EMIF_EXT_PHY_CTRL_24_SHDW);
+}
+
+static void get_default_timings(struct emif_data *emif)
+{
+ struct emif_platform_data *pd = emif->plat_data;
+
+ pd->timings = lpddr2_jedec_timings;
+ pd->timings_arr_size = ARRAY_SIZE(lpddr2_jedec_timings);
+
+ dev_warn(emif->dev, "%s: using default timings\n", __func__);
+}
+
+static int is_dev_data_valid(u32 type, u32 density, u32 io_width, u32 phy_type,
+ u32 ip_rev, struct device *dev)
+{
+ int valid;
+
+ valid = (type == DDR_TYPE_LPDDR2_S4 ||
+ type == DDR_TYPE_LPDDR2_S2)
+ && (density >= DDR_DENSITY_64Mb
+ && density <= DDR_DENSITY_8Gb)
+ && (io_width >= DDR_IO_WIDTH_8
+ && io_width <= DDR_IO_WIDTH_32);
+
+ /* Combinations of EMIF and PHY revisions that we support today */
+ switch (ip_rev) {
+ case EMIF_4D:
+ valid = valid && (phy_type == EMIF_PHY_TYPE_ATTILAPHY);
+ break;
+ case EMIF_4D5:
+ valid = valid && (phy_type == EMIF_PHY_TYPE_INTELLIPHY);
+ break;
+ default:
+ valid = 0;
+ }
+
+ if (!valid)
+ dev_err(dev, "%s: invalid DDR details\n", __func__);
+ return valid;
+}
+
+static int is_custom_config_valid(struct emif_custom_configs *cust_cfgs,
+ struct device *dev)
+{
+ int valid = 1;
+
+ if ((cust_cfgs->mask & EMIF_CUSTOM_CONFIG_LPMODE) &&
+ (cust_cfgs->lpmode != EMIF_LP_MODE_DISABLE))
+ valid = cust_cfgs->lpmode_freq_threshold &&
+ cust_cfgs->lpmode_timeout_performance &&
+ cust_cfgs->lpmode_timeout_power;
+
+ if (cust_cfgs->mask & EMIF_CUSTOM_CONFIG_TEMP_ALERT_POLL_INTERVAL)
+ valid = valid && cust_cfgs->temp_alert_poll_interval_ms;
+
+ if (!valid)
+ dev_warn(dev, "%s: invalid custom configs\n", __func__);
+
+ return valid;
+}
+
+static struct emif_data *__init_or_module get_device_details(
+ struct platform_device *pdev)
+{
+ u32 size;
+ struct emif_data *emif = NULL;
+ struct ddr_device_info *dev_info;
+ struct emif_custom_configs *cust_cfgs;
+ struct emif_platform_data *pd;
+ struct device *dev;
+ void *temp;
+
+ pd = pdev->dev.platform_data;
+ dev = &pdev->dev;
+
+ if (!(pd && pd->device_info && is_dev_data_valid(pd->device_info->type,
+ pd->device_info->density, pd->device_info->io_width,
+ pd->phy_type, pd->ip_rev, dev))) {
+ dev_err(dev, "%s: invalid device data\n", __func__);
+ goto error;
+ }
+
+ emif = devm_kzalloc(dev, sizeof(*emif), GFP_KERNEL);
+ temp = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+ dev_info = devm_kzalloc(dev, sizeof(*dev_info), GFP_KERNEL);
+
+ if (!emif || !pd || !dev_info) {
+ dev_err(dev, "%s:%d: allocation error\n", __func__, __LINE__);
+ goto error;
+ }
+
+ memcpy(temp, pd, sizeof(*pd));
+ pd = temp;
+ memcpy(dev_info, pd->device_info, sizeof(*dev_info));
+
+ pd->device_info = dev_info;
+ emif->plat_data = pd;
+ emif->dev = dev;
+ emif->temperature_level = SDRAM_TEMP_NOMINAL;
+
+ /*
+ * For EMIF instances other than EMIF1 see if the devices connected
+ * are exactly same as on EMIF1(which is typically the case). If so,
+ * mark it as a duplicate of EMIF1 and skip copying timings data.
+ * This will save some memory and some computation later.
+ */
+ emif->duplicate = emif1 && (memcmp(dev_info,
+ emif1->plat_data->device_info,
+ sizeof(struct ddr_device_info)) == 0);
+
+ if (emif->duplicate) {
+ pd->timings = NULL;
+ pd->min_tck = NULL;
+ goto out;
+ } else if (emif1) {
+ dev_warn(emif->dev, "%s: Non-symmetric DDR geometry\n",
+ __func__);
+ }
+
+ /*
+ * Copy custom configs - ignore allocation error, if any, as
+ * custom_configs is not very critical
+ */
+ cust_cfgs = pd->custom_configs;
+ if (cust_cfgs && is_custom_config_valid(cust_cfgs, dev)) {
+ temp = devm_kzalloc(dev, sizeof(*cust_cfgs), GFP_KERNEL);
+ if (temp)
+ memcpy(temp, cust_cfgs, sizeof(*cust_cfgs));
+ else
+ dev_warn(dev, "%s:%d: allocation error\n", __func__,
+ __LINE__);
+ pd->custom_configs = temp;
+ }
+
+ /*
+ * Copy timings and min-tck values from platform data. If it is not
+ * available or if memory allocation fails, use JEDEC defaults
+ */
+ size = sizeof(struct lpddr2_timings) * pd->timings_arr_size;
+ if (pd->timings) {
+ temp = devm_kzalloc(dev, size, GFP_KERNEL);
+ if (temp) {
+ memcpy(temp, pd->timings, sizeof(*pd->timings));
+ pd->timings = temp;
+ } else {
+ dev_warn(dev, "%s:%d: allocation error\n", __func__,
+ __LINE__);
+ get_default_timings(emif);
+ }
+ } else {
+ get_default_timings(emif);
+ }
+
+ if (pd->min_tck) {
+ temp = devm_kzalloc(dev, sizeof(*pd->min_tck), GFP_KERNEL);
+ if (temp) {
+ memcpy(temp, pd->min_tck, sizeof(*pd->min_tck));
+ pd->min_tck = temp;
+ } else {
+ dev_warn(dev, "%s:%d: allocation error\n", __func__,
+ __LINE__);
+ pd->min_tck = &lpddr2_jedec_min_tck;
+ }
+ } else {
+ pd->min_tck = &lpddr2_jedec_min_tck;
+ }
+
+out:
+ return emif;
+
+error:
+ return NULL;
+}
+
+static int __init_or_module emif_probe(struct platform_device *pdev)
+{
+ struct emif_data *emif;
+ struct resource *res;
+ int irq;
+
+ emif = get_device_details(pdev);
+ if (!emif) {
+ pr_err("%s: error getting device data\n", __func__);
+ goto error;
+ }
+
+ list_add(&emif->node, &device_list);
+ emif->addressing = get_addressing_table(emif->plat_data->device_info);
+
+ /* Save pointers to each other in emif and device structures */
+ emif->dev = &pdev->dev;
+ platform_set_drvdata(pdev, emif);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(emif->dev, "%s: error getting memory resource\n",
+ __func__);
+ goto error;
+ }
+
+ emif->base = devm_request_and_ioremap(emif->dev, res);
+ if (!emif->base) {
+ dev_err(emif->dev, "%s: devm_request_and_ioremap() failed\n",
+ __func__);
+ goto error;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(emif->dev, "%s: error getting IRQ resource - %d\n",
+ __func__, irq);
+ goto error;
+ }
+
+ emif_onetime_settings(emif);
+ emif_debugfs_init(emif);
+ disable_and_clear_all_interrupts(emif);
+ setup_interrupts(emif, irq);
+
+ /* One-time actions taken on probing the first device */
+ if (!emif1) {
+ emif1 = emif;
+ spin_lock_init(&emif_lock);
+
+ /*
+ * TODO: register notifiers for frequency and voltage
+ * change here once the respective frameworks are
+ * available
+ */
+ }
+
+ dev_info(&pdev->dev, "%s: device configured with addr = %p and IRQ%d\n",
+ __func__, emif->base, irq);
+
+ return 0;
+error:
+ return -ENODEV;
+}
+
+static int __exit emif_remove(struct platform_device *pdev)
+{
+ struct emif_data *emif = platform_get_drvdata(pdev);
+
+ emif_debugfs_exit(emif);
+
+ return 0;
+}
+
+static void emif_shutdown(struct platform_device *pdev)
+{
+ struct emif_data *emif = platform_get_drvdata(pdev);
+
+ disable_and_clear_all_interrupts(emif);
+}
+
+static int get_emif_reg_values(struct emif_data *emif, u32 freq,
+ struct emif_regs *regs)
+{
+ u32 cs1_used, ip_rev, phy_type;
+ u32 cl, type;
+ const struct lpddr2_timings *timings;
+ const struct lpddr2_min_tck *min_tck;
+ const struct ddr_device_info *device_info;
+ const struct lpddr2_addressing *addressing;
+ struct emif_data *emif_for_calc;
+ struct device *dev;
+ const struct emif_custom_configs *custom_configs;
+
+ dev = emif->dev;
+ /*
+ * If the devices on this EMIF instance is duplicate of EMIF1,
+ * use EMIF1 details for the calculation
+ */
+ emif_for_calc = emif->duplicate ? emif1 : emif;
+ timings = get_timings_table(emif_for_calc, freq);
+ addressing = emif_for_calc->addressing;
+ if (!timings || !addressing) {
+ dev_err(dev, "%s: not enough data available for %dHz",
+ __func__, freq);
+ return -1;
+ }
+
+ device_info = emif_for_calc->plat_data->device_info;
+ type = device_info->type;
+ cs1_used = device_info->cs1_used;
+ ip_rev = emif_for_calc->plat_data->ip_rev;
+ phy_type = emif_for_calc->plat_data->phy_type;
+
+ min_tck = emif_for_calc->plat_data->min_tck;
+ custom_configs = emif_for_calc->plat_data->custom_configs;
+
+ set_ddr_clk_period(freq);
+
+ regs->ref_ctrl_shdw = get_sdram_ref_ctrl_shdw(freq, addressing);
+ regs->sdram_tim1_shdw = get_sdram_tim_1_shdw(timings, min_tck,
+ addressing);
+ regs->sdram_tim2_shdw = get_sdram_tim_2_shdw(timings, min_tck,
+ addressing, type);
+ regs->sdram_tim3_shdw = get_sdram_tim_3_shdw(timings, min_tck,
+ addressing, type, ip_rev, EMIF_NORMAL_TIMINGS);
+
+ cl = get_cl(emif);
+
+ if (phy_type == EMIF_PHY_TYPE_ATTILAPHY && ip_rev == EMIF_4D) {
+ regs->phy_ctrl_1_shdw = get_ddr_phy_ctrl_1_attilaphy_4d(
+ timings, freq, cl);
+ } else if (phy_type == EMIF_PHY_TYPE_INTELLIPHY && ip_rev == EMIF_4D5) {
+ regs->phy_ctrl_1_shdw = get_phy_ctrl_1_intelliphy_4d5(freq, cl);
+ regs->ext_phy_ctrl_2_shdw = get_ext_phy_ctrl_2_intelliphy_4d5();
+ regs->ext_phy_ctrl_3_shdw = get_ext_phy_ctrl_3_intelliphy_4d5();
+ regs->ext_phy_ctrl_4_shdw = get_ext_phy_ctrl_4_intelliphy_4d5();
+ } else {
+ return -1;
+ }
+
+ /* Only timeout values in pwr_mgmt_ctrl_shdw register */
+ regs->pwr_mgmt_ctrl_shdw =
+ get_pwr_mgmt_ctrl(freq, emif_for_calc, ip_rev) &
+ (CS_TIM_MASK | SR_TIM_MASK | PD_TIM_MASK);
+
+ if (ip_rev & EMIF_4D) {
+ regs->read_idle_ctrl_shdw_normal =
+ get_read_idle_ctrl_shdw(DDR_VOLTAGE_STABLE);
+
+ regs->read_idle_ctrl_shdw_volt_ramp =
+ get_read_idle_ctrl_shdw(DDR_VOLTAGE_RAMPING);
+ } else if (ip_rev & EMIF_4D5) {
+ regs->dll_calib_ctrl_shdw_normal =
+ get_dll_calib_ctrl_shdw(DDR_VOLTAGE_STABLE);
+
+ regs->dll_calib_ctrl_shdw_volt_ramp =
+ get_dll_calib_ctrl_shdw(DDR_VOLTAGE_RAMPING);
+ }
+
+ if (type == DDR_TYPE_LPDDR2_S2 || type == DDR_TYPE_LPDDR2_S4) {
+ regs->ref_ctrl_shdw_derated = get_sdram_ref_ctrl_shdw(freq / 4,
+ addressing);
+
+ regs->sdram_tim1_shdw_derated =
+ get_sdram_tim_1_shdw_derated(timings, min_tck,
+ addressing);
+
+ regs->sdram_tim3_shdw_derated = get_sdram_tim_3_shdw(timings,
+ min_tck, addressing, type, ip_rev,
+ EMIF_DERATED_TIMINGS);
+ }
+
+ regs->freq = freq;
+
+ return 0;
+}
+
+/*
+ * get_regs() - gets the cached emif_regs structure for a given EMIF instance
+ * given frequency(freq):
+ *
+ * As an optimisation, every EMIF instance other than EMIF1 shares the
+ * register cache with EMIF1 if the devices connected on this instance
+ * are same as that on EMIF1(indicated by the duplicate flag)
+ *
+ * If we do not have an entry corresponding to the frequency given, we
+ * allocate a new entry and calculate the values
+ *
+ * Upon finding the right reg dump, save it in curr_regs. It can be
+ * directly used for thermal de-rating and voltage ramping changes.
+ */
+static struct emif_regs *get_regs(struct emif_data *emif, u32 freq)
+{
+ int i;
+ struct emif_regs **regs_cache;
+ struct emif_regs *regs = NULL;
+ struct device *dev;
+
+ dev = emif->dev;
+ if (emif->curr_regs && emif->curr_regs->freq == freq) {
+ dev_dbg(dev, "%s: using curr_regs - %u Hz", __func__, freq);
+ return emif->curr_regs;
+ }
+
+ if (emif->duplicate)
+ regs_cache = emif1->regs_cache;
+ else
+ regs_cache = emif->regs_cache;
+
+ for (i = 0; i < EMIF_MAX_NUM_FREQUENCIES && regs_cache[i]; i++) {
+ if (regs_cache[i]->freq == freq) {
+ regs = regs_cache[i];
+ dev_dbg(dev,
+ "%s: reg dump found in reg cache for %u Hz\n",
+ __func__, freq);
+ break;
+ }
+ }
+
+ /*
+ * If we don't have an entry for this frequency in the cache create one
+ * and calculate the values
+ */
+ if (!regs) {
+ regs = devm_kzalloc(emif->dev, sizeof(*regs), GFP_ATOMIC);
+ if (!regs)
+ return NULL;
+
+ if (get_emif_reg_values(emif, freq, regs)) {
+ devm_kfree(emif->dev, regs);
+ return NULL;
+ }
+
+ /*
+ * Now look for an un-used entry in the cache and save the
+ * newly created struct. If there are no free entries
+ * over-write the last entry
+ */
+ for (i = 0; i < EMIF_MAX_NUM_FREQUENCIES && regs_cache[i]; i++)
+ ;
+
+ if (i >= EMIF_MAX_NUM_FREQUENCIES) {
+ dev_warn(dev, "%s: regs_cache full - reusing a slot!!\n",
+ __func__);
+ i = EMIF_MAX_NUM_FREQUENCIES - 1;
+ devm_kfree(emif->dev, regs_cache[i]);
+ }
+ regs_cache[i] = regs;
+ }
+
+ return regs;
+}
+
+static void do_volt_notify_handling(struct emif_data *emif, u32 volt_state)
+{
+ dev_dbg(emif->dev, "%s: voltage notification : %d", __func__,
+ volt_state);
+
+ if (!emif->curr_regs) {
+ dev_err(emif->dev,
+ "%s: volt-notify before registers are ready: %d\n",
+ __func__, volt_state);
+ return;
+ }
+
+ setup_volt_sensitive_regs(emif, emif->curr_regs, volt_state);
+}
+
+/*
+ * TODO: voltage notify handling should be hooked up to
+ * regulator framework as soon as the necessary support
+ * is available in mainline kernel. This function is un-used
+ * right now.
+ */
+static void __attribute__((unused)) volt_notify_handling(u32 volt_state)
+{
+ struct emif_data *emif;
+
+ spin_lock_irqsave(&emif_lock, irq_state);
+
+ list_for_each_entry(emif, &device_list, node)
+ do_volt_notify_handling(emif, volt_state);
+ do_freq_update();
+
+ spin_unlock_irqrestore(&emif_lock, irq_state);
+}
+
+static void do_freq_pre_notify_handling(struct emif_data *emif, u32 new_freq)
+{
+ struct emif_regs *regs;
+
+ regs = get_regs(emif, new_freq);
+ if (!regs)
+ return;
+
+ emif->curr_regs = regs;
+
+ /*
+ * Update the shadow registers:
+ * Temperature and voltage-ramp sensitive settings are also configured
+ * in terms of DDR cycles. So, we need to update them too when there
+ * is a freq change
+ */
+ dev_dbg(emif->dev, "%s: setting up shadow registers for %uHz",
+ __func__, new_freq);
+ setup_registers(emif, regs);
+ setup_temperature_sensitive_regs(emif, regs);
+ setup_volt_sensitive_regs(emif, regs, DDR_VOLTAGE_STABLE);
+
+ /*
+ * Part of workaround for errata i728. See do_freq_update()
+ * for more details
+ */
+ if (emif->lpmode == EMIF_LP_MODE_SELF_REFRESH)
+ set_lpmode(emif, EMIF_LP_MODE_DISABLE);
+}
+
+/*
+ * TODO: frequency notify handling should be hooked up to
+ * clock framework as soon as the necessary support is
+ * available in mainline kernel. This function is un-used
+ * right now.
+ */
+static void __attribute__((unused)) freq_pre_notify_handling(u32 new_freq)
+{
+ struct emif_data *emif;
+
+ /*
+ * NOTE: we are taking the spin-lock here and releases it
+ * only in post-notifier. This doesn't look good and
+ * Sparse complains about it, but this seems to be
+ * un-avoidable. We need to lock a sequence of events
+ * that is split between EMIF and clock framework.
+ *
+ * 1. EMIF driver updates EMIF timings in shadow registers in the
+ * frequency pre-notify callback from clock framework
+ * 2. clock framework sets up the registers for the new frequency
+ * 3. clock framework initiates a hw-sequence that updates
+ * the frequency EMIF timings synchronously.
+ *
+ * All these 3 steps should be performed as an atomic operation
+ * vis-a-vis similar sequence in the EMIF interrupt handler
+ * for temperature events. Otherwise, there could be race
+ * conditions that could result in incorrect EMIF timings for
+ * a given frequency
+ */
+ spin_lock_irqsave(&emif_lock, irq_state);
+
+ list_for_each_entry(emif, &device_list, node)
+ do_freq_pre_notify_handling(emif, new_freq);
+}
+
+static void do_freq_post_notify_handling(struct emif_data *emif)
+{
+ /*
+ * Part of workaround for errata i728. See do_freq_update()
+ * for more details
+ */
+ if (emif->lpmode == EMIF_LP_MODE_SELF_REFRESH)
+ set_lpmode(emif, EMIF_LP_MODE_SELF_REFRESH);
+}
+
+/*
+ * TODO: frequency notify handling should be hooked up to
+ * clock framework as soon as the necessary support is
+ * available in mainline kernel. This function is un-used
+ * right now.
+ */
+static void __attribute__((unused)) freq_post_notify_handling(void)
+{
+ struct emif_data *emif;
+
+ list_for_each_entry(emif, &device_list, node)
+ do_freq_post_notify_handling(emif);
+
+ /*
+ * Lock is done in pre-notify handler. See freq_pre_notify_handling()
+ * for more details
+ */
+ spin_unlock_irqrestore(&emif_lock, irq_state);
+}
+
+static struct platform_driver emif_driver = {
+ .remove = __exit_p(emif_remove),
+ .shutdown = emif_shutdown,
+ .driver = {
+ .name = "emif",
+ },
+};
+
+static int __init_or_module emif_register(void)
+{
+ return platform_driver_probe(&emif_driver, emif_probe);
+}
+
+static void __exit emif_unregister(void)
+{
+ platform_driver_unregister(&emif_driver);
+}
+
+module_init(emif_register);
+module_exit(emif_unregister);
+MODULE_DESCRIPTION("TI EMIF SDRAM Controller Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:emif");
+MODULE_AUTHOR("Texas Instruments Inc");
diff --git a/drivers/memory/emif.h b/drivers/memory/emif.h
new file mode 100644
index 000000000000..bfe08bae961a
--- /dev/null
+++ b/drivers/memory/emif.h
@@ -0,0 +1,589 @@
+/*
+ * Defines for the EMIF driver
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Benoit Cousson (b-cousson@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.
+ */
+#ifndef __EMIF_H
+#define __EMIF_H
+
+/*
+ * Maximum number of different frequencies supported by EMIF driver
+ * Determines the number of entries in the pointer array for register
+ * cache
+ */
+#define EMIF_MAX_NUM_FREQUENCIES 6
+
+/* State of the core voltage */
+#define DDR_VOLTAGE_STABLE 0
+#define DDR_VOLTAGE_RAMPING 1
+
+/* Defines for timing De-rating */
+#define EMIF_NORMAL_TIMINGS 0
+#define EMIF_DERATED_TIMINGS 1
+
+/* Length of the forced read idle period in terms of cycles */
+#define EMIF_READ_IDLE_LEN_VAL 5
+
+/*
+ * forced read idle interval to be used when voltage
+ * is changed as part of DVFS/DPS - 1ms
+ */
+#define READ_IDLE_INTERVAL_DVFS (1*1000000)
+
+/*
+ * Forced read idle interval to be used when voltage is stable
+ * 50us - or maximum value will do
+ */
+#define READ_IDLE_INTERVAL_NORMAL (50*1000000)
+
+/* DLL calibration interval when voltage is NOT stable - 1us */
+#define DLL_CALIB_INTERVAL_DVFS (1*1000000)
+
+#define DLL_CALIB_ACK_WAIT_VAL 5
+
+/* Interval between ZQCS commands - hw team recommended value */
+#define EMIF_ZQCS_INTERVAL_US (50*1000)
+/* Enable ZQ Calibration on exiting Self-refresh */
+#define ZQ_SFEXITEN_ENABLE 1
+/*
+ * ZQ Calibration simultaneously on both chip-selects:
+ * Needs one calibration resistor per CS
+ */
+#define ZQ_DUALCALEN_DISABLE 0
+#define ZQ_DUALCALEN_ENABLE 1
+
+#define T_ZQCS_DEFAULT_NS 90
+#define T_ZQCL_DEFAULT_NS 360
+#define T_ZQINIT_DEFAULT_NS 1000
+
+/* DPD_EN */
+#define DPD_DISABLE 0
+#define DPD_ENABLE 1
+
+/*
+ * Default values for the low-power entry to be used if not provided by user.
+ * OMAP4/5 has a hw bug(i735) due to which this value can not be less than 512
+ * Timeout values are in DDR clock 'cycles' and frequency threshold in Hz
+ */
+#define EMIF_LP_MODE_TIMEOUT_PERFORMANCE 2048
+#define EMIF_LP_MODE_TIMEOUT_POWER 512
+#define EMIF_LP_MODE_FREQ_THRESHOLD 400000000
+
+/* DDR_PHY_CTRL_1 values for EMIF4D - ATTILA PHY combination */
+#define EMIF_DDR_PHY_CTRL_1_BASE_VAL_ATTILAPHY 0x049FF000
+#define EMIF_DLL_SLAVE_DLY_CTRL_400_MHZ_ATTILAPHY 0x41
+#define EMIF_DLL_SLAVE_DLY_CTRL_200_MHZ_ATTILAPHY 0x80
+#define EMIF_DLL_SLAVE_DLY_CTRL_100_MHZ_AND_LESS_ATTILAPHY 0xFF
+
+/* DDR_PHY_CTRL_1 values for EMIF4D5 INTELLIPHY combination */
+#define EMIF_DDR_PHY_CTRL_1_BASE_VAL_INTELLIPHY 0x0E084200
+#define EMIF_PHY_TOTAL_READ_LATENCY_INTELLIPHY_PS 10000
+
+/* TEMP_ALERT_CONFIG - corresponding to temp gradient 5 C/s */
+#define TEMP_ALERT_POLL_INTERVAL_DEFAULT_MS 360
+
+#define EMIF_T_CSTA 3
+#define EMIF_T_PDLL_UL 128
+
+/* External PHY control registers magic values */
+#define EMIF_EXT_PHY_CTRL_1_VAL 0x04020080
+#define EMIF_EXT_PHY_CTRL_5_VAL 0x04010040
+#define EMIF_EXT_PHY_CTRL_6_VAL 0x01004010
+#define EMIF_EXT_PHY_CTRL_7_VAL 0x00001004
+#define EMIF_EXT_PHY_CTRL_8_VAL 0x04010040
+#define EMIF_EXT_PHY_CTRL_9_VAL 0x01004010
+#define EMIF_EXT_PHY_CTRL_10_VAL 0x00001004
+#define EMIF_EXT_PHY_CTRL_11_VAL 0x00000000
+#define EMIF_EXT_PHY_CTRL_12_VAL 0x00000000
+#define EMIF_EXT_PHY_CTRL_13_VAL 0x00000000
+#define EMIF_EXT_PHY_CTRL_14_VAL 0x80080080
+#define EMIF_EXT_PHY_CTRL_15_VAL 0x00800800
+#define EMIF_EXT_PHY_CTRL_16_VAL 0x08102040
+#define EMIF_EXT_PHY_CTRL_17_VAL 0x00000001
+#define EMIF_EXT_PHY_CTRL_18_VAL 0x540A8150
+#define EMIF_EXT_PHY_CTRL_19_VAL 0xA81502A0
+#define EMIF_EXT_PHY_CTRL_20_VAL 0x002A0540
+#define EMIF_EXT_PHY_CTRL_21_VAL 0x00000000
+#define EMIF_EXT_PHY_CTRL_22_VAL 0x00000000
+#define EMIF_EXT_PHY_CTRL_23_VAL 0x00000000
+#define EMIF_EXT_PHY_CTRL_24_VAL 0x00000077
+
+#define EMIF_INTELLI_PHY_DQS_GATE_OPENING_DELAY_PS 1200
+
+/* Registers offset */
+#define EMIF_MODULE_ID_AND_REVISION 0x0000
+#define EMIF_STATUS 0x0004
+#define EMIF_SDRAM_CONFIG 0x0008
+#define EMIF_SDRAM_CONFIG_2 0x000c
+#define EMIF_SDRAM_REFRESH_CONTROL 0x0010
+#define EMIF_SDRAM_REFRESH_CTRL_SHDW 0x0014
+#define EMIF_SDRAM_TIMING_1 0x0018
+#define EMIF_SDRAM_TIMING_1_SHDW 0x001c
+#define EMIF_SDRAM_TIMING_2 0x0020
+#define EMIF_SDRAM_TIMING_2_SHDW 0x0024
+#define EMIF_SDRAM_TIMING_3 0x0028
+#define EMIF_SDRAM_TIMING_3_SHDW 0x002c
+#define EMIF_LPDDR2_NVM_TIMING 0x0030
+#define EMIF_LPDDR2_NVM_TIMING_SHDW 0x0034
+#define EMIF_POWER_MANAGEMENT_CONTROL 0x0038
+#define EMIF_POWER_MANAGEMENT_CTRL_SHDW 0x003c
+#define EMIF_LPDDR2_MODE_REG_DATA 0x0040
+#define EMIF_LPDDR2_MODE_REG_CONFIG 0x0050
+#define EMIF_OCP_CONFIG 0x0054
+#define EMIF_OCP_CONFIG_VALUE_1 0x0058
+#define EMIF_OCP_CONFIG_VALUE_2 0x005c
+#define EMIF_IODFT_TEST_LOGIC_GLOBAL_CONTROL 0x0060
+#define EMIF_IODFT_TEST_LOGIC_CTRL_MISR_RESULT 0x0064
+#define EMIF_IODFT_TEST_LOGIC_ADDRESS_MISR_RESULT 0x0068
+#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_1 0x006c
+#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_2 0x0070
+#define EMIF_IODFT_TEST_LOGIC_DATA_MISR_RESULT_3 0x0074
+#define EMIF_PERFORMANCE_COUNTER_1 0x0080
+#define EMIF_PERFORMANCE_COUNTER_2 0x0084
+#define EMIF_PERFORMANCE_COUNTER_CONFIG 0x0088
+#define EMIF_PERFORMANCE_COUNTER_MASTER_REGION_SELECT 0x008c
+#define EMIF_PERFORMANCE_COUNTER_TIME 0x0090
+#define EMIF_MISC_REG 0x0094
+#define EMIF_DLL_CALIB_CTRL 0x0098
+#define EMIF_DLL_CALIB_CTRL_SHDW 0x009c
+#define EMIF_END_OF_INTERRUPT 0x00a0
+#define EMIF_SYSTEM_OCP_INTERRUPT_RAW_STATUS 0x00a4
+#define EMIF_LL_OCP_INTERRUPT_RAW_STATUS 0x00a8
+#define EMIF_SYSTEM_OCP_INTERRUPT_STATUS 0x00ac
+#define EMIF_LL_OCP_INTERRUPT_STATUS 0x00b0
+#define EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_SET 0x00b4
+#define EMIF_LL_OCP_INTERRUPT_ENABLE_SET 0x00b8
+#define EMIF_SYSTEM_OCP_INTERRUPT_ENABLE_CLEAR 0x00bc
+#define EMIF_LL_OCP_INTERRUPT_ENABLE_CLEAR 0x00c0
+#define EMIF_SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG 0x00c8
+#define EMIF_TEMPERATURE_ALERT_CONFIG 0x00cc
+#define EMIF_OCP_ERROR_LOG 0x00d0
+#define EMIF_READ_WRITE_LEVELING_RAMP_WINDOW 0x00d4
+#define EMIF_READ_WRITE_LEVELING_RAMP_CONTROL 0x00d8
+#define EMIF_READ_WRITE_LEVELING_CONTROL 0x00dc
+#define EMIF_DDR_PHY_CTRL_1 0x00e4
+#define EMIF_DDR_PHY_CTRL_1_SHDW 0x00e8
+#define EMIF_DDR_PHY_CTRL_2 0x00ec
+#define EMIF_PRIORITY_TO_CLASS_OF_SERVICE_MAPPING 0x0100
+#define EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_1_MAPPING 0x0104
+#define EMIF_CONNECTION_ID_TO_CLASS_OF_SERVICE_2_MAPPING 0x0108
+#define EMIF_READ_WRITE_EXECUTION_THRESHOLD 0x0120
+#define EMIF_COS_CONFIG 0x0124
+#define EMIF_PHY_STATUS_1 0x0140
+#define EMIF_PHY_STATUS_2 0x0144
+#define EMIF_PHY_STATUS_3 0x0148
+#define EMIF_PHY_STATUS_4 0x014c
+#define EMIF_PHY_STATUS_5 0x0150
+#define EMIF_PHY_STATUS_6 0x0154
+#define EMIF_PHY_STATUS_7 0x0158
+#define EMIF_PHY_STATUS_8 0x015c
+#define EMIF_PHY_STATUS_9 0x0160
+#define EMIF_PHY_STATUS_10 0x0164
+#define EMIF_PHY_STATUS_11 0x0168
+#define EMIF_PHY_STATUS_12 0x016c
+#define EMIF_PHY_STATUS_13 0x0170
+#define EMIF_PHY_STATUS_14 0x0174
+#define EMIF_PHY_STATUS_15 0x0178
+#define EMIF_PHY_STATUS_16 0x017c
+#define EMIF_PHY_STATUS_17 0x0180
+#define EMIF_PHY_STATUS_18 0x0184
+#define EMIF_PHY_STATUS_19 0x0188
+#define EMIF_PHY_STATUS_20 0x018c
+#define EMIF_PHY_STATUS_21 0x0190
+#define EMIF_EXT_PHY_CTRL_1 0x0200
+#define EMIF_EXT_PHY_CTRL_1_SHDW 0x0204
+#define EMIF_EXT_PHY_CTRL_2 0x0208
+#define EMIF_EXT_PHY_CTRL_2_SHDW 0x020c
+#define EMIF_EXT_PHY_CTRL_3 0x0210
+#define EMIF_EXT_PHY_CTRL_3_SHDW 0x0214
+#define EMIF_EXT_PHY_CTRL_4 0x0218
+#define EMIF_EXT_PHY_CTRL_4_SHDW 0x021c
+#define EMIF_EXT_PHY_CTRL_5 0x0220
+#define EMIF_EXT_PHY_CTRL_5_SHDW 0x0224
+#define EMIF_EXT_PHY_CTRL_6 0x0228
+#define EMIF_EXT_PHY_CTRL_6_SHDW 0x022c
+#define EMIF_EXT_PHY_CTRL_7 0x0230
+#define EMIF_EXT_PHY_CTRL_7_SHDW 0x0234
+#define EMIF_EXT_PHY_CTRL_8 0x0238
+#define EMIF_EXT_PHY_CTRL_8_SHDW 0x023c
+#define EMIF_EXT_PHY_CTRL_9 0x0240
+#define EMIF_EXT_PHY_CTRL_9_SHDW 0x0244
+#define EMIF_EXT_PHY_CTRL_10 0x0248
+#define EMIF_EXT_PHY_CTRL_10_SHDW 0x024c
+#define EMIF_EXT_PHY_CTRL_11 0x0250
+#define EMIF_EXT_PHY_CTRL_11_SHDW 0x0254
+#define EMIF_EXT_PHY_CTRL_12 0x0258
+#define EMIF_EXT_PHY_CTRL_12_SHDW 0x025c
+#define EMIF_EXT_PHY_CTRL_13 0x0260
+#define EMIF_EXT_PHY_CTRL_13_SHDW 0x0264
+#define EMIF_EXT_PHY_CTRL_14 0x0268
+#define EMIF_EXT_PHY_CTRL_14_SHDW 0x026c
+#define EMIF_EXT_PHY_CTRL_15 0x0270
+#define EMIF_EXT_PHY_CTRL_15_SHDW 0x0274
+#define EMIF_EXT_PHY_CTRL_16 0x0278
+#define EMIF_EXT_PHY_CTRL_16_SHDW 0x027c
+#define EMIF_EXT_PHY_CTRL_17 0x0280
+#define EMIF_EXT_PHY_CTRL_17_SHDW 0x0284
+#define EMIF_EXT_PHY_CTRL_18 0x0288
+#define EMIF_EXT_PHY_CTRL_18_SHDW 0x028c
+#define EMIF_EXT_PHY_CTRL_19 0x0290
+#define EMIF_EXT_PHY_CTRL_19_SHDW 0x0294
+#define EMIF_EXT_PHY_CTRL_20 0x0298
+#define EMIF_EXT_PHY_CTRL_20_SHDW 0x029c
+#define EMIF_EXT_PHY_CTRL_21 0x02a0
+#define EMIF_EXT_PHY_CTRL_21_SHDW 0x02a4
+#define EMIF_EXT_PHY_CTRL_22 0x02a8
+#define EMIF_EXT_PHY_CTRL_22_SHDW 0x02ac
+#define EMIF_EXT_PHY_CTRL_23 0x02b0
+#define EMIF_EXT_PHY_CTRL_23_SHDW 0x02b4
+#define EMIF_EXT_PHY_CTRL_24 0x02b8
+#define EMIF_EXT_PHY_CTRL_24_SHDW 0x02bc
+#define EMIF_EXT_PHY_CTRL_25 0x02c0
+#define EMIF_EXT_PHY_CTRL_25_SHDW 0x02c4
+#define EMIF_EXT_PHY_CTRL_26 0x02c8
+#define EMIF_EXT_PHY_CTRL_26_SHDW 0x02cc
+#define EMIF_EXT_PHY_CTRL_27 0x02d0
+#define EMIF_EXT_PHY_CTRL_27_SHDW 0x02d4
+#define EMIF_EXT_PHY_CTRL_28 0x02d8
+#define EMIF_EXT_PHY_CTRL_28_SHDW 0x02dc
+#define EMIF_EXT_PHY_CTRL_29 0x02e0
+#define EMIF_EXT_PHY_CTRL_29_SHDW 0x02e4
+#define EMIF_EXT_PHY_CTRL_30 0x02e8
+#define EMIF_EXT_PHY_CTRL_30_SHDW 0x02ec
+
+/* Registers shifts and masks */
+
+/* EMIF_MODULE_ID_AND_REVISION */
+#define SCHEME_SHIFT 30
+#define SCHEME_MASK (0x3 << 30)
+#define MODULE_ID_SHIFT 16
+#define MODULE_ID_MASK (0xfff << 16)
+#define RTL_VERSION_SHIFT 11
+#define RTL_VERSION_MASK (0x1f << 11)
+#define MAJOR_REVISION_SHIFT 8
+#define MAJOR_REVISION_MASK (0x7 << 8)
+#define MINOR_REVISION_SHIFT 0
+#define MINOR_REVISION_MASK (0x3f << 0)
+
+/* STATUS */
+#define BE_SHIFT 31
+#define BE_MASK (1 << 31)
+#define DUAL_CLK_MODE_SHIFT 30
+#define DUAL_CLK_MODE_MASK (1 << 30)
+#define FAST_INIT_SHIFT 29
+#define FAST_INIT_MASK (1 << 29)
+#define RDLVLGATETO_SHIFT 6
+#define RDLVLGATETO_MASK (1 << 6)
+#define RDLVLTO_SHIFT 5
+#define RDLVLTO_MASK (1 << 5)
+#define WRLVLTO_SHIFT 4
+#define WRLVLTO_MASK (1 << 4)
+#define PHY_DLL_READY_SHIFT 2
+#define PHY_DLL_READY_MASK (1 << 2)
+
+/* SDRAM_CONFIG */
+#define SDRAM_TYPE_SHIFT 29
+#define SDRAM_TYPE_MASK (0x7 << 29)
+#define IBANK_POS_SHIFT 27
+#define IBANK_POS_MASK (0x3 << 27)
+#define DDR_TERM_SHIFT 24
+#define DDR_TERM_MASK (0x7 << 24)
+#define DDR2_DDQS_SHIFT 23
+#define DDR2_DDQS_MASK (1 << 23)
+#define DYN_ODT_SHIFT 21
+#define DYN_ODT_MASK (0x3 << 21)
+#define DDR_DISABLE_DLL_SHIFT 20
+#define DDR_DISABLE_DLL_MASK (1 << 20)
+#define SDRAM_DRIVE_SHIFT 18
+#define SDRAM_DRIVE_MASK (0x3 << 18)
+#define CWL_SHIFT 16
+#define CWL_MASK (0x3 << 16)
+#define NARROW_MODE_SHIFT 14
+#define NARROW_MODE_MASK (0x3 << 14)
+#define CL_SHIFT 10
+#define CL_MASK (0xf << 10)
+#define ROWSIZE_SHIFT 7
+#define ROWSIZE_MASK (0x7 << 7)
+#define IBANK_SHIFT 4
+#define IBANK_MASK (0x7 << 4)
+#define EBANK_SHIFT 3
+#define EBANK_MASK (1 << 3)
+#define PAGESIZE_SHIFT 0
+#define PAGESIZE_MASK (0x7 << 0)
+
+/* SDRAM_CONFIG_2 */
+#define CS1NVMEN_SHIFT 30
+#define CS1NVMEN_MASK (1 << 30)
+#define EBANK_POS_SHIFT 27
+#define EBANK_POS_MASK (1 << 27)
+#define RDBNUM_SHIFT 4
+#define RDBNUM_MASK (0x3 << 4)
+#define RDBSIZE_SHIFT 0
+#define RDBSIZE_MASK (0x7 << 0)
+
+/* SDRAM_REFRESH_CONTROL */
+#define INITREF_DIS_SHIFT 31
+#define INITREF_DIS_MASK (1 << 31)
+#define SRT_SHIFT 29
+#define SRT_MASK (1 << 29)
+#define ASR_SHIFT 28
+#define ASR_MASK (1 << 28)
+#define PASR_SHIFT 24
+#define PASR_MASK (0x7 << 24)
+#define REFRESH_RATE_SHIFT 0
+#define REFRESH_RATE_MASK (0xffff << 0)
+
+/* SDRAM_TIMING_1 */
+#define T_RTW_SHIFT 29
+#define T_RTW_MASK (0x7 << 29)
+#define T_RP_SHIFT 25
+#define T_RP_MASK (0xf << 25)
+#define T_RCD_SHIFT 21
+#define T_RCD_MASK (0xf << 21)
+#define T_WR_SHIFT 17
+#define T_WR_MASK (0xf << 17)
+#define T_RAS_SHIFT 12
+#define T_RAS_MASK (0x1f << 12)
+#define T_RC_SHIFT 6
+#define T_RC_MASK (0x3f << 6)
+#define T_RRD_SHIFT 3
+#define T_RRD_MASK (0x7 << 3)
+#define T_WTR_SHIFT 0
+#define T_WTR_MASK (0x7 << 0)
+
+/* SDRAM_TIMING_2 */
+#define T_XP_SHIFT 28
+#define T_XP_MASK (0x7 << 28)
+#define T_ODT_SHIFT 25
+#define T_ODT_MASK (0x7 << 25)
+#define T_XSNR_SHIFT 16
+#define T_XSNR_MASK (0x1ff << 16)
+#define T_XSRD_SHIFT 6
+#define T_XSRD_MASK (0x3ff << 6)
+#define T_RTP_SHIFT 3
+#define T_RTP_MASK (0x7 << 3)
+#define T_CKE_SHIFT 0
+#define T_CKE_MASK (0x7 << 0)
+
+/* SDRAM_TIMING_3 */
+#define T_PDLL_UL_SHIFT 28
+#define T_PDLL_UL_MASK (0xf << 28)
+#define T_CSTA_SHIFT 24
+#define T_CSTA_MASK (0xf << 24)
+#define T_CKESR_SHIFT 21
+#define T_CKESR_MASK (0x7 << 21)
+#define ZQ_ZQCS_SHIFT 15
+#define ZQ_ZQCS_MASK (0x3f << 15)
+#define T_TDQSCKMAX_SHIFT 13
+#define T_TDQSCKMAX_MASK (0x3 << 13)
+#define T_RFC_SHIFT 4
+#define T_RFC_MASK (0x1ff << 4)
+#define T_RAS_MAX_SHIFT 0
+#define T_RAS_MAX_MASK (0xf << 0)
+
+/* POWER_MANAGEMENT_CONTROL */
+#define PD_TIM_SHIFT 12
+#define PD_TIM_MASK (0xf << 12)
+#define DPD_EN_SHIFT 11
+#define DPD_EN_MASK (1 << 11)
+#define LP_MODE_SHIFT 8
+#define LP_MODE_MASK (0x7 << 8)
+#define SR_TIM_SHIFT 4
+#define SR_TIM_MASK (0xf << 4)
+#define CS_TIM_SHIFT 0
+#define CS_TIM_MASK (0xf << 0)
+
+/* LPDDR2_MODE_REG_DATA */
+#define VALUE_0_SHIFT 0
+#define VALUE_0_MASK (0x7f << 0)
+
+/* LPDDR2_MODE_REG_CONFIG */
+#define CS_SHIFT 31
+#define CS_MASK (1 << 31)
+#define REFRESH_EN_SHIFT 30
+#define REFRESH_EN_MASK (1 << 30)
+#define ADDRESS_SHIFT 0
+#define ADDRESS_MASK (0xff << 0)
+
+/* OCP_CONFIG */
+#define SYS_THRESH_MAX_SHIFT 24
+#define SYS_THRESH_MAX_MASK (0xf << 24)
+#define MPU_THRESH_MAX_SHIFT 20
+#define MPU_THRESH_MAX_MASK (0xf << 20)
+#define LL_THRESH_MAX_SHIFT 16
+#define LL_THRESH_MAX_MASK (0xf << 16)
+
+/* PERFORMANCE_COUNTER_1 */
+#define COUNTER1_SHIFT 0
+#define COUNTER1_MASK (0xffffffff << 0)
+
+/* PERFORMANCE_COUNTER_2 */
+#define COUNTER2_SHIFT 0
+#define COUNTER2_MASK (0xffffffff << 0)
+
+/* PERFORMANCE_COUNTER_CONFIG */
+#define CNTR2_MCONNID_EN_SHIFT 31
+#define CNTR2_MCONNID_EN_MASK (1 << 31)
+#define CNTR2_REGION_EN_SHIFT 30
+#define CNTR2_REGION_EN_MASK (1 << 30)
+#define CNTR2_CFG_SHIFT 16
+#define CNTR2_CFG_MASK (0xf << 16)
+#define CNTR1_MCONNID_EN_SHIFT 15
+#define CNTR1_MCONNID_EN_MASK (1 << 15)
+#define CNTR1_REGION_EN_SHIFT 14
+#define CNTR1_REGION_EN_MASK (1 << 14)
+#define CNTR1_CFG_SHIFT 0
+#define CNTR1_CFG_MASK (0xf << 0)
+
+/* PERFORMANCE_COUNTER_MASTER_REGION_SELECT */
+#define MCONNID2_SHIFT 24
+#define MCONNID2_MASK (0xff << 24)
+#define REGION_SEL2_SHIFT 16
+#define REGION_SEL2_MASK (0x3 << 16)
+#define MCONNID1_SHIFT 8
+#define MCONNID1_MASK (0xff << 8)
+#define REGION_SEL1_SHIFT 0
+#define REGION_SEL1_MASK (0x3 << 0)
+
+/* PERFORMANCE_COUNTER_TIME */
+#define TOTAL_TIME_SHIFT 0
+#define TOTAL_TIME_MASK (0xffffffff << 0)
+
+/* DLL_CALIB_CTRL */
+#define ACK_WAIT_SHIFT 16
+#define ACK_WAIT_MASK (0xf << 16)
+#define DLL_CALIB_INTERVAL_SHIFT 0
+#define DLL_CALIB_INTERVAL_MASK (0x1ff << 0)
+
+/* END_OF_INTERRUPT */
+#define EOI_SHIFT 0
+#define EOI_MASK (1 << 0)
+
+/* SYSTEM_OCP_INTERRUPT_RAW_STATUS */
+#define DNV_SYS_SHIFT 2
+#define DNV_SYS_MASK (1 << 2)
+#define TA_SYS_SHIFT 1
+#define TA_SYS_MASK (1 << 1)
+#define ERR_SYS_SHIFT 0
+#define ERR_SYS_MASK (1 << 0)
+
+/* LOW_LATENCY_OCP_INTERRUPT_RAW_STATUS */
+#define DNV_LL_SHIFT 2
+#define DNV_LL_MASK (1 << 2)
+#define TA_LL_SHIFT 1
+#define TA_LL_MASK (1 << 1)
+#define ERR_LL_SHIFT 0
+#define ERR_LL_MASK (1 << 0)
+
+/* SYSTEM_OCP_INTERRUPT_ENABLE_SET */
+#define EN_DNV_SYS_SHIFT 2
+#define EN_DNV_SYS_MASK (1 << 2)
+#define EN_TA_SYS_SHIFT 1
+#define EN_TA_SYS_MASK (1 << 1)
+#define EN_ERR_SYS_SHIFT 0
+#define EN_ERR_SYS_MASK (1 << 0)
+
+/* LOW_LATENCY_OCP_INTERRUPT_ENABLE_SET */
+#define EN_DNV_LL_SHIFT 2
+#define EN_DNV_LL_MASK (1 << 2)
+#define EN_TA_LL_SHIFT 1
+#define EN_TA_LL_MASK (1 << 1)
+#define EN_ERR_LL_SHIFT 0
+#define EN_ERR_LL_MASK (1 << 0)
+
+/* SDRAM_OUTPUT_IMPEDANCE_CALIBRATION_CONFIG */
+#define ZQ_CS1EN_SHIFT 31
+#define ZQ_CS1EN_MASK (1 << 31)
+#define ZQ_CS0EN_SHIFT 30
+#define ZQ_CS0EN_MASK (1 << 30)
+#define ZQ_DUALCALEN_SHIFT 29
+#define ZQ_DUALCALEN_MASK (1 << 29)
+#define ZQ_SFEXITEN_SHIFT 28
+#define ZQ_SFEXITEN_MASK (1 << 28)
+#define ZQ_ZQINIT_MULT_SHIFT 18
+#define ZQ_ZQINIT_MULT_MASK (0x3 << 18)
+#define ZQ_ZQCL_MULT_SHIFT 16
+#define ZQ_ZQCL_MULT_MASK (0x3 << 16)
+#define ZQ_REFINTERVAL_SHIFT 0
+#define ZQ_REFINTERVAL_MASK (0xffff << 0)
+
+/* TEMPERATURE_ALERT_CONFIG */
+#define TA_CS1EN_SHIFT 31
+#define TA_CS1EN_MASK (1 << 31)
+#define TA_CS0EN_SHIFT 30
+#define TA_CS0EN_MASK (1 << 30)
+#define TA_SFEXITEN_SHIFT 28
+#define TA_SFEXITEN_MASK (1 << 28)
+#define TA_DEVWDT_SHIFT 26
+#define TA_DEVWDT_MASK (0x3 << 26)
+#define TA_DEVCNT_SHIFT 24
+#define TA_DEVCNT_MASK (0x3 << 24)
+#define TA_REFINTERVAL_SHIFT 0
+#define TA_REFINTERVAL_MASK (0x3fffff << 0)
+
+/* OCP_ERROR_LOG */
+#define MADDRSPACE_SHIFT 14
+#define MADDRSPACE_MASK (0x3 << 14)
+#define MBURSTSEQ_SHIFT 11
+#define MBURSTSEQ_MASK (0x7 << 11)
+#define MCMD_SHIFT 8
+#define MCMD_MASK (0x7 << 8)
+#define MCONNID_SHIFT 0
+#define MCONNID_MASK (0xff << 0)
+
+/* DDR_PHY_CTRL_1 - EMIF4D */
+#define DLL_SLAVE_DLY_CTRL_SHIFT_4D 4
+#define DLL_SLAVE_DLY_CTRL_MASK_4D (0xFF << 4)
+#define READ_LATENCY_SHIFT_4D 0
+#define READ_LATENCY_MASK_4D (0xf << 0)
+
+/* DDR_PHY_CTRL_1 - EMIF4D5 */
+#define DLL_HALF_DELAY_SHIFT_4D5 21
+#define DLL_HALF_DELAY_MASK_4D5 (1 << 21)
+#define READ_LATENCY_SHIFT_4D5 0
+#define READ_LATENCY_MASK_4D5 (0x1f << 0)
+
+/* DDR_PHY_CTRL_1_SHDW */
+#define DDR_PHY_CTRL_1_SHDW_SHIFT 5
+#define DDR_PHY_CTRL_1_SHDW_MASK (0x7ffffff << 5)
+#define READ_LATENCY_SHDW_SHIFT 0
+#define READ_LATENCY_SHDW_MASK (0x1f << 0)
+
+#ifndef __ASSEMBLY__
+/*
+ * Structure containing shadow of important registers in EMIF
+ * The calculation function fills in this structure to be later used for
+ * initialisation and DVFS
+ */
+struct emif_regs {
+ u32 freq;
+ u32 ref_ctrl_shdw;
+ u32 ref_ctrl_shdw_derated;
+ u32 sdram_tim1_shdw;
+ u32 sdram_tim1_shdw_derated;
+ u32 sdram_tim2_shdw;
+ u32 sdram_tim3_shdw;
+ u32 sdram_tim3_shdw_derated;
+ u32 pwr_mgmt_ctrl_shdw;
+ union {
+ u32 read_idle_ctrl_shdw_normal;
+ u32 dll_calib_ctrl_shdw_normal;
+ };
+ union {
+ u32 read_idle_ctrl_shdw_volt_ramp;
+ u32 dll_calib_ctrl_shdw_volt_ramp;
+ };
+
+ u32 phy_ctrl_1_shdw;
+ u32 ext_phy_ctrl_2_shdw;
+ u32 ext_phy_ctrl_3_shdw;
+ u32 ext_phy_ctrl_4_shdw;
+};
+#endif /* __ASSEMBLY__ */
+#endif /* __EMIF_H */
diff --git a/drivers/memory/tegra20-mc.c b/drivers/memory/tegra20-mc.c
new file mode 100644
index 000000000000..3ed49c1c2b91
--- /dev/null
+++ b/drivers/memory/tegra20-mc.c
@@ -0,0 +1,257 @@
+/*
+ * Tegra20 Memory Controller
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ratelimit.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#define DRV_NAME "tegra20-mc"
+
+#define MC_INTSTATUS 0x0
+#define MC_INTMASK 0x4
+
+#define MC_INT_ERR_SHIFT 6
+#define MC_INT_ERR_MASK (0x1f << MC_INT_ERR_SHIFT)
+#define MC_INT_DECERR_EMEM BIT(MC_INT_ERR_SHIFT)
+#define MC_INT_INVALID_GART_PAGE BIT(MC_INT_ERR_SHIFT + 1)
+#define MC_INT_SECURITY_VIOLATION BIT(MC_INT_ERR_SHIFT + 2)
+#define MC_INT_ARBITRATION_EMEM BIT(MC_INT_ERR_SHIFT + 3)
+
+#define MC_GART_ERROR_REQ 0x30
+#define MC_DECERR_EMEM_OTHERS_STATUS 0x58
+#define MC_SECURITY_VIOLATION_STATUS 0x74
+
+#define SECURITY_VIOLATION_TYPE BIT(30) /* 0=TRUSTZONE, 1=CARVEOUT */
+
+#define MC_CLIENT_ID_MASK 0x3f
+
+#define NUM_MC_REG_BANKS 2
+
+struct tegra20_mc {
+ void __iomem *regs[NUM_MC_REG_BANKS];
+ struct device *dev;
+};
+
+static inline u32 mc_readl(struct tegra20_mc *mc, u32 offs)
+{
+ u32 val = 0;
+
+ if (offs < 0x24)
+ val = readl(mc->regs[0] + offs);
+ if (offs < 0x400)
+ val = readl(mc->regs[1] + offs - 0x3c);
+
+ return val;
+}
+
+static inline void mc_writel(struct tegra20_mc *mc, u32 val, u32 offs)
+{
+ if (offs < 0x24) {
+ writel(val, mc->regs[0] + offs);
+ return;
+ }
+ if (offs < 0x400) {
+ writel(val, mc->regs[1] + offs - 0x3c);
+ return;
+ }
+}
+
+static const char * const tegra20_mc_client[] = {
+ "cbr_display0a",
+ "cbr_display0ab",
+ "cbr_display0b",
+ "cbr_display0bb",
+ "cbr_display0c",
+ "cbr_display0cb",
+ "cbr_display1b",
+ "cbr_display1bb",
+ "cbr_eppup",
+ "cbr_g2pr",
+ "cbr_g2sr",
+ "cbr_mpeunifbr",
+ "cbr_viruv",
+ "csr_avpcarm7r",
+ "csr_displayhc",
+ "csr_displayhcb",
+ "csr_fdcdrd",
+ "csr_g2dr",
+ "csr_host1xdmar",
+ "csr_host1xr",
+ "csr_idxsrd",
+ "csr_mpcorer",
+ "csr_mpe_ipred",
+ "csr_mpeamemrd",
+ "csr_mpecsrd",
+ "csr_ppcsahbdmar",
+ "csr_ppcsahbslvr",
+ "csr_texsrd",
+ "csr_vdebsevr",
+ "csr_vdember",
+ "csr_vdemcer",
+ "csr_vdetper",
+ "cbw_eppu",
+ "cbw_eppv",
+ "cbw_eppy",
+ "cbw_mpeunifbw",
+ "cbw_viwsb",
+ "cbw_viwu",
+ "cbw_viwv",
+ "cbw_viwy",
+ "ccw_g2dw",
+ "csw_avpcarm7w",
+ "csw_fdcdwr",
+ "csw_host1xw",
+ "csw_ispw",
+ "csw_mpcorew",
+ "csw_mpecswr",
+ "csw_ppcsahbdmaw",
+ "csw_ppcsahbslvw",
+ "csw_vdebsevw",
+ "csw_vdembew",
+ "csw_vdetpmw",
+};
+
+static void tegra20_mc_decode(struct tegra20_mc *mc, int n)
+{
+ u32 addr, req;
+ const char *client = "Unknown";
+ int idx, cid;
+ const struct reg_info {
+ u32 offset;
+ u32 write_bit; /* 0=READ, 1=WRITE */
+ int cid_shift;
+ char *message;
+ } reg[] = {
+ {
+ .offset = MC_DECERR_EMEM_OTHERS_STATUS,
+ .write_bit = 31,
+ .message = "MC_DECERR",
+ },
+ {
+ .offset = MC_GART_ERROR_REQ,
+ .cid_shift = 1,
+ .message = "MC_GART_ERR",
+
+ },
+ {
+ .offset = MC_SECURITY_VIOLATION_STATUS,
+ .write_bit = 31,
+ .message = "MC_SECURITY_ERR",
+ },
+ };
+
+ idx = n - MC_INT_ERR_SHIFT;
+ if ((idx < 0) || (idx >= ARRAY_SIZE(reg))) {
+ dev_err_ratelimited(mc->dev, "Unknown interrupt status %08lx\n",
+ BIT(n));
+ return;
+ }
+
+ req = mc_readl(mc, reg[idx].offset);
+ cid = (req >> reg[idx].cid_shift) & MC_CLIENT_ID_MASK;
+ if (cid < ARRAY_SIZE(tegra20_mc_client))
+ client = tegra20_mc_client[cid];
+
+ addr = mc_readl(mc, reg[idx].offset + sizeof(u32));
+
+ dev_err_ratelimited(mc->dev, "%s (0x%08x): 0x%08x %s (%s %s)\n",
+ reg[idx].message, req, addr, client,
+ (req & BIT(reg[idx].write_bit)) ? "write" : "read",
+ (reg[idx].offset == MC_SECURITY_VIOLATION_STATUS) ?
+ ((req & SECURITY_VIOLATION_TYPE) ?
+ "carveout" : "trustzone") : "");
+}
+
+static const struct of_device_id tegra20_mc_of_match[] __devinitconst = {
+ { .compatible = "nvidia,tegra20-mc", },
+ {},
+};
+
+static irqreturn_t tegra20_mc_isr(int irq, void *data)
+{
+ u32 stat, mask, bit;
+ struct tegra20_mc *mc = data;
+
+ stat = mc_readl(mc, MC_INTSTATUS);
+ mask = mc_readl(mc, MC_INTMASK);
+ mask &= stat;
+ if (!mask)
+ return IRQ_NONE;
+ while ((bit = ffs(mask)) != 0)
+ tegra20_mc_decode(mc, bit - 1);
+ mc_writel(mc, stat, MC_INTSTATUS);
+ return IRQ_HANDLED;
+}
+
+static int __devinit tegra20_mc_probe(struct platform_device *pdev)
+{
+ struct resource *irq;
+ struct tegra20_mc *mc;
+ int i, err;
+ u32 intmask;
+
+ mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL);
+ if (!mc)
+ return -ENOMEM;
+ mc->dev = &pdev->dev;
+
+ for (i = 0; i < ARRAY_SIZE(mc->regs); i++) {
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ if (!res)
+ return -ENODEV;
+ mc->regs[i] = devm_request_and_ioremap(&pdev->dev, res);
+ if (!mc->regs[i])
+ return -EBUSY;
+ }
+
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq)
+ return -ENODEV;
+ err = devm_request_irq(&pdev->dev, irq->start, tegra20_mc_isr,
+ IRQF_SHARED, dev_name(&pdev->dev), mc);
+ if (err)
+ return -ENODEV;
+
+ platform_set_drvdata(pdev, mc);
+
+ intmask = MC_INT_INVALID_GART_PAGE |
+ MC_INT_DECERR_EMEM | MC_INT_SECURITY_VIOLATION;
+ mc_writel(mc, intmask, MC_INTMASK);
+ return 0;
+}
+
+static struct platform_driver tegra20_mc_driver = {
+ .probe = tegra20_mc_probe,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = tegra20_mc_of_match,
+ },
+};
+module_platform_driver(tegra20_mc_driver);
+
+MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>");
+MODULE_DESCRIPTION("Tegra20 MC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/memory/tegra30-mc.c b/drivers/memory/tegra30-mc.c
new file mode 100644
index 000000000000..e56ff04eb5cc
--- /dev/null
+++ b/drivers/memory/tegra30-mc.c
@@ -0,0 +1,382 @@
+/*
+ * Tegra30 Memory Controller
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ratelimit.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#define DRV_NAME "tegra30-mc"
+
+#define MC_INTSTATUS 0x0
+#define MC_INTMASK 0x4
+
+#define MC_INT_ERR_SHIFT 6
+#define MC_INT_ERR_MASK (0x1f << MC_INT_ERR_SHIFT)
+#define MC_INT_DECERR_EMEM BIT(MC_INT_ERR_SHIFT)
+#define MC_INT_SECURITY_VIOLATION BIT(MC_INT_ERR_SHIFT + 2)
+#define MC_INT_ARBITRATION_EMEM BIT(MC_INT_ERR_SHIFT + 3)
+#define MC_INT_INVALID_SMMU_PAGE BIT(MC_INT_ERR_SHIFT + 4)
+
+#define MC_ERR_STATUS 0x8
+#define MC_ERR_ADR 0xc
+
+#define MC_ERR_TYPE_SHIFT 28
+#define MC_ERR_TYPE_MASK (7 << MC_ERR_TYPE_SHIFT)
+#define MC_ERR_TYPE_DECERR_EMEM 2
+#define MC_ERR_TYPE_SECURITY_TRUSTZONE 3
+#define MC_ERR_TYPE_SECURITY_CARVEOUT 4
+#define MC_ERR_TYPE_INVALID_SMMU_PAGE 6
+
+#define MC_ERR_INVALID_SMMU_PAGE_SHIFT 25
+#define MC_ERR_INVALID_SMMU_PAGE_MASK (7 << MC_ERR_INVALID_SMMU_PAGE_SHIFT)
+#define MC_ERR_RW_SHIFT 16
+#define MC_ERR_RW BIT(MC_ERR_RW_SHIFT)
+#define MC_ERR_SECURITY BIT(MC_ERR_RW_SHIFT + 1)
+
+#define SECURITY_VIOLATION_TYPE BIT(30) /* 0=TRUSTZONE, 1=CARVEOUT */
+
+#define MC_EMEM_ARB_CFG 0x90
+#define MC_EMEM_ARB_OUTSTANDING_REQ 0x94
+#define MC_EMEM_ARB_TIMING_RCD 0x98
+#define MC_EMEM_ARB_TIMING_RP 0x9c
+#define MC_EMEM_ARB_TIMING_RC 0xa0
+#define MC_EMEM_ARB_TIMING_RAS 0xa4
+#define MC_EMEM_ARB_TIMING_FAW 0xa8
+#define MC_EMEM_ARB_TIMING_RRD 0xac
+#define MC_EMEM_ARB_TIMING_RAP2PRE 0xb0
+#define MC_EMEM_ARB_TIMING_WAP2PRE 0xb4
+#define MC_EMEM_ARB_TIMING_R2R 0xb8
+#define MC_EMEM_ARB_TIMING_W2W 0xbc
+#define MC_EMEM_ARB_TIMING_R2W 0xc0
+#define MC_EMEM_ARB_TIMING_W2R 0xc4
+
+#define MC_EMEM_ARB_DA_TURNS 0xd0
+#define MC_EMEM_ARB_DA_COVERS 0xd4
+#define MC_EMEM_ARB_MISC0 0xd8
+#define MC_EMEM_ARB_MISC1 0xdc
+
+#define MC_EMEM_ARB_RING3_THROTTLE 0xe4
+#define MC_EMEM_ARB_OVERRIDE 0xe8
+
+#define MC_TIMING_CONTROL 0xfc
+
+#define MC_CLIENT_ID_MASK 0x7f
+
+#define NUM_MC_REG_BANKS 4
+
+struct tegra30_mc {
+ void __iomem *regs[NUM_MC_REG_BANKS];
+ struct device *dev;
+ u32 ctx[0];
+};
+
+static inline u32 mc_readl(struct tegra30_mc *mc, u32 offs)
+{
+ u32 val = 0;
+
+ if (offs < 0x10)
+ val = readl(mc->regs[0] + offs);
+ if (offs < 0x1f0)
+ val = readl(mc->regs[1] + offs - 0x3c);
+ if (offs < 0x228)
+ val = readl(mc->regs[2] + offs - 0x200);
+ if (offs < 0x400)
+ val = readl(mc->regs[3] + offs - 0x284);
+
+ return val;
+}
+
+static inline void mc_writel(struct tegra30_mc *mc, u32 val, u32 offs)
+{
+ if (offs < 0x10) {
+ writel(val, mc->regs[0] + offs);
+ return;
+ }
+ if (offs < 0x1f0) {
+ writel(val, mc->regs[1] + offs - 0x3c);
+ return;
+ }
+ if (offs < 0x228) {
+ writel(val, mc->regs[2] + offs - 0x200);
+ return;
+ }
+ if (offs < 0x400) {
+ writel(val, mc->regs[3] + offs - 0x284);
+ return;
+ }
+}
+
+static const char * const tegra30_mc_client[] = {
+ "csr_ptcr",
+ "cbr_display0a",
+ "cbr_display0ab",
+ "cbr_display0b",
+ "cbr_display0bb",
+ "cbr_display0c",
+ "cbr_display0cb",
+ "cbr_display1b",
+ "cbr_display1bb",
+ "cbr_eppup",
+ "cbr_g2pr",
+ "cbr_g2sr",
+ "cbr_mpeunifbr",
+ "cbr_viruv",
+ "csr_afir",
+ "csr_avpcarm7r",
+ "csr_displayhc",
+ "csr_displayhcb",
+ "csr_fdcdrd",
+ "csr_fdcdrd2",
+ "csr_g2dr",
+ "csr_hdar",
+ "csr_host1xdmar",
+ "csr_host1xr",
+ "csr_idxsrd",
+ "csr_idxsrd2",
+ "csr_mpe_ipred",
+ "csr_mpeamemrd",
+ "csr_mpecsrd",
+ "csr_ppcsahbdmar",
+ "csr_ppcsahbslvr",
+ "csr_satar",
+ "csr_texsrd",
+ "csr_texsrd2",
+ "csr_vdebsevr",
+ "csr_vdember",
+ "csr_vdemcer",
+ "csr_vdetper",
+ "csr_mpcorelpr",
+ "csr_mpcorer",
+ "cbw_eppu",
+ "cbw_eppv",
+ "cbw_eppy",
+ "cbw_mpeunifbw",
+ "cbw_viwsb",
+ "cbw_viwu",
+ "cbw_viwv",
+ "cbw_viwy",
+ "ccw_g2dw",
+ "csw_afiw",
+ "csw_avpcarm7w",
+ "csw_fdcdwr",
+ "csw_fdcdwr2",
+ "csw_hdaw",
+ "csw_host1xw",
+ "csw_ispw",
+ "csw_mpcorelpw",
+ "csw_mpcorew",
+ "csw_mpecswr",
+ "csw_ppcsahbdmaw",
+ "csw_ppcsahbslvw",
+ "csw_sataw",
+ "csw_vdebsevw",
+ "csw_vdedbgw",
+ "csw_vdembew",
+ "csw_vdetpmw",
+};
+
+static void tegra30_mc_decode(struct tegra30_mc *mc, int n)
+{
+ u32 err, addr;
+ const char * const mc_int_err[] = {
+ "MC_DECERR",
+ "Unknown",
+ "MC_SECURITY_ERR",
+ "MC_ARBITRATION_EMEM",
+ "MC_SMMU_ERR",
+ };
+ const char * const err_type[] = {
+ "Unknown",
+ "Unknown",
+ "DECERR_EMEM",
+ "SECURITY_TRUSTZONE",
+ "SECURITY_CARVEOUT",
+ "Unknown",
+ "INVALID_SMMU_PAGE",
+ "Unknown",
+ };
+ char attr[6];
+ int cid, perm, type, idx;
+ const char *client = "Unknown";
+
+ idx = n - MC_INT_ERR_SHIFT;
+ if ((idx < 0) || (idx >= ARRAY_SIZE(mc_int_err)) || (idx == 1)) {
+ dev_err_ratelimited(mc->dev, "Unknown interrupt status %08lx\n",
+ BIT(n));
+ return;
+ }
+
+ err = readl(mc + MC_ERR_STATUS);
+
+ type = (err & MC_ERR_TYPE_MASK) >> MC_ERR_TYPE_SHIFT;
+ perm = (err & MC_ERR_INVALID_SMMU_PAGE_MASK) >>
+ MC_ERR_INVALID_SMMU_PAGE_SHIFT;
+ if (type == MC_ERR_TYPE_INVALID_SMMU_PAGE)
+ sprintf(attr, "%c-%c-%c",
+ (perm & BIT(2)) ? 'R' : '-',
+ (perm & BIT(1)) ? 'W' : '-',
+ (perm & BIT(0)) ? 'S' : '-');
+ else
+ attr[0] = '\0';
+
+ cid = err & MC_CLIENT_ID_MASK;
+ if (cid < ARRAY_SIZE(tegra30_mc_client))
+ client = tegra30_mc_client[cid];
+
+ addr = readl(mc + MC_ERR_ADR);
+
+ dev_err_ratelimited(mc->dev, "%s (0x%08x): 0x%08x %s (%s %s %s %s)\n",
+ mc_int_err[idx], err, addr, client,
+ (err & MC_ERR_SECURITY) ? "secure" : "non-secure",
+ (err & MC_ERR_RW) ? "write" : "read",
+ err_type[type], attr);
+}
+
+static const u32 tegra30_mc_ctx[] = {
+ MC_EMEM_ARB_CFG,
+ MC_EMEM_ARB_OUTSTANDING_REQ,
+ MC_EMEM_ARB_TIMING_RCD,
+ MC_EMEM_ARB_TIMING_RP,
+ MC_EMEM_ARB_TIMING_RC,
+ MC_EMEM_ARB_TIMING_RAS,
+ MC_EMEM_ARB_TIMING_FAW,
+ MC_EMEM_ARB_TIMING_RRD,
+ MC_EMEM_ARB_TIMING_RAP2PRE,
+ MC_EMEM_ARB_TIMING_WAP2PRE,
+ MC_EMEM_ARB_TIMING_R2R,
+ MC_EMEM_ARB_TIMING_W2W,
+ MC_EMEM_ARB_TIMING_R2W,
+ MC_EMEM_ARB_TIMING_W2R,
+ MC_EMEM_ARB_DA_TURNS,
+ MC_EMEM_ARB_DA_COVERS,
+ MC_EMEM_ARB_MISC0,
+ MC_EMEM_ARB_MISC1,
+ MC_EMEM_ARB_RING3_THROTTLE,
+ MC_EMEM_ARB_OVERRIDE,
+ MC_INTMASK,
+};
+
+static int tegra30_mc_suspend(struct device *dev)
+{
+ int i;
+ struct tegra30_mc *mc = dev_get_drvdata(dev);
+
+ for (i = 0; i < ARRAY_SIZE(tegra30_mc_ctx); i++)
+ mc->ctx[i] = mc_readl(mc, tegra30_mc_ctx[i]);
+ return 0;
+}
+
+static int tegra30_mc_resume(struct device *dev)
+{
+ int i;
+ struct tegra30_mc *mc = dev_get_drvdata(dev);
+
+ for (i = 0; i < ARRAY_SIZE(tegra30_mc_ctx); i++)
+ mc_writel(mc, mc->ctx[i], tegra30_mc_ctx[i]);
+
+ mc_writel(mc, 1, MC_TIMING_CONTROL);
+ /* Read-back to ensure that write reached */
+ mc_readl(mc, MC_TIMING_CONTROL);
+ return 0;
+}
+
+static UNIVERSAL_DEV_PM_OPS(tegra30_mc_pm,
+ tegra30_mc_suspend,
+ tegra30_mc_resume, NULL);
+
+static const struct of_device_id tegra30_mc_of_match[] __devinitconst = {
+ { .compatible = "nvidia,tegra30-mc", },
+ {},
+};
+
+static irqreturn_t tegra30_mc_isr(int irq, void *data)
+{
+ u32 stat, mask, bit;
+ struct tegra30_mc *mc = data;
+
+ stat = mc_readl(mc, MC_INTSTATUS);
+ mask = mc_readl(mc, MC_INTMASK);
+ mask &= stat;
+ if (!mask)
+ return IRQ_NONE;
+ while ((bit = ffs(mask)) != 0)
+ tegra30_mc_decode(mc, bit - 1);
+ mc_writel(mc, stat, MC_INTSTATUS);
+ return IRQ_HANDLED;
+}
+
+static int __devinit tegra30_mc_probe(struct platform_device *pdev)
+{
+ struct resource *irq;
+ struct tegra30_mc *mc;
+ size_t bytes;
+ int err, i;
+ u32 intmask;
+
+ bytes = sizeof(*mc) + sizeof(u32) * ARRAY_SIZE(tegra30_mc_ctx);
+ mc = devm_kzalloc(&pdev->dev, bytes, GFP_KERNEL);
+ if (!mc)
+ return -ENOMEM;
+ mc->dev = &pdev->dev;
+
+ for (i = 0; i < ARRAY_SIZE(mc->regs); i++) {
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ if (!res)
+ return -ENODEV;
+ mc->regs[i] = devm_request_and_ioremap(&pdev->dev, res);
+ if (!mc->regs[i])
+ return -EBUSY;
+ }
+
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq)
+ return -ENODEV;
+ err = devm_request_irq(&pdev->dev, irq->start, tegra30_mc_isr,
+ IRQF_SHARED, dev_name(&pdev->dev), mc);
+ if (err)
+ return -ENODEV;
+
+ platform_set_drvdata(pdev, mc);
+
+ intmask = MC_INT_INVALID_SMMU_PAGE |
+ MC_INT_DECERR_EMEM | MC_INT_SECURITY_VIOLATION;
+ mc_writel(mc, intmask, MC_INTMASK);
+ return 0;
+}
+
+static struct platform_driver tegra30_mc_driver = {
+ .probe = tegra30_mc_probe,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = tegra30_mc_of_match,
+ .pm = &tegra30_mc_pm,
+ },
+};
+module_platform_driver(tegra30_mc_driver);
+
+MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>");
+MODULE_DESCRIPTION("Tegra30 MC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/message/i2o/i2o_proc.c b/drivers/message/i2o/i2o_proc.c
index 6d115c7208ab..506c36f6e1db 100644
--- a/drivers/message/i2o/i2o_proc.c
+++ b/drivers/message/i2o/i2o_proc.c
@@ -283,7 +283,6 @@ static char *bus_strings[] = {
"Local Bus",
"ISA",
"EISA",
- "MCA",
"PCI",
"PCMCIA",
"NUBUS",
@@ -351,18 +350,6 @@ static int i2o_seq_show_hrt(struct seq_file *seq, void *v)
EisaSlotNumber);
break;
- case I2O_BUS_MCA:
- seq_printf(seq, " IOBase: %0#6x,",
- hrt->hrt_entry[i].bus.mca_bus.
- McaBaseIOPort);
- seq_printf(seq, " MemoryBase: %0#10x,",
- hrt->hrt_entry[i].bus.mca_bus.
- McaBaseMemoryAddress);
- seq_printf(seq, " Slot: %0#4x,",
- hrt->hrt_entry[i].bus.mca_bus.
- McaSlotNumber);
- break;
-
case I2O_BUS_PCI:
seq_printf(seq, " Bus: %0#4x",
hrt->hrt_entry[i].bus.pci_bus.
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index b5a0032f616e..f4b4dad77391 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -377,7 +377,6 @@ config PMIC_DA9052
config MFD_DA9052_SPI
bool "Support Dialog Semiconductor DA9052/53 PMIC variants with SPI"
- select IRQ_DOMAIN
select REGMAP_SPI
select REGMAP_IRQ
select PMIC_DA9052
@@ -390,7 +389,6 @@ config MFD_DA9052_SPI
config MFD_DA9052_I2C
bool "Support Dialog Semiconductor DA9052/53 PMIC variants with I2C"
- select IRQ_DOMAIN
select REGMAP_I2C
select REGMAP_IRQ
select PMIC_DA9052
@@ -417,7 +415,7 @@ config MFD_MAX8925
select MFD_CORE
help
Say yes here to support for Maxim Semiconductor MAX8925. This is
- a Power Management IC. This driver provies common support for
+ a Power Management IC. This driver provides common support for
accessing the device, additional drivers must be enabled in order
to use the functionality of the device.
@@ -440,7 +438,7 @@ config MFD_MAX8998
help
Say yes here to support for Maxim Semiconductor MAX8998 and
National Semiconductor LP3974. This is a Power Management IC.
- This driver provies common support for accessing the device,
+ This driver provides common support for accessing the device,
additional drivers must be enabled in order to use the functionality
of the device.
@@ -451,7 +449,7 @@ config MFD_S5M_CORE
select REGMAP_I2C
help
Support for the Samsung Electronics S5M MFD series.
- This driver provies common support for accessing the device,
+ This driver provides common support for accessing the device,
additional drivers must be enabled in order to use the functionality
of the device
@@ -561,7 +559,6 @@ config MFD_WM8994
bool "Support Wolfson Microelectronics WM8994"
select MFD_CORE
select REGMAP_I2C
- select IRQ_DOMAIN
select REGMAP_IRQ
depends on I2C=y && GENERIC_HARDIRQS
help
@@ -652,23 +649,6 @@ config EZX_PCAP
This enables the PCAP ASIC present on EZX Phones. This is
needed for MMC, TouchScreen, Sound, USB, etc..
-config AB5500_CORE
- bool "ST-Ericsson AB5500 Mixed Signal Power Management chip"
- depends on ABX500_CORE && MFD_DB5500_PRCMU
- select MFD_CORE
- help
- Select this option to enable access to AB5500 power management
- chip. This connects to the db5500 chip via the I2C bus via PRCMU.
- This chip embeds various other multimedia funtionalities as well.
-
-config AB5500_DEBUG
- bool "Enable debug info via debugfs"
- depends on AB5500_CORE && DEBUG_FS
- default y if DEBUG_FS
- help
- Select this option if you want debug information from the AB5500
- using the debug filesystem, debugfs.
-
config AB8500_CORE
bool "ST-Ericsson AB8500 Mixed Signal Power Management chip"
depends on GENERIC_HARDIRQS && ABX500_CORE
@@ -715,16 +695,6 @@ config MFD_DB8500_PRCMU
system controller running an XP70 microprocessor, which is accessed
through a register map.
-config MFD_DB5500_PRCMU
- bool "ST-Ericsson DB5500 Power Reset Control Management Unit"
- depends on UX500_SOC_DB5500
- select MFD_CORE
- help
- Select this option to enable support for the DB5500 Power Reset
- and Control Management Unit. This is basically an autonomous
- system controller running an XP70 microprocessor, which is accessed
- through a register map.
-
config MFD_CS5535
tristate "Support for CS5535 and CS5536 southbridge core functions"
select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 77293e150239..43672b87805a 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -87,15 +87,12 @@ obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o
obj-$(CONFIG_ABX500_CORE) += abx500-core.o
obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
-obj-$(CONFIG_AB5500_CORE) += ab5500-core.o
-obj-$(CONFIG_AB5500_DEBUG) += ab5500-debugfs.o
obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o
obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o
obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o
# ab8500-i2c need to come after db8500-prcmu (which provides the channel)
obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o
-obj-$(CONFIG_MFD_DB5500_PRCMU) += db5500-prcmu.o
obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
obj-$(CONFIG_LPC_SCH) += lpc_sch.o
diff --git a/drivers/mfd/ab5500-core.c b/drivers/mfd/ab5500-core.c
deleted file mode 100644
index 54d0fe40845f..000000000000
--- a/drivers/mfd/ab5500-core.c
+++ /dev/null
@@ -1,1439 +0,0 @@
-/*
- * Copyright (C) 2007-2011 ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- * Low-level core for exclusive access to the AB5500 IC on the I2C bus
- * and some basic chip-configuration.
- * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com>
- * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
- * Author: Mattias Wallin <mattias.wallin@stericsson.com>
- * Author: Rickard Andersson <rickard.andersson@stericsson.com>
- * Author: Karl Komierowski <karl.komierowski@stericsson.com>
- * Author: Bibek Basu <bibek.basu@stericsson.com>
- *
- * TODO: Event handling with irq_chip. Waiting for PRCMU fw support.
- */
-
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/random.h>
-#include <linux/mfd/abx500.h>
-#include <linux/mfd/abx500/ab5500.h>
-#include <linux/list.h>
-#include <linux/bitops.h>
-#include <linux/spinlock.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/db5500-prcmu.h>
-
-#include "ab5500-core.h"
-#include "ab5500-debugfs.h"
-
-#define AB5500_NUM_EVENT_REG 23
-#define AB5500_IT_LATCH0_REG 0x40
-#define AB5500_IT_MASK0_REG 0x60
-
-/*
- * Permissible register ranges for reading and writing per device and bank.
- *
- * The ranges must be listed in increasing address order, and no overlaps are
- * allowed. It is assumed that write permission implies read permission
- * (i.e. only RO and RW permissions should be used). Ranges with write
- * permission must not be split up.
- */
-
-#define NO_RANGE {.count = 0, .range = NULL,}
-static struct ab5500_i2c_banks ab5500_bank_ranges[AB5500_NUM_DEVICES] = {
- [AB5500_DEVID_USB] = {
- .nbanks = 1,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_USB,
- .nranges = 12,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x01,
- .last = 0x01,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x80,
- .last = 0x83,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x87,
- .last = 0x8A,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x8B,
- .last = 0x8B,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x91,
- .last = 0x92,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x93,
- .last = 0x93,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x94,
- .last = 0x94,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0xA8,
- .last = 0xB0,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0xB2,
- .last = 0xB2,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0xB4,
- .last = 0xBC,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0xBF,
- .last = 0xBF,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0xC1,
- .last = 0xC5,
- .perm = AB5500_PERM_RO,
- },
- },
- },
- },
- },
- [AB5500_DEVID_ADC] = {
- .nbanks = 1,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_ADC,
- .nranges = 6,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x1F,
- .last = 0x22,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x23,
- .last = 0x24,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x26,
- .last = 0x2D,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x2F,
- .last = 0x34,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x37,
- .last = 0x57,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x58,
- .last = 0x58,
- .perm = AB5500_PERM_RO,
- },
- },
- },
- },
- },
- [AB5500_DEVID_LEDS] = {
- .nbanks = 1,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_LED,
- .nranges = 1,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x0C,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- },
- },
- [AB5500_DEVID_VIDEO] = {
- .nbanks = 1,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_VDENC,
- .nranges = 12,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x08,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x09,
- .last = 0x09,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x0A,
- .last = 0x12,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x15,
- .last = 0x19,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x1B,
- .last = 0x21,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x27,
- .last = 0x2C,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x41,
- .last = 0x41,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x45,
- .last = 0x5B,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x5D,
- .last = 0x5D,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x69,
- .last = 0x69,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x6C,
- .last = 0x6D,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x80,
- .last = 0x81,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- },
- },
- [AB5500_DEVID_REGULATORS] = {
- .nbanks = 2,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_STARTUP,
- .nranges = 12,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x01,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x1F,
- .last = 0x1F,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x2E,
- .last = 0x2E,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x2F,
- .last = 0x30,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x50,
- .last = 0x51,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x60,
- .last = 0x61,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x66,
- .last = 0x8A,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x8C,
- .last = 0x96,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xAA,
- .last = 0xB4,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xB7,
- .last = 0xBF,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xC1,
- .last = 0xCA,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xD3,
- .last = 0xE0,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- {
- .bankid = AB5500_BANK_SIM_USBSIM,
- .nranges = 1,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x13,
- .last = 0x19,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- },
- },
- [AB5500_DEVID_SIM] = {
- .nbanks = 1,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_SIM_USBSIM,
- .nranges = 1,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x13,
- .last = 0x19,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- },
- },
- [AB5500_DEVID_RTC] = {
- .nbanks = 1,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_RTC,
- .nranges = 2,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x04,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x06,
- .last = 0x0C,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- },
- },
- [AB5500_DEVID_CHARGER] = {
- .nbanks = 1,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_CHG,
- .nranges = 2,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x11,
- .last = 0x11,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x12,
- .last = 0x1B,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- },
- },
- [AB5500_DEVID_FUELGAUGE] = {
- .nbanks = 1,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_FG_BATTCOM_ACC,
- .nranges = 2,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x0B,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x0C,
- .last = 0x10,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- },
- },
- [AB5500_DEVID_VIBRATOR] = {
- .nbanks = 1,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_VIBRA,
- .nranges = 2,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x10,
- .last = 0x13,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xFE,
- .last = 0xFE,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- },
- },
- [AB5500_DEVID_CODEC] = {
- .nbanks = 1,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_AUDIO_HEADSETUSB,
- .nranges = 2,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x48,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xEB,
- .last = 0xFB,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- },
- },
- [AB5500_DEVID_POWER] = {
- .nbanks = 2,
- .bank = (struct ab5500_i2c_ranges []) {
- {
- .bankid = AB5500_BANK_STARTUP,
- .nranges = 1,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x30,
- .last = 0x30,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- {
- .bankid = AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP,
- .nranges = 1,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x01,
- .last = 0x01,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- },
- },
-};
-
-#define AB5500_IRQ(bank, bit) ((bank) * 8 + (bit))
-
-/* I appologize for the resource names beeing a mix of upper case
- * and lower case but I want them to be exact as the documentation */
-static struct mfd_cell ab5500_devs[AB5500_NUM_DEVICES] = {
- [AB5500_DEVID_LEDS] = {
- .name = "ab5500-leds",
- .id = AB5500_DEVID_LEDS,
- },
- [AB5500_DEVID_POWER] = {
- .name = "ab5500-power",
- .id = AB5500_DEVID_POWER,
- },
- [AB5500_DEVID_REGULATORS] = {
- .name = "ab5500-regulator",
- .id = AB5500_DEVID_REGULATORS,
- },
- [AB5500_DEVID_SIM] = {
- .name = "ab5500-sim",
- .id = AB5500_DEVID_SIM,
- .num_resources = 1,
- .resources = (struct resource[]) {
- {
- .name = "SIMOFF",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(2, 0), /*rising*/
- .end = AB5500_IRQ(2, 1), /*falling*/
- },
- },
- },
- [AB5500_DEVID_RTC] = {
- .name = "ab5500-rtc",
- .id = AB5500_DEVID_RTC,
- .num_resources = 1,
- .resources = (struct resource[]) {
- {
- .name = "RTC_Alarm",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(1, 7),
- .end = AB5500_IRQ(1, 7),
- }
- },
- },
- [AB5500_DEVID_CHARGER] = {
- .name = "ab5500-charger",
- .id = AB5500_DEVID_CHARGER,
- },
- [AB5500_DEVID_ADC] = {
- .name = "ab5500-adc",
- .id = AB5500_DEVID_ADC,
- .num_resources = 10,
- .resources = (struct resource[]) {
- {
- .name = "TRIGGER-0",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(0, 0),
- .end = AB5500_IRQ(0, 0),
- },
- {
- .name = "TRIGGER-1",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(0, 1),
- .end = AB5500_IRQ(0, 1),
- },
- {
- .name = "TRIGGER-2",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(0, 2),
- .end = AB5500_IRQ(0, 2),
- },
- {
- .name = "TRIGGER-3",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(0, 3),
- .end = AB5500_IRQ(0, 3),
- },
- {
- .name = "TRIGGER-4",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(0, 4),
- .end = AB5500_IRQ(0, 4),
- },
- {
- .name = "TRIGGER-5",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(0, 5),
- .end = AB5500_IRQ(0, 5),
- },
- {
- .name = "TRIGGER-6",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(0, 6),
- .end = AB5500_IRQ(0, 6),
- },
- {
- .name = "TRIGGER-7",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(0, 7),
- .end = AB5500_IRQ(0, 7),
- },
- {
- .name = "TRIGGER-VBAT",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(0, 8),
- .end = AB5500_IRQ(0, 8),
- },
- {
- .name = "TRIGGER-VBAT-TXON",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(0, 9),
- .end = AB5500_IRQ(0, 9),
- },
- },
- },
- [AB5500_DEVID_FUELGAUGE] = {
- .name = "ab5500-fuelgauge",
- .id = AB5500_DEVID_FUELGAUGE,
- .num_resources = 6,
- .resources = (struct resource[]) {
- {
- .name = "Batt_attach",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(7, 5),
- .end = AB5500_IRQ(7, 5),
- },
- {
- .name = "Batt_removal",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(7, 6),
- .end = AB5500_IRQ(7, 6),
- },
- {
- .name = "UART_framing",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(7, 7),
- .end = AB5500_IRQ(7, 7),
- },
- {
- .name = "UART_overrun",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(8, 0),
- .end = AB5500_IRQ(8, 0),
- },
- {
- .name = "UART_Rdy_RX",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(8, 1),
- .end = AB5500_IRQ(8, 1),
- },
- {
- .name = "UART_Rdy_TX",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(8, 2),
- .end = AB5500_IRQ(8, 2),
- },
- },
- },
- [AB5500_DEVID_VIBRATOR] = {
- .name = "ab5500-vibrator",
- .id = AB5500_DEVID_VIBRATOR,
- },
- [AB5500_DEVID_CODEC] = {
- .name = "ab5500-codec",
- .id = AB5500_DEVID_CODEC,
- .num_resources = 3,
- .resources = (struct resource[]) {
- {
- .name = "audio_spkr1_ovc",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(9, 5),
- .end = AB5500_IRQ(9, 5),
- },
- {
- .name = "audio_plllocked",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(9, 6),
- .end = AB5500_IRQ(9, 6),
- },
- {
- .name = "audio_spkr2_ovc",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(17, 4),
- .end = AB5500_IRQ(17, 4),
- },
- },
- },
- [AB5500_DEVID_USB] = {
- .name = "ab5500-usb",
- .id = AB5500_DEVID_USB,
- .num_resources = 36,
- .resources = (struct resource[]) {
- {
- .name = "Link_Update",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(22, 1),
- .end = AB5500_IRQ(22, 1),
- },
- {
- .name = "DCIO",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(8, 3),
- .end = AB5500_IRQ(8, 4),
- },
- {
- .name = "VBUS_R",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(8, 5),
- .end = AB5500_IRQ(8, 5),
- },
- {
- .name = "VBUS_F",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(8, 6),
- .end = AB5500_IRQ(8, 6),
- },
- {
- .name = "CHGstate_10_PCVBUSchg",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(8, 7),
- .end = AB5500_IRQ(8, 7),
- },
- {
- .name = "DCIOreverse_ovc",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(9, 0),
- .end = AB5500_IRQ(9, 0),
- },
- {
- .name = "USBCharDetDone",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(9, 1),
- .end = AB5500_IRQ(9, 1),
- },
- {
- .name = "DCIO_no_limit",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(9, 2),
- .end = AB5500_IRQ(9, 2),
- },
- {
- .name = "USB_suspend",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(9, 3),
- .end = AB5500_IRQ(9, 3),
- },
- {
- .name = "DCIOreverse_fwdcurrent",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(9, 4),
- .end = AB5500_IRQ(9, 4),
- },
- {
- .name = "Vbus_Imeasmax_change",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(9, 5),
- .end = AB5500_IRQ(9, 6),
- },
- {
- .name = "OVV",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(14, 5),
- .end = AB5500_IRQ(14, 5),
- },
- {
- .name = "USBcharging_NOTok",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(15, 3),
- .end = AB5500_IRQ(15, 3),
- },
- {
- .name = "usb_adp_sensoroff",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(15, 6),
- .end = AB5500_IRQ(15, 6),
- },
- {
- .name = "usb_adp_probeplug",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(15, 7),
- .end = AB5500_IRQ(15, 7),
- },
- {
- .name = "usb_adp_sinkerror",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(16, 0),
- .end = AB5500_IRQ(16, 6),
- },
- {
- .name = "usb_adp_sourceerror",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(16, 1),
- .end = AB5500_IRQ(16, 1),
- },
- {
- .name = "usb_idgnd_r",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(16, 2),
- .end = AB5500_IRQ(16, 2),
- },
- {
- .name = "usb_idgnd_f",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(16, 3),
- .end = AB5500_IRQ(16, 3),
- },
- {
- .name = "usb_iddetR1",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(16, 4),
- .end = AB5500_IRQ(16, 5),
- },
- {
- .name = "usb_iddetR2",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(16, 6),
- .end = AB5500_IRQ(16, 7),
- },
- {
- .name = "usb_iddetR3",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(17, 0),
- .end = AB5500_IRQ(17, 1),
- },
- {
- .name = "usb_iddetR4",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(17, 2),
- .end = AB5500_IRQ(17, 3),
- },
- {
- .name = "CharTempWindowOk",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(17, 7),
- .end = AB5500_IRQ(18, 0),
- },
- {
- .name = "USB_SprDetect",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(18, 1),
- .end = AB5500_IRQ(18, 1),
- },
- {
- .name = "usb_adp_probe_unplug",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(18, 2),
- .end = AB5500_IRQ(18, 2),
- },
- {
- .name = "VBUSChDrop",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(18, 3),
- .end = AB5500_IRQ(18, 4),
- },
- {
- .name = "dcio_char_rec_done",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(18, 5),
- .end = AB5500_IRQ(18, 5),
- },
- {
- .name = "Charging_stopped_by_temp",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(18, 6),
- .end = AB5500_IRQ(18, 6),
- },
- {
- .name = "CHGstate_11_SafeModeVBUS",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(21, 1),
- .end = AB5500_IRQ(21, 2),
- },
- {
- .name = "CHGstate_12_comletedVBUS",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(21, 2),
- .end = AB5500_IRQ(21, 2),
- },
- {
- .name = "CHGstate_13_completedVBUS",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(21, 3),
- .end = AB5500_IRQ(21, 3),
- },
- {
- .name = "CHGstate_14_FullChgDCIO",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(21, 4),
- .end = AB5500_IRQ(21, 4),
- },
- {
- .name = "CHGstate_15_SafeModeDCIO",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(21, 5),
- .end = AB5500_IRQ(21, 5),
- },
- {
- .name = "CHGstate_16_OFFsuspendDCIO",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(21, 6),
- .end = AB5500_IRQ(21, 6),
- },
- {
- .name = "CHGstate_17_completedDCIO",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(21, 7),
- .end = AB5500_IRQ(21, 7),
- },
- },
- },
- [AB5500_DEVID_OTP] = {
- .name = "ab5500-otp",
- .id = AB5500_DEVID_OTP,
- },
- [AB5500_DEVID_VIDEO] = {
- .name = "ab5500-video",
- .id = AB5500_DEVID_VIDEO,
- .num_resources = 1,
- .resources = (struct resource[]) {
- {
- .name = "plugTVdet",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(22, 2),
- .end = AB5500_IRQ(22, 2),
- },
- },
- },
- [AB5500_DEVID_DBIECI] = {
- .name = "ab5500-dbieci",
- .id = AB5500_DEVID_DBIECI,
- .num_resources = 10,
- .resources = (struct resource[]) {
- {
- .name = "COLL",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(14, 0),
- .end = AB5500_IRQ(14, 0),
- },
- {
- .name = "RESERR",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(14, 1),
- .end = AB5500_IRQ(14, 1),
- },
- {
- .name = "FRAERR",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(14, 2),
- .end = AB5500_IRQ(14, 2),
- },
- {
- .name = "COMERR",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(14, 3),
- .end = AB5500_IRQ(14, 3),
- },
- {
- .name = "BSI_indicator",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(14, 4),
- .end = AB5500_IRQ(14, 4),
- },
- {
- .name = "SPDSET",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(14, 6),
- .end = AB5500_IRQ(14, 6),
- },
- {
- .name = "DSENT",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(14, 7),
- .end = AB5500_IRQ(14, 7),
- },
- {
- .name = "DREC",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(15, 0),
- .end = AB5500_IRQ(15, 0),
- },
- {
- .name = "ACCINT",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(15, 1),
- .end = AB5500_IRQ(15, 1),
- },
- {
- .name = "NOPINT",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(15, 2),
- .end = AB5500_IRQ(15, 2),
- },
- },
- },
- [AB5500_DEVID_ONSWA] = {
- .name = "ab5500-onswa",
- .id = AB5500_DEVID_ONSWA,
- .num_resources = 2,
- .resources = (struct resource[]) {
- {
- .name = "ONSWAn_rising",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(1, 3),
- .end = AB5500_IRQ(1, 3),
- },
- {
- .name = "ONSWAn_falling",
- .flags = IORESOURCE_IRQ,
- .start = AB5500_IRQ(1, 4),
- .end = AB5500_IRQ(1, 4),
- },
- },
- },
-};
-
-/*
- * Functionality for getting/setting register values.
- */
-int ab5500_get_register_interruptible_raw(struct ab5500 *ab,
- u8 bank, u8 reg,
- u8 *value)
-{
- int err;
-
- if (bank >= AB5500_NUM_BANKS)
- return -EINVAL;
-
- err = mutex_lock_interruptible(&ab->access_mutex);
- if (err)
- return err;
- err = db5500_prcmu_abb_read(bankinfo[bank].slave_addr, reg, value, 1);
-
- mutex_unlock(&ab->access_mutex);
- return err;
-}
-
-static int get_register_page_interruptible(struct ab5500 *ab, u8 bank,
- u8 first_reg, u8 *regvals, u8 numregs)
-{
- int err;
-
- if (bank >= AB5500_NUM_BANKS)
- return -EINVAL;
-
- err = mutex_lock_interruptible(&ab->access_mutex);
- if (err)
- return err;
-
- while (numregs) {
- /* The hardware limit for get page is 4 */
- u8 curnum = min_t(u8, numregs, 4u);
-
- err = db5500_prcmu_abb_read(bankinfo[bank].slave_addr,
- first_reg, regvals, curnum);
- if (err)
- goto out;
-
- numregs -= curnum;
- first_reg += curnum;
- regvals += curnum;
- }
-
-out:
- mutex_unlock(&ab->access_mutex);
- return err;
-}
-
-int ab5500_mask_and_set_register_interruptible_raw(struct ab5500 *ab, u8 bank,
- u8 reg, u8 bitmask, u8 bitvalues)
-{
- int err = 0;
-
- if (bank >= AB5500_NUM_BANKS)
- return -EINVAL;
-
- if (bitmask) {
- u8 buf;
-
- err = mutex_lock_interruptible(&ab->access_mutex);
- if (err)
- return err;
-
- if (bitmask == 0xFF) /* No need to read in this case. */
- buf = bitvalues;
- else { /* Read and modify the register value. */
- err = db5500_prcmu_abb_read(bankinfo[bank].slave_addr,
- reg, &buf, 1);
- if (err)
- return err;
-
- buf = ((~bitmask & buf) | (bitmask & bitvalues));
- }
- /* Write the new value. */
- err = db5500_prcmu_abb_write(bankinfo[bank].slave_addr, reg,
- &buf, 1);
-
- mutex_unlock(&ab->access_mutex);
- }
- return err;
-}
-
-static int
-set_register_interruptible(struct ab5500 *ab, u8 bank, u8 reg, u8 value)
-{
- return ab5500_mask_and_set_register_interruptible_raw(ab, bank, reg,
- 0xff, value);
-}
-
-/*
- * Read/write permission checking functions.
- */
-static const struct ab5500_i2c_ranges *get_bankref(u8 devid, u8 bank)
-{
- u8 i;
-
- if (devid < AB5500_NUM_DEVICES) {
- for (i = 0; i < ab5500_bank_ranges[devid].nbanks; i++) {
- if (ab5500_bank_ranges[devid].bank[i].bankid == bank)
- return &ab5500_bank_ranges[devid].bank[i];
- }
- }
- return NULL;
-}
-
-static bool page_write_allowed(u8 devid, u8 bank, u8 first_reg, u8 last_reg)
-{
- u8 i; /* range loop index */
- const struct ab5500_i2c_ranges *bankref;
-
- bankref = get_bankref(devid, bank);
- if (bankref == NULL || last_reg < first_reg)
- return false;
-
- for (i = 0; i < bankref->nranges; i++) {
- if (first_reg < bankref->range[i].first)
- break;
- if ((last_reg <= bankref->range[i].last) &&
- (bankref->range[i].perm & AB5500_PERM_WR))
- return true;
- }
- return false;
-}
-
-static bool reg_write_allowed(u8 devid, u8 bank, u8 reg)
-{
- return page_write_allowed(devid, bank, reg, reg);
-}
-
-static bool page_read_allowed(u8 devid, u8 bank, u8 first_reg, u8 last_reg)
-{
- u8 i;
- const struct ab5500_i2c_ranges *bankref;
-
- bankref = get_bankref(devid, bank);
- if (bankref == NULL || last_reg < first_reg)
- return false;
-
-
- /* Find the range (if it exists in the list) that includes first_reg. */
- for (i = 0; i < bankref->nranges; i++) {
- if (first_reg < bankref->range[i].first)
- return false;
- if (first_reg <= bankref->range[i].last)
- break;
- }
- /* Make sure that the entire range up to and including last_reg is
- * readable. This may span several of the ranges in the list.
- */
- while ((i < bankref->nranges) &&
- (bankref->range[i].perm & AB5500_PERM_RD)) {
- if (last_reg <= bankref->range[i].last)
- return true;
- if ((++i >= bankref->nranges) ||
- (bankref->range[i].first !=
- (bankref->range[i - 1].last + 1))) {
- break;
- }
- }
- return false;
-}
-
-static bool reg_read_allowed(u8 devid, u8 bank, u8 reg)
-{
- return page_read_allowed(devid, bank, reg, reg);
-}
-
-
-/*
- * The exported register access functionality.
- */
-static int ab5500_get_chip_id(struct device *dev)
-{
- struct ab5500 *ab = dev_get_drvdata(dev->parent);
-
- return (int)ab->chip_id;
-}
-
-static int ab5500_mask_and_set_register_interruptible(struct device *dev,
- u8 bank, u8 reg, u8 bitmask, u8 bitvalues)
-{
- struct ab5500 *ab;
- struct platform_device *pdev = to_platform_device(dev);
-
- if ((AB5500_NUM_BANKS <= bank) ||
- !reg_write_allowed(pdev->id, bank, reg))
- return -EINVAL;
-
- ab = dev_get_drvdata(dev->parent);
- return ab5500_mask_and_set_register_interruptible_raw(ab, bank, reg,
- bitmask, bitvalues);
-}
-
-static int ab5500_set_register_interruptible(struct device *dev, u8 bank,
- u8 reg, u8 value)
-{
- return ab5500_mask_and_set_register_interruptible(dev, bank, reg, 0xFF,
- value);
-}
-
-static int ab5500_get_register_interruptible(struct device *dev, u8 bank,
- u8 reg, u8 *value)
-{
- struct ab5500 *ab;
- struct platform_device *pdev = to_platform_device(dev);
-
- if ((AB5500_NUM_BANKS <= bank) ||
- !reg_read_allowed(pdev->id, bank, reg))
- return -EINVAL;
-
- ab = dev_get_drvdata(dev->parent);
- return ab5500_get_register_interruptible_raw(ab, bank, reg, value);
-}
-
-static int ab5500_get_register_page_interruptible(struct device *dev, u8 bank,
- u8 first_reg, u8 *regvals, u8 numregs)
-{
- struct ab5500 *ab;
- struct platform_device *pdev = to_platform_device(dev);
-
- if ((AB5500_NUM_BANKS <= bank) ||
- !page_read_allowed(pdev->id, bank,
- first_reg, (first_reg + numregs - 1)))
- return -EINVAL;
-
- ab = dev_get_drvdata(dev->parent);
- return get_register_page_interruptible(ab, bank, first_reg, regvals,
- numregs);
-}
-
-static int
-ab5500_event_registers_startup_state_get(struct device *dev, u8 *event)
-{
- struct ab5500 *ab;
-
- ab = dev_get_drvdata(dev->parent);
- if (!ab->startup_events_read)
- return -EAGAIN; /* Try again later */
-
- memcpy(event, ab->startup_events, AB5500_NUM_EVENT_REG);
- return 0;
-}
-
-static struct abx500_ops ab5500_ops = {
- .get_chip_id = ab5500_get_chip_id,
- .get_register = ab5500_get_register_interruptible,
- .set_register = ab5500_set_register_interruptible,
- .get_register_page = ab5500_get_register_page_interruptible,
- .set_register_page = NULL,
- .mask_and_set_register = ab5500_mask_and_set_register_interruptible,
- .event_registers_startup_state_get =
- ab5500_event_registers_startup_state_get,
- .startup_irq_enabled = NULL,
-};
-
-/*
- * ab5500_setup : Basic set-up, datastructure creation/destruction
- * and I2C interface.This sets up a default config
- * in the AB5500 chip so that it will work as expected.
- * @ab : Pointer to ab5500 structure
- * @settings : Pointer to struct abx500_init_settings
- * @size : Size of init data
- */
-static int __init ab5500_setup(struct ab5500 *ab,
- struct abx500_init_settings *settings, unsigned int size)
-{
- int err = 0;
- int i;
-
- for (i = 0; i < size; i++) {
- err = ab5500_mask_and_set_register_interruptible_raw(ab,
- settings[i].bank,
- settings[i].reg,
- 0xFF, settings[i].setting);
- if (err)
- goto exit_no_setup;
-
- /* If event mask register update the event mask in ab5500 */
- if ((settings[i].bank == AB5500_BANK_IT) &&
- (AB5500_MASK_BASE <= settings[i].reg) &&
- (settings[i].reg <= AB5500_MASK_END)) {
- ab->mask[settings[i].reg - AB5500_MASK_BASE] =
- settings[i].setting;
- }
- }
-exit_no_setup:
- return err;
-}
-
-struct ab_family_id {
- u8 id;
- char *name;
-};
-
-static const struct ab_family_id ids[] __initdata = {
- /* AB5500 */
- {
- .id = AB5500_1_0,
- .name = "1.0"
- },
- {
- .id = AB5500_1_1,
- .name = "1.1"
- },
- /* Terminator */
- {
- .id = 0x00,
- }
-};
-
-static int __init ab5500_probe(struct platform_device *pdev)
-{
- struct ab5500 *ab;
- struct ab5500_platform_data *ab5500_plf_data =
- pdev->dev.platform_data;
- int err;
- int i;
-
- ab = kzalloc(sizeof(struct ab5500), GFP_KERNEL);
- if (!ab) {
- dev_err(&pdev->dev,
- "could not allocate ab5500 device\n");
- return -ENOMEM;
- }
-
- /* Initialize data structure */
- mutex_init(&ab->access_mutex);
- mutex_init(&ab->irq_lock);
- ab->dev = &pdev->dev;
-
- platform_set_drvdata(pdev, ab);
-
- /* Read chip ID register */
- err = ab5500_get_register_interruptible_raw(ab,
- AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP,
- AB5500_CHIP_ID, &ab->chip_id);
- if (err) {
- dev_err(&pdev->dev, "could not communicate with the analog "
- "baseband chip\n");
- goto exit_no_detect;
- }
-
- for (i = 0; ids[i].id != 0x0; i++) {
- if (ids[i].id == ab->chip_id) {
- snprintf(&ab->chip_name[0], sizeof(ab->chip_name) - 1,
- "AB5500 %s", ids[i].name);
- break;
- }
- }
- if (ids[i].id == 0x0) {
- dev_err(&pdev->dev, "unknown analog baseband chip id: 0x%x\n",
- ab->chip_id);
- dev_err(&pdev->dev, "driver not started!\n");
- goto exit_no_detect;
- }
-
- /* Clear and mask all interrupts */
- for (i = 0; i < AB5500_NUM_IRQ_REGS; i++) {
- u8 latchreg = AB5500_IT_LATCH0_REG + i;
- u8 maskreg = AB5500_IT_MASK0_REG + i;
- u8 val;
-
- ab5500_get_register_interruptible_raw(ab, AB5500_BANK_IT,
- latchreg, &val);
- set_register_interruptible(ab, AB5500_BANK_IT, maskreg, 0xff);
- ab->mask[i] = ab->oldmask[i] = 0xff;
- }
-
- err = abx500_register_ops(&pdev->dev, &ab5500_ops);
- if (err) {
- dev_err(&pdev->dev, "ab5500_register ops error\n");
- goto exit_no_detect;
- }
-
- /* Set up and register the platform devices. */
- for (i = 0; i < AB5500_NUM_DEVICES; i++) {
- ab5500_devs[i].platform_data = ab5500_plf_data->dev_data[i];
- ab5500_devs[i].pdata_size =
- sizeof(ab5500_plf_data->dev_data[i]);
- }
-
- err = mfd_add_devices(&pdev->dev, 0, ab5500_devs,
- ARRAY_SIZE(ab5500_devs), NULL,
- ab5500_plf_data->irq.base);
- if (err) {
- dev_err(&pdev->dev, "ab5500_mfd_add_device error\n");
- goto exit_no_detect;
- }
-
- err = ab5500_setup(ab, ab5500_plf_data->init_settings,
- ab5500_plf_data->init_settings_sz);
- if (err) {
- dev_err(&pdev->dev, "ab5500_setup error\n");
- goto exit_no_detect;
- }
-
- ab5500_setup_debugfs(ab);
-
- dev_info(&pdev->dev, "detected AB chip: %s\n", &ab->chip_name[0]);
- return 0;
-
-exit_no_detect:
- kfree(ab);
- return err;
-}
-
-static int __exit ab5500_remove(struct platform_device *pdev)
-{
- struct ab5500 *ab = platform_get_drvdata(pdev);
-
- ab5500_remove_debugfs();
- mfd_remove_devices(&pdev->dev);
- kfree(ab);
- return 0;
-}
-
-static struct platform_driver ab5500_driver = {
- .driver = {
- .name = "ab5500-core",
- .owner = THIS_MODULE,
- },
- .remove = __exit_p(ab5500_remove),
-};
-
-static int __init ab5500_core_init(void)
-{
- return platform_driver_probe(&ab5500_driver, ab5500_probe);
-}
-
-static void __exit ab5500_core_exit(void)
-{
- platform_driver_unregister(&ab5500_driver);
-}
-
-subsys_initcall(ab5500_core_init);
-module_exit(ab5500_core_exit);
-
-MODULE_AUTHOR("Mattias Wallin <mattias.wallin@stericsson.com>");
-MODULE_DESCRIPTION("AB5500 core driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/ab5500-debugfs.c b/drivers/mfd/ab5500-debugfs.c
deleted file mode 100644
index 72006940937a..000000000000
--- a/drivers/mfd/ab5500-debugfs.c
+++ /dev/null
@@ -1,807 +0,0 @@
-/*
- * Copyright (C) 2011 ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- * Debugfs support for the AB5500 MFD driver
- */
-
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/mfd/abx500.h>
-#include <linux/mfd/abx500/ab5500.h>
-#include <linux/uaccess.h>
-
-#include "ab5500-core.h"
-#include "ab5500-debugfs.h"
-
-static struct ab5500_i2c_ranges ab5500_reg_ranges[AB5500_NUM_BANKS] = {
- [AB5500_BANK_LED] = {
- .bankid = AB5500_BANK_LED,
- .nranges = 1,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x0C,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- [AB5500_BANK_ADC] = {
- .bankid = AB5500_BANK_ADC,
- .nranges = 6,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x1F,
- .last = 0x22,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x23,
- .last = 0x24,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x26,
- .last = 0x2D,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x2F,
- .last = 0x34,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x37,
- .last = 0x57,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x58,
- .last = 0x58,
- .perm = AB5500_PERM_RO,
- },
- },
- },
- [AB5500_BANK_RTC] = {
- .bankid = AB5500_BANK_RTC,
- .nranges = 2,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x04,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x06,
- .last = 0x0C,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- [AB5500_BANK_STARTUP] = {
- .bankid = AB5500_BANK_STARTUP,
- .nranges = 12,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x01,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x1F,
- .last = 0x1F,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x2E,
- .last = 0x2E,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x2F,
- .last = 0x30,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x50,
- .last = 0x51,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x60,
- .last = 0x61,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x66,
- .last = 0x8A,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x8C,
- .last = 0x96,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xAA,
- .last = 0xB4,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xB7,
- .last = 0xBF,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xC1,
- .last = 0xCA,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xD3,
- .last = 0xE0,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- [AB5500_BANK_DBI_ECI] = {
- .bankid = AB5500_BANK_DBI_ECI,
- .nranges = 3,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x07,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x10,
- .last = 0x10,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x13,
- .last = 0x13,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- [AB5500_BANK_CHG] = {
- .bankid = AB5500_BANK_CHG,
- .nranges = 2,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x11,
- .last = 0x11,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x12,
- .last = 0x1B,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- [AB5500_BANK_FG_BATTCOM_ACC] = {
- .bankid = AB5500_BANK_FG_BATTCOM_ACC,
- .nranges = 2,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x0B,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x0C,
- .last = 0x10,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- [AB5500_BANK_USB] = {
- .bankid = AB5500_BANK_USB,
- .nranges = 12,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x01,
- .last = 0x01,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x80,
- .last = 0x83,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x87,
- .last = 0x8A,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x8B,
- .last = 0x8B,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x91,
- .last = 0x92,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x93,
- .last = 0x93,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x94,
- .last = 0x94,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0xA8,
- .last = 0xB0,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0xB2,
- .last = 0xB2,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0xB4,
- .last = 0xBC,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0xBF,
- .last = 0xBF,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0xC1,
- .last = 0xC5,
- .perm = AB5500_PERM_RO,
- },
- },
- },
- [AB5500_BANK_IT] = {
- .bankid = AB5500_BANK_IT,
- .nranges = 4,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x02,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x20,
- .last = 0x36,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x40,
- .last = 0x56,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x60,
- .last = 0x76,
- .perm = AB5500_PERM_RO,
- },
- },
- },
- [AB5500_BANK_VDDDIG_IO_I2C_CLK_TST] = {
- .bankid = AB5500_BANK_VDDDIG_IO_I2C_CLK_TST,
- .nranges = 7,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x02,
- .last = 0x02,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x12,
- .last = 0x12,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x30,
- .last = 0x34,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x40,
- .last = 0x44,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x50,
- .last = 0x54,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x60,
- .last = 0x64,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x70,
- .last = 0x74,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- [AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP] = {
- .bankid = AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP,
- .nranges = 13,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x01,
- .last = 0x01,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x02,
- .last = 0x02,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x0D,
- .last = 0x0F,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x1C,
- .last = 0x1C,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x1E,
- .last = 0x1E,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x20,
- .last = 0x21,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x25,
- .last = 0x25,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x28,
- .last = 0x2A,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x30,
- .last = 0x33,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x40,
- .last = 0x43,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x50,
- .last = 0x53,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x60,
- .last = 0x63,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x70,
- .last = 0x73,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- [AB5500_BANK_VIBRA] = {
- .bankid = AB5500_BANK_VIBRA,
- .nranges = 2,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x10,
- .last = 0x13,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xFE,
- .last = 0xFE,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- [AB5500_BANK_AUDIO_HEADSETUSB] = {
- .bankid = AB5500_BANK_AUDIO_HEADSETUSB,
- .nranges = 2,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x48,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0xEB,
- .last = 0xFB,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- [AB5500_BANK_SIM_USBSIM] = {
- .bankid = AB5500_BANK_SIM_USBSIM,
- .nranges = 1,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x13,
- .last = 0x19,
- .perm = AB5500_PERM_RW,
- },
- },
- },
- [AB5500_BANK_VDENC] = {
- .bankid = AB5500_BANK_VDENC,
- .nranges = 12,
- .range = (struct ab5500_reg_range[]) {
- {
- .first = 0x00,
- .last = 0x08,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x09,
- .last = 0x09,
- .perm = AB5500_PERM_RO,
- },
- {
- .first = 0x0A,
- .last = 0x12,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x15,
- .last = 0x19,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x1B,
- .last = 0x21,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x27,
- .last = 0x2C,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x41,
- .last = 0x41,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x45,
- .last = 0x5B,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x5D,
- .last = 0x5D,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x69,
- .last = 0x69,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x6C,
- .last = 0x6D,
- .perm = AB5500_PERM_RW,
- },
- {
- .first = 0x80,
- .last = 0x81,
- .perm = AB5500_PERM_RW,
- },
- },
- },
-};
-
-static int ab5500_registers_print(struct seq_file *s, void *p)
-{
- struct ab5500 *ab = s->private;
- unsigned int i;
- u8 bank = (u8)ab->debug_bank;
-
- seq_printf(s, "ab5500 register values:\n");
- for (bank = 0; bank < AB5500_NUM_BANKS; bank++) {
- seq_printf(s, " bank %u, %s (0x%x):\n", bank,
- bankinfo[bank].name,
- bankinfo[bank].slave_addr);
- for (i = 0; i < ab5500_reg_ranges[bank].nranges; i++) {
- u8 reg;
- int err;
-
- for (reg = ab5500_reg_ranges[bank].range[i].first;
- reg <= ab5500_reg_ranges[bank].range[i].last;
- reg++) {
- u8 value;
-
- err = ab5500_get_register_interruptible_raw(ab,
- bank, reg,
- &value);
- if (err < 0) {
- dev_err(ab->dev, "get_reg failed %d"
- "bank 0x%x reg 0x%x\n",
- err, bank, reg);
- return err;
- }
-
- err = seq_printf(s, "[%d/0x%02X]: 0x%02X\n",
- bank, reg, value);
- if (err < 0) {
- dev_err(ab->dev,
- "seq_printf overflow\n");
- /*
- * Error is not returned here since
- * the output is wanted in any case
- */
- return 0;
- }
- }
- }
- }
- return 0;
-}
-
-static int ab5500_registers_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ab5500_registers_print, inode->i_private);
-}
-
-static const struct file_operations ab5500_registers_fops = {
- .open = ab5500_registers_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static int ab5500_bank_print(struct seq_file *s, void *p)
-{
- struct ab5500 *ab = s->private;
-
- seq_printf(s, "%d\n", ab->debug_bank);
- return 0;
-}
-
-static int ab5500_bank_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ab5500_bank_print, inode->i_private);
-}
-
-static ssize_t ab5500_bank_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private;
- char buf[32];
- int buf_size;
- unsigned long user_bank;
- int err;
-
- /* Get userspace string and assure termination */
- buf_size = min(count, (sizeof(buf) - 1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
- buf[buf_size] = 0;
-
- err = strict_strtoul(buf, 0, &user_bank);
- if (err)
- return -EINVAL;
-
- if (user_bank >= AB5500_NUM_BANKS) {
- dev_err(ab->dev,
- "debugfs error input > number of banks\n");
- return -EINVAL;
- }
-
- ab->debug_bank = user_bank;
-
- return buf_size;
-}
-
-static int ab5500_address_print(struct seq_file *s, void *p)
-{
- struct ab5500 *ab = s->private;
-
- seq_printf(s, "0x%02X\n", ab->debug_address);
- return 0;
-}
-
-static int ab5500_address_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ab5500_address_print, inode->i_private);
-}
-
-static ssize_t ab5500_address_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private;
- char buf[32];
- int buf_size;
- unsigned long user_address;
- int err;
-
- /* Get userspace string and assure termination */
- buf_size = min(count, (sizeof(buf) - 1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
- buf[buf_size] = 0;
-
- err = strict_strtoul(buf, 0, &user_address);
- if (err)
- return -EINVAL;
- if (user_address > 0xff) {
- dev_err(ab->dev,
- "debugfs error input > 0xff\n");
- return -EINVAL;
- }
- ab->debug_address = user_address;
- return buf_size;
-}
-
-static int ab5500_val_print(struct seq_file *s, void *p)
-{
- struct ab5500 *ab = s->private;
- int err;
- u8 regvalue;
-
- err = ab5500_get_register_interruptible_raw(ab, (u8)ab->debug_bank,
- (u8)ab->debug_address, &regvalue);
- if (err) {
- dev_err(ab->dev, "get_reg failed %d, bank 0x%x"
- ", reg 0x%x\n", err, ab->debug_bank,
- ab->debug_address);
- return -EINVAL;
- }
- seq_printf(s, "0x%02X\n", regvalue);
-
- return 0;
-}
-
-static int ab5500_val_open(struct inode *inode, struct file *file)
-{
- return single_open(file, ab5500_val_print, inode->i_private);
-}
-
-static ssize_t ab5500_val_write(struct file *file,
- const char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private;
- char buf[32];
- int buf_size;
- unsigned long user_val;
- int err;
- u8 regvalue;
-
- /* Get userspace string and assure termination */
- buf_size = min(count, (sizeof(buf)-1));
- if (copy_from_user(buf, user_buf, buf_size))
- return -EFAULT;
- buf[buf_size] = 0;
-
- err = strict_strtoul(buf, 0, &user_val);
- if (err)
- return -EINVAL;
- if (user_val > 0xff) {
- dev_err(ab->dev,
- "debugfs error input > 0xff\n");
- return -EINVAL;
- }
- err = ab5500_mask_and_set_register_interruptible_raw(
- ab, (u8)ab->debug_bank,
- (u8)ab->debug_address, 0xFF, (u8)user_val);
- if (err)
- return -EINVAL;
-
- ab5500_get_register_interruptible_raw(ab, (u8)ab->debug_bank,
- (u8)ab->debug_address, &regvalue);
- if (err)
- return -EINVAL;
-
- return buf_size;
-}
-
-static const struct file_operations ab5500_bank_fops = {
- .open = ab5500_bank_open,
- .write = ab5500_bank_write,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static const struct file_operations ab5500_address_fops = {
- .open = ab5500_address_open,
- .write = ab5500_address_write,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static const struct file_operations ab5500_val_fops = {
- .open = ab5500_val_open,
- .write = ab5500_val_write,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .owner = THIS_MODULE,
-};
-
-static struct dentry *ab5500_dir;
-static struct dentry *ab5500_reg_file;
-static struct dentry *ab5500_bank_file;
-static struct dentry *ab5500_address_file;
-static struct dentry *ab5500_val_file;
-
-void __init ab5500_setup_debugfs(struct ab5500 *ab)
-{
- ab->debug_bank = AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP;
- ab->debug_address = AB5500_CHIP_ID;
-
- ab5500_dir = debugfs_create_dir("ab5500", NULL);
- if (!ab5500_dir)
- goto exit_no_debugfs;
-
- ab5500_reg_file = debugfs_create_file("all-bank-registers",
- S_IRUGO, ab5500_dir, ab, &ab5500_registers_fops);
- if (!ab5500_reg_file)
- goto exit_destroy_dir;
-
- ab5500_bank_file = debugfs_create_file("register-bank",
- (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_bank_fops);
- if (!ab5500_bank_file)
- goto exit_destroy_reg;
-
- ab5500_address_file = debugfs_create_file("register-address",
- (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_address_fops);
- if (!ab5500_address_file)
- goto exit_destroy_bank;
-
- ab5500_val_file = debugfs_create_file("register-value",
- (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_val_fops);
- if (!ab5500_val_file)
- goto exit_destroy_address;
-
- return;
-
-exit_destroy_address:
- debugfs_remove(ab5500_address_file);
-exit_destroy_bank:
- debugfs_remove(ab5500_bank_file);
-exit_destroy_reg:
- debugfs_remove(ab5500_reg_file);
-exit_destroy_dir:
- debugfs_remove(ab5500_dir);
-exit_no_debugfs:
- dev_err(ab->dev, "failed to create debugfs entries.\n");
- return;
-}
-
-void __exit ab5500_remove_debugfs(void)
-{
- debugfs_remove(ab5500_val_file);
- debugfs_remove(ab5500_address_file);
- debugfs_remove(ab5500_bank_file);
- debugfs_remove(ab5500_reg_file);
- debugfs_remove(ab5500_dir);
-}
diff --git a/drivers/mfd/ab5500-debugfs.h b/drivers/mfd/ab5500-debugfs.h
deleted file mode 100644
index 7330a9b6afa6..000000000000
--- a/drivers/mfd/ab5500-debugfs.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2011 ST-Ericsson
- * License terms: GNU General Public License (GPL) version 2
- * Debugfs interface to the AB5500 core driver
- */
-
-#ifdef CONFIG_DEBUG_FS
-
-void ab5500_setup_debugfs(struct ab5500 *ab);
-void ab5500_remove_debugfs(void);
-
-#else /* !CONFIG_DEBUG_FS */
-
-static inline void ab5500_setup_debugfs(struct ab5500 *ab)
-{
-}
-
-static inline void ab5500_remove_debugfs(void)
-{
-}
-
-#endif
diff --git a/drivers/mfd/db5500-prcmu.c b/drivers/mfd/db5500-prcmu.c
deleted file mode 100644
index bb115b2f04e9..000000000000
--- a/drivers/mfd/db5500-prcmu.c
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License Terms: GNU General Public License v2
- * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
- *
- * U5500 PRCM Unit interface driver
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include <linux/completion.h>
-#include <linux/irq.h>
-#include <linux/jiffies.h>
-#include <linux/bitops.h>
-#include <linux/interrupt.h>
-#include <linux/mfd/dbx500-prcmu.h>
-#include <mach/hardware.h>
-#include <mach/irqs.h>
-#include <mach/db5500-regs.h>
-#include "dbx500-prcmu-regs.h"
-
-#define _PRCM_MB_HEADER (tcdm_base + 0xFE8)
-#define PRCM_REQ_MB0_HEADER (_PRCM_MB_HEADER + 0x0)
-#define PRCM_REQ_MB1_HEADER (_PRCM_MB_HEADER + 0x1)
-#define PRCM_REQ_MB2_HEADER (_PRCM_MB_HEADER + 0x2)
-#define PRCM_REQ_MB3_HEADER (_PRCM_MB_HEADER + 0x3)
-#define PRCM_REQ_MB4_HEADER (_PRCM_MB_HEADER + 0x4)
-#define PRCM_REQ_MB5_HEADER (_PRCM_MB_HEADER + 0x5)
-#define PRCM_REQ_MB6_HEADER (_PRCM_MB_HEADER + 0x6)
-#define PRCM_REQ_MB7_HEADER (_PRCM_MB_HEADER + 0x7)
-#define PRCM_ACK_MB0_HEADER (_PRCM_MB_HEADER + 0x8)
-#define PRCM_ACK_MB1_HEADER (_PRCM_MB_HEADER + 0x9)
-#define PRCM_ACK_MB2_HEADER (_PRCM_MB_HEADER + 0xa)
-#define PRCM_ACK_MB3_HEADER (_PRCM_MB_HEADER + 0xb)
-#define PRCM_ACK_MB4_HEADER (_PRCM_MB_HEADER + 0xc)
-#define PRCM_ACK_MB5_HEADER (_PRCM_MB_HEADER + 0xd)
-#define PRCM_ACK_MB6_HEADER (_PRCM_MB_HEADER + 0xe)
-#define PRCM_ACK_MB7_HEADER (_PRCM_MB_HEADER + 0xf)
-
-/* Req Mailboxes */
-#define PRCM_REQ_MB0 (tcdm_base + 0xFD8)
-#define PRCM_REQ_MB1 (tcdm_base + 0xFCC)
-#define PRCM_REQ_MB2 (tcdm_base + 0xFC4)
-#define PRCM_REQ_MB3 (tcdm_base + 0xFC0)
-#define PRCM_REQ_MB4 (tcdm_base + 0xF98)
-#define PRCM_REQ_MB5 (tcdm_base + 0xF90)
-#define PRCM_REQ_MB6 (tcdm_base + 0xF8C)
-#define PRCM_REQ_MB7 (tcdm_base + 0xF84)
-
-/* Ack Mailboxes */
-#define PRCM_ACK_MB0 (tcdm_base + 0xF38)
-#define PRCM_ACK_MB1 (tcdm_base + 0xF30)
-#define PRCM_ACK_MB2 (tcdm_base + 0xF24)
-#define PRCM_ACK_MB3 (tcdm_base + 0xF20)
-#define PRCM_ACK_MB4 (tcdm_base + 0xF1C)
-#define PRCM_ACK_MB5 (tcdm_base + 0xF14)
-#define PRCM_ACK_MB6 (tcdm_base + 0xF0C)
-#define PRCM_ACK_MB7 (tcdm_base + 0xF08)
-
-enum mb_return_code {
- RC_SUCCESS,
- RC_FAIL,
-};
-
-/* Mailbox 0 headers. */
-enum mb0_header {
- /* request */
- RMB0H_PWR_STATE_TRANS = 1,
- RMB0H_WAKE_UP_CFG,
- RMB0H_RD_WAKE_UP_ACK,
- /* acknowledge */
- AMB0H_WAKE_UP = 1,
-};
-
-/* Mailbox 5 headers. */
-enum mb5_header {
- MB5H_I2C_WRITE = 1,
- MB5H_I2C_READ,
-};
-
-/* Request mailbox 5 fields. */
-#define PRCM_REQ_MB5_I2C_SLAVE (PRCM_REQ_MB5 + 0)
-#define PRCM_REQ_MB5_I2C_REG (PRCM_REQ_MB5 + 1)
-#define PRCM_REQ_MB5_I2C_SIZE (PRCM_REQ_MB5 + 2)
-#define PRCM_REQ_MB5_I2C_DATA (PRCM_REQ_MB5 + 4)
-
-/* Acknowledge mailbox 5 fields. */
-#define PRCM_ACK_MB5_RETURN_CODE (PRCM_ACK_MB5 + 0)
-#define PRCM_ACK_MB5_I2C_DATA (PRCM_ACK_MB5 + 4)
-
-#define NUM_MB 8
-#define MBOX_BIT BIT
-#define ALL_MBOX_BITS (MBOX_BIT(NUM_MB) - 1)
-
-/*
-* Used by MCDE to setup all necessary PRCMU registers
-*/
-#define PRCMU_RESET_DSIPLL 0x00004000
-#define PRCMU_UNCLAMP_DSIPLL 0x00400800
-
-/* HDMI CLK MGT PLLSW=001 (PLLSOC0), PLLDIV=0x8, = 50 Mhz*/
-#define PRCMU_DSI_CLOCK_SETTING 0x00000128
-/* TVCLK_MGT PLLSW=001 (PLLSOC0) PLLDIV=0x13, = 19.05 MHZ */
-#define PRCMU_DSI_LP_CLOCK_SETTING 0x00000135
-#define PRCMU_PLLDSI_FREQ_SETTING 0x00020121
-#define PRCMU_DSI_PLLOUT_SEL_SETTING 0x00000002
-#define PRCMU_ENABLE_ESCAPE_CLOCK_DIV 0x03000201
-#define PRCMU_DISABLE_ESCAPE_CLOCK_DIV 0x00000101
-
-#define PRCMU_ENABLE_PLLDSI 0x00000001
-#define PRCMU_DISABLE_PLLDSI 0x00000000
-
-#define PRCMU_DSI_RESET_SW 0x00000003
-#define PRCMU_RESOUTN0_PIN 0x00000001
-#define PRCMU_RESOUTN1_PIN 0x00000002
-#define PRCMU_RESOUTN2_PIN 0x00000004
-
-#define PRCMU_PLLDSI_LOCKP_LOCKED 0x3
-
-/*
- * mb0_transfer - state needed for mailbox 0 communication.
- * @lock: The transaction lock.
- */
-static struct {
- spinlock_t lock;
-} mb0_transfer;
-
-/*
- * mb5_transfer - state needed for mailbox 5 communication.
- * @lock: The transaction lock.
- * @work: The transaction completion structure.
- * @ack: Reply ("acknowledge") data.
- */
-static struct {
- struct mutex lock;
- struct completion work;
- struct {
- u8 header;
- u8 status;
- u8 value[4];
- } ack;
-} mb5_transfer;
-
-/* PRCMU TCDM base IO address. */
-static __iomem void *tcdm_base;
-
-/**
- * db5500_prcmu_abb_read() - Read register value(s) from the ABB.
- * @slave: The I2C slave address.
- * @reg: The (start) register address.
- * @value: The read out value(s).
- * @size: The number of registers to read.
- *
- * Reads register value(s) from the ABB.
- * @size has to be <= 4.
- */
-int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
-{
- int r;
-
- if ((size < 1) || (4 < size))
- return -EINVAL;
-
- mutex_lock(&mb5_transfer.lock);
-
- while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
- cpu_relax();
- writeb(slave, PRCM_REQ_MB5_I2C_SLAVE);
- writeb(reg, PRCM_REQ_MB5_I2C_REG);
- writeb(size, PRCM_REQ_MB5_I2C_SIZE);
- writeb(MB5H_I2C_READ, PRCM_REQ_MB5_HEADER);
-
- writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
- wait_for_completion(&mb5_transfer.work);
-
- r = 0;
- if ((mb5_transfer.ack.header == MB5H_I2C_READ) &&
- (mb5_transfer.ack.status == RC_SUCCESS))
- memcpy(value, mb5_transfer.ack.value, (size_t)size);
- else
- r = -EIO;
-
- mutex_unlock(&mb5_transfer.lock);
-
- return r;
-}
-
-/**
- * db5500_prcmu_abb_write() - Write register value(s) to the ABB.
- * @slave: The I2C slave address.
- * @reg: The (start) register address.
- * @value: The value(s) to write.
- * @size: The number of registers to write.
- *
- * Writes register value(s) to the ABB.
- * @size has to be <= 4.
- */
-int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
-{
- int r;
-
- if ((size < 1) || (4 < size))
- return -EINVAL;
-
- mutex_lock(&mb5_transfer.lock);
-
- while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
- cpu_relax();
- writeb(slave, PRCM_REQ_MB5_I2C_SLAVE);
- writeb(reg, PRCM_REQ_MB5_I2C_REG);
- writeb(size, PRCM_REQ_MB5_I2C_SIZE);
- memcpy_toio(PRCM_REQ_MB5_I2C_DATA, value, size);
- writeb(MB5H_I2C_WRITE, PRCM_REQ_MB5_HEADER);
-
- writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
- wait_for_completion(&mb5_transfer.work);
-
- if ((mb5_transfer.ack.header == MB5H_I2C_WRITE) &&
- (mb5_transfer.ack.status == RC_SUCCESS))
- r = 0;
- else
- r = -EIO;
-
- mutex_unlock(&mb5_transfer.lock);
-
- return r;
-}
-
-int db5500_prcmu_enable_dsipll(void)
-{
- int i;
-
- /* Enable DSIPLL_RESETN resets */
- writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_CLR);
- /* Unclamp DSIPLL in/out */
- writel(PRCMU_UNCLAMP_DSIPLL, PRCM_MMIP_LS_CLAMP_CLR);
- /* Set DSI PLL FREQ */
- writel(PRCMU_PLLDSI_FREQ_SETTING, PRCM_PLLDSI_FREQ);
- writel(PRCMU_DSI_PLLOUT_SEL_SETTING,
- PRCM_DSI_PLLOUT_SEL);
- /* Enable Escape clocks */
- writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV);
-
- /* Start DSI PLL */
- writel(PRCMU_ENABLE_PLLDSI, PRCM_PLLDSI_ENABLE);
- /* Reset DSI PLL */
- writel(PRCMU_DSI_RESET_SW, PRCM_DSI_SW_RESET);
- for (i = 0; i < 10; i++) {
- if ((readl(PRCM_PLLDSI_LOCKP) &
- PRCMU_PLLDSI_LOCKP_LOCKED) == PRCMU_PLLDSI_LOCKP_LOCKED)
- break;
- udelay(100);
- }
- /* Release DSIPLL_RESETN */
- writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_SET);
- return 0;
-}
-
-int db5500_prcmu_disable_dsipll(void)
-{
- /* Disable dsi pll */
- writel(PRCMU_DISABLE_PLLDSI, PRCM_PLLDSI_ENABLE);
- /* Disable escapeclock */
- writel(PRCMU_DISABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV);
- return 0;
-}
-
-int db5500_prcmu_set_display_clocks(void)
-{
- /* HDMI and TVCLK Should be handled somewhere else */
- /* PLLDIV=8, PLLSW=2, CLKEN=1 */
- writel(PRCMU_DSI_CLOCK_SETTING, PRCM_HDMICLK_MGT);
- /* PLLDIV=14, PLLSW=2, CLKEN=1 */
- writel(PRCMU_DSI_LP_CLOCK_SETTING, PRCM_TVCLK_MGT);
- return 0;
-}
-
-static void ack_dbb_wakeup(void)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&mb0_transfer.lock, flags);
-
- while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
- cpu_relax();
-
- writeb(RMB0H_RD_WAKE_UP_ACK, PRCM_REQ_MB0_HEADER);
- writel(MBOX_BIT(0), PRCM_MBOX_CPU_SET);
-
- spin_unlock_irqrestore(&mb0_transfer.lock, flags);
-}
-
-static inline void print_unknown_header_warning(u8 n, u8 header)
-{
- pr_warning("prcmu: Unknown message header (%d) in mailbox %d.\n",
- header, n);
-}
-
-static bool read_mailbox_0(void)
-{
- bool r;
- u8 header;
-
- header = readb(PRCM_ACK_MB0_HEADER);
- switch (header) {
- case AMB0H_WAKE_UP:
- r = true;
- break;
- default:
- print_unknown_header_warning(0, header);
- r = false;
- break;
- }
- writel(MBOX_BIT(0), PRCM_ARM_IT1_CLR);
- return r;
-}
-
-static bool read_mailbox_1(void)
-{
- writel(MBOX_BIT(1), PRCM_ARM_IT1_CLR);
- return false;
-}
-
-static bool read_mailbox_2(void)
-{
- writel(MBOX_BIT(2), PRCM_ARM_IT1_CLR);
- return false;
-}
-
-static bool read_mailbox_3(void)
-{
- writel(MBOX_BIT(3), PRCM_ARM_IT1_CLR);
- return false;
-}
-
-static bool read_mailbox_4(void)
-{
- writel(MBOX_BIT(4), PRCM_ARM_IT1_CLR);
- return false;
-}
-
-static bool read_mailbox_5(void)
-{
- u8 header;
-
- header = readb(PRCM_ACK_MB5_HEADER);
- switch (header) {
- case MB5H_I2C_READ:
- memcpy_fromio(mb5_transfer.ack.value, PRCM_ACK_MB5_I2C_DATA, 4);
- case MB5H_I2C_WRITE:
- mb5_transfer.ack.header = header;
- mb5_transfer.ack.status = readb(PRCM_ACK_MB5_RETURN_CODE);
- complete(&mb5_transfer.work);
- break;
- default:
- print_unknown_header_warning(5, header);
- break;
- }
- writel(MBOX_BIT(5), PRCM_ARM_IT1_CLR);
- return false;
-}
-
-static bool read_mailbox_6(void)
-{
- writel(MBOX_BIT(6), PRCM_ARM_IT1_CLR);
- return false;
-}
-
-static bool read_mailbox_7(void)
-{
- writel(MBOX_BIT(7), PRCM_ARM_IT1_CLR);
- return false;
-}
-
-static bool (* const read_mailbox[NUM_MB])(void) = {
- read_mailbox_0,
- read_mailbox_1,
- read_mailbox_2,
- read_mailbox_3,
- read_mailbox_4,
- read_mailbox_5,
- read_mailbox_6,
- read_mailbox_7
-};
-
-static irqreturn_t prcmu_irq_handler(int irq, void *data)
-{
- u32 bits;
- u8 n;
- irqreturn_t r;
-
- bits = (readl(PRCM_ARM_IT1_VAL) & ALL_MBOX_BITS);
- if (unlikely(!bits))
- return IRQ_NONE;
-
- r = IRQ_HANDLED;
- for (n = 0; bits; n++) {
- if (bits & MBOX_BIT(n)) {
- bits -= MBOX_BIT(n);
- if (read_mailbox[n]())
- r = IRQ_WAKE_THREAD;
- }
- }
- return r;
-}
-
-static irqreturn_t prcmu_irq_thread_fn(int irq, void *data)
-{
- ack_dbb_wakeup();
- return IRQ_HANDLED;
-}
-
-void __init db5500_prcmu_early_init(void)
-{
- tcdm_base = __io_address(U5500_PRCMU_TCDM_BASE);
- spin_lock_init(&mb0_transfer.lock);
- mutex_init(&mb5_transfer.lock);
- init_completion(&mb5_transfer.work);
-}
-
-/**
- * prcmu_fw_init - arch init call for the Linux PRCMU fw init logic
- *
- */
-int __init db5500_prcmu_init(void)
-{
- int r = 0;
-
- if (ux500_is_svp() || !cpu_is_u5500())
- return -ENODEV;
-
- /* Clean up the mailbox interrupts after pre-kernel code. */
- writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR);
-
- r = request_threaded_irq(IRQ_DB5500_PRCMU1, prcmu_irq_handler,
- prcmu_irq_thread_fn, 0, "prcmu", NULL);
- if (r < 0) {
- pr_err("prcmu: Failed to allocate IRQ_DB5500_PRCMU1.\n");
- return -EBUSY;
- }
- return 0;
-}
-
-arch_initcall(db5500_prcmu_init);
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
index 9fd4f63c45cc..738722cdecaa 100644
--- a/drivers/mfd/mc13xxx-core.c
+++ b/drivers/mfd/mc13xxx-core.c
@@ -813,7 +813,8 @@ err_revision:
mc13xxx_add_subdevice(mc13xxx, "%s-adc");
if (mc13xxx->flags & MC13XXX_USE_CODEC)
- mc13xxx_add_subdevice(mc13xxx, "%s-codec");
+ mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec",
+ pdata->codec, sizeof(*pdata->codec));
if (mc13xxx->flags & MC13XXX_USE_RTC)
mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
diff --git a/drivers/mfd/tps65911-comparator.c b/drivers/mfd/tps65911-comparator.c
index e7ff783aa31e..5a62e6bf89ae 100644
--- a/drivers/mfd/tps65911-comparator.c
+++ b/drivers/mfd/tps65911-comparator.c
@@ -26,7 +26,7 @@
#define COMP1 1
#define COMP2 2
-/* Comparator 1 voltage selection table in milivolts */
+/* Comparator 1 voltage selection table in millivolts */
static const u16 COMP_VSEL_TABLE[] = {
0, 2500, 2500, 2500, 2500, 2550, 2600, 2650,
2700, 2750, 2800, 2850, 2900, 2950, 3000, 3050,
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index c7795096d43b..2661f6e366f9 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -452,14 +452,32 @@ config ARM_CHARLCD
still useful.
config BMP085
- tristate "BMP085 digital pressure sensor"
+ bool
+ depends on SYSFS
+
+config BMP085_I2C
+ tristate "BMP085 digital pressure sensor on I2C"
+ select BMP085
+ select REGMAP_I2C
depends on I2C && SYSFS
help
- If you say yes here you get support for the Bosch Sensortec
- BMP085 digital pressure sensor.
+ Say Y here if you want to support Bosch Sensortec's digital pressure
+ sensor hooked to an I2C bus.
To compile this driver as a module, choose M here: the
- module will be called bmp085.
+ module will be called bmp085-i2c.
+
+config BMP085_SPI
+ tristate "BMP085 digital pressure sensor on SPI"
+ select BMP085
+ select REGMAP_SPI
+ depends on SPI_MASTER && SYSFS
+ help
+ Say Y here if you want to support Bosch Sensortec's digital pressure
+ sensor hooked to an SPI bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bmp085-spi.
config PCH_PHUB
tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) PHUB"
@@ -490,14 +508,6 @@ config USB_SWITCH_FSA9480
stereo and mono audio, video, microphone and UART data to use
a common connector port.
-config MAX8997_MUIC
- tristate "MAX8997 MUIC Support"
- depends on MFD_MAX8997
- help
- If you say yes here you get support for the MUIC device of
- Maxim MAX8997 PMIC.
- The MAX8997 MUIC is a USB port accessory detector and switch.
-
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
@@ -506,4 +516,5 @@ source "drivers/misc/ti-st/Kconfig"
source "drivers/misc/lis3lv02d/Kconfig"
source "drivers/misc/carma/Kconfig"
source "drivers/misc/altera-stapl/Kconfig"
+source "drivers/misc/mei/Kconfig"
endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 3e1d80106f04..456972faaeb3 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -11,6 +11,8 @@ obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o
obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
obj-$(CONFIG_BMP085) += bmp085.o
+obj-$(CONFIG_BMP085_I2C) += bmp085-i2c.o
+obj-$(CONFIG_BMP085_SPI) += bmp085-spi.o
obj-$(CONFIG_ICS932S401) += ics932s401.o
obj-$(CONFIG_LKDTM) += lkdtm.o
obj-$(CONFIG_TIFM_CORE) += tifm_core.o
@@ -48,4 +50,4 @@ obj-y += lis3lv02d/
obj-y += carma/
obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/
-obj-$(CONFIG_MAX8997_MUIC) += max8997-muic.o
+obj-$(CONFIG_INTEL_MEI) += mei/
diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c
index 1d1d42615915..6938f1be664d 100644
--- a/drivers/misc/ad525x_dpot.c
+++ b/drivers/misc/ad525x_dpot.c
@@ -749,7 +749,7 @@ exit:
}
EXPORT_SYMBOL(ad_dpot_probe);
-__devexit int ad_dpot_remove(struct device *dev)
+int ad_dpot_remove(struct device *dev)
{
struct dpot_data *data = dev_get_drvdata(dev);
int i;
diff --git a/drivers/misc/bh1780gli.c b/drivers/misc/bh1780gli.c
index 54f6f39f990a..f1f9877f3fdf 100644
--- a/drivers/misc/bh1780gli.c
+++ b/drivers/misc/bh1780gli.c
@@ -248,7 +248,7 @@ static const struct i2c_device_id bh1780_id[] = {
static struct i2c_driver bh1780_driver = {
.probe = bh1780_probe,
- .remove = bh1780_remove,
+ .remove = __devexit_p(bh1780_remove),
.id_table = bh1780_id,
.driver = {
.name = "bh1780",
diff --git a/drivers/misc/bmp085-i2c.c b/drivers/misc/bmp085-i2c.c
new file mode 100644
index 000000000000..9943971c13e3
--- /dev/null
+++ b/drivers/misc/bmp085-i2c.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2012 Bosch Sensortec GmbH
+ * Copyright (c) 2012 Unixphere AB
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include "bmp085.h"
+
+#define BMP085_I2C_ADDRESS 0x77
+
+static const unsigned short normal_i2c[] = { BMP085_I2C_ADDRESS,
+ I2C_CLIENT_END };
+
+static int bmp085_i2c_detect(struct i2c_client *client,
+ struct i2c_board_info *info)
+{
+ if (client->addr != BMP085_I2C_ADDRESS)
+ return -ENODEV;
+
+ return bmp085_detect(&client->dev);
+}
+
+static int __devinit bmp085_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int err;
+ struct regmap *regmap = devm_regmap_init_i2c(client,
+ &bmp085_regmap_config);
+
+ if (IS_ERR(regmap)) {
+ err = PTR_ERR(regmap);
+ dev_err(&client->dev, "Failed to init regmap: %d\n", err);
+ return err;
+ }
+
+ return bmp085_probe(&client->dev, regmap);
+}
+
+static int bmp085_i2c_remove(struct i2c_client *client)
+{
+ return bmp085_remove(&client->dev);
+}
+
+static const struct of_device_id bmp085_of_match[] = {
+ { .compatible = "bosch,bmp085", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, bmp085_of_match);
+
+static const struct i2c_device_id bmp085_id[] = {
+ { BMP085_NAME, 0 },
+ { "bmp180", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, bmp085_id);
+
+static struct i2c_driver bmp085_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = BMP085_NAME,
+ .of_match_table = bmp085_of_match
+ },
+ .id_table = bmp085_id,
+ .probe = bmp085_i2c_probe,
+ .remove = __devexit_p(bmp085_i2c_remove),
+
+ .detect = bmp085_i2c_detect,
+ .address_list = normal_i2c
+};
+
+module_i2c_driver(bmp085_i2c_driver);
+
+MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>");
+MODULE_DESCRIPTION("BMP085 I2C bus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/bmp085-spi.c b/drivers/misc/bmp085-spi.c
new file mode 100644
index 000000000000..78aaff9b5231
--- /dev/null
+++ b/drivers/misc/bmp085-spi.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2012 Bosch Sensortec GmbH
+ * Copyright (c) 2012 Unixphere AB
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/err.h>
+#include "bmp085.h"
+
+static int __devinit bmp085_spi_probe(struct spi_device *client)
+{
+ int err;
+ struct regmap *regmap;
+
+ client->bits_per_word = 8;
+ err = spi_setup(client);
+ if (err < 0) {
+ dev_err(&client->dev, "spi_setup failed!\n");
+ return err;
+ }
+
+ regmap = devm_regmap_init_spi(client, &bmp085_regmap_config);
+ if (IS_ERR(regmap)) {
+ err = PTR_ERR(regmap);
+ dev_err(&client->dev, "Failed to init regmap: %d\n", err);
+ return err;
+ }
+
+ return bmp085_probe(&client->dev, regmap);
+}
+
+static int bmp085_spi_remove(struct spi_device *client)
+{
+ return bmp085_remove(&client->dev);
+}
+
+static const struct of_device_id bmp085_of_match[] = {
+ { .compatible = "bosch,bmp085", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, bmp085_of_match);
+
+static const struct spi_device_id bmp085_id[] = {
+ { "bmp180", 0 },
+ { "bmp181", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, bmp085_id);
+
+static struct spi_driver bmp085_spi_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = BMP085_NAME,
+ .of_match_table = bmp085_of_match
+ },
+ .id_table = bmp085_id,
+ .probe = bmp085_spi_probe,
+ .remove = __devexit_p(bmp085_spi_remove)
+};
+
+static int __init bmp085_spi_init(void)
+{
+ return spi_register_driver(&bmp085_spi_driver);
+}
+
+static void __exit bmp085_spi_exit(void)
+{
+ spi_unregister_driver(&bmp085_spi_driver);
+}
+
+MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>");
+MODULE_DESCRIPTION("BMP085 SPI bus driver");
+MODULE_LICENSE("GPL");
+
+module_init(bmp085_spi_init);
+module_exit(bmp085_spi_exit);
diff --git a/drivers/misc/bmp085.c b/drivers/misc/bmp085.c
index 76c3064629f1..62e418293b7e 100644
--- a/drivers/misc/bmp085.c
+++ b/drivers/misc/bmp085.c
@@ -1,62 +1,62 @@
/* Copyright (c) 2010 Christoph Mair <christoph.mair@gmail.com>
-
- This driver supports the bmp085 digital barometric pressure
- and temperature sensor from Bosch Sensortec. The datasheet
- is available from their website:
- http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP085-DS000-05.pdf
-
- A pressure measurement is issued by reading from pressure0_input.
- The return value ranges from 30000 to 110000 pascal with a resulution
- of 1 pascal (0.01 millibar) which enables measurements from 9000m above
- to 500m below sea level.
-
- The temperature can be read from temp0_input. Values range from
- -400 to 850 representing the ambient temperature in degree celsius
- multiplied by 10.The resolution is 0.1 celsius.
-
- Because ambient pressure is temperature dependent, a temperature
- measurement will be executed automatically even if the user is reading
- from pressure0_input. This happens if the last temperature measurement
- has been executed more then one second ago.
-
- To decrease RMS noise from pressure measurements, the bmp085 can
- autonomously calculate the average of up to eight samples. This is
- set up by writing to the oversampling sysfs file. Accepted values
- are 0, 1, 2 and 3. 2^x when x is the value written to this file
- specifies the number of samples used to calculate the ambient pressure.
- RMS noise is specified with six pascal (without averaging) and decreases
- down to 3 pascal when using an oversampling setting of 3.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
+ * Copyright (c) 2012 Bosch Sensortec GmbH
+ * Copyright (c) 2012 Unixphere AB
+ *
+ * This driver supports the bmp085 and bmp18x digital barometric pressure
+ * and temperature sensors from Bosch Sensortec. The datasheets
+ * are available from their website:
+ * http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP085-DS000-05.pdf
+ * http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP180-DS000-07.pdf
+ *
+ * A pressure measurement is issued by reading from pressure0_input.
+ * The return value ranges from 30000 to 110000 pascal with a resulution
+ * of 1 pascal (0.01 millibar) which enables measurements from 9000m above
+ * to 500m below sea level.
+ *
+ * The temperature can be read from temp0_input. Values range from
+ * -400 to 850 representing the ambient temperature in degree celsius
+ * multiplied by 10.The resolution is 0.1 celsius.
+ *
+ * Because ambient pressure is temperature dependent, a temperature
+ * measurement will be executed automatically even if the user is reading
+ * from pressure0_input. This happens if the last temperature measurement
+ * has been executed more then one second ago.
+ *
+ * To decrease RMS noise from pressure measurements, the bmp085 can
+ * autonomously calculate the average of up to eight samples. This is
+ * set up by writing to the oversampling sysfs file. Accepted values
+ * are 0, 1, 2 and 3. 2^x when x is the value written to this file
+ * specifies the number of samples used to calculate the ambient pressure.
+ * RMS noise is specified with six pascal (without averaging) and decreases
+ * down to 3 pascal when using an oversampling setting of 3.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
#include <linux/module.h>
+#include <linux/device.h>
#include <linux/init.h>
-#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/delay.h>
+#include <linux/of.h>
+#include "bmp085.h"
-
-#define BMP085_I2C_ADDRESS 0x77
#define BMP085_CHIP_ID 0x55
-
#define BMP085_CALIBRATION_DATA_START 0xAA
#define BMP085_CALIBRATION_DATA_LENGTH 11 /* 16 bit values */
#define BMP085_CHIP_ID_REG 0xD0
-#define BMP085_VERSION_REG 0xD1
#define BMP085_CTRL_REG 0xF4
#define BMP085_TEMP_MEASUREMENT 0x2E
#define BMP085_PRESSURE_MEASUREMENT 0x34
@@ -65,12 +65,6 @@
#define BMP085_CONVERSION_REGISTER_XLSB 0xF8
#define BMP085_TEMP_CONVERSION_TIME 5
-#define BMP085_CLIENT_NAME "bmp085"
-
-
-static const unsigned short normal_i2c[] = { BMP085_I2C_ADDRESS,
- I2C_CLIENT_END };
-
struct bmp085_calibration_data {
s16 AC1, AC2, AC3;
u16 AC4, AC5, AC6;
@@ -78,35 +72,30 @@ struct bmp085_calibration_data {
s16 MB, MC, MD;
};
-
-/* Each client has this additional data */
struct bmp085_data {
- struct i2c_client *client;
- struct mutex lock;
- struct bmp085_calibration_data calibration;
- u32 raw_temperature;
- u32 raw_pressure;
- unsigned char oversampling_setting;
+ struct device *dev;
+ struct regmap *regmap;
+ struct mutex lock;
+ struct bmp085_calibration_data calibration;
+ u8 oversampling_setting;
+ u32 raw_temperature;
+ u32 raw_pressure;
+ u32 temp_measurement_period;
unsigned long last_temp_measurement;
- s32 b6; /* calculated temperature correction coefficient */
+ u8 chip_id;
+ s32 b6; /* calculated temperature correction coefficient */
};
-
-static s32 bmp085_read_calibration_data(struct i2c_client *client)
+static s32 bmp085_read_calibration_data(struct bmp085_data *data)
{
u16 tmp[BMP085_CALIBRATION_DATA_LENGTH];
- struct bmp085_data *data = i2c_get_clientdata(client);
struct bmp085_calibration_data *cali = &(data->calibration);
- s32 status = i2c_smbus_read_i2c_block_data(client,
- BMP085_CALIBRATION_DATA_START,
- BMP085_CALIBRATION_DATA_LENGTH*sizeof(u16),
- (u8 *)tmp);
+ s32 status = regmap_bulk_read(data->regmap,
+ BMP085_CALIBRATION_DATA_START, (u8 *)tmp,
+ (BMP085_CALIBRATION_DATA_LENGTH << 1));
if (status < 0)
return status;
- if (status != BMP085_CALIBRATION_DATA_LENGTH*sizeof(u16))
- return -EIO;
-
cali->AC1 = be16_to_cpu(tmp[0]);
cali->AC2 = be16_to_cpu(tmp[1]);
cali->AC3 = be16_to_cpu(tmp[2]);
@@ -121,30 +110,26 @@ static s32 bmp085_read_calibration_data(struct i2c_client *client)
return 0;
}
-
static s32 bmp085_update_raw_temperature(struct bmp085_data *data)
{
u16 tmp;
s32 status;
mutex_lock(&data->lock);
- status = i2c_smbus_write_byte_data(data->client, BMP085_CTRL_REG,
- BMP085_TEMP_MEASUREMENT);
- if (status != 0) {
- dev_err(&data->client->dev,
+ status = regmap_write(data->regmap, BMP085_CTRL_REG,
+ BMP085_TEMP_MEASUREMENT);
+ if (status < 0) {
+ dev_err(data->dev,
"Error while requesting temperature measurement.\n");
goto exit;
}
msleep(BMP085_TEMP_CONVERSION_TIME);
- status = i2c_smbus_read_i2c_block_data(data->client,
- BMP085_CONVERSION_REGISTER_MSB, sizeof(tmp), (u8 *)&tmp);
- if (status < 0)
- goto exit;
- if (status != sizeof(tmp)) {
- dev_err(&data->client->dev,
+ status = regmap_bulk_read(data->regmap, BMP085_CONVERSION_REGISTER_MSB,
+ &tmp, sizeof(tmp));
+ if (status < 0) {
+ dev_err(data->dev,
"Error while reading temperature measurement result\n");
- status = -EIO;
goto exit;
}
data->raw_temperature = be16_to_cpu(tmp);
@@ -162,10 +147,11 @@ static s32 bmp085_update_raw_pressure(struct bmp085_data *data)
s32 status;
mutex_lock(&data->lock);
- status = i2c_smbus_write_byte_data(data->client, BMP085_CTRL_REG,
- BMP085_PRESSURE_MEASUREMENT + (data->oversampling_setting<<6));
- if (status != 0) {
- dev_err(&data->client->dev,
+ status = regmap_write(data->regmap, BMP085_CTRL_REG,
+ BMP085_PRESSURE_MEASUREMENT +
+ (data->oversampling_setting << 6));
+ if (status < 0) {
+ dev_err(data->dev,
"Error while requesting pressure measurement.\n");
goto exit;
}
@@ -174,14 +160,11 @@ static s32 bmp085_update_raw_pressure(struct bmp085_data *data)
msleep(2+(3 << data->oversampling_setting));
/* copy data into a u32 (4 bytes), but skip the first byte. */
- status = i2c_smbus_read_i2c_block_data(data->client,
- BMP085_CONVERSION_REGISTER_MSB, 3, ((u8 *)&tmp)+1);
- if (status < 0)
- goto exit;
- if (status != 3) {
- dev_err(&data->client->dev,
+ status = regmap_bulk_read(data->regmap, BMP085_CONVERSION_REGISTER_MSB,
+ ((u8 *)&tmp)+1, 3);
+ if (status < 0) {
+ dev_err(data->dev,
"Error while reading pressure measurement results\n");
- status = -EIO;
goto exit;
}
data->raw_pressure = be32_to_cpu((tmp));
@@ -193,7 +176,6 @@ exit:
return status;
}
-
/*
* This function starts the temperature measurement and returns the value
* in tenth of a degree celsius.
@@ -205,7 +187,7 @@ static s32 bmp085_get_temperature(struct bmp085_data *data, int *temperature)
int status;
status = bmp085_update_raw_temperature(data);
- if (status != 0)
+ if (status < 0)
goto exit;
x1 = ((data->raw_temperature - cali->AC6) * cali->AC5) >> 15;
@@ -222,8 +204,10 @@ exit:
/*
* This function starts the pressure measurement and returns the value
* in millibar. Since the pressure depends on the ambient temperature,
- * a temperature measurement is executed if the last known value is older
- * than one second.
+ * a temperature measurement is executed according to the given temperature
+ * measurement period (default is 1 sec boundary). This period could vary
+ * and needs to be adjusted according to the sensor environment, i.e. if big
+ * temperature variations then the temperature needs to be read out often.
*/
static s32 bmp085_get_pressure(struct bmp085_data *data, int *pressure)
{
@@ -234,16 +218,16 @@ static s32 bmp085_get_pressure(struct bmp085_data *data, int *pressure)
int status;
/* alt least every second force an update of the ambient temperature */
- if (data->last_temp_measurement == 0 ||
- time_is_before_jiffies(data->last_temp_measurement + 1*HZ)) {
+ if ((data->last_temp_measurement == 0) ||
+ time_is_before_jiffies(data->last_temp_measurement + 1*HZ)) {
status = bmp085_get_temperature(data, NULL);
- if (status != 0)
- goto exit;
+ if (status < 0)
+ return status;
}
status = bmp085_update_raw_pressure(data);
- if (status != 0)
- goto exit;
+ if (status < 0)
+ return status;
x1 = (data->b6 * data->b6) >> 12;
x1 *= cali->B2;
@@ -274,15 +258,14 @@ static s32 bmp085_get_pressure(struct bmp085_data *data, int *pressure)
*pressure = p;
-exit:
- return status;
+ return 0;
}
/*
* This function sets the chip-internal oversampling. Valid values are 0..3.
* The chip will use 2^oversampling samples for internal averaging.
* This influences the measurement time and the accuracy; larger values
- * increase both. The datasheet gives on overview on how measurement time,
+ * increase both. The datasheet gives an overview on how measurement time,
* accuracy and noise correlate.
*/
static void bmp085_set_oversampling(struct bmp085_data *data,
@@ -306,22 +289,25 @@ static ssize_t set_oversampling(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct bmp085_data *data = i2c_get_clientdata(client);
+ struct bmp085_data *data = dev_get_drvdata(dev);
unsigned long oversampling;
- int success = strict_strtoul(buf, 10, &oversampling);
- if (success == 0) {
+ int err = kstrtoul(buf, 10, &oversampling);
+
+ if (err == 0) {
+ mutex_lock(&data->lock);
bmp085_set_oversampling(data, oversampling);
+ mutex_unlock(&data->lock);
return count;
}
- return success;
+
+ return err;
}
static ssize_t show_oversampling(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct bmp085_data *data = i2c_get_clientdata(client);
+ struct bmp085_data *data = dev_get_drvdata(dev);
+
return sprintf(buf, "%u\n", bmp085_get_oversampling(data));
}
static DEVICE_ATTR(oversampling, S_IWUSR | S_IRUGO,
@@ -333,11 +319,10 @@ static ssize_t show_temperature(struct device *dev,
{
int temperature;
int status;
- struct i2c_client *client = to_i2c_client(dev);
- struct bmp085_data *data = i2c_get_clientdata(client);
+ struct bmp085_data *data = dev_get_drvdata(dev);
status = bmp085_get_temperature(data, &temperature);
- if (status != 0)
+ if (status < 0)
return status;
else
return sprintf(buf, "%d\n", temperature);
@@ -350,11 +335,10 @@ static ssize_t show_pressure(struct device *dev,
{
int pressure;
int status;
- struct i2c_client *client = to_i2c_client(dev);
- struct bmp085_data *data = i2c_get_clientdata(client);
+ struct bmp085_data *data = dev_get_drvdata(dev);
status = bmp085_get_pressure(data, &pressure);
- if (status != 0)
+ if (status < 0)
return status;
else
return sprintf(buf, "%d\n", pressure);
@@ -373,38 +357,70 @@ static const struct attribute_group bmp085_attr_group = {
.attrs = bmp085_attributes,
};
-static int bmp085_detect(struct i2c_client *client, struct i2c_board_info *info)
+int bmp085_detect(struct device *dev)
{
- if (client->addr != BMP085_I2C_ADDRESS)
- return -ENODEV;
+ struct bmp085_data *data = dev_get_drvdata(dev);
+ unsigned int id;
+ int ret;
- if (i2c_smbus_read_byte_data(client, BMP085_CHIP_ID_REG) != BMP085_CHIP_ID)
+ ret = regmap_read(data->regmap, BMP085_CHIP_ID_REG, &id);
+ if (ret < 0)
+ return ret;
+
+ if (id != data->chip_id)
return -ENODEV;
return 0;
}
+EXPORT_SYMBOL_GPL(bmp085_detect);
-static int bmp085_init_client(struct i2c_client *client)
+static void __init bmp085_get_of_properties(struct bmp085_data *data)
{
- unsigned char version;
- int status;
- struct bmp085_data *data = i2c_get_clientdata(client);
- data->client = client;
- status = bmp085_read_calibration_data(client);
- if (status != 0)
- goto exit;
- version = i2c_smbus_read_byte_data(client, BMP085_VERSION_REG);
+#ifdef CONFIG_OF
+ struct device_node *np = data->dev->of_node;
+ u32 prop;
+
+ if (!np)
+ return;
+
+ if (!of_property_read_u32(np, "chip-id", &prop))
+ data->chip_id = prop & 0xff;
+
+ if (!of_property_read_u32(np, "temp-measurement-period", &prop))
+ data->temp_measurement_period = (prop/100)*HZ;
+
+ if (!of_property_read_u32(np, "default-oversampling", &prop))
+ data->oversampling_setting = prop & 0xff;
+#endif
+}
+
+static int bmp085_init_client(struct bmp085_data *data)
+{
+ int status = bmp085_read_calibration_data(data);
+
+ if (status < 0)
+ return status;
+
+ /* default settings */
+ data->chip_id = BMP085_CHIP_ID;
data->last_temp_measurement = 0;
+ data->temp_measurement_period = 1*HZ;
data->oversampling_setting = 3;
+
+ bmp085_get_of_properties(data);
+
mutex_init(&data->lock);
- dev_info(&data->client->dev, "BMP085 ver. %d.%d found.\n",
- (version & 0x0F), (version & 0xF0) >> 4);
-exit:
- return status;
+
+ return 0;
}
-static int __devinit bmp085_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+struct regmap_config bmp085_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8
+};
+EXPORT_SYMBOL_GPL(bmp085_regmap_config);
+
+__devinit int bmp085_probe(struct device *dev, struct regmap *regmap)
{
struct bmp085_data *data;
int err = 0;
@@ -415,58 +431,48 @@ static int __devinit bmp085_probe(struct i2c_client *client,
goto exit;
}
- /* default settings after POR */
- data->oversampling_setting = 0x00;
-
- i2c_set_clientdata(client, data);
+ dev_set_drvdata(dev, data);
+ data->dev = dev;
+ data->regmap = regmap;
/* Initialize the BMP085 chip */
- err = bmp085_init_client(client);
- if (err != 0)
+ err = bmp085_init_client(data);
+ if (err < 0)
goto exit_free;
+ err = bmp085_detect(dev);
+ if (err < 0) {
+ dev_err(dev, "%s: chip_id failed!\n", BMP085_NAME);
+ goto exit_free;
+ }
+
/* Register sysfs hooks */
- err = sysfs_create_group(&client->dev.kobj, &bmp085_attr_group);
+ err = sysfs_create_group(&dev->kobj, &bmp085_attr_group);
if (err)
goto exit_free;
- dev_info(&data->client->dev, "Successfully initialized bmp085!\n");
- goto exit;
+ dev_info(dev, "Successfully initialized %s!\n", BMP085_NAME);
+
+ return 0;
exit_free:
kfree(data);
exit:
return err;
}
+EXPORT_SYMBOL_GPL(bmp085_probe);
-static int __devexit bmp085_remove(struct i2c_client *client)
+int bmp085_remove(struct device *dev)
{
- sysfs_remove_group(&client->dev.kobj, &bmp085_attr_group);
- kfree(i2c_get_clientdata(client));
- return 0;
-}
+ struct bmp085_data *data = dev_get_drvdata(dev);
-static const struct i2c_device_id bmp085_id[] = {
- { "bmp085", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, bmp085_id);
-
-static struct i2c_driver bmp085_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "bmp085"
- },
- .id_table = bmp085_id,
- .probe = bmp085_probe,
- .remove = __devexit_p(bmp085_remove),
-
- .detect = bmp085_detect,
- .address_list = normal_i2c
-};
+ sysfs_remove_group(&data->dev->kobj, &bmp085_attr_group);
+ kfree(data);
-module_i2c_driver(bmp085_driver);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(bmp085_remove);
-MODULE_AUTHOR("Christoph Mair <christoph.mair@gmail.com");
+MODULE_AUTHOR("Christoph Mair <christoph.mair@gmail.com>");
MODULE_DESCRIPTION("BMP085 driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/misc/bmp085.h b/drivers/misc/bmp085.h
new file mode 100644
index 000000000000..2b8f615bca92
--- /dev/null
+++ b/drivers/misc/bmp085.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2012 Bosch Sensortec GmbH
+ * Copyright (c) 2012 Unixphere AB
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _BMP085_H
+#define _BMP085_H
+
+#include <linux/regmap.h>
+
+#define BMP085_NAME "bmp085"
+
+extern struct regmap_config bmp085_regmap_config;
+
+int bmp085_probe(struct device *dev, struct regmap *regmap);
+int bmp085_remove(struct device *dev);
+int bmp085_detect(struct device *dev);
+
+#endif
diff --git a/drivers/misc/c2port/Kconfig b/drivers/misc/c2port/Kconfig
index e46af9a5810d..33ee834e1b83 100644
--- a/drivers/misc/c2port/Kconfig
+++ b/drivers/misc/c2port/Kconfig
@@ -5,7 +5,7 @@
menuconfig C2PORT
tristate "Silicon Labs C2 port support (EXPERIMENTAL)"
depends on EXPERIMENTAL
- default no
+ default n
help
This option enables support for Silicon Labs C2 port used to
program Silicon micro controller chips (and other 8051 compatible).
@@ -23,8 +23,8 @@ if C2PORT
config C2PORT_DURAMAR_2150
tristate "C2 port support for Eurotech's Duramar 2150 (EXPERIMENTAL)"
- depends on X86 && C2PORT
- default no
+ depends on X86
+ default n
help
This option enables C2 support for the Eurotech's Duramar 2150
on board micro controller.
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index 01ab3c9b4cf7..0842c2994ee2 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -50,6 +50,7 @@ struct at25_data {
#define AT25_SR_BP1 0x08
#define AT25_SR_WPEN 0x80 /* writeprotect enable */
+#define AT25_INSTR_BIT3 0x08 /* Additional address bit in instr */
#define EE_MAXADDRLEN 3 /* 24 bit addresses, up to 2 MBytes */
@@ -75,6 +76,7 @@ at25_ee_read(
ssize_t status;
struct spi_transfer t[2];
struct spi_message m;
+ u8 instr;
if (unlikely(offset >= at25->bin.size))
return 0;
@@ -84,7 +86,12 @@ at25_ee_read(
return count;
cp = command;
- *cp++ = AT25_READ;
+
+ instr = AT25_READ;
+ if (at25->chip.flags & EE_INSTR_BIT3_IS_ADDR)
+ if (offset >= (1U << (at25->addrlen * 8)))
+ instr |= AT25_INSTR_BIT3;
+ *cp++ = instr;
/* 8/16/24-bit address is written MSB first */
switch (at25->addrlen) {
@@ -167,14 +174,14 @@ at25_ee_write(struct at25_data *at25, const char *buf, loff_t off,
/* For write, rollover is within the page ... so we write at
* most one page, then manually roll over to the next page.
*/
- bounce[0] = AT25_WRITE;
mutex_lock(&at25->lock);
do {
unsigned long timeout, retries;
unsigned segment;
unsigned offset = (unsigned) off;
- u8 *cp = bounce + 1;
+ u8 *cp = bounce;
int sr;
+ u8 instr;
*cp = AT25_WREN;
status = spi_write(at25->spi, cp, 1);
@@ -184,6 +191,12 @@ at25_ee_write(struct at25_data *at25, const char *buf, loff_t off,
break;
}
+ instr = AT25_WRITE;
+ if (at25->chip.flags & EE_INSTR_BIT3_IS_ADDR)
+ if (offset >= (1U << (at25->addrlen * 8)))
+ instr |= AT25_INSTR_BIT3;
+ *cp++ = instr;
+
/* 8/16/24-bit address is written MSB first */
switch (at25->addrlen) {
default: /* case 3 */
diff --git a/drivers/staging/mei/Kconfig b/drivers/misc/mei/Kconfig
index 47d78a72db2e..47d78a72db2e 100644
--- a/drivers/staging/mei/Kconfig
+++ b/drivers/misc/mei/Kconfig
diff --git a/drivers/staging/mei/Makefile b/drivers/misc/mei/Makefile
index 57168db6c7e5..57168db6c7e5 100644
--- a/drivers/staging/mei/Makefile
+++ b/drivers/misc/mei/Makefile
diff --git a/drivers/staging/mei/hw.h b/drivers/misc/mei/hw.h
index 24c4c962819e..24c4c962819e 100644
--- a/drivers/staging/mei/hw.h
+++ b/drivers/misc/mei/hw.h
diff --git a/drivers/staging/mei/init.c b/drivers/misc/mei/init.c
index eab711fb5fc4..a7d0bb0880ec 100644
--- a/drivers/staging/mei/init.c
+++ b/drivers/misc/mei/init.c
@@ -22,7 +22,7 @@
#include "mei_dev.h"
#include "hw.h"
#include "interface.h"
-#include "mei.h"
+#include <linux/mei.h>
const uuid_le mei_amthi_guid = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac,
0xa8, 0x46, 0xe0, 0xff, 0x65,
@@ -200,7 +200,7 @@ int mei_hw_init(struct mei_device *dev)
if (!(dev->me_hw_state & ME_RDY_HRA))
dev_dbg(&dev->pdev->dev, "ME turn off ME_RDY.\n");
- printk(KERN_ERR "mei: link layer initialization failed.\n");
+ dev_err(&dev->pdev->dev, "link layer initialization failed.\n");
ret = -ENODEV;
goto out;
}
diff --git a/drivers/staging/mei/interface.c b/drivers/misc/mei/interface.c
index 9a2cfafc52a6..428d21e36416 100644
--- a/drivers/staging/mei/interface.c
+++ b/drivers/misc/mei/interface.c
@@ -16,7 +16,7 @@
#include <linux/pci.h>
#include "mei_dev.h"
-#include "mei.h"
+#include <linux/mei.h>
#include "interface.h"
diff --git a/drivers/staging/mei/interface.h b/drivers/misc/mei/interface.h
index fb90c6f8a759..ddff5d16616f 100644
--- a/drivers/staging/mei/interface.h
+++ b/drivers/misc/mei/interface.h
@@ -19,7 +19,7 @@
#ifndef _MEI_INTERFACE_H_
#define _MEI_INTERFACE_H_
-#include "mei.h"
+#include <linux/mei.h>
#include "mei_dev.h"
@@ -51,8 +51,7 @@ int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl);
int mei_wd_send(struct mei_device *dev);
int mei_wd_stop(struct mei_device *dev, bool preserve);
-bool mei_wd_host_init(struct mei_device *dev);
-void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout);
+int mei_wd_host_init(struct mei_device *dev);
/*
* mei_watchdog_register - Registering watchdog interface
* once we got connection to the WD Client
diff --git a/drivers/staging/mei/interrupt.c b/drivers/misc/mei/interrupt.c
index 2007d2447b1c..93936f1b75eb 100644
--- a/drivers/staging/mei/interrupt.c
+++ b/drivers/misc/mei/interrupt.c
@@ -22,7 +22,7 @@
#include <linux/jiffies.h>
#include "mei_dev.h"
-#include "mei.h"
+#include <linux/mei.h>
#include "hw.h"
#include "interface.h"
diff --git a/drivers/staging/mei/iorw.c b/drivers/misc/mei/iorw.c
index 0a80dc4e62f3..f9cced69b65e 100644
--- a/drivers/staging/mei/iorw.c
+++ b/drivers/misc/mei/iorw.c
@@ -35,7 +35,7 @@
#include "mei_dev.h"
#include "hw.h"
-#include "mei.h"
+#include <linux/mei.h>
#include "interface.h"
diff --git a/drivers/staging/mei/main.c b/drivers/misc/mei/main.c
index 7c9321fa7bb1..c70333228337 100644
--- a/drivers/staging/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -14,6 +14,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -36,19 +38,10 @@
#include <linux/miscdevice.h>
#include "mei_dev.h"
-#include "mei.h"
+#include <linux/mei.h>
#include "interface.h"
-
-#define MEI_READ_TIMEOUT 45
-#define MEI_DRIVER_NAME "mei"
-#define MEI_DEV_NAME "mei"
-
-/*
- * mei driver strings
- */
-static char mei_driver_name[] = MEI_DRIVER_NAME;
-static const char mei_driver_string[] = "Intel(R) Management Engine Interface";
+static const char mei_driver_name[] = "mei";
/* The device pointer */
/* Currently this driver works as long as there is only a single AMT device. */
@@ -931,7 +924,7 @@ static const struct file_operations mei_fops = {
* Misc Device Struct
*/
static struct miscdevice mei_misc_device = {
- .name = MEI_DRIVER_NAME,
+ .name = "mei",
.fops = &mei_fops,
.minor = MISC_DYNAMIC_MINOR,
};
@@ -958,7 +951,7 @@ static int __devinit mei_probe(struct pci_dev *pdev,
/* enable pci dev */
err = pci_enable_device(pdev);
if (err) {
- printk(KERN_ERR "mei: Failed to enable pci device.\n");
+ dev_err(&pdev->dev, "failed to enable pci device.\n");
goto end;
}
/* set PCI host mastering */
@@ -966,7 +959,7 @@ static int __devinit mei_probe(struct pci_dev *pdev,
/* pci request regions for mei driver */
err = pci_request_regions(pdev, mei_driver_name);
if (err) {
- printk(KERN_ERR "mei: Failed to get pci regions.\n");
+ dev_err(&pdev->dev, "failed to get pci regions.\n");
goto disable_device;
}
/* allocates and initializes the mei dev structure */
@@ -978,7 +971,7 @@ static int __devinit mei_probe(struct pci_dev *pdev,
/* mapping IO device memory */
dev->mem_addr = pci_iomap(pdev, 0, 0);
if (!dev->mem_addr) {
- printk(KERN_ERR "mei: mapping I/O device memory failure.\n");
+ dev_err(&pdev->dev, "mapping I/O device memory failure.\n");
err = -ENOMEM;
goto free_device;
}
@@ -997,13 +990,13 @@ static int __devinit mei_probe(struct pci_dev *pdev,
IRQF_SHARED, mei_driver_name, dev);
if (err) {
- printk(KERN_ERR "mei: request_threaded_irq failure. irq = %d\n",
+ dev_err(&pdev->dev, "request_threaded_irq failure. irq = %d\n",
pdev->irq);
goto unmap_memory;
}
INIT_DELAYED_WORK(&dev->timer_work, mei_timer);
if (mei_hw_init(dev)) {
- printk(KERN_ERR "mei: Init hw failure.\n");
+ dev_err(&pdev->dev, "init hw failure.\n");
err = -ENODEV;
goto release_irq;
}
@@ -1020,7 +1013,7 @@ static int __devinit mei_probe(struct pci_dev *pdev,
mutex_unlock(&mei_mutex);
- pr_debug("mei: Driver initialization successful.\n");
+ pr_debug("initialization successful.\n");
return 0;
@@ -1041,7 +1034,7 @@ disable_device:
pci_disable_device(pdev);
end:
mutex_unlock(&mei_mutex);
- printk(KERN_ERR "mei: Driver initialization failed.\n");
+ dev_err(&pdev->dev, "initialization failed.\n");
return err;
}
@@ -1160,8 +1153,8 @@ static int mei_pci_resume(struct device *device)
IRQF_SHARED, mei_driver_name, dev);
if (err) {
- printk(KERN_ERR "mei: Request_irq failure. irq = %d\n",
- pdev->irq);
+ dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n",
+ pdev->irq);
return err;
}
@@ -1204,11 +1197,11 @@ static int __init mei_init_module(void)
{
int ret;
- pr_debug("mei: %s\n", mei_driver_string);
+ pr_debug("loading.\n");
/* init pci module */
ret = pci_register_driver(&mei_driver);
if (ret < 0)
- printk(KERN_ERR "mei: Error registering driver.\n");
+ pr_err("error registering driver.\n");
return ret;
}
@@ -1226,7 +1219,7 @@ static void __exit mei_exit_module(void)
misc_deregister(&mei_misc_device);
pci_unregister_driver(&mei_driver);
- pr_debug("mei: Driver unloaded successfully.\n");
+ pr_debug("unloaded successfully.\n");
}
module_exit(mei_exit_module);
diff --git a/drivers/staging/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 10b1b4e2f8ac..63d7ee97c5fb 100644
--- a/drivers/staging/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -19,7 +19,7 @@
#include <linux/types.h>
#include <linux/watchdog.h>
-#include "mei.h"
+#include <linux/mei.h>
#include "hw.h"
/*
diff --git a/drivers/staging/mei/wd.c b/drivers/misc/mei/wd.c
index cf4c29d10e7f..6be5605707b4 100644
--- a/drivers/staging/mei/wd.c
+++ b/drivers/misc/mei/wd.c
@@ -24,7 +24,7 @@
#include "mei_dev.h"
#include "hw.h"
#include "interface.h"
-#include "mei.h"
+#include <linux/mei.h>
static const u8 mei_start_wd_params[] = { 0x02, 0x12, 0x13, 0x10 };
static const u8 mei_stop_wd_params[] = { 0x02, 0x02, 0x14, 0x10 };
@@ -45,23 +45,22 @@ const uuid_le mei_wd_guid = UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, 0x89,
0x9D, 0xA9, 0x15, 0x14, 0xCB,
0x32, 0xAB);
-void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
+static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
{
- dev_dbg(&dev->pdev->dev, "timeout=%d.\n", timeout);
+ dev_dbg(&dev->pdev->dev, "wd: set timeout=%d.\n", timeout);
memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE);
- memcpy(dev->wd_data + MEI_WD_PARAMS_SIZE,
- &timeout, sizeof(u16));
+ memcpy(dev->wd_data + MEI_WD_PARAMS_SIZE, &timeout, sizeof(u16));
}
/**
* host_init_wd - mei initialization wd.
*
* @dev: the device structure
+ * returns -ENENT if wd client cannot be found
+ * -EIO if write has failed
*/
-bool mei_wd_host_init(struct mei_device *dev)
+int mei_wd_host_init(struct mei_device *dev)
{
- bool ret = false;
-
mei_cl_init(&dev->wd_cl, dev);
/* look for WD client and connect to it */
@@ -72,25 +71,21 @@ bool mei_wd_host_init(struct mei_device *dev)
mei_find_me_client_update_filext(dev, &dev->wd_cl,
&mei_wd_guid, MEI_WD_HOST_CLIENT_ID);
- dev_dbg(&dev->pdev->dev, "check wd_cl\n");
- if (MEI_FILE_CONNECTING == dev->wd_cl.state) {
- if (mei_connect(dev, &dev->wd_cl)) {
- dev_dbg(&dev->pdev->dev, "Failed to connect to WD client\n");
- dev->wd_cl.state = MEI_FILE_DISCONNECTED;
- dev->wd_cl.host_client_id = 0;
- ret = false;
- goto end;
- } else {
- dev->wd_cl.timer_count = CONNECT_TIMEOUT;
- }
- } else {
- dev_dbg(&dev->pdev->dev, "Failed to find WD client\n");
- ret = false;
- goto end;
+ dev_dbg(&dev->pdev->dev, "wd: check client\n");
+ if (MEI_FILE_CONNECTING != dev->wd_cl.state) {
+ dev_info(&dev->pdev->dev, "wd: failed to find the client\n");
+ return -ENOENT;
}
-end:
- return ret;
+ if (mei_connect(dev, &dev->wd_cl)) {
+ dev_err(&dev->pdev->dev, "wd: failed to connect to the client\n");
+ dev->wd_cl.state = MEI_FILE_DISCONNECTED;
+ dev->wd_cl.host_client_id = 0;
+ return -EIO;
+ }
+ dev->wd_cl.timer_count = CONNECT_TIMEOUT;
+
+ return 0;
}
/**
@@ -159,7 +154,7 @@ int mei_wd_stop(struct mei_device *dev, bool preserve)
if (ret)
goto out;
} else {
- dev_dbg(&dev->pdev->dev, "send stop WD failed\n");
+ dev_err(&dev->pdev->dev, "wd: send stop failed\n");
}
dev->wd_pending = false;
@@ -173,13 +168,13 @@ int mei_wd_stop(struct mei_device *dev, bool preserve)
dev->wd_stopped, 10 * HZ);
mutex_lock(&dev->device_lock);
if (dev->wd_stopped) {
- dev_dbg(&dev->pdev->dev, "stop wd complete ret=%d.\n", ret);
+ dev_dbg(&dev->pdev->dev, "wd: stop completed ret=%d.\n", ret);
ret = 0;
} else {
if (!ret)
ret = -ETIMEDOUT;
dev_warn(&dev->pdev->dev,
- "stop wd failed to complete ret=%d.\n", ret);
+ "wd: stop failed to complete ret=%d.\n", ret);
}
if (preserve)
@@ -208,13 +203,15 @@ static int mei_wd_ops_start(struct watchdog_device *wd_dev)
mutex_lock(&dev->device_lock);
if (dev->mei_state != MEI_ENABLED) {
- dev_dbg(&dev->pdev->dev, "mei_state != MEI_ENABLED mei_state= %d\n",
- dev->mei_state);
+ dev_dbg(&dev->pdev->dev,
+ "wd: mei_state != MEI_ENABLED mei_state = %d\n",
+ dev->mei_state);
goto end_unlock;
}
if (dev->wd_cl.state != MEI_FILE_CONNECTED) {
- dev_dbg(&dev->pdev->dev, "MEI Driver is not connected to Watchdog Client\n");
+ dev_dbg(&dev->pdev->dev,
+ "MEI Driver is not connected to Watchdog Client\n");
goto end_unlock;
}
@@ -267,7 +264,7 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
mutex_lock(&dev->device_lock);
if (dev->wd_cl.state != MEI_FILE_CONNECTED) {
- dev_dbg(&dev->pdev->dev, "wd is not connected.\n");
+ dev_err(&dev->pdev->dev, "wd: not connected.\n");
ret = -ENODEV;
goto end;
}
@@ -277,16 +274,17 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
dev->mei_host_buffer_is_empty = false;
- dev_dbg(&dev->pdev->dev, "sending watchdog ping\n");
+ dev_dbg(&dev->pdev->dev, "wd: sending ping\n");
if (mei_wd_send(dev)) {
- dev_dbg(&dev->pdev->dev, "wd send failed.\n");
+ dev_err(&dev->pdev->dev, "wd: send failed.\n");
ret = -EIO;
goto end;
}
if (mei_flow_ctrl_reduce(dev, &dev->wd_cl)) {
- dev_dbg(&dev->pdev->dev, "mei_flow_ctrl_reduce() failed.\n");
+ dev_err(&dev->pdev->dev,
+ "wd: mei_flow_ctrl_reduce() failed.\n");
ret = -EIO;
goto end;
}
@@ -346,7 +344,7 @@ static const struct watchdog_info wd_info = {
.options = WDIOF_KEEPALIVEPING,
};
-struct watchdog_device amt_wd_dev = {
+static struct watchdog_device amt_wd_dev = {
.info = &wd_info,
.ops = &wd_ops,
.timeout = AMT_WD_DEFAULT_TIMEOUT,
@@ -362,10 +360,12 @@ void mei_watchdog_register(struct mei_device *dev)
dev->wd_due_counter = !!dev->wd_timeout;
if (watchdog_register_device(&amt_wd_dev)) {
- dev_err(&dev->pdev->dev, "unable to register watchdog device.\n");
+ dev_err(&dev->pdev->dev,
+ "wd: unable to register watchdog device.\n");
dev->wd_interface_reg = false;
} else {
- dev_dbg(&dev->pdev->dev, "successfully register watchdog interface.\n");
+ dev_dbg(&dev->pdev->dev,
+ "wd: successfully register watchdog interface.\n");
dev->wd_interface_reg = true;
}
}
diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c
index 10fc4785dba7..9fbcacd703d5 100644
--- a/drivers/misc/pch_phub.c
+++ b/drivers/misc/pch_phub.c
@@ -65,10 +65,6 @@
#define PCI_VENDOR_ID_ROHM 0x10db
#define PCI_DEVICE_ID_ROHM_ML7213_PHUB 0x801A
-/* Macros for ML7213 */
-#define PCI_VENDOR_ID_ROHM 0x10db
-#define PCI_DEVICE_ID_ROHM_ML7213_PHUB 0x801A
-
/* Macros for ML7223 */
#define PCI_DEVICE_ID_ROHM_ML7223_mPHUB 0x8012 /* for Bus-m */
#define PCI_DEVICE_ID_ROHM_ML7223_nPHUB 0x8002 /* for Bus-n */
diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c
index 383133b201a1..b7eb545394b1 100644
--- a/drivers/misc/pti.c
+++ b/drivers/misc/pti.c
@@ -888,7 +888,7 @@ static struct pci_driver pti_pci_driver = {
.name = PCINAME,
.id_table = pci_ids,
.probe = pti_pci_probe,
- .remove = pti_pci_remove,
+ .remove = __devexit_p(pti_pci_remove),
};
/**
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index e3f5af96ab87..bb03ddda481d 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -39,6 +39,7 @@
#include <linux/regulator/consumer.h>
#include <linux/module.h>
#include <linux/fsl/mxs-dma.h>
+#include <linux/pinctrl/consumer.h>
#include <mach/mxs.h>
#include <mach/common.h>
@@ -682,6 +683,7 @@ static int mxs_mmc_probe(struct platform_device *pdev)
struct mmc_host *mmc;
struct resource *iores, *dmares, *r;
struct mxs_mmc_platform_data *pdata;
+ struct pinctrl *pinctrl;
int ret = 0, irq_err, irq_dma;
dma_cap_mask_t mask;
@@ -719,6 +721,12 @@ static int mxs_mmc_probe(struct platform_device *pdev)
host->irq = irq_err;
host->sdio_irq_en = 0;
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ goto out_iounmap;
+ }
+
host->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(host->clk)) {
ret = PTR_ERR(host->clk);
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 8abdaf6697a8..d190d04636a7 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -24,6 +24,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
#include <mach/esdhc.h>
#include "sdhci-pltfm.h"
#include "sdhci-esdhc.h"
@@ -68,6 +69,7 @@ struct pltfm_imx_data {
int flags;
u32 scratchpad;
enum imx_esdhc_type devtype;
+ struct pinctrl *pinctrl;
struct esdhc_platform_data boarddata;
};
@@ -467,6 +469,12 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
clk_prepare_enable(clk);
pltfm_host->clk = clk;
+ imx_data->pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(imx_data->pinctrl)) {
+ err = PTR_ERR(imx_data->pinctrl);
+ goto pin_err;
+ }
+
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data))
@@ -558,6 +566,7 @@ no_card_detect_irq:
gpio_free(boarddata->wp_gpio);
no_card_detect_pin:
no_board_data:
+pin_err:
clk_disable_unprepare(pltfm_host->clk);
clk_put(pltfm_host->clk);
err_clk_get:
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 53b26502f6e2..ff5a16991939 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -269,7 +269,6 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
"failed to allocate power gpio\n");
goto err_power_req;
}
- tegra_gpio_enable(plat->power_gpio);
gpio_direction_output(plat->power_gpio, 1);
}
@@ -280,7 +279,6 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
"failed to allocate cd gpio\n");
goto err_cd_req;
}
- tegra_gpio_enable(plat->cd_gpio);
gpio_direction_input(plat->cd_gpio);
rc = request_irq(gpio_to_irq(plat->cd_gpio), carddetect_irq,
@@ -301,7 +299,6 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
"failed to allocate wp gpio\n");
goto err_wp_req;
}
- tegra_gpio_enable(plat->wp_gpio);
gpio_direction_input(plat->wp_gpio);
}
@@ -329,23 +326,17 @@ err_add_host:
clk_disable(pltfm_host->clk);
clk_put(pltfm_host->clk);
err_clk_get:
- if (gpio_is_valid(plat->wp_gpio)) {
- tegra_gpio_disable(plat->wp_gpio);
+ if (gpio_is_valid(plat->wp_gpio))
gpio_free(plat->wp_gpio);
- }
err_wp_req:
if (gpio_is_valid(plat->cd_gpio))
free_irq(gpio_to_irq(plat->cd_gpio), host);
err_cd_irq_req:
- if (gpio_is_valid(plat->cd_gpio)) {
- tegra_gpio_disable(plat->cd_gpio);
+ if (gpio_is_valid(plat->cd_gpio))
gpio_free(plat->cd_gpio);
- }
err_cd_req:
- if (gpio_is_valid(plat->power_gpio)) {
- tegra_gpio_disable(plat->power_gpio);
+ if (gpio_is_valid(plat->power_gpio))
gpio_free(plat->power_gpio);
- }
err_power_req:
err_no_plat:
sdhci_pltfm_free(pdev);
@@ -362,21 +353,16 @@ static int __devexit sdhci_tegra_remove(struct platform_device *pdev)
sdhci_remove_host(host, dead);
- if (gpio_is_valid(plat->wp_gpio)) {
- tegra_gpio_disable(plat->wp_gpio);
+ if (gpio_is_valid(plat->wp_gpio))
gpio_free(plat->wp_gpio);
- }
if (gpio_is_valid(plat->cd_gpio)) {
free_irq(gpio_to_irq(plat->cd_gpio), host);
- tegra_gpio_disable(plat->cd_gpio);
gpio_free(plat->cd_gpio);
}
- if (gpio_is_valid(plat->power_gpio)) {
- tegra_gpio_disable(plat->power_gpio);
+ if (gpio_is_valid(plat->power_gpio))
gpio_free(plat->power_gpio);
- }
clk_disable(pltfm_host->clk);
clk_put(pltfm_host->clk);
diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c
index 8272c02668d6..50aa90aa7a7f 100644
--- a/drivers/mtd/devices/docg3.c
+++ b/drivers/mtd/devices/docg3.c
@@ -383,7 +383,7 @@ static void doc_set_device_id(struct docg3 *docg3, int id)
* leveling counters are stored. To access this last area of 4 bytes, a special
* mode must be input to the flash ASIC.
*
- * Returns 0 if no error occured, -EIO else.
+ * Returns 0 if no error occurred, -EIO else.
*/
static int doc_set_extra_page_mode(struct docg3 *docg3)
{
@@ -681,7 +681,7 @@ out:
* - one read of 512 bytes at offset 0
* - one read of 512 bytes at offset 512 + 16
*
- * Returns 0 if successful, -EIO if a read error occured.
+ * Returns 0 if successful, -EIO if a read error occurred.
*/
static int doc_read_page_prepare(struct docg3 *docg3, int block0, int block1,
int page, int offset)
@@ -839,7 +839,7 @@ static void calc_block_sector(loff_t from, int *block0, int *block1, int *page,
*
* Reads flash memory OOB area of pages.
*
- * Returns 0 if read successfull, of -EIO, -EINVAL if an error occured
+ * Returns 0 if read successful, of -EIO, -EINVAL if an error occurred
*/
static int doc_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops)
@@ -971,7 +971,7 @@ err_in_read:
* Reads flash memory pages. This function does not read the OOB chunk, but only
* the page data.
*
- * Returns 0 if read successfull, of -EIO, -EINVAL if an error occured
+ * Returns 0 if read successful, of -EIO, -EINVAL if an error occurred
*/
static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
@@ -1109,7 +1109,7 @@ static int doc_get_op_status(struct docg3 *docg3)
* Wait for the chip to be ready again after erase or write operation, and check
* erase/write status.
*
- * Returns 0 if erase successfull, -EIO if erase/write issue, -ETIMEOUT if
+ * Returns 0 if erase successful, -EIO if erase/write issue, -ETIMEOUT if
* timeout
*/
static int doc_write_erase_wait_status(struct docg3 *docg3)
@@ -1186,7 +1186,7 @@ static int doc_erase_block(struct docg3 *docg3, int block0, int block1)
* Erase a bunch of contiguous blocks, by pairs, as a "mtd" page of 1024 is
* split into 2 pages of 512 bytes on 2 contiguous blocks.
*
- * Returns 0 if erase successful, -EINVAL if adressing error, -EIO if erase
+ * Returns 0 if erase successful, -EINVAL if addressing error, -EIO if erase
* issue
*/
static int doc_erase(struct mtd_info *mtd, struct erase_info *info)
@@ -1397,7 +1397,7 @@ static int doc_backup_oob(struct docg3 *docg3, loff_t to,
* Or provide data without OOB, and then a all zeroed OOB will be used (ECC will
* still be filled in if asked for).
*
- * Returns 0 is successfull, EINVAL if length is not 14 bytes
+ * Returns 0 is successful, EINVAL if length is not 14 bytes
*/
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops)
@@ -1945,7 +1945,7 @@ static void doc_release_device(struct mtd_info *mtd)
* docg3_resume - Awakens docg3 floor
* @pdev: platfrom device
*
- * Returns 0 (always successfull)
+ * Returns 0 (always successful)
*/
static int docg3_resume(struct platform_device *pdev)
{
diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c
index 2e42ec2e8ff4..04769a49a7cb 100644
--- a/drivers/mtd/nand/autcpu12.c
+++ b/drivers/mtd/nand/autcpu12.c
@@ -102,10 +102,10 @@ static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd,
void __iomem *addr;
unsigned char bits;
- addr = CS89712_VIRT_BASE + AUTCPU12_SMC_PORT_OFFSET;
- bits = (ctrl & NAND_CLE) << 4;
+ bits = clps_readb(AUTCPU12_SMC_PORT_OFFSET) & ~0x30;
+ bits |= (ctrl & NAND_CLE) << 4;
bits |= (ctrl & NAND_ALE) << 2;
- writeb((readb(addr) & ~0x30) | bits, addr);
+ clps_writeb(bits, AUTCPU12_SMC_PORT_OFFSET);
addr = autcpu12_fio_base + AUTCPU12_SMC_SELECT_OFFSET;
writeb((readb(addr) & ~0x1) | (ctrl & NAND_NCE), addr);
@@ -120,9 +120,7 @@ static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd,
*/
int autcpu12_device_ready(struct mtd_info *mtd)
{
- void __iomem *addr = CS89712_VIRT_BASE + AUTCPU12_SMC_PORT_OFFSET;
-
- return readb(addr) & AUTCPU12_SMC_RDY;
+ return clps_readb(AUTCPU12_SMC_PORT_OFFSET) & AUTCPU12_SMC_RDY;
}
/*
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index 9ec51cec2e14..b68e04310bd8 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -24,6 +24,7 @@
#include <linux/module.h>
#include <linux/mtd/gpmi-nand.h>
#include <linux/mtd/partitions.h>
+#include <linux/pinctrl/consumer.h>
#include "gpmi-nand.h"
/* add our owner bbt descriptor */
@@ -476,6 +477,7 @@ acquire_err:
static int __devinit acquire_resources(struct gpmi_nand_data *this)
{
struct resources *res = &this->resources;
+ struct pinctrl *pinctrl;
int ret;
ret = acquire_register_block(this, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME);
@@ -494,6 +496,12 @@ static int __devinit acquire_resources(struct gpmi_nand_data *this)
if (ret)
goto exit_dma_channels;
+ pinctrl = devm_pinctrl_get_select_default(&this->pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ goto exit_pin;
+ }
+
res->clock = clk_get(&this->pdev->dev, NULL);
if (IS_ERR(res->clock)) {
pr_err("can not get the clock\n");
@@ -503,6 +511,7 @@ static int __devinit acquire_resources(struct gpmi_nand_data *this)
return 0;
exit_clock:
+exit_pin:
release_dma_channels(this);
exit_dma_channels:
release_bch_irq(this);
diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c
index 11e487813428..9bf5ce5fa22d 100644
--- a/drivers/mtd/nand/h1910.c
+++ b/drivers/mtd/nand/h1910.c
@@ -24,7 +24,7 @@
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <asm/io.h>
-#include <mach/hardware.h> /* for CLPS7111_VIRT_BASE */
+#include <mach/hardware.h>
#include <asm/sizes.h>
#include <mach/h1900-gpio.h>
#include <mach/ipaq.h>
diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c
index 1d3bfb26080c..0f50ef38b87b 100644
--- a/drivers/mtd/nand/orion_nand.c
+++ b/drivers/mtd/nand/orion_nand.c
@@ -13,6 +13,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/of.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
@@ -74,11 +75,13 @@ static void orion_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
static int __init orion_nand_probe(struct platform_device *pdev)
{
struct mtd_info *mtd;
+ struct mtd_part_parser_data ppdata = {};
struct nand_chip *nc;
struct orion_nand_data *board;
struct resource *res;
void __iomem *io_base;
int ret = 0;
+ u32 val = 0;
nc = kzalloc(sizeof(struct nand_chip) + sizeof(struct mtd_info), GFP_KERNEL);
if (!nc) {
@@ -101,7 +104,32 @@ static int __init orion_nand_probe(struct platform_device *pdev)
goto no_res;
}
- board = pdev->dev.platform_data;
+ if (pdev->dev.of_node) {
+ board = devm_kzalloc(&pdev->dev, sizeof(struct orion_nand_data),
+ GFP_KERNEL);
+ if (!board) {
+ printk(KERN_ERR "orion_nand: failed to allocate board structure.\n");
+ ret = -ENOMEM;
+ goto no_res;
+ }
+ if (!of_property_read_u32(pdev->dev.of_node, "cle", &val))
+ board->cle = (u8)val;
+ else
+ board->cle = 0;
+ if (!of_property_read_u32(pdev->dev.of_node, "ale", &val))
+ board->ale = (u8)val;
+ else
+ board->ale = 1;
+ if (!of_property_read_u32(pdev->dev.of_node,
+ "bank-width", &val))
+ board->width = (u8)val * 8;
+ else
+ board->width = 8;
+ if (!of_property_read_u32(pdev->dev.of_node,
+ "chip-delay", &val))
+ board->chip_delay = (u8)val;
+ } else
+ board = pdev->dev.platform_data;
mtd->priv = nc;
mtd->owner = THIS_MODULE;
@@ -115,6 +143,10 @@ static int __init orion_nand_probe(struct platform_device *pdev)
if (board->chip_delay)
nc->chip_delay = board->chip_delay;
+ WARN(board->width > 16,
+ "%d bit bus width out of range",
+ board->width);
+
if (board->width == 16)
nc->options |= NAND_BUSWIDTH_16;
@@ -129,8 +161,9 @@ static int __init orion_nand_probe(struct platform_device *pdev)
}
mtd->name = "orion_nand";
- ret = mtd_device_parse_register(mtd, NULL, NULL, board->parts,
- board->nr_parts);
+ ppdata.of_node = pdev->dev.of_node;
+ ret = mtd_device_parse_register(mtd, NULL, &ppdata,
+ board->parts, board->nr_parts);
if (ret) {
nand_release(mtd);
goto no_dev;
@@ -161,11 +194,19 @@ static int __devexit orion_nand_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_OF
+static struct of_device_id orion_nand_of_match_table[] = {
+ { .compatible = "mrvl,orion-nand", },
+ {},
+};
+#endif
+
static struct platform_driver orion_nand_driver = {
.remove = __devexit_p(orion_nand_remove),
.driver = {
.name = "orion_nand",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(orion_nand_of_match_table),
},
};
diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig
index 4dcc752a0c0b..738ee8dc16cd 100644
--- a/drivers/mtd/ubi/Kconfig
+++ b/drivers/mtd/ubi/Kconfig
@@ -52,12 +52,4 @@ config MTD_UBI_GLUEBI
work on top of UBI. Do not enable this unless you use legacy
software.
-config MTD_UBI_DEBUG
- bool "UBI debugging"
- depends on SYSFS
- select DEBUG_FS
- select KALLSYMS
- help
- This option enables UBI debugging.
-
endif # MTD_UBI
diff --git a/drivers/mtd/ubi/Makefile b/drivers/mtd/ubi/Makefile
index c9302a5452b0..a0803ac74712 100644
--- a/drivers/mtd/ubi/Makefile
+++ b/drivers/mtd/ubi/Makefile
@@ -1,7 +1,6 @@
obj-$(CONFIG_MTD_UBI) += ubi.o
-ubi-y += vtbl.o vmt.o upd.o build.o cdev.o kapi.o eba.o io.o wl.o scan.o
-ubi-y += misc.o
+ubi-y += vtbl.o vmt.o upd.o build.o cdev.o kapi.o eba.o io.o wl.o attach.o
+ubi-y += misc.o debug.o
-ubi-$(CONFIG_MTD_UBI_DEBUG) += debug.o
obj-$(CONFIG_MTD_UBI_GLUEBI) += gluebi.o
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/attach.c
index 12c43b44f815..bd27cbbb4066 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/attach.c
@@ -19,21 +19,21 @@
*/
/*
- * UBI scanning sub-system.
+ * UBI attaching sub-system.
*
- * This sub-system is responsible for scanning the flash media, checking UBI
- * headers and providing complete information about the UBI flash image.
+ * This sub-system is responsible for attaching MTD devices and it also
+ * implements flash media scanning.
*
- * The scanning information is represented by a &struct ubi_scan_info' object.
- * Information about found volumes is represented by &struct ubi_scan_volume
+ * The attaching information is represented by a &struct ubi_attach_info'
+ * object. Information about volumes is represented by &struct ubi_ainf_volume
* objects which are kept in volume RB-tree with root at the @volumes field.
* The RB-tree is indexed by the volume ID.
*
- * Scanned logical eraseblocks are represented by &struct ubi_scan_leb objects.
- * These objects are kept in per-volume RB-trees with the root at the
- * corresponding &struct ubi_scan_volume object. To put it differently, we keep
- * an RB-tree of per-volume objects and each of these objects is the root of
- * RB-tree of per-eraseblock objects.
+ * Logical eraseblocks are represented by &struct ubi_ainf_peb objects. These
+ * objects are kept in per-volume RB-trees with the root at the corresponding
+ * &struct ubi_ainf_volume object. To put it differently, we keep an RB-tree of
+ * per-volume objects and each of these objects is the root of RB-tree of
+ * per-LEB objects.
*
* Corrupted physical eraseblocks are put to the @corr list, free physical
* eraseblocks are put to the @free list and the physical eraseblock to be
@@ -51,28 +51,29 @@
*
* 1. Corruptions caused by power cuts. These are expected corruptions and UBI
* tries to handle them gracefully, without printing too many warnings and
- * error messages. The idea is that we do not lose important data in these case
- * - we may lose only the data which was being written to the media just before
- * the power cut happened, and the upper layers (e.g., UBIFS) are supposed to
- * handle such data losses (e.g., by using the FS journal).
+ * error messages. The idea is that we do not lose important data in these
+ * cases - we may lose only the data which were being written to the media just
+ * before the power cut happened, and the upper layers (e.g., UBIFS) are
+ * supposed to handle such data losses (e.g., by using the FS journal).
*
* When UBI detects a corruption (CRC-32 mismatch) in a PEB, and it looks like
* the reason is a power cut, UBI puts this PEB to the @erase list, and all
* PEBs in the @erase list are scheduled for erasure later.
*
* 2. Unexpected corruptions which are not caused by power cuts. During
- * scanning, such PEBs are put to the @corr list and UBI preserves them.
+ * attaching, such PEBs are put to the @corr list and UBI preserves them.
* Obviously, this lessens the amount of available PEBs, and if at some point
* UBI runs out of free PEBs, it switches to R/O mode. UBI also loudly informs
* about such PEBs every time the MTD device is attached.
*
* However, it is difficult to reliably distinguish between these types of
- * corruptions and UBI's strategy is as follows. UBI assumes corruption type 2
- * if the VID header is corrupted and the data area does not contain all 0xFFs,
- * and there were no bit-flips or integrity errors while reading the data area.
- * Otherwise UBI assumes corruption type 1. So the decision criteria are as
- * follows.
- * o If the data area contains only 0xFFs, there is no data, and it is safe
+ * corruptions and UBI's strategy is as follows (in case of attaching by
+ * scanning). UBI assumes corruption type 2 if the VID header is corrupted and
+ * the data area does not contain all 0xFFs, and there were no bit-flips or
+ * integrity errors (e.g., ECC errors in case of NAND) while reading the data
+ * area. Otherwise UBI assumes corruption type 1. So the decision criteria
+ * are as follows.
+ * o If the data area contains only 0xFFs, there are no data, and it is safe
* to just erase this PEB - this is corruption type 1.
* o If the data area has bit-flips or data integrity errors (ECC errors on
* NAND), it is probably a PEB which was being erased when power cut
@@ -88,11 +89,7 @@
#include <linux/random.h>
#include "ubi.h"
-#ifdef CONFIG_MTD_UBI_DEBUG
-static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si);
-#else
-#define paranoid_check_si(ubi, si) 0
-#endif
+static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai);
/* Temporary variables used during scanning */
static struct ubi_ec_hdr *ech;
@@ -100,13 +97,18 @@ static struct ubi_vid_hdr *vidh;
/**
* add_to_list - add physical eraseblock to a list.
- * @si: scanning information
+ * @ai: attaching information
* @pnum: physical eraseblock number to add
+ * @vol_id: the last used volume id for the PEB
+ * @lnum: the last used LEB number for the PEB
* @ec: erase counter of the physical eraseblock
* @to_head: if not zero, add to the head of the list
* @list: the list to add to
*
- * This function adds physical eraseblock @pnum to free, erase, or alien lists.
+ * This function allocates a 'struct ubi_ainf_peb' object for physical
+ * eraseblock @pnum and adds it to the "free", "erase", or "alien" lists.
+ * It stores the @lnum and @vol_id alongside, which can both be
+ * %UBI_UNKNOWN if they are not available, not readable, or not assigned.
* If @to_head is not zero, PEB will be added to the head of the list, which
* basically means it will be processed first later. E.g., we add corrupted
* PEBs (corrupted due to power cuts) to the head of the erase list to make
@@ -114,65 +116,68 @@ static struct ubi_vid_hdr *vidh;
* returns zero in case of success and a negative error code in case of
* failure.
*/
-static int add_to_list(struct ubi_scan_info *si, int pnum, int ec, int to_head,
- struct list_head *list)
+static int add_to_list(struct ubi_attach_info *ai, int pnum, int vol_id,
+ int lnum, int ec, int to_head, struct list_head *list)
{
- struct ubi_scan_leb *seb;
+ struct ubi_ainf_peb *aeb;
- if (list == &si->free) {
+ if (list == &ai->free) {
dbg_bld("add to free: PEB %d, EC %d", pnum, ec);
- } else if (list == &si->erase) {
+ } else if (list == &ai->erase) {
dbg_bld("add to erase: PEB %d, EC %d", pnum, ec);
- } else if (list == &si->alien) {
+ } else if (list == &ai->alien) {
dbg_bld("add to alien: PEB %d, EC %d", pnum, ec);
- si->alien_peb_count += 1;
+ ai->alien_peb_count += 1;
} else
BUG();
- seb = kmem_cache_alloc(si->scan_leb_slab, GFP_KERNEL);
- if (!seb)
+ aeb = kmem_cache_alloc(ai->aeb_slab_cache, GFP_KERNEL);
+ if (!aeb)
return -ENOMEM;
- seb->pnum = pnum;
- seb->ec = ec;
+ aeb->pnum = pnum;
+ aeb->vol_id = vol_id;
+ aeb->lnum = lnum;
+ aeb->ec = ec;
if (to_head)
- list_add(&seb->u.list, list);
+ list_add(&aeb->u.list, list);
else
- list_add_tail(&seb->u.list, list);
+ list_add_tail(&aeb->u.list, list);
return 0;
}
/**
* add_corrupted - add a corrupted physical eraseblock.
- * @si: scanning information
+ * @ai: attaching information
* @pnum: physical eraseblock number to add
* @ec: erase counter of the physical eraseblock
*
- * This function adds corrupted physical eraseblock @pnum to the 'corr' list.
- * The corruption was presumably not caused by a power cut. Returns zero in
- * case of success and a negative error code in case of failure.
+ * This function allocates a 'struct ubi_ainf_peb' object for a corrupted
+ * physical eraseblock @pnum and adds it to the 'corr' list. The corruption
+ * was presumably not caused by a power cut. Returns zero in case of success
+ * and a negative error code in case of failure.
*/
-static int add_corrupted(struct ubi_scan_info *si, int pnum, int ec)
+static int add_corrupted(struct ubi_attach_info *ai, int pnum, int ec)
{
- struct ubi_scan_leb *seb;
+ struct ubi_ainf_peb *aeb;
dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec);
- seb = kmem_cache_alloc(si->scan_leb_slab, GFP_KERNEL);
- if (!seb)
+ aeb = kmem_cache_alloc(ai->aeb_slab_cache, GFP_KERNEL);
+ if (!aeb)
return -ENOMEM;
- si->corr_peb_count += 1;
- seb->pnum = pnum;
- seb->ec = ec;
- list_add(&seb->u.list, &si->corr);
+ ai->corr_peb_count += 1;
+ aeb->pnum = pnum;
+ aeb->ec = ec;
+ list_add(&aeb->u.list, &ai->corr);
return 0;
}
/**
* validate_vid_hdr - check volume identifier header.
* @vid_hdr: the volume identifier header to check
- * @sv: information about the volume this logical eraseblock belongs to
+ * @av: information about the volume this logical eraseblock belongs to
* @pnum: physical eraseblock number the VID header came from
*
* This function checks that data stored in @vid_hdr is consistent. Returns
@@ -184,15 +189,15 @@ static int add_corrupted(struct ubi_scan_info *si, int pnum, int ec)
* headers of the same volume.
*/
static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr,
- const struct ubi_scan_volume *sv, int pnum)
+ const struct ubi_ainf_volume *av, int pnum)
{
int vol_type = vid_hdr->vol_type;
int vol_id = be32_to_cpu(vid_hdr->vol_id);
int used_ebs = be32_to_cpu(vid_hdr->used_ebs);
int data_pad = be32_to_cpu(vid_hdr->data_pad);
- if (sv->leb_count != 0) {
- int sv_vol_type;
+ if (av->leb_count != 0) {
+ int av_vol_type;
/*
* This is not the first logical eraseblock belonging to this
@@ -200,28 +205,28 @@ static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr,
* to the data in previous logical eraseblock headers.
*/
- if (vol_id != sv->vol_id) {
- dbg_err("inconsistent vol_id");
+ if (vol_id != av->vol_id) {
+ ubi_err("inconsistent vol_id");
goto bad;
}
- if (sv->vol_type == UBI_STATIC_VOLUME)
- sv_vol_type = UBI_VID_STATIC;
+ if (av->vol_type == UBI_STATIC_VOLUME)
+ av_vol_type = UBI_VID_STATIC;
else
- sv_vol_type = UBI_VID_DYNAMIC;
+ av_vol_type = UBI_VID_DYNAMIC;
- if (vol_type != sv_vol_type) {
- dbg_err("inconsistent vol_type");
+ if (vol_type != av_vol_type) {
+ ubi_err("inconsistent vol_type");
goto bad;
}
- if (used_ebs != sv->used_ebs) {
- dbg_err("inconsistent used_ebs");
+ if (used_ebs != av->used_ebs) {
+ ubi_err("inconsistent used_ebs");
goto bad;
}
- if (data_pad != sv->data_pad) {
- dbg_err("inconsistent data_pad");
+ if (data_pad != av->data_pad) {
+ ubi_err("inconsistent data_pad");
goto bad;
}
}
@@ -230,74 +235,74 @@ static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr,
bad:
ubi_err("inconsistent VID header at PEB %d", pnum);
- ubi_dbg_dump_vid_hdr(vid_hdr);
- ubi_dbg_dump_sv(sv);
+ ubi_dump_vid_hdr(vid_hdr);
+ ubi_dump_av(av);
return -EINVAL;
}
/**
- * add_volume - add volume to the scanning information.
- * @si: scanning information
+ * add_volume - add volume to the attaching information.
+ * @ai: attaching information
* @vol_id: ID of the volume to add
* @pnum: physical eraseblock number
* @vid_hdr: volume identifier header
*
* If the volume corresponding to the @vid_hdr logical eraseblock is already
- * present in the scanning information, this function does nothing. Otherwise
- * it adds corresponding volume to the scanning information. Returns a pointer
- * to the scanning volume object in case of success and a negative error code
- * in case of failure.
+ * present in the attaching information, this function does nothing. Otherwise
+ * it adds corresponding volume to the attaching information. Returns a pointer
+ * to the allocated "av" object in case of success and a negative error code in
+ * case of failure.
*/
-static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,
- int pnum,
+static struct ubi_ainf_volume *add_volume(struct ubi_attach_info *ai,
+ int vol_id, int pnum,
const struct ubi_vid_hdr *vid_hdr)
{
- struct ubi_scan_volume *sv;
- struct rb_node **p = &si->volumes.rb_node, *parent = NULL;
+ struct ubi_ainf_volume *av;
+ struct rb_node **p = &ai->volumes.rb_node, *parent = NULL;
ubi_assert(vol_id == be32_to_cpu(vid_hdr->vol_id));
/* Walk the volume RB-tree to look if this volume is already present */
while (*p) {
parent = *p;
- sv = rb_entry(parent, struct ubi_scan_volume, rb);
+ av = rb_entry(parent, struct ubi_ainf_volume, rb);
- if (vol_id == sv->vol_id)
- return sv;
+ if (vol_id == av->vol_id)
+ return av;
- if (vol_id > sv->vol_id)
+ if (vol_id > av->vol_id)
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
}
/* The volume is absent - add it */
- sv = kmalloc(sizeof(struct ubi_scan_volume), GFP_KERNEL);
- if (!sv)
+ av = kmalloc(sizeof(struct ubi_ainf_volume), GFP_KERNEL);
+ if (!av)
return ERR_PTR(-ENOMEM);
- sv->highest_lnum = sv->leb_count = 0;
- sv->vol_id = vol_id;
- sv->root = RB_ROOT;
- sv->used_ebs = be32_to_cpu(vid_hdr->used_ebs);
- sv->data_pad = be32_to_cpu(vid_hdr->data_pad);
- sv->compat = vid_hdr->compat;
- sv->vol_type = vid_hdr->vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME
+ av->highest_lnum = av->leb_count = 0;
+ av->vol_id = vol_id;
+ av->root = RB_ROOT;
+ av->used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+ av->data_pad = be32_to_cpu(vid_hdr->data_pad);
+ av->compat = vid_hdr->compat;
+ av->vol_type = vid_hdr->vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME
: UBI_STATIC_VOLUME;
- if (vol_id > si->highest_vol_id)
- si->highest_vol_id = vol_id;
+ if (vol_id > ai->highest_vol_id)
+ ai->highest_vol_id = vol_id;
- rb_link_node(&sv->rb, parent, p);
- rb_insert_color(&sv->rb, &si->volumes);
- si->vols_found += 1;
+ rb_link_node(&av->rb, parent, p);
+ rb_insert_color(&av->rb, &ai->volumes);
+ ai->vols_found += 1;
dbg_bld("added volume %d", vol_id);
- return sv;
+ return av;
}
/**
* compare_lebs - find out which logical eraseblock is newer.
* @ubi: UBI device description object
- * @seb: first logical eraseblock to compare
+ * @aeb: first logical eraseblock to compare
* @pnum: physical eraseblock number of the second logical eraseblock to
* compare
* @vid_hdr: volume identifier header of the second logical eraseblock
@@ -306,7 +311,7 @@ static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,
* case of success this function returns a positive value, in case of failure, a
* negative error code is returned. The success return codes use the following
* bits:
- * o bit 0 is cleared: the first PEB (described by @seb) is newer than the
+ * o bit 0 is cleared: the first PEB (described by @aeb) is newer than the
* second PEB (described by @pnum and @vid_hdr);
* o bit 0 is set: the second PEB is newer;
* o bit 1 is cleared: no bit-flips were detected in the newer LEB;
@@ -314,7 +319,7 @@ static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,
* o bit 2 is cleared: the older LEB is not corrupted;
* o bit 2 is set: the older LEB is corrupted.
*/
-static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
+static int compare_lebs(struct ubi_device *ubi, const struct ubi_ainf_peb *aeb,
int pnum, const struct ubi_vid_hdr *vid_hdr)
{
void *buf;
@@ -323,7 +328,7 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
struct ubi_vid_hdr *vh = NULL;
unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum);
- if (sqnum2 == seb->sqnum) {
+ if (sqnum2 == aeb->sqnum) {
/*
* This must be a really ancient UBI image which has been
* created before sequence numbers support has been added. At
@@ -337,7 +342,7 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
}
/* Obviously the LEB with lower sequence counter is older */
- second_is_newer = !!(sqnum2 > seb->sqnum);
+ second_is_newer = (sqnum2 > aeb->sqnum);
/*
* Now we know which copy is newer. If the copy flag of the PEB with
@@ -356,7 +361,7 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
return 1;
}
} else {
- if (!seb->copy_flag) {
+ if (!aeb->copy_flag) {
/* It is not a copy, so it is newer */
dbg_bld("first PEB %d is newer, copy_flag is unset",
pnum);
@@ -367,13 +372,13 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb,
if (!vh)
return -ENOMEM;
- pnum = seb->pnum;
+ pnum = aeb->pnum;
err = ubi_io_read_vid_hdr(ubi, pnum, vh, 0);
if (err) {
if (err == UBI_IO_BITFLIPS)
bitflips = 1;
else {
- dbg_err("VID of PEB %d header is bad, but it "
+ ubi_err("VID of PEB %d header is bad, but it "
"was OK earlier, err %d", pnum, err);
if (err > 0)
err = -EIO;
@@ -429,9 +434,9 @@ out_free_vidh:
}
/**
- * ubi_scan_add_used - add physical eraseblock to the scanning information.
+ * ubi_add_to_av - add used physical eraseblock to the attaching information.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
* @pnum: the physical eraseblock number
* @ec: erase counter
* @vid_hdr: the volume identifier header
@@ -444,14 +449,13 @@ out_free_vidh:
* to be picked, while the older one has to be dropped. This function returns
* zero in case of success and a negative error code in case of failure.
*/
-int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
- int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
- int bitflips)
+int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum,
+ int ec, const struct ubi_vid_hdr *vid_hdr, int bitflips)
{
int err, vol_id, lnum;
unsigned long long sqnum;
- struct ubi_scan_volume *sv;
- struct ubi_scan_leb *seb;
+ struct ubi_ainf_volume *av;
+ struct ubi_ainf_peb *aeb;
struct rb_node **p, *parent = NULL;
vol_id = be32_to_cpu(vid_hdr->vol_id);
@@ -461,25 +465,25 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
dbg_bld("PEB %d, LEB %d:%d, EC %d, sqnum %llu, bitflips %d",
pnum, vol_id, lnum, ec, sqnum, bitflips);
- sv = add_volume(si, vol_id, pnum, vid_hdr);
- if (IS_ERR(sv))
- return PTR_ERR(sv);
+ av = add_volume(ai, vol_id, pnum, vid_hdr);
+ if (IS_ERR(av))
+ return PTR_ERR(av);
- if (si->max_sqnum < sqnum)
- si->max_sqnum = sqnum;
+ if (ai->max_sqnum < sqnum)
+ ai->max_sqnum = sqnum;
/*
* Walk the RB-tree of logical eraseblocks of volume @vol_id to look
* if this is the first instance of this logical eraseblock or not.
*/
- p = &sv->root.rb_node;
+ p = &av->root.rb_node;
while (*p) {
int cmp_res;
parent = *p;
- seb = rb_entry(parent, struct ubi_scan_leb, u.rb);
- if (lnum != seb->lnum) {
- if (lnum < seb->lnum)
+ aeb = rb_entry(parent, struct ubi_ainf_peb, u.rb);
+ if (lnum != aeb->lnum) {
+ if (lnum < aeb->lnum)
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
@@ -491,8 +495,8 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
* logical eraseblock present.
*/
- dbg_bld("this LEB already exists: PEB %d, sqnum %llu, "
- "EC %d", seb->pnum, seb->sqnum, seb->ec);
+ dbg_bld("this LEB already exists: PEB %d, sqnum %llu, EC %d",
+ aeb->pnum, aeb->sqnum, aeb->ec);
/*
* Make sure that the logical eraseblocks have different
@@ -507,11 +511,11 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
* images, but refuse attaching old images with duplicated
* logical eraseblocks because there was an unclean reboot.
*/
- if (seb->sqnum == sqnum && sqnum != 0) {
+ if (aeb->sqnum == sqnum && sqnum != 0) {
ubi_err("two LEBs with same sequence number %llu",
sqnum);
- ubi_dbg_dump_seb(seb, 0);
- ubi_dbg_dump_vid_hdr(vid_hdr);
+ ubi_dump_aeb(aeb, 0);
+ ubi_dump_vid_hdr(vid_hdr);
return -EINVAL;
}
@@ -519,7 +523,7 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
* Now we have to drop the older one and preserve the newer
* one.
*/
- cmp_res = compare_lebs(ubi, seb, pnum, vid_hdr);
+ cmp_res = compare_lebs(ubi, aeb, pnum, vid_hdr);
if (cmp_res < 0)
return cmp_res;
@@ -528,23 +532,26 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
* This logical eraseblock is newer than the one
* found earlier.
*/
- err = validate_vid_hdr(vid_hdr, sv, pnum);
+ err = validate_vid_hdr(vid_hdr, av, pnum);
if (err)
return err;
- err = add_to_list(si, seb->pnum, seb->ec, cmp_res & 4,
- &si->erase);
+ err = add_to_list(ai, aeb->pnum, aeb->vol_id,
+ aeb->lnum, aeb->ec, cmp_res & 4,
+ &ai->erase);
if (err)
return err;
- seb->ec = ec;
- seb->pnum = pnum;
- seb->scrub = ((cmp_res & 2) || bitflips);
- seb->copy_flag = vid_hdr->copy_flag;
- seb->sqnum = sqnum;
+ aeb->ec = ec;
+ aeb->pnum = pnum;
+ aeb->vol_id = vol_id;
+ aeb->lnum = lnum;
+ aeb->scrub = ((cmp_res & 2) || bitflips);
+ aeb->copy_flag = vid_hdr->copy_flag;
+ aeb->sqnum = sqnum;
- if (sv->highest_lnum == lnum)
- sv->last_data_size =
+ if (av->highest_lnum == lnum)
+ av->last_data_size =
be32_to_cpu(vid_hdr->data_size);
return 0;
@@ -553,92 +560,64 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
* This logical eraseblock is older than the one found
* previously.
*/
- return add_to_list(si, pnum, ec, cmp_res & 4,
- &si->erase);
+ return add_to_list(ai, pnum, vol_id, lnum, ec,
+ cmp_res & 4, &ai->erase);
}
}
/*
* We've met this logical eraseblock for the first time, add it to the
- * scanning information.
+ * attaching information.
*/
- err = validate_vid_hdr(vid_hdr, sv, pnum);
+ err = validate_vid_hdr(vid_hdr, av, pnum);
if (err)
return err;
- seb = kmem_cache_alloc(si->scan_leb_slab, GFP_KERNEL);
- if (!seb)
+ aeb = kmem_cache_alloc(ai->aeb_slab_cache, GFP_KERNEL);
+ if (!aeb)
return -ENOMEM;
- seb->ec = ec;
- seb->pnum = pnum;
- seb->lnum = lnum;
- seb->scrub = bitflips;
- seb->copy_flag = vid_hdr->copy_flag;
- seb->sqnum = sqnum;
-
- if (sv->highest_lnum <= lnum) {
- sv->highest_lnum = lnum;
- sv->last_data_size = be32_to_cpu(vid_hdr->data_size);
+ aeb->ec = ec;
+ aeb->pnum = pnum;
+ aeb->vol_id = vol_id;
+ aeb->lnum = lnum;
+ aeb->scrub = bitflips;
+ aeb->copy_flag = vid_hdr->copy_flag;
+ aeb->sqnum = sqnum;
+
+ if (av->highest_lnum <= lnum) {
+ av->highest_lnum = lnum;
+ av->last_data_size = be32_to_cpu(vid_hdr->data_size);
}
- sv->leb_count += 1;
- rb_link_node(&seb->u.rb, parent, p);
- rb_insert_color(&seb->u.rb, &sv->root);
+ av->leb_count += 1;
+ rb_link_node(&aeb->u.rb, parent, p);
+ rb_insert_color(&aeb->u.rb, &av->root);
return 0;
}
/**
- * ubi_scan_find_sv - find volume in the scanning information.
- * @si: scanning information
+ * ubi_find_av - find volume in the attaching information.
+ * @ai: attaching information
* @vol_id: the requested volume ID
*
* This function returns a pointer to the volume description or %NULL if there
- * are no data about this volume in the scanning information.
- */
-struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si,
- int vol_id)
-{
- struct ubi_scan_volume *sv;
- struct rb_node *p = si->volumes.rb_node;
-
- while (p) {
- sv = rb_entry(p, struct ubi_scan_volume, rb);
-
- if (vol_id == sv->vol_id)
- return sv;
-
- if (vol_id > sv->vol_id)
- p = p->rb_left;
- else
- p = p->rb_right;
- }
-
- return NULL;
-}
-
-/**
- * ubi_scan_find_seb - find LEB in the volume scanning information.
- * @sv: a pointer to the volume scanning information
- * @lnum: the requested logical eraseblock
- *
- * This function returns a pointer to the scanning logical eraseblock or %NULL
- * if there are no data about it in the scanning volume information.
+ * are no data about this volume in the attaching information.
*/
-struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv,
- int lnum)
+struct ubi_ainf_volume *ubi_find_av(const struct ubi_attach_info *ai,
+ int vol_id)
{
- struct ubi_scan_leb *seb;
- struct rb_node *p = sv->root.rb_node;
+ struct ubi_ainf_volume *av;
+ struct rb_node *p = ai->volumes.rb_node;
while (p) {
- seb = rb_entry(p, struct ubi_scan_leb, u.rb);
+ av = rb_entry(p, struct ubi_ainf_volume, rb);
- if (lnum == seb->lnum)
- return seb;
+ if (vol_id == av->vol_id)
+ return av;
- if (lnum > seb->lnum)
+ if (vol_id > av->vol_id)
p = p->rb_left;
else
p = p->rb_right;
@@ -648,34 +627,34 @@ struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv,
}
/**
- * ubi_scan_rm_volume - delete scanning information about a volume.
- * @si: scanning information
- * @sv: the volume scanning information to delete
+ * ubi_remove_av - delete attaching information about a volume.
+ * @ai: attaching information
+ * @av: the volume attaching information to delete
*/
-void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv)
+void ubi_remove_av(struct ubi_attach_info *ai, struct ubi_ainf_volume *av)
{
struct rb_node *rb;
- struct ubi_scan_leb *seb;
+ struct ubi_ainf_peb *aeb;
- dbg_bld("remove scanning information about volume %d", sv->vol_id);
+ dbg_bld("remove attaching information about volume %d", av->vol_id);
- while ((rb = rb_first(&sv->root))) {
- seb = rb_entry(rb, struct ubi_scan_leb, u.rb);
- rb_erase(&seb->u.rb, &sv->root);
- list_add_tail(&seb->u.list, &si->erase);
+ while ((rb = rb_first(&av->root))) {
+ aeb = rb_entry(rb, struct ubi_ainf_peb, u.rb);
+ rb_erase(&aeb->u.rb, &av->root);
+ list_add_tail(&aeb->u.list, &ai->erase);
}
- rb_erase(&sv->rb, &si->volumes);
- kfree(sv);
- si->vols_found -= 1;
+ rb_erase(&av->rb, &ai->volumes);
+ kfree(av);
+ ai->vols_found -= 1;
}
/**
- * ubi_scan_erase_peb - erase a physical eraseblock.
+ * early_erase_peb - erase a physical eraseblock.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
* @pnum: physical eraseblock number to erase;
- * @ec: erase counter value to write (%UBI_SCAN_UNKNOWN_EC if it is unknown)
+ * @ec: erase counter value to write (%UBI_UNKNOWN if it is unknown)
*
* This function erases physical eraseblock 'pnum', and writes the erase
* counter header to it. This function should only be used on UBI device
@@ -683,8 +662,8 @@ void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv)
* This function returns zero in case of success and a negative error code in
* case of failure.
*/
-int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si,
- int pnum, int ec)
+static int early_erase_peb(struct ubi_device *ubi,
+ const struct ubi_attach_info *ai, int pnum, int ec)
{
int err;
struct ubi_ec_hdr *ec_hdr;
@@ -716,9 +695,9 @@ out_free:
}
/**
- * ubi_scan_get_free_peb - get a free physical eraseblock.
+ * ubi_early_get_peb - get a free physical eraseblock.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
*
* This function returns a free physical eraseblock. It is supposed to be
* called on the UBI initialization stages when the wear-leveling sub-system is
@@ -726,20 +705,20 @@ out_free:
* the lists, writes the EC header if it is needed, and removes it from the
* list.
*
- * This function returns scanning physical eraseblock information in case of
- * success and an error code in case of failure.
+ * This function returns a pointer to the "aeb" of the found free PEB in case
+ * of success and an error code in case of failure.
*/
-struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi,
- struct ubi_scan_info *si)
+struct ubi_ainf_peb *ubi_early_get_peb(struct ubi_device *ubi,
+ struct ubi_attach_info *ai)
{
int err = 0;
- struct ubi_scan_leb *seb, *tmp_seb;
+ struct ubi_ainf_peb *aeb, *tmp_aeb;
- if (!list_empty(&si->free)) {
- seb = list_entry(si->free.next, struct ubi_scan_leb, u.list);
- list_del(&seb->u.list);
- dbg_bld("return free PEB %d, EC %d", seb->pnum, seb->ec);
- return seb;
+ if (!list_empty(&ai->free)) {
+ aeb = list_entry(ai->free.next, struct ubi_ainf_peb, u.list);
+ list_del(&aeb->u.list);
+ dbg_bld("return free PEB %d, EC %d", aeb->pnum, aeb->ec);
+ return aeb;
}
/*
@@ -748,18 +727,18 @@ struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi,
* so forth. We don't want to take care about bad eraseblocks here -
* they'll be handled later.
*/
- list_for_each_entry_safe(seb, tmp_seb, &si->erase, u.list) {
- if (seb->ec == UBI_SCAN_UNKNOWN_EC)
- seb->ec = si->mean_ec;
+ list_for_each_entry_safe(aeb, tmp_aeb, &ai->erase, u.list) {
+ if (aeb->ec == UBI_UNKNOWN)
+ aeb->ec = ai->mean_ec;
- err = ubi_scan_erase_peb(ubi, si, seb->pnum, seb->ec+1);
+ err = early_erase_peb(ubi, ai, aeb->pnum, aeb->ec+1);
if (err)
continue;
- seb->ec += 1;
- list_del(&seb->u.list);
- dbg_bld("return PEB %d, EC %d", seb->pnum, seb->ec);
- return seb;
+ aeb->ec += 1;
+ list_del(&aeb->u.list);
+ dbg_bld("return PEB %d, EC %d", aeb->pnum, aeb->ec);
+ return aeb;
}
ubi_err("no free eraseblocks");
@@ -814,7 +793,7 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr,
ubi_err("PEB %d contains corrupted VID header, and the data does not "
"contain all 0xFF, this may be a non-UBI PEB or a severe VID "
"header corruption which requires manual inspection", pnum);
- ubi_dbg_dump_vid_hdr(vid_hdr);
+ ubi_dump_vid_hdr(vid_hdr);
dbg_msg("hexdump of PEB %d offset %d, length %d",
pnum, ubi->leb_start, ubi->leb_size);
ubi_dbg_print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
@@ -827,16 +806,18 @@ out_unlock:
}
/**
- * process_eb - read, check UBI headers, and add them to scanning information.
+ * scan_peb - scan and process UBI headers of a PEB.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
* @pnum: the physical eraseblock number
*
- * This function returns a zero if the physical eraseblock was successfully
- * handled and a negative error code in case of failure.
+ * This function reads UBI headers of PEB @pnum, checks them, and adds
+ * information about this PEB to the corresponding list or RB-tree in the
+ * "attaching info" structure. Returns zero if the physical eraseblock was
+ * successfully handled and a negative error code in case of failure.
*/
-static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
- int pnum)
+static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
+ int pnum)
{
long long uninitialized_var(ec);
int err, bitflips = 0, vol_id, ec_err = 0;
@@ -848,12 +829,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
if (err < 0)
return err;
else if (err) {
- /*
- * FIXME: this is actually duty of the I/O sub-system to
- * initialize this, but MTD does not provide enough
- * information.
- */
- si->bad_peb_count += 1;
+ ai->bad_peb_count += 1;
return 0;
}
@@ -867,13 +843,13 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
bitflips = 1;
break;
case UBI_IO_FF:
- si->empty_peb_count += 1;
- return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, 0,
- &si->erase);
+ ai->empty_peb_count += 1;
+ return add_to_list(ai, pnum, UBI_UNKNOWN, UBI_UNKNOWN,
+ UBI_UNKNOWN, 0, &ai->erase);
case UBI_IO_FF_BITFLIPS:
- si->empty_peb_count += 1;
- return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, 1,
- &si->erase);
+ ai->empty_peb_count += 1;
+ return add_to_list(ai, pnum, UBI_UNKNOWN, UBI_UNKNOWN,
+ UBI_UNKNOWN, 1, &ai->erase);
case UBI_IO_BAD_HDR_EBADMSG:
case UBI_IO_BAD_HDR:
/*
@@ -882,7 +858,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
* moved and EC be re-created.
*/
ec_err = err;
- ec = UBI_SCAN_UNKNOWN_EC;
+ ec = UBI_UNKNOWN;
bitflips = 1;
break;
default:
@@ -911,7 +887,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
*/
ubi_err("erase counter overflow, max is %d",
UBI_MAX_ERASECOUNTER);
- ubi_dbg_dump_ec_hdr(ech);
+ ubi_dump_ec_hdr(ech);
return -EINVAL;
}
@@ -933,7 +909,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
ubi->image_seq != image_seq) {
ubi_err("bad image sequence number %d in PEB %d, "
"expected %d", image_seq, pnum, ubi->image_seq);
- ubi_dbg_dump_ec_hdr(ech);
+ ubi_dump_ec_hdr(ech);
return -EINVAL;
}
}
@@ -957,7 +933,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
* PEB, bit it is not marked as bad yet. This may also
* be a result of power cut during erasure.
*/
- si->maybe_bad_peb_count += 1;
+ ai->maybe_bad_peb_count += 1;
case UBI_IO_BAD_HDR:
if (ec_err)
/*
@@ -984,23 +960,27 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
return err;
else if (!err)
/* This corruption is caused by a power cut */
- err = add_to_list(si, pnum, ec, 1, &si->erase);
+ err = add_to_list(ai, pnum, UBI_UNKNOWN,
+ UBI_UNKNOWN, ec, 1, &ai->erase);
else
/* This is an unexpected corruption */
- err = add_corrupted(si, pnum, ec);
+ err = add_corrupted(ai, pnum, ec);
if (err)
return err;
goto adjust_mean_ec;
case UBI_IO_FF_BITFLIPS:
- err = add_to_list(si, pnum, ec, 1, &si->erase);
+ err = add_to_list(ai, pnum, UBI_UNKNOWN, UBI_UNKNOWN,
+ ec, 1, &ai->erase);
if (err)
return err;
goto adjust_mean_ec;
case UBI_IO_FF:
if (ec_err)
- err = add_to_list(si, pnum, ec, 1, &si->erase);
+ err = add_to_list(ai, pnum, UBI_UNKNOWN,
+ UBI_UNKNOWN, ec, 1, &ai->erase);
else
- err = add_to_list(si, pnum, ec, 0, &si->free);
+ err = add_to_list(ai, pnum, UBI_UNKNOWN,
+ UBI_UNKNOWN, ec, 0, &ai->free);
if (err)
return err;
goto adjust_mean_ec;
@@ -1019,7 +999,8 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
case UBI_COMPAT_DELETE:
ubi_msg("\"delete\" compatible internal volume %d:%d"
" found, will remove it", vol_id, lnum);
- err = add_to_list(si, pnum, ec, 1, &si->erase);
+ err = add_to_list(ai, pnum, vol_id, lnum,
+ ec, 1, &ai->erase);
if (err)
return err;
return 0;
@@ -1034,7 +1015,8 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
case UBI_COMPAT_PRESERVE:
ubi_msg("\"preserve\" compatible internal volume %d:%d"
" found", vol_id, lnum);
- err = add_to_list(si, pnum, ec, 0, &si->alien);
+ err = add_to_list(ai, pnum, vol_id, lnum,
+ ec, 0, &ai->alien);
if (err)
return err;
return 0;
@@ -1049,40 +1031,40 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
if (ec_err)
ubi_warn("valid VID header but corrupted EC header at PEB %d",
pnum);
- err = ubi_scan_add_used(ubi, si, pnum, ec, vidh, bitflips);
+ err = ubi_add_to_av(ubi, ai, pnum, ec, vidh, bitflips);
if (err)
return err;
adjust_mean_ec:
if (!ec_err) {
- si->ec_sum += ec;
- si->ec_count += 1;
- if (ec > si->max_ec)
- si->max_ec = ec;
- if (ec < si->min_ec)
- si->min_ec = ec;
+ ai->ec_sum += ec;
+ ai->ec_count += 1;
+ if (ec > ai->max_ec)
+ ai->max_ec = ec;
+ if (ec < ai->min_ec)
+ ai->min_ec = ec;
}
return 0;
}
/**
- * check_what_we_have - check what PEB were found by scanning.
+ * late_analysis - analyze the overall situation with PEB.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
*
- * This is a helper function which takes a look what PEBs were found by
- * scanning, and decides whether the flash is empty and should be formatted and
- * whether there are too many corrupted PEBs and we should not attach this
- * MTD device. Returns zero if we should proceed with attaching the MTD device,
- * and %-EINVAL if we should not.
+ * This is a helper function which takes a look what PEBs we have after we
+ * gather information about all of them ("ai" is compete). It decides whether
+ * the flash is empty and should be formatted of whether there are too many
+ * corrupted PEBs and we should not attach this MTD device. Returns zero if we
+ * should proceed with attaching the MTD device, and %-EINVAL if we should not.
*/
-static int check_what_we_have(struct ubi_device *ubi, struct ubi_scan_info *si)
+static int late_analysis(struct ubi_device *ubi, struct ubi_attach_info *ai)
{
- struct ubi_scan_leb *seb;
+ struct ubi_ainf_peb *aeb;
int max_corr, peb_count;
- peb_count = ubi->peb_count - si->bad_peb_count - si->alien_peb_count;
+ peb_count = ubi->peb_count - ai->bad_peb_count - ai->alien_peb_count;
max_corr = peb_count / 20 ?: 8;
/*
@@ -1090,25 +1072,25 @@ static int check_what_we_have(struct ubi_device *ubi, struct ubi_scan_info *si)
* unclean reboots. However, many of them may indicate some problems
* with the flash HW or driver.
*/
- if (si->corr_peb_count) {
+ if (ai->corr_peb_count) {
ubi_err("%d PEBs are corrupted and preserved",
- si->corr_peb_count);
+ ai->corr_peb_count);
printk(KERN_ERR "Corrupted PEBs are:");
- list_for_each_entry(seb, &si->corr, u.list)
- printk(KERN_CONT " %d", seb->pnum);
+ list_for_each_entry(aeb, &ai->corr, u.list)
+ printk(KERN_CONT " %d", aeb->pnum);
printk(KERN_CONT "\n");
/*
* If too many PEBs are corrupted, we refuse attaching,
* otherwise, only print a warning.
*/
- if (si->corr_peb_count >= max_corr) {
+ if (ai->corr_peb_count >= max_corr) {
ubi_err("too many corrupted PEBs, refusing");
return -EINVAL;
}
}
- if (si->empty_peb_count + si->maybe_bad_peb_count == peb_count) {
+ if (ai->empty_peb_count + ai->maybe_bad_peb_count == peb_count) {
/*
* All PEBs are empty, or almost all - a couple PEBs look like
* they may be bad PEBs which were not marked as bad yet.
@@ -1124,8 +1106,8 @@ static int check_what_we_have(struct ubi_device *ubi, struct ubi_scan_info *si)
* 2. Flash contains non-UBI data and we do not want to format
* it and destroy possibly important information.
*/
- if (si->maybe_bad_peb_count <= 2) {
- si->is_empty = 1;
+ if (ai->maybe_bad_peb_count <= 2) {
+ ai->is_empty = 1;
ubi_msg("empty MTD device detected");
get_random_bytes(&ubi->image_seq,
sizeof(ubi->image_seq));
@@ -1141,40 +1123,41 @@ static int check_what_we_have(struct ubi_device *ubi, struct ubi_scan_info *si)
}
/**
- * ubi_scan - scan an MTD device.
+ * scan_all - scan entire MTD device.
* @ubi: UBI device description object
*
* This function does full scanning of an MTD device and returns complete
- * information about it. In case of failure, an error code is returned.
+ * information about it in form of a "struct ubi_attach_info" object. In case
+ * of failure, an error code is returned.
*/
-struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
+static struct ubi_attach_info *scan_all(struct ubi_device *ubi)
{
int err, pnum;
struct rb_node *rb1, *rb2;
- struct ubi_scan_volume *sv;
- struct ubi_scan_leb *seb;
- struct ubi_scan_info *si;
+ struct ubi_ainf_volume *av;
+ struct ubi_ainf_peb *aeb;
+ struct ubi_attach_info *ai;
- si = kzalloc(sizeof(struct ubi_scan_info), GFP_KERNEL);
- if (!si)
+ ai = kzalloc(sizeof(struct ubi_attach_info), GFP_KERNEL);
+ if (!ai)
return ERR_PTR(-ENOMEM);
- INIT_LIST_HEAD(&si->corr);
- INIT_LIST_HEAD(&si->free);
- INIT_LIST_HEAD(&si->erase);
- INIT_LIST_HEAD(&si->alien);
- si->volumes = RB_ROOT;
+ INIT_LIST_HEAD(&ai->corr);
+ INIT_LIST_HEAD(&ai->free);
+ INIT_LIST_HEAD(&ai->erase);
+ INIT_LIST_HEAD(&ai->alien);
+ ai->volumes = RB_ROOT;
err = -ENOMEM;
- si->scan_leb_slab = kmem_cache_create("ubi_scan_leb_slab",
- sizeof(struct ubi_scan_leb),
- 0, 0, NULL);
- if (!si->scan_leb_slab)
- goto out_si;
+ ai->aeb_slab_cache = kmem_cache_create("ubi_aeb_slab_cache",
+ sizeof(struct ubi_ainf_peb),
+ 0, 0, NULL);
+ if (!ai->aeb_slab_cache)
+ goto out_ai;
ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
if (!ech)
- goto out_si;
+ goto out_ai;
vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL);
if (!vidh)
@@ -1184,7 +1167,7 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
cond_resched();
dbg_gen("process PEB %d", pnum);
- err = process_eb(ubi, si, pnum);
+ err = scan_peb(ubi, ai, pnum);
if (err < 0)
goto out_vidh;
}
@@ -1192,10 +1175,10 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
dbg_msg("scanning is finished");
/* Calculate mean erase counter */
- if (si->ec_count)
- si->mean_ec = div_u64(si->ec_sum, si->ec_count);
+ if (ai->ec_count)
+ ai->mean_ec = div_u64(ai->ec_sum, ai->ec_count);
- err = check_what_we_have(ubi, si);
+ err = late_analysis(ubi, ai);
if (err)
goto out_vidh;
@@ -1203,55 +1186,102 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
* In case of unknown erase counter we use the mean erase counter
* value.
*/
- ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
- ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb)
- if (seb->ec == UBI_SCAN_UNKNOWN_EC)
- seb->ec = si->mean_ec;
+ ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb) {
+ ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb)
+ if (aeb->ec == UBI_UNKNOWN)
+ aeb->ec = ai->mean_ec;
}
- list_for_each_entry(seb, &si->free, u.list) {
- if (seb->ec == UBI_SCAN_UNKNOWN_EC)
- seb->ec = si->mean_ec;
+ list_for_each_entry(aeb, &ai->free, u.list) {
+ if (aeb->ec == UBI_UNKNOWN)
+ aeb->ec = ai->mean_ec;
}
- list_for_each_entry(seb, &si->corr, u.list)
- if (seb->ec == UBI_SCAN_UNKNOWN_EC)
- seb->ec = si->mean_ec;
+ list_for_each_entry(aeb, &ai->corr, u.list)
+ if (aeb->ec == UBI_UNKNOWN)
+ aeb->ec = ai->mean_ec;
- list_for_each_entry(seb, &si->erase, u.list)
- if (seb->ec == UBI_SCAN_UNKNOWN_EC)
- seb->ec = si->mean_ec;
+ list_for_each_entry(aeb, &ai->erase, u.list)
+ if (aeb->ec == UBI_UNKNOWN)
+ aeb->ec = ai->mean_ec;
- err = paranoid_check_si(ubi, si);
+ err = self_check_ai(ubi, ai);
if (err)
goto out_vidh;
ubi_free_vid_hdr(ubi, vidh);
kfree(ech);
- return si;
+ return ai;
out_vidh:
ubi_free_vid_hdr(ubi, vidh);
out_ech:
kfree(ech);
-out_si:
- ubi_scan_destroy_si(si);
+out_ai:
+ ubi_destroy_ai(ai);
return ERR_PTR(err);
}
/**
- * destroy_sv - free the scanning volume information
- * @sv: scanning volume information
- * @si: scanning information
+ * ubi_attach - attach an MTD device.
+ * @ubi: UBI device descriptor
*
- * This function destroys the volume RB-tree (@sv->root) and the scanning
- * volume information.
+ * This function returns zero in case of success and a negative error code in
+ * case of failure.
*/
-static void destroy_sv(struct ubi_scan_info *si, struct ubi_scan_volume *sv)
+int ubi_attach(struct ubi_device *ubi)
{
- struct ubi_scan_leb *seb;
- struct rb_node *this = sv->root.rb_node;
+ int err;
+ struct ubi_attach_info *ai;
+
+ ai = scan_all(ubi);
+ if (IS_ERR(ai))
+ return PTR_ERR(ai);
+
+ ubi->bad_peb_count = ai->bad_peb_count;
+ ubi->good_peb_count = ubi->peb_count - ubi->bad_peb_count;
+ ubi->corr_peb_count = ai->corr_peb_count;
+ ubi->max_ec = ai->max_ec;
+ ubi->mean_ec = ai->mean_ec;
+ ubi_msg("max. sequence number: %llu", ai->max_sqnum);
+
+ err = ubi_read_volume_table(ubi, ai);
+ if (err)
+ goto out_ai;
+
+ err = ubi_wl_init(ubi, ai);
+ if (err)
+ goto out_vtbl;
+
+ err = ubi_eba_init(ubi, ai);
+ if (err)
+ goto out_wl;
+
+ ubi_destroy_ai(ai);
+ return 0;
+
+out_wl:
+ ubi_wl_close(ubi);
+out_vtbl:
+ ubi_free_internal_volumes(ubi);
+ vfree(ubi->vtbl);
+out_ai:
+ ubi_destroy_ai(ai);
+ return err;
+}
+
+/**
+ * destroy_av - free volume attaching information.
+ * @av: volume attaching information
+ * @ai: attaching information
+ *
+ * This function destroys the volume attaching information.
+ */
+static void destroy_av(struct ubi_attach_info *ai, struct ubi_ainf_volume *av)
+{
+ struct ubi_ainf_peb *aeb;
+ struct rb_node *this = av->root.rb_node;
while (this) {
if (this->rb_left)
@@ -1259,224 +1289,222 @@ static void destroy_sv(struct ubi_scan_info *si, struct ubi_scan_volume *sv)
else if (this->rb_right)
this = this->rb_right;
else {
- seb = rb_entry(this, struct ubi_scan_leb, u.rb);
+ aeb = rb_entry(this, struct ubi_ainf_peb, u.rb);
this = rb_parent(this);
if (this) {
- if (this->rb_left == &seb->u.rb)
+ if (this->rb_left == &aeb->u.rb)
this->rb_left = NULL;
else
this->rb_right = NULL;
}
- kmem_cache_free(si->scan_leb_slab, seb);
+ kmem_cache_free(ai->aeb_slab_cache, aeb);
}
}
- kfree(sv);
+ kfree(av);
}
/**
- * ubi_scan_destroy_si - destroy scanning information.
- * @si: scanning information
+ * ubi_destroy_ai - destroy attaching information.
+ * @ai: attaching information
*/
-void ubi_scan_destroy_si(struct ubi_scan_info *si)
+void ubi_destroy_ai(struct ubi_attach_info *ai)
{
- struct ubi_scan_leb *seb, *seb_tmp;
- struct ubi_scan_volume *sv;
+ struct ubi_ainf_peb *aeb, *aeb_tmp;
+ struct ubi_ainf_volume *av;
struct rb_node *rb;
- list_for_each_entry_safe(seb, seb_tmp, &si->alien, u.list) {
- list_del(&seb->u.list);
- kmem_cache_free(si->scan_leb_slab, seb);
+ list_for_each_entry_safe(aeb, aeb_tmp, &ai->alien, u.list) {
+ list_del(&aeb->u.list);
+ kmem_cache_free(ai->aeb_slab_cache, aeb);
}
- list_for_each_entry_safe(seb, seb_tmp, &si->erase, u.list) {
- list_del(&seb->u.list);
- kmem_cache_free(si->scan_leb_slab, seb);
+ list_for_each_entry_safe(aeb, aeb_tmp, &ai->erase, u.list) {
+ list_del(&aeb->u.list);
+ kmem_cache_free(ai->aeb_slab_cache, aeb);
}
- list_for_each_entry_safe(seb, seb_tmp, &si->corr, u.list) {
- list_del(&seb->u.list);
- kmem_cache_free(si->scan_leb_slab, seb);
+ list_for_each_entry_safe(aeb, aeb_tmp, &ai->corr, u.list) {
+ list_del(&aeb->u.list);
+ kmem_cache_free(ai->aeb_slab_cache, aeb);
}
- list_for_each_entry_safe(seb, seb_tmp, &si->free, u.list) {
- list_del(&seb->u.list);
- kmem_cache_free(si->scan_leb_slab, seb);
+ list_for_each_entry_safe(aeb, aeb_tmp, &ai->free, u.list) {
+ list_del(&aeb->u.list);
+ kmem_cache_free(ai->aeb_slab_cache, aeb);
}
/* Destroy the volume RB-tree */
- rb = si->volumes.rb_node;
+ rb = ai->volumes.rb_node;
while (rb) {
if (rb->rb_left)
rb = rb->rb_left;
else if (rb->rb_right)
rb = rb->rb_right;
else {
- sv = rb_entry(rb, struct ubi_scan_volume, rb);
+ av = rb_entry(rb, struct ubi_ainf_volume, rb);
rb = rb_parent(rb);
if (rb) {
- if (rb->rb_left == &sv->rb)
+ if (rb->rb_left == &av->rb)
rb->rb_left = NULL;
else
rb->rb_right = NULL;
}
- destroy_sv(si, sv);
+ destroy_av(ai, av);
}
}
- if (si->scan_leb_slab)
- kmem_cache_destroy(si->scan_leb_slab);
+ if (ai->aeb_slab_cache)
+ kmem_cache_destroy(ai->aeb_slab_cache);
- kfree(si);
+ kfree(ai);
}
-#ifdef CONFIG_MTD_UBI_DEBUG
-
/**
- * paranoid_check_si - check the scanning information.
+ * self_check_ai - check the attaching information.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
*
- * This function returns zero if the scanning information is all right, and a
+ * This function returns zero if the attaching information is all right, and a
* negative error code if not or if an error occurred.
*/
-static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
+static int self_check_ai(struct ubi_device *ubi, struct ubi_attach_info *ai)
{
int pnum, err, vols_found = 0;
struct rb_node *rb1, *rb2;
- struct ubi_scan_volume *sv;
- struct ubi_scan_leb *seb, *last_seb;
+ struct ubi_ainf_volume *av;
+ struct ubi_ainf_peb *aeb, *last_aeb;
uint8_t *buf;
if (!ubi->dbg->chk_gen)
return 0;
/*
- * At first, check that scanning information is OK.
+ * At first, check that attaching information is OK.
*/
- ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
+ ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb) {
int leb_count = 0;
cond_resched();
vols_found += 1;
- if (si->is_empty) {
+ if (ai->is_empty) {
ubi_err("bad is_empty flag");
- goto bad_sv;
+ goto bad_av;
}
- if (sv->vol_id < 0 || sv->highest_lnum < 0 ||
- sv->leb_count < 0 || sv->vol_type < 0 || sv->used_ebs < 0 ||
- sv->data_pad < 0 || sv->last_data_size < 0) {
+ if (av->vol_id < 0 || av->highest_lnum < 0 ||
+ av->leb_count < 0 || av->vol_type < 0 || av->used_ebs < 0 ||
+ av->data_pad < 0 || av->last_data_size < 0) {
ubi_err("negative values");
- goto bad_sv;
+ goto bad_av;
}
- if (sv->vol_id >= UBI_MAX_VOLUMES &&
- sv->vol_id < UBI_INTERNAL_VOL_START) {
+ if (av->vol_id >= UBI_MAX_VOLUMES &&
+ av->vol_id < UBI_INTERNAL_VOL_START) {
ubi_err("bad vol_id");
- goto bad_sv;
+ goto bad_av;
}
- if (sv->vol_id > si->highest_vol_id) {
+ if (av->vol_id > ai->highest_vol_id) {
ubi_err("highest_vol_id is %d, but vol_id %d is there",
- si->highest_vol_id, sv->vol_id);
+ ai->highest_vol_id, av->vol_id);
goto out;
}
- if (sv->vol_type != UBI_DYNAMIC_VOLUME &&
- sv->vol_type != UBI_STATIC_VOLUME) {
+ if (av->vol_type != UBI_DYNAMIC_VOLUME &&
+ av->vol_type != UBI_STATIC_VOLUME) {
ubi_err("bad vol_type");
- goto bad_sv;
+ goto bad_av;
}
- if (sv->data_pad > ubi->leb_size / 2) {
+ if (av->data_pad > ubi->leb_size / 2) {
ubi_err("bad data_pad");
- goto bad_sv;
+ goto bad_av;
}
- last_seb = NULL;
- ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) {
+ last_aeb = NULL;
+ ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb) {
cond_resched();
- last_seb = seb;
+ last_aeb = aeb;
leb_count += 1;
- if (seb->pnum < 0 || seb->ec < 0) {
+ if (aeb->pnum < 0 || aeb->ec < 0) {
ubi_err("negative values");
- goto bad_seb;
+ goto bad_aeb;
}
- if (seb->ec < si->min_ec) {
- ubi_err("bad si->min_ec (%d), %d found",
- si->min_ec, seb->ec);
- goto bad_seb;
+ if (aeb->ec < ai->min_ec) {
+ ubi_err("bad ai->min_ec (%d), %d found",
+ ai->min_ec, aeb->ec);
+ goto bad_aeb;
}
- if (seb->ec > si->max_ec) {
- ubi_err("bad si->max_ec (%d), %d found",
- si->max_ec, seb->ec);
- goto bad_seb;
+ if (aeb->ec > ai->max_ec) {
+ ubi_err("bad ai->max_ec (%d), %d found",
+ ai->max_ec, aeb->ec);
+ goto bad_aeb;
}
- if (seb->pnum >= ubi->peb_count) {
+ if (aeb->pnum >= ubi->peb_count) {
ubi_err("too high PEB number %d, total PEBs %d",
- seb->pnum, ubi->peb_count);
- goto bad_seb;
+ aeb->pnum, ubi->peb_count);
+ goto bad_aeb;
}
- if (sv->vol_type == UBI_STATIC_VOLUME) {
- if (seb->lnum >= sv->used_ebs) {
+ if (av->vol_type == UBI_STATIC_VOLUME) {
+ if (aeb->lnum >= av->used_ebs) {
ubi_err("bad lnum or used_ebs");
- goto bad_seb;
+ goto bad_aeb;
}
} else {
- if (sv->used_ebs != 0) {
+ if (av->used_ebs != 0) {
ubi_err("non-zero used_ebs");
- goto bad_seb;
+ goto bad_aeb;
}
}
- if (seb->lnum > sv->highest_lnum) {
+ if (aeb->lnum > av->highest_lnum) {
ubi_err("incorrect highest_lnum or lnum");
- goto bad_seb;
+ goto bad_aeb;
}
}
- if (sv->leb_count != leb_count) {
+ if (av->leb_count != leb_count) {
ubi_err("bad leb_count, %d objects in the tree",
leb_count);
- goto bad_sv;
+ goto bad_av;
}
- if (!last_seb)
+ if (!last_aeb)
continue;
- seb = last_seb;
+ aeb = last_aeb;
- if (seb->lnum != sv->highest_lnum) {
+ if (aeb->lnum != av->highest_lnum) {
ubi_err("bad highest_lnum");
- goto bad_seb;
+ goto bad_aeb;
}
}
- if (vols_found != si->vols_found) {
- ubi_err("bad si->vols_found %d, should be %d",
- si->vols_found, vols_found);
+ if (vols_found != ai->vols_found) {
+ ubi_err("bad ai->vols_found %d, should be %d",
+ ai->vols_found, vols_found);
goto out;
}
- /* Check that scanning information is correct */
- ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
- last_seb = NULL;
- ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) {
+ /* Check that attaching information is correct */
+ ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb) {
+ last_aeb = NULL;
+ ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb) {
int vol_type;
cond_resched();
- last_seb = seb;
+ last_aeb = aeb;
- err = ubi_io_read_vid_hdr(ubi, seb->pnum, vidh, 1);
+ err = ubi_io_read_vid_hdr(ubi, aeb->pnum, vidh, 1);
if (err && err != UBI_IO_BITFLIPS) {
ubi_err("VID header is not OK (%d)", err);
if (err > 0)
@@ -1486,52 +1514,52 @@ static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
vol_type = vidh->vol_type == UBI_VID_DYNAMIC ?
UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME;
- if (sv->vol_type != vol_type) {
+ if (av->vol_type != vol_type) {
ubi_err("bad vol_type");
goto bad_vid_hdr;
}
- if (seb->sqnum != be64_to_cpu(vidh->sqnum)) {
- ubi_err("bad sqnum %llu", seb->sqnum);
+ if (aeb->sqnum != be64_to_cpu(vidh->sqnum)) {
+ ubi_err("bad sqnum %llu", aeb->sqnum);
goto bad_vid_hdr;
}
- if (sv->vol_id != be32_to_cpu(vidh->vol_id)) {
- ubi_err("bad vol_id %d", sv->vol_id);
+ if (av->vol_id != be32_to_cpu(vidh->vol_id)) {
+ ubi_err("bad vol_id %d", av->vol_id);
goto bad_vid_hdr;
}
- if (sv->compat != vidh->compat) {
+ if (av->compat != vidh->compat) {
ubi_err("bad compat %d", vidh->compat);
goto bad_vid_hdr;
}
- if (seb->lnum != be32_to_cpu(vidh->lnum)) {
- ubi_err("bad lnum %d", seb->lnum);
+ if (aeb->lnum != be32_to_cpu(vidh->lnum)) {
+ ubi_err("bad lnum %d", aeb->lnum);
goto bad_vid_hdr;
}
- if (sv->used_ebs != be32_to_cpu(vidh->used_ebs)) {
- ubi_err("bad used_ebs %d", sv->used_ebs);
+ if (av->used_ebs != be32_to_cpu(vidh->used_ebs)) {
+ ubi_err("bad used_ebs %d", av->used_ebs);
goto bad_vid_hdr;
}
- if (sv->data_pad != be32_to_cpu(vidh->data_pad)) {
- ubi_err("bad data_pad %d", sv->data_pad);
+ if (av->data_pad != be32_to_cpu(vidh->data_pad)) {
+ ubi_err("bad data_pad %d", av->data_pad);
goto bad_vid_hdr;
}
}
- if (!last_seb)
+ if (!last_aeb)
continue;
- if (sv->highest_lnum != be32_to_cpu(vidh->lnum)) {
- ubi_err("bad highest_lnum %d", sv->highest_lnum);
+ if (av->highest_lnum != be32_to_cpu(vidh->lnum)) {
+ ubi_err("bad highest_lnum %d", av->highest_lnum);
goto bad_vid_hdr;
}
- if (sv->last_data_size != be32_to_cpu(vidh->data_size)) {
- ubi_err("bad last_data_size %d", sv->last_data_size);
+ if (av->last_data_size != be32_to_cpu(vidh->data_size)) {
+ ubi_err("bad last_data_size %d", av->last_data_size);
goto bad_vid_hdr;
}
}
@@ -1553,21 +1581,21 @@ static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
buf[pnum] = 1;
}
- ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb)
- ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb)
- buf[seb->pnum] = 1;
+ ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb)
+ ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb)
+ buf[aeb->pnum] = 1;
- list_for_each_entry(seb, &si->free, u.list)
- buf[seb->pnum] = 1;
+ list_for_each_entry(aeb, &ai->free, u.list)
+ buf[aeb->pnum] = 1;
- list_for_each_entry(seb, &si->corr, u.list)
- buf[seb->pnum] = 1;
+ list_for_each_entry(aeb, &ai->corr, u.list)
+ buf[aeb->pnum] = 1;
- list_for_each_entry(seb, &si->erase, u.list)
- buf[seb->pnum] = 1;
+ list_for_each_entry(aeb, &ai->erase, u.list)
+ buf[aeb->pnum] = 1;
- list_for_each_entry(seb, &si->alien, u.list)
- buf[seb->pnum] = 1;
+ list_for_each_entry(aeb, &ai->alien, u.list)
+ buf[aeb->pnum] = 1;
err = 0;
for (pnum = 0; pnum < ubi->peb_count; pnum++)
@@ -1581,25 +1609,23 @@ static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si)
goto out;
return 0;
-bad_seb:
- ubi_err("bad scanning information about LEB %d", seb->lnum);
- ubi_dbg_dump_seb(seb, 0);
- ubi_dbg_dump_sv(sv);
+bad_aeb:
+ ubi_err("bad attaching information about LEB %d", aeb->lnum);
+ ubi_dump_aeb(aeb, 0);
+ ubi_dump_av(av);
goto out;
-bad_sv:
- ubi_err("bad scanning information about volume %d", sv->vol_id);
- ubi_dbg_dump_sv(sv);
+bad_av:
+ ubi_err("bad attaching information about volume %d", av->vol_id);
+ ubi_dump_av(av);
goto out;
bad_vid_hdr:
- ubi_err("bad scanning information about volume %d", sv->vol_id);
- ubi_dbg_dump_sv(sv);
- ubi_dbg_dump_vid_hdr(vidh);
+ ubi_err("bad attaching information about volume %d", av->vol_id);
+ ubi_dump_av(av);
+ ubi_dump_vid_hdr(vidh);
out:
- ubi_dbg_dump_stack();
+ dump_stack();
return -EINVAL;
}
-
-#endif /* CONFIG_MTD_UBI_DEBUG */
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 0fde9fc7d2e5..2c5ed5ca9c33 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -27,10 +27,6 @@
* module load parameters or the kernel boot parameters. If MTD devices were
* specified, UBI does not attach any MTD device, but it is possible to do
* later using the "UBI control device".
- *
- * At the moment we only attach UBI devices by scanning, which will become a
- * bottleneck when flashes reach certain large size. Then one may improve UBI
- * and add other methods, although it does not seem to be easy to do.
*/
#include <linux/err.h>
@@ -554,10 +550,10 @@ static void uif_close(struct ubi_device *ubi)
}
/**
- * free_internal_volumes - free internal volumes.
+ * ubi_free_internal_volumes - free internal volumes.
* @ubi: UBI device description object
*/
-static void free_internal_volumes(struct ubi_device *ubi)
+void ubi_free_internal_volumes(struct ubi_device *ubi)
{
int i;
@@ -569,59 +565,6 @@ static void free_internal_volumes(struct ubi_device *ubi)
}
/**
- * attach_by_scanning - attach an MTD device using scanning method.
- * @ubi: UBI device descriptor
- *
- * This function returns zero in case of success and a negative error code in
- * case of failure.
- *
- * Note, currently this is the only method to attach UBI devices. Hopefully in
- * the future we'll have more scalable attaching methods and avoid full media
- * scanning. But even in this case scanning will be needed as a fall-back
- * attaching method if there are some on-flash table corruptions.
- */
-static int attach_by_scanning(struct ubi_device *ubi)
-{
- int err;
- struct ubi_scan_info *si;
-
- si = ubi_scan(ubi);
- if (IS_ERR(si))
- return PTR_ERR(si);
-
- ubi->bad_peb_count = si->bad_peb_count;
- ubi->good_peb_count = ubi->peb_count - ubi->bad_peb_count;
- ubi->corr_peb_count = si->corr_peb_count;
- ubi->max_ec = si->max_ec;
- ubi->mean_ec = si->mean_ec;
- ubi_msg("max. sequence number: %llu", si->max_sqnum);
-
- err = ubi_read_volume_table(ubi, si);
- if (err)
- goto out_si;
-
- err = ubi_wl_init_scan(ubi, si);
- if (err)
- goto out_vtbl;
-
- err = ubi_eba_init_scan(ubi, si);
- if (err)
- goto out_wl;
-
- ubi_scan_destroy_si(si);
- return 0;
-
-out_wl:
- ubi_wl_close(ubi);
-out_vtbl:
- free_internal_volumes(ubi);
- vfree(ubi->vtbl);
-out_si:
- ubi_scan_destroy_si(si);
- return err;
-}
-
-/**
* io_init - initialize I/O sub-system for a given UBI device.
* @ubi: UBI device description object
*
@@ -790,11 +733,11 @@ static int io_init(struct ubi_device *ubi)
ubi_msg("data offset: %d", ubi->leb_start);
/*
- * Note, ideally, we have to initialize ubi->bad_peb_count here. But
+ * Note, ideally, we have to initialize @ubi->bad_peb_count here. But
* unfortunately, MTD does not provide this information. We should loop
* over all physical eraseblocks and invoke mtd->block_is_bad() for
- * each physical eraseblock. So, we skip ubi->bad_peb_count
- * uninitialized and initialize it after scanning.
+ * each physical eraseblock. So, we leave @ubi->bad_peb_count
+ * uninitialized so far.
*/
return 0;
@@ -805,7 +748,7 @@ static int io_init(struct ubi_device *ubi)
* @ubi: UBI device description object
* @vol_id: ID of the volume to re-size
*
- * This function re-sizes the volume marked by the @UBI_VTBL_AUTORESIZE_FLG in
+ * This function re-sizes the volume marked by the %UBI_VTBL_AUTORESIZE_FLG in
* the volume table to the largest possible size. See comments in ubi-header.h
* for more description of the flag. Returns zero in case of success and a
* negative error code in case of failure.
@@ -881,7 +824,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
for (i = 0; i < UBI_MAX_DEVICES; i++) {
ubi = ubi_devices[i];
if (ubi && mtd->index == ubi->mtd->index) {
- dbg_err("mtd%d is already attached to ubi%d",
+ ubi_err("mtd%d is already attached to ubi%d",
mtd->index, i);
return -EEXIST;
}
@@ -907,7 +850,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
if (!ubi_devices[ubi_num])
break;
if (ubi_num == UBI_MAX_DEVICES) {
- dbg_err("only %d UBI devices may be created",
+ ubi_err("only %d UBI devices may be created",
UBI_MAX_DEVICES);
return -ENFILE;
}
@@ -917,7 +860,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
/* Make sure ubi_num is not busy */
if (ubi_devices[ubi_num]) {
- dbg_err("ubi%d already exists", ubi_num);
+ ubi_err("ubi%d already exists", ubi_num);
return -EEXIST;
}
}
@@ -937,7 +880,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
spin_lock_init(&ubi->volumes_lock);
ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num);
- dbg_msg("sizeof(struct ubi_scan_leb) %zu", sizeof(struct ubi_scan_leb));
+ dbg_msg("sizeof(struct ubi_ainf_peb) %zu", sizeof(struct ubi_ainf_peb));
dbg_msg("sizeof(struct ubi_wl_entry) %zu", sizeof(struct ubi_wl_entry));
err = io_init(ubi);
@@ -953,9 +896,9 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset)
if (err)
goto out_free;
- err = attach_by_scanning(ubi);
+ err = ubi_attach(ubi);
if (err) {
- dbg_err("failed to attach by scanning, error %d", err);
+ ubi_err("failed to attach mtd%d, error %d", mtd->index, err);
goto out_debugging;
}
@@ -1020,7 +963,7 @@ out_uif:
uif_close(ubi);
out_detach:
ubi_wl_close(ubi);
- free_internal_volumes(ubi);
+ ubi_free_internal_volumes(ubi);
vfree(ubi->vtbl);
out_debugging:
ubi_debugging_exit_dev(ubi);
@@ -1092,7 +1035,7 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway)
ubi_debugfs_exit_dev(ubi);
uif_close(ubi);
ubi_wl_close(ubi);
- free_internal_volumes(ubi);
+ ubi_free_internal_volumes(ubi);
vfree(ubi->vtbl);
put_mtd_device(ubi->mtd);
ubi_debugging_exit_dev(ubi);
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index ad76592fb2f4..acec85deb6af 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -63,7 +63,7 @@ static int get_exclusive(struct ubi_volume_desc *desc)
users = vol->readers + vol->writers + vol->exclusive;
ubi_assert(users > 0);
if (users > 1) {
- dbg_err("%d users for volume %d", users, vol->vol_id);
+ ubi_err("%d users for volume %d", users, vol->vol_id);
err = -EBUSY;
} else {
vol->readers = vol->writers = 0;
@@ -159,7 +159,7 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
if (vol->updating) {
/* Update is in progress, seeking is prohibited */
- dbg_err("updating");
+ ubi_err("updating");
return -EBUSY;
}
@@ -178,7 +178,7 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
}
if (new_offset < 0 || new_offset > vol->used_bytes) {
- dbg_err("bad seek %lld", new_offset);
+ ubi_err("bad seek %lld", new_offset);
return -EINVAL;
}
@@ -216,11 +216,11 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
count, *offp, vol->vol_id);
if (vol->updating) {
- dbg_err("updating");
+ ubi_err("updating");
return -EBUSY;
}
if (vol->upd_marker) {
- dbg_err("damaged volume, update marker is set");
+ ubi_err("damaged volume, update marker is set");
return -EBADF;
}
if (*offp == vol->used_bytes || count == 0)
@@ -300,7 +300,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
lnum = div_u64_rem(*offp, vol->usable_leb_size, &off);
if (off & (ubi->min_io_size - 1)) {
- dbg_err("unaligned position");
+ ubi_err("unaligned position");
return -EINVAL;
}
@@ -309,7 +309,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
/* We can write only in fractions of the minimum I/O unit */
if (count & (ubi->min_io_size - 1)) {
- dbg_err("unaligned write length");
+ ubi_err("unaligned write length");
return -EINVAL;
}
@@ -334,8 +334,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
break;
}
- err = ubi_eba_write_leb(ubi, vol, lnum, tbuf, off, len,
- UBI_UNKNOWN);
+ err = ubi_eba_write_leb(ubi, vol, lnum, tbuf, off, len);
if (err)
break;
@@ -477,9 +476,6 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
if (req.lnum < 0 || req.lnum >= vol->reserved_pebs ||
req.bytes < 0 || req.lnum >= vol->usable_leb_size)
break;
- if (req.dtype != UBI_LONGTERM && req.dtype != UBI_SHORTTERM &&
- req.dtype != UBI_UNKNOWN)
- break;
err = get_exclusive(desc);
if (err < 0)
@@ -518,7 +514,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
if (err)
break;
- err = ubi_wl_flush(ubi);
+ err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
break;
}
@@ -532,7 +528,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
err = -EFAULT;
break;
}
- err = ubi_leb_map(desc, req.lnum, req.dtype);
+ err = ubi_leb_map(desc, req.lnum);
break;
}
@@ -647,8 +643,8 @@ static int verify_mkvol_req(const struct ubi_device *ubi,
return 0;
bad:
- dbg_err("bad volume creation request");
- ubi_dbg_dump_mkvol_req(req);
+ ubi_err("bad volume creation request");
+ ubi_dump_mkvol_req(req);
return err;
}
@@ -713,12 +709,12 @@ static int rename_volumes(struct ubi_device *ubi,
for (i = 0; i < req->count - 1; i++) {
for (n = i + 1; n < req->count; n++) {
if (req->ents[i].vol_id == req->ents[n].vol_id) {
- dbg_err("duplicated volume id %d",
+ ubi_err("duplicated volume id %d",
req->ents[i].vol_id);
return -EINVAL;
}
if (!strcmp(req->ents[i].name, req->ents[n].name)) {
- dbg_err("duplicated volume name \"%s\"",
+ ubi_err("duplicated volume name \"%s\"",
req->ents[i].name);
return -EINVAL;
}
@@ -741,7 +737,7 @@ static int rename_volumes(struct ubi_device *ubi,
re->desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_EXCLUSIVE);
if (IS_ERR(re->desc)) {
err = PTR_ERR(re->desc);
- dbg_err("cannot open volume %d, error %d", vol_id, err);
+ ubi_err("cannot open volume %d, error %d", vol_id, err);
kfree(re);
goto out_free;
}
@@ -800,7 +796,7 @@ static int rename_volumes(struct ubi_device *ubi,
continue;
/* The volume exists but busy, or an error occurred */
- dbg_err("cannot open volume \"%s\", error %d",
+ ubi_err("cannot open volume \"%s\", error %d",
re->new_name, err);
goto out_free;
}
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
index 61af9bb560ab..9f957c2d48e9 100644
--- a/drivers/mtd/ubi/debug.c
+++ b/drivers/mtd/ubi/debug.c
@@ -18,24 +18,49 @@
* Author: Artem Bityutskiy (Битюцкий Артём)
*/
-/*
- * Here we keep all the UBI debugging stuff which should normally be disabled
- * and compiled-out, but it is extremely helpful when hunting bugs or doing big
- * changes.
- */
-
-#ifdef CONFIG_MTD_UBI_DEBUG
-
#include "ubi.h"
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <linux/module.h>
+
+/**
+ * ubi_dump_flash - dump a region of flash.
+ * @ubi: UBI device description object
+ * @pnum: the physical eraseblock number to dump
+ * @offset: the starting offset within the physical eraseblock to dump
+ * @len: the length of the region to dump
+ */
+void ubi_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len)
+{
+ int err;
+ size_t read;
+ void *buf;
+ loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
+
+ buf = vmalloc(len);
+ if (!buf)
+ return;
+ err = mtd_read(ubi->mtd, addr, len, &read, buf);
+ if (err && err != -EUCLEAN) {
+ ubi_err("error %d while reading %d bytes from PEB %d:%d, "
+ "read %zd bytes", err, len, pnum, offset, read);
+ goto out;
+ }
+
+ ubi_msg("dumping %d bytes of data from PEB %d, offset %d",
+ len, pnum, offset);
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
+out:
+ vfree(buf);
+ return;
+}
+
/**
- * ubi_dbg_dump_ec_hdr - dump an erase counter header.
+ * ubi_dump_ec_hdr - dump an erase counter header.
* @ec_hdr: the erase counter header to dump
*/
-void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
+void ubi_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
{
printk(KERN_DEBUG "Erase counter header dump:\n");
printk(KERN_DEBUG "\tmagic %#08x\n",
@@ -57,10 +82,10 @@ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
}
/**
- * ubi_dbg_dump_vid_hdr - dump a volume identifier header.
+ * ubi_dump_vid_hdr - dump a volume identifier header.
* @vid_hdr: the volume identifier header to dump
*/
-void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
+void ubi_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
{
printk(KERN_DEBUG "Volume identifier header dump:\n");
printk(KERN_DEBUG "\tmagic %08x\n", be32_to_cpu(vid_hdr->magic));
@@ -82,10 +107,10 @@ void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
}
/**
- * ubi_dbg_dump_vol_info- dump volume information.
+ * ubi_dump_vol_info - dump volume information.
* @vol: UBI volume description object
*/
-void ubi_dbg_dump_vol_info(const struct ubi_volume *vol)
+void ubi_dump_vol_info(const struct ubi_volume *vol)
{
printk(KERN_DEBUG "Volume information dump:\n");
printk(KERN_DEBUG "\tvol_id %d\n", vol->vol_id);
@@ -112,11 +137,11 @@ void ubi_dbg_dump_vol_info(const struct ubi_volume *vol)
}
/**
- * ubi_dbg_dump_vtbl_record - dump a &struct ubi_vtbl_record object.
+ * ubi_dump_vtbl_record - dump a &struct ubi_vtbl_record object.
* @r: the object to dump
* @idx: volume table index
*/
-void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)
+void ubi_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)
{
int name_len = be16_to_cpu(r->name_len);
@@ -146,44 +171,44 @@ void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)
}
/**
- * ubi_dbg_dump_sv - dump a &struct ubi_scan_volume object.
- * @sv: the object to dump
+ * ubi_dump_av - dump a &struct ubi_ainf_volume object.
+ * @av: the object to dump
*/
-void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv)
+void ubi_dump_av(const struct ubi_ainf_volume *av)
{
- printk(KERN_DEBUG "Volume scanning information dump:\n");
- printk(KERN_DEBUG "\tvol_id %d\n", sv->vol_id);
- printk(KERN_DEBUG "\thighest_lnum %d\n", sv->highest_lnum);
- printk(KERN_DEBUG "\tleb_count %d\n", sv->leb_count);
- printk(KERN_DEBUG "\tcompat %d\n", sv->compat);
- printk(KERN_DEBUG "\tvol_type %d\n", sv->vol_type);
- printk(KERN_DEBUG "\tused_ebs %d\n", sv->used_ebs);
- printk(KERN_DEBUG "\tlast_data_size %d\n", sv->last_data_size);
- printk(KERN_DEBUG "\tdata_pad %d\n", sv->data_pad);
+ printk(KERN_DEBUG "Volume attaching information dump:\n");
+ printk(KERN_DEBUG "\tvol_id %d\n", av->vol_id);
+ printk(KERN_DEBUG "\thighest_lnum %d\n", av->highest_lnum);
+ printk(KERN_DEBUG "\tleb_count %d\n", av->leb_count);
+ printk(KERN_DEBUG "\tcompat %d\n", av->compat);
+ printk(KERN_DEBUG "\tvol_type %d\n", av->vol_type);
+ printk(KERN_DEBUG "\tused_ebs %d\n", av->used_ebs);
+ printk(KERN_DEBUG "\tlast_data_size %d\n", av->last_data_size);
+ printk(KERN_DEBUG "\tdata_pad %d\n", av->data_pad);
}
/**
- * ubi_dbg_dump_seb - dump a &struct ubi_scan_leb object.
- * @seb: the object to dump
+ * ubi_dump_aeb - dump a &struct ubi_ainf_peb object.
+ * @aeb: the object to dump
* @type: object type: 0 - not corrupted, 1 - corrupted
*/
-void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type)
+void ubi_dump_aeb(const struct ubi_ainf_peb *aeb, int type)
{
- printk(KERN_DEBUG "eraseblock scanning information dump:\n");
- printk(KERN_DEBUG "\tec %d\n", seb->ec);
- printk(KERN_DEBUG "\tpnum %d\n", seb->pnum);
+ printk(KERN_DEBUG "eraseblock attaching information dump:\n");
+ printk(KERN_DEBUG "\tec %d\n", aeb->ec);
+ printk(KERN_DEBUG "\tpnum %d\n", aeb->pnum);
if (type == 0) {
- printk(KERN_DEBUG "\tlnum %d\n", seb->lnum);
- printk(KERN_DEBUG "\tscrub %d\n", seb->scrub);
- printk(KERN_DEBUG "\tsqnum %llu\n", seb->sqnum);
+ printk(KERN_DEBUG "\tlnum %d\n", aeb->lnum);
+ printk(KERN_DEBUG "\tscrub %d\n", aeb->scrub);
+ printk(KERN_DEBUG "\tsqnum %llu\n", aeb->sqnum);
}
}
/**
- * ubi_dbg_dump_mkvol_req - dump a &struct ubi_mkvol_req object.
+ * ubi_dump_mkvol_req - dump a &struct ubi_mkvol_req object.
* @req: the object to dump
*/
-void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req)
+void ubi_dump_mkvol_req(const struct ubi_mkvol_req *req)
{
char nm[17];
@@ -200,38 +225,6 @@ void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req)
}
/**
- * ubi_dbg_dump_flash - dump a region of flash.
- * @ubi: UBI device description object
- * @pnum: the physical eraseblock number to dump
- * @offset: the starting offset within the physical eraseblock to dump
- * @len: the length of the region to dump
- */
-void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len)
-{
- int err;
- size_t read;
- void *buf;
- loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
-
- buf = vmalloc(len);
- if (!buf)
- return;
- err = mtd_read(ubi->mtd, addr, len, &read, buf);
- if (err && err != -EUCLEAN) {
- ubi_err("error %d while reading %d bytes from PEB %d:%d, "
- "read %zd bytes", err, len, pnum, offset, read);
- goto out;
- }
-
- dbg_msg("dumping %d bytes of data from PEB %d, offset %d",
- len, pnum, offset);
- print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
-out:
- vfree(buf);
- return;
-}
-
-/**
* ubi_debugging_init_dev - initialize debugging for an UBI device.
* @ubi: UBI device description object
*
@@ -479,5 +472,3 @@ void ubi_debugfs_exit_dev(struct ubi_device *ubi)
{
debugfs_remove_recursive(ubi->dbg->dfs_dir);
}
-
-#endif /* CONFIG_MTD_UBI_DEBUG */
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index ead2cd16ba75..d5d2645b51a7 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -21,21 +21,20 @@
#ifndef __UBI_DEBUG_H__
#define __UBI_DEBUG_H__
-#ifdef CONFIG_MTD_UBI_DEBUG
+void ubi_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len);
+void ubi_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr);
+void ubi_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
+
#include <linux/random.h>
#define ubi_assert(expr) do { \
if (unlikely(!(expr))) { \
printk(KERN_CRIT "UBI assert failed in %s at %u (pid %d)\n", \
__func__, __LINE__, current->pid); \
- ubi_dbg_dump_stack(); \
+ dump_stack(); \
} \
} while (0)
-#define dbg_err(fmt, ...) ubi_err(fmt, ##__VA_ARGS__)
-
-#define ubi_dbg_dump_stack() dump_stack()
-
#define ubi_dbg_print_hex_dump(l, ps, pt, r, g, b, len, a) \
print_hex_dump(l, ps, pt, r, g, b, len, a)
@@ -58,17 +57,13 @@
/* Initialization and build messages */
#define dbg_bld(fmt, ...) ubi_dbg_msg("bld", fmt, ##__VA_ARGS__)
-void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr);
-void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
-void ubi_dbg_dump_vol_info(const struct ubi_volume *vol);
-void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx);
-void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv);
-void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type);
-void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
-void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len);
-int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len);
-int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
- int offset, int len);
+void ubi_dump_vol_info(const struct ubi_volume *vol);
+void ubi_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx);
+void ubi_dump_av(const struct ubi_ainf_volume *av);
+void ubi_dump_aeb(const struct ubi_ainf_peb *aeb, int type);
+void ubi_dump_mkvol_req(const struct ubi_mkvol_req *req);
+int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset,
+ int len);
int ubi_debugging_init_dev(struct ubi_device *ubi);
void ubi_debugging_exit_dev(struct ubi_device *ubi);
int ubi_debugfs_init(void);
@@ -167,73 +162,4 @@ static inline int ubi_dbg_is_erase_failure(const struct ubi_device *ubi)
return 0;
}
-#else
-
-/* Use "if (0)" to make compiler check arguments even if debugging is off */
-#define ubi_assert(expr) do { \
- if (0) { \
- printk(KERN_CRIT "UBI assert failed in %s at %u (pid %d)\n", \
- __func__, __LINE__, current->pid); \
- } \
-} while (0)
-
-#define dbg_err(fmt, ...) do { \
- if (0) \
- ubi_err(fmt, ##__VA_ARGS__); \
-} while (0)
-
-#define ubi_dbg_msg(fmt, ...) do { \
- if (0) \
- printk(KERN_DEBUG fmt "\n", ##__VA_ARGS__); \
-} while (0)
-
-#define dbg_msg(fmt, ...) ubi_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_gen(fmt, ...) ubi_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_eba(fmt, ...) ubi_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_wl(fmt, ...) ubi_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_io(fmt, ...) ubi_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_bld(fmt, ...) ubi_dbg_msg(fmt, ##__VA_ARGS__)
-
-static inline void ubi_dbg_dump_stack(void) { return; }
-static inline void
-ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr) { return; }
-static inline void
-ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr) { return; }
-static inline void
-ubi_dbg_dump_vol_info(const struct ubi_volume *vol) { return; }
-static inline void
-ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx) { return; }
-static inline void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv) { return; }
-static inline void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb,
- int type) { return; }
-static inline void
-ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req) { return; }
-static inline void ubi_dbg_dump_flash(struct ubi_device *ubi,
- int pnum, int offset, int len) { return; }
-static inline void
-ubi_dbg_print_hex_dump(const char *l, const char *ps, int pt, int r,
- int g, const void *b, size_t len, bool a) { return; }
-static inline int ubi_dbg_check_all_ff(struct ubi_device *ubi,
- int pnum, int offset,
- int len) { return 0; }
-static inline int ubi_dbg_check_write(struct ubi_device *ubi,
- const void *buf, int pnum,
- int offset, int len) { return 0; }
-
-static inline int ubi_debugging_init_dev(struct ubi_device *ubi) { return 0; }
-static inline void ubi_debugging_exit_dev(struct ubi_device *ubi) { return; }
-static inline int ubi_debugfs_init(void) { return 0; }
-static inline void ubi_debugfs_exit(void) { return; }
-static inline int ubi_debugfs_init_dev(struct ubi_device *ubi) { return 0; }
-static inline void ubi_debugfs_exit_dev(struct ubi_device *ubi) { return; }
-
-static inline int
-ubi_dbg_is_bgt_disabled(const struct ubi_device *ubi) { return 0; }
-static inline int ubi_dbg_is_bitflip(const struct ubi_device *ubi) { return 0; }
-static inline int
-ubi_dbg_is_write_failure(const struct ubi_device *ubi) { return 0; }
-static inline int
-ubi_dbg_is_erase_failure(const struct ubi_device *ubi) { return 0; }
-
-#endif /* !CONFIG_MTD_UBI_DEBUG */
#endif /* !__UBI_DEBUG_H__ */
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 2455d620d96b..b703ac7729cf 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -341,7 +341,7 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
dbg_eba("erase LEB %d:%d, PEB %d", vol_id, lnum, pnum);
vol->eba_tbl[lnum] = UBI_LEB_UNMAPPED;
- err = ubi_wl_put_peb(ubi, pnum, 0);
+ err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 0);
out_unlock:
leb_write_unlock(ubi, vol_id, lnum);
@@ -507,7 +507,7 @@ static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum,
return -ENOMEM;
retry:
- new_pnum = ubi_wl_get_peb(ubi, UBI_UNKNOWN);
+ new_pnum = ubi_wl_get_peb(ubi);
if (new_pnum < 0) {
ubi_free_vid_hdr(ubi, vid_hdr);
return new_pnum;
@@ -550,7 +550,7 @@ retry:
ubi_free_vid_hdr(ubi, vid_hdr);
vol->eba_tbl[lnum] = new_pnum;
- ubi_wl_put_peb(ubi, pnum, 1);
+ ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
ubi_msg("data was successfully recovered");
return 0;
@@ -558,7 +558,7 @@ retry:
out_unlock:
mutex_unlock(&ubi->buf_mutex);
out_put:
- ubi_wl_put_peb(ubi, new_pnum, 1);
+ ubi_wl_put_peb(ubi, vol_id, lnum, new_pnum, 1);
ubi_free_vid_hdr(ubi, vid_hdr);
return err;
@@ -568,7 +568,7 @@ write_error:
* get another one.
*/
ubi_warn("failed to write to PEB %d", new_pnum);
- ubi_wl_put_peb(ubi, new_pnum, 1);
+ ubi_wl_put_peb(ubi, vol_id, lnum, new_pnum, 1);
if (++tries > UBI_IO_RETRIES) {
ubi_free_vid_hdr(ubi, vid_hdr);
return err;
@@ -585,7 +585,6 @@ write_error:
* @buf: the data to write
* @offset: offset within the logical eraseblock where to write
* @len: how many bytes to write
- * @dtype: data type
*
* This function writes data to logical eraseblock @lnum of a dynamic volume
* @vol. Returns zero in case of success and a negative error code in case
@@ -593,7 +592,7 @@ write_error:
* written to the flash media, but may be some garbage.
*/
int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
- const void *buf, int offset, int len, int dtype)
+ const void *buf, int offset, int len)
{
int err, pnum, tries = 0, vol_id = vol->vol_id;
struct ubi_vid_hdr *vid_hdr;
@@ -641,7 +640,7 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
retry:
- pnum = ubi_wl_get_peb(ubi, dtype);
+ pnum = ubi_wl_get_peb(ubi);
if (pnum < 0) {
ubi_free_vid_hdr(ubi, vid_hdr);
leb_write_unlock(ubi, vol_id, lnum);
@@ -687,7 +686,7 @@ write_error:
* eraseblock, so just put it and request a new one. We assume that if
* this physical eraseblock went bad, the erase code will handle that.
*/
- err = ubi_wl_put_peb(ubi, pnum, 1);
+ err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
if (err || ++tries > UBI_IO_RETRIES) {
ubi_ro_mode(ubi);
leb_write_unlock(ubi, vol_id, lnum);
@@ -707,7 +706,6 @@ write_error:
* @lnum: logical eraseblock number
* @buf: data to write
* @len: how many bytes to write
- * @dtype: data type
* @used_ebs: how many logical eraseblocks will this volume contain
*
* This function writes data to logical eraseblock @lnum of static volume
@@ -724,8 +722,7 @@ write_error:
* code in case of failure.
*/
int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
- int lnum, const void *buf, int len, int dtype,
- int used_ebs)
+ int lnum, const void *buf, int len, int used_ebs)
{
int err, pnum, tries = 0, data_size = len, vol_id = vol->vol_id;
struct ubi_vid_hdr *vid_hdr;
@@ -763,7 +760,7 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
vid_hdr->data_crc = cpu_to_be32(crc);
retry:
- pnum = ubi_wl_get_peb(ubi, dtype);
+ pnum = ubi_wl_get_peb(ubi);
if (pnum < 0) {
ubi_free_vid_hdr(ubi, vid_hdr);
leb_write_unlock(ubi, vol_id, lnum);
@@ -807,7 +804,7 @@ write_error:
return err;
}
- err = ubi_wl_put_peb(ubi, pnum, 1);
+ err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
if (err || ++tries > UBI_IO_RETRIES) {
ubi_ro_mode(ubi);
leb_write_unlock(ubi, vol_id, lnum);
@@ -827,7 +824,6 @@ write_error:
* @lnum: logical eraseblock number
* @buf: data to write
* @len: how many bytes to write
- * @dtype: data type
*
* This function changes the contents of a logical eraseblock atomically. @buf
* has to contain new logical eraseblock data, and @len - the length of the
@@ -839,7 +835,7 @@ write_error:
* LEB change may be done at a time. This is ensured by @ubi->alc_mutex.
*/
int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
- int lnum, const void *buf, int len, int dtype)
+ int lnum, const void *buf, int len)
{
int err, pnum, tries = 0, vol_id = vol->vol_id;
struct ubi_vid_hdr *vid_hdr;
@@ -856,7 +852,7 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
err = ubi_eba_unmap_leb(ubi, vol, lnum);
if (err)
return err;
- return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype);
+ return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0);
}
vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS);
@@ -881,7 +877,7 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
vid_hdr->data_crc = cpu_to_be32(crc);
retry:
- pnum = ubi_wl_get_peb(ubi, dtype);
+ pnum = ubi_wl_get_peb(ubi);
if (pnum < 0) {
err = pnum;
goto out_leb_unlock;
@@ -905,7 +901,7 @@ retry:
}
if (vol->eba_tbl[lnum] >= 0) {
- err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 0);
+ err = ubi_wl_put_peb(ubi, vol_id, lnum, vol->eba_tbl[lnum], 0);
if (err)
goto out_leb_unlock;
}
@@ -930,7 +926,7 @@ write_error:
goto out_leb_unlock;
}
- err = ubi_wl_put_peb(ubi, pnum, 1);
+ err = ubi_wl_put_peb(ubi, vol_id, lnum, pnum, 1);
if (err || ++tries > UBI_IO_RETRIES) {
ubi_ro_mode(ubi);
goto out_leb_unlock;
@@ -1171,7 +1167,7 @@ out_unlock_leb:
* print_rsvd_warning - warn about not having enough reserved PEBs.
* @ubi: UBI device description object
*
- * This is a helper function for 'ubi_eba_init_scan()' which is called when UBI
+ * This is a helper function for 'ubi_eba_init()' which is called when UBI
* cannot reserve enough PEBs for bad block handling. This function makes a
* decision whether we have to print a warning or not. The algorithm is as
* follows:
@@ -1186,13 +1182,13 @@ out_unlock_leb:
* reported by real users.
*/
static void print_rsvd_warning(struct ubi_device *ubi,
- struct ubi_scan_info *si)
+ struct ubi_attach_info *ai)
{
/*
* The 1 << 18 (256KiB) number is picked randomly, just a reasonably
* large number to distinguish between newly flashed and used images.
*/
- if (si->max_sqnum > (1 << 18)) {
+ if (ai->max_sqnum > (1 << 18)) {
int min = ubi->beb_rsvd_level / 10;
if (!min)
@@ -1209,19 +1205,19 @@ static void print_rsvd_warning(struct ubi_device *ubi,
}
/**
- * ubi_eba_init_scan - initialize the EBA sub-system using scanning information.
+ * ubi_eba_init - initialize the EBA sub-system using attaching information.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
*
* This function returns zero in case of success and a negative error code in
* case of failure.
*/
-int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
+int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
{
int i, j, err, num_volumes;
- struct ubi_scan_volume *sv;
+ struct ubi_ainf_volume *av;
struct ubi_volume *vol;
- struct ubi_scan_leb *seb;
+ struct ubi_ainf_peb *aeb;
struct rb_node *rb;
dbg_eba("initialize EBA sub-system");
@@ -1230,7 +1226,7 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
mutex_init(&ubi->alc_mutex);
ubi->ltree = RB_ROOT;
- ubi->global_sqnum = si->max_sqnum + 1;
+ ubi->global_sqnum = ai->max_sqnum + 1;
num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT;
for (i = 0; i < num_volumes; i++) {
@@ -1250,18 +1246,18 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
for (j = 0; j < vol->reserved_pebs; j++)
vol->eba_tbl[j] = UBI_LEB_UNMAPPED;
- sv = ubi_scan_find_sv(si, idx2vol_id(ubi, i));
- if (!sv)
+ av = ubi_find_av(ai, idx2vol_id(ubi, i));
+ if (!av)
continue;
- ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) {
- if (seb->lnum >= vol->reserved_pebs)
+ ubi_rb_for_each_entry(rb, aeb, &av->root, u.rb) {
+ if (aeb->lnum >= vol->reserved_pebs)
/*
* This may happen in case of an unclean reboot
* during re-size.
*/
- ubi_scan_move_to_list(sv, seb, &si->erase);
- vol->eba_tbl[seb->lnum] = seb->pnum;
+ ubi_move_aeb_to_list(av, aeb, &ai->erase);
+ vol->eba_tbl[aeb->lnum] = aeb->pnum;
}
}
@@ -1283,7 +1279,7 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
if (ubi->avail_pebs < ubi->beb_rsvd_level) {
/* No enough free physical eraseblocks */
ubi->beb_rsvd_pebs = ubi->avail_pebs;
- print_rsvd_warning(ubi, si);
+ print_rsvd_warning(ubi, ai);
} else
ubi->beb_rsvd_pebs = ubi->beb_rsvd_level;
diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c
index 90b98822d9a4..4e44bee4c564 100644
--- a/drivers/mtd/ubi/gluebi.c
+++ b/drivers/mtd/ubi/gluebi.c
@@ -227,7 +227,7 @@ static int gluebi_write(struct mtd_info *mtd, loff_t to, size_t len,
if (to_write > total_written)
to_write = total_written;
- err = ubi_write(gluebi->desc, lnum, buf, offs, to_write);
+ err = ubi_leb_write(gluebi->desc, lnum, buf, offs, to_write);
if (err)
break;
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 43f1a0011a55..a8d523794b52 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -91,21 +91,15 @@
#include <linux/slab.h>
#include "ubi.h"
-#ifdef CONFIG_MTD_UBI_DEBUG
-static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum);
-static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum);
-static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
- const struct ubi_ec_hdr *ec_hdr);
-static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum);
-static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
- const struct ubi_vid_hdr *vid_hdr);
-#else
-#define paranoid_check_not_bad(ubi, pnum) 0
-#define paranoid_check_peb_ec_hdr(ubi, pnum) 0
-#define paranoid_check_ec_hdr(ubi, pnum, ec_hdr) 0
-#define paranoid_check_peb_vid_hdr(ubi, pnum) 0
-#define paranoid_check_vid_hdr(ubi, pnum, vid_hdr) 0
-#endif
+static int self_check_not_bad(const struct ubi_device *ubi, int pnum);
+static int self_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum);
+static int self_check_ec_hdr(const struct ubi_device *ubi, int pnum,
+ const struct ubi_ec_hdr *ec_hdr);
+static int self_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum);
+static int self_check_vid_hdr(const struct ubi_device *ubi, int pnum,
+ const struct ubi_vid_hdr *vid_hdr);
+static int self_check_write(struct ubi_device *ubi, const void *buf, int pnum,
+ int offset, int len);
/**
* ubi_io_read - read data from a physical eraseblock.
@@ -142,7 +136,7 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset,
ubi_assert(offset >= 0 && offset + len <= ubi->peb_size);
ubi_assert(len > 0);
- err = paranoid_check_not_bad(ubi, pnum);
+ err = self_check_not_bad(ubi, pnum);
if (err)
return err;
@@ -189,16 +183,16 @@ retry:
}
if (retries++ < UBI_IO_RETRIES) {
- dbg_io("error %d%s while reading %d bytes from PEB "
- "%d:%d, read only %zd bytes, retry",
- err, errstr, len, pnum, offset, read);
+ ubi_warn("error %d%s while reading %d bytes from PEB "
+ "%d:%d, read only %zd bytes, retry",
+ err, errstr, len, pnum, offset, read);
yield();
goto retry;
}
ubi_err("error %d%s while reading %d bytes from PEB %d:%d, "
"read %zd bytes", err, errstr, len, pnum, offset, read);
- ubi_dbg_dump_stack();
+ dump_stack();
/*
* The driver should never return -EBADMSG if it failed to read
@@ -257,14 +251,12 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
return -EROFS;
}
- /* The below has to be compiled out if paranoid checks are disabled */
-
- err = paranoid_check_not_bad(ubi, pnum);
+ err = self_check_not_bad(ubi, pnum);
if (err)
return err;
/* The area we are writing to has to contain all 0xFF bytes */
- err = ubi_dbg_check_all_ff(ubi, pnum, offset, len);
+ err = ubi_self_check_all_ff(ubi, pnum, offset, len);
if (err)
return err;
@@ -273,18 +265,18 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
* We write to the data area of the physical eraseblock. Make
* sure it has valid EC and VID headers.
*/
- err = paranoid_check_peb_ec_hdr(ubi, pnum);
+ err = self_check_peb_ec_hdr(ubi, pnum);
if (err)
return err;
- err = paranoid_check_peb_vid_hdr(ubi, pnum);
+ err = self_check_peb_vid_hdr(ubi, pnum);
if (err)
return err;
}
if (ubi_dbg_is_write_failure(ubi)) {
- dbg_err("cannot write %d bytes to PEB %d:%d "
+ ubi_err("cannot write %d bytes to PEB %d:%d "
"(emulated)", len, pnum, offset);
- ubi_dbg_dump_stack();
+ dump_stack();
return -EIO;
}
@@ -293,13 +285,13 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
if (err) {
ubi_err("error %d while writing %d bytes to PEB %d:%d, written "
"%zd bytes", err, len, pnum, offset, written);
- ubi_dbg_dump_stack();
- ubi_dbg_dump_flash(ubi, pnum, offset, len);
+ dump_stack();
+ ubi_dump_flash(ubi, pnum, offset, len);
} else
ubi_assert(written == len);
if (!err) {
- err = ubi_dbg_check_write(ubi, buf, pnum, offset, len);
+ err = self_check_write(ubi, buf, pnum, offset, len);
if (err)
return err;
@@ -310,7 +302,7 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
offset += len;
len = ubi->peb_size - offset;
if (len)
- err = ubi_dbg_check_all_ff(ubi, pnum, offset, len);
+ err = ubi_self_check_all_ff(ubi, pnum, offset, len);
}
return err;
@@ -364,13 +356,13 @@ retry:
err = mtd_erase(ubi->mtd, &ei);
if (err) {
if (retries++ < UBI_IO_RETRIES) {
- dbg_io("error %d while erasing PEB %d, retry",
- err, pnum);
+ ubi_warn("error %d while erasing PEB %d, retry",
+ err, pnum);
yield();
goto retry;
}
ubi_err("cannot erase PEB %d, error %d", pnum, err);
- ubi_dbg_dump_stack();
+ dump_stack();
return err;
}
@@ -383,21 +375,21 @@ retry:
if (ei.state == MTD_ERASE_FAILED) {
if (retries++ < UBI_IO_RETRIES) {
- dbg_io("error while erasing PEB %d, retry", pnum);
+ ubi_warn("error while erasing PEB %d, retry", pnum);
yield();
goto retry;
}
ubi_err("cannot erase PEB %d", pnum);
- ubi_dbg_dump_stack();
+ dump_stack();
return -EIO;
}
- err = ubi_dbg_check_all_ff(ubi, pnum, 0, ubi->peb_size);
+ err = ubi_self_check_all_ff(ubi, pnum, 0, ubi->peb_size);
if (err)
return err;
if (ubi_dbg_is_erase_failure(ubi)) {
- dbg_err("cannot erase PEB %d (emulated)", pnum);
+ ubi_err("cannot erase PEB %d (emulated)", pnum);
return -EIO;
}
@@ -521,8 +513,7 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
* It is important to first invalidate the EC header, and then the VID
* header. Otherwise a power cut may lead to valid EC header and
* invalid VID header, in which case UBI will treat this PEB as
- * corrupted and will try to preserve it, and print scary warnings (see
- * the header comment in scan.c for more information).
+ * corrupted and will try to preserve it, and print scary warnings.
*/
addr = (loff_t)pnum * ubi->peb_size;
err = mtd_write(ubi->mtd, addr, 4, &written, (void *)&data);
@@ -563,7 +554,7 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
*/
ubi_err("cannot invalidate PEB %d, write returned %d read returned %d",
pnum, err, err1);
- ubi_dbg_dump_flash(ubi, pnum, 0, ubi->peb_size);
+ ubi_dump_flash(ubi, pnum, 0, ubi->peb_size);
return -EIO;
}
@@ -589,7 +580,7 @@ int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture)
ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
- err = paranoid_check_not_bad(ubi, pnum);
+ err = self_check_not_bad(ubi, pnum);
if (err != 0)
return err;
@@ -721,8 +712,8 @@ static int validate_ec_hdr(const struct ubi_device *ubi,
bad:
ubi_err("bad EC header");
- ubi_dbg_dump_ec_hdr(ec_hdr);
- ubi_dbg_dump_stack();
+ ubi_dump_ec_hdr(ec_hdr);
+ dump_stack();
return 1;
}
@@ -803,7 +794,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
if (verbose) {
ubi_warn("bad magic number at PEB %d: %08x instead of "
"%08x", pnum, magic, UBI_EC_HDR_MAGIC);
- ubi_dbg_dump_ec_hdr(ec_hdr);
+ ubi_dump_ec_hdr(ec_hdr);
}
dbg_bld("bad magic number at PEB %d: %08x instead of "
"%08x", pnum, magic, UBI_EC_HDR_MAGIC);
@@ -817,7 +808,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
if (verbose) {
ubi_warn("bad EC header CRC at PEB %d, calculated "
"%#08x, read %#08x", pnum, crc, hdr_crc);
- ubi_dbg_dump_ec_hdr(ec_hdr);
+ ubi_dump_ec_hdr(ec_hdr);
}
dbg_bld("bad EC header CRC at PEB %d, calculated "
"%#08x, read %#08x", pnum, crc, hdr_crc);
@@ -874,7 +865,7 @@ int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum,
crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
ec_hdr->hdr_crc = cpu_to_be32(crc);
- err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr);
+ err = self_check_ec_hdr(ubi, pnum, ec_hdr);
if (err)
return err;
@@ -905,40 +896,40 @@ static int validate_vid_hdr(const struct ubi_device *ubi,
int usable_leb_size = ubi->leb_size - data_pad;
if (copy_flag != 0 && copy_flag != 1) {
- dbg_err("bad copy_flag");
+ ubi_err("bad copy_flag");
goto bad;
}
if (vol_id < 0 || lnum < 0 || data_size < 0 || used_ebs < 0 ||
data_pad < 0) {
- dbg_err("negative values");
+ ubi_err("negative values");
goto bad;
}
if (vol_id >= UBI_MAX_VOLUMES && vol_id < UBI_INTERNAL_VOL_START) {
- dbg_err("bad vol_id");
+ ubi_err("bad vol_id");
goto bad;
}
if (vol_id < UBI_INTERNAL_VOL_START && compat != 0) {
- dbg_err("bad compat");
+ ubi_err("bad compat");
goto bad;
}
if (vol_id >= UBI_INTERNAL_VOL_START && compat != UBI_COMPAT_DELETE &&
compat != UBI_COMPAT_RO && compat != UBI_COMPAT_PRESERVE &&
compat != UBI_COMPAT_REJECT) {
- dbg_err("bad compat");
+ ubi_err("bad compat");
goto bad;
}
if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) {
- dbg_err("bad vol_type");
+ ubi_err("bad vol_type");
goto bad;
}
if (data_pad >= ubi->leb_size / 2) {
- dbg_err("bad data_pad");
+ ubi_err("bad data_pad");
goto bad;
}
@@ -950,45 +941,45 @@ static int validate_vid_hdr(const struct ubi_device *ubi,
* mapped logical eraseblocks.
*/
if (used_ebs == 0) {
- dbg_err("zero used_ebs");
+ ubi_err("zero used_ebs");
goto bad;
}
if (data_size == 0) {
- dbg_err("zero data_size");
+ ubi_err("zero data_size");
goto bad;
}
if (lnum < used_ebs - 1) {
if (data_size != usable_leb_size) {
- dbg_err("bad data_size");
+ ubi_err("bad data_size");
goto bad;
}
} else if (lnum == used_ebs - 1) {
if (data_size == 0) {
- dbg_err("bad data_size at last LEB");
+ ubi_err("bad data_size at last LEB");
goto bad;
}
} else {
- dbg_err("too high lnum");
+ ubi_err("too high lnum");
goto bad;
}
} else {
if (copy_flag == 0) {
if (data_crc != 0) {
- dbg_err("non-zero data CRC");
+ ubi_err("non-zero data CRC");
goto bad;
}
if (data_size != 0) {
- dbg_err("non-zero data_size");
+ ubi_err("non-zero data_size");
goto bad;
}
} else {
if (data_size == 0) {
- dbg_err("zero data_size of copy");
+ ubi_err("zero data_size of copy");
goto bad;
}
}
if (used_ebs != 0) {
- dbg_err("bad used_ebs");
+ ubi_err("bad used_ebs");
goto bad;
}
}
@@ -997,8 +988,8 @@ static int validate_vid_hdr(const struct ubi_device *ubi,
bad:
ubi_err("bad VID header");
- ubi_dbg_dump_vid_hdr(vid_hdr);
- ubi_dbg_dump_stack();
+ ubi_dump_vid_hdr(vid_hdr);
+ dump_stack();
return 1;
}
@@ -1054,7 +1045,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
if (verbose) {
ubi_warn("bad magic number at PEB %d: %08x instead of "
"%08x", pnum, magic, UBI_VID_HDR_MAGIC);
- ubi_dbg_dump_vid_hdr(vid_hdr);
+ ubi_dump_vid_hdr(vid_hdr);
}
dbg_bld("bad magic number at PEB %d: %08x instead of "
"%08x", pnum, magic, UBI_VID_HDR_MAGIC);
@@ -1068,7 +1059,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
if (verbose) {
ubi_warn("bad CRC at PEB %d, calculated %#08x, "
"read %#08x", pnum, crc, hdr_crc);
- ubi_dbg_dump_vid_hdr(vid_hdr);
+ ubi_dump_vid_hdr(vid_hdr);
}
dbg_bld("bad CRC at PEB %d, calculated %#08x, "
"read %#08x", pnum, crc, hdr_crc);
@@ -1112,7 +1103,7 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
dbg_io("write VID header to PEB %d", pnum);
ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
- err = paranoid_check_peb_ec_hdr(ubi, pnum);
+ err = self_check_peb_ec_hdr(ubi, pnum);
if (err)
return err;
@@ -1121,7 +1112,7 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
vid_hdr->hdr_crc = cpu_to_be32(crc);
- err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr);
+ err = self_check_vid_hdr(ubi, pnum, vid_hdr);
if (err)
return err;
@@ -1131,17 +1122,15 @@ int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum,
return err;
}
-#ifdef CONFIG_MTD_UBI_DEBUG
-
/**
- * paranoid_check_not_bad - ensure that a physical eraseblock is not bad.
+ * self_check_not_bad - ensure that a physical eraseblock is not bad.
* @ubi: UBI device description object
* @pnum: physical eraseblock number to check
*
* This function returns zero if the physical eraseblock is good, %-EINVAL if
* it is bad and a negative error code if an error occurred.
*/
-static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum)
+static int self_check_not_bad(const struct ubi_device *ubi, int pnum)
{
int err;
@@ -1152,13 +1141,13 @@ static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum)
if (!err)
return err;
- ubi_err("paranoid check failed for PEB %d", pnum);
- ubi_dbg_dump_stack();
+ ubi_err("self-check failed for PEB %d", pnum);
+ dump_stack();
return err > 0 ? -EINVAL : err;
}
/**
- * paranoid_check_ec_hdr - check if an erase counter header is all right.
+ * self_check_ec_hdr - check if an erase counter header is all right.
* @ubi: UBI device description object
* @pnum: physical eraseblock number the erase counter header belongs to
* @ec_hdr: the erase counter header to check
@@ -1166,8 +1155,8 @@ static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum)
* This function returns zero if the erase counter header contains valid
* values, and %-EINVAL if not.
*/
-static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
- const struct ubi_ec_hdr *ec_hdr)
+static int self_check_ec_hdr(const struct ubi_device *ubi, int pnum,
+ const struct ubi_ec_hdr *ec_hdr)
{
int err;
uint32_t magic;
@@ -1184,27 +1173,27 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
err = validate_ec_hdr(ubi, ec_hdr);
if (err) {
- ubi_err("paranoid check failed for PEB %d", pnum);
+ ubi_err("self-check failed for PEB %d", pnum);
goto fail;
}
return 0;
fail:
- ubi_dbg_dump_ec_hdr(ec_hdr);
- ubi_dbg_dump_stack();
+ ubi_dump_ec_hdr(ec_hdr);
+ dump_stack();
return -EINVAL;
}
/**
- * paranoid_check_peb_ec_hdr - check erase counter header.
+ * self_check_peb_ec_hdr - check erase counter header.
* @ubi: UBI device description object
* @pnum: the physical eraseblock number to check
*
* This function returns zero if the erase counter header is all right and and
* a negative error code if not or if an error occurred.
*/
-static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
+static int self_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
{
int err;
uint32_t crc, hdr_crc;
@@ -1225,14 +1214,14 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
hdr_crc = be32_to_cpu(ec_hdr->hdr_crc);
if (hdr_crc != crc) {
ubi_err("bad CRC, calculated %#08x, read %#08x", crc, hdr_crc);
- ubi_err("paranoid check failed for PEB %d", pnum);
- ubi_dbg_dump_ec_hdr(ec_hdr);
- ubi_dbg_dump_stack();
+ ubi_err("self-check failed for PEB %d", pnum);
+ ubi_dump_ec_hdr(ec_hdr);
+ dump_stack();
err = -EINVAL;
goto exit;
}
- err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr);
+ err = self_check_ec_hdr(ubi, pnum, ec_hdr);
exit:
kfree(ec_hdr);
@@ -1240,7 +1229,7 @@ exit:
}
/**
- * paranoid_check_vid_hdr - check that a volume identifier header is all right.
+ * self_check_vid_hdr - check that a volume identifier header is all right.
* @ubi: UBI device description object
* @pnum: physical eraseblock number the volume identifier header belongs to
* @vid_hdr: the volume identifier header to check
@@ -1248,8 +1237,8 @@ exit:
* This function returns zero if the volume identifier header is all right, and
* %-EINVAL if not.
*/
-static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
- const struct ubi_vid_hdr *vid_hdr)
+static int self_check_vid_hdr(const struct ubi_device *ubi, int pnum,
+ const struct ubi_vid_hdr *vid_hdr)
{
int err;
uint32_t magic;
@@ -1266,29 +1255,29 @@ static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
err = validate_vid_hdr(ubi, vid_hdr);
if (err) {
- ubi_err("paranoid check failed for PEB %d", pnum);
+ ubi_err("self-check failed for PEB %d", pnum);
goto fail;
}
return err;
fail:
- ubi_err("paranoid check failed for PEB %d", pnum);
- ubi_dbg_dump_vid_hdr(vid_hdr);
- ubi_dbg_dump_stack();
+ ubi_err("self-check failed for PEB %d", pnum);
+ ubi_dump_vid_hdr(vid_hdr);
+ dump_stack();
return -EINVAL;
}
/**
- * paranoid_check_peb_vid_hdr - check volume identifier header.
+ * self_check_peb_vid_hdr - check volume identifier header.
* @ubi: UBI device description object
* @pnum: the physical eraseblock number to check
*
* This function returns zero if the volume identifier header is all right,
* and a negative error code if not or if an error occurred.
*/
-static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
+static int self_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
{
int err;
uint32_t crc, hdr_crc;
@@ -1313,14 +1302,14 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
if (hdr_crc != crc) {
ubi_err("bad VID header CRC at PEB %d, calculated %#08x, "
"read %#08x", pnum, crc, hdr_crc);
- ubi_err("paranoid check failed for PEB %d", pnum);
- ubi_dbg_dump_vid_hdr(vid_hdr);
- ubi_dbg_dump_stack();
+ ubi_err("self-check failed for PEB %d", pnum);
+ ubi_dump_vid_hdr(vid_hdr);
+ dump_stack();
err = -EINVAL;
goto exit;
}
- err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr);
+ err = self_check_vid_hdr(ubi, pnum, vid_hdr);
exit:
ubi_free_vid_hdr(ubi, vid_hdr);
@@ -1328,7 +1317,7 @@ exit:
}
/**
- * ubi_dbg_check_write - make sure write succeeded.
+ * self_check_write - make sure write succeeded.
* @ubi: UBI device description object
* @buf: buffer with data which were written
* @pnum: physical eraseblock number the data were written to
@@ -1339,8 +1328,8 @@ exit:
* the original data buffer - the data have to match. Returns zero if the data
* match and a negative error code if not or in case of failure.
*/
-int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
- int offset, int len)
+static int self_check_write(struct ubi_device *ubi, const void *buf, int pnum,
+ int offset, int len)
{
int err, i;
size_t read;
@@ -1368,7 +1357,7 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
if (c == c1)
continue;
- ubi_err("paranoid check failed for PEB %d:%d, len %d",
+ ubi_err("self-check failed for PEB %d:%d, len %d",
pnum, offset, len);
ubi_msg("data differ at position %d", i);
dump_len = max_t(int, 128, len - i);
@@ -1380,7 +1369,7 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum,
i, i + dump_len);
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1,
buf1 + i, dump_len, 1);
- ubi_dbg_dump_stack();
+ dump_stack();
err = -EINVAL;
goto out_free;
}
@@ -1394,7 +1383,7 @@ out_free:
}
/**
- * ubi_dbg_check_all_ff - check that a region of flash is empty.
+ * ubi_self_check_all_ff - check that a region of flash is empty.
* @ubi: UBI device description object
* @pnum: the physical eraseblock number to check
* @offset: the starting offset within the physical eraseblock to check
@@ -1404,7 +1393,7 @@ out_free:
* @offset of the physical eraseblock @pnum, and a negative error code if not
* or if an error occurred.
*/
-int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
+int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
{
size_t read;
int err;
@@ -1438,14 +1427,12 @@ int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
return 0;
fail:
- ubi_err("paranoid check failed for PEB %d", pnum);
+ ubi_err("self-check failed for PEB %d", pnum);
ubi_msg("hex dump of the %d-%d region", offset, offset + len);
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
err = -EINVAL;
error:
- ubi_dbg_dump_stack();
+ dump_stack();
vfree(buf);
return err;
}
-
-#endif /* CONFIG_MTD_UBI_DEBUG */
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index 9fdb35367fe0..3aac1acceeb4 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -221,7 +221,7 @@ out_free:
kfree(desc);
out_put_ubi:
ubi_put_device(ubi);
- dbg_err("cannot open device %d, volume %d, error %d",
+ ubi_err("cannot open device %d, volume %d, error %d",
ubi_num, vol_id, err);
return ERR_PTR(err);
}
@@ -426,11 +426,9 @@ EXPORT_SYMBOL_GPL(ubi_leb_read);
* @buf: data to write
* @offset: offset within the logical eraseblock where to write
* @len: how many bytes to write
- * @dtype: expected data type
*
* This function writes @len bytes of data from @buf to offset @offset of
- * logical eraseblock @lnum. The @dtype argument describes expected lifetime of
- * the data.
+ * logical eraseblock @lnum.
*
* This function takes care of physical eraseblock write failures. If write to
* the physical eraseblock write operation fails, the logical eraseblock is
@@ -447,7 +445,7 @@ EXPORT_SYMBOL_GPL(ubi_leb_read);
* returns immediately with %-EBADF code.
*/
int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
- int offset, int len, int dtype)
+ int offset, int len)
{
struct ubi_volume *vol = desc->vol;
struct ubi_device *ubi = vol->ubi;
@@ -466,17 +464,13 @@ int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
offset & (ubi->min_io_size - 1) || len & (ubi->min_io_size - 1))
return -EINVAL;
- if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
- dtype != UBI_UNKNOWN)
- return -EINVAL;
-
if (vol->upd_marker)
return -EBADF;
if (len == 0)
return 0;
- return ubi_eba_write_leb(ubi, vol, lnum, buf, offset, len, dtype);
+ return ubi_eba_write_leb(ubi, vol, lnum, buf, offset, len);
}
EXPORT_SYMBOL_GPL(ubi_leb_write);
@@ -486,7 +480,6 @@ EXPORT_SYMBOL_GPL(ubi_leb_write);
* @lnum: logical eraseblock number to change
* @buf: data to write
* @len: how many bytes to write
- * @dtype: expected data type
*
* This function changes the contents of a logical eraseblock atomically. @buf
* has to contain new logical eraseblock data, and @len - the length of the
@@ -497,7 +490,7 @@ EXPORT_SYMBOL_GPL(ubi_leb_write);
* code in case of failure.
*/
int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
- int len, int dtype)
+ int len)
{
struct ubi_volume *vol = desc->vol;
struct ubi_device *ubi = vol->ubi;
@@ -515,17 +508,13 @@ int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
len > vol->usable_leb_size || len & (ubi->min_io_size - 1))
return -EINVAL;
- if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
- dtype != UBI_UNKNOWN)
- return -EINVAL;
-
if (vol->upd_marker)
return -EBADF;
if (len == 0)
return 0;
- return ubi_eba_atomic_leb_change(ubi, vol, lnum, buf, len, dtype);
+ return ubi_eba_atomic_leb_change(ubi, vol, lnum, buf, len);
}
EXPORT_SYMBOL_GPL(ubi_leb_change);
@@ -562,7 +551,7 @@ int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum)
if (err)
return err;
- return ubi_wl_flush(ubi);
+ return ubi_wl_flush(ubi, vol->vol_id, lnum);
}
EXPORT_SYMBOL_GPL(ubi_leb_erase);
@@ -626,7 +615,6 @@ EXPORT_SYMBOL_GPL(ubi_leb_unmap);
* ubi_leb_map - map logical eraseblock to a physical eraseblock.
* @desc: volume descriptor
* @lnum: logical eraseblock number
- * @dtype: expected data type
*
* This function maps an un-mapped logical eraseblock @lnum to a physical
* eraseblock. This means, that after a successful invocation of this
@@ -639,7 +627,7 @@ EXPORT_SYMBOL_GPL(ubi_leb_unmap);
* eraseblock is already mapped, and other negative error codes in case of
* other failures.
*/
-int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype)
+int ubi_leb_map(struct ubi_volume_desc *desc, int lnum)
{
struct ubi_volume *vol = desc->vol;
struct ubi_device *ubi = vol->ubi;
@@ -652,17 +640,13 @@ int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype)
if (lnum < 0 || lnum >= vol->reserved_pebs)
return -EINVAL;
- if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM &&
- dtype != UBI_UNKNOWN)
- return -EINVAL;
-
if (vol->upd_marker)
return -EBADF;
if (vol->eba_tbl[lnum] >= 0)
return -EBADMSG;
- return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype);
+ return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0);
}
EXPORT_SYMBOL_GPL(ubi_leb_map);
@@ -720,6 +704,33 @@ int ubi_sync(int ubi_num)
}
EXPORT_SYMBOL_GPL(ubi_sync);
+/**
+ * ubi_flush - flush UBI work queue.
+ * @ubi_num: UBI device to flush work queue
+ * @vol_id: volume id to flush for
+ * @lnum: logical eraseblock number to flush for
+ *
+ * This function executes all pending works for a particular volume id / logical
+ * eraseblock number pair. If either value is set to %UBI_ALL, then it acts as
+ * a wildcard for all of the corresponding volume numbers or logical
+ * eraseblock numbers. It returns zero in case of success and a negative error
+ * code in case of failure.
+ */
+int ubi_flush(int ubi_num, int vol_id, int lnum)
+{
+ struct ubi_device *ubi;
+ int err = 0;
+
+ ubi = ubi_get_device(ubi_num);
+ if (!ubi)
+ return -ENODEV;
+
+ err = ubi_wl_flush(ubi, vol_id, lnum);
+ ubi_put_device(ubi);
+ return err;
+}
+EXPORT_SYMBOL_GPL(ubi_flush);
+
BLOCKING_NOTIFIER_HEAD(ubi_notifiers);
/**
diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h
deleted file mode 100644
index d48aef15ab5d..000000000000
--- a/drivers/mtd/ubi/scan.h
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (c) International Business Machines Corp., 2006
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- * the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Artem Bityutskiy (Битюцкий Артём)
- */
-
-#ifndef __UBI_SCAN_H__
-#define __UBI_SCAN_H__
-
-/* The erase counter value for this physical eraseblock is unknown */
-#define UBI_SCAN_UNKNOWN_EC (-1)
-
-/**
- * struct ubi_scan_leb - scanning information about a physical eraseblock.
- * @ec: erase counter (%UBI_SCAN_UNKNOWN_EC if it is unknown)
- * @pnum: physical eraseblock number
- * @lnum: logical eraseblock number
- * @scrub: if this physical eraseblock needs scrubbing
- * @copy_flag: this LEB is a copy (@copy_flag is set in VID header of this LEB)
- * @sqnum: sequence number
- * @u: unions RB-tree or @list links
- * @u.rb: link in the per-volume RB-tree of &struct ubi_scan_leb objects
- * @u.list: link in one of the eraseblock lists
- *
- * One object of this type is allocated for each physical eraseblock during
- * scanning.
- */
-struct ubi_scan_leb {
- int ec;
- int pnum;
- int lnum;
- unsigned int scrub:1;
- unsigned int copy_flag:1;
- unsigned long long sqnum;
- union {
- struct rb_node rb;
- struct list_head list;
- } u;
-};
-
-/**
- * struct ubi_scan_volume - scanning information about a volume.
- * @vol_id: volume ID
- * @highest_lnum: highest logical eraseblock number in this volume
- * @leb_count: number of logical eraseblocks in this volume
- * @vol_type: volume type
- * @used_ebs: number of used logical eraseblocks in this volume (only for
- * static volumes)
- * @last_data_size: amount of data in the last logical eraseblock of this
- * volume (always equivalent to the usable logical eraseblock
- * size in case of dynamic volumes)
- * @data_pad: how many bytes at the end of logical eraseblocks of this volume
- * are not used (due to volume alignment)
- * @compat: compatibility flags of this volume
- * @rb: link in the volume RB-tree
- * @root: root of the RB-tree containing all the eraseblock belonging to this
- * volume (&struct ubi_scan_leb objects)
- *
- * One object of this type is allocated for each volume during scanning.
- */
-struct ubi_scan_volume {
- int vol_id;
- int highest_lnum;
- int leb_count;
- int vol_type;
- int used_ebs;
- int last_data_size;
- int data_pad;
- int compat;
- struct rb_node rb;
- struct rb_root root;
-};
-
-/**
- * struct ubi_scan_info - UBI scanning information.
- * @volumes: root of the volume RB-tree
- * @corr: list of corrupted physical eraseblocks
- * @free: list of free physical eraseblocks
- * @erase: list of physical eraseblocks which have to be erased
- * @alien: list of physical eraseblocks which should not be used by UBI (e.g.,
- * those belonging to "preserve"-compatible internal volumes)
- * @corr_peb_count: count of PEBs in the @corr list
- * @empty_peb_count: count of PEBs which are presumably empty (contain only
- * 0xFF bytes)
- * @alien_peb_count: count of PEBs in the @alien list
- * @bad_peb_count: count of bad physical eraseblocks
- * @maybe_bad_peb_count: count of bad physical eraseblocks which are not marked
- * as bad yet, but which look like bad
- * @vols_found: number of volumes found during scanning
- * @highest_vol_id: highest volume ID
- * @is_empty: flag indicating whether the MTD device is empty or not
- * @min_ec: lowest erase counter value
- * @max_ec: highest erase counter value
- * @max_sqnum: highest sequence number value
- * @mean_ec: mean erase counter value
- * @ec_sum: a temporary variable used when calculating @mean_ec
- * @ec_count: a temporary variable used when calculating @mean_ec
- * @scan_leb_slab: slab cache for &struct ubi_scan_leb objects
- *
- * This data structure contains the result of scanning and may be used by other
- * UBI sub-systems to build final UBI data structures, further error-recovery
- * and so on.
- */
-struct ubi_scan_info {
- struct rb_root volumes;
- struct list_head corr;
- struct list_head free;
- struct list_head erase;
- struct list_head alien;
- int corr_peb_count;
- int empty_peb_count;
- int alien_peb_count;
- int bad_peb_count;
- int maybe_bad_peb_count;
- int vols_found;
- int highest_vol_id;
- int is_empty;
- int min_ec;
- int max_ec;
- unsigned long long max_sqnum;
- int mean_ec;
- uint64_t ec_sum;
- int ec_count;
- struct kmem_cache *scan_leb_slab;
-};
-
-struct ubi_device;
-struct ubi_vid_hdr;
-
-/*
- * ubi_scan_move_to_list - move a PEB from the volume tree to a list.
- *
- * @sv: volume scanning information
- * @seb: scanning eraseblock information
- * @list: the list to move to
- */
-static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv,
- struct ubi_scan_leb *seb,
- struct list_head *list)
-{
- rb_erase(&seb->u.rb, &sv->root);
- list_add_tail(&seb->u.list, list);
-}
-
-int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
- int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
- int bitflips);
-struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si,
- int vol_id);
-struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv,
- int lnum);
-void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv);
-struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi,
- struct ubi_scan_info *si);
-int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si,
- int pnum, int ec);
-struct ubi_scan_info *ubi_scan(struct ubi_device *ubi);
-void ubi_scan_destroy_si(struct ubi_scan_info *si);
-
-#endif /* !__UBI_SCAN_H__ */
diff --git a/drivers/mtd/ubi/ubi-media.h b/drivers/mtd/ubi/ubi-media.h
index 6fb8ec2174a5..468ffbc0eabd 100644
--- a/drivers/mtd/ubi/ubi-media.h
+++ b/drivers/mtd/ubi/ubi-media.h
@@ -149,10 +149,10 @@ enum {
* The @image_seq field is used to validate a UBI image that has been prepared
* for a UBI device. The @image_seq value can be any value, but it must be the
* same on all eraseblocks. UBI will ensure that all new erase counter headers
- * also contain this value, and will check the value when scanning at start-up.
+ * also contain this value, and will check the value when attaching the flash.
* One way to make use of @image_seq is to increase its value by one every time
* an image is flashed over an existing image, then, if the flashing does not
- * complete, UBI will detect the error when scanning.
+ * complete, UBI will detect the error when attaching the media.
*/
struct ubi_ec_hdr {
__be32 magic;
@@ -298,8 +298,8 @@ struct ubi_vid_hdr {
#define UBI_INT_VOL_COUNT 1
/*
- * Starting ID of internal volumes. There is reserved room for 4096 internal
- * volumes.
+ * Starting ID of internal volumes: 0x7fffefff.
+ * There is reserved room for 4096 internal volumes.
*/
#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096)
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index b162790790a9..a1a81c9ea8ce 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -43,7 +43,6 @@
#include <asm/pgtable.h>
#include "ubi-media.h"
-#include "scan.h"
/* Maximum number of supported UBI devices */
#define UBI_MAX_DEVICES 32
@@ -66,7 +65,10 @@
/* Background thread name pattern */
#define UBI_BGT_NAME_PATTERN "ubi_bgt%dd"
-/* This marker in the EBA table means that the LEB is um-mapped */
+/*
+ * This marker in the EBA table means that the LEB is um-mapped.
+ * NOTE! It has to have the same value as %UBI_ALL.
+ */
#define UBI_LEB_UNMAPPED -1
/*
@@ -82,6 +84,9 @@
*/
#define UBI_PROT_QUEUE_LEN 10
+/* The volume ID/LEB number/erase counter is unknown */
+#define UBI_UNKNOWN -1
+
/*
* Error codes returned by the I/O sub-system.
*
@@ -222,8 +227,6 @@ struct ubi_volume_desc;
* @upd_ebs: how many eraseblocks are expected to be updated
* @ch_lnum: LEB number which is being changing by the atomic LEB change
* operation
- * @ch_dtype: data persistency type which is being changing by the atomic LEB
- * change operation
* @upd_bytes: how many bytes are expected to be received for volume update or
* atomic LEB change
* @upd_received: how many bytes were already received for volume update or
@@ -270,7 +273,6 @@ struct ubi_volume {
int upd_ebs;
int ch_lnum;
- int ch_dtype;
long long upd_bytes;
long long upd_received;
void *upd_buf;
@@ -477,6 +479,124 @@ struct ubi_device {
struct ubi_debug_info *dbg;
};
+/**
+ * struct ubi_ainf_peb - attach information about a physical eraseblock.
+ * @ec: erase counter (%UBI_UNKNOWN if it is unknown)
+ * @pnum: physical eraseblock number
+ * @vol_id: ID of the volume this LEB belongs to
+ * @lnum: logical eraseblock number
+ * @scrub: if this physical eraseblock needs scrubbing
+ * @copy_flag: this LEB is a copy (@copy_flag is set in VID header of this LEB)
+ * @sqnum: sequence number
+ * @u: unions RB-tree or @list links
+ * @u.rb: link in the per-volume RB-tree of &struct ubi_ainf_peb objects
+ * @u.list: link in one of the eraseblock lists
+ *
+ * One object of this type is allocated for each physical eraseblock when
+ * attaching an MTD device. Note, if this PEB does not belong to any LEB /
+ * volume, the @vol_id and @lnum fields are initialized to %UBI_UNKNOWN.
+ */
+struct ubi_ainf_peb {
+ int ec;
+ int pnum;
+ int vol_id;
+ int lnum;
+ unsigned int scrub:1;
+ unsigned int copy_flag:1;
+ unsigned long long sqnum;
+ union {
+ struct rb_node rb;
+ struct list_head list;
+ } u;
+};
+
+/**
+ * struct ubi_ainf_volume - attaching information about a volume.
+ * @vol_id: volume ID
+ * @highest_lnum: highest logical eraseblock number in this volume
+ * @leb_count: number of logical eraseblocks in this volume
+ * @vol_type: volume type
+ * @used_ebs: number of used logical eraseblocks in this volume (only for
+ * static volumes)
+ * @last_data_size: amount of data in the last logical eraseblock of this
+ * volume (always equivalent to the usable logical eraseblock
+ * size in case of dynamic volumes)
+ * @data_pad: how many bytes at the end of logical eraseblocks of this volume
+ * are not used (due to volume alignment)
+ * @compat: compatibility flags of this volume
+ * @rb: link in the volume RB-tree
+ * @root: root of the RB-tree containing all the eraseblock belonging to this
+ * volume (&struct ubi_ainf_peb objects)
+ *
+ * One object of this type is allocated for each volume when attaching an MTD
+ * device.
+ */
+struct ubi_ainf_volume {
+ int vol_id;
+ int highest_lnum;
+ int leb_count;
+ int vol_type;
+ int used_ebs;
+ int last_data_size;
+ int data_pad;
+ int compat;
+ struct rb_node rb;
+ struct rb_root root;
+};
+
+/**
+ * struct ubi_attach_info - MTD device attaching information.
+ * @volumes: root of the volume RB-tree
+ * @corr: list of corrupted physical eraseblocks
+ * @free: list of free physical eraseblocks
+ * @erase: list of physical eraseblocks which have to be erased
+ * @alien: list of physical eraseblocks which should not be used by UBI (e.g.,
+ * those belonging to "preserve"-compatible internal volumes)
+ * @corr_peb_count: count of PEBs in the @corr list
+ * @empty_peb_count: count of PEBs which are presumably empty (contain only
+ * 0xFF bytes)
+ * @alien_peb_count: count of PEBs in the @alien list
+ * @bad_peb_count: count of bad physical eraseblocks
+ * @maybe_bad_peb_count: count of bad physical eraseblocks which are not marked
+ * as bad yet, but which look like bad
+ * @vols_found: number of volumes found
+ * @highest_vol_id: highest volume ID
+ * @is_empty: flag indicating whether the MTD device is empty or not
+ * @min_ec: lowest erase counter value
+ * @max_ec: highest erase counter value
+ * @max_sqnum: highest sequence number value
+ * @mean_ec: mean erase counter value
+ * @ec_sum: a temporary variable used when calculating @mean_ec
+ * @ec_count: a temporary variable used when calculating @mean_ec
+ * @aeb_slab_cache: slab cache for &struct ubi_ainf_peb objects
+ *
+ * This data structure contains the result of attaching an MTD device and may
+ * be used by other UBI sub-systems to build final UBI data structures, further
+ * error-recovery and so on.
+ */
+struct ubi_attach_info {
+ struct rb_root volumes;
+ struct list_head corr;
+ struct list_head free;
+ struct list_head erase;
+ struct list_head alien;
+ int corr_peb_count;
+ int empty_peb_count;
+ int alien_peb_count;
+ int bad_peb_count;
+ int maybe_bad_peb_count;
+ int vols_found;
+ int highest_vol_id;
+ int is_empty;
+ int min_ec;
+ int max_ec;
+ unsigned long long max_sqnum;
+ int mean_ec;
+ uint64_t ec_sum;
+ int ec_count;
+ struct kmem_cache *aeb_slab_cache;
+};
+
#include "debug.h"
extern struct kmem_cache *ubi_wl_entry_slab;
@@ -487,12 +607,23 @@ extern struct class *ubi_class;
extern struct mutex ubi_devices_mutex;
extern struct blocking_notifier_head ubi_notifiers;
+/* scan.c */
+int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum,
+ int ec, const struct ubi_vid_hdr *vid_hdr, int bitflips);
+struct ubi_ainf_volume *ubi_find_av(const struct ubi_attach_info *ai,
+ int vol_id);
+void ubi_remove_av(struct ubi_attach_info *ai, struct ubi_ainf_volume *av);
+struct ubi_ainf_peb *ubi_early_get_peb(struct ubi_device *ubi,
+ struct ubi_attach_info *ai);
+int ubi_attach(struct ubi_device *ubi);
+void ubi_destroy_ai(struct ubi_attach_info *ai);
+
/* vtbl.c */
int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
struct ubi_vtbl_record *vtbl_rec);
int ubi_vtbl_rename_volumes(struct ubi_device *ubi,
struct list_head *rename_list);
-int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si);
+int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_attach_info *ai);
/* vmt.c */
int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req);
@@ -525,22 +656,22 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
void *buf, int offset, int len, int check);
int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
- const void *buf, int offset, int len, int dtype);
+ const void *buf, int offset, int len);
int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
- int lnum, const void *buf, int len, int dtype,
- int used_ebs);
+ int lnum, const void *buf, int len, int used_ebs);
int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
- int lnum, const void *buf, int len, int dtype);
+ int lnum, const void *buf, int len);
int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
struct ubi_vid_hdr *vid_hdr);
-int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si);
+int ubi_eba_init(struct ubi_device *ubi, struct ubi_attach_info *ai);
/* wl.c */
-int ubi_wl_get_peb(struct ubi_device *ubi, int dtype);
-int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture);
-int ubi_wl_flush(struct ubi_device *ubi);
+int ubi_wl_get_peb(struct ubi_device *ubi);
+int ubi_wl_put_peb(struct ubi_device *ubi, int vol_id, int lnum,
+ int pnum, int torture);
+int ubi_wl_flush(struct ubi_device *ubi, int vol_id, int lnum);
int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum);
-int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si);
+int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai);
void ubi_wl_close(struct ubi_device *ubi);
int ubi_thread(void *u);
@@ -573,6 +704,7 @@ int ubi_volume_notify(struct ubi_device *ubi, struct ubi_volume *vol,
int ubi_notify_all(struct ubi_device *ubi, int ntype,
struct notifier_block *nb);
int ubi_enumerate_volumes(struct notifier_block *nb);
+void ubi_free_internal_volumes(struct ubi_device *ubi);
/* kapi.c */
void ubi_do_get_device_info(struct ubi_device *ubi, struct ubi_device_info *di);
@@ -593,6 +725,21 @@ void ubi_do_get_volume_info(struct ubi_device *ubi, struct ubi_volume *vol,
rb = rb_next(rb), \
pos = (rb ? container_of(rb, typeof(*pos), member) : NULL))
+/*
+ * ubi_move_aeb_to_list - move a PEB from the volume tree to a list.
+ *
+ * @av: volume attaching information
+ * @aeb: attaching eraseblock information
+ * @list: the list to move to
+ */
+static inline void ubi_move_aeb_to_list(struct ubi_ainf_volume *av,
+ struct ubi_ainf_peb *aeb,
+ struct list_head *list)
+{
+ rb_erase(&aeb->u.rb, &av->root);
+ list_add_tail(&aeb->u.list, list);
+}
+
/**
* ubi_zalloc_vid_hdr - allocate a volume identifier header object.
* @ubi: UBI device description object
@@ -667,7 +814,7 @@ static inline void ubi_ro_mode(struct ubi_device *ubi)
if (!ubi->ro_mode) {
ubi->ro_mode = 1;
ubi_warn("switch to read-only mode");
- ubi_dbg_dump_stack();
+ dump_stack();
}
}
diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c
index 425bf5a3edd4..9f2ebd8750e7 100644
--- a/drivers/mtd/ubi/upd.c
+++ b/drivers/mtd/ubi/upd.c
@@ -147,7 +147,7 @@ int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol,
}
if (bytes == 0) {
- err = ubi_wl_flush(ubi);
+ err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
if (err)
return err;
@@ -186,14 +186,12 @@ int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol,
dbg_gen("start changing LEB %d:%d, %u bytes",
vol->vol_id, req->lnum, req->bytes);
if (req->bytes == 0)
- return ubi_eba_atomic_leb_change(ubi, vol, req->lnum, NULL, 0,
- req->dtype);
+ return ubi_eba_atomic_leb_change(ubi, vol, req->lnum, NULL, 0);
vol->upd_bytes = req->bytes;
vol->upd_received = 0;
vol->changing_leb = 1;
vol->ch_lnum = req->lnum;
- vol->ch_dtype = req->dtype;
vol->upd_buf = vmalloc(req->bytes);
if (!vol->upd_buf)
@@ -246,8 +244,7 @@ static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
return 0;
}
- err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, len,
- UBI_UNKNOWN);
+ err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, len);
} else {
/*
* When writing static volume, and this is the last logical
@@ -259,8 +256,7 @@ static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
* contain zeros, not random trash.
*/
memset(buf + len, 0, vol->usable_leb_size - len);
- err = ubi_eba_write_leb_st(ubi, vol, lnum, buf, len,
- UBI_UNKNOWN, used_ebs);
+ err = ubi_eba_write_leb_st(ubi, vol, lnum, buf, len, used_ebs);
}
return err;
@@ -365,7 +361,7 @@ int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol,
ubi_assert(vol->upd_received <= vol->upd_bytes);
if (vol->upd_received == vol->upd_bytes) {
- err = ubi_wl_flush(ubi);
+ err = ubi_wl_flush(ubi, UBI_ALL, UBI_ALL);
if (err)
return err;
/* The update is finished, clear the update marker */
@@ -421,7 +417,7 @@ int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol,
len - vol->upd_bytes);
len = ubi_calc_data_len(ubi, vol->upd_buf, len);
err = ubi_eba_atomic_leb_change(ubi, vol, vol->ch_lnum,
- vol->upd_buf, len, UBI_UNKNOWN);
+ vol->upd_buf, len);
if (err)
return err;
}
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index 863835f4aefe..0669cff8ac3c 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -29,11 +29,7 @@
#include <linux/export.h>
#include "ubi.h"
-#ifdef CONFIG_MTD_UBI_DEBUG
-static int paranoid_check_volumes(struct ubi_device *ubi);
-#else
-#define paranoid_check_volumes(ubi) 0
-#endif
+static int self_check_volumes(struct ubi_device *ubi);
static ssize_t vol_attribute_show(struct device *dev,
struct device_attribute *attr, char *buf);
@@ -227,7 +223,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
}
if (vol_id == UBI_VOL_NUM_AUTO) {
- dbg_err("out of volume IDs");
+ ubi_err("out of volume IDs");
err = -ENFILE;
goto out_unlock;
}
@@ -241,7 +237,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
/* Ensure that this volume does not exist */
err = -EEXIST;
if (ubi->volumes[vol_id]) {
- dbg_err("volume %d already exists", vol_id);
+ ubi_err("volume %d already exists", vol_id);
goto out_unlock;
}
@@ -250,7 +246,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
if (ubi->volumes[i] &&
ubi->volumes[i]->name_len == req->name_len &&
!strcmp(ubi->volumes[i]->name, req->name)) {
- dbg_err("volume \"%s\" exists (ID %d)", req->name, i);
+ ubi_err("volume \"%s\" exists (ID %d)", req->name, i);
goto out_unlock;
}
@@ -261,9 +257,9 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
/* Reserve physical eraseblocks */
if (vol->reserved_pebs > ubi->avail_pebs) {
- dbg_err("not enough PEBs, only %d available", ubi->avail_pebs);
+ ubi_err("not enough PEBs, only %d available", ubi->avail_pebs);
if (ubi->corr_peb_count)
- dbg_err("%d PEBs are corrupted and not used",
+ ubi_err("%d PEBs are corrupted and not used",
ubi->corr_peb_count);
err = -ENOSPC;
goto out_unlock;
@@ -284,7 +280,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
* Finish all pending erases because there may be some LEBs belonging
* to the same volume ID.
*/
- err = ubi_wl_flush(ubi);
+ err = ubi_wl_flush(ubi, vol_id, UBI_ALL);
if (err)
goto out_acc;
@@ -360,8 +356,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
spin_unlock(&ubi->volumes_lock);
ubi_volume_notify(ubi, vol, UBI_VOLUME_ADDED);
- if (paranoid_check_volumes(ubi))
- dbg_err("check failed while creating volume %d", vol_id);
+ self_check_volumes(ubi);
return err;
out_sysfs:
@@ -461,8 +456,8 @@ int ubi_remove_volume(struct ubi_volume_desc *desc, int no_vtbl)
spin_unlock(&ubi->volumes_lock);
ubi_volume_notify(ubi, vol, UBI_VOLUME_REMOVED);
- if (!no_vtbl && paranoid_check_volumes(ubi))
- dbg_err("check failed while removing volume %d", vol_id);
+ if (!no_vtbl)
+ self_check_volumes(ubi);
return err;
@@ -500,7 +495,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
if (vol->vol_type == UBI_STATIC_VOLUME &&
reserved_pebs < vol->used_ebs) {
- dbg_err("too small size %d, %d LEBs contain data",
+ ubi_err("too small size %d, %d LEBs contain data",
reserved_pebs, vol->used_ebs);
return -EINVAL;
}
@@ -529,10 +524,10 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
if (pebs > 0) {
spin_lock(&ubi->volumes_lock);
if (pebs > ubi->avail_pebs) {
- dbg_err("not enough PEBs: requested %d, available %d",
+ ubi_err("not enough PEBs: requested %d, available %d",
pebs, ubi->avail_pebs);
if (ubi->corr_peb_count)
- dbg_err("%d PEBs are corrupted and not used",
+ ubi_err("%d PEBs are corrupted and not used",
ubi->corr_peb_count);
spin_unlock(&ubi->volumes_lock);
err = -ENOSPC;
@@ -588,8 +583,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
}
ubi_volume_notify(ubi, vol, UBI_VOLUME_RESIZED);
- if (paranoid_check_volumes(ubi))
- dbg_err("check failed while re-sizing volume %d", vol_id);
+ self_check_volumes(ubi);
return err;
out_acc:
@@ -638,8 +632,8 @@ int ubi_rename_volumes(struct ubi_device *ubi, struct list_head *rename_list)
}
}
- if (!err && paranoid_check_volumes(ubi))
- ;
+ if (!err)
+ self_check_volumes(ubi);
return err;
}
@@ -686,8 +680,7 @@ int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol)
return err;
}
- if (paranoid_check_volumes(ubi))
- dbg_err("check failed while adding volume %d", vol_id);
+ self_check_volumes(ubi);
return err;
out_cdev:
@@ -712,16 +705,14 @@ void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol)
volume_sysfs_close(vol);
}
-#ifdef CONFIG_MTD_UBI_DEBUG
-
/**
- * paranoid_check_volume - check volume information.
+ * self_check_volume - check volume information.
* @ubi: UBI device description object
* @vol_id: volume ID
*
* Returns zero if volume is all right and a a negative error code if not.
*/
-static int paranoid_check_volume(struct ubi_device *ubi, int vol_id)
+static int self_check_volume(struct ubi_device *ubi, int vol_id)
{
int idx = vol_id2idx(ubi, vol_id);
int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker;
@@ -771,7 +762,7 @@ static int paranoid_check_volume(struct ubi_device *ubi, int vol_id)
}
if (vol->upd_marker && vol->corrupted) {
- dbg_err("update marker and corrupted simultaneously");
+ ubi_err("update marker and corrupted simultaneously");
goto fail;
}
@@ -853,22 +844,22 @@ static int paranoid_check_volume(struct ubi_device *ubi, int vol_id)
return 0;
fail:
- ubi_err("paranoid check failed for volume %d", vol_id);
+ ubi_err("self-check failed for volume %d", vol_id);
if (vol)
- ubi_dbg_dump_vol_info(vol);
- ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
+ ubi_dump_vol_info(vol);
+ ubi_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
dump_stack();
spin_unlock(&ubi->volumes_lock);
return -EINVAL;
}
/**
- * paranoid_check_volumes - check information about all volumes.
+ * self_check_volumes - check information about all volumes.
* @ubi: UBI device description object
*
* Returns zero if volumes are all right and a a negative error code if not.
*/
-static int paranoid_check_volumes(struct ubi_device *ubi)
+static int self_check_volumes(struct ubi_device *ubi)
{
int i, err = 0;
@@ -876,11 +867,10 @@ static int paranoid_check_volumes(struct ubi_device *ubi)
return 0;
for (i = 0; i < ubi->vtbl_slots; i++) {
- err = paranoid_check_volume(ubi, i);
+ err = self_check_volume(ubi, i);
if (err)
break;
}
return err;
}
-#endif
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
index 17cec0c01544..437bc193e170 100644
--- a/drivers/mtd/ubi/vtbl.c
+++ b/drivers/mtd/ubi/vtbl.c
@@ -37,16 +37,15 @@
* LEB 1. This scheme guarantees recoverability from unclean reboots.
*
* In this UBI implementation the on-flash volume table does not contain any
- * information about how many data static volumes contain. This information may
- * be found from the scanning data.
+ * information about how much data static volumes contain.
*
* But it would still be beneficial to store this information in the volume
* table. For example, suppose we have a static volume X, and all its physical
* eraseblocks became bad for some reasons. Suppose we are attaching the
- * corresponding MTD device, the scanning has found no logical eraseblocks
+ * corresponding MTD device, for some reason we find no logical eraseblocks
* corresponding to the volume X. According to the volume table volume X does
* exist. So we don't know whether it is just empty or all its physical
- * eraseblocks went bad. So we cannot alarm the user about this corruption.
+ * eraseblocks went bad. So we cannot alarm the user properly.
*
* The volume table also stores so-called "update marker", which is used for
* volume updates. Before updating the volume, the update marker is set, and
@@ -62,11 +61,7 @@
#include <asm/div64.h>
#include "ubi.h"
-#ifdef CONFIG_MTD_UBI_DEBUG
-static void paranoid_vtbl_check(const struct ubi_device *ubi);
-#else
-#define paranoid_vtbl_check(ubi)
-#endif
+static void self_vtbl_check(const struct ubi_device *ubi);
/* Empty volume table record */
static struct ubi_vtbl_record empty_vtbl_record;
@@ -106,12 +101,12 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
return err;
err = ubi_eba_write_leb(ubi, layout_vol, i, ubi->vtbl, 0,
- ubi->vtbl_size, UBI_LONGTERM);
+ ubi->vtbl_size);
if (err)
return err;
}
- paranoid_vtbl_check(ubi);
+ self_vtbl_check(ubi);
return 0;
}
@@ -158,7 +153,7 @@ int ubi_vtbl_rename_volumes(struct ubi_device *ubi,
return err;
err = ubi_eba_write_leb(ubi, layout_vol, i, ubi->vtbl, 0,
- ubi->vtbl_size, UBI_LONGTERM);
+ ubi->vtbl_size);
if (err)
return err;
}
@@ -197,7 +192,7 @@ static int vtbl_check(const struct ubi_device *ubi,
if (be32_to_cpu(vtbl[i].crc) != crc) {
ubi_err("bad CRC at record %u: %#08x, not %#08x",
i, crc, be32_to_cpu(vtbl[i].crc));
- ubi_dbg_dump_vtbl_record(&vtbl[i], i);
+ ubi_dump_vtbl_record(&vtbl[i], i);
return 1;
}
@@ -229,7 +224,7 @@ static int vtbl_check(const struct ubi_device *ubi,
n = ubi->leb_size % alignment;
if (data_pad != n) {
- dbg_err("bad data_pad, has to be %d", n);
+ ubi_err("bad data_pad, has to be %d", n);
err = 6;
goto bad;
}
@@ -245,7 +240,7 @@ static int vtbl_check(const struct ubi_device *ubi,
}
if (reserved_pebs > ubi->good_peb_count) {
- dbg_err("too large reserved_pebs %d, good PEBs %d",
+ ubi_err("too large reserved_pebs %d, good PEBs %d",
reserved_pebs, ubi->good_peb_count);
err = 9;
goto bad;
@@ -277,8 +272,8 @@ static int vtbl_check(const struct ubi_device *ubi,
!strncmp(vtbl[i].name, vtbl[n].name, len1)) {
ubi_err("volumes %d and %d have the same name"
" \"%s\"", i, n, vtbl[i].name);
- ubi_dbg_dump_vtbl_record(&vtbl[i], i);
- ubi_dbg_dump_vtbl_record(&vtbl[n], n);
+ ubi_dump_vtbl_record(&vtbl[i], i);
+ ubi_dump_vtbl_record(&vtbl[n], n);
return -EINVAL;
}
}
@@ -288,26 +283,26 @@ static int vtbl_check(const struct ubi_device *ubi,
bad:
ubi_err("volume table check failed: record %d, error %d", i, err);
- ubi_dbg_dump_vtbl_record(&vtbl[i], i);
+ ubi_dump_vtbl_record(&vtbl[i], i);
return -EINVAL;
}
/**
* create_vtbl - create a copy of volume table.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
* @copy: number of the volume table copy
* @vtbl: contents of the volume table
*
* This function returns zero in case of success and a negative error code in
* case of failure.
*/
-static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si,
+static int create_vtbl(struct ubi_device *ubi, struct ubi_attach_info *ai,
int copy, void *vtbl)
{
int err, tries = 0;
struct ubi_vid_hdr *vid_hdr;
- struct ubi_scan_leb *new_seb;
+ struct ubi_ainf_peb *new_aeb;
ubi_msg("create volume table (copy #%d)", copy + 1);
@@ -316,9 +311,9 @@ static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si,
return -ENOMEM;
retry:
- new_seb = ubi_scan_get_free_peb(ubi, si);
- if (IS_ERR(new_seb)) {
- err = PTR_ERR(new_seb);
+ new_aeb = ubi_early_get_peb(ubi, ai);
+ if (IS_ERR(new_aeb)) {
+ err = PTR_ERR(new_aeb);
goto out_free;
}
@@ -328,25 +323,24 @@ retry:
vid_hdr->data_size = vid_hdr->used_ebs =
vid_hdr->data_pad = cpu_to_be32(0);
vid_hdr->lnum = cpu_to_be32(copy);
- vid_hdr->sqnum = cpu_to_be64(++si->max_sqnum);
+ vid_hdr->sqnum = cpu_to_be64(++ai->max_sqnum);
/* The EC header is already there, write the VID header */
- err = ubi_io_write_vid_hdr(ubi, new_seb->pnum, vid_hdr);
+ err = ubi_io_write_vid_hdr(ubi, new_aeb->pnum, vid_hdr);
if (err)
goto write_error;
/* Write the layout volume contents */
- err = ubi_io_write_data(ubi, vtbl, new_seb->pnum, 0, ubi->vtbl_size);
+ err = ubi_io_write_data(ubi, vtbl, new_aeb->pnum, 0, ubi->vtbl_size);
if (err)
goto write_error;
/*
- * And add it to the scanning information. Don't delete the old version
- * of this LEB as it will be deleted and freed in 'ubi_scan_add_used()'.
+ * And add it to the attaching information. Don't delete the old version
+ * of this LEB as it will be deleted and freed in 'ubi_add_to_av()'.
*/
- err = ubi_scan_add_used(ubi, si, new_seb->pnum, new_seb->ec,
- vid_hdr, 0);
- kfree(new_seb);
+ err = ubi_add_to_av(ubi, ai, new_aeb->pnum, new_aeb->ec, vid_hdr, 0);
+ kfree(new_aeb);
ubi_free_vid_hdr(ubi, vid_hdr);
return err;
@@ -356,10 +350,10 @@ write_error:
* Probably this physical eraseblock went bad, try to pick
* another one.
*/
- list_add(&new_seb->u.list, &si->erase);
+ list_add(&new_aeb->u.list, &ai->erase);
goto retry;
}
- kfree(new_seb);
+ kfree(new_aeb);
out_free:
ubi_free_vid_hdr(ubi, vid_hdr);
return err;
@@ -369,20 +363,20 @@ out_free:
/**
* process_lvol - process the layout volume.
* @ubi: UBI device description object
- * @si: scanning information
- * @sv: layout volume scanning information
+ * @ai: attaching information
+ * @av: layout volume attaching information
*
* This function is responsible for reading the layout volume, ensuring it is
* not corrupted, and recovering from corruptions if needed. Returns volume
* table in case of success and a negative error code in case of failure.
*/
static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
- struct ubi_scan_info *si,
- struct ubi_scan_volume *sv)
+ struct ubi_attach_info *ai,
+ struct ubi_ainf_volume *av)
{
int err;
struct rb_node *rb;
- struct ubi_scan_leb *seb;
+ struct ubi_ainf_peb *aeb;
struct ubi_vtbl_record *leb[UBI_LAYOUT_VOLUME_EBS] = { NULL, NULL };
int leb_corrupted[UBI_LAYOUT_VOLUME_EBS] = {1, 1};
@@ -414,14 +408,14 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
dbg_gen("check layout volume");
/* Read both LEB 0 and LEB 1 into memory */
- ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) {
- leb[seb->lnum] = vzalloc(ubi->vtbl_size);
- if (!leb[seb->lnum]) {
+ ubi_rb_for_each_entry(rb, aeb, &av->root, u.rb) {
+ leb[aeb->lnum] = vzalloc(ubi->vtbl_size);
+ if (!leb[aeb->lnum]) {
err = -ENOMEM;
goto out_free;
}
- err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
+ err = ubi_io_read_data(ubi, leb[aeb->lnum], aeb->pnum, 0,
ubi->vtbl_size);
if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err))
/*
@@ -429,12 +423,12 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
* uncorrectable ECC error, but we have our own CRC and
* the data will be checked later. If the data is OK,
* the PEB will be scrubbed (because we set
- * seb->scrub). If the data is not OK, the contents of
+ * aeb->scrub). If the data is not OK, the contents of
* the PEB will be recovered from the second copy, and
- * seb->scrub will be cleared in
- * 'ubi_scan_add_used()'.
+ * aeb->scrub will be cleared in
+ * 'ubi_add_to_av()'.
*/
- seb->scrub = 1;
+ aeb->scrub = 1;
else if (err)
goto out_free;
}
@@ -453,7 +447,7 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
ubi->vtbl_size);
if (leb_corrupted[1]) {
ubi_warn("volume table copy #2 is corrupted");
- err = create_vtbl(ubi, si, 1, leb[0]);
+ err = create_vtbl(ubi, ai, 1, leb[0]);
if (err)
goto out_free;
ubi_msg("volume table was restored");
@@ -476,7 +470,7 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi,
}
ubi_warn("volume table copy #1 is corrupted");
- err = create_vtbl(ubi, si, 0, leb[1]);
+ err = create_vtbl(ubi, ai, 0, leb[1]);
if (err)
goto out_free;
ubi_msg("volume table was restored");
@@ -494,13 +488,13 @@ out_free:
/**
* create_empty_lvol - create empty layout volume.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
*
* This function returns volume table contents in case of success and a
* negative error code in case of failure.
*/
static struct ubi_vtbl_record *create_empty_lvol(struct ubi_device *ubi,
- struct ubi_scan_info *si)
+ struct ubi_attach_info *ai)
{
int i;
struct ubi_vtbl_record *vtbl;
@@ -515,7 +509,7 @@ static struct ubi_vtbl_record *create_empty_lvol(struct ubi_device *ubi,
for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
int err;
- err = create_vtbl(ubi, si, i, vtbl);
+ err = create_vtbl(ubi, ai, i, vtbl);
if (err) {
vfree(vtbl);
return ERR_PTR(err);
@@ -528,18 +522,19 @@ static struct ubi_vtbl_record *create_empty_lvol(struct ubi_device *ubi,
/**
* init_volumes - initialize volume information for existing volumes.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: scanning information
* @vtbl: volume table
*
* This function allocates volume description objects for existing volumes.
* Returns zero in case of success and a negative error code in case of
* failure.
*/
-static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
+static int init_volumes(struct ubi_device *ubi,
+ const struct ubi_attach_info *ai,
const struct ubi_vtbl_record *vtbl)
{
int i, reserved_pebs = 0;
- struct ubi_scan_volume *sv;
+ struct ubi_ainf_volume *av;
struct ubi_volume *vol;
for (i = 0; i < ubi->vtbl_slots; i++) {
@@ -595,8 +590,8 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
}
/* Static volumes only */
- sv = ubi_scan_find_sv(si, i);
- if (!sv) {
+ av = ubi_find_av(ai, i);
+ if (!av) {
/*
* No eraseblocks belonging to this volume found. We
* don't actually know whether this static volume is
@@ -608,22 +603,22 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
continue;
}
- if (sv->leb_count != sv->used_ebs) {
+ if (av->leb_count != av->used_ebs) {
/*
* We found a static volume which misses several
* eraseblocks. Treat it as corrupted.
*/
ubi_warn("static volume %d misses %d LEBs - corrupted",
- sv->vol_id, sv->used_ebs - sv->leb_count);
+ av->vol_id, av->used_ebs - av->leb_count);
vol->corrupted = 1;
continue;
}
- vol->used_ebs = sv->used_ebs;
+ vol->used_ebs = av->used_ebs;
vol->used_bytes =
(long long)(vol->used_ebs - 1) * vol->usable_leb_size;
- vol->used_bytes += sv->last_data_size;
- vol->last_eb_bytes = sv->last_data_size;
+ vol->used_bytes += av->last_data_size;
+ vol->last_eb_bytes = av->last_data_size;
}
/* And add the layout volume */
@@ -664,105 +659,104 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
}
/**
- * check_sv - check volume scanning information.
+ * check_av - check volume attaching information.
* @vol: UBI volume description object
- * @sv: volume scanning information
+ * @av: volume attaching information
*
- * This function returns zero if the volume scanning information is consistent
+ * This function returns zero if the volume attaching information is consistent
* to the data read from the volume tabla, and %-EINVAL if not.
*/
-static int check_sv(const struct ubi_volume *vol,
- const struct ubi_scan_volume *sv)
+static int check_av(const struct ubi_volume *vol,
+ const struct ubi_ainf_volume *av)
{
int err;
- if (sv->highest_lnum >= vol->reserved_pebs) {
+ if (av->highest_lnum >= vol->reserved_pebs) {
err = 1;
goto bad;
}
- if (sv->leb_count > vol->reserved_pebs) {
+ if (av->leb_count > vol->reserved_pebs) {
err = 2;
goto bad;
}
- if (sv->vol_type != vol->vol_type) {
+ if (av->vol_type != vol->vol_type) {
err = 3;
goto bad;
}
- if (sv->used_ebs > vol->reserved_pebs) {
+ if (av->used_ebs > vol->reserved_pebs) {
err = 4;
goto bad;
}
- if (sv->data_pad != vol->data_pad) {
+ if (av->data_pad != vol->data_pad) {
err = 5;
goto bad;
}
return 0;
bad:
- ubi_err("bad scanning information, error %d", err);
- ubi_dbg_dump_sv(sv);
- ubi_dbg_dump_vol_info(vol);
+ ubi_err("bad attaching information, error %d", err);
+ ubi_dump_av(av);
+ ubi_dump_vol_info(vol);
return -EINVAL;
}
/**
- * check_scanning_info - check that scanning information.
+ * check_attaching_info - check that attaching information.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
*
* Even though we protect on-flash data by CRC checksums, we still don't trust
- * the media. This function ensures that scanning information is consistent to
- * the information read from the volume table. Returns zero if the scanning
+ * the media. This function ensures that attaching information is consistent to
+ * the information read from the volume table. Returns zero if the attaching
* information is OK and %-EINVAL if it is not.
*/
-static int check_scanning_info(const struct ubi_device *ubi,
- struct ubi_scan_info *si)
+static int check_attaching_info(const struct ubi_device *ubi,
+ struct ubi_attach_info *ai)
{
int err, i;
- struct ubi_scan_volume *sv;
+ struct ubi_ainf_volume *av;
struct ubi_volume *vol;
- if (si->vols_found > UBI_INT_VOL_COUNT + ubi->vtbl_slots) {
- ubi_err("scanning found %d volumes, maximum is %d + %d",
- si->vols_found, UBI_INT_VOL_COUNT, ubi->vtbl_slots);
+ if (ai->vols_found > UBI_INT_VOL_COUNT + ubi->vtbl_slots) {
+ ubi_err("found %d volumes while attaching, maximum is %d + %d",
+ ai->vols_found, UBI_INT_VOL_COUNT, ubi->vtbl_slots);
return -EINVAL;
}
- if (si->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT &&
- si->highest_vol_id < UBI_INTERNAL_VOL_START) {
- ubi_err("too large volume ID %d found by scanning",
- si->highest_vol_id);
+ if (ai->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT &&
+ ai->highest_vol_id < UBI_INTERNAL_VOL_START) {
+ ubi_err("too large volume ID %d found", ai->highest_vol_id);
return -EINVAL;
}
for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
cond_resched();
- sv = ubi_scan_find_sv(si, i);
+ av = ubi_find_av(ai, i);
vol = ubi->volumes[i];
if (!vol) {
- if (sv)
- ubi_scan_rm_volume(si, sv);
+ if (av)
+ ubi_remove_av(ai, av);
continue;
}
if (vol->reserved_pebs == 0) {
ubi_assert(i < ubi->vtbl_slots);
- if (!sv)
+ if (!av)
continue;
/*
- * During scanning we found a volume which does not
+ * During attaching we found a volume which does not
* exist according to the information in the volume
* table. This must have happened due to an unclean
* reboot while the volume was being removed. Discard
* these eraseblocks.
*/
- ubi_msg("finish volume %d removal", sv->vol_id);
- ubi_scan_rm_volume(si, sv);
- } else if (sv) {
- err = check_sv(vol, sv);
+ ubi_msg("finish volume %d removal", av->vol_id);
+ ubi_remove_av(ai, av);
+ } else if (av) {
+ err = check_av(vol, av);
if (err)
return err;
}
@@ -774,16 +768,16 @@ static int check_scanning_info(const struct ubi_device *ubi,
/**
* ubi_read_volume_table - read the volume table.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
*
* This function reads volume table, checks it, recover from errors if needed,
* or creates it if needed. Returns zero in case of success and a negative
* error code in case of failure.
*/
-int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
+int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_attach_info *ai)
{
int i, err;
- struct ubi_scan_volume *sv;
+ struct ubi_ainf_volume *av;
empty_vtbl_record.crc = cpu_to_be32(0xf116c36b);
@@ -798,8 +792,8 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
ubi->vtbl_size = ubi->vtbl_slots * UBI_VTBL_RECORD_SIZE;
ubi->vtbl_size = ALIGN(ubi->vtbl_size, ubi->min_io_size);
- sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID);
- if (!sv) {
+ av = ubi_find_av(ai, UBI_LAYOUT_VOLUME_ID);
+ if (!av) {
/*
* No logical eraseblocks belonging to the layout volume were
* found. This could mean that the flash is just empty. In
@@ -808,8 +802,8 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
* But if flash is not empty this must be a corruption or the
* MTD device just contains garbage.
*/
- if (si->is_empty) {
- ubi->vtbl = create_empty_lvol(ubi, si);
+ if (ai->is_empty) {
+ ubi->vtbl = create_empty_lvol(ubi, ai);
if (IS_ERR(ubi->vtbl))
return PTR_ERR(ubi->vtbl);
} else {
@@ -817,14 +811,14 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
return -EINVAL;
}
} else {
- if (sv->leb_count > UBI_LAYOUT_VOLUME_EBS) {
+ if (av->leb_count > UBI_LAYOUT_VOLUME_EBS) {
/* This must not happen with proper UBI images */
- dbg_err("too many LEBs (%d) in layout volume",
- sv->leb_count);
+ ubi_err("too many LEBs (%d) in layout volume",
+ av->leb_count);
return -EINVAL;
}
- ubi->vtbl = process_lvol(ubi, si, sv);
+ ubi->vtbl = process_lvol(ubi, ai, av);
if (IS_ERR(ubi->vtbl))
return PTR_ERR(ubi->vtbl);
}
@@ -835,15 +829,15 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
* The layout volume is OK, initialize the corresponding in-RAM data
* structures.
*/
- err = init_volumes(ubi, si, ubi->vtbl);
+ err = init_volumes(ubi, ai, ubi->vtbl);
if (err)
goto out_free;
/*
- * Make sure that the scanning information is consistent to the
+ * Make sure that the attaching information is consistent to the
* information stored in the volume table.
*/
- err = check_scanning_info(ubi, si);
+ err = check_attaching_info(ubi, ai);
if (err)
goto out_free;
@@ -858,21 +852,17 @@ out_free:
return err;
}
-#ifdef CONFIG_MTD_UBI_DEBUG
-
/**
- * paranoid_vtbl_check - check volume table.
+ * self_vtbl_check - check volume table.
* @ubi: UBI device description object
*/
-static void paranoid_vtbl_check(const struct ubi_device *ubi)
+static void self_vtbl_check(const struct ubi_device *ubi)
{
if (!ubi->dbg->chk_gen)
return;
if (vtbl_check(ubi, ubi->vtbl)) {
- ubi_err("paranoid check failed");
+ ubi_err("self-check failed");
BUG();
}
}
-
-#endif /* CONFIG_MTD_UBI_DEBUG */
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 7c1a9bf8ac86..9df100a4ec38 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -41,12 +41,6 @@
* physical eraseblocks with low erase counter to free physical eraseblocks
* with high erase counter.
*
- * The 'ubi_wl_get_peb()' function accepts data type hints which help to pick
- * an "optimal" physical eraseblock. For example, when it is known that the
- * physical eraseblock will be "put" soon because it contains short-term data,
- * the WL sub-system may pick a free physical eraseblock with low erase
- * counter, and so forth.
- *
* If the WL sub-system fails to erase a physical eraseblock, it marks it as
* bad.
*
@@ -70,8 +64,7 @@
* to the user; instead, we first want to let users fill them up with data;
*
* o there is a chance that the user will put the physical eraseblock very
- * soon, so it makes sense not to move it for some time, but wait; this is
- * especially important in case of "short term" physical eraseblocks.
+ * soon, so it makes sense not to move it for some time, but wait.
*
* Physical eraseblocks stay protected only for limited time. But the "time" is
* measured in erase cycles in this case. This is implemented with help of the
@@ -147,6 +140,8 @@
* @list: a link in the list of pending works
* @func: worker function
* @e: physical eraseblock to erase
+ * @vol_id: the volume ID on which this erasure is being performed
+ * @lnum: the logical eraseblock number
* @torture: if the physical eraseblock has to be tortured
*
* The @func pointer points to the worker function. If the @cancel argument is
@@ -159,21 +154,16 @@ struct ubi_work {
int (*func)(struct ubi_device *ubi, struct ubi_work *wrk, int cancel);
/* The below fields are only relevant to erasure works */
struct ubi_wl_entry *e;
+ int vol_id;
+ int lnum;
int torture;
};
-#ifdef CONFIG_MTD_UBI_DEBUG
-static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec);
-static int paranoid_check_in_wl_tree(const struct ubi_device *ubi,
- struct ubi_wl_entry *e,
- struct rb_root *root);
-static int paranoid_check_in_pq(const struct ubi_device *ubi,
- struct ubi_wl_entry *e);
-#else
-#define paranoid_check_ec(ubi, pnum, ec) 0
-#define paranoid_check_in_wl_tree(ubi, e, root)
-#define paranoid_check_in_pq(ubi, e) 0
-#endif
+static int self_check_ec(struct ubi_device *ubi, int pnum, int ec);
+static int self_check_in_wl_tree(const struct ubi_device *ubi,
+ struct ubi_wl_entry *e, struct rb_root *root);
+static int self_check_in_pq(const struct ubi_device *ubi,
+ struct ubi_wl_entry *e);
/**
* wl_tree_add - add a wear-leveling entry to a WL RB-tree.
@@ -383,19 +373,15 @@ static struct ubi_wl_entry *find_wl_entry(struct rb_root *root, int diff)
/**
* ubi_wl_get_peb - get a physical eraseblock.
* @ubi: UBI device description object
- * @dtype: type of data which will be stored in this physical eraseblock
*
* This function returns a physical eraseblock in case of success and a
* negative error code in case of failure. Might sleep.
*/
-int ubi_wl_get_peb(struct ubi_device *ubi, int dtype)
+int ubi_wl_get_peb(struct ubi_device *ubi)
{
int err;
struct ubi_wl_entry *e, *first, *last;
- ubi_assert(dtype == UBI_LONGTERM || dtype == UBI_SHORTTERM ||
- dtype == UBI_UNKNOWN);
-
retry:
spin_lock(&ubi->wl_lock);
if (!ubi->free.rb_node) {
@@ -413,45 +399,15 @@ retry:
goto retry;
}
- switch (dtype) {
- case UBI_LONGTERM:
- /*
- * For long term data we pick a physical eraseblock with high
- * erase counter. But the highest erase counter we can pick is
- * bounded by the the lowest erase counter plus
- * %WL_FREE_MAX_DIFF.
- */
- e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);
- break;
- case UBI_UNKNOWN:
- /*
- * For unknown data we pick a physical eraseblock with medium
- * erase counter. But we by no means can pick a physical
- * eraseblock with erase counter greater or equivalent than the
- * lowest erase counter plus %WL_FREE_MAX_DIFF/2.
- */
- first = rb_entry(rb_first(&ubi->free), struct ubi_wl_entry,
- u.rb);
- last = rb_entry(rb_last(&ubi->free), struct ubi_wl_entry, u.rb);
-
- if (last->ec - first->ec < WL_FREE_MAX_DIFF)
- e = rb_entry(ubi->free.rb_node,
- struct ubi_wl_entry, u.rb);
- else
- e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF/2);
- break;
- case UBI_SHORTTERM:
- /*
- * For short term data we pick a physical eraseblock with the
- * lowest erase counter as we expect it will be erased soon.
- */
- e = rb_entry(rb_first(&ubi->free), struct ubi_wl_entry, u.rb);
- break;
- default:
- BUG();
- }
+ first = rb_entry(rb_first(&ubi->free), struct ubi_wl_entry, u.rb);
+ last = rb_entry(rb_last(&ubi->free), struct ubi_wl_entry, u.rb);
+
+ if (last->ec - first->ec < WL_FREE_MAX_DIFF)
+ e = rb_entry(ubi->free.rb_node, struct ubi_wl_entry, u.rb);
+ else
+ e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF/2);
- paranoid_check_in_wl_tree(ubi, e, &ubi->free);
+ self_check_in_wl_tree(ubi, e, &ubi->free);
/*
* Move the physical eraseblock to the protection queue where it will
@@ -462,8 +418,8 @@ retry:
prot_queue_add(ubi, e);
spin_unlock(&ubi->wl_lock);
- err = ubi_dbg_check_all_ff(ubi, e->pnum, ubi->vid_hdr_aloffset,
- ubi->peb_size - ubi->vid_hdr_aloffset);
+ err = ubi_self_check_all_ff(ubi, e->pnum, ubi->vid_hdr_aloffset,
+ ubi->peb_size - ubi->vid_hdr_aloffset);
if (err) {
ubi_err("new PEB %d does not contain all 0xFF bytes", e->pnum);
return err;
@@ -488,7 +444,7 @@ static int prot_queue_del(struct ubi_device *ubi, int pnum)
if (!e)
return -ENODEV;
- if (paranoid_check_in_pq(ubi, e))
+ if (self_check_in_pq(ubi, e))
return -ENODEV;
list_del(&e->u.list);
@@ -514,7 +470,7 @@ static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
dbg_wl("erase PEB %d, old EC %llu", e->pnum, ec);
- err = paranoid_check_ec(ubi, e->pnum, e->ec);
+ err = self_check_ec(ubi, e->pnum, e->ec);
if (err)
return -EINVAL;
@@ -627,13 +583,15 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
* schedule_erase - schedule an erase work.
* @ubi: UBI device description object
* @e: the WL entry of the physical eraseblock to erase
+ * @vol_id: the volume ID that last used this PEB
+ * @lnum: the last used logical eraseblock number for the PEB
* @torture: if the physical eraseblock has to be tortured
*
* This function returns zero in case of success and a %-ENOMEM in case of
* failure.
*/
static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
- int torture)
+ int vol_id, int lnum, int torture)
{
struct ubi_work *wl_wrk;
@@ -646,6 +604,8 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
wl_wrk->func = &erase_worker;
wl_wrk->e = e;
+ wl_wrk->vol_id = vol_id;
+ wl_wrk->lnum = lnum;
wl_wrk->torture = torture;
schedule_ubi_work(ubi, wl_wrk);
@@ -714,7 +674,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
e1->ec, e2->ec);
goto out_cancel;
}
- paranoid_check_in_wl_tree(ubi, e1, &ubi->used);
+ self_check_in_wl_tree(ubi, e1, &ubi->used);
rb_erase(&e1->u.rb, &ubi->used);
dbg_wl("move PEB %d EC %d to PEB %d EC %d",
e1->pnum, e1->ec, e2->pnum, e2->ec);
@@ -723,12 +683,12 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
scrubbing = 1;
e1 = rb_entry(rb_first(&ubi->scrub), struct ubi_wl_entry, u.rb);
e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF);
- paranoid_check_in_wl_tree(ubi, e1, &ubi->scrub);
+ self_check_in_wl_tree(ubi, e1, &ubi->scrub);
rb_erase(&e1->u.rb, &ubi->scrub);
dbg_wl("scrub PEB %d to PEB %d", e1->pnum, e2->pnum);
}
- paranoid_check_in_wl_tree(ubi, e2, &ubi->free);
+ self_check_in_wl_tree(ubi, e2, &ubi->free);
rb_erase(&e2->u.rb, &ubi->free);
ubi->move_from = e1;
ubi->move_to = e2;
@@ -846,7 +806,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
ubi->move_to_put = ubi->wl_scheduled = 0;
spin_unlock(&ubi->wl_lock);
- err = schedule_erase(ubi, e1, 0);
+ err = schedule_erase(ubi, e1, vol_id, lnum, 0);
if (err) {
kmem_cache_free(ubi_wl_entry_slab, e1);
if (e2)
@@ -861,7 +821,7 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
*/
dbg_wl("PEB %d (LEB %d:%d) was put meanwhile, erase",
e2->pnum, vol_id, lnum);
- err = schedule_erase(ubi, e2, 0);
+ err = schedule_erase(ubi, e2, vol_id, lnum, 0);
if (err) {
kmem_cache_free(ubi_wl_entry_slab, e2);
goto out_ro;
@@ -900,7 +860,7 @@ out_not_moved:
spin_unlock(&ubi->wl_lock);
ubi_free_vid_hdr(ubi, vid_hdr);
- err = schedule_erase(ubi, e2, torture);
+ err = schedule_erase(ubi, e2, vol_id, lnum, torture);
if (err) {
kmem_cache_free(ubi_wl_entry_slab, e2);
goto out_ro;
@@ -1019,6 +979,8 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
{
struct ubi_wl_entry *e = wl_wrk->e;
int pnum = e->pnum, err, need;
+ int vol_id = wl_wrk->vol_id;
+ int lnum = wl_wrk->lnum;
if (cancel) {
dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec);
@@ -1027,7 +989,8 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
return 0;
}
- dbg_wl("erase PEB %d EC %d", pnum, e->ec);
+ dbg_wl("erase PEB %d EC %d LEB %d:%d",
+ pnum, e->ec, wl_wrk->vol_id, wl_wrk->lnum);
err = sync_erase(ubi, e, wl_wrk->torture);
if (!err) {
@@ -1057,7 +1020,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
int err1;
/* Re-schedule the LEB for erasure */
- err1 = schedule_erase(ubi, e, 0);
+ err1 = schedule_erase(ubi, e, vol_id, lnum, 0);
if (err1) {
err = err1;
goto out_ro;
@@ -1125,6 +1088,8 @@ out_ro:
/**
* ubi_wl_put_peb - return a PEB to the wear-leveling sub-system.
* @ubi: UBI device description object
+ * @vol_id: the volume ID that last used this PEB
+ * @lnum: the last used logical eraseblock number for the PEB
* @pnum: physical eraseblock to return
* @torture: if this physical eraseblock has to be tortured
*
@@ -1133,7 +1098,8 @@ out_ro:
* occurred to this @pnum and it has to be tested. This function returns zero
* in case of success, and a negative error code in case of failure.
*/
-int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture)
+int ubi_wl_put_peb(struct ubi_device *ubi, int vol_id, int lnum,
+ int pnum, int torture)
{
int err;
struct ubi_wl_entry *e;
@@ -1175,13 +1141,13 @@ retry:
return 0;
} else {
if (in_wl_tree(e, &ubi->used)) {
- paranoid_check_in_wl_tree(ubi, e, &ubi->used);
+ self_check_in_wl_tree(ubi, e, &ubi->used);
rb_erase(&e->u.rb, &ubi->used);
} else if (in_wl_tree(e, &ubi->scrub)) {
- paranoid_check_in_wl_tree(ubi, e, &ubi->scrub);
+ self_check_in_wl_tree(ubi, e, &ubi->scrub);
rb_erase(&e->u.rb, &ubi->scrub);
} else if (in_wl_tree(e, &ubi->erroneous)) {
- paranoid_check_in_wl_tree(ubi, e, &ubi->erroneous);
+ self_check_in_wl_tree(ubi, e, &ubi->erroneous);
rb_erase(&e->u.rb, &ubi->erroneous);
ubi->erroneous_peb_count -= 1;
ubi_assert(ubi->erroneous_peb_count >= 0);
@@ -1199,7 +1165,7 @@ retry:
}
spin_unlock(&ubi->wl_lock);
- err = schedule_erase(ubi, e, torture);
+ err = schedule_erase(ubi, e, vol_id, lnum, torture);
if (err) {
spin_lock(&ubi->wl_lock);
wl_tree_add(e, &ubi->used);
@@ -1248,7 +1214,7 @@ retry:
}
if (in_wl_tree(e, &ubi->used)) {
- paranoid_check_in_wl_tree(ubi, e, &ubi->used);
+ self_check_in_wl_tree(ubi, e, &ubi->used);
rb_erase(&e->u.rb, &ubi->used);
} else {
int err;
@@ -1275,44 +1241,55 @@ retry:
/**
* ubi_wl_flush - flush all pending works.
* @ubi: UBI device description object
+ * @vol_id: the volume id to flush for
+ * @lnum: the logical eraseblock number to flush for
*
- * This function returns zero in case of success and a negative error code in
- * case of failure.
+ * This function executes all pending works for a particular volume id /
+ * logical eraseblock number pair. If either value is set to %UBI_ALL, then it
+ * acts as a wildcard for all of the corresponding volume numbers or logical
+ * eraseblock numbers. It returns zero in case of success and a negative error
+ * code in case of failure.
*/
-int ubi_wl_flush(struct ubi_device *ubi)
+int ubi_wl_flush(struct ubi_device *ubi, int vol_id, int lnum)
{
- int err;
+ int err = 0;
+ int found = 1;
/*
* Erase while the pending works queue is not empty, but not more than
* the number of currently pending works.
*/
- dbg_wl("flush (%d pending works)", ubi->works_count);
- while (ubi->works_count) {
- err = do_work(ubi);
- if (err)
- return err;
- }
+ dbg_wl("flush pending work for LEB %d:%d (%d pending works)",
+ vol_id, lnum, ubi->works_count);
- /*
- * Make sure all the works which have been done in parallel are
- * finished.
- */
down_write(&ubi->work_sem);
- up_write(&ubi->work_sem);
+ while (found) {
+ struct ubi_work *wrk;
+ found = 0;
- /*
- * And in case last was the WL worker and it canceled the LEB
- * movement, flush again.
- */
- while (ubi->works_count) {
- dbg_wl("flush more (%d pending works)", ubi->works_count);
- err = do_work(ubi);
- if (err)
- return err;
+ spin_lock(&ubi->wl_lock);
+ list_for_each_entry(wrk, &ubi->works, list) {
+ if ((vol_id == UBI_ALL || wrk->vol_id == vol_id) &&
+ (lnum == UBI_ALL || wrk->lnum == lnum)) {
+ list_del(&wrk->list);
+ ubi->works_count -= 1;
+ ubi_assert(ubi->works_count >= 0);
+ spin_unlock(&ubi->wl_lock);
+
+ err = wrk->func(ubi, wrk, 0);
+ if (err)
+ goto out;
+ spin_lock(&ubi->wl_lock);
+ found = 1;
+ break;
+ }
+ }
+ spin_unlock(&ubi->wl_lock);
}
- return 0;
+out:
+ up_write(&ubi->work_sem);
+ return err;
}
/**
@@ -1421,26 +1398,26 @@ static void cancel_pending(struct ubi_device *ubi)
}
/**
- * ubi_wl_init_scan - initialize the WL sub-system using scanning information.
+ * ubi_wl_init - initialize the WL sub-system using attaching information.
* @ubi: UBI device description object
- * @si: scanning information
+ * @ai: attaching information
*
* This function returns zero in case of success, and a negative error code in
* case of failure.
*/
-int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
+int ubi_wl_init(struct ubi_device *ubi, struct ubi_attach_info *ai)
{
int err, i;
struct rb_node *rb1, *rb2;
- struct ubi_scan_volume *sv;
- struct ubi_scan_leb *seb, *tmp;
+ struct ubi_ainf_volume *av;
+ struct ubi_ainf_peb *aeb, *tmp;
struct ubi_wl_entry *e;
ubi->used = ubi->erroneous = ubi->free = ubi->scrub = RB_ROOT;
spin_lock_init(&ubi->wl_lock);
mutex_init(&ubi->move_mutex);
init_rwsem(&ubi->work_sem);
- ubi->max_ec = si->max_ec;
+ ubi->max_ec = ai->max_ec;
INIT_LIST_HEAD(&ubi->works);
sprintf(ubi->bgt_name, UBI_BGT_NAME_PATTERN, ubi->ubi_num);
@@ -1454,48 +1431,48 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
INIT_LIST_HEAD(&ubi->pq[i]);
ubi->pq_head = 0;
- list_for_each_entry_safe(seb, tmp, &si->erase, u.list) {
+ list_for_each_entry_safe(aeb, tmp, &ai->erase, u.list) {
cond_resched();
e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
if (!e)
goto out_free;
- e->pnum = seb->pnum;
- e->ec = seb->ec;
+ e->pnum = aeb->pnum;
+ e->ec = aeb->ec;
ubi->lookuptbl[e->pnum] = e;
- if (schedule_erase(ubi, e, 0)) {
+ if (schedule_erase(ubi, e, aeb->vol_id, aeb->lnum, 0)) {
kmem_cache_free(ubi_wl_entry_slab, e);
goto out_free;
}
}
- list_for_each_entry(seb, &si->free, u.list) {
+ list_for_each_entry(aeb, &ai->free, u.list) {
cond_resched();
e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
if (!e)
goto out_free;
- e->pnum = seb->pnum;
- e->ec = seb->ec;
+ e->pnum = aeb->pnum;
+ e->ec = aeb->ec;
ubi_assert(e->ec >= 0);
wl_tree_add(e, &ubi->free);
ubi->lookuptbl[e->pnum] = e;
}
- ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
- ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) {
+ ubi_rb_for_each_entry(rb1, av, &ai->volumes, rb) {
+ ubi_rb_for_each_entry(rb2, aeb, &av->root, u.rb) {
cond_resched();
e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL);
if (!e)
goto out_free;
- e->pnum = seb->pnum;
- e->ec = seb->ec;
+ e->pnum = aeb->pnum;
+ e->ec = aeb->ec;
ubi->lookuptbl[e->pnum] = e;
- if (!seb->scrub) {
+ if (!aeb->scrub) {
dbg_wl("add PEB %d EC %d to the used tree",
e->pnum, e->ec);
wl_tree_add(e, &ubi->used);
@@ -1567,10 +1544,8 @@ void ubi_wl_close(struct ubi_device *ubi)
kfree(ubi->lookuptbl);
}
-#ifdef CONFIG_MTD_UBI_DEBUG
-
/**
- * paranoid_check_ec - make sure that the erase counter of a PEB is correct.
+ * self_check_ec - make sure that the erase counter of a PEB is correct.
* @ubi: UBI device description object
* @pnum: the physical eraseblock number to check
* @ec: the erase counter to check
@@ -1579,7 +1554,7 @@ void ubi_wl_close(struct ubi_device *ubi)
* is equivalent to @ec, and a negative error code if not or if an error
* occurred.
*/
-static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec)
+static int self_check_ec(struct ubi_device *ubi, int pnum, int ec)
{
int err;
long long read_ec;
@@ -1601,9 +1576,9 @@ static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec)
read_ec = be64_to_cpu(ec_hdr->ec);
if (ec != read_ec) {
- ubi_err("paranoid check failed for PEB %d", pnum);
+ ubi_err("self-check failed for PEB %d", pnum);
ubi_err("read EC is %lld, should be %d", read_ec, ec);
- ubi_dbg_dump_stack();
+ dump_stack();
err = 1;
} else
err = 0;
@@ -1614,7 +1589,7 @@ out_free:
}
/**
- * paranoid_check_in_wl_tree - check that wear-leveling entry is in WL RB-tree.
+ * self_check_in_wl_tree - check that wear-leveling entry is in WL RB-tree.
* @ubi: UBI device description object
* @e: the wear-leveling entry to check
* @root: the root of the tree
@@ -1622,9 +1597,8 @@ out_free:
* This function returns zero if @e is in the @root RB-tree and %-EINVAL if it
* is not.
*/
-static int paranoid_check_in_wl_tree(const struct ubi_device *ubi,
- struct ubi_wl_entry *e,
- struct rb_root *root)
+static int self_check_in_wl_tree(const struct ubi_device *ubi,
+ struct ubi_wl_entry *e, struct rb_root *root)
{
if (!ubi->dbg->chk_gen)
return 0;
@@ -1632,22 +1606,22 @@ static int paranoid_check_in_wl_tree(const struct ubi_device *ubi,
if (in_wl_tree(e, root))
return 0;
- ubi_err("paranoid check failed for PEB %d, EC %d, RB-tree %p ",
+ ubi_err("self-check failed for PEB %d, EC %d, RB-tree %p ",
e->pnum, e->ec, root);
- ubi_dbg_dump_stack();
+ dump_stack();
return -EINVAL;
}
/**
- * paranoid_check_in_pq - check if wear-leveling entry is in the protection
+ * self_check_in_pq - check if wear-leveling entry is in the protection
* queue.
* @ubi: UBI device description object
* @e: the wear-leveling entry to check
*
* This function returns zero if @e is in @ubi->pq and %-EINVAL if it is not.
*/
-static int paranoid_check_in_pq(const struct ubi_device *ubi,
- struct ubi_wl_entry *e)
+static int self_check_in_pq(const struct ubi_device *ubi,
+ struct ubi_wl_entry *e)
{
struct ubi_wl_entry *p;
int i;
@@ -1660,10 +1634,8 @@ static int paranoid_check_in_pq(const struct ubi_device *ubi,
if (p == e)
return 0;
- ubi_err("paranoid check failed for PEB %d, EC %d, Protect queue",
+ ubi_err("self-check failed for PEB %d, EC %d, Protect queue",
e->pnum, e->ec);
- ubi_dbg_dump_stack();
+ dump_stack();
return -EINVAL;
}
-
-#endif /* CONFIG_MTD_UBI_DEBUG */
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index 1efb08386c61..38c0690df5c8 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -35,6 +35,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
#define DRV_NAME "flexcan"
@@ -927,11 +928,16 @@ static int __devinit flexcan_probe(struct platform_device *pdev)
struct flexcan_priv *priv;
struct resource *mem;
struct clk *clk = NULL;
+ struct pinctrl *pinctrl;
void __iomem *base;
resource_size_t mem_size;
int err, irq;
u32 clock_freq = 0;
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl))
+ return PTR_ERR(pinctrl);
+
if (pdev->dev.of_node) {
const u32 *clock_freq_p;
diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig
index b60d6c5f29a0..03df9a8f2bbf 100644
--- a/drivers/net/can/sja1000/Kconfig
+++ b/drivers/net/can/sja1000/Kconfig
@@ -75,7 +75,7 @@ config CAN_KVASER_PCI
tristate "Kvaser PCIcanx and Kvaser PCIcan PCI Cards"
depends on PCI
---help---
- This driver is for the the PCIcanx and PCIcan cards (1, 2 or
+ This driver is for the PCIcanx and PCIcan cards (1, 2 or
4 channel) from Kvaser (http://www.kvaser.com).
config CAN_PLX_PCI
diff --git a/drivers/net/ethernet/3com/typhoon.c b/drivers/net/ethernet/3com/typhoon.c
index 1234a14b2b73..b15366635147 100644
--- a/drivers/net/ethernet/3com/typhoon.c
+++ b/drivers/net/ethernet/3com/typhoon.c
@@ -2549,8 +2549,7 @@ typhoon_init(void)
static void __exit
typhoon_cleanup(void)
{
- if (typhoon_fw)
- release_firmware(typhoon_fw);
+ release_firmware(typhoon_fw);
pci_unregister_driver(&typhoon_driver);
}
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index d55df3290174..edeeb516807a 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -15883,8 +15883,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
if (dev) {
struct tg3 *tp = netdev_priv(dev);
- if (tp->fw)
- release_firmware(tp->fw);
+ release_firmware(tp->fw);
tg3_reset_task_cancel(tp);
diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c
index 25c4e7f2a099..67cd2ed0306a 100644
--- a/drivers/net/ethernet/brocade/bna/bnad.c
+++ b/drivers/net/ethernet/brocade/bna/bnad.c
@@ -3520,9 +3520,7 @@ static void __exit
bnad_module_exit(void)
{
pci_unregister_driver(&bnad_pci_driver);
-
- if (bfi_fw)
- release_firmware(bfi_fw);
+ release_firmware(bfi_fw);
}
module_init(bnad_module_init);
diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c
index 7fa0227c9c02..8f2cf8c09e2d 100644
--- a/drivers/net/ethernet/freescale/fec.c
+++ b/drivers/net/ethernet/freescale/fec.c
@@ -48,6 +48,7 @@
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/of_net.h>
+#include <linux/pinctrl/consumer.h>
#include <asm/cacheflush.h>
@@ -1543,6 +1544,7 @@ fec_probe(struct platform_device *pdev)
struct resource *r;
const struct of_device_id *of_id;
static int dev_id;
+ struct pinctrl *pinctrl;
of_id = of_match_device(fec_dt_ids, &pdev->dev);
if (of_id)
@@ -1610,6 +1612,12 @@ fec_probe(struct platform_device *pdev)
}
}
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ goto failed_pin;
+ }
+
fep->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(fep->clk)) {
ret = PTR_ERR(fep->clk);
@@ -1640,6 +1648,7 @@ failed_mii_init:
failed_init:
clk_disable_unprepare(fep->clk);
clk_put(fep->clk);
+failed_pin:
failed_clk:
for (i = 0; i < FEC_IRQ_NUM; i++) {
irq = platform_get_irq(pdev, i);
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 1adb0245b9dd..0741aded9eb0 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -1082,7 +1082,7 @@ static int gfar_probe(struct platform_device *ofdev)
if (dev->features & NETIF_F_IP_CSUM ||
priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)
- dev->hard_header_len += GMAC_FCB_LEN;
+ dev->needed_headroom = GMAC_FCB_LEN;
/* Program the isrg regs only if number of grps > 1 */
if (priv->num_grps > 1) {
diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c
index d3469d8e3f0d..8d2666fcffd7 100644
--- a/drivers/net/ethernet/nxp/lpc_eth.c
+++ b/drivers/net/ethernet/nxp/lpc_eth.c
@@ -40,6 +40,7 @@
#include <linux/skbuff.h>
#include <linux/phy.h>
#include <linux/dma-mapping.h>
+#include <linux/of.h>
#include <linux/of_net.h>
#include <linux/types.h>
@@ -340,13 +341,17 @@
*/
#define LPC_POWERDOWN_MACAHB (1 << 31)
-/* Upon the upcoming introduction of device tree usage in LPC32xx,
- * lpc_phy_interface_mode() and use_iram_for_net() will be extended with a
- * device parameter for access to device tree information at runtime, instead
- * of defining the values at compile time
- */
-static inline phy_interface_t lpc_phy_interface_mode(void)
+static phy_interface_t lpc_phy_interface_mode(struct device *dev)
{
+ if (dev && dev->of_node) {
+ const char *mode = of_get_property(dev->of_node,
+ "phy-mode", NULL);
+ if (mode && !strcmp(mode, "mii"))
+ return PHY_INTERFACE_MODE_MII;
+ return PHY_INTERFACE_MODE_RMII;
+ }
+
+ /* non-DT */
#ifdef CONFIG_ARCH_LPC32XX_MII_SUPPORT
return PHY_INTERFACE_MODE_MII;
#else
@@ -354,12 +359,16 @@ static inline phy_interface_t lpc_phy_interface_mode(void)
#endif
}
-static inline int use_iram_for_net(void)
+static bool use_iram_for_net(struct device *dev)
{
+ if (dev && dev->of_node)
+ return of_property_read_bool(dev->of_node, "use-iram");
+
+ /* non-DT */
#ifdef CONFIG_ARCH_LPC32XX_IRAM_FOR_NET
- return 1;
+ return true;
#else
- return 0;
+ return false;
#endif
}
@@ -664,7 +673,7 @@ static void __lpc_eth_init(struct netdata_local *pldat)
LPC_ENET_CLRT(pldat->net_base));
writel(LPC_IPGR_LOAD_PART2(0x12), LPC_ENET_IPGR(pldat->net_base));
- if (lpc_phy_interface_mode() == PHY_INTERFACE_MODE_MII)
+ if (lpc_phy_interface_mode(&pldat->pdev->dev) == PHY_INTERFACE_MODE_MII)
writel(LPC_COMMAND_PASSRUNTFRAME,
LPC_ENET_COMMAND(pldat->net_base));
else {
@@ -804,12 +813,13 @@ static int lpc_mii_probe(struct net_device *ndev)
}
/* Attach to the PHY */
- if (lpc_phy_interface_mode() == PHY_INTERFACE_MODE_MII)
+ if (lpc_phy_interface_mode(&pldat->pdev->dev) == PHY_INTERFACE_MODE_MII)
netdev_info(ndev, "using MII interface\n");
else
netdev_info(ndev, "using RMII interface\n");
phydev = phy_connect(ndev, dev_name(&phydev->dev),
- &lpc_handle_link_change, 0, lpc_phy_interface_mode());
+ &lpc_handle_link_change, 0,
+ lpc_phy_interface_mode(&pldat->pdev->dev));
if (IS_ERR(phydev)) {
netdev_err(ndev, "Could not attach to PHY\n");
@@ -843,7 +853,7 @@ static int lpc_mii_init(struct netdata_local *pldat)
}
/* Setup MII mode */
- if (lpc_phy_interface_mode() == PHY_INTERFACE_MODE_MII)
+ if (lpc_phy_interface_mode(&pldat->pdev->dev) == PHY_INTERFACE_MODE_MII)
writel(LPC_COMMAND_PASSRUNTFRAME,
LPC_ENET_COMMAND(pldat->net_base));
else {
@@ -1315,18 +1325,26 @@ static const struct net_device_ops lpc_netdev_ops = {
static int lpc_eth_drv_probe(struct platform_device *pdev)
{
struct resource *res;
- struct resource *dma_res;
struct net_device *ndev;
struct netdata_local *pldat;
struct phy_device *phydev;
dma_addr_t dma_handle;
int irq, ret;
+ u32 tmp;
+
+ /* Setup network interface for RMII or MII mode */
+ tmp = __raw_readl(LPC32XX_CLKPWR_MACCLK_CTRL);
+ tmp &= ~LPC32XX_CLKPWR_MACCTRL_PINS_MSK;
+ if (lpc_phy_interface_mode(&pdev->dev) == PHY_INTERFACE_MODE_MII)
+ tmp |= LPC32XX_CLKPWR_MACCTRL_USE_MII_PINS;
+ else
+ tmp |= LPC32XX_CLKPWR_MACCTRL_USE_RMII_PINS;
+ __raw_writel(tmp, LPC32XX_CLKPWR_MACCLK_CTRL);
/* Get platform resources */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- dma_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
irq = platform_get_irq(pdev, 0);
- if ((!res) || (!dma_res) || (irq < 0) || (irq >= NR_IRQS)) {
+ if ((!res) || (irq < 0) || (irq >= NR_IRQS)) {
dev_err(&pdev->dev, "error getting resources.\n");
ret = -ENXIO;
goto err_exit;
@@ -1389,17 +1407,19 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
sizeof(struct txrx_desc_t) + sizeof(struct rx_status_t));
pldat->dma_buff_base_v = 0;
- if (use_iram_for_net()) {
- dma_handle = dma_res->start;
+ if (use_iram_for_net(&pldat->pdev->dev)) {
+ dma_handle = LPC32XX_IRAM_BASE;
if (pldat->dma_buff_size <= lpc32xx_return_iram_size())
pldat->dma_buff_base_v =
- io_p2v(dma_res->start);
+ io_p2v(LPC32XX_IRAM_BASE);
else
netdev_err(ndev,
"IRAM not big enough for net buffers, using SDRAM instead.\n");
}
if (pldat->dma_buff_base_v == 0) {
+ pldat->pdev->dev.coherent_dma_mask = 0xFFFFFFFF;
+ pldat->pdev->dev.dma_mask = &pldat->pdev->dev.coherent_dma_mask;
pldat->dma_buff_size = PAGE_ALIGN(pldat->dma_buff_size);
/* Allocate a chunk of memory for the DMA ethernet buffers
@@ -1488,7 +1508,7 @@ err_out_unregister_netdev:
platform_set_drvdata(pdev, NULL);
unregister_netdev(ndev);
err_out_dma_unmap:
- if (!use_iram_for_net() ||
+ if (!use_iram_for_net(&pldat->pdev->dev) ||
pldat->dma_buff_size > lpc32xx_return_iram_size())
dma_free_coherent(&pldat->pdev->dev, pldat->dma_buff_size,
pldat->dma_buff_base_v,
@@ -1515,7 +1535,7 @@ static int lpc_eth_drv_remove(struct platform_device *pdev)
unregister_netdev(ndev);
platform_set_drvdata(pdev, NULL);
- if (!use_iram_for_net() ||
+ if (!use_iram_for_net(&pldat->pdev->dev) ||
pldat->dma_buff_size > lpc32xx_return_iram_size())
dma_free_coherent(&pldat->pdev->dev, pldat->dma_buff_size,
pldat->dma_buff_base_v,
@@ -1584,6 +1604,14 @@ static int lpc_eth_drv_resume(struct platform_device *pdev)
}
#endif
+#ifdef CONFIG_OF
+static const struct of_device_id lpc_eth_match[] = {
+ { .compatible = "nxp,lpc-eth" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lpc_eth_match);
+#endif
+
static struct platform_driver lpc_eth_driver = {
.probe = lpc_eth_drv_probe,
.remove = __devexit_p(lpc_eth_drv_remove),
@@ -1593,6 +1621,7 @@ static struct platform_driver lpc_eth_driver = {
#endif
.driver = {
.name = MODNAME,
+ .of_match_table = of_match_ptr(lpc_eth_match),
},
};
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
index 0d725dc91bcb..8694124ef77d 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c
@@ -1260,8 +1260,7 @@ next:
void
netxen_release_firmware(struct netxen_adapter *adapter)
{
- if (adapter->fw)
- release_firmware(adapter->fw);
+ release_firmware(adapter->fw);
adapter->fw = NULL;
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
index d32cf0ddf1b9..799fd40ed03a 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
@@ -1321,8 +1321,7 @@ next:
void
qlcnic_release_firmware(struct qlcnic_adapter *adapter)
{
- if (adapter->fw)
- release_firmware(adapter->fw);
+ release_firmware(adapter->fw);
adapter->fw = NULL;
}
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 4f74b9762c29..00b4f56a671c 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -6051,7 +6051,7 @@ static int rtl_open(struct net_device *dev)
pm_runtime_get_sync(&pdev->dev);
/*
- * Rx and Tx desscriptors needs 256 bytes alignment.
+ * Rx and Tx descriptors needs 256 bytes alignment.
* dma_alloc_coherent provides more.
*/
tp->TxDescArray = dma_alloc_coherent(&pdev->dev, R8169_TX_RING_BYTES,
diff --git a/drivers/net/ethernet/s6gmac.c b/drivers/net/ethernet/s6gmac.c
index 8e9fda0c7aeb..2ed3ab4b3c2d 100644
--- a/drivers/net/ethernet/s6gmac.c
+++ b/drivers/net/ethernet/s6gmac.c
@@ -1,7 +1,7 @@
/*
* Ethernet driver for S6105 on chip network device
* (c)2008 emlix GmbH http://www.emlix.com
- * Authors: Oskar Schirmer <os@emlix.com>
+ * Authors: Oskar Schirmer <oskar@scara.com>
* Daniel Gloeckner <dg@emlix.com>
*
* This program is free software; you can redistribute it and/or
@@ -1070,4 +1070,4 @@ module_exit(s6gmac_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("S6105 on chip Ethernet driver");
-MODULE_AUTHOR("Oskar Schirmer <os@emlix.com>");
+MODULE_AUTHOR("Oskar Schirmer <oskar@scara.com>");
diff --git a/drivers/net/ethernet/tehuti/tehuti.c b/drivers/net/ethernet/tehuti/tehuti.c
index 8846516678c3..447a6932cab3 100644
--- a/drivers/net/ethernet/tehuti/tehuti.c
+++ b/drivers/net/ethernet/tehuti/tehuti.c
@@ -341,8 +341,8 @@ static int bdx_fw_load(struct bdx_priv *priv)
out:
if (master)
WRITE_REG(priv, regINIT_SEMAPHORE, 1);
- if (fw)
- release_firmware(fw);
+
+ release_firmware(fw);
if (rc) {
netdev_err(priv->ndev, "firmware loading failed\n");
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index 35758445297e..595205406d73 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -211,8 +211,8 @@ config KINGSUN_DONGLE
kingsun-sir.
config EP7211_DONGLE
- tristate "EP7211 I/R support"
- depends on IRTTY_SIR && ARCH_EP7211 && IRDA && EXPERIMENTAL
+ tristate "Cirrus Logic clps711x I/R support"
+ depends on IRTTY_SIR && ARCH_CLPS711X && IRDA && EXPERIMENTAL
help
Say Y here if you want to build support for the Cirrus logic
EP7211 chipset's infrared module.
@@ -316,7 +316,7 @@ config AU1000_FIR
tristate "Alchemy IrDA SIR/FIR"
depends on IRDA && MIPS_ALCHEMY
help
- Say Y/M here to build suppor the the IrDA peripheral on the
+ Say Y/M here to build support the IrDA peripheral on the
Alchemy Au1000 and Au1100 SoCs.
Say M to build a module; it will be called au1k_ir.ko
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 72f687b40d66..f9a86bdb12fa 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -1671,7 +1671,7 @@ static int irda_usb_probe(struct usb_interface *intf,
/* Is this really necessary? (no, except maybe for broken devices) */
if (usb_reset_configuration (dev) < 0) {
- err("reset_configuration failed");
+ dev_err(&intf->dev, "reset_configuration failed\n");
ret = -EIO;
goto err_out_3;
}
diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c
index 79aebeee928c..7b4833874ef5 100644
--- a/drivers/net/irda/kingsun-sir.c
+++ b/drivers/net/irda/kingsun-sir.c
@@ -134,14 +134,16 @@ static void kingsun_send_irq(struct urb *urb)
/* in process of stopping, just drop data */
if (!netif_running(kingsun->netdev)) {
- err("kingsun_send_irq: Network not running!");
+ dev_err(&kingsun->usbdev->dev,
+ "kingsun_send_irq: Network not running!\n");
return;
}
/* unlink, shutdown, unplug, other nasties */
if (urb->status != 0) {
- err("kingsun_send_irq: urb asynchronously failed - %d",
- urb->status);
+ dev_err(&kingsun->usbdev->dev,
+ "kingsun_send_irq: urb asynchronously failed - %d\n",
+ urb->status);
}
netif_wake_queue(netdev);
}
@@ -177,7 +179,8 @@ static netdev_tx_t kingsun_hard_xmit(struct sk_buff *skb,
kingsun, 1);
if ((ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC))) {
- err("kingsun_hard_xmit: failed tx_urb submit: %d", ret);
+ dev_err(&kingsun->usbdev->dev,
+ "kingsun_hard_xmit: failed tx_urb submit: %d\n", ret);
switch (ret) {
case -ENODEV:
case -EPIPE:
@@ -211,8 +214,9 @@ static void kingsun_rcv_irq(struct urb *urb)
/* unlink, shutdown, unplug, other nasties */
if (urb->status != 0) {
- err("kingsun_rcv_irq: urb asynchronously failed - %d",
- urb->status);
+ dev_err(&kingsun->usbdev->dev,
+ "kingsun_rcv_irq: urb asynchronously failed - %d\n",
+ urb->status);
kingsun->receiving = 0;
return;
}
@@ -238,8 +242,9 @@ static void kingsun_rcv_irq(struct urb *urb)
? 1 : 0;
}
} else if (urb->actual_length > 0) {
- err("%s(): Unexpected response length, expected %d got %d",
- __func__, kingsun->max_rx, urb->actual_length);
+ dev_err(&kingsun->usbdev->dev,
+ "%s(): Unexpected response length, expected %d got %d\n",
+ __func__, kingsun->max_rx, urb->actual_length);
}
/* This urb has already been filled in kingsun_net_open */
ret = usb_submit_urb(urb, GFP_ATOMIC);
@@ -286,7 +291,7 @@ static int kingsun_net_open(struct net_device *netdev)
sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
if (!kingsun->irlap) {
- err("kingsun-sir: irlap_open failed");
+ dev_err(&kingsun->usbdev->dev, "irlap_open failed\n");
goto free_mem;
}
@@ -298,7 +303,8 @@ static int kingsun_net_open(struct net_device *netdev)
kingsun->rx_urb->status = 0;
err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
if (err) {
- err("kingsun-sir: first urb-submit failed: %d", err);
+ dev_err(&kingsun->usbdev->dev,
+ "first urb-submit failed: %d\n", err);
goto close_irlap;
}
@@ -446,13 +452,15 @@ static int kingsun_probe(struct usb_interface *intf,
*/
interface = intf->cur_altsetting;
if (interface->desc.bNumEndpoints != 2) {
- err("kingsun-sir: expected 2 endpoints, found %d",
- interface->desc.bNumEndpoints);
+ dev_err(&intf->dev,
+ "kingsun-sir: expected 2 endpoints, found %d\n",
+ interface->desc.bNumEndpoints);
return -ENODEV;
}
endpoint = &interface->endpoint[KINGSUN_EP_IN].desc;
if (!usb_endpoint_is_int_in(endpoint)) {
- err("kingsun-sir: endpoint 0 is not interrupt IN");
+ dev_err(&intf->dev,
+ "kingsun-sir: endpoint 0 is not interrupt IN\n");
return -ENODEV;
}
@@ -460,14 +468,16 @@ static int kingsun_probe(struct usb_interface *intf,
pipe = usb_rcvintpipe(dev, ep_in);
maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
if (maxp_in > 255 || maxp_in <= 1) {
- err("%s: endpoint 0 has max packet size %d not in range",
- __FILE__, maxp_in);
+ dev_err(&intf->dev,
+ "endpoint 0 has max packet size %d not in range\n",
+ maxp_in);
return -ENODEV;
}
endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc;
if (!usb_endpoint_is_int_out(endpoint)) {
- err("kingsun-sir: endpoint 1 is not interrupt OUT");
+ dev_err(&intf->dev,
+ "kingsun-sir: endpoint 1 is not interrupt OUT\n");
return -ENODEV;
}
diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c
index abe689dffc72..824e2a93fe8a 100644
--- a/drivers/net/irda/ks959-sir.c
+++ b/drivers/net/irda/ks959-sir.c
@@ -247,8 +247,9 @@ static void ks959_speed_irq(struct urb *urb)
{
/* unlink, shutdown, unplug, other nasties */
if (urb->status != 0) {
- err("ks959_speed_irq: urb asynchronously failed - %d",
- urb->status);
+ dev_err(&urb->dev->dev,
+ "ks959_speed_irq: urb asynchronously failed - %d\n",
+ urb->status);
}
}
@@ -332,14 +333,16 @@ static void ks959_send_irq(struct urb *urb)
/* in process of stopping, just drop data */
if (!netif_running(kingsun->netdev)) {
- err("ks959_send_irq: Network not running!");
+ dev_err(&kingsun->usbdev->dev,
+ "ks959_send_irq: Network not running!\n");
return;
}
/* unlink, shutdown, unplug, other nasties */
if (urb->status != 0) {
- err("ks959_send_irq: urb asynchronously failed - %d",
- urb->status);
+ dev_err(&kingsun->usbdev->dev,
+ "ks959_send_irq: urb asynchronously failed - %d\n",
+ urb->status);
return;
}
@@ -358,8 +361,9 @@ static void ks959_send_irq(struct urb *urb)
if (kingsun->tx_buf_clear_used > 0) {
/* There is more data to be sent */
if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) {
- err("ks959_send_irq: failed tx_urb submit: %d",
- ret);
+ dev_err(&kingsun->usbdev->dev,
+ "ks959_send_irq: failed tx_urb submit: %d\n",
+ ret);
switch (ret) {
case -ENODEV:
case -EPIPE:
@@ -407,7 +411,8 @@ static netdev_tx_t ks959_hard_xmit(struct sk_buff *skb,
kingsun->tx_buf_clear_used = wraplen;
if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) {
- err("ks959_hard_xmit: failed tx_urb submit: %d", ret);
+ dev_err(&kingsun->usbdev->dev,
+ "ks959_hard_xmit: failed tx_urb submit: %d\n", ret);
switch (ret) {
case -ENODEV:
case -EPIPE:
@@ -442,8 +447,9 @@ static void ks959_rcv_irq(struct urb *urb)
/* unlink, shutdown, unplug, other nasties */
if (urb->status != 0) {
- err("kingsun_rcv_irq: urb asynchronously failed - %d",
- urb->status);
+ dev_err(&kingsun->usbdev->dev,
+ "kingsun_rcv_irq: urb asynchronously failed - %d\n",
+ urb->status);
kingsun->receiving = 0;
return;
}
@@ -536,7 +542,7 @@ static int ks959_net_open(struct net_device *netdev)
sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
if (!kingsun->irlap) {
- err("ks959-sir: irlap_open failed");
+ dev_err(&kingsun->usbdev->dev, "irlap_open failed\n");
goto free_mem;
}
@@ -549,7 +555,8 @@ static int ks959_net_open(struct net_device *netdev)
kingsun->rx_urb->status = 0;
err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
if (err) {
- err("ks959-sir: first urb-submit failed: %d", err);
+ dev_err(&kingsun->usbdev->dev,
+ "first urb-submit failed: %d\n", err);
goto close_irlap;
}
diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c
index f8c01088eeb7..5a278ab83c2f 100644
--- a/drivers/net/irda/ksdazzle-sir.c
+++ b/drivers/net/irda/ksdazzle-sir.c
@@ -168,10 +168,10 @@ struct ksdazzle_cb {
static void ksdazzle_speed_irq(struct urb *urb)
{
/* unlink, shutdown, unplug, other nasties */
- if (urb->status != 0) {
- err("ksdazzle_speed_irq: urb asynchronously failed - %d",
- urb->status);
- }
+ if (urb->status != 0)
+ dev_err(&urb->dev->dev,
+ "ksdazzle_speed_irq: urb asynchronously failed - %d\n",
+ urb->status);
}
/* Send a control request to change speed of the dongle */
@@ -245,14 +245,16 @@ static void ksdazzle_send_irq(struct urb *urb)
/* in process of stopping, just drop data */
if (!netif_running(kingsun->netdev)) {
- err("ksdazzle_send_irq: Network not running!");
+ dev_err(&kingsun->usbdev->dev,
+ "ksdazzle_send_irq: Network not running!\n");
return;
}
/* unlink, shutdown, unplug, other nasties */
if (urb->status != 0) {
- err("ksdazzle_send_irq: urb asynchronously failed - %d",
- urb->status);
+ dev_err(&kingsun->usbdev->dev,
+ "ksdazzle_send_irq: urb asynchronously failed - %d\n",
+ urb->status);
return;
}
@@ -271,7 +273,9 @@ static void ksdazzle_send_irq(struct urb *urb)
if (kingsun->tx_buf_clear_used > 0) {
/* There is more data to be sent */
if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) {
- err("ksdazzle_send_irq: failed tx_urb submit: %d", ret);
+ dev_err(&kingsun->usbdev->dev,
+ "ksdazzle_send_irq: failed tx_urb submit: %d\n",
+ ret);
switch (ret) {
case -ENODEV:
case -EPIPE:
@@ -320,7 +324,8 @@ static netdev_tx_t ksdazzle_hard_xmit(struct sk_buff *skb,
kingsun->tx_buf_clear_used = wraplen;
if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) {
- err("ksdazzle_hard_xmit: failed tx_urb submit: %d", ret);
+ dev_err(&kingsun->usbdev->dev,
+ "ksdazzle_hard_xmit: failed tx_urb submit: %d\n", ret);
switch (ret) {
case -ENODEV:
case -EPIPE:
@@ -355,8 +360,9 @@ static void ksdazzle_rcv_irq(struct urb *urb)
/* unlink, shutdown, unplug, other nasties */
if (urb->status != 0) {
- err("ksdazzle_rcv_irq: urb asynchronously failed - %d",
- urb->status);
+ dev_err(&kingsun->usbdev->dev,
+ "ksdazzle_rcv_irq: urb asynchronously failed - %d\n",
+ urb->status);
kingsun->receiving = 0;
return;
}
@@ -430,7 +436,7 @@ static int ksdazzle_net_open(struct net_device *netdev)
sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
if (!kingsun->irlap) {
- err("ksdazzle-sir: irlap_open failed");
+ dev_err(&kingsun->usbdev->dev, "irlap_open failed\n");
goto free_mem;
}
@@ -442,7 +448,7 @@ static int ksdazzle_net_open(struct net_device *netdev)
kingsun->rx_urb->status = 0;
err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
if (err) {
- err("ksdazzle-sir: first urb-submit failed: %d", err);
+ dev_err(&kingsun->usbdev->dev, "first urb-submit failed: %d\n", err);
goto close_irlap;
}
@@ -590,13 +596,14 @@ static int ksdazzle_probe(struct usb_interface *intf,
*/
interface = intf->cur_altsetting;
if (interface->desc.bNumEndpoints != 2) {
- err("ksdazzle: expected 2 endpoints, found %d",
- interface->desc.bNumEndpoints);
+ dev_err(&intf->dev, "ksdazzle: expected 2 endpoints, found %d\n",
+ interface->desc.bNumEndpoints);
return -ENODEV;
}
endpoint = &interface->endpoint[KINGSUN_EP_IN].desc;
if (!usb_endpoint_is_int_in(endpoint)) {
- err("ksdazzle: endpoint 0 is not interrupt IN");
+ dev_err(&intf->dev,
+ "ksdazzle: endpoint 0 is not interrupt IN\n");
return -ENODEV;
}
@@ -604,13 +611,16 @@ static int ksdazzle_probe(struct usb_interface *intf,
pipe = usb_rcvintpipe(dev, ep_in);
maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
if (maxp_in > 255 || maxp_in <= 1) {
- err("ksdazzle: endpoint 0 has max packet size %d not in range [2..255]", maxp_in);
+ dev_err(&intf->dev,
+ "ksdazzle: endpoint 0 has max packet size %d not in range [2..255]\n",
+ maxp_in);
return -ENODEV;
}
endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc;
if (!usb_endpoint_is_int_out(endpoint)) {
- err("ksdazzle: endpoint 1 is not interrupt OUT");
+ dev_err(&intf->dev,
+ "ksdazzle: endpoint 1 is not interrupt OUT\n");
return -ENODEV;
}
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index e6e59a078ef4..876e709b65ba 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -904,7 +904,7 @@ static int stir_net_open(struct net_device *netdev)
sprintf(hwname, "usb#%d", stir->usbdev->devnum);
stir->irlap = irlap_open(netdev, &stir->qos, hwname);
if (!stir->irlap) {
- err("stir4200: irlap_open failed");
+ dev_err(&stir->usbdev->dev, "irlap_open failed\n");
goto err_out5;
}
@@ -913,7 +913,7 @@ static int stir_net_open(struct net_device *netdev)
"%s", stir->netdev->name);
if (IS_ERR(stir->thread)) {
err = PTR_ERR(stir->thread);
- err("stir4200: unable to start kernel thread");
+ dev_err(&stir->usbdev->dev, "unable to start kernel thread\n");
goto err_out6;
}
@@ -1042,7 +1042,7 @@ static int stir_probe(struct usb_interface *intf,
ret = usb_reset_configuration(dev);
if (ret != 0) {
- err("stir4200: usb reset configuration failed");
+ dev_err(&intf->dev, "usb reset configuration failed\n");
goto err_out2;
}
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index 42b5151aa78a..71e2b0523bc2 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -1647,6 +1647,7 @@ static struct usb_driver asix_driver = {
.resume = usbnet_resume,
.disconnect = usbnet_disconnect,
.supports_autosuspend = 1,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(asix_driver);
diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c
index 182cfb4aeb1d..26c5bebd9eca 100644
--- a/drivers/net/usb/catc.c
+++ b/drivers/net/usb/catc.c
@@ -338,16 +338,18 @@ static void catc_irq_done(struct urb *urb)
} else {
catc->rx_urb->dev = catc->usbdev;
if ((res = usb_submit_urb(catc->rx_urb, GFP_ATOMIC)) < 0) {
- err("submit(rx_urb) status %d", res);
+ dev_err(&catc->usbdev->dev,
+ "submit(rx_urb) status %d\n", res);
}
}
}
resubmit:
res = usb_submit_urb (urb, GFP_ATOMIC);
if (res)
- err ("can't resubmit intr, %s-%s, status %d",
- catc->usbdev->bus->bus_name,
- catc->usbdev->devpath, res);
+ dev_err(&catc->usbdev->dev,
+ "can't resubmit intr, %s-%s, status %d\n",
+ catc->usbdev->bus->bus_name,
+ catc->usbdev->devpath, res);
}
/*
@@ -366,7 +368,8 @@ static int catc_tx_run(struct catc *catc)
catc->tx_urb->dev = catc->usbdev;
if ((status = usb_submit_urb(catc->tx_urb, GFP_ATOMIC)) < 0)
- err("submit(tx_urb), status %d", status);
+ dev_err(&catc->usbdev->dev, "submit(tx_urb), status %d\n",
+ status);
catc->tx_idx = !catc->tx_idx;
catc->tx_ptr = 0;
@@ -496,7 +499,8 @@ static void catc_ctrl_run(struct catc *catc)
memcpy(catc->ctrl_buf, q->buf, q->len);
if ((status = usb_submit_urb(catc->ctrl_urb, GFP_ATOMIC)))
- err("submit(ctrl_urb) status %d", status);
+ dev_err(&catc->usbdev->dev, "submit(ctrl_urb) status %d\n",
+ status);
}
static void catc_ctrl_done(struct urb *urb)
@@ -555,7 +559,7 @@ static int catc_ctrl_async(struct catc *catc, u8 dir, u8 request, u16 value,
catc->ctrl_head = (catc->ctrl_head + 1) & (CTRL_QUEUE - 1);
if (catc->ctrl_head == catc->ctrl_tail) {
- err("ctrl queue full");
+ dev_err(&catc->usbdev->dev, "ctrl queue full\n");
catc->ctrl_tail = (catc->ctrl_tail + 1) & (CTRL_QUEUE - 1);
retval = -1;
}
@@ -714,7 +718,8 @@ static int catc_open(struct net_device *netdev)
catc->irq_urb->dev = catc->usbdev;
if ((status = usb_submit_urb(catc->irq_urb, GFP_KERNEL)) < 0) {
- err("submit(irq_urb) status %d", status);
+ dev_err(&catc->usbdev->dev, "submit(irq_urb) status %d\n",
+ status);
return -1;
}
@@ -769,7 +774,7 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
if (usb_set_interface(usbdev,
intf->altsetting->desc.bInterfaceNumber, 1)) {
- err("Can't set altsetting 1.");
+ dev_err(&intf->dev, "Can't set altsetting 1.\n");
return -EIO;
}
@@ -799,7 +804,7 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
catc->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
if ((!catc->ctrl_urb) || (!catc->tx_urb) ||
(!catc->rx_urb) || (!catc->irq_urb)) {
- err("No free urbs available.");
+ dev_err(&intf->dev, "No free urbs available.\n");
usb_free_urb(catc->ctrl_urb);
usb_free_urb(catc->tx_urb);
usb_free_urb(catc->rx_urb);
@@ -947,6 +952,7 @@ static struct usb_driver catc_driver = {
.probe = catc_probe,
.disconnect = catc_disconnect,
.id_table = catc_id_table,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(catc_driver);
diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c
index 3e41b00c6806..d848d4dd5754 100644
--- a/drivers/net/usb/cdc-phonet.c
+++ b/drivers/net/usb/cdc-phonet.c
@@ -457,6 +457,7 @@ static struct usb_driver usbpn_driver = {
.probe = usbpn_probe,
.disconnect = usbpn_disconnect,
.id_table = usbpn_ids,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(usbpn_driver);
diff --git a/drivers/net/usb/cdc_eem.c b/drivers/net/usb/cdc_eem.c
index 685a4e22c768..434d5af8e6fb 100644
--- a/drivers/net/usb/cdc_eem.c
+++ b/drivers/net/usb/cdc_eem.c
@@ -368,6 +368,7 @@ static struct usb_driver eem_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(eem_driver);
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index fffee6aee8bb..a03de7197049 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -705,6 +705,7 @@ static struct usb_driver cdc_driver = {
.resume = usbnet_resume,
.reset_resume = usbnet_resume,
.supports_autosuspend = 1,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(cdc_driver);
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 7adc9f6b0ea1..4b9513fcf275 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -1212,6 +1212,7 @@ static struct usb_driver cdc_ncm_driver = {
.resume = usbnet_resume,
.reset_resume = usbnet_resume,
.supports_autosuspend = 1,
+ .disable_hub_initiated_lpm = 1,
};
static const struct ethtool_ops cdc_ncm_ethtool_ops = {
diff --git a/drivers/net/usb/cdc_subset.c b/drivers/net/usb/cdc_subset.c
index b403d934e4e3..0d1fe89ae0bd 100644
--- a/drivers/net/usb/cdc_subset.c
+++ b/drivers/net/usb/cdc_subset.c
@@ -336,6 +336,7 @@ static struct usb_driver cdc_subset_driver = {
.resume = usbnet_resume,
.disconnect = usbnet_disconnect,
.id_table = products,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(cdc_subset_driver);
diff --git a/drivers/net/usb/cx82310_eth.c b/drivers/net/usb/cx82310_eth.c
index 0e0531356e62..49ab45e17fe8 100644
--- a/drivers/net/usb/cx82310_eth.c
+++ b/drivers/net/usb/cx82310_eth.c
@@ -327,6 +327,7 @@ static struct usb_driver cx82310_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(cx82310_driver);
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
index b97226318ea5..e0433ce6ced7 100644
--- a/drivers/net/usb/dm9601.c
+++ b/drivers/net/usb/dm9601.c
@@ -670,6 +670,7 @@ static struct usb_driver dm9601_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(dm9601_driver);
diff --git a/drivers/net/usb/gl620a.c b/drivers/net/usb/gl620a.c
index 38266bdae26b..db3c8021f2a3 100644
--- a/drivers/net/usb/gl620a.c
+++ b/drivers/net/usb/gl620a.c
@@ -225,6 +225,7 @@ static struct usb_driver gl620a_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(gl620a_driver);
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 2d2a6882ba33..62f30b46fa42 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -106,13 +106,6 @@
#define MAX_RX_URBS 2
-static inline struct hso_serial *get_serial_by_tty(struct tty_struct *tty)
-{
- if (tty)
- return tty->driver_data;
- return NULL;
-}
-
/*****************************************************************************/
/* Debugging functions */
/*****************************************************************************/
@@ -255,9 +248,8 @@ struct hso_serial {
u8 dtr_state;
unsigned tx_urb_used:1;
+ struct tty_port port;
/* from usb_serial_port */
- struct tty_struct *tty;
- int open_count;
spinlock_t serial_lock;
int (*write_data) (struct hso_serial *serial);
@@ -1114,7 +1106,7 @@ static void hso_init_termios(struct ktermios *termios)
static void _hso_serial_set_termios(struct tty_struct *tty,
struct ktermios *old)
{
- struct hso_serial *serial = get_serial_by_tty(tty);
+ struct hso_serial *serial = tty->driver_data;
struct ktermios *termios;
if (!serial) {
@@ -1190,7 +1182,7 @@ static void put_rxbuf_data_and_resubmit_ctrl_urb(struct hso_serial *serial)
struct urb *urb;
urb = serial->rx_urb[0];
- if (serial->open_count > 0) {
+ if (serial->port.count > 0) {
count = put_rxbuf_data(urb, serial);
if (count == -1)
return;
@@ -1226,7 +1218,7 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb)
DUMP1(urb->transfer_buffer, urb->actual_length);
/* Anyone listening? */
- if (serial->open_count == 0)
+ if (serial->port.count == 0)
return;
if (status == 0) {
@@ -1268,7 +1260,7 @@ static void hso_unthrottle_tasklet(struct hso_serial *serial)
static void hso_unthrottle(struct tty_struct *tty)
{
- struct hso_serial *serial = get_serial_by_tty(tty);
+ struct hso_serial *serial = tty->driver_data;
tasklet_hi_schedule(&serial->unthrottle_tasklet);
}
@@ -1304,15 +1296,12 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)
kref_get(&serial->parent->ref);
/* setup */
- spin_lock_irq(&serial->serial_lock);
tty->driver_data = serial;
- tty_kref_put(serial->tty);
- serial->tty = tty_kref_get(tty);
- spin_unlock_irq(&serial->serial_lock);
+ tty_port_tty_set(&serial->port, tty);
/* check for port already opened, if not set the termios */
- serial->open_count++;
- if (serial->open_count == 1) {
+ serial->port.count++;
+ if (serial->port.count == 1) {
serial->rx_state = RX_IDLE;
/* Force default termio settings */
_hso_serial_set_termios(tty, NULL);
@@ -1324,7 +1313,7 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)
result = hso_start_serial_device(serial->parent, GFP_KERNEL);
if (result) {
hso_stop_serial_device(serial->parent);
- serial->open_count--;
+ serial->port.count--;
kref_put(&serial->parent->ref, hso_serial_ref_free);
}
} else {
@@ -1361,17 +1350,11 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)
/* reset the rts and dtr */
/* do the actual close */
- serial->open_count--;
+ serial->port.count--;
- if (serial->open_count <= 0) {
- serial->open_count = 0;
- spin_lock_irq(&serial->serial_lock);
- if (serial->tty == tty) {
- serial->tty->driver_data = NULL;
- serial->tty = NULL;
- tty_kref_put(tty);
- }
- spin_unlock_irq(&serial->serial_lock);
+ if (serial->port.count <= 0) {
+ serial->port.count = 0;
+ tty_port_tty_set(&serial->port, NULL);
if (!usb_gone)
hso_stop_serial_device(serial->parent);
tasklet_kill(&serial->unthrottle_tasklet);
@@ -1390,7 +1373,7 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)
static int hso_serial_write(struct tty_struct *tty, const unsigned char *buf,
int count)
{
- struct hso_serial *serial = get_serial_by_tty(tty);
+ struct hso_serial *serial = tty->driver_data;
int space, tx_bytes;
unsigned long flags;
@@ -1422,7 +1405,7 @@ out:
/* how much room is there for writing */
static int hso_serial_write_room(struct tty_struct *tty)
{
- struct hso_serial *serial = get_serial_by_tty(tty);
+ struct hso_serial *serial = tty->driver_data;
int room;
unsigned long flags;
@@ -1437,7 +1420,7 @@ static int hso_serial_write_room(struct tty_struct *tty)
/* setup the term */
static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
{
- struct hso_serial *serial = get_serial_by_tty(tty);
+ struct hso_serial *serial = tty->driver_data;
unsigned long flags;
if (old)
@@ -1446,7 +1429,7 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
/* the actual setup */
spin_lock_irqsave(&serial->serial_lock, flags);
- if (serial->open_count)
+ if (serial->port.count)
_hso_serial_set_termios(tty, old);
else
tty->termios = old;
@@ -1458,7 +1441,7 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
/* how many characters in the buffer */
static int hso_serial_chars_in_buffer(struct tty_struct *tty)
{
- struct hso_serial *serial = get_serial_by_tty(tty);
+ struct hso_serial *serial = tty->driver_data;
int chars;
unsigned long flags;
@@ -1629,7 +1612,7 @@ static int hso_get_count(struct tty_struct *tty,
struct serial_icounter_struct *icount)
{
struct uart_icount cnow;
- struct hso_serial *serial = get_serial_by_tty(tty);
+ struct hso_serial *serial = tty->driver_data;
struct hso_tiocmget *tiocmget = serial->tiocmget;
memset(icount, 0, sizeof(struct serial_icounter_struct));
@@ -1659,7 +1642,7 @@ static int hso_get_count(struct tty_struct *tty,
static int hso_serial_tiocmget(struct tty_struct *tty)
{
int retval;
- struct hso_serial *serial = get_serial_by_tty(tty);
+ struct hso_serial *serial = tty->driver_data;
struct hso_tiocmget *tiocmget;
u16 UART_state_bitmap;
@@ -1693,7 +1676,7 @@ static int hso_serial_tiocmset(struct tty_struct *tty,
int val = 0;
unsigned long flags;
int if_num;
- struct hso_serial *serial = get_serial_by_tty(tty);
+ struct hso_serial *serial = tty->driver_data;
/* sanity check */
if (!serial) {
@@ -1733,7 +1716,7 @@ static int hso_serial_tiocmset(struct tty_struct *tty,
static int hso_serial_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
- struct hso_serial *serial = get_serial_by_tty(tty);
+ struct hso_serial *serial = tty->driver_data;
int ret = 0;
D4("IOCTL cmd: %d, arg: %ld", cmd, arg);
@@ -1905,7 +1888,7 @@ static void intr_callback(struct urb *urb)
D1("Pending read interrupt on port %d\n", i);
spin_lock(&serial->serial_lock);
if (serial->rx_state == RX_IDLE &&
- serial->open_count > 0) {
+ serial->port.count > 0) {
/* Setup and send a ctrl req read on
* port i */
if (!serial->rx_urb_filled[0]) {
@@ -1954,14 +1937,13 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
spin_lock(&serial->serial_lock);
serial->tx_urb_used = 0;
- tty = tty_kref_get(serial->tty);
spin_unlock(&serial->serial_lock);
if (status) {
handle_usb_error(status, __func__, serial->parent);
- tty_kref_put(tty);
return;
}
hso_put_activity(serial->parent);
+ tty = tty_port_tty_get(&serial->port);
if (tty) {
tty_wakeup(tty);
tty_kref_put(tty);
@@ -2001,7 +1983,6 @@ static void ctrl_callback(struct urb *urb)
struct hso_serial *serial = urb->context;
struct usb_ctrlrequest *req;
int status = urb->status;
- struct tty_struct *tty;
/* sanity check */
if (!serial)
@@ -2009,11 +1990,9 @@ static void ctrl_callback(struct urb *urb)
spin_lock(&serial->serial_lock);
serial->tx_urb_used = 0;
- tty = tty_kref_get(serial->tty);
spin_unlock(&serial->serial_lock);
if (status) {
handle_usb_error(status, __func__, serial->parent);
- tty_kref_put(tty);
return;
}
@@ -2031,13 +2010,15 @@ static void ctrl_callback(struct urb *urb)
put_rxbuf_data_and_resubmit_ctrl_urb(serial);
spin_unlock(&serial->serial_lock);
} else {
+ struct tty_struct *tty = tty_port_tty_get(&serial->port);
hso_put_activity(serial->parent);
- if (tty)
+ if (tty) {
tty_wakeup(tty);
+ tty_kref_put(tty);
+ }
/* response to a write command */
hso_kick_transmit(serial);
}
- tty_kref_put(tty);
}
/* handle RX data for serial port */
@@ -2053,8 +2034,7 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
return -2;
}
- /* All callers to put_rxbuf_data hold serial_lock */
- tty = tty_kref_get(serial->tty);
+ tty = tty_port_tty_get(&serial->port);
/* Push data to tty */
if (tty) {
@@ -2074,12 +2054,12 @@ static int put_rxbuf_data(struct urb *urb, struct hso_serial *serial)
write_length_remaining -= curr_write_len;
tty_flip_buffer_push(tty);
}
+ tty_kref_put(tty);
}
if (write_length_remaining == 0) {
serial->curr_rx_urb_offset = 0;
serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;
}
- tty_kref_put(tty);
return write_length_remaining;
}
@@ -2320,6 +2300,7 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
serial->minor = minor;
serial->magic = HSO_SERIAL_MAGIC;
spin_lock_init(&serial->serial_lock);
+ tty_port_init(&serial->port);
serial->num_rx_urbs = num_urbs;
/* RX, allocate urb and initialize */
@@ -3098,7 +3079,7 @@ static int hso_resume(struct usb_interface *iface)
/* Start all serial ports */
for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
if (serial_table[i] && (serial_table[i]->interface == iface)) {
- if (dev2ser(serial_table[i])->open_count) {
+ if (dev2ser(serial_table[i])->port.count) {
result =
hso_start_serial_device(serial_table[i], GFP_NOIO);
hso_kick_transmit(dev2ser(serial_table[i]));
@@ -3172,13 +3153,12 @@ static void hso_free_interface(struct usb_interface *interface)
if (serial_table[i] &&
(serial_table[i]->interface == interface)) {
hso_dev = dev2ser(serial_table[i]);
- spin_lock_irq(&hso_dev->serial_lock);
- tty = tty_kref_get(hso_dev->tty);
- spin_unlock_irq(&hso_dev->serial_lock);
- if (tty)
+ tty = tty_port_tty_get(&hso_dev->port);
+ if (tty) {
tty_hangup(tty);
+ tty_kref_put(tty);
+ }
mutex_lock(&hso_dev->parent->mutex);
- tty_kref_put(tty);
hso_dev->parent->usb_gone = 1;
mutex_unlock(&hso_dev->parent->mutex);
kref_put(&serial_table[i]->ref, hso_serial_ref_free);
@@ -3291,6 +3271,7 @@ static struct usb_driver hso_driver = {
.resume = hso_resume,
.reset_resume = hso_resume,
.supports_autosuspend = 1,
+ .disable_hub_initiated_lpm = 1,
};
static int __init hso_init(void)
@@ -3312,7 +3293,6 @@ static int __init hso_init(void)
return -ENOMEM;
/* fill in all needed values */
- tty_drv->magic = TTY_DRIVER_MAGIC;
tty_drv->driver_name = driver_name;
tty_drv->name = tty_filename;
@@ -3333,7 +3313,7 @@ static int __init hso_init(void)
if (result) {
printk(KERN_ERR "%s - tty_register_driver failed(%d)\n",
__func__, result);
- return result;
+ goto err_free_tty;
}
/* register this module as an usb driver */
@@ -3341,13 +3321,16 @@ static int __init hso_init(void)
if (result) {
printk(KERN_ERR "Could not register hso driver? error: %d\n",
result);
- /* cleanup serial interface */
- tty_unregister_driver(tty_drv);
- return result;
+ goto err_unreg_tty;
}
/* done */
return 0;
+err_unreg_tty:
+ tty_unregister_driver(tty_drv);
+err_free_tty:
+ put_tty_driver(tty_drv);
+ return result;
}
static void __exit hso_exit(void)
@@ -3355,6 +3338,7 @@ static void __exit hso_exit(void)
printk(KERN_INFO "hso: unloaded\n");
tty_unregister_driver(tty_drv);
+ put_tty_driver(tty_drv);
/* deregister the usb driver */
usb_deregister(&hso_driver);
}
diff --git a/drivers/net/usb/int51x1.c b/drivers/net/usb/int51x1.c
index 12a22a453ff1..8de641713d5f 100644
--- a/drivers/net/usb/int51x1.c
+++ b/drivers/net/usb/int51x1.c
@@ -236,6 +236,7 @@ static struct usb_driver int51x1_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(int51x1_driver);
diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c
index dd78c4cbd459..964031e3da87 100644
--- a/drivers/net/usb/ipheth.c
+++ b/drivers/net/usb/ipheth.c
@@ -209,7 +209,8 @@ static void ipheth_rcvbulk_callback(struct urb *urb)
case 0:
break;
default:
- err("%s: urb status: %d", __func__, status);
+ dev_err(&dev->intf->dev, "%s: urb status: %d\n",
+ __func__, status);
return;
}
@@ -222,7 +223,8 @@ static void ipheth_rcvbulk_callback(struct urb *urb)
skb = dev_alloc_skb(len);
if (!skb) {
- err("%s: dev_alloc_skb: -ENOMEM", __func__);
+ dev_err(&dev->intf->dev, "%s: dev_alloc_skb: -ENOMEM\n",
+ __func__);
dev->net->stats.rx_dropped++;
return;
}
@@ -251,7 +253,8 @@ static void ipheth_sndbulk_callback(struct urb *urb)
status != -ENOENT &&
status != -ECONNRESET &&
status != -ESHUTDOWN)
- err("%s: urb status: %d", __func__, status);
+ dev_err(&dev->intf->dev, "%s: urb status: %d\n",
+ __func__, status);
dev_kfree_skb_irq(dev->tx_skb);
netif_wake_queue(dev->net);
@@ -271,7 +274,8 @@ static int ipheth_carrier_set(struct ipheth_device *dev)
dev->ctrl_buf, IPHETH_CTRL_BUF_SIZE,
IPHETH_CTRL_TIMEOUT);
if (retval < 0) {
- err("%s: usb_control_msg: %d", __func__, retval);
+ dev_err(&dev->intf->dev, "%s: usb_control_msg: %d\n",
+ __func__, retval);
return retval;
}
@@ -308,9 +312,11 @@ static int ipheth_get_macaddr(struct ipheth_device *dev)
IPHETH_CTRL_BUF_SIZE,
IPHETH_CTRL_TIMEOUT);
if (retval < 0) {
- err("%s: usb_control_msg: %d", __func__, retval);
+ dev_err(&dev->intf->dev, "%s: usb_control_msg: %d\n",
+ __func__, retval);
} else if (retval < ETH_ALEN) {
- err("%s: usb_control_msg: short packet: %d bytes",
+ dev_err(&dev->intf->dev,
+ "%s: usb_control_msg: short packet: %d bytes\n",
__func__, retval);
retval = -EINVAL;
} else {
@@ -335,7 +341,8 @@ static int ipheth_rx_submit(struct ipheth_device *dev, gfp_t mem_flags)
retval = usb_submit_urb(dev->rx_urb, mem_flags);
if (retval)
- err("%s: usb_submit_urb: %d", __func__, retval);
+ dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n",
+ __func__, retval);
return retval;
}
@@ -396,7 +403,8 @@ static int ipheth_tx(struct sk_buff *skb, struct net_device *net)
retval = usb_submit_urb(dev->tx_urb, GFP_ATOMIC);
if (retval) {
- err("%s: usb_submit_urb: %d", __func__, retval);
+ dev_err(&dev->intf->dev, "%s: usb_submit_urb: %d\n",
+ __func__, retval);
dev->net->stats.tx_errors++;
dev_kfree_skb_irq(skb);
} else {
@@ -414,7 +422,7 @@ static void ipheth_tx_timeout(struct net_device *net)
{
struct ipheth_device *dev = netdev_priv(net);
- err("%s: TX timeout", __func__);
+ dev_err(&dev->intf->dev, "%s: TX timeout\n", __func__);
dev->net->stats.tx_errors++;
usb_unlink_urb(dev->tx_urb);
}
@@ -464,7 +472,7 @@ static int ipheth_probe(struct usb_interface *intf,
hintf = usb_altnum_to_altsetting(intf, IPHETH_ALT_INTFNUM);
if (hintf == NULL) {
retval = -ENODEV;
- err("Unable to find alternate settings interface");
+ dev_err(&intf->dev, "Unable to find alternate settings interface\n");
goto err_endpoints;
}
@@ -477,7 +485,7 @@ static int ipheth_probe(struct usb_interface *intf,
}
if (!(dev->bulk_in && dev->bulk_out)) {
retval = -ENODEV;
- err("Unable to find endpoints");
+ dev_err(&intf->dev, "Unable to find endpoints\n");
goto err_endpoints;
}
@@ -495,7 +503,7 @@ static int ipheth_probe(struct usb_interface *intf,
retval = ipheth_alloc_urbs(dev);
if (retval) {
- err("error allocating urbs: %d", retval);
+ dev_err(&intf->dev, "error allocating urbs: %d\n", retval);
goto err_alloc_urbs;
}
@@ -506,7 +514,7 @@ static int ipheth_probe(struct usb_interface *intf,
retval = register_netdev(netdev);
if (retval) {
- err("error registering netdev: %d", retval);
+ dev_err(&intf->dev, "error registering netdev: %d\n", retval);
retval = -EIO;
goto err_register_netdev;
}
@@ -546,6 +554,7 @@ static struct usb_driver ipheth_driver = {
.probe = ipheth_probe,
.disconnect = ipheth_disconnect,
.id_table = ipheth_table,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(ipheth_driver);
diff --git a/drivers/net/usb/kalmia.c b/drivers/net/usb/kalmia.c
index 7562649b3d6b..92c49e0a59ec 100644
--- a/drivers/net/usb/kalmia.c
+++ b/drivers/net/usb/kalmia.c
@@ -372,7 +372,8 @@ static struct usb_driver kalmia_driver = {
.probe = usbnet_probe,
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
- .resume = usbnet_resume
+ .resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(kalmia_driver);
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index df2a2cf35a99..d8ad55284389 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -179,6 +179,7 @@ static struct usb_driver kaweth_driver = {
.resume = kaweth_resume,
.id_table = usb_klsi_table,
.supports_autosuspend = 1,
+ .disable_hub_initiated_lpm = 1,
};
typedef __u8 eth_addr_t[6];
@@ -400,12 +401,13 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth,
ret = request_firmware(&fw, fwname, &kaweth->dev->dev);
if (ret) {
- err("Firmware request failed\n");
+ dev_err(&kaweth->intf->dev, "Firmware request failed\n");
return ret;
}
if (fw->size > KAWETH_FIRMWARE_BUF_SIZE) {
- err("Firmware too big: %zu", fw->size);
+ dev_err(&kaweth->intf->dev, "Firmware too big: %zu\n",
+ fw->size);
release_firmware(fw);
return -ENOSPC;
}
@@ -501,9 +503,10 @@ static void kaweth_resubmit_int_urb(struct kaweth_device *kaweth, gfp_t mf)
}
if (status)
- err ("can't resubmit intr, %s-%s, status %d",
- kaweth->dev->bus->bus_name,
- kaweth->dev->devpath, status);
+ dev_err(&kaweth->intf->dev,
+ "can't resubmit intr, %s-%s, status %d\n",
+ kaweth->dev->bus->bus_name,
+ kaweth->dev->devpath, status);
}
static void int_callback(struct urb *u)
@@ -576,7 +579,8 @@ static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth,
kaweth->suspend_lowmem_rx = 1;
schedule_delayed_work(&kaweth->lowmem_work, HZ/4);
}
- err("resubmitting rx_urb %d failed", result);
+ dev_err(&kaweth->intf->dev, "resubmitting rx_urb %d failed\n",
+ result);
} else {
kaweth->suspend_lowmem_rx = 0;
}
@@ -634,20 +638,21 @@ static void kaweth_usb_receive(struct urb *urb)
spin_unlock(&kaweth->device_lock);
if(status && status != -EREMOTEIO && count != 1) {
- err("%s RX status: %d count: %d packet_len: %d",
- net->name,
- status,
- count,
- (int)pkt_len);
+ dev_err(&kaweth->intf->dev,
+ "%s RX status: %d count: %d packet_len: %d\n",
+ net->name, status, count, (int)pkt_len);
kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
return;
}
if(kaweth->net && (count > 2)) {
if(pkt_len > (count - 2)) {
- err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count);
- err("Packet len & 2047: %x", pkt_len & 2047);
- err("Count 2: %x", count2);
+ dev_err(&kaweth->intf->dev,
+ "Packet length too long for USB frame (pkt_len: %x, count: %x)\n",
+ pkt_len, count);
+ dev_err(&kaweth->intf->dev, "Packet len & 2047: %x\n",
+ pkt_len & 2047);
+ dev_err(&kaweth->intf->dev, "Count 2: %x\n", count2);
kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
return;
}
@@ -686,7 +691,7 @@ static int kaweth_open(struct net_device *net)
res = usb_autopm_get_interface(kaweth->intf);
if (res) {
- err("Interface cannot be resumed.");
+ dev_err(&kaweth->intf->dev, "Interface cannot be resumed.\n");
return -EIO;
}
res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
@@ -907,7 +912,8 @@ static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth)
KAWETH_CONTROL_TIMEOUT);
if(result < 0) {
- err("Failed to set Rx mode: %d", result);
+ dev_err(&kaweth->intf->dev, "Failed to set Rx mode: %d\n",
+ result);
}
else {
dbg("Set Rx mode to %d", packet_filter_bitmap);
@@ -1045,7 +1051,8 @@ static int kaweth_probe(
"kaweth/new_code.bin",
100,
2)) < 0) {
- err("Error downloading firmware (%d)", result);
+ dev_err(&intf->dev, "Error downloading firmware (%d)\n",
+ result);
goto err_fw;
}
@@ -1053,7 +1060,9 @@ static int kaweth_probe(
"kaweth/new_code_fix.bin",
100,
3)) < 0) {
- err("Error downloading firmware fix (%d)", result);
+ dev_err(&intf->dev,
+ "Error downloading firmware fix (%d)\n",
+ result);
goto err_fw;
}
@@ -1061,7 +1070,9 @@ static int kaweth_probe(
"kaweth/trigger_code.bin",
126,
2)) < 0) {
- err("Error downloading trigger code (%d)", result);
+ dev_err(&intf->dev,
+ "Error downloading trigger code (%d)\n",
+ result);
goto err_fw;
}
@@ -1070,13 +1081,14 @@ static int kaweth_probe(
"kaweth/trigger_code_fix.bin",
126,
3)) < 0) {
- err("Error downloading trigger code fix (%d)", result);
+ dev_err(&intf->dev, "Error downloading trigger code fix (%d)\n", result);
goto err_fw;
}
if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) {
- err("Error triggering firmware (%d)", result);
+ dev_err(&intf->dev, "Error triggering firmware (%d)\n",
+ result);
goto err_fw;
}
@@ -1091,7 +1103,7 @@ err_fw:
result = kaweth_read_configuration(kaweth);
if(result < 0) {
- err("Error reading configuration (%d), no net device created", result);
+ dev_err(&intf->dev, "Error reading configuration (%d), no net device created\n", result);
goto err_free_netdev;
}
@@ -1103,7 +1115,7 @@ err_fw:
if(!memcmp(&kaweth->configuration.hw_addr,
&bcast_addr,
sizeof(bcast_addr))) {
- err("Firmware not functioning properly, no net device created");
+ dev_err(&intf->dev, "Firmware not functioning properly, no net device created\n");
goto err_free_netdev;
}
@@ -1113,7 +1125,7 @@ err_fw:
}
if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) {
- err("Error setting SOFS wait");
+ dev_err(&intf->dev, "Error setting SOFS wait\n");
goto err_free_netdev;
}
@@ -1123,7 +1135,7 @@ err_fw:
KAWETH_PACKET_FILTER_MULTICAST);
if(result < 0) {
- err("Error setting receive filter");
+ dev_err(&intf->dev, "Error setting receive filter\n");
goto err_free_netdev;
}
@@ -1175,7 +1187,7 @@ err_fw:
SET_NETDEV_DEV(netdev, &intf->dev);
if (register_netdev(netdev) != 0) {
- err("Error registering netdev.");
+ dev_err(&intf->dev, "Error registering netdev.\n");
goto err_intfdata;
}
diff --git a/drivers/net/usb/lg-vl600.c b/drivers/net/usb/lg-vl600.c
index 45a981fde43f..808d6506da41 100644
--- a/drivers/net/usb/lg-vl600.c
+++ b/drivers/net/usb/lg-vl600.c
@@ -344,6 +344,7 @@ static struct usb_driver lg_vl600_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(lg_vl600_driver);
diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c
index c434b6ba0337..add1064f755d 100644
--- a/drivers/net/usb/mcs7830.c
+++ b/drivers/net/usb/mcs7830.c
@@ -690,6 +690,7 @@ static struct usb_driver mcs7830_driver = {
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.reset_resume = mcs7830_reset_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(mcs7830_driver);
diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c
index 83f965cb69e7..28c4d513ba85 100644
--- a/drivers/net/usb/net1080.c
+++ b/drivers/net/usb/net1080.c
@@ -587,6 +587,7 @@ static struct usb_driver net1080_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(net1080_driver);
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index 752393092325..7023220456c5 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -1489,6 +1489,7 @@ static struct usb_driver pegasus_driver = {
.id_table = pegasus_ids,
.suspend = pegasus_suspend,
.resume = pegasus_resume,
+ .disable_hub_initiated_lpm = 1,
};
static void __init parse_id(char *id)
diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c
index b2b035e29978..4584b9a805b3 100644
--- a/drivers/net/usb/plusb.c
+++ b/drivers/net/usb/plusb.c
@@ -152,6 +152,7 @@ static struct usb_driver plusb_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(plusb_driver);
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 63cfd0b2c31a..380dbea6109d 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -560,6 +560,7 @@ static struct usb_driver qmi_wwan_driver = {
.resume = qmi_wwan_resume,
.reset_resume = qmi_wwan_resume,
.supports_autosuspend = 1,
+ .disable_hub_initiated_lpm = 1,
};
static int __init qmi_wwan_init(void)
diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
index 0d746b3fdef1..4a4335833c36 100644
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -638,6 +638,7 @@ static struct usb_driver rndis_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(rndis_driver);
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index d363b31053da..0e2c92e0e532 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -203,7 +203,8 @@ static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size)
if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC))) {
if (ret == -ENODEV)
netif_device_detach(dev->netdev);
- err("control request submission failed: %d", ret);
+ dev_err(&dev->udev->dev,
+ "control request submission failed: %d\n", ret);
} else
set_bit(RX_REG_SET, &dev->flags);
@@ -516,9 +517,9 @@ resubmit:
if (res == -ENODEV)
netif_device_detach(dev->netdev);
else if (res)
- err ("can't resubmit intr, %s-%s/input0, status %d",
- dev->udev->bus->bus_name,
- dev->udev->devpath, res);
+ dev_err(&dev->udev->dev,
+ "can't resubmit intr, %s-%s/input0, status %d\n",
+ dev->udev->bus->bus_name, dev->udev->devpath, res);
}
static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message)
@@ -890,11 +891,11 @@ static int rtl8150_probe(struct usb_interface *intf,
dev->intr_interval = 100; /* 100ms */
if (!alloc_all_urbs(dev)) {
- err("out of memory");
+ dev_err(&intf->dev, "out of memory\n");
goto out;
}
if (!rtl8150_reset(dev)) {
- err("couldn't reset the device");
+ dev_err(&intf->dev, "couldn't reset the device\n");
goto out1;
}
fill_skb_pool(dev);
@@ -903,7 +904,7 @@ static int rtl8150_probe(struct usb_interface *intf,
usb_set_intfdata(intf, dev);
SET_NETDEV_DEV(netdev, &intf->dev);
if (register_netdev(netdev) != 0) {
- err("couldn't register the device");
+ dev_err(&intf->dev, "couldn't register the device\n");
goto out2;
}
@@ -947,7 +948,8 @@ static struct usb_driver rtl8150_driver = {
.disconnect = rtl8150_disconnect,
.id_table = rtl8150_table,
.suspend = rtl8150_suspend,
- .resume = rtl8150_resume
+ .resume = rtl8150_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(rtl8150_driver);
diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c
index b59cf20c7817..3faef5670d1f 100644
--- a/drivers/net/usb/sierra_net.c
+++ b/drivers/net/usb/sierra_net.c
@@ -982,6 +982,7 @@ static struct usb_driver sierra_net_driver = {
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.no_dynamic_id = 1,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(sierra_net_driver);
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index fb1a087b101d..1c6e51588da7 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -1254,6 +1254,7 @@ static struct usb_driver smsc75xx_driver = {
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.disconnect = usbnet_disconnect,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(smsc75xx_driver);
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 94ae66999f59..b1112e753859 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -1297,6 +1297,7 @@ static struct usb_driver smsc95xx_driver = {
.suspend = usbnet_suspend,
.resume = usbnet_resume,
.disconnect = usbnet_disconnect,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(smsc95xx_driver);
diff --git a/drivers/net/usb/zaurus.c b/drivers/net/usb/zaurus.c
index 34db195fb8b0..35c90307d473 100644
--- a/drivers/net/usb/zaurus.c
+++ b/drivers/net/usb/zaurus.c
@@ -377,6 +377,7 @@ static struct usb_driver zaurus_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(zaurus_driver);
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index d70ede7a7f96..d58431e99f73 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -203,37 +203,6 @@ config WANXL_BUILD_FIRMWARE
You should never need this option, say N.
-config PC300
- tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)"
- depends on HDLC && PCI && BROKEN
- ---help---
- This driver is broken because of struct tty_driver change.
-
- Driver for the Cyclades-PC300 synchronous communication boards.
-
- These boards provide synchronous serial interfaces to your
- Linux box (interfaces currently available are RS-232/V.35, X.21 and
- T1/E1). If you wish to support Multilink PPP, please select the
- option later and read the file README.mlppp provided by PC300
- package.
-
- To compile this as a module, choose M here: the module
- will be called pc300.
-
- If unsure, say N.
-
-config PC300_MLPPP
- bool "Cyclades-PC300 MLPPP support"
- depends on PC300 && PPP_MULTILINK && PPP_SYNC_TTY && HDLC_PPP
- help
- Multilink PPP over the PC300 synchronous communication boards.
-
-comment "Cyclades-PC300 MLPPP support is disabled."
- depends on HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP)
-
-comment "Refer to the file README.mlppp, provided by PC300 package."
- depends on HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP)
-
config PC300TOO
tristate "Cyclades PC300 RSV/X21 alternative support"
depends on HDLC && PCI
diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
index 19d14bc28356..eac709bed7ae 100644
--- a/drivers/net/wan/Makefile
+++ b/drivers/net/wan/Makefile
@@ -17,10 +17,6 @@ obj-$(CONFIG_HDLC_FR) += hdlc_fr.o
obj-$(CONFIG_HDLC_PPP) += hdlc_ppp.o
obj-$(CONFIG_HDLC_X25) += hdlc_x25.o
-pc300-y := pc300_drv.o
-pc300-$(CONFIG_PC300_MLPPP) += pc300_tty.o
-pc300-objs := $(pc300-y)
-
obj-$(CONFIG_HOSTESS_SV11) += z85230.o hostess_sv11.o
obj-$(CONFIG_SEALEVEL_4021) += z85230.o sealevel.o
obj-$(CONFIG_COSA) += cosa.o
@@ -35,7 +31,6 @@ obj-$(CONFIG_SDLA) += sdla.o
obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o
obj-$(CONFIG_LAPBETHER) += lapbether.o
obj-$(CONFIG_SBNI) += sbni.o
-obj-$(CONFIG_PC300) += pc300.o
obj-$(CONFIG_N2) += n2.o
obj-$(CONFIG_C101) += c101.o
obj-$(CONFIG_WANXL) += wanxl.o
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 3df0146b797e..efc162e0b511 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -1955,7 +1955,7 @@ static int at76_hw_scan(struct ieee80211_hw *hw,
ret = at76_set_card_command(priv->udev, CMD_SCAN, &scan, sizeof(scan));
if (ret < 0) {
- err("CMD_SCAN failed: %d", ret);
+ wiphy_err(priv->hw->wiphy, "CMD_SCAN failed: %d\n", ret);
goto exit;
}
@@ -2486,6 +2486,7 @@ static struct usb_driver at76_driver = {
.probe = at76_probe,
.disconnect = at76_disconnect,
.id_table = dev_table,
+ .disable_hub_initiated_lpm = 1,
};
static int __init at76_mod_init(void)
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 28a65d3a03d0..b869a358ce43 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -693,8 +693,8 @@ ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
ie, 2 + vif->ssid_len + beacon_ie_len,
0, GFP_KERNEL);
if (bss)
- ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added bss %pM to "
- "cfg80211\n", bssid);
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+ "added bss %pM to cfg80211\n", bssid);
kfree(ie);
} else
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss\n");
@@ -882,6 +882,32 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
vif->sme_state = SME_DISCONNECTED;
}
+static int ath6kl_set_probed_ssids(struct ath6kl *ar,
+ struct ath6kl_vif *vif,
+ struct cfg80211_ssid *ssids, int n_ssids)
+{
+ u8 i;
+
+ if (n_ssids > MAX_PROBED_SSID_INDEX)
+ return -EINVAL;
+
+ for (i = 0; i < n_ssids; i++) {
+ ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i,
+ ssids[i].ssid_len ?
+ SPECIFIC_SSID_FLAG : ANY_SSID_FLAG,
+ ssids[i].ssid_len,
+ ssids[i].ssid);
+ }
+
+ /* Make sure no old entries are left behind */
+ for (i = n_ssids; i < MAX_PROBED_SSID_INDEX; i++) {
+ ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i,
+ DISABLE_SSID_FLAG, 0, NULL);
+ }
+
+ return 0;
+}
+
static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
struct cfg80211_scan_request *request)
{
@@ -899,36 +925,25 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
if (!ar->usr_bss_filter) {
clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
- ret = ath6kl_wmi_bssfilter_cmd(
- ar->wmi, vif->fw_vif_idx,
- (test_bit(CONNECTED, &vif->flags) ?
- ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
+ ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
+ ALL_BSS_FILTER, 0);
if (ret) {
ath6kl_err("couldn't set bss filtering\n");
return ret;
}
}
- if (request->n_ssids && request->ssids[0].ssid_len) {
- u8 i;
-
- if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
- request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
-
- for (i = 0; i < request->n_ssids; i++)
- ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
- i + 1, SPECIFIC_SSID_FLAG,
- request->ssids[i].ssid_len,
- request->ssids[i].ssid);
- }
+ ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
+ request->n_ssids);
+ if (ret < 0)
+ return ret;
/* this also clears IE in fw if it's not set */
ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
WMI_FRAME_PROBE_REQ,
request->ie, request->ie_len);
if (ret) {
- ath6kl_err("failed to set Probe Request appie for "
- "scan");
+ ath6kl_err("failed to set Probe Request appie for scan");
return ret;
}
@@ -945,8 +960,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
if (channels == NULL) {
- ath6kl_warn("failed to set scan channels, "
- "scan all channels");
+ ath6kl_warn("failed to set scan channels, scan all channels");
n_channels = 0;
}
@@ -1018,6 +1032,20 @@ out:
vif->scan_req = NULL;
}
+void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
+ enum wmi_phy_mode mode)
+{
+ enum nl80211_channel_type type;
+
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+ "channel switch notify nw_type %d freq %d mode %d\n",
+ vif->nw_type, freq, mode);
+
+ type = (mode == WMI_11G_HT20) ? NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT;
+
+ cfg80211_ch_switch_notify(vif->ndev, freq, type);
+}
+
static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
u8 key_index, bool pairwise,
const u8 *mac_addr,
@@ -1111,9 +1139,8 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
ar->ap_mode_bkey.key_len = key->key_len;
memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
if (!test_bit(CONNECTED, &vif->flags)) {
- ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
- "key configuration until AP mode has been "
- "started\n");
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+ "Delay initial group key configuration until AP mode has been started\n");
/*
* The key will be set in ath6kl_connect_ap_mode() once
* the connected event is received from the target.
@@ -1129,8 +1156,8 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
* the AP mode has properly started
* (ath6kl_install_statioc_wep_keys).
*/
- ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
- "until AP mode has been started\n");
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+ "Delay WEP key configuration until AP mode has been started\n");
vif->wep_key_list[key_index].key_len = key->key_len;
memcpy(vif->wep_key_list[key_index].key, key->key,
key->key_len);
@@ -1962,8 +1989,7 @@ static int ath6kl_wow_sta(struct ath6kl *ar, struct ath6kl_vif *vif)
sizeof(discvr_pattern), discvr_offset,
discvr_pattern, discvr_mask);
if (ret) {
- ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR "
- "pattern\n");
+ ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR pattern\n");
return ret;
}
}
@@ -2031,6 +2057,10 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
u8 index = 0;
__be32 ips[MAX_IP_ADDRS];
+ /* The FW currently can't support multi-vif WoW properly. */
+ if (ar->num_vif > 1)
+ return -EIO;
+
vif = ath6kl_vif_first(ar);
if (!vif)
return -EIO;
@@ -2044,6 +2074,13 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST))
return -EINVAL;
+ if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags)) {
+ ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi,
+ vif->fw_vif_idx, false);
+ if (ret)
+ return ret;
+ }
+
/* Clear existing WOW patterns */
for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++)
ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx,
@@ -2147,8 +2184,8 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_HOST_MODE_AWAKE);
if (ret) {
- ath6kl_warn("Failed to configure host sleep mode for "
- "wow resume: %d\n", ret);
+ ath6kl_warn("Failed to configure host sleep mode for wow resume: %d\n",
+ ret);
ar->state = ATH6KL_STATE_WOW;
return ret;
}
@@ -2172,6 +2209,13 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
ar->state = ATH6KL_STATE_ON;
+ if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags)) {
+ ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi,
+ vif->fw_vif_idx, true);
+ if (ret)
+ return ret;
+ }
+
netif_wake_queue(vif->ndev);
return 0;
@@ -2186,8 +2230,10 @@ static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar)
if (!vif)
return -EIO;
- if (!ath6kl_cfg80211_ready(vif))
+ if (!test_bit(WMI_READY, &ar->flag)) {
+ ath6kl_err("deepsleep failed as wmi is not ready\n");
return -EIO;
+ }
ath6kl_cfg80211_stop_all(ar);
@@ -2447,6 +2493,24 @@ static int ath6kl_set_htcap(struct ath6kl_vif *vif, enum ieee80211_band band,
band, htcap);
}
+static int ath6kl_restore_htcap(struct ath6kl_vif *vif)
+{
+ struct wiphy *wiphy = vif->ar->wiphy;
+ int band, ret = 0;
+
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ if (!wiphy->bands[band])
+ continue;
+
+ ret = ath6kl_set_htcap(vif, band,
+ wiphy->bands[band]->ht_cap.ht_supported);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
static bool ath6kl_is_p2p_ie(const u8 *pos)
{
return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
@@ -2568,28 +2632,34 @@ static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon,
/* skip element id and length */
rsn_ie += 2;
- /* skip version, group cipher */
- if (rsn_ie_len < 6)
+ /* skip version */
+ if (rsn_ie_len < 2)
return -EINVAL;
- rsn_ie += 6;
- rsn_ie_len -= 6;
+ rsn_ie += 2;
+ rsn_ie_len -= 2;
+
+ /* skip group cipher suite */
+ if (rsn_ie_len < 4)
+ return 0;
+ rsn_ie += 4;
+ rsn_ie_len -= 4;
/* skip pairwise cipher suite */
if (rsn_ie_len < 2)
- return -EINVAL;
- cnt = *((u16 *) rsn_ie);
+ return 0;
+ cnt = get_unaligned_le16(rsn_ie);
rsn_ie += (2 + cnt * 4);
rsn_ie_len -= (2 + cnt * 4);
/* skip akm suite */
if (rsn_ie_len < 2)
- return -EINVAL;
- cnt = *((u16 *) rsn_ie);
+ return 0;
+ cnt = get_unaligned_le16(rsn_ie);
rsn_ie += (2 + cnt * 4);
rsn_ie_len -= (2 + cnt * 4);
if (rsn_ie_len < 2)
- return -EINVAL;
+ return 0;
memcpy(rsn_capab, rsn_ie, 2);
@@ -2766,6 +2836,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
return res;
}
+ memcpy(&vif->profile, &p, sizeof(p));
res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
if (res < 0)
return res;
@@ -2801,13 +2872,7 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev)
clear_bit(CONNECTED, &vif->flags);
/* Restore ht setting in firmware */
- if (ath6kl_set_htcap(vif, IEEE80211_BAND_2GHZ, true))
- return -EIO;
-
- if (ath6kl_set_htcap(vif, IEEE80211_BAND_5GHZ, true))
- return -EIO;
-
- return 0;
+ return ath6kl_restore_htcap(vif);
}
static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@@ -3081,7 +3146,6 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
struct ath6kl_vif *vif = netdev_priv(dev);
u16 interval;
int ret;
- u8 i;
if (ar->state != ATH6KL_STATE_ON)
return -EIO;
@@ -3089,29 +3153,23 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
if (vif->sme_state != SME_DISCONNECTED)
return -EBUSY;
+ /* The FW currently can't support multi-vif WoW properly. */
+ if (ar->num_vif > 1)
+ return -EIO;
+
ath6kl_cfg80211_scan_complete_event(vif, true);
- for (i = 0; i < ar->wiphy->max_sched_scan_ssids; i++) {
- ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
- i, DISABLE_SSID_FLAG,
- 0, NULL);
- }
+ ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
+ request->n_ssids);
+ if (ret < 0)
+ return ret;
/* fw uses seconds, also make sure that it's >0 */
interval = max_t(u16, 1, request->interval / 1000);
ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
interval, interval,
- 10, 0, 0, 0, 3, 0, 0, 0);
-
- if (request->n_ssids && request->ssids[0].ssid_len) {
- for (i = 0; i < request->n_ssids; i++) {
- ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
- i, SPECIFIC_SSID_FLAG,
- request->ssids[i].ssid_len,
- request->ssids[i].ssid);
- }
- }
+ vif->bg_scan_period, 0, 0, 0, 3, 0, 0, 0);
ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_WOW_MODE_ENABLE,
@@ -3271,8 +3329,7 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
if (ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER) != 0)
- ath6kl_warn("ath6kl_deep_sleep_enable: "
- "wmi_powermode_cmd failed\n");
+ ath6kl_warn("ath6kl_deep_sleep_enable: wmi_powermode_cmd failed\n");
return;
}
@@ -3352,6 +3409,7 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
vif->next_mode = nw_type;
vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL;
vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME;
+ vif->bg_scan_period = 0;
vif->htcap.ht_enable = true;
memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
@@ -3393,6 +3451,7 @@ err:
int ath6kl_cfg80211_init(struct ath6kl *ar)
{
struct wiphy *wiphy = ar->wiphy;
+ bool band_2gig = false, band_5gig = false, ht = false;
int ret;
wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
@@ -3413,8 +3472,46 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
/* max num of ssids that can be probed during scanning */
wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
- wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
- wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
+ switch (ar->hw.cap) {
+ case WMI_11AN_CAP:
+ ht = true;
+ case WMI_11A_CAP:
+ band_5gig = true;
+ break;
+ case WMI_11GN_CAP:
+ ht = true;
+ case WMI_11G_CAP:
+ band_2gig = true;
+ break;
+ case WMI_11AGN_CAP:
+ ht = true;
+ case WMI_11AG_CAP:
+ band_2gig = true;
+ band_5gig = true;
+ break;
+ default:
+ ath6kl_err("invalid phy capability!\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Even if the fw has HT support, advertise HT cap only when
+ * the firmware has support to override RSN capability, otherwise
+ * 4-way handshake would fail.
+ */
+ if (!(ht &&
+ test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
+ ar->fw_capabilities))) {
+ ath6kl_band_2ghz.ht_cap.cap = 0;
+ ath6kl_band_2ghz.ht_cap.ht_supported = false;
+ ath6kl_band_5ghz.ht_cap.cap = 0;
+ ath6kl_band_5ghz.ht_cap.ht_supported = false;
+ }
+ if (band_2gig)
+ wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
+ if (band_5gig)
+ wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
+
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
wiphy->cipher_suites = cipher_suites;
@@ -3430,7 +3527,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
wiphy->wowlan.pattern_min_len = 1;
wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
- wiphy->max_sched_scan_ssids = 10;
+ wiphy->max_sched_scan_ssids = MAX_PROBED_SSID_INDEX;
ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
WIPHY_FLAG_HAVE_AP_SME |
@@ -3447,8 +3544,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
ar->wiphy->probe_resp_offload =
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
- NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P |
- NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U;
+ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
ret = wiphy_register(wiphy);
if (ret < 0) {
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h
index c5def436417f..5ea8cbb79f43 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.h
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h
@@ -28,6 +28,8 @@ enum ath6kl_cfg_suspend_mode {
struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
enum nl80211_iftype type,
u8 fw_vif_idx, u8 nw_type);
+void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
+ enum wmi_phy_mode mode);
void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted);
void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index 9d67964a51dd..4d9c6f142698 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -126,9 +126,9 @@ struct ath6kl_fw_ie {
#define AR6003_HW_2_0_FIRMWARE_FILE "athwlan.bin.z77"
#define AR6003_HW_2_0_TCMD_FIRMWARE_FILE "athtcmd_ram.bin"
#define AR6003_HW_2_0_PATCH_FILE "data.patch.bin"
-#define AR6003_HW_2_0_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin"
+#define AR6003_HW_2_0_BOARD_DATA_FILE AR6003_HW_2_0_FW_DIR "/bdata.bin"
#define AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE \
- "ath6k/AR6003/hw2.0/bdata.SD31.bin"
+ AR6003_HW_2_0_FW_DIR "/bdata.SD31.bin"
/* AR6003 3.0 definitions */
#define AR6003_HW_2_1_1_VERSION 0x30000582
@@ -139,25 +139,33 @@ struct ath6kl_fw_ie {
#define AR6003_HW_2_1_1_UTF_FIRMWARE_FILE "utf.bin"
#define AR6003_HW_2_1_1_TESTSCRIPT_FILE "nullTestFlow.bin"
#define AR6003_HW_2_1_1_PATCH_FILE "data.patch.bin"
-#define AR6003_HW_2_1_1_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin"
+#define AR6003_HW_2_1_1_BOARD_DATA_FILE AR6003_HW_2_1_1_FW_DIR "/bdata.bin"
#define AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE \
- "ath6k/AR6003/hw2.1.1/bdata.SD31.bin"
+ AR6003_HW_2_1_1_FW_DIR "/bdata.SD31.bin"
/* AR6004 1.0 definitions */
#define AR6004_HW_1_0_VERSION 0x30000623
#define AR6004_HW_1_0_FW_DIR "ath6k/AR6004/hw1.0"
#define AR6004_HW_1_0_FIRMWARE_FILE "fw.ram.bin"
-#define AR6004_HW_1_0_BOARD_DATA_FILE "ath6k/AR6004/hw1.0/bdata.bin"
+#define AR6004_HW_1_0_BOARD_DATA_FILE AR6004_HW_1_0_FW_DIR "/bdata.bin"
#define AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE \
- "ath6k/AR6004/hw1.0/bdata.DB132.bin"
+ AR6004_HW_1_0_FW_DIR "/bdata.DB132.bin"
/* AR6004 1.1 definitions */
#define AR6004_HW_1_1_VERSION 0x30000001
#define AR6004_HW_1_1_FW_DIR "ath6k/AR6004/hw1.1"
#define AR6004_HW_1_1_FIRMWARE_FILE "fw.ram.bin"
-#define AR6004_HW_1_1_BOARD_DATA_FILE "ath6k/AR6004/hw1.1/bdata.bin"
+#define AR6004_HW_1_1_BOARD_DATA_FILE AR6004_HW_1_1_FW_DIR "/bdata.bin"
#define AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE \
- "ath6k/AR6004/hw1.1/bdata.DB132.bin"
+ AR6004_HW_1_1_FW_DIR "/bdata.DB132.bin"
+
+/* AR6004 1.2 definitions */
+#define AR6004_HW_1_2_VERSION 0x300007e8
+#define AR6004_HW_1_2_FW_DIR "ath6k/AR6004/hw1.2"
+#define AR6004_HW_1_2_FIRMWARE_FILE "fw.ram.bin"
+#define AR6004_HW_1_2_BOARD_DATA_FILE AR6004_HW_1_2_FW_DIR "/bdata.bin"
+#define AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE \
+ AR6004_HW_1_2_FW_DIR "/bdata.bin"
/* Per STA data, used in AP mode */
#define STA_PS_AWAKE BIT(0)
@@ -502,6 +510,8 @@ enum ath6kl_vif_state {
WLAN_ENABLED,
STATS_UPDATE_PEND,
HOST_SLEEP_MODE_CMD_PROCESSED,
+ NETDEV_MCAST_ALL_ON,
+ NETDEV_MCAST_ALL_OFF,
};
struct ath6kl_vif {
@@ -549,9 +559,11 @@ struct ath6kl_vif {
u16 assoc_bss_beacon_int;
u16 listen_intvl_t;
u16 bmiss_time_t;
+ u16 bg_scan_period;
u8 assoc_bss_dtim_period;
struct net_device_stats net_stats;
struct target_stats target_stats;
+ struct wmi_connect_cmd profile;
struct list_head mc_filter;
};
@@ -640,6 +652,7 @@ struct ath6kl {
u8 sta_list_index;
struct ath6kl_req_key ap_mode_bkey;
struct sk_buff_head mcastpsq;
+ u32 want_ch_switch;
/*
* FIXME: protects access to mcastpsq but is actually useless as
@@ -672,6 +685,7 @@ struct ath6kl {
u32 refclk_hz;
u32 uarttx_pin;
u32 testscript_addr;
+ enum wmi_phy_cap cap;
struct ath6kl_hw_fw {
const char *dir;
@@ -805,7 +819,8 @@ void aggr_reset_state(struct aggr_info_conn *aggr_conn);
struct ath6kl_sta *ath6kl_find_sta(struct ath6kl_vif *vif, u8 *node_addr);
struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid);
-void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver);
+void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver,
+ enum wmi_phy_cap cap);
int ath6kl_control_tx(void *devt, struct sk_buff *skb,
enum htc_endpoint_id eid);
void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel,
diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c
index 1b76aff78508..15cfe30e54fd 100644
--- a/drivers/net/wireless/ath/ath6kl/debug.c
+++ b/drivers/net/wireless/ath/ath6kl/debug.c
@@ -401,8 +401,10 @@ static ssize_t ath6kl_fwlog_block_read(struct file *file,
ret = wait_for_completion_interruptible(
&ar->debug.fwlog_completion);
- if (ret == -ERESTARTSYS)
+ if (ret == -ERESTARTSYS) {
+ vfree(buf);
return ret;
+ }
spin_lock(&ar->debug.fwlog_queue.lock);
}
@@ -1570,10 +1572,15 @@ static ssize_t ath6kl_bgscan_int_write(struct file *file,
size_t count, loff_t *ppos)
{
struct ath6kl *ar = file->private_data;
+ struct ath6kl_vif *vif;
u16 bgscan_int;
char buf[32];
ssize_t len;
+ vif = ath6kl_vif_first(ar);
+ if (!vif)
+ return -EIO;
+
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
@@ -1585,6 +1592,8 @@ static ssize_t ath6kl_bgscan_int_write(struct file *file,
if (bgscan_int == 0)
bgscan_int = 0xffff;
+ vif->bg_scan_period = bgscan_int;
+
ath6kl_wmi_scanparams_cmd(ar->wmi, 0, 0, 0, bgscan_int, 0, 0, 0, 3,
0, 0, 0);
@@ -1809,6 +1818,7 @@ int ath6kl_debug_init_fs(struct ath6kl *ar)
void ath6kl_debug_cleanup(struct ath6kl *ar)
{
skb_queue_purge(&ar->debug.fwlog_queue);
+ complete(&ar->debug.fwlog_completion);
kfree(ar->debug.roam_tbl);
}
diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c
index 065e61516d7a..2798624d3a9d 100644
--- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c
+++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c
@@ -83,10 +83,7 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info,
* never goes inactive EVER.
*/
cur_ep_dist->dist_flags |= HTC_EP_ACTIVE;
- } else if (cur_ep_dist->svc_id == WMI_DATA_BK_SVC)
- /* this is the lowest priority data endpoint */
- /* FIXME: this looks fishy, check */
- cred_info->lowestpri_ep_dist = cur_ep_dist->list;
+ }
/*
* Streams have to be created (explicit | implicit) for all
@@ -100,6 +97,13 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info,
*/
}
+ /*
+ * For ath6kl_credit_seek function,
+ * it use list_for_each_entry_reverse to walk around the whole ep list.
+ * Therefore assign this lowestpri_ep_dist after walk around the ep_list
+ */
+ cred_info->lowestpri_ep_dist = cur_ep_dist->list;
+
WARN_ON(cred_info->cur_free_credits <= 0);
list_for_each_entry(cur_ep_dist, ep_list, list) {
@@ -758,7 +762,7 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint,
u32 txb_mask;
u8 ac = WMM_NUM_AC;
- if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) ||
+ if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) &&
(WMI_CONTROL_SVC != endpoint->svc_id))
ac = target->dev->ar->ep2ac_map[endpoint->eid];
@@ -793,16 +797,17 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint,
* itself
*/
txb_mask = ((1 << ac) - 1);
- /*
- * when the scatter request resources drop below a
- * certain threshold, disable Tx bundling for all
- * AC's with priority lower than the current requesting
- * AC. Otherwise re-enable Tx bundling for them
- */
- if (scat_req->scat_q_depth < ATH6KL_SCATTER_REQS)
- target->tx_bndl_mask &= ~txb_mask;
- else
- target->tx_bndl_mask |= txb_mask;
+
+ /*
+ * when the scatter request resources drop below a
+ * certain threshold, disable Tx bundling for all
+ * AC's with priority lower than the current requesting
+ * AC. Otherwise re-enable Tx bundling for them
+ */
+ if (scat_req->scat_q_depth < ATH6KL_SCATTER_REQS)
+ target->tx_bndl_mask &= ~txb_mask;
+ else
+ target->tx_bndl_mask |= txb_mask;
}
ath6kl_dbg(ATH6KL_DBG_HTC, "htc tx pkts to scatter: %d\n",
@@ -849,6 +854,7 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target,
int bundle_sent;
int n_pkts_bundle;
u8 ac = WMM_NUM_AC;
+ int status;
spin_lock_bh(&target->tx_lock);
@@ -866,7 +872,7 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target,
*/
INIT_LIST_HEAD(&txq);
- if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) ||
+ if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) &&
(WMI_CONTROL_SVC != endpoint->svc_id))
ac = target->dev->ar->ep2ac_map[endpoint->eid];
@@ -910,7 +916,12 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target,
ath6kl_htc_tx_prep_pkt(packet, packet->info.tx.flags,
0, packet->info.tx.seqno);
- ath6kl_htc_tx_issue(target, packet);
+ status = ath6kl_htc_tx_issue(target, packet);
+
+ if (status) {
+ packet->status = status;
+ packet->completion(packet->context, packet);
+ }
}
spin_lock_bh(&target->tx_lock);
diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c
index b277b3446882..f9626c723693 100644
--- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c
+++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c
@@ -108,8 +108,6 @@ static void get_htc_packet_credit_based(struct htc_target *target,
/* get packet at head, but don't remove it */
packet = list_first_entry(&ep->txq, struct htc_packet, list);
- if (packet == NULL)
- break;
ath6kl_dbg(ATH6KL_DBG_HTC,
"%s: got head packet:0x%p , queue depth: %d\n",
@@ -803,8 +801,6 @@ static int htc_send_packets_multiple(struct htc_target *target,
/* get first packet to find out which ep the packets will go into */
packet = list_first_entry(pkt_queue, struct htc_packet, list);
- if (packet == NULL)
- return -EINVAL;
if (packet->endpoint >= ENDPOINT_MAX) {
WARN_ON_ONCE(1);
@@ -1382,6 +1378,9 @@ static int ath6kl_htc_pipe_conn_service(struct htc_target *target,
/* copy all the callbacks */
ep->ep_cb = conn_req->ep_cb;
+ /* initialize tx_drop_packet_threshold */
+ ep->tx_drop_packet_threshold = MAX_HI_COOKIE_NUM;
+
status = ath6kl_hif_pipe_map_service(ar, ep->svc_id,
&ep->pipe.pipeid_ul,
&ep->pipe.pipeid_dl);
@@ -1636,10 +1635,6 @@ static int ath6kl_htc_pipe_add_rxbuf_multiple(struct htc_target *target,
return -EINVAL;
first = list_first_entry(pkt_queue, struct htc_packet, list);
- if (first == NULL) {
- WARN_ON_ONCE(1);
- return -EINVAL;
- }
if (first->endpoint >= ENDPOINT_MAX) {
WARN_ON_ONCE(1);
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index 29ef50ea07d5..7eb0515f458a 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -119,6 +119,24 @@ static const struct ath6kl_hw hw_list[] = {
.fw_board = AR6004_HW_1_1_BOARD_DATA_FILE,
.fw_default_board = AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE,
},
+ {
+ .id = AR6004_HW_1_2_VERSION,
+ .name = "ar6004 hw 1.2",
+ .dataset_patch_addr = 0x436ecc,
+ .app_load_addr = 0x1234,
+ .board_ext_data_addr = 0x437000,
+ .reserved_ram_size = 9216,
+ .board_addr = 0x435c00,
+ .refclk_hz = 40000000,
+ .uarttx_pin = 11,
+
+ .fw = {
+ .dir = AR6004_HW_1_2_FW_DIR,
+ .fw = AR6004_HW_1_2_FIRMWARE_FILE,
+ },
+ .fw_board = AR6004_HW_1_2_BOARD_DATA_FILE,
+ .fw_default_board = AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE,
+ },
};
/*
@@ -445,9 +463,9 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx)
P2P_FLAG_MACADDR_REQ |
P2P_FLAG_HMODEL_REQ);
if (ret) {
- ath6kl_dbg(ATH6KL_DBG_TRC, "failed to request P2P "
- "capabilities (%d) - assuming P2P not "
- "supported\n", ret);
+ ath6kl_dbg(ATH6KL_DBG_TRC,
+ "failed to request P2P capabilities (%d) - assuming P2P not supported\n",
+ ret);
ar->p2p = false;
}
}
@@ -456,8 +474,9 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx)
/* Enable Probe Request reporting for P2P */
ret = ath6kl_wmi_probe_report_req_cmd(ar->wmi, idx, true);
if (ret) {
- ath6kl_dbg(ATH6KL_DBG_TRC, "failed to enable Probe "
- "Request reporting (%d)\n", ret);
+ ath6kl_dbg(ATH6KL_DBG_TRC,
+ "failed to enable Probe Request reporting (%d)\n",
+ ret);
}
}
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index 4d818f96c415..e5524470529c 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -421,8 +421,8 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel)
if (!ik->valid)
break;
- ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed addkey for "
- "the initial group key for AP mode\n");
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+ "Delayed addkey for the initial group key for AP mode\n");
memset(key_rsc, 0, sizeof(key_rsc));
res = ath6kl_wmi_addkey_cmd(
ar->wmi, vif->fw_vif_idx, ik->key_index, ik->key_type,
@@ -430,12 +430,19 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel)
ik->key,
KEY_OP_INIT_VAL, NULL, SYNC_BOTH_WMIFLAG);
if (res) {
- ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed "
- "addkey failed: %d\n", res);
+ ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+ "Delayed addkey failed: %d\n", res);
}
break;
}
+ if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) {
+ ar->want_ch_switch &= ~(1 << vif->fw_vif_idx);
+ /* we actually don't know the phymode, default to HT20 */
+ ath6kl_cfg80211_ch_switch_notify(vif, channel,
+ WMI_11G_HT20);
+ }
+
ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, NONE_BSS_FILTER, 0);
set_bit(CONNECTED, &vif->flags);
netif_carrier_on(vif->ndev);
@@ -541,7 +548,8 @@ void ath6kl_disconnect(struct ath6kl_vif *vif)
/* WMI Event handlers */
-void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver)
+void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver,
+ enum wmi_phy_cap cap)
{
struct ath6kl *ar = devt;
@@ -551,6 +559,7 @@ void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver)
ar->version.wlan_ver = sw_ver;
ar->version.abi_ver = abi_ver;
+ ar->hw.cap = cap;
snprintf(ar->wiphy->fw_version,
sizeof(ar->wiphy->fw_version),
@@ -584,6 +593,45 @@ void ath6kl_scan_complete_evt(struct ath6kl_vif *vif, int status)
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "scan complete: %d\n", status);
}
+static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel)
+{
+
+ struct ath6kl *ar = vif->ar;
+
+ vif->next_chan = channel;
+ vif->profile.ch = cpu_to_le16(channel);
+
+ switch (vif->nw_type) {
+ case AP_NETWORK:
+ return ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx,
+ &vif->profile);
+ default:
+ ath6kl_err("won't switch channels nw_type=%d\n", vif->nw_type);
+ return -ENOTSUPP;
+ }
+}
+
+static void ath6kl_check_ch_switch(struct ath6kl *ar, u16 channel)
+{
+
+ struct ath6kl_vif *vif;
+ int res = 0;
+
+ if (!ar->want_ch_switch)
+ return;
+
+ spin_lock_bh(&ar->list_lock);
+ list_for_each_entry(vif, &ar->vif_list, list) {
+ if (ar->want_ch_switch & (1 << vif->fw_vif_idx))
+ res = ath6kl_commit_ch_switch(vif, channel);
+
+ if (res)
+ ath6kl_err("channel switch failed nw_type %d res %d\n",
+ vif->nw_type, res);
+ }
+ spin_unlock_bh(&ar->list_lock);
+}
+
void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid,
u16 listen_int, u16 beacon_int,
enum network_type net_type, u8 beacon_ie_len,
@@ -601,9 +649,11 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid,
memcpy(vif->bssid, bssid, sizeof(vif->bssid));
vif->bss_ch = channel;
- if ((vif->nw_type == INFRA_NETWORK))
+ if ((vif->nw_type == INFRA_NETWORK)) {
ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
vif->listen_intvl_t, 0);
+ ath6kl_check_ch_switch(ar, channel);
+ }
netif_wake_queue(vif->ndev);
@@ -926,6 +976,11 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid,
struct ath6kl *ar = vif->ar;
if (vif->nw_type == AP_NETWORK) {
+ /* disconnect due to other STA vif switching channels */
+ if (reason == BSS_DISCONNECTED &&
+ prot_reason_status == WMI_AP_REASON_STA_ROAM)
+ ar->want_ch_switch |= 1 << vif->fw_vif_idx;
+
if (!ath6kl_remove_sta(ar, bssid, prot_reason_status))
return;
@@ -1090,7 +1145,7 @@ static int ath6kl_set_features(struct net_device *dev,
static void ath6kl_set_multicast_list(struct net_device *ndev)
{
struct ath6kl_vif *vif = netdev_priv(ndev);
- bool mc_all_on = false, mc_all_off = false;
+ bool mc_all_on = false;
int mc_count = netdev_mc_count(ndev);
struct netdev_hw_addr *ha;
bool found;
@@ -1102,24 +1157,41 @@ static void ath6kl_set_multicast_list(struct net_device *ndev)
!test_bit(WLAN_ENABLED, &vif->flags))
return;
+ /* Enable multicast-all filter. */
mc_all_on = !!(ndev->flags & IFF_PROMISC) ||
!!(ndev->flags & IFF_ALLMULTI) ||
!!(mc_count > ATH6K_MAX_MC_FILTERS_PER_LIST);
- mc_all_off = !(ndev->flags & IFF_MULTICAST) || mc_count == 0;
+ if (mc_all_on)
+ set_bit(NETDEV_MCAST_ALL_ON, &vif->flags);
+ else
+ clear_bit(NETDEV_MCAST_ALL_ON, &vif->flags);
+
+ mc_all_on = mc_all_on || (vif->ar->state == ATH6KL_STATE_ON);
- if (mc_all_on || mc_all_off) {
- /* Enable/disable all multicast */
- ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast filter\n",
- mc_all_on ? "enabling" : "disabling");
- ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx,
+ if (!(ndev->flags & IFF_MULTICAST)) {
+ mc_all_on = false;
+ set_bit(NETDEV_MCAST_ALL_OFF, &vif->flags);
+ } else {
+ clear_bit(NETDEV_MCAST_ALL_OFF, &vif->flags);
+ }
+
+ /* Enable/disable "multicast-all" filter*/
+ ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast-all filter\n",
+ mc_all_on ? "enabling" : "disabling");
+
+ ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx,
mc_all_on);
- if (ret)
- ath6kl_warn("Failed to %s multicast receive\n",
- mc_all_on ? "enable" : "disable");
+ if (ret) {
+ ath6kl_warn("Failed to %s multicast-all receive\n",
+ mc_all_on ? "enable" : "disable");
return;
}
+ if (test_bit(NETDEV_MCAST_ALL_ON, &vif->flags))
+ return;
+
+ /* Keep the driver and firmware mcast list in sync. */
list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) {
found = false;
netdev_for_each_mc_addr(ha, ndev) {
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
index 44ea7a742101..05b95405f7b5 100644
--- a/drivers/net/wireless/ath/ath6kl/sdio.c
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -552,7 +552,7 @@ static int ath6kl_sdio_write_async(struct ath6kl *ar, u32 address, u8 *buffer,
bus_req = ath6kl_sdio_alloc_busreq(ar_sdio);
- if (!bus_req)
+ if (WARN_ON_ONCE(!bus_req))
return -ENOMEM;
bus_req->address = address;
@@ -915,6 +915,9 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
}
cut_pwr:
+ if (func->card && func->card->host)
+ func->card->host->pm_flags &= ~MMC_PM_KEEP_POWER;
+
return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER, NULL);
}
@@ -985,9 +988,8 @@ static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr)
}
if (status) {
- ath6kl_err("%s: failed to write initial bytes of 0x%x "
- "to window reg: 0x%X\n", __func__,
- addr, reg_addr);
+ ath6kl_err("%s: failed to write initial bytes of 0x%x to window reg: 0x%X\n",
+ __func__, addr, reg_addr);
return status;
}
@@ -1076,8 +1078,8 @@ static int ath6kl_sdio_bmi_credits(struct ath6kl *ar)
(u8 *)&ar->bmi.cmd_credits, 4,
HIF_RD_SYNC_BYTE_INC);
if (ret) {
- ath6kl_err("Unable to decrement the command credit "
- "count register: %d\n", ret);
+ ath6kl_err("Unable to decrement the command credit count register: %d\n",
+ ret);
return ret;
}
@@ -1457,3 +1459,6 @@ MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_FW_DIR "/" AR6004_HW_1_1_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);
+MODULE_FIRMWARE(AR6004_HW_1_2_FW_DIR "/" AR6004_HW_1_2_FIRMWARE_FILE);
+MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE);
+MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE);
diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c
index 82f2f5cb475b..67206aedea6c 100644
--- a/drivers/net/wireless/ath/ath6kl/txrx.c
+++ b/drivers/net/wireless/ath/ath6kl/txrx.c
@@ -362,15 +362,11 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
skb, skb->data, skb->len);
/* If target is not associated */
- if (!test_bit(CONNECTED, &vif->flags)) {
- dev_kfree_skb(skb);
- return 0;
- }
+ if (!test_bit(CONNECTED, &vif->flags))
+ goto fail_tx;
- if (WARN_ON_ONCE(ar->state != ATH6KL_STATE_ON)) {
- dev_kfree_skb(skb);
- return 0;
- }
+ if (WARN_ON_ONCE(ar->state != ATH6KL_STATE_ON))
+ goto fail_tx;
if (!test_bit(WMI_READY, &ar->flag))
goto fail_tx;
diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c
index ec7f1f5fd1ca..3740c3d6ab88 100644
--- a/drivers/net/wireless/ath/ath6kl/usb.c
+++ b/drivers/net/wireless/ath/ath6kl/usb.c
@@ -1037,6 +1037,14 @@ static void ath6kl_usb_stop(struct ath6kl *ar)
hif_stop(ar);
}
+static void ath6kl_usb_cleanup_scatter(struct ath6kl *ar)
+{
+ /*
+ * USB doesn't support it. Just return.
+ */
+ return;
+}
+
static const struct ath6kl_hif_ops ath6kl_usb_ops = {
.diag_read32 = ath6kl_usb_diag_read32,
.diag_write32 = ath6kl_usb_diag_write32,
@@ -1049,6 +1057,7 @@ static const struct ath6kl_hif_ops ath6kl_usb_ops = {
.pipe_get_default = ath6kl_usb_get_default_pipe,
.pipe_map_service = ath6kl_usb_map_service_pipe,
.pipe_get_free_queue_number = ath6kl_usb_get_free_queue_number,
+ .cleanup_scatter = ath6kl_usb_cleanup_scatter,
};
/* ath6kl usb driver registered functions */
@@ -1182,6 +1191,7 @@ static struct usb_driver ath6kl_usb_driver = {
.disconnect = ath6kl_usb_remove,
.id_table = ath6kl_usb_ids,
.supports_autosuspend = true,
+ .disable_hub_initiated_lpm = 1,
};
static int ath6kl_usb_init(void)
@@ -1207,3 +1217,6 @@ MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);
+MODULE_FIRMWARE(AR6004_HW_1_2_FIRMWARE_FILE);
+MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE);
+MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE);
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 7c8a9977faf5..ee8ec2394c2c 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -16,6 +16,7 @@
*/
#include <linux/ip.h>
+#include <linux/in.h>
#include "core.h"
#include "debug.h"
#include "testmode.h"
@@ -289,6 +290,13 @@ int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, u8 if_idx,
layer2_priority);
} else
usr_pri = layer2_priority & 0x7;
+
+ /*
+ * Queue the EAPOL frames in the same WMM_AC_VO queue
+ * as that of management frames.
+ */
+ if (skb->protocol == cpu_to_be16(ETH_P_PAE))
+ usr_pri = WMI_VOICE_USER_PRIORITY;
}
/*
@@ -460,8 +468,9 @@ static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap,
freq, dur);
chan = ieee80211_get_channel(ar->wiphy, freq);
if (!chan) {
- ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl: Unknown channel "
- "(freq=%u)\n", freq);
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "remain_on_chnl: Unknown channel (freq=%u)\n",
+ freq);
return -EINVAL;
}
id = vif->last_roc_id;
@@ -488,12 +497,14 @@ static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi,
ev = (struct wmi_cancel_remain_on_chnl_event *) datap;
freq = le32_to_cpu(ev->freq);
dur = le32_to_cpu(ev->duration);
- ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl: freq=%u dur=%u "
- "status=%u\n", freq, dur, ev->status);
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "cancel_remain_on_chnl: freq=%u dur=%u status=%u\n",
+ freq, dur, ev->status);
chan = ieee80211_get_channel(ar->wiphy, freq);
if (!chan) {
- ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl: Unknown "
- "channel (freq=%u)\n", freq);
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "cancel_remain_on_chnl: Unknown channel (freq=%u)\n",
+ freq);
return -EINVAL;
}
if (vif->last_cancel_roc_id &&
@@ -548,12 +559,12 @@ static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len,
freq = le32_to_cpu(ev->freq);
dlen = le16_to_cpu(ev->len);
if (datap + len < ev->data + dlen) {
- ath6kl_err("invalid wmi_p2p_rx_probe_req_event: "
- "len=%d dlen=%u\n", len, dlen);
+ ath6kl_err("invalid wmi_p2p_rx_probe_req_event: len=%d dlen=%u\n",
+ len, dlen);
return -EINVAL;
}
- ath6kl_dbg(ATH6KL_DBG_WMI, "rx_probe_req: len=%u freq=%u "
- "probe_req_report=%d\n",
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "rx_probe_req: len=%u freq=%u probe_req_report=%d\n",
dlen, freq, vif->probe_req_report);
if (vif->probe_req_report || vif->nw_type == AP_NETWORK)
@@ -592,8 +603,8 @@ static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len,
freq = le32_to_cpu(ev->freq);
dlen = le16_to_cpu(ev->len);
if (datap + len < ev->data + dlen) {
- ath6kl_err("invalid wmi_rx_action_event: "
- "len=%d dlen=%u\n", len, dlen);
+ ath6kl_err("invalid wmi_rx_action_event: len=%d dlen=%u\n",
+ len, dlen);
return -EINVAL;
}
ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq);
@@ -687,7 +698,7 @@ static int ath6kl_wmi_ready_event_rx(struct wmi *wmi, u8 *datap, int len)
ath6kl_ready_event(wmi->parent_dev, ev->mac_addr,
le32_to_cpu(ev->sw_version),
- le32_to_cpu(ev->abi_version));
+ le32_to_cpu(ev->abi_version), ev->phy_cap);
return 0;
}
@@ -777,16 +788,15 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len,
/* AP mode start/STA connected event */
struct net_device *dev = vif->ndev;
if (memcmp(dev->dev_addr, ev->u.ap_bss.bssid, ETH_ALEN) == 0) {
- ath6kl_dbg(ATH6KL_DBG_WMI, "%s: freq %d bssid %pM "
- "(AP started)\n",
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "%s: freq %d bssid %pM (AP started)\n",
__func__, le16_to_cpu(ev->u.ap_bss.ch),
ev->u.ap_bss.bssid);
ath6kl_connect_ap_mode_bss(
vif, le16_to_cpu(ev->u.ap_bss.ch));
} else {
- ath6kl_dbg(ATH6KL_DBG_WMI, "%s: aid %u mac_addr %pM "
- "auth=%u keymgmt=%u cipher=%u apsd_info=%u "
- "(STA connected)\n",
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "%s: aid %u mac_addr %pM auth=%u keymgmt=%u cipher=%u apsd_info=%u (STA connected)\n",
__func__, ev->u.ap_sta.aid,
ev->u.ap_sta.mac_addr,
ev->u.ap_sta.auth,
@@ -1229,8 +1239,9 @@ static int ath6kl_wmi_neighbor_report_event_rx(struct wmi *wmi, u8 *datap,
ev = (struct wmi_neighbor_report_event *) datap;
if (sizeof(*ev) + ev->num_neighbors * sizeof(struct wmi_neighbor_info)
> len) {
- ath6kl_dbg(ATH6KL_DBG_WMI, "truncated neighbor event "
- "(num=%d len=%d)\n", ev->num_neighbors, len);
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "truncated neighbor event (num=%d len=%d)\n",
+ ev->num_neighbors, len);
return -EINVAL;
}
for (i = 0; i < ev->num_neighbors; i++) {
@@ -1814,12 +1825,14 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
u32 home_dwell_time, u32 force_scan_interval,
s8 num_chan, u16 *ch_list, u32 no_cck, u32 *rates)
{
+ struct ieee80211_supported_band *sband;
struct sk_buff *skb;
struct wmi_begin_scan_cmd *sc;
- s8 size;
+ s8 size, *supp_rates;
int i, band, ret;
struct ath6kl *ar = wmi->parent_dev;
int num_rates;
+ u32 ratemask;
size = sizeof(struct wmi_begin_scan_cmd);
@@ -1846,10 +1859,13 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
sc->num_ch = num_chan;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
- struct ieee80211_supported_band *sband =
- ar->wiphy->bands[band];
- u32 ratemask = rates[band];
- u8 *supp_rates = sc->supp_rates[band].rates;
+ sband = ar->wiphy->bands[band];
+
+ if (!sband)
+ continue;
+
+ ratemask = rates[band];
+ supp_rates = sc->supp_rates[band].rates;
num_rates = 0;
for (i = 0; i < sband->n_bitrates; i++) {
@@ -2129,8 +2145,8 @@ int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 if_idx, u8 key_index,
struct wmi_add_cipher_key_cmd *cmd;
int ret;
- ath6kl_dbg(ATH6KL_DBG_WMI, "addkey cmd: key_index=%u key_type=%d "
- "key_usage=%d key_len=%d key_op_ctrl=%d\n",
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "addkey cmd: key_index=%u key_type=%d key_usage=%d key_len=%d key_op_ctrl=%d\n",
key_index, key_type, key_usage, key_len, key_op_ctrl);
if ((key_index > WMI_MAX_KEY_INDEX) || (key_len > WMI_MAX_KEY_LEN) ||
@@ -3047,8 +3063,8 @@ int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, u8 if_idx,
res = ath6kl_wmi_cmd_send(wmip, if_idx, skb, WMI_AP_CONFIG_COMMIT_CMDID,
NO_SYNC_WMIFLAG);
- ath6kl_dbg(ATH6KL_DBG_WMI, "%s: nw_type=%u auth_mode=%u ch=%u "
- "ctrl_flags=0x%x-> res=%d\n",
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "%s: nw_type=%u auth_mode=%u ch=%u ctrl_flags=0x%x-> res=%d\n",
__func__, p->nw_type, p->auth_mode, le16_to_cpu(p->ch),
le32_to_cpu(p->ctrl_flags), res);
return res;
@@ -3208,8 +3224,9 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
if (!skb)
return -ENOMEM;
- ath6kl_dbg(ATH6KL_DBG_WMI, "set_appie_cmd: mgmt_frm_type=%u "
- "ie_len=%u\n", mgmt_frm_type, ie_len);
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "set_appie_cmd: mgmt_frm_type=%u ie_len=%u\n",
+ mgmt_frm_type, ie_len);
p = (struct wmi_set_appie_cmd *) skb->data;
p->mgmt_frm_type = mgmt_frm_type;
p->ie_len = ie_len;
@@ -3310,8 +3327,9 @@ static int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id,
wmi->last_mgmt_tx_frame = buf;
wmi->last_mgmt_tx_frame_len = data_len;
- ath6kl_dbg(ATH6KL_DBG_WMI, "send_action_cmd: id=%u freq=%u wait=%u "
- "len=%u\n", id, freq, wait, data_len);
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "send_action_cmd: id=%u freq=%u wait=%u len=%u\n",
+ id, freq, wait, data_len);
p = (struct wmi_send_action_cmd *) skb->data;
p->id = cpu_to_le32(id);
p->freq = cpu_to_le32(freq);
@@ -3348,8 +3366,9 @@ static int __ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id,
wmi->last_mgmt_tx_frame = buf;
wmi->last_mgmt_tx_frame_len = data_len;
- ath6kl_dbg(ATH6KL_DBG_WMI, "send_action_cmd: id=%u freq=%u wait=%u "
- "len=%u\n", id, freq, wait, data_len);
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "send_action_cmd: id=%u freq=%u wait=%u len=%u\n",
+ id, freq, wait, data_len);
p = (struct wmi_send_mgmt_cmd *) skb->data;
p->id = cpu_to_le32(id);
p->freq = cpu_to_le32(freq);
@@ -3402,8 +3421,9 @@ int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq,
if (!skb)
return -ENOMEM;
- ath6kl_dbg(ATH6KL_DBG_WMI, "send_probe_response_cmd: freq=%u dst=%pM "
- "len=%u\n", freq, dst, data_len);
+ ath6kl_dbg(ATH6KL_DBG_WMI,
+ "send_probe_response_cmd: freq=%u dst=%pM len=%u\n",
+ freq, dst, data_len);
p = (struct wmi_p2p_probe_response_cmd *) skb->data;
p->freq = cpu_to_le32(freq);
memcpy(p->destination_addr, dst, ETH_ALEN);
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index d3d2ab5c1689..9076bec3a2ba 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -106,6 +106,8 @@ struct wmi_data_sync_bufs {
#define WMM_AC_VI 2 /* video */
#define WMM_AC_VO 3 /* voice */
+#define WMI_VOICE_USER_PRIORITY 0x7
+
struct wmi {
u16 stream_exist_for_ac[WMM_NUM_AC];
u8 fat_pipe_exist;
@@ -1151,6 +1153,7 @@ enum wmi_phy_mode {
WMI_11AG_MODE = 0x3,
WMI_11B_MODE = 0x4,
WMI_11GONLY_MODE = 0x5,
+ WMI_11G_HT20 = 0x6,
};
#define WMI_MAX_CHANNELS 32
@@ -1416,6 +1419,16 @@ struct wmi_ready_event_2 {
u8 phy_cap;
} __packed;
+/* WMI_PHY_CAPABILITY */
+enum wmi_phy_cap {
+ WMI_11A_CAP = 0x01,
+ WMI_11G_CAP = 0x02,
+ WMI_11AG_CAP = 0x03,
+ WMI_11AN_CAP = 0x04,
+ WMI_11GN_CAP = 0x05,
+ WMI_11AGN_CAP = 0x06,
+};
+
/* Connect Event */
struct wmi_connect_event {
union {
@@ -1468,6 +1481,17 @@ enum wmi_disconnect_reason {
IBSS_MERGE = 0xe,
};
+/* AP mode disconnect proto_reasons */
+enum ap_disconnect_reason {
+ WMI_AP_REASON_STA_LEFT = 101,
+ WMI_AP_REASON_FROM_HOST = 102,
+ WMI_AP_REASON_COMM_TIMEOUT = 103,
+ WMI_AP_REASON_MAX_STA = 104,
+ WMI_AP_REASON_ACL = 105,
+ WMI_AP_REASON_STA_ROAM = 106,
+ WMI_AP_REASON_DFS_CHANNEL = 107,
+};
+
#define ATH6KL_COUNTRY_RD_SHIFT 16
struct ath6kl_wmi_regdomain {
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index a0387a027db0..9fdd70fcaf5b 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -892,34 +892,6 @@ static void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah)
AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);
}
-static bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan)
-{
- struct ath9k_rtt_hist *hist;
- u32 *table;
- int i;
- bool restore;
-
- if (!ah->caldata)
- return false;
-
- hist = &ah->caldata->rtt_hist;
- if (!hist->num_readings)
- return false;
-
- ar9003_hw_rtt_enable(ah);
- ar9003_hw_rtt_set_mask(ah, 0x00);
- for (i = 0; i < AR9300_MAX_CHAINS; i++) {
- if (!(ah->rxchainmask & (1 << i)))
- continue;
- table = &hist->table[i][hist->num_readings][0];
- ar9003_hw_rtt_load_hist(ah, i, table);
- }
- restore = ar9003_hw_rtt_force_restore(ah);
- ar9003_hw_rtt_disable(ah);
-
- return restore;
-}
-
static bool ar9003_hw_init_cal(struct ath_hw *ah,
struct ath9k_channel *chan)
{
@@ -942,9 +914,10 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
if (!ar9003_hw_rtt_restore(ah, chan))
run_rtt_cal = true;
- ath_dbg(common, CALIBRATE, "RTT restore %s\n",
- run_rtt_cal ? "failed" : "succeed");
+ if (run_rtt_cal)
+ ath_dbg(common, CALIBRATE, "RTT calibration to be done\n");
}
+
run_agc_cal = run_rtt_cal;
if (run_rtt_cal) {
@@ -1069,17 +1042,14 @@ skip_tx_iqcal:
#undef CL_TAB_ENTRY
if (run_rtt_cal && caldata) {
- struct ath9k_rtt_hist *hist = &caldata->rtt_hist;
- if (is_reusable && (hist->num_readings < RTT_HIST_MAX)) {
- u32 *table;
+ if (is_reusable) {
+ if (!ath9k_hw_rfbus_req(ah))
+ ath_err(ath9k_hw_common(ah),
+ "Could not stop baseband\n");
+ else
+ ar9003_hw_rtt_fill_hist(ah);
- hist->num_readings++;
- for (i = 0; i < AR9300_MAX_CHAINS; i++) {
- if (!(ah->rxchainmask & (1 << i)))
- continue;
- table = &hist->table[i][hist->num_readings][0];
- ar9003_hw_rtt_fill_hist(ah, i, table);
- }
+ ath9k_hw_rfbus_done(ah);
}
ar9003_hw_rtt_disable(ah);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c
index 3cac293a2849..ffbb180f91e1 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c
@@ -756,7 +756,7 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (caldata) {
caldata->done_txiqcal_once = false;
caldata->done_txclcal_once = false;
- caldata->rtt_hist.num_readings = 0;
+ caldata->rtt_done = false;
}
if (!ath9k_hw_init_cal(ah, chan))
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_rtt.c b/drivers/net/wireless/ath/ath9k/ar9003_rtt.c
index 458bedf0b0ae..74de3539c2c8 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_rtt.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_rtt.c
@@ -15,6 +15,7 @@
*/
#include "hw.h"
+#include "hw-ops.h"
#include "ar9003_phy.h"
#include "ar9003_rtt.h"
@@ -69,7 +70,7 @@ bool ar9003_hw_rtt_force_restore(struct ath_hw *ah)
}
static void ar9003_hw_rtt_load_hist_entry(struct ath_hw *ah, u8 chain,
- u32 index, u32 data28)
+ u32 index, u32 data28)
{
u32 val;
@@ -100,12 +101,21 @@ static void ar9003_hw_rtt_load_hist_entry(struct ath_hw *ah, u8 chain,
RTT_ACCESS_TIMEOUT);
}
-void ar9003_hw_rtt_load_hist(struct ath_hw *ah, u8 chain, u32 *table)
+void ar9003_hw_rtt_load_hist(struct ath_hw *ah)
{
- int i;
+ int chain, i;
- for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++)
- ar9003_hw_rtt_load_hist_entry(ah, chain, i, table[i]);
+ for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
+ if (!(ah->rxchainmask & (1 << chain)))
+ continue;
+ for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) {
+ ar9003_hw_rtt_load_hist_entry(ah, chain, i,
+ ah->caldata->rtt_table[chain][i]);
+ ath_dbg(ath9k_hw_common(ah), CALIBRATE,
+ "Load RTT value at idx %d, chain %d: 0x%x\n",
+ i, chain, ah->caldata->rtt_table[chain][i]);
+ }
+ }
}
static int ar9003_hw_rtt_fill_hist_entry(struct ath_hw *ah, u8 chain, u32 index)
@@ -128,27 +138,71 @@ static int ar9003_hw_rtt_fill_hist_entry(struct ath_hw *ah, u8 chain, u32 index)
RTT_ACCESS_TIMEOUT))
return RTT_BAD_VALUE;
- val = REG_READ(ah, AR_PHY_RTT_TABLE_SW_INTF_1_B(chain));
+ val = MS(REG_READ(ah, AR_PHY_RTT_TABLE_SW_INTF_1_B(chain)),
+ AR_PHY_RTT_SW_RTT_TABLE_DATA);
+
return val;
}
-void ar9003_hw_rtt_fill_hist(struct ath_hw *ah, u8 chain, u32 *table)
+void ar9003_hw_rtt_fill_hist(struct ath_hw *ah)
{
- int i;
+ int chain, i;
+
+ for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
+ if (!(ah->rxchainmask & (1 << chain)))
+ continue;
+ for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) {
+ ah->caldata->rtt_table[chain][i] =
+ ar9003_hw_rtt_fill_hist_entry(ah, chain, i);
+ ath_dbg(ath9k_hw_common(ah), CALIBRATE,
+ "RTT value at idx %d, chain %d is: 0x%x\n",
+ i, chain, ah->caldata->rtt_table[chain][i]);
+ }
+ }
- for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++)
- table[i] = ar9003_hw_rtt_fill_hist_entry(ah, chain, i);
+ ah->caldata->rtt_done = true;
}
void ar9003_hw_rtt_clear_hist(struct ath_hw *ah)
{
- int i, j;
+ int chain, i;
- for (i = 0; i < AR9300_MAX_CHAINS; i++) {
- if (!(ah->rxchainmask & (1 << i)))
+ for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
+ if (!(ah->rxchainmask & (1 << chain)))
continue;
- for (j = 0; j < MAX_RTT_TABLE_ENTRY; j++)
- ar9003_hw_rtt_load_hist_entry(ah, i, j, 0);
+ for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++)
+ ar9003_hw_rtt_load_hist_entry(ah, chain, i, 0);
}
+
+ if (ah->caldata)
+ ah->caldata->rtt_done = false;
+}
+
+bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+ bool restore;
+
+ if (!ah->caldata)
+ return false;
+
+ if (!ah->caldata->rtt_done)
+ return false;
+
+ ar9003_hw_rtt_enable(ah);
+ ar9003_hw_rtt_set_mask(ah, 0x10);
+
+ if (!ath9k_hw_rfbus_req(ah)) {
+ ath_err(ath9k_hw_common(ah), "Could not stop baseband\n");
+ restore = false;
+ goto fail;
+ }
+
+ ar9003_hw_rtt_load_hist(ah);
+ restore = ar9003_hw_rtt_force_restore(ah);
+
+fail:
+ ath9k_hw_rfbus_done(ah);
+ ar9003_hw_rtt_disable(ah);
+ return restore;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_rtt.h b/drivers/net/wireless/ath/ath9k/ar9003_rtt.h
index 030758d087d6..a43b30d723a4 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_rtt.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_rtt.h
@@ -21,8 +21,9 @@ void ar9003_hw_rtt_enable(struct ath_hw *ah);
void ar9003_hw_rtt_disable(struct ath_hw *ah);
void ar9003_hw_rtt_set_mask(struct ath_hw *ah, u32 rtt_mask);
bool ar9003_hw_rtt_force_restore(struct ath_hw *ah);
-void ar9003_hw_rtt_load_hist(struct ath_hw *ah, u8 chain, u32 *table);
-void ar9003_hw_rtt_fill_hist(struct ath_hw *ah, u8 chain, u32 *table);
+void ar9003_hw_rtt_load_hist(struct ath_hw *ah);
+void ar9003_hw_rtt_fill_hist(struct ath_hw *ah);
void ar9003_hw_rtt_clear_hist(struct ath_hw *ah);
+bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan);
#endif
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index f67cd952e741..aa327adcc3d8 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -1358,6 +1358,7 @@ static struct usb_driver ath9k_hif_usb_driver = {
#endif
.id_table = ath9k_hif_usb_ids,
.soft_unbind = 1,
+ .disable_hub_initiated_lpm = 1,
};
int ath9k_hif_usb_init(void)
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index f84477c5ebb1..abe05ec85d50 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1702,10 +1702,10 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
* For AR9462, make sure that calibration data for
* re-using are present.
*/
- if (AR_SREV_9462(ah) && (!ah->caldata ||
- !ah->caldata->done_txiqcal_once ||
- !ah->caldata->done_txclcal_once ||
- !ah->caldata->rtt_hist.num_readings))
+ if (AR_SREV_9462(ah) && (ah->caldata &&
+ (!ah->caldata->done_txiqcal_once ||
+ !ah->caldata->done_txclcal_once ||
+ !ah->caldata->rtt_done)))
goto fail;
ath_dbg(common, RESET, "FastChannelChange for %d -> %d\n",
@@ -1941,7 +1941,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (caldata) {
caldata->done_txiqcal_once = false;
caldata->done_txclcal_once = false;
- caldata->rtt_hist.num_readings = 0;
}
if (!ath9k_hw_init_cal(ah, chan))
return -EIO;
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 828b9bbc456d..b620c557c2a6 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -348,12 +348,6 @@ enum ath9k_int {
CHANNEL_HT40MINUS)
#define MAX_RTT_TABLE_ENTRY 6
-#define RTT_HIST_MAX 3
-struct ath9k_rtt_hist {
- u32 table[AR9300_MAX_CHAINS][RTT_HIST_MAX][MAX_RTT_TABLE_ENTRY];
- u8 num_readings;
-};
-
#define MAX_IQCAL_MEASUREMENT 8
#define MAX_CL_TAB_ENTRY 16
@@ -363,6 +357,7 @@ struct ath9k_hw_cal_data {
int32_t CalValid;
int8_t iCoff;
int8_t qCoff;
+ bool rtt_done;
bool paprd_done;
bool nfcal_pending;
bool nfcal_interference;
@@ -373,8 +368,8 @@ struct ath9k_hw_cal_data {
u32 num_measures[AR9300_MAX_CHAINS];
int tx_corr_coeff[MAX_IQCAL_MEASUREMENT][AR9300_MAX_CHAINS];
u32 tx_clcal[AR9300_MAX_CHAINS][MAX_CL_TAB_ENTRY];
+ u32 rtt_table[AR9300_MAX_CHAINS][MAX_RTT_TABLE_ENTRY];
struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
- struct ath9k_rtt_hist rtt_hist;
};
struct ath9k_channel {
diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c
index 89821e4835c7..888152ce3eca 100644
--- a/drivers/net/wireless/ath/carl9170/usb.c
+++ b/drivers/net/wireless/ath/carl9170/usb.c
@@ -1159,6 +1159,7 @@ static struct usb_driver carl9170_driver = {
.resume = carl9170_usb_resume,
.reset_resume = carl9170_usb_resume,
#endif /* CONFIG_PM */
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(carl9170_driver);
diff --git a/drivers/net/wireless/b43/bus.c b/drivers/net/wireless/b43/bus.c
index 424692df239d..565fdbdd6915 100644
--- a/drivers/net/wireless/b43/bus.c
+++ b/drivers/net/wireless/b43/bus.c
@@ -107,11 +107,9 @@ struct b43_bus_dev *b43_bus_dev_bcma_init(struct bcma_device *core)
dev->dma_dev = core->dma_dev;
dev->irq = core->irq;
- /*
dev->board_vendor = core->bus->boardinfo.vendor;
dev->board_type = core->bus->boardinfo.type;
- dev->board_rev = core->bus->boardinfo.rev;
- */
+ dev->board_rev = core->bus->sprom.board_rev;
dev->chip_id = core->bus->chipinfo.id;
dev->chip_rev = core->bus->chipinfo.rev;
@@ -210,7 +208,7 @@ struct b43_bus_dev *b43_bus_dev_ssb_init(struct ssb_device *sdev)
dev->board_vendor = sdev->bus->boardinfo.vendor;
dev->board_type = sdev->bus->boardinfo.type;
- dev->board_rev = sdev->bus->boardinfo.rev;
+ dev->board_rev = sdev->bus->sprom.board_rev;
dev->chip_id = sdev->bus->chip_id;
dev->chip_rev = sdev->bus->chip_rev;
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index b5f1b91002bb..777cd74921d7 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -1109,7 +1109,7 @@ static bool b43_dma_translation_in_low_word(struct b43_wldev *dev,
#ifdef CONFIG_B43_SSB
if (dev->dev->bus_type == B43_BUS_SSB &&
dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI &&
- !(dev->dev->sdev->bus->host_pci->is_pcie &&
+ !(pci_is_pcie(dev->dev->sdev->bus->host_pci) &&
ssb_read32(dev->dev->sdev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64))
return 1;
#endif
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 617afc8211b2..5a39b226b2e3 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -5243,10 +5243,10 @@ static void b43_sprom_fixup(struct ssb_bus *bus)
/* boardflags workarounds */
if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL &&
- bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74)
+ bus->chip_id == 0x4301 && bus->sprom.board_rev == 0x74)
bus->sprom.boardflags_lo |= B43_BFL_BTCOEXIST;
if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
- bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40)
+ bus->boardinfo.type == 0x4E && bus->sprom.board_rev > 0x40)
bus->sprom.boardflags_lo |= B43_BFL_PACTRL;
if (bus->bustype == SSB_BUSTYPE_PCI) {
pdev = bus->host_pci;
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 1be214b815fb..cd9c9bc186d9 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -1573,8 +1573,6 @@ static void b43legacy_request_firmware(struct work_struct *work)
const char *filename;
int err;
- /* do dummy read */
- ssb_read32(dev->dev, SSB_TMSHIGH);
if (!fw->ucode) {
if (rev == 2)
filename = "ucode2";
@@ -3781,7 +3779,7 @@ static void b43legacy_sprom_fixup(struct ssb_bus *bus)
/* boardflags workarounds */
if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
bus->boardinfo.type == 0x4E &&
- bus->boardinfo.rev > 0x40)
+ bus->sprom.board_rev > 0x40)
bus->sprom.boardflags_lo |= B43legacy_BFL_PACTRL;
}
diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c
index 950334197f40..995c7d0c212a 100644
--- a/drivers/net/wireless/b43legacy/phy.c
+++ b/drivers/net/wireless/b43legacy/phy.c
@@ -408,7 +408,7 @@ static void b43legacy_phy_setupg(struct b43legacy_wldev *dev)
if (is_bcm_board_vendor(dev) &&
(dev->dev->bus->boardinfo.type == 0x0416) &&
- (dev->dev->bus->boardinfo.rev == 0x0017))
+ (dev->dev->bus->sprom.board_rev == 0x0017))
return;
b43legacy_ilt_write(dev, 0x5001, 0x0002);
@@ -424,7 +424,7 @@ static void b43legacy_phy_setupg(struct b43legacy_wldev *dev)
if (is_bcm_board_vendor(dev) &&
(dev->dev->bus->boardinfo.type == 0x0416) &&
- (dev->dev->bus->boardinfo.rev == 0x0017))
+ (dev->dev->bus->sprom.board_rev == 0x0017))
return;
b43legacy_ilt_write(dev, 0x0401, 0x0002);
diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c
index fcbafcd603cc..896177690394 100644
--- a/drivers/net/wireless/b43legacy/radio.c
+++ b/drivers/net/wireless/b43legacy/radio.c
@@ -1998,7 +1998,7 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev)
if (phy->type == B43legacy_PHYTYPE_G) {
if (is_bcm_board_vendor(dev) &&
dev->dev->bus->boardinfo.type == 0x421 &&
- dev->dev->bus->boardinfo.rev >= 30)
+ dev->dev->bus->sprom.board_rev >= 30)
att = 3;
else if (is_bcm_board_vendor(dev) &&
dev->dev->bus->boardinfo.type == 0x416)
@@ -2008,7 +2008,7 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev)
} else {
if (is_bcm_board_vendor(dev) &&
dev->dev->bus->boardinfo.type == 0x421 &&
- dev->dev->bus->boardinfo.rev >= 30)
+ dev->dev->bus->sprom.board_rev >= 30)
att = 7;
else
att = 6;
@@ -2018,7 +2018,7 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev)
if (phy->type == B43legacy_PHYTYPE_G) {
if (is_bcm_board_vendor(dev) &&
dev->dev->bus->boardinfo.type == 0x421 &&
- dev->dev->bus->boardinfo.rev >= 30)
+ dev->dev->bus->sprom.board_rev >= 30)
att = 3;
else if (is_bcm_board_vendor(dev) &&
dev->dev->bus->boardinfo.type ==
@@ -2052,9 +2052,9 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev)
}
if (is_bcm_board_vendor(dev) &&
dev->dev->bus->boardinfo.type == 0x421) {
- if (dev->dev->bus->boardinfo.rev < 0x43)
+ if (dev->dev->bus->sprom.board_rev < 0x43)
att = 2;
- else if (dev->dev->bus->boardinfo.rev < 0x51)
+ else if (dev->dev->bus->sprom.board_rev < 0x51)
att = 3;
}
if (att == 0xFFFF)
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
index 4add7da24681..e2480d196276 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
@@ -85,18 +85,15 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
sdiodev->irq_wake = true;
/* must configure SDIO_CCCR_IENx to enable irq */
- data = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_0,
- SDIO_CCCR_IENx, &ret);
+ data = brcmf_sdio_regrb(sdiodev, SDIO_CCCR_IENx, &ret);
data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1;
- brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_IENx,
- data, &ret);
+ brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret);
/* redirect, configure ane enable io for interrupt signal */
data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;
if (sdiodev->irq_flags | IRQF_TRIGGER_HIGH)
data |= SDIO_SEPINT_ACT_HI;
- brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_BRCM_SEPINT,
- data, &ret);
+ brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);
return 0;
}
@@ -105,9 +102,8 @@ int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
{
brcmf_dbg(TRACE, "Entering\n");
- brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_BRCM_SEPINT,
- 0, NULL);
- brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_IENx, 0, NULL);
+ brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
+ brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
if (sdiodev->irq_wake) {
disable_irq_wake(sdiodev->irq);
@@ -158,153 +154,147 @@ int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
}
#endif /* CONFIG_BRCMFMAC_SDIO_OOB */
-u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr,
- int *err)
-{
- int status;
- s32 retry = 0;
- u8 data = 0;
-
- do {
- if (retry) /* wait for 1 ms till bus get settled down */
- udelay(1000);
- status = brcmf_sdioh_request_byte(sdiodev, SDIOH_READ, fnc_num,
- addr, (u8 *) &data);
- } while (status != 0
- && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
- if (err)
- *err = status;
-
- brcmf_dbg(INFO, "fun = %d, addr = 0x%x, u8data = 0x%x\n",
- fnc_num, addr, data);
-
- return data;
-}
-
-void
-brcmf_sdcard_cfg_write(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr,
- u8 data, int *err)
-{
- int status;
- s32 retry = 0;
-
- do {
- if (retry) /* wait for 1 ms till bus get settled down */
- udelay(1000);
- status = brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, fnc_num,
- addr, (u8 *) &data);
- } while (status != 0
- && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
- if (err)
- *err = status;
-
- brcmf_dbg(INFO, "fun = %d, addr = 0x%x, u8data = 0x%x\n",
- fnc_num, addr, data);
-}
-
int
brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
{
- int err = 0;
- brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
- (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
- if (!err)
- brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_SBADDRMID,
- (address >> 16) & SBSDIO_SBADDRMID_MASK,
- &err);
- if (!err)
- brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_SBADDRHIGH,
- (address >> 24) & SBSDIO_SBADDRHIGH_MASK,
- &err);
+ int err = 0, i;
+ u8 addr[3];
+ s32 retry;
+
+ addr[0] = (address >> 8) & SBSDIO_SBADDRLOW_MASK;
+ addr[1] = (address >> 16) & SBSDIO_SBADDRMID_MASK;
+ addr[2] = (address >> 24) & SBSDIO_SBADDRHIGH_MASK;
+
+ for (i = 0; i < 3; i++) {
+ retry = 0;
+ do {
+ if (retry)
+ usleep_range(1000, 2000);
+ err = brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE,
+ SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW + i,
+ &addr[i]);
+ } while (err != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
+
+ if (err) {
+ brcmf_dbg(ERROR, "failed at addr:0x%0x\n",
+ SBSDIO_FUNC1_SBADDRLOW + i);
+ break;
+ }
+ }
return err;
}
-u32 brcmf_sdcard_reg_read(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size)
+static int
+brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
+ void *data, bool write)
{
- int status;
- u32 word = 0;
- uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
-
- brcmf_dbg(INFO, "fun = 1, addr = 0x%x\n", addr);
-
- if (bar0 != sdiodev->sbwad) {
- if (brcmf_sdcard_set_sbaddr_window(sdiodev, bar0))
- return 0xFFFFFFFF;
+ u8 func_num, reg_size;
+ u32 bar;
+ s32 retry = 0;
+ int ret;
- sdiodev->sbwad = bar0;
+ /*
+ * figure out how to read the register based on address range
+ * 0x00 ~ 0x7FF: function 0 CCCR and FBR
+ * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
+ * The rest: function 1 silicon backplane core registers
+ */
+ if ((addr & ~REG_F0_REG_MASK) == 0) {
+ func_num = SDIO_FUNC_0;
+ reg_size = 1;
+ } else if ((addr & ~REG_F1_MISC_MASK) == 0) {
+ func_num = SDIO_FUNC_1;
+ reg_size = 1;
+ } else {
+ func_num = SDIO_FUNC_1;
+ reg_size = 4;
+
+ /* Set the window for SB core register */
+ bar = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
+ if (bar != sdiodev->sbwad) {
+ ret = brcmf_sdcard_set_sbaddr_window(sdiodev, bar);
+ if (ret != 0) {
+ memset(data, 0xFF, reg_size);
+ return ret;
+ }
+ sdiodev->sbwad = bar;
+ }
+ addr &= SBSDIO_SB_OFT_ADDR_MASK;
+ addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
}
- addr &= SBSDIO_SB_OFT_ADDR_MASK;
- if (size == 4)
- addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
+ do {
+ if (!write)
+ memset(data, 0, reg_size);
+ if (retry) /* wait for 1 ms till bus get settled down */
+ usleep_range(1000, 2000);
+ if (reg_size == 1)
+ ret = brcmf_sdioh_request_byte(sdiodev, write,
+ func_num, addr, data);
+ else
+ ret = brcmf_sdioh_request_word(sdiodev, write,
+ func_num, addr, data, 4);
+ } while (ret != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
- status = brcmf_sdioh_request_word(sdiodev, SDIOH_READ, SDIO_FUNC_1,
- addr, &word, size);
+ if (ret != 0)
+ brcmf_dbg(ERROR, "failed with %d\n", ret);
- sdiodev->regfail = (status != 0);
+ return ret;
+}
- brcmf_dbg(INFO, "u32data = 0x%x\n", word);
+u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
+{
+ u8 data;
+ int retval;
- /* if ok, return appropriately masked word */
- if (status == 0) {
- switch (size) {
- case sizeof(u8):
- return word & 0xff;
- case sizeof(u16):
- return word & 0xffff;
- case sizeof(u32):
- return word;
- default:
- sdiodev->regfail = true;
+ brcmf_dbg(INFO, "addr:0x%08x\n", addr);
+ retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
+ brcmf_dbg(INFO, "data:0x%02x\n", data);
- }
- }
+ if (ret)
+ *ret = retval;
- /* otherwise, bad sdio access or invalid size */
- brcmf_dbg(ERROR, "error reading addr 0x%04x size %d\n", addr, size);
- return 0xFFFFFFFF;
+ return data;
}
-u32 brcmf_sdcard_reg_write(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size,
- u32 data)
+u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
{
- int status;
- uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
- int err = 0;
+ u32 data;
+ int retval;
- brcmf_dbg(INFO, "fun = 1, addr = 0x%x, uint%ddata = 0x%x\n",
- addr, size * 8, data);
+ brcmf_dbg(INFO, "addr:0x%08x\n", addr);
+ retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
+ brcmf_dbg(INFO, "data:0x%08x\n", data);
- if (bar0 != sdiodev->sbwad) {
- err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
- if (err)
- return err;
+ if (ret)
+ *ret = retval;
- sdiodev->sbwad = bar0;
- }
+ return data;
+}
- addr &= SBSDIO_SB_OFT_ADDR_MASK;
- if (size == 4)
- addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
- status =
- brcmf_sdioh_request_word(sdiodev, SDIOH_WRITE, SDIO_FUNC_1,
- addr, &data, size);
- sdiodev->regfail = (status != 0);
+void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
+ u8 data, int *ret)
+{
+ int retval;
- if (status == 0)
- return 0;
+ brcmf_dbg(INFO, "addr:0x%08x, data:0x%02x\n", addr, data);
+ retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
- brcmf_dbg(ERROR, "error writing 0x%08x to addr 0x%04x size %d\n",
- data, addr, size);
- return 0xFFFFFFFF;
+ if (ret)
+ *ret = retval;
}
-bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev)
+void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
+ u32 data, int *ret)
{
- return sdiodev->regfail;
+ int retval;
+
+ brcmf_dbg(INFO, "addr:0x%08x, data:0x%08x\n", addr, data);
+ retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
+
+ if (ret)
+ *ret = retval;
}
static int brcmf_sdcard_recv_prepare(struct brcmf_sdio_dev *sdiodev, uint fn,
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
index dd07d33a927c..82f51dbd0d66 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
@@ -346,43 +346,17 @@ int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev,
return status;
}
-/* Read client card reg */
-static int
-brcmf_sdioh_card_regread(struct brcmf_sdio_dev *sdiodev, int func, u32 regaddr,
- int regsize, u32 *data)
-{
-
- if ((func == 0) || (regsize == 1)) {
- u8 temp = 0;
-
- brcmf_sdioh_request_byte(sdiodev, SDIOH_READ, func, regaddr,
- &temp);
- *data = temp;
- *data &= 0xff;
- brcmf_dbg(DATA, "byte read data=0x%02x\n", *data);
- } else {
- brcmf_sdioh_request_word(sdiodev, SDIOH_READ, func, regaddr,
- data, regsize);
- if (regsize == 2)
- *data &= 0xffff;
-
- brcmf_dbg(DATA, "word read data=0x%08x\n", *data);
- }
-
- return SUCCESS;
-}
-
static int brcmf_sdioh_get_cisaddr(struct brcmf_sdio_dev *sdiodev, u32 regaddr)
{
/* read 24 bits and return valid 17 bit addr */
- int i;
+ int i, ret;
u32 scratch, regdata;
__le32 scratch_le;
u8 *ptr = (u8 *)&scratch_le;
for (i = 0; i < 3; i++) {
- if ((brcmf_sdioh_card_regread(sdiodev, 0, regaddr, 1,
- &regdata)) != SUCCESS)
+ regdata = brcmf_sdio_regrl(sdiodev, regaddr, &ret);
+ if (ret != 0)
brcmf_dbg(ERROR, "Can't read!\n");
*ptr++ = (u8) regdata;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
index 149ee67beb2e..1dbf2be478c8 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
@@ -629,43 +629,29 @@ static bool data_ok(struct brcmf_sdio *bus)
* Reads a register in the SDIO hardware block. This block occupies a series of
* adresses on the 32 bit backplane bus.
*/
-static void
-r_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 reg_offset, u32 *retryvar)
+static int
+r_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 offset)
{
u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
- *retryvar = 0;
- do {
- *regvar = brcmf_sdcard_reg_read(bus->sdiodev,
- bus->ci->c_inf[idx].base + reg_offset,
- sizeof(u32));
- } while (brcmf_sdcard_regfail(bus->sdiodev) &&
- (++(*retryvar) <= retry_limit));
- if (*retryvar) {
- bus->regfails += (*retryvar-1);
- if (*retryvar > retry_limit) {
- brcmf_dbg(ERROR, "FAILED READ %Xh\n", reg_offset);
- *regvar = 0;
- }
- }
+ int ret;
+
+ *regvar = brcmf_sdio_regrl(bus->sdiodev,
+ bus->ci->c_inf[idx].base + offset, &ret);
+
+ return ret;
}
-static void
-w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset, u32 *retryvar)
+static int
+w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset)
{
u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
- *retryvar = 0;
- do {
- brcmf_sdcard_reg_write(bus->sdiodev,
- bus->ci->c_inf[idx].base + reg_offset,
- sizeof(u32), regval);
- } while (brcmf_sdcard_regfail(bus->sdiodev) &&
- (++(*retryvar) <= retry_limit));
- if (*retryvar) {
- bus->regfails += (*retryvar-1);
- if (*retryvar > retry_limit)
- brcmf_dbg(ERROR, "FAILED REGISTER WRITE %Xh\n",
- reg_offset);
- }
+ int ret;
+
+ brcmf_sdio_regwl(bus->sdiodev,
+ bus->ci->c_inf[idx].base + reg_offset,
+ regval, &ret);
+
+ return ret;
}
#define PKT_AVAILABLE() (intstatus & I_HMB_FRAME_IND)
@@ -697,16 +683,16 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
clkreq =
bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+ clkreq, &err);
if (err) {
brcmf_dbg(ERROR, "HT Avail request error: %d\n", err);
return -EBADE;
}
/* Check current status */
- clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, &err);
+ clkctl = brcmf_sdio_regrb(bus->sdiodev,
+ SBSDIO_FUNC1_CHIPCLKCSR, &err);
if (err) {
brcmf_dbg(ERROR, "HT Avail read error: %d\n", err);
return -EBADE;
@@ -715,9 +701,8 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
/* Go to pending and await interrupt if appropriate */
if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
/* Allow only clock-available interrupt */
- devctl = brcmf_sdcard_cfg_read(bus->sdiodev,
- SDIO_FUNC_1,
- SBSDIO_DEVICE_CTL, &err);
+ devctl = brcmf_sdio_regrb(bus->sdiodev,
+ SBSDIO_DEVICE_CTL, &err);
if (err) {
brcmf_dbg(ERROR, "Devctl error setting CA: %d\n",
err);
@@ -725,30 +710,28 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
}
devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_DEVICE_CTL, devctl, &err);
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
+ devctl, &err);
brcmf_dbg(INFO, "CLKCTL: set PENDING\n");
bus->clkstate = CLK_PENDING;
return 0;
} else if (bus->clkstate == CLK_PENDING) {
/* Cancel CA-only interrupt filter */
- devctl =
- brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ devctl = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_DEVICE_CTL, &err);
devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_DEVICE_CTL, devctl, &err);
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
+ devctl, &err);
}
/* Otherwise, wait here (polling) for HT Avail */
timeout = jiffies +
msecs_to_jiffies(PMU_MAX_TRANSITION_DLY/1000);
while (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
- clkctl = brcmf_sdcard_cfg_read(bus->sdiodev,
- SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR,
- &err);
+ clkctl = brcmf_sdio_regrb(bus->sdiodev,
+ SBSDIO_FUNC1_CHIPCLKCSR,
+ &err);
if (time_after(jiffies, timeout))
break;
else
@@ -781,17 +764,16 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
if (bus->clkstate == CLK_PENDING) {
/* Cancel CA-only interrupt filter */
- devctl = brcmf_sdcard_cfg_read(bus->sdiodev,
- SDIO_FUNC_1,
- SBSDIO_DEVICE_CTL, &err);
+ devctl = brcmf_sdio_regrb(bus->sdiodev,
+ SBSDIO_DEVICE_CTL, &err);
devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_DEVICE_CTL, devctl, &err);
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
+ devctl, &err);
}
bus->clkstate = CLK_SDONLY;
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+ clkreq, &err);
brcmf_dbg(INFO, "CLKCTL: turned OFF\n");
if (err) {
brcmf_dbg(ERROR, "Failed access turning clock off: %d\n",
@@ -874,7 +856,7 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok)
static int brcmf_sdbrcm_bussleep(struct brcmf_sdio *bus, bool sleep)
{
- uint retries = 0;
+ int ret;
brcmf_dbg(INFO, "request %s (currently %s)\n",
sleep ? "SLEEP" : "WAKE",
@@ -894,22 +876,20 @@ static int brcmf_sdbrcm_bussleep(struct brcmf_sdio *bus, bool sleep)
brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
/* Tell device to start using OOB wakeup */
- w_sdreg32(bus, SMB_USE_OOB,
- offsetof(struct sdpcmd_regs, tosbmailbox), &retries);
- if (retries > retry_limit)
+ ret = w_sdreg32(bus, SMB_USE_OOB,
+ offsetof(struct sdpcmd_regs, tosbmailbox));
+ if (ret != 0)
brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n");
/* Turn off our contribution to the HT clock request */
brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR,
- SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+ SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
/* Isolate the bus */
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_DEVICE_CTL,
- SBSDIO_DEVCTL_PADS_ISO, NULL);
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
+ SBSDIO_DEVCTL_PADS_ISO, NULL);
/* Change state */
bus->sleeping = true;
@@ -917,21 +897,20 @@ static int brcmf_sdbrcm_bussleep(struct brcmf_sdio *bus, bool sleep)
} else {
/* Waking up: bus power up is ok, set local state */
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+ 0, NULL);
/* Make sure the controller has the bus up */
brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
/* Send misc interrupt to indicate OOB not needed */
- w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, tosbmailboxdata),
- &retries);
- if (retries <= retry_limit)
- w_sdreg32(bus, SMB_DEV_INT,
- offsetof(struct sdpcmd_regs, tosbmailbox),
- &retries);
-
- if (retries > retry_limit)
+ ret = w_sdreg32(bus, 0,
+ offsetof(struct sdpcmd_regs, tosbmailboxdata));
+ if (ret == 0)
+ ret = w_sdreg32(bus, SMB_DEV_INT,
+ offsetof(struct sdpcmd_regs, tosbmailbox));
+
+ if (ret != 0)
brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP TO CLEAR OOB!!\n");
/* Make sure we have SD bus access */
@@ -955,17 +934,17 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
u32 intstatus = 0;
u32 hmb_data;
u8 fcbits;
- uint retries = 0;
+ int ret;
brcmf_dbg(TRACE, "Enter\n");
/* Read mailbox data and ack that we did so */
- r_sdreg32(bus, &hmb_data,
- offsetof(struct sdpcmd_regs, tohostmailboxdata), &retries);
+ ret = r_sdreg32(bus, &hmb_data,
+ offsetof(struct sdpcmd_regs, tohostmailboxdata));
- if (retries <= retry_limit)
+ if (ret == 0)
w_sdreg32(bus, SMB_INT_ACK,
- offsetof(struct sdpcmd_regs, tosbmailbox), &retries);
+ offsetof(struct sdpcmd_regs, tosbmailbox));
bus->f1regdata += 2;
/* Dongle recomposed rx frames, accept them again */
@@ -1040,17 +1019,16 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
if (abort)
brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_FRAMECTRL,
- SFC_RF_TERM, &err);
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
+ SFC_RF_TERM, &err);
bus->f1regdata++;
/* Wait until the packet has been flushed (device/FIFO stable) */
for (lastrbc = retries = 0xffff; retries > 0; retries--) {
- hi = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_RFRAMEBCHI, NULL);
- lo = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_RFRAMEBCLO, NULL);
+ hi = brcmf_sdio_regrb(bus->sdiodev,
+ SBSDIO_FUNC1_RFRAMEBCHI, &err);
+ lo = brcmf_sdio_regrb(bus->sdiodev,
+ SBSDIO_FUNC1_RFRAMEBCLO, &err);
bus->f1regdata += 2;
if ((hi == 0) && (lo == 0))
@@ -1070,11 +1048,11 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
if (rtx) {
bus->rxrtx++;
- w_sdreg32(bus, SMB_NAK,
- offsetof(struct sdpcmd_regs, tosbmailbox), &retries);
+ err = w_sdreg32(bus, SMB_NAK,
+ offsetof(struct sdpcmd_regs, tosbmailbox));
bus->f1regdata++;
- if (retries <= retry_limit)
+ if (err == 0)
bus->rxskip = true;
}
@@ -1082,7 +1060,7 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
bus->nextlen = 0;
/* If we can't reach the device, signal failure */
- if (err || brcmf_sdcard_regfail(bus->sdiodev))
+ if (err)
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
}
@@ -2178,21 +2156,16 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
bus->tx_sderrs++;
brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM,
- NULL);
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
+ SFC_WF_TERM, NULL);
bus->f1regdata++;
for (i = 0; i < 3; i++) {
u8 hi, lo;
- hi = brcmf_sdcard_cfg_read(bus->sdiodev,
- SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCHI,
- NULL);
- lo = brcmf_sdcard_cfg_read(bus->sdiodev,
- SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCLO,
- NULL);
+ hi = brcmf_sdio_regrb(bus->sdiodev,
+ SBSDIO_FUNC1_WFRAMEBCHI, NULL);
+ lo = brcmf_sdio_regrb(bus->sdiodev,
+ SBSDIO_FUNC1_WFRAMEBCLO, NULL);
bus->f1regdata += 2;
if ((hi == 0) && (lo == 0))
break;
@@ -2219,7 +2192,6 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
{
struct sk_buff *pkt;
u32 intstatus = 0;
- uint retries = 0;
int ret = 0, prec_out;
uint cnt = 0;
uint datalen;
@@ -2249,11 +2221,11 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
/* In poll mode, need to check for other events */
if (!bus->intr && cnt) {
/* Check device status, signal pending interrupt */
- r_sdreg32(bus, &intstatus,
- offsetof(struct sdpcmd_regs, intstatus),
- &retries);
+ ret = r_sdreg32(bus, &intstatus,
+ offsetof(struct sdpcmd_regs,
+ intstatus));
bus->f2txdata++;
- if (brcmf_sdcard_regfail(bus->sdiodev))
+ if (ret != 0)
break;
if (intstatus & bus->hostintmask)
bus->ipend = true;
@@ -2275,7 +2247,6 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
{
u32 local_hostintmask;
u8 saveclk;
- uint retries;
int err;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
@@ -2303,7 +2274,7 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
/* Disable and clear interrupts at the chip level also */
- w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask), &retries);
+ w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask));
local_hostintmask = bus->hostintmask;
bus->hostintmask = 0;
@@ -2311,24 +2282,23 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
/* Force clocks on backplane to be sure F2 interrupt propagates */
- saveclk = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, &err);
+ saveclk = brcmf_sdio_regrb(bus->sdiodev,
+ SBSDIO_FUNC1_CHIPCLKCSR, &err);
if (!err) {
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR,
- (saveclk | SBSDIO_FORCE_HT), &err);
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+ (saveclk | SBSDIO_FORCE_HT), &err);
}
if (err)
brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err);
/* Turn off the bus (F2), free any pending packets */
brcmf_dbg(INTR, "disable SDIO interrupts\n");
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
- SDIO_FUNC_ENABLE_1, NULL);
+ brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx, SDIO_FUNC_ENABLE_1,
+ NULL);
/* Clear any pending interrupts now that F2 is disabled */
w_sdreg32(bus, local_hostintmask,
- offsetof(struct sdpcmd_regs, intstatus), &retries);
+ offsetof(struct sdpcmd_regs, intstatus));
/* Turn off the backplane clock (only) */
brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
@@ -2373,12 +2343,12 @@ static inline void brcmf_sdbrcm_clrintr(struct brcmf_sdio *bus)
static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
{
u32 intstatus, newstatus = 0;
- uint retries = 0;
uint rxlimit = bus->rxbound; /* Rx frames to read before resched */
uint txlimit = bus->txbound; /* Tx frames to send before resched */
uint framecnt = 0; /* Temporary counter of tx/rx frames */
bool rxdone = true; /* Flag for no more read data */
bool resched = false; /* Flag indicating resched wanted */
+ int err;
brcmf_dbg(TRACE, "Enter\n");
@@ -2389,13 +2359,12 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
/* If waiting for HTAVAIL, check status */
if (bus->clkstate == CLK_PENDING) {
- int err;
u8 clkctl, devctl = 0;
#ifdef DEBUG
/* Check for inconsistent device control */
- devctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_DEVICE_CTL, &err);
+ devctl = brcmf_sdio_regrb(bus->sdiodev,
+ SBSDIO_DEVICE_CTL, &err);
if (err) {
brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", err);
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
@@ -2403,8 +2372,8 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
#endif /* DEBUG */
/* Read CSR, if clock on switch to AVAIL, else ignore */
- clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, &err);
+ clkctl = brcmf_sdio_regrb(bus->sdiodev,
+ SBSDIO_FUNC1_CHIPCLKCSR, &err);
if (err) {
brcmf_dbg(ERROR, "error reading CSR: %d\n",
err);
@@ -2415,17 +2384,16 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
devctl, clkctl);
if (SBSDIO_HTAV(clkctl)) {
- devctl = brcmf_sdcard_cfg_read(bus->sdiodev,
- SDIO_FUNC_1,
- SBSDIO_DEVICE_CTL, &err);
+ devctl = brcmf_sdio_regrb(bus->sdiodev,
+ SBSDIO_DEVICE_CTL, &err);
if (err) {
brcmf_dbg(ERROR, "error reading DEVCTL: %d\n",
err);
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
}
devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_DEVICE_CTL, devctl, &err);
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
+ devctl, &err);
if (err) {
brcmf_dbg(ERROR, "error writing DEVCTL: %d\n",
err);
@@ -2447,17 +2415,17 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
/* Pending interrupt indicates new device status */
if (bus->ipend) {
bus->ipend = false;
- r_sdreg32(bus, &newstatus,
- offsetof(struct sdpcmd_regs, intstatus), &retries);
+ err = r_sdreg32(bus, &newstatus,
+ offsetof(struct sdpcmd_regs, intstatus));
bus->f1regdata++;
- if (brcmf_sdcard_regfail(bus->sdiodev))
+ if (err != 0)
newstatus = 0;
newstatus &= bus->hostintmask;
bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
if (newstatus) {
- w_sdreg32(bus, newstatus,
- offsetof(struct sdpcmd_regs, intstatus),
- &retries);
+ err = w_sdreg32(bus, newstatus,
+ offsetof(struct sdpcmd_regs,
+ intstatus));
bus->f1regdata++;
}
}
@@ -2472,11 +2440,11 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
*/
if (intstatus & I_HMB_FC_CHANGE) {
intstatus &= ~I_HMB_FC_CHANGE;
- w_sdreg32(bus, I_HMB_FC_CHANGE,
- offsetof(struct sdpcmd_regs, intstatus), &retries);
+ err = w_sdreg32(bus, I_HMB_FC_CHANGE,
+ offsetof(struct sdpcmd_regs, intstatus));
- r_sdreg32(bus, &newstatus,
- offsetof(struct sdpcmd_regs, intstatus), &retries);
+ err = r_sdreg32(bus, &newstatus,
+ offsetof(struct sdpcmd_regs, intstatus));
bus->f1regdata += 2;
bus->fcstate =
!!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
@@ -2546,21 +2514,18 @@ clkwait:
brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM,
- NULL);
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
+ SFC_WF_TERM, &err);
bus->f1regdata++;
for (i = 0; i < 3; i++) {
u8 hi, lo;
- hi = brcmf_sdcard_cfg_read(bus->sdiodev,
- SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCHI,
- NULL);
- lo = brcmf_sdcard_cfg_read(bus->sdiodev,
- SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCLO,
- NULL);
+ hi = brcmf_sdio_regrb(bus->sdiodev,
+ SBSDIO_FUNC1_WFRAMEBCHI,
+ &err);
+ lo = brcmf_sdio_regrb(bus->sdiodev,
+ SBSDIO_FUNC1_WFRAMEBCLO,
+ &err);
bus->f1regdata += 2;
if ((hi == 0) && (lo == 0))
break;
@@ -2587,10 +2552,8 @@ clkwait:
else await next interrupt */
/* On failed register access, all bets are off:
no resched or interrupts */
- if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) ||
- brcmf_sdcard_regfail(bus->sdiodev)) {
- brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation %d\n",
- brcmf_sdcard_regfail(bus->sdiodev));
+ if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) || (err != 0)) {
+ brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation\n");
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
bus->intstatus = 0;
} else if (bus->clkstate == CLK_PENDING) {
@@ -2886,19 +2849,16 @@ static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_FRAMECTRL,
- SFC_WF_TERM, NULL);
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
+ SFC_WF_TERM, NULL);
bus->f1regdata++;
for (i = 0; i < 3; i++) {
u8 hi, lo;
- hi = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCHI,
- NULL);
- lo = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_WFRAMEBCLO,
- NULL);
+ hi = brcmf_sdio_regrb(bus->sdiodev,
+ SBSDIO_FUNC1_WFRAMEBCHI, NULL);
+ lo = brcmf_sdio_regrb(bus->sdiodev,
+ SBSDIO_FUNC1_WFRAMEBCLO, NULL);
bus->f1regdata += 2;
if (hi == 0 && lo == 0)
break;
@@ -3188,7 +3148,6 @@ static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus)
static int brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter)
{
- uint retries;
int bcmerror = 0;
struct chip_info *ci = bus->ci;
@@ -3222,7 +3181,7 @@ static int brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter)
}
w_sdreg32(bus, 0xFFFFFFFF,
- offsetof(struct sdpcmd_regs, intstatus), &retries);
+ offsetof(struct sdpcmd_regs, intstatus));
ci->resetcore(bus->sdiodev, ci, BCMA_CORE_ARM_CM3);
@@ -3444,7 +3403,6 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
struct brcmf_sdio *bus = sdiodev->bus;
unsigned long timeout;
- uint retries = 0;
u8 ready, enable;
int err, ret = 0;
u8 saveclk;
@@ -3472,13 +3430,11 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
goto exit;
/* Force clocks on backplane to be sure F2 interrupt propagates */
- saveclk =
- brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, &err);
+ saveclk = brcmf_sdio_regrb(bus->sdiodev,
+ SBSDIO_FUNC1_CHIPCLKCSR, &err);
if (!err) {
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR,
- (saveclk | SBSDIO_FORCE_HT), &err);
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+ (saveclk | SBSDIO_FORCE_HT), &err);
}
if (err) {
brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err);
@@ -3487,17 +3443,16 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
/* Enable function 2 (frame transfers) */
w_sdreg32(bus, SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT,
- offsetof(struct sdpcmd_regs, tosbmailboxdata), &retries);
+ offsetof(struct sdpcmd_regs, tosbmailboxdata));
enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
- enable, NULL);
+ brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx, enable, NULL);
timeout = jiffies + msecs_to_jiffies(BRCMF_WAIT_F2RDY);
ready = 0;
while (enable != ready) {
- ready = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_0,
- SDIO_CCCR_IORx, NULL);
+ ready = brcmf_sdio_regrb(bus->sdiodev,
+ SDIO_CCCR_IORx, NULL);
if (time_after(jiffies, timeout))
break;
else if (time_after(jiffies, timeout - BRCMF_WAIT_F2RDY + 50))
@@ -3512,21 +3467,18 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
/* Set up the interrupt mask and enable interrupts */
bus->hostintmask = HOSTINTMASK;
w_sdreg32(bus, bus->hostintmask,
- offsetof(struct sdpcmd_regs, hostintmask), &retries);
+ offsetof(struct sdpcmd_regs, hostintmask));
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_WATERMARK, 8, &err);
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_WATERMARK, 8, &err);
} else {
/* Disable F2 again */
enable = SDIO_FUNC_ENABLE_1;
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0,
- SDIO_CCCR_IOEx, enable, NULL);
+ brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx, enable, NULL);
ret = -ENODEV;
}
/* Restore previous clock setting */
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
if (ret == 0) {
ret = brcmf_sdio_intr_register(bus->sdiodev);
@@ -3606,9 +3558,9 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
if (!bus->dpc_sched) {
u8 devpend;
- devpend = brcmf_sdcard_cfg_read(bus->sdiodev,
- SDIO_FUNC_0, SDIO_CCCR_INTx,
- NULL);
+ devpend = brcmf_sdio_regrb(bus->sdiodev,
+ SDIO_CCCR_INTx,
+ NULL);
intstatus =
devpend & (INTR_STATUS_FUNC1 |
INTR_STATUS_FUNC2);
@@ -3732,24 +3684,18 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
bus->alp_only = true;
- /* Return the window to backplane enumeration space for core access */
- if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, SI_ENUM_BASE))
- brcmf_dbg(ERROR, "FAILED to return to SI_ENUM_BASE\n");
-
pr_debug("F1 signature read @0x18000000=0x%4x\n",
- brcmf_sdcard_reg_read(bus->sdiodev, SI_ENUM_BASE, 4));
+ brcmf_sdio_regrl(bus->sdiodev, SI_ENUM_BASE, NULL));
/*
* Force PLL off until brcmf_sdio_chip_attach()
* programs PLL control regs
*/
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR,
- BRCMF_INIT_CLKCTL1, &err);
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
+ BRCMF_INIT_CLKCTL1, &err);
if (!err)
- clkctl =
- brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
+ clkctl = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR, &err);
if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) {
@@ -3782,9 +3728,8 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
reg_addr = bus->ci->c_inf[idx].base +
offsetof(struct sdpcmd_regs, corecontrol);
- reg_val = brcmf_sdcard_reg_read(bus->sdiodev, reg_addr, sizeof(u32));
- brcmf_sdcard_reg_write(bus->sdiodev, reg_addr, sizeof(u32),
- reg_val | CC_BPRESEN);
+ reg_val = brcmf_sdio_regrl(bus->sdiodev, reg_addr, NULL);
+ brcmf_sdio_regwl(bus->sdiodev, reg_addr, reg_val | CC_BPRESEN, NULL);
brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);
@@ -3809,16 +3754,15 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus)
brcmf_dbg(TRACE, "Enter\n");
/* Disable F2 to clear any intermediate frame state on the dongle */
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
- SDIO_FUNC_ENABLE_1, NULL);
+ brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx,
+ SDIO_FUNC_ENABLE_1, NULL);
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
bus->sleeping = false;
bus->rxflow = false;
/* Done with backplane-dependent accesses, can drop clock... */
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
+ brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
/* ...and initialize clock/power states */
bus->clkstate = CLK_SDONLY;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
index 1534efc21631..f8e1f1c84d08 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
@@ -93,8 +93,9 @@ brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev,
idx = brcmf_sdio_chip_getinfidx(ci, coreid);
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbidhigh), 4);
+ regdata = brcmf_sdio_regrl(sdiodev,
+ CORE_SB(ci->c_inf[idx].base, sbidhigh),
+ NULL);
return SBCOREREV(regdata);
}
@@ -118,8 +119,9 @@ brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev,
idx = brcmf_sdio_chip_getinfidx(ci, coreid);
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+ regdata = brcmf_sdio_regrl(sdiodev,
+ CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
+ NULL);
regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT |
SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK);
return (SSB_TMSLOW_CLOCK == regdata);
@@ -135,13 +137,13 @@ brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
idx = brcmf_sdio_chip_getinfidx(ci, coreid);
- regdata = brcmf_sdcard_reg_read(sdiodev,
- ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
+ regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+ NULL);
ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK;
- regdata = brcmf_sdcard_reg_read(sdiodev,
- ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
- 4);
+ regdata = brcmf_sdio_regrl(sdiodev,
+ ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
+ NULL);
ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0);
return ret;
@@ -151,84 +153,85 @@ static void
brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
struct chip_info *ci, u16 coreid)
{
- u32 regdata;
+ u32 regdata, base;
u8 idx;
idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+ base = ci->c_inf[idx].base;
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+ regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
if (regdata & SSB_TMSLOW_RESET)
return;
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+ regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
if ((regdata & SSB_TMSLOW_CLOCK) != 0) {
/*
* set target reject and spin until busy is clear
* (preserve core-specific bits)
*/
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
- brcmf_sdcard_reg_write(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
- 4, regdata | SSB_TMSLOW_REJECT);
-
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+ regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow),
+ NULL);
+ brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
+ regdata | SSB_TMSLOW_REJECT, NULL);
+
+ regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow),
+ NULL);
udelay(1);
- SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4) &
+ SPINWAIT((brcmf_sdio_regrl(sdiodev,
+ CORE_SB(base, sbtmstatehigh),
+ NULL) &
SSB_TMSHIGH_BUSY), 100000);
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4);
+ regdata = brcmf_sdio_regrl(sdiodev,
+ CORE_SB(base, sbtmstatehigh),
+ NULL);
if (regdata & SSB_TMSHIGH_BUSY)
brcmf_dbg(ERROR, "core state still busy\n");
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbidlow), 4);
+ regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbidlow),
+ NULL);
if (regdata & SSB_IDLOW_INITIATOR) {
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbimstate), 4) |
- SSB_IMSTATE_REJECT;
- brcmf_sdcard_reg_write(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
- regdata);
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbimstate), 4);
+ regdata = brcmf_sdio_regrl(sdiodev,
+ CORE_SB(base, sbimstate),
+ NULL);
+ regdata |= SSB_IMSTATE_REJECT;
+ brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbimstate),
+ regdata, NULL);
+ regdata = brcmf_sdio_regrl(sdiodev,
+ CORE_SB(base, sbimstate),
+ NULL);
udelay(1);
- SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbimstate), 4) &
+ SPINWAIT((brcmf_sdio_regrl(sdiodev,
+ CORE_SB(base, sbimstate),
+ NULL) &
SSB_IMSTATE_BUSY), 100000);
}
/* set reset and reject while enabling the clocks */
- brcmf_sdcard_reg_write(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
- (SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
- SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+ regdata = SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
+ SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET;
+ brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
+ regdata, NULL);
+ regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow),
+ NULL);
udelay(10);
/* clear the initiator reject bit */
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbidlow), 4);
+ regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbidlow),
+ NULL);
if (regdata & SSB_IDLOW_INITIATOR) {
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbimstate), 4) &
- ~SSB_IMSTATE_REJECT;
- brcmf_sdcard_reg_write(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
- regdata);
+ regdata = brcmf_sdio_regrl(sdiodev,
+ CORE_SB(base, sbimstate),
+ NULL);
+ regdata &= ~SSB_IMSTATE_REJECT;
+ brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbimstate),
+ regdata, NULL);
}
}
/* leave reset and reject asserted */
- brcmf_sdcard_reg_write(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
- (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
+ brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
+ (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET), NULL);
udelay(1);
}
@@ -242,20 +245,19 @@ brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
idx = brcmf_sdio_chip_getinfidx(ci, coreid);
/* if core is already in reset, just return */
- regdata = brcmf_sdcard_reg_read(sdiodev,
- ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
- 4);
+ regdata = brcmf_sdio_regrl(sdiodev,
+ ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
+ NULL);
if ((regdata & BCMA_RESET_CTL_RESET) != 0)
return;
- brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
- 4, 0);
- regdata = brcmf_sdcard_reg_read(sdiodev,
- ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
+ brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, 0, NULL);
+ regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+ NULL);
udelay(10);
- brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
- 4, BCMA_RESET_CTL_RESET);
+ brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
+ BCMA_RESET_CTL_RESET, NULL);
udelay(1);
}
@@ -279,41 +281,47 @@ brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
* set reset while enabling the clock and
* forcing them on throughout the core
*/
- brcmf_sdcard_reg_write(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
- SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET);
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+ brcmf_sdio_regwl(sdiodev,
+ CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
+ SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET,
+ NULL);
+ regdata = brcmf_sdio_regrl(sdiodev,
+ CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
+ NULL);
udelay(1);
/* clear any serror */
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4);
+ regdata = brcmf_sdio_regrl(sdiodev,
+ CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
+ NULL);
if (regdata & SSB_TMSHIGH_SERR)
- brcmf_sdcard_reg_write(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4, 0);
+ brcmf_sdio_regwl(sdiodev,
+ CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
+ 0, NULL);
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbimstate), 4);
+ regdata = brcmf_sdio_regrl(sdiodev,
+ CORE_SB(ci->c_inf[idx].base, sbimstate),
+ NULL);
if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO))
- brcmf_sdcard_reg_write(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
- regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO));
+ brcmf_sdio_regwl(sdiodev,
+ CORE_SB(ci->c_inf[idx].base, sbimstate),
+ regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO),
+ NULL);
/* clear reset and allow it to propagate throughout the core */
- brcmf_sdcard_reg_write(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
- SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK);
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+ brcmf_sdio_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
+ SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK, NULL);
+ regdata = brcmf_sdio_regrl(sdiodev,
+ CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
+ NULL);
udelay(1);
/* leave clock enabled */
- brcmf_sdcard_reg_write(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
- 4, SSB_TMSLOW_CLOCK);
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+ brcmf_sdio_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
+ SSB_TMSLOW_CLOCK, NULL);
+ regdata = brcmf_sdio_regrl(sdiodev,
+ CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
+ NULL);
udelay(1);
}
@@ -330,18 +338,18 @@ brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
brcmf_sdio_ai_coredisable(sdiodev, ci, coreid);
/* now do initialization sequence */
- brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
- 4, BCMA_IOCTL_FGC | BCMA_IOCTL_CLK);
- regdata = brcmf_sdcard_reg_read(sdiodev,
- ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
- brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
- 4, 0);
+ brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+ BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL);
+ regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+ NULL);
+ brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
+ 0, NULL);
udelay(1);
- brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
- 4, BCMA_IOCTL_CLK);
- regdata = brcmf_sdcard_reg_read(sdiodev,
- ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
+ brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+ BCMA_IOCTL_CLK, NULL);
+ regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+ NULL);
udelay(1);
}
@@ -358,8 +366,9 @@ static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
*/
ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
ci->c_inf[0].base = regs;
- regdata = brcmf_sdcard_reg_read(sdiodev,
- CORE_CC_REG(ci->c_inf[0].base, chipid), 4);
+ regdata = brcmf_sdio_regrl(sdiodev,
+ CORE_CC_REG(ci->c_inf[0].base, chipid),
+ NULL);
ci->chip = regdata & CID_ID_MASK;
ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
ci->socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
@@ -428,8 +437,7 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
/* Try forcing SDIO core to do ALPAvail request only */
clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
- brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
+ brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
if (err) {
brcmf_dbg(ERROR, "error writing for HT off\n");
return err;
@@ -437,8 +445,8 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
/* If register supported, wait for ALPAvail and then force ALP */
/* This may take up to 15 milliseconds */
- clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, NULL);
+ clkval = brcmf_sdio_regrb(sdiodev,
+ SBSDIO_FUNC1_CHIPCLKCSR, NULL);
if ((clkval & ~SBSDIO_AVBITS) != clkset) {
brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
@@ -446,8 +454,8 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
return -EACCES;
}
- SPINWAIT(((clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
+ SPINWAIT(((clkval = brcmf_sdio_regrb(sdiodev,
+ SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
!SBSDIO_ALPAV(clkval)),
PMU_MAX_TRANSITION_DLY);
if (!SBSDIO_ALPAV(clkval)) {
@@ -457,13 +465,11 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
}
clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
- brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
+ brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
udelay(65);
/* Also, disable the extra SDIO pull-ups */
- brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
- SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
+ brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
return 0;
}
@@ -472,18 +478,22 @@ static void
brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
struct chip_info *ci)
{
+ u32 base = ci->c_inf[0].base;
+
/* get chipcommon rev */
ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id);
/* get chipcommon capabilites */
- ci->c_inf[0].caps =
- brcmf_sdcard_reg_read(sdiodev,
- CORE_CC_REG(ci->c_inf[0].base, capabilities), 4);
+ ci->c_inf[0].caps = brcmf_sdio_regrl(sdiodev,
+ CORE_CC_REG(base, capabilities),
+ NULL);
/* get pmu caps & rev */
if (ci->c_inf[0].caps & CC_CAP_PMU) {
- ci->pmucaps = brcmf_sdcard_reg_read(sdiodev,
- CORE_CC_REG(ci->c_inf[0].base, pmucapabilities), 4);
+ ci->pmucaps =
+ brcmf_sdio_regrl(sdiodev,
+ CORE_CC_REG(base, pmucapabilities),
+ NULL);
ci->pmurev = ci->pmucaps & PCAP_REV_MASK;
}
@@ -523,10 +533,10 @@ int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
brcmf_sdio_chip_buscoresetup(sdiodev, ci);
- brcmf_sdcard_reg_write(sdiodev,
- CORE_CC_REG(ci->c_inf[0].base, gpiopullup), 4, 0);
- brcmf_sdcard_reg_write(sdiodev,
- CORE_CC_REG(ci->c_inf[0].base, gpiopulldown), 4, 0);
+ brcmf_sdio_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopullup),
+ 0, NULL);
+ brcmf_sdio_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopulldown),
+ 0, NULL);
*ci_ptr = ci;
return 0;
@@ -562,6 +572,7 @@ brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
u32 str_mask = 0;
u32 str_shift = 0;
char chn[8];
+ u32 base = ci->c_inf[0].base;
if (!(ci->c_inf[0].caps & CC_CAP_PMU))
return;
@@ -591,17 +602,17 @@ brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
}
}
- brcmf_sdcard_reg_write(sdiodev,
- CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
- 4, 1);
- cc_data_temp = brcmf_sdcard_reg_read(sdiodev,
- CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr), 4);
+ brcmf_sdio_regwl(sdiodev, CORE_CC_REG(base, chipcontrol_addr),
+ 1, NULL);
+ cc_data_temp =
+ brcmf_sdio_regrl(sdiodev,
+ CORE_CC_REG(base, chipcontrol_addr),
+ NULL);
cc_data_temp &= ~str_mask;
drivestrength_sel <<= str_shift;
cc_data_temp |= drivestrength_sel;
- brcmf_sdcard_reg_write(sdiodev,
- CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
- 4, cc_data_temp);
+ brcmf_sdio_regwl(sdiodev, CORE_CC_REG(base, chipcontrol_addr),
+ cc_data_temp, NULL);
brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n",
drivestrength, cc_data_temp);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h
index 7010eaf71f99..29bf78d264e0 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h
@@ -40,6 +40,10 @@
/* Maximum number of I/O funcs */
#define SDIOD_MAX_IOFUNCS 7
+/* mask of register map */
+#define REG_F0_REG_MASK 0x7FF
+#define REG_F1_MISC_MASK 0x1FFFF
+
/* as of sdiod rev 0, supports 3 functions */
#define SBSDIO_NUM_FUNCTION 3
@@ -142,7 +146,6 @@ struct brcmf_sdio_dev {
u8 num_funcs; /* Supported funcs on client */
u32 func_cis_ptr[SDIOD_MAX_IOFUNCS];
u32 sbwad; /* Save backplane window address */
- bool regfail; /* status of last reg_r/w call */
void *bus;
atomic_t suspend; /* suspend flag */
wait_queue_head_t request_byte_wait;
@@ -164,31 +167,13 @@ struct brcmf_sdio_dev {
extern int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev);
extern int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev);
-/* Access SDIO address space (e.g. CCCR) using CMD52 (single-byte interface).
- * fn: function number
- * addr: unmodified SDIO-space address
- * data: data byte to write
- * err: pointer to error code (or NULL)
- */
-extern u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_dev *sdiodev, uint func,
- u32 addr, int *err);
-extern void brcmf_sdcard_cfg_write(struct brcmf_sdio_dev *sdiodev, uint func,
- u32 addr, u8 data, int *err);
-
-/* Synchronous access to device (client) core registers via CMD53 to F1.
- * addr: backplane address (i.e. >= regsva from attach)
- * size: register width in bytes (2 or 4)
- * data: data for register write
- */
-extern u32
-brcmf_sdcard_reg_read(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size);
-
-extern u32
-brcmf_sdcard_reg_write(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size,
- u32 data);
-
-/* Indicate if last reg read/write failed */
-extern bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev);
+/* sdio device register access interface */
+extern u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret);
+extern u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret);
+extern void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
+ u8 data, int *ret);
+extern void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
+ u32 data, int *ret);
/* Buffer transfer to/from device (client) core via cmd53.
* fn: function number
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
index 1d67ecf681b7..c5a34ffe6459 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
@@ -1596,7 +1596,8 @@ static struct usb_driver brcmf_usbdrvr = {
.id_table = brcmf_usb_devid_table,
.suspend = brcmf_usb_suspend,
.resume = brcmf_usb_resume,
- .supports_autosuspend = 1
+ .supports_autosuspend = 1,
+ .disable_hub_initiated_lpm = 1,
};
void brcmf_usb_exit(void)
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/Makefile b/drivers/net/wireless/brcm80211/brcmsmac/Makefile
index c2eb2d0af386..e227c4c68ef9 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/Makefile
+++ b/drivers/net/wireless/brcm80211/brcmsmac/Makefile
@@ -39,10 +39,7 @@ BRCMSMAC_OFILES := \
phy/phytbl_lcn.o \
phy/phytbl_n.o \
phy/phy_qmath.o \
- otp.o \
- srom.o \
dma.o \
- nicpci.o \
brcms_trace_events.o
MODULEPFX := brcmsmac
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
index c93ea35bceec..6d8b7213643a 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c
@@ -19,7 +19,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/delay.h>
-#include <linux/pci.h>
#include <defs.h>
#include <chipcommon.h>
@@ -29,8 +28,6 @@
#include "types.h"
#include "pub.h"
#include "pmu.h"
-#include "srom.h"
-#include "nicpci.h"
#include "aiutils.h"
/* slow_clk_ctl */
@@ -321,7 +318,6 @@
#define IS_SIM(chippkg) \
((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID))
-#define PCI(sih) (ai_get_buscoretype(sih) == PCI_CORE_ID)
#define PCIE(sih) (ai_get_buscoretype(sih) == PCIE_CORE_ID)
#define PCI_FORCEHT(sih) (PCIE(sih) && (ai_get_chip_id(sih) == BCM4716_CHIP_ID))
@@ -454,36 +450,9 @@ struct aidmp {
u32 componentid3; /* 0xffc */
};
-/* return true if PCIE capability exists in the pci config space */
-static bool ai_ispcie(struct si_info *sii)
-{
- u8 cap_ptr;
-
- cap_ptr =
- pcicore_find_pci_capability(sii->pcibus, PCI_CAP_ID_EXP, NULL,
- NULL);
- if (!cap_ptr)
- return false;
-
- return true;
-}
-
-static bool ai_buscore_prep(struct si_info *sii)
-{
- /* kludge to enable the clock on the 4306 which lacks a slowclock */
- if (!ai_ispcie(sii))
- ai_clkctl_xtal(&sii->pub, XTAL | PLL, ON);
- return true;
-}
-
static bool
ai_buscore_setup(struct si_info *sii, struct bcma_device *cc)
{
- struct bcma_device *pci = NULL;
- struct bcma_device *pcie = NULL;
- struct bcma_device *core;
-
-
/* no cores found, bail out */
if (cc->bus->nr_cores == 0)
return false;
@@ -492,8 +461,7 @@ ai_buscore_setup(struct si_info *sii, struct bcma_device *cc)
sii->pub.ccrev = cc->id.rev;
/* get chipcommon chipstatus */
- if (ai_get_ccrev(&sii->pub) >= 11)
- sii->chipst = bcma_read32(cc, CHIPCREGOFFS(chipstatus));
+ sii->chipst = bcma_read32(cc, CHIPCREGOFFS(chipstatus));
/* get chipcommon capabilites */
sii->pub.cccaps = bcma_read32(cc, CHIPCREGOFFS(capabilities));
@@ -506,64 +474,18 @@ ai_buscore_setup(struct si_info *sii, struct bcma_device *cc)
}
/* figure out buscore */
- list_for_each_entry(core, &cc->bus->cores, list) {
- uint cid, crev;
-
- cid = core->id.id;
- crev = core->id.rev;
-
- if (cid == PCI_CORE_ID) {
- pci = core;
- } else if (cid == PCIE_CORE_ID) {
- pcie = core;
- }
- }
-
- if (pci && pcie) {
- if (ai_ispcie(sii))
- pci = NULL;
- else
- pcie = NULL;
- }
- if (pci) {
- sii->buscore = pci;
- } else if (pcie) {
- sii->buscore = pcie;
- }
-
- /* fixup necessary chip/core configurations */
- if (!sii->pch) {
- sii->pch = pcicore_init(&sii->pub, sii->icbus->drv_pci.core);
- if (sii->pch == NULL)
- return false;
- }
- if (ai_pci_fixcfg(&sii->pub))
- return false;
+ sii->buscore = ai_findcore(&sii->pub, PCIE_CORE_ID, 0);
return true;
}
-/*
- * get boardtype and boardrev
- */
-static __used void ai_nvram_process(struct si_info *sii)
-{
- uint w = 0;
-
- /* do a pci config read to get subsystem id and subvendor id */
- pci_read_config_dword(sii->pcibus, PCI_SUBSYSTEM_VENDOR_ID, &w);
-
- sii->pub.boardvendor = w & 0xffff;
- sii->pub.boardtype = (w >> 16) & 0xffff;
-}
-
static struct si_info *ai_doattach(struct si_info *sii,
struct bcma_bus *pbus)
{
struct si_pub *sih = &sii->pub;
u32 w, savewin;
struct bcma_device *cc;
- uint socitype;
+ struct ssb_sprom *sprom = &pbus->sprom;
savewin = 0;
@@ -573,38 +495,15 @@ static struct si_info *ai_doattach(struct si_info *sii,
/* switch to Chipcommon core */
cc = pbus->drv_cc.core;
- /* bus/core/clk setup for register access */
- if (!ai_buscore_prep(sii))
- return NULL;
+ sih->chip = pbus->chipinfo.id;
+ sih->chiprev = pbus->chipinfo.rev;
+ sih->chippkg = pbus->chipinfo.pkg;
+ sih->boardvendor = pbus->boardinfo.vendor;
+ sih->boardtype = pbus->boardinfo.type;
- /*
- * ChipID recognition.
- * We assume we can read chipid at offset 0 from the regs arg.
- * If we add other chiptypes (or if we need to support old sdio
- * hosts w/o chipcommon), some way of recognizing them needs to
- * be added here.
- */
- w = bcma_read32(cc, CHIPCREGOFFS(chipid));
- socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
- /* Might as wll fill in chip id rev & pkg */
- sih->chip = w & CID_ID_MASK;
- sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT;
- sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT;
-
- /* scan for cores */
- if (socitype != SOCI_AI)
- return NULL;
-
- SI_MSG("Found chip type AI (0x%08x)\n", w);
if (!ai_buscore_setup(sii, cc))
goto exit;
- /* Init nvram from sprom/otp if they exist */
- if (srom_var_init(&sii->pub))
- goto exit;
-
- ai_nvram_process(sii);
-
/* === NVRAM, clock is ready === */
bcma_write32(cc, CHIPCREGOFFS(gpiopullup), 0);
bcma_write32(cc, CHIPCREGOFFS(gpiopulldown), 0);
@@ -617,15 +516,13 @@ static struct si_info *ai_doattach(struct si_info *sii,
}
/* setup the GPIO based LED powersave register */
- w = getintvar(sih, BRCMS_SROM_LEDDC);
+ w = (sprom->leddc_on_time << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) |
+ (sprom->leddc_off_time << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT);
if (w == 0)
w = DEFAULT_GPIOTIMERVAL;
ai_cc_reg(sih, offsetof(struct chipcregs, gpiotimerval),
~0, w);
- if (PCIE(sih))
- pcicore_attach(sii->pch, SI_DOATTACH);
-
if (ai_get_chip_id(sih) == BCM43224_CHIP_ID) {
/*
* enable 12 mA drive strenth for 43224 and
@@ -659,9 +556,6 @@ static struct si_info *ai_doattach(struct si_info *sii,
return sii;
exit:
- if (sii->pch)
- pcicore_deinit(sii->pch);
- sii->pch = NULL;
return NULL;
}
@@ -700,11 +594,6 @@ void ai_detach(struct si_pub *sih)
if (sii == NULL)
return;
- if (sii->pch)
- pcicore_deinit(sii->pch);
- sii->pch = NULL;
-
- srom_free_vars(sih);
kfree(sii);
}
@@ -755,21 +644,7 @@ uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val)
/* return the slow clock source - LPO, XTAL, or PCI */
static uint ai_slowclk_src(struct si_pub *sih, struct bcma_device *cc)
{
- struct si_info *sii;
- u32 val;
-
- sii = (struct si_info *)sih;
- if (ai_get_ccrev(&sii->pub) < 6) {
- pci_read_config_dword(sii->pcibus, PCI_GPIO_OUT,
- &val);
- if (val & PCI_CFG_GPIO_SCS)
- return SCC_SS_PCI;
- return SCC_SS_XTAL;
- } else if (ai_get_ccrev(&sii->pub) < 10) {
- return bcma_read32(cc, CHIPCREGOFFS(slow_clk_ctl)) &
- SCC_SS_MASK;
- } else /* Insta-clock */
- return SCC_SS_XTAL;
+ return SCC_SS_XTAL;
}
/*
@@ -779,36 +654,12 @@ static uint ai_slowclk_src(struct si_pub *sih, struct bcma_device *cc)
static uint ai_slowclk_freq(struct si_pub *sih, bool max_freq,
struct bcma_device *cc)
{
- u32 slowclk;
uint div;
- slowclk = ai_slowclk_src(sih, cc);
- if (ai_get_ccrev(sih) < 6) {
- if (slowclk == SCC_SS_PCI)
- return max_freq ? (PCIMAXFREQ / 64)
- : (PCIMINFREQ / 64);
- else
- return max_freq ? (XTALMAXFREQ / 32)
- : (XTALMINFREQ / 32);
- } else if (ai_get_ccrev(sih) < 10) {
- div = 4 *
- (((bcma_read32(cc, CHIPCREGOFFS(slow_clk_ctl)) &
- SCC_CD_MASK) >> SCC_CD_SHIFT) + 1);
- if (slowclk == SCC_SS_LPO)
- return max_freq ? LPOMAXFREQ : LPOMINFREQ;
- else if (slowclk == SCC_SS_XTAL)
- return max_freq ? (XTALMAXFREQ / div)
- : (XTALMINFREQ / div);
- else if (slowclk == SCC_SS_PCI)
- return max_freq ? (PCIMAXFREQ / div)
- : (PCIMINFREQ / div);
- } else {
- /* Chipc rev 10 is InstaClock */
- div = bcma_read32(cc, CHIPCREGOFFS(system_clk_ctl));
- div = 4 * ((div >> SYCC_CD_SHIFT) + 1);
- return max_freq ? XTALMAXFREQ : (XTALMINFREQ / div);
- }
- return 0;
+ /* Chipc rev 10 is InstaClock */
+ div = bcma_read32(cc, CHIPCREGOFFS(system_clk_ctl));
+ div = 4 * ((div >> SYCC_CD_SHIFT) + 1);
+ return max_freq ? XTALMAXFREQ : (XTALMINFREQ / div);
}
static void
@@ -831,8 +682,7 @@ ai_clkctl_setdelay(struct si_pub *sih, struct bcma_device *cc)
/* Starting with 4318 it is ILP that is used for the delays */
slowmaxfreq =
- ai_slowclk_freq(sih,
- (ai_get_ccrev(sih) >= 10) ? false : true, cc);
+ ai_slowclk_freq(sih, false, cc);
pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000;
fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000;
@@ -854,9 +704,8 @@ void ai_clkctl_init(struct si_pub *sih)
return;
/* set all Instaclk chip ILP to 1 MHz */
- if (ai_get_ccrev(sih) >= 10)
- bcma_maskset32(cc, CHIPCREGOFFS(system_clk_ctl), SYCC_CD_MASK,
- (ILP_DIV_1MHZ << SYCC_CD_SHIFT));
+ bcma_maskset32(cc, CHIPCREGOFFS(system_clk_ctl), SYCC_CD_MASK,
+ (ILP_DIV_1MHZ << SYCC_CD_SHIFT));
ai_clkctl_setdelay(sih, cc);
}
@@ -891,140 +740,6 @@ u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih)
return fpdelay;
}
-/* turn primary xtal and/or pll off/on */
-int ai_clkctl_xtal(struct si_pub *sih, uint what, bool on)
-{
- struct si_info *sii;
- u32 in, out, outen;
-
- sii = (struct si_info *)sih;
-
- /* pcie core doesn't have any mapping to control the xtal pu */
- if (PCIE(sih))
- return -1;
-
- pci_read_config_dword(sii->pcibus, PCI_GPIO_IN, &in);
- pci_read_config_dword(sii->pcibus, PCI_GPIO_OUT, &out);
- pci_read_config_dword(sii->pcibus, PCI_GPIO_OUTEN, &outen);
-
- /*
- * Avoid glitching the clock if GPRS is already using it.
- * We can't actually read the state of the PLLPD so we infer it
- * by the value of XTAL_PU which *is* readable via gpioin.
- */
- if (on && (in & PCI_CFG_GPIO_XTAL))
- return 0;
-
- if (what & XTAL)
- outen |= PCI_CFG_GPIO_XTAL;
- if (what & PLL)
- outen |= PCI_CFG_GPIO_PLL;
-
- if (on) {
- /* turn primary xtal on */
- if (what & XTAL) {
- out |= PCI_CFG_GPIO_XTAL;
- if (what & PLL)
- out |= PCI_CFG_GPIO_PLL;
- pci_write_config_dword(sii->pcibus,
- PCI_GPIO_OUT, out);
- pci_write_config_dword(sii->pcibus,
- PCI_GPIO_OUTEN, outen);
- udelay(XTAL_ON_DELAY);
- }
-
- /* turn pll on */
- if (what & PLL) {
- out &= ~PCI_CFG_GPIO_PLL;
- pci_write_config_dword(sii->pcibus,
- PCI_GPIO_OUT, out);
- mdelay(2);
- }
- } else {
- if (what & XTAL)
- out &= ~PCI_CFG_GPIO_XTAL;
- if (what & PLL)
- out |= PCI_CFG_GPIO_PLL;
- pci_write_config_dword(sii->pcibus,
- PCI_GPIO_OUT, out);
- pci_write_config_dword(sii->pcibus,
- PCI_GPIO_OUTEN, outen);
- }
-
- return 0;
-}
-
-/* clk control mechanism through chipcommon, no policy checking */
-static bool _ai_clkctl_cc(struct si_info *sii, uint mode)
-{
- struct bcma_device *cc;
- u32 scc;
-
- /* chipcommon cores prior to rev6 don't support dynamic clock control */
- if (ai_get_ccrev(&sii->pub) < 6)
- return false;
-
- cc = ai_findcore(&sii->pub, BCMA_CORE_CHIPCOMMON, 0);
-
- if (!(ai_get_cccaps(&sii->pub) & CC_CAP_PWR_CTL) &&
- (ai_get_ccrev(&sii->pub) < 20))
- return mode == CLK_FAST;
-
- switch (mode) {
- case CLK_FAST: /* FORCEHT, fast (pll) clock */
- if (ai_get_ccrev(&sii->pub) < 10) {
- /*
- * don't forget to force xtal back
- * on before we clear SCC_DYN_XTAL..
- */
- ai_clkctl_xtal(&sii->pub, XTAL, ON);
- bcma_maskset32(cc, CHIPCREGOFFS(slow_clk_ctl),
- (SCC_XC | SCC_FS | SCC_IP), SCC_IP);
- } else if (ai_get_ccrev(&sii->pub) < 20) {
- bcma_set32(cc, CHIPCREGOFFS(system_clk_ctl), SYCC_HR);
- } else {
- bcma_set32(cc, CHIPCREGOFFS(clk_ctl_st), CCS_FORCEHT);
- }
-
- /* wait for the PLL */
- if (ai_get_cccaps(&sii->pub) & CC_CAP_PMU) {
- u32 htavail = CCS_HTAVAIL;
- SPINWAIT(((bcma_read32(cc, CHIPCREGOFFS(clk_ctl_st)) &
- htavail) == 0), PMU_MAX_TRANSITION_DLY);
- } else {
- udelay(PLL_DELAY);
- }
- break;
-
- case CLK_DYNAMIC: /* enable dynamic clock control */
- if (ai_get_ccrev(&sii->pub) < 10) {
- scc = bcma_read32(cc, CHIPCREGOFFS(slow_clk_ctl));
- scc &= ~(SCC_FS | SCC_IP | SCC_XC);
- if ((scc & SCC_SS_MASK) != SCC_SS_XTAL)
- scc |= SCC_XC;
- bcma_write32(cc, CHIPCREGOFFS(slow_clk_ctl), scc);
-
- /*
- * for dynamic control, we have to
- * release our xtal_pu "force on"
- */
- if (scc & SCC_XC)
- ai_clkctl_xtal(&sii->pub, XTAL, OFF);
- } else if (ai_get_ccrev(&sii->pub) < 20) {
- /* Instaclock */
- bcma_mask32(cc, CHIPCREGOFFS(system_clk_ctl), ~SYCC_HR);
- } else {
- bcma_mask32(cc, CHIPCREGOFFS(clk_ctl_st), ~CCS_FORCEHT);
- }
- break;
-
- default:
- break;
- }
-
- return mode == CLK_FAST;
-}
-
/*
* clock control policy function throught chipcommon
*
@@ -1033,133 +748,53 @@ static bool _ai_clkctl_cc(struct si_info *sii, uint mode)
* this is a wrapper over the next internal function
* to allow flexible policy settings for outside caller
*/
-bool ai_clkctl_cc(struct si_pub *sih, uint mode)
+bool ai_clkctl_cc(struct si_pub *sih, enum bcma_clkmode mode)
{
struct si_info *sii;
+ struct bcma_device *cc;
sii = (struct si_info *)sih;
- /* chipcommon cores prior to rev6 don't support dynamic clock control */
- if (ai_get_ccrev(sih) < 6)
- return false;
-
if (PCI_FORCEHT(sih))
- return mode == CLK_FAST;
+ return mode == BCMA_CLKMODE_FAST;
- return _ai_clkctl_cc(sii, mode);
+ cc = ai_findcore(&sii->pub, BCMA_CORE_CHIPCOMMON, 0);
+ bcma_core_set_clockmode(cc, mode);
+ return mode == BCMA_CLKMODE_FAST;
}
void ai_pci_up(struct si_pub *sih)
{
struct si_info *sii;
+ struct bcma_device *cc;
sii = (struct si_info *)sih;
- if (PCI_FORCEHT(sih))
- _ai_clkctl_cc(sii, CLK_FAST);
+ if (PCI_FORCEHT(sih)) {
+ cc = ai_findcore(&sii->pub, BCMA_CORE_CHIPCOMMON, 0);
+ bcma_core_set_clockmode(cc, BCMA_CLKMODE_FAST);
+ }
if (PCIE(sih))
- pcicore_up(sii->pch, SI_PCIUP);
-
-}
-
-/* Unconfigure and/or apply various WARs when system is going to sleep mode */
-void ai_pci_sleep(struct si_pub *sih)
-{
- struct si_info *sii;
-
- sii = (struct si_info *)sih;
-
- pcicore_sleep(sii->pch);
+ bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, true);
}
/* Unconfigure and/or apply various WARs when going down */
void ai_pci_down(struct si_pub *sih)
{
struct si_info *sii;
+ struct bcma_device *cc;
sii = (struct si_info *)sih;
/* release FORCEHT since chip is going to "down" state */
- if (PCI_FORCEHT(sih))
- _ai_clkctl_cc(sii, CLK_DYNAMIC);
-
- pcicore_down(sii->pch, SI_PCIDOWN);
-}
-
-/*
- * Configure the pci core for pci client (NIC) action
- * coremask is the bitvec of cores by index to be enabled.
- */
-void ai_pci_setup(struct si_pub *sih, uint coremask)
-{
- struct si_info *sii;
- u32 w;
-
- sii = (struct si_info *)sih;
-
- /*
- * Enable sb->pci interrupts. Assume
- * PCI rev 2.3 support was added in pci core rev 6 and things changed..
- */
- if (PCIE(sih) || (PCI(sih) && (ai_get_buscorerev(sih) >= 6))) {
- /* pci config write to set this core bit in PCIIntMask */
- pci_read_config_dword(sii->pcibus, PCI_INT_MASK, &w);
- w |= (coremask << PCI_SBIM_SHIFT);
- pci_write_config_dword(sii->pcibus, PCI_INT_MASK, w);
- }
-
- if (PCI(sih)) {
- pcicore_pci_setup(sii->pch);
+ if (PCI_FORCEHT(sih)) {
+ cc = ai_findcore(&sii->pub, BCMA_CORE_CHIPCOMMON, 0);
+ bcma_core_set_clockmode(cc, BCMA_CLKMODE_DYNAMIC);
}
-}
-/*
- * Fixup SROMless PCI device's configuration.
- * The current core may be changed upon return.
- */
-int ai_pci_fixcfg(struct si_pub *sih)
-{
- struct si_info *sii = (struct si_info *)sih;
-
- /* Fixup PI in SROM shadow area to enable the correct PCI core access */
- /* check 'pi' is correct and fix it if not */
- pcicore_fixcfg(sii->pch);
- pcicore_hwup(sii->pch);
- return 0;
-}
-
-/* mask&set gpiocontrol bits */
-u32 ai_gpiocontrol(struct si_pub *sih, u32 mask, u32 val, u8 priority)
-{
- uint regoff;
-
- regoff = offsetof(struct chipcregs, gpiocontrol);
- return ai_cc_reg(sih, regoff, mask, val);
-}
-
-void ai_chipcontrl_epa4331(struct si_pub *sih, bool on)
-{
- struct bcma_device *cc;
- u32 val;
-
- cc = ai_findcore(sih, CC_CORE_ID, 0);
-
- if (on) {
- if (ai_get_chippkg(sih) == 9 || ai_get_chippkg(sih) == 0xb)
- /* Ext PA Controls for 4331 12x9 Package */
- bcma_set32(cc, CHIPCREGOFFS(chipcontrol),
- CCTRL4331_EXTPA_EN |
- CCTRL4331_EXTPA_ON_GPIO2_5);
- else
- /* Ext PA Controls for 4331 12x12 Package */
- bcma_set32(cc, CHIPCREGOFFS(chipcontrol),
- CCTRL4331_EXTPA_EN);
- } else {
- val &= ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5);
- bcma_mask32(cc, CHIPCREGOFFS(chipcontrol),
- ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5));
- }
+ if (PCIE(sih))
+ bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, false);
}
/* Enable BT-COEX & Ex-PA for 4313 */
@@ -1181,6 +816,9 @@ bool ai_deviceremoved(struct si_pub *sih)
sii = (struct si_info *)sih;
+ if (sii->icbus->hosttype != BCMA_HOSTTYPE_PCI)
+ return false;
+
pci_read_config_dword(sii->pcibus, PCI_VENDOR_ID, &w);
if ((w & 0xFFFF) != PCI_VENDOR_ID_BROADCOM)
return true;
@@ -1188,45 +826,6 @@ bool ai_deviceremoved(struct si_pub *sih)
return false;
}
-bool ai_is_sprom_available(struct si_pub *sih)
-{
- struct si_info *sii = (struct si_info *)sih;
-
- if (ai_get_ccrev(sih) >= 31) {
- struct bcma_device *cc;
- u32 sromctrl;
-
- if ((ai_get_cccaps(sih) & CC_CAP_SROM) == 0)
- return false;
-
- cc = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0);
- sromctrl = bcma_read32(cc, CHIPCREGOFFS(sromcontrol));
- return sromctrl & SRC_PRESENT;
- }
-
- switch (ai_get_chip_id(sih)) {
- case BCM4313_CHIP_ID:
- return (sii->chipst & CST4313_SPROM_PRESENT) != 0;
- default:
- return true;
- }
-}
-
-bool ai_is_otp_disabled(struct si_pub *sih)
-{
- struct si_info *sii = (struct si_info *)sih;
-
- switch (ai_get_chip_id(sih)) {
- case BCM4313_CHIP_ID:
- return (sii->chipst & CST4313_OTP_PRESENT) == 0;
- /* These chips always have their OTP on */
- case BCM43224_CHIP_ID:
- case BCM43225_CHIP_ID:
- default:
- return false;
- }
-}
-
uint ai_get_buscoretype(struct si_pub *sih)
{
struct si_info *sii = (struct si_info *)sih;
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h
index f84c6f781692..d9f04a683bdb 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h
@@ -113,10 +113,6 @@
#define XTAL 0x1 /* primary crystal oscillator (2050) */
#define PLL 0x2 /* main chip pll */
-/* clkctl clk mode */
-#define CLK_FAST 0 /* force fast (pll) clock */
-#define CLK_DYNAMIC 2 /* enable dynamic clock control */
-
/* GPIO usage priorities */
#define GPIO_DRV_PRIORITY 0 /* Driver */
#define GPIO_APP_PRIORITY 1 /* Application */
@@ -172,9 +168,7 @@ struct si_info {
struct si_pub pub; /* back plane public state (must be first) */
struct bcma_bus *icbus; /* handle to soc interconnect bus */
struct pci_dev *pcibus; /* handle to pci bus */
- struct pcicore_info *pch; /* PCI/E core handle */
struct bcma_device *buscore;
- struct list_head var_list; /* list of srom variables */
u32 chipst; /* chip status */
};
@@ -197,38 +191,20 @@ extern u32 ai_core_cflags(struct bcma_device *core, u32 mask, u32 val);
extern struct si_pub *ai_attach(struct bcma_bus *pbus);
extern void ai_detach(struct si_pub *sih);
extern uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val);
-extern void ai_pci_setup(struct si_pub *sih, uint coremask);
extern void ai_clkctl_init(struct si_pub *sih);
extern u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih);
extern bool ai_clkctl_cc(struct si_pub *sih, uint mode);
-extern int ai_clkctl_xtal(struct si_pub *sih, uint what, bool on);
extern bool ai_deviceremoved(struct si_pub *sih);
-extern u32 ai_gpiocontrol(struct si_pub *sih, u32 mask, u32 val,
- u8 priority);
-
-/* OTP status */
-extern bool ai_is_otp_disabled(struct si_pub *sih);
-
-/* SPROM availability */
-extern bool ai_is_sprom_available(struct si_pub *sih);
-extern void ai_pci_sleep(struct si_pub *sih);
extern void ai_pci_down(struct si_pub *sih);
extern void ai_pci_up(struct si_pub *sih);
-extern int ai_pci_fixcfg(struct si_pub *sih);
-extern void ai_chipcontrl_epa4331(struct si_pub *sih, bool on);
/* Enable Ex-PA for 4313 */
extern void ai_epa_4313war(struct si_pub *sih);
extern uint ai_get_buscoretype(struct si_pub *sih);
extern uint ai_get_buscorerev(struct si_pub *sih);
-static inline int ai_get_ccrev(struct si_pub *sih)
-{
- return sih->ccrev;
-}
-
static inline u32 ai_get_cccaps(struct si_pub *sih)
{
return sih->cccaps;
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/antsel.c b/drivers/net/wireless/brcm80211/brcmsmac/antsel.c
index a47ce25cb9a2..55e12c327911 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/antsel.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/antsel.c
@@ -108,7 +108,7 @@ brcms_c_antsel_init_cfg(struct antsel_info *asi, struct brcms_antselcfg *antsel,
struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc)
{
struct antsel_info *asi;
- struct si_pub *sih = wlc->hw->sih;
+ struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom;
asi = kzalloc(sizeof(struct antsel_info), GFP_ATOMIC);
if (!asi)
@@ -118,7 +118,7 @@ struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc)
asi->pub = wlc->pub;
asi->antsel_type = ANTSEL_NA;
asi->antsel_avail = false;
- asi->antsel_antswitch = (u8) getintvar(sih, BRCMS_SROM_ANTSWITCH);
+ asi->antsel_antswitch = sprom->antswitch;
if ((asi->pub->sromrev >= 4) && (asi->antsel_antswitch != 0)) {
switch (asi->antsel_antswitch) {
@@ -128,12 +128,12 @@ struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc)
/* 4321/2 board with 2x3 switch logic */
asi->antsel_type = ANTSEL_2x3;
/* Antenna selection availability */
- if (((u16) getintvar(sih, BRCMS_SROM_AA2G) == 7) ||
- ((u16) getintvar(sih, BRCMS_SROM_AA5G) == 7)) {
+ if ((sprom->ant_available_bg == 7) ||
+ (sprom->ant_available_a == 7)) {
asi->antsel_avail = true;
} else if (
- (u16) getintvar(sih, BRCMS_SROM_AA2G) == 3 ||
- (u16) getintvar(sih, BRCMS_SROM_AA5G) == 3) {
+ sprom->ant_available_bg == 3 ||
+ sprom->ant_available_a == 3) {
asi->antsel_avail = false;
} else {
asi->antsel_avail = false;
@@ -146,8 +146,8 @@ struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc)
break;
}
} else if ((asi->pub->sromrev == 4) &&
- ((u16) getintvar(sih, BRCMS_SROM_AA2G) == 7) &&
- ((u16) getintvar(sih, BRCMS_SROM_AA5G) == 0)) {
+ (sprom->ant_available_bg == 7) &&
+ (sprom->ant_available_a == 0)) {
/* hack to match old 4321CB2 cards with 2of3 antenna switch */
asi->antsel_type = ANTSEL_2x3;
asi->antsel_avail = true;
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c
index 0efe88e25a9a..eb77ac3cfb6b 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c
@@ -1110,7 +1110,7 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
char country_abbrev[BRCM_CNTRY_BUF_SZ];
const struct country_info *country;
struct brcms_pub *pub = wlc->pub;
- char *ccode;
+ struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom;
BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
@@ -1122,9 +1122,8 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
wlc->cmi = wlc_cm;
/* store the country code for passing up as a regulatory hint */
- ccode = getvar(wlc->hw->sih, BRCMS_SROM_CCODE);
- if (ccode && brcms_c_country_valid(ccode))
- strncpy(wlc->pub->srom_ccode, ccode, BRCM_CNTRY_BUF_SZ - 1);
+ if (sprom->alpha2 && brcms_c_country_valid(sprom->alpha2))
+ strncpy(wlc->pub->srom_ccode, sprom->alpha2, sizeof(sprom->alpha2));
/*
* internal country information which must match
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
index aa15558f75c8..50f92a0b7c41 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -25,7 +25,6 @@
#include <linux/bcma/bcma.h>
#include <net/mac80211.h>
#include <defs.h>
-#include "nicpci.h"
#include "phy/phy_int.h"
#include "d11.h"
#include "channel.h"
@@ -770,7 +769,7 @@ void brcms_dpc(unsigned long data)
* Precondition: Since this function is called in brcms_pci_probe() context,
* no locking is required.
*/
-static int brcms_request_fw(struct brcms_info *wl, struct pci_dev *pdev)
+static int brcms_request_fw(struct brcms_info *wl, struct bcma_device *pdev)
{
int status;
struct device *device = &pdev->dev;
@@ -1022,7 +1021,7 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)
spin_lock_init(&wl->isr_lock);
/* prepare ucode */
- if (brcms_request_fw(wl, pdev->bus->host_pci) < 0) {
+ if (brcms_request_fw(wl, pdev) < 0) {
wiphy_err(wl->wiphy, "%s: Failed to find firmware usually in "
"%s\n", KBUILD_MODNAME, "/lib/firmware/brcm");
brcms_release_fw(wl);
@@ -1043,12 +1042,12 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)
wl->pub->ieee_hw = hw;
/* register our interrupt handler */
- if (request_irq(pdev->bus->host_pci->irq, brcms_isr,
+ if (request_irq(pdev->irq, brcms_isr,
IRQF_SHARED, KBUILD_MODNAME, wl)) {
wiphy_err(wl->wiphy, "wl%d: request_irq() failed\n", unit);
goto fail;
}
- wl->irq = pdev->bus->host_pci->irq;
+ wl->irq = pdev->irq;
/* register module */
brcms_c_module_register(wl->pub, "linux", wl, NULL);
@@ -1098,7 +1097,7 @@ static int __devinit brcms_bcma_probe(struct bcma_device *pdev)
dev_info(&pdev->dev, "mfg %x core %x rev %d class %d irq %d\n",
pdev->id.manuf, pdev->id.id, pdev->id.rev, pdev->id.class,
- pdev->bus->host_pci->irq);
+ pdev->irq);
if ((pdev->id.manuf != BCMA_MANUF_BCM) ||
(pdev->id.id != BCMA_CORE_80211))
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c
index b4d92792c502..19db4052c44c 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
@@ -1219,7 +1219,7 @@ static void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw)
}
/* control chip clock to save power, enable dynamic clock or force fast clock */
-static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, uint mode)
+static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, enum bcma_clkmode mode)
{
if (ai_get_cccaps(wlc_hw->sih) & CC_CAP_PMU) {
/* new chips with PMU, CCS_FORCEHT will distribute the HT clock
@@ -1229,7 +1229,7 @@ static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, uint mode)
*/
if (wlc_hw->clk) {
- if (mode == CLK_FAST) {
+ if (mode == BCMA_CLKMODE_FAST) {
bcma_set32(wlc_hw->d11core,
D11REGOFFS(clk_ctl_st),
CCS_FORCEHT);
@@ -1260,7 +1260,7 @@ static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, uint mode)
~CCS_FORCEHT);
}
}
- wlc_hw->forcefastclk = (mode == CLK_FAST);
+ wlc_hw->forcefastclk = (mode == BCMA_CLKMODE_FAST);
} else {
/* old chips w/o PMU, force HT through cc,
@@ -1567,7 +1567,7 @@ void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw)
/* request FAST clock if not on */
fastclk = wlc_hw->forcefastclk;
if (!fastclk)
- brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
+ brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
wlc_phy_bw_state_set(wlc_hw->band->pi, bw);
@@ -1576,7 +1576,7 @@ void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw)
/* restore the clk */
if (!fastclk)
- brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
+ brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC);
}
static void brcms_b_upd_synthpu(struct brcms_hardware *wlc_hw)
@@ -1882,27 +1882,20 @@ static bool brcms_c_validboardtype(struct brcms_hardware *wlc_hw)
return true;
}
-static char *brcms_c_get_macaddr(struct brcms_hardware *wlc_hw)
+static void brcms_c_get_macaddr(struct brcms_hardware *wlc_hw, u8 etheraddr[ETH_ALEN])
{
- enum brcms_srom_id var_id = BRCMS_SROM_MACADDR;
- char *macaddr;
+ struct ssb_sprom *sprom = &wlc_hw->d11core->bus->sprom;
/* If macaddr exists, use it (Sromrev4, CIS, ...). */
- macaddr = getvar(wlc_hw->sih, var_id);
- if (macaddr != NULL)
- return macaddr;
+ if (!is_zero_ether_addr(sprom->il0mac)) {
+ memcpy(etheraddr, sprom->il0mac, 6);
+ return;
+ }
if (wlc_hw->_nbands > 1)
- var_id = BRCMS_SROM_ET1MACADDR;
+ memcpy(etheraddr, sprom->et1mac, 6);
else
- var_id = BRCMS_SROM_IL0MACADDR;
-
- macaddr = getvar(wlc_hw->sih, var_id);
- if (macaddr == NULL)
- wiphy_err(wlc_hw->wlc->wiphy, "wl%d: wlc_get_macaddr: macaddr "
- "getvar(%d) not found\n", wlc_hw->unit, var_id);
-
- return macaddr;
+ memcpy(etheraddr, sprom->il0mac, 6);
}
/* power both the pll and external oscillator on/off */
@@ -1917,9 +1910,6 @@ static void brcms_b_xtal(struct brcms_hardware *wlc_hw, bool want)
if (!want && wlc_hw->pllreq)
return;
- if (wlc_hw->sih)
- ai_clkctl_xtal(wlc_hw->sih, XTAL | PLL, want);
-
wlc_hw->sbclk = want;
if (!wlc_hw->sbclk) {
wlc_hw->clk = false;
@@ -2004,7 +1994,7 @@ void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags)
/* request FAST clock if not on */
fastclk = wlc_hw->forcefastclk;
if (!fastclk)
- brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
+ brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
/* reset the dma engines except first time thru */
if (bcma_core_is_enabled(wlc_hw->d11core)) {
@@ -2053,7 +2043,7 @@ void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags)
brcms_c_mctrl_reset(wlc_hw);
if (ai_get_cccaps(wlc_hw->sih) & CC_CAP_PMU)
- brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
+ brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
brcms_b_phy_reset(wlc_hw);
@@ -2065,7 +2055,7 @@ void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags)
/* restore the clk setting */
if (!fastclk)
- brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
+ brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC);
}
/* txfifo sizes needs to be modified(increased) since the newer cores
@@ -2218,7 +2208,7 @@ static void brcms_c_gpio_init(struct brcms_c_info *wlc)
gm |= gc |= BOARD_GPIO_PACTRL;
/* apply to gpiocontrol register */
- ai_gpiocontrol(wlc_hw->sih, gm, gc, GPIO_DRV_PRIORITY);
+ bcma_chipco_gpio_control(&wlc_hw->d11core->bus->drv_cc, gm, gc);
}
static void brcms_ucode_write(struct brcms_hardware *wlc_hw,
@@ -3371,7 +3361,7 @@ static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec) {
/* request FAST clock if not on */
fastclk = wlc_hw->forcefastclk;
if (!fastclk)
- brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
+ brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
/* disable interrupts */
macintmask = brcms_intrsoff(wlc->wl);
@@ -3405,7 +3395,7 @@ static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec) {
/* restore the clk */
if (!fastclk)
- brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
+ brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC);
}
static void brcms_c_set_phy_chanspec(struct brcms_c_info *wlc,
@@ -4436,17 +4426,22 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
uint unit, bool piomode)
{
struct brcms_hardware *wlc_hw;
- char *macaddr = NULL;
uint err = 0;
uint j;
bool wme = false;
struct shared_phy_params sha_params;
struct wiphy *wiphy = wlc->wiphy;
struct pci_dev *pcidev = core->bus->host_pci;
+ struct ssb_sprom *sprom = &core->bus->sprom;
- BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit,
- pcidev->vendor,
- pcidev->device);
+ if (core->bus->hosttype == BCMA_HOSTTYPE_PCI)
+ BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit,
+ pcidev->vendor,
+ pcidev->device);
+ else
+ BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit,
+ core->bus->boardinfo.vendor,
+ core->bus->boardinfo.type);
wme = true;
@@ -4472,7 +4467,8 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
}
/* verify again the device is supported */
- if (!brcms_c_chipmatch(pcidev->vendor, pcidev->device)) {
+ if (core->bus->hosttype == BCMA_HOSTTYPE_PCI &&
+ !brcms_c_chipmatch(pcidev->vendor, pcidev->device)) {
wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported "
"vendor/device (0x%x/0x%x)\n",
unit, pcidev->vendor, pcidev->device);
@@ -4480,8 +4476,13 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
goto fail;
}
- wlc_hw->vendorid = pcidev->vendor;
- wlc_hw->deviceid = pcidev->device;
+ if (core->bus->hosttype == BCMA_HOSTTYPE_PCI) {
+ wlc_hw->vendorid = pcidev->vendor;
+ wlc_hw->deviceid = pcidev->device;
+ } else {
+ wlc_hw->vendorid = core->bus->boardinfo.vendor;
+ wlc_hw->deviceid = core->bus->boardinfo.type;
+ }
wlc_hw->d11core = core;
wlc_hw->corerev = core->id.rev;
@@ -4501,7 +4502,7 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
* is still false; But it will be called again inside wlc_corereset,
* after d11 is out of reset.
*/
- brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
+ brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
if (!brcms_b_validate_chip_access(wlc_hw)) {
@@ -4512,7 +4513,7 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
}
/* get the board rev, used just below */
- j = getintvar(wlc_hw->sih, BRCMS_SROM_BOARDREV);
+ j = sprom->board_rev;
/* promote srom boardrev of 0xFF to 1 */
if (j == BOARDREV_PROMOTABLE)
j = BOARDREV_PROMOTED;
@@ -4525,11 +4526,9 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
err = 15;
goto fail;
}
- wlc_hw->sromrev = (u8) getintvar(wlc_hw->sih, BRCMS_SROM_REV);
- wlc_hw->boardflags = (u32) getintvar(wlc_hw->sih,
- BRCMS_SROM_BOARDFLAGS);
- wlc_hw->boardflags2 = (u32) getintvar(wlc_hw->sih,
- BRCMS_SROM_BOARDFLAGS2);
+ wlc_hw->sromrev = sprom->revision;
+ wlc_hw->boardflags = sprom->boardflags_lo + (sprom->boardflags_hi << 16);
+ wlc_hw->boardflags2 = sprom->boardflags2_lo + (sprom->boardflags2_hi << 16);
if (wlc_hw->boardflags & BFL_NOPLLDOWN)
brcms_b_pllreq(wlc_hw, true, BRCMS_PLLREQ_SHARED);
@@ -4702,25 +4701,18 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
*/
/* init etheraddr state variables */
- macaddr = brcms_c_get_macaddr(wlc_hw);
- if (macaddr == NULL) {
- wiphy_err(wiphy, "wl%d: brcms_b_attach: macaddr not found\n",
- unit);
- err = 21;
- goto fail;
- }
- if (!mac_pton(macaddr, wlc_hw->etheraddr) ||
- is_broadcast_ether_addr(wlc_hw->etheraddr) ||
+ brcms_c_get_macaddr(wlc_hw, wlc_hw->etheraddr);
+
+ if (is_broadcast_ether_addr(wlc_hw->etheraddr) ||
is_zero_ether_addr(wlc_hw->etheraddr)) {
- wiphy_err(wiphy, "wl%d: brcms_b_attach: bad macaddr %s\n",
- unit, macaddr);
+ wiphy_err(wiphy, "wl%d: brcms_b_attach: bad macaddr\n",
+ unit);
err = 22;
goto fail;
}
- BCMMSG(wlc->wiphy, "deviceid 0x%x nbands %d board 0x%x macaddr: %s\n",
- wlc_hw->deviceid, wlc_hw->_nbands, ai_get_boardtype(wlc_hw->sih),
- macaddr);
+ BCMMSG(wlc->wiphy, "deviceid 0x%x nbands %d board 0x%x\n",
+ wlc_hw->deviceid, wlc_hw->_nbands, ai_get_boardtype(wlc_hw->sih));
return err;
@@ -4770,16 +4762,16 @@ static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc)
int aa;
uint unit;
int bandtype;
- struct si_pub *sih = wlc->hw->sih;
+ struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom;
unit = wlc->pub->unit;
bandtype = wlc->band->bandtype;
/* get antennas available */
if (bandtype == BRCM_BAND_5G)
- aa = (s8) getintvar(sih, BRCMS_SROM_AA5G);
+ aa = sprom->ant_available_a;
else
- aa = (s8) getintvar(sih, BRCMS_SROM_AA2G);
+ aa = sprom->ant_available_bg;
if ((aa < 1) || (aa > 15)) {
wiphy_err(wlc->wiphy, "wl%d: %s: Invalid antennas available in"
@@ -4799,9 +4791,9 @@ static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc)
/* Compute Antenna Gain */
if (bandtype == BRCM_BAND_5G)
- wlc->band->antgain = (s8) getintvar(sih, BRCMS_SROM_AG1);
+ wlc->band->antgain = sprom->antenna_gain.a1;
else
- wlc->band->antgain = (s8) getintvar(sih, BRCMS_SROM_AG0);
+ wlc->band->antgain = sprom->antenna_gain.a0;
brcms_c_attach_antgain_init(wlc);
@@ -4952,15 +4944,6 @@ static int brcms_b_detach(struct brcms_c_info *wlc)
callbacks = 0;
- if (wlc_hw->sih) {
- /*
- * detach interrupt sync mechanism since interrupt is disabled
- * and per-port interrupt object may has been freed. this must
- * be done before sb core switch
- */
- ai_pci_sleep(wlc_hw->sih);
- }
-
brcms_b_detach_dmapio(wlc_hw);
band = wlc_hw->band;
@@ -5047,9 +5030,7 @@ static void brcms_b_hw_up(struct brcms_hardware *wlc_hw)
*/
brcms_b_xtal(wlc_hw, ON);
ai_clkctl_init(wlc_hw->sih);
- brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
-
- ai_pci_fixcfg(wlc_hw->sih);
+ brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
/*
* TODO: test suspend/resume
@@ -5078,8 +5059,6 @@ static void brcms_b_hw_up(struct brcms_hardware *wlc_hw)
static int brcms_b_up_prep(struct brcms_hardware *wlc_hw)
{
- uint coremask;
-
BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
/*
@@ -5088,15 +5067,14 @@ static int brcms_b_up_prep(struct brcms_hardware *wlc_hw)
*/
brcms_b_xtal(wlc_hw, ON);
ai_clkctl_init(wlc_hw->sih);
- brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
+ brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
/*
* Configure pci/pcmcia here instead of in brcms_c_attach()
* to allow mfg hotswap: down, hotswap (chip power cycle), up.
*/
- coremask = (1 << wlc_hw->wlc->core->coreidx);
-
- ai_pci_setup(wlc_hw->sih, coremask);
+ bcma_core_pci_irq_ctl(&wlc_hw->d11core->bus->drv_pci, wlc_hw->d11core,
+ true);
/*
* Need to read the hwradio status here to cover the case where the
@@ -5126,7 +5104,7 @@ static int brcms_b_up_finish(struct brcms_hardware *wlc_hw)
wlc_phy_hw_state_upd(wlc_hw->band->pi, true);
/* FULLY enable dynamic power control and d11 core interrupt */
- brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
+ brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC);
brcms_intrson(wlc_hw->wlc->wl);
return 0;
}
@@ -5267,7 +5245,7 @@ static int brcms_b_bmac_down_prep(struct brcms_hardware *wlc_hw)
brcms_intrsoff(wlc_hw->wlc->wl);
/* ensure we're running on the pll clock again */
- brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
+ brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
}
/* down phy at the last of this stage */
callbacks += wlc_phy_down(wlc_hw->band->pi);
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/nicpci.c b/drivers/net/wireless/brcm80211/brcmsmac/nicpci.c
deleted file mode 100644
index 7fad6dc19258..000000000000
--- a/drivers/net/wireless/brcm80211/brcmsmac/nicpci.c
+++ /dev/null
@@ -1,826 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-
-#include <defs.h>
-#include <soc.h>
-#include <chipcommon.h>
-#include "aiutils.h"
-#include "pub.h"
-#include "nicpci.h"
-
-/* SPROM offsets */
-#define SRSH_ASPM_OFFSET 4 /* word 4 */
-#define SRSH_ASPM_ENB 0x18 /* bit 3, 4 */
-#define SRSH_ASPM_L1_ENB 0x10 /* bit 4 */
-#define SRSH_ASPM_L0s_ENB 0x8 /* bit 3 */
-
-#define SRSH_PCIE_MISC_CONFIG 5 /* word 5 */
-#define SRSH_L23READY_EXIT_NOPERST 0x8000 /* bit 15 */
-#define SRSH_CLKREQ_OFFSET_REV5 20 /* word 20 for srom rev <= 5 */
-#define SRSH_CLKREQ_ENB 0x0800 /* bit 11 */
-#define SRSH_BD_OFFSET 6 /* word 6 */
-
-/* chipcontrol */
-#define CHIPCTRL_4321_PLL_DOWN 0x800000/* serdes PLL down override */
-
-/* MDIO control */
-#define MDIOCTL_DIVISOR_MASK 0x7f /* clock to be used on MDIO */
-#define MDIOCTL_DIVISOR_VAL 0x2
-#define MDIOCTL_PREAM_EN 0x80 /* Enable preamble sequnce */
-#define MDIOCTL_ACCESS_DONE 0x100 /* Transaction complete */
-
-/* MDIO Data */
-#define MDIODATA_MASK 0x0000ffff /* data 2 bytes */
-#define MDIODATA_TA 0x00020000 /* Turnaround */
-
-#define MDIODATA_REGADDR_SHF 18 /* Regaddr shift */
-#define MDIODATA_REGADDR_MASK 0x007c0000 /* Regaddr Mask */
-#define MDIODATA_DEVADDR_SHF 23 /* Physmedia devaddr shift */
-#define MDIODATA_DEVADDR_MASK 0x0f800000
- /* Physmedia devaddr Mask */
-
-/* MDIO Data for older revisions < 10 */
-#define MDIODATA_REGADDR_SHF_OLD 18 /* Regaddr shift */
-#define MDIODATA_REGADDR_MASK_OLD 0x003c0000
- /* Regaddr Mask */
-#define MDIODATA_DEVADDR_SHF_OLD 22 /* Physmedia devaddr shift */
-#define MDIODATA_DEVADDR_MASK_OLD 0x0fc00000
- /* Physmedia devaddr Mask */
-
-/* Transactions flags */
-#define MDIODATA_WRITE 0x10000000
-#define MDIODATA_READ 0x20000000
-#define MDIODATA_START 0x40000000
-
-#define MDIODATA_DEV_ADDR 0x0 /* dev address for serdes */
-#define MDIODATA_BLK_ADDR 0x1F /* blk address for serdes */
-
-/* serdes regs (rev < 10) */
-#define MDIODATA_DEV_PLL 0x1d /* SERDES PLL Dev */
-#define MDIODATA_DEV_TX 0x1e /* SERDES TX Dev */
-#define MDIODATA_DEV_RX 0x1f /* SERDES RX Dev */
-
-/* SERDES RX registers */
-#define SERDES_RX_CTRL 1 /* Rx cntrl */
-#define SERDES_RX_TIMER1 2 /* Rx Timer1 */
-#define SERDES_RX_CDR 6 /* CDR */
-#define SERDES_RX_CDRBW 7 /* CDR BW */
-/* SERDES RX control register */
-#define SERDES_RX_CTRL_FORCE 0x80 /* rxpolarity_force */
-#define SERDES_RX_CTRL_POLARITY 0x40 /* rxpolarity_value */
-
-/* SERDES PLL registers */
-#define SERDES_PLL_CTRL 1 /* PLL control reg */
-#define PLL_CTRL_FREQDET_EN 0x4000 /* bit 14 is FREQDET on */
-
-/* Linkcontrol reg offset in PCIE Cap */
-#define PCIE_CAP_LINKCTRL_OFFSET 16 /* offset in pcie cap */
-#define PCIE_CAP_LCREG_ASPML0s 0x01 /* ASPM L0s in linkctrl */
-#define PCIE_CAP_LCREG_ASPML1 0x02 /* ASPM L1 in linkctrl */
-#define PCIE_CLKREQ_ENAB 0x100 /* CLKREQ Enab in linkctrl */
-
-#define PCIE_ASPM_ENAB 3 /* ASPM L0s & L1 in linkctrl */
-#define PCIE_ASPM_L1_ENAB 2 /* ASPM L0s & L1 in linkctrl */
-#define PCIE_ASPM_L0s_ENAB 1 /* ASPM L0s & L1 in linkctrl */
-#define PCIE_ASPM_DISAB 0 /* ASPM L0s & L1 in linkctrl */
-
-/* Power management threshold */
-#define PCIE_L1THRESHOLDTIME_MASK 0xFF00 /* bits 8 - 15 */
-#define PCIE_L1THRESHOLDTIME_SHIFT 8 /* PCIE_L1THRESHOLDTIME_SHIFT */
-#define PCIE_L1THRESHOLD_WARVAL 0x72 /* WAR value */
-#define PCIE_ASPMTIMER_EXTEND 0x01000000
- /* > rev7:
- * enable extend ASPM timer
- */
-
-/* different register spaces to access thru pcie indirect access */
-#define PCIE_CONFIGREGS 1 /* Access to config space */
-#define PCIE_PCIEREGS 2 /* Access to pcie registers */
-
-/* PCIE protocol PHY diagnostic registers */
-#define PCIE_PLP_STATUSREG 0x204 /* Status */
-
-/* Status reg PCIE_PLP_STATUSREG */
-#define PCIE_PLP_POLARITYINV_STAT 0x10
-
-/* PCIE protocol DLLP diagnostic registers */
-#define PCIE_DLLP_LCREG 0x100 /* Link Control */
-#define PCIE_DLLP_PMTHRESHREG 0x128 /* Power Management Threshold */
-
-/* PCIE protocol TLP diagnostic registers */
-#define PCIE_TLP_WORKAROUNDSREG 0x004 /* TLP Workarounds */
-
-/* Sonics to PCI translation types */
-#define SBTOPCI_PREF 0x4 /* prefetch enable */
-#define SBTOPCI_BURST 0x8 /* burst enable */
-#define SBTOPCI_RC_READMULTI 0x20 /* memory read multiple */
-
-#define PCI_CLKRUN_DSBL 0x8000 /* Bit 15 forceClkrun */
-
-/* PCI core index in SROM shadow area */
-#define SRSH_PI_OFFSET 0 /* first word */
-#define SRSH_PI_MASK 0xf000 /* bit 15:12 */
-#define SRSH_PI_SHIFT 12 /* bit 15:12 */
-
-#define PCIREGOFFS(field) offsetof(struct sbpciregs, field)
-#define PCIEREGOFFS(field) offsetof(struct sbpcieregs, field)
-
-/* Sonics side: PCI core and host control registers */
-struct sbpciregs {
- u32 control; /* PCI control */
- u32 PAD[3];
- u32 arbcontrol; /* PCI arbiter control */
- u32 clkrun; /* Clkrun Control (>=rev11) */
- u32 PAD[2];
- u32 intstatus; /* Interrupt status */
- u32 intmask; /* Interrupt mask */
- u32 sbtopcimailbox; /* Sonics to PCI mailbox */
- u32 PAD[9];
- u32 bcastaddr; /* Sonics broadcast address */
- u32 bcastdata; /* Sonics broadcast data */
- u32 PAD[2];
- u32 gpioin; /* ro: gpio input (>=rev2) */
- u32 gpioout; /* rw: gpio output (>=rev2) */
- u32 gpioouten; /* rw: gpio output enable (>= rev2) */
- u32 gpiocontrol; /* rw: gpio control (>= rev2) */
- u32 PAD[36];
- u32 sbtopci0; /* Sonics to PCI translation 0 */
- u32 sbtopci1; /* Sonics to PCI translation 1 */
- u32 sbtopci2; /* Sonics to PCI translation 2 */
- u32 PAD[189];
- u32 pcicfg[4][64]; /* 0x400 - 0x7FF, PCI Cfg Space (>=rev8) */
- u16 sprom[36]; /* SPROM shadow Area */
- u32 PAD[46];
-};
-
-/* SB side: PCIE core and host control registers */
-struct sbpcieregs {
- u32 control; /* host mode only */
- u32 PAD[2];
- u32 biststatus; /* bist Status: 0x00C */
- u32 gpiosel; /* PCIE gpio sel: 0x010 */
- u32 gpioouten; /* PCIE gpio outen: 0x14 */
- u32 PAD[2];
- u32 intstatus; /* Interrupt status: 0x20 */
- u32 intmask; /* Interrupt mask: 0x24 */
- u32 sbtopcimailbox; /* sb to pcie mailbox: 0x028 */
- u32 PAD[53];
- u32 sbtopcie0; /* sb to pcie translation 0: 0x100 */
- u32 sbtopcie1; /* sb to pcie translation 1: 0x104 */
- u32 sbtopcie2; /* sb to pcie translation 2: 0x108 */
- u32 PAD[5];
-
- /* pcie core supports in direct access to config space */
- u32 configaddr; /* pcie config space access: Address field: 0x120 */
- u32 configdata; /* pcie config space access: Data field: 0x124 */
-
- /* mdio access to serdes */
- u32 mdiocontrol; /* controls the mdio access: 0x128 */
- u32 mdiodata; /* Data to the mdio access: 0x12c */
-
- /* pcie protocol phy/dllp/tlp register indirect access mechanism */
- u32 pcieindaddr; /* indirect access to
- * the internal register: 0x130
- */
- u32 pcieinddata; /* Data to/from the internal regsiter: 0x134 */
-
- u32 clkreqenctrl; /* >= rev 6, Clkreq rdma control : 0x138 */
- u32 PAD[177];
- u32 pciecfg[4][64]; /* 0x400 - 0x7FF, PCIE Cfg Space */
- u16 sprom[64]; /* SPROM shadow Area */
-};
-
-struct pcicore_info {
- struct bcma_device *core;
- struct si_pub *sih; /* System interconnect handle */
- struct pci_dev *dev;
- u8 pciecap_lcreg_offset;/* PCIE capability LCreg offset
- * in the config space
- */
- bool pcie_pr42767;
- u8 pcie_polarity;
- u8 pcie_war_aspm_ovr; /* Override ASPM/Clkreq settings */
-
- u8 pmecap_offset; /* PM Capability offset in the config space */
- bool pmecap; /* Capable of generating PME */
-};
-
-#define PCIE_ASPM(sih) \
- ((ai_get_buscoretype(sih) == PCIE_CORE_ID) && \
- ((ai_get_buscorerev(sih) >= 3) && \
- (ai_get_buscorerev(sih) <= 5)))
-
-
-/* delay needed between the mdio control/ mdiodata register data access */
-static void pr28829_delay(void)
-{
- udelay(10);
-}
-
-/* Initialize the PCI core.
- * It's caller's responsibility to make sure that this is done only once
- */
-struct pcicore_info *pcicore_init(struct si_pub *sih, struct bcma_device *core)
-{
- struct pcicore_info *pi;
-
- /* alloc struct pcicore_info */
- pi = kzalloc(sizeof(struct pcicore_info), GFP_ATOMIC);
- if (pi == NULL)
- return NULL;
-
- pi->sih = sih;
- pi->dev = core->bus->host_pci;
- pi->core = core;
-
- if (core->id.id == PCIE_CORE_ID) {
- u8 cap_ptr;
- cap_ptr = pcicore_find_pci_capability(pi->dev, PCI_CAP_ID_EXP,
- NULL, NULL);
- pi->pciecap_lcreg_offset = cap_ptr + PCIE_CAP_LINKCTRL_OFFSET;
- }
- return pi;
-}
-
-void pcicore_deinit(struct pcicore_info *pch)
-{
- kfree(pch);
-}
-
-/* return cap_offset if requested capability exists in the PCI config space */
-/* Note that it's caller's responsibility to make sure it's a pci bus */
-u8
-pcicore_find_pci_capability(struct pci_dev *dev, u8 req_cap_id,
- unsigned char *buf, u32 *buflen)
-{
- u8 cap_id;
- u8 cap_ptr = 0;
- u32 bufsize;
- u8 byte_val;
-
- /* check for Header type 0 */
- pci_read_config_byte(dev, PCI_HEADER_TYPE, &byte_val);
- if ((byte_val & 0x7f) != PCI_HEADER_TYPE_NORMAL)
- goto end;
-
- /* check if the capability pointer field exists */
- pci_read_config_byte(dev, PCI_STATUS, &byte_val);
- if (!(byte_val & PCI_STATUS_CAP_LIST))
- goto end;
-
- pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &cap_ptr);
- /* check if the capability pointer is 0x00 */
- if (cap_ptr == 0x00)
- goto end;
-
- /* loop thru the capability list
- * and see if the pcie capability exists
- */
-
- pci_read_config_byte(dev, cap_ptr, &cap_id);
-
- while (cap_id != req_cap_id) {
- pci_read_config_byte(dev, cap_ptr + 1, &cap_ptr);
- if (cap_ptr == 0x00)
- break;
- pci_read_config_byte(dev, cap_ptr, &cap_id);
- }
- if (cap_id != req_cap_id)
- goto end;
-
- /* found the caller requested capability */
- if (buf != NULL && buflen != NULL) {
- u8 cap_data;
-
- bufsize = *buflen;
- if (!bufsize)
- goto end;
- *buflen = 0;
- /* copy the capability data excluding cap ID and next ptr */
- cap_data = cap_ptr + 2;
- if ((bufsize + cap_data) > PCI_SZPCR)
- bufsize = PCI_SZPCR - cap_data;
- *buflen = bufsize;
- while (bufsize--) {
- pci_read_config_byte(dev, cap_data, buf);
- cap_data++;
- buf++;
- }
- }
-end:
- return cap_ptr;
-}
-
-/* ***** Register Access API */
-static uint
-pcie_readreg(struct bcma_device *core, uint addrtype, uint offset)
-{
- uint retval = 0xFFFFFFFF;
-
- switch (addrtype) {
- case PCIE_CONFIGREGS:
- bcma_write32(core, PCIEREGOFFS(configaddr), offset);
- (void)bcma_read32(core, PCIEREGOFFS(configaddr));
- retval = bcma_read32(core, PCIEREGOFFS(configdata));
- break;
- case PCIE_PCIEREGS:
- bcma_write32(core, PCIEREGOFFS(pcieindaddr), offset);
- (void)bcma_read32(core, PCIEREGOFFS(pcieindaddr));
- retval = bcma_read32(core, PCIEREGOFFS(pcieinddata));
- break;
- }
-
- return retval;
-}
-
-static uint pcie_writereg(struct bcma_device *core, uint addrtype,
- uint offset, uint val)
-{
- switch (addrtype) {
- case PCIE_CONFIGREGS:
- bcma_write32(core, PCIEREGOFFS(configaddr), offset);
- bcma_write32(core, PCIEREGOFFS(configdata), val);
- break;
- case PCIE_PCIEREGS:
- bcma_write32(core, PCIEREGOFFS(pcieindaddr), offset);
- bcma_write32(core, PCIEREGOFFS(pcieinddata), val);
- break;
- default:
- break;
- }
- return 0;
-}
-
-static bool pcie_mdiosetblock(struct pcicore_info *pi, uint blk)
-{
- uint mdiodata, i = 0;
- uint pcie_serdes_spinwait = 200;
-
- mdiodata = (MDIODATA_START | MDIODATA_WRITE | MDIODATA_TA |
- (MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) |
- (MDIODATA_BLK_ADDR << MDIODATA_REGADDR_SHF) |
- (blk << 4));
- bcma_write32(pi->core, PCIEREGOFFS(mdiodata), mdiodata);
-
- pr28829_delay();
- /* retry till the transaction is complete */
- while (i < pcie_serdes_spinwait) {
- if (bcma_read32(pi->core, PCIEREGOFFS(mdiocontrol)) &
- MDIOCTL_ACCESS_DONE)
- break;
-
- udelay(1000);
- i++;
- }
-
- if (i >= pcie_serdes_spinwait)
- return false;
-
- return true;
-}
-
-static int
-pcie_mdioop(struct pcicore_info *pi, uint physmedia, uint regaddr, bool write,
- uint *val)
-{
- uint mdiodata;
- uint i = 0;
- uint pcie_serdes_spinwait = 10;
-
- /* enable mdio access to SERDES */
- bcma_write32(pi->core, PCIEREGOFFS(mdiocontrol),
- MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL);
-
- if (ai_get_buscorerev(pi->sih) >= 10) {
- /* new serdes is slower in rw,
- * using two layers of reg address mapping
- */
- if (!pcie_mdiosetblock(pi, physmedia))
- return 1;
- mdiodata = ((MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) |
- (regaddr << MDIODATA_REGADDR_SHF));
- pcie_serdes_spinwait *= 20;
- } else {
- mdiodata = ((physmedia << MDIODATA_DEVADDR_SHF_OLD) |
- (regaddr << MDIODATA_REGADDR_SHF_OLD));
- }
-
- if (!write)
- mdiodata |= (MDIODATA_START | MDIODATA_READ | MDIODATA_TA);
- else
- mdiodata |= (MDIODATA_START | MDIODATA_WRITE | MDIODATA_TA |
- *val);
-
- bcma_write32(pi->core, PCIEREGOFFS(mdiodata), mdiodata);
-
- pr28829_delay();
-
- /* retry till the transaction is complete */
- while (i < pcie_serdes_spinwait) {
- if (bcma_read32(pi->core, PCIEREGOFFS(mdiocontrol)) &
- MDIOCTL_ACCESS_DONE) {
- if (!write) {
- pr28829_delay();
- *val = (bcma_read32(pi->core,
- PCIEREGOFFS(mdiodata)) &
- MDIODATA_MASK);
- }
- /* Disable mdio access to SERDES */
- bcma_write32(pi->core, PCIEREGOFFS(mdiocontrol), 0);
- return 0;
- }
- udelay(1000);
- i++;
- }
-
- /* Timed out. Disable mdio access to SERDES. */
- bcma_write32(pi->core, PCIEREGOFFS(mdiocontrol), 0);
- return 1;
-}
-
-/* use the mdio interface to read from mdio slaves */
-static int
-pcie_mdioread(struct pcicore_info *pi, uint physmedia, uint regaddr,
- uint *regval)
-{
- return pcie_mdioop(pi, physmedia, regaddr, false, regval);
-}
-
-/* use the mdio interface to write to mdio slaves */
-static int
-pcie_mdiowrite(struct pcicore_info *pi, uint physmedia, uint regaddr, uint val)
-{
- return pcie_mdioop(pi, physmedia, regaddr, true, &val);
-}
-
-/* ***** Support functions ***** */
-static u8 pcie_clkreq(struct pcicore_info *pi, u32 mask, u32 val)
-{
- u32 reg_val;
- u8 offset;
-
- offset = pi->pciecap_lcreg_offset;
- if (!offset)
- return 0;
-
- pci_read_config_dword(pi->dev, offset, &reg_val);
- /* set operation */
- if (mask) {
- if (val)
- reg_val |= PCIE_CLKREQ_ENAB;
- else
- reg_val &= ~PCIE_CLKREQ_ENAB;
- pci_write_config_dword(pi->dev, offset, reg_val);
- pci_read_config_dword(pi->dev, offset, &reg_val);
- }
- if (reg_val & PCIE_CLKREQ_ENAB)
- return 1;
- else
- return 0;
-}
-
-static void pcie_extendL1timer(struct pcicore_info *pi, bool extend)
-{
- u32 w;
- struct si_pub *sih = pi->sih;
-
- if (ai_get_buscoretype(sih) != PCIE_CORE_ID ||
- ai_get_buscorerev(sih) < 7)
- return;
-
- w = pcie_readreg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG);
- if (extend)
- w |= PCIE_ASPMTIMER_EXTEND;
- else
- w &= ~PCIE_ASPMTIMER_EXTEND;
- pcie_writereg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG, w);
- w = pcie_readreg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG);
-}
-
-/* centralized clkreq control policy */
-static void pcie_clkreq_upd(struct pcicore_info *pi, uint state)
-{
- struct si_pub *sih = pi->sih;
-
- switch (state) {
- case SI_DOATTACH:
- if (PCIE_ASPM(sih))
- pcie_clkreq(pi, 1, 0);
- break;
- case SI_PCIDOWN:
- /* turn on serdes PLL down */
- if (ai_get_buscorerev(sih) == 6) {
- ai_cc_reg(sih,
- offsetof(struct chipcregs, chipcontrol_addr),
- ~0, 0);
- ai_cc_reg(sih,
- offsetof(struct chipcregs, chipcontrol_data),
- ~0x40, 0);
- } else if (pi->pcie_pr42767) {
- pcie_clkreq(pi, 1, 1);
- }
- break;
- case SI_PCIUP:
- /* turn off serdes PLL down */
- if (ai_get_buscorerev(sih) == 6) {
- ai_cc_reg(sih,
- offsetof(struct chipcregs, chipcontrol_addr),
- ~0, 0);
- ai_cc_reg(sih,
- offsetof(struct chipcregs, chipcontrol_data),
- ~0x40, 0x40);
- } else if (PCIE_ASPM(sih)) { /* disable clkreq */
- pcie_clkreq(pi, 1, 0);
- }
- break;
- }
-}
-
-/* ***** PCI core WARs ***** */
-/* Done only once at attach time */
-static void pcie_war_polarity(struct pcicore_info *pi)
-{
- u32 w;
-
- if (pi->pcie_polarity != 0)
- return;
-
- w = pcie_readreg(pi->core, PCIE_PCIEREGS, PCIE_PLP_STATUSREG);
-
- /* Detect the current polarity at attach and force that polarity and
- * disable changing the polarity
- */
- if ((w & PCIE_PLP_POLARITYINV_STAT) == 0)
- pi->pcie_polarity = SERDES_RX_CTRL_FORCE;
- else
- pi->pcie_polarity = (SERDES_RX_CTRL_FORCE |
- SERDES_RX_CTRL_POLARITY);
-}
-
-/* enable ASPM and CLKREQ if srom doesn't have it */
-/* Needs to happen when update to shadow SROM is needed
- * : Coming out of 'standby'/'hibernate'
- * : If pcie_war_aspm_ovr state changed
- */
-static void pcie_war_aspm_clkreq(struct pcicore_info *pi)
-{
- struct si_pub *sih = pi->sih;
- u16 val16;
- u32 w;
-
- if (!PCIE_ASPM(sih))
- return;
-
- /* bypass this on QT or VSIM */
- val16 = bcma_read16(pi->core, PCIEREGOFFS(sprom[SRSH_ASPM_OFFSET]));
-
- val16 &= ~SRSH_ASPM_ENB;
- if (pi->pcie_war_aspm_ovr == PCIE_ASPM_ENAB)
- val16 |= SRSH_ASPM_ENB;
- else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L1_ENAB)
- val16 |= SRSH_ASPM_L1_ENB;
- else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L0s_ENAB)
- val16 |= SRSH_ASPM_L0s_ENB;
-
- bcma_write16(pi->core, PCIEREGOFFS(sprom[SRSH_ASPM_OFFSET]), val16);
-
- pci_read_config_dword(pi->dev, pi->pciecap_lcreg_offset, &w);
- w &= ~PCIE_ASPM_ENAB;
- w |= pi->pcie_war_aspm_ovr;
- pci_write_config_dword(pi->dev, pi->pciecap_lcreg_offset, w);
-
- val16 = bcma_read16(pi->core,
- PCIEREGOFFS(sprom[SRSH_CLKREQ_OFFSET_REV5]));
-
- if (pi->pcie_war_aspm_ovr != PCIE_ASPM_DISAB) {
- val16 |= SRSH_CLKREQ_ENB;
- pi->pcie_pr42767 = true;
- } else
- val16 &= ~SRSH_CLKREQ_ENB;
-
- bcma_write16(pi->core, PCIEREGOFFS(sprom[SRSH_CLKREQ_OFFSET_REV5]),
- val16);
-}
-
-/* Apply the polarity determined at the start */
-/* Needs to happen when coming out of 'standby'/'hibernate' */
-static void pcie_war_serdes(struct pcicore_info *pi)
-{
- u32 w = 0;
-
- if (pi->pcie_polarity != 0)
- pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CTRL,
- pi->pcie_polarity);
-
- pcie_mdioread(pi, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, &w);
- if (w & PLL_CTRL_FREQDET_EN) {
- w &= ~PLL_CTRL_FREQDET_EN;
- pcie_mdiowrite(pi, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, w);
- }
-}
-
-/* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */
-/* Needs to happen when coming out of 'standby'/'hibernate' */
-static void pcie_misc_config_fixup(struct pcicore_info *pi)
-{
- u16 val16;
-
- val16 = bcma_read16(pi->core,
- PCIEREGOFFS(sprom[SRSH_PCIE_MISC_CONFIG]));
-
- if ((val16 & SRSH_L23READY_EXIT_NOPERST) == 0) {
- val16 |= SRSH_L23READY_EXIT_NOPERST;
- bcma_write16(pi->core,
- PCIEREGOFFS(sprom[SRSH_PCIE_MISC_CONFIG]), val16);
- }
-}
-
-/* quick hack for testing */
-/* Needs to happen when coming out of 'standby'/'hibernate' */
-static void pcie_war_noplldown(struct pcicore_info *pi)
-{
- /* turn off serdes PLL down */
- ai_cc_reg(pi->sih, offsetof(struct chipcregs, chipcontrol),
- CHIPCTRL_4321_PLL_DOWN, CHIPCTRL_4321_PLL_DOWN);
-
- /* clear srom shadow backdoor */
- bcma_write16(pi->core, PCIEREGOFFS(sprom[SRSH_BD_OFFSET]), 0);
-}
-
-/* Needs to happen when coming out of 'standby'/'hibernate' */
-static void pcie_war_pci_setup(struct pcicore_info *pi)
-{
- struct si_pub *sih = pi->sih;
- u32 w;
-
- if (ai_get_buscorerev(sih) == 0 || ai_get_buscorerev(sih) == 1) {
- w = pcie_readreg(pi->core, PCIE_PCIEREGS,
- PCIE_TLP_WORKAROUNDSREG);
- w |= 0x8;
- pcie_writereg(pi->core, PCIE_PCIEREGS,
- PCIE_TLP_WORKAROUNDSREG, w);
- }
-
- if (ai_get_buscorerev(sih) == 1) {
- w = pcie_readreg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_LCREG);
- w |= 0x40;
- pcie_writereg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_LCREG, w);
- }
-
- if (ai_get_buscorerev(sih) == 0) {
- pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_TIMER1, 0x8128);
- pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDR, 0x0100);
- pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDRBW, 0x1466);
- } else if (PCIE_ASPM(sih)) {
- /* Change the L1 threshold for better performance */
- w = pcie_readreg(pi->core, PCIE_PCIEREGS,
- PCIE_DLLP_PMTHRESHREG);
- w &= ~PCIE_L1THRESHOLDTIME_MASK;
- w |= PCIE_L1THRESHOLD_WARVAL << PCIE_L1THRESHOLDTIME_SHIFT;
- pcie_writereg(pi->core, PCIE_PCIEREGS,
- PCIE_DLLP_PMTHRESHREG, w);
-
- pcie_war_serdes(pi);
-
- pcie_war_aspm_clkreq(pi);
- } else if (ai_get_buscorerev(pi->sih) == 7)
- pcie_war_noplldown(pi);
-
- /* Note that the fix is actually in the SROM,
- * that's why this is open-ended
- */
- if (ai_get_buscorerev(pi->sih) >= 6)
- pcie_misc_config_fixup(pi);
-}
-
-/* ***** Functions called during driver state changes ***** */
-void pcicore_attach(struct pcicore_info *pi, int state)
-{
- struct si_pub *sih = pi->sih;
- u32 bfl2 = (u32)getintvar(sih, BRCMS_SROM_BOARDFLAGS2);
-
- /* Determine if this board needs override */
- if (PCIE_ASPM(sih)) {
- if (bfl2 & BFL2_PCIEWAR_OVR)
- pi->pcie_war_aspm_ovr = PCIE_ASPM_DISAB;
- else
- pi->pcie_war_aspm_ovr = PCIE_ASPM_ENAB;
- }
-
- /* These need to happen in this order only */
- pcie_war_polarity(pi);
-
- pcie_war_serdes(pi);
-
- pcie_war_aspm_clkreq(pi);
-
- pcie_clkreq_upd(pi, state);
-
-}
-
-void pcicore_hwup(struct pcicore_info *pi)
-{
- if (!pi || ai_get_buscoretype(pi->sih) != PCIE_CORE_ID)
- return;
-
- pcie_war_pci_setup(pi);
-}
-
-void pcicore_up(struct pcicore_info *pi, int state)
-{
- if (!pi || ai_get_buscoretype(pi->sih) != PCIE_CORE_ID)
- return;
-
- /* Restore L1 timer for better performance */
- pcie_extendL1timer(pi, true);
-
- pcie_clkreq_upd(pi, state);
-}
-
-/* When the device is going to enter D3 state
- * (or the system is going to enter S3/S4 states)
- */
-void pcicore_sleep(struct pcicore_info *pi)
-{
- u32 w;
-
- if (!pi || !PCIE_ASPM(pi->sih))
- return;
-
- pci_read_config_dword(pi->dev, pi->pciecap_lcreg_offset, &w);
- w &= ~PCIE_CAP_LCREG_ASPML1;
- pci_write_config_dword(pi->dev, pi->pciecap_lcreg_offset, w);
-
- pi->pcie_pr42767 = false;
-}
-
-void pcicore_down(struct pcicore_info *pi, int state)
-{
- if (!pi || ai_get_buscoretype(pi->sih) != PCIE_CORE_ID)
- return;
-
- pcie_clkreq_upd(pi, state);
-
- /* Reduce L1 timer for better power savings */
- pcie_extendL1timer(pi, false);
-}
-
-void pcicore_fixcfg(struct pcicore_info *pi)
-{
- struct bcma_device *core = pi->core;
- u16 val16;
- uint regoff;
-
- switch (pi->core->id.id) {
- case BCMA_CORE_PCI:
- regoff = PCIREGOFFS(sprom[SRSH_PI_OFFSET]);
- break;
-
- case BCMA_CORE_PCIE:
- regoff = PCIEREGOFFS(sprom[SRSH_PI_OFFSET]);
- break;
-
- default:
- return;
- }
-
- val16 = bcma_read16(pi->core, regoff);
- if (((val16 & SRSH_PI_MASK) >> SRSH_PI_SHIFT) !=
- (u16)core->core_index) {
- val16 = ((u16)core->core_index << SRSH_PI_SHIFT) |
- (val16 & ~SRSH_PI_MASK);
- bcma_write16(pi->core, regoff, val16);
- }
-}
-
-/* precondition: current core is pci core */
-void
-pcicore_pci_setup(struct pcicore_info *pi)
-{
- bcma_set32(pi->core, PCIREGOFFS(sbtopci2),
- SBTOPCI_PREF | SBTOPCI_BURST);
-
- if (pi->core->id.rev >= 11) {
- bcma_set32(pi->core, PCIREGOFFS(sbtopci2),
- SBTOPCI_RC_READMULTI);
- bcma_set32(pi->core, PCIREGOFFS(clkrun), PCI_CLKRUN_DSBL);
- (void)bcma_read32(pi->core, PCIREGOFFS(clkrun));
- }
-}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/nicpci.h b/drivers/net/wireless/brcm80211/brcmsmac/nicpci.h
deleted file mode 100644
index 9fc3ead540a8..000000000000
--- a/drivers/net/wireless/brcm80211/brcmsmac/nicpci.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _BRCM_NICPCI_H_
-#define _BRCM_NICPCI_H_
-
-#include "types.h"
-
-/* PCI configuration address space size */
-#define PCI_SZPCR 256
-
-/* Brcm PCI configuration registers */
-/* backplane address space accessed by BAR0 */
-#define PCI_BAR0_WIN 0x80
-/* sprom property control */
-#define PCI_SPROM_CONTROL 0x88
-/* mask of PCI and other cores interrupts */
-#define PCI_INT_MASK 0x94
-/* backplane core interrupt mask bits offset */
-#define PCI_SBIM_SHIFT 8
-/* backplane address space accessed by second 4KB of BAR0 */
-#define PCI_BAR0_WIN2 0xac
-/* pci config space gpio input (>=rev3) */
-#define PCI_GPIO_IN 0xb0
-/* pci config space gpio output (>=rev3) */
-#define PCI_GPIO_OUT 0xb4
-/* pci config space gpio output enable (>=rev3) */
-#define PCI_GPIO_OUTEN 0xb8
-
-/* bar0 + 4K accesses external sprom */
-#define PCI_BAR0_SPROM_OFFSET (4 * 1024)
-/* bar0 + 6K accesses pci core registers */
-#define PCI_BAR0_PCIREGS_OFFSET (6 * 1024)
-/*
- * pci core SB registers are at the end of the
- * 8KB window, so their address is the "regular"
- * address plus 4K
- */
-#define PCI_BAR0_PCISBR_OFFSET (4 * 1024)
-/* bar0 window size Match with corerev 13 */
-#define PCI_BAR0_WINSZ (16 * 1024)
-/* On pci corerev >= 13 and all pcie, the bar0 is now 16KB and it maps: */
-/* bar0 + 8K accesses pci/pcie core registers */
-#define PCI_16KB0_PCIREGS_OFFSET (8 * 1024)
-/* bar0 + 12K accesses chipc core registers */
-#define PCI_16KB0_CCREGS_OFFSET (12 * 1024)
-
-struct sbpciregs;
-struct sbpcieregs;
-
-extern struct pcicore_info *pcicore_init(struct si_pub *sih,
- struct bcma_device *core);
-extern void pcicore_deinit(struct pcicore_info *pch);
-extern void pcicore_attach(struct pcicore_info *pch, int state);
-extern void pcicore_hwup(struct pcicore_info *pch);
-extern void pcicore_up(struct pcicore_info *pch, int state);
-extern void pcicore_sleep(struct pcicore_info *pch);
-extern void pcicore_down(struct pcicore_info *pch, int state);
-extern u8 pcicore_find_pci_capability(struct pci_dev *dev, u8 req_cap_id,
- unsigned char *buf, u32 *buflen);
-extern void pcicore_fixcfg(struct pcicore_info *pch);
-extern void pcicore_pci_setup(struct pcicore_info *pch);
-
-#endif /* _BRCM_NICPCI_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/otp.c b/drivers/net/wireless/brcm80211/brcmsmac/otp.c
deleted file mode 100644
index f1ca12625860..000000000000
--- a/drivers/net/wireless/brcm80211/brcmsmac/otp.c
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <linux/io.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-
-#include <brcm_hw_ids.h>
-#include <chipcommon.h>
-#include "aiutils.h"
-#include "otp.h"
-
-#define OTPS_GUP_MASK 0x00000f00
-#define OTPS_GUP_SHIFT 8
-/* h/w subregion is programmed */
-#define OTPS_GUP_HW 0x00000100
-/* s/w subregion is programmed */
-#define OTPS_GUP_SW 0x00000200
-/* chipid/pkgopt subregion is programmed */
-#define OTPS_GUP_CI 0x00000400
-/* fuse subregion is programmed */
-#define OTPS_GUP_FUSE 0x00000800
-
-/* Fields in otpprog in rev >= 21 */
-#define OTPP_COL_MASK 0x000000ff
-#define OTPP_COL_SHIFT 0
-#define OTPP_ROW_MASK 0x0000ff00
-#define OTPP_ROW_SHIFT 8
-#define OTPP_OC_MASK 0x0f000000
-#define OTPP_OC_SHIFT 24
-#define OTPP_READERR 0x10000000
-#define OTPP_VALUE_MASK 0x20000000
-#define OTPP_VALUE_SHIFT 29
-#define OTPP_START_BUSY 0x80000000
-#define OTPP_READ 0x40000000
-
-/* Opcodes for OTPP_OC field */
-#define OTPPOC_READ 0
-#define OTPPOC_BIT_PROG 1
-#define OTPPOC_VERIFY 3
-#define OTPPOC_INIT 4
-#define OTPPOC_SET 5
-#define OTPPOC_RESET 6
-#define OTPPOC_OCST 7
-#define OTPPOC_ROW_LOCK 8
-#define OTPPOC_PRESCN_TEST 9
-
-#define OTPTYPE_IPX(ccrev) ((ccrev) == 21 || (ccrev) >= 23)
-
-#define OTPP_TRIES 10000000 /* # of tries for OTPP */
-
-#define MAXNUMRDES 9 /* Maximum OTP redundancy entries */
-
-/* Fixed size subregions sizes in words */
-#define OTPGU_CI_SZ 2
-
-struct otpinfo;
-
-/* OTP function struct */
-struct otp_fn_s {
- int (*init)(struct si_pub *sih, struct otpinfo *oi);
- int (*read_region)(struct otpinfo *oi, int region, u16 *data,
- uint *wlen);
-};
-
-struct otpinfo {
- struct bcma_device *core; /* chipc core */
- const struct otp_fn_s *fn; /* OTP functions */
- struct si_pub *sih; /* Saved sb handle */
-
- /* IPX OTP section */
- u16 wsize; /* Size of otp in words */
- u16 rows; /* Geometry */
- u16 cols; /* Geometry */
- u32 status; /* Flag bits (lock/prog/rv).
- * (Reflected only when OTP is power cycled)
- */
- u16 hwbase; /* hardware subregion offset */
- u16 hwlim; /* hardware subregion boundary */
- u16 swbase; /* software subregion offset */
- u16 swlim; /* software subregion boundary */
- u16 fbase; /* fuse subregion offset */
- u16 flim; /* fuse subregion boundary */
- int otpgu_base; /* offset to General Use Region */
-};
-
-/* OTP layout */
-/* CC revs 21, 24 and 27 OTP General Use Region word offset */
-#define REVA4_OTPGU_BASE 12
-
-/* CC revs 23, 25, 26, 28 and above OTP General Use Region word offset */
-#define REVB8_OTPGU_BASE 20
-
-/* CC rev 36 OTP General Use Region word offset */
-#define REV36_OTPGU_BASE 12
-
-/* Subregion word offsets in General Use region */
-#define OTPGU_HSB_OFF 0
-#define OTPGU_SFB_OFF 1
-#define OTPGU_CI_OFF 2
-#define OTPGU_P_OFF 3
-#define OTPGU_SROM_OFF 4
-
-/* Flag bit offsets in General Use region */
-#define OTPGU_HWP_OFF 60
-#define OTPGU_SWP_OFF 61
-#define OTPGU_CIP_OFF 62
-#define OTPGU_FUSEP_OFF 63
-#define OTPGU_CIP_MSK 0x4000
-#define OTPGU_P_MSK 0xf000
-#define OTPGU_P_SHIFT (OTPGU_HWP_OFF % 16)
-
-/* OTP Size */
-#define OTP_SZ_FU_324 ((roundup(324, 8))/8) /* 324 bits */
-#define OTP_SZ_FU_288 (288/8) /* 288 bits */
-#define OTP_SZ_FU_216 (216/8) /* 216 bits */
-#define OTP_SZ_FU_72 (72/8) /* 72 bits */
-#define OTP_SZ_CHECKSUM (16/8) /* 16 bits */
-#define OTP4315_SWREG_SZ 178 /* 178 bytes */
-#define OTP_SZ_FU_144 (144/8) /* 144 bits */
-
-static u16
-ipxotp_otpr(struct otpinfo *oi, uint wn)
-{
- return bcma_read16(oi->core,
- CHIPCREGOFFS(sromotp[wn]));
-}
-
-/*
- * Calculate max HW/SW region byte size by subtracting fuse region
- * and checksum size, osizew is oi->wsize (OTP size - GU size) in words
- */
-static int ipxotp_max_rgnsz(struct si_pub *sih, int osizew)
-{
- int ret = 0;
-
- switch (ai_get_chip_id(sih)) {
- case BCM43224_CHIP_ID:
- case BCM43225_CHIP_ID:
- ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM;
- break;
- case BCM4313_CHIP_ID:
- ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM;
- break;
- default:
- break; /* Don't know about this chip */
- }
-
- return ret;
-}
-
-static void _ipxotp_init(struct otpinfo *oi)
-{
- uint k;
- u32 otpp, st;
- int ccrev = ai_get_ccrev(oi->sih);
-
-
- /*
- * record word offset of General Use Region
- * for various chipcommon revs
- */
- if (ccrev == 21 || ccrev == 24
- || ccrev == 27) {
- oi->otpgu_base = REVA4_OTPGU_BASE;
- } else if (ccrev == 36) {
- /*
- * OTP size greater than equal to 2KB (128 words),
- * otpgu_base is similar to rev23
- */
- if (oi->wsize >= 128)
- oi->otpgu_base = REVB8_OTPGU_BASE;
- else
- oi->otpgu_base = REV36_OTPGU_BASE;
- } else if (ccrev == 23 || ccrev >= 25) {
- oi->otpgu_base = REVB8_OTPGU_BASE;
- }
-
- /* First issue an init command so the status is up to date */
- otpp =
- OTPP_START_BUSY | ((OTPPOC_INIT << OTPP_OC_SHIFT) & OTPP_OC_MASK);
-
- bcma_write32(oi->core, CHIPCREGOFFS(otpprog), otpp);
- st = bcma_read32(oi->core, CHIPCREGOFFS(otpprog));
- for (k = 0; (st & OTPP_START_BUSY) && (k < OTPP_TRIES); k++)
- st = bcma_read32(oi->core, CHIPCREGOFFS(otpprog));
- if (k >= OTPP_TRIES)
- return;
-
- /* Read OTP lock bits and subregion programmed indication bits */
- oi->status = bcma_read32(oi->core, CHIPCREGOFFS(otpstatus));
-
- if ((ai_get_chip_id(oi->sih) == BCM43224_CHIP_ID)
- || (ai_get_chip_id(oi->sih) == BCM43225_CHIP_ID)) {
- u32 p_bits;
- p_bits = (ipxotp_otpr(oi, oi->otpgu_base + OTPGU_P_OFF) &
- OTPGU_P_MSK) >> OTPGU_P_SHIFT;
- oi->status |= (p_bits << OTPS_GUP_SHIFT);
- }
-
- /*
- * h/w region base and fuse region limit are fixed to
- * the top and the bottom of the general use region.
- * Everything else can be flexible.
- */
- oi->hwbase = oi->otpgu_base + OTPGU_SROM_OFF;
- oi->hwlim = oi->wsize;
- if (oi->status & OTPS_GUP_HW) {
- oi->hwlim =
- ipxotp_otpr(oi, oi->otpgu_base + OTPGU_HSB_OFF) / 16;
- oi->swbase = oi->hwlim;
- } else
- oi->swbase = oi->hwbase;
-
- /* subtract fuse and checksum from beginning */
- oi->swlim = ipxotp_max_rgnsz(oi->sih, oi->wsize) / 2;
-
- if (oi->status & OTPS_GUP_SW) {
- oi->swlim =
- ipxotp_otpr(oi, oi->otpgu_base + OTPGU_SFB_OFF) / 16;
- oi->fbase = oi->swlim;
- } else
- oi->fbase = oi->swbase;
-
- oi->flim = oi->wsize;
-}
-
-static int ipxotp_init(struct si_pub *sih, struct otpinfo *oi)
-{
- /* Make sure we're running IPX OTP */
- if (!OTPTYPE_IPX(ai_get_ccrev(sih)))
- return -EBADE;
-
- /* Make sure OTP is not disabled */
- if (ai_is_otp_disabled(sih))
- return -EBADE;
-
- /* Check for otp size */
- switch ((ai_get_cccaps(sih) & CC_CAP_OTPSIZE) >> CC_CAP_OTPSIZE_SHIFT) {
- case 0:
- /* Nothing there */
- return -EBADE;
- case 1: /* 32x64 */
- oi->rows = 32;
- oi->cols = 64;
- oi->wsize = 128;
- break;
- case 2: /* 64x64 */
- oi->rows = 64;
- oi->cols = 64;
- oi->wsize = 256;
- break;
- case 5: /* 96x64 */
- oi->rows = 96;
- oi->cols = 64;
- oi->wsize = 384;
- break;
- case 7: /* 16x64 *//* 1024 bits */
- oi->rows = 16;
- oi->cols = 64;
- oi->wsize = 64;
- break;
- default:
- /* Don't know the geometry */
- return -EBADE;
- }
-
- /* Retrieve OTP region info */
- _ipxotp_init(oi);
- return 0;
-}
-
-static int
-ipxotp_read_region(struct otpinfo *oi, int region, u16 *data, uint *wlen)
-{
- uint base, i, sz;
-
- /* Validate region selection */
- switch (region) {
- case OTP_HW_RGN:
- sz = (uint) oi->hwlim - oi->hwbase;
- if (!(oi->status & OTPS_GUP_HW)) {
- *wlen = sz;
- return -ENODATA;
- }
- if (*wlen < sz) {
- *wlen = sz;
- return -EOVERFLOW;
- }
- base = oi->hwbase;
- break;
- case OTP_SW_RGN:
- sz = ((uint) oi->swlim - oi->swbase);
- if (!(oi->status & OTPS_GUP_SW)) {
- *wlen = sz;
- return -ENODATA;
- }
- if (*wlen < sz) {
- *wlen = sz;
- return -EOVERFLOW;
- }
- base = oi->swbase;
- break;
- case OTP_CI_RGN:
- sz = OTPGU_CI_SZ;
- if (!(oi->status & OTPS_GUP_CI)) {
- *wlen = sz;
- return -ENODATA;
- }
- if (*wlen < sz) {
- *wlen = sz;
- return -EOVERFLOW;
- }
- base = oi->otpgu_base + OTPGU_CI_OFF;
- break;
- case OTP_FUSE_RGN:
- sz = (uint) oi->flim - oi->fbase;
- if (!(oi->status & OTPS_GUP_FUSE)) {
- *wlen = sz;
- return -ENODATA;
- }
- if (*wlen < sz) {
- *wlen = sz;
- return -EOVERFLOW;
- }
- base = oi->fbase;
- break;
- case OTP_ALL_RGN:
- sz = ((uint) oi->flim - oi->hwbase);
- if (!(oi->status & (OTPS_GUP_HW | OTPS_GUP_SW))) {
- *wlen = sz;
- return -ENODATA;
- }
- if (*wlen < sz) {
- *wlen = sz;
- return -EOVERFLOW;
- }
- base = oi->hwbase;
- break;
- default:
- return -EINVAL;
- }
-
- /* Read the data */
- for (i = 0; i < sz; i++)
- data[i] = ipxotp_otpr(oi, base + i);
-
- *wlen = sz;
- return 0;
-}
-
-static const struct otp_fn_s ipxotp_fn = {
- (int (*)(struct si_pub *, struct otpinfo *)) ipxotp_init,
- (int (*)(struct otpinfo *, int, u16 *, uint *)) ipxotp_read_region,
-};
-
-static int otp_init(struct si_pub *sih, struct otpinfo *oi)
-{
- int ret;
-
- memset(oi, 0, sizeof(struct otpinfo));
-
- oi->core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0);
-
- if (OTPTYPE_IPX(ai_get_ccrev(sih)))
- oi->fn = &ipxotp_fn;
-
- if (oi->fn == NULL)
- return -EBADE;
-
- oi->sih = sih;
-
- ret = (oi->fn->init)(sih, oi);
-
- return ret;
-}
-
-int
-otp_read_region(struct si_pub *sih, int region, u16 *data, uint *wlen) {
- struct otpinfo otpinfo;
- struct otpinfo *oi = &otpinfo;
- int err = 0;
-
- if (ai_is_otp_disabled(sih)) {
- err = -EPERM;
- goto out;
- }
-
- err = otp_init(sih, oi);
- if (err)
- goto out;
-
- err = ((oi)->fn->read_region)(oi, region, data, wlen);
-
- out:
- return err;
-}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/otp.h b/drivers/net/wireless/brcm80211/brcmsmac/otp.h
deleted file mode 100644
index 6b6d31cf9569..000000000000
--- a/drivers/net/wireless/brcm80211/brcmsmac/otp.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _BRCM_OTP_H_
-#define _BRCM_OTP_H_
-
-#include "types.h"
-
-/* OTP regions */
-#define OTP_HW_RGN 1
-#define OTP_SW_RGN 2
-#define OTP_CI_RGN 4
-#define OTP_FUSE_RGN 8
-/* From h/w region to end of OTP including checksum */
-#define OTP_ALL_RGN 0xf
-
-/* OTP Size */
-#define OTP_SZ_MAX (6144/8) /* maximum bytes in one CIS */
-
-extern int otp_read_region(struct si_pub *sih, int region, u16 *data,
- uint *wlen);
-
-#endif /* _BRCM_OTP_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
index 0fce56235f38..abfd78822fb8 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
@@ -4817,28 +4817,23 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
s8 txpwr = 0;
int i;
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
- struct phy_shim_info *shim = pi->sh->physhim;
+ struct ssb_sprom *sprom = &pi->d11core->bus->sprom;
if (CHSPEC_IS2G(pi->radio_chanspec)) {
u16 cckpo = 0;
u32 offset_ofdm, offset_mcs;
- pi_lcn->lcnphy_tr_isolation_mid =
- (u8)wlapi_getintvar(shim, BRCMS_SROM_TRISO2G);
+ pi_lcn->lcnphy_tr_isolation_mid = sprom->fem.ghz2.tr_iso;
- pi_lcn->lcnphy_rx_power_offset =
- (u8)wlapi_getintvar(shim, BRCMS_SROM_RXPO2G);
+ pi_lcn->lcnphy_rx_power_offset = sprom->rxpo2g;
- pi->txpa_2g[0] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B0);
- pi->txpa_2g[1] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B1);
- pi->txpa_2g[2] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B2);
+ pi->txpa_2g[0] = sprom->pa0b0;
+ pi->txpa_2g[1] = sprom->pa0b1;
+ pi->txpa_2g[2] = sprom->pa0b2;
- pi_lcn->lcnphy_rssi_vf =
- (u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISMF2G);
- pi_lcn->lcnphy_rssi_vc =
- (u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISMC2G);
- pi_lcn->lcnphy_rssi_gs =
- (u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISAV2G);
+ pi_lcn->lcnphy_rssi_vf = sprom->rssismf2g;
+ pi_lcn->lcnphy_rssi_vc = sprom->rssismc2g;
+ pi_lcn->lcnphy_rssi_gs = sprom->rssisav2g;
pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf;
pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc;
@@ -4848,7 +4843,7 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
pi_lcn->lcnphy_rssi_vc_hightemp = pi_lcn->lcnphy_rssi_vc;
pi_lcn->lcnphy_rssi_gs_hightemp = pi_lcn->lcnphy_rssi_gs;
- txpwr = (s8)wlapi_getintvar(shim, BRCMS_SROM_MAXP2GA0);
+ txpwr = sprom->core_pwr_info[0].maxpwr_2g;
pi->tx_srom_max_2g = txpwr;
for (i = 0; i < PWRTBL_NUM_COEFF; i++) {
@@ -4856,8 +4851,8 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
pi->txpa_2g_high_temp[i] = pi->txpa_2g[i];
}
- cckpo = (u16)wlapi_getintvar(shim, BRCMS_SROM_CCK2GPO);
- offset_ofdm = (u32)wlapi_getintvar(shim, BRCMS_SROM_OFDM2GPO);
+ cckpo = sprom->cck2gpo;
+ offset_ofdm = sprom->ofdm2gpo;
if (cckpo) {
uint max_pwr_chan = txpwr;
@@ -4876,7 +4871,7 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
} else {
u8 opo = 0;
- opo = (u8)wlapi_getintvar(shim, BRCMS_SROM_OPO);
+ opo = sprom->opo;
for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++)
pi->tx_srom_max_rate_2g[i] = txpwr;
@@ -4886,12 +4881,8 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
((offset_ofdm & 0xf) * 2);
offset_ofdm >>= 4;
}
- offset_mcs =
- wlapi_getintvar(shim,
- BRCMS_SROM_MCS2GPO1) << 16;
- offset_mcs |=
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS2GPO0);
+ offset_mcs = sprom->mcs2gpo[1] << 16;
+ offset_mcs |= sprom->mcs2gpo[0];
pi_lcn->lcnphy_mcs20_po = offset_mcs;
for (i = TXP_FIRST_SISO_MCS_20;
i <= TXP_LAST_SISO_MCS_20; i++) {
@@ -4901,25 +4892,17 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
}
}
- pi_lcn->lcnphy_rawtempsense =
- (u16)wlapi_getintvar(shim, BRCMS_SROM_RAWTEMPSENSE);
- pi_lcn->lcnphy_measPower =
- (u8)wlapi_getintvar(shim, BRCMS_SROM_MEASPOWER);
- pi_lcn->lcnphy_tempsense_slope =
- (u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPSENSE_SLOPE);
- pi_lcn->lcnphy_hw_iqcal_en =
- (bool)wlapi_getintvar(shim, BRCMS_SROM_HW_IQCAL_EN);
- pi_lcn->lcnphy_iqcal_swp_dis =
- (bool)wlapi_getintvar(shim, BRCMS_SROM_IQCAL_SWP_DIS);
- pi_lcn->lcnphy_tempcorrx =
- (u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPCORRX);
- pi_lcn->lcnphy_tempsense_option =
- (u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPSENSE_OPTION);
- pi_lcn->lcnphy_freqoffset_corr =
- (u8)wlapi_getintvar(shim, BRCMS_SROM_FREQOFFSET_CORR);
- if ((u8)wlapi_getintvar(shim, BRCMS_SROM_AA2G) > 1)
+ pi_lcn->lcnphy_rawtempsense = sprom->rawtempsense;
+ pi_lcn->lcnphy_measPower = sprom->measpower;
+ pi_lcn->lcnphy_tempsense_slope = sprom->tempsense_slope;
+ pi_lcn->lcnphy_hw_iqcal_en = sprom->hw_iqcal_en;
+ pi_lcn->lcnphy_iqcal_swp_dis = sprom->iqcal_swp_dis;
+ pi_lcn->lcnphy_tempcorrx = sprom->tempcorrx;
+ pi_lcn->lcnphy_tempsense_option = sprom->tempsense_option;
+ pi_lcn->lcnphy_freqoffset_corr = sprom->freqoffset_corr;
+ if (sprom->ant_available_bg > 1)
wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi,
- (u8) wlapi_getintvar(shim, BRCMS_SROM_AA2G));
+ sprom->ant_available_bg);
}
pi_lcn->lcnphy_cck_dig_filt_type = -1;
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
index 812b6e38526e..13b261517cce 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
@@ -14386,30 +14386,30 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
{
u16 bw40po, cddpo, stbcpo, bwduppo;
uint band_num;
- struct phy_shim_info *shim = pi->sh->physhim;
+ struct ssb_sprom *sprom = &pi->d11core->bus->sprom;
if (pi->sh->sromrev >= 9)
return;
- bw40po = (u16) wlapi_getintvar(shim, BRCMS_SROM_BW40PO);
+ bw40po = sprom->bw40po;
pi->bw402gpo = bw40po & 0xf;
pi->bw405gpo = (bw40po & 0xf0) >> 4;
pi->bw405glpo = (bw40po & 0xf00) >> 8;
pi->bw405ghpo = (bw40po & 0xf000) >> 12;
- cddpo = (u16) wlapi_getintvar(shim, BRCMS_SROM_CDDPO);
+ cddpo = sprom->cddpo;
pi->cdd2gpo = cddpo & 0xf;
pi->cdd5gpo = (cddpo & 0xf0) >> 4;
pi->cdd5glpo = (cddpo & 0xf00) >> 8;
pi->cdd5ghpo = (cddpo & 0xf000) >> 12;
- stbcpo = (u16) wlapi_getintvar(shim, BRCMS_SROM_STBCPO);
+ stbcpo = sprom->stbcpo;
pi->stbc2gpo = stbcpo & 0xf;
pi->stbc5gpo = (stbcpo & 0xf0) >> 4;
pi->stbc5glpo = (stbcpo & 0xf00) >> 8;
pi->stbc5ghpo = (stbcpo & 0xf000) >> 12;
- bwduppo = (u16) wlapi_getintvar(shim, BRCMS_SROM_BWDUPPO);
+ bwduppo = sprom->bwduppo;
pi->bwdup2gpo = bwduppo & 0xf;
pi->bwdup5gpo = (bwduppo & 0xf0) >> 4;
pi->bwdup5glpo = (bwduppo & 0xf00) >> 8;
@@ -14419,242 +14419,137 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
band_num++) {
switch (band_num) {
case 0:
-
pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_2g =
- (s8) wlapi_getintvar(shim,
- BRCMS_SROM_MAXP2GA0);
+ sprom->core_pwr_info[0].maxpwr_2g;
pi->nphy_pwrctrl_info[PHY_CORE_1].max_pwr_2g =
- (s8) wlapi_getintvar(shim,
- BRCMS_SROM_MAXP2GA1);
+ sprom->core_pwr_info[1].maxpwr_2g;
pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_a1 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA2GW0A0);
+ sprom->core_pwr_info[0].pa_2g[0];
pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_a1 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA2GW0A1);
+ sprom->core_pwr_info[1].pa_2g[0];
pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_b0 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA2GW1A0);
+ sprom->core_pwr_info[0].pa_2g[1];
pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_b0 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA2GW1A1);
+ sprom->core_pwr_info[1].pa_2g[1];
pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_b1 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA2GW2A0);
+ sprom->core_pwr_info[0].pa_2g[2];
pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_b1 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA2GW2A1);
+ sprom->core_pwr_info[1].pa_2g[2];
pi->nphy_pwrctrl_info[PHY_CORE_0].idle_targ_2g =
- (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT2GA0);
+ sprom->core_pwr_info[0].itssi_2g;
pi->nphy_pwrctrl_info[PHY_CORE_1].idle_targ_2g =
- (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT2GA1);
-
- pi->cck2gpo = (u16) wlapi_getintvar(shim,
- BRCMS_SROM_CCK2GPO);
-
- pi->ofdm2gpo =
- (u32) wlapi_getintvar(shim,
- BRCMS_SROM_OFDM2GPO);
-
- pi->mcs2gpo[0] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS2GPO0);
- pi->mcs2gpo[1] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS2GPO1);
- pi->mcs2gpo[2] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS2GPO2);
- pi->mcs2gpo[3] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS2GPO3);
- pi->mcs2gpo[4] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS2GPO4);
- pi->mcs2gpo[5] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS2GPO5);
- pi->mcs2gpo[6] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS2GPO6);
- pi->mcs2gpo[7] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS2GPO7);
+ sprom->core_pwr_info[1].itssi_2g;
+
+ pi->cck2gpo = sprom->cck2gpo;
+
+ pi->ofdm2gpo = sprom->ofdm2gpo;
+
+ pi->mcs2gpo[0] = sprom->mcs2gpo[0];
+ pi->mcs2gpo[1] = sprom->mcs2gpo[1];
+ pi->mcs2gpo[2] = sprom->mcs2gpo[2];
+ pi->mcs2gpo[3] = sprom->mcs2gpo[3];
+ pi->mcs2gpo[4] = sprom->mcs2gpo[4];
+ pi->mcs2gpo[5] = sprom->mcs2gpo[5];
+ pi->mcs2gpo[6] = sprom->mcs2gpo[6];
+ pi->mcs2gpo[7] = sprom->mcs2gpo[7];
break;
case 1:
pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_5gm =
- (s8) wlapi_getintvar(shim, BRCMS_SROM_MAXP5GA0);
+ sprom->core_pwr_info[0].maxpwr_5g;
pi->nphy_pwrctrl_info[PHY_CORE_1].max_pwr_5gm =
- (s8) wlapi_getintvar(shim,
- BRCMS_SROM_MAXP5GA1);
+ sprom->core_pwr_info[1].maxpwr_5g;
pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_a1 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA5GW0A0);
+ sprom->core_pwr_info[0].pa_5g[0];
pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_a1 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA5GW0A1);
+ sprom->core_pwr_info[1].pa_5g[0];
pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_b0 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA5GW1A0);
+ sprom->core_pwr_info[0].pa_5g[1];
pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_b0 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA5GW1A1);
+ sprom->core_pwr_info[1].pa_5g[1];
pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_b1 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA5GW2A0);
+ sprom->core_pwr_info[0].pa_5g[2];
pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_b1 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA5GW2A1);
+ sprom->core_pwr_info[1].pa_5g[2];
pi->nphy_pwrctrl_info[PHY_CORE_0].idle_targ_5gm =
- (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT5GA0);
+ sprom->core_pwr_info[0].itssi_5g;
pi->nphy_pwrctrl_info[PHY_CORE_1].idle_targ_5gm =
- (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT5GA1);
-
- pi->ofdm5gpo =
- (u32) wlapi_getintvar(shim,
- BRCMS_SROM_OFDM5GPO);
-
- pi->mcs5gpo[0] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GPO0);
- pi->mcs5gpo[1] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GPO1);
- pi->mcs5gpo[2] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GPO2);
- pi->mcs5gpo[3] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GPO3);
- pi->mcs5gpo[4] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GPO4);
- pi->mcs5gpo[5] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GPO5);
- pi->mcs5gpo[6] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GPO6);
- pi->mcs5gpo[7] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GPO7);
+ sprom->core_pwr_info[1].itssi_5g;
+
+ pi->ofdm5gpo = sprom->ofdm5gpo;
+
+ pi->mcs5gpo[0] = sprom->mcs5gpo[0];
+ pi->mcs5gpo[1] = sprom->mcs5gpo[1];
+ pi->mcs5gpo[2] = sprom->mcs5gpo[2];
+ pi->mcs5gpo[3] = sprom->mcs5gpo[3];
+ pi->mcs5gpo[4] = sprom->mcs5gpo[4];
+ pi->mcs5gpo[5] = sprom->mcs5gpo[5];
+ pi->mcs5gpo[6] = sprom->mcs5gpo[6];
+ pi->mcs5gpo[7] = sprom->mcs5gpo[7];
break;
case 2:
pi->nphy_pwrctrl_info[0].max_pwr_5gl =
- (s8) wlapi_getintvar(shim,
- BRCMS_SROM_MAXP5GLA0);
+ sprom->core_pwr_info[0].maxpwr_5gl;
pi->nphy_pwrctrl_info[1].max_pwr_5gl =
- (s8) wlapi_getintvar(shim,
- BRCMS_SROM_MAXP5GLA1);
+ sprom->core_pwr_info[1].maxpwr_5gl;
pi->nphy_pwrctrl_info[0].pwrdet_5gl_a1 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA5GLW0A0);
+ sprom->core_pwr_info[0].pa_5gl[0];
pi->nphy_pwrctrl_info[1].pwrdet_5gl_a1 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA5GLW0A1);
+ sprom->core_pwr_info[1].pa_5gl[0];
pi->nphy_pwrctrl_info[0].pwrdet_5gl_b0 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA5GLW1A0);
+ sprom->core_pwr_info[0].pa_5gl[1];
pi->nphy_pwrctrl_info[1].pwrdet_5gl_b0 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA5GLW1A1);
+ sprom->core_pwr_info[1].pa_5gl[1];
pi->nphy_pwrctrl_info[0].pwrdet_5gl_b1 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA5GLW2A0);
+ sprom->core_pwr_info[0].pa_5gl[2];
pi->nphy_pwrctrl_info[1].pwrdet_5gl_b1 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA5GLW2A1);
+ sprom->core_pwr_info[1].pa_5gl[2];
pi->nphy_pwrctrl_info[0].idle_targ_5gl = 0;
pi->nphy_pwrctrl_info[1].idle_targ_5gl = 0;
- pi->ofdm5glpo =
- (u32) wlapi_getintvar(shim,
- BRCMS_SROM_OFDM5GLPO);
-
- pi->mcs5glpo[0] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GLPO0);
- pi->mcs5glpo[1] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GLPO1);
- pi->mcs5glpo[2] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GLPO2);
- pi->mcs5glpo[3] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GLPO3);
- pi->mcs5glpo[4] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GLPO4);
- pi->mcs5glpo[5] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GLPO5);
- pi->mcs5glpo[6] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GLPO6);
- pi->mcs5glpo[7] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GLPO7);
+ pi->ofdm5glpo = sprom->ofdm5glpo;
+
+ pi->mcs5glpo[0] = sprom->mcs5glpo[0];
+ pi->mcs5glpo[1] = sprom->mcs5glpo[1];
+ pi->mcs5glpo[2] = sprom->mcs5glpo[2];
+ pi->mcs5glpo[3] = sprom->mcs5glpo[3];
+ pi->mcs5glpo[4] = sprom->mcs5glpo[4];
+ pi->mcs5glpo[5] = sprom->mcs5glpo[5];
+ pi->mcs5glpo[6] = sprom->mcs5glpo[6];
+ pi->mcs5glpo[7] = sprom->mcs5glpo[7];
break;
case 3:
pi->nphy_pwrctrl_info[0].max_pwr_5gh =
- (s8) wlapi_getintvar(shim,
- BRCMS_SROM_MAXP5GHA0);
+ sprom->core_pwr_info[0].maxpwr_5gh;
pi->nphy_pwrctrl_info[1].max_pwr_5gh =
- (s8) wlapi_getintvar(shim,
- BRCMS_SROM_MAXP5GHA1);
+ sprom->core_pwr_info[1].maxpwr_5gh;
pi->nphy_pwrctrl_info[0].pwrdet_5gh_a1 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA5GHW0A0);
+ sprom->core_pwr_info[0].pa_5gh[0];
pi->nphy_pwrctrl_info[1].pwrdet_5gh_a1 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA5GHW0A1);
+ sprom->core_pwr_info[1].pa_5gh[0];
pi->nphy_pwrctrl_info[0].pwrdet_5gh_b0 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA5GHW1A0);
+ sprom->core_pwr_info[0].pa_5gh[1];
pi->nphy_pwrctrl_info[1].pwrdet_5gh_b0 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA5GHW1A1);
+ sprom->core_pwr_info[1].pa_5gh[1];
pi->nphy_pwrctrl_info[0].pwrdet_5gh_b1 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA5GHW2A0);
+ sprom->core_pwr_info[0].pa_5gh[2];
pi->nphy_pwrctrl_info[1].pwrdet_5gh_b1 =
- (s16) wlapi_getintvar(shim,
- BRCMS_SROM_PA5GHW2A1);
+ sprom->core_pwr_info[1].pa_5gh[2];
pi->nphy_pwrctrl_info[0].idle_targ_5gh = 0;
pi->nphy_pwrctrl_info[1].idle_targ_5gh = 0;
- pi->ofdm5ghpo =
- (u32) wlapi_getintvar(shim,
- BRCMS_SROM_OFDM5GHPO);
-
- pi->mcs5ghpo[0] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GHPO0);
- pi->mcs5ghpo[1] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GHPO1);
- pi->mcs5ghpo[2] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GHPO2);
- pi->mcs5ghpo[3] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GHPO3);
- pi->mcs5ghpo[4] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GHPO4);
- pi->mcs5ghpo[5] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GHPO5);
- pi->mcs5ghpo[6] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GHPO6);
- pi->mcs5ghpo[7] =
- (u16) wlapi_getintvar(shim,
- BRCMS_SROM_MCS5GHPO7);
+ pi->ofdm5ghpo = sprom->ofdm5ghpo;
+
+ pi->mcs5ghpo[0] = sprom->mcs5ghpo[0];
+ pi->mcs5ghpo[1] = sprom->mcs5ghpo[1];
+ pi->mcs5ghpo[2] = sprom->mcs5ghpo[2];
+ pi->mcs5ghpo[3] = sprom->mcs5ghpo[3];
+ pi->mcs5ghpo[4] = sprom->mcs5ghpo[4];
+ pi->mcs5ghpo[5] = sprom->mcs5ghpo[5];
+ pi->mcs5ghpo[6] = sprom->mcs5ghpo[6];
+ pi->mcs5ghpo[7] = sprom->mcs5ghpo[7];
break;
}
}
@@ -14664,45 +14559,34 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
static bool wlc_phy_txpwr_srom_read_nphy(struct brcms_phy *pi)
{
- struct phy_shim_info *shim = pi->sh->physhim;
-
- pi->antswitch = (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWITCH);
- pi->aa2g = (u8) wlapi_getintvar(shim, BRCMS_SROM_AA2G);
- pi->aa5g = (u8) wlapi_getintvar(shim, BRCMS_SROM_AA5G);
-
- pi->srom_fem2g.tssipos = (u8) wlapi_getintvar(shim,
- BRCMS_SROM_TSSIPOS2G);
- pi->srom_fem2g.extpagain = (u8) wlapi_getintvar(shim,
- BRCMS_SROM_EXTPAGAIN2G);
- pi->srom_fem2g.pdetrange = (u8) wlapi_getintvar(shim,
- BRCMS_SROM_PDETRANGE2G);
- pi->srom_fem2g.triso = (u8) wlapi_getintvar(shim, BRCMS_SROM_TRISO2G);
- pi->srom_fem2g.antswctrllut =
- (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL2G);
-
- pi->srom_fem5g.tssipos = (u8) wlapi_getintvar(shim,
- BRCMS_SROM_TSSIPOS5G);
- pi->srom_fem5g.extpagain = (u8) wlapi_getintvar(shim,
- BRCMS_SROM_EXTPAGAIN5G);
- pi->srom_fem5g.pdetrange = (u8) wlapi_getintvar(shim,
- BRCMS_SROM_PDETRANGE5G);
- pi->srom_fem5g.triso = (u8) wlapi_getintvar(shim, BRCMS_SROM_TRISO5G);
- if (wlapi_getvar(shim, BRCMS_SROM_ANTSWCTL5G))
- pi->srom_fem5g.antswctrllut =
- (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL5G);
+ struct ssb_sprom *sprom = &pi->d11core->bus->sprom;
+
+ pi->antswitch = sprom->antswitch;
+ pi->aa2g = sprom->ant_available_bg;
+ pi->aa5g = sprom->ant_available_a;
+
+ pi->srom_fem2g.tssipos = sprom->fem.ghz2.tssipos;
+ pi->srom_fem2g.extpagain = sprom->fem.ghz2.extpa_gain;
+ pi->srom_fem2g.pdetrange = sprom->fem.ghz2.pdet_range;
+ pi->srom_fem2g.triso = sprom->fem.ghz2.tr_iso;
+ pi->srom_fem2g.antswctrllut = sprom->fem.ghz2.antswlut;
+
+ pi->srom_fem5g.tssipos = sprom->fem.ghz5.tssipos;
+ pi->srom_fem5g.extpagain = sprom->fem.ghz5.extpa_gain;
+ pi->srom_fem5g.pdetrange = sprom->fem.ghz5.pdet_range;
+ pi->srom_fem5g.triso = sprom->fem.ghz5.tr_iso;
+ if (sprom->fem.ghz5.antswlut)
+ pi->srom_fem5g.antswctrllut = sprom->fem.ghz5.antswlut;
else
- pi->srom_fem5g.antswctrllut =
- (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL2G);
+ pi->srom_fem5g.antswctrllut = sprom->fem.ghz2.antswlut;
wlc_phy_txpower_ipa_upd(pi);
- pi->phy_txcore_disable_temp =
- (s16) wlapi_getintvar(shim, BRCMS_SROM_TEMPTHRESH);
+ pi->phy_txcore_disable_temp = sprom->tempthresh;
if (pi->phy_txcore_disable_temp == 0)
pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
- pi->phy_tempsense_offset = (s8) wlapi_getintvar(shim,
- BRCMS_SROM_TEMPOFFSET);
+ pi->phy_tempsense_offset = sprom->tempoffset;
if (pi->phy_tempsense_offset != 0) {
if (pi->phy_tempsense_offset >
(NPHY_SROM_TEMPSHIFT + NPHY_SROM_MAXTEMPOFFSET))
@@ -14717,8 +14601,7 @@ static bool wlc_phy_txpwr_srom_read_nphy(struct brcms_phy *pi)
pi->phy_txcore_enable_temp =
pi->phy_txcore_disable_temp - PHY_HYSTERESIS_DELTATEMP;
- pi->phycal_tempdelta =
- (u8) wlapi_getintvar(shim, BRCMS_SROM_PHYCAL_TEMPDELTA);
+ pi->phycal_tempdelta = sprom->phycal_tempdelta;
if (pi->phycal_tempdelta > NPHY_CAL_MAXTEMPDELTA)
pi->phycal_tempdelta = 0;
@@ -21460,7 +21343,7 @@ void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init)
write_phy_reg(pi, 0xc8, 0x0);
write_phy_reg(pi, 0xc9, 0x0);
- ai_gpiocontrol(pi->sh->sih, mask, mask, GPIO_DRV_PRIORITY);
+ bcma_chipco_gpio_control(&pi->d11core->bus->drv_cc, mask, mask);
mc = bcma_read32(pi->d11core, D11REGOFFS(maccontrol));
mc &= ~MCTL_GPOUT_SEL_MASK;
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.c b/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.c
index 5926854f62e2..a0de5db0cd64 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.c
@@ -214,12 +214,3 @@ wlapi_copyto_objmem(struct phy_shim_info *physhim, uint offset, const void *buf,
{
brcms_b_copyto_objmem(physhim->wlc_hw, offset, buf, l, sel);
}
-
-char *wlapi_getvar(struct phy_shim_info *physhim, enum brcms_srom_id id)
-{
- return getvar(physhim->wlc_hw->sih, id);
-}
-int wlapi_getintvar(struct phy_shim_info *physhim, enum brcms_srom_id id)
-{
- return getintvar(physhim->wlc_hw->sih, id);
-}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h b/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h
index 9168c459b185..2c5b66b75970 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h
@@ -175,8 +175,5 @@ extern void wlapi_copyto_objmem(struct phy_shim_info *physhim, uint,
extern void wlapi_high_update_phy_mode(struct phy_shim_info *physhim,
u32 phy_mode);
extern u16 wlapi_bmac_get_txant(struct phy_shim_info *physhim);
-extern char *wlapi_getvar(struct phy_shim_info *physhim, enum brcms_srom_id id);
-extern int wlapi_getintvar(struct phy_shim_info *physhim,
- enum brcms_srom_id id);
#endif /* _BRCM_PHY_SHIM_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pub.h b/drivers/net/wireless/brcm80211/brcmsmac/pub.h
index f0038ad7d7bf..aa5d67f8d874 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h
@@ -22,232 +22,6 @@
#include "types.h"
#include "defs.h"
-enum brcms_srom_id {
- BRCMS_SROM_NULL,
- BRCMS_SROM_CONT,
- BRCMS_SROM_AA2G,
- BRCMS_SROM_AA5G,
- BRCMS_SROM_AG0,
- BRCMS_SROM_AG1,
- BRCMS_SROM_AG2,
- BRCMS_SROM_AG3,
- BRCMS_SROM_ANTSWCTL2G,
- BRCMS_SROM_ANTSWCTL5G,
- BRCMS_SROM_ANTSWITCH,
- BRCMS_SROM_BOARDFLAGS2,
- BRCMS_SROM_BOARDFLAGS,
- BRCMS_SROM_BOARDNUM,
- BRCMS_SROM_BOARDREV,
- BRCMS_SROM_BOARDTYPE,
- BRCMS_SROM_BW40PO,
- BRCMS_SROM_BWDUPPO,
- BRCMS_SROM_BXA2G,
- BRCMS_SROM_BXA5G,
- BRCMS_SROM_CC,
- BRCMS_SROM_CCK2GPO,
- BRCMS_SROM_CCKBW202GPO,
- BRCMS_SROM_CCKBW20UL2GPO,
- BRCMS_SROM_CCODE,
- BRCMS_SROM_CDDPO,
- BRCMS_SROM_DEVID,
- BRCMS_SROM_ET1MACADDR,
- BRCMS_SROM_EXTPAGAIN2G,
- BRCMS_SROM_EXTPAGAIN5G,
- BRCMS_SROM_FREQOFFSET_CORR,
- BRCMS_SROM_HW_IQCAL_EN,
- BRCMS_SROM_IL0MACADDR,
- BRCMS_SROM_IQCAL_SWP_DIS,
- BRCMS_SROM_LEDBH0,
- BRCMS_SROM_LEDBH1,
- BRCMS_SROM_LEDBH2,
- BRCMS_SROM_LEDBH3,
- BRCMS_SROM_LEDDC,
- BRCMS_SROM_LEGOFDM40DUPPO,
- BRCMS_SROM_LEGOFDMBW202GPO,
- BRCMS_SROM_LEGOFDMBW205GHPO,
- BRCMS_SROM_LEGOFDMBW205GLPO,
- BRCMS_SROM_LEGOFDMBW205GMPO,
- BRCMS_SROM_LEGOFDMBW20UL2GPO,
- BRCMS_SROM_LEGOFDMBW20UL5GHPO,
- BRCMS_SROM_LEGOFDMBW20UL5GLPO,
- BRCMS_SROM_LEGOFDMBW20UL5GMPO,
- BRCMS_SROM_MACADDR,
- BRCMS_SROM_MCS2GPO0,
- BRCMS_SROM_MCS2GPO1,
- BRCMS_SROM_MCS2GPO2,
- BRCMS_SROM_MCS2GPO3,
- BRCMS_SROM_MCS2GPO4,
- BRCMS_SROM_MCS2GPO5,
- BRCMS_SROM_MCS2GPO6,
- BRCMS_SROM_MCS2GPO7,
- BRCMS_SROM_MCS32PO,
- BRCMS_SROM_MCS5GHPO0,
- BRCMS_SROM_MCS5GHPO1,
- BRCMS_SROM_MCS5GHPO2,
- BRCMS_SROM_MCS5GHPO3,
- BRCMS_SROM_MCS5GHPO4,
- BRCMS_SROM_MCS5GHPO5,
- BRCMS_SROM_MCS5GHPO6,
- BRCMS_SROM_MCS5GHPO7,
- BRCMS_SROM_MCS5GLPO0,
- BRCMS_SROM_MCS5GLPO1,
- BRCMS_SROM_MCS5GLPO2,
- BRCMS_SROM_MCS5GLPO3,
- BRCMS_SROM_MCS5GLPO4,
- BRCMS_SROM_MCS5GLPO5,
- BRCMS_SROM_MCS5GLPO6,
- BRCMS_SROM_MCS5GLPO7,
- BRCMS_SROM_MCS5GPO0,
- BRCMS_SROM_MCS5GPO1,
- BRCMS_SROM_MCS5GPO2,
- BRCMS_SROM_MCS5GPO3,
- BRCMS_SROM_MCS5GPO4,
- BRCMS_SROM_MCS5GPO5,
- BRCMS_SROM_MCS5GPO6,
- BRCMS_SROM_MCS5GPO7,
- BRCMS_SROM_MCSBW202GPO,
- BRCMS_SROM_MCSBW205GHPO,
- BRCMS_SROM_MCSBW205GLPO,
- BRCMS_SROM_MCSBW205GMPO,
- BRCMS_SROM_MCSBW20UL2GPO,
- BRCMS_SROM_MCSBW20UL5GHPO,
- BRCMS_SROM_MCSBW20UL5GLPO,
- BRCMS_SROM_MCSBW20UL5GMPO,
- BRCMS_SROM_MCSBW402GPO,
- BRCMS_SROM_MCSBW405GHPO,
- BRCMS_SROM_MCSBW405GLPO,
- BRCMS_SROM_MCSBW405GMPO,
- BRCMS_SROM_MEASPOWER,
- BRCMS_SROM_OFDM2GPO,
- BRCMS_SROM_OFDM5GHPO,
- BRCMS_SROM_OFDM5GLPO,
- BRCMS_SROM_OFDM5GPO,
- BRCMS_SROM_OPO,
- BRCMS_SROM_PA0B0,
- BRCMS_SROM_PA0B1,
- BRCMS_SROM_PA0B2,
- BRCMS_SROM_PA0ITSSIT,
- BRCMS_SROM_PA0MAXPWR,
- BRCMS_SROM_PA1B0,
- BRCMS_SROM_PA1B1,
- BRCMS_SROM_PA1B2,
- BRCMS_SROM_PA1HIB0,
- BRCMS_SROM_PA1HIB1,
- BRCMS_SROM_PA1HIB2,
- BRCMS_SROM_PA1HIMAXPWR,
- BRCMS_SROM_PA1ITSSIT,
- BRCMS_SROM_PA1LOB0,
- BRCMS_SROM_PA1LOB1,
- BRCMS_SROM_PA1LOB2,
- BRCMS_SROM_PA1LOMAXPWR,
- BRCMS_SROM_PA1MAXPWR,
- BRCMS_SROM_PDETRANGE2G,
- BRCMS_SROM_PDETRANGE5G,
- BRCMS_SROM_PHYCAL_TEMPDELTA,
- BRCMS_SROM_RAWTEMPSENSE,
- BRCMS_SROM_REGREV,
- BRCMS_SROM_REV,
- BRCMS_SROM_RSSISAV2G,
- BRCMS_SROM_RSSISAV5G,
- BRCMS_SROM_RSSISMC2G,
- BRCMS_SROM_RSSISMC5G,
- BRCMS_SROM_RSSISMF2G,
- BRCMS_SROM_RSSISMF5G,
- BRCMS_SROM_RXCHAIN,
- BRCMS_SROM_RXPO2G,
- BRCMS_SROM_RXPO5G,
- BRCMS_SROM_STBCPO,
- BRCMS_SROM_TEMPCORRX,
- BRCMS_SROM_TEMPOFFSET,
- BRCMS_SROM_TEMPSENSE_OPTION,
- BRCMS_SROM_TEMPSENSE_SLOPE,
- BRCMS_SROM_TEMPTHRESH,
- BRCMS_SROM_TRI2G,
- BRCMS_SROM_TRI5GH,
- BRCMS_SROM_TRI5GL,
- BRCMS_SROM_TRI5G,
- BRCMS_SROM_TRISO2G,
- BRCMS_SROM_TRISO5G,
- BRCMS_SROM_TSSIPOS2G,
- BRCMS_SROM_TSSIPOS5G,
- BRCMS_SROM_TXCHAIN,
- /*
- * per-path identifiers (see srom.c)
- */
- BRCMS_SROM_ITT2GA0,
- BRCMS_SROM_ITT2GA1,
- BRCMS_SROM_ITT2GA2,
- BRCMS_SROM_ITT2GA3,
- BRCMS_SROM_ITT5GA0,
- BRCMS_SROM_ITT5GA1,
- BRCMS_SROM_ITT5GA2,
- BRCMS_SROM_ITT5GA3,
- BRCMS_SROM_MAXP2GA0,
- BRCMS_SROM_MAXP2GA1,
- BRCMS_SROM_MAXP2GA2,
- BRCMS_SROM_MAXP2GA3,
- BRCMS_SROM_MAXP5GA0,
- BRCMS_SROM_MAXP5GA1,
- BRCMS_SROM_MAXP5GA2,
- BRCMS_SROM_MAXP5GA3,
- BRCMS_SROM_MAXP5GHA0,
- BRCMS_SROM_MAXP5GHA1,
- BRCMS_SROM_MAXP5GHA2,
- BRCMS_SROM_MAXP5GHA3,
- BRCMS_SROM_MAXP5GLA0,
- BRCMS_SROM_MAXP5GLA1,
- BRCMS_SROM_MAXP5GLA2,
- BRCMS_SROM_MAXP5GLA3,
- BRCMS_SROM_PA2GW0A0,
- BRCMS_SROM_PA2GW0A1,
- BRCMS_SROM_PA2GW0A2,
- BRCMS_SROM_PA2GW0A3,
- BRCMS_SROM_PA2GW1A0,
- BRCMS_SROM_PA2GW1A1,
- BRCMS_SROM_PA2GW1A2,
- BRCMS_SROM_PA2GW1A3,
- BRCMS_SROM_PA2GW2A0,
- BRCMS_SROM_PA2GW2A1,
- BRCMS_SROM_PA2GW2A2,
- BRCMS_SROM_PA2GW2A3,
- BRCMS_SROM_PA5GHW0A0,
- BRCMS_SROM_PA5GHW0A1,
- BRCMS_SROM_PA5GHW0A2,
- BRCMS_SROM_PA5GHW0A3,
- BRCMS_SROM_PA5GHW1A0,
- BRCMS_SROM_PA5GHW1A1,
- BRCMS_SROM_PA5GHW1A2,
- BRCMS_SROM_PA5GHW1A3,
- BRCMS_SROM_PA5GHW2A0,
- BRCMS_SROM_PA5GHW2A1,
- BRCMS_SROM_PA5GHW2A2,
- BRCMS_SROM_PA5GHW2A3,
- BRCMS_SROM_PA5GLW0A0,
- BRCMS_SROM_PA5GLW0A1,
- BRCMS_SROM_PA5GLW0A2,
- BRCMS_SROM_PA5GLW0A3,
- BRCMS_SROM_PA5GLW1A0,
- BRCMS_SROM_PA5GLW1A1,
- BRCMS_SROM_PA5GLW1A2,
- BRCMS_SROM_PA5GLW1A3,
- BRCMS_SROM_PA5GLW2A0,
- BRCMS_SROM_PA5GLW2A1,
- BRCMS_SROM_PA5GLW2A2,
- BRCMS_SROM_PA5GLW2A3,
- BRCMS_SROM_PA5GW0A0,
- BRCMS_SROM_PA5GW0A1,
- BRCMS_SROM_PA5GW0A2,
- BRCMS_SROM_PA5GW0A3,
- BRCMS_SROM_PA5GW1A0,
- BRCMS_SROM_PA5GW1A1,
- BRCMS_SROM_PA5GW1A2,
- BRCMS_SROM_PA5GW1A3,
- BRCMS_SROM_PA5GW2A0,
- BRCMS_SROM_PA5GW2A1,
- BRCMS_SROM_PA5GW2A2,
- BRCMS_SROM_PA5GW2A3,
-};
-
#define BRCMS_NUMRATES 16 /* max # of rates in a rateset */
/* phy types */
@@ -565,8 +339,6 @@ extern void brcms_c_ampdu_flush(struct brcms_c_info *wlc,
struct ieee80211_sta *sta, u16 tid);
extern void brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid,
u8 ba_wsize, uint max_rx_ampdu_bytes);
-extern char *getvar(struct si_pub *sih, enum brcms_srom_id id);
-extern int getintvar(struct si_pub *sih, enum brcms_srom_id id);
extern int brcms_c_module_register(struct brcms_pub *pub,
const char *name, struct brcms_info *hdl,
int (*down_fn)(void *handle));
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/srom.c b/drivers/net/wireless/brcm80211/brcmsmac/srom.c
deleted file mode 100644
index b96f4b9d74bd..000000000000
--- a/drivers/net/wireless/brcm80211/brcmsmac/srom.c
+++ /dev/null
@@ -1,980 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/io.h>
-#include <linux/etherdevice.h>
-#include <linux/crc8.h>
-#include <stdarg.h>
-
-#include <chipcommon.h>
-#include <brcmu_utils.h>
-#include "pub.h"
-#include "nicpci.h"
-#include "aiutils.h"
-#include "otp.h"
-#include "srom.h"
-#include "soc.h"
-
-/*
- * SROM CRC8 polynomial value:
- *
- * x^8 + x^7 +x^6 + x^4 + x^2 + 1
- */
-#define SROM_CRC8_POLY 0xAB
-
-/* Maximum srom: 6 Kilobits == 768 bytes */
-#define SROM_MAX 768
-
-/* PCI fields */
-#define PCI_F0DEVID 48
-
-#define SROM_WORDS 64
-
-#define SROM_SSID 2
-
-#define SROM_WL1LHMAXP 29
-
-#define SROM_WL1LPAB0 30
-#define SROM_WL1LPAB1 31
-#define SROM_WL1LPAB2 32
-
-#define SROM_WL1HPAB0 33
-#define SROM_WL1HPAB1 34
-#define SROM_WL1HPAB2 35
-
-#define SROM_MACHI_IL0 36
-#define SROM_MACMID_IL0 37
-#define SROM_MACLO_IL0 38
-#define SROM_MACHI_ET1 42
-#define SROM_MACMID_ET1 43
-#define SROM_MACLO_ET1 44
-
-#define SROM_BXARSSI2G 40
-#define SROM_BXARSSI5G 41
-
-#define SROM_TRI52G 42
-#define SROM_TRI5GHL 43
-
-#define SROM_RXPO52G 45
-
-#define SROM_AABREV 46
-/* Fields in AABREV */
-#define SROM_BR_MASK 0x00ff
-#define SROM_CC_MASK 0x0f00
-#define SROM_CC_SHIFT 8
-#define SROM_AA0_MASK 0x3000
-#define SROM_AA0_SHIFT 12
-#define SROM_AA1_MASK 0xc000
-#define SROM_AA1_SHIFT 14
-
-#define SROM_WL0PAB0 47
-#define SROM_WL0PAB1 48
-#define SROM_WL0PAB2 49
-
-#define SROM_LEDBH10 50
-#define SROM_LEDBH32 51
-
-#define SROM_WL10MAXP 52
-
-#define SROM_WL1PAB0 53
-#define SROM_WL1PAB1 54
-#define SROM_WL1PAB2 55
-
-#define SROM_ITT 56
-
-#define SROM_BFL 57
-#define SROM_BFL2 28
-
-#define SROM_AG10 58
-
-#define SROM_CCODE 59
-
-#define SROM_OPO 60
-
-#define SROM_CRCREV 63
-
-#define SROM4_WORDS 220
-
-#define SROM4_TXCHAIN_MASK 0x000f
-#define SROM4_RXCHAIN_MASK 0x00f0
-#define SROM4_SWITCH_MASK 0xff00
-
-/* Per-path fields */
-#define MAX_PATH_SROM 4
-
-#define SROM4_CRCREV 219
-
-/* SROM Rev 8: Make space for a 48word hardware header for PCIe rev >= 6.
- * This is acombined srom for both MIMO and SISO boards, usable in
- * the .130 4Kilobit OTP with hardware redundancy.
- */
-#define SROM8_BREV 65
-
-#define SROM8_BFL0 66
-#define SROM8_BFL1 67
-#define SROM8_BFL2 68
-#define SROM8_BFL3 69
-
-#define SROM8_MACHI 70
-#define SROM8_MACMID 71
-#define SROM8_MACLO 72
-
-#define SROM8_CCODE 73
-#define SROM8_REGREV 74
-
-#define SROM8_LEDBH10 75
-#define SROM8_LEDBH32 76
-
-#define SROM8_LEDDC 77
-
-#define SROM8_AA 78
-
-#define SROM8_AG10 79
-#define SROM8_AG32 80
-
-#define SROM8_TXRXC 81
-
-#define SROM8_BXARSSI2G 82
-#define SROM8_BXARSSI5G 83
-#define SROM8_TRI52G 84
-#define SROM8_TRI5GHL 85
-#define SROM8_RXPO52G 86
-
-#define SROM8_FEM2G 87
-#define SROM8_FEM5G 88
-#define SROM8_FEM_ANTSWLUT_MASK 0xf800
-#define SROM8_FEM_ANTSWLUT_SHIFT 11
-#define SROM8_FEM_TR_ISO_MASK 0x0700
-#define SROM8_FEM_TR_ISO_SHIFT 8
-#define SROM8_FEM_PDET_RANGE_MASK 0x00f8
-#define SROM8_FEM_PDET_RANGE_SHIFT 3
-#define SROM8_FEM_EXTPA_GAIN_MASK 0x0006
-#define SROM8_FEM_EXTPA_GAIN_SHIFT 1
-#define SROM8_FEM_TSSIPOS_MASK 0x0001
-#define SROM8_FEM_TSSIPOS_SHIFT 0
-
-#define SROM8_THERMAL 89
-
-/* Temp sense related entries */
-#define SROM8_MPWR_RAWTS 90
-#define SROM8_TS_SLP_OPT_CORRX 91
-/* FOC: freiquency offset correction, HWIQ: H/W IOCAL enable,
- * IQSWP: IQ CAL swap disable */
-#define SROM8_FOC_HWIQ_IQSWP 92
-
-/* Temperature delta for PHY calibration */
-#define SROM8_PHYCAL_TEMPDELTA 93
-
-/* Per-path offsets & fields */
-#define SROM8_PATH0 96
-#define SROM8_PATH1 112
-#define SROM8_PATH2 128
-#define SROM8_PATH3 144
-
-#define SROM8_2G_ITT_MAXP 0
-#define SROM8_2G_PA 1
-#define SROM8_5G_ITT_MAXP 4
-#define SROM8_5GLH_MAXP 5
-#define SROM8_5G_PA 6
-#define SROM8_5GL_PA 9
-#define SROM8_5GH_PA 12
-
-/* All the miriad power offsets */
-#define SROM8_2G_CCKPO 160
-
-#define SROM8_2G_OFDMPO 161
-#define SROM8_5G_OFDMPO 163
-#define SROM8_5GL_OFDMPO 165
-#define SROM8_5GH_OFDMPO 167
-
-#define SROM8_2G_MCSPO 169
-#define SROM8_5G_MCSPO 177
-#define SROM8_5GL_MCSPO 185
-#define SROM8_5GH_MCSPO 193
-
-#define SROM8_CDDPO 201
-#define SROM8_STBCPO 202
-#define SROM8_BW40PO 203
-#define SROM8_BWDUPPO 204
-
-/* SISO PA parameters are in the path0 spaces */
-#define SROM8_SISO 96
-
-/* Legacy names for SISO PA paramters */
-#define SROM8_W0_ITTMAXP (SROM8_SISO + SROM8_2G_ITT_MAXP)
-#define SROM8_W0_PAB0 (SROM8_SISO + SROM8_2G_PA)
-#define SROM8_W0_PAB1 (SROM8_SISO + SROM8_2G_PA + 1)
-#define SROM8_W0_PAB2 (SROM8_SISO + SROM8_2G_PA + 2)
-#define SROM8_W1_ITTMAXP (SROM8_SISO + SROM8_5G_ITT_MAXP)
-#define SROM8_W1_MAXP_LCHC (SROM8_SISO + SROM8_5GLH_MAXP)
-#define SROM8_W1_PAB0 (SROM8_SISO + SROM8_5G_PA)
-#define SROM8_W1_PAB1 (SROM8_SISO + SROM8_5G_PA + 1)
-#define SROM8_W1_PAB2 (SROM8_SISO + SROM8_5G_PA + 2)
-#define SROM8_W1_PAB0_LC (SROM8_SISO + SROM8_5GL_PA)
-#define SROM8_W1_PAB1_LC (SROM8_SISO + SROM8_5GL_PA + 1)
-#define SROM8_W1_PAB2_LC (SROM8_SISO + SROM8_5GL_PA + 2)
-#define SROM8_W1_PAB0_HC (SROM8_SISO + SROM8_5GH_PA)
-#define SROM8_W1_PAB1_HC (SROM8_SISO + SROM8_5GH_PA + 1)
-#define SROM8_W1_PAB2_HC (SROM8_SISO + SROM8_5GH_PA + 2)
-
-/* SROM REV 9 */
-#define SROM9_2GPO_CCKBW20 160
-#define SROM9_2GPO_CCKBW20UL 161
-#define SROM9_2GPO_LOFDMBW20 162
-#define SROM9_2GPO_LOFDMBW20UL 164
-
-#define SROM9_5GLPO_LOFDMBW20 166
-#define SROM9_5GLPO_LOFDMBW20UL 168
-#define SROM9_5GMPO_LOFDMBW20 170
-#define SROM9_5GMPO_LOFDMBW20UL 172
-#define SROM9_5GHPO_LOFDMBW20 174
-#define SROM9_5GHPO_LOFDMBW20UL 176
-
-#define SROM9_2GPO_MCSBW20 178
-#define SROM9_2GPO_MCSBW20UL 180
-#define SROM9_2GPO_MCSBW40 182
-
-#define SROM9_5GLPO_MCSBW20 184
-#define SROM9_5GLPO_MCSBW20UL 186
-#define SROM9_5GLPO_MCSBW40 188
-#define SROM9_5GMPO_MCSBW20 190
-#define SROM9_5GMPO_MCSBW20UL 192
-#define SROM9_5GMPO_MCSBW40 194
-#define SROM9_5GHPO_MCSBW20 196
-#define SROM9_5GHPO_MCSBW20UL 198
-#define SROM9_5GHPO_MCSBW40 200
-
-#define SROM9_PO_MCS32 202
-#define SROM9_PO_LOFDM40DUP 203
-
-/* SROM flags (see sromvar_t) */
-
-/* value continues as described by the next entry */
-#define SRFL_MORE 1
-#define SRFL_NOFFS 2 /* value bits can't be all one's */
-#define SRFL_PRHEX 4 /* value is in hexdecimal format */
-#define SRFL_PRSIGN 8 /* value is in signed decimal format */
-#define SRFL_CCODE 0x10 /* value is in country code format */
-#define SRFL_ETHADDR 0x20 /* value is an Ethernet address */
-#define SRFL_LEDDC 0x40 /* value is an LED duty cycle */
-/* do not generate a nvram param, entry is for mfgc */
-#define SRFL_NOVAR 0x80
-
-/* Max. nvram variable table size */
-#define MAXSZ_NVRAM_VARS 4096
-
-/*
- * indicates type of value.
- */
-enum brcms_srom_var_type {
- BRCMS_SROM_STRING,
- BRCMS_SROM_SNUMBER,
- BRCMS_SROM_UNUMBER
-};
-
-/*
- * storage type for srom variable.
- *
- * var_list: for linked list operations.
- * varid: identifier of the variable.
- * var_type: type of variable.
- * buf: variable value when var_type == BRCMS_SROM_STRING.
- * uval: unsigned variable value when var_type == BRCMS_SROM_UNUMBER.
- * sval: signed variable value when var_type == BRCMS_SROM_SNUMBER.
- */
-struct brcms_srom_list_head {
- struct list_head var_list;
- enum brcms_srom_id varid;
- enum brcms_srom_var_type var_type;
- union {
- char buf[0];
- u32 uval;
- s32 sval;
- };
-};
-
-struct brcms_sromvar {
- enum brcms_srom_id varid;
- u32 revmask;
- u32 flags;
- u16 off;
- u16 mask;
-};
-
-struct brcms_varbuf {
- char *base; /* pointer to buffer base */
- char *buf; /* pointer to current position */
- unsigned int size; /* current (residual) size in bytes */
-};
-
-/*
- * Assumptions:
- * - Ethernet address spans across 3 consecutive words
- *
- * Table rules:
- * - Add multiple entries next to each other if a value spans across multiple
- * words (even multiple fields in the same word) with each entry except the
- * last having it's SRFL_MORE bit set.
- * - Ethernet address entry does not follow above rule and must not have
- * SRFL_MORE bit set. Its SRFL_ETHADDR bit implies it takes multiple words.
- * - The last entry's name field must be NULL to indicate the end of the table.
- * Other entries must have non-NULL name.
- */
-static const struct brcms_sromvar pci_sromvars[] = {
- {BRCMS_SROM_DEVID, 0xffffff00, SRFL_PRHEX | SRFL_NOVAR, PCI_F0DEVID,
- 0xffff},
- {BRCMS_SROM_BOARDREV, 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff},
- {BRCMS_SROM_BOARDFLAGS, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL0,
- 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM8_BFL1, 0xffff},
- {BRCMS_SROM_BOARDFLAGS2, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL2,
- 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM8_BFL3, 0xffff},
- {BRCMS_SROM_BOARDTYPE, 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff},
- {BRCMS_SROM_BOARDNUM, 0xffffff00, 0, SROM8_MACLO, 0xffff},
- {BRCMS_SROM_REGREV, 0xffffff00, 0, SROM8_REGREV, 0x00ff},
- {BRCMS_SROM_LEDBH0, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0x00ff},
- {BRCMS_SROM_LEDBH1, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0xff00},
- {BRCMS_SROM_LEDBH2, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0x00ff},
- {BRCMS_SROM_LEDBH3, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0xff00},
- {BRCMS_SROM_PA0B0, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff},
- {BRCMS_SROM_PA0B1, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff},
- {BRCMS_SROM_PA0B2, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff},
- {BRCMS_SROM_PA0ITSSIT, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0xff00},
- {BRCMS_SROM_PA0MAXPWR, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0x00ff},
- {BRCMS_SROM_OPO, 0xffffff00, 0, SROM8_2G_OFDMPO, 0x00ff},
- {BRCMS_SROM_AA2G, 0xffffff00, 0, SROM8_AA, 0x00ff},
- {BRCMS_SROM_AA5G, 0xffffff00, 0, SROM8_AA, 0xff00},
- {BRCMS_SROM_AG0, 0xffffff00, 0, SROM8_AG10, 0x00ff},
- {BRCMS_SROM_AG1, 0xffffff00, 0, SROM8_AG10, 0xff00},
- {BRCMS_SROM_AG2, 0xffffff00, 0, SROM8_AG32, 0x00ff},
- {BRCMS_SROM_AG3, 0xffffff00, 0, SROM8_AG32, 0xff00},
- {BRCMS_SROM_PA1B0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff},
- {BRCMS_SROM_PA1B1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff},
- {BRCMS_SROM_PA1B2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff},
- {BRCMS_SROM_PA1LOB0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff},
- {BRCMS_SROM_PA1LOB1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff},
- {BRCMS_SROM_PA1LOB2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff},
- {BRCMS_SROM_PA1HIB0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff},
- {BRCMS_SROM_PA1HIB1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff},
- {BRCMS_SROM_PA1HIB2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff},
- {BRCMS_SROM_PA1ITSSIT, 0xffffff00, 0, SROM8_W1_ITTMAXP, 0xff00},
- {BRCMS_SROM_PA1MAXPWR, 0xffffff00, 0, SROM8_W1_ITTMAXP, 0x00ff},
- {BRCMS_SROM_PA1LOMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0xff00},
- {BRCMS_SROM_PA1HIMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0x00ff},
- {BRCMS_SROM_BXA2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x1800},
- {BRCMS_SROM_RSSISAV2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x0700},
- {BRCMS_SROM_RSSISMC2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x00f0},
- {BRCMS_SROM_RSSISMF2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x000f},
- {BRCMS_SROM_BXA5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x1800},
- {BRCMS_SROM_RSSISAV5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x0700},
- {BRCMS_SROM_RSSISMC5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x00f0},
- {BRCMS_SROM_RSSISMF5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x000f},
- {BRCMS_SROM_TRI2G, 0xffffff00, 0, SROM8_TRI52G, 0x00ff},
- {BRCMS_SROM_TRI5G, 0xffffff00, 0, SROM8_TRI52G, 0xff00},
- {BRCMS_SROM_TRI5GL, 0xffffff00, 0, SROM8_TRI5GHL, 0x00ff},
- {BRCMS_SROM_TRI5GH, 0xffffff00, 0, SROM8_TRI5GHL, 0xff00},
- {BRCMS_SROM_RXPO2G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0x00ff},
- {BRCMS_SROM_RXPO5G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00},
- {BRCMS_SROM_TXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
- SROM4_TXCHAIN_MASK},
- {BRCMS_SROM_RXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
- SROM4_RXCHAIN_MASK},
- {BRCMS_SROM_ANTSWITCH, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
- SROM4_SWITCH_MASK},
- {BRCMS_SROM_TSSIPOS2G, 0xffffff00, 0, SROM8_FEM2G,
- SROM8_FEM_TSSIPOS_MASK},
- {BRCMS_SROM_EXTPAGAIN2G, 0xffffff00, 0, SROM8_FEM2G,
- SROM8_FEM_EXTPA_GAIN_MASK},
- {BRCMS_SROM_PDETRANGE2G, 0xffffff00, 0, SROM8_FEM2G,
- SROM8_FEM_PDET_RANGE_MASK},
- {BRCMS_SROM_TRISO2G, 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_TR_ISO_MASK},
- {BRCMS_SROM_ANTSWCTL2G, 0xffffff00, 0, SROM8_FEM2G,
- SROM8_FEM_ANTSWLUT_MASK},
- {BRCMS_SROM_TSSIPOS5G, 0xffffff00, 0, SROM8_FEM5G,
- SROM8_FEM_TSSIPOS_MASK},
- {BRCMS_SROM_EXTPAGAIN5G, 0xffffff00, 0, SROM8_FEM5G,
- SROM8_FEM_EXTPA_GAIN_MASK},
- {BRCMS_SROM_PDETRANGE5G, 0xffffff00, 0, SROM8_FEM5G,
- SROM8_FEM_PDET_RANGE_MASK},
- {BRCMS_SROM_TRISO5G, 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_TR_ISO_MASK},
- {BRCMS_SROM_ANTSWCTL5G, 0xffffff00, 0, SROM8_FEM5G,
- SROM8_FEM_ANTSWLUT_MASK},
- {BRCMS_SROM_TEMPTHRESH, 0xffffff00, 0, SROM8_THERMAL, 0xff00},
- {BRCMS_SROM_TEMPOFFSET, 0xffffff00, 0, SROM8_THERMAL, 0x00ff},
-
- {BRCMS_SROM_CCODE, 0xffffff00, SRFL_CCODE, SROM8_CCODE, 0xffff},
- {BRCMS_SROM_MACADDR, 0xffffff00, SRFL_ETHADDR, SROM8_MACHI, 0xffff},
- {BRCMS_SROM_LEDDC, 0xffffff00, SRFL_NOFFS | SRFL_LEDDC, SROM8_LEDDC,
- 0xffff},
- {BRCMS_SROM_RAWTEMPSENSE, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS,
- 0x01ff},
- {BRCMS_SROM_MEASPOWER, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS,
- 0xfe00},
- {BRCMS_SROM_TEMPSENSE_SLOPE, 0xffffff00, SRFL_PRHEX,
- SROM8_TS_SLP_OPT_CORRX, 0x00ff},
- {BRCMS_SROM_TEMPCORRX, 0xffffff00, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX,
- 0xfc00},
- {BRCMS_SROM_TEMPSENSE_OPTION, 0xffffff00, SRFL_PRHEX,
- SROM8_TS_SLP_OPT_CORRX, 0x0300},
- {BRCMS_SROM_FREQOFFSET_CORR, 0xffffff00, SRFL_PRHEX,
- SROM8_FOC_HWIQ_IQSWP, 0x000f},
- {BRCMS_SROM_IQCAL_SWP_DIS, 0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP,
- 0x0010},
- {BRCMS_SROM_HW_IQCAL_EN, 0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP,
- 0x0020},
- {BRCMS_SROM_PHYCAL_TEMPDELTA, 0xffffff00, 0, SROM8_PHYCAL_TEMPDELTA,
- 0x00ff},
-
- {BRCMS_SROM_CCK2GPO, 0x00000100, 0, SROM8_2G_CCKPO, 0xffff},
- {BRCMS_SROM_OFDM2GPO, 0x00000100, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM8_2G_OFDMPO + 1, 0xffff},
- {BRCMS_SROM_OFDM5GPO, 0x00000100, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM8_5G_OFDMPO + 1, 0xffff},
- {BRCMS_SROM_OFDM5GLPO, 0x00000100, SRFL_MORE, SROM8_5GL_OFDMPO, 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff},
- {BRCMS_SROM_OFDM5GHPO, 0x00000100, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff},
- {BRCMS_SROM_MCS2GPO0, 0x00000100, 0, SROM8_2G_MCSPO, 0xffff},
- {BRCMS_SROM_MCS2GPO1, 0x00000100, 0, SROM8_2G_MCSPO + 1, 0xffff},
- {BRCMS_SROM_MCS2GPO2, 0x00000100, 0, SROM8_2G_MCSPO + 2, 0xffff},
- {BRCMS_SROM_MCS2GPO3, 0x00000100, 0, SROM8_2G_MCSPO + 3, 0xffff},
- {BRCMS_SROM_MCS2GPO4, 0x00000100, 0, SROM8_2G_MCSPO + 4, 0xffff},
- {BRCMS_SROM_MCS2GPO5, 0x00000100, 0, SROM8_2G_MCSPO + 5, 0xffff},
- {BRCMS_SROM_MCS2GPO6, 0x00000100, 0, SROM8_2G_MCSPO + 6, 0xffff},
- {BRCMS_SROM_MCS2GPO7, 0x00000100, 0, SROM8_2G_MCSPO + 7, 0xffff},
- {BRCMS_SROM_MCS5GPO0, 0x00000100, 0, SROM8_5G_MCSPO, 0xffff},
- {BRCMS_SROM_MCS5GPO1, 0x00000100, 0, SROM8_5G_MCSPO + 1, 0xffff},
- {BRCMS_SROM_MCS5GPO2, 0x00000100, 0, SROM8_5G_MCSPO + 2, 0xffff},
- {BRCMS_SROM_MCS5GPO3, 0x00000100, 0, SROM8_5G_MCSPO + 3, 0xffff},
- {BRCMS_SROM_MCS5GPO4, 0x00000100, 0, SROM8_5G_MCSPO + 4, 0xffff},
- {BRCMS_SROM_MCS5GPO5, 0x00000100, 0, SROM8_5G_MCSPO + 5, 0xffff},
- {BRCMS_SROM_MCS5GPO6, 0x00000100, 0, SROM8_5G_MCSPO + 6, 0xffff},
- {BRCMS_SROM_MCS5GPO7, 0x00000100, 0, SROM8_5G_MCSPO + 7, 0xffff},
- {BRCMS_SROM_MCS5GLPO0, 0x00000100, 0, SROM8_5GL_MCSPO, 0xffff},
- {BRCMS_SROM_MCS5GLPO1, 0x00000100, 0, SROM8_5GL_MCSPO + 1, 0xffff},
- {BRCMS_SROM_MCS5GLPO2, 0x00000100, 0, SROM8_5GL_MCSPO + 2, 0xffff},
- {BRCMS_SROM_MCS5GLPO3, 0x00000100, 0, SROM8_5GL_MCSPO + 3, 0xffff},
- {BRCMS_SROM_MCS5GLPO4, 0x00000100, 0, SROM8_5GL_MCSPO + 4, 0xffff},
- {BRCMS_SROM_MCS5GLPO5, 0x00000100, 0, SROM8_5GL_MCSPO + 5, 0xffff},
- {BRCMS_SROM_MCS5GLPO6, 0x00000100, 0, SROM8_5GL_MCSPO + 6, 0xffff},
- {BRCMS_SROM_MCS5GLPO7, 0x00000100, 0, SROM8_5GL_MCSPO + 7, 0xffff},
- {BRCMS_SROM_MCS5GHPO0, 0x00000100, 0, SROM8_5GH_MCSPO, 0xffff},
- {BRCMS_SROM_MCS5GHPO1, 0x00000100, 0, SROM8_5GH_MCSPO + 1, 0xffff},
- {BRCMS_SROM_MCS5GHPO2, 0x00000100, 0, SROM8_5GH_MCSPO + 2, 0xffff},
- {BRCMS_SROM_MCS5GHPO3, 0x00000100, 0, SROM8_5GH_MCSPO + 3, 0xffff},
- {BRCMS_SROM_MCS5GHPO4, 0x00000100, 0, SROM8_5GH_MCSPO + 4, 0xffff},
- {BRCMS_SROM_MCS5GHPO5, 0x00000100, 0, SROM8_5GH_MCSPO + 5, 0xffff},
- {BRCMS_SROM_MCS5GHPO6, 0x00000100, 0, SROM8_5GH_MCSPO + 6, 0xffff},
- {BRCMS_SROM_MCS5GHPO7, 0x00000100, 0, SROM8_5GH_MCSPO + 7, 0xffff},
- {BRCMS_SROM_CDDPO, 0x00000100, 0, SROM8_CDDPO, 0xffff},
- {BRCMS_SROM_STBCPO, 0x00000100, 0, SROM8_STBCPO, 0xffff},
- {BRCMS_SROM_BW40PO, 0x00000100, 0, SROM8_BW40PO, 0xffff},
- {BRCMS_SROM_BWDUPPO, 0x00000100, 0, SROM8_BWDUPPO, 0xffff},
-
- /* power per rate from sromrev 9 */
- {BRCMS_SROM_CCKBW202GPO, 0xfffffe00, 0, SROM9_2GPO_CCKBW20, 0xffff},
- {BRCMS_SROM_CCKBW20UL2GPO, 0xfffffe00, 0, SROM9_2GPO_CCKBW20UL, 0xffff},
- {BRCMS_SROM_LEGOFDMBW202GPO, 0xfffffe00, SRFL_MORE,
- SROM9_2GPO_LOFDMBW20, 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_LOFDMBW20 + 1, 0xffff},
- {BRCMS_SROM_LEGOFDMBW20UL2GPO, 0xfffffe00, SRFL_MORE,
- SROM9_2GPO_LOFDMBW20UL, 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_LOFDMBW20UL + 1, 0xffff},
- {BRCMS_SROM_LEGOFDMBW205GLPO, 0xfffffe00, SRFL_MORE,
- SROM9_5GLPO_LOFDMBW20, 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_LOFDMBW20 + 1, 0xffff},
- {BRCMS_SROM_LEGOFDMBW20UL5GLPO, 0xfffffe00, SRFL_MORE,
- SROM9_5GLPO_LOFDMBW20UL, 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_LOFDMBW20UL + 1, 0xffff},
- {BRCMS_SROM_LEGOFDMBW205GMPO, 0xfffffe00, SRFL_MORE,
- SROM9_5GMPO_LOFDMBW20, 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_LOFDMBW20 + 1, 0xffff},
- {BRCMS_SROM_LEGOFDMBW20UL5GMPO, 0xfffffe00, SRFL_MORE,
- SROM9_5GMPO_LOFDMBW20UL, 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_LOFDMBW20UL + 1, 0xffff},
- {BRCMS_SROM_LEGOFDMBW205GHPO, 0xfffffe00, SRFL_MORE,
- SROM9_5GHPO_LOFDMBW20, 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_LOFDMBW20 + 1, 0xffff},
- {BRCMS_SROM_LEGOFDMBW20UL5GHPO, 0xfffffe00, SRFL_MORE,
- SROM9_5GHPO_LOFDMBW20UL, 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_LOFDMBW20UL + 1, 0xffff},
- {BRCMS_SROM_MCSBW202GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20,
- 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW20 + 1, 0xffff},
- {BRCMS_SROM_MCSBW20UL2GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20UL,
- 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW20UL + 1, 0xffff},
- {BRCMS_SROM_MCSBW402GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW40,
- 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW40 + 1, 0xffff},
- {BRCMS_SROM_MCSBW205GLPO, 0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW20,
- 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW20 + 1, 0xffff},
- {BRCMS_SROM_MCSBW20UL5GLPO, 0xfffffe00, SRFL_MORE,
- SROM9_5GLPO_MCSBW20UL, 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW20UL + 1, 0xffff},
- {BRCMS_SROM_MCSBW405GLPO, 0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW40,
- 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW40 + 1, 0xffff},
- {BRCMS_SROM_MCSBW205GMPO, 0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW20,
- 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW20 + 1, 0xffff},
- {BRCMS_SROM_MCSBW20UL5GMPO, 0xfffffe00, SRFL_MORE,
- SROM9_5GMPO_MCSBW20UL, 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW20UL + 1, 0xffff},
- {BRCMS_SROM_MCSBW405GMPO, 0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW40,
- 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW40 + 1, 0xffff},
- {BRCMS_SROM_MCSBW205GHPO, 0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW20,
- 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW20 + 1, 0xffff},
- {BRCMS_SROM_MCSBW20UL5GHPO, 0xfffffe00, SRFL_MORE,
- SROM9_5GHPO_MCSBW20UL, 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW20UL + 1, 0xffff},
- {BRCMS_SROM_MCSBW405GHPO, 0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW40,
- 0xffff},
- {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW40 + 1, 0xffff},
- {BRCMS_SROM_MCS32PO, 0xfffffe00, 0, SROM9_PO_MCS32, 0xffff},
- {BRCMS_SROM_LEGOFDM40DUPPO, 0xfffffe00, 0, SROM9_PO_LOFDM40DUP, 0xffff},
-
- {BRCMS_SROM_NULL, 0, 0, 0, 0}
-};
-
-static const struct brcms_sromvar perpath_pci_sromvars[] = {
- {BRCMS_SROM_MAXP2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0x00ff},
- {BRCMS_SROM_ITT2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0xff00},
- {BRCMS_SROM_ITT5GA0, 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0xff00},
- {BRCMS_SROM_PA2GW0A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA, 0xffff},
- {BRCMS_SROM_PA2GW1A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 1, 0xffff},
- {BRCMS_SROM_PA2GW2A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 2, 0xffff},
- {BRCMS_SROM_MAXP5GA0, 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0x00ff},
- {BRCMS_SROM_MAXP5GHA0, 0xffffff00, 0, SROM8_5GLH_MAXP, 0x00ff},
- {BRCMS_SROM_MAXP5GLA0, 0xffffff00, 0, SROM8_5GLH_MAXP, 0xff00},
- {BRCMS_SROM_PA5GW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA, 0xffff},
- {BRCMS_SROM_PA5GW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 1, 0xffff},
- {BRCMS_SROM_PA5GW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 2, 0xffff},
- {BRCMS_SROM_PA5GLW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA, 0xffff},
- {BRCMS_SROM_PA5GLW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 1,
- 0xffff},
- {BRCMS_SROM_PA5GLW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 2,
- 0xffff},
- {BRCMS_SROM_PA5GHW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA, 0xffff},
- {BRCMS_SROM_PA5GHW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 1,
- 0xffff},
- {BRCMS_SROM_PA5GHW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 2,
- 0xffff},
- {BRCMS_SROM_NULL, 0, 0, 0, 0}
-};
-
-/* crc table has the same contents for every device instance, so it can be
- * shared between devices. */
-static u8 brcms_srom_crc8_table[CRC8_TABLE_SIZE];
-
-static uint mask_shift(u16 mask)
-{
- uint i;
- for (i = 0; i < (sizeof(mask) << 3); i++) {
- if (mask & (1 << i))
- return i;
- }
- return 0;
-}
-
-static uint mask_width(u16 mask)
-{
- int i;
- for (i = (sizeof(mask) << 3) - 1; i >= 0; i--) {
- if (mask & (1 << i))
- return (uint) (i - mask_shift(mask) + 1);
- }
- return 0;
-}
-
-static inline void le16_to_cpu_buf(u16 *buf, uint nwords)
-{
- while (nwords--)
- *(buf + nwords) = le16_to_cpu(*(__le16 *)(buf + nwords));
-}
-
-static inline void cpu_to_le16_buf(u16 *buf, uint nwords)
-{
- while (nwords--)
- *(__le16 *)(buf + nwords) = cpu_to_le16(*(buf + nwords));
-}
-
-/*
- * convert binary srom data into linked list of srom variable items.
- */
-static int
-_initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
-{
- struct brcms_srom_list_head *entry;
- enum brcms_srom_id id;
- u16 w;
- u32 val = 0;
- const struct brcms_sromvar *srv;
- uint width;
- uint flags;
- u32 sr = (1 << sromrev);
- uint p;
- uint pb = SROM8_PATH0;
- const uint psz = SROM8_PATH1 - SROM8_PATH0;
-
- /* first store the srom revision */
- entry = kzalloc(sizeof(struct brcms_srom_list_head), GFP_KERNEL);
- if (!entry)
- return -ENOMEM;
-
- entry->varid = BRCMS_SROM_REV;
- entry->var_type = BRCMS_SROM_UNUMBER;
- entry->uval = sromrev;
- list_add(&entry->var_list, var_list);
-
- for (srv = pci_sromvars; srv->varid != BRCMS_SROM_NULL; srv++) {
- enum brcms_srom_var_type type;
- u8 ea[ETH_ALEN];
- u8 extra_space = 0;
-
- if ((srv->revmask & sr) == 0)
- continue;
-
- flags = srv->flags;
- id = srv->varid;
-
- /* This entry is for mfgc only. Don't generate param for it, */
- if (flags & SRFL_NOVAR)
- continue;
-
- if (flags & SRFL_ETHADDR) {
- /*
- * stored in string format XX:XX:XX:XX:XX:XX (17 chars)
- */
- ea[0] = (srom[srv->off] >> 8) & 0xff;
- ea[1] = srom[srv->off] & 0xff;
- ea[2] = (srom[srv->off + 1] >> 8) & 0xff;
- ea[3] = srom[srv->off + 1] & 0xff;
- ea[4] = (srom[srv->off + 2] >> 8) & 0xff;
- ea[5] = srom[srv->off + 2] & 0xff;
- /* 17 characters + string terminator - union size */
- extra_space = 18 - sizeof(s32);
- type = BRCMS_SROM_STRING;
- } else {
- w = srom[srv->off];
- val = (w & srv->mask) >> mask_shift(srv->mask);
- width = mask_width(srv->mask);
-
- while (srv->flags & SRFL_MORE) {
- srv++;
- if (srv->off == 0)
- continue;
-
- w = srom[srv->off];
- val +=
- ((w & srv->mask) >> mask_shift(srv->
- mask)) <<
- width;
- width += mask_width(srv->mask);
- }
-
- if ((flags & SRFL_NOFFS)
- && ((int)val == (1 << width) - 1))
- continue;
-
- if (flags & SRFL_CCODE) {
- type = BRCMS_SROM_STRING;
- } else if (flags & SRFL_LEDDC) {
- /* LED Powersave duty cycle has to be scaled:
- *(oncount >> 24) (offcount >> 8)
- */
- u32 w32 = /* oncount */
- (((val >> 8) & 0xff) << 24) |
- /* offcount */
- (((val & 0xff)) << 8);
- type = BRCMS_SROM_UNUMBER;
- val = w32;
- } else if ((flags & SRFL_PRSIGN)
- && (val & (1 << (width - 1)))) {
- type = BRCMS_SROM_SNUMBER;
- val |= ~0 << width;
- } else
- type = BRCMS_SROM_UNUMBER;
- }
-
- entry = kzalloc(sizeof(struct brcms_srom_list_head) +
- extra_space, GFP_KERNEL);
- if (!entry)
- return -ENOMEM;
- entry->varid = id;
- entry->var_type = type;
- if (flags & SRFL_ETHADDR) {
- snprintf(entry->buf, 18, "%pM", ea);
- } else if (flags & SRFL_CCODE) {
- if (val == 0)
- entry->buf[0] = '\0';
- else
- snprintf(entry->buf, 3, "%c%c",
- (val >> 8), (val & 0xff));
- } else {
- entry->uval = val;
- }
-
- list_add(&entry->var_list, var_list);
- }
-
- for (p = 0; p < MAX_PATH_SROM; p++) {
- for (srv = perpath_pci_sromvars;
- srv->varid != BRCMS_SROM_NULL; srv++) {
- if ((srv->revmask & sr) == 0)
- continue;
-
- if (srv->flags & SRFL_NOVAR)
- continue;
-
- w = srom[pb + srv->off];
- val = (w & srv->mask) >> mask_shift(srv->mask);
- width = mask_width(srv->mask);
-
- /* Cheating: no per-path var is more than
- * 1 word */
- if ((srv->flags & SRFL_NOFFS)
- && ((int)val == (1 << width) - 1))
- continue;
-
- entry =
- kzalloc(sizeof(struct brcms_srom_list_head),
- GFP_KERNEL);
- if (!entry)
- return -ENOMEM;
- entry->varid = srv->varid+p;
- entry->var_type = BRCMS_SROM_UNUMBER;
- entry->uval = val;
- list_add(&entry->var_list, var_list);
- }
- pb += psz;
- }
- return 0;
-}
-
-/*
- * The crc check is done on a little-endian array, we need
- * to switch the bytes around before checking crc (and
- * then switch it back).
- */
-static int do_crc_check(u16 *buf, unsigned nwords)
-{
- u8 crc;
-
- cpu_to_le16_buf(buf, nwords);
- crc = crc8(brcms_srom_crc8_table, (void *)buf, nwords << 1, CRC8_INIT_VALUE);
- le16_to_cpu_buf(buf, nwords);
-
- return crc == CRC8_GOOD_VALUE(brcms_srom_crc8_table);
-}
-
-/*
- * Read in and validate sprom.
- * Return 0 on success, nonzero on error.
- */
-static int
-sprom_read_pci(struct si_pub *sih, u16 *buf, uint nwords, bool check_crc)
-{
- int err = 0;
- uint i;
- struct bcma_device *core;
- uint sprom_offset;
-
- /* determine core to read */
- if (ai_get_ccrev(sih) < 32) {
- core = ai_findcore(sih, BCMA_CORE_80211, 0);
- sprom_offset = PCI_BAR0_SPROM_OFFSET;
- } else {
- core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0);
- sprom_offset = CHIPCREGOFFS(sromotp);
- }
-
- /* read the sprom */
- for (i = 0; i < nwords; i++)
- buf[i] = bcma_read16(core, sprom_offset+i*2);
-
- if (buf[0] == 0xffff)
- /*
- * The hardware thinks that an srom that starts with
- * 0xffff is blank, regardless of the rest of the
- * content, so declare it bad.
- */
- return -ENODATA;
-
- if (check_crc && !do_crc_check(buf, nwords))
- err = -EIO;
-
- return err;
-}
-
-static int otp_read_pci(struct si_pub *sih, u16 *buf, uint nwords)
-{
- u8 *otp;
- uint sz = OTP_SZ_MAX / 2; /* size in words */
- int err = 0;
-
- otp = kzalloc(OTP_SZ_MAX, GFP_ATOMIC);
- if (otp == NULL)
- return -ENOMEM;
-
- err = otp_read_region(sih, OTP_HW_RGN, (u16 *) otp, &sz);
-
- sz = min_t(uint, sz, nwords);
- memcpy(buf, otp, sz * 2);
-
- kfree(otp);
-
- /* Check CRC */
- if (buf[0] == 0xffff)
- /* The hardware thinks that an srom that starts with 0xffff
- * is blank, regardless of the rest of the content, so declare
- * it bad.
- */
- return -ENODATA;
-
- /* fixup the endianness so crc8 will pass */
- cpu_to_le16_buf(buf, sz);
- if (crc8(brcms_srom_crc8_table, (u8 *) buf, sz * 2,
- CRC8_INIT_VALUE) != CRC8_GOOD_VALUE(brcms_srom_crc8_table))
- err = -EIO;
- else
- /* now correct the endianness of the byte array */
- le16_to_cpu_buf(buf, sz);
-
- return err;
-}
-
-/*
- * Initialize nonvolatile variable table from sprom.
- * Return 0 on success, nonzero on error.
- */
-int srom_var_init(struct si_pub *sih)
-{
- u16 *srom;
- u8 sromrev = 0;
- u32 sr;
- int err = 0;
-
- /*
- * Apply CRC over SROM content regardless SROM is present or not.
- */
- srom = kmalloc(SROM_MAX, GFP_ATOMIC);
- if (!srom)
- return -ENOMEM;
-
- crc8_populate_lsb(brcms_srom_crc8_table, SROM_CRC8_POLY);
- if (ai_is_sprom_available(sih)) {
- err = sprom_read_pci(sih, srom, SROM4_WORDS, true);
-
- if (err == 0)
- /* srom read and passed crc */
- /* top word of sprom contains version and crc8 */
- sromrev = srom[SROM4_CRCREV] & 0xff;
- } else {
- /* Use OTP if SPROM not available */
- err = otp_read_pci(sih, srom, SROM4_WORDS);
- if (err == 0)
- /* OTP only contain SROM rev8/rev9 for now */
- sromrev = srom[SROM4_CRCREV] & 0xff;
- }
-
- if (!err) {
- struct si_info *sii = (struct si_info *)sih;
-
- /* Bitmask for the sromrev */
- sr = 1 << sromrev;
-
- /*
- * srom version check: Current valid versions: 8, 9
- */
- if ((sr & 0x300) == 0) {
- err = -EINVAL;
- goto errout;
- }
-
- INIT_LIST_HEAD(&sii->var_list);
-
- /* parse SROM into name=value pairs. */
- err = _initvars_srom_pci(sromrev, srom, &sii->var_list);
- if (err)
- srom_free_vars(sih);
- }
-
-errout:
- kfree(srom);
- return err;
-}
-
-void srom_free_vars(struct si_pub *sih)
-{
- struct si_info *sii;
- struct brcms_srom_list_head *entry, *next;
-
- sii = (struct si_info *)sih;
- list_for_each_entry_safe(entry, next, &sii->var_list, var_list) {
- list_del(&entry->var_list);
- kfree(entry);
- }
-}
-
-/*
- * Search the name=value vars for a specific one and return its value.
- * Returns NULL if not found.
- */
-char *getvar(struct si_pub *sih, enum brcms_srom_id id)
-{
- struct si_info *sii;
- struct brcms_srom_list_head *entry;
-
- sii = (struct si_info *)sih;
-
- list_for_each_entry(entry, &sii->var_list, var_list)
- if (entry->varid == id)
- return &entry->buf[0];
-
- /* nothing found */
- return NULL;
-}
-
-/*
- * Search the vars for a specific one and return its value as
- * an integer. Returns 0 if not found.-
- */
-int getintvar(struct si_pub *sih, enum brcms_srom_id id)
-{
- struct si_info *sii;
- struct brcms_srom_list_head *entry;
- unsigned long res;
-
- sii = (struct si_info *)sih;
-
- list_for_each_entry(entry, &sii->var_list, var_list)
- if (entry->varid == id) {
- if (entry->var_type == BRCMS_SROM_SNUMBER ||
- entry->var_type == BRCMS_SROM_UNUMBER)
- return (int)entry->sval;
- else if (!kstrtoul(&entry->buf[0], 0, &res))
- return (int)res;
- }
-
- return 0;
-}
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/srom.h b/drivers/net/wireless/brcm80211/brcmsmac/srom.h
deleted file mode 100644
index f2a58f262c99..000000000000
--- a/drivers/net/wireless/brcm80211/brcmsmac/srom.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2010 Broadcom Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef _BRCM_SROM_H_
-#define _BRCM_SROM_H_
-
-#include "types.h"
-
-/* Prototypes */
-extern int srom_var_init(struct si_pub *sih);
-extern void srom_free_vars(struct si_pub *sih);
-
-extern int srom_read(struct si_pub *sih, uint bus, void *curmap,
- uint byteoff, uint nbytes, u16 *buf, bool check_crc);
-
-#endif /* _BRCM_SROM_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/stf.c b/drivers/net/wireless/brcm80211/brcmsmac/stf.c
index d8f528eb180c..ed1d1aa71d2d 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/stf.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/stf.c
@@ -370,9 +370,11 @@ void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc)
void brcms_c_stf_phy_chain_calc(struct brcms_c_info *wlc)
{
+ struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom;
+
/* get available rx/tx chains */
- wlc->stf->hw_txchain = (u8) getintvar(wlc->hw->sih, BRCMS_SROM_TXCHAIN);
- wlc->stf->hw_rxchain = (u8) getintvar(wlc->hw->sih, BRCMS_SROM_RXCHAIN);
+ wlc->stf->hw_txchain = sprom->txchain;
+ wlc->stf->hw_rxchain = sprom->rxchain;
/* these parameter are intended to be used for all PHY types */
if (wlc->stf->hw_txchain == 0 || wlc->stf->hw_txchain == 0xf) {
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index 01dc44267317..e55ec6c8a920 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -31,6 +31,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
+#include <net/mac80211.h>
#include "iwl-dev.h"
#include "iwl-io.h"
@@ -273,9 +274,20 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
return;
}
+ /*
+ * Possible situations when BT needs to take over for receive,
+ * at the same time where STA needs to response to AP's frame(s),
+ * reduce the tx power of the required response frames, by that,
+ * allow the concurrent BT receive & WiFi transmit
+ * (BT - ANT A, WiFi -ANT B), without interference to one another
+ *
+ * Reduced tx power apply to control frames only (ACK/Back/CTS)
+ * when indicated by the BT config command
+ */
basic.kill_ack_mask = priv->kill_ack_mask;
basic.kill_cts_mask = priv->kill_cts_mask;
- basic.reduce_txpower = priv->reduced_txpower;
+ if (priv->reduced_txpower)
+ basic.reduce_txpower = IWLAGN_BT_REDUCED_TX_PWR;
basic.valid = priv->bt_valid;
/*
@@ -589,13 +601,31 @@ static bool iwlagn_set_kill_msk(struct iwl_priv *priv,
return need_update;
}
+/*
+ * Upon RSSI changes, sends a bt config command with following changes
+ * 1. enable/disable "reduced control frames tx power
+ * 2. update the "kill)ack_mask" and "kill_cts_mask"
+ *
+ * If "reduced tx power" is enabled, uCode shall
+ * 1. ACK/Back/CTS rate shall reduced to 6Mbps
+ * 2. not use duplciate 20/40MHz mode
+ */
static bool iwlagn_fill_txpower_mode(struct iwl_priv *priv,
struct iwl_bt_uart_msg *uart_msg)
{
bool need_update = false;
+ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+ int ave_rssi;
+ ave_rssi = ieee80211_ave_rssi(ctx->vif);
+ if (!ave_rssi) {
+ /* no rssi data, no changes to reduce tx power */
+ IWL_DEBUG_COEX(priv, "no rssi data available\n");
+ return need_update;
+ }
if (!priv->reduced_txpower &&
!iwl_is_associated(priv, IWL_RXON_CTX_PAN) &&
+ (ave_rssi > BT_ENABLE_REDUCED_TXPOWER_THRESHOLD) &&
(uart_msg->frame3 & (BT_UART_MSG_FRAME3ACL_MSK |
BT_UART_MSG_FRAME3OBEX_MSK)) &&
!(uart_msg->frame3 & (BT_UART_MSG_FRAME3SCOESCO_MSK |
@@ -606,13 +636,14 @@ static bool iwlagn_fill_txpower_mode(struct iwl_priv *priv,
need_update = true;
} else if (priv->reduced_txpower &&
(iwl_is_associated(priv, IWL_RXON_CTX_PAN) ||
+ (ave_rssi < BT_DISABLE_REDUCED_TXPOWER_THRESHOLD) ||
(uart_msg->frame3 & (BT_UART_MSG_FRAME3SCOESCO_MSK |
BT_UART_MSG_FRAME3SNIFF_MSK | BT_UART_MSG_FRAME3A2DP_MSK)) ||
!(uart_msg->frame3 & (BT_UART_MSG_FRAME3ACL_MSK |
BT_UART_MSG_FRAME3OBEX_MSK)))) {
/* disable reduced tx power */
priv->reduced_txpower = false;
- priv->bt_valid &= ~IWLAGN_BT_VALID_REDUCED_TX_PWR;
+ priv->bt_valid |= IWLAGN_BT_VALID_REDUCED_TX_PWR;
need_update = true;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
index 74fbee627306..0a3aa7c83003 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
@@ -61,6 +61,10 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv,
RXON_FILTER_ACCEPT_GRP_MSK;
break;
+ case NL80211_IFTYPE_MONITOR:
+ ctx->staging.dev_type = RXON_DEV_TYPE_SNIFFER;
+ break;
+
default:
IWL_ERR(priv, "Unsupported interface type %d\n",
ctx->vif->type);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index f2e9f298a947..3366e2e2f00f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -590,11 +590,17 @@ turn_off:
spin_unlock_bh(&priv->sta_lock);
if (test_bit(txq_id, priv->agg_q_alloc)) {
- /* If the transport didn't know that we wanted to start
- * agreggation, don't tell it that we want to stop them
+ /*
+ * If the transport didn't know that we wanted to start
+ * agreggation, don't tell it that we want to stop them.
+ * This can happen when we don't get the addBA response on
+ * time, or we hadn't time to drain the AC queues.
*/
- if (agg_state != IWL_AGG_STARTING)
+ if (agg_state == IWL_AGG_ON)
iwl_trans_tx_agg_disable(priv->trans, txq_id);
+ else
+ IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n",
+ agg_state);
iwlagn_dealloc_agg_txq(priv, txq_id);
}
@@ -1300,10 +1306,11 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
(u8 *) &ba_resp->sta_addr_lo32,
ba_resp->sta_id);
IWL_DEBUG_TX_REPLY(priv, "TID = %d, SeqCtl = %d, bitmap = 0x%llx, "
- "scd_flow = %d, scd_ssn = %d\n",
+ "scd_flow = %d, scd_ssn = %d sent:%d, acked:%d\n",
ba_resp->tid, le16_to_cpu(ba_resp->seq_ctl),
(unsigned long long)le64_to_cpu(ba_resp->bitmap),
- scd_flow, ba_resp_scd_ssn);
+ scd_flow, ba_resp_scd_ssn, ba_resp->txed,
+ ba_resp->txed_2_done);
/* Mark that the expected block-ack response arrived */
agg->wait_for_ba = false;
@@ -1319,8 +1326,6 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
*/
ba_resp->txed = ba_resp->txed_2_done;
}
- IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n",
- ba_resp->txed, ba_resp->txed_2_done);
priv->tid_data[sta_id][tid].next_reclaimed = ba_resp_scd_ssn;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 8d7637083fcf..ec36e2b020b6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -603,7 +603,7 @@ void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY;
priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
priv->contexts[IWL_RXON_CTX_BSS].exclusive_interface_modes =
- BIT(NL80211_IFTYPE_ADHOC);
+ BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MONITOR);
priv->contexts[IWL_RXON_CTX_BSS].interface_modes =
BIT(NL80211_IFTYPE_STATION);
priv->contexts[IWL_RXON_CTX_BSS].ap_devtype = RXON_DEV_TYPE_AP;
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 83a6930f3658..9af6a239b384 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -1910,6 +1910,8 @@ enum iwl_bt_kill_idx {
IWLAGN_BT_VALID_REDUCED_TX_PWR | \
IWLAGN_BT_VALID_3W_LUT)
+#define IWLAGN_BT_REDUCED_TX_PWR BIT(0)
+
#define IWLAGN_BT_DECISION_LUT_SIZE 12
struct iwl_basic_bt_cmd {
@@ -1923,6 +1925,10 @@ struct iwl_basic_bt_cmd {
u8 bt3_timer_t2_value;
__le16 bt4_reaction_time; /* unused */
__le32 bt3_lookup_table[IWLAGN_BT_DECISION_LUT_SIZE];
+ /*
+ * bit 0: use reduced tx power for control frame
+ * bit 1 - 7: reserved
+ */
u8 reduce_txpower;
u8 reserved;
__le16 valid;
@@ -2272,7 +2278,6 @@ struct iwl_ssid_ie {
#define IWL_GOOD_CRC_TH_DISABLED 0
#define IWL_GOOD_CRC_TH_DEFAULT cpu_to_le16(1)
#define IWL_GOOD_CRC_TH_NEVER cpu_to_le16(0xffff)
-#define IWL_MAX_SCAN_SIZE 1024
#define IWL_MAX_CMD_SIZE 4096
/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c
index d33cc9cc7d3f..ab2f4d7500a4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c
+++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c
@@ -150,6 +150,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
IEEE80211_HW_QUEUE_CONTROL |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
+ IEEE80211_HW_WANT_MONITOR_VIF |
IEEE80211_HW_SCAN_WHILE_IDLE;
hw->offchannel_tx_hw_queue = IWL_AUX_QUEUE;
@@ -223,8 +224,8 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
- /* we create the 802.11 header and a zero-length SSID element */
- hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 2;
+ /* we create the 802.11 header and a max-length SSID element */
+ hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 34;
/*
* We don't use all queues: 4 and 9 are unused and any
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index 8352265dbc4b..544ddf17f5bd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -253,6 +253,8 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
IWL_DEBUG_POWER(priv, "numSkipDtim = %u, dtimPeriod = %d\n",
skip, period);
+ /* The power level here is 0-4 (used as array index), but user expects
+ to see 1-5 (according to spec). */
IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1);
}
@@ -308,10 +310,12 @@ static void iwl_power_build_cmd(struct iwl_priv *priv,
priv->power_data.debug_sleep_level_override,
dtimper);
else {
+ /* Note that the user parameter is 1-5 (according to spec),
+ but we pass 0-4 because it acts as an array index. */
if (iwlwifi_mod_params.power_level > IWL_POWER_INDEX_1 &&
- iwlwifi_mod_params.power_level <= IWL_POWER_INDEX_5)
+ iwlwifi_mod_params.power_level <= IWL_POWER_NUM)
iwl_static_sleep_cmd(priv, cmd,
- iwlwifi_mod_params.power_level, dtimper);
+ iwlwifi_mod_params.power_level - 1, dtimper);
else
iwl_static_sleep_cmd(priv, cmd,
IWL_POWER_INDEX_1, dtimper);
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index a8437a6bc18e..031d8e21f82f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -52,6 +52,7 @@
#define IWL_PASSIVE_DWELL_TIME_52 (10)
#define IWL_PASSIVE_DWELL_BASE (100)
#define IWL_CHANNEL_TUNE_TIME 5
+#define MAX_SCAN_CHANNEL 50
static int iwl_send_scan_abort(struct iwl_priv *priv)
{
@@ -616,7 +617,8 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
*/
static u16 iwl_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta,
- const u8 *ies, int ie_len, int left)
+ const u8 *ies, int ie_len, const u8 *ssid,
+ u8 ssid_len, int left)
{
int len = 0;
u8 *pos = NULL;
@@ -638,14 +640,18 @@ static u16 iwl_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta,
/* ...next IE... */
pos = &frame->u.probe_req.variable[0];
- /* fill in our indirect SSID IE */
- left -= 2;
+ /* fill in our SSID IE */
+ left -= ssid_len + 2;
if (left < 0)
return 0;
*pos++ = WLAN_EID_SSID;
- *pos++ = 0;
+ *pos++ = ssid_len;
+ if (ssid && ssid_len) {
+ memcpy(pos, ssid, ssid_len);
+ pos += ssid_len;
+ }
- len += 2;
+ len += ssid_len + 2;
if (WARN_ON(left < ie_len))
return len;
@@ -679,6 +685,15 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
u8 active_chains;
u8 scan_tx_antennas = priv->hw_params.valid_tx_ant;
int ret;
+ int scan_cmd_size = sizeof(struct iwl_scan_cmd) +
+ MAX_SCAN_CHANNEL * sizeof(struct iwl_scan_channel) +
+ priv->fw->ucode_capa.max_probe_length;
+ const u8 *ssid = NULL;
+ u8 ssid_len = 0;
+
+ if (WARN_ON_ONCE(priv->scan_request &&
+ priv->scan_request->n_channels > MAX_SCAN_CHANNEL))
+ return -EINVAL;
lockdep_assert_held(&priv->mutex);
@@ -686,8 +701,7 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
ctx = iwl_rxon_ctx_from_vif(vif);
if (!priv->scan_cmd) {
- priv->scan_cmd = kmalloc(sizeof(struct iwl_scan_cmd) +
- IWL_MAX_SCAN_SIZE, GFP_KERNEL);
+ priv->scan_cmd = kmalloc(scan_cmd_size, GFP_KERNEL);
if (!priv->scan_cmd) {
IWL_DEBUG_SCAN(priv,
"fail to allocate memory for scan\n");
@@ -695,7 +709,7 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
}
}
scan = priv->scan_cmd;
- memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE);
+ memset(scan, 0, scan_cmd_size);
scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
@@ -746,10 +760,18 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
if (priv->scan_request->n_ssids) {
int i, p = 0;
IWL_DEBUG_SCAN(priv, "Kicking off active scan\n");
- for (i = 0; i < priv->scan_request->n_ssids; i++) {
- /* always does wildcard anyway */
- if (!priv->scan_request->ssids[i].ssid_len)
- continue;
+ /*
+ * The highest priority SSID is inserted to the
+ * probe request template.
+ */
+ ssid_len = priv->scan_request->ssids[0].ssid_len;
+ ssid = priv->scan_request->ssids[0].ssid;
+
+ /*
+ * Invert the order of ssids, the firmware will invert
+ * it back.
+ */
+ for (i = priv->scan_request->n_ssids - 1; i >= 1; i--) {
scan->direct_scan[p].id = WLAN_EID_SSID;
scan->direct_scan[p].len =
priv->scan_request->ssids[i].ssid_len;
@@ -883,7 +905,8 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
vif->addr,
priv->scan_request->ie,
priv->scan_request->ie_len,
- IWL_MAX_SCAN_SIZE - sizeof(*scan));
+ ssid, ssid_len,
+ scan_cmd_size - sizeof(*scan));
break;
case IWL_SCAN_RADIO_RESET:
case IWL_SCAN_ROC:
@@ -891,7 +914,8 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
cmd_len = iwl_fill_probe_req(
(struct ieee80211_mgmt *)scan->data,
iwl_bcast_addr, NULL, 0,
- IWL_MAX_SCAN_SIZE - sizeof(*scan));
+ NULL, 0,
+ scan_cmd_size - sizeof(*scan));
break;
default:
BUG();
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 75403e6e3990..cd3b0d400618 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -1011,6 +1011,7 @@ static struct usb_driver if_usb_driver = {
.suspend = if_usb_suspend,
.resume = if_usb_resume,
.reset_resume = if_usb_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(if_usb_driver);
diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c
index 7ced130f4f9e..19a5a92dd779 100644
--- a/drivers/net/wireless/libertas_tf/if_usb.c
+++ b/drivers/net/wireless/libertas_tf/if_usb.c
@@ -920,6 +920,7 @@ static struct usb_driver if_usb_driver = {
.id_table = if_usb_table,
.suspend = if_usb_suspend,
.resume = if_usb_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(if_usb_driver);
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 03c0c6b1372c..fb787df01666 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -746,6 +746,11 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
hwsim_check_sta_magic(txi->control.sta);
ieee80211_tx_info_clear_status(txi);
+
+ /* frame was transmitted at most favorable rate at first attempt */
+ txi->control.rates[0].count = 1;
+ txi->control.rates[1].idx = -1;
+
if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack)
txi->flags |= IEEE80211_TX_STAT_ACK;
ieee80211_tx_status_irqsafe(hw, skb);
diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile
index 5c1a46bf1e11..3f66ebb0a630 100644
--- a/drivers/net/wireless/mwifiex/Makefile
+++ b/drivers/net/wireless/mwifiex/Makefile
@@ -29,6 +29,8 @@ mwifiex-y += scan.o
mwifiex-y += join.o
mwifiex-y += sta_ioctl.o
mwifiex-y += sta_cmd.o
+mwifiex-y += uap_cmd.o
+mwifiex-y += ie.o
mwifiex-y += sta_cmdresp.o
mwifiex-y += sta_event.o
mwifiex-y += sta_tx.o
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index c78ea873a63a..87671446e24b 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -20,6 +20,23 @@
#include "cfg80211.h"
#include "main.h"
+static const struct ieee80211_iface_limit mwifiex_ap_sta_limits[] = {
+ {
+ .max = 1, .types = BIT(NL80211_IFTYPE_STATION),
+ },
+ {
+ .max = 1, .types = BIT(NL80211_IFTYPE_AP),
+ },
+};
+
+static const struct ieee80211_iface_combination mwifiex_iface_comb_ap_sta = {
+ .limits = mwifiex_ap_sta_limits,
+ .num_different_channels = 1,
+ .n_limits = ARRAY_SIZE(mwifiex_ap_sta_limits),
+ .max_interfaces = MWIFIEX_MAX_BSS_NUM,
+ .beacon_int_infra_match = true,
+};
+
/*
* This function maps the nl802.11 channel type into driver channel type.
*
@@ -67,7 +84,7 @@ mwifiex_is_alg_wep(u32 cipher)
/*
* This function retrieves the private structure from kernel wiphy structure.
*/
-static void *mwifiex_cfg80211_get_priv(struct wiphy *wiphy)
+static void *mwifiex_cfg80211_get_adapter(struct wiphy *wiphy)
{
return (void *) (*(unsigned long *) wiphy_priv(wiphy));
}
@@ -80,8 +97,10 @@ mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, bool pairwise, const u8 *mac_addr)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(netdev);
+ const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ const u8 *peer_mac = pairwise ? mac_addr : bc_mac;
- if (mwifiex_set_encode(priv, NULL, 0, key_index, 1)) {
+ if (mwifiex_set_encode(priv, NULL, 0, key_index, peer_mac, 1)) {
wiphy_err(wiphy, "deleting the crypto keys\n");
return -EFAULT;
}
@@ -98,7 +117,8 @@ mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy,
enum nl80211_tx_power_setting type,
int mbm)
{
- struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+ struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
+ struct mwifiex_private *priv;
struct mwifiex_power_cfg power_cfg;
int dbm = MBM_TO_DBM(mbm);
@@ -109,6 +129,8 @@ mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy,
power_cfg.is_power_auto = 1;
}
+ priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+
return mwifiex_set_tx_power(priv, &power_cfg);
}
@@ -148,7 +170,7 @@ mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
if (!priv->sec_info.wep_enabled)
return 0;
- if (mwifiex_set_encode(priv, NULL, 0, key_index, 0)) {
+ if (mwifiex_set_encode(priv, NULL, 0, key_index, NULL, 0)) {
wiphy_err(wiphy, "set default Tx key index\n");
return -EFAULT;
}
@@ -165,9 +187,11 @@ mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev,
struct key_params *params)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(netdev);
+ const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ const u8 *peer_mac = pairwise ? mac_addr : bc_mac;
if (mwifiex_set_encode(priv, params->key, params->key_len,
- key_index, 0)) {
+ key_index, peer_mac, 0)) {
wiphy_err(wiphy, "crypto keys added\n");
return -EFAULT;
}
@@ -192,13 +216,13 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
enum ieee80211_band band;
struct ieee80211_supported_band *sband;
struct ieee80211_channel *ch;
- struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
- struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
+ struct mwifiex_private *priv;
struct mwifiex_802_11d_domain_reg *domain_info = &adapter->domain_reg;
/* Set country code */
- domain_info->country_code[0] = priv->country_code[0];
- domain_info->country_code[1] = priv->country_code[1];
+ domain_info->country_code[0] = adapter->country_code[0];
+ domain_info->country_code[1] = adapter->country_code[1];
domain_info->country_code[2] = ' ';
band = mwifiex_band_to_radio_type(adapter->config_bands);
@@ -250,6 +274,8 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
domain_info->no_of_triplet = no_of_triplet;
+ priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+
if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
HostCmd_ACT_GEN_SET, 0, NULL)) {
wiphy_err(wiphy, "11D: setting domain info in FW\n");
@@ -272,12 +298,12 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
static int mwifiex_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
- struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+ struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
- wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for domain"
- " %c%c\n", request->alpha2[0], request->alpha2[1]);
+ wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for %c%c\n",
+ request->alpha2[0], request->alpha2[1]);
- memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2));
+ memcpy(adapter->country_code, request->alpha2, sizeof(request->alpha2));
switch (request->initiator) {
case NL80211_REGDOM_SET_BY_DRIVER:
@@ -361,33 +387,10 @@ mwifiex_set_rf_channel(struct mwifiex_private *priv,
if (mwifiex_bss_set_channel(priv, &cfp))
return -EFAULT;
- return mwifiex_drv_change_adhoc_chan(priv, cfp.channel);
-}
-
-/*
- * CFG802.11 operation handler to set channel.
- *
- * This function can only be used when station is not connected.
- */
-static int
-mwifiex_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type)
-{
- struct mwifiex_private *priv;
-
- if (dev)
- priv = mwifiex_netdev_get_priv(dev);
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
+ return mwifiex_drv_change_adhoc_chan(priv, cfp.channel);
else
- priv = mwifiex_cfg80211_get_priv(wiphy);
-
- if (priv->media_connected) {
- wiphy_err(wiphy, "This setting is valid only when station "
- "is not connected\n");
- return -EINVAL;
- }
-
- return mwifiex_set_rf_channel(priv, chan, channel_type);
+ return mwifiex_uap_set_channel(priv, cfp.channel);
}
/*
@@ -399,18 +402,13 @@ mwifiex_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
static int
mwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr)
{
- int ret;
-
if (frag_thr < MWIFIEX_FRAG_MIN_VALUE ||
frag_thr > MWIFIEX_FRAG_MAX_VALUE)
- return -EINVAL;
-
- /* Send request to firmware */
- ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
- HostCmd_ACT_GEN_SET, FRAG_THRESH_I,
- &frag_thr);
+ frag_thr = MWIFIEX_FRAG_MAX_VALUE;
- return ret;
+ return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, FRAG_THRESH_I,
+ &frag_thr);
}
/*
@@ -439,19 +437,85 @@ mwifiex_set_rts(struct mwifiex_private *priv, u32 rts_thr)
static int
mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
{
- struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
- int ret = 0;
+ struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
+ struct mwifiex_private *priv;
+ struct mwifiex_uap_bss_param *bss_cfg;
+ int ret, bss_started, i;
+
+ for (i = 0; i < adapter->priv_num; i++) {
+ priv = adapter->priv[i];
+
+ switch (priv->bss_role) {
+ case MWIFIEX_BSS_ROLE_UAP:
+ bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param),
+ GFP_KERNEL);
+ if (!bss_cfg)
+ return -ENOMEM;
+
+ mwifiex_set_sys_config_invalid_data(bss_cfg);
+
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD)
+ bss_cfg->rts_threshold = wiphy->rts_threshold;
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
+ bss_cfg->frag_threshold = wiphy->frag_threshold;
+ if (changed & WIPHY_PARAM_RETRY_LONG)
+ bss_cfg->retry_limit = wiphy->retry_long;
+
+ bss_started = priv->bss_started;
+
+ ret = mwifiex_send_cmd_sync(priv,
+ HostCmd_CMD_UAP_BSS_STOP,
+ HostCmd_ACT_GEN_SET, 0,
+ NULL);
+ if (ret) {
+ wiphy_err(wiphy, "Failed to stop the BSS\n");
+ kfree(bss_cfg);
+ return ret;
+ }
- if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
- ret = mwifiex_set_rts(priv, wiphy->rts_threshold);
- if (ret)
- return ret;
- }
+ ret = mwifiex_send_cmd_async(priv,
+ HostCmd_CMD_UAP_SYS_CONFIG,
+ HostCmd_ACT_GEN_SET,
+ UAP_BSS_PARAMS_I, bss_cfg);
- if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
- ret = mwifiex_set_frag(priv, wiphy->frag_threshold);
+ kfree(bss_cfg);
- return ret;
+ if (ret) {
+ wiphy_err(wiphy, "Failed to set bss config\n");
+ return ret;
+ }
+
+ if (!bss_started)
+ break;
+
+ ret = mwifiex_send_cmd_async(priv,
+ HostCmd_CMD_UAP_BSS_START,
+ HostCmd_ACT_GEN_SET, 0,
+ NULL);
+ if (ret) {
+ wiphy_err(wiphy, "Failed to start BSS\n");
+ return ret;
+ }
+
+ break;
+ case MWIFIEX_BSS_ROLE_STA:
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
+ ret = mwifiex_set_rts(priv,
+ wiphy->rts_threshold);
+ if (ret)
+ return ret;
+ }
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
+ ret = mwifiex_set_frag(priv,
+ wiphy->frag_threshold);
+ if (ret)
+ return ret;
+ }
+ break;
+ }
+ }
+
+ return 0;
}
/*
@@ -466,31 +530,59 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
int ret;
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
- if (priv->bss_mode == type) {
- wiphy_warn(wiphy, "already set to required type\n");
- return 0;
- }
-
- priv->bss_mode = type;
-
- switch (type) {
+ switch (dev->ieee80211_ptr->iftype) {
case NL80211_IFTYPE_ADHOC:
- dev->ieee80211_ptr->iftype = NL80211_IFTYPE_ADHOC;
- wiphy_dbg(wiphy, "info: setting interface type to adhoc\n");
+ switch (type) {
+ case NL80211_IFTYPE_STATION:
+ break;
+ case NL80211_IFTYPE_UNSPECIFIED:
+ wiphy_warn(wiphy, "%s: kept type as IBSS\n", dev->name);
+ case NL80211_IFTYPE_ADHOC: /* This shouldn't happen */
+ return 0;
+ case NL80211_IFTYPE_AP:
+ default:
+ wiphy_err(wiphy, "%s: changing to %d not supported\n",
+ dev->name, type);
+ return -EOPNOTSUPP;
+ }
break;
case NL80211_IFTYPE_STATION:
- dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
- wiphy_dbg(wiphy, "info: setting interface type to managed\n");
+ switch (type) {
+ case NL80211_IFTYPE_ADHOC:
+ break;
+ case NL80211_IFTYPE_UNSPECIFIED:
+ wiphy_warn(wiphy, "%s: kept type as STA\n", dev->name);
+ case NL80211_IFTYPE_STATION: /* This shouldn't happen */
+ return 0;
+ case NL80211_IFTYPE_AP:
+ default:
+ wiphy_err(wiphy, "%s: changing to %d not supported\n",
+ dev->name, type);
+ return -EOPNOTSUPP;
+ }
+ break;
+ case NL80211_IFTYPE_AP:
+ switch (type) {
+ case NL80211_IFTYPE_UNSPECIFIED:
+ wiphy_warn(wiphy, "%s: kept type as AP\n", dev->name);
+ case NL80211_IFTYPE_AP: /* This shouldn't happen */
+ return 0;
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_STATION:
+ default:
+ wiphy_err(wiphy, "%s: changing to %d not supported\n",
+ dev->name, type);
+ return -EOPNOTSUPP;
+ }
break;
- case NL80211_IFTYPE_UNSPECIFIED:
- dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
- wiphy_dbg(wiphy, "info: setting interface type to auto\n");
- return 0;
default:
- wiphy_err(wiphy, "unknown interface type: %d\n", type);
- return -EINVAL;
+ wiphy_err(wiphy, "%s: unknown iftype: %d\n",
+ dev->name, dev->ieee80211_ptr->iftype);
+ return -EOPNOTSUPP;
}
+ dev->ieee80211_ptr->iftype = type;
+ priv->bss_mode = type;
mwifiex_deauthenticate(priv, NULL);
priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM;
@@ -804,6 +896,90 @@ static int mwifiex_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy,
return 0;
}
+/* cfg80211 operation handler for stop ap.
+ * Function stops BSS running at uAP interface.
+ */
+static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+
+ if (mwifiex_del_mgmt_ies(priv))
+ wiphy_err(wiphy, "Failed to delete mgmt IEs!\n");
+
+ if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP,
+ HostCmd_ACT_GEN_SET, 0, NULL)) {
+ wiphy_err(wiphy, "Failed to stop the BSS\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* cfg80211 operation handler for start_ap.
+ * Function sets beacon period, DTIM period, SSID and security into
+ * AP config structure.
+ * AP is configured with these settings and BSS is started.
+ */
+static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_ap_settings *params)
+{
+ struct mwifiex_uap_bss_param *bss_cfg;
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+
+ if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP)
+ return -1;
+ if (mwifiex_set_mgmt_ies(priv, params))
+ return -1;
+
+ bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL);
+ if (!bss_cfg)
+ return -ENOMEM;
+
+ mwifiex_set_sys_config_invalid_data(bss_cfg);
+
+ if (params->beacon_interval)
+ bss_cfg->beacon_period = params->beacon_interval;
+ if (params->dtim_period)
+ bss_cfg->dtim_period = params->dtim_period;
+
+ if (params->ssid && params->ssid_len) {
+ memcpy(bss_cfg->ssid.ssid, params->ssid, params->ssid_len);
+ bss_cfg->ssid.ssid_len = params->ssid_len;
+ }
+
+ if (mwifiex_set_secure_params(priv, bss_cfg, params)) {
+ kfree(bss_cfg);
+ wiphy_err(wiphy, "Failed to parse secuirty parameters!\n");
+ return -1;
+ }
+
+ if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP,
+ HostCmd_ACT_GEN_SET, 0, NULL)) {
+ wiphy_err(wiphy, "Failed to stop the BSS\n");
+ kfree(bss_cfg);
+ return -1;
+ }
+
+ if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG,
+ HostCmd_ACT_GEN_SET,
+ UAP_BSS_PARAMS_I, bss_cfg)) {
+ wiphy_err(wiphy, "Failed to set the SSID\n");
+ kfree(bss_cfg);
+ return -1;
+ }
+
+ kfree(bss_cfg);
+
+ if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_BSS_START,
+ HostCmd_ACT_GEN_SET, 0, NULL)) {
+ wiphy_err(wiphy, "Failed to start the BSS\n");
+ return -1;
+ }
+
+ return 0;
+}
+
/*
* CFG802.11 operation handler for disconnection request.
*
@@ -923,7 +1099,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
priv->wep_key_curr_index = 0;
priv->sec_info.encryption_mode = 0;
priv->sec_info.is_authtype_auto = 0;
- ret = mwifiex_set_encode(priv, NULL, 0, 0, 1);
+ ret = mwifiex_set_encode(priv, NULL, 0, 0, NULL, 1);
if (mode == NL80211_IFTYPE_ADHOC) {
/* "privacy" is set only for ad-hoc mode */
@@ -971,7 +1147,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
" with key len %d\n", sme->key_len);
priv->wep_key_curr_index = sme->key_idx;
ret = mwifiex_set_encode(priv, sme->key, sme->key_len,
- sme->key_idx, 0);
+ sme->key_idx, NULL, 0);
}
}
done:
@@ -1050,6 +1226,11 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
goto done;
}
+ if (priv->bss_mode == NL80211_IFTYPE_AP) {
+ wiphy_err(wiphy, "skip association request for AP interface\n");
+ goto done;
+ }
+
wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n",
(char *) sme->ssid, sme->bssid);
@@ -1283,15 +1464,12 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
u32 *flags,
struct vif_params *params)
{
- struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
- struct mwifiex_adapter *adapter;
+ struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
+ struct mwifiex_private *priv;
struct net_device *dev;
void *mdev_priv;
+ struct wireless_dev *wdev;
- if (!priv)
- return NULL;
-
- adapter = priv->adapter;
if (!adapter)
return NULL;
@@ -1299,12 +1477,21 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
case NL80211_IFTYPE_UNSPECIFIED:
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
+ priv = adapter->priv[MWIFIEX_BSS_TYPE_STA];
if (priv->bss_mode) {
- wiphy_err(wiphy, "cannot create multiple"
- " station/adhoc interfaces\n");
+ wiphy_err(wiphy,
+ "cannot create multiple sta/adhoc ifaces\n");
return NULL;
}
+ wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+ if (!wdev)
+ return NULL;
+
+ wdev->wiphy = wiphy;
+ priv->wdev = wdev;
+ wdev->iftype = NL80211_IFTYPE_STATION;
+
if (type == NL80211_IFTYPE_UNSPECIFIED)
priv->bss_mode = NL80211_IFTYPE_STATION;
else
@@ -1312,11 +1499,36 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
priv->bss_type = MWIFIEX_BSS_TYPE_STA;
priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II;
- priv->bss_priority = 0;
+ priv->bss_priority = MWIFIEX_BSS_ROLE_STA;
priv->bss_role = MWIFIEX_BSS_ROLE_STA;
priv->bss_num = 0;
break;
+ case NL80211_IFTYPE_AP:
+ priv = adapter->priv[MWIFIEX_BSS_TYPE_UAP];
+
+ if (priv->bss_mode) {
+ wiphy_err(wiphy, "Can't create multiple AP interfaces");
+ return NULL;
+ }
+
+ wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+ if (!wdev)
+ return NULL;
+
+ priv->wdev = wdev;
+ wdev->wiphy = wiphy;
+ wdev->iftype = NL80211_IFTYPE_AP;
+
+ priv->bss_type = MWIFIEX_BSS_TYPE_UAP;
+ priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II;
+ priv->bss_priority = MWIFIEX_BSS_ROLE_UAP;
+ priv->bss_role = MWIFIEX_BSS_ROLE_UAP;
+ priv->bss_started = 0;
+ priv->bss_num = 0;
+ priv->bss_mode = type;
+
+ break;
default:
wiphy_err(wiphy, "type not supported\n");
return NULL;
@@ -1329,6 +1541,15 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
goto error;
}
+ mwifiex_init_priv_params(priv, dev);
+ priv->netdev = dev;
+
+ mwifiex_setup_ht_caps(&wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, priv);
+
+ if (adapter->config_bands & BAND_A)
+ mwifiex_setup_ht_caps(
+ &wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, priv);
+
dev_net_set(dev, wiphy_net(wiphy));
dev->ieee80211_ptr = priv->wdev;
dev->ieee80211_ptr->iftype = priv->bss_mode;
@@ -1343,9 +1564,6 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
mdev_priv = netdev_priv(dev);
*((unsigned long *) mdev_priv) = (unsigned long) priv;
- priv->netdev = dev;
- mwifiex_init_priv_params(priv, dev);
-
SET_NETDEV_DEV(dev, adapter->dev);
/* Register network device */
@@ -1417,7 +1635,6 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
.get_station = mwifiex_cfg80211_get_station,
.dump_station = mwifiex_cfg80211_dump_station,
.set_wiphy_params = mwifiex_cfg80211_set_wiphy_params,
- .set_channel = mwifiex_cfg80211_set_channel,
.join_ibss = mwifiex_cfg80211_join_ibss,
.leave_ibss = mwifiex_cfg80211_leave_ibss,
.add_key = mwifiex_cfg80211_add_key,
@@ -1426,6 +1643,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
.set_power_mgmt = mwifiex_cfg80211_set_power_mgmt,
.set_tx_power = mwifiex_cfg80211_set_tx_power,
.set_bitrate_mask = mwifiex_cfg80211_set_bitrate_mask,
+ .start_ap = mwifiex_cfg80211_start_ap,
+ .stop_ap = mwifiex_cfg80211_stop_ap,
.set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config,
};
@@ -1436,82 +1655,67 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
* default parameters and handler function pointers, and finally
* registers the device.
*/
-int mwifiex_register_cfg80211(struct mwifiex_private *priv)
+
+int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
{
int ret;
void *wdev_priv;
- struct wireless_dev *wdev;
- struct ieee80211_sta_ht_cap *ht_info;
+ struct wiphy *wiphy;
+ struct mwifiex_private *priv = adapter->priv[MWIFIEX_BSS_TYPE_STA];
u8 *country_code;
- wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
- if (!wdev) {
- dev_err(priv->adapter->dev, "%s: allocating wireless device\n",
- __func__);
- return -ENOMEM;
- }
- wdev->wiphy =
- wiphy_new(&mwifiex_cfg80211_ops,
- sizeof(struct mwifiex_private *));
- if (!wdev->wiphy) {
- kfree(wdev);
+ /* create a new wiphy for use with cfg80211 */
+ wiphy = wiphy_new(&mwifiex_cfg80211_ops,
+ sizeof(struct mwifiex_adapter *));
+ if (!wiphy) {
+ dev_err(adapter->dev, "%s: creating new wiphy\n", __func__);
return -ENOMEM;
}
- wdev->iftype = NL80211_IFTYPE_STATION;
- wdev->wiphy->max_scan_ssids = 10;
- wdev->wiphy->max_scan_ie_len = MWIFIEX_MAX_VSIE_LEN;
- wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC);
-
- wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &mwifiex_band_2ghz;
- ht_info = &wdev->wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap;
- mwifiex_setup_ht_caps(ht_info, priv);
-
- if (priv->adapter->config_bands & BAND_A) {
- wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz;
- ht_info = &wdev->wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap;
- mwifiex_setup_ht_caps(ht_info, priv);
- } else {
- wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
- }
+ wiphy->max_scan_ssids = MWIFIEX_MAX_SSID_LIST_LENGTH;
+ wiphy->max_scan_ie_len = MWIFIEX_MAX_VSIE_LEN;
+ wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_AP);
+
+ wiphy->bands[IEEE80211_BAND_2GHZ] = &mwifiex_band_2ghz;
+ if (adapter->config_bands & BAND_A)
+ wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz;
+ else
+ wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
+
+ wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta;
+ wiphy->n_iface_combinations = 1;
/* Initialize cipher suits */
- wdev->wiphy->cipher_suites = mwifiex_cipher_suites;
- wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites);
+ wiphy->cipher_suites = mwifiex_cipher_suites;
+ wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites);
- memcpy(wdev->wiphy->perm_addr, priv->curr_addr, ETH_ALEN);
- wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ memcpy(wiphy->perm_addr, priv->curr_addr, ETH_ALEN);
+ wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+ wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_CUSTOM_REGULATORY;
/* Reserve space for mwifiex specific private data for BSS */
- wdev->wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv);
-
- wdev->wiphy->reg_notifier = mwifiex_reg_notifier;
+ wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv);
- /* Set struct mwifiex_private pointer in wiphy_priv */
- wdev_priv = wiphy_priv(wdev->wiphy);
+ wiphy->reg_notifier = mwifiex_reg_notifier;
- *(unsigned long *) wdev_priv = (unsigned long) priv;
+ /* Set struct mwifiex_adapter pointer in wiphy_priv */
+ wdev_priv = wiphy_priv(wiphy);
+ *(unsigned long *)wdev_priv = (unsigned long)adapter;
- set_wiphy_dev(wdev->wiphy, (struct device *) priv->adapter->dev);
+ set_wiphy_dev(wiphy, (struct device *)priv->adapter->dev);
- ret = wiphy_register(wdev->wiphy);
+ ret = wiphy_register(wiphy);
if (ret < 0) {
- dev_err(priv->adapter->dev, "%s: registering cfg80211 device\n",
- __func__);
- wiphy_free(wdev->wiphy);
- kfree(wdev);
+ dev_err(adapter->dev,
+ "%s: wiphy_register failed: %d\n", __func__, ret);
+ wiphy_free(wiphy);
return ret;
- } else {
- dev_dbg(priv->adapter->dev,
- "info: successfully registered wiphy device\n");
}
-
country_code = mwifiex_11d_code_2_region(priv->adapter->region_code);
- if (country_code && regulatory_hint(wdev->wiphy, country_code))
- dev_err(priv->adapter->dev,
- "%s: regulatory_hint failed\n", __func__);
-
- priv->wdev = wdev;
+ if (country_code && regulatory_hint(wiphy, country_code))
+ dev_err(adapter->dev, "regulatory_hint() failed\n");
+ adapter->wiphy = wiphy;
return ret;
}
diff --git a/drivers/net/wireless/mwifiex/cfg80211.h b/drivers/net/wireless/mwifiex/cfg80211.h
index 76c76c60438b..c5848934f111 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.h
+++ b/drivers/net/wireless/mwifiex/cfg80211.h
@@ -24,6 +24,6 @@
#include "main.h"
-int mwifiex_register_cfg80211(struct mwifiex_private *);
+int mwifiex_register_cfg80211(struct mwifiex_adapter *);
#endif
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index 1710beffb93a..51e023ec1de4 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -440,6 +440,11 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter)
do_gettimeofday(&tstamp);
dev_dbg(adapter->dev, "event: %lu.%lu: cause: %#x\n",
tstamp.tv_sec, tstamp.tv_usec, eventcause);
+ } else {
+ /* Handle PS_SLEEP/AWAKE events on STA */
+ priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
+ if (!priv)
+ priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
}
ret = mwifiex_process_sta_event(priv);
@@ -540,8 +545,20 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
/* Prepare command */
if (cmd_no) {
- ret = mwifiex_sta_prepare_cmd(priv, cmd_no, cmd_action,
- cmd_oid, data_buf, cmd_ptr);
+ switch (cmd_no) {
+ case HostCmd_CMD_UAP_SYS_CONFIG:
+ case HostCmd_CMD_UAP_BSS_START:
+ case HostCmd_CMD_UAP_BSS_STOP:
+ ret = mwifiex_uap_prepare_cmd(priv, cmd_no, cmd_action,
+ cmd_oid, data_buf,
+ cmd_ptr);
+ break;
+ default:
+ ret = mwifiex_sta_prepare_cmd(priv, cmd_no, cmd_action,
+ cmd_oid, data_buf,
+ cmd_ptr);
+ break;
+ }
} else {
ret = mwifiex_cmd_host_cmd(priv, cmd_ptr, data_buf);
cmd_node->cmd_flag |= CMD_F_HOSTCMD;
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h
index d04aba4131dc..f918f66e5e27 100644
--- a/drivers/net/wireless/mwifiex/decl.h
+++ b/drivers/net/wireless/mwifiex/decl.h
@@ -28,7 +28,7 @@
#include <linux/ieee80211.h>
-#define MWIFIEX_MAX_BSS_NUM (1)
+#define MWIFIEX_MAX_BSS_NUM (2)
#define MWIFIEX_MIN_DATA_HEADER_LEN 36 /* sizeof(mwifiex_txpd)
* + 4 byte alignment
@@ -55,11 +55,17 @@
#define MWIFIEX_RX_DATA_BUF_SIZE (4 * 1024)
#define MWIFIEX_RX_CMD_BUF_SIZE (2 * 1024)
+#define MAX_BEACON_PERIOD (4000)
+#define MIN_BEACON_PERIOD (50)
+#define MAX_DTIM_PERIOD (100)
+#define MIN_DTIM_PERIOD (1)
+
#define MWIFIEX_RTS_MIN_VALUE (0)
#define MWIFIEX_RTS_MAX_VALUE (2347)
#define MWIFIEX_FRAG_MIN_VALUE (256)
#define MWIFIEX_FRAG_MAX_VALUE (2346)
+#define MWIFIEX_RETRY_LIMIT 14
#define MWIFIEX_SDIO_BLOCK_SIZE 256
#define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0)
@@ -92,6 +98,11 @@ struct mwifiex_fw_image {
u32 fw_len;
};
+struct mwifiex_802_11_ssid {
+ u32 ssid_len;
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+};
+
struct mwifiex_wait_queue {
wait_queue_head_t wait;
int status;
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 5f6adeb9b950..9f674bbebe65 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -93,6 +93,20 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define CAL_SNR(RSSI, NF) ((s16)((s16)(RSSI)-(s16)(NF)))
+#define UAP_BSS_PARAMS_I 0
+#define UAP_CUSTOM_IE_I 1
+#define MWIFIEX_AUTO_IDX_MASK 0xffff
+#define MWIFIEX_DELETE_MASK 0x0000
+#define MGMT_MASK_ASSOC_REQ 0x01
+#define MGMT_MASK_REASSOC_REQ 0x04
+#define MGMT_MASK_ASSOC_RESP 0x02
+#define MGMT_MASK_REASSOC_RESP 0x08
+#define MGMT_MASK_PROBE_REQ 0x10
+#define MGMT_MASK_PROBE_RESP 0x20
+#define MGMT_MASK_BEACON 0x100
+
+#define TLV_TYPE_UAP_SSID 0x0000
+
#define PROPRIETARY_TLV_BASE_ID 0x0100
#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0)
#define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1)
@@ -104,14 +118,26 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19)
#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22)
#define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31)
+#define TLV_TYPE_STA_MAC_ADDR (PROPRIETARY_TLV_BASE_ID + 32)
#define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 42)
+#define TLV_TYPE_UAP_BEACON_PERIOD (PROPRIETARY_TLV_BASE_ID + 44)
+#define TLV_TYPE_UAP_DTIM_PERIOD (PROPRIETARY_TLV_BASE_ID + 45)
+#define TLV_TYPE_UAP_RTS_THRESHOLD (PROPRIETARY_TLV_BASE_ID + 51)
+#define TLV_TYPE_UAP_WPA_PASSPHRASE (PROPRIETARY_TLV_BASE_ID + 60)
+#define TLV_TYPE_UAP_ENCRY_PROTOCOL (PROPRIETARY_TLV_BASE_ID + 64)
+#define TLV_TYPE_UAP_AKMP (PROPRIETARY_TLV_BASE_ID + 65)
+#define TLV_TYPE_UAP_FRAG_THRESHOLD (PROPRIETARY_TLV_BASE_ID + 70)
#define TLV_TYPE_RATE_DROP_CONTROL (PROPRIETARY_TLV_BASE_ID + 82)
#define TLV_TYPE_RATE_SCOPE (PROPRIETARY_TLV_BASE_ID + 83)
#define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 84)
+#define TLV_TYPE_UAP_RETRY_LIMIT (PROPRIETARY_TLV_BASE_ID + 93)
#define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 94)
+#define TLV_TYPE_UAP_MGMT_FRAME (PROPRIETARY_TLV_BASE_ID + 104)
#define TLV_TYPE_MGMT_IE (PROPRIETARY_TLV_BASE_ID + 105)
#define TLV_TYPE_AUTO_DS_PARAM (PROPRIETARY_TLV_BASE_ID + 113)
#define TLV_TYPE_PS_PARAM (PROPRIETARY_TLV_BASE_ID + 114)
+#define TLV_TYPE_PWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 145)
+#define TLV_TYPE_GWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 146)
#define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048
@@ -209,6 +235,9 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_RSSI_INFO 0x00a4
#define HostCmd_CMD_FUNC_INIT 0x00a9
#define HostCmd_CMD_FUNC_SHUTDOWN 0x00aa
+#define HostCmd_CMD_UAP_SYS_CONFIG 0x00b0
+#define HostCmd_CMD_UAP_BSS_START 0x00b1
+#define HostCmd_CMD_UAP_BSS_STOP 0x00b2
#define HostCmd_CMD_11N_CFG 0x00cd
#define HostCmd_CMD_11N_ADDBA_REQ 0x00ce
#define HostCmd_CMD_11N_ADDBA_RSP 0x00cf
@@ -223,6 +252,19 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_SET_BSS_MODE 0x00f7
#define HostCmd_CMD_PCIE_DESC_DETAILS 0x00fa
+#define PROTOCOL_NO_SECURITY 0x01
+#define PROTOCOL_STATIC_WEP 0x02
+#define PROTOCOL_WPA 0x08
+#define PROTOCOL_WPA2 0x20
+#define PROTOCOL_WPA2_MIXED 0x28
+#define PROTOCOL_EAP 0x40
+#define KEY_MGMT_NONE 0x04
+#define KEY_MGMT_PSK 0x02
+#define KEY_MGMT_EAP 0x01
+#define CIPHER_TKIP 0x04
+#define CIPHER_AES_CCMP 0x08
+#define VALID_CIPHER_BITMAP 0x0c
+
enum ENH_PS_MODES {
EN_PS = 1,
DIS_PS = 2,
@@ -313,15 +355,20 @@ enum ENH_PS_MODES {
#define EVENT_DATA_SNR_HIGH 0x00000027
#define EVENT_LINK_QUALITY 0x00000028
#define EVENT_PORT_RELEASE 0x0000002b
+#define EVENT_UAP_STA_DEAUTH 0x0000002c
+#define EVENT_UAP_STA_ASSOC 0x0000002d
+#define EVENT_UAP_BSS_START 0x0000002e
#define EVENT_PRE_BEACON_LOST 0x00000031
#define EVENT_ADDBA 0x00000033
#define EVENT_DELBA 0x00000034
#define EVENT_BA_STREAM_TIEMOUT 0x00000037
#define EVENT_AMSDU_AGGR_CTRL 0x00000042
+#define EVENT_UAP_BSS_IDLE 0x00000043
+#define EVENT_UAP_BSS_ACTIVE 0x00000044
#define EVENT_WEP_ICV_ERR 0x00000046
#define EVENT_HS_ACT_REQ 0x00000047
#define EVENT_BW_CHANGE 0x00000048
-
+#define EVENT_UAP_MIC_COUNTERMEASURES 0x0000004c
#define EVENT_HOSTWAKE_STAIE 0x0000004d
#define EVENT_ID_MASK 0xffff
@@ -1103,6 +1150,101 @@ struct host_cmd_ds_802_11_eeprom_access {
u8 value;
} __packed;
+struct host_cmd_tlv {
+ __le16 type;
+ __le16 len;
+} __packed;
+
+struct mwifiex_assoc_event {
+ u8 sta_addr[ETH_ALEN];
+ __le16 type;
+ __le16 len;
+ __le16 frame_control;
+ __le16 cap_info;
+ __le16 listen_interval;
+ u8 data[0];
+} __packed;
+
+struct host_cmd_ds_sys_config {
+ __le16 action;
+ u8 tlv[0];
+};
+
+struct host_cmd_tlv_akmp {
+ struct host_cmd_tlv tlv;
+ __le16 key_mgmt;
+ __le16 key_mgmt_operation;
+} __packed;
+
+struct host_cmd_tlv_pwk_cipher {
+ struct host_cmd_tlv tlv;
+ __le16 proto;
+ u8 cipher;
+ u8 reserved;
+} __packed;
+
+struct host_cmd_tlv_gwk_cipher {
+ struct host_cmd_tlv tlv;
+ u8 cipher;
+ u8 reserved;
+} __packed;
+
+struct host_cmd_tlv_passphrase {
+ struct host_cmd_tlv tlv;
+ u8 passphrase[0];
+} __packed;
+
+struct host_cmd_tlv_auth_type {
+ struct host_cmd_tlv tlv;
+ u8 auth_type;
+} __packed;
+
+struct host_cmd_tlv_encrypt_protocol {
+ struct host_cmd_tlv tlv;
+ __le16 proto;
+} __packed;
+
+struct host_cmd_tlv_ssid {
+ struct host_cmd_tlv tlv;
+ u8 ssid[0];
+} __packed;
+
+struct host_cmd_tlv_beacon_period {
+ struct host_cmd_tlv tlv;
+ __le16 period;
+} __packed;
+
+struct host_cmd_tlv_dtim_period {
+ struct host_cmd_tlv tlv;
+ u8 period;
+} __packed;
+
+struct host_cmd_tlv_frag_threshold {
+ struct host_cmd_tlv tlv;
+ __le16 frag_thr;
+} __packed;
+
+struct host_cmd_tlv_rts_threshold {
+ struct host_cmd_tlv tlv;
+ __le16 rts_thr;
+} __packed;
+
+struct host_cmd_tlv_retry_limit {
+ struct host_cmd_tlv tlv;
+ u8 limit;
+} __packed;
+
+struct host_cmd_tlv_mac_addr {
+ struct host_cmd_tlv tlv;
+ u8 mac_addr[ETH_ALEN];
+} __packed;
+
+struct host_cmd_tlv_channel_band {
+ struct host_cmd_tlv tlv;
+ u8 band_config;
+ u8 channel;
+} __packed;
+
struct host_cmd_ds_802_11_rf_channel {
__le16 action;
__le16 current_channel;
@@ -1167,6 +1309,20 @@ struct host_cmd_ds_802_11_subsc_evt {
__le16 events;
} __packed;
+struct mwifiex_ie {
+ __le16 ie_index;
+ __le16 mgmt_subtype_mask;
+ __le16 ie_length;
+ u8 ie_buffer[IEEE_MAX_IE_SIZE];
+} __packed;
+
+#define MAX_MGMT_IE_INDEX 16
+struct mwifiex_ie_list {
+ __le16 type;
+ __le16 len;
+ struct mwifiex_ie ie_list[MAX_MGMT_IE_INDEX];
+} __packed;
+
struct host_cmd_ds_command {
__le16 command;
__le16 size;
@@ -1217,6 +1373,7 @@ struct host_cmd_ds_command {
struct host_cmd_ds_pcie_details pcie_host_spec;
struct host_cmd_ds_802_11_eeprom_access eeprom;
struct host_cmd_ds_802_11_subsc_evt subsc_evt;
+ struct host_cmd_ds_sys_config uap_sys_config;
} params;
} __packed;
diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c
new file mode 100644
index 000000000000..ceb82cd749cc
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/ie.c
@@ -0,0 +1,396 @@
+/*
+ * Marvell Wireless LAN device driver: management IE handling- setting and
+ * deleting IE.
+ *
+ * Copyright (C) 2012, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "main.h"
+
+/* This function checks if current IE index is used by any on other interface.
+ * Return: -1: yes, current IE index is used by someone else.
+ * 0: no, current IE index is NOT used by other interface.
+ */
+static int
+mwifiex_ie_index_used_by_other_intf(struct mwifiex_private *priv, u16 idx)
+{
+ int i;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_ie *ie;
+
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (adapter->priv[i] != priv) {
+ ie = &adapter->priv[i]->mgmt_ie[idx];
+ if (ie->mgmt_subtype_mask && ie->ie_length)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* Get unused IE index. This index will be used for setting new IE */
+static int
+mwifiex_ie_get_autoidx(struct mwifiex_private *priv, u16 subtype_mask,
+ struct mwifiex_ie *ie, u16 *index)
+{
+ u16 mask, len, i;
+
+ for (i = 0; i < priv->adapter->max_mgmt_ie_index; i++) {
+ mask = le16_to_cpu(priv->mgmt_ie[i].mgmt_subtype_mask);
+ len = le16_to_cpu(priv->mgmt_ie[i].ie_length) +
+ le16_to_cpu(ie->ie_length);
+
+ if (mask == MWIFIEX_AUTO_IDX_MASK)
+ continue;
+
+ if (mask == subtype_mask) {
+ if (len > IEEE_MAX_IE_SIZE)
+ continue;
+
+ *index = i;
+ return 0;
+ }
+
+ if (!priv->mgmt_ie[i].ie_length) {
+ if (mwifiex_ie_index_used_by_other_intf(priv, i))
+ continue;
+
+ *index = i;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+/* This function prepares IE data buffer for command to be sent to FW */
+static int
+mwifiex_update_autoindex_ies(struct mwifiex_private *priv,
+ struct mwifiex_ie_list *ie_list)
+{
+ u16 travel_len, index, mask;
+ s16 input_len;
+ struct mwifiex_ie *ie;
+ u8 *tmp;
+
+ input_len = le16_to_cpu(ie_list->len);
+ travel_len = sizeof(struct host_cmd_tlv);
+
+ ie_list->len = 0;
+
+ while (input_len > 0) {
+ ie = (struct mwifiex_ie *)(((u8 *)ie_list) + travel_len);
+ input_len -= le16_to_cpu(ie->ie_length) + MWIFIEX_IE_HDR_SIZE;
+ travel_len += le16_to_cpu(ie->ie_length) + MWIFIEX_IE_HDR_SIZE;
+
+ index = le16_to_cpu(ie->ie_index);
+ mask = le16_to_cpu(ie->mgmt_subtype_mask);
+
+ if (index == MWIFIEX_AUTO_IDX_MASK) {
+ /* automatic addition */
+ if (mwifiex_ie_get_autoidx(priv, mask, ie, &index))
+ return -1;
+ if (index == MWIFIEX_AUTO_IDX_MASK)
+ return -1;
+
+ tmp = (u8 *)&priv->mgmt_ie[index].ie_buffer;
+ tmp += le16_to_cpu(priv->mgmt_ie[index].ie_length);
+ memcpy(tmp, &ie->ie_buffer, le16_to_cpu(ie->ie_length));
+ le16_add_cpu(&priv->mgmt_ie[index].ie_length,
+ le16_to_cpu(ie->ie_length));
+ priv->mgmt_ie[index].ie_index = cpu_to_le16(index);
+ priv->mgmt_ie[index].mgmt_subtype_mask =
+ cpu_to_le16(mask);
+
+ ie->ie_index = cpu_to_le16(index);
+ ie->ie_length = priv->mgmt_ie[index].ie_length;
+ memcpy(&ie->ie_buffer, &priv->mgmt_ie[index].ie_buffer,
+ le16_to_cpu(priv->mgmt_ie[index].ie_length));
+ } else {
+ if (mask != MWIFIEX_DELETE_MASK)
+ return -1;
+ /*
+ * Check if this index is being used on any
+ * other interface.
+ */
+ if (mwifiex_ie_index_used_by_other_intf(priv, index))
+ return -1;
+
+ ie->ie_length = 0;
+ memcpy(&priv->mgmt_ie[index], ie,
+ sizeof(struct mwifiex_ie));
+ }
+
+ le16_add_cpu(&ie_list->len,
+ le16_to_cpu(priv->mgmt_ie[index].ie_length) +
+ MWIFIEX_IE_HDR_SIZE);
+ }
+
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP)
+ return mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG,
+ HostCmd_ACT_GEN_SET,
+ UAP_CUSTOM_IE_I, ie_list);
+
+ return 0;
+}
+
+/* Copy individual custom IEs for beacon, probe response and assoc response
+ * and prepare single structure for IE setting.
+ * This function also updates allocated IE indices from driver.
+ */
+static int
+mwifiex_update_uap_custom_ie(struct mwifiex_private *priv,
+ struct mwifiex_ie *beacon_ie, u16 *beacon_idx,
+ struct mwifiex_ie *pr_ie, u16 *probe_idx,
+ struct mwifiex_ie *ar_ie, u16 *assoc_idx)
+{
+ struct mwifiex_ie_list *ap_custom_ie;
+ u8 *pos;
+ u16 len;
+ int ret;
+
+ ap_custom_ie = kzalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
+ if (!ap_custom_ie)
+ return -ENOMEM;
+
+ ap_custom_ie->type = cpu_to_le16(TLV_TYPE_MGMT_IE);
+ pos = (u8 *)ap_custom_ie->ie_list;
+
+ if (beacon_ie) {
+ len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE +
+ le16_to_cpu(beacon_ie->ie_length);
+ memcpy(pos, beacon_ie, len);
+ pos += len;
+ le16_add_cpu(&ap_custom_ie->len, len);
+ }
+ if (pr_ie) {
+ len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE +
+ le16_to_cpu(pr_ie->ie_length);
+ memcpy(pos, pr_ie, len);
+ pos += len;
+ le16_add_cpu(&ap_custom_ie->len, len);
+ }
+ if (ar_ie) {
+ len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE +
+ le16_to_cpu(ar_ie->ie_length);
+ memcpy(pos, ar_ie, len);
+ pos += len;
+ le16_add_cpu(&ap_custom_ie->len, len);
+ }
+
+ ret = mwifiex_update_autoindex_ies(priv, ap_custom_ie);
+
+ pos = (u8 *)(&ap_custom_ie->ie_list[0].ie_index);
+ if (beacon_ie && *beacon_idx == MWIFIEX_AUTO_IDX_MASK) {
+ /* save beacon ie index after auto-indexing */
+ *beacon_idx = le16_to_cpu(ap_custom_ie->ie_list[0].ie_index);
+ len = sizeof(*beacon_ie) - IEEE_MAX_IE_SIZE +
+ le16_to_cpu(beacon_ie->ie_length);
+ pos += len;
+ }
+ if (pr_ie && le16_to_cpu(pr_ie->ie_index) == MWIFIEX_AUTO_IDX_MASK) {
+ /* save probe resp ie index after auto-indexing */
+ *probe_idx = *((u16 *)pos);
+ len = sizeof(*pr_ie) - IEEE_MAX_IE_SIZE +
+ le16_to_cpu(pr_ie->ie_length);
+ pos += len;
+ }
+ if (ar_ie && le16_to_cpu(ar_ie->ie_index) == MWIFIEX_AUTO_IDX_MASK)
+ /* save assoc resp ie index after auto-indexing */
+ *assoc_idx = *((u16 *)pos);
+
+ return ret;
+}
+
+/* This function parses different IEs- Tail IEs, beacon IEs, probe response IEs,
+ * association response IEs from cfg80211_ap_settings function and sets these IE
+ * to FW.
+ */
+int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
+ struct cfg80211_ap_settings *params)
+{
+ struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL;
+ struct mwifiex_ie *ar_ie = NULL, *rsn_ie = NULL;
+ struct ieee_types_header *ie = NULL;
+ u16 beacon_idx = MWIFIEX_AUTO_IDX_MASK, pr_idx = MWIFIEX_AUTO_IDX_MASK;
+ u16 ar_idx = MWIFIEX_AUTO_IDX_MASK, rsn_idx = MWIFIEX_AUTO_IDX_MASK;
+ u16 mask;
+ int ret = 0;
+
+ if (params->beacon.tail && params->beacon.tail_len) {
+ ie = (void *)cfg80211_find_ie(WLAN_EID_RSN, params->beacon.tail,
+ params->beacon.tail_len);
+ if (ie) {
+ rsn_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
+ if (!rsn_ie)
+ return -ENOMEM;
+
+ rsn_ie->ie_index = cpu_to_le16(rsn_idx);
+ mask = MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP |
+ MGMT_MASK_ASSOC_RESP;
+ rsn_ie->mgmt_subtype_mask = cpu_to_le16(mask);
+ rsn_ie->ie_length = cpu_to_le16(ie->len + 2);
+ memcpy(rsn_ie->ie_buffer, ie, ie->len + 2);
+
+ if (mwifiex_update_uap_custom_ie(priv, rsn_ie, &rsn_idx,
+ NULL, NULL,
+ NULL, NULL)) {
+ ret = -1;
+ goto done;
+ }
+
+ priv->rsn_idx = rsn_idx;
+ }
+ }
+
+ if (params->beacon.beacon_ies && params->beacon.beacon_ies_len) {
+ beacon_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
+ if (!beacon_ie) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ beacon_ie->ie_index = cpu_to_le16(beacon_idx);
+ beacon_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON);
+ beacon_ie->ie_length =
+ cpu_to_le16(params->beacon.beacon_ies_len);
+ memcpy(beacon_ie->ie_buffer, params->beacon.beacon_ies,
+ params->beacon.beacon_ies_len);
+ }
+
+ if (params->beacon.proberesp_ies && params->beacon.proberesp_ies_len) {
+ pr_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
+ if (!pr_ie) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ pr_ie->ie_index = cpu_to_le16(pr_idx);
+ pr_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_PROBE_RESP);
+ pr_ie->ie_length =
+ cpu_to_le16(params->beacon.proberesp_ies_len);
+ memcpy(pr_ie->ie_buffer, params->beacon.proberesp_ies,
+ params->beacon.proberesp_ies_len);
+ }
+
+ if (params->beacon.assocresp_ies && params->beacon.assocresp_ies_len) {
+ ar_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
+ if (!ar_ie) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ ar_ie->ie_index = cpu_to_le16(ar_idx);
+ mask = MGMT_MASK_ASSOC_RESP | MGMT_MASK_REASSOC_RESP;
+ ar_ie->mgmt_subtype_mask = cpu_to_le16(mask);
+ ar_ie->ie_length =
+ cpu_to_le16(params->beacon.assocresp_ies_len);
+ memcpy(ar_ie->ie_buffer, params->beacon.assocresp_ies,
+ params->beacon.assocresp_ies_len);
+ }
+
+ if (beacon_ie || pr_ie || ar_ie) {
+ ret = mwifiex_update_uap_custom_ie(priv, beacon_ie,
+ &beacon_idx, pr_ie,
+ &pr_idx, ar_ie, &ar_idx);
+ if (ret)
+ goto done;
+ }
+
+ priv->beacon_idx = beacon_idx;
+ priv->proberesp_idx = pr_idx;
+ priv->assocresp_idx = ar_idx;
+
+done:
+ kfree(beacon_ie);
+ kfree(pr_ie);
+ kfree(ar_ie);
+ kfree(rsn_ie);
+
+ return ret;
+}
+
+/* This function removes management IE set */
+int mwifiex_del_mgmt_ies(struct mwifiex_private *priv)
+{
+ struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL;
+ struct mwifiex_ie *ar_ie = NULL, *rsn_ie = NULL;
+ int ret = 0;
+
+ if (priv->rsn_idx != MWIFIEX_AUTO_IDX_MASK) {
+ rsn_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
+ if (!rsn_ie)
+ return -ENOMEM;
+
+ rsn_ie->ie_index = cpu_to_le16(priv->rsn_idx);
+ rsn_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
+ rsn_ie->ie_length = 0;
+ if (mwifiex_update_uap_custom_ie(priv, rsn_ie, &priv->rsn_idx,
+ NULL, &priv->proberesp_idx,
+ NULL, &priv->assocresp_idx)) {
+ ret = -1;
+ goto done;
+ }
+
+ priv->rsn_idx = MWIFIEX_AUTO_IDX_MASK;
+ }
+
+ if (priv->beacon_idx != MWIFIEX_AUTO_IDX_MASK) {
+ beacon_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
+ if (!beacon_ie) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ beacon_ie->ie_index = cpu_to_le16(priv->beacon_idx);
+ beacon_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
+ beacon_ie->ie_length = 0;
+ }
+ if (priv->proberesp_idx != MWIFIEX_AUTO_IDX_MASK) {
+ pr_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
+ if (!pr_ie) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pr_ie->ie_index = cpu_to_le16(priv->proberesp_idx);
+ pr_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
+ pr_ie->ie_length = 0;
+ }
+ if (priv->assocresp_idx != MWIFIEX_AUTO_IDX_MASK) {
+ ar_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
+ if (!ar_ie) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ ar_ie->ie_index = cpu_to_le16(priv->assocresp_idx);
+ ar_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
+ ar_ie->ie_length = 0;
+ }
+
+ if (beacon_ie || pr_ie || ar_ie)
+ ret = mwifiex_update_uap_custom_ie(priv,
+ beacon_ie, &priv->beacon_idx,
+ pr_ie, &priv->proberesp_idx,
+ ar_ie, &priv->assocresp_idx);
+
+done:
+ kfree(beacon_ie);
+ kfree(pr_ie);
+ kfree(ar_ie);
+ kfree(rsn_ie);
+
+ return ret;
+}
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index d440c3eb640b..c1cb004db913 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -279,6 +279,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter));
adapter->arp_filter_size = 0;
adapter->channel_type = NL80211_CHAN_HT20;
+ adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX;
}
/*
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h
index f0f95524e96b..e6be6ee75951 100644
--- a/drivers/net/wireless/mwifiex/ioctl.h
+++ b/drivers/net/wireless/mwifiex/ioctl.h
@@ -62,6 +62,36 @@ enum {
BAND_AN = 16,
};
+#define MWIFIEX_WPA_PASSHPHRASE_LEN 64
+struct wpa_param {
+ u8 pairwise_cipher_wpa;
+ u8 pairwise_cipher_wpa2;
+ u8 group_cipher;
+ u32 length;
+ u8 passphrase[MWIFIEX_WPA_PASSHPHRASE_LEN];
+};
+
+#define KEY_MGMT_ON_HOST 0x03
+#define MWIFIEX_AUTH_MODE_AUTO 0xFF
+#define BAND_CONFIG_MANUAL 0x00
+struct mwifiex_uap_bss_param {
+ u8 channel;
+ u8 band_cfg;
+ u16 rts_threshold;
+ u16 frag_threshold;
+ u8 retry_limit;
+ struct mwifiex_802_11_ssid ssid;
+ u8 bcast_ssid_ctl;
+ u8 radio_ctl;
+ u8 dtim_period;
+ u16 beacon_period;
+ u16 auth_mode;
+ u16 protocol;
+ u16 key_mgmt;
+ u16 key_mgmt_operation;
+ struct wpa_param wpa_cfg;
+};
+
enum {
ADHOC_IDLE,
ADHOC_STARTED,
@@ -269,6 +299,8 @@ struct mwifiex_ds_read_eeprom {
#define IEEE_MAX_IE_SIZE 256
+#define MWIFIEX_IE_HDR_SIZE (sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE)
+
struct mwifiex_ds_misc_gen_ie {
u32 type;
u32 len;
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
index 8a390982463e..d6b4fb04011f 100644
--- a/drivers/net/wireless/mwifiex/join.c
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -1374,22 +1374,28 @@ static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, u8 *mac)
*
* In case of infra made, it sends deauthentication request, and
* in case of ad-hoc mode, a stop network request is sent to the firmware.
+ * In AP mode, a command to stop bss is sent to firmware.
*/
int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac)
{
- int ret = 0;
+ if (!priv->media_connected)
+ return 0;
- if (priv->media_connected) {
- if (priv->bss_mode == NL80211_IFTYPE_STATION) {
- ret = mwifiex_deauthenticate_infra(priv, mac);
- } else if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
- ret = mwifiex_send_cmd_sync(priv,
- HostCmd_CMD_802_11_AD_HOC_STOP,
- HostCmd_ACT_GEN_SET, 0, NULL);
- }
+ switch (priv->bss_mode) {
+ case NL80211_IFTYPE_STATION:
+ return mwifiex_deauthenticate_infra(priv, mac);
+ case NL80211_IFTYPE_ADHOC:
+ return mwifiex_send_cmd_sync(priv,
+ HostCmd_CMD_802_11_AD_HOC_STOP,
+ HostCmd_ACT_GEN_SET, 0, NULL);
+ case NL80211_IFTYPE_AP:
+ return mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP,
+ HostCmd_ACT_GEN_SET, 0, NULL);
+ default:
+ break;
}
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(mwifiex_deauthenticate);
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index be0f0e583f75..3192855c31c0 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -64,17 +64,17 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
adapter->priv_num = 0;
- /* Allocate memory for private structure */
- adapter->priv[0] = kzalloc(sizeof(struct mwifiex_private), GFP_KERNEL);
- if (!adapter->priv[0]) {
- dev_err(adapter->dev,
- "%s: failed to alloc priv[0]\n", __func__);
- goto error;
- }
-
- adapter->priv_num++;
+ for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) {
+ /* Allocate memory for private structure */
+ adapter->priv[i] =
+ kzalloc(sizeof(struct mwifiex_private), GFP_KERNEL);
+ if (!adapter->priv[i])
+ goto error;
- adapter->priv[0]->adapter = adapter;
+ adapter->priv[i]->adapter = adapter;
+ adapter->priv[i]->bss_priority = i;
+ adapter->priv_num++;
+ }
mwifiex_init_lock_list(adapter);
init_timer(&adapter->cmd_timer);
@@ -349,19 +349,26 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
if (adapter->hw_status != MWIFIEX_HW_STATUS_READY)
goto done;
- priv = adapter->priv[0];
- if (mwifiex_register_cfg80211(priv) != 0) {
+ priv = adapter->priv[MWIFIEX_BSS_ROLE_STA];
+ if (mwifiex_register_cfg80211(adapter)) {
dev_err(adapter->dev, "cannot register with cfg80211\n");
goto err_init_fw;
}
rtnl_lock();
/* Create station interface by default */
- if (!mwifiex_add_virtual_intf(priv->wdev->wiphy, "mlan%d",
+ if (!mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d",
NL80211_IFTYPE_STATION, NULL, NULL)) {
dev_err(adapter->dev, "cannot create default STA interface\n");
goto err_add_intf;
}
+
+ /* Create AP interface by default */
+ if (!mwifiex_add_virtual_intf(adapter->wiphy, "uap%d",
+ NL80211_IFTYPE_AP, NULL, NULL)) {
+ dev_err(adapter->dev, "cannot create default AP interface\n");
+ goto err_add_intf;
+ }
rtnl_unlock();
mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1);
@@ -369,7 +376,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
goto done;
err_add_intf:
- mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev);
+ mwifiex_del_virtual_intf(adapter->wiphy, priv->netdev);
rtnl_unlock();
err_init_fw:
pr_debug("info: %s: unregister device\n", __func__);
@@ -633,6 +640,12 @@ void mwifiex_init_priv_params(struct mwifiex_private *priv,
priv->current_key_index = 0;
priv->media_connected = false;
memset(&priv->nick_name, 0, sizeof(priv->nick_name));
+ memset(priv->mgmt_ie, 0,
+ sizeof(struct mwifiex_ie) * MAX_MGMT_IE_INDEX);
+ priv->beacon_idx = MWIFIEX_AUTO_IDX_MASK;
+ priv->proberesp_idx = MWIFIEX_AUTO_IDX_MASK;
+ priv->assocresp_idx = MWIFIEX_AUTO_IDX_MASK;
+ priv->rsn_idx = MWIFIEX_AUTO_IDX_MASK;
priv->num_tx_timeout = 0;
memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN);
}
@@ -830,19 +843,21 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
rtnl_lock();
if (priv->wdev && priv->netdev)
- mwifiex_del_virtual_intf(priv->wdev->wiphy,
- priv->netdev);
+ mwifiex_del_virtual_intf(adapter->wiphy, priv->netdev);
rtnl_unlock();
}
priv = adapter->priv[0];
- if (!priv)
+ if (!priv || !priv->wdev)
goto exit_remove;
- if (priv->wdev) {
- wiphy_unregister(priv->wdev->wiphy);
- wiphy_free(priv->wdev->wiphy);
- kfree(priv->wdev);
+ wiphy_unregister(priv->wdev->wiphy);
+ wiphy_free(priv->wdev->wiphy);
+
+ for (i = 0; i < adapter->priv_num; i++) {
+ priv = adapter->priv[i];
+ if (priv)
+ kfree(priv->wdev);
}
mwifiex_terminate_workqueue(adapter);
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 324ad390cacd..bd3b0bf94b9e 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -116,6 +116,7 @@ enum {
#define MAX_FREQUENCY_BAND_BG 2484
#define MWIFIEX_EVENT_HEADER_LEN 4
+#define MWIFIEX_UAP_EVENT_EXTRA_HEADER 2
#define MWIFIEX_TYPE_LEN 4
#define MWIFIEX_USB_TYPE_CMD 0xF00DFACE
@@ -370,6 +371,7 @@ struct mwifiex_private {
u8 bss_role;
u8 bss_priority;
u8 bss_num;
+ u8 bss_started;
u8 frame_type;
u8 curr_addr[ETH_ALEN];
u8 media_connected;
@@ -470,12 +472,16 @@ struct mwifiex_private {
struct cfg80211_scan_request *scan_request;
struct mwifiex_user_scan_cfg *user_scan_cfg;
u8 cfg_bssid[6];
- u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
struct wps wps;
u8 scan_block;
s32 cqm_rssi_thold;
u32 cqm_rssi_hyst;
u8 subsc_evt_rssi_state;
+ struct mwifiex_ie mgmt_ie[MAX_MGMT_IE_INDEX];
+ u16 beacon_idx;
+ u16 proberesp_idx;
+ u16 assocresp_idx;
+ u16 rsn_idx;
};
enum mwifiex_ba_status {
@@ -571,6 +577,7 @@ struct mwifiex_adapter {
char fw_name[32];
int winner;
struct device *dev;
+ struct wiphy *wiphy;
bool surprise_removed;
u32 fw_release_number;
u16 init_wait_q_woken;
@@ -677,6 +684,8 @@ struct mwifiex_adapter {
struct cmd_ctrl_node *cmd_queued;
spinlock_t queue_lock; /* lock for tx queues */
struct completion fw_load;
+ u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
+ u16 max_mgmt_ie_index;
};
int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
@@ -760,6 +769,9 @@ int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter,
int mwifiex_sta_prepare_cmd(struct mwifiex_private *, uint16_t cmd_no,
u16 cmd_action, u32 cmd_oid,
void *data_buf, void *cmd_buf);
+int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
+ u16 cmd_action, u32 cmd_oid,
+ void *data_buf, void *cmd_buf);
int mwifiex_process_sta_cmdresp(struct mwifiex_private *, u16 cmdresp_no,
struct host_cmd_ds_command *resp);
int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *,
@@ -820,6 +832,9 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
int is_command_pending(struct mwifiex_adapter *adapter);
void mwifiex_init_priv_params(struct mwifiex_private *priv,
struct net_device *dev);
+int mwifiex_set_secure_params(struct mwifiex_private *priv,
+ struct mwifiex_uap_bss_param *bss_config,
+ struct cfg80211_ap_settings *params);
/*
* This function checks if the queuing is RA based or not.
@@ -933,7 +948,8 @@ int mwifiex_set_radio(struct mwifiex_private *priv, u8 option);
int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, u16 channel);
int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
- int key_len, u8 key_index, int disable);
+ int key_len, u8 key_index, const u8 *mac_addr,
+ int disable);
int mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len);
@@ -969,6 +985,7 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv,
int mwifiex_main_process(struct mwifiex_adapter *);
+int mwifiex_uap_set_channel(struct mwifiex_private *priv, int channel);
int mwifiex_bss_set_channel(struct mwifiex_private *,
struct mwifiex_chan_freq_power *cfp);
int mwifiex_get_bss_info(struct mwifiex_private *,
@@ -986,6 +1003,11 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
u32 *flags, struct vif_params *params);
int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev);
+void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config);
+
+int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
+ struct cfg80211_ap_settings *params);
+int mwifiex_del_mgmt_ies(struct mwifiex_private *priv);
u8 *mwifiex_11d_code_2_region(u8 code);
#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index 87ed2a1f6cd9..40e025da6bc2 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -498,7 +498,8 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
{
struct host_cmd_ds_802_11_key_material *key_material =
&cmd->params.key_material;
- u16 key_param_len = 0;
+ struct host_cmd_tlv_mac_addr *tlv_mac;
+ u16 key_param_len = 0, cmd_size;
int ret = 0;
const u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@@ -614,11 +615,26 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
cpu_to_le16((u16) enc_key->key_len +
KEYPARAMSET_FIXED_LEN);
- key_param_len = (u16) (enc_key->key_len + KEYPARAMSET_FIXED_LEN)
+ key_param_len = (u16)(enc_key->key_len + KEYPARAMSET_FIXED_LEN)
+ sizeof(struct mwifiex_ie_types_header);
cmd->size = cpu_to_le16(sizeof(key_material->action) + S_DS_GEN
+ key_param_len);
+
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) {
+ tlv_mac = (void *)((u8 *)&key_material->key_param_set +
+ key_param_len);
+ tlv_mac->tlv.type = cpu_to_le16(TLV_TYPE_STA_MAC_ADDR);
+ tlv_mac->tlv.len = cpu_to_le16(ETH_ALEN);
+ memcpy(tlv_mac->mac_addr, enc_key->mac_addr, ETH_ALEN);
+ cmd_size = key_param_len + S_DS_GEN +
+ sizeof(key_material->action) +
+ sizeof(struct host_cmd_tlv_mac_addr);
+ } else {
+ cmd_size = key_param_len + S_DS_GEN +
+ sizeof(key_material->action);
+ }
+ cmd->size = cpu_to_le16(cmd_size);
}
return ret;
@@ -1248,13 +1264,15 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
if (ret)
return -1;
- /* Enable IEEE PS by default */
- priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
- ret = mwifiex_send_cmd_async(priv,
- HostCmd_CMD_802_11_PS_MODE_ENH,
- EN_AUTO_PS, BITMAP_STA_PS, NULL);
- if (ret)
- return -1;
+ if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
+ /* Enable IEEE PS by default */
+ priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
+ ret = mwifiex_send_cmd_async(
+ priv, HostCmd_CMD_802_11_PS_MODE_ENH,
+ EN_AUTO_PS, BITMAP_STA_PS, NULL);
+ if (ret)
+ return -1;
+ }
}
/* get tx rate */
@@ -1270,12 +1288,14 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
if (ret)
return -1;
- /* set ibss coalescing_status */
- ret = mwifiex_send_cmd_async(priv,
- HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
- HostCmd_ACT_GEN_SET, 0, &enable);
- if (ret)
- return -1;
+ if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) {
+ /* set ibss coalescing_status */
+ ret = mwifiex_send_cmd_async(
+ priv, HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
+ HostCmd_ACT_GEN_SET, 0, &enable);
+ if (ret)
+ return -1;
+ }
memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl));
amsdu_aggr_ctrl.enable = true;
@@ -1293,7 +1313,8 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
if (ret)
return -1;
- if (first_sta && (priv->adapter->iface_type != MWIFIEX_USB)) {
+ if (first_sta && priv->adapter->iface_type != MWIFIEX_USB &&
+ priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
/* Enable auto deep sleep */
auto_ds.auto_ds = DEEP_SLEEP_ON;
auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME;
@@ -1305,12 +1326,16 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
return -1;
}
- /* Send cmd to FW to enable/disable 11D function */
- state_11d = ENABLE_11D;
- ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SNMP_MIB,
- HostCmd_ACT_GEN_SET, DOT11D_I, &state_11d);
- if (ret)
- dev_err(priv->adapter->dev, "11D: failed to enable 11D\n");
+ if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
+ /* Send cmd to FW to enable/disable 11D function */
+ state_11d = ENABLE_11D;
+ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, DOT11D_I,
+ &state_11d);
+ if (ret)
+ dev_err(priv->adapter->dev,
+ "11D: failed to enable 11D\n");
+ }
/* Send cmd to FW to configure 11n specific configuration
* (Short GI, Channel BW, Green field support etc.) for transmit
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index 3aa54243dea9..a79ed9bd9695 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -944,6 +944,14 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
case HostCmd_CMD_802_11_SUBSCRIBE_EVENT:
ret = mwifiex_ret_subsc_evt(priv, resp, data_buf);
break;
+ case HostCmd_CMD_UAP_SYS_CONFIG:
+ break;
+ case HostCmd_CMD_UAP_BSS_START:
+ priv->bss_started = 1;
+ break;
+ case HostCmd_CMD_UAP_BSS_STOP:
+ priv->bss_started = 0;
+ break;
default:
dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
resp->command);
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c
index f6bbb9307f86..4ace5a3dcd23 100644
--- a/drivers/net/wireless/mwifiex/sta_event.c
+++ b/drivers/net/wireless/mwifiex/sta_event.c
@@ -184,8 +184,10 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv)
int mwifiex_process_sta_event(struct mwifiex_private *priv)
{
struct mwifiex_adapter *adapter = priv->adapter;
- int ret = 0;
+ int len, ret = 0;
u32 eventcause = adapter->event_cause;
+ struct station_info sinfo;
+ struct mwifiex_assoc_event *event;
switch (eventcause) {
case EVENT_DUMMY_HOST_WAKEUP_SIGNAL:
@@ -402,6 +404,53 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
case EVENT_HOSTWAKE_STAIE:
dev_dbg(adapter->dev, "event: HOSTWAKE_STAIE %d\n", eventcause);
break;
+
+ case EVENT_UAP_STA_ASSOC:
+ skb_pull(adapter->event_skb, MWIFIEX_UAP_EVENT_EXTRA_HEADER);
+ memset(&sinfo, 0, sizeof(sinfo));
+ event = (struct mwifiex_assoc_event *)adapter->event_skb->data;
+ if (le16_to_cpu(event->type) == TLV_TYPE_UAP_MGMT_FRAME) {
+ len = -1;
+
+ if (ieee80211_is_assoc_req(event->frame_control))
+ len = 0;
+ else if (ieee80211_is_reassoc_req(event->frame_control))
+ /* There will be ETH_ALEN bytes of
+ * current_ap_addr before the re-assoc ies.
+ */
+ len = ETH_ALEN;
+
+ if (len != -1) {
+ sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
+ sinfo.assoc_req_ies = (u8 *)&event->data[len];
+ len = (u8 *)sinfo.assoc_req_ies -
+ (u8 *)&event->frame_control;
+ sinfo.assoc_req_ies_len =
+ le16_to_cpu(event->len) - (u16)len;
+ }
+ }
+ cfg80211_new_sta(priv->netdev, event->sta_addr, &sinfo,
+ GFP_KERNEL);
+ break;
+ case EVENT_UAP_STA_DEAUTH:
+ skb_pull(adapter->event_skb, MWIFIEX_UAP_EVENT_EXTRA_HEADER);
+ cfg80211_del_sta(priv->netdev, adapter->event_skb->data,
+ GFP_KERNEL);
+ break;
+ case EVENT_UAP_BSS_IDLE:
+ priv->media_connected = false;
+ break;
+ case EVENT_UAP_BSS_ACTIVE:
+ priv->media_connected = true;
+ break;
+ case EVENT_UAP_BSS_START:
+ dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
+ memcpy(priv->netdev->dev_addr, adapter->event_body+2, ETH_ALEN);
+ break;
+ case EVENT_UAP_MIC_COUNTERMEASURES:
+ /* For future development */
+ dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
+ break;
default:
dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
eventcause);
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 58970e0f7d13..106c449477b2 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -462,7 +462,7 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv,
info->bss_chan = bss_desc->channel;
- memcpy(info->country_code, priv->country_code,
+ memcpy(info->country_code, adapter->country_code,
IEEE80211_COUNTRY_STRING_LEN);
info->media_connected = priv->media_connected;
@@ -1219,7 +1219,8 @@ mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version,
* with requisite parameters and calls the IOCTL handler.
*/
int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
- int key_len, u8 key_index, int disable)
+ int key_len, u8 key_index,
+ const u8 *mac_addr, int disable)
{
struct mwifiex_ds_encrypt_key encrypt_key;
@@ -1229,8 +1230,12 @@ int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
encrypt_key.key_index = key_index;
if (key_len)
memcpy(encrypt_key.key_material, key, key_len);
+ if (mac_addr)
+ memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);
} else {
encrypt_key.key_disable = true;
+ if (mac_addr)
+ memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);
}
return mwifiex_sec_ioctl_encrypt_key(priv, &encrypt_key);
diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c
new file mode 100644
index 000000000000..76dfbc42a732
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/uap_cmd.c
@@ -0,0 +1,432 @@
+/*
+ * Marvell Wireless LAN device driver: AP specific command handling
+ *
+ * Copyright (C) 2012, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "main.h"
+
+/* This function parses security related parameters from cfg80211_ap_settings
+ * and sets into FW understandable bss_config structure.
+ */
+int mwifiex_set_secure_params(struct mwifiex_private *priv,
+ struct mwifiex_uap_bss_param *bss_config,
+ struct cfg80211_ap_settings *params) {
+ int i;
+
+ switch (params->auth_type) {
+ case NL80211_AUTHTYPE_OPEN_SYSTEM:
+ bss_config->auth_mode = WLAN_AUTH_OPEN;
+ break;
+ case NL80211_AUTHTYPE_SHARED_KEY:
+ bss_config->auth_mode = WLAN_AUTH_SHARED_KEY;
+ break;
+ case NL80211_AUTHTYPE_NETWORK_EAP:
+ bss_config->auth_mode = WLAN_AUTH_LEAP;
+ break;
+ default:
+ bss_config->auth_mode = MWIFIEX_AUTH_MODE_AUTO;
+ break;
+ }
+
+ bss_config->key_mgmt_operation |= KEY_MGMT_ON_HOST;
+
+ for (i = 0; i < params->crypto.n_akm_suites; i++) {
+ switch (params->crypto.akm_suites[i]) {
+ case WLAN_AKM_SUITE_8021X:
+ if (params->crypto.wpa_versions &
+ NL80211_WPA_VERSION_1) {
+ bss_config->protocol = PROTOCOL_WPA;
+ bss_config->key_mgmt = KEY_MGMT_EAP;
+ }
+ if (params->crypto.wpa_versions &
+ NL80211_WPA_VERSION_2) {
+ bss_config->protocol = PROTOCOL_WPA2;
+ bss_config->key_mgmt = KEY_MGMT_EAP;
+ }
+ break;
+ case WLAN_AKM_SUITE_PSK:
+ if (params->crypto.wpa_versions &
+ NL80211_WPA_VERSION_1) {
+ bss_config->protocol = PROTOCOL_WPA;
+ bss_config->key_mgmt = KEY_MGMT_PSK;
+ }
+ if (params->crypto.wpa_versions &
+ NL80211_WPA_VERSION_2) {
+ bss_config->protocol = PROTOCOL_WPA2;
+ bss_config->key_mgmt = KEY_MGMT_PSK;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ for (i = 0; i < params->crypto.n_ciphers_pairwise; i++) {
+ switch (params->crypto.ciphers_pairwise[i]) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ bss_config->wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ bss_config->wpa_cfg.pairwise_cipher_wpa2 =
+ CIPHER_AES_CCMP;
+ default:
+ break;
+ }
+ }
+
+ switch (params->crypto.cipher_group) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ bss_config->wpa_cfg.group_cipher = CIPHER_TKIP;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ bss_config->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* This function initializes some of mwifiex_uap_bss_param variables.
+ * This helps FW in ignoring invalid values. These values may or may not
+ * be get updated to valid ones at later stage.
+ */
+void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config)
+{
+ config->bcast_ssid_ctl = 0x7F;
+ config->radio_ctl = 0x7F;
+ config->dtim_period = 0x7F;
+ config->beacon_period = 0x7FFF;
+ config->auth_mode = 0x7F;
+ config->rts_threshold = 0x7FFF;
+ config->frag_threshold = 0x7FFF;
+ config->retry_limit = 0x7F;
+}
+
+/* This function parses BSS related parameters from structure
+ * and prepares TLVs. These TLVs are appended to command buffer.
+*/
+static int
+mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
+{
+ struct host_cmd_tlv_dtim_period *dtim_period;
+ struct host_cmd_tlv_beacon_period *beacon_period;
+ struct host_cmd_tlv_ssid *ssid;
+ struct host_cmd_tlv_channel_band *chan_band;
+ struct host_cmd_tlv_frag_threshold *frag_threshold;
+ struct host_cmd_tlv_rts_threshold *rts_threshold;
+ struct host_cmd_tlv_retry_limit *retry_limit;
+ struct host_cmd_tlv_pwk_cipher *pwk_cipher;
+ struct host_cmd_tlv_gwk_cipher *gwk_cipher;
+ struct host_cmd_tlv_encrypt_protocol *encrypt_protocol;
+ struct host_cmd_tlv_auth_type *auth_type;
+ struct host_cmd_tlv_passphrase *passphrase;
+ struct host_cmd_tlv_akmp *tlv_akmp;
+ struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
+ u16 cmd_size = *param_size;
+
+ if (bss_cfg->ssid.ssid_len) {
+ ssid = (struct host_cmd_tlv_ssid *)tlv;
+ ssid->tlv.type = cpu_to_le16(TLV_TYPE_UAP_SSID);
+ ssid->tlv.len = cpu_to_le16((u16)bss_cfg->ssid.ssid_len);
+ memcpy(ssid->ssid, bss_cfg->ssid.ssid, bss_cfg->ssid.ssid_len);
+ cmd_size += sizeof(struct host_cmd_tlv) +
+ bss_cfg->ssid.ssid_len;
+ tlv += sizeof(struct host_cmd_tlv) + bss_cfg->ssid.ssid_len;
+ }
+ if (bss_cfg->channel && bss_cfg->channel <= MAX_CHANNEL_BAND_BG) {
+ chan_band = (struct host_cmd_tlv_channel_band *)tlv;
+ chan_band->tlv.type = cpu_to_le16(TLV_TYPE_CHANNELBANDLIST);
+ chan_band->tlv.len =
+ cpu_to_le16(sizeof(struct host_cmd_tlv_channel_band) -
+ sizeof(struct host_cmd_tlv));
+ chan_band->band_config = bss_cfg->band_cfg;
+ chan_band->channel = bss_cfg->channel;
+ cmd_size += sizeof(struct host_cmd_tlv_channel_band);
+ tlv += sizeof(struct host_cmd_tlv_channel_band);
+ }
+ if (bss_cfg->beacon_period >= MIN_BEACON_PERIOD &&
+ bss_cfg->beacon_period <= MAX_BEACON_PERIOD) {
+ beacon_period = (struct host_cmd_tlv_beacon_period *)tlv;
+ beacon_period->tlv.type =
+ cpu_to_le16(TLV_TYPE_UAP_BEACON_PERIOD);
+ beacon_period->tlv.len =
+ cpu_to_le16(sizeof(struct host_cmd_tlv_beacon_period) -
+ sizeof(struct host_cmd_tlv));
+ beacon_period->period = cpu_to_le16(bss_cfg->beacon_period);
+ cmd_size += sizeof(struct host_cmd_tlv_beacon_period);
+ tlv += sizeof(struct host_cmd_tlv_beacon_period);
+ }
+ if (bss_cfg->dtim_period >= MIN_DTIM_PERIOD &&
+ bss_cfg->dtim_period <= MAX_DTIM_PERIOD) {
+ dtim_period = (struct host_cmd_tlv_dtim_period *)tlv;
+ dtim_period->tlv.type = cpu_to_le16(TLV_TYPE_UAP_DTIM_PERIOD);
+ dtim_period->tlv.len =
+ cpu_to_le16(sizeof(struct host_cmd_tlv_dtim_period) -
+ sizeof(struct host_cmd_tlv));
+ dtim_period->period = bss_cfg->dtim_period;
+ cmd_size += sizeof(struct host_cmd_tlv_dtim_period);
+ tlv += sizeof(struct host_cmd_tlv_dtim_period);
+ }
+ if (bss_cfg->rts_threshold <= MWIFIEX_RTS_MAX_VALUE) {
+ rts_threshold = (struct host_cmd_tlv_rts_threshold *)tlv;
+ rts_threshold->tlv.type =
+ cpu_to_le16(TLV_TYPE_UAP_RTS_THRESHOLD);
+ rts_threshold->tlv.len =
+ cpu_to_le16(sizeof(struct host_cmd_tlv_rts_threshold) -
+ sizeof(struct host_cmd_tlv));
+ rts_threshold->rts_thr = cpu_to_le16(bss_cfg->rts_threshold);
+ cmd_size += sizeof(struct host_cmd_tlv_frag_threshold);
+ tlv += sizeof(struct host_cmd_tlv_frag_threshold);
+ }
+ if ((bss_cfg->frag_threshold >= MWIFIEX_FRAG_MIN_VALUE) &&
+ (bss_cfg->frag_threshold <= MWIFIEX_FRAG_MAX_VALUE)) {
+ frag_threshold = (struct host_cmd_tlv_frag_threshold *)tlv;
+ frag_threshold->tlv.type =
+ cpu_to_le16(TLV_TYPE_UAP_FRAG_THRESHOLD);
+ frag_threshold->tlv.len =
+ cpu_to_le16(sizeof(struct host_cmd_tlv_frag_threshold) -
+ sizeof(struct host_cmd_tlv));
+ frag_threshold->frag_thr = cpu_to_le16(bss_cfg->frag_threshold);
+ cmd_size += sizeof(struct host_cmd_tlv_frag_threshold);
+ tlv += sizeof(struct host_cmd_tlv_frag_threshold);
+ }
+ if (bss_cfg->retry_limit <= MWIFIEX_RETRY_LIMIT) {
+ retry_limit = (struct host_cmd_tlv_retry_limit *)tlv;
+ retry_limit->tlv.type = cpu_to_le16(TLV_TYPE_UAP_RETRY_LIMIT);
+ retry_limit->tlv.len =
+ cpu_to_le16(sizeof(struct host_cmd_tlv_retry_limit) -
+ sizeof(struct host_cmd_tlv));
+ retry_limit->limit = (u8)bss_cfg->retry_limit;
+ cmd_size += sizeof(struct host_cmd_tlv_retry_limit);
+ tlv += sizeof(struct host_cmd_tlv_retry_limit);
+ }
+ if ((bss_cfg->protocol & PROTOCOL_WPA) ||
+ (bss_cfg->protocol & PROTOCOL_WPA2) ||
+ (bss_cfg->protocol & PROTOCOL_EAP)) {
+ tlv_akmp = (struct host_cmd_tlv_akmp *)tlv;
+ tlv_akmp->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AKMP);
+ tlv_akmp->tlv.len =
+ cpu_to_le16(sizeof(struct host_cmd_tlv_akmp) -
+ sizeof(struct host_cmd_tlv));
+ tlv_akmp->key_mgmt_operation =
+ cpu_to_le16(bss_cfg->key_mgmt_operation);
+ tlv_akmp->key_mgmt = cpu_to_le16(bss_cfg->key_mgmt);
+ cmd_size += sizeof(struct host_cmd_tlv_akmp);
+ tlv += sizeof(struct host_cmd_tlv_akmp);
+
+ if (bss_cfg->wpa_cfg.pairwise_cipher_wpa &
+ VALID_CIPHER_BITMAP) {
+ pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
+ pwk_cipher->tlv.type =
+ cpu_to_le16(TLV_TYPE_PWK_CIPHER);
+ pwk_cipher->tlv.len = cpu_to_le16(
+ sizeof(struct host_cmd_tlv_pwk_cipher) -
+ sizeof(struct host_cmd_tlv));
+ pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA);
+ pwk_cipher->cipher =
+ bss_cfg->wpa_cfg.pairwise_cipher_wpa;
+ cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
+ tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
+ }
+ if (bss_cfg->wpa_cfg.pairwise_cipher_wpa2 &
+ VALID_CIPHER_BITMAP) {
+ pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
+ pwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
+ pwk_cipher->tlv.len = cpu_to_le16(
+ sizeof(struct host_cmd_tlv_pwk_cipher) -
+ sizeof(struct host_cmd_tlv));
+ pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA2);
+ pwk_cipher->cipher =
+ bss_cfg->wpa_cfg.pairwise_cipher_wpa2;
+ cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
+ tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
+ }
+ if (bss_cfg->wpa_cfg.group_cipher & VALID_CIPHER_BITMAP) {
+ gwk_cipher = (struct host_cmd_tlv_gwk_cipher *)tlv;
+ gwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_GWK_CIPHER);
+ gwk_cipher->tlv.len = cpu_to_le16(
+ sizeof(struct host_cmd_tlv_gwk_cipher) -
+ sizeof(struct host_cmd_tlv));
+ gwk_cipher->cipher = bss_cfg->wpa_cfg.group_cipher;
+ cmd_size += sizeof(struct host_cmd_tlv_gwk_cipher);
+ tlv += sizeof(struct host_cmd_tlv_gwk_cipher);
+ }
+ if (bss_cfg->wpa_cfg.length) {
+ passphrase = (struct host_cmd_tlv_passphrase *)tlv;
+ passphrase->tlv.type =
+ cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE);
+ passphrase->tlv.len =
+ cpu_to_le16(bss_cfg->wpa_cfg.length);
+ memcpy(passphrase->passphrase,
+ bss_cfg->wpa_cfg.passphrase,
+ bss_cfg->wpa_cfg.length);
+ cmd_size += sizeof(struct host_cmd_tlv) +
+ bss_cfg->wpa_cfg.length;
+ tlv += sizeof(struct host_cmd_tlv) +
+ bss_cfg->wpa_cfg.length;
+ }
+ }
+ if ((bss_cfg->auth_mode <= WLAN_AUTH_SHARED_KEY) ||
+ (bss_cfg->auth_mode == MWIFIEX_AUTH_MODE_AUTO)) {
+ auth_type = (struct host_cmd_tlv_auth_type *)tlv;
+ auth_type->tlv.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
+ auth_type->tlv.len =
+ cpu_to_le16(sizeof(struct host_cmd_tlv_auth_type) -
+ sizeof(struct host_cmd_tlv));
+ auth_type->auth_type = (u8)bss_cfg->auth_mode;
+ cmd_size += sizeof(struct host_cmd_tlv_auth_type);
+ tlv += sizeof(struct host_cmd_tlv_auth_type);
+ }
+ if (bss_cfg->protocol) {
+ encrypt_protocol = (struct host_cmd_tlv_encrypt_protocol *)tlv;
+ encrypt_protocol->tlv.type =
+ cpu_to_le16(TLV_TYPE_UAP_ENCRY_PROTOCOL);
+ encrypt_protocol->tlv.len =
+ cpu_to_le16(sizeof(struct host_cmd_tlv_encrypt_protocol)
+ - sizeof(struct host_cmd_tlv));
+ encrypt_protocol->proto = cpu_to_le16(bss_cfg->protocol);
+ cmd_size += sizeof(struct host_cmd_tlv_encrypt_protocol);
+ tlv += sizeof(struct host_cmd_tlv_encrypt_protocol);
+ }
+
+ *param_size = cmd_size;
+
+ return 0;
+}
+
+/* This function parses custom IEs from IE list and prepares command buffer */
+static int mwifiex_uap_custom_ie_prepare(u8 *tlv, void *cmd_buf, u16 *ie_size)
+{
+ struct mwifiex_ie_list *ap_ie = cmd_buf;
+ struct host_cmd_tlv *tlv_ie = (struct host_cmd_tlv *)tlv;
+
+ if (!ap_ie || !ap_ie->len || !ap_ie->ie_list)
+ return -1;
+
+ *ie_size += le16_to_cpu(ap_ie->len) + sizeof(struct host_cmd_tlv);
+
+ tlv_ie->type = cpu_to_le16(TLV_TYPE_MGMT_IE);
+ tlv_ie->len = ap_ie->len;
+ tlv += sizeof(struct host_cmd_tlv);
+
+ memcpy(tlv, ap_ie->ie_list, le16_to_cpu(ap_ie->len));
+
+ return 0;
+}
+
+/* Parse AP config structure and prepare TLV based command structure
+ * to be sent to FW for uAP configuration
+ */
+static int
+mwifiex_cmd_uap_sys_config(struct host_cmd_ds_command *cmd, u16 cmd_action,
+ u32 type, void *cmd_buf)
+{
+ u8 *tlv;
+ u16 cmd_size, param_size, ie_size;
+ struct host_cmd_ds_sys_config *sys_cfg;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_UAP_SYS_CONFIG);
+ cmd_size = (u16)(sizeof(struct host_cmd_ds_sys_config) + S_DS_GEN);
+ sys_cfg = (struct host_cmd_ds_sys_config *)&cmd->params.uap_sys_config;
+ sys_cfg->action = cpu_to_le16(cmd_action);
+ tlv = sys_cfg->tlv;
+
+ switch (type) {
+ case UAP_BSS_PARAMS_I:
+ param_size = cmd_size;
+ if (mwifiex_uap_bss_param_prepare(tlv, cmd_buf, &param_size))
+ return -1;
+ cmd->size = cpu_to_le16(param_size);
+ break;
+ case UAP_CUSTOM_IE_I:
+ ie_size = cmd_size;
+ if (mwifiex_uap_custom_ie_prepare(tlv, cmd_buf, &ie_size))
+ return -1;
+ cmd->size = cpu_to_le16(ie_size);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+/* This function prepares the AP specific commands before sending them
+ * to the firmware.
+ * This is a generic function which calls specific command preparation
+ * routines based upon the command number.
+ */
+int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no,
+ u16 cmd_action, u32 type,
+ void *data_buf, void *cmd_buf)
+{
+ struct host_cmd_ds_command *cmd = cmd_buf;
+
+ switch (cmd_no) {
+ case HostCmd_CMD_UAP_SYS_CONFIG:
+ if (mwifiex_cmd_uap_sys_config(cmd, cmd_action, type, data_buf))
+ return -1;
+ break;
+ case HostCmd_CMD_UAP_BSS_START:
+ case HostCmd_CMD_UAP_BSS_STOP:
+ cmd->command = cpu_to_le16(cmd_no);
+ cmd->size = cpu_to_le16(S_DS_GEN);
+ break;
+ default:
+ dev_err(priv->adapter->dev,
+ "PREP_CMD: unknown cmd %#x\n", cmd_no);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* This function sets the RF channel for AP.
+ *
+ * This function populates channel information in AP config structure
+ * and sends command to configure channel information in AP.
+ */
+int mwifiex_uap_set_channel(struct mwifiex_private *priv, int channel)
+{
+ struct mwifiex_uap_bss_param *bss_cfg;
+ struct wiphy *wiphy = priv->wdev->wiphy;
+
+ bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL);
+ if (!bss_cfg)
+ return -ENOMEM;
+
+ bss_cfg->band_cfg = BAND_CONFIG_MANUAL;
+ bss_cfg->channel = channel;
+
+ if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG,
+ HostCmd_ACT_GEN_SET,
+ UAP_BSS_PARAMS_I, bss_cfg)) {
+ wiphy_err(wiphy, "Failed to set the uAP channel\n");
+ kfree(bss_cfg);
+ return -1;
+ }
+
+ kfree(bss_cfg);
+ return 0;
+}
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
index 429a1dee2d26..f3fc65515857 100644
--- a/drivers/net/wireless/mwifiex/wmm.c
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -885,6 +885,10 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
tid_ptr = &(priv_tmp)->wmm.
tid_tbl_ptr[tos_to_tid[i]];
+ /* For non-STA ra_list_curr may be NULL */
+ if (!tid_ptr->ra_list_curr)
+ continue;
+
spin_lock_irqsave(&tid_ptr->tid_tbl_lock,
flags);
is_list_empty =
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c
index f634d4582bfe..7f53cea2f205 100644
--- a/drivers/net/wireless/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/orinoco/orinoco_usb.c
@@ -1752,6 +1752,7 @@ static struct usb_driver orinoco_driver = {
.probe = ezusb_probe,
.disconnect = ezusb_disconnect,
.id_table = ezusb_table,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(orinoco_driver);
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index e1eac830e2fc..7f207b6e9552 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -1140,6 +1140,7 @@ static struct usb_driver p54u_driver = {
.reset_resume = p54u_resume,
#endif /* CONFIG_PM */
.soft_unbind = 1,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(p54u_driver);
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index b91d1bb30b41..2e9e6af21362 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -505,9 +505,6 @@ static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev,
static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev);
-static int rndis_set_channel(struct wiphy *wiphy, struct net_device *dev,
- struct ieee80211_channel *chan, enum nl80211_channel_type channel_type);
-
static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, bool pairwise, const u8 *mac_addr,
struct key_params *params);
@@ -549,7 +546,6 @@ static const struct cfg80211_ops rndis_config_ops = {
.disconnect = rndis_disconnect,
.join_ibss = rndis_join_ibss,
.leave_ibss = rndis_leave_ibss,
- .set_channel = rndis_set_channel,
.add_key = rndis_add_key,
.del_key = rndis_del_key,
.set_default_key = rndis_set_default_key,
@@ -2398,16 +2394,6 @@ static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
return deauthenticate(usbdev);
}
-static int rndis_set_channel(struct wiphy *wiphy, struct net_device *netdev,
- struct ieee80211_channel *chan, enum nl80211_channel_type channel_type)
-{
- struct rndis_wlan_private *priv = wiphy_priv(wiphy);
- struct usbnet *usbdev = priv->usbdev;
-
- return set_channel(usbdev,
- ieee80211_frequency_to_channel(chan->center_freq));
-}
-
static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, bool pairwise, const u8 *mac_addr,
struct key_params *params)
@@ -3765,6 +3751,7 @@ static struct usb_driver rndis_wlan_driver = {
.disconnect = usbnet_disconnect,
.suspend = usbnet_suspend,
.resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(rndis_wlan_driver);
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index c88fd3e61090..669aecdb411d 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1980,6 +1980,7 @@ static struct usb_driver rt2500usb_driver = {
.disconnect = rt2x00usb_disconnect,
.suspend = rt2x00usb_suspend,
.resume = rt2x00usb_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(rt2500usb_driver);
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 931331d95217..cad25bfebd7a 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -1192,6 +1192,7 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
{ PCI_DEVICE(0x1814, 0x5390) },
{ PCI_DEVICE(0x1814, 0x5392) },
{ PCI_DEVICE(0x1814, 0x539a) },
+ { PCI_DEVICE(0x1814, 0x539b) },
{ PCI_DEVICE(0x1814, 0x539f) },
#endif
{ 0, }
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 5601302d09ad..bf78317a6adb 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -1302,6 +1302,7 @@ static struct usb_driver rt2800usb_driver = {
.disconnect = rt2x00usb_disconnect,
.suspend = rt2x00usb_suspend,
.resume = rt2x00usb_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(rt2800usb_driver);
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 155136691a38..77ccbbc7da41 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -2527,6 +2527,7 @@ static struct usb_driver rt73usb_driver = {
.disconnect = rt2x00usb_disconnect,
.suspend = rt2x00usb_suspend,
.resume = rt2x00usb_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(rt73usb_driver);
diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c
index d8114962b0c9..4fb1ca1b86b9 100644
--- a/drivers/net/wireless/rtl818x/rtl8187/dev.c
+++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c
@@ -1663,6 +1663,7 @@ static struct usb_driver rtl8187_driver = {
.id_table = rtl8187_table,
.probe = rtl8187_probe,
.disconnect = __devexit_p(rtl8187_disconnect),
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(rtl8187_driver);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
index 7737fb0c6661..d228358e6a40 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
@@ -373,6 +373,7 @@ static struct usb_driver rtl8192cu_driver = {
#ifdef CONFIG_AUTOSUSPEND
.supports_autosuspend = 1,
#endif
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(rtl8192cu_driver);
diff --git a/drivers/net/wireless/ti/wl12xx/Kconfig b/drivers/net/wireless/ti/wl12xx/Kconfig
index 5b92329122c4..c2183594655a 100644
--- a/drivers/net/wireless/ti/wl12xx/Kconfig
+++ b/drivers/net/wireless/ti/wl12xx/Kconfig
@@ -1,5 +1,6 @@
config WL12XX
tristate "TI wl12xx support"
+ depends on MAC80211
select WLCORE
---help---
This module adds support for wireless adapters based on TI wl1271,
diff --git a/drivers/net/wireless/ti/wlcore/Kconfig b/drivers/net/wireless/ti/wlcore/Kconfig
index 9d04c38938bc..54156b0b5c2d 100644
--- a/drivers/net/wireless/ti/wlcore/Kconfig
+++ b/drivers/net/wireless/ti/wlcore/Kconfig
@@ -1,6 +1,6 @@
config WLCORE
tristate "TI wlcore support"
- depends on WL_TI && GENERIC_HARDIRQS
+ depends on WL_TI && GENERIC_HARDIRQS && MAC80211
depends on INET
select FW_LOADER
---help---
diff --git a/drivers/net/wireless/ti/wlcore/acx.c b/drivers/net/wireless/ti/wlcore/acx.c
index 5912541a925e..509aa881d790 100644
--- a/drivers/net/wireless/ti/wlcore/acx.c
+++ b/drivers/net/wireless/ti/wlcore/acx.c
@@ -1714,3 +1714,83 @@ out:
return ret;
}
+
+/* Set the global behaviour of RX filters - On/Off + default action */
+int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable,
+ enum rx_filter_action action)
+{
+ struct acx_default_rx_filter *acx;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx default rx filter en: %d act: %d",
+ enable, action);
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx)
+ return -ENOMEM;
+
+ acx->enable = enable;
+ acx->default_action = action;
+
+ ret = wl1271_cmd_configure(wl, ACX_ENABLE_RX_DATA_FILTER, acx,
+ sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("acx default rx filter enable failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+/* Configure or disable a specific RX filter pattern */
+int wl1271_acx_set_rx_filter(struct wl1271 *wl, u8 index, bool enable,
+ struct wl12xx_rx_filter *filter)
+{
+ struct acx_rx_filter_cfg *acx;
+ int fields_size = 0;
+ int acx_size;
+ int ret;
+
+ WARN_ON(enable && !filter);
+ WARN_ON(index >= WL1271_MAX_RX_FILTERS);
+
+ wl1271_debug(DEBUG_ACX,
+ "acx set rx filter idx: %d enable: %d filter: %p",
+ index, enable, filter);
+
+ if (enable) {
+ fields_size = wl1271_rx_filter_get_fields_size(filter);
+
+ wl1271_debug(DEBUG_ACX, "act: %d num_fields: %d field_size: %d",
+ filter->action, filter->num_fields, fields_size);
+ }
+
+ acx_size = ALIGN(sizeof(*acx) + fields_size, 4);
+ acx = kzalloc(acx_size, GFP_KERNEL);
+
+ if (!acx)
+ return -ENOMEM;
+
+ acx->enable = enable;
+ acx->index = index;
+
+ if (enable) {
+ acx->num_fields = filter->num_fields;
+ acx->action = filter->action;
+ wl1271_rx_filter_flatten_fields(filter, acx->fields);
+ }
+
+ wl1271_dump(DEBUG_ACX, "RX_FILTER: ", acx, acx_size);
+
+ ret = wl1271_cmd_configure(wl, ACX_SET_RX_DATA_FILTER, acx, acx_size);
+ if (ret < 0) {
+ wl1271_warning("setting rx filter failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
diff --git a/drivers/net/wireless/ti/wlcore/acx.h b/drivers/net/wireless/ti/wlcore/acx.h
index b2f88831b7a9..8106b2ebfe60 100644
--- a/drivers/net/wireless/ti/wlcore/acx.h
+++ b/drivers/net/wireless/ti/wlcore/acx.h
@@ -1147,6 +1147,32 @@ struct wl12xx_acx_config_hangover {
u8 padding[2];
} __packed;
+
+struct acx_default_rx_filter {
+ struct acx_header header;
+ u8 enable;
+
+ /* action of type FILTER_XXX */
+ u8 default_action;
+
+ u8 pad[2];
+} __packed;
+
+
+struct acx_rx_filter_cfg {
+ struct acx_header header;
+
+ u8 enable;
+
+ /* 0 - WL1271_MAX_RX_FILTERS-1 */
+ u8 index;
+
+ u8 action;
+
+ u8 num_fields;
+ u8 fields[0];
+} __packed;
+
enum {
ACX_WAKE_UP_CONDITIONS = 0x0000,
ACX_MEM_CFG = 0x0001,
@@ -1304,5 +1330,9 @@ int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
int wl1271_acx_fm_coex(struct wl1271 *wl);
int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl);
int wl12xx_acx_config_hangover(struct wl1271 *wl);
+int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable,
+ enum rx_filter_action action);
+int wl1271_acx_set_rx_filter(struct wl1271 *wl, u8 index, bool enable,
+ struct wl12xx_rx_filter *filter);
#endif /* __WL1271_ACX_H__ */
diff --git a/drivers/net/wireless/ti/wlcore/boot.c b/drivers/net/wireless/ti/wlcore/boot.c
index 3a2207db5405..9b98230f84ce 100644
--- a/drivers/net/wireless/ti/wlcore/boot.c
+++ b/drivers/net/wireless/ti/wlcore/boot.c
@@ -72,7 +72,7 @@ static int wlcore_boot_fw_version(struct wl1271 *wl)
struct wl1271_static_data *static_data;
int ret;
- static_data = kmalloc(sizeof(*static_data), GFP_DMA);
+ static_data = kmalloc(sizeof(*static_data), GFP_KERNEL | GFP_DMA);
if (!static_data) {
wl1271_error("Couldn't allocate memory for static data!");
return -ENOMEM;
@@ -413,6 +413,7 @@ int wlcore_boot_run_firmware(struct wl1271 *wl)
/* unmask required mbox events */
wl->event_mask = BSS_LOSE_EVENT_ID |
+ REGAINED_BSS_EVENT_ID |
SCAN_COMPLETE_EVENT_ID |
ROLE_STOP_COMPLETE_EVENT_ID |
RSSI_SNR_TRIGGER_0_EVENT_ID |
diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c
index 5c4716c6f040..5b128a971449 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.c
+++ b/drivers/net/wireless/ti/wlcore/cmd.c
@@ -123,7 +123,9 @@ static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask)
unsigned long timeout;
int ret = 0;
- events_vector = kmalloc(sizeof(*events_vector), GFP_DMA);
+ events_vector = kmalloc(sizeof(*events_vector), GFP_KERNEL | GFP_DMA);
+ if (!events_vector)
+ return -ENOMEM;
timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
@@ -1034,7 +1036,7 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif)
skb_reserve(skb, sizeof(*hdr) + WL1271_EXTRA_SPACE_MAX);
tmpl = (struct wl12xx_arp_rsp_template *)skb_put(skb, sizeof(*tmpl));
- memset(tmpl, 0, sizeof(tmpl));
+ memset(tmpl, 0, sizeof(*tmpl));
/* llc layer */
memcpy(tmpl->llc_hdr, rfc1042_header, sizeof(rfc1042_header));
@@ -1083,7 +1085,7 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif)
/* mac80211 header */
hdr = (struct ieee80211_hdr_3addr *)skb_push(skb, sizeof(*hdr));
- memset(hdr, 0, sizeof(hdr));
+ memset(hdr, 0, sizeof(*hdr));
fc = IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS;
if (wlvif->sta.qos)
fc |= IEEE80211_STYPE_QOS_DATA;
diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c
index 292632ddf890..28e2a633c3be 100644
--- a/drivers/net/wireless/ti/wlcore/event.c
+++ b/drivers/net/wireless/ti/wlcore/event.c
@@ -103,7 +103,6 @@ static int wl1271_event_process(struct wl1271 *wl)
struct ieee80211_vif *vif;
struct wl12xx_vif *wlvif;
u32 vector;
- bool beacon_loss = false;
bool disconnect_sta = false;
unsigned long sta_bitmap = 0;
@@ -141,20 +140,23 @@ static int wl1271_event_process(struct wl1271 *wl)
mbox->soft_gemini_sense_info);
/*
- * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon
- * filtering) is enabled. Without PSM, the stack will receive all
- * beacons and can detect beacon loss by itself.
- *
- * As there's possibility that the driver disables PSM before receiving
- * BSS_LOSE_EVENT, beacon loss has to be reported to the stack.
- *
+ * We are HW_MONITOR device. On beacon loss - queue
+ * connection loss work. Cancel it on REGAINED event.
*/
if (vector & BSS_LOSE_EVENT_ID) {
/* TODO: check for multi-role */
+ int delay = wl->conf.conn.synch_fail_thold *
+ wl->conf.conn.bss_lose_timeout;
wl1271_info("Beacon loss detected.");
+ cancel_delayed_work_sync(&wl->connection_loss_work);
+ ieee80211_queue_delayed_work(wl->hw, &wl->connection_loss_work,
+ msecs_to_jiffies(delay));
+ }
- /* indicate to the stack, that beacons have been lost */
- beacon_loss = true;
+ if (vector & REGAINED_BSS_EVENT_ID) {
+ /* TODO: check for multi-role */
+ wl1271_info("Beacon regained.");
+ cancel_delayed_work_sync(&wl->connection_loss_work);
}
if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) {
@@ -257,13 +259,6 @@ static int wl1271_event_process(struct wl1271 *wl)
rcu_read_unlock();
}
}
-
- if (beacon_loss)
- wl12xx_for_each_wlvif_sta(wl, wlvif) {
- vif = wl12xx_wlvif_to_vif(wlvif);
- ieee80211_connection_loss(vif);
- }
-
return 0;
}
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 2b0f987660c6..acef93390d3d 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -1120,6 +1120,7 @@ int wl1271_plt_stop(struct wl1271 *wl)
cancel_work_sync(&wl->recovery_work);
cancel_delayed_work_sync(&wl->elp_work);
cancel_delayed_work_sync(&wl->tx_watchdog_work);
+ cancel_delayed_work_sync(&wl->connection_loss_work);
mutex_lock(&wl->mutex);
wl1271_power_off(wl);
@@ -1261,8 +1262,270 @@ static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
#ifdef CONFIG_PM
+static int
+wl1271_validate_wowlan_pattern(struct cfg80211_wowlan_trig_pkt_pattern *p)
+{
+ int num_fields = 0, in_field = 0, fields_size = 0;
+ int i, pattern_len = 0;
+
+ if (!p->mask) {
+ wl1271_warning("No mask in WoWLAN pattern");
+ return -EINVAL;
+ }
+
+ /*
+ * The pattern is broken up into segments of bytes at different offsets
+ * that need to be checked by the FW filter. Each segment is called
+ * a field in the FW API. We verify that the total number of fields
+ * required for this pattern won't exceed FW limits (8)
+ * as well as the total fields buffer won't exceed the FW limit.
+ * Note that if there's a pattern which crosses Ethernet/IP header
+ * boundary a new field is required.
+ */
+ for (i = 0; i < p->pattern_len; i++) {
+ if (test_bit(i, (unsigned long *)p->mask)) {
+ if (!in_field) {
+ in_field = 1;
+ pattern_len = 1;
+ } else {
+ if (i == WL1271_RX_FILTER_ETH_HEADER_SIZE) {
+ num_fields++;
+ fields_size += pattern_len +
+ RX_FILTER_FIELD_OVERHEAD;
+ pattern_len = 1;
+ } else
+ pattern_len++;
+ }
+ } else {
+ if (in_field) {
+ in_field = 0;
+ fields_size += pattern_len +
+ RX_FILTER_FIELD_OVERHEAD;
+ num_fields++;
+ }
+ }
+ }
+
+ if (in_field) {
+ fields_size += pattern_len + RX_FILTER_FIELD_OVERHEAD;
+ num_fields++;
+ }
+
+ if (num_fields > WL1271_RX_FILTER_MAX_FIELDS) {
+ wl1271_warning("RX Filter too complex. Too many segments");
+ return -EINVAL;
+ }
+
+ if (fields_size > WL1271_RX_FILTER_MAX_FIELDS_SIZE) {
+ wl1271_warning("RX filter pattern is too big");
+ return -E2BIG;
+ }
+
+ return 0;
+}
+
+struct wl12xx_rx_filter *wl1271_rx_filter_alloc(void)
+{
+ return kzalloc(sizeof(struct wl12xx_rx_filter), GFP_KERNEL);
+}
+
+void wl1271_rx_filter_free(struct wl12xx_rx_filter *filter)
+{
+ int i;
+
+ if (filter == NULL)
+ return;
+
+ for (i = 0; i < filter->num_fields; i++)
+ kfree(filter->fields[i].pattern);
+
+ kfree(filter);
+}
+
+int wl1271_rx_filter_alloc_field(struct wl12xx_rx_filter *filter,
+ u16 offset, u8 flags,
+ u8 *pattern, u8 len)
+{
+ struct wl12xx_rx_filter_field *field;
+
+ if (filter->num_fields == WL1271_RX_FILTER_MAX_FIELDS) {
+ wl1271_warning("Max fields per RX filter. can't alloc another");
+ return -EINVAL;
+ }
+
+ field = &filter->fields[filter->num_fields];
+
+ field->pattern = kzalloc(len, GFP_KERNEL);
+ if (!field->pattern) {
+ wl1271_warning("Failed to allocate RX filter pattern");
+ return -ENOMEM;
+ }
+
+ filter->num_fields++;
+
+ field->offset = cpu_to_le16(offset);
+ field->flags = flags;
+ field->len = len;
+ memcpy(field->pattern, pattern, len);
+
+ return 0;
+}
+
+int wl1271_rx_filter_get_fields_size(struct wl12xx_rx_filter *filter)
+{
+ int i, fields_size = 0;
+
+ for (i = 0; i < filter->num_fields; i++)
+ fields_size += filter->fields[i].len +
+ sizeof(struct wl12xx_rx_filter_field) -
+ sizeof(u8 *);
+
+ return fields_size;
+}
+
+void wl1271_rx_filter_flatten_fields(struct wl12xx_rx_filter *filter,
+ u8 *buf)
+{
+ int i;
+ struct wl12xx_rx_filter_field *field;
+
+ for (i = 0; i < filter->num_fields; i++) {
+ field = (struct wl12xx_rx_filter_field *)buf;
+
+ field->offset = filter->fields[i].offset;
+ field->flags = filter->fields[i].flags;
+ field->len = filter->fields[i].len;
+
+ memcpy(&field->pattern, filter->fields[i].pattern, field->len);
+ buf += sizeof(struct wl12xx_rx_filter_field) -
+ sizeof(u8 *) + field->len;
+ }
+}
+
+/*
+ * Allocates an RX filter returned through f
+ * which needs to be freed using rx_filter_free()
+ */
+static int wl1271_convert_wowlan_pattern_to_rx_filter(
+ struct cfg80211_wowlan_trig_pkt_pattern *p,
+ struct wl12xx_rx_filter **f)
+{
+ int i, j, ret = 0;
+ struct wl12xx_rx_filter *filter;
+ u16 offset;
+ u8 flags, len;
+
+ filter = wl1271_rx_filter_alloc();
+ if (!filter) {
+ wl1271_warning("Failed to alloc rx filter");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ i = 0;
+ while (i < p->pattern_len) {
+ if (!test_bit(i, (unsigned long *)p->mask)) {
+ i++;
+ continue;
+ }
+
+ for (j = i; j < p->pattern_len; j++) {
+ if (!test_bit(j, (unsigned long *)p->mask))
+ break;
+
+ if (i < WL1271_RX_FILTER_ETH_HEADER_SIZE &&
+ j >= WL1271_RX_FILTER_ETH_HEADER_SIZE)
+ break;
+ }
+
+ if (i < WL1271_RX_FILTER_ETH_HEADER_SIZE) {
+ offset = i;
+ flags = WL1271_RX_FILTER_FLAG_ETHERNET_HEADER;
+ } else {
+ offset = i - WL1271_RX_FILTER_ETH_HEADER_SIZE;
+ flags = WL1271_RX_FILTER_FLAG_IP_HEADER;
+ }
+
+ len = j - i;
+
+ ret = wl1271_rx_filter_alloc_field(filter,
+ offset,
+ flags,
+ &p->pattern[i], len);
+ if (ret)
+ goto err;
+
+ i = j;
+ }
+
+ filter->action = FILTER_SIGNAL;
+
+ *f = filter;
+ return 0;
+
+err:
+ wl1271_rx_filter_free(filter);
+ *f = NULL;
+
+ return ret;
+}
+
+static int wl1271_configure_wowlan(struct wl1271 *wl,
+ struct cfg80211_wowlan *wow)
+{
+ int i, ret;
+
+ if (!wow || wow->any || !wow->n_patterns) {
+ wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL);
+ wl1271_rx_filter_clear_all(wl);
+ return 0;
+ }
+
+ if (WARN_ON(wow->n_patterns > WL1271_MAX_RX_FILTERS))
+ return -EINVAL;
+
+ /* Validate all incoming patterns before clearing current FW state */
+ for (i = 0; i < wow->n_patterns; i++) {
+ ret = wl1271_validate_wowlan_pattern(&wow->patterns[i]);
+ if (ret) {
+ wl1271_warning("Bad wowlan pattern %d", i);
+ return ret;
+ }
+ }
+
+ wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL);
+ wl1271_rx_filter_clear_all(wl);
+
+ /* Translate WoWLAN patterns into filters */
+ for (i = 0; i < wow->n_patterns; i++) {
+ struct cfg80211_wowlan_trig_pkt_pattern *p;
+ struct wl12xx_rx_filter *filter = NULL;
+
+ p = &wow->patterns[i];
+
+ ret = wl1271_convert_wowlan_pattern_to_rx_filter(p, &filter);
+ if (ret) {
+ wl1271_warning("Failed to create an RX filter from "
+ "wowlan pattern %d", i);
+ goto out;
+ }
+
+ ret = wl1271_rx_filter_enable(wl, i, 1, filter);
+
+ wl1271_rx_filter_free(filter);
+ if (ret)
+ goto out;
+ }
+
+ ret = wl1271_acx_default_rx_filter_enable(wl, 1, FILTER_DROP);
+
+out:
+ return ret;
+}
+
static int wl1271_configure_suspend_sta(struct wl1271 *wl,
- struct wl12xx_vif *wlvif)
+ struct wl12xx_vif *wlvif,
+ struct cfg80211_wowlan *wow)
{
int ret = 0;
@@ -1273,6 +1536,7 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
if (ret < 0)
goto out;
+ wl1271_configure_wowlan(wl, wow);
ret = wl1271_acx_wake_up_conditions(wl, wlvif,
wl->conf.conn.suspend_wake_up_event,
wl->conf.conn.suspend_listen_interval);
@@ -1308,10 +1572,11 @@ out:
}
static int wl1271_configure_suspend(struct wl1271 *wl,
- struct wl12xx_vif *wlvif)
+ struct wl12xx_vif *wlvif,
+ struct cfg80211_wowlan *wow)
{
if (wlvif->bss_type == BSS_TYPE_STA_BSS)
- return wl1271_configure_suspend_sta(wl, wlvif);
+ return wl1271_configure_suspend_sta(wl, wlvif, wow);
if (wlvif->bss_type == BSS_TYPE_AP_BSS)
return wl1271_configure_suspend_ap(wl, wlvif);
return 0;
@@ -1332,6 +1597,8 @@ static void wl1271_configure_resume(struct wl1271 *wl,
return;
if (is_sta) {
+ wl1271_configure_wowlan(wl, NULL);
+
ret = wl1271_acx_wake_up_conditions(wl, wlvif,
wl->conf.conn.wake_up_event,
wl->conf.conn.listen_interval);
@@ -1355,15 +1622,16 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
int ret;
wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
- WARN_ON(!wow || !wow->any);
+ WARN_ON(!wow);
wl1271_tx_flush(wl);
mutex_lock(&wl->mutex);
wl->wow_enabled = true;
wl12xx_for_each_wlvif(wl, wlvif) {
- ret = wl1271_configure_suspend(wl, wlvif);
+ ret = wl1271_configure_suspend(wl, wlvif, wow);
if (ret < 0) {
+ mutex_unlock(&wl->mutex);
wl1271_warning("couldn't prepare device to suspend");
return ret;
}
@@ -1487,6 +1755,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
cancel_work_sync(&wl->tx_work);
cancel_delayed_work_sync(&wl->elp_work);
cancel_delayed_work_sync(&wl->tx_watchdog_work);
+ cancel_delayed_work_sync(&wl->connection_loss_work);
/* let's notify MAC80211 about the remaining pending TX frames */
wl12xx_tx_reset(wl, true);
@@ -3439,6 +3708,9 @@ sta_not_found:
do_join = true;
set_assoc = true;
+ /* Cancel connection_loss_work */
+ cancel_delayed_work_sync(&wl->connection_loss_work);
+
/*
* use basic rates from AP, and determine lowest rate
* to use with control frames.
@@ -4549,6 +4821,34 @@ static struct bin_attribute fwlog_attr = {
.read = wl1271_sysfs_read_fwlog,
};
+static void wl1271_connection_loss_work(struct work_struct *work)
+{
+ struct delayed_work *dwork;
+ struct wl1271 *wl;
+ struct ieee80211_vif *vif;
+ struct wl12xx_vif *wlvif;
+
+ dwork = container_of(work, struct delayed_work, work);
+ wl = container_of(dwork, struct wl1271, connection_loss_work);
+
+ wl1271_info("Connection loss work.");
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state == WL1271_STATE_OFF))
+ goto out;
+
+ /* Call mac80211 connection loss */
+ wl12xx_for_each_wlvif_sta(wl, wlvif) {
+ if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
+ goto out;
+ vif = wl12xx_wlvif_to_vif(wlvif);
+ ieee80211_connection_loss(vif);
+ }
+out:
+ mutex_unlock(&wl->mutex);
+}
+
static void wl12xx_derive_mac_addresses(struct wl1271 *wl,
u32 oui, u32 nic, int n)
{
@@ -4804,6 +5104,8 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size)
INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
INIT_DELAYED_WORK(&wl->tx_watchdog_work, wl12xx_tx_watchdog_work);
+ INIT_DELAYED_WORK(&wl->connection_loss_work,
+ wl1271_connection_loss_work);
wl->freezable_wq = create_freezable_workqueue("wl12xx_wq");
if (!wl->freezable_wq) {
@@ -4861,7 +5163,7 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size)
goto err_dummy_packet;
}
- wl->mbox = kmalloc(sizeof(*wl->mbox), GFP_DMA);
+ wl->mbox = kmalloc(sizeof(*wl->mbox), GFP_KERNEL | GFP_DMA);
if (!wl->mbox) {
ret = -ENOMEM;
goto err_fwlog;
@@ -5003,9 +5305,14 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev)
if (!ret) {
wl->irq_wake_enabled = true;
device_init_wakeup(wl->dev, 1);
- if (pdata->pwr_in_suspend)
+ if (pdata->pwr_in_suspend) {
wl->hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
-
+ wl->hw->wiphy->wowlan.n_patterns =
+ WL1271_MAX_RX_FILTERS;
+ wl->hw->wiphy->wowlan.pattern_min_len = 1;
+ wl->hw->wiphy->wowlan.pattern_max_len =
+ WL1271_RX_FILTER_MAX_PATTERN_SIZE;
+ }
}
disable_irq(wl->irq);
diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c
index 89bd9385e90b..1f1d9488dfb6 100644
--- a/drivers/net/wireless/ti/wlcore/rx.c
+++ b/drivers/net/wireless/ti/wlcore/rx.c
@@ -278,3 +278,39 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status)
wl12xx_rearm_rx_streaming(wl, active_hlids);
}
+
+int wl1271_rx_filter_enable(struct wl1271 *wl,
+ int index, bool enable,
+ struct wl12xx_rx_filter *filter)
+{
+ int ret;
+
+ if (wl->rx_filter_enabled[index] == enable) {
+ wl1271_warning("Request to enable an already "
+ "enabled rx filter %d", index);
+ return 0;
+ }
+
+ ret = wl1271_acx_set_rx_filter(wl, index, enable, filter);
+
+ if (ret) {
+ wl1271_error("Failed to %s rx data filter %d (err=%d)",
+ enable ? "enable" : "disable", index, ret);
+ return ret;
+ }
+
+ wl->rx_filter_enabled[index] = enable;
+
+ return 0;
+}
+
+void wl1271_rx_filter_clear_all(struct wl1271 *wl)
+{
+ int i;
+
+ for (i = 0; i < WL1271_MAX_RX_FILTERS; i++) {
+ if (!wl->rx_filter_enabled[i])
+ continue;
+ wl1271_rx_filter_enable(wl, i, 0, NULL);
+ }
+}
diff --git a/drivers/net/wireless/ti/wlcore/rx.h b/drivers/net/wireless/ti/wlcore/rx.h
index 6e129e2a8546..e9a162a864ca 100644
--- a/drivers/net/wireless/ti/wlcore/rx.h
+++ b/drivers/net/wireless/ti/wlcore/rx.h
@@ -138,5 +138,9 @@ struct wl1271_rx_descriptor {
void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status);
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
+int wl1271_rx_filter_enable(struct wl1271 *wl,
+ int index, bool enable,
+ struct wl12xx_rx_filter *filter);
+void wl1271_rx_filter_clear_all(struct wl1271 *wl);
#endif
diff --git a/drivers/net/wireless/ti/wlcore/wl12xx.h b/drivers/net/wireless/ti/wlcore/wl12xx.h
index a9b220c43e54..f12bdf745180 100644
--- a/drivers/net/wireless/ti/wlcore/wl12xx.h
+++ b/drivers/net/wireless/ti/wlcore/wl12xx.h
@@ -279,6 +279,39 @@ struct wl1271_link {
u8 ba_bitmap;
};
+#define WL1271_MAX_RX_FILTERS 5
+#define WL1271_RX_FILTER_MAX_FIELDS 8
+
+#define WL1271_RX_FILTER_ETH_HEADER_SIZE 14
+#define WL1271_RX_FILTER_MAX_FIELDS_SIZE 95
+#define RX_FILTER_FIELD_OVERHEAD \
+ (sizeof(struct wl12xx_rx_filter_field) - sizeof(u8 *))
+#define WL1271_RX_FILTER_MAX_PATTERN_SIZE \
+ (WL1271_RX_FILTER_MAX_FIELDS_SIZE - RX_FILTER_FIELD_OVERHEAD)
+
+#define WL1271_RX_FILTER_FLAG_MASK BIT(0)
+#define WL1271_RX_FILTER_FLAG_IP_HEADER 0
+#define WL1271_RX_FILTER_FLAG_ETHERNET_HEADER BIT(1)
+
+enum rx_filter_action {
+ FILTER_DROP = 0,
+ FILTER_SIGNAL = 1,
+ FILTER_FW_HANDLE = 2
+};
+
+struct wl12xx_rx_filter_field {
+ __le16 offset;
+ u8 len;
+ u8 flags;
+ u8 *pattern;
+} __packed;
+
+struct wl12xx_rx_filter {
+ u8 action;
+ int num_fields;
+ struct wl12xx_rx_filter_field fields[WL1271_RX_FILTER_MAX_FIELDS];
+};
+
struct wl1271_station {
u8 hlid;
};
@@ -439,6 +472,14 @@ int wl1271_plt_stop(struct wl1271 *wl);
int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif);
void wl12xx_queue_recovery_work(struct wl1271 *wl);
size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen);
+int wl1271_rx_filter_alloc_field(struct wl12xx_rx_filter *filter,
+ u16 offset, u8 flags,
+ u8 *pattern, u8 len);
+void wl1271_rx_filter_free(struct wl12xx_rx_filter *filter);
+struct wl12xx_rx_filter *wl1271_rx_filter_alloc(void);
+int wl1271_rx_filter_get_fields_size(struct wl12xx_rx_filter *filter);
+void wl1271_rx_filter_flatten_fields(struct wl12xx_rx_filter *filter,
+ u8 *buf);
#define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index 39f9fadfebd9..0b3f0b586f4b 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -243,6 +243,9 @@ struct wl1271 {
struct wl1271_scan scan;
struct delayed_work scan_complete_work;
+ /* Connection loss work */
+ struct delayed_work connection_loss_work;
+
bool sched_scanning;
/* The current band */
@@ -349,6 +352,9 @@ struct wl1271 {
/* size of the private FW status data */
size_t fw_status_priv_len;
+
+ /* RX Data filter rule state - enabled/disabled */
+ bool rx_filter_enabled[WL1271_MAX_RX_FILTERS];
};
int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev);
diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
index a66b93b7ff9a..48273dd05b63 100644
--- a/drivers/net/wireless/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -1905,6 +1905,7 @@ static struct usb_driver zd1201_usb = {
.id_table = zd1201_table,
.suspend = zd1201_suspend,
.resume = zd1201_resume,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(zd1201_usb);
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index f766b3e67c6d..af83c43bcdb1 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -1542,6 +1542,7 @@ static struct usb_driver driver = {
.disconnect = disconnect,
.pre_reset = pre_reset,
.post_reset = post_reset,
+ .disable_hub_initiated_lpm = 1,
};
struct workqueue_struct *zd_workqueue;
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 0ebbb1906c30..2027afe405fe 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -1962,9 +1962,6 @@ static int __init netif_init(void)
if (!xen_domain())
return -ENODEV;
- if (xen_initial_domain())
- return 0;
-
if (xen_hvm_domain() && !xen_platform_pci_unplug)
return -ENODEV;
@@ -1977,9 +1974,6 @@ module_init(netif_init);
static void __exit netif_exit(void)
{
- if (xen_initial_domain())
- return;
-
xenbus_unregister_driver(&netfront_driver);
}
module_exit(netif_exit);
diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
index 5af959274d4e..3b20b73ee649 100644
--- a/drivers/nfc/Kconfig
+++ b/drivers/nfc/Kconfig
@@ -17,6 +17,19 @@ config PN544_NFC
To compile this driver as a module, choose m here. The module will
be called pn544.
+config PN544_HCI_NFC
+ tristate "HCI PN544 NFC driver"
+ depends on I2C && NFC_SHDLC
+ select CRC_CCITT
+ default n
+ ---help---
+ NXP PN544 i2c driver.
+ This is a driver based on the SHDLC and HCI NFC kernel layers and
+ will thus not work with NXP libnfc library.
+
+ To compile this driver as a module, choose m here. The module will
+ be called pn544_hci.
+
config NFC_PN533
tristate "NXP PN533 USB driver"
depends on USB
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
index ab99e8572f02..473e44cef612 100644
--- a/drivers/nfc/Makefile
+++ b/drivers/nfc/Makefile
@@ -3,6 +3,7 @@
#
obj-$(CONFIG_PN544_NFC) += pn544.o
+obj-$(CONFIG_PN544_HCI_NFC) += pn544_hci.o
obj-$(CONFIG_NFC_PN533) += pn533.o
obj-$(CONFIG_NFC_WILINK) += nfcwilink.o
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index e6ec16d92e65..19110f0eb15f 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -394,9 +394,6 @@ static void pn533_wq_cmd_complete(struct work_struct *work)
struct pn533_frame *in_frame;
int rc;
- if (dev == NULL)
- return;
-
in_frame = dev->wq_in_frame;
if (dev->wq_in_error)
@@ -1194,8 +1191,8 @@ static int pn533_activate_target_nfcdep(struct pn533 *dev)
return rc;
}
-static int pn533_activate_target(struct nfc_dev *nfc_dev, u32 target_idx,
- u32 protocol)
+static int pn533_activate_target(struct nfc_dev *nfc_dev,
+ struct nfc_target *target, u32 protocol)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
int rc;
@@ -1243,7 +1240,8 @@ static int pn533_activate_target(struct nfc_dev *nfc_dev, u32 target_idx,
return 0;
}
-static void pn533_deactivate_target(struct nfc_dev *nfc_dev, u32 target_idx)
+static void pn533_deactivate_target(struct nfc_dev *nfc_dev,
+ struct nfc_target *target)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
u8 tg;
@@ -1351,7 +1349,7 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg,
return 0;
}
-static int pn533_dep_link_up(struct nfc_dev *nfc_dev, int target_idx,
+static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
u8 comm_mode, u8* gb, size_t gb_len)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
@@ -1552,10 +1550,9 @@ error:
return 0;
}
-static int pn533_data_exchange(struct nfc_dev *nfc_dev, u32 target_idx,
- struct sk_buff *skb,
- data_exchange_cb_t cb,
- void *cb_context)
+static int pn533_data_exchange(struct nfc_dev *nfc_dev,
+ struct nfc_target *target, struct sk_buff *skb,
+ data_exchange_cb_t cb, void *cb_context)
{
struct pn533 *dev = nfc_get_drvdata(nfc_dev);
struct pn533_frame *out_frame, *in_frame;
diff --git a/drivers/nfc/pn544_hci.c b/drivers/nfc/pn544_hci.c
new file mode 100644
index 000000000000..46f4a9f9f5e4
--- /dev/null
+++ b/drivers/nfc/pn544_hci.c
@@ -0,0 +1,947 @@
+/*
+ * HCI based Driver for NXP PN544 NFC Chip
+ *
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/crc-ccitt.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+
+#include <linux/nfc.h>
+#include <net/nfc/hci.h>
+#include <net/nfc/shdlc.h>
+
+#include <linux/nfc/pn544.h>
+
+#define DRIVER_DESC "HCI NFC driver for PN544"
+
+#define PN544_HCI_DRIVER_NAME "pn544_hci"
+
+/* Timing restrictions (ms) */
+#define PN544_HCI_RESETVEN_TIME 30
+
+static struct i2c_device_id pn544_hci_id_table[] = {
+ {"pn544", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, pn544_hci_id_table);
+
+#define HCI_MODE 0
+#define FW_MODE 1
+
+/* framing in HCI mode */
+#define PN544_HCI_LLC_LEN 1
+#define PN544_HCI_LLC_CRC 2
+#define PN544_HCI_LLC_LEN_CRC (PN544_HCI_LLC_LEN + PN544_HCI_LLC_CRC)
+#define PN544_HCI_LLC_MIN_SIZE (1 + PN544_HCI_LLC_LEN_CRC)
+#define PN544_HCI_LLC_MAX_PAYLOAD 29
+#define PN544_HCI_LLC_MAX_SIZE (PN544_HCI_LLC_LEN_CRC + 1 + \
+ PN544_HCI_LLC_MAX_PAYLOAD)
+
+enum pn544_state {
+ PN544_ST_COLD,
+ PN544_ST_FW_READY,
+ PN544_ST_READY,
+};
+
+#define FULL_VERSION_LEN 11
+
+/* Proprietary commands */
+#define PN544_WRITE 0x3f
+
+/* Proprietary gates, events, commands and registers */
+
+/* NFC_HCI_RF_READER_A_GATE additional registers and commands */
+#define PN544_RF_READER_A_AUTO_ACTIVATION 0x10
+#define PN544_RF_READER_A_CMD_CONTINUE_ACTIVATION 0x12
+#define PN544_MIFARE_CMD 0x21
+
+/* Commands that apply to all RF readers */
+#define PN544_RF_READER_CMD_PRESENCE_CHECK 0x30
+#define PN544_RF_READER_CMD_ACTIVATE_NEXT 0x32
+
+/* NFC_HCI_ID_MGMT_GATE additional registers */
+#define PN544_ID_MGMT_FULL_VERSION_SW 0x10
+
+#define PN544_RF_READER_ISO15693_GATE 0x12
+
+#define PN544_RF_READER_F_GATE 0x14
+#define PN544_FELICA_ID 0x04
+#define PN544_FELICA_RAW 0x20
+
+#define PN544_RF_READER_JEWEL_GATE 0x15
+#define PN544_JEWEL_RAW_CMD 0x23
+
+#define PN544_RF_READER_NFCIP1_INITIATOR_GATE 0x30
+#define PN544_RF_READER_NFCIP1_TARGET_GATE 0x31
+
+#define PN544_SYS_MGMT_GATE 0x90
+#define PN544_SYS_MGMT_INFO_NOTIFICATION 0x02
+
+#define PN544_POLLING_LOOP_MGMT_GATE 0x94
+#define PN544_PL_RDPHASES 0x06
+#define PN544_PL_EMULATION 0x07
+#define PN544_PL_NFCT_DEACTIVATED 0x09
+
+#define PN544_SWP_MGMT_GATE 0xA0
+
+#define PN544_NFC_WI_MGMT_GATE 0xA1
+
+static u8 pn544_custom_gates[] = {
+ PN544_SYS_MGMT_GATE,
+ PN544_SWP_MGMT_GATE,
+ PN544_POLLING_LOOP_MGMT_GATE,
+ PN544_NFC_WI_MGMT_GATE,
+ PN544_RF_READER_F_GATE,
+ PN544_RF_READER_JEWEL_GATE,
+ PN544_RF_READER_ISO15693_GATE,
+ PN544_RF_READER_NFCIP1_INITIATOR_GATE,
+ PN544_RF_READER_NFCIP1_TARGET_GATE
+};
+
+/* Largest headroom needed for outgoing custom commands */
+#define PN544_CMDS_HEADROOM 2
+
+struct pn544_hci_info {
+ struct i2c_client *i2c_dev;
+ struct nfc_shdlc *shdlc;
+
+ enum pn544_state state;
+
+ struct mutex info_lock;
+
+ unsigned int gpio_en;
+ unsigned int gpio_irq;
+ unsigned int gpio_fw;
+ unsigned int en_polarity;
+
+ int hard_fault; /*
+ * < 0 if hardware error occured (e.g. i2c err)
+ * and prevents normal operation.
+ */
+};
+
+static void pn544_hci_platform_init(struct pn544_hci_info *info)
+{
+ int polarity, retry, ret;
+ char rset_cmd[] = { 0x05, 0xF9, 0x04, 0x00, 0xC3, 0xE5 };
+ int count = sizeof(rset_cmd);
+
+ pr_info(DRIVER_DESC ": %s\n", __func__);
+ dev_info(&info->i2c_dev->dev, "Detecting nfc_en polarity\n");
+
+ /* Disable fw download */
+ gpio_set_value(info->gpio_fw, 0);
+
+ for (polarity = 0; polarity < 2; polarity++) {
+ info->en_polarity = polarity;
+ retry = 3;
+ while (retry--) {
+ /* power off */
+ gpio_set_value(info->gpio_en, !info->en_polarity);
+ usleep_range(10000, 15000);
+
+ /* power on */
+ gpio_set_value(info->gpio_en, info->en_polarity);
+ usleep_range(10000, 15000);
+
+ /* send reset */
+ dev_dbg(&info->i2c_dev->dev, "Sending reset cmd\n");
+ ret = i2c_master_send(info->i2c_dev, rset_cmd, count);
+ if (ret == count) {
+ dev_info(&info->i2c_dev->dev,
+ "nfc_en polarity : active %s\n",
+ (polarity == 0 ? "low" : "high"));
+ goto out;
+ }
+ }
+ }
+
+ dev_err(&info->i2c_dev->dev,
+ "Could not detect nfc_en polarity, fallback to active high\n");
+
+out:
+ gpio_set_value(info->gpio_en, !info->en_polarity);
+}
+
+static int pn544_hci_enable(struct pn544_hci_info *info, int mode)
+{
+ pr_info(DRIVER_DESC ": %s\n", __func__);
+
+ gpio_set_value(info->gpio_fw, 0);
+ gpio_set_value(info->gpio_en, info->en_polarity);
+ usleep_range(10000, 15000);
+
+ return 0;
+}
+
+static void pn544_hci_disable(struct pn544_hci_info *info)
+{
+ pr_info(DRIVER_DESC ": %s\n", __func__);
+
+ gpio_set_value(info->gpio_fw, 0);
+ gpio_set_value(info->gpio_en, !info->en_polarity);
+ usleep_range(10000, 15000);
+
+ gpio_set_value(info->gpio_en, info->en_polarity);
+ usleep_range(10000, 15000);
+
+ gpio_set_value(info->gpio_en, !info->en_polarity);
+ usleep_range(10000, 15000);
+}
+
+static int pn544_hci_i2c_write(struct i2c_client *client, u8 *buf, int len)
+{
+ int r;
+
+ usleep_range(3000, 6000);
+
+ r = i2c_master_send(client, buf, len);
+
+ if (r == -EREMOTEIO) { /* Retry, chip was in standby */
+ usleep_range(6000, 10000);
+ r = i2c_master_send(client, buf, len);
+ }
+
+ if (r >= 0 && r != len)
+ r = -EREMOTEIO;
+
+ return r;
+}
+
+static int check_crc(u8 *buf, int buflen)
+{
+ u8 len;
+ u16 crc;
+
+ len = buf[0] + 1;
+ crc = crc_ccitt(0xffff, buf, len - 2);
+ crc = ~crc;
+
+ if (buf[len - 2] != (crc & 0xff) || buf[len - 1] != (crc >> 8)) {
+ pr_err(PN544_HCI_DRIVER_NAME ": CRC error 0x%x != 0x%x 0x%x\n",
+ crc, buf[len - 1], buf[len - 2]);
+
+ pr_info(DRIVER_DESC ": %s : BAD CRC\n", __func__);
+ print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE,
+ 16, 2, buf, buflen, false);
+ return -EPERM;
+ }
+ return 0;
+}
+
+/*
+ * Reads an shdlc frame and returns it in a newly allocated sk_buff. Guarantees
+ * that i2c bus will be flushed and that next read will start on a new frame.
+ * returned skb contains only LLC header and payload.
+ * returns:
+ * -EREMOTEIO : i2c read error (fatal)
+ * -EBADMSG : frame was incorrect and discarded
+ * -ENOMEM : cannot allocate skb, frame dropped
+ */
+static int pn544_hci_i2c_read(struct i2c_client *client, struct sk_buff **skb)
+{
+ int r;
+ u8 len;
+ u8 tmp[PN544_HCI_LLC_MAX_SIZE - 1];
+
+ r = i2c_master_recv(client, &len, 1);
+ if (r != 1) {
+ dev_err(&client->dev, "cannot read len byte\n");
+ return -EREMOTEIO;
+ }
+
+ if ((len < (PN544_HCI_LLC_MIN_SIZE - 1)) ||
+ (len > (PN544_HCI_LLC_MAX_SIZE - 1))) {
+ dev_err(&client->dev, "invalid len byte\n");
+ r = -EBADMSG;
+ goto flush;
+ }
+
+ *skb = alloc_skb(1 + len, GFP_KERNEL);
+ if (*skb == NULL) {
+ r = -ENOMEM;
+ goto flush;
+ }
+
+ *skb_put(*skb, 1) = len;
+
+ r = i2c_master_recv(client, skb_put(*skb, len), len);
+ if (r != len) {
+ kfree_skb(*skb);
+ return -EREMOTEIO;
+ }
+
+ r = check_crc((*skb)->data, (*skb)->len);
+ if (r != 0) {
+ kfree_skb(*skb);
+ r = -EBADMSG;
+ goto flush;
+ }
+
+ skb_pull(*skb, 1);
+ skb_trim(*skb, (*skb)->len - 2);
+
+ usleep_range(3000, 6000);
+
+ return 0;
+
+flush:
+ if (i2c_master_recv(client, tmp, sizeof(tmp)) < 0)
+ r = -EREMOTEIO;
+
+ usleep_range(3000, 6000);
+
+ return r;
+}
+
+/*
+ * Reads an shdlc frame from the chip. This is not as straightforward as it
+ * seems. There are cases where we could loose the frame start synchronization.
+ * The frame format is len-data-crc, and corruption can occur anywhere while
+ * transiting on i2c bus, such that we could read an invalid len.
+ * In order to recover synchronization with the next frame, we must be sure
+ * to read the real amount of data without using the len byte. We do this by
+ * assuming the following:
+ * - the chip will always present only one single complete frame on the bus
+ * before triggering the interrupt
+ * - the chip will not present a new frame until we have completely read
+ * the previous one (or until we have handled the interrupt).
+ * The tricky case is when we read a corrupted len that is less than the real
+ * len. We must detect this here in order to determine that we need to flush
+ * the bus. This is the reason why we check the crc here.
+ */
+static irqreturn_t pn544_hci_irq_thread_fn(int irq, void *dev_id)
+{
+ struct pn544_hci_info *info = dev_id;
+ struct i2c_client *client = info->i2c_dev;
+ struct sk_buff *skb = NULL;
+ int r;
+
+ BUG_ON(!info);
+ BUG_ON(irq != info->i2c_dev->irq);
+
+ dev_dbg(&client->dev, "IRQ\n");
+
+ if (info->hard_fault != 0)
+ return IRQ_HANDLED;
+
+ r = pn544_hci_i2c_read(client, &skb);
+ if (r == -EREMOTEIO) {
+ info->hard_fault = r;
+
+ nfc_shdlc_recv_frame(info->shdlc, NULL);
+
+ return IRQ_HANDLED;
+ } else if ((r == -ENOMEM) || (r == -EBADMSG)) {
+ return IRQ_HANDLED;
+ }
+
+ nfc_shdlc_recv_frame(info->shdlc, skb);
+
+ return IRQ_HANDLED;
+}
+
+static int pn544_hci_open(struct nfc_shdlc *shdlc)
+{
+ struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc);
+ int r = 0;
+
+ mutex_lock(&info->info_lock);
+
+ if (info->state != PN544_ST_COLD) {
+ r = -EBUSY;
+ goto out;
+ }
+
+ r = pn544_hci_enable(info, HCI_MODE);
+
+out:
+ mutex_unlock(&info->info_lock);
+ return r;
+}
+
+static void pn544_hci_close(struct nfc_shdlc *shdlc)
+{
+ struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc);
+
+ mutex_lock(&info->info_lock);
+
+ if (info->state == PN544_ST_COLD)
+ goto out;
+
+ pn544_hci_disable(info);
+
+out:
+ mutex_unlock(&info->info_lock);
+}
+
+static int pn544_hci_ready(struct nfc_shdlc *shdlc)
+{
+ struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc);
+ struct sk_buff *skb;
+ static struct hw_config {
+ u8 adr[2];
+ u8 value;
+ } hw_config[] = {
+ {{0x9f, 0x9a}, 0x00},
+
+ {{0x98, 0x10}, 0xbc},
+
+ {{0x9e, 0x71}, 0x00},
+
+ {{0x98, 0x09}, 0x00},
+
+ {{0x9e, 0xb4}, 0x00},
+
+ {{0x9e, 0xd9}, 0xff},
+ {{0x9e, 0xda}, 0xff},
+ {{0x9e, 0xdb}, 0x23},
+ {{0x9e, 0xdc}, 0x21},
+ {{0x9e, 0xdd}, 0x22},
+ {{0x9e, 0xde}, 0x24},
+
+ {{0x9c, 0x01}, 0x08},
+
+ {{0x9e, 0xaa}, 0x01},
+
+ {{0x9b, 0xd1}, 0x0d},
+ {{0x9b, 0xd2}, 0x24},
+ {{0x9b, 0xd3}, 0x0a},
+ {{0x9b, 0xd4}, 0x22},
+ {{0x9b, 0xd5}, 0x08},
+ {{0x9b, 0xd6}, 0x1e},
+ {{0x9b, 0xdd}, 0x1c},
+
+ {{0x9b, 0x84}, 0x13},
+ {{0x99, 0x81}, 0x7f},
+ {{0x99, 0x31}, 0x70},
+
+ {{0x98, 0x00}, 0x3f},
+
+ {{0x9f, 0x09}, 0x00},
+
+ {{0x9f, 0x0a}, 0x05},
+
+ {{0x9e, 0xd1}, 0xa1},
+ {{0x99, 0x23}, 0x00},
+
+ {{0x9e, 0x74}, 0x80},
+
+ {{0x9f, 0x28}, 0x10},
+
+ {{0x9f, 0x35}, 0x14},
+
+ {{0x9f, 0x36}, 0x60},
+
+ {{0x9c, 0x31}, 0x00},
+
+ {{0x9c, 0x32}, 0xc8},
+
+ {{0x9c, 0x19}, 0x40},
+
+ {{0x9c, 0x1a}, 0x40},
+
+ {{0x9c, 0x0c}, 0x00},
+
+ {{0x9c, 0x0d}, 0x00},
+
+ {{0x9c, 0x12}, 0x00},
+
+ {{0x9c, 0x13}, 0x00},
+
+ {{0x98, 0xa2}, 0x0e},
+
+ {{0x98, 0x93}, 0x40},
+
+ {{0x98, 0x7d}, 0x02},
+ {{0x98, 0x7e}, 0x00},
+ {{0x9f, 0xc8}, 0x01},
+ };
+ struct hw_config *p = hw_config;
+ int count = ARRAY_SIZE(hw_config);
+ struct sk_buff *res_skb;
+ u8 param[4];
+ int r;
+
+ param[0] = 0;
+ while (count--) {
+ param[1] = p->adr[0];
+ param[2] = p->adr[1];
+ param[3] = p->value;
+
+ r = nfc_hci_send_cmd(hdev, PN544_SYS_MGMT_GATE, PN544_WRITE,
+ param, 4, &res_skb);
+ if (r < 0)
+ return r;
+
+ if (res_skb->len != 1) {
+ kfree_skb(res_skb);
+ return -EPROTO;
+ }
+
+ if (res_skb->data[0] != p->value) {
+ kfree_skb(res_skb);
+ return -EIO;
+ }
+
+ kfree_skb(res_skb);
+
+ p++;
+ }
+
+ param[0] = NFC_HCI_UICC_HOST_ID;
+ r = nfc_hci_set_param(hdev, NFC_HCI_ADMIN_GATE,
+ NFC_HCI_ADMIN_WHITELIST, param, 1);
+ if (r < 0)
+ return r;
+
+ param[0] = 0x3d;
+ r = nfc_hci_set_param(hdev, PN544_SYS_MGMT_GATE,
+ PN544_SYS_MGMT_INFO_NOTIFICATION, param, 1);
+ if (r < 0)
+ return r;
+
+ param[0] = 0x0;
+ r = nfc_hci_set_param(hdev, NFC_HCI_RF_READER_A_GATE,
+ PN544_RF_READER_A_AUTO_ACTIVATION, param, 1);
+ if (r < 0)
+ return r;
+
+ r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
+ NFC_HCI_EVT_END_OPERATION, NULL, 0);
+ if (r < 0)
+ return r;
+
+ param[0] = 0x1;
+ r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
+ PN544_PL_NFCT_DEACTIVATED, param, 1);
+ if (r < 0)
+ return r;
+
+ param[0] = 0x0;
+ r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
+ PN544_PL_RDPHASES, param, 1);
+ if (r < 0)
+ return r;
+
+ r = nfc_hci_get_param(hdev, NFC_HCI_ID_MGMT_GATE,
+ PN544_ID_MGMT_FULL_VERSION_SW, &skb);
+ if (r < 0)
+ return r;
+
+ if (skb->len != FULL_VERSION_LEN) {
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+
+ print_hex_dump(KERN_DEBUG, "FULL VERSION SOFTWARE INFO: ",
+ DUMP_PREFIX_NONE, 16, 1,
+ skb->data, FULL_VERSION_LEN, false);
+
+ kfree_skb(skb);
+
+ return 0;
+}
+
+static int pn544_hci_xmit(struct nfc_shdlc *shdlc, struct sk_buff *skb)
+{
+ struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc);
+ struct i2c_client *client = info->i2c_dev;
+
+ if (info->hard_fault != 0)
+ return info->hard_fault;
+
+ return pn544_hci_i2c_write(client, skb->data, skb->len);
+}
+
+static int pn544_hci_start_poll(struct nfc_shdlc *shdlc, u32 protocols)
+{
+ struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc);
+ u8 phases = 0;
+ int r;
+ u8 duration[2];
+ u8 activated;
+
+ pr_info(DRIVER_DESC ": %s protocols = %d\n", __func__, protocols);
+
+ r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
+ NFC_HCI_EVT_END_OPERATION, NULL, 0);
+ if (r < 0)
+ return r;
+
+ duration[0] = 0x18;
+ duration[1] = 0x6a;
+ r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
+ PN544_PL_EMULATION, duration, 2);
+ if (r < 0)
+ return r;
+
+ activated = 0;
+ r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
+ PN544_PL_NFCT_DEACTIVATED, &activated, 1);
+ if (r < 0)
+ return r;
+
+ if (protocols & (NFC_PROTO_ISO14443_MASK | NFC_PROTO_MIFARE_MASK |
+ NFC_PROTO_JEWEL_MASK))
+ phases |= 1; /* Type A */
+ if (protocols & NFC_PROTO_FELICA_MASK) {
+ phases |= (1 << 2); /* Type F 212 */
+ phases |= (1 << 3); /* Type F 424 */
+ }
+
+ phases |= (1 << 5); /* NFC active */
+
+ r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
+ PN544_PL_RDPHASES, &phases, 1);
+ if (r < 0)
+ return r;
+
+ r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
+ NFC_HCI_EVT_READER_REQUESTED, NULL, 0);
+ if (r < 0)
+ nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
+ NFC_HCI_EVT_END_OPERATION, NULL, 0);
+
+ return r;
+}
+
+static int pn544_hci_target_from_gate(struct nfc_shdlc *shdlc, u8 gate,
+ struct nfc_target *target)
+{
+ switch (gate) {
+ case PN544_RF_READER_F_GATE:
+ target->supported_protocols = NFC_PROTO_FELICA_MASK;
+ break;
+ case PN544_RF_READER_JEWEL_GATE:
+ target->supported_protocols = NFC_PROTO_JEWEL_MASK;
+ target->sens_res = 0x0c00;
+ break;
+ default:
+ return -EPROTO;
+ }
+
+ return 0;
+}
+
+static int pn544_hci_complete_target_discovered(struct nfc_shdlc *shdlc,
+ u8 gate,
+ struct nfc_target *target)
+{
+ struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc);
+ struct sk_buff *uid_skb;
+ int r = 0;
+
+ if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) {
+ if (target->nfcid1_len != 4 && target->nfcid1_len != 7 &&
+ target->nfcid1_len != 10)
+ return -EPROTO;
+
+ r = nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE,
+ PN544_RF_READER_CMD_ACTIVATE_NEXT,
+ target->nfcid1, target->nfcid1_len, NULL);
+ } else if (target->supported_protocols & NFC_PROTO_FELICA_MASK) {
+ r = nfc_hci_get_param(hdev, PN544_RF_READER_F_GATE,
+ PN544_FELICA_ID, &uid_skb);
+ if (r < 0)
+ return r;
+
+ if (uid_skb->len != 8) {
+ kfree_skb(uid_skb);
+ return -EPROTO;
+ }
+
+ r = nfc_hci_send_cmd(hdev, PN544_RF_READER_F_GATE,
+ PN544_RF_READER_CMD_ACTIVATE_NEXT,
+ uid_skb->data, uid_skb->len, NULL);
+ kfree_skb(uid_skb);
+ } else if (target->supported_protocols & NFC_PROTO_ISO14443_MASK) {
+ /*
+ * TODO: maybe other ISO 14443 require some kind of continue
+ * activation, but for now we've seen only this one below.
+ */
+ if (target->sens_res == 0x4403) /* Type 4 Mifare DESFire */
+ r = nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE,
+ PN544_RF_READER_A_CMD_CONTINUE_ACTIVATION,
+ NULL, 0, NULL);
+ }
+
+ return r;
+}
+
+#define MIFARE_CMD_AUTH_KEY_A 0x60
+#define MIFARE_CMD_AUTH_KEY_B 0x61
+#define MIFARE_CMD_HEADER 2
+#define MIFARE_UID_LEN 4
+#define MIFARE_KEY_LEN 6
+#define MIFARE_CMD_LEN 12
+/*
+ * Returns:
+ * <= 0: driver handled the data exchange
+ * 1: driver doesn't especially handle, please do standard processing
+ */
+static int pn544_hci_data_exchange(struct nfc_shdlc *shdlc,
+ struct nfc_target *target,
+ struct sk_buff *skb,
+ struct sk_buff **res_skb)
+{
+ struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc);
+ int r;
+
+ pr_info(DRIVER_DESC ": %s for gate=%d\n", __func__,
+ target->hci_reader_gate);
+
+ switch (target->hci_reader_gate) {
+ case NFC_HCI_RF_READER_A_GATE:
+ if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) {
+ /*
+ * It seems that pn544 is inverting key and UID for
+ * MIFARE authentication commands.
+ */
+ if (skb->len == MIFARE_CMD_LEN &&
+ (skb->data[0] == MIFARE_CMD_AUTH_KEY_A ||
+ skb->data[0] == MIFARE_CMD_AUTH_KEY_B)) {
+ u8 uid[MIFARE_UID_LEN];
+ u8 *data = skb->data + MIFARE_CMD_HEADER;
+
+ memcpy(uid, data + MIFARE_KEY_LEN,
+ MIFARE_UID_LEN);
+ memmove(data + MIFARE_UID_LEN, data,
+ MIFARE_KEY_LEN);
+ memcpy(data, uid, MIFARE_UID_LEN);
+ }
+
+ return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
+ PN544_MIFARE_CMD,
+ skb->data, skb->len, res_skb);
+ } else
+ return 1;
+ case PN544_RF_READER_F_GATE:
+ *skb_push(skb, 1) = 0;
+ *skb_push(skb, 1) = 0;
+
+ r = nfc_hci_send_cmd(hdev, target->hci_reader_gate,
+ PN544_FELICA_RAW,
+ skb->data, skb->len, res_skb);
+ if (r == 0)
+ skb_pull(*res_skb, 1);
+ return r;
+ case PN544_RF_READER_JEWEL_GATE:
+ return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
+ PN544_JEWEL_RAW_CMD,
+ skb->data, skb->len, res_skb);
+ default:
+ return 1;
+ }
+}
+
+static int pn544_hci_check_presence(struct nfc_shdlc *shdlc,
+ struct nfc_target *target)
+{
+ struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc);
+
+ return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
+ PN544_RF_READER_CMD_PRESENCE_CHECK,
+ NULL, 0, NULL);
+}
+
+static struct nfc_shdlc_ops pn544_shdlc_ops = {
+ .open = pn544_hci_open,
+ .close = pn544_hci_close,
+ .hci_ready = pn544_hci_ready,
+ .xmit = pn544_hci_xmit,
+ .start_poll = pn544_hci_start_poll,
+ .target_from_gate = pn544_hci_target_from_gate,
+ .complete_target_discovered = pn544_hci_complete_target_discovered,
+ .data_exchange = pn544_hci_data_exchange,
+ .check_presence = pn544_hci_check_presence,
+};
+
+static int __devinit pn544_hci_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct pn544_hci_info *info;
+ struct pn544_nfc_platform_data *pdata;
+ int r = 0;
+ u32 protocols;
+ struct nfc_hci_init_data init_data;
+
+ dev_dbg(&client->dev, "%s\n", __func__);
+ dev_dbg(&client->dev, "IRQ: %d\n", client->irq);
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "Need I2C_FUNC_I2C\n");
+ return -ENODEV;
+ }
+
+ info = kzalloc(sizeof(struct pn544_hci_info), GFP_KERNEL);
+ if (!info) {
+ dev_err(&client->dev,
+ "Cannot allocate memory for pn544_hci_info.\n");
+ r = -ENOMEM;
+ goto err_info_alloc;
+ }
+
+ info->i2c_dev = client;
+ info->state = PN544_ST_COLD;
+ mutex_init(&info->info_lock);
+ i2c_set_clientdata(client, info);
+
+ pdata = client->dev.platform_data;
+ if (pdata == NULL) {
+ dev_err(&client->dev, "No platform data\n");
+ r = -EINVAL;
+ goto err_pdata;
+ }
+
+ if (pdata->request_resources == NULL) {
+ dev_err(&client->dev, "request_resources() missing\n");
+ r = -EINVAL;
+ goto err_pdata;
+ }
+
+ r = pdata->request_resources(client);
+ if (r) {
+ dev_err(&client->dev, "Cannot get platform resources\n");
+ goto err_pdata;
+ }
+
+ info->gpio_en = pdata->get_gpio(NFC_GPIO_ENABLE);
+ info->gpio_fw = pdata->get_gpio(NFC_GPIO_FW_RESET);
+ info->gpio_irq = pdata->get_gpio(NFC_GPIO_IRQ);
+
+ pn544_hci_platform_init(info);
+
+ r = request_threaded_irq(client->irq, NULL, pn544_hci_irq_thread_fn,
+ IRQF_TRIGGER_RISING, PN544_HCI_DRIVER_NAME,
+ info);
+ if (r < 0) {
+ dev_err(&client->dev, "Unable to register IRQ handler\n");
+ goto err_rti;
+ }
+
+ init_data.gate_count = ARRAY_SIZE(pn544_custom_gates);
+
+ memcpy(init_data.gates, pn544_custom_gates,
+ ARRAY_SIZE(pn544_custom_gates));
+
+ /*
+ * TODO: Session id must include the driver name + some bus addr
+ * persistent info to discriminate 2 identical chips
+ */
+ strcpy(init_data.session_id, "ID544HCI");
+
+ protocols = NFC_PROTO_JEWEL_MASK |
+ NFC_PROTO_MIFARE_MASK |
+ NFC_PROTO_FELICA_MASK |
+ NFC_PROTO_ISO14443_MASK |
+ NFC_PROTO_NFC_DEP_MASK;
+
+ info->shdlc = nfc_shdlc_allocate(&pn544_shdlc_ops,
+ &init_data, protocols,
+ PN544_CMDS_HEADROOM, 0,
+ PN544_HCI_LLC_MAX_PAYLOAD,
+ dev_name(&client->dev));
+ if (!info->shdlc) {
+ dev_err(&client->dev, "Cannot allocate nfc shdlc.\n");
+ r = -ENOMEM;
+ goto err_allocshdlc;
+ }
+
+ nfc_shdlc_set_clientdata(info->shdlc, info);
+
+ return 0;
+
+err_allocshdlc:
+ free_irq(client->irq, info);
+
+err_rti:
+ if (pdata->free_resources != NULL)
+ pdata->free_resources();
+
+err_pdata:
+ kfree(info);
+
+err_info_alloc:
+ return r;
+}
+
+static __devexit int pn544_hci_remove(struct i2c_client *client)
+{
+ struct pn544_hci_info *info = i2c_get_clientdata(client);
+ struct pn544_nfc_platform_data *pdata = client->dev.platform_data;
+
+ dev_dbg(&client->dev, "%s\n", __func__);
+
+ nfc_shdlc_free(info->shdlc);
+
+ if (info->state != PN544_ST_COLD) {
+ if (pdata->disable)
+ pdata->disable();
+ }
+
+ free_irq(client->irq, info);
+ if (pdata->free_resources)
+ pdata->free_resources();
+
+ kfree(info);
+
+ return 0;
+}
+
+static struct i2c_driver pn544_hci_driver = {
+ .driver = {
+ .name = PN544_HCI_DRIVER_NAME,
+ },
+ .probe = pn544_hci_probe,
+ .id_table = pn544_hci_id_table,
+ .remove = __devexit_p(pn544_hci_remove),
+};
+
+static int __init pn544_hci_init(void)
+{
+ int r;
+
+ pr_debug(DRIVER_DESC ": %s\n", __func__);
+
+ r = i2c_add_driver(&pn544_hci_driver);
+ if (r) {
+ pr_err(PN544_HCI_DRIVER_NAME ": driver registration failed\n");
+ return r;
+ }
+
+ return 0;
+}
+
+static void __exit pn544_hci_exit(void)
+{
+ i2c_del_driver(&pn544_hci_driver);
+}
+
+module_init(pn544_hci_init);
+module_exit(pn544_hci_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 8e84ce9765a9..dfba3e64d595 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -51,12 +51,6 @@ config OF_IRQ
config OF_DEVICE
def_bool y
-config OF_GPIO
- def_bool y
- depends on GPIOLIB && !SPARC
- help
- OpenFirmware GPIO accessors
-
config OF_I2C
def_tristate I2C
depends on I2C && !SPARC
@@ -67,12 +61,6 @@ config OF_NET
depends on NETDEVICES
def_bool y
-config OF_SPI
- def_tristate SPI
- depends on SPI && !SPARC
- help
- OpenFirmware SPI accessors
-
config OF_MDIO
def_tristate PHYLIB
depends on PHYLIB
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index aa90e602c8a7..e027f444d10c 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -4,10 +4,8 @@ obj-$(CONFIG_OF_PROMTREE) += pdt.o
obj-$(CONFIG_OF_ADDRESS) += address.o
obj-$(CONFIG_OF_IRQ) += irq.o
obj-$(CONFIG_OF_DEVICE) += device.o platform.o
-obj-$(CONFIG_OF_GPIO) += gpio.o
obj-$(CONFIG_OF_I2C) += of_i2c.o
obj-$(CONFIG_OF_NET) += of_net.o
-obj-$(CONFIG_OF_SPI) += of_spi.o
obj-$(CONFIG_OF_SELFTEST) += selftest.o
obj-$(CONFIG_OF_MDIO) += of_mdio.o
obj-$(CONFIG_OF_PCI) += of_pci.o
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 66d96f14c274..7e262a6124c5 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -1,4 +1,5 @@
+#include <linux/device.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/module.h>
diff --git a/drivers/of/of_spi.c b/drivers/of/of_spi.c
deleted file mode 100644
index 6dbc074e4876..000000000000
--- a/drivers/of/of_spi.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * SPI OF support routines
- * Copyright (C) 2008 Secret Lab Technologies Ltd.
- *
- * Support routines for deriving SPI device attachments from the device
- * tree.
- */
-
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/device.h>
-#include <linux/spi/spi.h>
-#include <linux/of_irq.h>
-#include <linux/of_spi.h>
-
-/**
- * of_register_spi_devices - Register child devices onto the SPI bus
- * @master: Pointer to spi_master device
- *
- * Registers an spi_device for each child node of master node which has a 'reg'
- * property.
- */
-void of_register_spi_devices(struct spi_master *master)
-{
- struct spi_device *spi;
- struct device_node *nc;
- const __be32 *prop;
- int rc;
- int len;
-
- if (!master->dev.of_node)
- return;
-
- for_each_child_of_node(master->dev.of_node, nc) {
- /* Alloc an spi_device */
- spi = spi_alloc_device(master);
- if (!spi) {
- dev_err(&master->dev, "spi_device alloc error for %s\n",
- nc->full_name);
- spi_dev_put(spi);
- continue;
- }
-
- /* Select device driver */
- if (of_modalias_node(nc, spi->modalias,
- sizeof(spi->modalias)) < 0) {
- dev_err(&master->dev, "cannot find modalias for %s\n",
- nc->full_name);
- spi_dev_put(spi);
- continue;
- }
-
- /* Device address */
- prop = of_get_property(nc, "reg", &len);
- if (!prop || len < sizeof(*prop)) {
- dev_err(&master->dev, "%s has no 'reg' property\n",
- nc->full_name);
- spi_dev_put(spi);
- continue;
- }
- spi->chip_select = be32_to_cpup(prop);
-
- /* Mode (clock phase/polarity/etc.) */
- if (of_find_property(nc, "spi-cpha", NULL))
- spi->mode |= SPI_CPHA;
- if (of_find_property(nc, "spi-cpol", NULL))
- spi->mode |= SPI_CPOL;
- if (of_find_property(nc, "spi-cs-high", NULL))
- spi->mode |= SPI_CS_HIGH;
-
- /* Device speed */
- prop = of_get_property(nc, "spi-max-frequency", &len);
- if (!prop || len < sizeof(*prop)) {
- dev_err(&master->dev, "%s has no 'spi-max-frequency' property\n",
- nc->full_name);
- spi_dev_put(spi);
- continue;
- }
- spi->max_speed_hz = be32_to_cpup(prop);
-
- /* IRQ */
- spi->irq = irq_of_parse_and_map(nc, 0);
-
- /* Store a pointer to the node in the device structure */
- of_node_get(nc);
- spi->dev.of_node = nc;
-
- /* Register the new device */
- request_module(spi->modalias);
- rc = spi_add_device(spi);
- if (rc) {
- dev_err(&master->dev, "spi_device register error %s\n",
- nc->full_name);
- spi_dev_put(spi);
- }
-
- }
-}
-EXPORT_SYMBOL(of_register_spi_devices);
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
index e3b76d409dee..5003458980d3 100644
--- a/drivers/parisc/superio.c
+++ b/drivers/parisc/superio.c
@@ -348,7 +348,7 @@ int superio_fixup_irq(struct pci_dev *pcidev)
BUG();
return -1;
}
- printk("superio_fixup_irq(%s) ven 0x%x dev 0x%x from %p\n",
+ printk("superio_fixup_irq(%s) ven 0x%x dev 0x%x from %pf\n",
pci_name(pcidev),
pcidev->vendor, pcidev->device,
__builtin_return_address(0));
diff --git a/drivers/parport/parport_amiga.c b/drivers/parport/parport_amiga.c
index 8bef6d60f88b..ee78e0ee6e05 100644
--- a/drivers/parport/parport_amiga.c
+++ b/drivers/parport/parport_amiga.c
@@ -48,23 +48,6 @@ static unsigned char amiga_read_data(struct parport *p)
return ciaa.prb;
}
-#if 0
-static unsigned char control_pc_to_amiga(unsigned char control)
-{
- unsigned char ret = 0;
-
- if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */
- ;
- if (control & PARPORT_CONTROL_INIT) /* INITP */
- /* reset connected to cpu reset pin */;
- if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */
- /* Not connected */;
- if (control & PARPORT_CONTROL_STROBE) /* Strobe */
- /* Handled only directly by hardware */;
- return ret;
-}
-#endif
-
static unsigned char control_amiga_to_pc(unsigned char control)
{
return PARPORT_CONTROL_SELECT |
@@ -95,25 +78,6 @@ static unsigned char amiga_frob_control( struct parport *p, unsigned char mask,
return old;
}
-#if 0 /* currently unused */
-static unsigned char status_pc_to_amiga(unsigned char status)
-{
- unsigned char ret = 1;
-
- if (status & PARPORT_STATUS_BUSY) /* Busy */
- ret &= ~1;
- if (status & PARPORT_STATUS_ACK) /* Ack */
- /* handled in hardware */;
- if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */
- ret |= 2;
- if (status & PARPORT_STATUS_SELECT) /* select */
- ret |= 4;
- if (status & PARPORT_STATUS_ERROR) /* error */
- /* not connected */;
- return ret;
-}
-#endif
-
static unsigned char status_amiga_to_pc(unsigned char status)
{
unsigned char ret = PARPORT_STATUS_BUSY | PARPORT_STATUS_ACK | PARPORT_STATUS_ERROR;
diff --git a/drivers/parport/parport_atari.c b/drivers/parport/parport_atari.c
index 0b28fccec03f..7ad59ac68cf6 100644
--- a/drivers/parport/parport_atari.c
+++ b/drivers/parport/parport_atari.c
@@ -130,15 +130,6 @@ parport_atari_data_forward(struct parport *p)
static void
parport_atari_data_reverse(struct parport *p)
{
-#if 0 /* too dangerous, can kill sound chip */
- unsigned long flags;
-
- local_irq_save(flags);
- /* Soundchip port B as input. */
- sound_ym.rd_data_reg_sel = 7;
- sound_ym.wd_data = sound_ym.rd_data_reg_sel & ~0x40;
- local_irq_restore(flags);
-#endif
}
static struct parport_operations parport_atari_ops = {
diff --git a/drivers/parport/parport_mfc3.c b/drivers/parport/parport_mfc3.c
index 1c0c642b3e23..7578d79b3688 100644
--- a/drivers/parport/parport_mfc3.c
+++ b/drivers/parport/parport_mfc3.c
@@ -147,25 +147,6 @@ DPRINTK(KERN_DEBUG "frob_control mask %02x, value %02x\n",mask,val);
return old;
}
-#if 0 /* currently unused */
-static unsigned char status_pc_to_mfc3(unsigned char status)
-{
- unsigned char ret = 1;
-
- if (status & PARPORT_STATUS_BUSY) /* Busy */
- ret &= ~1;
- if (status & PARPORT_STATUS_ACK) /* Ack */
- ret |= 8;
- if (status & PARPORT_STATUS_PAPEROUT) /* PaperOut */
- ret |= 2;
- if (status & PARPORT_STATUS_SELECT) /* select */
- ret |= 4;
- if (status & PARPORT_STATUS_ERROR) /* error */
- ret |= 16;
- return ret;
-}
-#endif
-
static unsigned char status_mfc3_to_pc(unsigned char status)
{
unsigned char ret = PARPORT_STATUS_BUSY;
@@ -184,14 +165,6 @@ static unsigned char status_mfc3_to_pc(unsigned char status)
return ret;
}
-#if 0 /* currently unused */
-static void mfc3_write_status( struct parport *p, unsigned char status)
-{
-DPRINTK(KERN_DEBUG "write_status %02x\n",status);
- pia(p)->ppra = (pia(p)->ppra & 0xe0) | status_pc_to_mfc3(status);
-}
-#endif
-
static unsigned char mfc3_read_status(struct parport *p)
{
unsigned char status;
@@ -201,14 +174,6 @@ DPRINTK(KERN_DEBUG "read_status %02x\n", status);
return status;
}
-#if 0 /* currently unused */
-static void mfc3_change_mode( struct parport *p, int m)
-{
- /* XXX: This port only has one mode, and I am
- not sure about the corresponding PC-style mode*/
-}
-#endif
-
static int use_cnt = 0;
static irqreturn_t mfc3_interrupt(int irq, void *dev_id)
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 0cb64f50cecd..5abffe58a9d2 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -197,54 +197,6 @@ static int change_mode(struct parport *p, int m)
ECR_WRITE(p, oecr);
return 0;
}
-
-#ifdef CONFIG_PARPORT_1284
-/* Find FIFO lossage; FIFO is reset */
-#if 0
-static int get_fifo_residue(struct parport *p)
-{
- int residue;
- int cnfga;
- const struct parport_pc_private *priv = p->physport->private_data;
-
- /* Adjust for the contents of the FIFO. */
- for (residue = priv->fifo_depth; ; residue--) {
- if (inb(ECONTROL(p)) & 0x2)
- /* Full up. */
- break;
-
- outb(0, FIFO(p));
- }
-
- printk(KERN_DEBUG "%s: %d PWords were left in FIFO\n", p->name,
- residue);
-
- /* Reset the FIFO. */
- frob_set_mode(p, ECR_PS2);
-
- /* Now change to config mode and clean up. FIXME */
- frob_set_mode(p, ECR_CNF);
- cnfga = inb(CONFIGA(p));
- printk(KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga);
-
- if (!(cnfga & (1<<2))) {
- printk(KERN_DEBUG "%s: Accounting for extra byte\n", p->name);
- residue++;
- }
-
- /* Don't care about partial PWords until support is added for
- * PWord != 1 byte. */
-
- /* Back to PS2 mode. */
- frob_set_mode(p, ECR_PS2);
-
- DPRINTK(KERN_DEBUG
- "*** get_fifo_residue: done residue collecting (ecr = 0x%2.2x)\n",
- inb(ECONTROL(p)));
- return residue;
-}
-#endif /* 0 */
-#endif /* IEEE 1284 support */
#endif /* FIFO support */
/*
@@ -940,234 +892,6 @@ static size_t parport_pc_ecp_write_block_pio(struct parport *port,
return written;
}
-
-#if 0
-static size_t parport_pc_ecp_read_block_pio(struct parport *port,
- void *buf, size_t length,
- int flags)
-{
- size_t left = length;
- size_t fifofull;
- int r;
- const int fifo = FIFO(port);
- const struct parport_pc_private *priv = port->physport->private_data;
- const int fifo_depth = priv->fifo_depth;
- char *bufp = buf;
-
- port = port->physport;
- DPRINTK(KERN_DEBUG "parport_pc: parport_pc_ecp_read_block_pio\n");
- dump_parport_state("enter fcn", port);
-
- /* Special case: a timeout of zero means we cannot call schedule().
- * Also if O_NONBLOCK is set then use the default implementation. */
- if (port->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK)
- return parport_ieee1284_ecp_read_data(port, buf,
- length, flags);
-
- if (port->ieee1284.mode == IEEE1284_MODE_ECPRLE) {
- /* If the peripheral is allowed to send RLE compressed
- * data, it is possible for a byte to expand to 128
- * bytes in the FIFO. */
- fifofull = 128;
- } else {
- fifofull = fifo_depth;
- }
-
- /* If the caller wants less than a full FIFO's worth of data,
- * go through software emulation. Otherwise we may have to throw
- * away data. */
- if (length < fifofull)
- return parport_ieee1284_ecp_read_data(port, buf,
- length, flags);
-
- if (port->ieee1284.phase != IEEE1284_PH_REV_IDLE) {
- /* change to reverse-idle phase (must be in forward-idle) */
-
- /* Event 38: Set nAutoFd low (also make sure nStrobe is high) */
- parport_frob_control(port,
- PARPORT_CONTROL_AUTOFD
- | PARPORT_CONTROL_STROBE,
- PARPORT_CONTROL_AUTOFD);
- parport_pc_data_reverse(port); /* Must be in PS2 mode */
- udelay(5);
- /* Event 39: Set nInit low to initiate bus reversal */
- parport_frob_control(port,
- PARPORT_CONTROL_INIT,
- 0);
- /* Event 40: Wait for nAckReverse (PError) to go low */
- r = parport_wait_peripheral(port, PARPORT_STATUS_PAPEROUT, 0);
- if (r) {
- printk(KERN_DEBUG "%s: PE timeout Event 40 (%d) "
- "in ecp_read_block_pio\n", port->name, r);
- return 0;
- }
- }
-
- /* Set up ECP FIFO mode.*/
-/* parport_pc_frob_control(port,
- PARPORT_CONTROL_STROBE |
- PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_AUTOFD); */
- r = change_mode(port, ECR_ECP); /* ECP FIFO */
- if (r)
- printk(KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n",
- port->name);
-
- port->ieee1284.phase = IEEE1284_PH_REV_DATA;
-
- /* the first byte must be collected manually */
- dump_parport_state("pre 43", port);
- /* Event 43: Wait for nAck to go low */
- r = parport_wait_peripheral(port, PARPORT_STATUS_ACK, 0);
- if (r) {
- /* timed out while reading -- no data */
- printk(KERN_DEBUG "PIO read timed out (initial byte)\n");
- goto out_no_data;
- }
- /* read byte */
- *bufp++ = inb(DATA(port));
- left--;
- dump_parport_state("43-44", port);
- /* Event 44: nAutoFd (HostAck) goes high to acknowledge */
- parport_pc_frob_control(port,
- PARPORT_CONTROL_AUTOFD,
- 0);
- dump_parport_state("pre 45", port);
- /* Event 45: Wait for nAck to go high */
- /* r = parport_wait_peripheral(port, PARPORT_STATUS_ACK,
- PARPORT_STATUS_ACK); */
- dump_parport_state("post 45", port);
- r = 0;
- if (r) {
- /* timed out while waiting for peripheral to respond to ack */
- printk(KERN_DEBUG "ECP PIO read timed out (waiting for nAck)\n");
-
- /* keep hold of the byte we've got already */
- goto out_no_data;
- }
- /* Event 46: nAutoFd (HostAck) goes low to accept more data */
- parport_pc_frob_control(port,
- PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_AUTOFD);
-
-
- dump_parport_state("rev idle", port);
- /* Do the transfer. */
- while (left > fifofull) {
- int ret;
- unsigned long expire = jiffies + port->cad->timeout;
- unsigned char ecrval = inb(ECONTROL(port));
-
- if (need_resched() && time_before(jiffies, expire))
- /* Can't yield the port. */
- schedule();
-
- /* At this point, the FIFO may already be full. In
- * that case ECP is already holding back the
- * peripheral (assuming proper design) with a delayed
- * handshake. Work fast to avoid a peripheral
- * timeout. */
-
- if (ecrval & 0x01) {
- /* FIFO is empty. Wait for interrupt. */
- dump_parport_state("FIFO empty", port);
-
- /* Anyone else waiting for the port? */
- if (port->waithead) {
- printk(KERN_DEBUG "Somebody wants the port\n");
- break;
- }
-
- /* Clear serviceIntr */
- ECR_WRITE(port, ecrval & ~(1<<2));
-false_alarm:
- dump_parport_state("waiting", port);
- ret = parport_wait_event(port, HZ);
- DPRINTK(KERN_DEBUG "parport_wait_event returned %d\n",
- ret);
- if (ret < 0)
- break;
- ret = 0;
- if (!time_before(jiffies, expire)) {
- /* Timed out. */
- dump_parport_state("timeout", port);
- printk(KERN_DEBUG "PIO read timed out\n");
- break;
- }
- ecrval = inb(ECONTROL(port));
- if (!(ecrval & (1<<2))) {
- if (need_resched() &&
- time_before(jiffies, expire)) {
- schedule();
- }
- goto false_alarm;
- }
-
- /* Depending on how the FIFO threshold was
- * set, how long interrupt service took, and
- * how fast the peripheral is, we might be
- * lucky and have a just filled FIFO. */
- continue;
- }
-
- if (ecrval & 0x02) {
- /* FIFO is full. */
- dump_parport_state("FIFO full", port);
- insb(fifo, bufp, fifo_depth);
- bufp += fifo_depth;
- left -= fifo_depth;
- continue;
- }
-
- DPRINTK(KERN_DEBUG
- "*** ecp_read_block_pio: reading one byte from the FIFO\n");
-
- /* FIFO not filled. We will cycle this loop for a while
- * and either the peripheral will fill it faster,
- * tripping a fast empty with insb, or we empty it. */
- *bufp++ = inb(fifo);
- left--;
- }
-
- /* scoop up anything left in the FIFO */
- while (left && !(inb(ECONTROL(port) & 0x01))) {
- *bufp++ = inb(fifo);
- left--;
- }
-
- port->ieee1284.phase = IEEE1284_PH_REV_IDLE;
- dump_parport_state("rev idle2", port);
-
-out_no_data:
-
- /* Go to forward idle mode to shut the peripheral up (event 47). */
- parport_frob_control(port, PARPORT_CONTROL_INIT, PARPORT_CONTROL_INIT);
-
- /* event 49: PError goes high */
- r = parport_wait_peripheral(port,
- PARPORT_STATUS_PAPEROUT,
- PARPORT_STATUS_PAPEROUT);
- if (r) {
- printk(KERN_DEBUG
- "%s: PE timeout FWDIDLE (%d) in ecp_read_block_pio\n",
- port->name, r);
- }
-
- port->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
-
- /* Finish up. */
- {
- int lost = get_fifo_residue(port);
- if (lost)
- /* Shouldn't happen with compliant peripherals. */
- printk(KERN_DEBUG "%s: DATA LOSS (%d bytes)!\n",
- port->name, lost);
- }
-
- dump_parport_state("fwd idle", port);
- return length - left;
-}
-#endif /* 0 */
#endif /* IEEE 1284 support */
#endif /* Allowed to use FIFO/DMA */
@@ -2351,7 +2075,7 @@ struct parport *parport_pc_probe_port(unsigned long int base,
printk(KERN_INFO "%s: PC-style at 0x%lx", p->name, p->base);
if (p->base_hi && priv->ecr)
- printk(" (0x%lx)", p->base_hi);
+ printk(KERN_CONT " (0x%lx)", p->base_hi);
if (p->irq == PARPORT_IRQ_AUTO) {
p->irq = PARPORT_IRQ_NONE;
parport_irq_probe(p);
@@ -2362,7 +2086,7 @@ struct parport *parport_pc_probe_port(unsigned long int base,
p->irq = PARPORT_IRQ_NONE;
}
if (p->irq != PARPORT_IRQ_NONE) {
- printk(", irq %d", p->irq);
+ printk(KERN_CONT ", irq %d", p->irq);
priv->ctr_writable |= 0x10;
if (p->dma == PARPORT_DMA_AUTO) {
@@ -2386,21 +2110,21 @@ struct parport *parport_pc_probe_port(unsigned long int base,
/* p->ops->ecp_read_data = parport_pc_ecp_read_block_pio; */
#endif /* IEEE 1284 support */
if (p->dma != PARPORT_DMA_NONE) {
- printk(", dma %d", p->dma);
+ printk(KERN_CONT ", dma %d", p->dma);
p->modes |= PARPORT_MODE_DMA;
} else
- printk(", using FIFO");
+ printk(KERN_CONT ", using FIFO");
} else
/* We can't use the DMA channel after all. */
p->dma = PARPORT_DMA_NONE;
#endif /* Allowed to use FIFO/DMA */
- printk(" [");
+ printk(KERN_CONT " [");
#define printmode(x) \
{\
if (p->modes & PARPORT_MODE_##x) {\
- printk("%s%s", f ? "," : "", #x);\
+ printk(KERN_CONT "%s%s", f ? "," : "", #x);\
f++;\
} \
}
@@ -2416,9 +2140,9 @@ struct parport *parport_pc_probe_port(unsigned long int base,
}
#undef printmode
#ifndef CONFIG_PARPORT_1284
- printk("(,...)");
+ printk(KERN_CONT "(,...)");
#endif /* CONFIG_PARPORT_1284 */
- printk("]\n");
+ printk(KERN_CONT "]\n");
if (probedirq != PARPORT_IRQ_NONE)
printk(KERN_INFO "%s: irq %d detected\n", p->name, probedirq);
diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c
index 9390a534a2b2..983a2d2df659 100644
--- a/drivers/parport/parport_sunbpp.c
+++ b/drivers/parport/parport_sunbpp.c
@@ -82,27 +82,6 @@ static unsigned char parport_sunbpp_read_data(struct parport *p)
return sbus_readb(&regs->p_dr);
}
-#if 0
-static void control_pc_to_sunbpp(struct parport *p, unsigned char status)
-{
- struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
- unsigned char value_tcr = sbus_readb(&regs->p_tcr);
- unsigned char value_or = sbus_readb(&regs->p_or);
-
- if (status & PARPORT_CONTROL_STROBE)
- value_tcr |= P_TCR_DS;
- if (status & PARPORT_CONTROL_AUTOFD)
- value_or |= P_OR_AFXN;
- if (status & PARPORT_CONTROL_INIT)
- value_or |= P_OR_INIT;
- if (status & PARPORT_CONTROL_SELECT)
- value_or |= P_OR_SLCT_IN;
-
- sbus_writeb(value_or, &regs->p_or);
- sbus_writeb(value_tcr, &regs->p_tcr);
-}
-#endif
-
static unsigned char status_sunbpp_to_pc(struct parport *p)
{
struct bpp_regs __iomem *regs = (struct bpp_regs __iomem *)p->base;
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index a55e248618cd..86c63fe45d11 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -27,6 +27,7 @@
#include <linux/security.h>
#include <linux/pci-aspm.h>
#include <linux/slab.h>
+#include <linux/vgaarb.h>
#include "pci.h"
static int sysfs_initialized; /* = 0 */
@@ -417,6 +418,10 @@ static ssize_t
boot_vga_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct pci_dev *pdev = to_pci_dev(dev);
+ struct pci_dev *vga_dev = vga_default_device();
+
+ if (vga_dev)
+ return sprintf(buf, "%u\n", (pdev == vga_dev));
return sprintf(buf, "%u\n",
!!(pdev->resource[PCI_ROM_RESOURCE].flags &
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index bba3ab2066ee..8fd255f7ee40 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -217,7 +217,7 @@ config PCMCIA_PXA2XX
|| MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \
|| ARCOM_PCMCIA || ARCH_PXA_ESERIES || MACH_STARGATE2 \
|| MACH_VPAC270 || MACH_BALLOON3 || MACH_COLIBRI \
- || MACH_COLIBRI320)
+ || MACH_COLIBRI320 || MACH_H4700)
select PCMCIA_SA1111 if ARCH_LUBBOCK && SA1111
select PCMCIA_SOC_COMMON
help
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index 47525de6a631..7745b512a87c 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -69,6 +69,7 @@ pxa2xx-obj-$(CONFIG_MACH_VPAC270) += pxa2xx_vpac270.o
pxa2xx-obj-$(CONFIG_MACH_BALLOON3) += pxa2xx_balloon3.o
pxa2xx-obj-$(CONFIG_MACH_COLIBRI) += pxa2xx_colibri.o
pxa2xx-obj-$(CONFIG_MACH_COLIBRI320) += pxa2xx_colibri.o
+pxa2xx-obj-$(CONFIG_MACH_H4700) += pxa2xx_hx4700.o
obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_base.o $(pxa2xx-obj-y)
diff --git a/drivers/pcmcia/pxa2xx_hx4700.c b/drivers/pcmcia/pxa2xx_hx4700.c
new file mode 100644
index 000000000000..7dfef3ee5b53
--- /dev/null
+++ b/drivers/pcmcia/pxa2xx_hx4700.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2012 Paul Parsons <lost.distance@yahoo.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/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+
+#include <asm/mach-types.h>
+#include <mach/hx4700.h>
+
+#include "soc_common.h"
+
+static struct gpio gpios[] = {
+ { GPIO114_HX4700_CF_RESET, GPIOF_OUT_INIT_LOW, "CF reset" },
+ { EGPIO4_CF_3V3_ON, GPIOF_OUT_INIT_LOW, "CF 3.3V enable" },
+};
+
+static int hx4700_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+ int ret;
+
+ ret = gpio_request_array(gpios, ARRAY_SIZE(gpios));
+ if (ret)
+ goto out;
+
+ /*
+ * IRQ type must be set before soc_pcmcia_hw_init() calls request_irq().
+ * The asic3 default IRQ type is level trigger low level detect, exactly
+ * the the signal present on GPIOD4_CF_nCD when a CF card is inserted.
+ * If the IRQ type is not changed, the asic3 interrupt handler will loop
+ * repeatedly because it is unable to clear the level trigger interrupt.
+ */
+ irq_set_irq_type(gpio_to_irq(GPIOD4_CF_nCD), IRQ_TYPE_EDGE_BOTH);
+
+ skt->stat[SOC_STAT_CD].gpio = GPIOD4_CF_nCD;
+ skt->stat[SOC_STAT_CD].name = "PCMCIA CD";
+ skt->stat[SOC_STAT_RDY].gpio = GPIO60_HX4700_CF_RNB;
+ skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready";
+
+out:
+ return ret;
+}
+
+static void hx4700_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+ gpio_free_array(gpios, ARRAY_SIZE(gpios));
+}
+
+static void hx4700_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+ struct pcmcia_state *state)
+{
+ state->vs_3v = 1;
+ state->vs_Xv = 0;
+}
+
+static int hx4700_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+ const socket_state_t *state)
+{
+ switch (state->Vcc) {
+ case 0:
+ gpio_set_value(EGPIO4_CF_3V3_ON, 0);
+ break;
+ case 33:
+ gpio_set_value(EGPIO4_CF_3V3_ON, 1);
+ break;
+ default:
+ printk(KERN_ERR "pcmcia: Unsupported Vcc: %d\n", state->Vcc);
+ return -EINVAL;
+ }
+
+ gpio_set_value(GPIO114_HX4700_CF_RESET, (state->flags & SS_RESET) != 0);
+
+ return 0;
+}
+
+static struct pcmcia_low_level hx4700_pcmcia_ops = {
+ .owner = THIS_MODULE,
+ .nr = 1,
+ .hw_init = hx4700_pcmcia_hw_init,
+ .hw_shutdown = hx4700_pcmcia_hw_shutdown,
+ .socket_state = hx4700_pcmcia_socket_state,
+ .configure_socket = hx4700_pcmcia_configure_socket,
+};
+
+static struct platform_device *hx4700_pcmcia_device;
+
+static int __init hx4700_pcmcia_init(void)
+{
+ struct platform_device *pdev;
+
+ if (!machine_is_h4700())
+ return -ENODEV;
+
+ pdev = platform_device_register_data(NULL, "pxa2xx-pcmcia", -1,
+ &hx4700_pcmcia_ops, sizeof(hx4700_pcmcia_ops));
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
+
+ hx4700_pcmcia_device = pdev;
+
+ return 0;
+}
+
+static void __exit hx4700_pcmcia_exit(void)
+{
+ platform_device_unregister(hx4700_pcmcia_device);
+}
+
+module_init(hx4700_pcmcia_init);
+module_exit(hx4700_pcmcia_exit);
+
+MODULE_AUTHOR("Paul Parsons <lost.distance@yahoo.com>");
+MODULE_DESCRIPTION("HP iPAQ hx4700 PCMCIA driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 91c1f64102f0..c6e6ae0aa3b1 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -80,6 +80,16 @@ config PINCTRL_IMX28
select PINCONF
select PINCTRL_MXS
+config PINCTRL_NOMADIK
+ bool "Nomadik pin controller driver"
+ depends on ARCH_U8500 || ARCH_NOMADIK
+ select PINMUX
+ select PINCONF
+
+config PINCTRL_DB8500
+ bool "DB8500 pin controller driver"
+ depends on PINCTRL_NOMADIK && ARCH_U8500
+
config PINCTRL_PXA168
bool "PXA168 pin controller driver"
depends on ARCH_MMP
@@ -127,6 +137,8 @@ config PINCTRL_COH901
COH 901 335 and COH 901 571/3. They contain 3, 5 or 7
ports of 8 GPIO pins each.
+source "drivers/pinctrl/spear/Kconfig"
+
endmenu
endif
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 515e32ff1597..8c074376cdea 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -18,6 +18,8 @@ obj-$(CONFIG_PINCTRL_MMP2) += pinctrl-mmp2.o
obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o
obj-$(CONFIG_PINCTRL_IMX23) += pinctrl-imx23.o
obj-$(CONFIG_PINCTRL_IMX28) += pinctrl-imx28.o
+obj-$(CONFIG_PINCTRL_NOMADIK) += pinctrl-nomadik.o
+obj-$(CONFIG_PINCTRL_DB8500) += pinctrl-nomadik-db8500.o
obj-$(CONFIG_PINCTRL_PXA168) += pinctrl-pxa168.o
obj-$(CONFIG_PINCTRL_PXA910) += pinctrl-pxa910.o
obj-$(CONFIG_PINCTRL_SIRF) += pinctrl-sirf.o
@@ -26,3 +28,5 @@ obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o
obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o
obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o
obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o
+
+obj-$(CONFIG_PLAT_SPEAR) += spear/
diff --git a/drivers/pinctrl/pinctrl-nomadik-db8500.c b/drivers/pinctrl/pinctrl-nomadik-db8500.c
new file mode 100644
index 000000000000..8b2022276f71
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-nomadik-db8500.c
@@ -0,0 +1,857 @@
+#include <linux/kernel.h>
+#include <linux/pinctrl/pinctrl.h>
+#include "pinctrl-nomadik.h"
+
+/* All the pins that can be used for GPIO and some other functions */
+#define _GPIO(offset) (offset)
+
+#define DB8500_PIN_AJ5 _GPIO(0)
+#define DB8500_PIN_AJ3 _GPIO(1)
+#define DB8500_PIN_AH4 _GPIO(2)
+#define DB8500_PIN_AH3 _GPIO(3)
+#define DB8500_PIN_AH6 _GPIO(4)
+#define DB8500_PIN_AG6 _GPIO(5)
+#define DB8500_PIN_AF6 _GPIO(6)
+#define DB8500_PIN_AG5 _GPIO(7)
+#define DB8500_PIN_AD5 _GPIO(8)
+#define DB8500_PIN_AE4 _GPIO(9)
+#define DB8500_PIN_AF5 _GPIO(10)
+#define DB8500_PIN_AG4 _GPIO(11)
+#define DB8500_PIN_AC4 _GPIO(12)
+#define DB8500_PIN_AF3 _GPIO(13)
+#define DB8500_PIN_AE3 _GPIO(14)
+#define DB8500_PIN_AC3 _GPIO(15)
+#define DB8500_PIN_AD3 _GPIO(16)
+#define DB8500_PIN_AD4 _GPIO(17)
+#define DB8500_PIN_AC2 _GPIO(18)
+#define DB8500_PIN_AC1 _GPIO(19)
+#define DB8500_PIN_AB4 _GPIO(20)
+#define DB8500_PIN_AB3 _GPIO(21)
+#define DB8500_PIN_AA3 _GPIO(22)
+#define DB8500_PIN_AA4 _GPIO(23)
+#define DB8500_PIN_AB2 _GPIO(24)
+#define DB8500_PIN_Y4 _GPIO(25)
+#define DB8500_PIN_Y2 _GPIO(26)
+#define DB8500_PIN_AA2 _GPIO(27)
+#define DB8500_PIN_AA1 _GPIO(28)
+#define DB8500_PIN_W2 _GPIO(29)
+#define DB8500_PIN_W3 _GPIO(30)
+#define DB8500_PIN_V3 _GPIO(31)
+#define DB8500_PIN_V2 _GPIO(32)
+#define DB8500_PIN_AF2 _GPIO(33)
+#define DB8500_PIN_AE1 _GPIO(34)
+#define DB8500_PIN_AE2 _GPIO(35)
+#define DB8500_PIN_AG2 _GPIO(36)
+/* Hole */
+#define DB8500_PIN_F3 _GPIO(64)
+#define DB8500_PIN_F1 _GPIO(65)
+#define DB8500_PIN_G3 _GPIO(66)
+#define DB8500_PIN_G2 _GPIO(67)
+#define DB8500_PIN_E1 _GPIO(68)
+#define DB8500_PIN_E2 _GPIO(69)
+#define DB8500_PIN_G5 _GPIO(70)
+#define DB8500_PIN_G4 _GPIO(71)
+#define DB8500_PIN_H4 _GPIO(72)
+#define DB8500_PIN_H3 _GPIO(73)
+#define DB8500_PIN_J3 _GPIO(74)
+#define DB8500_PIN_H2 _GPIO(75)
+#define DB8500_PIN_J2 _GPIO(76)
+#define DB8500_PIN_H1 _GPIO(77)
+#define DB8500_PIN_F4 _GPIO(78)
+#define DB8500_PIN_E3 _GPIO(79)
+#define DB8500_PIN_E4 _GPIO(80)
+#define DB8500_PIN_D2 _GPIO(81)
+#define DB8500_PIN_C1 _GPIO(82)
+#define DB8500_PIN_D3 _GPIO(83)
+#define DB8500_PIN_C2 _GPIO(84)
+#define DB8500_PIN_D5 _GPIO(85)
+#define DB8500_PIN_C6 _GPIO(86)
+#define DB8500_PIN_B3 _GPIO(87)
+#define DB8500_PIN_C4 _GPIO(88)
+#define DB8500_PIN_E6 _GPIO(89)
+#define DB8500_PIN_A3 _GPIO(90)
+#define DB8500_PIN_B6 _GPIO(91)
+#define DB8500_PIN_D6 _GPIO(92)
+#define DB8500_PIN_B7 _GPIO(93)
+#define DB8500_PIN_D7 _GPIO(94)
+#define DB8500_PIN_E8 _GPIO(95)
+#define DB8500_PIN_D8 _GPIO(96)
+#define DB8500_PIN_D9 _GPIO(97)
+/* Hole */
+#define DB8500_PIN_A5 _GPIO(128)
+#define DB8500_PIN_B4 _GPIO(129)
+#define DB8500_PIN_C8 _GPIO(130)
+#define DB8500_PIN_A12 _GPIO(131)
+#define DB8500_PIN_C10 _GPIO(132)
+#define DB8500_PIN_B10 _GPIO(133)
+#define DB8500_PIN_B9 _GPIO(134)
+#define DB8500_PIN_A9 _GPIO(135)
+#define DB8500_PIN_C7 _GPIO(136)
+#define DB8500_PIN_A7 _GPIO(137)
+#define DB8500_PIN_C5 _GPIO(138)
+#define DB8500_PIN_C9 _GPIO(139)
+#define DB8500_PIN_B11 _GPIO(140)
+#define DB8500_PIN_C12 _GPIO(141)
+#define DB8500_PIN_C11 _GPIO(142)
+#define DB8500_PIN_D12 _GPIO(143)
+#define DB8500_PIN_B13 _GPIO(144)
+#define DB8500_PIN_C13 _GPIO(145)
+#define DB8500_PIN_D13 _GPIO(146)
+#define DB8500_PIN_C15 _GPIO(147)
+#define DB8500_PIN_B16 _GPIO(148)
+#define DB8500_PIN_B14 _GPIO(149)
+#define DB8500_PIN_C14 _GPIO(150)
+#define DB8500_PIN_D17 _GPIO(151)
+#define DB8500_PIN_D16 _GPIO(152)
+#define DB8500_PIN_B17 _GPIO(153)
+#define DB8500_PIN_C16 _GPIO(154)
+#define DB8500_PIN_C19 _GPIO(155)
+#define DB8500_PIN_C17 _GPIO(156)
+#define DB8500_PIN_A18 _GPIO(157)
+#define DB8500_PIN_C18 _GPIO(158)
+#define DB8500_PIN_B19 _GPIO(159)
+#define DB8500_PIN_B20 _GPIO(160)
+#define DB8500_PIN_D21 _GPIO(161)
+#define DB8500_PIN_D20 _GPIO(162)
+#define DB8500_PIN_C20 _GPIO(163)
+#define DB8500_PIN_B21 _GPIO(164)
+#define DB8500_PIN_C21 _GPIO(165)
+#define DB8500_PIN_A22 _GPIO(166)
+#define DB8500_PIN_B24 _GPIO(167)
+#define DB8500_PIN_C22 _GPIO(168)
+#define DB8500_PIN_D22 _GPIO(169)
+#define DB8500_PIN_C23 _GPIO(170)
+#define DB8500_PIN_D23 _GPIO(171)
+/* Hole */
+#define DB8500_PIN_AJ27 _GPIO(192)
+#define DB8500_PIN_AH27 _GPIO(193)
+#define DB8500_PIN_AF27 _GPIO(194)
+#define DB8500_PIN_AG28 _GPIO(195)
+#define DB8500_PIN_AG26 _GPIO(196)
+#define DB8500_PIN_AH24 _GPIO(197)
+#define DB8500_PIN_AG25 _GPIO(198)
+#define DB8500_PIN_AH23 _GPIO(199)
+#define DB8500_PIN_AH26 _GPIO(200)
+#define DB8500_PIN_AF24 _GPIO(201)
+#define DB8500_PIN_AF25 _GPIO(202)
+#define DB8500_PIN_AE23 _GPIO(203)
+#define DB8500_PIN_AF23 _GPIO(204)
+#define DB8500_PIN_AG23 _GPIO(205)
+#define DB8500_PIN_AG24 _GPIO(206)
+#define DB8500_PIN_AJ23 _GPIO(207)
+#define DB8500_PIN_AH16 _GPIO(208)
+#define DB8500_PIN_AG15 _GPIO(209)
+#define DB8500_PIN_AJ15 _GPIO(210)
+#define DB8500_PIN_AG14 _GPIO(211)
+#define DB8500_PIN_AF13 _GPIO(212)
+#define DB8500_PIN_AG13 _GPIO(213)
+#define DB8500_PIN_AH15 _GPIO(214)
+#define DB8500_PIN_AH13 _GPIO(215)
+#define DB8500_PIN_AG12 _GPIO(216)
+#define DB8500_PIN_AH12 _GPIO(217)
+#define DB8500_PIN_AH11 _GPIO(218)
+#define DB8500_PIN_AG10 _GPIO(219)
+#define DB8500_PIN_AH10 _GPIO(220)
+#define DB8500_PIN_AJ11 _GPIO(221)
+#define DB8500_PIN_AJ9 _GPIO(222)
+#define DB8500_PIN_AH9 _GPIO(223)
+#define DB8500_PIN_AG9 _GPIO(224)
+#define DB8500_PIN_AG8 _GPIO(225)
+#define DB8500_PIN_AF8 _GPIO(226)
+#define DB8500_PIN_AH7 _GPIO(227)
+#define DB8500_PIN_AJ6 _GPIO(228)
+#define DB8500_PIN_AG7 _GPIO(229)
+#define DB8500_PIN_AF7 _GPIO(230)
+/* Hole */
+#define DB8500_PIN_AF28 _GPIO(256)
+#define DB8500_PIN_AE29 _GPIO(257)
+#define DB8500_PIN_AD29 _GPIO(258)
+#define DB8500_PIN_AC29 _GPIO(259)
+#define DB8500_PIN_AD28 _GPIO(260)
+#define DB8500_PIN_AD26 _GPIO(261)
+#define DB8500_PIN_AE26 _GPIO(262)
+#define DB8500_PIN_AG29 _GPIO(263)
+#define DB8500_PIN_AE27 _GPIO(264)
+#define DB8500_PIN_AD27 _GPIO(265)
+#define DB8500_PIN_AC28 _GPIO(266)
+#define DB8500_PIN_AC27 _GPIO(267)
+
+/*
+ * The names of the pins are denoted by GPIO number and ball name, even
+ * though they can be used for other things than GPIO, this is the first
+ * column in the table of the data sheet and often used on schematics and
+ * such.
+ */
+static const struct pinctrl_pin_desc nmk_db8500_pins[] = {
+ PINCTRL_PIN(DB8500_PIN_AJ5, "GPIO0_AJ5"),
+ PINCTRL_PIN(DB8500_PIN_AJ3, "GPIO1_AJ3"),
+ PINCTRL_PIN(DB8500_PIN_AH4, "GPIO2_AH4"),
+ PINCTRL_PIN(DB8500_PIN_AH3, "GPIO3_AH3"),
+ PINCTRL_PIN(DB8500_PIN_AH6, "GPIO4_AH6"),
+ PINCTRL_PIN(DB8500_PIN_AG6, "GPIO5_AG6"),
+ PINCTRL_PIN(DB8500_PIN_AF6, "GPIO6_AF6"),
+ PINCTRL_PIN(DB8500_PIN_AG5, "GPIO7_AG5"),
+ PINCTRL_PIN(DB8500_PIN_AD5, "GPIO8_AD5"),
+ PINCTRL_PIN(DB8500_PIN_AE4, "GPIO9_AE4"),
+ PINCTRL_PIN(DB8500_PIN_AF5, "GPIO10_AF5"),
+ PINCTRL_PIN(DB8500_PIN_AG4, "GPIO11_AG4"),
+ PINCTRL_PIN(DB8500_PIN_AC4, "GPIO12_AC4"),
+ PINCTRL_PIN(DB8500_PIN_AF3, "GPIO13_AF3"),
+ PINCTRL_PIN(DB8500_PIN_AE3, "GPIO14_AE3"),
+ PINCTRL_PIN(DB8500_PIN_AC3, "GPIO15_AC3"),
+ PINCTRL_PIN(DB8500_PIN_AD3, "GPIO16_AD3"),
+ PINCTRL_PIN(DB8500_PIN_AD4, "GPIO17_AD4"),
+ PINCTRL_PIN(DB8500_PIN_AC2, "GPIO18_AC2"),
+ PINCTRL_PIN(DB8500_PIN_AC1, "GPIO19_AC1"),
+ PINCTRL_PIN(DB8500_PIN_AB4, "GPIO20_AB4"),
+ PINCTRL_PIN(DB8500_PIN_AB3, "GPIO21_AB3"),
+ PINCTRL_PIN(DB8500_PIN_AA3, "GPIO22_AA3"),
+ PINCTRL_PIN(DB8500_PIN_AA4, "GPIO23_AA4"),
+ PINCTRL_PIN(DB8500_PIN_AB2, "GPIO24_AB2"),
+ PINCTRL_PIN(DB8500_PIN_Y4, "GPIO25_Y4"),
+ PINCTRL_PIN(DB8500_PIN_Y2, "GPIO26_Y2"),
+ PINCTRL_PIN(DB8500_PIN_AA2, "GPIO27_AA2"),
+ PINCTRL_PIN(DB8500_PIN_AA1, "GPIO28_AA1"),
+ PINCTRL_PIN(DB8500_PIN_W2, "GPIO29_W2"),
+ PINCTRL_PIN(DB8500_PIN_W3, "GPIO30_W3"),
+ PINCTRL_PIN(DB8500_PIN_V3, "GPIO31_V3"),
+ PINCTRL_PIN(DB8500_PIN_V2, "GPIO32_V2"),
+ PINCTRL_PIN(DB8500_PIN_AF2, "GPIO33_AF2"),
+ PINCTRL_PIN(DB8500_PIN_AE1, "GPIO34_AE1"),
+ PINCTRL_PIN(DB8500_PIN_AE2, "GPIO35_AE2"),
+ PINCTRL_PIN(DB8500_PIN_AG2, "GPIO36_AG2"),
+ /* Hole */
+ PINCTRL_PIN(DB8500_PIN_F3, "GPIO64_F3"),
+ PINCTRL_PIN(DB8500_PIN_F1, "GPIO65_F1"),
+ PINCTRL_PIN(DB8500_PIN_G3, "GPIO66_G3"),
+ PINCTRL_PIN(DB8500_PIN_G2, "GPIO67_G2"),
+ PINCTRL_PIN(DB8500_PIN_E1, "GPIO68_E1"),
+ PINCTRL_PIN(DB8500_PIN_E2, "GPIO69_E2"),
+ PINCTRL_PIN(DB8500_PIN_G5, "GPIO70_G5"),
+ PINCTRL_PIN(DB8500_PIN_G4, "GPIO71_G4"),
+ PINCTRL_PIN(DB8500_PIN_H4, "GPIO72_H4"),
+ PINCTRL_PIN(DB8500_PIN_H3, "GPIO73_H3"),
+ PINCTRL_PIN(DB8500_PIN_J3, "GPIO74_J3"),
+ PINCTRL_PIN(DB8500_PIN_H2, "GPIO75_H2"),
+ PINCTRL_PIN(DB8500_PIN_J2, "GPIO76_J2"),
+ PINCTRL_PIN(DB8500_PIN_H1, "GPIO77_H1"),
+ PINCTRL_PIN(DB8500_PIN_F4, "GPIO78_F4"),
+ PINCTRL_PIN(DB8500_PIN_E3, "GPIO79_E3"),
+ PINCTRL_PIN(DB8500_PIN_E4, "GPIO80_E4"),
+ PINCTRL_PIN(DB8500_PIN_D2, "GPIO81_D2"),
+ PINCTRL_PIN(DB8500_PIN_C1, "GPIO82_C1"),
+ PINCTRL_PIN(DB8500_PIN_D3, "GPIO83_D3"),
+ PINCTRL_PIN(DB8500_PIN_C2, "GPIO84_C2"),
+ PINCTRL_PIN(DB8500_PIN_D5, "GPIO85_D5"),
+ PINCTRL_PIN(DB8500_PIN_C6, "GPIO86_C6"),
+ PINCTRL_PIN(DB8500_PIN_B3, "GPIO87_B3"),
+ PINCTRL_PIN(DB8500_PIN_C4, "GPIO88_C4"),
+ PINCTRL_PIN(DB8500_PIN_E6, "GPIO89_E6"),
+ PINCTRL_PIN(DB8500_PIN_A3, "GPIO90_A3"),
+ PINCTRL_PIN(DB8500_PIN_B6, "GPIO91_B6"),
+ PINCTRL_PIN(DB8500_PIN_D6, "GPIO92_D6"),
+ PINCTRL_PIN(DB8500_PIN_B7, "GPIO93_B7"),
+ PINCTRL_PIN(DB8500_PIN_D7, "GPIO94_D7"),
+ PINCTRL_PIN(DB8500_PIN_E8, "GPIO95_E8"),
+ PINCTRL_PIN(DB8500_PIN_D8, "GPIO96_D8"),
+ PINCTRL_PIN(DB8500_PIN_D9, "GPIO97_D9"),
+ /* Hole */
+ PINCTRL_PIN(DB8500_PIN_A5, "GPIO128_A5"),
+ PINCTRL_PIN(DB8500_PIN_B4, "GPIO129_B4"),
+ PINCTRL_PIN(DB8500_PIN_C8, "GPIO130_C8"),
+ PINCTRL_PIN(DB8500_PIN_A12, "GPIO131_A12"),
+ PINCTRL_PIN(DB8500_PIN_C10, "GPIO132_C10"),
+ PINCTRL_PIN(DB8500_PIN_B10, "GPIO133_B10"),
+ PINCTRL_PIN(DB8500_PIN_B9, "GPIO134_B9"),
+ PINCTRL_PIN(DB8500_PIN_A9, "GPIO135_A9"),
+ PINCTRL_PIN(DB8500_PIN_C7, "GPIO136_C7"),
+ PINCTRL_PIN(DB8500_PIN_A7, "GPIO137_A7"),
+ PINCTRL_PIN(DB8500_PIN_C5, "GPIO138_C5"),
+ PINCTRL_PIN(DB8500_PIN_C9, "GPIO139_C9"),
+ PINCTRL_PIN(DB8500_PIN_B11, "GPIO140_B11"),
+ PINCTRL_PIN(DB8500_PIN_C12, "GPIO141_C12"),
+ PINCTRL_PIN(DB8500_PIN_C11, "GPIO142_C11"),
+ PINCTRL_PIN(DB8500_PIN_D12, "GPIO143_D12"),
+ PINCTRL_PIN(DB8500_PIN_B13, "GPIO144_B13"),
+ PINCTRL_PIN(DB8500_PIN_C13, "GPIO145_C13"),
+ PINCTRL_PIN(DB8500_PIN_D13, "GPIO146_D13"),
+ PINCTRL_PIN(DB8500_PIN_C15, "GPIO147_C15"),
+ PINCTRL_PIN(DB8500_PIN_B16, "GPIO148_B16"),
+ PINCTRL_PIN(DB8500_PIN_B14, "GPIO149_B14"),
+ PINCTRL_PIN(DB8500_PIN_C14, "GPIO150_C14"),
+ PINCTRL_PIN(DB8500_PIN_D17, "GPIO151_D17"),
+ PINCTRL_PIN(DB8500_PIN_D16, "GPIO152_D16"),
+ PINCTRL_PIN(DB8500_PIN_B17, "GPIO153_B17"),
+ PINCTRL_PIN(DB8500_PIN_C16, "GPIO154_C16"),
+ PINCTRL_PIN(DB8500_PIN_C19, "GPIO155_C19"),
+ PINCTRL_PIN(DB8500_PIN_C17, "GPIO156_C17"),
+ PINCTRL_PIN(DB8500_PIN_A18, "GPIO157_A18"),
+ PINCTRL_PIN(DB8500_PIN_C18, "GPIO158_C18"),
+ PINCTRL_PIN(DB8500_PIN_B19, "GPIO159_B19"),
+ PINCTRL_PIN(DB8500_PIN_B20, "GPIO160_B20"),
+ PINCTRL_PIN(DB8500_PIN_D21, "GPIO161_D21"),
+ PINCTRL_PIN(DB8500_PIN_D20, "GPIO162_D20"),
+ PINCTRL_PIN(DB8500_PIN_C20, "GPIO163_C20"),
+ PINCTRL_PIN(DB8500_PIN_B21, "GPIO164_B21"),
+ PINCTRL_PIN(DB8500_PIN_C21, "GPIO165_C21"),
+ PINCTRL_PIN(DB8500_PIN_A22, "GPIO166_A22"),
+ PINCTRL_PIN(DB8500_PIN_B24, "GPIO167_B24"),
+ PINCTRL_PIN(DB8500_PIN_C22, "GPIO168_C22"),
+ PINCTRL_PIN(DB8500_PIN_D22, "GPIO169_D22"),
+ PINCTRL_PIN(DB8500_PIN_C23, "GPIO170_C23"),
+ PINCTRL_PIN(DB8500_PIN_D23, "GPIO171_D23"),
+ /* Hole */
+ PINCTRL_PIN(DB8500_PIN_AJ27, "GPIO192_AJ27"),
+ PINCTRL_PIN(DB8500_PIN_AH27, "GPIO193_AH27"),
+ PINCTRL_PIN(DB8500_PIN_AF27, "GPIO194_AF27"),
+ PINCTRL_PIN(DB8500_PIN_AG28, "GPIO195_AG28"),
+ PINCTRL_PIN(DB8500_PIN_AG26, "GPIO196_AG26"),
+ PINCTRL_PIN(DB8500_PIN_AH24, "GPIO197_AH24"),
+ PINCTRL_PIN(DB8500_PIN_AG25, "GPIO198_AG25"),
+ PINCTRL_PIN(DB8500_PIN_AH23, "GPIO199_AH23"),
+ PINCTRL_PIN(DB8500_PIN_AH26, "GPIO200_AH26"),
+ PINCTRL_PIN(DB8500_PIN_AF24, "GPIO201_AF24"),
+ PINCTRL_PIN(DB8500_PIN_AF25, "GPIO202_AF25"),
+ PINCTRL_PIN(DB8500_PIN_AE23, "GPIO203_AE23"),
+ PINCTRL_PIN(DB8500_PIN_AF23, "GPIO204_AF23"),
+ PINCTRL_PIN(DB8500_PIN_AG23, "GPIO205_AG23"),
+ PINCTRL_PIN(DB8500_PIN_AG24, "GPIO206_AG24"),
+ PINCTRL_PIN(DB8500_PIN_AJ23, "GPIO207_AJ23"),
+ PINCTRL_PIN(DB8500_PIN_AH16, "GPIO208_AH16"),
+ PINCTRL_PIN(DB8500_PIN_AG15, "GPIO209_AG15"),
+ PINCTRL_PIN(DB8500_PIN_AJ15, "GPIO210_AJ15"),
+ PINCTRL_PIN(DB8500_PIN_AG14, "GPIO211_AG14"),
+ PINCTRL_PIN(DB8500_PIN_AF13, "GPIO212_AF13"),
+ PINCTRL_PIN(DB8500_PIN_AG13, "GPIO213_AG13"),
+ PINCTRL_PIN(DB8500_PIN_AH15, "GPIO214_AH15"),
+ PINCTRL_PIN(DB8500_PIN_AH13, "GPIO215_AH13"),
+ PINCTRL_PIN(DB8500_PIN_AG12, "GPIO216_AG12"),
+ PINCTRL_PIN(DB8500_PIN_AH12, "GPIO217_AH12"),
+ PINCTRL_PIN(DB8500_PIN_AH11, "GPIO218_AH11"),
+ PINCTRL_PIN(DB8500_PIN_AG10, "GPIO219_AG10"),
+ PINCTRL_PIN(DB8500_PIN_AH10, "GPIO220_AH10"),
+ PINCTRL_PIN(DB8500_PIN_AJ11, "GPIO221_AJ11"),
+ PINCTRL_PIN(DB8500_PIN_AJ9, "GPIO222_AJ9"),
+ PINCTRL_PIN(DB8500_PIN_AH9, "GPIO223_AH9"),
+ PINCTRL_PIN(DB8500_PIN_AG9, "GPIO224_AG9"),
+ PINCTRL_PIN(DB8500_PIN_AG8, "GPIO225_AG8"),
+ PINCTRL_PIN(DB8500_PIN_AF8, "GPIO226_AF8"),
+ PINCTRL_PIN(DB8500_PIN_AH7, "GPIO227_AH7"),
+ PINCTRL_PIN(DB8500_PIN_AJ6, "GPIO228_AJ6"),
+ PINCTRL_PIN(DB8500_PIN_AG7, "GPIO229_AG7"),
+ PINCTRL_PIN(DB8500_PIN_AF7, "GPIO230_AF7"),
+ /* Hole */
+ PINCTRL_PIN(DB8500_PIN_AF28, "GPIO256_AF28"),
+ PINCTRL_PIN(DB8500_PIN_AE29, "GPIO257_AE29"),
+ PINCTRL_PIN(DB8500_PIN_AD29, "GPIO258_AD29"),
+ PINCTRL_PIN(DB8500_PIN_AC29, "GPIO259_AC29"),
+ PINCTRL_PIN(DB8500_PIN_AD28, "GPIO260_AD28"),
+ PINCTRL_PIN(DB8500_PIN_AD26, "GPIO261_AD26"),
+ PINCTRL_PIN(DB8500_PIN_AE26, "GPIO262_AE26"),
+ PINCTRL_PIN(DB8500_PIN_AG29, "GPIO263_AG29"),
+ PINCTRL_PIN(DB8500_PIN_AE27, "GPIO264_AE27"),
+ PINCTRL_PIN(DB8500_PIN_AD27, "GPIO265_AD27"),
+ PINCTRL_PIN(DB8500_PIN_AC28, "GPIO266_AC28"),
+ PINCTRL_PIN(DB8500_PIN_AC27, "GPIO267_AC27"),
+};
+
+#define DB8500_GPIO_RANGE(a, b, c) { .name = "DB8500", .id = a, .base = b, \
+ .pin_base = b, .npins = c }
+
+/*
+ * This matches the 32-pin gpio chips registered by the GPIO portion. This
+ * cannot be const since we assign the struct gpio_chip * pointer at runtime.
+ */
+static struct pinctrl_gpio_range nmk_db8500_ranges[] = {
+ DB8500_GPIO_RANGE(0, 0, 32),
+ DB8500_GPIO_RANGE(1, 32, 5),
+ DB8500_GPIO_RANGE(2, 64, 32),
+ DB8500_GPIO_RANGE(3, 96, 2),
+ DB8500_GPIO_RANGE(4, 128, 32),
+ DB8500_GPIO_RANGE(5, 160, 12),
+ DB8500_GPIO_RANGE(6, 192, 32),
+ DB8500_GPIO_RANGE(7, 224, 7),
+ DB8500_GPIO_RANGE(8, 256, 12),
+};
+
+/*
+ * Read the pin group names like this:
+ * u0_a_1 = first groups of pins for uart0 on alt function a
+ * i2c2_b_2 = second group of pins for i2c2 on alt function b
+ *
+ * The groups are arranged as sets per altfunction column, so we can
+ * mux in one group at a time by selecting the same altfunction for them
+ * all. When functions require pins on different altfunctions, you need
+ * to combine several groups.
+ */
+
+/* Altfunction A column */
+static const unsigned u0_a_1_pins[] = { DB8500_PIN_AJ5, DB8500_PIN_AJ3,
+ DB8500_PIN_AH4, DB8500_PIN_AH3 };
+static const unsigned u1rxtx_a_1_pins[] = { DB8500_PIN_AH6, DB8500_PIN_AG6 };
+static const unsigned u1ctsrts_a_1_pins[] = { DB8500_PIN_AF6, DB8500_PIN_AG5 };
+/* Image processor I2C line, this is driven by image processor firmware */
+static const unsigned ipi2c_a_1_pins[] = { DB8500_PIN_AD5, DB8500_PIN_AE4 };
+static const unsigned ipi2c_a_2_pins[] = { DB8500_PIN_AF5, DB8500_PIN_AG4 };
+/* MSP0 can only be on these pins, but TXD and RXD can be flipped */
+static const unsigned msp0txrx_a_1_pins[] = { DB8500_PIN_AC4, DB8500_PIN_AC3 };
+static const unsigned msp0tfstck_a_1_pins[] = { DB8500_PIN_AF3, DB8500_PIN_AE3 };
+static const unsigned msp0rfsrck_a_1_pins[] = { DB8500_PIN_AD3, DB8500_PIN_AD4 };
+/* Basic pins of the MMC/SD card 0 interface */
+static const unsigned mc0_a_1_pins[] = { DB8500_PIN_AC2, DB8500_PIN_AC1,
+ DB8500_PIN_AB4, DB8500_PIN_AA3, DB8500_PIN_AA4, DB8500_PIN_AB2,
+ DB8500_PIN_Y4, DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 };
+/* Often only 4 bits are used, then these are not needed (only used for MMC) */
+static const unsigned mc0_dat47_a_1_pins[] = { DB8500_PIN_W2, DB8500_PIN_W3,
+ DB8500_PIN_V3, DB8500_PIN_V2};
+static const unsigned mc0dat31dir_a_1_pins[] = { DB8500_PIN_AB3 };
+/* MSP1 can only be on these pins, but TXD and RXD can be flipped */
+static const unsigned msp1txrx_a_1_pins[] = { DB8500_PIN_AF2, DB8500_PIN_AG2 };
+static const unsigned msp1_a_1_pins[] = { DB8500_PIN_AE1, DB8500_PIN_AE2 };
+/* LCD interface */
+static const unsigned lcdb_a_1_pins[] = { DB8500_PIN_F3, DB8500_PIN_F1,
+ DB8500_PIN_G3, DB8500_PIN_G2 };
+static const unsigned lcdvsi0_a_1_pins[] = { DB8500_PIN_E1 };
+static const unsigned lcdvsi1_a_1_pins[] = { DB8500_PIN_E2 };
+static const unsigned lcd_d0_d7_a_1_pins[] = {
+ DB8500_PIN_G5, DB8500_PIN_G4, DB8500_PIN_H4, DB8500_PIN_H3,
+ DB8500_PIN_J3, DB8500_PIN_H2, DB8500_PIN_J2, DB8500_PIN_H1 };
+/* D8 thru D11 often used as TVOUT lines */
+static const unsigned lcd_d8_d11_a_1_pins[] = { DB8500_PIN_F4,
+ DB8500_PIN_E3, DB8500_PIN_E4, DB8500_PIN_D2 };
+static const unsigned lcd_d12_d23_a_1_pins[] = {
+ DB8500_PIN_C1, DB8500_PIN_D3, DB8500_PIN_C2, DB8500_PIN_D5,
+ DB8500_PIN_C6, DB8500_PIN_B3, DB8500_PIN_C4, DB8500_PIN_E6,
+ DB8500_PIN_A3, DB8500_PIN_B6, DB8500_PIN_D6, DB8500_PIN_B7 };
+static const unsigned kp_a_1_pins[] = { DB8500_PIN_D7, DB8500_PIN_E8,
+ DB8500_PIN_D8, DB8500_PIN_D9 };
+static const unsigned kpskaskb_a_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16 };
+static const unsigned kp_a_2_pins[] = {
+ DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17,
+ DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20,
+ DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21,
+ DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 };
+/* MC2 has 8 data lines and no direction control, so only for (e)MMC */
+static const unsigned mc2_a_1_pins[] = { DB8500_PIN_A5, DB8500_PIN_B4,
+ DB8500_PIN_C8, DB8500_PIN_A12, DB8500_PIN_C10, DB8500_PIN_B10,
+ DB8500_PIN_B9, DB8500_PIN_A9, DB8500_PIN_C7, DB8500_PIN_A7,
+ DB8500_PIN_C5 };
+static const unsigned ssp1_a_1_pins[] = { DB8500_PIN_C9, DB8500_PIN_B11,
+ DB8500_PIN_C12, DB8500_PIN_C11 };
+static const unsigned ssp0_a_1_pins[] = { DB8500_PIN_D12, DB8500_PIN_B13,
+ DB8500_PIN_C13, DB8500_PIN_D13 };
+static const unsigned i2c0_a_1_pins[] = { DB8500_PIN_C15, DB8500_PIN_B16 };
+/*
+ * Image processor GPIO pins are named "ipgpio" and have their own
+ * numberspace
+ */
+static const unsigned ipgpio0_a_1_pins[] = { DB8500_PIN_B14 };
+static const unsigned ipgpio1_a_1_pins[] = { DB8500_PIN_C14 };
+/* Three modem pins named RF_PURn, MODEM_STATE and MODEM_PWREN */
+static const unsigned modem_a_1_pins[] = { DB8500_PIN_D22, DB8500_PIN_C23,
+ DB8500_PIN_D23 };
+/*
+ * This MSP cannot switch RX and TX, SCK in a separate group since this
+ * seems to be optional.
+ */
+static const unsigned msp2sck_a_1_pins[] = { DB8500_PIN_AJ27 };
+static const unsigned msp2_a_1_pins[] = { DB8500_PIN_AH27, DB8500_PIN_AF27,
+ DB8500_PIN_AG28, DB8500_PIN_AG26 };
+static const unsigned mc4_a_1_pins[] = { DB8500_PIN_AH24, DB8500_PIN_AG25,
+ DB8500_PIN_AH23, DB8500_PIN_AH26, DB8500_PIN_AF24, DB8500_PIN_AF25,
+ DB8500_PIN_AE23, DB8500_PIN_AF23, DB8500_PIN_AG23, DB8500_PIN_AG24,
+ DB8500_PIN_AJ23 };
+/* MC1 has only 4 data pins, designed for SD or SDIO exclusively */
+static const unsigned mc1_a_1_pins[] = { DB8500_PIN_AH16, DB8500_PIN_AG15,
+ DB8500_PIN_AJ15, DB8500_PIN_AG14, DB8500_PIN_AF13, DB8500_PIN_AG13,
+ DB8500_PIN_AH15 };
+static const unsigned mc1dir_a_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AG12,
+ DB8500_PIN_AH12, DB8500_PIN_AH11 };
+static const unsigned hsir_a_1_pins[] = { DB8500_PIN_AG10, DB8500_PIN_AH10 };
+static const unsigned hsit_a_1_pins[] = { DB8500_PIN_AJ11, DB8500_PIN_AJ9,
+ DB8500_PIN_AH9, DB8500_PIN_AG9, DB8500_PIN_AG8, DB8500_PIN_AF8 };
+static const unsigned clkout_a_1_pins[] = { DB8500_PIN_AH7, DB8500_PIN_AJ6 };
+static const unsigned clkout_a_2_pins[] = { DB8500_PIN_AG7, DB8500_PIN_AF7 };
+static const unsigned usb_a_1_pins[] = { DB8500_PIN_AF28, DB8500_PIN_AE29,
+ DB8500_PIN_AD29, DB8500_PIN_AC29, DB8500_PIN_AD28, DB8500_PIN_AD26,
+ DB8500_PIN_AE26, DB8500_PIN_AG29, DB8500_PIN_AE27, DB8500_PIN_AD27,
+ DB8500_PIN_AC28, DB8500_PIN_AC27 };
+
+/* Altfunction B column */
+static const unsigned trig_b_1_pins[] = { DB8500_PIN_AJ5, DB8500_PIN_AJ3 };
+static const unsigned i2c4_b_1_pins[] = { DB8500_PIN_AH6, DB8500_PIN_AG6 };
+static const unsigned i2c1_b_1_pins[] = { DB8500_PIN_AF6, DB8500_PIN_AG5 };
+static const unsigned i2c2_b_1_pins[] = { DB8500_PIN_AD5, DB8500_PIN_AE4 };
+static const unsigned i2c2_b_2_pins[] = { DB8500_PIN_AF5, DB8500_PIN_AG4 };
+static const unsigned msp0txrx_b_1_pins[] = { DB8500_PIN_AC4, DB8500_PIN_AC3 };
+static const unsigned i2c1_b_2_pins[] = { DB8500_PIN_AD3, DB8500_PIN_AD4 };
+/* Just RX and TX for UART2 */
+static const unsigned u2rxtx_b_1_pins[] = { DB8500_PIN_AC2, DB8500_PIN_AC1 };
+static const unsigned uartmodtx_b_1_pins[] = { DB8500_PIN_AB4 };
+static const unsigned msp0sck_b_1_pins[] = { DB8500_PIN_AB3 };
+static const unsigned uartmodrx_b_1_pins[] = { DB8500_PIN_AA3 };
+static const unsigned stmmod_b_1_pins[] = { DB8500_PIN_AA4, DB8500_PIN_Y4,
+ DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 };
+static const unsigned uartmodrx_b_2_pins[] = { DB8500_PIN_AB2 };
+static const unsigned spi3_b_1_pins[] = { DB8500_PIN_W2, DB8500_PIN_W3,
+ DB8500_PIN_V3, DB8500_PIN_V2 };
+static const unsigned msp1txrx_b_1_pins[] = { DB8500_PIN_AF2, DB8500_PIN_AG2 };
+static const unsigned kp_b_1_pins[] = { DB8500_PIN_F3, DB8500_PIN_F1,
+ DB8500_PIN_G3, DB8500_PIN_G2, DB8500_PIN_E1, DB8500_PIN_E2,
+ DB8500_PIN_G5, DB8500_PIN_G4, DB8500_PIN_H4, DB8500_PIN_H3,
+ DB8500_PIN_J3, DB8500_PIN_H2, DB8500_PIN_J2, DB8500_PIN_H1,
+ DB8500_PIN_F4, DB8500_PIN_E3, DB8500_PIN_E4, DB8500_PIN_D2,
+ DB8500_PIN_C1, DB8500_PIN_D3, DB8500_PIN_C2, DB8500_PIN_D5 };
+static const unsigned sm_b_1_pins[] = { DB8500_PIN_C6, DB8500_PIN_B3,
+ DB8500_PIN_C4, DB8500_PIN_E6, DB8500_PIN_A3, DB8500_PIN_B6,
+ DB8500_PIN_D6, DB8500_PIN_B7, DB8500_PIN_D7, DB8500_PIN_D8,
+ DB8500_PIN_D9, DB8500_PIN_A5, DB8500_PIN_B4, DB8500_PIN_C8,
+ DB8500_PIN_A12, DB8500_PIN_C10, DB8500_PIN_B10, DB8500_PIN_B9,
+ DB8500_PIN_A9, DB8500_PIN_C7, DB8500_PIN_A7, DB8500_PIN_C5,
+ DB8500_PIN_C9, DB8500_PIN_B14 };
+/* This chip select pin can be "ps0" in alt B so have it separately */
+static const unsigned smcs0_b_1_pins[] = { DB8500_PIN_E8 };
+static const unsigned ipgpio7_b_1_pins[] = { DB8500_PIN_B11 };
+static const unsigned ipgpio2_b_1_pins[] = { DB8500_PIN_C12 };
+static const unsigned ipgpio3_b_1_pins[] = { DB8500_PIN_C11 };
+static const unsigned lcdaclk_b_1_pins[] = { DB8500_PIN_C14 };
+static const unsigned lcda_b_1_pins[] = { DB8500_PIN_D22,
+ DB8500_PIN_C23, DB8500_PIN_D23 };
+static const unsigned lcd_b_1_pins[] = { DB8500_PIN_D17, DB8500_PIN_D16,
+ DB8500_PIN_B17, DB8500_PIN_C16, DB8500_PIN_C19, DB8500_PIN_C17,
+ DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19, DB8500_PIN_B20,
+ DB8500_PIN_D21, DB8500_PIN_D20, DB8500_PIN_C20, DB8500_PIN_B21,
+ DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24, DB8500_PIN_C22 };
+static const unsigned ddrtrig_b_1_pins[] = { DB8500_PIN_AJ27 };
+static const unsigned pwl_b_1_pins[] = { DB8500_PIN_AF25 };
+static const unsigned spi1_b_1_pins[] = { DB8500_PIN_AG15, DB8500_PIN_AF13,
+ DB8500_PIN_AG13, DB8500_PIN_AH15 };
+static const unsigned mc3_b_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AG12,
+ DB8500_PIN_AH12, DB8500_PIN_AH11, DB8500_PIN_AG10, DB8500_PIN_AH10,
+ DB8500_PIN_AJ11, DB8500_PIN_AJ9, DB8500_PIN_AH9, DB8500_PIN_AG9,
+ DB8500_PIN_AG8 };
+static const unsigned pwl_b_2_pins[] = { DB8500_PIN_AF8 };
+static const unsigned pwl_b_3_pins[] = { DB8500_PIN_AG7 };
+static const unsigned pwl_b_4_pins[] = { DB8500_PIN_AF7 };
+
+/* Altfunction C column */
+static const unsigned ipjtag_c_1_pins[] = { DB8500_PIN_AJ5, DB8500_PIN_AJ3,
+ DB8500_PIN_AH4, DB8500_PIN_AH3, DB8500_PIN_AH6 };
+static const unsigned ipgpio6_c_1_pins[] = { DB8500_PIN_AG6 };
+static const unsigned ipgpio0_c_1_pins[] = { DB8500_PIN_AF6 };
+static const unsigned ipgpio1_c_1_pins[] = { DB8500_PIN_AG5 };
+static const unsigned ipgpio3_c_1_pins[] = { DB8500_PIN_AF5 };
+static const unsigned ipgpio2_c_1_pins[] = { DB8500_PIN_AG4 };
+static const unsigned slim0_c_1_pins[] = { DB8500_PIN_AD3, DB8500_PIN_AD4 };
+/* Optional 4-bit Memory Stick interface */
+static const unsigned ms_c_1_pins[] = { DB8500_PIN_AC2, DB8500_PIN_AC1,
+ DB8500_PIN_AB3, DB8500_PIN_AA3, DB8500_PIN_AA4, DB8500_PIN_AB2,
+ DB8500_PIN_Y4, DB8500_PIN_Y2, DB8500_PIN_AA2, DB8500_PIN_AA1 };
+static const unsigned iptrigout_c_1_pins[] = { DB8500_PIN_AB4 };
+static const unsigned u2rxtx_c_1_pins[] = { DB8500_PIN_W2, DB8500_PIN_W3 };
+static const unsigned u2ctsrts_c_1_pins[] = { DB8500_PIN_V3, DB8500_PIN_V2 };
+static const unsigned u0_c_1_pins[] = { DB8500_PIN_AF2, DB8500_PIN_AE1,
+ DB8500_PIN_AE2, DB8500_PIN_AG2 };
+static const unsigned ipgpio4_c_1_pins[] = { DB8500_PIN_F3 };
+static const unsigned ipgpio5_c_1_pins[] = { DB8500_PIN_F1 };
+static const unsigned ipgpio6_c_2_pins[] = { DB8500_PIN_G3 };
+static const unsigned ipgpio7_c_1_pins[] = { DB8500_PIN_G2 };
+static const unsigned smcleale_c_1_pins[] = { DB8500_PIN_E1, DB8500_PIN_E2 };
+static const unsigned stmape_c_1_pins[] = { DB8500_PIN_G5, DB8500_PIN_G4,
+ DB8500_PIN_H4, DB8500_PIN_H3, DB8500_PIN_J3 };
+static const unsigned u2rxtx_c_2_pins[] = { DB8500_PIN_H2, DB8500_PIN_J2 };
+static const unsigned ipgpio2_c_2_pins[] = { DB8500_PIN_F4 };
+static const unsigned ipgpio3_c_2_pins[] = { DB8500_PIN_E3 };
+static const unsigned ipgpio4_c_2_pins[] = { DB8500_PIN_E4 };
+static const unsigned ipgpio5_c_2_pins[] = { DB8500_PIN_D2 };
+static const unsigned mc5_c_1_pins[] = { DB8500_PIN_C6, DB8500_PIN_B3,
+ DB8500_PIN_C4, DB8500_PIN_E6, DB8500_PIN_A3, DB8500_PIN_B6,
+ DB8500_PIN_D6, DB8500_PIN_B7, DB8500_PIN_D7, DB8500_PIN_D8,
+ DB8500_PIN_D9 };
+static const unsigned mc2rstn_c_1_pins[] = { DB8500_PIN_C8 };
+static const unsigned kp_c_1_pins[] = { DB8500_PIN_C9, DB8500_PIN_B11,
+ DB8500_PIN_C12, DB8500_PIN_C11, DB8500_PIN_D17, DB8500_PIN_D16,
+ DB8500_PIN_C23, DB8500_PIN_D23 };
+static const unsigned smps1_c_1_pins[] = { DB8500_PIN_B14 };
+static const unsigned u2rxtx_c_3_pins[] = { DB8500_PIN_B17, DB8500_PIN_C16 };
+static const unsigned stmape_c_2_pins[] = { DB8500_PIN_C19, DB8500_PIN_C17,
+ DB8500_PIN_A18, DB8500_PIN_C18, DB8500_PIN_B19 };
+static const unsigned uartmodrx_c_1_pins[] = { DB8500_PIN_D21 };
+static const unsigned uartmodtx_c_1_pins[] = { DB8500_PIN_D20 };
+static const unsigned stmmod_c_1_pins[] = { DB8500_PIN_C20, DB8500_PIN_B21,
+ DB8500_PIN_C21, DB8500_PIN_A22, DB8500_PIN_B24 };
+static const unsigned usbsim_c_1_pins[] = { DB8500_PIN_D22 };
+static const unsigned mc4rstn_c_1_pins[] = { DB8500_PIN_AF25 };
+static const unsigned clkout_c_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AH12 };
+static const unsigned i2c3_c_1_pins[] = { DB8500_PIN_AG12, DB8500_PIN_AH11 };
+static const unsigned spi0_c_1_pins[] = { DB8500_PIN_AH10, DB8500_PIN_AH9,
+ DB8500_PIN_AG9, DB8500_PIN_AG8 };
+static const unsigned usbsim_c_2_pins[] = { DB8500_PIN_AF8 };
+static const unsigned i2c3_c_2_pins[] = { DB8500_PIN_AG7, DB8500_PIN_AF7 };
+
+/* Other C1 column */
+static const unsigned kp_oc1_1_pins[] = { DB8500_PIN_C6, DB8500_PIN_B3,
+ DB8500_PIN_C4, DB8500_PIN_E6, DB8500_PIN_A3, DB8500_PIN_B6,
+ DB8500_PIN_D6, DB8500_PIN_B7 };
+static const unsigned spi2_oc1_1_pins[] = { DB8500_PIN_AH13, DB8500_PIN_AG12,
+ DB8500_PIN_AH12, DB8500_PIN_AH11 };
+
+#define DB8500_PIN_GROUP(a,b) { .name = #a, .pins = a##_pins, \
+ .npins = ARRAY_SIZE(a##_pins), .altsetting = b }
+
+static const struct nmk_pingroup nmk_db8500_groups[] = {
+ /* Altfunction A column */
+ DB8500_PIN_GROUP(u0_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(u1rxtx_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(u1ctsrts_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(ipi2c_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(ipi2c_a_2, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(msp0txrx_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(msp0tfstck_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(msp0rfsrck_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(mc0_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(msp1txrx_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(msp1_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(lcdb_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(lcdvsi0_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(lcdvsi1_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(lcd_d0_d7_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(lcd_d8_d11_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(lcd_d12_d23_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(kp_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(mc2_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(ssp1_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(ssp0_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(i2c0_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(ipgpio0_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(ipgpio1_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(msp2sck_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(msp2_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(mc4_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(mc1_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(hsir_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(hsit_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(clkout_a_1, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(clkout_a_2, NMK_GPIO_ALT_A),
+ DB8500_PIN_GROUP(usb_a_1, NMK_GPIO_ALT_A),
+ /* Altfunction B column */
+ DB8500_PIN_GROUP(trig_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(i2c4_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(i2c1_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(i2c2_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(i2c2_b_2, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(msp0txrx_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(i2c1_b_2, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(u2rxtx_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(uartmodtx_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(msp0sck_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(uartmodrx_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(stmmod_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(uartmodrx_b_2, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(spi3_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(msp1txrx_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(kp_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(sm_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(smcs0_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(ipgpio7_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(ipgpio2_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(ipgpio3_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(lcdaclk_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(lcda_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(lcd_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(ddrtrig_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(pwl_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(spi1_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(mc3_b_1, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(pwl_b_2, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(pwl_b_3, NMK_GPIO_ALT_B),
+ DB8500_PIN_GROUP(pwl_b_4, NMK_GPIO_ALT_B),
+ /* Altfunction C column */
+ DB8500_PIN_GROUP(ipjtag_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio6_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio0_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio1_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio3_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio2_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(slim0_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ms_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(iptrigout_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(u2rxtx_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(u2ctsrts_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(u0_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio4_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio5_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio6_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio7_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(smcleale_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(stmape_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(u2rxtx_c_2, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio2_c_2, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio3_c_2, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio4_c_2, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(ipgpio5_c_2, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(mc5_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(mc2rstn_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(kp_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(smps1_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(u2rxtx_c_3, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(stmape_c_2, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(uartmodrx_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(uartmodtx_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(stmmod_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(usbsim_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(mc4rstn_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(clkout_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(i2c3_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(spi0_c_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(usbsim_c_2, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(i2c3_c_2, NMK_GPIO_ALT_C),
+ /* Other alt C1 column, these are still configured as alt C */
+ DB8500_PIN_GROUP(kp_oc1_1, NMK_GPIO_ALT_C),
+ DB8500_PIN_GROUP(spi2_oc1_1, NMK_GPIO_ALT_C),
+};
+
+/* We use this macro to define the groups applicable to a function */
+#define DB8500_FUNC_GROUPS(a, b...) \
+static const char * const a##_groups[] = { b };
+
+DB8500_FUNC_GROUPS(u0, "u0_a_1", "u0_c_1");
+DB8500_FUNC_GROUPS(u1, "u1rxtx_a_1", "u1ctsrts_a_1");
+/*
+ * UART2 can be muxed out with just RX/TX in four places, CTS+RTS is however
+ * only available on two pins in alternative function C
+ */
+DB8500_FUNC_GROUPS(u2, "u2rxtx_b_1", "u2rxtx_c_1", "u2ctsrts_c_1",
+ "u2rxtx_c_2", "u2rxtx_c_3");
+DB8500_FUNC_GROUPS(ipi2c, "ipi2c_a_1", "ipi2c_a_2");
+/*
+ * MSP0 can only be on a certain set of pins, but the TX/RX pins can be
+ * switched around by selecting the altfunction A or B. The SCK pin is
+ * only available on the altfunction B.
+ */
+DB8500_FUNC_GROUPS(msp0, "msp0txrx_a_1", "msp0tfstck_a_1", "msp0rfstck_a_1",
+ "msp0txrx_b_1", "msp0sck_b_1");
+DB8500_FUNC_GROUPS(mc0, "mc0_a_1");
+/* MSP0 can swap RX/TX like MSP0 but has no SCK pin available */
+DB8500_FUNC_GROUPS(msp1, "msp1txrx_a_1", "msp1_a_1", "msp1txrx_b_1");
+DB8500_FUNC_GROUPS(lcdb, "lcdb_a_1");
+DB8500_FUNC_GROUPS(lcd, "lcdvsi0_a_1", "lcdvsi1_a_1", "lcd_d0_d7_a_1",
+ "lcd_d8_d11_a_1", "lcd_d12_d23_a_1", "lcd_b_1");
+DB8500_FUNC_GROUPS(kp, "kp_a_1", "kp_b_1", "kp_c_1", "kp_oc1_1");
+DB8500_FUNC_GROUPS(mc2, "mc2_a_1", "mc2rstn_c_1");
+DB8500_FUNC_GROUPS(ssp1, "ssp1_a_1");
+DB8500_FUNC_GROUPS(ssp0, "ssp0_a_1");
+DB8500_FUNC_GROUPS(i2c0, "i2c0_a_1");
+/* The image processor has 8 GPIO pins that can be muxed out */
+DB8500_FUNC_GROUPS(ipgpio, "ipgpio0_a_1", "ipgpio1_a_1", "ipgpio7_b_1",
+ "ipgpio2_b_1", "ipgpio3_b_1", "ipgpio6_c_1", "ipgpio0_c_1",
+ "ipgpio1_c_1", "ipgpio3_c_1", "ipgpio2_c_1", "ipgpio4_c_1",
+ "ipgpio5_c_1", "ipgpio6_c_2", "ipgpio7_c_1", "ipgpio2_c_2",
+ "ipgpio3_c_2", "ipgpio4_c_2", "ipgpio5_c_2");
+/* MSP2 can not invert the RX/TX pins but has the optional SCK pin */
+DB8500_FUNC_GROUPS(msp2, "msp2sck_a_1", "msp2_a_1");
+DB8500_FUNC_GROUPS(mc4, "mc4_a_1", "mc4rstn_c_1");
+DB8500_FUNC_GROUPS(mc1, "mc1_a_1", "mc1dir_a_1");
+DB8500_FUNC_GROUPS(hsi, "hsir1_a_1", "hsit1_a_1");
+DB8500_FUNC_GROUPS(clkout, "clkout_a_1", "clkout_a_2", "clkout_c_1");
+DB8500_FUNC_GROUPS(usb, "usb_a_1");
+DB8500_FUNC_GROUPS(trig, "trig_b_1");
+DB8500_FUNC_GROUPS(i2c4, "i2c4_b_1");
+DB8500_FUNC_GROUPS(i2c1, "i2c1_b_1", "i2c1_b_2");
+DB8500_FUNC_GROUPS(i2c2, "i2c2_b_1", "i2c2_b_2");
+/*
+ * The modem UART can output its RX and TX pins in some different places,
+ * so select one of each.
+ */
+DB8500_FUNC_GROUPS(uartmod, "uartmodtx_b_1", "uartmodrx_b_1", "uartmodrx_b_2",
+ "uartmodrx_c_1", "uartmod_tx_c_1");
+DB8500_FUNC_GROUPS(stmmod, "stmmod_b_1", "stmmod_c_1");
+DB8500_FUNC_GROUPS(spi3, "spi3_b_1");
+/* Select between CS0 on alt B or PS1 on alt C */
+DB8500_FUNC_GROUPS(sm, "sm_b_1", "smcs0_b_1", "smcleale_c_1", "smps1_c_1");
+DB8500_FUNC_GROUPS(lcda, "lcdaclk_b_1", "lcda_b_1");
+DB8500_FUNC_GROUPS(ddrtrig, "ddrtrig_b_1");
+DB8500_FUNC_GROUPS(pwl, "pwl_b_1", "pwl_b_2", "pwl_b_3", "pwl_b_4");
+DB8500_FUNC_GROUPS(spi1, "spi1_b_1");
+DB8500_FUNC_GROUPS(mc3, "mc3_b_1");
+DB8500_FUNC_GROUPS(ipjtag, "ipjtag_c_1");
+DB8500_FUNC_GROUPS(slim0, "slim0_c_1");
+DB8500_FUNC_GROUPS(ms, "ms_c_1");
+DB8500_FUNC_GROUPS(iptrigout, "iptrigout_c_1");
+DB8500_FUNC_GROUPS(stmape, "stmape_c_1", "stmape_c_2");
+DB8500_FUNC_GROUPS(mc5, "mc5_c_1");
+DB8500_FUNC_GROUPS(usbsim, "usbsim_c_1", "usbsim_c_2");
+DB8500_FUNC_GROUPS(i2c3, "i2c3_c_1", "i2c3_c_2");
+DB8500_FUNC_GROUPS(spi0, "spi0_c_1");
+DB8500_FUNC_GROUPS(spi2, "spi2_oc1_1");
+
+#define FUNCTION(fname) \
+ { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+static const struct nmk_function nmk_db8500_functions[] = {
+ FUNCTION(u0),
+ FUNCTION(u1),
+ FUNCTION(u2),
+ FUNCTION(ipi2c),
+ FUNCTION(msp0),
+ FUNCTION(mc0),
+ FUNCTION(msp1),
+ FUNCTION(lcdb),
+ FUNCTION(lcd),
+ FUNCTION(kp),
+ FUNCTION(mc2),
+ FUNCTION(ssp1),
+ FUNCTION(ssp0),
+ FUNCTION(i2c0),
+ FUNCTION(ipgpio),
+ FUNCTION(msp2),
+ FUNCTION(mc4),
+ FUNCTION(mc1),
+ FUNCTION(hsi),
+ FUNCTION(clkout),
+ FUNCTION(usb),
+ FUNCTION(trig),
+ FUNCTION(i2c4),
+ FUNCTION(i2c1),
+ FUNCTION(i2c2),
+ FUNCTION(uartmod),
+ FUNCTION(stmmod),
+ FUNCTION(spi3),
+ FUNCTION(sm),
+ FUNCTION(lcda),
+ FUNCTION(ddrtrig),
+ FUNCTION(pwl),
+ FUNCTION(spi1),
+ FUNCTION(mc3),
+ FUNCTION(ipjtag),
+ FUNCTION(slim0),
+ FUNCTION(ms),
+ FUNCTION(iptrigout),
+ FUNCTION(stmape),
+ FUNCTION(mc5),
+ FUNCTION(usbsim),
+ FUNCTION(i2c3),
+ FUNCTION(spi0),
+ FUNCTION(spi2),
+};
+
+static const struct nmk_pinctrl_soc_data nmk_db8500_soc = {
+ .gpio_ranges = nmk_db8500_ranges,
+ .gpio_num_ranges = ARRAY_SIZE(nmk_db8500_ranges),
+ .pins = nmk_db8500_pins,
+ .npins = ARRAY_SIZE(nmk_db8500_pins),
+ .functions = nmk_db8500_functions,
+ .nfunctions = ARRAY_SIZE(nmk_db8500_functions),
+ .groups = nmk_db8500_groups,
+ .ngroups = ARRAY_SIZE(nmk_db8500_groups),
+};
+
+void __devinit
+nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc)
+{
+ *soc = &nmk_db8500_soc;
+}
diff --git a/drivers/gpio/gpio-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c
index 839624f9fe6a..b8e01c3eaa95 100644
--- a/drivers/gpio/gpio-nomadik.c
+++ b/drivers/pinctrl/pinctrl-nomadik.c
@@ -22,14 +22,20 @@
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/slab.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+/* Since we request GPIOs from ourself */
+#include <linux/pinctrl/consumer.h>
#include <asm/mach/irq.h>
#include <plat/pincfg.h>
#include <plat/gpio-nomadik.h>
-#include <mach/hardware.h>
-#include <asm/gpio.h>
+
+#include "pinctrl-nomadik.h"
/*
* The GPIO module in the Nomadik family of Systems-on-Chip is an
@@ -43,6 +49,7 @@
struct nmk_gpio_chip {
struct gpio_chip chip;
+ struct irq_domain *domain;
void __iomem *addr;
struct clk *clk;
unsigned int bank;
@@ -58,8 +65,16 @@ struct nmk_gpio_chip {
u32 real_wake;
u32 rwimsc;
u32 fwimsc;
- u32 slpm;
+ u32 rimsc;
+ u32 fimsc;
u32 pull_up;
+ u32 lowemi;
+};
+
+struct nmk_pinctrl {
+ struct device *dev;
+ struct pinctrl_dev *pctl;
+ const struct nmk_pinctrl_soc_data *soc;
};
static struct nmk_gpio_chip *
@@ -124,6 +139,24 @@ static void __nmk_gpio_set_pull(struct nmk_gpio_chip *nmk_chip,
}
}
+static void __nmk_gpio_set_lowemi(struct nmk_gpio_chip *nmk_chip,
+ unsigned offset, bool lowemi)
+{
+ u32 bit = BIT(offset);
+ bool enabled = nmk_chip->lowemi & bit;
+
+ if (lowemi == enabled)
+ return;
+
+ if (lowemi)
+ nmk_chip->lowemi |= bit;
+ else
+ nmk_chip->lowemi &= ~bit;
+
+ writel_relaxed(nmk_chip->lowemi,
+ nmk_chip->addr + NMK_GPIO_LOWEMI);
+}
+
static void __nmk_gpio_make_input(struct nmk_gpio_chip *nmk_chip,
unsigned offset)
{
@@ -150,8 +183,8 @@ static void __nmk_gpio_set_mode_safe(struct nmk_gpio_chip *nmk_chip,
unsigned offset, int gpio_mode,
bool glitch)
{
- u32 rwimsc = readl(nmk_chip->addr + NMK_GPIO_RWIMSC);
- u32 fwimsc = readl(nmk_chip->addr + NMK_GPIO_FWIMSC);
+ u32 rwimsc = nmk_chip->rwimsc;
+ u32 fwimsc = nmk_chip->fwimsc;
if (glitch && nmk_chip->set_ioforce) {
u32 bit = BIT(offset);
@@ -173,6 +206,36 @@ static void __nmk_gpio_set_mode_safe(struct nmk_gpio_chip *nmk_chip,
}
}
+static void
+nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset)
+{
+ u32 falling = nmk_chip->fimsc & BIT(offset);
+ u32 rising = nmk_chip->rimsc & BIT(offset);
+ int gpio = nmk_chip->chip.base + offset;
+ int irq = NOMADIK_GPIO_TO_IRQ(gpio);
+ struct irq_data *d = irq_get_irq_data(irq);
+
+ if (!rising && !falling)
+ return;
+
+ if (!d || !irqd_irq_disabled(d))
+ return;
+
+ if (rising) {
+ nmk_chip->rimsc &= ~BIT(offset);
+ writel_relaxed(nmk_chip->rimsc,
+ nmk_chip->addr + NMK_GPIO_RIMSC);
+ }
+
+ if (falling) {
+ nmk_chip->fimsc &= ~BIT(offset);
+ writel_relaxed(nmk_chip->fimsc,
+ nmk_chip->addr + NMK_GPIO_FIMSC);
+ }
+
+ dev_dbg(nmk_chip->chip.dev, "%d: clearing interrupt mask\n", gpio);
+}
+
static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
pin_cfg_t cfg, bool sleep, unsigned int *slpmregs)
{
@@ -238,6 +301,17 @@ static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
__nmk_gpio_set_pull(nmk_chip, offset, pull);
}
+ __nmk_gpio_set_lowemi(nmk_chip, offset, PIN_LOWEMI(cfg));
+
+ /*
+ * If the pin is switching to altfunc, and there was an interrupt
+ * installed on it which has been lazy disabled, actually mask the
+ * interrupt to prevent spurious interrupts that would occur while the
+ * pin is under control of the peripheral. Only SKE does this.
+ */
+ if (af != NMK_GPIO_ALT_GPIO)
+ nmk_gpio_disable_lazy_irq(nmk_chip, offset);
+
/*
* If we've backed up the SLPM registers (glitch workaround), modify
* the backups since they will be restored.
@@ -334,7 +408,7 @@ static int __nmk_config_pins(pin_cfg_t *cfgs, int num, bool sleep)
struct nmk_gpio_chip *nmk_chip;
int pin = PIN_NUM(cfgs[i]);
- nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(pin));
+ nmk_chip = nmk_gpio_chips[pin / NMK_GPIO_PER_CHIP];
if (!nmk_chip) {
ret = -EINVAL;
break;
@@ -342,7 +416,7 @@ static int __nmk_config_pins(pin_cfg_t *cfgs, int num, bool sleep)
clk_enable(nmk_chip->clk);
spin_lock(&nmk_chip->lock);
- __nmk_config_pin(nmk_chip, pin - nmk_chip->chip.base,
+ __nmk_config_pin(nmk_chip, pin % NMK_GPIO_PER_CHIP,
cfgs[i], sleep, glitch ? slpm : NULL);
spin_unlock(&nmk_chip->lock);
clk_disable(nmk_chip->clk);
@@ -426,7 +500,7 @@ int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode)
struct nmk_gpio_chip *nmk_chip;
unsigned long flags;
- nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
+ nmk_chip = nmk_gpio_chips[gpio / NMK_GPIO_PER_CHIP];
if (!nmk_chip)
return -EINVAL;
@@ -434,7 +508,7 @@ int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode)
spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
spin_lock(&nmk_chip->lock);
- __nmk_gpio_set_slpm(nmk_chip, gpio - nmk_chip->chip.base, mode);
+ __nmk_gpio_set_slpm(nmk_chip, gpio % NMK_GPIO_PER_CHIP, mode);
spin_unlock(&nmk_chip->lock);
spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
@@ -461,13 +535,13 @@ int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull)
struct nmk_gpio_chip *nmk_chip;
unsigned long flags;
- nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
+ nmk_chip = nmk_gpio_chips[gpio / NMK_GPIO_PER_CHIP];
if (!nmk_chip)
return -EINVAL;
clk_enable(nmk_chip->clk);
spin_lock_irqsave(&nmk_chip->lock, flags);
- __nmk_gpio_set_pull(nmk_chip, gpio - nmk_chip->chip.base, pull);
+ __nmk_gpio_set_pull(nmk_chip, gpio % NMK_GPIO_PER_CHIP, pull);
spin_unlock_irqrestore(&nmk_chip->lock, flags);
clk_disable(nmk_chip->clk);
@@ -489,13 +563,13 @@ int nmk_gpio_set_mode(int gpio, int gpio_mode)
struct nmk_gpio_chip *nmk_chip;
unsigned long flags;
- nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
+ nmk_chip = nmk_gpio_chips[gpio / NMK_GPIO_PER_CHIP];
if (!nmk_chip)
return -EINVAL;
clk_enable(nmk_chip->clk);
spin_lock_irqsave(&nmk_chip->lock, flags);
- __nmk_gpio_set_mode(nmk_chip, gpio - nmk_chip->chip.base, gpio_mode);
+ __nmk_gpio_set_mode(nmk_chip, gpio % NMK_GPIO_PER_CHIP, gpio_mode);
spin_unlock_irqrestore(&nmk_chip->lock, flags);
clk_disable(nmk_chip->clk);
@@ -508,11 +582,11 @@ int nmk_gpio_get_mode(int gpio)
struct nmk_gpio_chip *nmk_chip;
u32 afunc, bfunc, bit;
- nmk_chip = irq_get_chip_data(NOMADIK_GPIO_TO_IRQ(gpio));
+ nmk_chip = nmk_gpio_chips[gpio / NMK_GPIO_PER_CHIP];
if (!nmk_chip)
return -EINVAL;
- bit = 1 << (gpio - nmk_chip->chip.base);
+ bit = 1 << (gpio % NMK_GPIO_PER_CHIP);
clk_enable(nmk_chip->clk);
@@ -529,21 +603,19 @@ EXPORT_SYMBOL(nmk_gpio_get_mode);
/* IRQ functions */
static inline int nmk_gpio_get_bitmask(int gpio)
{
- return 1 << (gpio % 32);
+ return 1 << (gpio % NMK_GPIO_PER_CHIP);
}
static void nmk_gpio_irq_ack(struct irq_data *d)
{
- int gpio;
struct nmk_gpio_chip *nmk_chip;
- gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
nmk_chip = irq_data_get_irq_chip_data(d);
if (!nmk_chip)
return;
clk_enable(nmk_chip->clk);
- writel(nmk_gpio_get_bitmask(gpio), nmk_chip->addr + NMK_GPIO_IC);
+ writel(nmk_gpio_get_bitmask(d->hwirq), nmk_chip->addr + NMK_GPIO_IC);
clk_disable(nmk_chip->clk);
}
@@ -556,37 +628,52 @@ static void __nmk_gpio_irq_modify(struct nmk_gpio_chip *nmk_chip,
int gpio, enum nmk_gpio_irq_type which,
bool enable)
{
- u32 rimsc = which == WAKE ? NMK_GPIO_RWIMSC : NMK_GPIO_RIMSC;
- u32 fimsc = which == WAKE ? NMK_GPIO_FWIMSC : NMK_GPIO_FIMSC;
u32 bitmask = nmk_gpio_get_bitmask(gpio);
- u32 reg;
+ u32 *rimscval;
+ u32 *fimscval;
+ u32 rimscreg;
+ u32 fimscreg;
+
+ if (which == NORMAL) {
+ rimscreg = NMK_GPIO_RIMSC;
+ fimscreg = NMK_GPIO_FIMSC;
+ rimscval = &nmk_chip->rimsc;
+ fimscval = &nmk_chip->fimsc;
+ } else {
+ rimscreg = NMK_GPIO_RWIMSC;
+ fimscreg = NMK_GPIO_FWIMSC;
+ rimscval = &nmk_chip->rwimsc;
+ fimscval = &nmk_chip->fwimsc;
+ }
/* we must individually set/clear the two edges */
if (nmk_chip->edge_rising & bitmask) {
- reg = readl(nmk_chip->addr + rimsc);
if (enable)
- reg |= bitmask;
+ *rimscval |= bitmask;
else
- reg &= ~bitmask;
- writel(reg, nmk_chip->addr + rimsc);
+ *rimscval &= ~bitmask;
+ writel(*rimscval, nmk_chip->addr + rimscreg);
}
if (nmk_chip->edge_falling & bitmask) {
- reg = readl(nmk_chip->addr + fimsc);
if (enable)
- reg |= bitmask;
+ *fimscval |= bitmask;
else
- reg &= ~bitmask;
- writel(reg, nmk_chip->addr + fimsc);
+ *fimscval &= ~bitmask;
+ writel(*fimscval, nmk_chip->addr + fimscreg);
}
}
static void __nmk_gpio_set_wake(struct nmk_gpio_chip *nmk_chip,
int gpio, bool on)
{
- if (nmk_chip->sleepmode) {
- __nmk_gpio_set_slpm(nmk_chip, gpio - nmk_chip->chip.base,
- on ? NMK_GPIO_SLPM_WAKEUP_ENABLE
- : NMK_GPIO_SLPM_WAKEUP_DISABLE);
+ /*
+ * Ensure WAKEUP_ENABLE is on. No need to disable it if wakeup is
+ * disabled, since setting SLPM to 1 increases power consumption, and
+ * wakeup is anyhow controlled by the RIMSC and FIMSC registers.
+ */
+ if (nmk_chip->sleepmode && on) {
+ __nmk_gpio_set_slpm(nmk_chip, gpio % nmk_chip->chip.base,
+ NMK_GPIO_SLPM_WAKEUP_ENABLE);
}
__nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, on);
@@ -594,14 +681,12 @@ static void __nmk_gpio_set_wake(struct nmk_gpio_chip *nmk_chip,
static int nmk_gpio_irq_maskunmask(struct irq_data *d, bool enable)
{
- int gpio;
struct nmk_gpio_chip *nmk_chip;
unsigned long flags;
u32 bitmask;
- gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
nmk_chip = irq_data_get_irq_chip_data(d);
- bitmask = nmk_gpio_get_bitmask(gpio);
+ bitmask = nmk_gpio_get_bitmask(d->hwirq);
if (!nmk_chip)
return -EINVAL;
@@ -609,10 +694,10 @@ static int nmk_gpio_irq_maskunmask(struct irq_data *d, bool enable)
spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
spin_lock(&nmk_chip->lock);
- __nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, enable);
+ __nmk_gpio_irq_modify(nmk_chip, d->hwirq, NORMAL, enable);
if (!(nmk_chip->real_wake & bitmask))
- __nmk_gpio_set_wake(nmk_chip, gpio, enable);
+ __nmk_gpio_set_wake(nmk_chip, d->hwirq, enable);
spin_unlock(&nmk_chip->lock);
spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
@@ -636,20 +721,18 @@ static int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
struct nmk_gpio_chip *nmk_chip;
unsigned long flags;
u32 bitmask;
- int gpio;
- gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
nmk_chip = irq_data_get_irq_chip_data(d);
if (!nmk_chip)
return -EINVAL;
- bitmask = nmk_gpio_get_bitmask(gpio);
+ bitmask = nmk_gpio_get_bitmask(d->hwirq);
clk_enable(nmk_chip->clk);
spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
spin_lock(&nmk_chip->lock);
if (irqd_irq_disabled(d))
- __nmk_gpio_set_wake(nmk_chip, gpio, on);
+ __nmk_gpio_set_wake(nmk_chip, d->hwirq, on);
if (on)
nmk_chip->real_wake |= bitmask;
@@ -667,17 +750,14 @@ static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{
bool enabled = !irqd_irq_disabled(d);
bool wake = irqd_is_wakeup_set(d);
- int gpio;
struct nmk_gpio_chip *nmk_chip;
unsigned long flags;
u32 bitmask;
- gpio = NOMADIK_IRQ_TO_GPIO(d->irq);
nmk_chip = irq_data_get_irq_chip_data(d);
- bitmask = nmk_gpio_get_bitmask(gpio);
+ bitmask = nmk_gpio_get_bitmask(d->hwirq);
if (!nmk_chip)
return -EINVAL;
-
if (type & IRQ_TYPE_LEVEL_HIGH)
return -EINVAL;
if (type & IRQ_TYPE_LEVEL_LOW)
@@ -687,10 +767,10 @@ static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type)
spin_lock_irqsave(&nmk_chip->lock, flags);
if (enabled)
- __nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, false);
+ __nmk_gpio_irq_modify(nmk_chip, d->hwirq, NORMAL, false);
if (enabled || wake)
- __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, false);
+ __nmk_gpio_irq_modify(nmk_chip, d->hwirq, WAKE, false);
nmk_chip->edge_rising &= ~bitmask;
if (type & IRQ_TYPE_EDGE_RISING)
@@ -701,10 +781,10 @@ static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type)
nmk_chip->edge_falling |= bitmask;
if (enabled)
- __nmk_gpio_irq_modify(nmk_chip, gpio, NORMAL, true);
+ __nmk_gpio_irq_modify(nmk_chip, d->hwirq, NORMAL, true);
if (enabled || wake)
- __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, true);
+ __nmk_gpio_irq_modify(nmk_chip, d->hwirq, WAKE, true);
spin_unlock_irqrestore(&nmk_chip->lock, flags);
clk_disable(nmk_chip->clk);
@@ -750,7 +830,7 @@ static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc,
chained_irq_enter(host_chip, desc);
nmk_chip = irq_get_handler_data(irq);
- first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base);
+ first_irq = nmk_chip->domain->revmap_data.legacy.first_irq;
while (status) {
int bit = __ffs(status);
@@ -784,18 +864,6 @@ static void nmk_gpio_secondary_irq_handler(unsigned int irq,
static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip)
{
- unsigned int first_irq;
- int i;
-
- first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base);
- for (i = first_irq; i < first_irq + nmk_chip->chip.ngpio; i++) {
- irq_set_chip_and_handler(i, &nmk_gpio_irq_chip,
- handle_edge_irq);
- set_irq_flags(i, IRQF_VALID);
- irq_set_chip_data(i, nmk_chip);
- irq_set_irq_type(i, IRQ_TYPE_EDGE_FALLING);
- }
-
irq_set_chained_handler(nmk_chip->parent_irq, nmk_gpio_irq_handler);
irq_set_handler_data(nmk_chip->parent_irq, nmk_chip);
@@ -809,6 +877,25 @@ static int nmk_gpio_init_irq(struct nmk_gpio_chip *nmk_chip)
}
/* I/O Functions */
+
+static int nmk_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ /*
+ * Map back to global GPIO space and request muxing, the direction
+ * parameter does not matter for this controller.
+ */
+ int gpio = chip->base + offset;
+
+ return pinctrl_request_gpio(gpio);
+}
+
+static void nmk_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ int gpio = chip->base + offset;
+
+ pinctrl_free_gpio(gpio);
+}
+
static int nmk_gpio_make_input(struct gpio_chip *chip, unsigned offset)
{
struct nmk_gpio_chip *nmk_chip =
@@ -872,21 +959,23 @@ static int nmk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
struct nmk_gpio_chip *nmk_chip =
container_of(chip, struct nmk_gpio_chip, chip);
- return NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base) + offset;
+ return irq_find_mapping(nmk_chip->domain, offset);
}
#ifdef CONFIG_DEBUG_FS
#include <linux/seq_file.h>
-static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+static void nmk_gpio_dbg_show_one(struct seq_file *s, struct gpio_chip *chip,
+ unsigned offset, unsigned gpio)
{
- int mode;
- unsigned i;
- unsigned gpio = chip->base;
- int is_out;
+ const char *label = gpiochip_is_requested(chip, offset);
struct nmk_gpio_chip *nmk_chip =
container_of(chip, struct nmk_gpio_chip, chip);
+ int mode;
+ bool is_out;
+ bool pull;
+ u32 bit = 1 << offset;
const char *modes[] = {
[NMK_GPIO_ALT_GPIO] = "gpio",
[NMK_GPIO_ALT_A] = "altA",
@@ -895,61 +984,70 @@ static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
};
clk_enable(nmk_chip->clk);
-
- for (i = 0; i < chip->ngpio; i++, gpio++) {
- const char *label = gpiochip_is_requested(chip, i);
- bool pull;
- u32 bit = 1 << i;
-
- is_out = readl(nmk_chip->addr + NMK_GPIO_DIR) & bit;
- pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & bit);
- mode = nmk_gpio_get_mode(gpio);
- seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s %s",
- gpio, label ?: "(none)",
- is_out ? "out" : "in ",
- chip->get
- ? (chip->get(chip, i) ? "hi" : "lo")
- : "? ",
- (mode < 0) ? "unknown" : modes[mode],
- pull ? "pull" : "none");
-
- if (label && !is_out) {
- int irq = gpio_to_irq(gpio);
- struct irq_desc *desc = irq_to_desc(irq);
-
- /* This races with request_irq(), set_irq_type(),
- * and set_irq_wake() ... but those are "rare".
- */
- if (irq >= 0 && desc->action) {
- char *trigger;
- u32 bitmask = nmk_gpio_get_bitmask(gpio);
-
- if (nmk_chip->edge_rising & bitmask)
- trigger = "edge-rising";
- else if (nmk_chip->edge_falling & bitmask)
- trigger = "edge-falling";
- else
- trigger = "edge-undefined";
-
- seq_printf(s, " irq-%d %s%s",
- irq, trigger,
- irqd_is_wakeup_set(&desc->irq_data)
- ? " wakeup" : "");
- }
+ is_out = !!(readl(nmk_chip->addr + NMK_GPIO_DIR) & bit);
+ pull = !(readl(nmk_chip->addr + NMK_GPIO_PDIS) & bit);
+ mode = nmk_gpio_get_mode(gpio);
+
+ seq_printf(s, " gpio-%-3d (%-20.20s) %s %s %s %s",
+ gpio, label ?: "(none)",
+ is_out ? "out" : "in ",
+ chip->get
+ ? (chip->get(chip, offset) ? "hi" : "lo")
+ : "? ",
+ (mode < 0) ? "unknown" : modes[mode],
+ pull ? "pull" : "none");
+
+ if (label && !is_out) {
+ int irq = gpio_to_irq(gpio);
+ struct irq_desc *desc = irq_to_desc(irq);
+
+ /* This races with request_irq(), set_irq_type(),
+ * and set_irq_wake() ... but those are "rare".
+ */
+ if (irq >= 0 && desc->action) {
+ char *trigger;
+ u32 bitmask = nmk_gpio_get_bitmask(gpio);
+
+ if (nmk_chip->edge_rising & bitmask)
+ trigger = "edge-rising";
+ else if (nmk_chip->edge_falling & bitmask)
+ trigger = "edge-falling";
+ else
+ trigger = "edge-undefined";
+
+ seq_printf(s, " irq-%d %s%s",
+ irq, trigger,
+ irqd_is_wakeup_set(&desc->irq_data)
+ ? " wakeup" : "");
}
+ }
+ clk_disable(nmk_chip->clk);
+}
+static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+ unsigned i;
+ unsigned gpio = chip->base;
+
+ for (i = 0; i < chip->ngpio; i++, gpio++) {
+ nmk_gpio_dbg_show_one(s, chip, i, gpio);
seq_printf(s, "\n");
}
-
- clk_disable(nmk_chip->clk);
}
#else
+static inline void nmk_gpio_dbg_show_one(struct seq_file *s,
+ struct gpio_chip *chip,
+ unsigned offset, unsigned gpio)
+{
+}
#define nmk_gpio_dbg_show NULL
#endif
/* This structure is replicated for each GPIO block allocated at probe time */
static struct gpio_chip nmk_gpio_template = {
+ .request = nmk_gpio_request,
+ .free = nmk_gpio_free,
.direction_input = nmk_gpio_make_input,
.get = nmk_gpio_get_input,
.direction_output = nmk_gpio_make_output,
@@ -1008,21 +1106,11 @@ void nmk_gpio_wakeups_suspend(void)
clk_enable(chip->clk);
- chip->rwimsc = readl(chip->addr + NMK_GPIO_RWIMSC);
- chip->fwimsc = readl(chip->addr + NMK_GPIO_FWIMSC);
-
writel(chip->rwimsc & chip->real_wake,
chip->addr + NMK_GPIO_RWIMSC);
writel(chip->fwimsc & chip->real_wake,
chip->addr + NMK_GPIO_FWIMSC);
- if (chip->sleepmode) {
- chip->slpm = readl(chip->addr + NMK_GPIO_SLPC);
-
- /* 0 -> wakeup enable */
- writel(~chip->real_wake, chip->addr + NMK_GPIO_SLPC);
- }
-
clk_disable(chip->clk);
}
}
@@ -1042,9 +1130,6 @@ void nmk_gpio_wakeups_resume(void)
writel(chip->rwimsc, chip->addr + NMK_GPIO_RWIMSC);
writel(chip->fwimsc, chip->addr + NMK_GPIO_FWIMSC);
- if (chip->sleepmode)
- writel(chip->slpm, chip->addr + NMK_GPIO_SLPC);
-
clk_disable(chip->clk);
}
}
@@ -1068,19 +1153,62 @@ void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up)
}
}
+int nmk_gpio_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ struct nmk_gpio_chip *nmk_chip = d->host_data;
+
+ if (!nmk_chip)
+ return -EINVAL;
+
+ irq_set_chip_and_handler(irq, &nmk_gpio_irq_chip, handle_edge_irq);
+ set_irq_flags(irq, IRQF_VALID);
+ irq_set_chip_data(irq, nmk_chip);
+ irq_set_irq_type(irq, IRQ_TYPE_EDGE_FALLING);
+
+ return 0;
+}
+
+const struct irq_domain_ops nmk_gpio_irq_simple_ops = {
+ .map = nmk_gpio_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
static int __devinit nmk_gpio_probe(struct platform_device *dev)
{
struct nmk_gpio_platform_data *pdata = dev->dev.platform_data;
+ struct device_node *np = dev->dev.of_node;
struct nmk_gpio_chip *nmk_chip;
struct gpio_chip *chip;
struct resource *res;
struct clk *clk;
int secondary_irq;
+ void __iomem *base;
int irq;
int ret;
- if (!pdata)
+ if (!pdata && !np) {
+ dev_err(&dev->dev, "No platform data or device tree found\n");
return -ENODEV;
+ }
+
+ if (np) {
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ if (of_get_property(np, "supports-sleepmode", NULL))
+ pdata->supports_sleepmode = true;
+
+ if (of_property_read_u32(np, "gpio-bank", &dev->id)) {
+ dev_err(&dev->dev, "gpio-bank property not found\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pdata->first_gpio = dev->id * NMK_GPIO_PER_CHIP;
+ pdata->num_gpio = NMK_GPIO_PER_CHIP;
+ }
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!res) {
@@ -1106,10 +1234,16 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)
goto out;
}
+ base = ioremap(res->start, resource_size(res));
+ if (!base) {
+ ret = -ENOMEM;
+ goto out_release;
+ }
+
clk = clk_get(&dev->dev, NULL);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
- goto out_release;
+ goto out_unmap;
}
nmk_chip = kzalloc(sizeof(*nmk_chip), GFP_KERNEL);
@@ -1117,13 +1251,14 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)
ret = -ENOMEM;
goto out_clk;
}
+
/*
* The virt address in nmk_chip->addr is in the nomadik register space,
* so we can simply convert the resource address, without remapping
*/
nmk_chip->bank = dev->id;
nmk_chip->clk = clk;
- nmk_chip->addr = io_p2v(res->start);
+ nmk_chip->addr = base;
nmk_chip->chip = nmk_gpio_template;
nmk_chip->parent_irq = irq;
nmk_chip->secondary_parent_irq = secondary_irq;
@@ -1139,6 +1274,14 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)
chip->dev = &dev->dev;
chip->owner = THIS_MODULE;
+ clk_enable(nmk_chip->clk);
+ nmk_chip->lowemi = readl_relaxed(nmk_chip->addr + NMK_GPIO_LOWEMI);
+ clk_disable(nmk_chip->clk);
+
+#ifdef CONFIG_OF_GPIO
+ chip->of_node = np;
+#endif
+
ret = gpiochip_add(&nmk_chip->chip);
if (ret)
goto out_free;
@@ -1146,12 +1289,22 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)
BUG_ON(nmk_chip->bank >= ARRAY_SIZE(nmk_gpio_chips));
nmk_gpio_chips[nmk_chip->bank] = nmk_chip;
+
platform_set_drvdata(dev, nmk_chip);
+ nmk_chip->domain = irq_domain_add_legacy(np, NMK_GPIO_PER_CHIP,
+ NOMADIK_GPIO_TO_IRQ(pdata->first_gpio),
+ 0, &nmk_gpio_irq_simple_ops, nmk_chip);
+ if (!nmk_chip->domain) {
+ pr_err("%s: Failed to create irqdomain\n", np->full_name);
+ ret = -ENOSYS;
+ goto out_free;
+ }
+
nmk_gpio_init_irq(nmk_chip);
- dev_info(&dev->dev, "at address %p\n",
- nmk_chip->addr);
+ dev_info(&dev->dev, "at address %p\n", nmk_chip->addr);
+
return 0;
out_free:
@@ -1159,25 +1312,465 @@ out_free:
out_clk:
clk_disable(clk);
clk_put(clk);
+out_unmap:
+ iounmap(base);
out_release:
release_mem_region(res->start, resource_size(res));
out:
dev_err(&dev->dev, "Failure %i for GPIO %i-%i\n", ret,
pdata->first_gpio, pdata->first_gpio+31);
+ if (np)
+ kfree(pdata);
+
return ret;
}
+static int nmk_get_groups_cnt(struct pinctrl_dev *pctldev)
+{
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+ return npct->soc->ngroups;
+}
+
+static const char *nmk_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+ return npct->soc->groups[selector].name;
+}
+
+static int nmk_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
+ const unsigned **pins,
+ unsigned *num_pins)
+{
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+ *pins = npct->soc->groups[selector].pins;
+ *num_pins = npct->soc->groups[selector].npins;
+ return 0;
+}
+
+static struct pinctrl_gpio_range *
+nmk_match_gpio_range(struct pinctrl_dev *pctldev, unsigned offset)
+{
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+ int i;
+
+ for (i = 0; i < npct->soc->gpio_num_ranges; i++) {
+ struct pinctrl_gpio_range *range;
+
+ range = &npct->soc->gpio_ranges[i];
+ if (offset >= range->pin_base &&
+ offset <= (range->pin_base + range->npins - 1))
+ return range;
+ }
+ return NULL;
+}
+
+static void nmk_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+ unsigned offset)
+{
+ struct pinctrl_gpio_range *range;
+ struct gpio_chip *chip;
+
+ range = nmk_match_gpio_range(pctldev, offset);
+ if (!range || !range->gc) {
+ seq_printf(s, "invalid pin offset");
+ return;
+ }
+ chip = range->gc;
+ nmk_gpio_dbg_show_one(s, chip, offset - chip->base, offset);
+}
+
+static struct pinctrl_ops nmk_pinctrl_ops = {
+ .get_groups_count = nmk_get_groups_cnt,
+ .get_group_name = nmk_get_group_name,
+ .get_group_pins = nmk_get_group_pins,
+ .pin_dbg_show = nmk_pin_dbg_show,
+};
+
+static int nmk_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
+{
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+ return npct->soc->nfunctions;
+}
+
+static const char *nmk_pmx_get_func_name(struct pinctrl_dev *pctldev,
+ unsigned function)
+{
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+ return npct->soc->functions[function].name;
+}
+
+static int nmk_pmx_get_func_groups(struct pinctrl_dev *pctldev,
+ unsigned function,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+ *groups = npct->soc->functions[function].groups;
+ *num_groups = npct->soc->functions[function].ngroups;
+
+ return 0;
+}
+
+static int nmk_pmx_enable(struct pinctrl_dev *pctldev, unsigned function,
+ unsigned group)
+{
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+ const struct nmk_pingroup *g;
+ static unsigned int slpm[NUM_BANKS];
+ unsigned long flags;
+ bool glitch;
+ int ret = -EINVAL;
+ int i;
+
+ g = &npct->soc->groups[group];
+
+ if (g->altsetting < 0)
+ return -EINVAL;
+
+ dev_dbg(npct->dev, "enable group %s, %u pins\n", g->name, g->npins);
+
+ /* Handle this special glitch on altfunction C */
+ glitch = (g->altsetting == NMK_GPIO_ALT_C);
+
+ if (glitch) {
+ spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
+
+ /* Initially don't put any pins to sleep when switching */
+ memset(slpm, 0xff, sizeof(slpm));
+
+ /*
+ * Then mask the pins that need to be sleeping now when we're
+ * switching to the ALT C function.
+ */
+ for (i = 0; i < g->npins; i++)
+ slpm[g->pins[i] / NMK_GPIO_PER_CHIP] &= ~BIT(g->pins[i]);
+ nmk_gpio_glitch_slpm_init(slpm);
+ }
+
+ for (i = 0; i < g->npins; i++) {
+ struct pinctrl_gpio_range *range;
+ struct nmk_gpio_chip *nmk_chip;
+ struct gpio_chip *chip;
+ unsigned bit;
+
+ range = nmk_match_gpio_range(pctldev, g->pins[i]);
+ if (!range) {
+ dev_err(npct->dev,
+ "invalid pin offset %d in group %s at index %d\n",
+ g->pins[i], g->name, i);
+ goto out_glitch;
+ }
+ if (!range->gc) {
+ dev_err(npct->dev, "GPIO chip missing in range for pin offset %d in group %s at index %d\n",
+ g->pins[i], g->name, i);
+ goto out_glitch;
+ }
+ chip = range->gc;
+ nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
+ dev_dbg(npct->dev, "setting pin %d to altsetting %d\n", g->pins[i], g->altsetting);
+
+ clk_enable(nmk_chip->clk);
+ bit = g->pins[i] % NMK_GPIO_PER_CHIP;
+ /*
+ * If the pin is switching to altfunc, and there was an
+ * interrupt installed on it which has been lazy disabled,
+ * actually mask the interrupt to prevent spurious interrupts
+ * that would occur while the pin is under control of the
+ * peripheral. Only SKE does this.
+ */
+ nmk_gpio_disable_lazy_irq(nmk_chip, bit);
+
+ __nmk_gpio_set_mode_safe(nmk_chip, bit, g->altsetting, glitch);
+ clk_disable(nmk_chip->clk);
+ }
+
+ /* When all pins are successfully reconfigured we get here */
+ ret = 0;
+
+out_glitch:
+ if (glitch) {
+ nmk_gpio_glitch_slpm_restore(slpm);
+ spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
+ }
+
+ return ret;
+}
+
+static void nmk_pmx_disable(struct pinctrl_dev *pctldev,
+ unsigned function, unsigned group)
+{
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+ const struct nmk_pingroup *g;
+
+ g = &npct->soc->groups[group];
+
+ if (g->altsetting < 0)
+ return;
+
+ /* Poke out the mux, set the pin to some default state? */
+ dev_dbg(npct->dev, "disable group %s, %u pins\n", g->name, g->npins);
+}
+
+int nmk_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
+{
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+ struct nmk_gpio_chip *nmk_chip;
+ struct gpio_chip *chip;
+ unsigned bit;
+
+ if (!range) {
+ dev_err(npct->dev, "invalid range\n");
+ return -EINVAL;
+ }
+ if (!range->gc) {
+ dev_err(npct->dev, "missing GPIO chip in range\n");
+ return -EINVAL;
+ }
+ chip = range->gc;
+ nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
+
+ dev_dbg(npct->dev, "enable pin %u as GPIO\n", offset);
+
+ clk_enable(nmk_chip->clk);
+ bit = offset % NMK_GPIO_PER_CHIP;
+ /* There is no glitch when converting any pin to GPIO */
+ __nmk_gpio_set_mode(nmk_chip, bit, NMK_GPIO_ALT_GPIO);
+ clk_disable(nmk_chip->clk);
+
+ return 0;
+}
+
+void nmk_gpio_disable_free(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
+{
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+
+ dev_dbg(npct->dev, "disable pin %u as GPIO\n", offset);
+ /* Set the pin to some default state, GPIO is usually default */
+}
+
+static struct pinmux_ops nmk_pinmux_ops = {
+ .get_functions_count = nmk_pmx_get_funcs_cnt,
+ .get_function_name = nmk_pmx_get_func_name,
+ .get_function_groups = nmk_pmx_get_func_groups,
+ .enable = nmk_pmx_enable,
+ .disable = nmk_pmx_disable,
+ .gpio_request_enable = nmk_gpio_request_enable,
+ .gpio_disable_free = nmk_gpio_disable_free,
+};
+
+int nmk_pin_config_get(struct pinctrl_dev *pctldev,
+ unsigned pin,
+ unsigned long *config)
+{
+ /* Not implemented */
+ return -EINVAL;
+}
+
+int nmk_pin_config_set(struct pinctrl_dev *pctldev,
+ unsigned pin,
+ unsigned long config)
+{
+ static const char *pullnames[] = {
+ [NMK_GPIO_PULL_NONE] = "none",
+ [NMK_GPIO_PULL_UP] = "up",
+ [NMK_GPIO_PULL_DOWN] = "down",
+ [3] /* illegal */ = "??"
+ };
+ static const char *slpmnames[] = {
+ [NMK_GPIO_SLPM_INPUT] = "input/wakeup",
+ [NMK_GPIO_SLPM_NOCHANGE] = "no-change/no-wakeup",
+ };
+ struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
+ struct nmk_gpio_chip *nmk_chip;
+ struct pinctrl_gpio_range *range;
+ struct gpio_chip *chip;
+ unsigned bit;
+
+ /*
+ * The pin config contains pin number and altfunction fields, here
+ * we just ignore that part. It's being handled by the framework and
+ * pinmux callback respectively.
+ */
+ pin_cfg_t cfg = (pin_cfg_t) config;
+ int pull = PIN_PULL(cfg);
+ int slpm = PIN_SLPM(cfg);
+ int output = PIN_DIR(cfg);
+ int val = PIN_VAL(cfg);
+ bool lowemi = PIN_LOWEMI(cfg);
+ bool gpiomode = PIN_GPIOMODE(cfg);
+ bool sleep = PIN_SLEEPMODE(cfg);
+
+ range = nmk_match_gpio_range(pctldev, pin);
+ if (!range) {
+ dev_err(npct->dev, "invalid pin offset %d\n", pin);
+ return -EINVAL;
+ }
+ if (!range->gc) {
+ dev_err(npct->dev, "GPIO chip missing in range for pin %d\n",
+ pin);
+ return -EINVAL;
+ }
+ chip = range->gc;
+ nmk_chip = container_of(chip, struct nmk_gpio_chip, chip);
+
+ if (sleep) {
+ int slpm_pull = PIN_SLPM_PULL(cfg);
+ int slpm_output = PIN_SLPM_DIR(cfg);
+ int slpm_val = PIN_SLPM_VAL(cfg);
+
+ /* All pins go into GPIO mode at sleep */
+ gpiomode = true;
+
+ /*
+ * The SLPM_* values are normal values + 1 to allow zero to
+ * mean "same as normal".
+ */
+ if (slpm_pull)
+ pull = slpm_pull - 1;
+ if (slpm_output)
+ output = slpm_output - 1;
+ if (slpm_val)
+ val = slpm_val - 1;
+
+ dev_dbg(nmk_chip->chip.dev, "pin %d: sleep pull %s, dir %s, val %s\n",
+ pin,
+ slpm_pull ? pullnames[pull] : "same",
+ slpm_output ? (output ? "output" : "input") : "same",
+ slpm_val ? (val ? "high" : "low") : "same");
+ }
+
+ dev_dbg(nmk_chip->chip.dev, "pin %d [%#lx]: pull %s, slpm %s (%s%s), lowemi %s\n",
+ pin, cfg, pullnames[pull], slpmnames[slpm],
+ output ? "output " : "input",
+ output ? (val ? "high" : "low") : "",
+ lowemi ? "on" : "off" );
+
+ clk_enable(nmk_chip->clk);
+ bit = pin % NMK_GPIO_PER_CHIP;
+ if (gpiomode)
+ /* No glitch when going to GPIO mode */
+ __nmk_gpio_set_mode(nmk_chip, bit, NMK_GPIO_ALT_GPIO);
+ if (output)
+ __nmk_gpio_make_output(nmk_chip, bit, val);
+ else {
+ __nmk_gpio_make_input(nmk_chip, bit);
+ __nmk_gpio_set_pull(nmk_chip, bit, pull);
+ }
+ /* TODO: isn't this only applicable on output pins? */
+ __nmk_gpio_set_lowemi(nmk_chip, bit, lowemi);
+
+ __nmk_gpio_set_slpm(nmk_chip, bit, slpm);
+ clk_disable(nmk_chip->clk);
+ return 0;
+}
+
+static struct pinconf_ops nmk_pinconf_ops = {
+ .pin_config_get = nmk_pin_config_get,
+ .pin_config_set = nmk_pin_config_set,
+};
+
+static struct pinctrl_desc nmk_pinctrl_desc = {
+ .name = "pinctrl-nomadik",
+ .pctlops = &nmk_pinctrl_ops,
+ .pmxops = &nmk_pinmux_ops,
+ .confops = &nmk_pinconf_ops,
+ .owner = THIS_MODULE,
+};
+
+static int __devinit nmk_pinctrl_probe(struct platform_device *pdev)
+{
+ const struct platform_device_id *platid = platform_get_device_id(pdev);
+ struct nmk_pinctrl *npct;
+ int i;
+
+ npct = devm_kzalloc(&pdev->dev, sizeof(*npct), GFP_KERNEL);
+ if (!npct)
+ return -ENOMEM;
+
+ /* Poke in other ASIC variants here */
+ if (platid->driver_data == PINCTRL_NMK_DB8500)
+ nmk_pinctrl_db8500_init(&npct->soc);
+
+ /*
+ * We need all the GPIO drivers to probe FIRST, or we will not be able
+ * to obtain references to the struct gpio_chip * for them, and we
+ * need this to proceed.
+ */
+ for (i = 0; i < npct->soc->gpio_num_ranges; i++) {
+ if (!nmk_gpio_chips[i]) {
+ dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i);
+ devm_kfree(&pdev->dev, npct);
+ return -EPROBE_DEFER;
+ }
+ npct->soc->gpio_ranges[i].gc = &nmk_gpio_chips[i]->chip;
+ }
+
+ nmk_pinctrl_desc.pins = npct->soc->pins;
+ nmk_pinctrl_desc.npins = npct->soc->npins;
+ npct->dev = &pdev->dev;
+ npct->pctl = pinctrl_register(&nmk_pinctrl_desc, &pdev->dev, npct);
+ if (!npct->pctl) {
+ dev_err(&pdev->dev, "could not register Nomadik pinctrl driver\n");
+ return -EINVAL;
+ }
+
+ /* We will handle a range of GPIO pins */
+ for (i = 0; i < npct->soc->gpio_num_ranges; i++)
+ pinctrl_add_gpio_range(npct->pctl, &npct->soc->gpio_ranges[i]);
+
+ platform_set_drvdata(pdev, npct);
+ dev_info(&pdev->dev, "initialized Nomadik pin control driver\n");
+
+ return 0;
+}
+
+static const struct of_device_id nmk_gpio_match[] = {
+ { .compatible = "st,nomadik-gpio", },
+ {}
+};
+
static struct platform_driver nmk_gpio_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "gpio",
+ .of_match_table = nmk_gpio_match,
},
.probe = nmk_gpio_probe,
};
+static const struct platform_device_id nmk_pinctrl_id[] = {
+ { "pinctrl-stn8815", PINCTRL_NMK_STN8815 },
+ { "pinctrl-db8500", PINCTRL_NMK_DB8500 },
+};
+
+static struct platform_driver nmk_pinctrl_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "pinctrl-nomadik",
+ },
+ .probe = nmk_pinctrl_probe,
+ .id_table = nmk_pinctrl_id,
+};
+
static int __init nmk_gpio_init(void)
{
- return platform_driver_register(&nmk_gpio_driver);
+ int ret;
+
+ ret = platform_driver_register(&nmk_gpio_driver);
+ if (ret)
+ return ret;
+ return platform_driver_register(&nmk_pinctrl_driver);
}
core_initcall(nmk_gpio_init);
diff --git a/drivers/pinctrl/pinctrl-nomadik.h b/drivers/pinctrl/pinctrl-nomadik.h
new file mode 100644
index 000000000000..bc91aed7185d
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-nomadik.h
@@ -0,0 +1,77 @@
+#ifndef PINCTRL_PINCTRL_NOMADIK_H
+#define PINCTRL_PINCTRL_NOMADIK_H
+
+#include <plat/gpio-nomadik.h>
+
+/* Package definitions */
+#define PINCTRL_NMK_STN8815 0
+#define PINCTRL_NMK_DB8500 1
+
+/**
+ * struct nmk_function - Nomadik pinctrl mux function
+ * @name: The name of the function, exported to pinctrl core.
+ * @groups: An array of pin groups that may select this function.
+ * @ngroups: The number of entries in @groups.
+ */
+struct nmk_function {
+ const char *name;
+ const char * const *groups;
+ unsigned ngroups;
+};
+
+/**
+ * struct nmk_pingroup - describes a Nomadik pin group
+ * @name: the name of this specific pin group
+ * @pins: an array of discrete physical pins used in this group, taken
+ * from the driver-local pin enumeration space
+ * @num_pins: the number of pins in this group array, i.e. the number of
+ * elements in .pins so we can iterate over that array
+ * @altsetting: the altsetting to apply to all pins in this group to
+ * configure them to be used by a function
+ */
+struct nmk_pingroup {
+ const char *name;
+ const unsigned int *pins;
+ const unsigned npins;
+ int altsetting;
+};
+
+/**
+ * struct nmk_pinctrl_soc_data - Nomadik pin controller per-SoC configuration
+ * @gpio_ranges: An array of GPIO ranges for this SoC
+ * @gpio_num_ranges: The number of GPIO ranges for this SoC
+ * @pins: An array describing all pins the pin controller affects.
+ * All pins which are also GPIOs must be listed first within the
+ * array, and be numbered identically to the GPIO controller's
+ * numbering.
+ * @npins: The number of entries in @pins.
+ * @functions: The functions supported on this SoC.
+ * @nfunction: The number of entries in @functions.
+ * @groups: An array describing all pin groups the pin SoC supports.
+ * @ngroups: The number of entries in @groups.
+ */
+struct nmk_pinctrl_soc_data {
+ struct pinctrl_gpio_range *gpio_ranges;
+ unsigned gpio_num_ranges;
+ const struct pinctrl_pin_desc *pins;
+ unsigned npins;
+ const struct nmk_function *functions;
+ unsigned nfunctions;
+ const struct nmk_pingroup *groups;
+ unsigned ngroups;
+};
+
+#ifdef CONFIG_PINCTRL_DB8500
+
+void nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc);
+
+#else
+
+static inline void
+nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc)
+{
+}
+
+#endif
+
+#endif /* PINCTRL_PINCTRL_NOMADIK_H */
diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
index 2c98fba01ca5..b6934867d8d3 100644
--- a/drivers/pinctrl/pinctrl-tegra.c
+++ b/drivers/pinctrl/pinctrl-tegra.c
@@ -1,7 +1,7 @@
/*
* Driver for the NVIDIA Tegra pinmux
*
- * Copyright (c) 2011, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
*
* Derived from code:
* Copyright (C) 2010 Google, Inc.
@@ -22,7 +22,8 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
@@ -31,10 +32,9 @@
#include <mach/pinconf-tegra.h>
+#include "core.h"
#include "pinctrl-tegra.h"
-#define DRIVER_NAME "tegra-pinmux-disabled"
-
struct tegra_pmx {
struct device *dev;
struct pinctrl_dev *pctl;
@@ -83,15 +83,18 @@ static int tegra_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
return 0;
}
+#ifdef CONFIG_DEBUG_FS
static void tegra_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
struct seq_file *s,
unsigned offset)
{
- seq_printf(s, " " DRIVER_NAME);
+ seq_printf(s, " %s", dev_name(pctldev->dev));
}
+#endif
-static int reserve_map(struct pinctrl_map **map, unsigned *reserved_maps,
- unsigned *num_maps, unsigned reserve)
+static int reserve_map(struct device *dev, struct pinctrl_map **map,
+ unsigned *reserved_maps, unsigned *num_maps,
+ unsigned reserve)
{
unsigned old_num = *reserved_maps;
unsigned new_num = *num_maps + reserve;
@@ -101,8 +104,10 @@ static int reserve_map(struct pinctrl_map **map, unsigned *reserved_maps,
return 0;
new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL);
- if (!new_map)
+ if (!new_map) {
+ dev_err(dev, "krealloc(map) failed\n");
return -ENOMEM;
+ }
memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));
@@ -116,7 +121,7 @@ static int add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps,
unsigned *num_maps, const char *group,
const char *function)
{
- if (*num_maps == *reserved_maps)
+ if (WARN_ON(*num_maps == *reserved_maps))
return -ENOSPC;
(*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
@@ -127,19 +132,22 @@ static int add_map_mux(struct pinctrl_map **map, unsigned *reserved_maps,
return 0;
}
-static int add_map_configs(struct pinctrl_map **map, unsigned *reserved_maps,
- unsigned *num_maps, const char *group,
- unsigned long *configs, unsigned num_configs)
+static int add_map_configs(struct device *dev, struct pinctrl_map **map,
+ unsigned *reserved_maps, unsigned *num_maps,
+ const char *group, unsigned long *configs,
+ unsigned num_configs)
{
unsigned long *dup_configs;
- if (*num_maps == *reserved_maps)
+ if (WARN_ON(*num_maps == *reserved_maps))
return -ENOSPC;
dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
GFP_KERNEL);
- if (!dup_configs)
+ if (!dup_configs) {
+ dev_err(dev, "kmemdup(configs) failed\n");
return -ENOMEM;
+ }
(*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
(*map)[*num_maps].data.configs.group_or_pin = group;
@@ -150,8 +158,8 @@ static int add_map_configs(struct pinctrl_map **map, unsigned *reserved_maps,
return 0;
}
-static int add_config(unsigned long **configs, unsigned *num_configs,
- unsigned long config)
+static int add_config(struct device *dev, unsigned long **configs,
+ unsigned *num_configs, unsigned long config)
{
unsigned old_num = *num_configs;
unsigned new_num = old_num + 1;
@@ -159,8 +167,10 @@ static int add_config(unsigned long **configs, unsigned *num_configs,
new_configs = krealloc(*configs, sizeof(*new_configs) * new_num,
GFP_KERNEL);
- if (!new_configs)
+ if (!new_configs) {
+ dev_err(dev, "krealloc(configs) failed\n");
return -ENOMEM;
+ }
new_configs[old_num] = config;
@@ -201,7 +211,8 @@ static const struct cfg_param {
{"nvidia,slew-rate-rising", TEGRA_PINCONF_PARAM_SLEW_RATE_RISING},
};
-int tegra_pinctrl_dt_subnode_to_map(struct device_node *np,
+int tegra_pinctrl_dt_subnode_to_map(struct device *dev,
+ struct device_node *np,
struct pinctrl_map **map,
unsigned *reserved_maps,
unsigned *num_maps)
@@ -217,16 +228,25 @@ int tegra_pinctrl_dt_subnode_to_map(struct device_node *np,
const char *group;
ret = of_property_read_string(np, "nvidia,function", &function);
- if (ret < 0)
+ if (ret < 0) {
+ /* EINVAL=missing, which is fine since it's optional */
+ if (ret != -EINVAL)
+ dev_err(dev,
+ "could not parse property nvidia,function\n");
function = NULL;
+ }
for (i = 0; i < ARRAY_SIZE(cfg_params); i++) {
ret = of_property_read_u32(np, cfg_params[i].property, &val);
if (!ret) {
config = TEGRA_PINCONF_PACK(cfg_params[i].param, val);
- ret = add_config(&configs, &num_configs, config);
+ ret = add_config(dev, &configs, &num_configs, config);
if (ret < 0)
goto exit;
+ /* EINVAL=missing, which is fine since it's optional */
+ } else if (ret != -EINVAL) {
+ dev_err(dev, "could not parse property %s\n",
+ cfg_params[i].property);
}
}
@@ -236,11 +256,13 @@ int tegra_pinctrl_dt_subnode_to_map(struct device_node *np,
if (num_configs)
reserve++;
ret = of_property_count_strings(np, "nvidia,pins");
- if (ret < 0)
+ if (ret < 0) {
+ dev_err(dev, "could not parse property nvidia,pins\n");
goto exit;
+ }
reserve *= ret;
- ret = reserve_map(map, reserved_maps, num_maps, reserve);
+ ret = reserve_map(dev, map, reserved_maps, num_maps, reserve);
if (ret < 0)
goto exit;
@@ -253,8 +275,9 @@ int tegra_pinctrl_dt_subnode_to_map(struct device_node *np,
}
if (num_configs) {
- ret = add_map_configs(map, reserved_maps, num_maps,
- group, configs, num_configs);
+ ret = add_map_configs(dev, map, reserved_maps,
+ num_maps, group, configs,
+ num_configs);
if (ret < 0)
goto exit;
}
@@ -280,8 +303,8 @@ int tegra_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
*num_maps = 0;
for_each_child_of_node(np_config, np) {
- ret = tegra_pinctrl_dt_subnode_to_map(np, map, &reserved_maps,
- num_maps);
+ ret = tegra_pinctrl_dt_subnode_to_map(pctldev->dev, np, map,
+ &reserved_maps, num_maps);
if (ret < 0) {
tegra_pinctrl_dt_free_map(pctldev, *map, *num_maps);
return ret;
@@ -295,7 +318,9 @@ static struct pinctrl_ops tegra_pinctrl_ops = {
.get_groups_count = tegra_pinctrl_get_groups_count,
.get_group_name = tegra_pinctrl_get_group_name,
.get_group_pins = tegra_pinctrl_get_group_pins,
+#ifdef CONFIG_DEBUG_FS
.pin_dbg_show = tegra_pinctrl_pin_dbg_show,
+#endif
.dt_node_to_map = tegra_pinctrl_dt_node_to_map,
.dt_free_map = tegra_pinctrl_dt_free_map,
};
@@ -338,14 +363,14 @@ static int tegra_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned function,
g = &pmx->soc->groups[group];
- if (g->mux_reg < 0)
+ if (WARN_ON(g->mux_reg < 0))
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(g->funcs); i++) {
if (g->funcs[i] == function)
break;
}
- if (i == ARRAY_SIZE(g->funcs))
+ if (WARN_ON(i == ARRAY_SIZE(g->funcs)))
return -EINVAL;
val = pmx_readl(pmx, g->mux_bank, g->mux_reg);
@@ -365,7 +390,7 @@ static void tegra_pinctrl_disable(struct pinctrl_dev *pctldev,
g = &pmx->soc->groups[group];
- if (g->mux_reg < 0)
+ if (WARN_ON(g->mux_reg < 0))
return;
val = pmx_readl(pmx, g->mux_bank, g->mux_reg);
@@ -385,6 +410,7 @@ static struct pinmux_ops tegra_pinmux_ops = {
static int tegra_pinconf_reg(struct tegra_pmx *pmx,
const struct tegra_pingroup *g,
enum tegra_pinconf_param param,
+ bool report_err,
s8 *bank, s16 *reg, s8 *bit, s8 *width)
{
switch (param) {
@@ -472,9 +498,10 @@ static int tegra_pinconf_reg(struct tegra_pmx *pmx,
}
if (*reg < 0) {
- dev_err(pmx->dev,
- "Config param %04x not supported on group %s\n",
- param, g->name);
+ if (report_err)
+ dev_err(pmx->dev,
+ "Config param %04x not supported on group %s\n",
+ param, g->name);
return -ENOTSUPP;
}
@@ -484,12 +511,14 @@ static int tegra_pinconf_reg(struct tegra_pmx *pmx,
static int tegra_pinconf_get(struct pinctrl_dev *pctldev,
unsigned pin, unsigned long *config)
{
+ dev_err(pctldev->dev, "pin_config_get op not supported\n");
return -ENOTSUPP;
}
static int tegra_pinconf_set(struct pinctrl_dev *pctldev,
unsigned pin, unsigned long config)
{
+ dev_err(pctldev->dev, "pin_config_set op not supported\n");
return -ENOTSUPP;
}
@@ -507,7 +536,8 @@ static int tegra_pinconf_group_get(struct pinctrl_dev *pctldev,
g = &pmx->soc->groups[group];
- ret = tegra_pinconf_reg(pmx, g, param, &bank, &reg, &bit, &width);
+ ret = tegra_pinconf_reg(pmx, g, param, true, &bank, &reg, &bit,
+ &width);
if (ret < 0)
return ret;
@@ -534,7 +564,8 @@ static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev,
g = &pmx->soc->groups[group];
- ret = tegra_pinconf_reg(pmx, g, param, &bank, &reg, &bit, &width);
+ ret = tegra_pinconf_reg(pmx, g, param, true, &bank, &reg, &bit,
+ &width);
if (ret < 0)
return ret;
@@ -542,8 +573,10 @@ static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev,
/* LOCK can't be cleared */
if (param == TEGRA_PINCONF_PARAM_LOCK) {
- if ((val & BIT(bit)) && !arg)
+ if ((val & BIT(bit)) && !arg) {
+ dev_err(pctldev->dev, "LOCK bit cannot be cleared\n");
return -EINVAL;
+ }
}
/* Special-case Boolean values; allow any non-zero as true */
@@ -552,8 +585,12 @@ static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev,
/* Range-check user-supplied value */
mask = (1 << width) - 1;
- if (arg & ~mask)
+ if (arg & ~mask) {
+ dev_err(pctldev->dev,
+ "config %lx: %x too big for %d bit register\n",
+ config, arg, width);
return -EINVAL;
+ }
/* Update register */
val &= ~(mask << bit);
@@ -563,23 +600,78 @@ static int tegra_pinconf_group_set(struct pinctrl_dev *pctldev,
return 0;
}
+#ifdef CONFIG_DEBUG_FS
static void tegra_pinconf_dbg_show(struct pinctrl_dev *pctldev,
struct seq_file *s, unsigned offset)
{
}
+static const char *strip_prefix(const char *s)
+{
+ const char *comma = strchr(s, ',');
+ if (!comma)
+ return s;
+
+ return comma + 1;
+}
+
static void tegra_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
- struct seq_file *s, unsigned selector)
+ struct seq_file *s, unsigned group)
+{
+ struct tegra_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+ const struct tegra_pingroup *g;
+ int i, ret;
+ s8 bank, bit, width;
+ s16 reg;
+ u32 val;
+
+ g = &pmx->soc->groups[group];
+
+ for (i = 0; i < ARRAY_SIZE(cfg_params); i++) {
+ ret = tegra_pinconf_reg(pmx, g, cfg_params[i].param, false,
+ &bank, &reg, &bit, &width);
+ if (ret < 0)
+ continue;
+
+ val = pmx_readl(pmx, bank, reg);
+ val >>= bit;
+ val &= (1 << width) - 1;
+
+ seq_printf(s, "\n\t%s=%u",
+ strip_prefix(cfg_params[i].property), val);
+ }
+}
+
+static void tegra_pinconf_config_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s,
+ unsigned long config)
{
+ enum tegra_pinconf_param param = TEGRA_PINCONF_UNPACK_PARAM(config);
+ u16 arg = TEGRA_PINCONF_UNPACK_ARG(config);
+ const char *pname = "unknown";
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cfg_params); i++) {
+ if (cfg_params[i].param == param) {
+ pname = cfg_params[i].property;
+ break;
+ }
+ }
+
+ seq_printf(s, "%s=%d", strip_prefix(pname), arg);
}
+#endif
struct pinconf_ops tegra_pinconf_ops = {
.pin_config_get = tegra_pinconf_get,
.pin_config_set = tegra_pinconf_set,
.pin_config_group_get = tegra_pinconf_group_get,
.pin_config_group_set = tegra_pinconf_group_set,
+#ifdef CONFIG_DEBUG_FS
.pin_config_dbg_show = tegra_pinconf_dbg_show,
.pin_config_group_dbg_show = tegra_pinconf_group_dbg_show,
+ .pin_config_config_dbg_show = tegra_pinconf_config_dbg_show,
+#endif
};
static struct pinctrl_gpio_range tegra_pinctrl_gpio_range = {
@@ -589,60 +681,29 @@ static struct pinctrl_gpio_range tegra_pinctrl_gpio_range = {
};
static struct pinctrl_desc tegra_pinctrl_desc = {
- .name = DRIVER_NAME,
.pctlops = &tegra_pinctrl_ops,
.pmxops = &tegra_pinmux_ops,
.confops = &tegra_pinconf_ops,
.owner = THIS_MODULE,
};
-static struct of_device_id tegra_pinctrl_of_match[] __devinitdata = {
-#ifdef CONFIG_PINCTRL_TEGRA20
- {
- .compatible = "nvidia,tegra20-pinmux-disabled",
- .data = tegra20_pinctrl_init,
- },
-#endif
-#ifdef CONFIG_PINCTRL_TEGRA30
- {
- .compatible = "nvidia,tegra30-pinmux-disabled",
- .data = tegra30_pinctrl_init,
- },
-#endif
- {},
-};
-
-static int __devinit tegra_pinctrl_probe(struct platform_device *pdev)
+int __devinit tegra_pinctrl_probe(struct platform_device *pdev,
+ const struct tegra_pinctrl_soc_data *soc_data)
{
- const struct of_device_id *match;
- tegra_pinctrl_soc_initf initf = NULL;
struct tegra_pmx *pmx;
struct resource *res;
int i;
- match = of_match_device(tegra_pinctrl_of_match, &pdev->dev);
- if (match)
- initf = (tegra_pinctrl_soc_initf)match->data;
-#ifdef CONFIG_PINCTRL_TEGRA20
- if (!initf)
- initf = tegra20_pinctrl_init;
-#endif
- if (!initf) {
- dev_err(&pdev->dev,
- "Could not determine SoC-specific init func\n");
- return -EINVAL;
- }
-
pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
if (!pmx) {
dev_err(&pdev->dev, "Can't alloc tegra_pmx\n");
return -ENOMEM;
}
pmx->dev = &pdev->dev;
-
- (*initf)(&pmx->soc);
+ pmx->soc = soc_data;
tegra_pinctrl_gpio_range.npins = pmx->soc->ngpios;
+ tegra_pinctrl_desc.name = dev_name(&pdev->dev);
tegra_pinctrl_desc.pins = pmx->soc->pins;
tegra_pinctrl_desc.npins = pmx->soc->npins;
@@ -697,8 +758,9 @@ static int __devinit tegra_pinctrl_probe(struct platform_device *pdev)
return 0;
}
+EXPORT_SYMBOL_GPL(tegra_pinctrl_probe);
-static int __devexit tegra_pinctrl_remove(struct platform_device *pdev)
+int __devexit tegra_pinctrl_remove(struct platform_device *pdev)
{
struct tegra_pmx *pmx = platform_get_drvdata(pdev);
@@ -707,30 +769,4 @@ static int __devexit tegra_pinctrl_remove(struct platform_device *pdev)
return 0;
}
-
-static struct platform_driver tegra_pinctrl_driver = {
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
- .of_match_table = tegra_pinctrl_of_match,
- },
- .probe = tegra_pinctrl_probe,
- .remove = __devexit_p(tegra_pinctrl_remove),
-};
-
-static int __init tegra_pinctrl_init(void)
-{
- return platform_driver_register(&tegra_pinctrl_driver);
-}
-arch_initcall(tegra_pinctrl_init);
-
-static void __exit tegra_pinctrl_exit(void)
-{
- platform_driver_unregister(&tegra_pinctrl_driver);
-}
-module_exit(tegra_pinctrl_exit);
-
-MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
-MODULE_DESCRIPTION("NVIDIA Tegra pinctrl driver");
-MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, tegra_pinctrl_of_match);
+EXPORT_SYMBOL_GPL(tegra_pinctrl_remove);
diff --git a/drivers/pinctrl/pinctrl-tegra.h b/drivers/pinctrl/pinctrl-tegra.h
index 782c795326ef..705c007a38cc 100644
--- a/drivers/pinctrl/pinctrl-tegra.h
+++ b/drivers/pinctrl/pinctrl-tegra.h
@@ -139,25 +139,8 @@ struct tegra_pinctrl_soc_data {
unsigned ngroups;
};
-/**
- * tegra_pinctrl_soc_initf() - Retrieve pin controller details for a SoC.
- * @soc_data: This pointer must be updated to point at a struct containing
- * details of the SoC.
- */
-typedef void (*tegra_pinctrl_soc_initf)(
- const struct tegra_pinctrl_soc_data **soc_data);
-
-/**
- * tegra20_pinctrl_init() - Retrieve pin controller details for Tegra20
- * @soc_data: This pointer will be updated to point at a struct containing
- * details of Tegra20's pin controller.
- */
-void tegra20_pinctrl_init(const struct tegra_pinctrl_soc_data **soc_data);
-/**
- * tegra30_pinctrl_init() - Retrieve pin controller details for Tegra20
- * @soc_data: This pointer will be updated to point at a struct containing
- * details of Tegra30's pin controller.
- */
-void tegra30_pinctrl_init(const struct tegra_pinctrl_soc_data **soc_data);
+int tegra_pinctrl_probe(struct platform_device *pdev,
+ const struct tegra_pinctrl_soc_data *soc_data);
+int tegra_pinctrl_remove(struct platform_device *pdev);
#endif
diff --git a/drivers/pinctrl/pinctrl-tegra20.c b/drivers/pinctrl/pinctrl-tegra20.c
index f69ff96aa292..a74f9a568536 100644
--- a/drivers/pinctrl/pinctrl-tegra20.c
+++ b/drivers/pinctrl/pinctrl-tegra20.c
@@ -1,7 +1,7 @@
/*
* Pinctrl data for the NVIDIA Tegra20 pinmux
*
- * Copyright (c) 2011, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
*
* Derived from code:
* Copyright (C) 2010 Google, Inc.
@@ -17,6 +17,8 @@
* more details.
*/
+#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
@@ -2854,7 +2856,39 @@ static const struct tegra_pinctrl_soc_data tegra20_pinctrl = {
.ngroups = ARRAY_SIZE(tegra20_groups),
};
-void __devinit tegra20_pinctrl_init(const struct tegra_pinctrl_soc_data **soc)
+static int __devinit tegra20_pinctrl_probe(struct platform_device *pdev)
{
- *soc = &tegra20_pinctrl;
+ return tegra_pinctrl_probe(pdev, &tegra20_pinctrl);
}
+
+static struct of_device_id tegra20_pinctrl_of_match[] __devinitdata = {
+ { .compatible = "nvidia,tegra20-pinmux", },
+ { },
+};
+
+static struct platform_driver tegra20_pinctrl_driver = {
+ .driver = {
+ .name = "tegra20-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = tegra20_pinctrl_of_match,
+ },
+ .probe = tegra20_pinctrl_probe,
+ .remove = __devexit_p(tegra_pinctrl_remove),
+};
+
+static int __init tegra20_pinctrl_init(void)
+{
+ return platform_driver_register(&tegra20_pinctrl_driver);
+}
+arch_initcall(tegra20_pinctrl_init);
+
+static void __exit tegra20_pinctrl_exit(void)
+{
+ platform_driver_unregister(&tegra20_pinctrl_driver);
+}
+module_exit(tegra20_pinctrl_exit);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("NVIDIA Tegra20 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, tegra20_pinctrl_of_match);
diff --git a/drivers/pinctrl/pinctrl-tegra30.c b/drivers/pinctrl/pinctrl-tegra30.c
index 4d7571d4a431..0386fdf0da16 100644
--- a/drivers/pinctrl/pinctrl-tegra30.c
+++ b/drivers/pinctrl/pinctrl-tegra30.c
@@ -1,7 +1,7 @@
/*
* Pinctrl data for the NVIDIA Tegra30 pinmux
*
- * Copyright (c) 2011, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -13,6 +13,8 @@
* more details.
*/
+#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
@@ -3720,7 +3722,39 @@ static const struct tegra_pinctrl_soc_data tegra30_pinctrl = {
.ngroups = ARRAY_SIZE(tegra30_groups),
};
-void __devinit tegra30_pinctrl_init(const struct tegra_pinctrl_soc_data **soc)
+static int __devinit tegra30_pinctrl_probe(struct platform_device *pdev)
{
- *soc = &tegra30_pinctrl;
+ return tegra_pinctrl_probe(pdev, &tegra30_pinctrl);
}
+
+static struct of_device_id tegra30_pinctrl_of_match[] __devinitdata = {
+ { .compatible = "nvidia,tegra30-pinmux", },
+ { },
+};
+
+static struct platform_driver tegra30_pinctrl_driver = {
+ .driver = {
+ .name = "tegra30-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = tegra30_pinctrl_of_match,
+ },
+ .probe = tegra30_pinctrl_probe,
+ .remove = __devexit_p(tegra_pinctrl_remove),
+};
+
+static int __init tegra30_pinctrl_init(void)
+{
+ return platform_driver_register(&tegra30_pinctrl_driver);
+}
+arch_initcall(tegra30_pinctrl_init);
+
+static void __exit tegra30_pinctrl_exit(void)
+{
+ platform_driver_unregister(&tegra30_pinctrl_driver);
+}
+module_exit(tegra30_pinctrl_exit);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("NVIDIA Tegra30 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, tegra30_pinctrl_of_match);
diff --git a/drivers/pinctrl/spear/Kconfig b/drivers/pinctrl/spear/Kconfig
new file mode 100644
index 000000000000..6a2596b4f359
--- /dev/null
+++ b/drivers/pinctrl/spear/Kconfig
@@ -0,0 +1,34 @@
+#
+# ST Microelectronics SPEAr PINCTRL drivers
+#
+
+if PLAT_SPEAR
+
+config PINCTRL_SPEAR
+ bool
+ depends on OF
+ select PINMUX
+ help
+ This enables pin control drivers for SPEAr Platform
+
+config PINCTRL_SPEAR3XX
+ bool
+ depends on ARCH_SPEAR3XX
+ select PINCTRL_SPEAR
+
+config PINCTRL_SPEAR300
+ bool "ST Microelectronics SPEAr300 SoC pin controller driver"
+ depends on MACH_SPEAR300
+ select PINCTRL_SPEAR3XX
+
+config PINCTRL_SPEAR310
+ bool "ST Microelectronics SPEAr310 SoC pin controller driver"
+ depends on MACH_SPEAR310
+ select PINCTRL_SPEAR3XX
+
+config PINCTRL_SPEAR320
+ bool "ST Microelectronics SPEAr320 SoC pin controller driver"
+ depends on MACH_SPEAR320
+ select PINCTRL_SPEAR3XX
+
+endif
diff --git a/drivers/pinctrl/spear/Makefile b/drivers/pinctrl/spear/Makefile
new file mode 100644
index 000000000000..15dcb85da22d
--- /dev/null
+++ b/drivers/pinctrl/spear/Makefile
@@ -0,0 +1,7 @@
+# SPEAr pinmux support
+
+obj-$(CONFIG_PINCTRL_SPEAR) += pinctrl-spear.o
+obj-$(CONFIG_PINCTRL_SPEAR3XX) += pinctrl-spear3xx.o
+obj-$(CONFIG_PINCTRL_SPEAR300) += pinctrl-spear300.o
+obj-$(CONFIG_PINCTRL_SPEAR310) += pinctrl-spear310.o
+obj-$(CONFIG_PINCTRL_SPEAR320) += pinctrl-spear320.o
diff --git a/drivers/pinctrl/spear/pinctrl-spear.c b/drivers/pinctrl/spear/pinctrl-spear.c
new file mode 100644
index 000000000000..5ae50aadf885
--- /dev/null
+++ b/drivers/pinctrl/spear/pinctrl-spear.c
@@ -0,0 +1,354 @@
+/*
+ * Driver for the ST Microelectronics SPEAr pinmux
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * Inspired from:
+ * - U300 Pinctl drivers
+ * - Tegra Pinctl drivers
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "pinctrl-spear.h"
+
+#define DRIVER_NAME "spear-pinmux"
+
+static inline u32 pmx_readl(struct spear_pmx *pmx, u32 reg)
+{
+ return readl_relaxed(pmx->vbase + reg);
+}
+
+static inline void pmx_writel(struct spear_pmx *pmx, u32 val, u32 reg)
+{
+ writel_relaxed(val, pmx->vbase + reg);
+}
+
+static int set_mode(struct spear_pmx *pmx, int mode)
+{
+ struct spear_pmx_mode *pmx_mode = NULL;
+ int i;
+ u32 val;
+
+ if (!pmx->machdata->pmx_modes || !pmx->machdata->npmx_modes)
+ return -EINVAL;
+
+ for (i = 0; i < pmx->machdata->npmx_modes; i++) {
+ if (pmx->machdata->pmx_modes[i]->mode == (1 << mode)) {
+ pmx_mode = pmx->machdata->pmx_modes[i];
+ break;
+ }
+ }
+
+ if (!pmx_mode)
+ return -EINVAL;
+
+ val = pmx_readl(pmx, pmx_mode->reg);
+ val &= ~pmx_mode->mask;
+ val |= pmx_mode->val;
+ pmx_writel(pmx, val, pmx_mode->reg);
+
+ pmx->machdata->mode = pmx_mode->mode;
+ dev_info(pmx->dev, "Configured Mode: %s with id: %x\n\n",
+ pmx_mode->name ? pmx_mode->name : "no_name",
+ pmx_mode->reg);
+
+ return 0;
+}
+
+void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg)
+{
+ struct spear_pingroup *pgroup;
+ struct spear_modemux *modemux;
+ int i, j, group;
+
+ for (group = 0; group < machdata->ngroups; group++) {
+ pgroup = machdata->groups[group];
+
+ for (i = 0; i < pgroup->nmodemuxs; i++) {
+ modemux = &pgroup->modemuxs[i];
+
+ for (j = 0; j < modemux->nmuxregs; j++)
+ if (modemux->muxregs[j].reg == 0xFFFF)
+ modemux->muxregs[j].reg = reg;
+ }
+ }
+}
+
+static int spear_pinctrl_get_groups_cnt(struct pinctrl_dev *pctldev)
+{
+ struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+ return pmx->machdata->ngroups;
+}
+
+static const char *spear_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned group)
+{
+ struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+ return pmx->machdata->groups[group]->name;
+}
+
+static int spear_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned group, const unsigned **pins, unsigned *num_pins)
+{
+ struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+ *pins = pmx->machdata->groups[group]->pins;
+ *num_pins = pmx->machdata->groups[group]->npins;
+
+ return 0;
+}
+
+static void spear_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned offset)
+{
+ seq_printf(s, " " DRIVER_NAME);
+}
+
+int spear_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np_config,
+ struct pinctrl_map **map, unsigned *num_maps)
+{
+ struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+ struct device_node *np;
+ struct property *prop;
+ const char *function, *group;
+ int ret, index = 0, count = 0;
+
+ /* calculate number of maps required */
+ for_each_child_of_node(np_config, np) {
+ ret = of_property_read_string(np, "st,function", &function);
+ if (ret < 0)
+ return ret;
+
+ ret = of_property_count_strings(np, "st,pins");
+ if (ret < 0)
+ return ret;
+
+ count += ret;
+ }
+
+ if (!count) {
+ dev_err(pmx->dev, "No child nodes passed via DT\n");
+ return -ENODEV;
+ }
+
+ *map = kzalloc(sizeof(**map) * count, GFP_KERNEL);
+ if (!*map)
+ return -ENOMEM;
+
+ for_each_child_of_node(np_config, np) {
+ of_property_read_string(np, "st,function", &function);
+ of_property_for_each_string(np, "st,pins", prop, group) {
+ (*map)[index].type = PIN_MAP_TYPE_MUX_GROUP;
+ (*map)[index].data.mux.group = group;
+ (*map)[index].data.mux.function = function;
+ index++;
+ }
+ }
+
+ *num_maps = count;
+
+ return 0;
+}
+
+void spear_pinctrl_dt_free_map(struct pinctrl_dev *pctldev,
+ struct pinctrl_map *map, unsigned num_maps)
+{
+ kfree(map);
+}
+
+static struct pinctrl_ops spear_pinctrl_ops = {
+ .get_groups_count = spear_pinctrl_get_groups_cnt,
+ .get_group_name = spear_pinctrl_get_group_name,
+ .get_group_pins = spear_pinctrl_get_group_pins,
+ .pin_dbg_show = spear_pinctrl_pin_dbg_show,
+ .dt_node_to_map = spear_pinctrl_dt_node_to_map,
+ .dt_free_map = spear_pinctrl_dt_free_map,
+};
+
+static int spear_pinctrl_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+ struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+ return pmx->machdata->nfunctions;
+}
+
+static const char *spear_pinctrl_get_func_name(struct pinctrl_dev *pctldev,
+ unsigned function)
+{
+ struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+ return pmx->machdata->functions[function]->name;
+}
+
+static int spear_pinctrl_get_func_groups(struct pinctrl_dev *pctldev,
+ unsigned function, const char *const **groups,
+ unsigned * const ngroups)
+{
+ struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+
+ *groups = pmx->machdata->functions[function]->groups;
+ *ngroups = pmx->machdata->functions[function]->ngroups;
+
+ return 0;
+}
+
+static int spear_pinctrl_endisable(struct pinctrl_dev *pctldev,
+ unsigned function, unsigned group, bool enable)
+{
+ struct spear_pmx *pmx = pinctrl_dev_get_drvdata(pctldev);
+ const struct spear_pingroup *pgroup;
+ const struct spear_modemux *modemux;
+ struct spear_muxreg *muxreg;
+ u32 val, temp;
+ int i, j;
+ bool found = false;
+
+ pgroup = pmx->machdata->groups[group];
+
+ for (i = 0; i < pgroup->nmodemuxs; i++) {
+ modemux = &pgroup->modemuxs[i];
+
+ /* SoC have any modes */
+ if (pmx->machdata->modes_supported) {
+ if (!(pmx->machdata->mode & modemux->modes))
+ continue;
+ }
+
+ found = true;
+ for (j = 0; j < modemux->nmuxregs; j++) {
+ muxreg = &modemux->muxregs[j];
+
+ val = pmx_readl(pmx, muxreg->reg);
+ val &= ~muxreg->mask;
+
+ if (enable)
+ temp = muxreg->val;
+ else
+ temp = ~muxreg->val;
+
+ val |= temp;
+ pmx_writel(pmx, val, muxreg->reg);
+ }
+ }
+
+ if (!found) {
+ dev_err(pmx->dev, "pinmux group: %s not supported\n",
+ pgroup->name);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int spear_pinctrl_enable(struct pinctrl_dev *pctldev, unsigned function,
+ unsigned group)
+{
+ return spear_pinctrl_endisable(pctldev, function, group, true);
+}
+
+static void spear_pinctrl_disable(struct pinctrl_dev *pctldev,
+ unsigned function, unsigned group)
+{
+ spear_pinctrl_endisable(pctldev, function, group, false);
+}
+
+static struct pinmux_ops spear_pinmux_ops = {
+ .get_functions_count = spear_pinctrl_get_funcs_count,
+ .get_function_name = spear_pinctrl_get_func_name,
+ .get_function_groups = spear_pinctrl_get_func_groups,
+ .enable = spear_pinctrl_enable,
+ .disable = spear_pinctrl_disable,
+};
+
+static struct pinctrl_desc spear_pinctrl_desc = {
+ .name = DRIVER_NAME,
+ .pctlops = &spear_pinctrl_ops,
+ .pmxops = &spear_pinmux_ops,
+ .owner = THIS_MODULE,
+};
+
+int __devinit spear_pinctrl_probe(struct platform_device *pdev,
+ struct spear_pinctrl_machdata *machdata)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *res;
+ struct spear_pmx *pmx;
+
+ if (!machdata)
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+
+ pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
+ if (!pmx) {
+ dev_err(&pdev->dev, "Can't alloc spear_pmx\n");
+ return -ENOMEM;
+ }
+
+ pmx->vbase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!pmx->vbase) {
+ dev_err(&pdev->dev, "Couldn't ioremap at index 0\n");
+ return -ENODEV;
+ }
+
+ pmx->dev = &pdev->dev;
+ pmx->machdata = machdata;
+
+ /* configure mode, if supported by SoC */
+ if (machdata->modes_supported) {
+ int mode = 0;
+
+ if (of_property_read_u32(np, "st,pinmux-mode", &mode)) {
+ dev_err(&pdev->dev, "OF: pinmux mode not passed\n");
+ return -EINVAL;
+ }
+
+ if (set_mode(pmx, mode)) {
+ dev_err(&pdev->dev, "OF: Couldn't configure mode: %x\n",
+ mode);
+ return -EINVAL;
+ }
+ }
+
+ platform_set_drvdata(pdev, pmx);
+
+ spear_pinctrl_desc.pins = machdata->pins;
+ spear_pinctrl_desc.npins = machdata->npins;
+
+ pmx->pctl = pinctrl_register(&spear_pinctrl_desc, &pdev->dev, pmx);
+ if (IS_ERR(pmx->pctl)) {
+ dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
+ return PTR_ERR(pmx->pctl);
+ }
+
+ return 0;
+}
+
+int __devexit spear_pinctrl_remove(struct platform_device *pdev)
+{
+ struct spear_pmx *pmx = platform_get_drvdata(pdev);
+
+ pinctrl_unregister(pmx->pctl);
+
+ return 0;
+}
diff --git a/drivers/pinctrl/spear/pinctrl-spear.h b/drivers/pinctrl/spear/pinctrl-spear.h
new file mode 100644
index 000000000000..47a6b5b72f90
--- /dev/null
+++ b/drivers/pinctrl/spear/pinctrl-spear.h
@@ -0,0 +1,142 @@
+/*
+ * Driver header file for the ST Microelectronics SPEAr pinmux
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __PINMUX_SPEAR_H__
+#define __PINMUX_SPEAR_H__
+
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/types.h>
+
+struct platform_device;
+struct device;
+
+/**
+ * struct spear_pmx_mode - SPEAr pmx mode
+ * @name: name of pmx mode
+ * @mode: mode id
+ * @reg: register for configuring this mode
+ * @mask: mask of this mode in reg
+ * @val: val to be configured at reg after doing (val & mask)
+ */
+struct spear_pmx_mode {
+ const char *const name;
+ u16 mode;
+ u16 reg;
+ u16 mask;
+ u32 val;
+};
+
+/**
+ * struct spear_muxreg - SPEAr mux reg configuration
+ * @reg: register offset
+ * @mask: mask bits
+ * @val: val to be written on mask bits
+ */
+struct spear_muxreg {
+ u16 reg;
+ u32 mask;
+ u32 val;
+};
+
+/**
+ * struct spear_modemux - SPEAr mode mux configuration
+ * @modes: mode ids supported by this group of muxregs
+ * @nmuxregs: number of muxreg configurations to be done for modes
+ * @muxregs: array of muxreg configurations to be done for modes
+ */
+struct spear_modemux {
+ u16 modes;
+ u8 nmuxregs;
+ struct spear_muxreg *muxregs;
+};
+
+/**
+ * struct spear_pingroup - SPEAr pin group configurations
+ * @name: name of pin group
+ * @pins: array containing pin numbers
+ * @npins: size of pins array
+ * @modemuxs: array of modemux configurations for this pin group
+ * @nmodemuxs: size of array modemuxs
+ *
+ * A representation of a group of pins in the SPEAr pin controller. Each group
+ * allows some parameter or parameters to be configured.
+ */
+struct spear_pingroup {
+ const char *name;
+ const unsigned *pins;
+ unsigned npins;
+ struct spear_modemux *modemuxs;
+ unsigned nmodemuxs;
+};
+
+/**
+ * struct spear_function - SPEAr pinctrl mux function
+ * @name: The name of the function, exported to pinctrl core.
+ * @groups: An array of pin groups that may select this function.
+ * @ngroups: The number of entries in @groups.
+ */
+struct spear_function {
+ const char *name;
+ const char *const *groups;
+ unsigned ngroups;
+};
+
+/**
+ * struct spear_pinctrl_machdata - SPEAr pin controller machine driver
+ * configuration
+ * @pins: An array describing all pins the pin controller affects.
+ * All pins which are also GPIOs must be listed first within the *array,
+ * and be numbered identically to the GPIO controller's *numbering.
+ * @npins: The numbmer of entries in @pins.
+ * @functions: An array describing all mux functions the SoC supports.
+ * @nfunctions: The numbmer of entries in @functions.
+ * @groups: An array describing all pin groups the pin SoC supports.
+ * @ngroups: The numbmer of entries in @groups.
+ *
+ * @modes_supported: Does SoC support modes
+ * @mode: mode configured from probe
+ * @pmx_modes: array of modes supported by SoC
+ * @npmx_modes: number of entries in pmx_modes.
+ */
+struct spear_pinctrl_machdata {
+ const struct pinctrl_pin_desc *pins;
+ unsigned npins;
+ struct spear_function **functions;
+ unsigned nfunctions;
+ struct spear_pingroup **groups;
+ unsigned ngroups;
+
+ bool modes_supported;
+ u16 mode;
+ struct spear_pmx_mode **pmx_modes;
+ unsigned npmx_modes;
+};
+
+/**
+ * struct spear_pmx - SPEAr pinctrl mux
+ * @dev: pointer to struct dev of platform_device registered
+ * @pctl: pointer to struct pinctrl_dev
+ * @machdata: pointer to SoC or machine specific structure
+ * @vbase: virtual base address of pinmux controller
+ */
+struct spear_pmx {
+ struct device *dev;
+ struct pinctrl_dev *pctl;
+ struct spear_pinctrl_machdata *machdata;
+ void __iomem *vbase;
+};
+
+/* exported routines */
+void __devinit pmx_init_addr(struct spear_pinctrl_machdata *machdata, u16 reg);
+int __devinit spear_pinctrl_probe(struct platform_device *pdev,
+ struct spear_pinctrl_machdata *machdata);
+int __devexit spear_pinctrl_remove(struct platform_device *pdev);
+#endif /* __PINMUX_SPEAR_H__ */
diff --git a/drivers/pinctrl/spear/pinctrl-spear300.c b/drivers/pinctrl/spear/pinctrl-spear300.c
new file mode 100644
index 000000000000..9c82a35e4e78
--- /dev/null
+++ b/drivers/pinctrl/spear/pinctrl-spear300.c
@@ -0,0 +1,708 @@
+/*
+ * Driver for the ST Microelectronics SPEAr300 pinmux
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "pinctrl-spear3xx.h"
+
+#define DRIVER_NAME "spear300-pinmux"
+
+/* addresses */
+#define PMX_CONFIG_REG 0x00
+#define MODE_CONFIG_REG 0x04
+
+/* modes */
+#define NAND_MODE (1 << 0)
+#define NOR_MODE (1 << 1)
+#define PHOTO_FRAME_MODE (1 << 2)
+#define LEND_IP_PHONE_MODE (1 << 3)
+#define HEND_IP_PHONE_MODE (1 << 4)
+#define LEND_WIFI_PHONE_MODE (1 << 5)
+#define HEND_WIFI_PHONE_MODE (1 << 6)
+#define ATA_PABX_WI2S_MODE (1 << 7)
+#define ATA_PABX_I2S_MODE (1 << 8)
+#define CAML_LCDW_MODE (1 << 9)
+#define CAMU_LCD_MODE (1 << 10)
+#define CAMU_WLCD_MODE (1 << 11)
+#define CAML_LCD_MODE (1 << 12)
+
+static struct spear_pmx_mode pmx_mode_nand = {
+ .name = "nand",
+ .mode = NAND_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x00,
+};
+
+static struct spear_pmx_mode pmx_mode_nor = {
+ .name = "nor",
+ .mode = NOR_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x01,
+};
+
+static struct spear_pmx_mode pmx_mode_photo_frame = {
+ .name = "photo frame mode",
+ .mode = PHOTO_FRAME_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x02,
+};
+
+static struct spear_pmx_mode pmx_mode_lend_ip_phone = {
+ .name = "lend ip phone mode",
+ .mode = LEND_IP_PHONE_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x03,
+};
+
+static struct spear_pmx_mode pmx_mode_hend_ip_phone = {
+ .name = "hend ip phone mode",
+ .mode = HEND_IP_PHONE_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x04,
+};
+
+static struct spear_pmx_mode pmx_mode_lend_wifi_phone = {
+ .name = "lend wifi phone mode",
+ .mode = LEND_WIFI_PHONE_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x05,
+};
+
+static struct spear_pmx_mode pmx_mode_hend_wifi_phone = {
+ .name = "hend wifi phone mode",
+ .mode = HEND_WIFI_PHONE_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x06,
+};
+
+static struct spear_pmx_mode pmx_mode_ata_pabx_wi2s = {
+ .name = "ata pabx wi2s mode",
+ .mode = ATA_PABX_WI2S_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x07,
+};
+
+static struct spear_pmx_mode pmx_mode_ata_pabx_i2s = {
+ .name = "ata pabx i2s mode",
+ .mode = ATA_PABX_I2S_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x08,
+};
+
+static struct spear_pmx_mode pmx_mode_caml_lcdw = {
+ .name = "caml lcdw mode",
+ .mode = CAML_LCDW_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x0C,
+};
+
+static struct spear_pmx_mode pmx_mode_camu_lcd = {
+ .name = "camu lcd mode",
+ .mode = CAMU_LCD_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x0D,
+};
+
+static struct spear_pmx_mode pmx_mode_camu_wlcd = {
+ .name = "camu wlcd mode",
+ .mode = CAMU_WLCD_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0xE,
+};
+
+static struct spear_pmx_mode pmx_mode_caml_lcd = {
+ .name = "caml lcd mode",
+ .mode = CAML_LCD_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x0000000F,
+ .val = 0x0F,
+};
+
+static struct spear_pmx_mode *spear300_pmx_modes[] = {
+ &pmx_mode_nand,
+ &pmx_mode_nor,
+ &pmx_mode_photo_frame,
+ &pmx_mode_lend_ip_phone,
+ &pmx_mode_hend_ip_phone,
+ &pmx_mode_lend_wifi_phone,
+ &pmx_mode_hend_wifi_phone,
+ &pmx_mode_ata_pabx_wi2s,
+ &pmx_mode_ata_pabx_i2s,
+ &pmx_mode_caml_lcdw,
+ &pmx_mode_camu_lcd,
+ &pmx_mode_camu_wlcd,
+ &pmx_mode_caml_lcd,
+};
+
+/* fsmc_2chips_pins */
+static const unsigned fsmc_2chips_pins[] = { 1, 97 };
+static struct spear_muxreg fsmc_2chips_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_FIRDA_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux fsmc_2chips_modemux[] = {
+ {
+ .modes = NAND_MODE | NOR_MODE | PHOTO_FRAME_MODE |
+ ATA_PABX_WI2S_MODE | ATA_PABX_I2S_MODE,
+ .muxregs = fsmc_2chips_muxreg,
+ .nmuxregs = ARRAY_SIZE(fsmc_2chips_muxreg),
+ },
+};
+
+static struct spear_pingroup fsmc_2chips_pingroup = {
+ .name = "fsmc_2chips_grp",
+ .pins = fsmc_2chips_pins,
+ .npins = ARRAY_SIZE(fsmc_2chips_pins),
+ .modemuxs = fsmc_2chips_modemux,
+ .nmodemuxs = ARRAY_SIZE(fsmc_2chips_modemux),
+};
+
+/* fsmc_4chips_pins */
+static const unsigned fsmc_4chips_pins[] = { 1, 2, 3, 97 };
+static struct spear_muxreg fsmc_4chips_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_FIRDA_MASK | PMX_UART0_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux fsmc_4chips_modemux[] = {
+ {
+ .modes = NAND_MODE | NOR_MODE | PHOTO_FRAME_MODE |
+ ATA_PABX_WI2S_MODE | ATA_PABX_I2S_MODE,
+ .muxregs = fsmc_4chips_muxreg,
+ .nmuxregs = ARRAY_SIZE(fsmc_4chips_muxreg),
+ },
+};
+
+static struct spear_pingroup fsmc_4chips_pingroup = {
+ .name = "fsmc_4chips_grp",
+ .pins = fsmc_4chips_pins,
+ .npins = ARRAY_SIZE(fsmc_4chips_pins),
+ .modemuxs = fsmc_4chips_modemux,
+ .nmodemuxs = ARRAY_SIZE(fsmc_4chips_modemux),
+};
+
+static const char *const fsmc_grps[] = { "fsmc_2chips_grp", "fsmc_4chips_grp"
+};
+static struct spear_function fsmc_function = {
+ .name = "fsmc",
+ .groups = fsmc_grps,
+ .ngroups = ARRAY_SIZE(fsmc_grps),
+};
+
+/* clcd_lcdmode_pins */
+static const unsigned clcd_lcdmode_pins[] = { 49, 50 };
+static struct spear_muxreg clcd_lcdmode_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux clcd_lcdmode_modemux[] = {
+ {
+ .modes = HEND_IP_PHONE_MODE | HEND_WIFI_PHONE_MODE |
+ CAMU_LCD_MODE | CAML_LCD_MODE,
+ .muxregs = clcd_lcdmode_muxreg,
+ .nmuxregs = ARRAY_SIZE(clcd_lcdmode_muxreg),
+ },
+};
+
+static struct spear_pingroup clcd_lcdmode_pingroup = {
+ .name = "clcd_lcdmode_grp",
+ .pins = clcd_lcdmode_pins,
+ .npins = ARRAY_SIZE(clcd_lcdmode_pins),
+ .modemuxs = clcd_lcdmode_modemux,
+ .nmodemuxs = ARRAY_SIZE(clcd_lcdmode_modemux),
+};
+
+/* clcd_pfmode_pins */
+static const unsigned clcd_pfmode_pins[] = { 47, 48, 49, 50 };
+static struct spear_muxreg clcd_pfmode_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_2_3_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux clcd_pfmode_modemux[] = {
+ {
+ .modes = PHOTO_FRAME_MODE,
+ .muxregs = clcd_pfmode_muxreg,
+ .nmuxregs = ARRAY_SIZE(clcd_pfmode_muxreg),
+ },
+};
+
+static struct spear_pingroup clcd_pfmode_pingroup = {
+ .name = "clcd_pfmode_grp",
+ .pins = clcd_pfmode_pins,
+ .npins = ARRAY_SIZE(clcd_pfmode_pins),
+ .modemuxs = clcd_pfmode_modemux,
+ .nmodemuxs = ARRAY_SIZE(clcd_pfmode_modemux),
+};
+
+static const char *const clcd_grps[] = { "clcd_lcdmode_grp", "clcd_pfmode_grp"
+};
+static struct spear_function clcd_function = {
+ .name = "clcd",
+ .groups = clcd_grps,
+ .ngroups = ARRAY_SIZE(clcd_grps),
+};
+
+/* tdm_pins */
+static const unsigned tdm_pins[] = { 34, 35, 36, 37, 38 };
+static struct spear_muxreg tdm_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK | PMX_SSP_CS_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux tdm_modemux[] = {
+ {
+ .modes = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE |
+ HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE
+ | HEND_WIFI_PHONE_MODE | ATA_PABX_WI2S_MODE
+ | ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE
+ | CAMU_WLCD_MODE | CAML_LCD_MODE,
+ .muxregs = tdm_muxreg,
+ .nmuxregs = ARRAY_SIZE(tdm_muxreg),
+ },
+};
+
+static struct spear_pingroup tdm_pingroup = {
+ .name = "tdm_grp",
+ .pins = tdm_pins,
+ .npins = ARRAY_SIZE(tdm_pins),
+ .modemuxs = tdm_modemux,
+ .nmodemuxs = ARRAY_SIZE(tdm_modemux),
+};
+
+static const char *const tdm_grps[] = { "tdm_grp" };
+static struct spear_function tdm_function = {
+ .name = "tdm",
+ .groups = tdm_grps,
+ .ngroups = ARRAY_SIZE(tdm_grps),
+};
+
+/* i2c_clk_pins */
+static const unsigned i2c_clk_pins[] = { 45, 46, 47, 48 };
+static struct spear_muxreg i2c_clk_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux i2c_clk_modemux[] = {
+ {
+ .modes = LEND_IP_PHONE_MODE | HEND_IP_PHONE_MODE |
+ LEND_WIFI_PHONE_MODE | HEND_WIFI_PHONE_MODE |
+ ATA_PABX_WI2S_MODE | ATA_PABX_I2S_MODE | CAML_LCDW_MODE
+ | CAML_LCD_MODE,
+ .muxregs = i2c_clk_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2c_clk_muxreg),
+ },
+};
+
+static struct spear_pingroup i2c_clk_pingroup = {
+ .name = "i2c_clk_grp_grp",
+ .pins = i2c_clk_pins,
+ .npins = ARRAY_SIZE(i2c_clk_pins),
+ .modemuxs = i2c_clk_modemux,
+ .nmodemuxs = ARRAY_SIZE(i2c_clk_modemux),
+};
+
+static const char *const i2c_grps[] = { "i2c_clk_grp" };
+static struct spear_function i2c_function = {
+ .name = "i2c1",
+ .groups = i2c_grps,
+ .ngroups = ARRAY_SIZE(i2c_grps),
+};
+
+/* caml_pins */
+static const unsigned caml_pins[] = { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 };
+static struct spear_muxreg caml_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux caml_modemux[] = {
+ {
+ .modes = CAML_LCDW_MODE | CAML_LCD_MODE,
+ .muxregs = caml_muxreg,
+ .nmuxregs = ARRAY_SIZE(caml_muxreg),
+ },
+};
+
+static struct spear_pingroup caml_pingroup = {
+ .name = "caml_grp",
+ .pins = caml_pins,
+ .npins = ARRAY_SIZE(caml_pins),
+ .modemuxs = caml_modemux,
+ .nmodemuxs = ARRAY_SIZE(caml_modemux),
+};
+
+/* camu_pins */
+static const unsigned camu_pins[] = { 16, 17, 18, 19, 20, 21, 45, 46, 47, 48 };
+static struct spear_muxreg camu_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK | PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux camu_modemux[] = {
+ {
+ .modes = CAMU_LCD_MODE | CAMU_WLCD_MODE,
+ .muxregs = camu_muxreg,
+ .nmuxregs = ARRAY_SIZE(camu_muxreg),
+ },
+};
+
+static struct spear_pingroup camu_pingroup = {
+ .name = "camu_grp",
+ .pins = camu_pins,
+ .npins = ARRAY_SIZE(camu_pins),
+ .modemuxs = camu_modemux,
+ .nmodemuxs = ARRAY_SIZE(camu_modemux),
+};
+
+static const char *const cam_grps[] = { "caml_grp", "camu_grp" };
+static struct spear_function cam_function = {
+ .name = "cam",
+ .groups = cam_grps,
+ .ngroups = ARRAY_SIZE(cam_grps),
+};
+
+/* dac_pins */
+static const unsigned dac_pins[] = { 43, 44 };
+static struct spear_muxreg dac_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux dac_modemux[] = {
+ {
+ .modes = ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE
+ | CAMU_WLCD_MODE | CAML_LCD_MODE,
+ .muxregs = dac_muxreg,
+ .nmuxregs = ARRAY_SIZE(dac_muxreg),
+ },
+};
+
+static struct spear_pingroup dac_pingroup = {
+ .name = "dac_grp",
+ .pins = dac_pins,
+ .npins = ARRAY_SIZE(dac_pins),
+ .modemuxs = dac_modemux,
+ .nmodemuxs = ARRAY_SIZE(dac_modemux),
+};
+
+static const char *const dac_grps[] = { "dac_grp" };
+static struct spear_function dac_function = {
+ .name = "dac",
+ .groups = dac_grps,
+ .ngroups = ARRAY_SIZE(dac_grps),
+};
+
+/* i2s_pins */
+static const unsigned i2s_pins[] = { 39, 40, 41, 42 };
+static struct spear_muxreg i2s_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux i2s_modemux[] = {
+ {
+ .modes = LEND_IP_PHONE_MODE | HEND_IP_PHONE_MODE
+ | LEND_WIFI_PHONE_MODE | HEND_WIFI_PHONE_MODE |
+ ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE
+ | CAMU_WLCD_MODE | CAML_LCD_MODE,
+ .muxregs = i2s_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2s_muxreg),
+ },
+};
+
+static struct spear_pingroup i2s_pingroup = {
+ .name = "i2s_grp",
+ .pins = i2s_pins,
+ .npins = ARRAY_SIZE(i2s_pins),
+ .modemuxs = i2s_modemux,
+ .nmodemuxs = ARRAY_SIZE(i2s_modemux),
+};
+
+static const char *const i2s_grps[] = { "i2s_grp" };
+static struct spear_function i2s_function = {
+ .name = "i2s",
+ .groups = i2s_grps,
+ .ngroups = ARRAY_SIZE(i2s_grps),
+};
+
+/* sdhci_4bit_pins */
+static const unsigned sdhci_4bit_pins[] = { 28, 29, 30, 31, 32, 33 };
+static struct spear_muxreg sdhci_4bit_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_GPIO_PIN0_MASK | PMX_GPIO_PIN1_MASK |
+ PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK |
+ PMX_GPIO_PIN4_MASK | PMX_GPIO_PIN5_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux sdhci_4bit_modemux[] = {
+ {
+ .modes = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE |
+ HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE |
+ HEND_WIFI_PHONE_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE |
+ CAMU_WLCD_MODE | CAML_LCD_MODE | ATA_PABX_WI2S_MODE,
+ .muxregs = sdhci_4bit_muxreg,
+ .nmuxregs = ARRAY_SIZE(sdhci_4bit_muxreg),
+ },
+};
+
+static struct spear_pingroup sdhci_4bit_pingroup = {
+ .name = "sdhci_4bit_grp",
+ .pins = sdhci_4bit_pins,
+ .npins = ARRAY_SIZE(sdhci_4bit_pins),
+ .modemuxs = sdhci_4bit_modemux,
+ .nmodemuxs = ARRAY_SIZE(sdhci_4bit_modemux),
+};
+
+/* sdhci_8bit_pins */
+static const unsigned sdhci_8bit_pins[] = { 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33 };
+static struct spear_muxreg sdhci_8bit_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_GPIO_PIN0_MASK | PMX_GPIO_PIN1_MASK |
+ PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK |
+ PMX_GPIO_PIN4_MASK | PMX_GPIO_PIN5_MASK | PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux sdhci_8bit_modemux[] = {
+ {
+ .modes = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE |
+ HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE |
+ HEND_WIFI_PHONE_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE |
+ CAMU_WLCD_MODE | CAML_LCD_MODE,
+ .muxregs = sdhci_8bit_muxreg,
+ .nmuxregs = ARRAY_SIZE(sdhci_8bit_muxreg),
+ },
+};
+
+static struct spear_pingroup sdhci_8bit_pingroup = {
+ .name = "sdhci_8bit_grp",
+ .pins = sdhci_8bit_pins,
+ .npins = ARRAY_SIZE(sdhci_8bit_pins),
+ .modemuxs = sdhci_8bit_modemux,
+ .nmodemuxs = ARRAY_SIZE(sdhci_8bit_modemux),
+};
+
+static const char *const sdhci_grps[] = { "sdhci_4bit_grp", "sdhci_8bit_grp" };
+static struct spear_function sdhci_function = {
+ .name = "sdhci",
+ .groups = sdhci_grps,
+ .ngroups = ARRAY_SIZE(sdhci_grps),
+};
+
+/* gpio1_0_to_3_pins */
+static const unsigned gpio1_0_to_3_pins[] = { 39, 40, 41, 42 };
+static struct spear_muxreg gpio1_0_to_3_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux gpio1_0_to_3_modemux[] = {
+ {
+ .modes = PHOTO_FRAME_MODE,
+ .muxregs = gpio1_0_to_3_muxreg,
+ .nmuxregs = ARRAY_SIZE(gpio1_0_to_3_muxreg),
+ },
+};
+
+static struct spear_pingroup gpio1_0_to_3_pingroup = {
+ .name = "gpio1_0_to_3_grp",
+ .pins = gpio1_0_to_3_pins,
+ .npins = ARRAY_SIZE(gpio1_0_to_3_pins),
+ .modemuxs = gpio1_0_to_3_modemux,
+ .nmodemuxs = ARRAY_SIZE(gpio1_0_to_3_modemux),
+};
+
+/* gpio1_4_to_7_pins */
+static const unsigned gpio1_4_to_7_pins[] = { 43, 44, 45, 46 };
+
+static struct spear_muxreg gpio1_4_to_7_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux gpio1_4_to_7_modemux[] = {
+ {
+ .modes = PHOTO_FRAME_MODE,
+ .muxregs = gpio1_4_to_7_muxreg,
+ .nmuxregs = ARRAY_SIZE(gpio1_4_to_7_muxreg),
+ },
+};
+
+static struct spear_pingroup gpio1_4_to_7_pingroup = {
+ .name = "gpio1_4_to_7_grp",
+ .pins = gpio1_4_to_7_pins,
+ .npins = ARRAY_SIZE(gpio1_4_to_7_pins),
+ .modemuxs = gpio1_4_to_7_modemux,
+ .nmodemuxs = ARRAY_SIZE(gpio1_4_to_7_modemux),
+};
+
+static const char *const gpio1_grps[] = { "gpio1_0_to_3_grp", "gpio1_4_to_7_grp"
+};
+static struct spear_function gpio1_function = {
+ .name = "gpio1",
+ .groups = gpio1_grps,
+ .ngroups = ARRAY_SIZE(gpio1_grps),
+};
+
+/* pingroups */
+static struct spear_pingroup *spear300_pingroups[] = {
+ SPEAR3XX_COMMON_PINGROUPS,
+ &fsmc_2chips_pingroup,
+ &fsmc_4chips_pingroup,
+ &clcd_lcdmode_pingroup,
+ &clcd_pfmode_pingroup,
+ &tdm_pingroup,
+ &i2c_clk_pingroup,
+ &caml_pingroup,
+ &camu_pingroup,
+ &dac_pingroup,
+ &i2s_pingroup,
+ &sdhci_4bit_pingroup,
+ &sdhci_8bit_pingroup,
+ &gpio1_0_to_3_pingroup,
+ &gpio1_4_to_7_pingroup,
+};
+
+/* functions */
+static struct spear_function *spear300_functions[] = {
+ SPEAR3XX_COMMON_FUNCTIONS,
+ &fsmc_function,
+ &clcd_function,
+ &tdm_function,
+ &i2c_function,
+ &cam_function,
+ &dac_function,
+ &i2s_function,
+ &sdhci_function,
+ &gpio1_function,
+};
+
+static struct of_device_id spear300_pinctrl_of_match[] __devinitdata = {
+ {
+ .compatible = "st,spear300-pinmux",
+ },
+ {},
+};
+
+static int __devinit spear300_pinctrl_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ spear3xx_machdata.groups = spear300_pingroups;
+ spear3xx_machdata.ngroups = ARRAY_SIZE(spear300_pingroups);
+ spear3xx_machdata.functions = spear300_functions;
+ spear3xx_machdata.nfunctions = ARRAY_SIZE(spear300_functions);
+
+ spear3xx_machdata.modes_supported = true;
+ spear3xx_machdata.pmx_modes = spear300_pmx_modes;
+ spear3xx_machdata.npmx_modes = ARRAY_SIZE(spear300_pmx_modes);
+
+ pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG);
+
+ ret = spear_pinctrl_probe(pdev, &spear3xx_machdata);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int __devexit spear300_pinctrl_remove(struct platform_device *pdev)
+{
+ return spear_pinctrl_remove(pdev);
+}
+
+static struct platform_driver spear300_pinctrl_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = spear300_pinctrl_of_match,
+ },
+ .probe = spear300_pinctrl_probe,
+ .remove = __devexit_p(spear300_pinctrl_remove),
+};
+
+static int __init spear300_pinctrl_init(void)
+{
+ return platform_driver_register(&spear300_pinctrl_driver);
+}
+arch_initcall(spear300_pinctrl_init);
+
+static void __exit spear300_pinctrl_exit(void)
+{
+ platform_driver_unregister(&spear300_pinctrl_driver);
+}
+module_exit(spear300_pinctrl_exit);
+
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
+MODULE_DESCRIPTION("ST Microelectronics SPEAr300 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, spear300_pinctrl_of_match);
diff --git a/drivers/pinctrl/spear/pinctrl-spear310.c b/drivers/pinctrl/spear/pinctrl-spear310.c
new file mode 100644
index 000000000000..1a9707605125
--- /dev/null
+++ b/drivers/pinctrl/spear/pinctrl-spear310.c
@@ -0,0 +1,431 @@
+/*
+ * Driver for the ST Microelectronics SPEAr310 pinmux
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "pinctrl-spear3xx.h"
+
+#define DRIVER_NAME "spear310-pinmux"
+
+/* addresses */
+#define PMX_CONFIG_REG 0x08
+
+/* emi_cs_0_to_5_pins */
+static const unsigned emi_cs_0_to_5_pins[] = { 45, 46, 47, 48, 49, 50 };
+static struct spear_muxreg emi_cs_0_to_5_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux emi_cs_0_to_5_modemux[] = {
+ {
+ .muxregs = emi_cs_0_to_5_muxreg,
+ .nmuxregs = ARRAY_SIZE(emi_cs_0_to_5_muxreg),
+ },
+};
+
+static struct spear_pingroup emi_cs_0_to_5_pingroup = {
+ .name = "emi_cs_0_to_5_grp",
+ .pins = emi_cs_0_to_5_pins,
+ .npins = ARRAY_SIZE(emi_cs_0_to_5_pins),
+ .modemuxs = emi_cs_0_to_5_modemux,
+ .nmodemuxs = ARRAY_SIZE(emi_cs_0_to_5_modemux),
+};
+
+static const char *const emi_cs_0_to_5_grps[] = { "emi_cs_0_to_5_grp" };
+static struct spear_function emi_cs_0_to_5_function = {
+ .name = "emi",
+ .groups = emi_cs_0_to_5_grps,
+ .ngroups = ARRAY_SIZE(emi_cs_0_to_5_grps),
+};
+
+/* uart1_pins */
+static const unsigned uart1_pins[] = { 0, 1 };
+static struct spear_muxreg uart1_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_FIRDA_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux uart1_modemux[] = {
+ {
+ .muxregs = uart1_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart1_muxreg),
+ },
+};
+
+static struct spear_pingroup uart1_pingroup = {
+ .name = "uart1_grp",
+ .pins = uart1_pins,
+ .npins = ARRAY_SIZE(uart1_pins),
+ .modemuxs = uart1_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart1_modemux),
+};
+
+static const char *const uart1_grps[] = { "uart1_grp" };
+static struct spear_function uart1_function = {
+ .name = "uart1",
+ .groups = uart1_grps,
+ .ngroups = ARRAY_SIZE(uart1_grps),
+};
+
+/* uart2_pins */
+static const unsigned uart2_pins[] = { 43, 44 };
+static struct spear_muxreg uart2_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux uart2_modemux[] = {
+ {
+ .muxregs = uart2_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart2_muxreg),
+ },
+};
+
+static struct spear_pingroup uart2_pingroup = {
+ .name = "uart2_grp",
+ .pins = uart2_pins,
+ .npins = ARRAY_SIZE(uart2_pins),
+ .modemuxs = uart2_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart2_modemux),
+};
+
+static const char *const uart2_grps[] = { "uart2_grp" };
+static struct spear_function uart2_function = {
+ .name = "uart2",
+ .groups = uart2_grps,
+ .ngroups = ARRAY_SIZE(uart2_grps),
+};
+
+/* uart3_pins */
+static const unsigned uart3_pins[] = { 37, 38 };
+static struct spear_muxreg uart3_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux uart3_modemux[] = {
+ {
+ .muxregs = uart3_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart3_muxreg),
+ },
+};
+
+static struct spear_pingroup uart3_pingroup = {
+ .name = "uart3_grp",
+ .pins = uart3_pins,
+ .npins = ARRAY_SIZE(uart3_pins),
+ .modemuxs = uart3_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart3_modemux),
+};
+
+static const char *const uart3_grps[] = { "uart3_grp" };
+static struct spear_function uart3_function = {
+ .name = "uart3",
+ .groups = uart3_grps,
+ .ngroups = ARRAY_SIZE(uart3_grps),
+};
+
+/* uart4_pins */
+static const unsigned uart4_pins[] = { 39, 40 };
+static struct spear_muxreg uart4_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux uart4_modemux[] = {
+ {
+ .muxregs = uart4_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart4_muxreg),
+ },
+};
+
+static struct spear_pingroup uart4_pingroup = {
+ .name = "uart4_grp",
+ .pins = uart4_pins,
+ .npins = ARRAY_SIZE(uart4_pins),
+ .modemuxs = uart4_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart4_modemux),
+};
+
+static const char *const uart4_grps[] = { "uart4_grp" };
+static struct spear_function uart4_function = {
+ .name = "uart4",
+ .groups = uart4_grps,
+ .ngroups = ARRAY_SIZE(uart4_grps),
+};
+
+/* uart5_pins */
+static const unsigned uart5_pins[] = { 41, 42 };
+static struct spear_muxreg uart5_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux uart5_modemux[] = {
+ {
+ .muxregs = uart5_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart5_muxreg),
+ },
+};
+
+static struct spear_pingroup uart5_pingroup = {
+ .name = "uart5_grp",
+ .pins = uart5_pins,
+ .npins = ARRAY_SIZE(uart5_pins),
+ .modemuxs = uart5_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart5_modemux),
+};
+
+static const char *const uart5_grps[] = { "uart5_grp" };
+static struct spear_function uart5_function = {
+ .name = "uart5",
+ .groups = uart5_grps,
+ .ngroups = ARRAY_SIZE(uart5_grps),
+};
+
+/* fsmc_pins */
+static const unsigned fsmc_pins[] = { 34, 35, 36 };
+static struct spear_muxreg fsmc_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_SSP_CS_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux fsmc_modemux[] = {
+ {
+ .muxregs = fsmc_muxreg,
+ .nmuxregs = ARRAY_SIZE(fsmc_muxreg),
+ },
+};
+
+static struct spear_pingroup fsmc_pingroup = {
+ .name = "fsmc_grp",
+ .pins = fsmc_pins,
+ .npins = ARRAY_SIZE(fsmc_pins),
+ .modemuxs = fsmc_modemux,
+ .nmodemuxs = ARRAY_SIZE(fsmc_modemux),
+};
+
+static const char *const fsmc_grps[] = { "fsmc_grp" };
+static struct spear_function fsmc_function = {
+ .name = "fsmc",
+ .groups = fsmc_grps,
+ .ngroups = ARRAY_SIZE(fsmc_grps),
+};
+
+/* rs485_0_pins */
+static const unsigned rs485_0_pins[] = { 19, 20, 21, 22, 23 };
+static struct spear_muxreg rs485_0_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux rs485_0_modemux[] = {
+ {
+ .muxregs = rs485_0_muxreg,
+ .nmuxregs = ARRAY_SIZE(rs485_0_muxreg),
+ },
+};
+
+static struct spear_pingroup rs485_0_pingroup = {
+ .name = "rs485_0_grp",
+ .pins = rs485_0_pins,
+ .npins = ARRAY_SIZE(rs485_0_pins),
+ .modemuxs = rs485_0_modemux,
+ .nmodemuxs = ARRAY_SIZE(rs485_0_modemux),
+};
+
+static const char *const rs485_0_grps[] = { "rs485_0" };
+static struct spear_function rs485_0_function = {
+ .name = "rs485_0",
+ .groups = rs485_0_grps,
+ .ngroups = ARRAY_SIZE(rs485_0_grps),
+};
+
+/* rs485_1_pins */
+static const unsigned rs485_1_pins[] = { 14, 15, 16, 17, 18 };
+static struct spear_muxreg rs485_1_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux rs485_1_modemux[] = {
+ {
+ .muxregs = rs485_1_muxreg,
+ .nmuxregs = ARRAY_SIZE(rs485_1_muxreg),
+ },
+};
+
+static struct spear_pingroup rs485_1_pingroup = {
+ .name = "rs485_1_grp",
+ .pins = rs485_1_pins,
+ .npins = ARRAY_SIZE(rs485_1_pins),
+ .modemuxs = rs485_1_modemux,
+ .nmodemuxs = ARRAY_SIZE(rs485_1_modemux),
+};
+
+static const char *const rs485_1_grps[] = { "rs485_1" };
+static struct spear_function rs485_1_function = {
+ .name = "rs485_1",
+ .groups = rs485_1_grps,
+ .ngroups = ARRAY_SIZE(rs485_1_grps),
+};
+
+/* tdm_pins */
+static const unsigned tdm_pins[] = { 10, 11, 12, 13 };
+static struct spear_muxreg tdm_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_modemux tdm_modemux[] = {
+ {
+ .muxregs = tdm_muxreg,
+ .nmuxregs = ARRAY_SIZE(tdm_muxreg),
+ },
+};
+
+static struct spear_pingroup tdm_pingroup = {
+ .name = "tdm_grp",
+ .pins = tdm_pins,
+ .npins = ARRAY_SIZE(tdm_pins),
+ .modemuxs = tdm_modemux,
+ .nmodemuxs = ARRAY_SIZE(tdm_modemux),
+};
+
+static const char *const tdm_grps[] = { "tdm_grp" };
+static struct spear_function tdm_function = {
+ .name = "tdm",
+ .groups = tdm_grps,
+ .ngroups = ARRAY_SIZE(tdm_grps),
+};
+
+/* pingroups */
+static struct spear_pingroup *spear310_pingroups[] = {
+ SPEAR3XX_COMMON_PINGROUPS,
+ &emi_cs_0_to_5_pingroup,
+ &uart1_pingroup,
+ &uart2_pingroup,
+ &uart3_pingroup,
+ &uart4_pingroup,
+ &uart5_pingroup,
+ &fsmc_pingroup,
+ &rs485_0_pingroup,
+ &rs485_1_pingroup,
+ &tdm_pingroup,
+};
+
+/* functions */
+static struct spear_function *spear310_functions[] = {
+ SPEAR3XX_COMMON_FUNCTIONS,
+ &emi_cs_0_to_5_function,
+ &uart1_function,
+ &uart2_function,
+ &uart3_function,
+ &uart4_function,
+ &uart5_function,
+ &fsmc_function,
+ &rs485_0_function,
+ &rs485_1_function,
+ &tdm_function,
+};
+
+static struct of_device_id spear310_pinctrl_of_match[] __devinitdata = {
+ {
+ .compatible = "st,spear310-pinmux",
+ },
+ {},
+};
+
+static int __devinit spear310_pinctrl_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ spear3xx_machdata.groups = spear310_pingroups;
+ spear3xx_machdata.ngroups = ARRAY_SIZE(spear310_pingroups);
+ spear3xx_machdata.functions = spear310_functions;
+ spear3xx_machdata.nfunctions = ARRAY_SIZE(spear310_functions);
+
+ pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG);
+
+ spear3xx_machdata.modes_supported = false;
+
+ ret = spear_pinctrl_probe(pdev, &spear3xx_machdata);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int __devexit spear310_pinctrl_remove(struct platform_device *pdev)
+{
+ return spear_pinctrl_remove(pdev);
+}
+
+static struct platform_driver spear310_pinctrl_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = spear310_pinctrl_of_match,
+ },
+ .probe = spear310_pinctrl_probe,
+ .remove = __devexit_p(spear310_pinctrl_remove),
+};
+
+static int __init spear310_pinctrl_init(void)
+{
+ return platform_driver_register(&spear310_pinctrl_driver);
+}
+arch_initcall(spear310_pinctrl_init);
+
+static void __exit spear310_pinctrl_exit(void)
+{
+ platform_driver_unregister(&spear310_pinctrl_driver);
+}
+module_exit(spear310_pinctrl_exit);
+
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
+MODULE_DESCRIPTION("ST Microelectronics SPEAr310 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, SPEAr310_pinctrl_of_match);
diff --git a/drivers/pinctrl/spear/pinctrl-spear320.c b/drivers/pinctrl/spear/pinctrl-spear320.c
new file mode 100644
index 000000000000..de726e6c283a
--- /dev/null
+++ b/drivers/pinctrl/spear/pinctrl-spear320.c
@@ -0,0 +1,3468 @@
+/*
+ * Driver for the ST Microelectronics SPEAr320 pinmux
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "pinctrl-spear3xx.h"
+
+#define DRIVER_NAME "spear320-pinmux"
+
+/* addresses */
+#define PMX_CONFIG_REG 0x0C
+#define MODE_CONFIG_REG 0x10
+#define MODE_EXT_CONFIG_REG 0x18
+
+/* modes */
+#define AUTO_NET_SMII_MODE (1 << 0)
+#define AUTO_NET_MII_MODE (1 << 1)
+#define AUTO_EXP_MODE (1 << 2)
+#define SMALL_PRINTERS_MODE (1 << 3)
+#define EXTENDED_MODE (1 << 4)
+
+static struct spear_pmx_mode pmx_mode_auto_net_smii = {
+ .name = "Automation Networking SMII mode",
+ .mode = AUTO_NET_SMII_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x00000007,
+ .val = 0x0,
+};
+
+static struct spear_pmx_mode pmx_mode_auto_net_mii = {
+ .name = "Automation Networking MII mode",
+ .mode = AUTO_NET_MII_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x00000007,
+ .val = 0x1,
+};
+
+static struct spear_pmx_mode pmx_mode_auto_exp = {
+ .name = "Automation Expanded mode",
+ .mode = AUTO_EXP_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x00000007,
+ .val = 0x2,
+};
+
+static struct spear_pmx_mode pmx_mode_small_printers = {
+ .name = "Small Printers mode",
+ .mode = SMALL_PRINTERS_MODE,
+ .reg = MODE_CONFIG_REG,
+ .mask = 0x00000007,
+ .val = 0x3,
+};
+
+static struct spear_pmx_mode pmx_mode_extended = {
+ .name = "extended mode",
+ .mode = EXTENDED_MODE,
+ .reg = MODE_EXT_CONFIG_REG,
+ .mask = 0x00000001,
+ .val = 0x1,
+};
+
+static struct spear_pmx_mode *spear320_pmx_modes[] = {
+ &pmx_mode_auto_net_smii,
+ &pmx_mode_auto_net_mii,
+ &pmx_mode_auto_exp,
+ &pmx_mode_small_printers,
+ &pmx_mode_extended,
+};
+
+/* Extended mode registers and their offsets */
+#define EXT_CTRL_REG 0x0018
+ #define MII_MDIO_MASK (1 << 4)
+ #define MII_MDIO_10_11_VAL 0
+ #define MII_MDIO_81_VAL (1 << 4)
+ #define EMI_FSMC_DYNAMIC_MUX_MASK (1 << 5)
+ #define MAC_MODE_MII 0
+ #define MAC_MODE_RMII 1
+ #define MAC_MODE_SMII 2
+ #define MAC_MODE_SS_SMII 3
+ #define MAC_MODE_MASK 0x3
+ #define MAC1_MODE_SHIFT 16
+ #define MAC2_MODE_SHIFT 18
+
+#define IP_SEL_PAD_0_9_REG 0x00A4
+ #define PMX_PL_0_1_MASK (0x3F << 0)
+ #define PMX_UART2_PL_0_1_VAL 0x0
+ #define PMX_I2C2_PL_0_1_VAL (0x4 | (0x4 << 3))
+
+ #define PMX_PL_2_3_MASK (0x3F << 6)
+ #define PMX_I2C2_PL_2_3_VAL 0x0
+ #define PMX_UART6_PL_2_3_VAL ((0x1 << 6) | (0x1 << 9))
+ #define PMX_UART1_ENH_PL_2_3_VAL ((0x4 << 6) | (0x4 << 9))
+
+ #define PMX_PL_4_5_MASK (0x3F << 12)
+ #define PMX_UART5_PL_4_5_VAL ((0x1 << 12) | (0x1 << 15))
+ #define PMX_UART1_ENH_PL_4_5_VAL ((0x4 << 12) | (0x4 << 15))
+ #define PMX_PL_5_MASK (0x7 << 15)
+ #define PMX_TOUCH_Y_PL_5_VAL 0x0
+
+ #define PMX_PL_6_7_MASK (0x3F << 18)
+ #define PMX_PL_6_MASK (0x7 << 18)
+ #define PMX_PL_7_MASK (0x7 << 21)
+ #define PMX_UART4_PL_6_7_VAL ((0x1 << 18) | (0x1 << 21))
+ #define PMX_PWM_3_PL_6_VAL (0x2 << 18)
+ #define PMX_PWM_2_PL_7_VAL (0x2 << 21)
+ #define PMX_UART1_ENH_PL_6_7_VAL ((0x4 << 18) | (0x4 << 21))
+
+ #define PMX_PL_8_9_MASK (0x3F << 24)
+ #define PMX_UART3_PL_8_9_VAL ((0x1 << 24) | (0x1 << 27))
+ #define PMX_PWM_0_1_PL_8_9_VAL ((0x2 << 24) | (0x2 << 27))
+ #define PMX_I2C1_PL_8_9_VAL ((0x4 << 24) | (0x4 << 27))
+
+#define IP_SEL_PAD_10_19_REG 0x00A8
+ #define PMX_PL_10_11_MASK (0x3F << 0)
+ #define PMX_SMII_PL_10_11_VAL 0
+ #define PMX_RMII_PL_10_11_VAL ((0x4 << 0) | (0x4 << 3))
+
+ #define PMX_PL_12_MASK (0x7 << 6)
+ #define PMX_PWM3_PL_12_VAL 0
+ #define PMX_SDHCI_CD_PL_12_VAL (0x4 << 6)
+
+ #define PMX_PL_13_14_MASK (0x3F << 9)
+ #define PMX_PL_13_MASK (0x7 << 9)
+ #define PMX_PL_14_MASK (0x7 << 12)
+ #define PMX_SSP2_PL_13_14_15_16_VAL 0
+ #define PMX_UART4_PL_13_14_VAL ((0x1 << 9) | (0x1 << 12))
+ #define PMX_RMII_PL_13_14_VAL ((0x4 << 9) | (0x4 << 12))
+ #define PMX_PWM2_PL_13_VAL (0x2 << 9)
+ #define PMX_PWM1_PL_14_VAL (0x2 << 12)
+
+ #define PMX_PL_15_MASK (0x7 << 15)
+ #define PMX_PWM0_PL_15_VAL (0x2 << 15)
+ #define PMX_PL_15_16_MASK (0x3F << 15)
+ #define PMX_UART3_PL_15_16_VAL ((0x1 << 15) | (0x1 << 18))
+ #define PMX_RMII_PL_15_16_VAL ((0x4 << 15) | (0x4 << 18))
+
+ #define PMX_PL_17_18_MASK (0x3F << 21)
+ #define PMX_SSP1_PL_17_18_19_20_VAL 0
+ #define PMX_RMII_PL_17_18_VAL ((0x4 << 21) | (0x4 << 24))
+
+ #define PMX_PL_19_MASK (0x7 << 27)
+ #define PMX_I2C2_PL_19_VAL (0x1 << 27)
+ #define PMX_RMII_PL_19_VAL (0x4 << 27)
+
+#define IP_SEL_PAD_20_29_REG 0x00AC
+ #define PMX_PL_20_MASK (0x7 << 0)
+ #define PMX_I2C2_PL_20_VAL (0x1 << 0)
+ #define PMX_RMII_PL_20_VAL (0x4 << 0)
+
+ #define PMX_PL_21_TO_27_MASK (0x1FFFFF << 3)
+ #define PMX_SMII_PL_21_TO_27_VAL 0
+ #define PMX_RMII_PL_21_TO_27_VAL ((0x4 << 3) | (0x4 << 6) | (0x4 << 9) | (0x4 << 12) | (0x4 << 15) | (0x4 << 18) | (0x4 << 21))
+
+ #define PMX_PL_28_29_MASK (0x3F << 24)
+ #define PMX_PL_28_MASK (0x7 << 24)
+ #define PMX_PL_29_MASK (0x7 << 27)
+ #define PMX_UART1_PL_28_29_VAL 0
+ #define PMX_PWM_3_PL_28_VAL (0x4 << 24)
+ #define PMX_PWM_2_PL_29_VAL (0x4 << 27)
+
+#define IP_SEL_PAD_30_39_REG 0x00B0
+ #define PMX_PL_30_31_MASK (0x3F << 0)
+ #define PMX_CAN1_PL_30_31_VAL (0)
+ #define PMX_PL_30_MASK (0x7 << 0)
+ #define PMX_PL_31_MASK (0x7 << 3)
+ #define PMX_PWM1_EXT_PL_30_VAL (0x4 << 0)
+ #define PMX_PWM0_EXT_PL_31_VAL (0x4 << 3)
+ #define PMX_UART1_ENH_PL_31_VAL (0x3 << 3)
+
+ #define PMX_PL_32_33_MASK (0x3F << 6)
+ #define PMX_CAN0_PL_32_33_VAL 0
+ #define PMX_UART1_ENH_PL_32_33_VAL ((0x3 << 6) | (0x3 << 9))
+ #define PMX_SSP2_PL_32_33_VAL ((0x4 << 6) | (0x4 << 9))
+
+ #define PMX_PL_34_MASK (0x7 << 12)
+ #define PMX_PWM2_PL_34_VAL 0
+ #define PMX_UART1_ENH_PL_34_VAL (0x2 << 12)
+ #define PMX_SSP2_PL_34_VAL (0x4 << 12)
+
+ #define PMX_PL_35_MASK (0x7 << 15)
+ #define PMX_I2S_REF_CLK_PL_35_VAL 0
+ #define PMX_UART1_ENH_PL_35_VAL (0x2 << 15)
+ #define PMX_SSP2_PL_35_VAL (0x4 << 15)
+
+ #define PMX_PL_36_MASK (0x7 << 18)
+ #define PMX_TOUCH_X_PL_36_VAL 0
+ #define PMX_UART1_ENH_PL_36_VAL (0x2 << 18)
+ #define PMX_SSP1_PL_36_VAL (0x4 << 18)
+
+ #define PMX_PL_37_38_MASK (0x3F << 21)
+ #define PMX_PWM0_1_PL_37_38_VAL 0
+ #define PMX_UART5_PL_37_38_VAL ((0x2 << 21) | (0x2 << 24))
+ #define PMX_SSP1_PL_37_38_VAL ((0x4 << 21) | (0x4 << 24))
+
+ #define PMX_PL_39_MASK (0x7 << 27)
+ #define PMX_I2S_PL_39_VAL 0
+ #define PMX_UART4_PL_39_VAL (0x2 << 27)
+ #define PMX_SSP1_PL_39_VAL (0x4 << 27)
+
+#define IP_SEL_PAD_40_49_REG 0x00B4
+ #define PMX_PL_40_MASK (0x7 << 0)
+ #define PMX_I2S_PL_40_VAL 0
+ #define PMX_UART4_PL_40_VAL (0x2 << 0)
+ #define PMX_PWM3_PL_40_VAL (0x4 << 0)
+
+ #define PMX_PL_41_42_MASK (0x3F << 3)
+ #define PMX_PL_41_MASK (0x7 << 3)
+ #define PMX_PL_42_MASK (0x7 << 6)
+ #define PMX_I2S_PL_41_42_VAL 0
+ #define PMX_UART3_PL_41_42_VAL ((0x2 << 3) | (0x2 << 6))
+ #define PMX_PWM2_PL_41_VAL (0x4 << 3)
+ #define PMX_PWM1_PL_42_VAL (0x4 << 6)
+
+ #define PMX_PL_43_MASK (0x7 << 9)
+ #define PMX_SDHCI_PL_43_VAL 0
+ #define PMX_UART1_ENH_PL_43_VAL (0x2 << 9)
+ #define PMX_PWM0_PL_43_VAL (0x4 << 9)
+
+ #define PMX_PL_44_45_MASK (0x3F << 12)
+ #define PMX_SDHCI_PL_44_45_VAL 0
+ #define PMX_UART1_ENH_PL_44_45_VAL ((0x2 << 12) | (0x2 << 15))
+ #define PMX_SSP2_PL_44_45_VAL ((0x4 << 12) | (0x4 << 15))
+
+ #define PMX_PL_46_47_MASK (0x3F << 18)
+ #define PMX_SDHCI_PL_46_47_VAL 0
+ #define PMX_FSMC_EMI_PL_46_47_VAL ((0x2 << 18) | (0x2 << 21))
+ #define PMX_SSP2_PL_46_47_VAL ((0x4 << 18) | (0x4 << 21))
+
+ #define PMX_PL_48_49_MASK (0x3F << 24)
+ #define PMX_SDHCI_PL_48_49_VAL 0
+ #define PMX_FSMC_EMI_PL_48_49_VAL ((0x2 << 24) | (0x2 << 27))
+ #define PMX_SSP1_PL_48_49_VAL ((0x4 << 24) | (0x4 << 27))
+
+#define IP_SEL_PAD_50_59_REG 0x00B8
+ #define PMX_PL_50_51_MASK (0x3F << 0)
+ #define PMX_EMI_PL_50_51_VAL ((0x2 << 0) | (0x2 << 3))
+ #define PMX_SSP1_PL_50_51_VAL ((0x4 << 0) | (0x4 << 3))
+ #define PMX_PL_50_MASK (0x7 << 0)
+ #define PMX_PL_51_MASK (0x7 << 3)
+ #define PMX_SDHCI_PL_50_VAL 0
+ #define PMX_SDHCI_CD_PL_51_VAL 0
+
+ #define PMX_PL_52_53_MASK (0x3F << 6)
+ #define PMX_FSMC_PL_52_53_VAL 0
+ #define PMX_EMI_PL_52_53_VAL ((0x2 << 6) | (0x2 << 9))
+ #define PMX_UART3_PL_52_53_VAL ((0x4 << 6) | (0x4 << 9))
+
+ #define PMX_PL_54_55_56_MASK (0x1FF << 12)
+ #define PMX_FSMC_EMI_PL_54_55_56_VAL ((0x2 << 12) | (0x2 << 15) | (0x2 << 18))
+
+ #define PMX_PL_57_MASK (0x7 << 21)
+ #define PMX_FSMC_PL_57_VAL 0
+ #define PMX_PWM3_PL_57_VAL (0x4 << 21)
+
+ #define PMX_PL_58_59_MASK (0x3F << 24)
+ #define PMX_PL_58_MASK (0x7 << 24)
+ #define PMX_PL_59_MASK (0x7 << 27)
+ #define PMX_FSMC_EMI_PL_58_59_VAL ((0x2 << 24) | (0x2 << 27))
+ #define PMX_PWM2_PL_58_VAL (0x4 << 24)
+ #define PMX_PWM1_PL_59_VAL (0x4 << 27)
+
+#define IP_SEL_PAD_60_69_REG 0x00BC
+ #define PMX_PL_60_MASK (0x7 << 0)
+ #define PMX_FSMC_PL_60_VAL 0
+ #define PMX_PWM0_PL_60_VAL (0x4 << 0)
+
+ #define PMX_PL_61_TO_64_MASK (0xFFF << 3)
+ #define PMX_FSMC_PL_61_TO_64_VAL ((0x2 << 3) | (0x2 << 6) | (0x2 << 9) | (0x2 << 12))
+ #define PMX_SSP2_PL_61_TO_64_VAL ((0x4 << 3) | (0x4 << 6) | (0x4 << 9) | (0x4 << 12))
+
+ #define PMX_PL_65_TO_68_MASK (0xFFF << 15)
+ #define PMX_FSMC_PL_65_TO_68_VAL ((0x2 << 15) | (0x2 << 18) | (0x2 << 21) | (0x2 << 24))
+ #define PMX_SSP1_PL_65_TO_68_VAL ((0x4 << 15) | (0x4 << 18) | (0x4 << 21) | (0x4 << 24))
+
+ #define PMX_PL_69_MASK (0x7 << 27)
+ #define PMX_CLCD_PL_69_VAL (0)
+ #define PMX_EMI_PL_69_VAL (0x2 << 27)
+ #define PMX_SPP_PL_69_VAL (0x3 << 27)
+ #define PMX_UART5_PL_69_VAL (0x4 << 27)
+
+#define IP_SEL_PAD_70_79_REG 0x00C0
+ #define PMX_PL_70_MASK (0x7 << 0)
+ #define PMX_CLCD_PL_70_VAL (0)
+ #define PMX_FSMC_EMI_PL_70_VAL (0x2 << 0)
+ #define PMX_SPP_PL_70_VAL (0x3 << 0)
+ #define PMX_UART5_PL_70_VAL (0x4 << 0)
+
+ #define PMX_PL_71_72_MASK (0x3F << 3)
+ #define PMX_CLCD_PL_71_72_VAL (0)
+ #define PMX_FSMC_EMI_PL_71_72_VAL ((0x2 << 3) | (0x2 << 6))
+ #define PMX_SPP_PL_71_72_VAL ((0x3 << 3) | (0x3 << 6))
+ #define PMX_UART4_PL_71_72_VAL ((0x4 << 3) | (0x4 << 6))
+
+ #define PMX_PL_73_MASK (0x7 << 9)
+ #define PMX_CLCD_PL_73_VAL (0)
+ #define PMX_FSMC_EMI_PL_73_VAL (0x2 << 9)
+ #define PMX_SPP_PL_73_VAL (0x3 << 9)
+ #define PMX_UART3_PL_73_VAL (0x4 << 9)
+
+ #define PMX_PL_74_MASK (0x7 << 12)
+ #define PMX_CLCD_PL_74_VAL (0)
+ #define PMX_EMI_PL_74_VAL (0x2 << 12)
+ #define PMX_SPP_PL_74_VAL (0x3 << 12)
+ #define PMX_UART3_PL_74_VAL (0x4 << 12)
+
+ #define PMX_PL_75_76_MASK (0x3F << 15)
+ #define PMX_CLCD_PL_75_76_VAL (0)
+ #define PMX_EMI_PL_75_76_VAL ((0x2 << 15) | (0x2 << 18))
+ #define PMX_SPP_PL_75_76_VAL ((0x3 << 15) | (0x3 << 18))
+ #define PMX_I2C2_PL_75_76_VAL ((0x4 << 15) | (0x4 << 18))
+
+ #define PMX_PL_77_78_79_MASK (0x1FF << 21)
+ #define PMX_CLCD_PL_77_78_79_VAL (0)
+ #define PMX_EMI_PL_77_78_79_VAL ((0x2 << 21) | (0x2 << 24) | (0x2 << 27))
+ #define PMX_SPP_PL_77_78_79_VAL ((0x3 << 21) | (0x3 << 24) | (0x3 << 27))
+ #define PMX_RS485_PL_77_78_79_VAL ((0x4 << 21) | (0x4 << 24) | (0x4 << 27))
+
+#define IP_SEL_PAD_80_89_REG 0x00C4
+ #define PMX_PL_80_TO_85_MASK (0x3FFFF << 0)
+ #define PMX_CLCD_PL_80_TO_85_VAL 0
+ #define PMX_MII2_PL_80_TO_85_VAL ((0x1 << 0) | (0x1 << 3) | (0x1 << 6) | (0x1 << 9) | (0x1 << 12) | (0x1 << 15))
+ #define PMX_EMI_PL_80_TO_85_VAL ((0x2 << 0) | (0x2 << 3) | (0x2 << 6) | (0x2 << 9) | (0x2 << 12) | (0x2 << 15))
+ #define PMX_SPP_PL_80_TO_85_VAL ((0x3 << 0) | (0x3 << 3) | (0x3 << 6) | (0x3 << 9) | (0x3 << 12) | (0x3 << 15))
+ #define PMX_UART1_ENH_PL_80_TO_85_VAL ((0x4 << 0) | (0x4 << 3) | (0x4 << 6) | (0x4 << 9) | (0x4 << 12) | (0x4 << 15))
+
+ #define PMX_PL_86_87_MASK (0x3F << 18)
+ #define PMX_PL_86_MASK (0x7 << 18)
+ #define PMX_PL_87_MASK (0x7 << 21)
+ #define PMX_CLCD_PL_86_87_VAL 0
+ #define PMX_MII2_PL_86_87_VAL ((0x1 << 18) | (0x1 << 21))
+ #define PMX_EMI_PL_86_87_VAL ((0x2 << 18) | (0x2 << 21))
+ #define PMX_PWM3_PL_86_VAL (0x4 << 18)
+ #define PMX_PWM2_PL_87_VAL (0x4 << 21)
+
+ #define PMX_PL_88_89_MASK (0x3F << 24)
+ #define PMX_CLCD_PL_88_89_VAL 0
+ #define PMX_MII2_PL_88_89_VAL ((0x1 << 24) | (0x1 << 27))
+ #define PMX_EMI_PL_88_89_VAL ((0x2 << 24) | (0x2 << 27))
+ #define PMX_UART6_PL_88_89_VAL ((0x3 << 24) | (0x3 << 27))
+ #define PMX_PWM0_1_PL_88_89_VAL ((0x4 << 24) | (0x4 << 27))
+
+#define IP_SEL_PAD_90_99_REG 0x00C8
+ #define PMX_PL_90_91_MASK (0x3F << 0)
+ #define PMX_CLCD_PL_90_91_VAL 0
+ #define PMX_MII2_PL_90_91_VAL ((0x1 << 0) | (0x1 << 3))
+ #define PMX_EMI1_PL_90_91_VAL ((0x2 << 0) | (0x2 << 3))
+ #define PMX_UART5_PL_90_91_VAL ((0x3 << 0) | (0x3 << 3))
+ #define PMX_SSP2_PL_90_91_VAL ((0x4 << 0) | (0x4 << 3))
+
+ #define PMX_PL_92_93_MASK (0x3F << 6)
+ #define PMX_CLCD_PL_92_93_VAL 0
+ #define PMX_MII2_PL_92_93_VAL ((0x1 << 6) | (0x1 << 9))
+ #define PMX_EMI1_PL_92_93_VAL ((0x2 << 6) | (0x2 << 9))
+ #define PMX_UART4_PL_92_93_VAL ((0x3 << 6) | (0x3 << 9))
+ #define PMX_SSP2_PL_92_93_VAL ((0x4 << 6) | (0x4 << 9))
+
+ #define PMX_PL_94_95_MASK (0x3F << 12)
+ #define PMX_CLCD_PL_94_95_VAL 0
+ #define PMX_MII2_PL_94_95_VAL ((0x1 << 12) | (0x1 << 15))
+ #define PMX_EMI1_PL_94_95_VAL ((0x2 << 12) | (0x2 << 15))
+ #define PMX_UART3_PL_94_95_VAL ((0x3 << 12) | (0x3 << 15))
+ #define PMX_SSP1_PL_94_95_VAL ((0x4 << 12) | (0x4 << 15))
+
+ #define PMX_PL_96_97_MASK (0x3F << 18)
+ #define PMX_CLCD_PL_96_97_VAL 0
+ #define PMX_MII2_PL_96_97_VAL ((0x1 << 18) | (0x1 << 21))
+ #define PMX_EMI1_PL_96_97_VAL ((0x2 << 18) | (0x2 << 21))
+ #define PMX_I2C2_PL_96_97_VAL ((0x3 << 18) | (0x3 << 21))
+ #define PMX_SSP1_PL_96_97_VAL ((0x4 << 18) | (0x4 << 21))
+
+ #define PMX_PL_98_MASK (0x7 << 24)
+ #define PMX_CLCD_PL_98_VAL 0
+ #define PMX_I2C1_PL_98_VAL (0x2 << 24)
+ #define PMX_UART3_PL_98_VAL (0x4 << 24)
+
+ #define PMX_PL_99_MASK (0x7 << 27)
+ #define PMX_SDHCI_PL_99_VAL 0
+ #define PMX_I2C1_PL_99_VAL (0x2 << 27)
+ #define PMX_UART3_PL_99_VAL (0x4 << 27)
+
+#define IP_SEL_MIX_PAD_REG 0x00CC
+ #define PMX_PL_100_101_MASK (0x3F << 0)
+ #define PMX_SDHCI_PL_100_101_VAL 0
+ #define PMX_UART4_PL_100_101_VAL ((0x4 << 0) | (0x4 << 3))
+
+ #define PMX_SSP1_PORT_SEL_MASK (0x7 << 8)
+ #define PMX_SSP1_PORT_94_TO_97_VAL 0
+ #define PMX_SSP1_PORT_65_TO_68_VAL (0x1 << 8)
+ #define PMX_SSP1_PORT_48_TO_51_VAL (0x2 << 8)
+ #define PMX_SSP1_PORT_36_TO_39_VAL (0x3 << 8)
+ #define PMX_SSP1_PORT_17_TO_20_VAL (0x4 << 8)
+
+ #define PMX_SSP2_PORT_SEL_MASK (0x7 << 11)
+ #define PMX_SSP2_PORT_90_TO_93_VAL 0
+ #define PMX_SSP2_PORT_61_TO_64_VAL (0x1 << 11)
+ #define PMX_SSP2_PORT_44_TO_47_VAL (0x2 << 11)
+ #define PMX_SSP2_PORT_32_TO_35_VAL (0x3 << 11)
+ #define PMX_SSP2_PORT_13_TO_16_VAL (0x4 << 11)
+
+ #define PMX_UART1_ENH_PORT_SEL_MASK (0x3 << 14)
+ #define PMX_UART1_ENH_PORT_81_TO_85_VAL 0
+ #define PMX_UART1_ENH_PORT_44_45_34_36_VAL (0x1 << 14)
+ #define PMX_UART1_ENH_PORT_32_TO_34_36_VAL (0x2 << 14)
+ #define PMX_UART1_ENH_PORT_3_TO_5_7_VAL (0x3 << 14)
+
+ #define PMX_UART3_PORT_SEL_MASK (0x7 << 16)
+ #define PMX_UART3_PORT_94_VAL 0
+ #define PMX_UART3_PORT_73_VAL (0x1 << 16)
+ #define PMX_UART3_PORT_52_VAL (0x2 << 16)
+ #define PMX_UART3_PORT_41_VAL (0x3 << 16)
+ #define PMX_UART3_PORT_15_VAL (0x4 << 16)
+ #define PMX_UART3_PORT_8_VAL (0x5 << 16)
+ #define PMX_UART3_PORT_99_VAL (0x6 << 16)
+
+ #define PMX_UART4_PORT_SEL_MASK (0x7 << 19)
+ #define PMX_UART4_PORT_92_VAL 0
+ #define PMX_UART4_PORT_71_VAL (0x1 << 19)
+ #define PMX_UART4_PORT_39_VAL (0x2 << 19)
+ #define PMX_UART4_PORT_13_VAL (0x3 << 19)
+ #define PMX_UART4_PORT_6_VAL (0x4 << 19)
+ #define PMX_UART4_PORT_101_VAL (0x5 << 19)
+
+ #define PMX_UART5_PORT_SEL_MASK (0x3 << 22)
+ #define PMX_UART5_PORT_90_VAL 0
+ #define PMX_UART5_PORT_69_VAL (0x1 << 22)
+ #define PMX_UART5_PORT_37_VAL (0x2 << 22)
+ #define PMX_UART5_PORT_4_VAL (0x3 << 22)
+
+ #define PMX_UART6_PORT_SEL_MASK (0x1 << 24)
+ #define PMX_UART6_PORT_88_VAL 0
+ #define PMX_UART6_PORT_2_VAL (0x1 << 24)
+
+ #define PMX_I2C1_PORT_SEL_MASK (0x1 << 25)
+ #define PMX_I2C1_PORT_8_9_VAL 0
+ #define PMX_I2C1_PORT_98_99_VAL (0x1 << 25)
+
+ #define PMX_I2C2_PORT_SEL_MASK (0x3 << 26)
+ #define PMX_I2C2_PORT_96_97_VAL 0
+ #define PMX_I2C2_PORT_75_76_VAL (0x1 << 26)
+ #define PMX_I2C2_PORT_19_20_VAL (0x2 << 26)
+ #define PMX_I2C2_PORT_2_3_VAL (0x3 << 26)
+ #define PMX_I2C2_PORT_0_1_VAL (0x4 << 26)
+
+ #define PMX_SDHCI_CD_PORT_SEL_MASK (0x1 << 29)
+ #define PMX_SDHCI_CD_PORT_12_VAL 0
+ #define PMX_SDHCI_CD_PORT_51_VAL (0x1 << 29)
+
+/* Pad multiplexing for CLCD device */
+static const unsigned clcd_pins[] = { 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
+ 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
+ 97 };
+static struct spear_muxreg clcd_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_60_69_REG,
+ .mask = PMX_PL_69_MASK,
+ .val = PMX_CLCD_PL_69_VAL,
+ }, {
+ .reg = IP_SEL_PAD_70_79_REG,
+ .mask = PMX_PL_70_MASK | PMX_PL_71_72_MASK | PMX_PL_73_MASK |
+ PMX_PL_74_MASK | PMX_PL_75_76_MASK |
+ PMX_PL_77_78_79_MASK,
+ .val = PMX_CLCD_PL_70_VAL | PMX_CLCD_PL_71_72_VAL |
+ PMX_CLCD_PL_73_VAL | PMX_CLCD_PL_74_VAL |
+ PMX_CLCD_PL_75_76_VAL | PMX_CLCD_PL_77_78_79_VAL,
+ }, {
+ .reg = IP_SEL_PAD_80_89_REG,
+ .mask = PMX_PL_80_TO_85_MASK | PMX_PL_86_87_MASK |
+ PMX_PL_88_89_MASK,
+ .val = PMX_CLCD_PL_80_TO_85_VAL | PMX_CLCD_PL_86_87_VAL |
+ PMX_CLCD_PL_88_89_VAL,
+ }, {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_90_91_MASK | PMX_PL_92_93_MASK |
+ PMX_PL_94_95_MASK | PMX_PL_96_97_MASK | PMX_PL_98_MASK,
+ .val = PMX_CLCD_PL_90_91_VAL | PMX_CLCD_PL_92_93_VAL |
+ PMX_CLCD_PL_94_95_VAL | PMX_CLCD_PL_96_97_VAL |
+ PMX_CLCD_PL_98_VAL,
+ },
+};
+
+static struct spear_modemux clcd_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = clcd_muxreg,
+ .nmuxregs = ARRAY_SIZE(clcd_muxreg),
+ },
+};
+
+static struct spear_pingroup clcd_pingroup = {
+ .name = "clcd_grp",
+ .pins = clcd_pins,
+ .npins = ARRAY_SIZE(clcd_pins),
+ .modemuxs = clcd_modemux,
+ .nmodemuxs = ARRAY_SIZE(clcd_modemux),
+};
+
+static const char *const clcd_grps[] = { "clcd_grp" };
+static struct spear_function clcd_function = {
+ .name = "clcd",
+ .groups = clcd_grps,
+ .ngroups = ARRAY_SIZE(clcd_grps),
+};
+
+/* Pad multiplexing for EMI (Parallel NOR flash) device */
+static const unsigned emi_pins[] = { 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92,
+ 93, 94, 95, 96, 97 };
+static struct spear_muxreg emi_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg emi_ext_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_46_47_MASK | PMX_PL_48_49_MASK,
+ .val = PMX_FSMC_EMI_PL_46_47_VAL | PMX_FSMC_EMI_PL_48_49_VAL,
+ }, {
+ .reg = IP_SEL_PAD_50_59_REG,
+ .mask = PMX_PL_50_51_MASK | PMX_PL_52_53_MASK |
+ PMX_PL_54_55_56_MASK | PMX_PL_58_59_MASK,
+ .val = PMX_EMI_PL_50_51_VAL | PMX_EMI_PL_52_53_VAL |
+ PMX_FSMC_EMI_PL_54_55_56_VAL |
+ PMX_FSMC_EMI_PL_58_59_VAL,
+ }, {
+ .reg = IP_SEL_PAD_60_69_REG,
+ .mask = PMX_PL_69_MASK,
+ .val = PMX_EMI_PL_69_VAL,
+ }, {
+ .reg = IP_SEL_PAD_70_79_REG,
+ .mask = PMX_PL_70_MASK | PMX_PL_71_72_MASK | PMX_PL_73_MASK |
+ PMX_PL_74_MASK | PMX_PL_75_76_MASK |
+ PMX_PL_77_78_79_MASK,
+ .val = PMX_FSMC_EMI_PL_70_VAL | PMX_FSMC_EMI_PL_71_72_VAL |
+ PMX_FSMC_EMI_PL_73_VAL | PMX_EMI_PL_74_VAL |
+ PMX_EMI_PL_75_76_VAL | PMX_EMI_PL_77_78_79_VAL,
+ }, {
+ .reg = IP_SEL_PAD_80_89_REG,
+ .mask = PMX_PL_80_TO_85_MASK | PMX_PL_86_87_MASK |
+ PMX_PL_88_89_MASK,
+ .val = PMX_EMI_PL_80_TO_85_VAL | PMX_EMI_PL_86_87_VAL |
+ PMX_EMI_PL_88_89_VAL,
+ }, {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_90_91_MASK | PMX_PL_92_93_MASK |
+ PMX_PL_94_95_MASK | PMX_PL_96_97_MASK,
+ .val = PMX_EMI1_PL_90_91_VAL | PMX_EMI1_PL_92_93_VAL |
+ PMX_EMI1_PL_94_95_VAL | PMX_EMI1_PL_96_97_VAL,
+ }, {
+ .reg = EXT_CTRL_REG,
+ .mask = EMI_FSMC_DYNAMIC_MUX_MASK,
+ .val = EMI_FSMC_DYNAMIC_MUX_MASK,
+ },
+};
+
+static struct spear_modemux emi_modemux[] = {
+ {
+ .modes = AUTO_EXP_MODE | EXTENDED_MODE,
+ .muxregs = emi_muxreg,
+ .nmuxregs = ARRAY_SIZE(emi_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = emi_ext_muxreg,
+ .nmuxregs = ARRAY_SIZE(emi_ext_muxreg),
+ },
+};
+
+static struct spear_pingroup emi_pingroup = {
+ .name = "emi_grp",
+ .pins = emi_pins,
+ .npins = ARRAY_SIZE(emi_pins),
+ .modemuxs = emi_modemux,
+ .nmodemuxs = ARRAY_SIZE(emi_modemux),
+};
+
+static const char *const emi_grps[] = { "emi_grp" };
+static struct spear_function emi_function = {
+ .name = "emi",
+ .groups = emi_grps,
+ .ngroups = ARRAY_SIZE(emi_grps),
+};
+
+/* Pad multiplexing for FSMC (NAND flash) device */
+static const unsigned fsmc_8bit_pins[] = { 52, 53, 54, 55, 56, 57, 58, 59, 60,
+ 61, 62, 63, 64, 65, 66, 67, 68 };
+static struct spear_muxreg fsmc_8bit_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_50_59_REG,
+ .mask = PMX_PL_52_53_MASK | PMX_PL_54_55_56_MASK |
+ PMX_PL_57_MASK | PMX_PL_58_59_MASK,
+ .val = PMX_FSMC_PL_52_53_VAL | PMX_FSMC_EMI_PL_54_55_56_VAL |
+ PMX_FSMC_PL_57_VAL | PMX_FSMC_EMI_PL_58_59_VAL,
+ }, {
+ .reg = IP_SEL_PAD_60_69_REG,
+ .mask = PMX_PL_60_MASK | PMX_PL_61_TO_64_MASK |
+ PMX_PL_65_TO_68_MASK,
+ .val = PMX_FSMC_PL_60_VAL | PMX_FSMC_PL_61_TO_64_VAL |
+ PMX_FSMC_PL_65_TO_68_VAL,
+ }, {
+ .reg = EXT_CTRL_REG,
+ .mask = EMI_FSMC_DYNAMIC_MUX_MASK,
+ .val = EMI_FSMC_DYNAMIC_MUX_MASK,
+ },
+};
+
+static struct spear_modemux fsmc_8bit_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = fsmc_8bit_muxreg,
+ .nmuxregs = ARRAY_SIZE(fsmc_8bit_muxreg),
+ },
+};
+
+static struct spear_pingroup fsmc_8bit_pingroup = {
+ .name = "fsmc_8bit_grp",
+ .pins = fsmc_8bit_pins,
+ .npins = ARRAY_SIZE(fsmc_8bit_pins),
+ .modemuxs = fsmc_8bit_modemux,
+ .nmodemuxs = ARRAY_SIZE(fsmc_8bit_modemux),
+};
+
+static const unsigned fsmc_16bit_pins[] = { 46, 47, 48, 49, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 70, 71, 72, 73 };
+static struct spear_muxreg fsmc_16bit_autoexp_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg fsmc_16bit_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_46_47_MASK | PMX_PL_48_49_MASK,
+ .val = PMX_FSMC_EMI_PL_46_47_VAL | PMX_FSMC_EMI_PL_48_49_VAL,
+ }, {
+ .reg = IP_SEL_PAD_70_79_REG,
+ .mask = PMX_PL_70_MASK | PMX_PL_71_72_MASK | PMX_PL_73_MASK,
+ .val = PMX_FSMC_EMI_PL_70_VAL | PMX_FSMC_EMI_PL_71_72_VAL |
+ PMX_FSMC_EMI_PL_73_VAL,
+ }
+};
+
+static struct spear_modemux fsmc_16bit_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = fsmc_8bit_muxreg,
+ .nmuxregs = ARRAY_SIZE(fsmc_8bit_muxreg),
+ }, {
+ .modes = AUTO_EXP_MODE | EXTENDED_MODE,
+ .muxregs = fsmc_16bit_autoexp_muxreg,
+ .nmuxregs = ARRAY_SIZE(fsmc_16bit_autoexp_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = fsmc_16bit_muxreg,
+ .nmuxregs = ARRAY_SIZE(fsmc_16bit_muxreg),
+ },
+};
+
+static struct spear_pingroup fsmc_16bit_pingroup = {
+ .name = "fsmc_16bit_grp",
+ .pins = fsmc_16bit_pins,
+ .npins = ARRAY_SIZE(fsmc_16bit_pins),
+ .modemuxs = fsmc_16bit_modemux,
+ .nmodemuxs = ARRAY_SIZE(fsmc_16bit_modemux),
+};
+
+static const char *const fsmc_grps[] = { "fsmc_8bit_grp", "fsmc_16bit_grp" };
+static struct spear_function fsmc_function = {
+ .name = "fsmc",
+ .groups = fsmc_grps,
+ .ngroups = ARRAY_SIZE(fsmc_grps),
+};
+
+/* Pad multiplexing for SPP device */
+static const unsigned spp_pins[] = { 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85 };
+static struct spear_muxreg spp_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_60_69_REG,
+ .mask = PMX_PL_69_MASK,
+ .val = PMX_SPP_PL_69_VAL,
+ }, {
+ .reg = IP_SEL_PAD_70_79_REG,
+ .mask = PMX_PL_70_MASK | PMX_PL_71_72_MASK | PMX_PL_73_MASK |
+ PMX_PL_74_MASK | PMX_PL_75_76_MASK |
+ PMX_PL_77_78_79_MASK,
+ .val = PMX_SPP_PL_70_VAL | PMX_SPP_PL_71_72_VAL |
+ PMX_SPP_PL_73_VAL | PMX_SPP_PL_74_VAL |
+ PMX_SPP_PL_75_76_VAL | PMX_SPP_PL_77_78_79_VAL,
+ }, {
+ .reg = IP_SEL_PAD_80_89_REG,
+ .mask = PMX_PL_80_TO_85_MASK,
+ .val = PMX_SPP_PL_80_TO_85_VAL,
+ },
+};
+
+static struct spear_modemux spp_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = spp_muxreg,
+ .nmuxregs = ARRAY_SIZE(spp_muxreg),
+ },
+};
+
+static struct spear_pingroup spp_pingroup = {
+ .name = "spp_grp",
+ .pins = spp_pins,
+ .npins = ARRAY_SIZE(spp_pins),
+ .modemuxs = spp_modemux,
+ .nmodemuxs = ARRAY_SIZE(spp_modemux),
+};
+
+static const char *const spp_grps[] = { "spp_grp" };
+static struct spear_function spp_function = {
+ .name = "spp",
+ .groups = spp_grps,
+ .ngroups = ARRAY_SIZE(spp_grps),
+};
+
+/* Pad multiplexing for SDHCI device */
+static const unsigned sdhci_led_pins[] = { 34 };
+static struct spear_muxreg sdhci_led_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_SSP_CS_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg sdhci_led_ext_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_34_MASK,
+ .val = PMX_PWM2_PL_34_VAL,
+ },
+};
+
+static struct spear_modemux sdhci_led_modemux[] = {
+ {
+ .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | EXTENDED_MODE,
+ .muxregs = sdhci_led_muxreg,
+ .nmuxregs = ARRAY_SIZE(sdhci_led_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = sdhci_led_ext_muxreg,
+ .nmuxregs = ARRAY_SIZE(sdhci_led_ext_muxreg),
+ },
+};
+
+static struct spear_pingroup sdhci_led_pingroup = {
+ .name = "sdhci_led_grp",
+ .pins = sdhci_led_pins,
+ .npins = ARRAY_SIZE(sdhci_led_pins),
+ .modemuxs = sdhci_led_modemux,
+ .nmodemuxs = ARRAY_SIZE(sdhci_led_modemux),
+};
+
+static const unsigned sdhci_cd_12_pins[] = { 12, 43, 44, 45, 46, 47, 48, 49,
+ 50};
+static const unsigned sdhci_cd_51_pins[] = { 43, 44, 45, 46, 47, 48, 49, 50, 51
+};
+static struct spear_muxreg sdhci_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg sdhci_ext_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_43_MASK | PMX_PL_44_45_MASK | PMX_PL_46_47_MASK |
+ PMX_PL_48_49_MASK,
+ .val = PMX_SDHCI_PL_43_VAL | PMX_SDHCI_PL_44_45_VAL |
+ PMX_SDHCI_PL_46_47_VAL | PMX_SDHCI_PL_48_49_VAL,
+ }, {
+ .reg = IP_SEL_PAD_50_59_REG,
+ .mask = PMX_PL_50_MASK,
+ .val = PMX_SDHCI_PL_50_VAL,
+ }, {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_99_MASK,
+ .val = PMX_SDHCI_PL_99_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_PL_100_101_MASK,
+ .val = PMX_SDHCI_PL_100_101_VAL,
+ },
+};
+
+static struct spear_muxreg sdhci_cd_12_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_10_19_REG,
+ .mask = PMX_PL_12_MASK,
+ .val = PMX_SDHCI_CD_PL_12_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SDHCI_CD_PORT_SEL_MASK,
+ .val = PMX_SDHCI_CD_PORT_12_VAL,
+ },
+};
+
+static struct spear_muxreg sdhci_cd_51_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_50_59_REG,
+ .mask = PMX_PL_51_MASK,
+ .val = PMX_SDHCI_CD_PL_51_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SDHCI_CD_PORT_SEL_MASK,
+ .val = PMX_SDHCI_CD_PORT_51_VAL,
+ },
+};
+
+#define pmx_sdhci_common_modemux \
+ { \
+ .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | \
+ SMALL_PRINTERS_MODE | EXTENDED_MODE, \
+ .muxregs = sdhci_muxreg, \
+ .nmuxregs = ARRAY_SIZE(sdhci_muxreg), \
+ }, { \
+ .modes = EXTENDED_MODE, \
+ .muxregs = sdhci_ext_muxreg, \
+ .nmuxregs = ARRAY_SIZE(sdhci_ext_muxreg), \
+ }
+
+static struct spear_modemux sdhci_modemux[][3] = {
+ {
+ /* select pin 12 for cd */
+ pmx_sdhci_common_modemux,
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = sdhci_cd_12_muxreg,
+ .nmuxregs = ARRAY_SIZE(sdhci_cd_12_muxreg),
+ },
+ }, {
+ /* select pin 51 for cd */
+ pmx_sdhci_common_modemux,
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = sdhci_cd_51_muxreg,
+ .nmuxregs = ARRAY_SIZE(sdhci_cd_51_muxreg),
+ },
+ }
+};
+
+static struct spear_pingroup sdhci_pingroup[] = {
+ {
+ .name = "sdhci_cd_12_grp",
+ .pins = sdhci_cd_12_pins,
+ .npins = ARRAY_SIZE(sdhci_cd_12_pins),
+ .modemuxs = sdhci_modemux[0],
+ .nmodemuxs = ARRAY_SIZE(sdhci_modemux[0]),
+ }, {
+ .name = "sdhci_cd_51_grp",
+ .pins = sdhci_cd_51_pins,
+ .npins = ARRAY_SIZE(sdhci_cd_51_pins),
+ .modemuxs = sdhci_modemux[1],
+ .nmodemuxs = ARRAY_SIZE(sdhci_modemux[1]),
+ },
+};
+
+static const char *const sdhci_grps[] = { "sdhci_cd_12_grp", "sdhci_cd_51_grp",
+ "sdhci_led_grp" };
+
+static struct spear_function sdhci_function = {
+ .name = "sdhci",
+ .groups = sdhci_grps,
+ .ngroups = ARRAY_SIZE(sdhci_grps),
+};
+
+/* Pad multiplexing for I2S device */
+static const unsigned i2s_pins[] = { 35, 39, 40, 41, 42 };
+static struct spear_muxreg i2s_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_SSP_CS_MASK,
+ .val = 0,
+ }, {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg i2s_ext_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_35_MASK | PMX_PL_39_MASK,
+ .val = PMX_I2S_REF_CLK_PL_35_VAL | PMX_I2S_PL_39_VAL,
+ }, {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_40_MASK | PMX_PL_41_42_MASK,
+ .val = PMX_I2S_PL_40_VAL | PMX_I2S_PL_41_42_VAL,
+ },
+};
+
+static struct spear_modemux i2s_modemux[] = {
+ {
+ .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | EXTENDED_MODE,
+ .muxregs = i2s_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2s_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = i2s_ext_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2s_ext_muxreg),
+ },
+};
+
+static struct spear_pingroup i2s_pingroup = {
+ .name = "i2s_grp",
+ .pins = i2s_pins,
+ .npins = ARRAY_SIZE(i2s_pins),
+ .modemuxs = i2s_modemux,
+ .nmodemuxs = ARRAY_SIZE(i2s_modemux),
+};
+
+static const char *const i2s_grps[] = { "i2s_grp" };
+static struct spear_function i2s_function = {
+ .name = "i2s",
+ .groups = i2s_grps,
+ .ngroups = ARRAY_SIZE(i2s_grps),
+};
+
+/* Pad multiplexing for UART1 device */
+static const unsigned uart1_pins[] = { 28, 29 };
+static struct spear_muxreg uart1_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_GPIO_PIN0_MASK | PMX_GPIO_PIN1_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg uart1_ext_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_20_29_REG,
+ .mask = PMX_PL_28_29_MASK,
+ .val = PMX_UART1_PL_28_29_VAL,
+ },
+};
+
+static struct spear_modemux uart1_modemux[] = {
+ {
+ .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | AUTO_EXP_MODE
+ | SMALL_PRINTERS_MODE | EXTENDED_MODE,
+ .muxregs = uart1_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart1_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart1_ext_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart1_ext_muxreg),
+ },
+};
+
+static struct spear_pingroup uart1_pingroup = {
+ .name = "uart1_grp",
+ .pins = uart1_pins,
+ .npins = ARRAY_SIZE(uart1_pins),
+ .modemuxs = uart1_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart1_modemux),
+};
+
+static const char *const uart1_grps[] = { "uart1_grp" };
+static struct spear_function uart1_function = {
+ .name = "uart1",
+ .groups = uart1_grps,
+ .ngroups = ARRAY_SIZE(uart1_grps),
+};
+
+/* Pad multiplexing for UART1 Modem device */
+static const unsigned uart1_modem_2_to_7_pins[] = { 2, 3, 4, 5, 6, 7 };
+static const unsigned uart1_modem_31_to_36_pins[] = { 31, 32, 33, 34, 35, 36 };
+static const unsigned uart1_modem_34_to_45_pins[] = { 34, 35, 36, 43, 44, 45 };
+static const unsigned uart1_modem_80_to_85_pins[] = { 80, 81, 82, 83, 84, 85 };
+
+static struct spear_muxreg uart1_modem_ext_2_to_7_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MASK | PMX_I2C_MASK | PMX_SSP_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_2_3_MASK | PMX_PL_6_7_MASK,
+ .val = PMX_UART1_ENH_PL_2_3_VAL | PMX_UART1_ENH_PL_4_5_VAL |
+ PMX_UART1_ENH_PL_6_7_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART1_ENH_PORT_SEL_MASK,
+ .val = PMX_UART1_ENH_PORT_3_TO_5_7_VAL,
+ },
+};
+
+static struct spear_muxreg uart1_modem_31_to_36_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_GPIO_PIN3_MASK | PMX_GPIO_PIN4_MASK |
+ PMX_GPIO_PIN5_MASK | PMX_SSP_CS_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg uart1_modem_ext_31_to_36_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_31_MASK | PMX_PL_32_33_MASK | PMX_PL_34_MASK |
+ PMX_PL_35_MASK | PMX_PL_36_MASK,
+ .val = PMX_UART1_ENH_PL_31_VAL | PMX_UART1_ENH_PL_32_33_VAL |
+ PMX_UART1_ENH_PL_34_VAL | PMX_UART1_ENH_PL_35_VAL |
+ PMX_UART1_ENH_PL_36_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART1_ENH_PORT_SEL_MASK,
+ .val = PMX_UART1_ENH_PORT_32_TO_34_36_VAL,
+ },
+};
+
+static struct spear_muxreg uart1_modem_34_to_45_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK |
+ PMX_SSP_CS_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg uart1_modem_ext_34_to_45_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_34_MASK | PMX_PL_35_MASK | PMX_PL_36_MASK,
+ .val = PMX_UART1_ENH_PL_34_VAL | PMX_UART1_ENH_PL_35_VAL |
+ PMX_UART1_ENH_PL_36_VAL,
+ }, {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_43_MASK | PMX_PL_44_45_MASK,
+ .val = PMX_UART1_ENH_PL_43_VAL | PMX_UART1_ENH_PL_44_45_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART1_ENH_PORT_SEL_MASK,
+ .val = PMX_UART1_ENH_PORT_44_45_34_36_VAL,
+ },
+};
+
+static struct spear_muxreg uart1_modem_ext_80_to_85_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_80_89_REG,
+ .mask = PMX_PL_80_TO_85_MASK,
+ .val = PMX_UART1_ENH_PL_80_TO_85_VAL,
+ }, {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_43_MASK | PMX_PL_44_45_MASK,
+ .val = PMX_UART1_ENH_PL_43_VAL | PMX_UART1_ENH_PL_44_45_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART1_ENH_PORT_SEL_MASK,
+ .val = PMX_UART1_ENH_PORT_81_TO_85_VAL,
+ },
+};
+
+static struct spear_modemux uart1_modem_2_to_7_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart1_modem_ext_2_to_7_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart1_modem_ext_2_to_7_muxreg),
+ },
+};
+
+static struct spear_modemux uart1_modem_31_to_36_modemux[] = {
+ {
+ .modes = SMALL_PRINTERS_MODE | EXTENDED_MODE,
+ .muxregs = uart1_modem_31_to_36_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart1_modem_31_to_36_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart1_modem_ext_31_to_36_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart1_modem_ext_31_to_36_muxreg),
+ },
+};
+
+static struct spear_modemux uart1_modem_34_to_45_modemux[] = {
+ {
+ .modes = AUTO_EXP_MODE | EXTENDED_MODE,
+ .muxregs = uart1_modem_34_to_45_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart1_modem_34_to_45_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart1_modem_ext_34_to_45_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart1_modem_ext_34_to_45_muxreg),
+ },
+};
+
+static struct spear_modemux uart1_modem_80_to_85_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart1_modem_ext_80_to_85_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart1_modem_ext_80_to_85_muxreg),
+ },
+};
+
+static struct spear_pingroup uart1_modem_pingroup[] = {
+ {
+ .name = "uart1_modem_2_to_7_grp",
+ .pins = uart1_modem_2_to_7_pins,
+ .npins = ARRAY_SIZE(uart1_modem_2_to_7_pins),
+ .modemuxs = uart1_modem_2_to_7_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart1_modem_2_to_7_modemux),
+ }, {
+ .name = "uart1_modem_31_to_36_grp",
+ .pins = uart1_modem_31_to_36_pins,
+ .npins = ARRAY_SIZE(uart1_modem_31_to_36_pins),
+ .modemuxs = uart1_modem_31_to_36_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart1_modem_31_to_36_modemux),
+ }, {
+ .name = "uart1_modem_34_to_45_grp",
+ .pins = uart1_modem_34_to_45_pins,
+ .npins = ARRAY_SIZE(uart1_modem_34_to_45_pins),
+ .modemuxs = uart1_modem_34_to_45_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart1_modem_34_to_45_modemux),
+ }, {
+ .name = "uart1_modem_80_to_85_grp",
+ .pins = uart1_modem_80_to_85_pins,
+ .npins = ARRAY_SIZE(uart1_modem_80_to_85_pins),
+ .modemuxs = uart1_modem_80_to_85_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart1_modem_80_to_85_modemux),
+ },
+};
+
+static const char *const uart1_modem_grps[] = { "uart1_modem_2_to_7_grp",
+ "uart1_modem_31_to_36_grp", "uart1_modem_34_to_45_grp",
+ "uart1_modem_80_to_85_grp" };
+static struct spear_function uart1_modem_function = {
+ .name = "uart1_modem",
+ .groups = uart1_modem_grps,
+ .ngroups = ARRAY_SIZE(uart1_modem_grps),
+};
+
+/* Pad multiplexing for UART2 device */
+static const unsigned uart2_pins[] = { 0, 1 };
+static struct spear_muxreg uart2_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_FIRDA_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg uart2_ext_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_0_1_MASK,
+ .val = PMX_UART2_PL_0_1_VAL,
+ },
+};
+
+static struct spear_modemux uart2_modemux[] = {
+ {
+ .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | AUTO_EXP_MODE
+ | SMALL_PRINTERS_MODE | EXTENDED_MODE,
+ .muxregs = uart2_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart2_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart2_ext_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart2_ext_muxreg),
+ },
+};
+
+static struct spear_pingroup uart2_pingroup = {
+ .name = "uart2_grp",
+ .pins = uart2_pins,
+ .npins = ARRAY_SIZE(uart2_pins),
+ .modemuxs = uart2_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart2_modemux),
+};
+
+static const char *const uart2_grps[] = { "uart2_grp" };
+static struct spear_function uart2_function = {
+ .name = "uart2",
+ .groups = uart2_grps,
+ .ngroups = ARRAY_SIZE(uart2_grps),
+};
+
+/* Pad multiplexing for uart3 device */
+static const unsigned uart3_pins[][2] = { { 8, 9 }, { 15, 16 }, { 41, 42 },
+ { 52, 53 }, { 73, 74 }, { 94, 95 }, { 98, 99 } };
+
+static struct spear_muxreg uart3_ext_8_9_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_SSP_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_8_9_MASK,
+ .val = PMX_UART3_PL_8_9_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART3_PORT_SEL_MASK,
+ .val = PMX_UART3_PORT_8_VAL,
+ },
+};
+
+static struct spear_muxreg uart3_ext_15_16_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_10_19_REG,
+ .mask = PMX_PL_15_16_MASK,
+ .val = PMX_UART3_PL_15_16_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART3_PORT_SEL_MASK,
+ .val = PMX_UART3_PORT_15_VAL,
+ },
+};
+
+static struct spear_muxreg uart3_ext_41_42_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_41_42_MASK,
+ .val = PMX_UART3_PL_41_42_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART3_PORT_SEL_MASK,
+ .val = PMX_UART3_PORT_41_VAL,
+ },
+};
+
+static struct spear_muxreg uart3_ext_52_53_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_50_59_REG,
+ .mask = PMX_PL_52_53_MASK,
+ .val = PMX_UART3_PL_52_53_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART3_PORT_SEL_MASK,
+ .val = PMX_UART3_PORT_52_VAL,
+ },
+};
+
+static struct spear_muxreg uart3_ext_73_74_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_70_79_REG,
+ .mask = PMX_PL_73_MASK | PMX_PL_74_MASK,
+ .val = PMX_UART3_PL_73_VAL | PMX_UART3_PL_74_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART3_PORT_SEL_MASK,
+ .val = PMX_UART3_PORT_73_VAL,
+ },
+};
+
+static struct spear_muxreg uart3_ext_94_95_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_94_95_MASK,
+ .val = PMX_UART3_PL_94_95_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART3_PORT_SEL_MASK,
+ .val = PMX_UART3_PORT_94_VAL,
+ },
+};
+
+static struct spear_muxreg uart3_ext_98_99_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_98_MASK | PMX_PL_99_MASK,
+ .val = PMX_UART3_PL_98_VAL | PMX_UART3_PL_99_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART3_PORT_SEL_MASK,
+ .val = PMX_UART3_PORT_99_VAL,
+ },
+};
+
+static struct spear_modemux uart3_modemux[][1] = {
+ {
+ /* Select signals on pins 8_9 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart3_ext_8_9_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart3_ext_8_9_muxreg),
+ },
+ }, {
+ /* Select signals on pins 15_16 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart3_ext_15_16_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart3_ext_15_16_muxreg),
+ },
+ }, {
+ /* Select signals on pins 41_42 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart3_ext_41_42_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart3_ext_41_42_muxreg),
+ },
+ }, {
+ /* Select signals on pins 52_53 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart3_ext_52_53_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart3_ext_52_53_muxreg),
+ },
+ }, {
+ /* Select signals on pins 73_74 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart3_ext_73_74_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart3_ext_73_74_muxreg),
+ },
+ }, {
+ /* Select signals on pins 94_95 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart3_ext_94_95_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart3_ext_94_95_muxreg),
+ },
+ }, {
+ /* Select signals on pins 98_99 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart3_ext_98_99_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart3_ext_98_99_muxreg),
+ },
+ },
+};
+
+static struct spear_pingroup uart3_pingroup[] = {
+ {
+ .name = "uart3_8_9_grp",
+ .pins = uart3_pins[0],
+ .npins = ARRAY_SIZE(uart3_pins[0]),
+ .modemuxs = uart3_modemux[0],
+ .nmodemuxs = ARRAY_SIZE(uart3_modemux[0]),
+ }, {
+ .name = "uart3_15_16_grp",
+ .pins = uart3_pins[1],
+ .npins = ARRAY_SIZE(uart3_pins[1]),
+ .modemuxs = uart3_modemux[1],
+ .nmodemuxs = ARRAY_SIZE(uart3_modemux[1]),
+ }, {
+ .name = "uart3_41_42_grp",
+ .pins = uart3_pins[2],
+ .npins = ARRAY_SIZE(uart3_pins[2]),
+ .modemuxs = uart3_modemux[2],
+ .nmodemuxs = ARRAY_SIZE(uart3_modemux[2]),
+ }, {
+ .name = "uart3_52_53_grp",
+ .pins = uart3_pins[3],
+ .npins = ARRAY_SIZE(uart3_pins[3]),
+ .modemuxs = uart3_modemux[3],
+ .nmodemuxs = ARRAY_SIZE(uart3_modemux[3]),
+ }, {
+ .name = "uart3_73_74_grp",
+ .pins = uart3_pins[4],
+ .npins = ARRAY_SIZE(uart3_pins[4]),
+ .modemuxs = uart3_modemux[4],
+ .nmodemuxs = ARRAY_SIZE(uart3_modemux[4]),
+ }, {
+ .name = "uart3_94_95_grp",
+ .pins = uart3_pins[5],
+ .npins = ARRAY_SIZE(uart3_pins[5]),
+ .modemuxs = uart3_modemux[5],
+ .nmodemuxs = ARRAY_SIZE(uart3_modemux[5]),
+ }, {
+ .name = "uart3_98_99_grp",
+ .pins = uart3_pins[6],
+ .npins = ARRAY_SIZE(uart3_pins[6]),
+ .modemuxs = uart3_modemux[6],
+ .nmodemuxs = ARRAY_SIZE(uart3_modemux[6]),
+ },
+};
+
+static const char *const uart3_grps[] = { "uart3_8_9_grp", "uart3_15_16_grp",
+ "uart3_41_42_grp", "uart3_52_53_grp", "uart3_73_74_grp",
+ "uart3_94_95_grp", "uart3_98_99_grp" };
+
+static struct spear_function uart3_function = {
+ .name = "uart3",
+ .groups = uart3_grps,
+ .ngroups = ARRAY_SIZE(uart3_grps),
+};
+
+/* Pad multiplexing for uart4 device */
+static const unsigned uart4_pins[][2] = { { 6, 7 }, { 13, 14 }, { 39, 40 },
+ { 71, 72 }, { 92, 93 }, { 100, 101 } };
+
+static struct spear_muxreg uart4_ext_6_7_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_SSP_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_6_7_MASK,
+ .val = PMX_UART4_PL_6_7_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART4_PORT_SEL_MASK,
+ .val = PMX_UART4_PORT_6_VAL,
+ },
+};
+
+static struct spear_muxreg uart4_ext_13_14_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_10_19_REG,
+ .mask = PMX_PL_13_14_MASK,
+ .val = PMX_UART4_PL_13_14_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART4_PORT_SEL_MASK,
+ .val = PMX_UART4_PORT_13_VAL,
+ },
+};
+
+static struct spear_muxreg uart4_ext_39_40_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_39_MASK,
+ .val = PMX_UART4_PL_39_VAL,
+ }, {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_40_MASK,
+ .val = PMX_UART4_PL_40_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART4_PORT_SEL_MASK,
+ .val = PMX_UART4_PORT_39_VAL,
+ },
+};
+
+static struct spear_muxreg uart4_ext_71_72_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_70_79_REG,
+ .mask = PMX_PL_71_72_MASK,
+ .val = PMX_UART4_PL_71_72_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART4_PORT_SEL_MASK,
+ .val = PMX_UART4_PORT_71_VAL,
+ },
+};
+
+static struct spear_muxreg uart4_ext_92_93_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_92_93_MASK,
+ .val = PMX_UART4_PL_92_93_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART4_PORT_SEL_MASK,
+ .val = PMX_UART4_PORT_92_VAL,
+ },
+};
+
+static struct spear_muxreg uart4_ext_100_101_muxreg[] = {
+ {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_PL_100_101_MASK |
+ PMX_UART4_PORT_SEL_MASK,
+ .val = PMX_UART4_PL_100_101_VAL |
+ PMX_UART4_PORT_101_VAL,
+ },
+};
+
+static struct spear_modemux uart4_modemux[][1] = {
+ {
+ /* Select signals on pins 6_7 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart4_ext_6_7_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart4_ext_6_7_muxreg),
+ },
+ }, {
+ /* Select signals on pins 13_14 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart4_ext_13_14_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart4_ext_13_14_muxreg),
+ },
+ }, {
+ /* Select signals on pins 39_40 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart4_ext_39_40_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart4_ext_39_40_muxreg),
+ },
+ }, {
+ /* Select signals on pins 71_72 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart4_ext_71_72_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart4_ext_71_72_muxreg),
+ },
+ }, {
+ /* Select signals on pins 92_93 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart4_ext_92_93_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart4_ext_92_93_muxreg),
+ },
+ }, {
+ /* Select signals on pins 100_101_ */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart4_ext_100_101_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart4_ext_100_101_muxreg),
+ },
+ },
+};
+
+static struct spear_pingroup uart4_pingroup[] = {
+ {
+ .name = "uart4_6_7_grp",
+ .pins = uart4_pins[0],
+ .npins = ARRAY_SIZE(uart4_pins[0]),
+ .modemuxs = uart4_modemux[0],
+ .nmodemuxs = ARRAY_SIZE(uart4_modemux[0]),
+ }, {
+ .name = "uart4_13_14_grp",
+ .pins = uart4_pins[1],
+ .npins = ARRAY_SIZE(uart4_pins[1]),
+ .modemuxs = uart4_modemux[1],
+ .nmodemuxs = ARRAY_SIZE(uart4_modemux[1]),
+ }, {
+ .name = "uart4_39_40_grp",
+ .pins = uart4_pins[2],
+ .npins = ARRAY_SIZE(uart4_pins[2]),
+ .modemuxs = uart4_modemux[2],
+ .nmodemuxs = ARRAY_SIZE(uart4_modemux[2]),
+ }, {
+ .name = "uart4_71_72_grp",
+ .pins = uart4_pins[3],
+ .npins = ARRAY_SIZE(uart4_pins[3]),
+ .modemuxs = uart4_modemux[3],
+ .nmodemuxs = ARRAY_SIZE(uart4_modemux[3]),
+ }, {
+ .name = "uart4_92_93_grp",
+ .pins = uart4_pins[4],
+ .npins = ARRAY_SIZE(uart4_pins[4]),
+ .modemuxs = uart4_modemux[4],
+ .nmodemuxs = ARRAY_SIZE(uart4_modemux[4]),
+ }, {
+ .name = "uart4_100_101_grp",
+ .pins = uart4_pins[5],
+ .npins = ARRAY_SIZE(uart4_pins[5]),
+ .modemuxs = uart4_modemux[5],
+ .nmodemuxs = ARRAY_SIZE(uart4_modemux[5]),
+ },
+};
+
+static const char *const uart4_grps[] = { "uart4_6_7_grp", "uart4_13_14_grp",
+ "uart4_39_40_grp", "uart4_71_72_grp", "uart4_92_93_grp",
+ "uart4_100_101_grp" };
+
+static struct spear_function uart4_function = {
+ .name = "uart4",
+ .groups = uart4_grps,
+ .ngroups = ARRAY_SIZE(uart4_grps),
+};
+
+/* Pad multiplexing for uart5 device */
+static const unsigned uart5_pins[][2] = { { 4, 5 }, { 37, 38 }, { 69, 70 },
+ { 90, 91 } };
+
+static struct spear_muxreg uart5_ext_4_5_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_I2C_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_4_5_MASK,
+ .val = PMX_UART5_PL_4_5_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART5_PORT_SEL_MASK,
+ .val = PMX_UART5_PORT_4_VAL,
+ },
+};
+
+static struct spear_muxreg uart5_ext_37_38_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_37_38_MASK,
+ .val = PMX_UART5_PL_37_38_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART5_PORT_SEL_MASK,
+ .val = PMX_UART5_PORT_37_VAL,
+ },
+};
+
+static struct spear_muxreg uart5_ext_69_70_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_60_69_REG,
+ .mask = PMX_PL_69_MASK,
+ .val = PMX_UART5_PL_69_VAL,
+ }, {
+ .reg = IP_SEL_PAD_70_79_REG,
+ .mask = PMX_PL_70_MASK,
+ .val = PMX_UART5_PL_70_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART5_PORT_SEL_MASK,
+ .val = PMX_UART5_PORT_69_VAL,
+ },
+};
+
+static struct spear_muxreg uart5_ext_90_91_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_90_91_MASK,
+ .val = PMX_UART5_PL_90_91_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART5_PORT_SEL_MASK,
+ .val = PMX_UART5_PORT_90_VAL,
+ },
+};
+
+static struct spear_modemux uart5_modemux[][1] = {
+ {
+ /* Select signals on pins 4_5 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart5_ext_4_5_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart5_ext_4_5_muxreg),
+ },
+ }, {
+ /* Select signals on pins 37_38 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart5_ext_37_38_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart5_ext_37_38_muxreg),
+ },
+ }, {
+ /* Select signals on pins 69_70 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart5_ext_69_70_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart5_ext_69_70_muxreg),
+ },
+ }, {
+ /* Select signals on pins 90_91 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart5_ext_90_91_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart5_ext_90_91_muxreg),
+ },
+ },
+};
+
+static struct spear_pingroup uart5_pingroup[] = {
+ {
+ .name = "uart5_4_5_grp",
+ .pins = uart5_pins[0],
+ .npins = ARRAY_SIZE(uart5_pins[0]),
+ .modemuxs = uart5_modemux[0],
+ .nmodemuxs = ARRAY_SIZE(uart5_modemux[0]),
+ }, {
+ .name = "uart5_37_38_grp",
+ .pins = uart5_pins[1],
+ .npins = ARRAY_SIZE(uart5_pins[1]),
+ .modemuxs = uart5_modemux[1],
+ .nmodemuxs = ARRAY_SIZE(uart5_modemux[1]),
+ }, {
+ .name = "uart5_69_70_grp",
+ .pins = uart5_pins[2],
+ .npins = ARRAY_SIZE(uart5_pins[2]),
+ .modemuxs = uart5_modemux[2],
+ .nmodemuxs = ARRAY_SIZE(uart5_modemux[2]),
+ }, {
+ .name = "uart5_90_91_grp",
+ .pins = uart5_pins[3],
+ .npins = ARRAY_SIZE(uart5_pins[3]),
+ .modemuxs = uart5_modemux[3],
+ .nmodemuxs = ARRAY_SIZE(uart5_modemux[3]),
+ },
+};
+
+static const char *const uart5_grps[] = { "uart5_4_5_grp", "uart5_37_38_grp",
+ "uart5_69_70_grp", "uart5_90_91_grp" };
+static struct spear_function uart5_function = {
+ .name = "uart5",
+ .groups = uart5_grps,
+ .ngroups = ARRAY_SIZE(uart5_grps),
+};
+
+/* Pad multiplexing for uart6 device */
+static const unsigned uart6_pins[][2] = { { 2, 3 }, { 88, 89 } };
+static struct spear_muxreg uart6_ext_2_3_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_2_3_MASK,
+ .val = PMX_UART6_PL_2_3_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART6_PORT_SEL_MASK,
+ .val = PMX_UART6_PORT_2_VAL,
+ },
+};
+
+static struct spear_muxreg uart6_ext_88_89_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_80_89_REG,
+ .mask = PMX_PL_88_89_MASK,
+ .val = PMX_UART6_PL_88_89_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_UART6_PORT_SEL_MASK,
+ .val = PMX_UART6_PORT_88_VAL,
+ },
+};
+
+static struct spear_modemux uart6_modemux[][1] = {
+ {
+ /* Select signals on pins 2_3 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart6_ext_2_3_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart6_ext_2_3_muxreg),
+ },
+ }, {
+ /* Select signals on pins 88_89 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = uart6_ext_88_89_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart6_ext_88_89_muxreg),
+ },
+ },
+};
+
+static struct spear_pingroup uart6_pingroup[] = {
+ {
+ .name = "uart6_2_3_grp",
+ .pins = uart6_pins[0],
+ .npins = ARRAY_SIZE(uart6_pins[0]),
+ .modemuxs = uart6_modemux[0],
+ .nmodemuxs = ARRAY_SIZE(uart6_modemux[0]),
+ }, {
+ .name = "uart6_88_89_grp",
+ .pins = uart6_pins[1],
+ .npins = ARRAY_SIZE(uart6_pins[1]),
+ .modemuxs = uart6_modemux[1],
+ .nmodemuxs = ARRAY_SIZE(uart6_modemux[1]),
+ },
+};
+
+static const char *const uart6_grps[] = { "uart6_2_3_grp", "uart6_88_89_grp" };
+static struct spear_function uart6_function = {
+ .name = "uart6",
+ .groups = uart6_grps,
+ .ngroups = ARRAY_SIZE(uart6_grps),
+};
+
+/* UART - RS485 pmx */
+static const unsigned rs485_pins[] = { 77, 78, 79 };
+static struct spear_muxreg rs485_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_70_79_REG,
+ .mask = PMX_PL_77_78_79_MASK,
+ .val = PMX_RS485_PL_77_78_79_VAL,
+ },
+};
+
+static struct spear_modemux rs485_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = rs485_muxreg,
+ .nmuxregs = ARRAY_SIZE(rs485_muxreg),
+ },
+};
+
+static struct spear_pingroup rs485_pingroup = {
+ .name = "rs485_grp",
+ .pins = rs485_pins,
+ .npins = ARRAY_SIZE(rs485_pins),
+ .modemuxs = rs485_modemux,
+ .nmodemuxs = ARRAY_SIZE(rs485_modemux),
+};
+
+static const char *const rs485_grps[] = { "rs485_grp" };
+static struct spear_function rs485_function = {
+ .name = "rs485",
+ .groups = rs485_grps,
+ .ngroups = ARRAY_SIZE(rs485_grps),
+};
+
+/* Pad multiplexing for Touchscreen device */
+static const unsigned touchscreen_pins[] = { 5, 36 };
+static struct spear_muxreg touchscreen_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_I2C_MASK | PMX_SSP_CS_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg touchscreen_ext_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_5_MASK,
+ .val = PMX_TOUCH_Y_PL_5_VAL,
+ }, {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_36_MASK,
+ .val = PMX_TOUCH_X_PL_36_VAL,
+ },
+};
+
+static struct spear_modemux touchscreen_modemux[] = {
+ {
+ .modes = AUTO_NET_SMII_MODE | EXTENDED_MODE,
+ .muxregs = touchscreen_muxreg,
+ .nmuxregs = ARRAY_SIZE(touchscreen_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = touchscreen_ext_muxreg,
+ .nmuxregs = ARRAY_SIZE(touchscreen_ext_muxreg),
+ },
+};
+
+static struct spear_pingroup touchscreen_pingroup = {
+ .name = "touchscreen_grp",
+ .pins = touchscreen_pins,
+ .npins = ARRAY_SIZE(touchscreen_pins),
+ .modemuxs = touchscreen_modemux,
+ .nmodemuxs = ARRAY_SIZE(touchscreen_modemux),
+};
+
+static const char *const touchscreen_grps[] = { "touchscreen_grp" };
+static struct spear_function touchscreen_function = {
+ .name = "touchscreen",
+ .groups = touchscreen_grps,
+ .ngroups = ARRAY_SIZE(touchscreen_grps),
+};
+
+/* Pad multiplexing for CAN device */
+static const unsigned can0_pins[] = { 32, 33 };
+static struct spear_muxreg can0_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_GPIO_PIN4_MASK | PMX_GPIO_PIN5_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg can0_ext_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_32_33_MASK,
+ .val = PMX_CAN0_PL_32_33_VAL,
+ },
+};
+
+static struct spear_modemux can0_modemux[] = {
+ {
+ .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | AUTO_EXP_MODE
+ | EXTENDED_MODE,
+ .muxregs = can0_muxreg,
+ .nmuxregs = ARRAY_SIZE(can0_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = can0_ext_muxreg,
+ .nmuxregs = ARRAY_SIZE(can0_ext_muxreg),
+ },
+};
+
+static struct spear_pingroup can0_pingroup = {
+ .name = "can0_grp",
+ .pins = can0_pins,
+ .npins = ARRAY_SIZE(can0_pins),
+ .modemuxs = can0_modemux,
+ .nmodemuxs = ARRAY_SIZE(can0_modemux),
+};
+
+static const char *const can0_grps[] = { "can0_grp" };
+static struct spear_function can0_function = {
+ .name = "can0",
+ .groups = can0_grps,
+ .ngroups = ARRAY_SIZE(can0_grps),
+};
+
+static const unsigned can1_pins[] = { 30, 31 };
+static struct spear_muxreg can1_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg can1_ext_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_30_31_MASK,
+ .val = PMX_CAN1_PL_30_31_VAL,
+ },
+};
+
+static struct spear_modemux can1_modemux[] = {
+ {
+ .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | AUTO_EXP_MODE
+ | EXTENDED_MODE,
+ .muxregs = can1_muxreg,
+ .nmuxregs = ARRAY_SIZE(can1_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = can1_ext_muxreg,
+ .nmuxregs = ARRAY_SIZE(can1_ext_muxreg),
+ },
+};
+
+static struct spear_pingroup can1_pingroup = {
+ .name = "can1_grp",
+ .pins = can1_pins,
+ .npins = ARRAY_SIZE(can1_pins),
+ .modemuxs = can1_modemux,
+ .nmodemuxs = ARRAY_SIZE(can1_modemux),
+};
+
+static const char *const can1_grps[] = { "can1_grp" };
+static struct spear_function can1_function = {
+ .name = "can1",
+ .groups = can1_grps,
+ .ngroups = ARRAY_SIZE(can1_grps),
+};
+
+/* Pad multiplexing for PWM0_1 device */
+static const unsigned pwm0_1_pins[][2] = { { 37, 38 }, { 14, 15 }, { 8, 9 },
+ { 30, 31 }, { 42, 43 }, { 59, 60 }, { 88, 89 } };
+
+static struct spear_muxreg pwm0_1_pin_8_9_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_SSP_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_8_9_MASK,
+ .val = PMX_PWM_0_1_PL_8_9_VAL,
+ },
+};
+
+static struct spear_muxreg pwm0_1_autoexpsmallpri_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg pwm0_1_pin_14_15_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_10_19_REG,
+ .mask = PMX_PL_14_MASK | PMX_PL_15_MASK,
+ .val = PMX_PWM1_PL_14_VAL | PMX_PWM0_PL_15_VAL,
+ },
+};
+
+static struct spear_muxreg pwm0_1_pin_30_31_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_30_MASK | PMX_PL_31_MASK,
+ .val = PMX_PWM1_EXT_PL_30_VAL | PMX_PWM0_EXT_PL_31_VAL,
+ },
+};
+
+static struct spear_muxreg pwm0_1_net_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg pwm0_1_pin_37_38_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_37_38_MASK,
+ .val = PMX_PWM0_1_PL_37_38_VAL,
+ },
+};
+
+static struct spear_muxreg pwm0_1_pin_42_43_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK | PMX_TIMER_0_1_MASK ,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_42_MASK | PMX_PL_43_MASK,
+ .val = PMX_PWM1_PL_42_VAL |
+ PMX_PWM0_PL_43_VAL,
+ },
+};
+
+static struct spear_muxreg pwm0_1_pin_59_60_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_50_59_REG,
+ .mask = PMX_PL_59_MASK,
+ .val = PMX_PWM1_PL_59_VAL,
+ }, {
+ .reg = IP_SEL_PAD_60_69_REG,
+ .mask = PMX_PL_60_MASK,
+ .val = PMX_PWM0_PL_60_VAL,
+ },
+};
+
+static struct spear_muxreg pwm0_1_pin_88_89_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_80_89_REG,
+ .mask = PMX_PL_88_89_MASK,
+ .val = PMX_PWM0_1_PL_88_89_VAL,
+ },
+};
+
+static struct spear_modemux pwm0_1_pin_8_9_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm0_1_pin_8_9_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm0_1_pin_8_9_muxreg),
+ },
+};
+
+static struct spear_modemux pwm0_1_pin_14_15_modemux[] = {
+ {
+ .modes = AUTO_EXP_MODE | SMALL_PRINTERS_MODE | EXTENDED_MODE,
+ .muxregs = pwm0_1_autoexpsmallpri_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm0_1_autoexpsmallpri_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm0_1_pin_14_15_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm0_1_pin_14_15_muxreg),
+ },
+};
+
+static struct spear_modemux pwm0_1_pin_30_31_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm0_1_pin_30_31_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm0_1_pin_30_31_muxreg),
+ },
+};
+
+static struct spear_modemux pwm0_1_pin_37_38_modemux[] = {
+ {
+ .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | EXTENDED_MODE,
+ .muxregs = pwm0_1_net_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm0_1_net_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm0_1_pin_37_38_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm0_1_pin_37_38_muxreg),
+ },
+};
+
+static struct spear_modemux pwm0_1_pin_42_43_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm0_1_pin_42_43_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm0_1_pin_42_43_muxreg),
+ },
+};
+
+static struct spear_modemux pwm0_1_pin_59_60_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm0_1_pin_59_60_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm0_1_pin_59_60_muxreg),
+ },
+};
+
+static struct spear_modemux pwm0_1_pin_88_89_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm0_1_pin_88_89_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm0_1_pin_88_89_muxreg),
+ },
+};
+
+static struct spear_pingroup pwm0_1_pingroup[] = {
+ {
+ .name = "pwm0_1_pin_8_9_grp",
+ .pins = pwm0_1_pins[0],
+ .npins = ARRAY_SIZE(pwm0_1_pins[0]),
+ .modemuxs = pwm0_1_pin_8_9_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm0_1_pin_8_9_modemux),
+ }, {
+ .name = "pwm0_1_pin_14_15_grp",
+ .pins = pwm0_1_pins[1],
+ .npins = ARRAY_SIZE(pwm0_1_pins[1]),
+ .modemuxs = pwm0_1_pin_14_15_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm0_1_pin_14_15_modemux),
+ }, {
+ .name = "pwm0_1_pin_30_31_grp",
+ .pins = pwm0_1_pins[2],
+ .npins = ARRAY_SIZE(pwm0_1_pins[2]),
+ .modemuxs = pwm0_1_pin_30_31_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm0_1_pin_30_31_modemux),
+ }, {
+ .name = "pwm0_1_pin_37_38_grp",
+ .pins = pwm0_1_pins[3],
+ .npins = ARRAY_SIZE(pwm0_1_pins[3]),
+ .modemuxs = pwm0_1_pin_37_38_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm0_1_pin_37_38_modemux),
+ }, {
+ .name = "pwm0_1_pin_42_43_grp",
+ .pins = pwm0_1_pins[4],
+ .npins = ARRAY_SIZE(pwm0_1_pins[4]),
+ .modemuxs = pwm0_1_pin_42_43_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm0_1_pin_42_43_modemux),
+ }, {
+ .name = "pwm0_1_pin_59_60_grp",
+ .pins = pwm0_1_pins[5],
+ .npins = ARRAY_SIZE(pwm0_1_pins[5]),
+ .modemuxs = pwm0_1_pin_59_60_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm0_1_pin_59_60_modemux),
+ }, {
+ .name = "pwm0_1_pin_88_89_grp",
+ .pins = pwm0_1_pins[6],
+ .npins = ARRAY_SIZE(pwm0_1_pins[6]),
+ .modemuxs = pwm0_1_pin_88_89_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm0_1_pin_88_89_modemux),
+ },
+};
+
+static const char *const pwm0_1_grps[] = { "pwm0_1_pin_8_9_grp",
+ "pwm0_1_pin_14_15_grp", "pwm0_1_pin_30_31_grp", "pwm0_1_pin_37_38_grp",
+ "pwm0_1_pin_42_43_grp", "pwm0_1_pin_59_60_grp", "pwm0_1_pin_88_89_grp"
+};
+
+static struct spear_function pwm0_1_function = {
+ .name = "pwm0_1",
+ .groups = pwm0_1_grps,
+ .ngroups = ARRAY_SIZE(pwm0_1_grps),
+};
+
+/* Pad multiplexing for PWM2 device */
+static const unsigned pwm2_pins[][1] = { { 7 }, { 13 }, { 29 }, { 34 }, { 41 },
+ { 58 }, { 87 } };
+static struct spear_muxreg pwm2_net_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_SSP_CS_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg pwm2_pin_7_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_7_MASK,
+ .val = PMX_PWM_2_PL_7_VAL,
+ },
+};
+
+static struct spear_muxreg pwm2_autoexpsmallpri_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg pwm2_pin_13_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_10_19_REG,
+ .mask = PMX_PL_13_MASK,
+ .val = PMX_PWM2_PL_13_VAL,
+ },
+};
+
+static struct spear_muxreg pwm2_pin_29_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_GPIO_PIN1_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_20_29_REG,
+ .mask = PMX_PL_29_MASK,
+ .val = PMX_PWM_2_PL_29_VAL,
+ },
+};
+
+static struct spear_muxreg pwm2_pin_34_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_SSP_CS_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_34_MASK,
+ .val = PMX_PWM2_PL_34_VAL,
+ },
+};
+
+static struct spear_muxreg pwm2_pin_41_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_41_MASK,
+ .val = PMX_PWM2_PL_41_VAL,
+ },
+};
+
+static struct spear_muxreg pwm2_pin_58_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_50_59_REG,
+ .mask = PMX_PL_58_MASK,
+ .val = PMX_PWM2_PL_58_VAL,
+ },
+};
+
+static struct spear_muxreg pwm2_pin_87_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_80_89_REG,
+ .mask = PMX_PL_87_MASK,
+ .val = PMX_PWM2_PL_87_VAL,
+ },
+};
+
+static struct spear_modemux pwm2_pin_7_modemux[] = {
+ {
+ .modes = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | EXTENDED_MODE,
+ .muxregs = pwm2_net_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm2_net_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm2_pin_7_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm2_pin_7_muxreg),
+ },
+};
+static struct spear_modemux pwm2_pin_13_modemux[] = {
+ {
+ .modes = AUTO_EXP_MODE | SMALL_PRINTERS_MODE | EXTENDED_MODE,
+ .muxregs = pwm2_autoexpsmallpri_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm2_autoexpsmallpri_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm2_pin_13_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm2_pin_13_muxreg),
+ },
+};
+static struct spear_modemux pwm2_pin_29_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm2_pin_29_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm2_pin_29_muxreg),
+ },
+};
+static struct spear_modemux pwm2_pin_34_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm2_pin_34_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm2_pin_34_muxreg),
+ },
+};
+
+static struct spear_modemux pwm2_pin_41_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm2_pin_41_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm2_pin_41_muxreg),
+ },
+};
+
+static struct spear_modemux pwm2_pin_58_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm2_pin_58_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm2_pin_58_muxreg),
+ },
+};
+
+static struct spear_modemux pwm2_pin_87_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm2_pin_87_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm2_pin_87_muxreg),
+ },
+};
+
+static struct spear_pingroup pwm2_pingroup[] = {
+ {
+ .name = "pwm2_pin_7_grp",
+ .pins = pwm2_pins[0],
+ .npins = ARRAY_SIZE(pwm2_pins[0]),
+ .modemuxs = pwm2_pin_7_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm2_pin_7_modemux),
+ }, {
+ .name = "pwm2_pin_13_grp",
+ .pins = pwm2_pins[1],
+ .npins = ARRAY_SIZE(pwm2_pins[1]),
+ .modemuxs = pwm2_pin_13_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm2_pin_13_modemux),
+ }, {
+ .name = "pwm2_pin_29_grp",
+ .pins = pwm2_pins[2],
+ .npins = ARRAY_SIZE(pwm2_pins[2]),
+ .modemuxs = pwm2_pin_29_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm2_pin_29_modemux),
+ }, {
+ .name = "pwm2_pin_34_grp",
+ .pins = pwm2_pins[3],
+ .npins = ARRAY_SIZE(pwm2_pins[3]),
+ .modemuxs = pwm2_pin_34_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm2_pin_34_modemux),
+ }, {
+ .name = "pwm2_pin_41_grp",
+ .pins = pwm2_pins[4],
+ .npins = ARRAY_SIZE(pwm2_pins[4]),
+ .modemuxs = pwm2_pin_41_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm2_pin_41_modemux),
+ }, {
+ .name = "pwm2_pin_58_grp",
+ .pins = pwm2_pins[5],
+ .npins = ARRAY_SIZE(pwm2_pins[5]),
+ .modemuxs = pwm2_pin_58_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm2_pin_58_modemux),
+ }, {
+ .name = "pwm2_pin_87_grp",
+ .pins = pwm2_pins[6],
+ .npins = ARRAY_SIZE(pwm2_pins[6]),
+ .modemuxs = pwm2_pin_87_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm2_pin_87_modemux),
+ },
+};
+
+static const char *const pwm2_grps[] = { "pwm2_pin_7_grp", "pwm2_pin_13_grp",
+ "pwm2_pin_29_grp", "pwm2_pin_34_grp", "pwm2_pin_41_grp",
+ "pwm2_pin_58_grp", "pwm2_pin_87_grp" };
+static struct spear_function pwm2_function = {
+ .name = "pwm2",
+ .groups = pwm2_grps,
+ .ngroups = ARRAY_SIZE(pwm2_grps),
+};
+
+/* Pad multiplexing for PWM3 device */
+static const unsigned pwm3_pins[][1] = { { 6 }, { 12 }, { 28 }, { 40 }, { 57 },
+ { 86 } };
+static struct spear_muxreg pwm3_pin_6_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_SSP_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_6_MASK,
+ .val = PMX_PWM_3_PL_6_VAL,
+ },
+};
+
+static struct spear_muxreg pwm3_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg pwm3_pin_12_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_10_19_REG,
+ .mask = PMX_PL_12_MASK,
+ .val = PMX_PWM3_PL_12_VAL,
+ },
+};
+
+static struct spear_muxreg pwm3_pin_28_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_GPIO_PIN0_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_20_29_REG,
+ .mask = PMX_PL_28_MASK,
+ .val = PMX_PWM_3_PL_28_VAL,
+ },
+};
+
+static struct spear_muxreg pwm3_pin_40_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_40_MASK,
+ .val = PMX_PWM3_PL_40_VAL,
+ },
+};
+
+static struct spear_muxreg pwm3_pin_57_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_50_59_REG,
+ .mask = PMX_PL_57_MASK,
+ .val = PMX_PWM3_PL_57_VAL,
+ },
+};
+
+static struct spear_muxreg pwm3_pin_86_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_80_89_REG,
+ .mask = PMX_PL_86_MASK,
+ .val = PMX_PWM3_PL_86_VAL,
+ },
+};
+
+static struct spear_modemux pwm3_pin_6_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm3_pin_6_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm3_pin_6_muxreg),
+ },
+};
+
+static struct spear_modemux pwm3_pin_12_modemux[] = {
+ {
+ .modes = AUTO_EXP_MODE | SMALL_PRINTERS_MODE |
+ AUTO_NET_SMII_MODE | EXTENDED_MODE,
+ .muxregs = pwm3_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm3_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm3_pin_12_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm3_pin_12_muxreg),
+ },
+};
+
+static struct spear_modemux pwm3_pin_28_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm3_pin_28_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm3_pin_28_muxreg),
+ },
+};
+
+static struct spear_modemux pwm3_pin_40_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm3_pin_40_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm3_pin_40_muxreg),
+ },
+};
+
+static struct spear_modemux pwm3_pin_57_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm3_pin_57_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm3_pin_57_muxreg),
+ },
+};
+
+static struct spear_modemux pwm3_pin_86_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = pwm3_pin_86_muxreg,
+ .nmuxregs = ARRAY_SIZE(pwm3_pin_86_muxreg),
+ },
+};
+
+static struct spear_pingroup pwm3_pingroup[] = {
+ {
+ .name = "pwm3_pin_6_grp",
+ .pins = pwm3_pins[0],
+ .npins = ARRAY_SIZE(pwm3_pins[0]),
+ .modemuxs = pwm3_pin_6_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm3_pin_6_modemux),
+ }, {
+ .name = "pwm3_pin_12_grp",
+ .pins = pwm3_pins[1],
+ .npins = ARRAY_SIZE(pwm3_pins[1]),
+ .modemuxs = pwm3_pin_12_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm3_pin_12_modemux),
+ }, {
+ .name = "pwm3_pin_28_grp",
+ .pins = pwm3_pins[2],
+ .npins = ARRAY_SIZE(pwm3_pins[2]),
+ .modemuxs = pwm3_pin_28_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm3_pin_28_modemux),
+ }, {
+ .name = "pwm3_pin_40_grp",
+ .pins = pwm3_pins[3],
+ .npins = ARRAY_SIZE(pwm3_pins[3]),
+ .modemuxs = pwm3_pin_40_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm3_pin_40_modemux),
+ }, {
+ .name = "pwm3_pin_57_grp",
+ .pins = pwm3_pins[4],
+ .npins = ARRAY_SIZE(pwm3_pins[4]),
+ .modemuxs = pwm3_pin_57_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm3_pin_57_modemux),
+ }, {
+ .name = "pwm3_pin_86_grp",
+ .pins = pwm3_pins[5],
+ .npins = ARRAY_SIZE(pwm3_pins[5]),
+ .modemuxs = pwm3_pin_86_modemux,
+ .nmodemuxs = ARRAY_SIZE(pwm3_pin_86_modemux),
+ },
+};
+
+static const char *const pwm3_grps[] = { "pwm3_pin_6_grp", "pwm3_pin_12_grp",
+ "pwm3_pin_28_grp", "pwm3_pin_40_grp", "pwm3_pin_57_grp",
+ "pwm3_pin_86_grp" };
+static struct spear_function pwm3_function = {
+ .name = "pwm3",
+ .groups = pwm3_grps,
+ .ngroups = ARRAY_SIZE(pwm3_grps),
+};
+
+/* Pad multiplexing for SSP1 device */
+static const unsigned ssp1_pins[][2] = { { 17, 20 }, { 36, 39 }, { 48, 51 },
+ { 65, 68 }, { 94, 97 } };
+static struct spear_muxreg ssp1_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg ssp1_ext_17_20_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_10_19_REG,
+ .mask = PMX_PL_17_18_MASK | PMX_PL_19_MASK,
+ .val = PMX_SSP1_PL_17_18_19_20_VAL,
+ }, {
+ .reg = IP_SEL_PAD_20_29_REG,
+ .mask = PMX_PL_20_MASK,
+ .val = PMX_SSP1_PL_17_18_19_20_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SSP1_PORT_SEL_MASK,
+ .val = PMX_SSP1_PORT_17_TO_20_VAL,
+ },
+};
+
+static struct spear_muxreg ssp1_ext_36_39_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MODEM_MASK | PMX_SSP_CS_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_36_MASK | PMX_PL_37_38_MASK | PMX_PL_39_MASK,
+ .val = PMX_SSP1_PL_36_VAL | PMX_SSP1_PL_37_38_VAL |
+ PMX_SSP1_PL_39_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SSP1_PORT_SEL_MASK,
+ .val = PMX_SSP1_PORT_36_TO_39_VAL,
+ },
+};
+
+static struct spear_muxreg ssp1_ext_48_51_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_48_49_MASK,
+ .val = PMX_SSP1_PL_48_49_VAL,
+ }, {
+ .reg = IP_SEL_PAD_50_59_REG,
+ .mask = PMX_PL_50_51_MASK,
+ .val = PMX_SSP1_PL_50_51_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SSP1_PORT_SEL_MASK,
+ .val = PMX_SSP1_PORT_48_TO_51_VAL,
+ },
+};
+
+static struct spear_muxreg ssp1_ext_65_68_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_60_69_REG,
+ .mask = PMX_PL_65_TO_68_MASK,
+ .val = PMX_SSP1_PL_65_TO_68_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SSP1_PORT_SEL_MASK,
+ .val = PMX_SSP1_PORT_65_TO_68_VAL,
+ },
+};
+
+static struct spear_muxreg ssp1_ext_94_97_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_94_95_MASK | PMX_PL_96_97_MASK,
+ .val = PMX_SSP1_PL_94_95_VAL | PMX_SSP1_PL_96_97_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SSP1_PORT_SEL_MASK,
+ .val = PMX_SSP1_PORT_94_TO_97_VAL,
+ },
+};
+
+static struct spear_modemux ssp1_17_20_modemux[] = {
+ {
+ .modes = SMALL_PRINTERS_MODE | AUTO_NET_SMII_MODE |
+ EXTENDED_MODE,
+ .muxregs = ssp1_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp1_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = ssp1_ext_17_20_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp1_ext_17_20_muxreg),
+ },
+};
+
+static struct spear_modemux ssp1_36_39_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = ssp1_ext_36_39_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp1_ext_36_39_muxreg),
+ },
+};
+
+static struct spear_modemux ssp1_48_51_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = ssp1_ext_48_51_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp1_ext_48_51_muxreg),
+ },
+};
+static struct spear_modemux ssp1_65_68_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = ssp1_ext_65_68_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp1_ext_65_68_muxreg),
+ },
+};
+
+static struct spear_modemux ssp1_94_97_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = ssp1_ext_94_97_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp1_ext_94_97_muxreg),
+ },
+};
+
+static struct spear_pingroup ssp1_pingroup[] = {
+ {
+ .name = "ssp1_17_20_grp",
+ .pins = ssp1_pins[0],
+ .npins = ARRAY_SIZE(ssp1_pins[0]),
+ .modemuxs = ssp1_17_20_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp1_17_20_modemux),
+ }, {
+ .name = "ssp1_36_39_grp",
+ .pins = ssp1_pins[1],
+ .npins = ARRAY_SIZE(ssp1_pins[1]),
+ .modemuxs = ssp1_36_39_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp1_36_39_modemux),
+ }, {
+ .name = "ssp1_48_51_grp",
+ .pins = ssp1_pins[2],
+ .npins = ARRAY_SIZE(ssp1_pins[2]),
+ .modemuxs = ssp1_48_51_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp1_48_51_modemux),
+ }, {
+ .name = "ssp1_65_68_grp",
+ .pins = ssp1_pins[3],
+ .npins = ARRAY_SIZE(ssp1_pins[3]),
+ .modemuxs = ssp1_65_68_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp1_65_68_modemux),
+ }, {
+ .name = "ssp1_94_97_grp",
+ .pins = ssp1_pins[4],
+ .npins = ARRAY_SIZE(ssp1_pins[4]),
+ .modemuxs = ssp1_94_97_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp1_94_97_modemux),
+ },
+};
+
+static const char *const ssp1_grps[] = { "ssp1_17_20_grp", "ssp1_36_39_grp",
+ "ssp1_48_51_grp", "ssp1_65_68_grp", "ssp1_94_97_grp"
+};
+static struct spear_function ssp1_function = {
+ .name = "ssp1",
+ .groups = ssp1_grps,
+ .ngroups = ARRAY_SIZE(ssp1_grps),
+};
+
+/* Pad multiplexing for SSP2 device */
+static const unsigned ssp2_pins[][2] = { { 13, 16 }, { 32, 35 }, { 44, 47 },
+ { 61, 64 }, { 90, 93 } };
+static struct spear_muxreg ssp2_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg ssp2_ext_13_16_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_10_19_REG,
+ .mask = PMX_PL_13_14_MASK | PMX_PL_15_16_MASK,
+ .val = PMX_SSP2_PL_13_14_15_16_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SSP2_PORT_SEL_MASK,
+ .val = PMX_SSP2_PORT_13_TO_16_VAL,
+ },
+};
+
+static struct spear_muxreg ssp2_ext_32_35_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_SSP_CS_MASK | PMX_GPIO_PIN4_MASK |
+ PMX_GPIO_PIN5_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_30_39_REG,
+ .mask = PMX_PL_32_33_MASK | PMX_PL_34_MASK | PMX_PL_35_MASK,
+ .val = PMX_SSP2_PL_32_33_VAL | PMX_SSP2_PL_34_VAL |
+ PMX_SSP2_PL_35_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SSP2_PORT_SEL_MASK,
+ .val = PMX_SSP2_PORT_32_TO_35_VAL,
+ },
+};
+
+static struct spear_muxreg ssp2_ext_44_47_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_TIMER_0_1_MASK | PMX_TIMER_2_3_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_40_49_REG,
+ .mask = PMX_PL_44_45_MASK | PMX_PL_46_47_MASK,
+ .val = PMX_SSP2_PL_44_45_VAL | PMX_SSP2_PL_46_47_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SSP2_PORT_SEL_MASK,
+ .val = PMX_SSP2_PORT_44_TO_47_VAL,
+ },
+};
+
+static struct spear_muxreg ssp2_ext_61_64_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_60_69_REG,
+ .mask = PMX_PL_61_TO_64_MASK,
+ .val = PMX_SSP2_PL_61_TO_64_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SSP2_PORT_SEL_MASK,
+ .val = PMX_SSP2_PORT_61_TO_64_VAL,
+ },
+};
+
+static struct spear_muxreg ssp2_ext_90_93_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_90_91_MASK | PMX_PL_92_93_MASK,
+ .val = PMX_SSP2_PL_90_91_VAL | PMX_SSP2_PL_92_93_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_SSP2_PORT_SEL_MASK,
+ .val = PMX_SSP2_PORT_90_TO_93_VAL,
+ },
+};
+
+static struct spear_modemux ssp2_13_16_modemux[] = {
+ {
+ .modes = AUTO_NET_SMII_MODE | EXTENDED_MODE,
+ .muxregs = ssp2_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp2_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = ssp2_ext_13_16_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp2_ext_13_16_muxreg),
+ },
+};
+
+static struct spear_modemux ssp2_32_35_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = ssp2_ext_32_35_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp2_ext_32_35_muxreg),
+ },
+};
+
+static struct spear_modemux ssp2_44_47_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = ssp2_ext_44_47_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp2_ext_44_47_muxreg),
+ },
+};
+
+static struct spear_modemux ssp2_61_64_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = ssp2_ext_61_64_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp2_ext_61_64_muxreg),
+ },
+};
+
+static struct spear_modemux ssp2_90_93_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = ssp2_ext_90_93_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp2_ext_90_93_muxreg),
+ },
+};
+
+static struct spear_pingroup ssp2_pingroup[] = {
+ {
+ .name = "ssp2_13_16_grp",
+ .pins = ssp2_pins[0],
+ .npins = ARRAY_SIZE(ssp2_pins[0]),
+ .modemuxs = ssp2_13_16_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp2_13_16_modemux),
+ }, {
+ .name = "ssp2_32_35_grp",
+ .pins = ssp2_pins[1],
+ .npins = ARRAY_SIZE(ssp2_pins[1]),
+ .modemuxs = ssp2_32_35_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp2_32_35_modemux),
+ }, {
+ .name = "ssp2_44_47_grp",
+ .pins = ssp2_pins[2],
+ .npins = ARRAY_SIZE(ssp2_pins[2]),
+ .modemuxs = ssp2_44_47_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp2_44_47_modemux),
+ }, {
+ .name = "ssp2_61_64_grp",
+ .pins = ssp2_pins[3],
+ .npins = ARRAY_SIZE(ssp2_pins[3]),
+ .modemuxs = ssp2_61_64_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp2_61_64_modemux),
+ }, {
+ .name = "ssp2_90_93_grp",
+ .pins = ssp2_pins[4],
+ .npins = ARRAY_SIZE(ssp2_pins[4]),
+ .modemuxs = ssp2_90_93_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp2_90_93_modemux),
+ },
+};
+
+static const char *const ssp2_grps[] = { "ssp2_13_16_grp", "ssp2_32_35_grp",
+ "ssp2_44_47_grp", "ssp2_61_64_grp", "ssp2_90_93_grp" };
+static struct spear_function ssp2_function = {
+ .name = "ssp2",
+ .groups = ssp2_grps,
+ .ngroups = ARRAY_SIZE(ssp2_grps),
+};
+
+/* Pad multiplexing for cadence mii2 as mii device */
+static const unsigned mii2_pins[] = { 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
+ 90, 91, 92, 93, 94, 95, 96, 97 };
+static struct spear_muxreg mii2_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_80_89_REG,
+ .mask = PMX_PL_80_TO_85_MASK | PMX_PL_86_87_MASK |
+ PMX_PL_88_89_MASK,
+ .val = PMX_MII2_PL_80_TO_85_VAL | PMX_MII2_PL_86_87_VAL |
+ PMX_MII2_PL_88_89_VAL,
+ }, {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_90_91_MASK | PMX_PL_92_93_MASK |
+ PMX_PL_94_95_MASK | PMX_PL_96_97_MASK,
+ .val = PMX_MII2_PL_90_91_VAL | PMX_MII2_PL_92_93_VAL |
+ PMX_MII2_PL_94_95_VAL | PMX_MII2_PL_96_97_VAL,
+ }, {
+ .reg = EXT_CTRL_REG,
+ .mask = (MAC_MODE_MASK << MAC2_MODE_SHIFT) |
+ (MAC_MODE_MASK << MAC1_MODE_SHIFT) |
+ MII_MDIO_MASK,
+ .val = (MAC_MODE_MII << MAC2_MODE_SHIFT) |
+ (MAC_MODE_MII << MAC1_MODE_SHIFT) |
+ MII_MDIO_81_VAL,
+ },
+};
+
+static struct spear_modemux mii2_modemux[] = {
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = mii2_muxreg,
+ .nmuxregs = ARRAY_SIZE(mii2_muxreg),
+ },
+};
+
+static struct spear_pingroup mii2_pingroup = {
+ .name = "mii2_grp",
+ .pins = mii2_pins,
+ .npins = ARRAY_SIZE(mii2_pins),
+ .modemuxs = mii2_modemux,
+ .nmodemuxs = ARRAY_SIZE(mii2_modemux),
+};
+
+static const char *const mii2_grps[] = { "mii2_grp" };
+static struct spear_function mii2_function = {
+ .name = "mii2",
+ .groups = mii2_grps,
+ .ngroups = ARRAY_SIZE(mii2_grps),
+};
+
+/* Pad multiplexing for cadence mii 1_2 as smii or rmii device */
+static const unsigned smii0_1_pins[] = { 10, 11, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27 };
+static const unsigned rmii0_1_pins[] = { 10, 11, 21, 22, 23, 24, 25, 26, 27 };
+static struct spear_muxreg mii0_1_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ },
+};
+
+static struct spear_muxreg smii0_1_ext_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_10_19_REG,
+ .mask = PMX_PL_10_11_MASK,
+ .val = PMX_SMII_PL_10_11_VAL,
+ }, {
+ .reg = IP_SEL_PAD_20_29_REG,
+ .mask = PMX_PL_21_TO_27_MASK,
+ .val = PMX_SMII_PL_21_TO_27_VAL,
+ }, {
+ .reg = EXT_CTRL_REG,
+ .mask = (MAC_MODE_MASK << MAC2_MODE_SHIFT) |
+ (MAC_MODE_MASK << MAC1_MODE_SHIFT) |
+ MII_MDIO_MASK,
+ .val = (MAC_MODE_SMII << MAC2_MODE_SHIFT)
+ | (MAC_MODE_SMII << MAC1_MODE_SHIFT)
+ | MII_MDIO_10_11_VAL,
+ },
+};
+
+static struct spear_muxreg rmii0_1_ext_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_10_19_REG,
+ .mask = PMX_PL_10_11_MASK | PMX_PL_13_14_MASK |
+ PMX_PL_15_16_MASK | PMX_PL_17_18_MASK | PMX_PL_19_MASK,
+ .val = PMX_RMII_PL_10_11_VAL | PMX_RMII_PL_13_14_VAL |
+ PMX_RMII_PL_15_16_VAL | PMX_RMII_PL_17_18_VAL |
+ PMX_RMII_PL_19_VAL,
+ }, {
+ .reg = IP_SEL_PAD_20_29_REG,
+ .mask = PMX_PL_20_MASK | PMX_PL_21_TO_27_MASK,
+ .val = PMX_RMII_PL_20_VAL | PMX_RMII_PL_21_TO_27_VAL,
+ }, {
+ .reg = EXT_CTRL_REG,
+ .mask = (MAC_MODE_MASK << MAC2_MODE_SHIFT) |
+ (MAC_MODE_MASK << MAC1_MODE_SHIFT) |
+ MII_MDIO_MASK,
+ .val = (MAC_MODE_RMII << MAC2_MODE_SHIFT)
+ | (MAC_MODE_RMII << MAC1_MODE_SHIFT)
+ | MII_MDIO_10_11_VAL,
+ },
+};
+
+static struct spear_modemux mii0_1_modemux[][2] = {
+ {
+ /* configure as smii */
+ {
+ .modes = AUTO_NET_SMII_MODE | AUTO_EXP_MODE |
+ SMALL_PRINTERS_MODE | EXTENDED_MODE,
+ .muxregs = mii0_1_muxreg,
+ .nmuxregs = ARRAY_SIZE(mii0_1_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = smii0_1_ext_muxreg,
+ .nmuxregs = ARRAY_SIZE(smii0_1_ext_muxreg),
+ },
+ }, {
+ /* configure as rmii */
+ {
+ .modes = AUTO_NET_SMII_MODE | AUTO_EXP_MODE |
+ SMALL_PRINTERS_MODE | EXTENDED_MODE,
+ .muxregs = mii0_1_muxreg,
+ .nmuxregs = ARRAY_SIZE(mii0_1_muxreg),
+ }, {
+ .modes = EXTENDED_MODE,
+ .muxregs = rmii0_1_ext_muxreg,
+ .nmuxregs = ARRAY_SIZE(rmii0_1_ext_muxreg),
+ },
+ },
+};
+
+static struct spear_pingroup mii0_1_pingroup[] = {
+ {
+ .name = "smii0_1_grp",
+ .pins = smii0_1_pins,
+ .npins = ARRAY_SIZE(smii0_1_pins),
+ .modemuxs = mii0_1_modemux[0],
+ .nmodemuxs = ARRAY_SIZE(mii0_1_modemux[0]),
+ }, {
+ .name = "rmii0_1_grp",
+ .pins = rmii0_1_pins,
+ .npins = ARRAY_SIZE(rmii0_1_pins),
+ .modemuxs = mii0_1_modemux[1],
+ .nmodemuxs = ARRAY_SIZE(mii0_1_modemux[1]),
+ },
+};
+
+static const char *const mii0_1_grps[] = { "smii0_1_grp", "rmii0_1_grp" };
+static struct spear_function mii0_1_function = {
+ .name = "mii0_1",
+ .groups = mii0_1_grps,
+ .ngroups = ARRAY_SIZE(mii0_1_grps),
+};
+
+/* Pad multiplexing for i2c1 device */
+static const unsigned i2c1_pins[][2] = { { 8, 9 }, { 98, 99 } };
+static struct spear_muxreg i2c1_ext_8_9_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_SSP_CS_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_8_9_MASK,
+ .val = PMX_I2C1_PL_8_9_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_I2C1_PORT_SEL_MASK,
+ .val = PMX_I2C1_PORT_8_9_VAL,
+ },
+};
+
+static struct spear_muxreg i2c1_ext_98_99_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_98_MASK | PMX_PL_99_MASK,
+ .val = PMX_I2C1_PL_98_VAL | PMX_I2C1_PL_99_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_I2C1_PORT_SEL_MASK,
+ .val = PMX_I2C1_PORT_98_99_VAL,
+ },
+};
+
+static struct spear_modemux i2c1_modemux[][1] = {
+ {
+ /* Select signals on pins 8-9 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = i2c1_ext_8_9_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2c1_ext_8_9_muxreg),
+ },
+ }, {
+ /* Select signals on pins 98-99 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = i2c1_ext_98_99_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2c1_ext_98_99_muxreg),
+ },
+ },
+};
+
+static struct spear_pingroup i2c1_pingroup[] = {
+ {
+ .name = "i2c1_8_9_grp",
+ .pins = i2c1_pins[0],
+ .npins = ARRAY_SIZE(i2c1_pins[0]),
+ .modemuxs = i2c1_modemux[0],
+ .nmodemuxs = ARRAY_SIZE(i2c1_modemux[0]),
+ }, {
+ .name = "i2c1_98_99_grp",
+ .pins = i2c1_pins[1],
+ .npins = ARRAY_SIZE(i2c1_pins[1]),
+ .modemuxs = i2c1_modemux[1],
+ .nmodemuxs = ARRAY_SIZE(i2c1_modemux[1]),
+ },
+};
+
+static const char *const i2c1_grps[] = { "i2c1_8_9_grp", "i2c1_98_99_grp" };
+static struct spear_function i2c1_function = {
+ .name = "i2c1",
+ .groups = i2c1_grps,
+ .ngroups = ARRAY_SIZE(i2c1_grps),
+};
+
+/* Pad multiplexing for i2c2 device */
+static const unsigned i2c2_pins[][2] = { { 0, 1 }, { 2, 3 }, { 19, 20 },
+ { 75, 76 }, { 96, 97 } };
+static struct spear_muxreg i2c2_ext_0_1_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_FIRDA_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_0_1_MASK,
+ .val = PMX_I2C2_PL_0_1_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_I2C2_PORT_SEL_MASK,
+ .val = PMX_I2C2_PORT_0_1_VAL,
+ },
+};
+
+static struct spear_muxreg i2c2_ext_2_3_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_UART0_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_0_9_REG,
+ .mask = PMX_PL_2_3_MASK,
+ .val = PMX_I2C2_PL_2_3_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_I2C2_PORT_SEL_MASK,
+ .val = PMX_I2C2_PORT_2_3_VAL,
+ },
+};
+
+static struct spear_muxreg i2c2_ext_19_20_muxreg[] = {
+ {
+ .reg = PMX_CONFIG_REG,
+ .mask = PMX_MII_MASK,
+ .val = 0,
+ }, {
+ .reg = IP_SEL_PAD_10_19_REG,
+ .mask = PMX_PL_19_MASK,
+ .val = PMX_I2C2_PL_19_VAL,
+ }, {
+ .reg = IP_SEL_PAD_20_29_REG,
+ .mask = PMX_PL_20_MASK,
+ .val = PMX_I2C2_PL_20_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_I2C2_PORT_SEL_MASK,
+ .val = PMX_I2C2_PORT_19_20_VAL,
+ },
+};
+
+static struct spear_muxreg i2c2_ext_75_76_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_70_79_REG,
+ .mask = PMX_PL_75_76_MASK,
+ .val = PMX_I2C2_PL_75_76_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_I2C2_PORT_SEL_MASK,
+ .val = PMX_I2C2_PORT_75_76_VAL,
+ },
+};
+
+static struct spear_muxreg i2c2_ext_96_97_muxreg[] = {
+ {
+ .reg = IP_SEL_PAD_90_99_REG,
+ .mask = PMX_PL_96_97_MASK,
+ .val = PMX_I2C2_PL_96_97_VAL,
+ }, {
+ .reg = IP_SEL_MIX_PAD_REG,
+ .mask = PMX_I2C2_PORT_SEL_MASK,
+ .val = PMX_I2C2_PORT_96_97_VAL,
+ },
+};
+
+static struct spear_modemux i2c2_modemux[][1] = {
+ {
+ /* Select signals on pins 0_1 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = i2c2_ext_0_1_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2c2_ext_0_1_muxreg),
+ },
+ }, {
+ /* Select signals on pins 2_3 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = i2c2_ext_2_3_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2c2_ext_2_3_muxreg),
+ },
+ }, {
+ /* Select signals on pins 19_20 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = i2c2_ext_19_20_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2c2_ext_19_20_muxreg),
+ },
+ }, {
+ /* Select signals on pins 75_76 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = i2c2_ext_75_76_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2c2_ext_75_76_muxreg),
+ },
+ }, {
+ /* Select signals on pins 96_97 */
+ {
+ .modes = EXTENDED_MODE,
+ .muxregs = i2c2_ext_96_97_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2c2_ext_96_97_muxreg),
+ },
+ },
+};
+
+static struct spear_pingroup i2c2_pingroup[] = {
+ {
+ .name = "i2c2_0_1_grp",
+ .pins = i2c2_pins[0],
+ .npins = ARRAY_SIZE(i2c2_pins[0]),
+ .modemuxs = i2c2_modemux[0],
+ .nmodemuxs = ARRAY_SIZE(i2c2_modemux[0]),
+ }, {
+ .name = "i2c2_2_3_grp",
+ .pins = i2c2_pins[1],
+ .npins = ARRAY_SIZE(i2c2_pins[1]),
+ .modemuxs = i2c2_modemux[1],
+ .nmodemuxs = ARRAY_SIZE(i2c2_modemux[1]),
+ }, {
+ .name = "i2c2_19_20_grp",
+ .pins = i2c2_pins[2],
+ .npins = ARRAY_SIZE(i2c2_pins[2]),
+ .modemuxs = i2c2_modemux[2],
+ .nmodemuxs = ARRAY_SIZE(i2c2_modemux[2]),
+ }, {
+ .name = "i2c2_75_76_grp",
+ .pins = i2c2_pins[3],
+ .npins = ARRAY_SIZE(i2c2_pins[3]),
+ .modemuxs = i2c2_modemux[3],
+ .nmodemuxs = ARRAY_SIZE(i2c2_modemux[3]),
+ }, {
+ .name = "i2c2_96_97_grp",
+ .pins = i2c2_pins[4],
+ .npins = ARRAY_SIZE(i2c2_pins[4]),
+ .modemuxs = i2c2_modemux[4],
+ .nmodemuxs = ARRAY_SIZE(i2c2_modemux[4]),
+ },
+};
+
+static const char *const i2c2_grps[] = { "i2c2_0_1_grp", "i2c2_2_3_grp",
+ "i2c2_19_20_grp", "i2c2_75_76_grp", "i2c2_96_97_grp" };
+static struct spear_function i2c2_function = {
+ .name = "i2c2",
+ .groups = i2c2_grps,
+ .ngroups = ARRAY_SIZE(i2c2_grps),
+};
+
+/* pingroups */
+static struct spear_pingroup *spear320_pingroups[] = {
+ SPEAR3XX_COMMON_PINGROUPS,
+ &clcd_pingroup,
+ &emi_pingroup,
+ &fsmc_8bit_pingroup,
+ &fsmc_16bit_pingroup,
+ &spp_pingroup,
+ &sdhci_led_pingroup,
+ &sdhci_pingroup[0],
+ &sdhci_pingroup[1],
+ &i2s_pingroup,
+ &uart1_pingroup,
+ &uart1_modem_pingroup[0],
+ &uart1_modem_pingroup[1],
+ &uart1_modem_pingroup[2],
+ &uart1_modem_pingroup[3],
+ &uart2_pingroup,
+ &uart3_pingroup[0],
+ &uart3_pingroup[1],
+ &uart3_pingroup[2],
+ &uart3_pingroup[3],
+ &uart3_pingroup[4],
+ &uart3_pingroup[5],
+ &uart3_pingroup[6],
+ &uart4_pingroup[0],
+ &uart4_pingroup[1],
+ &uart4_pingroup[2],
+ &uart4_pingroup[3],
+ &uart4_pingroup[4],
+ &uart4_pingroup[5],
+ &uart5_pingroup[0],
+ &uart5_pingroup[1],
+ &uart5_pingroup[2],
+ &uart5_pingroup[3],
+ &uart6_pingroup[0],
+ &uart6_pingroup[1],
+ &rs485_pingroup,
+ &touchscreen_pingroup,
+ &can0_pingroup,
+ &can1_pingroup,
+ &pwm0_1_pingroup[0],
+ &pwm0_1_pingroup[1],
+ &pwm0_1_pingroup[2],
+ &pwm0_1_pingroup[3],
+ &pwm0_1_pingroup[4],
+ &pwm0_1_pingroup[5],
+ &pwm0_1_pingroup[6],
+ &pwm2_pingroup[0],
+ &pwm2_pingroup[1],
+ &pwm2_pingroup[2],
+ &pwm2_pingroup[3],
+ &pwm2_pingroup[4],
+ &pwm2_pingroup[5],
+ &pwm2_pingroup[6],
+ &pwm3_pingroup[0],
+ &pwm3_pingroup[1],
+ &pwm3_pingroup[2],
+ &pwm3_pingroup[3],
+ &pwm3_pingroup[4],
+ &pwm3_pingroup[5],
+ &ssp1_pingroup[0],
+ &ssp1_pingroup[1],
+ &ssp1_pingroup[2],
+ &ssp1_pingroup[3],
+ &ssp1_pingroup[4],
+ &ssp2_pingroup[0],
+ &ssp2_pingroup[1],
+ &ssp2_pingroup[2],
+ &ssp2_pingroup[3],
+ &ssp2_pingroup[4],
+ &mii2_pingroup,
+ &mii0_1_pingroup[0],
+ &mii0_1_pingroup[1],
+ &i2c1_pingroup[0],
+ &i2c1_pingroup[1],
+ &i2c2_pingroup[0],
+ &i2c2_pingroup[1],
+ &i2c2_pingroup[2],
+ &i2c2_pingroup[3],
+ &i2c2_pingroup[4],
+};
+
+/* functions */
+static struct spear_function *spear320_functions[] = {
+ SPEAR3XX_COMMON_FUNCTIONS,
+ &clcd_function,
+ &emi_function,
+ &fsmc_function,
+ &spp_function,
+ &sdhci_function,
+ &i2s_function,
+ &uart1_function,
+ &uart1_modem_function,
+ &uart2_function,
+ &uart3_function,
+ &uart4_function,
+ &uart5_function,
+ &uart6_function,
+ &rs485_function,
+ &touchscreen_function,
+ &can0_function,
+ &can1_function,
+ &pwm0_1_function,
+ &pwm2_function,
+ &pwm3_function,
+ &ssp1_function,
+ &ssp2_function,
+ &mii2_function,
+ &mii0_1_function,
+ &i2c1_function,
+ &i2c2_function,
+};
+
+static struct of_device_id spear320_pinctrl_of_match[] __devinitdata = {
+ {
+ .compatible = "st,spear320-pinmux",
+ },
+ {},
+};
+
+static int __devinit spear320_pinctrl_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ spear3xx_machdata.groups = spear320_pingroups;
+ spear3xx_machdata.ngroups = ARRAY_SIZE(spear320_pingroups);
+ spear3xx_machdata.functions = spear320_functions;
+ spear3xx_machdata.nfunctions = ARRAY_SIZE(spear320_functions);
+
+ spear3xx_machdata.modes_supported = true;
+ spear3xx_machdata.pmx_modes = spear320_pmx_modes;
+ spear3xx_machdata.npmx_modes = ARRAY_SIZE(spear320_pmx_modes);
+
+ pmx_init_addr(&spear3xx_machdata, PMX_CONFIG_REG);
+
+ ret = spear_pinctrl_probe(pdev, &spear3xx_machdata);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int __devexit spear320_pinctrl_remove(struct platform_device *pdev)
+{
+ return spear_pinctrl_remove(pdev);
+}
+
+static struct platform_driver spear320_pinctrl_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = spear320_pinctrl_of_match,
+ },
+ .probe = spear320_pinctrl_probe,
+ .remove = __devexit_p(spear320_pinctrl_remove),
+};
+
+static int __init spear320_pinctrl_init(void)
+{
+ return platform_driver_register(&spear320_pinctrl_driver);
+}
+arch_initcall(spear320_pinctrl_init);
+
+static void __exit spear320_pinctrl_exit(void)
+{
+ platform_driver_unregister(&spear320_pinctrl_driver);
+}
+module_exit(spear320_pinctrl_exit);
+
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
+MODULE_DESCRIPTION("ST Microelectronics SPEAr320 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, spear320_pinctrl_of_match);
diff --git a/drivers/pinctrl/spear/pinctrl-spear3xx.c b/drivers/pinctrl/spear/pinctrl-spear3xx.c
new file mode 100644
index 000000000000..832049a8b1c9
--- /dev/null
+++ b/drivers/pinctrl/spear/pinctrl-spear3xx.c
@@ -0,0 +1,588 @@
+/*
+ * Driver for the ST Microelectronics SPEAr3xx pinmux
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-spear3xx.h"
+
+/* pins */
+static const struct pinctrl_pin_desc spear3xx_pins[] = {
+ PINCTRL_PIN(0, "PLGPIO0"),
+ PINCTRL_PIN(1, "PLGPIO1"),
+ PINCTRL_PIN(2, "PLGPIO2"),
+ PINCTRL_PIN(3, "PLGPIO3"),
+ PINCTRL_PIN(4, "PLGPIO4"),
+ PINCTRL_PIN(5, "PLGPIO5"),
+ PINCTRL_PIN(6, "PLGPIO6"),
+ PINCTRL_PIN(7, "PLGPIO7"),
+ PINCTRL_PIN(8, "PLGPIO8"),
+ PINCTRL_PIN(9, "PLGPIO9"),
+ PINCTRL_PIN(10, "PLGPIO10"),
+ PINCTRL_PIN(11, "PLGPIO11"),
+ PINCTRL_PIN(12, "PLGPIO12"),
+ PINCTRL_PIN(13, "PLGPIO13"),
+ PINCTRL_PIN(14, "PLGPIO14"),
+ PINCTRL_PIN(15, "PLGPIO15"),
+ PINCTRL_PIN(16, "PLGPIO16"),
+ PINCTRL_PIN(17, "PLGPIO17"),
+ PINCTRL_PIN(18, "PLGPIO18"),
+ PINCTRL_PIN(19, "PLGPIO19"),
+ PINCTRL_PIN(20, "PLGPIO20"),
+ PINCTRL_PIN(21, "PLGPIO21"),
+ PINCTRL_PIN(22, "PLGPIO22"),
+ PINCTRL_PIN(23, "PLGPIO23"),
+ PINCTRL_PIN(24, "PLGPIO24"),
+ PINCTRL_PIN(25, "PLGPIO25"),
+ PINCTRL_PIN(26, "PLGPIO26"),
+ PINCTRL_PIN(27, "PLGPIO27"),
+ PINCTRL_PIN(28, "PLGPIO28"),
+ PINCTRL_PIN(29, "PLGPIO29"),
+ PINCTRL_PIN(30, "PLGPIO30"),
+ PINCTRL_PIN(31, "PLGPIO31"),
+ PINCTRL_PIN(32, "PLGPIO32"),
+ PINCTRL_PIN(33, "PLGPIO33"),
+ PINCTRL_PIN(34, "PLGPIO34"),
+ PINCTRL_PIN(35, "PLGPIO35"),
+ PINCTRL_PIN(36, "PLGPIO36"),
+ PINCTRL_PIN(37, "PLGPIO37"),
+ PINCTRL_PIN(38, "PLGPIO38"),
+ PINCTRL_PIN(39, "PLGPIO39"),
+ PINCTRL_PIN(40, "PLGPIO40"),
+ PINCTRL_PIN(41, "PLGPIO41"),
+ PINCTRL_PIN(42, "PLGPIO42"),
+ PINCTRL_PIN(43, "PLGPIO43"),
+ PINCTRL_PIN(44, "PLGPIO44"),
+ PINCTRL_PIN(45, "PLGPIO45"),
+ PINCTRL_PIN(46, "PLGPIO46"),
+ PINCTRL_PIN(47, "PLGPIO47"),
+ PINCTRL_PIN(48, "PLGPIO48"),
+ PINCTRL_PIN(49, "PLGPIO49"),
+ PINCTRL_PIN(50, "PLGPIO50"),
+ PINCTRL_PIN(51, "PLGPIO51"),
+ PINCTRL_PIN(52, "PLGPIO52"),
+ PINCTRL_PIN(53, "PLGPIO53"),
+ PINCTRL_PIN(54, "PLGPIO54"),
+ PINCTRL_PIN(55, "PLGPIO55"),
+ PINCTRL_PIN(56, "PLGPIO56"),
+ PINCTRL_PIN(57, "PLGPIO57"),
+ PINCTRL_PIN(58, "PLGPIO58"),
+ PINCTRL_PIN(59, "PLGPIO59"),
+ PINCTRL_PIN(60, "PLGPIO60"),
+ PINCTRL_PIN(61, "PLGPIO61"),
+ PINCTRL_PIN(62, "PLGPIO62"),
+ PINCTRL_PIN(63, "PLGPIO63"),
+ PINCTRL_PIN(64, "PLGPIO64"),
+ PINCTRL_PIN(65, "PLGPIO65"),
+ PINCTRL_PIN(66, "PLGPIO66"),
+ PINCTRL_PIN(67, "PLGPIO67"),
+ PINCTRL_PIN(68, "PLGPIO68"),
+ PINCTRL_PIN(69, "PLGPIO69"),
+ PINCTRL_PIN(70, "PLGPIO70"),
+ PINCTRL_PIN(71, "PLGPIO71"),
+ PINCTRL_PIN(72, "PLGPIO72"),
+ PINCTRL_PIN(73, "PLGPIO73"),
+ PINCTRL_PIN(74, "PLGPIO74"),
+ PINCTRL_PIN(75, "PLGPIO75"),
+ PINCTRL_PIN(76, "PLGPIO76"),
+ PINCTRL_PIN(77, "PLGPIO77"),
+ PINCTRL_PIN(78, "PLGPIO78"),
+ PINCTRL_PIN(79, "PLGPIO79"),
+ PINCTRL_PIN(80, "PLGPIO80"),
+ PINCTRL_PIN(81, "PLGPIO81"),
+ PINCTRL_PIN(82, "PLGPIO82"),
+ PINCTRL_PIN(83, "PLGPIO83"),
+ PINCTRL_PIN(84, "PLGPIO84"),
+ PINCTRL_PIN(85, "PLGPIO85"),
+ PINCTRL_PIN(86, "PLGPIO86"),
+ PINCTRL_PIN(87, "PLGPIO87"),
+ PINCTRL_PIN(88, "PLGPIO88"),
+ PINCTRL_PIN(89, "PLGPIO89"),
+ PINCTRL_PIN(90, "PLGPIO90"),
+ PINCTRL_PIN(91, "PLGPIO91"),
+ PINCTRL_PIN(92, "PLGPIO92"),
+ PINCTRL_PIN(93, "PLGPIO93"),
+ PINCTRL_PIN(94, "PLGPIO94"),
+ PINCTRL_PIN(95, "PLGPIO95"),
+ PINCTRL_PIN(96, "PLGPIO96"),
+ PINCTRL_PIN(97, "PLGPIO97"),
+ PINCTRL_PIN(98, "PLGPIO98"),
+ PINCTRL_PIN(99, "PLGPIO99"),
+ PINCTRL_PIN(100, "PLGPIO100"),
+ PINCTRL_PIN(101, "PLGPIO101"),
+};
+
+/* firda_pins */
+static const unsigned firda_pins[] = { 0, 1 };
+static struct spear_muxreg firda_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_FIRDA_MASK,
+ .val = PMX_FIRDA_MASK,
+ },
+};
+
+static struct spear_modemux firda_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = firda_muxreg,
+ .nmuxregs = ARRAY_SIZE(firda_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_firda_pingroup = {
+ .name = "firda_grp",
+ .pins = firda_pins,
+ .npins = ARRAY_SIZE(firda_pins),
+ .modemuxs = firda_modemux,
+ .nmodemuxs = ARRAY_SIZE(firda_modemux),
+};
+
+static const char *const firda_grps[] = { "firda_grp" };
+struct spear_function spear3xx_firda_function = {
+ .name = "firda",
+ .groups = firda_grps,
+ .ngroups = ARRAY_SIZE(firda_grps),
+};
+
+/* i2c_pins */
+static const unsigned i2c_pins[] = { 4, 5 };
+static struct spear_muxreg i2c_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_I2C_MASK,
+ .val = PMX_I2C_MASK,
+ },
+};
+
+static struct spear_modemux i2c_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = i2c_muxreg,
+ .nmuxregs = ARRAY_SIZE(i2c_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_i2c_pingroup = {
+ .name = "i2c0_grp",
+ .pins = i2c_pins,
+ .npins = ARRAY_SIZE(i2c_pins),
+ .modemuxs = i2c_modemux,
+ .nmodemuxs = ARRAY_SIZE(i2c_modemux),
+};
+
+static const char *const i2c_grps[] = { "i2c0_grp" };
+struct spear_function spear3xx_i2c_function = {
+ .name = "i2c0",
+ .groups = i2c_grps,
+ .ngroups = ARRAY_SIZE(i2c_grps),
+};
+
+/* ssp_cs_pins */
+static const unsigned ssp_cs_pins[] = { 34, 35, 36 };
+static struct spear_muxreg ssp_cs_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_SSP_CS_MASK,
+ .val = PMX_SSP_CS_MASK,
+ },
+};
+
+static struct spear_modemux ssp_cs_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = ssp_cs_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp_cs_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_ssp_cs_pingroup = {
+ .name = "ssp_cs_grp",
+ .pins = ssp_cs_pins,
+ .npins = ARRAY_SIZE(ssp_cs_pins),
+ .modemuxs = ssp_cs_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp_cs_modemux),
+};
+
+static const char *const ssp_cs_grps[] = { "ssp_cs_grp" };
+struct spear_function spear3xx_ssp_cs_function = {
+ .name = "ssp_cs",
+ .groups = ssp_cs_grps,
+ .ngroups = ARRAY_SIZE(ssp_cs_grps),
+};
+
+/* ssp_pins */
+static const unsigned ssp_pins[] = { 6, 7, 8, 9 };
+static struct spear_muxreg ssp_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_SSP_MASK,
+ .val = PMX_SSP_MASK,
+ },
+};
+
+static struct spear_modemux ssp_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = ssp_muxreg,
+ .nmuxregs = ARRAY_SIZE(ssp_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_ssp_pingroup = {
+ .name = "ssp0_grp",
+ .pins = ssp_pins,
+ .npins = ARRAY_SIZE(ssp_pins),
+ .modemuxs = ssp_modemux,
+ .nmodemuxs = ARRAY_SIZE(ssp_modemux),
+};
+
+static const char *const ssp_grps[] = { "ssp0_grp" };
+struct spear_function spear3xx_ssp_function = {
+ .name = "ssp0",
+ .groups = ssp_grps,
+ .ngroups = ARRAY_SIZE(ssp_grps),
+};
+
+/* mii_pins */
+static const unsigned mii_pins[] = { 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27 };
+static struct spear_muxreg mii_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_MII_MASK,
+ .val = PMX_MII_MASK,
+ },
+};
+
+static struct spear_modemux mii_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = mii_muxreg,
+ .nmuxregs = ARRAY_SIZE(mii_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_mii_pingroup = {
+ .name = "mii0_grp",
+ .pins = mii_pins,
+ .npins = ARRAY_SIZE(mii_pins),
+ .modemuxs = mii_modemux,
+ .nmodemuxs = ARRAY_SIZE(mii_modemux),
+};
+
+static const char *const mii_grps[] = { "mii0_grp" };
+struct spear_function spear3xx_mii_function = {
+ .name = "mii0",
+ .groups = mii_grps,
+ .ngroups = ARRAY_SIZE(mii_grps),
+};
+
+/* gpio0_pin0_pins */
+static const unsigned gpio0_pin0_pins[] = { 28 };
+static struct spear_muxreg gpio0_pin0_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_GPIO_PIN0_MASK,
+ .val = PMX_GPIO_PIN0_MASK,
+ },
+};
+
+static struct spear_modemux gpio0_pin0_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = gpio0_pin0_muxreg,
+ .nmuxregs = ARRAY_SIZE(gpio0_pin0_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_gpio0_pin0_pingroup = {
+ .name = "gpio0_pin0_grp",
+ .pins = gpio0_pin0_pins,
+ .npins = ARRAY_SIZE(gpio0_pin0_pins),
+ .modemuxs = gpio0_pin0_modemux,
+ .nmodemuxs = ARRAY_SIZE(gpio0_pin0_modemux),
+};
+
+/* gpio0_pin1_pins */
+static const unsigned gpio0_pin1_pins[] = { 29 };
+static struct spear_muxreg gpio0_pin1_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_GPIO_PIN1_MASK,
+ .val = PMX_GPIO_PIN1_MASK,
+ },
+};
+
+static struct spear_modemux gpio0_pin1_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = gpio0_pin1_muxreg,
+ .nmuxregs = ARRAY_SIZE(gpio0_pin1_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_gpio0_pin1_pingroup = {
+ .name = "gpio0_pin1_grp",
+ .pins = gpio0_pin1_pins,
+ .npins = ARRAY_SIZE(gpio0_pin1_pins),
+ .modemuxs = gpio0_pin1_modemux,
+ .nmodemuxs = ARRAY_SIZE(gpio0_pin1_modemux),
+};
+
+/* gpio0_pin2_pins */
+static const unsigned gpio0_pin2_pins[] = { 30 };
+static struct spear_muxreg gpio0_pin2_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_GPIO_PIN2_MASK,
+ .val = PMX_GPIO_PIN2_MASK,
+ },
+};
+
+static struct spear_modemux gpio0_pin2_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = gpio0_pin2_muxreg,
+ .nmuxregs = ARRAY_SIZE(gpio0_pin2_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_gpio0_pin2_pingroup = {
+ .name = "gpio0_pin2_grp",
+ .pins = gpio0_pin2_pins,
+ .npins = ARRAY_SIZE(gpio0_pin2_pins),
+ .modemuxs = gpio0_pin2_modemux,
+ .nmodemuxs = ARRAY_SIZE(gpio0_pin2_modemux),
+};
+
+/* gpio0_pin3_pins */
+static const unsigned gpio0_pin3_pins[] = { 31 };
+static struct spear_muxreg gpio0_pin3_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_GPIO_PIN3_MASK,
+ .val = PMX_GPIO_PIN3_MASK,
+ },
+};
+
+static struct spear_modemux gpio0_pin3_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = gpio0_pin3_muxreg,
+ .nmuxregs = ARRAY_SIZE(gpio0_pin3_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_gpio0_pin3_pingroup = {
+ .name = "gpio0_pin3_grp",
+ .pins = gpio0_pin3_pins,
+ .npins = ARRAY_SIZE(gpio0_pin3_pins),
+ .modemuxs = gpio0_pin3_modemux,
+ .nmodemuxs = ARRAY_SIZE(gpio0_pin3_modemux),
+};
+
+/* gpio0_pin4_pins */
+static const unsigned gpio0_pin4_pins[] = { 32 };
+static struct spear_muxreg gpio0_pin4_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_GPIO_PIN4_MASK,
+ .val = PMX_GPIO_PIN4_MASK,
+ },
+};
+
+static struct spear_modemux gpio0_pin4_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = gpio0_pin4_muxreg,
+ .nmuxregs = ARRAY_SIZE(gpio0_pin4_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_gpio0_pin4_pingroup = {
+ .name = "gpio0_pin4_grp",
+ .pins = gpio0_pin4_pins,
+ .npins = ARRAY_SIZE(gpio0_pin4_pins),
+ .modemuxs = gpio0_pin4_modemux,
+ .nmodemuxs = ARRAY_SIZE(gpio0_pin4_modemux),
+};
+
+/* gpio0_pin5_pins */
+static const unsigned gpio0_pin5_pins[] = { 33 };
+static struct spear_muxreg gpio0_pin5_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_GPIO_PIN5_MASK,
+ .val = PMX_GPIO_PIN5_MASK,
+ },
+};
+
+static struct spear_modemux gpio0_pin5_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = gpio0_pin5_muxreg,
+ .nmuxregs = ARRAY_SIZE(gpio0_pin5_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_gpio0_pin5_pingroup = {
+ .name = "gpio0_pin5_grp",
+ .pins = gpio0_pin5_pins,
+ .npins = ARRAY_SIZE(gpio0_pin5_pins),
+ .modemuxs = gpio0_pin5_modemux,
+ .nmodemuxs = ARRAY_SIZE(gpio0_pin5_modemux),
+};
+
+static const char *const gpio0_grps[] = { "gpio0_pin0_grp", "gpio0_pin1_grp",
+ "gpio0_pin2_grp", "gpio0_pin3_grp", "gpio0_pin4_grp", "gpio0_pin5_grp",
+};
+struct spear_function spear3xx_gpio0_function = {
+ .name = "gpio0",
+ .groups = gpio0_grps,
+ .ngroups = ARRAY_SIZE(gpio0_grps),
+};
+
+/* uart0_ext_pins */
+static const unsigned uart0_ext_pins[] = { 37, 38, 39, 40, 41, 42 };
+static struct spear_muxreg uart0_ext_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_UART0_MODEM_MASK,
+ .val = PMX_UART0_MODEM_MASK,
+ },
+};
+
+static struct spear_modemux uart0_ext_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = uart0_ext_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart0_ext_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_uart0_ext_pingroup = {
+ .name = "uart0_ext_grp",
+ .pins = uart0_ext_pins,
+ .npins = ARRAY_SIZE(uart0_ext_pins),
+ .modemuxs = uart0_ext_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart0_ext_modemux),
+};
+
+static const char *const uart0_ext_grps[] = { "uart0_ext_grp" };
+struct spear_function spear3xx_uart0_ext_function = {
+ .name = "uart0_ext",
+ .groups = uart0_ext_grps,
+ .ngroups = ARRAY_SIZE(uart0_ext_grps),
+};
+
+/* uart0_pins */
+static const unsigned uart0_pins[] = { 2, 3 };
+static struct spear_muxreg uart0_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_UART0_MASK,
+ .val = PMX_UART0_MASK,
+ },
+};
+
+static struct spear_modemux uart0_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = uart0_muxreg,
+ .nmuxregs = ARRAY_SIZE(uart0_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_uart0_pingroup = {
+ .name = "uart0_grp",
+ .pins = uart0_pins,
+ .npins = ARRAY_SIZE(uart0_pins),
+ .modemuxs = uart0_modemux,
+ .nmodemuxs = ARRAY_SIZE(uart0_modemux),
+};
+
+static const char *const uart0_grps[] = { "uart0_grp" };
+struct spear_function spear3xx_uart0_function = {
+ .name = "uart0",
+ .groups = uart0_grps,
+ .ngroups = ARRAY_SIZE(uart0_grps),
+};
+
+/* timer_0_1_pins */
+static const unsigned timer_0_1_pins[] = { 43, 44, 47, 48 };
+static struct spear_muxreg timer_0_1_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_TIMER_0_1_MASK,
+ .val = PMX_TIMER_0_1_MASK,
+ },
+};
+
+static struct spear_modemux timer_0_1_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = timer_0_1_muxreg,
+ .nmuxregs = ARRAY_SIZE(timer_0_1_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_timer_0_1_pingroup = {
+ .name = "timer_0_1_grp",
+ .pins = timer_0_1_pins,
+ .npins = ARRAY_SIZE(timer_0_1_pins),
+ .modemuxs = timer_0_1_modemux,
+ .nmodemuxs = ARRAY_SIZE(timer_0_1_modemux),
+};
+
+static const char *const timer_0_1_grps[] = { "timer_0_1_grp" };
+struct spear_function spear3xx_timer_0_1_function = {
+ .name = "timer_0_1",
+ .groups = timer_0_1_grps,
+ .ngroups = ARRAY_SIZE(timer_0_1_grps),
+};
+
+/* timer_2_3_pins */
+static const unsigned timer_2_3_pins[] = { 45, 46, 49, 50 };
+static struct spear_muxreg timer_2_3_muxreg[] = {
+ {
+ .reg = -1,
+ .mask = PMX_TIMER_2_3_MASK,
+ .val = PMX_TIMER_2_3_MASK,
+ },
+};
+
+static struct spear_modemux timer_2_3_modemux[] = {
+ {
+ .modes = ~0,
+ .muxregs = timer_2_3_muxreg,
+ .nmuxregs = ARRAY_SIZE(timer_2_3_muxreg),
+ },
+};
+
+struct spear_pingroup spear3xx_timer_2_3_pingroup = {
+ .name = "timer_2_3_grp",
+ .pins = timer_2_3_pins,
+ .npins = ARRAY_SIZE(timer_2_3_pins),
+ .modemuxs = timer_2_3_modemux,
+ .nmodemuxs = ARRAY_SIZE(timer_2_3_modemux),
+};
+
+static const char *const timer_2_3_grps[] = { "timer_2_3_grp" };
+struct spear_function spear3xx_timer_2_3_function = {
+ .name = "timer_2_3",
+ .groups = timer_2_3_grps,
+ .ngroups = ARRAY_SIZE(timer_2_3_grps),
+};
+
+struct spear_pinctrl_machdata spear3xx_machdata = {
+ .pins = spear3xx_pins,
+ .npins = ARRAY_SIZE(spear3xx_pins),
+};
diff --git a/drivers/pinctrl/spear/pinctrl-spear3xx.h b/drivers/pinctrl/spear/pinctrl-spear3xx.h
new file mode 100644
index 000000000000..5d5fdd8df7b8
--- /dev/null
+++ b/drivers/pinctrl/spear/pinctrl-spear3xx.h
@@ -0,0 +1,92 @@
+/*
+ * Header file for the ST Microelectronics SPEAr3xx pinmux
+ *
+ * Copyright (C) 2012 ST Microelectronics
+ * Viresh Kumar <viresh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __PINMUX_SPEAR3XX_H__
+#define __PINMUX_SPEAR3XX_H__
+
+#include "pinctrl-spear.h"
+
+/* pad mux declarations */
+#define PMX_FIRDA_MASK (1 << 14)
+#define PMX_I2C_MASK (1 << 13)
+#define PMX_SSP_CS_MASK (1 << 12)
+#define PMX_SSP_MASK (1 << 11)
+#define PMX_MII_MASK (1 << 10)
+#define PMX_GPIO_PIN0_MASK (1 << 9)
+#define PMX_GPIO_PIN1_MASK (1 << 8)
+#define PMX_GPIO_PIN2_MASK (1 << 7)
+#define PMX_GPIO_PIN3_MASK (1 << 6)
+#define PMX_GPIO_PIN4_MASK (1 << 5)
+#define PMX_GPIO_PIN5_MASK (1 << 4)
+#define PMX_UART0_MODEM_MASK (1 << 3)
+#define PMX_UART0_MASK (1 << 2)
+#define PMX_TIMER_2_3_MASK (1 << 1)
+#define PMX_TIMER_0_1_MASK (1 << 0)
+
+extern struct spear_pingroup spear3xx_firda_pingroup;
+extern struct spear_pingroup spear3xx_gpio0_pin0_pingroup;
+extern struct spear_pingroup spear3xx_gpio0_pin1_pingroup;
+extern struct spear_pingroup spear3xx_gpio0_pin2_pingroup;
+extern struct spear_pingroup spear3xx_gpio0_pin3_pingroup;
+extern struct spear_pingroup spear3xx_gpio0_pin4_pingroup;
+extern struct spear_pingroup spear3xx_gpio0_pin5_pingroup;
+extern struct spear_pingroup spear3xx_i2c_pingroup;
+extern struct spear_pingroup spear3xx_mii_pingroup;
+extern struct spear_pingroup spear3xx_ssp_cs_pingroup;
+extern struct spear_pingroup spear3xx_ssp_pingroup;
+extern struct spear_pingroup spear3xx_timer_0_1_pingroup;
+extern struct spear_pingroup spear3xx_timer_2_3_pingroup;
+extern struct spear_pingroup spear3xx_uart0_ext_pingroup;
+extern struct spear_pingroup spear3xx_uart0_pingroup;
+
+#define SPEAR3XX_COMMON_PINGROUPS \
+ &spear3xx_firda_pingroup, \
+ &spear3xx_gpio0_pin0_pingroup, \
+ &spear3xx_gpio0_pin1_pingroup, \
+ &spear3xx_gpio0_pin2_pingroup, \
+ &spear3xx_gpio0_pin3_pingroup, \
+ &spear3xx_gpio0_pin4_pingroup, \
+ &spear3xx_gpio0_pin5_pingroup, \
+ &spear3xx_i2c_pingroup, \
+ &spear3xx_mii_pingroup, \
+ &spear3xx_ssp_cs_pingroup, \
+ &spear3xx_ssp_pingroup, \
+ &spear3xx_timer_0_1_pingroup, \
+ &spear3xx_timer_2_3_pingroup, \
+ &spear3xx_uart0_ext_pingroup, \
+ &spear3xx_uart0_pingroup
+
+extern struct spear_function spear3xx_firda_function;
+extern struct spear_function spear3xx_gpio0_function;
+extern struct spear_function spear3xx_i2c_function;
+extern struct spear_function spear3xx_mii_function;
+extern struct spear_function spear3xx_ssp_cs_function;
+extern struct spear_function spear3xx_ssp_function;
+extern struct spear_function spear3xx_timer_0_1_function;
+extern struct spear_function spear3xx_timer_2_3_function;
+extern struct spear_function spear3xx_uart0_ext_function;
+extern struct spear_function spear3xx_uart0_function;
+
+#define SPEAR3XX_COMMON_FUNCTIONS \
+ &spear3xx_firda_function, \
+ &spear3xx_gpio0_function, \
+ &spear3xx_i2c_function, \
+ &spear3xx_mii_function, \
+ &spear3xx_ssp_cs_function, \
+ &spear3xx_ssp_function, \
+ &spear3xx_timer_0_1_function, \
+ &spear3xx_timer_2_3_function, \
+ &spear3xx_uart0_ext_function, \
+ &spear3xx_uart0_function
+
+extern struct spear_pinctrl_machdata spear3xx_machdata;
+
+#endif /* __PINMUX_SPEAR3XX_H__ */
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index 6b26666b37f2..c4c1a5444b38 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -1,7 +1,7 @@
/*-*-linux-c-*-*/
/*
- Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
+ Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@just42.net>
Copyright (C) 2008 Peter Gruber <nokos@gmx.net>
Copyright (C) 2008 Tony Vroon <tony@linx.net>
Based on earlier work:
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c
index 222ccd872ac5..f5d6d379f2fb 100644
--- a/drivers/power/bq27x00_battery.c
+++ b/drivers/power/bq27x00_battery.c
@@ -451,7 +451,7 @@ static int bq27x00_battery_capacity_level(struct bq27x00_device_info *di,
}
/*
- * Return the battery Voltage in milivolts
+ * Return the battery Voltage in millivolts
* Or < 0 if something fails.
*/
static int bq27x00_battery_voltage(struct bq27x00_device_info *di,
diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c
index a409fa050a1a..93d0a8b7718a 100644
--- a/drivers/ps3/ps3av.c
+++ b/drivers/ps3/ps3av.c
@@ -338,7 +338,7 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size,
mutex_unlock(&ps3av->mutex);
return 0;
- err:
+err:
mutex_unlock(&ps3av->mutex);
printk(KERN_ERR "%s: failed cid:%x res:%d\n", __func__, cid, res);
return res;
@@ -477,7 +477,6 @@ int ps3av_set_audio_mode(u32 ch, u32 fs, u32 word_bits, u32 format, u32 source)
return 0;
}
-
EXPORT_SYMBOL_GPL(ps3av_set_audio_mode);
static int ps3av_set_videomode(void)
@@ -501,7 +500,7 @@ static void ps3av_set_videomode_packet(u32 id)
video_mode = &video_mode_table[id & PS3AV_MODE_MASK];
- avb_param.num_of_video_pkt = PS3AV_AVB_NUM_VIDEO; /* num of head */
+ avb_param.num_of_video_pkt = PS3AV_AVB_NUM_VIDEO; /* num of head */
avb_param.num_of_audio_pkt = 0;
avb_param.num_of_av_video_pkt = ps3av->av_hw_conf.num_of_hdmi +
ps3av->av_hw_conf.num_of_avmulti;
@@ -521,7 +520,7 @@ static void ps3av_set_videomode_packet(u32 id)
#ifndef PS3AV_HDMI_YUV
if (ps3av->av_port[i] == PS3AV_CMD_AVPORT_HDMI_0 ||
ps3av->av_port[i] == PS3AV_CMD_AVPORT_HDMI_1)
- av_video_cs = RGB8; /* use RGB for HDMI */
+ av_video_cs = RGB8; /* use RGB for HDMI */
#endif
len += ps3av_cmd_set_av_video_cs(&avb_param.buf[len],
ps3av->av_port[i],
@@ -590,8 +589,8 @@ static void ps3avd(struct work_struct *work)
#define SHIFT_VESA 8
static const struct {
- unsigned mask : 19;
- unsigned id : 4;
+ unsigned mask:19;
+ unsigned id:4;
} ps3av_preferred_modes[] = {
{ PS3AV_RESBIT_WUXGA << SHIFT_VESA, PS3AV_MODE_WUXGA },
{ PS3AV_RESBIT_1920x1080P << SHIFT_60, PS3AV_MODE_1080P60 },
@@ -667,7 +666,8 @@ static enum ps3av_mode_num ps3av_hdmi_get_id(struct ps3av_info_monitor *info)
return id;
}
-static void ps3av_monitor_info_dump(const struct ps3av_pkt_av_get_monitor_info *monitor_info)
+static void ps3av_monitor_info_dump(
+ const struct ps3av_pkt_av_get_monitor_info *monitor_info)
{
const struct ps3av_info_monitor *info = &monitor_info->info;
const struct ps3av_info_audio *audio = info->audio;
@@ -717,8 +717,8 @@ static void ps3av_monitor_info_dump(const struct ps3av_pkt_av_get_monitor_info *
/* audio block */
for (i = 0; i < info->num_of_audio_block; i++) {
- pr_debug("audio[%d] type: %02x max_ch: %02x fs: %02x sbit: "
- "%02x\n",
+ pr_debug(
+ "audio[%d] type: %02x max_ch: %02x fs: %02x sbit: %02x\n",
i, audio->type, audio->max_num_of_ch, audio->fs,
audio->sbit);
audio++;
@@ -870,21 +870,18 @@ int ps3av_set_video_mode(int id)
return 0;
}
-
EXPORT_SYMBOL_GPL(ps3av_set_video_mode);
int ps3av_get_auto_mode(void)
{
return ps3av_auto_videomode(&ps3av->av_hw_conf);
}
-
EXPORT_SYMBOL_GPL(ps3av_get_auto_mode);
int ps3av_get_mode(void)
{
return ps3av ? ps3av->ps3av_mode : 0;
}
-
EXPORT_SYMBOL_GPL(ps3av_get_mode);
/* get resolution by video_mode */
@@ -902,7 +899,6 @@ int ps3av_video_mode2res(u32 id, u32 *xres, u32 *yres)
*yres = video_mode_table[id].y;
return 0;
}
-
EXPORT_SYMBOL_GPL(ps3av_video_mode2res);
/* mute */
@@ -911,7 +907,6 @@ int ps3av_video_mute(int mute)
return ps3av_set_av_video_mute(mute ? PS3AV_CMD_MUTE_ON
: PS3AV_CMD_MUTE_OFF);
}
-
EXPORT_SYMBOL_GPL(ps3av_video_mute);
/* mute analog output only */
@@ -935,7 +930,6 @@ int ps3av_audio_mute(int mute)
return ps3av_set_audio_mute(mute ? PS3AV_CMD_MUTE_ON
: PS3AV_CMD_MUTE_OFF);
}
-
EXPORT_SYMBOL_GPL(ps3av_audio_mute);
static int __devinit ps3av_probe(struct ps3_system_bus_device *dev)
diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
index 5648dad71fb3..ffdf712f9a67 100644
--- a/drivers/ptp/Kconfig
+++ b/drivers/ptp/Kconfig
@@ -70,7 +70,7 @@ config DP83640_PHY
using the SO_TIMESTAMPING API.
In order for this to work, your MAC driver must also
- implement the skb_tx_timetamp() function.
+ implement the skb_tx_timestamp() function.
config PTP_1588_CLOCK_PCH
tristate "Intel PCH EG20T as PTP clock"
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c
index 8dc3d9392bfa..4e01a423471b 100644
--- a/drivers/regulator/tps65910-regulator.c
+++ b/drivers/regulator/tps65910-regulator.c
@@ -31,54 +31,54 @@
TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3 | \
TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP)
-/* supported VIO voltages in milivolts */
+/* supported VIO voltages in millivolts */
static const u16 VIO_VSEL_table[] = {
1500, 1800, 2500, 3300,
};
/* VSEL tables for TPS65910 specific LDOs and dcdc's */
-/* supported VDD3 voltages in milivolts */
+/* supported VDD3 voltages in millivolts */
static const u16 VDD3_VSEL_table[] = {
5000,
};
-/* supported VDIG1 voltages in milivolts */
+/* supported VDIG1 voltages in millivolts */
static const u16 VDIG1_VSEL_table[] = {
1200, 1500, 1800, 2700,
};
-/* supported VDIG2 voltages in milivolts */
+/* supported VDIG2 voltages in millivolts */
static const u16 VDIG2_VSEL_table[] = {
1000, 1100, 1200, 1800,
};
-/* supported VPLL voltages in milivolts */
+/* supported VPLL voltages in millivolts */
static const u16 VPLL_VSEL_table[] = {
1000, 1100, 1800, 2500,
};
-/* supported VDAC voltages in milivolts */
+/* supported VDAC voltages in millivolts */
static const u16 VDAC_VSEL_table[] = {
1800, 2600, 2800, 2850,
};
-/* supported VAUX1 voltages in milivolts */
+/* supported VAUX1 voltages in millivolts */
static const u16 VAUX1_VSEL_table[] = {
1800, 2500, 2800, 2850,
};
-/* supported VAUX2 voltages in milivolts */
+/* supported VAUX2 voltages in millivolts */
static const u16 VAUX2_VSEL_table[] = {
1800, 2800, 2900, 3300,
};
-/* supported VAUX33 voltages in milivolts */
+/* supported VAUX33 voltages in millivolts */
static const u16 VAUX33_VSEL_table[] = {
1800, 2000, 2800, 3300,
};
-/* supported VMMC voltages in milivolts */
+/* supported VMMC voltages in millivolts */
static const u16 VMMC_VSEL_table[] = {
1800, 2800, 3000, 3300,
};
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index e756a0df3664..d6f8adaa26ef 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -1105,8 +1105,7 @@ static void rproc_fw_config_virtio(const struct firmware *fw, void *context)
goto out;
out:
- if (fw)
- release_firmware(fw);
+ release_firmware(fw);
/* allow rproc_unregister() contexts, if any, to proceed */
complete_all(&rproc->firmware_loading_complete);
}
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 8c8377d50c4c..4161bfe462cd 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -838,7 +838,7 @@ config RTC_DRV_AT32AP700X
config RTC_DRV_AT91RM9200
tristate "AT91RM9200 or some AT91SAM9 RTC"
- depends on ARCH_AT91RM9200 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
+ depends on ARCH_AT91
help
Driver for the internal RTC (Realtime Clock) module found on
Atmel AT91RM9200's and some AT91SAM9 chips. On AT91SAM9 chips
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 4f9f1dcc1551..6c0116d48c74 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -20,6 +20,7 @@
#include <linux/interrupt.h>
#include <linux/err.h>
#include <linux/reboot.h>
+#include <linux/serial.h> /* ASYNC_* flags */
#include <linux/slab.h>
#include <asm/ccwdev.h>
#include <asm/cio.h>
@@ -44,14 +45,11 @@
#define RAW3215_TIMEOUT HZ/10 /* time for delayed output */
#define RAW3215_FIXED 1 /* 3215 console device is not be freed */
-#define RAW3215_ACTIVE 2 /* set if the device is in use */
#define RAW3215_WORKING 4 /* set if a request is being worked on */
#define RAW3215_THROTTLED 8 /* set if reading is disabled */
#define RAW3215_STOPPED 16 /* set if writing is disabled */
-#define RAW3215_CLOSING 32 /* set while in close process */
#define RAW3215_TIMER_RUNS 64 /* set if the output delay timer is on */
#define RAW3215_FLUSHING 128 /* set to flush buffer (no delay) */
-#define RAW3215_FROZEN 256 /* set if 3215 is frozen for suspend */
#define TAB_STOP_SIZE 8 /* tab stop size */
@@ -76,6 +74,7 @@ struct raw3215_req {
} __attribute__ ((aligned(8)));
struct raw3215_info {
+ struct tty_port port;
struct ccw_device *cdev; /* device for tty driver */
spinlock_t *lock; /* pointer to irq lock */
int flags; /* state flags */
@@ -84,7 +83,6 @@ struct raw3215_info {
int head; /* first free byte in output buffer */
int count; /* number of bytes in output buffer */
int written; /* number of bytes in write requests */
- struct tty_struct *tty; /* pointer to tty structure if present */
struct raw3215_req *queued_read; /* pointer to queued read requests */
struct raw3215_req *queued_write;/* pointer to queued write requests */
struct tasklet_struct tlet; /* tasklet to invoke tty_wakeup */
@@ -293,7 +291,7 @@ static void raw3215_timeout(unsigned long __data)
if (raw->flags & RAW3215_TIMER_RUNS) {
del_timer(&raw->timer);
raw->flags &= ~RAW3215_TIMER_RUNS;
- if (!(raw->flags & RAW3215_FROZEN)) {
+ if (!(raw->port.flags & ASYNC_SUSPENDED)) {
raw3215_mk_write_req(raw);
raw3215_start_io(raw);
}
@@ -309,7 +307,8 @@ static void raw3215_timeout(unsigned long __data)
*/
static inline void raw3215_try_io(struct raw3215_info *raw)
{
- if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FROZEN))
+ if (!(raw->port.flags & ASYNC_INITIALIZED) ||
+ (raw->port.flags & ASYNC_SUSPENDED))
return;
if (raw->queued_read != NULL)
raw3215_start_io(raw);
@@ -324,10 +323,7 @@ static inline void raw3215_try_io(struct raw3215_info *raw)
}
} else if (!(raw->flags & RAW3215_TIMER_RUNS)) {
/* delay small writes */
- init_timer(&raw->timer);
raw->timer.expires = RAW3215_TIMEOUT + jiffies;
- raw->timer.data = (unsigned long) raw;
- raw->timer.function = raw3215_timeout;
add_timer(&raw->timer);
raw->flags |= RAW3215_TIMER_RUNS;
}
@@ -340,17 +336,21 @@ static inline void raw3215_try_io(struct raw3215_info *raw)
static void raw3215_wakeup(unsigned long data)
{
struct raw3215_info *raw = (struct raw3215_info *) data;
- tty_wakeup(raw->tty);
+ struct tty_struct *tty;
+
+ tty = tty_port_tty_get(&raw->port);
+ tty_wakeup(tty);
+ tty_kref_put(tty);
}
/*
* Try to start the next IO and wake up processes waiting on the tty.
*/
-static void raw3215_next_io(struct raw3215_info *raw)
+static void raw3215_next_io(struct raw3215_info *raw, struct tty_struct *tty)
{
raw3215_mk_write_req(raw);
raw3215_try_io(raw);
- if (raw->tty && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE)
+ if (tty && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE)
tasklet_schedule(&raw->tlet);
}
@@ -368,10 +368,11 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
raw = dev_get_drvdata(&cdev->dev);
req = (struct raw3215_req *) intparm;
+ tty = tty_port_tty_get(&raw->port);
cstat = irb->scsw.cmd.cstat;
dstat = irb->scsw.cmd.dstat;
if (cstat != 0)
- raw3215_next_io(raw);
+ raw3215_next_io(raw, tty);
if (dstat & 0x01) { /* we got a unit exception */
dstat &= ~0x01; /* we can ignore it */
}
@@ -381,13 +382,13 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
break;
/* Attention interrupt, someone hit the enter key */
raw3215_mk_read_req(raw);
- raw3215_next_io(raw);
+ raw3215_next_io(raw, tty);
break;
case 0x08:
case 0x0C:
/* Channel end interrupt. */
if ((raw = req->info) == NULL)
- return; /* That shouldn't happen ... */
+ goto put_tty; /* That shouldn't happen ... */
if (req->type == RAW3215_READ) {
/* store residual count, then wait for device end */
req->residual = irb->scsw.cmd.count;
@@ -397,11 +398,10 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
case 0x04:
/* Device end interrupt. */
if ((raw = req->info) == NULL)
- return; /* That shouldn't happen ... */
- if (req->type == RAW3215_READ && raw->tty != NULL) {
+ goto put_tty; /* That shouldn't happen ... */
+ if (req->type == RAW3215_READ && tty != NULL) {
unsigned int cchar;
- tty = raw->tty;
count = 160 - req->residual;
EBCASC(raw->inbuf, count);
cchar = ctrlchar_handle(raw->inbuf, count, tty);
@@ -411,7 +411,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
case CTRLCHAR_CTRL:
tty_insert_flip_char(tty, cchar, TTY_NORMAL);
- tty_flip_buffer_push(raw->tty);
+ tty_flip_buffer_push(tty);
break;
case CTRLCHAR_NONE:
@@ -424,7 +424,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
} else
count -= 2;
tty_insert_flip_string(tty, raw->inbuf, count);
- tty_flip_buffer_push(raw->tty);
+ tty_flip_buffer_push(tty);
break;
}
} else if (req->type == RAW3215_WRITE) {
@@ -439,7 +439,7 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
raw->queued_read == NULL) {
wake_up_interruptible(&raw->empty_wait);
}
- raw3215_next_io(raw);
+ raw3215_next_io(raw, tty);
break;
default:
/* Strange interrupt, I'll do my best to clean up */
@@ -451,9 +451,10 @@ static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
raw->flags &= ~RAW3215_WORKING;
raw3215_free_req(req);
}
- raw3215_next_io(raw);
+ raw3215_next_io(raw, tty);
}
- return;
+put_tty:
+ tty_kref_put(tty);
}
/*
@@ -487,7 +488,7 @@ static void raw3215_make_room(struct raw3215_info *raw, unsigned int length)
/* While console is frozen for suspend we have no other
* choice but to drop message from the buffer to make
* room for even more messages. */
- if (raw->flags & RAW3215_FROZEN) {
+ if (raw->port.flags & ASYNC_SUSPENDED) {
raw3215_drop_line(raw);
continue;
}
@@ -609,10 +610,10 @@ static int raw3215_startup(struct raw3215_info *raw)
{
unsigned long flags;
- if (raw->flags & RAW3215_ACTIVE)
+ if (raw->port.flags & ASYNC_INITIALIZED)
return 0;
raw->line_pos = 0;
- raw->flags |= RAW3215_ACTIVE;
+ raw->port.flags |= ASYNC_INITIALIZED;
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
raw3215_try_io(raw);
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
@@ -628,14 +629,15 @@ static void raw3215_shutdown(struct raw3215_info *raw)
DECLARE_WAITQUEUE(wait, current);
unsigned long flags;
- if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FIXED))
+ if (!(raw->port.flags & ASYNC_INITIALIZED) ||
+ (raw->flags & RAW3215_FIXED))
return;
/* Wait for outstanding requests, then free irq */
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
if ((raw->flags & RAW3215_WORKING) ||
raw->queued_write != NULL ||
raw->queued_read != NULL) {
- raw->flags |= RAW3215_CLOSING;
+ raw->port.flags |= ASYNC_CLOSING;
add_wait_queue(&raw->empty_wait, &wait);
set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
@@ -643,11 +645,41 @@ static void raw3215_shutdown(struct raw3215_info *raw)
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
remove_wait_queue(&raw->empty_wait, &wait);
set_current_state(TASK_RUNNING);
- raw->flags &= ~(RAW3215_ACTIVE | RAW3215_CLOSING);
+ raw->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING);
}
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
}
+static struct raw3215_info *raw3215_alloc_info(void)
+{
+ struct raw3215_info *info;
+
+ info = kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA);
+ if (!info)
+ return NULL;
+
+ info->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
+ info->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA);
+ if (!info->buffer || !info->inbuf) {
+ kfree(info);
+ return NULL;
+ }
+
+ setup_timer(&info->timer, raw3215_timeout, (unsigned long)info);
+ init_waitqueue_head(&info->empty_wait);
+ tasklet_init(&info->tlet, raw3215_wakeup, (unsigned long)info);
+ tty_port_init(&info->port);
+
+ return info;
+}
+
+static void raw3215_free_info(struct raw3215_info *raw)
+{
+ kfree(raw->inbuf);
+ kfree(raw->buffer);
+ kfree(raw);
+}
+
static int raw3215_probe (struct ccw_device *cdev)
{
struct raw3215_info *raw;
@@ -656,11 +688,15 @@ static int raw3215_probe (struct ccw_device *cdev)
/* Console is special. */
if (raw3215[0] && (raw3215[0] == dev_get_drvdata(&cdev->dev)))
return 0;
- raw = kmalloc(sizeof(struct raw3215_info) +
- RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA);
+
+ raw = raw3215_alloc_info();
if (raw == NULL)
return -ENOMEM;
+ raw->cdev = cdev;
+ dev_set_drvdata(&cdev->dev, raw);
+ cdev->handler = raw3215_irq;
+
spin_lock(&raw3215_device_lock);
for (line = 0; line < NR_3215; line++) {
if (!raw3215[line]) {
@@ -670,28 +706,10 @@ static int raw3215_probe (struct ccw_device *cdev)
}
spin_unlock(&raw3215_device_lock);
if (line == NR_3215) {
- kfree(raw);
+ raw3215_free_info(raw);
return -ENODEV;
}
- raw->cdev = cdev;
- raw->inbuf = (char *) raw + sizeof(struct raw3215_info);
- memset(raw, 0, sizeof(struct raw3215_info));
- raw->buffer = kmalloc(RAW3215_BUFFER_SIZE,
- GFP_KERNEL|GFP_DMA);
- if (raw->buffer == NULL) {
- spin_lock(&raw3215_device_lock);
- raw3215[line] = NULL;
- spin_unlock(&raw3215_device_lock);
- kfree(raw);
- return -ENOMEM;
- }
- init_waitqueue_head(&raw->empty_wait);
- tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);
-
- dev_set_drvdata(&cdev->dev, raw);
- cdev->handler = raw3215_irq;
-
return 0;
}
@@ -703,8 +721,7 @@ static void raw3215_remove (struct ccw_device *cdev)
raw = dev_get_drvdata(&cdev->dev);
if (raw) {
dev_set_drvdata(&cdev->dev, NULL);
- kfree(raw->buffer);
- kfree(raw);
+ raw3215_free_info(raw);
}
}
@@ -741,7 +758,7 @@ static int raw3215_pm_stop(struct ccw_device *cdev)
raw = dev_get_drvdata(&cdev->dev);
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
raw3215_make_room(raw, RAW3215_BUFFER_SIZE);
- raw->flags |= RAW3215_FROZEN;
+ raw->port.flags |= ASYNC_SUSPENDED;
spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags);
return 0;
}
@@ -754,7 +771,7 @@ static int raw3215_pm_start(struct ccw_device *cdev)
/* Allow I/O again and flush output buffer. */
raw = dev_get_drvdata(&cdev->dev);
spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags);
- raw->flags &= ~RAW3215_FROZEN;
+ raw->port.flags &= ~ASYNC_SUSPENDED;
raw->flags |= RAW3215_FLUSHING;
raw3215_try_io(raw);
raw->flags &= ~RAW3215_FLUSHING;
@@ -827,7 +844,7 @@ static void con3215_flush(void)
unsigned long flags;
raw = raw3215[0]; /* console 3215 is the first one */
- if (raw->flags & RAW3215_FROZEN)
+ if (raw->port.flags & ASYNC_SUSPENDED)
/* The console is still frozen for suspend. */
if (ccw_device_force_console())
/* Forcing didn't work, no panic message .. */
@@ -897,23 +914,16 @@ static int __init con3215_init(void)
if (IS_ERR(cdev))
return -ENODEV;
- raw3215[0] = raw = (struct raw3215_info *)
- kzalloc(sizeof(struct raw3215_info), GFP_KERNEL | GFP_DMA);
- raw->buffer = kzalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
- raw->inbuf = kzalloc(RAW3215_INBUF_SIZE, GFP_KERNEL | GFP_DMA);
+ raw3215[0] = raw = raw3215_alloc_info();
raw->cdev = cdev;
dev_set_drvdata(&cdev->dev, raw);
cdev->handler = raw3215_irq;
raw->flags |= RAW3215_FIXED;
- init_waitqueue_head(&raw->empty_wait);
- tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);
/* Request the console irq */
if (raw3215_startup(raw) != 0) {
- kfree(raw->inbuf);
- kfree(raw->buffer);
- kfree(raw);
+ raw3215_free_info(raw);
raw3215[0] = NULL;
return -ENODEV;
}
@@ -940,7 +950,7 @@ static int tty3215_open(struct tty_struct *tty, struct file * filp)
return -ENODEV;
tty->driver_data = raw;
- raw->tty = tty;
+ tty_port_tty_set(&raw->port, tty);
tty->low_latency = 0; /* don't use bottom half for pushing chars */
/*
@@ -971,7 +981,7 @@ static void tty3215_close(struct tty_struct *tty, struct file * filp)
raw3215_shutdown(raw);
tasklet_kill(&raw->tlet);
tty->closing = 0;
- raw->tty = NULL;
+ tty_port_tty_set(&raw->port, NULL);
}
/*
diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c
index 806588192483..7ef9cfdc17d8 100644
--- a/drivers/s390/char/keyboard.c
+++ b/drivers/s390/char/keyboard.c
@@ -199,7 +199,7 @@ handle_diacr(struct kbd_data *kbd, unsigned int ch)
if (ch == ' ' || ch == d)
return d;
- kbd_put_queue(kbd->tty, d);
+ kbd_put_queue(kbd->port, d);
return ch;
}
@@ -221,7 +221,7 @@ k_self(struct kbd_data *kbd, unsigned char value)
{
if (kbd->diacr)
value = handle_diacr(kbd, value);
- kbd_put_queue(kbd->tty, value);
+ kbd_put_queue(kbd->port, value);
}
/*
@@ -239,7 +239,7 @@ static void
k_fn(struct kbd_data *kbd, unsigned char value)
{
if (kbd->func_table[value])
- kbd_puts_queue(kbd->tty, kbd->func_table[value]);
+ kbd_puts_queue(kbd->port, kbd->func_table[value]);
}
static void
@@ -257,20 +257,20 @@ k_spec(struct kbd_data *kbd, unsigned char value)
* but we need only 16 bits here
*/
static void
-to_utf8(struct tty_struct *tty, ushort c)
+to_utf8(struct tty_port *port, ushort c)
{
if (c < 0x80)
/* 0******* */
- kbd_put_queue(tty, c);
+ kbd_put_queue(port, c);
else if (c < 0x800) {
/* 110***** 10****** */
- kbd_put_queue(tty, 0xc0 | (c >> 6));
- kbd_put_queue(tty, 0x80 | (c & 0x3f));
+ kbd_put_queue(port, 0xc0 | (c >> 6));
+ kbd_put_queue(port, 0x80 | (c & 0x3f));
} else {
/* 1110**** 10****** 10****** */
- kbd_put_queue(tty, 0xe0 | (c >> 12));
- kbd_put_queue(tty, 0x80 | ((c >> 6) & 0x3f));
- kbd_put_queue(tty, 0x80 | (c & 0x3f));
+ kbd_put_queue(port, 0xe0 | (c >> 12));
+ kbd_put_queue(port, 0x80 | ((c >> 6) & 0x3f));
+ kbd_put_queue(port, 0x80 | (c & 0x3f));
}
}
@@ -283,7 +283,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode)
unsigned short keysym;
unsigned char type, value;
- if (!kbd || !kbd->tty)
+ if (!kbd)
return;
if (keycode >= 384)
@@ -323,7 +323,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode)
#endif
(*k_handler[type])(kbd, value);
} else
- to_utf8(kbd->tty, keysym);
+ to_utf8(kbd->port, keysym);
}
/*
@@ -457,6 +457,7 @@ do_kdgkb_ioctl(struct kbd_data *kbd, struct kbsentry __user *u_kbs,
int kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg)
{
+ struct tty_struct *tty;
void __user *argp;
unsigned int ct;
int perm;
@@ -467,7 +468,10 @@ int kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg)
* To have permissions to do most of the vt ioctls, we either have
* to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
*/
- perm = current->signal->tty == kbd->tty || capable(CAP_SYS_TTY_CONFIG);
+ tty = tty_port_tty_get(kbd->port);
+ /* FIXME this test is pretty racy */
+ perm = current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG);
+ tty_kref_put(tty);
switch (cmd) {
case KDGKBTYPE:
return put_user(KB_101, (char __user *)argp);
diff --git a/drivers/s390/char/keyboard.h b/drivers/s390/char/keyboard.h
index 7e736aaeae6e..f682f4e49680 100644
--- a/drivers/s390/char/keyboard.h
+++ b/drivers/s390/char/keyboard.h
@@ -21,7 +21,7 @@ typedef void (fn_handler_fn)(struct kbd_data *);
*/
struct kbd_data {
- struct tty_struct *tty;
+ struct tty_port *port;
unsigned short **key_maps;
char **func_table;
fn_handler_fn **fn_handler;
@@ -42,16 +42,24 @@ int kbd_ioctl(struct kbd_data *, unsigned int, unsigned long);
* Helper Functions.
*/
static inline void
-kbd_put_queue(struct tty_struct *tty, int ch)
+kbd_put_queue(struct tty_port *port, int ch)
{
+ struct tty_struct *tty = tty_port_tty_get(port);
+ if (!tty)
+ return;
tty_insert_flip_char(tty, ch, 0);
tty_schedule_flip(tty);
+ tty_kref_put(tty);
}
static inline void
-kbd_puts_queue(struct tty_struct *tty, char *cp)
+kbd_puts_queue(struct tty_port *port, char *cp)
{
+ struct tty_struct *tty = tty_port_tty_get(port);
+ if (!tty)
+ return;
while (*cp)
tty_insert_flip_char(tty, *cp++, 0);
tty_schedule_flip(tty);
+ tty_kref_put(tty);
}
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
index 40a9d69c898e..e66a75b3822c 100644
--- a/drivers/s390/char/sclp_tty.c
+++ b/drivers/s390/char/sclp_tty.c
@@ -48,7 +48,7 @@ static struct sclp_buffer *sclp_ttybuf;
/* Timer for delayed output of console messages. */
static struct timer_list sclp_tty_timer;
-static struct tty_struct *sclp_tty;
+static struct tty_port sclp_port;
static unsigned char sclp_tty_chars[SCLP_TTY_BUF_SIZE];
static unsigned short int sclp_tty_chars_count;
@@ -64,7 +64,7 @@ static int sclp_tty_columns = 80;
static int
sclp_tty_open(struct tty_struct *tty, struct file *filp)
{
- sclp_tty = tty;
+ tty_port_tty_set(&sclp_port, tty);
tty->driver_data = NULL;
tty->low_latency = 0;
return 0;
@@ -76,7 +76,7 @@ sclp_tty_close(struct tty_struct *tty, struct file *filp)
{
if (tty->count > 1)
return;
- sclp_tty = NULL;
+ tty_port_tty_set(&sclp_port, NULL);
}
/*
@@ -108,6 +108,7 @@ sclp_tty_write_room (struct tty_struct *tty)
static void
sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
{
+ struct tty_struct *tty;
unsigned long flags;
void *page;
@@ -126,8 +127,10 @@ sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
spin_unlock_irqrestore(&sclp_tty_lock, flags);
} while (buffer && sclp_emit_buffer(buffer, sclp_ttybuf_callback));
/* check if the tty needs a wake up call */
- if (sclp_tty != NULL) {
- tty_wakeup(sclp_tty);
+ tty = tty_port_tty_get(&sclp_port);
+ if (tty != NULL) {
+ tty_wakeup(tty);
+ tty_kref_put(tty);
}
}
@@ -326,21 +329,22 @@ sclp_tty_flush_buffer(struct tty_struct *tty)
static void
sclp_tty_input(unsigned char* buf, unsigned int count)
{
+ struct tty_struct *tty = tty_port_tty_get(&sclp_port);
unsigned int cchar;
/*
* If this tty driver is currently closed
* then throw the received input away.
*/
- if (sclp_tty == NULL)
+ if (tty == NULL)
return;
- cchar = ctrlchar_handle(buf, count, sclp_tty);
+ cchar = ctrlchar_handle(buf, count, tty);
switch (cchar & CTRLCHAR_MASK) {
case CTRLCHAR_SYSRQ:
break;
case CTRLCHAR_CTRL:
- tty_insert_flip_char(sclp_tty, cchar, TTY_NORMAL);
- tty_flip_buffer_push(sclp_tty);
+ tty_insert_flip_char(tty, cchar, TTY_NORMAL);
+ tty_flip_buffer_push(tty);
break;
case CTRLCHAR_NONE:
/* send (normal) input to line discipline */
@@ -348,13 +352,14 @@ sclp_tty_input(unsigned char* buf, unsigned int count)
(strncmp((const char *) buf + count - 2, "^n", 2) &&
strncmp((const char *) buf + count - 2, "\252n", 2))) {
/* add the auto \n */
- tty_insert_flip_string(sclp_tty, buf, count);
- tty_insert_flip_char(sclp_tty, '\n', TTY_NORMAL);
+ tty_insert_flip_string(tty, buf, count);
+ tty_insert_flip_char(tty, '\n', TTY_NORMAL);
} else
- tty_insert_flip_string(sclp_tty, buf, count - 2);
- tty_flip_buffer_push(sclp_tty);
+ tty_insert_flip_string(tty, buf, count - 2);
+ tty_flip_buffer_push(tty);
break;
}
+ tty_kref_put(tty);
}
/*
@@ -543,7 +548,7 @@ sclp_tty_init(void)
sclp_tty_tolower = 1;
}
sclp_tty_chars_count = 0;
- sclp_tty = NULL;
+ tty_port_init(&sclp_port);
rc = sclp_register(&sclp_input_event);
if (rc) {
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index b635472ae660..edfc0fd73dc6 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -34,7 +34,6 @@
#define SCLP_VT220_DEVICE_NAME "ttysclp"
#define SCLP_VT220_CONSOLE_NAME "ttyS"
#define SCLP_VT220_CONSOLE_INDEX 1 /* console=ttyS1 */
-#define SCLP_VT220_BUF_SIZE 80
/* Representation of a single write request */
struct sclp_vt220_request {
@@ -56,8 +55,7 @@ struct sclp_vt220_sccb {
/* Structures and data needed to register tty driver */
static struct tty_driver *sclp_vt220_driver;
-/* The tty_struct that the kernel associated with us */
-static struct tty_struct *sclp_vt220_tty;
+static struct tty_port sclp_vt220_port;
/* Lock to protect internal data from concurrent access */
static spinlock_t sclp_vt220_lock;
@@ -116,6 +114,7 @@ static struct sclp_register sclp_vt220_register = {
static void
sclp_vt220_process_queue(struct sclp_vt220_request *request)
{
+ struct tty_struct *tty;
unsigned long flags;
void *page;
@@ -141,8 +140,10 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request)
if (request == NULL && sclp_vt220_flush_later)
sclp_vt220_emit_current();
/* Check if the tty needs a wake up call */
- if (sclp_vt220_tty != NULL) {
- tty_wakeup(sclp_vt220_tty);
+ tty = tty_port_tty_get(&sclp_vt220_port);
+ if (tty) {
+ tty_wakeup(tty);
+ tty_kref_put(tty);
}
}
@@ -460,11 +461,12 @@ sclp_vt220_write(struct tty_struct *tty, const unsigned char *buf, int count)
static void
sclp_vt220_receiver_fn(struct evbuf_header *evbuf)
{
+ struct tty_struct *tty = tty_port_tty_get(&sclp_vt220_port);
char *buffer;
unsigned int count;
/* Ignore input if device is not open */
- if (sclp_vt220_tty == NULL)
+ if (tty == NULL)
return;
buffer = (char *) ((addr_t) evbuf + sizeof(struct evbuf_header));
@@ -478,10 +480,11 @@ sclp_vt220_receiver_fn(struct evbuf_header *evbuf)
/* Send input to line discipline */
buffer++;
count--;
- tty_insert_flip_string(sclp_vt220_tty, buffer, count);
- tty_flip_buffer_push(sclp_vt220_tty);
+ tty_insert_flip_string(tty, buffer, count);
+ tty_flip_buffer_push(tty);
break;
}
+ tty_kref_put(tty);
}
/*
@@ -491,10 +494,7 @@ static int
sclp_vt220_open(struct tty_struct *tty, struct file *filp)
{
if (tty->count == 1) {
- sclp_vt220_tty = tty;
- tty->driver_data = kmalloc(SCLP_VT220_BUF_SIZE, GFP_KERNEL);
- if (tty->driver_data == NULL)
- return -ENOMEM;
+ tty_port_tty_set(&sclp_vt220_port, tty);
tty->low_latency = 0;
if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
tty->winsize.ws_row = 24;
@@ -510,11 +510,8 @@ sclp_vt220_open(struct tty_struct *tty, struct file *filp)
static void
sclp_vt220_close(struct tty_struct *tty, struct file *filp)
{
- if (tty->count == 1) {
- sclp_vt220_tty = NULL;
- kfree(tty->driver_data);
- tty->driver_data = NULL;
- }
+ if (tty->count == 1)
+ tty_port_tty_set(&sclp_vt220_port, NULL);
}
/*
@@ -635,9 +632,9 @@ static int __init __sclp_vt220_init(int num_pages)
INIT_LIST_HEAD(&sclp_vt220_empty);
INIT_LIST_HEAD(&sclp_vt220_outqueue);
init_timer(&sclp_vt220_timer);
+ tty_port_init(&sclp_vt220_port);
sclp_vt220_current_request = NULL;
sclp_vt220_buffered_chars = 0;
- sclp_vt220_tty = NULL;
sclp_vt220_flush_later = 0;
/* Allocate pages for output buffering */
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index b43445a55cb6..10ec690197cb 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -61,7 +61,7 @@ struct tty3270_line {
*/
struct tty3270 {
struct raw3270_view view;
- struct tty_struct *tty; /* Pointer to tty structure */
+ struct tty_port port;
void **freemem_pages; /* Array of pages used for freemem. */
struct list_head freemem; /* List of free memory for strings. */
@@ -324,9 +324,8 @@ tty3270_blank_line(struct tty3270 *tp)
static void
tty3270_write_callback(struct raw3270_request *rq, void *data)
{
- struct tty3270 *tp;
+ struct tty3270 *tp = container_of(rq->view, struct tty3270, view);
- tp = (struct tty3270 *) rq->view;
if (rq->rc != 0) {
/* Write wasn't successful. Refresh all. */
tp->update_flags = TTY_UPDATE_ALL;
@@ -450,10 +449,9 @@ tty3270_rcl_add(struct tty3270 *tp, char *input, int len)
static void
tty3270_rcl_backward(struct kbd_data *kbd)
{
- struct tty3270 *tp;
+ struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
struct string *s;
- tp = kbd->tty->driver_data;
spin_lock_bh(&tp->view.lock);
if (tp->inattr == TF_INPUT) {
if (tp->rcl_walk && tp->rcl_walk->prev != &tp->rcl_lines)
@@ -478,9 +476,8 @@ tty3270_rcl_backward(struct kbd_data *kbd)
static void
tty3270_exit_tty(struct kbd_data *kbd)
{
- struct tty3270 *tp;
+ struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
- tp = kbd->tty->driver_data;
raw3270_deactivate_view(&tp->view);
}
@@ -490,10 +487,9 @@ tty3270_exit_tty(struct kbd_data *kbd)
static void
tty3270_scroll_forward(struct kbd_data *kbd)
{
- struct tty3270 *tp;
+ struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
int nr_up;
- tp = kbd->tty->driver_data;
spin_lock_bh(&tp->view.lock);
nr_up = tp->nr_up - tp->view.rows + 2;
if (nr_up < 0)
@@ -513,10 +509,9 @@ tty3270_scroll_forward(struct kbd_data *kbd)
static void
tty3270_scroll_backward(struct kbd_data *kbd)
{
- struct tty3270 *tp;
+ struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
int nr_up;
- tp = kbd->tty->driver_data;
spin_lock_bh(&tp->view.lock);
nr_up = tp->nr_up + tp->view.rows - 2;
if (nr_up + tp->view.rows - 2 > tp->nr_lines)
@@ -537,11 +532,10 @@ static void
tty3270_read_tasklet(struct raw3270_request *rrq)
{
static char kreset_data = TW_KR;
- struct tty3270 *tp;
+ struct tty3270 *tp = container_of(rrq->view, struct tty3270, view);
char *input;
int len;
- tp = (struct tty3270 *) rrq->view;
spin_lock_bh(&tp->view.lock);
/*
* Two AID keys are special: For 0x7d (enter) the input line
@@ -577,13 +571,10 @@ tty3270_read_tasklet(struct raw3270_request *rrq)
raw3270_request_add_data(tp->kreset, &kreset_data, 1);
raw3270_start(&tp->view, tp->kreset);
- /* Emit input string. */
- if (tp->tty) {
- while (len-- > 0)
- kbd_keycode(tp->kbd, *input++);
- /* Emit keycode for AID byte. */
- kbd_keycode(tp->kbd, 256 + tp->input->string[0]);
- }
+ while (len-- > 0)
+ kbd_keycode(tp->kbd, *input++);
+ /* Emit keycode for AID byte. */
+ kbd_keycode(tp->kbd, 256 + tp->input->string[0]);
raw3270_request_reset(rrq);
xchg(&tp->read, rrq);
@@ -596,9 +587,10 @@ tty3270_read_tasklet(struct raw3270_request *rrq)
static void
tty3270_read_callback(struct raw3270_request *rq, void *data)
{
+ struct tty3270 *tp = container_of(rq->view, struct tty3270, view);
raw3270_get_view(rq->view);
/* Schedule tasklet to pass input to tty. */
- tasklet_schedule(&((struct tty3270 *) rq->view)->readlet);
+ tasklet_schedule(&tp->readlet);
}
/*
@@ -635,9 +627,8 @@ tty3270_issue_read(struct tty3270 *tp, int lock)
static int
tty3270_activate(struct raw3270_view *view)
{
- struct tty3270 *tp;
+ struct tty3270 *tp = container_of(view, struct tty3270, view);
- tp = (struct tty3270 *) view;
tp->update_flags = TTY_UPDATE_ALL;
tty3270_set_timer(tp, 1);
return 0;
@@ -646,9 +637,8 @@ tty3270_activate(struct raw3270_view *view)
static void
tty3270_deactivate(struct raw3270_view *view)
{
- struct tty3270 *tp;
+ struct tty3270 *tp = container_of(view, struct tty3270, view);
- tp = (struct tty3270 *) view;
del_timer(&tp->timer);
}
@@ -690,6 +680,17 @@ tty3270_alloc_view(void)
if (!tp->freemem_pages)
goto out_tp;
INIT_LIST_HEAD(&tp->freemem);
+ INIT_LIST_HEAD(&tp->lines);
+ INIT_LIST_HEAD(&tp->update);
+ INIT_LIST_HEAD(&tp->rcl_lines);
+ tp->rcl_max = 20;
+ tty_port_init(&tp->port);
+ setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update,
+ (unsigned long) tp);
+ tasklet_init(&tp->readlet,
+ (void (*)(unsigned long)) tty3270_read_tasklet,
+ (unsigned long) tp->read);
+
for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) {
tp->freemem_pages[pages] = (void *)
__get_free_pages(GFP_KERNEL|GFP_DMA, 0);
@@ -794,16 +795,15 @@ tty3270_free_screen(struct tty3270 *tp)
static void
tty3270_release(struct raw3270_view *view)
{
- struct tty3270 *tp;
- struct tty_struct *tty;
+ struct tty3270 *tp = container_of(view, struct tty3270, view);
+ struct tty_struct *tty = tty_port_tty_get(&tp->port);
- tp = (struct tty3270 *) view;
- tty = tp->tty;
if (tty) {
tty->driver_data = NULL;
- tp->tty = tp->kbd->tty = NULL;
+ tty_port_tty_set(&tp->port, NULL);
tty_hangup(tty);
raw3270_put_view(&tp->view);
+ tty_kref_put(tty);
}
}
@@ -813,8 +813,9 @@ tty3270_release(struct raw3270_view *view)
static void
tty3270_free(struct raw3270_view *view)
{
- tty3270_free_screen((struct tty3270 *) view);
- tty3270_free_view((struct tty3270 *) view);
+ struct tty3270 *tp = container_of(view, struct tty3270, view);
+ tty3270_free_screen(tp);
+ tty3270_free_view(tp);
}
/*
@@ -823,14 +824,13 @@ tty3270_free(struct raw3270_view *view)
static void
tty3270_del_views(void)
{
- struct tty3270 *tp;
int i;
for (i = 0; i < tty3270_max_index; i++) {
- tp = (struct tty3270 *)
+ struct raw3270_view *view =
raw3270_find_view(&tty3270_fn, i + RAW3270_FIRSTMINOR);
- if (!IS_ERR(tp))
- raw3270_del_view(&tp->view);
+ if (!IS_ERR(view))
+ raw3270_del_view(view);
}
}
@@ -848,22 +848,23 @@ static struct raw3270_fn tty3270_fn = {
static int
tty3270_open(struct tty_struct *tty, struct file * filp)
{
+ struct raw3270_view *view;
struct tty3270 *tp;
int i, rc;
if (tty->count > 1)
return 0;
/* Check if the tty3270 is already there. */
- tp = (struct tty3270 *)
- raw3270_find_view(&tty3270_fn,
+ view = raw3270_find_view(&tty3270_fn,
tty->index + RAW3270_FIRSTMINOR);
- if (!IS_ERR(tp)) {
+ if (!IS_ERR(view)) {
+ tp = container_of(view, struct tty3270, view);
tty->driver_data = tp;
tty->winsize.ws_row = tp->view.rows - 2;
tty->winsize.ws_col = tp->view.cols;
tty->low_latency = 0;
- tp->tty = tty;
- tp->kbd->tty = tty;
+ /* why to reassign? */
+ tty_port_tty_set(&tp->port, tty);
tp->inattr = TF_INPUT;
return 0;
}
@@ -871,7 +872,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
tty3270_max_index = tty->index + 1;
/* Quick exit if there is no device for tty->index. */
- if (PTR_ERR(tp) == -ENODEV)
+ if (PTR_ERR(view) == -ENODEV)
return -ENODEV;
/* Allocate tty3270 structure on first open. */
@@ -879,16 +880,6 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
if (IS_ERR(tp))
return PTR_ERR(tp);
- INIT_LIST_HEAD(&tp->lines);
- INIT_LIST_HEAD(&tp->update);
- INIT_LIST_HEAD(&tp->rcl_lines);
- tp->rcl_max = 20;
- setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update,
- (unsigned long) tp);
- tasklet_init(&tp->readlet,
- (void (*)(unsigned long)) tty3270_read_tasklet,
- (unsigned long) tp->read);
-
rc = raw3270_add_view(&tp->view, &tty3270_fn,
tty->index + RAW3270_FIRSTMINOR);
if (rc) {
@@ -903,7 +894,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
return rc;
}
- tp->tty = tty;
+ tty_port_tty_set(&tp->port, tty);
tty->low_latency = 0;
tty->driver_data = tp;
tty->winsize.ws_row = tp->view.rows - 2;
@@ -917,7 +908,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
for (i = 0; i < tp->view.rows - 2; i++)
tty3270_blank_line(tp);
- tp->kbd->tty = tty;
+ tp->kbd->port = &tp->port;
tp->kbd->fn_handler[KVAL(K_INCRCONSOLE)] = tty3270_exit_tty;
tp->kbd->fn_handler[KVAL(K_SCROLLBACK)] = tty3270_scroll_backward;
tp->kbd->fn_handler[KVAL(K_SCROLLFORW)] = tty3270_scroll_forward;
@@ -935,14 +926,13 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
static void
tty3270_close(struct tty_struct *tty, struct file * filp)
{
- struct tty3270 *tp;
+ struct tty3270 *tp = tty->driver_data;
if (tty->count > 1)
return;
- tp = (struct tty3270 *) tty->driver_data;
if (tp) {
tty->driver_data = NULL;
- tp->tty = tp->kbd->tty = NULL;
+ tty_port_tty_set(&tp->port, NULL);
raw3270_put_view(&tp->view);
}
}
@@ -1391,7 +1381,7 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch)
tty3270_lf(tp);
break;
case 'Z': /* Respond ID. */
- kbd_puts_queue(tp->tty, "\033[?6c");
+ kbd_puts_queue(&tp->port, "\033[?6c");
break;
case '7': /* Save cursor position. */
tp->saved_cx = tp->cx;
@@ -1437,11 +1427,11 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch)
tp->esc_state = ESnormal;
if (ch == 'n' && !tp->esc_ques) {
if (tp->esc_par[0] == 5) /* Status report. */
- kbd_puts_queue(tp->tty, "\033[0n");
+ kbd_puts_queue(&tp->port, "\033[0n");
else if (tp->esc_par[0] == 6) { /* Cursor report. */
char buf[40];
sprintf(buf, "\033[%d;%dR", tp->cy + 1, tp->cx + 1);
- kbd_puts_queue(tp->tty, buf);
+ kbd_puts_queue(&tp->port, buf);
}
return;
}
@@ -1513,12 +1503,13 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch)
* String write routine for 3270 ttys
*/
static void
-tty3270_do_write(struct tty3270 *tp, const unsigned char *buf, int count)
+tty3270_do_write(struct tty3270 *tp, struct tty_struct *tty,
+ const unsigned char *buf, int count)
{
int i_msg, i;
spin_lock_bh(&tp->view.lock);
- for (i_msg = 0; !tp->tty->stopped && i_msg < count; i_msg++) {
+ for (i_msg = 0; !tty->stopped && i_msg < count; i_msg++) {
if (tp->esc_state != 0) {
/* Continue escape sequence. */
tty3270_escape_sequence(tp, buf[i_msg]);
@@ -1595,10 +1586,10 @@ tty3270_write(struct tty_struct * tty,
if (!tp)
return 0;
if (tp->char_count > 0) {
- tty3270_do_write(tp, tp->char_buf, tp->char_count);
+ tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);
tp->char_count = 0;
}
- tty3270_do_write(tp, buf, count);
+ tty3270_do_write(tp, tty, buf, count);
return count;
}
@@ -1629,7 +1620,7 @@ tty3270_flush_chars(struct tty_struct *tty)
if (!tp)
return;
if (tp->char_count > 0) {
- tty3270_do_write(tp, tp->char_buf, tp->char_count);
+ tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);
tp->char_count = 0;
}
}
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index bea04e5d3b51..e9559782d3ec 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -808,19 +808,6 @@ config SCSI_FUTURE_DOMAIN
To compile this driver as a module, choose M here: the
module will be called fdomain.
-config SCSI_FD_MCS
- tristate "Future Domain MCS-600/700 SCSI support"
- depends on MCA_LEGACY && SCSI
- ---help---
- This is support for Future Domain MCS 600/700 MCA SCSI adapters.
- Some PS/2 computers are equipped with IBM Fast SCSI Adapter/A which
- is identical to the MCS 700 and hence also supported by this driver.
- This driver also supports the Reply SB16/SCSI card (the SCSI part).
- It supports multiple adapters in the same system.
-
- To compile this driver as a module, choose M here: the
- module will be called fd_mcs.
-
config SCSI_GDTH
tristate "Intel/ICP (former GDT SCSI Disk Array) RAID Controller support"
depends on (ISA || EISA || PCI) && SCSI && ISA_DMA_API
@@ -890,76 +877,6 @@ config SCSI_GENERIC_NCR53C400
not detect your card. See the file
<file:Documentation/scsi/g_NCR5380.txt> for details.
-config SCSI_IBMMCA
- tristate "IBMMCA SCSI support"
- depends on MCA && SCSI
- ---help---
- This is support for the IBM SCSI adapter found in many of the PS/2
- series computers. These machines have an MCA bus, so you need to
- answer Y to "MCA support" as well and read
- <file:Documentation/mca.txt>.
-
- If the adapter isn't found during boot (a common problem for models
- 56, 57, 76, and 77) you'll need to use the 'ibmmcascsi=<pun>' kernel
- option, where <pun> is the id of the SCSI subsystem (usually 7, but
- if that doesn't work check your reference diskette). Owners of
- model 95 with a LED-matrix-display can in addition activate some
- activity info like under OS/2, but more informative, by setting
- 'ibmmcascsi=display' as an additional kernel parameter. Try "man
- bootparam" or see the documentation of your boot loader about how to
- pass options to the kernel.
-
- To compile this driver as a module, choose M here: the
- module will be called ibmmca.
-
-config IBMMCA_SCSI_ORDER_STANDARD
- bool "Standard SCSI-order"
- depends on SCSI_IBMMCA
- ---help---
- In the PC-world and in most modern SCSI-BIOS-setups, SCSI-hard disks
- are assigned to the drive letters, starting with the lowest SCSI-id
- (physical number -- pun) to be drive C:, as seen from DOS and
- similar operating systems. When looking into papers describing the
- ANSI-SCSI-standard, this assignment of drives appears to be wrong.
- The SCSI-standard follows a hardware-hierarchy which says that id 7
- has the highest priority and id 0 the lowest. Therefore, the host
- adapters are still today everywhere placed as SCSI-id 7 by default.
- In the SCSI-standard, the drive letters express the priority of the
- disk. C: should be the hard disk, or a partition on it, with the
- highest priority. This must therefore be the disk with the highest
- SCSI-id (e.g. 6) and not the one with the lowest! IBM-BIOS kept the
- original definition of the SCSI-standard as also industrial- and
- process-control-machines, like VME-CPUs running under realtime-OSes
- (e.g. LynxOS, OS9) do.
-
- If you like to run Linux on your MCA-machine with the same
- assignment of hard disks as seen from e.g. DOS or OS/2 on your
- machine, which is in addition conformant to the SCSI-standard, you
- must say Y here. This is also necessary for MCA-Linux users who want
- to keep downward compatibility to older releases of the
- IBM-MCA-SCSI-driver (older than driver-release 2.00 and older than
- June 1997).
-
- If you like to have the lowest SCSI-id assigned as drive C:, as
- modern SCSI-BIOSes do, which does not conform to the standard, but
- is widespread and common in the PC-world of today, you must say N
- here. If unsure, say Y.
-
-config IBMMCA_SCSI_DEV_RESET
- bool "Reset SCSI-devices at boottime"
- depends on SCSI_IBMMCA
- ---help---
- By default, SCSI-devices are reset when the machine is powered on.
- However, some devices exist, like special-control-devices,
- SCSI-CNC-machines, SCSI-printer or scanners of older type, that do
- not reset when switched on. If you say Y here, each device connected
- to your SCSI-bus will be issued a reset-command after it has been
- probed, while the kernel is booting. This may cause problems with
- more modern devices, like hard disks, which do not appreciate these
- reset commands, and can cause your system to hang. So say Y only if
- you know that one of your older devices needs it; N is the safe
- answer.
-
config SCSI_IPS
tristate "IBM ServeRAID support"
depends on PCI && SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 8deedeaf5608..1a3368b08615 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -75,7 +75,6 @@ obj-$(CONFIG_SCSI_AIC94XX) += aic94xx/
obj-$(CONFIG_SCSI_PM8001) += pm8001/
obj-$(CONFIG_SCSI_ISCI) += isci/
obj-$(CONFIG_SCSI_IPS) += ips.o
-obj-$(CONFIG_SCSI_FD_MCS) += fd_mcs.o
obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o
obj-$(CONFIG_SCSI_IN2000) += in2000.o
obj-$(CONFIG_SCSI_GENERIC_NCR5380) += g_NCR5380.o
@@ -100,7 +99,6 @@ obj-$(CONFIG_SCSI_SYM53C8XX_2) += sym53c8xx_2/
obj-$(CONFIG_SCSI_ZALON) += zalon7xx.o
obj-$(CONFIG_SCSI_EATA_PIO) += eata_pio.o
obj-$(CONFIG_SCSI_7000FASST) += wd7000.o
-obj-$(CONFIG_SCSI_IBMMCA) += ibmmca.o
obj-$(CONFIG_SCSI_EATA) += eata.o
obj-$(CONFIG_SCSI_DC395x) += dc395x.o
obj-$(CONFIG_SCSI_DC390T) += tmscsim.o
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index ede91f378000..f79c8f9e33a4 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -22,7 +22,7 @@
* Added module command-line options
* 19-Jul-99
* Modified by Adam Fritzler
- * Added proper detection of the AHA-1640 (MCA version of AHA-1540)
+ * Added proper detection of the AHA-1640 (MCA, now deleted)
*/
#include <linux/module.h>
@@ -37,8 +37,6 @@
#include <linux/spinlock.h>
#include <linux/isapnp.h>
#include <linux/blkdev.h>
-#include <linux/mca.h>
-#include <linux/mca-legacy.h>
#include <linux/slab.h>
#include <asm/dma.h>
@@ -71,7 +69,7 @@
#define MAXBOARDS 4 /* Increase this and the sizes of the
arrays below, if you need more.. */
-/* Boards 3,4 slots are reserved for ISAPnP/MCA scans */
+/* Boards 3,4 slots are reserved for ISAPnP scans */
static unsigned int bases[MAXBOARDS] __initdata = {0x330, 0x334, 0, 0};
@@ -1009,66 +1007,6 @@ static int __init aha1542_detect(struct scsi_host_template * tpnt)
#endif
/*
- * Find MicroChannel cards (AHA1640)
- */
-#ifdef CONFIG_MCA_LEGACY
- if(MCA_bus) {
- int slot = 0;
- int pos = 0;
-
- for (indx = 0; (slot != MCA_NOTFOUND) && (indx < ARRAY_SIZE(bases)); indx++) {
-
- if (bases[indx])
- continue;
-
- /* Detect only AHA-1640 cards -- MCA ID 0F1F */
- slot = mca_find_unused_adapter(0x0f1f, slot);
- if (slot == MCA_NOTFOUND)
- break;
-
- /* Found one */
- pos = mca_read_stored_pos(slot, 3);
-
- /* Decode address */
- if (pos & 0x80) {
- if (pos & 0x02) {
- if (pos & 0x01)
- bases[indx] = 0x334;
- else
- bases[indx] = 0x234;
- } else {
- if (pos & 0x01)
- bases[indx] = 0x134;
- }
- } else {
- if (pos & 0x02) {
- if (pos & 0x01)
- bases[indx] = 0x330;
- else
- bases[indx] = 0x230;
- } else {
- if (pos & 0x01)
- bases[indx] = 0x130;
- }
- }
-
- /* No need to decode IRQ and Arb level -- those are
- * read off the card later.
- */
- printk(KERN_INFO "Found an AHA-1640 in MCA slot %d, I/O 0x%04x\n", slot, bases[indx]);
-
- mca_set_adapter_name(slot, "Adapter AHA-1640");
- mca_set_adapter_procfn(slot, NULL, NULL);
- mca_mark_as_used(slot);
-
- /* Go on */
- slot++;
- }
-
- }
-#endif
-
- /*
* Hunt for ISA Plug'n'Pray Adaptecs (AHA1535)
*/
diff --git a/drivers/scsi/aic94xx/aic94xx_seq.c b/drivers/scsi/aic94xx/aic94xx_seq.c
index 390168f62a13..5fdca93892ad 100644
--- a/drivers/scsi/aic94xx/aic94xx_seq.c
+++ b/drivers/scsi/aic94xx/aic94xx_seq.c
@@ -1228,8 +1228,7 @@ static int asd_seq_start_lseq(struct asd_ha_struct *asd_ha, int lseq)
int asd_release_firmware(void)
{
- if (sequencer_fw)
- release_firmware(sequencer_fw);
+ release_firmware(sequencer_fw);
return 0;
}
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index 394ed9e79fd4..34552bf1c023 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -1000,7 +1000,7 @@ static int esp_check_spur_intr(struct esp *esp)
static void esp_schedule_reset(struct esp *esp)
{
- esp_log_reset("ESP: esp_schedule_reset() from %p\n",
+ esp_log_reset("ESP: esp_schedule_reset() from %pf\n",
__builtin_return_address(0));
esp->flags |= ESP_FLAG_RESETTING;
esp_event(esp, ESP_EVENT_RESET);
diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c
deleted file mode 100644
index 53bfcaa86f09..000000000000
--- a/drivers/scsi/fd_mcs.c
+++ /dev/null
@@ -1,1354 +0,0 @@
-/* fd_mcs.c -- Future Domain MCS 600/700 (or IBM OEM) driver
- *
- * FutureDomain MCS-600/700 v0.2 03/11/1998 by ZP Gu (zpg@castle.net)
- *
- * This driver is cloned from fdomain.* to specifically support
- * the Future Domain MCS 600/700 MCA SCSI adapters. Some PS/2s
- * also equipped with IBM Fast SCSI Adapter/A which is an OEM
- * of MCS 700.
- *
- * This driver also supports Reply SB16/SCSI card (the SCSI part).
- *
- * What makes this driver different is that this driver is MCA only
- * and it supports multiple adapters in the same system, IRQ
- * sharing, some driver statistics, and maps highest SCSI id to sda.
- * All cards are auto-detected.
- *
- * Assumptions: TMC-1800/18C50/18C30, BIOS >= 3.4
- *
- * LILO command-line options:
- * fd_mcs=<FIFO_COUNT>[,<FIFO_SIZE>]
- *
- * ********************************************************
- * Please see Copyrights/Comments in fdomain.* for credits.
- * Following is from fdomain.c for acknowledgement:
- *
- * Created: Sun May 3 18:53:19 1992 by faith@cs.unc.edu
- * Revised: Wed Oct 2 11:10:55 1996 by r.faith@ieee.org
- * Author: Rickard E. Faith, faith@cs.unc.edu
- * Copyright 1992, 1993, 1994, 1995, 1996 Rickard E. Faith
- *
- * $Id: fdomain.c,v 5.45 1996/10/02 15:13:06 root Exp $
-
- * 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.
-
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
-
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
-
- **************************************************************************
-
- NOTES ON USER DEFINABLE OPTIONS:
-
- DEBUG: This turns on the printing of various debug information.
-
- ENABLE_PARITY: This turns on SCSI parity checking. With the current
- driver, all attached devices must support SCSI parity. If none of your
- devices support parity, then you can probably get the driver to work by
- turning this option off. I have no way of testing this, however, and it
- would appear that no one ever uses this option.
-
- FIFO_COUNT: The host adapter has an 8K cache (host adapters based on the
- 18C30 chip have a 2k cache). When this many 512 byte blocks are filled by
- the SCSI device, an interrupt will be raised. Therefore, this could be as
- low as 0, or as high as 16. Note, however, that values which are too high
- or too low seem to prevent any interrupts from occurring, and thereby lock
- up the machine. I have found that 2 is a good number, but throughput may
- be increased by changing this value to values which are close to 2.
- Please let me know if you try any different values.
- [*****Now a runtime option*****]
-
- RESELECTION: This is no longer an option, since I gave up trying to
- implement it in version 4.x of this driver. It did not improve
- performance at all and made the driver unstable (because I never found one
- of the two race conditions which were introduced by the multiple
- outstanding command code). The instability seems a very high price to pay
- just so that you don't have to wait for the tape to rewind. If you want
- this feature implemented, send me patches. I'll be happy to send a copy
- of my (broken) driver to anyone who would like to see a copy.
-
- **************************************************************************/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/proc_fs.h>
-#include <linux/delay.h>
-#include <linux/mca.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <scsi/scsicam.h>
-#include <linux/mca-legacy.h>
-
-#include <asm/io.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-
-#define DRIVER_VERSION "v0.2 by ZP Gu<zpg@castle.net>"
-
-/* START OF USER DEFINABLE OPTIONS */
-
-#define DEBUG 0 /* Enable debugging output */
-#define ENABLE_PARITY 1 /* Enable SCSI Parity */
-
-/* END OF USER DEFINABLE OPTIONS */
-
-#if DEBUG
-#define EVERY_ACCESS 0 /* Write a line on every scsi access */
-#define ERRORS_ONLY 1 /* Only write a line if there is an error */
-#define DEBUG_MESSAGES 1 /* Debug MESSAGE IN phase */
-#define DEBUG_ABORT 1 /* Debug abort() routine */
-#define DEBUG_RESET 1 /* Debug reset() routine */
-#define DEBUG_RACE 1 /* Debug interrupt-driven race condition */
-#else
-#define EVERY_ACCESS 0 /* LEAVE THESE ALONE--CHANGE THE ONES ABOVE */
-#define ERRORS_ONLY 0
-#define DEBUG_MESSAGES 0
-#define DEBUG_ABORT 0
-#define DEBUG_RESET 0
-#define DEBUG_RACE 0
-#endif
-
-/* Errors are reported on the line, so we don't need to report them again */
-#if EVERY_ACCESS
-#undef ERRORS_ONLY
-#define ERRORS_ONLY 0
-#endif
-
-#if ENABLE_PARITY
-#define PARITY_MASK 0x08
-#else
-#define PARITY_MASK 0x00
-#endif
-
-enum chip_type {
- unknown = 0x00,
- tmc1800 = 0x01,
- tmc18c50 = 0x02,
- tmc18c30 = 0x03,
-};
-
-enum {
- in_arbitration = 0x02,
- in_selection = 0x04,
- in_other = 0x08,
- disconnect = 0x10,
- aborted = 0x20,
- sent_ident = 0x40,
-};
-
-enum in_port_type {
- Read_SCSI_Data = 0,
- SCSI_Status = 1,
- TMC_Status = 2,
- FIFO_Status = 3, /* tmc18c50/tmc18c30 only */
- Interrupt_Cond = 4, /* tmc18c50/tmc18c30 only */
- LSB_ID_Code = 5,
- MSB_ID_Code = 6,
- Read_Loopback = 7,
- SCSI_Data_NoACK = 8,
- Interrupt_Status = 9,
- Configuration1 = 10,
- Configuration2 = 11, /* tmc18c50/tmc18c30 only */
- Read_FIFO = 12,
- FIFO_Data_Count = 14
-};
-
-enum out_port_type {
- Write_SCSI_Data = 0,
- SCSI_Cntl = 1,
- Interrupt_Cntl = 2,
- SCSI_Mode_Cntl = 3,
- TMC_Cntl = 4,
- Memory_Cntl = 5, /* tmc18c50/tmc18c30 only */
- Write_Loopback = 7,
- IO_Control = 11, /* tmc18c30 only */
- Write_FIFO = 12
-};
-
-struct fd_hostdata {
- unsigned long _bios_base;
- int _bios_major;
- int _bios_minor;
- volatile int _in_command;
- Scsi_Cmnd *_current_SC;
- enum chip_type _chip;
- int _adapter_mask;
- int _fifo_count; /* Number of 512 byte blocks before INTR */
-
- char _adapter_name[64];
-#if DEBUG_RACE
- volatile int _in_interrupt_flag;
-#endif
-
- int _SCSI_Mode_Cntl_port;
- int _FIFO_Data_Count_port;
- int _Interrupt_Cntl_port;
- int _Interrupt_Status_port;
- int _Interrupt_Cond_port;
- int _Read_FIFO_port;
- int _Read_SCSI_Data_port;
- int _SCSI_Cntl_port;
- int _SCSI_Data_NoACK_port;
- int _SCSI_Status_port;
- int _TMC_Cntl_port;
- int _TMC_Status_port;
- int _Write_FIFO_port;
- int _Write_SCSI_Data_port;
-
- int _FIFO_Size; /* = 0x2000; 8k FIFO for
- pre-tmc18c30 chips */
- /* simple stats */
- int _Bytes_Read;
- int _Bytes_Written;
- int _INTR_Processed;
-};
-
-#define FD_MAX_HOSTS 3 /* enough? */
-
-#define HOSTDATA(shpnt) ((struct fd_hostdata *) shpnt->hostdata)
-#define bios_base (HOSTDATA(shpnt)->_bios_base)
-#define bios_major (HOSTDATA(shpnt)->_bios_major)
-#define bios_minor (HOSTDATA(shpnt)->_bios_minor)
-#define in_command (HOSTDATA(shpnt)->_in_command)
-#define current_SC (HOSTDATA(shpnt)->_current_SC)
-#define chip (HOSTDATA(shpnt)->_chip)
-#define adapter_mask (HOSTDATA(shpnt)->_adapter_mask)
-#define FIFO_COUNT (HOSTDATA(shpnt)->_fifo_count)
-#define adapter_name (HOSTDATA(shpnt)->_adapter_name)
-#if DEBUG_RACE
-#define in_interrupt_flag (HOSTDATA(shpnt)->_in_interrupt_flag)
-#endif
-#define SCSI_Mode_Cntl_port (HOSTDATA(shpnt)->_SCSI_Mode_Cntl_port)
-#define FIFO_Data_Count_port (HOSTDATA(shpnt)->_FIFO_Data_Count_port)
-#define Interrupt_Cntl_port (HOSTDATA(shpnt)->_Interrupt_Cntl_port)
-#define Interrupt_Status_port (HOSTDATA(shpnt)->_Interrupt_Status_port)
-#define Interrupt_Cond_port (HOSTDATA(shpnt)->_Interrupt_Cond_port)
-#define Read_FIFO_port (HOSTDATA(shpnt)->_Read_FIFO_port)
-#define Read_SCSI_Data_port (HOSTDATA(shpnt)->_Read_SCSI_Data_port)
-#define SCSI_Cntl_port (HOSTDATA(shpnt)->_SCSI_Cntl_port)
-#define SCSI_Data_NoACK_port (HOSTDATA(shpnt)->_SCSI_Data_NoACK_port)
-#define SCSI_Status_port (HOSTDATA(shpnt)->_SCSI_Status_port)
-#define TMC_Cntl_port (HOSTDATA(shpnt)->_TMC_Cntl_port)
-#define TMC_Status_port (HOSTDATA(shpnt)->_TMC_Status_port)
-#define Write_FIFO_port (HOSTDATA(shpnt)->_Write_FIFO_port)
-#define Write_SCSI_Data_port (HOSTDATA(shpnt)->_Write_SCSI_Data_port)
-#define FIFO_Size (HOSTDATA(shpnt)->_FIFO_Size)
-#define Bytes_Read (HOSTDATA(shpnt)->_Bytes_Read)
-#define Bytes_Written (HOSTDATA(shpnt)->_Bytes_Written)
-#define INTR_Processed (HOSTDATA(shpnt)->_INTR_Processed)
-
-struct fd_mcs_adapters_struct {
- char *name;
- int id;
- enum chip_type fd_chip;
- int fifo_size;
- int fifo_count;
-};
-
-#define REPLY_ID 0x5137
-
-static struct fd_mcs_adapters_struct fd_mcs_adapters[] = {
- {"Future Domain SCSI Adapter MCS-700(18C50)",
- 0x60e9,
- tmc18c50,
- 0x2000,
- 4},
- {"Future Domain SCSI Adapter MCS-600/700(TMC-1800)",
- 0x6127,
- tmc1800,
- 0x2000,
- 4},
- {"Reply Sound Blaster/SCSI Adapter",
- REPLY_ID,
- tmc18c30,
- 0x800,
- 2},
-};
-
-#define FD_BRDS ARRAY_SIZE(fd_mcs_adapters)
-
-static irqreturn_t fd_mcs_intr(int irq, void *dev_id);
-
-static unsigned long addresses[] = { 0xc8000, 0xca000, 0xce000, 0xde000 };
-static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };
-static unsigned short interrupts[] = { 3, 5, 10, 11, 12, 14, 15, 0 };
-
-/* host information */
-static int found = 0;
-static struct Scsi_Host *hosts[FD_MAX_HOSTS + 1] = { NULL };
-
-static int user_fifo_count = 0;
-static int user_fifo_size = 0;
-
-#ifndef MODULE
-static int __init fd_mcs_setup(char *str)
-{
- static int done_setup = 0;
- int ints[3];
-
- get_options(str, 3, ints);
- if (done_setup++ || ints[0] < 1 || ints[0] > 2 || ints[1] < 1 || ints[1] > 16) {
- printk("fd_mcs: usage: fd_mcs=FIFO_COUNT, FIFO_SIZE\n");
- return 0;
- }
-
- user_fifo_count = ints[0] >= 1 ? ints[1] : 0;
- user_fifo_size = ints[0] >= 2 ? ints[2] : 0;
- return 1;
-}
-
-__setup("fd_mcs=", fd_mcs_setup);
-#endif /* !MODULE */
-
-static void print_banner(struct Scsi_Host *shpnt)
-{
- printk("scsi%d <fd_mcs>: ", shpnt->host_no);
-
- if (bios_base) {
- printk("BIOS at 0x%lX", bios_base);
- } else {
- printk("No BIOS");
- }
-
- printk(", HostID %d, %s Chip, IRQ %d, IO 0x%lX\n", shpnt->this_id, chip == tmc18c50 ? "TMC-18C50" : (chip == tmc18c30 ? "TMC-18C30" : (chip == tmc1800 ? "TMC-1800" : "Unknown")), shpnt->irq, shpnt->io_port);
-}
-
-
-static void do_pause(unsigned amount)
-{ /* Pause for amount*10 milliseconds */
- do {
- mdelay(10);
- } while (--amount);
-}
-
-static void fd_mcs_make_bus_idle(struct Scsi_Host *shpnt)
-{
- outb(0, SCSI_Cntl_port);
- outb(0, SCSI_Mode_Cntl_port);
- if (chip == tmc18c50 || chip == tmc18c30)
- outb(0x21 | PARITY_MASK, TMC_Cntl_port); /* Clear forced intr. */
- else
- outb(0x01 | PARITY_MASK, TMC_Cntl_port);
-}
-
-static int fd_mcs_detect(struct scsi_host_template * tpnt)
-{
- int loop;
- struct Scsi_Host *shpnt;
-
- /* get id, port, bios, irq */
- int slot;
- u_char pos2, pos3, pos4;
- int id, port, irq;
- unsigned long bios;
-
- /* if not MCA machine, return */
- if (!MCA_bus)
- return 0;
-
- /* changeable? */
- id = 7;
-
- for (loop = 0; loop < FD_BRDS; loop++) {
- slot = 0;
- while (MCA_NOTFOUND != (slot = mca_find_adapter(fd_mcs_adapters[loop].id, slot))) {
-
- /* if we get this far, an adapter has been detected and is
- enabled */
-
- printk(KERN_INFO "scsi <fd_mcs>: %s at slot %d\n", fd_mcs_adapters[loop].name, slot + 1);
-
- pos2 = mca_read_stored_pos(slot, 2);
- pos3 = mca_read_stored_pos(slot, 3);
- pos4 = mca_read_stored_pos(slot, 4);
-
- /* ready for next probe */
- slot++;
-
- if (fd_mcs_adapters[loop].id == REPLY_ID) { /* reply card */
- static int reply_irq[] = { 10, 11, 14, 15 };
-
- bios = 0; /* no bios */
-
- if (pos2 & 0x2)
- port = ports[pos4 & 0x3];
- else
- continue;
-
- /* can't really disable it, same as irq=10 */
- irq = reply_irq[((pos4 >> 2) & 0x1) + 2 * ((pos4 >> 4) & 0x1)];
- } else {
- bios = addresses[pos2 >> 6];
- port = ports[(pos2 >> 4) & 0x03];
- irq = interrupts[(pos2 >> 1) & 0x07];
- }
-
- if (irq) {
- /* claim the slot */
- mca_set_adapter_name(slot - 1, fd_mcs_adapters[loop].name);
-
- /* check irq/region */
- if (request_irq(irq, fd_mcs_intr, IRQF_SHARED, "fd_mcs", hosts)) {
- printk(KERN_ERR "fd_mcs: interrupt is not available, skipping...\n");
- continue;
- }
-
- /* request I/O region */
- if (request_region(port, 0x10, "fd_mcs")) {
- printk(KERN_ERR "fd_mcs: I/O region is already in use, skipping...\n");
- continue;
- }
- /* register */
- if (!(shpnt = scsi_register(tpnt, sizeof(struct fd_hostdata)))) {
- printk(KERN_ERR "fd_mcs: scsi_register() failed\n");
- release_region(port, 0x10);
- free_irq(irq, hosts);
- continue;
- }
-
-
- /* save name */
- strcpy(adapter_name, fd_mcs_adapters[loop].name);
-
- /* chip/fifo */
- chip = fd_mcs_adapters[loop].fd_chip;
- /* use boot time value if available */
- FIFO_COUNT = user_fifo_count ? user_fifo_count : fd_mcs_adapters[loop].fifo_count;
- FIFO_Size = user_fifo_size ? user_fifo_size : fd_mcs_adapters[loop].fifo_size;
-
-/* FIXME: Do we need to keep this bit of code inside NOT_USED around at all? */
-#ifdef NOT_USED
- /* *************************************************** */
- /* Try to toggle 32-bit mode. This only
- works on an 18c30 chip. (User reports
- say this works, so we should switch to
- it in the near future.) */
- outb(0x80, port + IO_Control);
- if ((inb(port + Configuration2) & 0x80) == 0x80) {
- outb(0x00, port + IO_Control);
- if ((inb(port + Configuration2) & 0x80) == 0x00) {
- chip = tmc18c30;
- FIFO_Size = 0x800; /* 2k FIFO */
-
- printk("FIRST: chip=%s, fifo_size=0x%x\n", (chip == tmc18c30) ? "tmc18c30" : "tmc18c50", FIFO_Size);
- }
- }
-
- /* That should have worked, but appears to
- have problems. Let's assume it is an
- 18c30 if the RAM is disabled. */
-
- if (inb(port + Configuration2) & 0x02) {
- chip = tmc18c30;
- FIFO_Size = 0x800; /* 2k FIFO */
-
- printk("SECOND: chip=%s, fifo_size=0x%x\n", (chip == tmc18c30) ? "tmc18c30" : "tmc18c50", FIFO_Size);
- }
- /* *************************************************** */
-#endif
-
- /* IBM/ANSI scsi scan ordering */
- /* Stick this back in when the scsi.c changes are there */
- shpnt->reverse_ordering = 1;
-
-
- /* saving info */
- hosts[found++] = shpnt;
-
- shpnt->this_id = id;
- shpnt->irq = irq;
- shpnt->io_port = port;
- shpnt->n_io_port = 0x10;
-
- /* save */
- bios_base = bios;
- adapter_mask = (1 << id);
-
- /* save more */
- SCSI_Mode_Cntl_port = port + SCSI_Mode_Cntl;
- FIFO_Data_Count_port = port + FIFO_Data_Count;
- Interrupt_Cntl_port = port + Interrupt_Cntl;
- Interrupt_Status_port = port + Interrupt_Status;
- Interrupt_Cond_port = port + Interrupt_Cond;
- Read_FIFO_port = port + Read_FIFO;
- Read_SCSI_Data_port = port + Read_SCSI_Data;
- SCSI_Cntl_port = port + SCSI_Cntl;
- SCSI_Data_NoACK_port = port + SCSI_Data_NoACK;
- SCSI_Status_port = port + SCSI_Status;
- TMC_Cntl_port = port + TMC_Cntl;
- TMC_Status_port = port + TMC_Status;
- Write_FIFO_port = port + Write_FIFO;
- Write_SCSI_Data_port = port + Write_SCSI_Data;
-
- Bytes_Read = 0;
- Bytes_Written = 0;
- INTR_Processed = 0;
-
- /* say something */
- print_banner(shpnt);
-
- /* reset */
- outb(1, SCSI_Cntl_port);
- do_pause(2);
- outb(0, SCSI_Cntl_port);
- do_pause(115);
- outb(0, SCSI_Mode_Cntl_port);
- outb(PARITY_MASK, TMC_Cntl_port);
- /* done reset */
- }
- }
-
- if (found == FD_MAX_HOSTS) {
- printk("fd_mcs: detecting reached max=%d host adapters.\n", FD_MAX_HOSTS);
- break;
- }
- }
-
- return found;
-}
-
-static const char *fd_mcs_info(struct Scsi_Host *shpnt)
-{
- return adapter_name;
-}
-
-static int TOTAL_INTR = 0;
-
-/*
- * inout : decides on the direction of the dataflow and the meaning of the
- * variables
- * buffer: If inout==FALSE data is being written to it else read from it
- * *start: If inout==FALSE start of the valid data in the buffer
- * offset: If inout==FALSE offset from the beginning of the imaginary file
- * from which we start writing into the buffer
- * length: If inout==FALSE max number of bytes to be written into the buffer
- * else number of bytes in the buffer
- */
-static int fd_mcs_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, int inout)
-{
- int len = 0;
-
- if (inout)
- return (-ENOSYS);
-
- *start = buffer + offset;
-
- len += sprintf(buffer + len, "Future Domain MCS-600/700 Driver %s\n", DRIVER_VERSION);
- len += sprintf(buffer + len, "HOST #%d: %s\n", shpnt->host_no, adapter_name);
- len += sprintf(buffer + len, "FIFO Size=0x%x, FIFO Count=%d\n", FIFO_Size, FIFO_COUNT);
- len += sprintf(buffer + len, "DriverCalls=%d, Interrupts=%d, BytesRead=%d, BytesWrite=%d\n\n", TOTAL_INTR, INTR_Processed, Bytes_Read, Bytes_Written);
-
- if ((len -= offset) <= 0)
- return 0;
- if (len > length)
- len = length;
- return len;
-}
-
-static int fd_mcs_select(struct Scsi_Host *shpnt, int target)
-{
- int status;
- unsigned long timeout;
-
- outb(0x82, SCSI_Cntl_port); /* Bus Enable + Select */
- outb(adapter_mask | (1 << target), SCSI_Data_NoACK_port);
-
- /* Stop arbitration and enable parity */
- outb(PARITY_MASK, TMC_Cntl_port);
-
- timeout = 350; /* 350mS -- because of timeouts
- (was 250mS) */
-
- do {
- status = inb(SCSI_Status_port); /* Read adapter status */
- if (status & 1) { /* Busy asserted */
- /* Enable SCSI Bus (on error, should make bus idle with 0) */
- outb(0x80, SCSI_Cntl_port);
- return 0;
- }
- udelay(1000); /* wait one msec */
- } while (--timeout);
-
- /* Make bus idle */
- fd_mcs_make_bus_idle(shpnt);
-#if EVERY_ACCESS
- if (!target)
- printk("Selection failed\n");
-#endif
-#if ERRORS_ONLY
- if (!target) {
- static int flag = 0;
-
- if (!flag) /* Skip first failure for all chips. */
- ++flag;
- else
- printk("fd_mcs: Selection failed\n");
- }
-#endif
- return 1;
-}
-
-static void my_done(struct Scsi_Host *shpnt, int error)
-{
- if (in_command) {
- in_command = 0;
- outb(0x00, Interrupt_Cntl_port);
- fd_mcs_make_bus_idle(shpnt);
- current_SC->result = error;
- current_SC->scsi_done(current_SC);
- } else {
- panic("fd_mcs: my_done() called outside of command\n");
- }
-#if DEBUG_RACE
- in_interrupt_flag = 0;
-#endif
-}
-
-/* only my_done needs to be protected */
-static irqreturn_t fd_mcs_intr(int irq, void *dev_id)
-{
- unsigned long flags;
- int status;
- int done = 0;
- unsigned data_count, tmp_count;
-
- int i = 0;
- struct Scsi_Host *shpnt;
-
- TOTAL_INTR++;
-
- /* search for one adapter-response on shared interrupt */
- while ((shpnt = hosts[i++])) {
- if ((inb(TMC_Status_port)) & 1)
- break;
- }
-
- /* return if some other device on this IRQ caused the interrupt */
- if (!shpnt) {
- return IRQ_NONE;
- }
-
- INTR_Processed++;
-
- outb(0x00, Interrupt_Cntl_port);
-
- /* Abort calls my_done, so we do nothing here. */
- if (current_SC->SCp.phase & aborted) {
-#if DEBUG_ABORT
- printk("Interrupt after abort, ignoring\n");
-#endif
- /* return IRQ_HANDLED; */
- }
-#if DEBUG_RACE
- ++in_interrupt_flag;
-#endif
-
- if (current_SC->SCp.phase & in_arbitration) {
- status = inb(TMC_Status_port); /* Read adapter status */
- if (!(status & 0x02)) {
-#if EVERY_ACCESS
- printk(" AFAIL ");
-#endif
- spin_lock_irqsave(shpnt->host_lock, flags);
- my_done(shpnt, DID_BUS_BUSY << 16);
- spin_unlock_irqrestore(shpnt->host_lock, flags);
- return IRQ_HANDLED;
- }
- current_SC->SCp.phase = in_selection;
-
- outb(0x40 | FIFO_COUNT, Interrupt_Cntl_port);
-
- outb(0x82, SCSI_Cntl_port); /* Bus Enable + Select */
- outb(adapter_mask | (1 << scmd_id(current_SC)), SCSI_Data_NoACK_port);
-
- /* Stop arbitration and enable parity */
- outb(0x10 | PARITY_MASK, TMC_Cntl_port);
-#if DEBUG_RACE
- in_interrupt_flag = 0;
-#endif
- return IRQ_HANDLED;
- } else if (current_SC->SCp.phase & in_selection) {
- status = inb(SCSI_Status_port);
- if (!(status & 0x01)) {
- /* Try again, for slow devices */
- if (fd_mcs_select(shpnt, scmd_id(current_SC))) {
-#if EVERY_ACCESS
- printk(" SFAIL ");
-#endif
- spin_lock_irqsave(shpnt->host_lock, flags);
- my_done(shpnt, DID_NO_CONNECT << 16);
- spin_unlock_irqrestore(shpnt->host_lock, flags);
- return IRQ_HANDLED;
- } else {
-#if EVERY_ACCESS
- printk(" AltSel ");
-#endif
- /* Stop arbitration and enable parity */
- outb(0x10 | PARITY_MASK, TMC_Cntl_port);
- }
- }
- current_SC->SCp.phase = in_other;
- outb(0x90 | FIFO_COUNT, Interrupt_Cntl_port);
- outb(0x80, SCSI_Cntl_port);
-#if DEBUG_RACE
- in_interrupt_flag = 0;
-#endif
- return IRQ_HANDLED;
- }
-
- /* current_SC->SCp.phase == in_other: this is the body of the routine */
-
- status = inb(SCSI_Status_port);
-
- if (status & 0x10) { /* REQ */
-
- switch (status & 0x0e) {
-
- case 0x08: /* COMMAND OUT */
- outb(current_SC->cmnd[current_SC->SCp.sent_command++], Write_SCSI_Data_port);
-#if EVERY_ACCESS
- printk("CMD = %x,", current_SC->cmnd[current_SC->SCp.sent_command - 1]);
-#endif
- break;
- case 0x00: /* DATA OUT -- tmc18c50/tmc18c30 only */
- if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
- current_SC->SCp.have_data_in = -1;
- outb(0xd0 | PARITY_MASK, TMC_Cntl_port);
- }
- break;
- case 0x04: /* DATA IN -- tmc18c50/tmc18c30 only */
- if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
- current_SC->SCp.have_data_in = 1;
- outb(0x90 | PARITY_MASK, TMC_Cntl_port);
- }
- break;
- case 0x0c: /* STATUS IN */
- current_SC->SCp.Status = inb(Read_SCSI_Data_port);
-#if EVERY_ACCESS
- printk("Status = %x, ", current_SC->SCp.Status);
-#endif
-#if ERRORS_ONLY
- if (current_SC->SCp.Status && current_SC->SCp.Status != 2 && current_SC->SCp.Status != 8) {
- printk("ERROR fd_mcs: target = %d, command = %x, status = %x\n", current_SC->device->id, current_SC->cmnd[0], current_SC->SCp.Status);
- }
-#endif
- break;
- case 0x0a: /* MESSAGE OUT */
- outb(MESSAGE_REJECT, Write_SCSI_Data_port); /* Reject */
- break;
- case 0x0e: /* MESSAGE IN */
- current_SC->SCp.Message = inb(Read_SCSI_Data_port);
-#if EVERY_ACCESS
- printk("Message = %x, ", current_SC->SCp.Message);
-#endif
- if (!current_SC->SCp.Message)
- ++done;
-#if DEBUG_MESSAGES || EVERY_ACCESS
- if (current_SC->SCp.Message) {
- printk("fd_mcs: message = %x\n", current_SC->SCp.Message);
- }
-#endif
- break;
- }
- }
-
- if (chip == tmc1800 && !current_SC->SCp.have_data_in && (current_SC->SCp.sent_command >= current_SC->cmd_len)) {
- /* We have to get the FIFO direction
- correct, so I've made a table based
- on the SCSI Standard of which commands
- appear to require a DATA OUT phase.
- */
- /*
- p. 94: Command for all device types
- CHANGE DEFINITION 40 DATA OUT
- COMPARE 39 DATA OUT
- COPY 18 DATA OUT
- COPY AND VERIFY 3a DATA OUT
- INQUIRY 12
- LOG SELECT 4c DATA OUT
- LOG SENSE 4d
- MODE SELECT (6) 15 DATA OUT
- MODE SELECT (10) 55 DATA OUT
- MODE SENSE (6) 1a
- MODE SENSE (10) 5a
- READ BUFFER 3c
- RECEIVE DIAGNOSTIC RESULTS 1c
- REQUEST SENSE 03
- SEND DIAGNOSTIC 1d DATA OUT
- TEST UNIT READY 00
- WRITE BUFFER 3b DATA OUT
-
- p.178: Commands for direct-access devices (not listed on p. 94)
- FORMAT UNIT 04 DATA OUT
- LOCK-UNLOCK CACHE 36
- PRE-FETCH 34
- PREVENT-ALLOW MEDIUM REMOVAL 1e
- READ (6)/RECEIVE 08
- READ (10) 3c
- READ CAPACITY 25
- READ DEFECT DATA (10) 37
- READ LONG 3e
- REASSIGN BLOCKS 07 DATA OUT
- RELEASE 17
- RESERVE 16 DATA OUT
- REZERO UNIT/REWIND 01
- SEARCH DATA EQUAL (10) 31 DATA OUT
- SEARCH DATA HIGH (10) 30 DATA OUT
- SEARCH DATA LOW (10) 32 DATA OUT
- SEEK (6) 0b
- SEEK (10) 2b
- SET LIMITS (10) 33
- START STOP UNIT 1b
- SYNCHRONIZE CACHE 35
- VERIFY (10) 2f
- WRITE (6)/PRINT/SEND 0a DATA OUT
- WRITE (10)/SEND 2a DATA OUT
- WRITE AND VERIFY (10) 2e DATA OUT
- WRITE LONG 3f DATA OUT
- WRITE SAME 41 DATA OUT ?
-
- p. 261: Commands for sequential-access devices (not previously listed)
- ERASE 19
- LOAD UNLOAD 1b
- LOCATE 2b
- READ BLOCK LIMITS 05
- READ POSITION 34
- READ REVERSE 0f
- RECOVER BUFFERED DATA 14
- SPACE 11
- WRITE FILEMARKS 10 ?
-
- p. 298: Commands for printer devices (not previously listed)
- ****** NOT SUPPORTED BY THIS DRIVER, since 0b is SEEK (6) *****
- SLEW AND PRINT 0b DATA OUT -- same as seek
- STOP PRINT 1b
- SYNCHRONIZE BUFFER 10
-
- p. 315: Commands for processor devices (not previously listed)
-
- p. 321: Commands for write-once devices (not previously listed)
- MEDIUM SCAN 38
- READ (12) a8
- SEARCH DATA EQUAL (12) b1 DATA OUT
- SEARCH DATA HIGH (12) b0 DATA OUT
- SEARCH DATA LOW (12) b2 DATA OUT
- SET LIMITS (12) b3
- VERIFY (12) af
- WRITE (12) aa DATA OUT
- WRITE AND VERIFY (12) ae DATA OUT
-
- p. 332: Commands for CD-ROM devices (not previously listed)
- PAUSE/RESUME 4b
- PLAY AUDIO (10) 45
- PLAY AUDIO (12) a5
- PLAY AUDIO MSF 47
- PLAY TRACK RELATIVE (10) 49
- PLAY TRACK RELATIVE (12) a9
- READ HEADER 44
- READ SUB-CHANNEL 42
- READ TOC 43
-
- p. 370: Commands for scanner devices (not previously listed)
- GET DATA BUFFER STATUS 34
- GET WINDOW 25
- OBJECT POSITION 31
- SCAN 1b
- SET WINDOW 24 DATA OUT
-
- p. 391: Commands for optical memory devices (not listed)
- ERASE (10) 2c
- ERASE (12) ac
- MEDIUM SCAN 38 DATA OUT
- READ DEFECT DATA (12) b7
- READ GENERATION 29
- READ UPDATED BLOCK 2d
- UPDATE BLOCK 3d DATA OUT
-
- p. 419: Commands for medium changer devices (not listed)
- EXCHANGE MEDIUM 46
- INITIALIZE ELEMENT STATUS 07
- MOVE MEDIUM a5
- POSITION TO ELEMENT 2b
- READ ELEMENT STATUS b8
- REQUEST VOL. ELEMENT ADDRESS b5
- SEND VOLUME TAG b6 DATA OUT
-
- p. 454: Commands for communications devices (not listed previously)
- GET MESSAGE (6) 08
- GET MESSAGE (10) 28
- GET MESSAGE (12) a8
- */
-
- switch (current_SC->cmnd[0]) {
- case CHANGE_DEFINITION:
- case COMPARE:
- case COPY:
- case COPY_VERIFY:
- case LOG_SELECT:
- case MODE_SELECT:
- case MODE_SELECT_10:
- case SEND_DIAGNOSTIC:
- case WRITE_BUFFER:
-
- case FORMAT_UNIT:
- case REASSIGN_BLOCKS:
- case RESERVE:
- case SEARCH_EQUAL:
- case SEARCH_HIGH:
- case SEARCH_LOW:
- case WRITE_6:
- case WRITE_10:
- case WRITE_VERIFY:
- case 0x3f:
- case 0x41:
-
- case 0xb1:
- case 0xb0:
- case 0xb2:
- case 0xaa:
- case 0xae:
-
- case 0x24:
-
- case 0x38:
- case 0x3d:
-
- case 0xb6:
-
- case 0xea: /* alternate number for WRITE LONG */
-
- current_SC->SCp.have_data_in = -1;
- outb(0xd0 | PARITY_MASK, TMC_Cntl_port);
- break;
-
- case 0x00:
- default:
-
- current_SC->SCp.have_data_in = 1;
- outb(0x90 | PARITY_MASK, TMC_Cntl_port);
- break;
- }
- }
-
- if (current_SC->SCp.have_data_in == -1) { /* DATA OUT */
- while ((data_count = FIFO_Size - inw(FIFO_Data_Count_port)) > 512) {
-#if EVERY_ACCESS
- printk("DC=%d, ", data_count);
-#endif
- if (data_count > current_SC->SCp.this_residual)
- data_count = current_SC->SCp.this_residual;
- if (data_count > 0) {
-#if EVERY_ACCESS
- printk("%d OUT, ", data_count);
-#endif
- if (data_count == 1) {
- Bytes_Written++;
-
- outb(*current_SC->SCp.ptr++, Write_FIFO_port);
- --current_SC->SCp.this_residual;
- } else {
- data_count >>= 1;
- tmp_count = data_count << 1;
- outsw(Write_FIFO_port, current_SC->SCp.ptr, data_count);
- current_SC->SCp.ptr += tmp_count;
- Bytes_Written += tmp_count;
- current_SC->SCp.this_residual -= tmp_count;
- }
- }
- if (!current_SC->SCp.this_residual) {
- if (current_SC->SCp.buffers_residual) {
- --current_SC->SCp.buffers_residual;
- ++current_SC->SCp.buffer;
- current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
- current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
- } else
- break;
- }
- }
- } else if (current_SC->SCp.have_data_in == 1) { /* DATA IN */
- while ((data_count = inw(FIFO_Data_Count_port)) > 0) {
-#if EVERY_ACCESS
- printk("DC=%d, ", data_count);
-#endif
- if (data_count > current_SC->SCp.this_residual)
- data_count = current_SC->SCp.this_residual;
- if (data_count) {
-#if EVERY_ACCESS
- printk("%d IN, ", data_count);
-#endif
- if (data_count == 1) {
- Bytes_Read++;
- *current_SC->SCp.ptr++ = inb(Read_FIFO_port);
- --current_SC->SCp.this_residual;
- } else {
- data_count >>= 1; /* Number of words */
- tmp_count = data_count << 1;
- insw(Read_FIFO_port, current_SC->SCp.ptr, data_count);
- current_SC->SCp.ptr += tmp_count;
- Bytes_Read += tmp_count;
- current_SC->SCp.this_residual -= tmp_count;
- }
- }
- if (!current_SC->SCp.this_residual && current_SC->SCp.buffers_residual) {
- --current_SC->SCp.buffers_residual;
- ++current_SC->SCp.buffer;
- current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
- current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
- }
- }
- }
-
- if (done) {
-#if EVERY_ACCESS
- printk(" ** IN DONE %d ** ", current_SC->SCp.have_data_in);
-#endif
-
-#if EVERY_ACCESS
- printk("BEFORE MY_DONE. . .");
-#endif
- spin_lock_irqsave(shpnt->host_lock, flags);
- my_done(shpnt, (current_SC->SCp.Status & 0xff)
- | ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16));
- spin_unlock_irqrestore(shpnt->host_lock, flags);
-#if EVERY_ACCESS
- printk("RETURNING.\n");
-#endif
-
- } else {
- if (current_SC->SCp.phase & disconnect) {
- outb(0xd0 | FIFO_COUNT, Interrupt_Cntl_port);
- outb(0x00, SCSI_Cntl_port);
- } else {
- outb(0x90 | FIFO_COUNT, Interrupt_Cntl_port);
- }
- }
-#if DEBUG_RACE
- in_interrupt_flag = 0;
-#endif
- return IRQ_HANDLED;
-}
-
-static int fd_mcs_release(struct Scsi_Host *shpnt)
-{
- int i, this_host, irq_usage;
-
- release_region(shpnt->io_port, shpnt->n_io_port);
-
- this_host = -1;
- irq_usage = 0;
- for (i = 0; i < found; i++) {
- if (shpnt == hosts[i])
- this_host = i;
- if (shpnt->irq == hosts[i]->irq)
- irq_usage++;
- }
-
- /* only for the last one */
- if (1 == irq_usage)
- free_irq(shpnt->irq, hosts);
-
- found--;
-
- for (i = this_host; i < found; i++)
- hosts[i] = hosts[i + 1];
-
- hosts[found] = NULL;
-
- return 0;
-}
-
-static int fd_mcs_queue_lck(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
-{
- struct Scsi_Host *shpnt = SCpnt->device->host;
-
- if (in_command) {
- panic("fd_mcs: fd_mcs_queue() NOT REENTRANT!\n");
- }
-#if EVERY_ACCESS
- printk("queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n",
- SCpnt->target, *(unsigned char *) SCpnt->cmnd,
- scsi_sg_count(SCpnt), scsi_bufflen(SCpnt));
-#endif
-
- fd_mcs_make_bus_idle(shpnt);
-
- SCpnt->scsi_done = done; /* Save this for the done function */
- current_SC = SCpnt;
-
- /* Initialize static data */
-
- if (scsi_bufflen(current_SC)) {
- current_SC->SCp.buffer = scsi_sglist(current_SC);
- current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer);
- current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
- current_SC->SCp.buffers_residual = scsi_sg_count(current_SC) - 1;
- } else {
- current_SC->SCp.ptr = NULL;
- current_SC->SCp.this_residual = 0;
- current_SC->SCp.buffer = NULL;
- current_SC->SCp.buffers_residual = 0;
- }
-
-
- current_SC->SCp.Status = 0;
- current_SC->SCp.Message = 0;
- current_SC->SCp.have_data_in = 0;
- current_SC->SCp.sent_command = 0;
- current_SC->SCp.phase = in_arbitration;
-
- /* Start arbitration */
- outb(0x00, Interrupt_Cntl_port);
- outb(0x00, SCSI_Cntl_port); /* Disable data drivers */
- outb(adapter_mask, SCSI_Data_NoACK_port); /* Set our id bit */
- in_command = 1;
- outb(0x20, Interrupt_Cntl_port);
- outb(0x14 | PARITY_MASK, TMC_Cntl_port); /* Start arbitration */
-
- return 0;
-}
-
-static DEF_SCSI_QCMD(fd_mcs_queue)
-
-#if DEBUG_ABORT || DEBUG_RESET
-static void fd_mcs_print_info(Scsi_Cmnd * SCpnt)
-{
- unsigned int imr;
- unsigned int irr;
- unsigned int isr;
- struct Scsi_Host *shpnt = SCpnt->host;
-
- if (!SCpnt || !SCpnt->host) {
- printk("fd_mcs: cannot provide detailed information\n");
- }
-
- printk("%s\n", fd_mcs_info(SCpnt->host));
- print_banner(SCpnt->host);
- switch (SCpnt->SCp.phase) {
- case in_arbitration:
- printk("arbitration ");
- break;
- case in_selection:
- printk("selection ");
- break;
- case in_other:
- printk("other ");
- break;
- default:
- printk("unknown ");
- break;
- }
-
- printk("(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n",
- SCpnt->SCp.phase, SCpnt->device->id, *(unsigned char *) SCpnt->cmnd,
- scsi_sg_count(SCpnt), scsi_bufflen(SCpnt));
- printk("sent_command = %d, have_data_in = %d, timeout = %d\n", SCpnt->SCp.sent_command, SCpnt->SCp.have_data_in, SCpnt->timeout);
-#if DEBUG_RACE
- printk("in_interrupt_flag = %d\n", in_interrupt_flag);
-#endif
-
- imr = (inb(0x0a1) << 8) + inb(0x21);
- outb(0x0a, 0xa0);
- irr = inb(0xa0) << 8;
- outb(0x0a, 0x20);
- irr += inb(0x20);
- outb(0x0b, 0xa0);
- isr = inb(0xa0) << 8;
- outb(0x0b, 0x20);
- isr += inb(0x20);
-
- /* Print out interesting information */
- printk("IMR = 0x%04x", imr);
- if (imr & (1 << shpnt->irq))
- printk(" (masked)");
- printk(", IRR = 0x%04x, ISR = 0x%04x\n", irr, isr);
-
- printk("SCSI Status = 0x%02x\n", inb(SCSI_Status_port));
- printk("TMC Status = 0x%02x", inb(TMC_Status_port));
- if (inb(TMC_Status_port) & 1)
- printk(" (interrupt)");
- printk("\n");
- printk("Interrupt Status = 0x%02x", inb(Interrupt_Status_port));
- if (inb(Interrupt_Status_port) & 0x08)
- printk(" (enabled)");
- printk("\n");
- if (chip == tmc18c50 || chip == tmc18c30) {
- printk("FIFO Status = 0x%02x\n", inb(shpnt->io_port + FIFO_Status));
- printk("Int. Condition = 0x%02x\n", inb(shpnt->io_port + Interrupt_Cond));
- }
- printk("Configuration 1 = 0x%02x\n", inb(shpnt->io_port + Configuration1));
- if (chip == tmc18c50 || chip == tmc18c30)
- printk("Configuration 2 = 0x%02x\n", inb(shpnt->io_port + Configuration2));
-}
-#endif
-
-static int fd_mcs_abort(Scsi_Cmnd * SCpnt)
-{
- struct Scsi_Host *shpnt = SCpnt->device->host;
-
- unsigned long flags;
-#if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT
- printk("fd_mcs: abort ");
-#endif
-
- spin_lock_irqsave(shpnt->host_lock, flags);
- if (!in_command) {
-#if EVERY_ACCESS || ERRORS_ONLY
- printk(" (not in command)\n");
-#endif
- spin_unlock_irqrestore(shpnt->host_lock, flags);
- return FAILED;
- } else
- printk("\n");
-
-#if DEBUG_ABORT
- fd_mcs_print_info(SCpnt);
-#endif
-
- fd_mcs_make_bus_idle(shpnt);
-
- current_SC->SCp.phase |= aborted;
-
- current_SC->result = DID_ABORT << 16;
-
- /* Aborts are not done well. . . */
- my_done(shpnt, DID_ABORT << 16);
-
- spin_unlock_irqrestore(shpnt->host_lock, flags);
- return SUCCESS;
-}
-
-static int fd_mcs_bus_reset(Scsi_Cmnd * SCpnt) {
- struct Scsi_Host *shpnt = SCpnt->device->host;
- unsigned long flags;
-
-#if DEBUG_RESET
- static int called_once = 0;
-#endif
-
-#if ERRORS_ONLY
- if (SCpnt)
- printk("fd_mcs: SCSI Bus Reset\n");
-#endif
-
-#if DEBUG_RESET
- if (called_once)
- fd_mcs_print_info(current_SC);
- called_once = 1;
-#endif
-
- spin_lock_irqsave(shpnt->host_lock, flags);
-
- outb(1, SCSI_Cntl_port);
- do_pause(2);
- outb(0, SCSI_Cntl_port);
- do_pause(115);
- outb(0, SCSI_Mode_Cntl_port);
- outb(PARITY_MASK, TMC_Cntl_port);
-
- spin_unlock_irqrestore(shpnt->host_lock, flags);
-
- /* Unless this is the very first call (i.e., SCPnt == NULL), everything
- is probably hosed at this point. We will, however, try to keep
- things going by informing the high-level code that we need help. */
- return SUCCESS;
-}
-
-#include <scsi/scsi_ioctl.h>
-
-static int fd_mcs_biosparam(struct scsi_device * disk, struct block_device *bdev,
- sector_t capacity, int *info_array)
-{
- unsigned char *p = scsi_bios_ptable(bdev);
- int size = capacity;
-
- /* BIOS >= 3.4 for MCA cards */
- /* This algorithm was provided by Future Domain (much thanks!). */
-
- if (p && p[65] == 0xaa && p[64] == 0x55 /* Partition table valid */
- && p[4]) { /* Partition type */
- /* The partition table layout is as follows:
-
- Start: 0x1b3h
- Offset: 0 = partition status
- 1 = starting head
- 2 = starting sector and cylinder (word, encoded)
- 4 = partition type
- 5 = ending head
- 6 = ending sector and cylinder (word, encoded)
- 8 = starting absolute sector (double word)
- c = number of sectors (double word)
- Signature: 0x1fe = 0x55aa
-
- So, this algorithm assumes:
- 1) the first partition table is in use,
- 2) the data in the first entry is correct, and
- 3) partitions never divide cylinders
-
- Note that (1) may be FALSE for NetBSD (and other BSD flavors),
- as well as for Linux. Note also, that Linux doesn't pay any
- attention to the fields that are used by this algorithm -- it
- only uses the absolute sector data. Recent versions of Linux's
- fdisk(1) will fill this data in correctly, and forthcoming
- versions will check for consistency.
-
- Checking for a non-zero partition type is not part of the
- Future Domain algorithm, but it seemed to be a reasonable thing
- to do, especially in the Linux and BSD worlds. */
-
- info_array[0] = p[5] + 1; /* heads */
- info_array[1] = p[6] & 0x3f; /* sectors */
- } else {
- /* Note that this new method guarantees that there will always be
- less than 1024 cylinders on a platter. This is good for drives
- up to approximately 7.85GB (where 1GB = 1024 * 1024 kB). */
- if ((unsigned int) size >= 0x7e0000U)
- {
- info_array[0] = 0xff; /* heads = 255 */
- info_array[1] = 0x3f; /* sectors = 63 */
- } else if ((unsigned int) size >= 0x200000U) {
- info_array[0] = 0x80; /* heads = 128 */
- info_array[1] = 0x3f; /* sectors = 63 */
- } else {
- info_array[0] = 0x40; /* heads = 64 */
- info_array[1] = 0x20; /* sectors = 32 */
- }
- }
- /* For both methods, compute the cylinders */
- info_array[2] = (unsigned int) size / (info_array[0] * info_array[1]);
- kfree(p);
- return 0;
-}
-
-static struct scsi_host_template driver_template = {
- .proc_name = "fd_mcs",
- .proc_info = fd_mcs_proc_info,
- .detect = fd_mcs_detect,
- .release = fd_mcs_release,
- .info = fd_mcs_info,
- .queuecommand = fd_mcs_queue,
- .eh_abort_handler = fd_mcs_abort,
- .eh_bus_reset_handler = fd_mcs_bus_reset,
- .bios_param = fd_mcs_biosparam,
- .can_queue = 1,
- .this_id = 7,
- .sg_tablesize = 64,
- .cmd_per_lun = 1,
- .use_clustering = DISABLE_CLUSTERING,
-};
-#include "scsi_module.c"
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
deleted file mode 100644
index cd09132d5d7d..000000000000
--- a/drivers/scsi/ibmmca.c
+++ /dev/null
@@ -1,2379 +0,0 @@
-/*
- Low Level Linux Driver for the IBM Microchannel SCSI Subsystem for
- Linux Kernel >= 2.4.0.
- Copyright (c) 1995 Strom Systems, Inc. under the terms of the GNU
- General Public License. Written by Martin Kolinek, December 1995.
- Further development by: Chris Beauregard, Klaus Kudielka, Michael Lang
- See the file Documentation/scsi/ibmmca.txt for a detailed description
- of this driver, the commandline arguments and the history of its
- development.
- See the WWW-page: http://www.uni-mainz.de/~langm000/linux.html for latest
- updates, info and ADF-files for adapters supported by this driver.
-
- Alan Cox <alan@lxorguk.ukuu.org.uk>
- Updated for Linux 2.5.45 to use the new error handler, cleaned up the
- lock macros and did a few unavoidable locking tweaks, plus one locking
- fix in the irq and completion path.
-
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/ctype.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/blkdev.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/mca.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-
-/* Common forward declarations for all Linux-versions: */
-static int ibmmca_queuecommand (struct Scsi_Host *, struct scsi_cmnd *);
-static int ibmmca_abort (Scsi_Cmnd *);
-static int ibmmca_host_reset (Scsi_Cmnd *);
-static int ibmmca_biosparam (struct scsi_device *, struct block_device *, sector_t, int *);
-static int ibmmca_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, int inout);
-
-
-
-/* current version of this driver-source: */
-#define IBMMCA_SCSI_DRIVER_VERSION "4.0b-ac"
-
-/* driver configuration */
-#define IM_MAX_HOSTS 8 /* maximum number of host adapters */
-#define IM_RESET_DELAY 60 /* seconds allowed for a reset */
-
-/* driver debugging - #undef all for normal operation */
-/* if defined: count interrupts and ignore this special one: */
-#undef IM_DEBUG_TIMEOUT //50
-#define TIMEOUT_PUN 0
-#define TIMEOUT_LUN 0
-/* verbose interrupt: */
-#undef IM_DEBUG_INT
-/* verbose queuecommand: */
-#undef IM_DEBUG_CMD
-/* verbose queucommand for specific SCSI-device type: */
-#undef IM_DEBUG_CMD_SPEC_DEV
-/* verbose device probing */
-#undef IM_DEBUG_PROBE
-
-/* device type that shall be displayed on syslog (only during debugging): */
-#define IM_DEBUG_CMD_DEVICE TYPE_TAPE
-
-/* relative addresses of hardware registers on a subsystem */
-#define IM_CMD_REG(h) ((h)->io_port) /*Command Interface, (4 bytes long) */
-#define IM_ATTN_REG(h) ((h)->io_port+4) /*Attention (1 byte) */
-#define IM_CTR_REG(h) ((h)->io_port+5) /*Basic Control (1 byte) */
-#define IM_INTR_REG(h) ((h)->io_port+6) /*Interrupt Status (1 byte, r/o) */
-#define IM_STAT_REG(h) ((h)->io_port+7) /*Basic Status (1 byte, read only) */
-
-/* basic I/O-port of first adapter */
-#define IM_IO_PORT 0x3540
-/* maximum number of hosts that can be found */
-#define IM_N_IO_PORT 8
-
-/*requests going into the upper nibble of the Attention register */
-/*note: the lower nibble specifies the device(0-14), or subsystem(15) */
-#define IM_IMM_CMD 0x10 /*immediate command */
-#define IM_SCB 0x30 /*Subsystem Control Block command */
-#define IM_LONG_SCB 0x40 /*long Subsystem Control Block command */
-#define IM_EOI 0xe0 /*end-of-interrupt request */
-
-/*values for bits 7,1,0 of Basic Control reg. (bits 6-2 reserved) */
-#define IM_HW_RESET 0x80 /*hardware reset */
-#define IM_ENABLE_DMA 0x02 /*enable subsystem's busmaster DMA */
-#define IM_ENABLE_INTR 0x01 /*enable interrupts to the system */
-
-/*to interpret the upper nibble of Interrupt Status register */
-/*note: the lower nibble specifies the device(0-14), or subsystem(15) */
-#define IM_SCB_CMD_COMPLETED 0x10
-#define IM_SCB_CMD_COMPLETED_WITH_RETRIES 0x50
-#define IM_LOOP_SCATTER_BUFFER_FULL 0x60
-#define IM_ADAPTER_HW_FAILURE 0x70
-#define IM_IMMEDIATE_CMD_COMPLETED 0xa0
-#define IM_CMD_COMPLETED_WITH_FAILURE 0xc0
-#define IM_CMD_ERROR 0xe0
-#define IM_SOFTWARE_SEQUENCING_ERROR 0xf0
-
-/*to interpret bits 3-0 of Basic Status register (bits 7-4 reserved) */
-#define IM_CMD_REG_FULL 0x08
-#define IM_CMD_REG_EMPTY 0x04
-#define IM_INTR_REQUEST 0x02
-#define IM_BUSY 0x01
-
-/*immediate commands (word written into low 2 bytes of command reg) */
-#define IM_RESET_IMM_CMD 0x0400
-#define IM_FEATURE_CTR_IMM_CMD 0x040c
-#define IM_DMA_PACING_IMM_CMD 0x040d
-#define IM_ASSIGN_IMM_CMD 0x040e
-#define IM_ABORT_IMM_CMD 0x040f
-#define IM_FORMAT_PREP_IMM_CMD 0x0417
-
-/*SCB (Subsystem Control Block) structure */
-struct im_scb {
- unsigned short command; /*command word (read, etc.) */
- unsigned short enable; /*enable word, modifies cmd */
- union {
- unsigned long log_blk_adr; /*block address on SCSI device */
- unsigned char scsi_cmd_length; /*6,10,12, for other scsi cmd */
- } u1;
- unsigned long sys_buf_adr; /*physical system memory adr */
- unsigned long sys_buf_length; /*size of sys mem buffer */
- unsigned long tsb_adr; /*Termination Status Block adr */
- unsigned long scb_chain_adr; /*optional SCB chain address */
- union {
- struct {
- unsigned short count; /*block count, on SCSI device */
- unsigned short length; /*block length, on SCSI device */
- } blk;
- unsigned char scsi_command[12]; /*other scsi command */
- } u2;
-};
-
-/*structure scatter-gather element (for list of system memory areas) */
-struct im_sge {
- void *address;
- unsigned long byte_length;
-};
-
-/*structure returned by a get_pos_info command: */
-struct im_pos_info {
- unsigned short pos_id; /* adapter id */
- unsigned char pos_3a; /* pos 3 (if pos 6 = 0) */
- unsigned char pos_2; /* pos 2 */
- unsigned char int_level; /* interrupt level IRQ 11 or 14 */
- unsigned char pos_4a; /* pos 4 (if pos 6 = 0) */
- unsigned short connector_size; /* MCA connector size: 16 or 32 Bit */
- unsigned char num_luns; /* number of supported luns per device */
- unsigned char num_puns; /* number of supported puns */
- unsigned char pacing_factor; /* pacing factor */
- unsigned char num_ldns; /* number of ldns available */
- unsigned char eoi_off; /* time EOI and interrupt inactive */
- unsigned char max_busy; /* time between reset and busy on */
- unsigned short cache_stat; /* ldn cachestat. Bit=1 = not cached */
- unsigned short retry_stat; /* retry status of ldns. Bit=1=disabled */
- unsigned char pos_4b; /* pos 4 (if pos 6 = 1) */
- unsigned char pos_3b; /* pos 3 (if pos 6 = 1) */
- unsigned char pos_6; /* pos 6 */
- unsigned char pos_5; /* pos 5 */
- unsigned short max_overlap; /* maximum overlapping requests */
- unsigned short num_bus; /* number of SCSI-busses */
-};
-
-/*values for SCB command word */
-#define IM_NO_SYNCHRONOUS 0x0040 /*flag for any command */
-#define IM_NO_DISCONNECT 0x0080 /*flag for any command */
-#define IM_READ_DATA_CMD 0x1c01
-#define IM_WRITE_DATA_CMD 0x1c02
-#define IM_READ_VERIFY_CMD 0x1c03
-#define IM_WRITE_VERIFY_CMD 0x1c04
-#define IM_REQUEST_SENSE_CMD 0x1c08
-#define IM_READ_CAPACITY_CMD 0x1c09
-#define IM_DEVICE_INQUIRY_CMD 0x1c0b
-#define IM_READ_LOGICAL_CMD 0x1c2a
-#define IM_OTHER_SCSI_CMD_CMD 0x241f
-
-/* unused, but supported, SCB commands */
-#define IM_GET_COMMAND_COMPLETE_STATUS_CMD 0x1c07 /* command status */
-#define IM_GET_POS_INFO_CMD 0x1c0a /* returns neat stuff */
-#define IM_READ_PREFETCH_CMD 0x1c31 /* caching controller only */
-#define IM_FOMAT_UNIT_CMD 0x1c16 /* format unit */
-#define IM_REASSIGN_BLOCK_CMD 0x1c18 /* in case of error */
-
-/*values to set bits in the enable word of SCB */
-#define IM_READ_CONTROL 0x8000
-#define IM_REPORT_TSB_ONLY_ON_ERROR 0x4000
-#define IM_RETRY_ENABLE 0x2000
-#define IM_POINTER_TO_LIST 0x1000
-#define IM_SUPRESS_EXCEPTION_SHORT 0x0400
-#define IM_BYPASS_BUFFER 0x0200
-#define IM_CHAIN_ON_NO_ERROR 0x0001
-
-/*TSB (Termination Status Block) structure */
-struct im_tsb {
- unsigned short end_status;
- unsigned short reserved1;
- unsigned long residual_byte_count;
- unsigned long sg_list_element_adr;
- unsigned short status_length;
- unsigned char dev_status;
- unsigned char cmd_status;
- unsigned char dev_error;
- unsigned char cmd_error;
- unsigned short reserved2;
- unsigned short reserved3;
- unsigned short low_of_last_scb_adr;
- unsigned short high_of_last_scb_adr;
-};
-
-/*subsystem uses interrupt request level 14 */
-#define IM_IRQ 14
-/*SCSI-2 F/W may evade to interrupt 11 */
-#define IM_IRQ_FW 11
-
-/* Model 95 has an additional alphanumeric display, which can be used
- to display SCSI-activities. 8595 models do not have any disk led, which
- makes this feature quite useful.
- The regular PS/2 disk led is turned on/off by bits 6,7 of system
- control port. */
-
-/* LED display-port (actually, last LED on display) */
-#define MOD95_LED_PORT 0x108
-/* system-control-register of PS/2s with diskindicator */
-#define PS2_SYS_CTR 0x92
-/* activity displaying methods */
-#define LED_DISP 1
-#define LED_ADISP 2
-#define LED_ACTIVITY 4
-/* failed intr */
-#define CMD_FAIL 255
-
-/* The SCSI-ID(!) of the accessed SCSI-device is shown on PS/2-95 machines' LED
- displays. ldn is no longer displayed here, because the ldn mapping is now
- done dynamically and the ldn <-> pun,lun maps can be looked-up at boottime
- or during uptime in /proc/scsi/ibmmca/<host_no> in case of trouble,
- interest, debugging or just for having fun. The left number gives the
- host-adapter number and the right shows the accessed SCSI-ID. */
-
-/* display_mode is set by the ibmmcascsi= command line arg */
-static int display_mode = 0;
-/* set default adapter timeout */
-static unsigned int adapter_timeout = 45;
-/* for probing on feature-command: */
-static unsigned int global_command_error_excuse = 0;
-/* global setting by command line for adapter_speed */
-static int global_adapter_speed = 0; /* full speed by default */
-
-/* Panel / LED on, do it right for F/W addressin, too. adisplay will
- * just ignore ids>7, as the panel has only 7 digits available */
-#define PS2_DISK_LED_ON(ad,id) { if (display_mode & LED_DISP) { if (id>9) \
- outw((ad+48)|((id+55)<<8), MOD95_LED_PORT ); else \
- outw((ad+48)|((id+48)<<8), MOD95_LED_PORT ); } else \
- if (display_mode & LED_ADISP) { if (id<7) outb((char)(id+48),MOD95_LED_PORT+1+id); \
- outb((char)(ad+48), MOD95_LED_PORT); } \
- if ((display_mode & LED_ACTIVITY)||(!display_mode)) \
- outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR); }
-
-/* Panel / LED off */
-/* bug fixed, Dec 15, 1997, where | was replaced by & here */
-#define PS2_DISK_LED_OFF() { if (display_mode & LED_DISP) \
- outw(0x2020, MOD95_LED_PORT ); else if (display_mode & LED_ADISP) { \
- outl(0x20202020,MOD95_LED_PORT); outl(0x20202020,MOD95_LED_PORT+4); } \
- if ((display_mode & LED_ACTIVITY)||(!display_mode)) \
- outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); }
-
-/* types of different supported hardware that goes to hostdata special */
-#define IBM_SCSI2_FW 0
-#define IBM_7568_WCACHE 1
-#define IBM_EXP_UNIT 2
-#define IBM_SCSI_WCACHE 3
-#define IBM_SCSI 4
-#define IBM_INTEGSCSI 5
-
-/* other special flags for hostdata structure */
-#define FORCED_DETECTION 100
-#define INTEGRATED_SCSI 101
-
-/* List of possible IBM-SCSI-adapters */
-static short ibmmca_id_table[] = {
- 0x8efc,
- 0x8efd,
- 0x8ef8,
- 0x8eff,
- 0x8efe,
- /* No entry for integrated SCSI, that's part of the register */
- 0
-};
-
-static const char *ibmmca_description[] = {
- "IBM SCSI-2 F/W Adapter", /* special = 0 */
- "IBM 7568 Industrial Computer SCSI Adapter w/Cache", /* special = 1 */
- "IBM Expansion Unit SCSI Controller", /* special = 2 */
- "IBM SCSI Adapter w/Cache", /* special = 3 */
- "IBM SCSI Adapter", /* special = 4 */
- "IBM Integrated SCSI Controller", /* special = 5 */
-};
-
-/* Max number of logical devices (can be up from 0 to 14). 15 is the address
-of the adapter itself. */
-#define MAX_LOG_DEV 15
-
-/*local data for a logical device */
-struct logical_device {
- struct im_scb scb; /* SCSI-subsystem-control-block structure */
- struct im_tsb tsb; /* SCSI command complete status block structure */
- struct im_sge sge[16]; /* scatter gather list structure */
- unsigned char buf[256]; /* SCSI command return data buffer */
- Scsi_Cmnd *cmd; /* SCSI-command that is currently in progress */
- int device_type; /* type of the SCSI-device. See include/scsi/scsi.h
- for interpretation of the possible values */
- int block_length; /* blocksize of a particular logical SCSI-device */
- int cache_flag; /* 1 if this is uncached, 0 if cache is present for ldn */
- int retry_flag; /* 1 if adapter retry is disabled, 0 if enabled */
-};
-
-/* statistics of the driver during operations (for proc_info) */
-struct Driver_Statistics {
- /* SCSI statistics on the adapter */
- int ldn_access[MAX_LOG_DEV + 1]; /* total accesses on a ldn */
- int ldn_read_access[MAX_LOG_DEV + 1]; /* total read-access on a ldn */
- int ldn_write_access[MAX_LOG_DEV + 1]; /* total write-access on a ldn */
- int ldn_inquiry_access[MAX_LOG_DEV + 1]; /* total inquiries on a ldn */
- int ldn_modeselect_access[MAX_LOG_DEV + 1]; /* total mode selects on ldn */
- int scbs; /* short SCBs queued */
- int long_scbs; /* long SCBs queued */
- int total_accesses; /* total accesses on all ldns */
- int total_interrupts; /* total interrupts (should be
- same as total_accesses) */
- int total_errors; /* command completed with error */
- /* dynamical assignment statistics */
- int total_scsi_devices; /* number of physical pun,lun */
- int dyn_flag; /* flag showing dynamical mode */
- int dynamical_assignments; /* number of remappings of ldns */
- int ldn_assignments[MAX_LOG_DEV + 1]; /* number of remappings of each
- ldn */
-};
-
-/* data structure for each host adapter */
-struct ibmmca_hostdata {
- /* array of logical devices: */
- struct logical_device _ld[MAX_LOG_DEV + 1];
- /* array to convert (pun, lun) into logical device number: */
- unsigned char _get_ldn[16][8];
- /*array that contains the information about the physical SCSI-devices
- attached to this host adapter: */
- unsigned char _get_scsi[16][8];
- /* used only when checking logical devices: */
- int _local_checking_phase_flag;
- /* report received interrupt: */
- int _got_interrupt;
- /* report termination-status of SCSI-command: */
- int _stat_result;
- /* reset status (used only when doing reset): */
- int _reset_status;
- /* code of the last SCSI command (needed for panic info): */
- int _last_scsi_command[MAX_LOG_DEV + 1];
- /* identifier of the last SCSI-command type */
- int _last_scsi_type[MAX_LOG_DEV + 1];
- /* last blockcount */
- int _last_scsi_blockcount[MAX_LOG_DEV + 1];
- /* last locgical block address */
- unsigned long _last_scsi_logical_block[MAX_LOG_DEV + 1];
- /* Counter that points on the next reassignable ldn for dynamical
- remapping. The default value is 7, that is the first reassignable
- number in the list at boottime: */
- int _next_ldn;
- /* Statistics-structure for this IBM-SCSI-host: */
- struct Driver_Statistics _IBM_DS;
- /* This hostadapters pos-registers pos2 until pos6 */
- unsigned int _pos[8];
- /* assign a special variable, that contains dedicated info about the
- adaptertype */
- int _special;
- /* connector size on the MCA bus */
- int _connector_size;
- /* synchronous SCSI transfer rate bitpattern */
- int _adapter_speed;
-};
-
-/* macros to access host data structure */
-#define subsystem_pun(h) ((h)->this_id)
-#define subsystem_maxid(h) ((h)->max_id)
-#define ld(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_ld)
-#define get_ldn(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_get_ldn)
-#define get_scsi(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_get_scsi)
-#define local_checking_phase_flag(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_local_checking_phase_flag)
-#define got_interrupt(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_got_interrupt)
-#define stat_result(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_stat_result)
-#define reset_status(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_reset_status)
-#define last_scsi_command(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_command)
-#define last_scsi_type(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_type)
-#define last_scsi_blockcount(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_blockcount)
-#define last_scsi_logical_block(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_logical_block)
-#define last_scsi_type(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_type)
-#define next_ldn(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_next_ldn)
-#define IBM_DS(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_IBM_DS)
-#define special(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_special)
-#define subsystem_connector_size(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_connector_size)
-#define adapter_speed(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_adapter_speed)
-#define pos2(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[2])
-#define pos3(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[3])
-#define pos4(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[4])
-#define pos5(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[5])
-#define pos6(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[6])
-
-/* Define a arbitrary number as subsystem-marker-type. This number is, as
- described in the ANSI-SCSI-standard, not occupied by other device-types. */
-#define TYPE_IBM_SCSI_ADAPTER 0x2F
-
-/* Define 0xFF for no device type, because this type is not defined within
- the ANSI-SCSI-standard, therefore, it can be used and should not cause any
- harm. */
-#define TYPE_NO_DEVICE 0xFF
-
-/* define medium-changer. If this is not defined previously, e.g. Linux
- 2.0.x, define this type here. */
-#ifndef TYPE_MEDIUM_CHANGER
-#define TYPE_MEDIUM_CHANGER 0x08
-#endif
-
-/* define possible operations for the immediate_assign command */
-#define SET_LDN 0
-#define REMOVE_LDN 1
-
-/* ldn which is used to probe the SCSI devices */
-#define PROBE_LDN 0
-
-/* reset status flag contents */
-#define IM_RESET_NOT_IN_PROGRESS 0
-#define IM_RESET_IN_PROGRESS 1
-#define IM_RESET_FINISHED_OK 2
-#define IM_RESET_FINISHED_FAIL 3
-#define IM_RESET_NOT_IN_PROGRESS_NO_INT 4
-#define IM_RESET_FINISHED_OK_NO_INT 5
-
-/* define undefined SCSI-command */
-#define NO_SCSI 0xffff
-
-/*-----------------------------------------------------------------------*/
-
-/* if this is nonzero, ibmmcascsi option has been passed to the kernel */
-static int io_port[IM_MAX_HOSTS] = { 0, 0, 0, 0, 0, 0, 0, 0 };
-static int scsi_id[IM_MAX_HOSTS] = { 7, 7, 7, 7, 7, 7, 7, 7 };
-
-/* fill module-parameters only, when this define is present.
- (that is kernel version 2.1.x) */
-#if defined(MODULE)
-static char *boot_options = NULL;
-module_param(boot_options, charp, 0);
-module_param_array(io_port, int, NULL, 0);
-module_param_array(scsi_id, int, NULL, 0);
-
-MODULE_LICENSE("GPL");
-#endif
-/*counter of concurrent disk read/writes, to turn on/off disk led */
-static int disk_rw_in_progress = 0;
-
-static unsigned int pos[8]; /* whole pos register-line for diagnosis */
-/* Taking into account the additions, made by ZP Gu.
- * This selects now the preset value from the configfile and
- * offers the 'normal' commandline option to be accepted */
-#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD
-static char ibm_ansi_order = 1;
-#else
-static char ibm_ansi_order = 0;
-#endif
-
-static void issue_cmd(struct Scsi_Host *, unsigned long, unsigned char);
-static void internal_done(Scsi_Cmnd * cmd);
-static void check_devices(struct Scsi_Host *, int);
-static int immediate_assign(struct Scsi_Host *, unsigned int, unsigned int, unsigned int, unsigned int);
-static int immediate_feature(struct Scsi_Host *, unsigned int, unsigned int);
-#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
-static int immediate_reset(struct Scsi_Host *, unsigned int);
-#endif
-static int device_inquiry(struct Scsi_Host *, int);
-static int read_capacity(struct Scsi_Host *, int);
-static int get_pos_info(struct Scsi_Host *);
-static char *ti_p(int);
-static char *ti_l(int);
-static char *ibmrate(unsigned int, int);
-static int probe_display(int);
-static int probe_bus_mode(struct Scsi_Host *);
-static int device_exists(struct Scsi_Host *, int, int *, int *);
-static int option_setup(char *);
-/* local functions needed for proc_info */
-static int ldn_access_load(struct Scsi_Host *, int);
-static int ldn_access_total_read_write(struct Scsi_Host *);
-
-static irqreturn_t interrupt_handler(int irq, void *dev_id)
-{
- unsigned int intr_reg;
- unsigned int cmd_result;
- unsigned int ldn;
- unsigned long flags;
- Scsi_Cmnd *cmd;
- int lastSCSI;
- struct device *dev = dev_id;
- struct Scsi_Host *shpnt = dev_get_drvdata(dev);
-
- spin_lock_irqsave(shpnt->host_lock, flags);
-
- if(!(inb(IM_STAT_REG(shpnt)) & IM_INTR_REQUEST)) {
- spin_unlock_irqrestore(shpnt->host_lock, flags);
- return IRQ_NONE;
- }
-
- /* the reset-function already did all the job, even ints got
- renabled on the subsystem, so just return */
- if ((reset_status(shpnt) == IM_RESET_NOT_IN_PROGRESS_NO_INT) || (reset_status(shpnt) == IM_RESET_FINISHED_OK_NO_INT)) {
- reset_status(shpnt) = IM_RESET_NOT_IN_PROGRESS;
- spin_unlock_irqrestore(shpnt->host_lock, flags);
- return IRQ_HANDLED;
- }
-
- /*must wait for attention reg not busy, then send EOI to subsystem */
- while (1) {
- if (!(inb(IM_STAT_REG(shpnt)) & IM_BUSY))
- break;
- cpu_relax();
- }
-
- /*get command result and logical device */
- intr_reg = (unsigned char) (inb(IM_INTR_REG(shpnt)));
- cmd_result = intr_reg & 0xf0;
- ldn = intr_reg & 0x0f;
- /* get the last_scsi_command here */
- lastSCSI = last_scsi_command(shpnt)[ldn];
- outb(IM_EOI | ldn, IM_ATTN_REG(shpnt));
-
- /*these should never happen (hw fails, or a local programming bug) */
- if (!global_command_error_excuse) {
- switch (cmd_result) {
- /* Prevent from Ooopsing on error to show the real reason */
- case IM_ADAPTER_HW_FAILURE:
- case IM_SOFTWARE_SEQUENCING_ERROR:
- case IM_CMD_ERROR:
- printk(KERN_ERR "IBM MCA SCSI: Fatal Subsystem ERROR!\n");
- printk(KERN_ERR " Last cmd=0x%x, ena=%x, len=", lastSCSI, ld(shpnt)[ldn].scb.enable);
- if (ld(shpnt)[ldn].cmd)
- printk("%ld/%ld,", (long) (scsi_bufflen(ld(shpnt)[ldn].cmd)), (long) (ld(shpnt)[ldn].scb.sys_buf_length));
- else
- printk("none,");
- if (ld(shpnt)[ldn].cmd)
- printk("Blocksize=%d", ld(shpnt)[ldn].scb.u2.blk.length);
- else
- printk("Blocksize=none");
- printk(", host=%p, ldn=0x%x\n", shpnt, ldn);
- if (ld(shpnt)[ldn].cmd) {
- printk(KERN_ERR "Blockcount=%d/%d\n", last_scsi_blockcount(shpnt)[ldn], ld(shpnt)[ldn].scb.u2.blk.count);
- printk(KERN_ERR "Logical block=%lx/%lx\n", last_scsi_logical_block(shpnt)[ldn], ld(shpnt)[ldn].scb.u1.log_blk_adr);
- }
- printk(KERN_ERR "Reason given: %s\n", (cmd_result == IM_ADAPTER_HW_FAILURE) ? "HARDWARE FAILURE" : (cmd_result == IM_SOFTWARE_SEQUENCING_ERROR) ? "SOFTWARE SEQUENCING ERROR" : (cmd_result == IM_CMD_ERROR) ? "COMMAND ERROR" : "UNKNOWN");
- /* if errors appear, enter this section to give detailed info */
- printk(KERN_ERR "IBM MCA SCSI: Subsystem Error-Status follows:\n");
- printk(KERN_ERR " Command Type................: %x\n", last_scsi_type(shpnt)[ldn]);
- printk(KERN_ERR " Attention Register..........: %x\n", inb(IM_ATTN_REG(shpnt)));
- printk(KERN_ERR " Basic Control Register......: %x\n", inb(IM_CTR_REG(shpnt)));
- printk(KERN_ERR " Interrupt Status Register...: %x\n", intr_reg);
- printk(KERN_ERR " Basic Status Register.......: %x\n", inb(IM_STAT_REG(shpnt)));
- if ((last_scsi_type(shpnt)[ldn] == IM_SCB) || (last_scsi_type(shpnt)[ldn] == IM_LONG_SCB)) {
- printk(KERN_ERR " SCB-Command.................: %x\n", ld(shpnt)[ldn].scb.command);
- printk(KERN_ERR " SCB-Enable..................: %x\n", ld(shpnt)[ldn].scb.enable);
- printk(KERN_ERR " SCB-logical block address...: %lx\n", ld(shpnt)[ldn].scb.u1.log_blk_adr);
- printk(KERN_ERR " SCB-system buffer address...: %lx\n", ld(shpnt)[ldn].scb.sys_buf_adr);
- printk(KERN_ERR " SCB-system buffer length....: %lx\n", ld(shpnt)[ldn].scb.sys_buf_length);
- printk(KERN_ERR " SCB-tsb address.............: %lx\n", ld(shpnt)[ldn].scb.tsb_adr);
- printk(KERN_ERR " SCB-Chain address...........: %lx\n", ld(shpnt)[ldn].scb.scb_chain_adr);
- printk(KERN_ERR " SCB-block count.............: %x\n", ld(shpnt)[ldn].scb.u2.blk.count);
- printk(KERN_ERR " SCB-block length............: %x\n", ld(shpnt)[ldn].scb.u2.blk.length);
- }
- printk(KERN_ERR " Send this report to the maintainer.\n");
- panic("IBM MCA SCSI: Fatal error message from the subsystem (0x%X,0x%X)!\n", lastSCSI, cmd_result);
- break;
- }
- } else {
- /* The command error handling is made silent, but we tell the
- * calling function, that there is a reported error from the
- * adapter. */
- switch (cmd_result) {
- case IM_ADAPTER_HW_FAILURE:
- case IM_SOFTWARE_SEQUENCING_ERROR:
- case IM_CMD_ERROR:
- global_command_error_excuse = CMD_FAIL;
- break;
- default:
- global_command_error_excuse = 0;
- break;
- }
- }
- /* if no panic appeared, increase the interrupt-counter */
- IBM_DS(shpnt).total_interrupts++;
- /*only for local checking phase */
- if (local_checking_phase_flag(shpnt)) {
- stat_result(shpnt) = cmd_result;
- got_interrupt(shpnt) = 1;
- reset_status(shpnt) = IM_RESET_FINISHED_OK;
- last_scsi_command(shpnt)[ldn] = NO_SCSI;
- spin_unlock_irqrestore(shpnt->host_lock, flags);
- return IRQ_HANDLED;
- }
- /* handling of commands coming from upper level of scsi driver */
- if (last_scsi_type(shpnt)[ldn] == IM_IMM_CMD) {
- /* verify ldn, and may handle rare reset immediate command */
- if ((reset_status(shpnt) == IM_RESET_IN_PROGRESS) && (last_scsi_command(shpnt)[ldn] == IM_RESET_IMM_CMD)) {
- if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) {
- disk_rw_in_progress = 0;
- PS2_DISK_LED_OFF();
- reset_status(shpnt) = IM_RESET_FINISHED_FAIL;
- } else {
- /*reset disk led counter, turn off disk led */
- disk_rw_in_progress = 0;
- PS2_DISK_LED_OFF();
- reset_status(shpnt) = IM_RESET_FINISHED_OK;
- }
- stat_result(shpnt) = cmd_result;
- last_scsi_command(shpnt)[ldn] = NO_SCSI;
- last_scsi_type(shpnt)[ldn] = 0;
- spin_unlock_irqrestore(shpnt->host_lock, flags);
- return IRQ_HANDLED;
- } else if (last_scsi_command(shpnt)[ldn] == IM_ABORT_IMM_CMD) {
- /* react on SCSI abort command */
-#ifdef IM_DEBUG_PROBE
- printk("IBM MCA SCSI: Interrupt from SCSI-abort.\n");
-#endif
- disk_rw_in_progress = 0;
- PS2_DISK_LED_OFF();
- cmd = ld(shpnt)[ldn].cmd;
- ld(shpnt)[ldn].cmd = NULL;
- if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE)
- cmd->result = DID_NO_CONNECT << 16;
- else
- cmd->result = DID_ABORT << 16;
- stat_result(shpnt) = cmd_result;
- last_scsi_command(shpnt)[ldn] = NO_SCSI;
- last_scsi_type(shpnt)[ldn] = 0;
- if (cmd->scsi_done)
- (cmd->scsi_done) (cmd); /* should be the internal_done */
- spin_unlock_irqrestore(shpnt->host_lock, flags);
- return IRQ_HANDLED;
- } else {
- disk_rw_in_progress = 0;
- PS2_DISK_LED_OFF();
- reset_status(shpnt) = IM_RESET_FINISHED_OK;
- stat_result(shpnt) = cmd_result;
- last_scsi_command(shpnt)[ldn] = NO_SCSI;
- spin_unlock_irqrestore(shpnt->host_lock, flags);
- return IRQ_HANDLED;
- }
- }
- last_scsi_command(shpnt)[ldn] = NO_SCSI;
- last_scsi_type(shpnt)[ldn] = 0;
- cmd = ld(shpnt)[ldn].cmd;
- ld(shpnt)[ldn].cmd = NULL;
-#ifdef IM_DEBUG_TIMEOUT
- if (cmd) {
- if ((cmd->target == TIMEOUT_PUN) && (cmd->device->lun == TIMEOUT_LUN)) {
- spin_unlock_irqsave(shpnt->host_lock, flags);
- printk("IBM MCA SCSI: Ignoring interrupt from pun=%x, lun=%x.\n", cmd->target, cmd->device->lun);
- return IRQ_HANDLED;
- }
- }
-#endif
- /*if no command structure, just return, else clear cmd */
- if (!cmd)
- {
- spin_unlock_irqrestore(shpnt->host_lock, flags);
- return IRQ_HANDLED;
- }
-
-#ifdef IM_DEBUG_INT
- printk("cmd=%02x ireg=%02x ds=%02x cs=%02x de=%02x ce=%02x\n", cmd->cmnd[0], intr_reg, ld(shpnt)[ldn].tsb.dev_status, ld(shpnt)[ldn].tsb.cmd_status, ld(shpnt)[ldn].tsb.dev_error, ld(shpnt)[ldn].tsb.cmd_error);
-#endif
- /*if this is end of media read/write, may turn off PS/2 disk led */
- if ((ld(shpnt)[ldn].device_type != TYPE_NO_LUN) && (ld(shpnt)[ldn].device_type != TYPE_NO_DEVICE)) {
- /* only access this, if there was a valid device addressed */
- if (--disk_rw_in_progress == 0)
- PS2_DISK_LED_OFF();
- }
-
- /* IBM describes the status-mask to be 0x1e, but this is not conform
- * with SCSI-definition, I suppose, the reason for it is that IBM
- * adapters do not support CMD_TERMINATED, TASK_SET_FULL and
- * ACA_ACTIVE as returning statusbyte information. (ML) */
- if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) {
- cmd->result = (unsigned char) (ld(shpnt)[ldn].tsb.dev_status & 0x1e);
- IBM_DS(shpnt).total_errors++;
- } else
- cmd->result = 0;
- /* write device status into cmd->result, and call done function */
- if (lastSCSI == NO_SCSI) { /* unexpected interrupt :-( */
- cmd->result |= DID_BAD_INTR << 16;
- printk("IBM MCA SCSI: WARNING - Interrupt from non-pending SCSI-command!\n");
- } else /* things went right :-) */
- cmd->result |= DID_OK << 16;
- if (cmd->scsi_done)
- (cmd->scsi_done) (cmd);
- spin_unlock_irqrestore(shpnt->host_lock, flags);
- return IRQ_HANDLED;
-}
-
-static void issue_cmd(struct Scsi_Host *shpnt, unsigned long cmd_reg,
- unsigned char attn_reg)
-{
- unsigned long flags;
- /* must wait for attention reg not busy */
- while (1) {
- spin_lock_irqsave(shpnt->host_lock, flags);
- if (!(inb(IM_STAT_REG(shpnt)) & IM_BUSY))
- break;
- spin_unlock_irqrestore(shpnt->host_lock, flags);
- }
- /* write registers and enable system interrupts */
- outl(cmd_reg, IM_CMD_REG(shpnt));
- outb(attn_reg, IM_ATTN_REG(shpnt));
- spin_unlock_irqrestore(shpnt->host_lock, flags);
-}
-
-static void internal_done(Scsi_Cmnd * cmd)
-{
- cmd->SCp.Status++;
- return;
-}
-
-/* SCSI-SCB-command for device_inquiry */
-static int device_inquiry(struct Scsi_Host *shpnt, int ldn)
-{
- int retr;
- struct im_scb *scb;
- struct im_tsb *tsb;
- unsigned char *buf;
-
- scb = &(ld(shpnt)[ldn].scb);
- tsb = &(ld(shpnt)[ldn].tsb);
- buf = (unsigned char *) (&(ld(shpnt)[ldn].buf));
- ld(shpnt)[ldn].tsb.dev_status = 0; /* prepare statusblock */
- for (retr = 0; retr < 3; retr++) {
- /* fill scb with inquiry command */
- scb->command = IM_DEVICE_INQUIRY_CMD | IM_NO_DISCONNECT;
- scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_RETRY_ENABLE | IM_BYPASS_BUFFER;
- last_scsi_command(shpnt)[ldn] = IM_DEVICE_INQUIRY_CMD;
- last_scsi_type(shpnt)[ldn] = IM_SCB;
- scb->sys_buf_adr = isa_virt_to_bus(buf);
- scb->sys_buf_length = 255; /* maximum bufferlength gives max info */
- scb->tsb_adr = isa_virt_to_bus(tsb);
- /* issue scb to passed ldn, and busy wait for interrupt */
- got_interrupt(shpnt) = 0;
- issue_cmd(shpnt, isa_virt_to_bus(scb), IM_SCB | ldn);
- while (!got_interrupt(shpnt))
- barrier();
-
- /*if command successful, break */
- if ((stat_result(shpnt) == IM_SCB_CMD_COMPLETED) || (stat_result(shpnt) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
- return 1;
- }
- /*if all three retries failed, return "no device at this ldn" */
- if (retr >= 3)
- return 0;
- else
- return 1;
-}
-
-static int read_capacity(struct Scsi_Host *shpnt, int ldn)
-{
- int retr;
- struct im_scb *scb;
- struct im_tsb *tsb;
- unsigned char *buf;
-
- scb = &(ld(shpnt)[ldn].scb);
- tsb = &(ld(shpnt)[ldn].tsb);
- buf = (unsigned char *) (&(ld(shpnt)[ldn].buf));
- ld(shpnt)[ldn].tsb.dev_status = 0;
- for (retr = 0; retr < 3; retr++) {
- /*fill scb with read capacity command */
- scb->command = IM_READ_CAPACITY_CMD;
- scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_RETRY_ENABLE | IM_BYPASS_BUFFER;
- last_scsi_command(shpnt)[ldn] = IM_READ_CAPACITY_CMD;
- last_scsi_type(shpnt)[ldn] = IM_SCB;
- scb->sys_buf_adr = isa_virt_to_bus(buf);
- scb->sys_buf_length = 8;
- scb->tsb_adr = isa_virt_to_bus(tsb);
- /*issue scb to passed ldn, and busy wait for interrupt */
- got_interrupt(shpnt) = 0;
- issue_cmd(shpnt, isa_virt_to_bus(scb), IM_SCB | ldn);
- while (!got_interrupt(shpnt))
- barrier();
-
- /*if got capacity, get block length and return one device found */
- if ((stat_result(shpnt) == IM_SCB_CMD_COMPLETED) || (stat_result(shpnt) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
- return 1;
- }
- /*if all three retries failed, return "no device at this ldn" */
- if (retr >= 3)
- return 0;
- else
- return 1;
-}
-
-static int get_pos_info(struct Scsi_Host *shpnt)
-{
- int retr;
- struct im_scb *scb;
- struct im_tsb *tsb;
- unsigned char *buf;
-
- scb = &(ld(shpnt)[MAX_LOG_DEV].scb);
- tsb = &(ld(shpnt)[MAX_LOG_DEV].tsb);
- buf = (unsigned char *) (&(ld(shpnt)[MAX_LOG_DEV].buf));
- ld(shpnt)[MAX_LOG_DEV].tsb.dev_status = 0;
- for (retr = 0; retr < 3; retr++) {
- /*fill scb with get_pos_info command */
- scb->command = IM_GET_POS_INFO_CMD;
- scb->enable = IM_READ_CONTROL | IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE | IM_BYPASS_BUFFER;
- last_scsi_command(shpnt)[MAX_LOG_DEV] = IM_GET_POS_INFO_CMD;
- last_scsi_type(shpnt)[MAX_LOG_DEV] = IM_SCB;
- scb->sys_buf_adr = isa_virt_to_bus(buf);
- if (special(shpnt) == IBM_SCSI2_FW)
- scb->sys_buf_length = 256; /* get all info from F/W adapter */
- else
- scb->sys_buf_length = 18; /* get exactly 18 bytes for other SCSI */
- scb->tsb_adr = isa_virt_to_bus(tsb);
- /*issue scb to ldn=15, and busy wait for interrupt */
- got_interrupt(shpnt) = 0;
- issue_cmd(shpnt, isa_virt_to_bus(scb), IM_SCB | MAX_LOG_DEV);
-
- /* FIXME: timeout */
- while (!got_interrupt(shpnt))
- barrier();
-
- /*if got POS-stuff, get block length and return one device found */
- if ((stat_result(shpnt) == IM_SCB_CMD_COMPLETED) || (stat_result(shpnt) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
- return 1;
- }
- /* if all three retries failed, return "no device at this ldn" */
- if (retr >= 3)
- return 0;
- else
- return 1;
-}
-
-/* SCSI-immediate-command for assign. This functions maps/unmaps specific
- ldn-numbers on SCSI (PUN,LUN). It is needed for presetting of the
- subsystem and for dynamical remapping od ldns. */
-static int immediate_assign(struct Scsi_Host *shpnt, unsigned int pun,
- unsigned int lun, unsigned int ldn,
- unsigned int operation)
-{
- int retr;
- unsigned long imm_cmd;
-
- for (retr = 0; retr < 3; retr++) {
- /* select mutation level of the SCSI-adapter */
- switch (special(shpnt)) {
- case IBM_SCSI2_FW:
- imm_cmd = (unsigned long) (IM_ASSIGN_IMM_CMD);
- imm_cmd |= (unsigned long) ((lun & 7) << 24);
- imm_cmd |= (unsigned long) ((operation & 1) << 23);
- imm_cmd |= (unsigned long) ((pun & 7) << 20) | ((pun & 8) << 24);
- imm_cmd |= (unsigned long) ((ldn & 15) << 16);
- break;
- default:
- imm_cmd = inl(IM_CMD_REG(shpnt));
- imm_cmd &= (unsigned long) (0xF8000000); /* keep reserved bits */
- imm_cmd |= (unsigned long) (IM_ASSIGN_IMM_CMD);
- imm_cmd |= (unsigned long) ((lun & 7) << 24);
- imm_cmd |= (unsigned long) ((operation & 1) << 23);
- imm_cmd |= (unsigned long) ((pun & 7) << 20);
- imm_cmd |= (unsigned long) ((ldn & 15) << 16);
- break;
- }
- last_scsi_command(shpnt)[MAX_LOG_DEV] = IM_ASSIGN_IMM_CMD;
- last_scsi_type(shpnt)[MAX_LOG_DEV] = IM_IMM_CMD;
- got_interrupt(shpnt) = 0;
- issue_cmd(shpnt, (unsigned long) (imm_cmd), IM_IMM_CMD | MAX_LOG_DEV);
- while (!got_interrupt(shpnt))
- barrier();
-
- /*if command successful, break */
- if (stat_result(shpnt) == IM_IMMEDIATE_CMD_COMPLETED)
- return 1;
- }
- if (retr >= 3)
- return 0;
- else
- return 1;
-}
-
-static int immediate_feature(struct Scsi_Host *shpnt, unsigned int speed, unsigned int timeout)
-{
- int retr;
- unsigned long imm_cmd;
-
- for (retr = 0; retr < 3; retr++) {
- /* select mutation level of the SCSI-adapter */
- imm_cmd = IM_FEATURE_CTR_IMM_CMD;
- imm_cmd |= (unsigned long) ((speed & 0x7) << 29);
- imm_cmd |= (unsigned long) ((timeout & 0x1fff) << 16);
- last_scsi_command(shpnt)[MAX_LOG_DEV] = IM_FEATURE_CTR_IMM_CMD;
- last_scsi_type(shpnt)[MAX_LOG_DEV] = IM_IMM_CMD;
- got_interrupt(shpnt) = 0;
- /* we need to run into command errors in order to probe for the
- * right speed! */
- global_command_error_excuse = 1;
- issue_cmd(shpnt, (unsigned long) (imm_cmd), IM_IMM_CMD | MAX_LOG_DEV);
-
- /* FIXME: timeout */
- while (!got_interrupt(shpnt))
- barrier();
- if (global_command_error_excuse == CMD_FAIL) {
- global_command_error_excuse = 0;
- return 2;
- } else
- global_command_error_excuse = 0;
- /*if command successful, break */
- if (stat_result(shpnt) == IM_IMMEDIATE_CMD_COMPLETED)
- return 1;
- }
- if (retr >= 3)
- return 0;
- else
- return 1;
-}
-
-#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
-static int immediate_reset(struct Scsi_Host *shpnt, unsigned int ldn)
-{
- int retries;
- int ticks;
- unsigned long imm_command;
-
- for (retries = 0; retries < 3; retries++) {
- imm_command = inl(IM_CMD_REG(shpnt));
- imm_command &= (unsigned long) (0xFFFF0000); /* keep reserved bits */
- imm_command |= (unsigned long) (IM_RESET_IMM_CMD);
- last_scsi_command(shpnt)[ldn] = IM_RESET_IMM_CMD;
- last_scsi_type(shpnt)[ldn] = IM_IMM_CMD;
- got_interrupt(shpnt) = 0;
- reset_status(shpnt) = IM_RESET_IN_PROGRESS;
- issue_cmd(shpnt, (unsigned long) (imm_command), IM_IMM_CMD | ldn);
- ticks = IM_RESET_DELAY * HZ;
- while (reset_status(shpnt) == IM_RESET_IN_PROGRESS && --ticks) {
- udelay((1 + 999 / HZ) * 1000);
- barrier();
- }
- /* if reset did not complete, just complain */
- if (!ticks) {
- printk(KERN_ERR "IBM MCA SCSI: reset did not complete within %d seconds.\n", IM_RESET_DELAY);
- reset_status(shpnt) = IM_RESET_FINISHED_OK;
- /* did not work, finish */
- return 1;
- }
- /*if command successful, break */
- if (stat_result(shpnt) == IM_IMMEDIATE_CMD_COMPLETED)
- return 1;
- }
- if (retries >= 3)
- return 0;
- else
- return 1;
-}
-#endif
-
-/* type-interpreter for physical device numbers */
-static char *ti_p(int dev)
-{
- switch (dev) {
- case TYPE_IBM_SCSI_ADAPTER:
- return ("A");
- case TYPE_DISK:
- return ("D");
- case TYPE_TAPE:
- return ("T");
- case TYPE_PROCESSOR:
- return ("P");
- case TYPE_WORM:
- return ("W");
- case TYPE_ROM:
- return ("R");
- case TYPE_SCANNER:
- return ("S");
- case TYPE_MOD:
- return ("M");
- case TYPE_MEDIUM_CHANGER:
- return ("C");
- case TYPE_NO_LUN:
- return ("+"); /* show NO_LUN */
- }
- return ("-"); /* TYPE_NO_DEVICE and others */
-}
-
-/* interpreter for logical device numbers (ldn) */
-static char *ti_l(int val)
-{
- const char hex[16] = "0123456789abcdef";
- static char answer[2];
-
- answer[1] = (char) (0x0);
- if (val <= MAX_LOG_DEV)
- answer[0] = hex[val];
- else
- answer[0] = '-';
- return (char *) &answer;
-}
-
-/* transfers bitpattern of the feature command to values in MHz */
-static char *ibmrate(unsigned int speed, int i)
-{
- switch (speed) {
- case 0:
- return i ? "5.00" : "10.00";
- case 1:
- return i ? "4.00" : "8.00";
- case 2:
- return i ? "3.33" : "6.66";
- case 3:
- return i ? "2.86" : "5.00";
- case 4:
- return i ? "2.50" : "4.00";
- case 5:
- return i ? "2.22" : "3.10";
- case 6:
- return i ? "2.00" : "2.50";
- case 7:
- return i ? "1.82" : "2.00";
- }
- return "---";
-}
-
-static int probe_display(int what)
-{
- static int rotator = 0;
- const char rotor[] = "|/-\\";
-
- if (!(display_mode & LED_DISP))
- return 0;
- if (!what) {
- outl(0x20202020, MOD95_LED_PORT);
- outl(0x20202020, MOD95_LED_PORT + 4);
- } else {
- outb('S', MOD95_LED_PORT + 7);
- outb('C', MOD95_LED_PORT + 6);
- outb('S', MOD95_LED_PORT + 5);
- outb('I', MOD95_LED_PORT + 4);
- outb('i', MOD95_LED_PORT + 3);
- outb('n', MOD95_LED_PORT + 2);
- outb('i', MOD95_LED_PORT + 1);
- outb((char) (rotor[rotator]), MOD95_LED_PORT);
- rotator++;
- if (rotator > 3)
- rotator = 0;
- }
- return 0;
-}
-
-static int probe_bus_mode(struct Scsi_Host *shpnt)
-{
- struct im_pos_info *info;
- int num_bus = 0;
- int ldn;
-
- info = (struct im_pos_info *) (&(ld(shpnt)[MAX_LOG_DEV].buf));
- if (get_pos_info(shpnt)) {
- if (info->connector_size & 0xf000)
- subsystem_connector_size(shpnt) = 16;
- else
- subsystem_connector_size(shpnt) = 32;
- num_bus |= (info->pos_4b & 8) >> 3;
- for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
- if ((special(shpnt) == IBM_SCSI_WCACHE) || (special(shpnt) == IBM_7568_WCACHE)) {
- if (!((info->cache_stat >> ldn) & 1))
- ld(shpnt)[ldn].cache_flag = 0;
- }
- if (!((info->retry_stat >> ldn) & 1))
- ld(shpnt)[ldn].retry_flag = 0;
- }
-#ifdef IM_DEBUG_PROBE
- printk("IBM MCA SCSI: SCSI-Cache bits: ");
- for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
- printk("%d", ld(shpnt)[ldn].cache_flag);
- }
- printk("\nIBM MCA SCSI: SCSI-Retry bits: ");
- for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
- printk("%d", ld(shpnt)[ldn].retry_flag);
- }
- printk("\n");
-#endif
- }
- return num_bus;
-}
-
-/* probing scsi devices */
-static void check_devices(struct Scsi_Host *shpnt, int adaptertype)
-{
- int id, lun, ldn, ticks;
- int count_devices; /* local counter for connected device */
- int max_pun;
- int num_bus;
- int speedrun; /* local adapter_speed check variable */
-
- /* assign default values to certain variables */
- ticks = 0;
- count_devices = 0;
- IBM_DS(shpnt).dyn_flag = 0; /* normally no need for dynamical ldn management */
- IBM_DS(shpnt).total_errors = 0; /* set errorcounter to 0 */
- next_ldn(shpnt) = 7; /* next ldn to be assigned is 7, because 0-6 is 'hardwired' */
-
- /* initialize the very important driver-informational arrays/structs */
- memset(ld(shpnt), 0, sizeof(ld(shpnt)));
- for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
- last_scsi_command(shpnt)[ldn] = NO_SCSI; /* emptify last SCSI-command storage */
- last_scsi_type(shpnt)[ldn] = 0;
- ld(shpnt)[ldn].cache_flag = 1;
- ld(shpnt)[ldn].retry_flag = 1;
- }
- memset(get_ldn(shpnt), TYPE_NO_DEVICE, sizeof(get_ldn(shpnt))); /* this is essential ! */
- memset(get_scsi(shpnt), TYPE_NO_DEVICE, sizeof(get_scsi(shpnt))); /* this is essential ! */
- for (lun = 0; lun < 8; lun++) {
- /* mark the adapter at its pun on all luns */
- get_scsi(shpnt)[subsystem_pun(shpnt)][lun] = TYPE_IBM_SCSI_ADAPTER;
- get_ldn(shpnt)[subsystem_pun(shpnt)][lun] = MAX_LOG_DEV; /* make sure, the subsystem
- ldn is active for all
- luns. */
- }
- probe_display(0); /* Supercool display usage during SCSI-probing. */
- /* This makes sense, when booting without any */
- /* monitor connected on model XX95. */
-
- /* STEP 1: */
- adapter_speed(shpnt) = global_adapter_speed;
- speedrun = adapter_speed(shpnt);
- while (immediate_feature(shpnt, speedrun, adapter_timeout) == 2) {
- probe_display(1);
- if (speedrun == 7)
- panic("IBM MCA SCSI: Cannot set Synchronous-Transfer-Rate!\n");
- speedrun++;
- if (speedrun > 7)
- speedrun = 7;
- }
- adapter_speed(shpnt) = speedrun;
- /* Get detailed information about the current adapter, necessary for
- * device operations: */
- num_bus = probe_bus_mode(shpnt);
-
- /* num_bus contains only valid data for the F/W adapter! */
- if (adaptertype == IBM_SCSI2_FW) { /* F/W SCSI adapter: */
- /* F/W adapter PUN-space extension evaluation: */
- if (num_bus) {
- printk(KERN_INFO "IBM MCA SCSI: Separate bus mode (wide-addressing enabled)\n");
- subsystem_maxid(shpnt) = 16;
- } else {
- printk(KERN_INFO "IBM MCA SCSI: Combined bus mode (wide-addressing disabled)\n");
- subsystem_maxid(shpnt) = 8;
- }
- printk(KERN_INFO "IBM MCA SCSI: Sync.-Rate (F/W: 20, Int.: 10, Ext.: %s) MBytes/s\n", ibmrate(speedrun, adaptertype));
- } else /* all other IBM SCSI adapters: */
- printk(KERN_INFO "IBM MCA SCSI: Synchronous-SCSI-Transfer-Rate: %s MBytes/s\n", ibmrate(speedrun, adaptertype));
-
- /* assign correct PUN device space */
- max_pun = subsystem_maxid(shpnt);
-
-#ifdef IM_DEBUG_PROBE
- printk("IBM MCA SCSI: Current SCSI-host index: %d\n", shpnt);
- printk("IBM MCA SCSI: Removing default logical SCSI-device mapping.");
-#else
- printk(KERN_INFO "IBM MCA SCSI: Dev. Order: %s, Mapping (takes <2min): ", (ibm_ansi_order) ? "ANSI" : "New");
-#endif
- for (ldn = 0; ldn < MAX_LOG_DEV; ldn++) {
- probe_display(1);
-#ifdef IM_DEBUG_PROBE
- printk(".");
-#endif
- immediate_assign(shpnt, 0, 0, ldn, REMOVE_LDN); /* remove ldn (wherever) */
- }
- lun = 0; /* default lun is 0 */
-#ifndef IM_DEBUG_PROBE
- printk("cleared,");
-#endif
- /* STEP 2: */
-#ifdef IM_DEBUG_PROBE
- printk("\nIBM MCA SCSI: Scanning SCSI-devices.");
-#endif
- for (id = 0; id < max_pun; id++)
-#ifdef CONFIG_SCSI_MULTI_LUN
- for (lun = 0; lun < 8; lun++)
-#endif
- {
- probe_display(1);
-#ifdef IM_DEBUG_PROBE
- printk(".");
-#endif
- if (id != subsystem_pun(shpnt)) {
- /* if pun is not the adapter: */
- /* set ldn=0 to pun,lun */
- immediate_assign(shpnt, id, lun, PROBE_LDN, SET_LDN);
- if (device_inquiry(shpnt, PROBE_LDN)) { /* probe device */
- get_scsi(shpnt)[id][lun] = (unsigned char) (ld(shpnt)[PROBE_LDN].buf[0]);
- /* entry, even for NO_LUN */
- if (ld(shpnt)[PROBE_LDN].buf[0] != TYPE_NO_LUN)
- count_devices++; /* a existing device is found */
- }
- /* remove ldn */
- immediate_assign(shpnt, id, lun, PROBE_LDN, REMOVE_LDN);
- }
- }
-#ifndef IM_DEBUG_PROBE
- printk("scanned,");
-#endif
- /* STEP 3: */
-#ifdef IM_DEBUG_PROBE
- printk("\nIBM MCA SCSI: Mapping SCSI-devices.");
-#endif
- ldn = 0;
- lun = 0;
-#ifdef CONFIG_SCSI_MULTI_LUN
- for (lun = 0; lun < 8 && ldn < MAX_LOG_DEV; lun++)
-#endif
- for (id = 0; id < max_pun && ldn < MAX_LOG_DEV; id++) {
- probe_display(1);
-#ifdef IM_DEBUG_PROBE
- printk(".");
-#endif
- if (id != subsystem_pun(shpnt)) {
- if (get_scsi(shpnt)[id][lun] != TYPE_NO_LUN && get_scsi(shpnt)[id][lun] != TYPE_NO_DEVICE) {
- /* Only map if accepted type. Always enter for
- lun == 0 to get no gaps into ldn-mapping for ldn<7. */
- immediate_assign(shpnt, id, lun, ldn, SET_LDN);
- get_ldn(shpnt)[id][lun] = ldn; /* map ldn */
- if (device_exists(shpnt, ldn, &ld(shpnt)[ldn].block_length, &ld(shpnt)[ldn].device_type)) {
-#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
- printk("resetting device at ldn=%x ... ", ldn);
- immediate_reset(shpnt, ldn);
-#endif
- ldn++;
- } else {
- /* device vanished, probably because we don't know how to
- * handle it or because it has problems */
- if (lun > 0) {
- /* remove mapping */
- get_ldn(shpnt)[id][lun] = TYPE_NO_DEVICE;
- immediate_assign(shpnt, 0, 0, ldn, REMOVE_LDN);
- } else
- ldn++;
- }
- } else if (lun == 0) {
- /* map lun == 0, even if no device exists */
- immediate_assign(shpnt, id, lun, ldn, SET_LDN);
- get_ldn(shpnt)[id][lun] = ldn; /* map ldn */
- ldn++;
- }
- }
- }
- /* STEP 4: */
-
- /* map remaining ldns to non-existing devices */
- for (lun = 1; lun < 8 && ldn < MAX_LOG_DEV; lun++)
- for (id = 0; id < max_pun && ldn < MAX_LOG_DEV; id++) {
- if (get_scsi(shpnt)[id][lun] == TYPE_NO_LUN || get_scsi(shpnt)[id][lun] == TYPE_NO_DEVICE) {
- probe_display(1);
- /* Map remaining ldns only to NON-existing pun,lun
- combinations to make sure an inquiry will fail.
- For MULTI_LUN, it is needed to avoid adapter autonome
- SCSI-remapping. */
- immediate_assign(shpnt, id, lun, ldn, SET_LDN);
- get_ldn(shpnt)[id][lun] = ldn;
- ldn++;
- }
- }
-#ifndef IM_DEBUG_PROBE
- printk("mapped.");
-#endif
- printk("\n");
-#ifdef IM_DEBUG_PROBE
- if (ibm_ansi_order)
- printk("IBM MCA SCSI: Device order: IBM/ANSI (pun=7 is first).\n");
- else
- printk("IBM MCA SCSI: Device order: New Industry Standard (pun=0 is first).\n");
-#endif
-
-#ifdef IM_DEBUG_PROBE
- /* Show the physical and logical mapping during boot. */
- printk("IBM MCA SCSI: Determined SCSI-device-mapping:\n");
- printk(" Physical SCSI-Device Map Logical SCSI-Device Map\n");
- printk("ID\\LUN 0 1 2 3 4 5 6 7 ID\\LUN 0 1 2 3 4 5 6 7\n");
- for (id = 0; id < max_pun; id++) {
- printk("%2d ", id);
- for (lun = 0; lun < 8; lun++)
- printk("%2s ", ti_p(get_scsi(shpnt)[id][lun]));
- printk(" %2d ", id);
- for (lun = 0; lun < 8; lun++)
- printk("%2s ", ti_l(get_ldn(shpnt)[id][lun]));
- printk("\n");
- }
-#endif
-
- /* assign total number of found SCSI-devices to the statistics struct */
- IBM_DS(shpnt).total_scsi_devices = count_devices;
-
- /* decide for output in /proc-filesystem, if the configuration of
- SCSI-devices makes dynamical reassignment of devices necessary */
- if (count_devices >= MAX_LOG_DEV)
- IBM_DS(shpnt).dyn_flag = 1; /* dynamical assignment is necessary */
- else
- IBM_DS(shpnt).dyn_flag = 0; /* dynamical assignment is not necessary */
-
- /* If no SCSI-devices are assigned, return 1 in order to cause message. */
- if (ldn == 0)
- printk("IBM MCA SCSI: Warning: No SCSI-devices found/assigned!\n");
-
- /* reset the counters for statistics on the current adapter */
- IBM_DS(shpnt).scbs = 0;
- IBM_DS(shpnt).long_scbs = 0;
- IBM_DS(shpnt).total_accesses = 0;
- IBM_DS(shpnt).total_interrupts = 0;
- IBM_DS(shpnt).dynamical_assignments = 0;
- memset(IBM_DS(shpnt).ldn_access, 0x0, sizeof(IBM_DS(shpnt).ldn_access));
- memset(IBM_DS(shpnt).ldn_read_access, 0x0, sizeof(IBM_DS(shpnt).ldn_read_access));
- memset(IBM_DS(shpnt).ldn_write_access, 0x0, sizeof(IBM_DS(shpnt).ldn_write_access));
- memset(IBM_DS(shpnt).ldn_inquiry_access, 0x0, sizeof(IBM_DS(shpnt).ldn_inquiry_access));
- memset(IBM_DS(shpnt).ldn_modeselect_access, 0x0, sizeof(IBM_DS(shpnt).ldn_modeselect_access));
- memset(IBM_DS(shpnt).ldn_assignments, 0x0, sizeof(IBM_DS(shpnt).ldn_assignments));
- probe_display(0);
- return;
-}
-
-static int device_exists(struct Scsi_Host *shpnt, int ldn, int *block_length, int *device_type)
-{
- unsigned char *buf;
- /* if no valid device found, return immediately with 0 */
- if (!(device_inquiry(shpnt, ldn)))
- return 0;
- buf = (unsigned char *) (&(ld(shpnt)[ldn].buf));
- if (*buf == TYPE_ROM) {
- *device_type = TYPE_ROM;
- *block_length = 2048; /* (standard blocksize for yellow-/red-book) */
- return 1;
- }
- if (*buf == TYPE_WORM) {
- *device_type = TYPE_WORM;
- *block_length = 2048;
- return 1;
- }
- if (*buf == TYPE_DISK) {
- *device_type = TYPE_DISK;
- if (read_capacity(shpnt, ldn)) {
- *block_length = *(buf + 7) + (*(buf + 6) << 8) + (*(buf + 5) << 16) + (*(buf + 4) << 24);
- return 1;
- } else
- return 0;
- }
- if (*buf == TYPE_MOD) {
- *device_type = TYPE_MOD;
- if (read_capacity(shpnt, ldn)) {
- *block_length = *(buf + 7) + (*(buf + 6) << 8) + (*(buf + 5) << 16) + (*(buf + 4) << 24);
- return 1;
- } else
- return 0;
- }
- if (*buf == TYPE_TAPE) {
- *device_type = TYPE_TAPE;
- *block_length = 0; /* not in use (setting by mt and mtst in op.) */
- return 1;
- }
- if (*buf == TYPE_PROCESSOR) {
- *device_type = TYPE_PROCESSOR;
- *block_length = 0; /* they set their stuff on drivers */
- return 1;
- }
- if (*buf == TYPE_SCANNER) {
- *device_type = TYPE_SCANNER;
- *block_length = 0; /* they set their stuff on drivers */
- return 1;
- }
- if (*buf == TYPE_MEDIUM_CHANGER) {
- *device_type = TYPE_MEDIUM_CHANGER;
- *block_length = 0; /* One never knows, what to expect on a medium
- changer device. */
- return 1;
- }
- return 0;
-}
-
-static void internal_ibmmca_scsi_setup(char *str, int *ints)
-{
- int i, j, io_base, id_base;
- char *token;
-
- io_base = 0;
- id_base = 0;
- if (str) {
- j = 0;
- while ((token = strsep(&str, ",")) != NULL) {
- if (!strcmp(token, "activity"))
- display_mode |= LED_ACTIVITY;
- if (!strcmp(token, "display"))
- display_mode |= LED_DISP;
- if (!strcmp(token, "adisplay"))
- display_mode |= LED_ADISP;
- if (!strcmp(token, "normal"))
- ibm_ansi_order = 0;
- if (!strcmp(token, "ansi"))
- ibm_ansi_order = 1;
- if (!strcmp(token, "fast"))
- global_adapter_speed = 0;
- if (!strcmp(token, "medium"))
- global_adapter_speed = 4;
- if (!strcmp(token, "slow"))
- global_adapter_speed = 7;
- if ((*token == '-') || (isdigit(*token))) {
- if (!(j % 2) && (io_base < IM_MAX_HOSTS))
- io_port[io_base++] = simple_strtoul(token, NULL, 0);
- if ((j % 2) && (id_base < IM_MAX_HOSTS))
- scsi_id[id_base++] = simple_strtoul(token, NULL, 0);
- j++;
- }
- }
- } else if (ints) {
- for (i = 0; i < IM_MAX_HOSTS && 2 * i + 2 < ints[0]; i++) {
- io_port[i] = ints[2 * i + 2];
- scsi_id[i] = ints[2 * i + 2];
- }
- }
- return;
-}
-
-#if 0
- FIXME NEED TO MOVE TO SYSFS
-
-static int ibmmca_getinfo(char *buf, int slot, void *dev_id)
-{
- struct Scsi_Host *shpnt;
- int len, speciale, connectore, k;
- unsigned int pos[8];
- unsigned long flags;
- struct Scsi_Host *dev = dev_id;
-
- spin_lock_irqsave(dev->host_lock, flags);
-
- shpnt = dev; /* assign host-structure to local pointer */
- len = 0; /* set filled text-buffer index to 0 */
- /* get the _special contents of the hostdata structure */
- speciale = ((struct ibmmca_hostdata *) shpnt->hostdata)->_special;
- connectore = ((struct ibmmca_hostdata *) shpnt->hostdata)->_connector_size;
- for (k = 2; k < 4; k++)
- pos[k] = ((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k];
- if (speciale == FORCED_DETECTION) { /* forced detection */
- len += sprintf(buf + len,
- "Adapter category: forced detected\n" "***************************************\n" "*** Forced detected SCSI Adapter ***\n" "*** No chip-information available ***\n" "***************************************\n");
- } else if (speciale == INTEGRATED_SCSI) {
- /* if the integrated subsystem has been found automatically: */
- len += sprintf(buf + len,
- "Adapter category: integrated\n" "Chip revision level: %d\n" "Chip status: %s\n" "8 kByte NVRAM status: %s\n", ((pos[2] & 0xf0) >> 4), (pos[2] & 1) ? "enabled" : "disabled", (pos[2] & 2) ? "locked" : "accessible");
- } else if ((speciale >= 0) && (speciale < ARRAY_SIZE(subsys_list))) {
- /* if the subsystem is a slot adapter */
- len += sprintf(buf + len, "Adapter category: slot-card\n" "ROM Segment Address: ");
- if ((pos[2] & 0xf0) == 0xf0)
- len += sprintf(buf + len, "off\n");
- else
- len += sprintf(buf + len, "0x%x\n", ((pos[2] & 0xf0) << 13) + 0xc0000);
- len += sprintf(buf + len, "Chip status: %s\n", (pos[2] & 1) ? "enabled" : "disabled");
- len += sprintf(buf + len, "Adapter I/O Offset: 0x%x\n", ((pos[2] & 0x0e) << 2));
- } else {
- len += sprintf(buf + len, "Adapter category: unknown\n");
- }
- /* common subsystem information to write to the slotn file */
- len += sprintf(buf + len, "Subsystem PUN: %d\n", shpnt->this_id);
- len += sprintf(buf + len, "I/O base address range: 0x%x-0x%x\n", (unsigned int) (shpnt->io_port), (unsigned int) (shpnt->io_port + 7));
- len += sprintf(buf + len, "MCA-slot size: %d bits", connectore);
- /* Now make sure, the bufferlength is devidable by 4 to avoid
- * paging problems of the buffer. */
- while (len % sizeof(int) != (sizeof(int) - 1))
- len += sprintf(buf + len, " ");
- len += sprintf(buf + len, "\n");
-
- spin_unlock_irqrestore(shpnt->host_lock, flags);
-
- return len;
-}
-#endif
-
-static struct scsi_host_template ibmmca_driver_template = {
- .proc_name = "ibmmca",
- .proc_info = ibmmca_proc_info,
- .name = "IBM SCSI-Subsystem",
- .queuecommand = ibmmca_queuecommand,
- .eh_abort_handler = ibmmca_abort,
- .eh_host_reset_handler = ibmmca_host_reset,
- .bios_param = ibmmca_biosparam,
- .can_queue = 16,
- .this_id = 7,
- .sg_tablesize = 16,
- .cmd_per_lun = 1,
- .use_clustering = ENABLE_CLUSTERING,
-};
-
-static int ibmmca_probe(struct device *dev)
-{
- struct Scsi_Host *shpnt;
- int port, id, i, j, k, irq, enabled, ret = -EINVAL;
- struct mca_device *mca_dev = to_mca_device(dev);
- const char *description = ibmmca_description[mca_dev->index];
-
- /* First of all, print the version number of the driver. This is
- * important to allow better user bugreports in case of already
- * having problems with the MCA_bus probing. */
- printk(KERN_INFO "IBM MCA SCSI: Version %s\n", IBMMCA_SCSI_DRIVER_VERSION);
- /* The POS2-register of all PS/2 model SCSI-subsystems has the following
- * interpretation of bits:
- * Bit 7 - 4 : Chip Revision ID (Release)
- * Bit 3 - 2 : Reserved
- * Bit 1 : 8k NVRAM Disabled
- * Bit 0 : Chip Enable (EN-Signal)
- * The POS3-register is interpreted as follows:
- * Bit 7 - 5 : SCSI ID
- * Bit 4 : Reserved = 0
- * Bit 3 - 0 : Reserved = 0
- * (taken from "IBM, PS/2 Hardware Interface Technical Reference, Common
- * Interfaces (1991)").
- * In short words, this means, that IBM PS/2 machines only support
- * 1 single subsystem by default. The slot-adapters must have another
- * configuration on pos2. Here, one has to assume the following
- * things for POS2-register:
- * Bit 7 - 4 : Chip Revision ID (Release)
- * Bit 3 - 1 : port offset factor
- * Bit 0 : Chip Enable (EN-Signal)
- * As I found a patch here, setting the IO-registers to 0x3540 forced,
- * as there was a 0x05 in POS2 on a model 56, I assume, that the
- * port 0x3540 must be fix for integrated SCSI-controllers.
- * Ok, this discovery leads to the following implementation: (M.Lang) */
-
- /* first look for the IBM SCSI integrated subsystem on the motherboard */
- for (j = 0; j < 8; j++) /* read the pos-information */
- pos[j] = mca_device_read_pos(mca_dev, j);
- id = (pos[3] & 0xe0) >> 5; /* this is correct and represents the PUN */
- enabled = (pos[2] &0x01);
- if (!enabled) {
- printk(KERN_WARNING "IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n");
- printk(KERN_WARNING " SCSI-operations may not work.\n");
- }
-
- /* pos2 = pos3 = 0xff if there is no integrated SCSI-subsystem present, but
- * if we ignore the settings of all surrounding pos registers, it is not
- * completely sufficient to only check pos2 and pos3. */
- /* Therefore, now the following if statement is used to
- * make sure, we see a real integrated onboard SCSI-interface and no
- * internal system information, which gets mapped to some pos registers
- * on models 95xx. */
- if (mca_dev->slot == MCA_INTEGSCSI &&
- ((!pos[0] && !pos[1] && pos[2] > 0 &&
- pos[3] > 0 && !pos[4] && !pos[5] &&
- !pos[6] && !pos[7]) ||
- (pos[0] == 0xff && pos[1] == 0xff &&
- pos[2] < 0xff && pos[3] < 0xff &&
- pos[4] == 0xff && pos[5] == 0xff &&
- pos[6] == 0xff && pos[7] == 0xff))) {
- irq = IM_IRQ;
- port = IM_IO_PORT;
- } else {
- irq = IM_IRQ;
- port = IM_IO_PORT + ((pos[2] &0x0e) << 2);
- if ((mca_dev->index == IBM_SCSI2_FW) && (pos[6] != 0)) {
- printk(KERN_ERR "IBM MCA SCSI: ERROR - Wrong POS(6)-register setting!\n");
- printk(KERN_ERR " Impossible to determine adapter PUN!\n");
- printk(KERN_ERR " Guessing adapter PUN = 7.\n");
- id = 7;
- } else {
- id = (pos[3] & 0xe0) >> 5; /* get subsystem PUN */
- if (mca_dev->index == IBM_SCSI2_FW) {
- id |= (pos[3] & 0x10) >> 1; /* get subsystem PUN high-bit
- * for F/W adapters */
- }
- }
- if ((mca_dev->index == IBM_SCSI2_FW) &&
- (pos[4] & 0x01) && (pos[6] == 0)) {
- /* IRQ11 is used by SCSI-2 F/W Adapter/A */
- printk(KERN_DEBUG "IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n");
- irq = IM_IRQ_FW;
- }
- }
-
-
-
- /* give detailed information on the subsystem. This helps me
- * additionally during debugging and analyzing bug-reports. */
- printk(KERN_INFO "IBM MCA SCSI: %s found, io=0x%x, scsi id=%d,\n",
- description, port, id);
- if (mca_dev->slot == MCA_INTEGSCSI)
- printk(KERN_INFO " chip rev.=%d, 8K NVRAM=%s, subsystem=%s\n", ((pos[2] & 0xf0) >> 4), (pos[2] & 2) ? "locked" : "accessible", (pos[2] & 1) ? "enabled." : "disabled.");
- else {
- if ((pos[2] & 0xf0) == 0xf0)
- printk(KERN_DEBUG " ROM Addr.=off,");
- else
- printk(KERN_DEBUG " ROM Addr.=0x%x,", ((pos[2] & 0xf0) << 13) + 0xc0000);
-
- printk(KERN_DEBUG " port-offset=0x%x, subsystem=%s\n", ((pos[2] & 0x0e) << 2), (pos[2] & 1) ? "enabled." : "disabled.");
- }
-
- /* check I/O region */
- if (!request_region(port, IM_N_IO_PORT, description)) {
- printk(KERN_ERR "IBM MCA SCSI: Unable to get I/O region 0x%x-0x%x (%d ports).\n", port, port + IM_N_IO_PORT - 1, IM_N_IO_PORT);
- goto out_fail;
- }
-
- /* register host */
- shpnt = scsi_host_alloc(&ibmmca_driver_template,
- sizeof(struct ibmmca_hostdata));
- if (!shpnt) {
- printk(KERN_ERR "IBM MCA SCSI: Unable to register host.\n");
- goto out_release;
- }
-
- dev_set_drvdata(dev, shpnt);
- if(request_irq(irq, interrupt_handler, IRQF_SHARED, description, dev)) {
- printk(KERN_ERR "IBM MCA SCSI: failed to request interrupt %d\n", irq);
- goto out_free_host;
- }
-
- /* request I/O region */
- special(shpnt) = mca_dev->index; /* important assignment or else crash! */
- subsystem_connector_size(shpnt) = 0; /* preset slot-size */
- shpnt->irq = irq; /* assign necessary stuff for the adapter */
- shpnt->io_port = port;
- shpnt->n_io_port = IM_N_IO_PORT;
- shpnt->this_id = id;
- shpnt->max_id = 8; /* 8 PUNs are default */
- /* now, the SCSI-subsystem is connected to Linux */
-
-#ifdef IM_DEBUG_PROBE
- ctrl = (unsigned int) (inb(IM_CTR_REG(found))); /* get control-register status */
- printk("IBM MCA SCSI: Control Register contents: %x, status: %x\n", ctrl, inb(IM_STAT_REG(found)));
- printk("IBM MCA SCSI: This adapters' POS-registers: ");
- for (i = 0; i < 8; i++)
- printk("%x ", pos[i]);
- printk("\n");
-#endif
- reset_status(shpnt) = IM_RESET_NOT_IN_PROGRESS;
-
- for (i = 0; i < 16; i++) /* reset the tables */
- for (j = 0; j < 8; j++)
- get_ldn(shpnt)[i][j] = MAX_LOG_DEV;
-
- /* check which logical devices exist */
- /* after this line, local interrupting is possible: */
- local_checking_phase_flag(shpnt) = 1;
- check_devices(shpnt, mca_dev->index); /* call by value, using the global variable hosts */
- local_checking_phase_flag(shpnt) = 0;
-
- /* an ibm mca subsystem has been detected */
-
- for (k = 2; k < 7; k++)
- ((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k] = pos[k];
- ((struct ibmmca_hostdata *) shpnt->hostdata)->_special = INTEGRATED_SCSI;
- mca_device_set_name(mca_dev, description);
- /* FIXME: NEED TO REPLUMB TO SYSFS
- mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo, shpnt);
- */
- mca_device_set_claim(mca_dev, 1);
- if (scsi_add_host(shpnt, dev)) {
- dev_printk(KERN_ERR, dev, "IBM MCA SCSI: scsi_add_host failed\n");
- goto out_free_host;
- }
- scsi_scan_host(shpnt);
-
- return 0;
- out_free_host:
- scsi_host_put(shpnt);
- out_release:
- release_region(port, IM_N_IO_PORT);
- out_fail:
- return ret;
-}
-
-static int __devexit ibmmca_remove(struct device *dev)
-{
- struct Scsi_Host *shpnt = dev_get_drvdata(dev);
- scsi_remove_host(shpnt);
- release_region(shpnt->io_port, shpnt->n_io_port);
- free_irq(shpnt->irq, dev);
- scsi_host_put(shpnt);
- return 0;
-}
-
-/* The following routine is the SCSI command queue for the midlevel driver */
-static int ibmmca_queuecommand_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
-{
- unsigned int ldn;
- unsigned int scsi_cmd;
- struct im_scb *scb;
- struct Scsi_Host *shpnt;
- int current_ldn;
- int id, lun;
- int target;
- int max_pun;
- int i;
- struct scatterlist *sg;
-
- shpnt = cmd->device->host;
-
- max_pun = subsystem_maxid(shpnt);
- if (ibm_ansi_order) {
- target = max_pun - 1 - cmd->device->id;
- if ((target <= subsystem_pun(shpnt)) && (cmd->device->id <= subsystem_pun(shpnt)))
- target--;
- else if ((target >= subsystem_pun(shpnt)) && (cmd->device->id >= subsystem_pun(shpnt)))
- target++;
- } else
- target = cmd->device->id;
-
- /* if (target,lun) is NO LUN or not existing at all, return error */
- if ((get_scsi(shpnt)[target][cmd->device->lun] == TYPE_NO_LUN) || (get_scsi(shpnt)[target][cmd->device->lun] == TYPE_NO_DEVICE)) {
- cmd->result = DID_NO_CONNECT << 16;
- if (done)
- done(cmd);
- return 0;
- }
-
- /*if (target,lun) unassigned, do further checks... */
- ldn = get_ldn(shpnt)[target][cmd->device->lun];
- if (ldn >= MAX_LOG_DEV) { /* on invalid ldn do special stuff */
- if (ldn > MAX_LOG_DEV) { /* dynamical remapping if ldn unassigned */
- current_ldn = next_ldn(shpnt); /* stop-value for one circle */
- while (ld(shpnt)[next_ldn(shpnt)].cmd) { /* search for a occupied, but not in */
- /* command-processing ldn. */
- next_ldn(shpnt)++;
- if (next_ldn(shpnt) >= MAX_LOG_DEV)
- next_ldn(shpnt) = 7;
- if (current_ldn == next_ldn(shpnt)) { /* One circle done ? */
- /* no non-processing ldn found */
- scmd_printk(KERN_WARNING, cmd,
- "IBM MCA SCSI: Cannot assign SCSI-device dynamically!\n"
- " On ldn 7-14 SCSI-commands everywhere in progress.\n"
- " Reporting DID_NO_CONNECT for device.\n");
- cmd->result = DID_NO_CONNECT << 16; /* return no connect */
- if (done)
- done(cmd);
- return 0;
- }
- }
-
- /* unmap non-processing ldn */
- for (id = 0; id < max_pun; id++)
- for (lun = 0; lun < 8; lun++) {
- if (get_ldn(shpnt)[id][lun] == next_ldn(shpnt)) {
- get_ldn(shpnt)[id][lun] = TYPE_NO_DEVICE;
- get_scsi(shpnt)[id][lun] = TYPE_NO_DEVICE;
- /* unmap entry */
- }
- }
- /* set reduced interrupt_handler-mode for checking */
- local_checking_phase_flag(shpnt) = 1;
- /* map found ldn to pun,lun */
- get_ldn(shpnt)[target][cmd->device->lun] = next_ldn(shpnt);
- /* change ldn to the right value, that is now next_ldn */
- ldn = next_ldn(shpnt);
- /* unassign all ldns (pun,lun,ldn does not matter for remove) */
- immediate_assign(shpnt, 0, 0, 0, REMOVE_LDN);
- /* set only LDN for remapped device */
- immediate_assign(shpnt, target, cmd->device->lun, ldn, SET_LDN);
- /* get device information for ld[ldn] */
- if (device_exists(shpnt, ldn, &ld(shpnt)[ldn].block_length, &ld(shpnt)[ldn].device_type)) {
- ld(shpnt)[ldn].cmd = NULL; /* To prevent panic set 0, because
- devices that were not assigned,
- should have nothing in progress. */
- get_scsi(shpnt)[target][cmd->device->lun] = ld(shpnt)[ldn].device_type;
- /* increase assignment counters for statistics in /proc */
- IBM_DS(shpnt).dynamical_assignments++;
- IBM_DS(shpnt).ldn_assignments[ldn]++;
- } else
- /* panic here, because a device, found at boottime has
- vanished */
- panic("IBM MCA SCSI: ldn=0x%x, SCSI-device on (%d,%d) vanished!\n", ldn, target, cmd->device->lun);
- /* unassign again all ldns (pun,lun,ldn does not matter for remove) */
- immediate_assign(shpnt, 0, 0, 0, REMOVE_LDN);
- /* remap all ldns, as written in the pun/lun table */
- lun = 0;
-#ifdef CONFIG_SCSI_MULTI_LUN
- for (lun = 0; lun < 8; lun++)
-#endif
- for (id = 0; id < max_pun; id++) {
- if (get_ldn(shpnt)[id][lun] <= MAX_LOG_DEV)
- immediate_assign(shpnt, id, lun, get_ldn(shpnt)[id][lun], SET_LDN);
- }
- /* set back to normal interrupt_handling */
- local_checking_phase_flag(shpnt) = 0;
-#ifdef IM_DEBUG_PROBE
- /* Information on syslog terminal */
- printk("IBM MCA SCSI: ldn=0x%x dynamically reassigned to (%d,%d).\n", ldn, target, cmd->device->lun);
-#endif
- /* increase next_ldn for next dynamical assignment */
- next_ldn(shpnt)++;
- if (next_ldn(shpnt) >= MAX_LOG_DEV)
- next_ldn(shpnt) = 7;
- } else { /* wall against Linux accesses to the subsystem adapter */
- cmd->result = DID_BAD_TARGET << 16;
- if (done)
- done(cmd);
- return 0;
- }
- }
-
- /*verify there is no command already in progress for this log dev */
- if (ld(shpnt)[ldn].cmd)
- panic("IBM MCA SCSI: cmd already in progress for this ldn.\n");
-
- /*save done in cmd, and save cmd for the interrupt handler */
- cmd->scsi_done = done;
- ld(shpnt)[ldn].cmd = cmd;
-
- /*fill scb information independent of the scsi command */
- scb = &(ld(shpnt)[ldn].scb);
- ld(shpnt)[ldn].tsb.dev_status = 0;
- scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE;
- scb->tsb_adr = isa_virt_to_bus(&(ld(shpnt)[ldn].tsb));
- scsi_cmd = cmd->cmnd[0];
-
- if (scsi_sg_count(cmd)) {
- BUG_ON(scsi_sg_count(cmd) > 16);
-
- scsi_for_each_sg(cmd, sg, scsi_sg_count(cmd), i) {
- ld(shpnt)[ldn].sge[i].address = (void *) (isa_page_to_bus(sg_page(sg)) + sg->offset);
- ld(shpnt)[ldn].sge[i].byte_length = sg->length;
- }
- scb->enable |= IM_POINTER_TO_LIST;
- scb->sys_buf_adr = isa_virt_to_bus(&(ld(shpnt)[ldn].sge[0]));
- scb->sys_buf_length = scsi_sg_count(cmd) * sizeof(struct im_sge);
- } else {
- scb->sys_buf_adr = isa_virt_to_bus(scsi_sglist(cmd));
- /* recent Linux midlevel SCSI places 1024 byte for inquiry
- * command. Far too much for old PS/2 hardware. */
- switch (scsi_cmd) {
- /* avoid command errors by setting bufferlengths to
- * ANSI-standard. Beware of forcing it to 255,
- * this could SEGV the kernel!!! */
- case INQUIRY:
- case REQUEST_SENSE:
- case MODE_SENSE:
- case MODE_SELECT:
- if (scsi_bufflen(cmd) > 255)
- scb->sys_buf_length = 255;
- else
- scb->sys_buf_length = scsi_bufflen(cmd);
- break;
- case TEST_UNIT_READY:
- scb->sys_buf_length = 0;
- break;
- default:
- scb->sys_buf_length = scsi_bufflen(cmd);
- break;
- }
- }
- /*fill scb information dependent on scsi command */
-
-#ifdef IM_DEBUG_CMD
- printk("issue scsi cmd=%02x to ldn=%d\n", scsi_cmd, ldn);
-#endif
-
- /* for specific device-type debugging: */
-#ifdef IM_DEBUG_CMD_SPEC_DEV
- if (ld(shpnt)[ldn].device_type == IM_DEBUG_CMD_DEVICE)
- printk("(SCSI-device-type=0x%x) issue scsi cmd=%02x to ldn=%d\n", ld(shpnt)[ldn].device_type, scsi_cmd, ldn);
-#endif
-
- /* for possible panics store current command */
- last_scsi_command(shpnt)[ldn] = scsi_cmd;
- last_scsi_type(shpnt)[ldn] = IM_SCB;
- /* update statistical info */
- IBM_DS(shpnt).total_accesses++;
- IBM_DS(shpnt).ldn_access[ldn]++;
-
- switch (scsi_cmd) {
- case READ_6:
- case WRITE_6:
- case READ_10:
- case WRITE_10:
- case READ_12:
- case WRITE_12:
- /* Distinguish between disk and other devices. Only disks (that are the
- most frequently accessed devices) should be supported by the
- IBM-SCSI-Subsystem commands. */
- switch (ld(shpnt)[ldn].device_type) {
- case TYPE_DISK: /* for harddisks enter here ... */
- case TYPE_MOD: /* ... try it also for MO-drives (send flames as */
- /* you like, if this won't work.) */
- if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || scsi_cmd == READ_12) {
- /* read command preparations */
- scb->enable |= IM_READ_CONTROL;
- IBM_DS(shpnt).ldn_read_access[ldn]++; /* increase READ-access on ldn stat. */
- scb->command = IM_READ_DATA_CMD | IM_NO_DISCONNECT;
- } else { /* write command preparations */
- IBM_DS(shpnt).ldn_write_access[ldn]++; /* increase write-count on ldn stat. */
- scb->command = IM_WRITE_DATA_CMD | IM_NO_DISCONNECT;
- }
- if (scsi_cmd == READ_6 || scsi_cmd == WRITE_6) {
- scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[3]) << 0) | (((unsigned) cmd->cmnd[2]) << 8) | ((((unsigned) cmd->cmnd[1]) & 0x1f) << 16);
- scb->u2.blk.count = (unsigned) cmd->cmnd[4];
- } else {
- scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[5]) << 0) | (((unsigned) cmd->cmnd[4]) << 8) | (((unsigned) cmd->cmnd[3]) << 16) | (((unsigned) cmd->cmnd[2]) << 24);
- scb->u2.blk.count = (((unsigned) cmd->cmnd[8]) << 0) | (((unsigned) cmd->cmnd[7]) << 8);
- }
- last_scsi_logical_block(shpnt)[ldn] = scb->u1.log_blk_adr;
- last_scsi_blockcount(shpnt)[ldn] = scb->u2.blk.count;
- scb->u2.blk.length = ld(shpnt)[ldn].block_length;
- break;
- /* for other devices, enter here. Other types are not known by
- Linux! TYPE_NO_LUN is forbidden as valid device. */
- case TYPE_ROM:
- case TYPE_TAPE:
- case TYPE_PROCESSOR:
- case TYPE_WORM:
- case TYPE_SCANNER:
- case TYPE_MEDIUM_CHANGER:
- /* If there is a sequential-device, IBM recommends to use
- IM_OTHER_SCSI_CMD_CMD instead of subsystem READ/WRITE.
- This includes CD-ROM devices, too, due to the partial sequential
- read capabilities. */
- scb->command = IM_OTHER_SCSI_CMD_CMD;
- if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || scsi_cmd == READ_12)
- /* enable READ */
- scb->enable |= IM_READ_CONTROL;
- scb->enable |= IM_BYPASS_BUFFER;
- scb->u1.scsi_cmd_length = cmd->cmd_len;
- memcpy(scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
- last_scsi_type(shpnt)[ldn] = IM_LONG_SCB;
- /* Read/write on this non-disk devices is also displayworthy,
- so flash-up the LED/display. */
- break;
- }
- break;
- case INQUIRY:
- IBM_DS(shpnt).ldn_inquiry_access[ldn]++;
- scb->command = IM_DEVICE_INQUIRY_CMD;
- scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
- scb->u1.log_blk_adr = 0;
- break;
- case TEST_UNIT_READY:
- scb->command = IM_OTHER_SCSI_CMD_CMD;
- scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
- scb->u1.log_blk_adr = 0;
- scb->u1.scsi_cmd_length = 6;
- memcpy(scb->u2.scsi_command, cmd->cmnd, 6);
- last_scsi_type(shpnt)[ldn] = IM_LONG_SCB;
- break;
- case READ_CAPACITY:
- /* the length of system memory buffer must be exactly 8 bytes */
- scb->command = IM_READ_CAPACITY_CMD;
- scb->enable |= IM_READ_CONTROL | IM_BYPASS_BUFFER;
- if (scb->sys_buf_length > 8)
- scb->sys_buf_length = 8;
- break;
- /* Commands that need read-only-mode (system <- device): */
- case REQUEST_SENSE:
- scb->command = IM_REQUEST_SENSE_CMD;
- scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
- break;
- /* Commands that need write-only-mode (system -> device): */
- case MODE_SELECT:
- case MODE_SELECT_10:
- IBM_DS(shpnt).ldn_modeselect_access[ldn]++;
- scb->command = IM_OTHER_SCSI_CMD_CMD;
- scb->enable |= IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; /*Select needs WRITE-enabled */
- scb->u1.scsi_cmd_length = cmd->cmd_len;
- memcpy(scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
- last_scsi_type(shpnt)[ldn] = IM_LONG_SCB;
- break;
- /* For other commands, read-only is useful. Most other commands are
- running without an input-data-block. */
- default:
- scb->command = IM_OTHER_SCSI_CMD_CMD;
- scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
- scb->u1.scsi_cmd_length = cmd->cmd_len;
- memcpy(scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
- last_scsi_type(shpnt)[ldn] = IM_LONG_SCB;
- break;
- }
- /*issue scb command, and return */
- if (++disk_rw_in_progress == 1)
- PS2_DISK_LED_ON(shpnt->host_no, target);
-
- if (last_scsi_type(shpnt)[ldn] == IM_LONG_SCB) {
- issue_cmd(shpnt, isa_virt_to_bus(scb), IM_LONG_SCB | ldn);
- IBM_DS(shpnt).long_scbs++;
- } else {
- issue_cmd(shpnt, isa_virt_to_bus(scb), IM_SCB | ldn);
- IBM_DS(shpnt).scbs++;
- }
- return 0;
-}
-
-static DEF_SCSI_QCMD(ibmmca_queuecommand)
-
-static int __ibmmca_abort(Scsi_Cmnd * cmd)
-{
- /* Abort does not work, as the adapter never generates an interrupt on
- * whatever situation is simulated, even when really pending commands
- * are running on the adapters' hardware ! */
-
- struct Scsi_Host *shpnt;
- unsigned int ldn;
- void (*saved_done) (Scsi_Cmnd *);
- int target;
- int max_pun;
- unsigned long imm_command;
-
-#ifdef IM_DEBUG_PROBE
- printk("IBM MCA SCSI: Abort subroutine called...\n");
-#endif
-
- shpnt = cmd->device->host;
-
- max_pun = subsystem_maxid(shpnt);
- if (ibm_ansi_order) {
- target = max_pun - 1 - cmd->device->id;
- if ((target <= subsystem_pun(shpnt)) && (cmd->device->id <= subsystem_pun(shpnt)))
- target--;
- else if ((target >= subsystem_pun(shpnt)) && (cmd->device->id >= subsystem_pun(shpnt)))
- target++;
- } else
- target = cmd->device->id;
-
- /* get logical device number, and disable system interrupts */
- printk(KERN_WARNING "IBM MCA SCSI: Sending abort to device pun=%d, lun=%d.\n", target, cmd->device->lun);
- ldn = get_ldn(shpnt)[target][cmd->device->lun];
-
- /*if cmd for this ldn has already finished, no need to abort */
- if (!ld(shpnt)[ldn].cmd) {
- return SUCCESS;
- }
-
- /* Clear ld.cmd, save done function, install internal done,
- * send abort immediate command (this enables sys. interrupts),
- * and wait until the interrupt arrives.
- */
- saved_done = cmd->scsi_done;
- cmd->scsi_done = internal_done;
- cmd->SCp.Status = 0;
- last_scsi_command(shpnt)[ldn] = IM_ABORT_IMM_CMD;
- last_scsi_type(shpnt)[ldn] = IM_IMM_CMD;
- imm_command = inl(IM_CMD_REG(shpnt));
- imm_command &= (unsigned long) (0xffff0000); /* mask reserved stuff */
- imm_command |= (unsigned long) (IM_ABORT_IMM_CMD);
- /* must wait for attention reg not busy */
- /* FIXME - timeout, politeness */
- while (1) {
- if (!(inb(IM_STAT_REG(shpnt)) & IM_BUSY))
- break;
- }
- /* write registers and enable system interrupts */
- outl(imm_command, IM_CMD_REG(shpnt));
- outb(IM_IMM_CMD | ldn, IM_ATTN_REG(shpnt));
-#ifdef IM_DEBUG_PROBE
- printk("IBM MCA SCSI: Abort queued to adapter...\n");
-#endif
- spin_unlock_irq(shpnt->host_lock);
- while (!cmd->SCp.Status)
- yield();
- spin_lock_irq(shpnt->host_lock);
- cmd->scsi_done = saved_done;
-#ifdef IM_DEBUG_PROBE
- printk("IBM MCA SCSI: Abort returned with adapter response...\n");
-#endif
-
- /*if abort went well, call saved done, then return success or error */
- if (cmd->result == (DID_ABORT << 16))
- {
- cmd->result |= DID_ABORT << 16;
- if (cmd->scsi_done)
- (cmd->scsi_done) (cmd);
- ld(shpnt)[ldn].cmd = NULL;
-#ifdef IM_DEBUG_PROBE
- printk("IBM MCA SCSI: Abort finished with success.\n");
-#endif
- return SUCCESS;
- } else {
- cmd->result |= DID_NO_CONNECT << 16;
- if (cmd->scsi_done)
- (cmd->scsi_done) (cmd);
- ld(shpnt)[ldn].cmd = NULL;
-#ifdef IM_DEBUG_PROBE
- printk("IBM MCA SCSI: Abort failed.\n");
-#endif
- return FAILED;
- }
-}
-
-static int ibmmca_abort(Scsi_Cmnd * cmd)
-{
- struct Scsi_Host *shpnt = cmd->device->host;
- int rc;
-
- spin_lock_irq(shpnt->host_lock);
- rc = __ibmmca_abort(cmd);
- spin_unlock_irq(shpnt->host_lock);
-
- return rc;
-}
-
-static int __ibmmca_host_reset(Scsi_Cmnd * cmd)
-{
- struct Scsi_Host *shpnt;
- Scsi_Cmnd *cmd_aid;
- int ticks, i;
- unsigned long imm_command;
-
- BUG_ON(cmd == NULL);
-
- ticks = IM_RESET_DELAY * HZ;
- shpnt = cmd->device->host;
-
- if (local_checking_phase_flag(shpnt)) {
- printk(KERN_WARNING "IBM MCA SCSI: unable to reset while checking devices.\n");
- return FAILED;
- }
-
- /* issue reset immediate command to subsystem, and wait for interrupt */
- printk("IBM MCA SCSI: resetting all devices.\n");
- reset_status(shpnt) = IM_RESET_IN_PROGRESS;
- last_scsi_command(shpnt)[0xf] = IM_RESET_IMM_CMD;
- last_scsi_type(shpnt)[0xf] = IM_IMM_CMD;
- imm_command = inl(IM_CMD_REG(shpnt));
- imm_command &= (unsigned long) (0xffff0000); /* mask reserved stuff */
- imm_command |= (unsigned long) (IM_RESET_IMM_CMD);
- /* must wait for attention reg not busy */
- while (1) {
- if (!(inb(IM_STAT_REG(shpnt)) & IM_BUSY))
- break;
- spin_unlock_irq(shpnt->host_lock);
- yield();
- spin_lock_irq(shpnt->host_lock);
- }
- /*write registers and enable system interrupts */
- outl(imm_command, IM_CMD_REG(shpnt));
- outb(IM_IMM_CMD | 0xf, IM_ATTN_REG(shpnt));
- /* wait for interrupt finished or intr_stat register to be set, as the
- * interrupt will not be executed, while we are in here! */
-
- /* FIXME: This is really really icky we so want a sleeping version of this ! */
- while (reset_status(shpnt) == IM_RESET_IN_PROGRESS && --ticks && ((inb(IM_INTR_REG(shpnt)) & 0x8f) != 0x8f)) {
- udelay((1 + 999 / HZ) * 1000);
- barrier();
- }
- /* if reset did not complete, just return an error */
- if (!ticks) {
- printk(KERN_ERR "IBM MCA SCSI: reset did not complete within %d seconds.\n", IM_RESET_DELAY);
- reset_status(shpnt) = IM_RESET_FINISHED_FAIL;
- return FAILED;
- }
-
- if ((inb(IM_INTR_REG(shpnt)) & 0x8f) == 0x8f) {
- /* analysis done by this routine and not by the intr-routine */
- if (inb(IM_INTR_REG(shpnt)) == 0xaf)
- reset_status(shpnt) = IM_RESET_FINISHED_OK_NO_INT;
- else if (inb(IM_INTR_REG(shpnt)) == 0xcf)
- reset_status(shpnt) = IM_RESET_FINISHED_FAIL;
- else /* failed, 4get it */
- reset_status(shpnt) = IM_RESET_NOT_IN_PROGRESS_NO_INT;
- outb(IM_EOI | 0xf, IM_ATTN_REG(shpnt));
- }
-
- /* if reset failed, just return an error */
- if (reset_status(shpnt) == IM_RESET_FINISHED_FAIL) {
- printk(KERN_ERR "IBM MCA SCSI: reset failed.\n");
- return FAILED;
- }
-
- /* so reset finished ok - call outstanding done's, and return success */
- printk(KERN_INFO "IBM MCA SCSI: Reset successfully completed.\n");
- for (i = 0; i < MAX_LOG_DEV; i++) {
- cmd_aid = ld(shpnt)[i].cmd;
- if (cmd_aid && cmd_aid->scsi_done) {
- ld(shpnt)[i].cmd = NULL;
- cmd_aid->result = DID_RESET << 16;
- }
- }
- return SUCCESS;
-}
-
-static int ibmmca_host_reset(Scsi_Cmnd * cmd)
-{
- struct Scsi_Host *shpnt = cmd->device->host;
- int rc;
-
- spin_lock_irq(shpnt->host_lock);
- rc = __ibmmca_host_reset(cmd);
- spin_unlock_irq(shpnt->host_lock);
-
- return rc;
-}
-
-static int ibmmca_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int *info)
-{
- int size = capacity;
- info[0] = 64;
- info[1] = 32;
- info[2] = size / (info[0] * info[1]);
- if (info[2] >= 1024) {
- info[0] = 128;
- info[1] = 63;
- info[2] = size / (info[0] * info[1]);
- if (info[2] >= 1024) {
- info[0] = 255;
- info[1] = 63;
- info[2] = size / (info[0] * info[1]);
- if (info[2] >= 1024)
- info[2] = 1023;
- }
- }
- return 0;
-}
-
-/* calculate percentage of total accesses on a ldn */
-static int ldn_access_load(struct Scsi_Host *shpnt, int ldn)
-{
- if (IBM_DS(shpnt).total_accesses == 0)
- return (0);
- if (IBM_DS(shpnt).ldn_access[ldn] == 0)
- return (0);
- return (IBM_DS(shpnt).ldn_access[ldn] * 100) / IBM_DS(shpnt).total_accesses;
-}
-
-/* calculate total amount of r/w-accesses */
-static int ldn_access_total_read_write(struct Scsi_Host *shpnt)
-{
- int a;
- int i;
-
- a = 0;
- for (i = 0; i <= MAX_LOG_DEV; i++)
- a += IBM_DS(shpnt).ldn_read_access[i] + IBM_DS(shpnt).ldn_write_access[i];
- return (a);
-}
-
-static int ldn_access_total_inquiry(struct Scsi_Host *shpnt)
-{
- int a;
- int i;
-
- a = 0;
- for (i = 0; i <= MAX_LOG_DEV; i++)
- a += IBM_DS(shpnt).ldn_inquiry_access[i];
- return (a);
-}
-
-static int ldn_access_total_modeselect(struct Scsi_Host *shpnt)
-{
- int a;
- int i;
-
- a = 0;
- for (i = 0; i <= MAX_LOG_DEV; i++)
- a += IBM_DS(shpnt).ldn_modeselect_access[i];
- return (a);
-}
-
-/* routine to display info in the proc-fs-structure (a deluxe feature) */
-static int ibmmca_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, int inout)
-{
- int len = 0;
- int i, id, lun;
- unsigned long flags;
- int max_pun;
-
-
- spin_lock_irqsave(shpnt->host_lock, flags); /* Check it */
-
- max_pun = subsystem_maxid(shpnt);
-
- len += sprintf(buffer + len, "\n IBM-SCSI-Subsystem-Linux-Driver, Version %s\n\n\n", IBMMCA_SCSI_DRIVER_VERSION);
- len += sprintf(buffer + len, " SCSI Access-Statistics:\n");
- len += sprintf(buffer + len, " Device Scanning Order....: %s\n", (ibm_ansi_order) ? "IBM/ANSI" : "New Industry Standard");
-#ifdef CONFIG_SCSI_MULTI_LUN
- len += sprintf(buffer + len, " Multiple LUN probing.....: Yes\n");
-#else
- len += sprintf(buffer + len, " Multiple LUN probing.....: No\n");
-#endif
- len += sprintf(buffer + len, " This Hostnumber..........: %d\n", shpnt->host_no);
- len += sprintf(buffer + len, " Base I/O-Port............: 0x%x\n", (unsigned int) (IM_CMD_REG(shpnt)));
- len += sprintf(buffer + len, " (Shared) IRQ.............: %d\n", IM_IRQ);
- len += sprintf(buffer + len, " Total Interrupts.........: %d\n", IBM_DS(shpnt).total_interrupts);
- len += sprintf(buffer + len, " Total SCSI Accesses......: %d\n", IBM_DS(shpnt).total_accesses);
- len += sprintf(buffer + len, " Total short SCBs.........: %d\n", IBM_DS(shpnt).scbs);
- len += sprintf(buffer + len, " Total long SCBs..........: %d\n", IBM_DS(shpnt).long_scbs);
- len += sprintf(buffer + len, " Total SCSI READ/WRITE..: %d\n", ldn_access_total_read_write(shpnt));
- len += sprintf(buffer + len, " Total SCSI Inquiries...: %d\n", ldn_access_total_inquiry(shpnt));
- len += sprintf(buffer + len, " Total SCSI Modeselects.: %d\n", ldn_access_total_modeselect(shpnt));
- len += sprintf(buffer + len, " Total SCSI other cmds..: %d\n", IBM_DS(shpnt).total_accesses - ldn_access_total_read_write(shpnt)
- - ldn_access_total_modeselect(shpnt)
- - ldn_access_total_inquiry(shpnt));
- len += sprintf(buffer + len, " Total SCSI command fails.: %d\n\n", IBM_DS(shpnt).total_errors);
- len += sprintf(buffer + len, " Logical-Device-Number (LDN) Access-Statistics:\n");
- len += sprintf(buffer + len, " LDN | Accesses [%%] | READ | WRITE | ASSIGNMENTS\n");
- len += sprintf(buffer + len, " -----|--------------|-----------|-----------|--------------\n");
- for (i = 0; i <= MAX_LOG_DEV; i++)
- len += sprintf(buffer + len, " %2X | %3d | %8d | %8d | %8d\n", i, ldn_access_load(shpnt, i), IBM_DS(shpnt).ldn_read_access[i], IBM_DS(shpnt).ldn_write_access[i], IBM_DS(shpnt).ldn_assignments[i]);
- len += sprintf(buffer + len, " -----------------------------------------------------------\n\n");
- len += sprintf(buffer + len, " Dynamical-LDN-Assignment-Statistics:\n");
- len += sprintf(buffer + len, " Number of physical SCSI-devices..: %d (+ Adapter)\n", IBM_DS(shpnt).total_scsi_devices);
- len += sprintf(buffer + len, " Dynamical Assignment necessary...: %s\n", IBM_DS(shpnt).dyn_flag ? "Yes" : "No ");
- len += sprintf(buffer + len, " Next LDN to be assigned..........: 0x%x\n", next_ldn(shpnt));
- len += sprintf(buffer + len, " Dynamical assignments done yet...: %d\n", IBM_DS(shpnt).dynamical_assignments);
- len += sprintf(buffer + len, "\n Current SCSI-Device-Mapping:\n");
- len += sprintf(buffer + len, " Physical SCSI-Device Map Logical SCSI-Device Map\n");
- len += sprintf(buffer + len, " ID\\LUN 0 1 2 3 4 5 6 7 ID\\LUN 0 1 2 3 4 5 6 7\n");
- for (id = 0; id < max_pun; id++) {
- len += sprintf(buffer + len, " %2d ", id);
- for (lun = 0; lun < 8; lun++)
- len += sprintf(buffer + len, "%2s ", ti_p(get_scsi(shpnt)[id][lun]));
- len += sprintf(buffer + len, " %2d ", id);
- for (lun = 0; lun < 8; lun++)
- len += sprintf(buffer + len, "%2s ", ti_l(get_ldn(shpnt)[id][lun]));
- len += sprintf(buffer + len, "\n");
- }
-
- len += sprintf(buffer + len, "(A = IBM-Subsystem, D = Harddisk, T = Tapedrive, P = Processor, W = WORM,\n");
- len += sprintf(buffer + len, " R = CD-ROM, S = Scanner, M = MO-Drive, C = Medium-Changer, + = unprovided LUN,\n");
- len += sprintf(buffer + len, " - = nothing found, nothing assigned or unprobed LUN)\n\n");
-
- *start = buffer + offset;
- len -= offset;
- if (len > length)
- len = length;
- spin_unlock_irqrestore(shpnt->host_lock, flags);
- return len;
-}
-
-static int option_setup(char *str)
-{
- int ints[IM_MAX_HOSTS];
- char *cur = str;
- int i = 1;
-
- while (cur && isdigit(*cur) && i < IM_MAX_HOSTS) {
- ints[i++] = simple_strtoul(cur, NULL, 0);
- if ((cur = strchr(cur, ',')) != NULL)
- cur++;
- }
- ints[0] = i - 1;
- internal_ibmmca_scsi_setup(cur, ints);
- return 1;
-}
-
-__setup("ibmmcascsi=", option_setup);
-
-static struct mca_driver ibmmca_driver = {
- .id_table = ibmmca_id_table,
- .driver = {
- .name = "ibmmca",
- .bus = &mca_bus_type,
- .probe = ibmmca_probe,
- .remove = __devexit_p(ibmmca_remove),
- },
-};
-
-static int __init ibmmca_init(void)
-{
-#ifdef MODULE
- /* If the driver is run as module, read from conf.modules or cmd-line */
- if (boot_options)
- option_setup(boot_options);
-#endif
-
- return mca_register_driver_integrated(&ibmmca_driver, MCA_INTEGSCSI);
-}
-
-static void __exit ibmmca_exit(void)
-{
- mca_unregister_driver(&ibmmca_driver);
-}
-
-module_init(ibmmca_init);
-module_exit(ibmmca_exit);
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 6c6486f626ee..538230be5cca 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -4473,17 +4473,14 @@ qla1280_exit(void)
pci_unregister_driver(&qla1280_pci_driver);
/* release any allocated firmware images */
for (i = 0; i < QL_NUM_FW_IMAGES; i++) {
- if (qla1280_fw_tbl[i].fw) {
- release_firmware(qla1280_fw_tbl[i].fw);
- qla1280_fw_tbl[i].fw = NULL;
- }
+ release_firmware(qla1280_fw_tbl[i].fw);
+ qla1280_fw_tbl[i].fw = NULL;
}
}
module_init(qla1280_init);
module_exit(qla1280_exit);
-
MODULE_AUTHOR("Qlogic & Jes Sorensen");
MODULE_DESCRIPTION("Qlogic ISP SCSI (qla1x80/qla1x160) driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 7db803377c64..c9c56a8427f3 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -4122,8 +4122,7 @@ qla2x00_release_firmware(void)
mutex_lock(&qla_fw_lock);
for (idx = 0; idx < FW_BLOBS; idx++)
- if (qla_fw_blobs[idx].fw)
- release_firmware(qla_fw_blobs[idx].fw);
+ release_firmware(qla_fw_blobs[idx].fw);
mutex_unlock(&qla_fw_lock);
}
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 386f0c53bea7..d0f71e5d065f 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -664,7 +664,7 @@ static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd)
}
/**
- * scsi_eh_prep_cmnd - Save a scsi command info as part of error recory
+ * scsi_eh_prep_cmnd - Save a scsi command info as part of error recovery
* @scmd: SCSI command structure to hijack
* @ses: structure to save restore information
* @cmnd: CDB to send. Can be NULL if no new cmnd is needed
@@ -739,7 +739,7 @@ void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses,
EXPORT_SYMBOL(scsi_eh_prep_cmnd);
/**
- * scsi_eh_restore_cmnd - Restore a scsi command info as part of error recory
+ * scsi_eh_restore_cmnd - Restore a scsi command info as part of error recovery
* @scmd: SCSI command structure to restore
* @ses: saved information from a coresponding call to scsi_eh_prep_cmnd
*
@@ -762,7 +762,7 @@ void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses)
EXPORT_SYMBOL(scsi_eh_restore_cmnd);
/**
- * scsi_send_eh_cmnd - submit a scsi command as part of error recory
+ * scsi_send_eh_cmnd - submit a scsi command as part of error recovery
* @scmd: SCSI command structure to hijack
* @cmnd: CDB to send
* @cmnd_size: size in bytes of @cmnd
diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c
index 8ac6ce792b69..a318264a4ba1 100644
--- a/drivers/scsi/sim710.c
+++ b/drivers/scsi/sim710.c
@@ -17,7 +17,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*----------------------------------------------------------------------------
*
- * MCA card detection code by Trent McNair.
+ * MCA card detection code by Trent McNair. (now deleted)
* Fixes to not explicitly nul bss data from Xavier Bestel.
* Some multiboard fixes from Rolf Eike Beer.
* Auto probing of EISA config space from Trevor Hemsley.
@@ -32,7 +32,6 @@
#include <linux/blkdev.h>
#include <linux/device.h>
#include <linux/init.h>
-#include <linux/mca.h>
#include <linux/eisa.h>
#include <linux/interrupt.h>
#include <scsi/scsi_host.h>
@@ -43,7 +42,7 @@
#include "53c700.h"
-/* Must be enough for both EISA and MCA */
+/* Must be enough for EISA */
#define MAX_SLOTS 8
static __u8 __initdata id_array[MAX_SLOTS] = { [0 ... MAX_SLOTS-1] = 7 };
@@ -89,7 +88,7 @@ param_setup(char *str)
__setup("sim710=", param_setup);
static struct scsi_host_template sim710_driver_template = {
- .name = "LSI (Symbios) 710 MCA/EISA",
+ .name = "LSI (Symbios) 710 EISA",
.proc_name = "sim710",
.this_id = 7,
.module = THIS_MODULE,
@@ -169,114 +168,6 @@ sim710_device_remove(struct device *dev)
return 0;
}
-#ifdef CONFIG_MCA
-
-/* CARD ID 01BB and 01BA use the same pos values */
-#define MCA_01BB_IO_PORTS { 0x0000, 0x0000, 0x0800, 0x0C00, 0x1000, 0x1400, \
- 0x1800, 0x1C00, 0x2000, 0x2400, 0x2800, \
- 0x2C00, 0x3000, 0x3400, 0x3800, 0x3C00, \
- 0x4000, 0x4400, 0x4800, 0x4C00, 0x5000 }
-
-#define MCA_01BB_IRQS { 3, 5, 11, 14 }
-
-/* CARD ID 004f */
-#define MCA_004F_IO_PORTS { 0x0000, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600 }
-#define MCA_004F_IRQS { 5, 9, 14 }
-
-static short sim710_mca_id_table[] = { 0x01bb, 0x01ba, 0x004f, 0};
-
-static __init int
-sim710_mca_probe(struct device *dev)
-{
- struct mca_device *mca_dev = to_mca_device(dev);
- int slot = mca_dev->slot;
- int pos[3];
- unsigned int base;
- int irq_vector;
- short id = sim710_mca_id_table[mca_dev->index];
- static int io_004f_by_pos[] = MCA_004F_IO_PORTS;
- static int irq_004f_by_pos[] = MCA_004F_IRQS;
- static int io_01bb_by_pos[] = MCA_01BB_IO_PORTS;
- static int irq_01bb_by_pos[] = MCA_01BB_IRQS;
- char *name;
- int clock;
-
- pos[0] = mca_device_read_stored_pos(mca_dev, 2);
- pos[1] = mca_device_read_stored_pos(mca_dev, 3);
- pos[2] = mca_device_read_stored_pos(mca_dev, 4);
-
- /*
- * 01BB & 01BA port base by bits 7,6,5,4,3,2 in pos[2]
- *
- * 000000 <disabled> 001010 0x2800
- * 000001 <invalid> 001011 0x2C00
- * 000010 0x0800 001100 0x3000
- * 000011 0x0C00 001101 0x3400
- * 000100 0x1000 001110 0x3800
- * 000101 0x1400 001111 0x3C00
- * 000110 0x1800 010000 0x4000
- * 000111 0x1C00 010001 0x4400
- * 001000 0x2000 010010 0x4800
- * 001001 0x2400 010011 0x4C00
- * 010100 0x5000
- *
- * 00F4 port base by bits 3,2,1 in pos[0]
- *
- * 000 <disabled> 001 0x200
- * 010 0x300 011 0x400
- * 100 0x500 101 0x600
- *
- * 01BB & 01BA IRQ is specified in pos[0] bits 7 and 6:
- *
- * 00 3 10 11
- * 01 5 11 14
- *
- * 00F4 IRQ specified by bits 6,5,4 in pos[0]
- *
- * 100 5 101 9
- * 110 14
- */
-
- if (id == 0x01bb || id == 0x01ba) {
- base = io_01bb_by_pos[(pos[2] & 0xFC) >> 2];
- irq_vector =
- irq_01bb_by_pos[((pos[0] & 0xC0) >> 6)];
-
- clock = 50;
- if (id == 0x01bb)
- name = "NCR 3360/3430 SCSI SubSystem";
- else
- name = "NCR Dual SIOP SCSI Host Adapter Board";
- } else if ( id == 0x004f ) {
- base = io_004f_by_pos[((pos[0] & 0x0E) >> 1)];
- irq_vector =
- irq_004f_by_pos[((pos[0] & 0x70) >> 4) - 4];
- clock = 50;
- name = "NCR 53c710 SCSI Host Adapter Board";
- } else {
- return -ENODEV;
- }
- mca_device_set_name(mca_dev, name);
- mca_device_set_claim(mca_dev, 1);
- base = mca_device_transform_ioport(mca_dev, base);
- irq_vector = mca_device_transform_irq(mca_dev, irq_vector);
-
- return sim710_probe_common(dev, base, irq_vector, clock,
- 0, id_array[slot]);
-}
-
-static struct mca_driver sim710_mca_driver = {
- .id_table = sim710_mca_id_table,
- .driver = {
- .name = "sim710",
- .bus = &mca_bus_type,
- .probe = sim710_mca_probe,
- .remove = __devexit_p(sim710_device_remove),
- },
-};
-
-#endif /* CONFIG_MCA */
-
#ifdef CONFIG_EISA
static struct eisa_device_id sim710_eisa_ids[] = {
{ "CPQ4410" },
@@ -344,10 +235,6 @@ static int __init sim710_init(void)
param_setup(sim710);
#endif
-#ifdef CONFIG_MCA
- err = mca_register_driver(&sim710_mca_driver);
-#endif
-
#ifdef CONFIG_EISA
err = eisa_driver_register(&sim710_eisa_driver);
#endif
@@ -361,11 +248,6 @@ static int __init sim710_init(void)
static void __exit sim710_exit(void)
{
-#ifdef CONFIG_MCA
- if (MCA_bus)
- mca_unregister_driver(&sim710_mca_driver);
-#endif
-
#ifdef CONFIG_EISA
eisa_driver_unregister(&sim710_eisa_driver);
#endif
diff --git a/drivers/sh/clk/cpg.c b/drivers/sh/clk/cpg.c
index 91b6d52f74eb..f0d015dd0fef 100644
--- a/drivers/sh/clk/cpg.c
+++ b/drivers/sh/clk/cpg.c
@@ -2,6 +2,7 @@
* Helper routines for SuperH Clock Pulse Generator blocks (CPG).
*
* Copyright (C) 2010 Magnus Damm
+ * Copyright (C) 2010 - 2012 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -13,26 +14,44 @@
#include <linux/io.h>
#include <linux/sh_clk.h>
-static int sh_clk_mstp32_enable(struct clk *clk)
+static unsigned int sh_clk_read(struct clk *clk)
{
- iowrite32(ioread32(clk->mapped_reg) & ~(1 << clk->enable_bit),
- clk->mapped_reg);
+ if (clk->flags & CLK_ENABLE_REG_8BIT)
+ return ioread8(clk->mapped_reg);
+ else if (clk->flags & CLK_ENABLE_REG_16BIT)
+ return ioread16(clk->mapped_reg);
+
+ return ioread32(clk->mapped_reg);
+}
+
+static void sh_clk_write(int value, struct clk *clk)
+{
+ if (clk->flags & CLK_ENABLE_REG_8BIT)
+ iowrite8(value, clk->mapped_reg);
+ else if (clk->flags & CLK_ENABLE_REG_16BIT)
+ iowrite16(value, clk->mapped_reg);
+ else
+ iowrite32(value, clk->mapped_reg);
+}
+
+static int sh_clk_mstp_enable(struct clk *clk)
+{
+ sh_clk_write(sh_clk_read(clk) & ~(1 << clk->enable_bit), clk);
return 0;
}
-static void sh_clk_mstp32_disable(struct clk *clk)
+static void sh_clk_mstp_disable(struct clk *clk)
{
- iowrite32(ioread32(clk->mapped_reg) | (1 << clk->enable_bit),
- clk->mapped_reg);
+ sh_clk_write(sh_clk_read(clk) | (1 << clk->enable_bit), clk);
}
-static struct sh_clk_ops sh_clk_mstp32_clk_ops = {
- .enable = sh_clk_mstp32_enable,
- .disable = sh_clk_mstp32_disable,
+static struct sh_clk_ops sh_clk_mstp_clk_ops = {
+ .enable = sh_clk_mstp_enable,
+ .disable = sh_clk_mstp_disable,
.recalc = followparent_recalc,
};
-int __init sh_clk_mstp32_register(struct clk *clks, int nr)
+int __init sh_clk_mstp_register(struct clk *clks, int nr)
{
struct clk *clkp;
int ret = 0;
@@ -40,7 +59,7 @@ int __init sh_clk_mstp32_register(struct clk *clks, int nr)
for (k = 0; !ret && (k < nr); k++) {
clkp = clks + k;
- clkp->ops = &sh_clk_mstp32_clk_ops;
+ clkp->ops = &sh_clk_mstp_clk_ops;
ret |= clk_register(clkp);
}
@@ -72,7 +91,7 @@ static unsigned long sh_clk_div6_recalc(struct clk *clk)
clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
table, NULL);
- idx = ioread32(clk->mapped_reg) & 0x003f;
+ idx = sh_clk_read(clk) & 0x003f;
return clk->freq_table[idx].frequency;
}
@@ -98,10 +117,10 @@ static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent)
if (ret < 0)
return ret;
- value = ioread32(clk->mapped_reg) &
+ value = sh_clk_read(clk) &
~(((1 << clk->src_width) - 1) << clk->src_shift);
- iowrite32(value | (i << clk->src_shift), clk->mapped_reg);
+ sh_clk_write(value | (i << clk->src_shift), clk);
/* Rebuild the frequency table */
clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
@@ -119,10 +138,10 @@ static int sh_clk_div6_set_rate(struct clk *clk, unsigned long rate)
if (idx < 0)
return idx;
- value = ioread32(clk->mapped_reg);
+ value = sh_clk_read(clk);
value &= ~0x3f;
value |= idx;
- iowrite32(value, clk->mapped_reg);
+ sh_clk_write(value, clk);
return 0;
}
@@ -133,9 +152,9 @@ static int sh_clk_div6_enable(struct clk *clk)
ret = sh_clk_div6_set_rate(clk, clk->rate);
if (ret == 0) {
- value = ioread32(clk->mapped_reg);
+ value = sh_clk_read(clk);
value &= ~0x100; /* clear stop bit to enable clock */
- iowrite32(value, clk->mapped_reg);
+ sh_clk_write(value, clk);
}
return ret;
}
@@ -144,10 +163,10 @@ static void sh_clk_div6_disable(struct clk *clk)
{
unsigned long value;
- value = ioread32(clk->mapped_reg);
+ value = sh_clk_read(clk);
value |= 0x100; /* stop clock */
value |= 0x3f; /* VDIV bits must be non-zero, overwrite divider */
- iowrite32(value, clk->mapped_reg);
+ sh_clk_write(value, clk);
}
static struct sh_clk_ops sh_clk_div6_clk_ops = {
@@ -182,7 +201,7 @@ static int __init sh_clk_init_parent(struct clk *clk)
return -EINVAL;
}
- val = (ioread32(clk->mapped_reg) >> clk->src_shift);
+ val = (sh_clk_read(clk) >> clk->src_shift);
val &= (1 << clk->src_width) - 1;
if (val >= clk->parent_num) {
@@ -252,7 +271,7 @@ static unsigned long sh_clk_div4_recalc(struct clk *clk)
clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
table, &clk->arch_flags);
- idx = (ioread32(clk->mapped_reg) >> clk->enable_bit) & 0x000f;
+ idx = (sh_clk_read(clk) >> clk->enable_bit) & 0x000f;
return clk->freq_table[idx].frequency;
}
@@ -270,15 +289,15 @@ static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent)
*/
if (parent->flags & CLK_ENABLE_ON_INIT)
- value = ioread32(clk->mapped_reg) & ~(1 << 7);
+ value = sh_clk_read(clk) & ~(1 << 7);
else
- value = ioread32(clk->mapped_reg) | (1 << 7);
+ value = sh_clk_read(clk) | (1 << 7);
ret = clk_reparent(clk, parent);
if (ret < 0)
return ret;
- iowrite32(value, clk->mapped_reg);
+ sh_clk_write(value, clk);
/* Rebiuld the frequency table */
clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
@@ -295,10 +314,10 @@ static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate)
if (idx < 0)
return idx;
- value = ioread32(clk->mapped_reg);
+ value = sh_clk_read(clk);
value &= ~(0xf << clk->enable_bit);
value |= (idx << clk->enable_bit);
- iowrite32(value, clk->mapped_reg);
+ sh_clk_write(value, clk);
if (d4t->kick)
d4t->kick(clk);
@@ -308,13 +327,13 @@ static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate)
static int sh_clk_div4_enable(struct clk *clk)
{
- iowrite32(ioread32(clk->mapped_reg) & ~(1 << 8), clk->mapped_reg);
+ sh_clk_write(sh_clk_read(clk) & ~(1 << 8), clk);
return 0;
}
static void sh_clk_div4_disable(struct clk *clk)
{
- iowrite32(ioread32(clk->mapped_reg) | (1 << 8), clk->mapped_reg);
+ sh_clk_write(sh_clk_read(clk) | (1 << 8), clk);
}
static struct sh_clk_ops sh_clk_div4_clk_ops = {
diff --git a/drivers/sh/intc/dynamic.c b/drivers/sh/intc/dynamic.c
index 5fea1ee8799a..14eb01ef5d72 100644
--- a/drivers/sh/intc/dynamic.c
+++ b/drivers/sh/intc/dynamic.c
@@ -55,11 +55,3 @@ void destroy_irq(unsigned int irq)
{
irq_free_desc(irq);
}
-
-void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs)
-{
- int i;
-
- for (i = 0; i < nr_vecs; i++)
- irq_reserve_irq(evt2irq(vectors[i].vect));
-}
diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c
index acc88b4d2869..249077e5cc48 100644
--- a/drivers/spi/spi-ath79.c
+++ b/drivers/spi/spi-ath79.c
@@ -216,9 +216,6 @@ static __devinit int ath79_spi_probe(struct platform_device *pdev)
if (pdata) {
master->bus_num = pdata->bus_num;
master->num_chipselect = pdata->num_chipselect;
- } else {
- master->bus_num = -1;
- master->num_chipselect = 1;
}
sp->bitbang.master = spi_master_get(master);
diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c
index 6eee64a5d240..b2d4b9e4e010 100644
--- a/drivers/spi/spi-coldfire-qspi.c
+++ b/drivers/spi/spi-coldfire-qspi.c
@@ -25,12 +25,12 @@
#include <linux/errno.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
-#include <linux/workqueue.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/spi/spi.h>
+#include <linux/pm_runtime.h>
#include <asm/coldfire.h>
#include <asm/mcfsim.h>
@@ -78,10 +78,7 @@ struct mcfqspi {
wait_queue_head_t waitq;
- struct work_struct work;
- struct workqueue_struct *workq;
- spinlock_t lock;
- struct list_head msgq;
+ struct device *dev;
};
static void mcfqspi_wr_qmr(struct mcfqspi *mcfqspi, u16 val)
@@ -303,120 +300,80 @@ static void mcfqspi_transfer_msg16(struct mcfqspi *mcfqspi, unsigned count,
}
}
-static void mcfqspi_work(struct work_struct *work)
+static int mcfqspi_transfer_one_message(struct spi_master *master,
+ struct spi_message *msg)
{
- struct mcfqspi *mcfqspi = container_of(work, struct mcfqspi, work);
- unsigned long flags;
-
- spin_lock_irqsave(&mcfqspi->lock, flags);
- while (!list_empty(&mcfqspi->msgq)) {
- struct spi_message *msg;
- struct spi_device *spi;
- struct spi_transfer *xfer;
- int status = 0;
-
- msg = container_of(mcfqspi->msgq.next, struct spi_message,
- queue);
-
- list_del_init(&msg->queue);
- spin_unlock_irqrestore(&mcfqspi->lock, flags);
-
- spi = msg->spi;
-
- list_for_each_entry(xfer, &msg->transfers, transfer_list) {
- bool cs_high = spi->mode & SPI_CS_HIGH;
- u16 qmr = MCFQSPI_QMR_MSTR;
-
- if (xfer->bits_per_word)
- qmr |= xfer->bits_per_word << 10;
- else
- qmr |= spi->bits_per_word << 10;
- if (spi->mode & SPI_CPHA)
- qmr |= MCFQSPI_QMR_CPHA;
- if (spi->mode & SPI_CPOL)
- qmr |= MCFQSPI_QMR_CPOL;
- if (xfer->speed_hz)
- qmr |= mcfqspi_qmr_baud(xfer->speed_hz);
- else
- qmr |= mcfqspi_qmr_baud(spi->max_speed_hz);
- mcfqspi_wr_qmr(mcfqspi, qmr);
-
- mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high);
-
- mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE);
- if ((xfer->bits_per_word ? xfer->bits_per_word :
- spi->bits_per_word) == 8)
- mcfqspi_transfer_msg8(mcfqspi, xfer->len,
- xfer->tx_buf,
- xfer->rx_buf);
- else
- mcfqspi_transfer_msg16(mcfqspi, xfer->len / 2,
- xfer->tx_buf,
- xfer->rx_buf);
- mcfqspi_wr_qir(mcfqspi, 0);
-
- if (xfer->delay_usecs)
- udelay(xfer->delay_usecs);
- if (xfer->cs_change) {
- if (!list_is_last(&xfer->transfer_list,
- &msg->transfers))
- mcfqspi_cs_deselect(mcfqspi,
- spi->chip_select,
- cs_high);
- } else {
- if (list_is_last(&xfer->transfer_list,
- &msg->transfers))
- mcfqspi_cs_deselect(mcfqspi,
- spi->chip_select,
- cs_high);
- }
- msg->actual_length += xfer->len;
+ struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+ struct spi_device *spi = msg->spi;
+ struct spi_transfer *t;
+ int status = 0;
+
+ list_for_each_entry(t, &msg->transfers, transfer_list) {
+ bool cs_high = spi->mode & SPI_CS_HIGH;
+ u16 qmr = MCFQSPI_QMR_MSTR;
+
+ if (t->bits_per_word)
+ qmr |= t->bits_per_word << 10;
+ else
+ qmr |= spi->bits_per_word << 10;
+ if (spi->mode & SPI_CPHA)
+ qmr |= MCFQSPI_QMR_CPHA;
+ if (spi->mode & SPI_CPOL)
+ qmr |= MCFQSPI_QMR_CPOL;
+ if (t->speed_hz)
+ qmr |= mcfqspi_qmr_baud(t->speed_hz);
+ else
+ qmr |= mcfqspi_qmr_baud(spi->max_speed_hz);
+ mcfqspi_wr_qmr(mcfqspi, qmr);
+
+ mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high);
+
+ mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE);
+ if ((t->bits_per_word ? t->bits_per_word :
+ spi->bits_per_word) == 8)
+ mcfqspi_transfer_msg8(mcfqspi, t->len, t->tx_buf,
+ t->rx_buf);
+ else
+ mcfqspi_transfer_msg16(mcfqspi, t->len / 2, t->tx_buf,
+ t->rx_buf);
+ mcfqspi_wr_qir(mcfqspi, 0);
+
+ if (t->delay_usecs)
+ udelay(t->delay_usecs);
+ if (t->cs_change) {
+ if (!list_is_last(&t->transfer_list, &msg->transfers))
+ mcfqspi_cs_deselect(mcfqspi, spi->chip_select,
+ cs_high);
+ } else {
+ if (list_is_last(&t->transfer_list, &msg->transfers))
+ mcfqspi_cs_deselect(mcfqspi, spi->chip_select,
+ cs_high);
}
- msg->status = status;
- msg->complete(msg->context);
-
- spin_lock_irqsave(&mcfqspi->lock, flags);
+ msg->actual_length += t->len;
}
- spin_unlock_irqrestore(&mcfqspi->lock, flags);
+ msg->status = status;
+ spi_finalize_current_message(master);
+
+ return status;
+
}
-static int mcfqspi_transfer(struct spi_device *spi, struct spi_message *msg)
+static int mcfqspi_prepare_transfer_hw(struct spi_master *master)
{
- struct mcfqspi *mcfqspi;
- struct spi_transfer *xfer;
- unsigned long flags;
-
- mcfqspi = spi_master_get_devdata(spi->master);
-
- list_for_each_entry(xfer, &msg->transfers, transfer_list) {
- if (xfer->bits_per_word && ((xfer->bits_per_word < 8)
- || (xfer->bits_per_word > 16))) {
- dev_dbg(&spi->dev,
- "%d bits per word is not supported\n",
- xfer->bits_per_word);
- goto fail;
- }
- if (xfer->speed_hz) {
- u32 real_speed = MCFQSPI_BUSCLK /
- mcfqspi_qmr_baud(xfer->speed_hz);
- if (real_speed != xfer->speed_hz)
- dev_dbg(&spi->dev,
- "using speed %d instead of %d\n",
- real_speed, xfer->speed_hz);
- }
- }
- msg->status = -EINPROGRESS;
- msg->actual_length = 0;
+ struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
- spin_lock_irqsave(&mcfqspi->lock, flags);
- list_add_tail(&msg->queue, &mcfqspi->msgq);
- queue_work(mcfqspi->workq, &mcfqspi->work);
- spin_unlock_irqrestore(&mcfqspi->lock, flags);
+ pm_runtime_get_sync(mcfqspi->dev);
+
+ return 0;
+}
+
+static int mcfqspi_unprepare_transfer_hw(struct spi_master *master)
+{
+ struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+
+ pm_runtime_put_sync(mcfqspi->dev);
return 0;
-fail:
- msg->status = -EINVAL;
- return -EINVAL;
}
static int mcfqspi_setup(struct spi_device *spi)
@@ -502,21 +459,10 @@ static int __devinit mcfqspi_probe(struct platform_device *pdev)
}
clk_enable(mcfqspi->clk);
- mcfqspi->workq = create_singlethread_workqueue(dev_name(master->dev.parent));
- if (!mcfqspi->workq) {
- dev_dbg(&pdev->dev, "create_workqueue failed\n");
- status = -ENOMEM;
- goto fail4;
- }
- INIT_WORK(&mcfqspi->work, mcfqspi_work);
- spin_lock_init(&mcfqspi->lock);
- INIT_LIST_HEAD(&mcfqspi->msgq);
- init_waitqueue_head(&mcfqspi->waitq);
-
pdata = pdev->dev.platform_data;
if (!pdata) {
dev_dbg(&pdev->dev, "platform data is missing\n");
- goto fail5;
+ goto fail4;
}
master->bus_num = pdata->bus_num;
master->num_chipselect = pdata->num_chipselect;
@@ -525,28 +471,33 @@ static int __devinit mcfqspi_probe(struct platform_device *pdev)
status = mcfqspi_cs_setup(mcfqspi);
if (status) {
dev_dbg(&pdev->dev, "error initializing cs_control\n");
- goto fail5;
+ goto fail4;
}
+ init_waitqueue_head(&mcfqspi->waitq);
+ mcfqspi->dev = &pdev->dev;
+
master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA;
master->setup = mcfqspi_setup;
- master->transfer = mcfqspi_transfer;
+ master->transfer_one_message = mcfqspi_transfer_one_message;
+ master->prepare_transfer_hardware = mcfqspi_prepare_transfer_hw;
+ master->unprepare_transfer_hardware = mcfqspi_unprepare_transfer_hw;
platform_set_drvdata(pdev, master);
status = spi_register_master(master);
if (status) {
dev_dbg(&pdev->dev, "spi_register_master failed\n");
- goto fail6;
+ goto fail5;
}
+ pm_runtime_enable(mcfqspi->dev);
+
dev_info(&pdev->dev, "Coldfire QSPI bus driver\n");
return 0;
-fail6:
- mcfqspi_cs_teardown(mcfqspi);
fail5:
- destroy_workqueue(mcfqspi->workq);
+ mcfqspi_cs_teardown(mcfqspi);
fail4:
clk_disable(mcfqspi->clk);
clk_put(mcfqspi->clk);
@@ -570,12 +521,12 @@ static int __devexit mcfqspi_remove(struct platform_device *pdev)
struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pm_runtime_disable(mcfqspi->dev);
/* disable the hardware (set the baud rate to 0) */
mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR);
platform_set_drvdata(pdev, NULL);
mcfqspi_cs_teardown(mcfqspi);
- destroy_workqueue(mcfqspi->workq);
clk_disable(mcfqspi->clk);
clk_put(mcfqspi->clk);
free_irq(mcfqspi->irq, mcfqspi);
@@ -587,11 +538,13 @@ static int __devexit mcfqspi_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
-
+#ifdef CONFIG_PM_SLEEP
static int mcfqspi_suspend(struct device *dev)
{
- struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev));
+ struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
+ struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+
+ spi_master_suspend(master);
clk_disable(mcfqspi->clk);
@@ -600,27 +553,47 @@ static int mcfqspi_suspend(struct device *dev)
static int mcfqspi_resume(struct device *dev)
{
- struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev));
+ struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
+ struct mcfqspi *mcfqspi = spi_master_get_devdata(master);
+
+ spi_master_resume(master);
clk_enable(mcfqspi->clk);
return 0;
}
+#endif
-static struct dev_pm_ops mcfqspi_dev_pm_ops = {
- .suspend = mcfqspi_suspend,
- .resume = mcfqspi_resume,
-};
+#ifdef CONFIG_PM_RUNTIME
+static int mcfqspi_runtime_suspend(struct device *dev)
+{
+ struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev));
-#define MCFQSPI_DEV_PM_OPS (&mcfqspi_dev_pm_ops)
-#else
-#define MCFQSPI_DEV_PM_OPS NULL
+ clk_disable(mcfqspi->clk);
+
+ return 0;
+}
+
+static int mcfqspi_runtime_resume(struct device *dev)
+{
+ struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev));
+
+ clk_enable(mcfqspi->clk);
+
+ return 0;
+}
#endif
+static const struct dev_pm_ops mcfqspi_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(mcfqspi_suspend, mcfqspi_resume)
+ SET_RUNTIME_PM_OPS(mcfqspi_runtime_suspend, mcfqspi_runtime_resume,
+ NULL)
+};
+
static struct platform_driver mcfqspi_driver = {
.driver.name = DRIVER_NAME,
.driver.owner = THIS_MODULE,
- .driver.pm = MCFQSPI_DEV_PM_OPS,
+ .driver.pm = &mcfqspi_pm,
.probe = mcfqspi_probe,
.remove = __devexit_p(mcfqspi_remove),
};
diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c
index 14f7cc9523f0..ff81abbb3066 100644
--- a/drivers/spi/spi-dw-pci.c
+++ b/drivers/spi/spi-dw-pci.c
@@ -164,18 +164,7 @@ static struct pci_driver dw_spi_driver = {
.resume = spi_resume,
};
-static int __init mrst_spi_init(void)
-{
- return pci_register_driver(&dw_spi_driver);
-}
-
-static void __exit mrst_spi_exit(void)
-{
- pci_unregister_driver(&dw_spi_driver);
-}
-
-module_init(mrst_spi_init);
-module_exit(mrst_spi_exit);
+module_pci_driver(dw_spi_driver);
MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>");
MODULE_DESCRIPTION("PCI interface driver for DW SPI Core");
diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c
index e8055073e84d..f97f1d248800 100644
--- a/drivers/spi/spi-ep93xx.c
+++ b/drivers/spi/spi-ep93xx.c
@@ -76,7 +76,6 @@
* @clk: clock for the controller
* @regs_base: pointer to ioremap()'d registers
* @sspdr_phys: physical address of the SSPDR register
- * @irq: IRQ number used by the driver
* @min_rate: minimum clock rate (in Hz) supported by the controller
* @max_rate: maximum clock rate (in Hz) supported by the controller
* @running: is the queue running
@@ -114,7 +113,6 @@ struct ep93xx_spi {
struct clk *clk;
void __iomem *regs_base;
unsigned long sspdr_phys;
- int irq;
unsigned long min_rate;
unsigned long max_rate;
bool running;
@@ -1031,6 +1029,7 @@ static int __devinit ep93xx_spi_probe(struct platform_device *pdev)
struct ep93xx_spi_info *info;
struct ep93xx_spi *espi;
struct resource *res;
+ int irq;
int error;
info = pdev->dev.platform_data;
@@ -1070,8 +1069,8 @@ static int __devinit ep93xx_spi_probe(struct platform_device *pdev)
espi->min_rate = clk_get_rate(espi->clk) / (254 * 256);
espi->pdev = pdev;
- espi->irq = platform_get_irq(pdev, 0);
- if (espi->irq < 0) {
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
error = -EBUSY;
dev_err(&pdev->dev, "failed to get irq resources\n");
goto fail_put_clock;
@@ -1084,26 +1083,20 @@ static int __devinit ep93xx_spi_probe(struct platform_device *pdev)
goto fail_put_clock;
}
- res = request_mem_region(res->start, resource_size(res), pdev->name);
- if (!res) {
- dev_err(&pdev->dev, "unable to request iomem resources\n");
- error = -EBUSY;
- goto fail_put_clock;
- }
-
espi->sspdr_phys = res->start + SSPDR;
- espi->regs_base = ioremap(res->start, resource_size(res));
+
+ espi->regs_base = devm_request_and_ioremap(&pdev->dev, res);
if (!espi->regs_base) {
dev_err(&pdev->dev, "failed to map resources\n");
error = -ENODEV;
- goto fail_free_mem;
+ goto fail_put_clock;
}
- error = request_irq(espi->irq, ep93xx_spi_interrupt, 0,
- "ep93xx-spi", espi);
+ error = devm_request_irq(&pdev->dev, irq, ep93xx_spi_interrupt,
+ 0, "ep93xx-spi", espi);
if (error) {
dev_err(&pdev->dev, "failed to request irq\n");
- goto fail_unmap_regs;
+ goto fail_put_clock;
}
if (info->use_dma && ep93xx_spi_setup_dma(espi))
@@ -1128,7 +1121,7 @@ static int __devinit ep93xx_spi_probe(struct platform_device *pdev)
}
dev_info(&pdev->dev, "EP93xx SPI Controller at 0x%08lx irq %d\n",
- (unsigned long)res->start, espi->irq);
+ (unsigned long)res->start, irq);
return 0;
@@ -1136,11 +1129,6 @@ fail_free_queue:
destroy_workqueue(espi->wq);
fail_free_dma:
ep93xx_spi_release_dma(espi);
- free_irq(espi->irq, espi);
-fail_unmap_regs:
- iounmap(espi->regs_base);
-fail_free_mem:
- release_mem_region(res->start, resource_size(res));
fail_put_clock:
clk_put(espi->clk);
fail_release_master:
@@ -1154,7 +1142,6 @@ static int __devexit ep93xx_spi_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct ep93xx_spi *espi = spi_master_get_devdata(master);
- struct resource *res;
spin_lock_irq(&espi->lock);
espi->running = false;
@@ -1180,10 +1167,6 @@ static int __devexit ep93xx_spi_remove(struct platform_device *pdev)
spin_unlock_irq(&espi->lock);
ep93xx_spi_release_dma(espi);
- free_irq(espi->irq, espi);
- iounmap(espi->regs_base);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
clk_put(espi->clk);
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 7523a2429d09..27bdc47b5250 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -17,7 +17,6 @@
#include <linux/mm.h>
#include <linux/of.h>
#include <linux/of_platform.h>
-#include <linux/of_spi.h>
#include <linux/interrupt.h>
#include <linux/err.h>
#include <sysdev/fsl_soc.h>
diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c
index 2674fad7f68a..1503574b215a 100644
--- a/drivers/spi/spi-fsl-lib.c
+++ b/drivers/spi/spi-fsl-lib.c
@@ -22,7 +22,7 @@
#include <linux/dma-mapping.h>
#include <linux/mm.h>
#include <linux/of_platform.h>
-#include <linux/of_spi.h>
+#include <linux/spi/spi.h>
#include <sysdev/fsl_soc.h>
#include "spi-fsl-lib.h"
diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c
index 5f748c0d96bd..6a62934ca74c 100644
--- a/drivers/spi/spi-fsl-spi.c
+++ b/drivers/spi/spi-fsl-spi.c
@@ -933,7 +933,7 @@ err:
static void fsl_spi_cs_control(struct spi_device *spi, bool on)
{
- struct device *dev = spi->dev.parent;
+ struct device *dev = spi->dev.parent->parent;
struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data);
u16 cs = spi->chip_select;
int gpio = pinfo->gpios[cs];
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 570f22053be8..69c9a6601f45 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -37,6 +37,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
#include <mach/spi.h>
@@ -758,6 +759,7 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)
struct spi_master *master;
struct spi_imx_data *spi_imx;
struct resource *res;
+ struct pinctrl *pinctrl;
int i, ret, num_cs;
if (!np && !mxc_platform_info) {
@@ -845,6 +847,12 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)
goto out_iounmap;
}
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ goto out_free_irq;
+ }
+
spi_imx->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(spi_imx->clk)) {
dev_err(&pdev->dev, "unable to get clock\n");
diff --git a/drivers/spi/spi-lm70llp.c b/drivers/spi/spi-lm70llp.c
index 933eb9d9ddd4..0759b5db9883 100644
--- a/drivers/spi/spi-lm70llp.c
+++ b/drivers/spi/spi-lm70llp.c
@@ -219,9 +219,6 @@ static void spi_lm70llp_attach(struct parport *p)
}
pp = spi_master_get_devdata(master);
- master->bus_num = -1; /* dynamic alloc of a bus number */
- master->num_chipselect = 1;
-
/*
* SPI and bitbang hookup.
*/
diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c
index 57633d963456..cb3a3830b0a5 100644
--- a/drivers/spi/spi-mpc52xx.c
+++ b/drivers/spi/spi-mpc52xx.c
@@ -433,7 +433,6 @@ static int __devinit mpc52xx_spi_probe(struct platform_device *op)
goto err_alloc;
}
- master->bus_num = -1;
master->setup = mpc52xx_spi_setup;
master->transfer = mpc52xx_spi_transfer;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
@@ -479,8 +478,6 @@ static int __devinit mpc52xx_spi_probe(struct platform_device *op)
gpio_direction_output(gpio_cs, 1);
ms->gpio_cs[i] = gpio_cs;
}
- } else {
- master->num_chipselect = 1;
}
spin_lock_init(&ms->lock);
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index bb9274c2526d..46ef5fe51db5 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -44,9 +44,7 @@
#include <plat/mcspi.h>
#define OMAP2_MCSPI_MAX_FREQ 48000000
-
-/* OMAP2 has 3 SPI controllers, while OMAP3 has 4 */
-#define OMAP2_MCSPI_MAX_CTRL 4
+#define SPI_AUTOSUSPEND_TIMEOUT 2000
#define OMAP2_MCSPI_REVISION 0x00
#define OMAP2_MCSPI_SYSSTATUS 0x14
@@ -111,19 +109,25 @@ struct omap2_mcspi_dma {
#define DMA_MIN_BYTES 160
+/*
+ * Used for context save and restore, structure members to be updated whenever
+ * corresponding registers are modified.
+ */
+struct omap2_mcspi_regs {
+ u32 modulctrl;
+ u32 wakeupenable;
+ struct list_head cs;
+};
+
struct omap2_mcspi {
- struct work_struct work;
- /* lock protects queue and registers */
- spinlock_t lock;
- struct list_head msg_queue;
struct spi_master *master;
/* Virtual base address of the controller */
void __iomem *base;
unsigned long phys;
/* SPI1 has 4 channels, while SPI2 has 2 */
struct omap2_mcspi_dma *dma_channels;
- struct device *dev;
- struct workqueue_struct *wq;
+ struct device *dev;
+ struct omap2_mcspi_regs ctx;
};
struct omap2_mcspi_cs {
@@ -135,17 +139,6 @@ struct omap2_mcspi_cs {
u32 chconf0;
};
-/* used for context save and restore, structure members to be updated whenever
- * corresponding registers are modified.
- */
-struct omap2_mcspi_regs {
- u32 modulctrl;
- u32 wakeupenable;
- struct list_head cs;
-};
-
-static struct omap2_mcspi_regs omap2_mcspi_ctx[OMAP2_MCSPI_MAX_CTRL];
-
#define MOD_REG_BIT(val, mask, set) do { \
if (set) \
val |= mask; \
@@ -236,9 +229,12 @@ static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active)
static void omap2_mcspi_set_master_mode(struct spi_master *master)
{
+ struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
+ struct omap2_mcspi_regs *ctx = &mcspi->ctx;
u32 l;
- /* setup when switching from (reset default) slave mode
+ /*
+ * Setup when switching from (reset default) slave mode
* to single-channel master mode
*/
l = mcspi_read_reg(master, OMAP2_MCSPI_MODULCTRL);
@@ -247,29 +243,26 @@ static void omap2_mcspi_set_master_mode(struct spi_master *master)
MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_SINGLE, 1);
mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, l);
- omap2_mcspi_ctx[master->bus_num - 1].modulctrl = l;
+ ctx->modulctrl = l;
}
static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi)
{
- struct spi_master *spi_cntrl;
- struct omap2_mcspi_cs *cs;
- spi_cntrl = mcspi->master;
+ struct spi_master *spi_cntrl = mcspi->master;
+ struct omap2_mcspi_regs *ctx = &mcspi->ctx;
+ struct omap2_mcspi_cs *cs;
/* McSPI: context restore */
- mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_MODULCTRL,
- omap2_mcspi_ctx[spi_cntrl->bus_num - 1].modulctrl);
-
- mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_WAKEUPENABLE,
- omap2_mcspi_ctx[spi_cntrl->bus_num - 1].wakeupenable);
+ mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_MODULCTRL, ctx->modulctrl);
+ mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_WAKEUPENABLE, ctx->wakeupenable);
- list_for_each_entry(cs, &omap2_mcspi_ctx[spi_cntrl->bus_num - 1].cs,
- node)
+ list_for_each_entry(cs, &ctx->cs, node)
__raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0);
}
static void omap2_mcspi_disable_clocks(struct omap2_mcspi *mcspi)
{
- pm_runtime_put_sync(mcspi->dev);
+ pm_runtime_mark_last_busy(mcspi->dev);
+ pm_runtime_put_autosuspend(mcspi->dev);
}
static int omap2_mcspi_enable_clocks(struct omap2_mcspi *mcspi)
@@ -277,6 +270,23 @@ static int omap2_mcspi_enable_clocks(struct omap2_mcspi *mcspi)
return pm_runtime_get_sync(mcspi->dev);
}
+static int omap2_prepare_transfer(struct spi_master *master)
+{
+ struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
+
+ pm_runtime_get_sync(mcspi->dev);
+ return 0;
+}
+
+static int omap2_unprepare_transfer(struct spi_master *master)
+{
+ struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
+
+ pm_runtime_mark_last_busy(mcspi->dev);
+ pm_runtime_put_autosuspend(mcspi->dev);
+ return 0;
+}
+
static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)
{
unsigned long timeout;
@@ -777,7 +787,8 @@ static int omap2_mcspi_request_dma(struct spi_device *spi)
static int omap2_mcspi_setup(struct spi_device *spi)
{
int ret;
- struct omap2_mcspi *mcspi;
+ struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master);
+ struct omap2_mcspi_regs *ctx = &mcspi->ctx;
struct omap2_mcspi_dma *mcspi_dma;
struct omap2_mcspi_cs *cs = spi->controller_state;
@@ -787,11 +798,10 @@ static int omap2_mcspi_setup(struct spi_device *spi)
return -EINVAL;
}
- mcspi = spi_master_get_devdata(spi->master);
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
if (!cs) {
- cs = kzalloc(sizeof *cs, GFP_KERNEL);
+ cs = devm_kzalloc(&spi->dev , sizeof *cs, GFP_KERNEL);
if (!cs)
return -ENOMEM;
cs->base = mcspi->base + spi->chip_select * 0x14;
@@ -799,8 +809,7 @@ static int omap2_mcspi_setup(struct spi_device *spi)
cs->chconf0 = 0;
spi->controller_state = cs;
/* Link this to context save list */
- list_add_tail(&cs->node,
- &omap2_mcspi_ctx[mcspi->master->bus_num - 1].cs);
+ list_add_tail(&cs->node, &ctx->cs);
}
if (mcspi_dma->dma_rx_channel == -1
@@ -833,7 +842,6 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
cs = spi->controller_state;
list_del(&cs->node);
- kfree(spi->controller_state);
}
if (spi->chip_select < spi->master->num_chipselect) {
@@ -850,144 +858,122 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
}
}
-static void omap2_mcspi_work(struct work_struct *work)
+static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m)
{
- struct omap2_mcspi *mcspi;
-
- mcspi = container_of(work, struct omap2_mcspi, work);
-
- if (omap2_mcspi_enable_clocks(mcspi) < 0)
- return;
-
- spin_lock_irq(&mcspi->lock);
/* We only enable one channel at a time -- the one whose message is
- * at the head of the queue -- although this controller would gladly
+ * -- although this controller would gladly
* arbitrate among multiple channels. This corresponds to "single
* channel" master mode. As a side effect, we need to manage the
* chipselect with the FORCE bit ... CS != channel enable.
*/
- while (!list_empty(&mcspi->msg_queue)) {
- struct spi_message *m;
- struct spi_device *spi;
- struct spi_transfer *t = NULL;
- int cs_active = 0;
- struct omap2_mcspi_cs *cs;
- struct omap2_mcspi_device_config *cd;
- int par_override = 0;
- int status = 0;
- u32 chconf;
-
- m = container_of(mcspi->msg_queue.next, struct spi_message,
- queue);
-
- list_del_init(&m->queue);
- spin_unlock_irq(&mcspi->lock);
-
- spi = m->spi;
- cs = spi->controller_state;
- cd = spi->controller_data;
- omap2_mcspi_set_enable(spi, 1);
- list_for_each_entry(t, &m->transfers, transfer_list) {
- if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
- status = -EINVAL;
- break;
- }
- if (par_override || t->speed_hz || t->bits_per_word) {
- par_override = 1;
- status = omap2_mcspi_setup_transfer(spi, t);
- if (status < 0)
- break;
- if (!t->speed_hz && !t->bits_per_word)
- par_override = 0;
- }
+ struct spi_device *spi;
+ struct spi_transfer *t = NULL;
+ int cs_active = 0;
+ struct omap2_mcspi_cs *cs;
+ struct omap2_mcspi_device_config *cd;
+ int par_override = 0;
+ int status = 0;
+ u32 chconf;
- if (!cs_active) {
- omap2_mcspi_force_cs(spi, 1);
- cs_active = 1;
- }
+ spi = m->spi;
+ cs = spi->controller_state;
+ cd = spi->controller_data;
- chconf = mcspi_cached_chconf0(spi);
- chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
- chconf &= ~OMAP2_MCSPI_CHCONF_TURBO;
+ omap2_mcspi_set_enable(spi, 1);
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
+ status = -EINVAL;
+ break;
+ }
+ if (par_override || t->speed_hz || t->bits_per_word) {
+ par_override = 1;
+ status = omap2_mcspi_setup_transfer(spi, t);
+ if (status < 0)
+ break;
+ if (!t->speed_hz && !t->bits_per_word)
+ par_override = 0;
+ }
- if (t->tx_buf == NULL)
- chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY;
- else if (t->rx_buf == NULL)
- chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
-
- if (cd && cd->turbo_mode && t->tx_buf == NULL) {
- /* Turbo mode is for more than one word */
- if (t->len > ((cs->word_len + 7) >> 3))
- chconf |= OMAP2_MCSPI_CHCONF_TURBO;
- }
+ if (!cs_active) {
+ omap2_mcspi_force_cs(spi, 1);
+ cs_active = 1;
+ }
- mcspi_write_chconf0(spi, chconf);
+ chconf = mcspi_cached_chconf0(spi);
+ chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
+ chconf &= ~OMAP2_MCSPI_CHCONF_TURBO;
- if (t->len) {
- unsigned count;
+ if (t->tx_buf == NULL)
+ chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY;
+ else if (t->rx_buf == NULL)
+ chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
- /* RX_ONLY mode needs dummy data in TX reg */
- if (t->tx_buf == NULL)
- __raw_writel(0, cs->base
- + OMAP2_MCSPI_TX0);
+ if (cd && cd->turbo_mode && t->tx_buf == NULL) {
+ /* Turbo mode is for more than one word */
+ if (t->len > ((cs->word_len + 7) >> 3))
+ chconf |= OMAP2_MCSPI_CHCONF_TURBO;
+ }
- if (m->is_dma_mapped || t->len >= DMA_MIN_BYTES)
- count = omap2_mcspi_txrx_dma(spi, t);
- else
- count = omap2_mcspi_txrx_pio(spi, t);
- m->actual_length += count;
+ mcspi_write_chconf0(spi, chconf);
- if (count != t->len) {
- status = -EIO;
- break;
- }
- }
+ if (t->len) {
+ unsigned count;
- if (t->delay_usecs)
- udelay(t->delay_usecs);
+ /* RX_ONLY mode needs dummy data in TX reg */
+ if (t->tx_buf == NULL)
+ __raw_writel(0, cs->base
+ + OMAP2_MCSPI_TX0);
+
+ if (m->is_dma_mapped || t->len >= DMA_MIN_BYTES)
+ count = omap2_mcspi_txrx_dma(spi, t);
+ else
+ count = omap2_mcspi_txrx_pio(spi, t);
+ m->actual_length += count;
- /* ignore the "leave it on after last xfer" hint */
- if (t->cs_change) {
- omap2_mcspi_force_cs(spi, 0);
- cs_active = 0;
+ if (count != t->len) {
+ status = -EIO;
+ break;
}
}
- /* Restore defaults if they were overriden */
- if (par_override) {
- par_override = 0;
- status = omap2_mcspi_setup_transfer(spi, NULL);
- }
+ if (t->delay_usecs)
+ udelay(t->delay_usecs);
- if (cs_active)
+ /* ignore the "leave it on after last xfer" hint */
+ if (t->cs_change) {
omap2_mcspi_force_cs(spi, 0);
+ cs_active = 0;
+ }
+ }
+ /* Restore defaults if they were overriden */
+ if (par_override) {
+ par_override = 0;
+ status = omap2_mcspi_setup_transfer(spi, NULL);
+ }
- omap2_mcspi_set_enable(spi, 0);
-
- m->status = status;
- m->complete(m->context);
+ if (cs_active)
+ omap2_mcspi_force_cs(spi, 0);
- spin_lock_irq(&mcspi->lock);
- }
+ omap2_mcspi_set_enable(spi, 0);
- spin_unlock_irq(&mcspi->lock);
+ m->status = status;
- omap2_mcspi_disable_clocks(mcspi);
}
-static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m)
+static int omap2_mcspi_transfer_one_message(struct spi_master *master,
+ struct spi_message *m)
{
struct omap2_mcspi *mcspi;
- unsigned long flags;
struct spi_transfer *t;
+ mcspi = spi_master_get_devdata(master);
m->actual_length = 0;
m->status = 0;
/* reject invalid messages and transfers */
- if (list_empty(&m->transfers) || !m->complete)
+ if (list_empty(&m->transfers))
return -EINVAL;
list_for_each_entry(t, &m->transfers, transfer_list) {
const void *tx_buf = t->tx_buf;
@@ -999,7 +985,7 @@ static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m)
|| (t->bits_per_word &&
( t->bits_per_word < 4
|| t->bits_per_word > 32))) {
- dev_dbg(&spi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
+ dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
t->speed_hz,
len,
tx_buf ? "tx" : "",
@@ -1008,7 +994,7 @@ static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m)
return -EINVAL;
}
if (t->speed_hz && t->speed_hz < (OMAP2_MCSPI_MAX_FREQ >> 15)) {
- dev_dbg(&spi->dev, "speed_hz %d below minimum %d Hz\n",
+ dev_dbg(mcspi->dev, "speed_hz %d below minimum %d Hz\n",
t->speed_hz,
OMAP2_MCSPI_MAX_FREQ >> 15);
return -EINVAL;
@@ -1018,51 +1004,46 @@ static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m)
continue;
if (tx_buf != NULL) {
- t->tx_dma = dma_map_single(&spi->dev, (void *) tx_buf,
+ t->tx_dma = dma_map_single(mcspi->dev, (void *) tx_buf,
len, DMA_TO_DEVICE);
- if (dma_mapping_error(&spi->dev, t->tx_dma)) {
- dev_dbg(&spi->dev, "dma %cX %d bytes error\n",
+ if (dma_mapping_error(mcspi->dev, t->tx_dma)) {
+ dev_dbg(mcspi->dev, "dma %cX %d bytes error\n",
'T', len);
return -EINVAL;
}
}
if (rx_buf != NULL) {
- t->rx_dma = dma_map_single(&spi->dev, rx_buf, t->len,
+ t->rx_dma = dma_map_single(mcspi->dev, rx_buf, t->len,
DMA_FROM_DEVICE);
- if (dma_mapping_error(&spi->dev, t->rx_dma)) {
- dev_dbg(&spi->dev, "dma %cX %d bytes error\n",
+ if (dma_mapping_error(mcspi->dev, t->rx_dma)) {
+ dev_dbg(mcspi->dev, "dma %cX %d bytes error\n",
'R', len);
if (tx_buf != NULL)
- dma_unmap_single(&spi->dev, t->tx_dma,
+ dma_unmap_single(mcspi->dev, t->tx_dma,
len, DMA_TO_DEVICE);
return -EINVAL;
}
}
}
- mcspi = spi_master_get_devdata(spi->master);
-
- spin_lock_irqsave(&mcspi->lock, flags);
- list_add_tail(&m->queue, &mcspi->msg_queue);
- queue_work(mcspi->wq, &mcspi->work);
- spin_unlock_irqrestore(&mcspi->lock, flags);
-
+ omap2_mcspi_work(mcspi, m);
+ spi_finalize_current_message(master);
return 0;
}
static int __init omap2_mcspi_master_setup(struct omap2_mcspi *mcspi)
{
struct spi_master *master = mcspi->master;
- u32 tmp;
- int ret = 0;
+ struct omap2_mcspi_regs *ctx = &mcspi->ctx;
+ int ret = 0;
ret = omap2_mcspi_enable_clocks(mcspi);
if (ret < 0)
return ret;
- tmp = OMAP2_MCSPI_WAKEUPENABLE_WKEN;
- mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE, tmp);
- omap2_mcspi_ctx[master->bus_num - 1].wakeupenable = tmp;
+ mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE,
+ OMAP2_MCSPI_WAKEUPENABLE_WKEN);
+ ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN;
omap2_mcspi_set_master_mode(master);
omap2_mcspi_disable_clocks(mcspi);
@@ -1102,14 +1083,13 @@ static const struct of_device_id omap_mcspi_of_match[] = {
};
MODULE_DEVICE_TABLE(of, omap_mcspi_of_match);
-static int __init omap2_mcspi_probe(struct platform_device *pdev)
+static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
{
struct spi_master *master;
struct omap2_mcspi_platform_config *pdata;
struct omap2_mcspi *mcspi;
struct resource *r;
int status = 0, i;
- char wq_name[20];
u32 regs_offset = 0;
static int bus_num = 1;
struct device_node *node = pdev->dev.of_node;
@@ -1125,7 +1105,9 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev)
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->setup = omap2_mcspi_setup;
- master->transfer = omap2_mcspi_transfer;
+ master->prepare_transfer_hardware = omap2_prepare_transfer;
+ master->unprepare_transfer_hardware = omap2_unprepare_transfer;
+ master->transfer_one_message = omap2_mcspi_transfer_one_message;
master->cleanup = omap2_mcspi_cleanup;
master->dev.of_node = node;
@@ -1150,13 +1132,6 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev)
mcspi = spi_master_get_devdata(master);
mcspi->master = master;
- sprintf(wq_name, "omap2_mcspi/%d", master->bus_num);
- mcspi->wq = alloc_workqueue(wq_name, WQ_MEM_RECLAIM, 1);
- if (mcspi->wq == NULL) {
- status = -ENOMEM;
- goto free_master;
- }
-
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (r == NULL) {
status = -ENODEV;
@@ -1166,32 +1141,24 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev)
r->start += regs_offset;
r->end += regs_offset;
mcspi->phys = r->start;
- if (!request_mem_region(r->start, resource_size(r),
- dev_name(&pdev->dev))) {
- status = -EBUSY;
- goto free_master;
- }
- mcspi->base = ioremap(r->start, resource_size(r));
+ mcspi->base = devm_request_and_ioremap(&pdev->dev, r);
if (!mcspi->base) {
dev_dbg(&pdev->dev, "can't ioremap MCSPI\n");
status = -ENOMEM;
- goto release_region;
+ goto free_master;
}
mcspi->dev = &pdev->dev;
- INIT_WORK(&mcspi->work, omap2_mcspi_work);
- spin_lock_init(&mcspi->lock);
- INIT_LIST_HEAD(&mcspi->msg_queue);
- INIT_LIST_HEAD(&omap2_mcspi_ctx[master->bus_num - 1].cs);
+ INIT_LIST_HEAD(&mcspi->ctx.cs);
mcspi->dma_channels = kcalloc(master->num_chipselect,
sizeof(struct omap2_mcspi_dma),
GFP_KERNEL);
if (mcspi->dma_channels == NULL)
- goto unmap_io;
+ goto free_master;
for (i = 0; i < master->num_chipselect; i++) {
char dma_ch_name[14];
@@ -1224,6 +1191,8 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev)
if (status < 0)
goto dma_chnl_free;
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
pm_runtime_enable(&pdev->dev);
if (status || omap2_mcspi_master_setup(mcspi) < 0)
@@ -1241,23 +1210,17 @@ disable_pm:
pm_runtime_disable(&pdev->dev);
dma_chnl_free:
kfree(mcspi->dma_channels);
-unmap_io:
- iounmap(mcspi->base);
-release_region:
- release_mem_region(r->start, resource_size(r));
free_master:
kfree(master);
platform_set_drvdata(pdev, NULL);
return status;
}
-static int __exit omap2_mcspi_remove(struct platform_device *pdev)
+static int __devexit omap2_mcspi_remove(struct platform_device *pdev)
{
struct spi_master *master;
struct omap2_mcspi *mcspi;
struct omap2_mcspi_dma *dma_channels;
- struct resource *r;
- void __iomem *base;
master = dev_get_drvdata(&pdev->dev);
mcspi = spi_master_get_devdata(master);
@@ -1265,14 +1228,9 @@ static int __exit omap2_mcspi_remove(struct platform_device *pdev)
omap2_mcspi_disable_clocks(mcspi);
pm_runtime_disable(&pdev->dev);
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(r->start, resource_size(r));
- base = mcspi->base;
spi_unregister_master(master);
- iounmap(base);
kfree(dma_channels);
- destroy_workqueue(mcspi->wq);
platform_set_drvdata(pdev, NULL);
return 0;
@@ -1291,13 +1249,12 @@ static int omap2_mcspi_resume(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
- struct omap2_mcspi_cs *cs;
+ struct omap2_mcspi_regs *ctx = &mcspi->ctx;
+ struct omap2_mcspi_cs *cs;
omap2_mcspi_enable_clocks(mcspi);
- list_for_each_entry(cs, &omap2_mcspi_ctx[master->bus_num - 1].cs,
- node) {
+ list_for_each_entry(cs, &ctx->cs, node) {
if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE) == 0) {
-
/*
* We need to toggle CS state for OMAP take this
* change in account.
@@ -1327,21 +1284,9 @@ static struct platform_driver omap2_mcspi_driver = {
.pm = &omap2_mcspi_pm_ops,
.of_match_table = omap_mcspi_of_match,
},
- .remove = __exit_p(omap2_mcspi_remove),
+ .probe = omap2_mcspi_probe,
+ .remove = __devexit_p(omap2_mcspi_remove),
};
-
-static int __init omap2_mcspi_init(void)
-{
- return platform_driver_probe(&omap2_mcspi_driver, omap2_mcspi_probe);
-}
-subsys_initcall(omap2_mcspi_init);
-
-static void __exit omap2_mcspi_exit(void)
-{
- platform_driver_unregister(&omap2_mcspi_driver);
-
-}
-module_exit(omap2_mcspi_exit);
-
+module_platform_driver(omap2_mcspi_driver);
MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c
index 98ec53285fc7..75ac9d48ef46 100644
--- a/drivers/spi/spi-ppc4xx.c
+++ b/drivers/spi/spi-ppc4xx.c
@@ -30,7 +30,6 @@
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/of_platform.h>
-#include <linux/of_spi.h>
#include <linux/of_gpio.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
@@ -467,9 +466,6 @@ static int __init spi_ppc4xx_of_probe(struct platform_device *op)
bbp->master->setup = spi_ppc4xx_setup;
bbp->master->cleanup = spi_ppc4xx_cleanup;
- /* Allocate bus num dynamically. */
- bbp->master->bus_num = -1;
-
/* the spi->mode bits understood by this driver: */
bbp->master->mode_bits =
SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST;
diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c
index 3fb44afe27b4..9f6ba34b172c 100644
--- a/drivers/spi/spi-pxa2xx-pci.c
+++ b/drivers/spi/spi-pxa2xx-pci.c
@@ -164,17 +164,7 @@ static struct pci_driver ce4100_spi_driver = {
.remove = __devexit_p(ce4100_spi_remove),
};
-static int __init ce4100_spi_init(void)
-{
- return pci_register_driver(&ce4100_spi_driver);
-}
-module_init(ce4100_spi_init);
-
-static void __exit ce4100_spi_exit(void)
-{
- pci_unregister_driver(&ce4100_spi_driver);
-}
-module_exit(ce4100_spi_exit);
+module_pci_driver(ce4100_spi_driver);
MODULE_DESCRIPTION("CE4100 PCI-SPI glue code for PXA's driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index 354f170eab95..4894bde4bbff 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -31,7 +31,11 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/clk.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/sh_dma.h>
#include <linux/spi/spi.h>
+#include <linux/spi/rspi.h>
#define RSPI_SPCR 0x00
#define RSPI_SSLP 0x01
@@ -141,6 +145,16 @@ struct rspi_data {
spinlock_t lock;
struct clk *clk;
unsigned char spsr;
+
+ /* for dmaengine */
+ struct sh_dmae_slave dma_tx;
+ struct sh_dmae_slave dma_rx;
+ struct dma_chan *chan_tx;
+ struct dma_chan *chan_rx;
+ int irq;
+
+ unsigned dma_width_16bit:1;
+ unsigned dma_callbacked:1;
};
static void rspi_write8(struct rspi_data *rspi, u8 data, u16 offset)
@@ -265,11 +279,125 @@ static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
return 0;
}
-static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg,
- struct spi_transfer *t)
+static void rspi_dma_complete(void *arg)
+{
+ struct rspi_data *rspi = arg;
+
+ rspi->dma_callbacked = 1;
+ wake_up_interruptible(&rspi->wait);
+}
+
+static int rspi_dma_map_sg(struct scatterlist *sg, void *buf, unsigned len,
+ struct dma_chan *chan,
+ enum dma_transfer_direction dir)
+{
+ sg_init_table(sg, 1);
+ sg_set_buf(sg, buf, len);
+ sg_dma_len(sg) = len;
+ return dma_map_sg(chan->device->dev, sg, 1, dir);
+}
+
+static void rspi_dma_unmap_sg(struct scatterlist *sg, struct dma_chan *chan,
+ enum dma_transfer_direction dir)
+{
+ dma_unmap_sg(chan->device->dev, sg, 1, dir);
+}
+
+static void rspi_memory_to_8bit(void *buf, const void *data, unsigned len)
+{
+ u16 *dst = buf;
+ const u8 *src = data;
+
+ while (len) {
+ *dst++ = (u16)(*src++);
+ len--;
+ }
+}
+
+static void rspi_memory_from_8bit(void *buf, const void *data, unsigned len)
+{
+ u8 *dst = buf;
+ const u16 *src = data;
+
+ while (len) {
+ *dst++ = (u8)*src++;
+ len--;
+ }
+}
+
+static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t)
+{
+ struct scatterlist sg;
+ void *buf = NULL;
+ struct dma_async_tx_descriptor *desc;
+ unsigned len;
+ int ret = 0;
+
+ if (rspi->dma_width_16bit) {
+ /*
+ * If DMAC bus width is 16-bit, the driver allocates a dummy
+ * buffer. And, the driver converts original data into the
+ * DMAC data as the following format:
+ * original data: 1st byte, 2nd byte ...
+ * DMAC data: 1st byte, dummy, 2nd byte, dummy ...
+ */
+ len = t->len * 2;
+ buf = kmalloc(len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ rspi_memory_to_8bit(buf, t->tx_buf, t->len);
+ } else {
+ len = t->len;
+ buf = (void *)t->tx_buf;
+ }
+
+ if (!rspi_dma_map_sg(&sg, buf, len, rspi->chan_tx, DMA_TO_DEVICE)) {
+ ret = -EFAULT;
+ goto end_nomap;
+ }
+ desc = dmaengine_prep_slave_sg(rspi->chan_tx, &sg, 1, DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc) {
+ ret = -EIO;
+ goto end;
+ }
+
+ /*
+ * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be
+ * called. So, this driver disables the IRQ while DMA transfer.
+ */
+ disable_irq(rspi->irq);
+
+ rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD, RSPI_SPCR);
+ rspi_enable_irq(rspi, SPCR_SPTIE);
+ rspi->dma_callbacked = 0;
+
+ desc->callback = rspi_dma_complete;
+ desc->callback_param = rspi;
+ dmaengine_submit(desc);
+ dma_async_issue_pending(rspi->chan_tx);
+
+ ret = wait_event_interruptible_timeout(rspi->wait,
+ rspi->dma_callbacked, HZ);
+ if (ret > 0 && rspi->dma_callbacked)
+ ret = 0;
+ else if (!ret)
+ ret = -ETIMEDOUT;
+ rspi_disable_irq(rspi, SPCR_SPTIE);
+
+ enable_irq(rspi->irq);
+
+end:
+ rspi_dma_unmap_sg(&sg, rspi->chan_tx, DMA_TO_DEVICE);
+end_nomap:
+ if (rspi->dma_width_16bit)
+ kfree(buf);
+
+ return ret;
+}
+
+static void rspi_receive_init(struct rspi_data *rspi)
{
- int remain = t->len;
- u8 *data;
unsigned char spsr;
spsr = rspi_read8(rspi, RSPI_SPSR);
@@ -278,6 +406,15 @@ static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg,
if (spsr & SPSR_OVRF)
rspi_write8(rspi, rspi_read8(rspi, RSPI_SPSR) & ~SPSR_OVRF,
RSPI_SPCR);
+}
+
+static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg,
+ struct spi_transfer *t)
+{
+ int remain = t->len;
+ u8 *data;
+
+ rspi_receive_init(rspi);
data = (u8 *)t->rx_buf;
while (remain > 0) {
@@ -307,6 +444,120 @@ static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg,
return 0;
}
+static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
+{
+ struct scatterlist sg, sg_dummy;
+ void *dummy = NULL, *rx_buf = NULL;
+ struct dma_async_tx_descriptor *desc, *desc_dummy;
+ unsigned len;
+ int ret = 0;
+
+ if (rspi->dma_width_16bit) {
+ /*
+ * If DMAC bus width is 16-bit, the driver allocates a dummy
+ * buffer. And, finally the driver converts the DMAC data into
+ * actual data as the following format:
+ * DMAC data: 1st byte, dummy, 2nd byte, dummy ...
+ * actual data: 1st byte, 2nd byte ...
+ */
+ len = t->len * 2;
+ rx_buf = kmalloc(len, GFP_KERNEL);
+ if (!rx_buf)
+ return -ENOMEM;
+ } else {
+ len = t->len;
+ rx_buf = t->rx_buf;
+ }
+
+ /* prepare dummy transfer to generate SPI clocks */
+ dummy = kzalloc(len, GFP_KERNEL);
+ if (!dummy) {
+ ret = -ENOMEM;
+ goto end_nomap;
+ }
+ if (!rspi_dma_map_sg(&sg_dummy, dummy, len, rspi->chan_tx,
+ DMA_TO_DEVICE)) {
+ ret = -EFAULT;
+ goto end_nomap;
+ }
+ desc_dummy = dmaengine_prep_slave_sg(rspi->chan_tx, &sg_dummy, 1,
+ DMA_TO_DEVICE, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc_dummy) {
+ ret = -EIO;
+ goto end_dummy_mapped;
+ }
+
+ /* prepare receive transfer */
+ if (!rspi_dma_map_sg(&sg, rx_buf, len, rspi->chan_rx,
+ DMA_FROM_DEVICE)) {
+ ret = -EFAULT;
+ goto end_dummy_mapped;
+
+ }
+ desc = dmaengine_prep_slave_sg(rspi->chan_rx, &sg, 1, DMA_FROM_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc) {
+ ret = -EIO;
+ goto end;
+ }
+
+ rspi_receive_init(rspi);
+
+ /*
+ * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be
+ * called. So, this driver disables the IRQ while DMA transfer.
+ */
+ disable_irq(rspi->irq);
+
+ rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD, RSPI_SPCR);
+ rspi_enable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE);
+ rspi->dma_callbacked = 0;
+
+ desc->callback = rspi_dma_complete;
+ desc->callback_param = rspi;
+ dmaengine_submit(desc);
+ dma_async_issue_pending(rspi->chan_rx);
+
+ desc_dummy->callback = NULL; /* No callback */
+ dmaengine_submit(desc_dummy);
+ dma_async_issue_pending(rspi->chan_tx);
+
+ ret = wait_event_interruptible_timeout(rspi->wait,
+ rspi->dma_callbacked, HZ);
+ if (ret > 0 && rspi->dma_callbacked)
+ ret = 0;
+ else if (!ret)
+ ret = -ETIMEDOUT;
+ rspi_disable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE);
+
+ enable_irq(rspi->irq);
+
+end:
+ rspi_dma_unmap_sg(&sg, rspi->chan_rx, DMA_FROM_DEVICE);
+end_dummy_mapped:
+ rspi_dma_unmap_sg(&sg_dummy, rspi->chan_tx, DMA_TO_DEVICE);
+end_nomap:
+ if (rspi->dma_width_16bit) {
+ if (!ret)
+ rspi_memory_from_8bit(t->rx_buf, rx_buf, t->len);
+ kfree(rx_buf);
+ }
+ kfree(dummy);
+
+ return ret;
+}
+
+static int rspi_is_dma(struct rspi_data *rspi, struct spi_transfer *t)
+{
+ if (t->tx_buf && rspi->chan_tx)
+ return 1;
+ /* If the module receives data by DMAC, it also needs TX DMAC */
+ if (t->rx_buf && rspi->chan_tx && rspi->chan_rx)
+ return 1;
+
+ return 0;
+}
+
static void rspi_work(struct work_struct *work)
{
struct rspi_data *rspi = container_of(work, struct rspi_data, ws);
@@ -325,12 +576,18 @@ static void rspi_work(struct work_struct *work)
list_for_each_entry(t, &mesg->transfers, transfer_list) {
if (t->tx_buf) {
- ret = rspi_send_pio(rspi, mesg, t);
+ if (rspi_is_dma(rspi, t))
+ ret = rspi_send_dma(rspi, t);
+ else
+ ret = rspi_send_pio(rspi, mesg, t);
if (ret < 0)
goto error;
}
if (t->rx_buf) {
- ret = rspi_receive_pio(rspi, mesg, t);
+ if (rspi_is_dma(rspi, t))
+ ret = rspi_receive_dma(rspi, t);
+ else
+ ret = rspi_receive_pio(rspi, mesg, t);
if (ret < 0)
goto error;
}
@@ -406,11 +663,58 @@ static irqreturn_t rspi_irq(int irq, void *_sr)
return ret;
}
+static bool rspi_filter(struct dma_chan *chan, void *filter_param)
+{
+ chan->private = filter_param;
+ return true;
+}
+
+static void __devinit rspi_request_dma(struct rspi_data *rspi,
+ struct platform_device *pdev)
+{
+ struct rspi_plat_data *rspi_pd = pdev->dev.platform_data;
+ dma_cap_mask_t mask;
+
+ if (!rspi_pd)
+ return;
+
+ rspi->dma_width_16bit = rspi_pd->dma_width_16bit;
+
+ /* If the module receives data by DMAC, it also needs TX DMAC */
+ if (rspi_pd->dma_rx_id && rspi_pd->dma_tx_id) {
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ rspi->dma_rx.slave_id = rspi_pd->dma_rx_id;
+ rspi->chan_rx = dma_request_channel(mask, rspi_filter,
+ &rspi->dma_rx);
+ if (rspi->chan_rx)
+ dev_info(&pdev->dev, "Use DMA when rx.\n");
+ }
+ if (rspi_pd->dma_tx_id) {
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ rspi->dma_tx.slave_id = rspi_pd->dma_tx_id;
+ rspi->chan_tx = dma_request_channel(mask, rspi_filter,
+ &rspi->dma_tx);
+ if (rspi->chan_tx)
+ dev_info(&pdev->dev, "Use DMA when tx\n");
+ }
+}
+
+static void __devexit rspi_release_dma(struct rspi_data *rspi)
+{
+ if (rspi->chan_tx)
+ dma_release_channel(rspi->chan_tx);
+ if (rspi->chan_rx)
+ dma_release_channel(rspi->chan_rx);
+}
+
static int __devexit rspi_remove(struct platform_device *pdev)
{
struct rspi_data *rspi = dev_get_drvdata(&pdev->dev);
spi_unregister_master(rspi->master);
+ rspi_release_dma(rspi);
free_irq(platform_get_irq(pdev, 0), rspi);
clk_put(rspi->clk);
iounmap(rspi->addr);
@@ -483,6 +787,9 @@ static int __devinit rspi_probe(struct platform_device *pdev)
goto error3;
}
+ rspi->irq = irq;
+ rspi_request_dma(rspi, pdev);
+
ret = spi_register_master(master);
if (ret < 0) {
dev_err(&pdev->dev, "spi_register_master error.\n");
@@ -494,6 +801,7 @@ static int __devinit rspi_probe(struct platform_device *pdev)
return 0;
error4:
+ rspi_release_dma(rspi);
free_irq(irq, rspi);
error3:
clk_put(rspi->clk);
diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c
index 52fe495bb32a..ecc3d9763d10 100644
--- a/drivers/spi/spi-sirf.c
+++ b/drivers/spi/spi-sirf.c
@@ -19,7 +19,7 @@
#include <linux/of_gpio.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
-#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/consumer.h>
#define DRIVER_NAME "sirfsoc_spi"
@@ -127,7 +127,7 @@ struct sirfsoc_spi {
void __iomem *base;
u32 ctrl_freq; /* SPI controller clock speed */
struct clk *clk;
- struct pinmux *pmx;
+ struct pinctrl *p;
/* rx & tx bufs from the spi_transfer */
const void *tx;
@@ -560,17 +560,15 @@ static int __devinit spi_sirfsoc_probe(struct platform_device *pdev)
master->bus_num = pdev->id;
sspi->bitbang.master->dev.of_node = pdev->dev.of_node;
- sspi->pmx = pinmux_get(&pdev->dev, NULL);
- ret = IS_ERR(sspi->pmx);
+ sspi->p = pinctrl_get_select_default(&pdev->dev);
+ ret = IS_ERR(sspi->p);
if (ret)
goto free_master;
- pinmux_enable(sspi->pmx);
-
sspi->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(sspi->clk)) {
ret = -EINVAL;
- goto free_pmx;
+ goto free_pin;
}
clk_enable(sspi->clk);
sspi->ctrl_freq = clk_get_rate(sspi->clk);
@@ -598,9 +596,8 @@ static int __devinit spi_sirfsoc_probe(struct platform_device *pdev)
free_clk:
clk_disable(sspi->clk);
clk_put(sspi->clk);
-free_pmx:
- pinmux_disable(sspi->pmx);
- pinmux_put(sspi->pmx);
+free_pin:
+ pinctrl_put(sspi->p);
free_master:
spi_master_put(master);
err_cs:
@@ -623,8 +620,7 @@ static int __devexit spi_sirfsoc_remove(struct platform_device *pdev)
}
clk_disable(sspi->clk);
clk_put(sspi->clk);
- pinmux_disable(sspi->pmx);
- pinmux_put(sspi->pmx);
+ pinctrl_put(sspi->p);
spi_master_put(master);
return 0;
}
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c
index ec47d3bdfd13..cd56dcf46320 100644
--- a/drivers/spi/spi-topcliff-pch.c
+++ b/drivers/spi/spi-topcliff-pch.c
@@ -1438,7 +1438,6 @@ static int __devinit pch_spi_pd_probe(struct platform_device *plat_dev)
plat_dev->id, data->io_remap_addr);
/* initialize members of SPI master */
- master->bus_num = -1;
master->num_chipselect = PCH_MAX_CS;
master->setup = pch_spi_setup;
master->transfer = pch_spi_transfer;
@@ -1779,7 +1778,7 @@ static struct pci_driver pch_spi_pcidev_driver = {
.name = "pch_spi",
.id_table = pch_spi_pcidev_id,
.probe = pch_spi_probe,
- .remove = pch_spi_remove,
+ .remove = __devexit_p(pch_spi_remove),
.suspend = pch_spi_suspend,
.resume = pch_spi_resume,
};
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 3d8f662e4fe9..1041cb83d67a 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -2,6 +2,7 @@
* SPI init/core code
*
* Copyright (C) 2005 David Brownell
+ * Copyright (C) 2008 Secret Lab Technologies Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,15 +20,16 @@
*/
#include <linux/kernel.h>
+#include <linux/kmod.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/cache.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
+#include <linux/of_irq.h>
#include <linux/slab.h>
#include <linux/mod_devicetable.h>
#include <linux/spi/spi.h>
-#include <linux/of_spi.h>
#include <linux/pm_runtime.h>
#include <linux/export.h>
#include <linux/sched.h>
@@ -530,7 +532,7 @@ static void spi_pump_messages(struct kthread_work *work)
/* Lock queue and check for queue work */
spin_lock_irqsave(&master->queue_lock, flags);
if (list_empty(&master->queue) || !master->running) {
- if (master->busy) {
+ if (master->busy && master->unprepare_transfer_hardware) {
ret = master->unprepare_transfer_hardware(master);
if (ret) {
spin_unlock_irqrestore(&master->queue_lock, flags);
@@ -560,7 +562,7 @@ static void spi_pump_messages(struct kthread_work *work)
master->busy = true;
spin_unlock_irqrestore(&master->queue_lock, flags);
- if (!was_busy) {
+ if (!was_busy && master->prepare_transfer_hardware) {
ret = master->prepare_transfer_hardware(master);
if (ret) {
dev_err(&master->dev,
@@ -798,6 +800,94 @@ err_init_queue:
/*-------------------------------------------------------------------------*/
+#if defined(CONFIG_OF) && !defined(CONFIG_SPARC)
+/**
+ * of_register_spi_devices() - Register child devices onto the SPI bus
+ * @master: Pointer to spi_master device
+ *
+ * Registers an spi_device for each child node of master node which has a 'reg'
+ * property.
+ */
+static void of_register_spi_devices(struct spi_master *master)
+{
+ struct spi_device *spi;
+ struct device_node *nc;
+ const __be32 *prop;
+ int rc;
+ int len;
+
+ if (!master->dev.of_node)
+ return;
+
+ for_each_child_of_node(master->dev.of_node, nc) {
+ /* Alloc an spi_device */
+ spi = spi_alloc_device(master);
+ if (!spi) {
+ dev_err(&master->dev, "spi_device alloc error for %s\n",
+ nc->full_name);
+ spi_dev_put(spi);
+ continue;
+ }
+
+ /* Select device driver */
+ if (of_modalias_node(nc, spi->modalias,
+ sizeof(spi->modalias)) < 0) {
+ dev_err(&master->dev, "cannot find modalias for %s\n",
+ nc->full_name);
+ spi_dev_put(spi);
+ continue;
+ }
+
+ /* Device address */
+ prop = of_get_property(nc, "reg", &len);
+ if (!prop || len < sizeof(*prop)) {
+ dev_err(&master->dev, "%s has no 'reg' property\n",
+ nc->full_name);
+ spi_dev_put(spi);
+ continue;
+ }
+ spi->chip_select = be32_to_cpup(prop);
+
+ /* Mode (clock phase/polarity/etc.) */
+ if (of_find_property(nc, "spi-cpha", NULL))
+ spi->mode |= SPI_CPHA;
+ if (of_find_property(nc, "spi-cpol", NULL))
+ spi->mode |= SPI_CPOL;
+ if (of_find_property(nc, "spi-cs-high", NULL))
+ spi->mode |= SPI_CS_HIGH;
+
+ /* Device speed */
+ prop = of_get_property(nc, "spi-max-frequency", &len);
+ if (!prop || len < sizeof(*prop)) {
+ dev_err(&master->dev, "%s has no 'spi-max-frequency' property\n",
+ nc->full_name);
+ spi_dev_put(spi);
+ continue;
+ }
+ spi->max_speed_hz = be32_to_cpup(prop);
+
+ /* IRQ */
+ spi->irq = irq_of_parse_and_map(nc, 0);
+
+ /* Store a pointer to the node in the device structure */
+ of_node_get(nc);
+ spi->dev.of_node = nc;
+
+ /* Register the new device */
+ request_module(spi->modalias);
+ rc = spi_add_device(spi);
+ if (rc) {
+ dev_err(&master->dev, "spi_device register error %s\n",
+ nc->full_name);
+ spi_dev_put(spi);
+ }
+
+ }
+}
+#else
+static void of_register_spi_devices(struct spi_master *master) { }
+#endif
+
static void spi_master_release(struct device *dev)
{
struct spi_master *master;
@@ -846,6 +936,8 @@ struct spi_master *spi_alloc_master(struct device *dev, unsigned size)
return NULL;
device_initialize(&master->dev);
+ master->bus_num = -1;
+ master->num_chipselect = 1;
master->dev.class = &spi_master_class;
master->dev.parent = get_device(dev);
spi_master_set_devdata(master, &master[1]);
diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c
index bad7ba517a1c..f551e5376147 100644
--- a/drivers/ssb/b43_pci_bridge.c
+++ b/drivers/ssb/b43_pci_bridge.c
@@ -29,6 +29,8 @@ static const struct pci_device_id b43_pci_bridge_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4319) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4320) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4322) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43222) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4325) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4328) },
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
index ed4124469a3a..e9d94968f394 100644
--- a/drivers/ssb/pci.c
+++ b/drivers/ssb/pci.c
@@ -178,6 +178,18 @@ err_pci:
#define SPEX(_outvar, _offset, _mask, _shift) \
SPEX16(_outvar, _offset, _mask, _shift)
+#define SPEX_ARRAY8(_field, _offset, _mask, _shift) \
+ do { \
+ SPEX(_field[0], _offset + 0, _mask, _shift); \
+ SPEX(_field[1], _offset + 2, _mask, _shift); \
+ SPEX(_field[2], _offset + 4, _mask, _shift); \
+ SPEX(_field[3], _offset + 6, _mask, _shift); \
+ SPEX(_field[4], _offset + 8, _mask, _shift); \
+ SPEX(_field[5], _offset + 10, _mask, _shift); \
+ SPEX(_field[6], _offset + 12, _mask, _shift); \
+ SPEX(_field[7], _offset + 14, _mask, _shift); \
+ } while (0)
+
static inline u8 ssb_crc8(u8 crc, u8 data)
{
@@ -360,8 +372,9 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);
SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);
SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
- SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
- SSB_SPROM1_BINF_CCODE_SHIFT);
+ if (out->revision == 1)
+ SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
+ SSB_SPROM1_BINF_CCODE_SHIFT);
SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
SSB_SPROM1_BINF_ANTA_SHIFT);
SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
@@ -387,6 +400,8 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
if (out->revision >= 2)
SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0);
+ SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8);
+ SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0);
/* Extract the antenna gain values. */
out->antenna_gain.a0 = r123_extract_antgain(out->revision, in,
@@ -455,14 +470,17 @@ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0);
SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A,
SSB_SPROM4_ETHPHY_ET1A_SHIFT);
+ SPEX(board_rev, SSB_SPROM4_BOARDREV, 0xFFFF, 0);
if (out->revision == 4) {
- SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0);
+ SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8);
+ SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0);
SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0);
SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0);
SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0);
SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0);
} else {
- SPEX(country_code, SSB_SPROM5_CCODE, 0xFFFF, 0);
+ SPEX(alpha2[0], SSB_SPROM5_CCODE, 0xff00, 8);
+ SPEX(alpha2[1], SSB_SPROM5_CCODE, 0x00ff, 0);
SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0);
SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0);
SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0);
@@ -525,7 +543,9 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
v = in[SPOFF(SSB_SPROM8_IL0MAC) + i];
*(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
}
- SPEX(country_code, SSB_SPROM8_CCODE, 0xFFFF, 0);
+ SPEX(board_rev, SSB_SPROM8_BOARDREV, 0xFFFF, 0);
+ SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
+ SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0);
SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0);
SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, 0xFFFF, 0);
@@ -655,6 +675,63 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G,
SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT);
+ SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON,
+ SSB_SPROM8_LEDDC_ON_SHIFT);
+ SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF,
+ SSB_SPROM8_LEDDC_OFF_SHIFT);
+
+ SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN,
+ SSB_SPROM8_TXRXC_TXCHAIN_SHIFT);
+ SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN,
+ SSB_SPROM8_TXRXC_RXCHAIN_SHIFT);
+ SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH,
+ SSB_SPROM8_TXRXC_SWITCH_SHIFT);
+
+ SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0);
+
+ SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0);
+ SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0);
+ SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0);
+ SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0);
+
+ SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP,
+ SSB_SPROM8_RAWTS_RAWTEMP_SHIFT);
+ SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER,
+ SSB_SPROM8_RAWTS_MEASPOWER_SHIFT);
+ SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX,
+ SSB_SPROM8_OPT_CORRX_TEMP_SLOPE,
+ SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT);
+ SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX,
+ SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT);
+ SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX,
+ SSB_SPROM8_OPT_CORRX_TEMP_OPTION,
+ SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT);
+ SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP,
+ SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR,
+ SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT);
+ SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP,
+ SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP,
+ SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT);
+ SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL,
+ SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT);
+
+ SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0);
+ SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0);
+ SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0);
+ SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0);
+
+ SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH,
+ SSB_SPROM8_THERMAL_TRESH_SHIFT);
+ SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET,
+ SSB_SPROM8_THERMAL_OFFSET_SHIFT);
+ SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA,
+ SSB_SPROM8_TEMPDELTA_PHYCAL,
+ SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT);
+ SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD,
+ SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT);
+ SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA,
+ SSB_SPROM8_TEMPDELTA_HYSTERESIS,
+ SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT);
sprom_extract_r458(out, in);
/* TODO - get remaining rev 8 stuff needed */
@@ -784,7 +861,6 @@ static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
{
bi->vendor = bus->host_pci->subsystem_vendor;
bi->type = bus->host_pci->subsystem_device;
- bi->rev = bus->host_pci->revision;
}
int ssb_pci_get_invariants(struct ssb_bus *bus,
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 97d412d91458..05e33c700750 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -24,8 +24,6 @@ menuconfig STAGING
if STAGING
-source "drivers/staging/serial/Kconfig"
-
source "drivers/staging/et131x/Kconfig"
source "drivers/staging/slicoss/Kconfig"
@@ -68,14 +66,10 @@ source "drivers/staging/octeon/Kconfig"
source "drivers/staging/serqt_usb2/Kconfig"
-source "drivers/staging/quatech_usb2/Kconfig"
-
source "drivers/staging/vt6655/Kconfig"
source "drivers/staging/vt6656/Kconfig"
-source "drivers/staging/vme/Kconfig"
-
source "drivers/staging/sep/Kconfig"
source "drivers/staging/iio/Kconfig"
@@ -116,12 +110,12 @@ source "drivers/staging/cptm1217/Kconfig"
source "drivers/staging/ste_rmi4/Kconfig"
-source "drivers/staging/mei/Kconfig"
-
source "drivers/staging/nvec/Kconfig"
source "drivers/staging/media/Kconfig"
+source "drivers/staging/net/Kconfig"
+
source "drivers/staging/omapdrm/Kconfig"
source "drivers/staging/android/Kconfig"
@@ -132,4 +126,10 @@ source "drivers/staging/ramster/Kconfig"
source "drivers/staging/ozwpan/Kconfig"
+source "drivers/staging/ccg/Kconfig"
+
+source "drivers/staging/ipack/Kconfig"
+
+source "drivers/staging/gdm72xx/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index ffe7d44374e6..a987b3ad380b 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -3,8 +3,8 @@
# fix for build system bug...
obj-$(CONFIG_STAGING) += staging.o
-obj-y += serial/
obj-y += media/
+obj-y += net/
obj-$(CONFIG_ET131X) += et131x/
obj-$(CONFIG_SLICOSS) += slicoss/
obj-$(CONFIG_USBIP_CORE) += usbip/
@@ -25,11 +25,11 @@ obj-$(CONFIG_TRANZPORT) += frontier/
obj-$(CONFIG_IDE_PHISON) += phison/
obj-$(CONFIG_LINE6_USB) += line6/
obj-$(CONFIG_USB_SERIAL_QUATECH2) += serqt_usb2/
-obj-$(CONFIG_USB_SERIAL_QUATECH_USB2) += quatech_usb2/
obj-$(CONFIG_OCTEON_ETHERNET) += octeon/
obj-$(CONFIG_VT6655) += vt6655/
obj-$(CONFIG_VT6656) += vt6656/
obj-$(CONFIG_VME_BUS) += vme/
+obj-$(CONFIG_IPACK_BUS) += ipack/
obj-$(CONFIG_DX_SEP) += sep/
obj-$(CONFIG_IIO) += iio/
obj-$(CONFIG_ZRAM) += zram/
@@ -50,10 +50,11 @@ obj-$(CONFIG_FT1000) += ft1000/
obj-$(CONFIG_SPEAKUP) += speakup/
obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217) += cptm1217/
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += ste_rmi4/
-obj-$(CONFIG_INTEL_MEI) += mei/
obj-$(CONFIG_MFD_NVEC) += nvec/
obj-$(CONFIG_DRM_OMAP) += omapdrm/
obj-$(CONFIG_ANDROID) += android/
obj-$(CONFIG_PHONE) += telephony/
obj-$(CONFIG_RAMSTER) += ramster/
obj-$(CONFIG_USB_WPAN_HCD) += ozwpan/
+obj-$(CONFIG_USB_G_CCG) += ccg/
+obj-$(CONFIG_WIMAX_GDM72XX) += gdm72xx/
diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig
index eb1dee26bda3..0e16b594460f 100644
--- a/drivers/staging/android/Kconfig
+++ b/drivers/staging/android/Kconfig
@@ -25,17 +25,9 @@ config ANDROID_LOGGER
tristate "Android log driver"
default n
-config ANDROID_PERSISTENT_RAM
- bool
- depends on HAVE_MEMBLOCK
- select REED_SOLOMON
- select REED_SOLOMON_ENC8
- select REED_SOLOMON_DEC8
-
config ANDROID_RAM_CONSOLE
bool "Android RAM buffer console"
- depends on !S390 && !UML && HAVE_MEMBLOCK
- select ANDROID_PERSISTENT_RAM
+ depends on !S390 && !UML && HAVE_MEMBLOCK && PSTORE_RAM=y
default n
config ANDROID_TIMED_OUTPUT
@@ -53,33 +45,14 @@ config ANDROID_LOW_MEMORY_KILLER
---help---
Register processes to be killed when memory is low
-source "drivers/staging/android/switch/Kconfig"
-
-config ANDROID_INTF_ALARM
+config ANDROID_INTF_ALARM_DEV
bool "Android alarm driver"
depends on RTC_CLASS
default n
help
Provides non-wakeup and rtc backed wakeup alarms based on rtc or
elapsed realtime, and a non-wakeup alarm on the monotonic clock.
- Also provides an interface to set the wall time which must be used
- for elapsed realtime to work.
-
-config ANDROID_INTF_ALARM_DEV
- bool "Android alarm device"
- depends on ANDROID_INTF_ALARM
- default y
- help
- Exports the alarm interface to user-space.
-
-config ANDROID_ALARM_OLDDRV_COMPAT
- bool "Android Alarm compatability with old drivers"
- depends on ANDROID_INTF_ALARM
- default n
- help
- Provides preprocessor alias to aid compatability with
- older out-of-tree drivers that use the Android Alarm
- in-kernel API. This will be removed eventually.
+ Also exports the alarm interface to user-space.
endif # if ANDROID
diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile
index 9b6c9ed91f69..98711e2b2afa 100644
--- a/drivers/staging/android/Makefile
+++ b/drivers/staging/android/Makefile
@@ -1,11 +1,8 @@
obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o
obj-$(CONFIG_ASHMEM) += ashmem.o
obj-$(CONFIG_ANDROID_LOGGER) += logger.o
-obj-$(CONFIG_ANDROID_PERSISTENT_RAM) += persistent_ram.o
obj-$(CONFIG_ANDROID_RAM_CONSOLE) += ram_console.o
obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o
obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o
obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o
-obj-$(CONFIG_ANDROID_SWITCH) += switch/
-obj-$(CONFIG_ANDROID_INTF_ALARM) += alarm.o
obj-$(CONFIG_ANDROID_INTF_ALARM_DEV) += alarm-dev.o
diff --git a/drivers/staging/android/alarm-dev.c b/drivers/staging/android/alarm-dev.c
index 03efb34cbe2e..53ce6ecf390a 100644
--- a/drivers/staging/android/alarm-dev.c
+++ b/drivers/staging/android/alarm-dev.c
@@ -22,19 +22,9 @@
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/uaccess.h>
+#include <linux/alarmtimer.h>
#include "android_alarm.h"
-/* XXX - Hack out wakelocks, while they are out of tree */
-struct wake_lock {
- int i;
-};
-#define wake_lock(x)
-#define wake_lock_timeout(x, y)
-#define wake_unlock(x)
-#define WAKE_LOCK_SUSPEND 0
-#define wake_lock_init(x, y, z) ((x)->i = 1)
-#define wake_lock_destroy(x)
-
#define ANDROID_ALARM_PRINT_INFO (1U << 0)
#define ANDROID_ALARM_PRINT_IO (1U << 1)
#define ANDROID_ALARM_PRINT_INT (1U << 2)
@@ -54,19 +44,65 @@ module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
ANDROID_ALARM_RTC_WAKEUP_MASK | \
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK)
-/* support old usespace code */
+/* support old userspace code */
#define ANDROID_ALARM_SET_OLD _IOW('a', 2, time_t) /* set alarm */
#define ANDROID_ALARM_SET_AND_WAIT_OLD _IOW('a', 3, time_t)
static int alarm_opened;
static DEFINE_SPINLOCK(alarm_slock);
-static struct wake_lock alarm_wake_lock;
+static struct wakeup_source alarm_wake_lock;
static DECLARE_WAIT_QUEUE_HEAD(alarm_wait_queue);
static uint32_t alarm_pending;
static uint32_t alarm_enabled;
static uint32_t wait_pending;
-static struct android_alarm alarms[ANDROID_ALARM_TYPE_COUNT];
+struct devalarm {
+ union {
+ struct hrtimer hrt;
+ struct alarm alrm;
+ } u;
+ enum android_alarm_type type;
+};
+
+static struct devalarm alarms[ANDROID_ALARM_TYPE_COUNT];
+
+
+static int is_wakeup(enum android_alarm_type type)
+{
+ if (type == ANDROID_ALARM_RTC_WAKEUP ||
+ type == ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP)
+ return 1;
+ return 0;
+}
+
+
+static void devalarm_start(struct devalarm *alrm, ktime_t exp)
+{
+ if (is_wakeup(alrm->type))
+ alarm_start(&alrm->u.alrm, exp);
+ else
+ hrtimer_start(&alrm->u.hrt, exp, HRTIMER_MODE_ABS);
+}
+
+
+static int devalarm_try_to_cancel(struct devalarm *alrm)
+{
+ int ret;
+ if (is_wakeup(alrm->type))
+ ret = alarm_try_to_cancel(&alrm->u.alrm);
+ else
+ ret = hrtimer_try_to_cancel(&alrm->u.hrt);
+ return ret;
+}
+
+static void devalarm_cancel(struct devalarm *alrm)
+{
+ if (is_wakeup(alrm->type))
+ alarm_cancel(&alrm->u.alrm);
+ else
+ hrtimer_cancel(&alrm->u.hrt);
+}
+
static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
@@ -75,6 +111,8 @@ static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct timespec new_alarm_time;
struct timespec new_rtc_time;
struct timespec tmp_time;
+ struct rtc_time new_rtc_tm;
+ struct rtc_device *rtc_dev;
enum android_alarm_type alarm_type = ANDROID_ALARM_IOCTL_TO_TYPE(cmd);
uint32_t alarm_type_mask = 1U << alarm_type;
@@ -101,11 +139,11 @@ static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case ANDROID_ALARM_CLEAR(0):
spin_lock_irqsave(&alarm_slock, flags);
pr_alarm(IO, "alarm %d clear\n", alarm_type);
- android_alarm_try_to_cancel(&alarms[alarm_type]);
+ devalarm_try_to_cancel(&alarms[alarm_type]);
if (alarm_pending) {
alarm_pending &= ~alarm_type_mask;
if (!alarm_pending && !wait_pending)
- wake_unlock(&alarm_wake_lock);
+ __pm_relax(&alarm_wake_lock);
}
alarm_enabled &= ~alarm_type_mask;
spin_unlock_irqrestore(&alarm_slock, flags);
@@ -132,8 +170,7 @@ from_old_alarm_set:
pr_alarm(IO, "alarm %d set %ld.%09ld\n", alarm_type,
new_alarm_time.tv_sec, new_alarm_time.tv_nsec);
alarm_enabled |= alarm_type_mask;
- android_alarm_start_range(&alarms[alarm_type],
- timespec_to_ktime(new_alarm_time),
+ devalarm_start(&alarms[alarm_type],
timespec_to_ktime(new_alarm_time));
spin_unlock_irqrestore(&alarm_slock, flags);
if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0)
@@ -144,7 +181,7 @@ from_old_alarm_set:
spin_lock_irqsave(&alarm_slock, flags);
pr_alarm(IO, "alarm wait\n");
if (!alarm_pending && wait_pending) {
- wake_unlock(&alarm_wake_lock);
+ __pm_relax(&alarm_wake_lock);
wait_pending = 0;
}
spin_unlock_irqrestore(&alarm_slock, flags);
@@ -163,7 +200,13 @@ from_old_alarm_set:
rv = -EFAULT;
goto err1;
}
- rv = android_alarm_set_rtc(new_rtc_time);
+ rtc_time_to_tm(new_rtc_time.tv_sec, &new_rtc_tm);
+ rtc_dev = alarmtimer_get_rtcdev();
+ rv = do_settimeofday(&new_rtc_time);
+ if (rv < 0)
+ goto err1;
+ if (rtc_dev)
+ rv = rtc_set_time(rtc_dev, &new_rtc_tm);
spin_lock_irqsave(&alarm_slock, flags);
alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK;
wake_up(&alarm_wait_queue);
@@ -179,8 +222,7 @@ from_old_alarm_set:
break;
case ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP:
case ANDROID_ALARM_ELAPSED_REALTIME:
- tmp_time =
- ktime_to_timespec(alarm_get_elapsed_realtime());
+ get_monotonic_boottime(&tmp_time);
break;
case ANDROID_ALARM_TYPE_COUNT:
case ANDROID_ALARM_SYSTEMTIME:
@@ -224,14 +266,14 @@ static int alarm_release(struct inode *inode, struct file *file)
alarm_enabled &= ~alarm_type_mask;
}
spin_unlock_irqrestore(&alarm_slock, flags);
- android_alarm_cancel(&alarms[i]);
+ devalarm_cancel(&alarms[i]);
spin_lock_irqsave(&alarm_slock, flags);
}
if (alarm_pending | wait_pending) {
if (alarm_pending)
pr_alarm(INFO, "alarm_release: clear "
"pending alarms %x\n", alarm_pending);
- wake_unlock(&alarm_wake_lock);
+ __pm_relax(&alarm_wake_lock);
wait_pending = 0;
alarm_pending = 0;
}
@@ -241,15 +283,15 @@ static int alarm_release(struct inode *inode, struct file *file)
return 0;
}
-static void alarm_triggered(struct android_alarm *alarm)
+static void devalarm_triggered(struct devalarm *alarm)
{
unsigned long flags;
uint32_t alarm_type_mask = 1U << alarm->type;
- pr_alarm(INT, "alarm_triggered type %d\n", alarm->type);
+ pr_alarm(INT, "devalarm_triggered type %d\n", alarm->type);
spin_lock_irqsave(&alarm_slock, flags);
if (alarm_enabled & alarm_type_mask) {
- wake_lock_timeout(&alarm_wake_lock, 5 * HZ);
+ __pm_wakeup_event(&alarm_wake_lock, 5000); /* 5secs */
alarm_enabled &= ~alarm_type_mask;
alarm_pending |= alarm_type_mask;
wake_up(&alarm_wait_queue);
@@ -257,6 +299,25 @@ static void alarm_triggered(struct android_alarm *alarm)
spin_unlock_irqrestore(&alarm_slock, flags);
}
+
+static enum hrtimer_restart devalarm_hrthandler(struct hrtimer *hrt)
+{
+ struct devalarm *devalrm = container_of(hrt, struct devalarm, u.hrt);
+
+ devalarm_triggered(devalrm);
+ return HRTIMER_NORESTART;
+}
+
+static enum alarmtimer_restart devalarm_alarmhandler(struct alarm *alrm,
+ ktime_t now)
+{
+ struct devalarm *devalrm = container_of(alrm, struct devalarm, u.alrm);
+
+ devalarm_triggered(devalrm);
+ return ALARMTIMER_NORESTART;
+}
+
+
static const struct file_operations alarm_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = alarm_ioctl,
@@ -279,17 +340,31 @@ static int __init alarm_dev_init(void)
if (err)
return err;
- for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++)
- android_alarm_init(&alarms[i], i, alarm_triggered);
- wake_lock_init(&alarm_wake_lock, WAKE_LOCK_SUSPEND, "alarm");
+ alarm_init(&alarms[ANDROID_ALARM_RTC_WAKEUP].u.alrm,
+ ALARM_REALTIME, devalarm_alarmhandler);
+ hrtimer_init(&alarms[ANDROID_ALARM_RTC].u.hrt,
+ CLOCK_REALTIME, HRTIMER_MODE_ABS);
+ alarm_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].u.alrm,
+ ALARM_BOOTTIME, devalarm_alarmhandler);
+ hrtimer_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME].u.hrt,
+ CLOCK_BOOTTIME, HRTIMER_MODE_ABS);
+ hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].u.hrt,
+ CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+
+ for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {
+ alarms[i].type = i;
+ if (!is_wakeup(i))
+ alarms[i].u.hrt.function = devalarm_hrthandler;
+ }
+ wakeup_source_init(&alarm_wake_lock, "alarm");
return 0;
}
static void __exit alarm_dev_exit(void)
{
misc_deregister(&alarm_device);
- wake_lock_destroy(&alarm_wake_lock);
+ wakeup_source_trash(&alarm_wake_lock);
}
module_init(alarm_dev_init);
diff --git a/drivers/staging/android/alarm.c b/drivers/staging/android/alarm.c
deleted file mode 100644
index c68950b9e08f..000000000000
--- a/drivers/staging/android/alarm.c
+++ /dev/null
@@ -1,601 +0,0 @@
-/* drivers/rtc/alarm.c
- *
- * Copyright (C) 2007-2009 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/time.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/miscdevice.h>
-#include <linux/platform_device.h>
-#include <linux/rtc.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include "android_alarm.h"
-
-/* XXX - Hack out wakelocks, while they are out of tree */
-struct wake_lock {
- int i;
-};
-#define wake_lock(x)
-#define wake_lock_timeout(x, y)
-#define wake_unlock(x)
-#define WAKE_LOCK_SUSPEND 0
-#define wake_lock_init(x, y, z) ((x)->i = 1)
-#define wake_lock_destroy(x)
-
-#define ANDROID_ALARM_PRINT_ERROR (1U << 0)
-#define ANDROID_ALARM_PRINT_INIT_STATUS (1U << 1)
-#define ANDROID_ALARM_PRINT_TSET (1U << 2)
-#define ANDROID_ALARM_PRINT_CALL (1U << 3)
-#define ANDROID_ALARM_PRINT_SUSPEND (1U << 4)
-#define ANDROID_ALARM_PRINT_INT (1U << 5)
-#define ANDROID_ALARM_PRINT_FLOW (1U << 6)
-
-static int debug_mask = ANDROID_ALARM_PRINT_ERROR | \
- ANDROID_ALARM_PRINT_INIT_STATUS;
-module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-#define pr_alarm(debug_level_mask, args...) \
- do { \
- if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask) { \
- pr_info(args); \
- } \
- } while (0)
-
-#define ANDROID_ALARM_WAKEUP_MASK ( \
- ANDROID_ALARM_RTC_WAKEUP_MASK | \
- ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK)
-
-/* support old usespace code */
-#define ANDROID_ALARM_SET_OLD _IOW('a', 2, time_t) /* set alarm */
-#define ANDROID_ALARM_SET_AND_WAIT_OLD _IOW('a', 3, time_t)
-
-struct alarm_queue {
- struct rb_root alarms;
- struct rb_node *first;
- struct hrtimer timer;
- ktime_t delta;
- bool stopped;
- ktime_t stopped_time;
-};
-
-static struct rtc_device *alarm_rtc_dev;
-static DEFINE_SPINLOCK(alarm_slock);
-static DEFINE_MUTEX(alarm_setrtc_mutex);
-static struct wake_lock alarm_rtc_wake_lock;
-static struct platform_device *alarm_platform_dev;
-struct alarm_queue alarms[ANDROID_ALARM_TYPE_COUNT];
-static bool suspended;
-
-static void update_timer_locked(struct alarm_queue *base, bool head_removed)
-{
- struct android_alarm *alarm;
- bool is_wakeup = base == &alarms[ANDROID_ALARM_RTC_WAKEUP] ||
- base == &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP];
-
- if (base->stopped) {
- pr_alarm(FLOW, "changed alarm while setting the wall time\n");
- return;
- }
-
- if (is_wakeup && !suspended && head_removed)
- wake_unlock(&alarm_rtc_wake_lock);
-
- if (!base->first)
- return;
-
- alarm = container_of(base->first, struct android_alarm, node);
-
- pr_alarm(FLOW, "selected alarm, type %d, func %pF at %lld\n",
- alarm->type, alarm->function, ktime_to_ns(alarm->expires));
-
- if (is_wakeup && suspended) {
- pr_alarm(FLOW, "changed alarm while suspened\n");
- wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ);
- return;
- }
-
- hrtimer_try_to_cancel(&base->timer);
- base->timer.node.expires = ktime_add(base->delta, alarm->expires);
- base->timer._softexpires = ktime_add(base->delta, alarm->softexpires);
- hrtimer_start_expires(&base->timer, HRTIMER_MODE_ABS);
-}
-
-static void alarm_enqueue_locked(struct android_alarm *alarm)
-{
- struct alarm_queue *base = &alarms[alarm->type];
- struct rb_node **link = &base->alarms.rb_node;
- struct rb_node *parent = NULL;
- struct android_alarm *entry;
- int leftmost = 1;
- bool was_first = false;
-
- pr_alarm(FLOW, "added alarm, type %d, func %pF at %lld\n",
- alarm->type, alarm->function, ktime_to_ns(alarm->expires));
-
- if (base->first == &alarm->node) {
- base->first = rb_next(&alarm->node);
- was_first = true;
- }
- if (!RB_EMPTY_NODE(&alarm->node)) {
- rb_erase(&alarm->node, &base->alarms);
- RB_CLEAR_NODE(&alarm->node);
- }
-
- while (*link) {
- parent = *link;
- entry = rb_entry(parent, struct android_alarm, node);
- /*
- * We dont care about collisions. Nodes with
- * the same expiry time stay together.
- */
- if (alarm->expires.tv64 < entry->expires.tv64) {
- link = &(*link)->rb_left;
- } else {
- link = &(*link)->rb_right;
- leftmost = 0;
- }
- }
- if (leftmost)
- base->first = &alarm->node;
- if (leftmost || was_first)
- update_timer_locked(base, was_first);
-
- rb_link_node(&alarm->node, parent, link);
- rb_insert_color(&alarm->node, &base->alarms);
-}
-
-/**
- * android_alarm_init - initialize an alarm
- * @alarm: the alarm to be initialized
- * @type: the alarm type to be used
- * @function: alarm callback function
- */
-void android_alarm_init(struct android_alarm *alarm,
- enum android_alarm_type type, void (*function)(struct android_alarm *))
-{
- RB_CLEAR_NODE(&alarm->node);
- alarm->type = type;
- alarm->function = function;
-
- pr_alarm(FLOW, "created alarm, type %d, func %pF\n", type, function);
-}
-
-
-/**
- * android_alarm_start_range - (re)start an alarm
- * @alarm: the alarm to be added
- * @start: earliest expiry time
- * @end: expiry time
- */
-void android_alarm_start_range(struct android_alarm *alarm, ktime_t start,
- ktime_t end)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&alarm_slock, flags);
- alarm->softexpires = start;
- alarm->expires = end;
- alarm_enqueue_locked(alarm);
- spin_unlock_irqrestore(&alarm_slock, flags);
-}
-
-/**
- * android_alarm_try_to_cancel - try to deactivate an alarm
- * @alarm: alarm to stop
- *
- * Returns:
- * 0 when the alarm was not active
- * 1 when the alarm was active
- * -1 when the alarm may currently be excuting the callback function and
- * cannot be stopped (it may also be inactive)
- */
-int android_alarm_try_to_cancel(struct android_alarm *alarm)
-{
- struct alarm_queue *base = &alarms[alarm->type];
- unsigned long flags;
- bool first = false;
- int ret = 0;
-
- spin_lock_irqsave(&alarm_slock, flags);
- if (!RB_EMPTY_NODE(&alarm->node)) {
- pr_alarm(FLOW, "canceled alarm, type %d, func %pF at %lld\n",
- alarm->type, alarm->function,
- ktime_to_ns(alarm->expires));
- ret = 1;
- if (base->first == &alarm->node) {
- base->first = rb_next(&alarm->node);
- first = true;
- }
- rb_erase(&alarm->node, &base->alarms);
- RB_CLEAR_NODE(&alarm->node);
- if (first)
- update_timer_locked(base, true);
- } else
- pr_alarm(FLOW, "tried to cancel alarm, type %d, func %pF\n",
- alarm->type, alarm->function);
- spin_unlock_irqrestore(&alarm_slock, flags);
- if (!ret && hrtimer_callback_running(&base->timer))
- ret = -1;
- return ret;
-}
-
-/**
- * android_alarm_cancel - cancel an alarm and wait for the handler to finish.
- * @alarm: the alarm to be cancelled
- *
- * Returns:
- * 0 when the alarm was not active
- * 1 when the alarm was active
- */
-int android_alarm_cancel(struct android_alarm *alarm)
-{
- for (;;) {
- int ret = android_alarm_try_to_cancel(alarm);
- if (ret >= 0)
- return ret;
- cpu_relax();
- }
-}
-
-/**
- * alarm_set_rtc - set the kernel and rtc walltime
- * @new_time: timespec value containing the new time
- */
-int android_alarm_set_rtc(struct timespec new_time)
-{
- int i;
- int ret;
- unsigned long flags;
- struct rtc_time rtc_new_rtc_time;
- struct timespec tmp_time;
-
- rtc_time_to_tm(new_time.tv_sec, &rtc_new_rtc_time);
-
- pr_alarm(TSET, "set rtc %ld %ld - rtc %02d:%02d:%02d %02d/%02d/%04d\n",
- new_time.tv_sec, new_time.tv_nsec,
- rtc_new_rtc_time.tm_hour, rtc_new_rtc_time.tm_min,
- rtc_new_rtc_time.tm_sec, rtc_new_rtc_time.tm_mon + 1,
- rtc_new_rtc_time.tm_mday,
- rtc_new_rtc_time.tm_year + 1900);
-
- mutex_lock(&alarm_setrtc_mutex);
- spin_lock_irqsave(&alarm_slock, flags);
- wake_lock(&alarm_rtc_wake_lock);
- getnstimeofday(&tmp_time);
- for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
- hrtimer_try_to_cancel(&alarms[i].timer);
- alarms[i].stopped = true;
- alarms[i].stopped_time = timespec_to_ktime(tmp_time);
- }
- alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta =
- alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta =
- ktime_sub(alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta,
- timespec_to_ktime(timespec_sub(tmp_time, new_time)));
- spin_unlock_irqrestore(&alarm_slock, flags);
- ret = do_settimeofday(&new_time);
- spin_lock_irqsave(&alarm_slock, flags);
- for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
- alarms[i].stopped = false;
- update_timer_locked(&alarms[i], false);
- }
- spin_unlock_irqrestore(&alarm_slock, flags);
- if (ret < 0) {
- pr_alarm(ERROR, "alarm_set_rtc: Failed to set time\n");
- goto err;
- }
- if (!alarm_rtc_dev) {
- pr_alarm(ERROR,
- "alarm_set_rtc: no RTC, time will be lost on reboot\n");
- goto err;
- }
- ret = rtc_set_time(alarm_rtc_dev, &rtc_new_rtc_time);
- if (ret < 0)
- pr_alarm(ERROR, "alarm_set_rtc: "
- "Failed to set RTC, time will be lost on reboot\n");
-err:
- wake_unlock(&alarm_rtc_wake_lock);
- mutex_unlock(&alarm_setrtc_mutex);
- return ret;
-}
-
-/**
- * alarm_get_elapsed_realtime - get the elapsed real time in ktime_t format
- *
- * returns the time in ktime_t format
- */
-ktime_t alarm_get_elapsed_realtime(void)
-{
- ktime_t now;
- unsigned long flags;
- struct alarm_queue *base = &alarms[ANDROID_ALARM_ELAPSED_REALTIME];
-
- spin_lock_irqsave(&alarm_slock, flags);
- now = base->stopped ? base->stopped_time : ktime_get_real();
- now = ktime_sub(now, base->delta);
- spin_unlock_irqrestore(&alarm_slock, flags);
- return now;
-}
-
-static enum hrtimer_restart alarm_timer_triggered(struct hrtimer *timer)
-{
- struct alarm_queue *base;
- struct android_alarm *alarm;
- unsigned long flags;
- ktime_t now;
-
- spin_lock_irqsave(&alarm_slock, flags);
-
- base = container_of(timer, struct alarm_queue, timer);
- now = base->stopped ? base->stopped_time : hrtimer_cb_get_time(timer);
- now = ktime_sub(now, base->delta);
-
- pr_alarm(INT, "alarm_timer_triggered type %ld at %lld\n",
- base - alarms, ktime_to_ns(now));
-
- while (base->first) {
- alarm = container_of(base->first, struct android_alarm, node);
- if (alarm->softexpires.tv64 > now.tv64) {
- pr_alarm(FLOW, "don't call alarm, %pF, %lld (s %lld)\n",
- alarm->function, ktime_to_ns(alarm->expires),
- ktime_to_ns(alarm->softexpires));
- break;
- }
- base->first = rb_next(&alarm->node);
- rb_erase(&alarm->node, &base->alarms);
- RB_CLEAR_NODE(&alarm->node);
- pr_alarm(CALL, "call alarm, type %d, func %pF, %lld (s %lld)\n",
- alarm->type, alarm->function,
- ktime_to_ns(alarm->expires),
- ktime_to_ns(alarm->softexpires));
- spin_unlock_irqrestore(&alarm_slock, flags);
- alarm->function(alarm);
- spin_lock_irqsave(&alarm_slock, flags);
- }
- if (!base->first)
- pr_alarm(FLOW, "no more alarms of type %ld\n", base - alarms);
- update_timer_locked(base, true);
- spin_unlock_irqrestore(&alarm_slock, flags);
- return HRTIMER_NORESTART;
-}
-
-static void alarm_triggered_func(void *p)
-{
- struct rtc_device *rtc = alarm_rtc_dev;
- if (!(rtc->irq_data & RTC_AF))
- return;
- pr_alarm(INT, "rtc alarm triggered\n");
- wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ);
-}
-
-static int alarm_suspend(struct platform_device *pdev, pm_message_t state)
-{
- int err = 0;
- unsigned long flags;
- struct rtc_wkalrm rtc_alarm;
- struct rtc_time rtc_current_rtc_time;
- unsigned long rtc_current_time;
- unsigned long rtc_alarm_time;
- struct timespec rtc_delta;
- struct timespec wall_time;
- struct alarm_queue *wakeup_queue = NULL;
- struct alarm_queue *tmp_queue = NULL;
-
- pr_alarm(SUSPEND, "alarm_suspend(%p, %d)\n", pdev, state.event);
-
- spin_lock_irqsave(&alarm_slock, flags);
- suspended = true;
- spin_unlock_irqrestore(&alarm_slock, flags);
-
- hrtimer_cancel(&alarms[ANDROID_ALARM_RTC_WAKEUP].timer);
- hrtimer_cancel(&alarms[
- ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].timer);
-
- tmp_queue = &alarms[ANDROID_ALARM_RTC_WAKEUP];
- if (tmp_queue->first)
- wakeup_queue = tmp_queue;
- tmp_queue = &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP];
- if (tmp_queue->first && (!wakeup_queue ||
- hrtimer_get_expires(&tmp_queue->timer).tv64 <
- hrtimer_get_expires(&wakeup_queue->timer).tv64))
- wakeup_queue = tmp_queue;
- if (wakeup_queue) {
- rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time);
- getnstimeofday(&wall_time);
- rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time);
- set_normalized_timespec(&rtc_delta,
- wall_time.tv_sec - rtc_current_time,
- wall_time.tv_nsec);
-
- rtc_alarm_time = timespec_sub(ktime_to_timespec(
- hrtimer_get_expires(&wakeup_queue->timer)),
- rtc_delta).tv_sec;
-
- rtc_time_to_tm(rtc_alarm_time, &rtc_alarm.time);
- rtc_alarm.enabled = 1;
- rtc_set_alarm(alarm_rtc_dev, &rtc_alarm);
- rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time);
- rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time);
- pr_alarm(SUSPEND,
- "rtc alarm set at %ld, now %ld, rtc delta %ld.%09ld\n",
- rtc_alarm_time, rtc_current_time,
- rtc_delta.tv_sec, rtc_delta.tv_nsec);
- if (rtc_current_time + 1 >= rtc_alarm_time) {
- pr_alarm(SUSPEND, "alarm about to go off\n");
- memset(&rtc_alarm, 0, sizeof(rtc_alarm));
- rtc_alarm.enabled = 0;
- rtc_set_alarm(alarm_rtc_dev, &rtc_alarm);
-
- spin_lock_irqsave(&alarm_slock, flags);
- suspended = false;
- wake_lock_timeout(&alarm_rtc_wake_lock, 2 * HZ);
- update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP],
- false);
- update_timer_locked(&alarms[
- ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP], false);
- err = -EBUSY;
- spin_unlock_irqrestore(&alarm_slock, flags);
- }
- }
- return err;
-}
-
-static int alarm_resume(struct platform_device *pdev)
-{
- struct rtc_wkalrm alarm;
- unsigned long flags;
-
- pr_alarm(SUSPEND, "alarm_resume(%p)\n", pdev);
-
- memset(&alarm, 0, sizeof(alarm));
- alarm.enabled = 0;
- rtc_set_alarm(alarm_rtc_dev, &alarm);
-
- spin_lock_irqsave(&alarm_slock, flags);
- suspended = false;
- update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP], false);
- update_timer_locked(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP],
- false);
- spin_unlock_irqrestore(&alarm_slock, flags);
-
- return 0;
-}
-
-static struct rtc_task alarm_rtc_task = {
- .func = alarm_triggered_func
-};
-
-static int rtc_alarm_add_device(struct device *dev,
- struct class_interface *class_intf)
-{
- int err;
- struct rtc_device *rtc = to_rtc_device(dev);
-
- mutex_lock(&alarm_setrtc_mutex);
-
- if (alarm_rtc_dev) {
- err = -EBUSY;
- goto err1;
- }
-
- alarm_platform_dev =
- platform_device_register_simple("alarm", -1, NULL, 0);
- if (IS_ERR(alarm_platform_dev)) {
- err = PTR_ERR(alarm_platform_dev);
- goto err2;
- }
- err = rtc_irq_register(rtc, &alarm_rtc_task);
- if (err)
- goto err3;
- alarm_rtc_dev = rtc;
- pr_alarm(INIT_STATUS, "using rtc device, %s, for alarms", rtc->name);
- mutex_unlock(&alarm_setrtc_mutex);
-
- return 0;
-
-err3:
- platform_device_unregister(alarm_platform_dev);
-err2:
-err1:
- mutex_unlock(&alarm_setrtc_mutex);
- return err;
-}
-
-static void rtc_alarm_remove_device(struct device *dev,
- struct class_interface *class_intf)
-{
- if (dev == &alarm_rtc_dev->dev) {
- pr_alarm(INIT_STATUS, "lost rtc device for alarms");
- rtc_irq_unregister(alarm_rtc_dev, &alarm_rtc_task);
- platform_device_unregister(alarm_platform_dev);
- alarm_rtc_dev = NULL;
- }
-}
-
-static struct class_interface rtc_alarm_interface = {
- .add_dev = &rtc_alarm_add_device,
- .remove_dev = &rtc_alarm_remove_device,
-};
-
-static struct platform_driver alarm_driver = {
- .suspend = alarm_suspend,
- .resume = alarm_resume,
- .driver = {
- .name = "alarm"
- }
-};
-
-static int __init alarm_late_init(void)
-{
- unsigned long flags;
- struct timespec tmp_time, system_time;
-
- /* this needs to run after the rtc is read at boot */
- spin_lock_irqsave(&alarm_slock, flags);
- /* We read the current rtc and system time so we can later calulate
- * elasped realtime to be (boot_systemtime + rtc - boot_rtc) ==
- * (rtc - (boot_rtc - boot_systemtime))
- */
- getnstimeofday(&tmp_time);
- ktime_get_ts(&system_time);
- alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta =
- alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta =
- timespec_to_ktime(timespec_sub(tmp_time, system_time));
-
- spin_unlock_irqrestore(&alarm_slock, flags);
- return 0;
-}
-
-static int __init alarm_driver_init(void)
-{
- int err;
- int i;
-
- for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
- hrtimer_init(&alarms[i].timer,
- CLOCK_REALTIME, HRTIMER_MODE_ABS);
- alarms[i].timer.function = alarm_timer_triggered;
- }
- hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].timer,
- CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
- alarms[ANDROID_ALARM_SYSTEMTIME].timer.function = alarm_timer_triggered;
- err = platform_driver_register(&alarm_driver);
- if (err < 0)
- goto err1;
- wake_lock_init(&alarm_rtc_wake_lock, WAKE_LOCK_SUSPEND, "alarm_rtc");
- rtc_alarm_interface.class = rtc_class;
- err = class_interface_register(&rtc_alarm_interface);
- if (err < 0)
- goto err2;
-
- return 0;
-
-err2:
- wake_lock_destroy(&alarm_rtc_wake_lock);
- platform_driver_unregister(&alarm_driver);
-err1:
- return err;
-}
-
-static void __exit alarm_exit(void)
-{
- class_interface_unregister(&rtc_alarm_interface);
- wake_lock_destroy(&alarm_rtc_wake_lock);
- platform_driver_unregister(&alarm_driver);
-}
-
-late_initcall(alarm_late_init);
-module_init(alarm_driver_init);
-module_exit(alarm_exit);
-
diff --git a/drivers/staging/android/android_alarm.h b/drivers/staging/android/android_alarm.h
index 6eecbde2ef6f..d0cafd637199 100644
--- a/drivers/staging/android/android_alarm.h
+++ b/drivers/staging/android/android_alarm.h
@@ -33,65 +33,6 @@ enum android_alarm_type {
/* ANDROID_ALARM_TIME_CHANGE = 16 */
};
-#ifdef __KERNEL__
-
-#include <linux/ktime.h>
-#include <linux/rbtree.h>
-
-/*
- * The alarm interface is similar to the hrtimer interface but adds support
- * for wakeup from suspend. It also adds an elapsed realtime clock that can
- * be used for periodic timers that need to keep runing while the system is
- * suspended and not be disrupted when the wall time is set.
- */
-
-/**
- * struct alarm - the basic alarm structure
- * @node: red black tree node for time ordered insertion
- * @type: alarm type. rtc/elapsed-realtime/systemtime, wakeup/non-wakeup.
- * @softexpires: the absolute earliest expiry time of the alarm.
- * @expires: the absolute expiry time.
- * @function: alarm expiry callback function
- *
- * The alarm structure must be initialized by alarm_init()
- *
- */
-
-struct android_alarm {
- struct rb_node node;
- enum android_alarm_type type;
- ktime_t softexpires;
- ktime_t expires;
- void (*function)(struct android_alarm *);
-};
-
-void android_alarm_init(struct android_alarm *alarm,
- enum android_alarm_type type, void (*function)(struct android_alarm *));
-void android_alarm_start_range(struct android_alarm *alarm, ktime_t start,
- ktime_t end);
-int android_alarm_try_to_cancel(struct android_alarm *alarm);
-int android_alarm_cancel(struct android_alarm *alarm);
-ktime_t alarm_get_elapsed_realtime(void);
-
-/* set rtc while preserving elapsed realtime */
-int android_alarm_set_rtc(const struct timespec ts);
-
-#ifdef CONFIG_ANDROID_ALARM_OLDDRV_COMPAT
-/*
- * Some older drivers depend on the old API,
- * so provide compatability macros for now.
- */
-#define alarm android_alarm
-#define alarm_init(x, y, z) android_alarm_init(x, y, z)
-#define alarm_start_range(x, y, z) android_alarm_start_range(x, y, z)
-#define alarm_try_to_cancel(x) android_alarm_try_to_cancel(x)
-#define alarm_cancel(x) android_alarm_cancel(x)
-#define alarm_set_rtc(x) android_alarm_set_rtc(x)
-#endif
-
-
-#endif
-
enum android_alarm_return_flags {
ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP,
ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC,
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
index 9f1f27e7c86e..4511420849bc 100644
--- a/drivers/staging/android/ashmem.c
+++ b/drivers/staging/android/ashmem.c
@@ -269,7 +269,7 @@ out:
return ret;
}
-static inline unsigned long calc_vm_may_flags(unsigned long prot)
+static inline vm_flags_t calc_vm_may_flags(unsigned long prot)
{
return _calc_vm_trans(prot, PROT_READ, VM_MAYREAD) |
_calc_vm_trans(prot, PROT_WRITE, VM_MAYWRITE) |
diff --git a/drivers/staging/android/binder.h b/drivers/staging/android/binder.h
index 25ab6f2759e9..2f7d195d8b15 100644
--- a/drivers/staging/android/binder.h
+++ b/drivers/staging/android/binder.h
@@ -53,17 +53,17 @@ struct flat_binder_object {
/* 8 bytes of data. */
union {
- void *binder; /* local object */
+ void __user *binder; /* local object */
signed long handle; /* remote object */
};
/* extra data associated with local object */
- void *cookie;
+ void __user *cookie;
};
/*
* On 64-bit platforms where user code may run in 32-bits the driver must
- * translate the buffer (and local binder) addresses apropriately.
+ * translate the buffer (and local binder) addresses appropriately.
*/
struct binder_write_read {
@@ -139,9 +139,9 @@ struct binder_transaction_data {
union {
struct {
/* transaction data */
- const void *buffer;
+ const void __user *buffer;
/* offsets from buffer to flat_binder_object structs */
- const void *offsets;
+ const void __user *offsets;
} ptr;
uint8_t buf[8];
} data;
diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c
index ea69b6a77dac..b2e71c6fd175 100644
--- a/drivers/staging/android/logger.c
+++ b/drivers/staging/android/logger.c
@@ -25,6 +25,7 @@
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/time.h>
+#include <linux/vmalloc.h>
#include "logger.h"
#include <asm/ioctls.h>
@@ -45,8 +46,12 @@ struct logger_log {
size_t w_off; /* current write head offset */
size_t head; /* new readers start here */
size_t size; /* size of the log */
+ struct list_head logs; /* list of log channels (myself)*/
};
+static LIST_HEAD(log_list);
+
+
/*
* struct logger_reader - a logging device open for reading
*
@@ -60,9 +65,9 @@ struct logger_reader {
};
/* logger_offset - returns index 'n' into the log via (optimized) modulus */
-size_t logger_offset(struct logger_log *log, size_t n)
+static size_t logger_offset(struct logger_log *log, size_t n)
{
- return n & (log->size-1);
+ return n & (log->size - 1);
}
@@ -348,7 +353,7 @@ static ssize_t do_write_log_from_user(struct logger_log *log,
* writev(), and aio_write(). Writes are our fast path, and we try to optimize
* them above all else.
*/
-ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
+static ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t ppos)
{
struct logger_log *log = file_get_log(iocb->ki_filp);
@@ -408,7 +413,15 @@ ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
return ret;
}
-static struct logger_log *get_log_from_minor(int);
+static struct logger_log *get_log_from_minor(int minor)
+{
+ struct logger_log *log;
+
+ list_for_each_entry(log, &log_list, logs)
+ if (log->misc.minor == minor)
+ return log;
+ return NULL;
+}
/*
* logger_open - the log's open() file operation
@@ -565,80 +578,84 @@ static const struct file_operations logger_fops = {
};
/*
- * Defines a log structure with name 'NAME' and a size of 'SIZE' bytes, which
- * must be a power of two, greater than LOGGER_ENTRY_MAX_LEN, and less than
- * LONG_MAX minus LOGGER_ENTRY_MAX_LEN.
+ * Log size must be a power of two, greater than LOGGER_ENTRY_MAX_LEN,
+ * and less than LONG_MAX minus LOGGER_ENTRY_MAX_LEN.
*/
-#define DEFINE_LOGGER_DEVICE(VAR, NAME, SIZE) \
-static unsigned char _buf_ ## VAR[SIZE]; \
-static struct logger_log VAR = { \
- .buffer = _buf_ ## VAR, \
- .misc = { \
- .minor = MISC_DYNAMIC_MINOR, \
- .name = NAME, \
- .fops = &logger_fops, \
- .parent = NULL, \
- }, \
- .wq = __WAIT_QUEUE_HEAD_INITIALIZER(VAR .wq), \
- .readers = LIST_HEAD_INIT(VAR .readers), \
- .mutex = __MUTEX_INITIALIZER(VAR .mutex), \
- .w_off = 0, \
- .head = 0, \
- .size = SIZE, \
-};
+static int __init create_log(char *log_name, int size)
+{
+ int ret = 0;
+ struct logger_log *log;
+ unsigned char *buffer;
-DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 256*1024)
-DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 256*1024)
-DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 256*1024)
-DEFINE_LOGGER_DEVICE(log_system, LOGGER_LOG_SYSTEM, 256*1024)
+ buffer = vmalloc(size);
+ if (buffer == NULL)
+ return -ENOMEM;
-static struct logger_log *get_log_from_minor(int minor)
-{
- if (log_main.misc.minor == minor)
- return &log_main;
- if (log_events.misc.minor == minor)
- return &log_events;
- if (log_radio.misc.minor == minor)
- return &log_radio;
- if (log_system.misc.minor == minor)
- return &log_system;
- return NULL;
-}
+ log = kzalloc(sizeof(struct logger_log), GFP_KERNEL);
+ if (log == NULL) {
+ ret = -ENOMEM;
+ goto out_free_buffer;
+ }
+ log->buffer = buffer;
-static int __init init_log(struct logger_log *log)
-{
- int ret;
+ log->misc.minor = MISC_DYNAMIC_MINOR;
+ log->misc.name = kstrdup(log_name, GFP_KERNEL);
+ if (log->misc.name == NULL) {
+ ret = -ENOMEM;
+ goto out_free_log;
+ }
+
+ log->misc.fops = &logger_fops;
+ log->misc.parent = NULL;
+ init_waitqueue_head(&log->wq);
+ INIT_LIST_HEAD(&log->readers);
+ mutex_init(&log->mutex);
+ log->w_off = 0;
+ log->head = 0;
+ log->size = size;
+
+ INIT_LIST_HEAD(&log->logs);
+ list_add_tail(&log->logs, &log_list);
+
+ /* finally, initialize the misc device for this log */
ret = misc_register(&log->misc);
if (unlikely(ret)) {
printk(KERN_ERR "logger: failed to register misc "
"device for log '%s'!\n", log->misc.name);
- return ret;
+ goto out_free_log;
}
printk(KERN_INFO "logger: created %luK log '%s'\n",
(unsigned long) log->size >> 10, log->misc.name);
return 0;
+
+out_free_log:
+ kfree(log);
+
+out_free_buffer:
+ vfree(buffer);
+ return ret;
}
static int __init logger_init(void)
{
int ret;
- ret = init_log(&log_main);
+ ret = create_log(LOGGER_LOG_MAIN, 256*1024);
if (unlikely(ret))
goto out;
- ret = init_log(&log_events);
+ ret = create_log(LOGGER_LOG_EVENTS, 256*1024);
if (unlikely(ret))
goto out;
- ret = init_log(&log_radio);
+ ret = create_log(LOGGER_LOG_RADIO, 256*1024);
if (unlikely(ret))
goto out;
- ret = init_log(&log_system);
+ ret = create_log(LOGGER_LOG_SYSTEM, 256*1024);
if (unlikely(ret))
goto out;
diff --git a/drivers/staging/android/ram_console.c b/drivers/staging/android/ram_console.c
index ce140ffc54ea..82323bb1d1a3 100644
--- a/drivers/staging/android/ram_console.c
+++ b/drivers/staging/android/ram_console.c
@@ -21,7 +21,7 @@
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/io.h>
-#include "persistent_ram.h"
+#include <linux/pstore_ram.h>
#include "ram_console.h"
static struct persistent_ram_zone *ram_console_zone;
diff --git a/drivers/staging/android/switch/Kconfig b/drivers/staging/android/switch/Kconfig
deleted file mode 100644
index 36846f62f4bc..000000000000
--- a/drivers/staging/android/switch/Kconfig
+++ /dev/null
@@ -1,11 +0,0 @@
-menuconfig ANDROID_SWITCH
- tristate "Android Switch class support"
- help
- Say Y here to enable Android switch class support. This allows
- monitoring switches by userspace via sysfs and uevent.
-
-config ANDROID_SWITCH_GPIO
- tristate "Android GPIO Switch support"
- depends on GENERIC_GPIO && ANDROID_SWITCH
- help
- Say Y here to enable GPIO based switch support.
diff --git a/drivers/staging/android/switch/Makefile b/drivers/staging/android/switch/Makefile
deleted file mode 100644
index d76bfdcedfaf..000000000000
--- a/drivers/staging/android/switch/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-# Android Switch Class Driver
-obj-$(CONFIG_ANDROID_SWITCH) += switch_class.o
-obj-$(CONFIG_ANDROID_SWITCH_GPIO) += switch_gpio.o
-
diff --git a/drivers/staging/android/switch/switch.h b/drivers/staging/android/switch/switch.h
deleted file mode 100644
index 4fcb3109875a..000000000000
--- a/drivers/staging/android/switch/switch.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Switch class driver
- *
- * Copyright (C) 2008 Google, Inc.
- * Author: Mike Lockwood <lockwood@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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 __LINUX_SWITCH_H__
-#define __LINUX_SWITCH_H__
-
-struct switch_dev {
- const char *name;
- struct device *dev;
- int index;
- int state;
-
- ssize_t (*print_name)(struct switch_dev *sdev, char *buf);
- ssize_t (*print_state)(struct switch_dev *sdev, char *buf);
-};
-
-struct gpio_switch_platform_data {
- const char *name;
- unsigned gpio;
-
- /* if NULL, switch_dev.name will be printed */
- const char *name_on;
- const char *name_off;
- /* if NULL, "0" or "1" will be printed */
- const char *state_on;
- const char *state_off;
-};
-
-extern int switch_dev_register(struct switch_dev *sdev);
-extern void switch_dev_unregister(struct switch_dev *sdev);
-
-static inline int switch_get_state(struct switch_dev *sdev)
-{
- return sdev->state;
-}
-
-extern void switch_set_state(struct switch_dev *sdev, int state);
-
-#endif /* __LINUX_SWITCH_H__ */
diff --git a/drivers/staging/android/switch/switch_class.c b/drivers/staging/android/switch/switch_class.c
deleted file mode 100644
index 74680446fc66..000000000000
--- a/drivers/staging/android/switch/switch_class.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * switch_class.c
- *
- * Copyright (C) 2008 Google, Inc.
- * Author: Mike Lockwood <lockwood@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
-*/
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/err.h>
-#include "switch.h"
-
-struct class *switch_class;
-static atomic_t device_count;
-
-static ssize_t state_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct switch_dev *sdev = (struct switch_dev *)
- dev_get_drvdata(dev);
-
- if (sdev->print_state) {
- int ret = sdev->print_state(sdev, buf);
- if (ret >= 0)
- return ret;
- }
- return sprintf(buf, "%d\n", sdev->state);
-}
-
-static ssize_t name_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct switch_dev *sdev = (struct switch_dev *)
- dev_get_drvdata(dev);
-
- if (sdev->print_name) {
- int ret = sdev->print_name(sdev, buf);
- if (ret >= 0)
- return ret;
- }
- return sprintf(buf, "%s\n", sdev->name);
-}
-
-static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, state_show, NULL);
-static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, name_show, NULL);
-
-void switch_set_state(struct switch_dev *sdev, int state)
-{
- char name_buf[120];
- char state_buf[120];
- char *prop_buf;
- char *envp[3];
- int env_offset = 0;
- int length;
-
- if (sdev->state != state) {
- sdev->state = state;
-
- prop_buf = (char *)get_zeroed_page(GFP_KERNEL);
- if (prop_buf) {
- length = name_show(sdev->dev, NULL, prop_buf);
- if (length > 0) {
- if (prop_buf[length - 1] == '\n')
- prop_buf[length - 1] = 0;
- snprintf(name_buf, sizeof(name_buf),
- "SWITCH_NAME=%s", prop_buf);
- envp[env_offset++] = name_buf;
- }
- length = state_show(sdev->dev, NULL, prop_buf);
- if (length > 0) {
- if (prop_buf[length - 1] == '\n')
- prop_buf[length - 1] = 0;
- snprintf(state_buf, sizeof(state_buf),
- "SWITCH_STATE=%s", prop_buf);
- envp[env_offset++] = state_buf;
- }
- envp[env_offset] = NULL;
- kobject_uevent_env(&sdev->dev->kobj, KOBJ_CHANGE, envp);
- free_page((unsigned long)prop_buf);
- } else {
- printk(KERN_ERR "out of memory in switch_set_state\n");
- kobject_uevent(&sdev->dev->kobj, KOBJ_CHANGE);
- }
- }
-}
-EXPORT_SYMBOL_GPL(switch_set_state);
-
-static int create_switch_class(void)
-{
- if (!switch_class) {
- switch_class = class_create(THIS_MODULE, "switch");
- if (IS_ERR(switch_class))
- return PTR_ERR(switch_class);
- atomic_set(&device_count, 0);
- }
-
- return 0;
-}
-
-int switch_dev_register(struct switch_dev *sdev)
-{
- int ret;
-
- if (!switch_class) {
- ret = create_switch_class();
- if (ret < 0)
- return ret;
- }
-
- sdev->index = atomic_inc_return(&device_count);
- sdev->dev = device_create(switch_class, NULL,
- MKDEV(0, sdev->index), NULL, sdev->name);
- if (IS_ERR(sdev->dev))
- return PTR_ERR(sdev->dev);
-
- ret = device_create_file(sdev->dev, &dev_attr_state);
- if (ret < 0)
- goto err_create_file_1;
- ret = device_create_file(sdev->dev, &dev_attr_name);
- if (ret < 0)
- goto err_create_file_2;
-
- dev_set_drvdata(sdev->dev, sdev);
- sdev->state = 0;
- return 0;
-
-err_create_file_2:
- device_remove_file(sdev->dev, &dev_attr_state);
-err_create_file_1:
- device_destroy(switch_class, MKDEV(0, sdev->index));
- printk(KERN_ERR "switch: Failed to register driver %s\n", sdev->name);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(switch_dev_register);
-
-void switch_dev_unregister(struct switch_dev *sdev)
-{
- device_remove_file(sdev->dev, &dev_attr_name);
- device_remove_file(sdev->dev, &dev_attr_state);
- device_destroy(switch_class, MKDEV(0, sdev->index));
- dev_set_drvdata(sdev->dev, NULL);
-}
-EXPORT_SYMBOL_GPL(switch_dev_unregister);
-
-static int __init switch_class_init(void)
-{
- return create_switch_class();
-}
-
-static void __exit switch_class_exit(void)
-{
- class_destroy(switch_class);
-}
-
-module_init(switch_class_init);
-module_exit(switch_class_exit);
-
-MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
-MODULE_DESCRIPTION("Switch class driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/android/switch/switch_gpio.c b/drivers/staging/android/switch/switch_gpio.c
deleted file mode 100644
index 38b2c2f6004e..000000000000
--- a/drivers/staging/android/switch/switch_gpio.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * switch_gpio.c
- *
- * Copyright (C) 2008 Google, Inc.
- * Author: Mike Lockwood <lockwood@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
-*/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/workqueue.h>
-#include <linux/gpio.h>
-#include "switch.h"
-
-struct gpio_switch_data {
- struct switch_dev sdev;
- unsigned gpio;
- const char *name_on;
- const char *name_off;
- const char *state_on;
- const char *state_off;
- int irq;
- struct work_struct work;
-};
-
-static void gpio_switch_work(struct work_struct *work)
-{
- int state;
- struct gpio_switch_data *data =
- container_of(work, struct gpio_switch_data, work);
-
- state = gpio_get_value(data->gpio);
- switch_set_state(&data->sdev, state);
-}
-
-static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
-{
- struct gpio_switch_data *switch_data =
- (struct gpio_switch_data *)dev_id;
-
- schedule_work(&switch_data->work);
- return IRQ_HANDLED;
-}
-
-static ssize_t switch_gpio_print_state(struct switch_dev *sdev, char *buf)
-{
- struct gpio_switch_data *switch_data =
- container_of(sdev, struct gpio_switch_data, sdev);
- const char *state;
- if (switch_get_state(sdev))
- state = switch_data->state_on;
- else
- state = switch_data->state_off;
-
- if (state)
- return sprintf(buf, "%s\n", state);
- return -1;
-}
-
-static int gpio_switch_probe(struct platform_device *pdev)
-{
- struct gpio_switch_platform_data *pdata = pdev->dev.platform_data;
- struct gpio_switch_data *switch_data;
- int ret = 0;
-
- if (!pdata)
- return -EBUSY;
-
- switch_data = kzalloc(sizeof(struct gpio_switch_data), GFP_KERNEL);
- if (!switch_data)
- return -ENOMEM;
-
- switch_data->sdev.name = pdata->name;
- switch_data->gpio = pdata->gpio;
- switch_data->name_on = pdata->name_on;
- switch_data->name_off = pdata->name_off;
- switch_data->state_on = pdata->state_on;
- switch_data->state_off = pdata->state_off;
- switch_data->sdev.print_state = switch_gpio_print_state;
-
- ret = switch_dev_register(&switch_data->sdev);
- if (ret < 0)
- goto err_switch_dev_register;
-
- ret = gpio_request(switch_data->gpio, pdev->name);
- if (ret < 0)
- goto err_request_gpio;
-
- ret = gpio_direction_input(switch_data->gpio);
- if (ret < 0)
- goto err_set_gpio_input;
-
- INIT_WORK(&switch_data->work, gpio_switch_work);
-
- switch_data->irq = gpio_to_irq(switch_data->gpio);
- if (switch_data->irq < 0) {
- ret = switch_data->irq;
- goto err_detect_irq_num_failed;
- }
-
- ret = request_irq(switch_data->irq, gpio_irq_handler,
- IRQF_TRIGGER_LOW, pdev->name, switch_data);
- if (ret < 0)
- goto err_request_irq;
-
- /* Perform initial detection */
- gpio_switch_work(&switch_data->work);
-
- return 0;
-
-err_request_irq:
-err_detect_irq_num_failed:
-err_set_gpio_input:
- gpio_free(switch_data->gpio);
-err_request_gpio:
- switch_dev_unregister(&switch_data->sdev);
-err_switch_dev_register:
- kfree(switch_data);
-
- return ret;
-}
-
-static int __devexit gpio_switch_remove(struct platform_device *pdev)
-{
- struct gpio_switch_data *switch_data = platform_get_drvdata(pdev);
-
- cancel_work_sync(&switch_data->work);
- gpio_free(switch_data->gpio);
- switch_dev_unregister(&switch_data->sdev);
- kfree(switch_data);
-
- return 0;
-}
-
-static struct platform_driver gpio_switch_driver = {
- .probe = gpio_switch_probe,
- .remove = __devexit_p(gpio_switch_remove),
- .driver = {
- .name = "switch-gpio",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init gpio_switch_init(void)
-{
- return platform_driver_register(&gpio_switch_driver);
-}
-
-static void __exit gpio_switch_exit(void)
-{
- platform_driver_unregister(&gpio_switch_driver);
-}
-
-module_init(gpio_switch_init);
-module_exit(gpio_switch_exit);
-
-MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
-MODULE_DESCRIPTION("GPIO Switch driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/android/timed_output.c b/drivers/staging/android/timed_output.c
index f373422308e0..38d930cadad3 100644
--- a/drivers/staging/android/timed_output.c
+++ b/drivers/staging/android/timed_output.c
@@ -99,6 +99,7 @@ EXPORT_SYMBOL_GPL(timed_output_dev_register);
void timed_output_dev_unregister(struct timed_output_dev *tdev)
{
+ tdev->enable(tdev, 0);
device_remove_file(tdev->dev, &dev_attr_enable);
device_destroy(timed_output_class, MKDEV(0, tdev->index));
dev_set_drvdata(tdev->dev, NULL);
diff --git a/drivers/staging/asus_oled/asus_oled.c b/drivers/staging/asus_oled/asus_oled.c
index 83549d9cfefc..510d79639217 100644
--- a/drivers/staging/asus_oled/asus_oled.c
+++ b/drivers/staging/asus_oled/asus_oled.c
@@ -782,20 +782,20 @@ static int __init asus_oled_init(void)
oled_class = class_create(THIS_MODULE, ASUS_OLED_UNDERSCORE_NAME);
if (IS_ERR(oled_class)) {
- err("Error creating " ASUS_OLED_UNDERSCORE_NAME " class");
+ printk(KERN_ERR "Error creating " ASUS_OLED_UNDERSCORE_NAME " class\n");
return PTR_ERR(oled_class);
}
retval = class_create_file(oled_class, &class_attr_version.attr);
if (retval) {
- err("Error creating class version file");
+ printk(KERN_ERR "Error creating class version file\n");
goto error;
}
retval = usb_register(&oled_driver);
if (retval) {
- err("usb_register failed. Error number %d", retval);
+ printk(KERN_ERR "usb_register failed. Error number %d\n", retval);
goto error;
}
diff --git a/drivers/staging/bcm/Adapter.h b/drivers/staging/bcm/Adapter.h
index 20cca24ff5f0..aa51d17be5a1 100644
--- a/drivers/staging/bcm/Adapter.h
+++ b/drivers/staging/bcm/Adapter.h
@@ -7,168 +7,145 @@
#define MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES 256
#include "Debug.h"
-struct _LEADER
-{
- USHORT Vcid;
- USHORT PLength;
- UCHAR Status;
+struct _LEADER {
+ USHORT Vcid;
+ USHORT PLength;
+ UCHAR Status;
UCHAR Unused[3];
-}__attribute__((packed));
-typedef struct _LEADER LEADER,*PLEADER;
+} __packed;
+typedef struct _LEADER LEADER, *PLEADER;
-struct _PACKETTOSEND
-{
+struct _PACKETTOSEND {
LEADER Leader;
UCHAR ucPayload;
-}__attribute__((packed));
+} __packed;
typedef struct _PACKETTOSEND PACKETTOSEND, *PPACKETTOSEND;
-
-struct _CONTROL_PACKET
-{
+struct _CONTROL_PACKET {
PVOID ControlBuff;
UINT ControlBuffLen;
- struct _CONTROL_PACKET* next;
-}__attribute__((packed));
-typedef struct _CONTROL_PACKET CONTROL_PACKET,*PCONTROL_PACKET;
-
+ struct _CONTROL_PACKET *next;
+} __packed;
+typedef struct _CONTROL_PACKET CONTROL_PACKET, *PCONTROL_PACKET;
-struct link_request
-{
+struct link_request {
LEADER Leader;
UCHAR szData[4];
-}__attribute__((packed));
+} __packed;
typedef struct link_request LINK_REQUEST, *PLINK_REQUEST;
-
-//classification extension is added
-typedef struct _ADD_CONNECTION
-{
- ULONG SrcIpAddressCount;
- ULONG SrcIpAddress[MAX_CONNECTIONS];
- ULONG SrcIpMask[MAX_CONNECTIONS];
-
- ULONG DestIpAddressCount;
- ULONG DestIpAddress[MAX_CONNECTIONS];
- ULONG DestIpMask[MAX_CONNECTIONS];
-
- USHORT SrcPortBegin;
- USHORT SrcPortEnd;
-
- USHORT DestPortBegin;
- USHORT DestPortEnd;
-
- UCHAR SrcTOS;
- UCHAR SrcProtocol;
-} ADD_CONNECTION,*PADD_CONNECTION;
-
-
-typedef struct _CLASSIFICATION_RULE
-{
- UCHAR ucIPSrcAddrLen;
- UCHAR ucIPSrcAddr[32];
- UCHAR ucIPDestAddrLen;
- UCHAR ucIPDestAddr[32];
- UCHAR ucSrcPortRangeLen;
- UCHAR ucSrcPortRange[4];
- UCHAR ucDestPortRangeLen;
- UCHAR ucDestPortRange[4];
- USHORT usVcid;
-} CLASSIFICATION_RULE,*PCLASSIFICATION_RULE;
-
-typedef struct _CLASSIFICATION_ONLY
-{
- USHORT usVcid;
- ULONG DestIpAddress;
- ULONG DestIpMask;
- USHORT usPortLo;
- USHORT usPortHi;
- BOOLEAN bIpVersion;
- UCHAR ucDestinationAddress[16];
+/* classification extension is added */
+typedef struct _ADD_CONNECTION {
+ ULONG SrcIpAddressCount;
+ ULONG SrcIpAddress[MAX_CONNECTIONS];
+ ULONG SrcIpMask[MAX_CONNECTIONS];
+
+ ULONG DestIpAddressCount;
+ ULONG DestIpAddress[MAX_CONNECTIONS];
+ ULONG DestIpMask[MAX_CONNECTIONS];
+
+ USHORT SrcPortBegin;
+ USHORT SrcPortEnd;
+
+ USHORT DestPortBegin;
+ USHORT DestPortEnd;
+
+ UCHAR SrcTOS;
+ UCHAR SrcProtocol;
+} ADD_CONNECTION, *PADD_CONNECTION;
+
+typedef struct _CLASSIFICATION_RULE {
+ UCHAR ucIPSrcAddrLen;
+ UCHAR ucIPSrcAddr[32];
+ UCHAR ucIPDestAddrLen;
+ UCHAR ucIPDestAddr[32];
+ UCHAR ucSrcPortRangeLen;
+ UCHAR ucSrcPortRange[4];
+ UCHAR ucDestPortRangeLen;
+ UCHAR ucDestPortRange[4];
+ USHORT usVcid;
+} CLASSIFICATION_RULE, *PCLASSIFICATION_RULE;
+
+typedef struct _CLASSIFICATION_ONLY {
+ USHORT usVcid;
+ ULONG DestIpAddress;
+ ULONG DestIpMask;
+ USHORT usPortLo;
+ USHORT usPortHi;
+ BOOLEAN bIpVersion;
+ UCHAR ucDestinationAddress[16];
} CLASSIFICATION_ONLY, *PCLASSIFICATION_ONLY;
-
#define MAX_IP_RANGE_LENGTH 4
#define MAX_PORT_RANGE 4
#define MAX_PROTOCOL_LENGTH 32
#define IPV6_ADDRESS_SIZEINBYTES 0x10
-typedef union _U_IP_ADDRESS
-{
- struct
- {
- ULONG ulIpv4Addr[MAX_IP_RANGE_LENGTH];//Source Ip Address Range
- ULONG ulIpv4Mask[MAX_IP_RANGE_LENGTH];//Source Ip Mask Address Range
+typedef union _U_IP_ADDRESS {
+ struct {
+ ULONG ulIpv4Addr[MAX_IP_RANGE_LENGTH]; /* Source Ip Address Range */
+ ULONG ulIpv4Mask[MAX_IP_RANGE_LENGTH]; /* Source Ip Mask Address Range */
};
- struct
- {
- ULONG ulIpv6Addr[MAX_IP_RANGE_LENGTH * 4];//Source Ip Address Range
- ULONG ulIpv6Mask[MAX_IP_RANGE_LENGTH * 4];//Source Ip Mask Address Range
-
+ struct {
+ ULONG ulIpv6Addr[MAX_IP_RANGE_LENGTH * 4]; /* Source Ip Address Range */
+ ULONG ulIpv6Mask[MAX_IP_RANGE_LENGTH * 4]; /* Source Ip Mask Address Range */
};
- struct
- {
- UCHAR ucIpv4Address[MAX_IP_RANGE_LENGTH * IP_LENGTH_OF_ADDRESS];
- UCHAR ucIpv4Mask[MAX_IP_RANGE_LENGTH * IP_LENGTH_OF_ADDRESS];
+ struct {
+ UCHAR ucIpv4Address[MAX_IP_RANGE_LENGTH * IP_LENGTH_OF_ADDRESS];
+ UCHAR ucIpv4Mask[MAX_IP_RANGE_LENGTH * IP_LENGTH_OF_ADDRESS];
};
- struct
- {
- UCHAR ucIpv6Address[MAX_IP_RANGE_LENGTH * IPV6_ADDRESS_SIZEINBYTES];
- UCHAR ucIpv6Mask[MAX_IP_RANGE_LENGTH * IPV6_ADDRESS_SIZEINBYTES];
+ struct {
+ UCHAR ucIpv6Address[MAX_IP_RANGE_LENGTH * IPV6_ADDRESS_SIZEINBYTES];
+ UCHAR ucIpv6Mask[MAX_IP_RANGE_LENGTH * IPV6_ADDRESS_SIZEINBYTES];
};
-}U_IP_ADDRESS;
+} U_IP_ADDRESS;
struct _packet_info;
-typedef struct _S_HDR_SUPRESSION_CONTEXTINFO
-{
+typedef struct _S_HDR_SUPRESSION_CONTEXTINFO {
+ UCHAR ucaHdrSupressionInBuf[MAX_PHS_LENGTHS]; /* Intermediate buffer to accumulate pkt Header for PHS */
+ UCHAR ucaHdrSupressionOutBuf[MAX_PHS_LENGTHS + PHSI_LEN]; /* Intermediate buffer containing pkt Header after PHS */
+} S_HDR_SUPRESSION_CONTEXTINFO;
+
+typedef struct _S_CLASSIFIER_RULE {
+ ULONG ulSFID;
+ UCHAR ucReserved[2];
+ B_UINT16 uiClassifierRuleIndex;
+ BOOLEAN bUsed;
+ USHORT usVCID_Value;
+ B_UINT8 u8ClassifierRulePriority; /* This field detemines the Classifier Priority */
+ U_IP_ADDRESS stSrcIpAddress;
+ UCHAR ucIPSourceAddressLength; /* Ip Source Address Length */
- UCHAR ucaHdrSupressionInBuf[MAX_PHS_LENGTHS]; //Intermediate buffer to accumulate pkt Header for PHS
- UCHAR ucaHdrSupressionOutBuf[MAX_PHS_LENGTHS + PHSI_LEN]; //Intermediate buffer containing pkt Header after PHS
+ U_IP_ADDRESS stDestIpAddress;
+ UCHAR ucIPDestinationAddressLength; /* Ip Destination Address Length */
+ UCHAR ucIPTypeOfServiceLength; /* Type of service Length */
+ UCHAR ucTosLow; /* Tos Low */
+ UCHAR ucTosHigh; /* Tos High */
+ UCHAR ucTosMask; /* Tos Mask */
-}S_HDR_SUPRESSION_CONTEXTINFO;
+ UCHAR ucProtocolLength; /* protocol Length */
+ UCHAR ucProtocol[MAX_PROTOCOL_LENGTH]; /* protocol Length */
+ USHORT usSrcPortRangeLo[MAX_PORT_RANGE];
+ USHORT usSrcPortRangeHi[MAX_PORT_RANGE];
+ UCHAR ucSrcPortRangeLength;
+ USHORT usDestPortRangeLo[MAX_PORT_RANGE];
+ USHORT usDestPortRangeHi[MAX_PORT_RANGE];
+ UCHAR ucDestPortRangeLength;
-typedef struct _S_CLASSIFIER_RULE
-{
- ULONG ulSFID;
- UCHAR ucReserved[2];
- B_UINT16 uiClassifierRuleIndex;
- BOOLEAN bUsed;
- USHORT usVCID_Value;
- B_UINT8 u8ClassifierRulePriority; //This field detemines the Classifier Priority
- U_IP_ADDRESS stSrcIpAddress;
- UCHAR ucIPSourceAddressLength;//Ip Source Address Length
-
- U_IP_ADDRESS stDestIpAddress;
- UCHAR ucIPDestinationAddressLength;//Ip Destination Address Length
- UCHAR ucIPTypeOfServiceLength;//Type of service Length
- UCHAR ucTosLow;//Tos Low
- UCHAR ucTosHigh;//Tos High
- UCHAR ucTosMask;//Tos Mask
-
- UCHAR ucProtocolLength;//protocol Length
- UCHAR ucProtocol[MAX_PROTOCOL_LENGTH];//protocol Length
- USHORT usSrcPortRangeLo[MAX_PORT_RANGE];
- USHORT usSrcPortRangeHi[MAX_PORT_RANGE];
- UCHAR ucSrcPortRangeLength;
-
- USHORT usDestPortRangeLo[MAX_PORT_RANGE];
- USHORT usDestPortRangeHi[MAX_PORT_RANGE];
- UCHAR ucDestPortRangeLength;
-
- BOOLEAN bProtocolValid;
- BOOLEAN bTOSValid;
- BOOLEAN bDestIpValid;
- BOOLEAN bSrcIpValid;
-
- //For IPv6 Addressing
- UCHAR ucDirection;
- BOOLEAN bIpv6Protocol;
- UINT32 u32PHSRuleID;
- S_PHS_RULE sPhsRule;
- UCHAR u8AssociatedPHSI;
-
- //Classification fields for ETH CS
+ BOOLEAN bProtocolValid;
+ BOOLEAN bTOSValid;
+ BOOLEAN bDestIpValid;
+ BOOLEAN bSrcIpValid;
+
+ /* For IPv6 Addressing */
+ UCHAR ucDirection;
+ BOOLEAN bIpv6Protocol;
+ UINT32 u32PHSRuleID;
+ S_PHS_RULE sPhsRule;
+ UCHAR u8AssociatedPHSI;
+
+ /* Classification fields for ETH CS */
UCHAR ucEthCSSrcMACLen;
UCHAR au8EThCSSrcMAC[MAC_ADDRESS_SIZE];
UCHAR au8EThCSSrcMACMask[MAC_ADDRESS_SIZE];
@@ -180,71 +157,67 @@ typedef struct _S_CLASSIFIER_RULE
UCHAR usUserPriority[2];
USHORT usVLANID;
USHORT usValidityBitMap;
-}S_CLASSIFIER_RULE;
-//typedef struct _S_CLASSIFIER_RULE S_CLASSIFIER_RULE;
-
-typedef struct _S_FRAGMENTED_PACKET_INFO
-{
- BOOLEAN bUsed;
- ULONG ulSrcIpAddress;
- USHORT usIpIdentification;
- S_CLASSIFIER_RULE *pstMatchedClassifierEntry;
- BOOLEAN bOutOfOrderFragment;
-}S_FRAGMENTED_PACKET_INFO,*PS_FRAGMENTED_PACKET_INFO;
-
-struct _packet_info
-{
- //classification extension Rule
- ULONG ulSFID;
- USHORT usVCID_Value;
- UINT uiThreshold;
- // This field determines the priority of the SF Queues
- B_UINT8 u8TrafficPriority;
-
- BOOLEAN bValid;
- BOOLEAN bActive;
- BOOLEAN bActivateRequestSent;
-
- B_UINT8 u8QueueType;//BE or rtPS
-
- UINT uiMaxBucketSize;//maximum size of the bucket for the queue
- UINT uiCurrentQueueDepthOnTarget;
- UINT uiCurrentBytesOnHost;
- UINT uiCurrentPacketsOnHost;
- UINT uiDroppedCountBytes;
- UINT uiDroppedCountPackets;
- UINT uiSentBytes;
- UINT uiSentPackets;
- UINT uiCurrentDrainRate;
- UINT uiThisPeriodSentBytes;
+} S_CLASSIFIER_RULE;
+/* typedef struct _S_CLASSIFIER_RULE S_CLASSIFIER_RULE; */
+
+typedef struct _S_FRAGMENTED_PACKET_INFO {
+ BOOLEAN bUsed;
+ ULONG ulSrcIpAddress;
+ USHORT usIpIdentification;
+ S_CLASSIFIER_RULE *pstMatchedClassifierEntry;
+ BOOLEAN bOutOfOrderFragment;
+} S_FRAGMENTED_PACKET_INFO, *PS_FRAGMENTED_PACKET_INFO;
+
+struct _packet_info {
+ /* classification extension Rule */
+ ULONG ulSFID;
+ USHORT usVCID_Value;
+ UINT uiThreshold;
+ /* This field determines the priority of the SF Queues */
+ B_UINT8 u8TrafficPriority;
+
+ BOOLEAN bValid;
+ BOOLEAN bActive;
+ BOOLEAN bActivateRequestSent;
+
+ B_UINT8 u8QueueType; /* BE or rtPS */
+
+ UINT uiMaxBucketSize; /* maximum size of the bucket for the queue */
+ UINT uiCurrentQueueDepthOnTarget;
+ UINT uiCurrentBytesOnHost;
+ UINT uiCurrentPacketsOnHost;
+ UINT uiDroppedCountBytes;
+ UINT uiDroppedCountPackets;
+ UINT uiSentBytes;
+ UINT uiSentPackets;
+ UINT uiCurrentDrainRate;
+ UINT uiThisPeriodSentBytes;
LARGE_INTEGER liDrainCalculated;
- UINT uiCurrentTokenCount;
- LARGE_INTEGER liLastUpdateTokenAt;
- UINT uiMaxAllowedRate;
- UINT NumOfPacketsSent;
- UCHAR ucDirection;
- USHORT usCID;
+ UINT uiCurrentTokenCount;
+ LARGE_INTEGER liLastUpdateTokenAt;
+ UINT uiMaxAllowedRate;
+ UINT NumOfPacketsSent;
+ UCHAR ucDirection;
+ USHORT usCID;
S_MIBS_EXTSERVICEFLOW_PARAMETERS stMibsExtServiceFlowTable;
- UINT uiCurrentRxRate;
- UINT uiThisPeriodRxBytes;
- UINT uiTotalRxBytes;
- UINT uiTotalTxBytes;
- UINT uiPendedLast;
- UCHAR ucIpVersion;
-
- union
- {
- struct
- {
- struct sk_buff* FirstTxQueue;
- struct sk_buff* LastTxQueue;
+ UINT uiCurrentRxRate;
+ UINT uiThisPeriodRxBytes;
+ UINT uiTotalRxBytes;
+ UINT uiTotalTxBytes;
+ UINT uiPendedLast;
+ UCHAR ucIpVersion;
+
+ union {
+ struct {
+ struct sk_buff *FirstTxQueue;
+ struct sk_buff *LastTxQueue;
};
- struct
- {
- struct sk_buff* ControlHead;
- struct sk_buff* ControlTail;
+ struct {
+ struct sk_buff *ControlHead;
+ struct sk_buff *ControlTail;
};
};
+
BOOLEAN bProtocolValid;
BOOLEAN bTOSValid;
BOOLEAN bDestIpValid;
@@ -255,226 +228,209 @@ struct _packet_info
BOOLEAN bAuthorizedSet;
BOOLEAN bClassifierPriority;
UCHAR ucServiceClassName[MAX_CLASS_NAME_LENGTH];
- BOOLEAN bHeaderSuppressionEnabled;
+ BOOLEAN bHeaderSuppressionEnabled;
spinlock_t SFQueueLock;
- void *pstSFIndication;
+ void *pstSFIndication;
struct timeval stLastUpdateTokenAt;
- atomic_t uiPerSFTxResourceCount;
+ atomic_t uiPerSFTxResourceCount;
UINT uiMaxLatency;
- UCHAR bIPCSSupport;
- UCHAR bEthCSSupport;
+ UCHAR bIPCSSupport;
+ UCHAR bEthCSSupport;
};
typedef struct _packet_info PacketInfo;
-
-typedef struct _PER_TARANG_DATA
-{
- struct _PER_TARANG_DATA * next;
- struct _MINI_ADAPTER * Adapter;
- struct sk_buff* RxAppControlHead;
- struct sk_buff* RxAppControlTail;
- volatile INT AppCtrlQueueLen;
- BOOLEAN MacTracingEnabled;
- BOOLEAN bApplicationToExit;
- S_MIBS_DROPPED_APP_CNTRL_MESSAGES stDroppedAppCntrlMsgs;
- ULONG RxCntrlMsgBitMask;
+typedef struct _PER_TARANG_DATA {
+ struct _PER_TARANG_DATA *next;
+ struct _MINI_ADAPTER *Adapter;
+ struct sk_buff *RxAppControlHead;
+ struct sk_buff *RxAppControlTail;
+ int AppCtrlQueueLen;
+ BOOLEAN MacTracingEnabled;
+ BOOLEAN bApplicationToExit;
+ S_MIBS_DROPPED_APP_CNTRL_MESSAGES stDroppedAppCntrlMsgs;
+ ULONG RxCntrlMsgBitMask;
} PER_TARANG_DATA, *PPER_TARANG_DATA;
-
#ifdef REL_4_1
-typedef struct _TARGET_PARAMS
-{
- B_UINT32 m_u32CfgVersion;
-
- // Scanning Related Params
- B_UINT32 m_u32CenterFrequency;
- B_UINT32 m_u32BandAScan;
- B_UINT32 m_u32BandBScan;
- B_UINT32 m_u32BandCScan;
-
- // QoS Params
- B_UINT32 m_u32minGrantsize; // size of minimum grant is 0 or 6
- B_UINT32 m_u32PHSEnable;
-
- // HO Params
- B_UINT32 m_u32HoEnable;
- B_UINT32 m_u32HoReserved1;
- B_UINT32 m_u32HoReserved2;
-
- // Power Control Params
- B_UINT32 m_u32MimoEnable;
- B_UINT32 m_u32SecurityEnable;
+typedef struct _TARGET_PARAMS {
+ B_UINT32 m_u32CfgVersion;
+
+ /* Scanning Related Params */
+ B_UINT32 m_u32CenterFrequency;
+ B_UINT32 m_u32BandAScan;
+ B_UINT32 m_u32BandBScan;
+ B_UINT32 m_u32BandCScan;
+
+ /* QoS Params */
+ B_UINT32 m_u32minGrantsize; /* size of minimum grant is 0 or 6 */
+ B_UINT32 m_u32PHSEnable;
+
+ /* HO Params */
+ B_UINT32 m_u32HoEnable;
+ B_UINT32 m_u32HoReserved1;
+ B_UINT32 m_u32HoReserved2;
+
+ /* Power Control Params */
+ B_UINT32 m_u32MimoEnable;
+ B_UINT32 m_u32SecurityEnable;
/*
- * bit 1: 1 Idlemode enable;
- * bit 2: 1 Sleepmode Enable
- */
- B_UINT32 m_u32PowerSavingModesEnable;
- /* PowerSaving Mode Options:
- bit 0 = 1: CPE mode - to keep pcmcia if alive;
- bit 1 = 1: CINR reporing in Idlemode Msg
- bit 2 = 1: Default PSC Enable in sleepmode*/
- B_UINT32 m_u32PowerSavingModeOptions;
-
- B_UINT32 m_u32ArqEnable;
-
- // From Version #3, the HARQ section renamed as general
- B_UINT32 m_u32HarqEnable;
- // EEPROM Param Location
- B_UINT32 m_u32EEPROMFlag;
- /* BINARY TYPE - 4th MSByte:
- * Interface Type - 3rd MSByte:
- * Vendor Type - 2nd MSByte
- */
- // Unused - LSByte
- B_UINT32 m_u32Customize;
- B_UINT32 m_u32ConfigBW; /* In Hz */
- B_UINT32 m_u32ShutDownTimer;
-
-
- B_UINT32 m_u32RadioParameter;
- B_UINT32 m_u32PhyParameter1;
- B_UINT32 m_u32PhyParameter2;
- B_UINT32 m_u32PhyParameter3;
+ * bit 1: 1 Idlemode enable;
+ * bit 2: 1 Sleepmode Enable
+ */
+ B_UINT32 m_u32PowerSavingModesEnable;
+ /* PowerSaving Mode Options:
+ * bit 0 = 1: CPE mode - to keep pcmcia if alive;
+ * bit 1 = 1: CINR reporing in Idlemode Msg
+ * bit 2 = 1: Default PSC Enable in sleepmode
+ */
+ B_UINT32 m_u32PowerSavingModeOptions;
+
+ B_UINT32 m_u32ArqEnable;
+
+ /* From Version #3, the HARQ section renamed as general */
+ B_UINT32 m_u32HarqEnable;
+ /* EEPROM Param Location */
+ B_UINT32 m_u32EEPROMFlag;
+ /* BINARY TYPE - 4th MSByte:
+ * Interface Type - 3rd MSByte:
+ * Vendor Type - 2nd MSByte
+ */
+ /* Unused - LSByte */
+ B_UINT32 m_u32Customize;
+ B_UINT32 m_u32ConfigBW; /* In Hz */
+ B_UINT32 m_u32ShutDownTimer;
+ B_UINT32 m_u32RadioParameter;
+ B_UINT32 m_u32PhyParameter1;
+ B_UINT32 m_u32PhyParameter2;
+ B_UINT32 m_u32PhyParameter3;
/* in eval mode only;
- * lower 16bits = basic cid for testing;
- * then bit 16 is test cqich,
- * bit 17 test init rang;
- * bit 18 test periodic rang
- * bit 19 is test harq ack/nack
- */
- B_UINT32 m_u32TestOptions;
-
+ * lower 16bits = basic cid for testing;
+ * then bit 16 is test cqich,
+ * bit 17 test init rang;
+ * bit 18 test periodic rang
+ * bit 19 is test harq ack/nack
+ */
+ B_UINT32 m_u32TestOptions;
B_UINT32 m_u32MaxMACDataperDLFrame;
B_UINT32 m_u32MaxMACDataperULFrame;
-
B_UINT32 m_u32Corr2MacFlags;
- //adding driver params.
- B_UINT32 HostDrvrConfig1;
- B_UINT32 HostDrvrConfig2;
- B_UINT32 HostDrvrConfig3;
- B_UINT32 HostDrvrConfig4;
- B_UINT32 HostDrvrConfig5;
- B_UINT32 HostDrvrConfig6;
- B_UINT32 m_u32SegmentedPUSCenable;
-
- // BAMC enable - but 4.x does not support this feature
- // This is added just to sync 4.x and 5.x CFGs
+ /* adding driver params. */
+ B_UINT32 HostDrvrConfig1;
+ B_UINT32 HostDrvrConfig2;
+ B_UINT32 HostDrvrConfig3;
+ B_UINT32 HostDrvrConfig4;
+ B_UINT32 HostDrvrConfig5;
+ B_UINT32 HostDrvrConfig6;
+ B_UINT32 m_u32SegmentedPUSCenable;
+
+ /* BAMC enable - but 4.x does not support this feature
+ * This is added just to sync 4.x and 5.x CFGs
+ */
B_UINT32 m_u32BandAMCEnable;
} STARGETPARAMS, *PSTARGETPARAMS;
#endif
-typedef struct _STTARGETDSXBUFFER
-{
- ULONG ulTargetDsxBuffer;
- B_UINT16 tid;
- BOOLEAN valid;
-}STTARGETDSXBUFFER, *PSTTARGETDSXBUFFER;
+typedef struct _STTARGETDSXBUFFER {
+ ULONG ulTargetDsxBuffer;
+ B_UINT16 tid;
+ BOOLEAN valid;
+} STTARGETDSXBUFFER, *PSTTARGETDSXBUFFER;
-typedef INT (*FP_FLASH_WRITE)(struct _MINI_ADAPTER*,UINT,PVOID);
+typedef int (*FP_FLASH_WRITE)(struct _MINI_ADAPTER *, UINT, PVOID);
-typedef INT (*FP_FLASH_WRITE_STATUS)(struct _MINI_ADAPTER*,UINT,PVOID);
+typedef int (*FP_FLASH_WRITE_STATUS)(struct _MINI_ADAPTER *, UINT, PVOID);
-/**
-Driver adapter data structure
-*/
-struct _MINI_ADAPTER
-{
- struct _MINI_ADAPTER *next;
+/*
+ * Driver adapter data structure
+ */
+struct _MINI_ADAPTER {
+ struct _MINI_ADAPTER *next;
struct net_device *dev;
u32 msg_enable;
-
- CHAR *caDsxReqResp;
+ CHAR *caDsxReqResp;
atomic_t ApplicationRunning;
- volatile INT CtrlQueueLen;
- atomic_t AppCtrlQueueLen;
- BOOLEAN AppCtrlQueueOverFlow;
+ BOOLEAN AppCtrlQueueOverFlow;
atomic_t CurrentApplicationCount;
- atomic_t RegisteredApplicationCount;
- BOOLEAN LinkUpStatus;
- BOOLEAN TimerActive;
+ atomic_t RegisteredApplicationCount;
+ BOOLEAN LinkUpStatus;
+ BOOLEAN TimerActive;
u32 StatisticsPointer;
struct sk_buff *RxControlHead;
struct sk_buff *RxControlTail;
-
struct semaphore RxAppControlQueuelock;
struct semaphore fw_download_sema;
-
- PPER_TARANG_DATA pTarangs;
- spinlock_t control_queue_lock;
+ PPER_TARANG_DATA pTarangs;
+ spinlock_t control_queue_lock;
wait_queue_head_t process_read_wait_queue;
- // the pointer to the first packet we have queued in send
- // deserialized miniport support variables
- atomic_t TotalPacketCount;
- atomic_t TxPktAvail;
-
- // this to keep track of the Tx and Rx MailBox Registers.
- atomic_t CurrNumFreeTxDesc;
- // to keep track the no of byte received
- USHORT PrevNumRecvDescs;
- USHORT CurrNumRecvDescs;
- UINT u32TotalDSD;
- PacketInfo PackInfo[NO_OF_QUEUES];
+ /* the pointer to the first packet we have queued in send
+ * deserialized miniport support variables
+ */
+ atomic_t TotalPacketCount;
+ atomic_t TxPktAvail;
+
+ /* this to keep track of the Tx and Rx MailBox Registers. */
+ atomic_t CurrNumFreeTxDesc;
+ /* to keep track the no of byte received */
+ USHORT PrevNumRecvDescs;
+ USHORT CurrNumRecvDescs;
+ UINT u32TotalDSD;
+ PacketInfo PackInfo[NO_OF_QUEUES];
S_CLASSIFIER_RULE astClassifierTable[MAX_CLASSIFIERS];
- BOOLEAN TransferMode;
+ BOOLEAN TransferMode;
/*************** qos ******************/
- BOOLEAN bETHCSEnabled;
-
- ULONG BEBucketSize;
- ULONG rtPSBucketSize;
- UCHAR LinkStatus;
- BOOLEAN AutoLinkUp;
- BOOLEAN AutoSyncup;
-
- int major;
- int minor;
- wait_queue_head_t tx_packet_wait_queue;
- wait_queue_head_t process_rx_cntrlpkt;
- atomic_t process_waiting;
- BOOLEAN fw_download_done;
-
- char *txctlpacket[MAX_CNTRL_PKTS];
- atomic_t cntrlpktCnt ;
- atomic_t index_app_read_cntrlpkt;
- atomic_t index_wr_txcntrlpkt;
- atomic_t index_rd_txcntrlpkt;
- UINT index_datpkt;
- struct semaphore rdmwrmsync;
+ BOOLEAN bETHCSEnabled;
+ ULONG BEBucketSize;
+ ULONG rtPSBucketSize;
+ UCHAR LinkStatus;
+ BOOLEAN AutoLinkUp;
+ BOOLEAN AutoSyncup;
+
+ int major;
+ int minor;
+ wait_queue_head_t tx_packet_wait_queue;
+ wait_queue_head_t process_rx_cntrlpkt;
+ atomic_t process_waiting;
+ BOOLEAN fw_download_done;
+
+ char *txctlpacket[MAX_CNTRL_PKTS];
+ atomic_t cntrlpktCnt ;
+ atomic_t index_app_read_cntrlpkt;
+ atomic_t index_wr_txcntrlpkt;
+ atomic_t index_rd_txcntrlpkt;
+ UINT index_datpkt;
+ struct semaphore rdmwrmsync;
STTARGETDSXBUFFER astTargetDsxBuffer[MAX_TARGET_DSX_BUFFERS];
ULONG ulFreeTargetBufferCnt;
- ULONG ulCurrentTargetBuffer;
- ULONG ulTotalTargetBuffersAvailable;
-
- unsigned long chip_id;
-
- wait_queue_head_t lowpower_mode_wait_queue;
-
+ ULONG ulCurrentTargetBuffer;
+ ULONG ulTotalTargetBuffersAvailable;
+ unsigned long chip_id;
+ wait_queue_head_t lowpower_mode_wait_queue;
BOOLEAN bFlashBoot;
BOOLEAN bBinDownloaded;
BOOLEAN bCfgDownloaded;
BOOLEAN bSyncUpRequestSent;
USHORT usBestEffortQueueIndex;
-
- wait_queue_head_t ioctl_fw_dnld_wait_queue;
- BOOLEAN waiting_to_fw_download_done;
- pid_t fw_download_process_pid;
+ wait_queue_head_t ioctl_fw_dnld_wait_queue;
+ BOOLEAN waiting_to_fw_download_done;
+ pid_t fw_download_process_pid;
PSTARGETPARAMS pstargetparams;
- BOOLEAN device_removed;
- BOOLEAN DeviceAccess;
- BOOLEAN bIsAutoCorrectEnabled;
- BOOLEAN bDDRInitDone;
- INT DDRSetting;
- ULONG ulPowerSaveMode;
- spinlock_t txtransmitlock;
- B_UINT8 txtransmit_running;
+ BOOLEAN device_removed;
+ BOOLEAN DeviceAccess;
+ BOOLEAN bIsAutoCorrectEnabled;
+ BOOLEAN bDDRInitDone;
+ int DDRSetting;
+ ULONG ulPowerSaveMode;
+ spinlock_t txtransmitlock;
+ B_UINT8 txtransmit_running;
/* Thread for control packet handling */
- struct task_struct *control_packet_handler;
+ struct task_struct *control_packet_handler;
/* thread for transmitting packets. */
- struct task_struct *transmit_packet_thread;
+ struct task_struct *transmit_packet_thread;
/* LED Related Structures */
LED_INFO_STRUCT LEDInfo;
@@ -482,39 +438,38 @@ struct _MINI_ADAPTER
/* Driver State for LED Blinking */
LedEventInfo_t DriverState;
/* Interface Specific */
- PVOID pvInterfaceAdapter;
- int (*bcm_file_download)( PVOID,
- struct file *,
- unsigned int);
- int (*bcm_file_readback_from_chip)( PVOID,
- struct file *,
- unsigned int);
- INT (*interface_rdm)(PVOID,
- UINT ,
- PVOID ,
- INT);
- INT (*interface_wrm)(PVOID,
- UINT ,
- PVOID ,
- INT);
+ PVOID pvInterfaceAdapter;
+ int (*bcm_file_download)(PVOID,
+ struct file *,
+ unsigned int);
+ int (*bcm_file_readback_from_chip)(PVOID,
+ struct file *,
+ unsigned int);
+ int (*interface_rdm)(PVOID,
+ UINT,
+ PVOID,
+ int);
+ int (*interface_wrm)(PVOID,
+ UINT,
+ PVOID,
+ int);
int (*interface_transmit)(PVOID, PVOID , UINT);
BOOLEAN IdleMode;
BOOLEAN bDregRequestSentInIdleMode;
BOOLEAN bTriedToWakeUpFromlowPowerMode;
BOOLEAN bShutStatus;
BOOLEAN bWakeUpDevice;
- unsigned int usIdleModePattern;
- //BOOLEAN bTriedToWakeUpFromShutdown;
+ unsigned int usIdleModePattern;
+ /* BOOLEAN bTriedToWakeUpFromShutdown; */
BOOLEAN bLinkDownRequested;
-
- int downloadDDR;
- PHS_DEVICE_EXTENSION stBCMPhsContext;
- S_HDR_SUPRESSION_CONTEXTINFO stPhsTxContextInfo;
+ int downloadDDR;
+ PHS_DEVICE_EXTENSION stBCMPhsContext;
+ S_HDR_SUPRESSION_CONTEXTINFO stPhsTxContextInfo;
uint8_t ucaPHSPktRestoreBuf[2048];
uint8_t bPHSEnabled;
BOOLEAN AutoFirmDld;
- BOOLEAN bMipsConfig;
- BOOLEAN bDPLLConfig;
+ BOOLEAN bMipsConfig;
+ BOOLEAN bDPLLConfig;
UINT32 aTxPktSizeHist[MIBS_MAX_HIST_ENTRIES];
UINT32 aRxPktSizeHist[MIBS_MAX_HIST_ENTRIES];
S_FRAGMENTED_PACKET_INFO astFragmentedPktClassifierTable[MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES];
@@ -527,108 +482,101 @@ struct _MINI_ADAPTER
BOOLEAN bStatusWrite;
UINT uiNVMDSDSize;
UINT uiVendorExtnFlag;
- //it will always represent chosen DSD at any point of time.
- // Generally it is Active DSD but in case of NVM RD/WR it might be different.
+ /* it will always represent chosen DSD at any point of time.
+ * Generally it is Active DSD but in case of NVM RD/WR it might be different.
+ */
UINT ulFlashCalStart;
- ULONG ulFlashControlSectionStart;
- ULONG ulFlashWriteSize;
- ULONG ulFlashID;
- FP_FLASH_WRITE fpFlashWrite;
- FP_FLASH_WRITE_STATUS fpFlashWriteWithStatusCheck;
-
+ ULONG ulFlashControlSectionStart;
+ ULONG ulFlashWriteSize;
+ ULONG ulFlashID;
+ FP_FLASH_WRITE fpFlashWrite;
+ FP_FLASH_WRITE_STATUS fpFlashWriteWithStatusCheck;
struct semaphore NVMRdmWrmLock;
+ struct device *pstCreatedClassDevice;
- struct device *pstCreatedClassDevice;
-
-// BOOLEAN InterfaceUpStatus;
- PFLASH2X_CS_INFO psFlash2xCSInfo;
- PFLASH_CS_INFO psFlashCSInfo ;
+ /* BOOLEAN InterfaceUpStatus; */
+ PFLASH2X_CS_INFO psFlash2xCSInfo;
+ PFLASH_CS_INFO psFlashCSInfo;
PFLASH2X_VENDORSPECIFIC_INFO psFlash2xVendorInfo;
- UINT uiFlashBaseAdd; //Flash start address
- UINT uiActiveISOOffset; //Active ISO offset chosen before f/w download
- FLASH2X_SECTION_VAL eActiveISO; //Active ISO section val
- FLASH2X_SECTION_VAL eActiveDSD; //Active DSD val chosen before f/w download
- UINT uiActiveDSDOffsetAtFwDld; //For accessing Active DSD chosen before f/w download
- UINT uiFlashLayoutMajorVersion ;
- UINT uiFlashLayoutMinorVersion;
- BOOLEAN bAllDSDWriteAllow ;
- BOOLEAN bSigCorrupted ;
- //this should be set who so ever want to change the Headers. after Wrtie it should be reset immediately.
- BOOLEAN bHeaderChangeAllowed ;
- INT SelectedChip ;
- BOOLEAN bEndPointHalted;
- //while bFlashRawRead will be true, Driver ignore map lay out and consider flash as of without any map.
- BOOLEAN bFlashRawRead;
- BOOLEAN bPreparingForLowPowerMode ;
- BOOLEAN bDoSuspend ;
- UINT syscfgBefFwDld ;
- BOOLEAN StopAllXaction ;
- UINT32 liTimeSinceLastNetEntry; //Used to Support extended CAPI requirements from
+ UINT uiFlashBaseAdd; /* Flash start address */
+ UINT uiActiveISOOffset; /* Active ISO offset chosen before f/w download */
+ FLASH2X_SECTION_VAL eActiveISO; /* Active ISO section val */
+ FLASH2X_SECTION_VAL eActiveDSD; /* Active DSD val chosen before f/w download */
+ UINT uiActiveDSDOffsetAtFwDld; /* For accessing Active DSD chosen before f/w download */
+ UINT uiFlashLayoutMajorVersion;
+ UINT uiFlashLayoutMinorVersion;
+ BOOLEAN bAllDSDWriteAllow;
+ BOOLEAN bSigCorrupted;
+ /* this should be set who so ever want to change the Headers. after Wrtie it should be reset immediately. */
+ BOOLEAN bHeaderChangeAllowed;
+ int SelectedChip;
+ BOOLEAN bEndPointHalted;
+ /* while bFlashRawRead will be true, Driver ignore map lay out and consider flash as of without any map. */
+ BOOLEAN bFlashRawRead;
+ BOOLEAN bPreparingForLowPowerMode;
+ BOOLEAN bDoSuspend;
+ UINT syscfgBefFwDld;
+ BOOLEAN StopAllXaction;
+ UINT32 liTimeSinceLastNetEntry; /* Used to Support extended CAPI requirements from */
struct semaphore LowPowerModeSync;
- ULONG liDrainCalculated;
- UINT gpioBitMap;
-
- S_BCM_DEBUG_STATE stDebugState;
-
+ ULONG liDrainCalculated;
+ UINT gpioBitMap;
+ S_BCM_DEBUG_STATE stDebugState;
};
typedef struct _MINI_ADAPTER MINI_ADAPTER, *PMINI_ADAPTER;
-#define GET_BCM_ADAPTER(net_dev) netdev_priv(net_dev)
+#define GET_BCM_ADAPTER(net_dev) netdev_priv(net_dev)
struct _ETH_HEADER_STRUC {
- UCHAR au8DestinationAddress[6];
- UCHAR au8SourceAddress[6];
- USHORT u16Etype;
-}__attribute__((packed));
+ UCHAR au8DestinationAddress[6];
+ UCHAR au8SourceAddress[6];
+ USHORT u16Etype;
+} __packed;
typedef struct _ETH_HEADER_STRUC ETH_HEADER_STRUC, *PETH_HEADER_STRUC;
+typedef struct FirmwareInfo {
+ void __user *pvMappedFirmwareAddress;
+ ULONG u32FirmwareLength;
+ ULONG u32StartingAddress;
+} __packed FIRMWARE_INFO, *PFIRMWARE_INFO;
-typedef struct FirmwareInfo
-{
- void __user * pvMappedFirmwareAddress;
- ULONG u32FirmwareLength;
- ULONG u32StartingAddress;
-}__attribute__((packed)) FIRMWARE_INFO, *PFIRMWARE_INFO;
-
-// holds the value of net_device structure..
+/* holds the value of net_device structure.. */
extern struct net_device *gblpnetdev;
-typedef struct _cntl_pkt{
- PMINI_ADAPTER Adapter;
- PLEADER PLeader;
-}cntl_pkt;
+typedef struct _cntl_pkt {
+ PMINI_ADAPTER Adapter;
+ PLEADER PLeader;
+} cntl_pkt;
typedef LINK_REQUEST CONTROL_MESSAGE;
-typedef struct _DDR_SETTING
-{
+typedef struct _DDR_SETTING {
UINT ulRegAddress;
UINT ulRegValue;
-}DDR_SETTING, *PDDR_SETTING;
+} DDR_SETTING, *PDDR_SETTING;
typedef DDR_SETTING DDR_SET_NODE, *PDDR_SET_NODE;
-INT
-InitAdapter(PMINI_ADAPTER psAdapter);
-
-// =====================================================================
-// Beceem vendor request codes for EP0
-// =====================================================================
+int InitAdapter(PMINI_ADAPTER psAdapter);
-#define BCM_REQUEST_READ 0x2
-#define BCM_REQUEST_WRITE 0x1
-#define EP2_MPS_REG 0x0F0110A0
-#define EP2_MPS 0x40
+/* =====================================================================
+ * Beceem vendor request codes for EP0
+ * =====================================================================
+ */
-#define EP2_CFG_REG 0x0F0110A8
-#define EP2_CFG_INT 0x27
-#define EP2_CFG_BULK 0x25
+#define BCM_REQUEST_READ 0x2
+#define BCM_REQUEST_WRITE 0x1
+#define EP2_MPS_REG 0x0F0110A0
+#define EP2_MPS 0x40
-#define EP4_MPS_REG 0x0F0110F0
-#define EP4_MPS 0x8C
+#define EP2_CFG_REG 0x0F0110A8
+#define EP2_CFG_INT 0x27
+#define EP2_CFG_BULK 0x25
-#define EP4_CFG_REG 0x0F0110F8
+#define EP4_MPS_REG 0x0F0110F0
+#define EP4_MPS 0x8C
-#define ISO_MPS_REG 0x0F0110C8
-#define ISO_MPS 0x00000000
+#define EP4_CFG_REG 0x0F0110F8
+#define ISO_MPS_REG 0x0F0110C8
+#define ISO_MPS 0x00000000
#define EP1 0
#define EP2 1
@@ -637,12 +585,9 @@ InitAdapter(PMINI_ADAPTER psAdapter);
#define EP5 4
#define EP6 5
-
-typedef enum eInterface_setting
-{
+typedef enum eInterface_setting {
DEFAULT_SETTING_0 = 0,
ALTERNATE_SETTING_1 = 1,
-}INTERFACE_SETTING;
-
-#endif //__ADAPTER_H__
+} INTERFACE_SETTING;
+#endif /* __ADAPTER_H__ */
diff --git a/drivers/staging/bcm/DDRInit.c b/drivers/staging/bcm/DDRInit.c
index 1c7db81a1ee8..2b46f4d4ef0e 100644
--- a/drivers/staging/bcm/DDRInit.c
+++ b/drivers/staging/bcm/DDRInit.c
@@ -1115,20 +1115,20 @@ int download_ddr_settings(PMINI_ADAPTER Adapter)
{
case DDR_80_MHZ:
psDDRSetting = asT3LP_DDRSetting80MHz;
- RegCount = (sizeof(asT3LP_DDRSetting80MHz)/sizeof(DDR_SET_NODE));
+ RegCount = ARRAY_SIZE(asT3LP_DDRSetting80MHz);
RegCount -= T3LP_SKIP_CLOCK_PROGRAM_DUMP_80MHZ ;
psDDRSetting += T3LP_SKIP_CLOCK_PROGRAM_DUMP_80MHZ;
break;
case DDR_100_MHZ:
psDDRSetting = asT3LP_DDRSetting100MHz;
- RegCount = (sizeof(asT3LP_DDRSetting100MHz)/sizeof(DDR_SET_NODE));
+ RegCount = ARRAY_SIZE(asT3LP_DDRSetting100MHz);
RegCount -= T3LP_SKIP_CLOCK_PROGRAM_DUMP_100MHZ ;
psDDRSetting += T3LP_SKIP_CLOCK_PROGRAM_DUMP_100MHZ;
break;
case DDR_133_MHZ:
bOverrideSelfRefresh = TRUE;
psDDRSetting = asT3LP_DDRSetting133MHz;
- RegCount = (sizeof(asT3LP_DDRSetting133MHz)/sizeof(DDR_SET_NODE));
+ RegCount = ARRAY_SIZE(asT3LP_DDRSetting133MHz);
RegCount -= T3LP_SKIP_CLOCK_PROGRAM_DUMP_133MHZ ;
psDDRSetting += T3LP_SKIP_CLOCK_PROGRAM_DUMP_133MHZ;
break;
@@ -1146,20 +1146,20 @@ int download_ddr_settings(PMINI_ADAPTER Adapter)
{
case DDR_80_MHZ:
psDDRSetting = asT3LPB_DDRSetting80MHz;
- RegCount=(sizeof(asT3LPB_DDRSetting80MHz)/sizeof(DDR_SET_NODE));
+ RegCount=ARRAY_SIZE(asT3LPB_DDRSetting80MHz);
RegCount -= T3LPB_SKIP_CLOCK_PROGRAM_DUMP_80MHZ ;
psDDRSetting += T3LPB_SKIP_CLOCK_PROGRAM_DUMP_80MHZ;
break;
case DDR_100_MHZ:
psDDRSetting = asT3LPB_DDRSetting100MHz;
- RegCount = (sizeof(asT3LPB_DDRSetting100MHz)/sizeof(DDR_SET_NODE));
+ RegCount = ARRAY_SIZE(asT3LPB_DDRSetting100MHz);
RegCount -= T3LPB_SKIP_CLOCK_PROGRAM_DUMP_100MHZ ;
psDDRSetting += T3LPB_SKIP_CLOCK_PROGRAM_DUMP_100MHZ;
break;
case DDR_133_MHZ:
bOverrideSelfRefresh = TRUE;
psDDRSetting = asT3LPB_DDRSetting133MHz;
- RegCount = (sizeof(asT3LPB_DDRSetting133MHz)/sizeof(DDR_SET_NODE));
+ RegCount = ARRAY_SIZE(asT3LPB_DDRSetting133MHz);
RegCount -= T3LPB_SKIP_CLOCK_PROGRAM_DUMP_133MHZ ;
psDDRSetting += T3LPB_SKIP_CLOCK_PROGRAM_DUMP_133MHZ;
break;
@@ -1167,7 +1167,7 @@ int download_ddr_settings(PMINI_ADAPTER Adapter)
case DDR_160_MHZ:
bOverrideSelfRefresh = TRUE;
psDDRSetting = asT3LPB_DDRSetting160MHz;
- RegCount = sizeof(asT3LPB_DDRSetting160MHz)/sizeof(DDR_SET_NODE);
+ RegCount = ARRAY_SIZE(asT3LPB_DDRSetting160MHz);
RegCount -= T3LPB_SKIP_CLOCK_PROGRAM_DUMP_160MHZ;
psDDRSetting += T3LPB_SKIP_CLOCK_PROGRAM_DUMP_160MHZ;
@@ -1181,19 +1181,19 @@ int download_ddr_settings(PMINI_ADAPTER Adapter)
{
case DDR_80_MHZ:
psDDRSetting = asT3_DDRSetting80MHz;
- RegCount = (sizeof(asT3_DDRSetting80MHz)/sizeof(DDR_SET_NODE));
+ RegCount = ARRAY_SIZE(asT3_DDRSetting80MHz);
RegCount-=T3_SKIP_CLOCK_PROGRAM_DUMP_80MHZ ;
psDDRSetting += T3_SKIP_CLOCK_PROGRAM_DUMP_80MHZ;
break;
case DDR_100_MHZ:
psDDRSetting = asT3_DDRSetting100MHz;
- RegCount = (sizeof(asT3_DDRSetting100MHz)/sizeof(DDR_SET_NODE));
+ RegCount = ARRAY_SIZE(asT3_DDRSetting100MHz);
RegCount-=T3_SKIP_CLOCK_PROGRAM_DUMP_100MHZ ;
psDDRSetting += T3_SKIP_CLOCK_PROGRAM_DUMP_100MHZ;
break;
case DDR_133_MHZ:
psDDRSetting = asT3_DDRSetting133MHz;
- RegCount = (sizeof(asT3_DDRSetting133MHz)/sizeof(DDR_SET_NODE));
+ RegCount = ARRAY_SIZE(asT3_DDRSetting133MHz);
RegCount-=T3_SKIP_CLOCK_PROGRAM_DUMP_133MHZ ;
psDDRSetting += T3_SKIP_CLOCK_PROGRAM_DUMP_133MHZ ;
break;
@@ -1207,20 +1207,20 @@ int download_ddr_settings(PMINI_ADAPTER Adapter)
{
case DDR_80_MHZ:
psDDRSetting = asT3B_DDRSetting80MHz;
- RegCount = (sizeof(asT3B_DDRSetting80MHz)/sizeof(DDR_SET_NODE));
+ RegCount = ARRAY_SIZE(asT3B_DDRSetting80MHz);
RegCount -= T3B_SKIP_CLOCK_PROGRAM_DUMP_80MHZ ;
psDDRSetting += T3B_SKIP_CLOCK_PROGRAM_DUMP_80MHZ;
break;
case DDR_100_MHZ:
psDDRSetting = asT3B_DDRSetting100MHz;
- RegCount = (sizeof(asT3B_DDRSetting100MHz)/sizeof(DDR_SET_NODE));
+ RegCount = ARRAY_SIZE(asT3B_DDRSetting100MHz);
RegCount -= T3B_SKIP_CLOCK_PROGRAM_DUMP_100MHZ ;
psDDRSetting += T3B_SKIP_CLOCK_PROGRAM_DUMP_100MHZ;
break;
case DDR_133_MHZ:
bOverrideSelfRefresh = TRUE;
psDDRSetting = asT3B_DDRSetting133MHz;
- RegCount = (sizeof(asT3B_DDRSetting133MHz)/sizeof(DDR_SET_NODE));
+ RegCount = ARRAY_SIZE(asT3B_DDRSetting133MHz);
RegCount -= T3B_SKIP_CLOCK_PROGRAM_DUMP_133MHZ ;
psDDRSetting += T3B_SKIP_CLOCK_PROGRAM_DUMP_133MHZ;
break;
diff --git a/drivers/staging/bcm/IPv6Protocol.c b/drivers/staging/bcm/IPv6Protocol.c
index 5b4fd372ec36..1da21642c18e 100644
--- a/drivers/staging/bcm/IPv6Protocol.c
+++ b/drivers/staging/bcm/IPv6Protocol.c
@@ -1,51 +1,52 @@
#include "headers.h"
-static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header);
-static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header);
+static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,
+ IPV6Header *pstIpv6Header);
+static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,
+ IPV6Header *pstIpv6Header);
static VOID DumpIpv6Header(IPV6Header *pstIpv6Header);
-static UCHAR * GetNextIPV6ChainedHeader(UCHAR **ppucPayload,UCHAR *pucNextHeader,BOOLEAN *bParseDone,USHORT *pusPayloadLength)
+static UCHAR *GetNextIPV6ChainedHeader(UCHAR **ppucPayload,
+ UCHAR *pucNextHeader, BOOLEAN *bParseDone, USHORT *pusPayloadLength)
{
UCHAR *pucRetHeaderPtr = NULL;
UCHAR *pucPayloadPtr = NULL;
USHORT usNextHeaderOffset = 0 ;
- PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+ PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
- if((NULL == ppucPayload) || (*pusPayloadLength == 0) || (*bParseDone))
- {
+ if ((ppucPayload == NULL) || (*pusPayloadLength == 0) ||
+ (*bParseDone)) {
*bParseDone = TRUE;
return NULL;
-
}
pucRetHeaderPtr = *ppucPayload;
pucPayloadPtr = *ppucPayload;
- if(!pucRetHeaderPtr || !pucPayloadPtr)
- {
+ if (!pucRetHeaderPtr || !pucPayloadPtr) {
*bParseDone = TRUE;
return NULL;
}
- //Get the Nextt Header Type
+ /* Get the Nextt Header Type */
*bParseDone = FALSE;
-
- switch(*pucNextHeader)
- {
+ switch (*pucNextHeader) {
case IPV6HDR_TYPE_HOPBYHOP:
{
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 HopByHop Header");
- usNextHeaderOffset+=sizeof(IPV6HopByHopOptionsHeader);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL, "\nIPv6 HopByHop Header");
+ usNextHeaderOffset += sizeof(IPV6HopByHopOptionsHeader);
}
break;
case IPV6HDR_TYPE_ROUTING:
{
IPV6RoutingHeader *pstIpv6RoutingHeader;
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Routing Header");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL, "\nIPv6 Routing Header");
pstIpv6RoutingHeader = (IPV6RoutingHeader *)pucPayloadPtr;
usNextHeaderOffset += sizeof(IPV6RoutingHeader);
usNextHeaderOffset += pstIpv6RoutingHeader->ucNumAddresses * IPV6_ADDRESS_SIZEINBYTES;
@@ -54,8 +55,10 @@ static UCHAR * GetNextIPV6ChainedHeader(UCHAR **ppucPayload,UCHAR *pucNextHeader
break;
case IPV6HDR_TYPE_FRAGMENTATION:
{
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Fragmentation Header");
- usNextHeaderOffset+= sizeof(IPV6FragmentHeader);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL,
+ "\nIPv6 Fragmentation Header");
+ usNextHeaderOffset += sizeof(IPV6FragmentHeader);
}
break;
@@ -63,9 +66,11 @@ static UCHAR * GetNextIPV6ChainedHeader(UCHAR **ppucPayload,UCHAR *pucNextHeader
{
IPV6DestOptionsHeader *pstIpv6DestOptsHdr = (IPV6DestOptionsHeader *)pucPayloadPtr;
int nTotalOptions = pstIpv6DestOptsHdr->ucHdrExtLen;
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 DestOpts Header Header");
- usNextHeaderOffset+= sizeof(IPV6DestOptionsHeader);
- usNextHeaderOffset+= nTotalOptions * IPV6_DESTOPTS_HDR_OPTIONSIZE ;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL,
+ "\nIPv6 DestOpts Header Header");
+ usNextHeaderOffset += sizeof(IPV6DestOptionsHeader);
+ usNextHeaderOffset += nTotalOptions * IPV6_DESTOPTS_HDR_OPTIONSIZE ;
}
break;
@@ -73,36 +78,43 @@ static UCHAR * GetNextIPV6ChainedHeader(UCHAR **ppucPayload,UCHAR *pucNextHeader
{
IPV6AuthenticationHeader *pstIpv6AuthHdr = (IPV6AuthenticationHeader *)pucPayloadPtr;
int nHdrLen = pstIpv6AuthHdr->ucLength;
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Authentication Header");
- usNextHeaderOffset+= nHdrLen * 4;
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL,
+ "\nIPv6 Authentication Header");
+ usNextHeaderOffset += nHdrLen * 4;
}
break;
case IPV6HDR_TYPE_ENCRYPTEDSECURITYPAYLOAD:
{
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Encrypted Security Payload Header");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL,
+ "\nIPv6 Encrypted Security Payload Header");
*bParseDone = TRUE;
}
break;
case IPV6_ICMP_HDR_TYPE:
{
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, " ICMP Header");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL, "\nICMP Header");
*bParseDone = TRUE;
}
break;
case TCP_HEADER_TYPE:
{
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, " \nTCP Header");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL, "\nTCP Header");
*bParseDone = TRUE;
}
break;
case UDP_HEADER_TYPE:
{
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, " \nUDP Header");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL, "\nUDP Header");
*bParseDone = TRUE;
}
break;
- default :
+ default:
{
*bParseDone = TRUE;
@@ -112,53 +124,49 @@ static UCHAR * GetNextIPV6ChainedHeader(UCHAR **ppucPayload,UCHAR *pucNextHeader
}
- if(*bParseDone == FALSE)
- {
- if(*pusPayloadLength <= usNextHeaderOffset)
- {
+ if (*bParseDone == FALSE) {
+ if (*pusPayloadLength <= usNextHeaderOffset) {
*bParseDone = TRUE;
- }
- else
- {
+ } else {
*pucNextHeader = *pucPayloadPtr;
- pucPayloadPtr+=usNextHeaderOffset;
- (*pusPayloadLength)-=usNextHeaderOffset;
+ pucPayloadPtr += usNextHeaderOffset;
+ (*pusPayloadLength) -= usNextHeaderOffset;
}
}
-
-
*ppucPayload = pucPayloadPtr;
return pucRetHeaderPtr;
}
-static UCHAR GetIpv6ProtocolPorts(UCHAR *pucPayload,USHORT *pusSrcPort,USHORT *pusDestPort,USHORT usPayloadLength,UCHAR ucNextHeader)
+static UCHAR GetIpv6ProtocolPorts(UCHAR *pucPayload, USHORT *pusSrcPort,
+ USHORT *pusDestPort, USHORT usPayloadLength, UCHAR ucNextHeader)
{
UCHAR *pIpv6HdrScanContext = pucPayload;
BOOLEAN bDone = FALSE;
- UCHAR ucHeaderType =0;
+ UCHAR ucHeaderType = 0;
UCHAR *pucNextHeader = NULL;
- PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+ PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
- if( !pucPayload || (usPayloadLength == 0))
- {
+ if (!pucPayload || (usPayloadLength == 0))
return 0;
- }
*pusSrcPort = *pusDestPort = 0;
ucHeaderType = ucNextHeader;
- while(!bDone)
- {
- pucNextHeader = GetNextIPV6ChainedHeader(&pIpv6HdrScanContext,&ucHeaderType,&bDone,&usPayloadLength);
- if(bDone)
- {
- if((ucHeaderType==TCP_HEADER_TYPE) || (ucHeaderType == UDP_HEADER_TYPE))
- {
- *pusSrcPort=*((PUSHORT)(pucNextHeader));
- *pusDestPort=*((PUSHORT)(pucNextHeader+2));
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, " \nProtocol Ports - Src Port :0x%x Dest Port : 0x%x",ntohs(*pusSrcPort),ntohs(*pusDestPort));
+ while (!bDone) {
+ pucNextHeader = GetNextIPV6ChainedHeader(&pIpv6HdrScanContext,
+ &ucHeaderType, &bDone, &usPayloadLength);
+ if (bDone) {
+ if ((ucHeaderType == TCP_HEADER_TYPE) ||
+ (ucHeaderType == UDP_HEADER_TYPE)) {
+ *pusSrcPort = *((PUSHORT)(pucNextHeader));
+ *pusDestPort = *((PUSHORT)(pucNextHeader+2));
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL,
+ "\nProtocol Ports - Src Port :0x%x Dest Port : 0x%x",
+ ntohs(*pusSrcPort),
+ ntohs(*pusDestPort));
}
break;
@@ -168,92 +176,111 @@ static UCHAR GetIpv6ProtocolPorts(UCHAR *pucPayload,USHORT *pusSrcPort,USHORT *p
}
-
-USHORT IpVersion6(PMINI_ADAPTER Adapter, /**< Pointer to the driver control structure */
- PVOID pcIpHeader, /**<Pointer to the IP Hdr of the packet*/
- S_CLASSIFIER_RULE *pstClassifierRule )
+/*
+ * Arg 1 PMINI_ADAPTER Adapter is a pointer ot the driver contorl structure
+ * Arg 2 PVOID pcIpHeader is a pointer to the IP header of the packet
+ */
+USHORT IpVersion6(PMINI_ADAPTER Adapter, PVOID pcIpHeader,
+ S_CLASSIFIER_RULE *pstClassifierRule)
{
USHORT ushDestPort = 0;
USHORT ushSrcPort = 0;
- UCHAR ucNextProtocolAboveIP =0;
+ UCHAR ucNextProtocolAboveIP = 0;
IPV6Header *pstIpv6Header = NULL;
BOOLEAN bClassificationSucceed = FALSE;
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "IpVersion6 ==========>\n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL, "IpVersion6 ==========>\n");
pstIpv6Header = (IPV6Header *)pcIpHeader;
DumpIpv6Header(pstIpv6Header);
- //Try to get the next higher layer protocol and the Ports Nos if TCP or UDP
+ /*
+ * Try to get the next higher layer protocol
+ * and the Ports Nos if TCP or UDP
+ */
ucNextProtocolAboveIP = GetIpv6ProtocolPorts((UCHAR *)(pcIpHeader + sizeof(IPV6Header)),
&ushSrcPort,
&ushDestPort,
pstIpv6Header->usPayloadLength,
pstIpv6Header->ucNextHeader);
- do
- {
- if(0 == pstClassifierRule->ucDirection)
- {
- //cannot be processed for classification.
- // it is a down link connection
+ do {
+ if (pstClassifierRule->ucDirection == 0) {
+ /*
+ * cannot be processed for classification.
+ * it is a down link connection
+ */
break;
}
- if(!pstClassifierRule->bIpv6Protocol)
- {
- //We are looking for Ipv6 Classifiers . Lets ignore this classifier and try the next one.
+ if (!pstClassifierRule->bIpv6Protocol) {
+ /*
+ * We are looking for Ipv6 Classifiers
+ * Lets ignore this classifier and try the next one
+ */
break;
}
- bClassificationSucceed=MatchSrcIpv6Address(pstClassifierRule,pstIpv6Header);
- if(!bClassificationSucceed)
- break;
+ bClassificationSucceed = MatchSrcIpv6Address(pstClassifierRule,
+ pstIpv6Header);
+ if (!bClassificationSucceed)
+ break;
- bClassificationSucceed=MatchDestIpv6Address(pstClassifierRule,pstIpv6Header);
- if(!bClassificationSucceed)
- break;
+ bClassificationSucceed = MatchDestIpv6Address(pstClassifierRule,
+ pstIpv6Header);
+ if (!bClassificationSucceed)
+ break;
- //Match the protocol type.For IPv6 the next protocol at end of Chain of IPv6 prot headers
- bClassificationSucceed=MatchProtocol(pstClassifierRule,ucNextProtocolAboveIP);
- if(!bClassificationSucceed)
- break;
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Protocol Matched");
+ /*
+ * Match the protocol type.
+ * For IPv6 the next protocol at end of
+ * Chain of IPv6 prot headers
+ */
+ bClassificationSucceed = MatchProtocol(pstClassifierRule,
+ ucNextProtocolAboveIP);
+ if (!bClassificationSucceed)
+ break;
- if((ucNextProtocolAboveIP == TCP_HEADER_TYPE) || (ucNextProtocolAboveIP == UDP_HEADER_TYPE))
- {
- //Match Src Port
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Source Port:%x\n",ntohs(ushSrcPort));
- bClassificationSucceed=MatchSrcPort(pstClassifierRule,ntohs(ushSrcPort));
- if(!bClassificationSucceed)
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL, "\nIPv6 Protocol Matched");
+
+ if ((ucNextProtocolAboveIP == TCP_HEADER_TYPE) ||
+ (ucNextProtocolAboveIP == UDP_HEADER_TYPE)) {
+ /* Match Src Port */
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL, "\nIPv6 Source Port:%x\n",
+ ntohs(ushSrcPort));
+ bClassificationSucceed = MatchSrcPort(pstClassifierRule,
+ ntohs(ushSrcPort));
+ if (!bClassificationSucceed)
break;
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Src Port Matched");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL, "\nIPv6 Src Port Matched");
- //Match Dest Port
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Destination Port:%x\n",ntohs(ushDestPort));
- bClassificationSucceed=MatchDestPort(pstClassifierRule,ntohs(ushDestPort));
- if(!bClassificationSucceed)
+ /* Match Dest Port */
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL, "\nIPv6 Destination Port:%x\n",
+ ntohs(ushDestPort));
+ bClassificationSucceed = MatchDestPort(pstClassifierRule,
+ ntohs(ushDestPort));
+ if (!bClassificationSucceed)
break;
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\nIPv6 Dest Port Matched");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL, "\nIPv6 Dest Port Matched");
}
- }while(0);
+ } while (0);
- if(TRUE==bClassificationSucceed)
- {
+ if (bClassificationSucceed == TRUE) {
INT iMatchedSFQueueIndex = 0;
- iMatchedSFQueueIndex = SearchSfid(Adapter,pstClassifierRule->ulSFID);
- if(iMatchedSFQueueIndex >= NO_OF_QUEUES)
- {
+ iMatchedSFQueueIndex = SearchSfid(Adapter, pstClassifierRule->ulSFID);
+ if (iMatchedSFQueueIndex >= NO_OF_QUEUES) {
bClassificationSucceed = FALSE;
- }
- else
- {
- if(FALSE == Adapter->PackInfo[iMatchedSFQueueIndex].bActive)
- {
+ } else {
+ if (Adapter->PackInfo[iMatchedSFQueueIndex].bActive == FALSE)
bClassificationSucceed = FALSE;
- }
}
}
@@ -261,52 +288,55 @@ USHORT IpVersion6(PMINI_ADAPTER Adapter, /**< Pointer to the driver control stru
}
-static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header)
+static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,
+ IPV6Header *pstIpv6Header)
{
- UINT uiLoopIndex=0;
- UINT uiIpv6AddIndex=0;
- UINT uiIpv6AddrNoLongWords = 4;
+ UINT uiLoopIndex = 0;
+ UINT uiIpv6AddIndex = 0;
+ UINT uiIpv6AddrNoLongWords = 4;
ULONG aulSrcIP[4];
- PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+ PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
/*
- //This is the no. of Src Addresses ie Range of IP Addresses contained
- //in the classifier rule for which we need to match
- */
+ * This is the no. of Src Addresses ie Range of IP Addresses contained
+ * in the classifier rule for which we need to match
+ */
UINT uiCountIPSrcAddresses = (UINT)pstClassifierRule->ucIPSourceAddressLength;
- if(0 == uiCountIPSrcAddresses)
+ if (uiCountIPSrcAddresses == 0)
return TRUE;
- //First Convert the Ip Address in the packet to Host Endian order
- for(uiIpv6AddIndex=0;uiIpv6AddIndex<uiIpv6AddrNoLongWords;uiIpv6AddIndex++)
- {
- aulSrcIP[uiIpv6AddIndex]=ntohl(pstIpv6Header->ulSrcIpAddress[uiIpv6AddIndex]);
- }
+ /* First Convert the Ip Address in the packet to Host Endian order */
+ for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++)
+ aulSrcIP[uiIpv6AddIndex] = ntohl(pstIpv6Header->ulSrcIpAddress[uiIpv6AddIndex]);
- for(uiLoopIndex=0;uiLoopIndex<uiCountIPSrcAddresses;uiLoopIndex+=uiIpv6AddrNoLongWords)
- {
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Src Ipv6 Address In Received Packet : \n ");
+ for (uiLoopIndex = 0; uiLoopIndex < uiCountIPSrcAddresses; uiLoopIndex += uiIpv6AddrNoLongWords) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "\n Src Ipv6 Address In Received Packet :\n ");
DumpIpv6Address(aulSrcIP);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Src Ipv6 Mask In Classifier Rule: \n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "\n Src Ipv6 Mask In Classifier Rule:\n");
DumpIpv6Address(&pstClassifierRule->stSrcIpAddress.ulIpv6Mask[uiLoopIndex]);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Src Ipv6 Address In Classifier Rule : \n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "\n Src Ipv6 Address In Classifier Rule :\n");
DumpIpv6Address(&pstClassifierRule->stSrcIpAddress.ulIpv6Addr[uiLoopIndex]);
- for(uiIpv6AddIndex=0;uiIpv6AddIndex<uiIpv6AddrNoLongWords;uiIpv6AddIndex++)
- {
- if((pstClassifierRule->stSrcIpAddress.ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] & aulSrcIP[uiIpv6AddIndex])
- != pstClassifierRule->stSrcIpAddress.ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex])
- {
- //Match failed for current Ipv6 Address.Try next Ipv6 Address
+ for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++) {
+ if ((pstClassifierRule->stSrcIpAddress.ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] & aulSrcIP[uiIpv6AddIndex])
+ != pstClassifierRule->stSrcIpAddress.ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex]) {
+ /*
+ * Match failed for current Ipv6 Address
+ * Try next Ipv6 Address
+ */
break;
}
- if(uiIpv6AddIndex == uiIpv6AddrNoLongWords-1)
- {
- //Match Found
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Ipv6 Src Ip Address Matched\n");
+ if (uiIpv6AddIndex == uiIpv6AddrNoLongWords-1) {
+ /* Match Found */
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL,
+ "Ipv6 Src Ip Address Matched\n");
return TRUE;
}
}
@@ -314,52 +344,56 @@ static BOOLEAN MatchSrcIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Head
return FALSE;
}
-static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Header *pstIpv6Header)
+static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,
+ IPV6Header *pstIpv6Header)
{
- UINT uiLoopIndex=0;
- UINT uiIpv6AddIndex=0;
- UINT uiIpv6AddrNoLongWords = 4;
+ UINT uiLoopIndex = 0;
+ UINT uiIpv6AddIndex = 0;
+ UINT uiIpv6AddrNoLongWords = 4;
ULONG aulDestIP[4];
- PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+ PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
/*
- //This is the no. of Destination Addresses ie Range of IP Addresses contained
- //in the classifier rule for which we need to match
- */
+ * This is the no. of Destination Addresses
+ * ie Range of IP Addresses contained in the classifier rule
+ * for which we need to match
+ */
UINT uiCountIPDestinationAddresses = (UINT)pstClassifierRule->ucIPDestinationAddressLength;
- if(0 == uiCountIPDestinationAddresses)
+ if (uiCountIPDestinationAddresses == 0)
return TRUE;
- //First Convert the Ip Address in the packet to Host Endian order
- for(uiIpv6AddIndex=0;uiIpv6AddIndex<uiIpv6AddrNoLongWords;uiIpv6AddIndex++)
- {
- aulDestIP[uiIpv6AddIndex]=ntohl(pstIpv6Header->ulDestIpAddress[uiIpv6AddIndex]);
- }
+ /* First Convert the Ip Address in the packet to Host Endian order */
+ for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++)
+ aulDestIP[uiIpv6AddIndex] = ntohl(pstIpv6Header->ulDestIpAddress[uiIpv6AddIndex]);
- for(uiLoopIndex=0;uiLoopIndex<uiCountIPDestinationAddresses;uiLoopIndex+=uiIpv6AddrNoLongWords)
- {
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Destination Ipv6 Address In Received Packet : \n ");
+ for (uiLoopIndex = 0; uiLoopIndex < uiCountIPDestinationAddresses; uiLoopIndex += uiIpv6AddrNoLongWords) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "\n Destination Ipv6 Address In Received Packet :\n ");
DumpIpv6Address(aulDestIP);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Destination Ipv6 Mask In Classifier Rule: \n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "\n Destination Ipv6 Mask In Classifier Rule :\n");
DumpIpv6Address(&pstClassifierRule->stDestIpAddress.ulIpv6Mask[uiLoopIndex]);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "\n Destination Ipv6 Address In Classifier Rule : \n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "\n Destination Ipv6 Address In Classifier Rule :\n");
DumpIpv6Address(&pstClassifierRule->stDestIpAddress.ulIpv6Addr[uiLoopIndex]);
- for(uiIpv6AddIndex=0;uiIpv6AddIndex<uiIpv6AddrNoLongWords;uiIpv6AddIndex++)
- {
- if((pstClassifierRule->stDestIpAddress.ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] & aulDestIP[uiIpv6AddIndex])
- != pstClassifierRule->stDestIpAddress.ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex])
- {
- //Match failed for current Ipv6 Address.Try next Ipv6 Address
+ for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++) {
+ if ((pstClassifierRule->stDestIpAddress.ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] & aulDestIP[uiIpv6AddIndex])
+ != pstClassifierRule->stDestIpAddress.ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex]) {
+ /*
+ * Match failed for current Ipv6 Address.
+ * Try next Ipv6 Address
+ */
break;
}
- if(uiIpv6AddIndex == uiIpv6AddrNoLongWords-1)
- {
- //Match Found
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Ipv6 Destination Ip Address Matched\n");
+ if (uiIpv6AddIndex == uiIpv6AddrNoLongWords-1) {
+ /* Match Found */
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG,
+ DBG_LVL_ALL,
+ "Ipv6 Destination Ip Address Matched\n");
return TRUE;
}
}
@@ -371,11 +405,11 @@ static BOOLEAN MatchDestIpv6Address(S_CLASSIFIER_RULE *pstClassifierRule,IPV6Hea
VOID DumpIpv6Address(ULONG *puIpv6Address)
{
UINT uiIpv6AddrNoLongWords = 4;
- UINT uiIpv6AddIndex=0;
- PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
- for(uiIpv6AddIndex=0;uiIpv6AddIndex<uiIpv6AddrNoLongWords;uiIpv6AddIndex++)
- {
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, ":%lx",puIpv6Address[uiIpv6AddIndex]);
+ UINT uiIpv6AddIndex = 0;
+ PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+ for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++) {
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ ":%lx", puIpv6Address[uiIpv6AddIndex]);
}
}
@@ -383,22 +417,35 @@ VOID DumpIpv6Address(ULONG *puIpv6Address)
static VOID DumpIpv6Header(IPV6Header *pstIpv6Header)
{
UCHAR ucVersion;
- UCHAR ucPrio ;
- PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "----Ipv6 Header---");
+ UCHAR ucPrio;
+ PMINI_ADAPTER Adapter = GET_BCM_ADAPTER(gblpnetdev);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "----Ipv6 Header---");
ucVersion = pstIpv6Header->ucVersionPrio & 0xf0;
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Version : %x \n",ucVersion);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "Version : %x\n", ucVersion);
ucPrio = pstIpv6Header->ucVersionPrio & 0x0f;
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Priority : %x \n",ucPrio);
- //BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Flow Label : %x \n",(pstIpv6Header->ucVersionPrio &0xf0);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Payload Length : %x \n",ntohs(pstIpv6Header->usPayloadLength));
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Next Header : %x \n",pstIpv6Header->ucNextHeader);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Hop Limit : %x \n",pstIpv6Header->ucHopLimit);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Src Address :\n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "Priority : %x\n", ucPrio);
+ /*
+ * BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ * "Flow Label : %x\n",(pstIpv6Header->ucVersionPrio &0xf0);
+ */
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "Payload Length : %x\n",
+ ntohs(pstIpv6Header->usPayloadLength));
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "Next Header : %x\n", pstIpv6Header->ucNextHeader);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "Hop Limit : %x\n", pstIpv6Header->ucHopLimit);
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "Src Address :\n");
DumpIpv6Address(pstIpv6Header->ulSrcIpAddress);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "Dest Address :\n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "Dest Address :\n");
DumpIpv6Address(pstIpv6Header->ulDestIpAddress);
- BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, "----Ipv6 Header End---");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL,
+ "----Ipv6 Header End---");
}
diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c
index c7725e141fd5..8223a6913fc5 100644
--- a/drivers/staging/bcm/Misc.c
+++ b/drivers/staging/bcm/Misc.c
@@ -835,7 +835,7 @@ int reset_card_proc(PMINI_ADAPTER ps_adapter)
Bcm_kill_all_URBs(psIntfAdapter);
/* Reset the UMA-B Device */
if (ps_adapter->chip_id >= T3LPB) {
- BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Reseting UMA-B\n");
+ BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Resetting UMA-B\n");
retval = usb_reset_device(psIntfAdapter->udev);
psIntfAdapter->psAdapter->StopAllXaction = FALSE;
diff --git a/drivers/staging/ccg/Kconfig b/drivers/staging/ccg/Kconfig
new file mode 100644
index 000000000000..ff05e52392bf
--- /dev/null
+++ b/drivers/staging/ccg/Kconfig
@@ -0,0 +1,20 @@
+if USB_GADGET
+
+config USB_G_CCG
+ tristate "Configurable Composite Gadget (STAGING)"
+ depends on STAGING && !USB_ZERO && !USB_ZERO_HNPTEST && !USB_AUDIO && !GADGET_UAC1 && !USB_ETH && !USB_ETH_RNDIS && !USB_ETH_EEM && !USB_G_NCM && !USB_GADGETFS && !USB_FUNCTIONFS && !USB_FUNCTIONFS_ETH && !USB_FUNCTIONFS_RNDIS && !USB_FUNCTIONFS_GENERIC && !USB_FILE_STORAGE && !USB_FILE_STORAGE_TEST && !USB_MASS_STORAGE && !USB_G_SERIAL && !USB_MIDI_GADGET && !USB_G_PRINTER && !USB_CDC_COMPOSITE && !USB_G_NOKIA && !USB_G_ACM_MS && !USB_G_MULTI && !USB_G_MULTI_RNDIS && !USB_G_MULTI_CDC && !USB_G_HID && !USB_G_DBGP && !USB_G_WEBCAM
+ help
+ The Configurable Composite Gadget supports multiple USB
+ functions: acm, mass storage, rndis and FunctionFS.
+ Each function can be configured and enabled/disabled
+ dynamically from userspace through a sysfs interface.
+
+ In order to compile this (either as a module or built-in),
+ "USB Gadget Drivers" and anything under it must not be
+ selected compiled-in in
+ Device Drivers->USB Support->USB Gadget Support.
+ However, you can say "M" there, if you do, the
+ Configurable Composite Gadget can be compiled "M" only
+ or not at all.
+
+endif # USB_GADGET
diff --git a/drivers/staging/ccg/Makefile b/drivers/staging/ccg/Makefile
new file mode 100644
index 000000000000..693da637a6d8
--- /dev/null
+++ b/drivers/staging/ccg/Makefile
@@ -0,0 +1,4 @@
+g_ccg-y := ccg.o
+ccflags-y += -Idrivers/usb/gadget
+
+obj-$(CONFIG_USB_G_CCG) += g_ccg.o
diff --git a/drivers/staging/ccg/TODO b/drivers/staging/ccg/TODO
new file mode 100644
index 000000000000..18612fe70171
--- /dev/null
+++ b/drivers/staging/ccg/TODO
@@ -0,0 +1,6 @@
+TODO:
+ - change configuration interface from sysfs to configfs
+
+Please send patches to Greg Kroah-Hartmann <gregkh@linuxfoundation.org>,
+Andrzej Pietrasiewicz <andrzej.p@samsung.com>, and
+Cc: Mike Lockwood <lockwood@android.com>
diff --git a/drivers/staging/ccg/ccg.c b/drivers/staging/ccg/ccg.c
new file mode 100644
index 000000000000..a5b36a97598d
--- /dev/null
+++ b/drivers/staging/ccg/ccg.c
@@ -0,0 +1,1299 @@
+/*
+ * Configurable Composite Gadget
+ *
+ * Initially contributed as "Android Composite Gdaget" by:
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ * Benoit Goby <benoit@android.com>
+ *
+ * Tailoring it to become a generic Configurable Composite Gadget is
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/utsname.h>
+#include <linux/platform_device.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/composite.h>
+#include <linux/usb/gadget.h>
+
+#include "gadget_chips.h"
+
+/*
+ * Kbuild is not very cooperative with respect to linking separately
+ * compiled library objects into one module. So for now we won't use
+ * separate compilation ... ensuring init/exit sections work to shrink
+ * the runtime footprint, and giving us at least some parts of what
+ * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
+ */
+#include "../../usb/gadget/usbstring.c"
+#include "../../usb/gadget/config.c"
+#include "../../usb/gadget/epautoconf.c"
+#include "../../usb/gadget/composite.c"
+
+#include "../../usb/gadget/f_mass_storage.c"
+#include "../../usb/gadget/u_serial.c"
+#include "../../usb/gadget/f_acm.c"
+#define USB_ETH_RNDIS y
+#include "../../usb/gadget/f_rndis.c"
+#include "../../usb/gadget/rndis.c"
+#include "../../usb/gadget/u_ether.c"
+#include "../../usb/gadget/f_fs.c"
+
+MODULE_AUTHOR("Mike Lockwood, Andrzej Pietrasiewicz");
+MODULE_DESCRIPTION("Configurable Composite USB Gadget");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+
+static const char longname[] = "Configurable Composite Gadget";
+
+/* Default vendor and product IDs, overridden by userspace */
+#define VENDOR_ID 0x1d6b /* Linux Foundation */
+#define PRODUCT_ID 0x0107
+#define GFS_MAX_DEVS 10
+
+struct ccg_usb_function {
+ char *name;
+ void *config;
+
+ struct device *dev;
+ char *dev_name;
+ struct device_attribute **attributes;
+
+ /* for ccg_dev.enabled_functions */
+ struct list_head enabled_list;
+
+ /* Optional: initialization during gadget bind */
+ int (*init)(struct ccg_usb_function *, struct usb_composite_dev *);
+ /* Optional: cleanup during gadget unbind */
+ void (*cleanup)(struct ccg_usb_function *);
+
+ int (*bind_config)(struct ccg_usb_function *,
+ struct usb_configuration *);
+
+ /* Optional: called when the configuration is removed */
+ void (*unbind_config)(struct ccg_usb_function *,
+ struct usb_configuration *);
+ /* Optional: handle ctrl requests before the device is configured */
+ int (*ctrlrequest)(struct ccg_usb_function *,
+ struct usb_composite_dev *,
+ const struct usb_ctrlrequest *);
+};
+
+struct ffs_obj {
+ const char *name;
+ bool mounted;
+ bool desc_ready;
+ bool used;
+ struct ffs_data *ffs_data;
+};
+
+struct ccg_dev {
+ struct ccg_usb_function **functions;
+ struct list_head enabled_functions;
+ struct usb_composite_dev *cdev;
+ struct device *dev;
+
+ bool enabled;
+ struct mutex mutex;
+ bool connected;
+ bool sw_connected;
+ struct work_struct work;
+
+ unsigned int max_func_num;
+ unsigned int func_num;
+ struct ffs_obj ffs_tab[GFS_MAX_DEVS];
+};
+
+static struct class *ccg_class;
+static struct ccg_dev *_ccg_dev;
+static int ccg_bind_config(struct usb_configuration *c);
+static void ccg_unbind_config(struct usb_configuration *c);
+
+static char func_names_buf[256];
+
+static struct usb_device_descriptor device_desc = {
+ .bLength = sizeof(device_desc),
+ .bDescriptorType = USB_DT_DEVICE,
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
+ .bDeviceClass = USB_CLASS_PER_INTERFACE,
+ .idVendor = __constant_cpu_to_le16(VENDOR_ID),
+ .idProduct = __constant_cpu_to_le16(PRODUCT_ID),
+ .bcdDevice = __constant_cpu_to_le16(0xffff),
+ .bNumConfigurations = 1,
+};
+
+static struct usb_configuration ccg_config_driver = {
+ .label = "ccg",
+ .unbind = ccg_unbind_config,
+ .bConfigurationValue = 1,
+ .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+ .bMaxPower = 0xFA, /* 500ma */
+};
+
+static void ccg_work(struct work_struct *data)
+{
+ struct ccg_dev *dev = container_of(data, struct ccg_dev, work);
+ struct usb_composite_dev *cdev = dev->cdev;
+ static char *disconnected[2] = { "USB_STATE=DISCONNECTED", NULL };
+ static char *connected[2] = { "USB_STATE=CONNECTED", NULL };
+ static char *configured[2] = { "USB_STATE=CONFIGURED", NULL };
+ char **uevent_envp = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cdev->lock, flags);
+ if (cdev->config)
+ uevent_envp = configured;
+ else if (dev->connected != dev->sw_connected)
+ uevent_envp = dev->connected ? connected : disconnected;
+ dev->sw_connected = dev->connected;
+ spin_unlock_irqrestore(&cdev->lock, flags);
+
+ if (uevent_envp) {
+ kobject_uevent_env(&dev->dev->kobj, KOBJ_CHANGE, uevent_envp);
+ pr_info("%s: sent uevent %s\n", __func__, uevent_envp[0]);
+ } else {
+ pr_info("%s: did not send uevent (%d %d %p)\n", __func__,
+ dev->connected, dev->sw_connected, cdev->config);
+ }
+}
+
+
+/*-------------------------------------------------------------------------*/
+/* Supported functions initialization */
+
+static struct ffs_obj *functionfs_find_dev(struct ccg_dev *dev,
+ const char *dev_name)
+{
+ int i;
+
+ for (i = 0; i < dev->max_func_num; i++)
+ if (strcmp(dev->ffs_tab[i].name, dev_name) == 0)
+ return &dev->ffs_tab[i];
+
+ return NULL;
+}
+
+static bool functionfs_all_ready(struct ccg_dev *dev)
+{
+ int i;
+
+ for (i = 0; i < dev->max_func_num; i++)
+ if (dev->ffs_tab[i].used && !dev->ffs_tab[i].desc_ready)
+ return false;
+
+ return true;
+}
+
+static int functionfs_ready_callback(struct ffs_data *ffs)
+{
+ struct ffs_obj *ffs_obj;
+ int ret;
+
+ mutex_lock(&_ccg_dev->mutex);
+
+ ffs_obj = ffs->private_data;
+ if (!ffs_obj) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (WARN_ON(ffs_obj->desc_ready)) {
+ ret = -EBUSY;
+ goto done;
+ }
+ ffs_obj->ffs_data = ffs;
+
+ if (functionfs_all_ready(_ccg_dev)) {
+ ret = -EBUSY;
+ goto done;
+ }
+ ffs_obj->desc_ready = true;
+
+done:
+ mutex_unlock(&_ccg_dev->mutex);
+ return ret;
+}
+
+static void reset_usb(struct ccg_dev *dev)
+{
+ /* Cancel pending control requests */
+ usb_ep_dequeue(dev->cdev->gadget->ep0, dev->cdev->req);
+ usb_remove_config(dev->cdev, &ccg_config_driver);
+ dev->enabled = false;
+ usb_gadget_disconnect(dev->cdev->gadget);
+}
+
+static void functionfs_closed_callback(struct ffs_data *ffs)
+{
+ struct ffs_obj *ffs_obj;
+
+ mutex_lock(&_ccg_dev->mutex);
+
+ ffs_obj = ffs->private_data;
+ if (!ffs_obj)
+ goto done;
+
+ ffs_obj->desc_ready = false;
+
+ if (_ccg_dev->enabled)
+ reset_usb(_ccg_dev);
+
+done:
+ mutex_unlock(&_ccg_dev->mutex);
+}
+
+static void *functionfs_acquire_dev_callback(const char *dev_name)
+{
+ struct ffs_obj *ffs_dev;
+
+ mutex_lock(&_ccg_dev->mutex);
+
+ ffs_dev = functionfs_find_dev(_ccg_dev, dev_name);
+ if (!ffs_dev) {
+ ffs_dev = ERR_PTR(-ENODEV);
+ goto done;
+ }
+
+ if (ffs_dev->mounted) {
+ ffs_dev = ERR_PTR(-EBUSY);
+ goto done;
+ }
+ ffs_dev->mounted = true;
+
+done:
+ mutex_unlock(&_ccg_dev->mutex);
+ return ffs_dev;
+}
+
+static void functionfs_release_dev_callback(struct ffs_data *ffs_data)
+{
+ struct ffs_obj *ffs_dev;
+
+ mutex_lock(&_ccg_dev->mutex);
+
+ ffs_dev = ffs_data->private_data;
+ if (ffs_dev)
+ ffs_dev->mounted = false;
+
+ mutex_unlock(&_ccg_dev->mutex);
+}
+
+static int functionfs_function_init(struct ccg_usb_function *f,
+ struct usb_composite_dev *cdev)
+{
+ return functionfs_init();
+}
+
+static void functionfs_function_cleanup(struct ccg_usb_function *f)
+{
+ functionfs_cleanup();
+}
+
+static int functionfs_function_bind_config(struct ccg_usb_function *f,
+ struct usb_configuration *c)
+{
+ struct ccg_dev *dev = _ccg_dev;
+ int i, ret;
+
+ for (i = dev->max_func_num; i--; ) {
+ if (!dev->ffs_tab[i].used)
+ continue;
+ ret = functionfs_bind(dev->ffs_tab[i].ffs_data, c->cdev);
+ if (unlikely(ret < 0)) {
+ while (++i < dev->max_func_num)
+ functionfs_unbind(dev->ffs_tab[i].ffs_data);
+ return ret;
+ }
+ }
+
+ for (i = dev->max_func_num; i--; ) {
+ if (!dev->ffs_tab[i].used)
+ continue;
+ ret = functionfs_bind_config(c->cdev, c,
+ dev->ffs_tab[i].ffs_data);
+ if (unlikely(ret < 0))
+ return ret;
+ }
+
+ return 0;
+}
+
+static void functionfs_function_unbind_config(struct ccg_usb_function *f,
+ struct usb_configuration *c)
+{
+ struct ccg_dev *dev = _ccg_dev;
+ int i;
+
+ for (i = dev->max_func_num; i--; )
+ if (dev->ffs_tab[i].ffs_data)
+ functionfs_unbind(dev->ffs_tab[i].ffs_data);
+}
+
+static ssize_t functionfs_user_functions_show(struct device *_dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ccg_dev *dev = _ccg_dev;
+ char *buff = buf;
+ int i;
+
+ mutex_lock(&dev->mutex);
+
+ for (i = 0; i < dev->max_func_num; i++)
+ buff += snprintf(buff, PAGE_SIZE + buf - buff, "%s,",
+ dev->ffs_tab[i].name);
+
+ mutex_unlock(&dev->mutex);
+
+ if (buff != buf)
+ *(buff - 1) = '\n';
+ return buff - buf;
+}
+
+static ssize_t functionfs_user_functions_store(struct device *_dev,
+ struct device_attribute *attr,
+ const char *buff, size_t size)
+{
+ struct ccg_dev *dev = _ccg_dev;
+ char *name, *b;
+ ssize_t ret = size;
+ int i;
+
+ buff = skip_spaces(buff);
+ if (!*buff)
+ return -EINVAL;
+
+ mutex_lock(&dev->mutex);
+
+ if (dev->enabled) {
+ ret = -EBUSY;
+ goto end;
+ }
+
+ for (i = 0; i < dev->max_func_num; i++)
+ if (dev->ffs_tab[i].mounted) {
+ ret = -EBUSY;
+ goto end;
+ }
+
+ strlcpy(func_names_buf, buff, sizeof(func_names_buf));
+ b = strim(func_names_buf);
+
+ /* replace the list of functions */
+ dev->max_func_num = 0;
+ while (b) {
+ name = strsep(&b, ",");
+ if (dev->max_func_num == GFS_MAX_DEVS) {
+ ret = -ENOSPC;
+ goto end;
+ }
+ if (functionfs_find_dev(dev, name)) {
+ ret = -EEXIST;
+ continue;
+ }
+ dev->ffs_tab[dev->max_func_num++].name = name;
+ }
+
+end:
+ mutex_unlock(&dev->mutex);
+ return ret;
+}
+
+static DEVICE_ATTR(user_functions, S_IRUGO | S_IWUSR,
+ functionfs_user_functions_show,
+ functionfs_user_functions_store);
+
+static ssize_t functionfs_max_user_functions_show(struct device *_dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d", GFS_MAX_DEVS);
+}
+
+static DEVICE_ATTR(max_user_functions, S_IRUGO,
+ functionfs_max_user_functions_show, NULL);
+
+static struct device_attribute *functionfs_function_attributes[] = {
+ &dev_attr_user_functions,
+ &dev_attr_max_user_functions,
+ NULL
+};
+
+static struct ccg_usb_function functionfs_function = {
+ .name = "fs",
+ .init = functionfs_function_init,
+ .cleanup = functionfs_function_cleanup,
+ .bind_config = functionfs_function_bind_config,
+ .unbind_config = functionfs_function_unbind_config,
+ .attributes = functionfs_function_attributes,
+};
+
+#define MAX_ACM_INSTANCES 4
+struct acm_function_config {
+ int instances;
+};
+
+static int
+acm_function_init(struct ccg_usb_function *f, struct usb_composite_dev *cdev)
+{
+ f->config = kzalloc(sizeof(struct acm_function_config), GFP_KERNEL);
+ if (!f->config)
+ return -ENOMEM;
+
+ return gserial_setup(cdev->gadget, MAX_ACM_INSTANCES);
+}
+
+static void acm_function_cleanup(struct ccg_usb_function *f)
+{
+ gserial_cleanup();
+ kfree(f->config);
+ f->config = NULL;
+}
+
+static int
+acm_function_bind_config(struct ccg_usb_function *f,
+ struct usb_configuration *c)
+{
+ int i;
+ int ret = 0;
+ struct acm_function_config *config = f->config;
+
+ for (i = 0; i < config->instances; i++) {
+ ret = acm_bind_config(c, i);
+ if (ret) {
+ pr_err("Could not bind acm%u config\n", i);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static ssize_t acm_instances_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ccg_usb_function *f = dev_get_drvdata(dev);
+ struct acm_function_config *config = f->config;
+ return sprintf(buf, "%d\n", config->instances);
+}
+
+static ssize_t acm_instances_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct ccg_usb_function *f = dev_get_drvdata(dev);
+ struct acm_function_config *config = f->config;
+ int value;
+ int ret = 0;
+
+ ret = kstrtoint(buf, 10, &value);
+ if (ret)
+ return ret;
+
+ if (value > MAX_ACM_INSTANCES)
+ return -EINVAL;
+
+ config->instances = value;
+
+ return size;
+}
+
+static DEVICE_ATTR(instances, S_IRUGO | S_IWUSR, acm_instances_show,
+ acm_instances_store);
+static struct device_attribute *acm_function_attributes[] = {
+ &dev_attr_instances,
+ NULL
+};
+
+static struct ccg_usb_function acm_function = {
+ .name = "acm",
+ .init = acm_function_init,
+ .cleanup = acm_function_cleanup,
+ .bind_config = acm_function_bind_config,
+ .attributes = acm_function_attributes,
+};
+
+struct rndis_function_config {
+ u8 ethaddr[ETH_ALEN];
+ u32 vendorID;
+ char manufacturer[256];
+ /* "Wireless" RNDIS; auto-detected by Windows */
+ bool wceis;
+};
+
+static int rndis_function_init(struct ccg_usb_function *f,
+ struct usb_composite_dev *cdev)
+{
+ f->config = kzalloc(sizeof(struct rndis_function_config), GFP_KERNEL);
+ if (!f->config)
+ return -ENOMEM;
+ return 0;
+}
+
+static void rndis_function_cleanup(struct ccg_usb_function *f)
+{
+ kfree(f->config);
+ f->config = NULL;
+}
+
+static int rndis_function_bind_config(struct ccg_usb_function *f,
+ struct usb_configuration *c)
+{
+ int ret;
+ struct rndis_function_config *rndis = f->config;
+
+ if (!rndis) {
+ pr_err("%s: rndis_pdata\n", __func__);
+ return -1;
+ }
+
+ pr_info("%s MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", __func__,
+ rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2],
+ rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]);
+
+ ret = gether_setup_name(c->cdev->gadget, rndis->ethaddr, "rndis");
+ if (ret) {
+ pr_err("%s: gether_setup failed\n", __func__);
+ return ret;
+ }
+
+ if (rndis->wceis) {
+ /* "Wireless" RNDIS; auto-detected by Windows */
+ rndis_iad_descriptor.bFunctionClass =
+ USB_CLASS_WIRELESS_CONTROLLER;
+ rndis_iad_descriptor.bFunctionSubClass = 0x01;
+ rndis_iad_descriptor.bFunctionProtocol = 0x03;
+ rndis_control_intf.bInterfaceClass =
+ USB_CLASS_WIRELESS_CONTROLLER;
+ rndis_control_intf.bInterfaceSubClass = 0x01;
+ rndis_control_intf.bInterfaceProtocol = 0x03;
+ }
+
+ return rndis_bind_config_vendor(c, rndis->ethaddr, rndis->vendorID,
+ rndis->manufacturer);
+}
+
+static void rndis_function_unbind_config(struct ccg_usb_function *f,
+ struct usb_configuration *c)
+{
+ gether_cleanup();
+}
+
+static ssize_t rndis_manufacturer_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ccg_usb_function *f = dev_get_drvdata(dev);
+ struct rndis_function_config *config = f->config;
+ return sprintf(buf, "%s\n", config->manufacturer);
+}
+
+static ssize_t rndis_manufacturer_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct ccg_usb_function *f = dev_get_drvdata(dev);
+ struct rndis_function_config *config = f->config;
+
+ if (size >= sizeof(config->manufacturer))
+ return -EINVAL;
+ memcpy(config->manufacturer, buf, size);
+ config->manufacturer[size] = 0;
+
+ return size;
+}
+
+static DEVICE_ATTR(manufacturer, S_IRUGO | S_IWUSR, rndis_manufacturer_show,
+ rndis_manufacturer_store);
+
+static ssize_t rndis_wceis_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ccg_usb_function *f = dev_get_drvdata(dev);
+ struct rndis_function_config *config = f->config;
+ return sprintf(buf, "%d\n", config->wceis);
+}
+
+static ssize_t rndis_wceis_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct ccg_usb_function *f = dev_get_drvdata(dev);
+ struct rndis_function_config *config = f->config;
+ int value;
+ int ret;
+
+ ret = kstrtoint(buf, 10, &value);
+ if (ret)
+ return ret;
+
+ config->wceis = value;
+
+ return size;
+}
+
+static DEVICE_ATTR(wceis, S_IRUGO | S_IWUSR, rndis_wceis_show,
+ rndis_wceis_store);
+
+static ssize_t rndis_ethaddr_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ccg_usb_function *f = dev_get_drvdata(dev);
+ struct rndis_function_config *rndis = f->config;
+ return sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n",
+ rndis->ethaddr[0], rndis->ethaddr[1], rndis->ethaddr[2],
+ rndis->ethaddr[3], rndis->ethaddr[4], rndis->ethaddr[5]);
+}
+
+static ssize_t rndis_ethaddr_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct ccg_usb_function *f = dev_get_drvdata(dev);
+ struct rndis_function_config *rndis = f->config;
+ unsigned char tmp[6];
+
+ if (sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+ tmp + 0, tmp + 1, tmp + 2, tmp + 3, tmp + 4, tmp + 5) !=
+ ETH_ALEN)
+ return -EINVAL;
+
+ memcpy(rndis->ethaddr, tmp, ETH_ALEN);
+
+ return ETH_ALEN;
+
+}
+
+static DEVICE_ATTR(ethaddr, S_IRUGO | S_IWUSR, rndis_ethaddr_show,
+ rndis_ethaddr_store);
+
+static ssize_t rndis_vendorID_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ccg_usb_function *f = dev_get_drvdata(dev);
+ struct rndis_function_config *config = f->config;
+ return sprintf(buf, "%04x\n", config->vendorID);
+}
+
+static ssize_t rndis_vendorID_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct ccg_usb_function *f = dev_get_drvdata(dev);
+ struct rndis_function_config *config = f->config;
+ int value;
+ int ret;
+
+ ret = kstrtou32(buf, 16, &value);
+ if (ret)
+ return ret;
+
+ config->vendorID = value;
+
+ return size;
+}
+
+static DEVICE_ATTR(vendorID, S_IRUGO | S_IWUSR, rndis_vendorID_show,
+ rndis_vendorID_store);
+
+static struct device_attribute *rndis_function_attributes[] = {
+ &dev_attr_manufacturer,
+ &dev_attr_wceis,
+ &dev_attr_ethaddr,
+ &dev_attr_vendorID,
+ NULL
+};
+
+static struct ccg_usb_function rndis_function = {
+ .name = "rndis",
+ .init = rndis_function_init,
+ .cleanup = rndis_function_cleanup,
+ .bind_config = rndis_function_bind_config,
+ .unbind_config = rndis_function_unbind_config,
+ .attributes = rndis_function_attributes,
+};
+
+static int mass_storage_function_init(struct ccg_usb_function *f,
+ struct usb_composite_dev *cdev)
+{
+ struct fsg_config fsg;
+ struct fsg_common *common;
+ int err;
+
+ memset(&fsg, 0, sizeof fsg);
+ fsg.nluns = 1;
+ fsg.luns[0].removable = 1;
+ fsg.vendor_name = iManufacturer;
+ fsg.product_name = iProduct;
+
+ common = fsg_common_init(NULL, cdev, &fsg);
+ if (IS_ERR(common))
+ return PTR_ERR(common);
+
+ err = sysfs_create_link(&f->dev->kobj,
+ &common->luns[0].dev.kobj,
+ "lun");
+ if (err) {
+ fsg_common_put(common);
+ return err;
+ }
+
+ f->config = common;
+ return 0;
+}
+
+static void mass_storage_function_cleanup(struct ccg_usb_function *f)
+{
+ fsg_common_put(f->config);
+ f->config = NULL;
+}
+
+static int mass_storage_function_bind_config(struct ccg_usb_function *f,
+ struct usb_configuration *c)
+{
+ struct fsg_common *common = f->config;
+ return fsg_bind_config(c->cdev, c, common);
+}
+
+static struct ccg_usb_function mass_storage_function = {
+ .name = "mass_storage",
+ .init = mass_storage_function_init,
+ .cleanup = mass_storage_function_cleanup,
+ .bind_config = mass_storage_function_bind_config,
+};
+
+static struct ccg_usb_function *supported_functions[] = {
+ &functionfs_function,
+ &acm_function,
+ &rndis_function,
+ &mass_storage_function,
+ NULL
+};
+
+
+static int ccg_init_functions(struct ccg_usb_function **functions,
+ struct usb_composite_dev *cdev)
+{
+ struct ccg_dev *dev = _ccg_dev;
+ struct ccg_usb_function *f;
+ struct device_attribute **attrs;
+ struct device_attribute *attr;
+ int err;
+ int index = 0;
+
+ for (; (f = *functions++); index++) {
+ f->dev_name = kasprintf(GFP_KERNEL, "f_%s", f->name);
+ if (!f->dev_name) {
+ pr_err("%s: Failed to alloc name %s", __func__,
+ f->name);
+ err = -ENOMEM;
+ goto err_alloc;
+ }
+ f->dev = device_create(ccg_class, dev->dev,
+ MKDEV(0, index), f, f->dev_name);
+ if (IS_ERR(f->dev)) {
+ pr_err("%s: Failed to create dev %s", __func__,
+ f->dev_name);
+ err = PTR_ERR(f->dev);
+ f->dev = NULL;
+ goto err_create;
+ }
+
+ if (f->init) {
+ err = f->init(f, cdev);
+ if (err) {
+ pr_err("%s: Failed to init %s", __func__,
+ f->name);
+ goto err_out;
+ }
+ }
+
+ attrs = f->attributes;
+ if (attrs) {
+ while ((attr = *attrs++) && !err)
+ err = device_create_file(f->dev, attr);
+ }
+ if (err) {
+ pr_err("%s: Failed to create function %s attributes",
+ __func__, f->name);
+ goto err_uninit;
+ }
+ }
+ return 0;
+
+err_uninit:
+ if (f->cleanup)
+ f->cleanup(f);
+err_out:
+ device_destroy(ccg_class, f->dev->devt);
+ f->dev = NULL;
+err_create:
+ kfree(f->dev_name);
+err_alloc:
+ return err;
+}
+
+static void ccg_cleanup_functions(struct ccg_usb_function **functions)
+{
+ struct ccg_usb_function *f;
+
+ while (*functions) {
+ f = *functions++;
+
+ if (f->dev) {
+ if (f->cleanup)
+ f->cleanup(f);
+ device_destroy(ccg_class, f->dev->devt);
+ kfree(f->dev_name);
+ }
+ }
+}
+
+static int ccg_bind_enabled_functions(struct ccg_dev *dev,
+ struct usb_configuration *c)
+{
+ struct ccg_usb_function *f;
+ int ret;
+
+ list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
+ ret = f->bind_config(f, c);
+ if (ret) {
+ pr_err("%s: %s failed", __func__, f->name);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static void ccg_unbind_enabled_functions(struct ccg_dev *dev,
+ struct usb_configuration *c)
+{
+ struct ccg_usb_function *f;
+
+ list_for_each_entry(f, &dev->enabled_functions, enabled_list)
+ if (f->unbind_config)
+ f->unbind_config(f, c);
+}
+
+static int ccg_enable_function(struct ccg_dev *dev, char *name)
+{
+ struct ccg_usb_function **functions = dev->functions;
+ struct ccg_usb_function *f;
+ while ((f = *functions++)) {
+ if (!strcmp(name, f->name)) {
+ list_add_tail(&f->enabled_list,
+ &dev->enabled_functions);
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+/*-------------------------------------------------------------------------*/
+/* /sys/class/ccg_usb/ccg%d/ interface */
+
+static ssize_t
+functions_show(struct device *pdev, struct device_attribute *attr, char *buf)
+{
+ struct ccg_dev *dev = dev_get_drvdata(pdev);
+ struct ccg_usb_function *f;
+ char *buff = buf;
+ int i;
+
+ mutex_lock(&dev->mutex);
+
+ list_for_each_entry(f, &dev->enabled_functions, enabled_list)
+ buff += sprintf(buff, "%s,", f->name);
+ for (i = 0; i < dev->max_func_num; i++)
+ if (dev->ffs_tab[i].used)
+ buff += sprintf(buff, "%s", dev->ffs_tab[i].name);
+
+ mutex_unlock(&dev->mutex);
+
+ if (buff != buf)
+ *(buff-1) = '\n';
+ return buff - buf;
+}
+
+static ssize_t
+functions_store(struct device *pdev, struct device_attribute *attr,
+ const char *buff, size_t size)
+{
+ struct ccg_dev *dev = dev_get_drvdata(pdev);
+ char *name;
+ char buf[256], *b;
+ int err, i;
+ bool functionfs_enabled;
+
+ buff = skip_spaces(buff);
+ if (!*buff)
+ return -EINVAL;
+
+ mutex_lock(&dev->mutex);
+
+ if (dev->enabled) {
+ mutex_unlock(&dev->mutex);
+ return -EBUSY;
+ }
+
+ INIT_LIST_HEAD(&dev->enabled_functions);
+ functionfs_enabled = false;
+ for (i = 0; i < dev->max_func_num; i++)
+ dev->ffs_tab[i].used = false;
+
+ strlcpy(buf, buff, sizeof(buf));
+ b = strim(buf);
+
+ while (b) {
+ struct ffs_obj *user_func;
+
+ name = strsep(&b, ",");
+ /* handle FunctionFS implicitly */
+ if (!strcmp(name, functionfs_function.name)) {
+ pr_err("ccg_usb: Cannot explicitly enable '%s'", name);
+ continue;
+ }
+ user_func = functionfs_find_dev(dev, name);
+ if (user_func)
+ name = functionfs_function.name;
+ err = 0;
+ if (!user_func || !functionfs_enabled)
+ err = ccg_enable_function(dev, name);
+ if (err)
+ pr_err("ccg_usb: Cannot enable '%s'", name);
+ else if (user_func) {
+ user_func->used = true;
+ dev->func_num++;
+ functionfs_enabled = true;
+ }
+ }
+
+ mutex_unlock(&dev->mutex);
+
+ return size;
+}
+
+static ssize_t enable_show(struct device *pdev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ccg_dev *dev = dev_get_drvdata(pdev);
+ return sprintf(buf, "%d\n", dev->enabled);
+}
+
+static ssize_t enable_store(struct device *pdev, struct device_attribute *attr,
+ const char *buff, size_t size)
+{
+ struct ccg_dev *dev = dev_get_drvdata(pdev);
+ struct usb_composite_dev *cdev = dev->cdev;
+ int enabled = 0;
+
+ mutex_lock(&dev->mutex);
+ sscanf(buff, "%d", &enabled);
+ if (enabled && dev->func_num && !functionfs_all_ready(dev)) {
+ mutex_unlock(&dev->mutex);
+ return -ENODEV;
+ }
+
+ if (enabled && !dev->enabled) {
+ int ret;
+
+ cdev->next_string_id = 0;
+ /*
+ * Update values in composite driver's copy of
+ * device descriptor.
+ */
+ cdev->desc.bDeviceClass = device_desc.bDeviceClass;
+ cdev->desc.bDeviceSubClass = device_desc.bDeviceSubClass;
+ cdev->desc.bDeviceProtocol = device_desc.bDeviceProtocol;
+ cdev->desc.idVendor = idVendor;
+ cdev->desc.idProduct = idProduct;
+ cdev->desc.bcdDevice = bcdDevice;
+
+ usb_add_config(cdev, &ccg_config_driver, ccg_bind_config);
+ dev->enabled = true;
+ ret = usb_gadget_connect(cdev->gadget);
+ if (ret) {
+ dev->enabled = false;
+ usb_remove_config(cdev, &ccg_config_driver);
+ }
+ } else if (!enabled && dev->enabled) {
+ reset_usb(dev);
+ } else {
+ pr_err("ccg_usb: already %s\n",
+ dev->enabled ? "enabled" : "disabled");
+ }
+
+ mutex_unlock(&dev->mutex);
+ return size;
+}
+
+static ssize_t state_show(struct device *pdev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ccg_dev *dev = dev_get_drvdata(pdev);
+ struct usb_composite_dev *cdev = dev->cdev;
+ char *state = "DISCONNECTED";
+ unsigned long flags;
+
+ if (!cdev)
+ goto out;
+
+ spin_lock_irqsave(&cdev->lock, flags);
+ if (cdev->config)
+ state = "CONFIGURED";
+ else if (dev->connected)
+ state = "CONNECTED";
+ spin_unlock_irqrestore(&cdev->lock, flags);
+out:
+ return sprintf(buf, "%s\n", state);
+}
+
+#define DESCRIPTOR_ATTR(field, format_string) \
+static ssize_t \
+field ## _show(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ return sprintf(buf, format_string, device_desc.field); \
+} \
+static ssize_t \
+field ## _store(struct device *dev, struct device_attribute *attr, \
+ const char *buf, size_t size) \
+{ \
+ int value; \
+ if (sscanf(buf, format_string, &value) == 1) { \
+ device_desc.field = value; \
+ return size; \
+ } \
+ return -1; \
+} \
+static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, field ## _show, field ## _store);
+
+DESCRIPTOR_ATTR(bDeviceClass, "%d\n")
+DESCRIPTOR_ATTR(bDeviceSubClass, "%d\n")
+DESCRIPTOR_ATTR(bDeviceProtocol, "%d\n")
+
+static DEVICE_ATTR(functions, S_IRUGO | S_IWUSR, functions_show,
+ functions_store);
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store);
+static DEVICE_ATTR(state, S_IRUGO, state_show, NULL);
+
+static struct device_attribute *ccg_usb_attributes[] = {
+ &dev_attr_bDeviceClass,
+ &dev_attr_bDeviceSubClass,
+ &dev_attr_bDeviceProtocol,
+ &dev_attr_functions,
+ &dev_attr_enable,
+ &dev_attr_state,
+ NULL
+};
+
+/*-------------------------------------------------------------------------*/
+/* Composite driver */
+
+static int ccg_bind_config(struct usb_configuration *c)
+{
+ struct ccg_dev *dev = _ccg_dev;
+ int ret = 0;
+
+ ret = ccg_bind_enabled_functions(dev, c);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void ccg_unbind_config(struct usb_configuration *c)
+{
+ struct ccg_dev *dev = _ccg_dev;
+
+ ccg_unbind_enabled_functions(dev, c);
+
+ usb_ep_autoconfig_reset(dev->cdev->gadget);
+}
+
+static int ccg_bind(struct usb_composite_dev *cdev)
+{
+ struct ccg_dev *dev = _ccg_dev;
+ struct usb_gadget *gadget = cdev->gadget;
+ int gcnum, ret;
+
+ /*
+ * Start disconnected. Userspace will connect the gadget once
+ * it is done configuring the functions.
+ */
+ usb_gadget_disconnect(gadget);
+
+ ret = ccg_init_functions(dev->functions, cdev);
+ if (ret)
+ return ret;
+
+ gcnum = usb_gadget_controller_number(gadget);
+ if (gcnum >= 0)
+ device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
+ else {
+ pr_warning("%s: controller '%s' not recognized\n",
+ longname, gadget->name);
+ device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
+ }
+
+ usb_gadget_set_selfpowered(gadget);
+ dev->cdev = cdev;
+
+ return 0;
+}
+
+static int ccg_usb_unbind(struct usb_composite_dev *cdev)
+{
+ struct ccg_dev *dev = _ccg_dev;
+
+ cancel_work_sync(&dev->work);
+ ccg_cleanup_functions(dev->functions);
+ return 0;
+}
+
+static struct usb_composite_driver ccg_usb_driver = {
+ .name = "configurable_usb",
+ .dev = &device_desc,
+ .unbind = ccg_usb_unbind,
+ .needs_serial = true,
+ .iManufacturer = "Linux Foundation",
+ .iProduct = longname,
+ .iSerialNumber = "1234567890123456",
+};
+
+static int ccg_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *c)
+{
+ struct ccg_dev *dev = _ccg_dev;
+ struct usb_composite_dev *cdev = get_gadget_data(gadget);
+ struct usb_request *req = cdev->req;
+ struct ccg_usb_function *f;
+ int value = -EOPNOTSUPP;
+ unsigned long flags;
+
+ req->zero = 0;
+ req->complete = composite_setup_complete;
+ req->length = 0;
+ gadget->ep0->driver_data = cdev;
+
+ list_for_each_entry(f, &dev->enabled_functions, enabled_list) {
+ if (f->ctrlrequest) {
+ value = f->ctrlrequest(f, cdev, c);
+ if (value >= 0)
+ break;
+ }
+ }
+
+ if (value < 0)
+ value = composite_setup(gadget, c);
+
+ spin_lock_irqsave(&cdev->lock, flags);
+ if (!dev->connected) {
+ dev->connected = 1;
+ schedule_work(&dev->work);
+ } else if (c->bRequest == USB_REQ_SET_CONFIGURATION &&
+ cdev->config) {
+ schedule_work(&dev->work);
+ }
+ spin_unlock_irqrestore(&cdev->lock, flags);
+
+ return value;
+}
+
+static void ccg_disconnect(struct usb_gadget *gadget)
+{
+ struct ccg_dev *dev = _ccg_dev;
+ struct usb_composite_dev *cdev = get_gadget_data(gadget);
+ unsigned long flags;
+
+ composite_disconnect(gadget);
+
+ spin_lock_irqsave(&cdev->lock, flags);
+ dev->connected = 0;
+ schedule_work(&dev->work);
+ spin_unlock_irqrestore(&cdev->lock, flags);
+}
+
+static int ccg_create_device(struct ccg_dev *dev)
+{
+ struct device_attribute **attrs = ccg_usb_attributes;
+ struct device_attribute *attr;
+ int err;
+
+ dev->dev = device_create(ccg_class, NULL, MKDEV(0, 0), NULL, "ccg0");
+ if (IS_ERR(dev->dev))
+ return PTR_ERR(dev->dev);
+
+ dev_set_drvdata(dev->dev, dev);
+
+ while ((attr = *attrs++)) {
+ err = device_create_file(dev->dev, attr);
+ if (err) {
+ device_destroy(ccg_class, dev->dev->devt);
+ return err;
+ }
+ }
+ return 0;
+}
+
+
+static int __init init(void)
+{
+ struct ccg_dev *dev;
+ int err;
+
+ ccg_class = class_create(THIS_MODULE, "ccg_usb");
+ if (IS_ERR(ccg_class))
+ return PTR_ERR(ccg_class);
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->functions = supported_functions;
+ INIT_LIST_HEAD(&dev->enabled_functions);
+ INIT_WORK(&dev->work, ccg_work);
+ mutex_init(&dev->mutex);
+
+ err = ccg_create_device(dev);
+ if (err) {
+ class_destroy(ccg_class);
+ kfree(dev);
+ return err;
+ }
+
+ _ccg_dev = dev;
+
+ /* Override composite driver functions */
+ composite_driver.setup = ccg_setup;
+ composite_driver.disconnect = ccg_disconnect;
+
+ err = usb_composite_probe(&ccg_usb_driver, ccg_bind);
+ if (err) {
+ class_destroy(ccg_class);
+ kfree(dev);
+ }
+
+ return err;
+}
+module_init(init);
+
+static void __exit cleanup(void)
+{
+ usb_composite_unregister(&ccg_usb_driver);
+ class_destroy(ccg_class);
+ kfree(_ccg_dev);
+ _ccg_dev = NULL;
+}
+module_exit(cleanup);
diff --git a/drivers/staging/ccg/sysfs-class-ccg_usb b/drivers/staging/ccg/sysfs-class-ccg_usb
new file mode 100644
index 000000000000..dd12a332fb00
--- /dev/null
+++ b/drivers/staging/ccg/sysfs-class-ccg_usb
@@ -0,0 +1,158 @@
+What: /sys/class/ccg_usb
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ The ccg_usb/ class subdirectory belongs to ccg
+ USB gadget.
+
+What: /sys/class/ccg_usb/ccgX
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ The /sys/class/ccg_usb/ccg{0,1,2,3...} class
+ subdirectories correspond to each ccg gadget device;
+ at the time of this writing there is only ccg0 and it
+ represents the ccg gadget.
+
+What: /sys/class/ccg_usb/ccgX/functions
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ A comma-separated list of USB function names to be activated
+ in this ccg gadget. It includes both the functions provided
+ in-kernel by the ccg gadget and the functions provided from
+ userspace through FunctionFS.
+
+What: /sys/class/ccg_usb/ccgX/enable
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ A flag activating/deactivating the ccg usb gadget.
+
+What: /sys/class/ccg_usb/ccgX/state
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ Configurable usb gadget state:
+
+ DISCONNECTED
+ CONNECTED
+ CONFIGURED
+
+What: /sys/class/ccg_usb/ccgX/f_acm/
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ The /sys/class/ccg_usb/ccgX/f_acm subdirectory
+ corresponds to the gadget's USB CDC serial (ACM) function
+ driver.
+
+What: /sys/class/ccg_usb/ccgX/f_acm/instances
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ Maximum number of the /dev/ttyGS<X> interface the driver uses.
+
+What: /sys/class/ccg_usb/ccgX/f_fs
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ The /sys/class/ccg_usb/ccgX/f_fs subdirectory
+ corresponds to the gadget's FunctionFS driver.
+
+What: /sys/class/ccg_usb/ccgX/f_fs/user_functions
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ A comma-separeted list of USB function names to be supported
+ from userspace. No other userspace FunctionFS functions can
+ be supported than listed here. However, the actual activation
+ of these functions is still done through
+ /sys/class/ccg_usb/ccgX/functions, where it is possible
+ to specify any subset (including maximum and empty) of
+ /sys/class/ccg_usb/ccgX/f_fs/user_functions.
+
+What: /sys/class/ccg_usb/ccgX/f_fs/max_user_functions
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ Maximum number of USB functions to be supported from userspace.
+
+What: /sys/class/ccg_usb/ccgX/f_rndis
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ The /sys/class/ccg_usb/ccgX/f_rndis subdirectory
+ corresponds to the gadget's RNDIS driver.
+
+What: /sys/class/ccg_usb/ccgX/f_rndis/manufacturer
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ RNDIS Ethernet port manufacturer string.
+
+What: /sys/class/ccg_usb/ccgX/f_rndis/wceis
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ RNDIS Ethernet port wireless flag.
+
+What: /sys/class/ccg_usb/ccgX/f_rndis/ethaddr
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ RNDIS Ethernet port Ethernet address.
+
+What: /sys/class/ccg_usb/ccgX/f_rndis/vendorID
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ RNDIS Ethernet port vendor ID.
+
+What: /sys/class/ccg_usb/ccgX/f_mass_storage
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ The /sys/class/ccg_usb/ccgX/f_mass_storage subdirectory
+ corresponds to the gadget's USB mass storage driver.
+
+What: /sys/class/ccg_usb/ccgX/f_mass_storage/lun
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ The /sys/class/ccg_usb/ccgX/f_mass_storage/lun
+ subdirectory corresponds to the gadget's USB mass storage
+ driver and its underlying storage.
+
+What: /sys/class/ccg_usb/ccgX/f_mass_storage/lun
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ The /sys/class/ccg_usb/ccgX/f_mass_storage/lun
+ subdirectory corresponds to the gadget's USB mass storage
+ driver and its underlying storage.
+
+What: /sys/class/ccg_usb/ccgX/f_mass_storage/lun/file
+Date: May 2012
+KernelVersion: 3.4
+Contact: linux-usb@vger.kernel.org
+Description:
+ Gadget's USB mass storage underlying file.
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig
index 12c691d90900..3bbe3fd103f3 100644
--- a/drivers/staging/comedi/Kconfig
+++ b/drivers/staging/comedi/Kconfig
@@ -1,6 +1,5 @@
config COMEDI
tristate "Data acquisition support (comedi)"
- default N
depends on m
depends on BROKEN || FRV || M32R || MN10300 || SUPERH || TILE || X86
---help---
@@ -14,10 +13,29 @@ config COMEDI_DEBUG
This is an option for use by developers; most people should
say N here. This enables comedi core and driver debugging.
+config COMEDI_DEFAULT_BUF_SIZE_KB
+ int "Comedi default initial asynchronous buffer size in KiB"
+ default "2048"
+ depends on COMEDI != n
+ ---help---
+ This is the default asynchronous buffer size which is used for
+ commands running in the background in kernel space. This
+ defaults to 2048 KiB of memory so that a 16 channel card
+ running at 10 kHz has of 2-4 seconds of buffer.
+
+config COMEDI_DEFAULT_BUF_MAXSIZE_KB
+ int "Comedi default maximum asynchronous buffer size in KiB"
+ default "20480"
+ depends on COMEDI != n
+ ---help---
+ This is the default maximum asynchronous buffer size which can
+ be requested by a userspace program without root privileges.
+ This is set to 20480 KiB so that a fast I/O card with 16
+ channels running at 100 kHz has 2-4 seconds of buffer.
+
menuconfig COMEDI_MISC_DRIVERS
tristate "Comedi misc drivers"
depends on COMEDI
- default N
---help---
Enable comedi misc drivers to be built
@@ -35,7 +53,6 @@ config COMEDI_KCOMEDILIB
config COMEDI_BOND
tristate "Device bonding support"
depends on COMEDI_KCOMEDILIB
- default N
---help---
Enable support for a driver to 'bond' (merge) multiple subdevices
from multiple devices together as one.
@@ -46,7 +63,6 @@ config COMEDI_BOND
config COMEDI_TEST
tristate "Fake waveform generator support"
select COMEDI_FC
- default N
---help---
Enable support for the fake waveform generator.
This driver is mainly for testing purposes, but can also be used to
@@ -58,7 +74,6 @@ config COMEDI_TEST
config COMEDI_PARPORT
tristate "Parallel port support"
- default N
---help---
Enable support for the standard parallel port.
A cheap and easy way to get a few more digital I/O lines. Steal
@@ -70,7 +85,6 @@ config COMEDI_PARPORT
config COMEDI_SERIAL2002
tristate "Driver for serial connected hardware"
- default N
---help---
Enable support for serial connected hardware
@@ -79,7 +93,6 @@ config COMEDI_SERIAL2002
config COMEDI_SKEL
tristate "Comedi skeleton driver"
- default N
---help---
Build the Skeleton driver, an example for driver writers
@@ -91,7 +104,6 @@ endif # COMEDI_MISC_DRIVERS
menuconfig COMEDI_ISA_DRIVERS
tristate "Comedi ISA and PC/104 drivers"
depends on COMEDI && ISA
- default N
---help---
Enable comedi ISA and PC/104 drivers to be built
@@ -103,7 +115,6 @@ if COMEDI_ISA_DRIVERS && ISA
config COMEDI_ACL7225B
tristate "ADlink NuDAQ ACL-7225b and compatibles support"
- default N
---help---
Enable support for ADlink NuDAQ ACL-7225b and compatibles,
ADlink ACL-7225b (acl7225b), ICP P16R16DIO (p16r16dio)
@@ -113,7 +124,6 @@ config COMEDI_ACL7225B
config COMEDI_PCL711
tristate "Advantech PCL-711/711b and ADlink ACL-8112 ISA card support"
- default N
---help---
Enable support for Advantech PCL-711 and 711b, ADlink ACL-8112
@@ -123,7 +133,6 @@ config COMEDI_PCL711
config COMEDI_PCL724
tristate "Advantech PCL-722/724/731 and ADlink ACL-7122/7124/PET-48DIO"
select COMEDI_8255
- default N
---help---
Enable support for Advantech PCL-724, PCL-722, PCL-731 and
ADlink ACL-7122, ACL-7124, PET-48DIO ISA cards
@@ -133,7 +142,6 @@ config COMEDI_PCL724
config COMEDI_PCL725
tristate "Advantech PCL-725 and compatible ISA card support"
- default N
---help---
Enable support for Advantech PCL-725 and compatible ISA cards.
@@ -142,7 +150,6 @@ config COMEDI_PCL725
config COMEDI_PCL726
tristate "Advantech PCL-726 and compatible ISA card support"
- default N
---help---
Enable support for Advantech PCL-726 and compatible ISA cards.
@@ -151,7 +158,6 @@ config COMEDI_PCL726
config COMEDI_PCL730
tristate "Advantech PCL-730 and ADlink ACL-7130 ISA card support"
- default N
---help---
Enable support for Advantech PCL-730, ICP ISO-730 and ADlink
ACL-7130 ISA cards
@@ -162,7 +168,6 @@ config COMEDI_PCL730
config COMEDI_PCL812
tristate "Advantech PCL-812/813 and ADlink ACL-8112/8113/8113/8216"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for Advantech PCL-812/PG, PCL-813/B, ADLink
ACL-8112DG/HG/PG, ACL-8113, ACL-8216, ICP DAS A-821PGH/PGL/PGL-NDA,
@@ -174,7 +179,6 @@ config COMEDI_PCL812
config COMEDI_PCL816
tristate "Advantech PCL-814 and PCL-816 ISA card support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for Advantech PCL-814 and PCL-816 ISA cards
@@ -184,7 +188,6 @@ config COMEDI_PCL816
config COMEDI_PCL818
tristate "Advantech PCL-718 and PCL-818 ISA card support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for Advantech PCL-818 ISA cards
PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818 and PCL-718
@@ -195,7 +198,6 @@ config COMEDI_PCL818
config COMEDI_PCM3724
tristate "Advantech PCM-3724 PC/104 card support"
select COMEDI_8255
- default N
---help---
Enable support for Advantech PCM-3724 PC/104 cards.
@@ -204,16 +206,43 @@ config COMEDI_PCM3724
config COMEDI_PCM3730
tristate "Advantech PCM-3730 and clone PC/104 board support"
- default N
---help---
Enable support for Advantech PCM-3730 and clone PC/104 boards
To compile this driver as a module, choose M here: the module will be
called pcm3730.
+config COMEDI_AMPLC_DIO200_ISA
+ tristate "Amplicon PC212E/PC214E/PC215E/PC218E/PC272E"
+ select COMEDI_AMPLC_DIO200
+ depends on COMEDI_ISA_DRIVERS
+ ---help---
+ Enable support for Amplicon PC212E, PC214E, PC215E, PC218E and
+ PC272E ISA DIO boards
+
+ To compile this driver as a module, choose M here: the module will be
+ called amplc_dio200.
+
+config COMEDI_AMPLC_PC236_ISA
+ tristate "Amplicon PC36AT DIO board support"
+ select COMEDI_AMPLC_PC236
+ ---help---
+ Enable support for Amplicon PC36AT ISA DIO board.
+
+ To compile this driver as a module, choose M here: the module will be
+ called amplc_pc236.
+
+config COMEDI_AMPLC_PC263_ISA
+ tristate "Amplicon PC263 relay board support"
+ select COMEDI_AMPLC_PC263
+ ---help---
+ Enable support for Amplicon PC263 ISA relay board.
+
+ To compile this driver as a module, choose M here: the module will be
+ called amplc_pc263.
+
config COMEDI_RTI800
tristate "Analog Devices RTI-800/815 ISA card support"
- default N
---help---
Enable support for Analog Devices RTI-800/815 ISA cards
@@ -222,7 +251,6 @@ config COMEDI_RTI800
config COMEDI_RTI802
tristate "Analog Devices RTI-802 ISA card support"
- default N
---help---
Enable support for Analog Devices RTI-802 ISA cards
@@ -233,18 +261,29 @@ config COMEDI_DAS16M1
tristate "MeasurementComputing CIO-DAS16/M1DAS-16 ISA card support"
select COMEDI_8255
select COMEDI_FC
- default N
---help---
Enable support for Measurement Computing CIO-DAS16/M1 ISA cards.
To compile this driver as a module, choose M here: the module will be
called das16m1.
+config COMEDI_DAS08_ISA
+ tristate "DAS-08 compatible ISA and PC/104 card support"
+ select COMEDI_DAS08
+ ---help---
+ Enable support for Keithley Metrabyte/ComputerBoards DAS08
+ and compatible ISA and PC/104 cards:
+ Keithley Metrabyte/ComputerBoards DAS08, DAS08-PGM, DAS08-PGH,
+ DAS08-PGL, DAS08-AOH, DAS08-AOL, DAS08-AOM, DAS08/JR-AO,
+ DAS08/JR-16-AO, PC104-DAS08, DAS08/JR/16.
+
+ To compile this driver as a module, choose M here: the module will be
+ called das08.
+
config COMEDI_DAS16
tristate "DAS-16 compatible ISA and PC/104 card support"
select COMEDI_8255
select COMEDI_FC
- default N
---help---
Enable support for Keithley Metrabyte/ComputerBoards DAS16
and compatible ISA and PC/104 cards:
@@ -261,7 +300,6 @@ config COMEDI_DAS16
config COMEDI_DAS800
tristate "DAS800 and compatible ISA card support"
select COMEDI_FC
- default N
---help---
Enable support for Keithley Metrabyte DAS800 and compatible ISA cards
Keithley Metrabyte DAS-800, DAS-801, DAS-802
@@ -275,7 +313,6 @@ config COMEDI_DAS1800
tristate "DAS1800 and compatible ISA card support"
depends on VIRT_TO_BUS
select COMEDI_FC
- default N
---help---
Enable support for DAS1800 and compatible ISA cards
Keithley Metrabyte DAS-1701ST, DAS-1701ST-DA, DAS-1701/AO,
@@ -289,7 +326,6 @@ config COMEDI_DAS1800
config COMEDI_DAS6402
tristate "DAS6402 and compatible ISA card support"
- default N
---help---
Enable support for DAS6402 and compatible ISA cards
Computerboards, Keithley Metrabyte DAS6402 and compatibles
@@ -299,7 +335,6 @@ config COMEDI_DAS6402
config COMEDI_DT2801
tristate "Data Translation DT2801 ISA card support"
- default N
---help---
Enable support for Data Translation DT2801 ISA cards
@@ -308,7 +343,6 @@ config COMEDI_DT2801
config COMEDI_DT2811
tristate "Data Translation DT2811 ISA card support"
- default N
---help---
Enable support for Data Translation DT2811 ISA cards
@@ -317,7 +351,6 @@ config COMEDI_DT2811
config COMEDI_DT2814
tristate "Data Translation DT2814 ISA card support"
- default N
---help---
Enable support for Data Translation DT2814 ISA cards
@@ -326,7 +359,6 @@ config COMEDI_DT2814
config COMEDI_DT2815
tristate "Data Translation DT2815 ISA card support"
- default N
---help---
Enable support for Data Translation DT2815 ISA cards
@@ -335,7 +367,6 @@ config COMEDI_DT2815
config COMEDI_DT2817
tristate "Data Translation DT2817 ISA card support"
- default N
---help---
Enable support for Data Translation DT2817 ISA cards
@@ -346,7 +377,6 @@ config COMEDI_DT282X
tristate "Data Translation DT2821 series and DT-EZ ISA card support"
select COMEDI_FC
depends on VIRT_TO_BUS
- default N
---help---
Enable support for Data Translation DT2821 series including DT-EZ
DT2821, DT2821-F-16SE, DT2821-F-8DI, DT2821-G-16SE, DT2821-G-8DI,
@@ -358,7 +388,6 @@ config COMEDI_DT282X
config COMEDI_DMM32AT
tristate "Diamond Systems MM-32-AT PC/104 board support"
- default N
---help---
Enable support for Diamond Systems MM-32-AT PC/104 boards
@@ -367,7 +396,6 @@ config COMEDI_DMM32AT
config COMEDI_FL512
tristate "FL512 ISA card support"
- default N
---help---
Enable support for FL512 ISA card
@@ -377,7 +405,6 @@ config COMEDI_FL512
config COMEDI_AIO_AIO12_8
tristate "I/O Products PC/104 AIO12-8 Analog I/O Board support"
select COMEDI_8255
- default N
---help---
Enable support for I/O Products PC/104 AIO12-8 Analog I/O Board
@@ -386,7 +413,6 @@ config COMEDI_AIO_AIO12_8
config COMEDI_AIO_IIRO_16
tristate "I/O Products PC/104 IIRO16 Board support"
- default N
---help---
Enable support for I/O Products PC/104 IIRO16 Relay And Isolated
Input Board
@@ -396,7 +422,6 @@ config COMEDI_AIO_IIRO_16
config COMEDI_C6XDIGIO
tristate "Mechatronic Systems Inc. C6x_DIGIO DSP daughter card support"
- default N
---help---
Enable support for Mechatronic Systems Inc. C6x_DIGIO DSP daughter
card
@@ -406,7 +431,6 @@ config COMEDI_C6XDIGIO
config COMEDI_MPC624
tristate "Micro/sys MPC-624 PC/104 board support"
- default N
---help---
Enable support for Micro/sys MPC-624 PC/104 board
@@ -415,7 +439,6 @@ config COMEDI_MPC624
config COMEDI_ADQ12B
tristate "MicroAxial ADQ12-B data acquisition and control card support"
- default N
---help---
Enable MicroAxial ADQ12-B daq and control card support.
@@ -426,7 +449,6 @@ config COMEDI_NI_AT_A2150
tristate "NI AT-A2150 ISA card support"
depends on COMEDI_NI_COMMON
depends on VIRT_TO_BUS
- default N
---help---
Enable support for National Instruments AT-A2150 cards
@@ -436,7 +458,6 @@ config COMEDI_NI_AT_A2150
config COMEDI_NI_AT_AO
tristate "NI AT-AO-6/10 EISA card support"
depends on COMEDI_NI_COMMON
- default N
---help---
Enable support for National Instruments AT-AO-6/10 cards
@@ -447,7 +468,6 @@ config COMEDI_NI_ATMIO
tristate "NI AT-MIO E series ISA-PNP card support"
depends on ISAPNP && COMEDI_NI_TIO && COMEDI_NI_COMMON
select COMEDI_8255
- default N
---help---
Enable support for National Instruments AT-MIO E series cards
National Instruments AT-MIO-16E-1 (ni_atmio),
@@ -461,7 +481,6 @@ config COMEDI_NI_ATMIO16D
tristate "NI AT-MIO16/AT-MIO16D series ISA-PNP card support"
depends on ISAPNP && COMEDI_NI_COMMON
select COMEDI_8255
- default N
---help---
Enable support for National Instruments AT-MIO16/AT-MIO16D cards.
@@ -470,7 +489,6 @@ config COMEDI_NI_ATMIO16D
config COMEDI_PCMAD
tristate "Winsystems PCM-A/D12 and PCM-A/D16 PC/104 board support"
- default N
---help---
Enable support for Winsystems PCM-A/D12 and PCM-A/D16 PC/104 boards.
@@ -479,7 +497,6 @@ config COMEDI_PCMAD
config COMEDI_PCMDA12
tristate "Winsystems PCM-D/A-12 8-channel AO PC/104 board support"
- default N
---help---
Enable support for Winsystems PCM-D/A-12 8-channel AO PC/104 boards.
Note that the board is not ISA-PNP capable and thus needs the I/O
@@ -490,7 +507,6 @@ config COMEDI_PCMDA12
config COMEDI_PCMMIO
tristate "Winsystems PCM-MIO PC/104 board support"
- default N
---help---
Enable support for Winsystems PCM-MIO multifunction PC/104 boards.
@@ -499,7 +515,6 @@ config COMEDI_PCMMIO
config COMEDI_PCMUIO
tristate "Winsystems PCM-UIO48A and PCM-UIO96A PC/104 board support"
- default N
---help---
Enable support for PCM-UIO48A and PCM-UIO96A PC/104 boards.
@@ -508,7 +523,6 @@ config COMEDI_PCMUIO
config COMEDI_MULTIQ3
tristate "Quanser Consulting MultiQ-3 ISA card support"
- default N
---help---
Enable support for Quanser Consulting MultiQ-3 ISA cards
@@ -517,7 +531,6 @@ config COMEDI_MULTIQ3
config COMEDI_POC
tristate "Generic driver for very simple devices"
- default N
---help---
Enable generic support for very simple / POC (Piece of Crap) boards,
Keithley Metrabyte DAC-02 (dac02), Advantech PCL-733 (pcl733) and
@@ -531,7 +544,6 @@ endif # COMEDI_ISA_DRIVERS
menuconfig COMEDI_PCI_DRIVERS
tristate "Comedi PCI drivers"
depends on COMEDI && PCI
- default N
---help---
Enable comedi PCI drivers to be built
@@ -544,7 +556,6 @@ if COMEDI_PCI_DRIVERS && PCI
config COMEDI_ADDI_APCI_035
tristate "ADDI-DATA APCI_035 support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADDI-DATA APCI_035 cards
@@ -554,7 +565,6 @@ config COMEDI_ADDI_APCI_035
config COMEDI_ADDI_APCI_1032
tristate "ADDI-DATA APCI_1032 support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADDI-DATA APCI_1032 cards
@@ -564,7 +574,6 @@ config COMEDI_ADDI_APCI_1032
config COMEDI_ADDI_APCI_1500
tristate "ADDI-DATA APCI_1500 support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADDI-DATA APCI_1500 cards
@@ -574,7 +583,6 @@ config COMEDI_ADDI_APCI_1500
config COMEDI_ADDI_APCI_1516
tristate "ADDI-DATA APCI_1516 support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADDI-DATA APCI_1516 cards
@@ -584,7 +592,6 @@ config COMEDI_ADDI_APCI_1516
config COMEDI_ADDI_APCI_1564
tristate "ADDI-DATA APCI_1564 support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADDI-DATA APCI_1564 cards
@@ -594,7 +601,6 @@ config COMEDI_ADDI_APCI_1564
config COMEDI_ADDI_APCI_16XX
tristate "ADDI-DATA APCI_16xx support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADDI-DATA APCI_16xx cards
@@ -604,7 +610,6 @@ config COMEDI_ADDI_APCI_16XX
config COMEDI_ADDI_APCI_2016
tristate "ADDI-DATA APCI_2016 support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADDI-DATA APCI_2016 cards
@@ -614,7 +619,6 @@ config COMEDI_ADDI_APCI_2016
config COMEDI_ADDI_APCI_2032
tristate "ADDI-DATA APCI_2032 support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADDI-DATA APCI_2032 cards
@@ -624,7 +628,6 @@ config COMEDI_ADDI_APCI_2032
config COMEDI_ADDI_APCI_2200
tristate "ADDI-DATA APCI_2200 support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADDI-DATA APCI_2200 cards
@@ -635,7 +638,6 @@ config COMEDI_ADDI_APCI_3001
tristate "ADDI-DATA APCI_3001 support"
depends on VIRT_TO_BUS
select COMEDI_FC
- default N
---help---
Enable support for ADDI-DATA APCI_3001 cards
@@ -646,7 +648,6 @@ config COMEDI_ADDI_APCI_3120
tristate "ADDI-DATA APCI_3520 support"
depends on VIRT_TO_BUS
select COMEDI_FC
- default N
---help---
Enable support for ADDI-DATA APCI_3520 cards
@@ -656,7 +657,6 @@ config COMEDI_ADDI_APCI_3120
config COMEDI_ADDI_APCI_3501
tristate "ADDI-DATA APCI_3501 support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADDI-DATA APCI_3501 cards
@@ -666,7 +666,6 @@ config COMEDI_ADDI_APCI_3501
config COMEDI_ADDI_APCI_3XXX
tristate "ADDI-DATA APCI_3xxx support"
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADDI-DATA APCI_3xxx cards
@@ -676,7 +675,6 @@ config COMEDI_ADDI_APCI_3XXX
config COMEDI_ADL_PCI6208
tristate "ADLink PCI-6208A support"
select COMEDI_8255
- default N
---help---
Enable support for ADLink PCI-6208A cards
@@ -685,7 +683,6 @@ config COMEDI_ADL_PCI6208
config COMEDI_ADL_PCI7230
tristate "ADLink PCI-7230 digital io board support"
- default N
---help---
Enable support for ADlink PCI-7230 digital io board support
@@ -694,7 +691,6 @@ config COMEDI_ADL_PCI7230
config COMEDI_ADL_PCI7296
tristate "ADLink PCI-7296 96 ch. digital io board support"
- default N
---help---
Enable support for ADlink PCI-7296 96 ch. digital io board support
@@ -703,7 +699,6 @@ config COMEDI_ADL_PCI7296
config COMEDI_ADL_PCI7432
tristate "ADLink PCI-7432 64 ch. isolated digital io board support"
- default N
---help---
Enable support for ADlink PCI-7432 64 ch. isolated digital io board
@@ -712,7 +707,6 @@ config COMEDI_ADL_PCI7432
config COMEDI_ADL_PCI8164
tristate "ADLink PCI-8164 4 Axes Motion Control board support"
- default N
---help---
Enable support for ADlink PCI-8164 4 Axes Motion Control board
@@ -722,7 +716,6 @@ config COMEDI_ADL_PCI8164
config COMEDI_ADL_PCI9111
tristate "ADLink PCI-9111HR support"
select COMEDI_FC
- default N
---help---
Enable support for ADlink PCI9111 cards
@@ -733,7 +726,6 @@ config COMEDI_ADL_PCI9118
tristate "ADLink PCI-9118DG, PCI-9118HG, PCI-9118HR support"
select COMEDI_FC
depends on VIRT_TO_BUS
- default N
---help---
Enable support for ADlink PCI-9118DG, PCI-9118HG, PCI-9118HR cards
@@ -742,7 +734,6 @@ config COMEDI_ADL_PCI9118
config COMEDI_ADV_PCI1710
tristate "Advantech PCI-171x, PCI-1720 and PCI-1731 support"
- default N
---help---
Enable support for Advantech PCI-1710, PCI-1710HG, PCI-1711,
PCI-1713, PCI-1720 and PCI-1731
@@ -752,7 +743,6 @@ config COMEDI_ADV_PCI1710
config COMEDI_ADV_PCI1723
tristate "Advantech PCI-1723 support"
- default N
---help---
Enable support for Advantech PCI-1723 cards
@@ -762,7 +752,6 @@ config COMEDI_ADV_PCI1723
config COMEDI_ADV_PCI_DIO
tristate "Advantech PCI DIO card support"
select COMEDI_8255
- default N
---help---
Enable support for Advantech PCI DIO cards
PCI-1730, PCI-1733, PCI-1734, PCI-1735U, PCI-1736UP, PCI-1739U,
@@ -772,31 +761,29 @@ config COMEDI_ADV_PCI_DIO
To compile this driver as a module, choose M here: the module will be
called adv_pci_dio.
-config COMEDI_AMPLC_DIO200
- tristate "Amplicon PC272E and PCI272 DIO board support"
- select COMEDI_8255
- default N
+config COMEDI_AMPLC_DIO200_PCI
+ tristate "Amplicon PCI215 and PCI272 DIO board support"
+ select COMEDI_AMPLC_DIO200
---help---
- Enable support for Amplicon PC272E and PCI272 DIO boards
+ Enable support for Amplicon PCI215 and PCI272 DIO boards.
To compile this driver as a module, choose M here: the module will be
called amplc_dio200.
-config COMEDI_AMPLC_PC236
- tristate "Amplicon PC36AT and PCI236 DIO board support"
- select COMEDI_8255
- default N
+config COMEDI_AMPLC_PC236_PCI
+ tristate "Amplicon PCI236 DIO board support"
+ select COMEDI_AMPLC_PC236
---help---
- Enable support for Amplicon PC36AT and PCI236 DIO boards
+ Enable support for Amplicon PCI236 DIO board.
To compile this driver as a module, choose M here: the module will be
called amplc_pc236.
-config COMEDI_AMPLC_PC263
- tristate "Amplicon PC263 and PCI263 relay board support"
- default N
+config COMEDI_AMPLC_PC263_PCI
+ tristate "Amplicon PCI263 relay board support"
+ select COMEDI_AMPLC_PC263
---help---
- Enable support for Amplicon PC263 and PCI263 relay boards
+ Enable support for Amplicon PCI263 relay board.
To compile this driver as a module, choose M here: the module will be
called amplc_pc263.
@@ -804,7 +791,6 @@ config COMEDI_AMPLC_PC263
config COMEDI_AMPLC_PCI224
tristate "Amplicon PCI224 and PCI234 support"
select COMEDI_FC
- default N
---help---
Enable support for Amplicon PCI224 and PCI234 AO boards
@@ -814,7 +800,6 @@ config COMEDI_AMPLC_PCI224
config COMEDI_AMPLC_PCI230
tristate "Amplicon PCI230 and PCI260 support"
select COMEDI_8255
- default N
---help---
Enable support for Amplicon PCI230 and PCI260 Multifunction I/O
boards
@@ -824,16 +809,23 @@ config COMEDI_AMPLC_PCI230
config COMEDI_CONTEC_PCI_DIO
tristate "Contec PIO1616L digital I/O board support"
- default N
---help---
Enable support for the Contec PIO1616L digital I/O board
To compile this driver as a module, choose M here: the module will be
called contec_pci_dio.
+config COMEDI_DAS08_PCI
+ tristate "DAS-08 PCI support"
+ select COMEDI_DAS08
+ ---help---
+ Enable support for PCI DAS-08 cards.
+
+ To compile this driver as a module, choose M here: the module will be
+ called das08.
+
config COMEDI_DT3000
tristate "Data Translation DT3000 series support"
- default N
---help---
Enable support for Data Translation DT3000 series
DT3001, DT3001-PGL, DT3002, DT3003, DT3003-PGL, DT3004, DT3005 and
@@ -844,7 +836,6 @@ config COMEDI_DT3000
config COMEDI_DYNA_PCI10XX
tristate "Dynalog PCI DAQ series support"
- default N
---help---
Enable support for Dynalog PCI DAQ series
PCI-1050
@@ -854,7 +845,6 @@ config COMEDI_DYNA_PCI10XX
config COMEDI_UNIOXX5
tristate "Fastwel UNIOxx-5 analog and digital io board support"
- default N
---help---
Enable support for Fastwel UNIOxx-5 (analog and digital i/o) boards
@@ -864,7 +854,6 @@ config COMEDI_UNIOXX5
config COMEDI_GSC_HPDI
tristate "General Standards PCI-HPDI32 / PMC-HPDI32 support"
select COMEDI_FC
- default N
---help---
Enable support for General Standards Corporation high speed parallel
digital interface rs485 boards PCI-HPDI32 and PMC-HPDI32.
@@ -875,7 +864,6 @@ config COMEDI_GSC_HPDI
config COMEDI_ICP_MULTI
tristate "Inova ICP_MULTI support"
- default N
---help---
Enable support for Inova ICP_MULTI card
@@ -884,7 +872,6 @@ config COMEDI_ICP_MULTI
config COMEDI_II_PCI20KC
tristate "Intelligent Instruments PCI-20001C carrier support"
- default N
---help---
Enable support for Intelligent Instruments PCI-20001C carrier
PCI-20001, PCI-20006 and PCI-20341
@@ -895,7 +882,6 @@ config COMEDI_II_PCI20KC
config COMEDI_DAQBOARD2000
tristate "IOtech DAQboard/2000 support"
select COMEDI_8255
- default N
---help---
Enable support for the IOtech DAQboard/2000
@@ -904,7 +890,6 @@ config COMEDI_DAQBOARD2000
config COMEDI_JR3_PCI
tristate "JR3/PCI force sensor board support"
- default N
---help---
Enable support for JR3/PCI force sensor boards
@@ -913,7 +898,6 @@ config COMEDI_JR3_PCI
config COMEDI_KE_COUNTER
tristate "Kolter-Electronic PCI Counter 1 card support"
- default N
---help---
Enable support for Kolter-Electronic PCI Counter 1 cards
@@ -924,7 +908,6 @@ config COMEDI_CB_PCIDAS64
tristate "MeasurementComputing PCI-DAS 64xx, 60xx, and 4020 support"
select COMEDI_8255
select COMEDI_FC
- default N
---help---
Enable support for ComputerBoards/MeasurementComputing PCI-DAS 64xx,
60xx, and 4020 series with the PLX 9080 PCI controller
@@ -936,7 +919,6 @@ config COMEDI_CB_PCIDAS
tristate "MeasurementComputing PCI-DAS support"
select COMEDI_8255
select COMEDI_FC
- default N
---help---
Enable support for ComputerBoards/MeasurementComputing PCI-DAS with
AMCC S5933 PCIcontroller: PCI-DAS1602/16, PCI-DAS1602/16jr,
@@ -949,7 +931,6 @@ config COMEDI_CB_PCIDAS
config COMEDI_CB_PCIDDA
tristate "MeasurementComputing PCI-DDA series support"
select COMEDI_8255
- default N
---help---
Enable support for ComputerBoards/MeasurementComputing PCI-DDA
series: PCI-DDA08/12, PCI-DDA04/12, PCI-DDA02/12, PCI-DDA08/16,
@@ -961,7 +942,6 @@ config COMEDI_CB_PCIDDA
config COMEDI_CB_PCIDIO
tristate "MeasurementComputing PCI-DIO series support"
select COMEDI_8255
- default N
---help---
Enable support for ComputerBoards/MeasurementComputing PCI-DIO series
PCI-DIO24, PCI-DIO24H and PCI-DIO48H
@@ -972,7 +952,6 @@ config COMEDI_CB_PCIDIO
config COMEDI_CB_PCIMDAS
tristate "MeasurementComputing PCIM-DAS1602/16 support"
select COMEDI_8255
- default N
---help---
Enable support for ComputerBoards/MeasurementComputing PCI Migration
series PCIM-DAS1602/16
@@ -983,7 +962,6 @@ config COMEDI_CB_PCIMDAS
config COMEDI_CB_PCIMDDA
tristate "MeasurementComputing PCIM-DDA06-16 support"
select COMEDI_8255
- default N
---help---
Enable support for ComputerBoards/MeasurementComputing PCIM-DDA06-16
@@ -992,7 +970,6 @@ config COMEDI_CB_PCIMDDA
config COMEDI_ME4000
tristate "Meilhaus ME-4000 support"
- default N
---help---
Enable support for Meilhaus PCI data acquisition cards
ME-4650, ME-4670i, ME-4680, ME-4680i and ME-4680is
@@ -1002,7 +979,6 @@ config COMEDI_ME4000
config COMEDI_ME_DAQ
tristate "Meilhaus ME-2000i, ME-2600i, ME-3000vm1 support"
- default N
---help---
Enable support for Meilhaus PCI data acquisition cards
ME-2000i, ME-2600i and ME-3000vm1
@@ -1013,7 +989,6 @@ config COMEDI_ME_DAQ
config COMEDI_NI_6527
tristate "NI 6527 support"
depends on COMEDI_MITE
- default N
---help---
Enable support for the National Instruments 6527 PCI card
@@ -1023,7 +998,6 @@ config COMEDI_NI_6527
config COMEDI_NI_65XX
tristate "NI 65xx static dio PCI card support"
depends on COMEDI_MITE
- default N
---help---
Enable support for National Instruments 65xx static dio boards.
Supported devices: National Instruments PCI-6509 (ni_65xx),
@@ -1037,7 +1011,6 @@ config COMEDI_NI_65XX
config COMEDI_NI_660X
tristate "NI 660x counter/timer PCI card support"
depends on COMEDI_NI_TIO && COMEDI_NI_COMMON
- default N
---help---
Enable support for National Instruments PCI-6601 (ni_660x), PCI-6602,
PXI-6602 and PXI-6608.
@@ -1048,7 +1021,6 @@ config COMEDI_NI_660X
config COMEDI_NI_670X
tristate "NI 670x PCI card support"
depends on COMEDI_MITE
- default N
---help---
Enable support for National Instruments PCI-6703 and PCI-6704
@@ -1059,7 +1031,6 @@ config COMEDI_NI_PCIDIO
tristate "NI PCI-DIO32HS, PCI-DIO96, PCI-6533, PCI-6503 support"
depends on COMEDI_MITE
select COMEDI_8255
- default N
---help---
Enable support for National Instruments PCI-DIO-32HS, PXI-6533,
PCI-DIO-96, PCI-DIO-96B, PXI-6508, PCI-6503, PCI-6503B, PCI-6503X,
@@ -1075,7 +1046,6 @@ config COMEDI_NI_PCIMIO
depends on COMEDI_NI_TIO && COMEDI_NI_COMMON
select COMEDI_8255
select COMEDI_FC
- default N
---help---
Enable support for National Instruments PCI-MIO-E series and M series
(all boards): PCI-MIO-16XE-10, PXI-6030E, PCI-MIO-16E-1,
@@ -1094,7 +1064,6 @@ config COMEDI_NI_PCIMIO
config COMEDI_RTD520
tristate "Real Time Devices PCI4520/DM7520 support"
select COMEDI_8255
- default N
---help---
Enable support for Real Time Devices PCI4520/DM7520
@@ -1103,7 +1072,6 @@ config COMEDI_RTD520
config COMEDI_S526
tristate "Sensoray s526 support"
- default N
---help---
Enable support for Sensoray s526
@@ -1113,7 +1081,6 @@ config COMEDI_S526
config COMEDI_S626
tristate "Sensoray 626 support"
select COMEDI_FC
- default N
---help---
Enable support for Sensoray 626
@@ -1122,7 +1089,6 @@ config COMEDI_S626
config COMEDI_SSV_DNP
tristate "SSV Embedded Systems DIL/Net-PC support"
- default N
---help---
Enable support for SSV Embedded Systems DIL/Net-PC
@@ -1134,7 +1100,6 @@ endif # COMEDI_PCI_DRIVERS
menuconfig COMEDI_PCMCIA_DRIVERS
tristate "Comedi PCMCIA drivers"
depends on COMEDI && (PCMCIA || PCCARD)
- default N
---help---
Enable comedi PCMCIA and PCCARD drivers to be built
@@ -1146,7 +1111,6 @@ if COMEDI_PCMCIA_DRIVERS && PCMCIA
config COMEDI_CB_DAS16_CS
tristate "CB DAS16 series PCMCIA support"
- default N
---help---
Enable support for the ComputerBoards/MeasurementComputing PCMCIA
cards DAS16/16, PCM-DAS16D/12 and PCM-DAS16s/16
@@ -1157,7 +1121,6 @@ config COMEDI_CB_DAS16_CS
config COMEDI_DAS08_CS
tristate "CB DAS08 PCMCIA support"
select COMEDI_DAS08
- default N
---help---
Enable support for the ComputerBoards/MeasurementComputing DAS-08
PCMCIA card
@@ -1168,7 +1131,6 @@ config COMEDI_DAS08_CS
config COMEDI_NI_DAQ_700_CS
tristate "NI DAQCard-700 PCMCIA support"
depends on COMEDI_NI_COMMON
- default N
---help---
Enable support for the National Instruments PCMCIA DAQCard-700 DIO
@@ -1179,7 +1141,6 @@ config COMEDI_NI_DAQ_DIO24_CS
tristate "NI DAQ-Card DIO-24 PCMCIA support"
depends on COMEDI_NI_COMMON
select COMEDI_8255
- default N
---help---
Enable support for the National Instruments PCMCIA DAQ-Card DIO-24
@@ -1189,7 +1150,6 @@ config COMEDI_NI_DAQ_DIO24_CS
config COMEDI_NI_LABPC_CS
tristate "NI DAQCard-1200 PCMCIA support"
depends on COMEDI_NI_LABPC
- default N
---help---
Enable support for the National Instruments PCMCIA DAQCard-1200
@@ -1201,7 +1161,6 @@ config COMEDI_NI_MIO_CS
depends on COMEDI_NI_TIO && COMEDI_NI_COMMON
select COMEDI_8255
select COMEDI_FC
- default N
---help---
Enable support for the National Instruments PCMCIA DAQCard E series
DAQCard-ai-16xe-50, DAQCard-ai-16e-4, DAQCard-6062E, DAQCard-6024E
@@ -1212,7 +1171,6 @@ config COMEDI_NI_MIO_CS
config COMEDI_QUATECH_DAQP_CS
tristate "Quatech DAQP PCMCIA data capture card support"
- default N
---help---
Enable support for the Quatech DAQP PCMCIA data capture cards
DAQP-208 and DAQP-308
@@ -1225,7 +1183,6 @@ endif # COMEDI_PCMCIA_DRIVERS
menuconfig COMEDI_USB_DRIVERS
tristate "Comedi USB drivers"
depends on COMEDI && USB
- default N
---help---
Enable comedi USB drivers to be built
@@ -1237,7 +1194,6 @@ if COMEDI_USB_DRIVERS && USB
config COMEDI_DT9812
tristate "DataTranslation DT9812 USB module support"
- default N
---help---
Enable support for the Data Translation DT9812 USB module
@@ -1246,7 +1202,6 @@ config COMEDI_DT9812
config COMEDI_USBDUX
tristate "ITL USB-DUX-D support"
- default N
---help---
Enable support for the Incite Technology Ltd USB-DUX-D Board
@@ -1256,7 +1211,6 @@ config COMEDI_USBDUX
config COMEDI_USBDUXFAST
tristate "ITL USB-DUXfast support"
select COMEDI_FC
- default N
---help---
Enable support for the Incite Technology Ltd USB-DUXfast Board
@@ -1266,7 +1220,6 @@ config COMEDI_USBDUXFAST
config COMEDI_USBDUXSIGMA
tristate "ITL USB-DUXsigma support"
select COMEDI_FC
- default N
---help---
Enable support for the Incite Technology Ltd USB-DUXsigma Board
@@ -1275,7 +1228,6 @@ config COMEDI_USBDUXSIGMA
config COMEDI_VMK80XX
tristate "Velleman VM110/VM140 USB Board support"
- default N
---help---
Build the Velleman USB Board Low-Level Driver supporting the
K8055/K8061 aka VM110/VM140 devices
@@ -1288,7 +1240,6 @@ endif # COMEDI_USB_DRIVERS
menuconfig COMEDI_NI_COMMON
tristate "Comedi National Instruments card support"
depends on COMEDI
- default N
---help---
Enable comedi support for National Instruments cards.
Modules in this section are used by many comedi NI drivers.
@@ -1302,7 +1253,6 @@ if COMEDI_NI_COMMON
config COMEDI_MITE
tristate "NI Mite PCI interface chip support"
depends on PCI
- default N
---help---
Enable support for National Instruments Mite PCI interface chip
@@ -1312,7 +1262,6 @@ config COMEDI_MITE
config COMEDI_NI_TIO
tristate "NI general purpose counter support"
depends on COMEDI_MITE
- default N
---help---
Enable support for National Instruments general purpose counters.
This module is not used directly by end-users. Rather, it
@@ -1328,7 +1277,6 @@ config COMEDI_NI_LABPC
select COMEDI_8255
select COMEDI_FC
depends on VIRT_TO_BUS
- default N
---help---
Enable support for National Instruments Lab-PC and compatibles
Lab-PC-1200, Lab-PC-1200AI, Lab-PC+ and PCI-1200.
@@ -1343,7 +1291,6 @@ endif # COMEDI_NI_COMMON
config COMEDI_8255
tristate "Generic 8255 support"
depends on COMEDI
- default N
---help---
Enable generic 8255 support.
@@ -1357,24 +1304,9 @@ config COMEDI_8255
To compile this driver as a module, choose M here: the module will be
called 8255.
-config COMEDI_DAS08
- tristate "DAS-08 compatible support"
- depends on COMEDI
- select COMEDI_8255
- default N
- ---help---
- Enable support for DAS08 and compatible ISA, PC/104 and PCI cards.
-
- Note that PCMCIA DAS08 cards are not directly supported by this
- driver, and need a separate driver as a wrapper.
-
- To compile this driver as a module, choose M here: the module will be
- called das08.
-
config COMEDI_FC
tristate "Comedi shared functions for low-level driver support"
depends on COMEDI
- default N
---help---
Enable support for shared functions for low-level drivers.
This module is not used directly by end-users. Rather, it
@@ -1382,3 +1314,22 @@ config COMEDI_FC
To compile this driver as a module, choose M here: the module will be
called comedi_fc.
+
+config COMEDI_AMPLC_DIO200
+ tristate
+ depends on COMEDI
+ select COMEDI_8255
+
+config COMEDI_AMPLC_PC236
+ tristate
+ depends on COMEDI
+ select COMEDI_8255
+
+config COMEDI_AMPLC_PC263
+ tristate
+ depends on COMEDI
+
+config COMEDI_DAS08
+ tristate
+ depends on COMEDI
+ select COMEDI_8255
diff --git a/drivers/staging/comedi/comedi.h b/drivers/staging/comedi/comedi.h
index 14ea35ac0156..8ea55aef10a7 100644
--- a/drivers/staging/comedi/comedi.h
+++ b/drivers/staging/comedi/comedi.h
@@ -465,7 +465,7 @@
/* only relevant to kernel modules. */
#define COMEDI_CB_EOS 1 /* end of scan */
-#define COMEDI_CB_EOA 2 /* end of acquisition */
+#define COMEDI_CB_EOA 2 /* end of acquisition/output */
#define COMEDI_CB_BLOCK 4 /* data has arrived:
* wakes up read() / write() */
#define COMEDI_CB_EOBUF 8 /* DEPRECATED: end of buffer */
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index 9bcf87ae4c00..76776571ed91 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -58,14 +58,35 @@ MODULE_LICENSE("GPL");
#ifdef CONFIG_COMEDI_DEBUG
int comedi_debug;
EXPORT_SYMBOL(comedi_debug);
-module_param(comedi_debug, int, 0644);
+module_param(comedi_debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(comedi_debug,
+ "enable comedi core and driver debugging if non-zero (default 0)"
+ );
#endif
bool comedi_autoconfig = 1;
-module_param(comedi_autoconfig, bool, 0444);
+module_param(comedi_autoconfig, bool, S_IRUGO);
+MODULE_PARM_DESC(comedi_autoconfig,
+ "enable drivers to auto-configure comedi devices (default 1)");
static int comedi_num_legacy_minors;
-module_param(comedi_num_legacy_minors, int, 0444);
+module_param(comedi_num_legacy_minors, int, S_IRUGO);
+MODULE_PARM_DESC(comedi_num_legacy_minors,
+ "number of comedi minor devices to reserve for non-auto-configured devices (default 0)"
+ );
+
+unsigned int comedi_default_buf_size_kb = CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB;
+module_param(comedi_default_buf_size_kb, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(comedi_default_buf_size_kb,
+ "default asynchronous buffer size in KiB (default "
+ __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB) ")");
+
+unsigned int comedi_default_buf_maxsize_kb
+ = CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB;
+module_param(comedi_default_buf_maxsize_kb, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(comedi_default_buf_maxsize_kb,
+ "default maximum size of asynchronous buffer in KiB (default "
+ __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB) ")");
static DEFINE_SPINLOCK(comedi_file_info_table_lock);
static struct comedi_device_file_info
@@ -108,15 +129,283 @@ static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
static int comedi_fasync(int fd, struct file *file, int on);
static int is_device_busy(struct comedi_device *dev);
+
static int resize_async_buffer(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_async *async, unsigned new_size);
+ struct comedi_async *async, unsigned new_size)
+{
+ int retval;
+
+ if (new_size > async->max_bufsize)
+ return -EPERM;
+
+ if (s->busy) {
+ DPRINTK("subdevice is busy, cannot resize buffer\n");
+ return -EBUSY;
+ }
+ if (async->mmap_count) {
+ DPRINTK("subdevice is mmapped, cannot resize buffer\n");
+ return -EBUSY;
+ }
+
+ if (!async->prealloc_buf)
+ return -EINVAL;
+
+ /* make sure buffer is an integral number of pages
+ * (we round up) */
+ new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
+
+ retval = comedi_buf_alloc(dev, s, new_size);
+ if (retval < 0)
+ return retval;
+
+ if (s->buf_change) {
+ retval = s->buf_change(dev, s, new_size);
+ if (retval < 0)
+ return retval;
+ }
+
+ DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
+ dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz);
+ return 0;
+}
+
+/* sysfs attribute files */
+
+static const unsigned bytes_per_kibi = 1024;
+
+static ssize_t show_max_read_buffer_kb(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t retval;
+ struct comedi_device_file_info *info = dev_get_drvdata(dev);
+ unsigned max_buffer_size_kb = 0;
+ struct comedi_subdevice *const read_subdevice =
+ comedi_get_read_subdevice(info);
+
+ mutex_lock(&info->device->mutex);
+ if (read_subdevice &&
+ (read_subdevice->subdev_flags & SDF_CMD_READ) &&
+ read_subdevice->async) {
+ max_buffer_size_kb = read_subdevice->async->max_bufsize /
+ bytes_per_kibi;
+ }
+ retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
+ mutex_unlock(&info->device->mutex);
+
+ return retval;
+}
+
+static ssize_t store_max_read_buffer_kb(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct comedi_device_file_info *info = dev_get_drvdata(dev);
+ unsigned int new_max_size_kb;
+ unsigned int new_max_size;
+ int ret;
+ struct comedi_subdevice *const read_subdevice =
+ comedi_get_read_subdevice(info);
+
+ ret = kstrtouint(buf, 10, &new_max_size_kb);
+ if (ret)
+ return ret;
+ if (new_max_size_kb > (UINT_MAX / bytes_per_kibi))
+ return -EINVAL;
+ new_max_size = new_max_size_kb * bytes_per_kibi;
+
+ mutex_lock(&info->device->mutex);
+ if (read_subdevice == NULL ||
+ (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
+ read_subdevice->async == NULL) {
+ mutex_unlock(&info->device->mutex);
+ return -EINVAL;
+ }
+ read_subdevice->async->max_bufsize = new_max_size;
+ mutex_unlock(&info->device->mutex);
+
+ return count;
+}
+
+static ssize_t show_read_buffer_kb(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t retval;
+ struct comedi_device_file_info *info = dev_get_drvdata(dev);
+ unsigned buffer_size_kb = 0;
+ struct comedi_subdevice *const read_subdevice =
+ comedi_get_read_subdevice(info);
+
+ mutex_lock(&info->device->mutex);
+ if (read_subdevice &&
+ (read_subdevice->subdev_flags & SDF_CMD_READ) &&
+ read_subdevice->async) {
+ buffer_size_kb = read_subdevice->async->prealloc_bufsz /
+ bytes_per_kibi;
+ }
+ retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
+ mutex_unlock(&info->device->mutex);
+
+ return retval;
+}
+
+static ssize_t store_read_buffer_kb(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct comedi_device_file_info *info = dev_get_drvdata(dev);
+ unsigned int new_size_kb;
+ unsigned int new_size;
+ int retval;
+ int ret;
+ struct comedi_subdevice *const read_subdevice =
+ comedi_get_read_subdevice(info);
+
+ ret = kstrtouint(buf, 10, &new_size_kb);
+ if (ret)
+ return ret;
+ if (new_size_kb > (UINT_MAX / bytes_per_kibi))
+ return -EINVAL;
+ new_size = new_size_kb * bytes_per_kibi;
+
+ mutex_lock(&info->device->mutex);
+ if (read_subdevice == NULL ||
+ (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
+ read_subdevice->async == NULL) {
+ mutex_unlock(&info->device->mutex);
+ return -EINVAL;
+ }
+ retval = resize_async_buffer(info->device, read_subdevice,
+ read_subdevice->async, new_size);
+ mutex_unlock(&info->device->mutex);
+
+ if (retval < 0)
+ return retval;
+ return count;
+}
+
+static ssize_t show_max_write_buffer_kb(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ ssize_t retval;
+ struct comedi_device_file_info *info = dev_get_drvdata(dev);
+ unsigned max_buffer_size_kb = 0;
+ struct comedi_subdevice *const write_subdevice =
+ comedi_get_write_subdevice(info);
+
+ mutex_lock(&info->device->mutex);
+ if (write_subdevice &&
+ (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
+ write_subdevice->async) {
+ max_buffer_size_kb = write_subdevice->async->max_bufsize /
+ bytes_per_kibi;
+ }
+ retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
+ mutex_unlock(&info->device->mutex);
+
+ return retval;
+}
+
+static ssize_t store_max_write_buffer_kb(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct comedi_device_file_info *info = dev_get_drvdata(dev);
+ unsigned int new_max_size_kb;
+ unsigned int new_max_size;
+ int ret;
+ struct comedi_subdevice *const write_subdevice =
+ comedi_get_write_subdevice(info);
+
+ ret = kstrtouint(buf, 10, &new_max_size_kb);
+ if (ret)
+ return ret;
+ if (new_max_size_kb > (UINT_MAX / bytes_per_kibi))
+ return -EINVAL;
+ new_max_size = new_max_size_kb * bytes_per_kibi;
+
+ mutex_lock(&info->device->mutex);
+ if (write_subdevice == NULL ||
+ (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
+ write_subdevice->async == NULL) {
+ mutex_unlock(&info->device->mutex);
+ return -EINVAL;
+ }
+ write_subdevice->async->max_bufsize = new_max_size;
+ mutex_unlock(&info->device->mutex);
+
+ return count;
+}
+
+static ssize_t show_write_buffer_kb(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t retval;
+ struct comedi_device_file_info *info = dev_get_drvdata(dev);
+ unsigned buffer_size_kb = 0;
+ struct comedi_subdevice *const write_subdevice =
+ comedi_get_write_subdevice(info);
+
+ mutex_lock(&info->device->mutex);
+ if (write_subdevice &&
+ (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
+ write_subdevice->async) {
+ buffer_size_kb = write_subdevice->async->prealloc_bufsz /
+ bytes_per_kibi;
+ }
+ retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
+ mutex_unlock(&info->device->mutex);
-/* declarations for sysfs attribute files */
-static struct device_attribute dev_attr_max_read_buffer_kb;
-static struct device_attribute dev_attr_read_buffer_kb;
-static struct device_attribute dev_attr_max_write_buffer_kb;
-static struct device_attribute dev_attr_write_buffer_kb;
+ return retval;
+}
+
+static ssize_t store_write_buffer_kb(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct comedi_device_file_info *info = dev_get_drvdata(dev);
+ unsigned int new_size_kb;
+ unsigned int new_size;
+ int retval;
+ int ret;
+ struct comedi_subdevice *const write_subdevice =
+ comedi_get_write_subdevice(info);
+
+ ret = kstrtouint(buf, 10, &new_size_kb);
+ if (ret)
+ return ret;
+ if (new_size_kb > (UINT_MAX / bytes_per_kibi))
+ return -EINVAL;
+ new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
+
+ mutex_lock(&info->device->mutex);
+ if (write_subdevice == NULL ||
+ (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
+ write_subdevice->async == NULL) {
+ mutex_unlock(&info->device->mutex);
+ return -EINVAL;
+ }
+ retval = resize_async_buffer(info->device, write_subdevice,
+ write_subdevice->async, new_size);
+ mutex_unlock(&info->device->mutex);
+
+ if (retval < 0)
+ return retval;
+ return count;
+}
+
+static struct device_attribute comedi_dev_attrs[] = {
+ __ATTR(max_read_buffer_kb, S_IRUGO | S_IWUSR,
+ show_max_read_buffer_kb, store_max_read_buffer_kb),
+ __ATTR(read_buffer_kb, S_IRUGO | S_IWUSR | S_IWGRP,
+ show_read_buffer_kb, store_read_buffer_kb),
+ __ATTR(max_write_buffer_kb, S_IRUGO | S_IWUSR,
+ show_max_write_buffer_kb, store_max_write_buffer_kb),
+ __ATTR(write_buffer_kb, S_IRUGO | S_IWUSR | S_IWGRP,
+ show_write_buffer_kb, store_write_buffer_kb),
+ __ATTR_NULL
+};
static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
@@ -280,7 +569,7 @@ static int do_devconfig_ioctl(struct comedi_device *dev,
if (ret == 0) {
if (!try_module_get(dev->driver->module)) {
comedi_device_detach(dev);
- return -ENOSYS;
+ ret = -ENOSYS;
}
}
@@ -1545,7 +1834,7 @@ done:
return retval;
}
-static unsigned int comedi_poll(struct file *file, poll_table * wait)
+static unsigned int comedi_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
const unsigned minor = iminor(file->f_dentry->d_inode);
@@ -2054,6 +2343,8 @@ static int __init comedi_init(void)
return PTR_ERR(comedi_class);
}
+ comedi_class->dev_attrs = comedi_dev_attrs;
+
/* XXX requires /proc interface */
comedi_proc_init();
@@ -2192,11 +2483,9 @@ static void comedi_device_cleanup(struct comedi_device *dev)
int comedi_alloc_board_minor(struct device *hardware_device)
{
- unsigned long flags;
struct comedi_device_file_info *info;
struct device *csdev;
unsigned i;
- int retval;
info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
if (info == NULL)
@@ -2206,15 +2495,16 @@ int comedi_alloc_board_minor(struct device *hardware_device)
kfree(info);
return -ENOMEM;
}
+ info->hardware_device = hardware_device;
comedi_device_init(info->device);
- spin_lock_irqsave(&comedi_file_info_table_lock, flags);
+ spin_lock(&comedi_file_info_table_lock);
for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) {
if (comedi_file_info_table[i] == NULL) {
comedi_file_info_table[i] = info;
break;
}
}
- spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
+ spin_unlock(&comedi_file_info_table_lock);
if (i == COMEDI_NUM_BOARD_MINORS) {
comedi_device_cleanup(info->device);
kfree(info->device);
@@ -2230,55 +2520,19 @@ int comedi_alloc_board_minor(struct device *hardware_device)
if (!IS_ERR(csdev))
info->device->class_dev = csdev;
dev_set_drvdata(csdev, info);
- retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
- if (retval) {
- printk(KERN_ERR
- "comedi: "
- "failed to create sysfs attribute file \"%s\".\n",
- dev_attr_max_read_buffer_kb.attr.name);
- comedi_free_board_minor(i);
- return retval;
- }
- retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
- if (retval) {
- printk(KERN_ERR
- "comedi: "
- "failed to create sysfs attribute file \"%s\".\n",
- dev_attr_read_buffer_kb.attr.name);
- comedi_free_board_minor(i);
- return retval;
- }
- retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
- if (retval) {
- printk(KERN_ERR
- "comedi: "
- "failed to create sysfs attribute file \"%s\".\n",
- dev_attr_max_write_buffer_kb.attr.name);
- comedi_free_board_minor(i);
- return retval;
- }
- retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
- if (retval) {
- printk(KERN_ERR
- "comedi: "
- "failed to create sysfs attribute file \"%s\".\n",
- dev_attr_write_buffer_kb.attr.name);
- comedi_free_board_minor(i);
- return retval;
- }
+
return i;
}
void comedi_free_board_minor(unsigned minor)
{
- unsigned long flags;
struct comedi_device_file_info *info;
BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
- spin_lock_irqsave(&comedi_file_info_table_lock, flags);
+ spin_lock(&comedi_file_info_table_lock);
info = comedi_file_info_table[minor];
comedi_file_info_table[minor] = NULL;
- spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
+ spin_unlock(&comedi_file_info_table_lock);
if (info) {
struct comedi_device *dev = info->device;
@@ -2294,14 +2548,29 @@ void comedi_free_board_minor(unsigned minor)
}
}
+int comedi_find_board_minor(struct device *hardware_device)
+{
+ int minor;
+ struct comedi_device_file_info *info;
+
+ for (minor = 0; minor < COMEDI_NUM_BOARD_MINORS; minor++) {
+ spin_lock(&comedi_file_info_table_lock);
+ info = comedi_file_info_table[minor];
+ if (info && info->hardware_device == hardware_device) {
+ spin_unlock(&comedi_file_info_table_lock);
+ return minor;
+ }
+ spin_unlock(&comedi_file_info_table_lock);
+ }
+ return -ENODEV;
+}
+
int comedi_alloc_subdevice_minor(struct comedi_device *dev,
struct comedi_subdevice *s)
{
- unsigned long flags;
struct comedi_device_file_info *info;
struct device *csdev;
unsigned i;
- int retval;
info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL);
if (info == NULL)
@@ -2309,14 +2578,14 @@ int comedi_alloc_subdevice_minor(struct comedi_device *dev,
info->device = dev;
info->read_subdevice = s;
info->write_subdevice = s;
- spin_lock_irqsave(&comedi_file_info_table_lock, flags);
+ spin_lock(&comedi_file_info_table_lock);
for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) {
if (comedi_file_info_table[i] == NULL) {
comedi_file_info_table[i] = info;
break;
}
}
- spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
+ spin_unlock(&comedi_file_info_table_lock);
if (i == COMEDI_NUM_MINORS) {
kfree(info);
printk(KERN_ERR
@@ -2331,48 +2600,12 @@ int comedi_alloc_subdevice_minor(struct comedi_device *dev,
if (!IS_ERR(csdev))
s->class_dev = csdev;
dev_set_drvdata(csdev, info);
- retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb);
- if (retval) {
- printk(KERN_ERR
- "comedi: "
- "failed to create sysfs attribute file \"%s\".\n",
- dev_attr_max_read_buffer_kb.attr.name);
- comedi_free_subdevice_minor(s);
- return retval;
- }
- retval = device_create_file(csdev, &dev_attr_read_buffer_kb);
- if (retval) {
- printk(KERN_ERR
- "comedi: "
- "failed to create sysfs attribute file \"%s\".\n",
- dev_attr_read_buffer_kb.attr.name);
- comedi_free_subdevice_minor(s);
- return retval;
- }
- retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb);
- if (retval) {
- printk(KERN_ERR
- "comedi: "
- "failed to create sysfs attribute file \"%s\".\n",
- dev_attr_max_write_buffer_kb.attr.name);
- comedi_free_subdevice_minor(s);
- return retval;
- }
- retval = device_create_file(csdev, &dev_attr_write_buffer_kb);
- if (retval) {
- printk(KERN_ERR
- "comedi: "
- "failed to create sysfs attribute file \"%s\".\n",
- dev_attr_write_buffer_kb.attr.name);
- comedi_free_subdevice_minor(s);
- return retval;
- }
+
return i;
}
void comedi_free_subdevice_minor(struct comedi_subdevice *s)
{
- unsigned long flags;
struct comedi_device_file_info *info;
if (s == NULL)
@@ -2383,10 +2616,10 @@ void comedi_free_subdevice_minor(struct comedi_subdevice *s)
BUG_ON(s->minor >= COMEDI_NUM_MINORS);
BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR);
- spin_lock_irqsave(&comedi_file_info_table_lock, flags);
+ spin_lock(&comedi_file_info_table_lock);
info = comedi_file_info_table[s->minor];
comedi_file_info_table[s->minor] = NULL;
- spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
+ spin_unlock(&comedi_file_info_table_lock);
if (s->class_dev) {
device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor));
@@ -2397,310 +2630,12 @@ void comedi_free_subdevice_minor(struct comedi_subdevice *s)
struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor)
{
- unsigned long flags;
struct comedi_device_file_info *info;
BUG_ON(minor >= COMEDI_NUM_MINORS);
- spin_lock_irqsave(&comedi_file_info_table_lock, flags);
+ spin_lock(&comedi_file_info_table_lock);
info = comedi_file_info_table[minor];
- spin_unlock_irqrestore(&comedi_file_info_table_lock, flags);
+ spin_unlock(&comedi_file_info_table_lock);
return info;
}
EXPORT_SYMBOL_GPL(comedi_get_device_file_info);
-
-static int resize_async_buffer(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_async *async, unsigned new_size)
-{
- int retval;
-
- if (new_size > async->max_bufsize)
- return -EPERM;
-
- if (s->busy) {
- DPRINTK("subdevice is busy, cannot resize buffer\n");
- return -EBUSY;
- }
- if (async->mmap_count) {
- DPRINTK("subdevice is mmapped, cannot resize buffer\n");
- return -EBUSY;
- }
-
- if (!async->prealloc_buf)
- return -EINVAL;
-
- /* make sure buffer is an integral number of pages
- * (we round up) */
- new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
-
- retval = comedi_buf_alloc(dev, s, new_size);
- if (retval < 0)
- return retval;
-
- if (s->buf_change) {
- retval = s->buf_change(dev, s, new_size);
- if (retval < 0)
- return retval;
- }
-
- DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
- dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz);
- return 0;
-}
-
-/* sysfs attribute files */
-
-static const unsigned bytes_per_kibi = 1024;
-
-static ssize_t show_max_read_buffer_kb(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- ssize_t retval;
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- unsigned max_buffer_size_kb = 0;
- struct comedi_subdevice *const read_subdevice =
- comedi_get_read_subdevice(info);
-
- mutex_lock(&info->device->mutex);
- if (read_subdevice &&
- (read_subdevice->subdev_flags & SDF_CMD_READ) &&
- read_subdevice->async) {
- max_buffer_size_kb = read_subdevice->async->max_bufsize /
- bytes_per_kibi;
- }
- retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
- mutex_unlock(&info->device->mutex);
-
- return retval;
-}
-
-static ssize_t store_max_read_buffer_kb(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- unsigned int new_max_size_kb;
- unsigned int new_max_size;
- int ret;
- struct comedi_subdevice *const read_subdevice =
- comedi_get_read_subdevice(info);
-
- ret = kstrtouint(buf, 10, &new_max_size_kb);
- if (ret)
- return ret;
- if (new_max_size_kb > (UINT_MAX / bytes_per_kibi))
- return -EINVAL;
- new_max_size = new_max_size_kb * bytes_per_kibi;
-
- mutex_lock(&info->device->mutex);
- if (read_subdevice == NULL ||
- (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
- read_subdevice->async == NULL) {
- mutex_unlock(&info->device->mutex);
- return -EINVAL;
- }
- read_subdevice->async->max_bufsize = new_max_size;
- mutex_unlock(&info->device->mutex);
-
- return count;
-}
-
-static struct device_attribute dev_attr_max_read_buffer_kb = {
- .attr = {
- .name = "max_read_buffer_kb",
- .mode = S_IRUGO | S_IWUSR},
- .show = &show_max_read_buffer_kb,
- .store = &store_max_read_buffer_kb
-};
-
-static ssize_t show_read_buffer_kb(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- ssize_t retval;
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- unsigned buffer_size_kb = 0;
- struct comedi_subdevice *const read_subdevice =
- comedi_get_read_subdevice(info);
-
- mutex_lock(&info->device->mutex);
- if (read_subdevice &&
- (read_subdevice->subdev_flags & SDF_CMD_READ) &&
- read_subdevice->async) {
- buffer_size_kb = read_subdevice->async->prealloc_bufsz /
- bytes_per_kibi;
- }
- retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
- mutex_unlock(&info->device->mutex);
-
- return retval;
-}
-
-static ssize_t store_read_buffer_kb(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- unsigned int new_size_kb;
- unsigned int new_size;
- int retval;
- int ret;
- struct comedi_subdevice *const read_subdevice =
- comedi_get_read_subdevice(info);
-
- ret = kstrtouint(buf, 10, &new_size_kb);
- if (ret)
- return ret;
- if (new_size_kb > (UINT_MAX / bytes_per_kibi))
- return -EINVAL;
- new_size = new_size_kb * bytes_per_kibi;
-
- mutex_lock(&info->device->mutex);
- if (read_subdevice == NULL ||
- (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 ||
- read_subdevice->async == NULL) {
- mutex_unlock(&info->device->mutex);
- return -EINVAL;
- }
- retval = resize_async_buffer(info->device, read_subdevice,
- read_subdevice->async, new_size);
- mutex_unlock(&info->device->mutex);
-
- if (retval < 0)
- return retval;
- return count;
-}
-
-static struct device_attribute dev_attr_read_buffer_kb = {
- .attr = {
- .name = "read_buffer_kb",
- .mode = S_IRUGO | S_IWUSR | S_IWGRP},
- .show = &show_read_buffer_kb,
- .store = &store_read_buffer_kb
-};
-
-static ssize_t show_max_write_buffer_kb(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- ssize_t retval;
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- unsigned max_buffer_size_kb = 0;
- struct comedi_subdevice *const write_subdevice =
- comedi_get_write_subdevice(info);
-
- mutex_lock(&info->device->mutex);
- if (write_subdevice &&
- (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
- write_subdevice->async) {
- max_buffer_size_kb = write_subdevice->async->max_bufsize /
- bytes_per_kibi;
- }
- retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb);
- mutex_unlock(&info->device->mutex);
-
- return retval;
-}
-
-static ssize_t store_max_write_buffer_kb(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- unsigned int new_max_size_kb;
- unsigned int new_max_size;
- int ret;
- struct comedi_subdevice *const write_subdevice =
- comedi_get_write_subdevice(info);
-
- ret = kstrtouint(buf, 10, &new_max_size_kb);
- if (ret)
- return ret;
- if (new_max_size_kb > (UINT_MAX / bytes_per_kibi))
- return -EINVAL;
- new_max_size = new_max_size_kb * bytes_per_kibi;
-
- mutex_lock(&info->device->mutex);
- if (write_subdevice == NULL ||
- (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
- write_subdevice->async == NULL) {
- mutex_unlock(&info->device->mutex);
- return -EINVAL;
- }
- write_subdevice->async->max_bufsize = new_max_size;
- mutex_unlock(&info->device->mutex);
-
- return count;
-}
-
-static struct device_attribute dev_attr_max_write_buffer_kb = {
- .attr = {
- .name = "max_write_buffer_kb",
- .mode = S_IRUGO | S_IWUSR},
- .show = &show_max_write_buffer_kb,
- .store = &store_max_write_buffer_kb
-};
-
-static ssize_t show_write_buffer_kb(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- ssize_t retval;
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- unsigned buffer_size_kb = 0;
- struct comedi_subdevice *const write_subdevice =
- comedi_get_write_subdevice(info);
-
- mutex_lock(&info->device->mutex);
- if (write_subdevice &&
- (write_subdevice->subdev_flags & SDF_CMD_WRITE) &&
- write_subdevice->async) {
- buffer_size_kb = write_subdevice->async->prealloc_bufsz /
- bytes_per_kibi;
- }
- retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb);
- mutex_unlock(&info->device->mutex);
-
- return retval;
-}
-
-static ssize_t store_write_buffer_kb(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct comedi_device_file_info *info = dev_get_drvdata(dev);
- unsigned int new_size_kb;
- unsigned int new_size;
- int retval;
- int ret;
- struct comedi_subdevice *const write_subdevice =
- comedi_get_write_subdevice(info);
-
- ret = kstrtouint(buf, 10, &new_size_kb);
- if (ret)
- return ret;
- if (new_size_kb > (UINT_MAX / bytes_per_kibi))
- return -EINVAL;
- new_size = ((uint64_t) new_size_kb) * bytes_per_kibi;
-
- mutex_lock(&info->device->mutex);
- if (write_subdevice == NULL ||
- (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 ||
- write_subdevice->async == NULL) {
- mutex_unlock(&info->device->mutex);
- return -EINVAL;
- }
- retval = resize_async_buffer(info->device, write_subdevice,
- write_subdevice->async, new_size);
- mutex_unlock(&info->device->mutex);
-
- if (retval < 0)
- return retval;
- return count;
-}
-
-static struct device_attribute dev_attr_write_buffer_kb = {
- .attr = {
- .name = "write_buffer_kb",
- .mode = S_IRUGO | S_IWUSR | S_IWGRP},
- .show = &show_write_buffer_kb,
- .store = &store_write_buffer_kb
-};
diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h
index 7a0d4bcbc355..134be93eaa6d 100644
--- a/drivers/staging/comedi/comedidev.h
+++ b/drivers/staging/comedi/comedidev.h
@@ -180,13 +180,18 @@ struct comedi_async {
unsigned int x);
};
+struct pci_dev;
+struct usb_interface;
+
struct comedi_driver {
struct comedi_driver *next;
const char *driver_name;
struct module *module;
int (*attach) (struct comedi_device *, struct comedi_devconfig *);
- int (*detach) (struct comedi_device *);
+ void (*detach) (struct comedi_device *);
+ int (*attach_pci) (struct comedi_device *, struct pci_dev *);
+ int (*attach_usb) (struct comedi_device *, struct usb_interface *);
/* number of elements in board_name and board_id arrays */
unsigned int num_names;
@@ -230,10 +235,16 @@ struct comedi_device {
void (*close) (struct comedi_device *dev);
};
+static inline const void *comedi_board(struct comedi_device *dev)
+{
+ return dev->board_ptr;
+}
+
struct comedi_device_file_info {
struct comedi_device *device;
struct comedi_subdevice *read_subdevice;
struct comedi_subdevice *write_subdevice;
+ struct device *hardware_device;
};
#ifdef CONFIG_COMEDI_DEBUG
@@ -287,6 +298,56 @@ int comedi_device_attach(struct comedi_device *dev,
int comedi_driver_register(struct comedi_driver *);
int comedi_driver_unregister(struct comedi_driver *);
+/**
+ * module_comedi_driver() - Helper macro for registering a comedi driver
+ * @__comedi_driver: comedi_driver struct
+ *
+ * Helper macro for comedi drivers which do not do anything special in module
+ * init/exit. This eliminates a lot of boilerplate. Each module may only use
+ * this macro once, and calling it replaces module_init() and module_exit().
+ */
+#define module_comedi_driver(__comedi_driver) \
+ module_driver(__comedi_driver, comedi_driver_register, \
+ comedi_driver_unregister)
+
+struct pci_driver;
+
+int comedi_pci_driver_register(struct comedi_driver *, struct pci_driver *);
+void comedi_pci_driver_unregister(struct comedi_driver *, struct pci_driver *);
+
+/**
+ * module_comedi_pci_driver() - Helper macro for registering a comedi PCI driver
+ * @__comedi_driver: comedi_driver struct
+ * @__pci_driver: pci_driver struct
+ *
+ * Helper macro for comedi PCI drivers which do not do anything special
+ * in module init/exit. This eliminates a lot of boilerplate. Each
+ * module may only use this macro once, and calling it replaces
+ * module_init() and module_exit()
+ */
+#define module_comedi_pci_driver(__comedi_driver, __pci_driver) \
+ module_driver(__comedi_driver, comedi_pci_driver_register, \
+ comedi_pci_driver_unregister, &(__pci_driver))
+
+struct usb_driver;
+
+int comedi_usb_driver_register(struct comedi_driver *, struct usb_driver *);
+void comedi_usb_driver_unregister(struct comedi_driver *, struct usb_driver *);
+
+/**
+ * module_comedi_usb_driver() - Helper macro for registering a comedi USB driver
+ * @__comedi_driver: comedi_driver struct
+ * @__usb_driver: usb_driver struct
+ *
+ * Helper macro for comedi USB drivers which do not do anything special
+ * in module init/exit. This eliminates a lot of boilerplate. Each
+ * module may only use this macro once, and calling it replaces
+ * module_init() and module_exit()
+ */
+#define module_comedi_usb_driver(__comedi_driver, __usb_driver) \
+ module_driver(__comedi_driver, comedi_usb_driver_register, \
+ comedi_usb_driver_unregister, &(__usb_driver))
+
void init_polling(void);
void cleanup_polling(void);
void start_polling(struct comedi_device *);
@@ -456,11 +517,12 @@ static inline void *comedi_aux_data(int options[], int n)
int comedi_alloc_subdevice_minor(struct comedi_device *dev,
struct comedi_subdevice *s);
void comedi_free_subdevice_minor(struct comedi_subdevice *s);
-int comedi_pci_auto_config(struct pci_dev *pcidev, const char *board_name);
+int comedi_pci_auto_config(struct pci_dev *pcidev,
+ struct comedi_driver *driver);
void comedi_pci_auto_unconfig(struct pci_dev *pcidev);
-struct usb_device; /* forward declaration */
-int comedi_usb_auto_config(struct usb_device *usbdev, const char *board_name);
-void comedi_usb_auto_unconfig(struct usb_device *usbdev);
+int comedi_usb_auto_config(struct usb_interface *intf,
+ struct comedi_driver *driver);
+void comedi_usb_auto_unconfig(struct usb_interface *intf);
#ifdef CONFIG_COMEDI_PCI_DRIVERS
#define CONFIG_COMEDI_PCI
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c
index bf185e2807d1..1c3d6386ea36 100644
--- a/drivers/staging/comedi/drivers.c
+++ b/drivers/staging/comedi/drivers.c
@@ -106,6 +106,26 @@ void comedi_device_detach(struct comedi_device *dev)
__comedi_device_detach(dev);
}
+/* do a little post-config cleanup */
+/* called with module refcount incremented, decrements it */
+static int comedi_device_postconfig(struct comedi_device *dev)
+{
+ int ret = postconfig(dev);
+ module_put(dev->driver->module);
+ if (ret < 0) {
+ __comedi_device_detach(dev);
+ return ret;
+ }
+ if (!dev->board_name) {
+ printk(KERN_WARNING "BUG: dev->board_name=<%p>\n",
+ dev->board_name);
+ dev->board_name = "BUG";
+ }
+ smp_wmb();
+ dev->attached = 1;
+ return 0;
+}
+
int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct comedi_driver *driv;
@@ -121,59 +141,36 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
}
if (driv->num_names) {
dev->board_ptr = comedi_recognize(driv, it->board_name);
- if (dev->board_ptr == NULL) {
- module_put(driv->module);
- continue;
- }
- } else {
- if (strcmp(driv->driver_name, it->board_name)) {
- module_put(driv->module);
+ if (dev->board_ptr)
+ break;
+ } else if (strcmp(driv->driver_name, it->board_name))
+ break;
+ module_put(driv->module);
+ }
+ if (driv == NULL) {
+ /* recognize has failed if we get here */
+ /* report valid board names before returning error */
+ for (driv = comedi_drivers; driv; driv = driv->next) {
+ if (!try_module_get(driv->module)) {
+ printk(KERN_INFO
+ "comedi: failed to increment module count\n");
continue;
}
+ comedi_report_boards(driv);
+ module_put(driv->module);
}
- /* initialize dev->driver here so
- * comedi_error() can be called from attach */
- dev->driver = driv;
- ret = driv->attach(dev, it);
- if (ret < 0) {
- module_put(dev->driver->module);
- __comedi_device_detach(dev);
- return ret;
- }
- goto attached;
+ return -EIO;
}
-
- /* recognize has failed if we get here */
- /* report valid board names before returning error */
- for (driv = comedi_drivers; driv; driv = driv->next) {
- if (!try_module_get(driv->module)) {
- printk(KERN_INFO
- "comedi: failed to increment module count\n");
- continue;
- }
- comedi_report_boards(driv);
- module_put(driv->module);
- }
- return -EIO;
-
-attached:
- /* do a little post-config cleanup */
- ret = postconfig(dev);
- module_put(dev->driver->module);
+ /* initialize dev->driver here so
+ * comedi_error() can be called from attach */
+ dev->driver = driv;
+ ret = driv->attach(dev, it);
if (ret < 0) {
+ module_put(dev->driver->module);
__comedi_device_detach(dev);
return ret;
}
-
- if (!dev->board_name) {
- printk(KERN_WARNING "BUG: dev->board_name=<%p>\n",
- dev->board_name);
- dev->board_name = "BUG";
- }
- smp_wmb();
- dev->attached = 1;
-
- return 0;
+ return comedi_device_postconfig(dev);
}
int comedi_driver_register(struct comedi_driver *driver)
@@ -242,6 +239,8 @@ static int postconfig(struct comedi_device *dev)
s->len_chanlist = 1;
if (s->do_cmd) {
+ unsigned int buf_size;
+
BUG_ON((s->subdev_flags & (SDF_CMD_READ |
SDF_CMD_WRITE)) == 0);
BUG_ON(!s->do_cmdtest);
@@ -257,19 +256,20 @@ static int postconfig(struct comedi_device *dev)
async->subdevice = s;
s->async = async;
-#define DEFAULT_BUF_MAXSIZE (64*1024)
-#define DEFAULT_BUF_SIZE (64*1024)
-
- async->max_bufsize = DEFAULT_BUF_MAXSIZE;
+ async->max_bufsize =
+ comedi_default_buf_maxsize_kb * 1024;
+ buf_size = comedi_default_buf_size_kb * 1024;
+ if (buf_size > async->max_bufsize)
+ buf_size = async->max_bufsize;
async->prealloc_buf = NULL;
async->prealloc_bufsz = 0;
- if (comedi_buf_alloc(dev, s, DEFAULT_BUF_SIZE) < 0) {
+ if (comedi_buf_alloc(dev, s, buf_size) < 0) {
printk(KERN_INFO "Buffer allocation failed\n");
return -ENOMEM;
}
if (s->buf_change) {
- ret = s->buf_change(dev, s, DEFAULT_BUF_SIZE);
+ ret = s->buf_change(dev, s, buf_size);
if (ret < 0)
return ret;
}
@@ -814,67 +814,102 @@ void comedi_reset_async_buf(struct comedi_async *async)
async->events = 0;
}
-static int comedi_auto_config(struct device *hardware_device,
- const char *board_name, const int *options,
- unsigned num_options)
+static int
+comedi_auto_config_helper(struct device *hardware_device,
+ struct comedi_driver *driver,
+ int (*attach_wrapper) (struct comedi_device *,
+ void *), void *context)
{
- struct comedi_devconfig it;
int minor;
struct comedi_device_file_info *dev_file_info;
- int retval;
- unsigned *private_data = NULL;
+ struct comedi_device *comedi_dev;
+ int ret;
- if (!comedi_autoconfig) {
- dev_set_drvdata(hardware_device, NULL);
+ if (!comedi_autoconfig)
return 0;
- }
minor = comedi_alloc_board_minor(hardware_device);
if (minor < 0)
return minor;
- private_data = kmalloc(sizeof(unsigned), GFP_KERNEL);
- if (private_data == NULL) {
- retval = -ENOMEM;
- goto cleanup;
+ dev_file_info = comedi_get_device_file_info(minor);
+ comedi_dev = dev_file_info->device;
+
+ mutex_lock(&comedi_dev->mutex);
+ if (comedi_dev->attached)
+ ret = -EBUSY;
+ else if (!try_module_get(driver->module)) {
+ printk(KERN_INFO "comedi: failed to increment module count\n");
+ ret = -EIO;
+ } else {
+ /* set comedi_dev->driver here for attach wrapper */
+ comedi_dev->driver = driver;
+ ret = (*attach_wrapper)(comedi_dev, context);
+ if (ret < 0) {
+ module_put(driver->module);
+ __comedi_device_detach(comedi_dev);
+ } else {
+ ret = comedi_device_postconfig(comedi_dev);
+ }
}
- *private_data = minor;
- dev_set_drvdata(hardware_device, private_data);
+ mutex_unlock(&comedi_dev->mutex);
- dev_file_info = comedi_get_device_file_info(minor);
+ if (ret < 0)
+ comedi_free_board_minor(minor);
+ return ret;
+}
+
+static int comedi_auto_config_wrapper(struct comedi_device *dev, void *context)
+{
+ struct comedi_devconfig *it = context;
+ struct comedi_driver *driv = dev->driver;
+
+ if (driv->num_names) {
+ /* look for generic board entry matching driver name, which
+ * has already been copied to it->board_name */
+ dev->board_ptr = comedi_recognize(driv, it->board_name);
+ if (dev->board_ptr == NULL) {
+ printk(KERN_WARNING
+ "comedi: auto config failed to find board entry"
+ " '%s' for driver '%s'\n", it->board_name,
+ driv->driver_name);
+ comedi_report_boards(driv);
+ return -EINVAL;
+ }
+ }
+ return driv->attach(dev, it);
+}
+
+static int comedi_auto_config(struct device *hardware_device,
+ struct comedi_driver *driver, const int *options,
+ unsigned num_options)
+{
+ struct comedi_devconfig it;
memset(&it, 0, sizeof(it));
- strncpy(it.board_name, board_name, COMEDI_NAMELEN);
+ strncpy(it.board_name, driver->driver_name, COMEDI_NAMELEN);
it.board_name[COMEDI_NAMELEN - 1] = '\0';
BUG_ON(num_options > COMEDI_NDEVCONFOPTS);
memcpy(it.options, options, num_options * sizeof(int));
-
- mutex_lock(&dev_file_info->device->mutex);
- retval = comedi_device_attach(dev_file_info->device, &it);
- mutex_unlock(&dev_file_info->device->mutex);
-
-cleanup:
- if (retval < 0) {
- kfree(private_data);
- comedi_free_board_minor(minor);
- }
- return retval;
+ return comedi_auto_config_helper(hardware_device, driver,
+ comedi_auto_config_wrapper, &it);
}
static void comedi_auto_unconfig(struct device *hardware_device)
{
- unsigned *minor = (unsigned *)dev_get_drvdata(hardware_device);
- if (minor == NULL)
- return;
-
- BUG_ON(*minor >= COMEDI_NUM_BOARD_MINORS);
+ int minor;
- comedi_free_board_minor(*minor);
- dev_set_drvdata(hardware_device, NULL);
- kfree(minor);
+ if (hardware_device == NULL)
+ return;
+ minor = comedi_find_board_minor(hardware_device);
+ if (minor < 0)
+ return;
+ BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS);
+ comedi_free_board_minor(minor);
}
-int comedi_pci_auto_config(struct pci_dev *pcidev, const char *board_name)
+static int comedi_old_pci_auto_config(struct pci_dev *pcidev,
+ struct comedi_driver *driver)
{
int options[2];
@@ -883,9 +918,30 @@ int comedi_pci_auto_config(struct pci_dev *pcidev, const char *board_name)
/* pci slot */
options[1] = PCI_SLOT(pcidev->devfn);
- return comedi_auto_config(&pcidev->dev, board_name,
+ return comedi_auto_config(&pcidev->dev, driver,
options, ARRAY_SIZE(options));
}
+
+static int comedi_pci_attach_wrapper(struct comedi_device *dev, void *pcidev)
+{
+ return dev->driver->attach_pci(dev, pcidev);
+}
+
+static int comedi_new_pci_auto_config(struct pci_dev *pcidev,
+ struct comedi_driver *driver)
+{
+ return comedi_auto_config_helper(&pcidev->dev, driver,
+ comedi_pci_attach_wrapper, pcidev);
+}
+
+int comedi_pci_auto_config(struct pci_dev *pcidev, struct comedi_driver *driver)
+{
+
+ if (driver->attach_pci)
+ return comedi_new_pci_auto_config(pcidev, driver);
+ else
+ return comedi_old_pci_auto_config(pcidev, driver);
+}
EXPORT_SYMBOL_GPL(comedi_pci_auto_config);
void comedi_pci_auto_unconfig(struct pci_dev *pcidev)
@@ -894,16 +950,96 @@ void comedi_pci_auto_unconfig(struct pci_dev *pcidev)
}
EXPORT_SYMBOL_GPL(comedi_pci_auto_unconfig);
-int comedi_usb_auto_config(struct usb_device *usbdev, const char *board_name)
+int comedi_pci_driver_register(struct comedi_driver *comedi_driver,
+ struct pci_driver *pci_driver)
+{
+ int ret;
+
+ ret = comedi_driver_register(comedi_driver);
+ if (ret < 0)
+ return ret;
+
+ /* FIXME: Remove this test after auditing all comedi pci drivers */
+ if (!pci_driver->name)
+ pci_driver->name = comedi_driver->driver_name;
+
+ ret = pci_register_driver(pci_driver);
+ if (ret < 0) {
+ comedi_driver_unregister(comedi_driver);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(comedi_pci_driver_register);
+
+void comedi_pci_driver_unregister(struct comedi_driver *comedi_driver,
+ struct pci_driver *pci_driver)
+{
+ pci_unregister_driver(pci_driver);
+ comedi_driver_unregister(comedi_driver);
+}
+EXPORT_SYMBOL_GPL(comedi_pci_driver_unregister);
+
+static int comedi_old_usb_auto_config(struct usb_interface *intf,
+ struct comedi_driver *driver)
+{
+ return comedi_auto_config(&intf->dev, driver, NULL, 0);
+}
+
+static int comedi_usb_attach_wrapper(struct comedi_device *dev, void *intf)
+{
+ return dev->driver->attach_usb(dev, intf);
+}
+
+static int comedi_new_usb_auto_config(struct usb_interface *intf,
+ struct comedi_driver *driver)
+{
+ return comedi_auto_config_helper(&intf->dev, driver,
+ comedi_usb_attach_wrapper, intf);
+}
+
+int comedi_usb_auto_config(struct usb_interface *intf,
+ struct comedi_driver *driver)
{
- BUG_ON(usbdev == NULL);
- return comedi_auto_config(&usbdev->dev, board_name, NULL, 0);
+ BUG_ON(intf == NULL);
+ if (driver->attach_usb)
+ return comedi_new_usb_auto_config(intf, driver);
+ else
+ return comedi_old_usb_auto_config(intf, driver);
}
EXPORT_SYMBOL_GPL(comedi_usb_auto_config);
-void comedi_usb_auto_unconfig(struct usb_device *usbdev)
+void comedi_usb_auto_unconfig(struct usb_interface *intf)
{
- BUG_ON(usbdev == NULL);
- comedi_auto_unconfig(&usbdev->dev);
+ BUG_ON(intf == NULL);
+ comedi_auto_unconfig(&intf->dev);
}
EXPORT_SYMBOL_GPL(comedi_usb_auto_unconfig);
+
+int comedi_usb_driver_register(struct comedi_driver *comedi_driver,
+ struct usb_driver *usb_driver)
+{
+ int ret;
+
+ ret = comedi_driver_register(comedi_driver);
+ if (ret < 0)
+ return ret;
+
+ ret = usb_register(usb_driver);
+ if (ret < 0) {
+ comedi_driver_unregister(comedi_driver);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(comedi_usb_driver_register);
+
+void comedi_usb_driver_unregister(struct comedi_driver *comedi_driver,
+ struct usb_driver *usb_driver)
+{
+ usb_deregister(usb_driver);
+ comedi_driver_unregister(comedi_driver);
+}
+EXPORT_SYMBOL_GPL(comedi_usb_driver_unregister);
diff --git a/drivers/staging/comedi/drivers/8255.c b/drivers/staging/comedi/drivers/8255.c
index 6c26ac887eee..27e39e4eb6b3 100644
--- a/drivers/staging/comedi/drivers/8255.c
+++ b/drivers/staging/comedi/drivers/8255.c
@@ -107,31 +107,6 @@ struct subdev_8255_struct {
#define CALLBACK_FUNC (((struct subdev_8255_struct *)s->private)->cb_func)
#define subdevpriv ((struct subdev_8255_struct *)s->private)
-static int dev_8255_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int dev_8255_detach(struct comedi_device *dev);
-static struct comedi_driver driver_8255 = {
- .driver_name = "8255",
- .module = THIS_MODULE,
- .attach = dev_8255_attach,
- .detach = dev_8255_detach,
-};
-
-static int __init driver_8255_init_module(void)
-{
- return comedi_driver_register(&driver_8255);
-}
-
-static void __exit driver_8255_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_8255);
-}
-
-module_init(driver_8255_init_module);
-module_exit(driver_8255_cleanup_module);
-
-static void do_config(struct comedi_device *dev, struct comedi_subdevice *s);
-
void subdev_8255_interrupt(struct comedi_device *dev,
struct comedi_subdevice *s)
{
@@ -185,6 +160,23 @@ static int subdev_8255_insn(struct comedi_device *dev,
return 2;
}
+static void do_config(struct comedi_device *dev, struct comedi_subdevice *s)
+{
+ int config;
+
+ config = CR_CW;
+ /* 1 in io_bits indicates output, 1 in config indicates input */
+ if (!(s->io_bits & 0x0000ff))
+ config |= CR_A_IO;
+ if (!(s->io_bits & 0x00ff00))
+ config |= CR_B_IO;
+ if (!(s->io_bits & 0x0f0000))
+ config |= CR_C_LO_IO;
+ if (!(s->io_bits & 0xf00000))
+ config |= CR_C_HI_IO;
+ CALLBACK_FUNC(1, _8255_CR, config, CALLBACK_ARG);
+}
+
static int subdev_8255_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -222,23 +214,6 @@ static int subdev_8255_insn_config(struct comedi_device *dev,
return 1;
}
-static void do_config(struct comedi_device *dev, struct comedi_subdevice *s)
-{
- int config;
-
- config = CR_CW;
- /* 1 in io_bits indicates output, 1 in config indicates input */
- if (!(s->io_bits & 0x0000ff))
- config |= CR_A_IO;
- if (!(s->io_bits & 0x00ff00))
- config |= CR_B_IO;
- if (!(s->io_bits & 0x0f0000))
- config |= CR_C_LO_IO;
- if (!(s->io_bits & 0xf00000))
- config |= CR_C_HI_IO;
- CALLBACK_FUNC(1, _8255_CR, config, CALLBACK_ARG);
-}
-
static int subdev_8255_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
@@ -442,14 +417,12 @@ static int dev_8255_attach(struct comedi_device *dev,
return 0;
}
-static int dev_8255_detach(struct comedi_device *dev)
+static void dev_8255_detach(struct comedi_device *dev)
{
int i;
unsigned long iobase;
struct comedi_subdevice *s;
- printk(KERN_INFO "comedi%d: 8255: remove\n", dev->minor);
-
for (i = 0; i < dev->n_subdevices; i++) {
s = dev->subdevices + i;
if (s->type != COMEDI_SUBD_UNUSED) {
@@ -458,10 +431,16 @@ static int dev_8255_detach(struct comedi_device *dev)
}
subdev_8255_cleanup(dev, s);
}
-
- return 0;
}
+static struct comedi_driver dev_8255_driver = {
+ .driver_name = "8255",
+ .module = THIS_MODULE,
+ .attach = dev_8255_attach,
+ .detach = dev_8255_detach,
+};
+module_comedi_driver(dev_8255_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/acl7225b.c b/drivers/staging/comedi/drivers/acl7225b.c
index 9def2250bb80..4e4fc418655f 100644
--- a/drivers/staging/comedi/drivers/acl7225b.c
+++ b/drivers/staging/comedi/drivers/acl7225b.c
@@ -22,46 +22,13 @@ Devices: [Adlink] ACL-7225b (acl7225b), [ICP] P16R16DIO (p16r16dio)
#define ACL7225_DI_LO 2 /* Digital input low byte (DI0-DI7) */
#define ACL7225_DI_HI 3 /* Digital input high byte (DI8-DI15) */
-static int acl7225b_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int acl7225b_detach(struct comedi_device *dev);
-
struct boardtype {
const char *name; /* driver name */
int io_range; /* len of I/O space */
};
-static const struct boardtype boardtypes[] = {
- {"acl7225b", ACL7225_SIZE,},
- {"p16r16dio", P16R16DIO_SIZE,},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
#define this_board ((const struct boardtype *)dev->board_ptr)
-static struct comedi_driver driver_acl7225b = {
- .driver_name = "acl7225b",
- .module = THIS_MODULE,
- .attach = acl7225b_attach,
- .detach = acl7225b_detach,
- .board_name = &boardtypes[0].name,
- .num_names = n_boardtypes,
- .offset = sizeof(struct boardtype),
-};
-
-static int __init driver_acl7225b_init_module(void)
-{
- return comedi_driver_register(&driver_acl7225b);
-}
-
-static void __exit driver_acl7225b_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_acl7225b);
-}
-
-module_init(driver_acl7225b_init_module);
-module_exit(driver_acl7225b_cleanup_module);
-
static int acl7225b_do_insn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -152,16 +119,28 @@ static int acl7225b_attach(struct comedi_device *dev,
return 0;
}
-static int acl7225b_detach(struct comedi_device *dev)
+static void acl7225b_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: acl7225b: remove\n", dev->minor);
-
if (dev->iobase)
release_region(dev->iobase, this_board->io_range);
-
- return 0;
}
+static const struct boardtype boardtypes[] = {
+ { "acl7225b", ACL7225_SIZE, },
+ { "p16r16dio", P16R16DIO_SIZE, },
+};
+
+static struct comedi_driver acl7225b_driver = {
+ .driver_name = "acl7225b",
+ .module = THIS_MODULE,
+ .attach = acl7225b_attach,
+ .detach = acl7225b_detach,
+ .board_name = &boardtypes[0].name,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .offset = sizeof(struct boardtype),
+};
+module_comedi_driver(acl7225b_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c
index ca5bd9b8704a..44aaf8351ba3 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_common.c
+++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c
@@ -224,2318 +224,1213 @@ MODULE_DEVICE_TABLE(pci, addi_apci_tbl);
static const struct addi_board boardtypes[] = {
#ifdef CONFIG_APCI_3120
- {"apci3120",
- APCI3120_BOARD_VENDOR_ID,
- 0x818D,
- AMCC_OP_REG_SIZE,
- APCI3120_ADDRESS_RANGE,
- 8,
- 0,
- ADDIDATA_NO_EEPROM,
- NULL,
- 16,
- 8,
- 16,
- 8,
- 0xffff,
- 0x3fff,
- &range_apci3120_ai,
- &range_apci3120_ao,
- 4,
- 4,
- 0x0f,
- 0,
- NULL,
- 1,
- 1,
- 1,
- 10000,
- 100000,
- v_APCI3120_Interrupt,
- i_APCI3120_Reset,
- i_APCI3120_InsnConfigAnalogInput,
- i_APCI3120_InsnReadAnalogInput,
- NULL,
- NULL,
- i_APCI3120_CommandTestAnalogInput,
- i_APCI3120_CommandAnalogInput,
- i_APCI3120_StopCyclicAcquisition,
- NULL,
- i_APCI3120_InsnWriteAnalogOutput,
- NULL,
- NULL,
- i_APCI3120_InsnReadDigitalInput,
- NULL,
- i_APCI3120_InsnBitsDigitalInput,
- i_APCI3120_InsnConfigDigitalOutput,
- i_APCI3120_InsnWriteDigitalOutput,
- i_APCI3120_InsnBitsDigitalOutput,
- NULL,
- i_APCI3120_InsnConfigTimer,
- i_APCI3120_InsnWriteTimer,
- i_APCI3120_InsnReadTimer,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci3120",
+ .i_VendorId = APCI3120_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x818D,
+ .i_IorangeBase0 = AMCC_OP_REG_SIZE,
+ .i_IorangeBase1 = APCI3120_ADDRESS_RANGE,
+ .i_IorangeBase2 = 8,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_NbrAoChannel = 8,
+ .i_AiMaxdata = 0xffff,
+ .i_AoMaxdata = 0x3fff,
+ .pr_AiRangelist = &range_apci3120_ai,
+ .pr_AoRangelist = &range_apci3120_ao,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 0x0f,
+ .i_Dma = 1,
+ .i_Timer = 1,
+ .b_AvailableConvertUnit = 1,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .ui_MinDelaytimeNs = 100000,
+ .interrupt = v_APCI3120_Interrupt,
+ .reset = i_APCI3120_Reset,
+ .ai_config = i_APCI3120_InsnConfigAnalogInput,
+ .ai_read = i_APCI3120_InsnReadAnalogInput,
+ .ai_cmdtest = i_APCI3120_CommandTestAnalogInput,
+ .ai_cmd = i_APCI3120_CommandAnalogInput,
+ .ai_cancel = i_APCI3120_StopCyclicAcquisition,
+ .ao_write = i_APCI3120_InsnWriteAnalogOutput,
+ .di_read = i_APCI3120_InsnReadDigitalInput,
+ .di_bits = i_APCI3120_InsnBitsDigitalInput,
+ .do_config = i_APCI3120_InsnConfigDigitalOutput,
+ .do_write = i_APCI3120_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3120_InsnBitsDigitalOutput,
+ .timer_config = i_APCI3120_InsnConfigTimer,
+ .timer_write = i_APCI3120_InsnWriteTimer,
+ .timer_read = i_APCI3120_InsnReadTimer,
+ },
#endif
#ifdef CONFIG_APCI_1032
- {"apci1032",
- APCI1032_BOARD_VENDOR_ID,
- 0x1003,
- 4,
- APCI1032_ADDRESS_RANGE,
- 0,
- 0,
- ADDIDATA_EEPROM,
- ADDIDATA_93C76,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- NULL,
- 32,
- 0,
- 0,
- 0,
- NULL,
- 0,
- 0,
- 0,
- 0,
- 0,
- v_APCI1032_Interrupt,
- i_APCI1032_Reset,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI1032_ConfigDigitalInput,
- i_APCI1032_Read1DigitalInput,
- NULL,
- i_APCI1032_ReadMoreDigitalInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci1032",
+ .i_VendorId = APCI1032_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x1003,
+ .i_IorangeBase0 = 4,
+ .i_IorangeBase1 = APCI1032_ADDRESS_RANGE,
+ .i_PCIEeprom = ADDIDATA_EEPROM,
+ .pc_EepromChip = ADDIDATA_93C76,
+ .i_NbrDiChannel = 32,
+ .interrupt = v_APCI1032_Interrupt,
+ .reset = i_APCI1032_Reset,
+ .di_config = i_APCI1032_ConfigDigitalInput,
+ .di_read = i_APCI1032_Read1DigitalInput,
+ .di_bits = i_APCI1032_ReadMoreDigitalInput,
+ },
#endif
#ifdef CONFIG_APCI_1516
- {"apci1516",
- APCI1516_BOARD_VENDOR_ID,
- 0x1001,
- 128,
- APCI1516_ADDRESS_RANGE,
- 32,
- 0,
- ADDIDATA_EEPROM,
- ADDIDATA_S5920,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- NULL,
- 8,
- 8,
- 0,
- 0,
- NULL,
- 0,
- 1,
- 0,
- 0,
- 0,
- NULL,
- i_APCI1516_Reset,
- NULL, NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI1516_Read1DigitalInput,
- NULL,
- i_APCI1516_ReadMoreDigitalInput,
- i_APCI1516_ConfigDigitalOutput,
- i_APCI1516_WriteDigitalOutput,
- i_APCI1516_ReadDigitalOutput,
- NULL,
- i_APCI1516_ConfigWatchdog,
- i_APCI1516_StartStopWriteWatchdog,
- i_APCI1516_ReadWatchdog,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci1516",
+ .i_VendorId = APCI1516_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x1001,
+ .i_IorangeBase0 = 128,
+ .i_IorangeBase1 = APCI1516_ADDRESS_RANGE,
+ .i_IorangeBase2 = 32,
+ .i_PCIEeprom = ADDIDATA_EEPROM,
+ .pc_EepromChip = ADDIDATA_S5920,
+ .i_NbrDiChannel = 8,
+ .i_NbrDoChannel = 8,
+ .i_Timer = 1,
+ .reset = i_APCI1516_Reset,
+ .di_read = i_APCI1516_Read1DigitalInput,
+ .di_bits = i_APCI1516_ReadMoreDigitalInput,
+ .do_config = i_APCI1516_ConfigDigitalOutput,
+ .do_write = i_APCI1516_WriteDigitalOutput,
+ .do_bits = i_APCI1516_ReadDigitalOutput,
+ .timer_config = i_APCI1516_ConfigWatchdog,
+ .timer_write = i_APCI1516_StartStopWriteWatchdog,
+ .timer_read = i_APCI1516_ReadWatchdog,
+ },
#endif
#ifdef CONFIG_APCI_2016
- {"apci2016",
- APCI2016_BOARD_VENDOR_ID,
- 0x1002,
- 128,
- APCI2016_ADDRESS_RANGE,
- 32,
- 0,
- ADDIDATA_EEPROM,
- ADDIDATA_S5920,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- NULL,
- 0,
- 16,
- 0,
- 0,
- NULL,
- 0,
- 1,
- 0,
- 0,
- 0,
- NULL,
- i_APCI2016_Reset,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI2016_ConfigDigitalOutput,
- i_APCI2016_WriteDigitalOutput,
- i_APCI2016_BitsDigitalOutput,
- NULL,
- i_APCI2016_ConfigWatchdog,
- i_APCI2016_StartStopWriteWatchdog,
- i_APCI2016_ReadWatchdog,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci2016",
+ .i_VendorId = APCI2016_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x1002,
+ .i_IorangeBase0 = 128,
+ .i_IorangeBase1 = APCI2016_ADDRESS_RANGE,
+ .i_IorangeBase2 = 32,
+ .i_PCIEeprom = ADDIDATA_EEPROM,
+ .pc_EepromChip = ADDIDATA_S5920,
+ .i_NbrDoChannel = 16,
+ .i_Timer = 1,
+ .reset = i_APCI2016_Reset,
+ .do_config = i_APCI2016_ConfigDigitalOutput,
+ .do_write = i_APCI2016_WriteDigitalOutput,
+ .do_bits = i_APCI2016_BitsDigitalOutput,
+ .timer_config = i_APCI2016_ConfigWatchdog,
+ .timer_write = i_APCI2016_StartStopWriteWatchdog,
+ .timer_read = i_APCI2016_ReadWatchdog,
+ },
#endif
#ifdef CONFIG_APCI_2032
- {"apci2032",
- APCI2032_BOARD_VENDOR_ID,
- 0x1004,
- 4,
- APCI2032_ADDRESS_RANGE,
- 0,
- 0,
- ADDIDATA_EEPROM,
- ADDIDATA_93C76,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- NULL,
- 0,
- 32,
- 0xffffffff,
- 0,
- NULL,
- 0,
- 1,
- 0,
- 0,
- 0,
- v_APCI2032_Interrupt,
- i_APCI2032_Reset,
- NULL, NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI2032_ConfigDigitalOutput,
- i_APCI2032_WriteDigitalOutput,
- i_APCI2032_ReadDigitalOutput,
- i_APCI2032_ReadInterruptStatus,
- i_APCI2032_ConfigWatchdog,
- i_APCI2032_StartStopWriteWatchdog,
- i_APCI2032_ReadWatchdog,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci2032",
+ .i_VendorId = APCI2032_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x1004,
+ .i_IorangeBase0 = 4,
+ .i_IorangeBase1 = APCI2032_ADDRESS_RANGE,
+ .i_PCIEeprom = ADDIDATA_EEPROM,
+ .pc_EepromChip = ADDIDATA_93C76,
+ .i_NbrDoChannel = 32,
+ .i_DoMaxdata = 0xffffffff,
+ .i_Timer = 1,
+ .interrupt = v_APCI2032_Interrupt,
+ .reset = i_APCI2032_Reset,
+ .do_config = i_APCI2032_ConfigDigitalOutput,
+ .do_write = i_APCI2032_WriteDigitalOutput,
+ .do_bits = i_APCI2032_ReadDigitalOutput,
+ .do_read = i_APCI2032_ReadInterruptStatus,
+ .timer_config = i_APCI2032_ConfigWatchdog,
+ .timer_write = i_APCI2032_StartStopWriteWatchdog,
+ .timer_read = i_APCI2032_ReadWatchdog,
+ },
#endif
#ifdef CONFIG_APCI_2200
- {"apci2200",
- APCI2200_BOARD_VENDOR_ID,
- 0x1005,
- 4,
- APCI2200_ADDRESS_RANGE,
- 0,
- 0,
- ADDIDATA_EEPROM,
- ADDIDATA_93C76,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- NULL,
- 8,
- 16,
- 0,
- 0,
- NULL,
- 0,
- 1,
- 0,
- 0,
- 0,
- NULL,
- i_APCI2200_Reset,
- NULL, NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI2200_Read1DigitalInput,
- NULL,
- i_APCI2200_ReadMoreDigitalInput,
- i_APCI2200_ConfigDigitalOutput,
- i_APCI2200_WriteDigitalOutput,
- i_APCI2200_ReadDigitalOutput,
- NULL,
- i_APCI2200_ConfigWatchdog,
- i_APCI2200_StartStopWriteWatchdog,
- i_APCI2200_ReadWatchdog,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci2200",
+ .i_VendorId = APCI2200_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x1005,
+ .i_IorangeBase0 = 4,
+ .i_IorangeBase1 = APCI2200_ADDRESS_RANGE,
+ .i_PCIEeprom = ADDIDATA_EEPROM,
+ .pc_EepromChip = ADDIDATA_93C76,
+ .i_NbrDiChannel = 8,
+ .i_NbrDoChannel = 16,
+ .i_Timer = 1,
+ .reset = i_APCI2200_Reset,
+ .di_read = i_APCI2200_Read1DigitalInput,
+ .di_bits = i_APCI2200_ReadMoreDigitalInput,
+ .do_config = i_APCI2200_ConfigDigitalOutput,
+ .do_write = i_APCI2200_WriteDigitalOutput,
+ .do_bits = i_APCI2200_ReadDigitalOutput,
+ .timer_config = i_APCI2200_ConfigWatchdog,
+ .timer_write = i_APCI2200_StartStopWriteWatchdog,
+ .timer_read = i_APCI2200_ReadWatchdog,
+ },
#endif
#ifdef CONFIG_APCI_1564
- {"apci1564",
- APCI1564_BOARD_VENDOR_ID,
- 0x1006,
- 128,
- APCI1564_ADDRESS_RANGE,
- 0,
- 0,
- ADDIDATA_EEPROM,
- ADDIDATA_93C76,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- NULL,
- 32,
- 32,
- 0xffffffff,
- 0,
- NULL,
- 0,
- 1,
- 0,
- 0,
- 0,
- v_APCI1564_Interrupt,
- i_APCI1564_Reset,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI1564_ConfigDigitalInput,
- i_APCI1564_Read1DigitalInput,
- NULL,
- i_APCI1564_ReadMoreDigitalInput,
- i_APCI1564_ConfigDigitalOutput,
- i_APCI1564_WriteDigitalOutput,
- i_APCI1564_ReadDigitalOutput,
- i_APCI1564_ReadInterruptStatus,
- i_APCI1564_ConfigTimerCounterWatchdog,
- i_APCI1564_StartStopWriteTimerCounterWatchdog,
- i_APCI1564_ReadTimerCounterWatchdog,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci1564",
+ .i_VendorId = APCI1564_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x1006,
+ .i_IorangeBase0 = 128,
+ .i_IorangeBase1 = APCI1564_ADDRESS_RANGE,
+ .i_PCIEeprom = ADDIDATA_EEPROM,
+ .pc_EepromChip = ADDIDATA_93C76,
+ .i_NbrDiChannel = 32,
+ .i_NbrDoChannel = 32,
+ .i_DoMaxdata = 0xffffffff,
+ .i_Timer = 1,
+ .interrupt = v_APCI1564_Interrupt,
+ .reset = i_APCI1564_Reset,
+ .di_config = i_APCI1564_ConfigDigitalInput,
+ .di_read = i_APCI1564_Read1DigitalInput,
+ .di_bits = i_APCI1564_ReadMoreDigitalInput,
+ .do_config = i_APCI1564_ConfigDigitalOutput,
+ .do_write = i_APCI1564_WriteDigitalOutput,
+ .do_bits = i_APCI1564_ReadDigitalOutput,
+ .do_read = i_APCI1564_ReadInterruptStatus,
+ .timer_config = i_APCI1564_ConfigTimerCounterWatchdog,
+ .timer_write = i_APCI1564_StartStopWriteTimerCounterWatchdog,
+ .timer_read = i_APCI1564_ReadTimerCounterWatchdog,
+ },
#endif
#ifdef CONFIG_APCI_1500
- {"apci1500",
- APCI1500_BOARD_VENDOR_ID,
- 0x80fc,
- 128,
- APCI1500_ADDRESS_RANGE,
- 4,
- 0,
- ADDIDATA_NO_EEPROM,
- NULL,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- NULL,
- 16,
- 16,
- 0xffff,
- 0,
- NULL,
- 0,
- 1,
- 0,
- 0,
- 0,
- v_APCI1500_Interrupt,
- i_APCI1500_Reset,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI1500_ConfigDigitalInputEvent,
- i_APCI1500_Initialisation,
- i_APCI1500_StartStopInputEvent,
- i_APCI1500_ReadMoreDigitalInput,
- i_APCI1500_ConfigDigitalOutputErrorInterrupt,
- i_APCI1500_WriteDigitalOutput,
- i_APCI1500_ConfigureInterrupt,
- NULL,
- i_APCI1500_ConfigCounterTimerWatchdog,
- i_APCI1500_StartStopTriggerTimerCounterWatchdog,
- i_APCI1500_ReadInterruptMask,
- i_APCI1500_ReadCounterTimerWatchdog,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci1500",
+ .i_VendorId = APCI1500_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x80fc,
+ .i_IorangeBase0 = 128,
+ .i_IorangeBase1 = APCI1500_ADDRESS_RANGE,
+ .i_IorangeBase2 = 4,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .i_NbrDiChannel = 16,
+ .i_NbrDoChannel = 16,
+ .i_DoMaxdata = 0xffff,
+ .i_Timer = 1,
+ .interrupt = v_APCI1500_Interrupt,
+ .reset = i_APCI1500_Reset,
+ .di_config = i_APCI1500_ConfigDigitalInputEvent,
+ .di_read = i_APCI1500_Initialisation,
+ .di_write = i_APCI1500_StartStopInputEvent,
+ .di_bits = i_APCI1500_ReadMoreDigitalInput,
+ .do_config = i_APCI1500_ConfigDigitalOutputErrorInterrupt,
+ .do_write = i_APCI1500_WriteDigitalOutput,
+ .do_bits = i_APCI1500_ConfigureInterrupt,
+ .timer_config = i_APCI1500_ConfigCounterTimerWatchdog,
+ .timer_write = i_APCI1500_StartStopTriggerTimerCounterWatchdog,
+ .timer_read = i_APCI1500_ReadInterruptMask,
+ .timer_bits = i_APCI1500_ReadCounterTimerWatchdog,
+ },
#endif
#ifdef CONFIG_APCI_3001
- {"apci3001",
- APCI3120_BOARD_VENDOR_ID,
- 0x828D,
- AMCC_OP_REG_SIZE,
- APCI3120_ADDRESS_RANGE,
- 8,
- 0,
- ADDIDATA_NO_EEPROM,
- NULL,
- 16,
- 8,
- 16,
- 0,
- 0xfff,
- 0,
- &range_apci3120_ai,
- NULL,
- 4,
- 4,
- 0x0f,
- 0,
- NULL,
- 1,
- 1,
- 1,
- 10000,
- 100000,
- v_APCI3120_Interrupt,
- i_APCI3120_Reset,
- i_APCI3120_InsnConfigAnalogInput,
- i_APCI3120_InsnReadAnalogInput,
- NULL,
- NULL,
- i_APCI3120_CommandTestAnalogInput,
- i_APCI3120_CommandAnalogInput,
- i_APCI3120_StopCyclicAcquisition,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3120_InsnReadDigitalInput,
- NULL,
- i_APCI3120_InsnBitsDigitalInput,
- i_APCI3120_InsnConfigDigitalOutput,
- i_APCI3120_InsnWriteDigitalOutput,
- i_APCI3120_InsnBitsDigitalOutput,
- NULL,
- i_APCI3120_InsnConfigTimer,
- i_APCI3120_InsnWriteTimer,
- i_APCI3120_InsnReadTimer,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci3001",
+ .i_VendorId = APCI3120_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x828D,
+ .i_IorangeBase0 = AMCC_OP_REG_SIZE,
+ .i_IorangeBase1 = APCI3120_ADDRESS_RANGE,
+ .i_IorangeBase2 = 8,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_AiMaxdata = 0xfff,
+ .pr_AiRangelist = &range_apci3120_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 0x0f,
+ .i_Dma = 1,
+ .i_Timer = 1,
+ .b_AvailableConvertUnit = 1,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .ui_MinDelaytimeNs = 100000,
+ .interrupt = v_APCI3120_Interrupt,
+ .reset = i_APCI3120_Reset,
+ .ai_config = i_APCI3120_InsnConfigAnalogInput,
+ .ai_read = i_APCI3120_InsnReadAnalogInput,
+ .ai_cmdtest = i_APCI3120_CommandTestAnalogInput,
+ .ai_cmd = i_APCI3120_CommandAnalogInput,
+ .ai_cancel = i_APCI3120_StopCyclicAcquisition,
+ .di_read = i_APCI3120_InsnReadDigitalInput,
+ .di_bits = i_APCI3120_InsnBitsDigitalInput,
+ .do_config = i_APCI3120_InsnConfigDigitalOutput,
+ .do_write = i_APCI3120_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3120_InsnBitsDigitalOutput,
+ .timer_config = i_APCI3120_InsnConfigTimer,
+ .timer_write = i_APCI3120_InsnWriteTimer,
+ .timer_read = i_APCI3120_InsnReadTimer,
+ },
#endif
#ifdef CONFIG_APCI_3501
- {"apci3501",
- APCI3501_BOARD_VENDOR_ID,
- 0x3001,
- 64,
- APCI3501_ADDRESS_RANGE,
- 0,
- 0,
- ADDIDATA_EEPROM,
- ADDIDATA_S5933,
- 0,
- 0,
- 0,
- 8,
- 0,
- 16383,
- NULL,
- &range_apci3501_ao,
- 2,
- 2,
- 0x3,
- 0,
- NULL,
- 0,
- 1,
- 0,
- 0,
- 0,
- v_APCI3501_Interrupt,
- i_APCI3501_Reset,
- NULL, NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3501_ConfigAnalogOutput,
- i_APCI3501_WriteAnalogOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3501_ReadDigitalInput,
- i_APCI3501_ConfigDigitalOutput,
- i_APCI3501_WriteDigitalOutput,
- i_APCI3501_ReadDigitalOutput,
- NULL,
- i_APCI3501_ConfigTimerCounterWatchdog,
- i_APCI3501_StartStopWriteTimerCounterWatchdog,
- i_APCI3501_ReadTimerCounterWatchdog,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci3501",
+ .i_VendorId = APCI3501_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x3001,
+ .i_IorangeBase0 = 64,
+ .i_IorangeBase1 = APCI3501_ADDRESS_RANGE,
+ .i_PCIEeprom = ADDIDATA_EEPROM,
+ .pc_EepromChip = ADDIDATA_S5933,
+ .i_AoMaxdata = 16383,
+ .pr_AoRangelist = &range_apci3501_ao,
+ .i_NbrDiChannel = 2,
+ .i_NbrDoChannel = 2,
+ .i_DoMaxdata = 0x3,
+ .i_Timer = 1,
+ .interrupt = v_APCI3501_Interrupt,
+ .reset = i_APCI3501_Reset,
+ .ao_config = i_APCI3501_ConfigAnalogOutput,
+ .ao_write = i_APCI3501_WriteAnalogOutput,
+ .di_bits = i_APCI3501_ReadDigitalInput,
+ .do_config = i_APCI3501_ConfigDigitalOutput,
+ .do_write = i_APCI3501_WriteDigitalOutput,
+ .do_bits = i_APCI3501_ReadDigitalOutput,
+ .timer_config = i_APCI3501_ConfigTimerCounterWatchdog,
+ .timer_write = i_APCI3501_StartStopWriteTimerCounterWatchdog,
+ .timer_read = i_APCI3501_ReadTimerCounterWatchdog,
+ },
#endif
#ifdef CONFIG_APCI_035
- {"apci035",
- APCI035_BOARD_VENDOR_ID,
- 0x0300,
- 127,
- APCI035_ADDRESS_RANGE,
- 0,
- 0,
- 1,
- ADDIDATA_S5920,
- 16,
- 8,
- 16,
- 0,
- 0xff,
- 0,
- &range_apci035_ai,
- NULL,
- 0,
- 0,
- 0,
- 0,
- NULL,
- 0,
- 1,
- 0,
- 10000,
- 100000,
- v_APCI035_Interrupt,
- i_APCI035_Reset,
- i_APCI035_ConfigAnalogInput,
- i_APCI035_ReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI035_ConfigTimerWatchdog,
- i_APCI035_StartStopWriteTimerWatchdog,
- i_APCI035_ReadTimerWatchdog,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci035",
+ .i_VendorId = APCI035_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x0300,
+ .i_IorangeBase0 = 127,
+ .i_IorangeBase1 = APCI035_ADDRESS_RANGE,
+ .i_PCIEeprom = 1,
+ .pc_EepromChip = ADDIDATA_S5920,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_AiMaxdata = 0xff,
+ .pr_AiRangelist = &range_apci035_ai,
+ .i_Timer = 1,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .ui_MinDelaytimeNs = 100000,
+ .interrupt = v_APCI035_Interrupt,
+ .reset = i_APCI035_Reset,
+ .ai_config = i_APCI035_ConfigAnalogInput,
+ .ai_read = i_APCI035_ReadAnalogInput,
+ .timer_config = i_APCI035_ConfigTimerWatchdog,
+ .timer_write = i_APCI035_StartStopWriteTimerWatchdog,
+ .timer_read = i_APCI035_ReadTimerWatchdog,
+ },
#endif
#ifdef CONFIG_APCI_3200
- {"apci3200",
- APCI3200_BOARD_VENDOR_ID,
- 0x3000,
- 128,
- 256,
- 4,
- 4,
- ADDIDATA_EEPROM,
- ADDIDATA_S5920,
- 16,
- 8,
- 16,
- 0,
- 0x3ffff,
- 0,
- &range_apci3200_ai,
- NULL,
- 4,
- 4,
- 0,
- 0,
- NULL,
- 0,
- 0,
- 0,
- 10000,
- 100000,
- v_APCI3200_Interrupt,
- i_APCI3200_Reset,
- i_APCI3200_ConfigAnalogInput,
- i_APCI3200_ReadAnalogInput,
- i_APCI3200_InsnWriteReleaseAnalogInput,
- i_APCI3200_InsnBits_AnalogInput_Test,
- i_APCI3200_CommandTestAnalogInput,
- i_APCI3200_CommandAnalogInput,
- i_APCI3200_StopCyclicAcquisition,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3200_ReadDigitalInput,
- i_APCI3200_ConfigDigitalOutput,
- i_APCI3200_WriteDigitalOutput,
- i_APCI3200_ReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci3200",
+ .i_VendorId = APCI3200_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x3000,
+ .i_IorangeBase0 = 128,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 4,
+ .i_IorangeBase3 = 4,
+ .i_PCIEeprom = ADDIDATA_EEPROM,
+ .pc_EepromChip = ADDIDATA_S5920,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_AiMaxdata = 0x3ffff,
+ .pr_AiRangelist = &range_apci3200_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .ui_MinDelaytimeNs = 100000,
+ .interrupt = v_APCI3200_Interrupt,
+ .reset = i_APCI3200_Reset,
+ .ai_config = i_APCI3200_ConfigAnalogInput,
+ .ai_read = i_APCI3200_ReadAnalogInput,
+ .ai_write = i_APCI3200_InsnWriteReleaseAnalogInput,
+ .ai_bits = i_APCI3200_InsnBits_AnalogInput_Test,
+ .ai_cmdtest = i_APCI3200_CommandTestAnalogInput,
+ .ai_cmd = i_APCI3200_CommandAnalogInput,
+ .ai_cancel = i_APCI3200_StopCyclicAcquisition,
+ .di_bits = i_APCI3200_ReadDigitalInput,
+ .do_config = i_APCI3200_ConfigDigitalOutput,
+ .do_write = i_APCI3200_WriteDigitalOutput,
+ .do_bits = i_APCI3200_ReadDigitalOutput,
+ },
#endif
#ifdef CONFIG_APCI_3300
/* Begin JK .20.10.2004 = APCI-3300 integration */
- {"apci3300",
- APCI3200_BOARD_VENDOR_ID,
- 0x3007,
- 128,
- 256,
- 4,
- 4,
- ADDIDATA_EEPROM,
- ADDIDATA_S5920,
- 0,
- 8,
- 8,
- 0,
- 0x3ffff,
- 0,
- &range_apci3300_ai,
- NULL,
- 4,
- 4,
- 0,
- 0,
- NULL,
- 0,
- 0,
- 0,
- 10000,
- 100000,
- v_APCI3200_Interrupt,
- i_APCI3200_Reset,
- i_APCI3200_ConfigAnalogInput,
- i_APCI3200_ReadAnalogInput,
- i_APCI3200_InsnWriteReleaseAnalogInput,
- i_APCI3200_InsnBits_AnalogInput_Test,
- i_APCI3200_CommandTestAnalogInput,
- i_APCI3200_CommandAnalogInput,
- i_APCI3200_StopCyclicAcquisition,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3200_ReadDigitalInput,
- i_APCI3200_ConfigDigitalOutput,
- i_APCI3200_WriteDigitalOutput,
- i_APCI3200_ReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci3300",
+ .i_VendorId = APCI3200_BOARD_VENDOR_ID,
+ .i_DeviceId = 0x3007,
+ .i_IorangeBase0 = 128,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 4,
+ .i_IorangeBase3 = 4,
+ .i_PCIEeprom = ADDIDATA_EEPROM,
+ .pc_EepromChip = ADDIDATA_S5920,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 8,
+ .i_AiMaxdata = 0x3ffff,
+ .pr_AiRangelist = &range_apci3300_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .ui_MinDelaytimeNs = 100000,
+ .interrupt = v_APCI3200_Interrupt,
+ .reset = i_APCI3200_Reset,
+ .ai_config = i_APCI3200_ConfigAnalogInput,
+ .ai_read = i_APCI3200_ReadAnalogInput,
+ .ai_write = i_APCI3200_InsnWriteReleaseAnalogInput,
+ .ai_bits = i_APCI3200_InsnBits_AnalogInput_Test,
+ .ai_cmdtest = i_APCI3200_CommandTestAnalogInput,
+ .ai_cmd = i_APCI3200_CommandAnalogInput,
+ .ai_cancel = i_APCI3200_StopCyclicAcquisition,
+ .di_bits = i_APCI3200_ReadDigitalInput,
+ .do_config = i_APCI3200_ConfigDigitalOutput,
+ .do_write = i_APCI3200_WriteDigitalOutput,
+ .do_bits = i_APCI3200_ReadDigitalOutput,
+ },
#endif
#ifdef CONFIG_APCI_1710
- {"apci1710", APCI1710_BOARD_VENDOR_ID, APCI1710_BOARD_DEVICE_ID,
- 128,
- 8,
- 256,
- 0,
- ADDIDATA_NO_EEPROM,
- NULL,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- NULL,
- 0,
- 0,
- 0,
- 0,
- NULL,
- 0,
- 0,
- 0,
- 0,
- 0,
- v_APCI1710_Interrupt,
- i_APCI1710_Reset,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
+ {
+ .pc_DriverName = "apci1710",
+ .i_VendorId = APCI1710_BOARD_VENDOR_ID,
+ .i_DeviceId = APCI1710_BOARD_DEVICE_ID,
+ .i_IorangeBase0 = 128,
+ .i_IorangeBase1 = 8,
+ .i_IorangeBase2 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .interrupt = v_APCI1710_Interrupt,
+ .reset = i_APCI1710_Reset,
+ },
#endif
#ifdef CONFIG_APCI_16XX
- {"apci1648",
- PCI_VENDOR_ID_ADDIDATA,
- 0x1009,
- 128,
- 0,
- 0,
- 0,
- ADDIDATA_NO_EEPROM,
- NULL,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- NULL,
- 0,
- 0,
- 0,
- 48,
- &range_apci16xx_ttl,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- i_APCI16XX_Reset,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI16XX_InsnConfigInitTTLIO,
- i_APCI16XX_InsnBitsReadTTLIO,
- i_APCI16XX_InsnReadTTLIOAllPortValue,
- i_APCI16XX_InsnBitsWriteTTLIO},
-
- {"apci1696",
- PCI_VENDOR_ID_ADDIDATA,
- 0x100A,
- 128,
- 0,
- 0,
- 0,
- ADDIDATA_NO_EEPROM,
- NULL,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- NULL,
- 0,
- 0,
- 0,
- 96,
- &range_apci16xx_ttl,
- 0,
- 0,
- 0,
- 0,
- 0,
- NULL,
- i_APCI16XX_Reset,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI16XX_InsnConfigInitTTLIO,
- i_APCI16XX_InsnBitsReadTTLIO,
- i_APCI16XX_InsnReadTTLIOAllPortValue,
- i_APCI16XX_InsnBitsWriteTTLIO},
+ {
+ .pc_DriverName = "apci1648",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x1009,
+ .i_IorangeBase0 = 128,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .i_NbrTTLChannel = 48,
+ .pr_TTLRangelist = &range_apci16xx_ttl,
+ .reset = i_APCI16XX_Reset,
+ .ttl_config = i_APCI16XX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI16XX_InsnBitsReadTTLIO,
+ .ttl_read = i_APCI16XX_InsnReadTTLIOAllPortValue,
+ .ttl_write = i_APCI16XX_InsnBitsWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci1696",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x100A,
+ .i_IorangeBase0 = 128,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .i_NbrTTLChannel = 96,
+ .pr_TTLRangelist = &range_apci16xx_ttl,
+ .reset = i_APCI16XX_Reset,
+ .ttl_config = i_APCI16XX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI16XX_InsnBitsReadTTLIO,
+ .ttl_read = i_APCI16XX_InsnReadTTLIOAllPortValue,
+ .ttl_write = i_APCI16XX_InsnBitsWriteTTLIO,
+ },
#endif
#ifdef CONFIG_APCI_3XXX
- {"apci3000-16",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3010,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 16,
- 8,
- 16,
- 0,
- 4095,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 0,
- 0,
- 0,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 10000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3000-8",
- PCI_VENDOR_ID_ADDIDATA,
- 0x300F,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 8,
- 4,
- 8,
- 0,
- 4095,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 0,
- 0,
- 0,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 10000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3000-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x300E,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 4,
- 2,
- 4,
- 0,
- 4095,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 0,
- 0,
- 0,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 10000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3006-16",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3013,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 16,
- 8,
- 16,
- 0,
- 65535,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 0,
- 0,
- 0,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 10000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3006-8",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3014,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 8,
- 4,
- 8,
- 0,
- 65535,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 0,
- 0,
- 0,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 10000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3006-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3015,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 4,
- 2,
- 4,
- 0,
- 65535,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 0,
- 0,
- 0,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 10000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3010-16",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3016,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 16,
- 8,
- 16,
- 0,
- 4095,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 4,
- 4,
- 1,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3010-8",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3017,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 8,
- 4,
- 8,
- 0,
- 4095,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 4,
- 4,
- 1,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3010-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3018,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 4,
- 2,
- 4,
- 0,
- 4095,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 4,
- 4,
- 1,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3016-16",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3019,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 16,
- 8,
- 16,
- 0,
- 65535,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 4,
- 4,
- 1,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3016-8",
- PCI_VENDOR_ID_ADDIDATA,
- 0x301A,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 8,
- 4,
- 8,
- 0,
- 65535,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 4,
- 4,
- 1,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3016-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x301B,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 4,
- 2,
- 4,
- 0,
- 65535,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 4,
- 4,
- 1,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3100-16-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x301C,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 16,
- 8,
- 16,
- 4,
- 4095,
- 4095,
- &range_apci3XXX_ai,
- &range_apci3XXX_ao,
- 0,
- 0,
- 0,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 10000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnWriteAnalogOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3100-8-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x301D,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 8,
- 4,
- 8,
- 4,
- 4095,
- 4095,
- &range_apci3XXX_ai,
- &range_apci3XXX_ao,
- 0,
- 0,
- 0,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 10000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnWriteAnalogOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3106-16-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x301E,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 16,
- 8,
- 16,
- 4,
- 65535,
- 4095,
- &range_apci3XXX_ai,
- &range_apci3XXX_ao,
- 0,
- 0,
- 0,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 10000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnWriteAnalogOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3106-8-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x301F,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 8,
- 4,
- 8,
- 4,
- 65535,
- 4095,
- &range_apci3XXX_ai,
- &range_apci3XXX_ao,
- 0,
- 0,
- 0,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 10000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnWriteAnalogOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3110-16-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3020,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 16,
- 8,
- 16,
- 4,
- 4095,
- 4095,
- &range_apci3XXX_ai,
- &range_apci3XXX_ao,
- 4,
- 4,
- 1,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnWriteAnalogOutput,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3110-8-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3021,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 8,
- 4,
- 8,
- 4,
- 4095,
- 4095,
- &range_apci3XXX_ai,
- &range_apci3XXX_ao,
- 4,
- 4,
- 1,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnWriteAnalogOutput,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3116-16-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3022,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 16,
- 8,
- 16,
- 4,
- 65535,
- 4095,
- &range_apci3XXX_ai,
- &range_apci3XXX_ao,
- 4,
- 4,
- 1,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnWriteAnalogOutput,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3116-8-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3023,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 8,
- 4,
- 8,
- 4,
- 65535,
- 4095,
- &range_apci3XXX_ai,
- &range_apci3XXX_ao,
- 4,
- 4,
- 1,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnWriteAnalogOutput,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
-
- {"apci3003",
- PCI_VENDOR_ID_ADDIDATA,
- 0x300B,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 0,
- 4,
- 4,
- 0,
- 65535,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 4,
- 4,
- 1,
- 0,
- NULL,
- 0,
- 0,
- 7,
- 2500,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
-
- {"apci3002-16",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3002,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 0,
- 16,
- 16,
- 0,
- 65535,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 4,
- 4,
- 1,
- 0,
- NULL,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
-
- {"apci3002-8",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3003,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 0,
- 8,
- 8,
- 0,
- 65535,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 4,
- 4,
- 1,
- 0,
- NULL,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
-
- {"apci3002-4",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3004,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 0,
- 4,
- 4,
- 0,
- 65535,
- 0,
- &range_apci3XXX_ai,
- NULL,
- 4,
- 4,
- 1,
- 0,
- NULL,
- 0,
- 0,
- 6,
- 5000,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- i_APCI3XXX_InsnConfigAnalogInput,
- i_APCI3XXX_InsnReadAnalogInput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnReadDigitalInput,
- NULL,
- i_APCI3XXX_InsnBitsDigitalInput,
- NULL,
- i_APCI3XXX_InsnWriteDigitalOutput,
- i_APCI3XXX_InsnBitsDigitalOutput,
- i_APCI3XXX_InsnReadDigitalOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL},
-
- {"apci3500",
- PCI_VENDOR_ID_ADDIDATA,
- 0x3024,
- 256,
- 256,
- 256,
- 256,
- ADDIDATA_NO_EEPROM,
- ADDIDATA_9054,
- 0,
- 0,
- 0,
- 4,
- 0,
- 4095,
- NULL,
- &range_apci3XXX_ao,
- 0,
- 0,
- 0,
- 24,
- &range_apci3XXX_ttl,
- 0,
- 0,
- 0,
- 0,
- 0,
- v_APCI3XXX_Interrupt,
- i_APCI3XXX_Reset,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnWriteAnalogOutput,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- i_APCI3XXX_InsnConfigInitTTLIO,
- i_APCI3XXX_InsnBitsTTLIO,
- i_APCI3XXX_InsnReadTTLIO,
- i_APCI3XXX_InsnWriteTTLIO},
+ {
+ .pc_DriverName = "apci3000-16",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3010,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_AiMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3000-8",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x300F,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 8,
+ .i_NbrAiChannelDiff = 4,
+ .i_AiChannelList = 8,
+ .i_AiMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3000-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x300E,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 4,
+ .i_NbrAiChannelDiff = 2,
+ .i_AiChannelList = 4,
+ .i_AiMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3006-16",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3013,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_AiMaxdata = 65535,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3006-8",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3014,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 8,
+ .i_NbrAiChannelDiff = 4,
+ .i_AiChannelList = 8,
+ .i_AiMaxdata = 65535,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3006-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3015,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 4,
+ .i_NbrAiChannelDiff = 2,
+ .i_AiChannelList = 4,
+ .i_AiMaxdata = 65535,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3010-16",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3016,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_AiMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3010-8",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3017,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 8,
+ .i_NbrAiChannelDiff = 4,
+ .i_AiChannelList = 8,
+ .i_AiMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3010-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3018,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 4,
+ .i_NbrAiChannelDiff = 2,
+ .i_AiChannelList = 4,
+ .i_AiMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3016-16",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3019,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_AiMaxdata = 65535,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3016-8",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x301A,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 8,
+ .i_NbrAiChannelDiff = 4,
+ .i_AiChannelList = 8,
+ .i_AiMaxdata = 65535,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3016-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x301B,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 4,
+ .i_NbrAiChannelDiff = 2,
+ .i_AiChannelList = 4,
+ .i_AiMaxdata = 65535,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3100-16-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x301C,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_NbrAoChannel = 4,
+ .i_AiMaxdata = 4095,
+ .i_AoMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .pr_AoRangelist = &range_apci3XXX_ao,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ao_write = i_APCI3XXX_InsnWriteAnalogOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3100-8-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x301D,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 8,
+ .i_NbrAiChannelDiff = 4,
+ .i_AiChannelList = 8,
+ .i_NbrAoChannel = 4,
+ .i_AiMaxdata = 4095,
+ .i_AoMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .pr_AoRangelist = &range_apci3XXX_ao,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ao_write = i_APCI3XXX_InsnWriteAnalogOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3106-16-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x301E,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_NbrAoChannel = 4,
+ .i_AiMaxdata = 65535,
+ .i_AoMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .pr_AoRangelist = &range_apci3XXX_ao,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ao_write = i_APCI3XXX_InsnWriteAnalogOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3106-8-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x301F,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 8,
+ .i_NbrAiChannelDiff = 4,
+ .i_AiChannelList = 8,
+ .i_NbrAoChannel = 4,
+ .i_AiMaxdata = 65535,
+ .i_AoMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .pr_AoRangelist = &range_apci3XXX_ao,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 10000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ao_write = i_APCI3XXX_InsnWriteAnalogOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3110-16-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3020,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_NbrAoChannel = 4,
+ .i_AiMaxdata = 4095,
+ .i_AoMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .pr_AoRangelist = &range_apci3XXX_ao,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ao_write = i_APCI3XXX_InsnWriteAnalogOutput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3110-8-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3021,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 8,
+ .i_NbrAiChannelDiff = 4,
+ .i_AiChannelList = 8,
+ .i_NbrAoChannel = 4,
+ .i_AiMaxdata = 4095,
+ .i_AoMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .pr_AoRangelist = &range_apci3XXX_ao,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ao_write = i_APCI3XXX_InsnWriteAnalogOutput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3116-16-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3022,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 16,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 16,
+ .i_NbrAoChannel = 4,
+ .i_AiMaxdata = 65535,
+ .i_AoMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .pr_AoRangelist = &range_apci3XXX_ao,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ao_write = i_APCI3XXX_InsnWriteAnalogOutput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3116-8-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3023,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannel = 8,
+ .i_NbrAiChannelDiff = 4,
+ .i_AiChannelList = 8,
+ .i_NbrAoChannel = 4,
+ .i_AiMaxdata = 65535,
+ .i_AoMaxdata = 4095,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .pr_AoRangelist = &range_apci3XXX_ao,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .ao_write = i_APCI3XXX_InsnWriteAnalogOutput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ }, {
+ .pc_DriverName = "apci3003",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x300B,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannelDiff = 4,
+ .i_AiChannelList = 4,
+ .i_AiMaxdata = 65535,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .b_AvailableConvertUnit = 7,
+ .ui_MinAcquisitiontimeNs = 2500,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ }, {
+ .pc_DriverName = "apci3002-16",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3002,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannelDiff = 16,
+ .i_AiChannelList = 16,
+ .i_AiMaxdata = 65535,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ }, {
+ .pc_DriverName = "apci3002-8",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3003,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannelDiff = 8,
+ .i_AiChannelList = 8,
+ .i_AiMaxdata = 65535,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ }, {
+ .pc_DriverName = "apci3002-4",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3004,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAiChannelDiff = 4,
+ .i_AiChannelList = 4,
+ .i_AiMaxdata = 65535,
+ .pr_AiRangelist = &range_apci3XXX_ai,
+ .i_NbrDiChannel = 4,
+ .i_NbrDoChannel = 4,
+ .i_DoMaxdata = 1,
+ .b_AvailableConvertUnit = 6,
+ .ui_MinAcquisitiontimeNs = 5000,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ai_config = i_APCI3XXX_InsnConfigAnalogInput,
+ .ai_read = i_APCI3XXX_InsnReadAnalogInput,
+ .di_read = i_APCI3XXX_InsnReadDigitalInput,
+ .di_bits = i_APCI3XXX_InsnBitsDigitalInput,
+ .do_write = i_APCI3XXX_InsnWriteDigitalOutput,
+ .do_bits = i_APCI3XXX_InsnBitsDigitalOutput,
+ .do_read = i_APCI3XXX_InsnReadDigitalOutput,
+ }, {
+ .pc_DriverName = "apci3500",
+ .i_VendorId = PCI_VENDOR_ID_ADDIDATA,
+ .i_DeviceId = 0x3024,
+ .i_IorangeBase0 = 256,
+ .i_IorangeBase1 = 256,
+ .i_IorangeBase2 = 256,
+ .i_IorangeBase3 = 256,
+ .i_PCIEeprom = ADDIDATA_NO_EEPROM,
+ .pc_EepromChip = ADDIDATA_9054,
+ .i_NbrAoChannel = 4,
+ .i_AoMaxdata = 4095,
+ .pr_AoRangelist = &range_apci3XXX_ao,
+ .i_NbrTTLChannel = 24,
+ .pr_TTLRangelist = &range_apci3XXX_ttl,
+ .interrupt = v_APCI3XXX_Interrupt,
+ .reset = i_APCI3XXX_Reset,
+ .ao_write = i_APCI3XXX_InsnWriteAnalogOutput,
+ .ttl_config = i_APCI3XXX_InsnConfigInitTTLIO,
+ .ttl_bits = i_APCI3XXX_InsnBitsTTLIO,
+ .ttl_read = i_APCI3XXX_InsnReadTTLIO,
+ .ttl_write = i_APCI3XXX_InsnWriteTTLIO,
+ },
#endif
};
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct addi_board))
-
static struct comedi_driver driver_addi = {
.driver_name = ADDIDATA_DRIVER_NAME,
.module = THIS_MODULE,
.attach = i_ADDI_Attach,
.detach = i_ADDI_Detach,
- .num_names = n_boardtypes,
+ .num_names = ARRAY_SIZE(boardtypes),
.board_name = &boardtypes[0].pc_DriverName,
.offset = sizeof(struct addi_board),
};
@@ -2543,7 +1438,7 @@ static struct comedi_driver driver_addi = {
static int __devinit driver_addi_pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_addi.driver_name);
+ return comedi_pci_auto_config(dev, &driver_addi);
}
static void __devexit driver_addi_pci_remove(struct pci_dev *dev)
@@ -2821,16 +1716,13 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* Set the initialisation flag */
devpriv->b_AiInitialisation = 1;
- s->insn_config =
- this_board->i_hwdrv_InsnConfigAnalogInput;
- s->insn_read = this_board->i_hwdrv_InsnReadAnalogInput;
- s->insn_write =
- this_board->i_hwdrv_InsnWriteAnalogInput;
- s->insn_bits = this_board->i_hwdrv_InsnBitsAnalogInput;
- s->do_cmdtest =
- this_board->i_hwdrv_CommandTestAnalogInput;
- s->do_cmd = this_board->i_hwdrv_CommandAnalogInput;
- s->cancel = this_board->i_hwdrv_CancelAnalogInput;
+ s->insn_config = this_board->ai_config;
+ s->insn_read = this_board->ai_read;
+ s->insn_write = this_board->ai_write;
+ s->insn_bits = this_board->ai_bits;
+ s->do_cmdtest = this_board->ai_cmdtest;
+ s->do_cmd = this_board->ai_cmd;
+ s->cancel = this_board->ai_cancel;
} else {
s->type = COMEDI_SUBD_UNUSED;
@@ -2846,10 +1738,8 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->len_chanlist =
devpriv->s_EeParameters.i_NbrAoChannel;
s->range_table = this_board->pr_AoRangelist;
- s->insn_config =
- this_board->i_hwdrv_InsnConfigAnalogOutput;
- s->insn_write =
- this_board->i_hwdrv_InsnWriteAnalogOutput;
+ s->insn_config = this_board->ao_config;
+ s->insn_write = this_board->ao_write;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
@@ -2864,12 +1754,10 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it)
devpriv->s_EeParameters.i_NbrDiChannel;
s->range_table = &range_digital;
s->io_bits = 0; /* all bits input */
- s->insn_config =
- this_board->i_hwdrv_InsnConfigDigitalInput;
- s->insn_read = this_board->i_hwdrv_InsnReadDigitalInput;
- s->insn_write =
- this_board->i_hwdrv_InsnWriteDigitalInput;
- s->insn_bits = this_board->i_hwdrv_InsnBitsDigitalInput;
+ s->insn_config = this_board->di_config;
+ s->insn_read = this_board->di_read;
+ s->insn_write = this_board->di_write;
+ s->insn_bits = this_board->di_bits;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
@@ -2886,13 +1774,11 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->range_table = &range_digital;
s->io_bits = 0xf; /* all bits output */
- s->insn_config = this_board->i_hwdrv_InsnConfigDigitalOutput; /* for digital output memory.. */
- s->insn_write =
- this_board->i_hwdrv_InsnWriteDigitalOutput;
- s->insn_bits =
- this_board->i_hwdrv_InsnBitsDigitalOutput;
- s->insn_read =
- this_board->i_hwdrv_InsnReadDigitalOutput;
+ /* insn_config - for digital output memory */
+ s->insn_config = this_board->do_config;
+ s->insn_write = this_board->do_write;
+ s->insn_bits = this_board->do_bits;
+ s->insn_read = this_board->do_read;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
@@ -2907,10 +1793,10 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->len_chanlist = 1;
s->range_table = &range_digital;
- s->insn_write = this_board->i_hwdrv_InsnWriteTimer;
- s->insn_read = this_board->i_hwdrv_InsnReadTimer;
- s->insn_config = this_board->i_hwdrv_InsnConfigTimer;
- s->insn_bits = this_board->i_hwdrv_InsnBitsTimer;
+ s->insn_write = this_board->timer_write;
+ s->insn_read = this_board->timer_read;
+ s->insn_config = this_board->timer_config;
+ s->insn_bits = this_board->timer_bits;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
@@ -2926,10 +1812,10 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->io_bits = 0; /* all bits input */
s->len_chanlist = this_board->i_NbrTTLChannel;
s->range_table = &range_digital;
- s->insn_config = this_board->i_hwdr_ConfigInitTTLIO;
- s->insn_bits = this_board->i_hwdr_ReadTTLIOBits;
- s->insn_read = this_board->i_hwdr_ReadTTLIOAllPortValue;
- s->insn_write = this_board->i_hwdr_WriteTTLIOChlOnOff;
+ s->insn_config = this_board->ttl_config;
+ s->insn_bits = this_board->ttl_bits;
+ s->insn_read = this_board->ttl_read;
+ s->insn_write = this_board->ttl_write;
} else {
s->type = COMEDI_SUBD_UNUSED;
}
@@ -2953,50 +1839,22 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-/*
-+----------------------------------------------------------------------------+
-| Function name : static int i_ADDI_Detach(struct comedi_device *dev) |
-| |
-| |
-+----------------------------------------------------------------------------+
-| Task : Deallocates resources of the addi_common driver |
-| Free the DMA buffers, unregister irq. |
-| |
-+----------------------------------------------------------------------------+
-| Input Parameters : struct comedi_device *dev |
-| |
-| |
-+----------------------------------------------------------------------------+
-| Return Value : 0 |
-| |
-+----------------------------------------------------------------------------+
-*/
-
-static int i_ADDI_Detach(struct comedi_device *dev)
+static void i_ADDI_Detach(struct comedi_device *dev)
{
-
if (dev->private) {
- if (devpriv->b_ValidDriver) {
+ if (devpriv->b_ValidDriver)
i_ADDI_Reset(dev);
- }
-
- if (dev->irq) {
+ if (dev->irq)
free_irq(dev->irq, dev);
- }
-
- if ((this_board->pc_EepromChip == NULL)
- || (strcmp(this_board->pc_EepromChip,
- ADDIDATA_9054) != 0)) {
- if (devpriv->allocated) {
+ if ((this_board->pc_EepromChip == NULL) ||
+ (strcmp(this_board->pc_EepromChip, ADDIDATA_9054) != 0)) {
+ if (devpriv->allocated)
i_pci_card_free(devpriv->amcc);
- }
-
if (devpriv->ul_DmaBufferVirtual[0]) {
free_pages((unsigned long)devpriv->
ul_DmaBufferVirtual[0],
devpriv->ui_DmaBufferPages[0]);
}
-
if (devpriv->ul_DmaBufferVirtual[1]) {
free_pages((unsigned long)devpriv->
ul_DmaBufferVirtual[1],
@@ -3004,20 +1862,14 @@ static int i_ADDI_Detach(struct comedi_device *dev)
}
} else {
iounmap(devpriv->dw_AiBase);
-
- if (devpriv->allocated) {
+ if (devpriv->allocated)
i_pci_card_free(devpriv->amcc);
- }
}
-
if (pci_list_builded) {
- /* v_pci_card_list_cleanup(PCI_VENDOR_ID_AMCC); */
v_pci_card_list_cleanup(this_board->i_VendorId);
pci_list_builded = 0;
}
}
-
- return 0;
}
/*
@@ -3041,7 +1893,7 @@ static int i_ADDI_Detach(struct comedi_device *dev)
static int i_ADDI_Reset(struct comedi_device *dev)
{
- this_board->i_hwdrv_Reset(dev);
+ this_board->reset(dev);
return 0;
}
@@ -3067,7 +1919,7 @@ static int i_ADDI_Reset(struct comedi_device *dev)
static irqreturn_t v_ADDI_Interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
- this_board->v_hwdrv_Interrupt(irq, d);
+ this_board->interrupt(irq, d);
return IRQ_RETVAL(1);
}
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.h b/drivers/staging/comedi/drivers/addi-data/addi_common.h
index c6980b7dfea0..2c3f34703dd2 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_common.h
+++ b/drivers/staging/comedi/drivers/addi-data/addi_common.h
@@ -94,111 +94,72 @@ struct addi_board {
unsigned int ui_MinDelaytimeNs; /* Minimum Delay in Nano secs */
/* interrupt and reset */
- void (*v_hwdrv_Interrupt)(int irq, void *d);
- int (*i_hwdrv_Reset)(struct comedi_device *dev);
+ void (*interrupt)(int irq, void *d);
+ int (*reset)(struct comedi_device *);
/* Subdevice functions */
/* ANALOG INPUT */
- int (*i_hwdrv_InsnConfigAnalogInput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnReadAnalogInput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnWriteAnalogInput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnBitsAnalogInput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_CommandTestAnalogInput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
- int (*i_hwdrv_CommandAnalogInput)(struct comedi_device *dev,
- struct comedi_subdevice *s);
- int (*i_hwdrv_CancelAnalogInput)(struct comedi_device *dev,
- struct comedi_subdevice *s);
+ int (*ai_config)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*ai_read)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*ai_write)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*ai_bits)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*ai_cmdtest)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_cmd *);
+ int (*ai_cmd)(struct comedi_device *, struct comedi_subdevice *);
+ int (*ai_cancel)(struct comedi_device *, struct comedi_subdevice *);
/* Analog Output */
- int (*i_hwdrv_InsnConfigAnalogOutput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnWriteAnalogOutput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnBitsAnalogOutput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
+ int (*ao_config)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*ao_write)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*ao_bits)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
/* Digital Input */
- int (*i_hwdrv_InsnConfigDigitalInput) (struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnReadDigitalInput) (struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnWriteDigitalInput) (struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnBitsDigitalInput) (struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
+ int (*di_config)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*di_read)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*di_write)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*di_bits)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
/* Digital Output */
- int (*i_hwdrv_InsnConfigDigitalOutput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnWriteDigitalOutput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnBitsDigitalOutput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnReadDigitalOutput)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
+ int (*do_config)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*do_write)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*do_bits)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*do_read)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
/* TIMER */
- int (*i_hwdrv_InsnConfigTimer)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
- int (*i_hwdrv_InsnWriteTimer)(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdrv_InsnReadTimer)(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
- int (*i_hwdrv_InsnBitsTimer)(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
+ int (*timer_config)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*timer_write)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*timer_read)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*timer_bits)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
/* TTL IO */
- int (*i_hwdr_ConfigInitTTLIO)(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdr_ReadTTLIOBits)(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
- int (*i_hwdr_ReadTTLIOAllPortValue)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
- int (*i_hwdr_WriteTTLIOChlOnOff)(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
+ int (*ttl_config)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*ttl_bits)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*ttl_read)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
+ int (*ttl_write)(struct comedi_device *, struct comedi_subdevice *,
+ struct comedi_insn *, unsigned int *);
};
/* MODULE INFO STRUCTURE */
@@ -455,7 +416,7 @@ static unsigned short pci_list_builded; /* set to 1 when list of card is known *
/* Function declarations */
static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int i_ADDI_Detach(struct comedi_device *dev);
+static void i_ADDI_Detach(struct comedi_device *dev);
static int i_ADDI_Reset(struct comedi_device *dev);
static irqreturn_t v_ADDI_Interrupt(int irq, void *d);
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
index e886ced4978f..ffe390c6da83 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c
@@ -156,7 +156,7 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, struct comedi_subd
} else
us_ConvertTiming = (unsigned short) (devpriv->ui_EocEosConversionTime / 1000); /* nano to useconds */
- /* this_board->i_hwdrv_InsnReadAnalogInput(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]); */
+ /* this_board->ai_read(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]); */
/* Clear software registers */
devpriv->b_TimerSelectMode = 0;
@@ -670,7 +670,7 @@ int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, struct comedi_subde
/* mode 1 */
devpriv->ui_AiTimer0 = cmd->convert_arg; /* timer constant in nano seconds */
- /* return this_board->i_hwdrv_CommandAnalogInput(1,dev,s); */
+ /* return this_board->ai_cmd(1,dev,s); */
return i_APCI3120_CyclicAnalogInput(1, dev, s);
}
@@ -680,7 +680,7 @@ int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, struct comedi_subde
/* mode 2 */
devpriv->ui_AiTimer1 = cmd->scan_begin_arg;
devpriv->ui_AiTimer0 = cmd->convert_arg; /* variable changed timer2 to timer0 */
- /* return this_board->i_hwdrv_CommandAnalogInput(2,dev,s); */
+ /* return this_board->ai_cmd(2,dev,s); */
return i_APCI3120_CyclicAnalogInput(2, dev, s);
}
return -1;
@@ -1922,7 +1922,7 @@ int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, struct comedi_subdevic
ui_Timervalue2 = data[1] / 1000; /* convert nano seconds to u seconds */
- /* this_board->i_hwdrv_InsnConfigTimer(dev, ui_Timervalue2,(unsigned char)data[0]); */
+ /* this_board->timer_config(dev, ui_Timervalue2,(unsigned char)data[0]); */
us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS);
/*
@@ -2092,7 +2092,7 @@ int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, struct comedi_subdevice
ui_Timervalue2 = 0;
}
- /* this_board->i_hwdrv_InsnWriteTimer(dev,data[0],ui_Timervalue2); */
+ /* this_board->timer_write(dev,data[0],ui_Timervalue2); */
switch (data[0]) {
case APCI3120_START:
@@ -2260,7 +2260,7 @@ int i_APCI3120_InsnReadTimer(struct comedi_device *dev, struct comedi_subdevice
comedi_error(dev, "\nread:timer2 not configured ");
}
- /* this_board->i_hwdrv_InsnReadTimer(dev,data); */
+ /* this_board->timer_read(dev,data); */
if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
/* Read the LOW unsigned short of Timer 2 register */
@@ -2331,7 +2331,7 @@ int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev,
ui_Chan = CR_CHAN(insn->chanspec); /* channel specified */
- /* this_board->i_hwdrv_InsnReadDigitalInput(dev,ui_Chan,data); */
+ /* this_board->di_read(dev,ui_Chan,data); */
if (ui_Chan <= 3) {
ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI3120_RD_STATUS);
@@ -2379,7 +2379,7 @@ int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, struct comedi_sub
*****/
*data = (ui_TmpValue >> 8) & 0xf;
- /* this_board->i_hwdrv_InsnBitsDigitalInput(dev,data); */
+ /* this_board->di_bits(dev,data); */
return insn->n;
}
@@ -2595,7 +2595,7 @@ int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,
ui_Range = CR_RANGE(insn->chanspec);
ui_Channel = CR_CHAN(insn->chanspec);
- /* this_board->i_hwdrv_InsnWriteAnalogOutput(dev, ui_Range, ui_Channel,data[0]); */
+ /* this_board->ao_write(dev, ui_Range, ui_Channel,data[0]); */
if (ui_Range) { /* if 1 then unipolar */
if (data[0] != 0)
diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c
index 4fc9e8520217..de8c68af3210 100644
--- a/drivers/staging/comedi/drivers/adl_pci6208.c
+++ b/drivers/staging/comedi/drivers/adl_pci6208.c
@@ -54,8 +54,6 @@ References:
#include "../comedidev.h"
#include "comedi_pci.h"
-#define PCI6208_DRIVER_NAME "adl_pci6208"
-
/* Board descriptions */
struct pci6208_board {
const char *name;
@@ -85,17 +83,6 @@ static const struct pci6208_board pci6208_boards[] = {
}
};
-/* This is used by modprobe to translate PCI IDs to drivers. Should
- * only be used for PCI and ISA-PnP devices */
-static DEFINE_PCI_DEVICE_TABLE(pci6208_pci_table) = {
- /* { PCI_VENDOR_ID_ADLINK, 0x6208, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */
- /* { PCI_VENDOR_ID_ADLINK, 0x6208, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, 0x6208) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pci6208_pci_table);
-
/* Will be initialized in pci6208_find device(). */
#define thisboard ((const struct pci6208_board *)dev->board_ptr)
@@ -107,157 +94,6 @@ struct pci6208_private {
#define devpriv ((struct pci6208_private *)dev->private)
-static int pci6208_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pci6208_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_pci6208 = {
- .driver_name = PCI6208_DRIVER_NAME,
- .module = THIS_MODULE,
- .attach = pci6208_attach,
- .detach = pci6208_detach,
-};
-
-static int __devinit driver_pci6208_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- return comedi_pci_auto_config(dev, driver_pci6208.driver_name);
-}
-
-static void __devexit driver_pci6208_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_pci6208_pci_driver = {
- .id_table = pci6208_pci_table,
- .probe = &driver_pci6208_pci_probe,
- .remove = __devexit_p(&driver_pci6208_pci_remove)
-};
-
-static int __init driver_pci6208_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_pci6208);
- if (retval < 0)
- return retval;
-
- driver_pci6208_pci_driver.name = (char *)driver_pci6208.driver_name;
- return pci_register_driver(&driver_pci6208_pci_driver);
-}
-
-static void __exit driver_pci6208_cleanup_module(void)
-{
- pci_unregister_driver(&driver_pci6208_pci_driver);
- comedi_driver_unregister(&driver_pci6208);
-}
-
-module_init(driver_pci6208_init_module);
-module_exit(driver_pci6208_cleanup_module);
-
-static int pci6208_find_device(struct comedi_device *dev, int bus, int slot);
-static int
-pci6208_pci_setup(struct pci_dev *pci_dev, unsigned long *io_base_ptr,
- int dev_minor);
-
-/*read/write functions*/
-static int pci6208_ao_winsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int pci6208_ao_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-/* static int pci6208_dio_insn_bits (struct comedi_device *dev,
- * struct comedi_subdevice *s, */
-/* struct comedi_insn *insn,unsigned int *data); */
-/* static int pci6208_dio_insn_config(struct comedi_device *dev,
- * struct comedi_subdevice *s, */
-/* struct comedi_insn *insn,unsigned int *data); */
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board. If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int pci6208_attach(struct comedi_device *dev,
- struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- int retval;
- unsigned long io_base;
-
- printk(KERN_INFO "comedi%d: pci6208: ", dev->minor);
-
- retval = alloc_private(dev, sizeof(struct pci6208_private));
- if (retval < 0)
- return retval;
-
- retval = pci6208_find_device(dev, it->options[0], it->options[1]);
- if (retval < 0)
- return retval;
-
- retval = pci6208_pci_setup(devpriv->pci_dev, &io_base, dev->minor);
- if (retval < 0)
- return retval;
-
- dev->iobase = io_base;
- dev->board_name = thisboard->name;
-
-/*
- * Allocate the subdevice structures. alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- */
- if (alloc_subdevices(dev, 2) < 0)
- return -ENOMEM;
-
- s = dev->subdevices + 0;
- /* analog output subdevice */
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE; /* anything else to add here?? */
- s->n_chan = thisboard->ao_chans;
- s->maxdata = 0xffff; /* 16-bit DAC */
- s->range_table = &range_bipolar10; /* this needs to be checked. */
- s->insn_write = pci6208_ao_winsn;
- s->insn_read = pci6208_ao_rinsn;
-
- /* s=dev->subdevices+1; */
- /* digital i/o subdevice */
- /* s->type=COMEDI_SUBD_DIO; */
- /* s->subdev_flags=SDF_READABLE|SDF_WRITABLE; */
- /* s->n_chan=16; */
- /* s->maxdata=1; */
- /* s->range_table=&range_digital; */
- /* s->insn_bits = pci6208_dio_insn_bits; */
- /* s->insn_config = pci6208_dio_insn_config; */
-
- printk(KERN_INFO "attached\n");
-
- return 1;
-}
-
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pci6208_detach(struct comedi_device *dev)
-{
- printk(KERN_INFO "comedi%d: pci6208: remove\n", dev->minor);
-
- if (devpriv && devpriv->pci_dev) {
- if (dev->iobase)
- comedi_pci_disable(devpriv->pci_dev);
- pci_dev_put(devpriv->pci_dev);
- }
-
- return 0;
-}
-
static int pci6208_ao_winsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -410,7 +246,7 @@ pci6208_pci_setup(struct pci_dev *pci_dev, unsigned long *io_base_ptr,
unsigned long io_base, io_range, lcr_io_base, lcr_io_range;
/* Enable PCI device and request regions */
- if (comedi_pci_enable(pci_dev, PCI6208_DRIVER_NAME) < 0) {
+ if (comedi_pci_enable(pci_dev, "adl_pci6208") < 0) {
printk(KERN_ERR "comedi%d: Failed to enable PCI device "
"and request regions\n",
dev_minor);
@@ -442,6 +278,103 @@ pci6208_pci_setup(struct pci_dev *pci_dev, unsigned long *io_base_ptr,
return 0;
}
+static int pci6208_attach(struct comedi_device *dev,
+ struct comedi_devconfig *it)
+{
+ struct comedi_subdevice *s;
+ int retval;
+ unsigned long io_base;
+
+ printk(KERN_INFO "comedi%d: pci6208: ", dev->minor);
+
+ retval = alloc_private(dev, sizeof(struct pci6208_private));
+ if (retval < 0)
+ return retval;
+
+ retval = pci6208_find_device(dev, it->options[0], it->options[1]);
+ if (retval < 0)
+ return retval;
+
+ retval = pci6208_pci_setup(devpriv->pci_dev, &io_base, dev->minor);
+ if (retval < 0)
+ return retval;
+
+ dev->iobase = io_base;
+ dev->board_name = thisboard->name;
+
+ if (alloc_subdevices(dev, 2) < 0)
+ return -ENOMEM;
+
+ s = dev->subdevices + 0;
+ /* analog output subdevice */
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE; /* anything else to add here?? */
+ s->n_chan = thisboard->ao_chans;
+ s->maxdata = 0xffff; /* 16-bit DAC */
+ s->range_table = &range_bipolar10; /* this needs to be checked. */
+ s->insn_write = pci6208_ao_winsn;
+ s->insn_read = pci6208_ao_rinsn;
+
+ /* s=dev->subdevices+1; */
+ /* digital i/o subdevice */
+ /* s->type=COMEDI_SUBD_DIO; */
+ /* s->subdev_flags=SDF_READABLE|SDF_WRITABLE; */
+ /* s->n_chan=16; */
+ /* s->maxdata=1; */
+ /* s->range_table=&range_digital; */
+ /* s->insn_bits = pci6208_dio_insn_bits; */
+ /* s->insn_config = pci6208_dio_insn_config; */
+
+ printk(KERN_INFO "attached\n");
+
+ return 1;
+}
+
+static void pci6208_detach(struct comedi_device *dev)
+{
+ if (devpriv && devpriv->pci_dev) {
+ if (dev->iobase)
+ comedi_pci_disable(devpriv->pci_dev);
+ pci_dev_put(devpriv->pci_dev);
+ }
+}
+
+static struct comedi_driver adl_pci6208_driver = {
+ .driver_name = "adl_pci6208",
+ .module = THIS_MODULE,
+ .attach = pci6208_attach,
+ .detach = pci6208_detach,
+};
+
+static int __devinit adl_pci6208_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, &adl_pci6208_driver);
+}
+
+static void __devexit adl_pci6208_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+/* This is used by modprobe to translate PCI IDs to drivers. Should
+ * only be used for PCI and ISA-PnP devices */
+static DEFINE_PCI_DEVICE_TABLE(adl_pci6208_pci_table) = {
+ /* { PCI_VENDOR_ID_ADLINK, 0x6208, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */
+ /* { PCI_VENDOR_ID_ADLINK, 0x6208, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */
+ { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, 0x6208) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, adl_pci6208_pci_table);
+
+static struct pci_driver adl_pci6208_pci_driver = {
+ .name = "adl_pci6208",
+ .id_table = adl_pci6208_pci_table,
+ .probe = adl_pci6208_pci_probe,
+ .remove = __devexit_p(adl_pci6208_pci_remove),
+};
+module_comedi_pci_driver(adl_pci6208_driver, adl_pci6208_pci_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adl_pci7230.c b/drivers/staging/comedi/drivers/adl_pci7230.c
index 20d570554fa4..e8053bc825f4 100644
--- a/drivers/staging/comedi/drivers/adl_pci7230.c
+++ b/drivers/staging/comedi/drivers/adl_pci7230.c
@@ -43,13 +43,6 @@ Configuration Options:
#define PCI_DEVICE_ID_PCI7230 0x7230
-static DEFINE_PCI_DEVICE_TABLE(adl_pci7230_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7230) },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, adl_pci7230_pci_table);
-
struct adl_pci7230_private {
int data;
struct pci_dev *pci_dev;
@@ -57,27 +50,36 @@ struct adl_pci7230_private {
#define devpriv ((struct adl_pci7230_private *)dev->private)
-static int adl_pci7230_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int adl_pci7230_detach(struct comedi_device *dev);
-static struct comedi_driver driver_adl_pci7230 = {
- .driver_name = "adl_pci7230",
- .module = THIS_MODULE,
- .attach = adl_pci7230_attach,
- .detach = adl_pci7230_detach,
-};
+static int adl_pci7230_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ if (insn->n != 2)
+ return -EINVAL;
+
+ if (data[0]) {
+ s->state &= ~data[0];
+ s->state |= (data[0] & data[1]);
+
+ outl((s->state << 16) & 0xffffffff, dev->iobase + PCI7230_DO);
+ }
-/* Digital IO */
+ return 2;
+}
static int adl_pci7230_di_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
- unsigned int *data);
+ unsigned int *data)
+{
+ if (insn->n != 2)
+ return -EINVAL;
-static int adl_pci7230_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
+ data[1] = inl(dev->iobase + PCI7230_DI) & 0xffffffff;
+
+ return 2;
+}
static int adl_pci7230_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
@@ -148,89 +150,46 @@ static int adl_pci7230_attach(struct comedi_device *dev,
return 1;
}
-static int adl_pci7230_detach(struct comedi_device *dev)
+static void adl_pci7230_detach(struct comedi_device *dev)
{
- printk(KERN_DEBUG "comedi%d: pci7230: remove\n", dev->minor);
-
if (devpriv && devpriv->pci_dev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
pci_dev_put(devpriv->pci_dev);
}
-
- return 0;
-}
-
-static int adl_pci7230_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- if (insn->n != 2)
- return -EINVAL;
-
- if (data[0]) {
- s->state &= ~data[0];
- s->state |= (data[0] & data[1]);
-
- outl((s->state << 16) & 0xffffffff, dev->iobase + PCI7230_DO);
- }
-
- return 2;
}
-static int adl_pci7230_di_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- if (insn->n != 2)
- return -EINVAL;
-
- data[1] = inl(dev->iobase + PCI7230_DI) & 0xffffffff;
-
- return 2;
-}
+static struct comedi_driver adl_pci7230_driver = {
+ .driver_name = "adl_pci7230",
+ .module = THIS_MODULE,
+ .attach = adl_pci7230_attach,
+ .detach = adl_pci7230_detach,
+};
-static int __devinit driver_adl_pci7230_pci_probe(struct pci_dev *dev,
- const struct pci_device_id
- *ent)
+static int __devinit adl_pci7230_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_adl_pci7230.driver_name);
+ return comedi_pci_auto_config(dev, &adl_pci7230_driver);
}
-static void __devexit driver_adl_pci7230_pci_remove(struct pci_dev *dev)
+static void __devexit adl_pci7230_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_adl_pci7230_pci_driver = {
- .id_table = adl_pci7230_pci_table,
- .probe = &driver_adl_pci7230_pci_probe,
- .remove = __devexit_p(&driver_adl_pci7230_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(adl_pci7230_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7230) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, adl_pci7230_pci_table);
-static int __init driver_adl_pci7230_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_adl_pci7230);
- if (retval < 0)
- return retval;
-
- driver_adl_pci7230_pci_driver.name =
- (char *)driver_adl_pci7230.driver_name;
- return pci_register_driver(&driver_adl_pci7230_pci_driver);
-}
-
-static void __exit driver_adl_pci7230_cleanup_module(void)
-{
- pci_unregister_driver(&driver_adl_pci7230_pci_driver);
- comedi_driver_unregister(&driver_adl_pci7230);
-}
-
-module_init(driver_adl_pci7230_init_module);
-module_exit(driver_adl_pci7230_cleanup_module);
+static struct pci_driver adl_pci7230_pci_driver = {
+ .name = "adl_pci7230",
+ .id_table = adl_pci7230_pci_table,
+ .probe = adl_pci7230_pci_probe,
+ .remove = __devexit_p(adl_pci7230_pci_remove),
+};
+module_comedi_pci_driver(adl_pci7230_driver, adl_pci7230_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adl_pci7296.c b/drivers/staging/comedi/drivers/adl_pci7296.c
index 9a2320537bdb..b4dae3b7598b 100644
--- a/drivers/staging/comedi/drivers/adl_pci7296.c
+++ b/drivers/staging/comedi/drivers/adl_pci7296.c
@@ -48,13 +48,6 @@ Configuration Options:
#define PCI_DEVICE_ID_PCI7296 0x7296
-static DEFINE_PCI_DEVICE_TABLE(adl_pci7296_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7296) },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, adl_pci7296_pci_table);
-
struct adl_pci7296_private {
int data;
struct pci_dev *pci_dev;
@@ -63,16 +56,6 @@ struct adl_pci7296_private {
#define devpriv ((struct adl_pci7296_private *)dev->private)
static int adl_pci7296_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int adl_pci7296_detach(struct comedi_device *dev);
-static struct comedi_driver driver_adl_pci7296 = {
- .driver_name = "adl_pci7296",
- .module = THIS_MODULE,
- .attach = adl_pci7296_attach,
- .detach = adl_pci7296_detach,
-};
-
-static int adl_pci7296_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
struct pci_dev *pcidev = NULL;
@@ -151,66 +134,52 @@ static int adl_pci7296_attach(struct comedi_device *dev,
return -EIO;
}
-static int adl_pci7296_detach(struct comedi_device *dev)
+static void adl_pci7296_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: pci7432: remove\n", dev->minor);
-
if (devpriv && devpriv->pci_dev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
pci_dev_put(devpriv->pci_dev);
}
- /* detach four 8255 digital io subdevices */
if (dev->subdevices) {
subdev_8255_cleanup(dev, dev->subdevices + 0);
subdev_8255_cleanup(dev, dev->subdevices + 1);
subdev_8255_cleanup(dev, dev->subdevices + 2);
subdev_8255_cleanup(dev, dev->subdevices + 3);
-
}
-
- return 0;
}
-static int __devinit driver_adl_pci7296_pci_probe(struct pci_dev *dev,
- const struct pci_device_id
- *ent)
+static struct comedi_driver adl_pci7296_driver = {
+ .driver_name = "adl_pci7296",
+ .module = THIS_MODULE,
+ .attach = adl_pci7296_attach,
+ .detach = adl_pci7296_detach,
+};
+
+static int __devinit adl_pci7296_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_adl_pci7296.driver_name);
+ return comedi_pci_auto_config(dev, &adl_pci7296_driver);
}
-static void __devexit driver_adl_pci7296_pci_remove(struct pci_dev *dev)
+static void __devexit adl_pci7296_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_adl_pci7296_pci_driver = {
- .id_table = adl_pci7296_pci_table,
- .probe = &driver_adl_pci7296_pci_probe,
- .remove = __devexit_p(&driver_adl_pci7296_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(adl_pci7296_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7296) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, adl_pci7296_pci_table);
-static int __init driver_adl_pci7296_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_adl_pci7296);
- if (retval < 0)
- return retval;
-
- driver_adl_pci7296_pci_driver.name =
- (char *)driver_adl_pci7296.driver_name;
- return pci_register_driver(&driver_adl_pci7296_pci_driver);
-}
-
-static void __exit driver_adl_pci7296_cleanup_module(void)
-{
- pci_unregister_driver(&driver_adl_pci7296_pci_driver);
- comedi_driver_unregister(&driver_adl_pci7296);
-}
-
-module_init(driver_adl_pci7296_init_module);
-module_exit(driver_adl_pci7296_cleanup_module);
+static struct pci_driver adl_pci7296_pci_driver = {
+ .name = "adl_pci7296",
+ .id_table = adl_pci7296_pci_table,
+ .probe = adl_pci7296_pci_probe,
+ .remove = __devexit_p(adl_pci7296_pci_remove),
+};
+module_comedi_pci_driver(adl_pci7296_driver, adl_pci7296_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adl_pci7432.c b/drivers/staging/comedi/drivers/adl_pci7432.c
index 86ee21976041..9cbfb61a4478 100644
--- a/drivers/staging/comedi/drivers/adl_pci7432.c
+++ b/drivers/staging/comedi/drivers/adl_pci7432.c
@@ -43,13 +43,6 @@ Configuration Options:
#define PCI_DEVICE_ID_PCI7432 0x7432
-static DEFINE_PCI_DEVICE_TABLE(adl_pci7432_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7432) },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, adl_pci7432_pci_table);
-
struct adl_pci7432_private {
int data;
struct pci_dev *pci_dev;
@@ -57,29 +50,44 @@ struct adl_pci7432_private {
#define devpriv ((struct adl_pci7432_private *)dev->private)
-static int adl_pci7432_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int adl_pci7432_detach(struct comedi_device *dev);
-static struct comedi_driver driver_adl_pci7432 = {
- .driver_name = "adl_pci7432",
- .module = THIS_MODULE,
- .attach = adl_pci7432_attach,
- .detach = adl_pci7432_detach,
-};
+static int adl_pci7432_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ printk(KERN_DEBUG "comedi: pci7432_do_insn_bits called\n");
+ printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]);
+
+ if (insn->n != 2)
+ return -EINVAL;
-/* Digital IO */
+ if (data[0]) {
+ s->state &= ~data[0];
+ s->state |= (data[0] & data[1]);
+
+ printk(KERN_DEBUG "comedi: out: %8x on iobase %4lx\n", s->state,
+ dev->iobase + PCI7432_DO);
+ outl(s->state & 0xffffffff, dev->iobase + PCI7432_DO);
+ }
+ return 2;
+}
static int adl_pci7432_di_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
- unsigned int *data);
+ unsigned int *data)
+{
+ printk(KERN_DEBUG "comedi: pci7432_di_insn_bits called\n");
+ printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]);
-static int adl_pci7432_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
+ if (insn->n != 2)
+ return -EINVAL;
+
+ data[1] = inl(dev->iobase + PCI7432_DI) & 0xffffffff;
+ printk(KERN_DEBUG "comedi: data1 %8x\n", data[1]);
-/* */
+ return 2;
+}
static int adl_pci7432_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
@@ -153,97 +161,46 @@ static int adl_pci7432_attach(struct comedi_device *dev,
return -EIO;
}
-static int adl_pci7432_detach(struct comedi_device *dev)
+static void adl_pci7432_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: pci7432: remove\n", dev->minor);
-
if (devpriv && devpriv->pci_dev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
pci_dev_put(devpriv->pci_dev);
}
-
- return 0;
}
-static int adl_pci7432_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- printk(KERN_DEBUG "comedi: pci7432_do_insn_bits called\n");
- printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]);
-
- if (insn->n != 2)
- return -EINVAL;
-
- if (data[0]) {
- s->state &= ~data[0];
- s->state |= (data[0] & data[1]);
-
- printk(KERN_DEBUG "comedi: out: %8x on iobase %4lx\n", s->state,
- dev->iobase + PCI7432_DO);
- outl(s->state & 0xffffffff, dev->iobase + PCI7432_DO);
- }
- return 2;
-}
-
-static int adl_pci7432_di_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- printk(KERN_DEBUG "comedi: pci7432_di_insn_bits called\n");
- printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]);
-
- if (insn->n != 2)
- return -EINVAL;
-
- data[1] = inl(dev->iobase + PCI7432_DI) & 0xffffffff;
- printk(KERN_DEBUG "comedi: data1 %8x\n", data[1]);
-
- return 2;
-}
+static struct comedi_driver adl_pci7432_driver = {
+ .driver_name = "adl_pci7432",
+ .module = THIS_MODULE,
+ .attach = adl_pci7432_attach,
+ .detach = adl_pci7432_detach,
+};
-static int __devinit driver_adl_pci7432_pci_probe(struct pci_dev *dev,
- const struct pci_device_id
- *ent)
+static int __devinit adl_pci7432_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_adl_pci7432.driver_name);
+ return comedi_pci_auto_config(dev, &adl_pci7432_driver);
}
-static void __devexit driver_adl_pci7432_pci_remove(struct pci_dev *dev)
+static void __devexit adl_pci7432_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_adl_pci7432_pci_driver = {
- .id_table = adl_pci7432_pci_table,
- .probe = &driver_adl_pci7432_pci_probe,
- .remove = __devexit_p(&driver_adl_pci7432_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(adl_pci7432_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7432) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, adl_pci7432_pci_table);
-static int __init driver_adl_pci7432_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_adl_pci7432);
- if (retval < 0)
- return retval;
-
- driver_adl_pci7432_pci_driver.name =
- (char *)driver_adl_pci7432.driver_name;
- return pci_register_driver(&driver_adl_pci7432_pci_driver);
-}
-
-static void __exit driver_adl_pci7432_cleanup_module(void)
-{
- pci_unregister_driver(&driver_adl_pci7432_pci_driver);
- comedi_driver_unregister(&driver_adl_pci7432);
-}
-
-module_init(driver_adl_pci7432_init_module);
-module_exit(driver_adl_pci7432_cleanup_module);
+static struct pci_driver adl_pci7432_pci_driver = {
+ .name = "adl_pci7432",
+ .id_table = adl_pci7432_pci_table,
+ .probe = adl_pci7432_pci_probe,
+ .remove = __devexit_p(adl_pci7432_pci_remove),
+};
+module_comedi_pci_driver(adl_pci7432_driver, adl_pci7432_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adl_pci8164.c b/drivers/staging/comedi/drivers/adl_pci8164.c
index 3b83d65bc1bc..409ef13ad090 100644
--- a/drivers/staging/comedi/drivers/adl_pci8164.c
+++ b/drivers/staging/comedi/drivers/adl_pci8164.c
@@ -56,13 +56,6 @@ Configuration Options:
#define PCI_DEVICE_ID_PCI8164 0x8164
-static DEFINE_PCI_DEVICE_TABLE(adl_pci8164_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI8164) },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, adl_pci8164_pci_table);
-
struct adl_pci8164_private {
int data;
struct pci_dev *pci_dev;
@@ -70,159 +63,6 @@ struct adl_pci8164_private {
#define devpriv ((struct adl_pci8164_private *)dev->private)
-static int adl_pci8164_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int adl_pci8164_detach(struct comedi_device *dev);
-static struct comedi_driver driver_adl_pci8164 = {
- .driver_name = "adl_pci8164",
- .module = THIS_MODULE,
- .attach = adl_pci8164_attach,
- .detach = adl_pci8164_detach,
-};
-
-static int adl_pci8164_insn_read_msts(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
-
-static int adl_pci8164_insn_read_ssts(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
-
-static int adl_pci8164_insn_read_buf0(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
-
-static int adl_pci8164_insn_read_buf1(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
-
-static int adl_pci8164_insn_write_cmd(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
-
-static int adl_pci8164_insn_write_otp(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
-
-static int adl_pci8164_insn_write_buf0(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
-
-static int adl_pci8164_insn_write_buf1(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
-
-static int adl_pci8164_attach(struct comedi_device *dev,
- struct comedi_devconfig *it)
-{
- struct pci_dev *pcidev = NULL;
- struct comedi_subdevice *s;
- int bus, slot;
-
- printk(KERN_INFO "comedi: attempt to attach...\n");
- printk(KERN_INFO "comedi%d: adl_pci8164\n", dev->minor);
-
- dev->board_name = "pci8164";
- bus = it->options[0];
- slot = it->options[1];
-
- if (alloc_private(dev, sizeof(struct adl_pci8164_private)) < 0)
- return -ENOMEM;
-
- if (alloc_subdevices(dev, 4) < 0)
- return -ENOMEM;
-
- for_each_pci_dev(pcidev) {
- if (pcidev->vendor == PCI_VENDOR_ID_ADLINK &&
- pcidev->device == PCI_DEVICE_ID_PCI8164) {
- if (bus || slot) {
- /* requested particular bus/slot */
- if (pcidev->bus->number != bus
- || PCI_SLOT(pcidev->devfn) != slot)
- continue;
- }
- devpriv->pci_dev = pcidev;
- if (comedi_pci_enable(pcidev, "adl_pci8164") < 0) {
- printk(KERN_ERR "comedi%d: Failed to enable "
- "PCI device and request regions\n", dev->minor);
- return -EIO;
- }
- dev->iobase = pci_resource_start(pcidev, 2);
- printk(KERN_DEBUG "comedi: base addr %4lx\n",
- dev->iobase);
-
- s = dev->subdevices + 0;
- s->type = COMEDI_SUBD_PROC;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 4;
- s->maxdata = 0xffff;
- s->len_chanlist = 4;
- /* s->range_table = &range_axis; */
- s->insn_read = adl_pci8164_insn_read_msts;
- s->insn_write = adl_pci8164_insn_write_cmd;
-
- s = dev->subdevices + 1;
- s->type = COMEDI_SUBD_PROC;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 4;
- s->maxdata = 0xffff;
- s->len_chanlist = 4;
- /* s->range_table = &range_axis; */
- s->insn_read = adl_pci8164_insn_read_ssts;
- s->insn_write = adl_pci8164_insn_write_otp;
-
- s = dev->subdevices + 2;
- s->type = COMEDI_SUBD_PROC;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 4;
- s->maxdata = 0xffff;
- s->len_chanlist = 4;
- /* s->range_table = &range_axis; */
- s->insn_read = adl_pci8164_insn_read_buf0;
- s->insn_write = adl_pci8164_insn_write_buf0;
-
- s = dev->subdevices + 3;
- s->type = COMEDI_SUBD_PROC;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 4;
- s->maxdata = 0xffff;
- s->len_chanlist = 4;
- /* s->range_table = &range_axis; */
- s->insn_read = adl_pci8164_insn_read_buf1;
- s->insn_write = adl_pci8164_insn_write_buf1;
-
- printk(KERN_INFO "comedi: attached\n");
-
- return 1;
- }
- }
-
- printk(KERN_ERR "comedi%d: no supported board found!"
- "(req. bus/slot : %d/%d)\n", dev->minor, bus, slot);
- return -EIO;
-}
-
-static int adl_pci8164_detach(struct comedi_device *dev)
-{
- printk(KERN_INFO "comedi%d: pci8164: remove\n", dev->minor);
-
- if (devpriv && devpriv->pci_dev) {
- if (dev->iobase)
- comedi_pci_disable(devpriv->pci_dev);
- pci_dev_put(devpriv->pci_dev);
- }
-
- return 0;
-}
-
/*
all the read commands are the same except for the addition a constant
* const to the data for inw()
@@ -384,45 +224,136 @@ static int adl_pci8164_insn_write_buf1(struct comedi_device *dev,
return 2;
}
-static int __devinit driver_adl_pci8164_pci_probe(struct pci_dev *dev,
- const struct pci_device_id
- *ent)
+static int adl_pci8164_attach(struct comedi_device *dev,
+ struct comedi_devconfig *it)
{
- return comedi_pci_auto_config(dev, driver_adl_pci8164.driver_name);
+ struct pci_dev *pcidev = NULL;
+ struct comedi_subdevice *s;
+ int bus, slot;
+
+ printk(KERN_INFO "comedi: attempt to attach...\n");
+ printk(KERN_INFO "comedi%d: adl_pci8164\n", dev->minor);
+
+ dev->board_name = "pci8164";
+ bus = it->options[0];
+ slot = it->options[1];
+
+ if (alloc_private(dev, sizeof(struct adl_pci8164_private)) < 0)
+ return -ENOMEM;
+
+ if (alloc_subdevices(dev, 4) < 0)
+ return -ENOMEM;
+
+ for_each_pci_dev(pcidev) {
+ if (pcidev->vendor == PCI_VENDOR_ID_ADLINK &&
+ pcidev->device == PCI_DEVICE_ID_PCI8164) {
+ if (bus || slot) {
+ /* requested particular bus/slot */
+ if (pcidev->bus->number != bus
+ || PCI_SLOT(pcidev->devfn) != slot)
+ continue;
+ }
+ devpriv->pci_dev = pcidev;
+ if (comedi_pci_enable(pcidev, "adl_pci8164") < 0) {
+ printk(KERN_ERR "comedi%d: Failed to enable "
+ "PCI device and request regions\n", dev->minor);
+ return -EIO;
+ }
+ dev->iobase = pci_resource_start(pcidev, 2);
+ printk(KERN_DEBUG "comedi: base addr %4lx\n",
+ dev->iobase);
+
+ s = dev->subdevices + 0;
+ s->type = COMEDI_SUBD_PROC;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 4;
+ s->maxdata = 0xffff;
+ s->len_chanlist = 4;
+ /* s->range_table = &range_axis; */
+ s->insn_read = adl_pci8164_insn_read_msts;
+ s->insn_write = adl_pci8164_insn_write_cmd;
+
+ s = dev->subdevices + 1;
+ s->type = COMEDI_SUBD_PROC;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 4;
+ s->maxdata = 0xffff;
+ s->len_chanlist = 4;
+ /* s->range_table = &range_axis; */
+ s->insn_read = adl_pci8164_insn_read_ssts;
+ s->insn_write = adl_pci8164_insn_write_otp;
+
+ s = dev->subdevices + 2;
+ s->type = COMEDI_SUBD_PROC;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 4;
+ s->maxdata = 0xffff;
+ s->len_chanlist = 4;
+ /* s->range_table = &range_axis; */
+ s->insn_read = adl_pci8164_insn_read_buf0;
+ s->insn_write = adl_pci8164_insn_write_buf0;
+
+ s = dev->subdevices + 3;
+ s->type = COMEDI_SUBD_PROC;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 4;
+ s->maxdata = 0xffff;
+ s->len_chanlist = 4;
+ /* s->range_table = &range_axis; */
+ s->insn_read = adl_pci8164_insn_read_buf1;
+ s->insn_write = adl_pci8164_insn_write_buf1;
+
+ printk(KERN_INFO "comedi: attached\n");
+
+ return 1;
+ }
+ }
+
+ printk(KERN_ERR "comedi%d: no supported board found!"
+ "(req. bus/slot : %d/%d)\n", dev->minor, bus, slot);
+ return -EIO;
}
-static void __devexit driver_adl_pci8164_pci_remove(struct pci_dev *dev)
+static void adl_pci8164_detach(struct comedi_device *dev)
{
- comedi_pci_auto_unconfig(dev);
+ if (devpriv && devpriv->pci_dev) {
+ if (dev->iobase)
+ comedi_pci_disable(devpriv->pci_dev);
+ pci_dev_put(devpriv->pci_dev);
+ }
}
-static struct pci_driver driver_adl_pci8164_pci_driver = {
- .id_table = adl_pci8164_pci_table,
- .probe = &driver_adl_pci8164_pci_probe,
- .remove = __devexit_p(&driver_adl_pci8164_pci_remove)
+static struct comedi_driver adl_pci8164_driver = {
+ .driver_name = "adl_pci8164",
+ .module = THIS_MODULE,
+ .attach = adl_pci8164_attach,
+ .detach = adl_pci8164_detach,
};
-static int __init driver_adl_pci8164_init_module(void)
+static int __devinit adl_pci8164_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- int retval;
-
- retval = comedi_driver_register(&driver_adl_pci8164);
- if (retval < 0)
- return retval;
-
- driver_adl_pci8164_pci_driver.name =
- (char *)driver_adl_pci8164.driver_name;
- return pci_register_driver(&driver_adl_pci8164_pci_driver);
+ return comedi_pci_auto_config(dev, &adl_pci8164_driver);
}
-static void __exit driver_adl_pci8164_cleanup_module(void)
+static void __devexit adl_pci8164_pci_remove(struct pci_dev *dev)
{
- pci_unregister_driver(&driver_adl_pci8164_pci_driver);
- comedi_driver_unregister(&driver_adl_pci8164);
+ comedi_pci_auto_unconfig(dev);
}
-module_init(driver_adl_pci8164_init_module);
-module_exit(driver_adl_pci8164_cleanup_module);
+static DEFINE_PCI_DEVICE_TABLE(adl_pci8164_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI8164) },
+ {0}
+};
+MODULE_DEVICE_TABLE(pci, adl_pci8164_pci_table);
+
+static struct pci_driver adl_pci8164_pci_driver = {
+ .name = "adl_pci8164",
+ .id_table = adl_pci8164_pci_table,
+ .probe = adl_pci8164_pci_probe,
+ .remove = __devexit_p(adl_pci8164_pci_remove),
+};
+module_comedi_pci_driver(adl_pci8164_driver, adl_pci8164_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c
index 2a9bd88a4abb..ccfb1a52154e 100644
--- a/drivers/staging/comedi/drivers/adl_pci9111.c
+++ b/drivers/staging/comedi/drivers/adl_pci9111.c
@@ -289,16 +289,6 @@ TODO:
PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_2); \
} while (0)
-/* Function prototypes */
-
-static int pci9111_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pci9111_detach(struct comedi_device *dev);
-static void pci9111_ai_munge(struct comedi_device *dev,
- struct comedi_subdevice *s, void *data,
- unsigned int num_bytes,
- unsigned int start_chan_index);
-
static const struct comedi_lrange pci9111_hr_ai_range = {
5,
{
@@ -310,14 +300,6 @@ static const struct comedi_lrange pci9111_hr_ai_range = {
}
};
-static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID) },
- /* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pci9111_pci_table);
-
/* */
/* Board specification structure */
/* */
@@ -354,51 +336,6 @@ static const struct pci9111_board pci9111_boards[] = {
#define pci9111_board_nbr \
(sizeof(pci9111_boards)/sizeof(struct pci9111_board))
-static struct comedi_driver pci9111_driver = {
- .driver_name = PCI9111_DRIVER_NAME,
- .module = THIS_MODULE,
- .attach = pci9111_attach,
- .detach = pci9111_detach,
-};
-
-static int __devinit pci9111_driver_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- return comedi_pci_auto_config(dev, pci9111_driver.driver_name);
-}
-
-static void __devexit pci9111_driver_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver pci9111_driver_pci_driver = {
- .id_table = pci9111_pci_table,
- .probe = &pci9111_driver_pci_probe,
- .remove = __devexit_p(&pci9111_driver_pci_remove)
-};
-
-static int __init pci9111_driver_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&pci9111_driver);
- if (retval < 0)
- return retval;
-
- pci9111_driver_pci_driver.name = (char *)pci9111_driver.driver_name;
- return pci_register_driver(&pci9111_driver_pci_driver);
-}
-
-static void __exit pci9111_driver_cleanup_module(void)
-{
- pci_unregister_driver(&pci9111_driver_pci_driver);
- comedi_driver_unregister(&pci9111_driver);
-}
-
-module_init(pci9111_driver_init_module);
-module_exit(pci9111_driver_cleanup_module);
-
/* Private data structure */
struct pci9111_private_data {
@@ -1445,31 +1382,54 @@ found:
return 0;
}
-/* Detach */
-
-static int pci9111_detach(struct comedi_device *dev)
+static void pci9111_detach(struct comedi_device *dev)
{
- /* Reset device */
-
if (dev->private != NULL) {
if (dev_private->is_valid)
pci9111_reset(dev);
-
}
- /* Release previously allocated irq */
-
if (dev->irq != 0)
free_irq(dev->irq, dev);
-
if (dev_private != NULL && dev_private->pci_device != NULL) {
if (dev->iobase)
comedi_pci_disable(dev_private->pci_device);
pci_dev_put(dev_private->pci_device);
}
+}
- return 0;
+static struct comedi_driver adl_pci9111_driver = {
+ .driver_name = "adl_pci9111",
+ .module = THIS_MODULE,
+ .attach = pci9111_attach,
+ .detach = pci9111_detach,
+};
+
+static int __devinit pci9111_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, &adl_pci9111_driver);
}
+static void __devexit pci9111_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID) },
+ /* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, pci9111_pci_table);
+
+static struct pci_driver adl_pci9111_pci_driver = {
+ .name = "adl_pci9111",
+ .id_table = pci9111_pci_table,
+ .probe = pci9111_pci_probe,
+ .remove = __devexit_p(pci9111_pci_remove),
+};
+module_comedi_pci_driver(adl_pci9111_driver, adl_pci9111_pci_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c
index f17654e44aef..78645863297b 100644
--- a/drivers/staging/comedi/drivers/adl_pci9118.c
+++ b/drivers/staging/comedi/drivers/adl_pci9118.c
@@ -221,10 +221,6 @@ static const struct comedi_lrange range_pci9118hg = { 8, {
* of BIP/UNI ranges
*/
-static int pci9118_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pci9118_detach(struct comedi_device *dev);
-
struct boardtype {
const char *name; /* board name */
int vendor_id; /* PCI vendor a device ID of card */
@@ -252,81 +248,6 @@ struct boardtype {
};
-static DEFINE_PCI_DEVICE_TABLE(pci9118_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_AMCC, 0x80d9) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pci9118_pci_table);
-
-static const struct boardtype boardtypes[] = {
- {"pci9118dg", PCI_VENDOR_ID_AMCC, 0x80d9,
- AMCC_OP_REG_SIZE, IORANGE_9118,
- 16, 8, 256, PCI9118_CHANLEN, 2, 0x0fff, 0x0fff,
- &range_pci9118dg_hr, &range_bipolar10,
- 3000, 12, 512},
- {"pci9118hg", PCI_VENDOR_ID_AMCC, 0x80d9,
- AMCC_OP_REG_SIZE, IORANGE_9118,
- 16, 8, 256, PCI9118_CHANLEN, 2, 0x0fff, 0x0fff,
- &range_pci9118hg, &range_bipolar10,
- 3000, 12, 512},
- {"pci9118hr", PCI_VENDOR_ID_AMCC, 0x80d9,
- AMCC_OP_REG_SIZE, IORANGE_9118,
- 16, 8, 256, PCI9118_CHANLEN, 2, 0xffff, 0x0fff,
- &range_pci9118dg_hr, &range_bipolar10,
- 10000, 40, 512},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
-
-static struct comedi_driver driver_pci9118 = {
- .driver_name = "adl_pci9118",
- .module = THIS_MODULE,
- .attach = pci9118_attach,
- .detach = pci9118_detach,
- .num_names = n_boardtypes,
- .board_name = &boardtypes[0].name,
- .offset = sizeof(struct boardtype),
-};
-
-static int __devinit driver_pci9118_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- return comedi_pci_auto_config(dev, driver_pci9118.driver_name);
-}
-
-static void __devexit driver_pci9118_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_pci9118_pci_driver = {
- .id_table = pci9118_pci_table,
- .probe = &driver_pci9118_pci_probe,
- .remove = __devexit_p(&driver_pci9118_pci_remove)
-};
-
-static int __init driver_pci9118_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_pci9118);
- if (retval < 0)
- return retval;
-
- driver_pci9118_pci_driver.name = (char *)driver_pci9118.driver_name;
- return pci_register_driver(&driver_pci9118_pci_driver);
-}
-
-static void __exit driver_pci9118_cleanup_module(void)
-{
- pci_unregister_driver(&driver_pci9118_pci_driver);
- comedi_driver_unregister(&driver_pci9118);
-}
-
-module_init(driver_pci9118_init_module);
-module_exit(driver_pci9118_cleanup_module);
-
struct pci9118_private {
unsigned long iobase_a; /* base+size for AMCC chip */
unsigned int master; /* master capable */
@@ -2190,9 +2111,6 @@ static int pci9118_reset(struct comedi_device *dev)
return 0;
}
-/*
-==============================================================================
-*/
static int pci9118_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
@@ -2435,10 +2353,7 @@ static int pci9118_attach(struct comedi_device *dev,
return 0;
}
-/*
-==============================================================================
-*/
-static int pci9118_detach(struct comedi_device *dev)
+static void pci9118_detach(struct comedi_device *dev)
{
if (dev->private) {
if (devpriv->valid)
@@ -2458,13 +2373,100 @@ static int pci9118_detach(struct comedi_device *dev)
free_pages((unsigned long)devpriv->dmabuf_virt[1],
devpriv->dmabuf_pages[1]);
}
+}
- return 0;
+static const struct boardtype boardtypes[] = {
+ {
+ .name = "pci9118dg",
+ .vendor_id = PCI_VENDOR_ID_AMCC,
+ .device_id = 0x80d9,
+ .iorange_amcc = AMCC_OP_REG_SIZE,
+ .iorange_9118 = IORANGE_9118,
+ .n_aichan = 16,
+ .n_aichand = 8,
+ .mux_aichan = 256,
+ .n_aichanlist = PCI9118_CHANLEN,
+ .n_aochan = 2,
+ .ai_maxdata = 0x0fff,
+ .ao_maxdata = 0x0fff,
+ .rangelist_ai = &range_pci9118dg_hr,
+ .rangelist_ao = &range_bipolar10,
+ .ai_ns_min = 3000,
+ .ai_pacer_min = 12,
+ .half_fifo_size = 512,
+ }, {
+ .name = "pci9118hg",
+ .vendor_id = PCI_VENDOR_ID_AMCC,
+ .device_id = 0x80d9,
+ .iorange_amcc = AMCC_OP_REG_SIZE,
+ .iorange_9118 = IORANGE_9118,
+ .n_aichan = 16,
+ .n_aichand = 8,
+ .mux_aichan = 256,
+ .n_aichanlist = PCI9118_CHANLEN,
+ .n_aochan = 2,
+ .ai_maxdata = 0x0fff,
+ .ao_maxdata = 0x0fff,
+ .rangelist_ai = &range_pci9118hg,
+ .rangelist_ao = &range_bipolar10,
+ .ai_ns_min = 3000,
+ .ai_pacer_min = 12,
+ .half_fifo_size = 512,
+ }, {
+ .name = "pci9118hr",
+ .vendor_id = PCI_VENDOR_ID_AMCC,
+ .device_id = 0x80d9,
+ .iorange_amcc = AMCC_OP_REG_SIZE,
+ .iorange_9118 = IORANGE_9118,
+ .n_aichan = 16,
+ .n_aichand = 8,
+ .mux_aichan = 256,
+ .n_aichanlist = PCI9118_CHANLEN,
+ .n_aochan = 2,
+ .ai_maxdata = 0xffff,
+ .ao_maxdata = 0x0fff,
+ .rangelist_ai = &range_pci9118dg_hr,
+ .rangelist_ao = &range_bipolar10,
+ .ai_ns_min = 10000,
+ .ai_pacer_min = 40,
+ .half_fifo_size = 512,
+ },
+};
+
+static struct comedi_driver adl_pci9118_driver = {
+ .driver_name = "adl_pci9118",
+ .module = THIS_MODULE,
+ .attach = pci9118_attach,
+ .detach = pci9118_detach,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .board_name = &boardtypes[0].name,
+ .offset = sizeof(struct boardtype),
+};
+
+static int __devinit adl_pci9118_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, &adl_pci9118_driver);
}
-/*
-==============================================================================
-*/
+static void __devexit adl_pci9118_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(adl_pci9118_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMCC, 0x80d9) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, adl_pci9118_pci_table);
+
+static struct pci_driver adl_pci9118_pci_driver = {
+ .name = "adl_pci9118",
+ .id_table = adl_pci9118_pci_table,
+ .probe = adl_pci9118_pci_probe,
+ .remove = __devexit_p(adl_pci9118_pci_remove),
+};
+module_comedi_pci_driver(adl_pci9118_driver, adl_pci9118_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c
index 5361f318b010..7d585a12050f 100644
--- a/drivers/staging/comedi/drivers/adq12b.c
+++ b/drivers/staging/comedi/drivers/adq12b.c
@@ -125,24 +125,6 @@ struct adq12b_board {
int do_chans;
};
-static const struct adq12b_board adq12b_boards[] = {
- {
- .name = "adq12b",
- .ai_se_chans = 16,
- .ai_diff_chans = 8,
- .ai_bits = 12,
- .di_chans = 5,
- .do_chans = 8}
-/* potentially, more adq-based deviced will be added */
-/*,
- .name = "adq12b",
- .ai_chans = 16, // this is just for reference, hardcoded again later
- .ai_bits = 12,
- .di_chans = 8,
- .do_chans = 5
- }*/
-};
-
#define thisboard ((const struct adq12b_board *)dev->board_ptr)
struct adq12b_private {
@@ -156,41 +138,88 @@ struct adq12b_private {
#define devpriv ((struct adq12b_private *)dev->private)
/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
+ * "instructions" read/write data in "one-shot" or "software-triggered"
+ * mode.
*/
-static int adq12b_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int adq12b_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_adq12b = {
- .driver_name = "adq12b",
- .module = THIS_MODULE,
- .attach = adq12b_attach,
- .detach = adq12b_detach,
- .board_name = &adq12b_boards[0].name,
- .offset = sizeof(struct adq12b_board),
- .num_names = ARRAY_SIZE(adq12b_boards),
-};
static int adq12b_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data);
+ unsigned int *data)
+{
+ int n, i;
+ int range, channel;
+ unsigned char hi, lo, status;
+
+ /* change channel and range only if it is different from the previous */
+ range = CR_RANGE(insn->chanspec);
+ channel = CR_CHAN(insn->chanspec);
+ if (channel != devpriv->last_channel || range != devpriv->last_range) {
+ outb((range << 4) | channel, dev->iobase + ADQ12B_CTREG);
+ udelay(50); /* wait for the mux to settle */
+ }
+
+ /* trigger conversion */
+ status = inb(dev->iobase + ADQ12B_ADLOW);
+
+ /* convert n samples */
+ for (n = 0; n < insn->n; n++) {
+
+ /* wait for end of conversion */
+ i = 0;
+ do {
+ /* udelay(1); */
+ status = inb(dev->iobase + ADQ12B_STINR);
+ status = status & ADQ12B_EOC;
+ } while (status == 0 && ++i < TIMEOUT);
+ /* } while (++i < 10); */
+
+ /* read data */
+ hi = inb(dev->iobase + ADQ12B_ADHIG);
+ lo = inb(dev->iobase + ADQ12B_ADLOW);
+
+ /* printk("debug: chan=%d range=%d status=%d hi=%d lo=%d\n",
+ channel, range, status, hi, lo); */
+ data[n] = (hi << 8) | lo;
+
+ }
+
+ /* return the number of samples read/written */
+ return n;
+}
+
static int adq12b_di_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
+ struct comedi_insn *insn, unsigned int *data)
+{
+
+ /* only bits 0-4 have information about digital inputs */
+ data[1] = (inb(dev->iobase + ADQ12B_STINR) & (0x1f));
+
+ return 2;
+}
+
static int adq12b_do_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
+ struct comedi_insn *insn, unsigned int *data)
+{
+ int channel;
+
+ for (channel = 0; channel < 8; channel++)
+ if (((data[0] >> channel) & 0x01) != 0)
+ outb((((data[1] >> channel) & 0x01) << 3) | channel,
+ dev->iobase + ADQ12B_OUTBR);
+
+ /* store information to retrieve when asked for reading */
+ if (data[0]) {
+ devpriv->digital_state &= ~data[0];
+ devpriv->digital_state |= (data[0] & data[1]);
+ }
+
+ data[1] = devpriv->digital_state;
+
+ return 2;
+}
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board. If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct comedi_subdevice *s;
@@ -295,125 +324,34 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int adq12b_detach(struct comedi_device *dev)
+static void adq12b_detach(struct comedi_device *dev)
{
if (dev->iobase)
release_region(dev->iobase, ADQ12B_SIZE);
-
kfree(devpriv);
-
- printk(KERN_INFO "comedi%d: adq12b: removed\n", dev->minor);
-
- return 0;
-}
-
-/*
- * "instructions" read/write data in "one-shot" or "software-triggered"
- * mode.
- */
-
-static int adq12b_ai_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data)
-{
- int n, i;
- int range, channel;
- unsigned char hi, lo, status;
-
- /* change channel and range only if it is different from the previous */
- range = CR_RANGE(insn->chanspec);
- channel = CR_CHAN(insn->chanspec);
- if (channel != devpriv->last_channel || range != devpriv->last_range) {
- outb((range << 4) | channel, dev->iobase + ADQ12B_CTREG);
- udelay(50); /* wait for the mux to settle */
- }
-
- /* trigger conversion */
- status = inb(dev->iobase + ADQ12B_ADLOW);
-
- /* convert n samples */
- for (n = 0; n < insn->n; n++) {
-
- /* wait for end of conversion */
- i = 0;
- do {
- /* udelay(1); */
- status = inb(dev->iobase + ADQ12B_STINR);
- status = status & ADQ12B_EOC;
- } while (status == 0 && ++i < TIMEOUT);
- /* } while (++i < 10); */
-
- /* read data */
- hi = inb(dev->iobase + ADQ12B_ADHIG);
- lo = inb(dev->iobase + ADQ12B_ADLOW);
-
- /* printk("debug: chan=%d range=%d status=%d hi=%d lo=%d\n",
- channel, range, status, hi, lo); */
- data[n] = (hi << 8) | lo;
-
- }
-
- /* return the number of samples read/written */
- return n;
-}
-
-static int adq12b_di_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
-
- /* only bits 0-4 have information about digital inputs */
- data[1] = (inb(dev->iobase + ADQ12B_STINR) & (0x1f));
-
- return 2;
}
-static int adq12b_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- int channel;
-
- for (channel = 0; channel < 8; channel++)
- if (((data[0] >> channel) & 0x01) != 0)
- outb((((data[1] >> channel) & 0x01) << 3) | channel,
- dev->iobase + ADQ12B_OUTBR);
-
- /* store information to retrieve when asked for reading */
- if (data[0]) {
- devpriv->digital_state &= ~data[0];
- devpriv->digital_state |= (data[0] & data[1]);
- }
-
- data[1] = devpriv->digital_state;
-
- return 2;
-}
-
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __init driver_adq12b_init_module(void)
-{
- return comedi_driver_register(&driver_adq12b);
-}
-
-static void __exit driver_adq12b_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_adq12b);
-}
+static const struct adq12b_board adq12b_boards[] = {
+ {
+ .name = "adq12b",
+ .ai_se_chans = 16,
+ .ai_diff_chans = 8,
+ .ai_bits = 12,
+ .di_chans = 5,
+ .do_chans = 8,
+ },
+};
-module_init(driver_adq12b_init_module);
-module_exit(driver_adq12b_cleanup_module);
+static struct comedi_driver adq12b_driver = {
+ .driver_name = "adq12b",
+ .module = THIS_MODULE,
+ .attach = adq12b_attach,
+ .detach = adq12b_detach,
+ .board_name = &adq12b_boards[0].name,
+ .offset = sizeof(struct adq12b_board),
+ .num_names = ARRAY_SIZE(adq12b_boards),
+};
+module_comedi_driver(adq12b_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c
index 8318c82a555a..de8c98cfe367 100644
--- a/drivers/staging/comedi/drivers/adv_pci1710.c
+++ b/drivers/staging/comedi/drivers/adv_pci1710.c
@@ -191,10 +191,6 @@ static const struct comedi_lrange range_pci171x_da = { 2, {
}
};
-static int pci1710_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pci1710_detach(struct comedi_device *dev);
-
struct boardtype {
const char *name; /* board name */
int device_id;
@@ -216,17 +212,6 @@ struct boardtype {
unsigned int fifo_half_size; /* size of FIFO/2 */
};
-static DEFINE_PCI_DEVICE_TABLE(pci1710_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1710) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1711) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1713) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1720) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1731) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pci1710_pci_table);
-
static const struct boardtype boardtypes[] = {
{"pci1710", 0x1710,
IORANGE_171x, 1, TYPE_PCI171X,
@@ -264,18 +249,6 @@ static const struct boardtype boardtypes[] = {
{.name = DRV_NAME},
};
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
-
-static struct comedi_driver driver_pci1710 = {
- .driver_name = DRV_NAME,
- .module = THIS_MODULE,
- .attach = pci1710_attach,
- .detach = pci1710_detach,
- .num_names = n_boardtypes,
- .board_name = &boardtypes[0].name,
- .offset = sizeof(struct boardtype),
-};
-
struct pci1710_private {
struct pci_dev *pcidev; /* ptr to PCI device */
char valid; /* card is usable */
@@ -676,7 +649,9 @@ static void interrupt_pci1710_every_sample(void *d)
s->async->buf_int_count, s->async->buf_int_ptr,
s->async->buf_user_count, s->async->buf_user_ptr);
DPRINTK("adv_pci1710 EDBG: EOS2\n");
- if ((!devpriv->neverending_ai) && (devpriv->ai_act_scan >= devpriv->ai_scans)) { /* all data sampled */
+ if ((!devpriv->neverending_ai) &&
+ (devpriv->ai_act_scan >= devpriv->ai_scans)) {
+ /* all data sampled */
pci171x_ai_cancel(dev, s);
s->async->events |= COMEDI_CB_EOA;
comedi_event(dev, s);
@@ -804,8 +779,8 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d)
irq);
if (!dev->attached) /* is device attached? */
return IRQ_NONE; /* no, exit */
-
- if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ)) /* is this interrupt from our board? */
+ /* is this interrupt from our board? */
+ if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
return IRQ_NONE; /* no, exit */
DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n",
@@ -814,7 +789,7 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d)
if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
devpriv->ai_et = 0;
devpriv->CntrlReg &= Control_CNT0;
- devpriv->CntrlReg |= Control_SW; /* set software trigger */
+ devpriv->CntrlReg |= Control_SW; /* set software trigger */
outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
outb(0, dev->iobase + PCI171x_CLRFIFO);
@@ -865,7 +840,8 @@ static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev,
devpriv->neverending_ai = 0;
devpriv->CntrlReg &= Control_CNT0;
- if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { /* don't we want wake up every scan? devpriv->ai_eos=1; */
+ /* don't we want wake up every scan? devpriv->ai_eos=1; */
+ if ((devpriv->ai_flags & TRIG_WAKE_EOS)) {
devpriv->ai_eos = 1;
} else {
devpriv->CntrlReg |= Control_ONEFH;
@@ -982,13 +958,13 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev,
#ifdef PCI171X_EXTDEBUG
pci171x_cmdtest_out(1, cmd);
#endif
- DPRINTK
- ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n",
- err);
+ DPRINTK(
+ "adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n",
+ err);
return 1;
}
- /* step 2: make sure trigger sources are unique and mutually compatible */
+ /* step2: make sure trigger srcs are unique and mutually compatible */
if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) {
cmd->start_src = TRIG_NOW;
@@ -1015,9 +991,9 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev,
#ifdef PCI171X_EXTDEBUG
pci171x_cmdtest_out(2, cmd);
#endif
- DPRINTK
- ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n",
- err);
+ DPRINTK(
+ "adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n",
+ err);
return 2;
}
@@ -1065,9 +1041,9 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev,
#ifdef PCI171X_EXTDEBUG
pci171x_cmdtest_out(3, cmd);
#endif
- DPRINTK
- ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n",
- err);
+ DPRINTK(
+ "adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n",
+ err);
return 3;
}
@@ -1160,48 +1136,41 @@ static int check_channel_list(struct comedi_device *dev,
return 0;
}
- if (n_chan > 1) {
- chansegment[0] = chanlist[0]; /* first channel is every time ok */
- for (i = 1, seglen = 1; i < n_chan; i++, seglen++) { /* build part of chanlist */
- /* printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
- if (chanlist[0] == chanlist[i])
- break; /* we detect loop, this must by finish */
- if (CR_CHAN(chanlist[i]) & 1) /* odd channel cann't by differencial */
- if (CR_AREF(chanlist[i]) == AREF_DIFF) {
- comedi_error(dev,
- "Odd channel can't be differential input!\n");
- return 0;
- }
- nowmustbechan =
- (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
- if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
- nowmustbechan = (nowmustbechan + 1) % s->n_chan;
- if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continuous :-( */
- printk
- ("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
- i, CR_CHAN(chanlist[i]), nowmustbechan,
- CR_CHAN(chanlist[0]));
- return 0;
- }
- chansegment[i] = chanlist[i]; /* well, this is next correct channel in list */
+ if (n_chan == 1)
+ return 1; /* seglen=1 */
+
+ chansegment[0] = chanlist[0]; /* first channel is every time ok */
+ for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
+ if (chanlist[0] == chanlist[i])
+ break; /* we detected a loop, stop */
+ if ((CR_CHAN(chanlist[i]) & 1) &&
+ (CR_AREF(chanlist[i]) == AREF_DIFF)) {
+ comedi_error(dev, "Odd channel cannot be differential input!\n");
+ return 0;
}
+ nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
+ if (CR_AREF(chansegment[i - 1]) == AREF_DIFF)
+ nowmustbechan = (nowmustbechan + 1) % s->n_chan;
+ if (nowmustbechan != CR_CHAN(chanlist[i])) {
+ printk("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
+ i, CR_CHAN(chanlist[i]), nowmustbechan,
+ CR_CHAN(chanlist[0]));
+ return 0;
+ }
+ chansegment[i] = chanlist[i]; /* next correct channel in list */
+ }
- for (i = 0, segpos = 0; i < n_chan; i++) { /* check whole chanlist */
- /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */
- if (chanlist[i] != chansegment[i % seglen]) {
- printk
- ("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
- i, CR_CHAN(chansegment[i]),
- CR_RANGE(chansegment[i]),
- CR_AREF(chansegment[i]),
- CR_CHAN(chanlist[i % seglen]),
- CR_RANGE(chanlist[i % seglen]),
- CR_AREF(chansegment[i % seglen]));
- return 0; /* chan/gain list is strange */
- }
+ for (i = 0, segpos = 0; i < n_chan; i++) {
+ if (chanlist[i] != chansegment[i % seglen]) {
+ printk("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
+ i, CR_CHAN(chansegment[i]),
+ CR_RANGE(chansegment[i]),
+ CR_AREF(chansegment[i]),
+ CR_CHAN(chanlist[i % seglen]),
+ CR_RANGE(chanlist[i % seglen]),
+ CR_AREF(chansegment[i % seglen]));
+ return 0;
}
- } else {
- seglen = 1;
}
return seglen;
}
@@ -1221,14 +1190,14 @@ static void setup_channel_list(struct comedi_device *dev,
DPRINTK("SegLen: %d\n", seglen);
for (i = 0; i < seglen; i++) { /* store range list to card */
chanprog = muxonechan[CR_CHAN(chanlist[i])];
- outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
+ outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
if (CR_AREF(chanlist[i]) == AREF_DIFF)
range |= 0x0020;
- outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
+ outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
#ifdef PCI171x_PARANOIDCHECK
devpriv->act_chanlist[i] =
- (CR_CHAN(chanlist[i]) << 12) & 0xf000;
+ (CR_CHAN(chanlist[i]) << 12) & 0xf000;
#endif
DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
devpriv->act_chanlist[i]);
@@ -1236,13 +1205,14 @@ static void setup_channel_list(struct comedi_device *dev,
#ifdef PCI171x_PARANOIDCHECK
for ( ; i < n_chan; i++) { /* store remainder of channel list */
devpriv->act_chanlist[i] =
- (CR_CHAN(chanlist[i]) << 12) & 0xf000;
+ (CR_CHAN(chanlist[i]) << 12) & 0xf000;
}
#endif
devpriv->ai_et_MuxVal =
- CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
- outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); /* select channel interval to scan */
+ CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
+ /* select channel interval to scan */
+ outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
DPRINTK("MUX: %4x L%4x.H%4x\n",
CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8),
CR_CHAN(chanlist[0]), CR_CHAN(chanlist[seglen - 1]));
@@ -1365,9 +1335,6 @@ static int pci1710_reset(struct comedi_device *dev)
DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n");
}
-/*
-==============================================================================
-*/
static int pci1710_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
@@ -1398,13 +1365,13 @@ static int pci1710_attach(struct comedi_device *dev,
while (NULL != (pcidev = pci_get_device(PCI_VENDOR_ID_ADVANTECH,
PCI_ANY_ID, pcidev))) {
if (strcmp(this_board->name, DRV_NAME) == 0) {
- for (i = 0; i < n_boardtypes; ++i) {
+ for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) {
if (pcidev->device == boardtypes[i].device_id) {
board_index = i;
break;
}
}
- if (i == n_boardtypes)
+ if (i == ARRAY_SIZE(boardtypes))
continue;
} else {
if (pcidev->device != boardtypes[board_index].device_id)
@@ -1584,12 +1551,8 @@ static int pci1710_attach(struct comedi_device *dev,
return 0;
}
-/*
-==============================================================================
-*/
-static int pci1710_detach(struct comedi_device *dev)
+static void pci1710_detach(struct comedi_device *dev)
{
-
if (dev->private) {
if (devpriv->valid)
pci1710_reset(dev);
@@ -1598,57 +1561,49 @@ static int pci1710_detach(struct comedi_device *dev)
if (devpriv->pcidev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pcidev);
-
pci_dev_put(devpriv->pcidev);
}
}
-
- return 0;
}
-/*
-==============================================================================
-*/
-static int __devinit driver_pci1710_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static struct comedi_driver adv_pci1710_driver = {
+ .driver_name = "adv_pci1710",
+ .module = THIS_MODULE,
+ .attach = pci1710_attach,
+ .detach = pci1710_detach,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .board_name = &boardtypes[0].name,
+ .offset = sizeof(struct boardtype),
+};
+
+static int __devinit adv_pci1710_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_pci1710.driver_name);
+ return comedi_pci_auto_config(dev, &adv_pci1710_driver);
}
-static void __devexit driver_pci1710_pci_remove(struct pci_dev *dev)
+static void __devexit adv_pci1710_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_pci1710_pci_driver = {
- .id_table = pci1710_pci_table,
- .probe = &driver_pci1710_pci_probe,
- .remove = __devexit_p(&driver_pci1710_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(adv_pci1710_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1710) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1711) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1713) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1720) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1731) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
-static int __init driver_pci1710_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_pci1710);
- if (retval < 0)
- return retval;
-
- driver_pci1710_pci_driver.name = (char *)driver_pci1710.driver_name;
- return pci_register_driver(&driver_pci1710_pci_driver);
-}
-
-static void __exit driver_pci1710_cleanup_module(void)
-{
- pci_unregister_driver(&driver_pci1710_pci_driver);
- comedi_driver_unregister(&driver_pci1710);
-}
-
-module_init(driver_pci1710_init_module);
-module_exit(driver_pci1710_cleanup_module);
-/*
-==============================================================================
-*/
+static struct pci_driver adv_pci1710_pci_driver = {
+ .name = "adv_pci1710",
+ .id_table = adv_pci1710_pci_table,
+ .probe = adv_pci1710_pci_probe,
+ .remove = __devexit_p(adv_pci1710_pci_remove),
+};
+module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c
index 29455a8e88b4..336addcbce3a 100644
--- a/drivers/staging/comedi/drivers/adv_pci1723.c
+++ b/drivers/staging/comedi/drivers/adv_pci1723.c
@@ -150,36 +150,6 @@ static const struct pci1723_board boardtypes[] = {
},
};
-/*
- * This is used by modprobe to translate PCI IDs to drivers.
- * Should only be used for PCI and ISA-PnP devices
- */
-static DEFINE_PCI_DEVICE_TABLE(pci1723_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1723) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pci1723_pci_table);
-
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int pci1723_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pci1723_detach(struct comedi_device *dev);
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pci1723_board))
-
-static struct comedi_driver driver_pci1723 = {
- .driver_name = "adv_pci1723",
- .module = THIS_MODULE,
- .attach = pci1723_attach,
- .detach = pci1723_detach,
-};
-
/* This structure is for data unique to this hardware driver. */
struct pci1723_private {
int valid; /* card is usable; */
@@ -319,10 +289,6 @@ static int pci1723_dio_insn_bits(struct comedi_device *dev,
return 2;
}
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a pci1723 board.
- */
static int pci1723_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
@@ -465,73 +431,50 @@ static int pci1723_attach(struct comedi_device *dev,
return 0;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pci1723_detach(struct comedi_device *dev)
+static void pci1723_detach(struct comedi_device *dev)
{
- printk(KERN_ERR "comedi%d: pci1723: remove\n", dev->minor);
-
if (dev->private) {
if (devpriv->valid)
pci1723_reset(dev);
-
if (devpriv->pcidev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pcidev);
pci_dev_put(devpriv->pcidev);
}
}
-
- return 0;
}
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __devinit driver_pci1723_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static struct comedi_driver adv_pci1723_driver = {
+ .driver_name = "adv_pci1723",
+ .module = THIS_MODULE,
+ .attach = pci1723_attach,
+ .detach = pci1723_detach,
+};
+
+static int __devinit adv_pci1723_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_pci1723.driver_name);
+ return comedi_pci_auto_config(dev, &adv_pci1723_driver);
}
-static void __devexit driver_pci1723_pci_remove(struct pci_dev *dev)
+static void __devexit adv_pci1723_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_pci1723_pci_driver = {
- .id_table = pci1723_pci_table,
- .probe = &driver_pci1723_pci_probe,
- .remove = __devexit_p(&driver_pci1723_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(adv_pci1723_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1723) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, adv_pci1723_pci_table);
-static int __init driver_pci1723_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_pci1723);
- if (retval < 0)
- return retval;
-
- driver_pci1723_pci_driver.name = (char *)driver_pci1723.driver_name;
- return pci_register_driver(&driver_pci1723_pci_driver);
-}
-
-static void __exit driver_pci1723_cleanup_module(void)
-{
- pci_unregister_driver(&driver_pci1723_pci_driver);
- comedi_driver_unregister(&driver_pci1723);
-}
-
-module_init(driver_pci1723_init_module);
-module_exit(driver_pci1723_cleanup_module);
+static struct pci_driver adv_pci1723_pci_driver = {
+ .name = "adv_pci1723",
+ .id_table = adv_pci1723_pci_table,
+ .probe = adv_pci1723_pci_probe,
+ .remove = __devexit_p(adv_pci1723_pci_remove),
+};
+module_comedi_pci_driver(adv_pci1723_driver, adv_pci1723_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c
index 7af068f4a749..43a32dc12cde 100644
--- a/drivers/staging/comedi/drivers/adv_pci_dio.c
+++ b/drivers/staging/comedi/drivers/adv_pci_dio.c
@@ -237,10 +237,6 @@ enum hw_io_access {
#define OMBCMD_RETRY 0x03 /* 3 times try request before error */
-static int pci_dio_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pci_dio_detach(struct comedi_device *dev);
-
struct diosubd_data {
int chans; /* num of chans */
int addr; /* PCI address ofset */
@@ -263,26 +259,6 @@ struct dio_boardtype {
enum hw_io_access io_access;
};
-static DEFINE_PCI_DEVICE_TABLE(pci_dio_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1730) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1733) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1734) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1735) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1736) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1739) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1750) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1751) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1752) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1753) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1754) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1756) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1760) },
- { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1762) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pci_dio_pci_table);
-
static const struct dio_boardtype boardtypes[] = {
{"pci1730", PCI_VENDOR_ID_ADVANTECH, 0x1730, PCIDIO_MAINREG,
TYPE_PCI1730,
@@ -406,15 +382,6 @@ static const struct dio_boardtype boardtypes[] = {
IO_16b}
};
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct dio_boardtype))
-
-static struct comedi_driver driver_pci_dio = {
- .driver_name = "adv_pci_dio",
- .module = THIS_MODULE,
- .attach = pci_dio_attach,
- .detach = pci_dio_detach
-};
-
struct pci_dio_private {
struct pci_dio_private *prev; /* previous private struct */
struct pci_dio_private *next; /* next private struct */
@@ -1116,9 +1083,6 @@ static int CheckAndAllocCard(struct comedi_device *dev,
return 1;
}
-/*
-==============================================================================
-*/
static int pci_dio_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
@@ -1134,7 +1098,7 @@ static int pci_dio_attach(struct comedi_device *dev,
for_each_pci_dev(pcidev) {
/* loop through cards supported by this driver */
- for (i = 0; i < n_boardtypes; ++i) {
+ for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) {
if (boardtypes[i].vendor_id != pcidev->vendor)
continue;
if (boardtypes[i].device_id != pcidev->device)
@@ -1162,7 +1126,7 @@ static int pci_dio_attach(struct comedi_device *dev,
return -EIO;
}
- if (comedi_pci_enable(pcidev, driver_pci_dio.driver_name)) {
+ if (comedi_pci_enable(pcidev, dev->driver->driver_name)) {
dev_err(dev->hw_dev, "Error: Can't enable PCI device and request regions!\n");
return -EIO;
}
@@ -1246,10 +1210,7 @@ static int pci_dio_attach(struct comedi_device *dev,
return 0;
}
-/*
-==============================================================================
-*/
-static int pci_dio_detach(struct comedi_device *dev)
+static void pci_dio_detach(struct comedi_device *dev)
{
int i, j;
struct comedi_subdevice *s;
@@ -1258,20 +1219,14 @@ static int pci_dio_detach(struct comedi_device *dev)
if (dev->private) {
if (devpriv->valid)
pci_dio_reset(dev);
-
-
- /* This shows the silliness of using this kind of
- * scheme for numbering subdevices. Don't do it. --ds */
subdev = 0;
for (i = 0; i < MAX_DI_SUBDEVS; i++) {
if (this_board->sdi[i].chans)
subdev++;
-
}
for (i = 0; i < MAX_DO_SUBDEVS; i++) {
if (this_board->sdo[i].chans)
subdev++;
-
}
for (i = 0; i < MAX_DIO_SUBDEVG; i++) {
for (j = 0; j < this_board->sdio[i].regs; j++) {
@@ -1280,82 +1235,73 @@ static int pci_dio_detach(struct comedi_device *dev)
subdev++;
}
}
-
if (this_board->boardid.chans)
subdev++;
-
for (i = 0; i < MAX_8254_SUBDEVS; i++)
if (this_board->s8254[i].chans)
subdev++;
-
for (i = 0; i < dev->n_subdevices; i++) {
s = dev->subdevices + i;
s->private = NULL;
}
-
if (devpriv->pcidev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pcidev);
-
pci_dev_put(devpriv->pcidev);
}
-
if (devpriv->prev)
devpriv->prev->next = devpriv->next;
else
pci_priv = devpriv->next;
-
if (devpriv->next)
devpriv->next->prev = devpriv->prev;
-
}
-
- return 0;
}
-/*
-==============================================================================
-*/
-static int __devinit driver_pci_dio_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static struct comedi_driver adv_pci_dio_driver = {
+ .driver_name = "adv_pci_dio",
+ .module = THIS_MODULE,
+ .attach = pci_dio_attach,
+ .detach = pci_dio_detach
+};
+
+static int __devinit adv_pci_dio_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_pci_dio.driver_name);
+ return comedi_pci_auto_config(dev, &adv_pci_dio_driver);
}
-static void __devexit driver_pci_dio_pci_remove(struct pci_dev *dev)
+static void __devexit adv_pci_dio_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_pci_dio_pci_driver = {
- .id_table = pci_dio_pci_table,
- .probe = &driver_pci_dio_pci_probe,
- .remove = __devexit_p(&driver_pci_dio_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(adv_pci_dio_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1730) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1733) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1734) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1735) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1736) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1739) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1750) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1751) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1752) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1753) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1754) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1756) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1760) },
+ { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1762) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, adv_pci_dio_pci_table);
-static int __init driver_pci_dio_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_pci_dio);
- if (retval < 0)
- return retval;
-
- driver_pci_dio_pci_driver.name = (char *)driver_pci_dio.driver_name;
- return pci_register_driver(&driver_pci_dio_pci_driver);
-}
-
-static void __exit driver_pci_dio_cleanup_module(void)
-{
- pci_unregister_driver(&driver_pci_dio_pci_driver);
- comedi_driver_unregister(&driver_pci_dio);
-}
-
-module_init(driver_pci_dio_init_module);
-module_exit(driver_pci_dio_cleanup_module);
-/*
-==============================================================================
-*/
+static struct pci_driver adv_pci_dio_pci_driver = {
+ .name = "adv_pci_dio",
+ .id_table = adv_pci_dio_pci_table,
+ .probe = adv_pci_dio_pci_probe,
+ .remove = __devexit_p(adv_pci_dio_pci_remove),
+};
+module_comedi_pci_driver(adv_pci_dio_driver, adv_pci_dio_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c
index b0f98e5e4bf3..64d82bc4ffe4 100644
--- a/drivers/staging/comedi/drivers/aio_aio12_8.c
+++ b/drivers/staging/comedi/drivers/aio_aio12_8.c
@@ -209,36 +209,23 @@ static int aio_aio12_8_attach(struct comedi_device *dev,
return 0;
}
-static int aio_aio12_8_detach(struct comedi_device *dev)
+static void aio_aio12_8_detach(struct comedi_device *dev)
{
subdev_8255_cleanup(dev, &dev->subdevices[2]);
if (dev->iobase)
release_region(dev->iobase, 24);
- return 0;
}
-static struct comedi_driver driver_aio_aio12_8 = {
- .driver_name = "aio_aio12_8",
- .module = THIS_MODULE,
- .attach = aio_aio12_8_attach,
- .detach = aio_aio12_8_detach,
- .board_name = &board_types[0].name,
- .num_names = 1,
- .offset = sizeof(struct aio12_8_boardtype),
+static struct comedi_driver aio_aio12_8_driver = {
+ .driver_name = "aio_aio12_8",
+ .module = THIS_MODULE,
+ .attach = aio_aio12_8_attach,
+ .detach = aio_aio12_8_detach,
+ .board_name = &board_types[0].name,
+ .num_names = ARRAY_SIZE(board_types),
+ .offset = sizeof(struct aio12_8_boardtype),
};
-
-static int __init driver_aio_aio12_8_init_module(void)
-{
- return comedi_driver_register(&driver_aio_aio12_8);
-}
-
-static void __exit driver_aio_aio12_8_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_aio_aio12_8);
-}
-
-module_init(driver_aio_aio12_8_init_module);
-module_exit(driver_aio_aio12_8_cleanup_module);
+module_comedi_driver(aio_aio12_8_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c
index 160b0a0f4f1e..04f6f94b1f47 100644
--- a/drivers/staging/comedi/drivers/aio_iiro_16.c
+++ b/drivers/staging/comedi/drivers/aio_iiro_16.c
@@ -67,30 +67,41 @@ struct aio_iiro_16_private {
#define devpriv ((struct aio_iiro_16_private *) dev->private)
-static int aio_iiro_16_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-
-static int aio_iiro_16_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_aio_iiro_16 = {
- .driver_name = "aio_iiro_16",
- .module = THIS_MODULE,
- .attach = aio_iiro_16_attach,
- .detach = aio_iiro_16_detach,
- .board_name = &aio_iiro_16_boards[0].name,
- .offset = sizeof(struct aio_iiro_16_board),
- .num_names = ARRAY_SIZE(aio_iiro_16_boards),
-};
+static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ if (insn->n != 2)
+ return -EINVAL;
+
+ if (data[0]) {
+ s->state &= ~data[0];
+ s->state |= data[0] & data[1];
+ outb(s->state & 0xff, dev->iobase + AIO_IIRO_16_RELAY_0_7);
+ outb((s->state >> 8) & 0xff,
+ dev->iobase + AIO_IIRO_16_RELAY_8_15);
+ }
+
+ data[1] = s->state;
+
+ return 2;
+}
static int aio_iiro_16_dio_insn_bits_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
- unsigned int *data);
+ unsigned int *data)
+{
+ if (insn->n != 2)
+ return -EINVAL;
-static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
+ data[1] = 0;
+ data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_0_7);
+ data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_8_15) << 8;
+
+ return 2;
+}
static int aio_iiro_16_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
@@ -138,64 +149,22 @@ static int aio_iiro_16_attach(struct comedi_device *dev,
return 1;
}
-static int aio_iiro_16_detach(struct comedi_device *dev)
+static void aio_iiro_16_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: aio_iiro_16: remove\n", dev->minor);
-
if (dev->iobase)
release_region(dev->iobase, AIO_IIRO_16_SIZE);
-
- return 0;
-}
-
-static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- if (insn->n != 2)
- return -EINVAL;
-
- if (data[0]) {
- s->state &= ~data[0];
- s->state |= data[0] & data[1];
- outb(s->state & 0xff, dev->iobase + AIO_IIRO_16_RELAY_0_7);
- outb((s->state >> 8) & 0xff,
- dev->iobase + AIO_IIRO_16_RELAY_8_15);
- }
-
- data[1] = s->state;
-
- return 2;
-}
-
-static int aio_iiro_16_dio_insn_bits_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- if (insn->n != 2)
- return -EINVAL;
-
- data[1] = 0;
- data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_0_7);
- data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_8_15) << 8;
-
- return 2;
-}
-
-static int __init driver_aio_iiro_16_init_module(void)
-{
- return comedi_driver_register(&driver_aio_iiro_16);
}
-static void __exit driver_aio_iiro_16_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_aio_iiro_16);
-}
-
-module_init(driver_aio_iiro_16_init_module);
-module_exit(driver_aio_iiro_16_cleanup_module);
+static struct comedi_driver aio_iiro_16_driver = {
+ .driver_name = "aio_iiro_16",
+ .module = THIS_MODULE,
+ .attach = aio_iiro_16_attach,
+ .detach = aio_iiro_16_detach,
+ .board_name = &aio_iiro_16_boards[0].name,
+ .offset = sizeof(struct aio_iiro_16_board),
+ .num_names = ARRAY_SIZE(aio_iiro_16_boards),
+};
+module_comedi_driver(aio_iiro_16_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c
index 566cc4411452..c9c5d97b3ca2 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200.c
@@ -217,6 +217,14 @@ order they appear in the channel list.
#define DIO200_DRIVER_NAME "amplc_dio200"
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA_MODULE
+#define CONFIG_COMEDI_AMPLC_DIO200_ISA
+#endif
+
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI_MODULE
+#define CONFIG_COMEDI_AMPLC_DIO200_PCI
+#endif
+
/* PCI IDs */
#define PCI_VENDOR_ID_AMPLICON 0x14dc
#define PCI_DEVICE_ID_AMPLICON_PCI272 0x000a
@@ -274,10 +282,14 @@ enum dio200_model {
};
enum dio200_layout {
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
pc212_layout,
pc214_layout,
+#endif
pc215_layout,
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
pc218_layout,
+#endif
pc272_layout
};
@@ -290,6 +302,7 @@ struct dio200_board {
};
static const struct dio200_board dio200_boards[] = {
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
{
.name = "pc212e",
.bustype = isa_bustype,
@@ -308,15 +321,6 @@ static const struct dio200_board dio200_boards[] = {
.model = pc215e_model,
.layout = pc215_layout,
},
-#ifdef CONFIG_COMEDI_PCI
- {
- .name = "pci215",
- .devid = PCI_DEVICE_ID_AMPLICON_PCI215,
- .bustype = pci_bustype,
- .model = pci215_model,
- .layout = pc215_layout,
- },
-#endif
{
.name = "pc218e",
.bustype = isa_bustype,
@@ -329,7 +333,15 @@ static const struct dio200_board dio200_boards[] = {
.model = pc272e_model,
.layout = pc272_layout,
},
-#ifdef CONFIG_COMEDI_PCI
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
+ {
+ .name = "pci215",
+ .devid = PCI_DEVICE_ID_AMPLICON_PCI215,
+ .bustype = pci_bustype,
+ .model = pci215_model,
+ .layout = pc215_layout,
+ },
{
.name = "pci272",
.devid = PCI_DEVICE_ID_AMPLICON_PCI272,
@@ -337,8 +349,6 @@ static const struct dio200_board dio200_boards[] = {
.model = pci272_model,
.layout = pc272_layout,
},
-#endif
-#ifdef CONFIG_COMEDI_PCI
{
.name = DIO200_DRIVER_NAME,
.devid = PCI_DEVICE_ID_INVALID,
@@ -367,6 +377,7 @@ struct dio200_layout_struct {
};
static const struct dio200_layout_struct dio200_layouts[] = {
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
[pc212_layout] = {
.n_subdevs = 6,
.sdtype = {sd_8255, sd_8254, sd_8254, sd_8254,
@@ -385,6 +396,7 @@ static const struct dio200_layout_struct dio200_layouts[] = {
.has_int_sce = 0,
.has_clk_gat_sce = 0,
},
+#endif
[pc215_layout] = {
.n_subdevs = 5,
.sdtype = {sd_8255, sd_8255, sd_8254,
@@ -394,6 +406,7 @@ static const struct dio200_layout_struct dio200_layouts[] = {
.has_int_sce = 1,
.has_clk_gat_sce = 1,
},
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
[pc218_layout] = {
.n_subdevs = 7,
.sdtype = {sd_8254, sd_8254, sd_8255, sd_8254,
@@ -405,6 +418,7 @@ static const struct dio200_layout_struct dio200_layouts[] = {
.has_int_sce = 1,
.has_clk_gat_sce = 1,
},
+#endif
[pc272_layout] = {
.n_subdevs = 4,
.sdtype = {sd_8255, sd_8255, sd_8255,
@@ -419,7 +433,7 @@ static const struct dio200_layout_struct dio200_layouts[] = {
* PCI driver table.
*/
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272) },
@@ -427,7 +441,7 @@ static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = {
};
MODULE_DEVICE_TABLE(pci, dio200_pci_table);
-#endif /* CONFIG_COMEDI_PCI */
+#endif /* CONFIG_COMEDI_AMPLC_DIO200_PCI */
/*
* Useful for shorthand access to the particular board structure
@@ -441,7 +455,7 @@ MODULE_DEVICE_TABLE(pci, dio200_pci_table);
feel free to suggest moving the variable to the struct comedi_device struct.
*/
struct dio200_private {
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
struct pci_dev *pci_dev; /* PCI device */
#endif
int intr_sd;
@@ -479,7 +493,7 @@ struct dio200_subdev_intr {
*/
static int dio200_attach(struct comedi_device *dev,
struct comedi_devconfig *it);
-static int dio200_detach(struct comedi_device *dev);
+static void dio200_detach(struct comedi_device *dev);
static struct comedi_driver driver_amplc_dio200 = {
.driver_name = DIO200_DRIVER_NAME,
.module = THIS_MODULE,
@@ -490,12 +504,12 @@ static struct comedi_driver driver_amplc_dio200 = {
.num_names = ARRAY_SIZE(dio200_boards),
};
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
static int __devinit driver_amplc_dio200_pci_probe(struct pci_dev *dev,
const struct pci_device_id
*ent)
{
- return comedi_pci_auto_config(dev, driver_amplc_dio200.driver_name);
+ return comedi_pci_auto_config(dev, &driver_amplc_dio200);
}
static void __devexit driver_amplc_dio200_pci_remove(struct pci_dev *dev)
@@ -549,7 +563,7 @@ module_exit(driver_amplc_dio200_cleanup_module);
* This function looks for a PCI device matching the requested board name,
* bus and slot.
*/
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
static int
dio200_find_pci(struct comedi_device *dev, int bus, int slot,
struct pci_dev **pci_dev_p)
@@ -611,6 +625,7 @@ dio200_find_pci(struct comedi_device *dev, int bus, int slot,
* This function checks and requests an I/O region, reporting an error
* if there is a conflict.
*/
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
static int
dio200_request_region(unsigned minor, unsigned long from, unsigned long extent)
{
@@ -621,6 +636,7 @@ dio200_request_region(unsigned minor, unsigned long from, unsigned long extent)
}
return 0;
}
+#endif
/*
* 'insn_bits' function for an 'INTERRUPT' subdevice.
@@ -1332,7 +1348,7 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
struct comedi_subdevice *s;
unsigned long iobase = 0;
unsigned int irq = 0;
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
struct pci_dev *pci_dev = NULL;
int bus = 0, slot = 0;
#endif
@@ -1354,12 +1370,14 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* Process options. */
switch (thisboard->bustype) {
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
case isa_bustype:
iobase = it->options[0];
irq = it->options[1];
share_irq = 0;
break;
-#ifdef CONFIG_COMEDI_PCI
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
case pci_bustype:
bus = it->options[0];
slot = it->options[1];
@@ -1382,7 +1400,7 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
devpriv->intr_sd = -1;
/* Enable device and reserve I/O spaces. */
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
if (pci_dev) {
ret = comedi_pci_enable(pci_dev, DIO200_DRIVER_NAME);
if (ret < 0) {
@@ -1396,9 +1414,11 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
} else
#endif
{
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
ret = dio200_request_region(dev->minor, iobase, DIO200_IO_SIZE);
if (ret < 0)
return ret;
+#endif
}
dev->iobase = iobase;
@@ -1474,12 +1494,19 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
}
printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
- if (thisboard->bustype == isa_bustype) {
+ switch (thisboard->bustype) {
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
+ case isa_bustype:
printk("(base %#lx) ", iobase);
- } else {
-#ifdef CONFIG_COMEDI_PCI
+ break;
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
+ case pci_bustype:
printk("(pci %s) ", pci_name(pci_dev));
+ break;
#endif
+ default:
+ break;
}
if (irq)
printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE"));
@@ -1491,22 +1518,11 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 1;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int dio200_detach(struct comedi_device *dev)
+static void dio200_detach(struct comedi_device *dev)
{
const struct dio200_layout_struct *layout;
unsigned n;
- printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor,
- DIO200_DRIVER_NAME);
-
if (dev->irq)
free_irq(dev->irq, dev);
if (dev->subdevices) {
@@ -1529,7 +1545,7 @@ static int dio200_detach(struct comedi_device *dev)
}
}
if (devpriv) {
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_PCI
if (devpriv->pci_dev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
@@ -1537,15 +1553,12 @@ static int dio200_detach(struct comedi_device *dev)
} else
#endif
{
+#ifdef CONFIG_COMEDI_AMPLC_DIO200_ISA
if (dev->iobase)
release_region(dev->iobase, DIO200_IO_SIZE);
+#endif
}
}
- if (dev->board_name)
- printk(KERN_INFO "comedi%d: %s removed\n",
- dev->minor, dev->board_name);
-
- return 0;
}
MODULE_AUTHOR("Comedi http://www.comedi.org");
diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c
index 7972cadd403e..57ba3228b1a9 100644
--- a/drivers/staging/comedi/drivers/amplc_pc236.c
+++ b/drivers/staging/comedi/drivers/amplc_pc236.c
@@ -63,6 +63,14 @@ unused.
#define PC236_DRIVER_NAME "amplc_pc236"
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA_MODULE
+#define CONFIG_COMEDI_AMPLC_PC236_ISA
+#endif
+
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI_MODULE
+#define CONFIG_COMEDI_AMPLC_PC236_PCI
+#endif
+
/* PCI236 PCI configuration register information */
#define PCI_VENDOR_ID_AMPLICON 0x14dc
#define PCI_DEVICE_ID_AMPLICON_PCI236 0x0009
@@ -106,13 +114,15 @@ struct pc236_board {
enum pc236_model model;
};
static const struct pc236_board pc236_boards[] = {
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
{
.name = "pc36at",
.fancy_name = "PC36AT",
.bustype = isa_bustype,
.model = pc36at_model,
},
-#ifdef CONFIG_COMEDI_PCI
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
{
.name = "pci236",
.fancy_name = "PCI236",
@@ -120,8 +130,6 @@ static const struct pc236_board pc236_boards[] = {
.bustype = pci_bustype,
.model = pci236_model,
},
-#endif
-#ifdef CONFIG_COMEDI_PCI
{
.name = PC236_DRIVER_NAME,
.fancy_name = PC236_DRIVER_NAME,
@@ -132,14 +140,14 @@ static const struct pc236_board pc236_boards[] = {
#endif
};
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
static DEFINE_PCI_DEVICE_TABLE(pc236_pci_table) = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI236) },
{0}
};
MODULE_DEVICE_TABLE(pci, pc236_pci_table);
-#endif /* CONFIG_COMEDI_PCI */
+#endif /* CONFIG_COMEDI_AMPLC_PC236_PCI */
/*
* Useful for shorthand access to the particular board structure
@@ -151,7 +159,7 @@ MODULE_DEVICE_TABLE(pci, pc236_pci_table);
feel free to suggest moving the variable to the struct comedi_device struct.
*/
struct pc236_private {
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
/* PCI device */
struct pci_dev *pci_dev;
unsigned long lcr_iobase; /* PLX PCI9052 config registers in PCIBAR1 */
@@ -168,7 +176,7 @@ struct pc236_private {
* the device code.
*/
static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int pc236_detach(struct comedi_device *dev);
+static void pc236_detach(struct comedi_device *dev);
static struct comedi_driver driver_amplc_pc236 = {
.driver_name = PC236_DRIVER_NAME,
.module = THIS_MODULE,
@@ -179,12 +187,12 @@ static struct comedi_driver driver_amplc_pc236 = {
.num_names = ARRAY_SIZE(pc236_boards),
};
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
static int __devinit driver_amplc_pc236_pci_probe(struct pci_dev *dev,
const struct pci_device_id
*ent)
{
- return comedi_pci_auto_config(dev, driver_amplc_pc236.driver_name);
+ return comedi_pci_auto_config(dev, &driver_amplc_pc236);
}
static void __devexit driver_amplc_pc236_pci_remove(struct pci_dev *dev)
@@ -234,8 +242,10 @@ module_init(driver_amplc_pc236_init_module);
module_exit(driver_amplc_pc236_cleanup_module);
#endif
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
static int pc236_request_region(unsigned minor, unsigned long from,
unsigned long extent);
+#endif
static void pc236_intr_disable(struct comedi_device *dev);
static void pc236_intr_enable(struct comedi_device *dev);
static int pc236_intr_check(struct comedi_device *dev);
@@ -255,7 +265,7 @@ static irqreturn_t pc236_interrupt(int irq, void *d);
* This function looks for a PCI device matching the requested board name,
* bus and slot.
*/
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
static int
pc236_find_pci(struct comedi_device *dev, int bus, int slot,
struct pci_dev **pci_dev_p)
@@ -324,7 +334,7 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it)
struct comedi_subdevice *s;
unsigned long iobase = 0;
unsigned int irq = 0;
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
struct pci_dev *pci_dev = NULL;
int bus = 0, slot = 0;
#endif
@@ -345,12 +355,14 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it)
}
/* Process options. */
switch (thisboard->bustype) {
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
case isa_bustype:
iobase = it->options[0];
irq = it->options[1];
share_irq = 0;
break;
-#ifdef CONFIG_COMEDI_PCI
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
case pci_bustype:
bus = it->options[0];
slot = it->options[1];
@@ -361,7 +373,7 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return ret;
devpriv->pci_dev = pci_dev;
break;
-#endif /* CONFIG_COMEDI_PCI */
+#endif
default:
printk(KERN_ERR
"comedi%d: %s: BUG! cannot determine board type!\n",
@@ -376,7 +388,7 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it)
dev->board_name = thisboard->name;
/* Enable device and reserve I/O spaces. */
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
if (pci_dev) {
ret = comedi_pci_enable(pci_dev, PC236_DRIVER_NAME);
@@ -392,9 +404,11 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it)
} else
#endif
{
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
ret = pc236_request_region(dev->minor, iobase, PC236_IO_SIZE);
if (ret < 0)
return ret;
+#endif
}
dev->iobase = iobase;
@@ -439,12 +453,19 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it)
}
}
printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
- if (thisboard->bustype == isa_bustype) {
+ switch (thisboard->bustype) {
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
+ case isa_bustype:
printk("(base %#lx) ", iobase);
- } else {
-#ifdef CONFIG_COMEDI_PCI
+ break;
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
+ case pci_bustype:
printk("(pci %s) ", pci_name(pci_dev));
+ break;
#endif
+ default:
+ break;
}
if (irq)
printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE"));
@@ -456,27 +477,16 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 1;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pc236_detach(struct comedi_device *dev)
+static void pc236_detach(struct comedi_device *dev)
{
- printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor,
- PC236_DRIVER_NAME);
if (devpriv)
pc236_intr_disable(dev);
-
if (dev->irq)
free_irq(dev->irq, dev);
if (dev->subdevices)
subdev_8255_cleanup(dev, dev->subdevices + 0);
if (devpriv) {
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
if (devpriv->pci_dev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
@@ -484,21 +494,19 @@ static int pc236_detach(struct comedi_device *dev)
} else
#endif
{
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
if (dev->iobase)
release_region(dev->iobase, PC236_IO_SIZE);
+#endif
}
}
- if (dev->board_name) {
- printk(KERN_INFO "comedi%d: %s removed\n",
- dev->minor, dev->board_name);
- }
- return 0;
}
/*
* This function checks and requests an I/O region, reporting an error
* if there is a conflict.
*/
+#ifdef CONFIG_COMEDI_AMPLC_PC236_ISA
static int pc236_request_region(unsigned minor, unsigned long from,
unsigned long extent)
{
@@ -509,6 +517,7 @@ static int pc236_request_region(unsigned minor, unsigned long from,
}
return 0;
}
+#endif
/*
* This function is called to mark the interrupt as disabled (no command
@@ -521,7 +530,7 @@ static void pc236_intr_disable(struct comedi_device *dev)
spin_lock_irqsave(&dev->spinlock, flags);
devpriv->enable_irq = 0;
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
if (devpriv->lcr_iobase)
outl(PCI236_INTR_DISABLE, devpriv->lcr_iobase + PLX9052_INTCSR);
#endif
@@ -539,7 +548,7 @@ static void pc236_intr_enable(struct comedi_device *dev)
spin_lock_irqsave(&dev->spinlock, flags);
devpriv->enable_irq = 1;
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
if (devpriv->lcr_iobase)
outl(PCI236_INTR_ENABLE, devpriv->lcr_iobase + PLX9052_INTCSR);
#endif
@@ -561,7 +570,7 @@ static int pc236_intr_check(struct comedi_device *dev)
spin_lock_irqsave(&dev->spinlock, flags);
if (devpriv->enable_irq) {
retval = 1;
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC236_PCI
if (devpriv->lcr_iobase) {
if ((inl(devpriv->lcr_iobase + PLX9052_INTCSR)
& PLX9052_INTCSR_LI1STAT_MASK)
diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c
index 191ac0d23ce7..974d7450051e 100644
--- a/drivers/staging/comedi/drivers/amplc_pc263.c
+++ b/drivers/staging/comedi/drivers/amplc_pc263.c
@@ -50,6 +50,14 @@ The state of the outputs can be read.
#define PC263_DRIVER_NAME "amplc_pc263"
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA_MODULE
+#define CONFIG_COMEDI_AMPLC_PC263_ISA
+#endif
+
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI_MODULE
+#define CONFIG_COMEDI_AMPLC_PC263_PCI
+#endif
+
/* PCI263 PCI configuration register information */
#define PCI_VENDOR_ID_AMPLICON 0x14dc
#define PCI_DEVICE_ID_AMPLICON_PCI263 0x000c
@@ -73,13 +81,15 @@ struct pc263_board {
enum pc263_model model;
};
static const struct pc263_board pc263_boards[] = {
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
{
.name = "pc263",
.fancy_name = "PC263",
.bustype = isa_bustype,
.model = pc263_model,
},
-#ifdef CONFIG_COMEDI_PCI
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
{
.name = "pci263",
.fancy_name = "PCI263",
@@ -87,8 +97,6 @@ static const struct pc263_board pc263_boards[] = {
.bustype = pci_bustype,
.model = pci263_model,
},
-#endif
-#ifdef CONFIG_COMEDI_PCI
{
.name = PC263_DRIVER_NAME,
.fancy_name = PC263_DRIVER_NAME,
@@ -99,14 +107,14 @@ static const struct pc263_board pc263_boards[] = {
#endif
};
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
static DEFINE_PCI_DEVICE_TABLE(pc263_pci_table) = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI263) },
{0}
};
MODULE_DEVICE_TABLE(pci, pc263_pci_table);
-#endif /* CONFIG_COMEDI_PCI */
+#endif /* CONFIG_COMEDI_AMPLC_PC263_PCI */
/*
* Useful for shorthand access to the particular board structure
@@ -117,14 +125,14 @@ MODULE_DEVICE_TABLE(pci, pc263_pci_table);
several hardware drivers keep similar information in this structure,
feel free to suggest moving the variable to the struct comedi_device struct.
*/
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
struct pc263_private {
/* PCI device. */
struct pci_dev *pci_dev;
};
#define devpriv ((struct pc263_private *)dev->private)
-#endif /* CONFIG_COMEDI_PCI */
+#endif /* CONFIG_COMEDI_AMPLC_PC263_PCI */
/*
* The struct comedi_driver structure tells the Comedi core module
@@ -133,7 +141,7 @@ struct pc263_private {
* the device code.
*/
static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int pc263_detach(struct comedi_device *dev);
+static void pc263_detach(struct comedi_device *dev);
static struct comedi_driver driver_amplc_pc263 = {
.driver_name = PC263_DRIVER_NAME,
.module = THIS_MODULE,
@@ -144,8 +152,10 @@ static struct comedi_driver driver_amplc_pc263 = {
.num_names = ARRAY_SIZE(pc263_boards),
};
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
static int pc263_request_region(unsigned minor, unsigned long from,
unsigned long extent);
+#endif
static int pc263_dio_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
@@ -157,7 +167,7 @@ static int pc263_dio_insn_config(struct comedi_device *dev,
* This function looks for a PCI device matching the requested board name,
* bus and slot.
*/
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
static int
pc263_find_pci(struct comedi_device *dev, int bus, int slot,
struct pci_dev **pci_dev_p)
@@ -225,7 +235,7 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct comedi_subdevice *s;
unsigned long iobase = 0;
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
struct pci_dev *pci_dev = NULL;
int bus = 0, slot = 0;
#endif
@@ -237,7 +247,7 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
* Allocate the private structure area. alloc_private() is a
* convenient macro defined in comedidev.h.
*/
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
ret = alloc_private(dev, sizeof(struct pc263_private));
if (ret < 0) {
printk(KERN_ERR "comedi%d: error! out of memory!\n",
@@ -247,10 +257,12 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
#endif
/* Process options. */
switch (thisboard->bustype) {
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
case isa_bustype:
iobase = it->options[0];
break;
-#ifdef CONFIG_COMEDI_PCI
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
case pci_bustype:
bus = it->options[0];
slot = it->options[1];
@@ -260,7 +272,7 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return ret;
devpriv->pci_dev = pci_dev;
break;
-#endif /* CONFIG_COMEDI_PCI */
+#endif
default:
printk(KERN_ERR
"comedi%d: %s: BUG! cannot determine board type!\n",
@@ -275,7 +287,7 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
dev->board_name = thisboard->name;
/* Enable device and reserve I/O spaces. */
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
if (pci_dev) {
ret = comedi_pci_enable(pci_dev, PC263_DRIVER_NAME);
if (ret < 0) {
@@ -289,9 +301,11 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
} else
#endif
{
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
ret = pc263_request_region(dev->minor, iobase, PC263_IO_SIZE);
if (ret < 0)
return ret;
+#endif
}
dev->iobase = iobase;
@@ -322,12 +336,18 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->state = s->state | (inb(dev->iobase) << 8);
printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name);
- if (thisboard->bustype == isa_bustype) {
+ switch (thisboard->bustype) {
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
+ case isa_bustype:
printk("(base %#lx) ", iobase);
- } else {
-#ifdef CONFIG_COMEDI_PCI
+ break;
+#endif
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
printk("(pci %s) ", pci_name(pci_dev));
+ break;
#endif
+ default:
+ break;
}
printk("attached\n");
@@ -335,23 +355,13 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 1;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pc263_detach(struct comedi_device *dev)
+static void pc263_detach(struct comedi_device *dev)
{
- printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor,
- PC263_DRIVER_NAME);
-
-#ifdef CONFIG_COMEDI_PCI
- if (devpriv) {
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
+ if (devpriv)
#endif
-#ifdef CONFIG_COMEDI_PCI
+ {
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
if (devpriv->pci_dev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
@@ -359,21 +369,19 @@ static int pc263_detach(struct comedi_device *dev)
} else
#endif
{
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
if (dev->iobase)
release_region(dev->iobase, PC263_IO_SIZE);
+#endif
}
}
- if (dev->board_name) {
- printk(KERN_INFO "comedi%d: %s removed\n",
- dev->minor, dev->board_name);
- }
- return 0;
}
/*
* This function checks and requests an I/O region, reporting an error
* if there is a conflict.
*/
+#ifdef CONFIG_COMEDI_AMPLC_PC263_ISA
static int pc263_request_region(unsigned minor, unsigned long from,
unsigned long extent)
{
@@ -384,6 +392,7 @@ static int pc263_request_region(unsigned minor, unsigned long from,
}
return 0;
}
+#endif
/* DIO devices are slightly special. Although it is possible to
* implement the insn_read/insn_write interface, it is much more
@@ -429,12 +438,12 @@ static int pc263_dio_insn_config(struct comedi_device *dev,
* A convenient macro that defines init_module() and cleanup_module(),
* as necessary.
*/
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_AMPLC_PC263_PCI
static int __devinit driver_amplc_pc263_pci_probe(struct pci_dev *dev,
const struct pci_device_id
*ent)
{
- return comedi_pci_auto_config(dev, driver_amplc_pc263.driver_name);
+ return comedi_pci_auto_config(dev, &driver_amplc_pc263);
}
static void __devexit driver_amplc_pc263_pci_remove(struct pci_dev *dev)
diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c
index b278917cec25..fbf19cae8747 100644
--- a/drivers/staging/comedi/drivers/amplc_pci224.c
+++ b/drivers/staging/comedi/drivers/amplc_pci224.c
@@ -380,18 +380,6 @@ static const struct pci224_board pci224_boards[] = {
};
/*
- * PCI driver table.
- */
-
-static DEFINE_PCI_DEVICE_TABLE(pci224_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI224) },
- { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI234) },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, pci224_pci_table);
-
-/*
* Useful for shorthand access to the particular board structure
*/
#define thisboard ((struct pci224_board *)dev->board_ptr)
@@ -422,65 +410,6 @@ struct pci224_private {
#define devpriv ((struct pci224_private *)dev->private)
/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int pci224_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pci224_detach(struct comedi_device *dev);
-static struct comedi_driver driver_amplc_pci224 = {
- .driver_name = DRIVER_NAME,
- .module = THIS_MODULE,
- .attach = pci224_attach,
- .detach = pci224_detach,
- .board_name = &pci224_boards[0].name,
- .offset = sizeof(struct pci224_board),
- .num_names = ARRAY_SIZE(pci224_boards),
-};
-
-static int __devinit driver_amplc_pci224_pci_probe(struct pci_dev *dev,
- const struct pci_device_id
- *ent)
-{
- return comedi_pci_auto_config(dev, driver_amplc_pci224.driver_name);
-}
-
-static void __devexit driver_amplc_pci224_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_amplc_pci224_pci_driver = {
- .id_table = pci224_pci_table,
- .probe = &driver_amplc_pci224_pci_probe,
- .remove = __devexit_p(&driver_amplc_pci224_pci_remove)
-};
-
-static int __init driver_amplc_pci224_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_amplc_pci224);
- if (retval < 0)
- return retval;
-
- driver_amplc_pci224_pci_driver.name =
- (char *)driver_amplc_pci224.driver_name;
- return pci_register_driver(&driver_amplc_pci224_pci_driver);
-}
-
-static void __exit driver_amplc_pci224_cleanup_module(void)
-{
- pci_unregister_driver(&driver_amplc_pci224_pci_driver);
- comedi_driver_unregister(&driver_amplc_pci224);
-}
-
-module_init(driver_amplc_pci224_init_module);
-module_exit(driver_amplc_pci224_cleanup_module);
-
-/*
* Called from the 'insn_write' function to perform a single write.
*/
static void
@@ -1312,6 +1241,20 @@ static irqreturn_t pci224_interrupt(int irq, void *d)
}
/*
+ * This function looks for a board matching the supplied PCI device.
+ */
+static const struct pci224_board
+*pci224_find_pci_board(struct pci_dev *pci_dev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pci224_boards); i++)
+ if (pci_dev->device == pci224_boards[i].devid)
+ return &pci224_boards[i];
+ return NULL;
+}
+
+/*
* This function looks for a PCI device matching the requested board name,
* bus and slot.
*/
@@ -1336,17 +1279,12 @@ pci224_find_pci(struct comedi_device *dev, int bus, int slot,
}
if (thisboard->model == any_model) {
/* Match any supported model. */
- int i;
-
- for (i = 0; i < ARRAY_SIZE(pci224_boards); i++) {
- if (pci_dev->device == pci224_boards[i].devid) {
- /* Change board_ptr to matched board. */
- dev->board_ptr = &pci224_boards[i];
- break;
- }
- }
- if (i == ARRAY_SIZE(pci224_boards))
+ const struct pci224_board *board_ptr;
+ board_ptr = pci224_find_pci_board(pci_dev);
+ if (board_ptr == NULL)
continue;
+ /* Change board_ptr to matched board. */
+ dev->board_ptr = board_ptr;
} else {
/* Match specific model name. */
if (thisboard->devid != pci_dev->device)
@@ -1370,35 +1308,16 @@ pci224_find_pci(struct comedi_device *dev, int bus, int slot,
}
/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board. If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
+ * Common part of attach and attach_pci.
*/
-static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+static int pci224_attach_common(struct comedi_device *dev,
+ struct pci_dev *pci_dev, int *options)
{
struct comedi_subdevice *s;
- struct pci_dev *pci_dev;
unsigned int irq;
- int bus = 0, slot = 0;
unsigned n;
int ret;
- printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor, DRIVER_NAME);
-
- bus = it->options[0];
- slot = it->options[1];
- ret = alloc_private(dev, sizeof(struct pci224_private));
- if (ret < 0) {
- printk(KERN_ERR "comedi%d: error! out of memory!\n",
- dev->minor);
- return ret;
- }
-
- ret = pci224_find_pci(dev, bus, slot, &pci_dev);
- if (ret < 0)
- return ret;
-
devpriv->pci_dev = pci_dev;
ret = comedi_pci_enable(pci_dev, DRIVER_NAME);
if (ret < 0) {
@@ -1483,24 +1402,26 @@ static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (!s->range_table_list)
return -ENOMEM;
- for (n = 2; n < 3 + s->n_chan; n++) {
- if (it->options[n] < 0 || it->options[n] > 1) {
- printk(KERN_WARNING "comedi%d: %s: warning! "
- "bad options[%u]=%d\n",
- dev->minor, DRIVER_NAME, n,
- it->options[n]);
+ if (options) {
+ for (n = 2; n < 3 + s->n_chan; n++) {
+ if (options[n] < 0 || options[n] > 1) {
+ printk(KERN_WARNING
+ "comedi%d: %s: warning! bad options[%u]=%d\n",
+ dev->minor, DRIVER_NAME, n,
+ options[n]);
+ }
}
}
for (n = 0; n < s->n_chan; n++) {
- if (n < COMEDI_NDEVCONFOPTS - 3 &&
- it->options[3 + n] == 1) {
- if (it->options[2] == 1)
+ if (n < COMEDI_NDEVCONFOPTS - 3 && options &&
+ options[3 + n] == 1) {
+ if (options[2] == 1)
range_table_list[n] = &range_pci234_ext;
else
range_table_list[n] = &range_bipolar5;
} else {
- if (it->options[2] == 1) {
+ if (options && options[2] == 1) {
range_table_list[n] =
&range_pci234_ext2;
} else {
@@ -1511,14 +1432,14 @@ static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it)
devpriv->hwrange = hwrange_pci234;
} else {
/* PCI224 range options. */
- if (it->options[2] == 1) {
+ if (options && options[2] == 1) {
s->range_table = &range_pci224_external;
devpriv->hwrange = hwrange_pci224_external;
} else {
- if (it->options[2] != 0) {
+ if (options && options[2] != 0) {
printk(KERN_WARNING "comedi%d: %s: warning! "
"bad options[2]=%d\n",
- dev->minor, DRIVER_NAME, it->options[2]);
+ dev->minor, DRIVER_NAME, options[2]);
}
s->range_table = &range_pci224_internal;
devpriv->hwrange = hwrange_pci224_internal;
@@ -1552,21 +1473,59 @@ static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 1;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pci224_detach(struct comedi_device *dev)
+static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+ struct pci_dev *pci_dev;
+ int bus, slot;
+ int ret;
+
+ printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor, DRIVER_NAME);
+
+ bus = it->options[0];
+ slot = it->options[1];
+ ret = alloc_private(dev, sizeof(struct pci224_private));
+ if (ret < 0) {
+ printk(KERN_ERR "comedi%d: error! out of memory!\n",
+ dev->minor);
+ return ret;
+ }
+
+ ret = pci224_find_pci(dev, bus, slot, &pci_dev);
+ if (ret < 0)
+ return ret;
+
+ return pci224_attach_common(dev, pci_dev, it->options);
+}
+
+static int
+pci224_attach_pci(struct comedi_device *dev, struct pci_dev *pci_dev)
{
- printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor, DRIVER_NAME);
+ int ret;
+
+ printk(KERN_DEBUG "comedi%d: %s: attach_pci %s\n", dev->minor,
+ DRIVER_NAME, pci_name(pci_dev));
+
+ ret = alloc_private(dev, sizeof(struct pci224_private));
+ if (ret < 0) {
+ printk(KERN_ERR "comedi%d: error! out of memory!\n",
+ dev->minor);
+ return ret;
+ }
+ dev->board_ptr = pci224_find_pci_board(pci_dev);
+ if (dev->board_ptr == NULL) {
+ printk(KERN_ERR
+ "comedi%d: %s: BUG! cannot determine board type!\n",
+ dev->minor, DRIVER_NAME);
+ return -EINVAL;
+ }
+ return pci224_attach_common(dev, pci_dev, NULL);
+}
+
+static void pci224_detach(struct comedi_device *dev)
+{
if (dev->irq)
free_irq(dev->irq, dev);
-
if (dev->subdevices) {
struct comedi_subdevice *s;
@@ -1581,18 +1540,49 @@ static int pci224_detach(struct comedi_device *dev)
if (devpriv->pci_dev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
-
pci_dev_put(devpriv->pci_dev);
}
}
- if (dev->board_name) {
- printk(KERN_INFO "comedi%d: %s removed\n",
- dev->minor, dev->board_name);
- }
+}
- return 0;
+static struct comedi_driver amplc_pci224_driver = {
+ .driver_name = "amplc_pci224",
+ .module = THIS_MODULE,
+ .attach = pci224_attach,
+ .detach = pci224_detach,
+ .attach_pci = pci224_attach_pci,
+ .board_name = &pci224_boards[0].name,
+ .offset = sizeof(struct pci224_board),
+ .num_names = ARRAY_SIZE(pci224_boards),
+};
+
+static int __devinit amplc_pci224_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id
+ *ent)
+{
+ return comedi_pci_auto_config(dev, &amplc_pci224_driver);
}
+static void __devexit amplc_pci224_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(amplc_pci224_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI224) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI234) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, amplc_pci224_pci_table);
+
+static struct pci_driver amplc_pci224_pci_driver = {
+ .name = "amplc_pci224",
+ .id_table = amplc_pci224_pci_table,
+ .probe = amplc_pci224_pci_probe,
+ .remove = __devexit_p(amplc_pci224_pci_remove),
+};
+module_comedi_pci_driver(amplc_pci224_driver, amplc_pci224_pci_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c
index 538979551c8e..d4c80b1281f2 100644
--- a/drivers/staging/comedi/drivers/amplc_pci230.c
+++ b/drivers/staging/comedi/drivers/amplc_pci230.c
@@ -500,13 +500,6 @@ static const struct pci230_board pci230_boards[] = {
},
};
-static DEFINE_PCI_DEVICE_TABLE(pci230_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI230) },
- { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI260) },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, pci230_pci_table);
/*
* Useful for shorthand access to the particular board structure
*/
@@ -595,65 +588,6 @@ static const struct comedi_lrange pci230_ao_range = { 2, {
/* PCI230 daccon bipolar flag for each analogue output range. */
static const unsigned char pci230_ao_bipolar[2] = { 0, 1 };
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int pci230_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pci230_detach(struct comedi_device *dev);
-static struct comedi_driver driver_amplc_pci230 = {
- .driver_name = "amplc_pci230",
- .module = THIS_MODULE,
- .attach = pci230_attach,
- .detach = pci230_detach,
- .board_name = &pci230_boards[0].name,
- .offset = sizeof(pci230_boards[0]),
- .num_names = ARRAY_SIZE(pci230_boards),
-};
-
-static int __devinit driver_amplc_pci230_pci_probe(struct pci_dev *dev,
- const struct pci_device_id
- *ent)
-{
- return comedi_pci_auto_config(dev, driver_amplc_pci230.driver_name);
-}
-
-static void __devexit driver_amplc_pci230_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_amplc_pci230_pci_driver = {
- .id_table = pci230_pci_table,
- .probe = &driver_amplc_pci230_pci_probe,
- .remove = __devexit_p(&driver_amplc_pci230_pci_remove)
-};
-
-static int __init driver_amplc_pci230_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_amplc_pci230);
- if (retval < 0)
- return retval;
-
- driver_amplc_pci230_pci_driver.name =
- (char *)driver_amplc_pci230.driver_name;
- return pci_register_driver(&driver_amplc_pci230_pci_driver);
-}
-
-static void __exit driver_amplc_pci230_cleanup_module(void)
-{
- pci_unregister_driver(&driver_amplc_pci230_pci_driver);
- comedi_driver_unregister(&driver_amplc_pci230);
-}
-
-module_init(driver_amplc_pci230_init_module);
-module_exit(driver_amplc_pci230_cleanup_module);
-
static int pci230_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
unsigned int *data);
@@ -1003,35 +937,19 @@ static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 1;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pci230_detach(struct comedi_device *dev)
+static void pci230_detach(struct comedi_device *dev)
{
- printk("comedi%d: amplc_pci230: remove\n", dev->minor);
-
if (dev->subdevices && thisboard->have_dio)
- /* Clean up dio subdevice. */
subdev_8255_cleanup(dev, dev->subdevices + 2);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
if (devpriv) {
if (devpriv->pci_dev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
-
pci_dev_put(devpriv->pci_dev);
}
}
-
- return 0;
}
static int get_resources(struct comedi_device *dev, unsigned int res_mask,
@@ -3048,6 +2966,42 @@ static int pci230_ai_cancel(struct comedi_device *dev,
return 0;
}
+static struct comedi_driver amplc_pci230_driver = {
+ .driver_name = "amplc_pci230",
+ .module = THIS_MODULE,
+ .attach = pci230_attach,
+ .detach = pci230_detach,
+ .board_name = &pci230_boards[0].name,
+ .offset = sizeof(pci230_boards[0]),
+ .num_names = ARRAY_SIZE(pci230_boards),
+};
+
+static int __devinit amplc_pci230_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, &amplc_pci230_driver);
+}
+
+static void __devexit amplc_pci230_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(amplc_pci230_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI230) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI260) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, amplc_pci230_pci_table);
+
+static struct pci_driver amplc_pci230_pci_driver = {
+ .name = "amplc_pci230",
+ .id_table = amplc_pci230_pci_table,
+ .probe = amplc_pci230_pci_probe,
+ .remove = __devexit_p(amplc_pci230_pci_remove)
+};
+module_comedi_pci_driver(amplc_pci230_driver, amplc_pci230_pci_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c
index 11cdaf2a5aa5..fb9951a746a6 100644
--- a/drivers/staging/comedi/drivers/c6xdigio.c
+++ b/drivers/staging/comedi/drivers/c6xdigio.c
@@ -97,16 +97,6 @@ union encvaluetype {
#define C6XDIGIO_TIME_OUT 20
-static int c6xdigio_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int c6xdigio_detach(struct comedi_device *dev);
-struct comedi_driver driver_c6xdigio = {
- .driver_name = "c6xdigio",
- .module = THIS_MODULE,
- .attach = c6xdigio_attach,
- .detach = c6xdigio_detach,
-};
-
static void C6X_pwmInit(unsigned long baseAddr)
{
int timeout = 0;
@@ -407,10 +397,6 @@ static void board_init(struct comedi_device *dev)
}
-/* static void board_halt(struct comedi_device *dev) { */
-/* C6X_pwmInit(dev->iobase); */
-/* } */
-
/*
options[0] - I/O port
options[1] - irq
@@ -500,36 +486,22 @@ static int c6xdigio_attach(struct comedi_device *dev,
return 0;
}
-static int c6xdigio_detach(struct comedi_device *dev)
+static void c6xdigio_detach(struct comedi_device *dev)
{
- /* board_halt(dev); may not need this */
-
- printk(KERN_DEBUG "comedi%d: c6xdigio: remove\n", dev->minor);
-
if (dev->iobase)
release_region(dev->iobase, C6XDIGIO_SIZE);
-
- /* Not using IRQ so I am not sure if I need this */
if (dev->irq)
free_irq(dev->irq, dev);
-
pnp_unregister_driver(&c6xdigio_pnp_driver);
-
- return 0;
-}
-
-static int __init driver_c6xdigio_init_module(void)
-{
- return comedi_driver_register(&driver_c6xdigio);
}
-static void __exit driver_c6xdigio_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_c6xdigio);
-}
-
-module_init(driver_c6xdigio_init_module);
-module_exit(driver_c6xdigio_cleanup_module);
+static struct comedi_driver c6xdigio_driver = {
+ .driver_name = "c6xdigio",
+ .module = THIS_MODULE,
+ .attach = c6xdigio_attach,
+ .detach = c6xdigio_detach,
+};
+module_comedi_driver(c6xdigio_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c
index 49404f49f7b7..35159235a1b6 100644
--- a/drivers/staging/comedi/drivers/cb_das16_cs.c
+++ b/drivers/staging/comedi/drivers/cb_das16_cs.c
@@ -91,7 +91,7 @@ struct das16cs_private {
static int das16cs_attach(struct comedi_device *dev,
struct comedi_devconfig *it);
-static int das16cs_detach(struct comedi_device *dev);
+static void das16cs_detach(struct comedi_device *dev);
static struct comedi_driver driver_das16cs = {
.driver_name = "cb_das16_cs",
.module = THIS_MODULE,
@@ -255,15 +255,10 @@ static int das16cs_attach(struct comedi_device *dev,
return 1;
}
-static int das16cs_detach(struct comedi_device *dev)
+static void das16cs_detach(struct comedi_device *dev)
{
- dev_dbg(dev->hw_dev, "comedi%d: das16cs: remove\n", dev->minor);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
-
- return 0;
}
static irqreturn_t das16cs_interrupt(int irq, void *d)
diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c
index 7e4ffcfdac62..ee9e084bb96c 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas.c
@@ -405,20 +405,6 @@ static const struct cb_pcidas_board cb_pcidas_boards[] = {
},
};
-static DEFINE_PCI_DEVICE_TABLE(cb_pcidas_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0001) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x000f) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0010) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0019) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001c) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x004c) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001a) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001b) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, cb_pcidas_pci_table);
-
/*
* Useful for shorthand access to the particular board structure
*/
@@ -462,22 +448,6 @@ struct cb_pcidas_private {
*/
#define devpriv ((struct cb_pcidas_private *)dev->private)
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int cb_pcidas_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int cb_pcidas_detach(struct comedi_device *dev);
-static struct comedi_driver driver_cb_pcidas = {
- .driver_name = "cb_pcidas",
- .module = THIS_MODULE,
- .attach = cb_pcidas_attach,
- .detach = cb_pcidas_detach,
-};
-
static int cb_pcidas_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
@@ -756,26 +726,12 @@ found:
return 1;
}
-/*
- * cb_pcidas_detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int cb_pcidas_detach(struct comedi_device *dev)
+static void cb_pcidas_detach(struct comedi_device *dev)
{
-
if (devpriv) {
if (devpriv->s5933_config) {
- /* disable and clear interrupts on amcc s5933 */
outl(INTCSR_INBOX_INTR_STATUS,
devpriv->s5933_config + AMCC_OP_REG_INTCSR);
-#ifdef CB_PCIDAS_DEBUG
- dev_dbg(dev->hw_dev, "detaching, incsr is 0x%x\n",
- inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR));
-#endif
}
}
if (dev->irq)
@@ -787,8 +743,6 @@ static int cb_pcidas_detach(struct comedi_device *dev)
comedi_pci_disable(devpriv->pci_dev);
pci_dev_put(devpriv->pci_dev);
}
-
- return 0;
}
/*
@@ -1918,47 +1872,44 @@ static int nvram_read(struct comedi_device *dev, unsigned int address,
return 0;
}
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __devinit driver_cb_pcidas_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static struct comedi_driver cb_pcidas_driver = {
+ .driver_name = "cb_pcidas",
+ .module = THIS_MODULE,
+ .attach = cb_pcidas_attach,
+ .detach = cb_pcidas_detach,
+};
+
+static int __devinit cb_pcidas_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_cb_pcidas.driver_name);
+ return comedi_pci_auto_config(dev, &cb_pcidas_driver);
}
-static void __devexit driver_cb_pcidas_pci_remove(struct pci_dev *dev)
+static void __devexit cb_pcidas_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_cb_pcidas_pci_driver = {
- .id_table = cb_pcidas_pci_table,
- .probe = &driver_cb_pcidas_pci_probe,
- .remove = __devexit_p(&driver_cb_pcidas_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(cb_pcidas_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0001) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x000f) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0010) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0019) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001c) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x004c) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001a) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001b) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, cb_pcidas_pci_table);
-static int __init driver_cb_pcidas_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_cb_pcidas);
- if (retval < 0)
- return retval;
-
- driver_cb_pcidas_pci_driver.name = (char *)driver_cb_pcidas.driver_name;
- return pci_register_driver(&driver_cb_pcidas_pci_driver);
-}
-
-static void __exit driver_cb_pcidas_cleanup_module(void)
-{
- pci_unregister_driver(&driver_cb_pcidas_pci_driver);
- comedi_driver_unregister(&driver_cb_pcidas);
-}
-
-module_init(driver_cb_pcidas_init_module);
-module_exit(driver_cb_pcidas_cleanup_module);
+static struct pci_driver cb_pcidas_pci_driver = {
+ .name = "cb_pcidas",
+ .id_table = cb_pcidas_pci_table,
+ .probe = cb_pcidas_pci_probe,
+ .remove = __devexit_p(cb_pcidas_pci_remove)
+};
+module_comedi_pci_driver(cb_pcidas_driver, cb_pcidas_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c
index 915157d47805..9d0b8754ff5b 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas64.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas64.c
@@ -1026,31 +1026,6 @@ static const struct pcidas64_board pcidas64_boards[] = {
#endif
};
-static DEFINE_PCI_DEVICE_TABLE(pcidas64_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x001d) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x001e) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0035) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0036) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0037) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0052) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005d) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005e) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005f) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0061) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0062) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0063) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0064) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0066) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0067) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0068) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x006f) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0078) },
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0079) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pcidas64_pci_table);
-
static inline struct pcidas64_board *board(const struct comedi_device *dev)
{
return (struct pcidas64_board *)dev->board_ptr;
@@ -1127,21 +1102,6 @@ static inline struct pcidas64_private *priv(struct comedi_device *dev)
return dev->private;
}
-/*
- * The comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int detach(struct comedi_device *dev);
-static struct comedi_driver driver_cb_pcidas = {
- .driver_name = "cb_pcidas64",
- .module = THIS_MODULE,
- .attach = attach,
- .detach = detach,
-};
-
static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -1216,44 +1176,6 @@ static unsigned int get_ao_divisor(unsigned int ns, unsigned int flags);
static void load_ao_dma(struct comedi_device *dev,
const struct comedi_cmd *cmd);
-static int __devinit driver_cb_pcidas_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- return comedi_pci_auto_config(dev, driver_cb_pcidas.driver_name);
-}
-
-static void __devexit driver_cb_pcidas_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_cb_pcidas_pci_driver = {
- .id_table = pcidas64_pci_table,
- .probe = &driver_cb_pcidas_pci_probe,
- .remove = __devexit_p(&driver_cb_pcidas_pci_remove)
-};
-
-static int __init driver_cb_pcidas_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_cb_pcidas);
- if (retval < 0)
- return retval;
-
- driver_cb_pcidas_pci_driver.name = (char *)driver_cb_pcidas.driver_name;
- return pci_register_driver(&driver_cb_pcidas_pci_driver);
-}
-
-static void __exit driver_cb_pcidas_cleanup_module(void)
-{
- pci_unregister_driver(&driver_cb_pcidas_pci_driver);
- comedi_driver_unregister(&driver_cb_pcidas);
-}
-
-module_init(driver_cb_pcidas_init_module);
-module_exit(driver_cb_pcidas_cleanup_module);
-
static unsigned int ai_range_bits_6xxx(const struct comedi_device *dev,
unsigned int range_index)
{
@@ -1781,7 +1703,7 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it)
dev_dbg(dev->hw_dev, "Found %s on bus %i, slot %i\n", board(dev)->name,
pcidev->bus->number, PCI_SLOT(pcidev->devfn));
- if (comedi_pci_enable(pcidev, driver_cb_pcidas.driver_name)) {
+ if (comedi_pci_enable(pcidev, dev->driver->driver_name)) {
dev_warn(dev->hw_dev, "failed to enable PCI device and request regions\n");
return -EIO;
}
@@ -1868,15 +1790,7 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int detach(struct comedi_device *dev)
+static void detach(struct comedi_device *dev)
{
unsigned int i;
@@ -1938,8 +1852,6 @@ static int detach(struct comedi_device *dev)
}
if (dev->subdevices)
subdev_8255_cleanup(dev, dev->subdevices + 4);
-
- return 0;
}
static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -4315,6 +4227,56 @@ static void i2c_write(struct comedi_device *dev, unsigned int address,
i2c_stop(dev);
}
+static struct comedi_driver cb_pcidas64_driver = {
+ .driver_name = "cb_pcidas64",
+ .module = THIS_MODULE,
+ .attach = attach,
+ .detach = detach,
+};
+
+static int __devinit cb_pcidas64_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, &cb_pcidas64_driver);
+}
+
+static void __devexit cb_pcidas64_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(cb_pcidas64_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x001d) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x001e) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0035) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0036) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0037) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0052) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005d) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005e) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005f) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0061) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0062) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0063) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0064) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0066) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0067) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0068) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x006f) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0078) },
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0079) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, cb_pcidas64_pci_table);
+
+static struct pci_driver cb_pcidas64_pci_driver = {
+ .name = "cb_pcidas64",
+ .id_table = cb_pcidas64_pci_table,
+ .probe = cb_pcidas64_pci_probe,
+ .remove = __devexit_p(cb_pcidas64_pci_remove),
+};
+module_comedi_pci_driver(cb_pcidas64_driver, cb_pcidas64_pci_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c
index abba220a767f..25ebca11eadc 100644
--- a/drivers/staging/comedi/drivers/cb_pcidda.c
+++ b/drivers/staging/comedi/drivers/cb_pcidda.c
@@ -51,9 +51,12 @@ Please report success/failure with other different cards to
#include "comedi_pci.h"
#include "8255.h"
-#define PCI_VENDOR_ID_CB 0x1307 /* PCI vendor number of ComputerBoards */
+
+/* PCI vendor number of ComputerBoards */
+#define PCI_VENDOR_ID_CB 0x1307
#define EEPROM_SIZE 128 /* number of entries in eeprom */
-#define MAX_AO_CHANNELS 8 /* maximum number of ao channels for supported boards */
+/* maximum number of ao channels for supported boards */
+#define MAX_AO_CHANNELS 8
/* PCI-DDA base addresses */
#define DIGITALIO_BADRINDEX 2
@@ -94,20 +97,26 @@ Please report success/failure with other different cards to
#define DACALIBRATION1 4 /* D/A CALIBRATION REGISTER 1 */
/* write bits */
-#define SERIAL_IN_BIT 0x1 /* serial data input for eeprom, caldacs, reference dac */
+/* serial data input for eeprom, caldacs, reference dac */
+#define SERIAL_IN_BIT 0x1
#define CAL_CHANNEL_MASK (0x7 << 1)
#define CAL_CHANNEL_BITS(channel) (((channel) << 1) & CAL_CHANNEL_MASK)
/* read bits */
#define CAL_COUNTER_MASK 0x1f
-#define CAL_COUNTER_OVERFLOW_BIT 0x20 /* calibration counter overflow status bit */
-#define AO_BELOW_REF_BIT 0x40 /* analog output is less than reference dac voltage */
+/* calibration counter overflow status bit */
+#define CAL_COUNTER_OVERFLOW_BIT 0x20
+/* analog output is less than reference dac voltage */
+#define AO_BELOW_REF_BIT 0x40
#define SERIAL_OUT_BIT 0x80 /* serial data out, for reading from eeprom */
#define DACALIBRATION2 6 /* D/A CALIBRATION REGISTER 2 */
#define SELECT_EEPROM_BIT 0x1 /* send serial data in to eeprom */
-#define DESELECT_REF_DAC_BIT 0x2 /* don't send serial data to MAX542 reference dac */
-#define DESELECT_CALDAC_BIT(n) (0x4 << (n)) /* don't send serial data to caldac n */
-#define DUMMY_BIT 0x40 /* manual says to set this bit with no explanation */
+/* don't send serial data to MAX542 reference dac */
+#define DESELECT_REF_DAC_BIT 0x2
+/* don't send serial data to caldac n */
+#define DESELECT_CALDAC_BIT(n) (0x4 << (n))
+/* manual says to set this bit with no explanation */
+#define DUMMY_BIT 0x40
#define DADATA 8 /* FIRST D/A DATA REGISTER (0) */
@@ -195,26 +204,17 @@ static const struct cb_pcidda_board cb_pcidda_boards[] = {
},
};
-static DEFINE_PCI_DEVICE_TABLE(cb_pcidda_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0020) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0021) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0022) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0023) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0024) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0025) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, cb_pcidda_pci_table);
-
/*
* Useful for shorthand access to the particular board structure
*/
#define thisboard ((const struct cb_pcidda_board *)dev->board_ptr)
-/* this structure is for data unique to this hardware driver. If
- several hardware drivers keep similar information in this structure,
- feel free to suggest moving the variable to the struct comedi_device struct. */
+/*
+ * this structure is for data unique to this hardware driver. If
+ * several hardware drivers keep similar information in this structure,
+ * feel free to suggest moving the variable to the struct comedi_device
+ * struct.
+ */
struct cb_pcidda_private {
int data;
@@ -227,8 +227,10 @@ struct cb_pcidda_private {
/* unsigned long control_status; */
/* unsigned long adc_fifo; */
- unsigned int dac_cal1_bits; /* bits last written to da calibration register 1 */
- unsigned int ao_range[MAX_AO_CHANNELS]; /* current range settings for output channels */
+ /* bits last written to da calibration register 1 */
+ unsigned int dac_cal1_bits;
+ /* current range settings for output channels */
+ unsigned int ao_range[MAX_AO_CHANNELS];
u16 eeprom_data[EEPROM_SIZE]; /* software copy of board's eeprom */
};
@@ -238,9 +240,6 @@ struct cb_pcidda_private {
*/
#define devpriv ((struct cb_pcidda_private *)dev->private)
-static int cb_pcidda_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int cb_pcidda_detach(struct comedi_device *dev);
/* static int cb_pcidda_ai_rinsn(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data); */
static int cb_pcidda_ao_winsn(struct comedi_device *dev,
struct comedi_subdevice *s,
@@ -259,19 +258,6 @@ static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel,
unsigned int range);
/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static struct comedi_driver driver_cb_pcidda = {
- .driver_name = "cb_pcidda",
- .module = THIS_MODULE,
- .attach = cb_pcidda_attach,
- .detach = cb_pcidda_detach,
-};
-
-/*
* Attach is called by the Comedi core to configure the driver
* for a particular board.
*/
@@ -377,7 +363,8 @@ found:
dev_dbg(dev->hw_dev, "eeprom:\n");
for (index = 0; index < EEPROM_SIZE; index++) {
devpriv->eeprom_data[index] = cb_pcidda_read_eeprom(dev, index);
- dev_dbg(dev->hw_dev, "%i:0x%x\n", index, devpriv->eeprom_data[index]);
+ dev_dbg(dev->hw_dev, "%i:0x%x\n", index,
+ devpriv->eeprom_data[index]);
}
/* set calibrations dacs */
@@ -387,19 +374,8 @@ found:
return 1;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int cb_pcidda_detach(struct comedi_device *dev)
+static void cb_pcidda_detach(struct comedi_device *dev)
{
-/*
- * Deallocate the I/O ports.
- */
if (devpriv) {
if (devpriv->pci_dev) {
if (devpriv->dac)
@@ -407,13 +383,10 @@ static int cb_pcidda_detach(struct comedi_device *dev)
pci_dev_put(devpriv->pci_dev);
}
}
- /* cleanup 8255 */
if (dev->subdevices) {
subdev_8255_cleanup(dev, dev->subdevices + 1);
subdev_8255_cleanup(dev, dev->subdevices + 2);
}
-
- return 0;
}
/*
@@ -484,7 +457,10 @@ static int cb_pcidda_ai_cmdtest(struct comedi_device *dev,
if (err)
return 1;
- /* step 2: make sure trigger sources are unique and mutually compatible */
+ /*
+ * step 2: make sure trigger sources are unique and mutually
+ * compatible
+ */
/* note that mutual compatibility is not an issue here */
if (cmd->scan_begin_src != TRIG_TIMER
@@ -696,8 +672,10 @@ static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev,
unsigned int i;
unsigned int cal2_bits;
unsigned int value;
- const int max_num_caldacs = 4; /* one caldac for every two dac channels */
- const int read_instruction = 0x6; /* bits to send to tell eeprom we want to read */
+ /* one caldac for every two dac channels */
+ const int max_num_caldacs = 4;
+ /* bits to send to tell eeprom we want to read */
+ const int read_instruction = 0x6;
const int instruction_length = 3;
const int address_length = 8;
@@ -729,9 +707,11 @@ static void cb_pcidda_write_caldac(struct comedi_device *dev,
{
unsigned int cal2_bits;
unsigned int i;
- const int num_channel_bits = 3; /* caldacs use 3 bit channel specification */
+ /* caldacs use 3 bit channel specification */
+ const int num_channel_bits = 3;
const int num_caldac_bits = 8; /* 8 bit calibration dacs */
- const int max_num_caldacs = 4; /* one caldac for every two dac channels */
+ /* one caldac for every two dac channels */
+ const int max_num_caldacs = 4;
/* write 3 bit channel */
cb_pcidda_serial_out(dev, channel, num_channel_bits);
@@ -790,14 +770,20 @@ static unsigned int offset_eeprom_address(unsigned int ao_channel,
return 0x7 + 2 * range + 12 * ao_channel;
}
-/* returns eeprom address that provides gain calibration for given ao channel and range */
+/*
+ * returns eeprom address that provides gain calibration for given ao
+ * channel and range
+ */
static unsigned int gain_eeprom_address(unsigned int ao_channel,
unsigned int range)
{
return 0x8 + 2 * range + 12 * ao_channel;
}
-/* returns upper byte of eeprom entry, which gives the coarse adjustment values */
+/*
+ * returns upper byte of eeprom entry, which gives the coarse adjustment
+ * values
+ */
static unsigned int eeprom_coarse_byte(unsigned int word)
{
return (word >> 8) & 0xff;
@@ -815,7 +801,7 @@ static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel,
{
unsigned int coarse_offset, fine_offset, coarse_gain, fine_gain;
- /* remember range so we can tell when we need to readjust calibration */
+ /* remember range so we can tell when we need to readjust calibration */
devpriv->ao_range[channel] = range;
/* get values from eeprom data */
@@ -843,47 +829,42 @@ static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel,
fine_gain_channel(channel), fine_gain);
}
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __devinit driver_cb_pcidda_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static struct comedi_driver cb_pcidda_driver = {
+ .driver_name = "cb_pcidda",
+ .module = THIS_MODULE,
+ .attach = cb_pcidda_attach,
+ .detach = cb_pcidda_detach,
+};
+
+static int __devinit cb_pcidda_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_cb_pcidda.driver_name);
+ return comedi_pci_auto_config(dev, &cb_pcidda_driver);
}
-static void __devexit driver_cb_pcidda_pci_remove(struct pci_dev *dev)
+static void __devexit cb_pcidda_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_cb_pcidda_pci_driver = {
- .id_table = cb_pcidda_pci_table,
- .probe = &driver_cb_pcidda_pci_probe,
- .remove = __devexit_p(&driver_cb_pcidda_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(cb_pcidda_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0020) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0021) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0022) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0023) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0024) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0025) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, cb_pcidda_pci_table);
-static int __init driver_cb_pcidda_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_cb_pcidda);
- if (retval < 0)
- return retval;
-
- driver_cb_pcidda_pci_driver.name = (char *)driver_cb_pcidda.driver_name;
- return pci_register_driver(&driver_cb_pcidda_pci_driver);
-}
-
-static void __exit driver_cb_pcidda_cleanup_module(void)
-{
- pci_unregister_driver(&driver_cb_pcidda_pci_driver);
- comedi_driver_unregister(&driver_cb_pcidda);
-}
-
-module_init(driver_cb_pcidda_init_module);
-module_exit(driver_cb_pcidda_cleanup_module);
+static struct pci_driver cb_pcidda_pci_driver = {
+ .name = "cb_pcidda",
+ .id_table = cb_pcidda_pci_table,
+ .probe = cb_pcidda_pci_probe,
+ .remove = __devexit_p(cb_pcidda_pci_remove),
+};
+module_comedi_pci_driver(cb_pcidda_driver, cb_pcidda_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/cb_pcidio.c b/drivers/staging/comedi/drivers/cb_pcidio.c
index 8f3215239a15..713132c8dbb5 100644
--- a/drivers/staging/comedi/drivers/cb_pcidio.c
+++ b/drivers/staging/comedi/drivers/cb_pcidio.c
@@ -86,19 +86,6 @@ static const struct pcidio_board pcidio_boards[] = {
},
};
-/* This is used by modprobe to translate PCI IDs to drivers. Should
- * only be used for PCI and ISA-PnP devices */
-/* Please add your PCI vendor ID to comedidev.h, and it will be forwarded
- * upstream. */
-static DEFINE_PCI_DEVICE_TABLE(pcidio_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0028) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0014) },
- { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x000b) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, pcidio_pci_table);
-
/*
* Useful for shorthand access to the particular board structure
*/
@@ -125,59 +112,6 @@ struct pcidio_private {
*/
#define devpriv ((struct pcidio_private *)dev->private)
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int pcidio_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcidio_detach(struct comedi_device *dev);
-static struct comedi_driver driver_cb_pcidio = {
- .driver_name = "cb_pcidio",
- .module = THIS_MODULE,
- .attach = pcidio_attach,
- .detach = pcidio_detach,
-
-/* It is not necessary to implement the following members if you are
- * writing a driver for a ISA PnP or PCI card */
-
- /* Most drivers will support multiple types of boards by
- * having an array of board structures. These were defined
- * in pcidio_boards[] above. Note that the element 'name'
- * was first in the structure -- Comedi uses this fact to
- * extract the name of the board without knowing any details
- * about the structure except for its length.
- * When a device is attached (by comedi_config), the name
- * of the device is given to Comedi, and Comedi tries to
- * match it by going through the list of board names. If
- * there is a match, the address of the pointer is put
- * into dev->board_ptr and driver->attach() is called.
- *
- * Note that these are not necessary if you can determine
- * the type of board in software. ISA PnP, PCI, and PCMCIA
- * devices are such boards.
- */
-
-/* The following fields should NOT be initialized if you are dealing
- * with PCI devices
- *
- * .board_name = pcidio_boards,
- * .offset = sizeof(struct pcidio_board),
- * .num_names = sizeof(pcidio_boards) / sizeof(structpcidio_board),
- */
-
-};
-
-/*------------------------------- FUNCTIONS -----------------------------------*/
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board. If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
static int pcidio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct pci_dev *pcidev = NULL;
@@ -261,15 +195,7 @@ found:
return 1;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pcidio_detach(struct comedi_device *dev)
+static void pcidio_detach(struct comedi_device *dev)
{
if (devpriv) {
if (devpriv->pci_dev) {
@@ -283,50 +209,41 @@ static int pcidio_detach(struct comedi_device *dev)
for (i = 0; i < thisboard->n_8255; i++)
subdev_8255_cleanup(dev, dev->subdevices + i);
}
- return 0;
}
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __devinit driver_cb_pcidio_pci_probe(struct pci_dev *dev,
+static struct comedi_driver cb_pcidio_driver = {
+ .driver_name = "cb_pcidio",
+ .module = THIS_MODULE,
+ .attach = pcidio_attach,
+ .detach = pcidio_detach,
+};
+
+static int __devinit cb_pcidio_pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_cb_pcidio.driver_name);
+ return comedi_pci_auto_config(dev, &cb_pcidio_driver);
}
-static void __devexit driver_cb_pcidio_pci_remove(struct pci_dev *dev)
+static void __devexit cb_pcidio_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_cb_pcidio_pci_driver = {
- .id_table = pcidio_pci_table,
- .probe = &driver_cb_pcidio_pci_probe,
- .remove = __devexit_p(&driver_cb_pcidio_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(cb_pcidio_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0028) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0014) },
+ { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x000b) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, cb_pcidio_pci_table);
-static int __init driver_cb_pcidio_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_cb_pcidio);
- if (retval < 0)
- return retval;
-
- driver_cb_pcidio_pci_driver.name = (char *)driver_cb_pcidio.driver_name;
- return pci_register_driver(&driver_cb_pcidio_pci_driver);
-}
-
-static void __exit driver_cb_pcidio_cleanup_module(void)
-{
- pci_unregister_driver(&driver_cb_pcidio_pci_driver);
- comedi_driver_unregister(&driver_cb_pcidio);
-}
-
-module_init(driver_cb_pcidio_init_module);
-module_exit(driver_cb_pcidio_cleanup_module);
+static struct pci_driver cb_pcidio_pci_driver = {
+ .name = "cb_pcidio",
+ .id_table = cb_pcidio_pci_table,
+ .probe = cb_pcidio_pci_probe,
+ .remove = __devexit_p(cb_pcidio_pci_remove),
+};
+module_comedi_pci_driver(cb_pcidio_driver, cb_pcidio_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c
index 8ba694263bd3..5f834d02ec24 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdas.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdas.c
@@ -123,15 +123,6 @@ static const struct cb_pcimdas_board cb_pcimdas_boards[] = {
},
};
-/* This is used by modprobe to translate PCI IDs to drivers. Should
- * only be used for PCI and ISA-PnP devices */
-static DEFINE_PCI_DEVICE_TABLE(cb_pcimdas_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0056) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, cb_pcimdas_pci_table);
-
#define N_BOARDS 1 /* Max number of boards supported */
/*
@@ -139,9 +130,12 @@ MODULE_DEVICE_TABLE(pci, cb_pcimdas_pci_table);
*/
#define thisboard ((const struct cb_pcimdas_board *)dev->board_ptr)
-/* this structure is for data unique to this hardware driver. If
- several hardware drivers keep similar information in this structure,
- feel free to suggest moving the variable to the struct comedi_device struct. */
+/*
+ * this structure is for data unique to this hardware driver. If
+ * several hardware drivers keep similar information in this structure,
+ * feel free to suggest moving the variable to the struct comedi_device
+ * struct.
+ */
struct cb_pcimdas_private {
int data;
@@ -172,22 +166,6 @@ struct cb_pcimdas_private {
*/
#define devpriv ((struct cb_pcimdas_private *)dev->private)
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int cb_pcimdas_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int cb_pcimdas_detach(struct comedi_device *dev);
-static struct comedi_driver driver_cb_pcimdas = {
- .driver_name = "cb_pcimdas",
- .module = THIS_MODULE,
- .attach = cb_pcimdas_attach,
- .detach = cb_pcimdas_detach,
-};
-
static int cb_pcimdas_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
@@ -317,7 +295,8 @@ found:
s->subdev_flags = SDF_WRITABLE;
s->n_chan = thisboard->ao_nchan;
s->maxdata = 1 << thisboard->ao_bits;
- s->range_table = &range_unknown; /* ranges are hardware settable, but not software readable. */
+ /* ranges are hardware settable, but not software readable. */
+ s->range_table = &range_unknown;
s->insn_write = &cb_pcimdas_ao_winsn;
s->insn_read = &cb_pcimdas_ao_rinsn;
@@ -331,29 +310,8 @@ found:
return 1;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int cb_pcimdas_detach(struct comedi_device *dev)
+static void cb_pcimdas_detach(struct comedi_device *dev)
{
- if (devpriv) {
- dev_dbg(dev->hw_dev, "devpriv->BADR0 = 0x%lx\n",
- devpriv->BADR0);
- dev_dbg(dev->hw_dev, "devpriv->BADR1 = 0x%lx\n",
- devpriv->BADR1);
- dev_dbg(dev->hw_dev, "devpriv->BADR2 = 0x%lx\n",
- devpriv->BADR2);
- dev_dbg(dev->hw_dev, "devpriv->BADR3 = 0x%lx\n",
- devpriv->BADR3);
- dev_dbg(dev->hw_dev, "devpriv->BADR4 = 0x%lx\n",
- devpriv->BADR4);
- }
-
if (dev->irq)
free_irq(dev->irq, dev);
if (devpriv) {
@@ -363,8 +321,6 @@ static int cb_pcimdas_detach(struct comedi_device *dev)
pci_dev_put(devpriv->pci_dev);
}
}
-
- return 0;
}
/*
@@ -402,7 +358,10 @@ static int cb_pcimdas_ai_rinsn(struct comedi_device *dev,
outb(0x01, devpriv->BADR3 + 6); /* set bursting off, conversions on */
outb(0x00, devpriv->BADR3 + 7); /* set range to 10V. UP/BP is controlled by a switch on the board */
- /* write channel limits to multiplexer, set Low (bits 0-3) and High (bits 4-7) channels to chan. */
+ /*
+ * write channel limits to multiplexer, set Low (bits 0-3) and
+ * High (bits 4-7) channels to chan.
+ */
chanlims = chan | (chan << 4);
outb(chanlims, devpriv->BADR3 + 0);
@@ -479,49 +438,37 @@ static int cb_pcimdas_ao_rinsn(struct comedi_device *dev,
return i;
}
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __devinit driver_cb_pcimdas_pci_probe(struct pci_dev *dev,
- const struct pci_device_id
- *ent)
+static struct comedi_driver cb_pcimdas_driver = {
+ .driver_name = "cb_pcimdas",
+ .module = THIS_MODULE,
+ .attach = cb_pcimdas_attach,
+ .detach = cb_pcimdas_detach,
+};
+
+static int __devinit cb_pcimdas_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_cb_pcimdas.driver_name);
+ return comedi_pci_auto_config(dev, &cb_pcimdas_driver);
}
-static void __devexit driver_cb_pcimdas_pci_remove(struct pci_dev *dev)
+static void __devexit cb_pcimdas_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_cb_pcimdas_pci_driver = {
- .id_table = cb_pcimdas_pci_table,
- .probe = &driver_cb_pcimdas_pci_probe,
- .remove = __devexit_p(&driver_cb_pcimdas_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(cb_pcimdas_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0056) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, cb_pcimdas_pci_table);
-static int __init driver_cb_pcimdas_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_cb_pcimdas);
- if (retval < 0)
- return retval;
-
- driver_cb_pcimdas_pci_driver.name =
- (char *)driver_cb_pcimdas.driver_name;
- return pci_register_driver(&driver_cb_pcimdas_pci_driver);
-}
-
-static void __exit driver_cb_pcimdas_cleanup_module(void)
-{
- pci_unregister_driver(&driver_cb_pcimdas_pci_driver);
- comedi_driver_unregister(&driver_cb_pcimdas);
-}
-
-module_init(driver_cb_pcimdas_init_module);
-module_exit(driver_cb_pcimdas_cleanup_module);
+static struct pci_driver cb_pcimdas_pci_driver = {
+ .name = "cb_pcimdas",
+ .id_table = cb_pcimdas_pci_table,
+ .probe = cb_pcimdas_pci_probe,
+ .remove = __devexit_p(cb_pcimdas_pci_remove),
+};
+module_comedi_pci_driver(cb_pcimdas_driver, cb_pcimdas_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c
index 40bddfa22220..b339685e234d 100644
--- a/drivers/staging/comedi/drivers/cb_pcimdda.c
+++ b/drivers/staging/comedi/drivers/cb_pcimdda.c
@@ -140,17 +140,6 @@ static const struct board_struct boards[] = {
#define REG_SZ (thisboard->reg_sz)
#define REGS_BADRINDEX (thisboard->regs_badrindex)
-/* This is used by modprobe to translate PCI IDs to drivers. Should
- * only be used for PCI and ISA-PnP devices */
-/* Please add your PCI vendor ID to comedidev.h, and it will be forwarded
- * upstream. */
-static DEFINE_PCI_DEVICE_TABLE(pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, PCI_ID_PCIM_DDA06_16) },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, pci_table);
-
/*
* this structure is for data unique to this hardware driver. If
* several hardware drivers keep similar information in this structure,
@@ -161,7 +150,6 @@ struct board_private_struct {
unsigned long registers; /* set by probe */
unsigned long dio_registers;
char attached_to_8255; /* boolean */
- char attached_successfully; /* boolean */
/* would be useful for a PCI device */
struct pci_dev *pci_dev;
@@ -177,66 +165,6 @@ struct board_private_struct {
*/
#define devpriv ((struct board_private_struct *)dev->private)
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int detach(struct comedi_device *dev);
-static struct comedi_driver cb_pcimdda_driver = {
- .driver_name = "cb_pcimdda",
- .module = THIS_MODULE,
- .attach = attach,
- .detach = detach,
-};
-
-MODULE_AUTHOR("Calin A. Culianu <calin@rtlab.org>");
-MODULE_DESCRIPTION("Comedi low-level driver for the Computerboards PCIM-DDA "
- "series. Currently only supports PCIM-DDA06-16 (which "
- "also happens to be the only board in this series. :) ) ");
-MODULE_LICENSE("GPL");
-static int __devinit cb_pcimdda_driver_pci_probe(struct pci_dev *dev,
- const struct pci_device_id
- *ent)
-{
- return comedi_pci_auto_config(dev, cb_pcimdda_driver.driver_name);
-}
-
-static void __devexit cb_pcimdda_driver_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver cb_pcimdda_driver_pci_driver = {
- .id_table = pci_table,
- .probe = &cb_pcimdda_driver_pci_probe,
- .remove = __devexit_p(&cb_pcimdda_driver_pci_remove)
-};
-
-static int __init cb_pcimdda_driver_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&cb_pcimdda_driver);
- if (retval < 0)
- return retval;
-
- cb_pcimdda_driver_pci_driver.name =
- (char *)cb_pcimdda_driver.driver_name;
- return pci_register_driver(&cb_pcimdda_driver_pci_driver);
-}
-
-static void __exit cb_pcimdda_driver_cleanup_module(void)
-{
- pci_unregister_driver(&cb_pcimdda_driver_pci_driver);
- comedi_driver_unregister(&cb_pcimdda_driver);
-}
-
-module_init(cb_pcimdda_driver_init_module);
-module_exit(cb_pcimdda_driver_cleanup_module);
-
static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -354,44 +282,24 @@ static int attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->type = COMEDI_SUBD_UNUSED;
}
- devpriv->attached_successfully = 1;
-
printk("attached\n");
return 1;
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int detach(struct comedi_device *dev)
+static void detach(struct comedi_device *dev)
{
if (devpriv) {
-
if (dev->subdevices && devpriv->attached_to_8255) {
- /* de-register us from the 8255 driver */
subdev_8255_cleanup(dev, dev->subdevices + 2);
devpriv->attached_to_8255 = 0;
}
-
if (devpriv->pci_dev) {
if (devpriv->registers)
comedi_pci_disable(devpriv->pci_dev);
pci_dev_put(devpriv->pci_dev);
}
-
- if (devpriv->attached_successfully && thisboard)
- printk("comedi%d: %s: detached\n", dev->minor,
- thisboard->name);
-
}
-
- return 0;
}
static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -515,3 +423,41 @@ static int probe(struct comedi_device *dev, const struct comedi_devconfig *it)
"card found at the requested position\n");
return -ENODEV;
}
+
+static struct comedi_driver cb_pcimdda_driver = {
+ .driver_name = "cb_pcimdda",
+ .module = THIS_MODULE,
+ .attach = attach,
+ .detach = detach,
+};
+
+static int __devinit cb_pcimdda_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, &cb_pcimdda_driver);
+}
+
+static void __devexit cb_pcimdda_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(cb_pcimdda_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, PCI_ID_PCIM_DDA06_16) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, cb_pcimdda_pci_table);
+
+static struct pci_driver cb_pcimdda_driver_pci_driver = {
+ .name = "cb_pcimdda",
+ .id_table = cb_pcimdda_pci_table,
+ .probe = cb_pcimdda_pci_probe,
+ .remove = __devexit_p(cb_pcimdda_pci_remove),
+};
+module_comedi_pci_driver(cb_pcimdda_driver, cb_pcimdda_driver_pci_driver);
+
+MODULE_AUTHOR("Calin A. Culianu <calin@rtlab.org>");
+MODULE_DESCRIPTION("Comedi low-level driver for the Computerboards PCIM-DDA "
+ "series. Currently only supports PCIM-DDA06-16 (which "
+ "also happens to be the only board in this series. :) ) ");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c
index d8aefb23d6b9..29412de06c31 100644
--- a/drivers/staging/comedi/drivers/comedi_bond.c
+++ b/drivers/staging/comedi/drivers/comedi_bond.c
@@ -60,7 +60,6 @@ Configuration Options:
#define MAX_CHANS 256
#define MODULE_NAME "comedi_bond"
-MODULE_LICENSE("GPL");
#ifndef STR
# define STR1(x) #x
# define STR(x) STR1(x)
@@ -79,10 +78,6 @@ MODULE_PARM_DESC(debug, "If true, print extra cryptic debugging output useful"
} while (0)
#define WARNING(x...) printk(KERN_WARNING MODULE_NAME ": WARNING: "x)
#define ERROR(x...) printk(KERN_ERR MODULE_NAME ": INTERNAL ERROR: "x)
-MODULE_AUTHOR("Calin A. Culianu");
-MODULE_DESCRIPTION(MODULE_NAME "A driver for COMEDI to bond multiple COMEDI "
- "devices together as one. In the words of John Lennon: "
- "'And the world will live as one...'");
/*
* Board descriptions for two imaginary boards. Describing the
@@ -93,12 +88,6 @@ struct BondingBoard {
const char *name;
};
-static const struct BondingBoard bondingBoards[] = {
- {
- .name = MODULE_NAME,
- },
-};
-
/*
* Useful for shorthand access to the particular board structure
*/
@@ -133,129 +122,6 @@ struct Private {
*/
#define devpriv ((struct Private *)dev->private)
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int bonding_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int bonding_detach(struct comedi_device *dev);
-/** Build Private array of all devices.. */
-static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it);
-static void doDevUnconfig(struct comedi_device *dev);
-/* Ugly implementation of realloc that always copies memory around -- I'm lazy,
- * what can I say? I like to do wasteful memcopies.. :) */
-static void *Realloc(const void *ptr, size_t len, size_t old_len);
-
-static struct comedi_driver driver_bonding = {
- .driver_name = MODULE_NAME,
- .module = THIS_MODULE,
- .attach = bonding_attach,
- .detach = bonding_detach,
- /* It is not necessary to implement the following members if you are
- * writing a driver for a ISA PnP or PCI card */
- /* Most drivers will support multiple types of boards by
- * having an array of board structures. These were defined
- * in skel_boards[] above. Note that the element 'name'
- * was first in the structure -- Comedi uses this fact to
- * extract the name of the board without knowing any details
- * about the structure except for its length.
- * When a device is attached (by comedi_config), the name
- * of the device is given to Comedi, and Comedi tries to
- * match it by going through the list of board names. If
- * there is a match, the address of the pointer is put
- * into dev->board_ptr and driver->attach() is called.
- *
- * Note that these are not necessary if you can determine
- * the type of board in software. ISA PnP, PCI, and PCMCIA
- * devices are such boards.
- */
- .board_name = &bondingBoards[0].name,
- .offset = sizeof(struct BondingBoard),
- .num_names = ARRAY_SIZE(bondingBoards),
-};
-
-static int bonding_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int bonding_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data);
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board. If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int bonding_attach(struct comedi_device *dev,
- struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
-
- LOG_MSG("comedi%d\n", dev->minor);
-
- /*
- * Allocate the private structure area. alloc_private() is a
- * convenient macro defined in comedidev.h.
- */
- if (alloc_private(dev, sizeof(struct Private)) < 0)
- return -ENOMEM;
-
- /*
- * Setup our bonding from config params.. sets up our Private struct..
- */
- if (!doDevConfig(dev, it))
- return -EINVAL;
-
- /*
- * Initialize dev->board_name. Note that we can use the "thisboard"
- * macro now, since we just initialized it in the last line.
- */
- dev->board_name = devpriv->name;
-
- /*
- * Allocate the subdevice structures. alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- */
- if (alloc_subdevices(dev, 1) < 0)
- return -ENOMEM;
-
- s = dev->subdevices + 0;
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = devpriv->nchans;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = bonding_dio_insn_bits;
- s->insn_config = bonding_dio_insn_config;
-
- LOG_MSG("attached with %u DIO channels coming from %u different "
- "subdevices all bonded together. "
- "John Lennon would be proud!\n",
- devpriv->nchans, devpriv->ndevs);
-
- return 1;
-}
-
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int bonding_detach(struct comedi_device *dev)
-{
- LOG_MSG("comedi%d: remove\n", dev->minor);
- doDevUnconfig(dev);
- return 0;
-}
-
/* DIO devices are slightly special. Although it is possible to
* implement the insn_read/insn_write interface, it is much more
* useful to applications if you implement the insn_bits interface.
@@ -466,7 +332,57 @@ static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it)
return 1;
}
-static void doDevUnconfig(struct comedi_device *dev)
+static int bonding_attach(struct comedi_device *dev,
+ struct comedi_devconfig *it)
+{
+ struct comedi_subdevice *s;
+
+ LOG_MSG("comedi%d\n", dev->minor);
+
+ /*
+ * Allocate the private structure area. alloc_private() is a
+ * convenient macro defined in comedidev.h.
+ */
+ if (alloc_private(dev, sizeof(struct Private)) < 0)
+ return -ENOMEM;
+
+ /*
+ * Setup our bonding from config params.. sets up our Private struct..
+ */
+ if (!doDevConfig(dev, it))
+ return -EINVAL;
+
+ /*
+ * Initialize dev->board_name. Note that we can use the "thisboard"
+ * macro now, since we just initialized it in the last line.
+ */
+ dev->board_name = devpriv->name;
+
+ /*
+ * Allocate the subdevice structures. alloc_subdevice() is a
+ * convenient macro defined in comedidev.h.
+ */
+ if (alloc_subdevices(dev, 1) < 0)
+ return -ENOMEM;
+
+ s = dev->subdevices + 0;
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = devpriv->nchans;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = bonding_dio_insn_bits;
+ s->insn_config = bonding_dio_insn_config;
+
+ LOG_MSG("attached with %u DIO channels coming from %u different "
+ "subdevices all bonded together. "
+ "John Lennon would be proud!\n",
+ devpriv->nchans, devpriv->ndevs);
+
+ return 1;
+}
+
+static void bonding_detach(struct comedi_device *dev)
{
unsigned long devs_closed = 0;
@@ -490,15 +406,25 @@ static void doDevUnconfig(struct comedi_device *dev)
}
}
-static int __init init(void)
-{
- return comedi_driver_register(&driver_bonding);
-}
+static const struct BondingBoard bondingBoards[] = {
+ {
+ .name = "comedi_bond",
+ },
+};
-static void __exit cleanup(void)
-{
- comedi_driver_unregister(&driver_bonding);
-}
+static struct comedi_driver bonding_driver = {
+ .driver_name = "comedi_bond",
+ .module = THIS_MODULE,
+ .attach = bonding_attach,
+ .detach = bonding_detach,
+ .board_name = &bondingBoards[0].name,
+ .offset = sizeof(struct BondingBoard),
+ .num_names = ARRAY_SIZE(bondingBoards),
+};
+module_comedi_driver(bonding_driver);
-module_init(init);
-module_exit(cleanup);
+MODULE_AUTHOR("Calin A. Culianu");
+MODULE_DESCRIPTION(MODULE_NAME "A driver for COMEDI to bond multiple COMEDI "
+ "devices together as one. In the words of John Lennon: "
+ "'And the world will live as one...'");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/staging/comedi/drivers/comedi_parport.c
index 21d834dd92b6..bff5dcd76107 100644
--- a/drivers/staging/comedi/drivers/comedi_parport.c
+++ b/drivers/staging/comedi/drivers/comedi_parport.c
@@ -91,29 +91,6 @@ pin, which can be used to wake up tasks.
#define PARPORT_B 1
#define PARPORT_C 2
-static int parport_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int parport_detach(struct comedi_device *dev);
-static struct comedi_driver driver_parport = {
- .driver_name = "comedi_parport",
- .module = THIS_MODULE,
- .attach = parport_attach,
- .detach = parport_detach,
-};
-
-static int __init driver_parport_init_module(void)
-{
- return comedi_driver_register(&driver_parport);
-}
-
-static void __exit driver_parport_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_parport);
-}
-
-module_init(driver_parport_init_module);
-module_exit(driver_parport_cleanup_module);
-
struct parport_private {
unsigned int a_data;
unsigned int c_data;
@@ -395,19 +372,22 @@ static int parport_attach(struct comedi_device *dev,
return 1;
}
-static int parport_detach(struct comedi_device *dev)
+static void parport_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: parport: remove\n", dev->minor);
-
if (dev->iobase)
release_region(dev->iobase, PARPORT_SIZE);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
- return 0;
}
+static struct comedi_driver parport_driver = {
+ .driver_name = "comedi_parport",
+ .module = THIS_MODULE,
+ .attach = parport_attach,
+ .detach = parport_detach,
+};
+module_comedi_driver(parport_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c
index a804742b8022..873e37450bba 100644
--- a/drivers/staging/comedi/drivers/comedi_test.c
+++ b/drivers/staging/comedi/drivers/comedi_test.c
@@ -67,15 +67,6 @@ struct waveform_board {
#define N_CHANS 8
-static const struct waveform_board waveform_boards[] = {
- {
- .name = "comedi_test",
- .ai_chans = N_CHANS,
- .ai_bits = 16,
- .have_dio = 0,
- },
-};
-
#define thisboard ((const struct waveform_board *)dev->board_ptr)
/* Data unique to this driver */
@@ -94,54 +85,6 @@ struct waveform_private {
};
#define devpriv ((struct waveform_private *)dev->private)
-static int waveform_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int waveform_detach(struct comedi_device *dev);
-static struct comedi_driver driver_waveform = {
- .driver_name = "comedi_test",
- .module = THIS_MODULE,
- .attach = waveform_attach,
- .detach = waveform_detach,
- .board_name = &waveform_boards[0].name,
- .offset = sizeof(struct waveform_board),
- .num_names = ARRAY_SIZE(waveform_boards),
-};
-
-static int __init driver_waveform_init_module(void)
-{
- return comedi_driver_register(&driver_waveform);
-}
-
-static void __exit driver_waveform_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_waveform);
-}
-
-module_init(driver_waveform_init_module);
-module_exit(driver_waveform_cleanup_module);
-
-static int waveform_ai_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
-static int waveform_ai_cmd(struct comedi_device *dev,
- struct comedi_subdevice *s);
-static int waveform_ai_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s);
-static int waveform_ai_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int waveform_ao_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static short fake_sawtooth(struct comedi_device *dev, unsigned int range,
- unsigned long current_time);
-static short fake_squarewave(struct comedi_device *dev, unsigned int range,
- unsigned long current_time);
-static short fake_flatline(struct comedi_device *dev, unsigned int range,
- unsigned long current_time);
-static short fake_waveform(struct comedi_device *dev, unsigned int channel,
- unsigned int range, unsigned long current_time);
-
/* 1000 nanosec in a microsec */
static const int nano_per_micro = 1000;
@@ -154,6 +97,78 @@ static const struct comedi_lrange waveform_ai_ranges = {
}
};
+static short fake_sawtooth(struct comedi_device *dev, unsigned int range_index,
+ unsigned long current_time)
+{
+ struct comedi_subdevice *s = dev->read_subdev;
+ unsigned int offset = s->maxdata / 2;
+ u64 value;
+ const struct comedi_krange *krange =
+ &s->range_table->range[range_index];
+ u64 binary_amplitude;
+
+ binary_amplitude = s->maxdata;
+ binary_amplitude *= devpriv->uvolt_amplitude;
+ do_div(binary_amplitude, krange->max - krange->min);
+
+ current_time %= devpriv->usec_period;
+ value = current_time;
+ value *= binary_amplitude * 2;
+ do_div(value, devpriv->usec_period);
+ value -= binary_amplitude; /* get rid of sawtooth's dc offset */
+
+ return offset + value;
+}
+
+static short fake_squarewave(struct comedi_device *dev,
+ unsigned int range_index,
+ unsigned long current_time)
+{
+ struct comedi_subdevice *s = dev->read_subdev;
+ unsigned int offset = s->maxdata / 2;
+ u64 value;
+ const struct comedi_krange *krange =
+ &s->range_table->range[range_index];
+ current_time %= devpriv->usec_period;
+
+ value = s->maxdata;
+ value *= devpriv->uvolt_amplitude;
+ do_div(value, krange->max - krange->min);
+
+ if (current_time < devpriv->usec_period / 2)
+ value *= -1;
+
+ return offset + value;
+}
+
+static short fake_flatline(struct comedi_device *dev, unsigned int range_index,
+ unsigned long current_time)
+{
+ return dev->read_subdev->maxdata / 2;
+}
+
+/* generates a different waveform depending on what channel is read */
+static short fake_waveform(struct comedi_device *dev, unsigned int channel,
+ unsigned int range, unsigned long current_time)
+{
+ enum {
+ SAWTOOTH_CHAN,
+ SQUARE_CHAN,
+ };
+ switch (channel) {
+ case SAWTOOTH_CHAN:
+ return fake_sawtooth(dev, range, current_time);
+ break;
+ case SQUARE_CHAN:
+ return fake_squarewave(dev, range, current_time);
+ break;
+ default:
+ break;
+ }
+
+ return fake_flatline(dev, range, current_time);
+}
+
/*
This is the background routine used to generate arbitrary data.
It should run in the background; therefore it is scheduled by
@@ -217,84 +232,6 @@ static void waveform_ai_interrupt(unsigned long arg)
comedi_event(dev, dev->read_subdev);
}
-static int waveform_attach(struct comedi_device *dev,
- struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- int amplitude = it->options[0];
- int period = it->options[1];
- int i;
-
- dev->board_name = thisboard->name;
-
- if (alloc_private(dev, sizeof(struct waveform_private)) < 0)
- return -ENOMEM;
-
- /* set default amplitude and period */
- if (amplitude <= 0)
- amplitude = 1000000; /* 1 volt */
- if (period <= 0)
- period = 100000; /* 0.1 sec */
-
- devpriv->uvolt_amplitude = amplitude;
- devpriv->usec_period = period;
-
- dev->n_subdevices = 2;
- if (alloc_subdevices(dev, dev->n_subdevices) < 0)
- return -ENOMEM;
-
- s = dev->subdevices + 0;
- dev->read_subdev = s;
- /* analog input subdevice */
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
- s->n_chan = thisboard->ai_chans;
- s->maxdata = (1 << thisboard->ai_bits) - 1;
- s->range_table = &waveform_ai_ranges;
- s->len_chanlist = s->n_chan * 2;
- s->insn_read = waveform_ai_insn_read;
- s->do_cmd = waveform_ai_cmd;
- s->do_cmdtest = waveform_ai_cmdtest;
- s->cancel = waveform_ai_cancel;
-
- s = dev->subdevices + 1;
- dev->write_subdev = s;
- /* analog output subdevice (loopback) */
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
- s->n_chan = thisboard->ai_chans;
- s->maxdata = (1 << thisboard->ai_bits) - 1;
- s->range_table = &waveform_ai_ranges;
- s->len_chanlist = s->n_chan * 2;
- s->insn_write = waveform_ao_insn_write;
- s->do_cmd = NULL;
- s->do_cmdtest = NULL;
- s->cancel = NULL;
-
- /* Our default loopback value is just a 0V flatline */
- for (i = 0; i < s->n_chan; i++)
- devpriv->ao_loopbacks[i] = s->maxdata / 2;
-
- init_timer(&(devpriv->timer));
- devpriv->timer.function = waveform_ai_interrupt;
- devpriv->timer.data = (unsigned long)dev;
-
- printk(KERN_INFO "comedi%d: comedi_test: "
- "%i microvolt, %li microsecond waveform attached\n", dev->minor,
- devpriv->uvolt_amplitude, devpriv->usec_period);
- return 1;
-}
-
-static int waveform_detach(struct comedi_device *dev)
-{
- printk("comedi%d: comedi_test: remove\n", dev->minor);
-
- if (dev->private)
- waveform_ai_cancel(dev, dev->read_subdev);
-
- return 0;
-}
-
static int waveform_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
@@ -465,78 +402,6 @@ static int waveform_ai_cancel(struct comedi_device *dev,
return 0;
}
-static short fake_sawtooth(struct comedi_device *dev, unsigned int range_index,
- unsigned long current_time)
-{
- struct comedi_subdevice *s = dev->read_subdev;
- unsigned int offset = s->maxdata / 2;
- u64 value;
- const struct comedi_krange *krange =
- &s->range_table->range[range_index];
- u64 binary_amplitude;
-
- binary_amplitude = s->maxdata;
- binary_amplitude *= devpriv->uvolt_amplitude;
- do_div(binary_amplitude, krange->max - krange->min);
-
- current_time %= devpriv->usec_period;
- value = current_time;
- value *= binary_amplitude * 2;
- do_div(value, devpriv->usec_period);
- value -= binary_amplitude; /* get rid of sawtooth's dc offset */
-
- return offset + value;
-}
-
-static short fake_squarewave(struct comedi_device *dev,
- unsigned int range_index,
- unsigned long current_time)
-{
- struct comedi_subdevice *s = dev->read_subdev;
- unsigned int offset = s->maxdata / 2;
- u64 value;
- const struct comedi_krange *krange =
- &s->range_table->range[range_index];
- current_time %= devpriv->usec_period;
-
- value = s->maxdata;
- value *= devpriv->uvolt_amplitude;
- do_div(value, krange->max - krange->min);
-
- if (current_time < devpriv->usec_period / 2)
- value *= -1;
-
- return offset + value;
-}
-
-static short fake_flatline(struct comedi_device *dev, unsigned int range_index,
- unsigned long current_time)
-{
- return dev->read_subdev->maxdata / 2;
-}
-
-/* generates a different waveform depending on what channel is read */
-static short fake_waveform(struct comedi_device *dev, unsigned int channel,
- unsigned int range, unsigned long current_time)
-{
- enum {
- SAWTOOTH_CHAN,
- SQUARE_CHAN,
- };
- switch (channel) {
- case SAWTOOTH_CHAN:
- return fake_sawtooth(dev, range, current_time);
- break;
- case SQUARE_CHAN:
- return fake_squarewave(dev, range, current_time);
- break;
- default:
- break;
- }
-
- return fake_flatline(dev, range, current_time);
-}
-
static int waveform_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -561,6 +426,100 @@ static int waveform_ao_insn_write(struct comedi_device *dev,
return insn->n;
}
+static int waveform_attach(struct comedi_device *dev,
+ struct comedi_devconfig *it)
+{
+ struct comedi_subdevice *s;
+ int amplitude = it->options[0];
+ int period = it->options[1];
+ int i;
+
+ dev->board_name = thisboard->name;
+
+ if (alloc_private(dev, sizeof(struct waveform_private)) < 0)
+ return -ENOMEM;
+
+ /* set default amplitude and period */
+ if (amplitude <= 0)
+ amplitude = 1000000; /* 1 volt */
+ if (period <= 0)
+ period = 100000; /* 0.1 sec */
+
+ devpriv->uvolt_amplitude = amplitude;
+ devpriv->usec_period = period;
+
+ dev->n_subdevices = 2;
+ if (alloc_subdevices(dev, dev->n_subdevices) < 0)
+ return -ENOMEM;
+
+ s = dev->subdevices + 0;
+ dev->read_subdev = s;
+ /* analog input subdevice */
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
+ s->n_chan = thisboard->ai_chans;
+ s->maxdata = (1 << thisboard->ai_bits) - 1;
+ s->range_table = &waveform_ai_ranges;
+ s->len_chanlist = s->n_chan * 2;
+ s->insn_read = waveform_ai_insn_read;
+ s->do_cmd = waveform_ai_cmd;
+ s->do_cmdtest = waveform_ai_cmdtest;
+ s->cancel = waveform_ai_cancel;
+
+ s = dev->subdevices + 1;
+ dev->write_subdev = s;
+ /* analog output subdevice (loopback) */
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITEABLE | SDF_GROUND;
+ s->n_chan = thisboard->ai_chans;
+ s->maxdata = (1 << thisboard->ai_bits) - 1;
+ s->range_table = &waveform_ai_ranges;
+ s->len_chanlist = s->n_chan * 2;
+ s->insn_write = waveform_ao_insn_write;
+ s->do_cmd = NULL;
+ s->do_cmdtest = NULL;
+ s->cancel = NULL;
+
+ /* Our default loopback value is just a 0V flatline */
+ for (i = 0; i < s->n_chan; i++)
+ devpriv->ao_loopbacks[i] = s->maxdata / 2;
+
+ init_timer(&(devpriv->timer));
+ devpriv->timer.function = waveform_ai_interrupt;
+ devpriv->timer.data = (unsigned long)dev;
+
+ printk(KERN_INFO "comedi%d: comedi_test: "
+ "%i microvolt, %li microsecond waveform attached\n", dev->minor,
+ devpriv->uvolt_amplitude, devpriv->usec_period);
+ return 1;
+}
+
+static void waveform_detach(struct comedi_device *dev)
+{
+ if (dev->private)
+ waveform_ai_cancel(dev, dev->read_subdev);
+}
+
+static const struct waveform_board waveform_boards[] = {
+ {
+ .name = "comedi_test",
+ .ai_chans = N_CHANS,
+ .ai_bits = 16,
+ .have_dio = 0,
+ },
+};
+
+static struct comedi_driver waveform_driver = {
+ .driver_name = "comedi_test",
+ .module = THIS_MODULE,
+ .attach = waveform_attach,
+ .detach = waveform_detach,
+ .board_name = &waveform_boards[0].name,
+ .offset = sizeof(struct waveform_board),
+ .num_names = ARRAY_SIZE(waveform_boards),
+};
+module_comedi_driver(waveform_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c
index e3659bd6e85e..b8bac80f2baf 100644
--- a/drivers/staging/comedi/drivers/contec_pci_dio.c
+++ b/drivers/staging/comedi/drivers/contec_pci_dio.c
@@ -56,13 +56,6 @@ static const struct contec_board contec_boards[] = {
};
#define PCI_DEVICE_ID_PIO1616L 0x8172
-static DEFINE_PCI_DEVICE_TABLE(contec_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_CONTEC, PCI_DEVICE_ID_PIO1616L),
- .driver_data = PIO1616L },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, contec_pci_table);
#define thisboard ((const struct contec_board *)dev->board_ptr)
@@ -75,30 +68,42 @@ struct contec_private {
#define devpriv ((struct contec_private *)dev->private)
-static int contec_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int contec_detach(struct comedi_device *dev);
-static struct comedi_driver driver_contec = {
- .driver_name = "contec_pci_dio",
- .module = THIS_MODULE,
- .attach = contec_attach,
- .detach = contec_detach,
-};
+static int contec_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+
+ dev_dbg(dev->hw_dev, "contec_do_insn_bits called\n");
+ dev_dbg(dev->hw_dev, "data: %d %d\n", data[0], data[1]);
+
+ if (insn->n != 2)
+ return -EINVAL;
+
+ if (data[0]) {
+ s->state &= ~data[0];
+ s->state |= data[0] & data[1];
+ dev_dbg(dev->hw_dev, "out: %d on %lx\n", s->state,
+ dev->iobase + thisboard->out_offs);
+ outw(s->state, dev->iobase + thisboard->out_offs);
+ }
+ return 2;
+}
-/* Classic digital IO */
static int contec_di_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int contec_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
+ struct comedi_insn *insn, unsigned int *data)
+{
+
+ dev_dbg(dev->hw_dev, "contec_di_insn_bits called\n");
+ dev_dbg(dev->hw_dev, "data: %d %d\n", data[0], data[1]);
-#if 0
-static int contec_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
+ if (insn->n != 2)
+ return -EINVAL;
-static int contec_ns_to_timer(unsigned int *ns, int round);
-#endif
+ data[1] = inw(dev->iobase + thisboard->in_offs);
+
+ return 2;
+}
static int contec_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
@@ -164,107 +169,47 @@ static int contec_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return -EIO;
}
-static int contec_detach(struct comedi_device *dev)
+static void contec_detach(struct comedi_device *dev)
{
- printk("comedi%d: contec: remove\n", dev->minor);
-
if (devpriv && devpriv->pci_dev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pci_dev);
pci_dev_put(devpriv->pci_dev);
}
-
- return 0;
-}
-
-#if 0
-static int contec_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_cmd *cmd)
-{
- printk("contec_cmdtest called\n");
- return 0;
-}
-
-static int contec_ns_to_timer(unsigned int *ns, int round)
-{
- return *ns;
-}
-#endif
-
-static int contec_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
-
- dev_dbg(dev->hw_dev, "contec_do_insn_bits called\n");
- dev_dbg(dev->hw_dev, "data: %d %d\n", data[0], data[1]);
-
- if (insn->n != 2)
- return -EINVAL;
-
- if (data[0]) {
- s->state &= ~data[0];
- s->state |= data[0] & data[1];
- dev_dbg(dev->hw_dev, "out: %d on %lx\n", s->state,
- dev->iobase + thisboard->out_offs);
- outw(s->state, dev->iobase + thisboard->out_offs);
- }
- return 2;
}
-static int contec_di_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
-
- dev_dbg(dev->hw_dev, "contec_di_insn_bits called\n");
- dev_dbg(dev->hw_dev, "data: %d %d\n", data[0], data[1]);
-
- if (insn->n != 2)
- return -EINVAL;
-
- data[1] = inw(dev->iobase + thisboard->in_offs);
-
- return 2;
-}
+static struct comedi_driver contec_pci_dio_driver = {
+ .driver_name = "contec_pci_dio",
+ .module = THIS_MODULE,
+ .attach = contec_attach,
+ .detach = contec_detach,
+};
-static int __devinit driver_contec_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static int __devinit contec_pci_dio_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_contec.driver_name);
+ return comedi_pci_auto_config(dev, &contec_pci_dio_driver);
}
-static void __devexit driver_contec_pci_remove(struct pci_dev *dev)
+static void __devexit contec_pci_dio_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_contec_pci_driver = {
- .id_table = contec_pci_table,
- .probe = &driver_contec_pci_probe,
- .remove = __devexit_p(&driver_contec_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(contec_pci_dio_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CONTEC, PCI_DEVICE_ID_PIO1616L),
+ .driver_data = PIO1616L },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, contec_pci_dio_pci_table);
-static int __init driver_contec_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_contec);
- if (retval < 0)
- return retval;
-
- driver_contec_pci_driver.name = (char *)driver_contec.driver_name;
- return pci_register_driver(&driver_contec_pci_driver);
-}
-
-static void __exit driver_contec_cleanup_module(void)
-{
- pci_unregister_driver(&driver_contec_pci_driver);
- comedi_driver_unregister(&driver_contec);
-}
-
-module_init(driver_contec_init_module);
-module_exit(driver_contec_cleanup_module);
+static struct pci_driver contec_pci_dio_pci_driver = {
+ .name = "contec_pci_dio",
+ .id_table = contec_pci_dio_pci_table,
+ .probe = contec_pci_dio_pci_probe,
+ .remove = __devexit_p(contec_pci_dio_pci_remove),
+};
+module_comedi_pci_driver(contec_pci_dio_driver, contec_pci_dio_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c
index e61c6a8f2857..696b58ca2e59 100644
--- a/drivers/staging/comedi/drivers/daqboard2000.c
+++ b/drivers/staging/comedi/drivers/daqboard2000.c
@@ -301,17 +301,6 @@ struct daqboard2000_hw {
#define DAQBOARD2000_PosRefDacSelect 0x0100
#define DAQBOARD2000_NegRefDacSelect 0x0000
-static int daqboard2000_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int daqboard2000_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_daqboard2000 = {
- .driver_name = "daqboard2000",
- .module = THIS_MODULE,
- .attach = daqboard2000_attach,
- .detach = daqboard2000_detach,
-};
-
struct daq200_boardtype {
const char *name;
int id;
@@ -321,16 +310,8 @@ static const struct daq200_boardtype boardtypes[] = {
{"ids4", DAQBOARD2000_SUBSYSTEM_IDS4},
};
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct daq200_boardtype))
#define this_board ((const struct daq200_boardtype *)dev->board_ptr)
-static DEFINE_PCI_DEVICE_TABLE(daqboard2000_pci_table) = {
- { PCI_DEVICE(0x1616, 0x0409) },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, daqboard2000_pci_table);
-
struct daqboard2000_private {
enum {
card_daqboard_2000
@@ -412,9 +393,12 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev,
DAQBOARD2000_AcqResetScanListFifo |
DAQBOARD2000_AcqResetResultsFifo | DAQBOARD2000_AcqResetConfigPipe;
- /* If pacer clock is not set to some high value (> 10 us), we
- risk multiple samples to be put into the result FIFO. */
- fpga->acqPacerClockDivLow = 1000000; /* 1 second, should be long enough */
+ /*
+ * If pacer clock is not set to some high value (> 10 us), we
+ * risk multiple samples to be put into the result FIFO.
+ */
+ /* 1 second, should be long enough */
+ fpga->acqPacerClockDivLow = 1000000;
fpga->acqPacerClockDivHigh = 0;
gain = CR_RANGE(insn->chanspec);
@@ -761,7 +745,7 @@ static int daqboard2000_attach(struct comedi_device *dev,
devpriv->pci_dev = card;
id = ((u32) card->
subsystem_device << 16) | card->subsystem_vendor;
- for (i = 0; i < n_boardtypes; i++) {
+ for (i = 0; i < ARRAY_SIZE(boardtypes); i++) {
if (boardtypes[i].id == id) {
dev_dbg(dev->hw_dev, "%s\n",
boardtypes[i].name);
@@ -852,14 +836,12 @@ out:
return result;
}
-static int daqboard2000_detach(struct comedi_device *dev)
+static void daqboard2000_detach(struct comedi_device *dev)
{
if (dev->subdevices)
subdev_8255_cleanup(dev, dev->subdevices + 2);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
if (devpriv) {
if (devpriv->daq)
iounmap(devpriv->daq);
@@ -871,48 +853,39 @@ static int daqboard2000_detach(struct comedi_device *dev)
pci_dev_put(devpriv->pci_dev);
}
}
- return 0;
}
-static int __devinit driver_daqboard2000_pci_probe(struct pci_dev *dev,
- const struct pci_device_id
- *ent)
+static struct comedi_driver daqboard2000_driver = {
+ .driver_name = "daqboard2000",
+ .module = THIS_MODULE,
+ .attach = daqboard2000_attach,
+ .detach = daqboard2000_detach,
+};
+
+static int __devinit daqboard2000_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_daqboard2000.driver_name);
+ return comedi_pci_auto_config(dev, &daqboard2000_driver);
}
-static void __devexit driver_daqboard2000_pci_remove(struct pci_dev *dev)
+static void __devexit daqboard2000_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_daqboard2000_pci_driver = {
- .id_table = daqboard2000_pci_table,
- .probe = &driver_daqboard2000_pci_probe,
- .remove = __devexit_p(&driver_daqboard2000_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(daqboard2000_pci_table) = {
+ { PCI_DEVICE(0x1616, 0x0409) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, daqboard2000_pci_table);
-static int __init driver_daqboard2000_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_daqboard2000);
- if (retval < 0)
- return retval;
-
- driver_daqboard2000_pci_driver.name =
- (char *)driver_daqboard2000.driver_name;
- return pci_register_driver(&driver_daqboard2000_pci_driver);
-}
-
-static void __exit driver_daqboard2000_cleanup_module(void)
-{
- pci_unregister_driver(&driver_daqboard2000_pci_driver);
- comedi_driver_unregister(&driver_daqboard2000);
-}
-
-module_init(driver_daqboard2000_init_module);
-module_exit(driver_daqboard2000_cleanup_module);
+static struct pci_driver daqboard2000_pci_driver = {
+ .name = "daqboard2000",
+ .id_table = daqboard2000_pci_table,
+ .probe = daqboard2000_pci_probe,
+ .remove = __devexit_p(daqboard2000_pci_remove),
+};
+module_comedi_pci_driver(daqboard2000_driver, daqboard2000_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c
index c2dd0ed36a73..1f319435e23f 100644
--- a/drivers/staging/comedi/drivers/das08.c
+++ b/drivers/staging/comedi/drivers/das08.c
@@ -61,6 +61,20 @@
#define DRV_NAME "das08"
+#ifdef CONFIG_COMEDI_DAS08_ISA_MODULE
+#define CONFIG_COMEDI_DAS08_ISA
+#endif
+#ifdef CONFIG_COMEDI_DAS08_PCI_MODULE
+#define CONFIG_COMEDI_DAS08_PCI
+#endif
+#ifdef CONFIG_COMEDI_DAS08_CS_MODULE
+#define CONFIG_COMEDI_DAS08_CS
+#endif
+
+#if defined(CONFIG_COMEDI_DAS08_ISA) || defined(CONFIG_COMEDI_DAS08_PCI)
+#define DO_COMEDI_DRIVER_REGISTER
+#endif
+
#define PCI_VENDOR_ID_COMPUTERBOARDS 0x1307
#define PCI_DEVICE_ID_PCIDAS08 0x29
#define PCIDAS08_SIZE 0x54
@@ -160,6 +174,7 @@ static int das08_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
static int das08_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
+#ifdef CONFIG_COMEDI_DAS08_ISA
static int das08jr_di_rbits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
@@ -172,6 +187,7 @@ static int das08jr_ao_winsn(struct comedi_device *dev,
static int das08ao_ao_winsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
+#endif
static void i8254_set_mode_low(unsigned int base, int channel,
unsigned int mode);
@@ -253,7 +269,9 @@ static const int *const das08_gainlists[] = {
das08_pgm_gainlist,
};
+#ifdef DO_COMEDI_DRIVER_REGISTER
static const struct das08_board_struct das08_boards[] = {
+#ifdef CONFIG_COMEDI_DAS08_ISA
{
.name = "isa-das08", /* cio-das08.pdf */
.bustype = isa,
@@ -395,25 +413,6 @@ static const struct das08_board_struct das08_boards[] = {
.i8254_offset = 0x04,
.iosize = 16, /* unchecked */
},
-#ifdef CONFIG_COMEDI_PCI
- {
- .name = "das08", /* pci-das08 */
- .id = PCI_DEVICE_ID_PCIDAS08,
- .bustype = pci,
- .ai = das08_ai_rinsn,
- .ai_nbits = 12,
- .ai_pg = das08_bipolar5,
- .ai_encoding = das08_encode12,
- .ao = NULL,
- .ao_nbits = 0,
- .di = das08_di_rbits,
- .do_ = das08_do_wbits,
- .do_nchan = 4,
- .i8255_offset = 0,
- .i8254_offset = 4,
- .iosize = 8,
- },
-#endif
{
.name = "pc104-das08",
.bustype = pc104,
@@ -462,9 +461,30 @@ static const struct das08_board_struct das08_boards[] = {
.name = "das08-pga-g2", /* a KM board */
},
#endif
+#endif /* CONFIG_COMEDI_DAS08_ISA */
+#ifdef CONFIG_COMEDI_DAS08_PCI
+ {
+ .name = "das08", /* pci-das08 */
+ .id = PCI_DEVICE_ID_PCIDAS08,
+ .bustype = pci,
+ .ai = das08_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_pg = das08_bipolar5,
+ .ai_encoding = das08_encode12,
+ .ao = NULL,
+ .ao_nbits = 0,
+ .di = das08_di_rbits,
+ .do_ = das08_do_wbits,
+ .do_nchan = 4,
+ .i8255_offset = 0,
+ .i8254_offset = 4,
+ .iosize = 8,
+ },
+#endif /* CONFIG_COMEDI_DAS08_PCI */
};
+#endif /* DO_COMEDI_DRIVER_REGISTER */
-#ifdef CONFIG_COMEDI_PCMCIA
+#ifdef CONFIG_COMEDI_DAS08_CS
struct das08_board_struct das08_cs_boards[NUM_DAS08_CS_BOARDS] = {
{
.name = "pcm-das08",
@@ -504,7 +524,7 @@ struct das08_board_struct das08_cs_boards[NUM_DAS08_CS_BOARDS] = {
};
#endif
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_DAS08_PCI
static DEFINE_PCI_DEVICE_TABLE(das08_pci_table) = {
{ PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, PCI_DEVICE_ID_PCIDAS08) },
{0}
@@ -619,6 +639,7 @@ static int das08_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
return 2;
}
+#ifdef CONFIG_COMEDI_DAS08_ISA
static int das08jr_di_rbits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -628,7 +649,9 @@ static int das08jr_di_rbits(struct comedi_device *dev,
return 2;
}
+#endif
+#ifdef CONFIG_COMEDI_DAS08_ISA
static int das08jr_do_wbits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -643,7 +666,9 @@ static int das08jr_do_wbits(struct comedi_device *dev,
return 2;
}
+#endif
+#ifdef CONFIG_COMEDI_DAS08_ISA
static int das08jr_ao_winsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -672,6 +697,7 @@ static int das08jr_ao_winsn(struct comedi_device *dev,
return n;
}
+#endif
/*
*
@@ -679,6 +705,7 @@ static int das08jr_ao_winsn(struct comedi_device *dev,
* a different method to force an update.
*
*/
+#ifdef CONFIG_COMEDI_DAS08_ISA
static int das08ao_ao_winsn(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -707,6 +734,7 @@ static int das08ao_ao_winsn(struct comedi_device *dev,
return n;
}
+#endif
static unsigned int i8254_read_channel_low(unsigned int base, int chan)
{
@@ -842,6 +870,7 @@ static int das08_counter_config(struct comedi_device *dev,
return 2;
}
+#ifdef DO_COMEDI_DRIVER_REGISTER
static int das08_attach(struct comedi_device *dev, struct comedi_devconfig *it);
static struct comedi_driver driver_das08 = {
@@ -853,6 +882,7 @@ static struct comedi_driver driver_das08 = {
.num_names = sizeof(das08_boards) / sizeof(struct das08_board_struct),
.offset = sizeof(struct das08_board_struct),
};
+#endif
int das08_common_attach(struct comedi_device *dev, unsigned long iobase)
{
@@ -972,11 +1002,12 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase)
}
EXPORT_SYMBOL_GPL(das08_common_attach);
+#ifdef DO_COMEDI_DRIVER_REGISTER
static int das08_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
int ret;
unsigned long iobase;
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_DAS08_PCI
unsigned long pci_iobase = 0;
struct pci_dev *pdev = NULL;
#endif
@@ -986,9 +1017,9 @@ static int das08_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return ret;
printk(KERN_INFO "comedi%d: das08: ", dev->minor);
+#ifdef CONFIG_COMEDI_DAS08_PCI
/* deal with a pci board */
if (thisboard->bustype == pci) {
-#ifdef CONFIG_COMEDI_PCI
if (it->options[0] || it->options[1]) {
printk("bus %i slot %i ",
it->options[0], it->options[1]);
@@ -1037,32 +1068,26 @@ static int das08_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* Enable local interrupt 1 and pci interrupt */
outw(INTR1_ENABLE | PCI_INTR_ENABLE, pci_iobase + INTCSR);
#endif
-#else /* CONFIG_COMEDI_PCI */
- printk(KERN_ERR "this driver has not been built with PCI support.\n");
- return -EINVAL;
-#endif /* CONFIG_COMEDI_PCI */
- } else {
+ } else
+#endif /* CONFIG_COMEDI_DAS08_PCI */
+ {
iobase = it->options[0];
}
printk(KERN_INFO "\n");
return das08_common_attach(dev, iobase);
}
+#endif /* DO_COMEDI_DRIVER_REGISTER */
-
-int das08_common_detach(struct comedi_device *dev)
+void das08_common_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: das08: remove\n", dev->minor);
-
if (dev->subdevices)
subdev_8255_cleanup(dev, dev->subdevices + 4);
-
- /* deallocate ioports for non-pcmcia, non-pci boards */
if ((thisboard->bustype != pcmcia) && (thisboard->bustype != pci)) {
if (dev->iobase)
release_region(dev->iobase, thisboard->iosize);
}
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_DAS08_PCI
if (devpriv) {
if (devpriv->pdev) {
if (devpriv->pci_iobase)
@@ -1072,16 +1097,14 @@ int das08_common_detach(struct comedi_device *dev)
}
}
#endif
-
- return 0;
}
EXPORT_SYMBOL_GPL(das08_common_detach);
-#ifdef CONFIG_COMEDI_PCI
+#ifdef CONFIG_COMEDI_DAS08_PCI
static int __devinit driver_das08_pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_das08.driver_name);
+ return comedi_pci_auto_config(dev, &driver_das08);
}
static void __devexit driver_das08_pci_remove(struct pci_dev *dev)
@@ -1094,43 +1117,38 @@ static struct pci_driver driver_das08_pci_driver = {
.probe = &driver_das08_pci_probe,
.remove = __devexit_p(&driver_das08_pci_remove)
};
+#endif /* CONFIG_COMEDI_DAS08_PCI */
static int __init driver_das08_init_module(void)
{
- int retval;
+ int retval = 0;
+#ifdef DO_COMEDI_DRIVER_REGISTER
retval = comedi_driver_register(&driver_das08);
if (retval < 0)
return retval;
-
+#endif
+#ifdef CONFIG_COMEDI_DAS08_PCI
driver_das08_pci_driver.name = (char *)driver_das08.driver_name;
- return pci_register_driver(&driver_das08_pci_driver);
+ retval = pci_register_driver(&driver_das08_pci_driver);
+#endif
+ return retval;
}
static void __exit driver_das08_cleanup_module(void)
{
+#ifdef CONFIG_COMEDI_DAS08_PCI
pci_unregister_driver(&driver_das08_pci_driver);
+#endif
+#ifdef DO_COMEDI_DRIVER_REGISTER
comedi_driver_unregister(&driver_das08);
+#endif
}
module_init(driver_das08_init_module);
module_exit(driver_das08_cleanup_module);
-#else
-static int __init driver_das08_init_module(void)
-{
- return comedi_driver_register(&driver_das08);
-}
-
-static void __exit driver_das08_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_das08);
-}
-
-module_init(driver_das08_init_module);
-module_exit(driver_das08_cleanup_module);
-#endif
-#ifdef CONFIG_COMEDI_PCMCIA
+#ifdef CONFIG_COMEDI_DAS08_CS
EXPORT_SYMBOL_GPL(das08_cs_boards);
#endif
diff --git a/drivers/staging/comedi/drivers/das08.h b/drivers/staging/comedi/drivers/das08.h
index 2a30d764ddfc..0b92f24b261f 100644
--- a/drivers/staging/comedi/drivers/das08.h
+++ b/drivers/staging/comedi/drivers/das08.h
@@ -74,6 +74,6 @@ struct das08_private_struct {
extern struct das08_board_struct das08_cs_boards[NUM_DAS08_CS_BOARDS];
int das08_common_attach(struct comedi_device *dev, unsigned long iobase);
-int das08_common_detach(struct comedi_device *dev);
+void das08_common_detach(struct comedi_device *dev);
#endif /* _DAS08_H */
diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c
index e7905bac92da..998444c1ba32 100644
--- a/drivers/staging/comedi/drivers/das16.c
+++ b/drivers/staging/comedi/drivers/das16.c
@@ -339,38 +339,6 @@ struct munge_info {
unsigned have_byte:1;
};
-static int das16_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int das16_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int das16_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int das16_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
-static int das16_cmd_exec(struct comedi_device *dev,
- struct comedi_subdevice *s);
-static int das16_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-static void das16_ai_munge(struct comedi_device *dev,
- struct comedi_subdevice *s, void *array,
- unsigned int num_bytes,
- unsigned int start_chan_index);
-
-static void das16_reset(struct comedi_device *dev);
-static irqreturn_t das16_dma_interrupt(int irq, void *d);
-static void das16_timer_interrupt(unsigned long arg);
-static void das16_interrupt(struct comedi_device *dev);
-
-static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns,
- int flags);
-static int das1600_mode_detect(struct comedi_device *dev);
-static unsigned int das16_suggest_transfer_size(struct comedi_device *dev,
- struct comedi_cmd cmd);
-
-static void reg_dump(struct comedi_device *dev);
-
struct das16_board {
const char *name;
void *ai;
@@ -389,344 +357,6 @@ struct das16_board {
unsigned int id;
};
-static const struct das16_board das16_boards[] = {
- {
- .name = "das-16",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 15000,
- .ai_pg = das16_pg_none,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x10,
- .i8254_offset = 0x0c,
- .size = 0x14,
- .id = 0x00,
- },
- {
- .name = "das-16g",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 15000,
- .ai_pg = das16_pg_none,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x10,
- .i8254_offset = 0x0c,
- .size = 0x14,
- .id = 0x00,
- },
- {
- .name = "das-16f",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 8500,
- .ai_pg = das16_pg_none,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x10,
- .i8254_offset = 0x0c,
- .size = 0x14,
- .id = 0x00,
- },
- {
- .name = "cio-das16", /* cio-das16.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 20000,
- .ai_pg = das16_pg_none,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x10,
- .i8254_offset = 0x0c,
- .size = 0x14,
- .id = 0x80,
- },
- {
- .name = "cio-das16/f", /* das16.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 10000,
- .ai_pg = das16_pg_none,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x10,
- .i8254_offset = 0x0c,
- .size = 0x14,
- .id = 0x80,
- },
- {
- .name = "cio-das16/jr", /* cio-das16jr.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 7692,
- .ai_pg = das16_pg_16jr,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x10,
- .id = 0x00,
- },
- {
- .name = "pc104-das16jr", /* pc104-das16jr_xx.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 3300,
- .ai_pg = das16_pg_16jr,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x10,
- .id = 0x00,
- },
- {
- .name = "cio-das16jr/16", /* cio-das16jr_16.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 16,
- .ai_speed = 10000,
- .ai_pg = das16_pg_16jr_16,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x10,
- .id = 0x00,
- },
- {
- .name = "pc104-das16jr/16", /* pc104-das16jr_xx.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 16,
- .ai_speed = 10000,
- .ai_pg = das16_pg_16jr_16,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x10,
- .id = 0x00,
- },
- {
- .name = "das-1201", /* 4924.pdf (keithley user's manual) */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 20000,
- .ai_pg = das16_pg_none,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x400,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0x20,
- },
- {
- .name = "das-1202", /* 4924.pdf (keithley user's manual) */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 10000,
- .ai_pg = das16_pg_none,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x400,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0x20,
- },
- {
- /* 4919.pdf and 4922.pdf (keithley user's manual) */
- .name = "das-1401",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 10000,
- .ai_pg = das16_pg_1601,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x0,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0 /* 4919.pdf says id bits are 0xe0, 4922.pdf says 0xc0 */
- },
- {
- /* 4919.pdf and 4922.pdf (keithley user's manual) */
- .name = "das-1402",
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 10000,
- .ai_pg = das16_pg_1602,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x0,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0 /* 4919.pdf says id bits are 0xe0, 4922.pdf says 0xc0 */
- },
- {
- .name = "das-1601", /* 4919.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 10000,
- .ai_pg = das16_pg_1601,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x400,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0},
- {
- .name = "das-1602", /* 4919.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 10000,
- .ai_pg = das16_pg_1602,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x400,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0},
- {
- .name = "cio-das1401/12", /* cio-das1400_series.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 6250,
- .ai_pg = das16_pg_1601,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0},
- {
- .name = "cio-das1402/12", /* cio-das1400_series.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 6250,
- .ai_pg = das16_pg_1602,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0},
- {
- .name = "cio-das1402/16", /* cio-das1400_series.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 16,
- .ai_speed = 10000,
- .ai_pg = das16_pg_1602,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0},
- {
- .name = "cio-das1601/12", /* cio-das160x-1x.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 6250,
- .ai_pg = das16_pg_1601,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x400,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0},
- {
- .name = "cio-das1602/12", /* cio-das160x-1x.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 10000,
- .ai_pg = das16_pg_1602,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x400,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0},
- {
- .name = "cio-das1602/16", /* cio-das160x-1x.pdf */
- .ai = das16_ai_rinsn,
- .ai_nbits = 16,
- .ai_speed = 10000,
- .ai_pg = das16_pg_1602,
- .ao = das16_ao_winsn,
- .ao_nbits = 12,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0x400,
- .i8254_offset = 0x0c,
- .size = 0x408,
- .id = 0xc0},
- {
- .name = "cio-das16/330", /* ? */
- .ai = das16_ai_rinsn,
- .ai_nbits = 12,
- .ai_speed = 3030,
- .ai_pg = das16_pg_16jr,
- .ao = NULL,
- .di = das16_di_rbits,
- .do_ = das16_do_wbits,
- .i8255_offset = 0,
- .i8254_offset = 0x0c,
- .size = 0x14,
- .id = 0xf0},
-#if 0
- {
- .name = "das16/330i", /* ? */
- },
- {
- .name = "das16/jr/ctr5", /* ? */
- },
- {
- /* cio-das16_m1_16.pdf, this board is a bit quirky, no dma */
- .name = "cio-das16/m1/16",
- },
-#endif
-};
-
-static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int das16_detach(struct comedi_device *dev);
-static struct comedi_driver driver_das16 = {
- .driver_name = "das16",
- .module = THIS_MODULE,
- .attach = das16_attach,
- .detach = das16_detach,
- .board_name = &das16_boards[0].name,
- .num_names = ARRAY_SIZE(das16_boards),
- .offset = sizeof(das16_boards[0]),
-};
-
#define DAS16_TIMEOUT 1000
/* Period for timer interrupt in jiffies. It's a function
@@ -926,6 +556,62 @@ static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
return 0;
}
+/* utility function that suggests a dma transfer size in bytes */
+static unsigned int das16_suggest_transfer_size(struct comedi_device *dev,
+ struct comedi_cmd cmd)
+{
+ unsigned int size;
+ unsigned int freq;
+
+ /* if we are using timer interrupt, we don't care how long it
+ * will take to complete transfer since it will be interrupted
+ * by timer interrupt */
+ if (devpriv->timer_mode)
+ return DAS16_DMA_SIZE;
+
+ /* otherwise, we are relying on dma terminal count interrupt,
+ * so pick a reasonable size */
+ if (cmd.convert_src == TRIG_TIMER)
+ freq = 1000000000 / cmd.convert_arg;
+ else if (cmd.scan_begin_src == TRIG_TIMER)
+ freq = (1000000000 / cmd.scan_begin_arg) * cmd.chanlist_len;
+ /* return some default value */
+ else
+ freq = 0xffffffff;
+
+ if (cmd.flags & TRIG_WAKE_EOS) {
+ size = sample_size * cmd.chanlist_len;
+ } else {
+ /* make buffer fill in no more than 1/3 second */
+ size = (freq / 3) * sample_size;
+ }
+
+ /* set a minimum and maximum size allowed */
+ if (size > DAS16_DMA_SIZE)
+ size = DAS16_DMA_SIZE - DAS16_DMA_SIZE % sample_size;
+ else if (size < sample_size)
+ size = sample_size;
+
+ if (cmd.stop_src == TRIG_COUNT && size > devpriv->adc_byte_count)
+ size = devpriv->adc_byte_count;
+
+ return size;
+}
+
+static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns,
+ int rounding_flags)
+{
+ i8253_cascade_ns_to_timer_2div(devpriv->clockbase, &(devpriv->divisor1),
+ &(devpriv->divisor2), &ns,
+ rounding_flags & TRIG_ROUND_MASK);
+
+ /* Write the values of ctr1 and ctr2 into counters 1 and 2 */
+ i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 1, devpriv->divisor1, 2);
+ i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 2, devpriv->divisor2, 2);
+
+ return ns;
+}
+
static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct comedi_async *async = s->async;
@@ -1170,34 +856,6 @@ static int das16_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
return i;
}
-static irqreturn_t das16_dma_interrupt(int irq, void *d)
-{
- int status;
- struct comedi_device *dev = d;
-
- status = inb(dev->iobase + DAS16_STATUS);
-
- if ((status & DAS16_INT) == 0) {
- DEBUG_PRINT("spurious interrupt\n");
- return IRQ_NONE;
- }
-
- /* clear interrupt */
- outb(0x00, dev->iobase + DAS16_STATUS);
- das16_interrupt(dev);
- return IRQ_HANDLED;
-}
-
-static void das16_timer_interrupt(unsigned long arg)
-{
- struct comedi_device *dev = (struct comedi_device *)arg;
-
- das16_interrupt(dev);
-
- if (devpriv->timer_running)
- mod_timer(&devpriv->timer, jiffies + timer_period());
-}
-
/* the pc104-das16jr (at least) has problems if the dma
transfer is interrupted in the middle of transferring
a 16 bit sample, so this function takes care to get
@@ -1309,18 +967,32 @@ static void das16_interrupt(struct comedi_device *dev)
cfc_handle_events(dev, s);
}
-static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns,
- int rounding_flags)
+static irqreturn_t das16_dma_interrupt(int irq, void *d)
{
- i8253_cascade_ns_to_timer_2div(devpriv->clockbase, &(devpriv->divisor1),
- &(devpriv->divisor2), &ns,
- rounding_flags & TRIG_ROUND_MASK);
+ int status;
+ struct comedi_device *dev = d;
- /* Write the values of ctr1 and ctr2 into counters 1 and 2 */
- i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 1, devpriv->divisor1, 2);
- i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 2, devpriv->divisor2, 2);
+ status = inb(dev->iobase + DAS16_STATUS);
- return ns;
+ if ((status & DAS16_INT) == 0) {
+ DEBUG_PRINT("spurious interrupt\n");
+ return IRQ_NONE;
+ }
+
+ /* clear interrupt */
+ outb(0x00, dev->iobase + DAS16_STATUS);
+ das16_interrupt(dev);
+ return IRQ_HANDLED;
+}
+
+static void das16_timer_interrupt(unsigned long arg)
+{
+ struct comedi_device *dev = (struct comedi_device *)arg;
+
+ das16_interrupt(dev);
+
+ if (devpriv->timer_running)
+ mod_timer(&devpriv->timer, jiffies + timer_period());
}
static void reg_dump(struct comedi_device *dev)
@@ -1394,6 +1066,22 @@ static int das1600_mode_detect(struct comedi_device *dev)
return 0;
}
+static void das16_ai_munge(struct comedi_device *dev,
+ struct comedi_subdevice *s, void *array,
+ unsigned int num_bytes,
+ unsigned int start_chan_index)
+{
+ unsigned int i, num_samples = num_bytes / sizeof(short);
+ short *data = array;
+
+ for (i = 0; i < num_samples; i++) {
+ data[i] = le16_to_cpu(data[i]);
+ if (thisboard->ai_nbits == 12)
+ data[i] = (data[i] >> 4) & 0xfff;
+
+ }
+}
+
/*
*
* Options list:
@@ -1402,7 +1090,6 @@ static int das1600_mode_detect(struct comedi_device *dev)
* 2 DMA
* 3 Clock speed (in MHz)
*/
-
static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct comedi_subdevice *s;
@@ -1675,15 +1362,11 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int das16_detach(struct comedi_device *dev)
+static void das16_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: das16: remove\n", dev->minor);
-
das16_reset(dev);
-
if (dev->subdevices)
subdev_8255_cleanup(dev, dev->subdevices + 4);
-
if (devpriv) {
int i;
for (i = 0; i < 2; i++) {
@@ -1698,10 +1381,8 @@ static int das16_detach(struct comedi_device *dev)
kfree(devpriv->user_ai_range_table);
kfree(devpriv->user_ao_range_table);
}
-
if (dev->irq)
free_irq(dev->irq, dev);
-
if (dev->iobase) {
if (thisboard->size < 0x400) {
release_region(dev->iobase, thisboard->size);
@@ -1711,80 +1392,318 @@ static int das16_detach(struct comedi_device *dev)
thisboard->size & 0x3ff);
}
}
-
- return 0;
}
-static int __init driver_das16_init_module(void)
-{
- return comedi_driver_register(&driver_das16);
-}
-
-static void __exit driver_das16_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_das16);
-}
-
-module_init(driver_das16_init_module);
-module_exit(driver_das16_cleanup_module);
-
-/* utility function that suggests a dma transfer size in bytes */
-static unsigned int das16_suggest_transfer_size(struct comedi_device *dev,
- struct comedi_cmd cmd)
-{
- unsigned int size;
- unsigned int freq;
-
- /* if we are using timer interrupt, we don't care how long it
- * will take to complete transfer since it will be interrupted
- * by timer interrupt */
- if (devpriv->timer_mode)
- return DAS16_DMA_SIZE;
-
- /* otherwise, we are relying on dma terminal count interrupt,
- * so pick a reasonable size */
- if (cmd.convert_src == TRIG_TIMER)
- freq = 1000000000 / cmd.convert_arg;
- else if (cmd.scan_begin_src == TRIG_TIMER)
- freq = (1000000000 / cmd.scan_begin_arg) * cmd.chanlist_len;
- /* return some default value */
- else
- freq = 0xffffffff;
-
- if (cmd.flags & TRIG_WAKE_EOS) {
- size = sample_size * cmd.chanlist_len;
- } else {
- /* make buffer fill in no more than 1/3 second */
- size = (freq / 3) * sample_size;
- }
-
- /* set a minimum and maximum size allowed */
- if (size > DAS16_DMA_SIZE)
- size = DAS16_DMA_SIZE - DAS16_DMA_SIZE % sample_size;
- else if (size < sample_size)
- size = sample_size;
-
- if (cmd.stop_src == TRIG_COUNT && size > devpriv->adc_byte_count)
- size = devpriv->adc_byte_count;
-
- return size;
-}
-
-static void das16_ai_munge(struct comedi_device *dev,
- struct comedi_subdevice *s, void *array,
- unsigned int num_bytes,
- unsigned int start_chan_index)
-{
- unsigned int i, num_samples = num_bytes / sizeof(short);
- short *data = array;
-
- for (i = 0; i < num_samples; i++) {
- data[i] = le16_to_cpu(data[i]);
- if (thisboard->ai_nbits == 12)
- data[i] = (data[i] >> 4) & 0xfff;
+static const struct das16_board das16_boards[] = {
+ {
+ .name = "das-16",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 15000,
+ .ai_pg = das16_pg_none,
+ .ao = das16_ao_winsn,
+ .ao_nbits = 12,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x10,
+ .i8254_offset = 0x0c,
+ .size = 0x14,
+ .id = 0x00,
+ }, {
+ .name = "das-16g",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 15000,
+ .ai_pg = das16_pg_none,
+ .ao = das16_ao_winsn,
+ .ao_nbits = 12,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x10,
+ .i8254_offset = 0x0c,
+ .size = 0x14,
+ .id = 0x00,
+ }, {
+ .name = "das-16f",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 8500,
+ .ai_pg = das16_pg_none,
+ .ao = das16_ao_winsn,
+ .ao_nbits = 12,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x10,
+ .i8254_offset = 0x0c,
+ .size = 0x14,
+ .id = 0x00,
+ }, {
+ .name = "cio-das16",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 20000,
+ .ai_pg = das16_pg_none,
+ .ao = das16_ao_winsn,
+ .ao_nbits = 12,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x10,
+ .i8254_offset = 0x0c,
+ .size = 0x14,
+ .id = 0x80,
+ }, {
+ .name = "cio-das16/f",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_none,
+ .ao = das16_ao_winsn,
+ .ao_nbits = 12,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x10,
+ .i8254_offset = 0x0c,
+ .size = 0x14,
+ .id = 0x80,
+ }, {
+ .name = "cio-das16/jr",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 7692,
+ .ai_pg = das16_pg_16jr,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0,
+ .i8254_offset = 0x0c,
+ .size = 0x10,
+ .id = 0x00,
+ }, {
+ .name = "pc104-das16jr",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 3300,
+ .ai_pg = das16_pg_16jr,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0,
+ .i8254_offset = 0x0c,
+ .size = 0x10,
+ .id = 0x00,
+ }, {
+ .name = "cio-das16jr/16",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 16,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_16jr_16,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0,
+ .i8254_offset = 0x0c,
+ .size = 0x10,
+ .id = 0x00,
+ }, {
+ .name = "pc104-das16jr/16",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 16,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_16jr_16,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0,
+ .i8254_offset = 0x0c,
+ .size = 0x10,
+ .id = 0x00,
+ }, {
+ .name = "das-1201",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 20000,
+ .ai_pg = das16_pg_none,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x400,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0x20,
+ }, {
+ .name = "das-1202",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_none,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x400,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0x20,
+ }, {
+ .name = "das-1401",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_1601,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x0,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "das-1402",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_1602,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x0,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "das-1601",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_1601,
+ .ao = das16_ao_winsn,
+ .ao_nbits = 12,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x400,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "das-1602",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_1602,
+ .ao = das16_ao_winsn,
+ .ao_nbits = 12,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x400,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "cio-das1401/12",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 6250,
+ .ai_pg = das16_pg_1601,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "cio-das1402/12",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 6250,
+ .ai_pg = das16_pg_1602,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "cio-das1402/16",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 16,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_1602,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "cio-das1601/12",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 6250,
+ .ai_pg = das16_pg_1601,
+ .ao = das16_ao_winsn,
+ .ao_nbits = 12,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x400,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "cio-das1602/12",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_1602,
+ .ao = das16_ao_winsn,
+ .ao_nbits = 12,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x400,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "cio-das1602/16",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 16,
+ .ai_speed = 10000,
+ .ai_pg = das16_pg_1602,
+ .ao = das16_ao_winsn,
+ .ao_nbits = 12,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0x400,
+ .i8254_offset = 0x0c,
+ .size = 0x408,
+ .id = 0xc0,
+ }, {
+ .name = "cio-das16/330",
+ .ai = das16_ai_rinsn,
+ .ai_nbits = 12,
+ .ai_speed = 3030,
+ .ai_pg = das16_pg_16jr,
+ .ao = NULL,
+ .di = das16_di_rbits,
+ .do_ = das16_do_wbits,
+ .i8255_offset = 0,
+ .i8254_offset = 0x0c,
+ .size = 0x14,
+ .id = 0xf0,
+ },
+};
- }
-}
+static struct comedi_driver das16_driver = {
+ .driver_name = "das16",
+ .module = THIS_MODULE,
+ .attach = das16_attach,
+ .detach = das16_detach,
+ .board_name = &das16_boards[0].name,
+ .num_names = ARRAY_SIZE(das16_boards),
+ .offset = sizeof(das16_boards[0]),
+};
+module_comedi_driver(das16_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c
index 5376e718e3d7..d2e1490cd808 100644
--- a/drivers/staging/comedi/drivers/das16m1.c
+++ b/drivers/staging/comedi/drivers/das16m1.c
@@ -132,57 +132,11 @@ static const struct comedi_lrange range_das16m1 = { 9,
}
};
-static int das16m1_do_wbits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int das16m1_di_rbits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int das16m1_ai_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int das16m1_cmd_test(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_cmd *cmd);
-static int das16m1_cmd_exec(struct comedi_device *dev,
- struct comedi_subdevice *s);
-static int das16m1_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s);
-
-static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s);
-static irqreturn_t das16m1_interrupt(int irq, void *d);
-static void das16m1_handler(struct comedi_device *dev, unsigned int status);
-
-static unsigned int das16m1_set_pacer(struct comedi_device *dev,
- unsigned int ns, int round_flag);
-
-static int das16m1_irq_bits(unsigned int irq);
-
struct das16m1_board {
const char *name;
unsigned int ai_speed;
};
-static const struct das16m1_board das16m1_boards[] = {
- {
- .name = "cio-das16/m1", /* CIO-DAS16_M1.pdf */
- .ai_speed = 1000, /* 1MHz max speed */
- },
-};
-
-static int das16m1_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int das16m1_detach(struct comedi_device *dev);
-static struct comedi_driver driver_das16m1 = {
- .driver_name = "das16m1",
- .module = THIS_MODULE,
- .attach = das16m1_attach,
- .detach = das16m1_detach,
- .board_name = &das16m1_boards[0].name,
- .num_names = ARRAY_SIZE(das16m1_boards),
- .offset = sizeof(das16m1_boards[0]),
-};
-
struct das16m1_private_struct {
unsigned int control_state;
volatile unsigned int adc_count; /* number of samples completed */
@@ -198,22 +152,17 @@ struct das16m1_private_struct {
#define devpriv ((struct das16m1_private_struct *)(dev->private))
#define thisboard ((const struct das16m1_board *)(dev->board_ptr))
-static int __init driver_das16m1_init_module(void)
+static inline short munge_sample(short data)
{
- return comedi_driver_register(&driver_das16m1);
+ return (data >> 4) & 0xfff;
}
-static void __exit driver_das16m1_cleanup_module(void)
+static void munge_sample_array(short *array, unsigned int num_elements)
{
- comedi_driver_unregister(&driver_das16m1);
-}
-
-module_init(driver_das16m1_init_module);
-module_exit(driver_das16m1_cleanup_module);
+ unsigned int i;
-static inline short munge_sample(short data)
-{
- return (data >> 4) & 0xfff;
+ for (i = 0; i < num_elements; i++)
+ array[i] = munge_sample(array[i]);
}
static int das16m1_cmd_test(struct comedi_device *dev,
@@ -340,6 +289,25 @@ static int das16m1_cmd_test(struct comedi_device *dev,
return 0;
}
+/* This function takes a time in nanoseconds and sets the *
+ * 2 pacer clocks to the closest frequency possible. It also *
+ * returns the actual sampling period. */
+static unsigned int das16m1_set_pacer(struct comedi_device *dev,
+ unsigned int ns, int rounding_flags)
+{
+ i8253_cascade_ns_to_timer_2div(DAS16M1_XTAL, &(devpriv->divisor1),
+ &(devpriv->divisor2), &ns,
+ rounding_flags & TRIG_ROUND_MASK);
+
+ /* Write the values of ctr1 and ctr2 into counters 1 and 2 */
+ i8254_load(dev->iobase + DAS16M1_8254_SECOND, 0, 1, devpriv->divisor1,
+ 2);
+ i8254_load(dev->iobase + DAS16M1_8254_SECOND, 0, 2, devpriv->divisor2,
+ 2);
+
+ return ns;
+}
+
static int das16m1_cmd_exec(struct comedi_device *dev,
struct comedi_subdevice *s)
{
@@ -484,57 +452,6 @@ static int das16m1_do_wbits(struct comedi_device *dev,
return 2;
}
-static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s)
-{
- unsigned long flags;
- unsigned int status;
-
- /* prevent race with interrupt handler */
- spin_lock_irqsave(&dev->spinlock, flags);
- status = inb(dev->iobase + DAS16M1_CS);
- das16m1_handler(dev, status);
- spin_unlock_irqrestore(&dev->spinlock, flags);
-
- return s->async->buf_write_count - s->async->buf_read_count;
-}
-
-static irqreturn_t das16m1_interrupt(int irq, void *d)
-{
- int status;
- struct comedi_device *dev = d;
-
- if (dev->attached == 0) {
- comedi_error(dev, "premature interrupt");
- return IRQ_HANDLED;
- }
- /* prevent race with comedi_poll() */
- spin_lock(&dev->spinlock);
-
- status = inb(dev->iobase + DAS16M1_CS);
-
- if ((status & (IRQDATA | OVRUN)) == 0) {
- comedi_error(dev, "spurious interrupt");
- spin_unlock(&dev->spinlock);
- return IRQ_NONE;
- }
-
- das16m1_handler(dev, status);
-
- /* clear interrupt */
- outb(0, dev->iobase + DAS16M1_CLEAR_INTR);
-
- spin_unlock(&dev->spinlock);
- return IRQ_HANDLED;
-}
-
-static void munge_sample_array(short *array, unsigned int num_elements)
-{
- unsigned int i;
-
- for (i = 0; i < num_elements; i++)
- array[i] = munge_sample(array[i]);
-}
-
static void das16m1_handler(struct comedi_device *dev, unsigned int status)
{
struct comedi_subdevice *s;
@@ -596,23 +513,47 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status)
}
-/* This function takes a time in nanoseconds and sets the *
- * 2 pacer clocks to the closest frequency possible. It also *
- * returns the actual sampling period. */
-static unsigned int das16m1_set_pacer(struct comedi_device *dev,
- unsigned int ns, int rounding_flags)
+static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s)
{
- i8253_cascade_ns_to_timer_2div(DAS16M1_XTAL, &(devpriv->divisor1),
- &(devpriv->divisor2), &ns,
- rounding_flags & TRIG_ROUND_MASK);
+ unsigned long flags;
+ unsigned int status;
- /* Write the values of ctr1 and ctr2 into counters 1 and 2 */
- i8254_load(dev->iobase + DAS16M1_8254_SECOND, 0, 1, devpriv->divisor1,
- 2);
- i8254_load(dev->iobase + DAS16M1_8254_SECOND, 0, 2, devpriv->divisor2,
- 2);
+ /* prevent race with interrupt handler */
+ spin_lock_irqsave(&dev->spinlock, flags);
+ status = inb(dev->iobase + DAS16M1_CS);
+ das16m1_handler(dev, status);
+ spin_unlock_irqrestore(&dev->spinlock, flags);
- return ns;
+ return s->async->buf_write_count - s->async->buf_read_count;
+}
+
+static irqreturn_t das16m1_interrupt(int irq, void *d)
+{
+ int status;
+ struct comedi_device *dev = d;
+
+ if (dev->attached == 0) {
+ comedi_error(dev, "premature interrupt");
+ return IRQ_HANDLED;
+ }
+ /* prevent race with comedi_poll() */
+ spin_lock(&dev->spinlock);
+
+ status = inb(dev->iobase + DAS16M1_CS);
+
+ if ((status & (IRQDATA | OVRUN)) == 0) {
+ comedi_error(dev, "spurious interrupt");
+ spin_unlock(&dev->spinlock);
+ return IRQ_NONE;
+ }
+
+ das16m1_handler(dev, status);
+
+ /* clear interrupt */
+ outb(0, dev->iobase + DAS16M1_CLEAR_INTR);
+
+ spin_unlock(&dev->spinlock);
+ return IRQ_HANDLED;
}
static int das16m1_irq_bits(unsigned int irq)
@@ -656,7 +597,6 @@ static int das16m1_irq_bits(unsigned int irq)
* 0 I/O base
* 1 IRQ
*/
-
static int das16m1_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
@@ -673,12 +613,12 @@ static int das16m1_attach(struct comedi_device *dev,
dev->board_name = thisboard->name;
- if (!request_region(iobase, DAS16M1_SIZE, driver_das16m1.driver_name)) {
+ if (!request_region(iobase, DAS16M1_SIZE, dev->driver->driver_name)) {
comedi_error(dev, "I/O port conflict\n");
return -EIO;
}
if (!request_region(iobase + DAS16M1_82C55, DAS16M1_SIZE2,
- driver_das16m1.driver_name)) {
+ dev->driver->driver_name)) {
release_region(iobase, DAS16M1_SIZE);
comedi_error(dev, "I/O port conflict\n");
return -EIO;
@@ -690,7 +630,7 @@ static int das16m1_attach(struct comedi_device *dev,
/* make sure it is valid */
if (das16m1_irq_bits(irq) >= 0) {
ret = request_irq(irq, das16m1_interrupt, 0,
- driver_das16m1.driver_name, dev);
+ dev->driver->driver_name, dev);
if (ret < 0)
return ret;
dev->irq = irq;
@@ -763,25 +703,36 @@ static int das16m1_attach(struct comedi_device *dev,
return 0;
}
-static int das16m1_detach(struct comedi_device *dev)
+static void das16m1_detach(struct comedi_device *dev)
{
-
-/* das16m1_reset(dev); */
-
if (dev->subdevices)
subdev_8255_cleanup(dev, dev->subdevices + 3);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
if (dev->iobase) {
release_region(dev->iobase, DAS16M1_SIZE);
release_region(dev->iobase + DAS16M1_82C55, DAS16M1_SIZE2);
}
-
- return 0;
}
+static const struct das16m1_board das16m1_boards[] = {
+ {
+ .name = "cio-das16/m1", /* CIO-DAS16_M1.pdf */
+ .ai_speed = 1000, /* 1MHz max speed */
+ },
+};
+
+static struct comedi_driver das16m1_driver = {
+ .driver_name = "das16m1",
+ .module = THIS_MODULE,
+ .attach = das16m1_attach,
+ .detach = das16m1_detach,
+ .board_name = &das16m1_boards[0].name,
+ .num_names = ARRAY_SIZE(das16m1_boards),
+ .offset = sizeof(das16m1_boards[0]),
+};
+module_comedi_driver(das16m1_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c
index 99ada5a53b9e..2ac344354c1d 100644
--- a/drivers/staging/comedi/drivers/das1800.c
+++ b/drivers/staging/comedi/drivers/das1800.c
@@ -183,9 +183,6 @@ enum {
das1802hr, das1802hr_da, das1801hc, das1802hc, das1801ao, das1802ao
};
-static int das1800_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int das1800_detach(struct comedi_device *dev);
static int das1800_probe(struct comedi_device *dev);
static int das1800_cancel(struct comedi_device *dev,
struct comedi_subdevice *s);
@@ -518,33 +515,6 @@ static const struct comedi_lrange range_ao_2 = {
};
*/
-static struct comedi_driver driver_das1800 = {
- .driver_name = "das1800",
- .module = THIS_MODULE,
- .attach = das1800_attach,
- .detach = das1800_detach,
- .num_names = ARRAY_SIZE(das1800_boards),
- .board_name = &das1800_boards[0].name,
- .offset = sizeof(struct das1800_board),
-};
-
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __init driver_das1800_init_module(void)
-{
- return comedi_driver_register(&driver_das1800);
-}
-
-static void __exit driver_das1800_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_das1800);
-}
-
-module_init(driver_das1800_init_module);
-module_exit(driver_das1800_cleanup_module);
-
static int das1800_init_dma(struct comedi_device *dev, unsigned int dma0,
unsigned int dma1)
{
@@ -579,7 +549,7 @@ static int das1800_init_dma(struct comedi_device *dev, unsigned int dma0,
return -EINVAL;
break;
}
- if (request_dma(dma0, driver_das1800.driver_name)) {
+ if (request_dma(dma0, dev->driver->driver_name)) {
dev_err(dev->hw_dev, "failed to allocate dma channel %i\n",
dma0);
return -EINVAL;
@@ -587,7 +557,7 @@ static int das1800_init_dma(struct comedi_device *dev, unsigned int dma0,
devpriv->dma0 = dma0;
devpriv->dma_current = dma0;
if (dma1) {
- if (request_dma(dma1, driver_das1800.driver_name)) {
+ if (request_dma(dma1, dev->driver->driver_name)) {
dev_err(dev->hw_dev, "failed to allocate dma channel %i\n",
dma1);
return -EINVAL;
@@ -633,7 +603,7 @@ static int das1800_attach(struct comedi_device *dev,
return -ENOMEM;
printk(KERN_DEBUG "comedi%d: %s: io 0x%lx", dev->minor,
- driver_das1800.driver_name, iobase);
+ dev->driver->driver_name, iobase);
if (irq) {
printk(KERN_CONT ", irq %u", irq);
if (dma0) {
@@ -650,7 +620,7 @@ static int das1800_attach(struct comedi_device *dev,
}
/* check if io addresses are available */
- if (!request_region(iobase, DAS1800_SIZE, driver_das1800.driver_name)) {
+ if (!request_region(iobase, DAS1800_SIZE, dev->driver->driver_name)) {
printk
(" I/O port conflict: failed to allocate ports 0x%lx to 0x%lx\n",
iobase, iobase + DAS1800_SIZE - 1);
@@ -671,7 +641,7 @@ static int das1800_attach(struct comedi_device *dev,
if (thisboard->ao_ability == 2) {
iobase2 = iobase + IOBASE2;
if (!request_region(iobase2, DAS1800_SIZE,
- driver_das1800.driver_name)) {
+ dev->driver->driver_name)) {
printk
(" I/O port conflict: failed to allocate ports 0x%lx to 0x%lx\n",
iobase2, iobase2 + DAS1800_SIZE - 1);
@@ -683,7 +653,7 @@ static int das1800_attach(struct comedi_device *dev,
/* grab our IRQ */
if (irq) {
if (request_irq(irq, das1800_interrupt, 0,
- driver_das1800.driver_name, dev)) {
+ dev->driver->driver_name, dev)) {
dev_dbg(dev->hw_dev, "unable to allocate irq %u\n",
irq);
return -EINVAL;
@@ -797,9 +767,8 @@ static int das1800_attach(struct comedi_device *dev,
return 0;
};
-static int das1800_detach(struct comedi_device *dev)
+static void das1800_detach(struct comedi_device *dev)
{
- /* only free stuff if it has been allocated by _attach */
if (dev->iobase)
release_region(dev->iobase, DAS1800_SIZE);
if (dev->irq)
@@ -814,11 +783,6 @@ static int das1800_detach(struct comedi_device *dev)
kfree(devpriv->ai_buf0);
kfree(devpriv->ai_buf1);
}
-
- dev_dbg(dev->hw_dev, "comedi%d: %s: remove\n", dev->minor,
- driver_das1800.driver_name);
-
- return 0;
};
/* probes and checks das-1800 series board type
@@ -1811,6 +1775,17 @@ static unsigned int suggest_transfer_size(struct comedi_cmd *cmd)
return size;
}
+static struct comedi_driver das1800_driver = {
+ .driver_name = "das1800",
+ .module = THIS_MODULE,
+ .attach = das1800_attach,
+ .detach = das1800_detach,
+ .num_names = ARRAY_SIZE(das1800_boards),
+ .board_name = &das1800_boards[0].name,
+ .offset = sizeof(struct das1800_board),
+};
+module_comedi_driver(das1800_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c
index f25684145e84..881f392d1dba 100644
--- a/drivers/staging/comedi/drivers/das6402.c
+++ b/drivers/staging/comedi/drivers/das6402.c
@@ -99,29 +99,6 @@ This driver has suffered bitrot.
#define C2 0x80
#define RWLH 0x30
-static int das6402_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int das6402_detach(struct comedi_device *dev);
-static struct comedi_driver driver_das6402 = {
- .driver_name = "das6402",
- .module = THIS_MODULE,
- .attach = das6402_attach,
- .detach = das6402_detach,
-};
-
-static int __init driver_das6402_init_module(void)
-{
- return comedi_driver_register(&driver_das6402);
-}
-
-static void __exit driver_das6402_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_das6402);
-}
-
-module_init(driver_das6402_init_module);
-module_exit(driver_das6402_cleanup_module);
-
struct das6402_private {
int ai_bytes_to_read;
@@ -130,7 +107,14 @@ struct das6402_private {
#define devpriv ((struct das6402_private *)dev->private)
static void das6402_ai_fifo_dregs(struct comedi_device *dev,
- struct comedi_subdevice *s);
+ struct comedi_subdevice *s)
+{
+ while (1) {
+ if (!(inb(dev->iobase + 8) & 0x01))
+ return;
+ comedi_buf_put(s->async, inw(dev->iobase));
+ }
+}
static void das6402_setcounter(struct comedi_device *dev)
{
@@ -209,16 +193,6 @@ static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n)
}
#endif
-static void das6402_ai_fifo_dregs(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- while (1) {
- if (!(inb(dev->iobase + 8) & 0x01))
- return;
- comedi_buf_put(s->async, inw(dev->iobase));
- }
-}
-
static int das6402_ai_cancel(struct comedi_device *dev,
struct comedi_subdevice *s)
{
@@ -300,16 +274,6 @@ static int board_init(struct comedi_device *dev)
return 0;
}
-static int das6402_detach(struct comedi_device *dev)
-{
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->iobase)
- release_region(dev->iobase, DAS6402_SIZE);
-
- return 0;
-}
-
static int das6402_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
@@ -363,6 +327,22 @@ static int das6402_attach(struct comedi_device *dev,
return 0;
}
+static void das6402_detach(struct comedi_device *dev)
+{
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+ if (dev->iobase)
+ release_region(dev->iobase, DAS6402_SIZE);
+}
+
+static struct comedi_driver das6402_driver = {
+ .driver_name = "das6402",
+ .module = THIS_MODULE,
+ .attach = das6402_attach,
+ .detach = das6402_detach,
+};
+module_comedi_driver(das6402_driver)
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c
index 6e347b40fe61..a3a54e1c5c98 100644
--- a/drivers/staging/comedi/drivers/das800.c
+++ b/drivers/staging/comedi/drivers/das800.c
@@ -245,7 +245,7 @@ struct das800_private {
static int das800_attach(struct comedi_device *dev,
struct comedi_devconfig *it);
-static int das800_detach(struct comedi_device *dev);
+static void das800_detach(struct comedi_device *dev);
static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
static struct comedi_driver driver_das800 = {
@@ -556,16 +556,12 @@ static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
};
-static int das800_detach(struct comedi_device *dev)
+static void das800_detach(struct comedi_device *dev)
{
- dev_info(dev->hw_dev, "comedi%d: das800: remove\n", dev->minor);
-
- /* only free stuff if it has been allocated by _attach */
if (dev->iobase)
release_region(dev->iobase, DAS800_SIZE);
if (dev->irq)
free_irq(dev->irq, dev);
- return 0;
};
static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c
index 2b4e6e6eb825..83828903db4b 100644
--- a/drivers/staging/comedi/drivers/dmm32at.c
+++ b/drivers/staging/comedi/drivers/dmm32at.c
@@ -224,7 +224,7 @@ struct dmm32at_private {
*/
static int dmm32at_attach(struct comedi_device *dev,
struct comedi_devconfig *it);
-static int dmm32at_detach(struct comedi_device *dev);
+static void dmm32at_detach(struct comedi_device *dev);
static struct comedi_driver driver_dmm32at = {
.driver_name = "dmm32at",
.module = THIS_MODULE,
@@ -450,23 +450,12 @@ static int dmm32at_attach(struct comedi_device *dev,
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int dmm32at_detach(struct comedi_device *dev)
+static void dmm32at_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: dmm32at: remove\n", dev->minor);
if (dev->irq)
free_irq(dev->irq, dev);
if (dev->iobase)
release_region(dev->iobase, DMM32AT_MEMSIZE);
-
- return 0;
}
/*
diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c
index b85c8366a396..625bd617a8e9 100644
--- a/drivers/staging/comedi/drivers/dt2801.c
+++ b/drivers/staging/comedi/drivers/dt2801.c
@@ -88,29 +88,6 @@ Configuration options:
#define DT2801_STATUS 1
#define DT2801_CMD 1
-static int dt2801_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int dt2801_detach(struct comedi_device *dev);
-static struct comedi_driver driver_dt2801 = {
- .driver_name = "dt2801",
- .module = THIS_MODULE,
- .attach = dt2801_attach,
- .detach = dt2801_detach,
-};
-
-static int __init driver_dt2801_init_module(void)
-{
- return comedi_driver_register(&driver_dt2801);
-}
-
-static void __exit driver_dt2801_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_dt2801);
-}
-
-module_init(driver_dt2801_init_module);
-module_exit(driver_dt2801_cleanup_module);
-
#if 0
/* ignore 'defined but not used' warning */
static const struct comedi_lrange range_dt2801_ai_pgh_bipolar = { 4, {
@@ -258,22 +235,6 @@ struct dt2801_private {
#define devpriv ((struct dt2801_private *)dev->private)
-static int dt2801_ai_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int dt2801_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int dt2801_ao_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int dt2801_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int dt2801_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
/* These are the low-level routines:
writecommand: write a command to the board
writedata: write data byte
@@ -503,6 +464,123 @@ static const struct comedi_lrange *ai_range_lkup(int type, int opt)
return &range_unknown;
}
+static int dt2801_error(struct comedi_device *dev, int stat)
+{
+ if (stat < 0) {
+ if (stat == -ETIME)
+ printk("dt2801: timeout\n");
+ else
+ printk("dt2801: error %d\n", stat);
+ return stat;
+ }
+ printk("dt2801: error status 0x%02x, resetting...\n", stat);
+
+ dt2801_reset(dev);
+ dt2801_reset(dev);
+
+ return -EIO;
+}
+
+static int dt2801_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ int d;
+ int stat;
+ int i;
+
+ for (i = 0; i < insn->n; i++) {
+ stat = dt2801_writecmd(dev, DT_C_READ_ADIM);
+ dt2801_writedata(dev, CR_RANGE(insn->chanspec));
+ dt2801_writedata(dev, CR_CHAN(insn->chanspec));
+ stat = dt2801_readdata2(dev, &d);
+
+ if (stat != 0)
+ return dt2801_error(dev, stat);
+
+ data[i] = d;
+ }
+
+ return i;
+}
+
+static int dt2801_ao_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ data[0] = devpriv->ao_readback[CR_CHAN(insn->chanspec)];
+
+ return 1;
+}
+
+static int dt2801_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ dt2801_writecmd(dev, DT_C_WRITE_DAIM);
+ dt2801_writedata(dev, CR_CHAN(insn->chanspec));
+ dt2801_writedata2(dev, data[0]);
+
+ devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[0];
+
+ return 1;
+}
+
+static int dt2801_dio_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ int which = 0;
+
+ if (s == dev->subdevices + 4)
+ which = 1;
+
+ if (insn->n != 2)
+ return -EINVAL;
+ if (data[0]) {
+ s->state &= ~data[0];
+ s->state |= (data[0] & data[1]);
+ dt2801_writecmd(dev, DT_C_WRITE_DIG);
+ dt2801_writedata(dev, which);
+ dt2801_writedata(dev, s->state);
+ }
+ dt2801_writecmd(dev, DT_C_READ_DIG);
+ dt2801_writedata(dev, which);
+ dt2801_readdata(dev, data + 1);
+
+ return 2;
+}
+
+static int dt2801_dio_insn_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ int which = 0;
+
+ if (s == dev->subdevices + 4)
+ which = 1;
+
+ /* configure */
+ switch (data[0]) {
+ case INSN_CONFIG_DIO_OUTPUT:
+ s->io_bits = 0xff;
+ dt2801_writecmd(dev, DT_C_SET_DIGOUT);
+ break;
+ case INSN_CONFIG_DIO_INPUT:
+ s->io_bits = 0;
+ dt2801_writecmd(dev, DT_C_SET_DIGIN);
+ break;
+ case INSN_CONFIG_DIO_QUERY:
+ data[1] = s->io_bits ? COMEDI_OUTPUT : COMEDI_INPUT;
+ return insn->n;
+ default:
+ return -EINVAL;
+ }
+ dt2801_writedata(dev, which);
+
+ return 1;
+}
+
/*
options:
[0] - i/o base
@@ -615,130 +693,19 @@ out:
return ret;
}
-static int dt2801_detach(struct comedi_device *dev)
+static void dt2801_detach(struct comedi_device *dev)
{
if (dev->iobase)
release_region(dev->iobase, DT2801_IOSIZE);
-
- return 0;
-}
-
-static int dt2801_error(struct comedi_device *dev, int stat)
-{
- if (stat < 0) {
- if (stat == -ETIME)
- printk("dt2801: timeout\n");
- else
- printk("dt2801: error %d\n", stat);
- return stat;
- }
- printk("dt2801: error status 0x%02x, resetting...\n", stat);
-
- dt2801_reset(dev);
- dt2801_reset(dev);
-
- return -EIO;
-}
-
-static int dt2801_ai_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- int d;
- int stat;
- int i;
-
- for (i = 0; i < insn->n; i++) {
- stat = dt2801_writecmd(dev, DT_C_READ_ADIM);
- dt2801_writedata(dev, CR_RANGE(insn->chanspec));
- dt2801_writedata(dev, CR_CHAN(insn->chanspec));
- stat = dt2801_readdata2(dev, &d);
-
- if (stat != 0)
- return dt2801_error(dev, stat);
-
- data[i] = d;
- }
-
- return i;
-}
-
-static int dt2801_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- data[0] = devpriv->ao_readback[CR_CHAN(insn->chanspec)];
-
- return 1;
-}
-
-static int dt2801_ao_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- dt2801_writecmd(dev, DT_C_WRITE_DAIM);
- dt2801_writedata(dev, CR_CHAN(insn->chanspec));
- dt2801_writedata2(dev, data[0]);
-
- devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[0];
-
- return 1;
-}
-
-static int dt2801_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- int which = 0;
-
- if (s == dev->subdevices + 4)
- which = 1;
-
- if (insn->n != 2)
- return -EINVAL;
- if (data[0]) {
- s->state &= ~data[0];
- s->state |= (data[0] & data[1]);
- dt2801_writecmd(dev, DT_C_WRITE_DIG);
- dt2801_writedata(dev, which);
- dt2801_writedata(dev, s->state);
- }
- dt2801_writecmd(dev, DT_C_READ_DIG);
- dt2801_writedata(dev, which);
- dt2801_readdata(dev, data + 1);
-
- return 2;
}
-static int dt2801_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- int which = 0;
-
- if (s == dev->subdevices + 4)
- which = 1;
-
- /* configure */
- switch (data[0]) {
- case INSN_CONFIG_DIO_OUTPUT:
- s->io_bits = 0xff;
- dt2801_writecmd(dev, DT_C_SET_DIGOUT);
- break;
- case INSN_CONFIG_DIO_INPUT:
- s->io_bits = 0;
- dt2801_writecmd(dev, DT_C_SET_DIGIN);
- break;
- case INSN_CONFIG_DIO_QUERY:
- data[1] = s->io_bits ? COMEDI_OUTPUT : COMEDI_INPUT;
- return insn->n;
- default:
- return -EINVAL;
- }
- dt2801_writedata(dev, which);
-
- return 1;
-}
+static struct comedi_driver dt2801_driver = {
+ .driver_name = "dt2801",
+ .module = THIS_MODULE,
+ .attach = dt2801_attach,
+ .detach = dt2801_detach,
+};
+module_comedi_driver(dt2801_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c
index 0131d5225b52..106ffea30b95 100644
--- a/drivers/staging/comedi/drivers/dt2811.c
+++ b/drivers/staging/comedi/drivers/dt2811.c
@@ -211,61 +211,8 @@ struct dt2811_board {
const struct comedi_lrange *unip_5;
};
-static const struct dt2811_board boardtypes[] = {
- {"dt2811-pgh",
- &range_dt2811_pgh_ai_5_bipolar,
- &range_dt2811_pgh_ai_2_5_bipolar,
- &range_dt2811_pgh_ai_5_unipolar,
- },
- {"dt2811-pgl",
- &range_dt2811_pgl_ai_5_bipolar,
- &range_dt2811_pgl_ai_2_5_bipolar,
- &range_dt2811_pgl_ai_5_unipolar,
- },
-};
-
#define this_board ((const struct dt2811_board *)dev->board_ptr)
-static int dt2811_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int dt2811_detach(struct comedi_device *dev);
-static struct comedi_driver driver_dt2811 = {
- .driver_name = "dt2811",
- .module = THIS_MODULE,
- .attach = dt2811_attach,
- .detach = dt2811_detach,
- .board_name = &boardtypes[0].name,
- .num_names = ARRAY_SIZE(boardtypes),
- .offset = sizeof(struct dt2811_board),
-};
-
-static int __init driver_dt2811_init_module(void)
-{
- return comedi_driver_register(&driver_dt2811);
-}
-
-static void __exit driver_dt2811_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_dt2811);
-}
-
-module_init(driver_dt2811_init_module);
-module_exit(driver_dt2811_cleanup_module);
-
-static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int dt2811_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int dt2811_di_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int dt2811_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
enum { card_2811_pgh, card_2811_pgl };
struct dt2811_private {
@@ -317,6 +264,120 @@ static irqreturn_t dt2811_interrupt(int irq, void *d)
}
#endif
+static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ int chan = CR_CHAN(insn->chanspec);
+ int timeout = DT2811_TIMEOUT;
+ int i;
+
+ for (i = 0; i < insn->n; i++) {
+ outb(chan, dev->iobase + DT2811_ADGCR);
+
+ while (timeout
+ && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY)
+ timeout--;
+ if (!timeout)
+ return -ETIME;
+
+ data[i] = inb(dev->iobase + DT2811_ADDATLO);
+ data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8;
+ data[i] &= 0xfff;
+ }
+
+ return i;
+}
+
+#if 0
+/* Wow. This is code from the Comedi stone age. But it hasn't been
+ * replaced, so I'll let it stay. */
+int dt2811_adtrig(kdev_t minor, comedi_adtrig *adtrig)
+{
+ struct comedi_device *dev = comedi_devices + minor;
+
+ if (adtrig->n < 1)
+ return 0;
+ dev->curadchan = adtrig->chan;
+ switch (dev->i_admode) {
+ case COMEDI_MDEMAND:
+ dev->ntrig = adtrig->n - 1;
+ /* not necessary */
+ /*printk("dt2811: AD soft trigger\n"); */
+ /*outb(DT2811_CLRERROR|DT2811_INTENB,
+ dev->iobase+DT2811_ADCSR); */
+ outb(dev->curadchan, dev->iobase + DT2811_ADGCR);
+ do_gettimeofday(&trigtime);
+ break;
+ case COMEDI_MCONTS:
+ dev->ntrig = adtrig->n;
+ break;
+ }
+
+ return 0;
+}
+#endif
+
+static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ int i;
+ int chan;
+
+ chan = CR_CHAN(insn->chanspec);
+
+ for (i = 0; i < insn->n; i++) {
+ outb(data[i] & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan);
+ outb((data[i] >> 8) & 0xff,
+ dev->iobase + DT2811_DADAT0HI + 2 * chan);
+ devpriv->ao_readback[chan] = data[i];
+ }
+
+ return i;
+}
+
+static int dt2811_ao_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ int i;
+ int chan;
+
+ chan = CR_CHAN(insn->chanspec);
+
+ for (i = 0; i < insn->n; i++)
+ data[i] = devpriv->ao_readback[chan];
+
+ return i;
+}
+
+static int dt2811_di_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ if (insn->n != 2)
+ return -EINVAL;
+
+ data[1] = inb(dev->iobase + DT2811_DIO);
+
+ return 2;
+}
+
+static int dt2811_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ if (insn->n != 2)
+ return -EINVAL;
+
+ s->state &= ~data[0];
+ s->state |= data[0] & data[1];
+ outb(s->state, dev->iobase + DT2811_DIO);
+
+ data[1] = s->state;
+
+ return 2;
+}
+
/*
options[0] Board base address
options[1] IRQ
@@ -337,7 +398,6 @@ static irqreturn_t dt2811_interrupt(int irq, void *d)
1 == bipolar 2.5V (-2.5V -- +2.5V)
2 == unipolar 5V (0V -- +5V)
*/
-
static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
/* int i, irq; */
@@ -511,131 +571,38 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int dt2811_detach(struct comedi_device *dev)
+static void dt2811_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: dt2811: remove\n", dev->minor);
-
if (dev->irq)
free_irq(dev->irq, dev);
if (dev->iobase)
release_region(dev->iobase, DT2811_SIZE);
-
- return 0;
-}
-
-static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- int chan = CR_CHAN(insn->chanspec);
- int timeout = DT2811_TIMEOUT;
- int i;
-
- for (i = 0; i < insn->n; i++) {
- outb(chan, dev->iobase + DT2811_ADGCR);
-
- while (timeout
- && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY)
- timeout--;
- if (!timeout)
- return -ETIME;
-
- data[i] = inb(dev->iobase + DT2811_ADDATLO);
- data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8;
- data[i] &= 0xfff;
- }
-
- return i;
}
-#if 0
-/* Wow. This is code from the Comedi stone age. But it hasn't been
- * replaced, so I'll let it stay. */
-int dt2811_adtrig(kdev_t minor, comedi_adtrig *adtrig)
-{
- struct comedi_device *dev = comedi_devices + minor;
-
- if (adtrig->n < 1)
- return 0;
- dev->curadchan = adtrig->chan;
- switch (dev->i_admode) {
- case COMEDI_MDEMAND:
- dev->ntrig = adtrig->n - 1;
- /* not necessary */
- /*printk("dt2811: AD soft trigger\n"); */
- /*outb(DT2811_CLRERROR|DT2811_INTENB,
- dev->iobase+DT2811_ADCSR); */
- outb(dev->curadchan, dev->iobase + DT2811_ADGCR);
- do_gettimeofday(&trigtime);
- break;
- case COMEDI_MCONTS:
- dev->ntrig = adtrig->n;
- break;
- }
-
- return 0;
-}
-#endif
-
-static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- int i;
- int chan;
-
- chan = CR_CHAN(insn->chanspec);
-
- for (i = 0; i < insn->n; i++) {
- outb(data[i] & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan);
- outb((data[i] >> 8) & 0xff,
- dev->iobase + DT2811_DADAT0HI + 2 * chan);
- devpriv->ao_readback[chan] = data[i];
- }
-
- return i;
-}
-
-static int dt2811_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- int i;
- int chan;
-
- chan = CR_CHAN(insn->chanspec);
-
- for (i = 0; i < insn->n; i++)
- data[i] = devpriv->ao_readback[chan];
-
- return i;
-}
-
-static int dt2811_di_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- if (insn->n != 2)
- return -EINVAL;
-
- data[1] = inb(dev->iobase + DT2811_DIO);
-
- return 2;
-}
-
-static int dt2811_do_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- if (insn->n != 2)
- return -EINVAL;
-
- s->state &= ~data[0];
- s->state |= data[0] & data[1];
- outb(s->state, dev->iobase + DT2811_DIO);
-
- data[1] = s->state;
+static const struct dt2811_board boardtypes[] = {
+ {
+ .name = "dt2811-pgh",
+ .bip_5 = &range_dt2811_pgh_ai_5_bipolar,
+ .bip_2_5 = &range_dt2811_pgh_ai_2_5_bipolar,
+ .unip_5 = &range_dt2811_pgh_ai_5_unipolar,
+ }, {
+ .name = "dt2811-pgl",
+ .bip_5 = &range_dt2811_pgl_ai_5_bipolar,
+ .bip_2_5 = &range_dt2811_pgl_ai_2_5_bipolar,
+ .unip_5 = &range_dt2811_pgl_ai_5_unipolar,
+ },
+};
- return 2;
-}
+static struct comedi_driver dt2811_driver = {
+ .driver_name = "dt2811",
+ .module = THIS_MODULE,
+ .attach = dt2811_attach,
+ .detach = dt2811_detach,
+ .board_name = &boardtypes[0].name,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .offset = sizeof(struct dt2811_board),
+};
+module_comedi_driver(dt2811_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/dt2814.c b/drivers/staging/comedi/drivers/dt2814.c
index 1c6248cf5928..fa4ade61be5f 100644
--- a/drivers/staging/comedi/drivers/dt2814.c
+++ b/drivers/staging/comedi/drivers/dt2814.c
@@ -60,31 +60,6 @@ addition, the clock does not seem to be very accurate.
#define DT2814_ENB 0x10
#define DT2814_CHANMASK 0x0f
-static int dt2814_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int dt2814_detach(struct comedi_device *dev);
-static struct comedi_driver driver_dt2814 = {
- .driver_name = "dt2814",
- .module = THIS_MODULE,
- .attach = dt2814_attach,
- .detach = dt2814_detach,
-};
-
-static int __init driver_dt2814_init_module(void)
-{
- return comedi_driver_register(&driver_dt2814);
-}
-
-static void __exit driver_dt2814_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_dt2814);
-}
-
-module_init(driver_dt2814_init_module);
-module_exit(driver_dt2814_cleanup_module);
-
-static irqreturn_t dt2814_interrupt(int irq, void *dev);
-
struct dt2814_private {
int ntrig;
@@ -260,6 +235,45 @@ static int dt2814_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
}
+static irqreturn_t dt2814_interrupt(int irq, void *d)
+{
+ int lo, hi;
+ struct comedi_device *dev = d;
+ struct comedi_subdevice *s;
+ int data;
+
+ if (!dev->attached) {
+ comedi_error(dev, "spurious interrupt");
+ return IRQ_HANDLED;
+ }
+
+ s = dev->subdevices + 0;
+
+ hi = inb(dev->iobase + DT2814_DATA);
+ lo = inb(dev->iobase + DT2814_DATA);
+
+ data = (hi << 4) | (lo >> 4);
+
+ if (!(--devpriv->ntrig)) {
+ int i;
+
+ outb(0, dev->iobase + DT2814_CSR);
+ /* note: turning off timed mode triggers another
+ sample. */
+
+ for (i = 0; i < DT2814_TIMEOUT; i++) {
+ if (inb(dev->iobase + DT2814_CSR) & DT2814_FINISH)
+ break;
+ }
+ inb(dev->iobase + DT2814_DATA);
+ inb(dev->iobase + DT2814_DATA);
+
+ s->async->events |= COMEDI_CB_EOA;
+ }
+ comedi_event(dev, s);
+ return IRQ_HANDLED;
+}
+
static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
int i, irq;
@@ -347,57 +361,21 @@ static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int dt2814_detach(struct comedi_device *dev)
+static void dt2814_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: dt2814: remove\n", dev->minor);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
if (dev->iobase)
release_region(dev->iobase, DT2814_SIZE);
-
- return 0;
}
-static irqreturn_t dt2814_interrupt(int irq, void *d)
-{
- int lo, hi;
- struct comedi_device *dev = d;
- struct comedi_subdevice *s;
- int data;
-
- if (!dev->attached) {
- comedi_error(dev, "spurious interrupt");
- return IRQ_HANDLED;
- }
-
- s = dev->subdevices + 0;
-
- hi = inb(dev->iobase + DT2814_DATA);
- lo = inb(dev->iobase + DT2814_DATA);
-
- data = (hi << 4) | (lo >> 4);
-
- if (!(--devpriv->ntrig)) {
- int i;
-
- outb(0, dev->iobase + DT2814_CSR);
- /* note: turning off timed mode triggers another
- sample. */
-
- for (i = 0; i < DT2814_TIMEOUT; i++) {
- if (inb(dev->iobase + DT2814_CSR) & DT2814_FINISH)
- break;
- }
- inb(dev->iobase + DT2814_DATA);
- inb(dev->iobase + DT2814_DATA);
-
- s->async->events |= COMEDI_CB_EOA;
- }
- comedi_event(dev, s);
- return IRQ_HANDLED;
-}
+static struct comedi_driver dt2814_driver = {
+ .driver_name = "dt2814",
+ .module = THIS_MODULE,
+ .attach = dt2814_attach,
+ .detach = dt2814_detach,
+};
+module_comedi_driver(dt2814_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c
index 4155da43fd51..bbab712be4b9 100644
--- a/drivers/staging/comedi/drivers/dt2815.c
+++ b/drivers/staging/comedi/drivers/dt2815.c
@@ -72,31 +72,6 @@ static const struct comedi_lrange
#define DT2815_DATA 0
#define DT2815_STATUS 1
-static int dt2815_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int dt2815_detach(struct comedi_device *dev);
-static struct comedi_driver driver_dt2815 = {
- .driver_name = "dt2815",
- .module = THIS_MODULE,
- .attach = dt2815_attach,
- .detach = dt2815_detach,
-};
-
-static int __init driver_dt2815_init_module(void)
-{
- return comedi_driver_register(&driver_dt2815);
-}
-
-static void __exit driver_dt2815_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_dt2815);
-}
-
-module_init(driver_dt2815_init_module);
-module_exit(driver_dt2815_cleanup_module);
-
-static void dt2815_free_resources(struct comedi_device *dev);
-
struct dt2815_private {
const struct comedi_lrange *range_type_list[8];
@@ -252,20 +227,19 @@ static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static void dt2815_free_resources(struct comedi_device *dev)
+static void dt2815_detach(struct comedi_device *dev)
{
if (dev->iobase)
release_region(dev->iobase, DT2815_SIZE);
}
-static int dt2815_detach(struct comedi_device *dev)
-{
- printk(KERN_INFO "comedi%d: dt2815: remove\n", dev->minor);
-
- dt2815_free_resources(dev);
-
- return 0;
-}
+static struct comedi_driver dt2815_driver = {
+ .driver_name = "dt2815",
+ .module = THIS_MODULE,
+ .attach = dt2815_attach,
+ .detach = dt2815_detach,
+};
+module_comedi_driver(dt2815_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/dt2817.c b/drivers/staging/comedi/drivers/dt2817.c
index 99c1584153d7..1ee10e7bf1d2 100644
--- a/drivers/staging/comedi/drivers/dt2817.c
+++ b/drivers/staging/comedi/drivers/dt2817.c
@@ -47,29 +47,6 @@ Configuration options:
#define DT2817_CR 0
#define DT2817_DATA 1
-static int dt2817_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int dt2817_detach(struct comedi_device *dev);
-static struct comedi_driver driver_dt2817 = {
- .driver_name = "dt2817",
- .module = THIS_MODULE,
- .attach = dt2817_attach,
- .detach = dt2817_detach,
-};
-
-static int __init driver_dt2817_init_module(void)
-{
- return comedi_driver_register(&driver_dt2817);
-}
-
-static void __exit driver_dt2817_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_dt2817);
-}
-
-module_init(driver_dt2817_init_module);
-module_exit(driver_dt2817_cleanup_module);
-
static int dt2817_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -182,16 +159,20 @@ static int dt2817_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int dt2817_detach(struct comedi_device *dev)
+static void dt2817_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: dt2817: remove\n", dev->minor);
-
if (dev->iobase)
release_region(dev->iobase, DT2817_SIZE);
-
- return 0;
}
+static struct comedi_driver dt2817_driver = {
+ .driver_name = "dt2817",
+ .module = THIS_MODULE,
+ .attach = dt2817_attach,
+ .detach = dt2817_detach,
+};
+module_comedi_driver(dt2817_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c
index 95ebc267bb74..736d8facaee8 100644
--- a/drivers/staging/comedi/drivers/dt282x.c
+++ b/drivers/staging/comedi/drivers/dt282x.c
@@ -221,136 +221,6 @@ struct dt282x_board {
int dabits;
};
-static const struct dt282x_board boardtypes[] = {
- {.name = "dt2821",
- .adbits = 12,
- .adchan_se = 16,
- .adchan_di = 8,
- .ai_speed = 20000,
- .ispgl = 0,
- .dachan = 2,
- .dabits = 12,
- },
- {.name = "dt2821-f",
- .adbits = 12,
- .adchan_se = 16,
- .adchan_di = 8,
- .ai_speed = 6500,
- .ispgl = 0,
- .dachan = 2,
- .dabits = 12,
- },
- {.name = "dt2821-g",
- .adbits = 12,
- .adchan_se = 16,
- .adchan_di = 8,
- .ai_speed = 4000,
- .ispgl = 0,
- .dachan = 2,
- .dabits = 12,
- },
- {.name = "dt2823",
- .adbits = 16,
- .adchan_se = 0,
- .adchan_di = 4,
- .ai_speed = 10000,
- .ispgl = 0,
- .dachan = 2,
- .dabits = 16,
- },
- {.name = "dt2824-pgh",
- .adbits = 12,
- .adchan_se = 16,
- .adchan_di = 8,
- .ai_speed = 20000,
- .ispgl = 0,
- .dachan = 0,
- .dabits = 0,
- },
- {.name = "dt2824-pgl",
- .adbits = 12,
- .adchan_se = 16,
- .adchan_di = 8,
- .ai_speed = 20000,
- .ispgl = 1,
- .dachan = 0,
- .dabits = 0,
- },
- {.name = "dt2825",
- .adbits = 12,
- .adchan_se = 16,
- .adchan_di = 8,
- .ai_speed = 20000,
- .ispgl = 1,
- .dachan = 2,
- .dabits = 12,
- },
- {.name = "dt2827",
- .adbits = 16,
- .adchan_se = 0,
- .adchan_di = 4,
- .ai_speed = 10000,
- .ispgl = 0,
- .dachan = 2,
- .dabits = 12,
- },
- {.name = "dt2828",
- .adbits = 12,
- .adchan_se = 4,
- .adchan_di = 0,
- .ai_speed = 10000,
- .ispgl = 0,
- .dachan = 2,
- .dabits = 12,
- },
- {.name = "dt2829",
- .adbits = 16,
- .adchan_se = 8,
- .adchan_di = 0,
- .ai_speed = 33250,
- .ispgl = 0,
- .dachan = 2,
- .dabits = 16,
- },
- {.name = "dt21-ez",
- .adbits = 12,
- .adchan_se = 16,
- .adchan_di = 8,
- .ai_speed = 10000,
- .ispgl = 0,
- .dachan = 2,
- .dabits = 12,
- },
- {.name = "dt23-ez",
- .adbits = 16,
- .adchan_se = 16,
- .adchan_di = 8,
- .ai_speed = 10000,
- .ispgl = 0,
- .dachan = 0,
- .dabits = 0,
- },
- {.name = "dt24-ez",
- .adbits = 12,
- .adchan_se = 16,
- .adchan_di = 8,
- .ai_speed = 10000,
- .ispgl = 0,
- .dachan = 0,
- .dabits = 0,
- },
- {.name = "dt24-ez-pgl",
- .adbits = 12,
- .adchan_se = 16,
- .adchan_di = 8,
- .ai_speed = 10000,
- .ispgl = 1,
- .dachan = 0,
- .dabits = 0,
- },
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct dt282x_board))
#define this_board ((const struct dt282x_board *)dev->board_ptr)
struct dt282x_private {
@@ -411,33 +281,6 @@ struct dt282x_private {
b \
} while (0)
-static int dt282x_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int dt282x_detach(struct comedi_device *dev);
-static struct comedi_driver driver_dt282x = {
- .driver_name = "dt282x",
- .module = THIS_MODULE,
- .attach = dt282x_attach,
- .detach = dt282x_detach,
- .board_name = &boardtypes[0].name,
- .num_names = n_boardtypes,
- .offset = sizeof(struct dt282x_board),
-};
-
-static int __init driver_dt282x_init_module(void)
-{
- return comedi_driver_register(&driver_dt282x);
-}
-
-static void __exit driver_dt282x_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_dt282x);
-}
-
-module_init(driver_dt282x_init_module);
-module_exit(driver_dt282x_cleanup_module);
-
-static void free_resources(struct comedi_device *dev);
static int prep_ai_dma(struct comedi_device *dev, int chan, int size);
static int prep_ao_dma(struct comedi_device *dev, int chan, int size);
static int dt282x_ai_cancel(struct comedi_device *dev,
@@ -1271,6 +1114,52 @@ enum { /* i/o base, irq, dma channels */
opt_ai_range, opt_ao0_range, opt_ao1_range, /* range */
};
+static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
+{
+ int ret;
+
+ devpriv->usedma = 0;
+
+ if (!dma1 && !dma2) {
+ printk(KERN_ERR " (no dma)");
+ return 0;
+ }
+
+ if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7)
+ return -EINVAL;
+
+ if (dma2 < dma1) {
+ int i;
+ i = dma1;
+ dma1 = dma2;
+ dma2 = i;
+ }
+
+ ret = request_dma(dma1, "dt282x A");
+ if (ret)
+ return -EBUSY;
+ devpriv->dma[0].chan = dma1;
+
+ ret = request_dma(dma2, "dt282x B");
+ if (ret)
+ return -EBUSY;
+ devpriv->dma[1].chan = dma2;
+
+ devpriv->dma_maxsize = PAGE_SIZE;
+ devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
+ devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
+ if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) {
+ printk(KERN_ERR " can't get DMA memory");
+ return -ENOMEM;
+ }
+
+ printk(KERN_INFO " (dma=%d,%d)", dma1, dma2);
+
+ devpriv->usedma = 1;
+
+ return 0;
+}
+
/*
options:
0 i/o base
@@ -1442,7 +1331,7 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static void free_resources(struct comedi_device *dev)
+static void dt282x_detach(struct comedi_device *dev)
{
if (dev->irq)
free_irq(dev->irq, dev);
@@ -1460,60 +1349,146 @@ static void free_resources(struct comedi_device *dev)
}
}
-static int dt282x_detach(struct comedi_device *dev)
-{
- printk(KERN_INFO "comedi%d: dt282x: remove\n", dev->minor);
-
- free_resources(dev);
-
- return 0;
-}
-
-static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
-{
- int ret;
-
- devpriv->usedma = 0;
-
- if (!dma1 && !dma2) {
- printk(KERN_ERR " (no dma)");
- return 0;
- }
-
- if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7)
- return -EINVAL;
-
- if (dma2 < dma1) {
- int i;
- i = dma1;
- dma1 = dma2;
- dma2 = i;
- }
-
- ret = request_dma(dma1, "dt282x A");
- if (ret)
- return -EBUSY;
- devpriv->dma[0].chan = dma1;
-
- ret = request_dma(dma2, "dt282x B");
- if (ret)
- return -EBUSY;
- devpriv->dma[1].chan = dma2;
-
- devpriv->dma_maxsize = PAGE_SIZE;
- devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
- devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
- if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) {
- printk(KERN_ERR " can't get DMA memory");
- return -ENOMEM;
- }
-
- printk(KERN_INFO " (dma=%d,%d)", dma1, dma2);
-
- devpriv->usedma = 1;
+static const struct dt282x_board boardtypes[] = {
+ {
+ .name = "dt2821",
+ .adbits = 12,
+ .adchan_se = 16,
+ .adchan_di = 8,
+ .ai_speed = 20000,
+ .ispgl = 0,
+ .dachan = 2,
+ .dabits = 12,
+ }, {
+ .name = "dt2821-f",
+ .adbits = 12,
+ .adchan_se = 16,
+ .adchan_di = 8,
+ .ai_speed = 6500,
+ .ispgl = 0,
+ .dachan = 2,
+ .dabits = 12,
+ }, {
+ .name = "dt2821-g",
+ .adbits = 12,
+ .adchan_se = 16,
+ .adchan_di = 8,
+ .ai_speed = 4000,
+ .ispgl = 0,
+ .dachan = 2,
+ .dabits = 12,
+ }, {
+ .name = "dt2823",
+ .adbits = 16,
+ .adchan_se = 0,
+ .adchan_di = 4,
+ .ai_speed = 10000,
+ .ispgl = 0,
+ .dachan = 2,
+ .dabits = 16,
+ }, {
+ .name = "dt2824-pgh",
+ .adbits = 12,
+ .adchan_se = 16,
+ .adchan_di = 8,
+ .ai_speed = 20000,
+ .ispgl = 0,
+ .dachan = 0,
+ .dabits = 0,
+ }, {
+ .name = "dt2824-pgl",
+ .adbits = 12,
+ .adchan_se = 16,
+ .adchan_di = 8,
+ .ai_speed = 20000,
+ .ispgl = 1,
+ .dachan = 0,
+ .dabits = 0,
+ }, {
+ .name = "dt2825",
+ .adbits = 12,
+ .adchan_se = 16,
+ .adchan_di = 8,
+ .ai_speed = 20000,
+ .ispgl = 1,
+ .dachan = 2,
+ .dabits = 12,
+ }, {
+ .name = "dt2827",
+ .adbits = 16,
+ .adchan_se = 0,
+ .adchan_di = 4,
+ .ai_speed = 10000,
+ .ispgl = 0,
+ .dachan = 2,
+ .dabits = 12,
+ }, {
+ .name = "dt2828",
+ .adbits = 12,
+ .adchan_se = 4,
+ .adchan_di = 0,
+ .ai_speed = 10000,
+ .ispgl = 0,
+ .dachan = 2,
+ .dabits = 12,
+ }, {
+ .name = "dt2829",
+ .adbits = 16,
+ .adchan_se = 8,
+ .adchan_di = 0,
+ .ai_speed = 33250,
+ .ispgl = 0,
+ .dachan = 2,
+ .dabits = 16,
+ }, {
+ .name = "dt21-ez",
+ .adbits = 12,
+ .adchan_se = 16,
+ .adchan_di = 8,
+ .ai_speed = 10000,
+ .ispgl = 0,
+ .dachan = 2,
+ .dabits = 12,
+ }, {
+ .name = "dt23-ez",
+ .adbits = 16,
+ .adchan_se = 16,
+ .adchan_di = 8,
+ .ai_speed = 10000,
+ .ispgl = 0,
+ .dachan = 0,
+ .dabits = 0,
+ }, {
+ .name = "dt24-ez",
+ .adbits = 12,
+ .adchan_se = 16,
+ .adchan_di = 8,
+ .ai_speed = 10000,
+ .ispgl = 0,
+ .dachan = 0,
+ .dabits = 0,
+ }, {
+ .name = "dt24-ez-pgl",
+ .adbits = 12,
+ .adchan_se = 16,
+ .adchan_di = 8,
+ .ai_speed = 10000,
+ .ispgl = 1,
+ .dachan = 0,
+ .dabits = 0,
+ },
+};
- return 0;
-}
+static struct comedi_driver dt282x_driver = {
+ .driver_name = "dt282x",
+ .module = THIS_MODULE,
+ .attach = dt282x_attach,
+ .detach = dt282x_detach,
+ .board_name = &boardtypes[0].name,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .offset = sizeof(struct dt282x_board),
+};
+module_comedi_driver(dt282x_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c
index 0a7979e52999..0d273269b572 100644
--- a/drivers/staging/comedi/drivers/dt3000.c
+++ b/drivers/staging/comedi/drivers/dt3000.c
@@ -164,19 +164,6 @@ static const struct dt3k_boardtype dt3k_boardtypes[] = {
#define n_dt3k_boards sizeof(dt3k_boardtypes)/sizeof(struct dt3k_boardtype)
#define this_board ((const struct dt3k_boardtype *)dev->board_ptr)
-static DEFINE_PCI_DEVICE_TABLE(dt3k_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0022) },
- { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0027) },
- { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0023) },
- { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0024) },
- { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0028) },
- { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0025) },
- { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0026) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, dt3k_pci_table);
-
#define DT3000_SIZE (4*0x1000)
/* dual-ported RAM location definitions */
@@ -276,54 +263,6 @@ struct dt3k_private {
#define devpriv ((struct dt3k_private *)dev->private)
-static int dt3000_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int dt3000_detach(struct comedi_device *dev);
-static struct comedi_driver driver_dt3000 = {
- .driver_name = "dt3000",
- .module = THIS_MODULE,
- .attach = dt3000_attach,
- .detach = dt3000_detach,
-};
-
-static int __devinit driver_dt3000_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- return comedi_pci_auto_config(dev, driver_dt3000.driver_name);
-}
-
-static void __devexit driver_dt3000_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_dt3000_pci_driver = {
- .id_table = dt3k_pci_table,
- .probe = &driver_dt3000_pci_probe,
- .remove = __devexit_p(&driver_dt3000_pci_remove)
-};
-
-static int __init driver_dt3000_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_dt3000);
- if (retval < 0)
- return retval;
-
- driver_dt3000_pci_driver.name = (char *)driver_dt3000.driver_name;
- return pci_register_driver(&driver_dt3000_pci_driver);
-}
-
-static void __exit driver_dt3000_cleanup_module(void)
-{
- pci_unregister_driver(&driver_dt3000_pci_driver);
- comedi_driver_unregister(&driver_dt3000);
-}
-
-module_init(driver_dt3000_init_module);
-module_exit(driver_dt3000_cleanup_module);
-
static void dt3k_ai_empty_fifo(struct comedi_device *dev,
struct comedi_subdevice *s);
static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *arg,
@@ -841,7 +780,77 @@ static int dt3k_mem_insn_read(struct comedi_device *dev,
return i;
}
-static int dt_pci_probe(struct comedi_device *dev, int bus, int slot);
+static int setup_pci(struct comedi_device *dev)
+{
+ resource_size_t addr;
+ int ret;
+
+ ret = comedi_pci_enable(devpriv->pci_dev, "dt3000");
+ if (ret < 0)
+ return ret;
+
+ addr = pci_resource_start(devpriv->pci_dev, 0);
+ devpriv->phys_addr = addr;
+ devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE);
+ if (!devpriv->io_addr)
+ return -ENOMEM;
+#if DEBUG
+ printk("0x%08llx mapped to %p, ",
+ (unsigned long long)devpriv->phys_addr, devpriv->io_addr);
+#endif
+
+ return 0;
+}
+
+static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board)
+{
+ int i;
+
+ for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from);
+ from != NULL;
+ from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) {
+ for (i = 0; i < n_dt3k_boards; i++) {
+ if (from->device == dt3k_boardtypes[i].device_id) {
+ *board = i;
+ return from;
+ }
+ }
+ printk
+ ("unknown Data Translation PCI device found with device_id=0x%04x\n",
+ from->device);
+ }
+ *board = -1;
+ return from;
+}
+
+static int dt_pci_probe(struct comedi_device *dev, int bus, int slot)
+{
+ int board;
+ int ret;
+ struct pci_dev *pcidev;
+
+ pcidev = NULL;
+ while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) {
+ if ((bus == 0 && slot == 0) ||
+ (pcidev->bus->number == bus &&
+ PCI_SLOT(pcidev->devfn) == slot)) {
+ break;
+ }
+ }
+ devpriv->pci_dev = pcidev;
+
+ if (board >= 0)
+ dev->board_ptr = dt3k_boardtypes + board;
+
+ if (!devpriv->pci_dev)
+ return 0;
+
+ ret = setup_pci(dev);
+ if (ret < 0)
+ return ret;
+
+ return 1;
+}
static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
@@ -935,11 +944,10 @@ static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int dt3000_detach(struct comedi_device *dev)
+static void dt3000_detach(struct comedi_device *dev)
{
if (dev->irq)
free_irq(dev->irq, dev);
-
if (devpriv) {
if (devpriv->pci_dev) {
if (devpriv->phys_addr)
@@ -949,85 +957,45 @@ static int dt3000_detach(struct comedi_device *dev)
if (devpriv->io_addr)
iounmap(devpriv->io_addr);
}
- /* XXX */
-
- return 0;
}
-static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board);
-static int setup_pci(struct comedi_device *dev);
+static struct comedi_driver dt3000_driver = {
+ .driver_name = "dt3000",
+ .module = THIS_MODULE,
+ .attach = dt3000_attach,
+ .detach = dt3000_detach,
+};
-static int dt_pci_probe(struct comedi_device *dev, int bus, int slot)
+static int __devinit dt3000_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- int board;
- int ret;
- struct pci_dev *pcidev;
-
- pcidev = NULL;
- while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) {
- if ((bus == 0 && slot == 0) ||
- (pcidev->bus->number == bus &&
- PCI_SLOT(pcidev->devfn) == slot)) {
- break;
- }
- }
- devpriv->pci_dev = pcidev;
-
- if (board >= 0)
- dev->board_ptr = dt3k_boardtypes + board;
-
- if (!devpriv->pci_dev)
- return 0;
-
- ret = setup_pci(dev);
- if (ret < 0)
- return ret;
-
- return 1;
+ return comedi_pci_auto_config(dev, &dt3000_driver);
}
-static int setup_pci(struct comedi_device *dev)
+static void __devexit dt3000_pci_remove(struct pci_dev *dev)
{
- resource_size_t addr;
- int ret;
-
- ret = comedi_pci_enable(devpriv->pci_dev, "dt3000");
- if (ret < 0)
- return ret;
-
- addr = pci_resource_start(devpriv->pci_dev, 0);
- devpriv->phys_addr = addr;
- devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE);
- if (!devpriv->io_addr)
- return -ENOMEM;
-#if DEBUG
- printk("0x%08llx mapped to %p, ",
- (unsigned long long)devpriv->phys_addr, devpriv->io_addr);
-#endif
-
- return 0;
+ comedi_pci_auto_unconfig(dev);
}
-static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board)
-{
- int i;
+static DEFINE_PCI_DEVICE_TABLE(dt3000_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0022) },
+ { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0027) },
+ { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0023) },
+ { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0024) },
+ { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0028) },
+ { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0025) },
+ { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0026) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, dt3000_pci_table);
- for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from);
- from != NULL;
- from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) {
- for (i = 0; i < n_dt3k_boards; i++) {
- if (from->device == dt3k_boardtypes[i].device_id) {
- *board = i;
- return from;
- }
- }
- printk
- ("unknown Data Translation PCI device found with device_id=0x%04x\n",
- from->device);
- }
- *board = -1;
- return from;
-}
+static struct pci_driver dt3000_pci_driver = {
+ .name = "dt3000",
+ .id_table = dt3000_pci_table,
+ .probe = dt3000_pci_probe,
+ .remove = __devexit_p(dt3000_pci_remove),
+};
+module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c
index e86ab5862895..22cda5c76ce4 100644
--- a/drivers/staging/comedi/drivers/dt9812.c
+++ b/drivers/staging/comedi/drivers/dt9812.c
@@ -196,7 +196,7 @@ struct dt9812_flash_data {
};
#define DT9812_MAX_NUM_MULTI_BYTE_RDS \
- ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / sizeof(u8))
+ ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / sizeof(u8))
struct dt9812_read_multi {
u8 count;
@@ -209,8 +209,8 @@ struct dt9812_write_byte {
};
#define DT9812_MAX_NUM_MULTI_BYTE_WRTS \
- ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / \
- sizeof(struct dt9812_write_byte))
+ ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / \
+ sizeof(struct dt9812_write_byte))
struct dt9812_write_multi {
u8 count;
@@ -224,7 +224,8 @@ struct dt9812_rmw_byte {
};
#define DT9812_MAX_NUM_MULTI_BYTE_RMWS \
- ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / sizeof(struct dt9812_rmw_byte))
+ ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / \
+ sizeof(struct dt9812_rmw_byte))
struct dt9812_rmw_multi {
u8 count;
@@ -365,7 +366,7 @@ static int dt9812_read_info(struct usb_dt9812 *dev, int offset, void *buf,
}
static int dt9812_read_multiple_registers(struct usb_dt9812 *dev, int reg_count,
- u8 * address, u8 * value)
+ u8 *address, u8 *value)
{
struct dt9812_usb_cmd cmd;
int i, count, retval;
@@ -391,8 +392,8 @@ static int dt9812_read_multiple_registers(struct usb_dt9812 *dev, int reg_count,
}
static int dt9812_write_multiple_registers(struct usb_dt9812 *dev,
- int reg_count, u8 * address,
- u8 * value)
+ int reg_count, u8 *address,
+ u8 *value)
{
struct dt9812_usb_cmd cmd;
int i, count, retval;
@@ -430,7 +431,7 @@ static int dt9812_rmw_multiple_registers(struct usb_dt9812 *dev, int reg_count,
return retval;
}
-static int dt9812_digital_in(struct slot_dt9812 *slot, u8 * bits)
+static int dt9812_digital_in(struct slot_dt9812 *slot, u8 *bits)
{
int result = -ENODEV;
@@ -476,7 +477,7 @@ static int dt9812_digital_out(struct slot_dt9812 *slot, u8 bits)
return result;
}
-static int dt9812_digital_out_shadow(struct slot_dt9812 *slot, u8 * bits)
+static int dt9812_digital_out_shadow(struct slot_dt9812 *slot, u8 *bits)
{
int result = -ENODEV;
@@ -547,12 +548,12 @@ static void dt9812_configure_gain(struct usb_dt9812 *dev,
rmw->or_value = F020_MASK_ADC0CF_AMP0GN2;
break;
default:
- err("Illegal gain %d\n", gain);
+ dev_err(&dev->interface->dev, "Illegal gain %d\n", gain);
}
}
-static int dt9812_analog_in(struct slot_dt9812 *slot, int channel, u16 * value,
+static int dt9812_analog_in(struct slot_dt9812 *slot, int channel, u16 *value,
enum dt9812_gain gain)
{
struct dt9812_rmw_byte rmw[3];
@@ -619,7 +620,7 @@ exit:
}
static int dt9812_analog_out_shadow(struct slot_dt9812 *slot, int channel,
- u16 * value)
+ u16 *value)
{
int result = -ENODEV;
@@ -715,7 +716,7 @@ static int dt9812_probe(struct usb_interface *interface,
iface_desc = interface->cur_altsetting;
if (iface_desc->desc.bNumEndpoints != 5) {
- err("Wrong number of endpints.");
+ dev_err(&interface->dev, "Wrong number of endpoints.\n");
retval = -ENODEV;
goto error;
}
@@ -781,22 +782,22 @@ static int dt9812_probe(struct usb_interface *interface,
}
if (dt9812_read_info(dev, 1, &dev->vendor, sizeof(dev->vendor)) != 0) {
- err("Failed to read vendor.");
+ dev_err(&interface->dev, "Failed to read vendor.\n");
retval = -ENODEV;
goto error;
}
if (dt9812_read_info(dev, 3, &dev->product, sizeof(dev->product)) != 0) {
- err("Failed to read product.");
+ dev_err(&interface->dev, "Failed to read product.\n");
retval = -ENODEV;
goto error;
}
if (dt9812_read_info(dev, 5, &dev->device, sizeof(dev->device)) != 0) {
- err("Failed to read device.");
+ dev_err(&interface->dev, "Failed to read device.\n");
retval = -ENODEV;
goto error;
}
if (dt9812_read_info(dev, 7, &dev->serial, sizeof(dev->serial)) != 0) {
- err("Failed to read serial.");
+ dev_err(&interface->dev, "Failed to read serial.\n");
retval = -ENODEV;
goto error;
}
@@ -1110,9 +1111,9 @@ static int dt9812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int dt9812_detach(struct comedi_device *dev)
+static void dt9812_detach(struct comedi_device *dev)
{
- return 0;
+ /* Nothing to cleanup */
}
static struct comedi_driver dt9812_comedi_driver = {
@@ -1146,7 +1147,9 @@ static int __init usb_dt9812_init(void)
result = comedi_driver_register(&dt9812_comedi_driver);
if (result) {
usb_deregister(&dt9812_usb_driver);
- err("comedi_driver_register failed. Error number %d", result);
+ printk(KERN_ERR KBUILD_MODNAME
+ ": comedi_driver_register failed. Error number %d\n",
+ result);
}
return result;
diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c
index da8a2bf31657..b0cec7b1b0c9 100644
--- a/drivers/staging/comedi/drivers/dyna_pci10xx.c
+++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c
@@ -48,17 +48,6 @@
static DEFINE_MUTEX(start_stop_sem);
-static DEFINE_PCI_DEVICE_TABLE(dyna_pci10xx_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_DYNALOG, 0x1050) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, dyna_pci10xx_pci_table);
-
-static int dyna_pci10xx_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int dyna_pci10xx_detach(struct comedi_device *dev);
-
static const struct comedi_lrange range_pci1050_ai = { 3, {
BIP_RANGE(10),
BIP_RANGE(5),
@@ -113,16 +102,6 @@ static const struct boardtype boardtypes[] = {
{.name = DRV_NAME},
};
-static struct comedi_driver driver_dyna_pci10xx = {
- .driver_name = DRV_NAME,
- .module = THIS_MODULE,
- .attach = dyna_pci10xx_attach,
- .detach = dyna_pci10xx_detach,
- .board_name = &boardtypes[0].name,
- .offset = sizeof(struct boardtype),
- .num_names = ARRAY_SIZE(boardtypes),
-};
-
struct dyna_pci10xx_private {
struct pci_dev *pci_dev; /* ptr to PCI device */
char valid; /* card is usable */
@@ -408,54 +387,48 @@ found:
return 1;
}
-static int dyna_pci10xx_detach(struct comedi_device *dev)
+static void dyna_pci10xx_detach(struct comedi_device *dev)
{
if (devpriv && devpriv->pci_dev) {
comedi_pci_disable(devpriv->pci_dev);
mutex_destroy(&devpriv->mutex);
}
-
- return 0;
}
-static int __devinit driver_dyna_pci10xx_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static struct comedi_driver dyna_pci10xx_driver = {
+ .driver_name = "dyna_pci10xx",
+ .module = THIS_MODULE,
+ .attach = dyna_pci10xx_attach,
+ .detach = dyna_pci10xx_detach,
+ .board_name = &boardtypes[0].name,
+ .offset = sizeof(struct boardtype),
+ .num_names = ARRAY_SIZE(boardtypes),
+};
+
+static int __devinit dyna_pci10xx_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_dyna_pci10xx.driver_name);
+ return comedi_pci_auto_config(dev, &dyna_pci10xx_driver);
}
-static void __devexit driver_dyna_pci10xx_pci_remove(struct pci_dev *dev)
+static void __devexit dyna_pci10xx_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_dyna_pci10xx_pci_driver = {
- .id_table = dyna_pci10xx_pci_table,
- .probe = &driver_dyna_pci10xx_pci_probe,
- .remove = __devexit_p(&driver_dyna_pci10xx_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(dyna_pci10xx_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_DYNALOG, 0x1050) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, dyna_pci10xx_pci_table);
-static int __init driver_dyna_pci10xx_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_dyna_pci10xx);
- if (retval < 0)
- return retval;
-
- driver_dyna_pci10xx_pci_driver.name =
- (char *)driver_dyna_pci10xx.driver_name;
- return pci_register_driver(&driver_dyna_pci10xx_pci_driver);
-}
-
-static void __exit driver_dyna_pci10xx_cleanup_module(void)
-{
- pci_unregister_driver(&driver_dyna_pci10xx_pci_driver);
- comedi_driver_unregister(&driver_dyna_pci10xx);
-}
-
-module_init(driver_dyna_pci10xx_init_module);
-module_exit(driver_dyna_pci10xx_cleanup_module);
+static struct pci_driver dyna_pci10xx_pci_driver = {
+ .name = "dyna_pci10xx",
+ .id_table = dyna_pci10xx_pci_table,
+ .probe = dyna_pci10xx_pci_probe,
+ .remove = __devexit_p(dyna_pci10xx_pci_remove),
+};
+module_comedi_pci_driver(dyna_pci10xx_driver, dyna_pci10xx_pci_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Prashant Shah <pshah.mumbai@gmail.com>");
diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c
index 7f49add60b21..d23814450b40 100644
--- a/drivers/staging/comedi/drivers/fl512.c
+++ b/drivers/staging/comedi/drivers/fl512.c
@@ -42,38 +42,6 @@ static const struct comedi_lrange range_fl512 = { 4, {
}
};
-static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int fl512_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_fl512 = {
- .driver_name = "fl512",
- .module = THIS_MODULE,
- .attach = fl512_attach,
- .detach = fl512_detach,
-};
-
-static int __init driver_fl512_init_module(void)
-{
- return comedi_driver_register(&driver_fl512);
-}
-
-static void __exit driver_fl512_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_fl512);
-}
-
-module_init(driver_fl512_init_module);
-module_exit(driver_fl512_cleanup_module);
-
-static int fl512_ai_insn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data);
-static int fl512_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int fl512_ao_insn_readback(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
/*
* fl512_ai_insn : this is the analog input function
*/
@@ -140,9 +108,6 @@ static int fl512_ao_insn_readback(struct comedi_device *dev,
return n;
}
-/*
- * start attach
- */
static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
unsigned long iobase;
@@ -209,14 +174,20 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 1;
}
-static int fl512_detach(struct comedi_device *dev)
+static void fl512_detach(struct comedi_device *dev)
{
if (dev->iobase)
release_region(dev->iobase, FL512_SIZE);
- printk(KERN_INFO "comedi%d: fl512: dummy i detach\n", dev->minor);
- return 0;
}
+static struct comedi_driver fl512_driver = {
+ .driver_name = "fl512",
+ .module = THIS_MODULE,
+ .attach = fl512_attach,
+ .detach = fl512_detach,
+};
+module_comedi_driver(fl512_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c
index bc020dea141b..8aece08bd0dd 100644
--- a/drivers/staging/comedi/drivers/gsc_hpdi.c
+++ b/drivers/staging/comedi/drivers/gsc_hpdi.c
@@ -53,8 +53,6 @@ support could be added to this driver.
#include "plx9080.h"
#include "comedi_fc.h"
-static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int hpdi_detach(struct comedi_device *dev);
static void abort_dma(struct comedi_device *dev, unsigned int channel);
static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -287,15 +285,6 @@ static const struct hpdi_board hpdi_boards[] = {
#endif
};
-static DEFINE_PCI_DEVICE_TABLE(hpdi_pci_table) = {
- {
- PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9080, PCI_VENDOR_ID_PLX,
- 0x2400, 0, 0, 0}, {
- 0}
-};
-
-MODULE_DEVICE_TABLE(pci, hpdi_pci_table);
-
static inline struct hpdi_board *board(const struct comedi_device *dev)
{
return (struct hpdi_board *)dev->board_ptr;
@@ -338,51 +327,6 @@ static inline struct hpdi_private *priv(struct comedi_device *dev)
return dev->private;
}
-static struct comedi_driver driver_hpdi = {
- .driver_name = "gsc_hpdi",
- .module = THIS_MODULE,
- .attach = hpdi_attach,
- .detach = hpdi_detach,
-};
-
-static int __devinit driver_hpdi_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- return comedi_pci_auto_config(dev, driver_hpdi.driver_name);
-}
-
-static void __devexit driver_hpdi_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_hpdi_pci_driver = {
- .id_table = hpdi_pci_table,
- .probe = &driver_hpdi_pci_probe,
- .remove = __devexit_p(&driver_hpdi_pci_remove)
-};
-
-static int __init driver_hpdi_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_hpdi);
- if (retval < 0)
- return retval;
-
- driver_hpdi_pci_driver.name = (char *)driver_hpdi.driver_name;
- return pci_register_driver(&driver_hpdi_pci_driver);
-}
-
-static void __exit driver_hpdi_cleanup_module(void)
-{
- pci_unregister_driver(&driver_hpdi_pci_driver);
- comedi_driver_unregister(&driver_hpdi);
-}
-
-module_init(driver_hpdi_init_module);
-module_exit(driver_hpdi_cleanup_module);
-
static int dio_config_insn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
unsigned int *data)
@@ -645,7 +589,7 @@ static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it)
"gsc_hpdi: found %s on bus %i, slot %i\n", board(dev)->name,
pcidev->bus->number, PCI_SLOT(pcidev->devfn));
- if (comedi_pci_enable(pcidev, driver_hpdi.driver_name)) {
+ if (comedi_pci_enable(pcidev, dev->driver->driver_name)) {
printk(KERN_WARNING
" failed enable PCI device and request regions\n");
return -EIO;
@@ -679,7 +623,7 @@ static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it)
/* get irq */
if (request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED,
- driver_hpdi.driver_name, dev)) {
+ dev->driver->driver_name, dev)) {
printk(KERN_WARNING
" unable to allocate irq %u\n", pcidev->irq);
return -EINVAL;
@@ -720,12 +664,10 @@ static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return init_hpdi(dev);
}
-static int hpdi_detach(struct comedi_device *dev)
+static void hpdi_detach(struct comedi_device *dev)
{
unsigned int i;
- printk(KERN_WARNING "comedi%d: gsc_hpdi: remove\n", dev->minor);
-
if (dev->irq)
free_irq(dev->irq, dev);
if ((priv(dev)) && (priv(dev)->hw_dev)) {
@@ -758,7 +700,6 @@ static int hpdi_detach(struct comedi_device *dev)
comedi_pci_disable(priv(dev)->hw_dev);
pci_dev_put(priv(dev)->hw_dev);
}
- return 0;
}
static int dio_config_block_size(struct comedi_device *dev, unsigned int *data)
@@ -1113,6 +1054,39 @@ static int hpdi_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
return 0;
}
+static struct comedi_driver gsc_hpdi_driver = {
+ .driver_name = "gsc_hpdi",
+ .module = THIS_MODULE,
+ .attach = hpdi_attach,
+ .detach = hpdi_detach,
+};
+
+static int __devinit gsc_hpdi_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, &gsc_hpdi_driver);
+}
+
+static void __devexit gsc_hpdi_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(gsc_hpdi_pci_table) = {
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9080, PCI_VENDOR_ID_PLX,
+ 0x2400, 0, 0, 0},
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, gsc_hpdi_pci_table);
+
+static struct pci_driver gsc_hpdi_pci_driver = {
+ .name = "gsc_hpdi",
+ .id_table = gsc_hpdi_pci_table,
+ .probe = gsc_hpdi_pci_probe,
+ .remove = __devexit_p(gsc_hpdi_pci_remove)
+};
+module_comedi_pci_driver(gsc_hpdi_driver, gsc_hpdi_pci_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c
index 126550f3c02b..fdc596fb0990 100644
--- a/drivers/staging/comedi/drivers/icp_multi.c
+++ b/drivers/staging/comedi/drivers/icp_multi.c
@@ -121,15 +121,6 @@ static const char range_codes_analog[] = { 0x00, 0x20, 0x10, 0x30 };
/*
==============================================================================
- Forward declarations
-==============================================================================
-*/
-static int icp_multi_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int icp_multi_detach(struct comedi_device *dev);
-
-/*
-==============================================================================
Data & Structure declarations
==============================================================================
*/
@@ -154,50 +145,6 @@ struct boardtype {
const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */
};
-static const struct boardtype boardtypes[] = {
- {"icp_multi", /* Driver name */
- DEVICE_ID, /* PCI device ID */
- IORANGE_ICP_MULTI, /* I/O range length */
- 1, /* 1=Card supports interrupts */
- TYPE_ICP_MULTI, /* Card type = ICP MULTI */
- 16, /* Num of A/D channels */
- 8, /* Num of A/D channels in diff mode */
- 4, /* Num of D/A channels */
- 16, /* Num of digital inputs */
- 8, /* Num of digital outputs */
- 4, /* Num of counters */
- 0x0fff, /* Resolution of A/D */
- 0x0fff, /* Resolution of D/A */
- &range_analog, /* Rangelist for A/D */
- range_codes_analog, /* Range codes for programming */
- &range_analog}, /* Rangelist for D/A */
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype))
-
-static struct comedi_driver driver_icp_multi = {
- .driver_name = "icp_multi",
- .module = THIS_MODULE,
- .attach = icp_multi_attach,
- .detach = icp_multi_detach,
- .num_names = n_boardtypes,
- .board_name = &boardtypes[0].name,
- .offset = sizeof(struct boardtype),
-};
-
-static int __init driver_icp_multi_init_module(void)
-{
- return comedi_driver_register(&driver_icp_multi);
-}
-
-static void __exit driver_icp_multi_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_icp_multi);
-}
-
-module_init(driver_icp_multi_init_module);
-module_exit(driver_icp_multi_cleanup_module);
-
struct icp_multi_private {
struct pcilst_struct *card; /* pointer to card */
char valid; /* card is usable */
@@ -222,25 +169,81 @@ struct icp_multi_private {
/*
==============================================================================
- More forward declarations
+
+Name: setup_channel_list
+
+Description:
+ This function sets the appropriate channel selection,
+ differential input mode and range bits in the ADC Command/
+ Status register.
+
+Parameters:
+ struct comedi_device *dev Pointer to current service structure
+ struct comedi_subdevice *s Pointer to current subdevice structure
+ unsigned int *chanlist Pointer to packed channel list
+ unsigned int n_chan Number of channels to scan
+
+Returns:Void
+
==============================================================================
*/
-
-#if 0
-static int check_channel_list(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int *chanlist, unsigned int n_chan);
-#endif
static void setup_channel_list(struct comedi_device *dev,
struct comedi_subdevice *s,
- unsigned int *chanlist, unsigned int n_chan);
-static int icp_multi_reset(struct comedi_device *dev);
+ unsigned int *chanlist, unsigned int n_chan)
+{
+ unsigned int i, range, chanprog;
+ unsigned int diff;
-/*
-==============================================================================
- Functions
-==============================================================================
-*/
+#ifdef ICP_MULTI_EXTDEBUG
+ printk(KERN_DEBUG
+ "icp multi EDBG: setup_channel_list(...,%d)\n", n_chan);
+#endif
+ devpriv->act_chanlist_len = n_chan;
+ devpriv->act_chanlist_pos = 0;
+
+ for (i = 0; i < n_chan; i++) {
+ /* Get channel */
+ chanprog = CR_CHAN(chanlist[i]);
+
+ /* Determine if it is a differential channel (Bit 15 = 1) */
+ if (CR_AREF(chanlist[i]) == AREF_DIFF) {
+ diff = 1;
+ chanprog &= 0x0007;
+ } else {
+ diff = 0;
+ chanprog &= 0x000f;
+ }
+
+ /* Clear channel, range and input mode bits
+ * in A/D command/status register */
+ devpriv->AdcCmdStatus &= 0xf00f;
+
+ /* Set channel number and differential mode status bit */
+ if (diff) {
+ /* Set channel number, bits 9-11 & mode, bit 6 */
+ devpriv->AdcCmdStatus |= (chanprog << 9);
+ devpriv->AdcCmdStatus |= ADC_DI;
+ } else
+ /* Set channel number, bits 8-11 */
+ devpriv->AdcCmdStatus |= (chanprog << 8);
+
+ /* Get range for current channel */
+ range = this_board->rangecode[CR_RANGE(chanlist[i])];
+ /* Set range. bits 4-5 */
+ devpriv->AdcCmdStatus |= range;
+
+ /* Output channel, range, mode to ICP Multi */
+ writew(devpriv->AdcCmdStatus,
+ devpriv->io_addr + ICP_MULTI_ADC_CSR);
+
+#ifdef ICP_MULTI_EXTDEBUG
+ printk(KERN_DEBUG
+ "GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
+ devpriv->act_chanlist[i]);
+#endif
+ }
+
+}
/*
==============================================================================
@@ -764,84 +767,6 @@ static int check_channel_list(struct comedi_device *dev,
/*
==============================================================================
-Name: setup_channel_list
-
-Description:
- This function sets the appropriate channel selection,
- differential input mode and range bits in the ADC Command/
- Status register.
-
-Parameters:
- struct comedi_device *dev Pointer to current service structure
- struct comedi_subdevice *s Pointer to current subdevice structure
- unsigned int *chanlist Pointer to packed channel list
- unsigned int n_chan Number of channels to scan
-
-Returns:Void
-
-==============================================================================
-*/
-static void setup_channel_list(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int *chanlist, unsigned int n_chan)
-{
- unsigned int i, range, chanprog;
- unsigned int diff;
-
-#ifdef ICP_MULTI_EXTDEBUG
- printk(KERN_DEBUG
- "icp multi EDBG: setup_channel_list(...,%d)\n", n_chan);
-#endif
- devpriv->act_chanlist_len = n_chan;
- devpriv->act_chanlist_pos = 0;
-
- for (i = 0; i < n_chan; i++) {
- /* Get channel */
- chanprog = CR_CHAN(chanlist[i]);
-
- /* Determine if it is a differential channel (Bit 15 = 1) */
- if (CR_AREF(chanlist[i]) == AREF_DIFF) {
- diff = 1;
- chanprog &= 0x0007;
- } else {
- diff = 0;
- chanprog &= 0x000f;
- }
-
- /* Clear channel, range and input mode bits
- * in A/D command/status register */
- devpriv->AdcCmdStatus &= 0xf00f;
-
- /* Set channel number and differential mode status bit */
- if (diff) {
- /* Set channel number, bits 9-11 & mode, bit 6 */
- devpriv->AdcCmdStatus |= (chanprog << 9);
- devpriv->AdcCmdStatus |= ADC_DI;
- } else
- /* Set channel number, bits 8-11 */
- devpriv->AdcCmdStatus |= (chanprog << 8);
-
- /* Get range for current channel */
- range = this_board->rangecode[CR_RANGE(chanlist[i])];
- /* Set range. bits 4-5 */
- devpriv->AdcCmdStatus |= range;
-
- /* Output channel, range, mode to ICP Multi */
- writew(devpriv->AdcCmdStatus,
- devpriv->io_addr + ICP_MULTI_ADC_CSR);
-
-#ifdef ICP_MULTI_EXTDEBUG
- printk(KERN_DEBUG
- "GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range,
- devpriv->act_chanlist[i]);
-#endif
- }
-
-}
-
-/*
-==============================================================================
-
Name: icp_multi_reset
Description:
@@ -897,23 +822,6 @@ static int icp_multi_reset(struct comedi_device *dev)
return 0;
}
-/*
-==============================================================================
-
-Name: icp_multi_attach
-
-Description:
- This function sets up all the appropriate data for the current
- device.
-
-Parameters:
- struct comedi_device *dev Pointer to current device structure
- struct comedi_devconfig *it Pointer to current device configuration
-
-Returns:int 0 = success
-
-==============================================================================
-*/
static int icp_multi_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
@@ -1099,44 +1007,53 @@ static int icp_multi_attach(struct comedi_device *dev,
return 0;
}
-/*
-==============================================================================
-
-Name: icp_multi_detach
-
-Description:
- This function releases all the resources used by the current
- device.
-
-Parameters:
- struct comedi_device *dev Pointer to current device structure
-
-Returns:int 0 = success
-
-==============================================================================
-*/
-static int icp_multi_detach(struct comedi_device *dev)
+static void icp_multi_detach(struct comedi_device *dev)
{
-
if (dev->private)
if (devpriv->valid)
icp_multi_reset(dev);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
if (dev->private && devpriv->io_addr)
iounmap(devpriv->io_addr);
-
if (dev->private && devpriv->card)
pci_card_free(devpriv->card);
-
if (--pci_list_builded == 0)
pci_card_list_cleanup(PCI_VENDOR_ID_ICP);
-
- return 0;
}
+static const struct boardtype boardtypes[] = {
+ {
+ .name = "icp_multi",
+ .device_id = DEVICE_ID,
+ .iorange = IORANGE_ICP_MULTI,
+ .have_irq = 1,
+ .cardtype = TYPE_ICP_MULTI,
+ .n_aichan = 16,
+ .n_aichand = 8,
+ .n_aochan = 4,
+ .n_dichan = 16,
+ .n_dochan = 8,
+ .n_ctrs = 4,
+ .ai_maxdata = 0x0fff,
+ .ao_maxdata = 0x0fff,
+ .rangelist_ai = &range_analog,
+ .rangecode = range_codes_analog,
+ .rangelist_ao = &range_analog,
+ },
+};
+
+static struct comedi_driver icp_multi_driver = {
+ .driver_name = "icp_multi",
+ .module = THIS_MODULE,
+ .attach = icp_multi_attach,
+ .detach = icp_multi_detach,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .board_name = &boardtypes[0].name,
+ .offset = sizeof(struct boardtype),
+};
+module_comedi_driver(icp_multi_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c
index e4711ef54719..f0a579a04a7d 100644
--- a/drivers/staging/comedi/drivers/ii_pci20kc.c
+++ b/drivers/staging/comedi/drivers/ii_pci20kc.c
@@ -159,17 +159,6 @@ struct pci20xxx_private {
#define devpriv ((struct pci20xxx_private *)dev->private)
#define CHAN (CR_CHAN(it->chanlist[0]))
-static int pci20xxx_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pci20xxx_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_pci20xxx = {
- .driver_name = "ii_pci20kc",
- .module = THIS_MODULE,
- .attach = pci20xxx_attach,
- .detach = pci20xxx_detach,
-};
-
static int pci20006_init(struct comedi_device *dev, struct comedi_subdevice *s,
int opt0, int opt1);
static int pci20341_init(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -275,11 +264,9 @@ static int pci20xxx_attach(struct comedi_device *dev,
return 1;
}
-static int pci20xxx_detach(struct comedi_device *dev)
+static void pci20xxx_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: pci20xxx: remove\n", dev->minor);
-
- return 0;
+ /* Nothing to cleanup */
}
/* pci20006m */
@@ -666,18 +653,13 @@ static unsigned int pci20xxx_di(struct comedi_device *dev,
}
#endif
-static int __init driver_pci20xxx_init_module(void)
-{
- return comedi_driver_register(&driver_pci20xxx);
-}
-
-static void __exit driver_pci20xxx_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pci20xxx);
-}
-
-module_init(driver_pci20xxx_init_module);
-module_exit(driver_pci20xxx_cleanup_module);
+static struct comedi_driver pci20xxx_driver = {
+ .driver_name = "ii_pci20kc",
+ .module = THIS_MODULE,
+ .attach = pci20xxx_attach,
+ .detach = pci20xxx_detach,
+};
+module_comedi_driver(pci20xxx_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c
index 6a79ba10630d..d536a11edb95 100644
--- a/drivers/staging/comedi/drivers/jr3_pci.c
+++ b/drivers/staging/comedi/drivers/jr3_pci.c
@@ -59,28 +59,6 @@ Devices: [JR3] PCI force sensor board (jr3_pci)
#define PCI_DEVICE_ID_JR3_3_CHANNEL 0x3113
#define PCI_DEVICE_ID_JR3_4_CHANNEL 0x3114
-static int jr3_pci_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int jr3_pci_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_jr3_pci = {
- .driver_name = "jr3_pci",
- .module = THIS_MODULE,
- .attach = jr3_pci_attach,
- .detach = jr3_pci_detach,
-};
-
-static DEFINE_PCI_DEVICE_TABLE(jr3_pci_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL) },
- { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL_NEW) },
- { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_2_CHANNEL) },
- { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_3_CHANNEL) },
- { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_4_CHANNEL) },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, jr3_pci_pci_table);
-
struct jr3_pci_dev_private {
struct pci_dev *pci_dev;
@@ -948,9 +926,7 @@ out:
return result;
}
-MODULE_FIRMWARE("comedi/jr3pci.idm");
-
-static int jr3_pci_detach(struct comedi_device *dev)
+static void jr3_pci_detach(struct comedi_device *dev)
{
int i;
struct jr3_pci_dev_private *devpriv = dev->private;
@@ -962,56 +938,52 @@ static int jr3_pci_detach(struct comedi_device *dev)
for (i = 0; i < devpriv->n_channels; i++)
kfree(dev->subdevices[i].private);
}
-
if (devpriv->iobase)
iounmap((void *)devpriv->iobase);
if (devpriv->pci_enabled)
comedi_pci_disable(devpriv->pci_dev);
-
if (devpriv->pci_dev)
pci_dev_put(devpriv->pci_dev);
}
- return 0;
}
-static int __devinit driver_jr3_pci_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static struct comedi_driver jr3_pci_driver = {
+ .driver_name = "jr3_pci",
+ .module = THIS_MODULE,
+ .attach = jr3_pci_attach,
+ .detach = jr3_pci_detach,
+};
+
+static int __devinit jr3_pci_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_jr3_pci.driver_name);
+ return comedi_pci_auto_config(dev, &jr3_pci_driver);
}
-static void __devexit driver_jr3_pci_pci_remove(struct pci_dev *dev)
+static void __devexit jr3_pci_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_jr3_pci_pci_driver = {
- .id_table = jr3_pci_pci_table,
- .probe = &driver_jr3_pci_pci_probe,
- .remove = __devexit_p(&driver_jr3_pci_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(jr3_pci_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL) },
+ { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL_NEW) },
+ { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_2_CHANNEL) },
+ { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_3_CHANNEL) },
+ { PCI_DEVICE(PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_4_CHANNEL) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, jr3_pci_pci_table);
-static int __init driver_jr3_pci_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_jr3_pci);
- if (retval < 0)
- return retval;
-
- driver_jr3_pci_pci_driver.name = (char *)driver_jr3_pci.driver_name;
- return pci_register_driver(&driver_jr3_pci_pci_driver);
-}
-
-static void __exit driver_jr3_pci_cleanup_module(void)
-{
- pci_unregister_driver(&driver_jr3_pci_pci_driver);
- comedi_driver_unregister(&driver_jr3_pci);
-}
-
-module_init(driver_jr3_pci_init_module);
-module_exit(driver_jr3_pci_cleanup_module);
+static struct pci_driver jr3_pci_pci_driver = {
+ .name = "jr3_pci",
+ .id_table = jr3_pci_pci_table,
+ .probe = jr3_pci_pci_probe,
+ .remove = __devexit_p(jr3_pci_pci_remove),
+};
+module_comedi_pci_driver(jr3_pci_driver, jr3_pci_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("comedi/jr3pci.idm");
diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c
index 4e9e9a078652..09d191844bf8 100644
--- a/drivers/staging/comedi/drivers/ke_counter.c
+++ b/drivers/staging/comedi/drivers/ke_counter.c
@@ -46,18 +46,6 @@ Kolter Electronic PCI Counter Card.
#define PCI_VENDOR_ID_KOLTER 0x1001
#define CNT_CARD_DEVICE_ID 0x0014
-/*-- function prototypes ----------------------------------------------------*/
-
-static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int cnt_detach(struct comedi_device *dev);
-
-static DEFINE_PCI_DEVICE_TABLE(cnt_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID) },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, cnt_pci_table);
-
/*-- board specification structure ------------------------------------------*/
struct cnt_board_struct {
@@ -87,51 +75,6 @@ struct cnt_device_private {
#define devpriv ((struct cnt_device_private *)dev->private)
-static struct comedi_driver cnt_driver = {
- .driver_name = CNT_DRIVER_NAME,
- .module = THIS_MODULE,
- .attach = cnt_attach,
- .detach = cnt_detach,
-};
-
-static int __devinit cnt_driver_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- return comedi_pci_auto_config(dev, cnt_driver.driver_name);
-}
-
-static void __devexit cnt_driver_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver cnt_driver_pci_driver = {
- .id_table = cnt_pci_table,
- .probe = &cnt_driver_pci_probe,
- .remove = __devexit_p(&cnt_driver_pci_remove)
-};
-
-static int __init cnt_driver_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&cnt_driver);
- if (retval < 0)
- return retval;
-
- cnt_driver_pci_driver.name = (char *)cnt_driver.driver_name;
- return pci_register_driver(&cnt_driver_pci_driver);
-}
-
-static void __exit cnt_driver_cleanup_module(void)
-{
- pci_unregister_driver(&cnt_driver_pci_driver);
- comedi_driver_unregister(&cnt_driver);
-}
-
-module_init(cnt_driver_init_module);
-module_exit(cnt_driver_cleanup_module);
-
/*-- counter write ----------------------------------------------------------*/
/* This should be used only for resetting the counters; maybe it is better
@@ -181,8 +124,6 @@ static int cnt_rinsn(struct comedi_device *dev,
return 1;
}
-/*-- attach -----------------------------------------------------------------*/
-
static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct comedi_subdevice *subdevice;
@@ -278,20 +219,47 @@ found:
return 0;
}
-/*-- detach -----------------------------------------------------------------*/
-
-static int cnt_detach(struct comedi_device *dev)
+static void cnt_detach(struct comedi_device *dev)
{
if (devpriv && devpriv->pcidev) {
if (dev->iobase)
comedi_pci_disable(devpriv->pcidev);
pci_dev_put(devpriv->pcidev);
}
- printk(KERN_INFO "comedi%d: " CNT_DRIVER_NAME " remove\n",
- dev->minor);
- return 0;
}
+static struct comedi_driver ke_counter_driver = {
+ .driver_name = "ke_counter",
+ .module = THIS_MODULE,
+ .attach = cnt_attach,
+ .detach = cnt_detach,
+};
+
+static int __devinit ke_counter_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, &ke_counter_driver);
+}
+
+static void __devexit ke_counter_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(ke_counter_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, ke_counter_pci_table);
+
+static struct pci_driver ke_counter_pci_driver = {
+ .name = "ke_counter",
+ .id_table = ke_counter_pci_table,
+ .probe = ke_counter_pci_probe,
+ .remove = __devexit_p(ke_counter_pci_remove),
+};
+module_comedi_pci_driver(ke_counter_driver, ke_counter_pci_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c
index b0bc6bb877ab..8ca1b54600db 100644
--- a/drivers/staging/comedi/drivers/me4000.c
+++ b/drivers/staging/comedi/drivers/me4000.c
@@ -65,30 +65,6 @@ broken.
#include "me4000_fw.h"
#endif
-/*=============================================================================
- PCI device table.
- This is used by modprobe to translate PCI IDs to drivers.
- ===========================================================================*/
-
-static DEFINE_PCI_DEVICE_TABLE(me4000_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4650) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4660) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4661) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4662) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4663) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4670) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4671) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4672) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4673) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4680) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4681) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4682) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4683) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, me4000_pci_table);
-
static const struct me4000_board me4000_boards[] = {
{"ME-4650", 0x4650, {0, 0}, {16, 0, 0, 0}, {4}, {0} },
@@ -113,22 +89,8 @@ static const struct me4000_board me4000_boards[] = {
#define ME4000_BOARD_VERSIONS (ARRAY_SIZE(me4000_boards) - 1)
/*-----------------------------------------------------------------------------
- Comedi function prototypes
- ---------------------------------------------------------------------------*/
-static int me4000_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int me4000_detach(struct comedi_device *dev);
-static struct comedi_driver driver_me4000 = {
- .driver_name = "me4000",
- .module = THIS_MODULE,
- .attach = me4000_attach,
- .detach = me4000_detach,
-};
-
-/*-----------------------------------------------------------------------------
Meilhaus function prototypes
---------------------------------------------------------------------------*/
-static int me4000_probe(struct comedi_device *dev, struct comedi_devconfig *it);
static int get_registers(struct comedi_device *dev, struct pci_dev *pci_dev_p);
static int init_board_info(struct comedi_device *dev,
struct pci_dev *pci_dev_p);
@@ -139,76 +101,10 @@ static int init_cnt_context(struct comedi_device *dev);
static int xilinx_download(struct comedi_device *dev);
static int reset_board(struct comedi_device *dev);
-static int me4000_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int me4000_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int cnt_reset(struct comedi_device *dev, unsigned int channel);
-
-static int cnt_config(struct comedi_device *dev,
- unsigned int channel, unsigned int mode);
-
-static int me4000_cnt_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int me4000_cnt_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int me4000_cnt_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int me4000_ai_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *subdevice,
- struct comedi_insn *insn, unsigned int *data);
-
-static int me4000_ai_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s);
-
-static int ai_check_chanlist(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
-
-static int ai_round_cmd_args(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd,
- unsigned int *init_ticks,
- unsigned int *scan_ticks,
- unsigned int *chan_ticks);
-
-static int ai_prepare(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd,
- unsigned int init_ticks,
- unsigned int scan_ticks, unsigned int chan_ticks);
-
static int ai_write_chanlist(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd);
-static irqreturn_t me4000_ai_isr(int irq, void *dev_id);
-
-static int me4000_ai_do_cmd_test(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
-
-static int me4000_ai_do_cmd(struct comedi_device *dev,
- struct comedi_subdevice *s);
-
-static int me4000_ao_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int me4000_ao_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
/*-----------------------------------------------------------------------------
Meilhaus inline functions
---------------------------------------------------------------------------*/
@@ -262,130 +158,6 @@ static const struct comedi_lrange me4000_ao_range = {
}
};
-static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- int result;
-
- CALL_PDEBUG("In me4000_attach()\n");
-
- result = me4000_probe(dev, it);
- if (result)
- return result;
-
- /*
- * Allocate the subdevice structures. alloc_subdevice() is a
- * convenient macro defined in comedidev.h. It relies on
- * n_subdevices being set correctly.
- */
- if (alloc_subdevices(dev, 4) < 0)
- return -ENOMEM;
-
- /*=========================================================================
- Analog input subdevice
- ========================================================================*/
-
- s = dev->subdevices + 0;
-
- if (thisboard->ai.count) {
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags =
- SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF;
- s->n_chan = thisboard->ai.count;
- s->maxdata = 0xFFFF; /* 16 bit ADC */
- s->len_chanlist = ME4000_AI_CHANNEL_LIST_COUNT;
- s->range_table = &me4000_ai_range;
- s->insn_read = me4000_ai_insn_read;
-
- if (info->irq > 0) {
- if (request_irq(info->irq, me4000_ai_isr,
- IRQF_SHARED, "ME-4000", dev)) {
- printk
- ("comedi%d: me4000: me4000_attach(): "
- "Unable to allocate irq\n", dev->minor);
- } else {
- dev->read_subdev = s;
- s->subdev_flags |= SDF_CMD_READ;
- s->cancel = me4000_ai_cancel;
- s->do_cmdtest = me4000_ai_do_cmd_test;
- s->do_cmd = me4000_ai_do_cmd;
- }
- } else {
- printk(KERN_WARNING
- "comedi%d: me4000: me4000_attach(): "
- "No interrupt available\n", dev->minor);
- }
- } else {
- s->type = COMEDI_SUBD_UNUSED;
- }
-
- /*=========================================================================
- Analog output subdevice
- ========================================================================*/
-
- s = dev->subdevices + 1;
-
- if (thisboard->ao.count) {
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITEABLE | SDF_COMMON | SDF_GROUND;
- s->n_chan = thisboard->ao.count;
- s->maxdata = 0xFFFF; /* 16 bit DAC */
- s->range_table = &me4000_ao_range;
- s->insn_write = me4000_ao_insn_write;
- s->insn_read = me4000_ao_insn_read;
- } else {
- s->type = COMEDI_SUBD_UNUSED;
- }
-
- /*=========================================================================
- Digital I/O subdevice
- ========================================================================*/
-
- s = dev->subdevices + 2;
-
- if (thisboard->dio.count) {
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = thisboard->dio.count * 8;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = me4000_dio_insn_bits;
- s->insn_config = me4000_dio_insn_config;
- } else {
- s->type = COMEDI_SUBD_UNUSED;
- }
-
- /*
- * Check for optoisolated ME-4000 version. If one the first
- * port is a fixed output port and the second is a fixed input port.
- */
- if (!me4000_inl(dev, info->dio_context.dir_reg)) {
- s->io_bits |= 0xFF;
- me4000_outl(dev, ME4000_DIO_CTRL_BIT_MODE_0,
- info->dio_context.dir_reg);
- }
-
- /*=========================================================================
- Counter subdevice
- ========================================================================*/
-
- s = dev->subdevices + 3;
-
- if (thisboard->cnt.count) {
- s->type = COMEDI_SUBD_COUNTER;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = thisboard->cnt.count;
- s->maxdata = 0xFFFF; /* 16 bit counters */
- s->insn_read = me4000_cnt_insn_read;
- s->insn_write = me4000_cnt_insn_write;
- s->insn_config = me4000_cnt_insn_config;
- } else {
- s->type = COMEDI_SUBD_UNUSED;
- }
-
- return 0;
-}
-
static int me4000_probe(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct pci_dev *pci_device = NULL;
@@ -920,22 +692,6 @@ static int reset_board(struct comedi_device *dev)
return 0;
}
-static int me4000_detach(struct comedi_device *dev)
-{
- CALL_PDEBUG("In me4000_detach()\n");
-
- if (info) {
- if (info->pci_dev_p) {
- reset_board(dev);
- if (info->plx_regbase)
- comedi_pci_disable(info->pci_dev_p);
- pci_dev_put(info->pci_dev_p);
- }
- }
-
- return 0;
-}
-
/*=============================================================================
Analog input section
===========================================================================*/
@@ -2424,43 +2180,185 @@ static int me4000_cnt_insn_write(struct comedi_device *dev,
return 1;
}
-static int __devinit driver_me4000_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- return comedi_pci_auto_config(dev, driver_me4000.driver_name);
+ struct comedi_subdevice *s;
+ int result;
+
+ CALL_PDEBUG("In me4000_attach()\n");
+
+ result = me4000_probe(dev, it);
+ if (result)
+ return result;
+
+ /*
+ * Allocate the subdevice structures. alloc_subdevice() is a
+ * convenient macro defined in comedidev.h. It relies on
+ * n_subdevices being set correctly.
+ */
+ if (alloc_subdevices(dev, 4) < 0)
+ return -ENOMEM;
+
+ /*=========================================================================
+ Analog input subdevice
+ ========================================================================*/
+
+ s = dev->subdevices + 0;
+
+ if (thisboard->ai.count) {
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags =
+ SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF;
+ s->n_chan = thisboard->ai.count;
+ s->maxdata = 0xFFFF; /* 16 bit ADC */
+ s->len_chanlist = ME4000_AI_CHANNEL_LIST_COUNT;
+ s->range_table = &me4000_ai_range;
+ s->insn_read = me4000_ai_insn_read;
+
+ if (info->irq > 0) {
+ if (request_irq(info->irq, me4000_ai_isr,
+ IRQF_SHARED, "ME-4000", dev)) {
+ printk
+ ("comedi%d: me4000: me4000_attach(): "
+ "Unable to allocate irq\n", dev->minor);
+ } else {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->cancel = me4000_ai_cancel;
+ s->do_cmdtest = me4000_ai_do_cmd_test;
+ s->do_cmd = me4000_ai_do_cmd;
+ }
+ } else {
+ printk(KERN_WARNING
+ "comedi%d: me4000: me4000_attach(): "
+ "No interrupt available\n", dev->minor);
+ }
+ } else {
+ s->type = COMEDI_SUBD_UNUSED;
+ }
+
+ /*=========================================================================
+ Analog output subdevice
+ ========================================================================*/
+
+ s = dev->subdevices + 1;
+
+ if (thisboard->ao.count) {
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITEABLE | SDF_COMMON | SDF_GROUND;
+ s->n_chan = thisboard->ao.count;
+ s->maxdata = 0xFFFF; /* 16 bit DAC */
+ s->range_table = &me4000_ao_range;
+ s->insn_write = me4000_ao_insn_write;
+ s->insn_read = me4000_ao_insn_read;
+ } else {
+ s->type = COMEDI_SUBD_UNUSED;
+ }
+
+ /*=========================================================================
+ Digital I/O subdevice
+ ========================================================================*/
+
+ s = dev->subdevices + 2;
+
+ if (thisboard->dio.count) {
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = thisboard->dio.count * 8;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = me4000_dio_insn_bits;
+ s->insn_config = me4000_dio_insn_config;
+ } else {
+ s->type = COMEDI_SUBD_UNUSED;
+ }
+
+ /*
+ * Check for optoisolated ME-4000 version. If one the first
+ * port is a fixed output port and the second is a fixed input port.
+ */
+ if (!me4000_inl(dev, info->dio_context.dir_reg)) {
+ s->io_bits |= 0xFF;
+ me4000_outl(dev, ME4000_DIO_CTRL_BIT_MODE_0,
+ info->dio_context.dir_reg);
+ }
+
+ /*=========================================================================
+ Counter subdevice
+ ========================================================================*/
+
+ s = dev->subdevices + 3;
+
+ if (thisboard->cnt.count) {
+ s->type = COMEDI_SUBD_COUNTER;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = thisboard->cnt.count;
+ s->maxdata = 0xFFFF; /* 16 bit counters */
+ s->insn_read = me4000_cnt_insn_read;
+ s->insn_write = me4000_cnt_insn_write;
+ s->insn_config = me4000_cnt_insn_config;
+ } else {
+ s->type = COMEDI_SUBD_UNUSED;
+ }
+
+ return 0;
}
-static void __devexit driver_me4000_pci_remove(struct pci_dev *dev)
+static void me4000_detach(struct comedi_device *dev)
{
- comedi_pci_auto_unconfig(dev);
+ if (info) {
+ if (info->pci_dev_p) {
+ reset_board(dev);
+ if (info->plx_regbase)
+ comedi_pci_disable(info->pci_dev_p);
+ pci_dev_put(info->pci_dev_p);
+ }
+ }
}
-static struct pci_driver driver_me4000_pci_driver = {
- .id_table = me4000_pci_table,
- .probe = &driver_me4000_pci_probe,
- .remove = __devexit_p(&driver_me4000_pci_remove)
+static struct comedi_driver me4000_driver = {
+ .driver_name = "me4000",
+ .module = THIS_MODULE,
+ .attach = me4000_attach,
+ .detach = me4000_detach,
};
-static int __init driver_me4000_init_module(void)
+static int __devinit me4000_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- int retval;
-
- retval = comedi_driver_register(&driver_me4000);
- if (retval < 0)
- return retval;
-
- driver_me4000_pci_driver.name = (char *)driver_me4000.driver_name;
- return pci_register_driver(&driver_me4000_pci_driver);
+ return comedi_pci_auto_config(dev, &me4000_driver);
}
-static void __exit driver_me4000_cleanup_module(void)
+static void __devexit me4000_pci_remove(struct pci_dev *dev)
{
- pci_unregister_driver(&driver_me4000_pci_driver);
- comedi_driver_unregister(&driver_me4000);
+ comedi_pci_auto_unconfig(dev);
}
-module_init(driver_me4000_init_module);
-module_exit(driver_me4000_cleanup_module);
+static DEFINE_PCI_DEVICE_TABLE(me4000_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4650) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4660) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4661) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4662) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4663) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4670) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4671) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4672) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4673) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4680) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4681) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4682) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4683) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, me4000_pci_table);
+
+static struct pci_driver me4000_pci_driver = {
+ .name = "me4000",
+ .id_table = me4000_pci_table,
+ .probe = me4000_pci_probe,
+ .remove = __devexit_p(me4000_pci_remove),
+};
+module_comedi_pci_driver(me4000_driver, me4000_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c
index 8b812e41c52b..ffe251250e6f 100644
--- a/drivers/staging/comedi/drivers/me_daq.c
+++ b/drivers/staging/comedi/drivers/me_daq.c
@@ -146,10 +146,6 @@ from http://www.comedi.org
#define ME_COUNTER_STARTDATA_B 0x0022 /* - | W */
#define ME_COUNTER_VALUE_B 0x0022 /* R | - */
-/* Function prototypes */
-static int me_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int me_detach(struct comedi_device *dev);
-
static const struct comedi_lrange me2000_ai_range = {
8,
{
@@ -187,14 +183,6 @@ static const struct comedi_lrange me2600_ao_range = {
}
};
-static DEFINE_PCI_DEVICE_TABLE(me_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2600_DEVICE_ID) },
- { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2000_DEVICE_ID) },
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, me_pci_table);
-
/* Board specification structure */
struct me_board {
const char *name; /* driver name */
@@ -247,51 +235,6 @@ static const struct me_board me_boards[] = {
#define me_board_nbr (sizeof(me_boards)/sizeof(struct me_board))
-static struct comedi_driver me_driver = {
- .driver_name = ME_DRIVER_NAME,
- .module = THIS_MODULE,
- .attach = me_attach,
- .detach = me_detach,
-};
-
-static int __devinit me_driver_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- return comedi_pci_auto_config(dev, me_driver.driver_name);
-}
-
-static void __devexit me_driver_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver me_driver_pci_driver = {
- .id_table = me_pci_table,
- .probe = &me_driver_pci_probe,
- .remove = __devexit_p(&me_driver_pci_remove)
-};
-
-static int __init me_driver_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&me_driver);
- if (retval < 0)
- return retval;
-
- me_driver_pci_driver.name = (char *)me_driver.driver_name;
- return pci_register_driver(&me_driver_pci_driver);
-}
-
-static void __exit me_driver_cleanup_module(void)
-{
- pci_unregister_driver(&me_driver_pci_driver);
- comedi_driver_unregister(&me_driver);
-}
-
-module_init(me_driver_init_module);
-module_exit(me_driver_cleanup_module);
-
/* Private data structure */
struct me_private_data {
struct pci_dev *pci_device;
@@ -669,12 +612,6 @@ static int me_reset(struct comedi_device *dev)
return 0;
}
-/*
- * Attach
- *
- * - Register PCI device
- * - Declare device driver capability
- */
static int me_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct pci_dev *pci_device = NULL;
@@ -869,8 +806,7 @@ found:
return 0;
}
-/* Detach */
-static int me_detach(struct comedi_device *dev)
+static void me_detach(struct comedi_device *dev)
{
if (dev_private) {
if (dev_private->me_regbase) {
@@ -882,13 +818,44 @@ static int me_detach(struct comedi_device *dev)
if (dev_private->pci_device) {
if (dev_private->plx_regbase_size)
comedi_pci_disable(dev_private->pci_device);
-
pci_dev_put(dev_private->pci_device);
}
}
- return 0;
}
+static struct comedi_driver me_daq_driver = {
+ .driver_name = "me_daq",
+ .module = THIS_MODULE,
+ .attach = me_attach,
+ .detach = me_detach,
+};
+
+static int __devinit me_daq_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, &me_daq_driver);
+}
+
+static void __devexit me_daq_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(me_daq_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2600_DEVICE_ID) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, ME2000_DEVICE_ID) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, me_daq_pci_table);
+
+static struct pci_driver me_daq_pci_driver = {
+ .name = "me_daq",
+ .id_table = me_daq_pci_table,
+ .probe = me_daq_pci_probe,
+ .remove = __devexit_p(me_daq_pci_remove),
+};
+module_comedi_pci_driver(me_daq_driver, me_daq_pci_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/mite.h b/drivers/staging/comedi/drivers/mite.h
index 999551f54c2a..83f1b27a4720 100644
--- a/drivers/staging/comedi/drivers/mite.h
+++ b/drivers/staging/comedi/drivers/mite.h
@@ -66,9 +66,9 @@ struct mite_struct {
struct pci_dev *pcidev;
resource_size_t mite_phys_addr;
- void *mite_io_addr;
+ void __iomem *mite_io_addr;
resource_size_t daq_phys_addr;
- void *daq_io_addr;
+ void __iomem *daq_io_addr;
struct mite_channel channels[MAX_MITE_DMA_CHANNELS];
short channel_allocated[MAX_MITE_DMA_CHANNELS];
diff --git a/drivers/staging/comedi/drivers/mpc624.c b/drivers/staging/comedi/drivers/mpc624.c
index dd09a6d46e5c..4304e864a4d4 100644
--- a/drivers/staging/comedi/drivers/mpc624.c
+++ b/drivers/staging/comedi/drivers/mpc624.c
@@ -148,131 +148,6 @@ static const struct comedi_lrange range_mpc624_bipolar10 = {
}
};
-/* -------------------------------------------------------------------------- */
-static int mpc624_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int mpc624_detach(struct comedi_device *dev);
-/* -------------------------------------------------------------------------- */
-static struct comedi_driver driver_mpc624 = {
- .driver_name = "mpc624",
- .module = THIS_MODULE,
- .attach = mpc624_attach,
- .detach = mpc624_detach
-};
-
-/* -------------------------------------------------------------------------- */
-static int mpc624_ai_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data);
-/* -------------------------------------------------------------------------- */
-static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- unsigned long iobase;
-
- iobase = it->options[0];
- printk(KERN_INFO "comedi%d: mpc624 [0x%04lx, ", dev->minor, iobase);
- if (request_region(iobase, MPC624_SIZE, "mpc624") == NULL) {
- printk(KERN_ERR "I/O port(s) in use\n");
- return -EIO;
- }
-
- dev->iobase = iobase;
- dev->board_name = "mpc624";
-
- /* Private structure initialization */
- if (alloc_private(dev, sizeof(struct skel_private)) < 0)
- return -ENOMEM;
-
- switch (it->options[1]) {
- case 0:
- devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz;
- printk(KERN_INFO "3.52 kHz, ");
- break;
- case 1:
- devpriv->ulConvertionRate = MPC624_SPEED_1_76_kHz;
- printk(KERN_INFO "1.76 kHz, ");
- break;
- case 2:
- devpriv->ulConvertionRate = MPC624_SPEED_880_Hz;
- printk(KERN_INFO "880 Hz, ");
- break;
- case 3:
- devpriv->ulConvertionRate = MPC624_SPEED_440_Hz;
- printk(KERN_INFO "440 Hz, ");
- break;
- case 4:
- devpriv->ulConvertionRate = MPC624_SPEED_220_Hz;
- printk(KERN_INFO "220 Hz, ");
- break;
- case 5:
- devpriv->ulConvertionRate = MPC624_SPEED_110_Hz;
- printk(KERN_INFO "110 Hz, ");
- break;
- case 6:
- devpriv->ulConvertionRate = MPC624_SPEED_55_Hz;
- printk(KERN_INFO "55 Hz, ");
- break;
- case 7:
- devpriv->ulConvertionRate = MPC624_SPEED_27_5_Hz;
- printk(KERN_INFO "27.5 Hz, ");
- break;
- case 8:
- devpriv->ulConvertionRate = MPC624_SPEED_13_75_Hz;
- printk(KERN_INFO "13.75 Hz, ");
- break;
- case 9:
- devpriv->ulConvertionRate = MPC624_SPEED_6_875_Hz;
- printk(KERN_INFO "6.875 Hz, ");
- break;
- default:
- printk
- (KERN_ERR "illegal conversion rate setting!"
- " Valid numbers are 0..9. Using 9 => 6.875 Hz, ");
- devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz;
- }
-
- /* Subdevices structures */
- if (alloc_subdevices(dev, 1) < 0)
- return -ENOMEM;
-
- s = dev->subdevices + 0;
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_DIFF;
- s->n_chan = 8;
- switch (it->options[1]) {
- default:
- s->maxdata = 0x3FFFFFFF;
- printk(KERN_INFO "30 bit, ");
- }
-
- switch (it->options[1]) {
- case 0:
- s->range_table = &range_mpc624_bipolar1;
- printk(KERN_INFO "1.01V]: ");
- break;
- default:
- s->range_table = &range_mpc624_bipolar10;
- printk(KERN_INFO "10.1V]: ");
- }
- s->len_chanlist = 1;
- s->insn_read = mpc624_ai_rinsn;
-
- printk(KERN_INFO "attached\n");
-
- return 1;
-}
-
-static int mpc624_detach(struct comedi_device *dev)
-{
- printk(KERN_INFO "comedi%d: mpc624: remove\n", dev->minor);
-
- if (dev->iobase)
- release_region(dev->iobase, MPC624_SIZE);
-
- return 0;
-}
-
/* Timeout 200ms */
#define TIMEOUT 200
@@ -406,18 +281,117 @@ static int mpc624_ai_rinsn(struct comedi_device *dev,
return n;
}
-static int __init driver_mpc624_init_module(void)
+static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- return comedi_driver_register(&driver_mpc624);
+ struct comedi_subdevice *s;
+ unsigned long iobase;
+
+ iobase = it->options[0];
+ printk(KERN_INFO "comedi%d: mpc624 [0x%04lx, ", dev->minor, iobase);
+ if (request_region(iobase, MPC624_SIZE, "mpc624") == NULL) {
+ printk(KERN_ERR "I/O port(s) in use\n");
+ return -EIO;
+ }
+
+ dev->iobase = iobase;
+ dev->board_name = "mpc624";
+
+ /* Private structure initialization */
+ if (alloc_private(dev, sizeof(struct skel_private)) < 0)
+ return -ENOMEM;
+
+ switch (it->options[1]) {
+ case 0:
+ devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz;
+ printk(KERN_INFO "3.52 kHz, ");
+ break;
+ case 1:
+ devpriv->ulConvertionRate = MPC624_SPEED_1_76_kHz;
+ printk(KERN_INFO "1.76 kHz, ");
+ break;
+ case 2:
+ devpriv->ulConvertionRate = MPC624_SPEED_880_Hz;
+ printk(KERN_INFO "880 Hz, ");
+ break;
+ case 3:
+ devpriv->ulConvertionRate = MPC624_SPEED_440_Hz;
+ printk(KERN_INFO "440 Hz, ");
+ break;
+ case 4:
+ devpriv->ulConvertionRate = MPC624_SPEED_220_Hz;
+ printk(KERN_INFO "220 Hz, ");
+ break;
+ case 5:
+ devpriv->ulConvertionRate = MPC624_SPEED_110_Hz;
+ printk(KERN_INFO "110 Hz, ");
+ break;
+ case 6:
+ devpriv->ulConvertionRate = MPC624_SPEED_55_Hz;
+ printk(KERN_INFO "55 Hz, ");
+ break;
+ case 7:
+ devpriv->ulConvertionRate = MPC624_SPEED_27_5_Hz;
+ printk(KERN_INFO "27.5 Hz, ");
+ break;
+ case 8:
+ devpriv->ulConvertionRate = MPC624_SPEED_13_75_Hz;
+ printk(KERN_INFO "13.75 Hz, ");
+ break;
+ case 9:
+ devpriv->ulConvertionRate = MPC624_SPEED_6_875_Hz;
+ printk(KERN_INFO "6.875 Hz, ");
+ break;
+ default:
+ printk
+ (KERN_ERR "illegal conversion rate setting!"
+ " Valid numbers are 0..9. Using 9 => 6.875 Hz, ");
+ devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz;
+ }
+
+ /* Subdevices structures */
+ if (alloc_subdevices(dev, 1) < 0)
+ return -ENOMEM;
+
+ s = dev->subdevices + 0;
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_DIFF;
+ s->n_chan = 8;
+ switch (it->options[1]) {
+ default:
+ s->maxdata = 0x3FFFFFFF;
+ printk(KERN_INFO "30 bit, ");
+ }
+
+ switch (it->options[1]) {
+ case 0:
+ s->range_table = &range_mpc624_bipolar1;
+ printk(KERN_INFO "1.01V]: ");
+ break;
+ default:
+ s->range_table = &range_mpc624_bipolar10;
+ printk(KERN_INFO "10.1V]: ");
+ }
+ s->len_chanlist = 1;
+ s->insn_read = mpc624_ai_rinsn;
+
+ printk(KERN_INFO "attached\n");
+
+ return 1;
}
-static void __exit driver_mpc624_cleanup_module(void)
+static void mpc624_detach(struct comedi_device *dev)
{
- comedi_driver_unregister(&driver_mpc624);
+ if (dev->iobase)
+ release_region(dev->iobase, MPC624_SIZE);
}
-module_init(driver_mpc624_init_module);
-module_exit(driver_mpc624_cleanup_module);
+static struct comedi_driver mpc624_driver = {
+ .driver_name = "mpc624",
+ .module = THIS_MODULE,
+ .attach = mpc624_attach,
+ .detach = mpc624_detach
+};
+module_comedi_driver(mpc624_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/mpc8260cpm.c b/drivers/staging/comedi/drivers/mpc8260cpm.c
index 5f6816a3fe8c..364470e4458f 100644
--- a/drivers/staging/comedi/drivers/mpc8260cpm.c
+++ b/drivers/staging/comedi/drivers/mpc8260cpm.c
@@ -46,75 +46,6 @@ struct mpc8260cpm_private {
#define devpriv ((struct mpc8260cpm_private *)dev->private)
-static int mpc8260cpm_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int mpc8260cpm_detach(struct comedi_device *dev);
-static struct comedi_driver driver_mpc8260cpm = {
- .driver_name = "mpc8260cpm",
- .module = THIS_MODULE,
- .attach = mpc8260cpm_attach,
- .detach = mpc8260cpm_detach,
-};
-
-static int __init driver_mpc8260cpm_init_module(void)
-{
- return comedi_driver_register(&driver_mpc8260cpm);
-}
-
-static void __exit driver_mpc8260cpm_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_mpc8260cpm);
-}
-
-module_init(driver_mpc8260cpm_init_module);
-module_exit(driver_mpc8260cpm_cleanup_module);
-
-static int mpc8260cpm_dio_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int mpc8260cpm_dio_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int mpc8260cpm_attach(struct comedi_device *dev,
- struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- int i;
-
- printk("comedi%d: mpc8260cpm: ", dev->minor);
-
- dev->board_ptr = mpc8260cpm_boards + dev->board;
-
- dev->board_name = thisboard->name;
-
- if (alloc_private(dev, sizeof(struct mpc8260cpm_private)) < 0)
- return -ENOMEM;
-
- if (alloc_subdevices(dev, 4) < 0)
- return -ENOMEM;
-
- for (i = 0; i < 4; i++) {
- s = dev->subdevices + i;
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 32;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_config = mpc8260cpm_dio_config;
- s->insn_bits = mpc8260cpm_dio_bits;
- }
-
- return 1;
-}
-
-static int mpc8260cpm_detach(struct comedi_device *dev)
-{
- printk("comedi%d: mpc8260cpm: remove\n", dev->minor);
-
- return 0;
-}
-
static unsigned long *cpm_pdat(int port)
{
switch (port) {
@@ -184,3 +115,48 @@ static int mpc8260cpm_dio_bits(struct comedi_device *dev,
return 2;
}
+
+static int mpc8260cpm_attach(struct comedi_device *dev,
+ struct comedi_devconfig *it)
+{
+ struct comedi_subdevice *s;
+ int i;
+
+ printk("comedi%d: mpc8260cpm: ", dev->minor);
+
+ dev->board_ptr = mpc8260cpm_boards + dev->board;
+
+ dev->board_name = thisboard->name;
+
+ if (alloc_private(dev, sizeof(struct mpc8260cpm_private)) < 0)
+ return -ENOMEM;
+
+ if (alloc_subdevices(dev, 4) < 0)
+ return -ENOMEM;
+
+ for (i = 0; i < 4; i++) {
+ s = dev->subdevices + i;
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 32;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_config = mpc8260cpm_dio_config;
+ s->insn_bits = mpc8260cpm_dio_bits;
+ }
+
+ return 1;
+}
+
+static void mpc8260cpm_detach(struct comedi_device *dev)
+{
+ /* Nothing to cleanup */
+}
+
+static struct comedi_driver mpc8260cpm_driver = {
+ .driver_name = "mpc8260cpm",
+ .module = THIS_MODULE,
+ .attach = mpc8260cpm_attach,
+ .detach = mpc8260cpm_detach,
+};
+module_comedi_driver(mpc8260cpm_driver);
diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c
index dace902d3bce..e951e73d66f5 100644
--- a/drivers/staging/comedi/drivers/multiq3.c
+++ b/drivers/staging/comedi/drivers/multiq3.c
@@ -83,29 +83,6 @@ Devices: [Quanser Consulting] MultiQ-3 (multiq3)
#define MULTIQ3_TIMEOUT 30
-static int multiq3_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int multiq3_detach(struct comedi_device *dev);
-static struct comedi_driver driver_multiq3 = {
- .driver_name = "multiq3",
- .module = THIS_MODULE,
- .attach = multiq3_attach,
- .detach = multiq3_detach,
-};
-
-static int __init driver_multiq3_init_module(void)
-{
- return comedi_driver_register(&driver_multiq3);
-}
-
-static void __exit driver_multiq3_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_multiq3);
-}
-
-module_init(driver_multiq3_init_module);
-module_exit(driver_multiq3_cleanup_module);
-
struct multiq3_private {
unsigned int ao_readback[2];
};
@@ -338,18 +315,22 @@ static int multiq3_attach(struct comedi_device *dev,
return 0;
}
-static int multiq3_detach(struct comedi_device *dev)
+static void multiq3_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: multiq3: remove\n", dev->minor);
-
if (dev->iobase)
release_region(dev->iobase, MULTIQ3_SIZE);
if (dev->irq)
free_irq(dev->irq, dev);
-
- return 0;
}
+static struct comedi_driver multiq3_driver = {
+ .driver_name = "multiq3",
+ .module = THIS_MODULE,
+ .attach = multiq3_attach,
+ .detach = multiq3_detach,
+};
+module_comedi_driver(multiq3_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c
index 54741c9e1af5..b02aa0efcd86 100644
--- a/drivers/staging/comedi/drivers/ni_6527.c
+++ b/drivers/staging/comedi/drivers/ni_6527.c
@@ -78,7 +78,7 @@ Updated: Sat, 25 Jan 2003 13:24:40 -0800
static int ni6527_attach(struct comedi_device *dev,
struct comedi_devconfig *it);
-static int ni6527_detach(struct comedi_device *dev);
+static void ni6527_detach(struct comedi_device *dev);
static struct comedi_driver driver_ni6527 = {
.driver_name = "ni6527",
.module = THIS_MODULE,
@@ -449,19 +449,15 @@ static int ni6527_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int ni6527_detach(struct comedi_device *dev)
+static void ni6527_detach(struct comedi_device *dev)
{
if (devpriv && devpriv->mite && devpriv->mite->daq_io_addr)
writeb(0x00,
devpriv->mite->daq_io_addr + Master_Interrupt_Control);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
if (devpriv && devpriv->mite)
mite_unsetup(devpriv->mite);
-
- return 0;
}
static int ni6527_find_device(struct comedi_device *dev, int bus, int slot)
@@ -493,7 +489,7 @@ static int ni6527_find_device(struct comedi_device *dev, int bus, int slot)
static int __devinit driver_ni6527_pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_ni6527.driver_name);
+ return comedi_pci_auto_config(dev, &driver_ni6527);
}
static void __devexit driver_ni6527_pci_remove(struct pci_dev *dev)
diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c
index 403fc0997d37..0d27a9323bc0 100644
--- a/drivers/staging/comedi/drivers/ni_65xx.c
+++ b/drivers/staging/comedi/drivers/ni_65xx.c
@@ -111,7 +111,7 @@ static inline unsigned Filter_Enable(unsigned port)
static int ni_65xx_attach(struct comedi_device *dev,
struct comedi_devconfig *it);
-static int ni_65xx_detach(struct comedi_device *dev);
+static void ni_65xx_detach(struct comedi_device *dev);
static struct comedi_driver driver_ni_65xx = {
.driver_name = "ni_65xx",
.module = THIS_MODULE,
@@ -784,7 +784,7 @@ static int ni_65xx_attach(struct comedi_device *dev,
return 0;
}
-static int ni_65xx_detach(struct comedi_device *dev)
+static void ni_65xx_detach(struct comedi_device *dev)
{
if (private(dev) && private(dev)->mite
&& private(dev)->mite->daq_io_addr) {
@@ -792,10 +792,8 @@ static int ni_65xx_detach(struct comedi_device *dev)
private(dev)->mite->daq_io_addr +
Master_Interrupt_Control);
}
-
if (dev->irq)
free_irq(dev->irq, dev);
-
if (private(dev)) {
unsigned i;
for (i = 0; i < dev->n_subdevices; ++i) {
@@ -805,7 +803,6 @@ static int ni_65xx_detach(struct comedi_device *dev)
if (private(dev)->mite)
mite_unsetup(private(dev)->mite);
}
- return 0;
}
static int ni_65xx_find_device(struct comedi_device *dev, int bus, int slot)
@@ -837,7 +834,7 @@ static int ni_65xx_find_device(struct comedi_device *dev, int bus, int slot)
static int __devinit driver_ni_65xx_pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_ni_65xx.driver_name);
+ return comedi_pci_auto_config(dev, &driver_ni_65xx);
}
static void __devexit driver_ni_65xx_pci_remove(struct pci_dev *dev)
diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c
index 35f3a4749825..8c40730e296a 100644
--- a/drivers/staging/comedi/drivers/ni_660x.c
+++ b/drivers/staging/comedi/drivers/ni_660x.c
@@ -458,7 +458,7 @@ static inline const struct ni_660x_board *board(struct comedi_device *dev)
static int ni_660x_attach(struct comedi_device *dev,
struct comedi_devconfig *it);
-static int ni_660x_detach(struct comedi_device *dev);
+static void ni_660x_detach(struct comedi_device *dev);
static void init_tio_chip(struct comedi_device *dev, int chipset);
static void ni_660x_select_pfi_output(struct comedi_device *dev,
unsigned pfi_channel,
@@ -474,7 +474,7 @@ static struct comedi_driver driver_ni_660x = {
static int __devinit driver_ni_660x_pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_ni_660x.driver_name);
+ return comedi_pci_auto_config(dev, &driver_ni_660x);
}
static void __devexit driver_ni_660x_pci_remove(struct pci_dev *dev)
@@ -761,7 +761,7 @@ static inline void ni_660x_write_register(struct comedi_device *dev,
unsigned chip_index, unsigned bits,
enum NI_660x_Register reg)
{
- void *const write_address =
+ void __iomem *write_address =
private(dev)->mite->daq_io_addr + GPCT_OFFSET[chip_index] +
registerData[reg].offset;
@@ -784,7 +784,7 @@ static inline unsigned ni_660x_read_register(struct comedi_device *dev,
unsigned chip_index,
enum NI_660x_Register reg)
{
- void *const read_address =
+ void __iomem *read_address =
private(dev)->mite->daq_io_addr + GPCT_OFFSET[chip_index] +
registerData[reg].offset;
@@ -1188,14 +1188,10 @@ static int ni_660x_attach(struct comedi_device *dev,
return 0;
}
-static int ni_660x_detach(struct comedi_device *dev)
+static void ni_660x_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: ni_660x: remove\n", dev->minor);
-
- /* Free irq */
if (dev->irq)
free_irq(dev->irq, dev);
-
if (dev->private) {
if (private(dev)->counter_dev)
ni_gpct_device_destroy(private(dev)->counter_dev);
@@ -1204,7 +1200,6 @@ static int ni_660x_detach(struct comedi_device *dev)
mite_unsetup(private(dev)->mite);
}
}
- return 0;
}
static int
diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c
index d8d91f90060e..a9cf94fd0c30 100644
--- a/drivers/staging/comedi/drivers/ni_670x.c
+++ b/drivers/staging/comedi/drivers/ni_670x.c
@@ -111,7 +111,7 @@ struct ni_670x_private {
static int ni_670x_attach(struct comedi_device *dev,
struct comedi_devconfig *it);
-static int ni_670x_detach(struct comedi_device *dev);
+static void ni_670x_detach(struct comedi_device *dev);
static struct comedi_driver driver_ni_670x = {
.driver_name = "ni_670x",
@@ -123,7 +123,7 @@ static struct comedi_driver driver_ni_670x = {
static int __devinit driver_ni_670x_pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_ni_670x.driver_name);
+ return comedi_pci_auto_config(dev, &driver_ni_670x);
}
static void __devexit driver_ni_670x_pci_remove(struct pci_dev *dev)
@@ -249,19 +249,13 @@ static int ni_670x_attach(struct comedi_device *dev,
return 1;
}
-static int ni_670x_detach(struct comedi_device *dev)
+static void ni_670x_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: ni_670x: remove\n", dev->minor);
-
kfree(dev->subdevices[0].range_table_list);
-
if (dev->private && devpriv->mite)
mite_unsetup(devpriv->mite);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
- return 0;
}
static int ni_670x_ao_winsn(struct comedi_device *dev,
diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c
index c25e44c1905e..ae896a094150 100644
--- a/drivers/staging/comedi/drivers/ni_at_a2150.c
+++ b/drivers/staging/comedi/drivers/ni_at_a2150.c
@@ -171,46 +171,13 @@ struct a2150_private {
#define devpriv ((struct a2150_private *)dev->private)
-static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int a2150_detach(struct comedi_device *dev);
static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-static struct comedi_driver driver_a2150 = {
- .driver_name = "ni_at_a2150",
- .module = THIS_MODULE,
- .attach = a2150_attach,
- .detach = a2150_detach,
-};
-
-static irqreturn_t a2150_interrupt(int irq, void *d);
-static int a2150_ai_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_cmd *cmd);
-static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
static int a2150_get_timing(struct comedi_device *dev, unsigned int *period,
int flags);
-static int a2150_probe(struct comedi_device *dev);
static int a2150_set_chanlist(struct comedi_device *dev,
unsigned int start_channel,
unsigned int num_channels);
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __init driver_a2150_init_module(void)
-{
- return comedi_driver_register(&driver_a2150);
-}
-
-static void __exit driver_a2150_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_a2150);
-}
-
-module_init(driver_a2150_init_module);
-module_exit(driver_a2150_cleanup_module);
-
#ifdef A2150_DEBUG
static void ni_dump_regs(struct comedi_device *dev)
@@ -331,161 +298,6 @@ static irqreturn_t a2150_interrupt(int irq, void *d)
return IRQ_HANDLED;
}
-/* probes board type, returns offset */
-static int a2150_probe(struct comedi_device *dev)
-{
- int status = inw(dev->iobase + STATUS_REG);
- return ID_BITS(status);
-}
-
-static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- unsigned long iobase = it->options[0];
- unsigned int irq = it->options[1];
- unsigned int dma = it->options[2];
- static const int timeout = 2000;
- int i;
-
- printk("comedi%d: %s: io 0x%lx", dev->minor, driver_a2150.driver_name,
- iobase);
- if (irq) {
- printk(", irq %u", irq);
- } else {
- printk(", no irq");
- }
- if (dma) {
- printk(", dma %u", dma);
- } else {
- printk(", no dma");
- }
- printk("\n");
-
- /* allocate and initialize dev->private */
- if (alloc_private(dev, sizeof(struct a2150_private)) < 0)
- return -ENOMEM;
-
- if (iobase == 0) {
- printk(" io base address required\n");
- return -EINVAL;
- }
-
- /* check if io addresses are available */
- if (!request_region(iobase, A2150_SIZE, driver_a2150.driver_name)) {
- printk(" I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
-
- /* grab our IRQ */
- if (irq) {
- /* check that irq is supported */
- if (irq < 3 || irq == 8 || irq == 13 || irq > 15) {
- printk(" invalid irq line %u\n", irq);
- return -EINVAL;
- }
- if (request_irq(irq, a2150_interrupt, 0,
- driver_a2150.driver_name, dev)) {
- printk("unable to allocate irq %u\n", irq);
- return -EINVAL;
- }
- devpriv->irq_dma_bits |= IRQ_LVL_BITS(irq);
- dev->irq = irq;
- }
- /* initialize dma */
- if (dma) {
- if (dma == 4 || dma > 7) {
- printk(" invalid dma channel %u\n", dma);
- return -EINVAL;
- }
- if (request_dma(dma, driver_a2150.driver_name)) {
- printk(" failed to allocate dma channel %u\n", dma);
- return -EINVAL;
- }
- devpriv->dma = dma;
- devpriv->dma_buffer =
- kmalloc(A2150_DMA_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
- if (devpriv->dma_buffer == NULL)
- return -ENOMEM;
-
- disable_dma(dma);
- set_dma_mode(dma, DMA_MODE_READ);
-
- devpriv->irq_dma_bits |= DMA_CHAN_BITS(dma);
- }
-
- dev->board_ptr = a2150_boards + a2150_probe(dev);
- dev->board_name = thisboard->name;
-
- if (alloc_subdevices(dev, 1) < 0)
- return -ENOMEM;
-
- /* analog input subdevice */
- s = dev->subdevices + 0;
- dev->read_subdev = s;
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_OTHER | SDF_CMD_READ;
- s->n_chan = 4;
- s->len_chanlist = 4;
- s->maxdata = 0xffff;
- s->range_table = &range_a2150;
- s->do_cmd = a2150_ai_cmd;
- s->do_cmdtest = a2150_ai_cmdtest;
- s->insn_read = a2150_ai_rinsn;
- s->cancel = a2150_cancel;
-
- /* need to do this for software counting of completed conversions, to
- * prevent hardware count from stopping acquisition */
- outw(HW_COUNT_DISABLE, dev->iobase + I8253_MODE_REG);
-
- /* set card's irq and dma levels */
- outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG);
-
- /* reset and sync adc clock circuitry */
- outw_p(DPD_BIT | APD_BIT, dev->iobase + CONFIG_REG);
- outw_p(DPD_BIT, dev->iobase + CONFIG_REG);
- /* initialize configuration register */
- devpriv->config_bits = 0;
- outw(devpriv->config_bits, dev->iobase + CONFIG_REG);
- /* wait until offset calibration is done, then enable analog inputs */
- for (i = 0; i < timeout; i++) {
- if ((DCAL_BIT & inw(dev->iobase + STATUS_REG)) == 0)
- break;
- udelay(1000);
- }
- if (i == timeout) {
- printk
- (" timed out waiting for offset calibration to complete\n");
- return -ETIME;
- }
- devpriv->config_bits |= ENABLE0_BIT | ENABLE1_BIT;
- outw(devpriv->config_bits, dev->iobase + CONFIG_REG);
-
- return 0;
-};
-
-static int a2150_detach(struct comedi_device *dev)
-{
- printk("comedi%d: %s: remove\n", dev->minor, driver_a2150.driver_name);
-
- /* only free stuff if it has been allocated by _attach */
- if (dev->iobase) {
- /* put board in power-down mode */
- outw(APD_BIT | DPD_BIT, dev->iobase + CONFIG_REG);
- release_region(dev->iobase, A2150_SIZE);
- }
-
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (devpriv) {
- if (devpriv->dma)
- free_dma(devpriv->dma);
- kfree(devpriv->dma_buffer);
- }
-
- return 0;
-};
-
static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
/* disable dma on card */
@@ -539,7 +351,10 @@ static int a2150_ai_cmdtest(struct comedi_device *dev,
if (err)
return 1;
- /* step 2: make sure trigger sources are unique and mutually compatible */
+ /*
+ * step 2: make sure trigger sources are unique and mutually
+ * compatible
+ */
if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT)
err++;
@@ -771,7 +586,10 @@ static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
/* start acquisition for soft trigger */
outw(0, dev->iobase + FIFO_START_REG);
- /* there is a 35.6 sample delay for data to get through the antialias filter */
+ /*
+ * there is a 35.6 sample delay for data to get through the
+ * antialias filter
+ */
for (n = 0; n < filter_delay; n++) {
for (i = 0; i < timeout; i++) {
if (inw(dev->iobase + STATUS_REG) & FNE_BIT)
@@ -812,8 +630,10 @@ static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
return n;
}
-/* sets bits in devpriv->clock_bits to nearest approximation of requested period,
- * adjusts requested period to actual timing. */
+/*
+ * sets bits in devpriv->clock_bits to nearest approximation of requested
+ * period, adjusts requested period to actual timing.
+ */
static int a2150_get_timing(struct comedi_device *dev, unsigned int *period,
int flags)
{
@@ -920,6 +740,162 @@ static int a2150_set_chanlist(struct comedi_device *dev,
return 0;
}
+/* probes board type, returns offset */
+static int a2150_probe(struct comedi_device *dev)
+{
+ int status = inw(dev->iobase + STATUS_REG);
+ return ID_BITS(status);
+}
+
+static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+ struct comedi_subdevice *s;
+ unsigned long iobase = it->options[0];
+ unsigned int irq = it->options[1];
+ unsigned int dma = it->options[2];
+ static const int timeout = 2000;
+ int i;
+
+ printk("comedi%d: %s: io 0x%lx", dev->minor, dev->driver->driver_name,
+ iobase);
+ if (irq) {
+ printk(", irq %u", irq);
+ } else {
+ printk(", no irq");
+ }
+ if (dma) {
+ printk(", dma %u", dma);
+ } else {
+ printk(", no dma");
+ }
+ printk("\n");
+
+ /* allocate and initialize dev->private */
+ if (alloc_private(dev, sizeof(struct a2150_private)) < 0)
+ return -ENOMEM;
+
+ if (iobase == 0) {
+ printk(" io base address required\n");
+ return -EINVAL;
+ }
+
+ /* check if io addresses are available */
+ if (!request_region(iobase, A2150_SIZE, dev->driver->driver_name)) {
+ printk(" I/O port conflict\n");
+ return -EIO;
+ }
+ dev->iobase = iobase;
+
+ /* grab our IRQ */
+ if (irq) {
+ /* check that irq is supported */
+ if (irq < 3 || irq == 8 || irq == 13 || irq > 15) {
+ printk(" invalid irq line %u\n", irq);
+ return -EINVAL;
+ }
+ if (request_irq(irq, a2150_interrupt, 0,
+ dev->driver->driver_name, dev)) {
+ printk("unable to allocate irq %u\n", irq);
+ return -EINVAL;
+ }
+ devpriv->irq_dma_bits |= IRQ_LVL_BITS(irq);
+ dev->irq = irq;
+ }
+ /* initialize dma */
+ if (dma) {
+ if (dma == 4 || dma > 7) {
+ printk(" invalid dma channel %u\n", dma);
+ return -EINVAL;
+ }
+ if (request_dma(dma, dev->driver->driver_name)) {
+ printk(" failed to allocate dma channel %u\n", dma);
+ return -EINVAL;
+ }
+ devpriv->dma = dma;
+ devpriv->dma_buffer =
+ kmalloc(A2150_DMA_BUFFER_SIZE, GFP_KERNEL | GFP_DMA);
+ if (devpriv->dma_buffer == NULL)
+ return -ENOMEM;
+
+ disable_dma(dma);
+ set_dma_mode(dma, DMA_MODE_READ);
+
+ devpriv->irq_dma_bits |= DMA_CHAN_BITS(dma);
+ }
+
+ dev->board_ptr = a2150_boards + a2150_probe(dev);
+ dev->board_name = thisboard->name;
+
+ if (alloc_subdevices(dev, 1) < 0)
+ return -ENOMEM;
+
+ /* analog input subdevice */
+ s = dev->subdevices + 0;
+ dev->read_subdev = s;
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_OTHER | SDF_CMD_READ;
+ s->n_chan = 4;
+ s->len_chanlist = 4;
+ s->maxdata = 0xffff;
+ s->range_table = &range_a2150;
+ s->do_cmd = a2150_ai_cmd;
+ s->do_cmdtest = a2150_ai_cmdtest;
+ s->insn_read = a2150_ai_rinsn;
+ s->cancel = a2150_cancel;
+
+ /* need to do this for software counting of completed conversions, to
+ * prevent hardware count from stopping acquisition */
+ outw(HW_COUNT_DISABLE, dev->iobase + I8253_MODE_REG);
+
+ /* set card's irq and dma levels */
+ outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG);
+
+ /* reset and sync adc clock circuitry */
+ outw_p(DPD_BIT | APD_BIT, dev->iobase + CONFIG_REG);
+ outw_p(DPD_BIT, dev->iobase + CONFIG_REG);
+ /* initialize configuration register */
+ devpriv->config_bits = 0;
+ outw(devpriv->config_bits, dev->iobase + CONFIG_REG);
+ /* wait until offset calibration is done, then enable analog inputs */
+ for (i = 0; i < timeout; i++) {
+ if ((DCAL_BIT & inw(dev->iobase + STATUS_REG)) == 0)
+ break;
+ udelay(1000);
+ }
+ if (i == timeout) {
+ printk
+ (" timed out waiting for offset calibration to complete\n");
+ return -ETIME;
+ }
+ devpriv->config_bits |= ENABLE0_BIT | ENABLE1_BIT;
+ outw(devpriv->config_bits, dev->iobase + CONFIG_REG);
+
+ return 0;
+};
+
+static void a2150_detach(struct comedi_device *dev)
+{
+ if (dev->iobase) {
+ outw(APD_BIT | DPD_BIT, dev->iobase + CONFIG_REG);
+ release_region(dev->iobase, A2150_SIZE);
+ }
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+ if (devpriv) {
+ if (devpriv->dma)
+ free_dma(devpriv->dma);
+ kfree(devpriv->dma_buffer);
+ }
+};
+
+static struct comedi_driver ni_at_a2150_driver = {
+ .driver_name = "ni_at_a2150",
+ .module = THIS_MODULE,
+ .attach = a2150_attach,
+ .detach = a2150_detach,
+};
+module_comedi_driver(ni_at_a2150_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c
index 138dcc2275ab..c43dd8ada1da 100644
--- a/drivers/staging/comedi/drivers/ni_at_ao.c
+++ b/drivers/staging/comedi/drivers/ni_at_ao.c
@@ -157,17 +157,6 @@ struct atao_board {
int n_ao_chans;
};
-static const struct atao_board atao_boards[] = {
- {
- .name = "ai-ao-6",
- .n_ao_chans = 6,
- },
- {
- .name = "ai-ao-10",
- .n_ao_chans = 10,
- },
-};
-
#define thisboard ((struct atao_board *)dev->board_ptr)
struct atao_private {
@@ -182,133 +171,6 @@ struct atao_private {
#define devpriv ((struct atao_private *)dev->private)
-static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int atao_detach(struct comedi_device *dev);
-static struct comedi_driver driver_atao = {
- .driver_name = "ni_at_ao",
- .module = THIS_MODULE,
- .attach = atao_attach,
- .detach = atao_detach,
- .board_name = &atao_boards[0].name,
- .offset = sizeof(struct atao_board),
- .num_names = ARRAY_SIZE(atao_boards),
-};
-
-static int __init driver_atao_init_module(void)
-{
- return comedi_driver_register(&driver_atao);
-}
-
-static void __exit driver_atao_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_atao);
-}
-
-module_init(driver_atao_init_module);
-module_exit(driver_atao_cleanup_module);
-
-static void atao_reset(struct comedi_device *dev);
-
-static int atao_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int atao_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int atao_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int atao_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int atao_calib_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int atao_calib_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- unsigned long iobase;
- int ao_unipolar;
-
- iobase = it->options[0];
- if (iobase == 0)
- iobase = 0x1c0;
- ao_unipolar = it->options[3];
-
- printk(KERN_INFO "comedi%d: ni_at_ao: 0x%04lx", dev->minor, iobase);
-
- if (!request_region(iobase, ATAO_SIZE, "ni_at_ao")) {
- printk(" I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
-
- /* dev->board_ptr = atao_probe(dev); */
-
- dev->board_name = thisboard->name;
-
- if (alloc_private(dev, sizeof(struct atao_private)) < 0)
- return -ENOMEM;
-
- if (alloc_subdevices(dev, 4) < 0)
- return -ENOMEM;
-
- s = dev->subdevices + 0;
- /* analog output subdevice */
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE;
- s->n_chan = thisboard->n_ao_chans;
- s->maxdata = (1 << 12) - 1;
- if (ao_unipolar)
- s->range_table = &range_unipolar10;
- else
- s->range_table = &range_bipolar10;
- s->insn_write = &atao_ao_winsn;
- s->insn_read = &atao_ao_rinsn;
-
- s = dev->subdevices + 1;
- /* digital i/o subdevice */
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 8;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = atao_dio_insn_bits;
- s->insn_config = atao_dio_insn_config;
-
- s = dev->subdevices + 2;
- /* caldac subdevice */
- s->type = COMEDI_SUBD_CALIB;
- s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL;
- s->n_chan = 21;
- s->maxdata = 0xff;
- s->insn_read = atao_calib_insn_read;
- s->insn_write = atao_calib_insn_write;
-
- s = dev->subdevices + 3;
- /* eeprom subdevice */
- /* s->type=COMEDI_SUBD_EEPROM; */
- s->type = COMEDI_SUBD_UNUSED;
-
- atao_reset(dev);
-
- printk(KERN_INFO "\n");
-
- return 0;
-}
-
-static int atao_detach(struct comedi_device *dev)
-{
- printk(KERN_INFO "comedi%d: atao: remove\n", dev->minor);
-
- if (dev->iobase)
- release_region(dev->iobase, ATAO_SIZE);
-
- return 0;
-}
-
static void atao_reset(struct comedi_device *dev)
{
/* This is the reset sequence described in the manual */
@@ -471,6 +333,106 @@ static int atao_calib_insn_write(struct comedi_device *dev,
return insn->n;
}
+static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+ struct comedi_subdevice *s;
+ unsigned long iobase;
+ int ao_unipolar;
+
+ iobase = it->options[0];
+ if (iobase == 0)
+ iobase = 0x1c0;
+ ao_unipolar = it->options[3];
+
+ printk(KERN_INFO "comedi%d: ni_at_ao: 0x%04lx", dev->minor, iobase);
+
+ if (!request_region(iobase, ATAO_SIZE, "ni_at_ao")) {
+ printk(" I/O port conflict\n");
+ return -EIO;
+ }
+ dev->iobase = iobase;
+
+ /* dev->board_ptr = atao_probe(dev); */
+
+ dev->board_name = thisboard->name;
+
+ if (alloc_private(dev, sizeof(struct atao_private)) < 0)
+ return -ENOMEM;
+
+ if (alloc_subdevices(dev, 4) < 0)
+ return -ENOMEM;
+
+ s = dev->subdevices + 0;
+ /* analog output subdevice */
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = thisboard->n_ao_chans;
+ s->maxdata = (1 << 12) - 1;
+ if (ao_unipolar)
+ s->range_table = &range_unipolar10;
+ else
+ s->range_table = &range_bipolar10;
+ s->insn_write = &atao_ao_winsn;
+ s->insn_read = &atao_ao_rinsn;
+
+ s = dev->subdevices + 1;
+ /* digital i/o subdevice */
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 8;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = atao_dio_insn_bits;
+ s->insn_config = atao_dio_insn_config;
+
+ s = dev->subdevices + 2;
+ /* caldac subdevice */
+ s->type = COMEDI_SUBD_CALIB;
+ s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL;
+ s->n_chan = 21;
+ s->maxdata = 0xff;
+ s->insn_read = atao_calib_insn_read;
+ s->insn_write = atao_calib_insn_write;
+
+ s = dev->subdevices + 3;
+ /* eeprom subdevice */
+ /* s->type=COMEDI_SUBD_EEPROM; */
+ s->type = COMEDI_SUBD_UNUSED;
+
+ atao_reset(dev);
+
+ printk(KERN_INFO "\n");
+
+ return 0;
+}
+
+static void atao_detach(struct comedi_device *dev)
+{
+ if (dev->iobase)
+ release_region(dev->iobase, ATAO_SIZE);
+}
+
+static const struct atao_board atao_boards[] = {
+ {
+ .name = "ai-ao-6",
+ .n_ao_chans = 6,
+ }, {
+ .name = "ai-ao-10",
+ .n_ao_chans = 10,
+ },
+};
+
+static struct comedi_driver ni_at_ao_driver = {
+ .driver_name = "ni_at_ao",
+ .module = THIS_MODULE,
+ .attach = atao_attach,
+ .detach = atao_detach,
+ .board_name = &atao_boards[0].name,
+ .offset = sizeof(struct atao_board),
+ .num_names = ARRAY_SIZE(atao_boards),
+};
+module_comedi_driver(ni_at_ao_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_atmio.c b/drivers/staging/comedi/drivers/ni_atmio.c
index 647c228abfbf..6448373878ed 100644
--- a/drivers/staging/comedi/drivers/ni_atmio.c
+++ b/drivers/staging/comedi/drivers/ni_atmio.c
@@ -343,49 +343,8 @@ static struct pnp_device_id device_ids[] = {
MODULE_DEVICE_TABLE(pnp, device_ids);
-static int ni_atmio_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int ni_atmio_detach(struct comedi_device *dev);
-static struct comedi_driver driver_atmio = {
- .driver_name = "ni_atmio",
- .module = THIS_MODULE,
- .attach = ni_atmio_attach,
- .detach = ni_atmio_detach,
-};
-
-static int __init driver_atmio_init_module(void)
-{
- return comedi_driver_register(&driver_atmio);
-}
-
-static void __exit driver_atmio_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_atmio);
-}
-
-module_init(driver_atmio_init_module);
-module_exit(driver_atmio_cleanup_module);
-
#include "ni_mio_common.c"
-static int ni_getboardtype(struct comedi_device *dev);
-
-/* clean up allocated resources */
-static int ni_atmio_detach(struct comedi_device *dev)
-{
- mio_common_detach(dev);
-
- if (dev->iobase)
- release_region(dev->iobase, NI_SIZE);
- if (dev->irq)
- free_irq(dev->irq, dev);
-
- if (devpriv->isapnp_dev)
- pnp_device_detach(devpriv->isapnp_dev);
-
- return 0;
-}
-
static int ni_isapnp_find_board(struct pnp_dev **dev)
{
struct pnp_dev *isapnp_dev = NULL;
@@ -424,6 +383,26 @@ static int ni_isapnp_find_board(struct pnp_dev **dev)
return 0;
}
+static int ni_getboardtype(struct comedi_device *dev)
+{
+ int device_id = ni_read_eeprom(dev, 511);
+ int i;
+
+ for (i = 0; i < n_ni_boards; i++) {
+ if (ni_boards[i].device_id == device_id)
+ return i;
+
+ }
+ if (device_id == 255)
+ printk(" can't find board\n");
+ else if (device_id == 0)
+ printk(" EEPROM read error (?) or device not found\n");
+ else
+ printk(" unknown device ID %d -- contact author\n", device_id);
+
+ return -1;
+}
+
static int ni_atmio_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
@@ -518,22 +497,21 @@ static int ni_atmio_attach(struct comedi_device *dev,
return 0;
}
-static int ni_getboardtype(struct comedi_device *dev)
+static void ni_atmio_detach(struct comedi_device *dev)
{
- int device_id = ni_read_eeprom(dev, 511);
- int i;
-
- for (i = 0; i < n_ni_boards; i++) {
- if (ni_boards[i].device_id == device_id)
- return i;
-
- }
- if (device_id == 255)
- printk(" can't find board\n");
- else if (device_id == 0)
- printk(" EEPROM read error (?) or device not found\n");
- else
- printk(" unknown device ID %d -- contact author\n", device_id);
-
- return -1;
+ mio_common_detach(dev);
+ if (dev->iobase)
+ release_region(dev->iobase, NI_SIZE);
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+ if (devpriv->isapnp_dev)
+ pnp_device_detach(devpriv->isapnp_dev);
}
+
+static struct comedi_driver ni_atmio_driver = {
+ .driver_name = "ni_atmio",
+ .module = THIS_MODULE,
+ .attach = ni_atmio_attach,
+ .detach = ni_atmio_detach,
+};
+module_comedi_driver(ni_atmio_driver);
diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c
index 285b933551ab..4f6145326747 100644
--- a/drivers/staging/comedi/drivers/ni_atmio16d.c
+++ b/drivers/staging/comedi/drivers/ni_atmio16d.c
@@ -110,60 +110,8 @@ struct atmio16_board_t {
int has_8255;
};
-static const struct atmio16_board_t atmio16_boards[] = {
- {
- .name = "atmio16",
- .has_8255 = 0,
- },
- {
- .name = "atmio16d",
- .has_8255 = 1,
- },
-};
-
-#define n_atmio16_boards ARRAY_SIZE(atmio16_boards)
-
#define boardtype ((const struct atmio16_board_t *)dev->board_ptr)
-/* function prototypes */
-static int atmio16d_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int atmio16d_detach(struct comedi_device *dev);
-static irqreturn_t atmio16d_interrupt(int irq, void *d);
-static int atmio16d_ai_cmdtest(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
-static int atmio16d_ai_cmd(struct comedi_device *dev,
- struct comedi_subdevice *s);
-static int atmio16d_ai_cancel(struct comedi_device *dev,
- struct comedi_subdevice *s);
-static void reset_counters(struct comedi_device *dev);
-static void reset_atmio16d(struct comedi_device *dev);
-
-/* main driver struct */
-static struct comedi_driver driver_atmio16d = {
- .driver_name = "atmio16",
- .module = THIS_MODULE,
- .attach = atmio16d_attach,
- .detach = atmio16d_detach,
- .board_name = &atmio16_boards[0].name,
- .num_names = n_atmio16_boards,
- .offset = sizeof(struct atmio16_board_t),
-};
-
-static int __init driver_atmio16d_init_module(void)
-{
- return comedi_driver_register(&driver_atmio16d);
-}
-
-static void __exit driver_atmio16d_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_atmio16d);
-}
-
-module_init(driver_atmio16d_init_module);
-module_exit(driver_atmio16d_cleanup_module);
-
/* range structs */
static const struct comedi_lrange range_atmio16d_ai_10_bipolar = { 4, {
BIP_RANGE
@@ -881,24 +829,38 @@ static int atmio16d_attach(struct comedi_device *dev,
return 0;
}
-static int atmio16d_detach(struct comedi_device *dev)
+static void atmio16d_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: atmio16d: remove\n", dev->minor);
-
if (dev->subdevices && boardtype->has_8255)
subdev_8255_cleanup(dev, dev->subdevices + 3);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
reset_atmio16d(dev);
-
if (dev->iobase)
release_region(dev->iobase, ATMIO16D_SIZE);
-
- return 0;
}
+static const struct atmio16_board_t atmio16_boards[] = {
+ {
+ .name = "atmio16",
+ .has_8255 = 0,
+ }, {
+ .name = "atmio16d",
+ .has_8255 = 1,
+ },
+};
+
+static struct comedi_driver atmio16d_driver = {
+ .driver_name = "atmio16",
+ .module = THIS_MODULE,
+ .attach = atmio16d_attach,
+ .detach = atmio16d_detach,
+ .board_name = &atmio16_boards[0].name,
+ .num_names = ARRAY_SIZE(atmio16_boards),
+ .offset = sizeof(struct atmio16_board_t),
+};
+module_comedi_driver(atmio16d_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c
index e2420123db87..75764e8d27eb 100644
--- a/drivers/staging/comedi/drivers/ni_daq_700.c
+++ b/drivers/staging/comedi/drivers/ni_daq_700.c
@@ -57,7 +57,7 @@ static struct pcmcia_device *pcmcia_cur_dev;
static int dio700_attach(struct comedi_device *dev,
struct comedi_devconfig *it);
-static int dio700_detach(struct comedi_device *dev);
+static void dio700_detach(struct comedi_device *dev);
enum dio700_bustype { pcmcia_bustype };
@@ -419,19 +419,14 @@ static int dio700_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
};
-static int dio700_detach(struct comedi_device *dev)
+static void dio700_detach(struct comedi_device *dev)
{
- printk(KERN_ERR "comedi%d: ni_daq_700: cs-remove\n", dev->minor);
-
if (dev->subdevices)
subdev_700_cleanup(dev, dev->subdevices + 0);
-
if (thisboard->bustype != pcmcia_bustype && dev->iobase)
release_region(dev->iobase, DIO700_SIZE);
if (dev->irq)
free_irq(dev->irq, dev);
-
- return 0;
};
static void dio700_config(struct pcmcia_device *link);
@@ -472,18 +467,12 @@ static int dio700_cs_attach(struct pcmcia_device *link)
static void dio700_cs_detach(struct pcmcia_device *link)
{
-
- printk(KERN_INFO "ni_daq_700: cs-detach!\n");
-
- dev_dbg(&link->dev, "dio700_cs_detach\n");
-
((struct local_info_t *)link->priv)->stop = 1;
dio700_release(link);
/* This points to the parent struct local_info_t struct */
kfree(link->priv);
-
-} /* dio700_cs_detach */
+}
static int dio700_pcmcia_config_loop(struct pcmcia_device *p_dev,
void *priv_data)
diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c
index c0423a8c3e36..493a22788637 100644
--- a/drivers/staging/comedi/drivers/ni_daq_dio24.c
+++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c
@@ -57,7 +57,7 @@ static struct pcmcia_device *pcmcia_cur_dev;
#define DIO24_SIZE 4 /* size of io region used by board */
static int dio24_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int dio24_detach(struct comedi_device *dev);
+static void dio24_detach(struct comedi_device *dev);
enum dio24_bustype { pcmcia_bustype };
@@ -168,19 +168,14 @@ static int dio24_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
};
-static int dio24_detach(struct comedi_device *dev)
+static void dio24_detach(struct comedi_device *dev)
{
- dev_info(dev->hw_dev, "comedi%d: ni_daq_dio24: remove\n", dev->minor);
-
if (dev->subdevices)
subdev_8255_cleanup(dev, dev->subdevices + 0);
-
if (thisboard->bustype != pcmcia_bustype && dev->iobase)
release_region(dev->iobase, DIO24_SIZE);
if (dev->irq)
free_irq(dev->irq, dev);
-
- return 0;
};
static void dio24_config(struct pcmcia_device *link);
@@ -221,18 +216,12 @@ static int dio24_cs_attach(struct pcmcia_device *link)
static void dio24_cs_detach(struct pcmcia_device *link)
{
-
- printk(KERN_INFO "ni_daq_dio24: HOLA SOY YO - cs-detach!\n");
-
- dev_dbg(&link->dev, "dio24_cs_detach\n");
-
((struct local_info_t *)link->priv)->stop = 1;
dio24_release(link);
/* This points to the parent local_info_t struct */
kfree(link->priv);
-
-} /* dio24_cs_detach */
+}
static int dio24_pcmcia_config_loop(struct pcmcia_device *p_dev,
void *priv_data)
diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c
index 721b2be22500..53349777246b 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.c
+++ b/drivers/staging/comedi/drivers/ni_labpc.c
@@ -805,13 +805,10 @@ static int labpc_find_device(struct comedi_device *dev, int bus, int slot)
}
#endif
-int labpc_common_detach(struct comedi_device *dev)
+void labpc_common_detach(struct comedi_device *dev)
{
- printk(KERN_ERR "comedi%d: ni_labpc: detach\n", dev->minor);
-
if (dev->subdevices)
subdev_8255_cleanup(dev, dev->subdevices + 2);
-
#ifdef CONFIG_ISA_DMA_API
/* only free stuff if it has been allocated by _attach */
kfree(devpriv->dma_buffer);
@@ -826,8 +823,6 @@ int labpc_common_detach(struct comedi_device *dev)
if (devpriv->mite)
mite_unsetup(devpriv->mite);
#endif
-
- return 0;
};
EXPORT_SYMBOL_GPL(labpc_common_detach);
@@ -2141,7 +2136,7 @@ static void write_caldac(struct comedi_device *dev, unsigned int channel,
static int __devinit driver_labpc_pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_labpc.driver_name);
+ return comedi_pci_auto_config(dev, &driver_labpc);
}
static void __devexit driver_labpc_pci_remove(struct pci_dev *dev)
diff --git a/drivers/staging/comedi/drivers/ni_labpc.h b/drivers/staging/comedi/drivers/ni_labpc.h
index 422cee58a967..e052ed3ba544 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.h
+++ b/drivers/staging/comedi/drivers/ni_labpc.h
@@ -103,7 +103,7 @@ struct labpc_private {
int labpc_common_attach(struct comedi_device *dev, unsigned long iobase,
unsigned int irq, unsigned int dma);
-int labpc_common_detach(struct comedi_device *dev);
+void labpc_common_detach(struct comedi_device *dev);
extern const int labpc_1200_is_unipolar[];
extern const int labpc_1200_ai_gain_bits[];
diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c
index ff3840544dd4..dbb61b6b3ed1 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_cs.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c
@@ -188,21 +188,13 @@ static int labpc_cs_attach(struct pcmcia_device *link)
static void labpc_cs_detach(struct pcmcia_device *link)
{
- dev_dbg(&link->dev, "labpc_cs_detach\n");
-
- /*
- If the device is currently configured and active, we won't
- actually delete it yet. Instead, it is marked so that when
- the release() function is called, that will trigger a proper
- detach().
- */
((struct local_info_t *)link->priv)->stop = 1;
labpc_release(link);
/* This points to the parent local_info_t struct (may be null) */
kfree(link->priv);
-} /* labpc_cs_detach */
+}
static int labpc_pcmcia_config_loop(struct pcmcia_device *p_dev,
void *priv_data)
diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c
index 53ec24bb6dce..b85765d266c2 100644
--- a/drivers/staging/comedi/drivers/ni_mio_cs.c
+++ b/drivers/staging/comedi/drivers/ni_mio_cs.c
@@ -227,7 +227,7 @@ static uint16_t mio_cs_win_in(struct comedi_device *dev, int addr)
static int mio_cs_attach(struct comedi_device *dev,
struct comedi_devconfig *it);
-static int mio_cs_detach(struct comedi_device *dev);
+static void mio_cs_detach(struct comedi_device *dev);
static struct comedi_driver driver_ni_mio_cs = {
.driver_name = "ni_mio_cs",
.module = THIS_MODULE,
@@ -240,18 +240,11 @@ static struct comedi_driver driver_ni_mio_cs = {
static int ni_getboardtype(struct comedi_device *dev,
struct pcmcia_device *link);
-/* clean up allocated resources */
-/* called when driver is removed */
-static int mio_cs_detach(struct comedi_device *dev)
+static void mio_cs_detach(struct comedi_device *dev)
{
mio_common_detach(dev);
-
- /* PCMCIA layer frees the IO region */
-
if (dev->irq)
free_irq(dev->irq, dev);
-
- return 0;
}
static void mio_cs_config(struct pcmcia_device *link);
@@ -276,8 +269,6 @@ static void cs_release(struct pcmcia_device *link)
static void cs_detach(struct pcmcia_device *link)
{
- DPRINTK("cs_detach(link=%p)\n", link);
-
cs_release(link);
}
diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c
index 1df8fcbcd108..37b700830e21 100644
--- a/drivers/staging/comedi/drivers/ni_pcidio.c
+++ b/drivers/staging/comedi/drivers/ni_pcidio.c
@@ -293,18 +293,9 @@ enum FPGA_Control_Bits {
#define IntEn (TransferReady|CountExpired|Waited|PrimaryTC|SecondaryTC)
#endif
-static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int nidio_detach(struct comedi_device *dev);
static int ni_pcidio_cancel(struct comedi_device *dev,
struct comedi_subdevice *s);
-static struct comedi_driver driver_pcidio = {
- .driver_name = "ni_pcidio",
- .module = THIS_MODULE,
- .attach = nidio_attach,
- .detach = nidio_detach,
-};
-
struct nidio_board {
int dev_id;
@@ -381,22 +372,6 @@ static const struct nidio_board nidio_boards[] = {
#define n_nidio_boards ARRAY_SIZE(nidio_boards)
#define this_board ((const struct nidio_board *)dev->board_ptr)
-static DEFINE_PCI_DEVICE_TABLE(ni_pcidio_pci_table) = {
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1150)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1320)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x12b0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0160)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1630)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x13c0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0400)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1250)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x17d0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1800)},
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, ni_pcidio_pci_table);
-
struct nidio96_private {
struct mite_struct *mite;
int boardtype;
@@ -414,7 +389,6 @@ static int ni_pcidio_cmdtest(struct comedi_device *dev,
static int ni_pcidio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
static int ni_pcidio_inttrig(struct comedi_device *dev,
struct comedi_subdevice *s, unsigned int trignum);
-static int nidio_find_device(struct comedi_device *dev, int bus, int slot);
static int ni_pcidio_ns_to_timer(int *nanosec, int round_mode);
static int setup_mite_dma(struct comedi_device *dev,
struct comedi_subdevice *s);
@@ -1205,6 +1179,33 @@ static int pci_6534_upload_firmware(struct comedi_device *dev, int options[])
return 0;
}
+static int nidio_find_device(struct comedi_device *dev, int bus, int slot)
+{
+ struct mite_struct *mite;
+ int i;
+
+ for (mite = mite_devices; mite; mite = mite->next) {
+ if (mite->used)
+ continue;
+ if (bus || slot) {
+ if (bus != mite->pcidev->bus->number ||
+ slot != PCI_SLOT(mite->pcidev->devfn))
+ continue;
+ }
+ for (i = 0; i < n_nidio_boards; i++) {
+ if (mite_device_id(mite) == nidio_boards[i].dev_id) {
+ dev->board_ptr = nidio_boards + i;
+ devpriv->mite = mite;
+
+ return 0;
+ }
+ }
+ }
+ printk(KERN_WARNING "no device found\n");
+ mite_list_devices();
+ return -EIO;
+}
+
static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
struct comedi_subdevice *s;
@@ -1306,7 +1307,7 @@ static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int nidio_detach(struct comedi_device *dev)
+static void nidio_detach(struct comedi_device *dev)
{
int i;
@@ -1314,10 +1315,8 @@ static int nidio_detach(struct comedi_device *dev)
for (i = 0; i < this_board->n_8255; i++)
subdev_8255_cleanup(dev, dev->subdevices + i);
}
-
if (dev->irq)
free_irq(dev->irq, dev);
-
if (devpriv) {
if (devpriv->di_mite_ring) {
mite_free_ring(devpriv->di_mite_ring);
@@ -1326,73 +1325,48 @@ static int nidio_detach(struct comedi_device *dev)
if (devpriv->mite)
mite_unsetup(devpriv->mite);
}
- return 0;
}
-static int nidio_find_device(struct comedi_device *dev, int bus, int slot)
-{
- struct mite_struct *mite;
- int i;
-
- for (mite = mite_devices; mite; mite = mite->next) {
- if (mite->used)
- continue;
- if (bus || slot) {
- if (bus != mite->pcidev->bus->number ||
- slot != PCI_SLOT(mite->pcidev->devfn))
- continue;
- }
- for (i = 0; i < n_nidio_boards; i++) {
- if (mite_device_id(mite) == nidio_boards[i].dev_id) {
- dev->board_ptr = nidio_boards + i;
- devpriv->mite = mite;
-
- return 0;
- }
- }
- }
- printk(KERN_WARNING "no device found\n");
- mite_list_devices();
- return -EIO;
-}
+static struct comedi_driver ni_pcidio_driver = {
+ .driver_name = "ni_pcidio",
+ .module = THIS_MODULE,
+ .attach = nidio_attach,
+ .detach = nidio_detach,
+};
-static int __devinit driver_pcidio_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static int __devinit ni_pcidio_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_pcidio.driver_name);
+ return comedi_pci_auto_config(dev, &ni_pcidio_driver);
}
-static void __devexit driver_pcidio_pci_remove(struct pci_dev *dev)
+static void __devexit ni_pcidio_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver driver_pcidio_pci_driver = {
- .id_table = ni_pcidio_pci_table,
- .probe = &driver_pcidio_pci_probe,
- .remove = __devexit_p(&driver_pcidio_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(ni_pcidio_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1150) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1320) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x12b0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0160) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1630) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x13c0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0400) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1250) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x17d0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1800) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, ni_pcidio_pci_table);
-static int __init driver_pcidio_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_pcidio);
- if (retval < 0)
- return retval;
-
- driver_pcidio_pci_driver.name = (char *)driver_pcidio.driver_name;
- return pci_register_driver(&driver_pcidio_pci_driver);
-}
-
-static void __exit driver_pcidio_cleanup_module(void)
-{
- pci_unregister_driver(&driver_pcidio_pci_driver);
- comedi_driver_unregister(&driver_pcidio);
-}
-
-module_init(driver_pcidio_init_module);
-module_exit(driver_pcidio_cleanup_module);
+static struct pci_driver ni_pcidio_pci_driver = {
+ .name = "ni_pcidio",
+ .id_table = ni_pcidio_pci_table,
+ .probe = ni_pcidio_pci_probe,
+ .remove = __devexit_p(ni_pcidio_pci_remove),
+};
+module_comedi_pci_driver(ni_pcidio_driver, ni_pcidio_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c
index 27baefa32b17..3974c0d98d2a 100644
--- a/drivers/staging/comedi/drivers/ni_pcimio.c
+++ b/drivers/staging/comedi/drivers/ni_pcimio.c
@@ -129,66 +129,6 @@ Bugs:
#define DRV_NAME "ni_pcimio"
-/* The following two tables must be in the same order */
-static DEFINE_PCI_DEVICE_TABLE(ni_pci_table) = {
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0162)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1170)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1180)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1190)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11b0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11c0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11d0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1270)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1330)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1340)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1350)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x14e0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x14f0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1580)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x15b0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1880)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1870)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x18b0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x18c0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2410)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2420)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2430)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2890)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x28c0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a60)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a70)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a80)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2ab0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b80)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b90)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2c80)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2ca0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70aa)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70ab)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70ac)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70af)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b4)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b6)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b7)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b8)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bc)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bd)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bf)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70c0)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70f2)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x710d)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x716c)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x716d)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717f)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x71bc)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717d)},
- {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x72e8)},
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, ni_pci_table);
-
/* These are not all the possible ao ranges for 628x boards.
They can do OFFSET +- REFERENCE where OFFSET can be
0V, 5V, APFI<0,1>, or AO<0...3> and RANGE can
@@ -1250,54 +1190,6 @@ static const struct ni_board_struct ni_boards[] = {
#define n_pcimio_boards ARRAY_SIZE(ni_boards)
-static int pcimio_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcimio_detach(struct comedi_device *dev);
-static struct comedi_driver driver_pcimio = {
- .driver_name = DRV_NAME,
- .module = THIS_MODULE,
- .attach = pcimio_attach,
- .detach = pcimio_detach,
-};
-
-static int __devinit driver_pcimio_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- return comedi_pci_auto_config(dev, driver_pcimio.driver_name);
-}
-
-static void __devexit driver_pcimio_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_pcimio_pci_driver = {
- .id_table = ni_pci_table,
- .probe = &driver_pcimio_pci_probe,
- .remove = __devexit_p(&driver_pcimio_pci_remove)
-};
-
-static int __init driver_pcimio_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_pcimio);
- if (retval < 0)
- return retval;
-
- driver_pcimio_pci_driver.name = (char *)driver_pcimio.driver_name;
- return pci_register_driver(&driver_pcimio_pci_driver);
-}
-
-static void __exit driver_pcimio_cleanup_module(void)
-{
- pci_unregister_driver(&driver_pcimio_pci_driver);
- comedi_driver_unregister(&driver_pcimio);
-}
-
-module_init(driver_pcimio_init_module);
-module_exit(driver_pcimio_cleanup_module);
-
struct ni_private {
NI_PRIVATE_COMMON};
#define devpriv ((struct ni_private *)dev->private)
@@ -1681,13 +1573,11 @@ static void init_6143(struct comedi_device *dev)
ni_writew(devpriv->ai_calib_source, Calibration_Channel_6143);
}
-/* cleans up allocated resources */
-static int pcimio_detach(struct comedi_device *dev)
+static void pcimio_detach(struct comedi_device *dev)
{
mio_common_detach(dev);
if (dev->irq)
free_irq(dev->irq, dev);
-
if (dev->private) {
mite_free_ring(devpriv->ai_mite_ring);
mite_free_ring(devpriv->ao_mite_ring);
@@ -1697,8 +1587,6 @@ static int pcimio_detach(struct comedi_device *dev)
if (devpriv->mite)
mite_unsetup(devpriv->mite);
}
-
- return 0;
}
static int pcimio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
@@ -1874,6 +1762,90 @@ static int pcimio_dio_change(struct comedi_device *dev,
return 0;
}
+static struct comedi_driver ni_pcimio_driver = {
+ .driver_name = "ni_pcimio",
+ .module = THIS_MODULE,
+ .attach = pcimio_attach,
+ .detach = pcimio_detach,
+};
+
+static int __devinit ni_pcimio_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, &ni_pcimio_driver);
+}
+
+static void __devexit ni_pcimio_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(ni_pcimio_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0162) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1170) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1180) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1190) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11b0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11c0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11d0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1270) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1330) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1340) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1350) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x14e0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x14f0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1580) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x15b0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1880) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1870) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x18b0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x18c0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2410) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2420) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2430) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2890) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x28c0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a60) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a70) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a80) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2ab0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b80) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b90) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2c80) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2ca0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70aa) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70ab) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70ac) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70af) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b4) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b6) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b7) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b8) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bc) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bd) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bf) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70c0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70f2) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x710d) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x716c) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x716d) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717f) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x71bc) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717d) },
+ { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x72e8) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, ni_pcimio_pci_table);
+
+static struct pci_driver ni_pcimio_pci_driver = {
+ .name = "ni_pcimio",
+ .id_table = ni_pcimio_pci_table,
+ .probe = ni_pcimio_pci_probe,
+ .remove = __devexit_p(ni_pcimio_pci_remove)
+};
+module_comedi_pci_driver(ni_pcimio_driver, ni_pcimio_pci_driver)
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/ni_tio_internal.h b/drivers/staging/comedi/drivers/ni_tio_internal.h
index c4ca53785832..5e00212aa022 100644
--- a/drivers/staging/comedi/drivers/ni_tio_internal.h
+++ b/drivers/staging/comedi/drivers/ni_tio_internal.h
@@ -362,8 +362,8 @@ static inline enum ni_gpct_register NITIO_Gi_ABZ_Reg(int counter_index)
return 0;
}
-static inline enum ni_gpct_register NITIO_Gi_Interrupt_Acknowledge_Reg(int
- counter_index)
+static inline enum ni_gpct_register NITIO_Gi_Interrupt_Acknowledge_Reg(
+ int counter_index)
{
switch (counter_index) {
case 0:
@@ -407,8 +407,8 @@ static inline enum ni_gpct_register NITIO_Gi_Status_Reg(int counter_index)
return 0;
}
-static inline enum ni_gpct_register NITIO_Gi_Interrupt_Enable_Reg(int
- counter_index)
+static inline enum ni_gpct_register NITIO_Gi_Interrupt_Enable_Reg(
+ int counter_index)
{
switch (counter_index) {
case 0:
@@ -472,15 +472,22 @@ enum Gi_Counting_Mode_Reg_Bits {
Gi_Index_Phase_LowA_HighB = 0x1 << Gi_Index_Phase_Bitshift,
Gi_Index_Phase_HighA_LowB = 0x2 << Gi_Index_Phase_Bitshift,
Gi_Index_Phase_HighA_HighB = 0x3 << Gi_Index_Phase_Bitshift,
- Gi_HW_Arm_Enable_Bit = 0x80, /* from m-series example code, not documented in 660x register level manual */
- Gi_660x_HW_Arm_Select_Mask = 0x7 << Gi_HW_Arm_Select_Shift, /* from m-series example code, not documented in 660x register level manual */
+ /* from m-series example code, not documented in 660x register level
+ * manual */
+ Gi_HW_Arm_Enable_Bit = 0x80,
+ /* from m-series example code, not documented in 660x register level
+ * manual */
+ Gi_660x_HW_Arm_Select_Mask = 0x7 << Gi_HW_Arm_Select_Shift,
Gi_660x_Prescale_X8_Bit = 0x1000,
Gi_M_Series_Prescale_X8_Bit = 0x2000,
Gi_M_Series_HW_Arm_Select_Mask = 0x1f << Gi_HW_Arm_Select_Shift,
- /* must be set for clocks over 40MHz, which includes synchronous counting and quadrature modes */
+ /* must be set for clocks over 40MHz, which includes synchronous
+ * counting and quadrature modes */
Gi_660x_Alternate_Sync_Bit = 0x2000,
Gi_M_Series_Alternate_Sync_Bit = 0x4000,
- Gi_660x_Prescale_X2_Bit = 0x4000, /* from m-series example code, not documented in 660x register level manual */
+ /* from m-series example code, not documented in 660x register level
+ * manual */
+ Gi_660x_Prescale_X2_Bit = 0x4000,
Gi_M_Series_Prescale_X2_Bit = 0x8000,
};
@@ -503,7 +510,8 @@ enum Gi_Mode_Bits {
Gi_Level_Gating_Bits = 0x1,
Gi_Rising_Edge_Gating_Bits = 0x2,
Gi_Falling_Edge_Gating_Bits = 0x3,
- Gi_Gate_On_Both_Edges_Bit = 0x4, /* used in conjunction with rising edge gating mode */
+ Gi_Gate_On_Both_Edges_Bit = 0x4, /* used in conjunction with
+ * rising edge gating mode */
Gi_Trigger_Mode_for_Edge_Gate_Mask = 0x18,
Gi_Edge_Gate_Starts_Stops_Bits = 0x0,
Gi_Edge_Gate_Stops_Starts_Bits = 0x8,
@@ -686,11 +694,10 @@ static inline unsigned Gi_Gate_Interrupt_Enable_Bit(unsigned counter_index)
{
unsigned bit;
- if (counter_index % 2) {
+ if (counter_index % 2)
bit = G1_Gate_Interrupt_Enable_Bit;
- } else {
+ else
bit = G0_Gate_Interrupt_Enable_Bit;
- }
return bit;
}
@@ -748,8 +755,9 @@ static inline void ni_tio_set_bits_transient(struct ni_gpct *counter,
}
/* ni_tio_set_bits( ) is for safely writing to registers whose bits may be
-twiddled in interrupt context, or whose software copy may be read in interrupt context.
-*/
+ * twiddled in interrupt context, or whose software copy may be read in
+ * interrupt context.
+ */
static inline void ni_tio_set_bits(struct ni_gpct *counter,
enum ni_gpct_register register_index,
unsigned bit_mask, unsigned bit_values)
diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c
index b44386a6b636..2e7753f988aa 100644
--- a/drivers/staging/comedi/drivers/pcl711.c
+++ b/drivers/staging/comedi/drivers/pcl711.c
@@ -148,42 +148,8 @@ struct pcl711_board {
const struct comedi_lrange *ai_range_type;
};
-static const struct pcl711_board boardtypes[] = {
- {"pcl711", 0, 0, 0, 5, 8, 1, 0, &range_bipolar5},
- {"pcl711b", 1, 0, 0, 5, 8, 1, 7, &range_pcl711b_ai},
- {"acl8112hg", 0, 1, 0, 12, 16, 2, 15, &range_acl8112hg_ai},
- {"acl8112dg", 0, 1, 1, 9, 16, 2, 15, &range_acl8112dg_ai},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl711_board))
#define this_board ((const struct pcl711_board *)dev->board_ptr)
-static int pcl711_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcl711_detach(struct comedi_device *dev);
-static struct comedi_driver driver_pcl711 = {
- .driver_name = "pcl711",
- .module = THIS_MODULE,
- .attach = pcl711_attach,
- .detach = pcl711_detach,
- .board_name = &boardtypes[0].name,
- .num_names = n_boardtypes,
- .offset = sizeof(struct pcl711_board),
-};
-
-static int __init driver_pcl711_init_module(void)
-{
- return comedi_driver_register(&driver_pcl711);
-}
-
-static void __exit driver_pcl711_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pcl711);
-}
-
-module_init(driver_pcl711_init_module);
-module_exit(driver_pcl711_cleanup_module);
-
struct pcl711_private {
int board;
@@ -513,21 +479,6 @@ static int pcl711_do_insn_bits(struct comedi_device *dev,
return 2;
}
-/* Free any resources that we have claimed */
-static int pcl711_detach(struct comedi_device *dev)
-{
- printk(KERN_INFO "comedi%d: pcl711: remove\n", dev->minor);
-
- if (dev->irq)
- free_irq(dev->irq, dev);
-
- if (dev->iobase)
- release_region(dev->iobase, PCL711_SIZE);
-
- return 0;
-}
-
-/* Initialization */
static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
int ret;
@@ -640,6 +591,32 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
+static void pcl711_detach(struct comedi_device *dev)
+{
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+ if (dev->iobase)
+ release_region(dev->iobase, PCL711_SIZE);
+}
+
+static const struct pcl711_board boardtypes[] = {
+ { "pcl711", 0, 0, 0, 5, 8, 1, 0, &range_bipolar5 },
+ { "pcl711b", 1, 0, 0, 5, 8, 1, 7, &range_pcl711b_ai },
+ { "acl8112hg", 0, 1, 0, 12, 16, 2, 15, &range_acl8112hg_ai },
+ { "acl8112dg", 0, 1, 1, 9, 16, 2, 15, &range_acl8112dg_ai },
+};
+
+static struct comedi_driver pcl711_driver = {
+ .driver_name = "pcl711",
+ .module = THIS_MODULE,
+ .attach = pcl711_attach,
+ .detach = pcl711_detach,
+ .board_name = &boardtypes[0].name,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .offset = sizeof(struct pcl711_board),
+};
+module_comedi_driver(pcl711_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl724.c b/drivers/staging/comedi/drivers/pcl724.c
index 61b075db66ef..1f66fe1c7d5e 100644
--- a/drivers/staging/comedi/drivers/pcl724.c
+++ b/drivers/staging/comedi/drivers/pcl724.c
@@ -56,10 +56,6 @@ See the source for configuration details.
/* #define PCL724_IRQ 1 no IRQ support now */
-static int pcl724_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcl724_detach(struct comedi_device *dev);
-
struct pcl724_board {
const char *name; /* board name */
@@ -71,41 +67,8 @@ struct pcl724_board {
char is_pet48;
};
-static const struct pcl724_board boardtypes[] = {
- {"pcl724", 24, 1, 0x00fc, PCL724_SIZE, 0, 0,},
- {"pcl722", 144, 6, 0x00fc, PCL722_SIZE, 1, 0,},
- {"pcl731", 48, 2, 0x9cfc, PCL731_SIZE, 0, 0,},
- {"acl7122", 144, 6, 0x9ee8, PCL722_SIZE, 1, 0,},
- {"acl7124", 24, 1, 0x00fc, PCL724_SIZE, 0, 0,},
- {"pet48dio", 48, 2, 0x9eb8, PET48_SIZE, 0, 1,},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl724_board))
#define this_board ((const struct pcl724_board *)dev->board_ptr)
-static struct comedi_driver driver_pcl724 = {
- .driver_name = "pcl724",
- .module = THIS_MODULE,
- .attach = pcl724_attach,
- .detach = pcl724_detach,
- .board_name = &boardtypes[0].name,
- .num_names = n_boardtypes,
- .offset = sizeof(struct pcl724_board),
-};
-
-static int __init driver_pcl724_init_module(void)
-{
- return comedi_driver_register(&driver_pcl724);
-}
-
-static void __exit driver_pcl724_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pcl724);
-}
-
-module_init(driver_pcl724_init_module);
-module_exit(driver_pcl724_cleanup_module);
-
static int subdev_8255_cb(int dir, int port, int data, unsigned long arg)
{
unsigned long iobase = arg;
@@ -214,25 +177,39 @@ static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int pcl724_detach(struct comedi_device *dev)
+static void pcl724_detach(struct comedi_device *dev)
{
int i;
- /* printk("comedi%d: pcl724: remove\n",dev->minor); */
-
for (i = 0; i < dev->n_subdevices; i++)
subdev_8255_cleanup(dev, dev->subdevices + i);
-
#ifdef PCL724_IRQ
if (dev->irq)
free_irq(dev->irq, dev);
#endif
-
release_region(dev->iobase, this_board->io_range);
-
- return 0;
}
+static const struct pcl724_board boardtypes[] = {
+ { "pcl724", 24, 1, 0x00fc, PCL724_SIZE, 0, 0, },
+ { "pcl722", 144, 6, 0x00fc, PCL722_SIZE, 1, 0, },
+ { "pcl731", 48, 2, 0x9cfc, PCL731_SIZE, 0, 0, },
+ { "acl7122", 144, 6, 0x9ee8, PCL722_SIZE, 1, 0, },
+ { "acl7124", 24, 1, 0x00fc, PCL724_SIZE, 0, 0, },
+ { "pet48dio", 48, 2, 0x9eb8, PET48_SIZE, 0, 1, },
+};
+
+static struct comedi_driver pcl724_driver = {
+ .driver_name = "pcl724",
+ .module = THIS_MODULE,
+ .attach = pcl724_attach,
+ .detach = pcl724_detach,
+ .board_name = &boardtypes[0].name,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .offset = sizeof(struct pcl724_board),
+};
+module_comedi_driver(pcl724_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl725.c b/drivers/staging/comedi/drivers/pcl725.c
index 24b223ca4399..83a6fa53dddd 100644
--- a/drivers/staging/comedi/drivers/pcl725.c
+++ b/drivers/staging/comedi/drivers/pcl725.c
@@ -20,29 +20,6 @@ Devices: [Advantech] PCL-725 (pcl725)
#define PCL725_DO 0
#define PCL725_DI 1
-static int pcl725_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcl725_detach(struct comedi_device *dev);
-static struct comedi_driver driver_pcl725 = {
- .driver_name = "pcl725",
- .module = THIS_MODULE,
- .attach = pcl725_attach,
- .detach = pcl725_detach,
-};
-
-static int __init driver_pcl725_init_module(void)
-{
- return comedi_driver_register(&driver_pcl725);
-}
-
-static void __exit driver_pcl725_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pcl725);
-}
-
-module_init(driver_pcl725_init_module);
-module_exit(driver_pcl725_cleanup_module);
-
static int pcl725_do_insn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
@@ -112,16 +89,20 @@ static int pcl725_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int pcl725_detach(struct comedi_device *dev)
+static void pcl725_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: pcl725: remove\n", dev->minor);
-
if (dev->iobase)
release_region(dev->iobase, PCL725_SIZE);
-
- return 0;
}
+static struct comedi_driver pcl725_driver = {
+ .driver_name = "pcl725",
+ .module = THIS_MODULE,
+ .attach = pcl725_attach,
+ .detach = pcl725_detach,
+};
+module_comedi_driver(pcl725_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c
index 897cd808eeb7..d25c30c694e3 100644
--- a/drivers/staging/comedi/drivers/pcl726.c
+++ b/drivers/staging/comedi/drivers/pcl726.c
@@ -111,10 +111,6 @@ static const struct comedi_lrange *const rangelist_728[] = {
&range_4_20mA, &range_0_20mA
};
-static int pcl726_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcl726_detach(struct comedi_device *dev);
-
struct pcl726_board {
const char *name; /* driver name */
@@ -149,32 +145,8 @@ static const struct pcl726_board boardtypes[] = {
&rangelist_728[0],},
};
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl726_board))
#define this_board ((const struct pcl726_board *)dev->board_ptr)
-static struct comedi_driver driver_pcl726 = {
- .driver_name = "pcl726",
- .module = THIS_MODULE,
- .attach = pcl726_attach,
- .detach = pcl726_detach,
- .board_name = &boardtypes[0].name,
- .num_names = n_boardtypes,
- .offset = sizeof(struct pcl726_board),
-};
-
-static int __init driver_pcl726_init_module(void)
-{
- return comedi_driver_register(&driver_pcl726);
-}
-
-static void __exit driver_pcl726_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pcl726);
-}
-
-module_init(driver_pcl726_init_module);
-module_exit(driver_pcl726_cleanup_module);
-
struct pcl726_private {
int bipolar[12];
@@ -378,21 +350,27 @@ static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int pcl726_detach(struct comedi_device *dev)
+static void pcl726_detach(struct comedi_device *dev)
{
-/* printk("comedi%d: pcl726: remove\n",dev->minor); */
-
#ifdef ACL6126_IRQ
if (dev->irq)
free_irq(dev->irq, dev);
#endif
-
if (dev->iobase)
release_region(dev->iobase, this_board->io_range);
-
- return 0;
}
+static struct comedi_driver pcl726_driver = {
+ .driver_name = "pcl726",
+ .module = THIS_MODULE,
+ .attach = pcl726_attach,
+ .detach = pcl726_detach,
+ .board_name = &boardtypes[0].name,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .offset = sizeof(struct pcl726_board),
+};
+module_comedi_driver(pcl726_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c
index c9682d614e0e..e11704addedb 100644
--- a/drivers/staging/comedi/drivers/pcl730.c
+++ b/drivers/staging/comedi/drivers/pcl730.c
@@ -26,48 +26,14 @@ The ACL-7130 card have an 8254 timer/counter not supported by this driver.
#define PCL730_DIO_LO 2 /* TTL Digital I/O low byte (D0-D7) */
#define PCL730_DIO_HI 3 /* TTL Digital I/O high byte (D8-D15) */
-static int pcl730_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcl730_detach(struct comedi_device *dev);
-
struct pcl730_board {
const char *name; /* board name */
unsigned int io_range; /* len of I/O space */
};
-static const struct pcl730_board boardtypes[] = {
- {"pcl730", PCL730_SIZE,},
- {"iso730", PCL730_SIZE,},
- {"acl7130", ACL7130_SIZE,},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl730_board))
#define this_board ((const struct pcl730_board *)dev->board_ptr)
-static struct comedi_driver driver_pcl730 = {
- .driver_name = "pcl730",
- .module = THIS_MODULE,
- .attach = pcl730_attach,
- .detach = pcl730_detach,
- .board_name = &boardtypes[0].name,
- .num_names = n_boardtypes,
- .offset = sizeof(struct pcl730_board),
-};
-
-static int __init driver_pcl730_init_module(void)
-{
- return comedi_driver_register(&driver_pcl730);
-}
-
-static void __exit driver_pcl730_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pcl730);
-}
-
-module_init(driver_pcl730_init_module);
-module_exit(driver_pcl730_cleanup_module);
-
static int pcl730_do_insn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
@@ -168,16 +134,29 @@ static int pcl730_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int pcl730_detach(struct comedi_device *dev)
+static void pcl730_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: pcl730: remove\n", dev->minor);
-
if (dev->iobase)
release_region(dev->iobase, this_board->io_range);
-
- return 0;
}
+static const struct pcl730_board boardtypes[] = {
+ { "pcl730", PCL730_SIZE, },
+ { "iso730", PCL730_SIZE, },
+ { "acl7130", ACL7130_SIZE, },
+};
+
+static struct comedi_driver pcl730_driver = {
+ .driver_name = "pcl730",
+ .module = THIS_MODULE,
+ .attach = pcl730_attach,
+ .detach = pcl730_detach,
+ .board_name = &boardtypes[0].name,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .offset = sizeof(struct pcl730_board),
+};
+module_comedi_driver(pcl730_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c
index 6fc74645af2c..51f4ca9f7927 100644
--- a/drivers/staging/comedi/drivers/pcl812.c
+++ b/drivers/staging/comedi/drivers/pcl812.c
@@ -316,10 +316,6 @@ static const struct comedi_lrange range_a821pgh_ai = { 4, {
}
};
-static int pcl812_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcl812_detach(struct comedi_device *dev);
-
struct pcl812_board {
const char *name; /* board name */
@@ -340,89 +336,8 @@ struct pcl812_board {
unsigned char haveMPC508; /* 1=board use MPC508A multiplexor */
};
-static const struct pcl812_board boardtypes[] = {
- {"pcl812", boardPCL812, 16, 0, 2, 16, 16, 0x0fff,
- 33000, 500, &range_bipolar10, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"pcl812pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
- 33000, 500, &range_pcl812pg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"acl8112pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
- 10000, 500, &range_pcl812pg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"acl8112dg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 10000, 500, &range_acl8112dg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
- {"acl8112hg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 10000, 500, &range_acl8112hg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
- {"a821pgl", boardA821, 16, 8, 1, 16, 16, 0x0fff,
- 10000, 500, &range_pcl813b_ai, &range_unipolar5,
- 0x000c, 0x00, PCLx1x_IORANGE, 0},
- {"a821pglnda", boardA821, 16, 8, 0, 0, 0, 0x0fff,
- 10000, 500, &range_pcl813b_ai, NULL,
- 0x000c, 0x00, PCLx1x_IORANGE, 0},
- {"a821pgh", boardA821, 16, 8, 1, 16, 16, 0x0fff,
- 10000, 500, &range_a821pgh_ai, &range_unipolar5,
- 0x000c, 0x00, PCLx1x_IORANGE, 0},
- {"a822pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 10000, 500, &range_acl8112dg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"a822pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 10000, 500, &range_acl8112hg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"a823pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 8000, 500, &range_acl8112dg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"a823pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
- 8000, 500, &range_acl8112hg_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
- {"pcl813", boardPCL813, 32, 0, 0, 0, 0, 0x0fff,
- 0, 0, &range_pcl813b_ai, NULL,
- 0x0000, 0x00, PCLx1x_IORANGE, 0},
- {"pcl813b", boardPCL813B, 32, 0, 0, 0, 0, 0x0fff,
- 0, 0, &range_pcl813b_ai, NULL,
- 0x0000, 0x00, PCLx1x_IORANGE, 0},
- {"acl8113", boardACL8113, 32, 0, 0, 0, 0, 0x0fff,
- 0, 0, &range_acl8113_1_ai, NULL,
- 0x0000, 0x00, PCLx1x_IORANGE, 0},
- {"iso813", boardISO813, 32, 0, 0, 0, 0, 0x0fff,
- 0, 0, &range_iso813_1_ai, NULL,
- 0x0000, 0x00, PCLx1x_IORANGE, 0},
- {"acl8216", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
- 10000, 500, &range_pcl813b2_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
- {"a826pg", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
- 10000, 500, &range_pcl813b2_ai, &range_unipolar5,
- 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl812_board))
#define this_board ((const struct pcl812_board *)dev->board_ptr)
-static struct comedi_driver driver_pcl812 = {
- .driver_name = "pcl812",
- .module = THIS_MODULE,
- .attach = pcl812_attach,
- .detach = pcl812_detach,
- .board_name = &boardtypes[0].name,
- .num_names = n_boardtypes,
- .offset = sizeof(struct pcl812_board),
-};
-
-static int __init driver_pcl812_init_module(void)
-{
- return comedi_driver_register(&driver_pcl812);
-}
-
-static void __exit driver_pcl812_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pcl812);
-}
-
-module_init(driver_pcl812_init_module);
-module_exit(driver_pcl812_cleanup_module);
-
struct pcl812_private {
unsigned char valid; /* =1 device is OK */
@@ -1356,9 +1271,6 @@ static void pcl812_reset(struct comedi_device *dev)
#endif
}
-/*
-==============================================================================
-*/
static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
int ret, subdev;
@@ -1702,19 +1614,79 @@ no_dma:
return 0;
}
-/*
-==============================================================================
- */
-static int pcl812_detach(struct comedi_device *dev)
+static void pcl812_detach(struct comedi_device *dev)
{
-
-#ifdef PCL812_EXTDEBUG
- printk(KERN_DEBUG "comedi%d: pcl812: remove\n", dev->minor);
-#endif
free_resources(dev);
- return 0;
}
+static const struct pcl812_board boardtypes[] = {
+ {"pcl812", boardPCL812, 16, 0, 2, 16, 16, 0x0fff,
+ 33000, 500, &range_bipolar10, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+ {"pcl812pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
+ 33000, 500, &range_pcl812pg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+ {"acl8112pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff,
+ 10000, 500, &range_pcl812pg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+ {"acl8112dg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+ 10000, 500, &range_acl8112dg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
+ {"acl8112hg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+ 10000, 500, &range_acl8112hg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
+ {"a821pgl", boardA821, 16, 8, 1, 16, 16, 0x0fff,
+ 10000, 500, &range_pcl813b_ai, &range_unipolar5,
+ 0x000c, 0x00, PCLx1x_IORANGE, 0},
+ {"a821pglnda", boardA821, 16, 8, 0, 0, 0, 0x0fff,
+ 10000, 500, &range_pcl813b_ai, NULL,
+ 0x000c, 0x00, PCLx1x_IORANGE, 0},
+ {"a821pgh", boardA821, 16, 8, 1, 16, 16, 0x0fff,
+ 10000, 500, &range_a821pgh_ai, &range_unipolar5,
+ 0x000c, 0x00, PCLx1x_IORANGE, 0},
+ {"a822pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+ 10000, 500, &range_acl8112dg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+ {"a822pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+ 10000, 500, &range_acl8112hg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+ {"a823pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+ 8000, 500, &range_acl8112dg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+ {"a823pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff,
+ 8000, 500, &range_acl8112hg_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+ {"pcl813", boardPCL813, 32, 0, 0, 0, 0, 0x0fff,
+ 0, 0, &range_pcl813b_ai, NULL,
+ 0x0000, 0x00, PCLx1x_IORANGE, 0},
+ {"pcl813b", boardPCL813B, 32, 0, 0, 0, 0, 0x0fff,
+ 0, 0, &range_pcl813b_ai, NULL,
+ 0x0000, 0x00, PCLx1x_IORANGE, 0},
+ {"acl8113", boardACL8113, 32, 0, 0, 0, 0, 0x0fff,
+ 0, 0, &range_acl8113_1_ai, NULL,
+ 0x0000, 0x00, PCLx1x_IORANGE, 0},
+ {"iso813", boardISO813, 32, 0, 0, 0, 0, 0x0fff,
+ 0, 0, &range_iso813_1_ai, NULL,
+ 0x0000, 0x00, PCLx1x_IORANGE, 0},
+ {"acl8216", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
+ 10000, 500, &range_pcl813b2_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 1},
+ {"a826pg", boardACL8216, 16, 8, 2, 16, 16, 0xffff,
+ 10000, 500, &range_pcl813b2_ai, &range_unipolar5,
+ 0xdcfc, 0x0a, PCLx1x_IORANGE, 0},
+};
+
+static struct comedi_driver pcl812_driver = {
+ .driver_name = "pcl812",
+ .module = THIS_MODULE,
+ .attach = pcl812_attach,
+ .detach = pcl812_detach,
+ .board_name = &boardtypes[0].name,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .offset = sizeof(struct pcl812_board),
+};
+module_comedi_driver(pcl812_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c
index 96cd7ec2ad53..cc67b6d46059 100644
--- a/drivers/staging/comedi/drivers/pcl816.c
+++ b/drivers/staging/comedi/drivers/pcl816.c
@@ -125,63 +125,14 @@ struct pcl816_board {
int i8254_osc_base; /* 1/frequency of on board oscilator in ns */
};
-static const struct pcl816_board boardtypes[] = {
- {"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816,
- &range_pcl816, PCLx1x_RANGE,
- 0x00fc, /* IRQ mask */
- 0x0a, /* DMA mask */
- 0xffff, /* 16-bit card */
- 0xffff, /* D/A maxdata */
- 1024,
- 1, /* ao chan list */
- 100},
- {"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816,
- &range_pcl816, PCLx1x_RANGE,
- 0x00fc,
- 0x0a,
- 0x3fff, /* 14 bit card */
- 0x3fff,
- 1024,
- 1,
- 100},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl816_board))
#define devpriv ((struct pcl816_private *)dev->private)
#define this_board ((const struct pcl816_board *)dev->board_ptr)
-static int pcl816_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcl816_detach(struct comedi_device *dev);
-
#ifdef unused
static int RTC_lock; /* RTC lock */
static int RTC_timer_lock; /* RTC int lock */
#endif
-static struct comedi_driver driver_pcl816 = {
- .driver_name = "pcl816",
- .module = THIS_MODULE,
- .attach = pcl816_attach,
- .detach = pcl816_detach,
- .board_name = &boardtypes[0].name,
- .num_names = n_boardtypes,
- .offset = sizeof(struct pcl816_board),
-};
-
-static int __init driver_pcl816_init_module(void)
-{
- return comedi_driver_register(&driver_pcl816);
-}
-
-static void __exit driver_pcl816_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pcl816);
-}
-
-module_init(driver_pcl816_init_module);
-module_exit(driver_pcl816_cleanup_module);
-
struct pcl816_private {
unsigned int dma; /* used DMA, 0=don't use DMA */
@@ -1075,46 +1026,6 @@ static int set_rtc_irq_bit(unsigned char bit)
}
#endif
-/*
-==============================================================================
- Free any resources that we have claimed
-*/
-static void free_resources(struct comedi_device *dev)
-{
- /* printk("free_resource()\n"); */
- if (dev->private) {
- pcl816_ai_cancel(dev, devpriv->sub_ai);
- pcl816_reset(dev);
- if (devpriv->dma)
- free_dma(devpriv->dma);
- if (devpriv->dmabuf[0])
- free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
- if (devpriv->dmabuf[1])
- free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
-#ifdef unused
- if (devpriv->rtc_irq)
- free_irq(devpriv->rtc_irq, dev);
- if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
- if (devpriv->rtc_iobase)
- release_region(devpriv->rtc_iobase,
- devpriv->rtc_iosize);
- }
-#endif
- }
-
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->iobase)
- release_region(dev->iobase, this_board->io_range);
- /* printk("free_resource() end\n"); */
-}
-
-/*
-==============================================================================
-
- Initialization
-
-*/
static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
int ret;
@@ -1340,21 +1251,69 @@ case COMEDI_SUBD_DO:
return 0;
}
-/*
-==============================================================================
- Removes device
- */
-static int pcl816_detach(struct comedi_device *dev)
+static void pcl816_detach(struct comedi_device *dev)
{
- DEBUG(printk(KERN_INFO "comedi%d: pcl816: remove\n", dev->minor);)
- free_resources(dev);
+ if (dev->private) {
+ pcl816_ai_cancel(dev, devpriv->sub_ai);
+ pcl816_reset(dev);
+ if (devpriv->dma)
+ free_dma(devpriv->dma);
+ if (devpriv->dmabuf[0])
+ free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
+ if (devpriv->dmabuf[1])
+ free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
+#ifdef unused
+ if (devpriv->rtc_irq)
+ free_irq(devpriv->rtc_irq, dev);
+ if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
+ if (devpriv->rtc_iobase)
+ release_region(devpriv->rtc_iobase,
+ devpriv->rtc_iosize);
+ }
+#endif
+ }
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+ if (dev->iobase)
+ release_region(dev->iobase, this_board->io_range);
#ifdef unused
if (devpriv->dma_rtc)
RTC_lock--;
#endif
- return 0;
}
+static const struct pcl816_board boardtypes[] = {
+ {"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816,
+ &range_pcl816, PCLx1x_RANGE,
+ 0x00fc, /* IRQ mask */
+ 0x0a, /* DMA mask */
+ 0xffff, /* 16-bit card */
+ 0xffff, /* D/A maxdata */
+ 1024,
+ 1, /* ao chan list */
+ 100},
+ {"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816,
+ &range_pcl816, PCLx1x_RANGE,
+ 0x00fc,
+ 0x0a,
+ 0x3fff, /* 14 bit card */
+ 0x3fff,
+ 1024,
+ 1,
+ 100},
+};
+
+static struct comedi_driver pcl816_driver = {
+ .driver_name = "pcl816",
+ .module = THIS_MODULE,
+ .attach = pcl816_attach,
+ .detach = pcl816_detach,
+ .board_name = &boardtypes[0].name,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .offset = sizeof(struct pcl816_board),
+};
+module_comedi_driver(pcl816_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c
index 7344a53a81c4..1406c9720f5d 100644
--- a/drivers/staging/comedi/drivers/pcl818.c
+++ b/drivers/staging/comedi/drivers/pcl818.c
@@ -247,10 +247,6 @@ static const struct comedi_lrange range718_bipolar0_5 =
static const struct comedi_lrange range718_unipolar2 = { 1, {UNI_RANGE(2),} };
static const struct comedi_lrange range718_unipolar1 = { 1, {BIP_RANGE(1),} };
-static int pcl818_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcl818_detach(struct comedi_device *dev);
-
#ifdef unused
static int RTC_lock; /* RTC lock */
static int RTC_timer_lock; /* RTC int lock */
@@ -277,56 +273,6 @@ struct pcl818_board {
int is_818;
};
-static const struct pcl818_board boardtypes[] = {
- {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 0, 1},
- {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 0, 1},
- {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 1, 1},
- {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 1, 1},
- {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 0, 1},
- {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 0, 0},
- /* pcm3718 */
- {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai,
- &range_unipolar5, PCLx1x_RANGE, 0x00fc,
- 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl818_board))
-
-static struct comedi_driver driver_pcl818 = {
- .driver_name = "pcl818",
- .module = THIS_MODULE,
- .attach = pcl818_attach,
- .detach = pcl818_detach,
- .board_name = &boardtypes[0].name,
- .num_names = n_boardtypes,
- .offset = sizeof(struct pcl818_board),
-};
-
-static int __init driver_pcl818_init_module(void)
-{
- return comedi_driver_register(&driver_pcl818);
-}
-
-static void __exit driver_pcl818_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pcl818);
-}
-
-module_init(driver_pcl818_init_module);
-module_exit(driver_pcl818_cleanup_module);
-
struct pcl818_private {
unsigned int dma; /* used DMA, 0=don't use DMA */
@@ -1688,48 +1634,6 @@ static int rtc_setfreq_irq(int freq)
}
#endif
-/*
-==============================================================================
- Free any resources that we have claimed
-*/
-static void free_resources(struct comedi_device *dev)
-{
- /* printk("free_resource()\n"); */
- if (dev->private) {
- pcl818_ai_cancel(dev, devpriv->sub_ai);
- pcl818_reset(dev);
- if (devpriv->dma)
- free_dma(devpriv->dma);
- if (devpriv->dmabuf[0])
- free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
- if (devpriv->dmabuf[1])
- free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
-#ifdef unused
- if (devpriv->rtc_irq)
- free_irq(devpriv->rtc_irq, dev);
- if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
- if (devpriv->rtc_iobase)
- release_region(devpriv->rtc_iobase,
- devpriv->rtc_iosize);
- }
- if (devpriv->dma_rtc)
- RTC_lock--;
-#endif
- }
-
- if (dev->irq)
- free_irq(dev->irq, dev);
- if (dev->iobase)
- release_region(dev->iobase, devpriv->io_range);
- /* printk("free_resource() end\n"); */
-}
-
-/*
-==============================================================================
-
- Initialization
-
-*/
static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
int ret;
@@ -2020,17 +1924,71 @@ no_dma:
return 0;
}
-/*
-==============================================================================
- Removes device
- */
-static int pcl818_detach(struct comedi_device *dev)
+static void pcl818_detach(struct comedi_device *dev)
{
- /* printk("comedi%d: pcl818: remove\n", dev->minor); */
- free_resources(dev);
- return 0;
+ if (dev->private) {
+ pcl818_ai_cancel(dev, devpriv->sub_ai);
+ pcl818_reset(dev);
+ if (devpriv->dma)
+ free_dma(devpriv->dma);
+ if (devpriv->dmabuf[0])
+ free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]);
+ if (devpriv->dmabuf[1])
+ free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]);
+#ifdef unused
+ if (devpriv->rtc_irq)
+ free_irq(devpriv->rtc_irq, dev);
+ if ((devpriv->dma_rtc) && (RTC_lock == 1)) {
+ if (devpriv->rtc_iobase)
+ release_region(devpriv->rtc_iobase,
+ devpriv->rtc_iosize);
+ }
+ if (devpriv->dma_rtc)
+ RTC_lock--;
+#endif
+ }
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+ if (dev->iobase)
+ release_region(dev->iobase, devpriv->io_range);
}
+static const struct pcl818_board boardtypes[] = {
+ {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai,
+ &range_unipolar5, PCLx1x_RANGE, 0x00fc,
+ 0x0a, 0xfff, 0xfff, 0, 1},
+ {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
+ &range_unipolar5, PCLx1x_RANGE, 0x00fc,
+ 0x0a, 0xfff, 0xfff, 0, 1},
+ {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai,
+ &range_unipolar5, PCLx1x_RANGE, 0x00fc,
+ 0x0a, 0xfff, 0xfff, 1, 1},
+ {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai,
+ &range_unipolar5, PCLx1x_RANGE, 0x00fc,
+ 0x0a, 0xfff, 0xfff, 1, 1},
+ {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai,
+ &range_unipolar5, PCLx1x_RANGE, 0x00fc,
+ 0x0a, 0xfff, 0xfff, 0, 1},
+ {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5,
+ &range_unipolar5, PCLx1x_RANGE, 0x00fc,
+ 0x0a, 0xfff, 0xfff, 0, 0},
+ /* pcm3718 */
+ {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai,
+ &range_unipolar5, PCLx1x_RANGE, 0x00fc,
+ 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ },
+};
+
+static struct comedi_driver pcl818_driver = {
+ .driver_name = "pcl818",
+ .module = THIS_MODULE,
+ .attach = pcl818_attach,
+ .detach = pcl818_detach,
+ .board_name = &boardtypes[0].name,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .offset = sizeof(struct pcl818_board),
+};
+module_comedi_driver(pcl818_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/staging/comedi/drivers/pcm3724.c
index f5c0bd17684c..7492b8f1d499 100644
--- a/drivers/staging/comedi/drivers/pcm3724.c
+++ b/drivers/staging/comedi/drivers/pcm3724.c
@@ -62,10 +62,6 @@ Copy/pasted/hacked from pcm724.c
#define CR_A_MODE(a) ((a)<<5)
#define CR_CW 0x80
-static int pcm3724_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcm3724_detach(struct comedi_device *dev);
-
struct pcm3724_board {
const char *name; /* driver name */
int dio; /* num of DIO */
@@ -80,36 +76,8 @@ struct priv_pcm3724 {
int dio_2;
};
-static const struct pcm3724_board boardtypes[] = {
- {"pcm3724", 48, 2, 0x00fc, PCM3724_SIZE,},
-};
-
-#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcm3724_board))
#define this_board ((const struct pcm3724_board *)dev->board_ptr)
-static struct comedi_driver driver_pcm3724 = {
- .driver_name = "pcm3724",
- .module = THIS_MODULE,
- .attach = pcm3724_attach,
- .detach = pcm3724_detach,
- .board_name = &boardtypes[0].name,
- .num_names = n_boardtypes,
- .offset = sizeof(struct pcm3724_board),
-};
-
-static int __init driver_pcm3724_init_module(void)
-{
- return comedi_driver_register(&driver_pcm3724);
-}
-
-static void __exit driver_pcm3724_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pcm3724);
-}
-
-module_init(driver_pcm3724_init_module);
-module_exit(driver_pcm3724_cleanup_module);
-
/* (setq c-basic-offset 8) */
static int subdev_8255_cb(int dir, int port, int data, unsigned long arg)
@@ -305,7 +273,7 @@ static int pcm3724_attach(struct comedi_device *dev,
return 0;
}
-static int pcm3724_detach(struct comedi_device *dev)
+static void pcm3724_detach(struct comedi_device *dev)
{
int i;
@@ -315,10 +283,23 @@ static int pcm3724_detach(struct comedi_device *dev)
}
if (dev->iobase)
release_region(dev->iobase, this_board->io_range);
-
- return 0;
}
+static const struct pcm3724_board boardtypes[] = {
+ { "pcm3724", 48, 2, 0x00fc, PCM3724_SIZE, },
+};
+
+static struct comedi_driver pcm3724_driver = {
+ .driver_name = "pcm3724",
+ .module = THIS_MODULE,
+ .attach = pcm3724_attach,
+ .detach = pcm3724_detach,
+ .board_name = &boardtypes[0].name,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .offset = sizeof(struct pcm3724_board),
+};
+module_comedi_driver(pcm3724_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcm3730.c b/drivers/staging/comedi/drivers/pcm3730.c
index bada6b236ff1..f8d1c644daf8 100644
--- a/drivers/staging/comedi/drivers/pcm3730.c
+++ b/drivers/staging/comedi/drivers/pcm3730.c
@@ -28,29 +28,6 @@ Configuration options:
#define PCM3730_DIB 2
#define PCM3730_DIC 3
-static int pcm3730_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcm3730_detach(struct comedi_device *dev);
-static struct comedi_driver driver_pcm3730 = {
- .driver_name = "pcm3730",
- .module = THIS_MODULE,
- .attach = pcm3730_attach,
- .detach = pcm3730_detach,
-};
-
-static int __init driver_pcm3730_init_module(void)
-{
- return comedi_driver_register(&driver_pcm3730);
-}
-
-static void __exit driver_pcm3730_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pcm3730);
-}
-
-module_init(driver_pcm3730_init_module);
-module_exit(driver_pcm3730_cleanup_module);
-
static int pcm3730_do_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
@@ -156,16 +133,20 @@ static int pcm3730_attach(struct comedi_device *dev,
return 0;
}
-static int pcm3730_detach(struct comedi_device *dev)
+static void pcm3730_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: pcm3730: remove\n", dev->minor);
-
if (dev->iobase)
release_region(dev->iobase, PCM3730_SIZE);
-
- return 0;
}
+static struct comedi_driver pcm3730_driver = {
+ .driver_name = "pcm3730",
+ .module = THIS_MODULE,
+ .attach = pcm3730_attach,
+ .detach = pcm3730_detach,
+};
+module_comedi_driver(pcm3730_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c
index 23b3d777340c..1ec7d5cb346a 100644
--- a/drivers/staging/comedi/drivers/pcmad.c
+++ b/drivers/staging/comedi/drivers/pcmad.c
@@ -57,19 +57,8 @@ struct pcmad_board_struct {
const char *name;
int n_ai_bits;
};
-static const struct pcmad_board_struct pcmad_boards[] = {
- {
- .name = "pcmad12",
- .n_ai_bits = 12,
- },
- {
- .name = "pcmad16",
- .n_ai_bits = 16,
- },
-};
#define this_board ((const struct pcmad_board_struct *)(dev->board_ptr))
-#define n_pcmad_boards ARRAY_SIZE(pcmad_boards)
struct pcmad_priv_struct {
int differential;
@@ -77,31 +66,6 @@ struct pcmad_priv_struct {
};
#define devpriv ((struct pcmad_priv_struct *)dev->private)
-static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int pcmad_detach(struct comedi_device *dev);
-static struct comedi_driver driver_pcmad = {
- .driver_name = "pcmad",
- .module = THIS_MODULE,
- .attach = pcmad_attach,
- .detach = pcmad_detach,
- .board_name = &pcmad_boards[0].name,
- .num_names = n_pcmad_boards,
- .offset = sizeof(pcmad_boards[0]),
-};
-
-static int __init driver_pcmad_init_module(void)
-{
- return comedi_driver_register(&driver_pcmad);
-}
-
-static void __exit driver_pcmad_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_pcmad);
-}
-
-module_init(driver_pcmad_init_module);
-module_exit(driver_pcmad_cleanup_module);
-
#define TIMEOUT 100
static int pcmad_ai_insn_read(struct comedi_device *dev,
@@ -175,19 +139,34 @@ static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int pcmad_detach(struct comedi_device *dev)
+static void pcmad_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: pcmad: remove\n", dev->minor);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
if (dev->iobase)
release_region(dev->iobase, PCMAD_SIZE);
-
- return 0;
}
+static const struct pcmad_board_struct pcmad_boards[] = {
+ {
+ .name = "pcmad12",
+ .n_ai_bits = 12,
+ }, {
+ .name = "pcmad16",
+ .n_ai_bits = 16,
+ },
+};
+static struct comedi_driver pcmad_driver = {
+ .driver_name = "pcmad",
+ .module = THIS_MODULE,
+ .attach = pcmad_attach,
+ .detach = pcmad_detach,
+ .board_name = &pcmad_boards[0].name,
+ .num_names = ARRAY_SIZE(pcmad_boards),
+ .offset = sizeof(pcmad_boards[0]),
+};
+module_comedi_driver(pcmad_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/pcmda12.c b/drivers/staging/comedi/drivers/pcmda12.c
index 0e9ffa28d745..4786148b4fd0 100644
--- a/drivers/staging/comedi/drivers/pcmda12.c
+++ b/drivers/staging/comedi/drivers/pcmda12.c
@@ -80,12 +80,6 @@ static const struct comedi_lrange pcmda12_ranges = {
}
};
-static const struct pcmda12_board pcmda12_boards[] = {
- {
- .name = "pcmda12",
- },
-};
-
/*
* Useful for shorthand access to the particular board structure
*/
@@ -99,137 +93,6 @@ struct pcmda12_private {
#define devpriv ((struct pcmda12_private *)(dev->private))
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int pcmda12_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcmda12_detach(struct comedi_device *dev);
-
-static void zero_chans(struct comedi_device *dev);
-
-static struct comedi_driver driver = {
- .driver_name = "pcmda12",
- .module = THIS_MODULE,
- .attach = pcmda12_attach,
- .detach = pcmda12_detach,
-/* It is not necessary to implement the following members if you are
- * writing a driver for a ISA PnP or PCI card */
- /* Most drivers will support multiple types of boards by
- * having an array of board structures. These were defined
- * in pcmda12_boards[] above. Note that the element 'name'
- * was first in the structure -- Comedi uses this fact to
- * extract the name of the board without knowing any details
- * about the structure except for its length.
- * When a device is attached (by comedi_config), the name
- * of the device is given to Comedi, and Comedi tries to
- * match it by going through the list of board names. If
- * there is a match, the address of the pointer is put
- * into dev->board_ptr and driver->attach() is called.
- *
- * Note that these are not necessary if you can determine
- * the type of board in software. ISA PnP, PCI, and PCMCIA
- * devices are such boards.
- */
- .board_name = &pcmda12_boards[0].name,
- .offset = sizeof(struct pcmda12_board),
- .num_names = ARRAY_SIZE(pcmda12_boards),
-};
-
-static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board. If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int pcmda12_attach(struct comedi_device *dev,
- struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- unsigned long iobase;
-
- iobase = it->options[0];
- printk(KERN_INFO
- "comedi%d: %s: io: %lx %s ", dev->minor, driver.driver_name,
- iobase, it->options[1] ? "simultaneous xfer mode enabled" : "");
-
- if (!request_region(iobase, IOSIZE, driver.driver_name)) {
- printk("I/O port conflict\n");
- return -EIO;
- }
- dev->iobase = iobase;
-
-/*
- * Initialize dev->board_name. Note that we can use the "thisboard"
- * macro now, since we just initialized it in the last line.
- */
- dev->board_name = thisboard->name;
-
-/*
- * Allocate the private structure area. alloc_private() is a
- * convenient macro defined in comedidev.h.
- */
- if (alloc_private(dev, sizeof(struct pcmda12_private)) < 0) {
- printk(KERN_ERR "cannot allocate private data structure\n");
- return -ENOMEM;
- }
-
- devpriv->simultaneous_xfer_mode = it->options[1];
-
- /*
- * Allocate the subdevice structures. alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- *
- * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
- * 96-channel version of the board.
- */
- if (alloc_subdevices(dev, 1) < 0) {
- printk(KERN_ERR "cannot allocate subdevice data structures\n");
- return -ENOMEM;
- }
-
- s = dev->subdevices;
- s->private = NULL;
- s->maxdata = (0x1 << BITS) - 1;
- s->range_table = &pcmda12_ranges;
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = CHANS;
- s->insn_write = &ao_winsn;
- s->insn_read = &ao_rinsn;
-
- zero_chans(dev); /* clear out all the registers, basically */
-
- printk(KERN_INFO "attached\n");
-
- return 1;
-}
-
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pcmda12_detach(struct comedi_device *dev)
-{
- printk(KERN_INFO
- "comedi%d: %s: remove\n", dev->minor, driver.driver_name);
- if (dev->iobase)
- release_region(dev->iobase, IOSIZE);
- return 0;
-}
-
static void zero_chans(struct comedi_device *dev)
{ /* sets up an
ASIC chip to defaults */
@@ -301,22 +164,91 @@ static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
return i;
}
+static int pcmda12_attach(struct comedi_device *dev,
+ struct comedi_devconfig *it)
+{
+ struct comedi_subdevice *s;
+ unsigned long iobase;
+
+ iobase = it->options[0];
+ printk(KERN_INFO
+ "comedi%d: %s: io: %lx %s ", dev->minor, dev->driver->driver_name,
+ iobase, it->options[1] ? "simultaneous xfer mode enabled" : "");
+
+ if (!request_region(iobase, IOSIZE, dev->driver->driver_name)) {
+ printk("I/O port conflict\n");
+ return -EIO;
+ }
+ dev->iobase = iobase;
+
/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
+ * Initialize dev->board_name. Note that we can use the "thisboard"
+ * macro now, since we just initialized it in the last line.
*/
-static int __init driver_init_module(void)
-{
- return comedi_driver_register(&driver);
+ dev->board_name = thisboard->name;
+
+/*
+ * Allocate the private structure area. alloc_private() is a
+ * convenient macro defined in comedidev.h.
+ */
+ if (alloc_private(dev, sizeof(struct pcmda12_private)) < 0) {
+ printk(KERN_ERR "cannot allocate private data structure\n");
+ return -ENOMEM;
+ }
+
+ devpriv->simultaneous_xfer_mode = it->options[1];
+
+ /*
+ * Allocate the subdevice structures. alloc_subdevice() is a
+ * convenient macro defined in comedidev.h.
+ *
+ * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
+ * 96-channel version of the board.
+ */
+ if (alloc_subdevices(dev, 1) < 0) {
+ printk(KERN_ERR "cannot allocate subdevice data structures\n");
+ return -ENOMEM;
+ }
+
+ s = dev->subdevices;
+ s->private = NULL;
+ s->maxdata = (0x1 << BITS) - 1;
+ s->range_table = &pcmda12_ranges;
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = CHANS;
+ s->insn_write = &ao_winsn;
+ s->insn_read = &ao_rinsn;
+
+ zero_chans(dev); /* clear out all the registers, basically */
+
+ printk(KERN_INFO "attached\n");
+
+ return 1;
}
-static void __exit driver_cleanup_module(void)
+static void pcmda12_detach(struct comedi_device *dev)
{
- comedi_driver_unregister(&driver);
+ if (dev->iobase)
+ release_region(dev->iobase, IOSIZE);
}
-module_init(driver_init_module);
-module_exit(driver_cleanup_module);
+static const struct pcmda12_board pcmda12_boards[] = {
+ {
+ .name = "pcmda12",
+ },
+};
+
+static struct comedi_driver pcmda12_driver = {
+ .driver_name = "pcmda12",
+ .module = THIS_MODULE,
+ .attach = pcmda12_attach,
+ .detach = pcmda12_detach,
+ .board_name = &pcmda12_boards[0].name,
+ .offset = sizeof(struct pcmda12_board),
+ .num_names = ARRAY_SIZE(pcmda12_boards),
+};
+module_comedi_driver(pcmda12_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c
index eddac00e4e29..efed168d2bac 100644
--- a/drivers/staging/comedi/drivers/pcmmio.c
+++ b/drivers/staging/comedi/drivers/pcmmio.c
@@ -145,13 +145,6 @@ Configuration Options:
#define PAGE_ENAB 2
#define PAGE_INT_ID 3
-static int ai_rinsn(struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *, unsigned int *);
-static int ao_rinsn(struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *, unsigned int *);
-static int ao_winsn(struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *, unsigned int *);
-
/*
* Board descriptions for two imaginary boards. Describing the
* boards in this way is optional, and completely driver-dependent.
@@ -190,23 +183,6 @@ static const struct comedi_lrange ranges_ao = {
RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)}
};
-static const struct pcmmio_board pcmmio_boards[] = {
- {
- .name = "pcmmio",
- .dio_num_asics = 1,
- .dio_num_ports = 6,
- .total_iosize = 32,
- .ai_bits = 16,
- .ao_bits = 16,
- .n_ai_chans = 16,
- .n_ao_chans = 8,
- .ai_range_table = &ranges_ai,
- .ao_range_table = &ranges_ao,
- .ai_rinsn = ai_rinsn,
- .ao_rinsn = ao_rinsn,
- .ao_winsn = ao_winsn},
-};
-
/*
* Useful for shorthand access to the particular board structure
*/
@@ -293,312 +269,6 @@ struct pcmmio_private {
*/
#define devpriv ((struct pcmmio_private *)dev->private)
#define subpriv ((struct pcmmio_subdev_private *)s->private)
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int pcmmio_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcmmio_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver = {
- .driver_name = "pcmmio",
- .module = THIS_MODULE,
- .attach = pcmmio_attach,
- .detach = pcmmio_detach,
-/* It is not necessary to implement the following members if you are
- * writing a driver for a ISA PnP or PCI card */
- /* Most drivers will support multiple types of boards by
- * having an array of board structures. These were defined
- * in pcmmio_boards[] above. Note that the element 'name'
- * was first in the structure -- Comedi uses this fact to
- * extract the name of the board without knowing any details
- * about the structure except for its length.
- * When a device is attached (by comedi_config), the name
- * of the device is given to Comedi, and Comedi tries to
- * match it by going through the list of board names. If
- * there is a match, the address of the pointer is put
- * into dev->board_ptr and driver->attach() is called.
- *
- * Note that these are not necessary if you can determine
- * the type of board in software. ISA PnP, PCI, and PCMCIA
- * devices are such boards.
- */
- .board_name = &pcmmio_boards[0].name,
- .offset = sizeof(struct pcmmio_board),
- .num_names = ARRAY_SIZE(pcmmio_boards),
-};
-
-static int pcmmio_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int pcmmio_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static irqreturn_t interrupt_pcmmio(int irq, void *d);
-static void pcmmio_stop_intr(struct comedi_device *, struct comedi_subdevice *);
-static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-static int pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
-
-/* some helper functions to deal with specifics of this device's registers */
-/* sets up/clears ASIC chips to defaults */
-static void init_asics(struct comedi_device *dev);
-static void switch_page(struct comedi_device *dev, int asic, int page);
-#ifdef notused
-static void lock_port(struct comedi_device *dev, int asic, int port);
-static void unlock_port(struct comedi_device *dev, int asic, int port);
-#endif
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board. If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic,
- thisasic_chanct = 0;
- unsigned long iobase;
- unsigned int irq[MAX_ASICS];
-
- iobase = it->options[0];
- irq[0] = it->options[1];
-
- printk(KERN_INFO "comedi%d: %s: io: %lx attaching...\n", dev->minor,
- driver.driver_name, iobase);
-
- dev->iobase = iobase;
-
- if (!iobase || !request_region(iobase,
- thisboard->total_iosize,
- driver.driver_name)) {
- printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor);
- return -EIO;
- }
-
-/*
- * Initialize dev->board_name. Note that we can use the "thisboard"
- * macro now, since we just initialized it in the last line.
- */
- dev->board_name = thisboard->name;
-
-/*
- * Allocate the private structure area. alloc_private() is a
- * convenient macro defined in comedidev.h.
- */
- if (alloc_private(dev, sizeof(struct pcmmio_private)) < 0) {
- printk(KERN_ERR "comedi%d: cannot allocate private data structure\n",
- dev->minor);
- return -ENOMEM;
- }
-
- for (asic = 0; asic < MAX_ASICS; ++asic) {
- devpriv->asics[asic].num = asic;
- devpriv->asics[asic].iobase =
- dev->iobase + 16 + asic * ASIC_IOSIZE;
- /*
- * this gets actually set at the end of this function when we
- * request_irqs
- */
- devpriv->asics[asic].irq = 0;
- spin_lock_init(&devpriv->asics[asic].spinlock);
- }
-
- chans_left = CHANS_PER_ASIC * thisboard->dio_num_asics;
- n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left);
- n_subdevs = n_dio_subdevs + 2;
- devpriv->sprivs =
- kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private),
- GFP_KERNEL);
- if (!devpriv->sprivs) {
- printk(KERN_ERR "comedi%d: cannot allocate subdevice private data structures\n",
- dev->minor);
- return -ENOMEM;
- }
- /*
- * Allocate the subdevice structures. alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- *
- * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO)
- */
- if (alloc_subdevices(dev, n_subdevs) < 0) {
- printk(KERN_ERR "comedi%d: cannot allocate subdevice data structures\n",
- dev->minor);
- return -ENOMEM;
- }
-
- /* First, AI */
- sdev_no = 0;
- s = dev->subdevices + sdev_no;
- s->private = devpriv->sprivs + sdev_no;
- s->maxdata = (1 << thisboard->ai_bits) - 1;
- s->range_table = thisboard->ai_range_table;
- s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
- s->type = COMEDI_SUBD_AI;
- s->n_chan = thisboard->n_ai_chans;
- s->len_chanlist = s->n_chan;
- s->insn_read = thisboard->ai_rinsn;
- subpriv->iobase = dev->iobase + 0;
- /* initialize the resource enable register by clearing it */
- outb(0, subpriv->iobase + 3);
- outb(0, subpriv->iobase + 4 + 3);
-
- /* Next, AO */
- ++sdev_no;
- s = dev->subdevices + sdev_no;
- s->private = devpriv->sprivs + sdev_no;
- s->maxdata = (1 << thisboard->ao_bits) - 1;
- s->range_table = thisboard->ao_range_table;
- s->subdev_flags = SDF_READABLE;
- s->type = COMEDI_SUBD_AO;
- s->n_chan = thisboard->n_ao_chans;
- s->len_chanlist = s->n_chan;
- s->insn_read = thisboard->ao_rinsn;
- s->insn_write = thisboard->ao_winsn;
- subpriv->iobase = dev->iobase + 8;
- /* initialize the resource enable register by clearing it */
- outb(0, subpriv->iobase + 3);
- outb(0, subpriv->iobase + 4 + 3);
-
- ++sdev_no;
- port = 0;
- asic = 0;
- for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
- int byte_no;
-
- s = dev->subdevices + sdev_no;
- s->private = devpriv->sprivs + sdev_no;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->type = COMEDI_SUBD_DIO;
- s->insn_bits = pcmmio_dio_insn_bits;
- s->insn_config = pcmmio_dio_insn_config;
- s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
- subpriv->dio.intr.asic = -1;
- subpriv->dio.intr.first_chan = -1;
- subpriv->dio.intr.asic_chan = -1;
- subpriv->dio.intr.num_asic_chans = -1;
- subpriv->dio.intr.active = 0;
- s->len_chanlist = 1;
-
- /* save the ioport address for each 'port' of 8 channels in the
- subdevice */
- for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
- if (port >= PORTS_PER_ASIC) {
- port = 0;
- ++asic;
- thisasic_chanct = 0;
- }
- subpriv->iobases[byte_no] =
- devpriv->asics[asic].iobase + port;
-
- if (thisasic_chanct <
- CHANS_PER_PORT * INTR_PORTS_PER_ASIC
- && subpriv->dio.intr.asic < 0) {
- /*
- * this is an interrupt subdevice,
- * so setup the struct
- */
- subpriv->dio.intr.asic = asic;
- subpriv->dio.intr.active = 0;
- subpriv->dio.intr.stop_count = 0;
- subpriv->dio.intr.first_chan = byte_no * 8;
- subpriv->dio.intr.asic_chan = thisasic_chanct;
- subpriv->dio.intr.num_asic_chans =
- s->n_chan - subpriv->dio.intr.first_chan;
- s->cancel = pcmmio_cancel;
- s->do_cmd = pcmmio_cmd;
- s->do_cmdtest = pcmmio_cmdtest;
- s->len_chanlist =
- subpriv->dio.intr.num_asic_chans;
- }
- thisasic_chanct += CHANS_PER_PORT;
- }
- spin_lock_init(&subpriv->dio.intr.spinlock);
-
- chans_left -= s->n_chan;
-
- if (!chans_left) {
- /*
- * reset the asic to our first asic,
- * to do intr subdevs
- */
- asic = 0;
- port = 0;
- }
-
- }
-
- init_asics(dev); /* clear out all the registers, basically */
-
- for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
- if (irq[asic]
- && request_irq(irq[asic], interrupt_pcmmio,
- IRQF_SHARED, thisboard->name, dev)) {
- int i;
- /* unroll the allocated irqs.. */
- for (i = asic - 1; i >= 0; --i) {
- free_irq(irq[i], dev);
- devpriv->asics[i].irq = irq[i] = 0;
- }
- irq[asic] = 0;
- }
- devpriv->asics[asic].irq = irq[asic];
- }
-
- dev->irq = irq[0]; /*
- * grr.. wish comedi dev struct supported
- * multiple irqs..
- */
-
- if (irq[0]) {
- printk(KERN_DEBUG "comedi%d: irq: %u\n", dev->minor, irq[0]);
- if (thisboard->dio_num_asics == 2 && irq[1])
- printk(KERN_DEBUG "comedi%d: second ASIC irq: %u\n",
- dev->minor, irq[1]);
- } else {
- printk(KERN_INFO "comedi%d: (IRQ mode disabled)\n", dev->minor);
- }
-
- printk(KERN_INFO "comedi%d: attached\n", dev->minor);
-
- return 1;
-}
-
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pcmmio_detach(struct comedi_device *dev)
-{
- int i;
-
- printk(KERN_INFO "comedi%d: %s: remove\n", dev->minor, driver.driver_name);
- if (dev->iobase)
- release_region(dev->iobase, thisboard->total_iosize);
-
- for (i = 0; i < MAX_ASICS; ++i) {
- if (devpriv && devpriv->asics[i].irq)
- free_irq(devpriv->asics[i].irq, dev);
- }
-
- if (devpriv && devpriv->sprivs)
- kfree(devpriv->sprivs);
-
- return 0;
-}
/* DIO devices are slightly special. Although it is possible to
* implement the insn_read/insn_write interface, it is much more
@@ -667,7 +337,7 @@ static int pcmmio_dio_insn_bits(struct comedi_device *dev,
}
#ifdef DAMMIT_ITS_BROKEN
/* DEBUG */
- printk("data_out_byte %02x\n", (unsigned)byte);
+ printk(KERN_DEBUG "data_out_byte %02x\n", (unsigned)byte);
#endif
/* save the digital input lines for this byte.. */
s->state |= ((unsigned int)byte) << offset;
@@ -751,6 +421,21 @@ static int pcmmio_dio_insn_config(struct comedi_device *dev,
return insn->n;
}
+static void switch_page(struct comedi_device *dev, int asic, int page)
+{
+ if (asic < 0 || asic >= thisboard->dio_num_asics)
+ return; /* paranoia */
+ if (page < 0 || page >= NUM_PAGES)
+ return; /* more paranoia */
+
+ devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
+ devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
+
+ /* now write out the shadow register */
+ outb(devpriv->asics[asic].pagelock,
+ devpriv->asics[asic].iobase + REG_PAGELOCK);
+}
+
static void init_asics(struct comedi_device *dev)
{ /* sets up an
ASIC chip to defaults */
@@ -788,21 +473,6 @@ static void init_asics(struct comedi_device *dev)
}
}
-static void switch_page(struct comedi_device *dev, int asic, int page)
-{
- if (asic < 0 || asic >= thisboard->dio_num_asics)
- return; /* paranoia */
- if (page < 0 || page >= NUM_PAGES)
- return; /* more paranoia */
-
- devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
- devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
-
- /* now write out the shadow register */
- outb(devpriv->asics[asic].pagelock,
- devpriv->asics[asic].iobase + REG_PAGELOCK);
-}
-
#ifdef notused
static void lock_port(struct comedi_device *dev, int asic, int port)
{
@@ -831,6 +501,27 @@ static void unlock_port(struct comedi_device *dev, int asic, int port)
}
#endif /* notused */
+static void pcmmio_stop_intr(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ int nports, firstport, asic, port;
+
+ asic = subpriv->dio.intr.asic;
+ if (asic < 0)
+ return; /* not an interrupt subdev */
+
+ subpriv->dio.intr.enabled_mask = 0;
+ subpriv->dio.intr.active = 0;
+ s->async->inttrig = 0;
+ nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
+ firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
+ switch_page(dev, asic, PAGE_ENAB);
+ for (port = firstport; port < firstport + nports; ++port) {
+ /* disable all intrs for this subdev.. */
+ outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
+ }
+}
+
static irqreturn_t interrupt_pcmmio(int irq, void *d)
{
int asic, got1 = 0;
@@ -991,27 +682,6 @@ static irqreturn_t interrupt_pcmmio(int irq, void *d)
return IRQ_HANDLED;
}
-static void pcmmio_stop_intr(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- int nports, firstport, asic, port;
-
- asic = subpriv->dio.intr.asic;
- if (asic < 0)
- return; /* not an interrupt subdev */
-
- subpriv->dio.intr.enabled_mask = 0;
- subpriv->dio.intr.active = 0;
- s->async->inttrig = 0;
- nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT;
- firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT;
- switch_page(dev, asic, PAGE_ENAB);
- for (port = firstport; port < firstport + nports; ++port) {
- /* disable all intrs for this subdev.. */
- outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
- }
-}
-
static int pcmmio_start_intr(struct comedi_device *dev,
struct comedi_subdevice *s)
{
@@ -1340,22 +1010,261 @@ static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
return n;
}
+static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+ struct comedi_subdevice *s;
+ int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic,
+ thisasic_chanct = 0;
+ unsigned long iobase;
+ unsigned int irq[MAX_ASICS];
+
+ iobase = it->options[0];
+ irq[0] = it->options[1];
+
+ printk(KERN_INFO "comedi%d: %s: io: %lx attaching...\n", dev->minor,
+ dev->driver->driver_name, iobase);
+
+ dev->iobase = iobase;
+
+ if (!iobase || !request_region(iobase,
+ thisboard->total_iosize,
+ dev->driver->driver_name)) {
+ printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor);
+ return -EIO;
+ }
+
/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
+ * Initialize dev->board_name. Note that we can use the "thisboard"
+ * macro now, since we just initialized it in the last line.
*/
-static int __init driver_init_module(void)
-{
- return comedi_driver_register(&driver);
+ dev->board_name = thisboard->name;
+
+/*
+ * Allocate the private structure area. alloc_private() is a
+ * convenient macro defined in comedidev.h.
+ */
+ if (alloc_private(dev, sizeof(struct pcmmio_private)) < 0) {
+ printk(KERN_ERR "comedi%d: cannot allocate private data structure\n",
+ dev->minor);
+ return -ENOMEM;
+ }
+
+ for (asic = 0; asic < MAX_ASICS; ++asic) {
+ devpriv->asics[asic].num = asic;
+ devpriv->asics[asic].iobase =
+ dev->iobase + 16 + asic * ASIC_IOSIZE;
+ /*
+ * this gets actually set at the end of this function when we
+ * request_irqs
+ */
+ devpriv->asics[asic].irq = 0;
+ spin_lock_init(&devpriv->asics[asic].spinlock);
+ }
+
+ chans_left = CHANS_PER_ASIC * thisboard->dio_num_asics;
+ n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left);
+ n_subdevs = n_dio_subdevs + 2;
+ devpriv->sprivs =
+ kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private),
+ GFP_KERNEL);
+ if (!devpriv->sprivs) {
+ printk(KERN_ERR "comedi%d: cannot allocate subdevice private data structures\n",
+ dev->minor);
+ return -ENOMEM;
+ }
+ /*
+ * Allocate the subdevice structures. alloc_subdevice() is a
+ * convenient macro defined in comedidev.h.
+ *
+ * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO)
+ */
+ if (alloc_subdevices(dev, n_subdevs) < 0) {
+ printk(KERN_ERR "comedi%d: cannot allocate subdevice data structures\n",
+ dev->minor);
+ return -ENOMEM;
+ }
+
+ /* First, AI */
+ sdev_no = 0;
+ s = dev->subdevices + sdev_no;
+ s->private = devpriv->sprivs + sdev_no;
+ s->maxdata = (1 << thisboard->ai_bits) - 1;
+ s->range_table = thisboard->ai_range_table;
+ s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
+ s->type = COMEDI_SUBD_AI;
+ s->n_chan = thisboard->n_ai_chans;
+ s->len_chanlist = s->n_chan;
+ s->insn_read = thisboard->ai_rinsn;
+ subpriv->iobase = dev->iobase + 0;
+ /* initialize the resource enable register by clearing it */
+ outb(0, subpriv->iobase + 3);
+ outb(0, subpriv->iobase + 4 + 3);
+
+ /* Next, AO */
+ ++sdev_no;
+ s = dev->subdevices + sdev_no;
+ s->private = devpriv->sprivs + sdev_no;
+ s->maxdata = (1 << thisboard->ao_bits) - 1;
+ s->range_table = thisboard->ao_range_table;
+ s->subdev_flags = SDF_READABLE;
+ s->type = COMEDI_SUBD_AO;
+ s->n_chan = thisboard->n_ao_chans;
+ s->len_chanlist = s->n_chan;
+ s->insn_read = thisboard->ao_rinsn;
+ s->insn_write = thisboard->ao_winsn;
+ subpriv->iobase = dev->iobase + 8;
+ /* initialize the resource enable register by clearing it */
+ outb(0, subpriv->iobase + 3);
+ outb(0, subpriv->iobase + 4 + 3);
+
+ ++sdev_no;
+ port = 0;
+ asic = 0;
+ for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
+ int byte_no;
+
+ s = dev->subdevices + sdev_no;
+ s->private = devpriv->sprivs + sdev_no;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->type = COMEDI_SUBD_DIO;
+ s->insn_bits = pcmmio_dio_insn_bits;
+ s->insn_config = pcmmio_dio_insn_config;
+ s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
+ subpriv->dio.intr.asic = -1;
+ subpriv->dio.intr.first_chan = -1;
+ subpriv->dio.intr.asic_chan = -1;
+ subpriv->dio.intr.num_asic_chans = -1;
+ subpriv->dio.intr.active = 0;
+ s->len_chanlist = 1;
+
+ /* save the ioport address for each 'port' of 8 channels in the
+ subdevice */
+ for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
+ if (port >= PORTS_PER_ASIC) {
+ port = 0;
+ ++asic;
+ thisasic_chanct = 0;
+ }
+ subpriv->iobases[byte_no] =
+ devpriv->asics[asic].iobase + port;
+
+ if (thisasic_chanct <
+ CHANS_PER_PORT * INTR_PORTS_PER_ASIC
+ && subpriv->dio.intr.asic < 0) {
+ /*
+ * this is an interrupt subdevice,
+ * so setup the struct
+ */
+ subpriv->dio.intr.asic = asic;
+ subpriv->dio.intr.active = 0;
+ subpriv->dio.intr.stop_count = 0;
+ subpriv->dio.intr.first_chan = byte_no * 8;
+ subpriv->dio.intr.asic_chan = thisasic_chanct;
+ subpriv->dio.intr.num_asic_chans =
+ s->n_chan - subpriv->dio.intr.first_chan;
+ s->cancel = pcmmio_cancel;
+ s->do_cmd = pcmmio_cmd;
+ s->do_cmdtest = pcmmio_cmdtest;
+ s->len_chanlist =
+ subpriv->dio.intr.num_asic_chans;
+ }
+ thisasic_chanct += CHANS_PER_PORT;
+ }
+ spin_lock_init(&subpriv->dio.intr.spinlock);
+
+ chans_left -= s->n_chan;
+
+ if (!chans_left) {
+ /*
+ * reset the asic to our first asic,
+ * to do intr subdevs
+ */
+ asic = 0;
+ port = 0;
+ }
+
+ }
+
+ init_asics(dev); /* clear out all the registers, basically */
+
+ for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
+ if (irq[asic]
+ && request_irq(irq[asic], interrupt_pcmmio,
+ IRQF_SHARED, thisboard->name, dev)) {
+ int i;
+ /* unroll the allocated irqs.. */
+ for (i = asic - 1; i >= 0; --i) {
+ free_irq(irq[i], dev);
+ devpriv->asics[i].irq = irq[i] = 0;
+ }
+ irq[asic] = 0;
+ }
+ devpriv->asics[asic].irq = irq[asic];
+ }
+
+ dev->irq = irq[0]; /*
+ * grr.. wish comedi dev struct supported
+ * multiple irqs..
+ */
+
+ if (irq[0]) {
+ printk(KERN_DEBUG "comedi%d: irq: %u\n", dev->minor, irq[0]);
+ if (thisboard->dio_num_asics == 2 && irq[1])
+ printk(KERN_DEBUG "comedi%d: second ASIC irq: %u\n",
+ dev->minor, irq[1]);
+ } else {
+ printk(KERN_INFO "comedi%d: (IRQ mode disabled)\n", dev->minor);
+ }
+
+ printk(KERN_INFO "comedi%d: attached\n", dev->minor);
+
+ return 1;
}
-static void __exit driver_cleanup_module(void)
+static void pcmmio_detach(struct comedi_device *dev)
{
- comedi_driver_unregister(&driver);
+ int i;
+
+ if (dev->iobase)
+ release_region(dev->iobase, thisboard->total_iosize);
+ for (i = 0; i < MAX_ASICS; ++i) {
+ if (devpriv && devpriv->asics[i].irq)
+ free_irq(devpriv->asics[i].irq, dev);
+ }
+ if (devpriv && devpriv->sprivs)
+ kfree(devpriv->sprivs);
}
-module_init(driver_init_module);
-module_exit(driver_cleanup_module);
+static const struct pcmmio_board pcmmio_boards[] = {
+ {
+ .name = "pcmmio",
+ .dio_num_asics = 1,
+ .dio_num_ports = 6,
+ .total_iosize = 32,
+ .ai_bits = 16,
+ .ao_bits = 16,
+ .n_ai_chans = 16,
+ .n_ao_chans = 8,
+ .ai_range_table = &ranges_ai,
+ .ao_range_table = &ranges_ao,
+ .ai_rinsn = ai_rinsn,
+ .ao_rinsn = ao_rinsn,
+ .ao_winsn = ao_winsn
+ },
+};
+
+static struct comedi_driver pcmmio_driver = {
+ .driver_name = "pcmmio",
+ .module = THIS_MODULE,
+ .attach = pcmmio_attach,
+ .detach = pcmmio_detach,
+ .board_name = &pcmmio_boards[0].name,
+ .offset = sizeof(struct pcmmio_board),
+ .num_names = ARRAY_SIZE(pcmmio_boards),
+};
+module_comedi_driver(pcmmio_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c
index 661ba2e03892..623381d50dac 100644
--- a/drivers/staging/comedi/drivers/pcmuio.c
+++ b/drivers/staging/comedi/drivers/pcmuio.c
@@ -155,19 +155,6 @@ struct pcmuio_board {
const int num_ports;
};
-static const struct pcmuio_board pcmuio_boards[] = {
- {
- .name = "pcmuio48",
- .num_asics = 1,
- .num_ports = 6,
- },
- {
- .name = "pcmuio96",
- .num_asics = 2,
- .num_ports = 12,
- },
-};
-
/*
* Useful for shorthand access to the particular board structure
*/
@@ -218,262 +205,6 @@ struct pcmuio_private {
*/
#define devpriv ((struct pcmuio_private *)dev->private)
#define subpriv ((struct pcmuio_subdev_private *)s->private)
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int pcmuio_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int pcmuio_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver = {
- .driver_name = "pcmuio",
- .module = THIS_MODULE,
- .attach = pcmuio_attach,
- .detach = pcmuio_detach,
-/* It is not necessary to implement the following members if you are
- * writing a driver for a ISA PnP or PCI card */
- /* Most drivers will support multiple types of boards by
- * having an array of board structures. These were defined
- * in pcmuio_boards[] above. Note that the element 'name'
- * was first in the structure -- Comedi uses this fact to
- * extract the name of the board without knowing any details
- * about the structure except for its length.
- * When a device is attached (by comedi_config), the name
- * of the device is given to Comedi, and Comedi tries to
- * match it by going through the list of board names. If
- * there is a match, the address of the pointer is put
- * into dev->board_ptr and driver->attach() is called.
- *
- * Note that these are not necessary if you can determine
- * the type of board in software. ISA PnP, PCI, and PCMCIA
- * devices are such boards.
- */
- .board_name = &pcmuio_boards[0].name,
- .offset = sizeof(struct pcmuio_board),
- .num_names = ARRAY_SIZE(pcmuio_boards),
-};
-
-static int pcmuio_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int pcmuio_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static irqreturn_t interrupt_pcmuio(int irq, void *d);
-static void pcmuio_stop_intr(struct comedi_device *, struct comedi_subdevice *);
-static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-static int pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
-
-/* some helper functions to deal with specifics of this device's registers */
-static void init_asics(struct comedi_device *dev); /* sets up/clears ASIC chips to defaults */
-static void switch_page(struct comedi_device *dev, int asic, int page);
-#ifdef notused
-static void lock_port(struct comedi_device *dev, int asic, int port);
-static void unlock_port(struct comedi_device *dev, int asic, int port);
-#endif
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board. If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0;
- unsigned long iobase;
- unsigned int irq[MAX_ASICS];
-
- iobase = it->options[0];
- irq[0] = it->options[1];
- irq[1] = it->options[2];
-
- dev_dbg(dev->hw_dev, "comedi%d: %s: io: %lx attached\n", dev->minor,
- driver.driver_name, iobase);
-
- dev->iobase = iobase;
-
- if (!iobase || !request_region(iobase,
- thisboard->num_asics * ASIC_IOSIZE,
- driver.driver_name)) {
- dev_err(dev->hw_dev, "I/O port conflict\n");
- return -EIO;
- }
-
-/*
- * Initialize dev->board_name. Note that we can use the "thisboard"
- * macro now, since we just initialized it in the last line.
- */
- dev->board_name = thisboard->name;
-
-/*
- * Allocate the private structure area. alloc_private() is a
- * convenient macro defined in comedidev.h.
- */
- if (alloc_private(dev, sizeof(struct pcmuio_private)) < 0) {
- dev_warn(dev->hw_dev, "cannot allocate private data structure\n");
- return -ENOMEM;
- }
-
- for (asic = 0; asic < MAX_ASICS; ++asic) {
- devpriv->asics[asic].num = asic;
- devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE;
- devpriv->asics[asic].irq = 0; /* this gets actually set at the end of
- this function when we
- request_irqs */
- spin_lock_init(&devpriv->asics[asic].spinlock);
- }
-
- chans_left = CHANS_PER_ASIC * thisboard->num_asics;
- n_subdevs = CALC_N_SUBDEVS(chans_left);
- devpriv->sprivs =
- kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private),
- GFP_KERNEL);
- if (!devpriv->sprivs) {
- dev_warn(dev->hw_dev, "cannot allocate subdevice private data structures\n");
- return -ENOMEM;
- }
- /*
- * Allocate the subdevice structures. alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- *
- * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
- * 96-channel version of the board.
- */
- if (alloc_subdevices(dev, n_subdevs) < 0) {
- dev_dbg(dev->hw_dev, "cannot allocate subdevice data structures\n");
- return -ENOMEM;
- }
-
- port = 0;
- asic = 0;
- for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
- int byte_no;
-
- s = dev->subdevices + sdev_no;
- s->private = devpriv->sprivs + sdev_no;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->type = COMEDI_SUBD_DIO;
- s->insn_bits = pcmuio_dio_insn_bits;
- s->insn_config = pcmuio_dio_insn_config;
- s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
- subpriv->intr.asic = -1;
- subpriv->intr.first_chan = -1;
- subpriv->intr.asic_chan = -1;
- subpriv->intr.num_asic_chans = -1;
- subpriv->intr.active = 0;
- s->len_chanlist = 1;
-
- /* save the ioport address for each 'port' of 8 channels in the
- subdevice */
- for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
- if (port >= PORTS_PER_ASIC) {
- port = 0;
- ++asic;
- thisasic_chanct = 0;
- }
- subpriv->iobases[byte_no] =
- devpriv->asics[asic].iobase + port;
-
- if (thisasic_chanct <
- CHANS_PER_PORT * INTR_PORTS_PER_ASIC
- && subpriv->intr.asic < 0) {
- /* this is an interrupt subdevice, so setup the struct */
- subpriv->intr.asic = asic;
- subpriv->intr.active = 0;
- subpriv->intr.stop_count = 0;
- subpriv->intr.first_chan = byte_no * 8;
- subpriv->intr.asic_chan = thisasic_chanct;
- subpriv->intr.num_asic_chans =
- s->n_chan - subpriv->intr.first_chan;
- dev->read_subdev = s;
- s->subdev_flags |= SDF_CMD_READ;
- s->cancel = pcmuio_cancel;
- s->do_cmd = pcmuio_cmd;
- s->do_cmdtest = pcmuio_cmdtest;
- s->len_chanlist = subpriv->intr.num_asic_chans;
- }
- thisasic_chanct += CHANS_PER_PORT;
- }
- spin_lock_init(&subpriv->intr.spinlock);
-
- chans_left -= s->n_chan;
-
- if (!chans_left) {
- asic = 0; /* reset the asic to our first asic, to do intr subdevs */
- port = 0;
- }
-
- }
-
- init_asics(dev); /* clear out all the registers, basically */
-
- for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
- if (irq[asic]
- && request_irq(irq[asic], interrupt_pcmuio,
- IRQF_SHARED, thisboard->name, dev)) {
- int i;
- /* unroll the allocated irqs.. */
- for (i = asic - 1; i >= 0; --i) {
- free_irq(irq[i], dev);
- devpriv->asics[i].irq = irq[i] = 0;
- }
- irq[asic] = 0;
- }
- devpriv->asics[asic].irq = irq[asic];
- }
-
- dev->irq = irq[0]; /* grr.. wish comedi dev struct supported multiple
- irqs.. */
-
- if (irq[0]) {
- dev_dbg(dev->hw_dev, "irq: %u\n", irq[0]);
- if (irq[1] && thisboard->num_asics == 2)
- dev_dbg(dev->hw_dev, "second ASIC irq: %u\n", irq[1]);
- } else {
- dev_dbg(dev->hw_dev, "(IRQ mode disabled)\n");
- }
-
-
- return 1;
-}
-
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int pcmuio_detach(struct comedi_device *dev)
-{
- int i;
-
- dev_dbg(dev->hw_dev, "comedi%d: %s: remove\n", dev->minor,
- driver.driver_name);
- if (dev->iobase)
- release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics);
-
- for (i = 0; i < MAX_ASICS; ++i) {
- if (devpriv->asics[i].irq)
- free_irq(devpriv->asics[i].irq, dev);
- }
-
- if (devpriv && devpriv->sprivs)
- kfree(devpriv->sprivs);
-
- return 0;
-}
/* DIO devices are slightly special. Although it is possible to
* implement the insn_read/insn_write interface, it is much more
@@ -621,6 +352,21 @@ static int pcmuio_dio_insn_config(struct comedi_device *dev,
return insn->n;
}
+static void switch_page(struct comedi_device *dev, int asic, int page)
+{
+ if (asic < 0 || asic >= thisboard->num_asics)
+ return; /* paranoia */
+ if (page < 0 || page >= NUM_PAGES)
+ return; /* more paranoia */
+
+ devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
+ devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
+
+ /* now write out the shadow register */
+ outb(devpriv->asics[asic].pagelock,
+ dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
+}
+
static void init_asics(struct comedi_device *dev)
{ /* sets up an
ASIC chip to defaults */
@@ -658,21 +404,6 @@ static void init_asics(struct comedi_device *dev)
}
}
-static void switch_page(struct comedi_device *dev, int asic, int page)
-{
- if (asic < 0 || asic >= thisboard->num_asics)
- return; /* paranoia */
- if (page < 0 || page >= NUM_PAGES)
- return; /* more paranoia */
-
- devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK;
- devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET;
-
- /* now write out the shadow register */
- outb(devpriv->asics[asic].pagelock,
- dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK);
-}
-
#ifdef notused
static void lock_port(struct comedi_device *dev, int asic, int port)
{
@@ -700,6 +431,27 @@ static void unlock_port(struct comedi_device *dev, int asic, int port)
}
#endif /* notused */
+static void pcmuio_stop_intr(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ int nports, firstport, asic, port;
+
+ asic = subpriv->intr.asic;
+ if (asic < 0)
+ return; /* not an interrupt subdev */
+
+ subpriv->intr.enabled_mask = 0;
+ subpriv->intr.active = 0;
+ s->async->inttrig = 0;
+ nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
+ firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
+ switch_page(dev, asic, PAGE_ENAB);
+ for (port = firstport; port < firstport + nports; ++port) {
+ /* disable all intrs for this subdev.. */
+ outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
+ }
+}
+
static irqreturn_t interrupt_pcmuio(int irq, void *d)
{
int asic, got1 = 0;
@@ -852,27 +604,6 @@ static irqreturn_t interrupt_pcmuio(int irq, void *d)
return IRQ_HANDLED;
}
-static void pcmuio_stop_intr(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- int nports, firstport, asic, port;
-
- asic = subpriv->intr.asic;
- if (asic < 0)
- return; /* not an interrupt subdev */
-
- subpriv->intr.enabled_mask = 0;
- subpriv->intr.active = 0;
- s->async->inttrig = 0;
- nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT;
- firstport = subpriv->intr.asic_chan / CHANS_PER_PORT;
- switch_page(dev, asic, PAGE_ENAB);
- for (port = firstport; port < firstport + nports; ++port) {
- /* disable all intrs for this subdev.. */
- outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port);
- }
-}
-
static int pcmuio_start_intr(struct comedi_device *dev,
struct comedi_subdevice *s)
{
@@ -1014,22 +745,205 @@ pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
return comedi_pcm_cmdtest(dev, s, cmd);
}
+static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+ struct comedi_subdevice *s;
+ int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0;
+ unsigned long iobase;
+ unsigned int irq[MAX_ASICS];
+
+ iobase = it->options[0];
+ irq[0] = it->options[1];
+ irq[1] = it->options[2];
+
+ dev_dbg(dev->hw_dev, "comedi%d: %s: io: %lx attached\n", dev->minor,
+ dev->driver->driver_name, iobase);
+
+ dev->iobase = iobase;
+
+ if (!iobase || !request_region(iobase,
+ thisboard->num_asics * ASIC_IOSIZE,
+ dev->driver->driver_name)) {
+ dev_err(dev->hw_dev, "I/O port conflict\n");
+ return -EIO;
+ }
+
/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
+ * Initialize dev->board_name. Note that we can use the "thisboard"
+ * macro now, since we just initialized it in the last line.
*/
-static int __init driver_init_module(void)
-{
- return comedi_driver_register(&driver);
+ dev->board_name = thisboard->name;
+
+/*
+ * Allocate the private structure area. alloc_private() is a
+ * convenient macro defined in comedidev.h.
+ */
+ if (alloc_private(dev, sizeof(struct pcmuio_private)) < 0) {
+ dev_warn(dev->hw_dev, "cannot allocate private data structure\n");
+ return -ENOMEM;
+ }
+
+ for (asic = 0; asic < MAX_ASICS; ++asic) {
+ devpriv->asics[asic].num = asic;
+ devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE;
+ devpriv->asics[asic].irq = 0; /* this gets actually set at the end of
+ this function when we
+ request_irqs */
+ spin_lock_init(&devpriv->asics[asic].spinlock);
+ }
+
+ chans_left = CHANS_PER_ASIC * thisboard->num_asics;
+ n_subdevs = CALC_N_SUBDEVS(chans_left);
+ devpriv->sprivs =
+ kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private),
+ GFP_KERNEL);
+ if (!devpriv->sprivs) {
+ dev_warn(dev->hw_dev, "cannot allocate subdevice private data structures\n");
+ return -ENOMEM;
+ }
+ /*
+ * Allocate the subdevice structures. alloc_subdevice() is a
+ * convenient macro defined in comedidev.h.
+ *
+ * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the
+ * 96-channel version of the board.
+ */
+ if (alloc_subdevices(dev, n_subdevs) < 0) {
+ dev_dbg(dev->hw_dev, "cannot allocate subdevice data structures\n");
+ return -ENOMEM;
+ }
+
+ port = 0;
+ asic = 0;
+ for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) {
+ int byte_no;
+
+ s = dev->subdevices + sdev_no;
+ s->private = devpriv->sprivs + sdev_no;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->type = COMEDI_SUBD_DIO;
+ s->insn_bits = pcmuio_dio_insn_bits;
+ s->insn_config = pcmuio_dio_insn_config;
+ s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV);
+ subpriv->intr.asic = -1;
+ subpriv->intr.first_chan = -1;
+ subpriv->intr.asic_chan = -1;
+ subpriv->intr.num_asic_chans = -1;
+ subpriv->intr.active = 0;
+ s->len_chanlist = 1;
+
+ /* save the ioport address for each 'port' of 8 channels in the
+ subdevice */
+ for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) {
+ if (port >= PORTS_PER_ASIC) {
+ port = 0;
+ ++asic;
+ thisasic_chanct = 0;
+ }
+ subpriv->iobases[byte_no] =
+ devpriv->asics[asic].iobase + port;
+
+ if (thisasic_chanct <
+ CHANS_PER_PORT * INTR_PORTS_PER_ASIC
+ && subpriv->intr.asic < 0) {
+ /* this is an interrupt subdevice, so setup the struct */
+ subpriv->intr.asic = asic;
+ subpriv->intr.active = 0;
+ subpriv->intr.stop_count = 0;
+ subpriv->intr.first_chan = byte_no * 8;
+ subpriv->intr.asic_chan = thisasic_chanct;
+ subpriv->intr.num_asic_chans =
+ s->n_chan - subpriv->intr.first_chan;
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->cancel = pcmuio_cancel;
+ s->do_cmd = pcmuio_cmd;
+ s->do_cmdtest = pcmuio_cmdtest;
+ s->len_chanlist = subpriv->intr.num_asic_chans;
+ }
+ thisasic_chanct += CHANS_PER_PORT;
+ }
+ spin_lock_init(&subpriv->intr.spinlock);
+
+ chans_left -= s->n_chan;
+
+ if (!chans_left) {
+ asic = 0; /* reset the asic to our first asic, to do intr subdevs */
+ port = 0;
+ }
+
+ }
+
+ init_asics(dev); /* clear out all the registers, basically */
+
+ for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) {
+ if (irq[asic]
+ && request_irq(irq[asic], interrupt_pcmuio,
+ IRQF_SHARED, thisboard->name, dev)) {
+ int i;
+ /* unroll the allocated irqs.. */
+ for (i = asic - 1; i >= 0; --i) {
+ free_irq(irq[i], dev);
+ devpriv->asics[i].irq = irq[i] = 0;
+ }
+ irq[asic] = 0;
+ }
+ devpriv->asics[asic].irq = irq[asic];
+ }
+
+ dev->irq = irq[0]; /* grr.. wish comedi dev struct supported multiple
+ irqs.. */
+
+ if (irq[0]) {
+ dev_dbg(dev->hw_dev, "irq: %u\n", irq[0]);
+ if (irq[1] && thisboard->num_asics == 2)
+ dev_dbg(dev->hw_dev, "second ASIC irq: %u\n", irq[1]);
+ } else {
+ dev_dbg(dev->hw_dev, "(IRQ mode disabled)\n");
+ }
+
+
+ return 1;
}
-static void __exit driver_cleanup_module(void)
+static void pcmuio_detach(struct comedi_device *dev)
{
- comedi_driver_unregister(&driver);
+ int i;
+
+ if (dev->iobase)
+ release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics);
+ for (i = 0; i < MAX_ASICS; ++i) {
+ if (devpriv->asics[i].irq)
+ free_irq(devpriv->asics[i].irq, dev);
+ }
+ if (devpriv && devpriv->sprivs)
+ kfree(devpriv->sprivs);
}
-module_init(driver_init_module);
-module_exit(driver_cleanup_module);
+static const struct pcmuio_board pcmuio_boards[] = {
+ {
+ .name = "pcmuio48",
+ .num_asics = 1,
+ .num_ports = 6,
+ }, {
+ .name = "pcmuio96",
+ .num_asics = 2,
+ .num_ports = 12,
+ },
+};
+
+static struct comedi_driver pcmuio_driver = {
+ .driver_name = "pcmuio",
+ .module = THIS_MODULE,
+ .attach = pcmuio_attach,
+ .detach = pcmuio_detach,
+ .board_name = &pcmuio_boards[0].name,
+ .offset = sizeof(struct pcmuio_board),
+ .num_names = ARRAY_SIZE(pcmuio_boards),
+};
+module_comedi_driver(pcmuio_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/poc.c b/drivers/staging/comedi/drivers/poc.c
index 831a576c24aa..e7120480687b 100644
--- a/drivers/staging/comedi/drivers/poc.c
+++ b/drivers/staging/comedi/drivers/poc.c
@@ -41,20 +41,6 @@ Configuration options:
#include <linux/ioport.h>
-static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int poc_detach(struct comedi_device *dev);
-static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int dac02_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int pcl733_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int pcl734_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
struct boarddef_struct {
const char *name;
unsigned int iosize;
@@ -70,108 +56,9 @@ struct boarddef_struct {
struct comedi_insn *, unsigned int *);
const struct comedi_lrange *range;
};
-static const struct boarddef_struct boards[] = {
- {
- .name = "dac02",
- .iosize = 8,
- /* .setup = dac02_setup, */
- .type = COMEDI_SUBD_AO,
- .n_chan = 2,
- .n_bits = 12,
- .winsn = dac02_ao_winsn,
- .rinsn = readback_insn,
- .range = &range_unknown,
- },
- {
- .name = "pcl733",
- .iosize = 4,
- .type = COMEDI_SUBD_DI,
- .n_chan = 32,
- .n_bits = 1,
- .insnbits = pcl733_insn_bits,
- .range = &range_digital,
- },
- {
- .name = "pcl734",
- .iosize = 4,
- .type = COMEDI_SUBD_DO,
- .n_chan = 32,
- .n_bits = 1,
- .insnbits = pcl734_insn_bits,
- .range = &range_digital,
- },
-};
-#define n_boards ARRAY_SIZE(boards)
#define this_board ((const struct boarddef_struct *)dev->board_ptr)
-static struct comedi_driver driver_poc = {
- .driver_name = "poc",
- .module = THIS_MODULE,
- .attach = poc_attach,
- .detach = poc_detach,
- .board_name = &boards[0].name,
- .num_names = n_boards,
- .offset = sizeof(boards[0]),
-};
-
-static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- unsigned long iobase;
- unsigned int iosize;
-
- iobase = it->options[0];
- printk(KERN_INFO "comedi%d: poc: using %s iobase 0x%lx\n", dev->minor,
- this_board->name, iobase);
-
- dev->board_name = this_board->name;
-
- if (iobase == 0) {
- printk(KERN_ERR "io base address required\n");
- return -EINVAL;
- }
-
- iosize = this_board->iosize;
- /* check if io addresses are available */
- if (!request_region(iobase, iosize, "dac02")) {
- printk(KERN_ERR "I/O port conflict: failed to allocate ports "
- "0x%lx to 0x%lx\n", iobase, iobase + iosize - 1);
- return -EIO;
- }
- dev->iobase = iobase;
-
- if (alloc_subdevices(dev, 1) < 0)
- return -ENOMEM;
- if (alloc_private(dev, sizeof(unsigned int) * this_board->n_chan) < 0)
- return -ENOMEM;
-
- /* analog output subdevice */
- s = dev->subdevices + 0;
- s->type = this_board->type;
- s->n_chan = this_board->n_chan;
- s->maxdata = (1 << this_board->n_bits) - 1;
- s->range_table = this_board->range;
- s->insn_write = this_board->winsn;
- s->insn_read = this_board->rinsn;
- s->insn_bits = this_board->insnbits;
- if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO)
- s->subdev_flags = SDF_WRITABLE;
-
- return 0;
-}
-
-static int poc_detach(struct comedi_device *dev)
-{
- /* only free stuff if it has been allocated by _attach */
- if (dev->iobase)
- release_region(dev->iobase, this_board->iosize);
-
- printk(KERN_INFO "comedi%d: dac02: remove\n", dev->minor);
-
- return 0;
-}
-
static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
@@ -248,18 +135,98 @@ static int pcl734_insn_bits(struct comedi_device *dev,
return 2;
}
-static int __init driver_poc_init_module(void)
+static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- return comedi_driver_register(&driver_poc);
+ struct comedi_subdevice *s;
+ unsigned long iobase;
+ unsigned int iosize;
+
+ iobase = it->options[0];
+ printk(KERN_INFO "comedi%d: poc: using %s iobase 0x%lx\n", dev->minor,
+ this_board->name, iobase);
+
+ dev->board_name = this_board->name;
+
+ if (iobase == 0) {
+ printk(KERN_ERR "io base address required\n");
+ return -EINVAL;
+ }
+
+ iosize = this_board->iosize;
+ /* check if io addresses are available */
+ if (!request_region(iobase, iosize, "dac02")) {
+ printk(KERN_ERR "I/O port conflict: failed to allocate ports "
+ "0x%lx to 0x%lx\n", iobase, iobase + iosize - 1);
+ return -EIO;
+ }
+ dev->iobase = iobase;
+
+ if (alloc_subdevices(dev, 1) < 0)
+ return -ENOMEM;
+ if (alloc_private(dev, sizeof(unsigned int) * this_board->n_chan) < 0)
+ return -ENOMEM;
+
+ /* analog output subdevice */
+ s = dev->subdevices + 0;
+ s->type = this_board->type;
+ s->n_chan = this_board->n_chan;
+ s->maxdata = (1 << this_board->n_bits) - 1;
+ s->range_table = this_board->range;
+ s->insn_write = this_board->winsn;
+ s->insn_read = this_board->rinsn;
+ s->insn_bits = this_board->insnbits;
+ if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO)
+ s->subdev_flags = SDF_WRITABLE;
+
+ return 0;
}
-static void __exit driver_poc_cleanup_module(void)
+static void poc_detach(struct comedi_device *dev)
{
- comedi_driver_unregister(&driver_poc);
+ if (dev->iobase)
+ release_region(dev->iobase, this_board->iosize);
}
-module_init(driver_poc_init_module);
-module_exit(driver_poc_cleanup_module);
+static const struct boarddef_struct boards[] = {
+ {
+ .name = "dac02",
+ .iosize = 8,
+ /* .setup = dac02_setup, */
+ .type = COMEDI_SUBD_AO,
+ .n_chan = 2,
+ .n_bits = 12,
+ .winsn = dac02_ao_winsn,
+ .rinsn = readback_insn,
+ .range = &range_unknown,
+ }, {
+ .name = "pcl733",
+ .iosize = 4,
+ .type = COMEDI_SUBD_DI,
+ .n_chan = 32,
+ .n_bits = 1,
+ .insnbits = pcl733_insn_bits,
+ .range = &range_digital,
+ }, {
+ .name = "pcl734",
+ .iosize = 4,
+ .type = COMEDI_SUBD_DO,
+ .n_chan = 32,
+ .n_bits = 1,
+ .insnbits = pcl734_insn_bits,
+ .range = &range_digital,
+ },
+};
+
+static struct comedi_driver poc_driver = {
+ .driver_name = "poc",
+ .module = THIS_MODULE,
+ .attach = poc_attach,
+ .detach = poc_detach,
+ .board_name = &boards[0].name,
+ .num_names = ARRAY_SIZE(boards),
+ .offset = sizeof(boards[0]),
+};
+module_comedi_driver(poc_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
index e0bb73445dd8..2f130b3095e9 100644
--- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c
+++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
@@ -181,7 +181,7 @@ static const struct comedi_lrange range_daqp_ao = { 1, {BIP_RANGE(5)} };
/* comedi interface code */
static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int daqp_detach(struct comedi_device *dev);
+static void daqp_detach(struct comedi_device *dev);
static struct comedi_driver driver_daqp = {
.driver_name = "quatech_daqp_cs",
.module = THIS_MODULE,
@@ -922,15 +922,9 @@ static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 1;
}
-/* daqp_detach (called from comedi_comdig) does nothing. If the PCMCIA
- * card is removed, daqp_cs_detach() is called by the pcmcia subsystem.
- */
-
-static int daqp_detach(struct comedi_device *dev)
+static void daqp_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: detaching daqp\n", dev->minor);
-
- return 0;
+ /* Nothing to cleanup */
}
/*====================================================================
@@ -1010,8 +1004,6 @@ static void daqp_cs_detach(struct pcmcia_device *link)
{
struct local_info_t *dev = link->priv;
- dev_dbg(&link->dev, "daqp_cs_detach\n");
-
dev->stop = 1;
daqp_cs_release(link);
@@ -1019,7 +1011,7 @@ static void daqp_cs_detach(struct pcmcia_device *link)
dev_table[dev->table_index] = NULL;
kfree(dev);
-} /* daqp_cs_detach */
+}
static int daqp_pcmcia_config_loop(struct pcmcia_device *p_dev, void *priv_data)
{
diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c
index 138441960506..1678a0ccb8c1 100644
--- a/drivers/staging/comedi/drivers/rtd520.c
+++ b/drivers/staging/comedi/drivers/rtd520.c
@@ -328,14 +328,6 @@ static const struct rtdBoard rtd520Boards[] = {
},
};
-static DEFINE_PCI_DEVICE_TABLE(rtd520_pci_table) = {
- { PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x7520) },
- { PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x4520) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, rtd520_pci_table);
-
/*
* Useful for shorthand access to the particular board structure
*/
@@ -347,13 +339,13 @@ MODULE_DEVICE_TABLE(pci, rtd520_pci_table);
*/
struct rtdPrivate {
/* memory mapped board structures */
- void *las0;
- void *las1;
- void *lcfg;
+ void __iomem *las0;
+ void __iomem *las1;
+ void __iomem *lcfg;
unsigned long intCount; /* interrupt count */
long aiCount; /* total transfer size (samples) */
- int transCount; /* # to tranfer data. 0->1/2FIFO */
+ int transCount; /* # to transfer data. 0->1/2FIFO */
int flags; /* flag event modes */
/* PCI device info */
@@ -377,8 +369,11 @@ struct rtdPrivate {
u8 utcCtrl[4]; /* crtl mode for 3 utc + read back */
u8 dioStatus; /* could be read back (dio0Ctrl) */
#ifdef USE_DMA
- /* Always DMA 1/2 FIFO. Buffer (dmaBuff?) is (at least) twice that size.
- After transferring, interrupt processes 1/2 FIFO and passes to comedi */
+ /*
+ * Always DMA 1/2 FIFO. Buffer (dmaBuff?) is (at least) twice that
+ * size. After transferring, interrupt processes 1/2 FIFO and
+ * passes to comedi
+ */
s16 dma0Offset; /* current processing offset (0, 1/2) */
uint16_t *dma0Buff[DMA_CHAIN_COUNT]; /* DMA buffers (for ADC) */
dma_addr_t dma0BuffPhysAddr[DMA_CHAIN_COUNT]; /* physical addresses */
@@ -581,7 +576,8 @@ struct rtdPrivate {
/* User output N source select (write only) */
#define RtdUsrOutSource(dev, n, v) \
- writel(v, devpriv->las0+((n <= 0) ? LAS0_UOUT0_SELECT : LAS0_UOUT1_SELECT))
+ writel(v, devpriv->las0+((n <= 0) ? LAS0_UOUT0_SELECT : \
+ LAS0_UOUT1_SELECT))
/* Digital IO */
#define RtdDio0Read(dev) \
@@ -608,7 +604,8 @@ struct rtdPrivate {
/* Write one data value (sign + 12bit + marker bits) */
/* Note: matches what DMA would put. Actual value << 3 */
#define RtdDacFifoPut(dev, n, v) \
- writew((v), devpriv->las1 + (((n) == 0) ? LAS1_DAC1_FIFO : LAS1_DAC2_FIFO))
+ writew((v), devpriv->las1 + (((n) == 0) ? LAS1_DAC1_FIFO : \
+ LAS1_DAC2_FIFO))
/* Start single DAC conversion */
#define RtdDacUpdate(dev, n) \
@@ -625,7 +622,8 @@ struct rtdPrivate {
/* Reset DAC FIFO */
#define RtdDacClearFifo(dev, n) \
- writel(0, devpriv->las0+(((n) == 0) ? LAS0_DAC1_RESET : LAS0_DAC2_RESET))
+ writel(0, devpriv->las0+(((n) == 0) ? LAS0_DAC1_RESET : \
+ LAS0_DAC2_RESET))
/* Set source for DMA 0 (write only, shadow?) */
#define RtdDma0Source(dev, n) \
@@ -705,22 +703,6 @@ struct rtdPrivate {
#define RtdDma1Status(dev) \
readb(devpriv->lcfg+LCFG_DMACSR1)
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attac/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int rtd_detach(struct comedi_device *dev);
-
-static struct comedi_driver rtd520Driver = {
- .driver_name = DRV_NAME,
- .module = THIS_MODULE,
- .attach = rtd_attach,
- .detach = rtd_detach,
-};
-
static int rtd_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
static int rtd_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
@@ -737,7 +719,10 @@ static int rtd_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_cmd *cmd);
static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-/* static int rtd_ai_poll (struct comedi_device *dev,struct comedi_subdevice *s); */
+/*
+ * static int rtd_ai_poll(struct comedi_device *dev,
+ * struct comedi_subdevice *s);
+ */
static int rtd_ns_to_timer(unsigned int *ns, int roundMode);
static irqreturn_t rtd_interrupt(int irq, void *d);
static int rtd520_probe_fifo_depth(struct comedi_device *dev);
@@ -857,7 +842,9 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it)
DPRINTK("rtd520: PCI latency = %d\n", pci_latency);
}
- /* Undocumented EPLD version (doesn't match RTD driver results) */
+ /*
+ * Undocumented EPLD version (doesn't match RTD driver results)
+ */
/*DPRINTK ("rtd520: Reading epld from %p\n",
devpriv->las0+0);
epld_version = readl (devpriv->las0+0);
@@ -970,9 +957,11 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it)
#ifdef USE_DMA
if (dev->irq > 0) {
printk("( DMA buff=%d )\n", DMA_CHAIN_COUNT);
- /* The PLX9080 has 2 DMA controllers, but there could be 4 sources:
- ADC, digital, DAC1, and DAC2. Since only the ADC supports cmd mode
- right now, this isn't an issue (yet) */
+ /*
+ * The PLX9080 has 2 DMA controllers, but there could be
+ * 4 sources: ADC, digital, DAC1, and DAC2. Since only the
+ * ADC supports cmd mode right now, this isn't an issue (yet)
+ */
devpriv->dma0Offset = 0;
for (index = 0; index < DMA_CHAIN_COUNT; index++) {
@@ -988,10 +977,14 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it)
}
/*DPRINTK ("buff[%d] @ %p virtual, %x PCI\n",
index,
- devpriv->dma0Buff[index], devpriv->dma0BuffPhysAddr[index]); */
+ devpriv->dma0Buff[index],
+ devpriv->dma0BuffPhysAddr[index]); */
}
- /* setup DMA descriptor ring (use cpu_to_le32 for byte ordering?) */
+ /*
+ * setup DMA descriptor ring (use cpu_to_le32 for byte
+ * ordering?)
+ */
devpriv->dma0Chain =
pci_alloc_consistent(devpriv->pci_dev,
sizeof(struct plx_dma_desc) *
@@ -1088,30 +1081,12 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it)
#endif
}
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int rtd_detach(struct comedi_device *dev)
+static void rtd_detach(struct comedi_device *dev)
{
#ifdef USE_DMA
int index;
#endif
- DPRINTK("comedi%d: rtd520: removing (%ld ints)\n",
- dev->minor, (devpriv ? devpriv->intCount : 0L));
- if (devpriv && devpriv->lcfg) {
- DPRINTK
- ("(int status 0x%x, overrun status 0x%x, fifo status 0x%x)...\n",
- 0xffff & RtdInterruptStatus(dev),
- 0xffff & RtdInterruptOverrunStatus(dev),
- (0xffff & RtdFifoStatus(dev)) ^ 0x6666);
- }
-
if (devpriv) {
/* Shut down any board ops by resetting it */
#ifdef USE_DMA
@@ -1148,37 +1123,24 @@ static int rtd_detach(struct comedi_device *dev)
devpriv->dma0Chain = NULL;
}
#endif /* USE_DMA */
-
- /* release IRQ */
if (dev->irq) {
- /* disable interrupt controller */
RtdPlxInterruptWrite(dev, RtdPlxInterruptRead(dev)
& ~(ICS_PLIE | ICS_DMA0_E |
ICS_DMA1_E));
free_irq(dev->irq, dev);
}
-
- /* release all regions that were allocated */
if (devpriv->las0)
iounmap(devpriv->las0);
-
if (devpriv->las1)
iounmap(devpriv->las1);
-
if (devpriv->lcfg)
iounmap(devpriv->lcfg);
-
if (devpriv->pci_dev) {
if (devpriv->got_regions)
comedi_pci_disable(devpriv->pci_dev);
-
pci_dev_put(devpriv->pci_dev);
}
}
-
- printk(KERN_INFO "comedi%d: rtd520: removed.\n", dev->minor);
-
- return 0;
}
/*
@@ -1278,7 +1240,8 @@ static int rtd520_probe_fifo_depth(struct comedi_device *dev)
}
}
if (i == limit) {
- printk(KERN_INFO "\ncomedi: %s: failed to probe fifo size.\n", DRV_NAME);
+ printk(KERN_INFO "\ncomedi: %s: failed to probe fifo size.\n",
+ DRV_NAME);
return -EIO;
}
RtdAdcClearFifo(dev);
@@ -1378,9 +1341,10 @@ static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s,
d = RtdAdcFifoGet(dev); /* get 2s comp value */
d = d >> 3; /* low 3 bits are marker lines */
- if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan))
- sample = d + 2048; /* convert to comedi unsigned data */
- else
+ if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan)) {
+ /* convert to comedi unsigned data */
+ sample = d + 2048;
+ } else
sample = d;
if (!comedi_buf_put(s->async, sample))
@@ -1406,9 +1370,10 @@ static int ai_read_dregs(struct comedi_device *dev, struct comedi_subdevice *s)
}
d = d >> 3; /* low 3 bits are marker lines */
- if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan))
- sample = d + 2048; /* convert to comedi unsigned data */
- else
+ if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan)) {
+ /* convert to comedi unsigned data */
+ sample = d + 2048;
+ } else
sample = d;
if (!comedi_buf_put(s->async, sample))
@@ -1525,7 +1490,9 @@ static int ai_process_dma(struct comedi_device *dev, struct comedi_subdevice *s)
comedi_buf_memcpy_to(s->async, 0, dp, n);
comedi_buf_write_free(s->async, n);
- /* always at least 1 scan -- 1/2 FIFO is larger than our max scan list */
+ /*
+ * always at least 1 scan -- 1/2 FIFO is larger than our max scan list
+ */
s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS;
if (++devpriv->dma0Offset >= DMA_CHAIN_COUNT) { /* next buffer */
@@ -1989,7 +1956,7 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
(TRANS_TARGET_PERIOD * cmd->chanlist_len) /
cmd->scan_begin_arg;
if (devpriv->transCount < cmd->chanlist_len) {
- /* tranfer after each scan (and avoid 0) */
+ /* transfer after each scan (and avoid 0) */
devpriv->transCount = cmd->chanlist_len;
} else { /* make a multiple of scan length */
devpriv->transCount =
@@ -2005,12 +1972,12 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->transCount = 0;
devpriv->flags &= ~SEND_EOS;
} else {
- /* interrupt for each tranfer */
+ /* interrupt for each transfer */
RtdAboutCounter(dev, devpriv->transCount - 1);
}
DPRINTK
- ("rtd520: scanLen=%d tranferCount=%d fifoLen=%d\n scanTime(ns)=%d flags=0x%x\n",
+ ("rtd520: scanLen=%d transferCount=%d fifoLen=%d\n scanTime(ns)=%d flags=0x%x\n",
cmd->chanlist_len, devpriv->transCount, devpriv->fifoLen,
cmd->scan_begin_arg, devpriv->flags);
} else { /* unknown timing, just use 1/2 FIFO */
@@ -2348,47 +2315,38 @@ static int rtd_dio_insn_config(struct comedi_device *dev,
return 1;
}
-/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
- */
-static int __devinit rtd520Driver_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
+static struct comedi_driver rtd520_driver = {
+ .driver_name = "rtd520",
+ .module = THIS_MODULE,
+ .attach = rtd_attach,
+ .detach = rtd_detach,
+};
+
+static int __devinit rtd520_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, rtd520Driver.driver_name);
+ return comedi_pci_auto_config(dev, &rtd520_driver);
}
-static void __devexit rtd520Driver_pci_remove(struct pci_dev *dev)
+static void __devexit rtd520_pci_remove(struct pci_dev *dev)
{
comedi_pci_auto_unconfig(dev);
}
-static struct pci_driver rtd520Driver_pci_driver = {
- .id_table = rtd520_pci_table,
- .probe = &rtd520Driver_pci_probe,
- .remove = __devexit_p(&rtd520Driver_pci_remove)
+static DEFINE_PCI_DEVICE_TABLE(rtd520_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x7520) },
+ { PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x4520) },
+ { 0 }
};
+MODULE_DEVICE_TABLE(pci, rtd520_pci_table);
-static int __init rtd520Driver_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&rtd520Driver);
- if (retval < 0)
- return retval;
-
- rtd520Driver_pci_driver.name = (char *)rtd520Driver.driver_name;
- return pci_register_driver(&rtd520Driver_pci_driver);
-}
-
-static void __exit rtd520Driver_cleanup_module(void)
-{
- pci_unregister_driver(&rtd520Driver_pci_driver);
- comedi_driver_unregister(&rtd520Driver);
-}
-
-module_init(rtd520Driver_init_module);
-module_exit(rtd520Driver_cleanup_module);
+static struct pci_driver rtd520_pci_driver = {
+ .name = "rtd520",
+ .id_table = rtd520_pci_table,
+ .probe = rtd520_pci_probe,
+ .remove = __devexit_p(rtd520_pci_remove),
+};
+module_comedi_pci_driver(rtd520_driver, rtd520_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c
index 72042b818310..f0eb52a77881 100644
--- a/drivers/staging/comedi/drivers/rti800.c
+++ b/drivers/staging/comedi/drivers/rti800.c
@@ -138,39 +138,8 @@ struct rti800_board {
int has_ao;
};
-static const struct rti800_board boardtypes[] = {
- {"rti800", 0},
- {"rti815", 1},
-};
-
#define this_board ((const struct rti800_board *)dev->board_ptr)
-static int rti800_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int rti800_detach(struct comedi_device *dev);
-static struct comedi_driver driver_rti800 = {
- .driver_name = "rti800",
- .module = THIS_MODULE,
- .attach = rti800_attach,
- .detach = rti800_detach,
- .num_names = ARRAY_SIZE(boardtypes),
- .board_name = &boardtypes[0].name,
- .offset = sizeof(struct rti800_board),
-};
-
-static int __init driver_rti800_init_module(void)
-{
- return comedi_driver_register(&driver_rti800);
-}
-
-static void __exit driver_rti800_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_rti800);
-}
-
-module_init(driver_rti800_init_module);
-module_exit(driver_rti800_cleanup_module);
-
static irqreturn_t rti800_interrupt(int irq, void *dev);
struct rti800_private {
@@ -474,19 +443,30 @@ static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int rti800_detach(struct comedi_device *dev)
+static void rti800_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: rti800: remove\n", dev->minor);
-
if (dev->iobase)
release_region(dev->iobase, RTI800_SIZE);
-
if (dev->irq)
free_irq(dev->irq, dev);
-
- return 0;
}
+static const struct rti800_board boardtypes[] = {
+ { "rti800", 0 },
+ { "rti815", 1 },
+};
+
+static struct comedi_driver rti800_driver = {
+ .driver_name = "rti800",
+ .module = THIS_MODULE,
+ .attach = rti800_attach,
+ .detach = rti800_detach,
+ .num_names = ARRAY_SIZE(boardtypes),
+ .board_name = &boardtypes[0].name,
+ .offset = sizeof(struct rti800_board),
+};
+module_comedi_driver(rti800_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c
index f59cb11590f6..09da5c21858c 100644
--- a/drivers/staging/comedi/drivers/rti802.c
+++ b/drivers/staging/comedi/drivers/rti802.c
@@ -47,29 +47,6 @@ Configuration Options:
#define RTI802_DATALOW 1
#define RTI802_DATAHIGH 2
-static int rti802_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int rti802_detach(struct comedi_device *dev);
-static struct comedi_driver driver_rti802 = {
- .driver_name = "rti802",
- .module = THIS_MODULE,
- .attach = rti802_attach,
- .detach = rti802_detach,
-};
-
-static int __init driver_rti802_init_module(void)
-{
- return comedi_driver_register(&driver_rti802);
-}
-
-static void __exit driver_rti802_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_rti802);
-}
-
-module_init(driver_rti802_init_module);
-module_exit(driver_rti802_cleanup_module);
-
struct rti802_private {
enum {
dac_2comp, dac_straight
@@ -152,16 +129,20 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return 0;
}
-static int rti802_detach(struct comedi_device *dev)
+static void rti802_detach(struct comedi_device *dev)
{
- printk(KERN_INFO "comedi%d: rti802: remove\n", dev->minor);
-
if (dev->iobase)
release_region(dev->iobase, RTI802_SIZE);
-
- return 0;
}
+static struct comedi_driver rti802_driver = {
+ .driver_name = "rti802",
+ .module = THIS_MODULE,
+ .attach = rti802_attach,
+ .detach = rti802_detach,
+};
+module_comedi_driver(rti802_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c
index 2b34daedc3d7..7a56434eb224 100644
--- a/drivers/staging/comedi/drivers/s526.c
+++ b/drivers/staging/comedi/drivers/s526.c
@@ -230,287 +230,6 @@ struct s526_private {
*/
#define devpriv ((struct s526_private *)dev->private)
-/*
- * The struct comedi_driver structure tells the Comedi core module
- * which functions to call to configure/deconfigure (attach/detach)
- * the board, and also about the kernel module that contains
- * the device code.
- */
-static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int s526_detach(struct comedi_device *dev);
-static struct comedi_driver driver_s526 = {
- .driver_name = "s526",
- .module = THIS_MODULE,
- .attach = s526_attach,
- .detach = s526_detach,
-/* It is not necessary to implement the following members if you are
- * writing a driver for a ISA PnP or PCI card */
- /* Most drivers will support multiple types of boards by
- * having an array of board structures. These were defined
- * in s526_boards[] above. Note that the element 'name'
- * was first in the structure -- Comedi uses this fact to
- * extract the name of the board without knowing any details
- * about the structure except for its length.
- * When a device is attached (by comedi_config), the name
- * of the device is given to Comedi, and Comedi tries to
- * match it by going through the list of board names. If
- * there is a match, the address of the pointer is put
- * into dev->board_ptr and driver->attach() is called.
- *
- * Note that these are not necessary if you can determine
- * the type of board in software. ISA PnP, PCI, and PCMCIA
- * devices are such boards.
- */
- .board_name = &s526_boards[0].name,
- .offset = sizeof(struct s526_board),
- .num_names = ARRAY_SIZE(s526_boards),
-};
-
-static int s526_gpct_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data);
-static int s526_gpct_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int s526_gpct_winsn(struct comedi_device *dev,
- struct comedi_subdevice *s, struct comedi_insn *insn,
- unsigned int *data);
-static int s526_ai_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int s526_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int s526_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board. If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
- struct comedi_subdevice *s;
- int iobase;
- int i, n;
-/* short value; */
-/* int subdev_channel = 0; */
- union cmReg cmReg;
-
- printk(KERN_INFO "comedi%d: s526: ", dev->minor);
-
- iobase = it->options[0];
- if (!iobase || !request_region(iobase, S526_IOSIZE, thisboard->name)) {
- comedi_error(dev, "I/O port conflict");
- return -EIO;
- }
- dev->iobase = iobase;
-
- printk("iobase=0x%lx\n", dev->iobase);
-
- /*** make it a little quieter, exw, 8/29/06
- for (i = 0; i < S526_NUM_PORTS; i++) {
- printk("0x%02x: 0x%04x\n", ADDR_REG(s526_ports[i]),
- inw(ADDR_REG(s526_ports[i])));
- }
- ***/
-
-/*
- * Initialize dev->board_name. Note that we can use the "thisboard"
- * macro now, since we just initialized it in the last line.
- */
- dev->board_ptr = &s526_boards[0];
-
- dev->board_name = thisboard->name;
-
-/*
- * Allocate the private structure area. alloc_private() is a
- * convenient macro defined in comedidev.h.
- */
- if (alloc_private(dev, sizeof(struct s526_private)) < 0)
- return -ENOMEM;
-
-/*
- * Allocate the subdevice structures. alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- */
- dev->n_subdevices = 4;
- if (alloc_subdevices(dev, dev->n_subdevices) < 0)
- return -ENOMEM;
-
- s = dev->subdevices + 0;
- /* GENERAL-PURPOSE COUNTER/TIME (GPCT) */
- s->type = COMEDI_SUBD_COUNTER;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL;
- /* KG: What does SDF_LSAMPL (see multiq3.c) mean? */
- s->n_chan = thisboard->gpct_chans;
- s->maxdata = 0x00ffffff; /* 24 bit counter */
- s->insn_read = s526_gpct_rinsn;
- s->insn_config = s526_gpct_insn_config;
- s->insn_write = s526_gpct_winsn;
-
- /* Command are not implemented yet, however they are necessary to
- allocate the necessary memory for the comedi_async struct (used
- to trigger the GPCT in case of pulsegenerator function */
- /* s->do_cmd = s526_gpct_cmd; */
- /* s->do_cmdtest = s526_gpct_cmdtest; */
- /* s->cancel = s526_gpct_cancel; */
-
- s = dev->subdevices + 1;
- /* dev->read_subdev=s; */
- /* analog input subdevice */
- s->type = COMEDI_SUBD_AI;
- /* we support differential */
- s->subdev_flags = SDF_READABLE | SDF_DIFF;
- /* channels 0 to 7 are the regular differential inputs */
- /* channel 8 is "reference 0" (+10V), channel 9 is "reference 1" (0V) */
- s->n_chan = 10;
- s->maxdata = 0xffff;
- s->range_table = &range_bipolar10;
- s->len_chanlist = 16; /* This is the maximum chanlist length that
- the board can handle */
- s->insn_read = s526_ai_rinsn;
- s->insn_config = s526_ai_insn_config;
-
- s = dev->subdevices + 2;
- /* analog output subdevice */
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE;
- s->n_chan = 4;
- s->maxdata = 0xffff;
- s->range_table = &range_bipolar10;
- s->insn_write = s526_ao_winsn;
- s->insn_read = s526_ao_rinsn;
-
- s = dev->subdevices + 3;
- /* digital i/o subdevice */
- if (thisboard->have_dio) {
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 8;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = s526_dio_insn_bits;
- s->insn_config = s526_dio_insn_config;
- } else {
- s->type = COMEDI_SUBD_UNUSED;
- }
-
- printk(KERN_INFO "attached\n");
-
- return 1;
-
-#if 0
- /* Example of Counter Application */
- /* One-shot (software trigger) */
- cmReg.reg.coutSource = 0; /* out RCAP */
- cmReg.reg.coutPolarity = 1; /* Polarity inverted */
- cmReg.reg.autoLoadResetRcap = 1;/* Auto load 0:disabled, 1:enabled */
- cmReg.reg.hwCtEnableSource = 3; /* NOT RCAP */
- cmReg.reg.ctEnableCtrl = 2; /* Hardware */
- cmReg.reg.clockSource = 2; /* Internal */
- cmReg.reg.countDir = 1; /* Down */
- cmReg.reg.countDirCtrl = 1; /* Software */
- cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */
- cmReg.reg.preloadRegSel = 0; /* PR0 */
- cmReg.reg.reserved = 0;
-
- outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
-
- outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel));
- outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel));
-
- /* Reset the counter */
- outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
- /* Load the counter from PR0 */
- outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
- /* Reset RCAP (fires one-shot) */
- outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel));
-
-#else
-
- /* Set Counter Mode Register */
- cmReg.reg.coutSource = 0; /* out RCAP */
- cmReg.reg.coutPolarity = 0; /* Polarity inverted */
- cmReg.reg.autoLoadResetRcap = 0; /* Auto load disabled */
- cmReg.reg.hwCtEnableSource = 2; /* NOT RCAP */
- cmReg.reg.ctEnableCtrl = 1; /* 1: Software, >1 : Hardware */
- cmReg.reg.clockSource = 3; /* x4 */
- cmReg.reg.countDir = 0; /* up */
- cmReg.reg.countDirCtrl = 0; /* quadrature */
- cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */
- cmReg.reg.preloadRegSel = 0; /* PR0 */
- cmReg.reg.reserved = 0;
-
- n = 0;
- printk(KERN_INFO "Mode reg=0x%04x, 0x%04lx\n",
- cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
- outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
- udelay(1000);
- printk(KERN_INFO "Read back mode reg=0x%04x\n",
- inw(ADDR_CHAN_REG(REG_C0M, n)));
-
- /* Load the pre-load register high word */
-/* value = (short) (0x55); */
-/* outw(value, ADDR_CHAN_REG(REG_C0H, n)); */
-
- /* Load the pre-load register low word */
-/* value = (short)(0xaa55); */
-/* outw(value, ADDR_CHAN_REG(REG_C0L, n)); */
-
- /* Write the Counter Control Register */
-/* outw(value, ADDR_CHAN_REG(REG_C0C, 0)); */
-
- /* Reset the counter if it is software preload */
- if (cmReg.reg.autoLoadResetRcap == 0) {
- /* Reset the counter */
- outw(0x8000, ADDR_CHAN_REG(REG_C0C, n));
- /* Load the counter from PR0 */
- outw(0x4000, ADDR_CHAN_REG(REG_C0C, n));
- }
-
- outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
- udelay(1000);
- printk(KERN_INFO "Read back mode reg=0x%04x\n",
- inw(ADDR_CHAN_REG(REG_C0M, n)));
-
-#endif
- printk(KERN_INFO "Current registres:\n");
-
- for (i = 0; i < S526_NUM_PORTS; i++) {
- printk(KERN_INFO "0x%02lx: 0x%04x\n",
- ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i])));
- }
- return 1;
-}
-
-/*
- * _detach is called to deconfigure a device. It should deallocate
- * resources.
- * This function is also called when _attach() fails, so it should be
- * careful not to release resources that were not necessarily
- * allocated by _attach(). dev->private and dev->subdevices are
- * deallocated automatically by the core.
- */
-static int s526_detach(struct comedi_device *dev)
-{
- printk(KERN_INFO "comedi%d: s526: remove\n", dev->minor);
-
- if (dev->iobase > 0)
- release_region(dev->iobase, S526_IOSIZE);
-
- return 0;
-}
-
static int s526_gpct_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
unsigned int *data)
@@ -1023,22 +742,218 @@ static int s526_dio_insn_config(struct comedi_device *dev,
return 1;
}
+static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+ struct comedi_subdevice *s;
+ int iobase;
+ int i, n;
+/* short value; */
+/* int subdev_channel = 0; */
+ union cmReg cmReg;
+
+ printk(KERN_INFO "comedi%d: s526: ", dev->minor);
+
+ iobase = it->options[0];
+ if (!iobase || !request_region(iobase, S526_IOSIZE, thisboard->name)) {
+ comedi_error(dev, "I/O port conflict");
+ return -EIO;
+ }
+ dev->iobase = iobase;
+
+ printk("iobase=0x%lx\n", dev->iobase);
+
+ /*** make it a little quieter, exw, 8/29/06
+ for (i = 0; i < S526_NUM_PORTS; i++) {
+ printk("0x%02x: 0x%04x\n", ADDR_REG(s526_ports[i]),
+ inw(ADDR_REG(s526_ports[i])));
+ }
+ ***/
+
/*
- * A convenient macro that defines init_module() and cleanup_module(),
- * as necessary.
+ * Initialize dev->board_name. Note that we can use the "thisboard"
+ * macro now, since we just initialized it in the last line.
*/
-static int __init driver_s526_init_module(void)
-{
- return comedi_driver_register(&driver_s526);
+ dev->board_ptr = &s526_boards[0];
+
+ dev->board_name = thisboard->name;
+
+/*
+ * Allocate the private structure area. alloc_private() is a
+ * convenient macro defined in comedidev.h.
+ */
+ if (alloc_private(dev, sizeof(struct s526_private)) < 0)
+ return -ENOMEM;
+
+/*
+ * Allocate the subdevice structures. alloc_subdevice() is a
+ * convenient macro defined in comedidev.h.
+ */
+ dev->n_subdevices = 4;
+ if (alloc_subdevices(dev, dev->n_subdevices) < 0)
+ return -ENOMEM;
+
+ s = dev->subdevices + 0;
+ /* GENERAL-PURPOSE COUNTER/TIME (GPCT) */
+ s->type = COMEDI_SUBD_COUNTER;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL;
+ /* KG: What does SDF_LSAMPL (see multiq3.c) mean? */
+ s->n_chan = thisboard->gpct_chans;
+ s->maxdata = 0x00ffffff; /* 24 bit counter */
+ s->insn_read = s526_gpct_rinsn;
+ s->insn_config = s526_gpct_insn_config;
+ s->insn_write = s526_gpct_winsn;
+
+ /* Command are not implemented yet, however they are necessary to
+ allocate the necessary memory for the comedi_async struct (used
+ to trigger the GPCT in case of pulsegenerator function */
+ /* s->do_cmd = s526_gpct_cmd; */
+ /* s->do_cmdtest = s526_gpct_cmdtest; */
+ /* s->cancel = s526_gpct_cancel; */
+
+ s = dev->subdevices + 1;
+ /* dev->read_subdev=s; */
+ /* analog input subdevice */
+ s->type = COMEDI_SUBD_AI;
+ /* we support differential */
+ s->subdev_flags = SDF_READABLE | SDF_DIFF;
+ /* channels 0 to 7 are the regular differential inputs */
+ /* channel 8 is "reference 0" (+10V), channel 9 is "reference 1" (0V) */
+ s->n_chan = 10;
+ s->maxdata = 0xffff;
+ s->range_table = &range_bipolar10;
+ s->len_chanlist = 16; /* This is the maximum chanlist length that
+ the board can handle */
+ s->insn_read = s526_ai_rinsn;
+ s->insn_config = s526_ai_insn_config;
+
+ s = dev->subdevices + 2;
+ /* analog output subdevice */
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 4;
+ s->maxdata = 0xffff;
+ s->range_table = &range_bipolar10;
+ s->insn_write = s526_ao_winsn;
+ s->insn_read = s526_ao_rinsn;
+
+ s = dev->subdevices + 3;
+ /* digital i/o subdevice */
+ if (thisboard->have_dio) {
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 8;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = s526_dio_insn_bits;
+ s->insn_config = s526_dio_insn_config;
+ } else {
+ s->type = COMEDI_SUBD_UNUSED;
+ }
+
+ printk(KERN_INFO "attached\n");
+
+ return 1;
+
+#if 0
+ /* Example of Counter Application */
+ /* One-shot (software trigger) */
+ cmReg.reg.coutSource = 0; /* out RCAP */
+ cmReg.reg.coutPolarity = 1; /* Polarity inverted */
+ cmReg.reg.autoLoadResetRcap = 1;/* Auto load 0:disabled, 1:enabled */
+ cmReg.reg.hwCtEnableSource = 3; /* NOT RCAP */
+ cmReg.reg.ctEnableCtrl = 2; /* Hardware */
+ cmReg.reg.clockSource = 2; /* Internal */
+ cmReg.reg.countDir = 1; /* Down */
+ cmReg.reg.countDirCtrl = 1; /* Software */
+ cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */
+ cmReg.reg.preloadRegSel = 0; /* PR0 */
+ cmReg.reg.reserved = 0;
+
+ outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
+
+ outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel));
+ outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel));
+
+ /* Reset the counter */
+ outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+ /* Load the counter from PR0 */
+ outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+ /* Reset RCAP (fires one-shot) */
+ outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel));
+
+#else
+
+ /* Set Counter Mode Register */
+ cmReg.reg.coutSource = 0; /* out RCAP */
+ cmReg.reg.coutPolarity = 0; /* Polarity inverted */
+ cmReg.reg.autoLoadResetRcap = 0; /* Auto load disabled */
+ cmReg.reg.hwCtEnableSource = 2; /* NOT RCAP */
+ cmReg.reg.ctEnableCtrl = 1; /* 1: Software, >1 : Hardware */
+ cmReg.reg.clockSource = 3; /* x4 */
+ cmReg.reg.countDir = 0; /* up */
+ cmReg.reg.countDirCtrl = 0; /* quadrature */
+ cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */
+ cmReg.reg.preloadRegSel = 0; /* PR0 */
+ cmReg.reg.reserved = 0;
+
+ n = 0;
+ printk(KERN_INFO "Mode reg=0x%04x, 0x%04lx\n",
+ cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
+ outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
+ udelay(1000);
+ printk(KERN_INFO "Read back mode reg=0x%04x\n",
+ inw(ADDR_CHAN_REG(REG_C0M, n)));
+
+ /* Load the pre-load register high word */
+/* value = (short) (0x55); */
+/* outw(value, ADDR_CHAN_REG(REG_C0H, n)); */
+
+ /* Load the pre-load register low word */
+/* value = (short)(0xaa55); */
+/* outw(value, ADDR_CHAN_REG(REG_C0L, n)); */
+
+ /* Write the Counter Control Register */
+/* outw(value, ADDR_CHAN_REG(REG_C0C, 0)); */
+
+ /* Reset the counter if it is software preload */
+ if (cmReg.reg.autoLoadResetRcap == 0) {
+ /* Reset the counter */
+ outw(0x8000, ADDR_CHAN_REG(REG_C0C, n));
+ /* Load the counter from PR0 */
+ outw(0x4000, ADDR_CHAN_REG(REG_C0C, n));
+ }
+
+ outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
+ udelay(1000);
+ printk(KERN_INFO "Read back mode reg=0x%04x\n",
+ inw(ADDR_CHAN_REG(REG_C0M, n)));
+
+#endif
+ printk(KERN_INFO "Current registres:\n");
+
+ for (i = 0; i < S526_NUM_PORTS; i++) {
+ printk(KERN_INFO "0x%02lx: 0x%04x\n",
+ ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i])));
+ }
+ return 1;
}
-static void __exit driver_s526_cleanup_module(void)
+static void s526_detach(struct comedi_device *dev)
{
- comedi_driver_unregister(&driver_s526);
+ if (dev->iobase > 0)
+ release_region(dev->iobase, S526_IOSIZE);
}
-module_init(driver_s526_init_module);
-module_exit(driver_s526_cleanup_module);
+static struct comedi_driver s526_driver = {
+ .driver_name = "s526",
+ .module = THIS_MODULE,
+ .attach = s526_attach,
+ .detach = s526_detach,
+ .board_name = &s526_boards[0].name,
+ .offset = sizeof(struct s526_board),
+ .num_names = ARRAY_SIZE(s526_boards),
+};
+module_comedi_driver(s526_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c
index 23fc64b9988e..7beb8f6853af 100644
--- a/drivers/staging/comedi/drivers/s626.c
+++ b/drivers/staging/comedi/drivers/s626.c
@@ -79,12 +79,17 @@ INSN_CONFIG instructions:
#include "comedi_fc.h"
#include "s626.h"
-MODULE_AUTHOR("Gianluca Palli <gpalli@deis.unibo.it>");
-MODULE_DESCRIPTION("Sensoray 626 Comedi driver module");
-MODULE_LICENSE("GPL");
+#define PCI_VENDOR_ID_S626 0x1131
+#define PCI_DEVICE_ID_S626 0x7146
+#define PCI_SUBVENDOR_ID_S626 0x6000
+#define PCI_SUBDEVICE_ID_S626 0x0272
struct s626_board {
const char *name;
+ int vendor_id;
+ int device_id;
+ int subvendor_id;
+ int subdevice_id;
int ai_chans;
int ai_bits;
int ao_chans;
@@ -97,6 +102,10 @@ struct s626_board {
static const struct s626_board s626_boards[] = {
{
.name = "s626",
+ .vendor_id = PCI_VENDOR_ID_S626,
+ .device_id = PCI_DEVICE_ID_S626,
+ .subvendor_id = PCI_SUBVENDOR_ID_S626,
+ .subdevice_id = PCI_SUBDEVICE_ID_S626,
.ai_chans = S626_ADC_CHANNELS,
.ai_bits = 14,
.ao_chans = S626_DAC_CHANNELS,
@@ -108,30 +117,6 @@ static const struct s626_board s626_boards[] = {
};
#define thisboard ((const struct s626_board *)dev->board_ptr)
-#define PCI_VENDOR_ID_S626 0x1131
-#define PCI_DEVICE_ID_S626 0x7146
-
-/*
- * For devices with vendor:device id == 0x1131:0x7146 you must specify
- * also subvendor:subdevice ids, because otherwise it will conflict with
- * Philips SAA7146 media/dvb based cards.
- */
-static DEFINE_PCI_DEVICE_TABLE(s626_pci_table) = {
- {PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626, 0x6000, 0x0272, 0, 0, 0},
- {0}
-};
-
-MODULE_DEVICE_TABLE(pci, s626_pci_table);
-
-static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int s626_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_s626 = {
- .driver_name = "s626",
- .module = THIS_MODULE,
- .attach = s626_attach,
- .detach = s626_detach,
-};
struct s626_private {
struct pci_dev *pdev;
@@ -224,44 +209,6 @@ static struct dio_private *dio_private_word[]={
#define devpriv ((struct s626_private *)dev->private)
#define diopriv ((struct dio_private *)s->private)
-static int __devinit driver_s626_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
-{
- return comedi_pci_auto_config(dev, driver_s626.driver_name);
-}
-
-static void __devexit driver_s626_pci_remove(struct pci_dev *dev)
-{
- comedi_pci_auto_unconfig(dev);
-}
-
-static struct pci_driver driver_s626_pci_driver = {
- .id_table = s626_pci_table,
- .probe = &driver_s626_pci_probe,
- .remove = __devexit_p(&driver_s626_pci_remove)
-};
-
-static int __init driver_s626_init_module(void)
-{
- int retval;
-
- retval = comedi_driver_register(&driver_s626);
- if (retval < 0)
- return retval;
-
- driver_s626_pci_driver.name = (char *)driver_s626.driver_name;
- return pci_register_driver(&driver_s626_pci_driver);
-}
-
-static void __exit driver_s626_cleanup_module(void)
-{
- pci_unregister_driver(&driver_s626_pci_driver);
- comedi_driver_unregister(&driver_s626);
-}
-
-module_init(driver_s626_init_module);
-module_exit(driver_s626_cleanup_module);
-
/* ioctl routines */
static int s626_ai_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
@@ -554,17 +501,17 @@ static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it)
resource_size_t resourceStart;
dma_addr_t appdma;
struct comedi_subdevice *s;
- const struct pci_device_id *ids;
struct pci_dev *pdev = NULL;
if (alloc_private(dev, sizeof(struct s626_private)) < 0)
return -ENOMEM;
- for (i = 0; i < (ARRAY_SIZE(s626_pci_table) - 1) && !pdev; i++) {
- ids = &s626_pci_table[i];
+ for (i = 0; i < ARRAY_SIZE(s626_boards) && !pdev; i++) {
do {
- pdev = pci_get_subsys(ids->vendor, ids->device,
- ids->subvendor, ids->subdevice,
+ pdev = pci_get_subsys(s626_boards[i].vendor_id,
+ s626_boards[i].device_id,
+ s626_boards[i].subvendor_id,
+ s626_boards[i].subdevice_id,
pdev);
if ((it->options[0] || it->options[1]) && pdev) {
@@ -1365,7 +1312,7 @@ static irqreturn_t s626_irq_handler(int irq, void *d)
return IRQ_HANDLED;
}
-static int s626_detach(struct comedi_device *dev)
+static void s626_detach(struct comedi_device *dev)
{
if (devpriv) {
/* stop ai_command */
@@ -1389,20 +1336,14 @@ static int s626_detach(struct comedi_device *dev)
if (dev->irq)
free_irq(dev->irq, dev);
-
if (devpriv->base_addr)
iounmap(devpriv->base_addr);
-
if (devpriv->pdev) {
if (devpriv->got_regions)
comedi_pci_disable(devpriv->pdev);
pci_dev_put(devpriv->pdev);
}
}
-
- DEBUG("s626_detach: S626 detached!\n");
-
- return 0;
}
/*
@@ -3367,3 +3308,45 @@ static void CountersInit(struct comedi_device *dev)
DEBUG("CountersInit: counters initialized\n");
}
+
+static struct comedi_driver s626_driver = {
+ .driver_name = "s626",
+ .module = THIS_MODULE,
+ .attach = s626_attach,
+ .detach = s626_detach,
+};
+
+static int __devinit s626_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ return comedi_pci_auto_config(dev, &s626_driver);
+}
+
+static void __devexit s626_pci_remove(struct pci_dev *dev)
+{
+ comedi_pci_auto_unconfig(dev);
+}
+
+/*
+ * For devices with vendor:device id == 0x1131:0x7146 you must specify
+ * also subvendor:subdevice ids, because otherwise it will conflict with
+ * Philips SAA7146 media/dvb based cards.
+ */
+static DEFINE_PCI_DEVICE_TABLE(s626_pci_table) = {
+ { PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626,
+ PCI_SUBVENDOR_ID_S626, PCI_SUBDEVICE_ID_S626, 0, 0, 0 },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, s626_pci_table);
+
+static struct pci_driver s626_pci_driver = {
+ .name = "s626",
+ .id_table = s626_pci_table,
+ .probe = s626_pci_probe,
+ .remove = __devexit_p(s626_pci_remove),
+};
+module_comedi_pci_driver(s626_driver, s626_pci_driver);
+
+MODULE_AUTHOR("Gianluca Palli <gpalli@deis.unibo.it>");
+MODULE_DESCRIPTION("Sensoray 626 Comedi driver module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c
index d880c2f6fbc1..6342bc5ddb3e 100644
--- a/drivers/staging/comedi/drivers/serial2002.c
+++ b/drivers/staging/comedi/drivers/serial2002.c
@@ -43,20 +43,10 @@ Status: in development
#include <linux/serial.h>
#include <linux/poll.h>
-/*
- * Board descriptions for two imaginary boards. Describing the
- * boards in this way is optional, and completely driver-dependent.
- * Some drivers use arrays such as this, other do not.
- */
struct serial2002_board {
const char *name;
};
-static const struct serial2002_board serial2002_boards[] = {
- {
- .name = "serial2002"}
-};
-
/*
* Useful for shorthand access to the particular board structure
*/
@@ -89,35 +79,6 @@ struct serial2002_private {
*/
#define devpriv ((struct serial2002_private *)dev->private)
-static int serial2002_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int serial2002_detach(struct comedi_device *dev);
-struct comedi_driver driver_serial2002 = {
- .driver_name = "serial2002",
- .module = THIS_MODULE,
- .attach = serial2002_attach,
- .detach = serial2002_detach,
- .board_name = &serial2002_boards[0].name,
- .offset = sizeof(struct serial2002_board),
- .num_names = ARRAY_SIZE(serial2002_boards),
-};
-
-static int serial2002_di_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int serial2002_do_winsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int serial2002_ai_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int serial2002_ao_winsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int serial2002_ao_rinsn(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
struct serial_data {
enum { is_invalid, is_digital, is_channel } kind;
int index;
@@ -887,32 +848,34 @@ static int serial2002_attach(struct comedi_device *dev,
return 1;
}
-static int serial2002_detach(struct comedi_device *dev)
+static void serial2002_detach(struct comedi_device *dev)
{
struct comedi_subdevice *s;
int i;
- dev_dbg(dev->hw_dev, "comedi%d: remove\n", dev->minor);
for (i = 0; i < 5; i++) {
s = &dev->subdevices[i];
kfree(s->maxdata_list);
kfree(s->range_table_list);
}
- return 0;
-}
-
-static int __init driver_serial2002_init_module(void)
-{
- return comedi_driver_register(&driver_serial2002);
}
-static void __exit driver_serial2002_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_serial2002);
-}
+static const struct serial2002_board serial2002_boards[] = {
+ {
+ .name = "serial2002"
+ },
+};
-module_init(driver_serial2002_init_module);
-module_exit(driver_serial2002_cleanup_module);
+static struct comedi_driver serial2002_driver = {
+ .driver_name = "serial2002",
+ .module = THIS_MODULE,
+ .attach = serial2002_attach,
+ .detach = serial2002_detach,
+ .board_name = &serial2002_boards[0].name,
+ .offset = sizeof(struct serial2002_board),
+ .num_names = ARRAY_SIZE(serial2002_boards),
+};
+module_comedi_driver(serial2002_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c
index ed69008f0d39..7d13ffa7f4f9 100644
--- a/drivers/staging/comedi/drivers/skel.c
+++ b/drivers/staging/comedi/drivers/skel.c
@@ -156,7 +156,7 @@ struct skel_private {
* the device code.
*/
static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int skel_detach(struct comedi_device *dev);
+static void skel_detach(struct comedi_device *dev);
static struct comedi_driver driver_skel = {
.driver_name = "dummy",
.module = THIS_MODULE,
@@ -295,11 +295,8 @@ static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it)
* allocated by _attach(). dev->private and dev->subdevices are
* deallocated automatically by the core.
*/
-static int skel_detach(struct comedi_device *dev)
+static void skel_detach(struct comedi_device *dev)
{
- pr_info("comedi%d: skel: remove\n", dev->minor);
-
- return 0;
}
/*
@@ -623,7 +620,7 @@ static int skel_dio_insn_config(struct comedi_device *dev,
static int __devinit driver_skel_pci_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
- return comedi_pci_auto_config(dev, driver_skel.driver_name);
+ return comedi_pci_auto_config(dev, &driver_skel);
}
static void __devexit driver_skel_pci_remove(struct pci_dev *dev)
diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/staging/comedi/drivers/ssv_dnp.c
index 526de2efa125..16c4f5a757bb 100644
--- a/drivers/staging/comedi/drivers/ssv_dnp.c
+++ b/drivers/staging/comedi/drivers/ssv_dnp.c
@@ -59,16 +59,6 @@ struct dnp_board {
int have_dio;
};
-/* We only support one DNP 'board' variant at the moment */
-static const struct dnp_board dnp_boards[] = {
-{
- .name = "dnp-1486",
- .ai_chans = 16,
- .ai_bits = 12,
- .have_dio = 1,
- },
-};
-
/* Useful for shorthand access to the particular board structure ----------- */
#define thisboard ((const struct dnp_board *)dev->board_ptr)
@@ -81,136 +71,6 @@ struct dnp_private_data {
#define devpriv ((dnp_private *)dev->private)
/* ------------------------------------------------------------------------- */
-/* The struct comedi_driver structure tells the Comedi core module which */
-/* functions to call to configure/deconfigure (attach/detach) the board, and */
-/* also about the kernel module that contains the device code. */
-/* */
-/* In the following section we define the API of this driver. */
-/* ------------------------------------------------------------------------- */
-
-static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it);
-static int dnp_detach(struct comedi_device *dev);
-
-static struct comedi_driver driver_dnp = {
- .driver_name = "ssv_dnp",
- .module = THIS_MODULE,
- .attach = dnp_attach,
- .detach = dnp_detach,
- .board_name = &dnp_boards[0].name,
- /* only necessary for non-PnP devs */
- .offset = sizeof(struct dnp_board), /* like ISA-PnP, PCI or PCMCIA */
- .num_names = ARRAY_SIZE(dnp_boards),
-};
-
-static int __init driver_dnp_init_module(void)
-{
- return comedi_driver_register(&driver_dnp);
-}
-
-static void __exit driver_dnp_cleanup_module(void)
-{
- comedi_driver_unregister(&driver_dnp);
-}
-
-module_init(driver_dnp_init_module);
-module_exit(driver_dnp_cleanup_module);
-
-static int dnp_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-static int dnp_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-
-/* ------------------------------------------------------------------------- */
-/* Attach is called by comedi core to configure the driver for a particular */
-/* board. If you specified a board_name array in the driver structure, */
-/* dev->board_ptr contains that address. */
-/* ------------------------------------------------------------------------- */
-
-static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
-
- struct comedi_subdevice *s;
-
- printk(KERN_INFO "comedi%d: dnp: ", dev->minor);
-
- /* Autoprobing: this should find out which board we have. Currently */
- /* only the 1486 board is supported and autoprobing is not */
- /* implemented :-) */
- /* dev->board_ptr = dnp_probe(dev); */
-
- /* Initialize the name of the board. */
- /* We can use the "thisboard" macro now. */
- dev->board_name = thisboard->name;
-
- /* Allocate the private structure area. alloc_private() is a */
- /* convenient macro defined in comedidev.h. */
- if (alloc_private(dev, sizeof(struct dnp_private_data)) < 0)
- return -ENOMEM;
-
- /* Allocate the subdevice structures. alloc_subdevice() is a */
- /* convenient macro defined in comedidev.h. */
-
- if (alloc_subdevices(dev, 1) < 0)
- return -ENOMEM;
-
- s = dev->subdevices + 0;
- /* digital i/o subdevice */
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 20;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = dnp_dio_insn_bits;
- s->insn_config = dnp_dio_insn_config;
-
- printk("attached\n");
-
- /* We use the I/O ports 0x22,0x23 and 0xa3-0xa9, which are always
- * allocated for the primary 8259, so we don't need to allocate them
- * ourselves. */
-
- /* configure all ports as input (default) */
- outb(PAMR, CSCIR);
- outb(0x00, CSCDR);
- outb(PBMR, CSCIR);
- outb(0x00, CSCDR);
- outb(PCMR, CSCIR);
- outb((inb(CSCDR) & 0xAA), CSCDR);
-
- return 1;
-
-}
-
-/* ------------------------------------------------------------------------- */
-/* detach is called to deconfigure a device. It should deallocate the */
-/* resources. This function is also called when _attach() fails, so it */
-/* should be careful not to release resources that were not necessarily */
-/* allocated by _attach(). dev->private and dev->subdevices are */
-/* deallocated automatically by the core. */
-/* ------------------------------------------------------------------------- */
-
-static int dnp_detach(struct comedi_device *dev)
-{
-
- /* configure all ports as input (default) */
- outb(PAMR, CSCIR);
- outb(0x00, CSCDR);
- outb(PBMR, CSCIR);
- outb(0x00, CSCDR);
- outb(PCMR, CSCIR);
- outb((inb(CSCDR) & 0xAA), CSCDR);
-
- /* announce that we are finished */
- printk(KERN_INFO "comedi%d: dnp: remove\n", dev->minor);
-
- return 0;
-
-}
-
-/* ------------------------------------------------------------------------- */
/* The insn_bits interface allows packed reading/writing of DIO channels. */
/* The comedi core can convert between insn_bits and insn_read/write, so you */
/* are able to use these instructions as well. */
@@ -326,6 +186,89 @@ static int dnp_dio_insn_config(struct comedi_device *dev,
}
+static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{
+ struct comedi_subdevice *s;
+
+ printk(KERN_INFO "comedi%d: dnp: ", dev->minor);
+
+ /* Autoprobing: this should find out which board we have. Currently */
+ /* only the 1486 board is supported and autoprobing is not */
+ /* implemented :-) */
+ /* dev->board_ptr = dnp_probe(dev); */
+
+ /* Initialize the name of the board. */
+ /* We can use the "thisboard" macro now. */
+ dev->board_name = thisboard->name;
+
+ /* Allocate the private structure area. alloc_private() is a */
+ /* convenient macro defined in comedidev.h. */
+ if (alloc_private(dev, sizeof(struct dnp_private_data)) < 0)
+ return -ENOMEM;
+
+ /* Allocate the subdevice structures. alloc_subdevice() is a */
+ /* convenient macro defined in comedidev.h. */
+
+ if (alloc_subdevices(dev, 1) < 0)
+ return -ENOMEM;
+
+ s = dev->subdevices + 0;
+ /* digital i/o subdevice */
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 20;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = dnp_dio_insn_bits;
+ s->insn_config = dnp_dio_insn_config;
+
+ printk("attached\n");
+
+ /* We use the I/O ports 0x22,0x23 and 0xa3-0xa9, which are always
+ * allocated for the primary 8259, so we don't need to allocate them
+ * ourselves. */
+
+ /* configure all ports as input (default) */
+ outb(PAMR, CSCIR);
+ outb(0x00, CSCDR);
+ outb(PBMR, CSCIR);
+ outb(0x00, CSCDR);
+ outb(PCMR, CSCIR);
+ outb((inb(CSCDR) & 0xAA), CSCDR);
+
+ return 1;
+}
+
+static void dnp_detach(struct comedi_device *dev)
+{
+ outb(PAMR, CSCIR);
+ outb(0x00, CSCDR);
+ outb(PBMR, CSCIR);
+ outb(0x00, CSCDR);
+ outb(PCMR, CSCIR);
+ outb((inb(CSCDR) & 0xAA), CSCDR);
+}
+
+static const struct dnp_board dnp_boards[] = {
+ {
+ .name = "dnp-1486",
+ .ai_chans = 16,
+ .ai_bits = 12,
+ .have_dio = 1,
+ },
+};
+
+static struct comedi_driver dnp_driver = {
+ .driver_name = "ssv_dnp",
+ .module = THIS_MODULE,
+ .attach = dnp_attach,
+ .detach = dnp_detach,
+ .board_name = &dnp_boards[0].name,
+ .offset = sizeof(struct dnp_board),
+ .num_names = ARRAY_SIZE(dnp_boards),
+};
+module_comedi_driver(dnp_driver);
+
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/unioxx5.c b/drivers/staging/comedi/drivers/unioxx5.c
index f45824f0d86b..d5f1f22aa708 100644
--- a/drivers/staging/comedi/drivers/unioxx5.c
+++ b/drivers/staging/comedi/drivers/unioxx5.c
@@ -83,96 +83,188 @@ struct unioxx5_subd_priv {
unsigned char usp_prev_cn_val[3]; /* previous channel value */
};
-static int unioxx5_attach(struct comedi_device *dev,
- struct comedi_devconfig *it);
-static int unioxx5_subdev_write(struct comedi_device *dev,
- struct comedi_subdevice *subdev,
- struct comedi_insn *insn, unsigned int *data);
-static int unioxx5_subdev_read(struct comedi_device *dev,
- struct comedi_subdevice *subdev,
- struct comedi_insn *insn, unsigned int *data);
-static int unioxx5_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *subdev,
- struct comedi_insn *insn, unsigned int *data);
-static int unioxx5_detach(struct comedi_device *dev);
-static int __unioxx5_subdev_init(struct comedi_subdevice *subdev,
- int subdev_iobase, int minor);
-static int __unioxx5_digital_write(struct unioxx5_subd_priv *usp,
- unsigned int *data, int channel, int minor);
-static int __unioxx5_digital_read(struct unioxx5_subd_priv *usp,
- unsigned int *data, int channel, int minor);
-/* static void __unioxx5_digital_config(struct unioxx5_subd_priv* usp, int mode); */
-static int __unioxx5_analog_write(struct unioxx5_subd_priv *usp,
- unsigned int *data, int channel, int minor);
-static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp,
- unsigned int *data, int channel, int minor);
-static int __unioxx5_define_chan_offset(int chan_num);
-static void __unioxx5_analog_config(struct unioxx5_subd_priv *usp, int channel);
+static int __unioxx5_define_chan_offset(int chan_num)
+{
-static struct comedi_driver unioxx5_driver = {
- .driver_name = DRIVER_NAME,
- .module = THIS_MODULE,
- .attach = unioxx5_attach,
- .detach = unioxx5_detach
-};
+ if (chan_num < 0 || chan_num > 23)
+ return -1;
-static int __init unioxx5_driver_init_module(void)
+ return (chan_num >> 3) + 1;
+}
+
+#if 0 /* not used? */
+static void __unioxx5_digital_config(struct unioxx5_subd_priv *usp, int mode)
{
- return comedi_driver_register(&unioxx5_driver);
+ int i, mask;
+
+ mask = (mode == ALL_2_OUTPUT) ? 0xFF : 0x00;
+ printk("COMEDI: mode = %d\n", mask);
+
+ outb(1, usp->usp_iobase + 0);
+
+ for (i = 0; i < 3; i++)
+ outb(mask, usp->usp_iobase + i);
+
+ outb(0, usp->usp_iobase + 0);
}
+#endif
-static void __exit unioxx5_driver_cleanup_module(void)
+/* configure channels for analog i/o (even to output, odd to input) */
+static void __unioxx5_analog_config(struct unioxx5_subd_priv *usp, int channel)
{
- comedi_driver_unregister(&unioxx5_driver);
+ int chan_a, chan_b, conf, channel_offset;
+
+ channel_offset = __unioxx5_define_chan_offset(channel);
+ conf = usp->usp_prev_cn_val[channel_offset - 1];
+ chan_a = chan_b = 1;
+
+ /* setting channel A and channel B mask */
+ if (channel % 2 == 0) {
+ chan_a <<= channel & 0x07;
+ chan_b <<= (channel + 1) & 0x07;
+ } else {
+ chan_a <<= (channel - 1) & 0x07;
+ chan_b <<= channel & 0x07;
+ }
+
+ conf |= chan_a; /* even channel ot output */
+ conf &= ~chan_b; /* odd channel to input */
+
+ outb(1, usp->usp_iobase + 0);
+ outb(conf, usp->usp_iobase + channel_offset);
+ outb(0, usp->usp_iobase + 0);
+
+ usp->usp_prev_cn_val[channel_offset - 1] = conf;
}
-module_init(unioxx5_driver_init_module);
-module_exit(unioxx5_driver_cleanup_module);
+static int __unioxx5_digital_read(struct unioxx5_subd_priv *usp,
+ unsigned int *data, int channel, int minor)
+{
+ int channel_offset, mask = 1 << (channel & 0x07);
-static int unioxx5_attach(struct comedi_device *dev,
- struct comedi_devconfig *it)
+ channel_offset = __unioxx5_define_chan_offset(channel);
+ if (channel_offset < 0) {
+ printk(KERN_ERR
+ "comedi%d: undefined channel %d. channel range is 0 .. 23\n",
+ minor, channel);
+ return 0;
+ }
+
+ *data = inb(usp->usp_iobase + channel_offset);
+ *data &= mask;
+
+ /* correct the read value to 0 or 1 */
+ if (channel_offset > 1)
+ channel -= 2 << channel_offset;
+ *data >>= channel;
+ return 1;
+}
+
+static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp,
+ unsigned int *data, int channel, int minor)
{
- int iobase, i, n_subd;
- int id, num, ba;
+ int module_no, read_ch;
+ char control;
- iobase = it->options[0];
+ module_no = channel / 2;
+ read_ch = channel % 2; /* depend on type of channel (A or B) */
- dev->board_name = DRIVER_NAME;
- dev->iobase = iobase;
- iobase += UNIOXX5_SUBDEV_BASE;
+ /* defining if given module can work on input */
+ if (usp->usp_module_type[module_no] & MODULE_OUTPUT_MASK) {
+ printk(KERN_ERR
+ "comedi%d: module in position %d with id 0x%02x is for output only",
+ minor, module_no, usp->usp_module_type[module_no]);
+ return 0;
+ }
- /* defining number of subdevices and getting they types (it must be 'g01') */
- for (i = n_subd = 0, ba = iobase; i < 4; i++, ba += UNIOXX5_SUBDEV_ODDS) {
- id = inb(ba + 0xE);
- num = inb(ba + 0xF);
+ __unioxx5_analog_config(usp, channel);
+ /* sends module number to card(1 .. 12) */
+ outb(module_no + 1, usp->usp_iobase + 5);
+ outb('V', usp->usp_iobase + 6); /* sends to module (V)erify command */
+ control = inb(usp->usp_iobase); /* get control register byte */
- if (id != 'g' || num != 1)
- continue;
+ /* waits while reading four bytes will be allowed */
+ while (!((control = inb(usp->usp_iobase + 0)) & Rx4CA))
+ ;
- n_subd++;
+ /* if four bytes readding error occurs - return 0(false) */
+ if ((control & Rx4CA_ERR_MASK)) {
+ printk("COMEDI: 4 bytes error\n");
+ return 0;
}
- /* unioxx5 can has from two to four subdevices */
- if (n_subd < 2) {
+ if (read_ch)
+ *data = inw(usp->usp_iobase + 6); /* channel B */
+ else
+ *data = inw(usp->usp_iobase + 4); /* channel A */
+
+ return 1;
+}
+
+static int __unioxx5_digital_write(struct unioxx5_subd_priv *usp,
+ unsigned int *data, int channel, int minor)
+{
+ int channel_offset, val;
+ int mask = 1 << (channel & 0x07);
+
+ channel_offset = __unioxx5_define_chan_offset(channel);
+ if (channel_offset < 0) {
printk(KERN_ERR
- "your card must has at least 2 'g01' subdevices\n");
- return -1;
+ "comedi%d: undefined channel %d. channel range is 0 .. 23\n",
+ minor, channel);
+ return 0;
}
- if (alloc_subdevices(dev, n_subd) < 0) {
- printk(KERN_ERR "out of memory\n");
- return -ENOMEM;
+ /* getting previous written value */
+ val = usp->usp_prev_wr_val[channel_offset - 1];
+
+ if (*data)
+ val |= mask;
+ else
+ val &= ~mask;
+
+ outb(val, usp->usp_iobase + channel_offset);
+ /* saving new written value */
+ usp->usp_prev_wr_val[channel_offset - 1] = val;
+
+ return 1;
+}
+
+static int __unioxx5_analog_write(struct unioxx5_subd_priv *usp,
+ unsigned int *data, int channel, int minor)
+{
+ int module, i;
+
+ module = channel / 2; /* definig module number(0 .. 11) */
+ i = (channel % 2) << 1; /* depends on type of channel (A or B) */
+
+ /* defining if given module can work on output */
+ if (!(usp->usp_module_type[module] & MODULE_OUTPUT_MASK)) {
+ printk(KERN_ERR
+ "comedi%d: module in position %d with id 0x%0x is for input only!\n",
+ minor, module, usp->usp_module_type[module]);
+ return 0;
}
- /* initializing each of for same subdevices */
- for (i = 0; i < n_subd; i++, iobase += UNIOXX5_SUBDEV_ODDS) {
- if (__unioxx5_subdev_init(&dev->subdevices[i], iobase,
- dev->minor) < 0)
- return -1;
+ __unioxx5_analog_config(usp, channel);
+ /* saving minor byte */
+ usp->usp_extra_data[module][i++] = (unsigned char)(*data & 0x00FF);
+ /* saving major byte */
+ usp->usp_extra_data[module][i] = (unsigned char)((*data & 0xFF00) >> 8);
+
+ /* while(!((inb(usp->usp_iobase + 0)) & TxBE)); */
+ /* sending module number to card(1 .. 12) */
+ outb(module + 1, usp->usp_iobase + 5);
+ outb('W', usp->usp_iobase + 6); /* sends (W)rite command to module */
+
+ /* sending for bytes to module(one byte per cycle iteration) */
+ for (i = 0; i < 4; i++) {
+ while (!((inb(usp->usp_iobase + 0)) & TxBE))
+ ; /* waits while writting will be allowed */
+ outb(usp->usp_extra_data[module][i], usp->usp_iobase + 6);
}
- printk(KERN_INFO "attached\n");
- return 0;
+ return 1;
}
static int unioxx5_subdev_read(struct comedi_device *dev,
@@ -275,22 +367,6 @@ static int unioxx5_insn_config(struct comedi_device *dev,
return 0;
}
-static int unioxx5_detach(struct comedi_device *dev)
-{
- int i;
- struct comedi_subdevice *subdev;
- struct unioxx5_subd_priv *usp;
-
- for (i = 0; i < dev->n_subdevices; i++) {
- subdev = &dev->subdevices[i];
- usp = subdev->private;
- release_region(usp->usp_iobase, UNIOXX5_SIZE);
- kfree(subdev->private);
- }
-
- return 0;
-}
-
/* initializing subdevice with given address */
static int __unioxx5_subdev_init(struct comedi_subdevice *subdev,
int subdev_iobase, int minor)
@@ -362,196 +438,73 @@ static int __unioxx5_subdev_init(struct comedi_subdevice *subdev,
return 0;
}
-static int __unioxx5_digital_write(struct unioxx5_subd_priv *usp,
- unsigned int *data, int channel, int minor)
+static int unioxx5_attach(struct comedi_device *dev,
+ struct comedi_devconfig *it)
{
- int channel_offset, val;
- int mask = 1 << (channel & 0x07);
-
- channel_offset = __unioxx5_define_chan_offset(channel);
- if (channel_offset < 0) {
- printk(KERN_ERR
- "comedi%d: undefined channel %d. channel range is 0 .. 23\n",
- minor, channel);
- return 0;
- }
-
- /* getting previous written value */
- val = usp->usp_prev_wr_val[channel_offset - 1];
+ int iobase, i, n_subd;
+ int id, num, ba;
- if (*data)
- val |= mask;
- else
- val &= ~mask;
+ iobase = it->options[0];
- outb(val, usp->usp_iobase + channel_offset);
- /* saving new written value */
- usp->usp_prev_wr_val[channel_offset - 1] = val;
+ dev->board_name = DRIVER_NAME;
+ dev->iobase = iobase;
+ iobase += UNIOXX5_SUBDEV_BASE;
- return 1;
-}
+ /* defining number of subdevices and getting they types (it must be 'g01') */
+ for (i = n_subd = 0, ba = iobase; i < 4; i++, ba += UNIOXX5_SUBDEV_ODDS) {
+ id = inb(ba + 0xE);
+ num = inb(ba + 0xF);
-/* function for digital reading */
-static int __unioxx5_digital_read(struct unioxx5_subd_priv *usp,
- unsigned int *data, int channel, int minor)
-{
- int channel_offset, mask = 1 << (channel & 0x07);
+ if (id != 'g' || num != 1)
+ continue;
- channel_offset = __unioxx5_define_chan_offset(channel);
- if (channel_offset < 0) {
- printk(KERN_ERR
- "comedi%d: undefined channel %d. channel range is 0 .. 23\n",
- minor, channel);
- return 0;
+ n_subd++;
}
- *data = inb(usp->usp_iobase + channel_offset);
- *data &= mask;
-
- if (channel_offset > 1)
- channel -= 2 << channel_offset; /* this operation is created for correct readed value to 0 or 1 */
- *data >>= channel;
- return 1;
-}
-
-#if 0 /* not used? */
-static void __unioxx5_digital_config(struct unioxx5_subd_priv *usp, int mode)
-{
- int i, mask;
-
- mask = (mode == ALL_2_OUTPUT) ? 0xFF : 0x00;
- printk("COMEDI: mode = %d\n", mask);
-
- outb(1, usp->usp_iobase + 0);
-
- for (i = 0; i < 3; i++)
- outb(mask, usp->usp_iobase + i);
-
- outb(0, usp->usp_iobase + 0);
-}
-#endif
-
-static int __unioxx5_analog_write(struct unioxx5_subd_priv *usp,
- unsigned int *data, int channel, int minor)
-{
- int module, i;
-
- module = channel / 2; /* definig module number(0 .. 11) */
- i = (channel % 2) << 1; /* depends on type of channel (A or B) */
-
- /* defining if given module can work on output */
- if (!(usp->usp_module_type[module] & MODULE_OUTPUT_MASK)) {
+ /* unioxx5 can has from two to four subdevices */
+ if (n_subd < 2) {
printk(KERN_ERR
- "comedi%d: module in position %d with id 0x%0x is for input only!\n",
- minor, module, usp->usp_module_type[module]);
- return 0;
- }
-
- __unioxx5_analog_config(usp, channel);
- /* saving minor byte */
- usp->usp_extra_data[module][i++] = (unsigned char)(*data & 0x00FF);
- /* saving major byte */
- usp->usp_extra_data[module][i] = (unsigned char)((*data & 0xFF00) >> 8);
-
- /* while(!((inb(usp->usp_iobase + 0)) & TxBE)); */
- /* sending module number to card(1 .. 12) */
- outb(module + 1, usp->usp_iobase + 5);
- outb('W', usp->usp_iobase + 6); /* sends (W)rite command to module */
-
- /* sending for bytes to module(one byte per cycle iteration) */
- for (i = 0; i < 4; i++) {
- while (!((inb(usp->usp_iobase + 0)) & TxBE))
- ; /* waits while writting will be allowed */
- outb(usp->usp_extra_data[module][i], usp->usp_iobase + 6);
+ "your card must has at least 2 'g01' subdevices\n");
+ return -1;
}
- return 1;
-}
-
-static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp,
- unsigned int *data, int channel, int minor)
-{
- int module_no, read_ch;
- char control;
-
- module_no = channel / 2;
- read_ch = channel % 2; /* depend on type of channel (A or B) */
-
- /* defining if given module can work on input */
- if (usp->usp_module_type[module_no] & MODULE_OUTPUT_MASK) {
- printk(KERN_ERR
- "comedi%d: module in position %d with id 0x%02x is for output only",
- minor, module_no, usp->usp_module_type[module_no]);
- return 0;
+ if (alloc_subdevices(dev, n_subd) < 0) {
+ printk(KERN_ERR "out of memory\n");
+ return -ENOMEM;
}
- __unioxx5_analog_config(usp, channel);
- /* sends module number to card(1 .. 12) */
- outb(module_no + 1, usp->usp_iobase + 5);
- outb('V', usp->usp_iobase + 6); /* sends to module (V)erify command */
- control = inb(usp->usp_iobase); /* get control register byte */
-
- /* waits while reading four bytes will be allowed */
- while (!((control = inb(usp->usp_iobase + 0)) & Rx4CA))
- ;
-
- /* if four bytes readding error occurs - return 0(false) */
- if ((control & Rx4CA_ERR_MASK)) {
- printk("COMEDI: 4 bytes error\n");
- return 0;
+ /* initializing each of for same subdevices */
+ for (i = 0; i < n_subd; i++, iobase += UNIOXX5_SUBDEV_ODDS) {
+ if (__unioxx5_subdev_init(&dev->subdevices[i], iobase,
+ dev->minor) < 0)
+ return -1;
}
- if (read_ch)
- *data = inw(usp->usp_iobase + 6); /* channel B */
- else
- *data = inw(usp->usp_iobase + 4); /* channel A */
-
- return 1;
+ printk(KERN_INFO "attached\n");
+ return 0;
}
-/* configure channels for analog i/o (even to output, odd to input) */
-static void __unioxx5_analog_config(struct unioxx5_subd_priv *usp, int channel)
+static void unioxx5_detach(struct comedi_device *dev)
{
- int chan_a, chan_b, conf, channel_offset;
-
- channel_offset = __unioxx5_define_chan_offset(channel);
- conf = usp->usp_prev_cn_val[channel_offset - 1];
- chan_a = chan_b = 1;
+ int i;
+ struct comedi_subdevice *subdev;
+ struct unioxx5_subd_priv *usp;
- /* setting channel A and channel B mask */
- if (channel % 2 == 0) {
- chan_a <<= channel & 0x07;
- chan_b <<= (channel + 1) & 0x07;
- } else {
- chan_a <<= (channel - 1) & 0x07;
- chan_b <<= channel & 0x07;
+ for (i = 0; i < dev->n_subdevices; i++) {
+ subdev = &dev->subdevices[i];
+ usp = subdev->private;
+ release_region(usp->usp_iobase, UNIOXX5_SIZE);
+ kfree(subdev->private);
}
-
- conf |= chan_a; /* even channel ot output */
- conf &= ~chan_b; /* odd channel to input */
-
- outb(1, usp->usp_iobase + 0);
- outb(conf, usp->usp_iobase + channel_offset);
- outb(0, usp->usp_iobase + 0);
-
- usp->usp_prev_cn_val[channel_offset - 1] = conf;
}
-/* *\
- * this function defines if the given channel number *
- * enters in default numeric interspace(from 0 to 23) *
- * and it returns address offset for usage needed *
- * channel. *
-\* */
-
-static int __unioxx5_define_chan_offset(int chan_num)
-{
-
- if (chan_num < 0 || chan_num > 23)
- return -1;
-
- return (chan_num >> 3) + 1;
-}
+static struct comedi_driver unioxx5_driver = {
+ .driver_name = DRIVER_NAME,
+ .module = THIS_MODULE,
+ .attach = unioxx5_attach,
+ .detach = unioxx5_detach,
+};
+module_comedi_driver(unioxx5_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c
index bf62e0dd6f69..13d9fd3efcfd 100644
--- a/drivers/staging/comedi/drivers/usbdux.c
+++ b/drivers/staging/comedi/drivers/usbdux.c
@@ -317,6 +317,8 @@ static struct usbduxsub usbduxsub[NUMUSBDUX];
static DEFINE_SEMAPHORE(start_stop_sem);
+static struct comedi_driver driver_usbdux; /* see below for initializer */
+
/*
* Stops the data acquision
* It should be safe to call this function from any context
@@ -2304,11 +2306,11 @@ static void usbdux_firmware_request_complete_handler(const struct firmware *fw,
void *context)
{
struct usbduxsub *usbduxsub_tmp = context;
- struct usb_device *usbdev = usbduxsub_tmp->usbdev;
+ struct usb_interface *uinterf = usbduxsub_tmp->interface;
int ret;
if (fw == NULL) {
- dev_err(&usbdev->dev,
+ dev_err(&uinterf->dev,
"Firmware complete handler without firmware!\n");
return;
}
@@ -2320,11 +2322,11 @@ static void usbdux_firmware_request_complete_handler(const struct firmware *fw,
ret = firmwareUpload(usbduxsub_tmp, fw->data, fw->size);
if (ret) {
- dev_err(&usbdev->dev,
+ dev_err(&uinterf->dev,
"Could not upload firmware (err=%d)\n", ret);
goto out;
}
- comedi_usb_auto_config(usbdev, BOARDNAME);
+ comedi_usb_auto_config(uinterf, &driver_usbdux);
out:
release_firmware(fw);
}
@@ -2606,7 +2608,7 @@ static void usbduxsub_disconnect(struct usb_interface *intf)
dev_err(&intf->dev, "comedi_: BUG! called with wrong ptr!!!\n");
return;
}
- comedi_usb_auto_unconfig(udev);
+ comedi_usb_auto_unconfig(intf);
down(&start_stop_sem);
down(&usbduxsub_tmp->sem);
tidy_up(usbduxsub_tmp);
@@ -2615,46 +2617,21 @@ static void usbduxsub_disconnect(struct usb_interface *intf)
dev_dbg(&intf->dev, "comedi_: disconnected from the usb\n");
}
-/* is called when comedi-config is called */
-static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+/* common part of attach and attach_usb */
+static int usbdux_attach_common(struct comedi_device *dev,
+ struct usbduxsub *udev,
+ void *aux_data, int aux_len)
{
int ret;
- int index;
- int i;
- struct usbduxsub *udev;
-
struct comedi_subdevice *s = NULL;
- dev->private = NULL;
-
- down(&start_stop_sem);
- /* find a valid device which has been detected by the probe function of
- * the usb */
- index = -1;
- for (i = 0; i < NUMUSBDUX; i++) {
- if ((usbduxsub[i].probed) && (!usbduxsub[i].attached)) {
- index = i;
- break;
- }
- }
- if (index < 0) {
- printk(KERN_ERR "comedi%d: usbdux: error: attach failed, no "
- "usbdux devs connected to the usb bus.\n", dev->minor);
- up(&start_stop_sem);
- return -ENODEV;
- }
-
- udev = &usbduxsub[index];
down(&udev->sem);
/* pointer back to the corresponding comedi device */
udev->comedidev = dev;
/* trying to upload the firmware into the chip */
- if (comedi_aux_data(it->options, 0) &&
- it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) {
- firmwareUpload(udev, comedi_aux_data(it->options, 0),
- it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]);
- }
+ if (aux_data)
+ firmwareUpload(udev, aux_data, aux_len);
dev->board_name = BOARDNAME;
@@ -2673,13 +2650,9 @@ static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it)
dev_err(&udev->interface->dev,
"comedi%d: error alloc space for subdev\n", dev->minor);
up(&udev->sem);
- up(&start_stop_sem);
return ret;
}
- dev_info(&udev->interface->dev,
- "comedi%d: usb-device %d is attached to comedi.\n",
- dev->minor, index);
/* private structure is also simply the usb-structure */
dev->private = udev;
@@ -2776,44 +2749,91 @@ static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it)
up(&udev->sem);
- up(&start_stop_sem);
-
dev_info(&udev->interface->dev, "comedi%d: attached to usbdux.\n",
dev->minor);
return 0;
}
-static int usbdux_detach(struct comedi_device *dev)
+/* is called when comedi-config is called */
+static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- struct usbduxsub *usbduxsub_tmp;
+ int ret;
+ int index;
+ int i;
+ void *aux_data;
+ int aux_len;
- if (!dev) {
- printk(KERN_ERR
- "comedi?: usbdux: detach without dev variable...\n");
- return -EFAULT;
+ dev->private = NULL;
+
+ aux_data = comedi_aux_data(it->options, 0);
+ aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH];
+ if (aux_data == NULL)
+ aux_len = 0;
+ else if (aux_len == 0)
+ aux_data = NULL;
+
+ down(&start_stop_sem);
+ /* find a valid device which has been detected by the probe function of
+ * the usb */
+ index = -1;
+ for (i = 0; i < NUMUSBDUX; i++) {
+ if ((usbduxsub[i].probed) && (!usbduxsub[i].attached)) {
+ index = i;
+ break;
+ }
}
- usbduxsub_tmp = dev->private;
- if (!usbduxsub_tmp) {
+ if (index < 0) {
printk(KERN_ERR
- "comedi?: usbdux: detach without ptr to usbduxsub[]\n");
- return -EFAULT;
- }
+ "comedi%d: usbdux: error: attach failed, no usbdux devs connected to the usb bus.\n",
+ dev->minor);
+ ret = -ENODEV;
+ } else
+ ret = usbdux_attach_common(dev, &usbduxsub[index],
+ aux_data, aux_len);
+ up(&start_stop_sem);
+ return ret;
+}
- dev_dbg(&usbduxsub_tmp->interface->dev, "comedi%d: detach usb device\n",
- dev->minor);
+/* is called from comedi_usb_auto_config() */
+static int usbdux_attach_usb(struct comedi_device *dev,
+ struct usb_interface *uinterf)
+{
+ int ret;
+ struct usbduxsub *this_usbduxsub;
- down(&usbduxsub_tmp->sem);
- /* Don't allow detach to free the private structure */
- /* It's one entry of of usbduxsub[] */
dev->private = NULL;
- usbduxsub_tmp->attached = 0;
- usbduxsub_tmp->comedidev = NULL;
- dev_dbg(&usbduxsub_tmp->interface->dev,
- "comedi%d: detach: successfully removed\n", dev->minor);
- up(&usbduxsub_tmp->sem);
- return 0;
+
+ down(&start_stop_sem);
+ this_usbduxsub = usb_get_intfdata(uinterf);
+ if (!this_usbduxsub || !this_usbduxsub->probed) {
+ printk(KERN_ERR
+ "comedi%d: usbdux: error: attach_usb failed, not connected\n",
+ dev->minor);
+ ret = -ENODEV;
+ } else if (this_usbduxsub->attached) {
+ printk(KERN_ERR
+ "comedi%d: usbdux: error: attach_usb failed, already attached\n",
+ dev->minor);
+ ret = -ENODEV;
+ } else
+ ret = usbdux_attach_common(dev, this_usbduxsub, NULL, 0);
+ up(&start_stop_sem);
+ return ret;
+}
+
+static void usbdux_detach(struct comedi_device *dev)
+{
+ struct usbduxsub *usb = dev->private;
+
+ if (usb) {
+ down(&usb->sem);
+ dev->private = NULL;
+ usb->attached = 0;
+ usb->comedidev = NULL;
+ up(&usb->sem);
+ }
}
/* main driver struct */
@@ -2822,6 +2842,7 @@ static struct comedi_driver driver_usbdux = {
.module = THIS_MODULE,
.attach = usbdux_attach,
.detach = usbdux_detach,
+ .attach_usb = usbdux_attach_usb,
};
/* Table with the USB-devices: just now only testing IDs */
diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c
index 2a8e725b7859..7b1d21a6fc53 100644
--- a/drivers/staging/comedi/drivers/usbduxfast.c
+++ b/drivers/staging/comedi/drivers/usbduxfast.c
@@ -201,6 +201,8 @@ static struct usbduxfastsub_s usbduxfastsub[NUMUSBDUXFAST];
static DEFINE_SEMAPHORE(start_stop_sem);
+static struct comedi_driver driver_usbduxfast; /* see below for initializer */
+
/*
* bulk transfers to usbduxfast
*/
@@ -453,14 +455,15 @@ static int usbduxfastsub_start(struct usbduxfastsub_s *udfs)
/* 7f92 to zero */
local_transfer_buffer[0] = 0;
/* bRequest, "Firmware" */
- ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), USBDUXFASTSUB_FIRMWARE,
- VENDOR_DIR_OUT, /* bmRequestType */
- USBDUXFASTSUB_CPUCS, /* Value */
- 0x0000, /* Index */
- /* address of the transfer buffer */
- local_transfer_buffer,
- 1, /* Length */
- EZTIMEOUT); /* Timeout */
+ ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0),
+ USBDUXFASTSUB_FIRMWARE,
+ VENDOR_DIR_OUT, /* bmRequestType */
+ USBDUXFASTSUB_CPUCS, /* Value */
+ 0x0000, /* Index */
+ /* address of the transfer buffer */
+ local_transfer_buffer,
+ 1, /* Length */
+ EZTIMEOUT); /* Timeout */
if (ret < 0) {
printk("comedi_: usbduxfast_: control msg failed (start)\n");
return ret;
@@ -477,7 +480,8 @@ static int usbduxfastsub_stop(struct usbduxfastsub_s *udfs)
/* 7f92 to one */
local_transfer_buffer[0] = 1;
/* bRequest, "Firmware" */
- ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), USBDUXFASTSUB_FIRMWARE,
+ ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0),
+ USBDUXFASTSUB_FIRMWARE,
VENDOR_DIR_OUT, /* bmRequestType */
USBDUXFASTSUB_CPUCS, /* Value */
0x0000, /* Index */
@@ -504,14 +508,15 @@ static int usbduxfastsub_upload(struct usbduxfastsub_s *udfs,
startAddr, local_transfer_buffer[0]);
#endif
/* brequest, firmware */
- ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), USBDUXFASTSUB_FIRMWARE,
- VENDOR_DIR_OUT, /* bmRequestType */
- startAddr, /* value */
- 0x0000, /* index */
- /* our local safe buffer */
- local_transfer_buffer,
- len, /* length */
- EZTIMEOUT); /* timeout */
+ ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0),
+ USBDUXFASTSUB_FIRMWARE,
+ VENDOR_DIR_OUT, /* bmRequestType */
+ startAddr, /* value */
+ 0x0000, /* index */
+ /* our local safe buffer */
+ local_transfer_buffer,
+ len, /* length */
+ EZTIMEOUT); /* timeout */
#ifdef CONFIG_COMEDI_DEBUG
printk(KERN_DEBUG "comedi_: usbduxfast: result=%d\n", ret);
@@ -1440,7 +1445,7 @@ static void usbduxfast_firmware_request_complete_handler(const struct firmware
*fw, void *context)
{
struct usbduxfastsub_s *usbduxfastsub_tmp = context;
- struct usb_device *usbdev = usbduxfastsub_tmp->usbdev;
+ struct usb_interface *uinterf = usbduxfastsub_tmp->interface;
int ret;
if (fw == NULL)
@@ -1453,12 +1458,12 @@ static void usbduxfast_firmware_request_complete_handler(const struct firmware
ret = firmwareUpload(usbduxfastsub_tmp, fw->data, fw->size);
if (ret) {
- dev_err(&usbdev->dev,
+ dev_err(&uinterf->dev,
"Could not upload firmware (err=%d)\n", ret);
goto out;
}
- comedi_usb_auto_config(usbdev, BOARDNAME);
+ comedi_usb_auto_config(uinterf, &driver_usbduxfast);
out:
release_firmware(fw);
}
@@ -1606,7 +1611,7 @@ static void usbduxfastsub_disconnect(struct usb_interface *intf)
return;
}
- comedi_usb_auto_unconfig(udev);
+ comedi_usb_auto_unconfig(intf);
down(&start_stop_sem);
down(&udfs->sem);
@@ -1721,43 +1726,19 @@ static int usbduxfast_attach(struct comedi_device *dev,
return 0;
}
-static int usbduxfast_detach(struct comedi_device *dev)
+static void usbduxfast_detach(struct comedi_device *dev)
{
- struct usbduxfastsub_s *udfs;
-
- if (!dev) {
- printk(KERN_ERR "comedi?: usbduxfast: detach without dev "
- "variable...\n");
- return -EFAULT;
- }
-#ifdef CONFIG_COMEDI_DEBUG
- printk(KERN_DEBUG "comedi%d: usbduxfast: detach usb device\n",
- dev->minor);
-#endif
-
- udfs = dev->private;
- if (!udfs) {
- printk(KERN_ERR "comedi?: usbduxfast: detach without ptr to "
- "usbduxfastsub[]\n");
- return -EFAULT;
+ struct usbduxfastsub_s *usb = dev->private;
+
+ if (usb) {
+ down(&usb->sem);
+ down(&start_stop_sem);
+ dev->private = NULL;
+ usb->attached = 0;
+ usb->comedidev = NULL;
+ up(&start_stop_sem);
+ up(&usb->sem);
}
-
- down(&udfs->sem);
- down(&start_stop_sem);
- /*
- * Don't allow detach to free the private structure
- * It's one entry of of usbduxfastsub[]
- */
- dev->private = NULL;
- udfs->attached = 0;
- udfs->comedidev = NULL;
-#ifdef CONFIG_COMEDI_DEBUG
- printk(KERN_DEBUG "comedi%d: usbduxfast: detach: successfully "
- "removed\n", dev->minor);
-#endif
- up(&start_stop_sem);
- up(&udfs->sem);
- return 0;
}
/*
diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c
index 63c9b6dbc317..465afbdf4069 100644
--- a/drivers/staging/comedi/drivers/usbduxsigma.c
+++ b/drivers/staging/comedi/drivers/usbduxsigma.c
@@ -267,6 +267,8 @@ static struct usbduxsub usbduxsub[NUMUSBDUX];
static DEFINE_SEMAPHORE(start_stop_sem);
+static struct comedi_driver driver_usbduxsigma; /* see below for initializer */
+
/*
* Stops the data acquision
* It should be safe to call this function from any context
@@ -2312,11 +2314,11 @@ static void usbdux_firmware_request_complete_handler(const struct firmware *fw,
void *context)
{
struct usbduxsub *usbduxsub_tmp = context;
- struct usb_device *usbdev = usbduxsub_tmp->usbdev;
+ struct usb_interface *uinterf = usbduxsub_tmp->interface;
int ret;
if (fw == NULL) {
- dev_err(&usbdev->dev,
+ dev_err(&uinterf->dev,
"Firmware complete handler without firmware!\n");
return;
}
@@ -2328,11 +2330,11 @@ static void usbdux_firmware_request_complete_handler(const struct firmware *fw,
ret = firmwareUpload(usbduxsub_tmp, fw->data, fw->size);
if (ret) {
- dev_err(&usbdev->dev,
+ dev_err(&uinterf->dev,
"Could not upload firmware (err=%d)\n", ret);
goto out;
}
- comedi_usb_auto_config(usbdev, BOARDNAME);
+ comedi_usb_auto_config(uinterf, &driver_usbduxsigma);
out:
release_firmware(fw);
}
@@ -2623,7 +2625,7 @@ static void usbduxsigma_disconnect(struct usb_interface *intf)
if (usbduxsub_tmp->ao_cmd_running)
/* we are still running a command */
usbdux_ao_stop(usbduxsub_tmp, 1);
- comedi_usb_auto_unconfig(udev);
+ comedi_usb_auto_unconfig(intf);
down(&start_stop_sem);
down(&usbduxsub_tmp->sem);
tidy_up(usbduxsub_tmp);
@@ -2799,37 +2801,17 @@ static int usbduxsigma_attach(struct comedi_device *dev,
return 0;
}
-static int usbduxsigma_detach(struct comedi_device *dev)
+static void usbduxsigma_detach(struct comedi_device *dev)
{
- struct usbduxsub *usbduxsub_tmp;
+ struct usbduxsub *usb = dev->private;
- if (!dev) {
- printk(KERN_ERR
- "comedi? usbduxsigma detach: dev=NULL\n");
- return -EFAULT;
+ if (usb) {
+ down(&usb->sem);
+ dev->private = NULL;
+ usb->attached = 0;
+ usb->comedidev = NULL;
+ up(&usb->sem);
}
-
- usbduxsub_tmp = dev->private;
- if (!usbduxsub_tmp) {
- printk(KERN_ERR
- "comedi?: usbduxsigma detach: private=NULL\n");
- return -EFAULT;
- }
-
- dev_dbg(&usbduxsub_tmp->interface->dev,
- "comedi%d: detach usb device\n",
- dev->minor);
-
- down(&usbduxsub_tmp->sem);
- /* Don't allow detach to free the private structure */
- /* It's one entry of of usbduxsub[] */
- dev->private = NULL;
- usbduxsub_tmp->attached = 0;
- usbduxsub_tmp->comedidev = NULL;
- dev_info(&usbduxsub_tmp->interface->dev,
- "comedi%d: successfully detached.\n", dev->minor);
- up(&usbduxsub_tmp->sem);
- return 0;
}
/* main driver struct */
diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c
index 3d13ca6e1670..baee8d767636 100644
--- a/drivers/staging/comedi/drivers/vmk80xx.c
+++ b/drivers/staging/comedi/drivers/vmk80xx.c
@@ -151,27 +151,12 @@ MODULE_DEVICE_TABLE(usb, vmk80xx_id_table);
#define URB_RCV_FLAG (1 << 0)
#define URB_SND_FLAG (1 << 1)
-#define CONFIG_VMK80XX_DEBUG
-#undef CONFIG_VMK80XX_DEBUG
-
-#ifdef CONFIG_VMK80XX_DEBUG
-static int dbgvm = 1;
-#else
-static int dbgvm;
-#endif
-
#ifdef CONFIG_COMEDI_DEBUG
static int dbgcm = 1;
#else
static int dbgcm;
#endif
-#define dbgvm(fmt, arg...) \
-do { \
- if (dbgvm) \
- printk(KERN_DEBUG fmt, ##arg); \
-} while (0)
-
#define dbgcm(fmt, arg...) \
do { \
if (dbgcm) \
@@ -247,13 +232,13 @@ static struct vmk80xx_usb vmb[VMK80XX_MAX_BOARDS];
static DEFINE_MUTEX(glb_mutex);
+static struct comedi_driver driver_vmk80xx; /* see below for initializer */
+
static void vmk80xx_tx_callback(struct urb *urb)
{
struct vmk80xx_usb *dev = urb->context;
int stat = urb->status;
- dbgvm("vmk80xx: %s\n", __func__);
-
if (stat && !(stat == -ENOENT
|| stat == -ECONNRESET || stat == -ESHUTDOWN))
dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n",
@@ -272,8 +257,6 @@ static void vmk80xx_rx_callback(struct urb *urb)
struct vmk80xx_usb *dev = urb->context;
int stat = urb->status;
- dbgvm("vmk80xx: %s\n", __func__);
-
switch (stat) {
case 0:
break;
@@ -295,7 +278,9 @@ resubmit:
if (!usb_submit_urb(urb, GFP_KERNEL))
goto exit;
- err("comedi#: vmk80xx: %s - submit urb failed\n", __func__);
+ dev_err(&urb->dev->dev,
+ "comedi#: vmk80xx: %s - submit urb failed\n",
+ __func__);
usb_unanchor_urb(urb);
}
@@ -312,8 +297,6 @@ static int vmk80xx_check_data_link(struct vmk80xx_usb *dev)
unsigned char tx[1];
unsigned char rx[2];
- dbgvm("vmk80xx: %s\n", __func__);
-
tx_pipe = usb_sndbulkpipe(dev->udev, 0x01);
rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81);
@@ -338,8 +321,6 @@ static void vmk80xx_read_eeprom(struct vmk80xx_usb *dev, int flag)
unsigned char rx[64];
int cnt;
- dbgvm("vmk80xx: %s\n", __func__);
-
tx_pipe = usb_sndbulkpipe(dev->udev, 0x01);
rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81);
@@ -367,8 +348,6 @@ static int vmk80xx_reset_device(struct vmk80xx_usb *dev)
int ival;
size_t size;
- dbgvm("vmk80xx: %s\n", __func__);
-
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb)
return -ENOMEM;
@@ -406,8 +385,6 @@ static void vmk80xx_build_int_urb(struct urb *urb, int flag)
void (*callback) (struct urb *);
int ival;
- dbgvm("vmk80xx: %s\n", __func__);
-
if (flag & URB_RCV_FLAG) {
rx_addr = dev->ep_rx->bEndpointAddress;
pipe = usb_rcvintpipe(dev->udev, rx_addr);
@@ -435,8 +412,6 @@ static void vmk80xx_do_bulk_msg(struct vmk80xx_usb *dev)
unsigned int rx_pipe;
size_t size;
- dbgvm("vmk80xx: %s\n", __func__);
-
set_bit(TRANS_IN_BUSY, &dev->flags);
set_bit(TRANS_OUT_BUSY, &dev->flags);
@@ -464,8 +439,6 @@ static int vmk80xx_read_packet(struct vmk80xx_usb *dev)
struct urb *urb;
int retval;
- dbgvm("vmk80xx: %s\n", __func__);
-
if (!dev->intf)
return -ENODEV;
@@ -512,8 +485,6 @@ static int vmk80xx_write_packet(struct vmk80xx_usb *dev, int cmd)
struct urb *urb;
int retval;
- dbgvm("vmk80xx: %s\n", __func__);
-
if (!dev->intf)
return -ENODEV;
@@ -588,8 +559,6 @@ static int vmk80xx_ai_rinsn(struct comedi_device *cdev,
int reg[2];
int n;
- dbgvm("vmk80xx: %s\n", __func__);
-
n = rudimentary_check(dev, DIR_IN);
if (n)
return n;
@@ -641,8 +610,6 @@ static int vmk80xx_ao_winsn(struct comedi_device *cdev,
int reg;
int n;
- dbgvm("vmk80xx: %s\n", __func__);
-
n = rudimentary_check(dev, DIR_OUT);
if (n)
return n;
@@ -686,8 +653,6 @@ static int vmk80xx_ao_rinsn(struct comedi_device *cdev,
int reg;
int n;
- dbgvm("vmk80xx: %s\n", __func__);
-
n = rudimentary_check(dev, DIR_IN);
if (n)
return n;
@@ -720,8 +685,6 @@ static int vmk80xx_di_bits(struct comedi_device *cdev,
int reg;
int retval;
- dbgvm("vmk80xx: %s\n", __func__);
-
retval = rudimentary_check(dev, DIR_IN);
if (retval)
return retval;
@@ -766,8 +729,6 @@ static int vmk80xx_di_rinsn(struct comedi_device *cdev,
int inp;
int n;
- dbgvm("vmk80xx: %s\n", __func__);
-
n = rudimentary_check(dev, DIR_IN);
if (n)
return n;
@@ -813,8 +774,6 @@ static int vmk80xx_do_winsn(struct comedi_device *cdev,
int cmd;
int n;
- dbgvm("vmk80xx: %s\n", __func__);
-
n = rudimentary_check(dev, DIR_OUT);
if (n)
return n;
@@ -861,8 +820,6 @@ static int vmk80xx_do_rinsn(struct comedi_device *cdev,
int reg;
int n;
- dbgvm("vmk80xx: %s\n", __func__);
-
n = rudimentary_check(dev, DIR_IN);
if (n)
return n;
@@ -895,8 +852,6 @@ static int vmk80xx_do_bits(struct comedi_device *cdev,
int dir, reg, cmd;
int retval;
- dbgvm("vmk80xx: %s\n", __func__);
-
dir = 0;
if (data[0])
@@ -962,8 +917,6 @@ static int vmk80xx_cnt_rinsn(struct comedi_device *cdev,
int reg[2];
int n;
- dbgvm("vmk80xx: %s\n", __func__);
-
n = rudimentary_check(dev, DIR_IN);
if (n)
return n;
@@ -1012,18 +965,16 @@ static int vmk80xx_cnt_cinsn(struct comedi_device *cdev,
int reg;
int n;
- dbgvm("vmk80xx: %s\n", __func__);
-
n = rudimentary_check(dev, DIR_OUT);
if (n)
return n;
- down(&dev->limit_sem);
-
insn_cmd = data[0];
if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET)
return -EINVAL;
+ down(&dev->limit_sem);
+
chan = CR_CHAN(insn->chanspec);
if (dev->board.model == VMK8055_MODEL) {
@@ -1060,8 +1011,6 @@ static int vmk80xx_cnt_winsn(struct comedi_device *cdev,
int cmd;
int n;
- dbgvm("vmk80xx: %s\n", __func__);
-
n = rudimentary_check(dev, DIR_OUT);
if (n)
return n;
@@ -1106,8 +1055,6 @@ static int vmk80xx_pwm_rinsn(struct comedi_device *cdev,
int reg[2];
int n;
- dbgvm("vmk80xx: %s\n", __func__);
-
n = rudimentary_check(dev, DIR_IN);
if (n)
return n;
@@ -1141,8 +1088,6 @@ static int vmk80xx_pwm_winsn(struct comedi_device *cdev,
int cmd;
int n;
- dbgvm("vmk80xx: %s\n", __func__);
-
n = rudimentary_check(dev, DIR_OUT);
if (n)
return n;
@@ -1191,8 +1136,6 @@ static int vmk80xx_attach(struct comedi_device *cdev,
struct comedi_subdevice *s;
int minor;
- dbgvm("vmk80xx: %s\n", __func__);
-
mutex_lock(&glb_mutex);
for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
@@ -1307,34 +1250,16 @@ static int vmk80xx_attach(struct comedi_device *cdev,
return 0;
}
-static int vmk80xx_detach(struct comedi_device *cdev)
+static void vmk80xx_detach(struct comedi_device *dev)
{
- struct vmk80xx_usb *dev;
- int minor;
-
- dbgvm("vmk80xx: %s\n", __func__);
-
- if (!cdev)
- return -EFAULT;
-
- dev = cdev->private;
- if (!dev)
- return -EFAULT;
+ struct vmk80xx_usb *usb = dev->private;
- down(&dev->limit_sem);
-
- cdev->private = NULL;
- dev->attached = 0;
-
- minor = cdev->minor;
-
- printk(KERN_INFO
- "comedi%d: vmk80xx: board #%d [%s] detached from comedi\n",
- minor, dev->count, dev->board.name);
-
- up(&dev->limit_sem);
-
- return 0;
+ if (usb) {
+ down(&usb->limit_sem);
+ dev->private = NULL;
+ usb->attached = 0;
+ up(&usb->limit_sem);
+ }
}
static int vmk80xx_probe(struct usb_interface *intf,
@@ -1346,8 +1271,6 @@ static int vmk80xx_probe(struct usb_interface *intf,
struct usb_endpoint_descriptor *ep_desc;
size_t size;
- dbgvm("vmk80xx: %s\n", __func__);
-
mutex_lock(&glb_mutex);
for (i = 0; i < VMK80XX_MAX_BOARDS; i++)
@@ -1482,7 +1405,7 @@ static int vmk80xx_probe(struct usb_interface *intf,
mutex_unlock(&glb_mutex);
- comedi_usb_auto_config(dev->udev, BOARDNAME);
+ comedi_usb_auto_config(intf, &driver_vmk80xx);
return 0;
error:
@@ -1495,12 +1418,10 @@ static void vmk80xx_disconnect(struct usb_interface *intf)
{
struct vmk80xx_usb *dev = usb_get_intfdata(intf);
- dbgvm("vmk80xx: %s\n", __func__);
-
if (!dev)
return;
- comedi_usb_auto_unconfig(dev->udev);
+ comedi_usb_auto_unconfig(intf);
mutex_lock(&glb_mutex);
down(&dev->limit_sem);
diff --git a/drivers/staging/comedi/internal.h b/drivers/staging/comedi/internal.h
index 434ce3433368..7ed20a04eef5 100644
--- a/drivers/staging/comedi/internal.h
+++ b/drivers/staging/comedi/internal.h
@@ -1,5 +1,5 @@
/*
- * various internal comedi functions
+ * various internal comedi stuff
*/
int do_rangeinfo_ioctl(struct comedi_device *dev,
struct comedi_rangeinfo __user *arg);
@@ -7,6 +7,10 @@ int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data);
int comedi_alloc_board_minor(struct device *hardware_device);
void comedi_free_board_minor(unsigned minor);
+int comedi_find_board_minor(struct device *hardware_device);
void comedi_reset_async_buf(struct comedi_async *async);
int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s,
unsigned long new_size);
+
+extern unsigned int comedi_default_buf_size_kb;
+extern unsigned int comedi_default_buf_maxsize_kb;
diff --git a/drivers/staging/et131x/et131x.c b/drivers/staging/et131x/et131x.c
index 886f5650444e..5b11c5e3622e 100644
--- a/drivers/staging/et131x/et131x.c
+++ b/drivers/staging/et131x/et131x.c
@@ -1710,7 +1710,8 @@ static int et131x_mdio_read(struct mii_bus *bus, int phy_addr, int reg)
return value;
}
-static int et131x_mdio_write(struct mii_bus *bus, int phy_addr, int reg, u16 value)
+static int et131x_mdio_write(struct mii_bus *bus, int phy_addr,
+ int reg, u16 value)
{
struct net_device *netdev = bus->priv;
struct et131x_adapter *adapter = netdev_priv(netdev);
@@ -4013,7 +4014,7 @@ static int et131x_pci_init(struct et131x_adapter *adapter,
dev_err(&pdev->dev, "Missing PCIe capabilities\n");
goto err_out;
}
-
+
/* Let's set up the PORT LOGIC Register. First we need to know what
* the max_payload_size is
*/
@@ -4060,7 +4061,7 @@ static int et131x_pci_init(struct et131x_adapter *adapter,
goto err_out;
}
- ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | ( 0x04 << 12);
+ ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | (0x04 << 12);
if (pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl)) {
dev_err(&pdev->dev,
@@ -4824,7 +4825,8 @@ static int et131x_open(struct net_device *netdev)
adapter->error_timer.data = (unsigned long)adapter;
add_timer(&adapter->error_timer);
- result = request_irq(irq, et131x_isr, IRQF_SHARED, netdev->name, netdev);
+ result = request_irq(irq, et131x_isr,
+ IRQF_SHARED, netdev->name, netdev);
if (result) {
dev_err(&pdev->dev, "could not register IRQ %d\n", irq);
return result;
diff --git a/drivers/staging/frontier/alphatrack.c b/drivers/staging/frontier/alphatrack.c
index 3bf0f40e97fd..acbb2cc510f9 100644
--- a/drivers/staging/frontier/alphatrack.c
+++ b/drivers/staging/frontier/alphatrack.c
@@ -333,8 +333,8 @@ static int usb_alphatrack_open(struct inode *inode, struct file *file)
interface = usb_find_interface(&usb_alphatrack_driver, subminor);
if (!interface) {
- err("%s - error, can't find device for minor %d\n",
- __func__, subminor);
+ printk(KERN_ERR "%s - error, can't find device for minor %d\n",
+ __func__, subminor);
retval = -ENODEV;
goto unlock_disconnect_exit;
}
@@ -494,7 +494,8 @@ static ssize_t usb_alphatrack_read(struct file *file, char __user *buffer,
/* verify that the device wasn't unplugged */
if (dev->intf == NULL) {
retval = -ENODEV;
- err("No device or device unplugged %d\n", retval);
+ printk(KERN_ERR "%s: No device or device unplugged %d\n",
+ __func__, retval);
goto unlock_exit;
}
@@ -564,7 +565,8 @@ static ssize_t usb_alphatrack_write(struct file *file,
/* verify that the device wasn't unplugged */
if (dev->intf == NULL) {
retval = -ENODEV;
- err("No device or device unplugged %d\n", retval);
+ printk(KERN_ERR "%s: No device or device unplugged %d\n",
+ __func__, retval);
goto unlock_exit;
}
@@ -599,7 +601,7 @@ static ssize_t usb_alphatrack_write(struct file *file,
}
if (dev->interrupt_out_endpoint == NULL) {
- err("Endpoint should not be be null!\n");
+ dev_err(&dev->intf->dev, "Endpoint should not be be null!\n");
goto unlock_exit;
}
@@ -619,7 +621,8 @@ static ssize_t usb_alphatrack_write(struct file *file,
retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL);
if (retval) {
dev->interrupt_out_busy = 0;
- err("Couldn't submit interrupt_out_urb %d\n", retval);
+ dev_err(&dev->intf->dev,
+ "Couldn't submit interrupt_out_urb %d\n", retval);
atomic_dec(&dev->writes_pending);
goto unlock_exit;
}
diff --git a/drivers/staging/frontier/tranzport.c b/drivers/staging/frontier/tranzport.c
index 29e99bbcae48..376706f1c712 100644
--- a/drivers/staging/frontier/tranzport.c
+++ b/drivers/staging/frontier/tranzport.c
@@ -353,7 +353,7 @@ static int usb_tranzport_open(struct inode *inode, struct file *file)
interface = usb_find_interface(&usb_tranzport_driver, subminor);
if (!interface) {
- err("%s - error, can't find device for minor %d\n",
+ printk(KERN_ERR "%s - error, can't find device for minor %d\n",
__func__, subminor);
retval = -ENODEV;
goto unlock_disconnect_exit;
@@ -517,9 +517,11 @@ static ssize_t usb_tranzport_read(struct file *file, char __user *buffer,
goto exit;
}
- /* verify that the device wasn't unplugged */ if (dev->intf == NULL) {
+ /* verify that the device wasn't unplugged */
+ if (dev->intf == NULL) {
retval = -ENODEV;
- err("No device or device unplugged %d\n", retval);
+ printk(KERN_ERR "%s: No device or device unplugged %d\n",
+ __func__, retval);
goto unlock_exit;
}
@@ -691,7 +693,8 @@ static ssize_t usb_tranzport_write(struct file *file,
/* verify that the device wasn't unplugged */
if (dev->intf == NULL) {
retval = -ENODEV;
- err("No device or device unplugged %d\n", retval);
+ printk(KERN_ERR "%s: No device or device unplugged %d\n",
+ __func__, retval);
goto unlock_exit;
}
@@ -726,7 +729,7 @@ static ssize_t usb_tranzport_write(struct file *file,
}
if (dev->interrupt_out_endpoint == NULL) {
- err("Endpoint should not be be null!\n");
+ dev_err(&dev->intf->dev, "Endpoint should not be be null!\n");
goto unlock_exit;
}
@@ -746,7 +749,8 @@ static ssize_t usb_tranzport_write(struct file *file,
retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL);
if (retval) {
dev->interrupt_out_busy = 0;
- err("Couldn't submit interrupt_out_urb %d\n", retval);
+ dev_err(&dev->intf->dev,
+ "Couldn't submit interrupt_out_urb %d\n", retval);
goto unlock_exit;
}
retval = bytes_to_write;
diff --git a/drivers/staging/gdm72xx/Kconfig b/drivers/staging/gdm72xx/Kconfig
new file mode 100644
index 000000000000..3c18efe31365
--- /dev/null
+++ b/drivers/staging/gdm72xx/Kconfig
@@ -0,0 +1,46 @@
+#
+# GCT GDM72xx WiMAX driver configuration
+#
+
+menuconfig WIMAX_GDM72XX
+ tristate "GCT GDM72xx WiMAX support"
+ depends on NET
+ help
+ Support for the GCT GDM72xx WiMAX chip
+
+if WIMAX_GDM72XX
+
+config WIMAX_GDM72XX_QOS
+ bool "Enable QoS support"
+ default n
+
+config WIMAX_GDM72XX_K_MODE
+ bool "Enable K mode"
+ default n
+
+config WIMAX_GDM72XX_WIMAX2
+ bool "Enable WIMAX2 support"
+ default n
+
+choice
+ prompt "Select interface"
+
+config WIMAX_GDM72XX_USB
+ bool "USB interface"
+ depends on USB
+
+config WIMAX_GDM72XX_SDIO
+ bool "SDIO interface"
+ depends on MMC
+
+endchoice
+
+if WIMAX_GDM72XX_USB
+
+config WIMAX_GDM72XX_USB_PM
+ bool "Enable power managerment support"
+ depends on USB_SUSPEND
+
+endif # WIMAX_GDM72XX_USB
+
+endif # WIMAX_GDM72XX
diff --git a/drivers/staging/gdm72xx/Makefile b/drivers/staging/gdm72xx/Makefile
new file mode 100644
index 000000000000..35da7b90b19b
--- /dev/null
+++ b/drivers/staging/gdm72xx/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_WIMAX_GDM72XX) := gdmwm.o
+
+gdmwm-y += gdm_wimax.o netlink_k.o
+gdmwm-$(CONFIG_WIMAX_GDM72XX_QOS) += gdm_qos.o
+gdmwm-$(CONFIG_WIMAX_GDM72XX_SDIO) += gdm_sdio.o sdio_boot.o
+gdmwm-$(CONFIG_WIMAX_GDM72XX_USB) += gdm_usb.o usb_boot.o
diff --git a/drivers/staging/gdm72xx/TODO b/drivers/staging/gdm72xx/TODO
new file mode 100644
index 000000000000..30ac01ab972f
--- /dev/null
+++ b/drivers/staging/gdm72xx/TODO
@@ -0,0 +1,5 @@
+TODO:
+- Replace kernel_thread with kthread in gdm_usb.c
+- Replace hard-coded firmware paths with request_firmware in
+ sdio_boot.c and usb_boot.c
+- Clean up coding style to meet kernel standard.
diff --git a/drivers/staging/gdm72xx/gdm_qos.c b/drivers/staging/gdm72xx/gdm_qos.c
new file mode 100644
index 000000000000..0217680ec545
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_qos.c
@@ -0,0 +1,460 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/version.h>
+#include <linux/etherdevice.h>
+#include <asm/byteorder.h>
+
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/if_ether.h>
+
+#include "gdm_wimax.h"
+#include "hci.h"
+#include "gdm_qos.h"
+
+#define B2H(x) __be16_to_cpu(x)
+
+#undef dprintk
+#define dprintk(fmt, args ...) printk(KERN_DEBUG "[QoS] " fmt, ## args)
+#undef wprintk
+#define wprintk(fmt, args ...) \
+ printk(KERN_WARNING "[QoS WARNING] " fmt, ## args)
+#undef eprintk
+#define eprintk(fmt, args ...) printk(KERN_ERR "[QoS ERROR] " fmt, ## args)
+
+
+#define MAX_FREE_LIST_CNT 32
+static struct {
+ struct list_head head;
+ int cnt;
+ spinlock_t lock;
+} qos_free_list;
+
+static void init_qos_entry_list(void)
+{
+ qos_free_list.cnt = 0;
+ INIT_LIST_HEAD(&qos_free_list.head);
+ spin_lock_init(&qos_free_list.lock);
+}
+
+static void *alloc_qos_entry(void)
+{
+ struct qos_entry_s *entry;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qos_free_list.lock, flags);
+ if (qos_free_list.cnt) {
+ entry = list_entry(qos_free_list.head.prev, struct qos_entry_s,
+ list);
+ list_del(&entry->list);
+ qos_free_list.cnt--;
+ spin_unlock_irqrestore(&qos_free_list.lock, flags);
+ return entry;
+ }
+ spin_unlock_irqrestore(&qos_free_list.lock, flags);
+
+ entry = kmalloc(sizeof(struct qos_entry_s), GFP_ATOMIC);
+ return entry;
+}
+
+static void free_qos_entry(void *entry)
+{
+ struct qos_entry_s *qentry = (struct qos_entry_s *) entry;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qos_free_list.lock, flags);
+ if (qos_free_list.cnt < MAX_FREE_LIST_CNT) {
+ list_add(&qentry->list, &qos_free_list.head);
+ qos_free_list.cnt++;
+ spin_unlock_irqrestore(&qos_free_list.lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&qos_free_list.lock, flags);
+
+ kfree(entry);
+}
+
+static void free_qos_entry_list(struct list_head *free_list)
+{
+ struct qos_entry_s *entry, *n;
+ int total_free = 0;
+
+ list_for_each_entry_safe(entry, n, free_list, list) {
+ list_del(&entry->list);
+ kfree(entry);
+ total_free++;
+ }
+
+ dprintk("%s: total_free_cnt=%d\n", __func__, total_free);
+}
+
+void gdm_qos_init(void *nic_ptr)
+{
+ struct nic *nic = nic_ptr;
+ struct qos_cb_s *qcb = &nic->qos;
+ int i;
+
+ for (i = 0 ; i < QOS_MAX; i++) {
+ INIT_LIST_HEAD(&qcb->qos_list[i]);
+ qcb->csr[i].QoSBufCount = 0;
+ qcb->csr[i].Enabled = 0;
+ }
+
+ qcb->qos_list_cnt = 0;
+ qcb->qos_null_idx = QOS_MAX-1;
+ qcb->qos_limit_size = 255;
+
+ spin_lock_init(&qcb->qos_lock);
+
+ init_qos_entry_list();
+}
+
+void gdm_qos_release_list(void *nic_ptr)
+{
+ struct nic *nic = nic_ptr;
+ struct qos_cb_s *qcb = &nic->qos;
+ unsigned long flags;
+ struct qos_entry_s *entry, *n;
+ struct list_head free_list;
+ int i;
+
+ INIT_LIST_HEAD(&free_list);
+
+ spin_lock_irqsave(&qcb->qos_lock, flags);
+
+ for (i = 0; i < QOS_MAX; i++) {
+ qcb->csr[i].QoSBufCount = 0;
+ qcb->csr[i].Enabled = 0;
+ }
+
+ qcb->qos_list_cnt = 0;
+ qcb->qos_null_idx = QOS_MAX-1;
+
+ for (i = 0; i < QOS_MAX; i++) {
+ list_for_each_entry_safe(entry, n, &qcb->qos_list[i], list) {
+ list_move_tail(&entry->list, &free_list);
+ }
+ }
+ spin_unlock_irqrestore(&qcb->qos_lock, flags);
+ free_qos_entry_list(&free_list);
+}
+
+static u32 chk_ipv4_rule(struct gdm_wimax_csr_s *csr, u8 *Stream, u8 *port)
+{
+ int i;
+
+ if (csr->ClassifierRuleEnable&IPTYPEOFSERVICE) {
+ if (((Stream[1] & csr->IPToSMask) < csr->IPToSLow) ||
+ ((Stream[1] & csr->IPToSMask) > csr->IPToSHigh))
+ return 1;
+ }
+
+ if (csr->ClassifierRuleEnable&PROTOCOL) {
+ if (Stream[9] != csr->Protocol)
+ return 1;
+ }
+
+ if (csr->ClassifierRuleEnable&IPMASKEDSRCADDRESS) {
+ for (i = 0; i < 4; i++) {
+ if ((Stream[12 + i] & csr->IPSrcAddrMask[i]) !=
+ (csr->IPSrcAddr[i] & csr->IPSrcAddrMask[i]))
+ return 1;
+ }
+ }
+
+ if (csr->ClassifierRuleEnable&IPMASKEDDSTADDRESS) {
+ for (i = 0; i < 4; i++) {
+ if ((Stream[16 + i] & csr->IPDstAddrMask[i]) !=
+ (csr->IPDstAddr[i] & csr->IPDstAddrMask[i]))
+ return 1;
+ }
+ }
+
+ if (csr->ClassifierRuleEnable&PROTOCOLSRCPORTRANGE) {
+ i = ((port[0]<<8)&0xff00)+port[1];
+ if ((i < csr->SrcPortLow) || (i > csr->SrcPortHigh))
+ return 1;
+ }
+
+ if (csr->ClassifierRuleEnable&PROTOCOLDSTPORTRANGE) {
+ i = ((port[2]<<8)&0xff00)+port[3];
+ if ((i < csr->DstPortLow) || (i > csr->DstPortHigh))
+ return 1;
+ }
+
+ return 0;
+}
+
+static u32 get_qos_index(struct nic *nic, u8* iph, u8* tcpudph)
+{
+ u32 IP_Ver, Header_Len, i;
+ struct qos_cb_s *qcb = &nic->qos;
+
+ if (iph == NULL || tcpudph == NULL)
+ return -1;
+
+ IP_Ver = (iph[0]>>4)&0xf;
+ Header_Len = iph[0]&0xf;
+
+ if (IP_Ver == 4) {
+ for (i = 0; i < QOS_MAX; i++) {
+ if (qcb->csr[i].Enabled) {
+ if (qcb->csr[i].ClassifierRuleEnable) {
+ if (chk_ipv4_rule(&qcb->csr[i], iph,
+ tcpudph) == 0)
+ return i;
+ }
+ }
+ }
+ }
+
+ return -1;
+}
+
+static u32 extract_qos_list(struct nic *nic, struct list_head *head)
+{
+ struct qos_cb_s *qcb = &nic->qos;
+ struct qos_entry_s *entry;
+ int i;
+
+ INIT_LIST_HEAD(head);
+
+ for (i = 0; i < QOS_MAX; i++) {
+ if (qcb->csr[i].Enabled) {
+ if (qcb->csr[i].QoSBufCount < qcb->qos_limit_size) {
+ if (!list_empty(&qcb->qos_list[i])) {
+ entry = list_entry(
+ qcb->qos_list[i].prev,
+ struct qos_entry_s, list);
+ list_move_tail(&entry->list, head);
+ qcb->csr[i].QoSBufCount++;
+
+ if (!list_empty(&qcb->qos_list[i]))
+ wprintk("QoS Index(%d) "
+ "is piled!!\n", i);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void send_qos_list(struct nic *nic, struct list_head *head)
+{
+ struct qos_entry_s *entry, *n;
+
+ list_for_each_entry_safe(entry, n, head, list) {
+ list_del(&entry->list);
+ free_qos_entry(entry);
+ gdm_wimax_send_tx(entry->skb, entry->dev);
+ }
+}
+
+int gdm_qos_send_hci_pkt(struct sk_buff *skb, struct net_device *dev)
+{
+ struct nic *nic = netdev_priv(dev);
+ int index;
+ struct qos_cb_s *qcb = &nic->qos;
+ unsigned long flags;
+ struct ethhdr *ethh = (struct ethhdr *) (skb->data + HCI_HEADER_SIZE);
+ struct iphdr *iph = (struct iphdr *) ((char *) ethh + ETH_HLEN);
+ struct tcphdr *tcph;
+ struct qos_entry_s *entry = NULL;
+ struct list_head send_list;
+ int ret = 0;
+
+ tcph = (struct tcphdr *) iph + iph->ihl*4;
+
+ if (B2H(ethh->h_proto) == ETH_P_IP) {
+ if (qcb->qos_list_cnt && !qos_free_list.cnt) {
+ entry = alloc_qos_entry();
+ entry->skb = skb;
+ entry->dev = dev;
+ dprintk("qcb->qos_list_cnt=%d\n", qcb->qos_list_cnt);
+ }
+
+ spin_lock_irqsave(&qcb->qos_lock, flags);
+ if (qcb->qos_list_cnt) {
+ index = get_qos_index(nic, (u8 *)iph, (u8 *) tcph);
+ if (index == -1)
+ index = qcb->qos_null_idx;
+
+ if (!entry) {
+ entry = alloc_qos_entry();
+ entry->skb = skb;
+ entry->dev = dev;
+ }
+
+ list_add_tail(&entry->list, &qcb->qos_list[index]);
+ extract_qos_list(nic, &send_list);
+ spin_unlock_irqrestore(&qcb->qos_lock, flags);
+ send_qos_list(nic, &send_list);
+ goto out;
+ }
+ spin_unlock_irqrestore(&qcb->qos_lock, flags);
+ if (entry)
+ free_qos_entry(entry);
+ }
+
+ ret = gdm_wimax_send_tx(skb, dev);
+out:
+ return ret;
+}
+
+static u32 get_csr(struct qos_cb_s *qcb, u32 SFID, int mode)
+{
+ int i;
+
+ for (i = 0; i < qcb->qos_list_cnt; i++) {
+ if (qcb->csr[i].SFID == SFID)
+ return i;
+ }
+
+ if (mode) {
+ for (i = 0; i < QOS_MAX; i++) {
+ if (qcb->csr[i].Enabled == 0) {
+ qcb->csr[i].Enabled = 1;
+ qcb->qos_list_cnt++;
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+#define QOS_CHANGE_DEL 0xFC
+#define QOS_ADD 0xFD
+#define QOS_REPORT 0xFE
+
+void gdm_recv_qos_hci_packet(void *nic_ptr, u8 *buf, int size)
+{
+ struct nic *nic = nic_ptr;
+ u32 i, SFID, index, pos;
+ u8 subCmdEvt;
+ u8 len;
+ struct qos_cb_s *qcb = &nic->qos;
+ struct qos_entry_s *entry, *n;
+ struct list_head send_list;
+ struct list_head free_list;
+ unsigned long flags;
+
+ subCmdEvt = (u8)buf[4];
+
+ if (subCmdEvt == QOS_REPORT) {
+ len = (u8)buf[5];
+
+ spin_lock_irqsave(&qcb->qos_lock, flags);
+ for (i = 0; i < qcb->qos_list_cnt; i++) {
+ SFID = ((buf[(i*5)+6]<<24)&0xff000000);
+ SFID += ((buf[(i*5)+7]<<16)&0xff0000);
+ SFID += ((buf[(i*5)+8]<<8)&0xff00);
+ SFID += (buf[(i*5)+9]);
+ index = get_csr(qcb, SFID, 0);
+ if (index == -1) {
+ spin_unlock_irqrestore(&qcb->qos_lock, flags);
+ eprintk("QoS ERROR: No SF\n");
+ return;
+ }
+ qcb->csr[index].QoSBufCount = buf[(i*5)+10];
+ }
+
+ extract_qos_list(nic, &send_list);
+ spin_unlock_irqrestore(&qcb->qos_lock, flags);
+ send_qos_list(nic, &send_list);
+ return;
+ } else if (subCmdEvt == QOS_ADD) {
+ pos = 5;
+ len = (u8)buf[pos++];
+
+ SFID = ((buf[pos++]<<24)&0xff000000);
+ SFID += ((buf[pos++]<<16)&0xff0000);
+ SFID += ((buf[pos++]<<8)&0xff00);
+ SFID += (buf[pos++]);
+
+ index = get_csr(qcb, SFID, 1);
+ if (index == -1) {
+ eprintk("QoS ERROR: csr Update Error\n");
+ return;
+ }
+
+ dprintk("QOS_ADD SFID = 0x%x, index=%d\n", SFID, index);
+
+ spin_lock_irqsave(&qcb->qos_lock, flags);
+ qcb->csr[index].SFID = SFID;
+ qcb->csr[index].ClassifierRuleEnable = ((buf[pos++]<<8)&0xff00);
+ qcb->csr[index].ClassifierRuleEnable += buf[pos++];
+ if (qcb->csr[index].ClassifierRuleEnable == 0)
+ qcb->qos_null_idx = index;
+ qcb->csr[index].IPToSMask = buf[pos++];
+ qcb->csr[index].IPToSLow = buf[pos++];
+ qcb->csr[index].IPToSHigh = buf[pos++];
+ qcb->csr[index].Protocol = buf[pos++];
+ qcb->csr[index].IPSrcAddrMask[0] = buf[pos++];
+ qcb->csr[index].IPSrcAddrMask[1] = buf[pos++];
+ qcb->csr[index].IPSrcAddrMask[2] = buf[pos++];
+ qcb->csr[index].IPSrcAddrMask[3] = buf[pos++];
+ qcb->csr[index].IPSrcAddr[0] = buf[pos++];
+ qcb->csr[index].IPSrcAddr[1] = buf[pos++];
+ qcb->csr[index].IPSrcAddr[2] = buf[pos++];
+ qcb->csr[index].IPSrcAddr[3] = buf[pos++];
+ qcb->csr[index].IPDstAddrMask[0] = buf[pos++];
+ qcb->csr[index].IPDstAddrMask[1] = buf[pos++];
+ qcb->csr[index].IPDstAddrMask[2] = buf[pos++];
+ qcb->csr[index].IPDstAddrMask[3] = buf[pos++];
+ qcb->csr[index].IPDstAddr[0] = buf[pos++];
+ qcb->csr[index].IPDstAddr[1] = buf[pos++];
+ qcb->csr[index].IPDstAddr[2] = buf[pos++];
+ qcb->csr[index].IPDstAddr[3] = buf[pos++];
+ qcb->csr[index].SrcPortLow = ((buf[pos++]<<8)&0xff00);
+ qcb->csr[index].SrcPortLow += buf[pos++];
+ qcb->csr[index].SrcPortHigh = ((buf[pos++]<<8)&0xff00);
+ qcb->csr[index].SrcPortHigh += buf[pos++];
+ qcb->csr[index].DstPortLow = ((buf[pos++]<<8)&0xff00);
+ qcb->csr[index].DstPortLow += buf[pos++];
+ qcb->csr[index].DstPortHigh = ((buf[pos++]<<8)&0xff00);
+ qcb->csr[index].DstPortHigh += buf[pos++];
+
+ qcb->qos_limit_size = 254/qcb->qos_list_cnt;
+ spin_unlock_irqrestore(&qcb->qos_lock, flags);
+ } else if (subCmdEvt == QOS_CHANGE_DEL) {
+ pos = 5;
+ len = (u8)buf[pos++];
+ SFID = ((buf[pos++]<<24)&0xff000000);
+ SFID += ((buf[pos++]<<16)&0xff0000);
+ SFID += ((buf[pos++]<<8)&0xff00);
+ SFID += (buf[pos++]);
+ index = get_csr(qcb, SFID, 1);
+ if (index == -1) {
+ eprintk("QoS ERROR: Wrong index(%d)\n", index);
+ return;
+ }
+
+ dprintk("QOS_CHANGE_DEL SFID = 0x%x, index=%d\n", SFID, index);
+
+ INIT_LIST_HEAD(&free_list);
+
+ spin_lock_irqsave(&qcb->qos_lock, flags);
+ qcb->csr[index].Enabled = 0;
+ qcb->qos_list_cnt--;
+ qcb->qos_limit_size = 254/qcb->qos_list_cnt;
+
+ list_for_each_entry_safe(entry, n, &qcb->qos_list[index],
+ list) {
+ list_move_tail(&entry->list, &free_list);
+ }
+ spin_unlock_irqrestore(&qcb->qos_lock, flags);
+ free_qos_entry_list(&free_list);
+ }
+}
diff --git a/drivers/staging/gdm72xx/gdm_qos.h b/drivers/staging/gdm72xx/gdm_qos.h
new file mode 100644
index 000000000000..33f2bd4cee32
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_qos.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#if !defined(GDM_QOS_H_20090403)
+#define GDM_QOS_H_20090403
+
+#include <linux/types.h>
+#include <linux/usb.h>
+#include <linux/list.h>
+
+#define BOOLEAN u8
+
+#define QOS_MAX 16
+#define IPTYPEOFSERVICE 0x8000
+#define PROTOCOL 0x4000
+#define IPMASKEDSRCADDRESS 0x2000
+#define IPMASKEDDSTADDRESS 0x1000
+#define PROTOCOLSRCPORTRANGE 0x800
+#define PROTOCOLDSTPORTRANGE 0x400
+#define DSTMACADDR 0x200
+#define SRCMACADDR 0x100
+#define ETHERTYPE 0x80
+#define IEEE802_1DUSERPRIORITY 0x40
+#define IEEE802_1QVLANID 0x10
+
+struct gdm_wimax_csr_s {
+ /* union{
+ U16 all;
+ struct _CS_CLASSIFIER_RULE_ENABLE{
+ IPTypeOfService:1,
+ Protocol:1,
+ IPMaskedSrcAddress:1,
+ IPMaskedDstAddress:1,
+ ProtocolSrcPortRange:1,
+ ProtocolDstPortRange:1,
+ DstMacAddr:1,
+ SrcMacAddr:1,
+ Ethertype:1,
+ IEEE802_1DUserPriority:1,
+ IEEE802_1QVLANID:1,
+ Reserved:5;
+ } fields;
+ } */
+ BOOLEAN Enabled;
+ u32 SFID;
+ u8 QoSBufCount;
+ u16 ClassifierRuleEnable;
+ u8 IPToSLow;
+ u8 IPToSHigh;
+ u8 IPToSMask;
+ u8 Protocol;
+ u8 IPSrcAddr[16];
+ u8 IPSrcAddrMask[16];
+ u8 IPDstAddr[16];
+ u8 IPDstAddrMask[16];
+ u16 SrcPortLow;
+ u16 SrcPortHigh;
+ u16 DstPortLow;
+ u16 DstPortHigh;
+};
+
+struct qos_entry_s {
+ struct list_head list;
+ struct sk_buff *skb;
+ struct net_device *dev;
+
+};
+
+struct qos_cb_s {
+ struct list_head qos_list[QOS_MAX];
+ u32 qos_list_cnt;
+ u32 qos_null_idx;
+ struct gdm_wimax_csr_s csr[QOS_MAX];
+ spinlock_t qos_lock;
+ u32 qos_limit_size;
+};
+
+void gdm_qos_init(void *nic_ptr);
+void gdm_qos_release_list(void *nic_ptr);
+int gdm_qos_send_hci_pkt(struct sk_buff *skb, struct net_device *dev);
+void gdm_recv_qos_hci_packet(void *nic_ptr, u8 *buf, int size);
+
+#endif
diff --git a/drivers/staging/gdm72xx/gdm_sdio.c b/drivers/staging/gdm72xx/gdm_sdio.c
new file mode 100644
index 000000000000..e1a3dd2fc4af
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_sdio.c
@@ -0,0 +1,754 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+
+#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+
+#include "gdm_sdio.h"
+#include "gdm_wimax.h"
+#include "sdio_boot.h"
+#include "hci.h"
+
+#define TYPE_A_HEADER_SIZE 4
+#define TYPE_A_LOOKAHEAD_SIZE 16
+
+#define MAX_NR_RX_BUF 4
+
+#define SDU_TX_BUF_SIZE 2048
+#define TX_BUF_SIZE 2048
+#define TX_CHUNK_SIZE (2048 - TYPE_A_HEADER_SIZE)
+#define RX_BUF_SIZE (25*1024)
+
+#define TX_HZ 2000
+#define TX_INTERVAL (1000000/TX_HZ)
+
+/*#define DEBUG*/
+
+static int init_sdio(struct sdiowm_dev *sdev);
+static void release_sdio(struct sdiowm_dev *sdev);
+
+#ifdef DEBUG
+static void hexdump(char *title, u8 *data, int len)
+{
+ int i;
+
+ printk(KERN_DEBUG "%s: length = %d\n", title, len);
+ for (i = 0; i < len; i++) {
+ printk(KERN_DEBUG "%02x ", data[i]);
+ if ((i & 0xf) == 0xf)
+ printk(KERN_DEBUG "\n");
+ }
+ printk(KERN_DEBUG "\n");
+}
+#endif
+
+static struct sdio_tx *alloc_tx_struct(struct tx_cxt *tx)
+{
+ struct sdio_tx *t = NULL;
+
+ t = kmalloc(sizeof(*t), GFP_ATOMIC);
+ if (t == NULL)
+ goto out;
+
+ memset(t, 0, sizeof(*t));
+
+ t->buf = kmalloc(TX_BUF_SIZE, GFP_ATOMIC);
+ if (t->buf == NULL)
+ goto out;
+
+ t->tx_cxt = tx;
+
+ return t;
+out:
+ if (t) {
+ kfree(t->buf);
+ kfree(t);
+ }
+ return NULL;
+}
+
+static void free_tx_struct(struct sdio_tx *t)
+{
+ if (t) {
+ kfree(t->buf);
+ kfree(t);
+ }
+}
+
+static struct sdio_rx *alloc_rx_struct(struct rx_cxt *rx)
+{
+ struct sdio_rx *r = NULL;
+
+ r = kmalloc(sizeof(*r), GFP_ATOMIC);
+ if (r == NULL)
+ goto out;
+
+ memset(r, 0, sizeof(*r));
+
+ r->rx_cxt = rx;
+
+ return r;
+out:
+ kfree(r);
+ return NULL;
+}
+
+static void free_rx_struct(struct sdio_rx *r)
+{
+ kfree(r);
+}
+
+/* Before this function is called, spin lock should be locked. */
+static struct sdio_tx *get_tx_struct(struct tx_cxt *tx, int *no_spc)
+{
+ struct sdio_tx *t;
+
+ if (list_empty(&tx->free_list))
+ return NULL;
+
+ t = list_entry(tx->free_list.prev, struct sdio_tx, list);
+ list_del(&t->list);
+
+ *no_spc = list_empty(&tx->free_list) ? 1 : 0;
+
+ return t;
+}
+
+/* Before this function is called, spin lock should be locked. */
+static void put_tx_struct(struct tx_cxt *tx, struct sdio_tx *t)
+{
+ list_add_tail(&t->list, &tx->free_list);
+}
+
+/* Before this function is called, spin lock should be locked. */
+static struct sdio_rx *get_rx_struct(struct rx_cxt *rx)
+{
+ struct sdio_rx *r;
+
+ if (list_empty(&rx->free_list))
+ return NULL;
+
+ r = list_entry(rx->free_list.prev, struct sdio_rx, list);
+ list_del(&r->list);
+
+ return r;
+}
+
+/* Before this function is called, spin lock should be locked. */
+static void put_rx_struct(struct rx_cxt *rx, struct sdio_rx *r)
+{
+ list_add_tail(&r->list, &rx->free_list);
+}
+
+static int init_sdio(struct sdiowm_dev *sdev)
+{
+ int ret = 0, i;
+ struct tx_cxt *tx = &sdev->tx;
+ struct rx_cxt *rx = &sdev->rx;
+ struct sdio_tx *t;
+ struct sdio_rx *r;
+
+ INIT_LIST_HEAD(&tx->free_list);
+ INIT_LIST_HEAD(&tx->sdu_list);
+ INIT_LIST_HEAD(&tx->hci_list);
+
+ spin_lock_init(&tx->lock);
+
+ tx->sdu_buf = kmalloc(SDU_TX_BUF_SIZE, GFP_KERNEL);
+ if (tx->sdu_buf == NULL) {
+ printk(KERN_ERR "Failed to allocate SDU tx buffer.\n");
+ goto fail;
+ }
+
+ for (i = 0; i < MAX_NR_SDU_BUF; i++) {
+ t = alloc_tx_struct(tx);
+ if (t == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+ list_add(&t->list, &tx->free_list);
+ }
+
+ INIT_LIST_HEAD(&rx->free_list);
+ INIT_LIST_HEAD(&rx->req_list);
+
+ spin_lock_init(&rx->lock);
+
+ for (i = 0; i < MAX_NR_RX_BUF; i++) {
+ r = alloc_rx_struct(rx);
+ if (r == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+ list_add(&r->list, &rx->free_list);
+ }
+
+ rx->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL);
+ if (rx->rx_buf == NULL) {
+ printk(KERN_ERR "Failed to allocate rx buffer.\n");
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ release_sdio(sdev);
+ return ret;
+}
+
+static void release_sdio(struct sdiowm_dev *sdev)
+{
+ struct tx_cxt *tx = &sdev->tx;
+ struct rx_cxt *rx = &sdev->rx;
+ struct sdio_tx *t, *t_next;
+ struct sdio_rx *r, *r_next;
+
+ kfree(tx->sdu_buf);
+
+ list_for_each_entry_safe(t, t_next, &tx->free_list, list) {
+ list_del(&t->list);
+ free_tx_struct(t);
+ }
+
+ list_for_each_entry_safe(t, t_next, &tx->sdu_list, list) {
+ list_del(&t->list);
+ free_tx_struct(t);
+ }
+
+ list_for_each_entry_safe(t, t_next, &tx->hci_list, list) {
+ list_del(&t->list);
+ free_tx_struct(t);
+ }
+
+ kfree(rx->rx_buf);
+
+ list_for_each_entry_safe(r, r_next, &rx->free_list, list) {
+ list_del(&r->list);
+ free_rx_struct(r);
+ }
+
+ list_for_each_entry_safe(r, r_next, &rx->req_list, list) {
+ list_del(&r->list);
+ free_rx_struct(r);
+ }
+}
+
+static void send_sdio_pkt(struct sdio_func *func, u8 *data, int len)
+{
+ int n, blocks, ret, remain;
+
+ sdio_claim_host(func);
+
+ blocks = len / func->cur_blksize;
+ n = blocks * func->cur_blksize;
+ if (blocks) {
+ ret = sdio_memcpy_toio(func, 0, data, n);
+ if (ret < 0) {
+ if (ret != -ENOMEDIUM)
+ printk(KERN_ERR "gdmwms: %s error: ret = %d\n",
+ __func__, ret);
+ goto end_io;
+ }
+ }
+
+ remain = len - n;
+ remain = (remain + 3) & ~3;
+
+ if (remain) {
+ ret = sdio_memcpy_toio(func, 0, data + n, remain);
+ if (ret < 0) {
+ if (ret != -ENOMEDIUM)
+ printk(KERN_ERR "gdmwms: %s error: ret = %d\n",
+ __func__, ret);
+ goto end_io;
+ }
+ }
+
+end_io:
+ sdio_release_host(func);
+}
+
+static void send_sdu(struct sdio_func *func, struct tx_cxt *tx)
+{
+ struct list_head *l, *next;
+ struct hci_s *hci;
+ struct sdio_tx *t;
+ int pos, len, i, estlen, aggr_num = 0, aggr_len;
+ u8 *buf;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tx->lock, flags);
+
+ pos = TYPE_A_HEADER_SIZE + HCI_HEADER_SIZE;
+ list_for_each_entry(t, &tx->sdu_list, list) {
+ estlen = ((t->len + 3) & ~3) + 4;
+ if ((pos + estlen) > SDU_TX_BUF_SIZE)
+ break;
+
+ aggr_num++;
+ memcpy(tx->sdu_buf + pos, t->buf, t->len);
+ memset(tx->sdu_buf + pos + t->len, 0, estlen - t->len);
+ pos += estlen;
+ }
+ aggr_len = pos;
+
+ hci = (struct hci_s *)(tx->sdu_buf + TYPE_A_HEADER_SIZE);
+ hci->cmd_evt = H2B(WIMAX_TX_SDU_AGGR);
+ hci->length = H2B(aggr_len - TYPE_A_HEADER_SIZE - HCI_HEADER_SIZE);
+
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+#ifdef DEBUG
+ hexdump("sdio_send", tx->sdu_buf + TYPE_A_HEADER_SIZE,
+ aggr_len - TYPE_A_HEADER_SIZE);
+#endif
+
+ for (pos = TYPE_A_HEADER_SIZE; pos < aggr_len; pos += TX_CHUNK_SIZE) {
+ len = aggr_len - pos;
+ len = len > TX_CHUNK_SIZE ? TX_CHUNK_SIZE : len;
+ buf = tx->sdu_buf + pos - TYPE_A_HEADER_SIZE;
+
+ buf[0] = len & 0xff;
+ buf[1] = (len >> 8) & 0xff;
+ buf[2] = (len >> 16) & 0xff;
+ buf[3] = (pos + len) >= aggr_len ? 0 : 1;
+ send_sdio_pkt(func, buf, len + TYPE_A_HEADER_SIZE);
+ }
+
+ spin_lock_irqsave(&tx->lock, flags);
+
+ for (l = tx->sdu_list.next, i = 0; i < aggr_num; i++, l = next) {
+ next = l->next;
+ t = list_entry(l, struct sdio_tx, list);
+ if (t->callback)
+ t->callback(t->cb_data);
+
+ list_del(l);
+ put_tx_struct(t->tx_cxt, t);
+ }
+
+ do_gettimeofday(&tx->sdu_stamp);
+ spin_unlock_irqrestore(&tx->lock, flags);
+}
+
+static void send_hci(struct sdio_func *func, struct tx_cxt *tx,
+ struct sdio_tx *t)
+{
+ unsigned long flags;
+
+#ifdef DEBUG
+ hexdump("sdio_send", t->buf + TYPE_A_HEADER_SIZE,
+ t->len - TYPE_A_HEADER_SIZE);
+#endif
+ send_sdio_pkt(func, t->buf, t->len);
+
+ spin_lock_irqsave(&tx->lock, flags);
+ if (t->callback)
+ t->callback(t->cb_data);
+ free_tx_struct(t);
+ spin_unlock_irqrestore(&tx->lock, flags);
+}
+
+static void do_tx(struct work_struct *work)
+{
+ struct sdiowm_dev *sdev = container_of(work, struct sdiowm_dev, ws);
+ struct sdio_func *func = sdev->func;
+ struct tx_cxt *tx = &sdev->tx;
+ struct sdio_tx *t = NULL;
+ struct timeval now, *before;
+ int is_sdu = 0;
+ long diff;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tx->lock, flags);
+ if (!tx->can_send) {
+ spin_unlock_irqrestore(&tx->lock, flags);
+ return;
+ }
+
+ if (!list_empty(&tx->hci_list)) {
+ t = list_entry(tx->hci_list.next, struct sdio_tx, list);
+ list_del(&t->list);
+ is_sdu = 0;
+ } else if (!tx->stop_sdu_tx && !list_empty(&tx->sdu_list)) {
+ do_gettimeofday(&now);
+ before = &tx->sdu_stamp;
+
+ diff = (now.tv_sec - before->tv_sec) * 1000000 +
+ (now.tv_usec - before->tv_usec);
+ if (diff >= 0 && diff < TX_INTERVAL) {
+ schedule_work(&sdev->ws);
+ spin_unlock_irqrestore(&tx->lock, flags);
+ return;
+ }
+ is_sdu = 1;
+ }
+
+ if (!is_sdu && t == NULL) {
+ spin_unlock_irqrestore(&tx->lock, flags);
+ return;
+ }
+
+ tx->can_send = 0;
+
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+ if (is_sdu)
+ send_sdu(func, tx);
+ else
+ send_hci(func, tx, t);
+}
+
+static int gdm_sdio_send(void *priv_dev, void *data, int len,
+ void (*cb)(void *data), void *cb_data)
+{
+ struct sdiowm_dev *sdev = priv_dev;
+ struct tx_cxt *tx = &sdev->tx;
+ struct sdio_tx *t;
+ u8 *pkt = data;
+ int no_spc = 0;
+ u16 cmd_evt;
+ unsigned long flags;
+
+ BUG_ON(len > TX_BUF_SIZE - TYPE_A_HEADER_SIZE);
+
+ spin_lock_irqsave(&tx->lock, flags);
+
+ cmd_evt = (pkt[0] << 8) | pkt[1];
+ if (cmd_evt == WIMAX_TX_SDU) {
+ t = get_tx_struct(tx, &no_spc);
+ if (t == NULL) {
+ /* This case must not happen. */
+ spin_unlock_irqrestore(&tx->lock, flags);
+ return -ENOSPC;
+ }
+ list_add_tail(&t->list, &tx->sdu_list);
+
+ memcpy(t->buf, data, len);
+
+ t->len = len;
+ t->callback = cb;
+ t->cb_data = cb_data;
+ } else {
+ t = alloc_tx_struct(tx);
+ if (t == NULL) {
+ spin_unlock_irqrestore(&tx->lock, flags);
+ return -ENOMEM;
+ }
+ list_add_tail(&t->list, &tx->hci_list);
+
+ t->buf[0] = len & 0xff;
+ t->buf[1] = (len >> 8) & 0xff;
+ t->buf[2] = (len >> 16) & 0xff;
+ t->buf[3] = 2;
+ memcpy(t->buf + TYPE_A_HEADER_SIZE, data, len);
+
+ t->len = len + TYPE_A_HEADER_SIZE;
+ t->callback = cb;
+ t->cb_data = cb_data;
+ }
+
+ if (tx->can_send)
+ schedule_work(&sdev->ws);
+
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+ if (no_spc)
+ return -ENOSPC;
+
+ return 0;
+}
+
+/*
+ * Handle the HCI, WIMAX_SDU_TX_FLOW.
+ */
+static int control_sdu_tx_flow(struct sdiowm_dev *sdev, u8 *hci_data, int len)
+{
+ struct tx_cxt *tx = &sdev->tx;
+ u16 cmd_evt;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tx->lock, flags);
+
+ cmd_evt = (hci_data[0] << 8) | (hci_data[1]);
+ if (cmd_evt != WIMAX_SDU_TX_FLOW)
+ goto out;
+
+ if (hci_data[4] == 0) {
+#ifdef DEBUG
+ printk(KERN_DEBUG "WIMAX ==> STOP SDU TX\n");
+#endif
+ tx->stop_sdu_tx = 1;
+ } else if (hci_data[4] == 1) {
+#ifdef DEBUG
+ printk(KERN_DEBUG "WIMAX ==> START SDU TX\n");
+#endif
+ tx->stop_sdu_tx = 0;
+ if (tx->can_send)
+ schedule_work(&sdev->ws);
+ /*
+ * If free buffer for sdu tx doesn't exist, then tx queue
+ * should not be woken. For this reason, don't pass the command,
+ * START_SDU_TX.
+ */
+ if (list_empty(&tx->free_list))
+ len = 0;
+ }
+
+out:
+ spin_unlock_irqrestore(&tx->lock, flags);
+ return len;
+}
+
+static void gdm_sdio_irq(struct sdio_func *func)
+{
+ struct phy_dev *phy_dev = sdio_get_drvdata(func);
+ struct sdiowm_dev *sdev = phy_dev->priv_dev;
+ struct tx_cxt *tx = &sdev->tx;
+ struct rx_cxt *rx = &sdev->rx;
+ struct sdio_rx *r;
+ unsigned long flags;
+ u8 val, hdr[TYPE_A_LOOKAHEAD_SIZE], *buf;
+ u32 len, blocks, n;
+ int ret, remain;
+
+ /* Check interrupt */
+ val = sdio_readb(func, 0x13, &ret);
+ if (val & 0x01)
+ sdio_writeb(func, 0x01, 0x13, &ret); /* clear interrupt */
+ else
+ return;
+
+ ret = sdio_memcpy_fromio(func, hdr, 0x0, TYPE_A_LOOKAHEAD_SIZE);
+ if (ret) {
+ printk(KERN_ERR "Cannot read from function %d\n", func->num);
+ goto done;
+ }
+
+ len = (hdr[2] << 16) | (hdr[1] << 8) | hdr[0];
+ if (len > (RX_BUF_SIZE - TYPE_A_HEADER_SIZE)) {
+ printk(KERN_ERR "Too big Type-A size: %d\n", len);
+ goto done;
+ }
+
+ if (hdr[3] == 1) { /* Ack */
+#ifdef DEBUG
+ u32 *ack_seq = (u32 *)&hdr[4];
+#endif
+ spin_lock_irqsave(&tx->lock, flags);
+ tx->can_send = 1;
+
+ if (!list_empty(&tx->sdu_list) || !list_empty(&tx->hci_list))
+ schedule_work(&sdev->ws);
+ spin_unlock_irqrestore(&tx->lock, flags);
+#ifdef DEBUG
+ printk(KERN_DEBUG "Ack... %0x\n", ntohl(*ack_seq));
+#endif
+ goto done;
+ }
+
+ memcpy(rx->rx_buf, hdr + TYPE_A_HEADER_SIZE,
+ TYPE_A_LOOKAHEAD_SIZE - TYPE_A_HEADER_SIZE);
+
+ buf = rx->rx_buf + TYPE_A_LOOKAHEAD_SIZE - TYPE_A_HEADER_SIZE;
+ remain = len - TYPE_A_LOOKAHEAD_SIZE + TYPE_A_HEADER_SIZE;
+ if (remain <= 0)
+ goto end_io;
+
+ blocks = remain / func->cur_blksize;
+
+ if (blocks) {
+ n = blocks * func->cur_blksize;
+ ret = sdio_memcpy_fromio(func, buf, 0x0, n);
+ if (ret) {
+ printk(KERN_ERR "Cannot read from function %d\n",
+ func->num);
+ goto done;
+ }
+ buf += n;
+ remain -= n;
+ }
+
+ if (remain) {
+ ret = sdio_memcpy_fromio(func, buf, 0x0, remain);
+ if (ret) {
+ printk(KERN_ERR "Cannot read from function %d\n",
+ func->num);
+ goto done;
+ }
+ }
+
+end_io:
+#ifdef DEBUG
+ hexdump("sdio_receive", rx->rx_buf, len);
+#endif
+ len = control_sdu_tx_flow(sdev, rx->rx_buf, len);
+
+ spin_lock_irqsave(&rx->lock, flags);
+
+ if (!list_empty(&rx->req_list)) {
+ r = list_entry(rx->req_list.next, struct sdio_rx, list);
+ spin_unlock_irqrestore(&rx->lock, flags);
+ if (r->callback)
+ r->callback(r->cb_data, rx->rx_buf, len);
+ spin_lock_irqsave(&rx->lock, flags);
+ list_del(&r->list);
+ put_rx_struct(rx, r);
+ }
+
+ spin_unlock_irqrestore(&rx->lock, flags);
+
+done:
+ sdio_writeb(func, 0x00, 0x10, &ret); /* PCRRT */
+ if (!phy_dev->netdev)
+ register_wimax_device(phy_dev, &func->dev);
+}
+
+static int gdm_sdio_receive(void *priv_dev,
+ void (*cb)(void *cb_data, void *data, int len),
+ void *cb_data)
+{
+ struct sdiowm_dev *sdev = priv_dev;
+ struct rx_cxt *rx = &sdev->rx;
+ struct sdio_rx *r;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rx->lock, flags);
+ r = get_rx_struct(rx);
+ if (r == NULL) {
+ spin_unlock_irqrestore(&rx->lock, flags);
+ return -ENOMEM;
+ }
+
+ r->callback = cb;
+ r->cb_data = cb_data;
+
+ list_add_tail(&r->list, &rx->req_list);
+ spin_unlock_irqrestore(&rx->lock, flags);
+
+ return 0;
+}
+
+static int sdio_wimax_probe(struct sdio_func *func,
+ const struct sdio_device_id *id)
+{
+ int ret;
+ struct phy_dev *phy_dev = NULL;
+ struct sdiowm_dev *sdev = NULL;
+
+ printk(KERN_INFO "Found GDM SDIO VID = 0x%04x PID = 0x%04x...\n",
+ func->vendor, func->device);
+ printk(KERN_INFO "GCT WiMax driver version %s\n", DRIVER_VERSION);
+
+ sdio_claim_host(func);
+ sdio_enable_func(func);
+ sdio_claim_irq(func, gdm_sdio_irq);
+
+ ret = sdio_boot(func);
+ if (ret)
+ return ret;
+
+ phy_dev = kmalloc(sizeof(*phy_dev), GFP_KERNEL);
+ if (phy_dev == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ sdev = kmalloc(sizeof(*sdev), GFP_KERNEL);
+ if (sdev == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memset(phy_dev, 0, sizeof(*phy_dev));
+ memset(sdev, 0, sizeof(*sdev));
+
+ phy_dev->priv_dev = (void *)sdev;
+ phy_dev->send_func = gdm_sdio_send;
+ phy_dev->rcv_func = gdm_sdio_receive;
+
+ ret = init_sdio(sdev);
+ if (sdev < 0)
+ goto out;
+
+ sdev->func = func;
+
+ sdio_writeb(func, 1, 0x14, &ret); /* Enable interrupt */
+ sdio_release_host(func);
+
+ INIT_WORK(&sdev->ws, do_tx);
+
+ sdio_set_drvdata(func, phy_dev);
+out:
+ if (ret) {
+ kfree(phy_dev);
+ kfree(sdev);
+ }
+
+ return ret;
+}
+
+static void sdio_wimax_remove(struct sdio_func *func)
+{
+ struct phy_dev *phy_dev = sdio_get_drvdata(func);
+ struct sdiowm_dev *sdev = phy_dev->priv_dev;
+
+ if (phy_dev->netdev)
+ unregister_wimax_device(phy_dev);
+ sdio_claim_host(func);
+ sdio_release_irq(func);
+ sdio_disable_func(func);
+ sdio_release_host(func);
+ release_sdio(sdev);
+
+ kfree(sdev);
+ kfree(phy_dev);
+}
+
+static const struct sdio_device_id sdio_wimax_ids[] = {
+ { SDIO_DEVICE(0x0296, 0x5347) },
+ {0}
+};
+
+MODULE_DEVICE_TABLE(sdio, sdio_wimax_ids);
+
+static struct sdio_driver sdio_wimax_driver = {
+ .probe = sdio_wimax_probe,
+ .remove = sdio_wimax_remove,
+ .name = "sdio_wimax",
+ .id_table = sdio_wimax_ids,
+};
+
+static int __init sdio_gdm_wimax_init(void)
+{
+ return sdio_register_driver(&sdio_wimax_driver);
+}
+
+static void __exit sdio_gdm_wimax_exit(void)
+{
+ sdio_unregister_driver(&sdio_wimax_driver);
+}
+
+module_init(sdio_gdm_wimax_init);
+module_exit(sdio_gdm_wimax_exit);
+
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_DESCRIPTION("GCT WiMax SDIO Device Driver");
+MODULE_AUTHOR("Ethan Park");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/gdm72xx/gdm_sdio.h b/drivers/staging/gdm72xx/gdm_sdio.h
new file mode 100644
index 000000000000..216e98f31bae
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_sdio.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __GDM_SDIO_H__
+#define __GDM_SDIO_H__
+
+#include <linux/types.h>
+#include <linux/time.h>
+
+#define MAX_NR_SDU_BUF 64
+
+struct sdio_tx {
+ struct list_head list;
+ struct tx_cxt *tx_cxt;
+
+ u8 *buf;
+ int len;
+
+ void (*callback)(void *cb_data);
+ void *cb_data;
+};
+
+struct tx_cxt {
+ struct list_head free_list;
+ struct list_head sdu_list;
+ struct list_head hci_list;
+ struct timeval sdu_stamp;
+
+ u8 *sdu_buf;
+
+ spinlock_t lock;
+ int can_send;
+ int stop_sdu_tx;
+};
+
+struct sdio_rx {
+ struct list_head list;
+ struct rx_cxt *rx_cxt;
+
+ void (*callback)(void *cb_data, void *data, int len);
+ void *cb_data;
+};
+
+struct rx_cxt {
+ struct list_head free_list;
+ struct list_head req_list;
+
+ u8 *rx_buf;
+
+ spinlock_t lock;
+};
+
+struct sdiowm_dev {
+ struct sdio_func *func;
+
+ struct tx_cxt tx;
+ struct rx_cxt rx;
+
+ struct work_struct ws;
+};
+
+#endif /* __GDM_SDIO_H__ */
diff --git a/drivers/staging/gdm72xx/gdm_usb.c b/drivers/staging/gdm72xx/gdm_usb.c
new file mode 100644
index 000000000000..1e9dc0d90362
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_usb.c
@@ -0,0 +1,798 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <asm/byteorder.h>
+
+#include "gdm_usb.h"
+#include "gdm_wimax.h"
+#include "usb_boot.h"
+#include "hci.h"
+
+#include "usb_ids.h"
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+#define TX_BUF_SIZE 2048
+#if defined(CONFIG_WIMAX_GDM72XX_WIMAX2)
+#define RX_BUF_SIZE (128*1024) /* For packet aggregation */
+#else
+#define RX_BUF_SIZE 2048
+#endif
+
+#define GDM7205_PADDING 256
+
+#define H2B(x) __cpu_to_be16(x)
+#define B2H(x) __be16_to_cpu(x)
+#define DB2H(x) __be32_to_cpu(x)
+
+#define DOWNLOAD_CONF_VALUE 0x21
+
+#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
+
+static DECLARE_WAIT_QUEUE_HEAD(k_wait);
+static LIST_HEAD(k_list);
+static DEFINE_SPINLOCK(k_lock);
+static int k_mode_stop;
+
+#define K_WAIT_TIME (2 * HZ / 100)
+
+#endif /* CONFIG_WIMAX_GDM72XX_K_MODE */
+
+static int init_usb(struct usbwm_dev *udev);
+static void release_usb(struct usbwm_dev *udev);
+
+/*#define DEBUG */
+#ifdef DEBUG
+static void hexdump(char *title, u8 *data, int len)
+{
+ int i;
+
+ printk(KERN_DEBUG "%s: length = %d\n", title, len);
+ for (i = 0; i < len; i++) {
+ printk(KERN_DEBUG "%02x ", data[i]);
+ if ((i & 0xf) == 0xf)
+ printk(KERN_DEBUG "\n");
+ }
+ printk(KERN_DEBUG "\n");
+}
+#endif
+
+static struct usb_tx *alloc_tx_struct(struct tx_cxt *tx)
+{
+ struct usb_tx *t = NULL;
+
+ t = kmalloc(sizeof(*t), GFP_ATOMIC);
+ if (t == NULL)
+ goto out;
+
+ memset(t, 0, sizeof(*t));
+
+ t->urb = usb_alloc_urb(0, GFP_ATOMIC);
+ t->buf = kmalloc(TX_BUF_SIZE, GFP_ATOMIC);
+ if (t->urb == NULL || t->buf == NULL)
+ goto out;
+
+ t->tx_cxt = tx;
+
+ return t;
+out:
+ if (t) {
+ usb_free_urb(t->urb);
+ kfree(t->buf);
+ kfree(t);
+ }
+ return NULL;
+}
+
+static void free_tx_struct(struct usb_tx *t)
+{
+ if (t) {
+ usb_free_urb(t->urb);
+ kfree(t->buf);
+ kfree(t);
+ }
+}
+
+static struct usb_rx *alloc_rx_struct(struct rx_cxt *rx)
+{
+ struct usb_rx *r = NULL;
+
+ r = kmalloc(sizeof(*r), GFP_ATOMIC);
+ if (r == NULL)
+ goto out;
+
+ memset(r, 0, sizeof(*r));
+
+ r->urb = usb_alloc_urb(0, GFP_ATOMIC);
+ r->buf = kmalloc(RX_BUF_SIZE, GFP_ATOMIC);
+ if (r->urb == NULL || r->buf == NULL)
+ goto out;
+
+ r->rx_cxt = rx;
+ return r;
+out:
+ if (r) {
+ usb_free_urb(r->urb);
+ kfree(r->buf);
+ kfree(r);
+ }
+ return NULL;
+}
+
+static void free_rx_struct(struct usb_rx *r)
+{
+ if (r) {
+ usb_free_urb(r->urb);
+ kfree(r->buf);
+ kfree(r);
+ }
+}
+
+/* Before this function is called, spin lock should be locked. */
+static struct usb_tx *get_tx_struct(struct tx_cxt *tx, int *no_spc)
+{
+ struct usb_tx *t;
+
+ if (list_empty(&tx->free_list)) {
+ *no_spc = 1;
+ return NULL;
+ }
+
+ t = list_entry(tx->free_list.next, struct usb_tx, list);
+ list_del(&t->list);
+
+ *no_spc = list_empty(&tx->free_list) ? 1 : 0;
+
+ return t;
+}
+
+/* Before this function is called, spin lock should be locked. */
+static void put_tx_struct(struct tx_cxt *tx, struct usb_tx *t)
+{
+ list_add_tail(&t->list, &tx->free_list);
+}
+
+/* Before this function is called, spin lock should be locked. */
+static struct usb_rx *get_rx_struct(struct rx_cxt *rx)
+{
+ struct usb_rx *r;
+
+ if (list_empty(&rx->free_list)) {
+ r = alloc_rx_struct(rx);
+ if (r == NULL)
+ return NULL;
+
+ list_add(&r->list, &rx->free_list);
+ }
+
+ r = list_entry(rx->free_list.next, struct usb_rx, list);
+ list_del(&r->list);
+ list_add_tail(&r->list, &rx->used_list);
+
+ return r;
+}
+
+/* Before this function is called, spin lock should be locked. */
+static void put_rx_struct(struct rx_cxt *rx, struct usb_rx *r)
+{
+ list_del(&r->list);
+ list_add(&r->list, &rx->free_list);
+}
+
+static int init_usb(struct usbwm_dev *udev)
+{
+ int ret = 0, i;
+ struct tx_cxt *tx = &udev->tx;
+ struct rx_cxt *rx = &udev->rx;
+ struct usb_tx *t;
+ struct usb_rx *r;
+
+ INIT_LIST_HEAD(&tx->free_list);
+ INIT_LIST_HEAD(&tx->sdu_list);
+ INIT_LIST_HEAD(&tx->hci_list);
+#if defined(CONFIG_WIMAX_GDM72XX_USB_PM) || defined(CONFIG_WIMAX_GDM72XX_K_MODE)
+ INIT_LIST_HEAD(&tx->pending_list);
+#endif
+
+ INIT_LIST_HEAD(&rx->free_list);
+ INIT_LIST_HEAD(&rx->used_list);
+
+ spin_lock_init(&tx->lock);
+ spin_lock_init(&rx->lock);
+
+ for (i = 0; i < MAX_NR_SDU_BUF; i++) {
+ t = alloc_tx_struct(tx);
+ if (t == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+ list_add(&t->list, &tx->free_list);
+ }
+
+ r = alloc_rx_struct(rx);
+ if (r == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ list_add(&r->list, &rx->free_list);
+ return ret;
+
+fail:
+ release_usb(udev);
+ return ret;
+}
+
+static void release_usb(struct usbwm_dev *udev)
+{
+ struct tx_cxt *tx = &udev->tx;
+ struct rx_cxt *rx = &udev->rx;
+ struct usb_tx *t, *t_next;
+ struct usb_rx *r, *r_next;
+
+ list_for_each_entry_safe(t, t_next, &tx->sdu_list, list) {
+ list_del(&t->list);
+ free_tx_struct(t);
+ }
+
+ list_for_each_entry_safe(t, t_next, &tx->hci_list, list) {
+ list_del(&t->list);
+ free_tx_struct(t);
+ }
+
+ list_for_each_entry_safe(t, t_next, &tx->free_list, list) {
+ list_del(&t->list);
+ free_tx_struct(t);
+ }
+
+ list_for_each_entry_safe(r, r_next, &rx->free_list, list) {
+ list_del(&r->list);
+ free_rx_struct(r);
+ }
+
+ list_for_each_entry_safe(r, r_next, &rx->used_list, list) {
+ list_del(&r->list);
+ free_rx_struct(r);
+ }
+}
+
+static void gdm_usb_send_complete(struct urb *urb)
+{
+ struct usb_tx *t = urb->context;
+ struct tx_cxt *tx = t->tx_cxt;
+ u8 *pkt = t->buf;
+ u16 cmd_evt;
+ unsigned long flags;
+
+ /* Completion by usb_unlink_urb */
+ if (urb->status == -ECONNRESET)
+ return;
+
+ spin_lock_irqsave(&tx->lock, flags);
+
+ if (t->callback)
+ t->callback(t->cb_data);
+
+ /* Delete from sdu list or hci list. */
+ list_del(&t->list);
+
+ cmd_evt = (pkt[0] << 8) | pkt[1];
+ if (cmd_evt == WIMAX_TX_SDU)
+ put_tx_struct(tx, t);
+ else
+ free_tx_struct(t);
+
+ spin_unlock_irqrestore(&tx->lock, flags);
+}
+
+static int gdm_usb_send(void *priv_dev, void *data, int len,
+ void (*cb)(void *data), void *cb_data)
+{
+ struct usbwm_dev *udev = priv_dev;
+ struct usb_device *usbdev = udev->usbdev;
+ struct tx_cxt *tx = &udev->tx;
+ struct usb_tx *t;
+ int padding = udev->padding;
+ int no_spc = 0, ret;
+ u8 *pkt = data;
+ u16 cmd_evt;
+ unsigned long flags;
+
+ if (!udev->usbdev) {
+ printk(KERN_ERR "%s: No such device\n", __func__);
+ return -ENODEV;
+ }
+
+ BUG_ON(len > TX_BUF_SIZE - padding - 1);
+
+ spin_lock_irqsave(&tx->lock, flags);
+
+ cmd_evt = (pkt[0] << 8) | pkt[1];
+ if (cmd_evt == WIMAX_TX_SDU) {
+ t = get_tx_struct(tx, &no_spc);
+ if (t == NULL) {
+ /* This case must not happen. */
+ spin_unlock_irqrestore(&tx->lock, flags);
+ return -ENOSPC;
+ }
+ list_add_tail(&t->list, &tx->sdu_list);
+ } else {
+ t = alloc_tx_struct(tx);
+ if (t == NULL) {
+ spin_unlock_irqrestore(&tx->lock, flags);
+ return -ENOMEM;
+ }
+ list_add_tail(&t->list, &tx->hci_list);
+ }
+
+ memcpy(t->buf + padding, data, len);
+ t->callback = cb;
+ t->cb_data = cb_data;
+
+ /*
+ * In some cases, USB Module of WiMax is blocked when data size is
+ * the multiple of 512. So, increment length by one in that case.
+ */
+ if ((len % 512) == 0)
+ len++;
+
+ usb_fill_bulk_urb(t->urb,
+ usbdev,
+ usb_sndbulkpipe(usbdev, 1),
+ t->buf,
+ len + padding,
+ gdm_usb_send_complete,
+ t);
+
+#ifdef DEBUG
+ hexdump("usb_send", t->buf, len + padding);
+#endif
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+ if (usbdev->state & USB_STATE_SUSPENDED) {
+ list_add_tail(&t->p_list, &tx->pending_list);
+ schedule_work(&udev->pm_ws);
+ goto out;
+ }
+#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */
+
+#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
+ if (udev->bw_switch) {
+ list_add_tail(&t->p_list, &tx->pending_list);
+ goto out;
+ } else if (cmd_evt == WIMAX_SCAN) {
+ struct rx_cxt *rx;
+ struct usb_rx *r;
+
+ rx = &udev->rx;
+
+ list_for_each_entry(r, &rx->used_list, list)
+ usb_unlink_urb(r->urb);
+ udev->bw_switch = 1;
+
+ spin_lock(&k_lock);
+ list_add_tail(&udev->list, &k_list);
+ spin_unlock(&k_lock);
+
+ wake_up(&k_wait);
+ }
+#endif /* CONFIG_WIMAX_GDM72XX_K_MODE */
+
+ ret = usb_submit_urb(t->urb, GFP_ATOMIC);
+ if (ret)
+ goto send_fail;
+
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+ usb_mark_last_busy(usbdev);
+#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */
+
+#if defined(CONFIG_WIMAX_GDM72XX_USB_PM) || defined(CONFIG_WIMAX_GDM72XX_K_MODE)
+out:
+#endif
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+ if (no_spc)
+ return -ENOSPC;
+
+ return 0;
+
+send_fail:
+ t->callback = NULL;
+ gdm_usb_send_complete(t->urb);
+ spin_unlock_irqrestore(&tx->lock, flags);
+ return ret;
+}
+
+static void gdm_usb_rcv_complete(struct urb *urb)
+{
+ struct usb_rx *r = urb->context;
+ struct rx_cxt *rx = r->rx_cxt;
+ struct usbwm_dev *udev = container_of(r->rx_cxt, struct usbwm_dev, rx);
+ struct tx_cxt *tx = &udev->tx;
+ struct usb_tx *t;
+ u16 cmd_evt;
+ unsigned long flags;
+
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+ struct usb_device *dev = urb->dev;
+#endif
+
+ /* Completion by usb_unlink_urb */
+ if (urb->status == -ECONNRESET)
+ return;
+
+ spin_lock_irqsave(&tx->lock, flags);
+
+ if (!urb->status) {
+ cmd_evt = (r->buf[0] << 8) | (r->buf[1]);
+#ifdef DEBUG
+ hexdump("usb_receive", r->buf, urb->actual_length);
+#endif
+ if (cmd_evt == WIMAX_SDU_TX_FLOW) {
+ if (r->buf[4] == 0) {
+#ifdef DEBUG
+ printk(KERN_DEBUG "WIMAX ==> STOP SDU TX\n");
+#endif
+ list_for_each_entry(t, &tx->sdu_list, list)
+ usb_unlink_urb(t->urb);
+ } else if (r->buf[4] == 1) {
+#ifdef DEBUG
+ printk(KERN_DEBUG "WIMAX ==> START SDU TX\n");
+#endif
+ list_for_each_entry(t, &tx->sdu_list, list) {
+ usb_submit_urb(t->urb, GFP_ATOMIC);
+ }
+ /*
+ * If free buffer for sdu tx doesn't
+ * exist, then tx queue should not be
+ * woken. For this reason, don't pass
+ * the command, START_SDU_TX.
+ */
+ if (list_empty(&tx->free_list))
+ urb->actual_length = 0;
+ }
+ }
+ }
+
+ if (!urb->status && r->callback)
+ r->callback(r->cb_data, r->buf, urb->actual_length);
+
+ spin_lock(&rx->lock);
+ put_rx_struct(rx, r);
+ spin_unlock(&rx->lock);
+
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+ usb_mark_last_busy(dev);
+#endif
+}
+
+static int gdm_usb_receive(void *priv_dev,
+ void (*cb)(void *cb_data, void *data, int len),
+ void *cb_data)
+{
+ struct usbwm_dev *udev = priv_dev;
+ struct usb_device *usbdev = udev->usbdev;
+ struct rx_cxt *rx = &udev->rx;
+ struct usb_rx *r;
+ unsigned long flags;
+
+ if (!udev->usbdev) {
+ printk(KERN_ERR "%s: No such device\n", __func__);
+ return -ENODEV;
+ }
+
+ spin_lock_irqsave(&rx->lock, flags);
+ r = get_rx_struct(rx);
+ spin_unlock_irqrestore(&rx->lock, flags);
+
+ if (r == NULL)
+ return -ENOMEM;
+
+ r->callback = cb;
+ r->cb_data = cb_data;
+
+ usb_fill_bulk_urb(r->urb,
+ usbdev,
+ usb_rcvbulkpipe(usbdev, 0x82),
+ r->buf,
+ RX_BUF_SIZE,
+ gdm_usb_rcv_complete,
+ r);
+
+ return usb_submit_urb(r->urb, GFP_ATOMIC);
+}
+
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+static void do_pm_control(struct work_struct *work)
+{
+ struct usbwm_dev *udev = container_of(work, struct usbwm_dev, pm_ws);
+ struct tx_cxt *tx = &udev->tx;
+ int ret;
+ unsigned long flags;
+
+ ret = usb_autopm_get_interface(udev->intf);
+ if (!ret)
+ usb_autopm_put_interface(udev->intf);
+
+ spin_lock_irqsave(&tx->lock, flags);
+ if (!(udev->usbdev->state & USB_STATE_SUSPENDED)
+ && (!list_empty(&tx->hci_list) || !list_empty(&tx->sdu_list))) {
+ struct usb_tx *t, *temp;
+
+ list_for_each_entry_safe(t, temp, &tx->pending_list, p_list) {
+ list_del(&t->p_list);
+ ret = usb_submit_urb(t->urb, GFP_ATOMIC);
+
+ if (ret) {
+ t->callback = NULL;
+ gdm_usb_send_complete(t->urb);
+ }
+ }
+ }
+ spin_unlock_irqrestore(&tx->lock, flags);
+}
+#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */
+
+static int gdm_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ int ret = 0;
+ u8 bConfigurationValue;
+ struct phy_dev *phy_dev = NULL;
+ struct usbwm_dev *udev = NULL;
+ u16 idVendor, idProduct, bcdDevice;
+
+ struct usb_device *usbdev = interface_to_usbdev(intf);
+
+ usb_get_dev(usbdev);
+ bConfigurationValue = usbdev->actconfig->desc.bConfigurationValue;
+
+ /*USB description is set up with Little-Endian*/
+ idVendor = L2H(usbdev->descriptor.idVendor);
+ idProduct = L2H(usbdev->descriptor.idProduct);
+ bcdDevice = L2H(usbdev->descriptor.bcdDevice);
+
+ printk(KERN_INFO "Found GDM USB VID = 0x%04x PID = 0x%04x...\n",
+ idVendor, idProduct);
+ printk(KERN_INFO "GCT WiMax driver version %s\n", DRIVER_VERSION);
+
+
+ if (idProduct == EMERGENCY_PID) {
+ ret = usb_emergency(usbdev);
+ goto out;
+ }
+
+ /* Support for EEPROM bootloader */
+ if (bConfigurationValue == DOWNLOAD_CONF_VALUE ||
+ idProduct & B_DOWNLOAD) {
+ ret = usb_boot(usbdev, bcdDevice);
+ goto out;
+ }
+
+ phy_dev = kmalloc(sizeof(*phy_dev), GFP_KERNEL);
+ if (phy_dev == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ udev = kmalloc(sizeof(*udev), GFP_KERNEL);
+ if (udev == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memset(phy_dev, 0, sizeof(*phy_dev));
+ memset(udev, 0, sizeof(*udev));
+
+ if (idProduct == 0x7205 || idProduct == 0x7206)
+ udev->padding = GDM7205_PADDING;
+ else
+ udev->padding = 0;
+
+ phy_dev->priv_dev = (void *)udev;
+ phy_dev->send_func = gdm_usb_send;
+ phy_dev->rcv_func = gdm_usb_receive;
+
+ ret = init_usb(udev);
+ if (ret < 0)
+ goto out;
+
+ udev->usbdev = usbdev;
+
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+ udev->intf = intf;
+
+ intf->needs_remote_wakeup = 1;
+ device_init_wakeup(&intf->dev, 1);
+
+ pm_runtime_set_autosuspend_delay(&usbdev->dev, 10 * 1000); /* msec */
+
+ INIT_WORK(&udev->pm_ws, do_pm_control);
+#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */
+
+ ret = register_wimax_device(phy_dev, &intf->dev);
+
+out:
+ if (ret) {
+ kfree(phy_dev);
+ kfree(udev);
+ }
+ usb_set_intfdata(intf, phy_dev);
+ return ret;
+}
+
+static void gdm_usb_disconnect(struct usb_interface *intf)
+{
+ u8 bConfigurationValue;
+ struct phy_dev *phy_dev;
+ struct usbwm_dev *udev;
+ u16 idProduct;
+ struct usb_device *usbdev = interface_to_usbdev(intf);
+
+ bConfigurationValue = usbdev->actconfig->desc.bConfigurationValue;
+ phy_dev = usb_get_intfdata(intf);
+
+ /*USB description is set up with Little-Endian*/
+ idProduct = L2H(usbdev->descriptor.idProduct);
+
+ if (idProduct != EMERGENCY_PID &&
+ bConfigurationValue != DOWNLOAD_CONF_VALUE &&
+ (idProduct & B_DOWNLOAD) == 0) {
+ udev = phy_dev->priv_dev;
+ udev->usbdev = NULL;
+
+ unregister_wimax_device(phy_dev);
+ release_usb(udev);
+ kfree(udev);
+ kfree(phy_dev);
+ }
+
+ usb_put_dev(usbdev);
+}
+
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+static int gdm_suspend(struct usb_interface *intf, pm_message_t pm_msg)
+{
+ struct phy_dev *phy_dev;
+ struct usbwm_dev *udev;
+ struct rx_cxt *rx;
+ struct usb_rx *r;
+
+ phy_dev = usb_get_intfdata(intf);
+ udev = phy_dev->priv_dev;
+ rx = &udev->rx;
+
+ list_for_each_entry(r, &rx->used_list, list)
+ usb_unlink_urb(r->urb);
+
+ return 0;
+}
+
+static int gdm_resume(struct usb_interface *intf)
+{
+ struct phy_dev *phy_dev;
+ struct usbwm_dev *udev;
+ struct rx_cxt *rx;
+ struct usb_rx *r;
+
+ phy_dev = usb_get_intfdata(intf);
+ udev = phy_dev->priv_dev;
+ rx = &udev->rx;
+
+ list_for_each_entry(r, &rx->used_list, list)
+ usb_submit_urb(r->urb, GFP_ATOMIC);
+
+ return 0;
+}
+
+#endif /* CONFIG_WIMAX_GDM72XX_USB_PM */
+
+#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
+static int k_mode_thread(void *arg)
+{
+ struct usbwm_dev *udev;
+ struct tx_cxt *tx;
+ struct rx_cxt *rx;
+ struct usb_tx *t, *temp;
+ struct usb_rx *r;
+ unsigned long flags, flags2, expire;
+ int ret;
+
+ daemonize("k_mode_wimax");
+
+ while (!k_mode_stop) {
+
+ spin_lock_irqsave(&k_lock, flags2);
+ while (!list_empty(&k_list)) {
+
+ udev = list_entry(k_list.next, struct usbwm_dev, list);
+ tx = &udev->tx;
+ rx = &udev->rx;
+
+ list_del(&udev->list);
+ spin_unlock_irqrestore(&k_lock, flags2);
+
+ expire = jiffies + K_WAIT_TIME;
+ while (jiffies < expire)
+ schedule_timeout(K_WAIT_TIME);
+
+ list_for_each_entry(r, &rx->used_list, list)
+ usb_submit_urb(r->urb, GFP_ATOMIC);
+
+ spin_lock_irqsave(&tx->lock, flags);
+
+ list_for_each_entry_safe(t, temp, &tx->pending_list,
+ p_list) {
+ list_del(&t->p_list);
+ ret = usb_submit_urb(t->urb, GFP_ATOMIC);
+
+ if (ret) {
+ t->callback = NULL;
+ gdm_usb_send_complete(t->urb);
+ }
+ }
+
+ udev->bw_switch = 0;
+ spin_unlock_irqrestore(&tx->lock, flags);
+
+ spin_lock_irqsave(&k_lock, flags2);
+ }
+ spin_unlock_irqrestore(&k_lock, flags2);
+
+ interruptible_sleep_on(&k_wait);
+ }
+ return 0;
+}
+#endif /* CONFIG_WIMAX_GDM72XX_K_MODE */
+
+static struct usb_driver gdm_usb_driver = {
+ .name = "gdm_wimax",
+ .probe = gdm_usb_probe,
+ .disconnect = gdm_usb_disconnect,
+ .id_table = id_table,
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+ .supports_autosuspend = 1,
+ .suspend = gdm_suspend,
+ .resume = gdm_resume,
+ .reset_resume = gdm_resume,
+#endif
+};
+
+static int __init usb_gdm_wimax_init(void)
+{
+#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
+ kernel_thread(k_mode_thread, NULL, CLONE_KERNEL);
+#endif /* CONFIG_WIMAX_GDM72XX_K_MODE */
+ return usb_register(&gdm_usb_driver);
+}
+
+static void __exit usb_gdm_wimax_exit(void)
+{
+#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
+ k_mode_stop = 1;
+ wake_up(&k_wait);
+#endif
+ usb_deregister(&gdm_usb_driver);
+}
+
+module_init(usb_gdm_wimax_init);
+module_exit(usb_gdm_wimax_exit);
+
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_DESCRIPTION("GCT WiMax Device Driver");
+MODULE_AUTHOR("Ethan Park");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/gdm72xx/gdm_usb.h b/drivers/staging/gdm72xx/gdm_usb.h
new file mode 100644
index 000000000000..ecb891f6a599
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_usb.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __GDM_USB_H__
+#define __GDM_USB_H__
+
+#include <linux/types.h>
+#include <linux/usb.h>
+#include <linux/list.h>
+
+#define B_DIFF_DL_DRV (1<<4)
+#define B_DOWNLOAD (1 << 5)
+#define MAX_NR_SDU_BUF 64
+
+struct usb_tx {
+ struct list_head list;
+#if defined(CONFIG_WIMAX_GDM72XX_USB_PM) || defined(CONFIG_WIMAX_GDM72XX_K_MODE)
+ struct list_head p_list;
+#endif
+ struct tx_cxt *tx_cxt;
+
+ struct urb *urb;
+ u8 *buf;
+
+ void (*callback)(void *cb_data);
+ void *cb_data;
+};
+
+struct tx_cxt {
+ struct list_head free_list;
+ struct list_head sdu_list;
+ struct list_head hci_list;
+#if defined(CONFIG_WIMAX_GDM72XX_USB_PM) || defined(CONFIG_WIMAX_GDM72XX_K_MODE)
+ struct list_head pending_list;
+#endif
+
+ spinlock_t lock;
+};
+
+struct usb_rx {
+ struct list_head list;
+ struct rx_cxt *rx_cxt;
+
+ struct urb *urb;
+ u8 *buf;
+
+ void (*callback)(void *cb_data, void *data, int len);
+ void *cb_data;
+};
+
+struct rx_cxt {
+ struct list_head free_list;
+ struct list_head used_list;
+ spinlock_t lock;
+};
+
+struct usbwm_dev {
+ struct usb_device *usbdev;
+#ifdef CONFIG_WIMAX_GDM72XX_USB_PM
+ struct work_struct pm_ws;
+
+ struct usb_interface *intf;
+#endif
+#ifdef CONFIG_WIMAX_GDM72XX_K_MODE
+ int bw_switch;
+ struct list_head list;
+#endif
+
+ struct tx_cxt tx;
+ struct rx_cxt rx;
+
+ int padding;
+};
+
+#endif /* __GDM_USB_H__ */
diff --git a/drivers/staging/gdm72xx/gdm_wimax.c b/drivers/staging/gdm72xx/gdm_wimax.c
new file mode 100644
index 000000000000..f1936b92533b
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_wimax.c
@@ -0,0 +1,1026 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/version.h>
+#include <linux/etherdevice.h>
+#include <asm/byteorder.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/udp.h>
+#include <linux/in.h>
+
+#include "gdm_wimax.h"
+#include "hci.h"
+#include "wm_ioctl.h"
+#include "netlink_k.h"
+
+#define gdm_wimax_send(n, d, l) \
+ (n->phy_dev->send_func)(n->phy_dev->priv_dev, d, l, NULL, NULL)
+#define gdm_wimax_send_with_cb(n, d, l, c, b) \
+ (n->phy_dev->send_func)(n->phy_dev->priv_dev, d, l, c, b)
+#define gdm_wimax_rcv_with_cb(n, c, b) \
+ (n->phy_dev->rcv_func)(n->phy_dev->priv_dev, c, b)
+
+#define EVT_MAX_SIZE 2048
+
+struct evt_entry {
+ struct list_head list;
+ struct net_device *dev;
+ char evt_data[EVT_MAX_SIZE];
+ int size;
+};
+
+static void __gdm_wimax_event_send(struct work_struct *work);
+static inline struct evt_entry *alloc_event_entry(void);
+static inline void free_event_entry(struct evt_entry *e);
+static struct evt_entry *get_event_entry(void);
+static void put_event_entry(struct evt_entry *e);
+
+static struct {
+ int ref_cnt;
+ struct sock *sock;
+ struct list_head evtq;
+ spinlock_t evt_lock;
+
+ struct list_head freeq;
+ struct work_struct ws;
+} wm_event;
+
+static u8 gdm_wimax_macaddr[6] = {0x00, 0x0a, 0x3b, 0xf0, 0x01, 0x30};
+
+static void gdm_wimax_ind_fsm_update(struct net_device *dev, struct fsm_s *fsm);
+static void gdm_wimax_ind_if_updown(struct net_device *dev, int if_up);
+
+#if defined(DEBUG_SDU)
+static void printk_hex(u8 *buf, u32 size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ if (i && i % 16 == 0)
+ printk(KERN_DEBUG "\n%02x ", *buf++);
+ else
+ printk(KERN_DEBUG "%02x ", *buf++);
+ }
+
+ printk(KERN_DEBUG "\n");
+}
+
+static const char *get_protocol_name(u16 protocol)
+{
+ static char buf[32];
+ const char *name = "-";
+
+ switch (protocol) {
+ case ETH_P_ARP:
+ name = "ARP";
+ break;
+ case ETH_P_IP:
+ name = "IP";
+ break;
+ case ETH_P_IPV6:
+ name = "IPv6";
+ break;
+ }
+
+ sprintf(buf, "0x%04x(%s)", protocol, name);
+ return buf;
+}
+
+static const char *get_ip_protocol_name(u8 ip_protocol)
+{
+ static char buf[32];
+ const char *name = "-";
+
+ switch (ip_protocol) {
+ case IPPROTO_TCP:
+ name = "TCP";
+ break;
+ case IPPROTO_UDP:
+ name = "UDP";
+ break;
+ case IPPROTO_ICMP:
+ name = "ICMP";
+ break;
+ }
+
+ sprintf(buf, "%u(%s)", ip_protocol, name);
+ return buf;
+}
+
+static const char *get_port_name(u16 port)
+{
+ static char buf[32];
+ const char *name = "-";
+
+ switch (port) {
+ case 67:
+ name = "DHCP-Server";
+ break;
+ case 68:
+ name = "DHCP-Client";
+ break;
+ case 69:
+ name = "TFTP";
+ break;
+ }
+
+ sprintf(buf, "%u(%s)", port, name);
+ return buf;
+}
+
+static void dump_eth_packet(const char *title, u8 *data, int len)
+{
+ struct iphdr *ih = NULL;
+ struct udphdr *uh = NULL;
+ u16 protocol = 0;
+ u8 ip_protocol = 0;
+ u16 port = 0;
+
+ protocol = (data[12]<<8) | data[13];
+ ih = (struct iphdr *) (data+ETH_HLEN);
+
+ if (protocol == ETH_P_IP) {
+ uh = (struct udphdr *) ((char *)ih + sizeof(struct iphdr));
+ ip_protocol = ih->protocol;
+ port = ntohs(uh->dest);
+ } else if (protocol == ETH_P_IPV6) {
+ struct ipv6hdr *i6h = (struct ipv6hdr *) data;
+ uh = (struct udphdr *) ((char *)i6h + sizeof(struct ipv6hdr));
+ ip_protocol = i6h->nexthdr;
+ port = ntohs(uh->dest);
+ }
+
+ printk(KERN_DEBUG "[%s] len=%d, %s, %s, %s\n",
+ title, len,
+ get_protocol_name(protocol),
+ get_ip_protocol_name(ip_protocol),
+ get_port_name(port));
+
+ #if 1
+ if (!(data[0] == 0xff && data[1] == 0xff)) {
+ if (protocol == ETH_P_IP) {
+ printk(KERN_DEBUG " src=%u.%u.%u.%u\n",
+ NIPQUAD(ih->saddr));
+ } else if (protocol == ETH_P_IPV6) {
+ #ifdef NIP6
+ printk(KERN_DEBUG " src=%x:%x:%x:%x:%x:%x:%x:%x\n",
+ NIP6(ih->saddr));
+ #else
+ printk(KERN_DEBUG " src=%pI6\n", &ih->saddr);
+ #endif
+ }
+ }
+ #endif
+
+ #if (DUMP_PACKET & DUMP_SDU_ALL)
+ printk_hex(data, len);
+ #else
+ #if (DUMP_PACKET & DUMP_SDU_ARP)
+ if (protocol == ETH_P_ARP)
+ printk_hex(data, len);
+ #endif
+ #if (DUMP_PACKET & DUMP_SDU_IP)
+ if (protocol == ETH_P_IP || protocol == ETH_P_IPV6)
+ printk_hex(data, len);
+ #else
+ #if (DUMP_PACKET & DUMP_SDU_IP_TCP)
+ if (ip_protocol == IPPROTO_TCP)
+ printk_hex(data, len);
+ #endif
+ #if (DUMP_PACKET & DUMP_SDU_IP_UDP)
+ if (ip_protocol == IPPROTO_UDP)
+ printk_hex(data, len);
+ #endif
+ #if (DUMP_PACKET & DUMP_SDU_IP_ICMP)
+ if (ip_protocol == IPPROTO_ICMP)
+ printk_hex(data, len);
+ #endif
+ #endif
+ #endif
+}
+#endif
+
+
+static inline int gdm_wimax_header(struct sk_buff **pskb)
+{
+ u16 buf[HCI_HEADER_SIZE / sizeof(u16)];
+ struct sk_buff *skb = *pskb;
+ int ret = 0;
+
+ if (unlikely(skb_headroom(skb) < HCI_HEADER_SIZE)) {
+ struct sk_buff *skb2;
+
+ skb2 = skb_realloc_headroom(skb, HCI_HEADER_SIZE);
+ if (skb2 == NULL)
+ return -ENOMEM;
+ if (skb->sk)
+ skb_set_owner_w(skb2, skb->sk);
+ kfree_skb(skb);
+ skb = skb2;
+ }
+
+ skb_push(skb, HCI_HEADER_SIZE);
+ buf[0] = H2B(WIMAX_TX_SDU);
+ buf[1] = H2B(skb->len - HCI_HEADER_SIZE);
+ memcpy(skb->data, buf, HCI_HEADER_SIZE);
+
+ *pskb = skb;
+ return ret;
+}
+
+static void gdm_wimax_event_rcv(struct net_device *dev, u16 type, void *msg,
+ int len)
+{
+ struct nic *nic = netdev_priv(dev);
+
+ #if defined(DEBUG_HCI)
+ u8 *buf = (u8 *) msg;
+ u16 hci_cmd = (buf[0]<<8) | buf[1];
+ u16 hci_len = (buf[2]<<8) | buf[3];
+ printk(KERN_DEBUG "H=>D: 0x%04x(%d)\n", hci_cmd, hci_len);
+ #endif
+
+ gdm_wimax_send(nic, msg, len);
+}
+
+static int gdm_wimax_event_init(void)
+{
+ if (wm_event.ref_cnt == 0) {
+ wm_event.sock = netlink_init(NETLINK_WIMAX,
+ gdm_wimax_event_rcv);
+ INIT_LIST_HEAD(&wm_event.evtq);
+ INIT_LIST_HEAD(&wm_event.freeq);
+ INIT_WORK(&wm_event.ws, __gdm_wimax_event_send);
+ spin_lock_init(&wm_event.evt_lock);
+ }
+
+ if (wm_event.sock) {
+ wm_event.ref_cnt++;
+ return 0;
+ }
+
+ printk(KERN_ERR "Creating WiMax Event netlink is failed\n");
+ return -1;
+}
+
+static void gdm_wimax_event_exit(void)
+{
+ if (wm_event.sock && --wm_event.ref_cnt == 0) {
+ struct evt_entry *e, *temp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&wm_event.evt_lock, flags);
+
+ list_for_each_entry_safe(e, temp, &wm_event.evtq, list) {
+ list_del(&e->list);
+ free_event_entry(e);
+ }
+ list_for_each_entry_safe(e, temp, &wm_event.freeq, list) {
+ list_del(&e->list);
+ free_event_entry(e);
+ }
+
+ spin_unlock_irqrestore(&wm_event.evt_lock, flags);
+ netlink_exit(wm_event.sock);
+ wm_event.sock = NULL;
+ }
+}
+
+static inline struct evt_entry *alloc_event_entry(void)
+{
+ return kmalloc(sizeof(struct evt_entry), GFP_ATOMIC);
+}
+
+static inline void free_event_entry(struct evt_entry *e)
+{
+ kfree(e);
+}
+
+static struct evt_entry *get_event_entry(void)
+{
+ struct evt_entry *e;
+
+ if (list_empty(&wm_event.freeq))
+ e = alloc_event_entry();
+ else {
+ e = list_entry(wm_event.freeq.next, struct evt_entry, list);
+ list_del(&e->list);
+ }
+
+ return e;
+}
+
+static void put_event_entry(struct evt_entry *e)
+{
+ BUG_ON(!e);
+
+ list_add_tail(&e->list, &wm_event.freeq);
+}
+
+static void __gdm_wimax_event_send(struct work_struct *work)
+{
+ int idx;
+ unsigned long flags;
+ struct evt_entry *e;
+
+ spin_lock_irqsave(&wm_event.evt_lock, flags);
+
+ while (!list_empty(&wm_event.evtq)) {
+ e = list_entry(wm_event.evtq.next, struct evt_entry, list);
+ spin_unlock_irqrestore(&wm_event.evt_lock, flags);
+
+ sscanf(e->dev->name, "wm%d", &idx);
+ netlink_send(wm_event.sock, idx, 0, e->evt_data, e->size);
+
+ spin_lock_irqsave(&wm_event.evt_lock, flags);
+ list_del(&e->list);
+ put_event_entry(e);
+ }
+
+ spin_unlock_irqrestore(&wm_event.evt_lock, flags);
+}
+
+static int gdm_wimax_event_send(struct net_device *dev, char *buf, int size)
+{
+ struct evt_entry *e;
+ unsigned long flags;
+
+ #if defined(DEBUG_HCI)
+ u16 hci_cmd = ((u8)buf[0]<<8) | (u8)buf[1];
+ u16 hci_len = ((u8)buf[2]<<8) | (u8)buf[3];
+ printk(KERN_DEBUG "D=>H: 0x%04x(%d)\n", hci_cmd, hci_len);
+ #endif
+
+ spin_lock_irqsave(&wm_event.evt_lock, flags);
+
+ e = get_event_entry();
+ if (!e) {
+ printk(KERN_ERR "%s: No memory for event\n", __func__);
+ spin_unlock_irqrestore(&wm_event.evt_lock, flags);
+ return -ENOMEM;
+ }
+
+ e->dev = dev;
+ e->size = size;
+ memcpy(e->evt_data, buf, size);
+
+ list_add_tail(&e->list, &wm_event.evtq);
+ spin_unlock_irqrestore(&wm_event.evt_lock, flags);
+
+ schedule_work(&wm_event.ws);
+
+ return 0;
+}
+
+static void tx_complete(void *arg)
+{
+ struct nic *nic = arg;
+
+ if (netif_queue_stopped(nic->netdev))
+ netif_wake_queue(nic->netdev);
+}
+
+int gdm_wimax_send_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ int ret = 0;
+ struct nic *nic = netdev_priv(dev);
+
+ ret = gdm_wimax_send_with_cb(nic, skb->data, skb->len, tx_complete,
+ nic);
+ if (ret == -ENOSPC) {
+ netif_stop_queue(dev);
+ ret = 0;
+ }
+
+ if (ret) {
+ skb_pull(skb, HCI_HEADER_SIZE);
+ return ret;
+ }
+
+ nic->stats.tx_packets++;
+ nic->stats.tx_bytes += skb->len - HCI_HEADER_SIZE;
+ kfree_skb(skb);
+ return ret;
+}
+
+static int gdm_wimax_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ int ret = 0;
+ struct nic *nic = netdev_priv(dev);
+ struct fsm_s *fsm = (struct fsm_s *) nic->sdk_data[SIOC_DATA_FSM].buf;
+
+ #if defined(DEBUG_SDU)
+ dump_eth_packet("TX", skb->data, skb->len);
+ #endif
+
+ ret = gdm_wimax_header(&skb);
+ if (ret < 0) {
+ skb_pull(skb, HCI_HEADER_SIZE);
+ return ret;
+ }
+
+ #if !defined(LOOPBACK_TEST)
+ if (!fsm)
+ printk(KERN_ERR "ASSERTION ERROR: fsm is NULL!!\n");
+ else if (fsm->m_status != M_CONNECTED) {
+ printk(KERN_EMERG "ASSERTION ERROR: Device is NOT ready. status=%d\n",
+ fsm->m_status);
+ kfree_skb(skb);
+ return 0;
+ }
+ #endif
+
+#if defined(CONFIG_WIMAX_GDM72XX_QOS)
+ ret = gdm_qos_send_hci_pkt(skb, dev);
+#else
+ ret = gdm_wimax_send_tx(skb, dev);
+#endif
+ return ret;
+}
+
+static int gdm_wimax_set_config(struct net_device *dev, struct ifmap *map)
+{
+ if (dev->flags & IFF_UP)
+ return -EBUSY;
+
+ return 0;
+}
+
+static void __gdm_wimax_set_mac_addr(struct net_device *dev, char *mac_addr)
+{
+ u16 hci_pkt_buf[32 / sizeof(u16)];
+ u8 *pkt = (u8 *) &hci_pkt_buf[0];
+ struct nic *nic = netdev_priv(dev);
+
+ /* Since dev is registered as a ethernet device,
+ * ether_setup has made dev->addr_len to be ETH_ALEN
+ */
+ memcpy(dev->dev_addr, mac_addr, dev->addr_len);
+
+ /* Let lower layer know of this change by sending
+ * SetInformation(MAC Address)
+ */
+ hci_pkt_buf[0] = H2B(WIMAX_SET_INFO); /* cmd_evt */
+ hci_pkt_buf[1] = H2B(8); /* size */
+ pkt[4] = 0; /* T */
+ pkt[5] = 6; /* L */
+ memcpy(pkt + 6, mac_addr, dev->addr_len); /* V */
+
+ gdm_wimax_send(nic, pkt, HCI_HEADER_SIZE + 8);
+}
+
+/* A driver function */
+static int gdm_wimax_set_mac_addr(struct net_device *dev, void *p)
+{
+ struct sockaddr *addr = p;
+
+ if (netif_running(dev))
+ return -EBUSY;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ __gdm_wimax_set_mac_addr(dev, addr->sa_data);
+
+ return 0;
+}
+
+static struct net_device_stats *gdm_wimax_stats(struct net_device *dev)
+{
+ struct nic *nic = netdev_priv(dev);
+
+ return &nic->stats;
+}
+
+static int gdm_wimax_open(struct net_device *dev)
+{
+ struct nic *nic = netdev_priv(dev);
+ struct fsm_s *fsm = (struct fsm_s *) nic->sdk_data[SIOC_DATA_FSM].buf;
+
+ netif_start_queue(dev);
+
+ if (fsm && fsm->m_status != M_INIT)
+ gdm_wimax_ind_if_updown(dev, 1);
+ return 0;
+}
+
+static int gdm_wimax_close(struct net_device *dev)
+{
+ struct nic *nic = netdev_priv(dev);
+ struct fsm_s *fsm = (struct fsm_s *) nic->sdk_data[SIOC_DATA_FSM].buf;
+
+ netif_stop_queue(dev);
+
+ if (fsm && fsm->m_status != M_INIT)
+ gdm_wimax_ind_if_updown(dev, 0);
+ return 0;
+}
+
+static void kdelete(void **buf)
+{
+ if (buf && *buf) {
+ kfree(*buf);
+ *buf = NULL;
+ }
+}
+
+static int gdm_wimax_ioctl_get_data(struct data_s *dst, struct data_s *src)
+{
+ int size;
+
+ size = dst->size < src->size ? dst->size : src->size;
+
+ dst->size = size;
+ if (src->size) {
+ if (!dst->buf)
+ return -EINVAL;
+ if (copy_to_user(dst->buf, src->buf, size))
+ return -EFAULT;
+ }
+ return 0;
+}
+
+static int gdm_wimax_ioctl_set_data(struct data_s *dst, struct data_s *src)
+{
+ if (!src->size) {
+ dst->size = 0;
+ return 0;
+ }
+
+ if (!src->buf)
+ return -EINVAL;
+
+ if (!(dst->buf && dst->size == src->size)) {
+ kdelete(&dst->buf);
+ dst->buf = kmalloc(src->size, GFP_KERNEL);
+ if (dst->buf == NULL)
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(dst->buf, src->buf, src->size)) {
+ kdelete(&dst->buf);
+ return -EFAULT;
+ }
+ dst->size = src->size;
+ return 0;
+}
+
+static void gdm_wimax_cleanup_ioctl(struct net_device *dev)
+{
+ struct nic *nic = netdev_priv(dev);
+ int i;
+
+ for (i = 0; i < SIOC_DATA_MAX; i++)
+ kdelete(&nic->sdk_data[i].buf);
+}
+
+static void gdm_update_fsm(struct net_device *dev, struct fsm_s *new_fsm)
+{
+ struct nic *nic = netdev_priv(dev);
+ struct fsm_s *cur_fsm =
+ (struct fsm_s *) nic->sdk_data[SIOC_DATA_FSM].buf;
+
+ if (!cur_fsm)
+ return;
+
+ if (cur_fsm->m_status != new_fsm->m_status ||
+ cur_fsm->c_status != new_fsm->c_status) {
+ if (new_fsm->m_status == M_CONNECTED)
+ netif_carrier_on(dev);
+ else if (cur_fsm->m_status == M_CONNECTED) {
+ netif_carrier_off(dev);
+ #if defined(CONFIG_WIMAX_GDM72XX_QOS)
+ gdm_qos_release_list(nic);
+ #endif
+ }
+ gdm_wimax_ind_fsm_update(dev, new_fsm);
+ }
+}
+
+static int gdm_wimax_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct wm_req_s *req = (struct wm_req_s *) ifr;
+ struct nic *nic = netdev_priv(dev);
+ int ret;
+
+ if (cmd != SIOCWMIOCTL)
+ return -EOPNOTSUPP;
+
+ switch (req->cmd) {
+ case SIOCG_DATA:
+ case SIOCS_DATA:
+ if (req->data_id >= SIOC_DATA_MAX) {
+ printk(KERN_ERR
+ "%s error: data-index(%d) is invalid!!\n",
+ __func__, req->data_id);
+ return -EOPNOTSUPP;
+ }
+ if (req->cmd == SIOCG_DATA) {
+ ret = gdm_wimax_ioctl_get_data(&req->data,
+ &nic->sdk_data[req->data_id]);
+ if (ret < 0)
+ return ret;
+ } else if (req->cmd == SIOCS_DATA) {
+ if (req->data_id == SIOC_DATA_FSM) {
+ /*NOTE: gdm_update_fsm should be called
+ before gdm_wimax_ioctl_set_data is called*/
+ gdm_update_fsm(dev,
+ (struct fsm_s *) req->data.buf);
+ }
+ ret = gdm_wimax_ioctl_set_data(
+ &nic->sdk_data[req->data_id], &req->data);
+ if (ret < 0)
+ return ret;
+ }
+ break;
+ default:
+ printk(KERN_ERR "%s: %x unknown ioctl\n", __func__, cmd);
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static void gdm_wimax_prepare_device(struct net_device *dev)
+{
+ struct nic *nic = netdev_priv(dev);
+ u16 buf[32 / sizeof(u16)];
+ struct hci_s *hci = (struct hci_s *) buf;
+ u16 len = 0;
+ u32 val = 0;
+
+ #define BIT_MULTI_CS 0
+ #define BIT_WIMAX 1
+ #define BIT_QOS 2
+ #define BIT_AGGREGATION 3
+
+ /* GetInformation mac address */
+ len = 0;
+ hci->cmd_evt = H2B(WIMAX_GET_INFO);
+ hci->data[len++] = TLV_T(T_MAC_ADDRESS);
+ hci->length = H2B(len);
+ gdm_wimax_send(nic, hci, HCI_HEADER_SIZE+len);
+
+ val = (1<<BIT_WIMAX) | (1<<BIT_MULTI_CS);
+ #if defined(CONFIG_WIMAX_GDM72XX_QOS)
+ val |= (1<<BIT_QOS);
+ #endif
+ #if defined(CONFIG_WIMAX_GDM72XX_WIMAX2)
+ val |= (1<<BIT_AGGREGATION);
+ #endif
+
+ /* Set capability */
+ len = 0;
+ hci->cmd_evt = H2B(WIMAX_SET_INFO);
+ hci->data[len++] = TLV_T(T_CAPABILITY);
+ hci->data[len++] = TLV_L(T_CAPABILITY);
+ val = DH2B(val);
+ memcpy(&hci->data[len], &val, TLV_L(T_CAPABILITY));
+ len += TLV_L(T_CAPABILITY);
+ hci->length = H2B(len);
+ gdm_wimax_send(nic, hci, HCI_HEADER_SIZE+len);
+
+ printk(KERN_INFO "GDM WiMax Set CAPABILITY: 0x%08X\n", DB2H(val));
+}
+
+static int gdm_wimax_hci_get_tlv(u8 *buf, u8 *T, u16 *L, u8 **V)
+{
+ #define __U82U16(b) ((u16)((u8 *)(b))[0] | ((u16)((u8 *)(b))[1] << 8))
+ int next_pos;
+
+ *T = buf[0];
+ if (buf[1] == 0x82) {
+ *L = B2H(__U82U16(&buf[2]));
+ next_pos = 1/*type*/+3/*len*/;
+ } else {
+ *L = buf[1];
+ next_pos = 1/*type*/+1/*len*/;
+ }
+ *V = &buf[next_pos];
+
+ next_pos += *L/*length of val*/;
+ return next_pos;
+}
+
+static int gdm_wimax_get_prepared_info(struct net_device *dev, char *buf,
+ int len)
+{
+ u8 T, *V;
+ u16 L;
+ u16 cmd_evt, cmd_len;
+ int pos = HCI_HEADER_SIZE;
+
+ cmd_evt = B2H(*(u16 *)&buf[0]);
+ cmd_len = B2H(*(u16 *)&buf[2]);
+
+ if (len < cmd_len + HCI_HEADER_SIZE) {
+ printk(KERN_ERR "%s: invalid length [%d/%d]\n", __func__,
+ cmd_len + HCI_HEADER_SIZE, len);
+ return -1;
+ }
+
+ if (cmd_evt == WIMAX_GET_INFO_RESULT) {
+ if (cmd_len < 2) {
+ printk(KERN_ERR "%s: len is too short [%x/%d]\n",
+ __func__, cmd_evt, len);
+ return -1;
+ }
+
+ pos += gdm_wimax_hci_get_tlv(&buf[pos], &T, &L, &V);
+ if (T == TLV_T(T_MAC_ADDRESS)) {
+ if (L != dev->addr_len) {
+ printk(KERN_ERR
+ "%s Invalid inofrmation result T/L "
+ "[%x/%d]\n", __func__, T, L);
+ return -1;
+ }
+ printk(KERN_INFO
+ "MAC change [%02x:%02x:%02x:%02x:%02x:%02x]"
+ "->[%02x:%02x:%02x:%02x:%02x:%02x]\n",
+ dev->dev_addr[0], dev->dev_addr[1],
+ dev->dev_addr[2], dev->dev_addr[3],
+ dev->dev_addr[4], dev->dev_addr[5],
+ V[0], V[1], V[2], V[3], V[4], V[5]);
+ memcpy(dev->dev_addr, V, dev->addr_len);
+ return 1;
+ }
+ }
+
+ gdm_wimax_event_send(dev, buf, len);
+ return 0;
+}
+
+static void gdm_wimax_netif_rx(struct net_device *dev, char *buf, int len)
+{
+ struct nic *nic = netdev_priv(dev);
+ struct sk_buff *skb;
+ int ret;
+
+ #if defined(DEBUG_SDU)
+ dump_eth_packet("RX", buf, len);
+ #endif
+
+ skb = dev_alloc_skb(len + 2);
+ if (!skb) {
+ printk(KERN_ERR "%s: dev_alloc_skb failed!\n", __func__);
+ return;
+ }
+ skb_reserve(skb, 2);
+
+ nic->stats.rx_packets++;
+ nic->stats.rx_bytes += len;
+
+ memcpy(skb_put(skb, len), buf, len);
+
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev); /* what will happen? */
+
+ ret = in_interrupt() ? netif_rx(skb) : netif_rx_ni(skb);
+ if (ret == NET_RX_DROP)
+ printk(KERN_ERR "%s skb dropped\n", __func__);
+}
+
+static void gdm_wimax_transmit_aggr_pkt(struct net_device *dev, char *buf,
+ int len)
+{
+ #define HCI_PADDING_BYTE 4
+ #define HCI_RESERVED_BYTE 4
+ struct hci_s *hci;
+ int length;
+
+ while (len > 0) {
+ hci = (struct hci_s *) buf;
+
+ if (B2H(hci->cmd_evt) != WIMAX_RX_SDU) {
+ printk(KERN_ERR "Wrong cmd_evt(0x%04X)\n",
+ B2H(hci->cmd_evt));
+ break;
+ }
+
+ length = B2H(hci->length);
+ gdm_wimax_netif_rx(dev, hci->data, length);
+
+ if (length & 0x3) {
+ /* Add padding size */
+ length += HCI_PADDING_BYTE - (length & 0x3);
+ }
+
+ length += HCI_HEADER_SIZE + HCI_RESERVED_BYTE;
+ len -= length;
+ buf += length;
+ }
+}
+
+static void gdm_wimax_transmit_pkt(struct net_device *dev, char *buf, int len)
+{
+ #if defined(CONFIG_WIMAX_GDM72XX_QOS)
+ struct nic *nic = netdev_priv(dev);
+ #endif
+ u16 cmd_evt, cmd_len;
+
+ /* This code is added for certain rx packet to be ignored. */
+ if (len == 0)
+ return;
+
+ cmd_evt = B2H(*(u16 *)&buf[0]);
+ cmd_len = B2H(*(u16 *)&buf[2]);
+
+ if (len < cmd_len + HCI_HEADER_SIZE) {
+ if (len)
+ printk(KERN_ERR "%s: invalid length [%d/%d]\n",
+ __func__, cmd_len + HCI_HEADER_SIZE, len);
+ return;
+ }
+
+ switch (cmd_evt) {
+ case WIMAX_RX_SDU_AGGR:
+ gdm_wimax_transmit_aggr_pkt(dev, &buf[HCI_HEADER_SIZE],
+ cmd_len);
+ break;
+ case WIMAX_RX_SDU:
+ gdm_wimax_netif_rx(dev, &buf[HCI_HEADER_SIZE], cmd_len);
+ break;
+ #if defined(CONFIG_WIMAX_GDM72XX_QOS)
+ case WIMAX_EVT_MODEM_REPORT:
+ gdm_recv_qos_hci_packet(nic, buf, len);
+ break;
+ #endif
+ case WIMAX_SDU_TX_FLOW:
+ if (buf[4] == 0) {
+ if (!netif_queue_stopped(dev))
+ netif_stop_queue(dev);
+ } else if (buf[4] == 1) {
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+ }
+ break;
+ default:
+ gdm_wimax_event_send(dev, buf, len);
+ break;
+ }
+}
+
+static void gdm_wimax_ind_fsm_update(struct net_device *dev, struct fsm_s *fsm)
+{
+ u16 buf[32 / sizeof(u16)];
+ u8 *hci_pkt_buf = (u8 *)&buf[0];
+
+ /* Indicate updating fsm */
+ buf[0] = H2B(WIMAX_FSM_UPDATE);
+ buf[1] = H2B(sizeof(struct fsm_s));
+ memcpy(&hci_pkt_buf[HCI_HEADER_SIZE], fsm, sizeof(struct fsm_s));
+
+ gdm_wimax_event_send(dev, hci_pkt_buf,
+ HCI_HEADER_SIZE + sizeof(struct fsm_s));
+}
+
+static void gdm_wimax_ind_if_updown(struct net_device *dev, int if_up)
+{
+ u16 buf[32 / sizeof(u16)];
+ struct hci_s *hci = (struct hci_s *) buf;
+ unsigned char up_down;
+
+ up_down = if_up ? WIMAX_IF_UP : WIMAX_IF_DOWN;
+
+ /* Indicate updating fsm */
+ hci->cmd_evt = H2B(WIMAX_IF_UPDOWN);
+ hci->length = H2B(sizeof(up_down));
+ hci->data[0] = up_down;
+
+ gdm_wimax_event_send(dev, (char *)hci, HCI_HEADER_SIZE+sizeof(up_down));
+}
+
+static void rx_complete(void *arg, void *data, int len)
+{
+ struct nic *nic = arg;
+
+ gdm_wimax_transmit_pkt(nic->netdev, data, len);
+ gdm_wimax_rcv_with_cb(nic, rx_complete, nic);
+}
+
+static void prepare_rx_complete(void *arg, void *data, int len)
+{
+ struct nic *nic = arg;
+ int ret;
+
+ ret = gdm_wimax_get_prepared_info(nic->netdev, data, len);
+ if (ret == 1)
+ gdm_wimax_rcv_with_cb(nic, rx_complete, nic);
+ else {
+ if (ret < 0)
+ printk(KERN_ERR "get_prepared_info failed(%d)\n", ret);
+ gdm_wimax_rcv_with_cb(nic, prepare_rx_complete, nic);
+ #if 0
+ /* Re-prepare WiMax device */
+ gdm_wimax_prepare_device(nic->netdev);
+ #endif
+ }
+}
+
+static void start_rx_proc(struct nic *nic)
+{
+ gdm_wimax_rcv_with_cb(nic, prepare_rx_complete, nic);
+}
+
+static struct net_device_ops gdm_netdev_ops = {
+ .ndo_open = gdm_wimax_open,
+ .ndo_stop = gdm_wimax_close,
+ .ndo_set_config = gdm_wimax_set_config,
+ .ndo_start_xmit = gdm_wimax_tx,
+ .ndo_get_stats = gdm_wimax_stats,
+ .ndo_set_mac_address = gdm_wimax_set_mac_addr,
+ .ndo_do_ioctl = gdm_wimax_ioctl,
+};
+
+int register_wimax_device(struct phy_dev *phy_dev, struct device *pdev)
+{
+ struct nic *nic = NULL;
+ struct net_device *dev;
+ int ret;
+
+ dev = (struct net_device *)alloc_netdev(sizeof(*nic),
+ "wm%d", ether_setup);
+
+ if (dev == NULL) {
+ printk(KERN_ERR "alloc_etherdev failed\n");
+ return -ENOMEM;
+ }
+
+ SET_NETDEV_DEV(dev, pdev);
+ dev->mtu = 1400;
+ dev->netdev_ops = &gdm_netdev_ops;
+ dev->flags &= ~IFF_MULTICAST;
+ memcpy(dev->dev_addr, gdm_wimax_macaddr, sizeof(gdm_wimax_macaddr));
+
+ nic = netdev_priv(dev);
+ memset(nic, 0, sizeof(*nic));
+
+ nic->netdev = dev;
+ nic->phy_dev = phy_dev;
+ phy_dev->netdev = dev;
+
+ /* event socket init */
+ ret = gdm_wimax_event_init();
+ if (ret < 0) {
+ printk(KERN_ERR "Cannot create event.\n");
+ goto cleanup;
+ }
+
+ ret = register_netdev(dev);
+ if (ret)
+ goto cleanup;
+
+ #if defined(LOOPBACK_TEST)
+ netif_start_queue(dev);
+ netif_carrier_on(dev);
+ #else
+ netif_carrier_off(dev);
+ #endif
+
+#ifdef CONFIG_WIMAX_GDM72XX_QOS
+ gdm_qos_init(nic);
+#endif
+
+ start_rx_proc(nic);
+
+ /* Prepare WiMax device */
+ gdm_wimax_prepare_device(dev);
+
+ return 0;
+
+cleanup:
+ printk(KERN_ERR "register_netdev failed\n");
+ free_netdev(dev);
+ return ret;
+}
+
+void unregister_wimax_device(struct phy_dev *phy_dev)
+{
+ struct nic *nic = netdev_priv(phy_dev->netdev);
+ struct fsm_s *fsm = (struct fsm_s *) nic->sdk_data[SIOC_DATA_FSM].buf;
+
+ if (fsm)
+ fsm->m_status = M_INIT;
+ unregister_netdev(nic->netdev);
+
+ gdm_wimax_event_exit();
+
+#if defined(CONFIG_WIMAX_GDM72XX_QOS)
+ gdm_qos_release_list(nic);
+#endif
+
+ gdm_wimax_cleanup_ioctl(phy_dev->netdev);
+
+ free_netdev(nic->netdev);
+}
diff --git a/drivers/staging/gdm72xx/gdm_wimax.h b/drivers/staging/gdm72xx/gdm_wimax.h
new file mode 100644
index 000000000000..023e6492e33d
--- /dev/null
+++ b/drivers/staging/gdm72xx/gdm_wimax.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __GDM_WIMAX_H__
+#define __GDM_WIMAX_H__
+
+#include <linux/netdevice.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include "wm_ioctl.h"
+#if defined(CONFIG_WIMAX_GDM72XX_QOS)
+#include "gdm_qos.h"
+#endif
+
+#define DRIVER_VERSION "3.2.3"
+
+/*#define ETH_P_IP 0x0800 */
+/*#define ETH_P_ARP 0x0806 */
+/*#define ETH_P_IPV6 0x86DD */
+
+#define H2L(x) __cpu_to_le16(x)
+#define L2H(x) __le16_to_cpu(x)
+#define DH2L(x) __cpu_to_le32(x)
+#define DL2H(x) __le32_to_cpu(x)
+
+#define H2B(x) __cpu_to_be16(x)
+#define B2H(x) __be16_to_cpu(x)
+#define DH2B(x) __cpu_to_be32(x)
+#define DB2H(x) __be32_to_cpu(x)
+
+struct phy_dev {
+ void *priv_dev;
+ struct net_device *netdev;
+
+ int (*send_func)(void *priv_dev, void *data, int len,
+ void (*cb)(void *cb_data), void *cb_data);
+ int (*rcv_func)(void *priv_dev,
+ void (*cb)(void *cb_data, void *data, int len),
+ void *cb_data);
+};
+
+struct nic {
+ struct net_device *netdev;
+ struct phy_dev *phy_dev;
+
+ struct net_device_stats stats;
+
+ struct data_s sdk_data[SIOC_DATA_MAX];
+
+#if defined(CONFIG_WIMAX_GDM72XX_QOS)
+ struct qos_cb_s qos;
+#endif
+
+};
+
+
+#if 0
+#define dprintk(fmt, args ...) printk(KERN_DEBUG " [GDM] " fmt, ## args)
+#else
+#define dprintk(...)
+#endif
+
+/*#define DEBUG_SDU */
+#if defined(DEBUG_SDU)
+#define DUMP_SDU_ALL (1<<0)
+#define DUMP_SDU_ARP (1<<1)
+#define DUMP_SDU_IP (1<<2)
+#define DUMP_SDU_IP_TCP (1<<8)
+#define DUMP_SDU_IP_UDP (1<<9)
+#define DUMP_SDU_IP_ICMP (1<<10)
+#define DUMP_PACKET (DUMP_SDU_ALL)
+#endif
+
+/*#define DEBUG_HCI */
+
+/*#define LOOPBACK_TEST */
+
+extern int register_wimax_device(struct phy_dev *phy_dev, struct device *pdev);
+extern int gdm_wimax_send_tx(struct sk_buff *skb, struct net_device *dev);
+extern void unregister_wimax_device(struct phy_dev *phy_dev);
+
+#endif
diff --git a/drivers/staging/gdm72xx/hci.h b/drivers/staging/gdm72xx/hci.h
new file mode 100644
index 000000000000..0e0676622f1d
--- /dev/null
+++ b/drivers/staging/gdm72xx/hci.h
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 HCI_H_20080801
+#define HCI_H_20080801
+
+#define HCI_HEADER_SIZE 4
+#define HCI_VALUE_OFFS (HCI_HEADER_SIZE)
+#define HCI_MAX_PACKET 2048
+#define HCI_MAX_PARAM (HCI_MAX_PACKET-HCI_HEADER_SIZE)
+#define HCI_MAX_TLV 32
+
+/* CMD-EVT */
+
+/* Category 0 */
+#define WIMAX_RESET 0x0000
+#define WIMAX_SET_INFO 0x0001
+#define WIMAX_GET_INFO 0x0002
+#define WIMAX_GET_INFO_RESULT 0x8003
+#define WIMAX_RADIO_OFF 0x0004
+#define WIMAX_RADIO_ON 0x0006
+#define WIMAX_WIMAX_RESET 0x0007 /* Is this still here */
+
+/* Category 1 */
+#define WIMAX_NET_ENTRY 0x0100
+#define WIMAX_NET_DISCONN 0x0102
+#define WIMAX_ENTER_SLEEP 0x0103
+#define WIMAX_EXIT_SLEEP 0x0104
+#define WIMAX_ENTER_IDLE 0x0105
+#define WIMAX_EXIT_IDLE 0x0106
+#define WIMAX_MODE_CHANGE 0x8108
+#define WIMAX_HANDOVER 0x8109 /* obsolete */
+
+#define WIMAX_SCAN 0x010d
+#define WIMAX_SCAN_COMPLETE 0x810e
+#define WIMAX_SCAN_RESULT 0x810f
+
+#define WIMAX_CONNECT 0x0110
+#define WIMAX_CONNECT_START 0x8111
+#define WIMAX_CONNECT_COMPLETE 0x8112
+#define WIMAX_ASSOC_START 0x8113
+#define WIMAX_ASSOC_COMPLETE 0x8114
+#define WIMAX_DISCONN_IND 0x8115
+#define WIMAX_ENTRY_IND 0x8116
+#define WIMAX_HO_START 0x8117
+#define WIMAX_HO_COMPLETE 0x8118
+#define WIMAX_RADIO_STATE_IND 0x8119
+#define WIMAX_IP_RENEW_IND 0x811a
+
+#define WIMAX_DISCOVER_NSP 0x011d
+#define WIMAX_DISCOVER_NSP_RESULT 0x811e
+
+#define WIMAX_SDU_TX_FLOW 0x8125
+
+/* Category 2 */
+#define WIMAX_TX_EAP 0x0200
+#define WIMAX_RX_EAP 0x8201
+#define WIMAX_TX_SDU 0x0202
+#define WIMAX_RX_SDU 0x8203
+#define WIMAX_RX_SDU_AGGR 0x8204
+#define WIMAX_TX_SDU_AGGR 0x0205
+
+/* Category 3 */
+#define WIMAX_DM_CMD 0x030a
+#define WIMAX_DM_RSP 0x830b
+
+#define WIMAX_CLI_CMD 0x030c
+#define WIMAX_CLI_RSP 0x830d
+
+#define WIMAX_DL_IMAGE 0x0310
+#define WIMAX_DL_IMAGE_STATUS 0x8311
+#define WIMAX_UL_IMAGE 0x0312
+#define WIMAX_UL_IMAGE_RESULT 0x8313
+#define WIMAX_UL_IMAGE_STATUS 0x0314
+
+#define WIMAX_EVT_MODEM_REPORT 0x8325
+
+/* Category 0xF */
+#define WIMAX_FSM_UPDATE 0x8F01
+#define WIMAX_IF_UPDOWN 0x8F02
+ #define WIMAX_IF_UP 1
+ #define WIMAX_IF_DOWN 2
+
+/* WIMAX mode */
+#define W_NULL 0
+#define W_STANDBY 1
+#define W_OOZ 2
+#define W_AWAKE 3
+#define W_IDLE 4
+#define W_SLEEP 5
+#define W_WAIT 6
+
+#define W_NET_ENTRY_RNG 0x80
+#define W_NET_ENTRY_SBC 0x81
+#define W_NET_ENTRY_PKM 0x82
+#define W_NET_ENTRY_REG 0x83
+#define W_NET_ENTRY_DSX 0x84
+
+#define W_NET_ENTRY_RNG_FAIL 0x1100100
+#define W_NET_ENTRY_SBC_FAIL 0x1100200
+#define W_NET_ENTRY_PKM_FAIL 0x1102000
+#define W_NET_ENTRY_REG_FAIL 0x1103000
+#define W_NET_ENTRY_DSX_FAIL 0x1104000
+
+/* Scan Type */
+#define W_SCAN_ALL_CHANNEL 0
+#define W_SCAN_ALL_SUBSCRIPTION 1
+#define W_SCAN_SPECIFIED_SUBSCRIPTION 2
+
+/*
+ * TLV
+ *
+ * [31:31] indicates the type is composite.
+ * [30:16] is the length of the type. 0 length means length is variable.
+ * [15:0] is the actual type.
+ *
+ */
+#define TLV_L(x) (((x) >> 16) & 0xff)
+#define TLV_T(x) ((x) & 0xff)
+#define TLV_COMPOSITE(x) ((x) >> 31)
+
+/* GENERAL */
+#define T_MAC_ADDRESS (0x00 | (6 << 16))
+#define T_BSID (0x01 | (6 << 16))
+#define T_MSK (0x02 | (64 << 16))
+#define T_RSSI_THRSHLD (0x03 | (1 << 16))
+#define T_FREQUENCY (0x04 | (4 << 16))
+#define T_CONN_CS_TYPE (0x05 | (1 << 16))
+#define T_HOST_IP_VER (0x06 | (1 << 16))
+#define T_STBY_SCAN_INTERVAL (0x07 | (4 << 16))
+#define T_OOZ_SCAN_INTERVAL (0x08 | (4 << 16))
+#define T_IMEI (0x09 | (8 << 16))
+#define T_PID (0x0a | (12 << 16))
+
+#define T_CAPABILITY (0x1a | (4 << 16))
+#define T_RELEASE_NUMBER (0x1b | (4 << 16))
+#define T_DRIVER_REVISION (0x1c | (4 << 16))
+#define T_FW_REVISION (0x1d | (4 << 16))
+#define T_MAC_HW_REVISION (0x1e | (4 << 16))
+#define T_PHY_HW_REVISION (0x1f | (4 << 16))
+
+/* HANDOVER */
+#define T_SCAN_INTERVAL (0x20 | (1 << 16))
+
+#define T_RSC_RETAIN_TIME (0x2f | (2 << 16))
+
+/* SLEEP */
+#define T_TYPE1_ISW (0x40 | (1 << 16))
+
+#define T_SLP_START_TO (0x4a | (2 << 16))
+
+/* IDLE */
+#define T_IDLE_MODE_TO (0x50 | (2 << 16))
+
+#define T_IDLE_START_TO (0x54 | (2 << 16))
+
+/* MONITOR */
+#define T_RSSI (0x60 | (1 << 16))
+#define T_CINR (0x61 | (1 << 16))
+#define T_TX_POWER (0x6a | (1 << 16))
+#define T_CUR_FREQ (0x7f | (4 << 16))
+
+
+/* WIMAX */
+#define T_MAX_SUBSCRIPTION (0xa1 | (1 << 16))
+#define T_MAX_SF (0xa2 | (1 << 16))
+#define T_PHY_TYPE (0xa3 | (1 << 16))
+#define T_PKM (0xa4 | (1 << 16))
+#define T_AUTH_POLICY (0xa5 | (1 << 16))
+#define T_CS_TYPE (0xa6 | (2 << 16))
+#define T_VENDOR_NAME (0xa7 | (0 << 16))
+#define T_MOD_NAME (0xa8 | (0 << 16))
+#define T_PACKET_FILTER (0xa9 | (1 << 16))
+#define T_NSP_CHANGE_COUNT (0xaa | (4 << 16))
+#define T_RADIO_STATE (0xab | (1 << 16))
+#define T_URI_CONTACT_TYPE (0xac | (1 << 16))
+#define T_URI_TEXT (0xad | (0 << 16))
+#define T_URI (0xae | (0 << 16))
+#define T_ENABLE_AUTH (0xaf | (1 << 16))
+#define T_TIMEOUT (0xb0 | (2 << 16))
+#define T_RUN_MODE (0xb1 | (1 << 16))
+#define T_OMADMT_VER (0xb2 | (4 << 16))
+/* This is measured in seconds from 00:00:00 GMT January 1, 1970. */
+#define T_RTC_TIME (0xb3 | (4 << 16))
+#define T_CERT_STATUS (0xb4 | (4 << 16))
+#define T_CERT_MASK (0xb5 | (4 << 16))
+#define T_EMSK (0xb6 | (64 << 16))
+
+/* Subscription TLV */
+#define T_SUBSCRIPTION_LIST (0xd1 | (0 << 16) | (1 << 31))
+#define T_H_NSPID (0xd2 | (3 << 16))
+#define T_NSP_NAME (0xd3 | (0 << 16))
+#define T_SUBSCRIPTION_NAME (0xd4 | (0 << 16))
+#define T_SUBSCRIPTION_FLAG (0xd5 | (2 << 16))
+#define T_V_NSPID (0xd6 | (3 << 16))
+#define T_NAP_ID (0xd7 | (3 << 16))
+#define T_PREAMBLES (0xd8 | (15 << 16))
+#define T_BW (0xd9 | (4 << 16))
+#define T_FFTSIZE (0xda | (4 << 16))
+#define T_DUPLEX_MODE (0xdb | (4 << 16))
+
+struct hci_s {
+ unsigned short cmd_evt;
+ unsigned short length;
+ unsigned char data[0];
+} __packed;
+
+#endif
diff --git a/drivers/staging/gdm72xx/netlink_k.c b/drivers/staging/gdm72xx/netlink_k.c
new file mode 100644
index 000000000000..292af0f7f451
--- /dev/null
+++ b/drivers/staging/gdm72xx/netlink_k.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <linux/netlink.h>
+#include <asm/byteorder.h>
+#include <net/sock.h>
+
+#if !defined(NLMSG_HDRLEN)
+#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#endif
+
+#define ND_MAX_GROUP 30
+#define ND_IFINDEX_LEN sizeof(int)
+#define ND_NLMSG_SPACE(len) (NLMSG_SPACE(len) + ND_IFINDEX_LEN)
+#define ND_NLMSG_DATA(nlh) \
+ ((void *)((char *)NLMSG_DATA(nlh) + ND_IFINDEX_LEN))
+#define ND_NLMSG_S_LEN(len) (len+ND_IFINDEX_LEN)
+#define ND_NLMSG_R_LEN(nlh) (nlh->nlmsg_len-ND_IFINDEX_LEN)
+#define ND_NLMSG_IFIDX(nlh) NLMSG_DATA(nlh)
+#define ND_MAX_MSG_LEN 8096
+
+#if defined(DEFINE_MUTEX)
+static DEFINE_MUTEX(netlink_mutex);
+#else
+static struct semaphore netlink_mutex;
+#define mutex_lock(x) down(x)
+#define mutex_unlock(x) up(x)
+#endif
+
+static void (*rcv_cb)(struct net_device *dev, u16 type, void *msg, int len);
+
+static void netlink_rcv_cb(struct sk_buff *skb)
+{
+ struct nlmsghdr *nlh;
+ struct net_device *dev;
+ u32 mlen;
+ void *msg;
+ int ifindex;
+
+ if (skb->len >= NLMSG_SPACE(0)) {
+ nlh = (struct nlmsghdr *)skb->data;
+
+ if (skb->len < nlh->nlmsg_len ||
+ nlh->nlmsg_len > ND_MAX_MSG_LEN) {
+ printk(KERN_ERR "Invalid length (%d,%d)\n", skb->len,
+ nlh->nlmsg_len);
+ return;
+ }
+
+ memcpy(&ifindex, ND_NLMSG_IFIDX(nlh), ND_IFINDEX_LEN);
+ msg = ND_NLMSG_DATA(nlh);
+ mlen = ND_NLMSG_R_LEN(nlh);
+
+ if (rcv_cb) {
+ dev = dev_get_by_index(&init_net, ifindex);
+ if (dev) {
+ rcv_cb(dev, nlh->nlmsg_type, msg, mlen);
+ dev_put(dev);
+ } else
+ printk(KERN_ERR "dev_get_by_index(%d) "
+ "is not found.\n", ifindex);
+ } else
+ printk(KERN_ERR "Unregistered Callback\n");
+ }
+}
+
+static void netlink_rcv(struct sk_buff *skb)
+{
+ mutex_lock(&netlink_mutex);
+ netlink_rcv_cb(skb);
+ mutex_unlock(&netlink_mutex);
+}
+
+struct sock *netlink_init(int unit, void (*cb)(struct net_device *dev, u16 type,
+ void *msg, int len))
+{
+ struct sock *sock;
+
+#if !defined(DEFINE_MUTEX)
+ init_MUTEX(&netlink_mutex);
+#endif
+
+ sock = netlink_kernel_create(&init_net, unit, 0, netlink_rcv, NULL,
+ THIS_MODULE);
+
+ if (sock)
+ rcv_cb = cb;
+
+ return sock;
+}
+
+void netlink_exit(struct sock *sock)
+{
+ sock_release(sock->sk_socket);
+}
+
+int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len)
+{
+ static u32 seq;
+ struct sk_buff *skb = NULL;
+ struct nlmsghdr *nlh;
+ int ret = 0;
+
+ if (group > ND_MAX_GROUP) {
+ printk(KERN_ERR "Group %d is invalied.\n", group);
+ printk(KERN_ERR "Valid group is 0 ~ %d.\n", ND_MAX_GROUP);
+ return -EINVAL;
+ }
+
+ skb = alloc_skb(NLMSG_SPACE(len), GFP_ATOMIC);
+ if (!skb) {
+ printk(KERN_ERR "netlink_broadcast ret=%d\n", ret);
+ return -ENOMEM;
+ }
+
+ seq++;
+ nlh = NLMSG_PUT(skb, 0, seq, type, len);
+ memcpy(NLMSG_DATA(nlh), msg, len);
+
+ NETLINK_CB(skb).pid = 0;
+ NETLINK_CB(skb).dst_group = 0;
+
+ ret = netlink_broadcast(sock, skb, 0, group+1, GFP_ATOMIC);
+
+ if (!ret)
+ return len;
+ else {
+ if (ret != -ESRCH) {
+ printk(KERN_ERR "netlink_broadcast g=%d, t=%d, l=%d, r=%d\n",
+ group, type, len, ret);
+ }
+ ret = 0;
+ }
+
+nlmsg_failure:
+ return ret;
+}
diff --git a/drivers/staging/gdm72xx/netlink_k.h b/drivers/staging/gdm72xx/netlink_k.h
new file mode 100644
index 000000000000..1dffaa6156e4
--- /dev/null
+++ b/drivers/staging/gdm72xx/netlink_k.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#if !defined(NETLINK_H_20081202)
+#define NETLINK_H_20081202
+#include <linux/netdevice.h>
+#include <net/sock.h>
+
+struct sock *netlink_init(int unit,
+ void (*cb)(struct net_device *dev, u16 type, void *msg, int len));
+void netlink_exit(struct sock *sock);
+int netlink_send(struct sock *sock, int group, u16 type, void *msg, int len);
+
+#endif
diff --git a/drivers/staging/gdm72xx/sdio_boot.c b/drivers/staging/gdm72xx/sdio_boot.c
new file mode 100644
index 000000000000..6ff4dc372522
--- /dev/null
+++ b/drivers/staging/gdm72xx/sdio_boot.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "gdm_sdio.h"
+
+#define TYPE_A_HEADER_SIZE 4
+#define TYPE_A_LOOKAHEAD_SIZE 16
+#define YMEM0_SIZE 0x8000 /* 32kbytes */
+#define DOWNLOAD_SIZE (YMEM0_SIZE - TYPE_A_HEADER_SIZE)
+
+#define KRN_PATH "/lib/firmware/gdm72xx/gdmskrn.bin"
+#define RFS_PATH "/lib/firmware/gdm72xx/gdmsrfs.bin"
+
+static u8 *tx_buf;
+
+static int ack_ready(struct sdio_func *func)
+{
+ unsigned long start = jiffies;
+ u8 val;
+ int ret;
+
+ while ((jiffies - start) < HZ) {
+ val = sdio_readb(func, 0x13, &ret);
+ if (val & 0x01)
+ return 1;
+ schedule();
+ }
+
+ return 0;
+}
+
+static int download_image(struct sdio_func *func, char *img_name)
+{
+ int ret = 0, len, size, pno;
+ struct file *filp = NULL;
+ struct inode *inode = NULL;
+ u8 *buf = tx_buf;
+ loff_t pos = 0;
+
+ filp = filp_open(img_name, O_RDONLY | O_LARGEFILE, 0);
+ if (IS_ERR(filp)) {
+ printk(KERN_ERR "Can't find %s.\n", img_name);
+ return -ENOENT;
+ }
+
+ if (filp->f_dentry)
+ inode = filp->f_dentry->d_inode;
+ if (!inode || !S_ISREG(inode->i_mode)) {
+ printk(KERN_ERR "Invalid file type: %s\n", img_name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ size = i_size_read(inode->i_mapping->host);
+ if (size <= 0) {
+ printk(KERN_ERR "Unable to find file size: %s\n", img_name);
+ ret = size;
+ goto out;
+ }
+
+ pno = 0;
+ while ((len = filp->f_op->read(filp, buf + TYPE_A_HEADER_SIZE,
+ DOWNLOAD_SIZE, &pos))) {
+ if (len < 0) {
+ ret = -1;
+ goto out;
+ }
+
+ buf[0] = len & 0xff;
+ buf[1] = (len >> 8) & 0xff;
+ buf[2] = (len >> 16) & 0xff;
+
+ if (pos >= size) /* The last packet */
+ buf[3] = 2;
+ else
+ buf[3] = 0;
+
+ ret = sdio_memcpy_toio(func, 0, buf, len + TYPE_A_HEADER_SIZE);
+ if (ret < 0) {
+ printk(KERN_ERR "gdmwm: send image error: "
+ "packet number = %d ret = %d\n", pno, ret);
+ goto out;
+ }
+ if (buf[3] == 2) /* The last packet */
+ break;
+ if (!ack_ready(func)) {
+ ret = -EIO;
+ printk(KERN_ERR "gdmwm: Ack is not ready.\n");
+ goto out;
+ }
+ ret = sdio_memcpy_fromio(func, buf, 0, TYPE_A_LOOKAHEAD_SIZE);
+ if (ret < 0) {
+ printk(KERN_ERR "gdmwm: receive ack error: "
+ "packet number = %d ret = %d\n", pno, ret);
+ goto out;
+ }
+ sdio_writeb(func, 0x01, 0x13, &ret);
+ sdio_writeb(func, 0x00, 0x10, &ret); /* PCRRT */
+
+ pno++;
+ }
+out:
+ filp_close(filp, current->files);
+ return ret;
+}
+
+int sdio_boot(struct sdio_func *func)
+{
+ static mm_segment_t fs;
+ int ret;
+
+ tx_buf = kmalloc(YMEM0_SIZE, GFP_KERNEL);
+ if (tx_buf == NULL) {
+ printk(KERN_ERR "Error: kmalloc: %s %d\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ fs = get_fs();
+ set_fs(get_ds());
+
+ ret = download_image(func, KRN_PATH);
+ if (ret)
+ goto restore_fs;
+ printk(KERN_INFO "GCT: Kernel download success.\n");
+
+ ret = download_image(func, RFS_PATH);
+ if (ret)
+ goto restore_fs;
+ printk(KERN_INFO "GCT: Filesystem download success.\n");
+
+restore_fs:
+ set_fs(fs);
+ kfree(tx_buf);
+ return ret;
+}
diff --git a/drivers/staging/gdm72xx/sdio_boot.h b/drivers/staging/gdm72xx/sdio_boot.h
new file mode 100644
index 000000000000..373ac28063c6
--- /dev/null
+++ b/drivers/staging/gdm72xx/sdio_boot.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __SDIO_BOOT_H__
+#define __SDIO_BOOT_H__
+
+struct sdio_func;
+
+extern int sdio_boot(struct sdio_func *func);
+
+#endif /* __SDIO_BOOT_H__ */
diff --git a/drivers/staging/gdm72xx/usb_boot.c b/drivers/staging/gdm72xx/usb_boot.c
new file mode 100644
index 000000000000..5a0e030220dc
--- /dev/null
+++ b/drivers/staging/gdm72xx/usb_boot.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/usb.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+
+#include <asm/byteorder.h>
+#include "gdm_usb.h"
+#include "usb_boot.h"
+
+#define DN_KERNEL_MAGIC_NUMBER 0x10760001
+#define DN_ROOTFS_MAGIC_NUMBER 0x10760002
+
+#define DOWNLOAD_SIZE 1024
+
+#define DH2B(x) __cpu_to_be32(x)
+#define DL2H(x) __le32_to_cpu(x)
+
+#define MIN(a, b) ((a) > (b) ? (b) : (a))
+
+#define MAX_IMG_CNT 16
+#define UIMG_PATH "/lib/firmware/gdm72xx/gdmuimg.bin"
+#define KERN_PATH "/lib/firmware/gdm72xx/zImage"
+#define FS_PATH "/lib/firmware/gdm72xx/ramdisk.jffs2"
+
+struct dn_header {
+ u32 magic_num;
+ u32 file_size;
+};
+
+struct img_header {
+ u32 magic_code;
+ u32 count;
+ u32 len;
+ u32 offset[MAX_IMG_CNT];
+ char hostname[32];
+ char date[32];
+};
+
+struct fw_info {
+ u32 id;
+ u32 len;
+ u32 kernel_len;
+ u32 rootfs_len;
+ u32 kernel_offset;
+ u32 rootfs_offset;
+ u32 fw_ver;
+ u32 mac_ver;
+ char hostname[32];
+ char userid[16];
+ char date[32];
+ char user_desc[128];
+};
+
+static void array_le32_to_cpu(u32 *arr, int num)
+{
+ int i;
+ for (i = 0; i < num; i++, arr++)
+ *arr = DL2H(*arr);
+}
+
+static u8 *tx_buf;
+
+static int gdm_wibro_send(struct usb_device *usbdev, void *data, int len)
+{
+ int ret;
+ int actual;
+
+ ret = usb_bulk_msg(usbdev, usb_sndbulkpipe(usbdev, 1), data, len,
+ &actual, 1000);
+
+ if (ret < 0) {
+ printk(KERN_ERR "Error : usb_bulk_msg ( result = %d )\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+static int gdm_wibro_recv(struct usb_device *usbdev, void *data, int len)
+{
+ int ret;
+ int actual;
+
+ ret = usb_bulk_msg(usbdev, usb_rcvbulkpipe(usbdev, 2), data, len,
+ &actual, 5000);
+
+ if (ret < 0) {
+ printk(KERN_ERR "Error : usb_bulk_msg(recv) ( result = %d )\n",
+ ret);
+ return ret;
+ }
+ return 0;
+}
+
+static int download_image(struct usb_device *usbdev, struct file *filp,
+ loff_t *pos, u32 img_len, u32 magic_num)
+{
+ struct dn_header h;
+ int ret = 0;
+ u32 size;
+ int len, readn;
+
+ size = (img_len + DOWNLOAD_SIZE - 1) & ~(DOWNLOAD_SIZE - 1);
+ h.magic_num = DH2B(magic_num);
+ h.file_size = DH2B(size);
+
+ ret = gdm_wibro_send(usbdev, &h, sizeof(h));
+ if (ret < 0)
+ goto out;
+
+ readn = 0;
+ while ((len = filp->f_op->read(filp, tx_buf, DOWNLOAD_SIZE, pos))) {
+
+ if (len < 0) {
+ ret = -1;
+ goto out;
+ }
+ readn += len;
+
+ ret = gdm_wibro_send(usbdev, tx_buf, DOWNLOAD_SIZE);
+ if (ret < 0)
+ goto out;
+ if (readn >= img_len)
+ break;
+ }
+
+ if (readn < img_len) {
+ printk(KERN_ERR "gdmwm: Cannot read to the requested size. "
+ "Read = %d Requested = %d\n", readn, img_len);
+ ret = -EIO;
+ }
+out:
+
+ return ret;
+}
+
+int usb_boot(struct usb_device *usbdev, u16 pid)
+{
+ int i, ret = 0;
+ struct file *filp = NULL;
+ struct inode *inode = NULL;
+ static mm_segment_t fs;
+ struct img_header hdr;
+ struct fw_info fw_info;
+ loff_t pos = 0;
+ char *img_name = UIMG_PATH;
+ int len;
+
+ tx_buf = kmalloc(DOWNLOAD_SIZE, GFP_KERNEL);
+ if (tx_buf == NULL) {
+ printk(KERN_ERR "Error: kmalloc\n");
+ return -ENOMEM;
+ }
+
+ fs = get_fs();
+ set_fs(get_ds());
+
+ filp = filp_open(img_name, O_RDONLY | O_LARGEFILE, 0);
+ if (IS_ERR(filp)) {
+ printk(KERN_ERR "Can't find %s.\n", img_name);
+ set_fs(fs);
+ ret = -ENOENT;
+ goto restore_fs;
+ }
+
+ if (filp->f_dentry)
+ inode = filp->f_dentry->d_inode;
+ if (!inode || !S_ISREG(inode->i_mode)) {
+ printk(KERN_ERR "Invalid file type: %s\n", img_name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ len = filp->f_op->read(filp, (u8 *)&hdr, sizeof(hdr), &pos);
+ if (len != sizeof(hdr)) {
+ printk(KERN_ERR "gdmwm: Cannot read the image info.\n");
+ ret = -EIO;
+ goto out;
+ }
+
+ array_le32_to_cpu((u32 *)&hdr, 19);
+#if 0
+ if (hdr.magic_code != 0x10767fff) {
+ printk(KERN_ERR "gdmwm: Invalid magic code 0x%08x\n",
+ hdr.magic_code);
+ ret = -EINVAL;
+ goto out;
+ }
+#endif
+ if (hdr.count > MAX_IMG_CNT) {
+ printk(KERN_ERR "gdmwm: Too many images. %d\n", hdr.count);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < hdr.count; i++) {
+ if (hdr.offset[i] > hdr.len) {
+ printk(KERN_ERR "gdmwm: Invalid offset. "
+ "Entry = %d Offset = 0x%08x "
+ "Image length = 0x%08x\n",
+ i, hdr.offset[i], hdr.len);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pos = hdr.offset[i];
+ len = filp->f_op->read(filp, (u8 *)&fw_info, sizeof(fw_info),
+ &pos);
+ if (len != sizeof(fw_info)) {
+ printk(KERN_ERR "gdmwm: Cannot read the FW info.\n");
+ ret = -EIO;
+ goto out;
+ }
+
+ array_le32_to_cpu((u32 *)&fw_info, 8);
+#if 0
+ if ((fw_info.id & 0xfffff000) != 0x10767000) {
+ printk(KERN_ERR "gdmwm: Invalid FW id. 0x%08x\n",
+ fw_info.id);
+ ret = -EIO;
+ goto out;
+ }
+#endif
+
+ if ((fw_info.id & 0xffff) != pid)
+ continue;
+
+ pos = hdr.offset[i] + fw_info.kernel_offset;
+ ret = download_image(usbdev, filp, &pos, fw_info.kernel_len,
+ DN_KERNEL_MAGIC_NUMBER);
+ if (ret < 0)
+ goto out;
+ printk(KERN_INFO "GCT: Kernel download success.\n");
+
+ pos = hdr.offset[i] + fw_info.rootfs_offset;
+ ret = download_image(usbdev, filp, &pos, fw_info.rootfs_len,
+ DN_ROOTFS_MAGIC_NUMBER);
+ if (ret < 0)
+ goto out;
+ printk(KERN_INFO "GCT: Filesystem download success.\n");
+
+ break;
+ }
+
+ if (i == hdr.count) {
+ printk(KERN_ERR "Firmware for gsk%x is not installed.\n", pid);
+ ret = -EINVAL;
+ }
+out:
+ filp_close(filp, current->files);
+
+restore_fs:
+ set_fs(fs);
+ kfree(tx_buf);
+ return ret;
+}
+
+/*#define GDM7205_PADDING 256 */
+#define DOWNLOAD_CHUCK 2048
+#define KERNEL_TYPE_STRING "linux"
+#define FS_TYPE_STRING "rootfs"
+
+static int em_wait_ack(struct usb_device *usbdev, int send_zlp)
+{
+ int ack;
+ int ret = -1;
+
+ if (send_zlp) {
+ /*Send ZLP*/
+ ret = gdm_wibro_send(usbdev, NULL, 0);
+ if (ret < 0)
+ goto out;
+ }
+
+ /*Wait for ACK*/
+ ret = gdm_wibro_recv(usbdev, &ack, sizeof(ack));
+ if (ret < 0)
+ goto out;
+out:
+ return ret;
+}
+
+static int em_download_image(struct usb_device *usbdev, char *path,
+ char *type_string)
+{
+ struct file *filp;
+ struct inode *inode;
+ static mm_segment_t fs;
+ char *buf = NULL;
+ loff_t pos = 0;
+ int ret = 0;
+ int len, readn = 0;
+ #if defined(GDM7205_PADDING)
+ const int pad_size = GDM7205_PADDING;
+ #else
+ const int pad_size = 0;
+ #endif
+
+ fs = get_fs();
+ set_fs(get_ds());
+
+ filp = filp_open(path, O_RDONLY | O_LARGEFILE, 0);
+ if (IS_ERR(filp)) {
+ printk(KERN_ERR "Can't find %s.\n", path);
+ set_fs(fs);
+ ret = -ENOENT;
+ goto restore_fs;
+ }
+
+ if (filp->f_dentry) {
+ inode = filp->f_dentry->d_inode;
+ if (!inode || !S_ISREG(inode->i_mode)) {
+ printk(KERN_ERR "Invalid file type: %s\n", path);
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+
+ buf = kmalloc(DOWNLOAD_CHUCK + pad_size, GFP_KERNEL);
+ if (buf == NULL) {
+ printk(KERN_ERR "Error: kmalloc\n");
+ return -ENOMEM;
+ }
+
+ strcpy(buf+pad_size, type_string);
+ ret = gdm_wibro_send(usbdev, buf, strlen(type_string)+pad_size);
+ if (ret < 0)
+ goto out;
+
+ while ((len = filp->f_op->read(filp, buf+pad_size, DOWNLOAD_CHUCK,
+ &pos))) {
+ if (len < 0) {
+ ret = -1;
+ goto out;
+ }
+ readn += len;
+
+ ret = gdm_wibro_send(usbdev, buf, len+pad_size);
+ if (ret < 0)
+ goto out;
+
+ ret = em_wait_ack(usbdev, ((len+pad_size) % 512 == 0));
+ if (ret < 0)
+ goto out;
+ }
+
+ ret = em_wait_ack(usbdev, 1);
+ if (ret < 0)
+ goto out;
+
+out:
+ filp_close(filp, current->files);
+
+restore_fs:
+ set_fs(fs);
+
+ kfree(buf);
+
+ return ret;
+}
+
+static int em_fw_reset(struct usb_device *usbdev)
+{
+ int ret;
+
+ /*Send ZLP*/
+ ret = gdm_wibro_send(usbdev, NULL, 0);
+ return ret;
+}
+
+int usb_emergency(struct usb_device *usbdev)
+{
+ int ret;
+
+ ret = em_download_image(usbdev, KERN_PATH, KERNEL_TYPE_STRING);
+ if (ret < 0)
+ goto out;
+ printk(KERN_INFO "GCT Emergency: Kernel download success.\n");
+
+ ret = em_download_image(usbdev, FS_PATH, FS_TYPE_STRING);
+ if (ret < 0)
+ goto out;
+ printk(KERN_INFO "GCT Emergency: Filesystem download success.\n");
+
+ ret = em_fw_reset(usbdev);
+out:
+ return ret;
+}
diff --git a/drivers/staging/gdm72xx/usb_boot.h b/drivers/staging/gdm72xx/usb_boot.h
new file mode 100644
index 000000000000..c715cd3cd300
--- /dev/null
+++ b/drivers/staging/gdm72xx/usb_boot.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __USB_BOOT_H__
+#define __USB_BOOT_H__
+
+struct usb_device;
+
+extern int usb_boot(struct usb_device *usbdev, u16 pid);
+extern int usb_emergency(struct usb_device *usbdev);
+
+#endif /* __USB_BOOT_H__ */
diff --git a/drivers/staging/gdm72xx/usb_ids.h b/drivers/staging/gdm72xx/usb_ids.h
new file mode 100644
index 000000000000..b34616b7203f
--- /dev/null
+++ b/drivers/staging/gdm72xx/usb_ids.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __USB_IDS_H__
+#define __USB_IDS_H__
+
+/*You can replace vendor-ID as yours.*/
+#define GCT_VID 0x1076
+
+/*You can replace product-ID as yours.*/
+#define GCT_PID1 0x7e00
+#define GCT_PID2 0x7f00
+
+#define USB_DEVICE_ID_MATCH_DEVICE_INTERFACE \
+ (USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_CLASS)
+
+#define USB_DEVICE_INTF(vend, prod, intf) \
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE_INTERFACE, \
+ .idVendor = (vend), .idProduct = (prod), .bInterfaceClass = (intf)
+
+#define EMERGENCY_PID 0x720f
+#define BL_PID_MASK 0xffc0
+
+#define USB_DEVICE_BOOTLOADER(vid, pid) \
+ {USB_DEVICE((vid), ((pid)&BL_PID_MASK)|B_DOWNLOAD)}, \
+ {USB_DEVICE((vid), ((pid)&BL_PID_MASK)|B_DOWNLOAD|B_DIFF_DL_DRV)}
+
+#define USB_DEVICE_CDC_DATA(vid, pid) \
+ {USB_DEVICE_INTF((vid), (pid), USB_CLASS_CDC_DATA)}
+
+static const struct usb_device_id id_table[] = {
+ USB_DEVICE_BOOTLOADER(GCT_VID, GCT_PID1),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x1),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x2),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x3),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x4),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x5),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x6),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x7),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x8),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0x9),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xa),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xb),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xc),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xd),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xe),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID1+0xf),
+
+ USB_DEVICE_BOOTLOADER(GCT_VID, GCT_PID2),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x1),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x2),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x3),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x4),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x5),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x6),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x7),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x8),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0x9),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xa),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xb),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xc),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xd),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xe),
+ USB_DEVICE_CDC_DATA(GCT_VID, GCT_PID2+0xf),
+
+ {USB_DEVICE(GCT_VID, EMERGENCY_PID)},
+ { }
+};
+
+#endif /* __USB_IDS_H__ */
diff --git a/drivers/staging/gdm72xx/wm_ioctl.h b/drivers/staging/gdm72xx/wm_ioctl.h
new file mode 100644
index 000000000000..9f46e06f2303
--- /dev/null
+++ b/drivers/staging/gdm72xx/wm_ioctl.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2012 GCT Semiconductor, Inc. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#if !defined(WM_IOCTL_H_20080714)
+#define WM_IOCTL_H_20080714
+#if !defined(__KERNEL__)
+#include <net/if.h>
+#endif
+
+#define NETLINK_WIMAX 31
+
+#define SIOCWMIOCTL SIOCDEVPRIVATE
+
+#define SIOCG_DATA 0x8D10
+#define SIOCS_DATA 0x8D11
+
+enum {
+ SIOC_DATA_FSM,
+ SIOC_DATA_NETLIST,
+ SIOC_DATA_CONNNSP,
+ SIOC_DATA_CONNCOMP,
+ SIOC_DATA_PROFILEID,
+
+ SIOC_DATA_END
+};
+
+#define SIOC_DATA_MAX 16
+
+/* FSM */
+enum {
+ M_INIT = 0,
+ M_OPEN_OFF,
+ M_OPEN_ON,
+ M_SCAN,
+ M_CONNECTING,
+ M_CONNECTED,
+ M_FSM_END,
+
+ C_INIT = 0,
+ C_CONNSTART,
+ C_ASSOCSTART,
+ C_RNG,
+ C_SBC,
+ C_AUTH,
+ C_REG,
+ C_DSX,
+ C_ASSOCCOMPLETE,
+ C_CONNCOMPLETE,
+ C_FSM_END,
+
+ D_INIT = 0,
+ D_READY,
+ D_LISTEN,
+ D_IPACQUISITION,
+
+ END_FSM
+};
+
+struct fsm_s {
+ int m_status; /*main status*/
+ int c_status; /*connection status*/
+ int d_status; /*oma-dm status*/
+};
+
+struct data_s {
+ int size;
+ void *buf;
+};
+
+struct wm_req_s {
+ union {
+ char ifrn_name[IFNAMSIZ];
+ } ifr_ifrn;
+
+ unsigned short cmd;
+
+ unsigned short data_id;
+ struct data_s data;
+
+/* NOTE: sizeof(struct wm_req_s) must be less than sizeof(struct ifreq). */
+};
+
+#ifndef ifr_name
+#define ifr_name ifr_ifrn.ifrn_name
+#endif
+
+#endif
diff --git a/drivers/staging/iio/Documentation/device.txt b/drivers/staging/iio/Documentation/device.txt
index 8926f2448cc9..0338c7cd0a8b 100644
--- a/drivers/staging/iio/Documentation/device.txt
+++ b/drivers/staging/iio/Documentation/device.txt
@@ -8,7 +8,7 @@ The crucial structure for device drivers in iio is iio_dev.
First allocate one using:
-struct iio_dev *indio_dev = iio_allocate_device(sizeof(struct chip_state));
+struct iio_dev *indio_dev = iio_device_alloc(sizeof(struct chip_state));
where chip_state is a structure of local state data for this instance of
the chip.
@@ -78,4 +78,4 @@ be registered afterwards (otherwise the whole parentage of devices
gets confused)
On remove, iio_device_unregister(indio_dev) will remove the device from
-the core, and iio_free_device will clean up.
+the core, and iio_device_free will clean up.
diff --git a/drivers/staging/iio/Documentation/generic_buffer.c b/drivers/staging/iio/Documentation/generic_buffer.c
index 69a05b9456d6..bf553356fdad 100644
--- a/drivers/staging/iio/Documentation/generic_buffer.c
+++ b/drivers/staging/iio/Documentation/generic_buffer.c
@@ -60,9 +60,9 @@ void print2byte(int input, struct iio_channel_info *info)
/* First swap if incorrect endian */
if (info->be)
- input = be16toh((uint_16t)input);
+ input = be16toh((uint16_t)input);
else
- input = le16toh((uint_16t)input);
+ input = le16toh((uint16_t)input);
/* shift before conversion to avoid sign extension
of left aligned data */
diff --git a/drivers/staging/iio/Documentation/iio_event_monitor.c b/drivers/staging/iio/Documentation/iio_event_monitor.c
index 0d21a277305f..22275845fb12 100644
--- a/drivers/staging/iio/Documentation/iio_event_monitor.c
+++ b/drivers/staging/iio/Documentation/iio_event_monitor.c
@@ -27,7 +27,7 @@
#include <fcntl.h>
#include <sys/ioctl.h>
#include "iio_utils.h"
-#include "../events.h"
+#include <linux/iio/events.h>
static const char * const iio_chan_type_name_spec[] = {
[IIO_VOLTAGE] = "voltage",
diff --git a/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2583 b/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2583
new file mode 100755
index 000000000000..470f7ad9c073
--- /dev/null
+++ b/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2583
@@ -0,0 +1,6 @@
+What: /sys/bus/iio/devices/device[n]/in_illuminance0_calibrate
+KernelVersion: 2.6.37
+Contact: linux-iio@vger.kernel.org
+Description:
+ This property causes an internal calibration of the als gain trim
+ value which is later used in calculating illuminance in lux.
diff --git a/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2x7x b/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2x7x
new file mode 100755
index 000000000000..b2798b258bf7
--- /dev/null
+++ b/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2x7x
@@ -0,0 +1,13 @@
+What: /sys/bus/iio/devices/device[n]/in_illuminance0_calibrate
+KernelVersion: 3.3-rc1
+Contact: linux-iio@vger.kernel.org
+Description:
+ Causes an internal calibration of the als gain trim
+ value which is later used in calculating illuminance in lux.
+
+What: /sys/bus/iio/devices/device[n]/in_proximity0_calibrate
+KernelVersion: 3.3-rc1
+Contact: linux-iio@vger.kernel.org
+Description:
+ Causes a recalculation and adjustment to the
+ proximity_thresh_rising_value.
diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-ad7192 b/drivers/staging/iio/Documentation/sysfs-bus-iio-ad7192
new file mode 100644
index 000000000000..1c35c507cc05
--- /dev/null
+++ b/drivers/staging/iio/Documentation/sysfs-bus-iio-ad7192
@@ -0,0 +1,20 @@
+What: /sys/.../iio:deviceX/ac_excitation_en
+KernelVersion: 3.1.0
+Contact: linux-iio@vger.kernel.org
+Description:
+ This attribute, if available, is used to enable the AC
+ excitation mode found on some converters. In ac excitation mode,
+ the polarity of the excitation voltage is reversed on
+ alternate cycles, to eliminate DC errors.
+
+What: /sys/.../iio:deviceX/bridge_switch_en
+KernelVersion: 3.1.0
+Contact: linux-iio@vger.kernel.org
+Description:
+ This attribute, if available, is used to close or open the
+ bridge power down switch found on some converters.
+ In bridge applications, such as strain gauges and load cells,
+ the bridge itself consumes the majority of the current in the
+ system. To minimize the current consumption of the system,
+ the bridge can be disconnected (when it is not being used
+ using the bridge_switch_en attribute.
diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-dds b/drivers/staging/iio/Documentation/sysfs-bus-iio-dds
index ffdd5478a35d..ee8c509c6733 100644
--- a/drivers/staging/iio/Documentation/sysfs-bus-iio-dds
+++ b/drivers/staging/iio/Documentation/sysfs-bus-iio-dds
@@ -1,83 +1,86 @@
-What: /sys/bus/iio/devices/.../ddsX_freqY
+What: /sys/bus/iio/devices/.../out_altvoltageX_frequencyY
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
Stores frequency into tuning word Y.
- There will be more than one ddsX_freqY file, which allows for
- pin controlled FSK Frequency Shift Keying
- (ddsX_pincontrol_freq_en is active) or the user can control
- the desired active tuning word by writing Y to the
- ddsX_freqsymbol file.
+ There will be more than one out_altvoltageX_frequencyY file,
+ which allows for pin controlled FSK Frequency Shift Keying
+ (out_altvoltageX_pincontrol_frequency_en is active) or the user
+ can control the desired active tuning word by writing Y to the
+ out_altvoltageX_frequencysymbol file.
-What: /sys/bus/iio/devices/.../ddsX_freqY_scale
+What: /sys/bus/iio/devices/.../out_altvoltageX_frequencyY_scale
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
- Scale to be applied to ddsX_freqY in order to obtain the
- desired value in Hz. If shared across all frequency registers
- Y is not present. It is also possible X is not present if
- shared across all channels.
+ Scale to be applied to out_altvoltageX_frequencyY in order to
+ obtain the desired value in Hz. If shared across all frequency
+ registers Y is not present. It is also possible X is not present
+ if shared across all channels.
-What: /sys/bus/iio/devices/.../ddsX_freqsymbol
+What: /sys/bus/iio/devices/.../out_altvoltageX_frequencysymbol
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
Specifies the active output frequency tuning word. The value
- corresponds to the Y in ddsX_freqY. To exit this mode the user
- can write ddsX_pincontrol_freq_en or ddsX_out_enable file.
+ corresponds to the Y in out_altvoltageX_frequencyY.
+ To exit this mode the user can write
+ out_altvoltageX_pincontrol_frequency_en or
+ out_altvoltageX_out_enable file.
-What: /sys/bus/iio/devices/.../ddsX_phaseY
+What: /sys/bus/iio/devices/.../out_altvoltageX_phaseY
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
Stores phase into Y.
- There will be more than one ddsX_phaseY file, which allows for
- pin controlled PSK Phase Shift Keying
- (ddsX_pincontrol_phase_en is active) or the user can
+ There will be more than one out_altvoltageX_phaseY file, which
+ allows for pin controlled PSK Phase Shift Keying
+ (out_altvoltageX_pincontrol_phase_en is active) or the user can
control the desired phase Y which is added to the phase
- accumulator output by writing Y to the en_phase file.
+ accumulator output by writing Y to the phase_en file.
-What: /sys/bus/iio/devices/.../ddsX_phaseY_scale
+What: /sys/bus/iio/devices/.../out_altvoltageX_phaseY_scale
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
- Scale to be applied to ddsX_phaseY in order to obtain the
- desired value in rad. If shared across all phase registers
+ Scale to be applied to out_altvoltageX_phaseY in order to obtain
+ the desired value in rad. If shared across all phase registers
Y is not present. It is also possible X is not present if
shared across all channels.
-What: /sys/bus/iio/devices/.../ddsX_phasesymbol
+What: /sys/bus/iio/devices/.../out_altvoltageX_phasesymbol
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
Specifies the active phase Y which is added to the phase
accumulator output. The value corresponds to the Y in
- ddsX_phaseY. To exit this mode the user can write
- ddsX_pincontrol_phase_en or disable file.
+ out_altvoltageX_phaseY. To exit this mode the user can write
+ out_altvoltageX_pincontrol_phase_en or disable file.
-What: /sys/bus/iio/devices/.../ddsX_pincontrol_en
-What: /sys/bus/iio/devices/.../ddsX_pincontrol_freq_en
-What: /sys/bus/iio/devices/.../ddsX_pincontrol_phase_en
+What: /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_en
+What: /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_frequency_en
+What: /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_phase_en
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
- ddsX_pincontrol_en: Both, the active frequency and phase is
- controlled by the respective phase and frequency control inputs.
- In case the device in question allows to independent controls,
- then there are dedicated files (ddsX_pincontrol_freq_en,
- ddsX_pincontrol_phase_en).
+ out_altvoltageX_pincontrol_en: Both, the active frequency and
+ phase is controlled by the respective phase and frequency
+ control inputs. In case the device in features independent
+ controls, then there are dedicated files
+ (out_altvoltageX_pincontrol_frequency_en,
+ out_altvoltageX_pincontrol_phase_en).
-What: /sys/bus/iio/devices/.../ddsX_out_enable
-What: /sys/bus/iio/devices/.../ddsX_outY_enable
+What: /sys/bus/iio/devices/.../out_altvoltageX_out_enable
+What: /sys/bus/iio/devices/.../out_altvoltageX_outY_enable
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
- ddsX_outY_enable controls signal generation on output Y of
- channel X. Y may be suppressed if all channels are
+ out_altvoltageX_outY_enable controls signal generation on
+ output Y of channel X. Y may be suppressed if all channels are
controlled together.
-What: /sys/bus/iio/devices/.../ddsX_outY_wavetype
+What: /sys/bus/iio/devices/.../out_altvoltageX_outY_wavetype
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
@@ -86,7 +89,7 @@ Description:
For a list of available output waveform options read
available_output_modes.
-What: /sys/bus/iio/devices/.../ddsX_outY_wavetype_available
+What: /sys/bus/iio/devices/.../out_altvoltageX_outY_wavetype_available
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-light b/drivers/staging/iio/Documentation/sysfs-bus-iio-light
index edbf470e4e30..715c74dcb53a 100644
--- a/drivers/staging/iio/Documentation/sysfs-bus-iio-light
+++ b/drivers/staging/iio/Documentation/sysfs-bus-iio-light
@@ -26,7 +26,7 @@ Description:
Hardware dependent list of possible values supported for the
adc_resolution of the given sensor.
-What: /sys/bus/iio/devices/device[n]/illuminance0[_input|_raw]
+What: /sys/bus/iio/devices/device[n]/in_illuminance0[_input|_raw]
KernelVersion: 2.6.35
Contact: linux-iio@vger.kernel.org
Description:
@@ -45,7 +45,7 @@ Description:
do this calculation manually by reading the infrared sensor
value and doing the negation in sw.
-What: /sys/bus/iio/devices/device[n]/proximity[_input|_raw]
+What: /sys/bus/iio/devices/device[n]/in_proximity[_input|_raw]
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
@@ -63,23 +63,22 @@ Description:
and if expressed in SI units, should include _input. If this
value is not in SI units, then it should include _raw.
-What: /sys/bus/iio/devices/device[n]/illuminance0_target
+What: /sys/bus/iio/devices/device[n]/in_illuminance0_target
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
This property gets/sets the last known external
lux measurement used in/for calibration.
-What: /sys/bus/iio/devices/device[n]/illuminance0_integration_time
+What: /sys/bus/iio/devices/device[n]/in_illuminance0_integration_time
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
This property gets/sets the sensors ADC analog integration time.
-What: /sys/bus/iio/devices/device[n]/illuminance0_calibscale
+What: /sys/bus/iio/devices/device[n]/in_illuminance0_lux_table
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
- Hardware or software applied calibration scale factor assumed
- to account for attenuation due to industrial design (glass
- filters or aperture holes).
+ This property gets/sets the table of coefficients
+ used in calculating illuminance in lux.
diff --git a/drivers/staging/iio/Documentation/trigger.txt b/drivers/staging/iio/Documentation/trigger.txt
index fc2012ebc100..75cc37ff1ed0 100644
--- a/drivers/staging/iio/Documentation/trigger.txt
+++ b/drivers/staging/iio/Documentation/trigger.txt
@@ -5,7 +5,7 @@ an IIO device. Whilst this can create device specific complexities
such triggers are registered with the core in the same way as
stand-alone triggers.
-struct iio_trig *trig = iio_allocate_trigger("<trigger format string>", ...);
+struct iio_trig *trig = iio_trigger_alloc("<trigger format string>", ...);
allocates a trigger structure. The key elements to then fill in within
a driver are:
diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
index fe1586718880..3c8e5ec26ac1 100644
--- a/drivers/staging/iio/Kconfig
+++ b/drivers/staging/iio/Kconfig
@@ -1,16 +1,9 @@
#
# Industrial I/O subsytem configuration
#
+menu "IIO staging drivers"
+ depends on IIO
-menuconfig IIO
- tristate "Industrial I/O support"
- depends on GENERIC_HARDIRQS
- help
- The industrial I/O subsystem provides a unified framework for
- drivers for many different types of embedded sensors using a
- number of different physical interfaces (i2c, spi, etc). See
- drivers/staging/iio/Documentation for more information.
-if IIO
config IIO_ST_HWMON
tristate "Hwmon driver that uses channels specified via iio maps"
depends on HWMON
@@ -19,12 +12,6 @@ config IIO_ST_HWMON
map allows IIO devices to provide basic hwmon functionality
for those channels specified in the map.
-config IIO_BUFFER
- bool "Enable buffer support within IIO"
- help
- Provide core support for various buffer based data
- acquisition methods.
-
if IIO_BUFFER
config IIO_SW_RING
@@ -36,39 +23,14 @@ config IIO_SW_RING
with the intention that some devices would be able to write
in interrupt context.
-config IIO_KFIFO_BUF
- select IIO_TRIGGER
- tristate "Industrial I/O buffering based on kfifo"
- help
- A simple fifo based on kfifo. Use this if you want a fifo
- rather than a ring buffer. Note that this currently provides
- no buffer events so it is up to userspace to work out how
- often to read from the buffer.
-
endif # IIO_BUFFER
-config IIO_TRIGGER
- boolean "Enable triggered sampling support"
- help
- Provides IIO core support for triggers. Currently these
- are used to initialize capture of samples to push into
- ring buffers. The triggers are effectively a 'capture
- data now' interrupt.
-
-config IIO_CONSUMERS_PER_TRIGGER
- int "Maximum number of consumers per trigger"
- depends on IIO_TRIGGER
- default "2"
- help
- This value controls the maximum number of consumers that a
- given trigger may handle. Default is 2.
-
source "drivers/staging/iio/accel/Kconfig"
source "drivers/staging/iio/adc/Kconfig"
source "drivers/staging/iio/addac/Kconfig"
source "drivers/staging/iio/cdc/Kconfig"
source "drivers/staging/iio/dac/Kconfig"
-source "drivers/staging/iio/dds/Kconfig"
+source "drivers/staging/iio/frequency/Kconfig"
source "drivers/staging/iio/gyro/Kconfig"
source "drivers/staging/iio/impedance-analyzer/Kconfig"
source "drivers/staging/iio/imu/Kconfig"
@@ -104,4 +66,4 @@ config IIO_SIMPLE_DUMMY_BUFFER
endif # IIO_SIMPLE_DUMMY
-endif # IIO
+endmenu
diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile
index 5075291dda7a..6a46d5afb380 100644
--- a/drivers/staging/iio/Makefile
+++ b/drivers/staging/iio/Makefile
@@ -2,13 +2,7 @@
# Makefile for the industrial I/O core.
#
-obj-$(CONFIG_IIO) += industrialio.o
-industrialio-y := industrialio-core.o industrialio-event.o inkern.o
-industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
-industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
-
obj-$(CONFIG_IIO_SW_RING) += ring_sw.o
-obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
obj-$(CONFIG_IIO_SIMPLE_DUMMY) += iio_dummy.o
iio_dummy-y := iio_simple_dummy.o
@@ -24,7 +18,7 @@ obj-y += adc/
obj-y += addac/
obj-y += cdc/
obj-y += dac/
-obj-y += dds/
+obj-y += frequency/
obj-y += gyro/
obj-y += impedance-analyzer/
obj-y += imu/
diff --git a/drivers/staging/iio/TODO b/drivers/staging/iio/TODO
index d1ad35e24abb..cf3f9489b9da 100644
--- a/drivers/staging/iio/TODO
+++ b/drivers/staging/iio/TODO
@@ -67,7 +67,7 @@ e-mailing the normal IIO list (see below).
Documentation
1) Lots of cleanup and expansion.
-2) Some device require indvidual docs.
+2) Some device require individual docs.
Contact: Jonathan Cameron <jic23@cam.ac.uk>.
Mailing list: linux-iio@vger.kernel.org
diff --git a/drivers/staging/iio/accel/adis16201_core.c b/drivers/staging/iio/accel/adis16201_core.c
index d439e45d07fa..02b340919c0e 100644
--- a/drivers/staging/iio/accel/adis16201_core.c
+++ b/drivers/staging/iio/accel/adis16201_core.c
@@ -15,9 +15,9 @@
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "adis16201.h"
@@ -171,7 +171,7 @@ static ssize_t adis16201_write_reset(struct device *dev,
ret = strtobool(buf, &res);
if (ret || !res)
return ret;
- return adis16201_reset(dev_get_drvdata(dev));
+ return adis16201_reset(dev_to_iio_dev(dev));
}
int adis16201_set_irq(struct iio_dev *indio_dev, bool enable)
@@ -298,7 +298,7 @@ static int adis16201_read_raw(struct iio_dev *indio_dev,
s16 val16;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
addr = adis16201_addresses[chan->address][0];
ret = adis16201_spi_read_reg_16(indio_dev, addr, &val16);
@@ -406,39 +406,104 @@ static int adis16201_write_raw(struct iio_dev *indio_dev,
}
static struct iio_chan_spec adis16201_channels[] = {
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "supply", 0, 0,
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .extend_name = "supply",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- in_supply, ADIS16201_SCAN_SUPPLY,
- IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0,
+ .address = in_supply,
+ .scan_index = ADIS16201_SCAN_SUPPLY,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_TEMP,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
- temp, ADIS16201_SCAN_TEMP,
- IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X,
+ .address = temp,
+ .scan_index = ADIS16201_SCAN_TEMP,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_ACCEL,
+ .modified = 1,
+ .channel2 = IIO_MOD_X,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
- accel_x, ADIS16201_SCAN_ACC_X,
- IIO_ST('s', 14, 16, 0), 0),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y,
+ .address = accel_x,
+ .scan_index = ADIS16201_SCAN_ACC_X,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_ACCEL,
+ .modified = 1,
+ .channel2 = IIO_MOD_Y,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
- accel_y, ADIS16201_SCAN_ACC_Y,
- IIO_ST('s', 14, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0,
+ .address = accel_y,
+ .scan_index = ADIS16201_SCAN_ACC_Y,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- in_aux, ADIS16201_SCAN_AUX_ADC,
- IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_X,
+ .address = in_aux,
+ .scan_index = ADIS16201_SCAN_AUX_ADC,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_INCLI,
+ .modified = 1,
+ .channel2 = IIO_MOD_X,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
- incli_x, ADIS16201_SCAN_INCLI_X,
- IIO_ST('s', 14, 16, 0), 0),
- IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_Y,
+ .address = incli_x,
+ .scan_index = ADIS16201_SCAN_INCLI_X,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_INCLI,
+ .modified = 1,
+ .channel2 = IIO_MOD_Y,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
- incli_y, ADIS16201_SCAN_INCLI_Y,
- IIO_ST('s', 14, 16, 0), 0),
+ .address = incli_y,
+ .scan_index = ADIS16201_SCAN_INCLI_Y,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ },
IIO_CHAN_SOFT_TIMESTAMP(7)
};
@@ -467,7 +532,7 @@ static int __devinit adis16201_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -522,7 +587,7 @@ error_uninitialize_ring:
error_unreg_ring_funcs:
adis16201_unconfigure_ring(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -535,7 +600,7 @@ static int adis16201_remove(struct spi_device *spi)
adis16201_remove_trigger(indio_dev);
iio_buffer_unregister(indio_dev);
adis16201_unconfigure_ring(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/accel/adis16201_ring.c b/drivers/staging/iio/accel/adis16201_ring.c
index 97f9e6b159d9..247602a8e54c 100644
--- a/drivers/staging/iio/accel/adis16201_ring.c
+++ b/drivers/staging/iio/accel/adis16201_ring.c
@@ -5,9 +5,9 @@
#include <linux/spi/spi.h>
#include <linux/slab.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
#include "adis16201.h"
@@ -66,9 +66,8 @@ static irqreturn_t adis16201_trigger_handler(int irq, void *p)
int i = 0;
s16 *data;
- size_t datasize = ring->access->get_bytes_per_datum(ring);
- data = kmalloc(datasize, GFP_KERNEL);
+ data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL) {
dev_err(&st->us->dev, "memory alloc failed in ring bh");
return -ENOMEM;
@@ -81,7 +80,7 @@ static irqreturn_t adis16201_trigger_handler(int irq, void *p)
data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
- if (ring->scan_timestamp)
+ if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
ring->access->store_to(ring, (u8 *)data, pf->timestamp);
diff --git a/drivers/staging/iio/accel/adis16201_trigger.c b/drivers/staging/iio/accel/adis16201_trigger.c
index bce505e716d0..96fdabbac201 100644
--- a/drivers/staging/iio/accel/adis16201_trigger.c
+++ b/drivers/staging/iio/accel/adis16201_trigger.c
@@ -3,8 +3,8 @@
#include <linux/spi/spi.h>
#include <linux/export.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
#include "adis16201.h"
/**
@@ -29,7 +29,7 @@ int adis16201_probe_trigger(struct iio_dev *indio_dev)
int ret;
struct adis16201_state *st = iio_priv(indio_dev);
- st->trig = iio_allocate_trigger("adis16201-dev%d", indio_dev->id);
+ st->trig = iio_trigger_alloc("adis16201-dev%d", indio_dev->id);
if (st->trig == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -56,7 +56,7 @@ int adis16201_probe_trigger(struct iio_dev *indio_dev)
error_free_irq:
free_irq(st->us->irq, st->trig);
error_free_trig:
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
error_ret:
return ret;
}
@@ -67,5 +67,5 @@ void adis16201_remove_trigger(struct iio_dev *indio_dev)
iio_trigger_unregister(state->trig);
free_irq(state->us->irq, state->trig);
- iio_free_trigger(state->trig);
+ iio_trigger_free(state->trig);
}
diff --git a/drivers/staging/iio/accel/adis16203_core.c b/drivers/staging/iio/accel/adis16203_core.c
index 1a5140f9e3f4..15d46bfd1b42 100644
--- a/drivers/staging/iio/accel/adis16203_core.c
+++ b/drivers/staging/iio/accel/adis16203_core.c
@@ -15,9 +15,9 @@
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "adis16203.h"
@@ -182,7 +182,7 @@ static ssize_t adis16203_write_reset(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
if (len < 1)
return -EINVAL;
switch (buf[0]) {
@@ -305,7 +305,7 @@ static int adis16203_read_raw(struct iio_dev *indio_dev,
u8 addr;
s16 val16;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
addr = adis16203_addresses[chan->address][0];
ret = adis16203_spi_read_reg_16(indio_dev, addr, &val16);
@@ -372,29 +372,75 @@ static int adis16203_read_raw(struct iio_dev *indio_dev,
}
static struct iio_chan_spec adis16203_channels[] = {
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "supply", 0, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- in_supply, ADIS16203_SCAN_SUPPLY,
- IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- in_aux, ADIS16203_SCAN_AUX_ADC,
- IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_X,
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
- incli_x, ADIS16203_SCAN_INCLI_X,
- IIO_ST('s', 14, 16, 0), 0),
- /* Fixme: Not what it appears to be - see data sheet */
- IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_Y,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- incli_y, ADIS16203_SCAN_INCLI_Y,
- IIO_ST('s', 14, 16, 0), 0),
- IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
- temp, ADIS16203_SCAN_TEMP,
- IIO_ST('u', 12, 16, 0), 0),
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .extend_name = "supply",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .address = in_supply,
+ .scan_index = ADIS16203_SCAN_SUPPLY,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .address = in_aux,
+ .scan_index = ADIS16203_SCAN_AUX_ADC,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_INCLI,
+ .modified = 1,
+ .channel2 = IIO_MOD_X,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+ .address = incli_x,
+ .scan_index = ADIS16203_SCAN_INCLI_X,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, { /* Fixme: Not what it appears to be - see data sheet */
+ .type = IIO_INCLI,
+ .modified = 1,
+ .channel2 = IIO_MOD_Y,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = incli_y,
+ .scan_index = ADIS16203_SCAN_INCLI_Y,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_TEMP,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
+ .address = temp,
+ .scan_index = ADIS16203_SCAN_TEMP,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ },
IIO_CHAN_SOFT_TIMESTAMP(5),
};
@@ -423,7 +469,7 @@ static int __devinit adis16203_probe(struct spi_device *spi)
struct adis16203_state *st;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -477,7 +523,7 @@ error_uninitialize_ring:
error_unreg_ring_funcs:
adis16203_unconfigure_ring(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -490,7 +536,7 @@ static int adis16203_remove(struct spi_device *spi)
adis16203_remove_trigger(indio_dev);
iio_buffer_unregister(indio_dev);
adis16203_unconfigure_ring(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/accel/adis16203_ring.c b/drivers/staging/iio/accel/adis16203_ring.c
index 6a8963db4f60..7bbd2c2bbd19 100644
--- a/drivers/staging/iio/accel/adis16203_ring.c
+++ b/drivers/staging/iio/accel/adis16203_ring.c
@@ -5,20 +5,19 @@
#include <linux/spi/spi.h>
#include <linux/slab.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
#include "adis16203.h"
/**
* adis16203_read_ring_data() read data registers which will be placed into ring
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @indio_dev: the IIO device
* @rx: somewhere to pass back the value read
**/
-static int adis16203_read_ring_data(struct device *dev, u8 *rx)
+static int adis16203_read_ring_data(struct iio_dev *indio_dev, u8 *rx)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct adis16203_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[ADIS16203_OUTPUTS + 1];
int ret;
@@ -66,22 +65,21 @@ static irqreturn_t adis16203_trigger_handler(int irq, void *p)
int i = 0;
s16 *data;
- size_t datasize = ring->access->get_bytes_per_datum(ring);
- data = kmalloc(datasize, GFP_KERNEL);
+ data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL) {
dev_err(&st->us->dev, "memory alloc failed in ring bh");
return -ENOMEM;
}
if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) &&
- adis16203_read_ring_data(&indio_dev->dev, st->rx) >= 0)
+ adis16203_read_ring_data(indio_dev, st->rx) >= 0)
for (; i < bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength); i++)
data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
- if (ring->scan_timestamp)
+ if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
ring->access->store_to(ring,
diff --git a/drivers/staging/iio/accel/adis16203_trigger.c b/drivers/staging/iio/accel/adis16203_trigger.c
index 24bcb8e15c55..b8a04073d6d7 100644
--- a/drivers/staging/iio/accel/adis16203_trigger.c
+++ b/drivers/staging/iio/accel/adis16203_trigger.c
@@ -3,8 +3,8 @@
#include <linux/spi/spi.h>
#include <linux/export.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
#include "adis16203.h"
/**
@@ -29,7 +29,7 @@ int adis16203_probe_trigger(struct iio_dev *indio_dev)
int ret;
struct adis16203_state *st = iio_priv(indio_dev);
- st->trig = iio_allocate_trigger("adis16203-dev%d", indio_dev->id);
+ st->trig = iio_trigger_alloc("adis16203-dev%d", indio_dev->id);
if (st->trig == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -58,7 +58,7 @@ int adis16203_probe_trigger(struct iio_dev *indio_dev)
error_free_irq:
free_irq(st->us->irq, st->trig);
error_free_trig:
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
error_ret:
return ret;
}
@@ -69,5 +69,5 @@ void adis16203_remove_trigger(struct iio_dev *indio_dev)
iio_trigger_unregister(st->trig);
free_irq(st->us->irq, st->trig);
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
}
diff --git a/drivers/staging/iio/accel/adis16204_core.c b/drivers/staging/iio/accel/adis16204_core.c
index fa89364b841e..ac9d95e4ea47 100644
--- a/drivers/staging/iio/accel/adis16204_core.c
+++ b/drivers/staging/iio/accel/adis16204_core.c
@@ -18,9 +18,9 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "adis16204.h"
@@ -173,7 +173,7 @@ static ssize_t adis16204_read_14bit_signed(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
s16 val = 0;
ssize_t ret;
@@ -211,7 +211,7 @@ static ssize_t adis16204_write_reset(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
if (len < 1)
return -EINVAL;
@@ -342,7 +342,7 @@ static int adis16204_read_raw(struct iio_dev *indio_dev,
int addrind;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
addr = adis16204_addresses[chan->address][0];
ret = adis16204_spi_read_reg_16(indio_dev, addr, &val16);
@@ -444,31 +444,78 @@ static int adis16204_write_raw(struct iio_dev *indio_dev,
}
static struct iio_chan_spec adis16204_channels[] = {
- IIO_CHAN(IIO_VOLTAGE, 0, 0, 0, "supply", 0, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- in_supply, ADIS16204_SCAN_SUPPLY,
- IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- in_aux, ADIS16204_SCAN_AUX_ADC,
- IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
- temp, ADIS16204_SCAN_TEMP,
- IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_PEAK_SEPARATE_BIT,
- accel_x, ADIS16204_SCAN_ACC_X,
- IIO_ST('s', 14, 16, 0), 0),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
- IIO_CHAN_INFO_PEAK_SEPARATE_BIT,
- accel_y, ADIS16204_SCAN_ACC_Y,
- IIO_ST('s', 14, 16, 0), 0),
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1, /* Note was not previously indexed */
+ .channel = 0,
+ .extend_name = "supply",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .address = in_supply,
+ .scan_index = ADIS16204_SCAN_SUPPLY,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .address = in_aux,
+ .scan_index = ADIS16204_SCAN_AUX_ADC,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_TEMP,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
+ .address = temp,
+ .scan_index = ADIS16204_SCAN_TEMP,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_ACCEL,
+ .modified = 1,
+ .channel2 = IIO_MOD_X,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ IIO_CHAN_INFO_PEAK_SEPARATE_BIT,
+ .address = accel_x,
+ .scan_index = ADIS16204_SCAN_ACC_X,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_ACCEL,
+ .modified = 1,
+ .channel2 = IIO_MOD_Y,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ IIO_CHAN_INFO_PEAK_SEPARATE_BIT,
+ .address = accel_y,
+ .scan_index = ADIS16204_SCAN_ACC_Y,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ },
IIO_CHAN_SOFT_TIMESTAMP(5),
};
@@ -498,7 +545,7 @@ static int __devinit adis16204_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -551,7 +598,7 @@ error_uninitialize_ring:
error_unreg_ring_funcs:
adis16204_unconfigure_ring(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -564,7 +611,7 @@ static int adis16204_remove(struct spi_device *spi)
adis16204_remove_trigger(indio_dev);
iio_buffer_unregister(indio_dev);
adis16204_unconfigure_ring(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/accel/adis16204_ring.c b/drivers/staging/iio/accel/adis16204_ring.c
index 5c8ab7338864..f73518bc6587 100644
--- a/drivers/staging/iio/accel/adis16204_ring.c
+++ b/drivers/staging/iio/accel/adis16204_ring.c
@@ -5,20 +5,19 @@
#include <linux/spi/spi.h>
#include <linux/slab.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
#include "adis16204.h"
/**
* adis16204_read_ring_data() read data registers which will be placed into ring
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @indio_dev: the IIO device
* @rx: somewhere to pass back the value read
**/
-static int adis16204_read_ring_data(struct device *dev, u8 *rx)
+static int adis16204_read_ring_data(struct iio_dev *indio_dev, u8 *rx)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct adis16204_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[ADIS16204_OUTPUTS + 1];
int ret;
@@ -63,22 +62,21 @@ static irqreturn_t adis16204_trigger_handler(int irq, void *p)
struct iio_buffer *ring = indio_dev->buffer;
int i = 0;
s16 *data;
- size_t datasize = ring->access->get_bytes_per_datum(ring);
- data = kmalloc(datasize, GFP_KERNEL);
+ data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL) {
dev_err(&st->us->dev, "memory alloc failed in ring bh");
return -ENOMEM;
}
if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) &&
- adis16204_read_ring_data(&indio_dev->dev, st->rx) >= 0)
+ adis16204_read_ring_data(indio_dev, st->rx) >= 0)
for (; i < bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength); i++)
data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
- if (ring->scan_timestamp)
+ if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
ring->access->store_to(ring, (u8 *)data, pf->timestamp);
diff --git a/drivers/staging/iio/accel/adis16204_trigger.c b/drivers/staging/iio/accel/adis16204_trigger.c
index 6e542af02c09..408a1682368e 100644
--- a/drivers/staging/iio/accel/adis16204_trigger.c
+++ b/drivers/staging/iio/accel/adis16204_trigger.c
@@ -3,8 +3,8 @@
#include <linux/spi/spi.h>
#include <linux/export.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
#include "adis16204.h"
/**
@@ -29,7 +29,7 @@ int adis16204_probe_trigger(struct iio_dev *indio_dev)
int ret;
struct adis16204_state *st = iio_priv(indio_dev);
- st->trig = iio_allocate_trigger("adis16204-dev%d", indio_dev->id);
+ st->trig = iio_trigger_alloc("adis16204-dev%d", indio_dev->id);
if (st->trig == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -58,7 +58,7 @@ int adis16204_probe_trigger(struct iio_dev *indio_dev)
error_free_irq:
free_irq(st->us->irq, st->trig);
error_free_trig:
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
error_ret:
return ret;
}
@@ -69,5 +69,5 @@ void adis16204_remove_trigger(struct iio_dev *indio_dev)
iio_trigger_unregister(state->trig);
free_irq(state->us->irq, state->trig);
- iio_free_trigger(state->trig);
+ iio_trigger_free(state->trig);
}
diff --git a/drivers/staging/iio/accel/adis16209_core.c b/drivers/staging/iio/accel/adis16209_core.c
index a98715f6bd6d..f6fd0d31d4f0 100644
--- a/drivers/staging/iio/accel/adis16209_core.c
+++ b/drivers/staging/iio/accel/adis16209_core.c
@@ -16,9 +16,9 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "adis16209.h"
@@ -157,7 +157,7 @@ static ssize_t adis16209_write_reset(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
if (len < 1)
return -EINVAL;
@@ -331,7 +331,7 @@ static int adis16209_read_raw(struct iio_dev *indio_dev,
s16 val16;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
addr = adis16209_addresses[chan->address][0];
ret = adis16209_spi_read_reg_16(indio_dev, addr, &val16);
@@ -408,41 +408,114 @@ static int adis16209_read_raw(struct iio_dev *indio_dev,
}
static struct iio_chan_spec adis16209_channels[] = {
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- in_supply, ADIS16209_SCAN_SUPPLY,
- IIO_ST('u', 14, 16, 0), 0),
- IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
- temp, ADIS16209_SCAN_TEMP,
- IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X,
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
- accel_x, ADIS16209_SCAN_ACC_X,
- IIO_ST('s', 14, 16, 0), 0),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y,
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
- accel_y, ADIS16209_SCAN_ACC_Y,
- IIO_ST('s', 14, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- in_aux, ADIS16209_SCAN_AUX_ADC,
- IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_X,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- incli_x, ADIS16209_SCAN_INCLI_X,
- IIO_ST('s', 14, 16, 0), 0),
- IIO_CHAN(IIO_INCLI, 1, 0, 0, NULL, 0, IIO_MOD_Y,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- incli_y, ADIS16209_SCAN_INCLI_Y,
- IIO_ST('s', 14, 16, 0), 0),
- IIO_CHAN(IIO_ROT, 0, 1, 0, NULL, 0, IIO_MOD_X,
- 0,
- rot, ADIS16209_SCAN_ROT,
- IIO_ST('s', 14, 16, 0), 0),
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .extend_name = "supply",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .address = in_supply,
+ .scan_index = ADIS16209_SCAN_SUPPLY,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_TEMP,
+ .indexed = 0,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT,
+ .address = temp,
+ .scan_index = ADIS16209_SCAN_TEMP,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_ACCEL,
+ .modified = 1,
+ .channel2 = IIO_MOD_X,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+ .address = accel_x,
+ .scan_index = ADIS16209_SCAN_ACC_X,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_ACCEL,
+ .modified = 1,
+ .channel2 = IIO_MOD_Y,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+ .address = accel_y,
+ .scan_index = ADIS16209_SCAN_ACC_Y,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .address = in_aux,
+ .scan_index = ADIS16209_SCAN_AUX_ADC,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_INCLI,
+ .modified = 1,
+ .channel2 = IIO_MOD_X,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = incli_x,
+ .scan_index = ADIS16209_SCAN_INCLI_X,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_INCLI,
+ .modified = 1,
+ .channel2 = IIO_MOD_Y,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = incli_y,
+ .scan_index = ADIS16209_SCAN_INCLI_Y,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_ROT,
+ .modified = 1,
+ .channel2 = IIO_MOD_X,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .address = rot,
+ .scan_index = ADIS16209_SCAN_ROT,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ },
IIO_CHAN_SOFT_TIMESTAMP(8)
};
@@ -471,7 +544,7 @@ static int __devinit adis16209_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -524,7 +597,7 @@ error_uninitialize_ring:
error_unreg_ring_funcs:
adis16209_unconfigure_ring(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -539,7 +612,7 @@ static int adis16209_remove(struct spi_device *spi)
adis16209_remove_trigger(indio_dev);
iio_buffer_unregister(indio_dev);
adis16209_unconfigure_ring(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/accel/adis16209_ring.c b/drivers/staging/iio/accel/adis16209_ring.c
index 57254b6b38b7..090607504c93 100644
--- a/drivers/staging/iio/accel/adis16209_ring.c
+++ b/drivers/staging/iio/accel/adis16209_ring.c
@@ -5,20 +5,19 @@
#include <linux/spi/spi.h>
#include <linux/slab.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
#include "adis16209.h"
/**
* adis16209_read_ring_data() read data registers which will be placed into ring
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @indio_dev: the IIO device
* @rx: somewhere to pass back the value read
**/
-static int adis16209_read_ring_data(struct device *dev, u8 *rx)
+static int adis16209_read_ring_data(struct iio_dev *indio_dev, u8 *rx)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct adis16209_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[ADIS16209_OUTPUTS + 1];
int ret;
@@ -61,25 +60,23 @@ static irqreturn_t adis16209_trigger_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16209_state *st = iio_priv(indio_dev);
struct iio_buffer *ring = indio_dev->buffer;
-
int i = 0;
s16 *data;
- size_t datasize = ring->access->get_bytes_per_datum(ring);
- data = kmalloc(datasize , GFP_KERNEL);
+ data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL) {
dev_err(&st->us->dev, "memory alloc failed in ring bh");
return -ENOMEM;
}
if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) &&
- adis16209_read_ring_data(&indio_dev->dev, st->rx) >= 0)
+ adis16209_read_ring_data(indio_dev, st->rx) >= 0)
for (; i < bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength); i++)
data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
- if (ring->scan_timestamp)
+ if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
ring->access->store_to(ring, (u8 *)data, pf->timestamp);
diff --git a/drivers/staging/iio/accel/adis16209_trigger.c b/drivers/staging/iio/accel/adis16209_trigger.c
index c5d82c1a55d9..2ad93dcaf40d 100644
--- a/drivers/staging/iio/accel/adis16209_trigger.c
+++ b/drivers/staging/iio/accel/adis16209_trigger.c
@@ -3,8 +3,8 @@
#include <linux/spi/spi.h>
#include <linux/export.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
#include "adis16209.h"
/**
@@ -38,7 +38,7 @@ int adis16209_probe_trigger(struct iio_dev *indio_dev)
int ret;
struct adis16209_state *st = iio_priv(indio_dev);
- st->trig = iio_allocate_trigger("adis16209-dev%d", indio_dev->id);
+ st->trig = iio_trigger_alloc("adis16209-dev%d", indio_dev->id);
if (st->trig == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -66,7 +66,7 @@ int adis16209_probe_trigger(struct iio_dev *indio_dev)
error_free_irq:
free_irq(st->us->irq, st->trig);
error_free_trig:
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
error_ret:
return ret;
}
@@ -77,5 +77,5 @@ void adis16209_remove_trigger(struct iio_dev *indio_dev)
iio_trigger_unregister(st->trig);
free_irq(st->us->irq, st->trig);
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
}
diff --git a/drivers/staging/iio/accel/adis16220_core.c b/drivers/staging/iio/accel/adis16220_core.c
index 51a852d45482..6a9ac898cb01 100644
--- a/drivers/staging/iio/accel/adis16220_core.c
+++ b/drivers/staging/iio/accel/adis16220_core.c
@@ -15,8 +15,8 @@
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "adis16220.h"
@@ -145,7 +145,7 @@ static ssize_t adis16220_read_16bit(struct device *dev,
char *buf)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
ssize_t ret;
s16 val = 0;
@@ -164,7 +164,7 @@ static ssize_t adis16220_write_16bit(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
u16 val;
@@ -208,7 +208,7 @@ static ssize_t adis16220_write_reset(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
bool val;
int ret;
@@ -228,7 +228,7 @@ static ssize_t adis16220_write_capture(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
bool val;
int ret;
@@ -393,7 +393,7 @@ static ssize_t adis16220_accel_bin_read(struct file *filp, struct kobject *kobj,
size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
return adis16220_capture_buffer_read(indio_dev, buf,
off, count,
@@ -415,7 +415,7 @@ static ssize_t adis16220_adc1_bin_read(struct file *filp, struct kobject *kobj,
size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
return adis16220_capture_buffer_read(indio_dev, buf,
off, count,
@@ -437,7 +437,7 @@ static ssize_t adis16220_adc2_bin_read(struct file *filp, struct kobject *kobj,
size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
return adis16220_capture_buffer_read(indio_dev, buf,
off, count,
@@ -507,7 +507,7 @@ static int adis16220_read_raw(struct iio_dev *indio_dev,
u8 bits;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
addrind = 0;
break;
case IIO_CHAN_INFO_OFFSET:
@@ -575,11 +575,13 @@ static const struct iio_chan_spec adis16220_channels[] = {
.indexed = 1,
.channel = 0,
.extend_name = "supply",
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = in_supply,
}, {
.type = IIO_ACCEL,
- .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
IIO_CHAN_INFO_PEAK_SEPARATE_BIT,
.address = accel,
@@ -587,20 +589,23 @@ static const struct iio_chan_spec adis16220_channels[] = {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = temp,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = in_1,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 2,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.address = in_2,
}
};
@@ -629,7 +634,7 @@ static int __devinit adis16220_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -680,7 +685,7 @@ error_rm_accel_bin:
error_unregister_dev:
iio_device_unregister(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -695,7 +700,7 @@ static int adis16220_remove(struct spi_device *spi)
sysfs_remove_bin_file(&indio_dev->dev.kobj, &adc1_bin);
sysfs_remove_bin_file(&indio_dev->dev.kobj, &accel_bin);
iio_device_unregister(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/accel/adis16240_core.c b/drivers/staging/iio/accel/adis16240_core.c
index 17f77fef7f2b..8b15eaea3381 100644
--- a/drivers/staging/iio/accel/adis16240_core.c
+++ b/drivers/staging/iio/accel/adis16240_core.c
@@ -19,9 +19,9 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "adis16240.h"
@@ -154,7 +154,7 @@ static ssize_t adis16240_spi_read_signed(struct device *dev,
char *buf,
unsigned bits)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
int ret;
s16 val = 0;
unsigned shift = 16 - bits;
@@ -177,7 +177,7 @@ static ssize_t adis16240_read_12bit_signed(struct device *dev,
char *buf)
{
ssize_t ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
/* Take the iio_dev status lock */
mutex_lock(&indio_dev->mlock);
@@ -203,7 +203,7 @@ static ssize_t adis16240_write_reset(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
if (len < 1)
return -EINVAL;
@@ -365,7 +365,7 @@ static int adis16240_read_raw(struct iio_dev *indio_dev,
s16 val16;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
addr = adis16240_addresses[chan->address][0];
ret = adis16240_spi_read_reg_16(indio_dev, addr, &val16);
@@ -468,33 +468,88 @@ static int adis16240_write_raw(struct iio_dev *indio_dev,
}
static struct iio_chan_spec adis16240_channels[] = {
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "supply", 0, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- in_supply, ADIS16240_SCAN_SUPPLY,
- IIO_ST('u', 10, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0,
- 0,
- in_aux, ADIS16240_SCAN_AUX_ADC,
- IIO_ST('u', 10, 16, 0), 0),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X,
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
- accel_x, ADIS16240_SCAN_ACC_X,
- IIO_ST('s', 10, 16, 0), 0),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y,
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
- accel_y, ADIS16240_SCAN_ACC_Y,
- IIO_ST('s', 10, 16, 0), 0),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Z,
- IIO_CHAN_INFO_SCALE_SHARED_BIT |
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
- accel_z, ADIS16240_SCAN_ACC_Z,
- IIO_ST('s', 10, 16, 0), 0),
- IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- temp, ADIS16240_SCAN_TEMP,
- IIO_ST('u', 10, 16, 0), 0),
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .extend_name = "supply",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .address = in_supply,
+ .scan_index = ADIS16240_SCAN_SUPPLY,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 10,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .address = in_aux,
+ .scan_index = ADIS16240_SCAN_AUX_ADC,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 10,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_ACCEL,
+ .modified = 1,
+ .channel2 = IIO_MOD_X,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+ .address = accel_x,
+ .scan_index = ADIS16240_SCAN_ACC_X,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 10,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_ACCEL,
+ .modified = 1,
+ .channel2 = IIO_MOD_Y,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+ .address = accel_y,
+ .scan_index = ADIS16240_SCAN_ACC_Y,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 10,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_ACCEL,
+ .modified = 1,
+ .channel2 = IIO_MOD_Z,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+ .address = accel_z,
+ .scan_index = ADIS16240_SCAN_ACC_Z,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 10,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_TEMP,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .address = temp,
+ .scan_index = ADIS16240_SCAN_TEMP,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 10,
+ .storagebits = 16,
+ },
+ },
IIO_CHAN_SOFT_TIMESTAMP(6)
};
@@ -523,7 +578,7 @@ static int __devinit adis16240_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -576,7 +631,7 @@ error_uninitialize_ring:
error_unreg_ring_funcs:
adis16240_unconfigure_ring(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -592,7 +647,7 @@ static int adis16240_remove(struct spi_device *spi)
adis16240_remove_trigger(indio_dev);
iio_buffer_unregister(indio_dev);
adis16240_unconfigure_ring(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/accel/adis16240_ring.c b/drivers/staging/iio/accel/adis16240_ring.c
index 43ba84e993ad..86a2a4757ea7 100644
--- a/drivers/staging/iio/accel/adis16240_ring.c
+++ b/drivers/staging/iio/accel/adis16240_ring.c
@@ -5,20 +5,19 @@
#include <linux/spi/spi.h>
#include <linux/slab.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
#include "adis16240.h"
/**
* adis16240_read_ring_data() read data registers which will be placed into ring
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @indio_dev: the IIO device
* @rx: somewhere to pass back the value read
**/
-static int adis16240_read_ring_data(struct device *dev, u8 *rx)
+static int adis16240_read_ring_data(struct iio_dev *indio_dev, u8 *rx)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct adis16240_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[ADIS16240_OUTPUTS + 1];
int ret;
@@ -61,22 +60,21 @@ static irqreturn_t adis16240_trigger_handler(int irq, void *p)
int i = 0;
s16 *data;
- size_t datasize = ring->access->get_bytes_per_datum(ring);
- data = kmalloc(datasize, GFP_KERNEL);
+ data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL) {
dev_err(&st->us->dev, "memory alloc failed in ring bh");
return -ENOMEM;
}
if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) &&
- adis16240_read_ring_data(&indio_dev->dev, st->rx) >= 0)
+ adis16240_read_ring_data(indio_dev, st->rx) >= 0)
for (; i < bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength); i++)
data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
- if (ring->scan_timestamp)
+ if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
ring->access->store_to(ring, (u8 *)data, pf->timestamp);
diff --git a/drivers/staging/iio/accel/adis16240_trigger.c b/drivers/staging/iio/accel/adis16240_trigger.c
index 8e0ce568e64c..fa90a22b143e 100644
--- a/drivers/staging/iio/accel/adis16240_trigger.c
+++ b/drivers/staging/iio/accel/adis16240_trigger.c
@@ -3,8 +3,8 @@
#include <linux/spi/spi.h>
#include <linux/export.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
#include "adis16240.h"
/**
@@ -38,7 +38,7 @@ int adis16240_probe_trigger(struct iio_dev *indio_dev)
int ret;
struct adis16240_state *st = iio_priv(indio_dev);
- st->trig = iio_allocate_trigger("adis16240-dev%d", indio_dev->id);
+ st->trig = iio_trigger_alloc("adis16240-dev%d", indio_dev->id);
if (st->trig == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -67,7 +67,7 @@ int adis16240_probe_trigger(struct iio_dev *indio_dev)
error_free_irq:
free_irq(st->us->irq, st->trig);
error_free_trig:
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
error_ret:
return ret;
}
@@ -78,5 +78,5 @@ void adis16240_remove_trigger(struct iio_dev *indio_dev)
iio_trigger_unregister(st->trig);
free_irq(st->us->irq, st->trig);
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
}
diff --git a/drivers/staging/iio/accel/kxsd9.c b/drivers/staging/iio/accel/kxsd9.c
index d13d7215ff6e..8cf7cd943c90 100644
--- a/drivers/staging/iio/accel/kxsd9.c
+++ b/drivers/staging/iio/accel/kxsd9.c
@@ -23,8 +23,8 @@
#include <linux/slab.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#define KXSD9_REG_X 0x00
#define KXSD9_REG_Y 0x02
@@ -158,7 +158,7 @@ static int kxsd9_read_raw(struct iio_dev *indio_dev,
struct kxsd9_state *st = iio_priv(indio_dev);
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
ret = kxsd9_read(indio_dev, chan->address);
if (ret < 0)
goto error_ret;
@@ -181,7 +181,8 @@ error_ret:
.type = IIO_ACCEL, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
.address = KXSD9_REG_##axis, \
}
@@ -189,6 +190,7 @@ static struct iio_chan_spec kxsd9_channels[] = {
KXSD9_ACCEL_CHAN(X), KXSD9_ACCEL_CHAN(Y), KXSD9_ACCEL_CHAN(Z),
{
.type = IIO_VOLTAGE,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.indexed = 1,
.address = KXSD9_REG_AUX,
}
@@ -226,7 +228,7 @@ static int __devinit kxsd9_probe(struct spi_device *spi)
struct kxsd9_state *st;
int ret = 0;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -254,7 +256,7 @@ static int __devinit kxsd9_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -262,7 +264,7 @@ error_ret:
static int __devexit kxsd9_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c
index 376da5137967..9d263484fb86 100644
--- a/drivers/staging/iio/accel/lis3l02dq_core.c
+++ b/drivers/staging/iio/accel/lis3l02dq_core.c
@@ -23,10 +23,10 @@
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/buffer.h>
#include "lis3l02dq.h"
@@ -257,7 +257,7 @@ static int lis3l02dq_read_raw(struct iio_dev *indio_dev,
u8 reg;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
/* Take the iio_dev status lock */
mutex_lock(&indio_dev->mlock);
if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
@@ -297,7 +297,7 @@ static ssize_t lis3l02dq_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
int ret, len = 0;
s8 t;
ret = lis3l02dq_spi_read_reg_8(indio_dev,
@@ -328,7 +328,7 @@ static ssize_t lis3l02dq_write_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
unsigned long val;
int ret;
u8 t;
@@ -513,7 +513,8 @@ static irqreturn_t lis3l02dq_event_handler(int irq, void *private)
}
#define LIS3L02DQ_INFO_MASK \
- (IIO_CHAN_INFO_SCALE_SHARED_BIT | \
+ (IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT | \
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT)
@@ -521,13 +522,26 @@ static irqreturn_t lis3l02dq_event_handler(int irq, void *private)
(IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | \
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING))
+#define LIS3L02DQ_CHAN(index, mod) \
+ { \
+ .type = IIO_ACCEL, \
+ .modified = 1, \
+ .channel2 = mod, \
+ .info_mask = LIS3L02DQ_INFO_MASK, \
+ .address = index, \
+ .scan_index = index, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ }, \
+ .event_mask = LIS3L02DQ_EVENT_MASK, \
+ }
+
static struct iio_chan_spec lis3l02dq_channels[] = {
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X, LIS3L02DQ_INFO_MASK,
- 0, 0, IIO_ST('s', 12, 16, 0), LIS3L02DQ_EVENT_MASK),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y, LIS3L02DQ_INFO_MASK,
- 1, 1, IIO_ST('s', 12, 16, 0), LIS3L02DQ_EVENT_MASK),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Z, LIS3L02DQ_INFO_MASK,
- 2, 2, IIO_ST('s', 12, 16, 0), LIS3L02DQ_EVENT_MASK),
+ LIS3L02DQ_CHAN(0, IIO_MOD_X),
+ LIS3L02DQ_CHAN(1, IIO_MOD_Y),
+ LIS3L02DQ_CHAN(2, IIO_MOD_Z),
IIO_CHAN_SOFT_TIMESTAMP(3)
};
@@ -666,7 +680,7 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi)
struct lis3l02dq_state *st;
struct iio_dev *indio_dev;
- indio_dev = iio_allocate_device(sizeof *st);
+ indio_dev = iio_device_alloc(sizeof *st);
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -724,7 +738,7 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi)
return 0;
error_remove_trigger:
- if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
+ if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)))
lis3l02dq_remove_trigger(indio_dev);
error_free_interrupt:
if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0)
@@ -734,7 +748,7 @@ error_uninitialize_buffer:
error_unreg_buffer_funcs:
lis3l02dq_unconfigure_buffer(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -789,7 +803,7 @@ static int lis3l02dq_remove(struct spi_device *spi)
iio_buffer_unregister(indio_dev);
lis3l02dq_unconfigure_buffer(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
err_ret:
return ret;
}
diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c
index 0fc3973f32ae..51b00dfc0465 100644
--- a/drivers/staging/iio/accel/lis3l02dq_ring.c
+++ b/drivers/staging/iio/accel/lis3l02dq_ring.c
@@ -6,11 +6,11 @@
#include <linux/slab.h>
#include <linux/export.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "../ring_sw.h"
-#include "../kfifo_buf.h"
-#include "../trigger.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
#include "lis3l02dq.h"
/**
@@ -137,9 +137,9 @@ static irqreturn_t lis3l02dq_trigger_handler(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct iio_buffer *buffer = indio_dev->buffer;
int len = 0;
- size_t datasize = buffer->access->get_bytes_per_datum(buffer);
- char *data = kmalloc(datasize, GFP_KERNEL);
+ char *data;
+ data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL) {
dev_err(indio_dev->dev.parent,
"memory alloc failed in buffer bh");
@@ -150,7 +150,7 @@ static irqreturn_t lis3l02dq_trigger_handler(int irq, void *p)
len = lis3l02dq_get_buffer_element(indio_dev, data);
/* Guaranteed to be aligned with 8 byte boundary */
- if (buffer->scan_timestamp)
+ if (indio_dev->scan_timestamp)
*(s64 *)(((phys_addr_t)data + len
+ sizeof(s64) - 1) & ~(sizeof(s64) - 1))
= pf->timestamp;
@@ -163,12 +163,11 @@ static irqreturn_t lis3l02dq_trigger_handler(int irq, void *p)
/* Caller responsible for locking as necessary. */
static int
-__lis3l02dq_write_data_ready_config(struct device *dev, bool state)
+__lis3l02dq_write_data_ready_config(struct iio_dev *indio_dev, bool state)
{
int ret;
u8 valold;
bool currentlyset;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct lis3l02dq_state *st = iio_priv(indio_dev);
/* Get the current event mask register */
@@ -236,7 +235,7 @@ static int lis3l02dq_data_rdy_trigger_set_state(struct iio_trigger *trig,
int ret = 0;
u8 t;
- __lis3l02dq_write_data_ready_config(&indio_dev->dev, state);
+ __lis3l02dq_write_data_ready_config(indio_dev, state);
if (state == false) {
/*
* A possible quirk with the handler is currently worked around
@@ -286,7 +285,7 @@ int lis3l02dq_probe_trigger(struct iio_dev *indio_dev)
int ret;
struct lis3l02dq_state *st = iio_priv(indio_dev);
- st->trig = iio_allocate_trigger("lis3l02dq-dev%d", indio_dev->id);
+ st->trig = iio_trigger_alloc("lis3l02dq-dev%d", indio_dev->id);
if (!st->trig) {
ret = -ENOMEM;
goto error_ret;
@@ -302,7 +301,7 @@ int lis3l02dq_probe_trigger(struct iio_dev *indio_dev)
return 0;
error_free_trig:
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
error_ret:
return ret;
}
@@ -312,7 +311,7 @@ void lis3l02dq_remove_trigger(struct iio_dev *indio_dev)
struct lis3l02dq_state *st = iio_priv(indio_dev);
iio_trigger_unregister(st->trig);
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
}
void lis3l02dq_unconfigure_buffer(struct iio_dev *indio_dev)
diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c
index 49764fb7181c..6ec5c204ff1d 100644
--- a/drivers/staging/iio/accel/sca3000_core.c
+++ b/drivers/staging/iio/accel/sca3000_core.c
@@ -18,10 +18,10 @@
#include <linux/spi/spi.h>
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/buffer.h>
#include "sca3000.h"
@@ -241,7 +241,7 @@ error_ret:
static int sca3000_check_status(struct device *dev)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
mutex_lock(&st->lock);
@@ -268,7 +268,7 @@ static ssize_t sca3000_show_rev(struct device *dev,
char *buf)
{
int len = 0, ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
mutex_lock(&st->lock);
@@ -296,7 +296,7 @@ sca3000_show_available_measurement_modes(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
int len = 0;
@@ -328,7 +328,7 @@ sca3000_show_measurement_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
int len = 0, ret;
@@ -379,7 +379,7 @@ sca3000_store_measurement_mode(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
int ret;
u8 mask = 0x03;
@@ -429,17 +429,31 @@ static IIO_DEVICE_ATTR(measurement_mode, S_IRUGO | S_IWUSR,
static IIO_DEVICE_ATTR(revision, S_IRUGO, sca3000_show_rev, NULL, 0);
#define SCA3000_INFO_MASK \
- IIO_CHAN_INFO_SCALE_SHARED_BIT
+ IIO_CHAN_INFO_RAW_SEPARATE_BIT | IIO_CHAN_INFO_SCALE_SHARED_BIT
#define SCA3000_EVENT_MASK \
(IIO_EV_BIT(IIO_EV_TYPE_MAG, IIO_EV_DIR_RISING))
+#define SCA3000_CHAN(index, mod) \
+ { \
+ .type = IIO_ACCEL, \
+ .modified = 1, \
+ .channel2 = mod, \
+ .info_mask = SCA3000_INFO_MASK, \
+ .address = index, \
+ .scan_index = index, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 11, \
+ .storagebits = 16, \
+ .shift = 5, \
+ }, \
+ .event_mask = SCA3000_EVENT_MASK, \
+ }
+
static struct iio_chan_spec sca3000_channels[] = {
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_X, SCA3000_INFO_MASK,
- 0, 0, IIO_ST('s', 11, 16, 5), SCA3000_EVENT_MASK),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Y, SCA3000_INFO_MASK,
- 1, 1, IIO_ST('s', 11, 16, 5), SCA3000_EVENT_MASK),
- IIO_CHAN(IIO_ACCEL, 1, 0, 0, NULL, 0, IIO_MOD_Z, SCA3000_INFO_MASK,
- 2, 2, IIO_ST('s', 11, 16, 5), SCA3000_EVENT_MASK),
+ SCA3000_CHAN(0, IIO_MOD_X),
+ SCA3000_CHAN(1, IIO_MOD_Y),
+ SCA3000_CHAN(2, IIO_MOD_Z),
};
static u8 sca3000_addresses[3][3] = {
@@ -462,7 +476,7 @@ static int sca3000_read_raw(struct iio_dev *indio_dev,
u8 address;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&st->lock);
if (st->mo_det_use_count) {
mutex_unlock(&st->lock);
@@ -503,7 +517,7 @@ static ssize_t sca3000_read_av_freq(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
int len = 0, ret, val;
@@ -574,7 +588,7 @@ static ssize_t sca3000_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
int ret, len = 0, base_freq = 0, val;
@@ -616,7 +630,7 @@ static ssize_t sca3000_set_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
int ret, base_freq = 0;
int ctrlval;
@@ -676,7 +690,7 @@ static ssize_t sca3000_read_temp(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
int ret;
int val;
@@ -897,7 +911,7 @@ static ssize_t sca3000_query_free_fall_mode(struct device *dev,
char *buf)
{
int ret, len;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
int val;
@@ -925,7 +939,7 @@ static ssize_t sca3000_set_free_fall_mode(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
long val;
int ret;
@@ -1131,7 +1145,7 @@ static int __devinit sca3000_probe(struct spi_device *spi)
struct sca3000_state *st;
struct iio_dev *indio_dev;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -1195,7 +1209,7 @@ error_unregister_ring:
error_unregister_dev:
iio_device_unregister(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
@@ -1233,7 +1247,7 @@ static int sca3000_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
iio_buffer_unregister(indio_dev);
sca3000_unconfigure_ring(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c
index 6b824a11f7f4..b7e1a002630a 100644
--- a/drivers/staging/iio/accel/sca3000_ring.c
+++ b/drivers/staging/iio/accel/sca3000_ring.c
@@ -18,9 +18,9 @@
#include <linux/sched.h>
#include <linux/poll.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "../ring_hw.h"
#include "sca3000.h"
@@ -157,7 +157,7 @@ static ssize_t sca3000_query_ring_int(struct device *dev,
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret, val;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
mutex_lock(&st->lock);
@@ -178,7 +178,7 @@ static ssize_t sca3000_set_ring_int(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
long val;
@@ -219,7 +219,7 @@ static ssize_t sca3000_show_buffer_scale(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct sca3000_state *st = iio_priv(indio_dev);
return sprintf(buf, "0.%06d\n", 4*st->info->scale);
diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig
index 592eabd85f36..2490dd25093b 100644
--- a/drivers/staging/iio/adc/Kconfig
+++ b/drivers/staging/iio/adc/Kconfig
@@ -25,7 +25,7 @@ config AD7606
depends on GPIOLIB
select IIO_BUFFER
select IIO_TRIGGER
- select IIO_SW_RING
+ select IIO_KFIFO_BUF
help
Say yes here to build support for Analog Devices:
ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC).
@@ -63,7 +63,7 @@ config AD799X_RING_BUFFER
bool "Analog Devices AD799x: use ring buffer"
depends on AD799X
select IIO_BUFFER
- select IIO_SW_RING
+ select IIO_KFIFO_BUF
help
Say yes here to include ring buffer support in the AD799X
ADC driver.
@@ -72,7 +72,7 @@ config AD7476
tristate "Analog Devices AD7475/6/7/8 AD7466/7/8 and AD7495 ADC driver"
depends on SPI
select IIO_BUFFER
- select IIO_SW_RING
+ select IIO_KFIFO_BUF
select IIO_TRIGGER
help
Say yes here to build support for Analog Devices
@@ -87,7 +87,7 @@ config AD7887
tristate "Analog Devices AD7887 ADC driver"
depends on SPI
select IIO_BUFFER
- select IIO_SW_RING
+ select IIO_KFIFO_BUF
select IIO_TRIGGER
help
Say yes here to build support for Analog Devices
@@ -113,7 +113,7 @@ config AD7793
tristate "Analog Devices AD7792 AD7793 ADC driver"
depends on SPI
select IIO_BUFFER
- select IIO_SW_RING
+ select IIO_KFIFO_BUF
select IIO_TRIGGER
help
Say yes here to build support for Analog Devices
@@ -135,7 +135,7 @@ config AD7192
tristate "Analog Devices AD7190 AD7192 AD7195 ADC driver"
depends on SPI
select IIO_BUFFER
- select IIO_SW_RING
+ select IIO_KFIFO_BUF
select IIO_TRIGGER
help
Say yes here to build support for Analog Devices AD7190,
@@ -195,11 +195,20 @@ config MAX1363_RING_BUFFER
config LPC32XX_ADC
tristate "NXP LPC32XX ADC"
- depends on ARCH_LPC32XX && !TOUCHSCREEN_LPC32XX
+ depends on ARCH_LPC32XX
help
Say yes here to build support for the integrated ADC inside the
LPC32XX SoC. Note that this feature uses the same hardware as the
- touchscreen driver, so you can only select one of the two drivers
- (lpc32xx_adc or lpc32xx_ts). Provides direct access via sysfs.
+ touchscreen driver, so you should either select only one of the two
+ drivers (lpc32xx_adc or lpc32xx_ts) or, in the OpenFirmware case,
+ activate only one via device tree selection. Provides direct access
+ via sysfs.
+
+config SPEAR_ADC
+ tristate "ST SPEAr ADC"
+ depends on PLAT_SPEAR
+ help
+ Say yes here to build support for the integrated ADC inside the
+ ST SPEAr SoC. Provides direct access via sysfs.
endmenu
diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile
index f83ab9551d8e..14e98b62b70a 100644
--- a/drivers/staging/iio/adc/Makefile
+++ b/drivers/staging/iio/adc/Makefile
@@ -38,3 +38,4 @@ obj-$(CONFIG_ADT7310) += adt7310.o
obj-$(CONFIG_ADT7410) += adt7410.o
obj-$(CONFIG_AD7280) += ad7280a.o
obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
+obj-$(CONFIG_SPEAR_ADC) += spear_adc.o
diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c
index 9fd6d63d2999..5eaeaf1f0ae8 100644
--- a/drivers/staging/iio/adc/ad7192.c
+++ b/drivers/staging/iio/adc/ad7192.c
@@ -1,7 +1,7 @@
/*
* AD7190 AD7192 AD7195 SPI ADC driver
*
- * Copyright 2011 Analog Devices Inc.
+ * Copyright 2011-2012 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
@@ -17,12 +17,12 @@
#include <linux/sched.h>
#include <linux/delay.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
-#include "../ring_sw.h"
-#include "../trigger.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
#include "ad7192.h"
@@ -456,31 +456,19 @@ out:
static int ad7192_ring_preenable(struct iio_dev *indio_dev)
{
struct ad7192_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
- size_t d_size;
unsigned channel;
+ int ret;
if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
return -EINVAL;
+ ret = iio_sw_buffer_preenable(indio_dev);
+ if (ret < 0)
+ return ret;
+
channel = find_first_bit(indio_dev->active_scan_mask,
indio_dev->masklength);
- d_size = bitmap_weight(indio_dev->active_scan_mask,
- indio_dev->masklength) *
- indio_dev->channels[0].scan_type.storagebits / 8;
-
- if (ring->scan_timestamp) {
- d_size += sizeof(s64);
-
- if (d_size % sizeof(s64))
- d_size += sizeof(s64) - (d_size % sizeof(s64));
- }
-
- if (indio_dev->buffer->access->set_bytes_per_datum)
- indio_dev->buffer->access->
- set_bytes_per_datum(indio_dev->buffer, d_size);
-
st->mode = (st->mode & ~AD7192_MODE_SEL(-1)) |
AD7192_MODE_SEL(AD7192_MODE_CONT);
st->conf = (st->conf & ~AD7192_CONF_CHAN(-1)) |
@@ -533,7 +521,7 @@ static irqreturn_t ad7192_trigger_handler(int irq, void *p)
indio_dev->channels[0].scan_type.realbits/8);
/* Guaranteed to be aligned with 8 byte boundary */
- if (ring->scan_timestamp)
+ if (indio_dev->scan_timestamp)
dat64[1] = pf->timestamp;
ring->access->store_to(ring, (u8 *)dat64, pf->timestamp);
@@ -556,7 +544,7 @@ static int ad7192_register_ring_funcs_and_init(struct iio_dev *indio_dev)
{
int ret;
- indio_dev->buffer = iio_sw_rb_allocate(indio_dev);
+ indio_dev->buffer = iio_kfifo_allocate(indio_dev);
if (!indio_dev->buffer) {
ret = -ENOMEM;
goto error_ret;
@@ -569,7 +557,7 @@ static int ad7192_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->id);
if (indio_dev->pollfunc == NULL) {
ret = -ENOMEM;
- goto error_deallocate_sw_rb;
+ goto error_deallocate_kfifo;
}
/* Ring buffer functions - here trigger setup related */
@@ -579,8 +567,8 @@ static int ad7192_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
return 0;
-error_deallocate_sw_rb:
- iio_sw_rb_free(indio_dev->buffer);
+error_deallocate_kfifo:
+ iio_kfifo_free(indio_dev->buffer);
error_ret:
return ret;
}
@@ -588,7 +576,7 @@ error_ret:
static void ad7192_ring_cleanup(struct iio_dev *indio_dev)
{
iio_dealloc_pollfunc(indio_dev->pollfunc);
- iio_sw_rb_free(indio_dev->buffer);
+ iio_kfifo_free(indio_dev->buffer);
}
/**
@@ -616,7 +604,7 @@ static int ad7192_probe_trigger(struct iio_dev *indio_dev)
struct ad7192_state *st = iio_priv(indio_dev);
int ret;
- st->trig = iio_allocate_trigger("%s-dev%d",
+ st->trig = iio_trigger_alloc("%s-dev%d",
spi_get_device_id(st->spi)->name,
indio_dev->id);
if (st->trig == NULL) {
@@ -649,7 +637,7 @@ static int ad7192_probe_trigger(struct iio_dev *indio_dev)
error_free_irq:
free_irq(st->spi->irq, indio_dev);
error_free_trig:
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
error_ret:
return ret;
}
@@ -660,14 +648,14 @@ static void ad7192_remove_trigger(struct iio_dev *indio_dev)
iio_trigger_unregister(st->trig);
free_irq(st->spi->irq, indio_dev);
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
}
static ssize_t ad7192_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7192_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", st->mclk /
@@ -679,7 +667,7 @@ static ssize_t ad7192_write_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7192_state *st = iio_priv(indio_dev);
unsigned long lval;
int div, ret;
@@ -718,7 +706,7 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
static ssize_t ad7192_show_scale_available(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7192_state *st = iio_priv(indio_dev);
int i, len = 0;
@@ -742,7 +730,7 @@ static ssize_t ad7192_show_ac_excitation(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7192_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", !!(st->mode & AD7192_MODE_ACX));
@@ -752,7 +740,7 @@ static ssize_t ad7192_show_bridge_switch(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7192_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", !!(st->gpocon & AD7192_GPOCON_BPDSW));
@@ -763,7 +751,7 @@ static ssize_t ad7192_set(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7192_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
@@ -849,7 +837,7 @@ static int ad7192_read_raw(struct iio_dev *indio_dev,
bool unipolar = !!(st->conf & AD7192_CONF_UNIPOLAR);
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
@@ -981,7 +969,8 @@ static const struct iio_info ad7195_info = {
.extend_name = _name, \
.channel = _chan, \
.channel2 = _chan2, \
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
.address = _address, \
.scan_index = _si, \
.scan_type = IIO_ST('s', 24, 32, 0)}
@@ -990,7 +979,8 @@ static const struct iio_info ad7195_info = {
{ .type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = _chan, \
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
.address = _address, \
.scan_index = _si, \
.scan_type = IIO_ST('s', 24, 32, 0)}
@@ -999,7 +989,8 @@ static const struct iio_info ad7195_info = {
{ .type = IIO_TEMP, \
.indexed = 1, \
.channel = _chan, \
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
.address = _address, \
.scan_index = _si, \
.scan_type = IIO_ST('s', 24, 32, 0)}
@@ -1033,7 +1024,7 @@ static int __devinit ad7192_probe(struct spi_device *spi)
return -ENODEV;
}
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -1114,7 +1105,7 @@ error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c
index 7dbd6812c240..cfc39a703126 100644
--- a/drivers/staging/iio/adc/ad7280a.c
+++ b/drivers/staging/iio/adc/ad7280a.c
@@ -16,9 +16,9 @@
#include <linux/interrupt.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
#include "ad7280a.h"
@@ -384,7 +384,7 @@ static ssize_t ad7280_show_balance_sw(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7280_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -398,7 +398,7 @@ static ssize_t ad7280_store_balance_sw(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7280_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
bool readin;
@@ -429,7 +429,7 @@ static ssize_t ad7280_show_balance_timer(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7280_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
@@ -453,7 +453,7 @@ static ssize_t ad7280_store_balance_timer(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7280_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
unsigned long val;
@@ -508,6 +508,7 @@ static int ad7280_channel_init(struct ad7280_state *st)
}
st->channels[cnt].indexed = 1;
st->channels[cnt].info_mask =
+ IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT;
st->channels[cnt].address =
AD7280A_DEVADDR(dev) << 8 | ch;
@@ -524,7 +525,9 @@ static int ad7280_channel_init(struct ad7280_state *st)
st->channels[cnt].channel2 = dev * 6;
st->channels[cnt].address = AD7280A_ALL_CELLS;
st->channels[cnt].indexed = 1;
- st->channels[cnt].info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT;
+ st->channels[cnt].info_mask =
+ IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT;
st->channels[cnt].scan_index = cnt;
st->channels[cnt].scan_type.sign = 'u';
st->channels[cnt].scan_type.realbits = 32;
@@ -596,7 +599,7 @@ static ssize_t ad7280_read_channel_config(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7280_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
unsigned val;
@@ -626,7 +629,7 @@ static ssize_t ad7280_write_channel_config(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7280_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -788,7 +791,7 @@ static int ad7280_read_raw(struct iio_dev *indio_dev,
int ret;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (chan->address == AD7280A_ALL_CELLS)
ret = ad7280_read_all_channels(st, st->scan_cnt, NULL);
@@ -836,7 +839,7 @@ static int __devinit ad7280_probe(struct spi_device *spi)
int ret;
const unsigned short tACQ_ns[4] = {465, 1010, 1460, 1890};
const unsigned short nAVG[4] = {1, 2, 4, 8};
- struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+ struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -942,7 +945,7 @@ error_free_channels:
kfree(st->channels);
error_free_device:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -961,7 +964,7 @@ static int __devexit ad7280_remove(struct spi_device *spi)
kfree(st->channels);
kfree(st->iio_attr);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/ad7291.c b/drivers/staging/iio/adc/ad7291.c
index 81d6b6128cb0..029b39c0ba60 100644
--- a/drivers/staging/iio/adc/ad7291.c
+++ b/drivers/staging/iio/adc/ad7291.c
@@ -17,9 +17,9 @@
#include <linux/regulator/consumer.h>
#include <linux/err.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
/*
* Simplified handling
@@ -132,7 +132,7 @@ static ssize_t ad7291_store_reset(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7291_chip_info *chip = iio_priv(indio_dev);
return ad7291_i2c_write(chip, AD7291_COMMAND,
@@ -214,7 +214,7 @@ static inline ssize_t ad7291_show_hyst(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7291_chip_info *chip = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
u16 data;
@@ -232,7 +232,7 @@ static inline ssize_t ad7291_set_hyst(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7291_chip_info *chip = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
u16 data;
@@ -461,7 +461,7 @@ static int ad7291_read_raw(struct iio_dev *indio_dev,
s16 signval;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
switch (chan->type) {
case IIO_VOLTAGE:
mutex_lock(&chip->state_lock);
@@ -536,7 +536,8 @@ static int ad7291_read_raw(struct iio_dev *indio_dev,
#define AD7291_VOLTAGE_CHAN(_chan) \
{ \
.type = IIO_VOLTAGE, \
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
.indexed = 1, \
.channel = _chan, \
.event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING)|\
@@ -554,7 +555,8 @@ static const struct iio_chan_spec ad7291_channels[] = {
AD7291_VOLTAGE_CHAN(7),
{
.type = IIO_TEMP,
- .info_mask = IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.indexed = 1,
.channel = 0,
@@ -585,7 +587,7 @@ static int __devinit ad7291_probe(struct i2c_client *client,
struct iio_dev *indio_dev;
int ret = 0, voltage_uv = 0;
- indio_dev = iio_allocate_device(sizeof(*chip));
+ indio_dev = iio_device_alloc(sizeof(*chip));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -667,7 +669,7 @@ error_put_reg:
if (!IS_ERR(chip->reg))
regulator_put(chip->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -687,7 +689,7 @@ static int __devexit ad7291_remove(struct i2c_client *client)
regulator_put(chip->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/ad7298.h b/drivers/staging/iio/adc/ad7298.h
index a0e5dea415ef..5051a7e4d4fd 100644
--- a/drivers/staging/iio/adc/ad7298.h
+++ b/drivers/staging/iio/adc/ad7298.h
@@ -38,7 +38,6 @@ struct ad7298_platform_data {
struct ad7298_state {
struct spi_device *spi;
struct regulator *reg;
- size_t d_size;
u16 int_vref_mv;
unsigned ext_ref;
struct spi_transfer ring_xfer[10];
diff --git a/drivers/staging/iio/adc/ad7298_core.c b/drivers/staging/iio/adc/ad7298_core.c
index 8dd6aa9cf928..c90f2b3e661f 100644
--- a/drivers/staging/iio/adc/ad7298_core.c
+++ b/drivers/staging/iio/adc/ad7298_core.c
@@ -16,40 +16,51 @@
#include <linux/delay.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "ad7298.h"
+#define AD7298_V_CHAN(index) \
+ { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = index, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .address = index, \
+ .scan_index = index, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ }, \
+ }
+
static struct iio_chan_spec ad7298_channels[] = {
- IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- 9, AD7298_CH_TEMP, IIO_ST('s', 32, 32, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 0, 0, IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 1, 1, IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 2, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 2, 2, IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 3, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 3, 3, IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 4, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 4, 4, IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 5, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 5, 5, IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 6, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 6, 6, IIO_ST('u', 12, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 7, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 7, 7, IIO_ST('u', 12, 16, 0), 0),
+ {
+ .type = IIO_TEMP,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .address = 9,
+ .scan_index = AD7298_CH_TEMP,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 32,
+ .storagebits = 32,
+ },
+ },
+ AD7298_V_CHAN(0),
+ AD7298_V_CHAN(1),
+ AD7298_V_CHAN(2),
+ AD7298_V_CHAN(3),
+ AD7298_V_CHAN(4),
+ AD7298_V_CHAN(5),
+ AD7298_V_CHAN(6),
+ AD7298_V_CHAN(7),
IIO_CHAN_SOFT_TIMESTAMP(8),
};
@@ -121,7 +132,7 @@ static int ad7298_read_raw(struct iio_dev *indio_dev,
unsigned int scale_uv;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) {
ret = -EBUSY;
@@ -168,7 +179,7 @@ static int __devinit ad7298_probe(struct spi_device *spi)
struct ad7298_platform_data *pdata = spi->dev.platform_data;
struct ad7298_state *st;
int ret;
- struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+ struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -241,7 +252,7 @@ error_disable_reg:
error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -258,7 +269,7 @@ static int __devexit ad7298_remove(struct spi_device *spi)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/ad7298_ring.c b/drivers/staging/iio/adc/ad7298_ring.c
index feeb0eeba59a..908a3e5609df 100644
--- a/drivers/staging/iio/adc/ad7298_ring.c
+++ b/drivers/staging/iio/adc/ad7298_ring.c
@@ -1,7 +1,7 @@
/*
* AD7298 SPI ADC driver
*
- * Copyright 2011 Analog Devices Inc.
+ * Copyright 2011-2012 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
@@ -11,10 +11,10 @@
#include <linux/slab.h>
#include <linux/spi/spi.h>
-#include "../iio.h"
-#include "../buffer.h"
-#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger_consumer.h>
#include "ad7298.h"
@@ -28,25 +28,17 @@
static int ad7298_ring_preenable(struct iio_dev *indio_dev)
{
struct ad7298_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
- size_t d_size;
int i, m;
unsigned short command;
- int scan_count = bitmap_weight(indio_dev->active_scan_mask,
- indio_dev->masklength);
- d_size = scan_count * (AD7298_STORAGE_BITS / 8);
-
- if (ring->scan_timestamp) {
- d_size += sizeof(s64);
-
- if (d_size % sizeof(s64))
- d_size += sizeof(s64) - (d_size % sizeof(s64));
- }
+ int scan_count, ret;
- if (ring->access->set_bytes_per_datum)
- ring->access->set_bytes_per_datum(ring, d_size);
+ ret = iio_sw_buffer_preenable(indio_dev);
+ if (ret < 0)
+ return ret;
- st->d_size = d_size;
+ /* Now compute overall size */
+ scan_count = bitmap_weight(indio_dev->active_scan_mask,
+ indio_dev->masklength);
command = AD7298_WRITE | st->ext_ref;
@@ -100,9 +92,9 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p)
if (b_sent)
return b_sent;
- if (ring->scan_timestamp) {
+ if (indio_dev->scan_timestamp) {
time_ns = iio_get_time_ns();
- memcpy((u8 *)buf + st->d_size - sizeof(s64),
+ memcpy((u8 *)buf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
}
@@ -126,7 +118,7 @@ int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev)
{
int ret;
- indio_dev->buffer = iio_sw_rb_allocate(indio_dev);
+ indio_dev->buffer = iio_kfifo_allocate(indio_dev);
if (!indio_dev->buffer) {
ret = -ENOMEM;
goto error_ret;
@@ -140,7 +132,7 @@ int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev)
if (indio_dev->pollfunc == NULL) {
ret = -ENOMEM;
- goto error_deallocate_sw_rb;
+ goto error_deallocate_kfifo;
}
/* Ring buffer functions - here trigger setup related */
@@ -151,8 +143,8 @@ int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
return 0;
-error_deallocate_sw_rb:
- iio_sw_rb_free(indio_dev->buffer);
+error_deallocate_kfifo:
+ iio_kfifo_free(indio_dev->buffer);
error_ret:
return ret;
}
@@ -160,5 +152,5 @@ error_ret:
void ad7298_ring_cleanup(struct iio_dev *indio_dev)
{
iio_dealloc_pollfunc(indio_dev->pollfunc);
- iio_sw_rb_free(indio_dev->buffer);
+ iio_kfifo_free(indio_dev->buffer);
}
diff --git a/drivers/staging/iio/adc/ad7476.h b/drivers/staging/iio/adc/ad7476.h
index 27f696c75cc4..b1dd9317fe1f 100644
--- a/drivers/staging/iio/adc/ad7476.h
+++ b/drivers/staging/iio/adc/ad7476.h
@@ -27,7 +27,6 @@ struct ad7476_state {
struct spi_device *spi;
const struct ad7476_chip_info *chip_info;
struct regulator *reg;
- size_t d_size;
u16 int_vref_mv;
struct spi_transfer xfer;
struct spi_message msg;
diff --git a/drivers/staging/iio/adc/ad7476_core.c b/drivers/staging/iio/adc/ad7476_core.c
index 0c064d1c3927..be1c260cf165 100644
--- a/drivers/staging/iio/adc/ad7476_core.c
+++ b/drivers/staging/iio/adc/ad7476_core.c
@@ -15,9 +15,9 @@
#include <linux/err.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "ad7476.h"
@@ -43,7 +43,7 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
unsigned int scale_uv;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
@@ -66,53 +66,51 @@ static int ad7476_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
}
+#define AD7476_CHAN(bits) \
+ { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = bits, \
+ .storagebits = 16, \
+ .shift = 12 - bits, \
+ }, \
+}
+
static const struct ad7476_chip_info ad7476_chip_info_tbl[] = {
[ID_AD7466] = {
- .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 0, 0, IIO_ST('u', 12, 16, 0), 0),
+ .channel[0] = AD7476_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7467] = {
- .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 0, 0, IIO_ST('u', 10, 16, 2), 0),
+ .channel[0] = AD7476_CHAN(10),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7468] = {
- .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1 , 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 0, 0, IIO_ST('u', 8, 16, 4), 0),
+ .channel[0] = AD7476_CHAN(8),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7475] = {
- .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 0, 0, IIO_ST('u', 12, 16, 0), 0),
+ .channel[0] = AD7476_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7476] = {
- .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 0, 0, IIO_ST('u', 12, 16, 0), 0),
+ .channel[0] = AD7476_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7477] = {
- .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 0, 0, IIO_ST('u', 10, 16, 2), 0),
+ .channel[0] = AD7476_CHAN(10),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7478] = {
- .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 0, 0, IIO_ST('u', 8, 16, 4), 0),
+ .channel[0] = AD7476_CHAN(8),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
},
[ID_AD7495] = {
- .channel[0] = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 0, 0, IIO_ST('u', 12, 16, 0), 0),
+ .channel[0] = AD7476_CHAN(12),
.channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1),
.int_vref_mv = 2500,
},
@@ -130,7 +128,7 @@ static int __devinit ad7476_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
int ret, voltage_uv = 0;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -200,7 +198,7 @@ error_disable_reg:
error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
@@ -218,7 +216,7 @@ static int ad7476_remove(struct spi_device *spi)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/ad7476_ring.c b/drivers/staging/iio/adc/ad7476_ring.c
index d6af6c05ce1c..383611b05764 100644
--- a/drivers/staging/iio/adc/ad7476_ring.c
+++ b/drivers/staging/iio/adc/ad7476_ring.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2010 Analog Devices Inc.
+ * Copyright 2010-2012 Analog Devices Inc.
* Copyright (C) 2008 Jonathan Cameron
*
* Licensed under the GPL-2 or later.
@@ -13,43 +13,13 @@
#include <linux/slab.h>
#include <linux/spi/spi.h>
-#include "../iio.h"
-#include "../buffer.h"
-#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger_consumer.h>
#include "ad7476.h"
-/**
- * ad7476_ring_preenable() setup the parameters of the ring before enabling
- *
- * The complex nature of the setting of the number of bytes per datum is due
- * to this driver currently ensuring that the timestamp is stored at an 8
- * byte boundary.
- **/
-static int ad7476_ring_preenable(struct iio_dev *indio_dev)
-{
- struct ad7476_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
-
- st->d_size = bitmap_weight(indio_dev->active_scan_mask,
- indio_dev->masklength) *
- st->chip_info->channel[0].scan_type.storagebits / 8;
-
- if (ring->scan_timestamp) {
- st->d_size += sizeof(s64);
-
- if (st->d_size % sizeof(s64))
- st->d_size += sizeof(s64) - (st->d_size % sizeof(s64));
- }
-
- if (indio_dev->buffer->access->set_bytes_per_datum)
- indio_dev->buffer->access->
- set_bytes_per_datum(indio_dev->buffer, st->d_size);
-
- return 0;
-}
-
static irqreturn_t ad7476_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
@@ -59,7 +29,7 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p)
__u8 *rxbuf;
int b_sent;
- rxbuf = kzalloc(st->d_size, GFP_KERNEL);
+ rxbuf = kzalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (rxbuf == NULL)
return -ENOMEM;
@@ -70,8 +40,8 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p)
time_ns = iio_get_time_ns();
- if (indio_dev->buffer->scan_timestamp)
- memcpy(rxbuf + st->d_size - sizeof(s64),
+ if (indio_dev->scan_timestamp)
+ memcpy(rxbuf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
indio_dev->buffer->access->store_to(indio_dev->buffer, rxbuf, time_ns);
@@ -83,7 +53,7 @@ done:
}
static const struct iio_buffer_setup_ops ad7476_ring_setup_ops = {
- .preenable = &ad7476_ring_preenable,
+ .preenable = &iio_sw_buffer_preenable,
.postenable = &iio_triggered_buffer_postenable,
.predisable = &iio_triggered_buffer_predisable,
};
@@ -93,7 +63,7 @@ int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev)
struct ad7476_state *st = iio_priv(indio_dev);
int ret = 0;
- indio_dev->buffer = iio_sw_rb_allocate(indio_dev);
+ indio_dev->buffer = iio_kfifo_allocate(indio_dev);
if (!indio_dev->buffer) {
ret = -ENOMEM;
goto error_ret;
@@ -108,7 +78,7 @@ int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->id);
if (indio_dev->pollfunc == NULL) {
ret = -ENOMEM;
- goto error_deallocate_sw_rb;
+ goto error_deallocate_kfifo;
}
/* Ring buffer functions - here trigger setup related */
@@ -119,8 +89,8 @@ int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
return 0;
-error_deallocate_sw_rb:
- iio_sw_rb_free(indio_dev->buffer);
+error_deallocate_kfifo:
+ iio_kfifo_free(indio_dev->buffer);
error_ret:
return ret;
}
@@ -128,5 +98,5 @@ error_ret:
void ad7476_ring_cleanup(struct iio_dev *indio_dev)
{
iio_dealloc_pollfunc(indio_dev->pollfunc);
- iio_sw_rb_free(indio_dev->buffer);
+ iio_kfifo_free(indio_dev->buffer);
}
diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c
index 97e8d3d4471e..10ab6dc823b9 100644
--- a/drivers/staging/iio/adc/ad7606_core.c
+++ b/drivers/staging/iio/adc/ad7606_core.c
@@ -18,9 +18,9 @@
#include <linux/sched.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "ad7606.h"
@@ -88,7 +88,7 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
unsigned int scale_uv;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
@@ -113,7 +113,7 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
static ssize_t ad7606_show_range(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7606_state *st = iio_priv(indio_dev);
return sprintf(buf, "%u\n", st->range);
@@ -122,7 +122,7 @@ static ssize_t ad7606_show_range(struct device *dev,
static ssize_t ad7606_store_range(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7606_state *st = iio_priv(indio_dev);
unsigned long lval;
@@ -147,7 +147,7 @@ static IIO_CONST_ATTR(in_voltage_range_available, "5000 10000");
static ssize_t ad7606_show_oversampling_ratio(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7606_state *st = iio_priv(indio_dev);
return sprintf(buf, "%u\n", st->oversampling);
@@ -168,7 +168,7 @@ static int ad7606_oversampling_get_index(unsigned val)
static ssize_t ad7606_store_oversampling_ratio(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7606_state *st = iio_priv(indio_dev);
unsigned long lval;
int ret;
@@ -229,14 +229,15 @@ static const struct attribute_group ad7606_attribute_group_range = {
.attrs = ad7606_attributes_range,
};
-#define AD7606_CHANNEL(num) \
- { \
- .type = IIO_VOLTAGE, \
- .indexed = 1, \
- .channel = num, \
- .address = num, \
- .scan_index = num, \
- .scan_type = IIO_ST('s', 16, 16, 0), \
+#define AD7606_CHANNEL(num) \
+ { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = num, \
+ .address = num, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, \
+ .scan_index = num, \
+ .scan_type = IIO_ST('s', 16, 16, 0), \
}
static struct iio_chan_spec ad7606_8_channels[] = {
@@ -460,7 +461,7 @@ struct iio_dev *ad7606_probe(struct device *dev, int irq,
struct ad7606_platform_data *pdata = dev->platform_data;
struct ad7606_state *st;
int ret;
- struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+ struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
@@ -559,7 +560,7 @@ error_disable_reg:
error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ERR_PTR(ret);
}
@@ -579,7 +580,7 @@ int ad7606_remove(struct iio_dev *indio_dev, int irq)
}
ad7606_free_gpios(st);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/ad7606_par.c b/drivers/staging/iio/adc/ad7606_par.c
index bb152a8e8c92..a53faafec070 100644
--- a/drivers/staging/iio/adc/ad7606_par.c
+++ b/drivers/staging/iio/adc/ad7606_par.c
@@ -12,7 +12,7 @@
#include <linux/err.h>
#include <linux/io.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "ad7606.h"
static int ad7606_par16_read_block(struct device *dev,
diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c
index 1ef9fbcaf2de..24ce8fc71646 100644
--- a/drivers/staging/iio/adc/ad7606_ring.c
+++ b/drivers/staging/iio/adc/ad7606_ring.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2011 Analog Devices Inc.
+ * Copyright 2011-2012 Analog Devices Inc.
*
* Licensed under the GPL-2.
*
@@ -11,10 +11,10 @@
#include <linux/kernel.h>
#include <linux/slab.h>
-#include "../iio.h"
-#include "../buffer.h"
-#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger_consumer.h>
#include "ad7606.h"
@@ -51,8 +51,7 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s)
__u8 *buf;
int ret;
- buf = kzalloc(ring->access->get_bytes_per_datum(ring),
- GFP_KERNEL);
+ buf = kzalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (buf == NULL)
return;
@@ -82,9 +81,8 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s)
time_ns = iio_get_time_ns();
- if (ring->scan_timestamp)
- *((s64 *)(buf + ring->access->get_bytes_per_datum(ring) -
- sizeof(s64))) = time_ns;
+ if (indio_dev->scan_timestamp)
+ *((s64 *)(buf + indio_dev->scan_bytes - sizeof(s64))) = time_ns;
ring->access->store_to(indio_dev->buffer, buf, time_ns);
done:
@@ -104,7 +102,7 @@ int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev)
struct ad7606_state *st = iio_priv(indio_dev);
int ret;
- indio_dev->buffer = iio_sw_rb_allocate(indio_dev);
+ indio_dev->buffer = iio_kfifo_allocate(indio_dev);
if (!indio_dev->buffer) {
ret = -ENOMEM;
goto error_ret;
@@ -119,13 +117,13 @@ int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->id);
if (indio_dev->pollfunc == NULL) {
ret = -ENOMEM;
- goto error_deallocate_sw_rb;
+ goto error_deallocate_kfifo;
}
/* Ring buffer functions - here trigger setup related */
indio_dev->setup_ops = &ad7606_ring_setup_ops;
- indio_dev->buffer->scan_timestamp = true ;
+ indio_dev->buffer->scan_timestamp = true;
INIT_WORK(&st->poll_work, &ad7606_poll_bh_to_ring);
@@ -133,8 +131,8 @@ int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
return 0;
-error_deallocate_sw_rb:
- iio_sw_rb_free(indio_dev->buffer);
+error_deallocate_kfifo:
+ iio_kfifo_free(indio_dev->buffer);
error_ret:
return ret;
}
@@ -142,5 +140,5 @@ error_ret:
void ad7606_ring_cleanup(struct iio_dev *indio_dev)
{
iio_dealloc_pollfunc(indio_dev->pollfunc);
- iio_sw_rb_free(indio_dev->buffer);
+ iio_kfifo_free(indio_dev->buffer);
}
diff --git a/drivers/staging/iio/adc/ad7606_spi.c b/drivers/staging/iio/adc/ad7606_spi.c
index 237f1c44d296..099d347da52d 100644
--- a/drivers/staging/iio/adc/ad7606_spi.c
+++ b/drivers/staging/iio/adc/ad7606_spi.c
@@ -11,7 +11,7 @@
#include <linux/types.h>
#include <linux/err.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "ad7606.h"
#define MAX_SPI_FREQ_HZ 23500000 /* VDRIVE above 4.75 V */
diff --git a/drivers/staging/iio/adc/ad7780.c b/drivers/staging/iio/adc/ad7780.c
index a13e58c814e6..1ece2ac8de56 100644
--- a/drivers/staging/iio/adc/ad7780.c
+++ b/drivers/staging/iio/adc/ad7780.c
@@ -18,8 +18,8 @@
#include <linux/gpio.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "ad7780.h"
@@ -94,7 +94,7 @@ static int ad7780_read_raw(struct iio_dev *indio_dev,
unsigned long scale_uv;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
ret = ad7780_read(st, &smpl);
mutex_unlock(&indio_dev->mlock);
@@ -126,14 +126,34 @@ static int ad7780_read_raw(struct iio_dev *indio_dev,
static const struct ad7780_chip_info ad7780_chip_info_tbl[] = {
[ID_AD7780] = {
- .channel = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 0, 0, IIO_ST('s', 24, 32, 8), 0),
+ .channel = {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ .shift = 8,
+ },
+ },
},
[ID_AD7781] = {
- .channel = IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- 0, 0, IIO_ST('s', 20, 32, 12), 0),
+ .channel = {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 20,
+ .storagebits = 32,
+ .shift = 12,
+ },
+ },
},
};
@@ -167,7 +187,7 @@ static int __devinit ad7780_probe(struct spi_device *spi)
return -ENODEV;
}
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -245,7 +265,7 @@ error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -262,7 +282,7 @@ static int ad7780_remove(struct spi_device *spi)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/ad7793.c b/drivers/staging/iio/adc/ad7793.c
index 84ecde1ad042..b36556fa2957 100644
--- a/drivers/staging/iio/adc/ad7793.c
+++ b/drivers/staging/iio/adc/ad7793.c
@@ -1,7 +1,7 @@
/*
* AD7792/AD7793 SPI ADC driver
*
- * Copyright 2011 Analog Devices Inc.
+ * Copyright 2011-2012 Analog Devices Inc.
*
* Licensed under the GPL-2.
*/
@@ -18,12 +18,12 @@
#include <linux/delay.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
-#include "../ring_sw.h"
-#include "../trigger.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
#include "ad7793.h"
@@ -319,31 +319,18 @@ out:
static int ad7793_ring_preenable(struct iio_dev *indio_dev)
{
struct ad7793_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
- size_t d_size;
unsigned channel;
+ int ret;
if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
return -EINVAL;
+ ret = iio_sw_buffer_preenable(indio_dev);
+ if (ret < 0)
+ return ret;
channel = find_first_bit(indio_dev->active_scan_mask,
indio_dev->masklength);
- d_size = bitmap_weight(indio_dev->active_scan_mask,
- indio_dev->masklength) *
- indio_dev->channels[0].scan_type.storagebits / 8;
-
- if (ring->scan_timestamp) {
- d_size += sizeof(s64);
-
- if (d_size % sizeof(s64))
- d_size += sizeof(s64) - (d_size % sizeof(s64));
- }
-
- if (indio_dev->buffer->access->set_bytes_per_datum)
- indio_dev->buffer->access->
- set_bytes_per_datum(indio_dev->buffer, d_size);
-
st->mode = (st->mode & ~AD7793_MODE_SEL(-1)) |
AD7793_MODE_SEL(AD7793_MODE_CONT);
st->conf = (st->conf & ~AD7793_CONF_CHAN(-1)) |
@@ -399,7 +386,7 @@ static irqreturn_t ad7793_trigger_handler(int irq, void *p)
indio_dev->channels[0].scan_type.realbits/8);
/* Guaranteed to be aligned with 8 byte boundary */
- if (ring->scan_timestamp)
+ if (indio_dev->scan_timestamp)
dat64[1] = pf->timestamp;
ring->access->store_to(ring, (u8 *)dat64, pf->timestamp);
@@ -422,7 +409,7 @@ static int ad7793_register_ring_funcs_and_init(struct iio_dev *indio_dev)
{
int ret;
- indio_dev->buffer = iio_sw_rb_allocate(indio_dev);
+ indio_dev->buffer = iio_kfifo_allocate(indio_dev);
if (!indio_dev->buffer) {
ret = -ENOMEM;
goto error_ret;
@@ -435,7 +422,7 @@ static int ad7793_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->id);
if (indio_dev->pollfunc == NULL) {
ret = -ENOMEM;
- goto error_deallocate_sw_rb;
+ goto error_deallocate_kfifo;
}
/* Ring buffer functions - here trigger setup related */
@@ -445,8 +432,8 @@ static int ad7793_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
return 0;
-error_deallocate_sw_rb:
- iio_sw_rb_free(indio_dev->buffer);
+error_deallocate_kfifo:
+ iio_kfifo_free(indio_dev->buffer);
error_ret:
return ret;
}
@@ -454,7 +441,7 @@ error_ret:
static void ad7793_ring_cleanup(struct iio_dev *indio_dev)
{
iio_dealloc_pollfunc(indio_dev->pollfunc);
- iio_sw_rb_free(indio_dev->buffer);
+ iio_kfifo_free(indio_dev->buffer);
}
/**
@@ -482,7 +469,7 @@ static int ad7793_probe_trigger(struct iio_dev *indio_dev)
struct ad7793_state *st = iio_priv(indio_dev);
int ret;
- st->trig = iio_allocate_trigger("%s-dev%d",
+ st->trig = iio_trigger_alloc("%s-dev%d",
spi_get_device_id(st->spi)->name,
indio_dev->id);
if (st->trig == NULL) {
@@ -516,7 +503,7 @@ static int ad7793_probe_trigger(struct iio_dev *indio_dev)
error_free_irq:
free_irq(st->spi->irq, indio_dev);
error_free_trig:
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
error_ret:
return ret;
}
@@ -527,7 +514,7 @@ static void ad7793_remove_trigger(struct iio_dev *indio_dev)
iio_trigger_unregister(st->trig);
free_irq(st->spi->irq, indio_dev);
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
}
static const u16 sample_freq_avail[16] = {0, 470, 242, 123, 62, 50, 39, 33, 19,
@@ -537,7 +524,7 @@ static ssize_t ad7793_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7793_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n",
@@ -549,7 +536,7 @@ static ssize_t ad7793_write_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7793_state *st = iio_priv(indio_dev);
long lval;
int i, ret;
@@ -591,7 +578,7 @@ static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
static ssize_t ad7793_show_scale_available(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7793_state *st = iio_priv(indio_dev);
int i, len = 0;
@@ -630,7 +617,7 @@ static int ad7793_read_raw(struct iio_dev *indio_dev,
bool unipolar = !!(st->conf & AD7793_CONF_UNIPOLAR);
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
@@ -760,7 +747,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.channel = 0,
.channel2 = 0,
.address = AD7793_CH_AIN1P_AIN1M,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.scan_index = 0,
.scan_type = IIO_ST('s', 24, 32, 0)
},
@@ -771,7 +759,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.channel = 1,
.channel2 = 1,
.address = AD7793_CH_AIN2P_AIN2M,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.scan_index = 1,
.scan_type = IIO_ST('s', 24, 32, 0)
},
@@ -782,7 +771,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.channel = 2,
.channel2 = 2,
.address = AD7793_CH_AIN3P_AIN3M,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.scan_index = 2,
.scan_type = IIO_ST('s', 24, 32, 0)
},
@@ -794,7 +784,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.channel = 2,
.channel2 = 2,
.address = AD7793_CH_AIN1M_AIN1M,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.scan_index = 2,
.scan_type = IIO_ST('s', 24, 32, 0)
},
@@ -803,7 +794,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.indexed = 1,
.channel = 0,
.address = AD7793_CH_TEMP,
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.scan_index = 4,
.scan_type = IIO_ST('s', 24, 32, 0),
},
@@ -813,7 +805,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.indexed = 1,
.channel = 4,
.address = AD7793_CH_AVDD_MONITOR,
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.scan_index = 5,
.scan_type = IIO_ST('s', 24, 32, 0),
},
@@ -827,7 +820,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.channel = 0,
.channel2 = 0,
.address = AD7793_CH_AIN1P_AIN1M,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.scan_index = 0,
.scan_type = IIO_ST('s', 16, 32, 0)
},
@@ -838,7 +832,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.channel = 1,
.channel2 = 1,
.address = AD7793_CH_AIN2P_AIN2M,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.scan_index = 1,
.scan_type = IIO_ST('s', 16, 32, 0)
},
@@ -849,7 +844,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.channel = 2,
.channel2 = 2,
.address = AD7793_CH_AIN3P_AIN3M,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.scan_index = 2,
.scan_type = IIO_ST('s', 16, 32, 0)
},
@@ -861,7 +857,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.channel = 2,
.channel2 = 2,
.address = AD7793_CH_AIN1M_AIN1M,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.scan_index = 2,
.scan_type = IIO_ST('s', 16, 32, 0)
},
@@ -870,7 +867,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.indexed = 1,
.channel = 0,
.address = AD7793_CH_TEMP,
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.scan_index = 4,
.scan_type = IIO_ST('s', 16, 32, 0),
},
@@ -880,7 +878,8 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
.indexed = 1,
.channel = 4,
.address = AD7793_CH_AVDD_MONITOR,
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.scan_index = 5,
.scan_type = IIO_ST('s', 16, 32, 0),
},
@@ -905,7 +904,7 @@ static int __devinit ad7793_probe(struct spi_device *spi)
return -ENODEV;
}
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -989,7 +988,7 @@ error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -1009,7 +1008,7 @@ static int ad7793_remove(struct spi_device *spi)
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/ad7816.c b/drivers/staging/iio/adc/ad7816.c
index 52b720e2b03a..5356b091b08f 100644
--- a/drivers/staging/iio/adc/ad7816.c
+++ b/drivers/staging/iio/adc/ad7816.c
@@ -16,9 +16,9 @@
#include <linux/spi/spi.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
/*
* AD7816 config masks
@@ -113,7 +113,7 @@ static ssize_t ad7816_show_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7816_chip_info *chip = iio_priv(indio_dev);
if (chip->mode)
@@ -127,7 +127,7 @@ static ssize_t ad7816_store_mode(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7816_chip_info *chip = iio_priv(indio_dev);
if (strcmp(buf, "full")) {
@@ -159,7 +159,7 @@ static ssize_t ad7816_show_channel(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7816_chip_info *chip = iio_priv(indio_dev);
return sprintf(buf, "%d\n", chip->channel_id);
@@ -170,7 +170,7 @@ static ssize_t ad7816_store_channel(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7816_chip_info *chip = iio_priv(indio_dev);
unsigned long data;
int ret;
@@ -208,7 +208,7 @@ static ssize_t ad7816_show_value(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7816_chip_info *chip = iio_priv(indio_dev);
u16 data;
s8 value;
@@ -263,7 +263,7 @@ static ssize_t ad7816_show_oti(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7816_chip_info *chip = iio_priv(indio_dev);
int value;
@@ -284,7 +284,7 @@ static inline ssize_t ad7816_set_oti(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7816_chip_info *chip = iio_priv(indio_dev);
long value;
u8 data;
@@ -354,7 +354,7 @@ static int __devinit ad7816_probe(struct spi_device *spi_dev)
return -EINVAL;
}
- indio_dev = iio_allocate_device(sizeof(*chip));
+ indio_dev = iio_device_alloc(sizeof(*chip));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -426,7 +426,7 @@ error_free_gpio_convert:
error_free_gpio_rdwr:
gpio_free(chip->rdwr_pin);
error_free_device:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -443,7 +443,7 @@ static int __devexit ad7816_remove(struct spi_device *spi_dev)
gpio_free(chip->busy_pin);
gpio_free(chip->convert_pin);
gpio_free(chip->rdwr_pin);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/ad7887.h b/drivers/staging/iio/adc/ad7887.h
index bc53b6532121..2e09e54fc9c5 100644
--- a/drivers/staging/iio/adc/ad7887.h
+++ b/drivers/staging/iio/adc/ad7887.h
@@ -63,7 +63,6 @@ struct ad7887_state {
struct spi_device *spi;
const struct ad7887_chip_info *chip_info;
struct regulator *reg;
- size_t d_size;
u16 int_vref_mv;
struct spi_transfer xfer[4];
struct spi_message msg[3];
diff --git a/drivers/staging/iio/adc/ad7887_core.c b/drivers/staging/iio/adc/ad7887_core.c
index e9bbc3eed15d..7186074deeb3 100644
--- a/drivers/staging/iio/adc/ad7887_core.c
+++ b/drivers/staging/iio/adc/ad7887_core.c
@@ -15,9 +15,9 @@
#include <linux/err.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "ad7887.h"
@@ -42,7 +42,7 @@ static int ad7887_read_raw(struct iio_dev *indio_dev,
unsigned int scale_uv;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
@@ -75,7 +75,8 @@ static const struct ad7887_chip_info ad7887_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.address = 1,
.scan_index = 1,
.scan_type = IIO_ST('u', 12, 16, 0),
@@ -84,7 +85,8 @@ static const struct ad7887_chip_info ad7887_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.address = 0,
.scan_index = 0,
.scan_type = IIO_ST('u', 12, 16, 0),
@@ -104,7 +106,7 @@ static int __devinit ad7887_probe(struct spi_device *spi)
struct ad7887_platform_data *pdata = spi->dev.platform_data;
struct ad7887_state *st;
int ret, voltage_uv = 0;
- struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+ struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -220,7 +222,7 @@ error_disable_reg:
error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -237,7 +239,7 @@ static int ad7887_remove(struct spi_device *spi)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/ad7887_ring.c b/drivers/staging/iio/adc/ad7887_ring.c
index d1809079b63d..fd91384db894 100644
--- a/drivers/staging/iio/adc/ad7887_ring.c
+++ b/drivers/staging/iio/adc/ad7887_ring.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-2011 Analog Devices Inc.
+ * Copyright 2010-2012 Analog Devices Inc.
* Copyright (C) 2008 Jonathan Cameron
*
* Licensed under the GPL-2.
@@ -12,10 +12,10 @@
#include <linux/slab.h>
#include <linux/spi/spi.h>
-#include "../iio.h"
-#include "../buffer.h"
-#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger_consumer.h>
#include "ad7887.h"
@@ -29,22 +29,11 @@
static int ad7887_ring_preenable(struct iio_dev *indio_dev)
{
struct ad7887_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
-
- st->d_size = bitmap_weight(indio_dev->active_scan_mask,
- indio_dev->masklength) *
- st->chip_info->channel[0].scan_type.storagebits / 8;
-
- if (ring->scan_timestamp) {
- st->d_size += sizeof(s64);
-
- if (st->d_size % sizeof(s64))
- st->d_size += sizeof(s64) - (st->d_size % sizeof(s64));
- }
+ int ret;
- if (indio_dev->buffer->access->set_bytes_per_datum)
- indio_dev->buffer->access->
- set_bytes_per_datum(indio_dev->buffer, st->d_size);
+ ret = iio_sw_buffer_preenable(indio_dev);
+ if (ret < 0)
+ return ret;
/* We know this is a single long so can 'cheat' */
switch (*indio_dev->active_scan_mask) {
@@ -83,7 +72,6 @@ static irqreturn_t ad7887_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad7887_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
s64 time_ns;
__u8 *buf;
int b_sent;
@@ -92,7 +80,7 @@ static irqreturn_t ad7887_trigger_handler(int irq, void *p)
indio_dev->masklength) *
st->chip_info->channel[0].scan_type.storagebits / 8;
- buf = kzalloc(st->d_size, GFP_KERNEL);
+ buf = kzalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
@@ -103,8 +91,8 @@ static irqreturn_t ad7887_trigger_handler(int irq, void *p)
time_ns = iio_get_time_ns();
memcpy(buf, st->data, bytes);
- if (ring->scan_timestamp)
- memcpy(buf + st->d_size - sizeof(s64),
+ if (indio_dev->scan_timestamp)
+ memcpy(buf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
indio_dev->buffer->access->store_to(indio_dev->buffer, buf, time_ns);
@@ -126,7 +114,7 @@ int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev)
{
int ret;
- indio_dev->buffer = iio_sw_rb_allocate(indio_dev);
+ indio_dev->buffer = iio_kfifo_allocate(indio_dev);
if (!indio_dev->buffer) {
ret = -ENOMEM;
goto error_ret;
@@ -139,7 +127,7 @@ int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->id);
if (indio_dev->pollfunc == NULL) {
ret = -ENOMEM;
- goto error_deallocate_sw_rb;
+ goto error_deallocate_kfifo;
}
/* Ring buffer functions - here trigger setup related */
indio_dev->setup_ops = &ad7887_ring_setup_ops;
@@ -148,8 +136,8 @@ int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
return 0;
-error_deallocate_sw_rb:
- iio_sw_rb_free(indio_dev->buffer);
+error_deallocate_kfifo:
+ iio_kfifo_free(indio_dev->buffer);
error_ret:
return ret;
}
@@ -157,5 +145,5 @@ error_ret:
void ad7887_ring_cleanup(struct iio_dev *indio_dev)
{
iio_dealloc_pollfunc(indio_dev->pollfunc);
- iio_sw_rb_free(indio_dev->buffer);
+ iio_kfifo_free(indio_dev->buffer);
}
diff --git a/drivers/staging/iio/adc/ad799x.h b/drivers/staging/iio/adc/ad799x.h
index 356f690a76fb..99f8abe9731b 100644
--- a/drivers/staging/iio/adc/ad799x.h
+++ b/drivers/staging/iio/adc/ad799x.h
@@ -104,7 +104,6 @@ struct ad799x_chip_info {
struct ad799x_state {
struct i2c_client *client;
const struct ad799x_chip_info *chip_info;
- size_t d_size;
struct iio_trigger *trig;
struct regulator *reg;
u16 int_vref_mv;
diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/staging/iio/adc/ad799x_core.c
index a8458669350f..80e0c6e25a9b 100644
--- a/drivers/staging/iio/adc/ad799x_core.c
+++ b/drivers/staging/iio/adc/ad799x_core.c
@@ -33,10 +33,10 @@
#include <linux/err.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/buffer.h>
#include "ad799x.h"
@@ -148,7 +148,7 @@ static int ad799x_read_raw(struct iio_dev *indio_dev,
unsigned int scale_uv;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev))
ret = -EBUSY;
@@ -182,7 +182,7 @@ static ssize_t ad799x_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad799x_state *st = iio_priv(indio_dev);
int ret;
@@ -201,7 +201,7 @@ static ssize_t ad799x_write_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad799x_state *st = iio_priv(indio_dev);
long val;
@@ -294,7 +294,7 @@ static ssize_t ad799x_read_channel_config(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad799x_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -312,7 +312,7 @@ static ssize_t ad799x_write_channel_config(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad799x_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -454,6 +454,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 0,
.scan_type = IIO_ST('u', 12, 16, 0),
},
@@ -461,6 +462,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 1,
.scan_type = IIO_ST('u', 12, 16, 0),
},
@@ -468,6 +470,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 2,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 2,
.scan_type = IIO_ST('u', 12, 16, 0),
},
@@ -475,6 +478,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 3,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 3,
.scan_type = IIO_ST('u', 12, 16, 0),
},
@@ -490,6 +494,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 0,
.scan_type = IIO_ST('u', 10, 16, 2),
},
@@ -497,6 +502,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 1,
.scan_type = IIO_ST('u', 10, 16, 2),
},
@@ -504,6 +510,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 2,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 2,
.scan_type = IIO_ST('u', 10, 16, 2),
},
@@ -511,6 +518,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 3,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 3,
.scan_type = IIO_ST('u', 10, 16, 2),
},
@@ -526,6 +534,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 0,
.scan_type = IIO_ST('u', 8, 16, 4),
},
@@ -533,6 +542,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 1,
.scan_type = IIO_ST('u', 8, 16, 4),
},
@@ -540,6 +550,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 2,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 2,
.scan_type = IIO_ST('u', 8, 16, 4),
},
@@ -547,6 +558,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 3,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 3,
.scan_type = IIO_ST('u', 8, 16, 4),
},
@@ -562,6 +574,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 0,
.scan_type = IIO_ST('u', 12, 16, 0),
.event_mask = AD799X_EV_MASK,
@@ -570,6 +583,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 1,
.scan_type = IIO_ST('u', 12, 16, 0),
.event_mask = AD799X_EV_MASK,
@@ -587,6 +601,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 0,
.scan_type = IIO_ST('u', 10, 16, 2),
.event_mask = AD799X_EV_MASK,
@@ -596,6 +611,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.indexed = 1,
.channel = 1,
.scan_index = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_type = IIO_ST('u', 10, 16, 2),
.event_mask = AD799X_EV_MASK,
},
@@ -603,6 +619,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 2,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 2,
.scan_type = IIO_ST('u', 10, 16, 2),
.event_mask = AD799X_EV_MASK,
@@ -611,6 +628,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 3,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 3,
.scan_type = IIO_ST('u', 10, 16, 2),
.event_mask = AD799X_EV_MASK,
@@ -628,6 +646,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 0,
.scan_type = IIO_ST('u', 12, 16, 0),
.event_mask = AD799X_EV_MASK,
@@ -636,6 +655,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 1,
.scan_type = IIO_ST('u', 12, 16, 0),
.event_mask = AD799X_EV_MASK,
@@ -644,6 +664,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 2,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 2,
.scan_type = IIO_ST('u', 12, 16, 0),
.event_mask = AD799X_EV_MASK,
@@ -652,6 +673,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 3,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 3,
.scan_type = IIO_ST('u', 12, 16, 0),
.event_mask = AD799X_EV_MASK,
@@ -669,6 +691,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 0,
.scan_type = IIO_ST('u', 10, 16, 2),
.event_mask = AD799X_EV_MASK,
@@ -677,6 +700,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 1,
.scan_type = IIO_ST('u', 10, 16, 2),
.event_mask = AD799X_EV_MASK,
@@ -685,6 +709,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 2,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 2,
.scan_type = IIO_ST('u', 10, 16, 2),
.event_mask = AD799X_EV_MASK,
@@ -693,6 +718,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 3,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 3,
.scan_type = IIO_ST('u', 10, 16, 2),
.event_mask = AD799X_EV_MASK,
@@ -701,6 +727,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 4,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 4,
.scan_type = IIO_ST('u', 10, 16, 2),
},
@@ -708,6 +735,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 5,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 5,
.scan_type = IIO_ST('u', 10, 16, 2),
},
@@ -715,6 +743,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 6,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 6,
.scan_type = IIO_ST('u', 10, 16, 2),
},
@@ -722,6 +751,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 7,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 7,
.scan_type = IIO_ST('u', 10, 16, 2),
},
@@ -738,6 +768,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 0,
.scan_type = IIO_ST('u', 12, 16, 0),
.event_mask = AD799X_EV_MASK,
@@ -746,6 +777,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 1,
.scan_type = IIO_ST('u', 12, 16, 0),
.event_mask = AD799X_EV_MASK,
@@ -754,6 +786,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 2,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 2,
.scan_type = IIO_ST('u', 12, 16, 0),
.event_mask = AD799X_EV_MASK,
@@ -762,6 +795,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 3,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 3,
.scan_type = IIO_ST('u', 12, 16, 0),
.event_mask = AD799X_EV_MASK,
@@ -770,6 +804,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 4,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 4,
.scan_type = IIO_ST('u', 12, 16, 0),
},
@@ -777,6 +812,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 5,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 5,
.scan_type = IIO_ST('u', 12, 16, 0),
},
@@ -784,6 +820,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 6,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 6,
.scan_type = IIO_ST('u', 12, 16, 0),
},
@@ -791,6 +828,7 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 7,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.scan_index = 7,
.scan_type = IIO_ST('u', 12, 16, 0),
},
@@ -809,7 +847,7 @@ static int __devinit ad799x_probe(struct i2c_client *client,
int ret;
struct ad799x_platform_data *pdata = client->dev.platform_data;
struct ad799x_state *st;
- struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+ struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -882,7 +920,7 @@ error_disable_reg:
error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -902,7 +940,7 @@ static __devexit int ad799x_remove(struct i2c_client *client)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/ad799x_ring.c b/drivers/staging/iio/adc/ad799x_ring.c
index 069765cab275..1c7ff4423db4 100644
--- a/drivers/staging/iio/adc/ad799x_ring.c
+++ b/drivers/staging/iio/adc/ad799x_ring.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Michael Hennerich, Analog Devices Inc.
+ * Copyright (C) 2010-2012 Michael Hennerich, Analog Devices Inc.
* Copyright (C) 2008-2010 Jonathan Cameron
*
* This program is free software; you can redistribute it and/or modify
@@ -16,10 +16,10 @@
#include <linux/i2c.h>
#include <linux/bitops.h>
-#include "../iio.h"
-#include "../buffer.h"
-#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger_consumer.h>
#include "ad799x.h"
@@ -32,9 +32,7 @@
**/
static int ad799x_ring_preenable(struct iio_dev *indio_dev)
{
- struct iio_buffer *ring = indio_dev->buffer;
struct ad799x_state *st = iio_priv(indio_dev);
-
/*
* Need to figure out the current mode based upon the requested
* scan mask in iio_dev
@@ -43,21 +41,7 @@ static int ad799x_ring_preenable(struct iio_dev *indio_dev)
if (st->id == ad7997 || st->id == ad7998)
ad7997_8_set_scan_mode(st, *indio_dev->active_scan_mask);
- st->d_size = bitmap_weight(indio_dev->active_scan_mask,
- indio_dev->masklength) * 2;
-
- if (ring->scan_timestamp) {
- st->d_size += sizeof(s64);
-
- if (st->d_size % sizeof(s64))
- st->d_size += sizeof(s64) - (st->d_size % sizeof(s64));
- }
-
- if (indio_dev->buffer->access->set_bytes_per_datum)
- indio_dev->buffer->access->
- set_bytes_per_datum(indio_dev->buffer, st->d_size);
-
- return 0;
+ return iio_sw_buffer_preenable(indio_dev);
}
/**
@@ -78,7 +62,7 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p)
int b_sent;
u8 cmd;
- rxbuf = kmalloc(st->d_size, GFP_KERNEL);
+ rxbuf = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (rxbuf == NULL)
goto out;
@@ -111,8 +95,8 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p)
time_ns = iio_get_time_ns();
- if (ring->scan_timestamp)
- memcpy(rxbuf + st->d_size - sizeof(s64),
+ if (indio_dev->scan_timestamp)
+ memcpy(rxbuf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
ring->access->store_to(indio_dev->buffer, rxbuf, time_ns);
@@ -136,7 +120,7 @@ int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev)
{
int ret = 0;
- indio_dev->buffer = iio_sw_rb_allocate(indio_dev);
+ indio_dev->buffer = iio_kfifo_allocate(indio_dev);
if (!indio_dev->buffer) {
ret = -ENOMEM;
goto error_ret;
@@ -150,7 +134,7 @@ int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->id);
if (indio_dev->pollfunc == NULL) {
ret = -ENOMEM;
- goto error_deallocate_sw_rb;
+ goto error_deallocate_kfifo;
}
/* Ring buffer functions - here trigger setup related */
@@ -161,8 +145,8 @@ int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev)
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
return 0;
-error_deallocate_sw_rb:
- iio_sw_rb_free(indio_dev->buffer);
+error_deallocate_kfifo:
+ iio_kfifo_free(indio_dev->buffer);
error_ret:
return ret;
}
@@ -170,5 +154,5 @@ error_ret:
void ad799x_ring_cleanup(struct iio_dev *indio_dev)
{
iio_dealloc_pollfunc(indio_dev->pollfunc);
- iio_sw_rb_free(indio_dev->buffer);
+ iio_kfifo_free(indio_dev->buffer);
}
diff --git a/drivers/staging/iio/adc/adt7310.c b/drivers/staging/iio/adc/adt7310.c
index caf57c1169b1..e5f1ed7f8696 100644
--- a/drivers/staging/iio/adc/adt7310.c
+++ b/drivers/staging/iio/adc/adt7310.c
@@ -15,9 +15,9 @@
#include <linux/spi/spi.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
/*
* ADT7310 registers definition
*/
@@ -175,7 +175,7 @@ static ssize_t adt7310_show_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
u8 config;
@@ -198,7 +198,7 @@ static ssize_t adt7310_store_mode(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
u16 config;
int ret;
@@ -242,7 +242,7 @@ static ssize_t adt7310_show_resolution(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
int ret;
int bits;
@@ -264,7 +264,7 @@ static ssize_t adt7310_store_resolution(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
unsigned long data;
u16 config;
@@ -300,7 +300,7 @@ static ssize_t adt7310_show_id(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
u8 id;
int ret;
@@ -350,7 +350,7 @@ static ssize_t adt7310_show_value(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
u8 status;
u16 data;
@@ -424,7 +424,7 @@ static ssize_t adt7310_show_event_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
int ret;
@@ -443,7 +443,7 @@ static ssize_t adt7310_set_event_mode(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
u16 config;
int ret;
@@ -476,7 +476,7 @@ static ssize_t adt7310_show_fault_queue(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
int ret;
@@ -492,7 +492,7 @@ static ssize_t adt7310_set_fault_queue(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
unsigned long data;
int ret;
@@ -522,7 +522,7 @@ static inline ssize_t adt7310_show_t_bound(struct device *dev,
u8 bound_reg,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
u16 data;
int ret;
@@ -540,7 +540,7 @@ static inline ssize_t adt7310_set_t_bound(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
long tmp1, tmp2;
u16 data;
@@ -660,7 +660,7 @@ static ssize_t adt7310_show_t_hyst(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
int ret;
u8 t_hyst;
@@ -677,7 +677,7 @@ static inline ssize_t adt7310_set_t_hyst(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7310_chip_info *chip = iio_priv(dev_info);
int ret;
unsigned long data;
@@ -753,7 +753,7 @@ static int __devinit adt7310_probe(struct spi_device *spi_dev)
unsigned long *adt7310_platform_data = spi_dev->dev.platform_data;
unsigned long irq_flags;
- indio_dev = iio_allocate_device(sizeof(*chip));
+ indio_dev = iio_device_alloc(sizeof(*chip));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -833,7 +833,7 @@ error_unreg_int_irq:
error_unreg_ct_irq:
free_irq(spi_dev->irq, indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -849,7 +849,7 @@ static int __devexit adt7310_remove(struct spi_device *spi_dev)
free_irq(adt7310_platform_data[0], indio_dev);
if (spi_dev->irq)
free_irq(spi_dev->irq, indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/adt7410.c b/drivers/staging/iio/adc/adt7410.c
index dff3e8ca2d78..917b6921e24d 100644
--- a/drivers/staging/iio/adc/adt7410.c
+++ b/drivers/staging/iio/adc/adt7410.c
@@ -15,9 +15,9 @@
#include <linux/i2c.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
/*
* ADT7410 registers definition
@@ -144,7 +144,7 @@ static ssize_t adt7410_show_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
u8 config;
@@ -167,7 +167,7 @@ static ssize_t adt7410_store_mode(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
u16 config;
int ret;
@@ -211,7 +211,7 @@ static ssize_t adt7410_show_resolution(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
int ret;
int bits;
@@ -233,7 +233,7 @@ static ssize_t adt7410_store_resolution(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
unsigned long data;
u16 config;
@@ -269,7 +269,7 @@ static ssize_t adt7410_show_id(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
u8 id;
int ret;
@@ -319,7 +319,7 @@ static ssize_t adt7410_show_value(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
u8 status;
u16 data;
@@ -392,7 +392,7 @@ static ssize_t adt7410_show_event_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
int ret;
@@ -411,7 +411,7 @@ static ssize_t adt7410_set_event_mode(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
u16 config;
int ret;
@@ -444,7 +444,7 @@ static ssize_t adt7410_show_fault_queue(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
int ret;
@@ -460,7 +460,7 @@ static ssize_t adt7410_set_fault_queue(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
unsigned long data;
int ret;
@@ -490,7 +490,7 @@ static inline ssize_t adt7410_show_t_bound(struct device *dev,
u8 bound_reg,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
u16 data;
int ret;
@@ -508,7 +508,7 @@ static inline ssize_t adt7410_set_t_bound(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
long tmp1, tmp2;
u16 data;
@@ -628,7 +628,7 @@ static ssize_t adt7410_show_t_hyst(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
int ret;
u8 t_hyst;
@@ -645,7 +645,7 @@ static inline ssize_t adt7410_set_t_hyst(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7410_chip_info *chip = iio_priv(dev_info);
int ret;
unsigned long data;
@@ -721,7 +721,7 @@ static int __devinit adt7410_probe(struct i2c_client *client,
int ret = 0;
unsigned long *adt7410_platform_data = client->dev.platform_data;
- indio_dev = iio_allocate_device(sizeof(*chip));
+ indio_dev = iio_device_alloc(sizeof(*chip));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -797,7 +797,7 @@ error_unreg_int_irq:
error_unreg_ct_irq:
free_irq(client->irq, indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -812,7 +812,7 @@ static int __devexit adt7410_remove(struct i2c_client *client)
free_irq(adt7410_platform_data[0], indio_dev);
if (client->irq)
free_irq(client->irq, indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/lpc32xx_adc.c b/drivers/staging/iio/adc/lpc32xx_adc.c
index dfc9033843a3..9690306d1f8f 100644
--- a/drivers/staging/iio/adc/lpc32xx_adc.c
+++ b/drivers/staging/iio/adc/lpc32xx_adc.c
@@ -30,9 +30,10 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/completion.h>
+#include <linux/of.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
/*
* LPC32XX registers definitions
@@ -73,7 +74,7 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev,
{
struct lpc32xx_adc_info *info = iio_priv(indio_dev);
- if (mask == 0) {
+ if (mask == IIO_CHAN_INFO_RAW) {
mutex_lock(&indio_dev->mlock);
clk_enable(info->clk);
/* Measurement setup */
@@ -98,12 +99,13 @@ static const struct iio_info lpc32xx_adc_iio_info = {
.driver_module = THIS_MODULE,
};
-#define LPC32XX_ADC_CHANNEL(_index) { \
- .type = IIO_VOLTAGE, \
- .indexed = 1, \
- .channel = _index, \
- .address = AD_IN * _index, \
- .scan_index = _index, \
+#define LPC32XX_ADC_CHANNEL(_index) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = _index, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, \
+ .address = AD_IN * _index, \
+ .scan_index = _index, \
}
static struct iio_chan_spec lpc32xx_adc_iio_channels[] = {
@@ -139,7 +141,7 @@ static int __devinit lpc32xx_adc_probe(struct platform_device *pdev)
goto errout1;
}
- iodev = iio_allocate_device(sizeof(struct lpc32xx_adc_info));
+ iodev = iio_device_alloc(sizeof(struct lpc32xx_adc_info));
if (!iodev) {
dev_err(&pdev->dev, "failed allocating iio device\n");
retval = -ENOMEM;
@@ -200,7 +202,7 @@ errout4:
errout3:
iounmap(info->adc_base);
errout2:
- iio_free_device(iodev);
+ iio_device_free(iodev);
errout1:
return retval;
}
@@ -216,17 +218,26 @@ static int __devexit lpc32xx_adc_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
clk_put(info->clk);
iounmap(info->adc_base);
- iio_free_device(iodev);
+ iio_device_free(iodev);
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id lpc32xx_adc_match[] = {
+ { .compatible = "nxp,lpc3220-adc" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, lpc32xx_adc_match);
+#endif
+
static struct platform_driver lpc32xx_adc_driver = {
.probe = lpc32xx_adc_probe,
.remove = __devexit_p(lpc32xx_adc_remove),
.driver = {
.name = MOD_NAME,
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(lpc32xx_adc_match),
},
};
diff --git a/drivers/staging/iio/adc/max1363_core.c b/drivers/staging/iio/adc/max1363_core.c
index cf3e2ca7e314..6799ce23a395 100644
--- a/drivers/staging/iio/adc/max1363_core.c
+++ b/drivers/staging/iio/adc/max1363_core.c
@@ -32,10 +32,11 @@
#include <linux/err.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/driver.h>
#include "max1363.h"
@@ -248,7 +249,7 @@ static int max1363_read_raw(struct iio_dev *indio_dev,
struct max1363_state *st = iio_priv(indio_dev);
int ret;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
ret = max1363_read_single_chan(indio_dev, chan, val, m);
if (ret < 0)
return ret;
@@ -281,7 +282,8 @@ static const enum max1363_modes max1363_mode_list[] = {
#define MAX1363_EV_M \
(IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) \
| IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING))
-#define MAX1363_INFO_MASK IIO_CHAN_INFO_SCALE_SHARED_BIT
+#define MAX1363_INFO_MASK (IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT)
#define MAX1363_CHAN_U(num, addr, si, bits, evmask) \
{ \
.type = IIO_VOLTAGE, \
@@ -497,7 +499,7 @@ static ssize_t max1363_monitor_show_freq(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct max1363_state *st = iio_priv(dev_get_drvdata(dev));
+ struct max1363_state *st = iio_priv(dev_to_iio_dev(dev));
return sprintf(buf, "%d\n", max1363_monitor_speeds[st->monitor_speed]);
}
@@ -506,7 +508,7 @@ static ssize_t max1363_monitor_store_freq(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct max1363_state *st = iio_priv(indio_dev);
int i, ret;
unsigned long val;
@@ -830,6 +832,7 @@ static struct attribute_group max1363_event_attribute_group = {
static const struct iio_info max1238_info = {
.read_raw = &max1363_read_raw,
.driver_module = THIS_MODULE,
+ .update_scan_mode = &max1363_update_scan_mode,
};
static const struct iio_info max1363_info = {
@@ -1284,11 +1287,14 @@ static int __devinit max1363_probe(struct i2c_client *client,
if (ret)
goto error_put_reg;
- indio_dev = iio_allocate_device(sizeof(struct max1363_state));
+ indio_dev = iio_device_alloc(sizeof(struct max1363_state));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_disable_reg;
}
+ ret = iio_map_array_register(indio_dev, client->dev.platform_data);
+ if (ret < 0)
+ goto error_free_device;
st = iio_priv(indio_dev);
st->reg = reg;
/* this is only used for device removal purposes */
@@ -1299,7 +1305,7 @@ static int __devinit max1363_probe(struct i2c_client *client,
ret = max1363_alloc_scan_masks(indio_dev);
if (ret)
- goto error_free_device;
+ goto error_unregister_map;
/* Estabilish that the iio_dev is a child of the i2c device */
indio_dev->dev.parent = &client->dev;
@@ -1349,8 +1355,10 @@ error_cleanup_ring:
max1363_ring_cleanup(indio_dev);
error_free_available_scan_masks:
kfree(indio_dev->available_scan_masks);
+error_unregister_map:
+ iio_map_array_unregister(indio_dev, client->dev.platform_data);
error_free_device:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_disable_reg:
regulator_disable(reg);
error_put_reg:
@@ -1375,7 +1383,8 @@ static int max1363_remove(struct i2c_client *client)
regulator_disable(reg);
regulator_put(reg);
}
- iio_free_device(indio_dev);
+ iio_map_array_unregister(indio_dev, client->dev.platform_data);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/adc/max1363_ring.c b/drivers/staging/iio/adc/max1363_ring.c
index d0a60a382930..b30201300121 100644
--- a/drivers/staging/iio/adc/max1363_ring.c
+++ b/drivers/staging/iio/adc/max1363_ring.c
@@ -14,10 +14,10 @@
#include <linux/i2c.h>
#include <linux/bitops.h>
-#include "../iio.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
#include "max1363.h"
@@ -54,7 +54,7 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p)
d_size = numvals*2;
else
d_size = numvals;
- if (indio_dev->buffer->scan_timestamp) {
+ if (indio_dev->scan_timestamp) {
d_size += sizeof(s64);
if (d_size % sizeof(s64))
d_size += sizeof(s64) - (d_size % sizeof(s64));
@@ -78,7 +78,7 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p)
time_ns = iio_get_time_ns();
- if (indio_dev->buffer->scan_timestamp)
+ if (indio_dev->scan_timestamp)
memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns));
iio_push_to_buffer(indio_dev->buffer, rxbuf, time_ns);
diff --git a/drivers/staging/iio/adc/spear_adc.c b/drivers/staging/iio/adc/spear_adc.c
new file mode 100644
index 000000000000..64d630e6fe29
--- /dev/null
+++ b/drivers/staging/iio/adc/spear_adc.c
@@ -0,0 +1,448 @@
+/*
+ * ST SPEAr ADC driver
+ *
+ * Copyright 2012 Stefan Roese <sr@denx.de>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/completion.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+/*
+ * SPEAR registers definitions
+ */
+
+#define SCAN_RATE_LO(x) ((x) & 0xFFFF)
+#define SCAN_RATE_HI(x) (((x) >> 0x10) & 0xFFFF)
+#define CLK_LOW(x) (((x) & 0xf) << 0)
+#define CLK_HIGH(x) (((x) & 0xf) << 4)
+
+/* Bit definitions for SPEAR_ADC_STATUS */
+#define START_CONVERSION (1 << 0)
+#define CHANNEL_NUM(x) ((x) << 1)
+#define ADC_ENABLE (1 << 4)
+#define AVG_SAMPLE(x) ((x) << 5)
+#define VREF_INTERNAL (1 << 9)
+
+#define DATA_MASK 0x03ff
+#define DATA_BITS 10
+
+#define MOD_NAME "spear-adc"
+
+#define ADC_CHANNEL_NUM 8
+
+#define CLK_MIN 2500000
+#define CLK_MAX 20000000
+
+struct adc_regs_spear3xx {
+ u32 status;
+ u32 average;
+ u32 scan_rate;
+ u32 clk; /* Not avail for 1340 & 1310 */
+ u32 ch_ctrl[ADC_CHANNEL_NUM];
+ u32 ch_data[ADC_CHANNEL_NUM];
+};
+
+struct chan_data {
+ u32 lsb;
+ u32 msb;
+};
+
+struct adc_regs_spear6xx {
+ u32 status;
+ u32 pad[2];
+ u32 clk;
+ u32 ch_ctrl[ADC_CHANNEL_NUM];
+ struct chan_data ch_data[ADC_CHANNEL_NUM];
+ u32 scan_rate_lo;
+ u32 scan_rate_hi;
+ struct chan_data average;
+};
+
+struct spear_adc_info {
+ struct device_node *np;
+ struct adc_regs_spear3xx __iomem *adc_base_spear3xx;
+ struct adc_regs_spear6xx __iomem *adc_base_spear6xx;
+ struct clk *clk;
+ struct completion completion;
+ u32 current_clk;
+ u32 sampling_freq;
+ u32 avg_samples;
+ u32 vref_external;
+ u32 value;
+};
+
+/*
+ * Functions to access some SPEAr ADC register. Abstracted into
+ * static inline functions, because of different register offsets
+ * on different SoC variants (SPEAr300 vs SPEAr600 etc).
+ */
+static void spear_adc_set_status(struct spear_adc_info *info, u32 val)
+{
+ __raw_writel(val, &info->adc_base_spear6xx->status);
+}
+
+static void spear_adc_set_clk(struct spear_adc_info *info, u32 val)
+{
+ u32 clk_high, clk_low, count;
+ u32 apb_clk = clk_get_rate(info->clk);
+
+ count = (apb_clk + val - 1) / val;
+ clk_low = count / 2;
+ clk_high = count - clk_low;
+ info->current_clk = apb_clk / count;
+
+ __raw_writel(CLK_LOW(clk_low) | CLK_HIGH(clk_high),
+ &info->adc_base_spear6xx->clk);
+}
+
+static void spear_adc_set_ctrl(struct spear_adc_info *info, int n,
+ u32 val)
+{
+ __raw_writel(val, &info->adc_base_spear6xx->ch_ctrl[n]);
+}
+
+static u32 spear_adc_get_average(struct spear_adc_info *info)
+{
+ if (of_device_is_compatible(info->np, "st,spear600-adc")) {
+ return __raw_readl(&info->adc_base_spear6xx->average.msb) &
+ DATA_MASK;
+ } else {
+ return __raw_readl(&info->adc_base_spear3xx->average) &
+ DATA_MASK;
+ }
+}
+
+static void spear_adc_set_scanrate(struct spear_adc_info *info, u32 rate)
+{
+ if (of_device_is_compatible(info->np, "st,spear600-adc")) {
+ __raw_writel(SCAN_RATE_LO(rate),
+ &info->adc_base_spear6xx->scan_rate_lo);
+ __raw_writel(SCAN_RATE_HI(rate),
+ &info->adc_base_spear6xx->scan_rate_hi);
+ } else {
+ __raw_writel(rate, &info->adc_base_spear3xx->scan_rate);
+ }
+}
+
+static int spear_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long mask)
+{
+ struct spear_adc_info *info = iio_priv(indio_dev);
+ u32 scale_mv;
+ u32 status;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&indio_dev->mlock);
+
+ status = CHANNEL_NUM(chan->channel) |
+ AVG_SAMPLE(info->avg_samples) |
+ START_CONVERSION | ADC_ENABLE;
+ if (info->vref_external == 0)
+ status |= VREF_INTERNAL;
+
+ spear_adc_set_status(info, status);
+ wait_for_completion(&info->completion); /* set by ISR */
+ *val = info->value;
+
+ mutex_unlock(&indio_dev->mlock);
+
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ scale_mv = (info->vref_external * 1000) >> DATA_BITS;
+ *val = scale_mv / 1000;
+ *val2 = (scale_mv % 1000) * 1000;
+ return IIO_VAL_INT_PLUS_MICRO;
+ }
+
+ return -EINVAL;
+}
+
+#define SPEAR_ADC_CHAN(idx) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .channel = idx, \
+ .scan_type = { \
+ .sign = 'u', \
+ .storagebits = 16, \
+ }, \
+}
+
+static struct iio_chan_spec spear_adc_iio_channels[] = {
+ SPEAR_ADC_CHAN(0),
+ SPEAR_ADC_CHAN(1),
+ SPEAR_ADC_CHAN(2),
+ SPEAR_ADC_CHAN(3),
+ SPEAR_ADC_CHAN(4),
+ SPEAR_ADC_CHAN(5),
+ SPEAR_ADC_CHAN(6),
+ SPEAR_ADC_CHAN(7),
+};
+
+static irqreturn_t spear_adc_isr(int irq, void *dev_id)
+{
+ struct spear_adc_info *info = (struct spear_adc_info *)dev_id;
+
+ /* Read value to clear IRQ */
+ info->value = spear_adc_get_average(info);
+ complete(&info->completion);
+
+ return IRQ_HANDLED;
+}
+
+static int spear_adc_configure(struct spear_adc_info *info)
+{
+ int i;
+
+ /* Reset ADC core */
+ spear_adc_set_status(info, 0);
+ __raw_writel(0, &info->adc_base_spear6xx->clk);
+ for (i = 0; i < 8; i++)
+ spear_adc_set_ctrl(info, i, 0);
+ spear_adc_set_scanrate(info, 0);
+
+ spear_adc_set_clk(info, info->sampling_freq);
+
+ return 0;
+}
+
+static ssize_t spear_adc_read_frequency(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct spear_adc_info *info = iio_priv(indio_dev);
+
+ return sprintf(buf, "%d\n", info->current_clk);
+}
+
+static ssize_t spear_adc_write_frequency(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct spear_adc_info *info = iio_priv(indio_dev);
+ u32 clk_high, clk_low, count;
+ u32 apb_clk = clk_get_rate(info->clk);
+ unsigned long lval;
+ int ret;
+
+ ret = kstrtoul(buf, 10, &lval);
+ if (ret)
+ return ret;
+
+ mutex_lock(&indio_dev->mlock);
+
+ if ((lval < CLK_MIN) || (lval > CLK_MAX)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ count = (apb_clk + lval - 1) / lval;
+ clk_low = count / 2;
+ clk_high = count - clk_low;
+ info->current_clk = apb_clk / count;
+ spear_adc_set_clk(info, lval);
+
+out:
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret ? ret : len;
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO,
+ spear_adc_read_frequency,
+ spear_adc_write_frequency);
+
+static struct attribute *spear_attributes[] = {
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group spear_attribute_group = {
+ .attrs = spear_attributes,
+};
+
+static const struct iio_info spear_adc_iio_info = {
+ .read_raw = &spear_read_raw,
+ .attrs = &spear_attribute_group,
+ .driver_module = THIS_MODULE,
+};
+
+static int __devinit spear_adc_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct spear_adc_info *info;
+ struct iio_dev *iodev = NULL;
+ int ret = -ENODEV;
+ int irq;
+
+ iodev = iio_device_alloc(sizeof(struct spear_adc_info));
+ if (!iodev) {
+ dev_err(dev, "failed allocating iio device\n");
+ ret = -ENOMEM;
+ goto errout1;
+ }
+
+ info = iio_priv(iodev);
+ info->np = np;
+
+ /*
+ * SPEAr600 has a different register layout than other SPEAr SoC's
+ * (e.g. SPEAr3xx). Let's provide two register base addresses
+ * to support multi-arch kernels.
+ */
+ info->adc_base_spear6xx = of_iomap(np, 0);
+ if (!info->adc_base_spear6xx) {
+ dev_err(dev, "failed mapping memory\n");
+ ret = -ENOMEM;
+ goto errout2;
+ }
+ info->adc_base_spear3xx =
+ (struct adc_regs_spear3xx *)info->adc_base_spear6xx;
+
+ info->clk = clk_get(dev, NULL);
+ if (IS_ERR(info->clk)) {
+ dev_err(dev, "failed getting clock\n");
+ goto errout3;
+ }
+
+ ret = clk_prepare(info->clk);
+ if (ret) {
+ dev_err(dev, "failed preparing clock\n");
+ goto errout4;
+ }
+
+ ret = clk_enable(info->clk);
+ if (ret) {
+ dev_err(dev, "failed enabling clock\n");
+ goto errout5;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if ((irq < 0) || (irq >= NR_IRQS)) {
+ dev_err(dev, "failed getting interrupt resource\n");
+ ret = -EINVAL;
+ goto errout6;
+ }
+
+ ret = devm_request_irq(dev, irq, spear_adc_isr, 0, MOD_NAME, info);
+ if (ret < 0) {
+ dev_err(dev, "failed requesting interrupt\n");
+ goto errout6;
+ }
+
+ if (of_property_read_u32(np, "sampling-frequency",
+ &info->sampling_freq)) {
+ dev_err(dev, "sampling-frequency missing in DT\n");
+ ret = -EINVAL;
+ goto errout6;
+ }
+
+ /*
+ * Optional avg_samples defaults to 0, resulting in single data
+ * conversion
+ */
+ of_property_read_u32(np, "average-samples", &info->avg_samples);
+
+ /*
+ * Optional vref_external defaults to 0, resulting in internal vref
+ * selection
+ */
+ of_property_read_u32(np, "vref-external", &info->vref_external);
+
+ spear_adc_configure(info);
+
+ platform_set_drvdata(pdev, iodev);
+
+ init_completion(&info->completion);
+
+ iodev->name = MOD_NAME;
+ iodev->dev.parent = dev;
+ iodev->info = &spear_adc_iio_info;
+ iodev->modes = INDIO_DIRECT_MODE;
+ iodev->channels = spear_adc_iio_channels;
+ iodev->num_channels = ARRAY_SIZE(spear_adc_iio_channels);
+
+ ret = iio_device_register(iodev);
+ if (ret)
+ goto errout6;
+
+ dev_info(dev, "SPEAR ADC driver loaded, IRQ %d\n", irq);
+
+ return 0;
+
+errout6:
+ clk_disable(info->clk);
+errout5:
+ clk_unprepare(info->clk);
+errout4:
+ clk_put(info->clk);
+errout3:
+ iounmap(info->adc_base_spear6xx);
+errout2:
+ iio_device_free(iodev);
+errout1:
+ return ret;
+}
+
+static int __devexit spear_adc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *iodev = platform_get_drvdata(pdev);
+ struct spear_adc_info *info = iio_priv(iodev);
+
+ iio_device_unregister(iodev);
+ platform_set_drvdata(pdev, NULL);
+ clk_disable(info->clk);
+ clk_unprepare(info->clk);
+ clk_put(info->clk);
+ iounmap(info->adc_base_spear6xx);
+ iio_device_free(iodev);
+
+ return 0;
+}
+
+static const struct of_device_id spear_adc_dt_ids[] = {
+ { .compatible = "st,spear600-adc", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, spear_adc_dt_ids);
+
+static struct platform_driver spear_adc_driver = {
+ .probe = spear_adc_probe,
+ .remove = __devexit_p(spear_adc_remove),
+ .driver = {
+ .name = MOD_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(spear_adc_dt_ids),
+ },
+};
+
+module_platform_driver(spear_adc_driver);
+
+MODULE_AUTHOR("Stefan Roese <sr@denx.de>");
+MODULE_DESCRIPTION("SPEAr ADC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c
index fd6a45444058..8fb014a046a2 100644
--- a/drivers/staging/iio/addac/adt7316.c
+++ b/drivers/staging/iio/addac/adt7316.c
@@ -19,9 +19,9 @@
#include <linux/rtc.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../events.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/events.h>
+#include <linux/iio/sysfs.h>
#include "adt7316.h"
/*
@@ -220,7 +220,7 @@ static ssize_t adt7316_show_enabled(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "%d\n", !!(chip->config1 & ADT7316_EN));
@@ -252,7 +252,7 @@ static ssize_t adt7316_store_enabled(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
int enable;
@@ -276,7 +276,7 @@ static ssize_t adt7316_show_select_ex_temp(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
@@ -290,7 +290,7 @@ static ssize_t adt7316_store_select_ex_temp(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config1;
int ret;
@@ -320,7 +320,7 @@ static ssize_t adt7316_show_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
if (chip->config2 & ADT7316_AD_SINGLE_CH_MODE)
@@ -334,7 +334,7 @@ static ssize_t adt7316_store_mode(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config2;
int ret;
@@ -370,7 +370,7 @@ static ssize_t adt7316_show_ad_channel(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE))
@@ -409,7 +409,7 @@ static ssize_t adt7316_store_ad_channel(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config2;
unsigned long data = 0;
@@ -455,7 +455,7 @@ static ssize_t adt7316_show_all_ad_channels(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
if (!(chip->config2 & ADT7316_AD_SINGLE_CH_MODE))
@@ -477,7 +477,7 @@ static ssize_t adt7316_show_disable_averaging(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "%d\n",
@@ -489,7 +489,7 @@ static ssize_t adt7316_store_disable_averaging(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config2;
int ret;
@@ -516,7 +516,7 @@ static ssize_t adt7316_show_enable_smbus_timeout(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "%d\n",
@@ -528,7 +528,7 @@ static ssize_t adt7316_store_enable_smbus_timeout(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config2;
int ret;
@@ -557,7 +557,7 @@ static ssize_t adt7316_store_reset(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config2;
int ret;
@@ -580,7 +580,7 @@ static ssize_t adt7316_show_powerdown(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "%d\n", !!(chip->config1 & ADT7316_PD));
@@ -591,7 +591,7 @@ static ssize_t adt7316_store_powerdown(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config1;
int ret;
@@ -618,7 +618,7 @@ static ssize_t adt7316_show_fast_ad_clock(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "%d\n", !!(chip->config3 & ADT7316_ADCLK_22_5));
@@ -629,7 +629,7 @@ static ssize_t adt7316_store_fast_ad_clock(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config3;
int ret;
@@ -656,7 +656,7 @@ static ssize_t adt7316_show_da_high_resolution(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
if (chip->config3 & ADT7316_DA_HIGH_RESOLUTION) {
@@ -674,7 +674,7 @@ static ssize_t adt7316_store_da_high_resolution(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config3;
int ret;
@@ -708,7 +708,7 @@ static ssize_t adt7316_show_AIN_internal_Vref(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
if ((chip->id & ID_FAMILY_MASK) != ID_ADT75XX)
@@ -723,7 +723,7 @@ static ssize_t adt7316_store_AIN_internal_Vref(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config3;
int ret;
@@ -755,7 +755,7 @@ static ssize_t adt7316_show_enable_prop_DACA(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "%d\n",
@@ -767,7 +767,7 @@ static ssize_t adt7316_store_enable_prop_DACA(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config3;
int ret;
@@ -794,7 +794,7 @@ static ssize_t adt7316_show_enable_prop_DACB(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "%d\n",
@@ -806,7 +806,7 @@ static ssize_t adt7316_store_enable_prop_DACB(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config3;
int ret;
@@ -833,7 +833,7 @@ static ssize_t adt7316_show_DAC_2Vref_ch_mask(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "0x%x\n",
@@ -845,7 +845,7 @@ static ssize_t adt7316_store_DAC_2Vref_ch_mask(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 dac_config;
unsigned long data = 0;
@@ -876,7 +876,7 @@ static ssize_t adt7316_show_DAC_update_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
if (!(chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA))
@@ -900,7 +900,7 @@ static ssize_t adt7316_store_DAC_update_mode(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 dac_config;
unsigned long data;
@@ -934,7 +934,7 @@ static ssize_t adt7316_show_all_DAC_update_modes(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
if (chip->config3 & ADT7316_DA_EN_VIA_DAC_LDCA)
@@ -955,7 +955,7 @@ static ssize_t adt7316_store_update_DAC(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 ldac_config;
unsigned long data;
@@ -994,7 +994,7 @@ static ssize_t adt7316_show_DA_AB_Vref_bypass(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
@@ -1009,7 +1009,7 @@ static ssize_t adt7316_store_DA_AB_Vref_bypass(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 dac_config;
int ret;
@@ -1039,7 +1039,7 @@ static ssize_t adt7316_show_DA_CD_Vref_bypass(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
@@ -1054,7 +1054,7 @@ static ssize_t adt7316_store_DA_CD_Vref_bypass(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 dac_config;
int ret;
@@ -1084,7 +1084,7 @@ static ssize_t adt7316_show_DAC_internal_Vref(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX)
@@ -1101,7 +1101,7 @@ static ssize_t adt7316_store_DAC_internal_Vref(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 ldac_config;
unsigned long data;
@@ -1220,7 +1220,7 @@ static ssize_t adt7316_show_VDD(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_VDD, buf);
@@ -1231,7 +1231,7 @@ static ssize_t adt7316_show_in_temp(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_IN, buf);
@@ -1243,7 +1243,7 @@ static ssize_t adt7316_show_ex_temp_AIN1(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_ad(chip, ADT7316_AD_SINGLE_CH_EX, buf);
@@ -1256,7 +1256,7 @@ static ssize_t adt7316_show_AIN2(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN2, buf);
@@ -1267,7 +1267,7 @@ static ssize_t adt7316_show_AIN3(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN3, buf);
@@ -1278,7 +1278,7 @@ static ssize_t adt7316_show_AIN4(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_ad(chip, ADT7516_AD_SINGLE_CH_AIN4, buf);
@@ -1330,7 +1330,7 @@ static ssize_t adt7316_show_in_temp_offset(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_temp_offset(chip, ADT7316_IN_TEMP_OFFSET, buf);
@@ -1341,7 +1341,7 @@ static ssize_t adt7316_store_in_temp_offset(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_store_temp_offset(chip, ADT7316_IN_TEMP_OFFSET, buf, len);
@@ -1355,7 +1355,7 @@ static ssize_t adt7316_show_ex_temp_offset(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_temp_offset(chip, ADT7316_EX_TEMP_OFFSET, buf);
@@ -1366,7 +1366,7 @@ static ssize_t adt7316_store_ex_temp_offset(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_store_temp_offset(chip, ADT7316_EX_TEMP_OFFSET, buf, len);
@@ -1380,7 +1380,7 @@ static ssize_t adt7316_show_in_analog_temp_offset(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_temp_offset(chip,
@@ -1392,7 +1392,7 @@ static ssize_t adt7316_store_in_analog_temp_offset(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_store_temp_offset(chip,
@@ -1407,7 +1407,7 @@ static ssize_t adt7316_show_ex_analog_temp_offset(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_temp_offset(chip,
@@ -1419,7 +1419,7 @@ static ssize_t adt7316_store_ex_analog_temp_offset(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_store_temp_offset(chip,
@@ -1504,7 +1504,7 @@ static ssize_t adt7316_show_DAC_A(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_DAC(chip, 0, buf);
@@ -1515,7 +1515,7 @@ static ssize_t adt7316_store_DAC_A(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_store_DAC(chip, 0, buf, len);
@@ -1528,7 +1528,7 @@ static ssize_t adt7316_show_DAC_B(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_DAC(chip, 1, buf);
@@ -1539,7 +1539,7 @@ static ssize_t adt7316_store_DAC_B(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_store_DAC(chip, 1, buf, len);
@@ -1552,7 +1552,7 @@ static ssize_t adt7316_show_DAC_C(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_DAC(chip, 2, buf);
@@ -1563,7 +1563,7 @@ static ssize_t adt7316_store_DAC_C(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_store_DAC(chip, 2, buf, len);
@@ -1576,7 +1576,7 @@ static ssize_t adt7316_show_DAC_D(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_show_DAC(chip, 3, buf);
@@ -1587,7 +1587,7 @@ static ssize_t adt7316_store_DAC_D(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return adt7316_store_DAC(chip, 3, buf, len);
@@ -1600,7 +1600,7 @@ static ssize_t adt7316_show_device_id(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 id;
int ret;
@@ -1618,7 +1618,7 @@ static ssize_t adt7316_show_manufactorer_id(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 id;
int ret;
@@ -1637,7 +1637,7 @@ static ssize_t adt7316_show_device_rev(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 rev;
int ret;
@@ -1655,7 +1655,7 @@ static ssize_t adt7316_show_bus_type(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 stat;
int ret;
@@ -1841,7 +1841,7 @@ static ssize_t adt7316_show_int_mask(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "0x%x\n", chip->int_mask);
@@ -1855,7 +1855,7 @@ static ssize_t adt7316_set_int_mask(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
unsigned long data;
int ret;
@@ -1895,7 +1895,7 @@ static inline ssize_t adt7316_show_ad_bound(struct device *dev,
char *buf)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 val;
int data;
@@ -1926,7 +1926,7 @@ static inline ssize_t adt7316_set_ad_bound(struct device *dev,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
long data;
u8 val;
@@ -1965,7 +1965,7 @@ static ssize_t adt7316_show_int_enabled(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return sprintf(buf, "%d\n", !!(chip->config1 & ADT7316_INT_EN));
@@ -1976,7 +1976,7 @@ static ssize_t adt7316_set_int_enabled(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *dev_info = dev_get_drvdata(dev);
+ struct iio_dev *dev_info = dev_to_iio_dev(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
u8 config1;
int ret;
@@ -2133,7 +2133,7 @@ int __devinit adt7316_probe(struct device *dev, struct adt7316_bus *bus,
unsigned short *adt7316_platform_data = dev->platform_data;
int ret = 0;
- indio_dev = iio_allocate_device(sizeof(*chip));
+ indio_dev = iio_device_alloc(sizeof(*chip));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -2210,7 +2210,7 @@ int __devinit adt7316_probe(struct device *dev, struct adt7316_bus *bus,
error_unreg_irq:
free_irq(chip->bus.irq, indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -2224,7 +2224,7 @@ int __devexit adt7316_remove(struct device *dev)
iio_device_unregister(indio_dev);
if (chip->bus.irq)
free_irq(chip->bus.irq, indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/cdc/ad7150.c b/drivers/staging/iio/cdc/ad7150.c
index e4a08dc9b6f5..a16d1a22db0a 100644
--- a/drivers/staging/iio/cdc/ad7150.c
+++ b/drivers/staging/iio/cdc/ad7150.c
@@ -13,9 +13,9 @@
#include <linux/i2c.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
/*
* AD7150 registers definition
*/
@@ -104,7 +104,7 @@ static int ad7150_read_raw(struct iio_dev *indio_dev,
struct ad7150_chip_info *chip = iio_priv(indio_dev);
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
ret = i2c_smbus_read_word_data(chip->client,
ad7150_addresses[chan->channel][0]);
if (ret < 0)
@@ -341,7 +341,7 @@ static ssize_t ad7150_show_timeout(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7150_chip_info *chip = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
u8 value;
@@ -370,7 +370,7 @@ static ssize_t ad7150_store_timeout(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7150_chip_info *chip = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int chan = IIO_EVENT_CODE_EXTRACT_CHAN(this_attr->address);
@@ -429,7 +429,8 @@ static const struct iio_chan_spec ad7150_channels[] = {
.type = IIO_CAPACITANCE,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT,
.event_mask =
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) |
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING) |
@@ -441,7 +442,8 @@ static const struct iio_chan_spec ad7150_channels[] = {
.type = IIO_CAPACITANCE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT,
.event_mask =
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) |
IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING) |
@@ -556,7 +558,7 @@ static int __devinit ad7150_probe(struct i2c_client *client,
struct ad7150_chip_info *chip;
struct iio_dev *indio_dev;
- indio_dev = iio_allocate_device(sizeof(*chip));
+ indio_dev = iio_device_alloc(sizeof(*chip));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -619,7 +621,7 @@ error_free_irq:
if (client->irq)
free_irq(client->irq, indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -635,7 +637,7 @@ static int __devexit ad7150_remove(struct i2c_client *client)
if (client->dev.platform_data)
free_irq(*(unsigned int *)client->dev.platform_data, indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/cdc/ad7152.c b/drivers/staging/iio/cdc/ad7152.c
index fdb83c35e6dd..98c3015116aa 100644
--- a/drivers/staging/iio/cdc/ad7152.c
+++ b/drivers/staging/iio/cdc/ad7152.c
@@ -15,8 +15,8 @@
#include <linux/module.h>
#include <linux/delay.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
/*
* TODO: Check compliance of calibbias with abi (units)
@@ -97,7 +97,7 @@ static inline ssize_t ad7152_start_calib(struct device *dev,
size_t len,
u8 regval)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7152_chip_info *chip = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
bool doit;
@@ -169,7 +169,7 @@ static ssize_t ad7152_show_filter_rate_setup(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7152_chip_info *chip = iio_priv(indio_dev);
return sprintf(buf, "%d\n",
@@ -181,7 +181,7 @@ static ssize_t ad7152_store_filter_rate_setup(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7152_chip_info *chip = iio_priv(indio_dev);
u8 data;
int ret, i;
@@ -329,7 +329,7 @@ static int ad7152_read_raw(struct iio_dev *indio_dev,
mutex_lock(&indio_dev->mlock);
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
/* First set whether in differential mode */
regval = chip->setup[chan->channel];
@@ -436,7 +436,8 @@ static const struct iio_chan_spec ad7152_channels[] = {
.type = IIO_CAPACITANCE,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
}, {
@@ -445,14 +446,16 @@ static const struct iio_chan_spec ad7152_channels[] = {
.indexed = 1,
.channel = 0,
.channel2 = 2,
- .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
}, {
.type = IIO_CAPACITANCE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
}, {
@@ -461,7 +464,8 @@ static const struct iio_chan_spec ad7152_channels[] = {
.indexed = 1,
.channel = 1,
.channel2 = 3,
- .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
}
@@ -477,7 +481,7 @@ static int __devinit ad7152_probe(struct i2c_client *client,
struct ad7152_chip_info *chip;
struct iio_dev *indio_dev;
- indio_dev = iio_allocate_device(sizeof(*chip));
+ indio_dev = iio_device_alloc(sizeof(*chip));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -509,7 +513,7 @@ static int __devinit ad7152_probe(struct i2c_client *client,
return 0;
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -519,7 +523,7 @@ static int __devexit ad7152_remove(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/cdc/ad7746.c b/drivers/staging/iio/cdc/ad7746.c
index 40b8512cbc32..754e11e87193 100644
--- a/drivers/staging/iio/cdc/ad7746.c
+++ b/drivers/staging/iio/cdc/ad7746.c
@@ -16,8 +16,8 @@
#include <linux/module.h>
#include <linux/stat.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "ad7746.h"
@@ -123,7 +123,8 @@ static const struct iio_chan_spec ad7746_channels[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.address = AD7746_REG_VT_DATA_HIGH << 8 |
AD7746_VTSETUP_VTMD_EXT_VIN,
},
@@ -132,7 +133,8 @@ static const struct iio_chan_spec ad7746_channels[] = {
.indexed = 1,
.channel = 1,
.extend_name = "supply",
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.address = AD7746_REG_VT_DATA_HIGH << 8 |
AD7746_VTSETUP_VTMD_VDD_MON,
},
@@ -140,7 +142,7 @@ static const struct iio_chan_spec ad7746_channels[] = {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .processed_val = IIO_PROCESSED,
+ .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
.address = AD7746_REG_VT_DATA_HIGH << 8 |
AD7746_VTSETUP_VTMD_INT_TEMP,
},
@@ -148,7 +150,7 @@ static const struct iio_chan_spec ad7746_channels[] = {
.type = IIO_TEMP,
.indexed = 1,
.channel = 1,
- .processed_val = IIO_PROCESSED,
+ .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
.address = AD7746_REG_VT_DATA_HIGH << 8 |
AD7746_VTSETUP_VTMD_EXT_TEMP,
},
@@ -156,7 +158,8 @@ static const struct iio_chan_spec ad7746_channels[] = {
.type = IIO_CAPACITANCE,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT |
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT,
@@ -168,7 +171,8 @@ static const struct iio_chan_spec ad7746_channels[] = {
.indexed = 1,
.channel = 0,
.channel2 = 2,
- .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT |
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT,
@@ -179,7 +183,8 @@ static const struct iio_chan_spec ad7746_channels[] = {
.type = IIO_CAPACITANCE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT |
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT,
@@ -192,7 +197,8 @@ static const struct iio_chan_spec ad7746_channels[] = {
.indexed = 1,
.channel = 1,
.channel2 = 3,
- .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT |
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT,
@@ -280,7 +286,7 @@ static inline ssize_t ad7746_start_calib(struct device *dev,
size_t len,
u8 regval)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7746_chip_info *chip = iio_priv(indio_dev);
bool doit;
int ret, timeout = 10;
@@ -319,7 +325,7 @@ static ssize_t ad7746_start_offset_calib(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
int ret = ad7746_select_channel(indio_dev,
&ad7746_channels[to_iio_dev_attr(attr)->address]);
if (ret < 0)
@@ -334,7 +340,7 @@ static ssize_t ad7746_start_gain_calib(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
int ret = ad7746_select_channel(indio_dev,
&ad7746_channels[to_iio_dev_attr(attr)->address]);
if (ret < 0)
@@ -359,7 +365,7 @@ static ssize_t ad7746_show_cap_filter_rate_setup(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7746_chip_info *chip = iio_priv(indio_dev);
return sprintf(buf, "%d\n", ad7746_cap_filter_rate_table[
@@ -371,7 +377,7 @@ static ssize_t ad7746_store_cap_filter_rate_setup(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7746_chip_info *chip = iio_priv(indio_dev);
u8 data;
int ret, i;
@@ -399,7 +405,7 @@ static ssize_t ad7746_show_vt_filter_rate_setup(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7746_chip_info *chip = iio_priv(indio_dev);
return sprintf(buf, "%d\n", ad7746_vt_filter_rate_table[
@@ -411,7 +417,7 @@ static ssize_t ad7746_store_vt_filter_rate_setup(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7746_chip_info *chip = iio_priv(indio_dev);
u8 data;
int ret, i;
@@ -572,7 +578,8 @@ static int ad7746_read_raw(struct iio_dev *indio_dev,
mutex_lock(&indio_dev->mlock);
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
+ case IIO_CHAN_INFO_PROCESSED:
ret = ad7746_select_channel(indio_dev, chan);
if (ret < 0)
goto out;
@@ -696,7 +703,7 @@ static int __devinit ad7746_probe(struct i2c_client *client,
int ret = 0;
unsigned char regval = 0;
- indio_dev = iio_allocate_device(sizeof(*chip));
+ indio_dev = iio_device_alloc(sizeof(*chip));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -756,7 +763,7 @@ static int __devinit ad7746_probe(struct i2c_client *client,
return 0;
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -766,7 +773,7 @@ static int __devexit ad7746_remove(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/dac/Kconfig b/drivers/staging/iio/dac/Kconfig
index a57803a5d1a7..a626f03871ec 100644
--- a/drivers/staging/iio/dac/Kconfig
+++ b/drivers/staging/iio/dac/Kconfig
@@ -56,12 +56,12 @@ config AD5624R_SPI
AD5664R converters (DAC). This driver uses the common SPI interface.
config AD5446
- tristate "Analog Devices AD5444/6, AD5620/40/60 and AD5542A/12A DAC SPI driver"
+ tristate "Analog Devices AD5446 and similar single channel DACs driver"
depends on SPI
help
Say yes here to build support for Analog Devices AD5444, AD5446,
- AD5512A, AD5542A, AD5543, AD5553, AD5601, AD5611, AD5620, AD5621,
- AD5640, AD5660, AD5662 DACs.
+ AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5601, AD5611, AD5620,
+ AD5621, AD5640, AD5660, AD5662 DACs.
To compile this driver as a module, choose M here: the
module will be called ad5446.
diff --git a/drivers/staging/iio/dac/ad5064.c b/drivers/staging/iio/dac/ad5064.c
index 06b162745a3e..047148aa66b2 100644
--- a/drivers/staging/iio/dac/ad5064.c
+++ b/drivers/staging/iio/dac/ad5064.c
@@ -16,8 +16,8 @@
#include <linux/sysfs.h>
#include <linux/regulator/consumer.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "dac.h"
#define AD5064_MAX_DAC_CHANNELS 8
@@ -144,14 +144,14 @@ static const char ad5064_powerdown_modes[][15] = {
};
static ssize_t ad5064_read_powerdown_mode_available(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan, char *buf)
+ uintptr_t private, const struct iio_chan_spec *chan, char *buf)
{
return sprintf(buf, "%s %s %s\n", ad5064_powerdown_modes[1],
ad5064_powerdown_modes[2], ad5064_powerdown_modes[3]);
}
static ssize_t ad5064_read_powerdown_mode(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan, char *buf)
+ uintptr_t private, const struct iio_chan_spec *chan, char *buf)
{
struct ad5064_state *st = iio_priv(indio_dev);
@@ -160,7 +160,8 @@ static ssize_t ad5064_read_powerdown_mode(struct iio_dev *indio_dev,
}
static ssize_t ad5064_write_powerdown_mode(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan, const char *buf, size_t len)
+ uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
+ size_t len)
{
struct ad5064_state *st = iio_priv(indio_dev);
unsigned int mode, i;
@@ -187,7 +188,7 @@ static ssize_t ad5064_write_powerdown_mode(struct iio_dev *indio_dev,
}
static ssize_t ad5064_read_dac_powerdown(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan, char *buf)
+ uintptr_t private, const struct iio_chan_spec *chan, char *buf)
{
struct ad5064_state *st = iio_priv(indio_dev);
@@ -195,7 +196,8 @@ static ssize_t ad5064_read_dac_powerdown(struct iio_dev *indio_dev,
}
static ssize_t ad5064_write_dac_powerdown(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan, const char *buf, size_t len)
+ uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
+ size_t len)
{
struct ad5064_state *st = iio_priv(indio_dev);
bool pwr_down;
@@ -235,7 +237,7 @@ static int ad5064_read_raw(struct iio_dev *indio_dev,
int scale_uv;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
*val = st->dac_cache[chan->channel];
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
@@ -260,7 +262,7 @@ static int ad5064_write_raw(struct iio_dev *indio_dev,
int ret;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
if (val > (1 << chan->scan_type.realbits) || val < 0)
return -EINVAL;
@@ -308,7 +310,8 @@ static struct iio_chan_spec_ext_info ad5064_ext_info[] = {
.indexed = 1, \
.output = 1, \
.channel = (chan), \
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
.address = AD5064_ADDR_DAC(chan), \
.scan_type = IIO_ST('u', (bits), 16, 20 - (bits)), \
.ext_info = ad5064_ext_info, \
@@ -442,7 +445,7 @@ static int __devinit ad5064_probe(struct spi_device *spi)
unsigned int i;
int ret;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -499,7 +502,7 @@ error_free_reg:
if (!st->use_internal_vref)
regulator_bulk_free(ad5064_num_vref(st), st->vref_reg);
error_free:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -517,7 +520,7 @@ static int __devexit ad5064_remove(struct spi_device *spi)
regulator_bulk_free(ad5064_num_vref(st), st->vref_reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/dac/ad5360.c b/drivers/staging/iio/dac/ad5360.c
index cec3693b50a3..38660efca78a 100644
--- a/drivers/staging/iio/dac/ad5360.c
+++ b/drivers/staging/iio/dac/ad5360.c
@@ -16,8 +16,8 @@
#include <linux/sysfs.h>
#include <linux/regulator/consumer.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "dac.h"
#define AD5360_CMD(x) ((x) << 22)
@@ -103,7 +103,8 @@ enum ad5360_type {
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \
IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \
@@ -250,7 +251,7 @@ static ssize_t ad5360_read_dac_powerdown(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5360_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", (bool)(st->ctrl & AD5360_SF_CTRL_PWR_DOWN));
@@ -278,7 +279,7 @@ static int ad5360_update_ctrl(struct iio_dev *indio_dev, unsigned int set,
static ssize_t ad5360_write_dac_powerdown(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
bool pwr_down;
int ret;
@@ -319,7 +320,7 @@ static int ad5360_write_raw(struct iio_dev *indio_dev,
unsigned int ofs_index;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
if (val >= max_val || val < 0)
return -EINVAL;
@@ -376,7 +377,7 @@ static int ad5360_read_raw(struct iio_dev *indio_dev,
int ret;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
ret = ad5360_read(indio_dev, AD5360_READBACK_X1A,
chan->address);
if (ret < 0)
@@ -464,7 +465,7 @@ static int __devinit ad5360_probe(struct spi_device *spi)
unsigned int i;
int ret;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
dev_err(&spi->dev, "Failed to allocate iio device\n");
return -ENOMEM;
@@ -519,7 +520,7 @@ error_free_reg:
error_free_channels:
kfree(indio_dev->channels);
error_free:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -536,7 +537,7 @@ static int __devexit ad5360_remove(struct spi_device *spi)
regulator_bulk_disable(st->chip_info->num_vrefs, st->vref_reg);
regulator_bulk_free(st->chip_info->num_vrefs, st->vref_reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/dac/ad5380.c b/drivers/staging/iio/dac/ad5380.c
index 4c50716fa801..370d2842190e 100644
--- a/drivers/staging/iio/dac/ad5380.c
+++ b/drivers/staging/iio/dac/ad5380.c
@@ -18,8 +18,8 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "dac.h"
@@ -85,7 +85,8 @@ enum ad5380_type {
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT | \
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \
.scan_type = IIO_ST('u', (_bits), 16, 14 - (_bits)) \
@@ -167,7 +168,7 @@ static const struct ad5380_chip_info ad5380_chip_info_tbl[] = {
static ssize_t ad5380_read_dac_powerdown(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5380_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", st->pwr_down);
@@ -176,7 +177,7 @@ static ssize_t ad5380_read_dac_powerdown(struct device *dev,
static ssize_t ad5380_write_dac_powerdown(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5380_state *st = iio_priv(indio_dev);
bool pwr_down;
int ret;
@@ -212,7 +213,7 @@ static const char ad5380_powerdown_modes[][15] = {
static ssize_t ad5380_read_powerdown_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5380_state *st = iio_priv(indio_dev);
unsigned int mode;
int ret;
@@ -229,7 +230,7 @@ static ssize_t ad5380_read_powerdown_mode(struct device *dev,
static ssize_t ad5380_write_powerdown_mode(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5380_state *st = iio_priv(indio_dev);
unsigned int i;
int ret;
@@ -292,7 +293,7 @@ static int ad5380_write_raw(struct iio_dev *indio_dev,
struct ad5380_state *st = iio_priv(indio_dev);
switch (info) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
case IIO_CHAN_INFO_CALIBSCALE:
if (val >= max_val || val < 0)
return -EINVAL;
@@ -322,7 +323,7 @@ static int ad5380_read_raw(struct iio_dev *indio_dev,
int ret;
switch (info) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
case IIO_CHAN_INFO_CALIBSCALE:
ret = regmap_read(st->regmap, ad5380_info_to_reg(chan, info),
val);
@@ -388,7 +389,7 @@ static int __devinit ad5380_probe(struct device *dev, struct regmap *regmap,
unsigned int ctrl = 0;
int ret;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
dev_err(dev, "Failed to allocate iio device\n");
ret = -ENOMEM;
@@ -454,7 +455,7 @@ error_free_reg:
kfree(indio_dev->channels);
error_free:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_regmap_exit:
regmap_exit(regmap);
@@ -476,7 +477,7 @@ static int __devexit ad5380_remove(struct device *dev)
}
regmap_exit(st->regmap);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/dac/ad5421.c b/drivers/staging/iio/dac/ad5421.c
index 0b040b204697..ffbd4c234f57 100644
--- a/drivers/staging/iio/dac/ad5421.c
+++ b/drivers/staging/iio/dac/ad5421.c
@@ -16,9 +16,9 @@
#include <linux/slab.h>
#include <linux/sysfs.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
#include "dac.h"
#include "ad5421.h"
@@ -87,7 +87,8 @@ static const struct iio_chan_spec ad5421_channels[] = {
.indexed = 1,
.output = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_OFFSET_SHARED_BIT |
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
@@ -304,7 +305,7 @@ static int ad5421_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
ret = ad5421_read(indio_dev, AD5421_REG_DAC_DATA);
if (ret < 0)
return ret;
@@ -340,7 +341,7 @@ static int ad5421_write_raw(struct iio_dev *indio_dev,
const unsigned int max_val = 1 << 16;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
if (val >= max_val || val < 0)
return -EINVAL;
@@ -456,7 +457,7 @@ static int __devinit ad5421_probe(struct spi_device *spi)
struct ad5421_state *st;
int ret;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
dev_err(&spi->dev, "Failed to allocate iio device\n");
return -ENOMEM;
@@ -511,7 +512,7 @@ error_free_irq:
if (spi->irq)
free_irq(spi->irq, indio_dev);
error_free:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -523,7 +524,7 @@ static int __devexit ad5421_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
if (spi->irq)
free_irq(spi->irq, indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/dac/ad5446.c b/drivers/staging/iio/dac/ad5446.c
index 633ffbb21814..daa65b384c13 100644
--- a/drivers/staging/iio/dac/ad5446.c
+++ b/drivers/staging/iio/dac/ad5446.c
@@ -18,229 +18,212 @@
#include <linux/err.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "dac.h"
#include "ad5446.h"
-static void ad5446_store_sample(struct ad5446_state *st, unsigned val)
+static int ad5446_write(struct ad5446_state *st, unsigned val)
{
- st->data.d16 = cpu_to_be16(AD5446_LOAD | val);
+ __be16 data = cpu_to_be16(val);
+ return spi_write(st->spi, &data, sizeof(data));
}
-static void ad5542_store_sample(struct ad5446_state *st, unsigned val)
+static int ad5660_write(struct ad5446_state *st, unsigned val)
{
- st->data.d16 = cpu_to_be16(val);
-}
+ uint8_t data[3];
-static void ad5620_store_sample(struct ad5446_state *st, unsigned val)
-{
- st->data.d16 = cpu_to_be16(AD5620_LOAD | val);
-}
+ data[0] = (val >> 16) & 0xFF;
+ data[1] = (val >> 8) & 0xFF;
+ data[2] = val & 0xFF;
-static void ad5660_store_sample(struct ad5446_state *st, unsigned val)
-{
- val |= AD5660_LOAD;
- st->data.d24[0] = (val >> 16) & 0xFF;
- st->data.d24[1] = (val >> 8) & 0xFF;
- st->data.d24[2] = val & 0xFF;
+ return spi_write(st->spi, data, sizeof(data));
}
-static void ad5620_store_pwr_down(struct ad5446_state *st, unsigned mode)
-{
- st->data.d16 = cpu_to_be16(mode << 14);
-}
+static const char * const ad5446_powerdown_modes[] = {
+ "", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"
+};
-static void ad5660_store_pwr_down(struct ad5446_state *st, unsigned mode)
+static ssize_t ad5446_read_powerdown_mode_available(struct iio_dev *indio_dev,
+ uintptr_t private, const struct iio_chan_spec *chan, char *buf)
{
- unsigned val = mode << 16;
-
- st->data.d24[0] = (val >> 16) & 0xFF;
- st->data.d24[1] = (val >> 8) & 0xFF;
- st->data.d24[2] = val & 0xFF;
+ return sprintf(buf, "%s %s %s\n", ad5446_powerdown_modes[1],
+ ad5446_powerdown_modes[2], ad5446_powerdown_modes[3]);
}
-static ssize_t ad5446_write_powerdown_mode(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t len)
+static ssize_t ad5446_write_powerdown_mode(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
+ const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad5446_state *st = iio_priv(indio_dev);
+ int i;
- if (sysfs_streq(buf, "1kohm_to_gnd"))
- st->pwr_down_mode = MODE_PWRDWN_1k;
- else if (sysfs_streq(buf, "100kohm_to_gnd"))
- st->pwr_down_mode = MODE_PWRDWN_100k;
- else if (sysfs_streq(buf, "three_state"))
- st->pwr_down_mode = MODE_PWRDWN_TRISTATE;
- else
+ for (i = 1; i < ARRAY_SIZE(ad5446_powerdown_modes); i++) {
+ if (sysfs_streq(buf, ad5446_powerdown_modes[i])) {
+ st->pwr_down_mode = i;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(ad5446_powerdown_modes))
return -EINVAL;
return len;
}
-static ssize_t ad5446_read_powerdown_mode(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t ad5446_read_powerdown_mode(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
+ char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad5446_state *st = iio_priv(indio_dev);
- char mode[][15] = {"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"};
-
- return sprintf(buf, "%s\n", mode[st->pwr_down_mode]);
+ return sprintf(buf, "%s\n", ad5446_powerdown_modes[st->pwr_down_mode]);
}
-static ssize_t ad5446_read_dac_powerdown(struct device *dev,
- struct device_attribute *attr,
+static ssize_t ad5446_read_dac_powerdown(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad5446_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", st->pwr_down);
}
-static ssize_t ad5446_write_dac_powerdown(struct device *dev,
- struct device_attribute *attr,
+static ssize_t ad5446_write_dac_powerdown(struct iio_dev *indio_dev,
+ uintptr_t private,
+ const struct iio_chan_spec *chan,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad5446_state *st = iio_priv(indio_dev);
- unsigned long readin;
+ unsigned int shift;
+ unsigned int val;
+ bool powerdown;
int ret;
- ret = strict_strtol(buf, 10, &readin);
+ ret = strtobool(buf, &powerdown);
if (ret)
return ret;
- if (readin > 1)
- ret = -EINVAL;
-
mutex_lock(&indio_dev->mlock);
- st->pwr_down = readin;
+ st->pwr_down = powerdown;
- if (st->pwr_down)
- st->chip_info->store_pwr_down(st, st->pwr_down_mode);
- else
- st->chip_info->store_sample(st, st->cached_val);
+ if (st->pwr_down) {
+ shift = chan->scan_type.realbits + chan->scan_type.shift;
+ val = st->pwr_down_mode << shift;
+ } else {
+ val = st->cached_val;
+ }
- ret = spi_sync(st->spi, &st->msg);
+ ret = st->chip_info->write(st, val);
mutex_unlock(&indio_dev->mlock);
return ret ? ret : len;
}
-static IIO_DEVICE_ATTR(out_voltage_powerdown_mode, S_IRUGO | S_IWUSR,
- ad5446_read_powerdown_mode,
- ad5446_write_powerdown_mode, 0);
-
-static IIO_CONST_ATTR(out_voltage_powerdown_mode_available,
- "1kohm_to_gnd 100kohm_to_gnd three_state");
-
-static IIO_DEVICE_ATTR(out_voltage0_powerdown, S_IRUGO | S_IWUSR,
- ad5446_read_dac_powerdown,
- ad5446_write_dac_powerdown, 0);
-
-static struct attribute *ad5446_attributes[] = {
- &iio_dev_attr_out_voltage0_powerdown.dev_attr.attr,
- &iio_dev_attr_out_voltage_powerdown_mode.dev_attr.attr,
- &iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr,
- NULL,
-};
-
-static const struct attribute_group ad5446_attribute_group = {
- .attrs = ad5446_attributes,
+static const struct iio_chan_spec_ext_info ad5064_ext_info_powerdown[] = {
+ {
+ .name = "powerdown",
+ .read = ad5446_read_dac_powerdown,
+ .write = ad5446_write_dac_powerdown,
+ }, {
+ .name = "powerdown_mode",
+ .read = ad5446_read_powerdown_mode,
+ .write = ad5446_write_powerdown_mode,
+ }, {
+ .name = "powerdown_mode_available",
+ .shared = true,
+ .read = ad5446_read_powerdown_mode_available,
+ },
+ { },
};
-#define AD5446_CHANNEL(bits, storage, shift) { \
+#define _AD5446_CHANNEL(bits, storage, shift, ext) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.channel = 0, \
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \
- .scan_type = IIO_ST('u', (bits), (storage), (shift)) \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .scan_type = IIO_ST('u', (bits), (storage), (shift)), \
+ .ext_info = (ext), \
}
+#define AD5446_CHANNEL(bits, storage, shift) \
+ _AD5446_CHANNEL(bits, storage, shift, NULL)
+
+#define AD5446_CHANNEL_POWERDOWN(bits, storage, shift) \
+ _AD5446_CHANNEL(bits, storage, shift, ad5064_ext_info_powerdown)
+
static const struct ad5446_chip_info ad5446_chip_info_tbl[] = {
[ID_AD5444] = {
.channel = AD5446_CHANNEL(12, 16, 2),
- .store_sample = ad5446_store_sample,
+ .write = ad5446_write,
},
[ID_AD5446] = {
.channel = AD5446_CHANNEL(14, 16, 0),
- .store_sample = ad5446_store_sample,
+ .write = ad5446_write,
},
[ID_AD5541A] = {
.channel = AD5446_CHANNEL(16, 16, 0),
- .store_sample = ad5542_store_sample,
- },
- [ID_AD5542A] = {
- .channel = AD5446_CHANNEL(16, 16, 0),
- .store_sample = ad5542_store_sample,
- },
- [ID_AD5543] = {
- .channel = AD5446_CHANNEL(16, 16, 0),
- .store_sample = ad5542_store_sample,
+ .write = ad5446_write,
},
[ID_AD5512A] = {
.channel = AD5446_CHANNEL(12, 16, 4),
- .store_sample = ad5542_store_sample,
+ .write = ad5446_write,
},
[ID_AD5553] = {
.channel = AD5446_CHANNEL(14, 16, 0),
- .store_sample = ad5542_store_sample,
+ .write = ad5446_write,
},
[ID_AD5601] = {
- .channel = AD5446_CHANNEL(8, 16, 6),
- .store_sample = ad5542_store_sample,
- .store_pwr_down = ad5620_store_pwr_down,
+ .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 6),
+ .write = ad5446_write,
},
[ID_AD5611] = {
- .channel = AD5446_CHANNEL(10, 16, 4),
- .store_sample = ad5542_store_sample,
- .store_pwr_down = ad5620_store_pwr_down,
+ .channel = AD5446_CHANNEL_POWERDOWN(10, 16, 4),
+ .write = ad5446_write,
},
[ID_AD5621] = {
- .channel = AD5446_CHANNEL(12, 16, 2),
- .store_sample = ad5542_store_sample,
- .store_pwr_down = ad5620_store_pwr_down,
+ .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
+ .write = ad5446_write,
},
[ID_AD5620_2500] = {
- .channel = AD5446_CHANNEL(12, 16, 2),
+ .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
.int_vref_mv = 2500,
- .store_sample = ad5620_store_sample,
- .store_pwr_down = ad5620_store_pwr_down,
+ .write = ad5446_write,
},
[ID_AD5620_1250] = {
- .channel = AD5446_CHANNEL(12, 16, 2),
+ .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2),
.int_vref_mv = 1250,
- .store_sample = ad5620_store_sample,
- .store_pwr_down = ad5620_store_pwr_down,
+ .write = ad5446_write,
},
[ID_AD5640_2500] = {
- .channel = AD5446_CHANNEL(14, 16, 0),
+ .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
.int_vref_mv = 2500,
- .store_sample = ad5620_store_sample,
- .store_pwr_down = ad5620_store_pwr_down,
+ .write = ad5446_write,
},
[ID_AD5640_1250] = {
- .channel = AD5446_CHANNEL(14, 16, 0),
+ .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0),
.int_vref_mv = 1250,
- .store_sample = ad5620_store_sample,
- .store_pwr_down = ad5620_store_pwr_down,
+ .write = ad5446_write,
},
[ID_AD5660_2500] = {
- .channel = AD5446_CHANNEL(16, 16, 0),
+ .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
.int_vref_mv = 2500,
- .store_sample = ad5660_store_sample,
- .store_pwr_down = ad5660_store_pwr_down,
+ .write = ad5660_write,
},
[ID_AD5660_1250] = {
- .channel = AD5446_CHANNEL(16, 16, 0),
+ .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
.int_vref_mv = 1250,
- .store_sample = ad5660_store_sample,
- .store_pwr_down = ad5660_store_pwr_down,
+ .write = ad5660_write,
+ },
+ [ID_AD5662] = {
+ .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0),
+ .write = ad5660_write,
},
};
@@ -254,6 +237,9 @@ static int ad5446_read_raw(struct iio_dev *indio_dev,
unsigned long scale_uv;
switch (m) {
+ case IIO_CHAN_INFO_RAW:
+ *val = st->cached_val;
+ return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
scale_uv = (st->vref_mv * 1000) >> chan->scan_type.realbits;
*val = scale_uv / 1000;
@@ -271,18 +257,18 @@ static int ad5446_write_raw(struct iio_dev *indio_dev,
long mask)
{
struct ad5446_state *st = iio_priv(indio_dev);
- int ret;
+ int ret = 0;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
if (val >= (1 << chan->scan_type.realbits) || val < 0)
return -EINVAL;
val <<= chan->scan_type.shift;
mutex_lock(&indio_dev->mlock);
st->cached_val = val;
- st->chip_info->store_sample(st, val);
- ret = spi_sync(st->spi, &st->msg);
+ if (!st->pwr_down)
+ ret = st->chip_info->write(st, val);
mutex_unlock(&indio_dev->mlock);
break;
default:
@@ -295,13 +281,6 @@ static int ad5446_write_raw(struct iio_dev *indio_dev,
static const struct iio_info ad5446_info = {
.read_raw = ad5446_read_raw,
.write_raw = ad5446_write_raw,
- .attrs = &ad5446_attribute_group,
- .driver_module = THIS_MODULE,
-};
-
-static const struct iio_info ad5446_info_no_pwr_down = {
- .read_raw = ad5446_read_raw,
- .write_raw = ad5446_write_raw,
.driver_module = THIS_MODULE,
};
@@ -321,7 +300,7 @@ static int __devinit ad5446_probe(struct spi_device *spi)
voltage_uv = regulator_get_voltage(reg);
}
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_disable_reg;
@@ -337,38 +316,17 @@ static int __devinit ad5446_probe(struct spi_device *spi)
/* Establish that the iio_dev is a child of the spi device */
indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name;
- if (st->chip_info->store_pwr_down)
- indio_dev->info = &ad5446_info;
- else
- indio_dev->info = &ad5446_info_no_pwr_down;
+ indio_dev->info = &ad5446_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = &st->chip_info->channel;
indio_dev->num_channels = 1;
- /* Setup default message */
-
- st->xfer.tx_buf = &st->data;
- st->xfer.len = st->chip_info->channel.scan_type.storagebits / 8;
-
- spi_message_init(&st->msg);
- spi_message_add_tail(&st->xfer, &st->msg);
-
- switch (spi_get_device_id(spi)->driver_data) {
- case ID_AD5620_2500:
- case ID_AD5620_1250:
- case ID_AD5640_2500:
- case ID_AD5640_1250:
- case ID_AD5660_2500:
- case ID_AD5660_1250:
+ if (st->chip_info->int_vref_mv)
st->vref_mv = st->chip_info->int_vref_mv;
- break;
- default:
- if (voltage_uv)
- st->vref_mv = voltage_uv / 1000;
- else
- dev_warn(&spi->dev,
- "reference voltage unspecified\n");
- }
+ else if (voltage_uv)
+ st->vref_mv = voltage_uv / 1000;
+ else
+ dev_warn(&spi->dev, "reference voltage unspecified\n");
ret = iio_device_register(indio_dev);
if (ret)
@@ -377,7 +335,7 @@ static int __devinit ad5446_probe(struct spi_device *spi)
return 0;
error_free_device:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_disable_reg:
if (!IS_ERR(reg))
regulator_disable(reg);
@@ -398,7 +356,7 @@ static int ad5446_remove(struct spi_device *spi)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
@@ -408,8 +366,8 @@ static const struct spi_device_id ad5446_id[] = {
{"ad5446", ID_AD5446},
{"ad5512a", ID_AD5512A},
{"ad5541a", ID_AD5541A},
- {"ad5542a", ID_AD5542A},
- {"ad5543", ID_AD5543},
+ {"ad5542a", ID_AD5541A}, /* ad5541a and ad5542a are compatible */
+ {"ad5543", ID_AD5541A}, /* ad5541a and ad5543 are compatible */
{"ad5553", ID_AD5553},
{"ad5601", ID_AD5601},
{"ad5611", ID_AD5611},
@@ -420,6 +378,7 @@ static const struct spi_device_id ad5446_id[] = {
{"ad5640-1250", ID_AD5640_1250},
{"ad5660-2500", ID_AD5660_2500},
{"ad5660-1250", ID_AD5660_1250},
+ {"ad5662", ID_AD5662},
{}
};
MODULE_DEVICE_TABLE(spi, ad5446_id);
diff --git a/drivers/staging/iio/dac/ad5446.h b/drivers/staging/iio/dac/ad5446.h
index 4ea3476fb065..dfd68ce7427e 100644
--- a/drivers/staging/iio/dac/ad5446.h
+++ b/drivers/staging/iio/dac/ad5446.h
@@ -34,43 +34,30 @@
* @spi: spi_device
* @chip_info: chip model specific constants, available modes etc
* @reg: supply regulator
- * @poll_work: bottom half of polling interrupt handler
* @vref_mv: actual reference voltage used
- * @xfer: default spi transfer
- * @msg: default spi message
- * @data: spi transmit buffer
*/
struct ad5446_state {
struct spi_device *spi;
const struct ad5446_chip_info *chip_info;
struct regulator *reg;
- struct work_struct poll_work;
unsigned short vref_mv;
unsigned cached_val;
unsigned pwr_down_mode;
unsigned pwr_down;
- struct spi_transfer xfer;
- struct spi_message msg;
- union {
- unsigned short d16;
- unsigned char d24[3];
- } data;
};
/**
* struct ad5446_chip_info - chip specific information
* @channel: channel spec for the DAC
* @int_vref_mv: AD5620/40/60: the internal reference voltage
- * @store_sample: chip specific helper function to store the datum
- * @store_sample: chip specific helper function to store the powerpown cmd
+ * @write: chip specific helper function to write to the register
*/
struct ad5446_chip_info {
struct iio_chan_spec channel;
u16 int_vref_mv;
- void (*store_sample) (struct ad5446_state *st, unsigned val);
- void (*store_pwr_down) (struct ad5446_state *st, unsigned mode);
+ int (*write)(struct ad5446_state *st, unsigned val);
};
/**
@@ -85,8 +72,6 @@ enum ad5446_supported_device_ids {
ID_AD5444,
ID_AD5446,
ID_AD5541A,
- ID_AD5542A,
- ID_AD5543,
ID_AD5512A,
ID_AD5553,
ID_AD5601,
@@ -98,6 +83,7 @@ enum ad5446_supported_device_ids {
ID_AD5640_1250,
ID_AD5660_2500,
ID_AD5660_1250,
+ ID_AD5662,
};
#endif /* IIO_DAC_AD5446_H_ */
diff --git a/drivers/staging/iio/dac/ad5504.c b/drivers/staging/iio/dac/ad5504.c
index bc17205fe722..019cf15cd24a 100644
--- a/drivers/staging/iio/dac/ad5504.c
+++ b/drivers/staging/iio/dac/ad5504.c
@@ -16,9 +16,9 @@
#include <linux/regulator/consumer.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
#include "dac.h"
#include "ad5504.h"
@@ -27,7 +27,8 @@
.indexed = 1, \
.output = 1, \
.channel = (_chan), \
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
.address = AD5504_ADDR_DAC(_chan), \
.scan_type = IIO_ST('u', 12, 16, 0), \
}
@@ -81,7 +82,7 @@ static int ad5504_read_raw(struct iio_dev *indio_dev,
int ret;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
ret = ad5504_spi_read(st->spi, chan->address);
if (ret < 0)
return ret;
@@ -109,7 +110,7 @@ static int ad5504_write_raw(struct iio_dev *indio_dev,
int ret;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
if (val >= (1 << chan->scan_type.realbits) || val < 0)
return -EINVAL;
@@ -124,7 +125,7 @@ static int ad5504_write_raw(struct iio_dev *indio_dev,
static ssize_t ad5504_read_powerdown_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5504_state *st = iio_priv(indio_dev);
const char mode[][14] = {"20kohm_to_gnd", "three_state"};
@@ -136,7 +137,7 @@ static ssize_t ad5504_write_powerdown_mode(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5504_state *st = iio_priv(indio_dev);
int ret;
@@ -154,7 +155,7 @@ static ssize_t ad5504_read_dac_powerdown(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5504_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -168,7 +169,7 @@ static ssize_t ad5504_write_dac_powerdown(struct device *dev,
{
long readin;
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5504_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -287,7 +288,7 @@ static int __devinit ad5504_probe(struct spi_device *spi)
struct regulator *reg;
int ret, voltage_uv = 0;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -350,7 +351,7 @@ error_put_reg:
if (!IS_ERR(reg))
regulator_put(reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -368,7 +369,7 @@ static int __devexit ad5504_remove(struct spi_device *spi)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/dac/ad5624r_spi.c b/drivers/staging/iio/dac/ad5624r_spi.c
index 10c7484366ef..42ff644ac43e 100644
--- a/drivers/staging/iio/dac/ad5624r_spi.c
+++ b/drivers/staging/iio/dac/ad5624r_spi.c
@@ -16,8 +16,8 @@
#include <linux/regulator/consumer.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "dac.h"
#include "ad5624r.h"
@@ -26,7 +26,8 @@
.indexed = 1, \
.output = 1, \
.channel = (_chan), \
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
.address = (_chan), \
.scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)), \
}
@@ -122,7 +123,7 @@ static int ad5624r_write_raw(struct iio_dev *indio_dev,
int ret;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
if (val >= (1 << chan->scan_type.realbits) || val < 0)
return -EINVAL;
@@ -140,7 +141,7 @@ static int ad5624r_write_raw(struct iio_dev *indio_dev,
static ssize_t ad5624r_read_powerdown_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5624r_state *st = iio_priv(indio_dev);
char mode[][15] = {"", "1kohm_to_gnd", "100kohm_to_gnd", "three_state"};
@@ -152,7 +153,7 @@ static ssize_t ad5624r_write_powerdown_mode(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5624r_state *st = iio_priv(indio_dev);
int ret;
@@ -172,7 +173,7 @@ static ssize_t ad5624r_read_dac_powerdown(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5624r_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -186,7 +187,7 @@ static ssize_t ad5624r_write_dac_powerdown(struct device *dev,
{
long readin;
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5624r_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -255,7 +256,7 @@ static int __devinit ad5624r_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
int ret, voltage_uv = 0;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -305,7 +306,7 @@ error_disable_reg:
error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
@@ -321,7 +322,7 @@ static int __devexit ad5624r_remove(struct spi_device *spi)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/dac/ad5686.c b/drivers/staging/iio/dac/ad5686.c
index 2415a6e60c77..c1e903ebc7b9 100644
--- a/drivers/staging/iio/dac/ad5686.c
+++ b/drivers/staging/iio/dac/ad5686.c
@@ -16,8 +16,8 @@
#include <linux/sysfs.h>
#include <linux/regulator/consumer.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "dac.h"
#define AD5686_DAC_CHANNELS 4
@@ -98,7 +98,8 @@ enum ad5686_supported_device_ids {
.indexed = 1, \
.output = 1, \
.channel = chan, \
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
.address = AD5686_ADDR_DAC(chan), \
.scan_type = IIO_ST('u', bits, 16, shift) \
}
@@ -172,7 +173,7 @@ static int ad5686_spi_read(struct ad5686_state *st, u8 addr)
static ssize_t ad5686_read_powerdown_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5686_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -186,7 +187,7 @@ static ssize_t ad5686_write_powerdown_mode(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5686_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
unsigned mode;
@@ -210,7 +211,7 @@ static ssize_t ad5686_read_dac_powerdown(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5686_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -224,7 +225,7 @@ static ssize_t ad5686_write_dac_powerdown(struct device *dev,
{
bool readin;
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5686_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -296,7 +297,7 @@ static int ad5686_read_raw(struct iio_dev *indio_dev,
int ret;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
ret = ad5686_spi_read(st, chan->address);
mutex_unlock(&indio_dev->mlock);
@@ -326,7 +327,7 @@ static int ad5686_write_raw(struct iio_dev *indio_dev,
int ret;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
if (val > (1 << chan->scan_type.realbits) || val < 0)
return -EINVAL;
@@ -358,7 +359,7 @@ static int __devinit ad5686_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
int ret, regdone = 0, voltage_uv = 0;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -410,7 +411,7 @@ error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -425,7 +426,7 @@ static int __devexit ad5686_remove(struct spi_device *spi)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/dac/ad5764.c b/drivers/staging/iio/dac/ad5764.c
index f73a73079490..03dbd937b081 100644
--- a/drivers/staging/iio/dac/ad5764.c
+++ b/drivers/staging/iio/dac/ad5764.c
@@ -16,8 +16,8 @@
#include <linux/sysfs.h>
#include <linux/regulator/consumer.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "dac.h"
#define AD5764_REG_SF_NOP 0x0
@@ -79,7 +79,8 @@ enum ad5764_type {
.output = 1, \
.channel = (_chan), \
.address = (_chan), \
- .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_OFFSET_SHARED_BIT | \
IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \
IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \
IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \
@@ -188,7 +189,7 @@ static int ad5764_write_raw(struct iio_dev *indio_dev,
unsigned int reg;
switch (info) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
if (val >= max_val || val < 0)
return -EINVAL;
val <<= chan->scan_type.shift;
@@ -228,7 +229,7 @@ static int ad5764_read_raw(struct iio_dev *indio_dev,
int ret;
switch (info) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
reg = AD5764_REG_DATA(chan->address);
ret = ad5764_read(indio_dev, reg, val);
if (ret < 0)
@@ -280,7 +281,7 @@ static int __devinit ad5764_probe(struct spi_device *spi)
struct ad5764_state *st;
int ret;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
dev_err(&spi->dev, "Failed to allocate iio device\n");
return -ENOMEM;
@@ -335,7 +336,7 @@ error_free_reg:
if (st->chip_info->int_vref == 0)
regulator_bulk_free(ARRAY_SIZE(st->vref_reg), st->vref_reg);
error_free:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -352,7 +353,7 @@ static int __devexit ad5764_remove(struct spi_device *spi)
regulator_bulk_free(ARRAY_SIZE(st->vref_reg), st->vref_reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/dac/ad5791.c b/drivers/staging/iio/dac/ad5791.c
index ac45636a8d72..13d8b5bb1cea 100644
--- a/drivers/staging/iio/dac/ad5791.c
+++ b/drivers/staging/iio/dac/ad5791.c
@@ -17,8 +17,8 @@
#include <linux/regulator/consumer.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "dac.h"
#include "ad5791.h"
@@ -78,7 +78,8 @@ static int ad5791_spi_read(struct spi_device *spi, u8 addr, u32 *val)
.indexed = 1, \
.address = AD5791_ADDR_DAC0, \
.channel = 0, \
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT | \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT | \
IIO_CHAN_INFO_OFFSET_SHARED_BIT, \
.scan_type = IIO_ST('u', bits, 24, shift) \
}
@@ -93,7 +94,7 @@ static const struct iio_chan_spec ad5791_channels[] = {
static ssize_t ad5791_read_powerdown_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5791_state *st = iio_priv(indio_dev);
const char mode[][14] = {"6kohm_to_gnd", "three_state"};
@@ -105,7 +106,7 @@ static ssize_t ad5791_write_powerdown_mode(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5791_state *st = iio_priv(indio_dev);
int ret;
@@ -123,7 +124,7 @@ static ssize_t ad5791_read_dac_powerdown(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5791_state *st = iio_priv(indio_dev);
return sprintf(buf, "%d\n", st->pwr_down);
@@ -135,7 +136,7 @@ static ssize_t ad5791_write_dac_powerdown(struct device *dev,
{
long readin;
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5791_state *st = iio_priv(indio_dev);
ret = strict_strtol(buf, 10, &readin);
@@ -231,7 +232,7 @@ static int ad5791_read_raw(struct iio_dev *indio_dev,
int ret;
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
ret = ad5791_spi_read(st->spi, chan->address, val);
if (ret)
return ret;
@@ -263,7 +264,7 @@ static int ad5791_write_raw(struct iio_dev *indio_dev,
struct ad5791_state *st = iio_priv(indio_dev);
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
val &= AD5791_RES_MASK(chan->scan_type.realbits);
val <<= chan->scan_type.shift;
@@ -288,7 +289,7 @@ static int __devinit ad5791_probe(struct spi_device *spi)
struct ad5791_state *st;
int ret, pos_voltage_uv = 0, neg_voltage_uv = 0;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -368,7 +369,7 @@ error_put_reg_neg:
error_put_reg_pos:
if (!IS_ERR(st->reg_vdd))
regulator_put(st->reg_vdd);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
@@ -389,7 +390,7 @@ static int __devexit ad5791_remove(struct spi_device *spi)
regulator_disable(st->reg_vss);
regulator_put(st->reg_vss);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/dac/max517.c b/drivers/staging/iio/dac/max517.c
index 41483c72cec1..5287cad1f3a4 100644
--- a/drivers/staging/iio/dac/max517.c
+++ b/drivers/staging/iio/dac/max517.c
@@ -25,8 +25,8 @@
#include <linux/i2c.h>
#include <linux/err.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "dac.h"
#include "max517.h"
@@ -59,7 +59,7 @@ static ssize_t max517_set_value(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count, int channel)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct max517_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
u8 outbuf[4]; /* 1x or 2x command + value */
@@ -128,7 +128,7 @@ static ssize_t max517_show_scale(struct device *dev,
struct device_attribute *attr,
char *buf, int channel)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct max517_data *data = iio_priv(indio_dev);
/* Corresponds to Vref / 2^(bits) */
unsigned int scale_uv = (data->vref_mv[channel - 1] * 1000) >> 8;
@@ -218,7 +218,7 @@ static int max517_probe(struct i2c_client *client,
struct max517_platform_data *platform_data = client->dev.platform_data;
int err;
- indio_dev = iio_allocate_device(sizeof(*data));
+ indio_dev = iio_device_alloc(sizeof(*data));
if (indio_dev == NULL) {
err = -ENOMEM;
goto exit;
@@ -257,14 +257,15 @@ static int max517_probe(struct i2c_client *client,
return 0;
exit_free_device:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
exit:
return err;
}
static int max517_remove(struct i2c_client *client)
{
- iio_free_device(i2c_get_clientdata(client));
+ iio_device_unregister(i2c_get_clientdata(client));
+ iio_device_free(i2c_get_clientdata(client));
return 0;
}
diff --git a/drivers/staging/iio/dds/dds.h b/drivers/staging/iio/dds/dds.h
deleted file mode 100644
index d8ac3a93baf6..000000000000
--- a/drivers/staging/iio/dds/dds.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * dds.h - sysfs attributes associated with DDS devices
- *
- * Copyright (c) 2010 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-/**
- * /sys/bus/iio/devices/.../ddsX_freqY
- */
-
-#define IIO_DEV_ATTR_FREQ(_channel, _num, _mode, _show, _store, _addr) \
- IIO_DEVICE_ATTR(dds##_channel##_freq##_num, \
- _mode, _show, _store, _addr)
-
-/**
- * /sys/bus/iio/devices/.../ddsX_freqY_scale
- */
-
-#define IIO_CONST_ATTR_FREQ_SCALE(_channel, _string) \
- IIO_CONST_ATTR(dds##_channel##_freq_scale, _string)
-
-/**
- * /sys/bus/iio/devices/.../ddsX_freqsymbol
- */
-
-#define IIO_DEV_ATTR_FREQSYMBOL(_channel, _mode, _show, _store, _addr) \
- IIO_DEVICE_ATTR(dds##_channel##_freqsymbol, \
- _mode, _show, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_phaseY
- */
-
-#define IIO_DEV_ATTR_PHASE(_channel, _num, _mode, _show, _store, _addr) \
- IIO_DEVICE_ATTR(dds##_channel##_phase##_num, \
- _mode, _show, _store, _addr)
-
-/**
- * /sys/bus/iio/devices/.../ddsX_phaseY_scale
- */
-
-#define IIO_CONST_ATTR_PHASE_SCALE(_channel, _string) \
- IIO_CONST_ATTR(dds##_channel##_phase_scale, _string)
-
-/**
- * /sys/bus/iio/devices/.../ddsX_phasesymbol
- */
-
-#define IIO_DEV_ATTR_PHASESYMBOL(_channel, _mode, _show, _store, _addr) \
- IIO_DEVICE_ATTR(dds##_channel##_phasesymbol, \
- _mode, _show, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_pincontrol_en
- */
-
-#define IIO_DEV_ATTR_PINCONTROL_EN(_channel, _mode, _show, _store, _addr)\
- IIO_DEVICE_ATTR(dds##_channel##_pincontrol_en, \
- _mode, _show, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_pincontrol_freq_en
- */
-
-#define IIO_DEV_ATTR_PINCONTROL_FREQ_EN(_channel, _mode, _show, _store, _addr)\
- IIO_DEVICE_ATTR(dds##_channel##_pincontrol_freq_en, \
- _mode, _show, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_pincontrol_phase_en
- */
-
-#define IIO_DEV_ATTR_PINCONTROL_PHASE_EN(_channel, _mode, _show, _store, _addr)\
- IIO_DEVICE_ATTR(dds##_channel##_pincontrol_phase_en, \
- _mode, _show, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_out_enable
- */
-
-#define IIO_DEV_ATTR_OUT_ENABLE(_channel, _mode, _show, _store, _addr) \
- IIO_DEVICE_ATTR(dds##_channel##_out_enable, \
- _mode, _show, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_outY_enable
- */
-
-#define IIO_DEV_ATTR_OUTY_ENABLE(_channel, _output, \
- _mode, _show, _store, _addr) \
- IIO_DEVICE_ATTR(dds##_channel##_out##_output##_enable, \
- _mode, _show, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_outY_wavetype
- */
-
-#define IIO_DEV_ATTR_OUT_WAVETYPE(_channel, _output, _store, _addr) \
- IIO_DEVICE_ATTR(dds##_channel##_out##_output##_wavetype, \
- S_IWUSR, NULL, _store, _addr);
-
-/**
- * /sys/bus/iio/devices/.../ddsX_outY_wavetype_available
- */
-
-#define IIO_CONST_ATTR_OUT_WAVETYPES_AVAILABLE(_channel, _output, _modes)\
- IIO_CONST_ATTR(dds##_channel##_out##_output##_wavetype_available,\
- _modes);
diff --git a/drivers/staging/iio/dds/Kconfig b/drivers/staging/iio/frequency/Kconfig
index 93b7141b2c1f..93b7141b2c1f 100644
--- a/drivers/staging/iio/dds/Kconfig
+++ b/drivers/staging/iio/frequency/Kconfig
diff --git a/drivers/staging/iio/dds/Makefile b/drivers/staging/iio/frequency/Makefile
index 147746176b9b..147746176b9b 100644
--- a/drivers/staging/iio/dds/Makefile
+++ b/drivers/staging/iio/frequency/Makefile
diff --git a/drivers/staging/iio/dds/ad5930.c b/drivers/staging/iio/frequency/ad5930.c
index 9c32d1beae25..2d541d0eebef 100644
--- a/drivers/staging/iio/dds/ad5930.c
+++ b/drivers/staging/iio/frequency/ad5930.c
@@ -16,8 +16,8 @@
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#define DRV_NAME "ad5930"
@@ -48,7 +48,7 @@ static ssize_t ad5930_set_parameter(struct device *dev,
struct spi_transfer xfer;
int ret;
struct ad5903_config *config = (struct ad5903_config *)buf;
- struct iio_dev *idev = dev_get_drvdata(dev);
+ struct iio_dev *idev = dev_to_iio_dev(dev);
struct ad5930_state *st = iio_priv(idev);
config->control = (config->control & ~value_mask);
@@ -97,7 +97,7 @@ static int __devinit ad5930_probe(struct spi_device *spi)
struct iio_dev *idev;
int ret = 0;
- idev = iio_allocate_device(sizeof(*st));
+ idev = iio_device_alloc(sizeof(*st));
if (idev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -122,7 +122,7 @@ static int __devinit ad5930_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(idev);
+ iio_device_free(idev);
error_ret:
return ret;
}
@@ -130,7 +130,7 @@ error_ret:
static int __devexit ad5930_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/dds/ad9832.c b/drivers/staging/iio/frequency/ad9832.c
index 2ccf25dd9289..fed39404e34a 100644
--- a/drivers/staging/iio/dds/ad9832.c
+++ b/drivers/staging/iio/frequency/ad9832.c
@@ -16,8 +16,8 @@
#include <linux/module.h>
#include <asm/div64.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "dds.h"
#include "ad9832.h"
@@ -77,7 +77,7 @@ static ssize_t ad9832_write(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad9832_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
@@ -177,18 +177,18 @@ static IIO_DEV_ATTR_OUT_ENABLE(0, S_IWUSR, NULL,
ad9832_write, AD9832_OUTPUT_EN);
static struct attribute *ad9832_attributes[] = {
- &iio_dev_attr_dds0_freq0.dev_attr.attr,
- &iio_dev_attr_dds0_freq1.dev_attr.attr,
- &iio_const_attr_dds0_freq_scale.dev_attr.attr,
- &iio_dev_attr_dds0_phase0.dev_attr.attr,
- &iio_dev_attr_dds0_phase1.dev_attr.attr,
- &iio_dev_attr_dds0_phase2.dev_attr.attr,
- &iio_dev_attr_dds0_phase3.dev_attr.attr,
- &iio_const_attr_dds0_phase_scale.dev_attr.attr,
- &iio_dev_attr_dds0_pincontrol_en.dev_attr.attr,
- &iio_dev_attr_dds0_freqsymbol.dev_attr.attr,
- &iio_dev_attr_dds0_phasesymbol.dev_attr.attr,
- &iio_dev_attr_dds0_out_enable.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_frequency0.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_frequency1.dev_attr.attr,
+ &iio_const_attr_out_altvoltage0_frequency_scale.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_phase0.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_phase1.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_phase2.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_phase3.dev_attr.attr,
+ &iio_const_attr_out_altvoltage0_phase_scale.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_pincontrol_en.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_frequencysymbol.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_phasesymbol.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_out_enable.dev_attr.attr,
NULL,
};
@@ -221,7 +221,7 @@ static int __devinit ad9832_probe(struct spi_device *spi)
goto error_put_reg;
}
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_disable_reg;
@@ -313,7 +313,7 @@ static int __devinit ad9832_probe(struct spi_device *spi)
return 0;
error_free_device:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_disable_reg:
if (!IS_ERR(reg))
regulator_disable(reg);
@@ -334,7 +334,7 @@ static int __devexit ad9832_remove(struct spi_device *spi)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/dds/ad9832.h b/drivers/staging/iio/frequency/ad9832.h
index c5b701f8aabb..c5b701f8aabb 100644
--- a/drivers/staging/iio/dds/ad9832.h
+++ b/drivers/staging/iio/frequency/ad9832.h
diff --git a/drivers/staging/iio/dds/ad9834.c b/drivers/staging/iio/frequency/ad9834.c
index 38a2de08626f..1b2dc741d2ce 100644
--- a/drivers/staging/iio/dds/ad9834.c
+++ b/drivers/staging/iio/frequency/ad9834.c
@@ -19,8 +19,8 @@
#include <linux/module.h>
#include <asm/div64.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "dds.h"
#include "ad9834.h"
@@ -66,7 +66,7 @@ static ssize_t ad9834_write(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad9834_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
@@ -145,7 +145,7 @@ static ssize_t ad9834_store_wavetype(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad9834_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret = 0;
@@ -203,7 +203,7 @@ static ssize_t ad9834_show_out0_wavetype_available(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad9834_state *st = iio_priv(indio_dev);
char *str;
@@ -218,14 +218,14 @@ static ssize_t ad9834_show_out0_wavetype_available(struct device *dev,
}
-static IIO_DEVICE_ATTR(dds0_out0_wavetype_available, S_IRUGO,
+static IIO_DEVICE_ATTR(out_altvoltage0_out0_wavetype_available, S_IRUGO,
ad9834_show_out0_wavetype_available, NULL, 0);
static ssize_t ad9834_show_out1_wavetype_available(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad9834_state *st = iio_priv(indio_dev);
char *str;
@@ -237,7 +237,7 @@ static ssize_t ad9834_show_out1_wavetype_available(struct device *dev,
return sprintf(buf, "%s\n", str);
}
-static IIO_DEVICE_ATTR(dds0_out1_wavetype_available, S_IRUGO,
+static IIO_DEVICE_ATTR(out_altvoltage0_out1_wavetype_available, S_IRUGO,
ad9834_show_out1_wavetype_available, NULL, 0);
/**
@@ -263,36 +263,36 @@ static IIO_DEV_ATTR_OUT_WAVETYPE(0, 0, ad9834_store_wavetype, 0);
static IIO_DEV_ATTR_OUT_WAVETYPE(0, 1, ad9834_store_wavetype, 1);
static struct attribute *ad9834_attributes[] = {
- &iio_dev_attr_dds0_freq0.dev_attr.attr,
- &iio_dev_attr_dds0_freq1.dev_attr.attr,
- &iio_const_attr_dds0_freq_scale.dev_attr.attr,
- &iio_dev_attr_dds0_phase0.dev_attr.attr,
- &iio_dev_attr_dds0_phase1.dev_attr.attr,
- &iio_const_attr_dds0_phase_scale.dev_attr.attr,
- &iio_dev_attr_dds0_pincontrol_en.dev_attr.attr,
- &iio_dev_attr_dds0_freqsymbol.dev_attr.attr,
- &iio_dev_attr_dds0_phasesymbol.dev_attr.attr,
- &iio_dev_attr_dds0_out_enable.dev_attr.attr,
- &iio_dev_attr_dds0_out1_enable.dev_attr.attr,
- &iio_dev_attr_dds0_out0_wavetype.dev_attr.attr,
- &iio_dev_attr_dds0_out1_wavetype.dev_attr.attr,
- &iio_dev_attr_dds0_out0_wavetype_available.dev_attr.attr,
- &iio_dev_attr_dds0_out1_wavetype_available.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_frequency0.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_frequency1.dev_attr.attr,
+ &iio_const_attr_out_altvoltage0_frequency_scale.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_phase0.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_phase1.dev_attr.attr,
+ &iio_const_attr_out_altvoltage0_phase_scale.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_pincontrol_en.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_frequencysymbol.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_phasesymbol.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_out_enable.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_out1_enable.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_out0_wavetype.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_out1_wavetype.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_out0_wavetype_available.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_out1_wavetype_available.dev_attr.attr,
NULL,
};
static struct attribute *ad9833_attributes[] = {
- &iio_dev_attr_dds0_freq0.dev_attr.attr,
- &iio_dev_attr_dds0_freq1.dev_attr.attr,
- &iio_const_attr_dds0_freq_scale.dev_attr.attr,
- &iio_dev_attr_dds0_phase0.dev_attr.attr,
- &iio_dev_attr_dds0_phase1.dev_attr.attr,
- &iio_const_attr_dds0_phase_scale.dev_attr.attr,
- &iio_dev_attr_dds0_freqsymbol.dev_attr.attr,
- &iio_dev_attr_dds0_phasesymbol.dev_attr.attr,
- &iio_dev_attr_dds0_out_enable.dev_attr.attr,
- &iio_dev_attr_dds0_out0_wavetype.dev_attr.attr,
- &iio_dev_attr_dds0_out0_wavetype_available.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_frequency0.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_frequency1.dev_attr.attr,
+ &iio_const_attr_out_altvoltage0_frequency_scale.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_phase0.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_phase1.dev_attr.attr,
+ &iio_const_attr_out_altvoltage0_phase_scale.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_frequencysymbol.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_phasesymbol.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_out_enable.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_out0_wavetype.dev_attr.attr,
+ &iio_dev_attr_out_altvoltage0_out0_wavetype_available.dev_attr.attr,
NULL,
};
@@ -334,7 +334,7 @@ static int __devinit ad9834_probe(struct spi_device *spi)
goto error_put_reg;
}
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_disable_reg;
@@ -414,7 +414,7 @@ static int __devinit ad9834_probe(struct spi_device *spi)
return 0;
error_free_device:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_disable_reg:
if (!IS_ERR(reg))
regulator_disable(reg);
@@ -434,7 +434,7 @@ static int __devexit ad9834_remove(struct spi_device *spi)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/dds/ad9834.h b/drivers/staging/iio/frequency/ad9834.h
index ed5ed8d0007f..ed5ed8d0007f 100644
--- a/drivers/staging/iio/dds/ad9834.h
+++ b/drivers/staging/iio/frequency/ad9834.h
diff --git a/drivers/staging/iio/dds/ad9850.c b/drivers/staging/iio/frequency/ad9850.c
index f4f731bb2191..74abee054ac0 100644
--- a/drivers/staging/iio/dds/ad9850.c
+++ b/drivers/staging/iio/frequency/ad9850.c
@@ -16,8 +16,8 @@
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#define DRV_NAME "ad9850"
@@ -43,7 +43,7 @@ static ssize_t ad9850_set_parameter(struct device *dev,
struct spi_transfer xfer;
int ret;
struct ad9850_config *config = (struct ad9850_config *)buf;
- struct iio_dev *idev = dev_get_drvdata(dev);
+ struct iio_dev *idev = dev_to_iio_dev(dev);
struct ad9850_state *st = iio_priv(idev);
xfer.len = len;
@@ -83,7 +83,7 @@ static int __devinit ad9850_probe(struct spi_device *spi)
struct iio_dev *idev;
int ret = 0;
- idev = iio_allocate_device(sizeof(*st));
+ idev = iio_device_alloc(sizeof(*st));
if (idev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -108,7 +108,7 @@ static int __devinit ad9850_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(idev);
+ iio_device_free(idev);
error_ret:
return ret;
}
@@ -116,7 +116,7 @@ error_ret:
static int __devexit ad9850_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/dds/ad9852.c b/drivers/staging/iio/frequency/ad9852.c
index 554266c615a8..fd9d14a413a5 100644
--- a/drivers/staging/iio/dds/ad9852.c
+++ b/drivers/staging/iio/frequency/ad9852.c
@@ -16,8 +16,8 @@
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#define DRV_NAME "ad9852"
@@ -71,7 +71,7 @@ static ssize_t ad9852_set_parameter(struct device *dev,
struct spi_transfer xfer;
int ret;
struct ad9852_config *config = (struct ad9852_config *)buf;
- struct iio_dev *idev = dev_get_drvdata(dev);
+ struct iio_dev *idev = dev_to_iio_dev(dev);
struct ad9852_state *st = iio_priv(idev);
xfer.len = 3;
@@ -232,7 +232,7 @@ static int __devinit ad9852_probe(struct spi_device *spi)
struct iio_dev *idev;
int ret = 0;
- idev = iio_allocate_device(sizeof(*st));
+ idev = iio_device_alloc(sizeof(*st));
if (idev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -258,7 +258,7 @@ static int __devinit ad9852_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(idev);
+ iio_device_free(idev);
error_ret:
return ret;
@@ -267,7 +267,7 @@ error_ret:
static int __devexit ad9852_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/dds/ad9910.c b/drivers/staging/iio/frequency/ad9910.c
index 3985766d6f87..5a7ba305b75a 100644
--- a/drivers/staging/iio/dds/ad9910.c
+++ b/drivers/staging/iio/frequency/ad9910.c
@@ -16,8 +16,8 @@
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#define DRV_NAME "ad9910"
@@ -123,7 +123,7 @@ static ssize_t ad9910_set_parameter(struct device *dev,
struct spi_transfer xfer;
int ret;
struct ad9910_config *config = (struct ad9910_config *)buf;
- struct iio_dev *idev = dev_get_drvdata(dev);
+ struct iio_dev *idev = dev_to_iio_dev(dev);
struct ad9910_state *st = iio_priv(idev);
xfer.len = 5;
@@ -367,7 +367,7 @@ static int __devinit ad9910_probe(struct spi_device *spi)
struct iio_dev *idev;
int ret = 0;
- idev = iio_allocate_device(sizeof(*st));
+ idev = iio_device_alloc(sizeof(*st));
if (idev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -392,7 +392,7 @@ static int __devinit ad9910_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(idev);
+ iio_device_free(idev);
error_ret:
return ret;
}
@@ -400,7 +400,7 @@ error_ret:
static int __devexit ad9910_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/dds/ad9951.c b/drivers/staging/iio/frequency/ad9951.c
index 4d150048002a..ba6f49ff09ae 100644
--- a/drivers/staging/iio/dds/ad9951.c
+++ b/drivers/staging/iio/frequency/ad9951.c
@@ -16,8 +16,8 @@
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#define DRV_NAME "ad9951"
@@ -64,7 +64,7 @@ static ssize_t ad9951_set_parameter(struct device *dev,
struct spi_transfer xfer;
int ret;
struct ad9951_config *config = (struct ad9951_config *)buf;
- struct iio_dev *idev = dev_get_drvdata(dev);
+ struct iio_dev *idev = dev_to_iio_dev(dev);
struct ad9951_state *st = iio_priv(idev);
xfer.len = 3;
@@ -176,7 +176,7 @@ static int __devinit ad9951_probe(struct spi_device *spi)
struct iio_dev *idev;
int ret = 0;
- idev = iio_allocate_device(sizeof(*st));
+ idev = iio_device_alloc(sizeof(*st));
if (idev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -202,7 +202,7 @@ static int __devinit ad9951_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(idev);
+ iio_device_free(idev);
error_ret:
return ret;
@@ -211,7 +211,7 @@ error_ret:
static int __devexit ad9951_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/frequency/dds.h b/drivers/staging/iio/frequency/dds.h
new file mode 100644
index 000000000000..c3342f6e052b
--- /dev/null
+++ b/drivers/staging/iio/frequency/dds.h
@@ -0,0 +1,110 @@
+/*
+ * dds.h - sysfs attributes associated with DDS devices
+ *
+ * Copyright (c) 2010 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_frequencyY
+ */
+
+#define IIO_DEV_ATTR_FREQ(_channel, _num, _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(out_altvoltage##_channel##_frequency##_num, \
+ _mode, _show, _store, _addr)
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_frequencyY_scale
+ */
+
+#define IIO_CONST_ATTR_FREQ_SCALE(_channel, _string) \
+ IIO_CONST_ATTR(out_altvoltage##_channel##_frequency_scale, _string)
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_frequencysymbol
+ */
+
+#define IIO_DEV_ATTR_FREQSYMBOL(_channel, _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(out_altvoltage##_channel##_frequencysymbol, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_phaseY
+ */
+
+#define IIO_DEV_ATTR_PHASE(_channel, _num, _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(out_altvoltage##_channel##_phase##_num, \
+ _mode, _show, _store, _addr)
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_phaseY_scale
+ */
+
+#define IIO_CONST_ATTR_PHASE_SCALE(_channel, _string) \
+ IIO_CONST_ATTR(out_altvoltage##_channel##_phase_scale, _string)
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_phasesymbol
+ */
+
+#define IIO_DEV_ATTR_PHASESYMBOL(_channel, _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(out_altvoltage##_channel##_phasesymbol, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_en
+ */
+
+#define IIO_DEV_ATTR_PINCONTROL_EN(_channel, _mode, _show, _store, _addr)\
+ IIO_DEVICE_ATTR(out_altvoltage##_channel##_pincontrol_en, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_frequency_en
+ */
+
+#define IIO_DEV_ATTR_PINCONTROL_FREQ_EN(_channel, _mode, _show, _store, _addr)\
+ IIO_DEVICE_ATTR(out_altvoltage##_channel##_pincontrol_frequency_en,\
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_pincontrol_phase_en
+ */
+
+#define IIO_DEV_ATTR_PINCONTROL_PHASE_EN(_channel, _mode, _show, _store, _addr)\
+ IIO_DEVICE_ATTR(out_altvoltage##_channel##_pincontrol_phase_en, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_out_enable
+ */
+
+#define IIO_DEV_ATTR_OUT_ENABLE(_channel, _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(out_altvoltage##_channel##_out_enable, \
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_outY_enable
+ */
+
+#define IIO_DEV_ATTR_OUTY_ENABLE(_channel, _output, \
+ _mode, _show, _store, _addr) \
+ IIO_DEVICE_ATTR(out_altvoltage##_channel##_out##_output##_enable,\
+ _mode, _show, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_outY_wavetype
+ */
+
+#define IIO_DEV_ATTR_OUT_WAVETYPE(_channel, _output, _store, _addr) \
+ IIO_DEVICE_ATTR(out_altvoltage##_channel##_out##_output##_wavetype,\
+ S_IWUSR, NULL, _store, _addr);
+
+/**
+ * /sys/bus/iio/devices/.../out_altvoltageX_outY_wavetype_available
+ */
+
+#define IIO_CONST_ATTR_OUT_WAVETYPES_AVAILABLE(_channel, _output, _modes)\
+ IIO_CONST_ATTR( \
+ out_altvoltage##_channel##_out##_output##_wavetype_available, _modes);
diff --git a/drivers/staging/iio/gyro/adis16060_core.c b/drivers/staging/iio/gyro/adis16060_core.c
index 02cc23420b90..9931e2060e1f 100644
--- a/drivers/staging/iio/gyro/adis16060_core.c
+++ b/drivers/staging/iio/gyro/adis16060_core.c
@@ -15,8 +15,8 @@
#include <linux/slab.h>
#include <linux/sysfs.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#define ADIS16060_GYRO 0x20 /* Measure Angular Rate (Gyro) */
#define ADIS16060_TEMP_OUT 0x10 /* Measure Temperature */
@@ -85,7 +85,7 @@ static int adis16060_read_raw(struct iio_dev *indio_dev,
int ret;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
/* Take the iio_dev status lock */
mutex_lock(&indio_dev->mlock);
ret = adis16060_spi_write(indio_dev, chan->address);
@@ -120,22 +120,26 @@ static const struct iio_chan_spec adis16060_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.address = ADIS16060_GYRO,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.address = ADIS16060_AIN1,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.address = ADIS16060_AIN2,
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = ADIS16060_TEMP_OUT,
}
@@ -148,7 +152,7 @@ static int __devinit adis16060_r_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -174,7 +178,7 @@ static int __devinit adis16060_r_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -183,7 +187,7 @@ error_ret:
static int adis16060_r_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/gyro/adis16080_core.c b/drivers/staging/iio/gyro/adis16080_core.c
index 1815490db8b4..11f1dccd7a0d 100644
--- a/drivers/staging/iio/gyro/adis16080_core.c
+++ b/drivers/staging/iio/gyro/adis16080_core.c
@@ -14,8 +14,8 @@
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#define ADIS16080_DIN_GYRO (0 << 10) /* Gyroscope output */
#define ADIS16080_DIN_TEMP (1 << 10) /* Temperature output */
@@ -87,7 +87,7 @@ static int adis16080_read_raw(struct iio_dev *indio_dev,
mutex_lock(&indio_dev->mlock);
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
ret = adis16080_spi_write(indio_dev,
chan->address |
ADIS16080_DIN_WRITE);
@@ -110,21 +110,25 @@ static const struct iio_chan_spec adis16080_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.address = ADIS16080_DIN_GYRO,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.address = ADIS16080_DIN_AIN1,
}, {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.address = ADIS16080_DIN_AIN2,
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.address = ADIS16080_DIN_TEMP,
}
};
@@ -141,7 +145,7 @@ static int __devinit adis16080_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -167,7 +171,7 @@ static int __devinit adis16080_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -176,7 +180,7 @@ error_ret:
static int adis16080_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/gyro/adis16130_core.c b/drivers/staging/iio/gyro/adis16130_core.c
index 947eb86f05d8..bf61cd0b5bbc 100644
--- a/drivers/staging/iio/gyro/adis16130_core.c
+++ b/drivers/staging/iio/gyro/adis16130_core.c
@@ -16,8 +16,8 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#define ADIS16130_CON 0x0
#define ADIS16130_CON_RD (1 << 6)
@@ -100,11 +100,13 @@ static const struct iio_chan_spec adis16130_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.address = ADIS16130_RATEDATA,
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.address = ADIS16130_TEMPDATA,
}
};
@@ -121,7 +123,7 @@ static int __devinit adis16130_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -145,7 +147,7 @@ static int __devinit adis16130_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
@@ -155,7 +157,7 @@ error_ret:
static int adis16130_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/gyro/adis16260_core.c b/drivers/staging/iio/gyro/adis16260_core.c
index 8f6af47e9559..ec765f955f8d 100644
--- a/drivers/staging/iio/gyro/adis16260_core.c
+++ b/drivers/staging/iio/gyro/adis16260_core.c
@@ -18,9 +18,9 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "adis16260.h"
@@ -149,7 +149,7 @@ static ssize_t adis16260_read_frequency_available(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adis16260_state *st = iio_priv(indio_dev);
if (spi_get_device_id(st->us)->driver_data)
return sprintf(buf, "%s\n", "0.129 ~ 256");
@@ -161,7 +161,7 @@ static ssize_t adis16260_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adis16260_state *st = iio_priv(indio_dev);
int ret, len = 0;
u16 t;
@@ -186,7 +186,7 @@ static ssize_t adis16260_write_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adis16260_state *st = iio_priv(indio_dev);
long val;
int ret;
@@ -237,7 +237,7 @@ static ssize_t adis16260_write_reset(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
if (len < 1)
return -EINVAL;
switch (buf[0]) {
@@ -389,30 +389,76 @@ enum adis16260_channel {
};
#define ADIS16260_GYRO_CHANNEL_SET(axis, mod) \
struct iio_chan_spec adis16260_channels_##axis[] = { \
- IIO_CHAN(IIO_ANGL_VEL, 1, 0, 0, NULL, 0, mod, \
- IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
- IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
- gyro, ADIS16260_SCAN_GYRO, \
- IIO_ST('s', 14, 16, 0), 0), \
- IIO_CHAN(IIO_ANGL, 1, 0, 0, NULL, 0, mod, \
- 0, \
- angle, ADIS16260_SCAN_ANGL, \
- IIO_ST('u', 14, 16, 0), 0), \
- IIO_CHAN(IIO_TEMP, 0, 1, 0, NULL, 0, 0, \
- IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
- temp, ADIS16260_SCAN_TEMP, \
- IIO_ST('u', 12, 16, 0), 0), \
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "supply", 0, 0, \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
- in_supply, ADIS16260_SCAN_SUPPLY, \
- IIO_ST('u', 12, 16, 0), 0), \
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, NULL, 1, 0, \
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
- in_aux, ADIS16260_SCAN_AUX_ADC, \
- IIO_ST('u', 12, 16, 0), 0), \
- IIO_CHAN_SOFT_TIMESTAMP(5) \
+ { \
+ .type = IIO_ANGL_VEL, \
+ .modified = 1, \
+ .channel2 = mod, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT | \
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .address = gyro, \
+ .scan_index = ADIS16260_SCAN_GYRO, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 14, \
+ .storagebits = 16, \
+ }, \
+ }, { \
+ .type = IIO_ANGL, \
+ .modified = 1, \
+ .channel2 = mod, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, \
+ .address = angle, \
+ .scan_index = ADIS16260_SCAN_ANGL, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 14, \
+ .storagebits = 16, \
+ }, \
+ }, { \
+ .type = IIO_TEMP, \
+ .indexed = 1, \
+ .channel = 0, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .address = temp, \
+ .scan_index = ADIS16260_SCAN_TEMP, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ }, \
+ }, { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = 0, \
+ .extend_name = "supply", \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .address = in_supply, \
+ .scan_index = ADIS16260_SCAN_SUPPLY, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ }, \
+ }, { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = 1, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .address = in_aux, \
+ .scan_index = ADIS16260_SCAN_AUX_ADC, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ }, \
+ }, \
+ IIO_CHAN_SOFT_TIMESTAMP(5), \
}
static const ADIS16260_GYRO_CHANNEL_SET(x, IIO_MOD_X);
@@ -440,7 +486,7 @@ static int adis16260_read_raw(struct iio_dev *indio_dev,
s16 val16;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
addr = adis16260_addresses[chan->address][0];
ret = adis16260_spi_read_reg_16(indio_dev, addr, &val16);
@@ -581,7 +627,7 @@ static int __devinit adis16260_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -666,7 +712,7 @@ error_uninitialize_ring:
error_unreg_ring_funcs:
adis16260_unconfigure_ring(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -687,7 +733,7 @@ static int adis16260_remove(struct spi_device *spi)
adis16260_remove_trigger(indio_dev);
iio_buffer_unregister(indio_dev);
adis16260_unconfigure_ring(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
err_ret:
return ret;
diff --git a/drivers/staging/iio/gyro/adis16260_ring.c b/drivers/staging/iio/gyro/adis16260_ring.c
index 711f15122a08..0fe2d9dfb6cd 100644
--- a/drivers/staging/iio/gyro/adis16260_ring.c
+++ b/drivers/staging/iio/gyro/adis16260_ring.c
@@ -5,20 +5,19 @@
#include <linux/spi/spi.h>
#include <linux/slab.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
#include "adis16260.h"
/**
* adis16260_read_ring_data() read data registers which will be placed into ring
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @indio_dev: the IIO device
* @rx: somewhere to pass back the value read
**/
-static int adis16260_read_ring_data(struct device *dev, u8 *rx)
+static int adis16260_read_ring_data(struct iio_dev *indio_dev, u8 *rx)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct adis16260_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[ADIS16260_OUTPUTS + 1];
int ret;
@@ -66,22 +65,21 @@ static irqreturn_t adis16260_trigger_handler(int irq, void *p)
struct iio_buffer *ring = indio_dev->buffer;
int i = 0;
s16 *data;
- size_t datasize = ring->access->get_bytes_per_datum(ring);
- data = kmalloc(datasize , GFP_KERNEL);
+ data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL) {
dev_err(&st->us->dev, "memory alloc failed in ring bh");
return -ENOMEM;
}
if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength) &&
- adis16260_read_ring_data(&indio_dev->dev, st->rx) >= 0)
+ adis16260_read_ring_data(indio_dev, st->rx) >= 0)
for (; i < bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength); i++)
data[i] = be16_to_cpup((__be16 *)&(st->rx[i*2]));
/* Guaranteed to be aligned with 8 byte boundary */
- if (ring->scan_timestamp)
+ if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
ring->access->store_to(ring, (u8 *)data, pf->timestamp);
diff --git a/drivers/staging/iio/gyro/adis16260_trigger.c b/drivers/staging/iio/gyro/adis16260_trigger.c
index 8299cd18d705..034559e4d5b9 100644
--- a/drivers/staging/iio/gyro/adis16260_trigger.c
+++ b/drivers/staging/iio/gyro/adis16260_trigger.c
@@ -3,8 +3,8 @@
#include <linux/spi/spi.h>
#include <linux/export.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
#include "adis16260.h"
/**
@@ -29,7 +29,7 @@ int adis16260_probe_trigger(struct iio_dev *indio_dev)
int ret;
struct adis16260_state *st = iio_priv(indio_dev);
- st->trig = iio_allocate_trigger("%s-dev%d",
+ st->trig = iio_trigger_alloc("%s-dev%d",
spi_get_device_id(st->us)->name,
indio_dev->id);
if (st->trig == NULL) {
@@ -60,7 +60,7 @@ int adis16260_probe_trigger(struct iio_dev *indio_dev)
error_free_irq:
free_irq(st->us->irq, st->trig);
error_free_trig:
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
error_ret:
return ret;
}
@@ -71,5 +71,5 @@ void adis16260_remove_trigger(struct iio_dev *indio_dev)
iio_trigger_unregister(st->trig);
free_irq(st->us->irq, st->trig);
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
}
diff --git a/drivers/staging/iio/gyro/adxrs450.h b/drivers/staging/iio/gyro/adxrs450.h
index af0c870100b6..f8cf21f02943 100644
--- a/drivers/staging/iio/gyro/adxrs450.h
+++ b/drivers/staging/iio/gyro/adxrs450.h
@@ -49,7 +49,7 @@ enum {
* @us: actual spi_device
* @buf_lock: mutex to protect tx and rx
* @tx: transmit buffer
- * @rx: recieve buffer
+ * @rx: receive buffer
**/
struct adxrs450_state {
struct spi_device *us;
diff --git a/drivers/staging/iio/gyro/adxrs450_core.c b/drivers/staging/iio/gyro/adxrs450_core.c
index 15e2496f70c8..6513119b1e90 100644
--- a/drivers/staging/iio/gyro/adxrs450_core.c
+++ b/drivers/staging/iio/gyro/adxrs450_core.c
@@ -18,8 +18,8 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "adxrs450.h"
@@ -265,7 +265,7 @@ static int adxrs450_read_raw(struct iio_dev *indio_dev,
s16 t;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
switch (chan->type) {
case IIO_ANGL_VEL:
ret = adxrs450_spi_sensor_data(indio_dev, &t);
@@ -329,14 +329,16 @@ static const struct iio_chan_spec adxrs450_channels[2][2] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
}
},
[ID_ADXRS453] = {
@@ -344,13 +346,15 @@ static const struct iio_chan_spec adxrs450_channels[2][2] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE_BIT,
}, {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
}
},
};
@@ -368,7 +372,7 @@ static int __devinit adxrs450_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -399,7 +403,7 @@ static int __devinit adxrs450_probe(struct spi_device *spi)
error_initial:
iio_device_unregister(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
@@ -408,7 +412,7 @@ error_ret:
static int adxrs450_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/iio_dummy_evgen.c b/drivers/staging/iio/iio_dummy_evgen.c
index f39f346bf04f..0cd4fe916bf9 100644
--- a/drivers/staging/iio/iio_dummy_evgen.c
+++ b/drivers/staging/iio/iio_dummy_evgen.c
@@ -22,8 +22,8 @@
#include <linux/sysfs.h>
#include "iio_dummy_evgen.h"
-#include "iio.h"
-#include "sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
/* Fiddly bit of faking and irq without hardware */
#define IIO_EVENTGEN_NO 10
diff --git a/drivers/staging/iio/iio_hwmon.c b/drivers/staging/iio/iio_hwmon.c
index a603a5f51f93..b03554fee443 100644
--- a/drivers/staging/iio/iio_hwmon.c
+++ b/drivers/staging/iio/iio_hwmon.c
@@ -14,8 +14,8 @@
#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
-#include "consumer.h"
-#include "types.h"
+#include <linux/iio/consumer.h>
+#include <linux/iio/types.h>
/**
* struct iio_hwmon_state - device instance state
diff --git a/drivers/staging/iio/iio_simple_dummy.c b/drivers/staging/iio/iio_simple_dummy.c
index e3a94572bb40..310411911ed7 100644
--- a/drivers/staging/iio/iio_simple_dummy.c
+++ b/drivers/staging/iio/iio_simple_dummy.c
@@ -19,10 +19,10 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include "iio.h"
-#include "sysfs.h"
-#include "events.h"
-#include "buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/buffer.h>
#include "iio_simple_dummy.h"
/*
@@ -73,6 +73,12 @@ static struct iio_chan_spec iio_dummy_channels[] = {
/* What other information is available? */
.info_mask =
/*
+ * in_voltage0_raw
+ * Raw (unscaled no bias removal etc) measurement
+ * from the device.
+ */
+ IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ /*
* in_voltage0_offset
* Offset for userspace to apply prior to scale
* when converting to standard units (microvolts)
@@ -114,6 +120,12 @@ static struct iio_chan_spec iio_dummy_channels[] = {
.channel2 = 2,
.info_mask =
/*
+ * in_voltage1-voltage2_raw
+ * Raw (unscaled no bias removal etc) measurement
+ * from the device.
+ */
+ IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ /*
* in_voltage-voltage_scale
* Shared version of scale - shared by differential
* input channels of type IIO_VOLTAGE.
@@ -135,6 +147,7 @@ static struct iio_chan_spec iio_dummy_channels[] = {
.channel = 3,
.channel2 = 4,
.info_mask =
+ IIO_CHAN_INFO_RAW_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT,
.scan_index = diffvoltage3m4,
.scan_type = {
@@ -154,6 +167,7 @@ static struct iio_chan_spec iio_dummy_channels[] = {
/* Channel 2 is use for modifiers */
.channel2 = IIO_MOD_X,
.info_mask =
+ IIO_CHAN_INFO_RAW_SEPARATE_BIT |
/*
* Internal bias correction value. Applied
* by the hardware or driver prior to userspace
@@ -177,6 +191,7 @@ static struct iio_chan_spec iio_dummy_channels[] = {
/* DAC channel out_voltage0_raw */
{
.type = IIO_VOLTAGE,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.output = 1,
.indexed = 1,
.channel = 0,
@@ -203,7 +218,7 @@ static int iio_dummy_read_raw(struct iio_dev *indio_dev,
mutex_lock(&st->lock);
switch (mask) {
- case 0: /* magic value - channel value read */
+ case IIO_CHAN_INFO_RAW: /* magic value - channel value read */
switch (chan->type) {
case IIO_VOLTAGE:
if (chan->output) {
@@ -290,7 +305,7 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev,
struct iio_dummy_state *st = iio_priv(indio_dev);
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
if (chan->output == 0)
return -EINVAL;
@@ -377,7 +392,7 @@ static int __devinit iio_dummy_probe(int index)
* It also has a region (accessed by iio_priv()
* for chip specific state information.
*/
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -455,9 +470,7 @@ error_unconfigure_buffer:
error_unregister_events:
iio_simple_dummy_events_unregister(indio_dev);
error_free_device:
- /* Note free device should only be called, before registration
- * has succeeded. */
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -494,7 +507,7 @@ static int iio_dummy_remove(int index)
goto error_ret;
/* Free all structures */
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/staging/iio/iio_simple_dummy_buffer.c
index bb4daf744362..fdfc8739095a 100644
--- a/drivers/staging/iio/iio_simple_dummy_buffer.c
+++ b/drivers/staging/iio/iio_simple_dummy_buffer.c
@@ -18,9 +18,9 @@
#include <linux/irq.h>
#include <linux/bitmap.h>
-#include "iio.h"
-#include "trigger_consumer.h"
-#include "kfifo_buf.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/kfifo_buf.h>
#include "iio_simple_dummy.h"
@@ -37,7 +37,7 @@ static const s16 fakedata[] = {
* @irq: the interrupt number
* @p: private data - always a pointer to the poll func.
*
- * This is the guts of buffered capture. On a trigger event occuring,
+ * This is the guts of buffered capture. On a trigger event occurring,
* if the pollfunc is attached then this handler is called as a threaded
* interrupt (and hence may sleep). It is responsible for grabbing data
* from the device and pushing it into the associated buffer.
@@ -48,12 +48,9 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
struct iio_dev *indio_dev = pf->indio_dev;
struct iio_buffer *buffer = indio_dev->buffer;
int len = 0;
- /*
- * The datasize is obtained from the buffer. It was stored when
- * the preenable setup function was called.
- */
- size_t datasize = buffer->access->get_bytes_per_datum(buffer);
- u16 *data = kmalloc(datasize, GFP_KERNEL);
+ u16 *data;
+
+ data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
@@ -64,7 +61,7 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
* up a fast read. The capture will consist of all of them.
* Hence we just call the grab data function and fill the
* buffer without processing.
- * sofware scans: can be considered to be random access
+ * software scans: can be considered to be random access
* so efficient reading is just a case of minimal bus
* transactions.
* software culled hardware scans:
@@ -87,7 +84,7 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
}
}
/* Store a timestampe at an 8 byte boundary */
- if (buffer->scan_timestamp)
+ if (indio_dev->scan_timestamp)
*(s64 *)(((phys_addr_t)data + len
+ sizeof(s64) - 1) & ~(sizeof(s64) - 1))
= iio_get_time_ns();
diff --git a/drivers/staging/iio/iio_simple_dummy_events.c b/drivers/staging/iio/iio_simple_dummy_events.c
index 449c7a5ece80..317b77465db4 100644
--- a/drivers/staging/iio/iio_simple_dummy_events.c
+++ b/drivers/staging/iio/iio_simple_dummy_events.c
@@ -12,9 +12,9 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
-#include "iio.h"
-#include "sysfs.h"
-#include "events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
#include "iio_simple_dummy.h"
/* Evgen 'fakes' interrupt events for this example */
@@ -122,7 +122,7 @@ int iio_simple_dummy_write_event_value(struct iio_dev *indio_dev,
* @private: pointer to device instance state.
*
* This handler is responsible for querying the device to find out what
- * event occured and for then pushing that event towards userspace.
+ * event occurred and for then pushing that event towards userspace.
* Here only one event occurs so we push that directly on with locally
* grabbed timestamp.
*/
diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c
index cd82b56d58af..a8e51bc04439 100644
--- a/drivers/staging/iio/impedance-analyzer/ad5933.c
+++ b/drivers/staging/iio/impedance-analyzer/ad5933.c
@@ -19,9 +19,9 @@
#include <linux/module.h>
#include <asm/div64.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "../ring_sw.h"
#include "ad5933.h"
@@ -109,15 +109,46 @@ static struct ad5933_platform_data ad5933_default_pdata = {
};
static struct iio_chan_spec ad5933_channels[] = {
- IIO_CHAN(IIO_TEMP, 0, 1, 1, NULL, 0, 0, 0,
- 0, AD5933_REG_TEMP_DATA, IIO_ST('s', 14, 16, 0), 0),
- /* Ring Channels */
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "real_raw", 0, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- AD5933_REG_REAL_DATA, 0, IIO_ST('s', 16, 16, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "imag_raw", 0, 0,
- IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
- AD5933_REG_IMAG_DATA, 1, IIO_ST('s', 16, 16, 0), 0),
+ {
+ .type = IIO_TEMP,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
+ .address = AD5933_REG_TEMP_DATA,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ },
+ }, { /* Ring Channels */
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .extend_name = "real_raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .address = AD5933_REG_REAL_DATA,
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 16,
+ .storagebits = 16,
+ },
+ }, {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .extend_name = "imag_raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .address = AD5933_REG_IMAG_DATA,
+ .scan_index = 1,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 16,
+ .storagebits = 16,
+ },
+ },
};
static int ad5933_i2c_write(struct i2c_client *client,
@@ -260,7 +291,7 @@ static ssize_t ad5933_show_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5933_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret;
@@ -289,7 +320,7 @@ static ssize_t ad5933_store_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5933_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
long val;
@@ -323,7 +354,7 @@ static ssize_t ad5933_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5933_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int ret = 0, len = 0;
@@ -366,7 +397,7 @@ static ssize_t ad5933_store(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad5933_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
long val;
@@ -495,7 +526,8 @@ static int ad5933_read_raw(struct iio_dev *indio_dev,
mutex_lock(&indio_dev->mlock);
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
+ case IIO_CHAN_INFO_PROCESSED:
if (iio_buffer_enabled(indio_dev)) {
ret = -EBUSY;
goto out;
@@ -537,19 +569,14 @@ static const struct iio_info ad5933_info = {
static int ad5933_ring_preenable(struct iio_dev *indio_dev)
{
struct ad5933_state *st = iio_priv(indio_dev);
- size_t d_size;
int ret;
if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
return -EINVAL;
- d_size = bitmap_weight(indio_dev->active_scan_mask,
- indio_dev->masklength) *
- ad5933_channels[1].scan_type.storagebits / 8;
-
- if (indio_dev->buffer->access->set_bytes_per_datum)
- indio_dev->buffer->access->
- set_bytes_per_datum(indio_dev->buffer, d_size);
+ ret = iio_sw_buffer_preenable(indio_dev);
+ if (ret < 0)
+ return ret;
ret = ad5933_reset(st);
if (ret < 0)
@@ -678,7 +705,7 @@ static int __devinit ad5933_probe(struct i2c_client *client,
int ret, voltage_uv = 0;
struct ad5933_platform_data *pdata = client->dev.platform_data;
struct ad5933_state *st;
- struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+ struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
@@ -757,7 +784,7 @@ error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -774,7 +801,7 @@ static __devexit int ad5933_remove(struct i2c_client *client)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c
index e73ad7818d85..1f6bd854e950 100644
--- a/drivers/staging/iio/imu/adis16400_core.c
+++ b/drivers/staging/iio/imu/adis16400_core.c
@@ -26,9 +26,9 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "adis16400.h"
enum adis16400_chip_variant {
@@ -179,7 +179,7 @@ static ssize_t adis16400_read_frequency(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
int ret, len = 0;
ret = adis16400_get_freq(indio_dev);
if (ret < 0)
@@ -225,7 +225,7 @@ static ssize_t adis16400_write_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct adis16400_state *st = iio_priv(indio_dev);
long val;
int ret;
@@ -279,7 +279,7 @@ static ssize_t adis16400_write_reset(struct device *dev,
if (ret < 0)
return ret;
if (val) {
- ret = adis16400_reset(dev_get_drvdata(dev));
+ ret = adis16400_reset(dev_to_iio_dev(dev));
if (ret < 0)
return ret;
}
@@ -545,7 +545,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
s16 val16;
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
mutex_lock(&indio_dev->mlock);
ret = adis16400_spi_read_reg_16(indio_dev,
adis16400_addresses[chan->address][0],
@@ -635,7 +635,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.indexed = 1,
.channel = 0,
.extend_name = "supply",
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = in_supply,
.scan_index = ADIS16400_SCAN_SUPPLY,
.scan_type = IIO_ST('u', 14, 16, 0)
@@ -643,7 +644,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = gyro_x,
@@ -653,7 +655,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = gyro_y,
@@ -663,7 +666,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = gyro_z,
@@ -673,7 +677,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_x,
@@ -683,7 +688,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_y,
@@ -693,7 +699,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_z,
@@ -703,7 +710,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.type = IIO_MAGN,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = magn_x,
.scan_index = ADIS16400_SCAN_MAGN_X,
@@ -712,7 +720,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.type = IIO_MAGN,
.modified = 1,
.channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = magn_y,
.scan_index = ADIS16400_SCAN_MAGN_Y,
@@ -721,7 +730,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.type = IIO_MAGN,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = magn_z,
.scan_index = ADIS16400_SCAN_MAGN_Z,
@@ -730,7 +740,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = temp,
.scan_index = ADIS16400_SCAN_TEMP,
@@ -739,7 +750,8 @@ static struct iio_chan_spec adis16400_channels[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = in1,
.scan_index = ADIS16400_SCAN_ADC_0,
.scan_type = IIO_ST('s', 12, 16, 0),
@@ -753,7 +765,8 @@ static struct iio_chan_spec adis16350_channels[] = {
.indexed = 1,
.channel = 0,
.extend_name = "supply",
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = in_supply,
.scan_index = ADIS16400_SCAN_SUPPLY,
.scan_type = IIO_ST('u', 12, 16, 0)
@@ -761,7 +774,8 @@ static struct iio_chan_spec adis16350_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = gyro_x,
@@ -771,7 +785,8 @@ static struct iio_chan_spec adis16350_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = gyro_y,
@@ -781,17 +796,19 @@ static struct iio_chan_spec adis16350_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = gyro_z,
.scan_index = ADIS16400_SCAN_GYRO_Z,
.scan_type = IIO_ST('s', 14, 16, 0),
}, {
- .type = IIO_ACCEL,
+ .type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_x,
@@ -801,7 +818,8 @@ static struct iio_chan_spec adis16350_channels[] = {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_y,
@@ -811,7 +829,8 @@ static struct iio_chan_spec adis16350_channels[] = {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_z,
@@ -822,7 +841,8 @@ static struct iio_chan_spec adis16350_channels[] = {
.indexed = 1,
.channel = 0,
.extend_name = "x",
- .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = temp0,
@@ -833,7 +853,8 @@ static struct iio_chan_spec adis16350_channels[] = {
.indexed = 1,
.channel = 1,
.extend_name = "y",
- .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = temp1,
@@ -844,7 +865,8 @@ static struct iio_chan_spec adis16350_channels[] = {
.indexed = 1,
.channel = 2,
.extend_name = "z",
- .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = temp2,
.scan_index = ADIS16350_SCAN_TEMP_Z,
@@ -853,7 +875,8 @@ static struct iio_chan_spec adis16350_channels[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = in1,
.scan_index = ADIS16350_SCAN_ADC_0,
.scan_type = IIO_ST('s', 12, 16, 0),
@@ -867,7 +890,8 @@ static struct iio_chan_spec adis16300_channels[] = {
.indexed = 1,
.channel = 0,
.extend_name = "supply",
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = in_supply,
.scan_index = ADIS16400_SCAN_SUPPLY,
.scan_type = IIO_ST('u', 12, 16, 0)
@@ -875,7 +899,8 @@ static struct iio_chan_spec adis16300_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = gyro_x,
@@ -885,7 +910,8 @@ static struct iio_chan_spec adis16300_channels[] = {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_x,
@@ -895,7 +921,8 @@ static struct iio_chan_spec adis16300_channels[] = {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_y,
@@ -905,7 +932,8 @@ static struct iio_chan_spec adis16300_channels[] = {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_z,
@@ -915,7 +943,8 @@ static struct iio_chan_spec adis16300_channels[] = {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_OFFSET_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = temp,
.scan_index = ADIS16400_SCAN_TEMP,
@@ -924,7 +953,8 @@ static struct iio_chan_spec adis16300_channels[] = {
.type = IIO_VOLTAGE,
.indexed = 1,
.channel = 1,
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
.address = in1,
.scan_index = ADIS16350_SCAN_ADC_0,
.scan_type = IIO_ST('s', 12, 16, 0),
@@ -932,7 +962,8 @@ static struct iio_chan_spec adis16300_channels[] = {
.type = IIO_INCLI,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.address = incli_x,
.scan_index = ADIS16300_SCAN_INCLI_X,
.scan_type = IIO_ST('s', 13, 16, 0),
@@ -940,7 +971,8 @@ static struct iio_chan_spec adis16300_channels[] = {
.type = IIO_INCLI,
.modified = 1,
.channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
.address = incli_y,
.scan_index = ADIS16300_SCAN_INCLI_Y,
.scan_type = IIO_ST('s', 13, 16, 0),
@@ -953,7 +985,8 @@ static const struct iio_chan_spec adis16334_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = gyro_x,
@@ -963,7 +996,8 @@ static const struct iio_chan_spec adis16334_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = gyro_y,
@@ -973,7 +1007,8 @@ static const struct iio_chan_spec adis16334_channels[] = {
.type = IIO_ANGL_VEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = gyro_z,
@@ -983,7 +1018,8 @@ static const struct iio_chan_spec adis16334_channels[] = {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_X,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_x,
@@ -993,7 +1029,8 @@ static const struct iio_chan_spec adis16334_channels[] = {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Y,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_y,
@@ -1003,7 +1040,8 @@ static const struct iio_chan_spec adis16334_channels[] = {
.type = IIO_ACCEL,
.modified = 1,
.channel2 = IIO_MOD_Z,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT |
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SHARED_BIT,
.address = accel_z,
@@ -1013,7 +1051,8 @@ static const struct iio_chan_spec adis16334_channels[] = {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask = IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT |
IIO_CHAN_INFO_SCALE_SHARED_BIT,
.address = accel_z,
.scan_index = ADIS16400_SCAN_ACC_Z,
@@ -1122,7 +1161,7 @@ static int __devinit adis16400_probe(struct spi_device *spi)
{
int ret;
struct adis16400_state *st;
- struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+ struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -1172,14 +1211,14 @@ static int __devinit adis16400_probe(struct spi_device *spi)
return 0;
error_remove_trigger:
- if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
+ if (spi->irq)
adis16400_remove_trigger(indio_dev);
error_uninitialize_ring:
iio_buffer_unregister(indio_dev);
error_unreg_ring_funcs:
adis16400_unconfigure_ring(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -1198,7 +1237,7 @@ static int adis16400_remove(struct spi_device *spi)
adis16400_remove_trigger(indio_dev);
iio_buffer_unregister(indio_dev);
adis16400_unconfigure_ring(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c
index 8daa038b23e6..809e2c4270d1 100644
--- a/drivers/staging/iio/imu/adis16400_ring.c
+++ b/drivers/staging/iio/imu/adis16400_ring.c
@@ -6,20 +6,19 @@
#include <linux/bitops.h>
#include <linux/export.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
#include "adis16400.h"
/**
* adis16400_spi_read_burst() - read all data registers
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @indio_dev: the IIO device
* @rx: somewhere to pass back the value read (min size is 24 bytes)
**/
-static int adis16400_spi_read_burst(struct device *dev, u8 *rx)
+static int adis16400_spi_read_burst(struct iio_dev *indio_dev, u8 *rx)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct adis16400_state *st = iio_priv(indio_dev);
u32 old_speed_hz = st->us->max_speed_hz;
int ret;
@@ -71,9 +70,8 @@ static const u16 read_all_tx_array[] = {
cpu_to_be16(ADIS16400_READ_REG(ADIS16400_AUX_ADC)),
};
-static int adis16350_spi_read_all(struct device *dev, u8 *rx)
+static int adis16350_spi_read_all(struct iio_dev *indio_dev, u8 *rx)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct adis16400_state *st = iio_priv(indio_dev);
struct spi_message msg;
@@ -119,12 +117,12 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p)
struct iio_buffer *ring = indio_dev->buffer;
int i = 0, j, ret = 0;
s16 *data;
- size_t datasize = ring->access->get_bytes_per_datum(ring);
+
/* Asumption that long is enough for maximum channels */
unsigned long mask = *indio_dev->active_scan_mask;
int scan_count = bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength);
- data = kmalloc(datasize , GFP_KERNEL);
+ data = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
if (data == NULL) {
dev_err(&st->us->dev, "memory alloc failed in ring bh");
return -ENOMEM;
@@ -132,13 +130,13 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p)
if (scan_count) {
if (st->variant->flags & ADIS16400_NO_BURST) {
- ret = adis16350_spi_read_all(&indio_dev->dev, st->rx);
+ ret = adis16350_spi_read_all(indio_dev, st->rx);
if (ret < 0)
goto err;
for (; i < scan_count; i++)
data[i] = *(s16 *)(st->rx + i*2);
} else {
- ret = adis16400_spi_read_burst(&indio_dev->dev, st->rx);
+ ret = adis16400_spi_read_burst(indio_dev, st->rx);
if (ret < 0)
goto err;
for (; i < scan_count; i++) {
diff --git a/drivers/staging/iio/imu/adis16400_trigger.c b/drivers/staging/iio/imu/adis16400_trigger.c
index 5bf000757522..42a678e92fc6 100644
--- a/drivers/staging/iio/imu/adis16400_trigger.c
+++ b/drivers/staging/iio/imu/adis16400_trigger.c
@@ -3,8 +3,8 @@
#include <linux/spi/spi.h>
#include <linux/export.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
#include "adis16400.h"
/**
@@ -29,7 +29,7 @@ int adis16400_probe_trigger(struct iio_dev *indio_dev)
int ret;
struct adis16400_state *st = iio_priv(indio_dev);
- st->trig = iio_allocate_trigger("%s-dev%d",
+ st->trig = iio_trigger_alloc("%s-dev%d",
indio_dev->name,
indio_dev->id);
if (st->trig == NULL) {
@@ -59,7 +59,7 @@ int adis16400_probe_trigger(struct iio_dev *indio_dev)
error_free_irq:
free_irq(st->us->irq, st->trig);
error_free_trig:
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
error_ret:
return ret;
}
@@ -70,5 +70,5 @@ void adis16400_remove_trigger(struct iio_dev *indio_dev)
iio_trigger_unregister(st->trig);
free_irq(st->us->irq, st->trig);
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
}
diff --git a/drivers/staging/iio/light/Kconfig b/drivers/staging/iio/light/Kconfig
index e7e9159d9895..4bed30eac3ed 100644
--- a/drivers/staging/iio/light/Kconfig
+++ b/drivers/staging/iio/light/Kconfig
@@ -4,15 +4,26 @@
menu "Light sensors"
config SENSORS_ISL29018
- tristate "ISL 29018 light and proximity sensor"
- depends on I2C
- default n
- help
- If you say yes here you get support for ambient light sensing and
- proximity infrared sensing from Intersil ISL29018.
- This driver will provide the measurements of ambient light intensity
- in lux, proximity infrared sensing and normal infrared sensing.
- Data from sensor is accessible via sysfs.
+ tristate "ISL 29018 light and proximity sensor"
+ depends on I2C
+ select REGMAP_I2C
+ default n
+ help
+ If you say yes here you get support for ambient light sensing and
+ proximity infrared sensing from Intersil ISL29018.
+ This driver will provide the measurements of ambient light intensity
+ in lux, proximity infrared sensing and normal infrared sensing.
+ Data from sensor is accessible via sysfs.
+
+config SENSORS_ISL29028
+ tristate "Intersil ISL29028 Concurrent Light and Proximity Sensor"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Provides driver for the Intersil's ISL29028 device.
+ This driver supports the sysfs interface to get the ALS, IR intensity,
+ Proximity value via iio. The ISL29028 provides the concurrent sensing
+ of ambient light and proximity.
config SENSORS_TSL2563
tristate "TAOS TSL2560, TSL2561, TSL2562 and TSL2563 ambient light sensors"
@@ -31,4 +42,12 @@ config TSL2583
Provides support for the TAOS tsl2580, tsl2581 and tsl2583 devices.
Access ALS data via iio, sysfs.
+config TSL2x7x
+ tristate "TAOS TSL/TMD2x71 and TSL/TMD2x72 Family of light and proximity sensors"
+ depends on I2C
+ help
+ Support for: tsl2571, tsl2671, tmd2671, tsl2771, tmd2771, tsl2572, tsl2672,
+ tmd2672, tsl2772, tmd2772 devices.
+ Provides iio_events and direct access via sysfs.
+
endmenu
diff --git a/drivers/staging/iio/light/Makefile b/drivers/staging/iio/light/Makefile
index 3011fbfa8dc2..141af1eb164c 100644
--- a/drivers/staging/iio/light/Makefile
+++ b/drivers/staging/iio/light/Makefile
@@ -4,4 +4,6 @@
obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o
+obj-$(CONFIG_SENSORS_ISL29028) += isl29028.o
obj-$(CONFIG_TSL2583) += tsl2583.o
+obj-$(CONFIG_TSL2x7x) += tsl2x7x_core.o
diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c
index 38ec52b65dfa..0abbf18d6103 100644
--- a/drivers/staging/iio/light/isl29018.c
+++ b/drivers/staging/iio/light/isl29018.c
@@ -26,9 +26,11 @@
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/delay.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
#define CONVERSION_TIME_MS 100
#define ISL29018_REG_ADD_COMMAND1 0x00
@@ -51,49 +53,22 @@
#define ISL29018_REG_ADD_DATA_LSB 0x02
#define ISL29018_REG_ADD_DATA_MSB 0x03
-#define ISL29018_MAX_REGS (ISL29018_REG_ADD_DATA_MSB+1)
#define ISL29018_REG_TEST 0x08
#define ISL29018_TEST_SHIFT 0
#define ISL29018_TEST_MASK (0xFF << ISL29018_TEST_SHIFT)
struct isl29018_chip {
- struct i2c_client *client;
+ struct device *dev;
+ struct regmap *regmap;
struct mutex lock;
unsigned int lux_scale;
unsigned int range;
unsigned int adc_bit;
int prox_scheme;
- u8 reg_cache[ISL29018_MAX_REGS];
};
-static int isl29018_write_data(struct i2c_client *client, u8 reg,
- u8 val, u8 mask, u8 shift)
-{
- u8 regval = val;
- int ret;
- struct isl29018_chip *chip = iio_priv(i2c_get_clientdata(client));
-
- /* don't cache or mask REG_TEST */
- if (reg < ISL29018_MAX_REGS) {
- regval = chip->reg_cache[reg];
- regval &= ~mask;
- regval |= val << shift;
- }
-
- ret = i2c_smbus_write_byte_data(client, reg, regval);
- if (ret) {
- dev_err(&client->dev, "Write to device fails status %x\n", ret);
- } else {
- /* don't update cache on err */
- if (reg < ISL29018_MAX_REGS)
- chip->reg_cache[reg] = regval;
- }
-
- return ret;
-}
-
-static int isl29018_set_range(struct i2c_client *client, unsigned long range,
+static int isl29018_set_range(struct isl29018_chip *chip, unsigned long range,
unsigned int *new_range)
{
static const unsigned long supp_ranges[] = {1000, 4000, 16000, 64000};
@@ -109,11 +84,11 @@ static int isl29018_set_range(struct i2c_client *client, unsigned long range,
if (i >= ARRAY_SIZE(supp_ranges))
return -EINVAL;
- return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII,
- i, COMMANDII_RANGE_MASK, COMMANDII_RANGE_SHIFT);
+ return regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMANDII,
+ COMMANDII_RANGE_MASK, i << COMMANDII_RANGE_SHIFT);
}
-static int isl29018_set_resolution(struct i2c_client *client,
+static int isl29018_set_resolution(struct isl29018_chip *chip,
unsigned long adcbit, unsigned int *conf_adc_bit)
{
static const unsigned long supp_adcbit[] = {16, 12, 8, 4};
@@ -129,48 +104,49 @@ static int isl29018_set_resolution(struct i2c_client *client,
if (i >= ARRAY_SIZE(supp_adcbit))
return -EINVAL;
- return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII,
- i, COMMANDII_RESOLUTION_MASK,
- COMMANDII_RESOLUTION_SHIFT);
+ return regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMANDII,
+ COMMANDII_RESOLUTION_MASK,
+ i << COMMANDII_RESOLUTION_SHIFT);
}
-static int isl29018_read_sensor_input(struct i2c_client *client, int mode)
+static int isl29018_read_sensor_input(struct isl29018_chip *chip, int mode)
{
int status;
- int lsb;
- int msb;
+ unsigned int lsb;
+ unsigned int msb;
/* Set mode */
- status = isl29018_write_data(client, ISL29018_REG_ADD_COMMAND1,
- mode, COMMMAND1_OPMODE_MASK, COMMMAND1_OPMODE_SHIFT);
+ status = regmap_write(chip->regmap, ISL29018_REG_ADD_COMMAND1,
+ mode << COMMMAND1_OPMODE_SHIFT);
if (status) {
- dev_err(&client->dev, "Error in setting operating mode\n");
+ dev_err(chip->dev,
+ "Error in setting operating mode err %d\n", status);
return status;
}
msleep(CONVERSION_TIME_MS);
- lsb = i2c_smbus_read_byte_data(client, ISL29018_REG_ADD_DATA_LSB);
- if (lsb < 0) {
- dev_err(&client->dev, "Error in reading LSB DATA\n");
- return lsb;
+ status = regmap_read(chip->regmap, ISL29018_REG_ADD_DATA_LSB, &lsb);
+ if (status < 0) {
+ dev_err(chip->dev,
+ "Error in reading LSB DATA with err %d\n", status);
+ return status;
}
- msb = i2c_smbus_read_byte_data(client, ISL29018_REG_ADD_DATA_MSB);
- if (msb < 0) {
- dev_err(&client->dev, "Error in reading MSB DATA\n");
- return msb;
+ status = regmap_read(chip->regmap, ISL29018_REG_ADD_DATA_MSB, &msb);
+ if (status < 0) {
+ dev_err(chip->dev,
+ "Error in reading MSB DATA with error %d\n", status);
+ return status;
}
- dev_vdbg(&client->dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb);
+ dev_vdbg(chip->dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb);
return (msb << 8) | lsb;
}
-static int isl29018_read_lux(struct i2c_client *client, int *lux)
+static int isl29018_read_lux(struct isl29018_chip *chip, int *lux)
{
int lux_data;
- struct isl29018_chip *chip = iio_priv(i2c_get_clientdata(client));
- lux_data = isl29018_read_sensor_input(client,
- COMMMAND1_OPMODE_ALS_ONCE);
+ lux_data = isl29018_read_sensor_input(chip, COMMMAND1_OPMODE_ALS_ONCE);
if (lux_data < 0)
return lux_data;
@@ -180,11 +156,11 @@ static int isl29018_read_lux(struct i2c_client *client, int *lux)
return 0;
}
-static int isl29018_read_ir(struct i2c_client *client, int *ir)
+static int isl29018_read_ir(struct isl29018_chip *chip, int *ir)
{
int ir_data;
- ir_data = isl29018_read_sensor_input(client, COMMMAND1_OPMODE_IR_ONCE);
+ ir_data = isl29018_read_sensor_input(chip, COMMMAND1_OPMODE_IR_ONCE);
if (ir_data < 0)
return ir_data;
@@ -194,7 +170,7 @@ static int isl29018_read_ir(struct i2c_client *client, int *ir)
return 0;
}
-static int isl29018_read_proximity_ir(struct i2c_client *client, int scheme,
+static int isl29018_read_proximity_ir(struct isl29018_chip *chip, int scheme,
int *near_ir)
{
int status;
@@ -202,14 +178,15 @@ static int isl29018_read_proximity_ir(struct i2c_client *client, int scheme,
int ir_data = -1;
/* Do proximity sensing with required scheme */
- status = isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII,
- scheme, COMMANDII_SCHEME_MASK, COMMANDII_SCHEME_SHIFT);
+ status = regmap_update_bits(chip->regmap, ISL29018_REG_ADD_COMMANDII,
+ COMMANDII_SCHEME_MASK,
+ scheme << COMMANDII_SCHEME_SHIFT);
if (status) {
- dev_err(&client->dev, "Error in setting operating mode\n");
+ dev_err(chip->dev, "Error in setting operating mode\n");
return status;
}
- prox_data = isl29018_read_sensor_input(client,
+ prox_data = isl29018_read_sensor_input(chip,
COMMMAND1_OPMODE_PROX_ONCE);
if (prox_data < 0)
return prox_data;
@@ -219,8 +196,7 @@ static int isl29018_read_proximity_ir(struct i2c_client *client, int scheme,
return 0;
}
- ir_data = isl29018_read_sensor_input(client,
- COMMMAND1_OPMODE_IR_ONCE);
+ ir_data = isl29018_read_sensor_input(chip, COMMMAND1_OPMODE_IR_ONCE);
if (ir_data < 0)
return ir_data;
@@ -238,7 +214,7 @@ static int isl29018_read_proximity_ir(struct i2c_client *client, int scheme,
static ssize_t show_range(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct isl29018_chip *chip = iio_priv(indio_dev);
return sprintf(buf, "%u\n", chip->range);
@@ -247,9 +223,8 @@ static ssize_t show_range(struct device *dev,
static ssize_t store_range(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct isl29018_chip *chip = iio_priv(indio_dev);
- struct i2c_client *client = chip->client;
int status;
unsigned long lval;
unsigned int new_range;
@@ -264,10 +239,11 @@ static ssize_t store_range(struct device *dev,
}
mutex_lock(&chip->lock);
- status = isl29018_set_range(client, lval, &new_range);
+ status = isl29018_set_range(chip, lval, &new_range);
if (status < 0) {
mutex_unlock(&chip->lock);
- dev_err(dev, "Error in setting max range\n");
+ dev_err(dev,
+ "Error in setting max range with err %d\n", status);
return status;
}
chip->range = new_range;
@@ -280,7 +256,7 @@ static ssize_t store_range(struct device *dev,
static ssize_t show_resolution(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct isl29018_chip *chip = iio_priv(indio_dev);
return sprintf(buf, "%u\n", chip->adc_bit);
@@ -289,9 +265,8 @@ static ssize_t show_resolution(struct device *dev,
static ssize_t store_resolution(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct isl29018_chip *chip = iio_priv(indio_dev);
- struct i2c_client *client = chip->client;
int status;
unsigned long lval;
unsigned int new_adc_bit;
@@ -304,7 +279,7 @@ static ssize_t store_resolution(struct device *dev,
}
mutex_lock(&chip->lock);
- status = isl29018_set_resolution(client, lval, &new_adc_bit);
+ status = isl29018_set_resolution(chip, lval, &new_adc_bit);
if (status < 0) {
mutex_unlock(&chip->lock);
dev_err(dev, "Error in setting resolution\n");
@@ -320,7 +295,7 @@ static ssize_t store_resolution(struct device *dev,
static ssize_t show_prox_infrared_supression(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct isl29018_chip *chip = iio_priv(indio_dev);
/* return the "proximity scheme" i.e. if the chip does on chip
@@ -331,7 +306,7 @@ static ssize_t show_prox_infrared_supression(struct device *dev,
static ssize_t store_prox_infrared_supression(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct isl29018_chip *chip = iio_priv(indio_dev);
unsigned long lval;
@@ -379,20 +354,20 @@ static int isl29018_read_raw(struct iio_dev *indio_dev,
{
int ret = -EINVAL;
struct isl29018_chip *chip = iio_priv(indio_dev);
- struct i2c_client *client = chip->client;
mutex_lock(&chip->lock);
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
+ case IIO_CHAN_INFO_PROCESSED:
switch (chan->type) {
case IIO_LIGHT:
- ret = isl29018_read_lux(client, val);
+ ret = isl29018_read_lux(chip, val);
break;
case IIO_INTENSITY:
- ret = isl29018_read_ir(client, val);
+ ret = isl29018_read_ir(chip, val);
break;
case IIO_PROXIMITY:
- ret = isl29018_read_proximity_ir(client,
+ ret = isl29018_read_proximity_ir(chip,
chip->prox_scheme, val);
break;
default:
@@ -419,15 +394,17 @@ static const struct iio_chan_spec isl29018_channels[] = {
.type = IIO_LIGHT,
.indexed = 1,
.channel = 0,
- .processed_val = IIO_PROCESSED,
- .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
}, {
.type = IIO_INTENSITY,
.modified = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
.channel2 = IIO_MOD_LIGHT_IR,
}, {
/* Unindexed in current ABI. But perhaps it should be. */
.type = IIO_PROXIMITY,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
}
};
@@ -456,15 +433,12 @@ static const struct attribute_group isl29108_group = {
.attrs = isl29018_attributes,
};
-static int isl29018_chip_init(struct i2c_client *client)
+static int isl29018_chip_init(struct isl29018_chip *chip)
{
- struct isl29018_chip *chip = iio_priv(i2c_get_clientdata(client));
int status;
int new_adc_bit;
unsigned int new_range;
- memset(chip->reg_cache, 0, sizeof(chip->reg_cache));
-
/* Code added per Intersil Application Note 1534:
* When VDD sinks to approximately 1.8V or below, some of
* the part's registers may change their state. When VDD
@@ -485,10 +459,9 @@ static int isl29018_chip_init(struct i2c_client *client)
* the same thing EXCEPT the data sheet asks for a 1ms delay after
* writing the CMD1 register.
*/
- status = isl29018_write_data(client, ISL29018_REG_TEST, 0,
- ISL29018_TEST_MASK, ISL29018_TEST_SHIFT);
+ status = regmap_write(chip->regmap, ISL29018_REG_TEST, 0x0);
if (status < 0) {
- dev_err(&client->dev, "Failed to clear isl29018 TEST reg."
+ dev_err(chip->dev, "Failed to clear isl29018 TEST reg."
"(%d)\n", status);
return status;
}
@@ -497,10 +470,9 @@ static int isl29018_chip_init(struct i2c_client *client)
* "Operating Mode" (COMMAND1) register is reprogrammed when
* data is read from the device.
*/
- status = isl29018_write_data(client, ISL29018_REG_ADD_COMMAND1, 0,
- 0xff, 0);
+ status = regmap_write(chip->regmap, ISL29018_REG_ADD_COMMAND1, 0);
if (status < 0) {
- dev_err(&client->dev, "Failed to clear isl29018 CMD1 reg."
+ dev_err(chip->dev, "Failed to clear isl29018 CMD1 reg."
"(%d)\n", status);
return status;
}
@@ -508,13 +480,13 @@ static int isl29018_chip_init(struct i2c_client *client)
msleep(1); /* per data sheet, page 10 */
/* set defaults */
- status = isl29018_set_range(client, chip->range, &new_range);
+ status = isl29018_set_range(chip, chip->range, &new_range);
if (status < 0) {
- dev_err(&client->dev, "Init of isl29018 fails\n");
+ dev_err(chip->dev, "Init of isl29018 fails\n");
return status;
}
- status = isl29018_set_resolution(client, chip->adc_bit,
+ status = isl29018_set_resolution(chip, chip->adc_bit,
&new_adc_bit);
return 0;
@@ -527,6 +499,32 @@ static const struct iio_info isl29108_info = {
.write_raw = &isl29018_write_raw,
};
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ISL29018_REG_ADD_DATA_LSB:
+ case ISL29018_REG_ADD_DATA_MSB:
+ case ISL29018_REG_ADD_COMMAND1:
+ case ISL29018_REG_TEST:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/*
+ * isl29018_regmap_config: regmap configuration.
+ * Use RBTREE mechanism for caching.
+ */
+static const struct regmap_config isl29018_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_reg = is_volatile_reg,
+ .max_register = ISL29018_REG_TEST,
+ .num_reg_defaults_raw = ISL29018_REG_TEST + 1,
+ .cache_type = REGCACHE_RBTREE,
+};
+
static int __devinit isl29018_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -534,7 +532,7 @@ static int __devinit isl29018_probe(struct i2c_client *client,
struct iio_dev *indio_dev;
int err;
- indio_dev = iio_allocate_device(sizeof(*chip));
+ indio_dev = iio_device_alloc(sizeof(*chip));
if (indio_dev == NULL) {
dev_err(&client->dev, "iio allocation fails\n");
err = -ENOMEM;
@@ -543,7 +541,7 @@ static int __devinit isl29018_probe(struct i2c_client *client,
chip = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
- chip->client = client;
+ chip->dev = &client->dev;
mutex_init(&chip->lock);
@@ -551,7 +549,14 @@ static int __devinit isl29018_probe(struct i2c_client *client,
chip->range = 1000;
chip->adc_bit = 16;
- err = isl29018_chip_init(client);
+ chip->regmap = devm_regmap_init_i2c(client, &isl29018_regmap_config);
+ if (IS_ERR(chip->regmap)) {
+ err = PTR_ERR(chip->regmap);
+ dev_err(chip->dev, "regmap initialization failed: %d\n", err);
+ goto exit;
+ }
+
+ err = isl29018_chip_init(chip);
if (err)
goto exit_iio_free;
@@ -569,7 +574,7 @@ static int __devinit isl29018_probe(struct i2c_client *client,
return 0;
exit_iio_free:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
exit:
return err;
}
@@ -580,7 +585,7 @@ static int __devexit isl29018_remove(struct i2c_client *client)
dev_dbg(&client->dev, "%s()\n", __func__);
iio_device_unregister(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
@@ -593,7 +598,7 @@ static const struct i2c_device_id isl29018_id[] = {
MODULE_DEVICE_TABLE(i2c, isl29018_id);
static const struct of_device_id isl29018_of_match[] = {
- { .compatible = "invn,isl29018", },
+ { .compatible = "isil,isl29018", },
{ },
};
MODULE_DEVICE_TABLE(of, isl29018_of_match);
diff --git a/drivers/staging/iio/light/isl29028.c b/drivers/staging/iio/light/isl29028.c
new file mode 100644
index 000000000000..33a4c3f94a14
--- /dev/null
+++ b/drivers/staging/iio/light/isl29028.c
@@ -0,0 +1,566 @@
+/*
+ * IIO driver for the light sensor ISL29028.
+ * ISL29028 is Concurrent Ambient Light and Proximity Sensor
+ *
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define CONVERSION_TIME_MS 100
+
+#define ISL29028_REG_CONFIGURE 0x01
+
+#define CONFIGURE_ALS_IR_MODE_ALS 0
+#define CONFIGURE_ALS_IR_MODE_IR BIT(0)
+#define CONFIGURE_ALS_IR_MODE_MASK BIT(0)
+
+#define CONFIGURE_ALS_RANGE_LOW_LUX 0
+#define CONFIGURE_ALS_RANGE_HIGH_LUX BIT(1)
+#define CONFIGURE_ALS_RANGE_MASK BIT(1)
+
+#define CONFIGURE_ALS_DIS 0
+#define CONFIGURE_ALS_EN BIT(2)
+#define CONFIGURE_ALS_EN_MASK BIT(2)
+
+#define CONFIGURE_PROX_DRIVE BIT(3)
+
+#define CONFIGURE_PROX_SLP_SH 4
+#define CONFIGURE_PROX_SLP_MASK (7 << CONFIGURE_PROX_SLP_SH)
+
+#define CONFIGURE_PROX_EN BIT(7)
+#define CONFIGURE_PROX_EN_MASK BIT(7)
+
+#define ISL29028_REG_INTERRUPT 0x02
+
+#define ISL29028_REG_PROX_DATA 0x08
+#define ISL29028_REG_ALSIR_L 0x09
+#define ISL29028_REG_ALSIR_U 0x0A
+
+#define ISL29028_REG_TEST1_MODE 0x0E
+#define ISL29028_REG_TEST2_MODE 0x0F
+
+#define ISL29028_NUM_REGS (ISL29028_REG_TEST2_MODE + 1)
+
+enum als_ir_mode {
+ MODE_NONE = 0,
+ MODE_ALS,
+ MODE_IR
+};
+
+struct isl29028_chip {
+ struct device *dev;
+ struct mutex lock;
+ struct regmap *regmap;
+
+ unsigned int prox_sampling;
+ bool enable_prox;
+
+ int lux_scale;
+ int als_ir_mode;
+};
+
+static int isl29028_set_proxim_sampling(struct isl29028_chip *chip,
+ unsigned int sampling)
+{
+ static unsigned int prox_period[] = {800, 400, 200, 100, 75, 50, 12, 0};
+ int sel;
+ unsigned int period = DIV_ROUND_UP(1000, sampling);
+
+ for (sel = 0; sel < ARRAY_SIZE(prox_period); ++sel) {
+ if (period >= prox_period[sel])
+ break;
+ }
+ return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+ CONFIGURE_PROX_SLP_MASK, sel << CONFIGURE_PROX_SLP_SH);
+}
+
+static int isl29028_enable_proximity(struct isl29028_chip *chip, bool enable)
+{
+ int ret;
+ int val = 0;
+
+ if (enable)
+ val = CONFIGURE_PROX_EN;
+ ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+ CONFIGURE_PROX_EN_MASK, val);
+ if (ret < 0)
+ return ret;
+
+ /* Wait for conversion to be complete for first sample */
+ mdelay(DIV_ROUND_UP(1000, chip->prox_sampling));
+ return 0;
+}
+
+static int isl29028_set_als_scale(struct isl29028_chip *chip, int lux_scale)
+{
+ int val = (lux_scale == 2000) ? CONFIGURE_ALS_RANGE_HIGH_LUX :
+ CONFIGURE_ALS_RANGE_LOW_LUX;
+
+ return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+ CONFIGURE_ALS_RANGE_MASK, val);
+}
+
+static int isl29028_set_als_ir_mode(struct isl29028_chip *chip,
+ enum als_ir_mode mode)
+{
+ int ret = 0;
+
+ switch (mode) {
+ case MODE_ALS:
+ ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+ CONFIGURE_ALS_IR_MODE_MASK, CONFIGURE_ALS_IR_MODE_ALS);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+ CONFIGURE_ALS_RANGE_MASK, CONFIGURE_ALS_RANGE_HIGH_LUX);
+ break;
+
+ case MODE_IR:
+ ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+ CONFIGURE_ALS_IR_MODE_MASK, CONFIGURE_ALS_IR_MODE_IR);
+ break;
+
+ case MODE_NONE:
+ return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+ CONFIGURE_ALS_EN_MASK, CONFIGURE_ALS_DIS);
+ }
+
+ if (ret < 0)
+ return ret;
+
+ /* Enable the ALS/IR */
+ ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+ CONFIGURE_ALS_EN_MASK, CONFIGURE_ALS_EN);
+ if (ret < 0)
+ return ret;
+
+ /* Need to wait for conversion time if ALS/IR mode enabled */
+ mdelay(CONVERSION_TIME_MS);
+ return 0;
+}
+
+static int isl29028_read_als_ir(struct isl29028_chip *chip, int *als_ir)
+{
+ unsigned int lsb;
+ unsigned int msb;
+ int ret;
+
+ ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_L, &lsb);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Error in reading register ALSIR_L err %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_U, &msb);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Error in reading register ALSIR_U err %d\n", ret);
+ return ret;
+ }
+
+ *als_ir = ((msb & 0xF) << 8) | (lsb & 0xFF);
+ return 0;
+}
+
+static int isl29028_read_proxim(struct isl29028_chip *chip, int *prox)
+{
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(chip->regmap, ISL29028_REG_PROX_DATA, &data);
+ if (ret < 0) {
+ dev_err(chip->dev, "Error in reading register %d, error %d\n",
+ ISL29028_REG_PROX_DATA, ret);
+ return ret;
+ }
+ *prox = data;
+ return 0;
+}
+
+static int isl29028_proxim_get(struct isl29028_chip *chip, int *prox_data)
+{
+ int ret;
+
+ if (!chip->enable_prox) {
+ ret = isl29028_enable_proximity(chip, true);
+ if (ret < 0)
+ return ret;
+ chip->enable_prox = true;
+ }
+ return isl29028_read_proxim(chip, prox_data);
+}
+
+static int isl29028_als_get(struct isl29028_chip *chip, int *als_data)
+{
+ int ret;
+ int als_ir_data;
+
+ if (chip->als_ir_mode != MODE_ALS) {
+ ret = isl29028_set_als_ir_mode(chip, MODE_ALS);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Error in enabling ALS mode err %d\n", ret);
+ return ret;
+ }
+ chip->als_ir_mode = MODE_ALS;
+ }
+
+ ret = isl29028_read_als_ir(chip, &als_ir_data);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * convert als data count to lux.
+ * if lux_scale = 125, lux = count * 0.031
+ * if lux_scale = 2000, lux = count * 0.49
+ */
+ if (chip->lux_scale == 125)
+ als_ir_data = (als_ir_data * 31) / 1000;
+ else
+ als_ir_data = (als_ir_data * 49) / 100;
+
+ *als_data = als_ir_data;
+ return 0;
+}
+
+static int isl29028_ir_get(struct isl29028_chip *chip, int *ir_data)
+{
+ int ret;
+
+ if (chip->als_ir_mode != MODE_IR) {
+ ret = isl29028_set_als_ir_mode(chip, MODE_IR);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Error in enabling IR mode err %d\n", ret);
+ return ret;
+ }
+ chip->als_ir_mode = MODE_IR;
+ }
+ return isl29028_read_als_ir(chip, ir_data);
+}
+
+/* Channel IO */
+static int isl29028_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val, int val2, long mask)
+{
+ struct isl29028_chip *chip = iio_priv(indio_dev);
+ int ret = -EINVAL;
+
+ mutex_lock(&chip->lock);
+ switch (chan->type) {
+ case IIO_PROXIMITY:
+ if (mask != IIO_CHAN_INFO_SAMP_FREQ) {
+ dev_err(chip->dev,
+ "proximity: mask value 0x%08lx not supported\n",
+ mask);
+ break;
+ }
+ if (val < 1 || val > 100) {
+ dev_err(chip->dev,
+ "Samp_freq %d is not in range[1:100]\n", val);
+ break;
+ }
+ ret = isl29028_set_proxim_sampling(chip, val);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Setting proximity samp_freq fail, err %d\n",
+ ret);
+ break;
+ }
+ chip->prox_sampling = val;
+ break;
+
+ case IIO_LIGHT:
+ if (mask != IIO_CHAN_INFO_SCALE) {
+ dev_err(chip->dev,
+ "light: mask value 0x%08lx not supported\n",
+ mask);
+ break;
+ }
+ if ((val != 125) && (val != 2000)) {
+ dev_err(chip->dev,
+ "lux scale %d is invalid [125, 2000]\n", val);
+ break;
+ }
+ ret = isl29028_set_als_scale(chip, val);
+ if (ret < 0) {
+ dev_err(chip->dev,
+ "Setting lux scale fail with error %d\n", ret);
+ break;
+ }
+ chip->lux_scale = val;
+ break;
+
+ default:
+ dev_err(chip->dev, "Unsupported channel type\n");
+ break;
+ }
+ mutex_unlock(&chip->lock);
+ return ret;
+}
+
+static int isl29028_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val, int *val2, long mask)
+{
+ struct isl29028_chip *chip = iio_priv(indio_dev);
+ int ret = -EINVAL;
+
+ mutex_lock(&chip->lock);
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ case IIO_CHAN_INFO_PROCESSED:
+ switch (chan->type) {
+ case IIO_LIGHT:
+ ret = isl29028_als_get(chip, val);
+ break;
+ case IIO_INTENSITY:
+ ret = isl29028_ir_get(chip, val);
+ break;
+ case IIO_PROXIMITY:
+ ret = isl29028_proxim_get(chip, val);
+ break;
+ default:
+ break;
+ }
+ if (ret < 0)
+ break;
+ ret = IIO_VAL_INT;
+ break;
+
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ if (chan->type != IIO_PROXIMITY)
+ break;
+ *val = chip->prox_sampling;
+ ret = IIO_VAL_INT;
+ break;
+
+ case IIO_CHAN_INFO_SCALE:
+ if (chan->type != IIO_LIGHT)
+ break;
+ *val = chip->lux_scale;
+ ret = IIO_VAL_INT;
+ break;
+
+ default:
+ dev_err(chip->dev, "mask value 0x%08lx not supported\n", mask);
+ break;
+ }
+ mutex_unlock(&chip->lock);
+ return ret;
+}
+
+static IIO_CONST_ATTR(in_proximity_sampling_frequency_available,
+ "1, 3, 5, 10, 13, 20, 83, 100");
+static IIO_CONST_ATTR(in_illuminance_scale_available, "125, 2000");
+
+#define ISL29028_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr)
+#define ISL29028_CONST_ATTR(name) (&iio_const_attr_##name.dev_attr.attr)
+static struct attribute *isl29028_attributes[] = {
+ ISL29028_CONST_ATTR(in_proximity_sampling_frequency_available),
+ ISL29028_CONST_ATTR(in_illuminance_scale_available),
+ NULL,
+};
+
+static const struct attribute_group isl29108_group = {
+ .attrs = isl29028_attributes,
+};
+
+static const struct iio_chan_spec isl29028_channels[] = {
+ {
+ .type = IIO_LIGHT,
+ .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+ }, {
+ .type = IIO_INTENSITY,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ }, {
+ .type = IIO_PROXIMITY,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SAMP_FREQ_SEPARATE_BIT,
+ }
+};
+
+static const struct iio_info isl29028_info = {
+ .attrs = &isl29108_group,
+ .driver_module = THIS_MODULE,
+ .read_raw = &isl29028_read_raw,
+ .write_raw = &isl29028_write_raw,
+};
+
+static int isl29028_chip_init(struct isl29028_chip *chip)
+{
+ int ret;
+
+ chip->enable_prox = false;
+ chip->prox_sampling = 20;
+ chip->lux_scale = 2000;
+ chip->als_ir_mode = MODE_NONE;
+
+ ret = regmap_write(chip->regmap, ISL29028_REG_TEST1_MODE, 0x0);
+ if (ret < 0) {
+ dev_err(chip->dev, "%s(): write to reg %d failed, err = %d\n",
+ __func__, ISL29028_REG_TEST1_MODE, ret);
+ return ret;
+ }
+ ret = regmap_write(chip->regmap, ISL29028_REG_TEST2_MODE, 0x0);
+ if (ret < 0) {
+ dev_err(chip->dev, "%s(): write to reg %d failed, err = %d\n",
+ __func__, ISL29028_REG_TEST2_MODE, ret);
+ return ret;
+ }
+
+ ret = regmap_write(chip->regmap, ISL29028_REG_CONFIGURE, 0x0);
+ if (ret < 0) {
+ dev_err(chip->dev, "%s(): write to reg %d failed, err = %d\n",
+ __func__, ISL29028_REG_CONFIGURE, ret);
+ return ret;
+ }
+
+ ret = isl29028_set_proxim_sampling(chip, chip->prox_sampling);
+ if (ret < 0) {
+ dev_err(chip->dev, "%s(): setting the proximity, err = %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = isl29028_set_als_scale(chip, chip->lux_scale);
+ if (ret < 0)
+ dev_err(chip->dev, "%s(): setting als scale failed, err = %d\n",
+ __func__, ret);
+ return ret;
+}
+
+static bool is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case ISL29028_REG_INTERRUPT:
+ case ISL29028_REG_PROX_DATA:
+ case ISL29028_REG_ALSIR_L:
+ case ISL29028_REG_ALSIR_U:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_config isl29028_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_reg = is_volatile_reg,
+ .max_register = ISL29028_NUM_REGS - 1,
+ .num_reg_defaults_raw = ISL29028_NUM_REGS,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit isl29028_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct isl29028_chip *chip;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = iio_device_alloc(sizeof(*chip));
+ if (!indio_dev) {
+ dev_err(&client->dev, "iio allocation fails\n");
+ return -ENOMEM;
+ }
+
+ chip = iio_priv(indio_dev);
+
+ i2c_set_clientdata(client, indio_dev);
+ chip->dev = &client->dev;
+ mutex_init(&chip->lock);
+
+ chip->regmap = devm_regmap_init_i2c(client, &isl29028_regmap_config);
+ if (IS_ERR(chip->regmap)) {
+ ret = PTR_ERR(chip->regmap);
+ dev_err(chip->dev, "regmap initialization failed: %d\n", ret);
+ goto exit_iio_free;
+ }
+
+ ret = isl29028_chip_init(chip);
+ if (ret < 0) {
+ dev_err(chip->dev, "chip initialization failed: %d\n", ret);
+ goto exit_iio_free;
+ }
+
+ indio_dev->info = &isl29028_info;
+ indio_dev->channels = isl29028_channels;
+ indio_dev->num_channels = ARRAY_SIZE(isl29028_channels);
+ indio_dev->name = id->name;
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ ret = iio_device_register(indio_dev);
+ if (ret < 0) {
+ dev_err(chip->dev, "iio registration fails with error %d\n",
+ ret);
+ goto exit_iio_free;
+ }
+ return 0;
+
+exit_iio_free:
+ iio_device_free(indio_dev);
+ return ret;
+}
+
+static int __devexit isl29028_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+ iio_device_unregister(indio_dev);
+ iio_device_free(indio_dev);
+ return 0;
+}
+
+static const struct i2c_device_id isl29028_id[] = {
+ {"isl29028", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, isl29028_id);
+
+static const struct of_device_id isl29028_of_match[] = {
+ { .compatible = "isil,isl29028", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, isl29028_of_match);
+
+static struct i2c_driver isl29028_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "isl29028",
+ .owner = THIS_MODULE,
+ .of_match_table = isl29028_of_match,
+ },
+ .probe = isl29028_probe,
+ .remove = __devexit_p(isl29028_remove),
+ .id_table = isl29028_id,
+};
+
+module_i2c_driver(isl29028_driver);
+
+MODULE_DESCRIPTION("ISL29028 Ambient Light and Proximity Sensor driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
diff --git a/drivers/staging/iio/light/tsl2563.c b/drivers/staging/iio/light/tsl2563.c
index 546c95a4ea9e..9d740be43a82 100644
--- a/drivers/staging/iio/light/tsl2563.c
+++ b/drivers/staging/iio/light/tsl2563.c
@@ -35,9 +35,9 @@
#include <linux/err.h>
#include <linux/slab.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../events.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
#include "tsl2563.h"
/* Use this many bits for fraction part. */
@@ -465,7 +465,7 @@ static int tsl2563_write_raw(struct iio_dev *indio_dev,
{
struct tsl2563_chip *chip = iio_priv(indio_dev);
- if (chan->channel == 0)
+ if (chan->channel == IIO_MOD_LIGHT_BOTH)
chip->calib0 = calib_from_sysfs(val);
else
chip->calib1 = calib_from_sysfs(val);
@@ -485,7 +485,8 @@ static int tsl2563_read_raw(struct iio_dev *indio_dev,
mutex_lock(&chip->lock);
switch (m) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
+ case IIO_CHAN_INFO_PROCESSED:
switch (chan->type) {
case IIO_LIGHT:
ret = tsl2563_get_adc(chip);
@@ -534,12 +535,14 @@ static const struct iio_chan_spec tsl2563_channels[] = {
{
.type = IIO_LIGHT,
.indexed = 1,
+ .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
.channel = 0,
}, {
.type = IIO_INTENSITY,
.modified = 1,
.channel2 = IIO_MOD_LIGHT_BOTH,
- .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
.event_mask = (IIO_EV_BIT(IIO_EV_TYPE_THRESH,
IIO_EV_DIR_RISING) |
IIO_EV_BIT(IIO_EV_TYPE_THRESH,
@@ -548,7 +551,8 @@ static const struct iio_chan_spec tsl2563_channels[] = {
.type = IIO_INTENSITY,
.modified = 1,
.channel2 = IIO_MOD_LIGHT_IR,
- .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
}
};
@@ -710,7 +714,7 @@ static int __devinit tsl2563_probe(struct i2c_client *client,
int err = 0;
u8 id = 0;
- indio_dev = iio_allocate_device(sizeof(*chip));
+ indio_dev = iio_device_alloc(sizeof(*chip));
if (!indio_dev)
return -ENOMEM;
@@ -797,7 +801,7 @@ fail2:
if (client->irq)
free_irq(client->irq, indio_dev);
fail1:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return err;
}
@@ -818,7 +822,7 @@ static int tsl2563_remove(struct i2c_client *client)
if (client->irq)
free_irq(client->irq, indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/light/tsl2583.c b/drivers/staging/iio/light/tsl2583.c
index 8671d98e0448..5e23ad5a30d5 100644
--- a/drivers/staging/iio/light/tsl2583.c
+++ b/drivers/staging/iio/light/tsl2583.c
@@ -28,7 +28,7 @@
#include <linux/unistd.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#define TSL258X_MAX_DEVICE_REGS 32
@@ -483,7 +483,7 @@ static int taos_chip_off(struct iio_dev *indio_dev)
static ssize_t taos_power_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2583_chip *chip = iio_priv(indio_dev);
return sprintf(buf, "%d\n", chip->taos_chip_status);
@@ -492,7 +492,7 @@ static ssize_t taos_power_state_show(struct device *dev,
static ssize_t taos_power_state_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
unsigned long value;
if (strict_strtoul(buf, 0, &value))
@@ -509,7 +509,7 @@ static ssize_t taos_power_state_store(struct device *dev,
static ssize_t taos_gain_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2583_chip *chip = iio_priv(indio_dev);
char gain[4] = {0};
@@ -534,7 +534,7 @@ static ssize_t taos_gain_show(struct device *dev,
static ssize_t taos_gain_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2583_chip *chip = iio_priv(indio_dev);
unsigned long value;
@@ -571,7 +571,7 @@ static ssize_t taos_gain_available_show(struct device *dev,
static ssize_t taos_als_time_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2583_chip *chip = iio_priv(indio_dev);
return sprintf(buf, "%d\n", chip->taos_settings.als_time);
@@ -580,7 +580,7 @@ static ssize_t taos_als_time_show(struct device *dev,
static ssize_t taos_als_time_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2583_chip *chip = iio_priv(indio_dev);
unsigned long value;
@@ -608,7 +608,7 @@ static ssize_t taos_als_time_available_show(struct device *dev,
static ssize_t taos_als_trim_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2583_chip *chip = iio_priv(indio_dev);
return sprintf(buf, "%d\n", chip->taos_settings.als_gain_trim);
@@ -617,7 +617,7 @@ static ssize_t taos_als_trim_show(struct device *dev,
static ssize_t taos_als_trim_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2583_chip *chip = iio_priv(indio_dev);
unsigned long value;
@@ -633,7 +633,7 @@ static ssize_t taos_als_trim_store(struct device *dev,
static ssize_t taos_als_cal_target_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2583_chip *chip = iio_priv(indio_dev);
return sprintf(buf, "%d\n", chip->taos_settings.als_cal_target);
@@ -642,7 +642,7 @@ static ssize_t taos_als_cal_target_show(struct device *dev,
static ssize_t taos_als_cal_target_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2583_chip *chip = iio_priv(indio_dev);
unsigned long value;
@@ -660,7 +660,7 @@ static ssize_t taos_lux_show(struct device *dev, struct device_attribute *attr,
{
int ret;
- ret = taos_get_lux(dev_get_drvdata(dev));
+ ret = taos_get_lux(dev_to_iio_dev(dev));
if (ret < 0)
return ret;
@@ -670,7 +670,7 @@ static ssize_t taos_lux_show(struct device *dev, struct device_attribute *attr,
static ssize_t taos_do_calibrate(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
unsigned long value;
if (strict_strtoul(buf, 0, &value))
@@ -708,7 +708,7 @@ static ssize_t taos_luxtable_show(struct device *dev,
static ssize_t taos_luxtable_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct tsl2583_chip *chip = iio_priv(indio_dev);
int value[ARRAY_SIZE(taos_device_lux)*3 + 1];
int n;
@@ -815,7 +815,7 @@ static int __devinit taos_probe(struct i2c_client *clientp,
return -EOPNOTSUPP;
}
- indio_dev = iio_allocate_device(sizeof(*chip));
+ indio_dev = iio_device_alloc(sizeof(*chip));
if (indio_dev == NULL) {
ret = -ENOMEM;
dev_err(&clientp->dev, "iio allocation failed\n");
@@ -879,7 +879,7 @@ static int __devinit taos_probe(struct i2c_client *clientp,
dev_info(&clientp->dev, "Light sensor found.\n");
return 0;
fail1:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
fail2:
return ret;
}
@@ -926,7 +926,7 @@ static SIMPLE_DEV_PM_OPS(taos_pm_ops, taos_suspend, taos_resume);
static int __devexit taos_remove(struct i2c_client *client)
{
iio_device_unregister(i2c_get_clientdata(client));
- iio_free_device(i2c_get_clientdata(client));
+ iio_device_free(i2c_get_clientdata(client));
return 0;
}
diff --git a/drivers/staging/iio/light/tsl2x7x.h b/drivers/staging/iio/light/tsl2x7x.h
new file mode 100755
index 000000000000..c4acf5ff1794
--- /dev/null
+++ b/drivers/staging/iio/light/tsl2x7x.h
@@ -0,0 +1,100 @@
+/*
+ * Device driver for monitoring ambient light intensity (lux)
+ * and proximity (prox) within the TAOS TSL2X7X family of devices.
+ *
+ * Copyright (c) 2012, TAOS Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __TSL2X7X_H
+#define __TSL2X7X_H
+#include <linux/pm.h>
+
+/* Max number of segments allowable in LUX table */
+#define TSL2X7X_MAX_LUX_TABLE_SIZE 9
+#define MAX_DEFAULT_TABLE_BYTES (sizeof(int) * TSL2X7X_MAX_LUX_TABLE_SIZE)
+
+struct iio_dev;
+
+struct tsl2x7x_lux {
+ unsigned int ratio;
+ unsigned int ch0;
+ unsigned int ch1;
+};
+
+/**
+ * struct tsl2x7x_default_settings - power on defaults unless
+ * overridden by platform data.
+ * @als_time: ALS Integration time - multiple of 50mS
+ * @als_gain: Index into the ALS gain table.
+ * @als_gain_trim: default gain trim to account for
+ * aperture effects.
+ * @wait_time: Time between PRX and ALS cycles
+ * in 2.7 periods
+ * @prx_time: 5.2ms prox integration time -
+ * decrease in 2.7ms periods
+ * @prx_gain: Proximity gain index
+ * @prox_config: Prox configuration filters.
+ * @als_cal_target: Known external ALS reading for
+ * calibration.
+ * @interrupts_en: Enable/Disable - 0x00 = none, 0x10 = als,
+ * 0x20 = prx, 0x30 = bth
+ * @persistence: H/W Filters, Number of 'out of limits'
+ * ADC readings PRX/ALS.
+ * @als_thresh_low: CH0 'low' count to trigger interrupt.
+ * @als_thresh_high: CH0 'high' count to trigger interrupt.
+ * @prox_thres_low: Low threshold proximity detection.
+ * @prox_thres_high: High threshold proximity detection
+ * @prox_pulse_count: Number if proximity emitter pulses
+ * @prox_max_samples_cal: Used for prox cal.
+ */
+struct tsl2x7x_settings {
+ int als_time;
+ int als_gain;
+ int als_gain_trim;
+ int wait_time;
+ int prx_time;
+ int prox_gain;
+ int prox_config;
+ int als_cal_target;
+ u8 interrupts_en;
+ u8 persistence;
+ int als_thresh_low;
+ int als_thresh_high;
+ int prox_thres_low;
+ int prox_thres_high;
+ int prox_pulse_count;
+ int prox_max_samples_cal;
+};
+
+/**
+ * struct tsl2X7X_platform_data - Platform callback, glass and defaults
+ * @platform_power: Suspend/resume platform callback
+ * @power_on: Power on callback
+ * @power_off: Power off callback
+ * @platform_lux_table: Device specific glass coefficents
+ * @platform_default_settings: Device specific power on defaults
+ *
+ */
+struct tsl2X7X_platform_data {
+ int (*platform_power)(struct device *dev, pm_message_t);
+ int (*power_on) (struct iio_dev *indio_dev);
+ int (*power_off) (struct i2c_client *dev);
+ struct tsl2x7x_lux platform_lux_table[TSL2X7X_MAX_LUX_TABLE_SIZE];
+ struct tsl2x7x_settings *platform_default_settings;
+};
+
+#endif /* __TSL2X7X_H */
diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c
new file mode 100755
index 000000000000..c3b05a1b3ea8
--- /dev/null
+++ b/drivers/staging/iio/light/tsl2x7x_core.c
@@ -0,0 +1,2082 @@
+/*
+ * Device driver for monitoring ambient light intensity in (lux)
+ * and proximity detection (prox) within the TAOS TSL2X7X family of devices.
+ *
+ * Copyright (c) 2012, TAOS Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include "tsl2x7x.h"
+
+/* Cal defs*/
+#define PROX_STAT_CAL 0
+#define PROX_STAT_SAMP 1
+#define MAX_SAMPLES_CAL 200
+
+/* TSL2X7X Device ID */
+#define TRITON_ID 0x00
+#define SWORDFISH_ID 0x30
+#define HALIBUT_ID 0x20
+
+/* Lux calculation constants */
+#define TSL2X7X_LUX_CALC_OVER_FLOW 65535
+
+/* TAOS Register definitions - note:
+ * depending on device, some of these register are not used and the
+ * register address is benign.
+ */
+/* 2X7X register offsets */
+#define TSL2X7X_MAX_CONFIG_REG 16
+
+/* Device Registers and Masks */
+#define TSL2X7X_CNTRL 0x00
+#define TSL2X7X_ALS_TIME 0X01
+#define TSL2X7X_PRX_TIME 0x02
+#define TSL2X7X_WAIT_TIME 0x03
+#define TSL2X7X_ALS_MINTHRESHLO 0X04
+#define TSL2X7X_ALS_MINTHRESHHI 0X05
+#define TSL2X7X_ALS_MAXTHRESHLO 0X06
+#define TSL2X7X_ALS_MAXTHRESHHI 0X07
+#define TSL2X7X_PRX_MINTHRESHLO 0X08
+#define TSL2X7X_PRX_MINTHRESHHI 0X09
+#define TSL2X7X_PRX_MAXTHRESHLO 0X0A
+#define TSL2X7X_PRX_MAXTHRESHHI 0X0B
+#define TSL2X7X_PERSISTENCE 0x0C
+#define TSL2X7X_PRX_CONFIG 0x0D
+#define TSL2X7X_PRX_COUNT 0x0E
+#define TSL2X7X_GAIN 0x0F
+#define TSL2X7X_NOTUSED 0x10
+#define TSL2X7X_REVID 0x11
+#define TSL2X7X_CHIPID 0x12
+#define TSL2X7X_STATUS 0x13
+#define TSL2X7X_ALS_CHAN0LO 0x14
+#define TSL2X7X_ALS_CHAN0HI 0x15
+#define TSL2X7X_ALS_CHAN1LO 0x16
+#define TSL2X7X_ALS_CHAN1HI 0x17
+#define TSL2X7X_PRX_LO 0x18
+#define TSL2X7X_PRX_HI 0x19
+
+/* tsl2X7X cmd reg masks */
+#define TSL2X7X_CMD_REG 0x80
+#define TSL2X7X_CMD_SPL_FN 0x60
+
+#define TSL2X7X_CMD_PROX_INT_CLR 0X05
+#define TSL2X7X_CMD_ALS_INT_CLR 0x06
+#define TSL2X7X_CMD_PROXALS_INT_CLR 0X07
+
+/* tsl2X7X cntrl reg masks */
+#define TSL2X7X_CNTL_ADC_ENBL 0x02
+#define TSL2X7X_CNTL_PWR_ON 0x01
+
+/* tsl2X7X status reg masks */
+#define TSL2X7X_STA_ADC_VALID 0x01
+#define TSL2X7X_STA_PRX_VALID 0x02
+#define TSL2X7X_STA_ADC_PRX_VALID (TSL2X7X_STA_ADC_VALID |\
+ TSL2X7X_STA_PRX_VALID)
+#define TSL2X7X_STA_ALS_INTR 0x10
+#define TSL2X7X_STA_PRX_INTR 0x20
+
+/* tsl2X7X cntrl reg masks */
+#define TSL2X7X_CNTL_REG_CLEAR 0x00
+#define TSL2X7X_CNTL_PROX_INT_ENBL 0X20
+#define TSL2X7X_CNTL_ALS_INT_ENBL 0X10
+#define TSL2X7X_CNTL_WAIT_TMR_ENBL 0X08
+#define TSL2X7X_CNTL_PROX_DET_ENBL 0X04
+#define TSL2X7X_CNTL_PWRON 0x01
+#define TSL2X7X_CNTL_ALSPON_ENBL 0x03
+#define TSL2X7X_CNTL_INTALSPON_ENBL 0x13
+#define TSL2X7X_CNTL_PROXPON_ENBL 0x0F
+#define TSL2X7X_CNTL_INTPROXPON_ENBL 0x2F
+
+/*Prox diode to use */
+#define TSL2X7X_DIODE0 0x10
+#define TSL2X7X_DIODE1 0x20
+#define TSL2X7X_DIODE_BOTH 0x30
+
+/* LED Power */
+#define TSL2X7X_mA100 0x00
+#define TSL2X7X_mA50 0x40
+#define TSL2X7X_mA25 0x80
+#define TSL2X7X_mA13 0xD0
+#define TSL2X7X_MAX_TIMER_CNT (0xFF)
+
+/*Common device IIO EventMask */
+#define TSL2X7X_EVENT_MASK \
+ (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | \
+ IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING)),
+
+#define TSL2X7X_MIN_ITIME 3
+
+/* TAOS txx2x7x Device family members */
+enum {
+ tsl2571,
+ tsl2671,
+ tmd2671,
+ tsl2771,
+ tmd2771,
+ tsl2572,
+ tsl2672,
+ tmd2672,
+ tsl2772,
+ tmd2772
+};
+
+enum {
+ TSL2X7X_CHIP_UNKNOWN = 0,
+ TSL2X7X_CHIP_WORKING = 1,
+ TSL2X7X_CHIP_SUSPENDED = 2
+};
+
+struct tsl2x7x_parse_result {
+ int integer;
+ int fract;
+};
+
+/* Per-device data */
+struct tsl2x7x_als_info {
+ u16 als_ch0;
+ u16 als_ch1;
+ u16 lux;
+};
+
+struct tsl2x7x_prox_stat {
+ int min;
+ int max;
+ int mean;
+ unsigned long stddev;
+};
+
+struct tsl2x7x_chip_info {
+ int chan_table_elements;
+ struct iio_chan_spec channel[4];
+ const struct iio_info *info;
+};
+
+struct tsl2X7X_chip {
+ kernel_ulong_t id;
+ struct mutex prox_mutex;
+ struct mutex als_mutex;
+ struct i2c_client *client;
+ u16 prox_data;
+ struct tsl2x7x_als_info als_cur_info;
+ struct tsl2x7x_settings tsl2x7x_settings;
+ struct tsl2X7X_platform_data *pdata;
+ int als_time_scale;
+ int als_saturation;
+ int tsl2x7x_chip_status;
+ u8 tsl2x7x_config[TSL2X7X_MAX_CONFIG_REG];
+ const struct tsl2x7x_chip_info *chip_info;
+ const struct iio_info *info;
+ s64 event_timestamp;
+ /* This structure is intentionally large to accommodate
+ * updates via sysfs. */
+ /* Sized to 9 = max 8 segments + 1 termination segment */
+ struct tsl2x7x_lux tsl2x7x_device_lux[TSL2X7X_MAX_LUX_TABLE_SIZE];
+};
+
+/* Different devices require different coefficents */
+static const struct tsl2x7x_lux tsl2x71_lux_table[] = {
+ { 14461, 611, 1211 },
+ { 18540, 352, 623 },
+ { 0, 0, 0 },
+};
+
+static const struct tsl2x7x_lux tmd2x71_lux_table[] = {
+ { 11635, 115, 256 },
+ { 15536, 87, 179 },
+ { 0, 0, 0 },
+};
+
+static const struct tsl2x7x_lux tsl2x72_lux_table[] = {
+ { 14013, 466, 917 },
+ { 18222, 310, 552 },
+ { 0, 0, 0 },
+};
+
+static const struct tsl2x7x_lux tmd2x72_lux_table[] = {
+ { 13218, 130, 262 },
+ { 17592, 92, 169 },
+ { 0, 0, 0 },
+};
+
+static const struct tsl2x7x_lux *tsl2x7x_default_lux_table_group[] = {
+ [tsl2571] = tsl2x71_lux_table,
+ [tsl2671] = tsl2x71_lux_table,
+ [tmd2671] = tmd2x71_lux_table,
+ [tsl2771] = tsl2x71_lux_table,
+ [tmd2771] = tmd2x71_lux_table,
+ [tsl2572] = tsl2x72_lux_table,
+ [tsl2672] = tsl2x72_lux_table,
+ [tmd2672] = tmd2x72_lux_table,
+ [tsl2772] = tsl2x72_lux_table,
+ [tmd2772] = tmd2x72_lux_table,
+};
+
+static const struct tsl2x7x_settings tsl2x7x_default_settings = {
+ .als_time = 219, /* 101 ms */
+ .als_gain = 0,
+ .prx_time = 254, /* 5.4 ms */
+ .prox_gain = 1,
+ .wait_time = 245,
+ .prox_config = 0,
+ .als_gain_trim = 1000,
+ .als_cal_target = 150,
+ .als_thresh_low = 200,
+ .als_thresh_high = 256,
+ .persistence = 255,
+ .interrupts_en = 0,
+ .prox_thres_low = 0,
+ .prox_thres_high = 512,
+ .prox_max_samples_cal = 30,
+ .prox_pulse_count = 8
+};
+
+static const s16 tsl2X7X_als_gainadj[] = {
+ 1,
+ 8,
+ 16,
+ 120
+};
+
+static const s16 tsl2X7X_prx_gainadj[] = {
+ 1,
+ 2,
+ 4,
+ 8
+};
+
+/* Channel variations */
+enum {
+ ALS,
+ PRX,
+ ALSPRX,
+ PRX2,
+ ALSPRX2,
+};
+
+static const u8 device_channel_config[] = {
+ ALS,
+ PRX,
+ PRX,
+ ALSPRX,
+ ALSPRX,
+ ALS,
+ PRX2,
+ PRX2,
+ ALSPRX2,
+ ALSPRX2
+};
+
+/**
+ * tsl2x7x_parse_buffer() - parse a decimal result from a buffer.
+ * @*buf: pointer to char buffer to parse
+ * @*result: pointer to buffer to contain
+ * resulting interger / decimal as ints.
+ *
+ */
+static int
+tsl2x7x_parse_buffer(const char *buf, struct tsl2x7x_parse_result *result)
+{
+ int integer = 0, fract = 0, fract_mult = 100000;
+ bool integer_part = true, negative = false;
+
+ if (buf[0] == '-') {
+ negative = true;
+ buf++;
+ }
+
+ while (*buf) {
+ if ('0' <= *buf && *buf <= '9') {
+ if (integer_part)
+ integer = integer*10 + *buf - '0';
+ else {
+ fract += fract_mult*(*buf - '0');
+ if (fract_mult == 1)
+ break;
+ fract_mult /= 10;
+ }
+ } else if (*buf == '\n') {
+ if (*(buf + 1) == '\0')
+ break;
+ else
+ return -EINVAL;
+ } else if (*buf == '.') {
+ integer_part = false;
+ } else {
+ return -EINVAL;
+ }
+ buf++;
+ }
+ if (negative) {
+ if (integer)
+ integer = -integer;
+ else
+ fract = -fract;
+ }
+
+ result->integer = integer;
+ result->fract = fract;
+
+ return 0;
+}
+
+/**
+ * tsl2x7x_i2c_read() - Read a byte from a register.
+ * @client: i2c client
+ * @reg: device register to read from
+ * @*val: pointer to location to store register contents.
+ *
+ */
+static int
+tsl2x7x_i2c_read(struct i2c_client *client, u8 reg, u8 *val)
+{
+ int ret = 0;
+
+ /* select register to write */
+ ret = i2c_smbus_write_byte(client, (TSL2X7X_CMD_REG | reg));
+ if (ret < 0) {
+ dev_err(&client->dev, "%s: failed to write register %x\n"
+ , __func__, reg);
+ return ret;
+ }
+
+ /* read the data */
+ ret = i2c_smbus_read_byte(client);
+ if (ret >= 0)
+ *val = (u8)ret;
+ else
+ dev_err(&client->dev, "%s: failed to read register %x\n"
+ , __func__, reg);
+
+ return ret;
+}
+
+/**
+ * tsl2x7x_get_lux() - Reads and calculates current lux value.
+ * @indio_dev: pointer to IIO device
+ *
+ * The raw ch0 and ch1 values of the ambient light sensed in the last
+ * integration cycle are read from the device.
+ * Time scale factor array values are adjusted based on the integration time.
+ * The raw values are multiplied by a scale factor, and device gain is obtained
+ * using gain index. Limit checks are done next, then the ratio of a multiple
+ * of ch1 value, to the ch0 value, is calculated. Array tsl2x7x_device_lux[]
+ * is then scanned to find the first ratio value that is just above the ratio
+ * we just calculated. The ch0 and ch1 multiplier constants in the array are
+ * then used along with the time scale factor array values, to calculate the
+ * lux.
+ */
+static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
+{
+ u16 ch0, ch1; /* separated ch0/ch1 data from device */
+ u32 lux; /* raw lux calculated from device data */
+ u64 lux64;
+ u32 ratio;
+ u8 buf[4];
+ struct tsl2x7x_lux *p;
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ int i, ret;
+ u32 ch0lux = 0;
+ u32 ch1lux = 0;
+
+ if (mutex_trylock(&chip->als_mutex) == 0)
+ return chip->als_cur_info.lux; /* busy, so return LAST VALUE */
+
+ if (chip->tsl2x7x_chip_status != TSL2X7X_CHIP_WORKING) {
+ /* device is not enabled */
+ dev_err(&chip->client->dev, "%s: device is not enabled\n",
+ __func__);
+ ret = -EBUSY ;
+ goto out_unlock;
+ }
+
+ ret = tsl2x7x_i2c_read(chip->client,
+ (TSL2X7X_CMD_REG | TSL2X7X_STATUS), &buf[0]);
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: Failed to read STATUS Reg\n", __func__);
+ goto out_unlock;
+ }
+ /* is data new & valid */
+ if (!(buf[0] & TSL2X7X_STA_ADC_VALID)) {
+ dev_err(&chip->client->dev,
+ "%s: data not valid yet\n", __func__);
+ ret = chip->als_cur_info.lux; /* return LAST VALUE */
+ goto out_unlock;
+ }
+
+ for (i = 0; i < 4; i++) {
+ ret = tsl2x7x_i2c_read(chip->client,
+ (TSL2X7X_CMD_REG | (TSL2X7X_ALS_CHAN0LO + i)),
+ &buf[i]);
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: failed to read. err=%x\n", __func__, ret);
+ goto out_unlock;
+ }
+ }
+
+ /* clear any existing interrupt status */
+ ret = i2c_smbus_write_byte(chip->client,
+ (TSL2X7X_CMD_REG |
+ TSL2X7X_CMD_SPL_FN |
+ TSL2X7X_CMD_ALS_INT_CLR));
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: i2c_write_command failed - err = %d\n",
+ __func__, ret);
+ goto out_unlock; /* have no data, so return failure */
+ }
+
+ /* extract ALS/lux data */
+ ch0 = le16_to_cpup((const __le16 *)&buf[0]);
+ ch1 = le16_to_cpup((const __le16 *)&buf[2]);
+
+ chip->als_cur_info.als_ch0 = ch0;
+ chip->als_cur_info.als_ch1 = ch1;
+
+ if ((ch0 >= chip->als_saturation) || (ch1 >= chip->als_saturation)) {
+ lux = TSL2X7X_LUX_CALC_OVER_FLOW;
+ goto return_max;
+ }
+
+ if (ch0 == 0) {
+ /* have no data, so return LAST VALUE */
+ ret = chip->als_cur_info.lux;
+ goto out_unlock;
+ }
+ /* calculate ratio */
+ ratio = (ch1 << 15) / ch0;
+ /* convert to unscaled lux using the pointer to the table */
+ p = (struct tsl2x7x_lux *) chip->tsl2x7x_device_lux;
+ while (p->ratio != 0 && p->ratio < ratio)
+ p++;
+
+ if (p->ratio == 0) {
+ lux = 0;
+ } else {
+ ch0lux = DIV_ROUND_UP((ch0 * p->ch0),
+ tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain]);
+ ch1lux = DIV_ROUND_UP((ch1 * p->ch1),
+ tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain]);
+ lux = ch0lux - ch1lux;
+ }
+
+ /* note: lux is 31 bit max at this point */
+ if (ch1lux > ch0lux) {
+ dev_dbg(&chip->client->dev, "ch1lux > ch0lux-return last value\n");
+ ret = chip->als_cur_info.lux;
+ goto out_unlock;
+ }
+
+ /* adjust for active time scale */
+ if (chip->als_time_scale == 0)
+ lux = 0;
+ else
+ lux = (lux + (chip->als_time_scale >> 1)) /
+ chip->als_time_scale;
+
+ /* adjust for active gain scale
+ * The tsl2x7x_device_lux tables have a factor of 256 built-in.
+ * User-specified gain provides a multiplier.
+ * Apply user-specified gain before shifting right to retain precision.
+ * Use 64 bits to avoid overflow on multiplication.
+ * Then go back to 32 bits before division to avoid using div_u64().
+ */
+
+ lux64 = lux;
+ lux64 = lux64 * chip->tsl2x7x_settings.als_gain_trim;
+ lux64 >>= 8;
+ lux = lux64;
+ lux = (lux + 500) / 1000;
+
+ if (lux > TSL2X7X_LUX_CALC_OVER_FLOW) /* check for overflow */
+ lux = TSL2X7X_LUX_CALC_OVER_FLOW;
+
+ /* Update the structure with the latest lux. */
+return_max:
+ chip->als_cur_info.lux = lux;
+ ret = lux;
+
+out_unlock:
+ mutex_unlock(&chip->als_mutex);
+
+ return ret;
+}
+
+/**
+ * tsl2x7x_get_prox() - Reads proximity data registers and updates
+ * chip->prox_data.
+ *
+ * @indio_dev: pointer to IIO device
+ */
+static int tsl2x7x_get_prox(struct iio_dev *indio_dev)
+{
+ int i;
+ int ret;
+ u8 status;
+ u8 chdata[2];
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+ if (mutex_trylock(&chip->prox_mutex) == 0) {
+ dev_err(&chip->client->dev,
+ "%s: Can't get prox mutex\n", __func__);
+ return -EBUSY;
+ }
+
+ ret = tsl2x7x_i2c_read(chip->client,
+ (TSL2X7X_CMD_REG | TSL2X7X_STATUS), &status);
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: i2c err=%d\n", __func__, ret);
+ goto prox_poll_err;
+ }
+
+ switch (chip->id) {
+ case tsl2571:
+ case tsl2671:
+ case tmd2671:
+ case tsl2771:
+ case tmd2771:
+ if (!(status & TSL2X7X_STA_ADC_VALID))
+ goto prox_poll_err;
+ break;
+ case tsl2572:
+ case tsl2672:
+ case tmd2672:
+ case tsl2772:
+ case tmd2772:
+ if (!(status & TSL2X7X_STA_PRX_VALID))
+ goto prox_poll_err;
+ break;
+ }
+
+ for (i = 0; i < 2; i++) {
+ ret = tsl2x7x_i2c_read(chip->client,
+ (TSL2X7X_CMD_REG |
+ (TSL2X7X_PRX_LO + i)), &chdata[i]);
+ if (ret < 0)
+ goto prox_poll_err;
+ }
+
+ chip->prox_data =
+ le16_to_cpup((const __le16 *)&chdata[0]);
+
+prox_poll_err:
+
+ mutex_unlock(&chip->prox_mutex);
+
+ return chip->prox_data;
+}
+
+/**
+ * tsl2x7x_defaults() - Populates the device nominal operating parameters
+ * with those provided by a 'platform' data struct or
+ * with prefined defaults.
+ *
+ * @chip: pointer to device structure.
+ */
+static void tsl2x7x_defaults(struct tsl2X7X_chip *chip)
+{
+ /* If Operational settings defined elsewhere.. */
+ if (chip->pdata && chip->pdata->platform_default_settings != 0)
+ memcpy(&(chip->tsl2x7x_settings),
+ chip->pdata->platform_default_settings,
+ sizeof(tsl2x7x_default_settings));
+ else
+ memcpy(&(chip->tsl2x7x_settings),
+ &tsl2x7x_default_settings,
+ sizeof(tsl2x7x_default_settings));
+
+ /* Load up the proper lux table. */
+ if (chip->pdata && chip->pdata->platform_lux_table[0].ratio != 0)
+ memcpy(chip->tsl2x7x_device_lux,
+ chip->pdata->platform_lux_table,
+ sizeof(chip->pdata->platform_lux_table));
+ else
+ memcpy(chip->tsl2x7x_device_lux,
+ (struct tsl2x7x_lux *)tsl2x7x_default_lux_table_group[chip->id],
+ MAX_DEFAULT_TABLE_BYTES);
+}
+
+/**
+ * tsl2x7x_als_calibrate() - Obtain single reading and calculate
+ * the als_gain_trim.
+ *
+ * @indio_dev: pointer to IIO device
+ */
+static int tsl2x7x_als_calibrate(struct iio_dev *indio_dev)
+{
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ u8 reg_val;
+ int gain_trim_val;
+ int ret;
+ int lux_val;
+
+ ret = i2c_smbus_write_byte(chip->client,
+ (TSL2X7X_CMD_REG | TSL2X7X_CNTRL));
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: failed to write CNTRL register, ret=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ reg_val = i2c_smbus_read_byte(chip->client);
+ if ((reg_val & (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON))
+ != (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON)) {
+ dev_err(&chip->client->dev,
+ "%s: failed: ADC not enabled\n", __func__);
+ return -1;
+ }
+
+ ret = i2c_smbus_write_byte(chip->client,
+ (TSL2X7X_CMD_REG | TSL2X7X_CNTRL));
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: failed to write ctrl reg: ret=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ reg_val = i2c_smbus_read_byte(chip->client);
+ if ((reg_val & TSL2X7X_STA_ADC_VALID) != TSL2X7X_STA_ADC_VALID) {
+ dev_err(&chip->client->dev,
+ "%s: failed: STATUS - ADC not valid.\n", __func__);
+ return -ENODATA;
+ }
+
+ lux_val = tsl2x7x_get_lux(indio_dev);
+ if (lux_val < 0) {
+ dev_err(&chip->client->dev,
+ "%s: failed to get lux\n", __func__);
+ return lux_val;
+ }
+
+ gain_trim_val = (((chip->tsl2x7x_settings.als_cal_target)
+ * chip->tsl2x7x_settings.als_gain_trim) / lux_val);
+ if ((gain_trim_val < 250) || (gain_trim_val > 4000))
+ return -ERANGE;
+
+ chip->tsl2x7x_settings.als_gain_trim = gain_trim_val;
+ dev_info(&chip->client->dev,
+ "%s als_calibrate completed\n", chip->client->name);
+
+ return (int) gain_trim_val;
+}
+
+static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
+{
+ int i;
+ int ret = 0;
+ u8 *dev_reg;
+ u8 utmp;
+ int als_count;
+ int als_time;
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ u8 reg_val = 0;
+
+ if (chip->pdata && chip->pdata->power_on)
+ chip->pdata->power_on(indio_dev);
+
+ /* Non calculated parameters */
+ chip->tsl2x7x_config[TSL2X7X_PRX_TIME] =
+ chip->tsl2x7x_settings.prx_time;
+ chip->tsl2x7x_config[TSL2X7X_WAIT_TIME] =
+ chip->tsl2x7x_settings.wait_time;
+ chip->tsl2x7x_config[TSL2X7X_PRX_CONFIG] =
+ chip->tsl2x7x_settings.prox_config;
+
+ chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHLO] =
+ (chip->tsl2x7x_settings.als_thresh_low) & 0xFF;
+ chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHHI] =
+ (chip->tsl2x7x_settings.als_thresh_low >> 8) & 0xFF;
+ chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHLO] =
+ (chip->tsl2x7x_settings.als_thresh_high) & 0xFF;
+ chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHHI] =
+ (chip->tsl2x7x_settings.als_thresh_high >> 8) & 0xFF;
+ chip->tsl2x7x_config[TSL2X7X_PERSISTENCE] =
+ chip->tsl2x7x_settings.persistence;
+
+ chip->tsl2x7x_config[TSL2X7X_PRX_COUNT] =
+ chip->tsl2x7x_settings.prox_pulse_count;
+ chip->tsl2x7x_config[TSL2X7X_PRX_MINTHRESHLO] =
+ chip->tsl2x7x_settings.prox_thres_low;
+ chip->tsl2x7x_config[TSL2X7X_PRX_MAXTHRESHLO] =
+ chip->tsl2x7x_settings.prox_thres_high;
+
+ /* and make sure we're not already on */
+ if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) {
+ /* if forcing a register update - turn off, then on */
+ dev_info(&chip->client->dev, "device is already enabled\n");
+ return -EINVAL;
+ }
+
+ /* determine als integration regster */
+ als_count = (chip->tsl2x7x_settings.als_time * 100 + 135) / 270;
+ if (als_count == 0)
+ als_count = 1; /* ensure at least one cycle */
+
+ /* convert back to time (encompasses overrides) */
+ als_time = (als_count * 27 + 5) / 10;
+ chip->tsl2x7x_config[TSL2X7X_ALS_TIME] = 256 - als_count;
+
+ /* Set the gain based on tsl2x7x_settings struct */
+ chip->tsl2x7x_config[TSL2X7X_GAIN] =
+ (chip->tsl2x7x_settings.als_gain |
+ (TSL2X7X_mA100 | TSL2X7X_DIODE1)
+ | ((chip->tsl2x7x_settings.prox_gain) << 2));
+
+ /* set chip struct re scaling and saturation */
+ chip->als_saturation = als_count * 922; /* 90% of full scale */
+ chip->als_time_scale = (als_time + 25) / 50;
+
+ /* TSL2X7X Specific power-on / adc enable sequence
+ * Power on the device 1st. */
+ utmp = TSL2X7X_CNTL_PWR_ON;
+ ret = i2c_smbus_write_byte_data(chip->client,
+ TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp);
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: failed on CNTRL reg.\n", __func__);
+ return ret;
+ }
+
+ /* Use the following shadow copy for our delay before enabling ADC.
+ * Write all the registers. */
+ for (i = 0, dev_reg = chip->tsl2x7x_config;
+ i < TSL2X7X_MAX_CONFIG_REG; i++) {
+ ret = i2c_smbus_write_byte_data(chip->client,
+ TSL2X7X_CMD_REG + i, *dev_reg++);
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: failed on write to reg %d.\n", __func__, i);
+ return ret;
+ }
+ }
+
+ mdelay(3); /* Power-on settling time */
+
+ /* NOW enable the ADC
+ * initialize the desired mode of operation */
+ utmp = TSL2X7X_CNTL_PWR_ON |
+ TSL2X7X_CNTL_ADC_ENBL |
+ TSL2X7X_CNTL_PROX_DET_ENBL;
+ ret = i2c_smbus_write_byte_data(chip->client,
+ TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp);
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: failed on 2nd CTRL reg.\n", __func__);
+ return ret;
+ }
+
+ chip->tsl2x7x_chip_status = TSL2X7X_CHIP_WORKING;
+
+ if (chip->tsl2x7x_settings.interrupts_en != 0) {
+ dev_info(&chip->client->dev, "Setting Up Interrupt(s)\n");
+
+ reg_val = TSL2X7X_CNTL_PWR_ON | TSL2X7X_CNTL_ADC_ENBL;
+ if ((chip->tsl2x7x_settings.interrupts_en == 0x20) ||
+ (chip->tsl2x7x_settings.interrupts_en == 0x30))
+ reg_val |= TSL2X7X_CNTL_PROX_DET_ENBL;
+
+ reg_val |= chip->tsl2x7x_settings.interrupts_en;
+ ret = i2c_smbus_write_byte_data(chip->client,
+ (TSL2X7X_CMD_REG | TSL2X7X_CNTRL), reg_val);
+ if (ret < 0)
+ dev_err(&chip->client->dev,
+ "%s: failed in tsl2x7x_IOCTL_INT_SET.\n",
+ __func__);
+
+ /* Clear out any initial interrupts */
+ ret = i2c_smbus_write_byte(chip->client,
+ TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN |
+ TSL2X7X_CMD_PROXALS_INT_CLR);
+ if (ret < 0) {
+ dev_err(&chip->client->dev,
+ "%s: Failed to clear Int status\n",
+ __func__);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static int tsl2x7x_chip_off(struct iio_dev *indio_dev)
+{
+ int ret;
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+ /* turn device off */
+ chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED;
+
+ ret = i2c_smbus_write_byte_data(chip->client,
+ TSL2X7X_CMD_REG | TSL2X7X_CNTRL, 0x00);
+
+ if (chip->pdata && chip->pdata->power_off)
+ chip->pdata->power_off(chip->client);
+
+ return ret;
+}
+
+/**
+ * tsl2x7x_invoke_change
+ * @indio_dev: pointer to IIO device
+ *
+ * Obtain and lock both ALS and PROX resources,
+ * determine and save device state (On/Off),
+ * cycle device to implement updated parameter,
+ * put device back into proper state, and unlock
+ * resource.
+ */
+static
+int tsl2x7x_invoke_change(struct iio_dev *indio_dev)
+{
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ int device_status = chip->tsl2x7x_chip_status;
+
+ mutex_lock(&chip->als_mutex);
+ mutex_lock(&chip->prox_mutex);
+
+ if (device_status == TSL2X7X_CHIP_WORKING)
+ tsl2x7x_chip_off(indio_dev);
+
+ tsl2x7x_chip_on(indio_dev);
+
+ if (device_status != TSL2X7X_CHIP_WORKING)
+ tsl2x7x_chip_off(indio_dev);
+
+ mutex_unlock(&chip->prox_mutex);
+ mutex_unlock(&chip->als_mutex);
+
+ return 0;
+}
+
+static
+void tsl2x7x_prox_calculate(int *data, int length,
+ struct tsl2x7x_prox_stat *statP)
+{
+ int i;
+ int sample_sum;
+ int tmp;
+
+ if (length == 0)
+ length = 1;
+
+ sample_sum = 0;
+ statP->min = INT_MAX;
+ statP->max = INT_MIN;
+ for (i = 0; i < length; i++) {
+ sample_sum += data[i];
+ statP->min = min(statP->min, data[i]);
+ statP->max = max(statP->max, data[i]);
+ }
+
+ statP->mean = sample_sum / length;
+ sample_sum = 0;
+ for (i = 0; i < length; i++) {
+ tmp = data[i] - statP->mean;
+ sample_sum += tmp * tmp;
+ }
+ statP->stddev = int_sqrt((long)sample_sum)/length;
+}
+
+/**
+ * tsl2x7x_prox_cal() - Calculates std. and sets thresholds.
+ * @indio_dev: pointer to IIO device
+ *
+ * Calculates a standard deviation based on the samples,
+ * and sets the threshold accordingly.
+ */
+static void tsl2x7x_prox_cal(struct iio_dev *indio_dev)
+{
+ int prox_history[MAX_SAMPLES_CAL + 1];
+ int i;
+ struct tsl2x7x_prox_stat prox_stat_data[2];
+ struct tsl2x7x_prox_stat *calP;
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ u8 tmp_irq_settings;
+ u8 current_state = chip->tsl2x7x_chip_status;
+
+ if (chip->tsl2x7x_settings.prox_max_samples_cal > MAX_SAMPLES_CAL) {
+ dev_err(&chip->client->dev,
+ "%s: max prox samples cal is too big: %d\n",
+ __func__, chip->tsl2x7x_settings.prox_max_samples_cal);
+ chip->tsl2x7x_settings.prox_max_samples_cal = MAX_SAMPLES_CAL;
+ }
+
+ /* have to stop to change settings */
+ tsl2x7x_chip_off(indio_dev);
+
+ /* Enable proximity detection save just in case prox not wanted yet*/
+ tmp_irq_settings = chip->tsl2x7x_settings.interrupts_en;
+ chip->tsl2x7x_settings.interrupts_en |= TSL2X7X_CNTL_PROX_INT_ENBL;
+
+ /*turn on device if not already on*/
+ tsl2x7x_chip_on(indio_dev);
+
+ /*gather the samples*/
+ for (i = 0; i < chip->tsl2x7x_settings.prox_max_samples_cal; i++) {
+ mdelay(15);
+ tsl2x7x_get_prox(indio_dev);
+ prox_history[i] = chip->prox_data;
+ dev_info(&chip->client->dev, "2 i=%d prox data= %d\n",
+ i, chip->prox_data);
+ }
+
+ tsl2x7x_chip_off(indio_dev);
+ calP = &prox_stat_data[PROX_STAT_CAL];
+ tsl2x7x_prox_calculate(prox_history,
+ chip->tsl2x7x_settings.prox_max_samples_cal, calP);
+ chip->tsl2x7x_settings.prox_thres_high = (calP->max << 1) - calP->mean;
+
+ dev_info(&chip->client->dev, " cal min=%d mean=%d max=%d\n",
+ calP->min, calP->mean, calP->max);
+ dev_info(&chip->client->dev,
+ "%s proximity threshold set to %d\n",
+ chip->client->name, chip->tsl2x7x_settings.prox_thres_high);
+
+ /* back to the way they were */
+ chip->tsl2x7x_settings.interrupts_en = tmp_irq_settings;
+ if (current_state == TSL2X7X_CHIP_WORKING)
+ tsl2x7x_chip_on(indio_dev);
+}
+
+static ssize_t tsl2x7x_power_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", chip->tsl2x7x_chip_status);
+}
+
+static ssize_t tsl2x7x_power_state_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ bool value;
+
+ if (strtobool(buf, &value))
+ return -EINVAL;
+
+ if (value)
+ tsl2x7x_chip_on(indio_dev);
+ else
+ tsl2x7x_chip_off(indio_dev);
+
+ return len;
+}
+
+static ssize_t tsl2x7x_gain_available_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+
+ switch (chip->id) {
+ case tsl2571:
+ case tsl2671:
+ case tmd2671:
+ case tsl2771:
+ case tmd2771:
+ return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 128");
+ break;
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 120");
+}
+
+static ssize_t tsl2x7x_prox_gain_available_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", "1 2 4 8");
+}
+
+static ssize_t tsl2x7x_als_time_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+ int y, z;
+
+ y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1;
+ z = y * TSL2X7X_MIN_ITIME;
+ y /= 1000;
+ z %= 1000;
+
+ return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z);
+}
+
+static ssize_t tsl2x7x_als_time_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ struct tsl2x7x_parse_result result;
+
+ result.integer = 0;
+ result.fract = 0;
+
+ tsl2x7x_parse_buffer(buf, &result);
+
+ result.fract /= 1000;
+ result.fract /= 3;
+ chip->tsl2x7x_settings.als_time =
+ (TSL2X7X_MAX_TIMER_CNT - (u8)result.fract);
+
+ dev_info(&chip->client->dev, "%s: als time = %d",
+ __func__, chip->tsl2x7x_settings.als_time);
+
+ tsl2x7x_invoke_change(indio_dev);
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static IIO_CONST_ATTR(in_illuminance0_integration_time_available,
+ ".00272 - .696");
+
+static ssize_t tsl2x7x_als_cal_target_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ chip->tsl2x7x_settings.als_cal_target);
+}
+
+static ssize_t tsl2x7x_als_cal_target_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ unsigned long value;
+
+ if (kstrtoul(buf, 0, &value))
+ return -EINVAL;
+
+ if (value)
+ chip->tsl2x7x_settings.als_cal_target = value;
+
+ tsl2x7x_invoke_change(indio_dev);
+
+ return len;
+}
+
+/* persistence settings */
+static ssize_t tsl2x7x_als_persistence_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+ int y, z, filter_delay;
+
+ /* Determine integration time */
+ y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1;
+ z = y * TSL2X7X_MIN_ITIME;
+ filter_delay = z * (chip->tsl2x7x_settings.persistence & 0x0F);
+ y = (filter_delay / 1000);
+ z = (filter_delay % 1000);
+
+ return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z);
+}
+
+static ssize_t tsl2x7x_als_persistence_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ struct tsl2x7x_parse_result result;
+ int y, z, filter_delay;
+
+ result.integer = 0;
+ result.fract = 0;
+ tsl2x7x_parse_buffer(buf, &result);
+
+ result.fract /= 1000;
+ y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1;
+ z = y * TSL2X7X_MIN_ITIME;
+
+ filter_delay =
+ DIV_ROUND_UP(((result.integer * 1000) + result.fract), z);
+
+ chip->tsl2x7x_settings.persistence &= 0xF0;
+ chip->tsl2x7x_settings.persistence |= (filter_delay & 0x0F);
+
+ dev_info(&chip->client->dev, "%s: als persistence = %d",
+ __func__, filter_delay);
+
+ tsl2x7x_invoke_change(indio_dev);
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static ssize_t tsl2x7x_prox_persistence_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+ int y, z, filter_delay;
+
+ /* Determine integration time */
+ y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.prx_time) + 1;
+ z = y * TSL2X7X_MIN_ITIME;
+ filter_delay = z * ((chip->tsl2x7x_settings.persistence & 0xF0) >> 4);
+ y = (filter_delay / 1000);
+ z = (filter_delay % 1000);
+
+ return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z);
+}
+
+static ssize_t tsl2x7x_prox_persistence_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ struct tsl2x7x_parse_result result;
+ int y, z, filter_delay;
+
+ result.integer = 0;
+ result.fract = 0;
+ tsl2x7x_parse_buffer(buf, &result);
+
+ result.fract /= 1000;
+ y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.prx_time) + 1;
+ z = y * TSL2X7X_MIN_ITIME;
+
+ filter_delay =
+ DIV_ROUND_UP(((result.integer * 1000) + result.fract), z);
+
+ chip->tsl2x7x_settings.persistence &= 0x0F;
+ chip->tsl2x7x_settings.persistence |= ((filter_delay << 4) & 0xF0);
+
+ dev_info(&chip->client->dev, "%s: prox persistence = %d",
+ __func__, filter_delay);
+
+ tsl2x7x_invoke_change(indio_dev);
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static ssize_t tsl2x7x_do_calibrate(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ bool value;
+
+ if (strtobool(buf, &value))
+ return -EINVAL;
+
+ if (value)
+ tsl2x7x_als_calibrate(indio_dev);
+
+ tsl2x7x_invoke_change(indio_dev);
+
+ return len;
+}
+
+static ssize_t tsl2x7x_luxtable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsl2X7X_chip *chip = iio_priv(dev_to_iio_dev(dev));
+ int i = 0;
+ int offset = 0;
+
+ while (i < (TSL2X7X_MAX_LUX_TABLE_SIZE * 3)) {
+ offset += snprintf(buf + offset, PAGE_SIZE, "%d,%d,%d,",
+ chip->tsl2x7x_device_lux[i].ratio,
+ chip->tsl2x7x_device_lux[i].ch0,
+ chip->tsl2x7x_device_lux[i].ch1);
+ if (chip->tsl2x7x_device_lux[i].ratio == 0) {
+ /* We just printed the first "0" entry.
+ * Now get rid of the extra "," and break. */
+ offset--;
+ break;
+ }
+ i++;
+ }
+
+ offset += snprintf(buf + offset, PAGE_SIZE, "\n");
+ return offset;
+}
+
+static ssize_t tsl2x7x_luxtable_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ int value[ARRAY_SIZE(chip->tsl2x7x_device_lux)*3 + 1];
+ int n;
+
+ get_options(buf, ARRAY_SIZE(value), value);
+
+ /* We now have an array of ints starting at value[1], and
+ * enumerated by value[0].
+ * We expect each group of three ints is one table entry,
+ * and the last table entry is all 0.
+ */
+ n = value[0];
+ if ((n % 3) || n < 6 ||
+ n > ((ARRAY_SIZE(chip->tsl2x7x_device_lux) - 1) * 3)) {
+ dev_info(dev, "LUX TABLE INPUT ERROR 1 Value[0]=%d\n", n);
+ return -EINVAL;
+ }
+
+ if ((value[(n - 2)] | value[(n - 1)] | value[n]) != 0) {
+ dev_info(dev, "LUX TABLE INPUT ERROR 2 Value[0]=%d\n", n);
+ return -EINVAL;
+ }
+
+ if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING)
+ tsl2x7x_chip_off(indio_dev);
+
+ /* Zero out the table */
+ memset(chip->tsl2x7x_device_lux, 0, sizeof(chip->tsl2x7x_device_lux));
+ memcpy(chip->tsl2x7x_device_lux, &value[1], (value[0] * 4));
+
+ tsl2x7x_invoke_change(indio_dev);
+
+ return len;
+}
+
+static ssize_t tsl2x7x_do_prox_calibrate(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ bool value;
+
+ if (strtobool(buf, &value))
+ return -EINVAL;
+
+ if (value)
+ tsl2x7x_prox_cal(indio_dev);
+
+ tsl2x7x_invoke_change(indio_dev);
+
+ return len;
+}
+
+static int tsl2x7x_read_interrupt_config(struct iio_dev *indio_dev,
+ u64 event_code)
+{
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ int ret;
+
+ if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY)
+ ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x10);
+ else
+ ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x20);
+
+ return ret;
+}
+
+static int tsl2x7x_write_interrupt_config(struct iio_dev *indio_dev,
+ u64 event_code,
+ int val)
+{
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+ if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY) {
+ if (val)
+ chip->tsl2x7x_settings.interrupts_en |= 0x10;
+ else
+ chip->tsl2x7x_settings.interrupts_en &= 0x20;
+ } else {
+ if (val)
+ chip->tsl2x7x_settings.interrupts_en |= 0x20;
+ else
+ chip->tsl2x7x_settings.interrupts_en &= 0x10;
+ }
+
+ tsl2x7x_invoke_change(indio_dev);
+
+ return 0;
+}
+
+static int tsl2x7x_write_thresh(struct iio_dev *indio_dev,
+ u64 event_code,
+ int val)
+{
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+ if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY) {
+ switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
+ case IIO_EV_DIR_RISING:
+ chip->tsl2x7x_settings.als_thresh_high = val;
+ break;
+ case IIO_EV_DIR_FALLING:
+ chip->tsl2x7x_settings.als_thresh_low = val;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
+ case IIO_EV_DIR_RISING:
+ chip->tsl2x7x_settings.prox_thres_high = val;
+ break;
+ case IIO_EV_DIR_FALLING:
+ chip->tsl2x7x_settings.prox_thres_low = val;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ tsl2x7x_invoke_change(indio_dev);
+
+ return 0;
+}
+
+static int tsl2x7x_read_thresh(struct iio_dev *indio_dev,
+ u64 event_code,
+ int *val)
+{
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+ if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY) {
+ switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
+ case IIO_EV_DIR_RISING:
+ *val = chip->tsl2x7x_settings.als_thresh_high;
+ break;
+ case IIO_EV_DIR_FALLING:
+ *val = chip->tsl2x7x_settings.als_thresh_low;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
+ case IIO_EV_DIR_RISING:
+ *val = chip->tsl2x7x_settings.prox_thres_high;
+ break;
+ case IIO_EV_DIR_FALLING:
+ *val = chip->tsl2x7x_settings.prox_thres_low;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int tsl2x7x_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long mask)
+{
+ int ret = -EINVAL;
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ switch (chan->type) {
+ case IIO_LIGHT:
+ tsl2x7x_get_lux(indio_dev);
+ *val = chip->als_cur_info.lux;
+ ret = IIO_VAL_INT;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ break;
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->type) {
+ case IIO_INTENSITY:
+ tsl2x7x_get_lux(indio_dev);
+ if (chan->channel == 0)
+ *val = chip->als_cur_info.als_ch0;
+ else
+ *val = chip->als_cur_info.als_ch1;
+ ret = IIO_VAL_INT;
+ break;
+ case IIO_PROXIMITY:
+ tsl2x7x_get_prox(indio_dev);
+ *val = chip->prox_data;
+ ret = IIO_VAL_INT;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ break;
+ case IIO_CHAN_INFO_CALIBSCALE:
+ if (chan->type == IIO_LIGHT)
+ *val =
+ tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain];
+ else
+ *val =
+ tsl2X7X_prx_gainadj[chip->tsl2x7x_settings.prox_gain];
+ ret = IIO_VAL_INT;
+ break;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ *val = chip->tsl2x7x_settings.als_gain_trim;
+ ret = IIO_VAL_INT;
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int tsl2x7x_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask)
+{
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_CALIBSCALE:
+ if (chan->type == IIO_INTENSITY) {
+ switch (val) {
+ case 1:
+ chip->tsl2x7x_settings.als_gain = 0;
+ break;
+ case 8:
+ chip->tsl2x7x_settings.als_gain = 1;
+ break;
+ case 16:
+ chip->tsl2x7x_settings.als_gain = 2;
+ break;
+ case 120:
+ switch (chip->id) {
+ case tsl2572:
+ case tsl2672:
+ case tmd2672:
+ case tsl2772:
+ case tmd2772:
+ return -EINVAL;
+ break;
+ }
+ chip->tsl2x7x_settings.als_gain = 3;
+ break;
+ case 128:
+ switch (chip->id) {
+ case tsl2571:
+ case tsl2671:
+ case tmd2671:
+ case tsl2771:
+ case tmd2771:
+ return -EINVAL;
+ break;
+ }
+ chip->tsl2x7x_settings.als_gain = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ switch (val) {
+ case 1:
+ chip->tsl2x7x_settings.prox_gain = 0;
+ break;
+ case 2:
+ chip->tsl2x7x_settings.prox_gain = 1;
+ break;
+ case 4:
+ chip->tsl2x7x_settings.prox_gain = 2;
+ break;
+ case 8:
+ chip->tsl2x7x_settings.prox_gain = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ break;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ chip->tsl2x7x_settings.als_gain_trim = val;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ tsl2x7x_invoke_change(indio_dev);
+
+ return 0;
+}
+
+static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR,
+ tsl2x7x_power_state_show, tsl2x7x_power_state_store);
+
+static DEVICE_ATTR(in_proximity0_calibscale_available, S_IRUGO,
+ tsl2x7x_prox_gain_available_show, NULL);
+
+static DEVICE_ATTR(in_illuminance0_calibscale_available, S_IRUGO,
+ tsl2x7x_gain_available_show, NULL);
+
+static DEVICE_ATTR(in_illuminance0_integration_time, S_IRUGO | S_IWUSR,
+ tsl2x7x_als_time_show, tsl2x7x_als_time_store);
+
+static DEVICE_ATTR(in_illuminance0_target_input, S_IRUGO | S_IWUSR,
+ tsl2x7x_als_cal_target_show, tsl2x7x_als_cal_target_store);
+
+static DEVICE_ATTR(in_illuminance0_calibrate, S_IWUSR, NULL,
+ tsl2x7x_do_calibrate);
+
+static DEVICE_ATTR(in_proximity0_calibrate, S_IWUSR, NULL,
+ tsl2x7x_do_prox_calibrate);
+
+static DEVICE_ATTR(in_illuminance0_lux_table, S_IRUGO | S_IWUSR,
+ tsl2x7x_luxtable_show, tsl2x7x_luxtable_store);
+
+static DEVICE_ATTR(in_intensity0_thresh_period, S_IRUGO | S_IWUSR,
+ tsl2x7x_als_persistence_show, tsl2x7x_als_persistence_store);
+
+static DEVICE_ATTR(in_proximity0_thresh_period, S_IRUGO | S_IWUSR,
+ tsl2x7x_prox_persistence_show, tsl2x7x_prox_persistence_store);
+
+/* Use the default register values to identify the Taos device */
+static int tsl2x7x_device_id(unsigned char *id, int target)
+{
+ switch (target) {
+ case tsl2571:
+ case tsl2671:
+ case tsl2771:
+ return ((*id & 0xf0) == TRITON_ID);
+ break;
+ case tmd2671:
+ case tmd2771:
+ return ((*id & 0xf0) == HALIBUT_ID);
+ break;
+ case tsl2572:
+ case tsl2672:
+ case tmd2672:
+ case tsl2772:
+ case tmd2772:
+ return ((*id & 0xf0) == SWORDFISH_ID);
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static irqreturn_t tsl2x7x_event_handler(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ s64 timestamp = iio_get_time_ns();
+ int ret;
+ u8 value;
+
+ value = i2c_smbus_read_byte_data(chip->client,
+ TSL2X7X_CMD_REG | TSL2X7X_STATUS);
+
+ /* What type of interrupt do we need to process */
+ if (value & TSL2X7X_STA_PRX_INTR) {
+ tsl2x7x_get_prox(indio_dev); /* freshen data for ABI */
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY,
+ 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_EITHER),
+ timestamp);
+ }
+
+ if (value & TSL2X7X_STA_ALS_INTR) {
+ tsl2x7x_get_lux(indio_dev); /* freshen data for ABI */
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
+ 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_EITHER),
+ timestamp);
+ }
+ /* Clear interrupt now that we have handled it. */
+ ret = i2c_smbus_write_byte(chip->client,
+ TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN |
+ TSL2X7X_CMD_PROXALS_INT_CLR);
+ if (ret < 0)
+ dev_err(&chip->client->dev,
+ "%s: Failed to clear irq from event handler. err = %d\n",
+ __func__, ret);
+
+ return IRQ_HANDLED;
+}
+
+static struct attribute *tsl2x7x_ALS_device_attrs[] = {
+ &dev_attr_power_state.attr,
+ &dev_attr_in_illuminance0_calibscale_available.attr,
+ &dev_attr_in_illuminance0_integration_time.attr,
+ &iio_const_attr_in_illuminance0_integration_time_available\
+ .dev_attr.attr,
+ &dev_attr_in_illuminance0_target_input.attr,
+ &dev_attr_in_illuminance0_calibrate.attr,
+ &dev_attr_in_illuminance0_lux_table.attr,
+ NULL
+};
+
+static struct attribute *tsl2x7x_PRX_device_attrs[] = {
+ &dev_attr_power_state.attr,
+ &dev_attr_in_proximity0_calibrate.attr,
+ NULL
+};
+
+static struct attribute *tsl2x7x_ALSPRX_device_attrs[] = {
+ &dev_attr_power_state.attr,
+ &dev_attr_in_illuminance0_calibscale_available.attr,
+ &dev_attr_in_illuminance0_integration_time.attr,
+ &iio_const_attr_in_illuminance0_integration_time_available\
+ .dev_attr.attr,
+ &dev_attr_in_illuminance0_target_input.attr,
+ &dev_attr_in_illuminance0_calibrate.attr,
+ &dev_attr_in_illuminance0_lux_table.attr,
+ &dev_attr_in_proximity0_calibrate.attr,
+ NULL
+};
+
+static struct attribute *tsl2x7x_PRX2_device_attrs[] = {
+ &dev_attr_power_state.attr,
+ &dev_attr_in_proximity0_calibrate.attr,
+ &dev_attr_in_proximity0_calibscale_available.attr,
+ NULL
+};
+
+static struct attribute *tsl2x7x_ALSPRX2_device_attrs[] = {
+ &dev_attr_power_state.attr,
+ &dev_attr_in_illuminance0_calibscale_available.attr,
+ &dev_attr_in_illuminance0_integration_time.attr,
+ &iio_const_attr_in_illuminance0_integration_time_available\
+ .dev_attr.attr,
+ &dev_attr_in_illuminance0_target_input.attr,
+ &dev_attr_in_illuminance0_calibrate.attr,
+ &dev_attr_in_illuminance0_lux_table.attr,
+ &dev_attr_in_proximity0_calibrate.attr,
+ &dev_attr_in_proximity0_calibscale_available.attr,
+ NULL
+};
+
+static struct attribute *tsl2X7X_ALS_event_attrs[] = {
+ &dev_attr_in_intensity0_thresh_period.attr,
+ NULL,
+};
+static struct attribute *tsl2X7X_PRX_event_attrs[] = {
+ &dev_attr_in_proximity0_thresh_period.attr,
+ NULL,
+};
+
+static struct attribute *tsl2X7X_ALSPRX_event_attrs[] = {
+ &dev_attr_in_intensity0_thresh_period.attr,
+ &dev_attr_in_proximity0_thresh_period.attr,
+ NULL,
+};
+
+static const struct attribute_group tsl2X7X_device_attr_group_tbl[] = {
+ [ALS] = {
+ .attrs = tsl2x7x_ALS_device_attrs,
+ },
+ [PRX] = {
+ .attrs = tsl2x7x_PRX_device_attrs,
+ },
+ [ALSPRX] = {
+ .attrs = tsl2x7x_ALSPRX_device_attrs,
+ },
+ [PRX2] = {
+ .attrs = tsl2x7x_PRX2_device_attrs,
+ },
+ [ALSPRX2] = {
+ .attrs = tsl2x7x_ALSPRX2_device_attrs,
+ },
+};
+
+static struct attribute_group tsl2X7X_event_attr_group_tbl[] = {
+ [ALS] = {
+ .attrs = tsl2X7X_ALS_event_attrs,
+ .name = "events",
+ },
+ [PRX] = {
+ .attrs = tsl2X7X_PRX_event_attrs,
+ .name = "events",
+ },
+ [ALSPRX] = {
+ .attrs = tsl2X7X_ALSPRX_event_attrs,
+ .name = "events",
+ },
+};
+
+static const struct iio_info tsl2X7X_device_info[] = {
+ [ALS] = {
+ .attrs = &tsl2X7X_device_attr_group_tbl[ALS],
+ .event_attrs = &tsl2X7X_event_attr_group_tbl[ALS],
+ .driver_module = THIS_MODULE,
+ .read_raw = &tsl2x7x_read_raw,
+ .write_raw = &tsl2x7x_write_raw,
+ .read_event_value = &tsl2x7x_read_thresh,
+ .write_event_value = &tsl2x7x_write_thresh,
+ .read_event_config = &tsl2x7x_read_interrupt_config,
+ .write_event_config = &tsl2x7x_write_interrupt_config,
+ },
+ [PRX] = {
+ .attrs = &tsl2X7X_device_attr_group_tbl[PRX],
+ .event_attrs = &tsl2X7X_event_attr_group_tbl[PRX],
+ .driver_module = THIS_MODULE,
+ .read_raw = &tsl2x7x_read_raw,
+ .write_raw = &tsl2x7x_write_raw,
+ .read_event_value = &tsl2x7x_read_thresh,
+ .write_event_value = &tsl2x7x_write_thresh,
+ .read_event_config = &tsl2x7x_read_interrupt_config,
+ .write_event_config = &tsl2x7x_write_interrupt_config,
+ },
+ [ALSPRX] = {
+ .attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX],
+ .event_attrs = &tsl2X7X_event_attr_group_tbl[ALSPRX],
+ .driver_module = THIS_MODULE,
+ .read_raw = &tsl2x7x_read_raw,
+ .write_raw = &tsl2x7x_write_raw,
+ .read_event_value = &tsl2x7x_read_thresh,
+ .write_event_value = &tsl2x7x_write_thresh,
+ .read_event_config = &tsl2x7x_read_interrupt_config,
+ .write_event_config = &tsl2x7x_write_interrupt_config,
+ },
+ [PRX2] = {
+ .attrs = &tsl2X7X_device_attr_group_tbl[PRX2],
+ .event_attrs = &tsl2X7X_event_attr_group_tbl[PRX],
+ .driver_module = THIS_MODULE,
+ .read_raw = &tsl2x7x_read_raw,
+ .write_raw = &tsl2x7x_write_raw,
+ .read_event_value = &tsl2x7x_read_thresh,
+ .write_event_value = &tsl2x7x_write_thresh,
+ .read_event_config = &tsl2x7x_read_interrupt_config,
+ .write_event_config = &tsl2x7x_write_interrupt_config,
+ },
+ [ALSPRX2] = {
+ .attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX2],
+ .event_attrs = &tsl2X7X_event_attr_group_tbl[ALSPRX],
+ .driver_module = THIS_MODULE,
+ .read_raw = &tsl2x7x_read_raw,
+ .write_raw = &tsl2x7x_write_raw,
+ .read_event_value = &tsl2x7x_read_thresh,
+ .write_event_value = &tsl2x7x_write_thresh,
+ .read_event_config = &tsl2x7x_read_interrupt_config,
+ .write_event_config = &tsl2x7x_write_interrupt_config,
+ },
+};
+
+static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
+ [ALS] = {
+ .channel = {
+ {
+ .type = IIO_LIGHT,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
+ }, {
+ .type = IIO_INTENSITY,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+ .event_mask = TSL2X7X_EVENT_MASK
+ }, {
+ .type = IIO_INTENSITY,
+ .indexed = 1,
+ .channel = 1,
+ },
+ },
+ .chan_table_elements = 3,
+ .info = &tsl2X7X_device_info[ALS],
+ },
+ [PRX] = {
+ .channel = {
+ {
+ .type = IIO_PROXIMITY,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .event_mask = TSL2X7X_EVENT_MASK
+ },
+ },
+ .chan_table_elements = 1,
+ .info = &tsl2X7X_device_info[PRX],
+ },
+ [ALSPRX] = {
+ .channel = {
+ {
+ .type = IIO_LIGHT,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT
+ }, {
+ .type = IIO_INTENSITY,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+ .event_mask = TSL2X7X_EVENT_MASK
+ }, {
+ .type = IIO_INTENSITY,
+ .indexed = 1,
+ .channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ }, {
+ .type = IIO_PROXIMITY,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ .event_mask = TSL2X7X_EVENT_MASK
+ },
+ },
+ .chan_table_elements = 4,
+ .info = &tsl2X7X_device_info[ALSPRX],
+ },
+ [PRX2] = {
+ .channel = {
+ {
+ .type = IIO_PROXIMITY,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
+ .event_mask = TSL2X7X_EVENT_MASK
+ },
+ },
+ .chan_table_elements = 1,
+ .info = &tsl2X7X_device_info[PRX2],
+ },
+ [ALSPRX2] = {
+ .channel = {
+ {
+ .type = IIO_LIGHT,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
+ }, {
+ .type = IIO_INTENSITY,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
+ .event_mask = TSL2X7X_EVENT_MASK
+ }, {
+ .type = IIO_INTENSITY,
+ .indexed = 1,
+ .channel = 1,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
+ }, {
+ .type = IIO_PROXIMITY,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
+ .event_mask = TSL2X7X_EVENT_MASK
+ },
+ },
+ .chan_table_elements = 4,
+ .info = &tsl2X7X_device_info[ALSPRX2],
+ },
+};
+
+static int __devinit tsl2x7x_probe(struct i2c_client *clientp,
+ const struct i2c_device_id *id)
+{
+ int ret;
+ unsigned char device_id;
+ struct iio_dev *indio_dev;
+ struct tsl2X7X_chip *chip;
+
+ indio_dev = iio_device_alloc(sizeof(*chip));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ chip = iio_priv(indio_dev);
+ chip->client = clientp;
+ i2c_set_clientdata(clientp, indio_dev);
+
+ ret = tsl2x7x_i2c_read(chip->client,
+ TSL2X7X_CHIPID, &device_id);
+ if (ret < 0)
+ goto fail1;
+
+ if ((!tsl2x7x_device_id(&device_id, id->driver_data)) ||
+ (tsl2x7x_device_id(&device_id, id->driver_data) == -EINVAL)) {
+ dev_info(&chip->client->dev,
+ "%s: i2c device found does not match expected id\n",
+ __func__);
+ goto fail1;
+ }
+
+ ret = i2c_smbus_write_byte(clientp, (TSL2X7X_CMD_REG | TSL2X7X_CNTRL));
+ if (ret < 0) {
+ dev_err(&clientp->dev, "%s: write to cmd reg failed. err = %d\n",
+ __func__, ret);
+ goto fail1;
+ }
+
+ /* ALS and PROX functions can be invoked via user space poll
+ * or H/W interrupt. If busy return last sample. */
+ mutex_init(&chip->als_mutex);
+ mutex_init(&chip->prox_mutex);
+
+ chip->tsl2x7x_chip_status = TSL2X7X_CHIP_UNKNOWN;
+ chip->pdata = clientp->dev.platform_data;
+ chip->id = id->driver_data;
+ chip->chip_info =
+ &tsl2x7x_chip_info_tbl[device_channel_config[id->driver_data]];
+
+ indio_dev->info = chip->chip_info->info;
+ indio_dev->dev.parent = &clientp->dev;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->name = chip->client->name;
+ indio_dev->channels = chip->chip_info->channel;
+ indio_dev->num_channels = chip->chip_info->chan_table_elements;
+
+ if (clientp->irq) {
+ ret = request_threaded_irq(clientp->irq,
+ NULL,
+ &tsl2x7x_event_handler,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "TSL2X7X_event",
+ indio_dev);
+ if (ret) {
+ dev_err(&clientp->dev,
+ "%s: irq request failed", __func__);
+ goto fail2;
+ }
+ }
+
+ /* Load up the defaults */
+ tsl2x7x_defaults(chip);
+ /* Make sure the chip is on */
+ tsl2x7x_chip_on(indio_dev);
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&clientp->dev,
+ "%s: iio registration failed\n", __func__);
+ goto fail1;
+ }
+
+ dev_info(&clientp->dev, "%s Light sensor found.\n", id->name);
+
+ return 0;
+
+fail1:
+ if (clientp->irq)
+ free_irq(clientp->irq, indio_dev);
+fail2:
+ iio_device_free(indio_dev);
+
+ return ret;
+}
+
+static int tsl2x7x_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ int ret = 0;
+
+ if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) {
+ ret = tsl2x7x_chip_off(indio_dev);
+ chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED;
+ }
+
+ if (chip->pdata && chip->pdata->platform_power) {
+ pm_message_t pmm = {PM_EVENT_SUSPEND};
+ chip->pdata->platform_power(dev, pmm);
+ }
+
+ return ret;
+}
+
+static int tsl2x7x_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct tsl2X7X_chip *chip = iio_priv(indio_dev);
+ int ret = 0;
+
+ if (chip->pdata && chip->pdata->platform_power) {
+ pm_message_t pmm = {PM_EVENT_RESUME};
+ chip->pdata->platform_power(dev, pmm);
+ }
+
+ if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_SUSPENDED)
+ ret = tsl2x7x_chip_on(indio_dev);
+
+ return ret;
+}
+
+static int __devexit tsl2x7x_remove(struct i2c_client *client)
+{
+ struct tsl2X7X_chip *chip = i2c_get_clientdata(client);
+ struct iio_dev *indio_dev = iio_priv_to_dev(chip);
+
+ tsl2x7x_chip_off(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ if (client->irq)
+ free_irq(client->irq, chip->client->name);
+
+ iio_device_free(indio_dev);
+
+ return 0;
+}
+
+static struct i2c_device_id tsl2x7x_idtable[] = {
+ { "tsl2571", tsl2571 },
+ { "tsl2671", tsl2671 },
+ { "tmd2671", tmd2671 },
+ { "tsl2771", tsl2771 },
+ { "tmd2771", tmd2771 },
+ { "tsl2572", tsl2572 },
+ { "tsl2672", tsl2672 },
+ { "tmd2672", tmd2672 },
+ { "tsl2772", tsl2772 },
+ { "tmd2772", tmd2772 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, tsl2x7x_idtable);
+
+static const struct dev_pm_ops tsl2x7x_pm_ops = {
+ .suspend = tsl2x7x_suspend,
+ .resume = tsl2x7x_resume,
+};
+
+/* Driver definition */
+static struct i2c_driver tsl2x7x_driver = {
+ .driver = {
+ .name = "tsl2x7x",
+ .pm = &tsl2x7x_pm_ops,
+ },
+ .id_table = tsl2x7x_idtable,
+ .probe = tsl2x7x_probe,
+ .remove = __devexit_p(tsl2x7x_remove),
+};
+
+module_i2c_driver(tsl2x7x_driver);
+
+MODULE_AUTHOR("J. August Brenner<jbrenner@taosinc.com>");
+MODULE_DESCRIPTION("TAOS tsl2x7x ambient and proximity light sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/magnetometer/Kconfig b/drivers/staging/iio/magnetometer/Kconfig
index 722c4e13f713..b9d932595ba9 100644
--- a/drivers/staging/iio/magnetometer/Kconfig
+++ b/drivers/staging/iio/magnetometer/Kconfig
@@ -15,13 +15,13 @@ config SENSORS_AK8975
will be called ak8975.
config SENSORS_HMC5843
- tristate "Honeywell HMC5843 3-Axis Magnetometer"
+ tristate "Honeywell HMC5843/5883/5883L 3-Axis Magnetometer"
depends on I2C
help
- Say Y here to add support for the Honeywell HMC 5843 3-Axis
- Magnetometer (digital compass).
+ Say Y here to add support for the Honeywell HMC5843, HMC5883 and
+ HMC5883L 3-Axis Magnetometer (digital compass).
To compile this driver as a module, choose M here: the module
- will be called hmc5843
+ will be called hmc5843.
endmenu
diff --git a/drivers/staging/iio/magnetometer/ak8975.c b/drivers/staging/iio/magnetometer/ak8975.c
index ebc2d0840caf..5834e4a70f8c 100644
--- a/drivers/staging/iio/magnetometer/ak8975.c
+++ b/drivers/staging/iio/magnetometer/ak8975.c
@@ -30,8 +30,8 @@
#include <linux/gpio.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
/*
* Register definitions, as well as various shifts and masks to get at the
* individual fields of the registers.
@@ -242,7 +242,7 @@ static int ak8975_setup(struct i2c_client *client)
static ssize_t show_mode(struct device *dev, struct device_attribute *devattr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ak8975_data *data = iio_priv(indio_dev);
return sprintf(buf, "%u\n", data->mode);
@@ -255,7 +255,7 @@ static ssize_t show_mode(struct device *dev, struct device_attribute *devattr,
static ssize_t store_mode(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ak8975_data *data = iio_priv(indio_dev);
struct i2c_client *client = data->client;
bool value;
@@ -431,7 +431,7 @@ static int ak8975_read_raw(struct iio_dev *indio_dev,
struct ak8975_data *data = iio_priv(indio_dev);
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
return ak8975_read_axis(indio_dev, chan->address, val);
case IIO_CHAN_INFO_SCALE:
*val = data->raw_to_gauss[chan->address];
@@ -445,7 +445,8 @@ static int ak8975_read_raw(struct iio_dev *indio_dev,
.type = IIO_MAGN, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
- .info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
.address = index, \
}
@@ -505,7 +506,7 @@ static int ak8975_probe(struct i2c_client *client,
}
/* Register with IIO */
- indio_dev = iio_allocate_device(sizeof(*data));
+ indio_dev = iio_device_alloc(sizeof(*data));
if (indio_dev == NULL) {
err = -ENOMEM;
goto exit_gpio;
@@ -536,7 +537,7 @@ static int ak8975_probe(struct i2c_client *client,
return 0;
exit_free_iio:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
exit_gpio:
if (gpio_is_valid(eoc_gpio))
gpio_free(eoc_gpio);
@@ -554,7 +555,7 @@ static int ak8975_remove(struct i2c_client *client)
if (gpio_is_valid(data->eoc_gpio))
gpio_free(data->eoc_gpio);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/magnetometer/hmc5843.c b/drivers/staging/iio/magnetometer/hmc5843.c
index e00b416c4d33..c1fa09f07625 100644
--- a/drivers/staging/iio/magnetometer/hmc5843.c
+++ b/drivers/staging/iio/magnetometer/hmc5843.c
@@ -2,6 +2,8 @@
Author: Shubhrajyoti Datta <shubhrajyoti@ti.com>
Acknowledgement: Jonathan Cameron <jic23@cam.ac.uk> for valuable inputs.
+ Support for HMC5883 and HMC5883L by Peter Meerwald <pmeerw@pmeerw.net>.
+
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
@@ -22,10 +24,8 @@
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/types.h>
-#include "../iio.h"
-#include "../sysfs.h"
-
-#define HMC5843_I2C_ADDRESS 0x1E
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#define HMC5843_CONFIG_REG_A 0x00
#define HMC5843_CONFIG_REG_B 0x01
@@ -36,110 +36,185 @@
#define HMC5843_DATA_OUT_Y_LSB_REG 0x06
#define HMC5843_DATA_OUT_Z_MSB_REG 0x07
#define HMC5843_DATA_OUT_Z_LSB_REG 0x08
+/* Beware: Y and Z are exchanged on HMC5883 */
+#define HMC5883_DATA_OUT_Z_MSB_REG 0x05
+#define HMC5883_DATA_OUT_Z_LSB_REG 0x06
+#define HMC5883_DATA_OUT_Y_MSB_REG 0x07
+#define HMC5883_DATA_OUT_Y_LSB_REG 0x08
#define HMC5843_STATUS_REG 0x09
#define HMC5843_ID_REG_A 0x0A
#define HMC5843_ID_REG_B 0x0B
#define HMC5843_ID_REG_C 0x0C
+enum hmc5843_ids {
+ HMC5843_ID,
+ HMC5883_ID,
+ HMC5883L_ID,
+};
+
+/*
+ * Beware: identification of the HMC5883 is still "H43";
+ * I2C address is also unchanged
+ */
#define HMC5843_ID_REG_LENGTH 0x03
#define HMC5843_ID_STRING "H43"
+#define HMC5843_I2C_ADDRESS 0x1E
/*
- * Range settings in (+-)Ga
- * */
-#define RANGE_GAIN_OFFSET 0x05
-
-#define RANGE_0_7 0x00
-#define RANGE_1_0 0x01 /* default */
-#define RANGE_1_5 0x02
-#define RANGE_2_0 0x03
-#define RANGE_3_2 0x04
-#define RANGE_3_8 0x05
-#define RANGE_4_5 0x06
-#define RANGE_6_5 0x07 /* Not recommended */
+ * Range gain settings in (+-)Ga
+ * Beware: HMC5843 and HMC5883 have different recommended sensor field
+ * ranges; default corresponds to +-1.0 Ga and +-1.3 Ga, respectively
+ */
+#define HMC5843_RANGE_GAIN_OFFSET 0x05
+#define HMC5843_RANGE_GAIN_DEFAULT 0x01
+#define HMC5843_RANGE_GAIN_MAX 0x07
/*
* Device status
*/
-#define DATA_READY 0x01
-#define DATA_OUTPUT_LOCK 0x02
-#define VOLTAGE_REGULATOR_ENABLED 0x04
+#define HMC5843_DATA_READY 0x01
+#define HMC5843_DATA_OUTPUT_LOCK 0x02
+/* Does not exist on HMC5883, not used */
+#define HMC5843_VOLTAGE_REGULATOR_ENABLED 0x04
/*
* Mode register configuration
*/
-#define MODE_CONVERSION_CONTINUOUS 0x00
-#define MODE_CONVERSION_SINGLE 0x01
-#define MODE_IDLE 0x02
-#define MODE_SLEEP 0x03
-
-/* Minimum Data Output Rate in 1/10 Hz */
-#define RATE_OFFSET 0x02
-#define RATE_BITMASK 0x1C
-#define RATE_5 0x00
-#define RATE_10 0x01
-#define RATE_20 0x02
-#define RATE_50 0x03
-#define RATE_100 0x04
-#define RATE_200 0x05
-#define RATE_500 0x06
-#define RATE_NOT_USED 0x07
+#define HMC5843_MODE_CONVERSION_CONTINUOUS 0x00
+#define HMC5843_MODE_CONVERSION_SINGLE 0x01
+#define HMC5843_MODE_IDLE 0x02
+#define HMC5843_MODE_SLEEP 0x03
+#define HMC5843_MODE_MASK 0x03
+
+/*
+ * HMC5843: Minimum data output rate
+ * HMC5883: Typical data output rate
+ */
+#define HMC5843_RATE_OFFSET 0x02
+#define HMC5843_RATE_BITMASK 0x1C
+#define HMC5843_RATE_NOT_USED 0x07
/*
- * Device Configuration
+ * Device measurement configuration
*/
-#define CONF_NORMAL 0x00
-#define CONF_POSITIVE_BIAS 0x01
-#define CONF_NEGATIVE_BIAS 0x02
-#define CONF_NOT_USED 0x03
-#define MEAS_CONF_MASK 0x03
+#define HMC5843_MEAS_CONF_NORMAL 0x00
+#define HMC5843_MEAS_CONF_POSITIVE_BIAS 0x01
+#define HMC5843_MEAS_CONF_NEGATIVE_BIAS 0x02
+#define HMC5843_MEAS_CONF_NOT_USED 0x03
+#define HMC5843_MEAS_CONF_MASK 0x03
-static int hmc5843_regval_to_nanoscale[] = {
+/*
+ * Scaling factors: 10000000/Gain
+ */
+static const int hmc5843_regval_to_nanoscale[] = {
6173, 7692, 10309, 12821, 18868, 21739, 25641, 35714
};
-static const int regval_to_input_field_mg[] = {
- 700,
- 1000,
- 1500,
- 2000,
- 3200,
- 3800,
- 4500,
- 6500
+static const int hmc5883_regval_to_nanoscale[] = {
+ 7812, 9766, 13021, 16287, 24096, 27701, 32573, 45662
};
-static const char * const regval_to_samp_freq[] = {
- "0.5",
- "1",
- "2",
- "5",
- "10",
- "20",
- "50",
+
+static const int hmc5883l_regval_to_nanoscale[] = {
+ 7299, 9174, 12195, 15152, 22727, 25641, 30303, 43478
+};
+
+/*
+ * From the HMC5843 datasheet:
+ * Value | Sensor input field range (Ga) | Gain (counts/milli-Gauss)
+ * 0 | (+-)0.7 | 1620
+ * 1 | (+-)1.0 | 1300
+ * 2 | (+-)1.5 | 970
+ * 3 | (+-)2.0 | 780
+ * 4 | (+-)3.2 | 530
+ * 5 | (+-)3.8 | 460
+ * 6 | (+-)4.5 | 390
+ * 7 | (+-)6.5 | 280
+ *
+ * From the HMC5883 datasheet:
+ * Value | Recommended sensor field range (Ga) | Gain (counts/Gauss)
+ * 0 | (+-)0.9 | 1280
+ * 1 | (+-)1.2 | 1024
+ * 2 | (+-)1.9 | 768
+ * 3 | (+-)2.5 | 614
+ * 4 | (+-)4.0 | 415
+ * 5 | (+-)4.6 | 361
+ * 6 | (+-)5.5 | 307
+ * 7 | (+-)7.9 | 219
+ *
+ * From the HMC5883L datasheet:
+ * Value | Recommended sensor field range (Ga) | Gain (LSB/Gauss)
+ * 0 | (+-)0.88 | 1370
+ * 1 | (+-)1.3 | 1090
+ * 2 | (+-)1.9 | 820
+ * 3 | (+-)2.5 | 660
+ * 4 | (+-)4.0 | 440
+ * 5 | (+-)4.7 | 390
+ * 6 | (+-)5.6 | 330
+ * 7 | (+-)8.1 | 230
+ */
+static const int hmc5843_regval_to_input_field_mga[] = {
+ 700, 1000, 1500, 2000, 3200, 3800, 4500, 6500
+};
+
+static const int hmc5883_regval_to_input_field_mga[] = {
+ 900, 1200, 1900, 2500, 4000, 4600, 5500, 7900
+};
+
+static const int hmc5883l_regval_to_input_field_mga[] = {
+ 880, 1300, 1900, 2500, 4000, 4700, 5600, 8100
+};
+
+/*
+ * From the datasheet:
+ * Value | HMC5843 | HMC5883/HMC5883L
+ * | Data output rate (Hz) | Data output rate (Hz)
+ * 0 | 0.5 | 0.75
+ * 1 | 1 | 1.5
+ * 2 | 2 | 3
+ * 3 | 5 | 7.5
+ * 4 | 10 (default) | 15
+ * 5 | 20 | 30
+ * 6 | 50 | 75
+ * 7 | Not used | Not used
+ */
+static const char * const hmc5843_regval_to_sample_freq[] = {
+ "0.5", "1", "2", "5", "10", "20", "50",
+};
+
+static const char * const hmc5883_regval_to_sample_freq[] = {
+ "0.75", "1.5", "3", "7.5", "15", "30", "75",
};
/* Addresses to scan: 0x1E */
static const unsigned short normal_i2c[] = { HMC5843_I2C_ADDRESS,
- I2C_CLIENT_END };
+ I2C_CLIENT_END };
+
+/* Describe chip variants */
+struct hmc5843_chip_info {
+ const struct iio_chan_spec *channels;
+ int num_channels;
+ const char * const *regval_to_sample_freq;
+ const int *regval_to_input_field_mga;
+ const int *regval_to_nanoscale;
+};
/* Each client has this additional data */
struct hmc5843_data {
struct mutex lock;
- u8 rate;
- u8 meas_conf;
- u8 operating_mode;
- u8 range;
+ u8 rate;
+ u8 meas_conf;
+ u8 operating_mode;
+ u8 range;
+ const struct hmc5843_chip_info *variant;
};
-static void hmc5843_init_client(struct i2c_client *client);
-
+/* The lower two bits contain the current conversion mode */
static s32 hmc5843_configure(struct i2c_client *client,
u8 operating_mode)
{
- /* The lower two bits contain the current conversion mode */
return i2c_smbus_write_byte_data(client,
HMC5843_MODE_REG,
- (operating_mode & 0x03));
+ operating_mode & HMC5843_MODE_MASK);
}
/* Return the measurement value from the specified channel */
@@ -153,7 +228,7 @@ static int hmc5843_read_measurement(struct iio_dev *indio_dev,
mutex_lock(&data->lock);
result = i2c_smbus_read_byte_data(client, HMC5843_STATUS_REG);
- while (!(result & DATA_READY))
+ while (!(result & HMC5843_DATA_READY))
result = i2c_smbus_read_byte_data(client, HMC5843_STATUS_REG);
result = i2c_smbus_read_word_data(client, address);
@@ -161,30 +236,29 @@ static int hmc5843_read_measurement(struct iio_dev *indio_dev,
if (result < 0)
return -EINVAL;
- *val = (s16)swab16((u16)result);
+ *val = (s16)swab16((u16)result);
return IIO_VAL_INT;
}
-
/*
- * From the datasheet
+ * From the datasheet:
* 0 - Continuous-Conversion Mode: In continuous-conversion mode, the
- * device continuously performs conversions and places the result in the
- * data register.
+ * device continuously performs conversions and places the result in
+ * the data register.
*
- * 1 - Single-Conversion Mode : device performs a single measurement,
- * sets RDY high and returned to sleep mode
+ * 1 - Single-Conversion Mode : Device performs a single measurement,
+ * sets RDY high and returns to sleep mode.
*
- * 2 - Idle Mode : Device is placed in idle mode.
+ * 2 - Idle Mode : Device is placed in idle mode.
*
- * 3 - Sleep Mode. Device is placed in sleep mode.
+ * 3 - Sleep Mode : Device is placed in sleep mode.
*
*/
static ssize_t hmc5843_show_operating_mode(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct hmc5843_data *data = iio_priv(indio_dev);
return sprintf(buf, "%d\n", data->operating_mode);
}
@@ -194,21 +268,22 @@ static ssize_t hmc5843_set_operating_mode(struct device *dev,
const char *buf,
size_t count)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
struct hmc5843_data *data = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
unsigned long operating_mode = 0;
s32 status;
int error;
+
mutex_lock(&data->lock);
- error = strict_strtoul(buf, 10, &operating_mode);
+ error = kstrtoul(buf, 10, &operating_mode);
if (error) {
count = error;
goto exit;
}
- dev_dbg(dev, "set Conversion mode to %lu\n", operating_mode);
- if (operating_mode > MODE_SLEEP) {
+ dev_dbg(dev, "set conversion mode to %lu\n", operating_mode);
+ if (operating_mode > HMC5843_MODE_SLEEP) {
count = -EINVAL;
goto exit;
}
@@ -225,6 +300,7 @@ exit:
mutex_unlock(&data->lock);
return count;
}
+
static IIO_DEVICE_ATTR(operating_mode,
S_IWUSR | S_IRUGO,
hmc5843_show_operating_mode,
@@ -234,25 +310,29 @@ static IIO_DEVICE_ATTR(operating_mode,
/*
* API for setting the measurement configuration to
* Normal, Positive bias and Negative bias
- * From the datasheet
*
- * Normal measurement configuration (default): In normal measurement
- * configuration the device follows normal measurement flow. Pins BP and BN
- * are left floating and high impedance.
+ * From the datasheet:
+ * 0 - Normal measurement configuration (default): In normal measurement
+ * configuration the device follows normal measurement flow. Pins BP
+ * and BN are left floating and high impedance.
*
- * Positive bias configuration: In positive bias configuration, a positive
- * current is forced across the resistive load on pins BP and BN.
+ * 1 - Positive bias configuration: In positive bias configuration, a
+ * positive current is forced across the resistive load on pins BP
+ * and BN.
*
- * Negative bias configuration. In negative bias configuration, a negative
- * current is forced across the resistive load on pins BP and BN.
+ * 2 - Negative bias configuration. In negative bias configuration, a
+ * negative current is forced across the resistive load on pins BP
+ * and BN.
*
*/
static s32 hmc5843_set_meas_conf(struct i2c_client *client,
u8 meas_conf)
{
- struct hmc5843_data *data = i2c_get_clientdata(client);
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct hmc5843_data *data = iio_priv(indio_dev);
u8 reg_val;
- reg_val = (meas_conf & MEAS_CONF_MASK) | (data->rate << RATE_OFFSET);
+ reg_val = (meas_conf & HMC5843_MEAS_CONF_MASK) |
+ (data->rate << HMC5843_RATE_OFFSET);
return i2c_smbus_write_byte_data(client, HMC5843_CONFIG_REG_A, reg_val);
}
@@ -260,7 +340,7 @@ static ssize_t hmc5843_show_measurement_configuration(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct hmc5843_data *data = iio_priv(indio_dev);
return sprintf(buf, "%d\n", data->meas_conf);
}
@@ -270,16 +350,20 @@ static ssize_t hmc5843_set_measurement_configuration(struct device *dev,
const char *buf,
size_t count)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
- struct hmc5843_data *data = i2c_get_clientdata(client);
+ struct hmc5843_data *data = iio_priv(indio_dev);
unsigned long meas_conf = 0;
- int error = strict_strtoul(buf, 10, &meas_conf);
+ int error;
+
+ error = kstrtoul(buf, 10, &meas_conf);
if (error)
return error;
- mutex_lock(&data->lock);
+ if (meas_conf >= HMC5843_MEAS_CONF_NOT_USED)
+ return -EINVAL;
- dev_dbg(dev, "set mode to %lu\n", meas_conf);
+ mutex_lock(&data->lock);
+ dev_dbg(dev, "set measurement configuration to %lu\n", meas_conf);
if (hmc5843_set_meas_conf(client, meas_conf)) {
count = -EINVAL;
goto exit;
@@ -290,71 +374,85 @@ exit:
mutex_unlock(&data->lock);
return count;
}
+
static IIO_DEVICE_ATTR(meas_conf,
S_IWUSR | S_IRUGO,
hmc5843_show_measurement_configuration,
hmc5843_set_measurement_configuration,
0);
-/*
- * From Datasheet
- * The table shows the minimum data output
- * Value | Minimum data output rate(Hz)
- * 0 | 0.5
- * 1 | 1
- * 2 | 2
- * 3 | 5
- * 4 | 10 (default)
- * 5 | 20
- * 6 | 50
- * 7 | Not used
- */
-static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("0.5 1 2 5 10 20 50");
+static ssize_t hmc5843_show_sampling_frequencies_available(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct hmc5843_data *data = iio_priv(indio_dev);
+ ssize_t total_n = 0;
+ int i;
+
+ for (i = 0; i < HMC5843_RATE_NOT_USED; i++) {
+ ssize_t n = sprintf(buf, "%s ", data->variant->regval_to_sample_freq[i]);
+ buf += n;
+ total_n += n;
+ }
+ /* replace trailing space by newline */
+ buf[-1] = '\n';
+
+ return total_n;
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(hmc5843_show_sampling_frequencies_available);
static s32 hmc5843_set_rate(struct i2c_client *client,
u8 rate)
{
- struct hmc5843_data *data = i2c_get_clientdata(client);
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct hmc5843_data *data = iio_priv(indio_dev);
u8 reg_val;
- reg_val = (data->meas_conf) | (rate << RATE_OFFSET);
- if (rate >= RATE_NOT_USED) {
+ if (rate >= HMC5843_RATE_NOT_USED) {
dev_err(&client->dev,
- "This data output rate is not supported\n");
+ "data output rate is not supported\n");
return -EINVAL;
}
+
+ reg_val = data->meas_conf | (rate << HMC5843_RATE_OFFSET);
return i2c_smbus_write_byte_data(client, HMC5843_CONFIG_REG_A, reg_val);
}
-static ssize_t set_sampling_frequency(struct device *dev,
+static int hmc5843_check_sampling_frequency(struct hmc5843_data *data,
+ const char *buf)
+{
+ const char * const *samp_freq = data->variant->regval_to_sample_freq;
+ int i;
+
+ for (i = 0; i < HMC5843_RATE_NOT_USED; i++) {
+ if (sysfs_streq(buf, samp_freq[i]))
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static ssize_t hmc5843_set_sampling_frequency(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
struct hmc5843_data *data = iio_priv(indio_dev);
- unsigned long rate = 0;
-
- if (strncmp(buf, "0.5" , 3) == 0)
- rate = RATE_5;
- else if (strncmp(buf, "1" , 1) == 0)
- rate = RATE_10;
- else if (strncmp(buf, "2", 1) == 0)
- rate = RATE_20;
- else if (strncmp(buf, "5", 1) == 0)
- rate = RATE_50;
- else if (strncmp(buf, "10", 2) == 0)
- rate = RATE_100;
- else if (strncmp(buf, "20" , 2) == 0)
- rate = RATE_200;
- else if (strncmp(buf, "50" , 2) == 0)
- rate = RATE_500;
- else
- return -EINVAL;
+ int rate;
+
+ rate = hmc5843_check_sampling_frequency(data, buf);
+ if (rate < 0) {
+ dev_err(&client->dev,
+ "sampling frequency is not supported\n");
+ return rate;
+ }
mutex_lock(&data->lock);
- dev_dbg(dev, "set rate to %lu\n", rate);
+ dev_dbg(dev, "set rate to %d\n", rate);
if (hmc5843_set_rate(client, rate)) {
count = -EINVAL;
goto exit;
@@ -366,89 +464,79 @@ exit:
return count;
}
-static ssize_t show_sampling_frequency(struct device *dev,
+static ssize_t hmc5843_show_sampling_frequency(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ struct hmc5843_data *data = iio_priv(indio_dev);
s32 rate;
- rate = i2c_smbus_read_byte_data(client, this_attr->address);
+ rate = i2c_smbus_read_byte_data(client, this_attr->address);
if (rate < 0)
return rate;
- rate = (rate & RATE_BITMASK) >> RATE_OFFSET;
- return sprintf(buf, "%s\n", regval_to_samp_freq[rate]);
+ rate = (rate & HMC5843_RATE_BITMASK) >> HMC5843_RATE_OFFSET;
+ return sprintf(buf, "%s\n", data->variant->regval_to_sample_freq[rate]);
}
+
static IIO_DEVICE_ATTR(sampling_frequency,
S_IWUSR | S_IRUGO,
- show_sampling_frequency,
- set_sampling_frequency,
+ hmc5843_show_sampling_frequency,
+ hmc5843_set_sampling_frequency,
HMC5843_CONFIG_REG_A);
-/*
- * From Datasheet
- * Nominal gain settings
- * Value | Sensor Input Field Range(Ga) | Gain(counts/ milli-gauss)
- *0 |(+-)0.7 |1620
- *1 |(+-)1.0 |1300
- *2 |(+-)1.5 |970
- *3 |(+-)2.0 |780
- *4 |(+-)3.2 |530
- *5 |(+-)3.8 |460
- *6 |(+-)4.5 |390
- *7 |(+-)6.5 |280
- */
-static ssize_t show_range(struct device *dev,
+static ssize_t hmc5843_show_range_gain(struct device *dev,
struct device_attribute *attr,
char *buf)
{
u8 range;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct hmc5843_data *data = iio_priv(indio_dev);
range = data->range;
- return sprintf(buf, "%d\n", regval_to_input_field_mg[range]);
+ return sprintf(buf, "%d\n", data->variant->regval_to_input_field_mga[range]);
}
-static ssize_t set_range(struct device *dev,
+static ssize_t hmc5843_set_range_gain(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct i2c_client *client = to_i2c_client(indio_dev->dev.parent);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct hmc5843_data *data = iio_priv(indio_dev);
unsigned long range = 0;
int error;
+
mutex_lock(&data->lock);
- error = strict_strtoul(buf, 10, &range);
+ error = kstrtoul(buf, 10, &range);
if (error) {
count = error;
goto exit;
}
dev_dbg(dev, "set range to %lu\n", range);
- if (range > RANGE_6_5) {
+ if (range > HMC5843_RANGE_GAIN_MAX) {
count = -EINVAL;
goto exit;
}
data->range = range;
- range = range << RANGE_GAIN_OFFSET;
+ range = range << HMC5843_RANGE_GAIN_OFFSET;
if (i2c_smbus_write_byte_data(client, this_attr->address, range))
count = -EINVAL;
exit:
mutex_unlock(&data->lock);
return count;
-
}
+
static IIO_DEVICE_ATTR(in_magn_range,
S_IWUSR | S_IRUGO,
- show_range,
- set_range,
+ hmc5843_show_range_gain,
+ hmc5843_set_range_gain,
HMC5843_CONFIG_REG_B);
static int hmc5843_read_raw(struct iio_dev *indio_dev,
@@ -459,13 +547,13 @@ static int hmc5843_read_raw(struct iio_dev *indio_dev,
struct hmc5843_data *data = iio_priv(indio_dev);
switch (mask) {
- case 0:
+ case IIO_CHAN_INFO_RAW:
return hmc5843_read_measurement(indio_dev,
chan->address,
val);
case IIO_CHAN_INFO_SCALE:
*val = 0;
- *val2 = hmc5843_regval_to_nanoscale[data->range];
+ *val2 = data->variant->regval_to_nanoscale[data->range];
return IIO_VAL_INT_PLUS_NANO;
};
return -EINVAL;
@@ -476,7 +564,8 @@ static int hmc5843_read_raw(struct iio_dev *indio_dev,
.type = IIO_MAGN, \
.modified = 1, \
.channel2 = IIO_MOD_##axis, \
- .info_mask = IIO_CHAN_INFO_SCALE_SHARED_BIT, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+ IIO_CHAN_INFO_SCALE_SHARED_BIT, \
.address = add \
}
@@ -486,12 +575,18 @@ static const struct iio_chan_spec hmc5843_channels[] = {
HMC5843_CHANNEL(Z, HMC5843_DATA_OUT_Z_MSB_REG),
};
+static const struct iio_chan_spec hmc5883_channels[] = {
+ HMC5843_CHANNEL(X, HMC5843_DATA_OUT_X_MSB_REG),
+ HMC5843_CHANNEL(Y, HMC5883_DATA_OUT_Y_MSB_REG),
+ HMC5843_CHANNEL(Z, HMC5883_DATA_OUT_Z_MSB_REG),
+};
+
static struct attribute *hmc5843_attributes[] = {
&iio_dev_attr_meas_conf.dev_attr.attr,
&iio_dev_attr_operating_mode.dev_attr.attr,
&iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_dev_attr_in_magn_range.dev_attr.attr,
- &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
NULL
};
@@ -499,6 +594,33 @@ static const struct attribute_group hmc5843_group = {
.attrs = hmc5843_attributes,
};
+static const struct hmc5843_chip_info hmc5843_chip_info_tbl[] = {
+ [HMC5843_ID] = {
+ .channels = hmc5843_channels,
+ .num_channels = ARRAY_SIZE(hmc5843_channels),
+ .regval_to_sample_freq = hmc5843_regval_to_sample_freq,
+ .regval_to_input_field_mga =
+ hmc5843_regval_to_input_field_mga,
+ .regval_to_nanoscale = hmc5843_regval_to_nanoscale,
+ },
+ [HMC5883_ID] = {
+ .channels = hmc5883_channels,
+ .num_channels = ARRAY_SIZE(hmc5883_channels),
+ .regval_to_sample_freq = hmc5883_regval_to_sample_freq,
+ .regval_to_input_field_mga =
+ hmc5883_regval_to_input_field_mga,
+ .regval_to_nanoscale = hmc5883_regval_to_nanoscale,
+ },
+ [HMC5883L_ID] = {
+ .channels = hmc5883_channels,
+ .num_channels = ARRAY_SIZE(hmc5883_channels),
+ .regval_to_sample_freq = hmc5883_regval_to_sample_freq,
+ .regval_to_input_field_mga =
+ hmc5883l_regval_to_input_field_mga,
+ .regval_to_nanoscale = hmc5883l_regval_to_nanoscale,
+ },
+};
+
static int hmc5843_detect(struct i2c_client *client,
struct i2c_board_info *info)
{
@@ -518,18 +640,23 @@ static int hmc5843_detect(struct i2c_client *client,
return 0;
}
-/* Called when we have found a new HMC5843. */
-static void hmc5843_init_client(struct i2c_client *client)
+/* Called when we have found a new HMC58X3 */
+static void hmc5843_init_client(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct hmc5843_data *data = iio_priv(indio_dev);
+ data->variant = &hmc5843_chip_info_tbl[id->driver_data];
+ indio_dev->channels = data->variant->channels;
+ indio_dev->num_channels = data->variant->num_channels;
hmc5843_set_meas_conf(client, data->meas_conf);
hmc5843_set_rate(client, data->rate);
hmc5843_configure(client, data->operating_mode);
i2c_smbus_write_byte_data(client, HMC5843_CONFIG_REG_B, data->range);
mutex_init(&data->lock);
- pr_info("HMC5843 initialized\n");
+
+ pr_info("%s initialized\n", id->name);
}
static const struct iio_info hmc5843_info = {
@@ -545,35 +672,34 @@ static int hmc5843_probe(struct i2c_client *client,
struct iio_dev *indio_dev;
int err = 0;
- indio_dev = iio_allocate_device(sizeof(*data));
+ indio_dev = iio_device_alloc(sizeof(*data));
if (indio_dev == NULL) {
err = -ENOMEM;
goto exit;
}
- data = iio_priv(indio_dev);
- /* default settings at probe */
- data->meas_conf = CONF_NORMAL;
- data->range = RANGE_1_0;
- data->operating_mode = MODE_CONVERSION_CONTINUOUS;
+ /* default settings at probe */
+ data = iio_priv(indio_dev);
+ data->meas_conf = HMC5843_MEAS_CONF_NORMAL;
+ data->range = HMC5843_RANGE_GAIN_DEFAULT;
+ data->operating_mode = HMC5843_MODE_CONVERSION_CONTINUOUS;
i2c_set_clientdata(client, indio_dev);
-
- /* Initialize the HMC5843 chip */
- hmc5843_init_client(client);
+ hmc5843_init_client(client, id);
indio_dev->info = &hmc5843_info;
indio_dev->name = id->name;
- indio_dev->channels = hmc5843_channels;
- indio_dev->num_channels = ARRAY_SIZE(hmc5843_channels);
indio_dev->dev.parent = &client->dev;
indio_dev->modes = INDIO_DIRECT_MODE;
+
err = iio_device_register(indio_dev);
if (err)
goto exit_free2;
+
return 0;
+
exit_free2:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
exit:
return err;
}
@@ -584,8 +710,8 @@ static int hmc5843_remove(struct i2c_client *client)
iio_device_unregister(indio_dev);
/* sleep mode to save power */
- hmc5843_configure(client, MODE_SLEEP);
- iio_free_device(indio_dev);
+ hmc5843_configure(client, HMC5843_MODE_SLEEP);
+ iio_device_free(indio_dev);
return 0;
}
@@ -593,14 +719,18 @@ static int hmc5843_remove(struct i2c_client *client)
#ifdef CONFIG_PM_SLEEP
static int hmc5843_suspend(struct device *dev)
{
- hmc5843_configure(to_i2c_client(dev), MODE_SLEEP);
+ hmc5843_configure(to_i2c_client(dev), HMC5843_MODE_SLEEP);
return 0;
}
static int hmc5843_resume(struct device *dev)
{
- struct hmc5843_data *data = i2c_get_clientdata(to_i2c_client(dev));
- hmc5843_configure(to_i2c_client(dev), data->operating_mode);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct hmc5843_data *data = iio_priv(indio_dev);
+
+ hmc5843_configure(client, data->operating_mode);
+
return 0;
}
@@ -611,7 +741,9 @@ static SIMPLE_DEV_PM_OPS(hmc5843_pm_ops, hmc5843_suspend, hmc5843_resume);
#endif
static const struct i2c_device_id hmc5843_id[] = {
- { "hmc5843", 0 },
+ { "hmc5843", HMC5843_ID },
+ { "hmc5883", HMC5883_ID },
+ { "hmc5883l", HMC5883L_ID },
{ }
};
MODULE_DEVICE_TABLE(i2c, hmc5843_id);
@@ -630,5 +762,5 @@ static struct i2c_driver hmc5843_driver = {
module_i2c_driver(hmc5843_driver);
MODULE_AUTHOR("Shubhrajyoti Datta <shubhrajyoti@ti.com");
-MODULE_DESCRIPTION("HMC5843 driver");
+MODULE_DESCRIPTION("HMC5843/5883/5883L driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c
index 57baac6c0d40..f04ece7fbc2f 100644
--- a/drivers/staging/iio/meter/ade7753.c
+++ b/drivers/staging/iio/meter/ade7753.c
@@ -18,8 +18,8 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "meter.h"
#include "ade7753.h"
@@ -28,7 +28,7 @@ static int ade7753_spi_write_reg_8(struct device *dev,
u8 val)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7753_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
@@ -46,7 +46,7 @@ static int ade7753_spi_write_reg_16(struct device *dev,
u16 value)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7753_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
@@ -63,7 +63,7 @@ static int ade7753_spi_read_reg_8(struct device *dev,
u8 reg_address,
u8 *val)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7753_state *st = iio_priv(indio_dev);
ssize_t ret;
@@ -82,7 +82,7 @@ static int ade7753_spi_read_reg_16(struct device *dev,
u8 reg_address,
u16 *val)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7753_state *st = iio_priv(indio_dev);
ssize_t ret;
@@ -104,7 +104,7 @@ static int ade7753_spi_read_reg_24(struct device *dev,
u32 *val)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7753_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
@@ -416,7 +416,7 @@ static ssize_t ade7753_write_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7753_state *st = iio_priv(indio_dev);
unsigned long val;
int ret;
@@ -517,7 +517,7 @@ static int __devinit ade7753_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -546,7 +546,7 @@ static int __devinit ade7753_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
@@ -564,7 +564,7 @@ static int ade7753_remove(struct spi_device *spi)
if (ret)
goto err_ret;
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
err_ret:
return ret;
}
diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c
index 8d81c92007e9..6cee28a5e877 100644
--- a/drivers/staging/iio/meter/ade7754.c
+++ b/drivers/staging/iio/meter/ade7754.c
@@ -18,8 +18,8 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "meter.h"
#include "ade7754.h"
@@ -28,7 +28,7 @@ static int ade7754_spi_write_reg_8(struct device *dev,
u8 val)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7754_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
@@ -46,7 +46,7 @@ static int ade7754_spi_write_reg_16(struct device *dev,
u16 value)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7754_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
@@ -63,7 +63,7 @@ static int ade7754_spi_read_reg_8(struct device *dev,
u8 reg_address,
u8 *val)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7754_state *st = iio_priv(indio_dev);
int ret;
@@ -82,7 +82,7 @@ static int ade7754_spi_read_reg_16(struct device *dev,
u8 reg_address,
u16 *val)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7754_state *st = iio_priv(indio_dev);
int ret;
@@ -104,7 +104,7 @@ static int ade7754_spi_read_reg_24(struct device *dev,
u32 *val)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7754_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
@@ -436,7 +436,7 @@ static ssize_t ade7754_write_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7754_state *st = iio_priv(indio_dev);
unsigned long val;
int ret;
@@ -540,7 +540,7 @@ static int __devinit ade7754_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -568,7 +568,7 @@ static int __devinit ade7754_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
@@ -585,7 +585,7 @@ static int ade7754_remove(struct spi_device *spi)
if (ret)
goto err_ret;
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
err_ret:
return ret;
diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c
index dcb20294dfe8..96d6114a31aa 100644
--- a/drivers/staging/iio/meter/ade7758_core.c
+++ b/drivers/staging/iio/meter/ade7758_core.c
@@ -18,9 +18,9 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
-#include "../buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
#include "meter.h"
#include "ade7758.h"
@@ -29,7 +29,7 @@ int ade7758_spi_write_reg_8(struct device *dev,
u8 val)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7758_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
@@ -48,7 +48,7 @@ static int ade7758_spi_write_reg_16(struct device *dev,
{
int ret;
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7758_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[] = {
{
@@ -77,7 +77,7 @@ static int ade7758_spi_write_reg_24(struct device *dev,
{
int ret;
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7758_state *st = iio_priv(indio_dev);
struct spi_transfer xfers[] = {
{
@@ -106,7 +106,7 @@ int ade7758_spi_read_reg_8(struct device *dev,
u8 *val)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7758_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
@@ -149,7 +149,7 @@ static int ade7758_spi_read_reg_16(struct device *dev,
u16 *val)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7758_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
@@ -195,7 +195,7 @@ static int ade7758_spi_read_reg_24(struct device *dev,
u32 *val)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7758_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
@@ -534,7 +534,7 @@ static ssize_t ade7758_write_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
unsigned long val;
int ret;
u8 reg, t;
@@ -662,66 +662,217 @@ static const struct attribute_group ade7758_attribute_group = {
};
static struct iio_chan_spec ade7758_channels[] = {
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "raw", 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_A, AD7758_VOLTAGE),
- 0, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_CURRENT, 0, 1, 0, "raw", 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_A, AD7758_CURRENT),
- 1, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_POWER, 0, 1, 0, "apparent_raw", 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_A, AD7758_APP_PWR),
- 2, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_POWER, 0, 1, 0, "active_raw", 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_A, AD7758_ACT_PWR),
- 3, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_POWER, 0, 1, 0, "reactive_raw", 0, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_A, AD7758_REACT_PWR),
- 4, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "raw", 1, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_B, AD7758_VOLTAGE),
- 5, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_CURRENT, 0, 1, 0, "raw", 1, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_B, AD7758_CURRENT),
- 6, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_POWER, 0, 1, 0, "apparent_raw", 1, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_B, AD7758_APP_PWR),
- 7, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_POWER, 0, 1, 0, "active_raw", 1, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_B, AD7758_ACT_PWR),
- 8, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_POWER, 0, 1, 0, "reactive_raw", 1, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_B, AD7758_REACT_PWR),
- 9, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_VOLTAGE, 0, 1, 0, "raw", 2, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_C, AD7758_VOLTAGE),
- 10, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_CURRENT, 0, 1, 0, "raw", 2, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_C, AD7758_CURRENT),
- 11, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_POWER, 0, 1, 0, "apparent_raw", 2, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_C, AD7758_APP_PWR),
- 12, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_POWER, 0, 1, 0, "active_raw", 2, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_C, AD7758_ACT_PWR),
- 13, IIO_ST('s', 24, 32, 0), 0),
- IIO_CHAN(IIO_POWER, 0, 1, 0, "reactive_raw", 2, 0,
- IIO_CHAN_INFO_SCALE_SHARED_BIT,
- AD7758_WT(AD7758_PHASE_C, AD7758_REACT_PWR),
- 14, IIO_ST('s', 24, 32, 0), 0),
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .extend_name = "raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_A, AD7758_VOLTAGE),
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_CURRENT,
+ .indexed = 1,
+ .channel = 0,
+ .extend_name = "raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_A, AD7758_CURRENT),
+ .scan_index = 1,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_POWER,
+ .indexed = 1,
+ .channel = 0,
+ .extend_name = "apparent_raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_A, AD7758_APP_PWR),
+ .scan_index = 2,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_POWER,
+ .indexed = 1,
+ .channel = 0,
+ .extend_name = "active_raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_A, AD7758_ACT_PWR),
+ .scan_index = 3,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_POWER,
+ .indexed = 1,
+ .channel = 0,
+ .extend_name = "reactive_raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_A, AD7758_REACT_PWR),
+ .scan_index = 4,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 1,
+ .extend_name = "raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_B, AD7758_VOLTAGE),
+ .scan_index = 5,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_CURRENT,
+ .indexed = 1,
+ .channel = 1,
+ .extend_name = "raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_B, AD7758_CURRENT),
+ .scan_index = 6,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_POWER,
+ .indexed = 1,
+ .channel = 1,
+ .extend_name = "apparent_raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_B, AD7758_APP_PWR),
+ .scan_index = 7,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_POWER,
+ .indexed = 1,
+ .channel = 1,
+ .extend_name = "active_raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_B, AD7758_ACT_PWR),
+ .scan_index = 8,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_POWER,
+ .indexed = 1,
+ .channel = 1,
+ .extend_name = "reactive_raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_B, AD7758_REACT_PWR),
+ .scan_index = 9,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 2,
+ .extend_name = "raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_C, AD7758_VOLTAGE),
+ .scan_index = 10,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_CURRENT,
+ .indexed = 1,
+ .channel = 2,
+ .extend_name = "raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_C, AD7758_CURRENT),
+ .scan_index = 11,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_POWER,
+ .indexed = 1,
+ .channel = 2,
+ .extend_name = "apparent_raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_C, AD7758_APP_PWR),
+ .scan_index = 12,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_POWER,
+ .indexed = 1,
+ .channel = 2,
+ .extend_name = "active_raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_C, AD7758_ACT_PWR),
+ .scan_index = 13,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ }, {
+ .type = IIO_POWER,
+ .indexed = 1,
+ .channel = 2,
+ .extend_name = "reactive_raw",
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
+ IIO_CHAN_INFO_SCALE_SHARED_BIT,
+ .address = AD7758_WT(AD7758_PHASE_C, AD7758_REACT_PWR),
+ .scan_index = 14,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ },
+ },
IIO_CHAN_SOFT_TIMESTAMP(15),
};
@@ -734,7 +885,7 @@ static int __devinit ade7758_probe(struct spi_device *spi)
{
int i, ret;
struct ade7758_state *st;
- struct iio_dev *indio_dev = iio_allocate_device(sizeof(*st));
+ struct iio_dev *indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
@@ -800,7 +951,7 @@ static int __devinit ade7758_probe(struct spi_device *spi)
return 0;
error_remove_trigger:
- if (indio_dev->modes & INDIO_BUFFER_TRIGGERED)
+ if (spi->irq)
ade7758_remove_trigger(indio_dev);
error_uninitialize_ring:
ade7758_uninitialize_ring(indio_dev);
@@ -811,7 +962,7 @@ error_free_tx:
error_free_rx:
kfree(st->rx);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -833,7 +984,7 @@ static int ade7758_remove(struct spi_device *spi)
kfree(st->tx);
kfree(st->rx);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
err_ret:
return ret;
diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c
index c45b23bb1229..92159f208d14 100644
--- a/drivers/staging/iio/meter/ade7758_ring.c
+++ b/drivers/staging/iio/meter/ade7758_ring.c
@@ -12,18 +12,17 @@
#include <linux/slab.h>
#include <asm/unaligned.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "../ring_sw.h"
-#include "../trigger_consumer.h"
+#include <linux/iio/trigger_consumer.h>
#include "ade7758.h"
/**
* ade7758_spi_read_burst() - read data registers
- * @dev: device associated with child of actual device (iio_dev or iio_trig)
+ * @indio_dev: the IIO device
**/
-static int ade7758_spi_read_burst(struct device *dev)
+static int ade7758_spi_read_burst(struct iio_dev *indio_dev)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ade7758_state *st = iio_priv(indio_dev);
int ret;
@@ -68,11 +67,11 @@ static irqreturn_t ade7758_trigger_handler(int irq, void *p)
u32 *dat32 = (u32 *)dat64;
if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
- if (ade7758_spi_read_burst(&indio_dev->dev) >= 0)
+ if (ade7758_spi_read_burst(indio_dev) >= 0)
*dat32 = get_unaligned_be32(&st->rx_buf[5]) & 0xFFFFFF;
/* Guaranteed to be aligned with 8 byte boundary */
- if (ring->scan_timestamp)
+ if (indio_dev->scan_timestamp)
dat64[1] = pf->timestamp;
ring->access->store_to(ring, (u8 *)dat64, pf->timestamp);
@@ -92,29 +91,19 @@ static irqreturn_t ade7758_trigger_handler(int irq, void *p)
static int ade7758_ring_preenable(struct iio_dev *indio_dev)
{
struct ade7758_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
- size_t d_size;
unsigned channel;
+ int ret;
if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength))
return -EINVAL;
+ ret = iio_sw_buffer_preenable(indio_dev);
+ if (ret < 0)
+ return ret;
+
channel = find_first_bit(indio_dev->active_scan_mask,
indio_dev->masklength);
- d_size = st->ade7758_ring_channels[channel].scan_type.storagebits / 8;
-
- if (ring->scan_timestamp) {
- d_size += sizeof(s64);
-
- if (d_size % sizeof(s64))
- d_size += sizeof(s64) - (d_size % sizeof(s64));
- }
-
- if (indio_dev->buffer->access->set_bytes_per_datum)
- indio_dev->buffer->access->
- set_bytes_per_datum(indio_dev->buffer, d_size);
-
ade7758_write_waveform_type(&indio_dev->dev,
st->ade7758_ring_channels[channel].address);
diff --git a/drivers/staging/iio/meter/ade7758_trigger.c b/drivers/staging/iio/meter/ade7758_trigger.c
index b6569c706651..f9c6a340092b 100644
--- a/drivers/staging/iio/meter/ade7758_trigger.c
+++ b/drivers/staging/iio/meter/ade7758_trigger.c
@@ -11,8 +11,8 @@
#include <linux/spi/spi.h>
#include <linux/export.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
#include "ade7758.h"
/**
@@ -63,7 +63,7 @@ int ade7758_probe_trigger(struct iio_dev *indio_dev)
struct ade7758_state *st = iio_priv(indio_dev);
int ret;
- st->trig = iio_allocate_trigger("%s-dev%d",
+ st->trig = iio_trigger_alloc("%s-dev%d",
spi_get_device_id(st->us)->name,
indio_dev->id);
if (st->trig == NULL) {
@@ -94,7 +94,7 @@ int ade7758_probe_trigger(struct iio_dev *indio_dev)
error_free_irq:
free_irq(st->us->irq, st->trig);
error_free_trig:
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
error_ret:
return ret;
}
@@ -105,5 +105,5 @@ void ade7758_remove_trigger(struct iio_dev *indio_dev)
iio_trigger_unregister(st->trig);
free_irq(st->us->irq, st->trig);
- iio_free_trigger(st->trig);
+ iio_trigger_free(st->trig);
}
diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c
index 0beab478dcd9..b3f7e0fa9612 100644
--- a/drivers/staging/iio/meter/ade7759.c
+++ b/drivers/staging/iio/meter/ade7759.c
@@ -18,8 +18,8 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "meter.h"
#include "ade7759.h"
@@ -28,7 +28,7 @@ static int ade7759_spi_write_reg_8(struct device *dev,
u8 val)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
@@ -46,7 +46,7 @@ static int ade7759_spi_write_reg_16(struct device *dev,
u16 value)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
@@ -63,7 +63,7 @@ static int ade7759_spi_read_reg_8(struct device *dev,
u8 reg_address,
u8 *val)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
int ret;
@@ -82,7 +82,7 @@ static int ade7759_spi_read_reg_16(struct device *dev,
u8 reg_address,
u16 *val)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
int ret;
@@ -104,7 +104,7 @@ static int ade7759_spi_read_reg_40(struct device *dev,
u64 *val)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
@@ -376,7 +376,7 @@ static ssize_t ade7759_write_frequency(struct device *dev,
const char *buf,
size_t len)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7759_state *st = iio_priv(indio_dev);
unsigned long val;
int ret;
@@ -463,7 +463,7 @@ static int __devinit ade7759_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
/* setup the industrialio driver allocated elements */
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -491,7 +491,7 @@ static int __devinit ade7759_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -507,7 +507,7 @@ static int ade7759_remove(struct spi_device *spi)
if (ret)
goto err_ret;
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
err_ret:
return ret;
diff --git a/drivers/staging/iio/meter/ade7854-i2c.c b/drivers/staging/iio/meter/ade7854-i2c.c
index 1e1faa0479d3..06090465fa5f 100644
--- a/drivers/staging/iio/meter/ade7854-i2c.c
+++ b/drivers/staging/iio/meter/ade7854-i2c.c
@@ -12,7 +12,7 @@
#include <linux/slab.h>
#include <linux/module.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "ade7854.h"
static int ade7854_i2c_write_reg_8(struct device *dev,
@@ -20,7 +20,7 @@ static int ade7854_i2c_write_reg_8(struct device *dev,
u8 value)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
@@ -39,7 +39,7 @@ static int ade7854_i2c_write_reg_16(struct device *dev,
u16 value)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
@@ -59,7 +59,7 @@ static int ade7854_i2c_write_reg_24(struct device *dev,
u32 value)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
@@ -80,7 +80,7 @@ static int ade7854_i2c_write_reg_32(struct device *dev,
u32 value)
{
int ret;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
@@ -101,7 +101,7 @@ static int ade7854_i2c_read_reg_8(struct device *dev,
u16 reg_address,
u8 *val)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
@@ -127,7 +127,7 @@ static int ade7854_i2c_read_reg_16(struct device *dev,
u16 reg_address,
u16 *val)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
@@ -153,7 +153,7 @@ static int ade7854_i2c_read_reg_24(struct device *dev,
u16 reg_address,
u32 *val)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
@@ -179,7 +179,7 @@ static int ade7854_i2c_read_reg_32(struct device *dev,
u16 reg_address,
u32 *val)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
@@ -208,7 +208,7 @@ static int __devinit ade7854_i2c_probe(struct i2c_client *client,
struct ade7854_state *st;
struct iio_dev *indio_dev;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
@@ -226,7 +226,7 @@ static int __devinit ade7854_i2c_probe(struct i2c_client *client,
ret = ade7854_probe(indio_dev, &client->dev);
if (ret)
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
diff --git a/drivers/staging/iio/meter/ade7854-spi.c b/drivers/staging/iio/meter/ade7854-spi.c
index 81121862c1bd..9fb2f8bfca81 100644
--- a/drivers/staging/iio/meter/ade7854-spi.c
+++ b/drivers/staging/iio/meter/ade7854-spi.c
@@ -12,7 +12,7 @@
#include <linux/slab.h>
#include <linux/module.h>
-#include "../iio.h"
+#include <linux/iio/iio.h>
#include "ade7854.h"
static int ade7854_spi_write_reg_8(struct device *dev,
@@ -21,7 +21,7 @@ static int ade7854_spi_write_reg_8(struct device *dev,
{
int ret;
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
struct spi_transfer xfer = {
.tx_buf = st->tx,
@@ -49,7 +49,7 @@ static int ade7854_spi_write_reg_16(struct device *dev,
{
int ret;
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
struct spi_transfer xfer = {
.tx_buf = st->tx,
@@ -78,7 +78,7 @@ static int ade7854_spi_write_reg_24(struct device *dev,
{
int ret;
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
struct spi_transfer xfer = {
.tx_buf = st->tx,
@@ -108,7 +108,7 @@ static int ade7854_spi_write_reg_32(struct device *dev,
{
int ret;
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
struct spi_transfer xfer = {
.tx_buf = st->tx,
@@ -138,7 +138,7 @@ static int ade7854_spi_read_reg_8(struct device *dev,
u8 *val)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
@@ -180,7 +180,7 @@ static int ade7854_spi_read_reg_16(struct device *dev,
u16 *val)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
@@ -221,7 +221,7 @@ static int ade7854_spi_read_reg_24(struct device *dev,
u32 *val)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
@@ -263,7 +263,7 @@ static int ade7854_spi_read_reg_32(struct device *dev,
u32 *val)
{
struct spi_message msg;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
struct spi_transfer xfers[] = {
@@ -306,7 +306,7 @@ static int __devinit ade7854_spi_probe(struct spi_device *spi)
struct ade7854_state *st;
struct iio_dev *indio_dev;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL)
return -ENOMEM;
st = iio_priv(indio_dev);
@@ -325,7 +325,7 @@ static int __devinit ade7854_spi_probe(struct spi_device *spi)
ret = ade7854_probe(indio_dev, &spi->dev);
if (ret)
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/meter/ade7854.c b/drivers/staging/iio/meter/ade7854.c
index 49c01c5c1b59..c642da84842a 100644
--- a/drivers/staging/iio/meter/ade7854.c
+++ b/drivers/staging/iio/meter/ade7854.c
@@ -17,8 +17,8 @@
#include <linux/list.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "meter.h"
#include "ade7854.h"
@@ -28,7 +28,7 @@ static ssize_t ade7854_read_8bit(struct device *dev,
{
int ret;
u8 val = 0;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -45,7 +45,7 @@ static ssize_t ade7854_read_16bit(struct device *dev,
{
int ret;
u16 val = 0;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -62,7 +62,7 @@ static ssize_t ade7854_read_24bit(struct device *dev,
{
int ret;
u32 val;
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
@@ -80,7 +80,7 @@ static ssize_t ade7854_read_32bit(struct device *dev,
int ret;
u32 val = 0;
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
ret = st->read_reg_32(dev, this_attr->address, &val);
@@ -96,7 +96,7 @@ static ssize_t ade7854_write_8bit(struct device *dev,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
@@ -117,7 +117,7 @@ static ssize_t ade7854_write_16bit(struct device *dev,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
@@ -138,7 +138,7 @@ static ssize_t ade7854_write_24bit(struct device *dev,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
@@ -159,7 +159,7 @@ static ssize_t ade7854_write_32bit(struct device *dev,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
@@ -176,7 +176,7 @@ error_ret:
static int ade7854_reset(struct device *dev)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
u16 val;
@@ -425,7 +425,7 @@ static IIO_DEV_ATTR_CVAHR(ade7854_read_32bit,
static int ade7854_set_irq(struct device *dev, bool enable)
{
- struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7854_state *st = iio_priv(indio_dev);
int ret;
@@ -581,7 +581,7 @@ int ade7854_probe(struct iio_dev *indio_dev, struct device *dev)
error_unreg_dev:
iio_device_unregister(indio_dev);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return ret;
}
@@ -590,7 +590,7 @@ EXPORT_SYMBOL(ade7854_probe);
int ade7854_remove(struct iio_dev *indio_dev)
{
iio_device_unregister(indio_dev);
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/meter/meter.h b/drivers/staging/iio/meter/meter.h
index 6a3db1423631..23e1b5f480a9 100644
--- a/drivers/staging/iio/meter/meter.h
+++ b/drivers/staging/iio/meter/meter.h
@@ -1,4 +1,4 @@
-#include "../sysfs.h"
+#include <linux/iio/sysfs.h>
/* metering ic types of attribute */
diff --git a/drivers/staging/iio/resolver/ad2s1200.c b/drivers/staging/iio/resolver/ad2s1200.c
index d8ce854c1897..8b71eb0e16f5 100644
--- a/drivers/staging/iio/resolver/ad2s1200.c
+++ b/drivers/staging/iio/resolver/ad2s1200.c
@@ -19,8 +19,8 @@
#include <linux/gpio.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#define DRV_NAME "ad2s1200"
@@ -85,10 +85,12 @@ static const struct iio_chan_spec ad2s1200_channels[] = {
.type = IIO_ANGL,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
}, {
.type = IIO_ANGL_VEL,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
}
};
@@ -110,7 +112,7 @@ static int __devinit ad2s1200_probe(struct spi_device *spi)
DRV_NAME, pins[pn]);
goto error_ret;
}
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -140,7 +142,7 @@ static int __devinit ad2s1200_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
for (--pn; pn >= 0; pn--)
gpio_free(pins[pn]);
@@ -150,7 +152,7 @@ error_ret:
static int __devexit ad2s1200_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c
index c439fcf72be7..f313859476c1 100644
--- a/drivers/staging/iio/resolver/ad2s1210.c
+++ b/drivers/staging/iio/resolver/ad2s1210.c
@@ -18,8 +18,8 @@
#include <linux/gpio.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
#include "ad2s1210.h"
#define DRV_NAME "ad2s1210"
@@ -200,7 +200,7 @@ static ssize_t ad2s1210_store_softreset(struct device *dev,
const char *buf,
size_t len)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
int ret;
mutex_lock(&st->lock);
@@ -214,7 +214,7 @@ static ssize_t ad2s1210_show_fclkin(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
return sprintf(buf, "%d\n", st->fclkin);
}
@@ -223,7 +223,7 @@ static ssize_t ad2s1210_store_fclkin(struct device *dev,
const char *buf,
size_t len)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
unsigned long fclkin;
int ret;
@@ -252,7 +252,7 @@ static ssize_t ad2s1210_show_fexcit(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
return sprintf(buf, "%d\n", st->fexcit);
}
@@ -260,7 +260,7 @@ static ssize_t ad2s1210_store_fexcit(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
unsigned long fexcit;
int ret;
@@ -287,7 +287,7 @@ static ssize_t ad2s1210_show_control(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
int ret;
mutex_lock(&st->lock);
ret = ad2s1210_config_read(st, AD2S1210_REG_CONTROL);
@@ -299,7 +299,7 @@ static ssize_t ad2s1210_store_control(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
unsigned long udata;
unsigned char data;
int ret;
@@ -345,7 +345,7 @@ error_ret:
static ssize_t ad2s1210_show_resolution(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
return sprintf(buf, "%d\n", st->resolution);
}
@@ -353,7 +353,7 @@ static ssize_t ad2s1210_store_resolution(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
unsigned char data;
unsigned long udata;
int ret;
@@ -403,7 +403,7 @@ error_ret:
static ssize_t ad2s1210_show_fault(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
int ret;
mutex_lock(&st->lock);
@@ -418,7 +418,7 @@ static ssize_t ad2s1210_clear_fault(struct device *dev,
const char *buf,
size_t len)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
int ret;
mutex_lock(&st->lock);
@@ -441,7 +441,7 @@ static ssize_t ad2s1210_show_reg(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
struct iio_dev_attr *iattr = to_iio_dev_attr(attr);
int ret;
@@ -455,7 +455,7 @@ static ssize_t ad2s1210_show_reg(struct device *dev,
static ssize_t ad2s1210_store_reg(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
- struct ad2s1210_state *st = iio_priv(dev_get_drvdata(dev));
+ struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev));
unsigned long data;
int ret;
struct iio_dev_attr *iattr = to_iio_dev_attr(attr);
@@ -580,10 +580,12 @@ static struct iio_chan_spec ad2s1210_channels[] = {
.type = IIO_ANGL,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
}, {
.type = IIO_ANGL_VEL,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
}
};
@@ -688,7 +690,7 @@ static int __devinit ad2s1210_probe(struct spi_device *spi)
if (spi->dev.platform_data == NULL)
return -EINVAL;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -729,7 +731,7 @@ static int __devinit ad2s1210_probe(struct spi_device *spi)
error_free_gpios:
ad2s1210_free_gpios(st);
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -740,7 +742,7 @@ static int __devexit ad2s1210_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
ad2s1210_free_gpios(iio_priv(indio_dev));
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
return 0;
}
diff --git a/drivers/staging/iio/resolver/ad2s90.c b/drivers/staging/iio/resolver/ad2s90.c
index 2a86f582ddf1..a8057228dca1 100644
--- a/drivers/staging/iio/resolver/ad2s90.c
+++ b/drivers/staging/iio/resolver/ad2s90.c
@@ -16,8 +16,8 @@
#include <linux/sysfs.h>
#include <linux/module.h>
-#include "../iio.h"
-#include "../sysfs.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
struct ad2s90_state {
struct mutex lock;
@@ -55,6 +55,7 @@ static const struct iio_chan_spec ad2s90_chan = {
.type = IIO_ANGL,
.indexed = 1,
.channel = 0,
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
};
static int __devinit ad2s90_probe(struct spi_device *spi)
@@ -63,7 +64,7 @@ static int __devinit ad2s90_probe(struct spi_device *spi)
struct ad2s90_state *st;
int ret = 0;
- indio_dev = iio_allocate_device(sizeof(*st));
+ indio_dev = iio_device_alloc(sizeof(*st));
if (indio_dev == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -92,7 +93,7 @@ static int __devinit ad2s90_probe(struct spi_device *spi)
return 0;
error_free_dev:
- iio_free_device(indio_dev);
+ iio_device_free(indio_dev);
error_ret:
return ret;
}
@@ -100,7 +101,7 @@ error_ret:
static int __devexit ad2s90_remove(struct spi_device *spi)
{
iio_device_unregister(spi_get_drvdata(spi));
- iio_free_device(spi_get_drvdata(spi));
+ iio_device_free(spi_get_drvdata(spi));
return 0;
}
diff --git a/drivers/staging/iio/ring_sw.c b/drivers/staging/iio/ring_sw.c
index b9945ec44faa..9358c6cb1c72 100644
--- a/drivers/staging/iio/ring_sw.c
+++ b/drivers/staging/iio/ring_sw.c
@@ -15,7 +15,7 @@
#include <linux/sched.h>
#include <linux/poll.h>
#include "ring_sw.h"
-#include "trigger.h"
+#include <linux/iio/trigger.h>
/**
* struct iio_sw_ring_buffer - software ring buffer
diff --git a/drivers/staging/iio/ring_sw.h b/drivers/staging/iio/ring_sw.h
index 7556e2122367..a5857aa7aefa 100644
--- a/drivers/staging/iio/ring_sw.h
+++ b/drivers/staging/iio/ring_sw.h
@@ -23,7 +23,7 @@
#ifndef _IIO_RING_SW_H_
#define _IIO_RING_SW_H_
-#include "buffer.h"
+#include <linux/iio/buffer.h>
struct iio_buffer *iio_sw_rb_allocate(struct iio_dev *indio_dev);
void iio_sw_rb_free(struct iio_buffer *ring);
diff --git a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
index 665653d79f02..f85734d212bb 100644
--- a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
+++ b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c
@@ -15,8 +15,8 @@
#include <asm/gptimers.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
struct bfin_timer {
unsigned short id, bit;
@@ -172,7 +172,7 @@ static int __devinit iio_bfin_tmr_trigger_probe(struct platform_device *pdev)
st->timer_num = ret;
st->t = &iio_bfin_timer_code[st->timer_num];
- st->trig = iio_allocate_trigger("bfintmr%d", st->timer_num);
+ st->trig = iio_trigger_alloc("bfintmr%d", st->timer_num);
if (!st->trig) {
ret = -ENOMEM;
goto out1;
@@ -203,7 +203,7 @@ static int __devinit iio_bfin_tmr_trigger_probe(struct platform_device *pdev)
out4:
iio_trigger_unregister(st->trig);
out2:
- iio_put_trigger(st->trig);
+ iio_trigger_put(st->trig);
out1:
kfree(st);
out:
@@ -217,7 +217,7 @@ static int __devexit iio_bfin_tmr_trigger_remove(struct platform_device *pdev)
disable_gptimers(st->t->bit);
free_irq(st->irq, st);
iio_trigger_unregister(st->trig);
- iio_put_trigger(st->trig);
+ iio_trigger_put(st->trig);
kfree(st);
return 0;
diff --git a/drivers/staging/iio/trigger/iio-trig-gpio.c b/drivers/staging/iio/trigger/iio-trig-gpio.c
index a3465947235e..90b26846fc6b 100644
--- a/drivers/staging/iio/trigger/iio-trig-gpio.c
+++ b/drivers/staging/iio/trigger/iio-trig-gpio.c
@@ -22,8 +22,8 @@
#include <linux/gpio.h>
#include <linux/slab.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
static LIST_HEAD(iio_gpio_trigger_list);
static DEFINE_MUTEX(iio_gpio_trigger_list_lock);
@@ -72,7 +72,7 @@ static int iio_gpio_trigger_probe(struct platform_device *pdev)
for (irq = irq_res->start; irq <= irq_res->end; irq++) {
- trig = iio_allocate_trigger("irqtrig%d", irq);
+ trig = iio_trigger_alloc("irqtrig%d", irq);
if (!trig) {
ret = -ENOMEM;
goto error_free_completed_registrations;
@@ -114,7 +114,7 @@ error_release_irq:
error_free_trig_info:
kfree(trig_info);
error_put_trigger:
- iio_put_trigger(trig);
+ iio_trigger_put(trig);
error_free_completed_registrations:
/* The rest should have been added to the iio_gpio_trigger_list */
list_for_each_entry_safe(trig,
@@ -144,7 +144,7 @@ static int iio_gpio_trigger_remove(struct platform_device *pdev)
iio_trigger_unregister(trig);
free_irq(trig_info->irq, trig);
kfree(trig_info);
- iio_put_trigger(trig);
+ iio_trigger_put(trig);
}
mutex_unlock(&iio_gpio_trigger_list_lock);
diff --git a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
index a80cf67bf84d..9f2d055524a3 100644
--- a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
+++ b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c
@@ -16,8 +16,8 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/rtc.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
static LIST_HEAD(iio_prtc_trigger_list);
static DEFINE_MUTEX(iio_prtc_trigger_list_lock);
@@ -112,7 +112,7 @@ static int iio_trig_periodic_rtc_probe(struct platform_device *dev)
for (i = 0;; i++) {
if (pdata[i] == NULL)
break;
- trig = iio_allocate_trigger("periodic%s", pdata[i]);
+ trig = iio_trigger_alloc("periodic%s", pdata[i]);
if (!trig) {
ret = -ENOMEM;
goto error_free_completed_registrations;
@@ -152,7 +152,7 @@ error_free_trig_info:
kfree(trig_info);
error_put_trigger_and_remove_from_list:
list_del(&trig->alloc_list);
- iio_put_trigger(trig);
+ iio_trigger_put(trig);
error_free_completed_registrations:
list_for_each_entry_safe(trig,
trig2,
diff --git a/drivers/staging/iio/trigger/iio-trig-sysfs.c b/drivers/staging/iio/trigger/iio-trig-sysfs.c
index 174dc65709d5..552763bb3d4c 100644
--- a/drivers/staging/iio/trigger/iio-trig-sysfs.c
+++ b/drivers/staging/iio/trigger/iio-trig-sysfs.c
@@ -11,8 +11,8 @@
#include <linux/slab.h>
#include <linux/list.h>
-#include "../iio.h"
-#include "../trigger.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
struct iio_sysfs_trig {
struct iio_trigger *trig;
@@ -139,7 +139,7 @@ static int iio_sysfs_trigger_probe(int id)
goto out1;
}
t->id = id;
- t->trig = iio_allocate_trigger("sysfstrig%d", id);
+ t->trig = iio_trigger_alloc("sysfstrig%d", id);
if (!t->trig) {
ret = -ENOMEM;
goto free_t;
@@ -158,7 +158,7 @@ static int iio_sysfs_trigger_probe(int id)
return 0;
out2:
- iio_put_trigger(t->trig);
+ iio_trigger_put(t->trig);
free_t:
kfree(t);
out1:
@@ -182,7 +182,7 @@ static int iio_sysfs_trigger_remove(int id)
}
iio_trigger_unregister(t->trig);
- iio_free_trigger(t->trig);
+ iio_trigger_free(t->trig);
list_del(&t->l);
kfree(t);
diff --git a/drivers/staging/ipack/Kconfig b/drivers/staging/ipack/Kconfig
new file mode 100644
index 000000000000..af321789dddb
--- /dev/null
+++ b/drivers/staging/ipack/Kconfig
@@ -0,0 +1,20 @@
+#
+# IPACK configuration.
+#
+
+menuconfig IPACK_BUS
+ tristate "IndustryPack bus support"
+ ---help---
+ If you say Y here you get support for the IndustryPack Framework
+ for drivers for many types of boards that support this industrial
+ bus. The IndustryPack Framework is a virtual bus allowing to
+ communicate between carrier and mezzanine cards connected through
+ this bus.
+
+if IPACK_BUS
+
+source "drivers/staging/ipack/bridges/Kconfig"
+
+source "drivers/staging/ipack/devices/Kconfig"
+
+endif # IPACK
diff --git a/drivers/staging/ipack/Makefile b/drivers/staging/ipack/Makefile
new file mode 100644
index 000000000000..85ff223616fd
--- /dev/null
+++ b/drivers/staging/ipack/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the IPACK bridge device drivers.
+#
+obj-$(CONFIG_IPACK_BUS) += ipack.o
+obj-y += devices/
+obj-y += bridges/
diff --git a/drivers/staging/ipack/TODO b/drivers/staging/ipack/TODO
new file mode 100644
index 000000000000..3a45a53afd88
--- /dev/null
+++ b/drivers/staging/ipack/TODO
@@ -0,0 +1,46 @@
+ TODO
+ ====
+Introduction
+============
+
+These drivers add support for IndustryPack devices: carrier and mezzanine
+boards.
+
+The ipack driver is just an abstraction of the bus providing the common
+operations between the two kind of boards.
+
+TODO
+====
+
+TPCI-200
+--------
+
+* It receives the name of the mezzanine plugged in each slot by SYSFS.
+ No autodetection supported yet, because the mezzanine driver could not be
+ loaded at the time that the tpci200 driver loads.
+
+* It has a linked list with the tpci200 devices it is managing. Get rid of it
+ and use driver_for_each_device() instead.
+
+IP-OCTAL
+--------
+
+* It has a linked list which saves the devices it is currently
+ managing. It should use the driver_for_each_device() function. It is not there
+ due to the impossibility of using container_of macro to recover the
+ corresponding "struct ipoctal" because the attribute "struct ipack_device" is
+ a pointer. This code should be refactored.
+
+Ipack
+-----
+
+* The structures and API exported can be improved a lot. For example, the
+ way to unregistering mezzanine devices, doing the mezzanine driver a call to
+ remove_device() to notify the carrier driver, or the opposite with the call to
+ the ipack_driver_ops' remove() function could be improved.
+
+
+Contact
+=======
+
+Contact: Samuel Iglesias Gonsalvez <siglesias@igalia.com> \ No newline at end of file
diff --git a/drivers/staging/ipack/bridges/Kconfig b/drivers/staging/ipack/bridges/Kconfig
new file mode 100644
index 000000000000..97c837ea7a03
--- /dev/null
+++ b/drivers/staging/ipack/bridges/Kconfig
@@ -0,0 +1,8 @@
+config BOARD_TPCI200
+ tristate "TEWS TPCI-200 support for IndustryPack bus"
+ depends on IPACK_BUS
+ depends on PCI
+ help
+ This driver supports the TEWS TPCI200 device for the IndustryPack bus.
+ default n
+
diff --git a/drivers/staging/ipack/bridges/Makefile b/drivers/staging/ipack/bridges/Makefile
new file mode 100644
index 000000000000..d8b76459300f
--- /dev/null
+++ b/drivers/staging/ipack/bridges/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_BOARD_TPCI200) += tpci200.o
diff --git a/drivers/staging/ipack/bridges/tpci200.c b/drivers/staging/ipack/bridges/tpci200.c
new file mode 100644
index 000000000000..ad2870750235
--- /dev/null
+++ b/drivers/staging/ipack/bridges/tpci200.c
@@ -0,0 +1,1141 @@
+/**
+ * tpci200.c
+ *
+ * driver for the TEWS TPCI-200 device
+ * Copyright (c) 2009 Nicolas Serafini, EIC2 SA
+ * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN
+ * Copyright (c) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include "tpci200.h"
+
+static struct ipack_bus_ops tpci200_bus_ops;
+
+/* TPCI200 controls registers */
+static int control_reg[] = {
+ TPCI200_CONTROL_A_REG,
+ TPCI200_CONTROL_B_REG,
+ TPCI200_CONTROL_C_REG,
+ TPCI200_CONTROL_D_REG
+};
+
+/* Linked list to save the registered devices */
+static LIST_HEAD(tpci200_list);
+
+static int tpci200_slot_unregister(struct ipack_device *dev);
+
+static struct tpci200_board *check_slot(struct ipack_device *dev)
+{
+ struct tpci200_board *tpci200;
+ int found = 0;
+
+ if (dev == NULL) {
+ pr_info("Slot doesn't exist.\n");
+ return NULL;
+ }
+
+ list_for_each_entry(tpci200, &tpci200_list, list) {
+ if (tpci200->number == dev->bus_nr) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ pr_err("Carrier not found\n");
+ return NULL;
+ }
+
+ if (dev->slot >= TPCI200_NB_SLOT) {
+ pr_info("Slot [%d:%d] doesn't exist! Last tpci200 slot is %d.\n",
+ dev->bus_nr, dev->slot, TPCI200_NB_SLOT-1);
+ return NULL;
+ }
+
+ BUG_ON(tpci200->slots == NULL);
+ if (tpci200->slots[dev->slot].dev == NULL) {
+ pr_info("Slot [%d:%d] is not registered !\n", dev->bus_nr,
+ dev->slot);
+ return NULL;
+ }
+
+ return tpci200;
+}
+
+static inline unsigned char __tpci200_read8(void __iomem *address,
+ unsigned long offset)
+{
+ return ioread8(address + (offset^1));
+}
+
+static inline unsigned short __tpci200_read16(void __iomem *address,
+ unsigned long offset)
+{
+ return ioread16(address + offset);
+}
+
+static inline unsigned int __tpci200_read32(void __iomem *address,
+ unsigned long offset)
+{
+ return swahw32(ioread32(address + offset));
+}
+
+static inline void __tpci200_write8(unsigned char value,
+ void __iomem *address, unsigned long offset)
+{
+ iowrite8(value, address+(offset^1));
+}
+
+static inline void __tpci200_write16(unsigned short value,
+ void __iomem *address,
+ unsigned long offset)
+{
+ iowrite16(value, address+offset);
+}
+
+static inline void __tpci200_write32(unsigned int value,
+ void __iomem *address,
+ unsigned long offset)
+{
+ iowrite32(swahw32(value), address+offset);
+}
+
+static struct ipack_addr_space *get_slot_address_space(struct ipack_device *dev,
+ int space)
+{
+ struct ipack_addr_space *addr;
+
+ switch (space) {
+ case IPACK_IO_SPACE:
+ addr = &dev->io_space;
+ break;
+ case IPACK_ID_SPACE:
+ addr = &dev->id_space;
+ break;
+ case IPACK_MEM_SPACE:
+ addr = &dev->mem_space;
+ break;
+ default:
+ pr_err("Slot [%d:%d] space number %d doesn't exist !\n",
+ dev->bus_nr, dev->slot, space);
+ return NULL;
+ break;
+ }
+
+ if ((addr->size == 0) || (addr->address == NULL)) {
+ pr_err("Error, slot space not mapped !\n");
+ return NULL;
+ }
+
+ return addr;
+}
+
+static int tpci200_read8(struct ipack_device *dev, int space,
+ unsigned long offset, unsigned char *value)
+{
+ struct ipack_addr_space *addr;
+ struct tpci200_board *tpci200;
+
+ tpci200 = check_slot(dev);
+ if (tpci200 == NULL)
+ return -EINVAL;
+
+ addr = get_slot_address_space(dev, space);
+ if (addr == NULL)
+ return -EINVAL;
+
+ if (offset >= addr->size) {
+ pr_err("Error, slot space offset error !\n");
+ return -EFAULT;
+ }
+
+ *value = __tpci200_read8(addr->address, offset);
+
+ return 0;
+}
+
+static int tpci200_read16(struct ipack_device *dev, int space,
+ unsigned long offset, unsigned short *value)
+{
+ struct ipack_addr_space *addr;
+ struct tpci200_board *tpci200;
+
+ tpci200 = check_slot(dev);
+ if (tpci200 == NULL)
+ return -EINVAL;
+
+ addr = get_slot_address_space(dev, space);
+ if (addr == NULL)
+ return -EINVAL;
+
+ if ((offset+2) >= addr->size) {
+ pr_err("Error, slot space offset error !\n");
+ return -EFAULT;
+ }
+ *value = __tpci200_read16(addr->address, offset);
+
+ return 0;
+}
+
+static int tpci200_read32(struct ipack_device *dev, int space,
+ unsigned long offset, unsigned int *value)
+{
+ struct ipack_addr_space *addr;
+ struct tpci200_board *tpci200;
+
+ tpci200 = check_slot(dev);
+ if (tpci200 == NULL)
+ return -EINVAL;
+
+ addr = get_slot_address_space(dev, space);
+ if (addr == NULL)
+ return -EINVAL;
+
+ if ((offset+4) >= addr->size) {
+ pr_err("Error, slot space offset error !\n");
+ return -EFAULT;
+ }
+
+ *value = __tpci200_read32(addr->address, offset);
+
+ return 0;
+}
+
+static int tpci200_write8(struct ipack_device *dev, int space,
+ unsigned long offset, unsigned char value)
+{
+ struct ipack_addr_space *addr;
+ struct tpci200_board *tpci200;
+
+ tpci200 = check_slot(dev);
+ if (tpci200 == NULL)
+ return -EINVAL;
+
+ addr = get_slot_address_space(dev, space);
+ if (addr == NULL)
+ return -EINVAL;
+
+ if (offset >= addr->size) {
+ pr_err("Error, slot space offset error !\n");
+ return -EFAULT;
+ }
+
+ __tpci200_write8(value, addr->address, offset);
+
+ return 0;
+}
+
+static int tpci200_write16(struct ipack_device *dev, int space,
+ unsigned long offset, unsigned short value)
+{
+ struct ipack_addr_space *addr;
+ struct tpci200_board *tpci200;
+
+ tpci200 = check_slot(dev);
+ if (tpci200 == NULL)
+ return -EINVAL;
+
+ addr = get_slot_address_space(dev, space);
+ if (addr == NULL)
+ return -EINVAL;
+
+ if ((offset+2) >= addr->size) {
+ pr_err("Error, slot space offset error !\n");
+ return -EFAULT;
+ }
+
+ __tpci200_write16(value, addr->address, offset);
+
+ return 0;
+}
+
+static int tpci200_write32(struct ipack_device *dev, int space,
+ unsigned long offset, unsigned int value)
+{
+ struct ipack_addr_space *addr;
+ struct tpci200_board *tpci200;
+
+ tpci200 = check_slot(dev);
+ if (tpci200 == NULL)
+ return -EINVAL;
+
+ addr = get_slot_address_space(dev, space);
+ if (addr == NULL)
+ return -EINVAL;
+
+ if ((offset+4) >= addr->size) {
+ pr_err("Error, slot space offset error !\n");
+ return -EFAULT;
+ }
+
+ __tpci200_write32(value, addr->address, offset);
+
+ return 0;
+}
+
+static void tpci200_unregister(struct tpci200_board *tpci200)
+{
+ int i;
+
+ free_irq(tpci200->info->pdev->irq, (void *) tpci200);
+
+ pci_iounmap(tpci200->info->pdev, tpci200->info->interface_regs);
+ pci_iounmap(tpci200->info->pdev, tpci200->info->ioidint_space);
+ pci_iounmap(tpci200->info->pdev, tpci200->info->mem8_space);
+
+ pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR);
+ pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR);
+ pci_release_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR);
+
+ pci_disable_device(tpci200->info->pdev);
+ pci_dev_put(tpci200->info->pdev);
+
+ kfree(tpci200->info);
+
+ for (i = 0; i < TPCI200_NB_SLOT; i++) {
+ tpci200->slots[i].io_phys.address = NULL;
+ tpci200->slots[i].io_phys.size = 0;
+ tpci200->slots[i].id_phys.address = NULL;
+ tpci200->slots[i].id_phys.size = 0;
+ tpci200->slots[i].mem_phys.address = NULL;
+ tpci200->slots[i].mem_phys.size = 0;
+ }
+}
+
+static irqreturn_t tpci200_interrupt(int irq, void *dev_id)
+{
+ struct tpci200_board *tpci200 = (struct tpci200_board *) dev_id;
+ int i;
+ unsigned long flags;
+ unsigned short status_reg, reg_value;
+ unsigned short unhandled_ints = 0;
+ irqreturn_t ret = IRQ_NONE;
+
+ spin_lock_irqsave(&tpci200->info->access_lock, flags);
+
+ /* Read status register */
+ status_reg = readw(tpci200->info->interface_regs +
+ TPCI200_STATUS_REG);
+
+ if (status_reg & TPCI200_SLOT_INT_MASK) {
+ unhandled_ints = status_reg & TPCI200_SLOT_INT_MASK;
+ /* callback to the IRQ handler for the corresponding slot */
+ for (i = 0; i < TPCI200_NB_SLOT; i++) {
+ if ((tpci200->slots[i].irq != NULL) &&
+ (status_reg & ((TPCI200_A_INT0 | TPCI200_A_INT1) << (2*i)))) {
+
+ ret = tpci200->slots[i].irq->handler(tpci200->slots[i].irq->arg);
+
+ /* Dummy reads */
+ readw(tpci200->slots[i].dev->io_space.address +
+ 0xC0);
+ readw(tpci200->slots[i].dev->io_space.address +
+ 0xC2);
+
+ unhandled_ints &= ~(((TPCI200_A_INT0 | TPCI200_A_INT1) << (2*i)));
+ }
+ }
+ }
+ /* Interrupt not handled are disabled */
+ if (unhandled_ints) {
+ for (i = 0; i < TPCI200_NB_SLOT; i++) {
+ if (unhandled_ints & ((TPCI200_INT0_EN | TPCI200_INT1_EN) << (2*i))) {
+ pr_info("No registered ISR for slot [%d:%d]!. IRQ will be disabled.\n",
+ tpci200->number, i);
+ reg_value = readw(
+ tpci200->info->interface_regs +
+ control_reg[i]);
+ reg_value &=
+ ~(TPCI200_INT0_EN | TPCI200_INT1_EN);
+ writew(reg_value,
+ (tpci200->info->interface_regs +
+ control_reg[i]));
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&tpci200->info->access_lock, flags);
+ return ret;
+}
+
+#ifdef CONFIG_SYSFS
+
+static struct ipack_device *tpci200_slot_register(unsigned int tpci200_number,
+ unsigned int slot_position)
+{
+ int found = 0;
+ struct ipack_device *dev;
+ struct tpci200_board *tpci200;
+
+ list_for_each_entry(tpci200, &tpci200_list, list) {
+ if (tpci200->number == tpci200_number) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ pr_err("carrier board not found for the device\n");
+ return NULL;
+ }
+
+ if (slot_position >= TPCI200_NB_SLOT) {
+ pr_info("Slot [%d:%d] doesn't exist!\n", tpci200_number,
+ slot_position);
+ return NULL;
+ }
+
+ if (mutex_lock_interruptible(&tpci200->mutex))
+ return NULL;
+
+ if (tpci200->slots[slot_position].dev != NULL) {
+ pr_err("Slot [%d:%d] already installed !\n", tpci200_number,
+ slot_position);
+ goto err_unlock;
+ }
+
+ /*
+ * Give the same IRQ number as the slot number.
+ * The TPCI200 has assigned his own two IRQ by PCI bus driver
+ */
+ dev = ipack_device_register(tpci200->info->ipack_bus,
+ slot_position, slot_position);
+ if (dev == NULL) {
+ pr_info("Slot [%d:%d] Unable to register an ipack device\n",
+ tpci200_number, slot_position);
+ goto err_unlock;
+ }
+
+ tpci200->slots[slot_position].dev = dev;
+ mutex_unlock(&tpci200->mutex);
+ return dev;
+
+err_unlock:
+ mutex_unlock(&tpci200->mutex);
+ return NULL;
+}
+
+static ssize_t tpci200_store_board(struct device *pdev, const char *buf,
+ size_t count, int slot)
+{
+ struct tpci200_board *card = dev_get_drvdata(pdev);
+ struct ipack_device *dev = card->slots[slot].dev;
+
+ if (dev != NULL)
+ return -EBUSY;
+
+ dev = tpci200_slot_register(card->number, slot);
+ if (dev == NULL)
+ return -ENODEV;
+
+ return count;
+}
+
+static ssize_t tpci200_show_board(struct device *pdev, char *buf, int slot)
+{
+ struct tpci200_board *card = dev_get_drvdata(pdev);
+ struct ipack_device *dev = card->slots[slot].dev;
+
+ if (dev != NULL)
+ return snprintf(buf, PAGE_SIZE, "%s\n", dev_name(&dev->dev));
+ else
+ return snprintf(buf, PAGE_SIZE, "none\n");
+}
+
+static ssize_t tpci200_show_description(struct device *pdev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE,
+ "TEWS tpci200 carrier PCI for Industry-pack mezzanines.\n");
+}
+
+static ssize_t tpci200_show_board_slot0(struct device *pdev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return tpci200_show_board(pdev, buf, 0);
+}
+
+static ssize_t tpci200_store_board_slot0(struct device *pdev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return tpci200_store_board(pdev, buf, count, 0);
+}
+
+static ssize_t tpci200_show_board_slot1(struct device *pdev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return tpci200_show_board(pdev, buf, 1);
+}
+
+static ssize_t tpci200_store_board_slot1(struct device *pdev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return tpci200_store_board(pdev, buf, count, 1);
+}
+
+static ssize_t tpci200_show_board_slot2(struct device *pdev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return tpci200_show_board(pdev, buf, 2);
+}
+
+static ssize_t tpci200_store_board_slot2(struct device *pdev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return tpci200_store_board(pdev, buf, count, 2);
+}
+
+
+static ssize_t tpci200_show_board_slot3(struct device *pdev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return tpci200_show_board(pdev, buf, 3);
+}
+
+static ssize_t tpci200_store_board_slot3(struct device *pdev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return tpci200_store_board(pdev, buf, count, 3);
+}
+
+/* Declaration of the device attributes for the TPCI200 */
+static DEVICE_ATTR(description, S_IRUGO,
+ tpci200_show_description, NULL);
+static DEVICE_ATTR(board_slot0, S_IRUGO | S_IWUSR,
+ tpci200_show_board_slot0, tpci200_store_board_slot0);
+static DEVICE_ATTR(board_slot1, S_IRUGO | S_IWUSR,
+ tpci200_show_board_slot1, tpci200_store_board_slot1);
+static DEVICE_ATTR(board_slot2, S_IRUGO | S_IWUSR,
+ tpci200_show_board_slot2, tpci200_store_board_slot2);
+static DEVICE_ATTR(board_slot3, S_IRUGO | S_IWUSR,
+ tpci200_show_board_slot3, tpci200_store_board_slot3);
+
+static struct attribute *tpci200_attrs[] = {
+ &dev_attr_description.attr,
+ &dev_attr_board_slot0.attr,
+ &dev_attr_board_slot1.attr,
+ &dev_attr_board_slot2.attr,
+ &dev_attr_board_slot3.attr,
+ NULL,
+};
+
+static struct attribute_group tpci200_attr_group = {
+ .attrs = tpci200_attrs,
+};
+
+static int tpci200_create_sysfs_files(struct tpci200_board *card)
+{
+ return sysfs_create_group(&card->info->pdev->dev.kobj,
+ &tpci200_attr_group);
+}
+
+static void tpci200_remove_sysfs_files(struct tpci200_board *card)
+{
+ sysfs_remove_group(&card->info->pdev->dev.kobj, &tpci200_attr_group);
+}
+
+#else
+
+static int tpci200_create_sysfs_files(struct tpci200_board *card)
+{
+ return 0;
+}
+
+static void tpci200_remove_sysfs_files(struct tpci200_board *card)
+{
+}
+
+#endif /* CONFIG_SYSFS */
+
+static int tpci200_register(struct tpci200_board *tpci200)
+{
+ int i;
+ int res;
+ unsigned long ioidint_base;
+ unsigned long mem_base;
+ unsigned short slot_ctrl;
+
+ if (pci_enable_device(tpci200->info->pdev) < 0)
+ return -ENODEV;
+
+ if (tpci200_create_sysfs_files(tpci200) < 0) {
+ pr_err("failed creating sysfs files\n");
+ res = -EFAULT;
+ goto out_disable_pci;
+ }
+
+ /* Request IP interface register (Bar 2) */
+ res = pci_request_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR,
+ "Carrier IP interface registers");
+ if (res) {
+ pr_err("(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 2 !",
+ tpci200->info->pdev->bus->number,
+ tpci200->info->pdev->devfn);
+ goto out_remove_sysfs;
+ }
+
+ /* Request IO ID INT space (Bar 3) */
+ res = pci_request_region(tpci200->info->pdev,
+ TPCI200_IO_ID_INT_SPACES_BAR,
+ "Carrier IO ID INT space");
+ if (res) {
+ pr_err("(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 3 !",
+ tpci200->info->pdev->bus->number,
+ tpci200->info->pdev->devfn);
+ goto out_release_ip_space;
+ }
+
+ /* Request MEM space (Bar 4) */
+ res = pci_request_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR,
+ "Carrier MEM space");
+ if (res) {
+ pr_err("(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 4!",
+ tpci200->info->pdev->bus->number,
+ tpci200->info->pdev->devfn);
+ goto out_release_ioid_int_space;
+ }
+
+ /* Map internal tpci200 driver user space */
+ tpci200->info->interface_regs =
+ ioremap(pci_resource_start(tpci200->info->pdev,
+ TPCI200_IP_INTERFACE_BAR),
+ TPCI200_IFACE_SIZE);
+ tpci200->info->ioidint_space =
+ ioremap(pci_resource_start(tpci200->info->pdev,
+ TPCI200_IO_ID_INT_SPACES_BAR),
+ TPCI200_IOIDINT_SIZE);
+ tpci200->info->mem8_space =
+ ioremap(pci_resource_start(tpci200->info->pdev,
+ TPCI200_MEM8_SPACE_BAR),
+ TPCI200_MEM8_SIZE);
+
+ spin_lock_init(&tpci200->info->access_lock);
+ ioidint_base = pci_resource_start(tpci200->info->pdev,
+ TPCI200_IO_ID_INT_SPACES_BAR);
+ mem_base = pci_resource_start(tpci200->info->pdev,
+ TPCI200_MEM8_SPACE_BAR);
+
+ /* Set the default parameters of the slot
+ * INT0 disabled, level sensitive
+ * INT1 disabled, level sensitive
+ * error interrupt disabled
+ * timeout interrupt disabled
+ * recover time disabled
+ * clock rate 8 MHz
+ */
+ slot_ctrl = 0;
+
+ /* Set all slot physical address space */
+ for (i = 0; i < TPCI200_NB_SLOT; i++) {
+ tpci200->slots[i].io_phys.address =
+ (void __iomem *)ioidint_base +
+ TPCI200_IO_SPACE_OFF + TPCI200_IO_SPACE_GAP*i;
+ tpci200->slots[i].io_phys.size = TPCI200_IO_SPACE_SIZE;
+
+ tpci200->slots[i].id_phys.address =
+ (void __iomem *)ioidint_base +
+ TPCI200_ID_SPACE_OFF + TPCI200_ID_SPACE_GAP*i;
+ tpci200->slots[i].id_phys.size = TPCI200_ID_SPACE_SIZE;
+
+ tpci200->slots[i].mem_phys.address =
+ (void __iomem *)mem_base + TPCI200_MEM8_GAP*i;
+ tpci200->slots[i].mem_phys.size = TPCI200_MEM8_SIZE;
+
+ writew(slot_ctrl, (tpci200->info->interface_regs +
+ control_reg[i]));
+ }
+
+ res = request_irq(tpci200->info->pdev->irq,
+ tpci200_interrupt, IRQF_SHARED,
+ KBUILD_MODNAME, (void *) tpci200);
+ if (res) {
+ pr_err("(bn 0x%X, sn 0x%X) unable to register IRQ !",
+ tpci200->info->pdev->bus->number,
+ tpci200->info->pdev->devfn);
+ tpci200_unregister(tpci200);
+ goto out_err;
+ }
+
+ return 0;
+
+out_release_ioid_int_space:
+ pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR);
+out_release_ip_space:
+ pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR);
+out_remove_sysfs:
+ tpci200_remove_sysfs_files(tpci200);
+out_disable_pci:
+ pci_disable_device(tpci200->info->pdev);
+out_err:
+ return res;
+}
+
+static int __tpci200_request_irq(struct tpci200_board *tpci200,
+ struct ipack_device *dev)
+{
+ unsigned short slot_ctrl;
+
+ /* Set the default parameters of the slot
+ * INT0 enabled, level sensitive
+ * INT1 enabled, level sensitive
+ * error interrupt disabled
+ * timeout interrupt disabled
+ * recover time disabled
+ * clock rate 8 MHz
+ */
+ slot_ctrl = TPCI200_INT0_EN | TPCI200_INT1_EN;
+ writew(slot_ctrl, (tpci200->info->interface_regs +
+ control_reg[dev->slot]));
+
+ return 0;
+}
+
+static void __tpci200_free_irq(struct tpci200_board *tpci200,
+ struct ipack_device *dev)
+{
+ unsigned short slot_ctrl;
+
+ /* Set the default parameters of the slot
+ * INT0 disabled, level sensitive
+ * INT1 disabled, level sensitive
+ * error interrupt disabled
+ * timeout interrupt disabled
+ * recover time disabled
+ * clock rate 8 MHz
+ */
+ slot_ctrl = 0;
+ writew(slot_ctrl, (tpci200->info->interface_regs +
+ control_reg[dev->slot]));
+}
+
+static int tpci200_free_irq(struct ipack_device *dev)
+{
+ int res;
+ struct slot_irq *slot_irq;
+ struct tpci200_board *tpci200;
+
+ tpci200 = check_slot(dev);
+ if (tpci200 == NULL) {
+ res = -EINVAL;
+ goto out;
+ }
+
+ if (mutex_lock_interruptible(&tpci200->mutex)) {
+ res = -ERESTARTSYS;
+ goto out;
+ }
+
+ if (tpci200->slots[dev->slot].irq == NULL) {
+ res = -EINVAL;
+ goto out_unlock;
+ }
+
+ __tpci200_free_irq(tpci200, dev);
+ slot_irq = tpci200->slots[dev->slot].irq;
+ tpci200->slots[dev->slot].irq = NULL;
+ kfree(slot_irq);
+
+out_unlock:
+ mutex_unlock(&tpci200->mutex);
+out:
+ return res;
+}
+
+static int tpci200_slot_unmap_space(struct ipack_device *dev, int space)
+{
+ int res;
+ struct ipack_addr_space *virt_addr_space;
+ struct tpci200_board *tpci200;
+
+ tpci200 = check_slot(dev);
+ if (tpci200 == NULL) {
+ res = -EINVAL;
+ goto out;
+ }
+
+ if (mutex_lock_interruptible(&tpci200->mutex)) {
+ res = -ERESTARTSYS;
+ goto out;
+ }
+
+ switch (space) {
+ case IPACK_IO_SPACE:
+ if (dev->io_space.address == NULL) {
+ pr_info("Slot [%d:%d] IO space not mapped !\n",
+ dev->bus_nr, dev->slot);
+ goto out_unlock;
+ }
+ virt_addr_space = &dev->io_space;
+ break;
+ case IPACK_ID_SPACE:
+ if (dev->id_space.address == NULL) {
+ pr_info("Slot [%d:%d] ID space not mapped !\n",
+ dev->bus_nr, dev->slot);
+ goto out_unlock;
+ }
+ virt_addr_space = &dev->id_space;
+ break;
+ case IPACK_MEM_SPACE:
+ if (dev->mem_space.address == NULL) {
+ pr_info("Slot [%d:%d] MEM space not mapped !\n",
+ dev->bus_nr, dev->slot);
+ goto out_unlock;
+ }
+ virt_addr_space = &dev->mem_space;
+ break;
+ default:
+ pr_err("Slot [%d:%d] space number %d doesn't exist !\n",
+ dev->bus_nr, dev->slot, space);
+ res = -EINVAL;
+ goto out_unlock;
+ break;
+ }
+
+ iounmap(virt_addr_space->address);
+
+ virt_addr_space->address = NULL;
+ virt_addr_space->size = 0;
+out_unlock:
+ mutex_unlock(&tpci200->mutex);
+out:
+ return res;
+}
+
+static int tpci200_slot_unregister(struct ipack_device *dev)
+{
+ struct tpci200_board *tpci200;
+
+ if (dev == NULL)
+ return -ENODEV;
+
+ tpci200 = check_slot(dev);
+ if (tpci200 == NULL)
+ return -EINVAL;
+
+ tpci200_free_irq(dev);
+
+ if (mutex_lock_interruptible(&tpci200->mutex))
+ return -ERESTARTSYS;
+
+ ipack_device_unregister(dev);
+ tpci200->slots[dev->slot].dev = NULL;
+ mutex_unlock(&tpci200->mutex);
+
+ return 0;
+}
+
+static int tpci200_slot_map_space(struct ipack_device *dev,
+ unsigned int memory_size, int space)
+{
+ int res;
+ unsigned int size_to_map;
+ void __iomem *phys_address;
+ struct ipack_addr_space *virt_addr_space;
+ struct tpci200_board *tpci200;
+
+ tpci200 = check_slot(dev);
+ if (tpci200 == NULL) {
+ res = -EINVAL;
+ goto out;
+ }
+
+ if (mutex_lock_interruptible(&tpci200->mutex)) {
+ res = -ERESTARTSYS;
+ goto out;
+ }
+
+ switch (space) {
+ case IPACK_IO_SPACE:
+ if (dev->io_space.address != NULL) {
+ pr_err("Slot [%d:%d] IO space already mapped !\n",
+ tpci200->number, dev->slot);
+ res = -EINVAL;
+ goto out_unlock;
+ }
+ virt_addr_space = &dev->io_space;
+
+ phys_address = tpci200->slots[dev->slot].io_phys.address;
+ size_to_map = tpci200->slots[dev->slot].io_phys.size;
+ break;
+ case IPACK_ID_SPACE:
+ if (dev->id_space.address != NULL) {
+ pr_err("Slot [%d:%d] ID space already mapped !\n",
+ tpci200->number, dev->slot);
+ res = -EINVAL;
+ goto out_unlock;
+ }
+ virt_addr_space = &dev->id_space;
+
+ phys_address = tpci200->slots[dev->slot].id_phys.address;
+ size_to_map = tpci200->slots[dev->slot].id_phys.size;
+ break;
+ case IPACK_MEM_SPACE:
+ if (dev->mem_space.address != NULL) {
+ pr_err("Slot [%d:%d] MEM space already mapped !\n",
+ tpci200->number, dev->slot);
+ res = -EINVAL;
+ goto out_unlock;
+ }
+ virt_addr_space = &dev->mem_space;
+
+ if (memory_size > tpci200->slots[dev->slot].mem_phys.size) {
+ pr_err("Slot [%d:%d] request is 0x%X memory, only 0x%X available !\n",
+ dev->bus_nr, dev->slot, memory_size,
+ tpci200->slots[dev->slot].mem_phys.size);
+ res = -EINVAL;
+ goto out_unlock;
+ }
+
+ phys_address = tpci200->slots[dev->slot].mem_phys.address;
+ size_to_map = memory_size;
+ break;
+ default:
+ pr_err("Slot [%d:%d] space %d doesn't exist !\n",
+ tpci200->number, dev->slot, space);
+ res = -EINVAL;
+ goto out_unlock;
+ break;
+ }
+
+ virt_addr_space->size = size_to_map;
+ virt_addr_space->address =
+ ioremap((unsigned long)phys_address, size_to_map);
+
+out_unlock:
+ mutex_unlock(&tpci200->mutex);
+out:
+ return res;
+}
+
+static int tpci200_request_irq(struct ipack_device *dev, int vector,
+ int (*handler)(void *), void *arg)
+{
+ int res;
+ struct slot_irq *slot_irq;
+ struct tpci200_board *tpci200;
+
+ tpci200 = check_slot(dev);
+ if (tpci200 == NULL) {
+ res = -EINVAL;
+ goto out;
+ }
+
+ if (mutex_lock_interruptible(&tpci200->mutex)) {
+ res = -ERESTARTSYS;
+ goto out;
+ }
+
+ if (tpci200->slots[dev->slot].irq != NULL) {
+ pr_err("Slot [%d:%d] IRQ already registered !\n", dev->bus_nr,
+ dev->slot);
+ res = -EINVAL;
+ goto out_unlock;
+ }
+
+ slot_irq = kzalloc(sizeof(struct slot_irq), GFP_KERNEL);
+ if (slot_irq == NULL) {
+ pr_err("Slot [%d:%d] unable to allocate memory for IRQ !\n",
+ dev->bus_nr, dev->slot);
+ res = -ENOMEM;
+ goto out_unlock;
+ }
+
+ /*
+ * WARNING: Setup Interrupt Vector in the IndustryPack device
+ * before an IRQ request.
+ * Read the User Manual of your IndustryPack device to know
+ * where to write the vector in memory.
+ */
+ slot_irq->vector = vector;
+ slot_irq->handler = handler;
+ slot_irq->arg = arg;
+ slot_irq->name = dev_name(&dev->dev);
+
+ tpci200->slots[dev->slot].irq = slot_irq;
+ res = __tpci200_request_irq(tpci200, dev);
+
+out_unlock:
+ mutex_unlock(&tpci200->mutex);
+out:
+ return res;
+}
+
+static void tpci200_slot_remove(struct tpci200_slot *slot)
+{
+ if ((slot->dev == NULL) ||
+ (slot->dev->driver->ops->remove == NULL))
+ return;
+
+ slot->dev->driver->ops->remove(slot->dev);
+}
+
+static void tpci200_uninstall(struct tpci200_board *tpci200)
+{
+ int i;
+
+ for (i = 0; i < TPCI200_NB_SLOT; i++)
+ tpci200_slot_remove(&tpci200->slots[i]);
+
+ tpci200_unregister(tpci200);
+ kfree(tpci200->slots);
+}
+
+static struct ipack_bus_ops tpci200_bus_ops = {
+ .map_space = tpci200_slot_map_space,
+ .unmap_space = tpci200_slot_unmap_space,
+ .request_irq = tpci200_request_irq,
+ .free_irq = tpci200_free_irq,
+ .read8 = tpci200_read8,
+ .read16 = tpci200_read16,
+ .read32 = tpci200_read32,
+ .write8 = tpci200_write8,
+ .write16 = tpci200_write16,
+ .write32 = tpci200_write32,
+ .remove_device = tpci200_slot_unregister,
+};
+
+static int tpci200_install(struct tpci200_board *tpci200)
+{
+ int res;
+
+ tpci200->slots = kzalloc(
+ TPCI200_NB_SLOT * sizeof(struct tpci200_slot), GFP_KERNEL);
+ if (tpci200->slots == NULL) {
+ res = -ENOMEM;
+ goto out_err;
+ }
+
+ res = tpci200_register(tpci200);
+ if (res)
+ goto out_free;
+
+ mutex_init(&tpci200->mutex);
+ return 0;
+
+out_free:
+ kfree(tpci200->slots);
+ tpci200->slots = NULL;
+out_err:
+ return res;
+}
+
+static int tpci200_pciprobe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ int ret;
+ struct tpci200_board *tpci200;
+
+ tpci200 = kzalloc(sizeof(struct tpci200_board), GFP_KERNEL);
+ if (!tpci200)
+ return -ENOMEM;
+
+ tpci200->info = kzalloc(sizeof(struct tpci200_infos), GFP_KERNEL);
+ if (!tpci200->info) {
+ kfree(tpci200);
+ return -ENOMEM;
+ }
+
+ /* Save struct pci_dev pointer */
+ tpci200->info->pdev = pdev;
+ tpci200->info->id_table = (struct pci_device_id *)id;
+
+ /* register the device and initialize it */
+ ret = tpci200_install(tpci200);
+ if (ret) {
+ pr_err("Error during tpci200 install !\n");
+ kfree(tpci200->info);
+ kfree(tpci200);
+ return -ENODEV;
+ }
+
+ /* Register the carrier in the industry pack bus driver */
+ tpci200->info->ipack_bus = ipack_bus_register(&pdev->dev,
+ TPCI200_NB_SLOT,
+ &tpci200_bus_ops);
+ if (!tpci200->info->ipack_bus) {
+ pr_err("error registering the carrier on ipack driver\n");
+ tpci200_uninstall(tpci200);
+ kfree(tpci200->info);
+ kfree(tpci200);
+ return -EFAULT;
+ }
+
+ /* save the bus number given by ipack to logging purpose */
+ tpci200->number = tpci200->info->ipack_bus->bus_nr;
+ dev_set_drvdata(&pdev->dev, tpci200);
+ /* add the registered device in an internal linked list */
+ list_add_tail(&tpci200->list, &tpci200_list);
+ return ret;
+}
+
+static void __tpci200_pci_remove(struct tpci200_board *tpci200)
+{
+ tpci200_uninstall(tpci200);
+ tpci200_remove_sysfs_files(tpci200);
+ list_del(&tpci200->list);
+ ipack_bus_unregister(tpci200->info->ipack_bus);
+ kfree(tpci200->info);
+ kfree(tpci200);
+}
+
+static void __devexit tpci200_pci_remove(struct pci_dev *dev)
+{
+ struct tpci200_board *tpci200, *next;
+
+ /* Search the registered device to uninstall it */
+ list_for_each_entry_safe(tpci200, next, &tpci200_list, list) {
+ if (tpci200->info->pdev == dev) {
+ __tpci200_pci_remove(tpci200);
+ break;
+ }
+ }
+}
+
+static struct pci_device_id tpci200_idtable[2] = {
+ { TPCI200_VENDOR_ID, TPCI200_DEVICE_ID, TPCI200_SUBVENDOR_ID,
+ TPCI200_SUBDEVICE_ID },
+ { 0, },
+};
+
+static struct pci_driver tpci200_pci_drv = {
+ .name = "tpci200",
+ .id_table = tpci200_idtable,
+ .probe = tpci200_pciprobe,
+ .remove = __devexit_p(tpci200_pci_remove),
+};
+
+static int __init tpci200_drvr_init_module(void)
+{
+ return pci_register_driver(&tpci200_pci_drv);
+}
+
+static void __exit tpci200_drvr_exit_module(void)
+{
+ struct tpci200_board *tpci200, *next;
+
+ list_for_each_entry_safe(tpci200, next, &tpci200_list, list)
+ __tpci200_pci_remove(tpci200);
+
+ pci_unregister_driver(&tpci200_pci_drv);
+}
+
+MODULE_DESCRIPTION("TEWS TPCI-200 device driver");
+MODULE_LICENSE("GPL");
+module_init(tpci200_drvr_init_module);
+module_exit(tpci200_drvr_exit_module);
diff --git a/drivers/staging/ipack/bridges/tpci200.h b/drivers/staging/ipack/bridges/tpci200.h
new file mode 100644
index 000000000000..0b547eedddc2
--- /dev/null
+++ b/drivers/staging/ipack/bridges/tpci200.h
@@ -0,0 +1,162 @@
+/**
+ * tpci200.h
+ *
+ * driver for the carrier TEWS TPCI-200
+ * Copyright (c) 2009 Nicolas Serafini, EIC2 SA
+ * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN
+ * Copyright (c) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ */
+
+#ifndef _TPCI200_H_
+#define _TPCI200_H_
+
+#include <linux/version.h>
+#include <linux/limits.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/swab.h>
+#include <linux/io.h>
+
+#include "../ipack.h"
+
+#define TPCI200_NB_SLOT 0x4
+#define TPCI200_NB_BAR 0x6
+
+#define TPCI200_VENDOR_ID 0x1498
+#define TPCI200_DEVICE_ID 0x30C8
+#define TPCI200_SUBVENDOR_ID 0x1498
+#define TPCI200_SUBDEVICE_ID 0x300A
+
+#define TPCI200_IP_INTERFACE_BAR 2
+#define TPCI200_IO_ID_INT_SPACES_BAR 3
+#define TPCI200_MEM16_SPACE_BAR 4
+#define TPCI200_MEM8_SPACE_BAR 5
+
+#define TPCI200_REVISION_REG 0x00
+#define TPCI200_CONTROL_A_REG 0x02
+#define TPCI200_CONTROL_B_REG 0x04
+#define TPCI200_CONTROL_C_REG 0x06
+#define TPCI200_CONTROL_D_REG 0x08
+#define TPCI200_RESET_REG 0x0A
+#define TPCI200_STATUS_REG 0x0C
+
+#define TPCI200_IFACE_SIZE 0x100
+
+#define TPCI200_IO_SPACE_OFF 0x0000
+#define TPCI200_IO_SPACE_GAP 0x0100
+#define TPCI200_IO_SPACE_SIZE 0x0080
+#define TPCI200_ID_SPACE_OFF 0x0080
+#define TPCI200_ID_SPACE_GAP 0x0100
+#define TPCI200_ID_SPACE_SIZE 0x0040
+#define TPCI200_INT_SPACE_OFF 0x00C0
+#define TPCI200_INT_SPACE_GAP 0x0100
+#define TPCI200_INT_SPACE_SIZE 0x0040
+#define TPCI200_IOIDINT_SIZE 0x0400
+
+#define TPCI200_MEM8_GAP 0x00400000
+#define TPCI200_MEM8_SIZE 0x00400000
+#define TPCI200_MEM16_GAP 0x00800000
+#define TPCI200_MEM16_SIZE 0x00800000
+
+#define TPCI200_INT0_EN 0x0040
+#define TPCI200_INT1_EN 0x0080
+#define TPCI200_INT0_EDGE 0x0010
+#define TPCI200_INT1_EDGE 0x0020
+#define TPCI200_ERR_INT_EN 0x0008
+#define TPCI200_TIME_INT_EN 0x0004
+#define TPCI200_RECOVER_EN 0x0002
+#define TPCI200_CLK32 0x0001
+
+#define TPCI200_A_RESET 0x0001
+#define TPCI200_B_RESET 0x0002
+#define TPCI200_C_RESET 0x0004
+#define TPCI200_D_RESET 0x0008
+
+#define TPCI200_A_TIMEOUT 0x1000
+#define TPCI200_B_TIMEOUT 0x2000
+#define TPCI200_C_TIMEOUT 0x4000
+#define TPCI200_D_TIMEOUT 0x8000
+
+#define TPCI200_A_ERROR 0x0100
+#define TPCI200_B_ERROR 0x0200
+#define TPCI200_C_ERROR 0x0400
+#define TPCI200_D_ERROR 0x0800
+
+#define TPCI200_A_INT0 0x0001
+#define TPCI200_A_INT1 0x0002
+#define TPCI200_B_INT0 0x0004
+#define TPCI200_B_INT1 0x0008
+#define TPCI200_C_INT0 0x0010
+#define TPCI200_C_INT1 0x0020
+#define TPCI200_D_INT0 0x0040
+#define TPCI200_D_INT1 0x0080
+
+#define TPCI200_SLOT_INT_MASK 0x00FF
+
+#define VME_IOID_SPACE "IOID"
+#define VME_MEM_SPACE "MEM"
+
+/**
+ * struct slot_irq - slot IRQ definition.
+ * @vector Vector number
+ * @handler Handler called when IRQ arrives
+ * @arg Handler argument
+ * @name IRQ name
+ *
+ */
+struct slot_irq {
+ int vector;
+ int (*handler)(void *);
+ void *arg;
+ const char *name;
+};
+
+/**
+ * struct tpci200_slot - data specific to the tpci200 slot.
+ * @slot_id Slot identification gived to external interface
+ * @irq Slot IRQ infos
+ * @io_phys IO physical base address register of the slot
+ * @id_phys ID physical base address register of the slot
+ * @mem_phys MEM physical base address register of the slot
+ *
+ */
+struct tpci200_slot {
+ struct ipack_device *dev;
+ struct slot_irq *irq;
+ struct ipack_addr_space io_phys;
+ struct ipack_addr_space id_phys;
+ struct ipack_addr_space mem_phys;
+};
+
+/**
+ * struct tpci200_infos - informations specific of the TPCI200 tpci200.
+ * @pci_dev PCI device
+ * @interface_regs Pointer to IP interface space (Bar 2)
+ * @ioidint_space Pointer to IP ID, IO and INT space (Bar 3)
+ * @mem8_space Pointer to MEM space (Bar 4)
+ * @access_lock Mutex lock for simultaneous access
+ *
+ */
+struct tpci200_infos {
+ struct pci_dev *pdev;
+ struct pci_device_id *id_table;
+ void __iomem *interface_regs;
+ void __iomem *ioidint_space;
+ void __iomem *mem8_space;
+ spinlock_t access_lock;
+ struct ipack_bus_device *ipack_bus;
+};
+struct tpci200_board {
+ struct list_head list;
+ unsigned int number;
+ struct mutex mutex;
+ struct tpci200_slot *slots;
+ struct tpci200_infos *info;
+};
+
+#endif /* _TPCI200_H_ */
diff --git a/drivers/staging/ipack/devices/Kconfig b/drivers/staging/ipack/devices/Kconfig
new file mode 100644
index 000000000000..39f71888a584
--- /dev/null
+++ b/drivers/staging/ipack/devices/Kconfig
@@ -0,0 +1,7 @@
+config SERIAL_IPOCTAL
+ tristate "IndustryPack IP-OCTAL uart support"
+ depends on IPACK_BUS
+ help
+ This driver supports the IPOCTAL serial port device for the IndustryPack bus.
+ default n
+
diff --git a/drivers/staging/ipack/devices/Makefile b/drivers/staging/ipack/devices/Makefile
new file mode 100644
index 000000000000..6de18bda4a9a
--- /dev/null
+++ b/drivers/staging/ipack/devices/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SERIAL_IPOCTAL) += ipoctal.o
diff --git a/drivers/staging/ipack/devices/ipoctal.c b/drivers/staging/ipack/devices/ipoctal.c
new file mode 100644
index 000000000000..29f6fa841d23
--- /dev/null
+++ b/drivers/staging/ipack/devices/ipoctal.c
@@ -0,0 +1,901 @@
+/**
+ * ipoctal.c
+ *
+ * driver for the GE IP-OCTAL boards
+ * Copyright (c) 2009 Nicolas Serafini, EIC2 SA
+ * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN
+ * Copyright (c) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/tty_flip.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/atomic.h>
+#include "../ipack.h"
+#include "ipoctal.h"
+#include "scc2698.h"
+
+#define IP_OCTAL_MANUFACTURER_ID 0xF0
+#define IP_OCTAL_232_ID 0x22
+#define IP_OCTAL_422_ID 0x2A
+#define IP_OCTAL_485_ID 0x48
+
+#define IP_OCTAL_ID_SPACE_VECTOR 0x41
+#define IP_OCTAL_NB_BLOCKS 4
+
+static struct ipack_driver driver;
+static const struct tty_operations ipoctal_fops;
+
+struct ipoctal {
+ struct list_head list;
+ struct ipack_device *dev;
+ unsigned int board_id;
+ struct scc2698_channel *chan_regs;
+ struct scc2698_block *block_regs;
+ struct ipoctal_stats chan_stats[NR_CHANNELS];
+ char *buffer[NR_CHANNELS];
+ unsigned int nb_bytes[NR_CHANNELS];
+ unsigned int count_wr[NR_CHANNELS];
+ struct ipoctal_config chan_config[NR_CHANNELS];
+ wait_queue_head_t queue[NR_CHANNELS];
+ unsigned short error_flag[NR_CHANNELS];
+ spinlock_t lock[NR_CHANNELS];
+ unsigned int pointer_read[NR_CHANNELS];
+ unsigned int pointer_write[NR_CHANNELS];
+ atomic_t open[NR_CHANNELS];
+ unsigned char write;
+ struct tty_port tty_port[NR_CHANNELS];
+ struct tty_driver *tty_drv;
+};
+
+/* Linked list to save the registered devices */
+static LIST_HEAD(ipoctal_list);
+
+static inline void ipoctal_write_io_reg(struct ipoctal *ipoctal,
+ unsigned char *dest,
+ unsigned char value)
+{
+ unsigned long offset;
+
+ offset = ((void __iomem *) dest) - ipoctal->dev->io_space.address;
+ ipoctal->dev->bus->ops->write8(ipoctal->dev, IPACK_IO_SPACE, offset,
+ value);
+}
+
+static inline void ipoctal_write_cr_cmd(struct ipoctal *ipoctal,
+ unsigned char *dest,
+ unsigned char value)
+{
+ ipoctal_write_io_reg(ipoctal, dest, value);
+}
+
+static inline unsigned char ipoctal_read_io_reg(struct ipoctal *ipoctal,
+ unsigned char *src)
+{
+ unsigned long offset;
+ unsigned char value;
+
+ offset = ((void __iomem *) src) - ipoctal->dev->io_space.address;
+ ipoctal->dev->bus->ops->read8(ipoctal->dev, IPACK_IO_SPACE, offset,
+ &value);
+ return value;
+}
+
+static struct ipoctal *ipoctal_find_board(struct tty_struct *tty)
+{
+ struct ipoctal *p;
+
+ list_for_each_entry(p, &ipoctal_list, list) {
+ if (tty->driver->major == p->tty_drv->major)
+ return p;
+ }
+
+ return NULL;
+}
+
+static int ipoctal_port_activate(struct tty_port *port, struct tty_struct *tty)
+{
+ struct ipoctal *ipoctal;
+ int channel = tty->index;
+
+ ipoctal = ipoctal_find_board(tty);
+
+ if (ipoctal == NULL) {
+ pr_err("Device not found. Major %d\n", tty->driver->major);
+ return -ENODEV;
+ }
+
+ ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_ENABLE_RX);
+ tty->driver_data = ipoctal;
+
+ return 0;
+}
+
+static int ipoctal_open(struct tty_struct *tty, struct file *file)
+{
+ int channel = tty->index;
+ int res;
+ struct ipoctal *ipoctal;
+
+ ipoctal = ipoctal_find_board(tty);
+
+ if (ipoctal == NULL) {
+ pr_err("Device not found. Major %d\n", tty->driver->major);
+ return -ENODEV;
+ }
+
+ if (atomic_read(&ipoctal->open[channel]))
+ return -EBUSY;
+
+ res = tty_port_open(&ipoctal->tty_port[channel], tty, file);
+ if (res)
+ return res;
+
+ atomic_inc(&ipoctal->open[channel]);
+ return 0;
+}
+
+static void ipoctal_reset_stats(struct ipoctal_stats *stats)
+{
+ stats->tx = 0;
+ stats->rx = 0;
+ stats->rcv_break = 0;
+ stats->framing_err = 0;
+ stats->overrun_err = 0;
+ stats->parity_err = 0;
+}
+
+static void ipoctal_free_channel(struct tty_struct *tty)
+{
+ int channel = tty->index;
+ struct ipoctal *ipoctal = tty->driver_data;
+
+ if (ipoctal == NULL)
+ return;
+
+ ipoctal_reset_stats(&ipoctal->chan_stats[channel]);
+ ipoctal->pointer_read[channel] = 0;
+ ipoctal->pointer_write[channel] = 0;
+ ipoctal->nb_bytes[channel] = 0;
+}
+
+static void ipoctal_close(struct tty_struct *tty, struct file *filp)
+{
+ int channel = tty->index;
+ struct ipoctal *ipoctal = tty->driver_data;
+
+ tty_port_close(&ipoctal->tty_port[channel], tty, filp);
+
+ if (atomic_dec_and_test(&ipoctal->open[channel]))
+ ipoctal_free_channel(tty);
+}
+
+static int ipoctal_get_icount(struct tty_struct *tty,
+ struct serial_icounter_struct *icount)
+{
+ struct ipoctal *ipoctal = tty->driver_data;
+ int channel = tty->index;
+
+ icount->cts = 0;
+ icount->dsr = 0;
+ icount->rng = 0;
+ icount->dcd = 0;
+ icount->rx = ipoctal->chan_stats[channel].rx;
+ icount->tx = ipoctal->chan_stats[channel].tx;
+ icount->frame = ipoctal->chan_stats[channel].framing_err;
+ icount->parity = ipoctal->chan_stats[channel].parity_err;
+ icount->brk = ipoctal->chan_stats[channel].rcv_break;
+ return 0;
+}
+
+static int ipoctal_irq_handler(void *arg)
+{
+ unsigned int channel;
+ unsigned int block;
+ unsigned char isr;
+ unsigned char sr;
+ unsigned char isr_tx_rdy, isr_rx_rdy;
+ unsigned char value;
+ unsigned char flag;
+ struct tty_struct *tty;
+ struct ipoctal *ipoctal = (struct ipoctal *) arg;
+
+ /* Check all channels */
+ for (channel = 0; channel < NR_CHANNELS; channel++) {
+ /* If there is no client, skip the check */
+ if (!atomic_read(&ipoctal->open[channel]))
+ continue;
+
+ tty = tty_port_tty_get(&ipoctal->tty_port[channel]);
+ if (!tty)
+ continue;
+
+ /*
+ * The HW is organized in pair of channels.
+ * See which register we need to read from
+ */
+ block = channel / 2;
+ isr = ipoctal_read_io_reg(ipoctal,
+ &ipoctal->block_regs[block].u.r.isr);
+ sr = ipoctal_read_io_reg(ipoctal,
+ &ipoctal->chan_regs[channel].u.r.sr);
+
+ if ((channel % 2) == 1) {
+ isr_tx_rdy = isr & ISR_TxRDY_B;
+ isr_rx_rdy = isr & ISR_RxRDY_FFULL_B;
+ } else {
+ isr_tx_rdy = isr & ISR_TxRDY_A;
+ isr_rx_rdy = isr & ISR_RxRDY_FFULL_A;
+ }
+
+ /* In case of RS-485, change from TX to RX when finishing TX.
+ * Half-duplex.
+ */
+ if ((ipoctal->board_id == IP_OCTAL_485_ID) &&
+ (sr & SR_TX_EMPTY) &&
+ (ipoctal->nb_bytes[channel] == 0)) {
+ ipoctal_write_io_reg(ipoctal,
+ &ipoctal->chan_regs[channel].u.w.cr,
+ CR_DISABLE_TX);
+ ipoctal_write_cr_cmd(ipoctal,
+ &ipoctal->chan_regs[channel].u.w.cr,
+ CR_CMD_NEGATE_RTSN);
+ ipoctal_write_io_reg(ipoctal,
+ &ipoctal->chan_regs[channel].u.w.cr,
+ CR_ENABLE_RX);
+ ipoctal->write = 1;
+ wake_up_interruptible(&ipoctal->queue[channel]);
+ }
+
+ /* RX data */
+ if (isr_rx_rdy && (sr & SR_RX_READY)) {
+ value = ipoctal_read_io_reg(ipoctal,
+ &ipoctal->chan_regs[channel].u.r.rhr);
+ flag = TTY_NORMAL;
+
+ /* Error: count statistics */
+ if (sr & SR_ERROR) {
+ ipoctal_write_cr_cmd(ipoctal,
+ &ipoctal->chan_regs[channel].u.w.cr,
+ CR_CMD_RESET_ERR_STATUS);
+
+ if (sr & SR_OVERRUN_ERROR) {
+ ipoctal->error_flag[channel] |= UART_OVERRUN;
+ ipoctal->chan_stats[channel].overrun_err++;
+ /* Overrun doesn't affect the current character*/
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ }
+ if (sr & SR_PARITY_ERROR) {
+ ipoctal->error_flag[channel] |= UART_PARITY;
+ ipoctal->chan_stats[channel].parity_err++;
+ flag = TTY_PARITY;
+ }
+ if (sr & SR_FRAMING_ERROR) {
+ ipoctal->error_flag[channel] |= UART_FRAMING;
+ ipoctal->chan_stats[channel].framing_err++;
+ flag = TTY_FRAME;
+ }
+ if (sr & SR_RECEIVED_BREAK) {
+ ipoctal->error_flag[channel] |= UART_BREAK;
+ ipoctal->chan_stats[channel].rcv_break++;
+ flag = TTY_BREAK;
+ }
+ }
+
+ tty_insert_flip_char(tty, value, flag);
+ }
+
+ /* TX of each character */
+ if (isr_tx_rdy && (sr & SR_TX_READY)) {
+ unsigned int *pointer_write =
+ &ipoctal->pointer_write[channel];
+
+ if (ipoctal->nb_bytes[channel] <= 0) {
+ ipoctal->nb_bytes[channel] = 0;
+ continue;
+ }
+ spin_lock(&ipoctal->lock[channel]);
+ value = ipoctal->buffer[channel][*pointer_write];
+ ipoctal_write_io_reg(ipoctal,
+ &ipoctal->chan_regs[channel].u.w.thr,
+ value);
+ ipoctal->chan_stats[channel].tx++;
+ ipoctal->count_wr[channel]++;
+ (*pointer_write)++;
+ *pointer_write = *pointer_write % PAGE_SIZE;
+ ipoctal->nb_bytes[channel]--;
+ spin_unlock(&ipoctal->lock[channel]);
+
+ if ((ipoctal->nb_bytes[channel] == 0) &&
+ (waitqueue_active(&ipoctal->queue[channel]))) {
+
+ if (ipoctal->board_id != IP_OCTAL_485_ID) {
+ ipoctal->write = 1;
+ wake_up_interruptible(&ipoctal->queue[channel]);
+ }
+ }
+ }
+
+ tty_flip_buffer_push(tty);
+ tty_kref_put(tty);
+ }
+ return IRQ_HANDLED;
+}
+
+static int ipoctal_check_model(struct ipack_device *dev, unsigned char *id)
+{
+ unsigned char manufacturerID;
+ unsigned char board_id;
+
+ dev->bus->ops->read8(dev, IPACK_ID_SPACE,
+ IPACK_IDPROM_OFFSET_MANUFACTURER_ID, &manufacturerID);
+ if (manufacturerID != IP_OCTAL_MANUFACTURER_ID)
+ return -ENODEV;
+
+ dev->bus->ops->read8(dev, IPACK_ID_SPACE,
+ IPACK_IDPROM_OFFSET_MODEL, (unsigned char *)&board_id);
+
+ switch (board_id) {
+ case IP_OCTAL_232_ID:
+ case IP_OCTAL_422_ID:
+ case IP_OCTAL_485_ID:
+ *id = board_id;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static const struct tty_port_operations ipoctal_tty_port_ops = {
+ .dtr_rts = NULL,
+ .activate = ipoctal_port_activate,
+};
+
+static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
+ unsigned int slot, unsigned int vector)
+{
+ int res = 0;
+ int i;
+ struct tty_driver *tty;
+ char name[20];
+ unsigned char board_id;
+
+ res = ipoctal->dev->bus->ops->map_space(ipoctal->dev, 0,
+ IPACK_ID_SPACE);
+ if (res) {
+ pr_err("Unable to map slot [%d:%d] ID space!\n", bus_nr, slot);
+ return res;
+ }
+
+ res = ipoctal_check_model(ipoctal->dev, &board_id);
+ if (res) {
+ ipoctal->dev->bus->ops->unmap_space(ipoctal->dev,
+ IPACK_ID_SPACE);
+ goto out_unregister_id_space;
+ }
+ ipoctal->board_id = board_id;
+
+ res = ipoctal->dev->bus->ops->map_space(ipoctal->dev, 0,
+ IPACK_IO_SPACE);
+ if (res) {
+ pr_err("Unable to map slot [%d:%d] IO space!\n", bus_nr, slot);
+ goto out_unregister_id_space;
+ }
+
+ res = ipoctal->dev->bus->ops->map_space(ipoctal->dev,
+ 0x8000, IPACK_MEM_SPACE);
+ if (res) {
+ pr_err("Unable to map slot [%d:%d] MEM space!\n", bus_nr, slot);
+ goto out_unregister_io_space;
+ }
+
+ /* Save the virtual address to access the registers easily */
+ ipoctal->chan_regs =
+ (struct scc2698_channel *) ipoctal->dev->io_space.address;
+ ipoctal->block_regs =
+ (struct scc2698_block *) ipoctal->dev->io_space.address;
+
+ /* Disable RX and TX before touching anything */
+ for (i = 0; i < NR_CHANNELS ; i++) {
+ ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[i].u.w.cr,
+ CR_DISABLE_RX | CR_DISABLE_TX);
+ }
+
+ for (i = 0; i < IP_OCTAL_NB_BLOCKS; i++) {
+ ipoctal_write_io_reg(ipoctal,
+ &ipoctal->block_regs[i].u.w.acr,
+ ACR_BRG_SET2);
+ ipoctal_write_io_reg(ipoctal,
+ &ipoctal->block_regs[i].u.w.opcr,
+ OPCR_MPP_OUTPUT | OPCR_MPOa_RTSN |
+ OPCR_MPOb_RTSN);
+ ipoctal_write_io_reg(ipoctal,
+ &ipoctal->block_regs[i].u.w.imr,
+ IMR_TxRDY_A | IMR_RxRDY_FFULL_A |
+ IMR_DELTA_BREAK_A | IMR_TxRDY_B |
+ IMR_RxRDY_FFULL_B | IMR_DELTA_BREAK_B);
+ }
+
+ /*
+ * IP-OCTAL has different addresses to copy its IRQ vector.
+ * Depending of the carrier these addresses are accesible or not.
+ * More info in the datasheet.
+ */
+ ipoctal->dev->bus->ops->request_irq(ipoctal->dev, vector,
+ ipoctal_irq_handler, ipoctal);
+ ipoctal->dev->bus->ops->write8(ipoctal->dev, IPACK_ID_SPACE, 0, vector);
+
+ /* Register the TTY device */
+
+ /* Each IP-OCTAL channel is a TTY port */
+ tty = alloc_tty_driver(NR_CHANNELS);
+
+ if (!tty) {
+ res = -ENOMEM;
+ goto out_unregister_slot_unmap;
+ }
+
+ /* Fill struct tty_driver with ipoctal data */
+ tty->owner = THIS_MODULE;
+ tty->driver_name = "ipoctal";
+ sprintf(name, "ipoctal.%d.%d.", bus_nr, slot);
+ tty->name = name;
+ tty->major = 0;
+
+ tty->minor_start = 0;
+ tty->type = TTY_DRIVER_TYPE_SERIAL;
+ tty->subtype = SERIAL_TYPE_NORMAL;
+ tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+ tty->init_termios = tty_std_termios;
+ tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ tty->init_termios.c_ispeed = 9600;
+ tty->init_termios.c_ospeed = 9600;
+
+ tty_set_operations(tty, &ipoctal_fops);
+ res = tty_register_driver(tty);
+ if (res) {
+ pr_err("Can't register tty driver.\n");
+ put_tty_driver(tty);
+ goto out_unregister_slot_unmap;
+ }
+
+ /* Save struct tty_driver for use it when uninstalling the device */
+ ipoctal->tty_drv = tty;
+
+ for (i = 0; i < NR_CHANNELS; i++) {
+ tty_port_init(&ipoctal->tty_port[i]);
+ tty_port_alloc_xmit_buf(&ipoctal->tty_port[i]);
+ ipoctal->tty_port[i].ops = &ipoctal_tty_port_ops;
+
+ ipoctal_reset_stats(&ipoctal->chan_stats[i]);
+ ipoctal->nb_bytes[i] = 0;
+ init_waitqueue_head(&ipoctal->queue[i]);
+ ipoctal->error_flag[i] = UART_NOERROR;
+
+ spin_lock_init(&ipoctal->lock[i]);
+ ipoctal->pointer_read[i] = 0;
+ ipoctal->pointer_write[i] = 0;
+ ipoctal->nb_bytes[i] = 0;
+ tty_register_device(tty, i, NULL);
+
+ /*
+ * Enable again the RX. TX will be enabled when
+ * there is something to send
+ */
+ ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[i].u.w.cr,
+ CR_ENABLE_RX);
+ }
+
+ return 0;
+
+out_unregister_slot_unmap:
+ ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_ID_SPACE);
+out_unregister_io_space:
+ ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_IO_SPACE);
+out_unregister_id_space:
+ ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_MEM_SPACE);
+ return res;
+}
+
+static inline int ipoctal_copy_write_buffer(struct ipoctal *ipoctal,
+ unsigned int channel,
+ const unsigned char *buf,
+ int count)
+{
+ unsigned long flags;
+ int i;
+ unsigned int *pointer_read = &ipoctal->pointer_read[channel];
+
+ /* Copy the bytes from the user buffer to the internal one */
+ for (i = 0; i < count; i++) {
+ if (i <= (PAGE_SIZE - ipoctal->nb_bytes[channel])) {
+ spin_lock_irqsave(&ipoctal->lock[channel], flags);
+ ipoctal->tty_port[channel].xmit_buf[*pointer_read] = buf[i];
+ *pointer_read = (*pointer_read + 1) % PAGE_SIZE;
+ ipoctal->nb_bytes[channel]++;
+ spin_unlock_irqrestore(&ipoctal->lock[channel], flags);
+ } else {
+ break;
+ }
+ }
+ return i;
+}
+
+static int ipoctal_write(struct ipoctal *ipoctal, unsigned int channel,
+ const unsigned char *buf, int count)
+{
+ ipoctal->nb_bytes[channel] = 0;
+ ipoctal->count_wr[channel] = 0;
+
+ ipoctal_copy_write_buffer(ipoctal, channel, buf, count);
+
+ ipoctal->error_flag[channel] = UART_NOERROR;
+
+ /* As the IP-OCTAL 485 only supports half duplex, do it manually */
+ if (ipoctal->board_id == IP_OCTAL_485_ID) {
+ ipoctal_write_io_reg(ipoctal,
+ &ipoctal->chan_regs[channel].u.w.cr,
+ CR_DISABLE_RX);
+ ipoctal_write_cr_cmd(ipoctal,
+ &ipoctal->chan_regs[channel].u.w.cr,
+ CR_CMD_ASSERT_RTSN);
+ }
+
+ /*
+ * Send a packet and then disable TX to avoid failure after several send
+ * operations
+ */
+ ipoctal_write_io_reg(ipoctal,
+ &ipoctal->chan_regs[channel].u.w.cr,
+ CR_ENABLE_TX);
+ wait_event_interruptible(ipoctal->queue[channel], ipoctal->write);
+ ipoctal_write_io_reg(ipoctal,
+ &ipoctal->chan_regs[channel].u.w.cr,
+ CR_DISABLE_TX);
+
+ ipoctal->write = 0;
+ return ipoctal->count_wr[channel];
+}
+
+static int ipoctal_write_tty(struct tty_struct *tty,
+ const unsigned char *buf, int count)
+{
+ unsigned int channel = tty->index;
+ struct ipoctal *ipoctal = tty->driver_data;
+
+ return ipoctal_write(ipoctal, channel, buf, count);
+}
+
+static int ipoctal_write_room(struct tty_struct *tty)
+{
+ int channel = tty->index;
+ struct ipoctal *ipoctal = tty->driver_data;
+
+ return PAGE_SIZE - ipoctal->nb_bytes[channel];
+}
+
+static int ipoctal_chars_in_buffer(struct tty_struct *tty)
+{
+ int channel = tty->index;
+ struct ipoctal *ipoctal = tty->driver_data;
+
+ return ipoctal->nb_bytes[channel];
+}
+
+static void ipoctal_set_termios(struct tty_struct *tty,
+ struct ktermios *old_termios)
+{
+ unsigned int cflag;
+ unsigned char mr1 = 0;
+ unsigned char mr2 = 0;
+ unsigned char csr = 0;
+ unsigned int channel = tty->index;
+ struct ipoctal *ipoctal = tty->driver_data;
+ speed_t baud;
+
+ cflag = tty->termios->c_cflag;
+
+ /* Disable and reset everything before change the setup */
+ ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_DISABLE_RX | CR_DISABLE_TX);
+ ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_CMD_RESET_RX);
+ ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_CMD_RESET_TX);
+ ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_CMD_RESET_ERR_STATUS);
+ ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_CMD_RESET_MR);
+
+ /* Set Bits per chars */
+ switch (cflag & CSIZE) {
+ case CS6:
+ mr1 |= MR1_CHRL_6_BITS;
+ break;
+ case CS7:
+ mr1 |= MR1_CHRL_7_BITS;
+ break;
+ case CS8:
+ default:
+ mr1 |= MR1_CHRL_8_BITS;
+ /* By default, select CS8 */
+ tty->termios->c_cflag = (cflag & ~CSIZE) | CS8;
+ break;
+ }
+
+ /* Set Parity */
+ if (cflag & PARENB)
+ if (cflag & PARODD)
+ mr1 |= MR1_PARITY_ON | MR1_PARITY_ODD;
+ else
+ mr1 |= MR1_PARITY_ON | MR1_PARITY_EVEN;
+ else
+ mr1 |= MR1_PARITY_OFF;
+
+ /* Mark or space parity is not supported */
+ tty->termios->c_cflag &= ~CMSPAR;
+
+ /* Set stop bits */
+ if (cflag & CSTOPB)
+ mr2 |= MR2_STOP_BITS_LENGTH_2;
+ else
+ mr2 |= MR2_STOP_BITS_LENGTH_1;
+
+ /* Set the flow control */
+ switch (ipoctal->board_id) {
+ case IP_OCTAL_232_ID:
+ if (cflag & CRTSCTS) {
+ mr1 |= MR1_RxRTS_CONTROL_ON;
+ mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_ON;
+ ipoctal->chan_config[channel].flow_control = 1;
+ } else {
+ mr1 |= MR1_RxRTS_CONTROL_OFF;
+ mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_OFF;
+ ipoctal->chan_config[channel].flow_control = 0;
+ }
+ break;
+ case IP_OCTAL_422_ID:
+ mr1 |= MR1_RxRTS_CONTROL_OFF;
+ mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_OFF;
+ ipoctal->chan_config[channel].flow_control = 0;
+ break;
+ case IP_OCTAL_485_ID:
+ mr1 |= MR1_RxRTS_CONTROL_OFF;
+ mr2 |= MR2_TxRTS_CONTROL_ON | MR2_CTS_ENABLE_TX_OFF;
+ ipoctal->chan_config[channel].flow_control = 0;
+ break;
+ default:
+ return;
+ break;
+ }
+
+ baud = tty_get_baud_rate(tty);
+ tty_termios_encode_baud_rate(tty->termios, baud, baud);
+
+ /* Set baud rate */
+ switch (tty->termios->c_ospeed) {
+ case 75:
+ csr |= TX_CLK_75 | RX_CLK_75;
+ break;
+ case 110:
+ csr |= TX_CLK_110 | RX_CLK_110;
+ break;
+ case 150:
+ csr |= TX_CLK_150 | RX_CLK_150;
+ break;
+ case 300:
+ csr |= TX_CLK_300 | RX_CLK_300;
+ break;
+ case 600:
+ csr |= TX_CLK_600 | RX_CLK_600;
+ break;
+ case 1200:
+ csr |= TX_CLK_1200 | RX_CLK_1200;
+ break;
+ case 1800:
+ csr |= TX_CLK_1800 | RX_CLK_1800;
+ break;
+ case 2000:
+ csr |= TX_CLK_2000 | RX_CLK_2000;
+ break;
+ case 2400:
+ csr |= TX_CLK_2400 | RX_CLK_2400;
+ break;
+ case 4800:
+ csr |= TX_CLK_4800 | RX_CLK_4800;
+ break;
+ case 9600:
+ csr |= TX_CLK_9600 | RX_CLK_9600;
+ break;
+ case 19200:
+ csr |= TX_CLK_19200 | RX_CLK_19200;
+ break;
+ case 38400:
+ default:
+ csr |= TX_CLK_38400 | RX_CLK_38400;
+ /* In case of default, we establish 38400 bps */
+ tty_termios_encode_baud_rate(tty->termios, 38400, 38400);
+ break;
+ }
+
+ mr1 |= MR1_ERROR_CHAR;
+ mr1 |= MR1_RxINT_RxRDY;
+
+ /* Write the control registers */
+ ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.mr, mr1);
+ ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.mr, mr2);
+ ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.csr, csr);
+
+ /* save the setup in the structure */
+ ipoctal->chan_config[channel].baud = tty_get_baud_rate(tty);
+ ipoctal->chan_config[channel].bits_per_char = cflag & CSIZE;
+ ipoctal->chan_config[channel].parity = cflag & PARENB;
+ ipoctal->chan_config[channel].stop_bits = cflag & CSTOPB;
+
+ /* Enable again the RX */
+ ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_ENABLE_RX);
+}
+
+static void ipoctal_hangup(struct tty_struct *tty)
+{
+ unsigned long flags;
+ int channel = tty->index;
+ struct ipoctal *ipoctal = tty->driver_data;
+
+ if (ipoctal == NULL)
+ return;
+
+ spin_lock_irqsave(&ipoctal->lock[channel], flags);
+ ipoctal->nb_bytes[channel] = 0;
+ ipoctal->pointer_read[channel] = 0;
+ ipoctal->pointer_write[channel] = 0;
+ spin_unlock_irqrestore(&ipoctal->lock[channel], flags);
+
+ tty_port_hangup(&ipoctal->tty_port[channel]);
+
+ ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_DISABLE_RX | CR_DISABLE_TX);
+ ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_CMD_RESET_RX);
+ ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_CMD_RESET_TX);
+ ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_CMD_RESET_ERR_STATUS);
+ ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
+ CR_CMD_RESET_MR);
+
+ clear_bit(ASYNCB_INITIALIZED, &ipoctal->tty_port[channel].flags);
+ wake_up_interruptible(&ipoctal->tty_port[channel].open_wait);
+}
+
+static const struct tty_operations ipoctal_fops = {
+ .ioctl = NULL,
+ .open = ipoctal_open,
+ .close = ipoctal_close,
+ .write = ipoctal_write_tty,
+ .set_termios = ipoctal_set_termios,
+ .write_room = ipoctal_write_room,
+ .chars_in_buffer = ipoctal_chars_in_buffer,
+ .get_icount = ipoctal_get_icount,
+ .hangup = ipoctal_hangup,
+};
+
+static int ipoctal_match(struct ipack_device *dev)
+{
+ int res;
+ unsigned char board_id;
+
+ if ((!dev->bus->ops) || (!dev->bus->ops->map_space) ||
+ (!dev->bus->ops->unmap_space))
+ return 0;
+
+ res = dev->bus->ops->map_space(dev, 0, IPACK_ID_SPACE);
+ if (res)
+ return 0;
+
+ res = ipoctal_check_model(dev, &board_id);
+ dev->bus->ops->unmap_space(dev, IPACK_ID_SPACE);
+ if (!res)
+ return 1;
+
+ return 0;
+}
+
+static int ipoctal_probe(struct ipack_device *dev)
+{
+ int res;
+ struct ipoctal *ipoctal;
+
+ ipoctal = kzalloc(sizeof(struct ipoctal), GFP_KERNEL);
+ if (ipoctal == NULL)
+ return -ENOMEM;
+
+ ipoctal->dev = dev;
+ res = ipoctal_inst_slot(ipoctal, dev->bus_nr, dev->slot, dev->irq);
+ if (res)
+ goto out_uninst;
+
+ list_add_tail(&ipoctal->list, &ipoctal_list);
+ return 0;
+
+out_uninst:
+ kfree(ipoctal);
+ return res;
+}
+
+static void __ipoctal_remove(struct ipoctal *ipoctal)
+{
+ int i;
+
+ for (i = 0; i < NR_CHANNELS; i++) {
+ tty_unregister_device(ipoctal->tty_drv, i);
+ tty_port_free_xmit_buf(&ipoctal->tty_port[i]);
+ }
+
+ tty_unregister_driver(ipoctal->tty_drv);
+ put_tty_driver(ipoctal->tty_drv);
+
+ /* Tell the carrier board to free all the resources for this device */
+ if (ipoctal->dev->bus->ops->remove_device != NULL)
+ ipoctal->dev->bus->ops->remove_device(ipoctal->dev);
+
+ list_del(&ipoctal->list);
+ kfree(ipoctal);
+}
+
+static void ipoctal_remove(struct ipack_device *device)
+{
+ struct ipoctal *ipoctal, *next;
+
+ list_for_each_entry_safe(ipoctal, next, &ipoctal_list, list) {
+ if (ipoctal->dev == device)
+ __ipoctal_remove(ipoctal);
+ }
+}
+
+static struct ipack_driver_ops ipoctal_drv_ops = {
+ .match = ipoctal_match,
+ .probe = ipoctal_probe,
+ .remove = ipoctal_remove,
+};
+
+static int __init ipoctal_init(void)
+{
+ driver.ops = &ipoctal_drv_ops;
+ return ipack_driver_register(&driver, THIS_MODULE, KBUILD_MODNAME);
+}
+
+static void __exit ipoctal_exit(void)
+{
+ struct ipoctal *p, *next;
+
+ list_for_each_entry_safe(p, next, &ipoctal_list, list)
+ __ipoctal_remove(p);
+
+ ipack_driver_unregister(&driver);
+}
+
+MODULE_DESCRIPTION("IP-Octal 232, 422 and 485 device driver");
+MODULE_LICENSE("GPL");
+
+module_init(ipoctal_init);
+module_exit(ipoctal_exit);
diff --git a/drivers/staging/ipack/devices/ipoctal.h b/drivers/staging/ipack/devices/ipoctal.h
new file mode 100644
index 000000000000..266f3617069d
--- /dev/null
+++ b/drivers/staging/ipack/devices/ipoctal.h
@@ -0,0 +1,80 @@
+/**
+ * ipoctal.h
+ *
+ * driver for the IPOCTAL boards
+ * Copyright (c) 2009 Nicolas Serafini, EIC2 SA
+ * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN
+ * Copyright (c) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ */
+
+#ifndef _IPOCTAL_H
+#define _IPOCTAL_H_
+
+#define NR_CHANNELS 8
+#define IPOCTAL_MAX_BOARDS 16
+#define MAX_DEVICES (NR_CHANNELS * IPOCTAL_MAX_BOARDS)
+#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+/**
+ * enum uart_parity_e - UART supported parity.
+ */
+enum uart_parity_e {
+ UART_NONE = 0,
+ UART_ODD = 1,
+ UART_EVEN = 2,
+};
+
+/**
+ * enum uart_error - UART error type
+ *
+ */
+enum uart_error {
+ UART_NOERROR = 0, /* No error during transmission */
+ UART_TIMEOUT = 1 << 0, /* Timeout error */
+ UART_OVERRUN = 1 << 1, /* Overrun error */
+ UART_PARITY = 1 << 2, /* Parity error */
+ UART_FRAMING = 1 << 3, /* Framing error */
+ UART_BREAK = 1 << 4, /* Received break */
+};
+
+/**
+ * struct ipoctal_config - Serial configuration
+ *
+ * @baud: Baud rate
+ * @stop_bits: Stop bits (1 or 2)
+ * @bits_per_char: data size in bits
+ * @parity
+ * @flow_control: Flow control management (RTS/CTS) (0 disabled, 1 enabled)
+ */
+struct ipoctal_config {
+ unsigned int baud;
+ unsigned int stop_bits;
+ unsigned int bits_per_char;
+ unsigned short parity;
+ unsigned int flow_control;
+};
+
+/**
+ * struct ipoctal_stats -- Stats since last reset
+ *
+ * @tx: Number of transmitted bytes
+ * @rx: Number of received bytes
+ * @overrun: Number of overrun errors
+ * @parity_err: Number of parity errors
+ * @framing_err: Number of framing errors
+ * @rcv_break: Number of break received
+ */
+struct ipoctal_stats {
+ unsigned long tx;
+ unsigned long rx;
+ unsigned long overrun_err;
+ unsigned long parity_err;
+ unsigned long framing_err;
+ unsigned long rcv_break;
+};
+
+#endif /* _IPOCTAL_H_ */
diff --git a/drivers/staging/ipack/devices/scc2698.h b/drivers/staging/ipack/devices/scc2698.h
new file mode 100644
index 000000000000..47f6269985fd
--- /dev/null
+++ b/drivers/staging/ipack/devices/scc2698.h
@@ -0,0 +1,228 @@
+/*
+ * scc2698.h
+ *
+ * driver for the IPOCTAL boards
+ * Copyright (c) 2009 Nicolas Serafini, EIC2 SA
+ * Copyright (c) 2010,2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN
+ * Copyright (c) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ */
+
+#ifndef SCC2698_H_
+#define SCC2698_H_
+
+/*
+ * struct scc2698_channel - Channel access to scc2698 IO
+ *
+ * dn value are only spacer.
+ *
+ */
+struct scc2698_channel {
+ union {
+ struct {
+ unsigned char d0, mr; /* Mode register 1/2*/
+ unsigned char d1, sr; /* Status register */
+ unsigned char d2, r1; /* reserved */
+ unsigned char d3, rhr; /* Receive holding register (R) */
+ unsigned char junk[8]; /* other crap for block control */
+ } r; /* Read access */
+ struct {
+ unsigned char d0, mr; /* Mode register 1/2 */
+ unsigned char d1, csr; /* Clock select register */
+ unsigned char d2, cr; /* Command register */
+ unsigned char d3, thr; /* Transmit holding register */
+ unsigned char junk[8]; /* other crap for block control */
+ } w; /* Write access */
+ } u;
+};
+
+/*
+ * struct scc2698_block - Block access to scc2698 IO
+ *
+ * The scc2698 contain 4 block.
+ * Each block containt two channel a and b.
+ * dn value are only spacer.
+ *
+ */
+struct scc2698_block {
+ union {
+ struct {
+ unsigned char d0, mra; /* Mode register 1/2 (a) */
+ unsigned char d1, sra; /* Status register (a) */
+ unsigned char d2, r1; /* reserved */
+ unsigned char d3, rhra; /* Receive holding register (a) */
+ unsigned char d4, ipcr; /* Input port change register of block */
+ unsigned char d5, isr; /* Interrupt status register of block */
+ unsigned char d6, ctur; /* Counter timer upper register of block */
+ unsigned char d7, ctlr; /* Counter timer lower register of block */
+ unsigned char d8, mrb; /* Mode register 1/2 (b) */
+ unsigned char d9, srb; /* Status register (b) */
+ unsigned char da, r2; /* reserved */
+ unsigned char db, rhrb; /* Receive holding register (b) */
+ unsigned char dc, r3; /* reserved */
+ unsigned char dd, ip; /* Input port register of block */
+ unsigned char de, ctg; /* Start counter timer of block */
+ unsigned char df, cts; /* Stop counter timer of block */
+ } r; /* Read access */
+ struct {
+ unsigned char d0, mra; /* Mode register 1/2 (a) */
+ unsigned char d1, csra; /* Clock select register (a) */
+ unsigned char d2, cra; /* Command register (a) */
+ unsigned char d3, thra; /* Transmit holding register (a) */
+ unsigned char d4, acr; /* Auxiliary control register of block */
+ unsigned char d5, imr; /* Interrupt mask register of block */
+ unsigned char d6, ctu; /* Counter timer upper register of block */
+ unsigned char d7, ctl; /* Counter timer lower register of block */
+ unsigned char d8, mrb; /* Mode register 1/2 (b) */
+ unsigned char d9, csrb; /* Clock select register (a) */
+ unsigned char da, crb; /* Command register (b) */
+ unsigned char db, thrb; /* Transmit holding register (b) */
+ unsigned char dc, r1; /* reserved */
+ unsigned char dd, opcr; /* Output port configuration register of block */
+ unsigned char de, r2; /* reserved */
+ unsigned char df, r3; /* reserved */
+ } w; /* Write access */
+ } u;
+} ;
+
+#define MR1_CHRL_5_BITS (0x0 << 0)
+#define MR1_CHRL_6_BITS (0x1 << 0)
+#define MR1_CHRL_7_BITS (0x2 << 0)
+#define MR1_CHRL_8_BITS (0x3 << 0)
+#define MR1_PARITY_EVEN (0x1 << 2)
+#define MR1_PARITY_ODD (0x0 << 2)
+#define MR1_PARITY_ON (0x0 << 3)
+#define MR1_PARITY_FORCE (0x1 << 3)
+#define MR1_PARITY_OFF (0x2 << 3)
+#define MR1_PARITY_SPECIAL (0x3 << 3)
+#define MR1_ERROR_CHAR (0x0 << 5)
+#define MR1_ERROR_BLOCK (0x1 << 5)
+#define MR1_RxINT_RxRDY (0x0 << 6)
+#define MR1_RxINT_FFULL (0x1 << 6)
+#define MR1_RxRTS_CONTROL_ON (0x1 << 7)
+#define MR1_RxRTS_CONTROL_OFF (0x0 << 7)
+
+#define MR2_STOP_BITS_LENGTH_1 (0x7 << 0)
+#define MR2_STOP_BITS_LENGTH_2 (0xF << 0)
+#define MR2_CTS_ENABLE_TX_ON (0x1 << 4)
+#define MR2_CTS_ENABLE_TX_OFF (0x0 << 4)
+#define MR2_TxRTS_CONTROL_ON (0x1 << 5)
+#define MR2_TxRTS_CONTROL_OFF (0x0 << 5)
+#define MR2_CH_MODE_NORMAL (0x0 << 6)
+#define MR2_CH_MODE_ECHO (0x1 << 6)
+#define MR2_CH_MODE_LOCAL (0x2 << 6)
+#define MR2_CH_MODE_REMOTE (0x3 << 6)
+
+#define CR_ENABLE_RX (0x1 << 0)
+#define CR_DISABLE_RX (0x1 << 1)
+#define CR_ENABLE_TX (0x1 << 2)
+#define CR_DISABLE_TX (0x1 << 3)
+#define CR_CMD_RESET_MR (0x1 << 4)
+#define CR_CMD_RESET_RX (0x2 << 4)
+#define CR_CMD_RESET_TX (0x3 << 4)
+#define CR_CMD_RESET_ERR_STATUS (0x4 << 4)
+#define CR_CMD_RESET_BREAK_CHANGE (0x5 << 4)
+#define CR_CMD_START_BREAK (0x6 << 4)
+#define CR_CMD_STOP_BREAK (0x7 << 4)
+#define CR_CMD_ASSERT_RTSN (0x8 << 4)
+#define CR_CMD_NEGATE_RTSN (0x9 << 4)
+#define CR_CMD_SET_TIMEOUT_MODE (0xA << 4)
+#define CR_CMD_DISABLE_TIMEOUT_MODE (0xC << 4)
+
+#define SR_RX_READY (0x1 << 0)
+#define SR_FIFO_FULL (0x1 << 1)
+#define SR_TX_READY (0x1 << 2)
+#define SR_TX_EMPTY (0x1 << 3)
+#define SR_OVERRUN_ERROR (0x1 << 4)
+#define SR_PARITY_ERROR (0x1 << 5)
+#define SR_FRAMING_ERROR (0x1 << 6)
+#define SR_RECEIVED_BREAK (0x1 << 7)
+
+#define SR_ERROR (0xF0)
+
+#define ACR_DELTA_IP0_IRQ_EN (0x1 << 0)
+#define ACR_DELTA_IP1_IRQ_EN (0x1 << 1)
+#define ACR_DELTA_IP2_IRQ_EN (0x1 << 2)
+#define ACR_DELTA_IP3_IRQ_EN (0x1 << 3)
+#define ACR_CT_Mask (0x7 << 4)
+#define ACR_CExt (0x0 << 4)
+#define ACR_CTxCA (0x1 << 4)
+#define ACR_CTxCB (0x2 << 4)
+#define ACR_CClk16 (0x3 << 4)
+#define ACR_TExt (0x4 << 4)
+#define ACR_TExt16 (0x5 << 4)
+#define ACR_TClk (0x6 << 4)
+#define ACR_TClk16 (0x7 << 4)
+#define ACR_BRG_SET1 (0x0 << 7)
+#define ACR_BRG_SET2 (0x1 << 7)
+
+#define TX_CLK_75 (0x0 << 0)
+#define TX_CLK_110 (0x1 << 0)
+#define TX_CLK_38400 (0x2 << 0)
+#define TX_CLK_150 (0x3 << 0)
+#define TX_CLK_300 (0x4 << 0)
+#define TX_CLK_600 (0x5 << 0)
+#define TX_CLK_1200 (0x6 << 0)
+#define TX_CLK_2000 (0x7 << 0)
+#define TX_CLK_2400 (0x8 << 0)
+#define TX_CLK_4800 (0x9 << 0)
+#define TX_CLK_1800 (0xA << 0)
+#define TX_CLK_9600 (0xB << 0)
+#define TX_CLK_19200 (0xC << 0)
+#define RX_CLK_75 (0x0 << 4)
+#define RX_CLK_110 (0x1 << 4)
+#define RX_CLK_38400 (0x2 << 4)
+#define RX_CLK_150 (0x3 << 4)
+#define RX_CLK_300 (0x4 << 4)
+#define RX_CLK_600 (0x5 << 4)
+#define RX_CLK_1200 (0x6 << 4)
+#define RX_CLK_2000 (0x7 << 4)
+#define RX_CLK_2400 (0x8 << 4)
+#define RX_CLK_4800 (0x9 << 4)
+#define RX_CLK_1800 (0xA << 4)
+#define RX_CLK_9600 (0xB << 4)
+#define RX_CLK_19200 (0xC << 4)
+
+#define OPCR_MPOa_RTSN (0x0 << 0)
+#define OPCR_MPOa_C_TO (0x1 << 0)
+#define OPCR_MPOa_TxC1X (0x2 << 0)
+#define OPCR_MPOa_TxC16X (0x3 << 0)
+#define OPCR_MPOa_RxC1X (0x4 << 0)
+#define OPCR_MPOa_RxC16X (0x5 << 0)
+#define OPCR_MPOa_TxRDY (0x6 << 0)
+#define OPCR_MPOa_RxRDY_FF (0x7 << 0)
+
+#define OPCR_MPOb_RTSN (0x0 << 4)
+#define OPCR_MPOb_C_TO (0x1 << 4)
+#define OPCR_MPOb_TxC1X (0x2 << 4)
+#define OPCR_MPOb_TxC16X (0x3 << 4)
+#define OPCR_MPOb_RxC1X (0x4 << 4)
+#define OPCR_MPOb_RxC16X (0x5 << 4)
+#define OPCR_MPOb_TxRDY (0x6 << 4)
+#define OPCR_MPOb_RxRDY_FF (0x7 << 4)
+
+#define OPCR_MPP_INPUT (0x0 << 7)
+#define OPCR_MPP_OUTPUT (0x1 << 7)
+
+#define IMR_TxRDY_A (0x1 << 0)
+#define IMR_RxRDY_FFULL_A (0x1 << 1)
+#define IMR_DELTA_BREAK_A (0x1 << 2)
+#define IMR_COUNTER_READY (0x1 << 3)
+#define IMR_TxRDY_B (0x1 << 4)
+#define IMR_RxRDY_FFULL_B (0x1 << 5)
+#define IMR_DELTA_BREAK_B (0x1 << 6)
+#define IMR_INPUT_PORT_CHANGE (0x1 << 7)
+
+#define ISR_TxRDY_A (0x1 << 0)
+#define ISR_RxRDY_FFULL_A (0x1 << 1)
+#define ISR_DELTA_BREAK_A (0x1 << 2)
+#define ISR_COUNTER_READY (0x1 << 3)
+#define ISR_TxRDY_B (0x1 << 4)
+#define ISR_RxRDY_FFULL_B (0x1 << 5)
+#define ISR_DELTA_BREAK_B (0x1 << 6)
+#define ISR_INPUT_PORT_CHANGE (0x1 << 7)
+
+#endif /* SCC2698_H_ */
diff --git a/drivers/staging/ipack/ipack.c b/drivers/staging/ipack/ipack.c
new file mode 100644
index 000000000000..2b4fa51bf167
--- /dev/null
+++ b/drivers/staging/ipack/ipack.c
@@ -0,0 +1,205 @@
+/*
+ * Industry-pack bus support functions.
+ *
+ * (C) 2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN
+ * (C) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include "ipack.h"
+
+#define to_ipack_dev(device) container_of(device, struct ipack_device, dev)
+#define to_ipack_driver(drv) container_of(drv, struct ipack_driver, driver)
+
+/* used when allocating bus numbers */
+#define IPACK_MAXBUS 64
+
+static DEFINE_MUTEX(ipack_mutex);
+
+struct ipack_busmap {
+ unsigned long busmap[IPACK_MAXBUS / (8*sizeof(unsigned long))];
+};
+static struct ipack_busmap busmap;
+
+static void ipack_device_release(struct device *dev)
+{
+ struct ipack_device *device = to_ipack_dev(dev);
+ kfree(device);
+}
+
+static int ipack_bus_match(struct device *device, struct device_driver *driver)
+{
+ int ret;
+ struct ipack_device *dev = to_ipack_dev(device);
+ struct ipack_driver *drv = to_ipack_driver(driver);
+
+ if ((!drv->ops) || (!drv->ops->match))
+ return -EINVAL;
+
+ ret = drv->ops->match(dev);
+ if (ret)
+ dev->driver = drv;
+
+ return 0;
+}
+
+static int ipack_bus_probe(struct device *device)
+{
+ struct ipack_device *dev = to_ipack_dev(device);
+
+ if (!dev->driver->ops->probe)
+ return -EINVAL;
+
+ return dev->driver->ops->probe(dev);
+}
+
+static int ipack_bus_remove(struct device *device)
+{
+ struct ipack_device *dev = to_ipack_dev(device);
+
+ if (!dev->driver->ops->remove)
+ return -EINVAL;
+
+ dev->driver->ops->remove(dev);
+ return 0;
+}
+
+static struct bus_type ipack_bus_type = {
+ .name = "ipack",
+ .probe = ipack_bus_probe,
+ .match = ipack_bus_match,
+ .remove = ipack_bus_remove,
+};
+
+static int ipack_assign_bus_number(void)
+{
+ int busnum;
+
+ mutex_lock(&ipack_mutex);
+ busnum = find_next_zero_bit(busmap.busmap, IPACK_MAXBUS, 1);
+
+ if (busnum >= IPACK_MAXBUS) {
+ pr_err("too many buses\n");
+ busnum = -1;
+ goto error_find_busnum;
+ }
+
+ set_bit(busnum, busmap.busmap);
+
+error_find_busnum:
+ mutex_unlock(&ipack_mutex);
+ return busnum;
+}
+
+struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots,
+ struct ipack_bus_ops *ops)
+{
+ int bus_nr;
+ struct ipack_bus_device *bus;
+
+ bus = kzalloc(sizeof(struct ipack_bus_device), GFP_KERNEL);
+ if (!bus)
+ return NULL;
+
+ bus_nr = ipack_assign_bus_number();
+ if (bus_nr < 0) {
+ kfree(bus);
+ return NULL;
+ }
+
+ bus->bus_nr = bus_nr;
+ bus->parent = parent;
+ bus->slots = slots;
+ bus->ops = ops;
+ return bus;
+}
+EXPORT_SYMBOL_GPL(ipack_bus_register);
+
+int ipack_bus_unregister(struct ipack_bus_device *bus)
+{
+ mutex_lock(&ipack_mutex);
+ clear_bit(bus->bus_nr, busmap.busmap);
+ mutex_unlock(&ipack_mutex);
+ kfree(bus);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipack_bus_unregister);
+
+int ipack_driver_register(struct ipack_driver *edrv, struct module *owner,
+ char *name)
+{
+ edrv->driver.owner = owner;
+ edrv->driver.name = name;
+ edrv->driver.bus = &ipack_bus_type;
+ return driver_register(&edrv->driver);
+}
+EXPORT_SYMBOL_GPL(ipack_driver_register);
+
+void ipack_driver_unregister(struct ipack_driver *edrv)
+{
+ driver_unregister(&edrv->driver);
+}
+EXPORT_SYMBOL_GPL(ipack_driver_unregister);
+
+struct ipack_device *ipack_device_register(struct ipack_bus_device *bus,
+ int slot, int irqv)
+{
+ int ret;
+ struct ipack_device *dev;
+
+ dev = kzalloc(sizeof(struct ipack_device), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ dev->dev.bus = &ipack_bus_type;
+ dev->dev.release = ipack_device_release;
+ dev->dev.parent = bus->parent;
+ dev->slot = slot;
+ dev->bus_nr = bus->bus_nr;
+ dev->irq = irqv;
+ dev->bus = bus;
+ dev_set_name(&dev->dev,
+ "ipack-dev.%u.%u", dev->bus_nr, dev->slot);
+
+ ret = device_register(&dev->dev);
+ if (ret < 0) {
+ pr_err("error registering the device.\n");
+ dev->driver->ops->remove(dev);
+ kfree(dev);
+ return NULL;
+ }
+
+ return dev;
+}
+EXPORT_SYMBOL_GPL(ipack_device_register);
+
+void ipack_device_unregister(struct ipack_device *dev)
+{
+ device_unregister(&dev->dev);
+}
+EXPORT_SYMBOL_GPL(ipack_device_unregister);
+
+static int __init ipack_init(void)
+{
+ return bus_register(&ipack_bus_type);
+}
+
+static void __exit ipack_exit(void)
+{
+ bus_unregister(&ipack_bus_type);
+}
+
+module_init(ipack_init);
+module_exit(ipack_exit);
+
+MODULE_AUTHOR("Samuel Iglesias Gonsalvez <siglesias@igalia.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Industry-pack bus core");
diff --git a/drivers/staging/ipack/ipack.h b/drivers/staging/ipack/ipack.h
new file mode 100644
index 000000000000..8bc001e3ca4e
--- /dev/null
+++ b/drivers/staging/ipack/ipack.h
@@ -0,0 +1,183 @@
+/*
+ * Industry-pack bus.
+ *
+ * (C) 2011 Samuel Iglesias Gonsalvez <siglesia@cern.ch>, CERN
+ * (C) 2012 Samuel Iglesias Gonsalvez <siglesias@igalia.com>, Igalia
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ */
+
+#include <linux/device.h>
+
+#define IPACK_IDPROM_OFFSET_I 0x01
+#define IPACK_IDPROM_OFFSET_P 0x03
+#define IPACK_IDPROM_OFFSET_A 0x05
+#define IPACK_IDPROM_OFFSET_C 0x07
+#define IPACK_IDPROM_OFFSET_MANUFACTURER_ID 0x09
+#define IPACK_IDPROM_OFFSET_MODEL 0x0B
+#define IPACK_IDPROM_OFFSET_REVISION 0x0D
+#define IPACK_IDPROM_OFFSET_RESERVED 0x0F
+#define IPACK_IDPROM_OFFSET_DRIVER_ID_L 0x11
+#define IPACK_IDPROM_OFFSET_DRIVER_ID_H 0x13
+#define IPACK_IDPROM_OFFSET_NUM_BYTES 0x15
+#define IPACK_IDPROM_OFFSET_CRC 0x17
+
+struct ipack_bus_ops;
+struct ipack_driver;
+
+enum ipack_space {
+ IPACK_IO_SPACE = 0,
+ IPACK_ID_SPACE = 1,
+ IPACK_MEM_SPACE = 2,
+};
+
+/**
+ * struct ipack_addr_space - Virtual address space mapped for a specified type.
+ *
+ * @address: virtual address
+ * @size: size of the mapped space
+ */
+struct ipack_addr_space {
+ void __iomem *address;
+ unsigned int size;
+};
+
+/**
+ * struct ipack_device
+ *
+ * @bus_nr: IP bus number where the device is plugged
+ * @slot: Slot where the device is plugged in the carrier board
+ * @irq: IRQ vector
+ * @driver: Pointer to the ipack_driver that manages the device
+ * @bus: ipack_bus_device where the device is plugged to.
+ * @id_space: Virtual address to ID space.
+ * @io_space: Virtual address to IO space.
+ * @mem_space: Virtual address to MEM space.
+ * @dev: device in kernel representation.
+ *
+ * Warning: Direct access to mapped memory is possible but the endianness
+ * is not the same with PCI carrier or VME carrier. The endianness is managed
+ * by the carrier board throught bus->ops.
+ */
+struct ipack_device {
+ unsigned int bus_nr;
+ unsigned int slot;
+ unsigned int irq;
+ struct ipack_driver *driver;
+ struct ipack_bus_device *bus;
+ struct ipack_addr_space id_space;
+ struct ipack_addr_space io_space;
+ struct ipack_addr_space mem_space;
+ struct device dev;
+};
+
+/**
+ * struct ipack_driver_ops -- callbacks to mezzanine driver for installing/removing one device
+ *
+ * @match: Match function
+ * @probe: Probe function
+ * @remove: tell the driver that the carrier board wants to remove one device
+ */
+
+struct ipack_driver_ops {
+ int (*match) (struct ipack_device *dev);
+ int (*probe) (struct ipack_device *dev);
+ void (*remove) (struct ipack_device *dev);
+};
+
+/**
+ * struct ipack_driver -- Specific data to each ipack board driver
+ *
+ * @driver: Device driver kernel representation
+ * @ops: Mezzanine driver operations specific for the ipack bus.
+ */
+struct ipack_driver {
+ struct device_driver driver;
+ struct ipack_driver_ops *ops;
+};
+
+/**
+ * struct ipack_bus_ops - available operations on a bridge module
+ *
+ * @map_space: map IP address space
+ * @unmap_space: unmap IP address space
+ * @request_irq: request IRQ
+ * @free_irq: free IRQ
+ * @read8: read unsigned char
+ * @read16: read unsigned short
+ * @read32: read unsigned int
+ * @write8: read unsigned char
+ * @write16: read unsigned short
+ * @write32: read unsigned int
+ * @remove_device: tell the bridge module that the device has been removed
+ */
+struct ipack_bus_ops {
+ int (*map_space) (struct ipack_device *dev, unsigned int memory_size, int space);
+ int (*unmap_space) (struct ipack_device *dev, int space);
+ int (*request_irq) (struct ipack_device *dev, int vector, int (*handler)(void *), void *arg);
+ int (*free_irq) (struct ipack_device *dev);
+ int (*read8) (struct ipack_device *dev, int space, unsigned long offset, unsigned char *value);
+ int (*read16) (struct ipack_device *dev, int space, unsigned long offset, unsigned short *value);
+ int (*read32) (struct ipack_device *dev, int space, unsigned long offset, unsigned int *value);
+ int (*write8) (struct ipack_device *dev, int space, unsigned long offset, unsigned char value);
+ int (*write16) (struct ipack_device *dev, int space, unsigned long offset, unsigned short value);
+ int (*write32) (struct ipack_device *dev, int space, unsigned long offset, unsigned int value);
+ int (*remove_device) (struct ipack_device *dev);
+};
+
+/**
+ * struct ipack_bus_device
+ *
+ * @dev: pointer to carrier device
+ * @slots: number of slots available
+ * @bus_nr: ipack bus number
+ * @ops: bus operations for the mezzanine drivers
+ */
+struct ipack_bus_device {
+ struct device *parent;
+ int slots;
+ int bus_nr;
+ struct ipack_bus_ops *ops;
+};
+
+/**
+ * ipack_bus_register -- register a new ipack bus
+ *
+ * @parent: pointer to the parent device, if any.
+ * @slots: number of slots available in the bus device.
+ * @ops: bus operations for the mezzanine drivers.
+ *
+ * The carrier board device should call this function to register itself as
+ * available bus device in ipack.
+ */
+struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots,
+ struct ipack_bus_ops *ops);
+
+/**
+ * ipack_bus_unregister -- unregister an ipack bus
+ */
+int ipack_bus_unregister(struct ipack_bus_device *bus);
+
+/**
+ * ipack_driver_register -- Register a new driver
+ *
+ * Called by a ipack driver to register itself as a driver
+ * that can manage ipack devices.
+ */
+int ipack_driver_register(struct ipack_driver *edrv, struct module *owner, char *name);
+void ipack_driver_unregister(struct ipack_driver *edrv);
+
+/**
+ * ipack_device_register -- register a new mezzanine device
+ *
+ * @bus: ipack bus device it is plugged to.
+ * @slot: slot position in the bus device.
+ * @irqv: IRQ vector for the mezzanine.
+ *
+ * Register a new ipack device (mezzanine device). The call is done by
+ * the carrier device driver.
+ */
+struct ipack_device *ipack_device_register(struct ipack_bus_device *bus, int slot, int irqv);
+void ipack_device_unregister(struct ipack_device *dev);
diff --git a/drivers/staging/line6/config.h b/drivers/staging/line6/config.h
deleted file mode 100644
index f8a5149e3dad..000000000000
--- a/drivers/staging/line6/config.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.8.0
- *
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2.
- *
- */
-
-#ifndef CONFIG_H
-#define CONFIG_H
-
-
-#ifdef CONFIG_USB_DEBUG
-#define DEBUG 1
-#endif
-
-
-/*
- * Development tools.
- */
-#define DO_DEBUG_MESSAGES 0
-#define DO_DUMP_URB_SEND DO_DEBUG_MESSAGES
-#define DO_DUMP_URB_RECEIVE DO_DEBUG_MESSAGES
-#define DO_DUMP_PCM_SEND 0
-#define DO_DUMP_PCM_RECEIVE 0
-#define DO_DUMP_MIDI_SEND DO_DEBUG_MESSAGES
-#define DO_DUMP_MIDI_RECEIVE DO_DEBUG_MESSAGES
-#define DO_DUMP_ANY (DO_DUMP_URB_SEND || DO_DUMP_URB_RECEIVE || \
- DO_DUMP_PCM_SEND || DO_DUMP_PCM_RECEIVE || \
- DO_DUMP_MIDI_SEND || DO_DUMP_MIDI_RECEIVE)
-#define CREATE_RAW_FILE 0
-
-#if DO_DEBUG_MESSAGES
-#define CHECKPOINT printk(KERN_INFO "line6usb: %s (%s:%d)\n", \
- __func__, __FILE__, __LINE__)
-#endif
-
-#if DO_DEBUG_MESSAGES
-#define DEBUG_MESSAGES(x) (x)
-#else
-#define DEBUG_MESSAGES(x)
-#endif
-
-
-#endif
diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c
index e8023afd3656..4513f78f1127 100644
--- a/drivers/staging/line6/driver.c
+++ b/drivers/staging/line6/driver.c
@@ -92,15 +92,10 @@ const unsigned char line6_midi_id[] = {
Code to request version of POD, Variax interface
(and maybe other devices).
*/
-static const char line6_request_version0[] = {
+static const char line6_request_version[] = {
0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7
};
-/*
- Copy of version request code with GFP_KERNEL flag for use in URB.
-*/
-static const char *line6_request_version;
-
struct usb_line6 *line6_devices[LINE6_MAX_DEVICES];
/**
@@ -336,8 +331,21 @@ int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer,
*/
int line6_version_request_async(struct usb_line6 *line6)
{
- return line6_send_raw_message_async(line6, line6_request_version,
- sizeof(line6_request_version0));
+ char *buffer;
+ int retval;
+
+ buffer = kmalloc(sizeof(line6_request_version), GFP_ATOMIC);
+ if (buffer == NULL) {
+ dev_err(line6->ifcdev, "Out of memory");
+ return -ENOMEM;
+ }
+
+ memcpy(buffer, line6_request_version, sizeof(line6_request_version));
+
+ retval = line6_send_raw_message_async(line6, buffer,
+ sizeof(line6_request_version));
+ kfree(buffer);
+ return retval;
}
/*
@@ -1292,69 +1300,7 @@ static struct usb_driver line6_driver = {
.id_table = line6_id_table,
};
-/*
- Module initialization.
-*/
-static int __init line6_init(void)
-{
- int i, retval;
-
- printk(KERN_INFO "%s driver version %s\n", DRIVER_NAME, DRIVER_VERSION);
-
- for (i = LINE6_MAX_DEVICES; i--;)
- line6_devices[i] = NULL;
-
- retval = usb_register(&line6_driver);
-
- if (retval) {
- err("usb_register failed. Error number %d", retval);
- return retval;
- }
-
- line6_request_version = kmalloc(sizeof(line6_request_version0),
- GFP_KERNEL);
-
- if (line6_request_version == NULL) {
- err("Out of memory");
- return -ENOMEM;
- }
-
- memcpy((char *)line6_request_version, line6_request_version0,
- sizeof(line6_request_version0));
-
- return retval;
-}
-
-/*
- Module cleanup.
-*/
-static void __exit line6_exit(void)
-{
- int i;
- struct usb_line6 *line6;
- struct snd_line6_pcm *line6pcm;
-
- /* stop all PCM channels */
- for (i = LINE6_MAX_DEVICES; i--;) {
- line6 = line6_devices[i];
-
- if (line6 == NULL)
- continue;
-
- line6pcm = line6->line6pcm;
-
- if (line6pcm == NULL)
- continue;
-
- line6_pcm_release(line6pcm, ~0);
- }
-
- usb_deregister(&line6_driver);
- kfree(line6_request_version);
-}
-
-module_init(line6_init);
-module_exit(line6_exit);
+module_usb_driver(line6_driver);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/staging/line6/midi.c b/drivers/staging/line6/midi.c
index 13d02939c3cb..50407294fbd4 100644
--- a/drivers/staging/line6/midi.c
+++ b/drivers/staging/line6/midi.c
@@ -406,7 +406,7 @@ int line6_init_midi(struct usb_line6 *line6)
line6midi->line6 = line6;
- switch(line6->product) {
+ switch (line6->product) {
case LINE6_DEVID_PODHD300:
case LINE6_DEVID_PODHD500:
line6midi->midi_mask_transmit = 1;
diff --git a/drivers/staging/line6/midibuf.c b/drivers/staging/line6/midibuf.c
index 7b532e5ce8b4..836e8c847c52 100644
--- a/drivers/staging/line6/midibuf.c
+++ b/drivers/staging/line6/midibuf.c
@@ -64,7 +64,7 @@ int line6_midibuf_init(struct MidiBuffer *this, int size, int split)
void line6_midibuf_status(struct MidiBuffer *this)
{
- printk(KERN_DEBUG "midibuf size=%d split=%d pos_read=%d pos_write=%d "
+ pr_debug("midibuf size=%d split=%d pos_read=%d pos_write=%d "
"full=%d command_prev=%02x\n", this->size, this->split,
this->pos_read, this->pos_write, this->full, this->command_prev);
}
diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c
index 90d2d4475cb4..5e319e3ce685 100644
--- a/drivers/staging/line6/pcm.c
+++ b/drivers/staging/line6/pcm.c
@@ -99,7 +99,7 @@ int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels)
unsigned long flags_new = flags_old | channels;
unsigned long flags_final = flags_old;
int err = 0;
-
+
line6pcm->prev_fbuf = NULL;
if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) {
diff --git a/drivers/staging/line6/toneport.c b/drivers/staging/line6/toneport.c
index b754f69a29c4..31b624b63425 100644
--- a/drivers/staging/line6/toneport.c
+++ b/drivers/staging/line6/toneport.c
@@ -168,7 +168,7 @@ static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2)
cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ);
if (ret < 0) {
- err("send failed (error %d)\n", ret);
+ dev_err(&usbdev->dev, "send failed (error %d)\n", ret);
return ret;
}
diff --git a/drivers/staging/media/as102/as102_drv.c b/drivers/staging/media/as102/as102_drv.c
index ea4f992de235..ac92eaf6c74b 100644
--- a/drivers/staging/media/as102/as102_drv.c
+++ b/drivers/staging/media/as102/as102_drv.c
@@ -279,40 +279,8 @@ void as102_dvb_unregister(struct as102_dev_t *as102_dev)
pr_info("Unregistered device %s", as102_dev->name);
}
-static int __init as102_driver_init(void)
-{
- int ret;
-
- /* register this driver with the low level subsystem */
- ret = usb_register(&as102_usb_driver);
- if (ret)
- err("usb_register failed (ret = %d)", ret);
-
- return ret;
-}
-
-/*
- * Mandatory function : Adds a special section to the module indicating
- * where initialisation function is defined
- */
-module_init(as102_driver_init);
-
-/**
- * as102_driver_exit - as102 driver exit point
- *
- * This function is called when device has to be removed.
- */
-static void __exit as102_driver_exit(void)
-{
- /* deregister this driver with the low level bus subsystem */
- usb_deregister(&as102_usb_driver);
-}
+module_usb_driver(as102_usb_driver);
-/*
- * required function for unload: Adds a special section to the module
- * indicating where unload function is defined
- */
-module_exit(as102_driver_exit);
/* modinfo details */
MODULE_DESCRIPTION(DRIVER_FULL_NAME);
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/as102/as102_fe.c b/drivers/staging/media/as102/as102_fe.c
index 5917657b9d0f..9ce8c9daa2e7 100644
--- a/drivers/staging/media/as102/as102_fe.c
+++ b/drivers/staging/media/as102/as102_fe.c
@@ -17,8 +17,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/version.h>
-
#include "as102_drv.h"
#include "as10x_types.h"
#include "as10x_cmd.h"
diff --git a/drivers/staging/media/as102/as102_fw.c b/drivers/staging/media/as102/as102_fw.c
index 1075fb1df0d9..b9670ee41b4e 100644
--- a/drivers/staging/media/as102/as102_fw.c
+++ b/drivers/staging/media/as102/as102_fw.c
@@ -230,11 +230,8 @@ int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap)
pr_info("%s: firmware: %s loaded with success\n",
DRIVER_NAME, fw2);
error:
- /* free data buffer */
kfree(cmd_buf);
- /* release firmware if needed */
- if (firmware != NULL)
- release_firmware(firmware);
+ release_firmware(firmware);
LEAVE();
return errno;
diff --git a/drivers/staging/media/as102/as102_usb_drv.c b/drivers/staging/media/as102/as102_usb_drv.c
index 0f6bfe7eccba..aaf1bc2ad1b2 100644
--- a/drivers/staging/media/as102/as102_usb_drv.c
+++ b/drivers/staging/media/as102/as102_usb_drv.c
@@ -367,7 +367,7 @@ static int as102_usb_probe(struct usb_interface *intf,
ENTER();
/* This should never actually happen */
- if ((sizeof(as102_usb_id_table) / sizeof(struct usb_device_id)) !=
+ if (ARRAY_SIZE(as102_usb_id_table) !=
(sizeof(as102_device_names) / sizeof(const char *))) {
pr_err("Device names table invalid size");
return -EINVAL;
@@ -375,13 +375,12 @@ static int as102_usb_probe(struct usb_interface *intf,
as102_dev = kzalloc(sizeof(struct as102_dev_t), GFP_KERNEL);
if (as102_dev == NULL) {
- err("%s: kzalloc failed", __func__);
+ dev_err(&intf->dev, "%s: kzalloc failed\n", __func__);
return -ENOMEM;
}
/* Assign the user-friendly device name */
- for (i = 0; i < (sizeof(as102_usb_id_table) /
- sizeof(struct usb_device_id)); i++) {
+ for (i = 0; i < ARRAY_SIZE(as102_usb_id_table); i++) {
if (id == &as102_usb_id_table[i]) {
as102_dev->name = as102_device_names[i];
as102_dev->elna_cfg = as102_elna_cfg[i];
@@ -411,8 +410,9 @@ static int as102_usb_probe(struct usb_interface *intf,
ret = usb_register_dev(intf, &as102_usb_class_driver);
if (ret < 0) {
/* something prevented us from registering this driver */
- err("%s: usb_register_dev() failed (errno = %d)",
- __func__, ret);
+ dev_err(&intf->dev,
+ "%s: usb_register_dev() failed (errno = %d)\n",
+ __func__, ret);
goto failed;
}
diff --git a/drivers/staging/media/as102/as102_usb_drv.h b/drivers/staging/media/as102/as102_usb_drv.h
index fc2884ab02a2..1ad1ec52b11e 100644
--- a/drivers/staging/media/as102/as102_usb_drv.h
+++ b/drivers/staging/media/as102/as102_usb_drv.h
@@ -17,8 +17,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/version.h>
-
#ifndef _AS102_USB_DRV_H_
#define _AS102_USB_DRV_H_
diff --git a/drivers/staging/media/as102/as10x_cmd.c b/drivers/staging/media/as102/as10x_cmd.c
index 262bb94ad27e..a73df10982d0 100644
--- a/drivers/staging/media/as102/as10x_cmd.c
+++ b/drivers/staging/media/as102/as10x_cmd.c
@@ -31,7 +31,7 @@
*/
int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap)
{
- int error;
+ int error = AS10X_CMD_ERROR;
struct as10x_cmd_t *pcmd, *prsp;
ENTER();
@@ -54,8 +54,6 @@ int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap)
(uint8_t *) prsp,
sizeof(prsp->body.turn_on.rsp) +
HEADER_SIZE);
- } else {
- error = AS10X_CMD_ERROR;
}
if (error < 0)
@@ -77,7 +75,7 @@ out:
*/
int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap)
{
- int error;
+ int error = AS10X_CMD_ERROR;
struct as10x_cmd_t *pcmd, *prsp;
ENTER();
@@ -99,8 +97,6 @@ int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap)
sizeof(pcmd->body.turn_off.req) + HEADER_SIZE,
(uint8_t *) prsp,
sizeof(prsp->body.turn_off.rsp) + HEADER_SIZE);
- } else {
- error = AS10X_CMD_ERROR;
}
if (error < 0)
@@ -124,7 +120,7 @@ out:
int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap,
struct as10x_tune_args *ptune)
{
- int error;
+ int error = AS10X_CMD_ERROR;
struct as10x_cmd_t *preq, *prsp;
ENTER();
@@ -159,8 +155,6 @@ int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap,
(uint8_t *) prsp,
sizeof(prsp->body.set_tune.rsp)
+ HEADER_SIZE);
- } else {
- error = AS10X_CMD_ERROR;
}
if (error < 0)
@@ -184,7 +178,7 @@ out:
int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap,
struct as10x_tune_status *pstatus)
{
- int error;
+ int error = AS10X_CMD_ERROR;
struct as10x_cmd_t *preq, *prsp;
ENTER();
@@ -208,8 +202,6 @@ int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap,
sizeof(preq->body.get_tune_status.req) + HEADER_SIZE,
(uint8_t *) prsp,
sizeof(prsp->body.get_tune_status.rsp) + HEADER_SIZE);
- } else {
- error = AS10X_CMD_ERROR;
}
if (error < 0)
@@ -241,7 +233,7 @@ out:
*/
int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap, struct as10x_tps *ptps)
{
- int error;
+ int error = AS10X_CMD_ERROR;
struct as10x_cmd_t *pcmd, *prsp;
ENTER();
@@ -266,8 +258,6 @@ int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap, struct as10x_tps *ptps)
(uint8_t *) prsp,
sizeof(prsp->body.get_tps.rsp) +
HEADER_SIZE);
- } else {
- error = AS10X_CMD_ERROR;
}
if (error < 0)
@@ -305,7 +295,7 @@ out:
int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t *adap,
struct as10x_demod_stats *pdemod_stats)
{
- int error;
+ int error = AS10X_CMD_ERROR;
struct as10x_cmd_t *pcmd, *prsp;
ENTER();
@@ -330,8 +320,6 @@ int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t *adap,
(uint8_t *) prsp,
sizeof(prsp->body.get_demod_stats.rsp)
+ HEADER_SIZE);
- } else {
- error = AS10X_CMD_ERROR;
}
if (error < 0)
@@ -370,7 +358,7 @@ out:
int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap,
uint8_t *is_ready)
{
- int error;
+ int error = AS10X_CMD_ERROR;
struct as10x_cmd_t *pcmd, *prsp;
ENTER();
@@ -395,8 +383,6 @@ int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap,
(uint8_t *) prsp,
sizeof(prsp->body.get_impulse_rsp.rsp)
+ HEADER_SIZE);
- } else {
- error = AS10X_CMD_ERROR;
}
if (error < 0)
diff --git a/drivers/staging/media/dt3155v4l/dt3155v4l.c b/drivers/staging/media/dt3155v4l/dt3155v4l.c
index 280c84ec4cc2..c365cdf714ea 100644
--- a/drivers/staging/media/dt3155v4l/dt3155v4l.c
+++ b/drivers/staging/media/dt3155v4l/dt3155v4l.c
@@ -898,6 +898,10 @@ dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id)
INIT_LIST_HEAD(&pd->dmaq);
mutex_init(&pd->mux);
pd->vdev->lock = &pd->mux; /* for locking v4l2_file_operations */
+ /* Locking in file operations other than ioctl should be done
+ by the driver, not the V4L2 core.
+ This driver needs auditing so that this flag can be removed. */
+ set_bit(V4L2_FL_LOCK_ALL_FOPS, &pd->vdev->flags);
spin_lock_init(&pd->lock);
pd->csr2 = csr2_init;
pd->config = config_init;
diff --git a/drivers/staging/media/easycap/easycap_ioctl.c b/drivers/staging/media/easycap/easycap_ioctl.c
index 9413b37490c2..3cee3cd986d2 100644
--- a/drivers/staging/media/easycap/easycap_ioctl.c
+++ b/drivers/staging/media/easycap/easycap_ioctl.c
@@ -26,6 +26,7 @@
/*****************************************************************************/
#include "easycap.h"
+#include <linux/version.h>
/*--------------------------------------------------------------------------*/
/*
diff --git a/drivers/staging/media/easycap/easycap_main.c b/drivers/staging/media/easycap/easycap_main.c
index d0fe34afc2e5..a1c45e4dcdce 100644
--- a/drivers/staging/media/easycap/easycap_main.c
+++ b/drivers/staging/media/easycap/easycap_main.c
@@ -700,214 +700,7 @@ static int videodev_release(struct video_device *pvideo_device)
JOM(4, "ending successfully\n");
return 0;
}
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-/*****************************************************************************/
-/*--------------------------------------------------------------------------*/
-/*
- * THIS FUNCTION IS CALLED FROM WITHIN easycap_usb_disconnect() AND IS
- * PROTECTED BY SEMAPHORES SET AND CLEARED BY easycap_usb_disconnect().
- *
- * BY THIS STAGE THE DEVICE HAS ALREADY BEEN PHYSICALLY UNPLUGGED, SO
- * peasycap->pusb_device IS NO LONGER VALID.
- */
-/*---------------------------------------------------------------------------*/
-static void easycap_delete(struct kref *pkref)
-{
- struct easycap *peasycap;
- struct data_urb *pdata_urb;
- struct list_head *plist_head, *plist_next;
- int k, m, gone, kd;
- int allocation_video_urb;
- int allocation_video_page;
- int allocation_video_struct;
- int allocation_audio_urb;
- int allocation_audio_page;
- int allocation_audio_struct;
- int registered_video, registered_audio;
-
- peasycap = container_of(pkref, struct easycap, kref);
- if (!peasycap) {
- SAM("ERROR: peasycap is NULL: cannot perform deletions\n");
- return;
- }
- kd = easycap_isdongle(peasycap);
-/*---------------------------------------------------------------------------*/
-/*
- * FREE VIDEO.
- */
-/*---------------------------------------------------------------------------*/
- if (peasycap->purb_video_head) {
- m = 0;
- list_for_each(plist_head, peasycap->purb_video_head) {
- pdata_urb = list_entry(plist_head,
- struct data_urb, list_head);
- if (pdata_urb && pdata_urb->purb) {
- usb_free_urb(pdata_urb->purb);
- pdata_urb->purb = NULL;
- peasycap->allocation_video_urb--;
- m++;
- }
- }
-
- JOM(4, "%i video urbs freed\n", m);
-/*---------------------------------------------------------------------------*/
- JOM(4, "freeing video data_urb structures.\n");
- m = 0;
- list_for_each_safe(plist_head, plist_next,
- peasycap->purb_video_head) {
- pdata_urb = list_entry(plist_head,
- struct data_urb, list_head);
- if (pdata_urb) {
- peasycap->allocation_video_struct -=
- sizeof(struct data_urb);
- kfree(pdata_urb);
- m++;
- }
- }
- JOM(4, "%i video data_urb structures freed\n", m);
- JOM(4, "setting peasycap->purb_video_head=NULL\n");
- peasycap->purb_video_head = NULL;
- }
-/*---------------------------------------------------------------------------*/
- JOM(4, "freeing video isoc buffers.\n");
- m = 0;
- for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) {
- if (peasycap->video_isoc_buffer[k].pgo) {
- free_pages((unsigned long)
- peasycap->video_isoc_buffer[k].pgo,
- VIDEO_ISOC_ORDER);
- peasycap->video_isoc_buffer[k].pgo = NULL;
- peasycap->allocation_video_page -=
- BIT(VIDEO_ISOC_ORDER);
- m++;
- }
- }
- JOM(4, "isoc video buffers freed: %i pages\n",
- m * (0x01 << VIDEO_ISOC_ORDER));
-/*---------------------------------------------------------------------------*/
- JOM(4, "freeing video field buffers.\n");
- gone = 0;
- for (k = 0; k < FIELD_BUFFER_MANY; k++) {
- for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++) {
- if (peasycap->field_buffer[k][m].pgo) {
- free_page((unsigned long)
- peasycap->field_buffer[k][m].pgo);
- peasycap->field_buffer[k][m].pgo = NULL;
- peasycap->allocation_video_page -= 1;
- gone++;
- }
- }
- }
- JOM(4, "video field buffers freed: %i pages\n", gone);
-/*---------------------------------------------------------------------------*/
- JOM(4, "freeing video frame buffers.\n");
- gone = 0;
- for (k = 0; k < FRAME_BUFFER_MANY; k++) {
- for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++) {
- if (peasycap->frame_buffer[k][m].pgo) {
- free_page((unsigned long)
- peasycap->frame_buffer[k][m].pgo);
- peasycap->frame_buffer[k][m].pgo = NULL;
- peasycap->allocation_video_page -= 1;
- gone++;
- }
- }
- }
- JOM(4, "video frame buffers freed: %i pages\n", gone);
-/*---------------------------------------------------------------------------*/
-/*
- * FREE AUDIO.
- */
-/*---------------------------------------------------------------------------*/
- if (peasycap->purb_audio_head) {
- JOM(4, "freeing audio urbs\n");
- m = 0;
- list_for_each(plist_head, (peasycap->purb_audio_head)) {
- pdata_urb = list_entry(plist_head,
- struct data_urb, list_head);
- if (pdata_urb && pdata_urb->purb) {
- usb_free_urb(pdata_urb->purb);
- pdata_urb->purb = NULL;
- peasycap->allocation_audio_urb--;
- m++;
- }
- }
- JOM(4, "%i audio urbs freed\n", m);
-/*---------------------------------------------------------------------------*/
- JOM(4, "freeing audio data_urb structures.\n");
- m = 0;
- list_for_each_safe(plist_head, plist_next,
- peasycap->purb_audio_head) {
- pdata_urb = list_entry(plist_head,
- struct data_urb, list_head);
- if (pdata_urb) {
- peasycap->allocation_audio_struct -=
- sizeof(struct data_urb);
- kfree(pdata_urb);
- m++;
- }
- }
- JOM(4, "%i audio data_urb structures freed\n", m);
- JOM(4, "setting peasycap->purb_audio_head=NULL\n");
- peasycap->purb_audio_head = NULL;
- }
-/*---------------------------------------------------------------------------*/
- JOM(4, "freeing audio isoc buffers.\n");
- m = 0;
- for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
- if (peasycap->audio_isoc_buffer[k].pgo) {
- free_pages((unsigned long)
- (peasycap->audio_isoc_buffer[k].pgo),
- AUDIO_ISOC_ORDER);
- peasycap->audio_isoc_buffer[k].pgo = NULL;
- peasycap->allocation_audio_page -=
- BIT(AUDIO_ISOC_ORDER);
- m++;
- }
- }
- JOM(4, "easyoss_delete(): isoc audio buffers freed: %i pages\n",
- m * (0x01 << AUDIO_ISOC_ORDER));
-/*---------------------------------------------------------------------------*/
- JOM(4, "freeing easycap structure.\n");
- allocation_video_urb = peasycap->allocation_video_urb;
- allocation_video_page = peasycap->allocation_video_page;
- allocation_video_struct = peasycap->allocation_video_struct;
- registered_video = peasycap->registered_video;
- allocation_audio_urb = peasycap->allocation_audio_urb;
- allocation_audio_page = peasycap->allocation_audio_page;
- allocation_audio_struct = peasycap->allocation_audio_struct;
- registered_audio = peasycap->registered_audio;
-
- if (0 <= kd && DONGLE_MANY > kd) {
- if (mutex_lock_interruptible(&mutex_dongle)) {
- SAY("ERROR: cannot down mutex_dongle\n");
- } else {
- JOM(4, "locked mutex_dongle\n");
- easycapdc60_dongle[kd].peasycap = NULL;
- mutex_unlock(&mutex_dongle);
- JOM(4, "unlocked mutex_dongle\n");
- JOT(4, " null-->dongle[%i].peasycap\n", kd);
- allocation_video_struct -= sizeof(struct easycap);
- }
- } else {
- SAY("ERROR: cannot purge dongle[].peasycap");
- }
- kfree(peasycap);
-
-/*---------------------------------------------------------------------------*/
- SAY("%8i=video urbs after all deletions\n", allocation_video_urb);
- SAY("%8i=video pages after all deletions\n", allocation_video_page);
- SAY("%8i=video structs after all deletions\n", allocation_video_struct);
- SAY("%8i=video devices after all deletions\n", registered_video);
- SAY("%8i=audio urbs after all deletions\n", allocation_audio_urb);
- SAY("%8i=audio pages after all deletions\n", allocation_audio_page);
- SAY("%8i=audio structs after all deletions\n", allocation_audio_struct);
- SAY("%8i=audio devices after all deletions\n", registered_audio);
-
- JOT(4, "ending.\n");
- return;
-}
/*****************************************************************************/
static unsigned int easycap_poll(struct file *file, poll_table *wait)
{
@@ -2842,6 +2635,813 @@ static void easycap_complete(struct urb *purb)
return;
}
+static struct easycap *alloc_easycap(u8 bInterfaceNumber)
+{
+ struct easycap *peasycap;
+ int i;
+
+ peasycap = kzalloc(sizeof(struct easycap), GFP_KERNEL);
+ if (!peasycap) {
+ SAY("ERROR: Could not allocate peasycap\n");
+ return NULL;
+ }
+
+ if (mutex_lock_interruptible(&mutex_dongle)) {
+ SAY("ERROR: cannot lock mutex_dongle\n");
+ kfree(peasycap);
+ return NULL;
+ }
+
+ /* Find a free dongle in easycapdc60_dongle array */
+ for (i = 0; i < DONGLE_MANY; i++) {
+
+ if ((!easycapdc60_dongle[i].peasycap) &&
+ (!mutex_is_locked(&easycapdc60_dongle[i].mutex_video)) &&
+ (!mutex_is_locked(&easycapdc60_dongle[i].mutex_audio))) {
+
+ easycapdc60_dongle[i].peasycap = peasycap;
+ peasycap->isdongle = i;
+ JOM(8, "intf[%i]: peasycap-->easycap"
+ "_dongle[%i].peasycap\n",
+ bInterfaceNumber, i);
+ break;
+ }
+ }
+
+ mutex_unlock(&mutex_dongle);
+
+ if (i >= DONGLE_MANY) {
+ SAM("ERROR: too many dongles\n");
+ kfree(peasycap);
+ return NULL;
+ }
+
+ return peasycap;
+}
+
+static void free_easycap(struct easycap *peasycap)
+{
+ int allocation_video_urb;
+ int allocation_video_page;
+ int allocation_video_struct;
+ int allocation_audio_urb;
+ int allocation_audio_page;
+ int allocation_audio_struct;
+ int registered_video, registered_audio;
+ int kd;
+
+ JOM(4, "freeing easycap structure.\n");
+ allocation_video_urb = peasycap->allocation_video_urb;
+ allocation_video_page = peasycap->allocation_video_page;
+ allocation_video_struct = peasycap->allocation_video_struct;
+ registered_video = peasycap->registered_video;
+ allocation_audio_urb = peasycap->allocation_audio_urb;
+ allocation_audio_page = peasycap->allocation_audio_page;
+ allocation_audio_struct = peasycap->allocation_audio_struct;
+ registered_audio = peasycap->registered_audio;
+
+ kd = easycap_isdongle(peasycap);
+ if (0 <= kd && DONGLE_MANY > kd) {
+ if (mutex_lock_interruptible(&mutex_dongle)) {
+ SAY("ERROR: cannot down mutex_dongle\n");
+ } else {
+ JOM(4, "locked mutex_dongle\n");
+ easycapdc60_dongle[kd].peasycap = NULL;
+ mutex_unlock(&mutex_dongle);
+ JOM(4, "unlocked mutex_dongle\n");
+ JOT(4, " null-->dongle[%i].peasycap\n", kd);
+ allocation_video_struct -= sizeof(struct easycap);
+ }
+ } else {
+ SAY("ERROR: cannot purge dongle[].peasycap");
+ }
+
+ /* Free device structure */
+ kfree(peasycap);
+
+ SAY("%8i=video urbs after all deletions\n", allocation_video_urb);
+ SAY("%8i=video pages after all deletions\n", allocation_video_page);
+ SAY("%8i=video structs after all deletions\n", allocation_video_struct);
+ SAY("%8i=video devices after all deletions\n", registered_video);
+ SAY("%8i=audio urbs after all deletions\n", allocation_audio_urb);
+ SAY("%8i=audio pages after all deletions\n", allocation_audio_page);
+ SAY("%8i=audio structs after all deletions\n", allocation_audio_struct);
+ SAY("%8i=audio devices after all deletions\n", registered_audio);
+}
+
+/*
+ * FIXME: Identify the appropriate pointer peasycap for interfaces
+ * 1 and 2. The address of peasycap->pusb_device is reluctantly used
+ * for this purpose.
+ */
+static struct easycap *get_easycap(struct usb_device *usbdev,
+ u8 bInterfaceNumber)
+{
+ int i;
+ struct easycap *peasycap;
+
+ for (i = 0; i < DONGLE_MANY; i++) {
+ if (easycapdc60_dongle[i].peasycap->pusb_device == usbdev) {
+ peasycap = easycapdc60_dongle[i].peasycap;
+ JOT(8, "intf[%i]: dongle[%i].peasycap\n",
+ bInterfaceNumber, i);
+ break;
+ }
+ }
+ if (i >= DONGLE_MANY) {
+ SAY("ERROR: peasycap is unknown when probing interface %i\n",
+ bInterfaceNumber);
+ return NULL;
+ }
+ if (!peasycap) {
+ SAY("ERROR: peasycap is NULL when probing interface %i\n",
+ bInterfaceNumber);
+ return NULL;
+ }
+
+ return peasycap;
+}
+
+static void init_easycap(struct easycap *peasycap,
+ struct usb_device *usbdev,
+ struct usb_interface *intf,
+ u8 bInterfaceNumber)
+{
+ /* Save usb_device and usb_interface */
+ peasycap->pusb_device = usbdev;
+ peasycap->pusb_interface = intf;
+
+ peasycap->minor = -1;
+ kref_init(&peasycap->kref);
+ JOM(8, "intf[%i]: after kref_init(..._video) "
+ "%i=peasycap->kref.refcount.counter\n",
+ bInterfaceNumber, peasycap->kref.refcount.counter);
+
+ /* module params */
+ peasycap->gain = (s8)clamp(easycap_gain, 0, 31);
+
+ init_waitqueue_head(&peasycap->wq_video);
+ init_waitqueue_head(&peasycap->wq_audio);
+ init_waitqueue_head(&peasycap->wq_trigger);
+
+ peasycap->allocation_video_struct = sizeof(struct easycap);
+
+ peasycap->microphone = false;
+
+ peasycap->video_interface = -1;
+ peasycap->video_altsetting_on = -1;
+ peasycap->video_altsetting_off = -1;
+ peasycap->video_endpointnumber = -1;
+ peasycap->video_isoc_maxframesize = -1;
+ peasycap->video_isoc_buffer_size = -1;
+
+ peasycap->audio_interface = -1;
+ peasycap->audio_altsetting_on = -1;
+ peasycap->audio_altsetting_off = -1;
+ peasycap->audio_endpointnumber = -1;
+ peasycap->audio_isoc_maxframesize = -1;
+ peasycap->audio_isoc_buffer_size = -1;
+
+ peasycap->frame_buffer_many = FRAME_BUFFER_MANY;
+
+ peasycap->ntsc = easycap_ntsc;
+ JOM(8, "defaulting initially to %s\n",
+ easycap_ntsc ? "NTSC" : "PAL");
+}
+
+static int populate_inputset(struct easycap *peasycap)
+{
+ struct inputset *inputset;
+ struct easycap_format *peasycap_format;
+ struct v4l2_pix_format *pix;
+ int m, i, k, mask, fmtidx;
+ s32 value;
+
+ inputset = peasycap->inputset;
+
+ fmtidx = peasycap->ntsc ? NTSC_M : PAL_BGHIN;
+
+ m = 0;
+ mask = 0;
+ for (i = 0; easycap_standard[i].mask != 0xffff; i++) {
+ if (fmtidx == easycap_standard[i].v4l2_standard.index) {
+ m++;
+ for (k = 0; k < INPUT_MANY; k++)
+ inputset[k].standard_offset = i;
+ mask = easycap_standard[i].mask;
+ }
+ }
+
+ if (m != 1) {
+ SAM("ERROR: inputset->standard_offset unpopulated, %i=m\n", m);
+ return -ENOENT;
+ }
+
+ peasycap_format = &easycap_format[0];
+ m = 0;
+ for (i = 0; peasycap_format->v4l2_format.fmt.pix.width; i++) {
+ pix = &peasycap_format->v4l2_format.fmt.pix;
+ if (((peasycap_format->mask & 0x0F) == (mask & 0x0F))
+ && pix->field == V4L2_FIELD_NONE
+ && pix->pixelformat == V4L2_PIX_FMT_UYVY
+ && pix->width == 640 && pix->height == 480) {
+ m++;
+ for (k = 0; k < INPUT_MANY; k++)
+ inputset[k].format_offset = i;
+ break;
+ }
+ peasycap_format++;
+ }
+ if (m != 1) {
+ SAM("ERROR: inputset[]->format_offset unpopulated\n");
+ return -ENOENT;
+ }
+
+ m = 0;
+ for (i = 0; easycap_control[i].id != 0xffffffff; i++) {
+ value = easycap_control[i].default_value;
+ if (V4L2_CID_BRIGHTNESS == easycap_control[i].id) {
+ m++;
+ for (k = 0; k < INPUT_MANY; k++)
+ inputset[k].brightness = value;
+ } else if (V4L2_CID_CONTRAST == easycap_control[i].id) {
+ m++;
+ for (k = 0; k < INPUT_MANY; k++)
+ inputset[k].contrast = value;
+ } else if (V4L2_CID_SATURATION == easycap_control[i].id) {
+ m++;
+ for (k = 0; k < INPUT_MANY; k++)
+ inputset[k].saturation = value;
+ } else if (V4L2_CID_HUE == easycap_control[i].id) {
+ m++;
+ for (k = 0; k < INPUT_MANY; k++)
+ inputset[k].hue = value;
+ }
+ }
+
+ if (m != 4) {
+ SAM("ERROR: inputset[]->brightness underpopulated\n");
+ return -ENOENT;
+ }
+
+ for (k = 0; k < INPUT_MANY; k++)
+ inputset[k].input = k;
+ JOM(4, "populated inputset[]\n");
+
+ return 0;
+}
+
+static int alloc_framebuffers(struct easycap *peasycap)
+{
+ int i, j;
+ void *pbuf;
+
+ JOM(4, "allocating %i frame buffers of size %li\n",
+ FRAME_BUFFER_MANY, (long int)FRAME_BUFFER_SIZE);
+ JOM(4, ".... each scattered over %li pages\n",
+ FRAME_BUFFER_SIZE/PAGE_SIZE);
+
+ for (i = 0; i < FRAME_BUFFER_MANY; i++) {
+ for (j = 0; j < FRAME_BUFFER_SIZE/PAGE_SIZE; j++) {
+ if (peasycap->frame_buffer[i][j].pgo)
+ SAM("attempting to reallocate framebuffers\n");
+ else {
+ pbuf = (void *)__get_free_page(GFP_KERNEL);
+ if (!pbuf) {
+ SAM("ERROR: Could not allocate "
+ "framebuffer %i page %i\n", i, j);
+ return -ENOMEM;
+ }
+ peasycap->allocation_video_page += 1;
+ peasycap->frame_buffer[i][j].pgo = pbuf;
+ }
+ peasycap->frame_buffer[i][j].pto =
+ peasycap->frame_buffer[i][j].pgo;
+ }
+ }
+
+ peasycap->frame_fill = 0;
+ peasycap->frame_read = 0;
+ JOM(4, "allocation of frame buffers done: %i pages\n", i*j);
+
+ return 0;
+}
+
+static void free_framebuffers(struct easycap *peasycap)
+{
+ int k, m, gone;
+
+ JOM(4, "freeing video frame buffers.\n");
+ gone = 0;
+ for (k = 0; k < FRAME_BUFFER_MANY; k++) {
+ for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++) {
+ if (peasycap->frame_buffer[k][m].pgo) {
+ free_page((unsigned long)
+ peasycap->frame_buffer[k][m].pgo);
+ peasycap->frame_buffer[k][m].pgo = NULL;
+ peasycap->allocation_video_page -= 1;
+ gone++;
+ }
+ }
+ }
+ JOM(4, "video frame buffers freed: %i pages\n", gone);
+}
+
+static int alloc_fieldbuffers(struct easycap *peasycap)
+{
+ int i, j;
+ void *pbuf;
+
+ JOM(4, "allocating %i field buffers of size %li\n",
+ FIELD_BUFFER_MANY, (long int)FIELD_BUFFER_SIZE);
+ JOM(4, ".... each scattered over %li pages\n",
+ FIELD_BUFFER_SIZE/PAGE_SIZE);
+
+ for (i = 0; i < FIELD_BUFFER_MANY; i++) {
+ for (j = 0; j < FIELD_BUFFER_SIZE/PAGE_SIZE; j++) {
+ if (peasycap->field_buffer[i][j].pgo) {
+ SAM("ERROR: attempting to reallocate "
+ "fieldbuffers\n");
+ } else {
+ pbuf = (void *) __get_free_page(GFP_KERNEL);
+ if (!pbuf) {
+ SAM("ERROR: Could not allocate "
+ "fieldbuffer %i page %i\n", i, j);
+ return -ENOMEM;
+ }
+ peasycap->allocation_video_page += 1;
+ peasycap->field_buffer[i][j].pgo = pbuf;
+ }
+ peasycap->field_buffer[i][j].pto =
+ peasycap->field_buffer[i][j].pgo;
+ }
+ /* TODO: Hardcoded 0x0200 meaning? */
+ peasycap->field_buffer[i][0].kount = 0x0200;
+ }
+ peasycap->field_fill = 0;
+ peasycap->field_page = 0;
+ peasycap->field_read = 0;
+ JOM(4, "allocation of field buffers done: %i pages\n", i*j);
+
+ return 0;
+}
+
+static void free_fieldbuffers(struct easycap *peasycap)
+{
+ int k, m, gone;
+
+ JOM(4, "freeing video field buffers.\n");
+ gone = 0;
+ for (k = 0; k < FIELD_BUFFER_MANY; k++) {
+ for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++) {
+ if (peasycap->field_buffer[k][m].pgo) {
+ free_page((unsigned long)
+ peasycap->field_buffer[k][m].pgo);
+ peasycap->field_buffer[k][m].pgo = NULL;
+ peasycap->allocation_video_page -= 1;
+ gone++;
+ }
+ }
+ }
+ JOM(4, "video field buffers freed: %i pages\n", gone);
+}
+
+static int alloc_isocbuffers(struct easycap *peasycap)
+{
+ int i;
+ void *pbuf;
+
+ JOM(4, "allocating %i isoc video buffers of size %i\n",
+ VIDEO_ISOC_BUFFER_MANY,
+ peasycap->video_isoc_buffer_size);
+ JOM(4, ".... each occupying contiguous memory pages\n");
+
+ for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++) {
+ pbuf = (void *)__get_free_pages(GFP_KERNEL,
+ VIDEO_ISOC_ORDER);
+ if (!pbuf) {
+ SAM("ERROR: Could not allocate isoc "
+ "video buffer %i\n", i);
+ return -ENOMEM;
+ }
+ peasycap->allocation_video_page += BIT(VIDEO_ISOC_ORDER);
+
+ peasycap->video_isoc_buffer[i].pgo = pbuf;
+ peasycap->video_isoc_buffer[i].pto =
+ pbuf + peasycap->video_isoc_buffer_size;
+ peasycap->video_isoc_buffer[i].kount = i;
+ }
+ JOM(4, "allocation of isoc video buffers done: %i pages\n",
+ i * (0x01 << VIDEO_ISOC_ORDER));
+ return 0;
+}
+
+static void free_isocbuffers(struct easycap *peasycap)
+{
+ int k, m;
+
+ JOM(4, "freeing video isoc buffers.\n");
+ m = 0;
+ for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) {
+ if (peasycap->video_isoc_buffer[k].pgo) {
+ free_pages((unsigned long)
+ peasycap->video_isoc_buffer[k].pgo,
+ VIDEO_ISOC_ORDER);
+ peasycap->video_isoc_buffer[k].pgo = NULL;
+ peasycap->allocation_video_page -=
+ BIT(VIDEO_ISOC_ORDER);
+ m++;
+ }
+ }
+ JOM(4, "isoc video buffers freed: %i pages\n",
+ m * (0x01 << VIDEO_ISOC_ORDER));
+}
+
+static int create_video_urbs(struct easycap *peasycap)
+{
+ struct urb *purb;
+ struct data_urb *pdata_urb;
+ int i, j;
+
+ JOM(4, "allocating %i struct urb.\n", VIDEO_ISOC_BUFFER_MANY);
+ JOM(4, "using %i=peasycap->video_isoc_framesperdesc\n",
+ peasycap->video_isoc_framesperdesc);
+ JOM(4, "using %i=peasycap->video_isoc_maxframesize\n",
+ peasycap->video_isoc_maxframesize);
+ JOM(4, "using %i=peasycap->video_isoc_buffer_sizen",
+ peasycap->video_isoc_buffer_size);
+
+ for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++) {
+ purb = usb_alloc_urb(peasycap->video_isoc_framesperdesc,
+ GFP_KERNEL);
+ if (!purb) {
+ SAM("ERROR: usb_alloc_urb returned NULL for buffer "
+ "%i\n", i);
+ return -ENOMEM;
+ }
+
+ peasycap->allocation_video_urb += 1;
+ pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
+ if (!pdata_urb) {
+ SAM("ERROR: Could not allocate struct data_urb.\n");
+ return -ENOMEM;
+ }
+
+ peasycap->allocation_video_struct +=
+ sizeof(struct data_urb);
+
+ pdata_urb->purb = purb;
+ pdata_urb->isbuf = i;
+ pdata_urb->length = 0;
+ list_add_tail(&(pdata_urb->list_head),
+ peasycap->purb_video_head);
+
+ if (!i) {
+ JOM(4, "initializing video urbs thus:\n");
+ JOM(4, " purb->interval = 1;\n");
+ JOM(4, " purb->dev = peasycap->pusb_device;\n");
+ JOM(4, " purb->pipe = usb_rcvisocpipe"
+ "(peasycap->pusb_device,%i);\n",
+ peasycap->video_endpointnumber);
+ JOM(4, " purb->transfer_flags = URB_ISO_ASAP;\n");
+ JOM(4, " purb->transfer_buffer = peasycap->"
+ "video_isoc_buffer[.].pgo;\n");
+ JOM(4, " purb->transfer_buffer_length = %i;\n",
+ peasycap->video_isoc_buffer_size);
+ JOM(4, " purb->complete = easycap_complete;\n");
+ JOM(4, " purb->context = peasycap;\n");
+ JOM(4, " purb->start_frame = 0;\n");
+ JOM(4, " purb->number_of_packets = %i;\n",
+ peasycap->video_isoc_framesperdesc);
+ JOM(4, " for (j = 0; j < %i; j++)\n",
+ peasycap->video_isoc_framesperdesc);
+ JOM(4, " {\n");
+ JOM(4, " purb->iso_frame_desc[j].offset = j*%i;\n",
+ peasycap->video_isoc_maxframesize);
+ JOM(4, " purb->iso_frame_desc[j].length = %i;\n",
+ peasycap->video_isoc_maxframesize);
+ JOM(4, " }\n");
+ }
+
+ purb->interval = 1;
+ purb->dev = peasycap->pusb_device;
+ purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
+ peasycap->video_endpointnumber);
+
+ purb->transfer_flags = URB_ISO_ASAP;
+ purb->transfer_buffer = peasycap->video_isoc_buffer[i].pgo;
+ purb->transfer_buffer_length =
+ peasycap->video_isoc_buffer_size;
+
+ purb->complete = easycap_complete;
+ purb->context = peasycap;
+ purb->start_frame = 0;
+ purb->number_of_packets = peasycap->video_isoc_framesperdesc;
+
+ for (j = 0; j < peasycap->video_isoc_framesperdesc; j++) {
+ purb->iso_frame_desc[j].offset =
+ j * peasycap->video_isoc_maxframesize;
+ purb->iso_frame_desc[j].length =
+ peasycap->video_isoc_maxframesize;
+ }
+ }
+ JOM(4, "allocation of %i struct urb done.\n", i);
+ return 0;
+}
+
+static void free_video_urbs(struct easycap *peasycap)
+{
+ struct list_head *plist_head, *plist_next;
+ struct data_urb *pdata_urb;
+ int m;
+
+ if (peasycap->purb_video_head) {
+ m = 0;
+ list_for_each(plist_head, peasycap->purb_video_head) {
+ pdata_urb = list_entry(plist_head,
+ struct data_urb, list_head);
+ if (pdata_urb && pdata_urb->purb) {
+ usb_free_urb(pdata_urb->purb);
+ pdata_urb->purb = NULL;
+ peasycap->allocation_video_urb--;
+ m++;
+ }
+ }
+
+ JOM(4, "%i video urbs freed\n", m);
+ JOM(4, "freeing video data_urb structures.\n");
+ m = 0;
+ list_for_each_safe(plist_head, plist_next,
+ peasycap->purb_video_head) {
+ pdata_urb = list_entry(plist_head,
+ struct data_urb, list_head);
+ if (pdata_urb) {
+ peasycap->allocation_video_struct -=
+ sizeof(struct data_urb);
+ kfree(pdata_urb);
+ m++;
+ }
+ }
+ JOM(4, "%i video data_urb structures freed\n", m);
+ JOM(4, "setting peasycap->purb_video_head=NULL\n");
+ peasycap->purb_video_head = NULL;
+ }
+}
+
+static int alloc_audio_buffers(struct easycap *peasycap)
+{
+ void *pbuf;
+ int k;
+
+ JOM(4, "allocating %i isoc audio buffers of size %i\n",
+ AUDIO_ISOC_BUFFER_MANY,
+ peasycap->audio_isoc_buffer_size);
+ JOM(4, ".... each occupying contiguous memory pages\n");
+
+ for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
+ pbuf = (void *)__get_free_pages(GFP_KERNEL, AUDIO_ISOC_ORDER);
+ if (!pbuf) {
+ SAM("ERROR: Could not allocate isoc audio buffer %i\n",
+ k);
+ return -ENOMEM;
+ }
+ peasycap->allocation_audio_page += BIT(AUDIO_ISOC_ORDER);
+
+ peasycap->audio_isoc_buffer[k].pgo = pbuf;
+ peasycap->audio_isoc_buffer[k].pto =
+ pbuf + peasycap->audio_isoc_buffer_size;
+ peasycap->audio_isoc_buffer[k].kount = k;
+ }
+
+ JOM(4, "allocation of isoc audio buffers done.\n");
+ return 0;
+}
+
+static void free_audio_buffers(struct easycap *peasycap)
+{
+ int k, m;
+
+ JOM(4, "freeing audio isoc buffers.\n");
+ m = 0;
+ for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
+ if (peasycap->audio_isoc_buffer[k].pgo) {
+ free_pages((unsigned long)
+ (peasycap->audio_isoc_buffer[k].pgo),
+ AUDIO_ISOC_ORDER);
+ peasycap->audio_isoc_buffer[k].pgo = NULL;
+ peasycap->allocation_audio_page -=
+ BIT(AUDIO_ISOC_ORDER);
+ m++;
+ }
+ }
+ JOM(4, "easyoss_delete(): isoc audio buffers freed: %i pages\n",
+ m * (0x01 << AUDIO_ISOC_ORDER));
+}
+
+static int create_audio_urbs(struct easycap *peasycap)
+{
+ struct urb *purb;
+ struct data_urb *pdata_urb;
+ int k, j;
+
+ JOM(4, "allocating %i struct urb.\n", AUDIO_ISOC_BUFFER_MANY);
+ JOM(4, "using %i=peasycap->audio_isoc_framesperdesc\n",
+ peasycap->audio_isoc_framesperdesc);
+ JOM(4, "using %i=peasycap->audio_isoc_maxframesize\n",
+ peasycap->audio_isoc_maxframesize);
+ JOM(4, "using %i=peasycap->audio_isoc_buffer_size\n",
+ peasycap->audio_isoc_buffer_size);
+
+ for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
+ purb = usb_alloc_urb(peasycap->audio_isoc_framesperdesc,
+ GFP_KERNEL);
+ if (!purb) {
+ SAM("ERROR: usb_alloc_urb returned NULL for buffer "
+ "%i\n", k);
+ return -ENOMEM;
+ }
+ peasycap->allocation_audio_urb += 1 ;
+ pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
+ if (!pdata_urb) {
+ usb_free_urb(purb);
+ SAM("ERROR: Could not allocate struct data_urb.\n");
+ return -ENOMEM;
+ }
+ peasycap->allocation_audio_struct +=
+ sizeof(struct data_urb);
+
+ pdata_urb->purb = purb;
+ pdata_urb->isbuf = k;
+ pdata_urb->length = 0;
+ list_add_tail(&(pdata_urb->list_head),
+ peasycap->purb_audio_head);
+
+ if (!k) {
+ JOM(4, "initializing audio urbs thus:\n");
+ JOM(4, " purb->interval = 1;\n");
+ JOM(4, " purb->dev = peasycap->pusb_device;\n");
+ JOM(4, " purb->pipe = usb_rcvisocpipe(peasycap->"
+ "pusb_device,%i);\n",
+ peasycap->audio_endpointnumber);
+ JOM(4, " purb->transfer_flags = URB_ISO_ASAP;\n");
+ JOM(4, " purb->transfer_buffer = "
+ "peasycap->audio_isoc_buffer[.].pgo;\n");
+ JOM(4, " purb->transfer_buffer_length = %i;\n",
+ peasycap->audio_isoc_buffer_size);
+ JOM(4, " purb->complete = easycap_alsa_complete;\n");
+ JOM(4, " purb->context = peasycap;\n");
+ JOM(4, " purb->start_frame = 0;\n");
+ JOM(4, " purb->number_of_packets = %i;\n",
+ peasycap->audio_isoc_framesperdesc);
+ JOM(4, " for (j = 0; j < %i; j++)\n",
+ peasycap->audio_isoc_framesperdesc);
+ JOM(4, " {\n");
+ JOM(4, " purb->iso_frame_desc[j].offset = j*%i;\n",
+ peasycap->audio_isoc_maxframesize);
+ JOM(4, " purb->iso_frame_desc[j].length = %i;\n",
+ peasycap->audio_isoc_maxframesize);
+ JOM(4, " }\n");
+ }
+
+ purb->interval = 1;
+ purb->dev = peasycap->pusb_device;
+ purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
+ peasycap->audio_endpointnumber);
+ purb->transfer_flags = URB_ISO_ASAP;
+ purb->transfer_buffer = peasycap->audio_isoc_buffer[k].pgo;
+ purb->transfer_buffer_length =
+ peasycap->audio_isoc_buffer_size;
+ purb->complete = easycap_alsa_complete;
+ purb->context = peasycap;
+ purb->start_frame = 0;
+ purb->number_of_packets = peasycap->audio_isoc_framesperdesc;
+ for (j = 0; j < peasycap->audio_isoc_framesperdesc; j++) {
+ purb->iso_frame_desc[j].offset =
+ j * peasycap->audio_isoc_maxframesize;
+ purb->iso_frame_desc[j].length =
+ peasycap->audio_isoc_maxframesize;
+ }
+ }
+ JOM(4, "allocation of %i struct urb done.\n", k);
+ return 0;
+}
+
+static void free_audio_urbs(struct easycap *peasycap)
+{
+ struct list_head *plist_head, *plist_next;
+ struct data_urb *pdata_urb;
+ int m;
+
+ if (peasycap->purb_audio_head) {
+ JOM(4, "freeing audio urbs\n");
+ m = 0;
+ list_for_each(plist_head, (peasycap->purb_audio_head)) {
+ pdata_urb = list_entry(plist_head,
+ struct data_urb, list_head);
+ if (pdata_urb && pdata_urb->purb) {
+ usb_free_urb(pdata_urb->purb);
+ pdata_urb->purb = NULL;
+ peasycap->allocation_audio_urb--;
+ m++;
+ }
+ }
+ JOM(4, "%i audio urbs freed\n", m);
+ JOM(4, "freeing audio data_urb structures.\n");
+ m = 0;
+ list_for_each_safe(plist_head, plist_next,
+ peasycap->purb_audio_head) {
+ pdata_urb = list_entry(plist_head,
+ struct data_urb, list_head);
+ if (pdata_urb) {
+ peasycap->allocation_audio_struct -=
+ sizeof(struct data_urb);
+ kfree(pdata_urb);
+ m++;
+ }
+ }
+ JOM(4, "%i audio data_urb structures freed\n", m);
+ JOM(4, "setting peasycap->purb_audio_head=NULL\n");
+ peasycap->purb_audio_head = NULL;
+ }
+}
+
+static void config_easycap(struct easycap *peasycap,
+ u8 bInterfaceNumber,
+ u8 bInterfaceClass,
+ u8 bInterfaceSubClass)
+{
+ if ((USB_CLASS_VIDEO == bInterfaceClass) ||
+ (USB_CLASS_VENDOR_SPEC == bInterfaceClass)) {
+ if (-1 == peasycap->video_interface) {
+ peasycap->video_interface = bInterfaceNumber;
+ JOM(4, "setting peasycap->video_interface=%i\n",
+ peasycap->video_interface);
+ } else {
+ if (peasycap->video_interface != bInterfaceNumber) {
+ SAM("ERROR: attempting to reset "
+ "peasycap->video_interface\n");
+ SAM("...... continuing with "
+ "%i=peasycap->video_interface\n",
+ peasycap->video_interface);
+ }
+ }
+ } else if ((USB_CLASS_AUDIO == bInterfaceClass) &&
+ (USB_SUBCLASS_AUDIOSTREAMING == bInterfaceSubClass)) {
+ if (-1 == peasycap->audio_interface) {
+ peasycap->audio_interface = bInterfaceNumber;
+ JOM(4, "setting peasycap->audio_interface=%i\n",
+ peasycap->audio_interface);
+ } else {
+ if (peasycap->audio_interface != bInterfaceNumber) {
+ SAM("ERROR: attempting to reset "
+ "peasycap->audio_interface\n");
+ SAM("...... continuing with "
+ "%i=peasycap->audio_interface\n",
+ peasycap->audio_interface);
+ }
+ }
+ }
+}
+
+/*
+ * This function is called from within easycap_usb_disconnect() and is
+ * protected by semaphores set and cleared by easycap_usb_disconnect().
+ * By this stage the device has already been physically unplugged,
+ * so peasycap->pusb_device is no longer valid.
+ */
+static void easycap_delete(struct kref *pkref)
+{
+ struct easycap *peasycap;
+
+ peasycap = container_of(pkref, struct easycap, kref);
+ if (!peasycap) {
+ SAM("ERROR: peasycap is NULL: cannot perform deletions\n");
+ return;
+ }
+
+ /* Free video urbs */
+ free_video_urbs(peasycap);
+
+ /* Free video isoc buffers */
+ free_isocbuffers(peasycap);
+
+ /* Free video field buffers */
+ free_fieldbuffers(peasycap);
+
+ /* Free video frame buffers */
+ free_framebuffers(peasycap);
+
+ /* Free audio urbs */
+ free_audio_urbs(peasycap);
+
+ /* Free audio isoc buffers */
+ free_audio_buffers(peasycap);
+
+ free_easycap(peasycap);
+
+ JOT(4, "ending.\n");
+}
+
static const struct v4l2_file_operations v4l2_fops = {
.owner = THIS_MODULE,
.open = easycap_open_noinode,
@@ -2850,6 +3450,36 @@ static const struct v4l2_file_operations v4l2_fops = {
.mmap = easycap_mmap,
};
+static int easycap_register_video(struct easycap *peasycap)
+{
+ /*
+ * FIXME: This is believed to be harmless,
+ * but may well be unnecessary or wrong.
+ */
+ peasycap->video_device.v4l2_dev = NULL;
+
+ strcpy(&peasycap->video_device.name[0], "easycapdc60");
+ peasycap->video_device.fops = &v4l2_fops;
+ peasycap->video_device.minor = -1;
+ peasycap->video_device.release = (void *)(&videodev_release);
+
+ video_set_drvdata(&(peasycap->video_device), (void *)peasycap);
+
+ if (0 != (video_register_device(&(peasycap->video_device),
+ VFL_TYPE_GRABBER, -1))) {
+ videodev_release(&(peasycap->video_device));
+ return -ENODEV;
+ }
+
+ peasycap->registered_video++;
+
+ SAM("registered with videodev: %i=minor\n",
+ peasycap->video_device.minor);
+ peasycap->minor = peasycap->video_device.minor;
+
+ return 0;
+}
+
/*
* When the device is plugged, this function is called three times,
* one for each interface.
@@ -2861,24 +3491,15 @@ static int easycap_usb_probe(struct usb_interface *intf,
struct usb_host_interface *alt;
struct usb_endpoint_descriptor *ep;
struct usb_interface_descriptor *interface;
- struct urb *purb;
struct easycap *peasycap;
- int ndong;
- struct data_urb *pdata_urb;
- int i, j, k, m, rc;
+ int i, j, rc;
u8 bInterfaceNumber;
u8 bInterfaceClass;
u8 bInterfaceSubClass;
- void *pbuf;
int okalt[8], isokalt;
int okepn[8];
int okmps[8];
int maxpacketsize;
- u16 mask;
- s32 value;
- struct easycap_format *peasycap_format;
- int fmtidx;
- struct inputset *inputset;
usbdev = interface_to_usbdev(intf);
@@ -2916,76 +3537,16 @@ static int easycap_usb_probe(struct usb_interface *intf,
* interfaces 1 and 2 are probed.
*/
if (0 == bInterfaceNumber) {
- peasycap = kzalloc(sizeof(struct easycap), GFP_KERNEL);
- if (!peasycap) {
- SAY("ERROR: Could not allocate peasycap\n");
- return -ENOMEM;
- }
-
- /* Perform urgent initializations */
- peasycap->minor = -1;
- kref_init(&peasycap->kref);
- JOM(8, "intf[%i]: after kref_init(..._video) "
- "%i=peasycap->kref.refcount.counter\n",
- bInterfaceNumber, peasycap->kref.refcount.counter);
-
- /* module params */
- peasycap->gain = (s8)clamp(easycap_gain, 0, 31);
-
- init_waitqueue_head(&peasycap->wq_video);
- init_waitqueue_head(&peasycap->wq_audio);
- init_waitqueue_head(&peasycap->wq_trigger);
-
- if (mutex_lock_interruptible(&mutex_dongle)) {
- SAY("ERROR: cannot down mutex_dongle\n");
- return -ERESTARTSYS;
- }
-
- for (ndong = 0; ndong < DONGLE_MANY; ndong++) {
- if ((!easycapdc60_dongle[ndong].peasycap) &&
- (!mutex_is_locked(&easycapdc60_dongle
- [ndong].mutex_video)) &&
- (!mutex_is_locked(&easycapdc60_dongle
- [ndong].mutex_audio))) {
- easycapdc60_dongle[ndong].peasycap = peasycap;
- peasycap->isdongle = ndong;
- JOM(8, "intf[%i]: peasycap-->easycap"
- "_dongle[%i].peasycap\n",
- bInterfaceNumber, ndong);
- break;
- }
- }
-
- if (DONGLE_MANY <= ndong) {
- SAM("ERROR: too many dongles\n");
- mutex_unlock(&mutex_dongle);
+ /*
+ * Alloc structure and save it in a free slot in
+ * easycapdc60_dongle array
+ */
+ peasycap = alloc_easycap(bInterfaceNumber);
+ if (!peasycap)
return -ENOMEM;
- }
- mutex_unlock(&mutex_dongle);
-
- peasycap->allocation_video_struct = sizeof(struct easycap);
-
- /* and further initialize the structure */
- peasycap->pusb_device = usbdev;
- peasycap->pusb_interface = intf;
- peasycap->microphone = false;
-
- peasycap->video_interface = -1;
- peasycap->video_altsetting_on = -1;
- peasycap->video_altsetting_off = -1;
- peasycap->video_endpointnumber = -1;
- peasycap->video_isoc_maxframesize = -1;
- peasycap->video_isoc_buffer_size = -1;
-
- peasycap->audio_interface = -1;
- peasycap->audio_altsetting_on = -1;
- peasycap->audio_altsetting_off = -1;
- peasycap->audio_endpointnumber = -1;
- peasycap->audio_isoc_maxframesize = -1;
- peasycap->audio_isoc_buffer_size = -1;
-
- peasycap->frame_buffer_many = FRAME_BUFFER_MANY;
+ /* Perform basic struct initialization */
+ init_easycap(peasycap, usbdev, intf, bInterfaceNumber);
/* Dynamically fill in the available formats */
rc = easycap_video_fillin_formats();
@@ -2996,136 +3557,19 @@ static int easycap_usb_probe(struct usb_interface *intf,
JOM(4, "%i formats available\n", rc);
/* Populate easycap.inputset[] */
- inputset = peasycap->inputset;
- fmtidx = peasycap->ntsc ? NTSC_M : PAL_BGHIN;
- m = 0;
- mask = 0;
- for (i = 0; 0xFFFF != easycap_standard[i].mask; i++) {
- if (fmtidx == easycap_standard[i].v4l2_standard.index) {
- m++;
- for (k = 0; k < INPUT_MANY; k++)
- inputset[k].standard_offset = i;
-
- mask = easycap_standard[i].mask;
- }
- }
- if (1 != m) {
- SAM("ERROR: "
- "inputset->standard_offset unpopulated, %i=m\n", m);
- return -ENOENT;
- }
-
- peasycap_format = &easycap_format[0];
- m = 0;
- for (i = 0; peasycap_format->v4l2_format.fmt.pix.width; i++) {
- struct v4l2_pix_format *pix =
- &peasycap_format->v4l2_format.fmt.pix;
- if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) &&
- pix->field == V4L2_FIELD_NONE &&
- pix->pixelformat == V4L2_PIX_FMT_UYVY &&
- pix->width == 640 && pix->height == 480) {
- m++;
- for (k = 0; k < INPUT_MANY; k++)
- inputset[k].format_offset = i;
- break;
- }
- peasycap_format++;
- }
- if (1 != m) {
- SAM("ERROR: inputset[]->format_offset unpopulated\n");
- return -ENOENT;
- }
-
- m = 0;
- for (i = 0; 0xFFFFFFFF != easycap_control[i].id; i++) {
- value = easycap_control[i].default_value;
- if (V4L2_CID_BRIGHTNESS == easycap_control[i].id) {
- m++;
- for (k = 0; k < INPUT_MANY; k++)
- inputset[k].brightness = value;
- } else if (V4L2_CID_CONTRAST == easycap_control[i].id) {
- m++;
- for (k = 0; k < INPUT_MANY; k++)
- inputset[k].contrast = value;
- } else if (V4L2_CID_SATURATION == easycap_control[i].id) {
- m++;
- for (k = 0; k < INPUT_MANY; k++)
- inputset[k].saturation = value;
- } else if (V4L2_CID_HUE == easycap_control[i].id) {
- m++;
- for (k = 0; k < INPUT_MANY; k++)
- inputset[k].hue = value;
- }
- }
-
- if (4 != m) {
- SAM("ERROR: inputset[]->brightness underpopulated\n");
- return -ENOENT;
- }
- for (k = 0; k < INPUT_MANY; k++)
- inputset[k].input = k;
- JOM(4, "populated inputset[]\n");
+ rc = populate_inputset(peasycap);
+ if (rc < 0)
+ return rc;
JOM(4, "finished initialization\n");
} else {
-
- /*
- * FIXME: Identify the appropriate pointer
- * peasycap for interfaces 1 and 2.
- * The address of peasycap->pusb_device
- * is reluctantly used for this purpose.
- */
- for (ndong = 0; ndong < DONGLE_MANY; ndong++) {
- if (usbdev == easycapdc60_dongle[ndong].peasycap->
- pusb_device) {
- peasycap = easycapdc60_dongle[ndong].peasycap;
- JOT(8, "intf[%i]: dongle[%i].peasycap\n",
- bInterfaceNumber, ndong);
- break;
- }
- }
- if (DONGLE_MANY <= ndong) {
- SAY("ERROR: peasycap is unknown when probing interface %i\n",
- bInterfaceNumber);
+ peasycap = get_easycap(usbdev, bInterfaceNumber);
+ if (!peasycap)
return -ENODEV;
- }
- if (!peasycap) {
- SAY("ERROR: peasycap is NULL when probing interface %i\n",
- bInterfaceNumber);
- return -ENODEV;
- }
}
- if ((USB_CLASS_VIDEO == bInterfaceClass) ||
- (USB_CLASS_VENDOR_SPEC == bInterfaceClass)) {
- if (-1 == peasycap->video_interface) {
- peasycap->video_interface = bInterfaceNumber;
- JOM(4, "setting peasycap->video_interface=%i\n",
- peasycap->video_interface);
- } else {
- if (peasycap->video_interface != bInterfaceNumber) {
- SAM("ERROR: attempting to reset "
- "peasycap->video_interface\n");
- SAM("...... continuing with "
- "%i=peasycap->video_interface\n",
- peasycap->video_interface);
- }
- }
- } else if ((USB_CLASS_AUDIO == bInterfaceClass) &&
- (USB_SUBCLASS_AUDIOSTREAMING == bInterfaceSubClass)) {
- if (-1 == peasycap->audio_interface) {
- peasycap->audio_interface = bInterfaceNumber;
- JOM(4, "setting peasycap->audio_interface=%i\n",
- peasycap->audio_interface);
- } else {
- if (peasycap->audio_interface != bInterfaceNumber) {
- SAM("ERROR: attempting to reset "
- "peasycap->audio_interface\n");
- SAM("...... continuing with "
- "%i=peasycap->audio_interface\n",
- peasycap->audio_interface);
- }
- }
- }
+ config_easycap(peasycap, bInterfaceNumber,
+ bInterfaceClass,
+ bInterfaceSubClass);
/*
* Investigate all altsettings. This is done in detail
@@ -3368,173 +3812,23 @@ static int easycap_usb_probe(struct usb_interface *intf,
*/
INIT_LIST_HEAD(&(peasycap->urb_video_head));
peasycap->purb_video_head = &(peasycap->urb_video_head);
- JOM(4, "allocating %i frame buffers of size %li\n",
- FRAME_BUFFER_MANY, (long int)FRAME_BUFFER_SIZE);
- JOM(4, ".... each scattered over %li pages\n",
- FRAME_BUFFER_SIZE/PAGE_SIZE);
-
- for (k = 0; k < FRAME_BUFFER_MANY; k++) {
- for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++) {
- if (peasycap->frame_buffer[k][m].pgo)
- SAM("attempting to reallocate frame "
- " buffers\n");
- else {
- pbuf = (void *)__get_free_page(GFP_KERNEL);
- if (!pbuf) {
- SAM("ERROR: Could not allocate frame "
- "buffer %i page %i\n", k, m);
- return -ENOMEM;
- }
-
- peasycap->allocation_video_page += 1;
- peasycap->frame_buffer[k][m].pgo = pbuf;
- }
- peasycap->frame_buffer[k][m].pto =
- peasycap->frame_buffer[k][m].pgo;
- }
- }
-
- peasycap->frame_fill = 0;
- peasycap->frame_read = 0;
- JOM(4, "allocation of frame buffers done: %i pages\n", k *
- m);
- JOM(4, "allocating %i field buffers of size %li\n",
- FIELD_BUFFER_MANY, (long int)FIELD_BUFFER_SIZE);
- JOM(4, ".... each scattered over %li pages\n",
- FIELD_BUFFER_SIZE/PAGE_SIZE);
-
- for (k = 0; k < FIELD_BUFFER_MANY; k++) {
- for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++) {
- if (peasycap->field_buffer[k][m].pgo) {
- SAM("ERROR: attempting to reallocate "
- "field buffers\n");
- } else {
- pbuf = (void *) __get_free_page(GFP_KERNEL);
- if (!pbuf) {
- SAM("ERROR: Could not allocate field"
- " buffer %i page %i\n", k, m);
- return -ENOMEM;
- }
-
- peasycap->allocation_video_page += 1;
- peasycap->field_buffer[k][m].pgo = pbuf;
- }
- peasycap->field_buffer[k][m].pto =
- peasycap->field_buffer[k][m].pgo;
- }
- peasycap->field_buffer[k][0].kount = 0x0200;
- }
- peasycap->field_fill = 0;
- peasycap->field_page = 0;
- peasycap->field_read = 0;
- JOM(4, "allocation of field buffers done: %i pages\n", k *
- m);
- JOM(4, "allocating %i isoc video buffers of size %i\n",
- VIDEO_ISOC_BUFFER_MANY,
- peasycap->video_isoc_buffer_size);
- JOM(4, ".... each occupying contiguous memory pages\n");
-
- for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) {
- pbuf = (void *)__get_free_pages(GFP_KERNEL,
- VIDEO_ISOC_ORDER);
- if (!pbuf) {
- SAM("ERROR: Could not allocate isoc video buffer "
- "%i\n", k);
- return -ENOMEM;
- }
- peasycap->allocation_video_page +=
- BIT(VIDEO_ISOC_ORDER);
- peasycap->video_isoc_buffer[k].pgo = pbuf;
- peasycap->video_isoc_buffer[k].pto =
- pbuf + peasycap->video_isoc_buffer_size;
- peasycap->video_isoc_buffer[k].kount = k;
- }
- JOM(4, "allocation of isoc video buffers done: %i pages\n",
- k * (0x01 << VIDEO_ISOC_ORDER));
-
- /* Allocate and initialize multiple struct usb */
- JOM(4, "allocating %i struct urb.\n", VIDEO_ISOC_BUFFER_MANY);
- JOM(4, "using %i=peasycap->video_isoc_framesperdesc\n",
- peasycap->video_isoc_framesperdesc);
- JOM(4, "using %i=peasycap->video_isoc_maxframesize\n",
- peasycap->video_isoc_maxframesize);
- JOM(4, "using %i=peasycap->video_isoc_buffer_sizen",
- peasycap->video_isoc_buffer_size);
-
- for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) {
- purb = usb_alloc_urb(peasycap->video_isoc_framesperdesc,
- GFP_KERNEL);
- if (!purb) {
- SAM("ERROR: usb_alloc_urb returned NULL for buffer "
- "%i\n", k);
- return -ENOMEM;
- }
+ rc = alloc_framebuffers(peasycap);
+ if (rc < 0)
+ return rc;
- peasycap->allocation_video_urb += 1;
- pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
- if (!pdata_urb) {
- SAM("ERROR: Could not allocate struct data_urb.\n");
- return -ENOMEM;
- }
+ rc = alloc_fieldbuffers(peasycap);
+ if (rc < 0)
+ return rc;
- peasycap->allocation_video_struct +=
- sizeof(struct data_urb);
+ rc = alloc_isocbuffers(peasycap);
+ if (rc < 0)
+ return rc;
- pdata_urb->purb = purb;
- pdata_urb->isbuf = k;
- pdata_urb->length = 0;
- list_add_tail(&(pdata_urb->list_head),
- peasycap->purb_video_head);
-
- /* Initialize allocated urbs */
- if (!k) {
- JOM(4, "initializing video urbs thus:\n");
- JOM(4, " purb->interval = 1;\n");
- JOM(4, " purb->dev = peasycap->pusb_device;\n");
- JOM(4, " purb->pipe = usb_rcvisocpipe"
- "(peasycap->pusb_device,%i);\n",
- peasycap->video_endpointnumber);
- JOM(4, " purb->transfer_flags = URB_ISO_ASAP;\n");
- JOM(4, " purb->transfer_buffer = peasycap->"
- "video_isoc_buffer[.].pgo;\n");
- JOM(4, " purb->transfer_buffer_length = %i;\n",
- peasycap->video_isoc_buffer_size);
- JOM(4, " purb->complete = easycap_complete;\n");
- JOM(4, " purb->context = peasycap;\n");
- JOM(4, " purb->start_frame = 0;\n");
- JOM(4, " purb->number_of_packets = %i;\n",
- peasycap->video_isoc_framesperdesc);
- JOM(4, " for (j = 0; j < %i; j++)\n",
- peasycap->video_isoc_framesperdesc);
- JOM(4, " {\n");
- JOM(4, " purb->iso_frame_desc[j].offset = j*%i;\n",
- peasycap->video_isoc_maxframesize);
- JOM(4, " purb->iso_frame_desc[j].length = %i;\n",
- peasycap->video_isoc_maxframesize);
- JOM(4, " }\n");
- }
-
- purb->interval = 1;
- purb->dev = peasycap->pusb_device;
- purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
- peasycap->video_endpointnumber);
- purb->transfer_flags = URB_ISO_ASAP;
- purb->transfer_buffer = peasycap->video_isoc_buffer[k].pgo;
- purb->transfer_buffer_length =
- peasycap->video_isoc_buffer_size;
- purb->complete = easycap_complete;
- purb->context = peasycap;
- purb->start_frame = 0;
- purb->number_of_packets = peasycap->video_isoc_framesperdesc;
- for (j = 0; j < peasycap->video_isoc_framesperdesc; j++) {
- purb->iso_frame_desc[j].offset = j *
- peasycap->video_isoc_maxframesize;
- purb->iso_frame_desc[j].length =
- peasycap->video_isoc_maxframesize;
- }
- }
- JOM(4, "allocation of %i struct urb done.\n", k);
+ /* Allocate and initialize video urbs */
+ rc = create_video_urbs(peasycap);
+ if (rc < 0)
+ return rc;
/* Save pointer peasycap in this interface */
usb_set_intfdata(intf, peasycap);
@@ -3545,9 +3839,6 @@ static int easycap_usb_probe(struct usb_interface *intf,
* because some udev rules triggers easycap_open()
* immediately after registration, causing a clash.
*/
- peasycap->ntsc = easycap_ntsc;
- JOM(8, "defaulting initially to %s\n",
- easycap_ntsc ? "NTSC" : "PAL");
rc = reset(peasycap);
if (rc) {
SAM("ERROR: reset() rc = %i\n", rc);
@@ -3562,32 +3853,12 @@ static int easycap_usb_probe(struct usb_interface *intf,
JOM(4, "registered device instance: %s\n",
peasycap->v4l2_device.name);
- /*
- * FIXME: This is believed to be harmless,
- * but may well be unnecessary or wrong.
- */
- peasycap->video_device.v4l2_dev = NULL;
-
-
- strcpy(&peasycap->video_device.name[0], "easycapdc60");
- peasycap->video_device.fops = &v4l2_fops;
- peasycap->video_device.minor = -1;
- peasycap->video_device.release = (void *)(&videodev_release);
-
- video_set_drvdata(&(peasycap->video_device), (void *)peasycap);
-
- if (0 != (video_register_device(&(peasycap->video_device),
- VFL_TYPE_GRABBER, -1))) {
- err("Not able to register with videodev");
- videodev_release(&(peasycap->video_device));
+ rc = easycap_register_video(peasycap);
+ if (rc < 0) {
+ dev_err(&intf->dev,
+ "Not able to register with videodev\n");
return -ENODEV;
}
-
- peasycap->registered_video++;
- SAM("registered with videodev: %i=minor\n",
- peasycap->video_device.minor);
- peasycap->minor = peasycap->video_device.minor;
-
break;
}
/* 1: Audio control */
@@ -3710,109 +3981,14 @@ static int easycap_usb_probe(struct usb_interface *intf,
INIT_LIST_HEAD(&(peasycap->urb_audio_head));
peasycap->purb_audio_head = &(peasycap->urb_audio_head);
- JOM(4, "allocating %i isoc audio buffers of size %i\n",
- AUDIO_ISOC_BUFFER_MANY,
- peasycap->audio_isoc_buffer_size);
- JOM(4, ".... each occupying contiguous memory pages\n");
-
- for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
- pbuf = (void *)__get_free_pages(GFP_KERNEL,
- AUDIO_ISOC_ORDER);
- if (!pbuf) {
- SAM("ERROR: Could not allocate isoc audio buffer "
- "%i\n", k);
- return -ENOMEM;
- }
- peasycap->allocation_audio_page +=
- BIT(AUDIO_ISOC_ORDER);
-
- peasycap->audio_isoc_buffer[k].pgo = pbuf;
- peasycap->audio_isoc_buffer[k].pto = pbuf +
- peasycap->audio_isoc_buffer_size;
- peasycap->audio_isoc_buffer[k].kount = k;
- }
- JOM(4, "allocation of isoc audio buffers done.\n");
+ alloc_audio_buffers(peasycap);
+ if (rc < 0)
+ return rc;
/* Allocate and initialize urbs */
- JOM(4, "allocating %i struct urb.\n", AUDIO_ISOC_BUFFER_MANY);
- JOM(4, "using %i=peasycap->audio_isoc_framesperdesc\n",
- peasycap->audio_isoc_framesperdesc);
- JOM(4, "using %i=peasycap->audio_isoc_maxframesize\n",
- peasycap->audio_isoc_maxframesize);
- JOM(4, "using %i=peasycap->audio_isoc_buffer_size\n",
- peasycap->audio_isoc_buffer_size);
-
- for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
- purb = usb_alloc_urb(peasycap->audio_isoc_framesperdesc,
- GFP_KERNEL);
- if (!purb) {
- SAM("ERROR: usb_alloc_urb returned NULL for buffer "
- "%i\n", k);
- return -ENOMEM;
- }
- peasycap->allocation_audio_urb += 1 ;
- pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
- if (!pdata_urb) {
- usb_free_urb(purb);
- SAM("ERROR: Could not allocate struct data_urb.\n");
- return -ENOMEM;
- }
- peasycap->allocation_audio_struct +=
- sizeof(struct data_urb);
-
- pdata_urb->purb = purb;
- pdata_urb->isbuf = k;
- pdata_urb->length = 0;
- list_add_tail(&(pdata_urb->list_head),
- peasycap->purb_audio_head);
-
- if (!k) {
- JOM(4, "initializing audio urbs thus:\n");
- JOM(4, " purb->interval = 1;\n");
- JOM(4, " purb->dev = peasycap->pusb_device;\n");
- JOM(4, " purb->pipe = usb_rcvisocpipe(peasycap->"
- "pusb_device,%i);\n",
- peasycap->audio_endpointnumber);
- JOM(4, " purb->transfer_flags = URB_ISO_ASAP;\n");
- JOM(4, " purb->transfer_buffer = "
- "peasycap->audio_isoc_buffer[.].pgo;\n");
- JOM(4, " purb->transfer_buffer_length = %i;\n",
- peasycap->audio_isoc_buffer_size);
- JOM(4, " purb->complete = easycap_alsa_complete;\n");
- JOM(4, " purb->context = peasycap;\n");
- JOM(4, " purb->start_frame = 0;\n");
- JOM(4, " purb->number_of_packets = %i;\n",
- peasycap->audio_isoc_framesperdesc);
- JOM(4, " for (j = 0; j < %i; j++)\n",
- peasycap->audio_isoc_framesperdesc);
- JOM(4, " {\n");
- JOM(4, " purb->iso_frame_desc[j].offset = j*%i;\n",
- peasycap->audio_isoc_maxframesize);
- JOM(4, " purb->iso_frame_desc[j].length = %i;\n",
- peasycap->audio_isoc_maxframesize);
- JOM(4, " }\n");
- }
-
- purb->interval = 1;
- purb->dev = peasycap->pusb_device;
- purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
- peasycap->audio_endpointnumber);
- purb->transfer_flags = URB_ISO_ASAP;
- purb->transfer_buffer = peasycap->audio_isoc_buffer[k].pgo;
- purb->transfer_buffer_length =
- peasycap->audio_isoc_buffer_size;
- purb->complete = easycap_alsa_complete;
- purb->context = peasycap;
- purb->start_frame = 0;
- purb->number_of_packets = peasycap->audio_isoc_framesperdesc;
- for (j = 0; j < peasycap->audio_isoc_framesperdesc; j++) {
- purb->iso_frame_desc[j].offset = j *
- peasycap->audio_isoc_maxframesize;
- purb->iso_frame_desc[j].length =
- peasycap->audio_isoc_maxframesize;
- }
- }
- JOM(4, "allocation of %i struct urb done.\n", k);
+ rc = create_audio_urbs(peasycap);
+ if (rc < 0)
+ return rc;
/* Save pointer peasycap in this interface */
usb_set_intfdata(intf, peasycap);
@@ -3822,7 +3998,8 @@ static int easycap_usb_probe(struct usb_interface *intf,
rc = easycap_alsa_probe(peasycap);
if (rc) {
- err("easycap_alsa_probe() rc = %i\n", rc);
+ dev_err(&intf->dev, "easycap_alsa_probe() rc = %i\n",
+ rc);
return -ENODEV;
}
@@ -3841,15 +4018,13 @@ static int easycap_usb_probe(struct usb_interface *intf,
SAM("ends successfully for interface %i\n", bInterfaceNumber);
return 0;
}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
+
/*
- * WHEN THIS FUNCTION IS CALLED THE EasyCAP HAS ALREADY BEEN PHYSICALLY
- * UNPLUGGED. HENCE peasycap->pusb_device IS NO LONGER VALID.
- *
- * THIS FUNCTION AFFECTS ALSA. BEWARE.
+ * When this function is called the device has already been
+ * physically unplugged.
+ * Hence, peasycap->pusb_device is no longer valid.
+ * This function affects alsa.
*/
-/*---------------------------------------------------------------------------*/
static void easycap_usb_disconnect(struct usb_interface *pusb_interface)
{
struct usb_host_interface *pusb_host_interface;
@@ -3874,6 +4049,7 @@ static void easycap_usb_disconnect(struct usb_interface *pusb_interface)
minor = pusb_interface->minor;
JOT(4, "intf[%i]: minor=%i\n", bInterfaceNumber, minor);
+ /* There is nothing to do for Interface Number 1 */
if (1 == bInterfaceNumber)
return;
@@ -3882,11 +4058,8 @@ static void easycap_usb_disconnect(struct usb_interface *pusb_interface)
SAY("ERROR: peasycap is NULL\n");
return;
}
-/*---------------------------------------------------------------------------*/
-/*
- * IF THE WAIT QUEUES ARE NOT CLEARED A DEADLOCK IS POSSIBLE. BEWARE.
-*/
-/*---------------------------------------------------------------------------*/
+
+ /* If the waitqueues are not cleared a deadlock is possible */
peasycap->video_eof = 1;
peasycap->audio_eof = 1;
wake_up_interruptible(&(peasycap->wq_video));
@@ -3902,15 +4075,14 @@ static void easycap_usb_disconnect(struct usb_interface *pusb_interface)
default:
break;
}
-/*--------------------------------------------------------------------------*/
-/*
- * DEREGISTER
- *
- * THIS PROCEDURE WILL BLOCK UNTIL easycap_poll(), VIDEO IOCTL AND AUDIO
- * IOCTL ARE ALL UNLOCKED. IF THIS IS NOT DONE AN Oops CAN OCCUR WHEN
- * AN EasyCAP IS UNPLUGGED WHILE THE URBS ARE RUNNING. BEWARE.
- */
-/*--------------------------------------------------------------------------*/
+
+ /*
+ * Deregister
+ * This procedure will block until easycap_poll(),
+ * video and audio ioctl are all unlocked.
+ * If this is not done an oops can occur when an easycap
+ * is unplugged while the urbs are running.
+ */
kd = easycap_isdongle(peasycap);
switch (bInterfaceNumber) {
case 0: {
@@ -3927,7 +4099,6 @@ static void easycap_usb_disconnect(struct usb_interface *pusb_interface)
} else {
SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd);
}
-/*---------------------------------------------------------------------------*/
if (!peasycap->v4l2_device.name[0]) {
SAM("ERROR: peasycap->v4l2_device.name is empty\n");
if (0 <= kd && DONGLE_MANY > kd)
@@ -3943,7 +4114,6 @@ static void easycap_usb_disconnect(struct usb_interface *pusb_interface)
JOM(4, "intf[%i]: video_unregister_device() minor=%i\n",
bInterfaceNumber, minor);
peasycap->registered_video--;
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
if (0 <= kd && DONGLE_MANY > kd) {
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
@@ -3979,12 +4149,12 @@ static void easycap_usb_disconnect(struct usb_interface *pusb_interface)
default:
break;
}
-/*---------------------------------------------------------------------------*/
-/*
- * CALL easycap_delete() IF NO REMAINING REFERENCES TO peasycap
- * (ALSO WHEN ALSA HAS BEEN IN USE)
- */
-/*---------------------------------------------------------------------------*/
+
+ /*
+ * If no remaining references to peasycap,
+ * call easycap_delete.
+ * (Also when alsa has been in use)
+ */
if (!peasycap->kref.refcount.counter) {
SAM("ERROR: peasycap->kref.refcount.counter is zero "
"so cannot call kref_put()\n");
@@ -4019,17 +4189,11 @@ static void easycap_usb_disconnect(struct usb_interface *pusb_interface)
mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
JOT(4, "unlocked dongle[%i].mutex_video\n", kd);
}
-/*---------------------------------------------------------------------------*/
JOM(4, "ends\n");
return;
}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- * PARAMETERS APPLICABLE TO ENTIRE DRIVER, I.E. BOTH VIDEO AND AUDIO
- */
-/*---------------------------------------------------------------------------*/
+/* Devices supported by this driver */
static struct usb_device_id easycap_usb_device_id_table[] = {
{USB_DEVICE(USB_EASYCAP_VENDOR_ID, USB_EASYCAP_PRODUCT_ID)},
{ }
@@ -4064,14 +4228,11 @@ static int __init easycap_module_init(void)
return rc;
}
-/*****************************************************************************/
+
static void __exit easycap_module_exit(void)
{
usb_deregister(&easycap_usb_driver);
}
-/*****************************************************************************/
module_init(easycap_module_init);
module_exit(easycap_module_exit);
-
-/*****************************************************************************/
diff --git a/drivers/staging/media/go7007/README b/drivers/staging/media/go7007/README
index 48f447637817..aeba1324a9c5 100644
--- a/drivers/staging/media/go7007/README
+++ b/drivers/staging/media/go7007/README
@@ -6,6 +6,6 @@ Todo:
- testing?
- handle churn in v4l layer.
-Please send patchs to Greg Kroah-Hartman <greg@kroah.com> and Cc: Ross
+Please send patches to Greg Kroah-Hartman <greg@linuxfoundation.org> and Cc: Ross
Cohen <rcohen@snurgle.org> as well.
diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c
index 3ef4cd8b4de3..c184ad30fbd8 100644
--- a/drivers/staging/media/go7007/go7007-v4l2.c
+++ b/drivers/staging/media/go7007/go7007-v4l2.c
@@ -76,7 +76,6 @@ static void abort_queued(struct go7007 *go)
static int go7007_streamoff(struct go7007 *go)
{
- int retval = -EINVAL;
unsigned long flags;
mutex_lock(&go->hw_lock);
@@ -87,7 +86,6 @@ static int go7007_streamoff(struct go7007 *go)
abort_queued(go);
spin_unlock_irqrestore(&go->spinlock, flags);
go7007_reset_encoder(go);
- retval = 0;
}
mutex_unlock(&go->hw_lock);
return 0;
diff --git a/drivers/staging/media/go7007/go7007.txt b/drivers/staging/media/go7007/go7007.txt
index 9db1f3952fd2..fcb3e235abbf 100644
--- a/drivers/staging/media/go7007/go7007.txt
+++ b/drivers/staging/media/go7007/go7007.txt
@@ -87,7 +87,6 @@ kernel as built-in or modules:
CONFIG_SOUND - Sound card support
CONFIG_SND - Advanced Linux Sound Architecture
CONFIG_USB - Support for Host-side USB
- CONFIG_USB_DEVICEFS - USB device filesystem
CONFIG_USB_EHCI_HCD - EHCI HCD (USB 2.0) support
Additionally, to use the example application, the following options need to
diff --git a/drivers/staging/media/go7007/s2250-loader.c b/drivers/staging/media/go7007/s2250-loader.c
index 4e132519e253..f1bd159ac195 100644
--- a/drivers/staging/media/go7007/s2250-loader.c
+++ b/drivers/staging/media/go7007/s2250-loader.c
@@ -160,32 +160,10 @@ static struct usb_driver s2250loader_driver = {
.id_table = s2250loader_ids,
};
-static int __init s2250loader_init(void)
-{
- int r;
- unsigned i = 0;
-
- for (i = 0; i < MAX_DEVICES; i++)
- s2250_dev_table[i] = NULL;
-
- r = usb_register(&s2250loader_driver);
- if (r) {
- printk(KERN_ERR "usb_register failed. Error number %d\n", r);
- return -1;
- }
-
- printk(KERN_INFO "s2250loader_init: driver registered\n");
- return 0;
-}
-module_init(s2250loader_init);
-
-static void __exit s2250loader_cleanup(void)
-{
- printk(KERN_INFO "s2250loader_cleanup\n");
- usb_deregister(&s2250loader_driver);
-}
-module_exit(s2250loader_cleanup);
+module_usb_driver(s2250loader_driver);
MODULE_AUTHOR("");
MODULE_DESCRIPTION("firmware loader for Sensoray 2250/2251");
MODULE_LICENSE("GPL v2");
+MODULE_FIRMWARE(S2250_LOADER_FIRMWARE);
+MODULE_FIRMWARE(S2250_FIRMWARE);
diff --git a/drivers/staging/media/lirc/lirc_imon.c b/drivers/staging/media/lirc/lirc_imon.c
index 5f7f8cd3a661..2944fde89f44 100644
--- a/drivers/staging/media/lirc/lirc_imon.c
+++ b/drivers/staging/media/lirc/lirc_imon.c
@@ -70,10 +70,6 @@ static ssize_t vfd_write(struct file *file, const char __user *buf,
static int ir_open(void *data);
static void ir_close(void *data);
-/* Driver init/exit prototypes */
-static int __init imon_init(void);
-static void __exit imon_exit(void);
-
/*** G L O B A L S ***/
#define IMON_DATA_BUF_SZ 35
@@ -209,8 +205,9 @@ static void deregister_from_lirc(struct imon_context *context)
retval = lirc_unregister_driver(minor);
if (retval)
- err("%s: unable to deregister from lirc(%d)",
- __func__, retval);
+ printk(KERN_ERR KBUILD_MODNAME
+ ": %s: unable to deregister from lirc(%d)",
+ __func__, retval);
else
printk(KERN_INFO MOD_NAME ": Deregistered iMON driver "
"(minor:%d)\n", minor);
@@ -234,16 +231,18 @@ static int display_open(struct inode *inode, struct file *file)
subminor = iminor(inode);
interface = usb_find_interface(&imon_driver, subminor);
if (!interface) {
- err("%s: could not find interface for minor %d",
- __func__, subminor);
+ printk(KERN_ERR KBUILD_MODNAME
+ ": %s: could not find interface for minor %d\n",
+ __func__, subminor);
retval = -ENODEV;
goto exit;
}
context = usb_get_intfdata(interface);
if (!context) {
- err("%s: no context found for minor %d",
- __func__, subminor);
+ dev_err(&interface->dev,
+ "%s: no context found for minor %d\n",
+ __func__, subminor);
retval = -ENODEV;
goto exit;
}
@@ -251,10 +250,12 @@ static int display_open(struct inode *inode, struct file *file)
mutex_lock(&context->ctx_lock);
if (!context->display) {
- err("%s: display not supported by device", __func__);
+ dev_err(&interface->dev,
+ "%s: display not supported by device\n", __func__);
retval = -ENODEV;
} else if (context->display_isopen) {
- err("%s: display port is already open", __func__);
+ dev_err(&interface->dev,
+ "%s: display port is already open\n", __func__);
retval = -EBUSY;
} else {
context->display_isopen = 1;
@@ -281,17 +282,20 @@ static int display_close(struct inode *inode, struct file *file)
context = file->private_data;
if (!context) {
- err("%s: no context for device", __func__);
+ printk(KERN_ERR KBUILD_MODNAME
+ "%s: no context for device\n", __func__);
return -ENODEV;
}
mutex_lock(&context->ctx_lock);
if (!context->display) {
- err("%s: display not supported by device", __func__);
+ dev_err(&context->usbdev->dev,
+ "%s: display not supported by device\n", __func__);
retval = -ENODEV;
} else if (!context->display_isopen) {
- err("%s: display is not open", __func__);
+ dev_err(&context->usbdev->dev,
+ "%s: display is not open\n", __func__);
retval = -EIO;
} else {
context->display_isopen = 0;
@@ -340,19 +344,23 @@ static int send_packet(struct imon_context *context)
retval = usb_submit_urb(context->tx_urb, GFP_KERNEL);
if (retval) {
atomic_set(&(context->tx.busy), 0);
- err("%s: error submitting urb(%d)", __func__, retval);
+ dev_err(&context->usbdev->dev,
+ "%s: error submitting urb(%d)\n", __func__, retval);
} else {
/* Wait for transmission to complete (or abort) */
mutex_unlock(&context->ctx_lock);
retval = wait_for_completion_interruptible(
&context->tx.finished);
if (retval)
- err("%s: task interrupted", __func__);
+ dev_err(&context->usbdev->dev,
+ "%s: task interrupted\n", __func__);
mutex_lock(&context->ctx_lock);
retval = context->tx.status;
if (retval)
- err("%s: packet tx failed (%d)", __func__, retval);
+ dev_err(&context->usbdev->dev,
+ "%s: packet tx failed (%d)\n",
+ __func__, retval);
}
return retval;
@@ -383,20 +391,23 @@ static ssize_t vfd_write(struct file *file, const char __user *buf,
context = file->private_data;
if (!context) {
- err("%s: no context for device", __func__);
+ printk(KERN_ERR KBUILD_MODNAME
+ "%s: no context for device\n", __func__);
return -ENODEV;
}
mutex_lock(&context->ctx_lock);
if (!context->dev_present) {
- err("%s: no iMON device present", __func__);
+ dev_err(&context->usbdev->dev,
+ "%s: no iMON device present\n", __func__);
retval = -ENODEV;
goto exit;
}
if (n_bytes <= 0 || n_bytes > IMON_DATA_BUF_SZ - 3) {
- err("%s: invalid payload size", __func__);
+ dev_err(&context->usbdev->dev,
+ "%s: invalid payload size\n", __func__);
retval = -EINVAL;
goto exit;
}
@@ -425,8 +436,9 @@ static ssize_t vfd_write(struct file *file, const char __user *buf,
retval = send_packet(context);
if (retval) {
- err("%s: send packet failed for packet #%d",
- __func__, seq/2);
+ dev_err(&context->usbdev->dev,
+ "%s: send packet failed for packet #%d\n",
+ __func__, seq/2);
goto exit;
} else {
seq += 2;
@@ -441,7 +453,8 @@ static ssize_t vfd_write(struct file *file, const char __user *buf,
context->usb_tx_buf[7] = (unsigned char) seq;
retval = send_packet(context);
if (retval)
- err("%s: send packet failed for packet #%d",
+ dev_err(&context->usbdev->dev,
+ "%s: send packet failed for packet #%d\n",
__func__, seq/2);
}
@@ -508,7 +521,8 @@ static void ir_close(void *data)
context = (struct imon_context *)data;
if (!context) {
- err("%s: no context for device", __func__);
+ printk(KERN_ERR KBUILD_MODNAME
+ "%s: no context for device\n", __func__);
return;
}
@@ -732,7 +746,7 @@ static int imon_probe(struct usb_interface *interface,
context = kzalloc(sizeof(struct imon_context), GFP_KERNEL);
if (!context) {
- err("%s: kzalloc failed for context", __func__);
+ dev_err(dev, "%s: kzalloc failed for context\n", __func__);
alloc_status = 1;
goto alloc_status_switch;
}
@@ -797,7 +811,7 @@ static int imon_probe(struct usb_interface *interface,
/* Input endpoint is mandatory */
if (!ir_ep_found) {
- err("%s: no valid input (IR) endpoint found.", __func__);
+ dev_err(dev, "%s: no valid input (IR) endpoint found.\n", __func__);
retval = -ENODEV;
alloc_status = 2;
goto alloc_status_switch;
@@ -814,30 +828,30 @@ static int imon_probe(struct usb_interface *interface,
driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
if (!driver) {
- err("%s: kzalloc failed for lirc_driver", __func__);
+ dev_err(dev, "%s: kzalloc failed for lirc_driver\n", __func__);
alloc_status = 2;
goto alloc_status_switch;
}
rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
if (!rbuf) {
- err("%s: kmalloc failed for lirc_buffer", __func__);
+ dev_err(dev, "%s: kmalloc failed for lirc_buffer\n", __func__);
alloc_status = 3;
goto alloc_status_switch;
}
if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) {
- err("%s: lirc_buffer_init failed", __func__);
+ dev_err(dev, "%s: lirc_buffer_init failed\n", __func__);
alloc_status = 4;
goto alloc_status_switch;
}
rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!rx_urb) {
- err("%s: usb_alloc_urb failed for IR urb", __func__);
+ dev_err(dev, "%s: usb_alloc_urb failed for IR urb\n", __func__);
alloc_status = 5;
goto alloc_status_switch;
}
tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!tx_urb) {
- err("%s: usb_alloc_urb failed for display urb",
+ dev_err(dev, "%s: usb_alloc_urb failed for display urb\n",
__func__);
alloc_status = 6;
goto alloc_status_switch;
@@ -865,7 +879,7 @@ static int imon_probe(struct usb_interface *interface,
lirc_minor = lirc_register_driver(driver);
if (lirc_minor < 0) {
- err("%s: lirc_register_driver failed", __func__);
+ dev_err(dev, "%s: lirc_register_driver failed\n", __func__);
alloc_status = 7;
goto unlock;
} else
@@ -900,8 +914,8 @@ static int imon_probe(struct usb_interface *interface,
retval = usb_submit_urb(context->rx_urb, GFP_KERNEL);
if (retval) {
- err("%s: usb_submit_urb failed for intf0 (%d)",
- __func__, retval);
+ dev_err(dev, "%s: usb_submit_urb failed for intf0 (%d)\n",
+ __func__, retval);
mutex_unlock(&context->ctx_lock);
goto exit;
}
diff --git a/drivers/staging/media/lirc/lirc_sasem.c b/drivers/staging/media/lirc/lirc_sasem.c
index 74421043b954..f4e4d9003f38 100644
--- a/drivers/staging/media/lirc/lirc_sasem.c
+++ b/drivers/staging/media/lirc/lirc_sasem.c
@@ -80,10 +80,6 @@ static ssize_t vfd_write(struct file *file, const char *buf,
static int ir_open(void *data);
static void ir_close(void *data);
-/* Driver init/exit prototypes */
-static int __init sasem_init(void);
-static void __exit sasem_exit(void);
-
/*** G L O B A L S ***/
#define SASEM_DATA_BUF_SZ 32
@@ -185,7 +181,7 @@ static void deregister_from_lirc(struct sasem_context *context)
retval = lirc_unregister_driver(minor);
if (retval)
- err("%s: unable to deregister from lirc (%d)",
+ printk(KERN_ERR "%s: unable to deregister from lirc (%d)\n",
__func__, retval);
else
printk(KERN_INFO "Deregistered Sasem driver (minor:%d)\n",
@@ -210,16 +206,18 @@ static int vfd_open(struct inode *inode, struct file *file)
subminor = iminor(inode);
interface = usb_find_interface(&sasem_driver, subminor);
if (!interface) {
- err("%s: could not find interface for minor %d",
- __func__, subminor);
+ printk(KERN_ERR KBUILD_MODNAME
+ ": %s: could not find interface for minor %d\n",
+ __func__, subminor);
retval = -ENODEV;
goto exit;
}
context = usb_get_intfdata(interface);
if (!context) {
- err("%s: no context found for minor %d",
- __func__, subminor);
+ dev_err(&interface->dev,
+ "%s: no context found for minor %d\n",
+ __func__, subminor);
retval = -ENODEV;
goto exit;
}
@@ -227,12 +225,13 @@ static int vfd_open(struct inode *inode, struct file *file)
mutex_lock(&context->ctx_lock);
if (context->vfd_isopen) {
- err("%s: VFD port is already open", __func__);
+ dev_err(&interface->dev,
+ "%s: VFD port is already open", __func__);
retval = -EBUSY;
} else {
context->vfd_isopen = 1;
file->private_data = context;
- printk(KERN_INFO "VFD port opened\n");
+ dev_info(&interface->dev, "VFD port opened\n");
}
mutex_unlock(&context->ctx_lock);
@@ -253,7 +252,8 @@ static long vfd_ioctl(struct file *file, unsigned cmd, unsigned long arg)
context = (struct sasem_context *) file->private_data;
if (!context) {
- err("%s: no context for device", __func__);
+ printk(KERN_ERR KBUILD_MODNAME
+ ": %s: no context for device\n", __func__);
return -ENODEV;
}
@@ -287,14 +287,15 @@ static int vfd_close(struct inode *inode, struct file *file)
context = (struct sasem_context *) file->private_data;
if (!context) {
- err("%s: no context for device", __func__);
+ printk(KERN_ERR KBUILD_MODNAME
+ ": %s: no context for device\n", __func__);
return -ENODEV;
}
mutex_lock(&context->ctx_lock);
if (!context->vfd_isopen) {
- err("%s: VFD is not open", __func__);
+ dev_err(&context->dev->dev, "%s: VFD is not open\n", __func__);
retval = -EIO;
} else {
context->vfd_isopen = 0;
@@ -339,7 +340,8 @@ static int send_packet(struct sasem_context *context)
retval = usb_submit_urb(context->tx_urb, GFP_KERNEL);
if (retval) {
atomic_set(&(context->tx.busy), 0);
- err("%s: error submitting urb (%d)", __func__, retval);
+ dev_err(&context->dev->dev, "%s: error submitting urb (%d)\n",
+ __func__, retval);
} else {
/* Wait for transmission to complete (or abort) */
mutex_unlock(&context->ctx_lock);
@@ -348,7 +350,9 @@ static int send_packet(struct sasem_context *context)
retval = context->tx.status;
if (retval)
- err("%s: packet tx failed (%d)", __func__, retval);
+ dev_err(&context->dev->dev,
+ "%s: packet tx failed (%d)\n",
+ __func__, retval);
}
return retval;
@@ -369,20 +373,23 @@ static ssize_t vfd_write(struct file *file, const char *buf,
context = (struct sasem_context *) file->private_data;
if (!context) {
- err("%s: no context for device", __func__);
+ printk(KERN_ERR KBUILD_MODNAME
+ ": %s: no context for device\n", __func__);
return -ENODEV;
}
mutex_lock(&context->ctx_lock);
if (!context->dev_present) {
- err("%s: no Sasem device present", __func__);
+ printk(KERN_ERR KBUILD_MODNAME
+ ": %s: no Sasem device present\n", __func__);
retval = -ENODEV;
goto exit;
}
if (n_bytes <= 0 || n_bytes > SASEM_DATA_BUF_SZ) {
- err("%s: invalid payload size", __func__);
+ dev_err(&context->dev->dev, "%s: invalid payload size\n",
+ __func__);
retval = -EINVAL;
goto exit;
}
@@ -440,9 +447,9 @@ static ssize_t vfd_write(struct file *file, const char *buf,
}
retval = send_packet(context);
if (retval) {
-
- err("%s: send packet failed for packet #%d",
- __func__, i);
+ dev_err(&context->dev->dev,
+ "%s: send packet failed for packet #%d\n",
+ __func__, i);
goto exit;
}
}
@@ -492,7 +499,8 @@ static int ir_open(void *data)
mutex_lock(&context->ctx_lock);
if (context->ir_isopen) {
- err("%s: IR port is already open", __func__);
+ dev_err(&context->dev->dev, "%s: IR port is already open\n",
+ __func__);
retval = -EBUSY;
goto exit;
}
@@ -506,8 +514,9 @@ static int ir_open(void *data)
retval = usb_submit_urb(context->rx_urb, GFP_KERNEL);
if (retval)
- err("%s: usb_submit_urb failed for ir_open (%d)",
- __func__, retval);
+ dev_err(&context->dev->dev,
+ "%s: usb_submit_urb failed for ir_open (%d)\n",
+ __func__, retval);
else {
context->ir_isopen = 1;
printk(KERN_INFO "IR port opened\n");
@@ -529,7 +538,8 @@ static void ir_close(void *data)
context = (struct sasem_context *)data;
if (!context) {
- err("%s: no context for device", __func__);
+ printk(KERN_ERR KBUILD_MODNAME
+ ": %s: no context for device\n", __func__);
return;
}
@@ -687,7 +697,7 @@ static int sasem_probe(struct usb_interface *interface,
struct sasem_context *context = NULL;
int i;
- printk(KERN_INFO "%s: found Sasem device\n", __func__);
+ dev_info(&interface->dev, "%s: found Sasem device\n", __func__);
dev = usb_get_dev(interface_to_usbdev(interface));
@@ -719,8 +729,8 @@ static int sasem_probe(struct usb_interface *interface,
rx_endpoint = ep;
ir_ep_found = 1;
if (debug)
- printk(KERN_INFO "%s: found IR endpoint\n",
- __func__);
+ dev_info(&interface->dev,
+ "%s: found IR endpoint\n", __func__);
} else if (!vfd_ep_found &&
ep_dir == USB_DIR_OUT &&
@@ -729,22 +739,23 @@ static int sasem_probe(struct usb_interface *interface,
tx_endpoint = ep;
vfd_ep_found = 1;
if (debug)
- printk(KERN_INFO "%s: found VFD endpoint\n",
- __func__);
+ dev_info(&interface->dev,
+ "%s: found VFD endpoint\n", __func__);
}
}
/* Input endpoint is mandatory */
if (!ir_ep_found) {
-
- err("%s: no valid input (IR) endpoint found.", __func__);
+ dev_err(&interface->dev,
+ "%s: no valid input (IR) endpoint found.\n", __func__);
retval = -ENODEV;
goto exit;
}
if (!vfd_ep_found)
- printk(KERN_INFO "%s: no valid output (VFD) endpoint found.\n",
- __func__);
+ dev_info(&interface->dev,
+ "%s: no valid output (VFD) endpoint found.\n",
+ __func__);
/* Allocate memory */
@@ -752,38 +763,44 @@ static int sasem_probe(struct usb_interface *interface,
context = kzalloc(sizeof(struct sasem_context), GFP_KERNEL);
if (!context) {
- err("%s: kzalloc failed for context", __func__);
+ dev_err(&interface->dev,
+ "%s: kzalloc failed for context\n", __func__);
alloc_status = 1;
goto alloc_status_switch;
}
driver = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
if (!driver) {
- err("%s: kzalloc failed for lirc_driver", __func__);
+ dev_err(&interface->dev,
+ "%s: kzalloc failed for lirc_driver\n", __func__);
alloc_status = 2;
goto alloc_status_switch;
}
rbuf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
if (!rbuf) {
- err("%s: kmalloc failed for lirc_buffer", __func__);
+ dev_err(&interface->dev,
+ "%s: kmalloc failed for lirc_buffer\n", __func__);
alloc_status = 3;
goto alloc_status_switch;
}
if (lirc_buffer_init(rbuf, BUF_CHUNK_SIZE, BUF_SIZE)) {
- err("%s: lirc_buffer_init failed", __func__);
+ dev_err(&interface->dev,
+ "%s: lirc_buffer_init failed\n", __func__);
alloc_status = 4;
goto alloc_status_switch;
}
rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!rx_urb) {
- err("%s: usb_alloc_urb failed for IR urb", __func__);
+ dev_err(&interface->dev,
+ "%s: usb_alloc_urb failed for IR urb\n", __func__);
alloc_status = 5;
goto alloc_status_switch;
}
if (vfd_ep_found) {
tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!tx_urb) {
- err("%s: usb_alloc_urb failed for VFD urb",
- __func__);
+ dev_err(&interface->dev,
+ "%s: usb_alloc_urb failed for VFD urb",
+ __func__);
alloc_status = 6;
goto alloc_status_switch;
}
@@ -807,7 +824,8 @@ static int sasem_probe(struct usb_interface *interface,
lirc_minor = lirc_register_driver(driver);
if (lirc_minor < 0) {
- err("%s: lirc_register_driver failed", __func__);
+ dev_err(&interface->dev,
+ "%s: lirc_register_driver failed\n", __func__);
alloc_status = 7;
retval = lirc_minor;
goto unlock;
diff --git a/drivers/staging/media/lirc/lirc_ttusbir.c b/drivers/staging/media/lirc/lirc_ttusbir.c
index 7950887ff113..3bb865c02173 100644
--- a/drivers/staging/media/lirc/lirc_ttusbir.c
+++ b/drivers/staging/media/lirc/lirc_ttusbir.c
@@ -113,8 +113,9 @@ static int set_use_inc(void *data)
for (i = 0; i < num_urbs; i++) {
retval = usb_submit_urb(ttusbir->urb[i], GFP_KERNEL);
if (retval) {
- err("%s: usb_submit_urb failed on urb %d",
- __func__, i);
+ dev_err(&ttusbir->interf->dev,
+ "%s: usb_submit_urb failed on urb %d\n",
+ __func__, i);
return retval;
}
}
@@ -278,7 +279,7 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)
if (ttusbir->alt_setting != -1)
DPRINTK("alt setting: %d\n", ttusbir->alt_setting);
else {
- err("Could not find alternate setting\n");
+ dev_err(&intf->dev, "Could not find alternate setting\n");
kfree(ttusbir);
return -EINVAL;
}
@@ -291,7 +292,7 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)
/* Register as a LIRC driver */
if (lirc_buffer_init(&ttusbir->rbuf, sizeof(int), 256) < 0) {
- err("Could not get memory for LIRC data buffer\n");
+ dev_err(&intf->dev, "Could not get memory for LIRC data buffer\n");
usb_set_intfdata(intf, NULL);
kfree(ttusbir);
return -ENOMEM;
@@ -310,7 +311,7 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)
ttusbir->driver.features = LIRC_CAN_REC_MODE2;
ttusbir->minor = lirc_register_driver(&ttusbir->driver);
if (ttusbir->minor < 0) {
- err("Error registering as LIRC driver\n");
+ dev_err(&intf->dev, "Error registering as LIRC driver\n");
usb_set_intfdata(intf, NULL);
lirc_buffer_free(&ttusbir->rbuf);
kfree(ttusbir);
@@ -321,7 +322,7 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)
for (i = 0; i < num_urbs; i++) {
ttusbir->urb[i] = usb_alloc_urb(8, GFP_KERNEL);
if (!ttusbir->urb[i]) {
- err("Could not allocate memory for the URB\n");
+ dev_err(&intf->dev, "Could not allocate memory for the URB\n");
for (j = i - 1; j >= 0; j--)
kfree(ttusbir->urb[j]);
lirc_buffer_free(&ttusbir->rbuf);
diff --git a/drivers/staging/mei/TODO b/drivers/staging/mei/TODO
deleted file mode 100644
index fc266018355e..000000000000
--- a/drivers/staging/mei/TODO
+++ /dev/null
@@ -1,10 +0,0 @@
-TODO:
- - Cleanup and split the timer function
-Upon Unstaging:
- - move mei.h to include/linux/mei.h
- - Documentation/ioctl/ioctl-number.txt
- - move mei.txt under Documentation/mei/
- - move mei-amt-version.c under Documentation/mei
- - add hostprogs-y for mei-amt-version.c
- - drop mei_version.h
- - Updated MAINTAINERS
diff --git a/drivers/staging/net/Kconfig b/drivers/staging/net/Kconfig
new file mode 100644
index 000000000000..a64e56b1898a
--- /dev/null
+++ b/drivers/staging/net/Kconfig
@@ -0,0 +1,38 @@
+if NETDEVICES
+
+if WAN
+
+config PC300
+ tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)"
+ depends on HDLC && PCI && BROKEN
+ ---help---
+ This driver is broken because of struct tty_driver change.
+
+ Driver for the Cyclades-PC300 synchronous communication boards.
+
+ These boards provide synchronous serial interfaces to your
+ Linux box (interfaces currently available are RS-232/V.35, X.21 and
+ T1/E1). If you wish to support Multilink PPP, please select the
+ option later and read the file README.mlppp provided by PC300
+ package.
+
+ To compile this as a module, choose M here: the module
+ will be called pc300.
+
+ If unsure, say N.
+
+config PC300_MLPPP
+ bool "Cyclades-PC300 MLPPP support"
+ depends on PC300 && PPP_MULTILINK && PPP_SYNC_TTY && HDLC_PPP
+ help
+ Multilink PPP over the PC300 synchronous communication boards.
+
+comment "Cyclades-PC300 MLPPP support is disabled."
+ depends on HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP)
+
+comment "Refer to the file README.mlppp, provided by PC300 package."
+ depends on HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP)
+
+endif # WAN
+
+endif # NETDEVICES
diff --git a/drivers/staging/net/Makefile b/drivers/staging/net/Makefile
new file mode 100644
index 000000000000..0799c43d5114
--- /dev/null
+++ b/drivers/staging/net/Makefile
@@ -0,0 +1,5 @@
+pc300-y := pc300_drv.o
+pc300-$(CONFIG_PC300_MLPPP) += pc300_tty.o
+pc300-objs := $(pc300-y)
+
+obj-$(CONFIG_PC300) += pc300.o
diff --git a/drivers/staging/net/TODO b/drivers/staging/net/TODO
new file mode 100644
index 000000000000..e3446f2ad7c7
--- /dev/null
+++ b/drivers/staging/net/TODO
@@ -0,0 +1,5 @@
+PC300
+The driver is very broken and cannot work with the current TTY layer. It is
+inevitable to convert it to the new TTY API.
+
+If no one steps in to adopt the driver, it will be removed in the 3.7 release.
diff --git a/drivers/net/wan/pc300-falc-lh.h b/drivers/staging/net/pc300-falc-lh.h
index 01ed23ca76c7..01ed23ca76c7 100644
--- a/drivers/net/wan/pc300-falc-lh.h
+++ b/drivers/staging/net/pc300-falc-lh.h
diff --git a/drivers/net/wan/pc300.h b/drivers/staging/net/pc300.h
index 2e4f84f6cad4..2e4f84f6cad4 100644
--- a/drivers/net/wan/pc300.h
+++ b/drivers/staging/net/pc300.h
diff --git a/drivers/net/wan/pc300_drv.c b/drivers/staging/net/pc300_drv.c
index cb0f8d932b0c..cb0f8d932b0c 100644
--- a/drivers/net/wan/pc300_drv.c
+++ b/drivers/staging/net/pc300_drv.c
diff --git a/drivers/net/wan/pc300_tty.c b/drivers/staging/net/pc300_tty.c
index 4709f4228561..4709f4228561 100644
--- a/drivers/net/wan/pc300_tty.c
+++ b/drivers/staging/net/pc300_tty.c
diff --git a/drivers/staging/nvec/nvec.h b/drivers/staging/nvec/nvec.h
index a4c17b0e10cf..ba6ed8f4e8a3 100644
--- a/drivers/staging/nvec/nvec.h
+++ b/drivers/staging/nvec/nvec.h
@@ -42,7 +42,7 @@
* enum nvec_event_size - The size of an event message
* @NVEC_2BYTES: The message has one command byte and one data byte
* @NVEC_3BYTES: The message has one command byte and two data bytes
- * @NVEC_VAR_SIZE: The message has one command byte, one count byte, and as
+ * @NVEC_VAR_SIZE: The message has one command byte, one count byte, and has
* up to as many bytes as the number in the count byte. The
* maximum is 32
*
diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c
index d91751f9ffe8..34afc16bc493 100644
--- a/drivers/staging/octeon/ethernet-rx.c
+++ b/drivers/staging/octeon/ethernet-rx.c
@@ -163,7 +163,7 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work)
/*
* We received a packet with either an alignment error
* or a FCS error. This may be signalling that we are
- * running 10Mbps with GMXX_RXX_FRM_CTL[PRE_CHK}
+ * running 10Mbps with GMXX_RXX_FRM_CTL[PRE_CHK]
* off. If this is the case we need to parse the
* packet to determine if we can remove a non spec
* preamble and generate a correct packet.
diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c
index 5877b2c64e2a..5631dd9f8201 100644
--- a/drivers/staging/octeon/ethernet-tx.c
+++ b/drivers/staging/octeon/ethernet-tx.c
@@ -62,7 +62,7 @@
* You can define GET_SKBUFF_QOS() to override how the skbuff output
* function determines which output queue is used. The default
* implementation always uses the base queue for the port. If, for
- * example, you wanted to use the skb->priority fieid, define
+ * example, you wanted to use the skb->priority field, define
* GET_SKBUFF_QOS as: #define GET_SKBUFF_QOS(skb) ((skb)->priority)
*/
#ifndef GET_SKBUFF_QOS
@@ -165,8 +165,8 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
#endif
/*
- * Prefetch the private data structure. It is larger that one
- * cache line.
+ * Prefetch the private data structure. It is larger than the
+ * one cache line.
*/
prefetch(priv);
@@ -291,8 +291,8 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
* See if we can put this skb in the FPA pool. Any strange
* behavior from the Linux networking stack will most likely
* be caused by a bug in the following code. If some field is
- * in use by the network stack and get carried over when a
- * buffer is reused, bad thing may happen. If in doubt and
+ * in use by the network stack and gets carried over when a
+ * buffer is reused, bad things may happen. If in doubt and
* you dont need the absolute best performance, disable the
* define REUSE_SKBUFFS_WITHOUT_FREE. The reuse of buffers has
* shown a 25% increase in performance under some loads.
diff --git a/drivers/staging/octeon/ethernet-util.h b/drivers/staging/octeon/ethernet-util.h
index 144fb99bf50c..2da5ce17ead0 100644
--- a/drivers/staging/octeon/ethernet-util.h
+++ b/drivers/staging/octeon/ethernet-util.h
@@ -38,7 +38,7 @@ static inline void *cvm_oct_get_buffer_ptr(union cvmx_buf_ptr packet_ptr)
}
/**
- * INTERFACE - convert IPD port to locgical interface
+ * INTERFACE - convert IPD port to logical interface
* @ipd_port: Port to check
*
* Returns Logical interface
diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c
index 60cba8194de3..18f7a790f73d 100644
--- a/drivers/staging/octeon/ethernet.c
+++ b/drivers/staging/octeon/ethernet.c
@@ -357,7 +357,7 @@ static void cvm_oct_common_set_multicast_list(struct net_device *dev)
/* Force accept multicast packets */
control.s.mcst = 2;
else
- /* Force reject multicat packets */
+ /* Force reject multicast packets */
control.s.mcst = 1;
if (dev->flags & IFF_PROMISC)
diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c
index 3d9199320d86..992275c0d87c 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon.c
+++ b/drivers/staging/olpc_dcon/olpc_dcon.c
@@ -71,8 +71,8 @@ static int dcon_hw_init(struct dcon_priv *dcon, int is_init)
ver = dcon_read(dcon, DCON_REG_ID);
if ((ver >> 8) != 0xDC) {
- printk(KERN_ERR "olpc-dcon: DCON ID not 0xDCxx: 0x%04x "
- "instead.\n", ver);
+ printk(KERN_ERR "olpc-dcon: DCON ID not 0xDCxx: 0x%04x instead.\n",
+ ver);
rc = -ENXIO;
goto err;
}
@@ -134,10 +134,10 @@ static int dcon_bus_stabilize(struct dcon_priv *dcon, int is_powered_down)
power_up:
if (is_powered_down) {
x = 1;
- x = olpc_ec_cmd(0x26, (unsigned char *) &x, 1, NULL, 0);
+ x = olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0);
if (x) {
- printk(KERN_WARNING "olpc-dcon: unable to force dcon "
- "to power up: %d!\n", x);
+ printk(KERN_WARNING "olpc-dcon: unable to force dcon to power up: %d!\n",
+ x);
return x;
}
msleep(10); /* we'll be conservative */
@@ -150,11 +150,10 @@ power_up:
x = dcon_read(dcon, DCON_REG_ID);
}
if (x < 0) {
- printk(KERN_ERR "olpc-dcon: unable to stabilize dcon's "
- "smbus, reasserting power and praying.\n");
+ printk(KERN_ERR "olpc-dcon: unable to stabilize dcon's smbus, reasserting power and praying.\n");
BUG_ON(olpc_board_at_least(olpc_board(0xc2)));
x = 0;
- olpc_ec_cmd(0x26, (unsigned char *) &x, 1, NULL, 0);
+ olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0);
msleep(100);
is_powered_down = 1;
goto power_up; /* argh, stupid hardware.. */
@@ -220,10 +219,10 @@ static void dcon_sleep(struct dcon_priv *dcon, bool sleep)
if (sleep) {
x = 0;
- x = olpc_ec_cmd(0x26, (unsigned char *) &x, 1, NULL, 0);
+ x = olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0);
if (x)
- printk(KERN_WARNING "olpc-dcon: unable to force dcon "
- "to power down: %d!\n", x);
+ printk(KERN_WARNING "olpc-dcon: unable to force dcon to power down: %d!\n",
+ x);
else
dcon->asleep = sleep;
} else {
@@ -232,8 +231,8 @@ static void dcon_sleep(struct dcon_priv *dcon, bool sleep)
dcon->disp_mode |= MODE_BL_ENABLE;
x = dcon_bus_stabilize(dcon, 1);
if (x)
- printk(KERN_WARNING "olpc-dcon: unable to reinit dcon"
- " hardware: %d!\n", x);
+ printk(KERN_WARNING "olpc-dcon: unable to reinit dcon hardware: %d!\n",
+ x);
else
dcon->asleep = sleep;
@@ -304,7 +303,7 @@ static void dcon_source_switch(struct work_struct *work)
switch (source) {
case DCON_SOURCE_CPU:
- printk("dcon_source_switch to CPU\n");
+ printk(KERN_INFO "dcon_source_switch to CPU\n");
/* Enable the scanline interrupt bit */
if (dcon_write(dcon, DCON_REG_MODE,
dcon->disp_mode | MODE_SCAN_INT))
@@ -599,7 +598,7 @@ static int dcon_fb_notifier(struct notifier_block *self,
struct fb_event *evdata = data;
struct dcon_priv *dcon = container_of(self, struct dcon_priv,
fbevent_nb);
- int *blank = (int *) evdata->data;
+ int *blank = (int *)evdata->data;
if (((event != FB_EVENT_BLANK) && (event != FB_EVENT_CONBLANK)) ||
dcon->ignore_fb_events)
return 0;
diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
index cb6ce0cf92a0..c87fdfac4855 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
+++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
@@ -116,7 +116,7 @@ static int dcon_init_xo_1(struct dcon_priv *dcon)
cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_NEGATIVE_EDGE_STS);
cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_NEGATIVE_EDGE_STS);
- /* FIXME: Clear the posiitive status as well, just to be sure */
+ /* FIXME: Clear the positive status as well, just to be sure */
cs5535_gpio_set(OLPC_GPIO_DCON_IRQ, GPIO_POSITIVE_EDGE_STS);
cs5535_gpio_set(OLPC_GPIO_DCON_BLANK, GPIO_POSITIVE_EDGE_STS);
diff --git a/drivers/staging/omapdrm/Makefile b/drivers/staging/omapdrm/Makefile
index d9cdc120d122..1ca0e0016de4 100644
--- a/drivers/staging/omapdrm/Makefile
+++ b/drivers/staging/omapdrm/Makefile
@@ -13,6 +13,7 @@ omapdrm-y := omap_drv.o \
omap_fb.o \
omap_fbdev.o \
omap_gem.o \
+ omap_gem_dmabuf.o \
omap_dmm_tiler.o \
tcm-sita.o
diff --git a/drivers/staging/omapdrm/omap_crtc.c b/drivers/staging/omapdrm/omap_crtc.c
index 490a7f15604b..8b864afb40b6 100644
--- a/drivers/staging/omapdrm/omap_crtc.c
+++ b/drivers/staging/omapdrm/omap_crtc.c
@@ -36,12 +36,6 @@ struct omap_crtc {
struct drm_framebuffer *old_fb;
};
-static void omap_crtc_gamma_set(struct drm_crtc *crtc,
- u16 *red, u16 *green, u16 *blue, uint32_t start, uint32_t size)
-{
- /* not supported.. at least not yet */
-}
-
static void omap_crtc_destroy(struct drm_crtc *crtc)
{
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
@@ -198,7 +192,6 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
}
static const struct drm_crtc_funcs omap_crtc_funcs = {
- .gamma_set = omap_crtc_gamma_set,
.set_config = drm_crtc_helper_set_config,
.destroy = omap_crtc_destroy,
.page_flip = omap_crtc_page_flip_locked,
diff --git a/drivers/staging/omapdrm/omap_dmm_tiler.c b/drivers/staging/omapdrm/omap_dmm_tiler.c
index 1ecb6a73d790..9d83060e753a 100644
--- a/drivers/staging/omapdrm/omap_dmm_tiler.c
+++ b/drivers/staging/omapdrm/omap_dmm_tiler.c
@@ -347,7 +347,7 @@ struct tiler_block *tiler_reserve_2d(enum tiler_fmt fmt, uint16_t w,
ret = tcm_reserve_2d(containers[fmt], w, h, align, &block->area);
if (ret) {
kfree(block);
- return 0;
+ return ERR_PTR(-ENOMEM);
}
/* add to allocation list */
@@ -371,7 +371,7 @@ struct tiler_block *tiler_reserve_1d(size_t size)
if (tcm_reserve_1d(containers[TILFMT_PAGE], num_pages,
&block->area)) {
kfree(block);
- return 0;
+ return ERR_PTR(-ENOMEM);
}
spin_lock(&omap_dmm->list_lock);
diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c
index 620b8d54223d..4beab9447ceb 100644
--- a/drivers/staging/omapdrm/omap_drv.c
+++ b/drivers/staging/omapdrm/omap_drv.c
@@ -58,7 +58,7 @@ static void omap_fb_output_poll_changed(struct drm_device *dev)
}
}
-static struct drm_mode_config_funcs omap_mode_config_funcs = {
+static const struct drm_mode_config_funcs omap_mode_config_funcs = {
.fb_create = omap_framebuffer_create,
.output_poll_changed = omap_fb_output_poll_changed,
};
@@ -726,7 +726,7 @@ static void dev_irq_uninstall(struct drm_device *dev)
DBG("irq_uninstall: dev=%p", dev);
}
-static struct vm_operations_struct omap_gem_vm_ops = {
+static const struct vm_operations_struct omap_gem_vm_ops = {
.fault = omap_gem_fault,
.open = drm_gem_vm_open,
.close = drm_gem_vm_close,
@@ -746,7 +746,7 @@ static const struct file_operations omapdriver_fops = {
static struct drm_driver omap_drm_driver = {
.driver_features =
- DRIVER_HAVE_IRQ | DRIVER_MODESET | DRIVER_GEM,
+ DRIVER_HAVE_IRQ | DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
.load = dev_load,
.unload = dev_unload,
.open = dev_open,
@@ -766,6 +766,10 @@ static struct drm_driver omap_drm_driver = {
.debugfs_init = omap_debugfs_init,
.debugfs_cleanup = omap_debugfs_cleanup,
#endif
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+ .gem_prime_export = omap_gem_prime_export,
+ .gem_prime_import = omap_gem_prime_import,
.gem_init_object = omap_gem_init_object,
.gem_free_object = omap_gem_free_object,
.gem_vm_ops = &omap_gem_vm_ops,
diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h
index b7e0f0773003..f238d574da0c 100644
--- a/drivers/staging/omapdrm/omap_drv.h
+++ b/drivers/staging/omapdrm/omap_drv.h
@@ -138,6 +138,8 @@ int omap_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev,
int omap_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
struct drm_mode_create_dumb *args);
int omap_gem_mmap(struct file *filp, struct vm_area_struct *vma);
+int omap_gem_mmap_obj(struct drm_gem_object *obj,
+ struct vm_area_struct *vma);
int omap_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
int omap_gem_op_start(struct drm_gem_object *obj, enum omap_gem_op op);
int omap_gem_op_finish(struct drm_gem_object *obj, enum omap_gem_op op);
@@ -145,12 +147,24 @@ int omap_gem_op_sync(struct drm_gem_object *obj, enum omap_gem_op op);
int omap_gem_op_async(struct drm_gem_object *obj, enum omap_gem_op op,
void (*fxn)(void *arg), void *arg);
int omap_gem_roll(struct drm_gem_object *obj, uint32_t roll);
+void omap_gem_cpu_sync(struct drm_gem_object *obj, int pgoff);
+void omap_gem_dma_sync(struct drm_gem_object *obj,
+ enum dma_data_direction dir);
int omap_gem_get_paddr(struct drm_gem_object *obj,
dma_addr_t *paddr, bool remap);
int omap_gem_put_paddr(struct drm_gem_object *obj);
+int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages,
+ bool remap);
+int omap_gem_put_pages(struct drm_gem_object *obj);
+uint32_t omap_gem_flags(struct drm_gem_object *obj);
uint64_t omap_gem_mmap_offset(struct drm_gem_object *obj);
size_t omap_gem_mmap_size(struct drm_gem_object *obj);
+struct dma_buf * omap_gem_prime_export(struct drm_device *dev,
+ struct drm_gem_object *obj, int flags);
+struct drm_gem_object * omap_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *buffer);
+
static inline int align_pitch(int pitch, int width, int bpp)
{
int bytespp = (bpp + 7) / 8;
diff --git a/drivers/staging/omapdrm/omap_fb.c b/drivers/staging/omapdrm/omap_fb.c
index 04b235b6724a..74260f043ab1 100644
--- a/drivers/staging/omapdrm/omap_fb.c
+++ b/drivers/staging/omapdrm/omap_fb.c
@@ -167,7 +167,7 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, int x, int y,
}
/* Call for unpin 'a' (if not NULL), and pin 'b' (if not NULL). Although
- * buffers to unpin are just just pushed to the unpin fifo so that the
+ * buffers to unpin are just pushed to the unpin fifo so that the
* caller can defer unpin until vblank.
*
* Note if this fails (ie. something went very wrong!), all buffers are
@@ -197,8 +197,11 @@ int omap_framebuffer_replace(struct drm_framebuffer *a,
pa->paddr = 0;
}
- if (pb && !ret)
+ if (pb && !ret) {
ret = omap_gem_get_paddr(pb->bo, &pb->paddr, true);
+ if (!ret)
+ omap_gem_dma_sync(pb->bo, DMA_TO_DEVICE);
+ }
}
if (ret) {
diff --git a/drivers/staging/omapdrm/omap_gem.c b/drivers/staging/omapdrm/omap_gem.c
index 921f058cc6a4..3a0d035a9e03 100644
--- a/drivers/staging/omapdrm/omap_gem.c
+++ b/drivers/staging/omapdrm/omap_gem.c
@@ -207,13 +207,27 @@ static inline bool is_shmem(struct drm_gem_object *obj)
return obj->filp != NULL;
}
+/**
+ * shmem buffers that are mapped cached can simulate coherency via using
+ * page faulting to keep track of dirty pages
+ */
+static inline bool is_cached_coherent(struct drm_gem_object *obj)
+{
+ struct omap_gem_object *omap_obj = to_omap_bo(obj);
+ return is_shmem(obj) &&
+ ((omap_obj->flags & OMAP_BO_CACHE_MASK) == OMAP_BO_CACHED);
+}
+
static DEFINE_SPINLOCK(sync_lock);
/** ensure backing pages are allocated */
static int omap_gem_attach_pages(struct drm_gem_object *obj)
{
+ struct drm_device *dev = obj->dev;
struct omap_gem_object *omap_obj = to_omap_bo(obj);
struct page **pages;
+ int i, npages = obj->size >> PAGE_SHIFT;
+ dma_addr_t *addrs;
WARN_ON(omap_obj->pages);
@@ -231,16 +245,18 @@ static int omap_gem_attach_pages(struct drm_gem_object *obj)
* DSS, GPU, etc. are not cache coherent:
*/
if (omap_obj->flags & (OMAP_BO_WC|OMAP_BO_UNCACHED)) {
- int i, npages = obj->size >> PAGE_SHIFT;
- dma_addr_t *addrs = kmalloc(npages * sizeof(addrs), GFP_KERNEL);
+ addrs = kmalloc(npages * sizeof(addrs), GFP_KERNEL);
for (i = 0; i < npages; i++) {
- addrs[i] = dma_map_page(obj->dev->dev, pages[i],
+ addrs[i] = dma_map_page(dev->dev, pages[i],
0, PAGE_SIZE, DMA_BIDIRECTIONAL);
}
- omap_obj->addrs = addrs;
+ } else {
+ addrs = kzalloc(npages * sizeof(addrs), GFP_KERNEL);
}
+ omap_obj->addrs = addrs;
omap_obj->pages = pages;
+
return 0;
}
@@ -258,14 +274,21 @@ static void omap_gem_detach_pages(struct drm_gem_object *obj)
dma_unmap_page(obj->dev->dev, omap_obj->addrs[i],
PAGE_SIZE, DMA_BIDIRECTIONAL);
}
- kfree(omap_obj->addrs);
- omap_obj->addrs = NULL;
}
+ kfree(omap_obj->addrs);
+ omap_obj->addrs = NULL;
+
_drm_gem_put_pages(obj, omap_obj->pages, true, false);
omap_obj->pages = NULL;
}
+/* get buffer flags */
+uint32_t omap_gem_flags(struct drm_gem_object *obj)
+{
+ return to_omap_bo(obj)->flags;
+}
+
/** get mmap offset */
static uint64_t mmap_offset(struct drm_gem_object *obj)
{
@@ -330,6 +353,7 @@ static int fault_1d(struct drm_gem_object *obj,
vma->vm_start) >> PAGE_SHIFT;
if (omap_obj->pages) {
+ omap_gem_cpu_sync(obj, pgoff);
pfn = page_to_pfn(omap_obj->pages[pgoff]);
} else {
BUG_ON(!(omap_obj->flags & OMAP_BO_DMA));
@@ -504,7 +528,6 @@ fail:
/** We override mainly to fix up some of the vm mapping flags.. */
int omap_gem_mmap(struct file *filp, struct vm_area_struct *vma)
{
- struct omap_gem_object *omap_obj;
int ret;
ret = drm_gem_mmap(filp, vma);
@@ -513,8 +536,13 @@ int omap_gem_mmap(struct file *filp, struct vm_area_struct *vma)
return ret;
}
- /* after drm_gem_mmap(), it is safe to access the obj */
- omap_obj = to_omap_bo(vma->vm_private_data);
+ return omap_gem_mmap_obj(vma->vm_private_data, vma);
+}
+
+int omap_gem_mmap_obj(struct drm_gem_object *obj,
+ struct vm_area_struct *vma)
+{
+ struct omap_gem_object *omap_obj = to_omap_bo(obj);
vma->vm_flags &= ~VM_PFNMAP;
vma->vm_flags |= VM_MIXEDMAP;
@@ -524,12 +552,31 @@ int omap_gem_mmap(struct file *filp, struct vm_area_struct *vma)
} else if (omap_obj->flags & OMAP_BO_UNCACHED) {
vma->vm_page_prot = pgprot_noncached(vm_get_page_prot(vma->vm_flags));
} else {
+ /*
+ * We do have some private objects, at least for scanout buffers
+ * on hardware without DMM/TILER. But these are allocated write-
+ * combine
+ */
+ if (WARN_ON(!obj->filp))
+ return -EINVAL;
+
+ /*
+ * Shunt off cached objs to shmem file so they have their own
+ * address_space (so unmap_mapping_range does what we want,
+ * in particular in the case of mmap'd dmabufs)
+ */
+ fput(vma->vm_file);
+ get_file(obj->filp);
+ vma->vm_pgoff = 0;
+ vma->vm_file = obj->filp;
+
vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
}
- return ret;
+ return 0;
}
+
/**
* omap_gem_dumb_create - create a dumb buffer
* @drm_file: our client file
@@ -639,6 +686,48 @@ fail:
return ret;
}
+/* Sync the buffer for CPU access.. note pages should already be
+ * attached, ie. omap_gem_get_pages()
+ */
+void omap_gem_cpu_sync(struct drm_gem_object *obj, int pgoff)
+{
+ struct drm_device *dev = obj->dev;
+ struct omap_gem_object *omap_obj = to_omap_bo(obj);
+
+ if (is_cached_coherent(obj) && omap_obj->addrs[pgoff]) {
+ dma_unmap_page(dev->dev, omap_obj->addrs[pgoff],
+ PAGE_SIZE, DMA_BIDIRECTIONAL);
+ omap_obj->addrs[pgoff] = 0;
+ }
+}
+
+/* sync the buffer for DMA access */
+void omap_gem_dma_sync(struct drm_gem_object *obj,
+ enum dma_data_direction dir)
+{
+ struct drm_device *dev = obj->dev;
+ struct omap_gem_object *omap_obj = to_omap_bo(obj);
+
+ if (is_cached_coherent(obj)) {
+ int i, npages = obj->size >> PAGE_SHIFT;
+ struct page **pages = omap_obj->pages;
+ bool dirty = false;
+
+ for (i = 0; i < npages; i++) {
+ if (!omap_obj->addrs[i]) {
+ omap_obj->addrs[i] = dma_map_page(dev->dev, pages[i], 0,
+ PAGE_SIZE, DMA_BIDIRECTIONAL);
+ dirty = true;
+ }
+ }
+
+ if (dirty) {
+ unmap_mapping_range(obj->filp->f_mapping, 0,
+ omap_gem_mmap_size(obj), 1);
+ }
+ }
+}
+
/* Get physical address for DMA.. if 'remap' is true, and the buffer is not
* already contiguous, remap it to pin in physically contiguous memory.. (ie.
* map in TILER)
@@ -703,6 +792,7 @@ int omap_gem_get_paddr(struct drm_gem_object *obj,
*paddr = omap_obj->paddr;
} else {
ret = -EINVAL;
+ goto fail;
}
fail:
@@ -764,9 +854,27 @@ static int get_pages(struct drm_gem_object *obj, struct page ***pages)
return 0;
}
-int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages)
+/* if !remap, and we don't have pages backing, then fail, rather than
+ * increasing the pin count (which we don't really do yet anyways,
+ * because we don't support swapping pages back out). And 'remap'
+ * might not be quite the right name, but I wanted to keep it working
+ * similarly to omap_gem_get_paddr(). Note though that mutex is not
+ * aquired if !remap (because this can be called in atomic ctxt),
+ * but probably omap_gem_get_paddr() should be changed to work in the
+ * same way. If !remap, a matching omap_gem_put_pages() call is not
+ * required (and should not be made).
+ */
+int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages,
+ bool remap)
{
int ret;
+ if (!remap) {
+ struct omap_gem_object *omap_obj = to_omap_bo(obj);
+ if (!omap_obj->pages)
+ return -ENOMEM;
+ *pages = omap_obj->pages;
+ return 0;
+ }
mutex_lock(&obj->dev->struct_mutex);
ret = get_pages(obj, pages);
mutex_unlock(&obj->dev->struct_mutex);
diff --git a/drivers/staging/omapdrm/omap_gem_dmabuf.c b/drivers/staging/omapdrm/omap_gem_dmabuf.c
new file mode 100644
index 000000000000..42728e0cc194
--- /dev/null
+++ b/drivers/staging/omapdrm/omap_gem_dmabuf.c
@@ -0,0 +1,220 @@
+/*
+ * drivers/staging/omapdrm/omap_gem_dmabuf.c
+ *
+ * Copyright (C) 2011 Texas Instruments
+ * Author: Rob Clark <rob.clark@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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 "omap_drv.h"
+
+#include <linux/dma-buf.h>
+
+static struct sg_table *omap_gem_map_dma_buf(
+ struct dma_buf_attachment *attachment,
+ enum dma_data_direction dir)
+{
+ struct drm_gem_object *obj = attachment->dmabuf->priv;
+ struct sg_table *sg;
+ dma_addr_t paddr;
+ int ret;
+
+ sg = kzalloc(sizeof(*sg), GFP_KERNEL);
+ if (!sg)
+ return ERR_PTR(-ENOMEM);
+
+ /* camera, etc, need physically contiguous.. but we need a
+ * better way to know this..
+ */
+ ret = omap_gem_get_paddr(obj, &paddr, true);
+ if (ret)
+ goto out;
+
+ ret = sg_alloc_table(sg, 1, GFP_KERNEL);
+ if (ret)
+ goto out;
+
+ sg_init_table(sg->sgl, 1);
+ sg_dma_len(sg->sgl) = obj->size;
+ sg_set_page(sg->sgl, pfn_to_page(PFN_DOWN(paddr)), obj->size, 0);
+ sg_dma_address(sg->sgl) = paddr;
+
+ /* this should be after _get_paddr() to ensure we have pages attached */
+ omap_gem_dma_sync(obj, dir);
+
+out:
+ if (ret)
+ return ERR_PTR(ret);
+ return sg;
+}
+
+static void omap_gem_unmap_dma_buf(struct dma_buf_attachment *attachment,
+ struct sg_table *sg, enum dma_data_direction dir)
+{
+ struct drm_gem_object *obj = attachment->dmabuf->priv;
+ omap_gem_put_paddr(obj);
+ sg_free_table(sg);
+ kfree(sg);
+}
+
+static void omap_gem_dmabuf_release(struct dma_buf *buffer)
+{
+ struct drm_gem_object *obj = buffer->priv;
+ /* release reference that was taken when dmabuf was exported
+ * in omap_gem_prime_set()..
+ */
+ drm_gem_object_unreference_unlocked(obj);
+}
+
+
+static int omap_gem_dmabuf_begin_cpu_access(struct dma_buf *buffer,
+ size_t start, size_t len, enum dma_data_direction dir)
+{
+ struct drm_gem_object *obj = buffer->priv;
+ struct page **pages;
+ if (omap_gem_flags(obj) & OMAP_BO_TILED) {
+ /* TODO we would need to pin at least part of the buffer to
+ * get de-tiled view. For now just reject it.
+ */
+ return -ENOMEM;
+ }
+ /* make sure we have the pages: */
+ return omap_gem_get_pages(obj, &pages, true);
+}
+
+static void omap_gem_dmabuf_end_cpu_access(struct dma_buf *buffer,
+ size_t start, size_t len, enum dma_data_direction dir)
+{
+ struct drm_gem_object *obj = buffer->priv;
+ omap_gem_put_pages(obj);
+}
+
+
+static void *omap_gem_dmabuf_kmap_atomic(struct dma_buf *buffer,
+ unsigned long page_num)
+{
+ struct drm_gem_object *obj = buffer->priv;
+ struct page **pages;
+ omap_gem_get_pages(obj, &pages, false);
+ omap_gem_cpu_sync(obj, page_num);
+ return kmap_atomic(pages[page_num]);
+}
+
+static void omap_gem_dmabuf_kunmap_atomic(struct dma_buf *buffer,
+ unsigned long page_num, void *addr)
+{
+ kunmap_atomic(addr);
+}
+
+static void *omap_gem_dmabuf_kmap(struct dma_buf *buffer,
+ unsigned long page_num)
+{
+ struct drm_gem_object *obj = buffer->priv;
+ struct page **pages;
+ omap_gem_get_pages(obj, &pages, false);
+ omap_gem_cpu_sync(obj, page_num);
+ return kmap(pages[page_num]);
+}
+
+static void omap_gem_dmabuf_kunmap(struct dma_buf *buffer,
+ unsigned long page_num, void *addr)
+{
+ struct drm_gem_object *obj = buffer->priv;
+ struct page **pages;
+ omap_gem_get_pages(obj, &pages, false);
+ kunmap(pages[page_num]);
+}
+
+/*
+ * TODO maybe we can split up drm_gem_mmap to avoid duplicating
+ * some here.. or at least have a drm_dmabuf_mmap helper.
+ */
+static int omap_gem_dmabuf_mmap(struct dma_buf *buffer,
+ struct vm_area_struct *vma)
+{
+ struct drm_gem_object *obj = buffer->priv;
+ int ret = 0;
+
+ if (WARN_ON(!obj->filp))
+ return -EINVAL;
+
+ /* Check for valid size. */
+ if (omap_gem_mmap_size(obj) < vma->vm_end - vma->vm_start) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ if (!obj->dev->driver->gem_vm_ops) {
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ vma->vm_flags |= VM_RESERVED | VM_IO | VM_PFNMAP | VM_DONTEXPAND;
+ vma->vm_ops = obj->dev->driver->gem_vm_ops;
+ vma->vm_private_data = obj;
+ vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+
+ /* Take a ref for this mapping of the object, so that the fault
+ * handler can dereference the mmap offset's pointer to the object.
+ * This reference is cleaned up by the corresponding vm_close
+ * (which should happen whether the vma was created by this call, or
+ * by a vm_open due to mremap or partial unmap or whatever).
+ */
+ vma->vm_ops->open(vma);
+
+out_unlock:
+
+ return omap_gem_mmap_obj(obj, vma);
+}
+
+struct dma_buf_ops omap_dmabuf_ops = {
+ .map_dma_buf = omap_gem_map_dma_buf,
+ .unmap_dma_buf = omap_gem_unmap_dma_buf,
+ .release = omap_gem_dmabuf_release,
+ .begin_cpu_access = omap_gem_dmabuf_begin_cpu_access,
+ .end_cpu_access = omap_gem_dmabuf_end_cpu_access,
+ .kmap_atomic = omap_gem_dmabuf_kmap_atomic,
+ .kunmap_atomic = omap_gem_dmabuf_kunmap_atomic,
+ .kmap = omap_gem_dmabuf_kmap,
+ .kunmap = omap_gem_dmabuf_kunmap,
+ .mmap = omap_gem_dmabuf_mmap,
+};
+
+struct dma_buf * omap_gem_prime_export(struct drm_device *dev,
+ struct drm_gem_object *obj, int flags)
+{
+ return dma_buf_export(obj, &omap_dmabuf_ops, obj->size, 0600);
+}
+
+struct drm_gem_object * omap_gem_prime_import(struct drm_device *dev,
+ struct dma_buf *buffer)
+{
+ struct drm_gem_object *obj;
+
+ /* is this one of own objects? */
+ if (buffer->ops == &omap_dmabuf_ops) {
+ obj = buffer->priv;
+ /* is it from our device? */
+ if (obj->dev == dev) {
+ drm_gem_object_reference(obj);
+ return obj;
+ }
+ }
+
+ /*
+ * TODO add support for importing buffers from other devices..
+ * for now we don't need this but would be nice to add eventually
+ */
+ return ERR_PTR(-EINVAL);
+}
diff --git a/drivers/staging/omapdrm/tcm-sita.c b/drivers/staging/omapdrm/tcm-sita.c
index 10d5ac3dae4b..efb609510540 100644
--- a/drivers/staging/omapdrm/tcm-sita.c
+++ b/drivers/staging/omapdrm/tcm-sita.c
@@ -200,7 +200,7 @@ static s32 sita_reserve_1d(struct tcm *tcm, u32 num_slots,
*
* @param w width
* @param h height
- * @param area pointer to the area that will be populated with the reesrved
+ * @param area pointer to the area that will be populated with the reserved
* area
*
* @return 0 on success, non-0 error value on failure.
diff --git a/drivers/staging/ozwpan/README b/drivers/staging/ozwpan/README
index bb1a69b94541..7c055ec99544 100644
--- a/drivers/staging/ozwpan/README
+++ b/drivers/staging/ozwpan/README
@@ -9,7 +9,7 @@ technology.
To operate the driver must be bound to a suitable network interface. This can
be done when the module is loaded (specifying the name of the network interface
-as a paramter - e.g. 'insmod ozwpan g_net_dev=go0') or can be bound after
+as a parameter - e.g. 'insmod ozwpan g_net_dev=go0') or can be bound after
loading using an ioctl call. See the ozappif.h file and the ioctls
OZ_IOCTL_ADD_BINDING and OZ_IOCTL_REMOVE_BINDING.
diff --git a/drivers/staging/ozwpan/ozappif.h b/drivers/staging/ozwpan/ozappif.h
index af0273293872..1b59b0748c6b 100644
--- a/drivers/staging/ozwpan/ozappif.h
+++ b/drivers/staging/ozwpan/ozappif.h
@@ -11,13 +11,13 @@
#define OZ_IOCTL_MAGIC 0xf4
struct oz_mac_addr {
- unsigned char a[6];
+ __u8 a[6];
};
#define OZ_MAX_PDS 8
struct oz_pd_list {
- int count;
+ __u32 count;
struct oz_mac_addr addr[OZ_MAX_PDS];
};
@@ -27,18 +27,10 @@ struct oz_binding_info {
char name[OZ_MAX_BINDING_LEN];
};
-struct oz_test {
- int action;
-};
-
#define OZ_IOCTL_GET_PD_LIST _IOR(OZ_IOCTL_MAGIC, 0, struct oz_pd_list)
#define OZ_IOCTL_SET_ACTIVE_PD _IOW(OZ_IOCTL_MAGIC, 1, struct oz_mac_addr)
#define OZ_IOCTL_GET_ACTIVE_PD _IOR(OZ_IOCTL_MAGIC, 2, struct oz_mac_addr)
-#define OZ_IOCTL_CLEAR_EVENTS _IO(OZ_IOCTL_MAGIC, 3)
-#define OZ_IOCTL_GET_EVENTS _IOR(OZ_IOCTL_MAGIC, 4, struct oz_evtlist)
#define OZ_IOCTL_ADD_BINDING _IOW(OZ_IOCTL_MAGIC, 5, struct oz_binding_info)
-#define OZ_IOCTL_TEST _IOWR(OZ_IOCTL_MAGIC, 6, struct oz_test)
-#define OZ_IOCTL_SET_EVENT_MASK _IOW(OZ_IOCTL_MAGIC, 7, unsigned long)
#define OZ_IOCTL_REMOVE_BINDING _IOW(OZ_IOCTL_MAGIC, 8, struct oz_binding_info)
#define OZ_IOCTL_MAX 9
diff --git a/drivers/staging/ozwpan/ozcdev.c b/drivers/staging/ozwpan/ozcdev.c
index 1c380d687963..27325f74ecdc 100644
--- a/drivers/staging/ozwpan/ozcdev.c
+++ b/drivers/staging/ozwpan/ozcdev.c
@@ -41,9 +41,6 @@ struct oz_serial_ctx {
};
/*------------------------------------------------------------------------------
*/
-int g_taction;
-/*------------------------------------------------------------------------------
- */
static struct oz_cdev g_cdev;
/*------------------------------------------------------------------------------
* Context: process and softirq
@@ -276,20 +273,6 @@ long oz_cdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return -EFAULT;
}
break;
-#ifdef WANT_EVENT_TRACE
- case OZ_IOCTL_CLEAR_EVENTS:
- oz_events_clear();
- break;
- case OZ_IOCTL_GET_EVENTS:
- rc = oz_events_copy((void __user *)arg);
- break;
- case OZ_IOCTL_SET_EVENT_MASK:
- if (copy_from_user(&g_evt_mask, (void __user *)arg,
- sizeof(unsigned long))) {
- return -EFAULT;
- }
- break;
-#endif /* WANT_EVENT_TRACE */
case OZ_IOCTL_ADD_BINDING:
case OZ_IOCTL_REMOVE_BINDING: {
struct oz_binding_info b;
diff --git a/drivers/staging/ozwpan/ozevent.c b/drivers/staging/ozwpan/ozevent.c
index 73703d3e96bd..7f66b4f19b01 100644
--- a/drivers/staging/ozwpan/ozevent.c
+++ b/drivers/staging/ozwpan/ozevent.c
@@ -5,29 +5,46 @@
*/
#include "ozconfig.h"
#ifdef WANT_EVENT_TRACE
+#include <linux/module.h>
+#include <linux/debugfs.h>
#include <linux/jiffies.h>
#include <linux/uaccess.h>
#include "oztrace.h"
#include "ozevent.h"
+#include "ozappif.h"
/*------------------------------------------------------------------------------
+ * Although the event mask is logically part of the oz_evtdev structure, it is
+ * needed outside of this file so define it seperately to avoid the need to
+ * export definition of struct oz_evtdev.
*/
-unsigned long g_evt_mask = 0xffffffff;
+u32 g_evt_mask;
/*------------------------------------------------------------------------------
*/
#define OZ_MAX_EVTS 2048 /* Must be power of 2 */
-DEFINE_SPINLOCK(g_eventlock);
-static int g_evt_in;
-static int g_evt_out;
-static int g_missed_events;
-static struct oz_event g_events[OZ_MAX_EVTS];
+struct oz_evtdev {
+ struct dentry *root_dir;
+ int evt_in;
+ int evt_out;
+ int missed_events;
+ int present;
+ atomic_t users;
+ spinlock_t lock;
+ struct oz_event evts[OZ_MAX_EVTS];
+};
+
+static struct oz_evtdev g_evtdev;
+
/*------------------------------------------------------------------------------
* Context: process
*/
void oz_event_init(void)
{
+ /* Because g_evtdev is static external all fields initally zero so no
+ * need to reinitialised those.
+ */
oz_trace("Event tracing initialized\n");
- g_evt_in = g_evt_out = 0;
- g_missed_events = 0;
+ spin_lock_init(&g_evtdev.lock);
+ atomic_set(&g_evtdev.users, 0);
}
/*------------------------------------------------------------------------------
* Context: process
@@ -43,74 +60,136 @@ void oz_event_log2(u8 evt, u8 ctx1, u16 ctx2, void *ctx3, unsigned ctx4)
{
unsigned long irqstate;
int ix;
- spin_lock_irqsave(&g_eventlock, irqstate);
- ix = (g_evt_in + 1) & (OZ_MAX_EVTS - 1);
- if (ix != g_evt_out) {
- struct oz_event *e = &g_events[g_evt_in];
+ spin_lock_irqsave(&g_evtdev.lock, irqstate);
+ ix = (g_evtdev.evt_in + 1) & (OZ_MAX_EVTS - 1);
+ if (ix != g_evtdev.evt_out) {
+ struct oz_event *e = &g_evtdev.evts[g_evtdev.evt_in];
e->jiffies = jiffies;
e->evt = evt;
e->ctx1 = ctx1;
e->ctx2 = ctx2;
- e->ctx3 = ctx3;
+ e->ctx3 = (__u32)(unsigned long)ctx3;
e->ctx4 = ctx4;
- g_evt_in = ix;
+ g_evtdev.evt_in = ix;
} else {
- g_missed_events++;
+ g_evtdev.missed_events++;
}
- spin_unlock_irqrestore(&g_eventlock, irqstate);
+ spin_unlock_irqrestore(&g_evtdev.lock, irqstate);
}
/*------------------------------------------------------------------------------
* Context: process
*/
-int oz_events_copy(struct oz_evtlist __user *lst)
+static void oz_events_clear(struct oz_evtdev *dev)
{
- int first;
- int ix;
- struct hdr {
- int count;
- int missed;
- } hdr;
- ix = g_evt_out;
- hdr.count = g_evt_in - ix;
- if (hdr.count < 0)
- hdr.count += OZ_MAX_EVTS;
- if (hdr.count > OZ_EVT_LIST_SZ)
- hdr.count = OZ_EVT_LIST_SZ;
- hdr.missed = g_missed_events;
- g_missed_events = 0;
- if (copy_to_user((void __user *)lst, &hdr, sizeof(hdr)))
- return -EFAULT;
- first = OZ_MAX_EVTS - ix;
- if (first > hdr.count)
- first = hdr.count;
- if (first) {
- int sz = first*sizeof(struct oz_event);
- void __user *p = (void __user *)lst->evts;
- if (copy_to_user(p, &g_events[ix], sz))
- return -EFAULT;
- if (hdr.count > first) {
- p = (void __user *)&lst->evts[first];
- sz = (hdr.count-first)*sizeof(struct oz_event);
- if (copy_to_user(p, g_events, sz))
- return -EFAULT;
- }
+ unsigned long irqstate;
+ oz_trace("Clearing events\n");
+ spin_lock_irqsave(&dev->lock, irqstate);
+ dev->evt_in = dev->evt_out = 0;
+ dev->missed_events = 0;
+ spin_unlock_irqrestore(&dev->lock, irqstate);
+}
+#ifdef CONFIG_DEBUG_FS
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+int oz_events_open(struct inode *inode, struct file *filp)
+{
+ oz_trace("oz_evt_open()\n");
+ oz_trace("Open flags: 0x%x\n", filp->f_flags);
+ if (atomic_add_return(1, &g_evtdev.users) == 1) {
+ oz_events_clear(&g_evtdev);
+ return nonseekable_open(inode, filp);
+ } else {
+ atomic_dec(&g_evtdev.users);
+ return -EBUSY;
}
- ix += hdr.count;
- if (ix >= OZ_MAX_EVTS)
- ix -= OZ_MAX_EVTS;
- g_evt_out = ix;
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+int oz_events_release(struct inode *inode, struct file *filp)
+{
+ oz_events_clear(&g_evtdev);
+ atomic_dec(&g_evtdev.users);
+ g_evt_mask = 0;
+ oz_trace("oz_evt_release()\n");
return 0;
}
/*------------------------------------------------------------------------------
* Context: process
*/
-void oz_events_clear(void)
+ssize_t oz_events_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *fpos)
{
- unsigned long irqstate;
- spin_lock_irqsave(&g_eventlock, irqstate);
- g_evt_in = g_evt_out = 0;
- g_missed_events = 0;
- spin_unlock_irqrestore(&g_eventlock, irqstate);
+ struct oz_evtdev *dev = &g_evtdev;
+ int rc = 0;
+ int nb_evts = count / sizeof(struct oz_event);
+ int n;
+ int sz;
+
+ n = dev->evt_in - dev->evt_out;
+ if (n < 0)
+ n += OZ_MAX_EVTS;
+ if (nb_evts > n)
+ nb_evts = n;
+ if (nb_evts == 0)
+ goto out;
+ n = OZ_MAX_EVTS - dev->evt_out;
+ if (n > nb_evts)
+ n = nb_evts;
+ sz = n * sizeof(struct oz_event);
+ if (copy_to_user(buf, &dev->evts[dev->evt_out], sz)) {
+ rc = -EFAULT;
+ goto out;
+ }
+ if (n == nb_evts)
+ goto out2;
+ n = nb_evts - n;
+ if (copy_to_user(buf + sz, dev->evts, n * sizeof(struct oz_event))) {
+ rc = -EFAULT;
+ goto out;
+ }
+out2:
+ dev->evt_out = (dev->evt_out + nb_evts) & (OZ_MAX_EVTS - 1);
+ rc = nb_evts * sizeof(struct oz_event);
+out:
+ return rc;
}
-#endif /* WANT_EVENT_TRACE */
+/*------------------------------------------------------------------------------
+ */
+const struct file_operations oz_events_fops = {
+ .owner = THIS_MODULE,
+ .open = oz_events_open,
+ .release = oz_events_release,
+ .read = oz_events_read,
+};
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+void oz_debugfs_init(void)
+{
+ struct dentry *parent;
+ parent = debugfs_create_dir("ozwpan", NULL);
+ if (parent == NULL) {
+ oz_trace("Failed to create debugfs directory ozmo\n");
+ return;
+ } else {
+ g_evtdev.root_dir = parent;
+ if (debugfs_create_file("events", S_IRUSR, parent, NULL,
+ &oz_events_fops) == NULL)
+ oz_trace("Failed to create file ozmo/events\n");
+ if (debugfs_create_x32("event_mask", S_IRUSR | S_IWUSR, parent,
+ &g_evt_mask) == NULL)
+ oz_trace("Failed to create file ozmo/event_mask\n");
+ }
+}
+/*------------------------------------------------------------------------------
+ * Context: process
+ */
+void oz_debugfs_remove(void)
+{
+ debugfs_remove_recursive(g_evtdev.root_dir);
+}
+#endif /* CONFIG_DEBUG_FS */
+#endif /* WANT_EVENT_TRACE */
diff --git a/drivers/staging/ozwpan/ozevent.h b/drivers/staging/ozwpan/ozevent.h
index f033d014c6f3..32f6f9859c41 100644
--- a/drivers/staging/ozwpan/ozevent.h
+++ b/drivers/staging/ozwpan/ozevent.h
@@ -9,23 +9,24 @@
#include "ozeventdef.h"
#ifdef WANT_EVENT_TRACE
-extern unsigned long g_evt_mask;
+extern u32 g_evt_mask;
void oz_event_init(void);
void oz_event_term(void);
void oz_event_log2(u8 evt, u8 ctx1, u16 ctx2, void *ctx3, unsigned ctx4);
+void oz_debugfs_init(void);
+void oz_debugfs_remove(void);
#define oz_event_log(__evt, __ctx1, __ctx2, __ctx3, __ctx4) \
do { \
if ((1<<(__evt)) & g_evt_mask) \
oz_event_log2(__evt, __ctx1, __ctx2, __ctx3, __ctx4); \
} while (0)
-int oz_events_copy(struct oz_evtlist __user *lst);
-void oz_events_clear(void);
+
#else
#define oz_event_init()
#define oz_event_term()
#define oz_event_log(__evt, __ctx1, __ctx2, __ctx3, __ctx4)
-#define oz_events_copy(__lst)
-#define oz_events_clear()
+#define oz_debugfs_init()
+#define oz_debugfs_remove()
#endif /* WANT_EVENT_TRACE */
#endif /* _OZEVENT_H */
diff --git a/drivers/staging/ozwpan/ozeventdef.h b/drivers/staging/ozwpan/ozeventdef.h
index a880288bab11..4b938981671a 100644
--- a/drivers/staging/ozwpan/ozeventdef.h
+++ b/drivers/staging/ozwpan/ozeventdef.h
@@ -29,19 +29,12 @@
#define OZ_EVT_DEBUG 20
struct oz_event {
- unsigned long jiffies;
- unsigned char evt;
- unsigned char ctx1;
- unsigned short ctx2;
- void *ctx3;
- unsigned ctx4;
-};
-
-#define OZ_EVT_LIST_SZ 64
-struct oz_evtlist {
- int count;
- int missed;
- struct oz_event evts[OZ_EVT_LIST_SZ];
+ __u32 jiffies;
+ __u8 evt;
+ __u8 ctx1;
+ __u16 ctx2;
+ __u32 ctx3;
+ __u32 ctx4;
};
#endif /* _OZEVENTDEF_H */
diff --git a/drivers/staging/ozwpan/ozhcd.c b/drivers/staging/ozwpan/ozhcd.c
index 750b14eb505e..251f07c39a6b 100644
--- a/drivers/staging/ozwpan/ozhcd.c
+++ b/drivers/staging/ozwpan/ozhcd.c
@@ -1416,7 +1416,7 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb,
oz_trace("USB_REQ_SET_CONFIGURATION - req\n");
break;
case USB_REQ_GET_CONFIGURATION:
- /* We short curcuit this case and reply directly since
+ /* We short circuit this case and reply directly since
* we have the selected configuration number cached.
*/
oz_event_log(OZ_EVT_CTRL_LOCAL, setup->bRequest, 0, 0,
@@ -1432,7 +1432,7 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb,
}
break;
case USB_REQ_GET_INTERFACE:
- /* We short curcuit this case and reply directly since
+ /* We short circuit this case and reply directly since
* we have the selected interface alternative cached.
*/
oz_event_log(OZ_EVT_CTRL_LOCAL, setup->bRequest, 0, 0,
@@ -1463,7 +1463,7 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb,
rc = -ENOMEM;
} else {
/* Note: we are queuing the request after we have
- * submitted it to be tranmitted. If the request were
+ * submitted it to be transmitted. If the request were
* to complete before we queued it then it would not
* be found in the queue. It seems impossible for
* this to happen but if it did the request would
diff --git a/drivers/staging/ozwpan/ozmain.c b/drivers/staging/ozwpan/ozmain.c
index aaf2ccc0bcfb..7579645d642a 100644
--- a/drivers/staging/ozwpan/ozmain.c
+++ b/drivers/staging/ozwpan/ozmain.c
@@ -33,6 +33,9 @@ static int __init ozwpan_init(void)
oz_protocol_init(g_net_dev);
oz_app_enable(OZ_APPID_USB, 1);
oz_apps_init();
+#ifdef CONFIG_DEBUG_FS
+ oz_debugfs_init();
+#endif
return 0;
}
/*------------------------------------------------------------------------------
@@ -44,6 +47,9 @@ static void __exit ozwpan_exit(void)
oz_apps_term();
oz_cdev_deregister();
oz_event_term();
+#ifdef CONFIG_DEBUG_FS
+ oz_debugfs_remove();
+#endif
}
/*------------------------------------------------------------------------------
*/
@@ -53,6 +59,6 @@ module_exit(ozwpan_exit);
MODULE_AUTHOR("Chris Kelly");
MODULE_DESCRIPTION("Ozmo Devices USB over WiFi hcd driver");
-MODULE_VERSION("1.0.8");
+MODULE_VERSION("1.0.9");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/ozwpan/ozusbsvc.c b/drivers/staging/ozwpan/ozusbsvc.c
index 9e74f9602384..8fa7f256ad8c 100644
--- a/drivers/staging/ozwpan/ozusbsvc.c
+++ b/drivers/staging/ozwpan/ozusbsvc.c
@@ -7,7 +7,7 @@
* The implementation of this service is split into two parts the first of which
* is protocol independent and the second contains protocol specific details.
* This split is to allow alternative protocols to be defined.
- * The implemenation of this service uses ozhcd.c to implement a USB HCD.
+ * The implementation of this service uses ozhcd.c to implement a USB HCD.
* -----------------------------------------------------------------------------
*/
#include <linux/init.h>
diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c
index 6183573f112f..7365089a33e8 100644
--- a/drivers/staging/panel/panel.c
+++ b/drivers/staging/panel/panel.c
@@ -754,7 +754,7 @@ static void lcd_backlight(int on)
if (lcd_bl_pin == PIN_NONE)
return;
- /* The backlight is activated by seting the AUTOFEED line to +5V */
+ /* The backlight is activated by setting the AUTOFEED line to +5V */
spin_lock(&pprt_lock);
bits.bl = on;
panel_set_bits();
diff --git a/drivers/staging/quatech_usb2/Kconfig b/drivers/staging/quatech_usb2/Kconfig
deleted file mode 100644
index 1494f42f3da0..000000000000
--- a/drivers/staging/quatech_usb2/Kconfig
+++ /dev/null
@@ -1,15 +0,0 @@
-config USB_SERIAL_QUATECH_USB2
- tristate "USB Quatech xSU2-[14]00 USB Serial Driver"
- depends on USB_SERIAL
- help
- Say Y here if you want to use a Quatech USB2.0 to serial adaptor. This
- driver supports the SSU2-100, DSU2-100, DSU2-400, QSU2-100, QSU2-400,
- ESU2-400 and ESU2-100 USB2.0 to RS232 / 485 / 422 serial adaptors.
-
- Some hardware has an incorrect product string and announces itself as
- ESU-100 (which uses the serqt driver) even though it is an ESU2-100.
- Check the label on the bottom of your device.
-
- To compile this driver as a module, choose M here: the module will be
- called quatech_usb2 .
-
diff --git a/drivers/staging/quatech_usb2/Makefile b/drivers/staging/quatech_usb2/Makefile
deleted file mode 100644
index bcd1f890d163..000000000000
--- a/drivers/staging/quatech_usb2/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_USB_SERIAL_QUATECH_USB2) += quatech_usb2.o
diff --git a/drivers/staging/quatech_usb2/TODO b/drivers/staging/quatech_usb2/TODO
deleted file mode 100644
index 67f61dbe14ac..000000000000
--- a/drivers/staging/quatech_usb2/TODO
+++ /dev/null
@@ -1,8 +0,0 @@
-Incomplete list of things that this driver does not yet implement completely or
-at all. some of these may not be possible to implement because the hardware
-support does not exist. Others may be possible, but the magic control codes to
-make them happen are unknown, and some may just need the driver support to
-implement them writing.
-
-* Mark/Space parity is not implemented (reported back correctly)
-* IXANY flow control mode is not implemented (flag ignored completely)
diff --git a/drivers/staging/quatech_usb2/quatech_usb2.c b/drivers/staging/quatech_usb2/quatech_usb2.c
deleted file mode 100644
index bb977e00cc86..000000000000
--- a/drivers/staging/quatech_usb2/quatech_usb2.c
+++ /dev/null
@@ -1,1976 +0,0 @@
-/*
- * Driver for Quatech Inc USB2.0 to serial adaptors. Largely unrelated to the
- * serqt_usb driver, based on a re-write of the vendor supplied serqt_usb2 code,
- * which is unrelated to the serqt_usb2 in the staging kernel
- */
-
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/module.h>
-#include <linux/serial.h>
-#include <linux/usb.h>
-#include <linux/usb/serial.h>
-#include <linux/uaccess.h>
-
-static bool debug;
-
-/* Version Information */
-#define DRIVER_VERSION "v2.00"
-#define DRIVER_AUTHOR "Tim Gobeli, Quatech, Inc"
-#define DRIVER_DESC "Quatech USB 2.0 to Serial Driver"
-
-/* vendor and device IDs */
-#define USB_VENDOR_ID_QUATECH 0x061d /* Quatech VID */
-#define QUATECH_SSU2_100 0xC120 /* RS232 single port */
-#define QUATECH_DSU2_100 0xC140 /* RS232 dual port */
-#define QUATECH_DSU2_400 0xC150 /* RS232/422/485 dual port */
-#define QUATECH_QSU2_100 0xC160 /* RS232 four port */
-#define QUATECH_QSU2_400 0xC170 /* RS232/422/485 four port */
-#define QUATECH_ESU2_100 0xC1A0 /* RS232 eight port */
-#define QUATECH_ESU2_400 0xC180 /* RS232/422/485 eight port */
-
-/* magic numbers go here, when we find out which ones are needed */
-
-#define QU2BOXPWRON 0x8000 /* magic number to turn FPGA power on */
-#define QU2BOX232 0x40 /* RS232 mode on MEI devices */
-#define QU2BOXSPD9600 0x60 /* set speed to 9600 baud */
-#define QT2_FIFO_DEPTH 1024 /* size of hardware fifos */
-#define QT2_TX_HEADER_LENGTH 5
-/* length of the header sent to the box with each write URB */
-
-/* directions for USB transfers */
-#define USBD_TRANSFER_DIRECTION_IN 0xc0
-#define USBD_TRANSFER_DIRECTION_OUT 0x40
-
-/* special Quatech command IDs. These are pushed down the
- USB control pipe to get the box on the end to do things */
-#define QT_SET_GET_DEVICE 0xc2
-#define QT_OPEN_CLOSE_CHANNEL 0xca
-/*#define QT_GET_SET_PREBUF_TRIG_LVL 0xcc
-#define QT_SET_ATF 0xcd*/
-#define QT2_GET_SET_REGISTER 0xc0
-#define QT2_GET_SET_UART 0xc1
-#define QT2_HW_FLOW_CONTROL_MASK 0xc5
-#define QT2_SW_FLOW_CONTROL_MASK 0xc6
-#define QT2_SW_FLOW_CONTROL_DISABLE 0xc7
-#define QT2_BREAK_CONTROL 0xc8
-#define QT2_STOP_RECEIVE 0xe0
-#define QT2_FLUSH_DEVICE 0xc4
-#define QT2_GET_SET_QMCR 0xe1
-
-/* sorts of flush we can do on */
-#define QT2_FLUSH_RX 0x00
-#define QT2_FLUSH_TX 0x01
-
-/* port setting constants, used to set up serial port speeds, flow
- * control and so on */
-#define QT2_SERIAL_MCR_DTR 0x01
-#define QT2_SERIAL_MCR_RTS 0x02
-#define QT2_SERIAL_MCR_LOOP 0x10
-
-#define QT2_SERIAL_MSR_CTS 0x10
-#define QT2_SERIAL_MSR_CD 0x80
-#define QT2_SERIAL_MSR_RI 0x40
-#define QT2_SERIAL_MSR_DSR 0x20
-#define QT2_SERIAL_MSR_MASK 0xf0
-
-#define QT2_SERIAL_8_DATA 0x03
-#define QT2_SERIAL_7_DATA 0x02
-#define QT2_SERIAL_6_DATA 0x01
-#define QT2_SERIAL_5_DATA 0x00
-
-#define QT2_SERIAL_ODD_PARITY 0x08
-#define QT2_SERIAL_EVEN_PARITY 0x18
-#define QT2_SERIAL_TWO_STOPB 0x04
-#define QT2_SERIAL_ONE_STOPB 0x00
-
-#define QT2_MAX_BAUD_RATE 921600
-#define QT2_MAX_BAUD_REMAINDER 4608
-
-#define QT2_SERIAL_LSR_OE 0x02
-#define QT2_SERIAL_LSR_PE 0x04
-#define QT2_SERIAL_LSR_FE 0x08
-#define QT2_SERIAL_LSR_BI 0x10
-
-/* value of Line Status Register when UART has completed
- * emptying data out on the line */
-#define QT2_LSR_TEMT 0x40
-
-/* register numbers on each UART, for use with qt2_box_[get|set]_register*/
-#define QT2_XMT_HOLD_REGISTER 0x00
-#define QT2_XVR_BUFFER_REGISTER 0x00
-#define QT2_FIFO_CONTROL_REGISTER 0x02
-#define QT2_LINE_CONTROL_REGISTER 0x03
-#define QT2_MODEM_CONTROL_REGISTER 0x04
-#define QT2_LINE_STATUS_REGISTER 0x05
-#define QT2_MODEM_STATUS_REGISTER 0x06
-
-/* handy macros for doing escape sequence parsing on data reads */
-#define THISCHAR ((unsigned char *)(urb->transfer_buffer))[i]
-#define NEXTCHAR ((unsigned char *)(urb->transfer_buffer))[i + 1]
-#define THIRDCHAR ((unsigned char *)(urb->transfer_buffer))[i + 2]
-#define FOURTHCHAR ((unsigned char *)(urb->transfer_buffer))[i + 3]
-#define FIFTHCHAR ((unsigned char *)(urb->transfer_buffer))[i + 4]
-
-static const struct usb_device_id quausb2_id_table[] = {
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU2_100)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_100)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_400)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_100)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_400)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_100)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_400)},
- {} /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, quausb2_id_table);
-
-/* custom structures we need go here */
-static struct usb_driver quausb2_usb_driver = {
- .name = "quatech-usb2-serial",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = quausb2_id_table,
-};
-
-/**
- * quatech2_port: Structure in which to keep all the messy stuff that this
- * driver needs alongside the usb_serial_port structure
- * @read_urb_busy: Flag indicating that port->read_urb is in use
- * @close_pending: flag indicating that this port is in the process of
- * being closed (and so no new reads / writes should be started).
- * @shadowLSR: Last received state of the line status register, holds the
- * value of the line status flags from the port
- * @shadowMSR: Last received state of the modem status register, holds
- * the value of the modem status received from the port
- * @rcv_flush: Flag indicating that a receive flush has occurred on
- * the hardware.
- * @xmit_flush: Flag indicating that a transmit flush has been processed by
- * the hardware.
- * @tx_pending_bytes: Number of bytes waiting to be sent. This total
- * includes the size (excluding header) of URBs that have been submitted but
- * have not yet been sent to to the device, and bytes that have been sent out
- * of the port but not yet reported sent by the "xmit_empty" messages (which
- * indicate the number of bytes sent each time they are received, despite the
- * misleading name).
- * - Starts at zero when port is initialised.
- * - is incremented by the size of the data to be written (no headers)
- * each time a write urb is dispatched.
- * - is decremented each time a "transmit empty" message is received
- * by the driver in the data stream.
- * @lock: Mutex to lock access to this structure when we need to ensure that
- * races don't occur to access bits of it.
- * @open_count: The number of uses of the port currently having
- * it open, i.e. the reference count.
- */
-struct quatech2_port {
- int magic;
- bool read_urb_busy;
- bool close_pending;
- __u8 shadowLSR;
- __u8 shadowMSR;
- bool rcv_flush;
- bool xmit_flush;
- int tx_pending_bytes;
- struct mutex modelock;
- int open_count;
-
- char active; /* someone has this device open */
- unsigned char *xfer_to_tty_buffer;
- wait_queue_head_t wait;
- __u8 shadowLCR; /* last LCR value received */
- __u8 shadowMCR; /* last MCR value received */
- char RxHolding;
- struct semaphore pend_xmit_sem; /* locks this structure */
- spinlock_t lock;
-};
-
-/**
- * Structure to hold device-wide internal status information
- * @param ReadBulkStopped The last bulk read attempt ended in tears
- * @param open_ports The number of serial ports currently in use on the box
- * @param current_port Pointer to the serial port structure of the port which
- * the read stream is currently directed to. Escape sequences in the read
- * stream will change this around as data arrives from different ports on the
- * box
- * @buffer_size: The max size buffer each URB can take, used to set the size of
- * the buffers allocated for writing to each port on the device (we need to
- * store this because it is known only to the endpoint, but used each time a
- * port is opened and a new buffer is allocated.
- */
-struct quatech2_dev {
- bool ReadBulkStopped;
- char open_ports;
- struct usb_serial_port *current_port;
- int buffer_size;
-};
-
-/* structure which holds line and modem status flags */
-struct qt2_status_data {
- __u8 line_status;
- __u8 modem_status;
-};
-
-/* Function prototypes */
-static int qt2_boxpoweron(struct usb_serial *serial);
-static int qt2_boxsetQMCR(struct usb_serial *serial, __u16 Uart_Number,
- __u8 QMCR_Value);
-static int port_paranoia_check(struct usb_serial_port *port,
- const char *function);
-static int serial_paranoia_check(struct usb_serial *serial,
- const char *function);
-static inline struct quatech2_port *qt2_get_port_private(struct usb_serial_port
- *port);
-static inline void qt2_set_port_private(struct usb_serial_port *port,
- struct quatech2_port *data);
-static inline struct quatech2_dev *qt2_get_dev_private(struct usb_serial
- *serial);
-static inline void qt2_set_dev_private(struct usb_serial *serial,
- struct quatech2_dev *data);
-static int qt2_openboxchannel(struct usb_serial *serial, __u16
- Uart_Number, struct qt2_status_data *pDeviceData);
-static int qt2_closeboxchannel(struct usb_serial *serial, __u16
- Uart_Number);
-static int qt2_conf_uart(struct usb_serial *serial, unsigned short Uart_Number,
- unsigned short divisor, unsigned char LCR);
-static void qt2_read_bulk_callback(struct urb *urb);
-static void qt2_write_bulk_callback(struct urb *urb);
-static void qt2_process_line_status(struct usb_serial_port *port,
- unsigned char LineStatus);
-static void qt2_process_modem_status(struct usb_serial_port *port,
- unsigned char ModemStatus);
-static void qt2_process_xmit_empty(struct usb_serial_port *port,
- unsigned char fourth_char, unsigned char fifth_char);
-static void qt2_process_port_change(struct usb_serial_port *port,
- unsigned char New_Current_Port);
-static void qt2_process_rcv_flush(struct usb_serial_port *port);
-static void qt2_process_xmit_flush(struct usb_serial_port *port);
-static void qt2_process_rx_char(struct usb_serial_port *port,
- unsigned char data);
-static int qt2_box_get_register(struct usb_serial *serial,
- unsigned char uart_number, unsigned short register_num,
- __u8 *pValue);
-static int qt2_box_set_register(struct usb_serial *serial,
- unsigned short Uart_Number, unsigned short Register_Num,
- unsigned short Value);
-static int qt2_boxsetuart(struct usb_serial *serial, unsigned short Uart_Number,
- unsigned short default_divisor, unsigned char default_LCR);
-static int qt2_boxsethw_flowctl(struct usb_serial *serial,
- unsigned int UartNumber, bool bSet);
-static int qt2_boxsetsw_flowctl(struct usb_serial *serial, __u16 UartNumber,
- unsigned char stop_char, unsigned char start_char);
-static int qt2_boxunsetsw_flowctl(struct usb_serial *serial, __u16 UartNumber);
-static int qt2_boxstoprx(struct usb_serial *serial, unsigned short uart_number,
- unsigned short stop);
-
-/* implementation functions, roughly in order of use, are here */
-static int qt2_calc_num_ports(struct usb_serial *serial)
-{
- int num_ports;
- int flag_as_400;
- switch (serial->dev->descriptor.idProduct) {
- case QUATECH_SSU2_100:
- num_ports = 1;
- break;
-
- case QUATECH_DSU2_400:
- flag_as_400 = true;
- case QUATECH_DSU2_100:
- num_ports = 2;
- break;
-
- case QUATECH_QSU2_400:
- flag_as_400 = true;
- case QUATECH_QSU2_100:
- num_ports = 4;
- break;
-
- case QUATECH_ESU2_400:
- flag_as_400 = true;
- case QUATECH_ESU2_100:
- num_ports = 8;
- break;
- default:
- num_ports = 1;
- break;
- }
- return num_ports;
-}
-
-static int qt2_attach(struct usb_serial *serial)
-{
- struct usb_serial_port *port;
- struct quatech2_port *qt2_port; /* port-specific private data pointer */
- struct quatech2_dev *qt2_dev; /* dev-specific private data pointer */
- int i;
- /* stuff for storing endpoint addresses now */
- struct usb_endpoint_descriptor *endpoint;
- struct usb_host_interface *iface_desc;
- struct usb_serial_port *port0; /* first port structure on device */
-
- /* check how many endpoints there are on the device, for
- * sanity's sake */
- dbg("%s(): Endpoints: %d bulk in, %d bulk out, %d interrupt in",
- __func__, serial->num_bulk_in,
- serial->num_bulk_out, serial->num_interrupt_in);
- if ((serial->num_bulk_in != 1) || (serial->num_bulk_out != 1)) {
- dbg("Device has wrong number of bulk endpoints!");
- return -ENODEV;
- }
- iface_desc = serial->interface->cur_altsetting;
-
- /* Set up per-device private data, storing extra data alongside
- * struct usb_serial */
- qt2_dev = kzalloc(sizeof(*qt2_dev), GFP_KERNEL);
- if (!qt2_dev) {
- dbg("%s: kmalloc for quatech2_dev failed!",
- __func__);
- return -ENOMEM;
- }
- qt2_dev->open_ports = 0; /* no ports open */
- qt2_set_dev_private(serial, qt2_dev); /* store private data */
-
- /* Now setup per port private data, which replaces all the things
- * that quatech added to standard kernel structures in their driver */
- for (i = 0; i < serial->num_ports; i++) {
- port = serial->port[i];
- qt2_port = kzalloc(sizeof(*qt2_port), GFP_KERNEL);
- if (!qt2_port) {
- dbg("%s: kmalloc for quatech2_port (%d) failed!.",
- __func__, i);
- return -ENOMEM;
- }
- /* initialise stuff in the structure */
- qt2_port->open_count = 0; /* port is not open */
- spin_lock_init(&qt2_port->lock);
- mutex_init(&qt2_port->modelock);
- qt2_set_port_private(port, qt2_port);
- }
-
- /* gain access to port[0]'s structure because we want to store
- * device-level stuff in it */
- if (serial_paranoia_check(serial, __func__))
- return -ENODEV;
- port0 = serial->port[0]; /* get the first port's device structure */
-
- /* print endpoint addresses so we can check them later
- * by hand */
- for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
- endpoint = &iface_desc->endpoint[i].desc;
- if ((endpoint->bEndpointAddress & 0x80) &&
- ((endpoint->bmAttributes & 3) == 0x02)) {
- /* we found a bulk in endpoint */
- dbg("found bulk in at %#.2x",
- endpoint->bEndpointAddress);
- }
-
- if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
- ((endpoint->bmAttributes & 3) == 0x02)) {
- /* we found a bulk out endpoint */
- dbg("found bulk out at %#.2x",
- endpoint->bEndpointAddress);
- qt2_dev->buffer_size = endpoint->wMaxPacketSize;
- /* max size of URB needs recording for the device */
- }
- } /* end printing endpoint addresses */
-
- /* switch on power to the hardware */
- if (qt2_boxpoweron(serial) < 0) {
- dbg("qt2_boxpoweron() failed");
- goto startup_error;
- }
- /* set all ports to RS232 mode */
- for (i = 0; i < serial->num_ports; ++i) {
- if (qt2_boxsetQMCR(serial, i, QU2BOX232) < 0) {
- dbg("qt2_boxsetQMCR() on port %d failed",
- i);
- goto startup_error;
- }
- }
-
- return 0;
-
-startup_error:
- for (i = 0; i < serial->num_ports; i++) {
- port = serial->port[i];
- qt2_port = qt2_get_port_private(port);
- kfree(qt2_port);
- qt2_set_port_private(port, NULL);
- }
- qt2_dev = qt2_get_dev_private(serial);
- kfree(qt2_dev);
- qt2_set_dev_private(serial, NULL);
-
- dbg("Exit fail %s\n", __func__);
- return -EIO;
-}
-
-static void qt2_release(struct usb_serial *serial)
-{
- struct usb_serial_port *port;
- struct quatech2_port *qt_port;
- int i;
-
- dbg("enterting %s", __func__);
-
- for (i = 0; i < serial->num_ports; i++) {
- port = serial->port[i];
- if (!port)
- continue;
-
- qt_port = usb_get_serial_port_data(port);
- kfree(qt_port);
- usb_set_serial_port_data(port, NULL);
- }
-}
-/* This function is called once per serial port on the device, when
- * that port is opened by a userspace application.
- * The tty_struct and the usb_serial_port belong to this port,
- * i.e. there are multiple ones for a multi-port device.
- * However the usb_serial_port structure has a back-pointer
- * to the parent usb_serial structure which belongs to the device,
- * so we can access either the device-wide information or
- * any other port's information (because there are also forward
- * pointers) via that pointer.
- * This is most helpful if the device shares resources (e.g. end
- * points) between different ports
- */
-int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)
-{
- struct usb_serial *serial; /* device structure */
- struct usb_serial_port *port0; /* first port structure on device */
- struct quatech2_port *port_extra; /* extra data for this port */
- struct quatech2_port *port0_extra; /* extra data for first port */
- struct quatech2_dev *dev_extra; /* extra data for the device */
- struct qt2_status_data ChannelData;
- unsigned short default_divisor = QU2BOXSPD9600;
- unsigned char default_LCR = QT2_SERIAL_8_DATA;
- int status;
- int result;
-
- if (port_paranoia_check(port, __func__))
- return -ENODEV;
-
- dbg("%s(): port %d", __func__, port->number);
-
- serial = port->serial; /* get the parent device structure */
- if (serial_paranoia_check(serial, __func__)) {
- dbg("usb_serial struct failed sanity check");
- return -ENODEV;
- }
- dev_extra = qt2_get_dev_private(serial);
- /* get the device private data */
- if (dev_extra == NULL) {
- dbg("device extra data pointer is null");
- return -ENODEV;
- }
- port0 = serial->port[0]; /* get the first port's device structure */
- if (port_paranoia_check(port0, __func__)) {
- dbg("port0 usb_serial_port struct failed sanity check");
- return -ENODEV;
- }
-
- port_extra = qt2_get_port_private(port);
- port0_extra = qt2_get_port_private(port0);
- if (port_extra == NULL || port0_extra == NULL) {
- dbg("failed to get private data for port or port0");
- return -ENODEV;
- }
-
- /* FIXME: are these needed? Does it even do anything useful? */
- /* get the modem and line status values from the UART */
- status = qt2_openboxchannel(serial, port->number,
- &ChannelData);
- if (status < 0) {
- dbg("qt2_openboxchannel on channel %d failed",
- port->number);
- return status;
- }
- port_extra->shadowLSR = ChannelData.line_status &
- (QT2_SERIAL_LSR_OE | QT2_SERIAL_LSR_PE |
- QT2_SERIAL_LSR_FE | QT2_SERIAL_LSR_BI);
- port_extra->shadowMSR = ChannelData.modem_status &
- (QT2_SERIAL_MSR_CTS | QT2_SERIAL_MSR_DSR |
- QT2_SERIAL_MSR_RI | QT2_SERIAL_MSR_CD);
-
-/* port_extra->fifo_empty_flag = true;*/
- dbg("qt2_openboxchannel on channel %d completed.",
- port->number);
-
- /* Set Baud rate to default and turn off flow control here */
- status = qt2_conf_uart(serial, port->number, default_divisor,
- default_LCR);
- if (status < 0) {
- dbg("qt2_conf_uart() failed on channel %d",
- port->number);
- return status;
- }
- dbg("qt2_conf_uart() completed on channel %d",
- port->number);
-
- /*
- * At this point we will need some end points to make further progress.
- * Handlily, the correct endpoint addresses have been filled out into
- * the usb_serial_port structure for us by the driver core, so we
- * already have access to them.
- * As there is only one bulk in and one bulk out end-point, these are in
- * port[0]'s structure, and the rest are uninitialised. Handily,
- * when we do a write to a port, we will use the same endpoint
- * regardless of the port, with a 5-byte header added on to
- * tell the box which port it should eventually come out of, so we only
- * need the one set of endpoints. We will have one URB per port for
- * writing, so that multiple ports can be writing at once.
- * Finally we need a bulk in URB to use for background reads from the
- * device, which will deal with uplink data from the box to host.
- */
- dbg("port0 bulk in endpoint is %#.2x", port0->bulk_in_endpointAddress);
- dbg("port0 bulk out endpoint is %#.2x",
- port0->bulk_out_endpointAddress);
-
- /* set up write_urb for bulk out transfers on this port. The USB
- * serial framework will have allocated a blank URB, buffer etc for
- * port0 when it put the endpoints there, but not for any of the other
- * ports on the device because there are no more endpoints. Thus we
- * have to allocate our own URBs for ports 1-7
- */
- if (port->write_urb == NULL) {
- dbg("port->write_urb == NULL, allocating one");
- port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!port->write_urb) {
- err("Allocating write URB failed");
- return -ENOMEM;
- }
- /* buffer same size as port0 */
- port->bulk_out_size = dev_extra->buffer_size;
- port->bulk_out_buffer = kmalloc(port->bulk_out_size,
- GFP_KERNEL);
- if (!port->bulk_out_buffer) {
- err("Couldn't allocate bulk_out_buffer");
- return -ENOMEM;
- }
- }
- if (serial->dev == NULL)
- dbg("serial->dev == NULL");
- dbg("port->bulk_out_size is %d", port->bulk_out_size);
-
- usb_fill_bulk_urb(port->write_urb, serial->dev,
- usb_sndbulkpipe(serial->dev,
- port0->bulk_out_endpointAddress),
- port->bulk_out_buffer,
- port->bulk_out_size,
- qt2_write_bulk_callback,
- port);
- port_extra->tx_pending_bytes = 0;
-
- if (dev_extra->open_ports == 0) {
- /* this is first port to be opened, so need the read URB
- * initialised for bulk in transfers (this is shared amongst
- * all the ports on the device) */
- usb_fill_bulk_urb(port0->read_urb, serial->dev,
- usb_rcvbulkpipe(serial->dev,
- port0->bulk_in_endpointAddress),
- port0->bulk_in_buffer,
- port0->bulk_in_size,
- qt2_read_bulk_callback, serial);
- dbg("port0 bulk in URB initialised");
-
- /* submit URB, i.e. start reading from device (async) */
- dev_extra->ReadBulkStopped = false;
- port_extra->read_urb_busy = true;
- result = usb_submit_urb(port->read_urb, GFP_KERNEL);
- if (result) {
- dev_err(&port->dev,
- "%s(): Error %d submitting bulk in urb",
- __func__, result);
- port_extra->read_urb_busy = false;
- dev_extra->ReadBulkStopped = true;
- }
-
- /* When the first port is opened, initialise the value of
- * current_port in dev_extra to this port, so it is set
- * to something. Once the box sends data it will send the
- * relevant escape sequences to get it to the right port anyway
- */
- dev_extra->current_port = port;
- }
-
- /* initialize our wait queues */
- init_waitqueue_head(&port_extra->wait);
- /* increment the count of openings of this port by one */
- port_extra->open_count++;
-
- /* remember to store dev_extra, port_extra and port0_extra back again at
- * end !*/
- qt2_set_port_private(port, port_extra);
- qt2_set_port_private(serial->port[0], port0_extra);
- qt2_set_dev_private(serial, dev_extra);
-
- dev_extra->open_ports++; /* one more port opened */
-
- return 0;
-}
-
-/* called when a port is closed by userspace. It won't be called, however,
- * until calls to chars_in_buffer() reveal that the port has completed
- * sending buffered data, and there is nothing else to do. Thus we don't have
- * to rely on forcing data through in this function. */
-/* Setting close_pending should keep new data from being written out,
- * once all the data in the enpoint buffers is moved out we won't get
- * any more. */
-/* BoxStopReceive would keep any more data from coming from a given
- * port, but isn't called by the vendor driver, although their comments
- * mention it. Should it be used here to stop the inbound data
- * flow?
- */
-static void qt2_close(struct usb_serial_port *port)
-{
- /* time out value for flush loops */
- unsigned long jift;
- struct quatech2_port *port_extra; /* extra data for this port */
- struct usb_serial *serial; /* device structure */
- struct quatech2_dev *dev_extra; /* extra data for the device */
- __u8 lsr_value = 0; /* value of Line Status Register */
- int status; /* result of last USB comms function */
-
- dbg("%s(): port %d", __func__, port->number);
- serial = port->serial; /* get the parent device structure */
- dev_extra = qt2_get_dev_private(serial);
- /* get the device private data */
- port_extra = qt2_get_port_private(port); /* port private data */
-
- /* we can now (and only now) stop reading data */
- port_extra->close_pending = true;
- dbg("%s(): port_extra->close_pending = true", __func__);
- /* although the USB side is now empty, the UART itself may
- * still be pushing characters out over the line, so we have to
- * wait testing the actual line status until the lines change
- * indicating that the data is done transferring. */
- /* FIXME: slow this polling down so it doesn't run the USB bus flat out
- * if it actually has to spend any time in this loop (which it normally
- * doesn't because the buffer is nearly empty) */
- jift = jiffies + (10 * HZ); /* 10 sec timeout */
- do {
- status = qt2_box_get_register(serial, port->number,
- QT2_LINE_STATUS_REGISTER, &lsr_value);
- if (status < 0) {
- dbg("%s(): qt2_box_get_register failed", __func__);
- break;
- }
- if ((lsr_value & QT2_LSR_TEMT)) {
- dbg("UART done sending");
- break;
- }
- schedule();
- } while (jiffies <= jift);
-
- status = qt2_closeboxchannel(serial, port->number);
- if (status < 0)
- dbg("%s(): port %d qt2_box_open_close_channel failed",
- __func__, port->number);
- /* to avoid leaking URBs, we should now free the write_urb for this
- * port and set the pointer to null so that next time the port is opened
- * a new URB is allocated. This avoids leaking URBs when the device is
- * removed */
- usb_free_urb(port->write_urb);
- kfree(port->bulk_out_buffer);
- port->bulk_out_buffer = NULL;
- port->bulk_out_size = 0;
-
- /* decrement the count of openings of this port by one */
- port_extra->open_count--;
- /* one less overall open as well */
- dev_extra->open_ports--;
- dbg("%s(): Exit, dev_extra->open_ports = %d", __func__,
- dev_extra->open_ports);
-}
-
-/**
- * qt2_write - write bytes from the tty layer out to the USB device.
- * @buf: The data to be written, size at least count.
- * @count: The number of bytes requested for transmission.
- * @return The number of bytes actually accepted for transmission to the device.
- */
-static int qt2_write(struct tty_struct *tty, struct usb_serial_port *port,
- const unsigned char *buf, int count)
-{
- struct usb_serial *serial; /* parent device struct */
- __u8 header_array[5]; /* header used to direct writes to the correct
- port on the device */
- struct quatech2_port *port_extra; /* extra data for this port */
- int result;
-
- serial = port->serial; /* get the parent device of the port */
- port_extra = qt2_get_port_private(port); /* port extra info */
- if (serial == NULL)
- return -ENODEV;
- dbg("%s(): port %d, requested to write %d bytes, %d already pending",
- __func__, port->number, count, port_extra->tx_pending_bytes);
-
- if (count <= 0) {
- dbg("%s(): write request of <= 0 bytes", __func__);
- return 0; /* no bytes written */
- }
-
- /* check if the write urb is already in use, i.e. data already being
- * sent to this port */
- if ((port->write_urb->status == -EINPROGRESS)) {
- /* Fifo hasn't been emptied since last write to this port */
- dbg("%s(): already writing, port->write_urb->status == "
- "-EINPROGRESS", __func__);
- /* schedule_work(&port->work); commented in vendor driver */
- return 0;
- } else if (port_extra->tx_pending_bytes >= QT2_FIFO_DEPTH) {
- /* buffer is full (==). > should not occur, but would indicate
- * that an overflow had occurred */
- dbg("%s(): port transmit buffer is full!", __func__);
- /* schedule_work(&port->work); commented in vendor driver */
- return 0;
- }
-
- /* We must fill the first 5 bytes of anything we sent with a transmit
- * header which directes the data to the correct port. The maximum
- * size we can send out in one URB is port->bulk_out_size, which caps
- * the number of bytes of real data we can send in each write. As the
- * semantics of write allow us to write less than we were give, we cap
- * the maximum we will ever write to the device as 5 bytes less than
- * one URB's worth, by reducing the value of the count argument
- * appropriately*/
- if (count > port->bulk_out_size - QT2_TX_HEADER_LENGTH) {
- count = port->bulk_out_size - QT2_TX_HEADER_LENGTH;
- dbg("%s(): write request bigger than urb, only accepting "
- "%d bytes", __func__, count);
- }
- /* we must also ensure that the FIFO at the other end can cope with the
- * URB we send it, otherwise it will have problems. As above, we can
- * restrict the write size by just shrinking count.*/
- if (count > (QT2_FIFO_DEPTH - port_extra->tx_pending_bytes)) {
- count = QT2_FIFO_DEPTH - port_extra->tx_pending_bytes;
- dbg("%s(): not enough room in buffer, only accepting %d bytes",
- __func__, count);
- }
- /* now build the header for transmission */
- header_array[0] = 0x1b;
- header_array[1] = 0x1b;
- header_array[2] = (__u8)port->number;
- header_array[3] = (__u8)count;
- header_array[4] = (__u8)count >> 8;
- /* copy header into URB */
- memcpy(port->write_urb->transfer_buffer, header_array,
- QT2_TX_HEADER_LENGTH);
- /* and actual data to write */
- memcpy(port->write_urb->transfer_buffer + 5, buf, count);
-
- dbg("%s(): first data byte to send = %#.2x", __func__, *buf);
-
- /* set up our urb */
- usb_fill_bulk_urb(port->write_urb, serial->dev,
- usb_sndbulkpipe(serial->dev,
- port->bulk_out_endpointAddress),
- port->write_urb->transfer_buffer, count + 5,
- (qt2_write_bulk_callback), port);
- /* send the data out the bulk port */
- result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
- if (result) {
- /* error couldn't submit urb */
- result = 0; /* return 0 as nothing got written */
- dbg("%s(): failed submitting write urb, error %d",
- __func__, result);
- } else {
- port_extra->tx_pending_bytes += count;
- result = count; /* return number of bytes written, i.e. count */
- dbg("%s(): submitted write urb, wrote %d bytes, "
- "total pending bytes %d",
- __func__, result, port_extra->tx_pending_bytes);
- }
- return result;
-}
-
-/* This is used by the next layer up to know how much space is available
- * in the buffer on the device. It is used on a device closure to avoid
- * calling close() until the buffer is reported to be empty.
- * The returned value must never go down by more than the number of bytes
- * written for correct behaviour further up the driver stack, i.e. if I call
- * it, then write 6 bytes, then call again I should get 6 less, or possibly
- * only 5 less if one was written in the meantime, etc. I should never get 7
- * less (or any bigger number) because I only wrote 6 bytes.
- */
-static int qt2_write_room(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- /* parent usb_serial_port pointer */
- struct quatech2_port *port_extra; /* extra data for this port */
- int room = 0;
- port_extra = qt2_get_port_private(port);
-
- if (port_extra->close_pending == true) {
- dbg("%s(): port_extra->close_pending == true", __func__);
- return -ENODEV;
- }
- /* Q: how many bytes would a write() call actually succeed in writing
- * if it happened now?
- * A: one QT2_FIFO_DEPTH, less the number of bytes waiting to be sent
- * out of the port, unless this is more than the size of the
- * write_urb output buffer less the header, which is the maximum
- * size write we can do.
-
- * Most of the implementation of this is done when writes to the device
- * are started or terminate. When we send a write to the device, we
- * reduce the free space count by the size of the dispatched write.
- * When a "transmit empty" message comes back up the USB read stream,
- * we decrement the count by the number of bytes reported sent, thus
- * keeping track of the difference between sent and received bytes.
- */
-
- room = (QT2_FIFO_DEPTH - port_extra->tx_pending_bytes);
- /* space in FIFO */
- if (room > port->bulk_out_size - QT2_TX_HEADER_LENGTH)
- room = port->bulk_out_size - QT2_TX_HEADER_LENGTH;
- /* if more than the URB can hold, then cap to that limit */
-
- dbg("%s(): port %d: write room is %d", __func__, port->number, room);
- return room;
-}
-
-static int qt2_chars_in_buffer(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- /* parent usb_serial_port pointer */
- struct quatech2_port *port_extra; /* extra data for this port */
- port_extra = qt2_get_port_private(port);
-
- dbg("%s(): port %d: chars_in_buffer = %d", __func__,
- port->number, port_extra->tx_pending_bytes);
- return port_extra->tx_pending_bytes;
-}
-
-/* called when userspace does an ioctl() on the device. Note that
- * TIOCMGET and TIOCMSET are filtered off to their own methods before they get
- * here, so we don't have to handle them.
- */
-static int qt2_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct usb_serial *serial = port->serial;
- __u8 mcr_value; /* Modem Control Register value */
- __u8 msr_value; /* Modem Status Register value */
- unsigned short prev_msr_value; /* Previous value of Modem Status
- * Register used to implement waiting for a line status change to
- * occur */
- struct quatech2_port *port_extra; /* extra data for this port */
- DECLARE_WAITQUEUE(wait, current);
- /* Declare a wait queue named "wait" */
-
- unsigned int value;
- unsigned int UartNumber;
-
- if (serial == NULL)
- return -ENODEV;
- UartNumber = tty->index - serial->minor;
- port_extra = qt2_get_port_private(port);
-
- dbg("%s(): port %d, UartNumber %d, tty =0x%p", __func__,
- port->number, UartNumber, tty);
-
- if (cmd == TIOCMBIS || cmd == TIOCMBIC) {
- if (qt2_box_get_register(port->serial, UartNumber,
- QT2_MODEM_CONTROL_REGISTER, &mcr_value) < 0)
- return -ESPIPE;
- if (copy_from_user(&value, (unsigned int *)arg,
- sizeof(value)))
- return -EFAULT;
-
- switch (cmd) {
- case TIOCMBIS:
- if (value & TIOCM_RTS)
- mcr_value |= QT2_SERIAL_MCR_RTS;
- if (value & TIOCM_DTR)
- mcr_value |= QT2_SERIAL_MCR_DTR;
- if (value & TIOCM_LOOP)
- mcr_value |= QT2_SERIAL_MCR_LOOP;
- break;
- case TIOCMBIC:
- if (value & TIOCM_RTS)
- mcr_value &= ~QT2_SERIAL_MCR_RTS;
- if (value & TIOCM_DTR)
- mcr_value &= ~QT2_SERIAL_MCR_DTR;
- if (value & TIOCM_LOOP)
- mcr_value &= ~QT2_SERIAL_MCR_LOOP;
- break;
- default:
- break;
- } /* end of local switch on cmd */
- if (qt2_box_set_register(port->serial, UartNumber,
- QT2_MODEM_CONTROL_REGISTER, mcr_value) < 0) {
- return -ESPIPE;
- } else {
- port_extra->shadowMCR = mcr_value;
- return 0;
- }
- } else if (cmd == TIOCMIWAIT) {
- dbg("%s() port %d, cmd == TIOCMIWAIT enter",
- __func__, port->number);
- prev_msr_value = port_extra->shadowMSR & QT2_SERIAL_MSR_MASK;
- barrier();
- __set_current_state(TASK_INTERRUPTIBLE);
- while (1) {
- add_wait_queue(&port_extra->wait, &wait);
- schedule();
- dbg("%s(): port %d, cmd == TIOCMIWAIT here\n",
- __func__, port->number);
- remove_wait_queue(&port_extra->wait, &wait);
- /* see if a signal woke us up */
- if (signal_pending(current))
- return -ERESTARTSYS;
- set_current_state(TASK_INTERRUPTIBLE);
- msr_value = port_extra->shadowMSR & QT2_SERIAL_MSR_MASK;
- if (msr_value == prev_msr_value) {
- __set_current_state(TASK_RUNNING);
- return -EIO; /* no change - error */
- }
- if ((arg & TIOCM_RNG &&
- ((prev_msr_value & QT2_SERIAL_MSR_RI) ==
- (msr_value & QT2_SERIAL_MSR_RI))) ||
- (arg & TIOCM_DSR &&
- ((prev_msr_value & QT2_SERIAL_MSR_DSR) ==
- (msr_value & QT2_SERIAL_MSR_DSR))) ||
- (arg & TIOCM_CD &&
- ((prev_msr_value & QT2_SERIAL_MSR_CD) ==
- (msr_value & QT2_SERIAL_MSR_CD))) ||
- (arg & TIOCM_CTS &&
- ((prev_msr_value & QT2_SERIAL_MSR_CTS) ==
- (msr_value & QT2_SERIAL_MSR_CTS)))) {
- __set_current_state(TASK_RUNNING);
- return 0;
- }
- } /* end inifinite while */
- /* FIXME: This while loop needs a way to break out if the device
- * is disconnected while a process is waiting for the MSR to
- * change, because once it's disconnected, it isn't going to
- * change state ... */
- } else {
- /* any other ioctls we don't know about come here */
- dbg("%s(): No ioctl for that one. port = %d", __func__,
- port->number);
- return -ENOIOCTLCMD;
- }
-}
-
-/* Called when the user wishes to change the port settings using the termios
- * userspace interface */
-static void qt2_set_termios(struct tty_struct *tty,
- struct usb_serial_port *port, struct ktermios *old_termios)
-{
- struct usb_serial *serial; /* parent serial device */
- int baud, divisor, remainder;
- unsigned char LCR_change_to = 0;
- int status;
- __u16 UartNumber;
-
- dbg("%s(): port %d", __func__, port->number);
-
- serial = port->serial;
-
- UartNumber = port->number;
-
- if (old_termios && !tty_termios_hw_change(old_termios, tty->termios))
- return;
-
- switch (tty->termios->c_cflag) {
- case CS5:
- LCR_change_to |= QT2_SERIAL_5_DATA;
- break;
- case CS6:
- LCR_change_to |= QT2_SERIAL_6_DATA;
- break;
- case CS7:
- LCR_change_to |= QT2_SERIAL_7_DATA;
- break;
- default:
- case CS8:
- LCR_change_to |= QT2_SERIAL_8_DATA;
- break;
- }
-
- /* Parity stuff */
- if (tty->termios->c_cflag & PARENB) {
- if (tty->termios->c_cflag & PARODD)
- LCR_change_to |= QT2_SERIAL_ODD_PARITY;
- else
- LCR_change_to |= QT2_SERIAL_EVEN_PARITY;
- }
- /* Because LCR_change_to is initialised to zero, we don't have to worry
- * about the case where PARENB is not set or clearing bits, because by
- * default all of them are cleared, turning parity off.
- * as we don't support mark/space parity, we should clear the
- * mark/space parity bit in c_cflag, so the caller can tell we have
- * ignored the request */
- tty->termios->c_cflag &= ~CMSPAR;
-
- if (tty->termios->c_cflag & CSTOPB)
- LCR_change_to |= QT2_SERIAL_TWO_STOPB;
- else
- LCR_change_to |= QT2_SERIAL_ONE_STOPB;
-
- /* Thats the LCR stuff, next we need to work out the divisor as the
- * LCR and the divisor are set together */
- baud = tty_get_baud_rate(tty);
- if (!baud) {
- /* pick a default, any default... */
- baud = 9600;
- }
- dbg("%s(): got baud = %d", __func__, baud);
-
- divisor = QT2_MAX_BAUD_RATE / baud;
- remainder = QT2_MAX_BAUD_RATE % baud;
- /* Round to nearest divisor */
- if (((remainder * 2) >= baud) && (baud != 110))
- divisor++;
- dbg("%s(): setting divisor = %d, QT2_MAX_BAUD_RATE = %d , LCR = %#.2x",
- __func__, divisor, QT2_MAX_BAUD_RATE, LCR_change_to);
-
- status = qt2_boxsetuart(serial, UartNumber, (unsigned short) divisor,
- LCR_change_to);
- if (status < 0) {
- dbg("qt2_boxsetuart() failed");
- return;
- } else {
- /* now encode the baud rate we actually set, which may be
- * different to the request */
- baud = QT2_MAX_BAUD_RATE / divisor;
- tty_encode_baud_rate(tty, baud, baud);
- }
-
- /* Now determine flow control */
- if (tty->termios->c_cflag & CRTSCTS) {
- dbg("%s(): Enabling HW flow control port %d", __func__,
- port->number);
- /* Enable RTS/CTS flow control */
- status = qt2_boxsethw_flowctl(serial, UartNumber, true);
- if (status < 0) {
- dbg("qt2_boxsethw_flowctl() failed");
- return;
- }
- } else {
- /* Disable RTS/CTS flow control */
- dbg("%s(): disabling HW flow control port %d", __func__,
- port->number);
- status = qt2_boxsethw_flowctl(serial, UartNumber, false);
- if (status < 0) {
- dbg("qt2_boxsethw_flowctl failed");
- return;
- }
- }
- /* if we are implementing XON/XOFF, set the start and stop character
- * in the device */
- if (I_IXOFF(tty) || I_IXON(tty)) {
- unsigned char stop_char = STOP_CHAR(tty);
- unsigned char start_char = START_CHAR(tty);
- status = qt2_boxsetsw_flowctl(serial, UartNumber, stop_char,
- start_char);
- if (status < 0)
- dbg("qt2_boxsetsw_flowctl (enabled) failed");
- } else {
- /* disable SW flow control */
- status = qt2_boxunsetsw_flowctl(serial, UartNumber);
- if (status < 0)
- dbg("qt2_boxunsetsw_flowctl (disabling) failed");
- }
-}
-
-static int qt2_tiocmget(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct usb_serial *serial = port->serial;
-
- __u8 mcr_value; /* Modem Control Register value */
- __u8 msr_value; /* Modem Status Register value */
- unsigned int result = 0;
- int status;
- unsigned int UartNumber;
-
- if (serial == NULL)
- return -ENODEV;
-
- dbg("%s(): port %d, tty =0x%p", __func__, port->number, tty);
- UartNumber = tty->index - serial->minor;
- dbg("UartNumber is %d", UartNumber);
-
- status = qt2_box_get_register(port->serial, UartNumber,
- QT2_MODEM_CONTROL_REGISTER, &mcr_value);
- if (status >= 0) {
- status = qt2_box_get_register(port->serial, UartNumber,
- QT2_MODEM_STATUS_REGISTER, &msr_value);
- }
- if (status >= 0) {
- result = ((mcr_value & QT2_SERIAL_MCR_DTR) ? TIOCM_DTR : 0)
- /*DTR set */
- | ((mcr_value & QT2_SERIAL_MCR_RTS) ? TIOCM_RTS : 0)
- /*RTS set */
- | ((msr_value & QT2_SERIAL_MSR_CTS) ? TIOCM_CTS : 0)
- /* CTS set */
- | ((msr_value & QT2_SERIAL_MSR_CD) ? TIOCM_CAR : 0)
- /*Carrier detect set */
- | ((msr_value & QT2_SERIAL_MSR_RI) ? TIOCM_RI : 0)
- /* Ring indicator set */
- | ((msr_value & QT2_SERIAL_MSR_DSR) ? TIOCM_DSR : 0);
- /* DSR set */
- return result;
- } else {
- return -ESPIPE;
- }
-}
-
-static int qt2_tiocmset(struct tty_struct *tty,
- unsigned int set, unsigned int clear)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct usb_serial *serial = port->serial;
- __u8 mcr_value; /* Modem Control Register value */
- int status;
- unsigned int UartNumber;
-
- if (serial == NULL)
- return -ENODEV;
-
- UartNumber = tty->index - serial->minor;
- dbg("%s(): port %d, UartNumber %d", __func__, port->number, UartNumber);
-
- status = qt2_box_get_register(port->serial, UartNumber,
- QT2_MODEM_CONTROL_REGISTER, &mcr_value);
- if (status < 0)
- return -ESPIPE;
-
- /* Turn off RTS, DTR and loopback, then only turn on what was asked
- * for */
- mcr_value &= ~(QT2_SERIAL_MCR_RTS | QT2_SERIAL_MCR_DTR |
- QT2_SERIAL_MCR_LOOP);
- if (set & TIOCM_RTS)
- mcr_value |= QT2_SERIAL_MCR_RTS;
- if (set & TIOCM_DTR)
- mcr_value |= QT2_SERIAL_MCR_DTR;
- if (set & TIOCM_LOOP)
- mcr_value |= QT2_SERIAL_MCR_LOOP;
-
- status = qt2_box_set_register(port->serial, UartNumber,
- QT2_MODEM_CONTROL_REGISTER, mcr_value);
- if (status < 0)
- return -ESPIPE;
- else
- return 0;
-}
-
-/** qt2_break - Turn BREAK on and off on the UARTs
- */
-static void qt2_break(struct tty_struct *tty, int break_state)
-{
- struct usb_serial_port *port = tty->driver_data; /* parent port */
- struct usb_serial *serial = port->serial; /* parent device */
- struct quatech2_port *port_extra; /* extra data for this port */
- __u16 break_value;
- unsigned int result;
-
- port_extra = qt2_get_port_private(port);
- if (!serial) {
- dbg("%s(): port %d: no serial object", __func__, port->number);
- return;
- }
-
- if (break_state == -1)
- break_value = 1;
- else
- break_value = 0;
- dbg("%s(): port %d, break_value %d", __func__, port->number,
- break_value);
-
- mutex_lock(&port_extra->modelock);
- if (!port_extra->open_count) {
- dbg("%s(): port not open", __func__);
- goto exit;
- }
-
- result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- QT2_BREAK_CONTROL, 0x40, break_value,
- port->number, NULL, 0, 300);
-exit:
- mutex_unlock(&port_extra->modelock);
- dbg("%s(): exit port %d", __func__, port->number);
-
-}
-/**
- * qt2_throttle: - stop reading new data from the port
- */
-static void qt2_throttle(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct usb_serial *serial = port->serial;
- struct quatech2_port *port_extra; /* extra data for this port */
- dbg("%s(): port %d", __func__, port->number);
-
- port_extra = qt2_get_port_private(port);
- if (!serial) {
- dbg("%s(): enter port %d no serial object", __func__,
- port->number);
- return;
- }
-
- mutex_lock(&port_extra->modelock); /* lock structure */
- if (!port_extra->open_count) {
- dbg("%s(): port not open", __func__);
- goto exit;
- }
- /* Send command to box to stop receiving stuff. This will stop this
- * particular UART from filling the endpoint - in the multiport case the
- * FPGA UART will handle any flow control implemented, but for the single
- * port it's handed differently and we just quit submitting urbs
- */
- if (serial->dev->descriptor.idProduct != QUATECH_SSU2_100)
- qt2_boxstoprx(serial, port->number, 1);
-
- port->throttled = 1;
-exit:
- mutex_unlock(&port_extra->modelock);
- dbg("%s(): port %d: setting port->throttled", __func__, port->number);
- return;
-}
-
-/**
- * qt2_unthrottle: - start receiving data through the port again after being
- * throttled
- */
-static void qt2_unthrottle(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct usb_serial *serial = port->serial;
- struct quatech2_port *port_extra; /* extra data for this port */
- struct usb_serial_port *port0; /* first port structure on device */
- struct quatech2_dev *dev_extra; /* extra data for the device */
-
- if (!serial) {
- dbg("%s() enter port %d no serial object!", __func__,
- port->number);
- return;
- }
- dbg("%s(): enter port %d", __func__, port->number);
- dev_extra = qt2_get_dev_private(serial);
- port_extra = qt2_get_port_private(port);
- port0 = serial->port[0]; /* get the first port's device structure */
-
- mutex_lock(&port_extra->modelock);
- if (!port_extra->open_count) {
- dbg("%s(): port %d not open", __func__, port->number);
- goto exit;
- }
-
- if (port->throttled != 0) {
- dbg("%s(): port %d: unsetting port->throttled", __func__,
- port->number);
- port->throttled = 0;
- /* Send command to box to start receiving stuff */
- if (serial->dev->descriptor.idProduct != QUATECH_SSU2_100) {
- qt2_boxstoprx(serial, port->number, 0);
- } else if (dev_extra->ReadBulkStopped == true) {
- usb_fill_bulk_urb(port0->read_urb, serial->dev,
- usb_rcvbulkpipe(serial->dev,
- port0->bulk_in_endpointAddress),
- port0->bulk_in_buffer,
- port0->bulk_in_size,
- qt2_read_bulk_callback,
- serial);
- }
- }
-exit:
- mutex_unlock(&port_extra->modelock);
- dbg("%s(): exit port %d", __func__, port->number);
- return;
-}
-
-/* internal, private helper functions for the driver */
-
-/* Power up the FPGA in the box to get it working */
-static int qt2_boxpoweron(struct usb_serial *serial)
-{
- int result;
- __u8 Direcion;
- unsigned int pipe;
- Direcion = USBD_TRANSFER_DIRECTION_OUT;
- pipe = usb_rcvctrlpipe(serial->dev, 0);
- result = usb_control_msg(serial->dev, pipe, QT_SET_GET_DEVICE,
- Direcion, QU2BOXPWRON, 0x00, NULL, 0x00,
- 5000);
- return result;
-}
-
-/*
- * qt2_boxsetQMCR Issue a QT2_GET_SET_QMCR vendor-spcific request on the
- * default control pipe. If successful return the number of bytes written,
- * otherwise return a negative error number of the problem.
- */
-static int qt2_boxsetQMCR(struct usb_serial *serial, __u16 Uart_Number,
- __u8 QMCR_Value)
-{
- int result;
- __u16 PortSettings;
-
- PortSettings = (__u16)(QMCR_Value);
-
- dbg("%s(): Port = %d, PortSettings = 0x%x", __func__,
- Uart_Number, PortSettings);
-
- result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- QT2_GET_SET_QMCR, 0x40, PortSettings,
- (__u16)Uart_Number, NULL, 0, 5000);
- return result;
-}
-
-static int port_paranoia_check(struct usb_serial_port *port,
- const char *function)
-{
- if (!port) {
- dbg("%s - port == NULL", function);
- return -1;
- }
- if (!port->serial) {
- dbg("%s - port->serial == NULL\n", function);
- return -1;
- }
- return 0;
-}
-
-static int serial_paranoia_check(struct usb_serial *serial,
- const char *function)
-{
- if (!serial) {
- dbg("%s - serial == NULL\n", function);
- return -1;
- }
-
- if (!serial->type) {
- dbg("%s - serial->type == NULL!", function);
- return -1;
- }
-
- return 0;
-}
-
-static inline struct quatech2_port *qt2_get_port_private(struct usb_serial_port
- *port)
-{
- return (struct quatech2_port *)usb_get_serial_port_data(port);
-}
-
-static inline void qt2_set_port_private(struct usb_serial_port *port,
- struct quatech2_port *data)
-{
- usb_set_serial_port_data(port, (void *)data);
-}
-
-static inline struct quatech2_dev *qt2_get_dev_private(struct usb_serial
- *serial)
-{
- return (struct quatech2_dev *)usb_get_serial_data(serial);
-}
-static inline void qt2_set_dev_private(struct usb_serial *serial,
- struct quatech2_dev *data)
-{
- usb_set_serial_data(serial, (void *)data);
-}
-
-static int qt2_openboxchannel(struct usb_serial *serial, __u16
- Uart_Number, struct qt2_status_data *status)
-{
- int result;
- __u16 length;
- __u8 Direcion;
- unsigned int pipe;
- length = sizeof(struct qt2_status_data);
- Direcion = USBD_TRANSFER_DIRECTION_IN;
- pipe = usb_rcvctrlpipe(serial->dev, 0);
- result = usb_control_msg(serial->dev, pipe, QT_OPEN_CLOSE_CHANNEL,
- Direcion, 0x00, Uart_Number, status, length, 5000);
- return result;
-}
-static int qt2_closeboxchannel(struct usb_serial *serial, __u16 Uart_Number)
-{
- int result;
- __u8 direcion;
- unsigned int pipe;
- direcion = USBD_TRANSFER_DIRECTION_OUT;
- pipe = usb_sndctrlpipe(serial->dev, 0);
- result = usb_control_msg(serial->dev, pipe, QT_OPEN_CLOSE_CHANNEL,
- direcion, 0, Uart_Number, NULL, 0, 5000);
- return result;
-}
-
-/* qt2_conf_uart Issue a SET_UART vendor-spcific request on the default
- * control pipe. If successful sets baud rate divisor and LCR value
- */
-static int qt2_conf_uart(struct usb_serial *serial, unsigned short Uart_Number,
- unsigned short divisor, unsigned char LCR)
-{
- int result;
- unsigned short UartNumandLCR;
-
- UartNumandLCR = (LCR << 8) + Uart_Number;
-
- result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- QT2_GET_SET_UART, 0x40, divisor, UartNumandLCR,
- NULL, 0, 300);
- return result;
-}
-
-/** @brief Callback for asynchronous submission of read URBs on bulk in
- * endpoints
- *
- * Registered in qt2_open_port(), used to deal with incomming data
- * from the box.
- */
-static void qt2_read_bulk_callback(struct urb *urb)
-{
- /* Get the device pointer (struct usb_serial) back out of the URB */
- struct usb_serial *serial = urb->context;
- /* get the extra struct for the device */
- struct quatech2_dev *dev_extra = qt2_get_dev_private(serial);
- /* Get first port structure from the device */
- struct usb_serial_port *port0 = serial->port[0];
- /* Get the currently active port structure from serial struct */
- struct usb_serial_port *active = dev_extra->current_port;
- /* get the extra struct for port 0 */
- struct quatech2_port *port0_extra = qt2_get_port_private(port0);
- /* and for the currently active port */
- struct quatech2_port *active_extra = qt2_get_port_private(active);
- /* When we finally get to doing some tty stuff, we will need this */
- struct tty_struct *tty_st;
- unsigned int RxCount; /* the length of the data to process */
- unsigned int i; /* loop counter over the data to process */
- int result; /* return value cache variable */
- bool escapeflag; /* flag set to true if this loop iteration is
- * parsing an escape sequence, rather than
- * ordinary data */
- dbg("%s(): callback running, active port is %d", __func__,
- active->number);
-
- if (urb->status) {
- /* read didn't go well */
- dev_extra->ReadBulkStopped = true;
- dbg("%s(): nonzero bulk read status received: %d",
- __func__, urb->status);
- return;
- }
-
- /* inline port_sofrint() here */
- if (port_paranoia_check(port0, __func__) != 0) {
- dbg("%s - port_paranoia_check on port0 failed, exiting\n",
-__func__);
- return;
- }
- if (port_paranoia_check(active, __func__) != 0) {
- dbg("%s - port_paranoia_check on current_port "
- "failed, exiting", __func__);
- return;
- }
-
-/* This single callback function has to do for all the ports on
- * the device. Data being read up the USB can contain certain
- * escape sequences which are used to communicate out-of-band
- * information from the serial port in-band over the USB.
- * These escapes include sending modem and flow control line
- * status, and switching the port. The concept of a "Current Port"
- * is used, which is where data is going until a port change
- * escape seqence is received. This Current Port is kept between
- * callbacks so that when this function enters we know which the
- * currently active port is and can get to work right away without
- * the box having to send repeat escape sequences (anyway, how
- * would it know to do so?).
- */
-
- if (active_extra->close_pending == true) {
- /* We are closing , stop reading */
- dbg("%s - (active->close_pending == true", __func__);
- if (dev_extra->open_ports <= 0) {
- /* If this is the only port left open - stop the
- * bulk read */
- dev_extra->ReadBulkStopped = true;
- dbg("%s - (ReadBulkStopped == true;", __func__);
- return;
- }
- }
-
- /*
- * RxHolding is asserted by throttle, if we assert it, we're not
- * receiving any more characters and let the box handle the flow
- * control
- */
- if ((port0_extra->RxHolding == true) &&
- (serial->dev->descriptor.idProduct == QUATECH_SSU2_100)) {
- /* single port device, input is already stopped, so we don't
- * need any more input data */
- dev_extra->ReadBulkStopped = true;
- return;
- }
- /* finally, we are in a situation where we might consider the data
- * that is contained within the URB, and what to do about it.
- * This is likely to involved communicating up to the TTY layer, so
- * we will need to get hold of the tty for the port we are currently
- * dealing with */
-
- /* active is a usb_serial_port. It has a member port which is a
- * tty_port. From this we get a tty_struct pointer which is what we
- * actually wanted, and keep it on tty_st */
- tty_st = tty_port_tty_get(&active->port);
- if (!tty_st) {
- dbg("%s - bad tty pointer - exiting", __func__);
- return;
- }
- RxCount = urb->actual_length; /* grab length of data handy */
-
- if (RxCount) {
- /* skip all this if no data to process */
- for (i = 0; i < RxCount ; ++i) {
- /* Look ahead code here -works on several bytes at onc*/
- if ((i <= (RxCount - 3)) && (THISCHAR == 0x1b)
- && (NEXTCHAR == 0x1b)) {
- /* we are in an escape sequence, type
- * determined by the 3rd char */
- escapeflag = false;
- switch (THIRDCHAR) {
- case 0x00:
- /* Line status change 4th byte must
- * follow */
- if (i > (RxCount - 4)) {
- dbg("Illegal escape sequences "
- "in received data");
- break;
- }
- qt2_process_line_status(active,
- FOURTHCHAR);
- i += 3;
- escapeflag = true;
- break;
- case 0x01:
- /* Modem status status change 4th byte
- * must follow */
- if (i > (RxCount - 4)) {
- dbg("Illegal escape sequences "
- "in received data");
- break;
- }
- qt2_process_modem_status(active,
- FOURTHCHAR);
- i += 3;
- escapeflag = true;
- break;
- case 0x02:
- /* xmit hold empty 4th byte
- * must follow */
- if (i > (RxCount - 4)) {
- dbg("Illegal escape sequences "
- "in received data");
- break;
- }
- qt2_process_xmit_empty(active,
- FOURTHCHAR, FIFTHCHAR);
- i += 4;
- escapeflag = true;
- break;
- case 0x03:
- /* Port number change 4th byte
- * must follow */
- if (i > (RxCount - 4)) {
- dbg("Illegal escape sequences "
- "in received data");
- break;
- }
- /* Port change. If port open push
- * current data up to tty layer */
- if (active_extra->open_count > 0)
- tty_flip_buffer_push(tty_st);
-
- dbg("Port Change: new port = %d",
- FOURTHCHAR);
- qt2_process_port_change(active,
- FOURTHCHAR);
- i += 3;
- escapeflag = true;
- /* having changed port, the pointers for
- * the currently active port are all out
- * of date and need updating */
- active = dev_extra->current_port;
- active_extra =
- qt2_get_port_private(active);
- tty_st = tty_port_tty_get(
- &active->port);
- break;
- case 0x04:
- /* Recv flush 3rd byte must
- * follow */
- if (i > (RxCount - 3)) {
- dbg("Illegal escape sequences "
- "in received data");
- break;
- }
- qt2_process_rcv_flush(active);
- i += 2;
- escapeflag = true;
- break;
- case 0x05:
- /* xmit flush 3rd byte must follow */
- if (i > (RxCount - 3)) {
- dbg("Illegal escape sequences "
- "in received data");
- break;
- }
- qt2_process_xmit_flush(active);
- i += 2;
- escapeflag = true;
- break;
- case 0xff:
- dbg("No status sequence");
- qt2_process_rx_char(active, THISCHAR);
- qt2_process_rx_char(active, NEXTCHAR);
- i += 2;
- break;
- default:
- qt2_process_rx_char(active, THISCHAR);
- i += 1;
- break;
- } /*end switch*/
- if (escapeflag == true)
- continue;
- /* if we did an escape char, we don't need
- * to mess around pushing data through the
- * tty layer, and can go round again */
- } /*endif*/
- if (tty_st && urb->actual_length) {
- tty_buffer_request_room(tty_st, 1);
- tty_insert_flip_string(tty_st, &(
- (unsigned char *)
- (urb->transfer_buffer)
- )[i], 1);
- }
- } /*endfor*/
- tty_flip_buffer_push(tty_st);
- } /*endif*/
-
- /* at this point we have complete dealing with the data for this
- * callback. All we have to do now is to start the async read process
- * back off again. */
-
- usb_fill_bulk_urb(port0->read_urb, serial->dev,
- usb_rcvbulkpipe(serial->dev, port0->bulk_in_endpointAddress),
- port0->bulk_in_buffer, port0->bulk_in_size,
- qt2_read_bulk_callback, serial);
- result = usb_submit_urb(port0->read_urb, GFP_ATOMIC);
- if (result) {
- dbg("%s(): failed resubmitting read urb, error %d",
- __func__, result);
- } else {
- dbg("%s() successfully resubmitted read urb", __func__);
- if (tty_st && RxCount) {
- /* if some inbound data was processed, then
- * we need to push that through the tty layer
- */
- tty_flip_buffer_push(tty_st);
- tty_schedule_flip(tty_st);
- }
- }
-
- /* cribbed from serqt_usb2 driver, but not sure which work needs
- * scheduling - port0 or currently active port? */
- /* schedule_work(&port->work); */
- dbg("%s() completed", __func__);
- return;
-}
-
-/** @brief Callback for asynchronous submission of write URBs on bulk in
- * endpoints
- *
- * Registered in qt2_write(), used to deal with outgoing data
- * to the box.
- */
-static void qt2_write_bulk_callback(struct urb *urb)
-{
- struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
- struct usb_serial *serial = port->serial;
- dbg("%s(): port %d", __func__, port->number);
- if (!serial) {
- dbg("%s(): bad serial pointer, exiting", __func__);
- return;
- }
- if (urb->status) {
- dbg("%s(): nonzero write bulk status received: %d",
- __func__, urb->status);
- return;
- }
- /* FIXME What is supposed to be going on here?
- * does this actually do anything useful, and should it?
- */
- /*port_softint((void *) serial); commented in vendor driver */
- schedule_work(&port->work);
- dbg("%s(): port %d exit", __func__, port->number);
- return;
-}
-
-static void qt2_process_line_status(struct usb_serial_port *port,
- unsigned char LineStatus)
-{
- /* obtain the private structure for the port */
- struct quatech2_port *port_extra = qt2_get_port_private(port);
- port_extra->shadowLSR = LineStatus & (QT2_SERIAL_LSR_OE |
- QT2_SERIAL_LSR_PE | QT2_SERIAL_LSR_FE | QT2_SERIAL_LSR_BI);
-}
-static void qt2_process_modem_status(struct usb_serial_port *port,
- unsigned char ModemStatus)
-{
- /* obtain the private structure for the port */
- struct quatech2_port *port_extra = qt2_get_port_private(port);
- port_extra->shadowMSR = ModemStatus;
- wake_up_interruptible(&port_extra->wait);
- /* this wakes up the otherwise indefinitely waiting code for
- * the TIOCMIWAIT ioctl, so that it can notice that
- * port_extra->shadowMSR has changed and the ioctl needs to return.
- */
-}
-
-static void qt2_process_xmit_empty(struct usb_serial_port *port,
- unsigned char fourth_char, unsigned char fifth_char)
-{
- int byte_count;
- /* obtain the private structure for the port */
- struct quatech2_port *port_extra = qt2_get_port_private(port);
-
- byte_count = (int)(fifth_char * 16);
- byte_count += (int)fourth_char;
- /* byte_count indicates how many bytes the device has written out. This
- * message appears to occur regularly, and is used in the vendor driver
- * to keep track of the fill state of the port transmit buffer */
- port_extra->tx_pending_bytes -= byte_count;
- /* reduce the stored data queue length by the known number of bytes
- * sent */
- dbg("port %d: %d bytes reported sent, %d still pending", port->number,
- byte_count, port_extra->tx_pending_bytes);
-
- /*port_extra->xmit_fifo_room_bytes = FIFO_DEPTH; ???*/
-}
-
-static void qt2_process_port_change(struct usb_serial_port *port,
- unsigned char New_Current_Port)
-{
- /* obtain the parent usb serial device structure */
- struct usb_serial *serial = port->serial;
- /* obtain the private structure for the device */
- struct quatech2_dev *dev_extra = qt2_get_dev_private(serial);
- dev_extra->current_port = serial->port[New_Current_Port];
- /* what should I do with this? commented out in upstream
- * driver */
- /*schedule_work(&port->work);*/
-}
-
-static void qt2_process_rcv_flush(struct usb_serial_port *port)
-{
- /* obtain the private structure for the port */
- struct quatech2_port *port_extra = qt2_get_port_private(port);
- port_extra->rcv_flush = true;
-}
-static void qt2_process_xmit_flush(struct usb_serial_port *port)
-{
- /* obtain the private structure for the port */
- struct quatech2_port *port_extra = qt2_get_port_private(port);
- port_extra->xmit_flush = true;
-}
-
-static void qt2_process_rx_char(struct usb_serial_port *port,
- unsigned char data)
-{
- /* get the tty_struct for this port */
- struct tty_struct *tty = tty_port_tty_get(&(port->port));
- /* get the URB with the data in to push */
- struct urb *urb = port->serial->port[0]->read_urb;
-
- if (tty && urb->actual_length) {
- tty_buffer_request_room(tty, 1);
- tty_insert_flip_string(tty, &data, 1);
- /* should this be commented out here? */
- /*tty_flip_buffer_push(tty);*/
- }
-}
-
-/** @brief Retrieve the value of a register from the device
- *
- * Issues a GET_REGISTER vendor-spcific request over the USB control
- * pipe to obtain a value back from a specific register on a specific
- * UART
- * @param serial Serial device handle to access the device through
- * @param uart_number Which UART the value is wanted from
- * @param register_num Which register to read the value from
- * @param pValue Pointer to somewhere to put the retrieved value
- */
-static int qt2_box_get_register(struct usb_serial *serial,
- unsigned char uart_number, unsigned short register_num,
- __u8 *pValue)
-{
- int result;
- result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
- QT2_GET_SET_REGISTER, 0xC0, register_num,
- uart_number, (void *)pValue, sizeof(*pValue), 300);
- return result;
-}
-
-/** qt2_box_set_register
- * Issue a SET_REGISTER vendor-specific request on the default control pipe
- */
-static int qt2_box_set_register(struct usb_serial *serial,
- unsigned short Uart_Number, unsigned short Register_Num,
- unsigned short Value)
-{
- int result;
- unsigned short reg_and_byte;
-
- reg_and_byte = Value;
- reg_and_byte = reg_and_byte << 8;
- reg_and_byte = reg_and_byte + Register_Num;
-
- result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- QT2_GET_SET_REGISTER, 0x40, reg_and_byte,
- Uart_Number, NULL, 0, 300);
- return result;
-}
-
-/** qt2_boxsetuart - Issue a SET_UART vendor-spcific request on the default
- * control pipe. If successful sets baud rate divisor and LCR value.
- */
-static int qt2_boxsetuart(struct usb_serial *serial, unsigned short Uart_Number,
- unsigned short default_divisor, unsigned char default_LCR)
-{
- unsigned short UartNumandLCR;
-
- UartNumandLCR = (default_LCR << 8) + Uart_Number;
-
- return usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- QT2_GET_SET_UART, 0x40, default_divisor, UartNumandLCR,
- NULL, 0, 300);
-}
-
-/** qt2_boxsethw_flowctl - Turn hardware (RTS/CTS) flow control on and off for
- * a hardware UART.
- */
-static int qt2_boxsethw_flowctl(struct usb_serial *serial,
- unsigned int UartNumber, bool bSet)
-{
- __u8 MCR_Value = 0;
- __u8 MSR_Value = 0;
- __u16 MOUT_Value = 0;
-
- if (bSet == true) {
- MCR_Value = QT2_SERIAL_MCR_RTS;
- /* flow control, box will clear RTS line to prevent remote
- * device from transmitting more chars */
- } else {
- /* no flow control to remote device */
- MCR_Value = 0;
- }
- MOUT_Value = MCR_Value << 8;
-
- if (bSet == true) {
- MSR_Value = QT2_SERIAL_MSR_CTS;
- /* flow control on, box will inhibit tx data if CTS line is
- * asserted */
- } else {
- /* Box will not inhibit tx data due to CTS line */
- MSR_Value = 0;
- }
- MOUT_Value |= MSR_Value;
- return usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- QT2_HW_FLOW_CONTROL_MASK, 0x40, MOUT_Value, UartNumber,
- NULL, 0, 300);
-}
-
-/** qt2_boxsetsw_flowctl - Turn software (XON/XOFF) flow control on for
- * a hardware UART, and set the XON and XOFF characters.
- */
-static int qt2_boxsetsw_flowctl(struct usb_serial *serial, __u16 UartNumber,
- unsigned char stop_char, unsigned char start_char)
-{
- __u16 nSWflowout;
-
- nSWflowout = start_char << 8;
- nSWflowout = (unsigned short)stop_char;
- return usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- QT2_SW_FLOW_CONTROL_MASK, 0x40, nSWflowout, UartNumber,
- NULL, 0, 300);
-}
-
-/** qt2_boxunsetsw_flowctl - Turn software (XON/XOFF) flow control off for
- * a hardware UART.
- */
-static int qt2_boxunsetsw_flowctl(struct usb_serial *serial, __u16 UartNumber)
-{
- return usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- QT2_SW_FLOW_CONTROL_DISABLE, 0x40, 0, UartNumber, NULL,
- 0, 300);
-}
-
-/**
- * qt2_boxstoprx - Start and stop reception of data by the FPGA UART in
- * response to requests from the tty layer
- * @serial: pointer to the usb_serial structure for the parent device
- * @uart_number: which UART on the device we are addressing
- * @stop: Whether to start or stop data reception. Set to 1 to stop data being
- * received, and to 0 to start it being received.
- */
-static int qt2_boxstoprx(struct usb_serial *serial, unsigned short uart_number,
- unsigned short stop)
-{
- return usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- QT2_STOP_RECEIVE, 0x40, stop, uart_number, NULL, 0, 300);
-}
-
-
-/*
- * last things in file: stuff to register this driver into the generic
- * USB serial framework.
- */
-
-static struct usb_serial_driver quatech2_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "quatech_usb2",
- },
- .description = DRIVER_DESC,
- .id_table = quausb2_id_table,
- .num_ports = 8,
- .open = qt2_open,
- .close = qt2_close,
- .write = qt2_write,
- .write_room = qt2_write_room,
- .chars_in_buffer = qt2_chars_in_buffer,
- .throttle = qt2_throttle,
- .unthrottle = qt2_unthrottle,
- .calc_num_ports = qt2_calc_num_ports,
- .ioctl = qt2_ioctl,
- .set_termios = qt2_set_termios,
- .break_ctl = qt2_break,
- .tiocmget = qt2_tiocmget,
- .tiocmset = qt2_tiocmset,
- .attach = qt2_attach,
- .release = qt2_release,
- .read_bulk_callback = qt2_read_bulk_callback,
- .write_bulk_callback = qt2_write_bulk_callback,
-};
-
-static struct usb_serial_driver * const serial_drivers[] = {
- &quatech2_device, NULL
-};
-
-module_usb_serial_driver(quausb2_usb_driver, serial_drivers);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/staging/ramster/Kconfig b/drivers/staging/ramster/Kconfig
index 4af1f8d4b953..8349887827dc 100644
--- a/drivers/staging/ramster/Kconfig
+++ b/drivers/staging/ramster/Kconfig
@@ -1,6 +1,6 @@
config RAMSTER
bool "Cross-machine RAM capacity sharing, aka peer-to-peer tmem"
- depends on (CLEANCACHE || FRONTSWAP) && CONFIGFS_FS=y && !ZCACHE && !XVMALLOC && !HIGHMEM
+ depends on (CLEANCACHE || FRONTSWAP) && CONFIGFS_FS=y && !ZCACHE && !XVMALLOC && !HIGHMEM && NET
select LZO_COMPRESS
select LZO_DECOMPRESS
default n
diff --git a/drivers/staging/ramster/cluster/tcp.c b/drivers/staging/ramster/cluster/tcp.c
index b9721c1055b1..d0a07d722b61 100644
--- a/drivers/staging/ramster/cluster/tcp.c
+++ b/drivers/staging/ramster/cluster/tcp.c
@@ -111,7 +111,7 @@ static struct socket *r2net_listen_sock;
* r2net_wq. teardown detaches the callbacks before destroying the workqueue.
* quorum work is queued as sock containers are shutdown.. stop_listening
* tears down all the node's sock containers, preventing future shutdowns
- * and queued quroum work, before canceling delayed quorum work and
+ * and queued quorum work, before canceling delayed quorum work and
* destroying the work queue.
*/
static struct workqueue_struct *r2net_wq;
@@ -660,7 +660,7 @@ out:
/*
* we register callbacks so we can queue work on events before calling
- * the original callbacks. our callbacks our careful to test user_data
+ * the original callbacks. our callbacks are careful to test user_data
* to discover when they've reaced with r2net_unregister_callbacks().
*/
static void r2net_register_callbacks(struct sock *sk,
diff --git a/drivers/staging/ramster/xvmalloc.c b/drivers/staging/ramster/xvmalloc.c
index 93ba8e9407aa..44ceb0b823a9 100644
--- a/drivers/staging/ramster/xvmalloc.c
+++ b/drivers/staging/ramster/xvmalloc.c
@@ -132,7 +132,7 @@ static u32 find_block(struct xv_pool *pool, u32 size,
if (!pool->flbitmap)
return 0;
- /* Get freelist index correspoding to this size */
+ /* Get freelist index corresponding to this size */
slindex = get_index(size);
slbitmap = pool->slbitmap[slindex / BITS_PER_LONG];
slbitstart = slindex % BITS_PER_LONG;
diff --git a/drivers/staging/ramster/zcache-main.c b/drivers/staging/ramster/zcache-main.c
index 68b2e053a0e6..4e7ef0e6b79c 100644
--- a/drivers/staging/ramster/zcache-main.c
+++ b/drivers/staging/ramster/zcache-main.c
@@ -1331,7 +1331,7 @@ static ssize_t zv_max_mean_zsize_store(struct kobject *kobj,
* when that limit is reached, further puts will be rejected (until
* some pages have been flushed). Note that, due to compression,
* this number may exceed 100; it defaults to 75 and we set an
- * arbitary limit of 150. A poor choice will almost certainly result
+ * arbitrary limit of 150. A poor choice will almost certainly result
* in OOM's, so this value should only be changed prudently.
*/
static ssize_t zv_page_count_policy_percent_show(struct kobject *kobj,
@@ -2004,7 +2004,7 @@ int zcache_pampd_replace_in_obj(void *new_pampd, struct tmem_obj *obj)
* Called by the message handler after a (still compressed) page has been
* fetched from the remote machine in response to an "is_remote" tmem_get
* or persistent tmem_localify. For a tmem_get, "extra" is the address of
- * the page that is to be filled to succesfully resolve the tmem_get; for
+ * the page that is to be filled to successfully resolve the tmem_get; for
* a (persistent) tmem_localify, "extra" is NULL (as the data is placed only
* in the local zcache). "data" points to "size" bytes of (compressed) data
* passed in the message. In the case of a persistent remote get, if
@@ -2095,7 +2095,7 @@ out:
/*
* Called on a remote persistent tmem_get to attempt to preallocate
* local storage for the data contained in the remote persistent page.
- * If succesfully preallocated, returns the pampd, marked as remote and
+ * If successfully preallocated, returns the pampd, marked as remote and
* in_transit. Else returns NULL. Note that the appropriate tmem data
* structure must be locked.
*/
diff --git a/drivers/staging/rtl8187se/Makefile b/drivers/staging/rtl8187se/Makefile
index 72db504b23b4..91d1aa2830c9 100644
--- a/drivers/staging/rtl8187se/Makefile
+++ b/drivers/staging/rtl8187se/Makefile
@@ -10,7 +10,7 @@ ccflags-y += -DHIGH_POWER
ccflags-y += -DSW_DIG
ccflags-y += -DRATE_ADAPT
-#enable it for legacy power save, disable it for leisure power save
+#enable it for legacy power save, disable it for leisure power save
ccflags-y += -DENABLE_LPS
diff --git a/drivers/staging/rtl8187se/ieee80211/dot11d.c b/drivers/staging/rtl8187se/ieee80211/dot11d.c
index 309bb8bf287e..0e93eb0735a7 100644
--- a/drivers/staging/rtl8187se/ieee80211/dot11d.c
+++ b/drivers/staging/rtl8187se/ieee80211/dot11d.c
@@ -55,7 +55,7 @@ Dot11d_Reset(struct ieee80211_device *ieee)
//
// Description:
-// Update country IE from Beacon or Probe Resopnse
+// Update country IE from Beacon or Probe Response
// and configure PHY for operation in the regulatory domain.
//
// TODO:
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211.h b/drivers/staging/rtl8187se/ieee80211/ieee80211.h
index 40dd715d9df7..b94c48b29302 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211.h
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211.h
@@ -834,7 +834,7 @@ enum ieee80211_state {
/* the association procedure is sending AUTH request*/
IEEE80211_ASSOCIATING_AUTHENTICATING,
- /* the association procedure has successfully authentcated
+ /* the association procedure has successfully authenticated
* and is sending association request
*/
IEEE80211_ASSOCIATING_AUTHENTICATED,
@@ -934,7 +934,7 @@ struct ieee80211_device {
* with RX of broad/multicast frames */
/* Fragmentation structures */
- // each streaming contain a entry
+ /* each stream contains an entry */
struct ieee80211_frag_entry frag_cache[17][IEEE80211_FRAG_CACHE_LEN];
unsigned int frag_next_idx[17];
u16 fts; /* Fragmentation Threshold */
@@ -972,7 +972,7 @@ struct ieee80211_device {
int rate; /* current rate */
int basic_rate;
- //FIXME: pleace callback, see if redundant with softmac_features
+ //FIXME: please callback, see if redundant with softmac_features
short active_scan;
/* this contains flags for selectively enable softmac support */
@@ -1106,7 +1106,7 @@ struct ieee80211_device {
/* used instead of hard_start_xmit (not softmac_hard_start_xmit)
* if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data
- * frames. I the option IEEE_SOFTMAC_SINGLE_QUEUE is also set
+ * frames. If the option IEEE_SOFTMAC_SINGLE_QUEUE is also set
* then also management frames are sent via this callback.
* This function can't sleep.
*/
@@ -1124,7 +1124,7 @@ struct ieee80211_device {
/* ask to the driver to retune the radio .
* This function can sleep. the driver should ensure
- * the radio has been swithced before return.
+ * the radio has been switched before return.
*/
void (*set_chan)(struct net_device *dev,short ch);
@@ -1135,7 +1135,7 @@ struct ieee80211_device {
* The syncro version is similar to the start_scan but
* does not return until all channels has been scanned.
* this is called in user context and should sleep,
- * it is called in a work_queue when swithcing to ad-hoc mode
+ * it is called in a work_queue when switching to ad-hoc mode
* or in behalf of iwlist scan when the card is associated
* and root user ask for a scan.
* the function stop_scan should stop both the syncro and
@@ -1196,7 +1196,7 @@ struct ieee80211_device {
/* Generate probe requests */
#define IEEE_SOFTMAC_PROBERQ (1<<4)
-/* Generate respones to probe requests */
+/* Generate response to probe requests */
#define IEEE_SOFTMAC_PROBERS (1<<5)
/* The ieee802.11 stack will manages the netif queue
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
index 26bacb96d247..8173240dcf7a 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c
@@ -42,7 +42,7 @@ short ieee80211_is_shortslot(const struct ieee80211_network *net)
return net->capability & WLAN_CAPABILITY_SHORT_SLOT;
}
-/* returns the total length needed for pleacing the RATE MFIE
+/* returns the total length needed for placing the RATE MFIE
* tag and the EXTENDED RATE MFIE tag if needed.
* It encludes two bytes per tag for the tag itself and its len
*/
@@ -60,7 +60,7 @@ unsigned int ieee80211_MFIE_rate_len(struct ieee80211_device *ieee)
return rate_len;
}
-/* pleace the MFIE rate, tag to the memory (double) poined.
+/* place the MFIE rate, tag to the memory (double) poised.
* Then it updates the pointer so that
* it points after the new MFIE tag added.
*/
@@ -467,7 +467,7 @@ void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee)
* So we switch to IEEE80211_LINKED_SCANNING to remember
* that we are still logically linked (not interested in
* new network events, despite for updating the net list,
- * but we are temporarly 'unlinked' as the driver shall
+ * but we are temporarily 'unlinked' as the driver shall
* not filter RX frames and the channel is changing.
* So the only situation in witch are interested is to check
* if the state become LINKED because of the #1 situation
@@ -530,7 +530,7 @@ void ieee80211_softmac_ips_scan_syncro(struct ieee80211_device *ieee)
* So we switch to IEEE80211_LINKED_SCANNING to remember
* that we are still logically linked (not interested in
* new network events, despite for updating the net list,
- * but we are temporarly 'unlinked' as the driver shall
+ * but we are temporarily 'unlinked' as the driver shall
* not filter RX frames and the channel is changing.
* So the only situation in witch are interested is to check
* if the state become LINKED because of the #1 situation
@@ -1140,7 +1140,7 @@ void ieee80211_associate_abort(struct ieee80211_device *ieee)
ieee->associate_seq++;
- /* don't scan, and avoid to have the RX path possibily
+ /* don't scan, and avoid to have the RX path possibly
* try again to associate. Even do not react to AUTH or
* ASSOC response. Just wait for the retry wq to be scheduled.
* Here we will check if there are good nets to associate
@@ -1346,14 +1346,14 @@ inline void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee
//printk("apset=%d apmatch=%d ssidset=%d ssidbroad=%d ssidmatch=%d\n",apset,apmatch,ssidset,ssidbroad,ssidmatch);
if ( /* if the user set the AP check if match.
- * if the network does not broadcast essid we check the user supplyed ANY essid
+ * if the network does not broadcast essid we check the user supplied ANY essid
* if the network does broadcast and the user does not set essid it is OK
* if the network does broadcast and the user did set essid chech if essid match
*/
( apset && apmatch &&
((ssidset && ssidbroad && ssidmatch) || (ssidbroad && !ssidset) || (!ssidbroad && ssidset)) ) ||
/* if the ap is not set, check that the user set the bssid
- * and the network does bradcast and that those two bssid matches
+ * and the network does broadcast and that those two bssid matches
*/
(!apset && ssidset && ssidbroad && ssidmatch)
){
@@ -1821,7 +1821,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
while (left >= sizeof(struct ieee80211_info_element_hdr)) {
if (sizeof(struct ieee80211_info_element_hdr) + info_element->len > left) {
- printk(KERN_WARNING "[re]associate reeponse error!");
+ printk(KERN_WARNING "[re]associate response error!");
return 1;
}
switch (info_element->id) {
@@ -1905,7 +1905,7 @@ associate_complete:
}
}else{
ieee->softmac_stats.rx_auth_rs_err++;
- IEEE80211_DEBUG_MGMT("Authentication respose status code 0x%x",errcode);
+ IEEE80211_DEBUG_MGMT("Authentication response status code 0x%x",errcode);
ieee80211_associate_abort(ieee);
}
@@ -2184,15 +2184,15 @@ void ieee80211_start_ibss_wq(struct work_struct *work)
if(ieee->state == IEEE80211_NOLINK)
ieee->current_network.channel = 10;
- /* if not then the state is not linked. Maybe the user swithced to
+ /* if not then the state is not linked. Maybe the user switched to
* ad-hoc mode just after being in monitor mode, or just after
* being very few time in managed mode (so the card have had no
* time to scan all the chans..) or we have just run up the iface
* after setting ad-hoc mode. So we have to give another try..
* Here, in ibss mode, should be safe to do this without extra care
- * (in bss mode we had to make sure no-one tryed to associate when
+ * (in bss mode we had to make sure no-one tried to associate when
* we had just checked the ieee->state and we was going to start the
- * scan) beacause in ibss mode the ieee80211_new_net function, when
+ * scan) because in ibss mode the ieee80211_new_net function, when
* finds a good net, just set the ieee->state to IEEE80211_LINKED,
* so, at worst, we waste a bit of time to initiate an unneeded syncro
* scan, that will stop at the first round because it sees the state
@@ -2342,7 +2342,7 @@ void ieee80211_associate_retry_wq(struct work_struct *work)
goto exit;
/* until we do not set the state to IEEE80211_NOLINK
* there are no possibility to have someone else trying
- * to start an association procdure (we get here with
+ * to start an association procedure (we get here with
* ieee->state = IEEE80211_ASSOCIATING).
* When we set the state to IEEE80211_NOLINK it is possible
* that the RX path run an attempt to associate, but
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
index e46ff2ffa09b..5d204906baf7 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c
@@ -362,7 +362,7 @@ int ieee80211_wx_set_essid(struct ieee80211_device *ieee,
ieee80211_stop_protocol(ieee);
/* this is just to be sure that the GET wx callback
- * has consisten infos. not needed otherwise
+ * has consistent infos. not needed otherwise
*/
spin_lock_irqsave(&ieee->lock, flags);
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
index 552115cd760e..89ed86ef0d15 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c
@@ -328,7 +328,7 @@ int ieee80211_rtl_xmit(struct sk_buff *skb,
//printk(KERN_WARNING "upper layer packet!\n");
spin_lock_irqsave(&ieee->lock, flags);
- /* If there is no driver handler to take the TXB, dont' bother
+ /* If there is no driver handler to take the TXB, don't bother
* creating it... */
if ((!ieee->hard_start_xmit && !(ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE))||
((!ieee->softmac_data_hard_start_xmit && (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)))) {
@@ -413,10 +413,7 @@ int ieee80211_rtl_xmit(struct sk_buff *skb,
/* Determine fragmentation size based on destination (multicast
* and broadcast are not fragmented) */
-// if (is_multicast_ether_addr(dest) ||
-// is_broadcast_ether_addr(dest)) {
- if (is_multicast_ether_addr(header.addr1) ||
- is_broadcast_ether_addr(header.addr1)) {
+ if (is_multicast_ether_addr(header.addr1)) {
frag_size = MAX_FRAG_THRESHOLD;
qos_ctl = QOS_CTL_NOTCONTAIN_ACK;
}
diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c
index ca414a915a4e..c7917b24425c 100644
--- a/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c
+++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c
@@ -363,7 +363,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
(*crypt)->priv);
sec.flags |= (1 << key);
/* This ensures a key will be activated if no key is
- * explicitely set */
+ * explicitly set */
if (key == sec.active_key)
sec.flags |= SEC_ACTIVE_KEY;
ieee->tx_keyidx = key;//by wb 080312
diff --git a/drivers/staging/rtl8187se/r8180.h b/drivers/staging/rtl8187se/r8180.h
index a2c46ae4a400..2682afbac4ff 100644
--- a/drivers/staging/rtl8187se/r8180.h
+++ b/drivers/staging/rtl8187se/r8180.h
@@ -11,7 +11,7 @@
Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
- We want to tanks the Authors of those projects and the Ndiswrapper
+ We want to thanks the Authors of those projects and the Ndiswrapper
project Authors.
*/
@@ -514,12 +514,12 @@ typedef struct r8180_priv
bool bDefaultAntenna1;
u8 SignalStrength;
long Stats_SignalStrength;
- long LastSignalStrengthInPercent; // In percentange, used for smoothing, e.g. Moving Average.
+ long LastSignalStrengthInPercent; // In percentage, used for smoothing, e.g. Moving Average.
u8 SignalQuality; // in 0-100 index.
long Stats_SignalQuality;
long RecvSignalPower; // in dBm.
long Stats_RecvSignalPower;
- u8 LastRxPktAntenna; // +by amy 080312 Antenn which received the lasted packet. 0: Aux, 1:Main. Added by Roger, 2008.01.25.
+ u8 LastRxPktAntenna; // +by amy 080312 Antenna which received the lasted packet. 0: Aux, 1:Main. Added by Roger, 2008.01.25.
u32 AdRxOkCnt;
long AdRxSignalStrength;
u8 CurrAntennaIndex; // Index to current Antenna (both Tx and Rx).
@@ -530,7 +530,7 @@ typedef struct r8180_priv
long AdRxSsThreshold; // Signal strength threshold to switch antenna.
long AdMaxRxSsThreshold; // Max value of AdRxSsThreshold.
bool bAdSwitchedChecking; // TRUE if we shall shall check Rx signal strength for last time switching antenna.
- long AdRxSsBeforeSwitched; // Rx signal strength before we swithed antenna.
+ long AdRxSsBeforeSwitched; // Rx signal strength before we switched antenna.
struct timer_list SwAntennaDiversityTimer;
//by amy for antenna
//{by amy 080312
@@ -553,7 +553,7 @@ typedef struct r8180_priv
bool bDigMechanism; // TRUE if DIG is enabled, FALSE ow.
bool bRegHighPowerMechanism; // For High Power Mechanism. 061010, by rcnjko.
u32 FalseAlarmRegValue;
- u8 RegDigOfdmFaUpTh; // Upper threhold of OFDM false alarm, which is used in DIG.
+ u8 RegDigOfdmFaUpTh; // Upper threshold of OFDM false alarm, which is used in DIG.
u8 DIG_NumberFallbackVote;
u8 DIG_NumberUpgradeVote;
// For HW antenna diversity, added by Roger, 2008.01.30.
diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c
index 4fe52f6b0034..fd22b75aea4f 100644
--- a/drivers/staging/rtl8187se/r8180_core.c
+++ b/drivers/staging/rtl8187se/r8180_core.c
@@ -1329,7 +1329,7 @@ u16 N_DBPSOfRate(u16 DataRate)
}
/*
- * For Netgear case, they want good-looking singal strength.
+ * For Netgear case, they want good-looking signal strength.
*/
long NetgearSignalStrengthTranslate(long LastSS, long CurrSS)
{
@@ -1380,7 +1380,7 @@ long TranslateToDbm8185(u8 SignalStrengthIndex)
/*
* Perform signal smoothing for dynamic mechanism.
- * This is different with PerformSignalSmoothing8185 in smoothing fomula.
+ * This is different with PerformSignalSmoothing8185 in smoothing formula.
* No dramatic adjustion is apply because dynamic mechanism need some degree
* of correctness. Ported from 8187B.
*/
@@ -1535,7 +1535,7 @@ void rtl8180_rx(struct net_device *dev)
/* HW is probably passing several buggy frames
* without FD or LD flag set.
* Throw this garbage away to prevent skb
- * memory exausting
+ * memory exhausting
*/
if (!priv->rx_skb_complete)
dev_kfree_skb_any(priv->rx_skb);
@@ -1648,14 +1648,14 @@ void rtl8180_rx(struct net_device *dev)
priv->Stats_SignalQuality = (long)(priv->Stats_SignalQuality * 5 + (long)priv->SignalQuality + 5) / 6;
priv->Stats_RecvSignalPower = (long)(priv->Stats_RecvSignalPower * 5 + priv->RecvSignalPower - 1) / 6;
- /* Figure out which antenna that received the lasted packet. */
+ /* Figure out which antenna that received the last packet. */
priv->LastRxPktAntenna = Antenna ? 1 : 0; /* 0: aux, 1: main. */
SwAntennaDiversityRxOk8185(dev, priv->SignalStrength);
}
if (first) {
if (!priv->rx_skb_complete) {
- /* seems that HW sometimes fails to reiceve and
+ /* seems that HW sometimes fails to receive and
doesn't provide the last descriptor */
dev_kfree_skb_any(priv->rx_skb);
priv->stats.rxnolast++;
@@ -1672,7 +1672,7 @@ void rtl8180_rx(struct net_device *dev)
priv->rx_skb_complete = 0;
priv->rx_skb->dev = dev;
} else {
- /* if we are here we should have already RXed
+ /* if we are here we should have already RXed
* the first frame.
* If we get here and the skb is not allocated then
* we have just throw out garbage (skb not allocated)
@@ -1821,15 +1821,15 @@ rate) {
/*
* This is a rough attempt to TX a frame
* This is called by the ieee 80211 stack to TX management frames.
- * If the ring is full packet are dropped (for data frame the queue
+ * If the ring is full packets are dropped (for data frame the queue
* is stopped before this can happen). For this reason it is better
* if the descriptors are larger than the largest management frame
- * we intend to TX: i'm unsure what the HW does if it will not found
+ * we intend to TX: i'm unsure what the HW does if it will not find
* the last fragment of a frame because it has been dropped...
* Since queues for Management and Data frames are different we
* might use a different lock than tx_lock (for example mgmt_tx_lock)
*/
-/* these function may loops if invoked with 0 descriptors or 0 len buffer */
+/* these function may loop if invoked with 0 descriptors or 0 len buffer */
int rtl8180_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
@@ -2003,8 +2003,7 @@ short rtl8180_tx(struct net_device *dev, u8* txbuf, int len, int priority,
}
memcpy(&dest, frag_hdr->addr1, ETH_ALEN);
- if (is_multicast_ether_addr(dest) ||
- is_broadcast_ether_addr(dest)) {
+ if (is_multicast_ether_addr(dest)) {
Duration = 0;
RtsDur = 0;
bRTSEnable = 0;
@@ -2378,7 +2377,7 @@ void rtl8180_wmm_param_update(struct work_struct *work)
u8 u1bAIFS;
u32 u4bAcParam;
pAcParam = (PAC_PARAM)(&AcParam);
- /* Retrive paramters to udpate. */
+ /* Retrieve paramters to update. */
u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime;
u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit))<<AC_PARAM_TXOP_LIMIT_OFFSET)|
(((u32)(pAcParam->f.Ecw.f.ECWmax))<<AC_PARAM_ECW_MAX_OFFSET)|
@@ -2414,7 +2413,7 @@ void rtl8180_wmm_param_update(struct work_struct *work)
u8 u1bAIFS;
u32 u4bAcParam;
- /* Retrive paramters to udpate. */
+ /* Retrieve paramters to update. */
eACI = pAcParam->f.AciAifsn.f.ACI;
/* Mode G/A: slotTimeTimer = 9; Mode B: 20 */
u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime;
@@ -2700,7 +2699,7 @@ short rtl8180_init(struct net_device *dev)
priv->bTxPowerTrack = false;
priv->ThermalMeter = 0;
priv->FalseAlarmRegValue = 0;
- priv->RegDigOfdmFaUpTh = 0xc; /* Upper threhold of OFDM false alarm, which is used in DIG. */
+ priv->RegDigOfdmFaUpTh = 0xc; /* Upper threshold of OFDM false alarm, which is used in DIG. */
priv->DIG_NumberFallbackVote = 0;
priv->DIG_NumberUpgradeVote = 0;
priv->LastSignalStrengthInPercent = 0;
@@ -2896,7 +2895,7 @@ short rtl8180_init(struct net_device *dev)
priv->chtxpwr_ofdm[i+1] = (word & 0xff00) >> 8;
}
- /* 3Read crystal calibtration and thermal meter indication on 87SE. */
+ /* 3Read crystal calibration and thermal meter indication on 87SE. */
eeprom_93cx6_read(&eeprom, EEPROM_RSV>>1, &tmpu16);
/* Crystal calibration for Xin and Xout resp. */
@@ -3140,7 +3139,7 @@ void rtl8180_adapter_start(struct net_device *dev)
/*
* The following is very strange. seems to be that 1 means test mode,
- * but we need to acknolwledges the nic when a packet is ready
+ * but we need to acknowledges the nic when a packet is ready
* although we set it to 0
*/
@@ -3971,7 +3970,7 @@ irqreturn_t rtl8180_interrupt(int irq, void *netdev, struct pt_regs *regs)
}
if (inta == 0xffff) {
- /* HW disappared */
+ /* HW disappeared */
spin_unlock_irqrestore(&priv->irq_th_lock, flags);
return IRQ_HANDLED;
}
diff --git a/drivers/staging/rtl8187se/r8180_dm.c b/drivers/staging/rtl8187se/r8180_dm.c
index 4d7a5951486e..b8f2ba010a04 100644
--- a/drivers/staging/rtl8187se/r8180_dm.c
+++ b/drivers/staging/rtl8187se/r8180_dm.c
@@ -2,7 +2,7 @@
#include "r8180_hw.h"
#include "r8180_93cx6.h"
- /* Return TRUE if we shall perform High Power Mecahnism, FALSE otherwise. */
+ /* Return TRUE if we shall perform High Power Mechanism, FALSE otherwise. */
#define RATE_ADAPTIVE_TIMER_PERIOD 300
bool CheckHighPower(struct net_device *dev)
@@ -105,7 +105,7 @@ void rtl8180_tx_pw_wq(struct work_struct *work)
/*
- * Return TRUE if we shall perform DIG Mecahnism, FALSE otherwise.
+ * Return TRUE if we shall perform DIG Mechanism, FALSE otherwise.
*/
bool CheckDig(struct net_device *dev)
{
@@ -507,7 +507,7 @@ void StaRateAdaptive87SE(struct net_device *dev)
* and retry rate.
* (3) Remove all Initial Gain Updates over OFDM rate. To avoid the complicated
* situation, Initial Gain Update is upon on DIG mechanism except CCK rate.
- * (4) Add the mehanism of trying to upgrade tx rate.
+ * (4) Add the mechanism of trying to upgrade tx rate.
* (5) Record the information of upping tx rate to avoid trying upping tx rate constantly.
*
*/
@@ -528,7 +528,7 @@ void StaRateAdaptive87SE(struct net_device *dev)
if (priv->bTryuping == true) {
/* 2 For Test Upgrading mechanism
* Note:
- * Sometimes the throughput is upon on the capability bwtween the AP and NIC,
+ * Sometimes the throughput is upon on the capability between the AP and NIC,
* thus the low data rate does not improve the performance.
* We randomly upgrade the data rate and check if the retry rate is improved.
*/
@@ -704,7 +704,7 @@ void StaRateAdaptive87SE(struct net_device *dev)
/*
* The difference in throughput between 48Mbps and 36Mbps is 8M.
- * So, we must be carefully in this rate scale. Isaiah 2008-02-15.
+ * So, we must be careful in this rate scale. Isaiah 2008-02-15.
*/
if (((priv->CurrentOperaRate == 72) || (priv->CurrentOperaRate == 48) || (priv->CurrentOperaRate == 36)) &&
(priv->FailTxRateCount > 2))
@@ -1009,7 +1009,7 @@ void SwAntennaDiversity(struct net_device *dev)
if (priv->AdCheckPeriod > priv->AdMaxCheckPeriod)
priv->AdCheckPeriod = priv->AdMaxCheckPeriod;
- /* Wrong deceision => switch back. */
+ /* Wrong decision => switch back. */
SwitchAntenna(dev);
} else {
/* Rx Signal Strength is improved. */
@@ -1057,7 +1057,7 @@ void SwAntennaDiversity(struct net_device *dev)
}
/*
* <Roger_Notes> We evaluate Rx signal strength ONLY when default antenna
- * didn't changed by HW evaluation.
+ * didn't change by HW evaluation.
* 2008.02.27.
*
* [TRC Dell Lab] SignalStrength is inaccuracy. Isaiah 2008-03-05
@@ -1098,7 +1098,7 @@ void SwAntennaDiversity(struct net_device *dev)
priv->AdAuxAntennaRxOkCnt = 0;
}
- /* Return TRUE if we shall perform Tx Power Tracking Mecahnism, FALSE otherwise. */
+ /* Return TRUE if we shall perform Tx Power Tracking Mechanism, FALSE otherwise. */
bool CheckTxPwrTracking(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
diff --git a/drivers/staging/rtl8187se/r8180_rtl8225z2.c b/drivers/staging/rtl8187se/r8180_rtl8225z2.c
index ee5b867fd0d4..d28c1d996084 100644
--- a/drivers/staging/rtl8187se/r8180_rtl8225z2.c
+++ b/drivers/staging/rtl8187se/r8180_rtl8225z2.c
@@ -190,7 +190,7 @@ static void rtl8225_SetTXPowerLevel(struct net_device *dev, short ch)
write_phy_cck(dev, 0x44 + i, power);
}
- /* FIXME Is this delay really needeed ? */
+ /* FIXME Is this delay really needed ? */
force_pci_posting(dev);
mdelay(1);
@@ -479,7 +479,7 @@ s8 DbmToTxPwrIdx(struct r8180_priv *priv, WIRELESS_MODE WirelessMode,
/*
* TRUE if we want to use a default implementation.
- * We shall set it to FALSE when we have exact translation formular
+ * We shall set it to FALSE when we have exact translation formula
* for target IC. 070622, by rcnjko.
*/
if (bUseDefault) {
diff --git a/drivers/staging/rtl8187se/r8180_wx.c b/drivers/staging/rtl8187se/r8180_wx.c
index 303ec691262a..46ee6f47f525 100644
--- a/drivers/staging/rtl8187se/r8180_wx.c
+++ b/drivers/staging/rtl8187se/r8180_wx.c
@@ -13,7 +13,7 @@
Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver.
- We want to tanks the Authors of those projects and the Ndiswrapper
+ We want to thanks the Authors of those projects and the Ndiswrapper
project Authors.
*/
@@ -1181,7 +1181,7 @@ static iw_handler r8180_wx_handlers[] = {
r8180_wx_set_wap, /* SIOCSIWAP */
r8180_wx_get_wap, /* SIOCGIWAP */
r8180_wx_set_mlme, /* SIOCSIWMLME*/
- dummy, /* SIOCGIWAPLIST -- depricated */
+ dummy, /* SIOCGIWAPLIST -- deprecated */
r8180_wx_set_scan, /* SIOCSIWSCAN */
r8180_wx_get_scan, /* SIOCGIWSCAN */
r8180_wx_set_essid, /* SIOCSIWESSID */
@@ -1369,7 +1369,7 @@ static inline int is_same_network(struct ieee80211_network *src,
(dst->capability & WLAN_CAPABILITY_BSS)));
}
-/* WB modefied to show signal to GUI on 18-01-2008 */
+/* WB modified to show signal to GUI on 18-01-2008 */
static struct iw_statistics *r8180_get_wireless_stats(struct net_device *dev)
{
struct r8180_priv *priv = ieee80211_priv(dev);
diff --git a/drivers/staging/rtl8187se/r8180_wx.h b/drivers/staging/rtl8187se/r8180_wx.h
index 735d03dceed3..408191403112 100644
--- a/drivers/staging/rtl8187se/r8180_wx.h
+++ b/drivers/staging/rtl8187se/r8180_wx.h
@@ -7,7 +7,7 @@
Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon
Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
- We want to tanks the Authors of such projects and the Ndiswrapper project Authors.
+ We want to thanks the Authors of such projects and the Ndiswrapper project Authors.
*/
/* this file (will) contains wireless extension handlers*/
diff --git a/drivers/staging/rtl8187se/r8185b_init.c b/drivers/staging/rtl8187se/r8185b_init.c
index 4b0b830f9ab6..914495783c06 100644
--- a/drivers/staging/rtl8187se/r8185b_init.c
+++ b/drivers/staging/rtl8187se/r8185b_init.c
@@ -1,22 +1,22 @@
-/*++
-Copyright (c) Realtek Semiconductor Corp. All rights reserved.
-
-Module Name:
- r8185b_init.c
-
-Abstract:
- Hardware Initialization and Hardware IO for RTL8185B
-
-Major Change History:
- When Who What
- ---------- --------------- -------------------------------
- 2006-11-15 Xiong Created
-
-Notes:
- This file is ported from RTL8185B Windows driver.
-
-
---*/
+/*
+ * Copyright (c) Realtek Semiconductor Corp. All rights reserved.
+ *
+ * Module Name:
+ * r8185b_init.c
+ *
+ * Abstract:
+ * Hardware Initialization and Hardware IO for RTL8185B
+ *
+ * Major Change History:
+ * When Who What
+ * ---------- --------------- -------------------------------
+ * 2006-11-15 Xiong Created
+ *
+ * Notes:
+ * This file is ported from RTL8185B Windows driver.
+ *
+ *
+ */
/*--------------------------Include File------------------------------------*/
#include <linux/spinlock.h>
@@ -25,155 +25,134 @@ Notes:
#include "r8180_rtl8225.h" /* RTL8225 Radio frontend */
#include "r8180_93cx6.h" /* Card EEPROM */
#include "r8180_wx.h"
-
#include "ieee80211/dot11d.h"
-
-
/* #define CONFIG_RTL8180_IO_MAP */
-
#define TC_3W_POLL_MAX_TRY_CNT 5
+
static u8 MAC_REG_TABLE[][2] = {
- /*PAGA 0: */
- /* 0x34(BRSR), 0xBE(RATE_FALLBACK_CTL), 0x1E0(ARFR) would set in HwConfigureRTL8185() */
- /* 0x272(RFSW_CTRL), 0x1CE(AESMSK_QC) set in InitializeAdapter8185(). */
- /* 0x1F0~0x1F8 set in MacConfig_85BASIC() */
- {0x08, 0xae}, {0x0a, 0x72}, {0x5b, 0x42},
- {0x84, 0x88}, {0x85, 0x24}, {0x88, 0x54}, {0x8b, 0xb8}, {0x8c, 0x03},
- {0x8d, 0x40}, {0x8e, 0x00}, {0x8f, 0x00}, {0x5b, 0x18}, {0x91, 0x03},
- {0x94, 0x0F}, {0x95, 0x32},
- {0x96, 0x00}, {0x97, 0x07}, {0xb4, 0x22}, {0xdb, 0x00},
- {0xf0, 0x32}, {0xf1, 0x32}, {0xf2, 0x00}, {0xf3, 0x00}, {0xf4, 0x32},
- {0xf5, 0x43}, {0xf6, 0x00}, {0xf7, 0x00}, {0xf8, 0x46}, {0xf9, 0xa4},
- {0xfa, 0x00}, {0xfb, 0x00}, {0xfc, 0x96}, {0xfd, 0xa4}, {0xfe, 0x00},
- {0xff, 0x00},
-
- /*PAGE 1: */
- /* For Flextronics system Logo PCIHCT failure: */
- /* 0x1C4~0x1CD set no-zero value to avoid PCI configuration space 0x45[7]=1 */
- {0x5e, 0x01},
- {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x04}, {0x5b, 0x00}, {0x60, 0x24},
- {0x61, 0x97}, {0x62, 0xF0}, {0x63, 0x09}, {0x80, 0x0F}, {0x81, 0xFF},
- {0x82, 0xFF}, {0x83, 0x03},
- {0xC4, 0x22}, {0xC5, 0x22}, {0xC6, 0x22}, {0xC7, 0x22}, {0xC8, 0x22}, /* lzm add 080826 */
- {0xC9, 0x22}, {0xCA, 0x22}, {0xCB, 0x22}, {0xCC, 0x22}, {0xCD, 0x22},/* lzm add 080826 */
- {0xe2, 0x00},
-
-
- /* PAGE 2: */
- {0x5e, 0x02},
- {0x0c, 0x04}, {0x4c, 0x30}, {0x4d, 0x08}, {0x50, 0x05}, {0x51, 0xf5},
- {0x52, 0x04}, {0x53, 0xa0}, {0x54, 0xff}, {0x55, 0xff}, {0x56, 0xff},
- {0x57, 0xff}, {0x58, 0x08}, {0x59, 0x08}, {0x5a, 0x08}, {0x5b, 0x08},
- {0x60, 0x08}, {0x61, 0x08}, {0x62, 0x08}, {0x63, 0x08}, {0x64, 0x2f},
- {0x8c, 0x3f}, {0x8d, 0x3f}, {0x8e, 0x3f},
- {0x8f, 0x3f}, {0xc4, 0xff}, {0xc5, 0xff}, {0xc6, 0xff}, {0xc7, 0xff},
- {0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x80}, {0xcb, 0x00},
-
- /* PAGA 0: */
- {0x5e, 0x00}, {0x9f, 0x03}
- };
-
-
-static u8 ZEBRA_AGC[] = {
- 0,
- 0x7E, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72,
- 0x71, 0x70, 0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62,
- 0x48, 0x47, 0x46, 0x45, 0x44, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x08, 0x07,
- 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x15, 0x16,
- 0x17, 0x17, 0x18, 0x18, 0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e,
- 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24,
- 0x24, 0x25, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F
- };
-
-static u32 ZEBRA_RF_RX_GAIN_TABLE[] = {
- 0x0096, 0x0076, 0x0056, 0x0036, 0x0016, 0x01f6, 0x01d6, 0x01b6,
- 0x0196, 0x0176, 0x00F7, 0x00D7, 0x00B7, 0x0097, 0x0077, 0x0057,
- 0x0037, 0x00FB, 0x00DB, 0x00BB, 0x00FF, 0x00E3, 0x00C3, 0x00A3,
- 0x0083, 0x0063, 0x0043, 0x0023, 0x0003, 0x01E3, 0x01C3, 0x01A3,
- 0x0183, 0x0163, 0x0143, 0x0123, 0x0103
+ /*PAGA 0: */
+ /* 0x34(BRSR), 0xBE(RATE_FALLBACK_CTL), 0x1E0(ARFR) would set in HwConfigureRTL8185() */
+ /* 0x272(RFSW_CTRL), 0x1CE(AESMSK_QC) set in InitializeAdapter8185(). */
+ /* 0x1F0~0x1F8 set in MacConfig_85BASIC() */
+ {0x08, 0xae}, {0x0a, 0x72}, {0x5b, 0x42},
+ {0x84, 0x88}, {0x85, 0x24}, {0x88, 0x54}, {0x8b, 0xb8}, {0x8c, 0x03},
+ {0x8d, 0x40}, {0x8e, 0x00}, {0x8f, 0x00}, {0x5b, 0x18}, {0x91, 0x03},
+ {0x94, 0x0F}, {0x95, 0x32},
+ {0x96, 0x00}, {0x97, 0x07}, {0xb4, 0x22}, {0xdb, 0x00},
+ {0xf0, 0x32}, {0xf1, 0x32}, {0xf2, 0x00}, {0xf3, 0x00}, {0xf4, 0x32},
+ {0xf5, 0x43}, {0xf6, 0x00}, {0xf7, 0x00}, {0xf8, 0x46}, {0xf9, 0xa4},
+ {0xfa, 0x00}, {0xfb, 0x00}, {0xfc, 0x96}, {0xfd, 0xa4}, {0xfe, 0x00},
+ {0xff, 0x00},
+
+ /*PAGE 1: */
+ /* For Flextronics system Logo PCIHCT failure: */
+ /* 0x1C4~0x1CD set no-zero value to avoid PCI configuration space 0x45[7]=1 */
+ {0x5e, 0x01},
+ {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x04}, {0x5b, 0x00}, {0x60, 0x24},
+ {0x61, 0x97}, {0x62, 0xF0}, {0x63, 0x09}, {0x80, 0x0F}, {0x81, 0xFF},
+ {0x82, 0xFF}, {0x83, 0x03},
+ {0xC4, 0x22}, {0xC5, 0x22}, {0xC6, 0x22}, {0xC7, 0x22}, {0xC8, 0x22}, /* lzm add 080826 */
+ {0xC9, 0x22}, {0xCA, 0x22}, {0xCB, 0x22}, {0xCC, 0x22}, {0xCD, 0x22}, /* lzm add 080826 */
+ {0xe2, 0x00},
+
+
+ /* PAGE 2: */
+ {0x5e, 0x02},
+ {0x0c, 0x04}, {0x4c, 0x30}, {0x4d, 0x08}, {0x50, 0x05}, {0x51, 0xf5},
+ {0x52, 0x04}, {0x53, 0xa0}, {0x54, 0xff}, {0x55, 0xff}, {0x56, 0xff},
+ {0x57, 0xff}, {0x58, 0x08}, {0x59, 0x08}, {0x5a, 0x08}, {0x5b, 0x08},
+ {0x60, 0x08}, {0x61, 0x08}, {0x62, 0x08}, {0x63, 0x08}, {0x64, 0x2f},
+ {0x8c, 0x3f}, {0x8d, 0x3f}, {0x8e, 0x3f},
+ {0x8f, 0x3f}, {0xc4, 0xff}, {0xc5, 0xff}, {0xc6, 0xff}, {0xc7, 0xff},
+ {0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x80}, {0xcb, 0x00},
+
+ /* PAGA 0: */
+ {0x5e, 0x00}, {0x9f, 0x03}
+ };
+
+
+static u8 ZEBRA_AGC[] = {
+ 0,
+ 0x7E, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72,
+ 0x71, 0x70, 0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62,
+ 0x48, 0x47, 0x46, 0x45, 0x44, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x08, 0x07,
+ 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x15, 0x16,
+ 0x17, 0x17, 0x18, 0x18, 0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e,
+ 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x23, 0x23, 0x24,
+ 0x24, 0x25, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F
+ };
+
+static u32 ZEBRA_RF_RX_GAIN_TABLE[] = {
+ 0x0096, 0x0076, 0x0056, 0x0036, 0x0016, 0x01f6, 0x01d6, 0x01b6,
+ 0x0196, 0x0176, 0x00F7, 0x00D7, 0x00B7, 0x0097, 0x0077, 0x0057,
+ 0x0037, 0x00FB, 0x00DB, 0x00BB, 0x00FF, 0x00E3, 0x00C3, 0x00A3,
+ 0x0083, 0x0063, 0x0043, 0x0023, 0x0003, 0x01E3, 0x01C3, 0x01A3,
+ 0x0183, 0x0163, 0x0143, 0x0123, 0x0103
};
-static u8 OFDM_CONFIG[] = {
- /* OFDM reg0x06[7:0]=0xFF: Enable power saving mode in RX */
- /* OFDM reg0x3C[4]=1'b1: Enable RX power saving mode */
- /* ofdm 0x3a = 0x7b ,(original : 0xfb) For ECS shielding room TP test */
-
- /* 0x00 */
- 0x10, 0x0F, 0x0A, 0x0C, 0x14, 0xFA, 0xFF, 0x50,
- 0x00, 0x50, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00,
- /* 0x10 */
- 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xA8, 0x26,
- 0x32, 0x33, 0x06, 0xA5, 0x6F, 0x55, 0xC8, 0xBB,
- /* 0x20 */
- 0x0A, 0xE1, 0x2C, 0x4A, 0x86, 0x83, 0x34, 0x00,
- 0x4F, 0x24, 0x6F, 0xC2, 0x03, 0x40, 0x80, 0x00,
- /* 0x30 */
- 0xC0, 0xC1, 0x58, 0xF1, 0x00, 0xC4, 0x90, 0x3e,
- 0xD8, 0x3C, 0x7B, 0x10, 0x10
- };
-
-/* ---------------------------------------------------------------
- * Hardware IO
- * the code is ported from Windows source code
- ----------------------------------------------------------------*/
-
-void
-PlatformIOWrite1Byte(
- struct net_device *dev,
- u32 offset,
- u8 data
- )
+static u8 OFDM_CONFIG[] = {
+ /* OFDM reg0x06[7:0]=0xFF: Enable power saving mode in RX */
+ /* OFDM reg0x3C[4]=1'b1: Enable RX power saving mode */
+ /* ofdm 0x3a = 0x7b ,(original : 0xfb) For ECS shielding room TP test */
+ /* 0x00 */
+ 0x10, 0x0F, 0x0A, 0x0C, 0x14, 0xFA, 0xFF, 0x50,
+ 0x00, 0x50, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00,
+ /* 0x10 */
+ 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xA8, 0x26,
+ 0x32, 0x33, 0x06, 0xA5, 0x6F, 0x55, 0xC8, 0xBB,
+ /* 0x20 */
+ 0x0A, 0xE1, 0x2C, 0x4A, 0x86, 0x83, 0x34, 0x00,
+ 0x4F, 0x24, 0x6F, 0xC2, 0x03, 0x40, 0x80, 0x00,
+ /* 0x30 */
+ 0xC0, 0xC1, 0x58, 0xF1, 0x00, 0xC4, 0x90, 0x3e,
+ 0xD8, 0x3C, 0x7B, 0x10, 0x10
+ };
+
+ /*---------------------------------------------------------------
+ * Hardware IO
+ * the code is ported from Windows source code
+ *---------------------------------------------------------------
+ */
+
+void PlatformIOWrite1Byte(struct net_device *dev, u32 offset, u8 data)
{
write_nic_byte(dev, offset, data);
- read_nic_byte(dev, offset); /* To make sure write operation is completed, 2005.11.09, by rcnjko. */
-
+ read_nic_byte(dev, offset); /* To make sure write operation is completed, 2005.11.09, by rcnjko. */
}
-void
-PlatformIOWrite2Byte(
- struct net_device *dev,
- u32 offset,
- u16 data
- )
+void PlatformIOWrite2Byte(struct net_device *dev, u32 offset, u16 data)
{
write_nic_word(dev, offset, data);
read_nic_word(dev, offset); /* To make sure write operation is completed, 2005.11.09, by rcnjko. */
-
-
}
+
u8 PlatformIORead1Byte(struct net_device *dev, u32 offset);
-void
-PlatformIOWrite4Byte(
- struct net_device *dev,
- u32 offset,
- u32 data
- )
+void PlatformIOWrite4Byte(struct net_device *dev, u32 offset, u32 data)
{
-/* {by amy 080312 */
-if (offset == PhyAddr) {
-/* For Base Band configuration. */
+ if (offset == PhyAddr) {
+ /* For Base Band configuration. */
unsigned char cmdByte;
unsigned long dataBytes;
unsigned char idx;
- u8 u1bTmp;
+ u8 u1bTmp;
cmdByte = (u8)(data & 0x000000ff);
dataBytes = data>>8;
/*
- 071010, rcnjko:
- The critical section is only BB read/write race condition.
- Assumption:
- 1. We assume NO one will access BB at DIRQL, otherwise, system will crash for
- acquiring the spinlock in such context.
- 2. PlatformIOWrite4Byte() MUST NOT be recursive.
- */
-/* NdisAcquireSpinLock( &(pDevice->IoSpinLock) ); */
-
- for (idx = 0; idx < 30; idx++) {
- /* Make sure command bit is clear before access it. */
+ * 071010, rcnjko:
+ * The critical section is only BB read/write race condition.
+ * Assumption:
+ * 1. We assume NO one will access BB at DIRQL, otherwise, system will crash for
+ * acquiring the spinlock in such context.
+ * 2. PlatformIOWrite4Byte() MUST NOT be recursive.
+ */
+ /* NdisAcquireSpinLock( &(pDevice->IoSpinLock) ); */
+
+ for (idx = 0; idx < 30; idx++) {
+ /* Make sure command bit is clear before access it. */
u1bTmp = PlatformIORead1Byte(dev, PhyAddr);
if ((u1bTmp & BIT7) == 0)
break;
@@ -186,20 +165,14 @@ if (offset == PhyAddr) {
write_nic_byte(dev, offset, cmdByte);
-/* NdisReleaseSpinLock( &(pDevice->IoSpinLock) ); */
- }
-/* by amy 080312} */
- else {
+ /* NdisReleaseSpinLock( &(pDevice->IoSpinLock) ); */
+ } else {
write_nic_dword(dev, offset, data);
read_nic_dword(dev, offset); /* To make sure write operation is completed, 2005.11.09, by rcnjko. */
}
}
-u8
-PlatformIORead1Byte(
- struct net_device *dev,
- u32 offset
- )
+u8 PlatformIORead1Byte(struct net_device *dev, u32 offset)
{
u8 data = 0;
@@ -209,11 +182,7 @@ PlatformIORead1Byte(
return data;
}
-u16
-PlatformIORead2Byte(
- struct net_device *dev,
- u32 offset
- )
+u16 PlatformIORead2Byte(struct net_device *dev, u32 offset)
{
u16 data = 0;
@@ -223,11 +192,7 @@ PlatformIORead2Byte(
return data;
}
-u32
-PlatformIORead4Byte(
- struct net_device *dev,
- u32 offset
- )
+u32 PlatformIORead4Byte(struct net_device *dev, u32 offset)
{
u32 data = 0;
@@ -242,22 +207,19 @@ void SetOutputEnableOfRfPins(struct net_device *dev)
write_nic_word(dev, RFPinsEnable, 0x1bff);
}
-static int
-HwHSSIThreeWire(
- struct net_device *dev,
- u8 *pDataBuf,
- u8 nDataBufBitCnt,
- int bSI,
- int bWrite
- )
+static int HwHSSIThreeWire(struct net_device *dev,
+ u8 *pDataBuf,
+ u8 nDataBufBitCnt,
+ int bSI,
+ int bWrite)
{
int bResult = 1;
u8 TryCnt;
u8 u1bTmp;
- do {
+ do {
/* Check if WE and RE are cleared. */
- for (TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) {
+ for (TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) {
u1bTmp = read_nic_byte(dev, SW_3W_CMD1);
if ((u1bTmp & (SW_3W_CMD1_RE|SW_3W_CMD1_WE)) == 0)
break;
@@ -275,15 +237,15 @@ HwHSSIThreeWire(
u1bTmp = read_nic_byte(dev, RF_SW_CONFIG);
if (bSI)
- u1bTmp |= RF_SW_CFG_SI; /* reg08[1]=1 Serial Interface(SI) */
+ u1bTmp |= RF_SW_CFG_SI; /* reg08[1]=1 Serial Interface(SI) */
else
- u1bTmp &= ~RF_SW_CFG_SI; /* reg08[1]=0 Parallel Interface(PI) */
+ u1bTmp &= ~RF_SW_CFG_SI; /* reg08[1]=0 Parallel Interface(PI) */
write_nic_byte(dev, RF_SW_CONFIG, u1bTmp);
- if (bSI) {
+ if (bSI) {
/* jong: HW SI read must set reg84[3]=0. */
u1bTmp = read_nic_byte(dev, RFPinsSelect);
u1bTmp &= ~BIT3;
@@ -291,14 +253,14 @@ HwHSSIThreeWire(
}
/* Fill up data buffer for write operation. */
- if (bWrite) {
- if (nDataBufBitCnt == 16) {
+ if (bWrite) {
+ if (nDataBufBitCnt == 16) {
write_nic_word(dev, SW_3W_DB0, *((u16 *)pDataBuf));
- } else if (nDataBufBitCnt == 64) {
+ } else if (nDataBufBitCnt == 64) {
/* RTL8187S shouldn't enter this case */
write_nic_dword(dev, SW_3W_DB0, *((u32 *)pDataBuf));
write_nic_dword(dev, SW_3W_DB1, *((u32 *)(pDataBuf + 4)));
- } else {
+ } else {
int idx;
int ByteCnt = nDataBufBitCnt / 8;
/* printk("%d\n",nDataBufBitCnt); */
@@ -324,11 +286,11 @@ HwHSSIThreeWire(
write_nic_byte(dev, (SW_3W_DB0+idx), *(pDataBuf+idx));
}
- } else { /* read */
- if (bSI) {
- /* SI - reg274[3:0] : RF register's Address */
+ } else { /* read */
+ if (bSI) {
+ /* SI - reg274[3:0] : RF register's Address */
write_nic_word(dev, SW_3W_DB0, *((u16 *)pDataBuf));
- } else {
+ } else {
/* PI - reg274[15:12] : RF register's Address */
write_nic_word(dev, SW_3W_DB0, (*((u16 *)pDataBuf)) << 12);
}
@@ -343,7 +305,7 @@ HwHSSIThreeWire(
/* Check if DONE is set. */
- for (TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) {
+ for (TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) {
u1bTmp = read_nic_byte(dev, SW_3W_CMD1);
if ((u1bTmp & SW_3W_CMD1_DONE) != 0)
break;
@@ -353,12 +315,12 @@ HwHSSIThreeWire(
write_nic_byte(dev, SW_3W_CMD1, 0);
- /* Read back data for read operation. */
- if (bWrite == 0) {
- if (bSI) {
+ /* Read back data for read operation. */
+ if (bWrite == 0) {
+ if (bSI) {
/* Serial Interface : reg363_362[11:0] */
*((u16 *)pDataBuf) = read_nic_word(dev, SI_DATA_READ) ;
- } else {
+ } else {
/* Parallel Interface : reg361_360[11:0] */
*((u16 *)pDataBuf) = read_nic_word(dev, PI_DATA_READ);
}
@@ -366,13 +328,12 @@ HwHSSIThreeWire(
*((u16 *)pDataBuf) &= 0x0FFF;
}
- } while (0);
+ } while (0);
return bResult;
}
-void
-RF_WriteReg(struct net_device *dev, u8 offset, u32 data)
+void RF_WriteReg(struct net_device *dev, u8 offset, u32 data)
{
u32 data2Write;
u8 len;
@@ -400,11 +361,7 @@ u32 RF_ReadReg(struct net_device *dev, u8 offset)
/* by Owen on 04/07/14 for writing BB register successfully */
-void
-WriteBBPortUchar(
- struct net_device *dev,
- u32 Data
- )
+void WriteBBPortUchar(struct net_device *dev, u32 Data)
{
/* u8 TimeoutCounter; */
u8 RegisterContent;
@@ -421,11 +378,7 @@ WriteBBPortUchar(
}
}
-u8
-ReadBBPortUchar(
- struct net_device *dev,
- u32 addr
- )
+u8 ReadBBPortUchar(struct net_device *dev, u32 addr)
{
/*u8 TimeoutCounter; */
u8 RegisterContent;
@@ -435,66 +388,62 @@ ReadBBPortUchar(
return RegisterContent;
}
-/* {by amy 080312 */
/*
- Description:
- Perform Antenna settings with antenna diversity on 87SE.
- Created by Roger, 2008.01.25.
-*/
-bool
-SetAntennaConfig87SE(
- struct net_device *dev,
- u8 DefaultAnt, /* 0: Main, 1: Aux. */
- bool bAntDiversity /* 1:Enable, 0: Disable. */
-)
+ * Description:
+ * Perform Antenna settings with antenna diversity on 87SE.
+ * Created by Roger, 2008.01.25.
+ */
+bool SetAntennaConfig87SE(struct net_device *dev,
+ u8 DefaultAnt, /* 0: Main, 1: Aux. */
+ bool bAntDiversity) /* 1:Enable, 0: Disable. */
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
bool bAntennaSwitched = true;
/* printk("SetAntennaConfig87SE(): DefaultAnt(%d), bAntDiversity(%d)\n", DefaultAnt, bAntDiversity); */
- /* Threshold for antenna diversity. */
+ /* Threshold for antenna diversity. */
write_phy_cck(dev, 0x0c, 0x09); /* Reg0c : 09 */
- if (bAntDiversity) { /* Enable Antenna Diversity. */
- if (DefaultAnt == 1) { /* aux antenna */
+ if (bAntDiversity) { /* Enable Antenna Diversity. */
+ if (DefaultAnt == 1) { /* aux antenna */
- /* Mac register, aux antenna */
+ /* Mac register, aux antenna */
write_nic_byte(dev, ANTSEL, 0x00);
- /* Config CCK RX antenna. */
+ /* Config CCK RX antenna. */
write_phy_cck(dev, 0x11, 0xbb); /* Reg11 : bb */
write_phy_cck(dev, 0x01, 0xc7); /* Reg01 : c7 */
- /* Config OFDM RX antenna. */
- write_phy_ofdm(dev, 0x0D, 0x54); /* Reg0d : 54 */
- write_phy_ofdm(dev, 0x18, 0xb2); /* Reg18 : b2 */
- } else { /* use main antenna */
- /* Mac register, main antenna */
+ /* Config OFDM RX antenna. */
+ write_phy_ofdm(dev, 0x0D, 0x54); /* Reg0d : 54 */
+ write_phy_ofdm(dev, 0x18, 0xb2); /* Reg18 : b2 */
+ } else { /* use main antenna */
+ /* Mac register, main antenna */
write_nic_byte(dev, ANTSEL, 0x03);
- /* base band */
- /* Config CCK RX antenna. */
- write_phy_cck(dev, 0x11, 0x9b); /* Reg11 : 9b */
- write_phy_cck(dev, 0x01, 0xc7); /* Reg01 : c7 */
+ /* base band */
+ /* Config CCK RX antenna. */
+ write_phy_cck(dev, 0x11, 0x9b); /* Reg11 : 9b */
+ write_phy_cck(dev, 0x01, 0xc7); /* Reg01 : c7 */
/* Config OFDM RX antenna. */
write_phy_ofdm(dev, 0x0d, 0x5c); /* Reg0d : 5c */
write_phy_ofdm(dev, 0x18, 0xb2); /* Reg18 : b2 */
}
- } else {
+ } else {
/* Disable Antenna Diversity. */
- if (DefaultAnt == 1) { /* aux Antenna */
+ if (DefaultAnt == 1) { /* aux Antenna */
/* Mac register, aux antenna */
write_nic_byte(dev, ANTSEL, 0x00);
/* Config CCK RX antenna. */
- write_phy_cck(dev, 0x11, 0xbb); /* Reg11 : bb */
- write_phy_cck(dev, 0x01, 0x47); /* Reg01 : 47 */
+ write_phy_cck(dev, 0x11, 0xbb); /* Reg11 : bb */
+ write_phy_cck(dev, 0x01, 0x47); /* Reg01 : 47 */
/* Config OFDM RX antenna. */
- write_phy_ofdm(dev, 0x0D, 0x54); /* Reg0d : 54 */
- write_phy_ofdm(dev, 0x18, 0x32); /* Reg18 : 32 */
- } else { /* main Antenna */
+ write_phy_ofdm(dev, 0x0D, 0x54); /* Reg0d : 54 */
+ write_phy_ofdm(dev, 0x18, 0x32); /* Reg18 : 32 */
+ } else { /* main Antenna */
/* Mac register, main antenna */
write_nic_byte(dev, ANTSEL, 0x03);
@@ -502,25 +451,22 @@ SetAntennaConfig87SE(
write_phy_cck(dev, 0x11, 0x9b); /* Reg11 : 9b */
write_phy_cck(dev, 0x01, 0x47); /* Reg01 : 47 */
- /* Config OFDM RX antenna. */
- write_phy_ofdm(dev, 0x0D, 0x5c); /* Reg0d : 5c */
- write_phy_ofdm(dev, 0x18, 0x32); /*Reg18 : 32 */
+ /* Config OFDM RX antenna. */
+ write_phy_ofdm(dev, 0x0D, 0x5c); /* Reg0d : 5c */
+ write_phy_ofdm(dev, 0x18, 0x32); /*Reg18 : 32 */
}
}
priv->CurrAntennaIndex = DefaultAnt; /* Update default settings. */
return bAntennaSwitched;
}
-/* by amy 080312 */
/*
----------------------------------------------------------------
- * Hardware Initialization.
- * the code is ported from Windows source code
-----------------------------------------------------------------*/
-
-void
-ZEBRA_Config_85BASIC_HardCode(
- struct net_device *dev
- )
+ *--------------------------------------------------------------
+ * Hardware Initialization.
+ * the code is ported from Windows source code
+ *--------------------------------------------------------------
+ */
+
+void ZEBRA_Config_85BASIC_HardCode(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
@@ -532,163 +478,151 @@ ZEBRA_Config_85BASIC_HardCode(
/*
-=============================================================================
- 87S_PCIE :: RADIOCFG.TXT
-=============================================================================
-*/
+ *===========================================================================
+ * 87S_PCIE :: RADIOCFG.TXT
+ *===========================================================================
+ */
/* Page1 : reg16-reg30 */
- RF_WriteReg(dev, 0x00, 0x013f); mdelay(1); /* switch to page1 */
- u4bRF23 = RF_ReadReg(dev, 0x08); mdelay(1);
- u4bRF24 = RF_ReadReg(dev, 0x09); mdelay(1);
+ RF_WriteReg(dev, 0x00, 0x013f); mdelay(1); /* switch to page1 */
+ u4bRF23 = RF_ReadReg(dev, 0x08); mdelay(1);
+ u4bRF24 = RF_ReadReg(dev, 0x09); mdelay(1);
if (u4bRF23 == 0x818 && u4bRF24 == 0x70C) {
d_cut = 1;
printk(KERN_INFO "rtl8187se: card type changed from C- to D-cut\n");
}
- /* Page0 : reg0-reg15 */
-
- RF_WriteReg(dev, 0x00, 0x009f); mdelay(1);/* 1 */
-
- RF_WriteReg(dev, 0x01, 0x06e0); mdelay(1);
-
- RF_WriteReg(dev, 0x02, 0x004d); mdelay(1);/* 2 */
-
- RF_WriteReg(dev, 0x03, 0x07f1); mdelay(1);/* 3 */
-
- RF_WriteReg(dev, 0x04, 0x0975); mdelay(1);
- RF_WriteReg(dev, 0x05, 0x0c72); mdelay(1);
- RF_WriteReg(dev, 0x06, 0x0ae6); mdelay(1);
- RF_WriteReg(dev, 0x07, 0x00ca); mdelay(1);
- RF_WriteReg(dev, 0x08, 0x0e1c); mdelay(1);
- RF_WriteReg(dev, 0x09, 0x02f0); mdelay(1);
- RF_WriteReg(dev, 0x0a, 0x09d0); mdelay(1);
- RF_WriteReg(dev, 0x0b, 0x01ba); mdelay(1);
- RF_WriteReg(dev, 0x0c, 0x0640); mdelay(1);
- RF_WriteReg(dev, 0x0d, 0x08df); mdelay(1);
- RF_WriteReg(dev, 0x0e, 0x0020); mdelay(1);
- RF_WriteReg(dev, 0x0f, 0x0990); mdelay(1);
-
+ /* Page0 : reg0-reg15 */
+
+ RF_WriteReg(dev, 0x00, 0x009f); mdelay(1);/* 1 */
+ RF_WriteReg(dev, 0x01, 0x06e0); mdelay(1);
+ RF_WriteReg(dev, 0x02, 0x004d); mdelay(1);/* 2 */
+ RF_WriteReg(dev, 0x03, 0x07f1); mdelay(1);/* 3 */
+ RF_WriteReg(dev, 0x04, 0x0975); mdelay(1);
+ RF_WriteReg(dev, 0x05, 0x0c72); mdelay(1);
+ RF_WriteReg(dev, 0x06, 0x0ae6); mdelay(1);
+ RF_WriteReg(dev, 0x07, 0x00ca); mdelay(1);
+ RF_WriteReg(dev, 0x08, 0x0e1c); mdelay(1);
+ RF_WriteReg(dev, 0x09, 0x02f0); mdelay(1);
+ RF_WriteReg(dev, 0x0a, 0x09d0); mdelay(1);
+ RF_WriteReg(dev, 0x0b, 0x01ba); mdelay(1);
+ RF_WriteReg(dev, 0x0c, 0x0640); mdelay(1);
+ RF_WriteReg(dev, 0x0d, 0x08df); mdelay(1);
+ RF_WriteReg(dev, 0x0e, 0x0020); mdelay(1);
+ RF_WriteReg(dev, 0x0f, 0x0990); mdelay(1);
/* Page1 : reg16-reg30 */
- RF_WriteReg(dev, 0x00, 0x013f); mdelay(1);
-
- RF_WriteReg(dev, 0x03, 0x0806); mdelay(1);
-
- RF_WriteReg(dev, 0x04, 0x03a7); mdelay(1);
- RF_WriteReg(dev, 0x05, 0x059b); mdelay(1);
- RF_WriteReg(dev, 0x06, 0x0081); mdelay(1);
-
-
- RF_WriteReg(dev, 0x07, 0x01A0); mdelay(1);
+ RF_WriteReg(dev, 0x00, 0x013f); mdelay(1);
+ RF_WriteReg(dev, 0x03, 0x0806); mdelay(1);
+ RF_WriteReg(dev, 0x04, 0x03a7); mdelay(1);
+ RF_WriteReg(dev, 0x05, 0x059b); mdelay(1);
+ RF_WriteReg(dev, 0x06, 0x0081); mdelay(1);
+ RF_WriteReg(dev, 0x07, 0x01A0); mdelay(1);
/* Don't write RF23/RF24 to make a difference between 87S C cut and D cut. asked by SD3 stevenl. */
- RF_WriteReg(dev, 0x0a, 0x0001); mdelay(1);
- RF_WriteReg(dev, 0x0b, 0x0418); mdelay(1);
+ RF_WriteReg(dev, 0x0a, 0x0001); mdelay(1);
+ RF_WriteReg(dev, 0x0b, 0x0418); mdelay(1);
if (d_cut) {
- RF_WriteReg(dev, 0x0c, 0x0fbe); mdelay(1);
- RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1);
- RF_WriteReg(dev, 0x0e, 0x0807); mdelay(1); /* RX LO buffer */
- } else {
- RF_WriteReg(dev, 0x0c, 0x0fbe); mdelay(1);
- RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1);
- RF_WriteReg(dev, 0x0e, 0x0806); mdelay(1); /* RX LO buffer */
+ RF_WriteReg(dev, 0x0c, 0x0fbe); mdelay(1);
+ RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1);
+ RF_WriteReg(dev, 0x0e, 0x0807); mdelay(1); /* RX LO buffer */
+ } else {
+ RF_WriteReg(dev, 0x0c, 0x0fbe); mdelay(1);
+ RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1);
+ RF_WriteReg(dev, 0x0e, 0x0806); mdelay(1); /* RX LO buffer */
}
- RF_WriteReg(dev, 0x0f, 0x0acc); mdelay(1);
-
- RF_WriteReg(dev, 0x00, 0x01d7); mdelay(1); /* 6 */
+ RF_WriteReg(dev, 0x0f, 0x0acc); mdelay(1);
+ RF_WriteReg(dev, 0x00, 0x01d7); mdelay(1); /* 6 */
+ RF_WriteReg(dev, 0x03, 0x0e00); mdelay(1);
+ RF_WriteReg(dev, 0x04, 0x0e50); mdelay(1);
- RF_WriteReg(dev, 0x03, 0x0e00); mdelay(1);
- RF_WriteReg(dev, 0x04, 0x0e50); mdelay(1);
- for (i = 0; i <= 36; i++) {
- RF_WriteReg(dev, 0x01, i); mdelay(1);
+ for (i = 0; i <= 36; i++) {
+ RF_WriteReg(dev, 0x01, i); mdelay(1);
RF_WriteReg(dev, 0x02, ZEBRA_RF_RX_GAIN_TABLE[i]); mdelay(1);
}
- RF_WriteReg(dev, 0x05, 0x0203); mdelay(1); /* 203, 343 */
- RF_WriteReg(dev, 0x06, 0x0200); mdelay(1); /* 400 */
+ RF_WriteReg(dev, 0x05, 0x0203); mdelay(1); /* 203, 343 */
+ RF_WriteReg(dev, 0x06, 0x0200); mdelay(1); /* 400 */
+ RF_WriteReg(dev, 0x00, 0x0137); mdelay(1); /* switch to reg16-reg30, and HSSI disable 137 */
+ mdelay(10); /* Deay 10 ms. */ /* 0xfd */
- RF_WriteReg(dev, 0x00, 0x0137); mdelay(1); /* switch to reg16-reg30, and HSSI disable 137 */
- mdelay(10); /* Deay 10 ms. */ /* 0xfd */
+ RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1); /* Z4 synthesizer loop filter setting, 392 */
+ mdelay(10); /* Deay 10 ms. */ /* 0xfd */
- RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1); /* Z4 synthesizer loop filter setting, 392 */
- mdelay(10); /* Deay 10 ms. */ /* 0xfd */
+ RF_WriteReg(dev, 0x00, 0x0037); mdelay(1); /* switch to reg0-reg15, and HSSI disable */
+ mdelay(10); /* Deay 10 ms. */ /* 0xfd */
- RF_WriteReg(dev, 0x00, 0x0037); mdelay(1); /* switch to reg0-reg15, and HSSI disable */
- mdelay(10); /* Deay 10 ms. */ /* 0xfd */
+ RF_WriteReg(dev, 0x04, 0x0160); mdelay(1); /* CBC on, Tx Rx disable, High gain */
+ mdelay(10); /* Deay 10 ms. */ /* 0xfd */
- RF_WriteReg(dev, 0x04, 0x0160); mdelay(1); /* CBC on, Tx Rx disable, High gain */
- mdelay(10); /* Deay 10 ms. */ /* 0xfd */
+ RF_WriteReg(dev, 0x07, 0x0080); mdelay(1); /* Z4 setted channel 1 */
+ mdelay(10); /* Deay 10 ms. */ /* 0xfd */
- RF_WriteReg(dev, 0x07, 0x0080); mdelay(1); /* Z4 setted channel 1 */
- mdelay(10); /* Deay 10 ms. */ /* 0xfd */
+ RF_WriteReg(dev, 0x02, 0x088D); mdelay(1); /* LC calibration */
+ mdelay(200); /* Deay 200 ms. */ /* 0xfd */
+ mdelay(10); /* Deay 10 ms. */ /* 0xfd */
+ mdelay(10); /* Deay 10 ms. */ /* 0xfd */
- RF_WriteReg(dev, 0x02, 0x088D); mdelay(1); /* LC calibration */
- mdelay(200); /* Deay 200 ms. */ /* 0xfd */
- mdelay(10); /* Deay 10 ms. */ /* 0xfd */
- mdelay(10); /* Deay 10 ms. */ /* 0xfd */
+ RF_WriteReg(dev, 0x00, 0x0137); mdelay(1); /* switch to reg16-reg30 137, and HSSI disable 137 */
+ mdelay(10); /* Deay 10 ms. */ /* 0xfd */
- RF_WriteReg(dev, 0x00, 0x0137); mdelay(1); /* switch to reg16-reg30 137, and HSSI disable 137 */
- mdelay(10); /* Deay 10 ms. */ /* 0xfd */
-
- RF_WriteReg(dev, 0x07, 0x0000); mdelay(1);
- RF_WriteReg(dev, 0x07, 0x0180); mdelay(1);
- RF_WriteReg(dev, 0x07, 0x0220); mdelay(1);
- RF_WriteReg(dev, 0x07, 0x03E0); mdelay(1);
+ RF_WriteReg(dev, 0x07, 0x0000); mdelay(1);
+ RF_WriteReg(dev, 0x07, 0x0180); mdelay(1);
+ RF_WriteReg(dev, 0x07, 0x0220); mdelay(1);
+ RF_WriteReg(dev, 0x07, 0x03E0); mdelay(1);
/* DAC calibration off 20070702 */
- RF_WriteReg(dev, 0x06, 0x00c1); mdelay(1);
- RF_WriteReg(dev, 0x0a, 0x0001); mdelay(1);
-/* {by amy 080312 */
+ RF_WriteReg(dev, 0x06, 0x00c1); mdelay(1);
+ RF_WriteReg(dev, 0x0a, 0x0001); mdelay(1);
/* For crystal calibration, added by Roger, 2007.12.11. */
- if (priv->bXtalCalibration) { /* reg 30. */
- /* enable crystal calibration.
- RF Reg[30], (1)Xin:[12:9], Xout:[8:5], addr[4:0].
- (2)PA Pwr delay timer[15:14], default: 2.4us, set BIT15=0
- (3)RF signal on/off when calibration[13], default: on, set BIT13=0.
- So we should minus 4 BITs offset. */
- RF_WriteReg(dev, 0x0f, (priv->XtalCal_Xin<<5) | (priv->XtalCal_Xout<<1) | BIT11 | BIT9); mdelay(1);
+ if (priv->bXtalCalibration) { /* reg 30. */
+ /*
+ * enable crystal calibration.
+ * RF Reg[30], (1)Xin:[12:9], Xout:[8:5], addr[4:0].
+ * (2)PA Pwr delay timer[15:14], default: 2.4us, set BIT15=0
+ * (3)RF signal on/off when calibration[13], default: on, set BIT13=0.
+ * So we should minus 4 BITs offset.
+ */
+ RF_WriteReg(dev, 0x0f, (priv->XtalCal_Xin<<5) | (priv->XtalCal_Xout<<1) | BIT11 | BIT9); mdelay(1);
printk("ZEBRA_Config_85BASIC_HardCode(): (%02x)\n",
- (priv->XtalCal_Xin<<5) | (priv->XtalCal_Xout<<1) | BIT11 | BIT9);
- } else {
+ (priv->XtalCal_Xin<<5) | (priv->XtalCal_Xout<<1) | BIT11 | BIT9);
+ } else {
/* using default value. Xin=6, Xout=6. */
- RF_WriteReg(dev, 0x0f, 0x0acc); mdelay(1);
+ RF_WriteReg(dev, 0x0f, 0x0acc); mdelay(1);
}
-/* by amy 080312 */
- RF_WriteReg(dev, 0x00, 0x00bf); mdelay(1); /* switch to reg0-reg15, and HSSI enable */
- RF_WriteReg(dev, 0x0d, 0x08df); mdelay(1); /* Rx BB start calibration, 00c//+edward */
- RF_WriteReg(dev, 0x02, 0x004d); mdelay(1); /* temperature meter off */
- RF_WriteReg(dev, 0x04, 0x0975); mdelay(1); /* Rx mode */
+ RF_WriteReg(dev, 0x00, 0x00bf); mdelay(1); /* switch to reg0-reg15, and HSSI enable */
+ RF_WriteReg(dev, 0x0d, 0x08df); mdelay(1); /* Rx BB start calibration, 00c//+edward */
+ RF_WriteReg(dev, 0x02, 0x004d); mdelay(1); /* temperature meter off */
+ RF_WriteReg(dev, 0x04, 0x0975); mdelay(1); /* Rx mode */
mdelay(10); /* Deay 10 ms.*/ /* 0xfe */
mdelay(10); /* Deay 10 ms.*/ /* 0xfe */
mdelay(10); /* Deay 10 ms.*/ /* 0xfe */
- RF_WriteReg(dev, 0x00, 0x0197); mdelay(1); /* Rx mode*/ /*+edward */
- RF_WriteReg(dev, 0x05, 0x05ab); mdelay(1); /* Rx mode*/ /*+edward */
- RF_WriteReg(dev, 0x00, 0x009f); mdelay(1); /* Rx mode*/ /*+edward */
-
- RF_WriteReg(dev, 0x01, 0x0000); mdelay(1); /* Rx mode*/ /*+edward */
- RF_WriteReg(dev, 0x02, 0x0000); mdelay(1); /* Rx mode*/ /*+edward */
- /* power save parameters. */
+ RF_WriteReg(dev, 0x00, 0x0197); mdelay(1); /* Rx mode*/ /*+edward */
+ RF_WriteReg(dev, 0x05, 0x05ab); mdelay(1); /* Rx mode*/ /*+edward */
+ RF_WriteReg(dev, 0x00, 0x009f); mdelay(1); /* Rx mode*/ /*+edward */
+ RF_WriteReg(dev, 0x01, 0x0000); mdelay(1); /* Rx mode*/ /*+edward */
+ RF_WriteReg(dev, 0x02, 0x0000); mdelay(1); /* Rx mode*/ /*+edward */
+ /* power save parameters. */
u1b24E = read_nic_byte(dev, 0x24E);
write_nic_byte(dev, 0x24E, (u1b24E & (~(BIT5|BIT6))));
/*=============================================================================
-
- =============================================================================
- CCKCONF.TXT
- =============================================================================
- */
- /* [POWER SAVE] Power Saving Parameters by jong. 2007-11-27
- CCK reg0x00[7]=1'b1 :power saving for TX (default)
- CCK reg0x00[6]=1'b1: power saving for RX (default)
- CCK reg0x06[4]=1'b1: turn off channel estimation related circuits if not doing channel estimation.
- CCK reg0x06[3]=1'b1: turn off unused circuits before cca = 1
- CCK reg0x06[2]=1'b1: turn off cck's circuit if macrst =0
- */
+ *
+ *===========================================================================
+ * CCKCONF.TXT
+ *===========================================================================
+ *
+ * [POWER SAVE] Power Saving Parameters by jong. 2007-11-27
+ * CCK reg0x00[7]=1'b1 :power saving for TX (default)
+ * CCK reg0x00[6]=1'b1: power saving for RX (default)
+ * CCK reg0x06[4]=1'b1: turn off channel estimation related circuits if not doing channel estimation.
+ * CCK reg0x06[3]=1'b1: turn off unused circuits before cca = 1
+ * CCK reg0x06[2]=1'b1: turn off cck's circuit if macrst =0
+ */
write_phy_cck(dev, 0x00, 0xc8);
write_phy_cck(dev, 0x06, 0x1c);
@@ -697,7 +631,7 @@ ZEBRA_Config_85BASIC_HardCode(
write_phy_cck(dev, 0x2f, 0x06);
write_phy_cck(dev, 0x01, 0x46);
- /* power control */
+ /* power control */
write_nic_byte(dev, CCK_TXAGC, 0x10);
write_nic_byte(dev, OFDM_TXAGC, 0x1B);
write_nic_byte(dev, ANTSEL, 0x03);
@@ -705,14 +639,14 @@ ZEBRA_Config_85BASIC_HardCode(
/*
- =============================================================================
- AGC.txt
- =============================================================================
- */
+ *===========================================================================
+ * AGC.txt
+ *===========================================================================
+ */
write_phy_ofdm(dev, 0x00, 0x12);
- for (i = 0; i < 128; i++) {
+ for (i = 0; i < 128; i++) {
data = ZEBRA_AGC[i+1];
data = data << 8;
@@ -730,49 +664,43 @@ ZEBRA_Config_85BASIC_HardCode(
PlatformIOWrite4Byte(dev, PhyAddr, 0x00001080); /* Annie, 2006-05-05 */
/*
- =============================================================================
-
- =============================================================================
- OFDMCONF.TXT
- =============================================================================
- */
-
- for (i = 0; i < 60; i++) {
+ *===========================================================================
+ *
+ *===========================================================================
+ * OFDMCONF.TXT
+ *===========================================================================
+ */
+
+ for (i = 0; i < 60; i++) {
u4bRegOffset = i;
u4bRegValue = OFDM_CONFIG[i];
WriteBBPortUchar(dev,
- (0x00000080 |
- (u4bRegOffset & 0x7f) |
- ((u4bRegValue & 0xff) << 8)));
+ (0x00000080 |
+ (u4bRegOffset & 0x7f) |
+ ((u4bRegValue & 0xff) << 8)));
}
/*
- =============================================================================
- by amy for antenna
- =============================================================================
- */
-/* {by amy 080312 */
+ *===========================================================================
+ * by amy for antenna
+ *===========================================================================
+ */
/* Config Sw/Hw Combinational Antenna Diversity. Added by Roger, 2008.02.26. */
SetAntennaConfig87SE(dev, priv->bDefaultAntenna1, priv->bSwAntennaDiverity);
-/* by amy 080312} */
-/* by amy for antenna */
}
-void
-UpdateInitialGain(
- struct net_device *dev
- )
+void UpdateInitialGain(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
/* lzm add 080826 */
- if (priv->eRFPowerState != eRfOn) {
+ if (priv->eRFPowerState != eRfOn) {
/* Don't access BB/RF under disable PLL situation.
- RT_TRACE(COMP_DIG, DBG_LOUD, ("UpdateInitialGain - pHalData->eRFPowerState!=eRfOn\n"));
- Back to the original state
- */
+ * RT_TRACE(COMP_DIG, DBG_LOUD, ("UpdateInitialGain - pHalData->eRFPowerState!=eRfOn\n"));
+ * Back to the original state
+ */
priv->InitialGain = priv->InitialGainBackUp;
return;
}
@@ -826,7 +754,7 @@ UpdateInitialGain(
write_phy_ofdm(dev, 0x05, 0xfc); mdelay(1);
break;
- default: /* MP */
+ default: /* MP */
write_phy_ofdm(dev, 0x17, 0x26); mdelay(1);
write_phy_ofdm(dev, 0x24, 0x86); mdelay(1);
write_phy_ofdm(dev, 0x05, 0xfa); mdelay(1);
@@ -834,14 +762,11 @@ UpdateInitialGain(
}
}
/*
- Description:
- Tx Power tracking mechanism routine on 87SE.
- Created by Roger, 2007.12.11.
-*/
-void
-InitTxPwrTracking87SE(
- struct net_device *dev
-)
+ * Description:
+ * Tx Power tracking mechanism routine on 87SE.
+ * Created by Roger, 2007.12.11.
+ */
+void InitTxPwrTracking87SE(struct net_device *dev)
{
u32 u4bRfReg;
@@ -851,49 +776,41 @@ InitTxPwrTracking87SE(
RF_WriteReg(dev, 0x02, u4bRfReg|PWR_METER_EN); mdelay(1);
}
-void
-PhyConfig8185(
- struct net_device *dev
- )
+void PhyConfig8185(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
write_nic_dword(dev, RCR, priv->ReceiveConfig);
priv->RFProgType = read_nic_byte(dev, CONFIG4) & 0x03;
/* RF config */
ZEBRA_Config_85BASIC_HardCode(dev);
-/* {by amy 080312 */
/* Set default initial gain state to 4, approved by SD3 DZ, by Bruce, 2007-06-06. */
- if (priv->bDigMechanism) {
+ if (priv->bDigMechanism) {
if (priv->InitialGain == 0)
priv->InitialGain = 4;
}
/*
- Enable thermal meter indication to implement TxPower tracking on 87SE.
- We initialize thermal meter here to avoid unsuccessful configuration.
- Added by Roger, 2007.12.11.
- */
+ * Enable thermal meter indication to implement TxPower tracking on 87SE.
+ * We initialize thermal meter here to avoid unsuccessful configuration.
+ * Added by Roger, 2007.12.11.
+ */
if (priv->bTxPowerTrack)
InitTxPwrTracking87SE(dev);
-/* by amy 080312} */
priv->InitialGainBackUp = priv->InitialGain;
UpdateInitialGain(dev);
return;
}
-void
-HwConfigureRTL8185(
- struct net_device *dev
- )
+void HwConfigureRTL8185(struct net_device *dev)
{
/* RTL8185_TODO: Determine Retrylimit, TxAGC, AutoRateFallback control. */
- u8 bUNIVERSAL_CONTROL_RL = 0;
- u8 bUNIVERSAL_CONTROL_AGC = 1;
- u8 bUNIVERSAL_CONTROL_ANT = 1;
- u8 bAUTO_RATE_FALLBACK_CTL = 1;
- u8 val8;
+ u8 bUNIVERSAL_CONTROL_RL = 0;
+ u8 bUNIVERSAL_CONTROL_AGC = 1;
+ u8 bUNIVERSAL_CONTROL_ANT = 1;
+ u8 bAUTO_RATE_FALLBACK_CTL = 1;
+ u8 val8;
write_nic_word(dev, BRSR, 0x0fff);
/* Retry limit */
val8 = read_nic_byte(dev, CW_CONF);
@@ -907,24 +824,24 @@ HwConfigureRTL8185(
/* Tx AGC */
val8 = read_nic_byte(dev, TXAGC_CTL);
- if (bUNIVERSAL_CONTROL_AGC) {
+ if (bUNIVERSAL_CONTROL_AGC) {
write_nic_byte(dev, CCK_TXAGC, 128);
write_nic_byte(dev, OFDM_TXAGC, 128);
val8 = val8 & 0xfe;
- } else {
+ } else {
val8 = val8 | 0x01 ;
}
write_nic_byte(dev, TXAGC_CTL, val8);
- /* Tx Antenna including Feedback control */
+ /* Tx Antenna including Feedback control */
val8 = read_nic_byte(dev, TXAGC_CTL);
- if (bUNIVERSAL_CONTROL_ANT) {
+ if (bUNIVERSAL_CONTROL_ANT) {
write_nic_byte(dev, ANTSEL, 0x00);
val8 = val8 & 0xfd;
- } else {
+ } else {
val8 = val8 & (val8|0x02); /* xiong-2006-11-15 */
}
@@ -933,7 +850,7 @@ HwConfigureRTL8185(
/* Auto Rate fallback control */
val8 = read_nic_byte(dev, RATE_FALLBACK);
val8 &= 0x7c;
- if (bAUTO_RATE_FALLBACK_CTL) {
+ if (bAUTO_RATE_FALLBACK_CTL) {
val8 |= RATE_FALLBACK_CTL_ENABLE | RATE_FALLBACK_CTL_AUTO_STEP1;
/* <RJ_TODO_8185B> We shall set up the ARFR according to user's setting. */
@@ -942,40 +859,34 @@ HwConfigureRTL8185(
write_nic_byte(dev, RATE_FALLBACK, val8);
}
-static void
-MacConfig_85BASIC_HardCode(
- struct net_device *dev)
+static void MacConfig_85BASIC_HardCode(struct net_device *dev)
{
/*
- ============================================================================
- MACREG.TXT
- ============================================================================
- */
- int nLinesRead = 0;
-
- u32 u4bRegOffset, u4bRegValue, u4bPageIndex = 0;
- int i;
+ *==========================================================================
+ * MACREG.TXT
+ *==========================================================================
+ */
+ int nLinesRead = 0;
+ u32 u4bRegOffset, u4bRegValue, u4bPageIndex = 0;
+ int i;
nLinesRead = sizeof(MAC_REG_TABLE)/2;
- for (i = 0; i < nLinesRead; i++) { /* nLinesRead=101 */
+ for (i = 0; i < nLinesRead; i++) { /* nLinesRead=101 */
u4bRegOffset = MAC_REG_TABLE[i][0];
u4bRegValue = MAC_REG_TABLE[i][1];
if (u4bRegOffset == 0x5e)
u4bPageIndex = u4bRegValue;
-
else
- u4bRegOffset |= (u4bPageIndex << 8);
+ u4bRegOffset |= (u4bPageIndex << 8);
write_nic_byte(dev, u4bRegOffset, (u8)u4bRegValue);
}
/* ============================================================================ */
}
-static void
-MacConfig_85BASIC(
- struct net_device *dev)
+static void MacConfig_85BASIC(struct net_device *dev)
{
u8 u1DA;
@@ -994,18 +905,18 @@ MacConfig_85BASIC(
PlatformIOWrite4Byte(dev, 0x1F4, 0x00000000);
PlatformIOWrite1Byte(dev, 0x1F8, 0x00);
- /* Asked for by SD3 CM Lin, 2006.06.27, by rcnjko. */
- /* power save parameter based on "87SE power save parameters 20071127.doc", as follow. */
+ /* Asked for by SD3 CM Lin, 2006.06.27, by rcnjko. */
+ /* power save parameter based on "87SE power save parameters 20071127.doc", as follow. */
/* Enable DA10 TX power saving */
u1DA = read_nic_byte(dev, PHYPR);
write_nic_byte(dev, PHYPR, (u1DA | BIT2));
- /* POWER: */
+ /* POWER: */
write_nic_word(dev, 0x360, 0x1000);
write_nic_word(dev, 0x362, 0x1000);
- /* AFE. */
+ /* AFE. */
write_nic_word(dev, 0x370, 0x0560);
write_nic_word(dev, 0x372, 0x0560);
write_nic_word(dev, 0x374, 0x0DA4);
@@ -1013,54 +924,48 @@ MacConfig_85BASIC(
write_nic_word(dev, 0x378, 0x0560);
write_nic_word(dev, 0x37A, 0x0560);
write_nic_word(dev, 0x37C, 0x00EC);
- write_nic_word(dev, 0x37E, 0x00EC); /*+edward */
+ write_nic_word(dev, 0x37E, 0x00EC); /* +edward */
write_nic_byte(dev, 0x24E, 0x01);
}
-u8
-GetSupportedWirelessMode8185(
- struct net_device *dev
-)
+u8 GetSupportedWirelessMode8185(struct net_device *dev)
{
- u8 btSupportedWirelessMode = 0;
+ u8 btSupportedWirelessMode = 0;
btSupportedWirelessMode = (WIRELESS_MODE_B | WIRELESS_MODE_G);
return btSupportedWirelessMode;
}
-void
-ActUpdateChannelAccessSetting(
- struct net_device *dev,
- WIRELESS_MODE WirelessMode,
- PCHANNEL_ACCESS_SETTING ChnlAccessSetting
- )
+void ActUpdateChannelAccessSetting(struct net_device *dev,
+ WIRELESS_MODE WirelessMode,
+ PCHANNEL_ACCESS_SETTING ChnlAccessSetting)
{
- struct r8180_priv *priv = ieee80211_priv(dev);
- struct ieee80211_device *ieee = priv->ieee80211;
+ struct r8180_priv *priv = ieee80211_priv(dev);
+ struct ieee80211_device *ieee = priv->ieee80211;
AC_CODING eACI;
AC_PARAM AcParam;
- u8 bFollowLegacySetting = 0;
- u8 u1bAIFS;
+ u8 bFollowLegacySetting = 0;
+ u8 u1bAIFS;
/*
- <RJ_TODO_8185B>
- TODO: We still don't know how to set up these registers, just follow WMAC to
- verify 8185B FPAG.
-
- <RJ_TODO_8185B>
- Jong said CWmin/CWmax register are not functional in 8185B,
- so we shall fill channel access realted register into AC parameter registers,
- even in nQBss.
- */
+ * <RJ_TODO_8185B>
+ * TODO: We still don't know how to set up these registers, just follow WMAC to
+ * verify 8185B FPAG.
+ *
+ * <RJ_TODO_8185B>
+ * Jong said CWmin/CWmax register are not functional in 8185B,
+ * so we shall fill channel access realted register into AC parameter registers,
+ * even in nQBss.
+ */
ChnlAccessSetting->SIFS_Timer = 0x22; /* Suggested by Jong, 2005.12.08. */
- ChnlAccessSetting->DIFS_Timer = 0x1C; /* 2006.06.02, by rcnjko. */
- ChnlAccessSetting->SlotTimeTimer = 9; /* 2006.06.02, by rcnjko. */
- ChnlAccessSetting->EIFS_Timer = 0x5B; /* Suggested by wcchu, it is the default value of EIFS register, 2005.12.08. */
- ChnlAccessSetting->CWminIndex = 3; /* 2006.06.02, by rcnjko. */
- ChnlAccessSetting->CWmaxIndex = 7; /* 2006.06.02, by rcnjko. */
+ ChnlAccessSetting->DIFS_Timer = 0x1C; /* 2006.06.02, by rcnjko. */
+ ChnlAccessSetting->SlotTimeTimer = 9; /* 2006.06.02, by rcnjko. */
+ ChnlAccessSetting->EIFS_Timer = 0x5B; /* Suggested by wcchu, it is the default value of EIFS register, 2005.12.08. */
+ ChnlAccessSetting->CWminIndex = 3; /* 2006.06.02, by rcnjko. */
+ ChnlAccessSetting->CWmaxIndex = 7; /* 2006.06.02, by rcnjko. */
write_nic_byte(dev, SIFS, ChnlAccessSetting->SIFS_Timer);
- write_nic_byte(dev, SLOT, ChnlAccessSetting->SlotTimeTimer); /* Rewrited from directly use PlatformEFIOWrite1Byte(), by Annie, 2006-03-29. */
+ write_nic_byte(dev, SLOT, ChnlAccessSetting->SlotTimeTimer); /* Rewrited from directly use PlatformEFIOWrite1Byte(), by Annie, 2006-03-29. */
u1bAIFS = aSifsTime + (2 * ChnlAccessSetting->SlotTimeTimer);
@@ -1074,17 +979,17 @@ ActUpdateChannelAccessSetting(
}
/* this setting is copied from rtl8187B. xiong-2006-11-13 */
- if (bFollowLegacySetting) {
+ if (bFollowLegacySetting) {
/*
- Follow 802.11 seeting to AC parameter, all AC shall use the same parameter.
- 2005.12.01, by rcnjko.
- */
+ * Follow 802.11 seeting to AC parameter, all AC shall use the same parameter.
+ * 2005.12.01, by rcnjko.
+ */
AcParam.longData = 0;
AcParam.f.AciAifsn.f.AIFSN = 2; /* Follow 802.11 DIFS. */
AcParam.f.AciAifsn.f.ACM = 0;
- AcParam.f.Ecw.f.ECWmin = ChnlAccessSetting->CWminIndex; /* Follow 802.11 CWmin. */
- AcParam.f.Ecw.f.ECWmax = ChnlAccessSetting->CWmaxIndex; /* Follow 802.11 CWmax. */
+ AcParam.f.Ecw.f.ECWmin = ChnlAccessSetting->CWminIndex; /* Follow 802.11 CWmin. */
+ AcParam.f.Ecw.f.ECWmax = ChnlAccessSetting->CWmaxIndex; /* Follow 802.11 CWmax. */
AcParam.f.TXOPLimit = 0;
/* lzm reserved 080826 */
@@ -1095,7 +1000,7 @@ ActUpdateChannelAccessSetting(
if (ieee->iw_mode == IW_MODE_ADHOC)
AcParam.f.TXOPLimit = 0x0020;
- for (eACI = 0; eACI < AC_MAX; eACI++) {
+ for (eACI = 0; eACI < AC_MAX; eACI++) {
AcParam.f.AciAifsn.f.ACI = (u8)eACI;
{
PAC_PARAM pAcParam = (PAC_PARAM)(&AcParam);
@@ -1103,7 +1008,7 @@ ActUpdateChannelAccessSetting(
u8 u1bAIFS;
u32 u4bAcParam;
- /* Retrive paramters to udpate. */
+ /* Retrieve paramters to update. */
eACI = pAcParam->f.AciAifsn.f.ACI;
u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * ChnlAccessSetting->SlotTimeTimer + aSifsTime;
u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit)) << AC_PARAM_TXOP_LIMIT_OFFSET) |
@@ -1111,7 +1016,7 @@ ActUpdateChannelAccessSetting(
(((u32)(pAcParam->f.Ecw.f.ECWmin)) << AC_PARAM_ECW_MIN_OFFSET) |
(((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET));
- switch (eACI) {
+ switch (eACI) {
case AC1_BK:
/* write_nic_dword(dev, AC_BK_PARAM, u4bAcParam); */
break;
@@ -1133,47 +1038,46 @@ ActUpdateChannelAccessSetting(
break;
}
- /* Cehck ACM bit. */
+ /* Cehck ACM bit. */
/* If it is set, immediately set ACM control bit to downgrading AC for passing WMM testplan. Annie, 2005-12-13. */
{
PACI_AIFSN pAciAifsn = (PACI_AIFSN)(&pAcParam->f.AciAifsn);
AC_CODING eACI = pAciAifsn->f.ACI;
- /*modified Joseph */
- /*for 8187B AsynIORead issue */
+ /*for 8187B AsynIORead issue */
u8 AcmCtrl = 0;
- if (pAciAifsn->f.ACM) {
+ if (pAciAifsn->f.ACM) {
/* ACM bit is 1. */
- switch (eACI) {
+ switch (eACI) {
case AC0_BE:
- AcmCtrl |= (BEQ_ACM_EN|BEQ_ACM_CTL|ACM_HW_EN); /* or 0x21 */
+ AcmCtrl |= (BEQ_ACM_EN|BEQ_ACM_CTL|ACM_HW_EN); /* or 0x21 */
break;
case AC2_VI:
- AcmCtrl |= (VIQ_ACM_EN|VIQ_ACM_CTL|ACM_HW_EN); /* or 0x42 */
+ AcmCtrl |= (VIQ_ACM_EN|VIQ_ACM_CTL|ACM_HW_EN); /* or 0x42 */
break;
case AC3_VO:
- AcmCtrl |= (VOQ_ACM_EN|VOQ_ACM_CTL|ACM_HW_EN); /* or 0x84 */
+ AcmCtrl |= (VOQ_ACM_EN|VOQ_ACM_CTL|ACM_HW_EN); /* or 0x84 */
break;
default:
DMESGW("SetHwReg8185(): [HW_VAR_ACM_CTRL] ACM set failed: eACI is %d\n", eACI);
break;
}
- } else {
+ } else {
/* ACM bit is 0. */
- switch (eACI) {
+ switch (eACI) {
case AC0_BE:
- AcmCtrl &= ((~BEQ_ACM_EN) & (~BEQ_ACM_CTL) & (~ACM_HW_EN)); /* and 0xDE */
+ AcmCtrl &= ((~BEQ_ACM_EN) & (~BEQ_ACM_CTL) & (~ACM_HW_EN)); /* and 0xDE */
break;
case AC2_VI:
- AcmCtrl &= ((~VIQ_ACM_EN) & (~VIQ_ACM_CTL) & (~ACM_HW_EN)); /* and 0xBD */
+ AcmCtrl &= ((~VIQ_ACM_EN) & (~VIQ_ACM_CTL) & (~ACM_HW_EN)); /* and 0xBD */
break;
case AC3_VO:
- AcmCtrl &= ((~VOQ_ACM_EN) & (~VOQ_ACM_CTL) & (~ACM_HW_EN)); /* and 0x7B */
+ AcmCtrl &= ((~VOQ_ACM_EN) & (~VOQ_ACM_CTL) & (~ACM_HW_EN)); /* and 0x7B */
break;
default:
@@ -1187,53 +1091,51 @@ ActUpdateChannelAccessSetting(
}
}
-void
-ActSetWirelessMode8185(
- struct net_device *dev,
- u8 btWirelessMode
- )
+void ActSetWirelessMode8185(struct net_device *dev, u8 btWirelessMode)
{
- struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
- struct ieee80211_device *ieee = priv->ieee80211;
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
+ struct ieee80211_device *ieee = priv->ieee80211;
u8 btSupportedWirelessMode = GetSupportedWirelessMode8185(dev);
if ((btWirelessMode & btSupportedWirelessMode) == 0) {
- /* Don't switch to unsupported wireless mode, 2006.02.15, by rcnjko. */
+ /* Don't switch to unsupported wireless mode, 2006.02.15, by rcnjko. */
DMESGW("ActSetWirelessMode8185(): WirelessMode(%d) is not supported (%d)!\n",
btWirelessMode, btSupportedWirelessMode);
return;
}
- /* 1. Assign wireless mode to swtich if necessary. */
- if (btWirelessMode == WIRELESS_MODE_AUTO) {
- if ((btSupportedWirelessMode & WIRELESS_MODE_A)) {
+ /* 1. Assign wireless mode to switch if necessary. */
+ if (btWirelessMode == WIRELESS_MODE_AUTO) {
+ if ((btSupportedWirelessMode & WIRELESS_MODE_A)) {
btWirelessMode = WIRELESS_MODE_A;
- } else if (btSupportedWirelessMode & WIRELESS_MODE_G) {
+ } else if (btSupportedWirelessMode & WIRELESS_MODE_G) {
btWirelessMode = WIRELESS_MODE_G;
- } else if ((btSupportedWirelessMode & WIRELESS_MODE_B)) {
- btWirelessMode = WIRELESS_MODE_B;
- } else {
- DMESGW("ActSetWirelessMode8185(): No valid wireless mode supported, btSupportedWirelessMode(%x)!!!\n",
- btSupportedWirelessMode);
+ } else if ((btSupportedWirelessMode & WIRELESS_MODE_B)) {
btWirelessMode = WIRELESS_MODE_B;
+ } else {
+ DMESGW("ActSetWirelessMode8185(): No valid wireless mode supported, btSupportedWirelessMode(%x)!!!\n",
+ btSupportedWirelessMode);
+ btWirelessMode = WIRELESS_MODE_B;
}
}
- /* 2. Swtich band: RF or BB specific actions,
+ /*
+ * 2. Swtich band: RF or BB specific actions,
* for example, refresh tables in omc8255, or change initial gain if necessary.
* Nothing to do for Zebra to switch band.
- * Update current wireless mode if we swtich to specified band successfully. */
+ * Update current wireless mode if we switch to specified band successfully.
+ */
ieee->mode = (WIRELESS_MODE)btWirelessMode;
- /* 3. Change related setting. */
- if( ieee->mode == WIRELESS_MODE_A ) {
+ /* 3. Change related setting. */
+ if( ieee->mode == WIRELESS_MODE_A ) {
DMESG("WIRELESS_MODE_A\n");
- } else if( ieee->mode == WIRELESS_MODE_B ) {
- DMESG("WIRELESS_MODE_B\n");
- } else if( ieee->mode == WIRELESS_MODE_G ) {
- DMESG("WIRELESS_MODE_G\n");
+ } else if( ieee->mode == WIRELESS_MODE_B ) {
+ DMESG("WIRELESS_MODE_B\n");
+ } else if( ieee->mode == WIRELESS_MODE_G ) {
+ DMESG("WIRELESS_MODE_G\n");
}
ActUpdateChannelAccessSetting( dev, ieee->mode, &priv->ChannelAccessSetting);
}
@@ -1245,22 +1147,16 @@ void rtl8185b_irq_enable(struct net_device *dev)
priv->irq_enabled = 1;
write_nic_dword(dev, IMR, priv->IntrMask);
}
-/* by amy for power save */
-void
-DrvIFIndicateDisassociation(
- struct net_device *dev,
- u16 reason
- )
+
+void DrvIFIndicateDisassociation(struct net_device *dev, u16 reason)
{
/* nothing is needed after disassociation request. */
- }
-void
-MgntDisconnectIBSS(
- struct net_device *dev
-)
+}
+
+void MgntDisconnectIBSS(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
- u8 i;
+ u8 i;
DrvIFIndicateDisassociation(dev, unspec_reason);
@@ -1271,166 +1167,143 @@ MgntDisconnectIBSS(
priv->ieee80211->state = IEEE80211_NOLINK;
/*
- Stop Beacon.
-
- Vista add a Adhoc profile, HW radio off until OID_DOT11_RESET_REQUEST
- Driver would set MSR=NO_LINK, then HW Radio ON, MgntQueue Stuck.
- Because Bcn DMA isn't complete, mgnt queue would stuck until Bcn packet send.
-
- Disable Beacon Queue Own bit, suggested by jong */
+ * Stop Beacon.
+ *
+ * Vista add a Adhoc profile, HW radio off until OID_DOT11_RESET_REQUEST
+ * Driver would set MSR=NO_LINK, then HW Radio ON, MgntQueue Stuck.
+ * Because Bcn DMA isn't complete, mgnt queue would stuck until Bcn packet send.
+ *
+ * Disable Beacon Queue Own bit, suggested by jong
+ */
ieee80211_stop_send_beacons(priv->ieee80211);
priv->ieee80211->link_change(dev);
notify_wx_assoc_event(priv->ieee80211);
}
-void
-MlmeDisassociateRequest(
- struct net_device *dev,
- u8 *asSta,
- u8 asRsn
- )
+
+void MlmeDisassociateRequest(struct net_device *dev, u8 *asSta, u8 asRsn)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
u8 i;
SendDisassociation(priv->ieee80211, asSta, asRsn);
- if (memcmp(priv->ieee80211->current_network.bssid, asSta, 6) == 0) {
- /*ShuChen TODO: change media status. */
- /*ShuChen TODO: What to do when disassociate. */
+ if (memcmp(priv->ieee80211->current_network.bssid, asSta, 6) == 0) {
+ /* ShuChen TODO: change media status. */
+ /* ShuChen TODO: What to do when disassociate. */
DrvIFIndicateDisassociation(dev, unspec_reason);
-
-
for (i = 0; i < 6; i++)
priv->ieee80211->current_network.bssid[i] = 0x22;
ieee80211_disassociate(priv->ieee80211);
}
-
}
-void
-MgntDisconnectAP(
- struct net_device *dev,
- u8 asRsn
-)
+void MgntDisconnectAP(struct net_device *dev, u8 asRsn)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
/*
- Commented out by rcnjko, 2005.01.27:
- I move SecClearAllKeys() to MgntActSet_802_11_DISASSOCIATE().
-
- 2004/09/15, kcwu, the key should be cleared, or the new handshaking will not success
-
- In WPA WPA2 need to Clear all key ... because new key will set after new handshaking.
- 2004.10.11, by rcnjko. */
+ * Commented out by rcnjko, 2005.01.27:
+ * I move SecClearAllKeys() to MgntActSet_802_11_DISASSOCIATE().
+ *
+ * 2004/09/15, kcwu, the key should be cleared, or the new handshaking will not success
+ *
+ * In WPA WPA2 need to Clear all key ... because new key will set after new handshaking.
+ * 2004.10.11, by rcnjko.
+ */
MlmeDisassociateRequest(dev, priv->ieee80211->current_network.bssid, asRsn);
priv->ieee80211->state = IEEE80211_NOLINK;
}
-bool
-MgntDisconnect(
- struct net_device *dev,
- u8 asRsn
-)
+
+bool MgntDisconnect(struct net_device *dev, u8 asRsn)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
/*
- Schedule an workitem to wake up for ps mode, 070109, by rcnjko.
- */
+ * Schedule an workitem to wake up for ps mode, 070109, by rcnjko.
+ */
if (IS_DOT11D_ENABLE(priv->ieee80211))
Dot11d_Reset(priv->ieee80211);
- /* In adhoc mode, update beacon frame. */
+ /* In adhoc mode, update beacon frame. */
if (priv->ieee80211->state == IEEE80211_LINKED) {
if (priv->ieee80211->iw_mode == IW_MODE_ADHOC)
MgntDisconnectIBSS(dev);
- if (priv->ieee80211->iw_mode == IW_MODE_INFRA) {
- /* We clear key here instead of MgntDisconnectAP() because that
- MgntActSet_802_11_DISASSOCIATE() is an interface called by OS,
- e.g. OID_802_11_DISASSOCIATE in Windows while as MgntDisconnectAP() is
- used to handle disassociation related things to AP, e.g. send Disassoc
- frame to AP. 2005.01.27, by rcnjko. */
+ if (priv->ieee80211->iw_mode == IW_MODE_INFRA) {
+ /*
+ * We clear key here instead of MgntDisconnectAP() because that
+ * MgntActSet_802_11_DISASSOCIATE() is an interface called by OS,
+ * e.g. OID_802_11_DISASSOCIATE in Windows while as MgntDisconnectAP() is
+ * used to handle disassociation related things to AP, e.g. send Disassoc
+ * frame to AP. 2005.01.27, by rcnjko.
+ */
MgntDisconnectAP(dev, asRsn);
}
- /* Inidicate Disconnect, 2005.02.23, by rcnjko. */
+ /* Indicate Disconnect, 2005.02.23, by rcnjko. */
}
return true;
}
/*
- Description:
- Chang RF Power State.
- Note that, only MgntActSet_RF_State() is allowed to set HW_VAR_RF_STATE.
-
- Assumption:
- PASSIVE LEVEL.
-*/
-bool
-SetRFPowerState(
- struct net_device *dev,
- RT_RF_POWER_STATE eRFPowerState
- )
+ * Description:
+ * Chang RF Power State.
+ * Note that, only MgntActSet_RF_State() is allowed to set HW_VAR_RF_STATE.
+ *
+ * Assumption:
+ * PASSIVE LEVEL.
+ */
+bool SetRFPowerState(struct net_device *dev, RT_RF_POWER_STATE eRFPowerState)
{
- struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
- bool bResult = false;
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
+ bool bResult = false;
if (eRFPowerState == priv->eRFPowerState)
return bResult;
- bResult = SetZebraRFPowerState8185(dev, eRFPowerState);
+ bResult = SetZebraRFPowerState8185(dev, eRFPowerState);
return bResult;
}
-void
-HalEnableRx8185Dummy(
- struct net_device *dev
- )
+
+void HalEnableRx8185Dummy(struct net_device *dev)
{
}
-void
-HalDisableRx8185Dummy(
- struct net_device *dev
- )
+
+void HalDisableRx8185Dummy(struct net_device *dev)
{
}
-bool
-MgntActSet_RF_State(
- struct net_device *dev,
- RT_RF_POWER_STATE StateToSet,
- u32 ChangeSource
- )
+bool MgntActSet_RF_State(struct net_device *dev, RT_RF_POWER_STATE StateToSet, u32 ChangeSource)
{
- struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
- bool bActionAllowed = false;
- bool bConnectBySSID = false;
- RT_RF_POWER_STATE rtState;
- u16 RFWaitCounter = 0;
+ struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
+ bool bActionAllowed = false;
+ bool bConnectBySSID = false;
+ RT_RF_POWER_STATE rtState;
+ u16 RFWaitCounter = 0;
unsigned long flag;
/*
- Prevent the race condition of RF state change. By Bruce, 2007-11-28.
- Only one thread can change the RF state at one time, and others should wait to be executed.
- */
- while (true) {
+ * Prevent the race condition of RF state change. By Bruce, 2007-11-28.
+ * Only one thread can change the RF state at one time, and others should wait to be executed.
+ */
+ while (true) {
spin_lock_irqsave(&priv->rf_ps_lock, flag);
- if (priv->RFChangeInProgress) {
+ if (priv->RFChangeInProgress) {
spin_unlock_irqrestore(&priv->rf_ps_lock, flag);
/* Set RF after the previous action is done. */
- while (priv->RFChangeInProgress) {
+ while (priv->RFChangeInProgress) {
RFWaitCounter++;
udelay(1000); /* 1 ms */
- /* Wait too long, return FALSE to avoid to be stuck here. */
- if (RFWaitCounter > 1000) { /* 1sec */
+ /* Wait too long, return FALSE to avoid to be stuck here. */
+ if (RFWaitCounter > 1000) { /* 1sec */
printk("MgntActSet_RF_State(): Wait too long to set RF\n");
- /* TODO: Reset RF state? */
+ /* TODO: Reset RF state? */
return false;
}
}
- } else {
+ } else {
priv->RFChangeInProgress = true;
spin_unlock_irqrestore(&priv->rf_ps_lock, flag);
break;
@@ -1438,12 +1311,12 @@ MgntActSet_RF_State(
}
rtState = priv->eRFPowerState;
- switch (StateToSet) {
+ switch (StateToSet) {
case eRfOn:
/*
- Turn On RF no matter the IPS setting because we need to update the RF state to Ndis under Vista, or
- the Windows does not allow the driver to perform site survey any more. By Bruce, 2007-10-02.
- */
+ * Turn On RF no matter the IPS setting because we need to update the RF state to Ndis under Vista, or
+ * the Windows does not allow the driver to perform site survey any more. By Bruce, 2007-10-02.
+ */
priv->RfOffReason &= (~ChangeSource);
if (!priv->RfOffReason) {
@@ -1453,25 +1326,24 @@ MgntActSet_RF_State(
if (rtState == eRfOff && ChangeSource >= RF_CHANGE_BY_HW && !priv->bInHctTest)
bConnectBySSID = true;
- } else
- ;
+ } else
+ ;
break;
case eRfOff:
- /* 070125, rcnjko: we always keep connected in AP mode. */
-
- if (priv->RfOffReason > RF_CHANGE_BY_IPS) {
- /*
- 060808, Annie:
- Disconnect to current BSS when radio off. Asked by QuanTa.
-
- Calling MgntDisconnect() instead of MgntActSet_802_11_DISASSOCIATE(),
- because we do NOT need to set ssid to dummy ones.
- */
- MgntDisconnect(dev, disas_lv_ss);
-
- /* Clear content of bssDesc[] and bssDesc4Query[] to avoid reporting old bss to UI. */
- }
+ /* 070125, rcnjko: we always keep connected in AP mode. */
+
+ if (priv->RfOffReason > RF_CHANGE_BY_IPS) {
+ /*
+ * 060808, Annie:
+ * Disconnect to current BSS when radio off. Asked by QuanTa.
+ *
+ * Calling MgntDisconnect() instead of MgntActSet_802_11_DISASSOCIATE(),
+ * because we do NOT need to set ssid to dummy ones.
+ */
+ MgntDisconnect(dev, disas_lv_ss);
+ /* Clear content of bssDesc[] and bssDesc4Query[] to avoid reporting old bss to UI. */
+ }
priv->RfOffReason |= ChangeSource;
bActionAllowed = true;
@@ -1484,14 +1356,14 @@ MgntActSet_RF_State(
break;
}
- if (bActionAllowed) {
- /* Config HW to the specified mode. */
+ if (bActionAllowed) {
+ /* Config HW to the specified mode. */
SetRFPowerState(dev, StateToSet);
/* Turn on RF. */
- if (StateToSet == eRfOn) {
+ if (StateToSet == eRfOn) {
HalEnableRx8185Dummy(dev);
- if (bConnectBySSID) {
+ if (bConnectBySSID) {
/* by amy not supported */
}
}
@@ -1507,69 +1379,61 @@ MgntActSet_RF_State(
spin_unlock_irqrestore(&priv->rf_ps_lock, flag);
return bActionAllowed;
}
-void
-InactivePowerSave(
- struct net_device *dev
- )
+
+void InactivePowerSave(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
/*
- This flag "bSwRfProcessing", indicates the status of IPS procedure, should be set if the IPS workitem
- is really scheduled.
- The old code, sets this flag before scheduling the IPS workitem and however, at the same time the
- previous IPS workitem did not end yet, fails to schedule the current workitem. Thus, bSwRfProcessing
- blocks the IPS procedure of switching RF.
- */
+ * This flag "bSwRfProcessing", indicates the status of IPS procedure, should be set if the IPS workitem
+ * is really scheduled.
+ * The old code, sets this flag before scheduling the IPS workitem and however, at the same time the
+ * previous IPS workitem did not end yet, fails to schedule the current workitem. Thus, bSwRfProcessing
+ * blocks the IPS procedure of switching RF.
+ */
priv->bSwRfProcessing = true;
MgntActSet_RF_State(dev, priv->eInactivePowerState, RF_CHANGE_BY_IPS);
/*
- To solve CAM values miss in RF OFF, rewrite CAM values after RF ON. By Bruce, 2007-09-20.
- */
+ * To solve CAM values miss in RF OFF, rewrite CAM values after RF ON. By Bruce, 2007-09-20.
+ */
priv->bSwRfProcessing = false;
}
/*
- Description:
- Enter the inactive power save mode. RF will be off
-*/
-void
-IPSEnter(
- struct net_device *dev
- )
+ * Description:
+ * Enter the inactive power save mode. RF will be off
+ */
+void IPSEnter(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
RT_RF_POWER_STATE rtState;
- if (priv->bInactivePs) {
+ if (priv->bInactivePs) {
rtState = priv->eRFPowerState;
/*
- Do not enter IPS in the following conditions:
- (1) RF is already OFF or Sleep
- (2) bSwRfProcessing (indicates the IPS is still under going)
- (3) Connectted (only disconnected can trigger IPS)
- (4) IBSS (send Beacon)
- (5) AP mode (send Beacon)
- */
+ * Do not enter IPS in the following conditions:
+ * (1) RF is already OFF or Sleep
+ * (2) bSwRfProcessing (indicates the IPS is still under going)
+ * (3) Connected (only disconnected can trigger IPS)
+ * (4) IBSS (send Beacon)
+ * (5) AP mode (send Beacon)
+ */
if (rtState == eRfOn && !priv->bSwRfProcessing
- && (priv->ieee80211->state != IEEE80211_LINKED)) {
+ && (priv->ieee80211->state != IEEE80211_LINKED)) {
priv->eInactivePowerState = eRfOff;
InactivePowerSave(dev);
}
}
}
-void
-IPSLeave(
- struct net_device *dev
- )
+void IPSLeave(struct net_device *dev)
{
struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev);
RT_RF_POWER_STATE rtState;
- if (priv->bInactivePs) {
+ if (priv->bInactivePs) {
rtState = priv->eRFPowerState;
- if ((rtState == eRfOff || rtState == eRfSleep) && (!priv->bSwRfProcessing) && priv->RfOffReason <= RF_CHANGE_BY_IPS) {
+ if ((rtState == eRfOff || rtState == eRfSleep) && (!priv->bSwRfProcessing) && priv->RfOffReason <= RF_CHANGE_BY_IPS) {
priv->eInactivePowerState = eRfOn;
InactivePowerSave(dev);
}
@@ -1582,8 +1446,8 @@ void rtl8185b_adapter_start(struct net_device *dev)
struct ieee80211_device *ieee = priv->ieee80211;
u8 SupportedWirelessMode;
- u8 InitWirelessMode;
- u8 bInvalidWirelessMode = 0;
+ u8 InitWirelessMode;
+ u8 bInvalidWirelessMode = 0;
u8 tmpu8;
u8 btCR9346;
u8 TmpU1b;
@@ -1598,89 +1462,89 @@ void rtl8185b_adapter_start(struct net_device *dev)
HwConfigureRTL8185(dev);
write_nic_dword(dev, MAC0, ((u32 *)dev->dev_addr)[0]);
write_nic_word(dev, MAC4, ((u32 *)dev->dev_addr)[1] & 0xffff);
- write_nic_byte(dev, MSR, read_nic_byte(dev, MSR) & 0xf3); /* default network type to 'No Link' */
+ write_nic_byte(dev, MSR, read_nic_byte(dev, MSR) & 0xf3); /* default network type to 'No Link' */
write_nic_word(dev, BcnItv, 100);
write_nic_word(dev, AtimWnd, 2);
PlatformIOWrite2Byte(dev, FEMR, 0xFFFF);
write_nic_byte(dev, WPA_CONFIG, 0);
MacConfig_85BASIC(dev);
- /* Override the RFSW_CTRL (MAC offset 0x272-0x273), 2006.06.07, by rcnjko. */
- /* BT_DEMO_BOARD type */
+ /* Override the RFSW_CTRL (MAC offset 0x272-0x273), 2006.06.07, by rcnjko. */
+ /* BT_DEMO_BOARD type */
PlatformIOWrite2Byte(dev, RFSW_CTRL, 0x569a);
/*
- -----------------------------------------------------------------------------
- Set up PHY related.
- -----------------------------------------------------------------------------
- */
- /* Enable Config3.PARAM_En to revise AnaaParm. */
- write_nic_byte(dev, CR9346, 0xc0); /* enable config register write */
+ *---------------------------------------------------------------------------
+ * Set up PHY related.
+ *---------------------------------------------------------------------------
+ */
+ /* Enable Config3.PARAM_En to revise AnaaParm. */
+ write_nic_byte(dev, CR9346, 0xc0); /* enable config register write */
tmpu8 = read_nic_byte(dev, CONFIG3);
write_nic_byte(dev, CONFIG3, (tmpu8 | CONFIG3_PARM_En));
- /* Turn on Analog power. */
- /* Asked for by William, otherwise, MAC 3-wire can't work, 2006.06.27, by rcnjko. */
+ /* Turn on Analog power. */
+ /* Asked for by William, otherwise, MAC 3-wire can't work, 2006.06.27, by rcnjko. */
write_nic_dword(dev, ANAPARAM2, ANAPARM2_ASIC_ON);
write_nic_dword(dev, ANAPARAM, ANAPARM_ASIC_ON);
write_nic_word(dev, ANAPARAM3, 0x0010);
write_nic_byte(dev, CONFIG3, tmpu8);
write_nic_byte(dev, CR9346, 0x00);
- /* enable EEM0 and EEM1 in 9346CR */
+ /* enable EEM0 and EEM1 in 9346CR */
btCR9346 = read_nic_byte(dev, CR9346);
write_nic_byte(dev, CR9346, (btCR9346 | 0xC0));
- /* B cut use LED1 to control HW RF on/off */
+ /* B cut use LED1 to control HW RF on/off */
TmpU1b = read_nic_byte(dev, CONFIG5);
TmpU1b = TmpU1b & ~BIT3;
write_nic_byte(dev, CONFIG5, TmpU1b);
- /* disable EEM0 and EEM1 in 9346CR */
+ /* disable EEM0 and EEM1 in 9346CR */
btCR9346 &= ~(0xC0);
write_nic_byte(dev, CR9346, btCR9346);
- /* Enable Led (suggested by Jong) */
- /* B-cut RF Radio on/off 5e[3]=0 */
+ /* Enable Led (suggested by Jong) */
+ /* B-cut RF Radio on/off 5e[3]=0 */
btPSR = read_nic_byte(dev, PSR);
write_nic_byte(dev, PSR, (btPSR | BIT3));
- /* setup initial timing for RFE. */
+ /* setup initial timing for RFE. */
write_nic_word(dev, RFPinsOutput, 0x0480);
SetOutputEnableOfRfPins(dev);
write_nic_word(dev, RFPinsSelect, 0x2488);
- /* PHY config. */
+ /* PHY config. */
PhyConfig8185(dev);
/*
- We assume RegWirelessMode has already been initialized before,
- however, we has to validate the wireless mode here and provide a
- reasonable initialized value if necessary. 2005.01.13, by rcnjko.
- */
+ * We assume RegWirelessMode has already been initialized before,
+ * however, we has to validate the wireless mode here and provide a
+ * reasonable initialized value if necessary. 2005.01.13, by rcnjko.
+ */
SupportedWirelessMode = GetSupportedWirelessMode8185(dev);
if ((ieee->mode != WIRELESS_MODE_B) &&
(ieee->mode != WIRELESS_MODE_G) &&
(ieee->mode != WIRELESS_MODE_A) &&
- (ieee->mode != WIRELESS_MODE_AUTO)) {
- /* It should be one of B, G, A, or AUTO. */
+ (ieee->mode != WIRELESS_MODE_AUTO)) {
+ /* It should be one of B, G, A, or AUTO. */
bInvalidWirelessMode = 1;
- } else {
- /* One of B, G, A, or AUTO. */
- /* Check if the wireless mode is supported by RF. */
+ } else {
+ /* One of B, G, A, or AUTO. */
+ /* Check if the wireless mode is supported by RF. */
if ((ieee->mode != WIRELESS_MODE_AUTO) &&
- (ieee->mode & SupportedWirelessMode) == 0) {
+ (ieee->mode & SupportedWirelessMode) == 0) {
bInvalidWirelessMode = 1;
}
}
- if (bInvalidWirelessMode || ieee->mode == WIRELESS_MODE_AUTO) {
- /* Auto or other invalid value. */
- /* Assigne a wireless mode to initialize. */
- if ((SupportedWirelessMode & WIRELESS_MODE_A)) {
+ if (bInvalidWirelessMode || ieee->mode == WIRELESS_MODE_AUTO) {
+ /* Auto or other invalid value. */
+ /* Assigne a wireless mode to initialize. */
+ if ((SupportedWirelessMode & WIRELESS_MODE_A)) {
InitWirelessMode = WIRELESS_MODE_A;
- } else if ((SupportedWirelessMode & WIRELESS_MODE_G)) {
+ } else if ((SupportedWirelessMode & WIRELESS_MODE_G)) {
InitWirelessMode = WIRELESS_MODE_G;
- } else if ((SupportedWirelessMode & WIRELESS_MODE_B)) {
+ } else if ((SupportedWirelessMode & WIRELESS_MODE_B)) {
InitWirelessMode = WIRELESS_MODE_B;
- } else {
+ } else {
DMESGW("InitializeAdapter8185(): No valid wireless mode supported, SupportedWirelessMode(%x)!!!\n",
SupportedWirelessMode);
InitWirelessMode = WIRELESS_MODE_B;
@@ -1690,24 +1554,21 @@ void rtl8185b_adapter_start(struct net_device *dev)
if (bInvalidWirelessMode)
ieee->mode = (WIRELESS_MODE)InitWirelessMode;
- } else {
- /* One of B, G, A. */
+ } else {
+ /* One of B, G, A. */
InitWirelessMode = ieee->mode;
}
-/* by amy for power save */
priv->eRFPowerState = eRfOff;
priv->RfOffReason = 0;
{
MgntActSet_RF_State(dev, eRfOn, 0);
}
/*
- If inactive power mode is enabled, disable rf while in disconnected state.
- */
+ * If inactive power mode is enabled, disable rf while in disconnected state.
+ */
if (priv->bInactivePs)
MgntActSet_RF_State(dev , eRfOff, RF_CHANGE_BY_IPS);
-/* by amy for power save */
-
ActSetWirelessMode8185(dev, (u8)(InitWirelessMode));
/* ----------------------------------------------------------------------------- */
@@ -1715,7 +1576,7 @@ void rtl8185b_adapter_start(struct net_device *dev)
rtl8185b_irq_enable(dev);
netif_start_queue(dev);
- }
+}
void rtl8185b_rx_enable(struct net_device *dev)
{
@@ -1728,7 +1589,7 @@ void rtl8185b_rx_enable(struct net_device *dev)
DMESG("NIC in promisc mode");
if (priv->ieee80211->iw_mode == IW_MODE_MONITOR || \
- dev->flags & IFF_PROMISC) {
+ dev->flags & IFF_PROMISC) {
priv->ReceiveConfig = priv->ReceiveConfig & (~RCR_APM);
priv->ReceiveConfig = priv->ReceiveConfig | RCR_AAP;
}
diff --git a/drivers/staging/rtl8192e/Kconfig b/drivers/staging/rtl8192e/Kconfig
index f87e21101857..4602a47cdb4a 100644
--- a/drivers/staging/rtl8192e/Kconfig
+++ b/drivers/staging/rtl8192e/Kconfig
@@ -14,6 +14,7 @@ if RTLLIB
config RTLLIB_CRYPTO_CCMP
tristate "Support for rtllib CCMP crypto"
depends on RTLLIB
+ select CRYPTO_AES
default y
---help---
CCMP crypto driver for rtllib.
@@ -23,6 +24,8 @@ config RTLLIB_CRYPTO_CCMP
config RTLLIB_CRYPTO_TKIP
tristate "Support for rtllib TKIP crypto"
depends on RTLLIB
+ select CRYPTO_ARC4
+ select CRYPTO_MICHAEL_MIC
default y
---help---
TKIP crypto driver for rtllib.
@@ -31,6 +34,7 @@ config RTLLIB_CRYPTO_TKIP
config RTLLIB_CRYPTO_WEP
tristate "Support for rtllib WEP crypto"
+ select CRYPTO_ARC4
depends on RTLLIB
default y
---help---
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c
index 58d044ea5524..ea91744f7ccf 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_cmdpkt.c
@@ -342,7 +342,6 @@ static void cmpk_handle_tx_rate_history(struct net_device *dev, u8 *pmsg)
u32 cmpk_message_handle_rx(struct net_device *dev,
struct rtllib_rx_stats *pstats)
{
- struct r8192_priv *priv = rtllib_priv(dev);
int total_length;
u8 cmd_length, exe_cnt = 0;
u8 element_id;
@@ -409,8 +408,6 @@ u32 cmpk_message_handle_rx(struct net_device *dev,
return 1;
}
- priv->stats.rxcmdpkt[element_id]++;
-
total_length -= cmd_length;
pcmd_buff += cmd_length;
}
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c
index 37719859bdae..b526fa428679 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c
@@ -216,7 +216,7 @@ static bool firmware_check_ready(struct net_device *dev,
break;
default:
rt_status = false;
- RT_TRACE(COMP_FIRMWARE, "Unknown firware status");
+ RT_TRACE(COMP_FIRMWARE, "Unknown firmware status");
break;
}
diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
index 3e705efaaf22..9676c591c859 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
+++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_phy.c
@@ -689,7 +689,7 @@ void rtl8192_phy_setTxPower(struct net_device *dev, u8 channel)
case RF_8258:
break;
default:
- RT_TRACE(COMP_ERR, "unknown rf chip in funtion %s()\n",
+ RT_TRACE(COMP_ERR, "unknown rf chip in function %s()\n",
__func__);
break;
}
diff --git a/drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h b/drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h
index d5de279f6644..970298b07af7 100644
--- a/drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h
+++ b/drivers/staging/rtl8192e/rtl8192e/r819xE_phyreg.h
@@ -306,7 +306,7 @@
#define bRFStart 0x0000f000
#define bBBStart 0x000000f0
#define bBBCCKStart 0x0000000f
-/* Reg)x814 */
+/* Reg x814 */
#define bPAEnd 0xf
#define bTREnd 0x0f000000
#define bRFEnd 0x000f0000
@@ -844,7 +844,7 @@
#define bRTL8258_RxLPFBW 0xc00
#define bRTL8258_RSSILPFBW 0xc0
-/* byte endable for sb_write */
+/* byte enable for sb_write */
#define bByte0 0x1
#define bByte1 0x2
#define bByte2 0x4
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
index 71adb6b3344d..4f602b227b50 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c
@@ -1025,7 +1025,7 @@ static int rtl8192_sta_down(struct net_device *dev, bool shutdownrf)
break;
}
RT_TRACE(COMP_DBG, "===>%s():RF is in progress, need to wait "
- "until rf chang is done.\n", __func__);
+ "until rf change is done.\n", __func__);
mdelay(1);
RFInProgressTimeOut++;
spin_lock_irqsave(&priv->rf_ps_lock, flags);
@@ -1211,7 +1211,7 @@ static void rtl8192_init_priv_variable(struct net_device *dev)
priv->AcmControl = 0;
priv->pFirmware = vzalloc(sizeof(struct rt_firmware));
if (!priv->pFirmware)
- printk(KERN_ERR "rtl8193e: Unable to allocate space "
+ printk(KERN_ERR "rtl8192e: Unable to allocate space "
"for firmware\n");
skb_queue_head_init(&priv->rx_queue);
@@ -2024,10 +2024,10 @@ short rtl8192_tx(struct net_device *dev, struct sk_buff *skb)
stype = WLAN_FC_GET_STYPE(fc);
pda_addr = header->addr1;
- if (is_multicast_ether_addr(pda_addr))
- multi_addr = true;
- else if (is_broadcast_ether_addr(pda_addr))
+ if (is_broadcast_ether_addr(pda_addr))
broad_addr = true;
+ else if (is_multicast_ether_addr(pda_addr))
+ multi_addr = true;
else
uni_addr = true;
@@ -2358,8 +2358,7 @@ static void rtl8192_rx_normal(struct net_device *dev)
stats.RxBufShift);
skb_trim(skb, skb->len - 4/*sCrcLng*/);
rtllib_hdr = (struct rtllib_hdr_1addr *)skb->data;
- if (!is_broadcast_ether_addr(rtllib_hdr->addr1) &&
- !is_multicast_ether_addr(rtllib_hdr->addr1)) {
+ if (!is_multicast_ether_addr(rtllib_hdr->addr1)) {
/* unicast packet */
unicast_packet = true;
}
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
index 2a2519cc284d..320d5fc026b4 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.h
@@ -353,7 +353,6 @@ struct rt_stats {
unsigned long rxrdu;
unsigned long rxok;
unsigned long rxframgment;
- unsigned long rxcmdpkt[8];
unsigned long rxurberr;
unsigned long rxstaterr;
unsigned long rxdatacrcerr;
@@ -944,7 +943,7 @@ struct r8192_priv {
bool bfsync_processing;
u32 rate_record;
u32 rateCountDiffRecord;
- u32 ContiuneDiffCount;
+ u32 ContinueDiffCount;
bool bswitch_fsync;
u8 framesync;
u32 framesyncC34;
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
index f026b7171f62..481b1e4d4913 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
@@ -493,7 +493,7 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev)
if (priv->bResetInProgress) {
RT_TRACE(COMP_POWER_TRACKING,
- "we are in slient reset progress, so return\n");
+ "we are in silent reset progress, so return\n");
write_nic_byte(dev, Pw_Track_Flag, 0);
write_nic_byte(dev, FW_Busy_Flag, 0);
return;
@@ -2615,22 +2615,22 @@ void dm_fsync_timer_callback(unsigned long data)
rate_count_diff;
if (DiffNum >=
priv->rtllib->fsync_seconddiff_ratethreshold)
- priv->ContiuneDiffCount++;
+ priv->ContinueDiffCount++;
else
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
- if (priv->ContiuneDiffCount >= 2) {
+ if (priv->ContinueDiffCount >= 2) {
bSwitchFromCountDiff = true;
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
}
} else {
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
}
if (rate_count_diff <=
priv->rtllib->fsync_firstdiff_ratethreshold) {
bSwitchFromCountDiff = true;
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
}
priv->rate_record = rate_count;
priv->rateCountDiffRecord = rate_count_diff;
@@ -2677,10 +2677,10 @@ void dm_fsync_timer_callback(unsigned long data)
write_nic_byte(dev, 0xC36, 0x5c);
write_nic_byte(dev, 0xC3e, 0x96);
}
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd);
}
- RT_TRACE(COMP_HALDM, "ContiuneDiffCount %d\n", priv->ContiuneDiffCount);
+ RT_TRACE(COMP_HALDM, "ContinueDiffCount %d\n", priv->ContinueDiffCount);
RT_TRACE(COMP_HALDM, "rateRecord %d rateCount %d, rateCountdiff %d "
"bSwitchFsync %d\n", priv->rate_record, rate_count,
rate_count_diff, priv->bswitch_fsync);
@@ -2723,7 +2723,7 @@ static void dm_EndSWFsync(struct net_device *dev)
write_nic_byte(dev, 0xC3e, 0x96);
}
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd);
}
@@ -2735,7 +2735,7 @@ static void dm_StartSWFsync(struct net_device *dev)
RT_TRACE(COMP_HALDM, "%s\n", __func__);
priv->rate_record = 0;
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
priv->rateCountDiffRecord = 0;
priv->bswitch_fsync = false;
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
index 4e93669210af..778d7baf8e08 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c
@@ -1322,9 +1322,9 @@ static struct iw_statistics *r8192_get_wireless_stats(struct net_device *dev)
struct iw_handler_def r8192_wx_handlers_def = {
.standard = r8192_wx_handlers,
- .num_standard = sizeof(r8192_wx_handlers) / sizeof(iw_handler),
+ .num_standard = ARRAY_SIZE(r8192_wx_handlers),
.private = r8192_private_handler,
- .num_private = sizeof(r8192_private_handler) / sizeof(iw_handler),
+ .num_private = ARRAY_SIZE(r8192_private_handler),
.num_private_args = sizeof(r8192_private_args) /
sizeof(struct iw_priv_args),
.get_wireless_stats = r8192_get_wireless_stats,
diff --git a/drivers/staging/rtl8192e/rtl819x_TSProc.c b/drivers/staging/rtl8192e/rtl819x_TSProc.c
index 711a096be7a7..658e875232aa 100644
--- a/drivers/staging/rtl8192e/rtl819x_TSProc.c
+++ b/drivers/staging/rtl8192e/rtl819x_TSProc.c
@@ -310,7 +310,7 @@ bool GetTs(struct rtllib_device *ieee, struct ts_common_info **ppTS,
u8 *Addr, u8 TID, enum tr_select TxRxSelect, bool bAddNewTs)
{
u8 UP = 0;
- if (is_broadcast_ether_addr(Addr) || is_multicast_ether_addr(Addr)) {
+ if (is_multicast_ether_addr(Addr)) {
RTLLIB_DEBUG(RTLLIB_DL_ERR, "ERR! get TS for Broadcast or "
"Multicast\n");
return false;
diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h
index e26aec86a5c8..d7460ae3a765 100644
--- a/drivers/staging/rtl8192e/rtllib.h
+++ b/drivers/staging/rtl8192e/rtllib.h
@@ -169,7 +169,7 @@ struct cb_desc {
u8 nStuckCount;
- /* Tx Firmware Relaged flags (10-11)*/
+ /* Tx Firmware Related flags (10-11)*/
u8 bCTSEnable:1;
u8 bRTSEnable:1;
u8 bUseShortGI:1;
@@ -1690,7 +1690,7 @@ enum rtllib_state {
/* the association procedure is sending AUTH request*/
RTLLIB_ASSOCIATING_AUTHENTICATING,
- /* the association procedure has successfully authentcated
+ /* the association procedure has successfully authenticated
* and is sending association request
*/
RTLLIB_ASSOCIATING_AUTHENTICATED,
@@ -2409,7 +2409,7 @@ struct rtllib_device {
/* used instead of hard_start_xmit (not softmac_hard_start_xmit)
* if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data
- * frames. I the option IEEE_SOFTMAC_SINGLE_QUEUE is also set
+ * frames. If the option IEEE_SOFTMAC_SINGLE_QUEUE is also set
* then also management frames are sent via this callback.
* This function can't sleep.
*/
@@ -2422,12 +2422,12 @@ struct rtllib_device {
*/
void (*data_hard_stop)(struct net_device *dev);
- /* OK this is complementar to data_poll_hard_stop */
+ /* OK this is complementing to data_poll_hard_stop */
void (*data_hard_resume)(struct net_device *dev);
/* ask to the driver to retune the radio .
* This function can sleep. the driver should ensure
- * the radio has been swithced before return.
+ * the radio has been switched before return.
*/
void (*set_chan)(struct net_device *dev, short ch);
@@ -2438,7 +2438,7 @@ struct rtllib_device {
* The syncro version is similar to the start_scan but
* does not return until all channels has been scanned.
* this is called in user context and should sleep,
- * it is called in a work_queue when swithcing to ad-hoc mode
+ * it is called in a work_queue when switching to ad-hoc mode
* or in behalf of iwlist scan when the card is associated
* and root user ask for a scan.
* the fucntion stop_scan should stop both the syncro and
@@ -2481,7 +2481,7 @@ struct rtllib_device {
struct rtllib_network *network);
- /* check whether Tx hw resouce available */
+ /* check whether Tx hw resource available */
short (*check_nic_enough_desc)(struct net_device *dev, int queue_index);
short (*get_nic_desc_num)(struct net_device *dev, int queue_index);
void (*SetBWModeHandler)(struct net_device *dev,
@@ -2543,10 +2543,10 @@ struct rtllib_device {
/* Generate probe requests */
#define IEEE_SOFTMAC_PROBERQ (1<<4)
-/* Generate respones to probe requests */
+/* Generate response to probe requests */
#define IEEE_SOFTMAC_PROBERS (1<<5)
-/* The ieee802.11 stack will manages the netif queue
+/* The ieee802.11 stack will manage the netif queue
* wake/stop for the driver, taking care of 802.11
* fragmentation. See softmac.c for details. */
#define IEEE_SOFTMAC_TX_QUEUE (1<<7)
diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c
index 13979b5ea32a..8b8a5c661a26 100644
--- a/drivers/staging/rtl8192e/rtllib_rx.c
+++ b/drivers/staging/rtl8192e/rtllib_rx.c
@@ -496,7 +496,7 @@ void rtllib_indicate_packets(struct rtllib_device *ieee, struct rtllib_rxb **prx
memcpy(skb_push(sub_skb, ETH_ALEN), prxb->dst, ETH_ALEN);
}
- /* Indicat the packets to upper layer */
+ /* Indicate the packets to upper layer */
if (sub_skb) {
stats->rx_packets++;
stats->rx_bytes += sub_skb->len;
@@ -1000,7 +1000,7 @@ static int rtllib_rx_data_filter(struct rtllib_device *ieee, u16 fc,
return -1;
/* {broad,multi}cast packets to our BSS go through */
- if (is_multicast_ether_addr(dst) || is_broadcast_ether_addr(dst)) {
+ if (is_multicast_ether_addr(dst)) {
if (memcmp(bssid, ieee->current_network.bssid, ETH_ALEN))
return -1;
}
@@ -1233,7 +1233,7 @@ static void rtllib_rx_indicate_pkt_legacy(struct rtllib_device *ieee,
if (is_multicast_ether_addr(dst))
ieee->stats.multicast++;
- /* Indicat the packets to upper layer */
+ /* Indicate the packets to upper layer */
memset(sub_skb->cb, 0, sizeof(sub_skb->cb));
sub_skb->protocol = eth_type_trans(sub_skb, dev);
sub_skb->dev = dev;
@@ -1269,7 +1269,7 @@ static int rtllib_rx_InfraAdhoc(struct rtllib_device *ieee, struct sk_buff *skb,
sc = le16_to_cpu(hdr->seq_ctl);
/*Filter pkt not to me*/
- multicast = is_multicast_ether_addr(hdr->addr1)|is_broadcast_ether_addr(hdr->addr1);
+ multicast = is_multicast_ether_addr(hdr->addr1);
unicast = !multicast;
if (unicast && (compare_ether_addr(dev->dev_addr, hdr->addr1) != 0)) {
if (ieee->bNetPromiscuousMode)
@@ -1350,7 +1350,7 @@ static int rtllib_rx_InfraAdhoc(struct rtllib_device *ieee, struct sk_buff *skb,
/* Get TS for Rx Reorder */
hdr = (struct rtllib_hdr_4addr *) skb->data;
if (ieee->current_network.qos_data.active && IsQoSDataFrame(skb->data)
- && !is_multicast_ether_addr(hdr->addr1) && !is_broadcast_ether_addr(hdr->addr1)
+ && !is_multicast_ether_addr(hdr->addr1)
&& (!bToOtherSTA)) {
TID = Frame_QoSTID(skb->data);
SeqNum = WLAN_GET_SEQ_SEQ(sc);
diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c
index c5a15dba1bf5..a21b4d91a596 100644
--- a/drivers/staging/rtl8192e/rtllib_softmac.c
+++ b/drivers/staging/rtl8192e/rtllib_softmac.c
@@ -31,7 +31,7 @@ short rtllib_is_shortslot(const struct rtllib_network *net)
return net->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME;
}
-/* returns the total length needed for pleacing the RATE MFIE
+/* returns the total length needed for placing the RATE MFIE
* tag and the EXTENDED RATE MFIE tag if needed.
* It encludes two bytes per tag for the tag itself and its len
*/
@@ -49,7 +49,7 @@ static unsigned int rtllib_MFIE_rate_len(struct rtllib_device *ieee)
return rate_len;
}
-/* pleace the MFIE rate, tag to the memory (double) poined.
+/* place the MFIE rate, tag to the memory (double) pointed.
* Then it updates the pointer so that
* it points after the new MFIE tag added.
*/
@@ -557,7 +557,7 @@ void rtllib_softmac_scan_syncro(struct rtllib_device *ieee, u8 is_mesh)
* new network events, despite for updating the net list,
* but we are temporarly 'unlinked' as the driver shall
* not filter RX frames and the channel is changing.
- * So the only situation in witch are interested is to check
+ * So the only situation in which are interested is to check
* if the state become LINKED because of the #1 situation
*/
@@ -1681,7 +1681,7 @@ inline void rtllib_softmac_new_net(struct rtllib_device *ieee,
/* if the user set the AP check if match.
* if the network does not broadcast essid we check the
- * user supplyed ANY essid
+ * user supplied ANY essid
* if the network does broadcast and the user does not set
* essid it is OK
* if the network does broadcast and the user did set essid
@@ -2444,16 +2444,16 @@ inline int rtllib_rx_frame_softmac(struct rtllib_device *ieee,
/* following are for a simplier TX queue management.
* Instead of using netif_[stop/wake]_queue the driver
- * will uses these two function (plus a reset one), that
- * will internally uses the kernel netif_* and takes
+ * will use these two functions (plus a reset one), that
+ * will internally use the kernel netif_* and takes
* care of the ieee802.11 fragmentation.
* So the driver receives a fragment per time and might
- * call the stop function when it want without take care
- * to have enought room to TX an entire packet.
- * This might be useful if each fragment need it's own
+ * call the stop function when it wants to not
+ * have enough room to TX an entire packet.
+ * This might be useful if each fragment needs it's own
* descriptor, thus just keep a total free memory > than
- * the max fragmentation treshold is not enought.. If the
- * ieee802.11 stack passed a TXB struct then you needed
+ * the max fragmentation threshold is not enough.. If the
+ * ieee802.11 stack passed a TXB struct then you need
* to keep N free descriptors where
* N = MAX_PACKET_SIZE / MIN_FRAG_TRESHOLD
* In this way you need just one and the 802.11 stack
@@ -2696,15 +2696,15 @@ static void rtllib_start_ibss_wq(void *data)
rtllib_softmac_check_all_nets(ieee);
- /* if not then the state is not linked. Maybe the user swithced to
+ /* if not then the state is not linked. Maybe the user switched to
* ad-hoc mode just after being in monitor mode, or just after
* being very few time in managed mode (so the card have had no
* time to scan all the chans..) or we have just run up the iface
* after setting ad-hoc mode. So we have to give another try..
* Here, in ibss mode, should be safe to do this without extra care
- * (in bss mode we had to make sure no-one tryed to associate when
+ * (in bss mode we had to make sure no-one tried to associate when
* we had just checked the ieee->state and we was going to start the
- * scan) beacause in ibss mode the rtllib_new_net function, when
+ * scan) because in ibss mode the rtllib_new_net function, when
* finds a good net, just set the ieee->state to RTLLIB_LINKED,
* so, at worst, we waste a bit of time to initiate an unneeded syncro
* scan, that will stop at the first round because it sees the state
@@ -2819,7 +2819,7 @@ void rtllib_start_bss(struct rtllib_device *ieee)
/* ensure no-one start an associating process (thus setting
* the ieee->state to rtllib_ASSOCIATING) while we
- * have just cheked it and we are going to enable scan.
+ * have just checked it and we are going to enable scan.
* The rtllib_new_net function is always called with
* lock held (from both rtllib_softmac_check_all_nets and
* the rx path), so we cannot be in the middle of such function
@@ -2872,7 +2872,7 @@ static void rtllib_associate_retry_wq(void *data)
/* until we do not set the state to RTLLIB_NOLINK
* there are no possibility to have someone else trying
- * to start an association procdure (we get here with
+ * to start an association procedure (we get here with
* ieee->state = RTLLIB_ASSOCIATING).
* When we set the state to RTLLIB_NOLINK it is possible
* that the RX path run an attempt to associate, but
@@ -3679,8 +3679,7 @@ void rtllib_MlmeDisassociateRequest(struct rtllib_device *rtllib, u8 *asSta,
RemovePeerTS(rtllib, asSta);
-
- if (memcpy(rtllib->current_network.bssid, asSta, 6) == NULL) {
+ if (memcmp(rtllib->current_network.bssid, asSta, 6) == 0) {
rtllib->state = RTLLIB_NOLINK;
for (i = 0; i < 6; i++)
diff --git a/drivers/staging/rtl8192e/rtllib_softmac_wx.c b/drivers/staging/rtl8192e/rtllib_softmac_wx.c
index 1523bc7a2105..1bb6b52e0f24 100644
--- a/drivers/staging/rtl8192e/rtllib_softmac_wx.c
+++ b/drivers/staging/rtl8192e/rtllib_softmac_wx.c
@@ -479,7 +479,7 @@ int rtllib_wx_set_essid(struct rtllib_device *ieee,
/* this is just to be sure that the GET wx callback
- * has consisten infos. not needed otherwise
+ * has consistent infos. not needed otherwise
*/
spin_lock_irqsave(&ieee->lock, flags);
@@ -575,7 +575,7 @@ int rtllib_wx_set_power(struct rtllib_device *ieee,
if ((!ieee->sta_wake_up) ||
(!ieee->enter_sleep_state) ||
(!ieee->ps_is_queue_empty)) {
- RTLLIB_DEBUG(RTLLIB_DL_ERR, "%s(): PS mode is tryied to be use "
+ RTLLIB_DEBUG(RTLLIB_DL_ERR, "%s(): PS mode is tried to be use "
"but driver missed a callback\n\n", __func__);
return -1;
}
diff --git a/drivers/staging/rtl8192e/rtllib_tx.c b/drivers/staging/rtl8192e/rtllib_tx.c
index f451bfc27a86..42900ee4825b 100644
--- a/drivers/staging/rtl8192e/rtllib_tx.c
+++ b/drivers/staging/rtl8192e/rtllib_tx.c
@@ -59,7 +59,7 @@
802.11 Data Frame
-802.11 frame_contorl for data frames - 2 bytes
+802.11 frame_control for data frames - 2 bytes
,-----------------------------------------------------------------------------------------.
bits | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | d | e |
|----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|------|
@@ -296,8 +296,7 @@ static void rtllib_tx_query_agg_cap(struct rtllib_device *ieee,
return;
if (!IsQoSDataFrame(skb->data))
return;
- if (is_multicast_ether_addr(hdr->addr1) ||
- is_broadcast_ether_addr(hdr->addr1))
+ if (is_multicast_ether_addr(hdr->addr1))
return;
if (tcb_desc->bdhcp || ieee->CntAfterLink < 2)
@@ -515,7 +514,7 @@ u16 rtllib_query_seqnum(struct rtllib_device *ieee, struct sk_buff *skb,
{
u16 seqnum = 0;
- if (is_multicast_ether_addr(dst) || is_broadcast_ether_addr(dst))
+ if (is_multicast_ether_addr(dst))
return 0;
if (IsQoSDataFrame(skb->data)) {
struct tx_ts_record *pTS = NULL;
@@ -576,7 +575,7 @@ int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev)
spin_lock_irqsave(&ieee->lock, flags);
- /* If there is no driver handler to take the TXB, dont' bother
+ /* If there is no driver handler to take the TXB, don't bother
* creating it... */
if ((!ieee->hard_start_xmit && !(ieee->softmac_features &
IEEE_SOFTMAC_TX_QUEUE)) ||
@@ -698,8 +697,7 @@ int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev)
ETH_ALEN);
}
- bIsMulticast = is_broadcast_ether_addr(header.addr1) ||
- is_multicast_ether_addr(header.addr1);
+ bIsMulticast = is_multicast_ether_addr(header.addr1);
header.frame_ctl = cpu_to_le16(fc);
@@ -738,7 +736,7 @@ int rtllib_xmit_inter(struct sk_buff *skb, struct net_device *dev)
(CFG_RTLLIB_COMPUTE_FCS | CFG_RTLLIB_RESERVE_FCS))
bytes_per_frag -= RTLLIB_FCS_LEN;
- /* Each fragment may need to have room for encryptiong
+ /* Each fragment may need to have room for encrypting
* pre/postfix */
if (encrypt) {
bytes_per_frag -= crypt->ops->extra_mpdu_prefix_len +
diff --git a/drivers/staging/rtl8192e/rtllib_wx.c b/drivers/staging/rtl8192e/rtllib_wx.c
index c27ff7edbaf2..c7e8d4d8ec2b 100644
--- a/drivers/staging/rtl8192e/rtllib_wx.c
+++ b/drivers/staging/rtl8192e/rtllib_wx.c
@@ -88,7 +88,7 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee,
}
/* Add the protocol name */
iwe.cmd = SIOCGIWNAME;
- for (i = 0; i < (sizeof(rtllib_modes)/sizeof(rtllib_modes[0])); i++) {
+ for (i = 0; i < ARRAY_SIZE(rtllib_modes); i++) {
if (network->mode&(1<<i)) {
sprintf(pname, rtllib_modes[i].mode_string,
rtllib_modes[i].mode_size);
@@ -408,7 +408,7 @@ int rtllib_wx_set_encode(struct rtllib_device *ieee,
(*crypt)->priv);
sec.flags |= (1 << key);
/* This ensures a key will be activated if no key is
- * explicitely set */
+ * explicitly set */
if (key == sec.active_key)
sec.flags |= SEC_ACTIVE_KEY;
ieee->crypt_info.tx_keyidx = key;
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
index e3d47bcf4cab..82d4bf6a86a5 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_module.c
@@ -161,7 +161,7 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
if (ieee->pHTInfo == NULL)
{
IEEE80211_DEBUG(IEEE80211_DL_ERR, "can't alloc memory for HTInfo\n");
- return NULL;
+ goto failed;
}
HTUpdateDefaultSetting(ieee);
HTInitializeHTInfo(ieee); //may move to other place.
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
index be2a28cf8edd..e3cf7a45b900 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c
@@ -671,7 +671,7 @@ void RxReorderIndicatePacket( struct ieee80211_device *ieee,
index = 1;
} else {
/* Current packet is going to be inserted into pending list.*/
- //IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): We RX no ordered packed, insert to orderd list\n",__FUNCTION__);
+ //IEEE80211_DEBUG(IEEE80211_DL_REORDER,"%s(): We RX no ordered packed, insert to ordered list\n",__FUNCTION__);
if(!list_empty(&ieee->RxReorder_Unused_List)) {
pReorderEntry = (PRX_REORDER_ENTRY)list_entry(ieee->RxReorder_Unused_List.next,RX_REORDER_ENTRY,List);
list_del_init(&pReorderEntry->List);
@@ -1285,7 +1285,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
*/
//added by amy for reorder
if(ieee->current_network.qos_data.active && IsQoSDataFrame(skb->data)
- && !is_multicast_ether_addr(hdr->addr1) && !is_broadcast_ether_addr(hdr->addr1))
+ && !is_multicast_ether_addr(hdr->addr1))
{
TID = Frame_QoSTID(skb->data);
SeqNum = WLAN_GET_SEQ_SEQ(sc);
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
index c2ab5fa15465..f6ff8cff313a 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
@@ -2062,7 +2062,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb,
}
}else{
ieee->softmac_stats.rx_auth_rs_err++;
- IEEE80211_DEBUG_MGMT("Authentication respose status code 0x%x",errcode);
+ IEEE80211_DEBUG_MGMT("Authentication response status code 0x%x",errcode);
ieee80211_associate_abort(ieee);
}
diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
index 59c45a510efb..3f5ceeb88b6c 100644
--- a/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
+++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_tx.c
@@ -314,7 +314,7 @@ void ieee80211_tx_query_agg_cap(struct ieee80211_device* ieee, struct sk_buff* s
if (!IsQoSDataFrame(skb->data))
return;
- if (is_multicast_ether_addr(hdr->addr1) || is_broadcast_ether_addr(hdr->addr1))
+ if (is_multicast_ether_addr(hdr->addr1))
return;
//check packet and mode later
#ifdef TO_DO_LIST
@@ -575,7 +575,7 @@ void ieee80211_txrate_selectmode(struct ieee80211_device* ieee, cb_desc* tcb_des
void ieee80211_query_seqnum(struct ieee80211_device*ieee, struct sk_buff* skb, u8* dst)
{
- if (is_multicast_ether_addr(dst) || is_broadcast_ether_addr(dst))
+ if (is_multicast_ether_addr(dst))
return;
if (IsQoSDataFrame(skb->data)) //we deal qos data only
{
@@ -693,8 +693,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
/* Determine fragmentation size based on destination (multicast
* and broadcast are not fragmented) */
- if (is_multicast_ether_addr(header.addr1) ||
- is_broadcast_ether_addr(header.addr1)) {
+ if (is_multicast_ether_addr(header.addr1)) {
frag_size = MAX_FRAG_THRESHOLD;
qos_ctl |= QOS_CTL_NOTCONTAIN_ACK;
}
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
index 957ce4ef48b5..06a9824bbff1 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
@@ -350,7 +350,7 @@ bool GetTs(
// We do not build any TS for Broadcast or Multicast stream.
// So reject these kinds of search here.
//
- if(is_broadcast_ether_addr(Addr) || is_multicast_ether_addr(Addr))
+ if (is_multicast_ether_addr(Addr))
{
IEEE80211_DEBUG(IEEE80211_DL_ERR, "get TS for Broadcast or Multicast\n");
return false;
diff --git a/drivers/staging/rtl8192u/r8180_93cx6.c b/drivers/staging/rtl8192u/r8180_93cx6.c
index 8878cfeb0fbb..3c515b7bc542 100644
--- a/drivers/staging/rtl8192u/r8180_93cx6.c
+++ b/drivers/staging/rtl8192u/r8180_93cx6.c
@@ -14,7 +14,7 @@
Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver.
- We want to tanks the Authors of those projects and the Ndiswrapper
+ We want to thank the Authors of those projects and the Ndiswrapper
project Authors.
*/
diff --git a/drivers/staging/rtl8192u/r8180_93cx6.h b/drivers/staging/rtl8192u/r8180_93cx6.h
index fb3ac9766ea5..5cea51e1142e 100644
--- a/drivers/staging/rtl8192u/r8180_93cx6.h
+++ b/drivers/staging/rtl8192u/r8180_93cx6.h
@@ -7,7 +7,7 @@
Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon
Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
- We want to tanks the Authors of such projects and the Ndiswrapper project Authors.
+ We want to thank the Authors of such projects and the Ndiswrapper project Authors.
*/
/*This files contains card eeprom (93c46 or 93c56) programming routines*/
diff --git a/drivers/staging/rtl8192u/r8192U.h b/drivers/staging/rtl8192u/r8192U.h
index 9b81f26d40fe..57e3383cc935 100644
--- a/drivers/staging/rtl8192u/r8192U.h
+++ b/drivers/staging/rtl8192u/r8192U.h
@@ -11,7 +11,7 @@
Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
- We want to tanks the Authors of those projects and the Ndiswrapper
+ We want to thank the Authors of those projects and the Ndiswrapper
project Authors.
*/
@@ -98,7 +98,7 @@ do { if(rt_global_debug_component & component) \
#define COMP_INIT BIT2 // during driver initialization / halt / reset.
-#define COMP_RECV BIT3 // Reveive part data path.
+#define COMP_RECV BIT3 // Receive data path.
#define COMP_SEND BIT4 // Send part path.
#define COMP_IO BIT5 // I/O Related. Added by Annie, 2006-03-02.
#define COMP_POWER BIT6 // 802.11 Power Save mode or System/Device Power state related.
@@ -322,7 +322,7 @@ typedef struct _tx_fwinfo_819x_usb {
u8 TxSubCarrier:2; // This is used for legacy OFDM rate only.
u8 STBC:2;
u8 AllowAggregation:1;
- u8 RtsHT:1; //Interpre RtsRate field as high throughput data rate
+ u8 RtsHT:1; //Interpret RtsRate field as high throughput data rate
u8 RtsShort:1; //Short PLCP for CCK, or short GI for 11n MCS
u8 RtsBandwidth:1; // This is used for HT MCS rate only.
u8 RtsSubcarrier:2; // This is used for legacy OFDM rate only.
@@ -610,7 +610,6 @@ typedef struct Stats
// unsigned long rxnopointer;
unsigned long rxok;
unsigned long rxframgment;
- unsigned long rxcmdpkt[4]; //08/05/08 amy rx cmd element txfeedback/bcn report/cfg set/query
unsigned long rxurberr;
unsigned long rxstaterr;
unsigned long received_rate_histogram[4][32]; //0: Total, 1:OK, 2:CRC, 3:ICV, 2007 07 03 cosa
@@ -1117,7 +1116,7 @@ typedef struct r8192_priv
bool bfsync_processing; // 500ms Fsync timer is active or not
u32 rate_record;
u32 rateCountDiffRecord;
- u32 ContiuneDiffCount;
+ u32 ContinueDiffCount;
bool bswitch_fsync;
u8 framesync;
diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c
index 9c00865f302a..5981d6658320 100644
--- a/drivers/staging/rtl8192u/r8192U_core.c
+++ b/drivers/staging/rtl8192u/r8192U_core.c
@@ -203,7 +203,7 @@ static void rtl819x_set_channel_map(u8 channel_plan, struct r8192_priv* priv)
{
Dot11d_Init(ieee);
ieee->bGlobalDomain = false;
- //acturally 8225 & 8256 rf chip only support B,G,24N mode
+ //actually 8225 & 8256 rf chips only support B,G,24N mode
if ((priv->rf_chip == RF_8225) || (priv->rf_chip == RF_8256))
{
min_chan = 1;
@@ -1103,7 +1103,7 @@ inline u16 rtl8192_rate2rate(short rate)
}
-/* The protype of rx_isr has changed since one verion of Linux Kernel */
+/* The prototype of rx_isr has changed since one version of Linux Kernel */
static void rtl8192_rx_isr(struct urb *urb)
{
struct sk_buff *skb = (struct sk_buff *) urb->context;
@@ -1476,7 +1476,7 @@ static void rtl8192_tx_isr(struct urb *tx_urb)
if(tcb_desc->queue_index != TXCMD_QUEUE) {
if(tx_urb->status == 0) {
dev->trans_start = jiffies;
- // As act as station mode, destion shall be unicast address.
+ // Act as station mode, destination shall be unicast address.
//priv->ieee80211->stats.tx_bytes+=(skb->len - priv->ieee80211->tx_headroom);
//priv->ieee80211->stats.tx_packets++;
priv->stats.txoktotal++;
@@ -1522,13 +1522,13 @@ static void rtl8192_tx_isr(struct urb *tx_urb)
else if ((skb_queue_len(&priv->ieee80211->skb_drv_aggQ[queue_index])!= 0)&&\
(!(priv->ieee80211->queue_stop))) {
// Tx Driver Aggregation process
- /* The driver will aggregation the packets according to the following stets
+ /* The driver will aggregation the packets according to the following stats
* 1. check whether there's tx irq available, for it's a completion return
* function, it should contain enough tx irq;
- * 2. check pakcet type;
+ * 2. check packet type;
* 3. initialize sendlist, check whether the to-be send packet no greater than 1
- * 4. aggregation the packets, and fill firmware info and tx desc to it, etc.
- * 5. check whehter the packet could be sent, otherwise just insert to wait head
+ * 4. aggregates the packets, and fill firmware info and tx desc into it, etc.
+ * 5. check whether the packet could be sent, otherwise just insert into wait head
* */
skb = skb_dequeue(&priv->ieee80211->skb_drv_aggQ[queue_index]);
if(!check_nic_enough_desc(dev, queue_index)) {
@@ -2447,7 +2447,7 @@ static int rtl8192_qos_handle_probe_response(struct r8192_priv *priv,
return 0;
}
-/* handle manage frame frame beacon and probe response */
+/* handle and manage frame from beacon and probe response */
static int rtl8192_handle_beacon(struct net_device * dev,
struct ieee80211_beacon * beacon,
struct ieee80211_network * network)
@@ -2625,7 +2625,7 @@ bool GetHalfNmodeSupportByAPs819xUsb(struct net_device* dev)
void rtl8192_refresh_supportrate(struct r8192_priv* priv)
{
struct ieee80211_device* ieee = priv->ieee80211;
- //we donot consider set support rate for ABG mode, only HT MCS rate is set here.
+ //we do not consider set support rate for ABG mode, only HT MCS rate is set here.
if (ieee->mode == WIRELESS_MODE_N_24G || ieee->mode == WIRELESS_MODE_N_5G)
{
memcpy(ieee->Regdot11HTOperationalRateSet, ieee->RegHTSuppRateSet, 16);
@@ -2780,10 +2780,10 @@ static void rtl8192_init_priv_variable(struct net_device* dev)
priv->TransmitConfig =
// TCR_DurProcMode | //for RTL8185B, duration setting by HW
//? TCR_DISReqQsize |
- (TCR_MXDMA_2048<<TCR_MXDMA_OFFSET)| // Max DMA Burst Size per Tx DMA Burst, 7: reservied.
+ (TCR_MXDMA_2048<<TCR_MXDMA_OFFSET)| // Max DMA Burst Size per Tx DMA Burst, 7: reserved.
(priv->ShortRetryLimit<<TCR_SRL_OFFSET)| // Short retry limit
(priv->LongRetryLimit<<TCR_LRL_OFFSET) | // Long retry limit
- (false ? TCR_SAT: 0); // FALSE: HW provies PLCP length and LENGEXT, TURE: SW proiveds them
+ (false ? TCR_SAT: 0); // FALSE: HW provides PLCP length and LENGEXT, TRUE: SW provides them
#ifdef TO_DO_LIST
if(Adapter->bInHctTest)
pHalData->ReceiveConfig = pHalData->CSMethod |
@@ -3437,7 +3437,7 @@ if(Adapter->ResetProgress == RESET_TYPE_NORESET)
{ // User disable RF via registry.
RT_TRACE((COMP_INIT|COMP_RF), DBG_LOUD, ("InitializeAdapter819xUsb(): Turn off RF for RegRfOff ----------\n"));
MgntActSet_RF_State(Adapter, eRfOff, RF_CHANGE_BY_SW);
- // Those action will be discard in MgntActSet_RF_State because off the same state
+ // Those actions will be discard in MgntActSet_RF_State because of the same state
for(eRFPath = 0; eRFPath <pHalData->NumTotalRFPath; eRFPath++)
PHY_SetRFReg(Adapter, (RF90_RADIO_PATH_E)eRFPath, 0x4, 0xC00, 0x0);
}
@@ -3458,7 +3458,7 @@ if(Adapter->ResetProgress == RESET_TYPE_NORESET)
if(pHalData->eRFPowerState == eRfOff)
{
MgntActSet_RF_State(Adapter, eRfOff, pMgntInfo->RfOffReason);
- // Those action will be discard in MgntActSet_RF_State because off the same state
+ // Those actions will be discard in MgntActSet_RF_State because of the same state
for(eRFPath = 0; eRFPath <pHalData->NumTotalRFPath; eRFPath++)
PHY_SetRFReg(Adapter, (RF90_RADIO_PATH_E)eRFPath, 0x4, 0xC00, 0x0);
}
@@ -3586,7 +3586,7 @@ TxCheckStuck(struct net_device *dev)
//unsigned long flags;
//
- // Decide Stuch threshold according to current power save mode
+ // Decide such threshold according to current power save mode
//
// RT_TRACE(COMP_RESET, " ==> TxCheckStuck()\n");
@@ -3745,7 +3745,7 @@ rtl819x_ifcheck_resetornot(struct net_device *dev)
// Driver should not check RX stuck in IBSS mode because it is required to
// set Check BSSID in order to send beacon, however, if check BSSID is
- // set, STA cannot hear any packet a all. Emily, 2008.04.12
+ // set, STA cannot hear any packet at all. Emily, 2008.04.12
RxResetType = RxCheckStuck(dev);
}
if(TxResetType==RESET_TYPE_NORMAL || RxResetType==RESET_TYPE_NORMAL)
@@ -3962,7 +3962,7 @@ RESET_START:
up(&priv->wx_sem);
RT_TRACE(COMP_RESET,"%s():<==========down process is finished\n",__FUNCTION__);
//rtl8192_irq_disable(dev);
- RT_TRACE(COMP_RESET,"%s():===========>start to up the driver\n",__FUNCTION__);
+ RT_TRACE(COMP_RESET,"%s():===========>start up the driver\n",__FUNCTION__);
reset_status = _rtl8192_up(dev);
RT_TRACE(COMP_RESET,"%s():<===========up process is finished\n",__FUNCTION__);
@@ -4155,7 +4155,7 @@ extern void rtl819x_watchdog_wqcallback(struct work_struct *work)
void watch_dog_timer_callback(unsigned long data)
{
struct r8192_priv *priv = ieee80211_priv((struct net_device *) data);
- //printk("===============>watch_dog timer\n");
+ //printk("===============>watch_dog timer\n");
queue_delayed_work(priv->priv_wq,&priv->watch_dog_wq, 0);
mod_timer(&priv->watch_dog_timer, jiffies + MSECS(IEEE80211_WATCH_DOG_TIME));
}
@@ -4170,7 +4170,7 @@ int _rtl8192_up(struct net_device *dev)
init_status = rtl8192_adapter_start(dev);
if(!init_status)
{
- RT_TRACE(COMP_ERR,"ERR!!! %s(): initialization is failed!\n", __FUNCTION__);
+ RT_TRACE(COMP_ERR,"ERR!!! %s(): initialization failed!\n", __FUNCTION__);
priv->up=priv->ieee80211->ieee_up = 0;
return -EAGAIN;
}
@@ -4256,7 +4256,7 @@ int rtl8192_down(struct net_device *dev)
skb_queue_purge(&priv->ieee80211->skb_drv_aggQ [i]);
}
- //as cancel_delayed_work will del work->timer, so if work is not definedas struct delayed_work, it will corrupt
+ //as cancel_delayed_work will del work->timer, so if work is not defined as struct delayed_work, it will corrupt
// flush_scheduled_work();
rtl8192_cancel_deferred_work(priv);
deinit_hal_dm(dev);
@@ -4516,7 +4516,7 @@ u8 HwRateToMRate90(bool bIsHT, u8 rate)
/**
* Function: UpdateRxPktTimeStamp
- * Overview: Recored down the TSF time stamp when receiving a packet
+ * Overview: Record the TSF time stamp when receiving a packet
*
* Input:
* PADAPTER Adapter
@@ -4556,10 +4556,10 @@ long rtl819x_translate_todbm(u8 signal_strength_index )// 0-100 index.
}
-/* 2008/01/22 MH We can not delcare RSSI/EVM total value of sliding window to
+/* 2008/01/22 MH We can not declare RSSI/EVM total value of sliding window to
be a local static. Otherwise, it may increase when we return from S3/S4. The
- value will be kept in memory or disk. We must delcare the value in adapter
- and it will be reinitialized when return from S3/S4. */
+ value will be kept in memory or disk. Declare the value in the adaptor
+ and it will be reinitialized when returned from S3/S4. */
void rtl8192_process_phyinfo(struct r8192_priv * priv,u8* buffer, struct ieee80211_rx_stats * pprevious_stats, struct ieee80211_rx_stats * pcurrent_stats)
{
bool bcheck = false;
@@ -5091,8 +5091,8 @@ static void rtl8192_query_rxphystatus(
tmp_rxevm = pofdm_buf->rxevm_X[i];
rx_evmX = (char)(tmp_rxevm);
- // Do not use shift operation like "rx_evmX >>= 1" because the compilor of free build environment
- // fill most significant bit to "zero" when doing shifting operation which may change a negative
+ // Do not use shift operation like "rx_evmX >>= 1" because the compiler of free build environment
+ // will set the most significant bit to "zero" when doing shifting operation which may change a negative
// value to positive one, then the dbm value (which is supposed to be negative) is not correct anymore.
rx_evmX /= 2; //dbm
@@ -5171,7 +5171,7 @@ void TranslateRxSignalStuff819xUsb(struct sk_buff *skb,
type = WLAN_FC_GET_TYPE(fc);
praddr = hdr->addr1;
- /* Check if the received packet is acceptabe. */
+ /* Check if the received packet is acceptable. */
bpacket_match_bssid = ((IEEE80211_FTYPE_CTL != type) &&
(eqMacAddr(priv->ieee80211->current_network.bssid, (fc & IEEE80211_FCTL_TODS)? hdr->addr1 : (fc & IEEE80211_FCTL_FROMDS )? hdr->addr2 : hdr->addr3))
&& (!pstats->bHwError) && (!pstats->bCRC)&& (!pstats->bICV));
@@ -5211,7 +5211,7 @@ void TranslateRxSignalStuff819xUsb(struct sk_buff *skb,
/**
* Function: UpdateReceivedRateHistogramStatistics
-* Overview: Recored down the received data rate
+* Overview: Record the received data rate
*
* Input:
* struct net_device *dev
@@ -5401,7 +5401,7 @@ void query_rxdesc_status(struct sk_buff *skb, struct ieee80211_rx_stats *stats,
}
#ifdef USB_RX_AGGREGATION_SUPPORT
- /* for the rx aggregated sub frame, the redundant space truelly contained in the packet */
+ /* for the rx aggregated sub frame, the redundant space truly contained in the packet */
if(bIsRxAggrSubframe) {
skb_pull(skb, 8);
}
@@ -5480,7 +5480,7 @@ void rtl8192_rx_nomal(struct sk_buff* skb)
PacketShiftBytes = GetRxPacketShiftBytes819xUsb(&stats, false);
}
#endif
- /* Process the MPDU recevied */
+ /* Process the MPDU received */
skb_trim(skb, skb->len - 4/*sCrcLng*/);
rx_pkt_len = skb->len;
@@ -5538,7 +5538,7 @@ void rtl8192_rx_nomal(struct sk_buff* skb)
if(PacketLength > agg_skb->len) {
break;
}
- /* Process the MPDU recevied */
+ /* Process the MPDU received */
skb = dev_alloc_skb(PacketLength);
memcpy(skb_put(skb,PacketLength),agg_skb->data, PacketLength);
skb_trim(skb, skb->len - 4/*sCrcLng*/);
diff --git a/drivers/staging/rtl8192u/r8192U_dm.c b/drivers/staging/rtl8192u/r8192U_dm.c
index 2dde9fa5c21e..cd8dc85e9c0f 100644
--- a/drivers/staging/rtl8192u/r8192U_dm.c
+++ b/drivers/staging/rtl8192u/r8192U_dm.c
@@ -38,7 +38,7 @@ static u32 edca_setting_UL[HT_IOT_PEER_MAX] =
/*------------------------Define global variable-----------------------------*/
// Debug variable ?
dig_t dm_digtable;
-// Store current shoftware write register content for MAC PHY.
+// Store current software write register content for MAC PHY.
u8 dm_shadow[16][256] = {{0}};
// For Dynamic Rx Path Selection by Signal Strength
DRxPathSel DM_RxPathSelTable;
@@ -119,7 +119,7 @@ static void dm_pd_th(struct net_device *dev);
static void dm_cs_ratio(struct net_device *dev);
static void dm_init_ctstoself(struct net_device *dev);
-// DM --> EDCA turboe mode control
+// DM --> EDCA turbo mode control
static void dm_check_edca_turbo(struct net_device *dev);
// DM --> HW RF control
@@ -348,7 +348,7 @@ extern void init_rate_adaptive(struct net_device * dev)
*
* Revised History:
* When Who Remark
- * 05/26/08 amy Create version 0 proting from windows code.
+ * 05/26/08 amy Create version 0 porting from windows code.
*
*---------------------------------------------------------------------------*/
static void dm_check_rate_adaptive(struct net_device * dev)
@@ -543,7 +543,7 @@ static u32 OFDMSwingTable[OFDM_Table_Length] = {
0x5a400169, // 3, +3db
0x50800142, // 4, +2db
0x47c0011f, // 5, +1db
- 0x40000100, // 6, +0db ===> default, upper for higher temprature, lower for low temprature
+ 0x40000100, // 6, +0db ===> default, upper for higher temperature, lower for low temperature
0x390000e4, // 7, -1db
0x32c000cb, // 8, -2db
0x2d4000b5, // 9, -3db
@@ -678,7 +678,7 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device * dev)
{
write_nic_byte(dev, 0x1ba, 0);
viviflag = FALSE;
- RT_TRACE(COMP_POWER_TRACKING, "we filted this data\n");
+ RT_TRACE(COMP_POWER_TRACKING, "we filtered the data\n");
for(k = 0;k < 5; k++)
tmp_report[k] = 0;
break;
@@ -864,14 +864,14 @@ static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device * dev)
RT_TRACE(COMP_POWER_TRACKING, "Readback ThermalMeterA = %d \n", tmpRegA);
if(tmpRegA < 3 || tmpRegA > 13)
return;
- if(tmpRegA >= 12) // if over 12, TP will be bad when high temprature
+ if(tmpRegA >= 12) // if over 12, TP will be bad when high temperature
tmpRegA = 12;
RT_TRACE(COMP_POWER_TRACKING, "Valid ThermalMeterA = %d \n", tmpRegA);
priv->ThermalMeter[0] = ThermalMeterVal; //We use fixed value by Bryant's suggestion
priv->ThermalMeter[1] = ThermalMeterVal; //We use fixed value by Bryant's suggestion
- //Get current RF-A temprature index
- if(priv->ThermalMeter[0] >= (u8)tmpRegA) //lower temprature
+ //Get current RF-A temperature index
+ if(priv->ThermalMeter[0] >= (u8)tmpRegA) //lower temperature
{
tmpOFDMindex = tmpCCK20Mindex = 6+(priv->ThermalMeter[0]-(u8)tmpRegA);
tmpCCK40Mindex = tmpCCK20Mindex - 6;
@@ -885,7 +885,7 @@ static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device * dev)
else
{
tmpval = ((u8)tmpRegA - priv->ThermalMeter[0]);
- if(tmpval >= 6) // higher temprature
+ if(tmpval >= 6) // higher temperature
tmpOFDMindex = tmpCCK20Mindex = 0; // max to +6dB
else
tmpOFDMindex = tmpCCK20Mindex = 6 - tmpval;
@@ -1457,9 +1457,9 @@ static void dm_InitializeTXPowerTracking_ThermalMeter(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- // Tx Power tracking by Theremal Meter require Firmware R/W 3-wire. This mechanism
+ // Tx Power tracking by Thermal Meter requires Firmware R/W 3-wire. This mechanism
// can be enabled only when Firmware R/W 3-wire is enabled. Otherwise, frequent r/w
- // 3-wire by driver cause RF goes into wrong state.
+ // 3-wire by driver causes RF to go into a wrong state.
if(priv->ieee80211->FwRWRF)
priv->btxpower_tracking = TRUE;
else
@@ -1520,7 +1520,7 @@ static void dm_CheckTXPowerTracking_ThermalMeter(struct net_device *dev)
if(!TM_Trigger)
{
- //Attention!! You have to wirte all 12bits data to RF, or it may cause RF to crash
+ //Attention!! You have to write all 12bits of data to RF, or it may cause RF to crash
//actually write reg0x02 bit1=0, then bit1=1.
//DbgPrint("Trigger ThermalMeter, write RF reg0x2 = 0x4d to 0x4f\n");
rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4d);
@@ -1744,7 +1744,7 @@ extern void dm_restore_dynamic_mechanism_state(struct net_device *dev)
write_nic_dword(dev, RATR0, ratr_value);
write_nic_byte(dev, UFWP, 1);
}
- //Resore TX Power Tracking Index
+ //Restore TX Power Tracking Index
if(priv->btxpower_trackingInit && priv->btxpower_tracking){
dm_txpower_reset_recovery(dev);
}
@@ -2031,7 +2031,7 @@ static void dm_dig_init(struct net_device *dev)
dm_digtable.dbg_mode = DM_DBG_OFF; //off=by real rssi value, on=by DM_DigTable.Rssi_val for new dig
dm_digtable.dig_algorithm_switch = 0;
- /* 2007/10/04 MH Define init gain threshol. */
+ /* 2007/10/04 MH Define init gain threshold. */
dm_digtable.dig_state = DM_STA_DIG_MAX;
dm_digtable.dig_highpwr_state = DM_STA_DIG_MAX;
dm_digtable.initialgain_lowerbound_state = false;
@@ -2097,7 +2097,7 @@ static void dm_ctrl_initgain_byrssi_by_driverrssi(
return;
//DbgPrint("Dig by Sw Rssi \n");
- if(dm_digtable.dig_algorithm_switch) // if swithed algorithm, we have to disable FW Dig.
+ if(dm_digtable.dig_algorithm_switch) // if switched algorithm, we have to disable FW Dig.
fw_dig = 0;
if(fw_dig <= 3) // execute several times to make sure the FW Dig is disabled
{// FW DIG Off
@@ -2160,8 +2160,8 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm(
/*DbgPrint("DIG Check\n\r RSSI=%d LOW=%d HIGH=%d STATE=%d",
pHalData->UndecoratedSmoothedPWDB, DM_DigTable.RssiLowThresh,
DM_DigTable.RssiHighThresh, DM_DigTable.Dig_State);*/
- /* 1. When RSSI decrease, We have to judge if it is smaller than a treshold
- and then execute below step. */
+ /* 1. When RSSI decrease, We have to judge if it is smaller than a threshold
+ and then execute the step below. */
if ((priv->undecorated_smoothed_pwdb <= dm_digtable.rssi_low_thresh))
{
/* 2008/02/05 MH When we execute silent reset, the DIG PHY parameters
@@ -2220,8 +2220,8 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm(
}
- /* 2. When RSSI increase, We have to judge if it is larger than a treshold
- and then execute below step. */
+ /* 2. When RSSI increase, We have to judge if it is larger than a threshold
+ and then execute the step below. */
if ((priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_thresh) )
{
u8 reset_flag = 0;
@@ -2329,7 +2329,7 @@ static void dm_ctrl_initgain_byrssi_highpwr(
}
/* 3. When RSSI >75% or <70%, it is a high power issue. We have to judge if
- it is larger than a treshold and then execute below step. */
+ it is larger than a threshold and then execute the step below. */
// 2008/02/05 MH SD3-Jerry Modify PD_TH for high power issue.
if (priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_power_highthresh)
{
@@ -2841,8 +2841,8 @@ static void dm_check_rfctrl_gpio(struct net_device * dev)
{
//struct r8192_priv *priv = ieee80211_priv(dev);
- // Walk around for DTM test, we will not enable HW - radio on/off because r/w
- // page 1 register before Lextra bus is enabled cause system fails when resuming
+ // Work around for DTM test, we will not enable HW - radio on/off because r/w
+ // page 1 register before extra bus is enabled causing system failures when resuming
// from S4. 20080218, Emily
// Stop to execute workitem to prevent S3/S4 bug.
@@ -3377,30 +3377,30 @@ extern void dm_fsync_timer_callback(unsigned long data)
{
u32 DiffNum = priv->rateCountDiffRecord - rate_count_diff;
- // Contiune count
+ // Continue count
if(DiffNum >= priv->ieee80211->fsync_seconddiff_ratethreshold)
- priv->ContiuneDiffCount++;
+ priv->ContinueDiffCount++;
else
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
- // Contiune count over
- if(priv->ContiuneDiffCount >=2)
+ // Continue count over
+ if(priv->ContinueDiffCount >=2)
{
bSwitchFromCountDiff = true;
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
}
}
else
{
- // Stop contiune count
- priv->ContiuneDiffCount = 0;
+ // Stop the continued count
+ priv->ContinueDiffCount = 0;
}
//If Count diff <= FsyncRateCountThreshold
if(rate_count_diff <= priv->ieee80211->fsync_firstdiff_ratethreshold)
{
bSwitchFromCountDiff = true;
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
}
priv->rate_record = rate_count;
priv->rateCountDiffRecord = rate_count_diff;
@@ -3468,14 +3468,14 @@ extern void dm_fsync_timer_callback(unsigned long data)
#endif
write_nic_byte(dev, 0xC3e, 0x96);
}
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
#ifdef RTL8190P
write_nic_dword(dev, rOFDM0_RxDetector2, 0x164052cd);
#else
write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd);
#endif
}
- RT_TRACE(COMP_HALDM, "ContiuneDiffCount %d\n", priv->ContiuneDiffCount);
+ RT_TRACE(COMP_HALDM, "ContinueDiffCount %d\n", priv->ContinueDiffCount);
RT_TRACE(COMP_HALDM, "rateRecord %d rateCount %d, rateCountdiff %d bSwitchFsync %d\n", priv->rate_record, rate_count, rate_count_diff , priv->bswitch_fsync);
}
@@ -3507,7 +3507,7 @@ static void dm_EndSWFsync(struct net_device *dev)
write_nic_byte(dev, 0xC3e, 0x96);
}
- priv->ContiuneDiffCount = 0;
+ priv->ContinueDiffCount = 0;
#ifndef RTL8190P
write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd);
#endif
@@ -3523,8 +3523,8 @@ static void dm_StartSWFsync(struct net_device *dev)
RT_TRACE(COMP_HALDM,"%s\n", __FUNCTION__);
// Initial rate record to zero, start to record.
priv->rate_record = 0;
- // Initial contiune diff count to zero, start to record.
- priv->ContiuneDiffCount = 0;
+ // Initialize continue diff count to zero, start to record.
+ priv->ContinueDiffCount = 0;
priv->rateCountDiffRecord = 0;
priv->bswitch_fsync = false;
@@ -3875,7 +3875,7 @@ static void dm_send_rssi_tofw(struct net_device *dev)
// If we test chariot, we should stop the TX command ?
// Because 92E will always silent reset when we send tx command. We use register
- // 0x1e0(byte) to botify driver.
+ // 0x1e0(byte) to notify driver.
write_nic_byte(dev, DRIVER_RSSI, (u8)priv->undecorated_smoothed_pwdb);
return;
tx_cmd.Op = TXCMD_SET_RX_RSSI;
diff --git a/drivers/staging/rtl8192u/r8192U_hw.h b/drivers/staging/rtl8192u/r8192U_hw.h
index e89aaf70143b..1bfe871dcfb2 100644
--- a/drivers/staging/rtl8192u/r8192U_hw.h
+++ b/drivers/staging/rtl8192u/r8192U_hw.h
@@ -10,7 +10,7 @@
Parts of this driver are based on the Intel Pro Wireless
2100 GPL driver.
- We want to tanks the Authors of those projects
+ We want to thank the Authors of those projects
and the Ndiswrapper project Authors.
*/
diff --git a/drivers/staging/rtl8192u/r8192U_wx.c b/drivers/staging/rtl8192u/r8192U_wx.c
index f6408f98ede6..71f2d2349c38 100644
--- a/drivers/staging/rtl8192u/r8192U_wx.c
+++ b/drivers/staging/rtl8192u/r8192U_wx.c
@@ -13,7 +13,7 @@
Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver.
- We want to tanks the Authors of those projects and the Ndiswrapper
+ We want to thank the Authors of those projects and the Ndiswrapper
project Authors.
*/
@@ -256,7 +256,7 @@ static int r8192_wx_get_ap_status(struct net_device *dev,
//count the length of input ssid
for(name_len=0 ; ((char*)wrqu->data.pointer)[name_len]!='\0' ; name_len++);
- //search for the correspoding info which is received
+ //search for the corresponding info which is received
list_for_each_entry(target, &ieee->network_list, list) {
if ( (target->ssid_len == name_len) &&
(strncmp(target->ssid, (char*)wrqu->data.pointer, name_len)==0)){
@@ -419,7 +419,7 @@ static int rtl8180_wx_get_range(struct net_device *dev,
range->max_qual.updated = 7; /* Updated all three */
range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */
- /* TODO: Find real 'good' to 'bad' threshol value for RSSI */
+ /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
range->avg_qual.level = 20 + -98;
range->avg_qual.noise = 0;
range->avg_qual.updated = 7; /* Updated all three */
@@ -1047,7 +1047,7 @@ static iw_handler r8192_wx_handlers[] =
#else
NULL,
#endif
- dummy, /* SIOCGIWAPLIST -- depricated */
+ dummy, /* SIOCGIWAPLIST -- deprecated */
r8192_wx_set_scan, /* SIOCSIWSCAN */
r8192_wx_get_scan, /* SIOCGIWSCAN */
r8192_wx_set_essid, /* SIOCSIWESSID */
@@ -1211,9 +1211,9 @@ struct iw_statistics *r8192_get_wireless_stats(struct net_device *dev)
struct iw_handler_def r8192_wx_handlers_def={
.standard = r8192_wx_handlers,
- .num_standard = sizeof(r8192_wx_handlers) / sizeof(iw_handler),
+ .num_standard = ARRAY_SIZE(r8192_wx_handlers),
.private = r8192_private_handler,
- .num_private = sizeof(r8192_private_handler) / sizeof(iw_handler),
+ .num_private = ARRAY_SIZE(r8192_private_handler),
.num_private_args = sizeof(r8192_private_args) / sizeof(struct iw_priv_args),
#if WIRELESS_EXT >= 17
.get_wireless_stats = r8192_get_wireless_stats,
diff --git a/drivers/staging/rtl8192u/r8192U_wx.h b/drivers/staging/rtl8192u/r8192U_wx.h
index f4cf2801136a..9f6b10505426 100644
--- a/drivers/staging/rtl8192u/r8192U_wx.h
+++ b/drivers/staging/rtl8192u/r8192U_wx.h
@@ -7,7 +7,7 @@
Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon
Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
- We want to tanks the Authors of such projects and the Ndiswrapper project Authors.
+ We want to thank the Authors of such projects and the Ndiswrapper project Authors.
*/
/* this file (will) contains wireless extension handlers*/
diff --git a/drivers/staging/rtl8192u/r819xU_HTType.h b/drivers/staging/rtl8192u/r819xU_HTType.h
index 2ac421626e7c..e07f8b17a0d6 100644
--- a/drivers/staging/rtl8192u/r819xU_HTType.h
+++ b/drivers/staging/rtl8192u/r819xU_HTType.h
@@ -211,7 +211,7 @@ typedef struct _RT_HIGH_THROUGHPUT{
u8 bEnableHT;
u8 bCurrentHTSupport;
- u8 bRegBW40MHz; // Tx 40MHz channel capablity
+ u8 bRegBW40MHz; // Tx 40MHz channel capability
u8 bCurBW40MHz; // Tx 40MHz channel capability
u8 bRegShortGI40MHz; // Tx Short GI for 40Mhz
diff --git a/drivers/staging/rtl8192u/r819xU_cmdpkt.c b/drivers/staging/rtl8192u/r819xU_cmdpkt.c
index 0cb28c776c49..a8a6dc2c365f 100644
--- a/drivers/staging/rtl8192u/r819xU_cmdpkt.c
+++ b/drivers/staging/rtl8192u/r819xU_cmdpkt.c
@@ -157,7 +157,7 @@ SendTxCommandPacket(
seg_ptr = skb_put(skb, buffer_len);
/*
* Transform from little endian to big endian
- * and pending zero
+ * and pending zero
*/
memcpy(seg_ptr,codevirtualaddress,buffer_len);
tcb_desc->txbuf_size= (u16)buffer_len;
@@ -697,7 +697,6 @@ cmpk_message_handle_rx(
struct ieee80211_rx_stats *pstats)
{
// u32 debug_level = DBG_LOUD;
- struct r8192_priv *priv = ieee80211_priv(dev);
int total_length;
u8 cmd_length, exe_cnt = 0;
u8 element_id;
@@ -719,15 +718,15 @@ cmpk_message_handle_rx(
/* 2. Read virtual address from RFD. */
pcmd_buff = pstats->virtual_address;
- /* 3. Read command pakcet element id and length. */
+ /* 3. Read command packet element id and length. */
element_id = pcmd_buff[0];
/*RT_TRACE(COMP_SEND, DebugLevel,
("\n\r[CMPK]-->element ID=%d Len=%d", element_id, total_length));*/
- /* 4. Check every received command packet conent according to different
+ /* 4. Check every received command packet content according to different
element type. Because FW may aggregate RX command packet to minimize
transmit time between DRV and FW.*/
- // Add a counter to prevent to locked in the loop too long
+ // Add a counter to prevent the lock in the loop from being held too long
while (total_length > 0 || exe_cnt++ >100)
{
/* 2007/01/17 MH We support aggregation of different cmd in the same packet. */
@@ -779,9 +778,6 @@ cmpk_message_handle_rx(
// 2007/01/22 MH Add to display tx statistic.
//cmpk_DisplayTxStatistic(pAdapter);
- /* 2007/03/09 MH Collect sidderent cmd element pkt num. */
- priv->stats.rxcmdpkt[element_id]++;
-
total_length -= cmd_length;
pcmd_buff += cmd_length;
} /* while (total_length > 0) */
diff --git a/drivers/staging/rtl8192u/r819xU_firmware.c b/drivers/staging/rtl8192u/r819xU_firmware.c
index 4bb5fffca5b9..b12d19079798 100644
--- a/drivers/staging/rtl8192u/r819xU_firmware.c
+++ b/drivers/staging/rtl8192u/r819xU_firmware.c
@@ -275,11 +275,11 @@ bool init_firmware(struct net_device *dev)
/*
* Download boot, main, and data image for System reset.
- * Download data image for firmware reseta
+ * Download data image for firmware reset
*/
for(init_step = starting_state; init_step <= FW_INIT_STEP2_DATA; init_step++) {
/*
- * Open Image file, and map file to contineous memory if open file success.
+ * Open image file, and map file to continuous memory if open file success.
* or read image file from array. Default load from IMG file
*/
if(rst_opt == OPT_SYSTEM_RESET) {
diff --git a/drivers/staging/rtl8192u/r819xU_phy.c b/drivers/staging/rtl8192u/r819xU_phy.c
index c4586b0817d1..dd1954daea2d 100644
--- a/drivers/staging/rtl8192u/r819xU_phy.c
+++ b/drivers/staging/rtl8192u/r819xU_phy.c
@@ -40,7 +40,7 @@ static u32 RF_CHANNEL_TABLE_ZEBRA[] = {
* and do register read/write
* input: u32 dwBitMask //taget bit pos in the addr to be modified
* output: none
- * return: u32 return the shift bit bit position of the mask
+ * return: u32 return the shift bit position of the mask
* ****************************************************************************/
u32 rtl8192_CalculateBitShift(u32 dwBitMask)
{
@@ -176,7 +176,7 @@ u32 rtl8192_phy_RFSerialRead(struct net_device* dev, RF90_RADIO_PATH_E eRFPath,
rtl8192_setBBreg(dev, pPhyReg->rfHSSIPara2, bLSSIReadEdge, 0x1);
- // TODO: we should not delay such a long time. Ask help from SD3
+ // TODO: we should not delay such a long time. Ask for help from SD3
msleep(1);
ret = rtl8192_QueryBBReg(dev, pPhyReg->rfLSSIReadBack, bLSSIReadBackData);
@@ -252,7 +252,7 @@ void rtl8192_phy_RFSerialWrite(struct net_device* dev, RF90_RADIO_PATH_E eRFPath
NewOffset = Offset;
}
- // Put write addr in [5:0] and write data in [31:16]
+ // Put write addr in [5:0] and write data in [31:16]
DataAndAddr = (Data<<16) | (NewOffset&0x3f);
// Write Operation
@@ -525,7 +525,7 @@ void rtl8192_phy_configmac(struct net_device* dev)
}
/******************************************************************************
- *function: This function do dirty work
+ *function: This function does dirty work
* input: dev
* output: none
* return: none
@@ -578,7 +578,7 @@ void rtl8192_phyConfigBB(struct net_device* dev, u8 ConfigType)
void rtl8192_InitBBRFRegDef(struct net_device* dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
-// RF Interface Sowrtware Control
+// RF Interface Software Control
priv->PHYRegDef[RF90_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW; // 16 LSBs if read 32-bit from 0x870
priv->PHYRegDef[RF90_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW; // 16 MSBs if read 32-bit from 0x870 (16-bit for 0x872)
priv->PHYRegDef[RF90_PATH_C].rfintfs = rFPGA0_XCD_RFInterfaceSW;// 16 LSBs if read 32-bit from 0x874
@@ -602,7 +602,7 @@ void rtl8192_InitBBRFRegDef(struct net_device* dev)
priv->PHYRegDef[RF90_PATH_C].rfintfe = rFPGA0_XC_RFInterfaceOE;// 16 MSBs if read 32-bit from 0x86A (16-bit for 0x86A)
priv->PHYRegDef[RF90_PATH_D].rfintfe = rFPGA0_XD_RFInterfaceOE;// 16 MSBs if read 32-bit from 0x86C (16-bit for 0x86E)
- //Addr of LSSI. Wirte RF register by driver
+ //Addr of LSSI. Write RF register by driver
priv->PHYRegDef[RF90_PATH_A].rf3wireOffset = rFPGA0_XA_LSSIParameter; //LSSI Parameter
priv->PHYRegDef[RF90_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter;
priv->PHYRegDef[RF90_PATH_C].rf3wireOffset = rFPGA0_XC_LSSIParameter;
@@ -1384,7 +1384,7 @@ u8 rtl8192_phy_SwChnlStepByStep(struct net_device *dev, u8 channel, u8* stage, u
}
/******************************************************************************
- *function: This function does acturally set channel work
+ *function: This function does actually set channel work
* input: struct net_device *dev
* u8 channel
* output: none
@@ -1425,7 +1425,7 @@ void rtl8192_SwChnl_WorkItem(struct net_device *dev)
}
/******************************************************************************
- *function: This function scheduled actural workitem to set channel
+ *function: This function scheduled actual work item to set channel
* input: net_device dev
* u8 channel //channel to set
* output: none
diff --git a/drivers/staging/rtl8192u/r819xU_phyreg.h b/drivers/staging/rtl8192u/r819xU_phyreg.h
index 06b0b539e1bc..50f24dce8b16 100644
--- a/drivers/staging/rtl8192u/r819xU_phyreg.h
+++ b/drivers/staging/rtl8192u/r819xU_phyreg.h
@@ -443,7 +443,7 @@
#define bCCKRxIG 0x7f00
#define bCCKLNAPolarity 0x800000
#define bCCKRx1stGain 0x7f0000
-#define bCCKRFExtend 0x20000000 //CCK Rx Iinital gain polarity
+#define bCCKRFExtend 0x20000000 //CCK Rx inital gain polarity
#define bCCKRxAGCSatLevel 0x1f000000
#define bCCKRxAGCSatCount 0xe0
#define bCCKRxRFSettle 0x1f //AGCsamp_dly
diff --git a/drivers/staging/rtl8712/big_endian.h b/drivers/staging/rtl8712/big_endian.h
deleted file mode 100644
index b16f8ecf99c6..000000000000
--- a/drivers/staging/rtl8712/big_endian.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * Modifications for inclusion into the Linux staging tree are
- * Copyright(c) 2010 Larry Finger. All rights reserved.
- *
- * Contact information:
- * WLAN FAE <wlanfae@realtek.com>
- * Larry Finger <Larry.Finger@lwfinger.net>
- *
- ******************************************************************************/
-#ifndef _LINUX_BYTEORDER_BIG_ENDIAN_H
-#define _LINUX_BYTEORDER_BIG_ENDIAN_H
-
-#ifndef __BIG_ENDIAN
-#define __BIG_ENDIAN 4321
-#endif
-#ifndef __BIG_ENDIAN_BITFIELD
-#define __BIG_ENDIAN_BITFIELD
-#endif
-
-#include "swab.h"
-
-#define __constant_htonl(x) ((__u32)(x))
-#define __constant_ntohl(x) ((__u32)(x))
-#define __constant_htons(x) ((__u16)(x))
-#define __constant_ntohs(x) ((__u16)(x))
-#define __constant_cpu_to_le64(x) ___constant_swab64((x))
-#define __constant_le64_to_cpu(x) ___constant_swab64((x))
-#define __constant_cpu_to_le32(x) ___constant_swab32((x))
-#define __constant_le32_to_cpu(x) ___constant_swab32((x))
-#define __constant_cpu_to_le16(x) ___constant_swab16((x))
-#define __constant_le16_to_cpu(x) ___constant_swab16((x))
-#define __constant_cpu_to_be64(x) ((__u64)(x))
-#define __constant_be64_to_cpu(x) ((__u64)(x))
-#define __constant_cpu_to_be32(x) ((__u32)(x))
-#define __constant_be32_to_cpu(x) ((__u32)(x))
-#define __constant_cpu_to_be16(x) ((__u16)(x))
-#define __constant_be16_to_cpu(x) ((__u16)(x))
-#define __cpu_to_le64(x) __swab64((x))
-#define __le64_to_cpu(x) __swab64((x))
-#define __cpu_to_le32(x) __swab32((x))
-#define __le32_to_cpu(x) __swab32((x))
-#define __cpu_to_le16(x) __swab16((x))
-#define __le16_to_cpu(x) __swab16((x))
-#define __cpu_to_be64(x) ((__u64)(x))
-#define __be64_to_cpu(x) ((__u64)(x))
-#define __cpu_to_be32(x) ((__u32)(x))
-#define __be32_to_cpu(x) ((__u32)(x))
-#define __cpu_to_be16(x) ((__u16)(x))
-#define __be16_to_cpu(x) ((__u16)(x))
-#define __cpu_to_le64p(x) __swab64p((x))
-#define __le64_to_cpup(x) __swab64p((x))
-#define __cpu_to_le32p(x) __swab32p((x))
-#define __le32_to_cpup(x) __swab32p((x))
-#define __cpu_to_le16p(x) __swab16p((x))
-#define __le16_to_cpup(x) __swab16p((x))
-#define __cpu_to_be64p(x) (*(__u64 *)(x))
-#define __be64_to_cpup(x) (*(__u64 *)(x))
-#define __cpu_to_be32p(x) (*(__u32 *)(x))
-#define __be32_to_cpup(x) (*(__u32 *)(x))
-#define __cpu_to_be16p(x) (*(__u16 *)(x))
-#define __be16_to_cpup(x) (*(__u16 *)(x))
-#define __cpu_to_le64s(x) __swab64s((x))
-#define __le64_to_cpus(x) __swab64s((x))
-#define __cpu_to_le32s(x) __swab32s((x))
-#define __le32_to_cpus(x) __swab32s((x))
-#define __cpu_to_le16s(x) __swab16s((x))
-#define __le16_to_cpus(x) __swab16s((x))
-#define __cpu_to_be64s(x) do {} while (0)
-#define __be64_to_cpus(x) do {} while (0)
-#define __cpu_to_be32s(x) do {} while (0)
-#define __be32_to_cpus(x) do {} while (0)
-#define __cpu_to_be16s(x) do {} while (0)
-#define __be16_to_cpus(x) do {} while (0)
-
-#include "generic.h"
-
-#endif /* _LINUX_BYTEORDER_BIG_ENDIAN_H */
-
diff --git a/drivers/staging/rtl8712/drv_types.h b/drivers/staging/rtl8712/drv_types.h
index e83665d06020..62b55663c63a 100644
--- a/drivers/staging/rtl8712/drv_types.h
+++ b/drivers/staging/rtl8712/drv_types.h
@@ -146,7 +146,7 @@ struct dvobj_priv {
/**
* struct _adapter - the main adapter structure for this device.
*
- * bup: True indicates that the interface is Up.
+ * bup: True indicates that the interface is up.
*/
struct _adapter {
struct dvobj_priv dvobjpriv;
diff --git a/drivers/staging/rtl8712/generic.h b/drivers/staging/rtl8712/generic.h
deleted file mode 100644
index 8868c9f4adf8..000000000000
--- a/drivers/staging/rtl8712/generic.h
+++ /dev/null
@@ -1,178 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * Modifications for inclusion into the Linux staging tree are
- * Copyright(c) 2010 Larry Finger. All rights reserved.
- *
- * Contact information:
- * WLAN FAE <wlanfae@realtek.com>
- * Larry Finger <Larry.Finger@lwfinger.net>
- *
- ******************************************************************************/
-#ifndef _LINUX_BYTEORDER_GENERIC_H
-#define _LINUX_BYTEORDER_GENERIC_H
-
-/*
- * linux/byteorder_generic.h
- * Generic Byte-reordering support
- *
- * Francois-Rene Rideau <fare@tunes.org> 19970707
- * gathered all the good ideas from all asm-foo/byteorder.h into one file,
- * cleaned them up.
- * I hope it is compliant with non-GCC compilers.
- * I decided to put __BYTEORDER_HAS_U64__ in byteorder.h,
- * because I wasn't sure it would be ok to put it in types.h
- * Upgraded it to 2.1.43
- * Francois-Rene Rideau <fare@tunes.org> 19971012
- * Upgraded it to 2.1.57
- * to please Linus T., replaced huge #ifdef's between little/big endian
- * by nestedly #include'd files.
- * Francois-Rene Rideau <fare@tunes.org> 19971205
- * Made it to 2.1.71; now a facelift:
- * Put files under include/linux/byteorder/
- * Split swab from generic support.
- *
- * TODO:
- * = Regular kernel maintainers could also replace all these manual
- * byteswap macros that remain, disseminated among drivers,
- * after some grep or the sources...
- * = Linus might want to rename all these macros and files to fit his taste,
- * to fit his personal naming scheme.
- * = it seems that a few drivers would also appreciate
- * nybble swapping support...
- * = every architecture could add their byteswap macro in asm/byteorder.h
- * see how some architectures already do (i386, alpha, ppc, etc)
- * = cpu_to_beXX and beXX_to_cpu might some day need to be well
- * distinguished throughout the kernel. This is not the case currently,
- * since little endian, big endian, and pdp endian machines needn't it.
- * But this might be the case for, say, a port of Linux to 20/21 bit
- * architectures (and F21 Linux addict around?).
- */
-
-/*
- * The following macros are to be defined by <asm/byteorder.h>:
- *
- * Conversion of long and short int between network and host format
- * ntohl(__u32 x)
- * ntohs(__u16 x)
- * htonl(__u32 x)
- * htons(__u16 x)
- * It seems that some programs (which? where? or perhaps a standard? POSIX?)
- * might like the above to be functions, not macros (why?).
- * if that's true, then detect them, and take measures.
- * Anyway, the measure is: define only ___ntohl as a macro instead,
- * and in a separate file, have
- * unsigned long inline ntohl(x){return ___ntohl(x);}
- *
- * The same for constant arguments
- * __constant_ntohl(__u32 x)
- * __constant_ntohs(__u16 x)
- * __constant_htonl(__u32 x)
- * __constant_htons(__u16 x)
- *
- * Conversion of XX-bit integers (16- 32- or 64-)
- * between native CPU format and little/big endian format
- * 64-bit stuff only defined for proper architectures
- * cpu_to_[bl]eXX(__uXX x)
- * [bl]eXX_to_cpu(__uXX x)
- *
- * The same, but takes a pointer to the value to convert
- * cpu_to_[bl]eXXp(__uXX x)
- * [bl]eXX_to_cpup(__uXX x)
- *
- * The same, but change in situ
- * cpu_to_[bl]eXXs(__uXX x)
- * [bl]eXX_to_cpus(__uXX x)
- *
- * See asm-foo/byteorder.h for examples of how to provide
- * architecture-optimized versions
- *
- */
-
-
-/*
- * inside the kernel, we can use nicknames;
- * outside of it, we must avoid POSIX namespace pollution...
- */
-#define cpu_to_le64 __cpu_to_le64
-#define le64_to_cpu __le64_to_cpu
-#define cpu_to_le32 __cpu_to_le32
-#define le32_to_cpu __le32_to_cpu
-#define cpu_to_le16 __cpu_to_le16
-#define le16_to_cpu __le16_to_cpu
-#define cpu_to_be64 __cpu_to_be64
-#define be64_to_cpu __be64_to_cpu
-#define cpu_to_be32 __cpu_to_be32
-#define be32_to_cpu __be32_to_cpu
-#define cpu_to_be16 __cpu_to_be16
-#define be16_to_cpu __be16_to_cpu
-#define cpu_to_le64p __cpu_to_le64p
-#define le64_to_cpup __le64_to_cpup
-#define cpu_to_le32p __cpu_to_le32p
-#define le32_to_cpup __le32_to_cpup
-#define cpu_to_le16p __cpu_to_le16p
-#define le16_to_cpup __le16_to_cpup
-#define cpu_to_be64p __cpu_to_be64p
-#define be64_to_cpup __be64_to_cpup
-#define cpu_to_be32p __cpu_to_be32p
-#define be32_to_cpup __be32_to_cpup
-#define cpu_to_be16p __cpu_to_be16p
-#define be16_to_cpup __be16_to_cpup
-#define cpu_to_le64s __cpu_to_le64s
-#define le64_to_cpus __le64_to_cpus
-#define cpu_to_le32s __cpu_to_le32s
-#define le32_to_cpus __le32_to_cpus
-#define cpu_to_le16s __cpu_to_le16s
-#define le16_to_cpus __le16_to_cpus
-#define cpu_to_be64s __cpu_to_be64s
-#define be64_to_cpus __be64_to_cpus
-#define cpu_to_be32s __cpu_to_be32s
-#define be32_to_cpus __be32_to_cpus
-#define cpu_to_be16s __cpu_to_be16s
-#define be16_to_cpus __be16_to_cpus
-
-
-/*
- * Handle ntohl and suches. These have various compatibility
- * issues - like we want to give the prototype even though we
- * also have a macro for them in case some strange program
- * wants to take the address of the thing or something..
- *
- * Note that these used to return a "long" in libc5, even though
- * long is often 64-bit these days.. Thus the casts.
- *
- * They have to be macros in order to do the constant folding
- * correctly - if the argument passed into a inline function
- * it is no longer constant according to gcc..
- */
-
-#undef ntohl
-#undef ntohs
-#undef htonl
-#undef htons
-
-/*
- * Do the prototypes. Somebody might want to take the
- * address or some such sick thing..
- */
-extern __u32 ntohl(__u32);
-extern __u32 htonl(__u32);
-extern unsigned short int ntohs(unsigned short int);
-extern unsigned short int htons(unsigned short int);
-
-#endif /* _LINUX_BYTEORDER_GENERIC_H */
-
diff --git a/drivers/staging/rtl8712/hal_init.c b/drivers/staging/rtl8712/hal_init.c
index cc893c0f5ad3..cb9d4cfe8fe4 100644
--- a/drivers/staging/rtl8712/hal_init.c
+++ b/drivers/staging/rtl8712/hal_init.c
@@ -36,7 +36,6 @@
#include "osdep_service.h"
#include "drv_types.h"
-#include "rtl871x_byteorder.h"
#include "usb_osintf.h"
#define FWBUFF_ALIGN_SZ 512
diff --git a/drivers/staging/rtl8712/ieee80211.h b/drivers/staging/rtl8712/ieee80211.h
index 3c0092b7de09..21515c31b373 100644
--- a/drivers/staging/rtl8712/ieee80211.h
+++ b/drivers/staging/rtl8712/ieee80211.h
@@ -705,7 +705,7 @@ enum ieee80211_state {
IEEE80211_ASSOCIATING_RETRY,
/* the association procedure is sending AUTH request*/
IEEE80211_ASSOCIATING_AUTHENTICATING,
- /* the association procedure has successfully authentcated
+ /* the association procedure has successfully authenticated
* and is sending association request
*/
IEEE80211_ASSOCIATING_AUTHENTICATED,
diff --git a/drivers/staging/rtl8712/if_ether.h b/drivers/staging/rtl8712/if_ether.h
deleted file mode 100644
index 2bbe527bcd5c..000000000000
--- a/drivers/staging/rtl8712/if_ether.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * Modifications for inclusion into the Linux staging tree are
- * Copyright(c) 2010 Larry Finger. All rights reserved.
- *
- * Contact information:
- * WLAN FAE <wlanfae@realtek.com>
- * Larry Finger <Larry.Finger@lwfinger.net>
- *
- ******************************************************************************/
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Global definitions for the Ethernet IEEE 802.3 interface.
- *
- * Version: @(#)if_ether.h 1.0.1a 02/08/94
- *
- * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- * Donald Becker, <becker@super.org>
- * Alan Cox, <alan@redhat.com>
- * Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
- *
- * 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.
- */
-
-#ifndef _LINUX_IF_ETHER_H
-#define _LINUX_IF_ETHER_H
-
-/*
- * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble
- * and FCS/CRC (frame check sequence).
- */
-
-#define ETH_ALEN 6 /* Octets in one ethernet addr */
-#define ETH_HLEN 14 /* Total octets in header. */
-#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */
-#define ETH_DATA_LEN 1500 /* Max. octets in payload */
-#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
-
-/*
- * These are the defined Ethernet Protocol ID's.
- */
-
-#define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */
-#define ETH_P_PUP 0x0200 /* Xerox PUP packet */
-#define ETH_P_PUPAT 0x0201 /* Xerox PUP Addr Trans packet */
-#define ETH_P_IP 0x0800 /* Internet Protocol packet */
-#define ETH_P_X25 0x0805 /* CCITT X.25 */
-#define ETH_P_ARP 0x0806 /* Address Resolution packet */
-#define ETH_P_BPQ 0x08FF /* G8BPQ AX.25 Ethernet Packet
- * [ NOT AN OFFICIAL ID ] */
-#define ETH_P_IEEEPUP 0x0a00 /* Xerox IEEE802.3 PUP packet */
-#define ETH_P_IEEEPUPAT 0x0a01 /* Xerox IEEE802.3 PUP Addr
- * Trans packet */
-#define ETH_P_DEC 0x6000 /* DEC Assigned proto */
-#define ETH_P_DNA_DL 0x6001 /* DEC DNA Dump/Load */
-#define ETH_P_DNA_RC 0x6002 /* DEC DNA Remote Console */
-#define ETH_P_DNA_RT 0x6003 /* DEC DNA Routing */
-#define ETH_P_LAT 0x6004 /* DEC LAT */
-#define ETH_P_DIAG 0x6005 /* DEC Diagnostics */
-#define ETH_P_CUST 0x6006 /* DEC Customer use */
-#define ETH_P_SCA 0x6007 /* DEC Systems Comms Arch */
-#define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */
-#define ETH_P_ATALK 0x809B /* Appletalk DDP */
-#define ETH_P_AARP 0x80F3 /* Appletalk AARP */
-#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */
-#define ETH_P_IPX 0x8137 /* IPX over DIX */
-#define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */
-#define ETH_P_PPP_DISC 0x8863 /* PPPoE discovery messages */
-#define ETH_P_PPP_SES 0x8864 /* PPPoE session messages */
-#define ETH_P_ATMMPOA 0x884c /* MultiProtocol Over ATM */
-#define ETH_P_ATMFATE 0x8884 /* Frame-based ATM Transport
- * over Ethernet
- */
-
-/*
- * Non DIX types. Won't clash for 1500 types.
- */
-
-#define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */
-#define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */
-#define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */
-#define ETH_P_802_2 0x0004 /* 802.2 frames */
-#define ETH_P_SNAP 0x0005 /* Internal only */
-#define ETH_P_DDCMP 0x0006 /* DEC DDCMP: Internal only */
-#define ETH_P_WAN_PPP 0x0007 /* Dummy type for WAN PPP frames*/
-#define ETH_P_PPP_MP 0x0008 /* Dummy type for PPP MP frames */
-#define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */
-#define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/
-#define ETH_P_TR_802_2 0x0011i /* 802.2 frames */
-#define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */
-#define ETH_P_CONTROL 0x0016 /* Card specific control frames */
-#define ETH_P_IRDA 0x0017 /* Linux-IrDA */
-#define ETH_P_ECONET 0x0018 /* Acorn Econet */
-
-/*
- * This is an Ethernet frame header.
- */
-
-struct ethhdr {
- unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
- unsigned char h_source[ETH_ALEN]; /* source ether addr */
- unsigned short h_proto; /* packet type ID field */
-};
-
-struct _vlan {
- unsigned short h_vlan_TCI; /* Encapsulates priority and VLAN ID*/
- unsigned short h_vlan_encapsulated_proto;
-};
-
-
-
-#define get_vlan_id(pvlan) ((ntohs((unsigned short)pvlan->h_vlan_TCI)) & 0xfff)
-#define get_vlan_priority(pvlan) ((ntohs((unsigned short)\
- pvlan->h_vlan_TCI)) >> 13)
-#define get_vlan_encap_proto(pvlan) (ntohs((unsigned short)\
- pvlan->h_vlan_encapsulated_proto))
-
-
-#endif /* _LINUX_IF_ETHER_H */
-
diff --git a/drivers/staging/rtl8712/ip.h b/drivers/staging/rtl8712/ip.h
deleted file mode 100644
index f37b0f8d14d4..000000000000
--- a/drivers/staging/rtl8712/ip.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Definitions for the IP protocol.
- *
- * Version: @(#)ip.h 1.0.2 04/28/93
- *
- * Authors: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- *
- * 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.
- */
-#ifndef _LINUX_IP_H
-#define _LINUX_IP_H
-
-#include "rtl871x_byteorder.h"
-
-/* SOL_IP socket options */
-
-#define IPTOS_TOS_MASK 0x1E
-#define IPTOS_TOS(tos) ((tos)&IPTOS_TOS_MASK)
-#define IPTOS_LOWDELAY 0x10
-#define IPTOS_THROUGHPUT 0x08
-#define IPTOS_RELIABILITY 0x04
-#define IPTOS_MINCOST 0x02
-
-#define IPTOS_PREC_MASK 0xE0
-#define IPTOS_PREC(tos) ((tos)&IPTOS_PREC_MASK)
-#define IPTOS_PREC_NETCONTROL 0xe0
-#define IPTOS_PREC_INTERNETCONTROL 0xc0
-#define IPTOS_PREC_CRITIC_ECP 0xa0
-#define IPTOS_PREC_FLASHOVERRIDE 0x80
-#define IPTOS_PREC_FLASH 0x60
-#define IPTOS_PREC_IMMEDIATE 0x40
-#define IPTOS_PREC_PRIORITY 0x20
-#define IPTOS_PREC_ROUTINE 0x00
-
-/* IP options */
-#define IPOPT_COPY 0x80
-#define IPOPT_CLASS_MASK 0x60
-#define IPOPT_NUMBER_MASK 0x1f
-
-#define IPOPT_COPIED(o) ((o)&IPOPT_COPY)
-#define IPOPT_CLASS(o) ((o)&IPOPT_CLASS_MASK)
-#define IPOPT_NUMBER(o) ((o)&IPOPT_NUMBER_MASK)
-
-#define IPOPT_CONTROL 0x00
-#define IPOPT_RESERVED1 0x20
-#define IPOPT_MEASUREMENT 0x40
-#define IPOPT_RESERVED2 0x60
-
-#define IPOPT_END (0 | IPOPT_CONTROL)
-#define IPOPT_NOOP (1 | IPOPT_CONTROL)
-#define IPOPT_SEC (2 | IPOPT_CONTROL|IPOPT_COPY)
-#define IPOPT_LSRR (3 | IPOPT_CONTROL|IPOPT_COPY)
-#define IPOPT_TIMESTAMP (4 | IPOPT_MEASUREMENT)
-#define IPOPT_RR (7 | IPOPT_CONTROL)
-#define IPOPT_SID (8 | IPOPT_CONTROL | IPOPT_COPY)
-#define IPOPT_SSRR (9 | IPOPT_CONTROL | IPOPT_COPY)
-#define IPOPT_RA (20 | IPOPT_CONTROL | IPOPT_COPY)
-
-#define IPVERSION 4
-#define MAXTTL 255
-#define IPDEFTTL 64
-
-/* struct timestamp, struct route and MAX_ROUTES are removed.
- *
- * REASONS: it is clear that nobody used them because:
- * - MAX_ROUTES value was wrong.
- * - "struct route" was wrong.
- * - "struct timestamp" had fatally misaligned bitfields and was completely
- * unusable.
- */
-
-#define IPOPT_OPTVAL 0
-#define IPOPT_OLEN 1
-#define IPOPT_OFFSET 2
-#define IPOPT_MINOFF 4
-#define MAX_IPOPTLEN 40
-#define IPOPT_NOP IPOPT_NOOP
-#define IPOPT_EOL IPOPT_END
-#define IPOPT_TS IPOPT_TIMESTAMP
-
-#define IPOPT_TS_TSONLY 0 /* timestamps only */
-#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */
-#define IPOPT_TS_PRESPEC 3 /* specified modules only */
-
-struct ip_options {
- __u32 faddr; /* Saved first hop address */
- unsigned char optlen;
- unsigned char srr;
- unsigned char rr;
- unsigned char ts;
- unsigned char is_setbyuser:1, /* Set by setsockopt? */
- is_data:1, /* Options in __data, rather than skb */
- is_strictroute:1, /* Strict source route */
- srr_is_hit:1, /* Packet destination addr was our one*/
- is_changed:1, /* IP checksum more not valid */
- rr_needaddr:1, /* Need to record addr of outgoing dev*/
- ts_needtime:1, /* Need to record timestamp */
- ts_needaddr:1; /* Need to record addr of outgoing dev*/
- unsigned char router_alert;
- unsigned char __pad1;
- unsigned char __pad2;
- unsigned char __data[0];
-};
-
-#define optlength(opt) (sizeof(struct ip_options) + opt->optlen)
-
-struct iphdr {
-#if defined(__LITTLE_ENDIAN_BITFIELD)
- __u8 ihl:4,
- version:4;
-#elif defined(__BIG_ENDIAN_BITFIELD)
- __u8 version:4,
- ihl:4;
-#else
-#error "Please fix <asm/byteorder.h>"
-#endif
- __u8 tos;
- __u16 tot_len;
- __u16 id;
- __u16 frag_off;
- __u8 ttl;
- __u8 protocol;
- __u16 check;
- __u32 saddr;
- __u32 daddr;
- /*The options start here. */
-};
-
-#endif /* _LINUX_IP_H */
-
diff --git a/drivers/staging/rtl8712/little_endian.h b/drivers/staging/rtl8712/little_endian.h
deleted file mode 100644
index cd57d6c2850f..000000000000
--- a/drivers/staging/rtl8712/little_endian.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * Modifications for inclusion into the Linux staging tree are
- * Copyright(c) 2010 Larry Finger. All rights reserved.
- *
- * Contact information:
- * WLAN FAE <wlanfae@realtek.com>
- * Larry Finger <Larry.Finger@lwfinger.net>
- *
- ******************************************************************************/
-#ifndef _LINUX_BYTEORDER_LITTLE_ENDIAN_H
-#define _LINUX_BYTEORDER_LITTLE_ENDIAN_H
-
-#ifndef __LITTLE_ENDIAN
-#define __LITTLE_ENDIAN 1234
-#endif
-#ifndef __LITTLE_ENDIAN_BITFIELD
-#define __LITTLE_ENDIAN_BITFIELD
-#endif
-
-#include "swab.h"
-
-#define __constant_htonl(x) ___constant_swab32((x))
-#define __constant_ntohl(x) ___constant_swab32((x))
-#define __constant_htons(x) ___constant_swab16((x))
-#define __constant_ntohs(x) ___constant_swab16((x))
-#define __constant_cpu_to_le64(x) ((__u64)(x))
-#define __constant_le64_to_cpu(x) ((__u64)(x))
-#define __constant_cpu_to_le32(x) ((__u32)(x))
-#define __constant_le32_to_cpu(x) ((__u32)(x))
-#define __constant_cpu_to_le16(x) ((__u16)(x))
-#define __constant_le16_to_cpu(x) ((__u16)(x))
-#define __constant_cpu_to_be64(x) ___constant_swab64((x))
-#define __constant_be64_to_cpu(x) ___constant_swab64((x))
-#define __constant_cpu_to_be32(x) ___constant_swab32((x))
-#define __constant_be32_to_cpu(x) ___constant_swab32((x))
-#define __constant_cpu_to_be16(x) ___constant_swab16((x))
-#define __constant_be16_to_cpu(x) ___constant_swab16((x))
-#define __cpu_to_le64(x) ((__u64)(x))
-#define __le64_to_cpu(x) ((__u64)(x))
-#define __cpu_to_le32(x) ((__u32)(x))
-#define __le32_to_cpu(x) ((__u32)(x))
-#define __cpu_to_le16(x) ((__u16)(x))
-#define __le16_to_cpu(x) ((__u16)(x))
-#define __cpu_to_be64(x) __swab64((x))
-#define __be64_to_cpu(x) __swab64((x))
-#define __cpu_to_be32(x) __swab32((x))
-#define __be32_to_cpu(x) __swab32((x))
-#define __cpu_to_be16(x) __swab16((x))
-#define __be16_to_cpu(x) __swab16((x))
-#define __cpu_to_le64p(x) (*(__u64 *)(x))
-#define __le64_to_cpup(x) (*(__u64 *)(x))
-#define __cpu_to_le32p(x) (*(__u32 *)(x))
-#define __le32_to_cpup(x) (*(__u32 *)(x))
-#define __cpu_to_le16p(x) (*(__u16 *)(x))
-#define __le16_to_cpup(x) (*(__u16 *)(x))
-#define __cpu_to_be64p(x) __swab64p((x))
-#define __be64_to_cpup(x) __swab64p((x))
-#define __cpu_to_be32p(x) __swab32p((x))
-#define __be32_to_cpup(x) __swab32p((x))
-#define __cpu_to_be16p(x) __swab16p((x))
-#define __be16_to_cpup(x) __swab16p((x))
-#define __cpu_to_le64s(x) do {} while (0)
-#define __le64_to_cpus(x) do {} while (0)
-#define __cpu_to_le32s(x) do {} while (0)
-#define __le32_to_cpus(x) do {} while (0)
-#define __cpu_to_le16s(x) do {} while (0)
-#define __le16_to_cpus(x) do {} while (0)
-#define __cpu_to_be64s(x) __swab64s((x))
-#define __be64_to_cpus(x) __swab64s((x))
-#define __cpu_to_be32s(x) __swab32s((x))
-#define __be32_to_cpus(x) __swab32s((x))
-#define __cpu_to_be16s(x) __swab16s((x))
-#define __be16_to_cpus(x) __swab16s((x))
-
-#include "generic.h"
-
-#endif /* _LINUX_BYTEORDER_LITTLE_ENDIAN_H */
-
diff --git a/drivers/staging/rtl8712/os_intfs.c b/drivers/staging/rtl8712/os_intfs.c
index 7bbd53a410e3..448f00dd68fe 100644
--- a/drivers/staging/rtl8712/os_intfs.c
+++ b/drivers/staging/rtl8712/os_intfs.c
@@ -52,7 +52,7 @@ static int lbkmode = RTL8712_AIR_TRX;
static int hci = RTL8712_USB;
static int ampdu_enable = 1;/*for enable tx_ampdu*/
-/* The video_mode variable is for vedio mode.*/
+/* The video_mode variable is for video mode.*/
/* It may be specify when inserting module with video_mode=1 parameter.*/
static int video_mode = 1; /* enable video mode*/
@@ -248,7 +248,7 @@ static u32 start_drv_threads(struct _adapter *padapter)
void r8712_stop_drv_threads(struct _adapter *padapter)
{
- /*Below is to termindate r8712_cmd_thread & event_thread...*/
+ /*Below is to terminate r8712_cmd_thread & event_thread...*/
up(&padapter->cmdpriv.cmd_queue_sema);
if (padapter->cmdThread)
_down_sema(&padapter->cmdpriv.terminate_cmdthread_sema);
diff --git a/drivers/staging/rtl8712/osdep_service.h b/drivers/staging/rtl8712/osdep_service.h
index 9ba603310fdc..f1ccc7ebbda7 100644
--- a/drivers/staging/rtl8712/osdep_service.h
+++ b/drivers/staging/rtl8712/osdep_service.h
@@ -29,7 +29,6 @@
#define _SUCCESS 1
#define _FAIL 0
-#include <linux/version.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
@@ -107,8 +106,6 @@ static inline void _set_workitem(_workitem *pwork)
schedule_work(pwork);
}
-#include "rtl871x_byteorder.h"
-
#ifndef BIT
#define BIT(x) (1 << (x))
#endif
diff --git a/drivers/staging/rtl8712/rtl8712_cmd.c b/drivers/staging/rtl8712/rtl8712_cmd.c
index 9f6ebc419b0b..088647cdca99 100644
--- a/drivers/staging/rtl8712/rtl8712_cmd.c
+++ b/drivers/staging/rtl8712/rtl8712_cmd.c
@@ -50,7 +50,6 @@
#include "drv_types.h"
#include "recv_osdep.h"
#include "mlme_osdep.h"
-#include "rtl871x_byteorder.h"
#include "rtl871x_ioctl_set.h"
static void check_hw_pbc(struct _adapter *padapter)
@@ -69,7 +68,7 @@ static void check_hw_pbc(struct _adapter *padapter)
* After trigger PBC, the variable will be set to false */
DBG_8712("CheckPbcGPIO - PBC is pressed !!!!\n");
/* 0 is the default value and it means the application monitors
- * the HW PBC doesn't privde its pid to driver. */
+ * the HW PBC doesn't provide its pid to driver. */
if (padapter->pid == 0)
return;
kill_pid(find_vpid(padapter->pid), SIGUSR1, 1);
@@ -382,7 +381,7 @@ _next:
*pcmdbuf = cpu_to_le32((cmdsz & 0x0000ffff) |
(pcmd->cmdcode << 16) |
(pcmdpriv->cmd_seq << 24));
- pcmdbuf += 2 ; /* 8 bytes aligment */
+ pcmdbuf += 2 ; /* 8 bytes alignment */
memcpy((u8 *)pcmdbuf, pcmd->parmbuf, pcmd->cmdsz);
while (check_cmd_fifo(padapter, wr_sz) == _FAIL) {
if ((padapter->bDriverStopped == true) ||
@@ -471,7 +470,7 @@ void r8712_event_handle(struct _adapter *padapter, uint *peventbuf)
pevt_priv->event_seq++; /* update evt_seq */
if (pevt_priv->event_seq > 127)
pevt_priv->event_seq = 0;
- peventbuf = peventbuf + 2; /* move to event content, 8 bytes aligment */
+ peventbuf = peventbuf + 2; /* move to event content, 8 bytes alignment */
if (peventbuf) {
event_callback = wlanevents[evt_code].event_callback;
if (event_callback)
diff --git a/drivers/staging/rtl8712/rtl8712_cmd.h b/drivers/staging/rtl8712/rtl8712_cmd.h
index 766a6463266a..039ab3e97172 100644
--- a/drivers/staging/rtl8712/rtl8712_cmd.h
+++ b/drivers/staging/rtl8712/rtl8712_cmd.h
@@ -121,7 +121,7 @@ enum rtl8712_h2c_cmd {
GEN_CMD_CODE(_GetCurDataRate) ,
GEN_CMD_CODE(_GetTxRetrycnt), /* to record times that Tx retry to
- * transmmit packet after association
+ * transmit packet after association
*/
GEN_CMD_CODE(_GetRxRetrycnt), /* to record total number of the
* received frame with ReTry bit set in
diff --git a/drivers/staging/rtl8712/rtl8712_efuse.c b/drivers/staging/rtl8712/rtl8712_efuse.c
index b08e9a25c9c5..377fca905801 100644
--- a/drivers/staging/rtl8712/rtl8712_efuse.c
+++ b/drivers/staging/rtl8712/rtl8712_efuse.c
@@ -417,7 +417,7 @@ u8 r8712_efuse_pg_packet_write(struct _adapter *padapter, const u8 offset,
} else { /* write header fail */
bResult = false;
if (0xFF == efuse_data)
- return bResult; /* not thing damaged. */
+ return bResult; /* nothing damaged. */
/* call rescue procedure */
if (fix_header(padapter, efuse_data, efuse_addr) ==
false)
diff --git a/drivers/staging/rtl8712/rtl8712_gp_bitdef.h b/drivers/staging/rtl8712/rtl8712_gp_bitdef.h
index 884a8212176d..138ea453d9df 100644
--- a/drivers/staging/rtl8712/rtl8712_gp_bitdef.h
+++ b/drivers/staging/rtl8712/rtl8712_gp_bitdef.h
@@ -70,7 +70,7 @@
#define GPIOSEL_BT 2 /* BT_coex*/
#define GPIOSEL_WLANDBG 3 /* WLANDBG*/
#define GPIOSEL_GPIO_MASK (~(BIT(0)|BIT(1)))
-/* HW Readio OFF switch (GPIO BIT) */
+/* HW Radio OFF switch (GPIO BIT) */
#define HAL_8192S_HW_GPIO_OFF_BIT BIT(3)
#define HAL_8192S_HW_GPIO_OFF_MASK 0xF7
#define HAL_8192S_HW_GPIO_WPS_BIT BIT(4)
diff --git a/drivers/staging/rtl8712/rtl8712_hal.h b/drivers/staging/rtl8712/rtl8712_hal.h
index d19865a5a50c..4c51fa373b54 100644
--- a/drivers/staging/rtl8712/rtl8712_hal.h
+++ b/drivers/staging/rtl8712/rtl8712_hal.h
@@ -83,7 +83,7 @@ struct fw_priv { /*8-bytes alignment required*/
unsigned char rfintfs; /* 0:SWSI, 1:HWSI, 2:HWPI*/
unsigned char def_nettype;
unsigned char turboMode;
- unsigned char lowPowerMode;/* 0: noral mode, 1: low power mode*/
+ unsigned char lowPowerMode;/* 0: normal mode, 1: low power mode*/
/*--- long word 2 ----*/
unsigned char lbk_mode; /*0x00: normal, 0x03: MACLBK, 0x01: PHYLBK*/
unsigned char mp_mode; /* 1: for MP use, 0: for normal driver */
@@ -123,7 +123,7 @@ struct fw_priv { /*8-bytes alignment required*/
unsigned char rsvd053;
};
-struct fw_hdr {/*8-byte alinment required*/
+struct fw_hdr {/*8-byte alignment required*/
unsigned short signature;
unsigned short version; /*0x8000 ~ 0x8FFF for FPGA version,
*0x0000 ~ 0x7FFF for ASIC version,*/
diff --git a/drivers/staging/rtl8712/rtl8712_led.c b/drivers/staging/rtl8712/rtl8712_led.c
index bac56e5caf12..c9eb4b74799b 100644
--- a/drivers/staging/rtl8712/rtl8712_led.c
+++ b/drivers/staging/rtl8712/rtl8712_led.c
@@ -60,7 +60,7 @@ enum _LED_STATE_871x {
* the # of times to blink is depend on time
* for scanning. */
LED_NO_LINK_BLINK = 7, /* LED is blinking during no link state. */
- LED_BLINK_StartToBlink = 8,/* Customzied for Sercomm Printer
+ LED_BLINK_StartToBlink = 8,/* Customized for Sercomm Printer
* Server case */
LED_BLINK_WPS = 9, /* LED is blinkg during WPS communication */
LED_TXRX_BLINK = 10,
@@ -826,7 +826,7 @@ static void BlinkTimerCallback(unsigned long data)
{
struct LED_871x *pLed = (struct LED_871x *)data;
- /* This fixed the crash problem on Fedora 12 when trying to do thei
+ /* This fixed the crash problem on Fedora 12 when trying to do the
* insmod;ifconfig up;rmmod commands. */
if ((pLed->padapter->bSurpriseRemoved == true) ||
(pLed->padapter->bDriverStopped == true))
@@ -836,7 +836,7 @@ static void BlinkTimerCallback(unsigned long data)
/* Description:
* Callback function of LED BlinkWorkItem.
- * We dispatch acture LED blink action according to LedStrategy.
+ * We dispatch actual LED blink action according to LedStrategy.
*/
static void BlinkWorkItemCallback(struct work_struct *work)
{
diff --git a/drivers/staging/rtl8712/rtl8712_recv.c b/drivers/staging/rtl8712/rtl8712_recv.c
index fa6dc9c09b3f..8e82ce2fee38 100644
--- a/drivers/staging/rtl8712/rtl8712_recv.c
+++ b/drivers/staging/rtl8712/rtl8712_recv.c
@@ -28,12 +28,13 @@
#define _RTL8712_RECV_C_
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+
#include "osdep_service.h"
#include "drv_types.h"
#include "recv_osdep.h"
#include "mlme_osdep.h"
-#include "ip.h"
-#include "if_ether.h"
#include "ethernet.h"
#include "usb_ops.h"
#include "wifi.h"
@@ -459,7 +460,7 @@ void r8712_rxcmd_event_hdl(struct _adapter *padapter, void *prxcmdbuf)
cmd_seq = (u8)((le32_to_cpu(voffset) >> 24) & 0x7f);
eid = (u8)((le32_to_cpu(voffset) >> 16) & 0xff);
r8712_event_handle(padapter, (uint *)poffset);
- poffset += (cmd_len + 8);/*8 bytes aligment*/
+ poffset += (cmd_len + 8);/*8 bytes alignment*/
} while (le32_to_cpu(voffset) & BIT(31));
}
@@ -603,7 +604,7 @@ static int recv_indicatepkt_reorder(struct _adapter *padapter,
}
}
spin_lock_irqsave(&ppending_recvframe_queue->lock, irql);
- /*s2. check if winstart_b(indicate_seq) needs to been updated*/
+ /*s2. check if winstart_b(indicate_seq) needs to be updated*/
if (!check_indicate_seq(preorder_ctrl, pattrib->seq_num))
goto _err_exit;
/*s3. Insert all packet into Reorder Queue to maintain its ordering.*/
diff --git a/drivers/staging/rtl8712/rtl8712_xmit.c b/drivers/staging/rtl8712/rtl8712_xmit.c
index 693331955d67..3d23514c0222 100644
--- a/drivers/staging/rtl8712/rtl8712_xmit.c
+++ b/drivers/staging/rtl8712/rtl8712_xmit.c
@@ -30,7 +30,6 @@
#include "osdep_service.h"
#include "drv_types.h"
-#include "rtl871x_byteorder.h"
#include "wifi.h"
#include "osdep_intf.h"
#include "usb_ops.h"
diff --git a/drivers/staging/rtl8712/rtl871x_byteorder.h b/drivers/staging/rtl8712/rtl871x_byteorder.h
deleted file mode 100644
index bd3703b98bce..000000000000
--- a/drivers/staging/rtl8712/rtl871x_byteorder.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- *
- ******************************************************************************/
-#ifndef _RTL871X_BYTEORDER_H_
-#define _RTL871X_BYTEORDER_H_
-
-#if defined(__LITTLE_ENDIAN)
-# include "little_endian.h"
-#elif defined(__BIG_ENDIAN)
-# include "big_endian.h"
-#else
-# error "Must be LITTLE/BIG Endian Host"
-#endif
-
-#endif /* _RTL871X_BYTEORDER_H_ */
-
diff --git a/drivers/staging/rtl8712/rtl871x_cmd.c b/drivers/staging/rtl8712/rtl871x_cmd.c
index d77388bdba7b..659683e022b9 100644
--- a/drivers/staging/rtl8712/rtl871x_cmd.c
+++ b/drivers/staging/rtl8712/rtl871x_cmd.c
@@ -50,7 +50,6 @@
#include "drv_types.h"
#include "recv_osdep.h"
#include "mlme_osdep.h"
-#include "rtl871x_byteorder.h"
/*
Caller and the r8712_cmd_thread can protect cmd_q by spin_lock.
diff --git a/drivers/staging/rtl8712/rtl871x_cmd.h b/drivers/staging/rtl8712/rtl871x_cmd.h
index 757ebf77e9d6..9d93189d8700 100644
--- a/drivers/staging/rtl8712/rtl871x_cmd.h
+++ b/drivers/staging/rtl8712/rtl871x_cmd.h
@@ -720,7 +720,7 @@ struct DisconnectCtrlEx_param {
* Result:
* 0x00: success
* 0x01: success, and check Response.
- * 0x02: cmd ignored due to duplicated sequcne number
+ * 0x02: cmd ignored due to duplicated sequence number
* 0x03: cmd dropped due to invalid cmd code
* 0x04: reserved.
*/
diff --git a/drivers/staging/rtl8712/rtl871x_io.h b/drivers/staging/rtl8712/rtl871x_io.h
index d3d8727c2ec5..dc23395fec3b 100644
--- a/drivers/staging/rtl8712/rtl871x_io.h
+++ b/drivers/staging/rtl8712/rtl871x_io.h
@@ -117,7 +117,7 @@ struct io_req {
u32 command;
u32 status;
u8 *pbuf;
- void (*_async_io_callback)(struct _adapter *padater,
+ void (*_async_io_callback)(struct _adapter *padapter,
struct io_req *pio_req, u8 *cnxt);
u8 *cnxt;
};
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
index ef35bc29a3fa..35e781fca4a0 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
@@ -43,7 +43,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/version.h>
#include <linux/io.h>
#include <linux/semaphore.h>
#include <net/iw_handler.h>
@@ -242,7 +241,7 @@ static inline char *translate_scan(struct _adapter *padapter,
/* Add frequency/channel */
iwe.cmd = SIOCGIWFREQ;
{
- /* check legel index */
+ /* check legal index */
u8 dsconfig = pnetwork->network.Configuration.DSConfig;
if (dsconfig >= 1 && dsconfig <= sizeof(
ieee80211_wlan_frequencies) / sizeof(long))
@@ -810,11 +809,11 @@ static int r871x_wx_set_pmkid(struct net_device *dev,
/*
There are the BSSID information in the bssid.sa_data array.
- If cmd is IW_PMKSA_FLUSH, it means the wpa_suppplicant wants to clear
- all the PMKID information. If cmd is IW_PMKSA_ADD, it means the
- wpa_supplicant wants to add a PMKID/BSSID to driver.
+ If cmd is IW_PMKSA_FLUSH, it means the wpa_supplicant wants to clear
+ all the PMKID information. If cmd is IW_PMKSA_ADD, it means the
+ wpa_supplicant wants to add a PMKID/BSSID to driver.
If cmd is IW_PMKSA_REMOVE, it means the wpa_supplicant wants to
- remove a PMKID/BSSID from driver.
+ remove a PMKID/BSSID from driver.
*/
if (pPMK == NULL)
return -EINVAL;
@@ -924,7 +923,7 @@ static int r8711_wx_get_range(struct net_device *dev,
range->max_qual.noise = 100;
range->max_qual.updated = 7; /* Updated all three */
range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */
- /* TODO: Find real 'good' to 'bad' threshol value for RSSI */
+ /* TODO: Find real 'good' to 'bad' threshold value for RSSI */
range->avg_qual.level = 20 + -98;
range->avg_qual.noise = 0;
range->avg_qual.updated = 7; /* Updated all three */
@@ -1071,7 +1070,7 @@ FREE_EXT:
* MAC# of a preferred Access Point.
* Currently, the request comes via Wireless Extensions' SIOCSIWAP ioctl.
*
- * For this operation to succeed, there is no need for the interface to be Up.
+ * For this operation to succeed, there is no need for the interface to be up.
*
*/
static int r8711_wx_set_wap(struct net_device *dev,
@@ -2389,10 +2388,10 @@ static struct iw_statistics *r871x_get_wireless_stats(struct net_device *dev)
struct iw_handler_def r871x_handlers_def = {
.standard = r8711_handlers,
- .num_standard = sizeof(r8711_handlers) / sizeof(iw_handler),
+ .num_standard = ARRAY_SIZE(r8711_handlers),
.private = r8711_private_handler,
.private_args = (struct iw_priv_args *)r8711_private_args,
- .num_private = sizeof(r8711_private_handler) / sizeof(iw_handler),
+ .num_private = ARRAY_SIZE(r8711_private_handler),
.num_private_args = sizeof(r8711_private_args) /
sizeof(struct iw_priv_args),
.get_wireless_stats = r871x_get_wireless_stats
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_set.c b/drivers/staging/rtl8712/rtl871x_ioctl_set.c
index fb29b423752f..f352b32355a0 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_set.c
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_set.c
@@ -264,7 +264,7 @@ void r8712_set_802_11_infrastructure_mode(struct _adapter *padapter,
(*pold_state == Ndis802_11Infrastructure) ||
(*pold_state == Ndis802_11IBSS)) {
/* will clr Linked_state before this function,
- * we must have chked whether issue dis-assoc_cmd or
+ * we must have checked whether issue dis-assoc_cmd or
* not */
r8712_ind_disconnect(padapter);
}
diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c
index 4277d0304b7a..dc7adc132d12 100644
--- a/drivers/staging/rtl8712/rtl871x_mlme.c
+++ b/drivers/staging/rtl8712/rtl871x_mlme.c
@@ -137,7 +137,7 @@ static void _free_network_nolock(struct mlme_priv *pmlmepriv,
/*
return the wlan_network with the matching addr
- Shall be calle under atomic context...
+ Shall be called under atomic context...
to avoid possible racing condition...
*/
static struct wlan_network *_r8712_find_network(struct __queue *scanned_queue,
@@ -255,7 +255,7 @@ void r8712_free_network_queue(struct _adapter *dev)
/*
return the wlan_network with the matching addr
- Shall be calle under atomic context...
+ Shall be called under atomic context...
to avoid possible racing condition...
*/
static struct wlan_network *r8712_find_network(struct __queue *scanned_queue,
@@ -1037,7 +1037,7 @@ void r8712_cpwm_event_callback(struct _adapter *adapter, u8 *pbuf)
* and the WiFi client will drop the data with seq number 0.
* So, the 8712 firmware has to inform driver with receiving the
* ADDBA-Req frame so that the driver can reset the
- * sequence value of Rx reorder contorl.
+ * sequence value of Rx reorder control.
*/
void r8712_got_addbareq_event_callback(struct _adapter *adapter, u8 *pbuf)
{
@@ -1775,7 +1775,7 @@ static void update_ht_cap(struct _adapter *padapter, u8 *pie, uint ie_len)
phtpriv->rx_ampdu_maxlen = max_ampdu_sz;
}
/* for A-MPDU Rx reordering buffer control for bmc_sta & sta_info
- * if A-MPDU Rx is enabled, reseting rx_ordering_ctrl
+ * if A-MPDU Rx is enabled, resetting rx_ordering_ctrl
* wstart_b(indicate_seq) to default value=0xffff
* todo: check if AP can send A-MPDU packets
*/
diff --git a/drivers/staging/rtl8712/rtl871x_mlme.h b/drivers/staging/rtl8712/rtl871x_mlme.h
index 71ca01350b5e..42bd0bf8a816 100644
--- a/drivers/staging/rtl8712/rtl871x_mlme.h
+++ b/drivers/staging/rtl8712/rtl871x_mlme.h
@@ -69,8 +69,8 @@ since mlme_priv is a shared resource between many threads,
like ISR/Call-Back functions, the OID handlers, and even timer functions.
Each _queue has its own locks, already.
Other items are protected by mlme_priv.lock.
-To avoid possible dead lock, any thread trying to modifiying mlme_priv
-SHALL not lock up more than one locks at a time!
+To avoid possible dead lock, any thread trying to modify mlme_priv
+SHALL not lock up more than one lock at a time!
*/
#define traffic_threshold 10
@@ -132,7 +132,7 @@ static inline sint get_fwstate(struct mlme_priv *pmlmepriv)
* therefore set it to be the critical section...
*
* ### NOTE:#### (!!!!)
- * TAKE CARE THAT BEFORE CALLING THIS FUNC, LOCK pmlmepriv->lock
+ * TAKE CARE BEFORE CALLING THIS FUNC, LOCK pmlmepriv->lock
*/
static inline void set_fwstate(struct mlme_priv *pmlmepriv, sint state)
{
diff --git a/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h b/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h
index 23532a793859..8e2586231ffd 100644
--- a/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h
+++ b/drivers/staging/rtl8712/rtl871x_mp_phy_regdef.h
@@ -184,7 +184,7 @@
/*RxIQ DC offset, Rx digital filter, DC notch filter */
#define rOFDM0_XARxAFE 0xc10
-#define rOFDM0_XARxIQImbalance 0xc14 /* RxIQ imblance matrix */
+#define rOFDM0_XARxIQImbalance 0xc14 /* RxIQ imbalance matrix */
#define rOFDM0_XBRxAFE 0xc18
#define rOFDM0_XBRxIQImbalance 0xc1c
#define rOFDM0_XCRxAFE 0xc20
@@ -603,7 +603,7 @@
#define bCCKRxIG 0x7f00
#define bCCKLNAPolarity 0x800000
#define bCCKRx1stGain 0x7f0000
-#define bCCKRFExtend 0x20000000 /* CCK Rx Iinital gain polarity */
+#define bCCKRFExtend 0x20000000 /* CCK Rx inital gain polarity */
#define bCCKRxAGCSatLevel 0x1f000000
#define bCCKRxAGCSatCount 0xe0
#define bCCKRxRFSettle 0x1f /* AGCsamp_dly */
diff --git a/drivers/staging/rtl8712/rtl871x_recv.c b/drivers/staging/rtl8712/rtl871x_recv.c
index 5b03b405883e..c9d1743e5c5d 100644
--- a/drivers/staging/rtl8712/rtl871x_recv.c
+++ b/drivers/staging/rtl8712/rtl871x_recv.c
@@ -28,15 +28,15 @@
#define _RTL871X_RECV_C_
+#include <linux/ip.h>
#include <linux/slab.h>
+#include <linux/if_ether.h>
#include <linux/kmemleak.h>
#include "osdep_service.h"
#include "drv_types.h"
#include "recv_osdep.h"
#include "mlme_osdep.h"
-#include "ip.h"
-#include "if_ether.h"
#include "ethernet.h"
#include "usb_ops.h"
#include "wifi.h"
diff --git a/drivers/staging/rtl8712/rtl871x_xmit.c b/drivers/staging/rtl8712/rtl871x_xmit.c
index aa57e7754f04..78f570b571a7 100644
--- a/drivers/staging/rtl8712/rtl871x_xmit.c
+++ b/drivers/staging/rtl8712/rtl871x_xmit.c
@@ -30,7 +30,6 @@
#include "osdep_service.h"
#include "drv_types.h"
-#include "rtl871x_byteorder.h"
#include "wifi.h"
#include "osdep_intf.h"
#include "usb_ops.h"
@@ -72,7 +71,7 @@ sint _r8712_init_xmit_priv(struct xmit_priv *pxmitpriv,
memset((unsigned char *)pxmitpriv, 0, sizeof(struct xmit_priv));
spin_lock_init(&pxmitpriv->lock);
/*
- Please insert all the queue initializaiton using _init_queue below
+ Please insert all the queue initialization using _init_queue below
*/
pxmitpriv->adapter = padapter;
_init_queue(&pxmitpriv->be_pending);
diff --git a/drivers/staging/rtl8712/rtl871x_xmit.h b/drivers/staging/rtl8712/rtl871x_xmit.h
index 638b79b4c5a8..ee906987735a 100644
--- a/drivers/staging/rtl8712/rtl871x_xmit.h
+++ b/drivers/staging/rtl8712/rtl871x_xmit.h
@@ -119,7 +119,7 @@ struct pkt_attrib {
u8 priority;
u8 encrypt; /* when 0 indicate no encrypt. when non-zero,
- * indicate the encrypt algorith*/
+ * indicate the encrypt algorithm*/
u8 iv_len;
u8 icv_len;
unsigned char iv[8];
diff --git a/drivers/staging/rtl8712/swab.h b/drivers/staging/rtl8712/swab.h
deleted file mode 100644
index f12781829c1b..000000000000
--- a/drivers/staging/rtl8712/swab.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
- *
- * Modifications for inclusion into the Linux staging tree are
- * Copyright(c) 2010 Larry Finger. All rights reserved.
- *
- * Contact information:
- * WLAN FAE <wlanfae@realtek.com>
- * Larry Finger <Larry.Finger@lwfinger.net>
- *
- ******************************************************************************/
-#ifndef _LINUX_BYTEORDER_SWAB_H
-#define _LINUX_BYTEORDER_SWAB_H
-
-#ifndef __u16
- #define __u16 unsigned short
-#endif
-
-#ifndef __u32
- #define __u32 unsigned int
-#endif
-
-#ifndef __u8
- #define __u8 unsigned char
-#endif
-
-#ifndef __u64
- #define __u64 unsigned long long
-#endif
-
-
-static inline __u16 ___swab16(__u16 x)
-{
- __u16 __x = x;
- return (__u16)(
- (((__u16)(__x) & (__u16)0x00ffU) << 8) |
- (((__u16)(__x) & (__u16)0xff00U) >> 8));
-
-}
-
-static inline __u32 ___swab32(__u32 x)
-{
- __u32 __x = (x);
- return (__u32)(
- (((__u32)(__x) & (__u32)0x000000ffUL) << 24) |
- (((__u32)(__x) & (__u32)0x0000ff00UL) << 8) |
- (((__u32)(__x) & (__u32)0x00ff0000UL) >> 8) |
- (((__u32)(__x) & (__u32)0xff000000UL) >> 24));
-}
-
-static inline __u64 ___swab64(__u64 x)
-{
- __u64 __x = (x);
-
- return (__u64)( \
- (__u64)(((__u64)(__x) & (__u64)0x00000000000000ffULL) << 56) | \
- (__u64)(((__u64)(__x) & (__u64)0x000000000000ff00ULL) << 40) | \
- (__u64)(((__u64)(__x) & (__u64)0x0000000000ff0000ULL) << 24) | \
- (__u64)(((__u64)(__x) & (__u64)0x00000000ff000000ULL) << 8) | \
- (__u64)(((__u64)(__x) & (__u64)0x000000ff00000000ULL) >> 8) | \
- (__u64)(((__u64)(__x) & (__u64)0x0000ff0000000000ULL) >> 24) | \
- (__u64)(((__u64)(__x) & (__u64)0x00ff000000000000ULL) >> 40) | \
- (__u64)(((__u64)(__x) & (__u64)0xff00000000000000ULL) >> 56));
-}
-
-#ifndef __arch__swab16
-static inline __u16 __arch__swab16(__u16 x)
-{
- return ___swab16(x);
-}
-
-#endif
-
-#ifndef __arch__swab32
-static inline __u32 __arch__swab32(__u32 x)
-{
- __u32 __tmp = (x) ;
- return ___swab32(__tmp);
-}
-#endif
-
-#ifndef __arch__swab64
-
-static inline __u64 __arch__swab64(__u64 x)
-{
- __u64 __tmp = (x) ;
- return ___swab64(__tmp);
-}
-
-
-#endif
-
-#define __swab16(x) __fswab16(x)
-#define __swab32(x) __fswab32(x)
-#define __swab64(x) __fswab64(x)
-
-static inline const __u16 __fswab16(__u16 x)
-{
- return __arch__swab16(x);
-}
-static inline const __u32 __fswab32(__u32 x)
-{
- return __arch__swab32(x);
-}
-
-#define swab16 __swab16
-#define swab32 __swab32
-#define swab64 __swab64
-#define swab16p __swab16p
-#define swab32p __swab32p
-#define swab64p __swab64p
-#define swab16s __swab16s
-#define swab32s __swab32s
-#define swab64s __swab64s
-
-#endif /* _LINUX_BYTEORDER_SWAB_H */
-
diff --git a/drivers/staging/rtl8712/usb_halinit.c b/drivers/staging/rtl8712/usb_halinit.c
index 46287c17a417..b4ae11a78b46 100644
--- a/drivers/staging/rtl8712/usb_halinit.c
+++ b/drivers/staging/rtl8712/usb_halinit.c
@@ -141,7 +141,7 @@ u8 r8712_usb_hal_bus_init(struct _adapter *padapter)
/* Enable AFE PLL Macro Block */
val8 = r8712_read8(padapter, AFE_PLL_CTRL);
r8712_write8(padapter, AFE_PLL_CTRL, (val8 | 0x11));
- /* Attatch AFE PLL to MACTOP/BB/PCIe Digital */
+ /* Attach AFE PLL to MACTOP/BB/PCIe Digital */
val8 = r8712_read8(padapter, SYS_ISO_CTRL);
r8712_write8(padapter, SYS_ISO_CTRL, (val8 & 0xEE));
/* Switch to 40M clock */
@@ -234,7 +234,7 @@ u8 r8712_usb_hal_bus_init(struct _adapter *padapter)
udelay(500);
r8712_write8(padapter, AFE_PLL_CTRL, (val8 | 0x11));
udelay(500);
- /* Attatch AFE PLL to MACTOP/BB/PCIe Digital */
+ /* Attach AFE PLL to MACTOP/BB/PCIe Digital */
val8 = r8712_read8(padapter, SYS_ISO_CTRL);
r8712_write8(padapter, SYS_ISO_CTRL, (val8 & 0xEE));
/* Switch to 40M clock */
diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c
index e419b4fd82b9..9bd18e2d0513 100644
--- a/drivers/staging/rtl8712/usb_intf.c
+++ b/drivers/staging/rtl8712/usb_intf.c
@@ -621,30 +621,28 @@ static void r871xu_dev_remove(struct usb_interface *pusb_intf)
struct usb_device *udev = interface_to_usbdev(pusb_intf);
usb_set_intfdata(pusb_intf, NULL);
- if (padapter) {
- if (padapter->fw_found)
- release_firmware(padapter->fw);
- /* never exit with a firmware callback pending */
- wait_for_completion(&padapter->rtl8712_fw_ready);
- if (drvpriv.drv_registered == true)
- padapter->bSurpriseRemoved = true;
- if (pnetdev != NULL) {
- /* will call netdev_close() */
- unregister_netdev(pnetdev);
- }
- flush_scheduled_work();
- udelay(1);
- /*Stop driver mlme relation timer */
- if (padapter->fw_found)
- r8712_stop_drv_timers(padapter);
- r871x_dev_unload(padapter);
- r8712_free_drv_sw(padapter);
+ if (padapter->fw_found)
+ release_firmware(padapter->fw);
+ /* never exit with a firmware callback pending */
+ wait_for_completion(&padapter->rtl8712_fw_ready);
+ if (drvpriv.drv_registered == true)
+ padapter->bSurpriseRemoved = true;
+ if (pnetdev != NULL) {
+ /* will call netdev_close() */
+ unregister_netdev(pnetdev);
}
+ flush_scheduled_work();
+ udelay(1);
+ /*Stop driver mlme relation timer */
+ if (padapter->fw_found)
+ r8712_stop_drv_timers(padapter);
+ r871x_dev_unload(padapter);
+ r8712_free_drv_sw(padapter);
usb_set_intfdata(pusb_intf, NULL);
/* decrease the reference count of the usb device structure
* when disconnect */
usb_put_dev(udev);
- /* If we didn't unplug usb dongle and remove/insert modlue, driver
+ /* If we didn't unplug usb dongle and remove/insert module, driver
* fails on sitesurvey for the first time when device is up.
* Reset usb port for sitesurvey fail issue. */
if (udev->state != USB_STATE_NOTATTACHED)
diff --git a/drivers/staging/rtl8712/usb_ops.c b/drivers/staging/rtl8712/usb_ops.c
index 5a8b0ebd0b79..c03508d935f2 100644
--- a/drivers/staging/rtl8712/usb_ops.c
+++ b/drivers/staging/rtl8712/usb_ops.c
@@ -33,7 +33,6 @@
#include "osdep_intf.h"
#include "usb_ops.h"
#include "recv_osdep.h"
-#include "rtl871x_byteorder.h"
static u8 usb_read8(struct intf_hdl *pintfhdl, u32 addr)
{
diff --git a/drivers/staging/rtl8712/wifi.h b/drivers/staging/rtl8712/wifi.h
index 277398cff0a7..793443e758ac 100644
--- a/drivers/staging/rtl8712/wifi.h
+++ b/drivers/staging/rtl8712/wifi.h
@@ -26,7 +26,6 @@
#ifndef _WIFI_H_
#define _WIFI_H_
-#include "rtl871x_byteorder.h"
#include <linux/compiler.h>
#ifdef BIT
diff --git a/drivers/staging/rtl8712/xmit_linux.c b/drivers/staging/rtl8712/xmit_linux.c
index c9703627c8f5..65542cb7168f 100644
--- a/drivers/staging/rtl8712/xmit_linux.c
+++ b/drivers/staging/rtl8712/xmit_linux.c
@@ -29,14 +29,12 @@
#define _XMIT_OSDEP_C_
#include <linux/usb.h>
+#include <linux/ip.h>
+#include <linux/if_ether.h>
#include "osdep_service.h"
#include "drv_types.h"
-
-#include "if_ether.h"
-#include "ip.h"
-#include "rtl871x_byteorder.h"
#include "wifi.h"
#include "mlme_osdep.h"
#include "xmit_osdep.h"
diff --git a/drivers/staging/rts5139/ms.c b/drivers/staging/rts5139/ms.c
index b0e9071c8e52..6eef33b03f55 100644
--- a/drivers/staging/rts5139/ms.c
+++ b/drivers/staging/rts5139/ms.c
@@ -2680,7 +2680,7 @@ static int mspro_set_rw_cmd(struct rts51x_chip *chip, u32 start_sec,
return STATUS_SUCCESS;
}
-void mspro_stop_seq_mode(struct rts51x_chip *chip)
+static void mspro_stop_seq_mode(struct rts51x_chip *chip)
{
struct ms_info *ms_card = &(chip->ms_card);
int retval;
@@ -3149,7 +3149,7 @@ Fail:
TRACE_RET(chip, STATUS_FAIL);
sec_cnt = chip->rsp_buf[0];
- RTS51X_DEBUGP("%d pages need be trasferred, %d pages remained\n",
+ RTS51X_DEBUGP("%d pages need be transferred, %d pages remained\n",
(int)page_cnt, (int)sec_cnt);
page_addr = start_page + (page_cnt - sec_cnt);
@@ -3864,7 +3864,7 @@ static int ms_rw_multi_sector(struct scsi_cmnd *srb, struct rts51x_chip *chip,
log_blk = (u16) (start_sector >> ms_card->block_shift);
start_page = (u8) (start_sector & ms_card->page_off);
- for (seg_no = 0; seg_no < sizeof(ms_start_idx) / 2; seg_no++) {
+ for (seg_no = 0; seg_no < ARRAY_SIZE(ms_start_idx) - 1; seg_no++) {
if (log_blk < ms_start_idx[seg_no + 1])
break;
}
@@ -4020,7 +4020,8 @@ static int ms_rw_multi_sector(struct scsi_cmnd *srb, struct rts51x_chip *chip,
log_blk++;
- for (seg_no = 0; seg_no < sizeof(ms_start_idx) / 2; seg_no++) {
+ for (seg_no = 0; seg_no < ARRAY_SIZE(ms_start_idx) - 1;
+ seg_no++) {
if (log_blk < ms_start_idx[seg_no + 1])
break;
}
@@ -4134,7 +4135,7 @@ void ms_cleanup_work(struct rts51x_chip *chip)
}
}
-int ms_power_off_card3v3(struct rts51x_chip *chip)
+static int ms_power_off_card3v3(struct rts51x_chip *chip)
{
int retval;
diff --git a/drivers/staging/rts5139/ms.h b/drivers/staging/rts5139/ms.h
index 3ce1dc90f19d..0321d06e776d 100644
--- a/drivers/staging/rts5139/ms.h
+++ b/drivers/staging/rts5139/ms.h
@@ -234,7 +234,6 @@
void mspro_polling_format_status(struct rts51x_chip *chip);
void mspro_format_sense(struct rts51x_chip *chip, unsigned int lun);
-void mspro_stop_seq_mode(struct rts51x_chip *chip);
int reset_ms_card(struct rts51x_chip *chip);
int ms_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 start_sector,
u16 sector_cnt);
@@ -242,7 +241,6 @@ int mspro_format(struct scsi_cmnd *srb, struct rts51x_chip *chip,
int short_data_len, int quick_format);
void ms_free_l2p_tbl(struct rts51x_chip *chip);
void ms_cleanup_work(struct rts51x_chip *chip);
-int ms_power_off_card3v3(struct rts51x_chip *chip);
int release_ms_card(struct rts51x_chip *chip);
int ms_delay_write(struct rts51x_chip *chip);
diff --git a/drivers/staging/rts5139/ms_mg.c b/drivers/staging/rts5139/ms_mg.c
index 154b5230aa5e..057d96c1a937 100644
--- a/drivers/staging/rts5139/ms_mg.c
+++ b/drivers/staging/rts5139/ms_mg.c
@@ -38,7 +38,7 @@
#ifdef SUPPORT_MAGIC_GATE
-int mg_check_int_error(struct rts51x_chip *chip)
+static int mg_check_int_error(struct rts51x_chip *chip)
{
u8 value;
@@ -444,7 +444,7 @@ int mg_rsp(struct scsi_cmnd *srb, struct rts51x_chip *chip)
*
* Since the extra 4 bytes data is just only a prefix to original data
* that read from medium, so that the 4-byte data pushed into Ring buffer
- * precedes data tramsinssion from medium to Ring buffer by DMA mechanisim
+ * precedes data transmission from medium to Ring buffer by DMA mechanism
* in order to get maximum performance and minimum code size simultaneously.
*/
int mg_get_ICV(struct scsi_cmnd *srb, struct rts51x_chip *chip)
diff --git a/drivers/staging/rts5139/rts51x.c b/drivers/staging/rts5139/rts51x.c
index 2b9f785954df..c3fe7dda1f4e 100644
--- a/drivers/staging/rts5139/rts51x.c
+++ b/drivers/staging/rts5139/rts51x.c
@@ -56,12 +56,6 @@ MODULE_DESCRIPTION(RTS51X_DESC);
MODULE_LICENSE("GPL");
MODULE_VERSION(DRIVER_VERSION);
-#ifdef SCSI_SCAN_DELAY
-static unsigned int delay_use = 5;
-module_param(delay_use, uint, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");
-#endif
-
static int auto_delink_en;
module_param(auto_delink_en, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(auto_delink_en, "enable auto delink");
@@ -114,7 +108,7 @@ static inline void usb_autopm_disable(struct usb_interface *intf)
usb_autopm_get_interface(intf);
}
-void rts51x_try_to_enter_ss(struct rts51x_chip *chip)
+static void rts51x_try_to_enter_ss(struct rts51x_chip *chip)
{
RTS51X_DEBUGP("Ready to enter SS state\n");
usb_autopm_enable(chip->usb->pusb_intf);
@@ -207,7 +201,7 @@ int rts51x_reset_resume(struct usb_interface *iface)
#else /* CONFIG_PM */
-void rts51x_try_to_enter_ss(struct rts51x_chip *chip)
+static void rts51x_try_to_enter_ss(struct rts51x_chip *chip)
{
}
@@ -364,11 +358,6 @@ static int rts51x_polling_thread(void *__chip)
{
struct rts51x_chip *chip = (struct rts51x_chip *)__chip;
-#ifdef SCSI_SCAN_DELAY
- /* Wait until SCSI scan finished */
- wait_timeout((delay_use + 5) * HZ);
-#endif
-
for (;;) {
wait_timeout(POLLING_INTERVAL);
@@ -432,38 +421,6 @@ static int rts51x_polling_thread(void *__chip)
return 0;
}
-#ifdef SCSI_SCAN_DELAY
-/* Thread to carry out delayed SCSI-device scanning */
-static int rts51x_scan_thread(void *__chip)
-{
- struct rts51x_chip *chip = (struct rts51x_chip *)__chip;
-
- printk(KERN_DEBUG
- "rts51x: device found at %d\n", chip->usb->pusb_dev->devnum);
-
- set_freezable();
- /* Wait for the timeout to expire or for a disconnect */
- if (delay_use > 0) {
- printk(KERN_DEBUG "rts51x: waiting for device "
- "to settle before scanning\n");
- wait_event_freezable_timeout(chip->usb->delay_wait,
- test_bit(FLIDX_DONT_SCAN,
- &chip->usb->dflags),
- delay_use * HZ);
- }
-
- /* If the device is still connected, perform the scanning */
- if (!test_bit(FLIDX_DONT_SCAN, &chip->usb->dflags)) {
- scsi_scan_host(rts51x_to_host(chip));
- printk(KERN_DEBUG "rts51x: device scan complete\n");
-
- /* Should we unbind if no devices were detected? */
- }
-
- complete_and_exit(&chip->usb->scanning_done, 0);
-}
-#endif
-
/* Associate our private data with the USB device */
static int associate_dev(struct rts51x_chip *chip, struct usb_interface *intf)
{
@@ -521,7 +478,6 @@ static void rts51x_init_options(struct rts51x_chip *chip)
{
struct rts51x_option *option = &(chip->option);
- option->led_blink_speed = 7;
option->mspro_formatter_enable = 1;
option->fpga_sd_sdr104_clk = CLK_100;
@@ -549,7 +505,6 @@ static void rts51x_init_options(struct rts51x_chip *chip)
option->ss_en = ss_en;
option->ss_delay = ss_delay;
- option->needs_remote_wakeup = needs_remote_wakeup;
option->auto_delink_en = auto_delink_en;
@@ -561,10 +516,7 @@ static void rts51x_init_options(struct rts51x_chip *chip)
option->rts5129_D3318_off_enable = 0;
option->sd20_pad_drive = 0;
option->reset_or_rw_fail_set_pad_drive = 1;
- option->rcc_fail_flag = 0;
- option->rcc_bug_fix_en = 1;
option->debounce_num = 2;
- option->polling_time = 100;
option->led_toggle_interval = 6;
option->xd_rwn_step = 0;
option->sd_send_status_en = 0;
@@ -737,15 +689,6 @@ static void quiesce_and_remove_host(struct rts51x_chip *chip)
if (rts51x->pusb_dev->state == USB_STATE_NOTATTACHED)
set_bit(FLIDX_DISCONNECTING, &rts51x->dflags);
-#ifdef SCSI_SCAN_DELAY
- /* Prevent SCSI-scanning (if it hasn't started yet)
- * and wait for the SCSI-scanning thread to stop.
- */
- set_bit(FLIDX_DONT_SCAN, &rts51x->dflags);
- wake_up(&rts51x->delay_wait);
- wait_for_completion(&rts51x->scanning_done);
-#endif
-
/* Removing the host will perform an orderly shutdown: caches
* synchronized, disks spun down, etc.
*/
@@ -757,9 +700,6 @@ static void quiesce_and_remove_host(struct rts51x_chip *chip)
scsi_lock(host);
set_bit(FLIDX_DISCONNECTING, &rts51x->dflags);
scsi_unlock(host);
-#ifdef SCSI_SCAN_DELAY
- wake_up(&rts51x->delay_wait);
-#endif
}
/* Second stage of disconnect processing: deallocate all resources */
@@ -818,10 +758,6 @@ static int rts51x_probe(struct usb_interface *intf,
init_completion(&rts51x->control_exit);
init_completion(&rts51x->polling_exit);
init_completion(&(rts51x->notify));
-#ifdef SCSI_SCAN_DELAY
- init_waitqueue_head(&rts51x->delay_wait);
- init_completion(&rts51x->scanning_done);
-#endif
chip->usb = rts51x;
@@ -855,22 +791,7 @@ static int rts51x_probe(struct usb_interface *intf,
printk(KERN_WARNING RTS51X_TIP "Unable to add the scsi host\n");
goto BadDevice;
}
-#ifdef SCSI_SCAN_DELAY
- /* Start up the thread for delayed SCSI-device scanning */
- th = kthread_create(rts51x_scan_thread, chip, RTS51X_SCAN_THREAD);
- if (IS_ERR(th)) {
- printk(KERN_WARNING RTS51X_TIP
- "Unable to start the device-scanning thread\n");
- complete(&rts51x->scanning_done);
- quiesce_and_remove_host(chip);
- result = PTR_ERR(th);
- goto BadDevice;
- }
-
- wake_up_process(th);
-#else
scsi_scan_host(rts51x_to_host(chip));
-#endif
/* Start up our polling thread */
th = kthread_run(rts51x_polling_thread, chip, RTS51X_POLLING_THREAD);
diff --git a/drivers/staging/rts5139/rts51x.h b/drivers/staging/rts5139/rts51x.h
index b2c58390bfc5..ecc0109a5b1a 100644
--- a/drivers/staging/rts5139/rts51x.h
+++ b/drivers/staging/rts5139/rts51x.h
@@ -47,11 +47,9 @@
#define RTS51X_DESC "Realtek RTS5139/29 USB card reader driver"
#define RTS51X_NAME "rts5139"
#define RTS51X_CTL_THREAD "rts5139-control"
-#define RTS51X_SCAN_THREAD "rts5139-scan"
#define RTS51X_POLLING_THREAD "rts5139-polling"
#define POLLING_IN_THREAD
-/* #define SCSI_SCAN_DELAY */
#define SUPPORT_FILE_OP
#define wait_timeout_x(task_state, msecs) \
@@ -66,8 +64,6 @@ do { \
/* Size of the DMA-mapped I/O buffer */
#define RTS51X_IOBUF_SIZE 1024
-/* Size of the autosense data buffer */
-#define RTS51X_SENSE_SIZE 18
/* Dynamic bitflag definitions (dflags): used in set_bit() etc. */
#define FLIDX_URB_ACTIVE 0 /* current_urb is in use */
@@ -76,7 +72,6 @@ do { \
#define FLIDX_DISCONNECTING 3 /* disconnect in progress */
#define FLIDX_RESETTING 4 /* device reset in progress */
#define FLIDX_TIMED_OUT 5 /* SCSI midlayer timed out */
-#define FLIDX_DONT_SCAN 6 /* don't scan (disconnect) */
struct rts51x_chip;
@@ -116,10 +111,6 @@ struct rts51x_usb {
struct completion control_exit; /* control thread exit */
struct completion polling_exit; /* polling thread exit */
struct completion notify; /* thread begin/end */
-#ifdef SCSI_SCAN_DELAY
- wait_queue_head_t delay_wait; /* wait during scan, reset */
- struct completion scanning_done; /* wait for scan thread */
-#endif
};
extern struct usb_driver rts51x_driver;
@@ -188,7 +179,6 @@ enum xfer_buf_dir { TO_XFER_BUF, FROM_XFER_BUF };
/* General routines provided by the usb-storage standard core */
#ifdef CONFIG_PM
-void rts51x_try_to_enter_ss(struct rts51x_chip *chip);
void rts51x_try_to_exit_ss(struct rts51x_chip *chip);
int rts51x_suspend(struct usb_interface *iface, pm_message_t message);
int rts51x_resume(struct usb_interface *iface);
diff --git a/drivers/staging/rts5139/rts51x_card.c b/drivers/staging/rts5139/rts51x_card.c
index 424a84581b86..4192c3bac12f 100644
--- a/drivers/staging/rts5139/rts51x_card.c
+++ b/drivers/staging/rts5139/rts51x_card.c
@@ -37,7 +37,6 @@
#include "rts51x_chip.h"
#include "rts51x_card.h"
#include "rts51x_transport.h"
-#include "rts51x_sys.h"
#include "xd.h"
#include "sd.h"
#include "ms.h"
@@ -94,7 +93,7 @@ void do_remaining_work(struct rts51x_chip *chip)
ms_cleanup_work(chip);
}
-void do_reset_xd_card(struct rts51x_chip *chip)
+static void do_reset_xd_card(struct rts51x_chip *chip)
{
int retval;
@@ -148,7 +147,7 @@ void do_reset_sd_card(struct rts51x_chip *chip)
}
}
-void do_reset_ms_card(struct rts51x_chip *chip)
+static void do_reset_ms_card(struct rts51x_chip *chip)
{
int retval;
@@ -175,7 +174,7 @@ void do_reset_ms_card(struct rts51x_chip *chip)
}
}
-void card_cd_debounce(struct rts51x_chip *chip, u8 *need_reset,
+static void card_cd_debounce(struct rts51x_chip *chip, u8 *need_reset,
u8 *need_release)
{
int retval;
@@ -191,7 +190,6 @@ void card_cd_debounce(struct rts51x_chip *chip, u8 *need_reset,
goto Exit_Debounce;
if (chip->card_exist) {
- rts51x_clear_start_time(chip);
retval = rts51x_read_register(chip, CARD_INT_PEND, &value);
if (retval != STATUS_SUCCESS) {
rts51x_ep0_write_register(chip, MC_FIFO_CTL, FIFO_FLUSH,
@@ -214,17 +212,11 @@ void card_cd_debounce(struct rts51x_chip *chip, u8 *need_reset,
}
} else {
if (chip->card_status & XD_CD) {
- rts51x_clear_start_time(chip);
reset_map |= XD_CARD;
} else if (chip->card_status & SD_CD) {
- rts51x_clear_start_time(chip);
reset_map |= SD_CARD;
} else if (chip->card_status & MS_CD) {
- rts51x_clear_start_time(chip);
reset_map |= MS_CARD;
- } else {
- if (rts51x_check_start_time(chip))
- rts51x_set_start_time(chip);
}
}
@@ -709,7 +701,7 @@ u8 get_lun_card(struct rts51x_chip *chip, unsigned int lun)
return 0;
}
-int card_share_mode(struct rts51x_chip *chip, int card)
+static int card_share_mode(struct rts51x_chip *chip, int card)
{
u8 value;
@@ -823,22 +815,6 @@ int enable_card_clock(struct rts51x_chip *chip, u8 card)
return STATUS_SUCCESS;
}
-int disable_card_clock(struct rts51x_chip *chip, u8 card)
-{
- u8 clk_en = 0;
-
- if (card & XD_CARD)
- clk_en |= XD_CLK_EN;
- if (card & SD_CARD)
- clk_en |= SD_CLK_EN;
- if (card & MS_CARD)
- clk_en |= MS_CLK_EN;
-
- RTS51X_WRITE_REG(chip, CARD_CLK_EN, clk_en, 0);
-
- return STATUS_SUCCESS;
-}
-
int card_power_on(struct rts51x_chip *chip, u8 card)
{
u8 mask, val1, val2;
@@ -851,16 +827,7 @@ int card_power_on(struct rts51x_chip *chip, u8 card)
if ((card == SD_CARD) || (card == XD_CARD)) {
RTS51X_WRITE_REG(chip, CARD_PWR_CTL, mask | LDO3318_PWR_MASK,
val1 | LDO_SUSPEND);
- /* RTS51X_WRITE_REG(chip, CARD_PWR_CTL,
- LDO3318_PWR_MASK, LDO_SUSPEND); */
}
- /* else if(card==XD_CARD)
- {
- RTS51X_WRITE_REG(chip, CARD_PWR_CTL,
- mask|LDO3318_PWR_MASK, val1|LDO_SUSPEND);
- //RTS51X_WRITE_REG(chip, CARD_PWR_CTL,
- // LDO3318_PWR_MASK, LDO_SUSPEND);
- } */
else {
#endif
RTS51X_WRITE_REG(chip, CARD_PWR_CTL, mask, val1);
@@ -879,17 +846,6 @@ int card_power_on(struct rts51x_chip *chip, u8 card)
return STATUS_SUCCESS;
}
-int card_power_off(struct rts51x_chip *chip, u8 card)
-{
- u8 mask, val;
-
- mask = POWER_MASK;
- val = POWER_OFF;
- RTS51X_WRITE_REG(chip, CARD_PWR_CTL, mask, val);
-
- return STATUS_SUCCESS;
-}
-
int monitor_card_cd(struct rts51x_chip *chip, u8 card)
{
int retval;
diff --git a/drivers/staging/rts5139/rts51x_card.h b/drivers/staging/rts5139/rts51x_card.h
index ac3c1e741ab9..c5c03cce98bd 100644
--- a/drivers/staging/rts5139/rts51x_card.h
+++ b/drivers/staging/rts5139/rts51x_card.h
@@ -204,13 +204,7 @@
/* LDO_POWER_CFG */
#define TUNE_SD18_MASK 0x1C
-#define TUNE_SD18_1V7 0x00
#define TUNE_SD18_1V8 (0x01 << 2)
-#define TUNE_SD18_1V9 (0x02 << 2)
-#define TUNE_SD18_2V0 (0x03 << 2)
-#define TUNE_SD18_2V7 (0x04 << 2)
-#define TUNE_SD18_2V8 (0x05 << 2)
-#define TUNE_SD18_2V9 (0x06 << 2)
#define TUNE_SD18_3V3 (0x07 << 2)
/* XD_CP_WAITTIME */
@@ -744,9 +738,7 @@
int monitor_card_cd(struct rts51x_chip *chip, u8 card);
void do_remaining_work(struct rts51x_chip *chip);
-void do_reset_xd_card(struct rts51x_chip *chip);
void do_reset_sd_card(struct rts51x_chip *chip);
-void do_reset_ms_card(struct rts51x_chip *chip);
void rts51x_init_cards(struct rts51x_chip *chip);
void rts51x_release_cards(struct rts51x_chip *chip);
int switch_ssc_clock(struct rts51x_chip *chip, int clk);
@@ -754,15 +746,12 @@ int switch_normal_clock(struct rts51x_chip *chip, int clk);
int card_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 sec_addr,
u16 sec_cnt);
u8 get_lun_card(struct rts51x_chip *chip, unsigned int lun);
-int card_share_mode(struct rts51x_chip *chip, int card);
int rts51x_select_card(struct rts51x_chip *chip, int card);
void eject_card(struct rts51x_chip *chip, unsigned int lun);
void trans_dma_enable(enum dma_data_direction dir, struct rts51x_chip *chip,
u32 byte_cnt, u8 pack_size);
int enable_card_clock(struct rts51x_chip *chip, u8 card);
-int disable_card_clock(struct rts51x_chip *chip, u8 card);
int card_power_on(struct rts51x_chip *chip, u8 card);
-int card_power_off(struct rts51x_chip *chip, u8 card);
int toggle_gpio(struct rts51x_chip *chip, u8 gpio);
int turn_on_led(struct rts51x_chip *chip, u8 gpio);
int turn_off_led(struct rts51x_chip *chip, u8 gpio);
diff --git a/drivers/staging/rts5139/rts51x_chip.c b/drivers/staging/rts5139/rts51x_chip.c
index b3e0bb22b0ff..db88d7a194b8 100644
--- a/drivers/staging/rts5139/rts51x_chip.c
+++ b/drivers/staging/rts5139/rts51x_chip.c
@@ -34,7 +34,6 @@
#include "rts51x_chip.h"
#include "rts51x_card.h"
#include "rts51x_transport.h"
-#include "rts51x_sys.h"
#include "xd.h"
#include "ms.h"
#include "sd.h"
@@ -79,20 +78,18 @@ int rts51x_reset_chip(struct rts51x_chip *chip)
chip->option.sd20_pad_drive);
if (chip->rts5179)
rts51x_write_register(chip, CARD_PULL_CTL5, 0x03, 0x01);
- if (!chip->option.ww_enable) {
- if (CHECK_PKG(chip, LQFP48)) {
- rts51x_write_register(chip, CARD_PULL_CTL3,
- 0x80, 0x80);
- rts51x_write_register(chip, CARD_PULL_CTL6,
- 0xf0, 0xA0);
- } else {
- rts51x_write_register(chip, CARD_PULL_CTL1,
- 0x30, 0x20);
- rts51x_write_register(chip, CARD_PULL_CTL3,
- 0x80, 0x80);
- rts51x_write_register(chip, CARD_PULL_CTL6,
- 0x0c, 0x08);
- }
+ if (CHECK_PKG(chip, LQFP48)) {
+ rts51x_write_register(chip, CARD_PULL_CTL3,
+ 0x80, 0x80);
+ rts51x_write_register(chip, CARD_PULL_CTL6,
+ 0xf0, 0xA0);
+ } else {
+ rts51x_write_register(chip, CARD_PULL_CTL1,
+ 0x30, 0x20);
+ rts51x_write_register(chip, CARD_PULL_CTL3,
+ 0x80, 0x80);
+ rts51x_write_register(chip, CARD_PULL_CTL6,
+ 0x0c, 0x08);
}
}
if (chip->option.sd_ctl & SUPPORT_UHS50_MMC44) {
@@ -121,12 +118,6 @@ int rts51x_reset_chip(struct rts51x_chip *chip)
/* GPIO OE */
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_GPIO, GPIO_OE, GPIO_OE);
-#ifdef LED_AUTO_BLINK
- /* LED autoblink */
- rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_AUTO_BLINK,
- BLINK_ENABLE | BLINK_SPEED_MASK,
- BLINK_ENABLE | chip->option.led_blink_speed);
-#endif
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DMA1_CTL,
EXTEND_DMA1_ASYNC_SIGNAL, EXTEND_DMA1_ASYNC_SIGNAL);
@@ -144,7 +135,6 @@ int rts51x_reset_chip(struct rts51x_chip *chip)
card_power_on(chip, SD_CARD | MS_CARD | XD_CARD);
wait_timeout(10);
}
- rts51x_clear_start_time(chip);
return STATUS_SUCCESS;
}
@@ -164,12 +154,6 @@ int rts51x_init_chip(struct rts51x_chip *chip)
chip->card_ejected = 0;
chip->lun2card[0] = XD_CARD | SD_CARD | MS_CARD;
-#if 0
- chip->option.sdr50_tx_phase = 0x01;
- chip->option.sdr50_rx_phase = 0x05;
- chip->option.ddr50_tx_phase = 0x09;
- chip->option.ddr50_rx_phase = 0x06; /* add for debug */
-#endif
#ifdef CLOSE_SSC_POWER
rts51x_write_register(chip, FPDCTL, SSC_POWER_MASK, SSC_POWER_ON);
udelay(100);
@@ -178,9 +162,6 @@ int rts51x_init_chip(struct rts51x_chip *chip)
RTS51X_SET_STAT(chip, STAT_RUN);
RTS51X_READ_REG(chip, HW_VERSION, &val);
- if ((val & 0x0f) >= 2)
- chip->option.rcc_bug_fix_en = 0;
- RTS51X_DEBUGP("rcc bug fix enable:%d\n", chip->option.rcc_bug_fix_en);
RTS51X_DEBUGP("HW_VERSION: 0x%x\n", val);
if (val & FPGA_VER) {
chip->asic_code = 0;
@@ -237,7 +218,6 @@ int rts51x_release_chip(struct rts51x_chip *chip)
return STATUS_SUCCESS;
}
-#ifndef LED_AUTO_BLINK
static inline void rts51x_blink_led(struct rts51x_chip *chip)
{
/* Read/Write */
@@ -251,20 +231,6 @@ static inline void rts51x_blink_led(struct rts51x_chip *chip)
}
}
}
-#endif
-
-int rts51x_check_start_time(struct rts51x_chip *chip)
-{
- return 0;
-}
-
-void rts51x_set_start_time(struct rts51x_chip *chip)
-{
-}
-
-void rts51x_clear_start_time(struct rts51x_chip *chip)
-{
-}
static void rts51x_auto_delink_cmd(struct rts51x_chip *chip)
{
@@ -287,7 +253,6 @@ static void rts51x_auto_delink_polling_cycle(struct rts51x_chip *chip)
chip->option.delink_delay * 2) {
if (chip->auto_delink_counter ==
chip->option.delink_delay) {
- clear_first_install_mark(chip);
if (chip->card_exist) {
/* False card */
if (!chip->card_ejected) {
@@ -321,91 +286,13 @@ static void rts51x_auto_delink(struct rts51x_chip *chip)
}
#else
/* some of called funcs are not implemented, so comment it out */
-#if 0
-/* using precise time as delink time */
-static void rts51x_auto_delink_precise_time(struct rts51x_chip *chip)
-{
- int retvalue = 0;
-
- retvalue = rts51x_get_card_status(chip, &chip->card_status);
- /* get card CD status success and card CD not exist,
- * then check whether delink */
- if ((retvalue == STATUS_SUCCESS)
- && (!(chip->card_status & (SD_CD | MS_CD | XD_CD)))) {
- if (rts51x_count_delink_time(chip) >=
- chip->option.delink_delay) {
- clear_first_install_mark(chip);
- RTS51X_DEBUGP("No card inserted, do delink\n");
- /* sangdy2010-05-17:disable because there is error
- * after SSC clock closed and card power
- * has been closed before */
- /* rts51x_write_register(chip, CARD_PWR_CTL,
- DV3318_AUTO_PWR_OFF, 0); */
- rts51x_auto_delink_cmd(chip);
- }
- /* card CD exist and not ready, then do force delink */
- if ((retvalue == STATUS_SUCCESS)
- && (chip->card_status & (SD_CD | MS_CD | XD_CD))) {
- /* if card is not ejected or safely remove,
- * then do force delink */
- if (!chip->card_ejected) {
- /* sangdy2010-11-16:polling at least 2 cycles
- * then do force delink for card may force delink
- * if card is extracted and insert quickly
- * after ready. */
- if (chip->auto_delink_counter > 1) {
- if (rts51x_count_delink_time(chip) >
- chip->option.delink_delay * 2) {
- RTS51X_DEBUGP("Try to do force"
- "delink\n");
- rts51x_auto_delink_force_cmd(chip);
- }
- }
- }
- }
- chip->auto_delink_counter++;
-}
-#else
-static void rts51x_auto_delink_precise_time(struct rts51x_chip *chip)
-{
-}
-#endif
-
static void rts51x_auto_delink(struct rts51x_chip *chip)
{
- rts51x_auto_delink_precise_time(chip);
}
#endif
void rts51x_polling_func(struct rts51x_chip *chip)
{
-#ifdef SUPPORT_SD_LOCK
- struct sd_info *sd_card = &(chip->sd_card);
-
- if (sd_card->sd_erase_status) {
- if (chip->card_exist & SD_CARD) {
- u8 val;
- rts51x_read_register(chip, SD_BUS_STAT, &val);
- if (val & SD_DAT0_STATUS) {
- /* Erase completed */
- sd_card->sd_erase_status = SD_NOT_ERASE;
- sd_card->sd_lock_notify = 1;
-
- /* SD card should be reinited,
- * so we release it here. */
- sd_cleanup_work(chip);
- release_sd_card(chip);
- chip->card_ready &= ~SD_CARD;
- chip->card_exist &= ~SD_CARD;
- chip->rw_card[chip->card2lun[SD_CARD]] = NULL;
- clear_bit(chip->card2lun[SD_CARD],
- &(chip->lun_mc));
- }
- } else {
- sd_card->sd_erase_status = SD_NOT_ERASE;
- }
- }
-#endif
rts51x_init_cards(chip);
@@ -431,9 +318,7 @@ void rts51x_polling_func(struct rts51x_chip *chip)
if (!RTS51X_CHK_STAT(chip, STAT_IDLE)) {
RTS51X_DEBUGP("Idle state!\n");
RTS51X_SET_STAT(chip, STAT_IDLE);
-#ifndef LED_AUTO_BLINK
chip->led_toggle_counter = 0;
-#endif
/* Idle state, turn off LED
* to reduce power consumption */
if (chip->option.led_always_on
@@ -467,9 +352,7 @@ void rts51x_polling_func(struct rts51x_chip *chip)
switch (RTS51X_GET_STAT(chip)) {
case STAT_RUN:
-#ifndef LED_AUTO_BLINK
rts51x_blink_led(chip);
-#endif
do_remaining_work(chip);
break;
@@ -484,7 +367,6 @@ void rts51x_polling_func(struct rts51x_chip *chip)
rts51x_auto_delink(chip);
} else {
chip->auto_delink_counter = 0;
- rts51x_clear_start_time(chip);
}
}
@@ -831,7 +713,7 @@ void rts51x_do_before_power_down(struct rts51x_chip *chip)
chip->cur_clk = 0;
chip->card_exist = 0;
chip->cur_card = 0;
- if (chip->asic_code && !chip->option.ww_enable) {
+ if (chip->asic_code) {
if (CHECK_PKG(chip, LQFP48)) {
rts51x_write_register(chip, CARD_PULL_CTL3, 0x80, 0x00);
rts51x_write_register(chip, CARD_PULL_CTL6, 0xf0, 0x50);
@@ -863,16 +745,6 @@ void rts51x_prepare_run(struct rts51x_chip *chip)
rts51x_write_register(chip, CLK_DIV, CLK_CHANGE, 0x00);
}
#endif
-#if 0
- if (chip->option.ss_en && RTS51X_CHK_STAT(chip, STAT_SS)) {
- rts51x_try_to_exit_ss(chip);
- wait_timeout(100);
- rts51x_init_chip(chip);
- rts51x_init_cards(chip);
- }
-
- RTS51X_SET_STAT(chip, STAT_RUN);
-#endif
}
#ifdef _MSG_TRACE
@@ -1017,24 +889,6 @@ void rts51x_pp_status(struct rts51x_chip *chip, unsigned int lun, u8 *status,
status[0x0F] = 0x00;
}
}
-#ifdef SUPPORT_SD_LOCK
- /* SD Lock/Unlock */
- if (card == SD_CARD) {
- status[0x17] = 0x80;
- if (sd_card->sd_erase_status)
- status[0x17] |= 0x01; /* Under erasing */
- if (sd_card->sd_lock_status & SD_LOCKED) {
- status[0x17] |= 0x02; /* Locked */
- status[0x07] |= 0x40; /* Read protected */
- }
- if (sd_card->sd_lock_status & SD_PWD_EXIST)
- status[0x17] |= 0x04; /* Contain PWD */
- } else {
- status[0x17] = 0x00;
- }
-
- RTS51X_DEBUGP("status[0x17] = 0x%x\n", status[0x17]);
-#endif
/* Function 0
* Support Magic Gate, CPRM and PhyRegister R/W */
@@ -1044,12 +898,6 @@ void rts51x_pp_status(struct rts51x_chip *chip, unsigned int lun, u8 *status,
* Support OC LUN status & WP LUN status */
status[0x1A] = 0x28;
- /* Function 7 */
-#ifdef SUPPORT_SD_LOCK
- /* Support SD Lock/Unlock */
- status[0x1F] = 0x01;
-#endif
-
/* Function 2
* Support OC LUN status & WP LUN status */
status[0x1A] = 0x28;
diff --git a/drivers/staging/rts5139/rts51x_chip.h b/drivers/staging/rts5139/rts51x_chip.h
index 13fc2a410d90..6d395b6533a8 100644
--- a/drivers/staging/rts5139/rts51x_chip.h
+++ b/drivers/staging/rts5139/rts51x_chip.h
@@ -39,12 +39,7 @@
#define SUPPORT_CPRM
#define SUPPORT_MAGIC_GATE
#define SUPPORT_MSXC
-/* #define LED_AUTO_BLINK */
-
-/* { wwang, 2010-07-26
- * Add support for SD lock/unlock */
-/* #define SUPPORT_SD_LOCK */
-/* } wwang, 2010-07-26 */
+#define USING_POLLING_CYCLE_DELINK
#ifdef SUPPORT_MAGIC_GA
/* Using NORMAL_WRITE instead of AUTO_WRITE to set ICVTE */
@@ -63,7 +58,6 @@
#define SUPPORT_OCP
#define MS_SPEEDUP
-/* #define XD_SPEEDUP */
#define SD_XD_IO_FOLLOW_PWR
@@ -81,7 +75,6 @@
#define MAX_ALLOWED_LUN_CNT 8
#define CMD_BUF_LEN 1024
-#define RSP_BUF_LEN 1024
#define POLLING_INTERVAL 50 /* 50ms */
#define XD_FREE_TABLE_CNT 1200
@@ -128,8 +121,6 @@
#endif
#define STATUS_FAIL 1
-#define STATUS_READ_FAIL 2
-#define STATUS_WRITE_FAIL 3
#define STATUS_TIMEDOUT 4
#define STATUS_NOMEM 5
#define STATUS_TRANS_SHORT 6
@@ -139,8 +130,6 @@
#define IDLE_MAX_COUNT 10
#define POLLING_WAIT_CNT 1
-#define DELINK_DELAY 100
-#define LED_TOGGLE_INTERVAL 6
#define LED_GPIO 0
/* package */
@@ -157,8 +146,6 @@
#define TRANSPORT_GOOD 0
/* Transport good, command failed */
#define TRANSPORT_FAILED 1
-/* Command failed, no auto-sense */
-#define TRANSPORT_NO_SENSE 2
/* Transport bad (i.e. device dead) */
#define TRANSPORT_ERROR 3
@@ -195,7 +182,6 @@ struct trace_msg_t {
#define SENSE_TYPE_MEDIA_INVALID_CMD_FIELD 6
#define SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR 7
#define SENSE_TYPE_MEDIA_WRITE_ERR 8
-#define SENSE_TYPE_FORMAT_IN_PROGRESS 9
#define SENSE_TYPE_FORMAT_CMD_FAILED 10
#ifdef SUPPORT_MAGIC_GATE
/* COPY PROTECTION KEY EXCHANGE FAILURE - KEY NOT ESTABLISHED */
@@ -207,83 +193,27 @@ struct trace_msg_t {
/* WRITE ERROR */
#define SENSE_TYPE_MG_WRITE_ERR 0x0e
#endif
-#ifdef SUPPORT_SD_LOCK
-/* FOR Locked SD card */
-#define SENSE_TYPE_MEDIA_READ_FORBIDDEN 0x10
-#endif
/*---- sense key ----*/
-#define ILI 0x20 /* ILI bit is on */
-
-#define NO_SENSE 0x00 /* not exist sense key */
-#define RECOVER_ERR 0x01 /* Target/Logical unit is recoverd */
-#define NOT_READY 0x02 /* Logical unit is not ready */
-#define MEDIA_ERR 0x03 /* medium/data error */
-#define HARDWARE_ERR 0x04 /* hardware error */
#define ILGAL_REQ 0x05 /* CDB/parameter/identify msg error */
-#define UNIT_ATTENTION 0x06 /* unit attention condition occur */
-#define DAT_PRTCT 0x07 /* read/write is desable */
-#define BLNC_CHK 0x08 /* find blank/DOF in read */
- /* write to unblank area */
-#define CPY_ABRT 0x0a /* Copy/Compare/Copy&Verify illgal */
-#define ABRT_CMD 0x0b /* Target make the command in error */
-#define EQUAL 0x0c /* Search Data end with Equal */
-#define VLM_OVRFLW 0x0d /* Some data are left in buffer */
-#define MISCMP 0x0e /* find inequality */
/*-----------------------------------
SENSE_DATA
-----------------------------------*/
-/*---- valid ----*/
-#define SENSE_VALID 0x80 /* Sense data is valid as SCSI2 */
-#define SENSE_INVALID 0x00 /* Sense data is invalid as SCSI2 */
/*---- error code ----*/
#define CUR_ERR 0x70 /* current error */
-#define DEF_ERR 0x71 /* specific command error */
/*---- sense key Infomation ----*/
-#define SNSKEYINFO_LEN 3 /* length of sense key infomation */
#define SKSV 0x80
#define CDB_ILLEGAL 0x40
-#define DAT_ILLEGAL 0x00
-#define BPV 0x08
-#define BIT_ILLEGAL0 0 /* bit0 is illegal */
-#define BIT_ILLEGAL1 1 /* bit1 is illegal */
-#define BIT_ILLEGAL2 2 /* bit2 is illegal */
-#define BIT_ILLEGAL3 3 /* bit3 is illegal */
-#define BIT_ILLEGAL4 4 /* bit4 is illegal */
-#define BIT_ILLEGAL5 5 /* bit5 is illegal */
-#define BIT_ILLEGAL6 6 /* bit6 is illegal */
-#define BIT_ILLEGAL7 7 /* bit7 is illegal */
/*---- ASC ----*/
-#define ASC_NO_INFO 0x00
-#define ASC_MISCMP 0x1d
#define ASC_INVLD_CDB 0x24
-#define ASC_INVLD_PARA 0x26
-#define ASC_LU_NOT_READY 0x04
-#define ASC_WRITE_ERR 0x0c
-#define ASC_READ_ERR 0x11
-#define ASC_LOAD_EJCT_ERR 0x53
-#define ASC_MEDIA_NOT_PRESENT 0x3A
-#define ASC_MEDIA_CHANGED 0x28
-#define ASC_MEDIA_IN_PROCESS 0x04
-#define ASC_WRITE_PROTECT 0x27
-#define ASC_LUN_NOT_SUPPORTED 0x25
/*---- ASQC ----*/
-#define ASCQ_NO_INFO 0x00
-#define ASCQ_MEDIA_IN_PROCESS 0x01
-#define ASCQ_MISCMP 0x00
#define ASCQ_INVLD_CDB 0x00
-#define ASCQ_INVLD_PARA 0x02
-#define ASCQ_LU_NOT_READY 0x02
-#define ASCQ_WRITE_ERR 0x02
-#define ASCQ_READ_ERR 0x00
-#define ASCQ_LOAD_EJCT_ERR 0x00
-#define ASCQ_WRITE_PROTECT 0x00
struct sense_data_t {
unsigned char err_code; /* error code */
@@ -296,13 +226,13 @@ struct sense_data_t {
unsigned char seg_no; /* segment No. */
unsigned char sense_key; /* byte5 : ILI */
/* bit3-0 : sense key */
- unsigned char info[4]; /* infomation */
+ unsigned char info[4]; /* information */
unsigned char ad_sense_len; /* additional sense data length */
- unsigned char cmd_info[4]; /* command specific infomation */
+ unsigned char cmd_info[4]; /* command specific information */
unsigned char asc; /* ASC */
unsigned char ascq; /* ASCQ */
unsigned char rfu; /* FRU */
- unsigned char sns_key_info[3]; /* sense key specific infomation */
+ unsigned char sns_key_info[3]; /* sense key specific information */
};
/* sd_ctl bit map */
@@ -323,8 +253,6 @@ struct sense_data_t {
#define SUPPORT_UHS50_MMC44 0x40
struct rts51x_option {
- u8 led_blink_speed;
-
int mspro_formatter_enable;
/* card clock expected by user for fpga platform */
@@ -368,8 +296,6 @@ struct rts51x_option {
int ss_en;
/* Interval to enter SS from IDLE state (second) */
int ss_delay;
- int needs_remote_wakeup;
- u8 ww_enable; /* sangdy2010-08-03:add for remote wakeup */
/* Enable SSC clock */
int ssc_en;
@@ -392,10 +318,7 @@ struct rts51x_option {
/*if reset or rw fail,then set SD20 pad drive again */
u8 reset_or_rw_fail_set_pad_drive;
- u8 rcc_fail_flag; /* add to indicate whether rcc bug happen */
- u8 rcc_bug_fix_en; /* if set,then support fixing rcc bug */
u8 debounce_num; /* debounce number */
- int polling_time; /* polling delay time */
u8 led_toggle_interval; /* used to control led toggle speed */
int xd_rwn_step;
u8 sd_send_status_en;
@@ -405,7 +328,7 @@ struct rts51x_option {
u8 ddr50_rx_phase;
u8 sdr50_tx_phase;
u8 sdr50_rx_phase;
- /* used to enable select sdr50 tx phase according to proportion. */
+ /* used to enable select sdr50 tx phase according to proportion. */
u8 sdr50_phase_sel;
u8 ms_errreg_fix;
u8 reset_mmc_first;
@@ -614,11 +537,6 @@ struct sd_info {
u8 sd_reset_fail; /* sangdy2010-07-01 */
u8 sd_send_status_en;
-#ifdef SUPPORT_SD_LOCK
- u8 sd_lock_status;
- u8 sd_erase_status;
- u8 sd_lock_notify;
-#endif
};
#define MODE_512_SEQ 0x01
@@ -720,9 +638,8 @@ struct rts51x_chip {
struct scsi_cmnd *srb;
struct sense_data_t sense_buffer[MAX_ALLOWED_LUN_CNT];
-#ifndef LED_AUTO_BLINK
int led_toggle_counter;
-#endif
+
int ss_counter;
int idle_counter;
int auto_delink_counter;
diff --git a/drivers/staging/rts5139/rts51x_fop.c b/drivers/staging/rts5139/rts51x_fop.c
index 6eaebb6223c9..ef893c8cdec6 100644
--- a/drivers/staging/rts5139/rts51x_fop.c
+++ b/drivers/staging/rts5139/rts51x_fop.c
@@ -234,12 +234,7 @@ ssize_t rts51x_write(struct file *filp, const char __user *buf, size_t count,
return 0;
}
-#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) */
-int rts51x_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
-#else
long rts51x_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-#endif
{
struct rts51x_chip *chip;
struct sd_direct_cmnd cmnd;
diff --git a/drivers/staging/rts5139/rts51x_fop.h b/drivers/staging/rts5139/rts51x_fop.h
index 94d75f08d255..eb45acf50d1a 100644
--- a/drivers/staging/rts5139/rts51x_fop.h
+++ b/drivers/staging/rts5139/rts51x_fop.h
@@ -50,12 +50,7 @@ ssize_t rts51x_read(struct file *filp, char __user *buf, size_t count,
loff_t *f_pos);
ssize_t rts51x_write(struct file *filp, const char __user *buf, size_t count,
loff_t *f_pos);
-#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) */
-int rts51x_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg);
-#else
long rts51x_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
-#endif
#endif
diff --git a/drivers/staging/rts5139/rts51x_scsi.c b/drivers/staging/rts5139/rts51x_scsi.c
index 87c9cdc8bd29..e07a1f4f58cf 100644
--- a/drivers/staging/rts5139/rts51x_scsi.c
+++ b/drivers/staging/rts5139/rts51x_scsi.c
@@ -40,7 +40,6 @@
#include "rts51x_scsi.h"
#include "rts51x_card.h"
#include "rts51x_transport.h"
-#include "rts51x_sys.h"
#include "sd_cprm.h"
#include "ms_mg.h"
#include "trace.h"
@@ -370,10 +369,6 @@ void set_sense_type(struct rts51x_chip *chip, unsigned int lun, int sense_type)
ASC_INVLD_CDB, ASCQ_INVLD_CDB, CDB_ILLEGAL, 1);
break;
- case SENSE_TYPE_FORMAT_IN_PROGRESS:
- set_sense_data(chip, lun, CUR_ERR, 0x02, 0, 0x04, 0x04, 0, 0);
- break;
-
case SENSE_TYPE_FORMAT_CMD_FAILED:
set_sense_data(chip, lun, CUR_ERR, 0x03, 0, 0x31, 0x01, 0, 0);
break;
@@ -396,12 +391,6 @@ void set_sense_type(struct rts51x_chip *chip, unsigned int lun, int sense_type)
break;
#endif
-#ifdef SUPPORT_SD_LOCK
- case SENSE_TYPE_MEDIA_READ_FORBIDDEN:
- set_sense_data(chip, lun, CUR_ERR, 0x07, 0, 0x11, 0x13, 0, 0);
- break;
-#endif
-
case SENSE_TYPE_NO_SENSE:
default:
set_sense_data(chip, lun, CUR_ERR, 0, 0, 0, 0, 0, 0);
@@ -448,20 +437,6 @@ static int test_unit_ready(struct scsi_cmnd *srb, struct rts51x_chip *chip)
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE);
return TRANSPORT_FAILED;
}
-#ifdef SUPPORT_SD_LOCK
- if (get_lun_card(chip, SCSI_LUN(srb)) == SD_CARD) {
- struct sd_info *sd_card = &(chip->sd_card);
- if (sd_card->sd_lock_notify) {
- sd_card->sd_lock_notify = 0;
- set_sense_type(chip, lun, SENSE_TYPE_MEDIA_CHANGE);
- return TRANSPORT_FAILED;
- } else if (sd_card->sd_lock_status & SD_LOCKED) {
- set_sense_type(chip, lun,
- SENSE_TYPE_MEDIA_READ_FORBIDDEN);
- return TRANSPORT_FAILED;
- }
- }
-#endif
return TRANSPORT_GOOD;
}
@@ -797,9 +772,6 @@ static int request_sense(struct scsi_cmnd *srb, struct rts51x_chip *chip)
static int read_write(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
-#ifdef SUPPORT_SD_LOCK
- struct sd_info *sd_card = &(chip->sd_card);
-#endif
unsigned int lun = SCSI_LUN(srb);
int retval;
u32 start_sec;
@@ -819,25 +791,6 @@ static int read_write(struct scsi_cmnd *srb, struct rts51x_chip *chip)
rts51x_prepare_run(chip);
RTS51X_SET_STAT(chip, STAT_RUN);
-#ifdef SUPPORT_SD_LOCK
- if (sd_card->sd_erase_status) {
- /* Accessing to any card is forbidden
- * until the erase procedure of SD is completed */
- RTS51X_DEBUGP("SD card being erased!\n");
- set_sense_type(chip, lun, SENSE_TYPE_MEDIA_READ_FORBIDDEN);
- TRACE_RET(chip, TRANSPORT_FAILED);
- }
-
- if (get_lun_card(chip, lun) == SD_CARD) {
- if (sd_card->sd_lock_status & SD_LOCKED) {
- RTS51X_DEBUGP("SD card locked!\n");
- set_sense_type(chip, lun,
- SENSE_TYPE_MEDIA_READ_FORBIDDEN);
- TRACE_RET(chip, TRANSPORT_FAILED);
- }
- }
-#endif
-
if ((srb->cmnd[0] == READ_10) || (srb->cmnd[0] == WRITE_10)) {
start_sec =
((u32) srb->cmnd[2] << 24) |
@@ -883,20 +836,12 @@ static int read_write(struct scsi_cmnd *srb, struct rts51x_chip *chip)
retval = card_rw(srb, chip, start_sec, sec_cnt);
if (retval != STATUS_SUCCESS) {
-#if 0
- if (chip->need_release & chip->lun2card[lun]) {
- set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
- } else {
-#endif
if (srb->sc_data_direction == DMA_FROM_DEVICE) {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR);
} else {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR);
}
-#if 0
- }
-#endif
TRACE_RET(chip, TRANSPORT_FAILED);
}
@@ -1516,7 +1461,7 @@ static int ms_format_cmnd(struct scsi_cmnd *srb, struct rts51x_chip *chip)
}
#ifdef SUPPORT_PCGL_1P18
-int get_ms_information(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+static int get_ms_information(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
struct ms_info *ms_card = &(chip->ms_card);
unsigned int lun = SCSI_LUN(srb);
@@ -1677,7 +1622,7 @@ static int sd_extention_cmnd(struct scsi_cmnd *srb, struct rts51x_chip *chip)
#endif
#ifdef SUPPORT_MAGIC_GATE
-int mg_report_key(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+static int mg_report_key(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
struct ms_info *ms_card = &(chip->ms_card);
unsigned int lun = SCSI_LUN(srb);
@@ -1764,7 +1709,7 @@ int mg_report_key(struct scsi_cmnd *srb, struct rts51x_chip *chip)
return TRANSPORT_GOOD;
}
-int mg_send_key(struct scsi_cmnd *srb, struct rts51x_chip *chip)
+static int mg_send_key(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
struct ms_info *ms_card = &(chip->ms_card);
unsigned int lun = SCSI_LUN(srb);
@@ -1871,30 +1816,10 @@ int mg_send_key(struct scsi_cmnd *srb, struct rts51x_chip *chip)
int rts51x_scsi_handler(struct scsi_cmnd *srb, struct rts51x_chip *chip)
{
-#ifdef SUPPORT_SD_LOCK
- struct sd_info *sd_card = &(chip->sd_card);
-#endif
struct ms_info *ms_card = &(chip->ms_card);
unsigned int lun = SCSI_LUN(srb);
int result = TRANSPORT_GOOD;
-#ifdef SUPPORT_SD_LOCK
- if (sd_card->sd_erase_status) {
- /* Block all SCSI command except for REQUEST_SENSE
- * and rs_ppstatus */
- if (!
- ((srb->cmnd[0] == VENDOR_CMND)
- && (srb->cmnd[1] == SCSI_APP_CMD)
- && (srb->cmnd[2] == GET_DEV_STATUS))
- && (srb->cmnd[0] != REQUEST_SENSE)) {
- /* Logical Unit Not Ready Format in Progress */
- set_sense_data(chip, lun, CUR_ERR, 0x02, 0, 0x04, 0x04,
- 0, 0);
- TRACE_RET(chip, TRANSPORT_FAILED);
- }
- }
-#endif
-
if ((get_lun_card(chip, lun) == MS_CARD) &&
(ms_card->format_status == FORMAT_IN_PROGRESS)) {
if ((srb->cmnd[0] != REQUEST_SENSE)
@@ -1994,11 +1919,6 @@ int rts51x_scsi_handler(struct scsi_cmnd *srb, struct rts51x_chip *chip)
* Host functions
***********************************************************************/
-const char *host_info(struct Scsi_Host *host)
-{
- return "SCSI emulation for RTS51xx USB driver-based card reader";
-}
-
int slave_alloc(struct scsi_device *sdev)
{
/*
@@ -2111,14 +2031,7 @@ int queuecommand_lck(struct scsi_cmnd *srb, void (*done) (struct scsi_cmnd *))
return 0;
}
-#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) */
-int queuecommand(struct scsi_cmnd *srb, void (*done) (struct scsi_cmnd *))
-{
- return queuecommand_lck(srb, done);
-}
-#else
DEF_SCSI_QCMD(queuecommand)
-#endif
/***********************************************************************
* Error handling functions
***********************************************************************/
diff --git a/drivers/staging/rts5139/rts51x_scsi.h b/drivers/staging/rts5139/rts51x_scsi.h
index 3a8ca069b278..060d2c2e77ec 100644
--- a/drivers/staging/rts5139/rts51x_scsi.h
+++ b/drivers/staging/rts5139/rts51x_scsi.h
@@ -145,16 +145,11 @@ struct Scsi_Host;
struct scsi_device;
struct scsi_cmnd;
-const char *host_info(struct Scsi_Host *host);
int slave_alloc(struct scsi_device *sdev);
int slave_configure(struct scsi_device *sdev);
int proc_info(struct Scsi_Host *host, char *buffer,
char **start, off_t offset, int length, int inout);
-#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) */
-int queuecommand(struct scsi_cmnd *srb, void (*done) (struct scsi_cmnd *));
-#else
int queuecommand(struct Scsi_Host *, struct scsi_cmnd *);
-#endif
int command_abort(struct scsi_cmnd *srb);
int device_reset(struct scsi_cmnd *srb);
int bus_reset(struct scsi_cmnd *srb);
diff --git a/drivers/staging/rts5139/rts51x_sys.h b/drivers/staging/rts5139/rts51x_sys.h
deleted file mode 100644
index b09cd34a6c02..000000000000
--- a/drivers/staging/rts5139/rts51x_sys.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Driver for Realtek USB RTS51xx card reader
- * Header file
- *
- * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- * Author:
- * wwang (wei_wang@realsil.com.cn)
- * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
- * Maintainer:
- * Edwin Rong (edwin_rong@realsil.com.cn)
- * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
- */
-
-#ifndef __RTS51X_SYS_H
-#define __RTS51X_SYS_H
-
-#include "rts51x.h"
-#include "rts51x_chip.h"
-#include "rts51x_card.h"
-
-#define USING_POLLING_CYCLE_DELINK
-
-extern int rts51x_check_start_time(struct rts51x_chip *chip);
-extern void rts51x_set_start_time(struct rts51x_chip *chip);
-extern void rts51x_clear_start_time(struct rts51x_chip *chip);
-
-/* typedef dma_addr_t ULONG_PTR; */
-
-static inline void rts51x_reset_detected_cards(struct rts51x_chip *chip)
-{
-/* rts51x_reset_cards(chip); */
-}
-
-static inline void clear_first_install_mark(struct rts51x_chip *chip)
-{
-}
-
-void rts51x_enter_ss(struct rts51x_chip *chip);
-void rts51x_exit_ss(struct rts51x_chip *chip);
-
-#endif /* __RTS51X_SYS_H */
diff --git a/drivers/staging/rts5139/rts51x_transport.c b/drivers/staging/rts5139/rts51x_transport.c
index da9c83b49426..89e4d805a345 100644
--- a/drivers/staging/rts5139/rts51x_transport.c
+++ b/drivers/staging/rts5139/rts51x_transport.c
@@ -120,7 +120,7 @@ unsigned int rts51x_access_sglist(unsigned char *buffer,
return cnt;
}
-unsigned int rts51x_access_xfer_buf(unsigned char *buffer,
+static unsigned int rts51x_access_xfer_buf(unsigned char *buffer,
unsigned int buflen, struct scsi_cmnd *srb,
struct scatterlist **sgptr,
unsigned int *offset, enum xfer_buf_dir dir)
@@ -252,6 +252,8 @@ static int rts51x_msg_common(struct rts51x_chip *chip, struct urb *urb,
return status;
}
+static int rts51x_clear_halt(struct rts51x_chip *chip, unsigned int pipe);
+
/*
* Interpret the results of a URB transfer
*/
@@ -359,7 +361,7 @@ int rts51x_ctrl_transfer(struct rts51x_chip *chip, unsigned int pipe,
rts51x->current_urb->actual_length);
}
-int rts51x_clear_halt(struct rts51x_chip *chip, unsigned int pipe)
+static int rts51x_clear_halt(struct rts51x_chip *chip, unsigned int pipe)
{
int result;
int endp = usb_pipeendpoint(pipe);
@@ -378,11 +380,6 @@ int rts51x_clear_halt(struct rts51x_chip *chip, unsigned int pipe)
return STATUS_SUCCESS;
}
-int rts51x_reset_pipe(struct rts51x_chip *chip, char pipe)
-{
- return rts51x_clear_halt(chip, pipe);
-}
-
static void rts51x_sg_clean(struct usb_sg_request *io)
{
if (io->urbs) {
@@ -391,226 +388,17 @@ static void rts51x_sg_clean(struct usb_sg_request *io)
kfree(io->urbs);
io->urbs = NULL;
}
-#if 0 /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) */
- if (io->dev->dev.dma_mask != NULL)
- usb_buffer_unmap_sg(io->dev, usb_pipein(io->pipe),
- io->sg, io->nents);
-#endif
io->dev = NULL;
}
-#if 0
-static void rts51x_sg_complete(struct urb *urb)
-{
- struct usb_sg_request *io = urb->context;
- int status = urb->status;
-
- spin_lock(&io->lock);
-
- /* In 2.5 we require hcds' endpoint queues not to progress after fault
- * reports, until the completion callback (this!) returns. That lets
- * device driver code (like this routine) unlink queued urbs first,
- * if it needs to, since the HC won't work on them at all. So it's
- * not possible for page N+1 to overwrite page N, and so on.
- *
- * That's only for "hard" faults; "soft" faults (unlinks) sometimes
- * complete before the HCD can get requests away from hardware,
- * though never during cleanup after a hard fault.
- */
- if (io->status
- && (io->status != -ECONNRESET
- || status != -ECONNRESET)
- && urb->actual_length) {
- dev_err(io->dev->bus->controller,
- "dev %s ep%d%s scatterlist error %d/%d\n",
- io->dev->devpath,
- usb_endpoint_num(&urb->ep->desc),
- usb_urb_dir_in(urb) ? "in" : "out",
- status, io->status);
- /* BUG (); */
- }
-
- if (io->status == 0 && status && status != -ECONNRESET) {
- int i, found, retval;
-
- io->status = status;
-
- /* the previous urbs, and this one, completed already.
- * unlink pending urbs so they won't rx/tx bad data.
- * careful: unlink can sometimes be synchronous...
- */
- spin_unlock(&io->lock);
- for (i = 0, found = 0; i < io->entries; i++) {
- if (!io->urbs[i] || !io->urbs[i]->dev)
- continue;
- if (found) {
- retval = usb_unlink_urb(io->urbs[i]);
- if (retval != -EINPROGRESS &&
- retval != -ENODEV &&
- retval != -EBUSY)
- dev_err(&io->dev->dev,
- "%s, unlink --> %d\n",
- __func__, retval);
- } else if (urb == io->urbs[i])
- found = 1;
- }
- spin_lock(&io->lock);
- }
- urb->dev = NULL;
-
- /* on the last completion, signal usb_sg_wait() */
- io->bytes += urb->actual_length;
- io->count--;
- if (!io->count)
- complete(&io->complete);
-
- spin_unlock(&io->lock);
-}
-
-/* This function is ported from usb_sg_init, which can transfer
- * sg list partially */
-int rts51x_sg_init_partial(struct usb_sg_request *io, struct usb_device *dev,
- unsigned pipe, unsigned period, void *buf, struct scatterlist **sgptr,
- unsigned int *offset, int nents, size_t length, gfp_t mem_flags)
-{
- int i;
- int urb_flags;
- int dma;
- struct scatterlist *sg = *sgptr, *first_sg;
-
- first_sg = (struct scatterlist *)buf;
- if (!sg)
- sg = first_sg;
-
- if (!io || !dev || !sg
- || usb_pipecontrol(pipe)
- || usb_pipeisoc(pipe)
- || (nents <= 0))
- return -EINVAL;
-
- spin_lock_init(&io->lock);
- io->dev = dev;
- io->pipe = pipe;
- io->sg = first_sg; /* used by unmap */
- io->nents = nents;
-
- RTS51X_DEBUGP("Before map, sg address: 0x%x\n", (unsigned int)sg);
- RTS51X_DEBUGP("Before map, dev address: 0x%x\n", (unsigned int)dev);
-
- /* not all host controllers use DMA (like the mainstream pci ones);
- * they can use PIO (sl811) or be software over another transport.
- */
- dma = (dev->dev.dma_mask != NULL);
- if (dma) {
- /* map the whole sg list, because here we only know the
- * total nents */
- io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe),
- first_sg, nents);
- } else {
- io->entries = nents;
- }
-
- /* initialize all the urbs we'll use */
- if (io->entries <= 0)
- return io->entries;
-
- io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags);
- if (!io->urbs)
- goto nomem;
-
- urb_flags = URB_NO_INTERRUPT;
- if (dma)
- urb_flags |= URB_NO_TRANSFER_DMA_MAP;
- if (usb_pipein(pipe))
- urb_flags |= URB_SHORT_NOT_OK;
-
- RTS51X_DEBUGP("io->entries = %d\n", io->entries);
-
- for (i = 0; (sg != NULL) && (length > 0); i++) {
- unsigned len;
-
- RTS51X_DEBUGP("sg address: 0x%x\n", (unsigned int)sg);
- RTS51X_DEBUGP("length = %d, *offset = %d\n", length, *offset);
-
- io->urbs[i] = usb_alloc_urb(0, mem_flags);
- if (!io->urbs[i]) {
- io->entries = i;
- goto nomem;
- }
-
- io->urbs[i]->dev = NULL;
- io->urbs[i]->pipe = pipe;
- io->urbs[i]->interval = period;
- io->urbs[i]->transfer_flags = urb_flags;
-
- io->urbs[i]->complete = rts51x_sg_complete;
- io->urbs[i]->context = io;
-
- if (dma) {
- io->urbs[i]->transfer_dma =
- sg_dma_address(sg) + *offset;
- len = sg_dma_len(sg) - *offset;
- io->urbs[i]->transfer_buffer = NULL;
- RTS51X_DEBUGP(" -- sg entry dma length = %d\n",
- sg_dma_len(sg));
- } else {
- /* hc may use _only_ transfer_buffer */
- io->urbs[i]->transfer_buffer = sg_virt(sg) + *offset;
- len = sg->length - *offset;
- RTS51X_DEBUGP(" -- sg entry length = %d\n",
- sg->length);
- }
-
- if (length >= len) {
- *offset = 0;
- io->urbs[i]->transfer_buffer_length = len;
- length -= len;
- sg = sg_next(sg);
- } else {
- *offset += length;
- io->urbs[i]->transfer_buffer_length = length;
- length = 0;
- }
- if (length == 0)
- io->entries = i + 1;
-#if 0
- if (length) {
- len = min_t(unsigned, len, length);
- length -= len;
- if (length == 0) {
- io->entries = i + 1;
- *offset += len;
- } else {
- *offset = 0;
- }
- }
-#endif
- }
- RTS51X_DEBUGP("In %s, urb count: %d\n", __func__, i);
- io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT;
-
- RTS51X_DEBUGP("sg address stored in sgptr: 0x%x\n", (unsigned int)sg);
- *sgptr = sg;
-
- /* transaction state */
- io->count = io->entries;
- io->status = 0;
- io->bytes = 0;
- init_completion(&io->complete);
- return 0;
-nomem:
- rts51x_sg_clean(io);
- return -ENOMEM;
-}
-#endif
-int rts51x_sg_init(struct usb_sg_request *io, struct usb_device *dev,
+static int rts51x_sg_init(struct usb_sg_request *io, struct usb_device *dev,
unsigned pipe, unsigned period, struct scatterlist *sg,
int nents, size_t length, gfp_t mem_flags)
{
return usb_sg_init(io, dev, pipe, period, sg, nents, length, mem_flags);
}
-int rts51x_sg_wait(struct usb_sg_request *io, int timeout)
+static int rts51x_sg_wait(struct usb_sg_request *io, int timeout)
{
long timeleft;
int i;
@@ -630,7 +418,7 @@ int rts51x_sg_wait(struct usb_sg_request *io, int timeout)
*/
spin_unlock_irq(&io->lock);
switch (retval) {
- /* maybe we retrying will recover */
+ /* maybe the retry will recover */
case -ENXIO: /* hc didn't queue this one */
case -EAGAIN:
case -ENOMEM:
@@ -740,56 +528,9 @@ static int rts51x_bulk_transfer_sglist(struct rts51x_chip *chip,
return interpret_urb_result(chip, pipe, length, result,
chip->usb->current_sg.bytes);
}
-#if 0
-static int rts51x_bulk_transfer_sglist_partial(struct rts51x_chip *chip,
- unsigned int pipe, void *buf, struct scatterlist **sgptr,
- unsigned int *offset, int num_sg, unsigned int length,
- unsigned int *act_len, int timeout)
-{
- int result;
-
- /* don't submit s-g requests during abort processing */
- if (test_bit(FLIDX_ABORTING, &chip->usb->dflags))
- TRACE_RET(chip, STATUS_ERROR);
- /* initialize the scatter-gather request block */
- RTS51X_DEBUGP("%s: xfer %u bytes, %d entries\n", __func__,
- length, num_sg);
- result = rts51x_sg_init_partial(&chip->usb->current_sg,
- chip->usb->pusb_dev, pipe, 0, buf, sgptr, offset,
- num_sg, length, GFP_NOIO);
- if (result) {
- RTS51X_DEBUGP("rts51x_sg_init_partial returned %d\n", result);
- TRACE_RET(chip, STATUS_ERROR);
- }
-
- /* since the block has been initialized successfully, it's now
- * okay to cancel it */
- set_bit(FLIDX_SG_ACTIVE, &chip->usb->dflags);
-
- /* did an abort occur during the submission? */
- if (test_bit(FLIDX_ABORTING, &chip->usb->dflags)) {
-
- /* cancel the request, if it hasn't been cancelled already */
- if (test_and_clear_bit(FLIDX_SG_ACTIVE, &chip->usb->dflags)) {
- RTS51X_DEBUGP("-- cancelling sg request\n");
- usb_sg_cancel(&chip->usb->current_sg);
- }
- }
-
- /* wait for the completion of the transfer */
- result = rts51x_sg_wait(&chip->usb->current_sg, timeout);
-
- clear_bit(FLIDX_SG_ACTIVE, &chip->usb->dflags);
-
- /* result = us->current_sg.status; */
- if (act_len)
- *act_len = chip->usb->current_sg.bytes;
- return interpret_urb_result(chip, pipe, length, result,
- chip->usb->current_sg.bytes);
-}
-#endif
-int rts51x_bulk_transfer_buf(struct rts51x_chip *chip, unsigned int pipe,
+static int rts51x_bulk_transfer_buf(struct rts51x_chip *chip,
+ unsigned int pipe,
void *buf, unsigned int length,
unsigned int *act_len, int timeout)
{
@@ -860,11 +601,6 @@ int rts51x_transfer_data_partial(struct rts51x_chip *chip, unsigned int pipe,
}
kfree(tmp_buf);
-#if 0
- result = rts51x_bulk_transfer_sglist_partial(chip, pipe, buf,
- (struct scatterlist **)ptr, offset,
- use_sg, len, act_len, timeout);
-#endif
} else {
unsigned int step = 0;
if (offset)
diff --git a/drivers/staging/rts5139/rts51x_transport.h b/drivers/staging/rts5139/rts51x_transport.h
index 9dd556ea9c08..024f115540a6 100644
--- a/drivers/staging/rts5139/rts51x_transport.h
+++ b/drivers/staging/rts5139/rts51x_transport.h
@@ -40,11 +40,6 @@ unsigned int rts51x_access_sglist(unsigned char *buffer,
unsigned int buflen, void *sglist,
void **sgptr, unsigned int *offset,
enum xfer_buf_dir dir);
-unsigned int rts51x_access_xfer_buf(unsigned char *buffer, unsigned int buflen,
- struct scsi_cmnd *srb,
- struct scatterlist **sgptr,
- unsigned int *offset,
- enum xfer_buf_dir dir);
void rts51x_set_xfer_buf(unsigned char *buffer, unsigned int buflen,
struct scsi_cmnd *srb);
void rts51x_get_xfer_buf(unsigned char *buffer, unsigned int buflen,
@@ -53,7 +48,6 @@ void rts51x_get_xfer_buf(unsigned char *buffer, unsigned int buflen,
int rts51x_ctrl_transfer(struct rts51x_chip *chip, unsigned int pipe,
u8 request, u8 requesttype, u16 value, u16 index,
void *data, u16 size, int timeout);
-int rts51x_clear_halt(struct rts51x_chip *chip, unsigned int pipe);
int rts51x_transfer_data(struct rts51x_chip *chip, unsigned int pipe,
void *buf, unsigned int len, int use_sg,
unsigned int *act_len, int timeout);
@@ -62,12 +56,6 @@ int rts51x_transfer_data_partial(struct rts51x_chip *chip, unsigned int pipe,
unsigned int len, int use_sg,
unsigned int *act_len, int timeout);
-/* whichPipe:
- * 0: bulk in pipe
- * 1: bulk out pipe
- * 2: intr in pipe */
-int rts51x_reset_pipe(struct rts51x_chip *chip, char pipe);
-
#ifndef POLLING_IN_THREAD
int rts51x_start_epc_transfer(struct rts51x_chip *chip);
void rts51x_cancel_epc_transfer(struct rts51x_chip *chip);
diff --git a/drivers/staging/rts5139/sd.c b/drivers/staging/rts5139/sd.c
index d5dd2f926d1d..b739f26f78cc 100644
--- a/drivers/staging/rts5139/sd.c
+++ b/drivers/staging/rts5139/sd.c
@@ -246,12 +246,7 @@ RTY_SEND_CMD:
if (buf[1] & 0x80)
TRACE_RET(chip, STATUS_FAIL);
}
-#ifdef SUPPORT_SD_LOCK
- /* exclude bit25 CARD_IS_LOCKED */
- if (buf[1] & 0x7D) {
-#else
if (buf[1] & 0x7F) {
-#endif
RTS51X_DEBUGP("buf[1]: 0x%02x\n", buf[1]);
TRACE_RET(chip, STATUS_FAIL);
}
@@ -709,37 +704,7 @@ int sd_select_card(struct rts51x_chip *chip, int select)
return STATUS_SUCCESS;
}
-#ifdef SUPPORT_SD_LOCK
-int sd_update_lock_status(struct rts51x_chip *chip)
-{
- struct sd_info *sd_card = &(chip->sd_card);
- int retval;
- u8 rsp[5];
-
- retval =
- sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr,
- SD_RSP_TYPE_R1, rsp, 5);
- if (retval != STATUS_SUCCESS)
- TRACE_RET(chip, STATUS_FAIL);
-
- if (rsp[1] & 0x02)
- sd_card->sd_lock_status |= SD_LOCKED;
- else
- sd_card->sd_lock_status &= ~SD_LOCKED;
-
- RTS51X_DEBUGP("sd_card->sd_lock_status = 0x%x\n",
- sd_card->sd_lock_status);
-
- if (rsp[1] & 0x01) {
- /* LOCK_UNLOCK_FAILED */
- TRACE_RET(chip, STATUS_FAIL);
- }
-
- return STATUS_SUCCESS;
-}
-#endif
-
-int sd_wait_currentstate_dataready(struct rts51x_chip *chip, u8 statechk,
+static int sd_wait_currentstate_dataready(struct rts51x_chip *chip, u8 statechk,
u8 rdychk, u16 pollingcnt)
{
struct sd_info *sd_card = &(chip->sd_card);
@@ -1197,15 +1162,6 @@ static int sd_switch_function(struct rts51x_chip *chip, u8 bus_width)
RTS51X_DEBUGP("SD_FUNC_GROUP_1: func_to_switch = 0x%02x",
func_to_switch);
-#ifdef SUPPORT_SD_LOCK
- if ((sd_card->sd_lock_status & SD_SDR_RST)
- && (DDR50_SUPPORT == func_to_switch)
- && (sd_card->func_group1_mask & SDR50_SUPPORT_MASK)) {
- func_to_switch = SDR50_SUPPORT;
- RTS51X_DEBUGP("Using SDR50 instead of DDR50 for SD Lock\n");
- }
-#endif
-
if (func_to_switch) {
retval =
sd_check_switch(chip, SD_FUNC_GROUP_1, func_to_switch,
@@ -1562,7 +1518,7 @@ static u8 sd_search_final_phase(struct rts51x_chip *chip, u32 phase_map,
}
Search_Finish:
- RTS51X_DEBUGP("Final choosen phase: %d\n", final_phase);
+ RTS51X_DEBUGP("Final chosen phase: %d\n", final_phase);
return final_phase;
}
@@ -2024,10 +1980,6 @@ Switch_Fail:
k = 0;
hi_cap_flow = 0;
support_1v8 = 0;
-#ifdef SUPPORT_SD_LOCK
- if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON)
- goto SD_UNLOCK_ENTRY;
-#endif
retval = sd_prepare_reset(chip);
if (retval != STATUS_SUCCESS)
@@ -2182,7 +2134,7 @@ RTY_CMD55:
sd_card->sd_addr += (u32) rsp[2] << 16;
/* Get CSD register for Calculating Timing,Capacity,
- * Check CSD to determaine as if this is the SD ROM card */
+ * Check CSD to determine as if this is the SD ROM card */
retval = sd_check_csd(chip, 1);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
@@ -2190,20 +2142,6 @@ RTY_CMD55:
retval = sd_select_card(chip, 1);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
-#ifdef SUPPORT_SD_LOCK
-SD_UNLOCK_ENTRY:
- /* Get SD lock status */
- retval = sd_update_lock_status(chip);
- if (retval != STATUS_SUCCESS)
- TRACE_RET(chip, STATUS_FAIL);
-
- if (sd_card->sd_lock_status & SD_LOCKED) {
- sd_card->sd_lock_status |= (SD_LOCK_1BIT_MODE | SD_PWD_EXIST);
- return STATUS_SUCCESS;
- } else if (!(sd_card->sd_lock_status & SD_UNLOCK_POW_ON)) {
- sd_card->sd_lock_status &= ~SD_PWD_EXIST;
- }
-#endif
/* ACMD42 */
retval =
@@ -2294,10 +2232,6 @@ SD_UNLOCK_ENTRY:
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
}
-#ifdef SUPPORT_SD_LOCK
- /* clear 1 bit mode status */
- sd_card->sd_lock_status &= ~SD_LOCK_1BIT_MODE;
-#endif
if (CHK_SD30_SPEED(sd_card)) {
rts51x_write_register(chip, SD30_DRIVE_SEL, SD30_DRIVE_MASK,
@@ -2380,19 +2314,6 @@ SD_UNLOCK_ENTRY:
chip->card_bus_width[chip->card2lun[SD_CARD]] = 4;
-#ifdef SUPPORT_SD_LOCK
- if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON) {
- rts51x_init_cmd(chip);
-
- rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0x02);
- rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 0x00);
-
- retval = rts51x_send_cmd(chip, MODE_C, 100);
- if (retval != STATUS_SUCCESS)
- TRACE_RET(chip, retval);
- }
-#endif
-
return STATUS_SUCCESS;
}
@@ -2587,17 +2508,10 @@ static int mmc_switch_timing_bus(struct rts51x_chip *chip)
sd_card->capacity =
((u32) buf[5] << 24) | ((u32) buf[4] << 16) |
((u32) buf[3] << 8) | ((u32) buf[2]);
-#ifdef SUPPORT_SD_LOCK
- if (!(sd_card->sd_lock_status & SD_SDR_RST) && CHECK_UHS50(chip))
- card_type_mask = 0x07;
- else
- card_type_mask = 0x03;
-#else
if (CHECK_UHS50(chip))
card_type_mask = 0x07;
else
card_type_mask = 0x03;
-#endif
card_type = buf[1] & card_type_mask;
if (card_type) {
@@ -2626,15 +2540,9 @@ static int mmc_switch_timing_bus(struct rts51x_chip *chip)
if (mmc_test_switch_bus(chip, MMC_8BIT_BUS) == STATUS_SUCCESS) {
SET_MMC_8BIT(sd_card);
chip->card_bus_width[chip->card2lun[SD_CARD]] = 8;
-#ifdef SUPPORT_SD_LOCK
- sd_card->sd_lock_status &= ~SD_LOCK_1BIT_MODE;
-#endif
} else if (mmc_test_switch_bus(chip, MMC_4BIT_BUS) == STATUS_SUCCESS) {
SET_MMC_4BIT(sd_card);
chip->card_bus_width[chip->card2lun[SD_CARD]] = 4;
-#ifdef SUPPORT_SD_LOCK
- sd_card->sd_lock_status &= ~SD_LOCK_1BIT_MODE;
-#endif
} else {
CLR_MMC_8BIT(sd_card);
CLR_MMC_4BIT(sd_card);
@@ -2652,11 +2560,6 @@ static int reset_mmc(struct rts51x_chip *chip)
u8 change_to_ddr52 = 1;
u8 cmd[5];
-#ifdef SUPPORT_SD_LOCK
- if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON)
- goto MMC_UNLOCK_ENTRY;
-#endif
-
MMC_DDR_FAIL:
retval = sd_prepare_reset(chip);
@@ -2745,7 +2648,7 @@ RTY_MMC_RST:
TRACE_RET(chip, retval);
/* Get CSD register for Calculating Timing,Capacity
- * Check CSD to determaine as if this is the SD ROM card */
+ * Check CSD to determine as if this is the SD ROM card */
retval = sd_check_csd(chip, 1);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
@@ -2763,13 +2666,6 @@ RTY_MMC_RST:
0);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
-#ifdef SUPPORT_SD_LOCK
-MMC_UNLOCK_ENTRY:
- /* Get SD lock status */
- retval = sd_update_lock_status(chip);
- if (retval != STATUS_SUCCESS)
- TRACE_RET(chip, STATUS_FAIL);
-#endif
RTS51X_WRITE_REG(chip, SD_CFG1, SD_CLK_DIVIDE_MASK, SD_CLK_DIVIDE_0);
@@ -2842,18 +2738,6 @@ MMC_UNLOCK_ENTRY:
}
}
}
-#ifdef SUPPORT_SD_LOCK
- if (sd_card->sd_lock_status & SD_UNLOCK_POW_ON) {
- rts51x_init_cmd(chip);
-
- rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0x02);
- rts51x_add_cmd(chip, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 0x00);
-
- retval = rts51x_send_cmd(chip, MODE_C, 100);
- if (retval != STATUS_SUCCESS)
- TRACE_RET(chip, retval);
- }
-#endif
retval = rts51x_get_card_status(chip, &(chip->card_status));
if (retval != STATUS_SUCCESS)
@@ -2879,11 +2763,6 @@ int reset_sd_card(struct rts51x_chip *chip)
sd_card->capacity = 0;
sd_card->sd_switch_fail = 0;
-#ifdef SUPPORT_SD_LOCK
- sd_card->sd_lock_status = 0;
- sd_card->sd_erase_status = 0;
-#endif
-
sd_clear_reset_fail(chip);
enable_card_clock(chip, SD_CARD);
@@ -3006,7 +2885,7 @@ static int wait_data_buf_ready(struct rts51x_chip *chip)
TRACE_RET(chip, STATUS_FAIL);
}
-void sd_stop_seq_mode(struct rts51x_chip *chip)
+static void sd_stop_seq_mode(struct rts51x_chip *chip)
{
struct sd_info *sd_card = &(chip->sd_card);
int retval;
@@ -3300,7 +3179,7 @@ void sd_cleanup_work(struct rts51x_chip *chip)
}
}
-inline void sd_fill_power_off_card3v3(struct rts51x_chip *chip)
+static inline void sd_fill_power_off_card3v3(struct rts51x_chip *chip)
{
rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_CLK_EN, SD_CLK_EN, 0);
@@ -3322,7 +3201,7 @@ inline void sd_fill_power_off_card3v3(struct rts51x_chip *chip)
}
}
-int sd_power_off_card3v3(struct rts51x_chip *chip)
+static int sd_power_off_card3v3(struct rts51x_chip *chip)
{
int retval;
@@ -3346,17 +3225,12 @@ int release_sd_card(struct rts51x_chip *chip)
struct sd_info *sd_card = &(chip->sd_card);
int retval;
- RTS51X_DEBUGP("elease_sd_card\n");
+ RTS51X_DEBUGP("release_sd_card\n");
chip->card_ready &= ~SD_CARD;
chip->card_fail &= ~SD_CARD;
chip->card_wp &= ~SD_CARD;
-#ifdef SUPPORT_SD_LOCK
- sd_card->sd_lock_status = 0;
- sd_card->sd_erase_status = 0;
-#endif
-
memset(sd_card->raw_csd, 0, 16);
memset(sd_card->raw_scr, 0, 8);
diff --git a/drivers/staging/rts5139/sd.h b/drivers/staging/rts5139/sd.h
index 0805edcaea86..de155d8e682d 100644
--- a/drivers/staging/rts5139/sd.h
+++ b/drivers/staging/rts5139/sd.h
@@ -141,29 +141,6 @@
#define SWITCH_MODE_ERR 0x06
#define SWITCH_PASS 0x07
-#ifdef SUPPORT_SD_LOCK
-/* CMD42 Parameter */
-#define SD_ERASE 0x08
-#define SD_LOCK 0x04
-#define SD_UNLOCK 0x00
-#define SD_CLR_PWD 0x02
-#define SD_SET_PWD 0x01
-
-#define SD_PWD_LEN 0x10
-
-/* SD lock unlock Status */
-#define SD_LOCKED 0x80 /* Global lock status */
-#define SD_LOCK_1BIT_MODE 0x40 /**/
-#define SD_PWD_EXIST 0x20
-#define SD_UNLOCK_POW_ON 0x01 /**/
-#define SD_SDR_RST 0x02 /* Reset SD30 card with current DDR mode to SDR mode. */
-/* g_bySDEraseStatus */
-#define SD_NOT_ERASE 0x00
-#define SD_UNDER_ERASING 0x01
-#define SD_COMPLETE_ERASE 0x02
-/* SD_RW FAIL status */
-#define SD_RW_FORBIDDEN 0x0F /* read/write is forbidden (SD card) */
-#endif
/* Function Group Definition */
/* Function Group 1 */
#define HS_SUPPORT 0x01
@@ -282,17 +259,11 @@ struct timing_phase_path {
int sd_select_card(struct rts51x_chip *chip, int select);
int reset_sd_card(struct rts51x_chip *chip);
int sd_switch_clock(struct rts51x_chip *chip);
-void sd_stop_seq_mode(struct rts51x_chip *chip);
int sd_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 start_sector,
u16 sector_cnt);
void sd_cleanup_work(struct rts51x_chip *chip);
-int sd_power_off_card3v3(struct rts51x_chip *chip);
int release_sd_card(struct rts51x_chip *chip);
-#ifdef SUPPORT_SD_LOCK
-int sd_update_lock_status(struct rts51x_chip *chip);
-#endif
-
#ifdef SUPPORT_CPRM
extern int reset_sd(struct rts51x_chip *chip);
extern int sd_check_data0_status(struct rts51x_chip *chip);
diff --git a/drivers/staging/rts5139/sd_cprm.c b/drivers/staging/rts5139/sd_cprm.c
index d5969d992d84..f8c60711f710 100644
--- a/drivers/staging/rts5139/sd_cprm.c
+++ b/drivers/staging/rts5139/sd_cprm.c
@@ -77,12 +77,7 @@ static inline int get_rsp_type(u8 rsp_code, u8 *rsp_type, int *rsp_len)
return STATUS_SUCCESS;
}
-int soft_reset_sd_card(struct rts51x_chip *chip)
-{
- return reset_sd(chip);
-}
-
-int ext_sd_send_cmd_get_rsp(struct rts51x_chip *chip, u8 cmd_idx,
+static int ext_sd_send_cmd_get_rsp(struct rts51x_chip *chip, u8 cmd_idx,
u32 arg, u8 rsp_type, u8 *rsp, int rsp_len,
int special_check)
{
@@ -206,11 +201,7 @@ RTY_SEND_CMD:
if (buf[1] & 0x80)
TRACE_RET(chip, STATUS_FAIL);
}
-#ifdef SUPPORT_SD_LOCK
- if (buf[1] & 0x7D) {
-#else
if (buf[1] & 0x7F) {
-#endif
TRACE_RET(chip, STATUS_FAIL);
}
if (buf[2] & 0xF8)
@@ -233,7 +224,7 @@ RTY_SEND_CMD:
return STATUS_SUCCESS;
}
-int ext_sd_get_rsp(struct rts51x_chip *chip, int len, u8 *rsp, u8 rsp_type)
+static int ext_sd_get_rsp(struct rts51x_chip *chip, int len, u8 *rsp, u8 rsp_type)
{
int retval, rsp_len;
u16 reg_addr;
@@ -305,26 +296,8 @@ int ext_sd_execute_no_data(struct rts51x_chip *chip, unsigned int lun,
retval = sd_switch_clock(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, TRANSPORT_FAILED);
-#ifdef SUPPORT_SD_LOCK
- if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) {
- if (CHK_MMC_8BIT(sd_card)) {
- retval =
- rts51x_write_register(chip, SD_CFG1, 0x03,
- SD_BUS_WIDTH_8);
- if (retval != STATUS_SUCCESS)
- TRACE_RET(chip, TRANSPORT_FAILED);
- } else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) {
- retval =
- rts51x_write_register(chip, SD_CFG1, 0x03,
- SD_BUS_WIDTH_4);
- if (retval != STATUS_SUCCESS)
- TRACE_RET(chip, TRANSPORT_FAILED);
- }
- }
-#else
/* Set H/W SD/MMC Bus Width */
rts51x_write_register(chip, SD_CFG1, 0x03, SD_BUS_WIDTH_4);
-#endif
if (standby) {
retval = sd_select_card(chip, 0);
@@ -350,12 +323,6 @@ int ext_sd_execute_no_data(struct rts51x_chip *chip, unsigned int lun,
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Cmd_Failed);
}
-#ifdef SUPPORT_SD_LOCK
- /* Get SD lock status */
- retval = sd_update_lock_status(chip);
- if (retval != STATUS_SUCCESS)
- TRACE_GOTO(chip, SD_Execute_Cmd_Failed);
-#endif
return TRANSPORT_GOOD;
@@ -399,21 +366,7 @@ int ext_sd_execute_read_data(struct rts51x_chip *chip, unsigned int lun,
retval = sd_switch_clock(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, TRANSPORT_FAILED);
-#ifdef SUPPORT_SD_LOCK
- if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) {
- if (CHK_MMC_8BIT(sd_card))
- bus_width = SD_BUS_WIDTH_8;
- else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card))
- bus_width = SD_BUS_WIDTH_4;
- else
- bus_width = SD_BUS_WIDTH_1;
- } else {
- bus_width = SD_BUS_WIDTH_4;
- }
- RTS51X_DEBUGP("bus_width = %d\n", bus_width);
-#else
bus_width = SD_BUS_WIDTH_4;
-#endif
if (data_len < 512) {
retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, data_len,
@@ -599,11 +552,6 @@ int ext_sd_execute_write_data(struct rts51x_chip *chip, unsigned int lun,
int cmd13_checkbit = 0, write_err = 0;
u8 rsp_type;
u32 i;
-#ifdef SUPPORT_SD_LOCK
- int lock_cmd_fail = 0;
- u8 sd_lock_state = 0;
- u8 lock_cmd_type = 0;
-#endif
if (sd_card->pre_cmd_err) {
sd_card->pre_cmd_err = 0;
@@ -614,12 +562,6 @@ int ext_sd_execute_write_data(struct rts51x_chip *chip, unsigned int lun,
retval = sd_switch_clock(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
-#ifdef SUPPORT_SD_LOCK
- if (cmd_idx == LOCK_UNLOCK) {
- sd_lock_state = sd_card->sd_lock_status;
- sd_lock_state &= SD_LOCKED;
- }
-#endif
retval = get_rsp_type(rsp_code, &rsp_type, &rsp_len);
if (retval != STATUS_SUCCESS) {
@@ -631,25 +573,7 @@ int ext_sd_execute_write_data(struct rts51x_chip *chip, unsigned int lun,
retval = sd_switch_clock(chip);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, TRANSPORT_FAILED);
-#ifdef SUPPORT_SD_LOCK
- if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) {
- if (CHK_MMC_8BIT(sd_card)) {
- retval =
- rts51x_write_register(chip, SD_CFG1, 0x03,
- SD_BUS_WIDTH_8);
- if (retval != STATUS_SUCCESS)
- TRACE_RET(chip, TRANSPORT_FAILED);
- } else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) {
- retval =
- rts51x_write_register(chip, SD_CFG1, 0x03,
- SD_BUS_WIDTH_4);
- if (retval != STATUS_SUCCESS)
- TRACE_RET(chip, TRANSPORT_FAILED);
- }
- }
-#else
rts51x_write_register(chip, SD_CFG1, 0x03, SD_BUS_WIDTH_4);
-#endif
if (data_len < 512) {
retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, data_len,
@@ -692,10 +616,6 @@ int ext_sd_execute_write_data(struct rts51x_chip *chip, unsigned int lun,
else
memcpy(buf, data_buf, data_len);
-#ifdef SUPPORT_SD_LOCK
- if (cmd_idx == LOCK_UNLOCK)
- lock_cmd_type = buf[0] & 0x0F;
-#endif
if (data_len > 256) {
rts51x_init_cmd(chip);
@@ -802,29 +722,6 @@ int ext_sd_execute_write_data(struct rts51x_chip *chip, unsigned int lun,
SD_STOP | SD_CLR_ERR);
TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
}
-#ifdef SUPPORT_SD_LOCK
- if (cmd_idx == LOCK_UNLOCK) {
- if (lock_cmd_type == SD_ERASE) {
- sd_card->sd_erase_status = SD_UNDER_ERASING;
- scsi_set_resid(srb, 0);
- return TRANSPORT_GOOD;
- }
-
- rts51x_init_cmd(chip);
- rts51x_add_cmd(chip, CHECK_REG_CMD, SD_BUS_STAT, SD_DAT0_STATUS,
- SD_DAT0_STATUS);
- retval = rts51x_send_cmd(chip, MODE_CR, 250);
- if (retval != STATUS_SUCCESS)
- TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
- rts51x_get_rsp(chip, 1, 200); /* Don't care return value */
-
- retval = sd_update_lock_status(chip);
- if (retval != STATUS_SUCCESS) {
- RTS51X_DEBUGP("Lock command fail!\n");
- lock_cmd_fail = 1;
- }
- }
-#endif /* SUPPORT_SD_LOCK */
if (standby) {
retval = sd_select_card(chip, 1);
@@ -865,51 +762,6 @@ int ext_sd_execute_write_data(struct rts51x_chip *chip, unsigned int lun,
}
if (retval != STATUS_SUCCESS)
TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed);
-#ifdef SUPPORT_SD_LOCK
- if (cmd_idx == LOCK_UNLOCK) {
- if (!lock_cmd_fail) {
- RTS51X_DEBUGP("lock_cmd_type = 0x%x\n",
- lock_cmd_type);
- if (lock_cmd_type & SD_CLR_PWD)
- sd_card->sd_lock_status &= ~SD_PWD_EXIST;
- if (lock_cmd_type & SD_SET_PWD)
- sd_card->sd_lock_status |= SD_PWD_EXIST;
- }
-
- RTS51X_DEBUGP("sd_lock_state = 0x%x,"
- "sd_card->sd_lock_status = 0x%x\n",
- sd_lock_state, sd_card->sd_lock_status);
- if (sd_lock_state ^ (sd_card->sd_lock_status & SD_LOCKED)) {
- sd_card->sd_lock_notify = 1;
- if (sd_lock_state) {
- if (sd_card->sd_lock_status &
- SD_LOCK_1BIT_MODE) {
- sd_card->sd_lock_status |=
- (SD_UNLOCK_POW_ON | SD_SDR_RST);
- if (CHK_SD(sd_card)) {
- retval = reset_sd(chip);
- if (retval != STATUS_SUCCESS) {
- sd_card->sd_lock_status
- &= ~(SD_UNLOCK_POW_ON |
- SD_SDR_RST);
- TRACE_GOTO(chip,
- SD_Execute_Write_Cmd_Failed);
- }
- }
-
- sd_card->sd_lock_status &=
- ~(SD_UNLOCK_POW_ON | SD_SDR_RST);
- }
- }
- }
- }
-
- if (lock_cmd_fail) {
- scsi_set_resid(srb, 0);
- set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE);
- TRACE_RET(chip, TRANSPORT_FAILED);
- }
-#endif /* SUPPORT_SD_LOCK */
return TRANSPORT_GOOD;
@@ -1173,30 +1025,18 @@ int sd_hw_rst(struct scsi_cmnd *srb, struct rts51x_chip *chip)
switch (srb->cmnd[1] & 0x0F) {
case 0:
/* SD Card Power Off -> ON and Initialization */
-#ifdef SUPPORT_SD_LOCK
- if (0x64 == srb->cmnd[9]) {
- /* Command Mode */
- sd_card->sd_lock_status |= SD_SDR_RST;
- }
-#endif /* SUPPORT_SD_LOCK */
retval = reset_sd_card(chip);
if (retval != STATUS_SUCCESS) {
-#ifdef SUPPORT_SD_LOCK
- sd_card->sd_lock_status &= ~SD_SDR_RST;
-#endif
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
sd_card->pre_cmd_err = 1;
TRACE_RET(chip, TRANSPORT_FAILED);
}
-#ifdef SUPPORT_SD_LOCK
- sd_card->sd_lock_status &= ~SD_SDR_RST;
-#endif
break;
case 1:
/* reset CMD(CMD0) and Initialization
* (without SD Card Power Off -> ON) */
- retval = soft_reset_sd_card(chip);
+ retval = reset_sd(chip);
if (retval != STATUS_SUCCESS) {
set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT);
sd_card->pre_cmd_err = 1;
diff --git a/drivers/staging/rts5139/xd.c b/drivers/staging/rts5139/xd.c
index 5820605d1806..58f8ba24caed 100644
--- a/drivers/staging/rts5139/xd.c
+++ b/drivers/staging/rts5139/xd.c
@@ -47,13 +47,6 @@ static inline void xd_set_err_code(struct rts51x_chip *chip, u8 err_code)
xd_card->err_code = err_code;
}
-static inline int xd_check_err_code(struct rts51x_chip *chip, u8 err_code)
-{
- struct xd_info *xd_card = &(chip->xd_card);
-
- return (xd_card->err_code == err_code);
-}
-
static int xd_set_init_para(struct rts51x_chip *chip)
{
struct xd_info *xd_card = &(chip->xd_card);
@@ -862,6 +855,8 @@ static void xd_set_l2p_tbl(struct rts51x_chip *chip, int zone_no, u16 log_off,
zone->l2p_table[log_off] = phy_off;
}
+static int xd_delay_write(struct rts51x_chip *chip);
+
static u32 xd_get_l2p_tbl(struct rts51x_chip *chip, int zone_no, u16 log_off)
{
struct xd_info *xd_card = &(chip->xd_card);
@@ -1182,91 +1177,6 @@ static int xd_copy_page(struct rts51x_chip *chip,
return STATUS_SUCCESS;
}
-#ifdef XD_SPEEDUP
-static int xd_auto_copy_page(struct rts51x_chip *chip,
- u32 old_blk, u32 new_blk,
- u8 start_page, u8 end_page)
-{
- struct xd_info *xd_card = &(chip->xd_card);
- u32 old_page, new_page;
- int retval;
- u8 page_count;
-
- RTS51X_DEBUGP("Auto copy page from block 0x%x to block 0x%x\n",
- old_blk, new_blk);
-
- if (start_page > end_page)
- TRACE_RET(chip, STATUS_FAIL);
-
- page_count = end_page - start_page;
-
- if ((old_blk == BLK_NOT_FOUND) || (new_blk == BLK_NOT_FOUND))
- TRACE_RET(chip, STATUS_FAIL);
-
- old_page = (old_blk << xd_card->block_shift) + start_page;
- new_page = (new_blk << xd_card->block_shift) + start_page;
-
- XD_CLR_BAD_NEWBLK(xd_card);
-
- rts51x_init_cmd(chip);
-
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WAITTIME, 0x03, WAIT_FF);
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_PAGELEN, 0xFF, page_count);
-
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR0, 0xFF, 0);
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR1, 0xFF,
- (u8) old_page);
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR2, 0xFF,
- (u8) (old_page >> 8));
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR3, 0xFF,
- (u8) (old_page >> 16));
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_READADDR4, 0xFF, 0);
-
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR0, 0xFF, 0);
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR1, 0xFF,
- (u8) new_page);
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR2, 0xFF,
- (u8) (new_page >> 8));
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR3, 0xFF,
- (u8) (new_page >> 16));
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CP_WRITEADDR4, 0xFF, 0);
-
- rts51x_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01,
- PINGPONG_BUFFER);
-
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CFG,
- XD_BA_TRANSFORM | XD_ADDR_MASK, 0 | xd_card->addr_cycle);
-
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_CHK_DATA_STATUS,
- XD_AUTO_CHK_DATA_STATUS, 0);
- rts51x_add_cmd(chip, WRITE_REG_CMD, XD_TRANSFER, 0xFF,
- XD_TRANSFER_START | XD_COPY_PAGES);
- rts51x_add_cmd(chip, CHECK_REG_CMD, XD_TRANSFER, XD_TRANSFER_END,
- XD_TRANSFER_END);
-
- retval = rts51x_send_cmd(chip, MODE_CR, 100);
- if (retval != STATUS_SUCCESS) {
- rts51x_clear_xd_error(chip);
- TRACE_GOTO(chip, Copy_Fail);
- }
-
- retval = rts51x_get_rsp(chip, 1, 800);
- if (retval != STATUS_SUCCESS) {
- rts51x_clear_xd_error(chip);
- TRACE_GOTO(chip, Copy_Fail);
- }
-
- return STATUS_SUCCESS;
-
-Copy_Fail:
- retval = xd_copy_page(chip, old_blk, new_blk, start_page, end_page);
- if (retval != STATUS_SUCCESS)
- TRACE_RET(chip, retval);
-
- return STATUS_SUCCESS;
-}
-#endif
-
static int xd_reset_cmd(struct rts51x_chip *chip)
{
int retval;
@@ -1686,15 +1596,9 @@ Fail:
XD_CLR_BAD_OLDBLK(xd_card);
TRACE_RET(chip, STATUS_FAIL);
}
-#ifdef XD_SPEEDUP
- retval =
- xd_auto_copy_page(chip, phy_blk, new_blk, 0,
- xd_card->page_off + 1);
-#else
retval =
xd_copy_page(chip, phy_blk, new_blk, 0,
xd_card->page_off + 1);
-#endif
if (retval != STATUS_SUCCESS) {
if (!XD_CHK_BAD_NEWBLK(xd_card)) {
retval = xd_erase_block(chip, new_blk);
@@ -1741,13 +1645,8 @@ static int xd_finish_write(struct rts51x_chip *chip,
TRACE_RET(chip, STATUS_FAIL);
}
} else {
-#ifdef XD_SPEEDUP
- retval = xd_auto_copy_page(chip, old_blk, new_blk,
- page_off, xd_card->page_off + 1);
-#else
retval = xd_copy_page(chip, old_blk, new_blk,
page_off, xd_card->page_off + 1);
-#endif
if (retval != STATUS_SUCCESS) {
if (!XD_CHK_BAD_NEWBLK(xd_card)) {
retval = xd_erase_block(chip, new_blk);
@@ -1789,11 +1688,7 @@ static int xd_prepare_write(struct rts51x_chip *chip,
old_blk, new_blk, log_blk, (int)page_off);
if (page_off) {
-#ifdef XD_SPEEDUP
- retval = xd_auto_copy_page(chip, old_blk, new_blk, 0, page_off);
-#else
retval = xd_copy_page(chip, old_blk, new_blk, 0, page_off);
-#endif
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, retval);
}
@@ -1922,7 +1817,7 @@ Fail:
TRACE_RET(chip, STATUS_FAIL);
}
-int xd_delay_write(struct rts51x_chip *chip)
+static int xd_delay_write(struct rts51x_chip *chip)
{
struct xd_info *xd_card = &(chip->xd_card);
struct xd_delay_write_tag *delay_write = &(xd_card->delay_write);
@@ -1999,18 +1894,11 @@ int xd_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 start_sector,
(start_page > delay_write->pageoff)) {
delay_write->delay_write_flag = 0;
if (delay_write->old_phyblock != BLK_NOT_FOUND) {
-#ifdef XD_SPEEDUP
- retval = xd_auto_copy_page(chip,
- delay_write->old_phyblock,
- delay_write->new_phyblock,
- delay_write->pageoff, start_page);
-#else
retval = xd_copy_page(chip,
delay_write->old_phyblock,
delay_write->new_phyblock,
delay_write->pageoff,
start_page);
-#endif
if (retval != STATUS_SUCCESS) {
set_sense_type(chip, lun,
SENSE_TYPE_MEDIA_WRITE_ERR);
@@ -2198,7 +2086,7 @@ void xd_cleanup_work(struct rts51x_chip *chip)
}
}
-int xd_power_off_card3v3(struct rts51x_chip *chip)
+static int xd_power_off_card3v3(struct rts51x_chip *chip)
{
int retval;
@@ -2232,7 +2120,7 @@ int release_xd_card(struct rts51x_chip *chip)
struct xd_info *xd_card = &(chip->xd_card);
int retval;
- RTS51X_DEBUGP("elease_xd_card\n");
+ RTS51X_DEBUGP("release_xd_card\n");
chip->card_ready &= ~XD_CARD;
chip->card_fail &= ~XD_CARD;
diff --git a/drivers/staging/rts5139/xd.h b/drivers/staging/rts5139/xd.h
index fa695903ba65..55e4205e23fa 100644
--- a/drivers/staging/rts5139/xd.h
+++ b/drivers/staging/rts5139/xd.h
@@ -182,12 +182,10 @@
#define CIS1_9 (256 + 9)
int reset_xd_card(struct rts51x_chip *chip);
-int xd_delay_write(struct rts51x_chip *chip);
int xd_rw(struct scsi_cmnd *srb, struct rts51x_chip *chip, u32 start_sector,
u16 sector_cnt);
void xd_free_l2p_tbl(struct rts51x_chip *chip);
void xd_cleanup_work(struct rts51x_chip *chip);
-int xd_power_off_card3v3(struct rts51x_chip *chip);
int release_xd_card(struct rts51x_chip *chip);
#endif /* __RTS51X_XD_H */
diff --git a/drivers/staging/rts_pstor/ms.c b/drivers/staging/rts_pstor/ms.c
index f9a4498984cc..0bf6d95b3fab 100644
--- a/drivers/staging/rts_pstor/ms.c
+++ b/drivers/staging/rts_pstor/ms.c
@@ -4136,7 +4136,7 @@ int mg_set_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip)
#else
retval = ms_transfer_data(chip, MS_TM_AUTO_WRITE, PRO_WRITE_LONG_DATA,
2, WAIT_INT, 0, 0, buf + 4, 1024);
- if ((retval != STATUS_SUCCESS) || check_ms_err(chip) {
+ if ((retval != STATUS_SUCCESS) || check_ms_err(chip)) {
rtsx_clear_ms_error(chip);
if (ms_card->mg_auth == 0) {
if ((buf[5] & 0xC0) != 0) {
diff --git a/drivers/staging/rts_pstor/rtsx_transport.c b/drivers/staging/rts_pstor/rtsx_transport.c
index 9b2e5c99870f..54a474235f26 100644
--- a/drivers/staging/rts_pstor/rtsx_transport.c
+++ b/drivers/staging/rts_pstor/rtsx_transport.c
@@ -130,7 +130,7 @@ unsigned int rtsx_stor_access_xfer_buf(unsigned char *buffer,
/* Store the contents of buffer into srb's transfer buffer and set the
* SCSI residue. */
void rtsx_stor_set_xfer_buf(unsigned char *buffer,
- unsigned int buflen, struct scsi_cmnd *srb)
+ unsigned int buflen, struct scsi_cmnd *srb)
{
unsigned int index = 0, offset = 0;
@@ -141,7 +141,7 @@ void rtsx_stor_set_xfer_buf(unsigned char *buffer,
}
void rtsx_stor_get_xfer_buf(unsigned char *buffer,
- unsigned int buflen, struct scsi_cmnd *srb)
+ unsigned int buflen, struct scsi_cmnd *srb)
{
unsigned int index = 0, offset = 0;
diff --git a/drivers/staging/sep/sep_driver_config.h b/drivers/staging/sep/sep_driver_config.h
index fa7c0d09bfa5..9d9fc7c94a6e 100644
--- a/drivers/staging/sep/sep_driver_config.h
+++ b/drivers/staging/sep/sep_driver_config.h
@@ -68,11 +68,11 @@
#define SEP_DRIVER_MIN_DATA_SIZE_PER_TABLE 16
/* flag that signifies tah the lock is
-currently held by the proccess (struct file) */
+currently held by the process (struct file) */
#define SEP_DRIVER_OWN_LOCK_FLAG 1
/* flag that signifies tah the lock is currently NOT
-held by the proccess (struct file) */
+held by the process (struct file) */
#define SEP_DRIVER_DISOWN_LOCK_FLAG 0
/* indicates whether driver has mapped/unmapped shared area */
@@ -280,7 +280,7 @@ held by the proccess (struct file) */
/*
* Used to limit number of concurrent processes
- * allowed to allocte dynamic buffers in fastcall
+ * allowed to allocate dynamic buffers in fastcall
* interface.
*/
#define SEP_DOUBLEBUF_USERS_LIMIT 3
diff --git a/drivers/staging/sep/sep_main.c b/drivers/staging/sep/sep_main.c
index f1701bc6e312..df1d13e96fcd 100644
--- a/drivers/staging/sep/sep_main.c
+++ b/drivers/staging/sep/sep_main.c
@@ -786,7 +786,7 @@ static unsigned int sep_poll(struct file *filp, poll_table *wait)
"[PID%d] poll: send_ct is %lx reply ct is %lx\n",
current->pid, sep->send_ct, sep->reply_ct);
- /* Check if error occured during poll */
+ /* Check if error occurred during poll */
retval2 = sep_read_reg(sep, HW_HOST_SEP_HOST_GPR3_REG_ADDR);
if ((retval2 != 0x0) && (retval2 != 0x8)) {
dev_dbg(&sep->pdev->dev, "[PID%d] poll; poll error %x\n",
@@ -1160,7 +1160,7 @@ static int sep_lock_kernel_pages(struct sep_device *sep,
/* Put mapped kernel sg into kernel resource array */
- /* Set output params acording to the in_out flag */
+ /* Set output params according to the in_out flag */
if (in_out_flag == SEP_DRIVER_IN_FLAG) {
*lli_array_ptr = lli_array;
dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_num_pages =
@@ -1358,7 +1358,7 @@ static int sep_lock_user_pages(struct sep_device *sep,
lli_array[num_pages - 1].block_size);
}
- /* Set output params acording to the in_out flag */
+ /* Set output params according to the in_out flag */
if (in_out_flag == SEP_DRIVER_IN_FLAG) {
*lli_array_ptr = lli_array;
dma_ctx->dma_res_arr[dma_ctx->nr_dcb_creat].in_num_pages =
@@ -2038,7 +2038,7 @@ static int sep_prepare_input_dma_table(struct sep_device *sep,
/*
* If this is not the last table -
- * then allign it to the block size
+ * then align it to the block size
*/
if (!last_table_flag)
table_data_size =
@@ -3033,7 +3033,7 @@ static int sep_free_dcb_handler(struct sep_device *sep,
* @cmd: command
* @arg: pointer to argument structure
*
- * Implement the ioctl methods availble on the SEP device.
+ * Implement the ioctl methods available on the SEP device.
*/
static long sep_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
@@ -4460,7 +4460,7 @@ static int sep_pm_runtime_suspend(struct device *dev)
* @sep_pm_runtime_resume: resume- no communication with cpu & main memory
* @sep_pm_runtime_suspend: suspend- no communication with cpu & main memory
* @sep_pci_suspend: suspend - main memory is still ON
- * @sep_pci_resume: resume - main meory is still ON
+ * @sep_pci_resume: resume - main memory is still ON
*/
static const struct dev_pm_ops sep_pm = {
.runtime_resume = sep_pm_runtime_resume,
diff --git a/drivers/staging/serial/68360serial.c b/drivers/staging/serial/68360serial.c
deleted file mode 100644
index daf0b1d0dc28..000000000000
--- a/drivers/staging/serial/68360serial.c
+++ /dev/null
@@ -1,2979 +0,0 @@
-/*
- * UART driver for 68360 CPM SCC or SMC
- * Copyright (c) 2000 D. Jeff Dionne <jeff@uclinux.org>,
- * Copyright (c) 2000 Michael Leslie <mleslie@lineo.ca>
- * Copyright (c) 1997 Dan Malek <dmalek@jlc.net>
- *
- * I used the serial.c driver as the framework for this driver.
- * Give credit to those guys.
- * The original code was written for the MBX860 board. I tried to make
- * it generic, but there may be some assumptions in the structures that
- * have to be fixed later.
- * To save porting time, I did not bother to change any object names
- * that are not accessed outside of this file.
- * It still needs lots of work........When it was easy, I included code
- * to support the SCCs, but this has never been tested, nor is it complete.
- * Only the SCCs support modem control, so that is not complete either.
- *
- * This module exports the following rs232 io functions:
- *
- * int rs_360_init(void);
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/serialP.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <asm/irq.h>
-#include <asm/m68360.h>
-#include <asm/commproc.h>
-
-
-#ifdef CONFIG_KGDB
-extern void breakpoint(void);
-extern void set_debug_traps(void);
-extern int kgdb_output_string (const char* s, unsigned int count);
-#endif
-
-
-/* #ifdef CONFIG_SERIAL_CONSOLE */ /* This seems to be a post 2.0 thing - mles */
-#include <linux/console.h>
-#include <linux/jiffies.h>
-
-/* this defines the index into rs_table for the port to use
- */
-#ifndef CONFIG_SERIAL_CONSOLE_PORT
-#define CONFIG_SERIAL_CONSOLE_PORT 1 /* ie SMC2 - note USE_SMC2 must be defined */
-#endif
-/* #endif */
-
-#if 0
-/* SCC2 for console
- */
-#undef CONFIG_SERIAL_CONSOLE_PORT
-#define CONFIG_SERIAL_CONSOLE_PORT 2
-#endif
-
-
-#define TX_WAKEUP ASYNC_SHARE_IRQ
-
-static char *serial_name = "CPM UART driver";
-static char *serial_version = "0.03";
-
-static struct tty_driver *serial_driver;
-int serial_console_setup(struct console *co, char *options);
-
-/*
- * Serial driver configuration section. Here are the various options:
- */
-#define SERIAL_PARANOIA_CHECK
-#define CONFIG_SERIAL_NOPAUSE_IO
-#define SERIAL_DO_RESTART
-
-/* Set of debugging defines */
-
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-
-#define _INLINE_ inline
-
-#define DBG_CNT(s)
-
-/* We overload some of the items in the data structure to meet our
- * needs. For example, the port address is the CPM parameter ram
- * offset for the SCC or SMC. The maximum number of ports is 4 SCCs and
- * 2 SMCs. The "hub6" field is used to indicate the channel number, with
- * a flag indicating SCC or SMC, and the number is used as an index into
- * the CPM parameter area for this device.
- * The "type" field is currently set to 0, for PORT_UNKNOWN. It is
- * not currently used. I should probably use it to indicate the port
- * type of SMC or SCC.
- * The SMCs do not support any modem control signals.
- */
-#define smc_scc_num hub6
-#define NUM_IS_SCC ((int)0x00010000)
-#define PORT_NUM(P) ((P) & 0x0000ffff)
-
-
-#if defined (CONFIG_UCQUICC)
-
-volatile extern void *_periph_base;
-/* sipex transceiver
- * mode bits for are on pins
- *
- * SCC2 d16..19
- * SCC3 d20..23
- * SCC4 d24..27
- */
-#define SIPEX_MODE(n,m) ((m & 0x0f)<<(16+4*(n-1)))
-
-static uint sipex_mode_bits = 0x00000000;
-
-#endif
-
-/* There is no `serial_state' defined back here in 2.0.
- * Try to get by with serial_struct
- */
-/* #define serial_state serial_struct */
-
-/* 2.4 -> 2.0 portability problem: async_icount in 2.4 has a few
- * extras: */
-
-#if 0
-struct async_icount_24 {
- __u32 cts, dsr, rng, dcd, tx, rx;
- __u32 frame, parity, overrun, brk;
- __u32 buf_overrun;
-} icount;
-#endif
-
-#if 0
-
-struct serial_state {
- int magic;
- int baud_base;
- unsigned long port;
- int irq;
- int flags;
- int hub6;
- int type;
- int line;
- int revision; /* Chip revision (950) */
- int xmit_fifo_size;
- int custom_divisor;
- int count;
- u8 *iomem_base;
- u16 iomem_reg_shift;
- unsigned short close_delay;
- unsigned short closing_wait; /* time to wait before closing */
- struct async_icount_24 icount;
- int io_type;
- struct async_struct *info;
-};
-#endif
-
-#define SSTATE_MAGIC 0x5302
-
-
-
-/* SMC2 is sometimes used for low performance TDM interfaces. Define
- * this as 1 if you want SMC2 as a serial port UART managed by this driver.
- * Define this as 0 if you wish to use SMC2 for something else.
- */
-#define USE_SMC2 1
-
-#if 0
-/* Define SCC to ttySx mapping. */
-#define SCC_NUM_BASE (USE_SMC2 + 1) /* SCC base tty "number" */
-
-/* Define which SCC is the first one to use for a serial port. These
- * are 0-based numbers, i.e. this assumes the first SCC (SCC1) is used
- * for Ethernet, and the first available SCC for serial UART is SCC2.
- * NOTE: IF YOU CHANGE THIS, you have to change the PROFF_xxx and
- * interrupt vectors in the table below to match.
- */
-#define SCC_IDX_BASE 1 /* table index */
-#endif
-
-
-/* Processors other than the 860 only get SMCs configured by default.
- * Either they don't have SCCs or they are allocated somewhere else.
- * Of course, there are now 860s without some SCCs, so we will need to
- * address that someday.
- * The Embedded Planet Multimedia I/O cards use TDM interfaces to the
- * stereo codec parts, and we use SMC2 to help support that.
- */
-static struct serial_state rs_table[] = {
-/* type line PORT IRQ FLAGS smc_scc_num (F.K.A. hub6) */
- { 0, 0, PRSLOT_SMC1, CPMVEC_SMC1, 0, 0 } /* SMC1 ttyS0 */
-#if USE_SMC2
- ,{ 0, 0, PRSLOT_SMC2, CPMVEC_SMC2, 0, 1 } /* SMC2 ttyS1 */
-#endif
-
-#if defined(CONFIG_SERIAL_68360_SCC)
- ,{ 0, 0, PRSLOT_SCC2, CPMVEC_SCC2, 0, (NUM_IS_SCC | 1) } /* SCC2 ttyS2 */
- ,{ 0, 0, PRSLOT_SCC3, CPMVEC_SCC3, 0, (NUM_IS_SCC | 2) } /* SCC3 ttyS3 */
- ,{ 0, 0, PRSLOT_SCC4, CPMVEC_SCC4, 0, (NUM_IS_SCC | 3) } /* SCC4 ttyS4 */
-#endif
-};
-
-#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state))
-
-/* The number of buffer descriptors and their sizes.
- */
-#define RX_NUM_FIFO 4
-#define RX_BUF_SIZE 32
-#define TX_NUM_FIFO 4
-#define TX_BUF_SIZE 32
-
-#define CONSOLE_NUM_FIFO 2
-#define CONSOLE_BUF_SIZE 4
-
-char *console_fifos[CONSOLE_NUM_FIFO * CONSOLE_BUF_SIZE];
-
-/* The async_struct in serial.h does not really give us what we
- * need, so define our own here.
- */
-typedef struct serial_info {
- int magic;
- int flags;
-
- struct serial_state *state;
- /* struct serial_struct *state; */
- /* struct async_struct *state; */
-
- struct tty_struct *tty;
- int read_status_mask;
- int ignore_status_mask;
- int timeout;
- int line;
- int x_char; /* xon/xoff character */
- int close_delay;
- unsigned short closing_wait;
- unsigned short closing_wait2;
- unsigned long event;
- unsigned long last_active;
- int blocked_open; /* # of blocked opens */
- struct work_struct tqueue;
- struct work_struct tqueue_hangup;
- wait_queue_head_t open_wait;
- wait_queue_head_t close_wait;
-
-
-/* CPM Buffer Descriptor pointers.
- */
- QUICC_BD *rx_bd_base;
- QUICC_BD *rx_cur;
- QUICC_BD *tx_bd_base;
- QUICC_BD *tx_cur;
-} ser_info_t;
-
-
-/* since kmalloc_init() does not get called until much after this initialization: */
-static ser_info_t quicc_ser_info[NR_PORTS];
-static char rx_buf_pool[NR_PORTS * RX_NUM_FIFO * RX_BUF_SIZE];
-static char tx_buf_pool[NR_PORTS * TX_NUM_FIFO * TX_BUF_SIZE];
-
-static void change_speed(ser_info_t *info);
-static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout);
-
-static inline int serial_paranoia_check(ser_info_t *info,
- char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
- static const char *badmagic =
- "Warning: bad magic number for serial struct (%s) in %s\n";
- static const char *badinfo =
- "Warning: null async_struct for (%s) in %s\n";
-
- if (!info) {
- printk(badinfo, name, routine);
- return 1;
- }
- if (info->magic != SERIAL_MAGIC) {
- printk(badmagic, name, routine);
- return 1;
- }
-#endif
- return 0;
-}
-
-/*
- * This is used to figure out the divisor speeds and the timeouts,
- * indexed by the termio value. The generic CPM functions are responsible
- * for setting and assigning baud rate generators for us.
- */
-static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
-
-/* This sucks. There is a better way: */
-#if defined(CONFIG_CONSOLE_9600)
- #define CONSOLE_BAUDRATE 9600
-#elif defined(CONFIG_CONSOLE_19200)
- #define CONSOLE_BAUDRATE 19200
-#elif defined(CONFIG_CONSOLE_115200)
- #define CONSOLE_BAUDRATE 115200
-#else
- #warning "console baud rate undefined"
- #define CONSOLE_BAUDRATE 9600
-#endif
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * They enable or disable transmitter interrupts, as necessary.
- * ------------------------------------------------------------
- */
-static void rs_360_stop(struct tty_struct *tty)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- int idx;
- unsigned long flags;
- volatile struct scc_regs *sccp;
- volatile struct smc_regs *smcp;
-
- if (serial_paranoia_check(info, tty->name, "rs_stop"))
- return;
-
- local_irq_save(flags);
- idx = PORT_NUM(info->state->smc_scc_num);
- if (info->state->smc_scc_num & NUM_IS_SCC) {
- sccp = &pquicc->scc_regs[idx];
- sccp->scc_sccm &= ~UART_SCCM_TX;
- } else {
- /* smcp = &cpmp->cp_smc[idx]; */
- smcp = &pquicc->smc_regs[idx];
- smcp->smc_smcm &= ~SMCM_TX;
- }
- local_irq_restore(flags);
-}
-
-
-static void rs_360_start(struct tty_struct *tty)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- int idx;
- unsigned long flags;
- volatile struct scc_regs *sccp;
- volatile struct smc_regs *smcp;
-
- if (serial_paranoia_check(info, tty->name, "rs_stop"))
- return;
-
- local_irq_save(flags);
- idx = PORT_NUM(info->state->smc_scc_num);
- if (info->state->smc_scc_num & NUM_IS_SCC) {
- sccp = &pquicc->scc_regs[idx];
- sccp->scc_sccm |= UART_SCCM_TX;
- } else {
- smcp = &pquicc->smc_regs[idx];
- smcp->smc_smcm |= SMCM_TX;
- }
- local_irq_restore(flags);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Here starts the interrupt handling routines. All of the following
- * subroutines are declared as inline and are folded into
- * rs_interrupt(). They were separated out for readability's sake.
- *
- * Note: rs_interrupt() is a "fast" interrupt, which means that it
- * runs with interrupts turned off. People who may want to modify
- * rs_interrupt() should try to keep the interrupt handler as fast as
- * possible. After you are done making modifications, it is not a bad
- * idea to do:
- *
- * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
- *
- * and look at the resulting assemble code in serial.s.
- *
- * - Ted Ts'o (tytso@mit.edu), 7-Mar-93
- * -----------------------------------------------------------------------
- */
-
-static _INLINE_ void receive_chars(ser_info_t *info)
-{
- struct tty_struct *tty = info->port.tty;
- unsigned char ch, flag, *cp;
- /*int ignored = 0;*/
- int i;
- ushort status;
- struct async_icount *icount;
- /* struct async_icount_24 *icount; */
- volatile QUICC_BD *bdp;
-
- icount = &info->state->icount;
-
- /* Just loop through the closed BDs and copy the characters into
- * the buffer.
- */
- bdp = info->rx_cur;
- for (;;) {
- if (bdp->status & BD_SC_EMPTY) /* If this one is empty */
- break; /* we are all done */
-
- /* The read status mask tell us what we should do with
- * incoming characters, especially if errors occur.
- * One special case is the use of BD_SC_EMPTY. If
- * this is not set, we are supposed to be ignoring
- * inputs. In this case, just mark the buffer empty and
- * continue.
- */
- if (!(info->read_status_mask & BD_SC_EMPTY)) {
- bdp->status |= BD_SC_EMPTY;
- bdp->status &=
- ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
-
- if (bdp->status & BD_SC_WRAP)
- bdp = info->rx_bd_base;
- else
- bdp++;
- continue;
- }
-
- /* Get the number of characters and the buffer pointer.
- */
- i = bdp->length;
- /* cp = (unsigned char *)__va(bdp->buf); */
- cp = (char *)bdp->buf;
- status = bdp->status;
-
- while (i-- > 0) {
- ch = *cp++;
- icount->rx++;
-
-#ifdef SERIAL_DEBUG_INTR
- printk("DR%02x:%02x...", ch, status);
-#endif
- flag = TTY_NORMAL;
-
- if (status & (BD_SC_BR | BD_SC_FR |
- BD_SC_PR | BD_SC_OV)) {
- /*
- * For statistics only
- */
- if (status & BD_SC_BR)
- icount->brk++;
- else if (status & BD_SC_PR)
- icount->parity++;
- else if (status & BD_SC_FR)
- icount->frame++;
- if (status & BD_SC_OV)
- icount->overrun++;
-
- /*
- * Now check to see if character should be
- * ignored, and mask off conditions which
- * should be ignored.
- if (status & info->ignore_status_mask) {
- if (++ignored > 100)
- break;
- continue;
- }
- */
- status &= info->read_status_mask;
-
- if (status & (BD_SC_BR)) {
-#ifdef SERIAL_DEBUG_INTR
- printk("handling break....");
-#endif
- *tty->flip.flag_buf_ptr = TTY_BREAK;
- if (info->flags & ASYNC_SAK)
- do_SAK(tty);
- } else if (status & BD_SC_PR)
- flag = TTY_PARITY;
- else if (status & BD_SC_FR)
- flag = TTY_FRAME;
- }
- tty_insert_flip_char(tty, ch, flag);
- if (status & BD_SC_OV)
- /*
- * Overrun is special, since it's
- * reported immediately, and doesn't
- * affect the current character
- */
- tty_insert_flip_char(tty, 0, TTY_OVERRUN);
- }
-
- /* This BD is ready to be used again. Clear status.
- * Get next BD.
- */
- bdp->status |= BD_SC_EMPTY;
- bdp->status &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
-
- if (bdp->status & BD_SC_WRAP)
- bdp = info->rx_bd_base;
- else
- bdp++;
- }
-
- info->rx_cur = (QUICC_BD *)bdp;
-
- tty_schedule_flip(tty);
-}
-
-static _INLINE_ void receive_break(ser_info_t *info)
-{
- struct tty_struct *tty = info->port.tty;
-
- info->state->icount.brk++;
- /* Check to see if there is room in the tty buffer for
- * the break. If not, we exit now, losing the break. FIXME
- */
- tty_insert_flip_char(tty, 0, TTY_BREAK);
- tty_schedule_flip(tty);
-}
-
-static _INLINE_ void transmit_chars(ser_info_t *info)
-{
-
- if ((info->flags & TX_WAKEUP) ||
- (info->port.tty->flags & (1 << TTY_DO_WRITE_WAKEUP))) {
- schedule_work(&info->tqueue);
- }
-
-#ifdef SERIAL_DEBUG_INTR
- printk("THRE...");
-#endif
-}
-
-#ifdef notdef
- /* I need to do this for the SCCs, so it is left as a reminder.
- */
-static _INLINE_ void check_modem_status(struct async_struct *info)
-{
- int status;
- /* struct async_icount *icount; */
- struct async_icount_24 *icount;
-
- status = serial_in(info, UART_MSR);
-
- if (status & UART_MSR_ANY_DELTA) {
- icount = &info->state->icount;
- /* update input line counters */
- if (status & UART_MSR_TERI)
- icount->rng++;
- if (status & UART_MSR_DDSR)
- icount->dsr++;
- if (status & UART_MSR_DDCD) {
- icount->dcd++;
-#ifdef CONFIG_HARD_PPS
- if ((info->flags & ASYNC_HARDPPS_CD) &&
- (status & UART_MSR_DCD))
- hardpps();
-#endif
- }
- if (status & UART_MSR_DCTS)
- icount->cts++;
- wake_up_interruptible(&info->delta_msr_wait);
- }
-
- if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
-#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
- printk("ttys%d CD now %s...", info->line,
- (status & UART_MSR_DCD) ? "on" : "off");
-#endif
- if (status & UART_MSR_DCD)
- wake_up_interruptible(&info->open_wait);
- else {
-#ifdef SERIAL_DEBUG_OPEN
- printk("scheduling hangup...");
-#endif
- queue_task(&info->tqueue_hangup,
- &tq_scheduler);
- }
- }
- if (info->flags & ASYNC_CTS_FLOW) {
- if (info->port.tty->hw_stopped) {
- if (status & UART_MSR_CTS) {
-#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
- printk("CTS tx start...");
-#endif
- info->port.tty->hw_stopped = 0;
- info->IER |= UART_IER_THRI;
- serial_out(info, UART_IER, info->IER);
- rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
- return;
- }
- } else {
- if (!(status & UART_MSR_CTS)) {
-#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
- printk("CTS tx stop...");
-#endif
- info->port.tty->hw_stopped = 1;
- info->IER &= ~UART_IER_THRI;
- serial_out(info, UART_IER, info->IER);
- }
- }
- }
-}
-#endif
-
-/*
- * This is the serial driver's interrupt routine for a single port
- */
-/* static void rs_360_interrupt(void *dev_id) */ /* until and if we start servicing irqs here */
-static void rs_360_interrupt(int vec, void *dev_id)
-{
- u_char events;
- int idx;
- ser_info_t *info;
- volatile struct smc_regs *smcp;
- volatile struct scc_regs *sccp;
-
- info = dev_id;
-
- idx = PORT_NUM(info->state->smc_scc_num);
- if (info->state->smc_scc_num & NUM_IS_SCC) {
- sccp = &pquicc->scc_regs[idx];
- events = sccp->scc_scce;
- if (events & SCCM_RX)
- receive_chars(info);
- if (events & SCCM_TX)
- transmit_chars(info);
- sccp->scc_scce = events;
- } else {
- smcp = &pquicc->smc_regs[idx];
- events = smcp->smc_smce;
- if (events & SMCM_BRKE)
- receive_break(info);
- if (events & SMCM_RX)
- receive_chars(info);
- if (events & SMCM_TX)
- transmit_chars(info);
- smcp->smc_smce = events;
- }
-
-#ifdef SERIAL_DEBUG_INTR
- printk("rs_interrupt_single(%d, %x)...",
- info->state->smc_scc_num, events);
-#endif
-#ifdef modem_control
- check_modem_status(info);
-#endif
- info->last_active = jiffies;
-#ifdef SERIAL_DEBUG_INTR
- printk("end.\n");
-#endif
-}
-
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-
-static void do_softint(void *private_)
-{
- ser_info_t *info = (ser_info_t *) private_;
- struct tty_struct *tty;
-
- tty = info->port.tty;
- if (!tty)
- return;
-
- if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event))
- tty_wakeup(tty);
-}
-
-
-/*
- * This routine is called from the scheduler tqueue when the interrupt
- * routine has signalled that a hangup has occurred. The path of
- * hangup processing is:
- *
- * serial interrupt routine -> (scheduler tqueue) ->
- * do_serial_hangup() -> tty->hangup() -> rs_hangup()
- *
- */
-static void do_serial_hangup(void *private_)
-{
- struct async_struct *info = (struct async_struct *) private_;
- struct tty_struct *tty;
-
- tty = info->port.tty;
- if (!tty)
- return;
-
- tty_hangup(tty);
-}
-
-
-static int startup(ser_info_t *info)
-{
- unsigned long flags;
- int retval=0;
- int idx;
- /*struct serial_state *state = info->state;*/
- volatile struct smc_regs *smcp;
- volatile struct scc_regs *sccp;
- volatile struct smc_uart_pram *up;
- volatile struct uart_pram *scup;
-
-
- local_irq_save(flags);
-
- if (info->flags & ASYNC_INITIALIZED) {
- goto errout;
- }
-
-#ifdef maybe
- if (!state->port || !state->type) {
- if (info->port.tty)
- set_bit(TTY_IO_ERROR, &info->port.tty->flags);
- goto errout;
- }
-#endif
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("starting up ttys%d (irq %d)...", info->line, state->irq);
-#endif
-
-
-#ifdef modem_control
- info->MCR = 0;
- if (info->port.tty->termios->c_cflag & CBAUD)
- info->MCR = UART_MCR_DTR | UART_MCR_RTS;
-#endif
-
- if (info->port.tty)
- clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
-
- /*
- * and set the speed of the serial port
- */
- change_speed(info);
-
- idx = PORT_NUM(info->state->smc_scc_num);
- if (info->state->smc_scc_num & NUM_IS_SCC) {
- sccp = &pquicc->scc_regs[idx];
- scup = &pquicc->pram[info->state->port].scc.pscc.u;
-
- scup->mrblr = RX_BUF_SIZE;
- scup->max_idl = RX_BUF_SIZE;
-
- sccp->scc_sccm |= (UART_SCCM_TX | UART_SCCM_RX);
- sccp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-
- } else {
- smcp = &pquicc->smc_regs[idx];
-
- /* Enable interrupts and I/O.
- */
- smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
- smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN);
-
- /* We can tune the buffer length and idle characters
- * to take advantage of the entire incoming buffer size.
- * If mrblr is something other than 1, maxidl has to be
- * non-zero or we never get an interrupt. The maxidl
- * is the number of character times we wait after reception
- * of the last character before we decide no more characters
- * are coming.
- */
- /* up = (smc_uart_t *)&pquicc->cp_dparam[state->port]; */
- /* holy unionized structures, Batman: */
- up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
-
- up->mrblr = RX_BUF_SIZE;
- up->max_idl = RX_BUF_SIZE;
-
- up->brkcr = 1; /* number of break chars */
- }
-
- info->flags |= ASYNC_INITIALIZED;
- local_irq_restore(flags);
- return 0;
-
-errout:
- local_irq_restore(flags);
- return retval;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void shutdown(ser_info_t *info)
-{
- unsigned long flags;
- struct serial_state *state;
- int idx;
- volatile struct smc_regs *smcp;
- volatile struct scc_regs *sccp;
-
- if (!(info->flags & ASYNC_INITIALIZED))
- return;
-
- state = info->state;
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("Shutting down serial port %d (irq %d)....", info->line,
- state->irq);
-#endif
-
- local_irq_save(flags);
-
- idx = PORT_NUM(state->smc_scc_num);
- if (state->smc_scc_num & NUM_IS_SCC) {
- sccp = &pquicc->scc_regs[idx];
- sccp->scc_gsmr.w.low &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-#ifdef CONFIG_SERIAL_CONSOLE
- /* We can't disable the transmitter if this is the
- * system console.
- */
- if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT)
-#endif
- sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
- } else {
- smcp = &pquicc->smc_regs[idx];
-
- /* Disable interrupts and I/O.
- */
- smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
-#ifdef CONFIG_SERIAL_CONSOLE
- /* We can't disable the transmitter if this is the
- * system console.
- */
- if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT)
-#endif
- smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
- }
-
- if (info->port.tty)
- set_bit(TTY_IO_ERROR, &info->port.tty->flags);
-
- info->flags &= ~ASYNC_INITIALIZED;
- local_irq_restore(flags);
-}
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void change_speed(ser_info_t *info)
-{
- int baud_rate;
- unsigned cflag, cval, scval, prev_mode;
- int i, bits, sbits, idx;
- unsigned long flags;
- struct serial_state *state;
- volatile struct smc_regs *smcp;
- volatile struct scc_regs *sccp;
-
- if (!info->port.tty || !info->port.tty->termios)
- return;
- cflag = info->port.tty->termios->c_cflag;
-
- state = info->state;
-
- /* Character length programmed into the mode register is the
- * sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
- * 1 or 2 stop bits, minus 1.
- * The value 'bits' counts this for us.
- */
- cval = 0;
- scval = 0;
-
- /* byte size and parity */
- switch (cflag & CSIZE) {
- case CS5: bits = 5; break;
- case CS6: bits = 6; break;
- case CS7: bits = 7; break;
- case CS8: bits = 8; break;
- /* Never happens, but GCC is too dumb to figure it out */
- default: bits = 8; break;
- }
- sbits = bits - 5;
-
- if (cflag & CSTOPB) {
- cval |= SMCMR_SL; /* Two stops */
- scval |= SCU_PMSR_SL;
- bits++;
- }
- if (cflag & PARENB) {
- cval |= SMCMR_PEN;
- scval |= SCU_PMSR_PEN;
- bits++;
- }
- if (!(cflag & PARODD)) {
- cval |= SMCMR_PM_EVEN;
- scval |= (SCU_PMSR_REVP | SCU_PMSR_TEVP);
- }
-
- /* Determine divisor based on baud rate */
- i = cflag & CBAUD;
- if (i >= (sizeof(baud_table)/sizeof(int)))
- baud_rate = 9600;
- else
- baud_rate = baud_table[i];
-
- info->timeout = (TX_BUF_SIZE*HZ*bits);
- info->timeout += HZ/50; /* Add .02 seconds of slop */
-
-#ifdef modem_control
- /* CTS flow control flag and modem status interrupts */
- info->IER &= ~UART_IER_MSI;
- if (info->flags & ASYNC_HARDPPS_CD)
- info->IER |= UART_IER_MSI;
- if (cflag & CRTSCTS) {
- info->flags |= ASYNC_CTS_FLOW;
- info->IER |= UART_IER_MSI;
- } else
- info->flags &= ~ASYNC_CTS_FLOW;
- if (cflag & CLOCAL)
- info->flags &= ~ASYNC_CHECK_CD;
- else {
- info->flags |= ASYNC_CHECK_CD;
- info->IER |= UART_IER_MSI;
- }
- serial_out(info, UART_IER, info->IER);
-#endif
-
- /*
- * Set up parity check flag
- */
- info->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
- if (I_INPCK(info->port.tty))
- info->read_status_mask |= BD_SC_FR | BD_SC_PR;
- if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty))
- info->read_status_mask |= BD_SC_BR;
-
- /*
- * Characters to ignore
- */
- info->ignore_status_mask = 0;
- if (I_IGNPAR(info->port.tty))
- info->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
- if (I_IGNBRK(info->port.tty)) {
- info->ignore_status_mask |= BD_SC_BR;
- /*
- * If we're ignore parity and break indicators, ignore
- * overruns too. (For real raw support).
- */
- if (I_IGNPAR(info->port.tty))
- info->ignore_status_mask |= BD_SC_OV;
- }
- /*
- * !!! ignore all characters if CREAD is not set
- */
- if ((cflag & CREAD) == 0)
- info->read_status_mask &= ~BD_SC_EMPTY;
- local_irq_save(flags);
-
- /* Start bit has not been added (so don't, because we would just
- * subtract it later), and we need to add one for the number of
- * stops bits (there is always at least one).
- */
- bits++;
- idx = PORT_NUM(state->smc_scc_num);
- if (state->smc_scc_num & NUM_IS_SCC) {
- sccp = &pquicc->scc_regs[idx];
- sccp->scc_psmr = (sbits << 12) | scval;
- } else {
- smcp = &pquicc->smc_regs[idx];
-
- /* Set the mode register. We want to keep a copy of the
- * enables, because we want to put them back if they were
- * present.
- */
- prev_mode = smcp->smc_smcmr;
- smcp->smc_smcmr = smcr_mk_clen(bits) | cval | SMCMR_SM_UART;
- smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN));
- }
-
- m360_cpm_setbrg((state - rs_table), baud_rate);
-
- local_irq_restore(flags);
-}
-
-static void rs_360_put_char(struct tty_struct *tty, unsigned char ch)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- volatile QUICC_BD *bdp;
-
- if (serial_paranoia_check(info, tty->name, "rs_put_char"))
- return 0;
-
- if (!tty)
- return 0;
-
- bdp = info->tx_cur;
- while (bdp->status & BD_SC_READY);
-
- /* *((char *)__va(bdp->buf)) = ch; */
- *((char *)bdp->buf) = ch;
- bdp->length = 1;
- bdp->status |= BD_SC_READY;
-
- /* Get next BD.
- */
- if (bdp->status & BD_SC_WRAP)
- bdp = info->tx_bd_base;
- else
- bdp++;
-
- info->tx_cur = (QUICC_BD *)bdp;
- return 1;
-
-}
-
-static int rs_360_write(struct tty_struct * tty,
- const unsigned char *buf, int count)
-{
- int c, ret = 0;
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- volatile QUICC_BD *bdp;
-
-#ifdef CONFIG_KGDB
- /* Try to let stub handle output. Returns true if it did. */
- if (kgdb_output_string(buf, count))
- return ret;
-#endif
-
- if (serial_paranoia_check(info, tty->name, "rs_write"))
- return 0;
-
- if (!tty)
- return 0;
-
- bdp = info->tx_cur;
-
- while (1) {
- c = min(count, TX_BUF_SIZE);
-
- if (c <= 0)
- break;
-
- if (bdp->status & BD_SC_READY) {
- info->flags |= TX_WAKEUP;
- break;
- }
-
- /* memcpy(__va(bdp->buf), buf, c); */
- memcpy((void *)bdp->buf, buf, c);
-
- bdp->length = c;
- bdp->status |= BD_SC_READY;
-
- buf += c;
- count -= c;
- ret += c;
-
- /* Get next BD.
- */
- if (bdp->status & BD_SC_WRAP)
- bdp = info->tx_bd_base;
- else
- bdp++;
- info->tx_cur = (QUICC_BD *)bdp;
- }
- return ret;
-}
-
-static int rs_360_write_room(struct tty_struct *tty)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- int ret;
-
- if (serial_paranoia_check(info, tty->name, "rs_write_room"))
- return 0;
-
- if ((info->tx_cur->status & BD_SC_READY) == 0) {
- info->flags &= ~TX_WAKEUP;
- ret = TX_BUF_SIZE;
- }
- else {
- info->flags |= TX_WAKEUP;
- ret = 0;
- }
- return ret;
-}
-
-/* I could track this with transmit counters....maybe later.
-*/
-static int rs_360_chars_in_buffer(struct tty_struct *tty)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
- return 0;
- return 0;
-}
-
-static void rs_360_flush_buffer(struct tty_struct *tty)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
- return;
-
- /* There is nothing to "flush", whatever we gave the CPM
- * is on its way out.
- */
- tty_wakeup(tty);
- info->flags &= ~TX_WAKEUP;
-}
-
-/*
- * This function is used to send a high-priority XON/XOFF character to
- * the device
- */
-static void rs_360_send_xchar(struct tty_struct *tty, char ch)
-{
- volatile QUICC_BD *bdp;
-
- ser_info_t *info = (ser_info_t *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_send_char"))
- return;
-
- bdp = info->tx_cur;
- while (bdp->status & BD_SC_READY);
-
- /* *((char *)__va(bdp->buf)) = ch; */
- *((char *)bdp->buf) = ch;
- bdp->length = 1;
- bdp->status |= BD_SC_READY;
-
- /* Get next BD.
- */
- if (bdp->status & BD_SC_WRAP)
- bdp = info->tx_bd_base;
- else
- bdp++;
-
- info->tx_cur = (QUICC_BD *)bdp;
-}
-
-/*
- * ------------------------------------------------------------
- * rs_throttle()
- *
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void rs_360_throttle(struct tty_struct * tty)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
- char buf[64];
-
- printk("throttle %s: %d....\n", _tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty));
-#endif
-
- if (serial_paranoia_check(info, tty->name, "rs_throttle"))
- return;
-
- if (I_IXOFF(tty))
- rs_360_send_xchar(tty, STOP_CHAR(tty));
-
-#ifdef modem_control
- if (tty->termios->c_cflag & CRTSCTS)
- info->MCR &= ~UART_MCR_RTS;
-
- local_irq_disable();
- serial_out(info, UART_MCR, info->MCR);
- local_irq_enable();
-#endif
-}
-
-static void rs_360_unthrottle(struct tty_struct * tty)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
-#ifdef SERIAL_DEBUG_THROTTLE
- char buf[64];
-
- printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty));
-#endif
-
- if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
- return;
-
- if (I_IXOFF(tty)) {
- if (info->x_char)
- info->x_char = 0;
- else
- rs_360_send_xchar(tty, START_CHAR(tty));
- }
-#ifdef modem_control
- if (tty->termios->c_cflag & CRTSCTS)
- info->MCR |= UART_MCR_RTS;
- local_irq_disable();
- serial_out(info, UART_MCR, info->MCR);
- local_irq_enable();
-#endif
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-#ifdef maybe
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- * is emptied. On bus types like RS485, the transmitter must
- * release the bus after transmitting. This must be done when
- * the transmit shift register is empty, not be done when the
- * transmit holding register is empty. This functionality
- * allows an RS485 driver to be written in user space.
- */
-static int get_lsr_info(struct async_struct * info, unsigned int *value)
-{
- unsigned char status;
- unsigned int result;
-
- local_irq_disable();
- status = serial_in(info, UART_LSR);
- local_irq_enable();
- result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
- return put_user(result,value);
-}
-#endif
-
-static int rs_360_tiocmget(struct tty_struct *tty)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- unsigned int result = 0;
-#ifdef modem_control
- unsigned char control, status;
-
- if (serial_paranoia_check(info, tty->name, __func__))
- return -ENODEV;
-
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
-
- control = info->MCR;
- local_irq_disable();
- status = serial_in(info, UART_MSR);
- local_irq_enable();
- result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
- | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
-#ifdef TIOCM_OUT1
- | ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0)
- | ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0)
-#endif
- | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0)
- | ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
- | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
- | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
-#endif
- return result;
-}
-
-static int rs_360_tiocmset(struct tty_struct *tty,
- unsigned int set, unsigned int clear)
-{
-#ifdef modem_control
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- unsigned int arg;
-
- if (serial_paranoia_check(info, tty->name, __func__))
- return -ENODEV;
-
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
- /* FIXME: locking on info->mcr */
- if (set & TIOCM_RTS)
- info->mcr |= UART_MCR_RTS;
- if (set & TIOCM_DTR)
- info->mcr |= UART_MCR_DTR;
- if (clear & TIOCM_RTS)
- info->MCR &= ~UART_MCR_RTS;
- if (clear & TIOCM_DTR)
- info->MCR &= ~UART_MCR_DTR;
-
-#ifdef TIOCM_OUT1
- if (set & TIOCM_OUT1)
- info->MCR |= UART_MCR_OUT1;
- if (set & TIOCM_OUT2)
- info->MCR |= UART_MCR_OUT2;
- if (clear & TIOCM_OUT1)
- info->MCR &= ~UART_MCR_OUT1;
- if (clear & TIOCM_OUT2)
- info->MCR &= ~UART_MCR_OUT2;
-#endif
-
- local_irq_disable();
- serial_out(info, UART_MCR, info->MCR);
- local_irq_enable();
-#endif
- return 0;
-}
-
-/* Sending a break is a two step process on the SMC/SCC. It is accomplished
- * by sending a STOP TRANSMIT command followed by a RESTART TRANSMIT
- * command. We take advantage of the begin/end functions to make this
- * happen.
- */
-static ushort smc_chan_map[] = {
- CPM_CR_CH_SMC1,
- CPM_CR_CH_SMC2
-};
-
-static ushort scc_chan_map[] = {
- CPM_CR_CH_SCC1,
- CPM_CR_CH_SCC2,
- CPM_CR_CH_SCC3,
- CPM_CR_CH_SCC4
-};
-
-static void begin_break(ser_info_t *info)
-{
- volatile QUICC *cp;
- ushort chan;
- int idx;
-
- cp = pquicc;
-
- idx = PORT_NUM(info->state->smc_scc_num);
- if (info->state->smc_scc_num & NUM_IS_SCC)
- chan = scc_chan_map[idx];
- else
- chan = smc_chan_map[idx];
-
- cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG;
- while (cp->cp_cr & CPM_CR_FLG);
-}
-
-static void end_break(ser_info_t *info)
-{
- volatile QUICC *cp;
- ushort chan;
- int idx;
-
- cp = pquicc;
-
- idx = PORT_NUM(info->state->smc_scc_num);
- if (info->state->smc_scc_num & NUM_IS_SCC)
- chan = scc_chan_map[idx];
- else
- chan = smc_chan_map[idx];
-
- cp->cp_cr = mk_cr_cmd(chan, CPM_CR_RESTART_TX) | CPM_CR_FLG;
- while (cp->cp_cr & CPM_CR_FLG);
-}
-
-/*
- * This routine sends a break character out the serial port.
- */
-static void send_break(ser_info_t *info, unsigned int duration)
-{
-#ifdef SERIAL_DEBUG_SEND_BREAK
- printk("rs_send_break(%d) jiff=%lu...", duration, jiffies);
-#endif
- begin_break(info);
- msleep_interruptible(duration);
- end_break(info);
-#ifdef SERIAL_DEBUG_SEND_BREAK
- printk("done jiffies=%lu\n", jiffies);
-#endif
-}
-
-
-/*
- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
- * Return: write counters to the user passed counter struct
- * NB: both 1->0 and 0->1 transitions are counted except for
- * RI where only 0->1 is counted.
- */
-static int rs_360_get_icount(struct tty_struct *tty,
- struct serial_icounter_struct *icount)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- struct async_icount cnow;
-
- local_irq_disable();
- cnow = info->state->icount;
- local_irq_enable();
-
- icount->cts = cnow.cts;
- icount->dsr = cnow.dsr;
- icount->rng = cnow.rng;
- icount->dcd = cnow.dcd;
-
- return 0;
-}
-
-static int rs_360_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- int error;
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- int retval;
- struct async_icount cnow;
- /* struct async_icount_24 cnow;*/ /* kernel counter temps */
- struct serial_icounter_struct *p_cuser; /* user space */
-
- if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
- return -ENODEV;
-
- if (cmd != TIOCMIWAIT) {
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
- }
-
- switch (cmd) {
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (signal_pending(current))
- return -EINTR;
- if (!arg) {
- send_break(info, 250); /* 1/4 second */
- if (signal_pending(current))
- return -EINTR;
- }
- return 0;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- if (signal_pending(current))
- return -EINTR;
- send_break(info, arg ? arg*100 : 250);
- if (signal_pending(current))
- return -EINTR;
- return 0;
- case TIOCSBRK:
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- tty_wait_until_sent(tty, 0);
- begin_break(info);
- return 0;
- case TIOCCBRK:
- retval = tty_check_change(tty);
- if (retval)
- return retval;
- end_break(info);
- return 0;
-#ifdef maybe
- case TIOCSERGETLSR: /* Get line status register */
- return get_lsr_info(info, (unsigned int *) arg);
-#endif
- /*
- * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
- * - mask passed in arg for lines of interest
- * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
- * Caller should use TIOCGICOUNT to see which one it was
- */
- case TIOCMIWAIT:
-#ifdef modem_control
- local_irq_disable();
- /* note the counters on entry */
- cprev = info->state->icount;
- local_irq_enable();
- while (1) {
- interruptible_sleep_on(&info->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
- local_irq_disable();
- cnow = info->state->icount; /* atomic copy */
- local_irq_enable();
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
- return 0;
- }
- cprev = cnow;
- }
- /* NOTREACHED */
-#else
- return 0;
-#endif
-
-
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-/* FIX UP modem control here someday......
-*/
-static void rs_360_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
-
- change_speed(info);
-
-#ifdef modem_control
- /* Handle transition to B0 status */
- if ((old_termios->c_cflag & CBAUD) &&
- !(tty->termios->c_cflag & CBAUD)) {
- info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
- local_irq_disable();
- serial_out(info, UART_MCR, info->MCR);
- local_irq_enable();
- }
-
- /* Handle transition away from B0 status */
- if (!(old_termios->c_cflag & CBAUD) &&
- (tty->termios->c_cflag & CBAUD)) {
- info->MCR |= UART_MCR_DTR;
- if (!tty->hw_stopped ||
- !(tty->termios->c_cflag & CRTSCTS)) {
- info->MCR |= UART_MCR_RTS;
- }
- local_irq_disable();
- serial_out(info, UART_MCR, info->MCR);
- local_irq_enable();
- }
-
- /* Handle turning off CRTSCTS */
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
- rs_360_start(tty);
- }
-#endif
-
-#if 0
- /*
- * No need to wake up processes in open wait, since they
- * sample the CLOCAL flag once, and don't recheck it.
- * XXX It's not clear whether the current behavior is correct
- * or not. Hence, this may change.....
- */
- if (!(old_termios->c_cflag & CLOCAL) &&
- (tty->termios->c_cflag & CLOCAL))
- wake_up_interruptible(&info->open_wait);
-#endif
-}
-
-/*
- * ------------------------------------------------------------
- * rs_close()
- *
- * This routine is called when the serial port gets closed. First, we
- * wait for the last remaining data to be sent. Then, we unlink its
- * async structure from the interrupt chain if necessary, and we free
- * that IRQ if nothing is left in the chain.
- * ------------------------------------------------------------
- */
-static void rs_360_close(struct tty_struct *tty, struct file * filp)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- /* struct async_state *state; */
- struct serial_state *state;
- unsigned long flags;
- int idx;
- volatile struct smc_regs *smcp;
- volatile struct scc_regs *sccp;
-
- if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
- return;
-
- state = info->state;
-
- local_irq_save(flags);
-
- if (tty_hung_up_p(filp)) {
- DBG_CNT("before DEC-hung");
- local_irq_restore(flags);
- return;
- }
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_close ttys%d, count = %d\n", info->line, state->count);
-#endif
- if ((tty->count == 1) && (state->count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. state->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- printk("rs_close: bad serial port count; tty->count is 1, "
- "state->count is %d\n", state->count);
- state->count = 1;
- }
- if (--state->count < 0) {
- printk("rs_close: bad serial port count for ttys%d: %d\n",
- info->line, state->count);
- state->count = 0;
- }
- if (state->count) {
- DBG_CNT("before DEC-2");
- local_irq_restore(flags);
- return;
- }
- info->flags |= ASYNC_CLOSING;
- /*
- * Now we wait for the transmit buffer to clear; and we notify
- * the line discipline to only process XON/XOFF characters.
- */
- tty->closing = 1;
- if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
- tty_wait_until_sent(tty, info->closing_wait);
- /*
- * At this point we stop accepting input. To do this, we
- * disable the receive line status interrupts, and tell the
- * interrupt driver to stop checking the data ready bit in the
- * line status register.
- */
- info->read_status_mask &= ~BD_SC_EMPTY;
- if (info->flags & ASYNC_INITIALIZED) {
-
- idx = PORT_NUM(info->state->smc_scc_num);
- if (info->state->smc_scc_num & NUM_IS_SCC) {
- sccp = &pquicc->scc_regs[idx];
- sccp->scc_sccm &= ~UART_SCCM_RX;
- sccp->scc_gsmr.w.low &= ~SCC_GSMRL_ENR;
- } else {
- smcp = &pquicc->smc_regs[idx];
- smcp->smc_smcm &= ~SMCM_RX;
- smcp->smc_smcmr &= ~SMCMR_REN;
- }
- /*
- * Before we drop DTR, make sure the UART transmitter
- * has completely drained; this is especially
- * important if there is a transmit FIFO!
- */
- rs_360_wait_until_sent(tty, info->timeout);
- }
- shutdown(info);
- rs_360_flush_buffer(tty);
- tty_ldisc_flush(tty);
- tty->closing = 0;
- info->event = 0;
- info->port.tty = NULL;
- if (info->blocked_open) {
- if (info->close_delay) {
- msleep_interruptible(jiffies_to_msecs(info->close_delay));
- }
- wake_up_interruptible(&info->open_wait);
- }
- info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
- wake_up_interruptible(&info->close_wait);
- local_irq_restore(flags);
-}
-
-/*
- * rs_wait_until_sent() --- wait until the transmitter is empty
- */
-static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- unsigned long orig_jiffies, char_time;
- /*int lsr;*/
- volatile QUICC_BD *bdp;
-
- if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
- return;
-
-#ifdef maybe
- if (info->state->type == PORT_UNKNOWN)
- return;
-#endif
-
- orig_jiffies = jiffies;
- /*
- * Set the check interval to be 1/5 of the estimated time to
- * send a single character, and make it at least 1. The check
- * interval should also be less than the timeout.
- *
- * Note: we have to use pretty tight timings here to satisfy
- * the NIST-PCTS.
- */
- char_time = 1;
- if (timeout)
- char_time = min(char_time, (unsigned long)timeout);
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
- printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
- printk("jiff=%lu...", jiffies);
-#endif
-
- /* We go through the loop at least once because we can't tell
- * exactly when the last character exits the shifter. There can
- * be at least two characters waiting to be sent after the buffers
- * are empty.
- */
- do {
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
- printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
-#endif
-/* current->counter = 0; make us low-priority */
- msleep_interruptible(jiffies_to_msecs(char_time));
- if (signal_pending(current))
- break;
- if (timeout && (time_after(jiffies, orig_jiffies + timeout)))
- break;
- /* The 'tx_cur' is really the next buffer to send. We
- * have to back up to the previous BD and wait for it
- * to go. This isn't perfect, because all this indicates
- * is the buffer is available. There are still characters
- * in the CPM FIFO.
- */
- bdp = info->tx_cur;
- if (bdp == info->tx_bd_base)
- bdp += (TX_NUM_FIFO-1);
- else
- bdp--;
- } while (bdp->status & BD_SC_READY);
- current->state = TASK_RUNNING;
-#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
- printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
-#endif
-}
-
-/*
- * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-static void rs_360_hangup(struct tty_struct *tty)
-{
- ser_info_t *info = (ser_info_t *)tty->driver_data;
- struct serial_state *state = info->state;
-
- if (serial_paranoia_check(info, tty->name, "rs_hangup"))
- return;
-
- state = info->state;
-
- rs_360_flush_buffer(tty);
- shutdown(info);
- info->event = 0;
- state->count = 0;
- info->flags &= ~ASYNC_NORMAL_ACTIVE;
- info->port.tty = NULL;
- wake_up_interruptible(&info->open_wait);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
- ser_info_t *info)
-{
-#ifdef DO_THIS_LATER
- DECLARE_WAITQUEUE(wait, current);
-#endif
- struct serial_state *state = info->state;
- int retval;
- int do_clocal = 0;
-
- /*
- * If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (tty_hung_up_p(filp) ||
- (info->flags & ASYNC_CLOSING)) {
- if (info->flags & ASYNC_CLOSING)
- interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
- if (info->flags & ASYNC_HUP_NOTIFY)
- return -EAGAIN;
- else
- return -ERESTARTSYS;
-#else
- return -EAGAIN;
-#endif
- }
-
- /*
- * If non-blocking mode is set, or the port is not enabled,
- * then make the check up front and then exit.
- * If this is an SMC port, we don't have modem control to wait
- * for, so just get out here.
- */
- if ((filp->f_flags & O_NONBLOCK) ||
- (tty->flags & (1 << TTY_IO_ERROR)) ||
- !(info->state->smc_scc_num & NUM_IS_SCC)) {
- info->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
- }
-
- if (tty->termios->c_cflag & CLOCAL)
- do_clocal = 1;
-
- /*
- * Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, state->count is dropped by one, so that
- * rs_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
- retval = 0;
-#ifdef DO_THIS_LATER
- add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready before block: ttys%d, count = %d\n",
- state->line, state->count);
-#endif
- local_irq_disable();
- if (!tty_hung_up_p(filp))
- state->count--;
- local_irq_enable();
- info->blocked_open++;
- while (1) {
- local_irq_disable();
- if (tty->termios->c_cflag & CBAUD)
- serial_out(info, UART_MCR,
- serial_inp(info, UART_MCR) |
- (UART_MCR_DTR | UART_MCR_RTS));
- local_irq_enable();
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp) ||
- !(info->flags & ASYNC_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
- if (info->flags & ASYNC_HUP_NOTIFY)
- retval = -EAGAIN;
- else
- retval = -ERESTARTSYS;
-#else
- retval = -EAGAIN;
-#endif
- break;
- }
- if (!(info->flags & ASYNC_CLOSING) &&
- (do_clocal || (serial_in(info, UART_MSR) &
- UART_MSR_DCD)))
- break;
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready blocking: ttys%d, count = %d\n",
- info->line, state->count);
-#endif
- tty_unlock();
- schedule();
- tty_lock();
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&info->open_wait, &wait);
- if (!tty_hung_up_p(filp))
- state->count++;
- info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready after blocking: ttys%d, count = %d\n",
- info->line, state->count);
-#endif
-#endif /* DO_THIS_LATER */
- if (retval)
- return retval;
- info->flags |= ASYNC_NORMAL_ACTIVE;
- return 0;
-}
-
-static int get_async_struct(int line, ser_info_t **ret_info)
-{
- struct serial_state *sstate;
-
- sstate = rs_table + line;
- if (sstate->info) {
- sstate->count++;
- *ret_info = (ser_info_t *)sstate->info;
- return 0;
- }
- else {
- return -ENOMEM;
- }
-}
-
-/*
- * This routine is called whenever a serial port is opened. It
- * enables interrupts for a serial port, linking in its async structure into
- * the IRQ chain. It also performs the serial-specific
- * initialization for the tty structure.
- */
-static int rs_360_open(struct tty_struct *tty, struct file * filp)
-{
- ser_info_t *info;
- int retval, line;
-
- line = tty->index;
- if ((line < 0) || (line >= NR_PORTS))
- return -ENODEV;
- retval = get_async_struct(line, &info);
- if (retval)
- return retval;
- if (serial_paranoia_check(info, tty->name, "rs_open"))
- return -ENODEV;
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_open %s, count = %d\n", tty->name, info->state->count);
-#endif
- tty->driver_data = info;
- info->port.tty = tty;
-
- /*
- * Start up serial port
- */
- retval = startup(info);
- if (retval)
- return retval;
-
- retval = block_til_ready(tty, filp, info);
- if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_open returning after block_til_ready with %d\n",
- retval);
-#endif
- return retval;
- }
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_open %s successful...", tty->name);
-#endif
- return 0;
-}
-
-/*
- * /proc fs routines....
- */
-
-static inline int line_info(char *buf, struct serial_state *state)
-{
-#ifdef notdef
- struct async_struct *info = state->info, scr_info;
- char stat_buf[30], control, status;
-#endif
- int ret;
-
- ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
- state->line,
- (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC",
- (unsigned int)(state->port), state->irq);
-
- if (!state->port || (state->type == PORT_UNKNOWN)) {
- ret += sprintf(buf+ret, "\n");
- return ret;
- }
-
-#ifdef notdef
- /*
- * Figure out the current RS-232 lines
- */
- if (!info) {
- info = &scr_info; /* This is just for serial_{in,out} */
-
- info->magic = SERIAL_MAGIC;
- info->port = state->port;
- info->flags = state->flags;
- info->quot = 0;
- info->port.tty = NULL;
- }
- local_irq_disable();
- status = serial_in(info, UART_MSR);
- control = info ? info->MCR : serial_in(info, UART_MCR);
- local_irq_enable();
-
- stat_buf[0] = 0;
- stat_buf[1] = 0;
- if (control & UART_MCR_RTS)
- strcat(stat_buf, "|RTS");
- if (status & UART_MSR_CTS)
- strcat(stat_buf, "|CTS");
- if (control & UART_MCR_DTR)
- strcat(stat_buf, "|DTR");
- if (status & UART_MSR_DSR)
- strcat(stat_buf, "|DSR");
- if (status & UART_MSR_DCD)
- strcat(stat_buf, "|CD");
- if (status & UART_MSR_RI)
- strcat(stat_buf, "|RI");
-
- if (info->quot) {
- ret += sprintf(buf+ret, " baud:%d",
- state->baud_base / info->quot);
- }
-
- ret += sprintf(buf+ret, " tx:%d rx:%d",
- state->icount.tx, state->icount.rx);
-
- if (state->icount.frame)
- ret += sprintf(buf+ret, " fe:%d", state->icount.frame);
-
- if (state->icount.parity)
- ret += sprintf(buf+ret, " pe:%d", state->icount.parity);
-
- if (state->icount.brk)
- ret += sprintf(buf+ret, " brk:%d", state->icount.brk);
-
- if (state->icount.overrun)
- ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
-
- /*
- * Last thing is the RS-232 status lines
- */
- ret += sprintf(buf+ret, " %s\n", stat_buf+1);
-#endif
- return ret;
-}
-
-int rs_360_read_proc(char *page, char **start, off_t off, int count,
- int *eof, void *data)
-{
- int i, len = 0;
- off_t begin = 0;
-
- len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
- for (i = 0; i < NR_PORTS && len < 4000; i++) {
- len += line_info(page + len, &rs_table[i]);
- if (len+begin > off+count)
- goto done;
- if (len+begin < off) {
- begin += len;
- len = 0;
- }
- }
- *eof = 1;
-done:
- if (off >= len+begin)
- return 0;
- *start = page + (begin-off);
- return ((count < begin+len-off) ? count : begin+len-off);
-}
-
-/*
- * ---------------------------------------------------------------------
- * rs_init() and friends
- *
- * rs_init() is called at boot-time to initialize the serial driver.
- * ---------------------------------------------------------------------
- */
-
-/*
- * This routine prints out the appropriate serial driver version
- * number, and identifies which options were configured into this
- * driver.
- */
-static _INLINE_ void show_serial_version(void)
-{
- printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
-}
-
-
-/*
- * The serial console driver used during boot. Note that these names
- * clash with those found in "serial.c", so we currently can't support
- * the 16xxx uarts and these at the same time. I will fix this to become
- * an indirect function call from tty_io.c (or something).
- */
-
-#ifdef CONFIG_SERIAL_CONSOLE
-
-/*
- * Print a string to the serial port trying not to disturb any possible
- * real use of the port...
- */
-static void my_console_write(int idx, const char *s,
- unsigned count)
-{
- struct serial_state *ser;
- ser_info_t *info;
- unsigned i;
- QUICC_BD *bdp, *bdbase;
- volatile struct smc_uart_pram *up;
- volatile u_char *cp;
-
- ser = rs_table + idx;
-
-
- /* If the port has been initialized for general use, we have
- * to use the buffer descriptors allocated there. Otherwise,
- * we simply use the single buffer allocated.
- */
- if ((info = (ser_info_t *)ser->info) != NULL) {
- bdp = info->tx_cur;
- bdbase = info->tx_bd_base;
- }
- else {
- /* Pointer to UART in parameter ram.
- */
- /* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */
- up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u;
-
- /* Get the address of the host memory buffer.
- */
- bdp = bdbase = (QUICC_BD *)((uint)pquicc + (uint)up->tbase);
- }
-
- /*
- * We need to gracefully shut down the transmitter, disable
- * interrupts, then send our bytes out.
- */
-
- /*
- * Now, do each character. This is not as bad as it looks
- * since this is a holding FIFO and not a transmitting FIFO.
- * We could add the complexity of filling the entire transmit
- * buffer, but we would just wait longer between accesses......
- */
- for (i = 0; i < count; i++, s++) {
- /* Wait for transmitter fifo to empty.
- * Ready indicates output is ready, and xmt is doing
- * that, not that it is ready for us to send.
- */
- while (bdp->status & BD_SC_READY);
-
- /* Send the character out.
- */
- cp = bdp->buf;
- *cp = *s;
-
- bdp->length = 1;
- bdp->status |= BD_SC_READY;
-
- if (bdp->status & BD_SC_WRAP)
- bdp = bdbase;
- else
- bdp++;
-
- /* if a LF, also do CR... */
- if (*s == 10) {
- while (bdp->status & BD_SC_READY);
- /* cp = __va(bdp->buf); */
- cp = bdp->buf;
- *cp = 13;
- bdp->length = 1;
- bdp->status |= BD_SC_READY;
-
- if (bdp->status & BD_SC_WRAP) {
- bdp = bdbase;
- }
- else {
- bdp++;
- }
- }
- }
-
- /*
- * Finally, Wait for transmitter & holding register to empty
- * and restore the IER
- */
- while (bdp->status & BD_SC_READY);
-
- if (info)
- info->tx_cur = (QUICC_BD *)bdp;
-}
-
-static void serial_console_write(struct console *c, const char *s,
- unsigned count)
-{
-#ifdef CONFIG_KGDB
- /* Try to let stub handle output. Returns true if it did. */
- if (kgdb_output_string(s, count))
- return;
-#endif
- my_console_write(c->index, s, count);
-}
-
-
-
-/*void console_print_68360(const char *p)
-{
- const char *cp = p;
- int i;
-
- for (i=0;cp[i]!=0;i++);
-
- serial_console_write (p, i);
-
- //Comment this if you want to have a strict interrupt-driven output
- //rs_fair_output();
-
- return;
-}*/
-
-
-
-
-
-
-#ifdef CONFIG_XMON
-int
-xmon_360_write(const char *s, unsigned count)
-{
- my_console_write(0, s, count);
- return(count);
-}
-#endif
-
-#ifdef CONFIG_KGDB
-void
-putDebugChar(char ch)
-{
- my_console_write(0, &ch, 1);
-}
-#endif
-
-/*
- * Receive character from the serial port. This only works well
- * before the port is initialized for real use.
- */
-static int my_console_wait_key(int idx, int xmon, char *obuf)
-{
- struct serial_state *ser;
- u_char c, *cp;
- ser_info_t *info;
- QUICC_BD *bdp;
- volatile struct smc_uart_pram *up;
- int i;
-
- ser = rs_table + idx;
-
- /* Get the address of the host memory buffer.
- * If the port has been initialized for general use, we must
- * use information from the port structure.
- */
- if ((info = (ser_info_t *)ser->info))
- bdp = info->rx_cur;
- else
- /* bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase]; */
- bdp = (QUICC_BD *)((uint)pquicc + (uint)up->tbase);
-
- /* Pointer to UART in parameter ram.
- */
- /* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */
- up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
-
- /*
- * We need to gracefully shut down the receiver, disable
- * interrupts, then read the input.
- * XMON just wants a poll. If no character, return -1, else
- * return the character.
- */
- if (!xmon) {
- while (bdp->status & BD_SC_EMPTY);
- }
- else {
- if (bdp->status & BD_SC_EMPTY)
- return -1;
- }
-
- cp = (char *)bdp->buf;
-
- if (obuf) {
- i = c = bdp->length;
- while (i-- > 0)
- *obuf++ = *cp++;
- }
- else {
- c = *cp;
- }
- bdp->status |= BD_SC_EMPTY;
-
- if (info) {
- if (bdp->status & BD_SC_WRAP) {
- bdp = info->rx_bd_base;
- }
- else {
- bdp++;
- }
- info->rx_cur = (QUICC_BD *)bdp;
- }
-
- return((int)c);
-}
-
-static int serial_console_wait_key(struct console *co)
-{
- return(my_console_wait_key(co->index, 0, NULL));
-}
-
-#ifdef CONFIG_XMON
-int
-xmon_360_read_poll(void)
-{
- return(my_console_wait_key(0, 1, NULL));
-}
-
-int
-xmon_360_read_char(void)
-{
- return(my_console_wait_key(0, 0, NULL));
-}
-#endif
-
-#ifdef CONFIG_KGDB
-static char kgdb_buf[RX_BUF_SIZE], *kgdp;
-static int kgdb_chars;
-
-unsigned char
-getDebugChar(void)
-{
- if (kgdb_chars <= 0) {
- kgdb_chars = my_console_wait_key(0, 0, kgdb_buf);
- kgdp = kgdb_buf;
- }
- kgdb_chars--;
-
- return(*kgdp++);
-}
-
-void kgdb_interruptible(int state)
-{
-}
-void kgdb_map_scc(void)
-{
- struct serial_state *ser;
- uint mem_addr;
- volatile QUICC_BD *bdp;
- volatile smc_uart_t *up;
-
- cpmp = (cpm360_t *)&(((immap_t *)IMAP_ADDR)->im_cpm);
-
- /* To avoid data cache CPM DMA coherency problems, allocate a
- * buffer in the CPM DPRAM. This will work until the CPM and
- * serial ports are initialized. At that time a memory buffer
- * will be allocated.
- * The port is already initialized from the boot procedure, all
- * we do here is give it a different buffer and make it a FIFO.
- */
-
- ser = rs_table;
-
- /* Right now, assume we are using SMCs.
- */
- up = (smc_uart_t *)&cpmp->cp_dparam[ser->port];
-
- /* Allocate space for an input FIFO, plus a few bytes for output.
- * Allocate bytes to maintain word alignment.
- */
- mem_addr = (uint)(&cpmp->cp_dpmem[0x1000]);
-
- /* Set the physical address of the host memory buffers in
- * the buffer descriptors.
- */
- bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase];
- bdp->buf = mem_addr;
-
- bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_tbase];
- bdp->buf = mem_addr+RX_BUF_SIZE;
-
- up->smc_mrblr = RX_BUF_SIZE; /* receive buffer length */
- up->smc_maxidl = RX_BUF_SIZE;
-}
-#endif
-
-static struct tty_struct *serial_console_device(struct console *c, int *index)
-{
- *index = c->index;
- return serial_driver;
-}
-
-
-struct console sercons = {
- .name = "ttyS",
- .write = serial_console_write,
- .device = serial_console_device,
- .wait_key = serial_console_wait_key,
- .setup = serial_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = CONFIG_SERIAL_CONSOLE_PORT,
-};
-
-
-
-/*
- * Register console.
- */
-long console_360_init(long kmem_start, long kmem_end)
-{
- register_console(&sercons);
- /*register_console (console_print_68360); - 2.0.38 only required a write
- function pointer. */
- return kmem_start;
-}
-
-#endif
-
-/* Index in baud rate table of the default console baud rate.
-*/
-static int baud_idx;
-
-static const struct tty_operations rs_360_ops = {
- .owner = THIS_MODULE,
- .open = rs_360_open,
- .close = rs_360_close,
- .write = rs_360_write,
- .put_char = rs_360_put_char,
- .write_room = rs_360_write_room,
- .chars_in_buffer = rs_360_chars_in_buffer,
- .flush_buffer = rs_360_flush_buffer,
- .ioctl = rs_360_ioctl,
- .throttle = rs_360_throttle,
- .unthrottle = rs_360_unthrottle,
- /* .send_xchar = rs_360_send_xchar, */
- .set_termios = rs_360_set_termios,
- .stop = rs_360_stop,
- .start = rs_360_start,
- .hangup = rs_360_hangup,
- /* .wait_until_sent = rs_360_wait_until_sent, */
- /* .read_proc = rs_360_read_proc, */
- .tiocmget = rs_360_tiocmget,
- .tiocmset = rs_360_tiocmset,
- .get_icount = rs_360_get_icount,
-};
-
-static int __init rs_360_init(void)
-{
- struct serial_state * state;
- ser_info_t *info;
- void *mem_addr;
- uint dp_addr, iobits;
- int i, j, idx;
- ushort chan;
- QUICC_BD *bdp;
- volatile QUICC *cp;
- volatile struct smc_regs *sp;
- volatile struct smc_uart_pram *up;
- volatile struct scc_regs *scp;
- volatile struct uart_pram *sup;
- /* volatile immap_t *immap; */
-
- serial_driver = alloc_tty_driver(NR_PORTS);
- if (!serial_driver)
- return -1;
-
- show_serial_version();
-
- serial_driver->name = "ttyS";
- serial_driver->major = TTY_MAJOR;
- serial_driver->minor_start = 64;
- serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
- serial_driver->subtype = SERIAL_TYPE_NORMAL;
- serial_driver->init_termios = tty_std_termios;
- serial_driver->init_termios.c_cflag =
- baud_idx | CS8 | CREAD | HUPCL | CLOCAL;
- serial_driver->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(serial_driver, &rs_360_ops);
-
- if (tty_register_driver(serial_driver))
- panic("Couldn't register serial driver\n");
-
- cp = pquicc; /* Get pointer to Communication Processor */
- /* immap = (immap_t *)IMAP_ADDR; */ /* and to internal registers */
-
-
- /* Configure SCC2, SCC3, and SCC4 instead of port A parallel I/O.
- */
- /* The "standard" configuration through the 860.
- */
-/* immap->im_ioport.iop_papar |= 0x00fc; */
-/* immap->im_ioport.iop_padir &= ~0x00fc; */
-/* immap->im_ioport.iop_paodr &= ~0x00fc; */
- cp->pio_papar |= 0x00fc;
- cp->pio_padir &= ~0x00fc;
- /* cp->pio_paodr &= ~0x00fc; */
-
-
- /* Since we don't yet do modem control, connect the port C pins
- * as general purpose I/O. This will assert CTS and CD for the
- * SCC ports.
- */
- /* FIXME: see 360um p.7-365 and 860um p.34-12
- * I can't make sense of these bits - mleslie*/
-/* immap->im_ioport.iop_pcdir |= 0x03c6; */
-/* immap->im_ioport.iop_pcpar &= ~0x03c6; */
-
-/* cp->pio_pcdir |= 0x03c6; */
-/* cp->pio_pcpar &= ~0x03c6; */
-
-
-
- /* Connect SCC2 and SCC3 to NMSI. Connect BRG3 to SCC2 and
- * BRG4 to SCC3.
- */
- cp->si_sicr &= ~0x00ffff00;
- cp->si_sicr |= 0x001b1200;
-
-#ifdef CONFIG_PP04
- /* Frequentis PP04 forced to RS-232 until we know better.
- * Port C 12 and 13 low enables RS-232 on SCC3 and SCC4.
- */
- immap->im_ioport.iop_pcdir |= 0x000c;
- immap->im_ioport.iop_pcpar &= ~0x000c;
- immap->im_ioport.iop_pcdat &= ~0x000c;
-
- /* This enables the TX driver.
- */
- cp->cp_pbpar &= ~0x6000;
- cp->cp_pbdat &= ~0x6000;
-#endif
-
- for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
- state->magic = SSTATE_MAGIC;
- state->line = i;
- state->type = PORT_UNKNOWN;
- state->custom_divisor = 0;
- state->close_delay = 5*HZ/10;
- state->closing_wait = 30*HZ;
- state->icount.cts = state->icount.dsr =
- state->icount.rng = state->icount.dcd = 0;
- state->icount.rx = state->icount.tx = 0;
- state->icount.frame = state->icount.parity = 0;
- state->icount.overrun = state->icount.brk = 0;
- printk(KERN_INFO "ttyS%d at irq 0x%02x is an %s\n",
- i, (unsigned int)(state->irq),
- (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC");
-
-#ifdef CONFIG_SERIAL_CONSOLE
- /* If we just printed the message on the console port, and
- * we are about to initialize it for general use, we have
- * to wait a couple of character times for the CR/NL to
- * make it out of the transmit buffer.
- */
- if (i == CONFIG_SERIAL_CONSOLE_PORT)
- mdelay(8);
-
-
-/* idx = PORT_NUM(info->state->smc_scc_num); */
-/* if (info->state->smc_scc_num & NUM_IS_SCC) */
-/* chan = scc_chan_map[idx]; */
-/* else */
-/* chan = smc_chan_map[idx]; */
-
-/* cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG; */
-/* while (cp->cp_cr & CPM_CR_FLG); */
-
-#endif
- /* info = kmalloc(sizeof(ser_info_t), GFP_KERNEL); */
- info = &quicc_ser_info[i];
- if (info) {
- memset (info, 0, sizeof(ser_info_t));
- info->magic = SERIAL_MAGIC;
- info->line = i;
- info->flags = state->flags;
- INIT_WORK(&info->tqueue, do_softint, info);
- INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info);
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
- info->state = state;
- state->info = (struct async_struct *)info;
-
- /* We need to allocate a transmit and receive buffer
- * descriptors from dual port ram, and a character
- * buffer area from host mem.
- */
- dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * RX_NUM_FIFO);
-
- /* Allocate space for FIFOs in the host memory.
- * (for now this is from a static array of buffers :(
- */
- /* mem_addr = m360_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE); */
- /* mem_addr = kmalloc (RX_NUM_FIFO * RX_BUF_SIZE, GFP_BUFFER); */
- mem_addr = &rx_buf_pool[i * RX_NUM_FIFO * RX_BUF_SIZE];
-
- /* Set the physical address of the host memory
- * buffers in the buffer descriptors, and the
- * virtual address for us to work with.
- */
- bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
- info->rx_cur = info->rx_bd_base = bdp;
-
- /* initialize rx buffer descriptors */
- for (j=0; j<(RX_NUM_FIFO-1); j++) {
- bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE];
- bdp->status = BD_SC_EMPTY | BD_SC_INTRPT;
- mem_addr += RX_BUF_SIZE;
- bdp++;
- }
- bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE];
- bdp->status = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
-
-
- idx = PORT_NUM(info->state->smc_scc_num);
- if (info->state->smc_scc_num & NUM_IS_SCC) {
-
-#if defined (CONFIG_UCQUICC) && 1
- /* set the transceiver mode to RS232 */
- sipex_mode_bits &= ~(uint)SIPEX_MODE(idx,0x0f); /* clear current mode */
- sipex_mode_bits |= (uint)SIPEX_MODE(idx,0x02);
- *(uint *)_periph_base = sipex_mode_bits;
- /* printk ("sipex bits = 0x%08x\n", sipex_mode_bits); */
-#endif
- }
-
- dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * TX_NUM_FIFO);
-
- /* Allocate space for FIFOs in the host memory.
- */
- /* mem_addr = m360_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE); */
- /* mem_addr = kmalloc (TX_NUM_FIFO * TX_BUF_SIZE, GFP_BUFFER); */
- mem_addr = &tx_buf_pool[i * TX_NUM_FIFO * TX_BUF_SIZE];
-
- /* Set the physical address of the host memory
- * buffers in the buffer descriptors, and the
- * virtual address for us to work with.
- */
- /* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */
- bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
- info->tx_cur = info->tx_bd_base = (QUICC_BD *)bdp;
-
- /* initialize tx buffer descriptors */
- for (j=0; j<(TX_NUM_FIFO-1); j++) {
- bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE];
- bdp->status = BD_SC_INTRPT;
- mem_addr += TX_BUF_SIZE;
- bdp++;
- }
- bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE];
- bdp->status = (BD_SC_WRAP | BD_SC_INTRPT);
-
- if (info->state->smc_scc_num & NUM_IS_SCC) {
- scp = &pquicc->scc_regs[idx];
- sup = &pquicc->pram[info->state->port].scc.pscc.u;
- sup->rbase = dp_addr;
- sup->tbase = dp_addr;
-
- /* Set up the uart parameters in the
- * parameter ram.
- */
- sup->rfcr = SMC_EB;
- sup->tfcr = SMC_EB;
-
- /* Set this to 1 for now, so we get single
- * character interrupts. Using idle character
- * time requires some additional tuning.
- */
- sup->mrblr = 1;
- sup->max_idl = 0;
- sup->brkcr = 1;
- sup->parec = 0;
- sup->frmer = 0;
- sup->nosec = 0;
- sup->brkec = 0;
- sup->uaddr1 = 0;
- sup->uaddr2 = 0;
- sup->toseq = 0;
- {
- int i;
- for (i=0;i<8;i++)
- sup->cc[i] = 0x8000;
- }
- sup->rccm = 0xc0ff;
-
- /* Send the CPM an initialize command.
- */
- chan = scc_chan_map[idx];
-
- /* execute the INIT RX & TX PARAMS command for this channel. */
- cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
- while (cp->cp_cr & CPM_CR_FLG);
-
- /* Set UART mode, 8 bit, no parity, one stop.
- * Enable receive and transmit.
- */
- scp->scc_gsmr.w.high = 0;
- scp->scc_gsmr.w.low =
- (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
-
- /* Disable all interrupts and clear all pending
- * events.
- */
- scp->scc_sccm = 0;
- scp->scc_scce = 0xffff;
- scp->scc_dsr = 0x7e7e;
- scp->scc_psmr = 0x3000;
-
- /* If the port is the console, enable Rx and Tx.
- */
-#ifdef CONFIG_SERIAL_CONSOLE
- if (i == CONFIG_SERIAL_CONSOLE_PORT)
- scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-#endif
- }
- else {
- /* Configure SMCs Tx/Rx instead of port B
- * parallel I/O.
- */
- up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
- up->rbase = dp_addr;
-
- iobits = 0xc0 << (idx * 4);
- cp->pip_pbpar |= iobits;
- cp->pip_pbdir &= ~iobits;
- cp->pip_pbodr &= ~iobits;
-
-
- /* Connect the baud rate generator to the
- * SMC based upon index in rs_table. Also
- * make sure it is connected to NMSI.
- */
- cp->si_simode &= ~(0xffff << (idx * 16));
- cp->si_simode |= (i << ((idx * 16) + 12));
-
- up->tbase = dp_addr;
-
- /* Set up the uart parameters in the
- * parameter ram.
- */
- up->rfcr = SMC_EB;
- up->tfcr = SMC_EB;
-
- /* Set this to 1 for now, so we get single
- * character interrupts. Using idle character
- * time requires some additional tuning.
- */
- up->mrblr = 1;
- up->max_idl = 0;
- up->brkcr = 1;
-
- /* Send the CPM an initialize command.
- */
- chan = smc_chan_map[idx];
-
- cp->cp_cr = mk_cr_cmd(chan,
- CPM_CR_INIT_TRX) | CPM_CR_FLG;
-#ifdef CONFIG_SERIAL_CONSOLE
- if (i == CONFIG_SERIAL_CONSOLE_PORT)
- printk("");
-#endif
- while (cp->cp_cr & CPM_CR_FLG);
-
- /* Set UART mode, 8 bit, no parity, one stop.
- * Enable receive and transmit.
- */
- sp = &cp->smc_regs[idx];
- sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
-
- /* Disable all interrupts and clear all pending
- * events.
- */
- sp->smc_smcm = 0;
- sp->smc_smce = 0xff;
-
- /* If the port is the console, enable Rx and Tx.
- */
-#ifdef CONFIG_SERIAL_CONSOLE
- if (i == CONFIG_SERIAL_CONSOLE_PORT)
- sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
-#endif
- }
-
- /* Install interrupt handler.
- */
- /* cpm_install_handler(IRQ_MACHSPEC | state->irq, rs_360_interrupt, info); */
- /*request_irq(IRQ_MACHSPEC | state->irq, rs_360_interrupt, */
- request_irq(state->irq, rs_360_interrupt, 0, "ttyS",
- (void *)info);
-
- /* Set up the baud rate generator.
- */
- m360_cpm_setbrg(i, baud_table[baud_idx]);
-
- }
- }
-
- return 0;
-}
-module_init(rs_360_init);
-
-/* This must always be called before the rs_360_init() function, otherwise
- * it blows away the port control information.
- */
-//static int __init serial_console_setup( struct console *co, char *options)
-int serial_console_setup( struct console *co, char *options)
-{
- struct serial_state *ser;
- uint mem_addr, dp_addr, bidx, idx, iobits;
- ushort chan;
- QUICC_BD *bdp;
- volatile QUICC *cp;
- volatile struct smc_regs *sp;
- volatile struct scc_regs *scp;
- volatile struct smc_uart_pram *up;
- volatile struct uart_pram *sup;
-
-/* mleslie TODO:
- * add something to the 68k bootloader to store a desired initial console baud rate */
-
-/* bd_t *bd; */ /* a board info struct used by EPPC-bug */
-/* bd = (bd_t *)__res; */
-
- for (bidx = 0; bidx < (sizeof(baud_table) / sizeof(int)); bidx++)
- /* if (bd->bi_baudrate == baud_table[bidx]) */
- if (CONSOLE_BAUDRATE == baud_table[bidx])
- break;
-
- /* co->cflag = CREAD|CLOCAL|bidx|CS8; */
- baud_idx = bidx;
-
- ser = rs_table + CONFIG_SERIAL_CONSOLE_PORT;
-
- cp = pquicc; /* Get pointer to Communication Processor */
-
- idx = PORT_NUM(ser->smc_scc_num);
- if (ser->smc_scc_num & NUM_IS_SCC) {
-
- /* TODO: need to set up SCC pin assignment etc. here */
-
- }
- else {
- iobits = 0xc0 << (idx * 4);
- cp->pip_pbpar |= iobits;
- cp->pip_pbdir &= ~iobits;
- cp->pip_pbodr &= ~iobits;
-
- /* Connect the baud rate generator to the
- * SMC based upon index in rs_table. Also
- * make sure it is connected to NMSI.
- */
- cp->si_simode &= ~(0xffff << (idx * 16));
- cp->si_simode |= (idx << ((idx * 16) + 12));
- }
-
- /* When we get here, the CPM has been reset, so we need
- * to configure the port.
- * We need to allocate a transmit and receive buffer descriptor
- * from dual port ram, and a character buffer area from host mem.
- */
-
- /* Allocate space for two buffer descriptors in the DP ram.
- */
- dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * CONSOLE_NUM_FIFO);
-
- /* Allocate space for two 2 byte FIFOs in the host memory.
- */
- /* mem_addr = m360_cpm_hostalloc(8); */
- mem_addr = (uint)console_fifos;
-
-
- /* Set the physical address of the host memory buffers in
- * the buffer descriptors.
- */
- /* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */
- bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
- bdp->buf = (char *)mem_addr;
- (bdp+1)->buf = (char *)(mem_addr+4);
-
- /* For the receive, set empty and wrap.
- * For transmit, set wrap.
- */
- bdp->status = BD_SC_EMPTY | BD_SC_WRAP;
- (bdp+1)->status = BD_SC_WRAP;
-
- /* Set up the uart parameters in the parameter ram.
- */
- if (ser->smc_scc_num & NUM_IS_SCC) {
- scp = &cp->scc_regs[idx];
- /* sup = (scc_uart_t *)&cp->cp_dparam[ser->port]; */
- sup = &pquicc->pram[ser->port].scc.pscc.u;
-
- sup->rbase = dp_addr;
- sup->tbase = dp_addr + sizeof(QUICC_BD);
-
- /* Set up the uart parameters in the
- * parameter ram.
- */
- sup->rfcr = SMC_EB;
- sup->tfcr = SMC_EB;
-
- /* Set this to 1 for now, so we get single
- * character interrupts. Using idle character
- * time requires some additional tuning.
- */
- sup->mrblr = 1;
- sup->max_idl = 0;
- sup->brkcr = 1;
- sup->parec = 0;
- sup->frmer = 0;
- sup->nosec = 0;
- sup->brkec = 0;
- sup->uaddr1 = 0;
- sup->uaddr2 = 0;
- sup->toseq = 0;
- {
- int i;
- for (i=0;i<8;i++)
- sup->cc[i] = 0x8000;
- }
- sup->rccm = 0xc0ff;
-
- /* Send the CPM an initialize command.
- */
- chan = scc_chan_map[idx];
-
- cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
- while (cp->cp_cr & CPM_CR_FLG);
-
- /* Set UART mode, 8 bit, no parity, one stop.
- * Enable receive and transmit.
- */
- scp->scc_gsmr.w.high = 0;
- scp->scc_gsmr.w.low =
- (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
-
- /* Disable all interrupts and clear all pending
- * events.
- */
- scp->scc_sccm = 0;
- scp->scc_scce = 0xffff;
- scp->scc_dsr = 0x7e7e;
- scp->scc_psmr = 0x3000;
-
- scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-
- }
- else {
- /* up = (smc_uart_t *)&cp->cp_dparam[ser->port]; */
- up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u;
-
- up->rbase = dp_addr; /* Base of receive buffer desc. */
- up->tbase = dp_addr+sizeof(QUICC_BD); /* Base of xmt buffer desc. */
- up->rfcr = SMC_EB;
- up->tfcr = SMC_EB;
-
- /* Set this to 1 for now, so we get single character interrupts.
- */
- up->mrblr = 1; /* receive buffer length */
- up->max_idl = 0; /* wait forever for next char */
-
- /* Send the CPM an initialize command.
- */
- chan = smc_chan_map[idx];
- cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
- while (cp->cp_cr & CPM_CR_FLG);
-
- /* Set UART mode, 8 bit, no parity, one stop.
- * Enable receive and transmit.
- */
- sp = &cp->smc_regs[idx];
- sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
-
- /* And finally, enable Rx and Tx.
- */
- sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
- }
-
- /* Set up the baud rate generator.
- */
- /* m360_cpm_setbrg((ser - rs_table), bd->bi_baudrate); */
- m360_cpm_setbrg((ser - rs_table), CONSOLE_BAUDRATE);
-
- return 0;
-}
-
-/*
- * Local variables:
- * c-indent-level: 4
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- */
diff --git a/drivers/staging/serial/Kconfig b/drivers/staging/serial/Kconfig
deleted file mode 100644
index 9489688397e0..000000000000
--- a/drivers/staging/serial/Kconfig
+++ /dev/null
@@ -1,16 +0,0 @@
-config SERIAL_68360_SMC
- bool "68360 SMC uart support"
- depends on M68360
- help
- This driver supports the SMC serial ports of the Motorola 68360 CPU.
-
-config SERIAL_68360_SCC
- bool "68360 SCC uart support"
- depends on M68360
- help
- This driver supports the SCC serial ports of the Motorola 68360 CPU.
-
-config SERIAL_68360
- bool
- depends on SERIAL_68360_SMC || SERIAL_68360_SCC
- default y
diff --git a/drivers/staging/serial/Makefile b/drivers/staging/serial/Makefile
deleted file mode 100644
index 37a6a0b35fba..000000000000
--- a/drivers/staging/serial/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_SERIAL_68360) += 68360serial.o
diff --git a/drivers/staging/serial/TODO b/drivers/staging/serial/TODO
deleted file mode 100644
index a19cda81dab4..000000000000
--- a/drivers/staging/serial/TODO
+++ /dev/null
@@ -1,6 +0,0 @@
-These are a few serial drivers that either do not build, or do not work if they
-do build, or if they seem to work, are for obsolete hardware, or are full of
-unfixable races and no one uses them anymore.
-
-If no one steps up to adopt any of these drivers, they will be removed
-in the 3.4 release.
diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c
index ae1d815e2a53..43045db982d4 100644
--- a/drivers/staging/serqt_usb2/serqt_usb2.c
+++ b/drivers/staging/serqt_usb2/serqt_usb2.c
@@ -41,13 +41,6 @@ static bool debug;
#define QUATECH_HSU200B 0xC0B1 /* HSU200B */
#define QUATECH_HSU200C 0xC0B2 /* HSU200C */
#define QUATECH_HSU200D 0xC0B3 /* HSU200D */
-#define QUATECH_SSU100_2 0xC120 /* SSU100_2 */
-#define QUATECH_DSU100_2 0xC140 /* DSU100_2 */
-#define QUATECH_DSU400_2 0xC150 /* DSU400_2 */
-#define QUATECH_QSU100_2 0xC160 /* QSU100_2 */
-#define QUATECH_QSU400_2 0xC170 /* QSU400_2 */
-#define QUATECH_ESU400_2 0xC180 /* ESU400_2 */
-#define QUATECH_ESU100_2 0xC1A0 /* ESU100_2 */
#define QT_SET_GET_DEVICE 0xc2
#define QT_OPEN_CLOSE_CHANNEL 0xca
@@ -125,7 +118,7 @@ static bool debug;
#define MODEM_CTRL 0x40
#define RS232_MODE 0x00
-static const struct usb_device_id serqt_id_table[] = {
+static const struct usb_device_id id_table[] = {
{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU200)},
{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU100)},
{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU200)},
@@ -143,17 +136,9 @@ static const struct usb_device_id serqt_id_table[] = {
{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_HSU200B)},
{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_HSU200C)},
{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_HSU200D)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU100_2)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU100_2)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU400_2)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU100_2)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU400_2)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU400_2)},
- {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU100_2)},
{} /* Terminating entry */
};
-
-MODULE_DEVICE_TABLE(usb, serqt_id_table);
+MODULE_DEVICE_TABLE(usb, id_table);
struct qt_get_device_data {
__u8 porta;
@@ -195,13 +180,6 @@ struct quatech_port {
char closePending;
};
-static struct usb_driver serqt_usb_driver = {
- .name = "quatech-usb-serial",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = serqt_id_table,
-};
-
static int port_paranoia_check(struct usb_serial_port *port,
const char *function)
{
@@ -304,8 +282,6 @@ static void qt_write_bulk_callback(struct urb *urb)
quatech_port = urb->context;
- dbg("%s - port %d\n", __func__, quatech_port->port_num);
-
tty = tty_port_tty_get(&quatech_port->port->port);
if (tty)
@@ -351,7 +327,6 @@ static void qt_read_bulk_callback(struct urb *urb)
/* index = MINOR(port->tty->device) - serial->minor; */
index = tty->index - serial->minor;
- dbg("%s - port %d\n", __func__, port->number);
dbg("%s - port->RxHolding = %d\n", __func__, qt_port->RxHolding);
if (port_paranoia_check(port, __func__) != 0) {
@@ -726,8 +701,6 @@ static int qt_startup(struct usb_serial *serial)
int i;
int status;
- dbg("enterting %s", __func__);
-
/* Now setup per port private data */
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
@@ -855,8 +828,6 @@ static void qt_release(struct usb_serial *serial)
struct quatech_port *qt_port;
int i;
- dbg("enterting %s", __func__);
-
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
if (!port)
@@ -882,8 +853,6 @@ static int qt_open(struct tty_struct *tty,
if (port_paranoia_check(port, __func__))
return -ENODEV;
- dbg("%s - port %d\n", __func__, port->number);
-
serial = port->serial;
if (serial_paranoia_check(serial, __func__))
@@ -1006,8 +975,6 @@ static int qt_chars_in_buffer(struct tty_struct *tty)
serial = get_usb_serial(port, __func__);
- dbg("%s - port %d\n", __func__, port->number);
-
if (serial->num_bulk_out) {
if (port->write_urb->status == -EINPROGRESS)
chars = port->write_urb->transfer_buffer_length;
@@ -1054,8 +1021,6 @@ static void qt_close(struct usb_serial_port *port)
unsigned int index;
status = 0;
- dbg("%s - port %d\n", __func__, port->number);
-
tty = tty_port_tty_get(&port->port);
index = tty->index - serial->minor;
@@ -1109,8 +1074,6 @@ static int qt_write(struct tty_struct *tty, struct usb_serial_port *port,
if (serial == NULL)
return -ENODEV;
- dbg("%s - port %d\n", __func__, port->number);
-
if (count == 0) {
dbg("%s - write request of 0 bytes\n", __func__);
return 0;
@@ -1173,8 +1136,6 @@ static int qt_write_room(struct tty_struct *tty)
mutex_lock(&qt_port->lock);
- dbg("%s - port %d\n", __func__, port->number);
-
if (serial->num_bulk_out) {
if (port->write_urb->status != -EINPROGRESS)
retval = port->bulk_out_size;
@@ -1241,8 +1202,6 @@ static void qt_set_termios(struct tty_struct *tty,
int baud, divisor, remainder;
int status;
- dbg("%s", __func__);
-
index = tty->index - port->serial->minor;
switch (cflag) {
@@ -1365,8 +1324,6 @@ static void qt_break(struct tty_struct *tty, int break_state)
mutex_lock(&qt_port->lock);
- dbg("%s - port %d\n", __func__, port->number);
-
result =
usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
QT_BREAK_CONTROL, 0x40, onoff, index, NULL, 0, 300);
@@ -1385,8 +1342,6 @@ static inline int qt_real_tiocmget(struct tty_struct *tty,
int status;
unsigned int index;
- dbg("%s - port %d, tty =0x%p\n", __func__, port->number, tty);
-
index = tty->index - serial->minor;
status =
BoxGetRegister(port->serial, index, MODEM_CONTROL_REGISTER, &mcr);
@@ -1426,8 +1381,6 @@ static inline int qt_real_tiocmset(struct tty_struct *tty,
int status;
unsigned int index;
- dbg("%s - port %d\n", __func__, port->number);
-
index = tty->index - serial->minor;
status =
BoxGetRegister(port->serial, index, MODEM_CONTROL_REGISTER, &mcr);
@@ -1461,18 +1414,11 @@ static int qt_tiocmget(struct tty_struct *tty)
struct quatech_port *qt_port = qt_get_port_private(port);
int retval = -ENODEV;
- dbg("In %s\n", __func__);
-
if (!serial)
return -ENODEV;
mutex_lock(&qt_port->lock);
-
- dbg("%s - port %d\n", __func__, port->number);
- dbg("%s - port->RxHolding = %d\n", __func__, qt_port->RxHolding);
-
retval = qt_real_tiocmget(tty, port, serial);
-
mutex_unlock(&qt_port->lock);
return retval;
}
@@ -1486,18 +1432,11 @@ static int qt_tiocmset(struct tty_struct *tty,
struct quatech_port *qt_port = qt_get_port_private(port);
int retval = -ENODEV;
- dbg("In %s\n", __func__);
-
if (!serial)
return -ENODEV;
mutex_lock(&qt_port->lock);
-
- dbg("%s - port %d\n", __func__, port->number);
- dbg("%s - qt_port->RxHolding = %d\n", __func__, qt_port->RxHolding);
-
retval = qt_real_tiocmset(tty, port, serial, set);
-
mutex_unlock(&qt_port->lock);
return retval;
}
@@ -1508,8 +1447,6 @@ static void qt_throttle(struct tty_struct *tty)
struct usb_serial *serial = get_usb_serial(port, __func__);
struct quatech_port *qt_port;
- dbg("%s - port %d\n", __func__, port->number);
-
if (!serial)
return;
@@ -1519,7 +1456,6 @@ static void qt_throttle(struct tty_struct *tty)
/* pass on to the driver specific version of this function */
qt_port->RxHolding = 1;
- dbg("%s - port->RxHolding = 1\n", __func__);
mutex_unlock(&qt_port->lock);
return;
@@ -1539,8 +1475,6 @@ static void qt_unthrottle(struct tty_struct *tty)
mutex_lock(&qt_port->lock);
- dbg("%s - port %d\n", __func__, port->number);
-
if (qt_port->RxHolding == 1) {
dbg("%s -qt_port->RxHolding == 1\n", __func__);
@@ -1559,8 +1493,9 @@ static void qt_unthrottle(struct tty_struct *tty)
qt_read_bulk_callback, port);
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (result)
- err("%s - failed restarting read urb, error %d",
- __func__, result);
+ dev_err(&port->dev,
+ "%s - failed restarting read urb, error %d\n",
+ __func__, result);
}
}
mutex_unlock(&qt_port->lock);
@@ -1589,7 +1524,7 @@ static struct usb_serial_driver quatech_device = {
.name = "serqt",
},
.description = DRIVER_DESC,
- .id_table = serqt_id_table,
+ .id_table = id_table,
.num_ports = 8,
.open = qt_open,
.close = qt_close,
@@ -1612,7 +1547,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&quatech_device, NULL
};
-module_usb_serial_driver(serqt_usb_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/staging/sm7xx/smtcfb.c b/drivers/staging/sm7xx/smtcfb.c
index 83c582ed12e5..746c4cd5d30e 100644
--- a/drivers/staging/sm7xx/smtcfb.c
+++ b/drivers/staging/sm7xx/smtcfb.c
@@ -2,31 +2,19 @@
* Silicon Motion SM7XX frame buffer device
*
* Copyright (C) 2006 Silicon Motion Technology Corp.
- * Authors: Ge Wang, gewang@siliconmotion.com
- * Boyod boyod.yang@siliconmotion.com.cn
+ * Authors: Ge Wang, gewang@siliconmotion.com
+ * Boyod boyod.yang@siliconmotion.com.cn
*
* Copyright (C) 2009 Lemote, Inc.
- * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
*
* Copyright (C) 2011 Igalia, S.L.
- * Author: Javier M. Mellid <jmunhoz@igalia.com>
+ * Author: Javier M. Mellid <jmunhoz@igalia.com>
*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive for
- * more details.
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
*
- * Version 0.10.26192.21.01
- * - Add PowerPC/Big endian support
- * - Verified on 2.6.19.2
- * Boyod.yang <boyod.yang@siliconmotion.com.cn>
- *
- * Version 0.09.2621.00.01
- * - Only support Linux Kernel's version 2.6.21
- * Boyod.yang <boyod.yang@siliconmotion.com.cn>
- *
- * Version 0.09
- * - Only support Linux Kernel's version 2.6.12
- * Boyod.yang <boyod.yang@siliconmotion.com.cn>
*/
#include <linux/io.h>
@@ -45,40 +33,19 @@
#include "smtcfb.h"
-#ifdef DEBUG
-#define smdbg(format, arg...) printk(KERN_DEBUG format , ## arg)
-#else
-#define smdbg(format, arg...)
-#endif
-
struct screen_info smtc_screen_info;
/*
* Private structure
*/
struct smtcfb_info {
- /*
- * The following is a pointer to be passed into the
- * functions below. The modules outside the main
- * voyager.c driver have no knowledge as to what
- * is within this structure.
- */
struct fb_info fb;
- struct display_switch *dispsw;
- struct pci_dev *dev;
- signed int currcon;
-
+ struct pci_dev *pdev;
struct {
u8 red, green, blue;
} palette[NR_RGB];
-
u_int palette_size;
-};
-struct par_info {
- /*
- * Hardware
- */
u16 chipID;
unsigned char __iomem *m_pMMIO;
char __iomem *m_pLFB;
@@ -121,15 +88,6 @@ char __iomem *smtc_RegBaseAddress; /* Memory Map IO starting address */
char __iomem *smtc_VRAMBaseAddress; /* video memory starting address */
static u32 colreg[17];
-static struct par_info hw; /* hardware information */
-
-u16 smtc_ChipIDs[] = {
- 0x710,
- 0x712,
- 0x720
-};
-
-#define numSMTCchipIDs ARRAY_SIZE(smtc_ChipIDs)
static struct fb_var_screeninfo smtcfb_var = {
.xres = 1024,
@@ -154,30 +112,29 @@ static struct fb_fix_screeninfo smtcfb_fix = {
.accel = FB_ACCEL_SMI_LYNX,
};
-static void sm712_set_timing(struct smtcfb_info *sfb,
- struct par_info *ppar_info)
+static void sm712_set_timing(struct smtcfb_info *sfb)
{
int i = 0, j = 0;
u32 m_nScreenStride;
- smdbg("\nppar_info->width = %d ppar_info->height = %d"
- "sfb->fb.var.bits_per_pixel = %d ppar_info->hz = %d\n",
- ppar_info->width, ppar_info->height,
- sfb->fb.var.bits_per_pixel, ppar_info->hz);
+ dev_dbg(&sfb->pdev->dev,
+ "sfb->width=%d sfb->height=%d "
+ "sfb->fb.var.bits_per_pixel=%d sfb->hz=%d\n",
+ sfb->width, sfb->height, sfb->fb.var.bits_per_pixel, sfb->hz);
for (j = 0; j < numVGAModes; j++) {
- if (VGAMode[j].mmSizeX == ppar_info->width &&
- VGAMode[j].mmSizeY == ppar_info->height &&
+ if (VGAMode[j].mmSizeX == sfb->width &&
+ VGAMode[j].mmSizeY == sfb->height &&
VGAMode[j].bpp == sfb->fb.var.bits_per_pixel &&
- VGAMode[j].hz == ppar_info->hz) {
+ VGAMode[j].hz == sfb->hz) {
- smdbg("\nVGAMode[j].mmSizeX = %d VGAMode[j].mmSizeY ="
- "%d VGAMode[j].bpp = %d"
- "VGAMode[j].hz=%d\n",
- VGAMode[j].mmSizeX, VGAMode[j].mmSizeY,
- VGAMode[j].bpp, VGAMode[j].hz);
+ dev_dbg(&sfb->pdev->dev,
+ "VGAMode[j].mmSizeX=%d VGAMode[j].mmSizeY=%d "
+ "VGAMode[j].bpp=%d VGAMode[j].hz=%d\n",
+ VGAMode[j].mmSizeX, VGAMode[j].mmSizeY,
+ VGAMode[j].bpp, VGAMode[j].hz);
- smdbg("VGAMode index=%d\n", j);
+ dev_dbg(&sfb->pdev->dev, "VGAMode index=%d\n", j);
smtc_mmiowb(0x0, 0x3c6);
@@ -238,37 +195,37 @@ static void sm712_set_timing(struct smtcfb_info *sfb,
smtc_mmiowb(0x67, 0x3c2);
/* set VPR registers */
- writel(0x0, ppar_info->m_pVPR + 0x0C);
- writel(0x0, ppar_info->m_pVPR + 0x40);
+ writel(0x0, sfb->m_pVPR + 0x0C);
+ writel(0x0, sfb->m_pVPR + 0x40);
/* set data width */
m_nScreenStride =
- (ppar_info->width * sfb->fb.var.bits_per_pixel) / 64;
+ (sfb->width * sfb->fb.var.bits_per_pixel) / 64;
switch (sfb->fb.var.bits_per_pixel) {
case 8:
- writel(0x0, ppar_info->m_pVPR + 0x0);
+ writel(0x0, sfb->m_pVPR + 0x0);
break;
case 16:
- writel(0x00020000, ppar_info->m_pVPR + 0x0);
+ writel(0x00020000, sfb->m_pVPR + 0x0);
break;
case 24:
- writel(0x00040000, ppar_info->m_pVPR + 0x0);
+ writel(0x00040000, sfb->m_pVPR + 0x0);
break;
case 32:
- writel(0x00030000, ppar_info->m_pVPR + 0x0);
+ writel(0x00030000, sfb->m_pVPR + 0x0);
break;
}
writel((u32) (((m_nScreenStride + 2) << 16) | m_nScreenStride),
- ppar_info->m_pVPR + 0x10);
+ sfb->m_pVPR + 0x10);
}
static void sm712_setpalette(int regno, unsigned red, unsigned green,
unsigned blue, struct fb_info *info)
{
- struct par_info *cur_par = (struct par_info *)info->par;
+ struct smtcfb_info *sfb = info->par;
- if (cur_par->BaseAddressInVRAM)
+ if (sfb->BaseAddressInVRAM)
/*
* second display palette for dual head. Enable CRT RAM, 6-bit
* RAM
@@ -283,14 +240,13 @@ static void sm712_setpalette(int regno, unsigned red, unsigned green,
smtc_mmiowb(blue >> 10, dac_val);
}
-static void smtc_set_timing(struct smtcfb_info *sfb, struct par_info
- *ppar_info)
+static void smtc_set_timing(struct smtcfb_info *sfb)
{
- switch (ppar_info->chipID) {
+ switch (sfb->chipID) {
case 0x710:
case 0x712:
case 0x720:
- sm712_set_timing(sfb, ppar_info);
+ sm712_set_timing(sfb);
break;
}
}
@@ -310,7 +266,7 @@ static inline unsigned int chan_to_field(unsigned int chan,
return chan << bf->offset;
}
-static int cfb_blank(int blank_mode, struct fb_info *info)
+static int smtc_blank(int blank_mode, struct fb_info *info)
{
/* clear DPMS setting */
switch (blank_mode) {
@@ -660,10 +616,10 @@ void smtcfb_setmode(struct smtcfb_info *sfb)
break;
}
- hw.width = sfb->fb.var.xres;
- hw.height = sfb->fb.var.yres;
- hw.hz = 60;
- smtc_set_timing(sfb, &hw);
+ sfb->width = sfb->fb.var.xres;
+ sfb->height = sfb->fb.var.yres;
+ sfb->hz = 60;
+ smtc_set_timing(sfb);
}
static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
@@ -697,7 +653,7 @@ static struct fb_ops smtcfb_ops = {
.fb_check_var = smtc_check_var,
.fb_set_par = smtc_set_par,
.fb_setcolreg = smtc_setcolreg,
- .fb_blank = cfb_blank,
+ .fb_blank = smtc_blank,
.fb_fillrect = cfb_fillrect,
.fb_imageblit = cfb_imageblit,
.fb_copyarea = cfb_copyarea,
@@ -710,8 +666,7 @@ static struct fb_ops smtcfb_ops = {
/*
* Alloc struct smtcfb_info and assign the default value
*/
-static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *dev,
- char *name)
+static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *pdev, char *name)
{
struct smtcfb_info *sfb;
@@ -720,8 +675,7 @@ static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *dev,
if (!sfb)
return NULL;
- sfb->currcon = -1;
- sfb->dev = dev;
+ sfb->pdev = pdev;
/*** Init sfb->fb with default value ***/
sfb->fb.flags = FBINFO_FLAG_DEFAULT;
@@ -745,7 +699,9 @@ static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *dev,
/* text mode acceleration */
sfb->fb.var.accel_flags = FB_ACCELF_TEXT;
sfb->fb.var.vmode = FB_VMODE_NONINTERLACED;
- sfb->fb.par = &hw;
+
+ sfb->fb.par = sfb;
+
sfb->fb.pseudo_palette = colreg;
return sfb;
@@ -766,17 +722,17 @@ static void smtc_unmap_mmio(struct smtcfb_info *sfb)
*/
static int smtc_map_smem(struct smtcfb_info *sfb,
- struct pci_dev *dev, u_long smem_len)
+ struct pci_dev *pdev, u_long smem_len)
{
if (sfb->fb.var.bits_per_pixel == 32) {
#ifdef __BIG_ENDIAN
- sfb->fb.fix.smem_start = pci_resource_start(dev, 0)
+ sfb->fb.fix.smem_start = pci_resource_start(pdev, 0)
+ 0x800000;
#else
- sfb->fb.fix.smem_start = pci_resource_start(dev, 0);
+ sfb->fb.fix.smem_start = pci_resource_start(pdev, 0);
#endif
} else {
- sfb->fb.fix.smem_start = pci_resource_start(dev, 0);
+ sfb->fb.fix.smem_start = pci_resource_start(pdev, 0);
}
sfb->fb.fix.smem_len = smem_len;
@@ -784,8 +740,8 @@ static int smtc_map_smem(struct smtcfb_info *sfb,
sfb->fb.screen_base = smtc_VRAMBaseAddress;
if (!sfb->fb.screen_base) {
- printk(KERN_ERR "%s: unable to map screen memory\n",
- sfb->fb.fix.id);
+ dev_err(&pdev->dev,
+ "%s: unable to map screen memory\n", sfb->fb.fix.id);
return -ENOMEM;
}
@@ -831,16 +787,14 @@ static int __init sm712vga_setup(char *options)
{
int index;
- if (!options || !*options) {
- smdbg("\n No vga parameter\n");
+ if (!options || !*options)
return -EINVAL;
- }
smtc_screen_info.lfb_width = 0;
smtc_screen_info.lfb_height = 0;
smtc_screen_info.lfb_depth = 0;
- smdbg("\nsm712vga_setup = %s\n", options);
+ pr_debug("sm712vga_setup = %s\n", options);
for (index = 0;
index < ARRAY_SIZE(vesa_mode);
@@ -858,10 +812,6 @@ static int __init sm712vga_setup(char *options)
}
__setup("vga=", sm712vga_setup);
-/* Jason (08/13/2009)
- * Original init function changed to probe method to be used by pci_drv
- * process used to detect chips replaced with kernel process in pci_drv
- */
static int __devinit smtcfb_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -871,23 +821,20 @@ static int __devinit smtcfb_pci_probe(struct pci_dev *pdev,
int err;
unsigned long pFramebufferPhysical;
- printk(KERN_INFO
- "Silicon Motion display driver " SMTC_LINUX_FB_VERSION "\n");
+ dev_info(&pdev->dev, "Silicon Motion display driver.");
err = pci_enable_device(pdev); /* enable SMTC chip */
if (err)
return err;
- hw.chipID = ent->device;
- sprintf(name, "sm%Xfb", hw.chipID);
-
sfb = smtc_alloc_fb_info(pdev, name);
if (!sfb)
goto failed_free;
- /* Jason (08/13/2009)
- * Store fb_info to be further used when suspending and resuming
- */
+
+ sfb->chipID = ent->device;
+ sprintf(name, "sm%Xfb", sfb->chipID);
+
pci_set_drvdata(pdev, sfb);
sm7xx_init_hw();
@@ -910,37 +857,37 @@ static int __devinit smtcfb_pci_probe(struct pci_dev *pdev,
#endif
/* Map address and memory detection */
pFramebufferPhysical = pci_resource_start(pdev, 0);
- pci_read_config_byte(pdev, PCI_REVISION_ID, &hw.chipRevID);
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chipRevID);
- switch (hw.chipID) {
+ switch (sfb->chipID) {
case 0x710:
case 0x712:
sfb->fb.fix.mmio_start = pFramebufferPhysical + 0x00400000;
sfb->fb.fix.mmio_len = 0x00400000;
smem_size = SM712_VIDEOMEMORYSIZE;
#ifdef __BIG_ENDIAN
- hw.m_pLFB = (smtc_VRAMBaseAddress =
+ sfb->m_pLFB = (smtc_VRAMBaseAddress =
ioremap(pFramebufferPhysical, 0x00c00000));
#else
- hw.m_pLFB = (smtc_VRAMBaseAddress =
+ sfb->m_pLFB = (smtc_VRAMBaseAddress =
ioremap(pFramebufferPhysical, 0x00800000));
#endif
- hw.m_pMMIO = (smtc_RegBaseAddress =
+ sfb->m_pMMIO = (smtc_RegBaseAddress =
smtc_VRAMBaseAddress + 0x00700000);
- hw.m_pDPR = smtc_VRAMBaseAddress + 0x00408000;
- hw.m_pVPR = hw.m_pLFB + 0x0040c000;
+ sfb->m_pDPR = smtc_VRAMBaseAddress + 0x00408000;
+ sfb->m_pVPR = sfb->m_pLFB + 0x0040c000;
#ifdef __BIG_ENDIAN
if (sfb->fb.var.bits_per_pixel == 32) {
smtc_VRAMBaseAddress += 0x800000;
- hw.m_pLFB += 0x800000;
- printk(KERN_INFO
- "\nsmtc_VRAMBaseAddress=%p hw.m_pLFB=%p\n",
- smtc_VRAMBaseAddress, hw.m_pLFB);
+ sfb->m_pLFB += 0x800000;
+ dev_info(&pdev->dev,
+ "smtc_VRAMBaseAddress=%p sfb->m_pLFB=%p",
+ smtc_VRAMBaseAddress, sfb->m_pLFB);
}
#endif
if (!smtc_RegBaseAddress) {
- printk(KERN_ERR
- "%s: unable to map memory mapped IO\n",
+ dev_err(&pdev->dev,
+ "%s: unable to map memory mapped IO!",
sfb->fb.fix.id);
err = -ENOMEM;
goto failed_fb;
@@ -962,20 +909,20 @@ static int __devinit smtcfb_pci_probe(struct pci_dev *pdev,
sfb->fb.fix.mmio_start = pFramebufferPhysical;
sfb->fb.fix.mmio_len = 0x00200000;
smem_size = SM722_VIDEOMEMORYSIZE;
- hw.m_pDPR = ioremap(pFramebufferPhysical, 0x00a00000);
- hw.m_pLFB = (smtc_VRAMBaseAddress =
- hw.m_pDPR + 0x00200000);
- hw.m_pMMIO = (smtc_RegBaseAddress =
- hw.m_pDPR + 0x000c0000);
- hw.m_pVPR = hw.m_pDPR + 0x800;
+ sfb->m_pDPR = ioremap(pFramebufferPhysical, 0x00a00000);
+ sfb->m_pLFB = (smtc_VRAMBaseAddress =
+ sfb->m_pDPR + 0x00200000);
+ sfb->m_pMMIO = (smtc_RegBaseAddress =
+ sfb->m_pDPR + 0x000c0000);
+ sfb->m_pVPR = sfb->m_pDPR + 0x800;
smtc_seqw(0x62, 0xff);
smtc_seqw(0x6a, 0x0d);
smtc_seqw(0x6b, 0x02);
break;
default:
- printk(KERN_ERR
- "No valid Silicon Motion display chip was detected!\n");
+ dev_err(&pdev->dev,
+ "No valid Silicon Motion display chip was detected!");
goto failed_fb;
}
@@ -992,22 +939,21 @@ static int __devinit smtcfb_pci_probe(struct pci_dev *pdev,
smtcfb_setmode(sfb);
/* Primary display starting from 0 position */
- hw.BaseAddressInVRAM = 0;
- sfb->fb.par = &hw;
+ sfb->BaseAddressInVRAM = 0;
err = register_framebuffer(&sfb->fb);
if (err < 0)
goto failed;
- printk(KERN_INFO "Silicon Motion SM%X Rev%X primary display mode"
- "%dx%d-%d Init Complete.\n", hw.chipID, hw.chipRevID,
- sfb->fb.var.xres, sfb->fb.var.yres,
- sfb->fb.var.bits_per_pixel);
+ dev_info(&pdev->dev,
+ "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.",
+ sfb->chipID, sfb->chipRevID, sfb->fb.var.xres,
+ sfb->fb.var.yres, sfb->fb.var.bits_per_pixel);
return 0;
failed:
- printk(KERN_ERR "Silicon Motion, Inc. primary display init fail\n");
+ dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.");
smtc_unmap_smem(sfb);
smtc_unmap_mmio(sfb);
@@ -1021,7 +967,6 @@ failed_free:
}
-/* Jason (08/11/2009) PCI_DRV wrapper essential structs */
static DEFINE_PCI_DEVICE_TABLE(smtcfb_pci_table) = {
{ PCI_DEVICE(0x126f, 0x710), },
{ PCI_DEVICE(0x126f, 0x712), },
@@ -1030,9 +975,6 @@ static DEFINE_PCI_DEVICE_TABLE(smtcfb_pci_table) = {
};
-/* Jason (08/14/2009)
- * do some clean up when the driver module is removed
- */
static void __devexit smtcfb_pci_remove(struct pci_dev *pdev)
{
struct smtcfb_info *sfb;
@@ -1078,7 +1020,7 @@ static int smtcfb_pci_resume(struct device *device)
/* reinit hardware */
sm7xx_init_hw();
- switch (hw.chipID) {
+ switch (sfb->chipID) {
case 0x710:
case 0x712:
/* set MCLK = 14.31818 * (0x16 / 0x2) */
diff --git a/drivers/staging/sm7xx/smtcfb.h b/drivers/staging/sm7xx/smtcfb.h
index ab95af2b9c07..43d86f873410 100644
--- a/drivers/staging/sm7xx/smtcfb.h
+++ b/drivers/staging/sm7xx/smtcfb.h
@@ -13,19 +13,11 @@
* more details.
*/
-#define SMTC_LINUX_FB_VERSION "version 0.11.2619.21.01 July 27, 2008"
-
#define NR_PALETTE 256
#define NR_RGB 2
#define FB_ACCEL_SMI_LYNX 88
-#ifdef __BIG_ENDIAN
-#define PC_VGA 0
-#else
-#define PC_VGA 1
-#endif
-
#define SCREEN_X_RES 1024
#define SCREEN_Y_RES 600
#define SCREEN_BPP 16
diff --git a/drivers/staging/telephony/ixj.c b/drivers/staging/telephony/ixj.c
index f96027921f60..fd7757ad7fa3 100644
--- a/drivers/staging/telephony/ixj.c
+++ b/drivers/staging/telephony/ixj.c
@@ -19,20 +19,20 @@
* David W. Erhart, <derhart@quicknet.net>
* John Sellers, <jsellers@quicknet.net>
* Mike Preston, <mpreston@quicknet.net>
- *
+ *
* Fixes: David Huggins-Daines, <dhd@cepstral.com>
* Fabio Ferrari, <fabio.ferrari@digitro.com.br>
* Artis Kugevics, <artis@mt.lv>
* Daniele Bellucci, <bellucda@tiscali.it>
*
- * More information about the hardware related to this driver can be found
+ * More information about the hardware related to this driver can be found
* at our website: http://www.quicknet.net
*
* IN NO EVENT SHALL QUICKNET TECHNOLOGIES, INC. BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
* OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF QUICKNET
* TECHNOLOGIES, INC. HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
+ *
* QUICKNET TECHNOLOGIES, INC. SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
@@ -317,7 +317,7 @@ static IXJ *ixj[IXJMAX];
/*
* Allocate a free IXJ device
*/
-
+
static IXJ *ixj_alloc()
{
for(cnt=0; cnt<IXJMAX; cnt++)
@@ -366,7 +366,7 @@ static IXJ ixj[IXJMAX];
/*
* Allocate a free IXJ device
*/
-
+
static IXJ *ixj_alloc(void)
{
int cnt;
@@ -1084,7 +1084,7 @@ static void ixj_pstn_state(IXJ *j)
printk(KERN_INFO "IXJ /dev/phone%d Next Ring Cadence state at %u min %ld - %ld - max %ld\n", j->board,
j->cadence_f[4].on3, j->cadence_f[4].on3min, j->cadence_f[4].on3dot, j->cadence_f[4].on3max);
break;
- case 6:
+ case 6:
printk(KERN_INFO "IXJ /dev/phone%d Next Ring Cadence state at %u min %ld - %ld - max %ld\n", j->board,
j->cadence_f[4].off3, j->cadence_f[4].off3min, j->cadence_f[4].off3dot, j->cadence_f[4].off3max);
break;
@@ -1109,7 +1109,7 @@ static void ixj_pstn_state(IXJ *j)
}
j->pstn_ring_stop = j->pstn_ring_int = 0;
daa_set_mode(j, SOP_PU_SLEEP);
- }
+ }
outb_p(j->pld_scrw.byte, j->XILINXbase);
if (j->pstn_cid_intr && time_after(jiffies, j->pstn_cid_received + hertz)) {
ixj_daa_cid_read(j);
@@ -1133,7 +1133,7 @@ static void ixj_pstn_state(IXJ *j)
printk("IXJ DAA possible wink /dev/phone%d %ld\n", j->board, jiffies);
}
j->pstn_winkstart = jiffies;
- }
+ }
} else {
if (j->pstn_winkstart) {
if(ixjdebug & 0x0008) {
@@ -1524,7 +1524,7 @@ static inline void LED_SetState(int state, IXJ *j)
/*********************************************************************
* GPIO Pins are configured as follows on the Quicknet Internet
* PhoneJACK Telephony Cards
-*
+*
* POTS Select GPIO_6=0 GPIO_7=0
* Mic/Speaker Select GPIO_6=0 GPIO_7=1
* Handset Select GPIO_6=1 GPIO_7=0
@@ -1932,7 +1932,7 @@ static int ixj_hookstate(IXJ *j)
if(fOffHook != j->p_hook) {
if(!j->checkwait) {
j->checkwait = jiffies;
- }
+ }
if(time_before(jiffies, j->checkwait + 2)) {
fOffHook ^= 1;
} else {
@@ -2342,8 +2342,8 @@ static int ixj_release(struct inode *inode, struct file *file_p)
j->ixj_signals[cnt] = SIGIO;
/* Set the excetion signal enable flags */
- j->ex_sig.bits.dtmf_ready = j->ex_sig.bits.hookstate = j->ex_sig.bits.flash = j->ex_sig.bits.pstn_ring =
- j->ex_sig.bits.caller_id = j->ex_sig.bits.pstn_wink = j->ex_sig.bits.f0 = j->ex_sig.bits.f1 = j->ex_sig.bits.f2 =
+ j->ex_sig.bits.dtmf_ready = j->ex_sig.bits.hookstate = j->ex_sig.bits.flash = j->ex_sig.bits.pstn_ring =
+ j->ex_sig.bits.caller_id = j->ex_sig.bits.pstn_wink = j->ex_sig.bits.f0 = j->ex_sig.bits.f1 = j->ex_sig.bits.f2 =
j->ex_sig.bits.f3 = j->ex_sig.bits.fc0 = j->ex_sig.bits.fc1 = j->ex_sig.bits.fc2 = j->ex_sig.bits.fc3 = 1;
file_p->private_data = NULL;
@@ -2506,7 +2506,7 @@ static int read_filters(IXJ *j)
j->cadence_f[cnt].on1, j->cadence_f[cnt].on1min, j->cadence_f[cnt].on1dot, j->cadence_f[cnt].on1max);
break;
case 2:
- printk(KERN_INFO "IXJ /dev/phone%d Next Tone Cadence state at %ld - %ld\n", j->board, j->cadence_f[cnt].off1min,
+ printk(KERN_INFO "IXJ /dev/phone%d Next Tone Cadence state at %ld - %ld\n", j->board, j->cadence_f[cnt].off1min,
j->cadence_f[cnt].off1max);
break;
case 3:
@@ -2521,12 +2521,12 @@ static int read_filters(IXJ *j)
printk(KERN_INFO "IXJ /dev/phone%d Next Tone Cadence state at %ld - %ld\n", j->board, j->cadence_f[cnt].on3min,
j->cadence_f[cnt].on3max);
break;
- case 6:
+ case 6:
printk(KERN_INFO "IXJ /dev/phone%d Next Tone Cadence state at %ld - %ld\n", j->board, j->cadence_f[cnt].off3min,
j->cadence_f[cnt].off3max);
break;
}
- }
+ }
}
if (j->cadence_f[cnt].state == 7) {
j->cadence_f[cnt].state = 0;
@@ -2656,37 +2656,37 @@ static void ulaw2alaw(unsigned char *buff, unsigned long len)
{
static unsigned char table_ulaw2alaw[] =
{
- 0x2A, 0x2B, 0x28, 0x29, 0x2E, 0x2F, 0x2C, 0x2D,
- 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
- 0x3A, 0x3B, 0x38, 0x39, 0x3E, 0x3F, 0x3C, 0x3D,
- 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
- 0x0B, 0x08, 0x09, 0x0E, 0x0F, 0x0C, 0x0D, 0x02,
- 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x1A,
- 0x1B, 0x18, 0x19, 0x1E, 0x1F, 0x1C, 0x1D, 0x12,
- 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x6B,
- 0x68, 0x69, 0x6E, 0x6F, 0x6C, 0x6D, 0x62, 0x63,
- 0x60, 0x61, 0x66, 0x67, 0x64, 0x65, 0x7B, 0x79,
- 0x7E, 0x7F, 0x7C, 0x7D, 0x72, 0x73, 0x70, 0x71,
- 0x76, 0x77, 0x74, 0x75, 0x4B, 0x49, 0x4F, 0x4D,
- 0x42, 0x43, 0x40, 0x41, 0x46, 0x47, 0x44, 0x45,
- 0x5A, 0x5B, 0x58, 0x59, 0x5E, 0x5F, 0x5C, 0x5D,
- 0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51,
- 0x56, 0x56, 0x57, 0x57, 0x54, 0x54, 0x55, 0xD5,
- 0xAA, 0xAB, 0xA8, 0xA9, 0xAE, 0xAF, 0xAC, 0xAD,
- 0xA2, 0xA3, 0xA0, 0xA1, 0xA6, 0xA7, 0xA4, 0xA5,
- 0xBA, 0xBB, 0xB8, 0xB9, 0xBE, 0xBF, 0xBC, 0xBD,
- 0xB2, 0xB3, 0xB0, 0xB1, 0xB6, 0xB7, 0xB4, 0xB5,
- 0x8B, 0x88, 0x89, 0x8E, 0x8F, 0x8C, 0x8D, 0x82,
- 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85, 0x9A,
- 0x9B, 0x98, 0x99, 0x9E, 0x9F, 0x9C, 0x9D, 0x92,
- 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95, 0xEB,
- 0xE8, 0xE9, 0xEE, 0xEF, 0xEC, 0xED, 0xE2, 0xE3,
- 0xE0, 0xE1, 0xE6, 0xE7, 0xE4, 0xE5, 0xFB, 0xF9,
- 0xFE, 0xFF, 0xFC, 0xFD, 0xF2, 0xF3, 0xF0, 0xF1,
- 0xF6, 0xF7, 0xF4, 0xF5, 0xCB, 0xC9, 0xCF, 0xCD,
- 0xC2, 0xC3, 0xC0, 0xC1, 0xC6, 0xC7, 0xC4, 0xC5,
- 0xDA, 0xDB, 0xD8, 0xD9, 0xDE, 0xDF, 0xDC, 0xDD,
- 0xD2, 0xD2, 0xD3, 0xD3, 0xD0, 0xD0, 0xD1, 0xD1,
+ 0x2A, 0x2B, 0x28, 0x29, 0x2E, 0x2F, 0x2C, 0x2D,
+ 0x22, 0x23, 0x20, 0x21, 0x26, 0x27, 0x24, 0x25,
+ 0x3A, 0x3B, 0x38, 0x39, 0x3E, 0x3F, 0x3C, 0x3D,
+ 0x32, 0x33, 0x30, 0x31, 0x36, 0x37, 0x34, 0x35,
+ 0x0B, 0x08, 0x09, 0x0E, 0x0F, 0x0C, 0x0D, 0x02,
+ 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05, 0x1A,
+ 0x1B, 0x18, 0x19, 0x1E, 0x1F, 0x1C, 0x1D, 0x12,
+ 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15, 0x6B,
+ 0x68, 0x69, 0x6E, 0x6F, 0x6C, 0x6D, 0x62, 0x63,
+ 0x60, 0x61, 0x66, 0x67, 0x64, 0x65, 0x7B, 0x79,
+ 0x7E, 0x7F, 0x7C, 0x7D, 0x72, 0x73, 0x70, 0x71,
+ 0x76, 0x77, 0x74, 0x75, 0x4B, 0x49, 0x4F, 0x4D,
+ 0x42, 0x43, 0x40, 0x41, 0x46, 0x47, 0x44, 0x45,
+ 0x5A, 0x5B, 0x58, 0x59, 0x5E, 0x5F, 0x5C, 0x5D,
+ 0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51,
+ 0x56, 0x56, 0x57, 0x57, 0x54, 0x54, 0x55, 0xD5,
+ 0xAA, 0xAB, 0xA8, 0xA9, 0xAE, 0xAF, 0xAC, 0xAD,
+ 0xA2, 0xA3, 0xA0, 0xA1, 0xA6, 0xA7, 0xA4, 0xA5,
+ 0xBA, 0xBB, 0xB8, 0xB9, 0xBE, 0xBF, 0xBC, 0xBD,
+ 0xB2, 0xB3, 0xB0, 0xB1, 0xB6, 0xB7, 0xB4, 0xB5,
+ 0x8B, 0x88, 0x89, 0x8E, 0x8F, 0x8C, 0x8D, 0x82,
+ 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85, 0x9A,
+ 0x9B, 0x98, 0x99, 0x9E, 0x9F, 0x9C, 0x9D, 0x92,
+ 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95, 0xEB,
+ 0xE8, 0xE9, 0xEE, 0xEF, 0xEC, 0xED, 0xE2, 0xE3,
+ 0xE0, 0xE1, 0xE6, 0xE7, 0xE4, 0xE5, 0xFB, 0xF9,
+ 0xFE, 0xFF, 0xFC, 0xFD, 0xF2, 0xF3, 0xF0, 0xF1,
+ 0xF6, 0xF7, 0xF4, 0xF5, 0xCB, 0xC9, 0xCF, 0xCD,
+ 0xC2, 0xC3, 0xC0, 0xC1, 0xC6, 0xC7, 0xC4, 0xC5,
+ 0xDA, 0xDB, 0xD8, 0xD9, 0xDE, 0xDF, 0xDC, 0xDD,
+ 0xD2, 0xD2, 0xD3, 0xD3, 0xD0, 0xD0, 0xD1, 0xD1,
0xD6, 0xD6, 0xD7, 0xD7, 0xD4, 0xD4, 0xD5, 0xD5
};
@@ -2701,37 +2701,37 @@ static void alaw2ulaw(unsigned char *buff, unsigned long len)
{
static unsigned char table_alaw2ulaw[] =
{
- 0x29, 0x2A, 0x27, 0x28, 0x2D, 0x2E, 0x2B, 0x2C,
- 0x21, 0x22, 0x1F, 0x20, 0x25, 0x26, 0x23, 0x24,
- 0x39, 0x3A, 0x37, 0x38, 0x3D, 0x3E, 0x3B, 0x3C,
- 0x31, 0x32, 0x2F, 0x30, 0x35, 0x36, 0x33, 0x34,
- 0x0A, 0x0B, 0x08, 0x09, 0x0E, 0x0F, 0x0C, 0x0D,
- 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
- 0x1A, 0x1B, 0x18, 0x19, 0x1E, 0x1F, 0x1C, 0x1D,
- 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
- 0x62, 0x63, 0x60, 0x61, 0x66, 0x67, 0x64, 0x65,
- 0x5D, 0x5D, 0x5C, 0x5C, 0x5F, 0x5F, 0x5E, 0x5E,
- 0x74, 0x76, 0x70, 0x72, 0x7C, 0x7E, 0x78, 0x7A,
- 0x6A, 0x6B, 0x68, 0x69, 0x6E, 0x6F, 0x6C, 0x6D,
- 0x48, 0x49, 0x46, 0x47, 0x4C, 0x4D, 0x4A, 0x4B,
- 0x40, 0x41, 0x3F, 0x3F, 0x44, 0x45, 0x42, 0x43,
- 0x56, 0x57, 0x54, 0x55, 0x5A, 0x5B, 0x58, 0x59,
- 0x4F, 0x4F, 0x4E, 0x4E, 0x52, 0x53, 0x50, 0x51,
- 0xA9, 0xAA, 0xA7, 0xA8, 0xAD, 0xAE, 0xAB, 0xAC,
- 0xA1, 0xA2, 0x9F, 0xA0, 0xA5, 0xA6, 0xA3, 0xA4,
- 0xB9, 0xBA, 0xB7, 0xB8, 0xBD, 0xBE, 0xBB, 0xBC,
- 0xB1, 0xB2, 0xAF, 0xB0, 0xB5, 0xB6, 0xB3, 0xB4,
- 0x8A, 0x8B, 0x88, 0x89, 0x8E, 0x8F, 0x8C, 0x8D,
- 0x82, 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85,
- 0x9A, 0x9B, 0x98, 0x99, 0x9E, 0x9F, 0x9C, 0x9D,
- 0x92, 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95,
- 0xE2, 0xE3, 0xE0, 0xE1, 0xE6, 0xE7, 0xE4, 0xE5,
- 0xDD, 0xDD, 0xDC, 0xDC, 0xDF, 0xDF, 0xDE, 0xDE,
- 0xF4, 0xF6, 0xF0, 0xF2, 0xFC, 0xFE, 0xF8, 0xFA,
- 0xEA, 0xEB, 0xE8, 0xE9, 0xEE, 0xEF, 0xEC, 0xED,
- 0xC8, 0xC9, 0xC6, 0xC7, 0xCC, 0xCD, 0xCA, 0xCB,
- 0xC0, 0xC1, 0xBF, 0xBF, 0xC4, 0xC5, 0xC2, 0xC3,
- 0xD6, 0xD7, 0xD4, 0xD5, 0xDA, 0xDB, 0xD8, 0xD9,
+ 0x29, 0x2A, 0x27, 0x28, 0x2D, 0x2E, 0x2B, 0x2C,
+ 0x21, 0x22, 0x1F, 0x20, 0x25, 0x26, 0x23, 0x24,
+ 0x39, 0x3A, 0x37, 0x38, 0x3D, 0x3E, 0x3B, 0x3C,
+ 0x31, 0x32, 0x2F, 0x30, 0x35, 0x36, 0x33, 0x34,
+ 0x0A, 0x0B, 0x08, 0x09, 0x0E, 0x0F, 0x0C, 0x0D,
+ 0x02, 0x03, 0x00, 0x01, 0x06, 0x07, 0x04, 0x05,
+ 0x1A, 0x1B, 0x18, 0x19, 0x1E, 0x1F, 0x1C, 0x1D,
+ 0x12, 0x13, 0x10, 0x11, 0x16, 0x17, 0x14, 0x15,
+ 0x62, 0x63, 0x60, 0x61, 0x66, 0x67, 0x64, 0x65,
+ 0x5D, 0x5D, 0x5C, 0x5C, 0x5F, 0x5F, 0x5E, 0x5E,
+ 0x74, 0x76, 0x70, 0x72, 0x7C, 0x7E, 0x78, 0x7A,
+ 0x6A, 0x6B, 0x68, 0x69, 0x6E, 0x6F, 0x6C, 0x6D,
+ 0x48, 0x49, 0x46, 0x47, 0x4C, 0x4D, 0x4A, 0x4B,
+ 0x40, 0x41, 0x3F, 0x3F, 0x44, 0x45, 0x42, 0x43,
+ 0x56, 0x57, 0x54, 0x55, 0x5A, 0x5B, 0x58, 0x59,
+ 0x4F, 0x4F, 0x4E, 0x4E, 0x52, 0x53, 0x50, 0x51,
+ 0xA9, 0xAA, 0xA7, 0xA8, 0xAD, 0xAE, 0xAB, 0xAC,
+ 0xA1, 0xA2, 0x9F, 0xA0, 0xA5, 0xA6, 0xA3, 0xA4,
+ 0xB9, 0xBA, 0xB7, 0xB8, 0xBD, 0xBE, 0xBB, 0xBC,
+ 0xB1, 0xB2, 0xAF, 0xB0, 0xB5, 0xB6, 0xB3, 0xB4,
+ 0x8A, 0x8B, 0x88, 0x89, 0x8E, 0x8F, 0x8C, 0x8D,
+ 0x82, 0x83, 0x80, 0x81, 0x86, 0x87, 0x84, 0x85,
+ 0x9A, 0x9B, 0x98, 0x99, 0x9E, 0x9F, 0x9C, 0x9D,
+ 0x92, 0x93, 0x90, 0x91, 0x96, 0x97, 0x94, 0x95,
+ 0xE2, 0xE3, 0xE0, 0xE1, 0xE6, 0xE7, 0xE4, 0xE5,
+ 0xDD, 0xDD, 0xDC, 0xDC, 0xDF, 0xDF, 0xDE, 0xDE,
+ 0xF4, 0xF6, 0xF0, 0xF2, 0xFC, 0xFE, 0xF8, 0xFA,
+ 0xEA, 0xEB, 0xE8, 0xE9, 0xEE, 0xEF, 0xEC, 0xED,
+ 0xC8, 0xC9, 0xC6, 0xC7, 0xCC, 0xCD, 0xCA, 0xCB,
+ 0xC0, 0xC1, 0xBF, 0xBF, 0xC4, 0xC5, 0xC2, 0xC3,
+ 0xD6, 0xD7, 0xD4, 0xD5, 0xDA, 0xDB, 0xD8, 0xD9,
0xCF, 0xCF, 0xCE, 0xCE, 0xD2, 0xD3, 0xD0, 0xD1
};
@@ -3090,7 +3090,7 @@ static int ixj_write_cid_string(IXJ *j, char *s, int checksum)
static void ixj_pad_fsk(IXJ *j, int pad)
{
- int cnt;
+ int cnt;
for (cnt = 0; cnt < pad; cnt++) {
if(j->fskdcnt < (j->fsksize - 1))
@@ -3474,7 +3474,7 @@ static void ixj_write_frame(IXJ *j)
ixj_post_cid(j);
}
/* This may seem rude, but if we just played one frame of FSK data for CallerID
- and there is real audio data in the buffer, we need to throw it away because
+ and there is real audio data in the buffer, we need to throw it away because
we just used it's time slot */
if (j->write_buffer_rp > j->write_buffer_wp) {
j->write_buffer_rp += j->cid_play_frame_size * 2;
@@ -3486,7 +3486,7 @@ static void ixj_write_frame(IXJ *j)
wake_up_interruptible(&j->poll_q); /* Wake any blocked selects */
}
- } else if (j->write_buffer && j->write_buffers_empty < 1) {
+ } else if (j->write_buffer && j->write_buffers_empty < 1) {
if (j->write_buffer_wp > j->write_buffer_rp) {
frame_count =
(j->write_buffer_wp - j->write_buffer_rp) / (j->play_frame_size * 2);
@@ -4150,7 +4150,7 @@ static void ixj_aec_start(IXJ *j, int level)
ixj_WriteDSPCommand(0xCF97, j); /* Set AGC Enable */
ixj_WriteDSPCommand(0x0000, j); /* to off */
-
+
break;
case AEC_MED:
@@ -4161,7 +4161,7 @@ static void ixj_aec_start(IXJ *j, int level)
ixj_WriteDSPCommand(0xCF97, j); /* Set AGC Enable */
ixj_WriteDSPCommand(0x0000, j); /* to off */
-
+
break;
case AEC_HIGH:
@@ -4172,7 +4172,7 @@ static void ixj_aec_start(IXJ *j, int level)
ixj_WriteDSPCommand(0xCF97, j); /* Set AGC Enable */
ixj_WriteDSPCommand(0x0000, j); /* to off */
-
+
break;
case AEC_AGC:
@@ -4197,28 +4197,28 @@ static void ixj_aec_start(IXJ *j, int level)
/* Now we can set the AGC initial parameters and turn it on */
ixj_WriteDSPCommand(0xCF90, j); /* Set AGC Minimum gain */
ixj_WriteDSPCommand(0x0020, j); /* to 0.125 (-18dB) */
-
+
ixj_WriteDSPCommand(0xCF91, j); /* Set AGC Maximum gain */
ixj_WriteDSPCommand(0x1000, j); /* to 16 (24dB) */
-
+
ixj_WriteDSPCommand(0xCF92, j); /* Set AGC start gain */
ixj_WriteDSPCommand(0x0800, j); /* to 8 (+18dB) */
-
+
ixj_WriteDSPCommand(0xCF93, j); /* Set AGC hold time */
ixj_WriteDSPCommand(0x1F40, j); /* to 2 seconds (units are 250us) */
-
+
ixj_WriteDSPCommand(0xCF94, j); /* Set AGC Attack Time Constant */
ixj_WriteDSPCommand(0x0005, j); /* to 8ms */
-
+
ixj_WriteDSPCommand(0xCF95, j); /* Set AGC Decay Time Constant */
ixj_WriteDSPCommand(0x000D, j); /* to 4096ms */
-
+
ixj_WriteDSPCommand(0xCF96, j); /* Set AGC Attack Threshold */
ixj_WriteDSPCommand(0x1200, j); /* to 25% */
-
+
ixj_WriteDSPCommand(0xCF97, j); /* Set AGC Enable */
ixj_WriteDSPCommand(0x0001, j); /* to on */
-
+
break;
case AEC_AUTO:
@@ -4495,7 +4495,7 @@ static int ixj_play_start(IXJ *j)
return -ENOMEM;
}
/* j->write_buffers_empty = 2; */
- j->write_buffers_empty = 1;
+ j->write_buffers_empty = 1;
j->write_buffer_size = j->play_frame_size * 2;
j->write_buffer_end = j->write_buffer + j->play_frame_size * 2;
j->write_buffer_rp = j->write_buffer_wp = j->write_buffer;
@@ -6465,9 +6465,9 @@ static long do_ixj_ioctl(struct file *file_p, unsigned int cmd, unsigned long ar
ixj_ringback(j);
break;
case PHONE_WINK:
- if(j->cardtype == QTI_PHONEJACK)
+ if(j->cardtype == QTI_PHONEJACK)
retval = -1;
- else
+ else
retval = ixj_wink(j);
break;
case PHONE_CPT_STOP:
@@ -6553,7 +6553,7 @@ static long do_ixj_ioctl(struct file *file_p, unsigned int cmd, unsigned long ar
ixj_write_vmwi(j, arg);
break;
case IXJCTL_CID:
- if (copy_to_user(argp, &j->cid, sizeof(PHONE_CID)))
+ if (copy_to_user(argp, &j->cid, sizeof(PHONE_CID)))
retval = -EFAULT;
j->ex.bits.caller_id = 0;
break;
@@ -6575,13 +6575,13 @@ static long do_ixj_ioctl(struct file *file_p, unsigned int cmd, unsigned long ar
break;
case PHONE_CAPABILITIES_LIST:
add_caps(j);
- if (copy_to_user(argp, j->caplist, sizeof(struct phone_capability) * j->caps))
+ if (copy_to_user(argp, j->caplist, sizeof(struct phone_capability) * j->caps))
retval = -EFAULT;
break;
case PHONE_CAPABILITIES_CHECK:
{
struct phone_capability cap;
- if (copy_from_user(&cap, argp, sizeof(cap)))
+ if (copy_from_user(&cap, argp, sizeof(cap)))
retval = -EFAULT;
else {
add_caps(j);
@@ -6597,13 +6597,13 @@ static long do_ixj_ioctl(struct file *file_p, unsigned int cmd, unsigned long ar
j->ex.bits.pstn_ring = 0;
break;
case IXJCTL_SET_FILTER:
- if (copy_from_user(&jf, argp, sizeof(jf)))
+ if (copy_from_user(&jf, argp, sizeof(jf)))
retval = -EFAULT;
else
retval = ixj_init_filter(j, &jf);
break;
case IXJCTL_SET_FILTER_RAW:
- if (copy_from_user(&jfr, argp, sizeof(jfr)))
+ if (copy_from_user(&jfr, argp, sizeof(jfr)))
retval = -EFAULT;
else
retval = ixj_init_filter_raw(j, &jfr);
@@ -6638,9 +6638,9 @@ static long do_ixj_ioctl(struct file *file_p, unsigned int cmd, unsigned long ar
raise *= 2;
}
if(j->sigdef.signal)
- j->ex_sig.bytes |= raise;
+ j->ex_sig.bytes |= raise;
else
- j->ex_sig.bytes &= (raise^0xffff);
+ j->ex_sig.bytes &= (raise^0xffff);
}
break;
case IXJCTL_INTERCOM_STOP:
@@ -7040,9 +7040,9 @@ static int ixj_selfprobe(IXJ *j)
/* initialise the DTMF prescale to a sensible value */
if (j->cardtype == QTI_LINEJACK) {
- set_dtmf_prescale(j, 0x10);
+ set_dtmf_prescale(j, 0x10);
} else {
- set_dtmf_prescale(j, 0x40);
+ set_dtmf_prescale(j, 0x40);
}
set_play_volume(j, 0x100);
set_rec_volume(j, 0x100);
@@ -7095,15 +7095,15 @@ static int ixj_selfprobe(IXJ *j)
j->ixj_signals[cnt] = SIGIO;
/* Set the excetion signal enable flags */
- j->ex_sig.bits.dtmf_ready = j->ex_sig.bits.hookstate = j->ex_sig.bits.flash = j->ex_sig.bits.pstn_ring =
- j->ex_sig.bits.caller_id = j->ex_sig.bits.pstn_wink = j->ex_sig.bits.f0 = j->ex_sig.bits.f1 = j->ex_sig.bits.f2 =
+ j->ex_sig.bits.dtmf_ready = j->ex_sig.bits.hookstate = j->ex_sig.bits.flash = j->ex_sig.bits.pstn_ring =
+ j->ex_sig.bits.caller_id = j->ex_sig.bits.pstn_wink = j->ex_sig.bits.f0 = j->ex_sig.bits.f1 = j->ex_sig.bits.f2 =
j->ex_sig.bits.f3 = j->ex_sig.bits.fc0 = j->ex_sig.bits.fc1 = j->ex_sig.bits.fc2 = j->ex_sig.bits.fc3 = 1;
#ifdef IXJ_DYN_ALLOC
j->fskdata = NULL;
#endif
j->fskdcnt = 0;
j->cidcw_wait = 0;
-
+
/* Register with the Telephony for Linux subsystem */
j->p.f_op = &ixj_fops;
j->p.open = ixj_open;
@@ -7118,7 +7118,7 @@ static int ixj_selfprobe(IXJ *j)
/*
* Exported service for pcmcia card handling
*/
-
+
IXJ *ixj_pcmcia_probe(unsigned long dsp, unsigned long xilinx)
{
IXJ *j = ixj_alloc();
@@ -7320,7 +7320,7 @@ static int ixj_get_status_proc(char *buf)
len += sprintf(buf + len, "\nRec volume 0x%x", get_rec_volume(j));
len += sprintf(buf + len, "\nPlay volume 0x%x", get_play_volume(j));
len += sprintf(buf + len, "\nDTMF prescale 0x%x", get_dtmf_prescale(j));
-
+
len += sprintf(buf + len, "\nHook state %d", j->hookstate); /* j->r_hook); */
if (j->cardtype == QTI_LINEJACK) {
@@ -7417,7 +7417,7 @@ static int ixj_get_status_proc(char *buf)
len += sprintf(buf + len, "\nPControl Wait Fails %ld", j->pcontrolwaitfail);
len += sprintf(buf + len, "\nIs Control Ready Checks %ld", j->iscontrolready);
len += sprintf(buf + len, "\nIs Control Ready Check failures %ld", j->iscontrolreadyfail);
-
+
#endif
len += sprintf(buf + len, "\n");
}
@@ -7608,7 +7608,7 @@ static IXJ *new_ixj(unsigned long port)
}
static int __init ixj_probe_isapnp(int *cnt)
-{
+{
int probe = 0;
int func = 0x110;
struct pnp_dev *dev = NULL, *old_dev = NULL;
@@ -7686,7 +7686,7 @@ static int __init ixj_probe_isapnp(int *cnt)
}
return probe;
}
-
+
static int __init ixj_probe_isa(int *cnt)
{
int i, probe;
@@ -7713,7 +7713,7 @@ static int __init ixj_probe_isa(int *cnt)
static int __init ixj_probe_pci(int *cnt)
{
- struct pci_dev *pci = NULL;
+ struct pci_dev *pci = NULL;
int i, probe = 0;
IXJ *j = NULL;
@@ -7745,7 +7745,7 @@ static int __init ixj_probe_pci(int *cnt)
static int __init ixj_init(void)
{
int cnt = 0;
- int probe = 0;
+ int probe = 0;
cnt = 0;
@@ -7887,7 +7887,7 @@ static void DAA_Coeff_US(IXJ *j)
/* j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[2] = 0x2D; */
/* j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[1] = 0x62; */
/* j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_1[0] = 0x2D; */
- /* Bytes for Ringing part 2 (06):13,42,A6,BA,D4,73,CA,D5 */
+ /* Bytes for Ringing part 2 (06):13,42,A6,BA,D4,73,CA,D5 */
/* j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[7] = 0x2D; */
/* j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[6] = 0x62; */
/* j->m_DAAShadowRegs.COP_REGS.COP.RingerImpendance_2[5] = 0xA6; */
diff --git a/drivers/staging/tidspbridge/core/io_sm.c b/drivers/staging/tidspbridge/core/io_sm.c
index 9b50b5bd4edb..c51f651dfd1b 100644
--- a/drivers/staging/tidspbridge/core/io_sm.c
+++ b/drivers/staging/tidspbridge/core/io_sm.c
@@ -2212,7 +2212,7 @@ void dump_dl_modules(struct bridge_dev_context *bridge_context)
if (status) {
pr_debug(
- "%s: Failed to read dll_module stuct for 0x%x.\n",
+ "%s: Failed to read dll_module struct for 0x%x.\n",
__func__, module_dsp_addr);
break;
}
diff --git a/drivers/staging/tidspbridge/core/ue_deh.c b/drivers/staging/tidspbridge/core/ue_deh.c
index 006ffd752895..3d28b2345fbd 100644
--- a/drivers/staging/tidspbridge/core/ue_deh.c
+++ b/drivers/staging/tidspbridge/core/ue_deh.c
@@ -215,7 +215,7 @@ static inline const char *event_to_string(int event)
case DSP_MMUFAULT: return "DSP_MMUFAULT"; break;
case DSP_PWRERROR: return "DSP_PWRERROR"; break;
case DSP_WDTOVERFLOW: return "DSP_WDTOVERFLOW"; break;
- default: return "unkown event"; break;
+ default: return "unknown event"; break;
}
}
diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c
index fa870e3f7f6a..92ced35e6b7f 100644
--- a/drivers/staging/usbip/stub_dev.c
+++ b/drivers/staging/usbip/stub_dev.c
@@ -113,8 +113,8 @@ static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr,
spin_unlock(&sdev->ud.lock);
- sdev->ud.tcp_rx = kthread_run(stub_rx_loop, &sdev->ud, "stub_rx");
- sdev->ud.tcp_tx = kthread_run(stub_tx_loop, &sdev->ud, "stub_tx");
+ sdev->ud.tcp_rx = kthread_get_run(stub_rx_loop, &sdev->ud, "stub_rx");
+ sdev->ud.tcp_tx = kthread_get_run(stub_tx_loop, &sdev->ud, "stub_tx");
spin_lock(&sdev->ud.lock);
sdev->ud.status = SDEV_ST_USED;
@@ -187,10 +187,10 @@ static void stub_shutdown_connection(struct usbip_device *ud)
}
/* 1. stop threads */
- if (ud->tcp_rx && !task_is_dead(ud->tcp_rx))
- kthread_stop(ud->tcp_rx);
- if (ud->tcp_tx && !task_is_dead(ud->tcp_tx))
- kthread_stop(ud->tcp_tx);
+ if (ud->tcp_rx)
+ kthread_stop_put(ud->tcp_rx);
+ if (ud->tcp_tx)
+ kthread_stop_put(ud->tcp_tx);
/*
* 2. close the socket
diff --git a/drivers/staging/usbip/usbip_common.h b/drivers/staging/usbip/usbip_common.h
index c7b888ca54f5..5d89c0fd6f7b 100644
--- a/drivers/staging/usbip/usbip_common.h
+++ b/drivers/staging/usbip/usbip_common.h
@@ -292,6 +292,23 @@ struct usbip_device {
} eh_ops;
};
+#define kthread_get_run(threadfn, data, namefmt, ...) \
+({ \
+ struct task_struct *__k \
+ = kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
+ if (!IS_ERR(__k)) { \
+ get_task_struct(__k); \
+ wake_up_process(__k); \
+ } \
+ __k; \
+})
+
+#define kthread_stop_put(k) \
+ do { \
+ kthread_stop(k); \
+ put_task_struct(k); \
+ } while (0)
+
/* usbip_common.c */
void usbip_dump_urb(struct urb *purb);
void usbip_dump_header(struct usbip_header *pdu);
diff --git a/drivers/staging/usbip/usbip_protocol.txt b/drivers/staging/usbip/usbip_protocol.txt
index 0f102081e86c..16b6fe27284c 100644
--- a/drivers/staging/usbip/usbip_protocol.txt
+++ b/drivers/staging/usbip/usbip_protocol.txt
@@ -27,7 +27,7 @@ Once the client knows the list of exported USB devices it may decide to use one
of them. First the client opens a TCP/IP connection towards the server and
sends an OP_REQ_IMPORT packet. The server replies with OP_REP_IMPORT. If the
import was successful the TCP/IP connection remains open and will be used
-to trasfer the URB traffic between the client and the server. The client may
+to transfer the URB traffic between the client and the server. The client may
send two types of packets: the USBIP_CMD_SUBMIT to submit an URB, and
USBIP_CMD_UNLINK to unlink a previously submitted URB. The answers of the
server may be USBIP_RET_SUBMIT and USBIP_RET_UNLINK respectively.
diff --git a/drivers/staging/usbip/userspace/libsrc/vhci_driver.c b/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
index 269787751b20..0958ba53e94a 100644
--- a/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
+++ b/drivers/staging/usbip/userspace/libsrc/vhci_driver.c
@@ -59,7 +59,10 @@ static int parse_status(char *value)
/* skip a header line */
- c = strchr(value, '\n') + 1;
+ c = strchr(value, '\n');
+ if (!c)
+ return -1;
+ c++;
while (*c != '\0') {
int port, status, speed, devid;
@@ -109,7 +112,10 @@ static int parse_status(char *value)
/* go to the next line */
- c = strchr(c, '\n') + 1;
+ c = strchr(c, '\n');
+ if (!c)
+ break;
+ c++;
}
dbg("exit");
@@ -264,11 +270,17 @@ static int get_nports(void)
attr_status->method, attr_status->value);
/* skip a header line */
- c = strchr(attr_status->value, '\n') + 1;
+ c = strchr(attr_status->value, '\n');
+ if (!c)
+ return 0;
+ c++;
while (*c != '\0') {
/* go to the next line */
- c = strchr(c, '\n') + 1;
+ c = strchr(c, '\n');
+ if (!c)
+ return nports;
+ c++;
nports += 1;
}
diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c
index dca9bf11f0c2..f708cbaee16b 100644
--- a/drivers/staging/usbip/vhci_hcd.c
+++ b/drivers/staging/usbip/vhci_hcd.c
@@ -821,10 +821,10 @@ static void vhci_shutdown_connection(struct usbip_device *ud)
}
/* kill threads related to this sdev, if v.c. exists */
- if (vdev->ud.tcp_rx && !task_is_dead(vdev->ud.tcp_rx))
- kthread_stop(vdev->ud.tcp_rx);
- if (vdev->ud.tcp_tx && !task_is_dead(vdev->ud.tcp_tx))
- kthread_stop(vdev->ud.tcp_tx);
+ if (vdev->ud.tcp_rx)
+ kthread_stop_put(vdev->ud.tcp_rx);
+ if (vdev->ud.tcp_tx)
+ kthread_stop_put(vdev->ud.tcp_tx);
pr_info("stop threads\n");
diff --git a/drivers/staging/usbip/vhci_rx.c b/drivers/staging/usbip/vhci_rx.c
index f5fba7320c5a..f0eaf04fa25b 100644
--- a/drivers/staging/usbip/vhci_rx.c
+++ b/drivers/staging/usbip/vhci_rx.c
@@ -162,7 +162,7 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev,
* already received the result of its submit result and gave
* back the URB.
*/
- pr_info("the urb (seqnum %d) was already given backed\n",
+ pr_info("the urb (seqnum %d) was already given back\n",
pdu->base.seqnum);
} else {
usbip_dbg_vhci_rx("now giveback urb %p\n", urb);
diff --git a/drivers/staging/usbip/vhci_sysfs.c b/drivers/staging/usbip/vhci_sysfs.c
index 0cd039bb5fd6..7ce9c2f7e442 100644
--- a/drivers/staging/usbip/vhci_sysfs.c
+++ b/drivers/staging/usbip/vhci_sysfs.c
@@ -222,8 +222,8 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,
spin_unlock(&the_controller->lock);
/* end the lock */
- vdev->ud.tcp_rx = kthread_run(vhci_rx_loop, &vdev->ud, "vhci_rx");
- vdev->ud.tcp_tx = kthread_run(vhci_tx_loop, &vdev->ud, "vhci_tx");
+ vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx");
+ vdev->ud.tcp_tx = kthread_get_run(vhci_tx_loop, &vdev->ud, "vhci_tx");
rh_port_connect(rhport, speed);
diff --git a/drivers/staging/vme/Makefile b/drivers/staging/vme/Makefile
index b4ea3f8d0a50..accdb72e39e2 100644
--- a/drivers/staging/vme/Makefile
+++ b/drivers/staging/vme/Makefile
@@ -1,8 +1 @@
-#
-# Makefile for the VME bridge device drivers.
-#
-obj-$(CONFIG_VME_BUS) += vme.o
-
-obj-y += bridges/
obj-y += devices/
-obj-y += boards/
diff --git a/drivers/staging/vme/TODO b/drivers/staging/vme/TODO
deleted file mode 100644
index 79f00333e7ef..000000000000
--- a/drivers/staging/vme/TODO
+++ /dev/null
@@ -1,5 +0,0 @@
- TODO
- ====
-
-- Add one or more device drivers which use the VME framework.
-
diff --git a/drivers/staging/vme/devices/Kconfig b/drivers/staging/vme/devices/Kconfig
index 55ec30cb1fa2..d0cab1766190 100644
--- a/drivers/staging/vme/devices/Kconfig
+++ b/drivers/staging/vme/devices/Kconfig
@@ -2,6 +2,7 @@ comment "VME Device Drivers"
config VME_USER
tristate "VME user space access driver"
+ depends on STAGING
help
If you say Y here you want to be able to access a limited number of
VME windows in a manner at least semi-compatible with the interface
@@ -9,7 +10,7 @@ config VME_USER
config VME_PIO2
tristate "GE PIO2 VME"
- depends on GPIOLIB
+ depends on STAGING && GPIOLIB
help
Say Y here to include support for the GE PIO2. The PIO2 is a 6U VME
slave card, implementing 32 solid-state relay switched IO lines, in
diff --git a/drivers/staging/vme/devices/vme_pio2_cntr.c b/drivers/staging/vme/devices/vme_pio2_cntr.c
index 08e0d59806ca..6335471faa36 100644
--- a/drivers/staging/vme/devices/vme_pio2_cntr.c
+++ b/drivers/staging/vme/devices/vme_pio2_cntr.c
@@ -17,8 +17,8 @@
#include <linux/device.h>
#include <linux/types.h>
#include <linux/gpio.h>
+#include <linux/vme.h>
-#include "../vme.h"
#include "vme_pio2.h"
static int pio2_cntr_irq_set(struct pio2_card *card, int id)
diff --git a/drivers/staging/vme/devices/vme_pio2_core.c b/drivers/staging/vme/devices/vme_pio2_core.c
index 573c80003f0c..4bf8e05ac312 100644
--- a/drivers/staging/vme/devices/vme_pio2_core.c
+++ b/drivers/staging/vme/devices/vme_pio2_core.c
@@ -10,7 +10,6 @@
* option) any later version.
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -20,8 +19,8 @@
#include <linux/ctype.h>
#include <linux/gpio.h>
#include <linux/slab.h>
+#include <linux/vme.h>
-#include "../vme.h"
#include "vme_pio2.h"
diff --git a/drivers/staging/vme/devices/vme_pio2_gpio.c b/drivers/staging/vme/devices/vme_pio2_gpio.c
index 858484915f08..ad76a477825b 100644
--- a/drivers/staging/vme/devices/vme_pio2_gpio.c
+++ b/drivers/staging/vme/devices/vme_pio2_gpio.c
@@ -10,7 +10,6 @@
* option) any later version.
*/
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -21,8 +20,8 @@
#include <linux/ctype.h>
#include <linux/gpio.h>
#include <linux/slab.h>
+#include <linux/vme.h>
-#include "../vme.h"
#include "vme_pio2.h"
static const char driver_name[] = "pio2_gpio";
@@ -79,7 +78,7 @@ static void pio2_gpio_set(struct gpio_chip *chip, unsigned int offset,
if ((card->bank[PIO2_CHANNEL_BANK[offset]].config == INPUT) |
(card->bank[PIO2_CHANNEL_BANK[offset]].config == NOFIT)) {
- dev_err(&card->vdev->dev, "Channel not availabe as output\n");
+ dev_err(&card->vdev->dev, "Channel not available as output\n");
return;
}
diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c
index 7dcd1622b5f5..e24a6f95db12 100644
--- a/drivers/staging/vme/devices/vme_user.c
+++ b/drivers/staging/vme/devices/vme_user.c
@@ -27,7 +27,7 @@
#include <linux/module.h>
#include <linux/pagemap.h>
#include <linux/pci.h>
-#include <linux/semaphore.h>
+#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/syscalls.h>
@@ -36,8 +36,8 @@
#include <linux/io.h>
#include <linux/uaccess.h>
+#include <linux/vme.h>
-#include "../vme.h"
#include "vme_user.h"
static DEFINE_MUTEX(vme_user_mutex);
@@ -95,7 +95,7 @@ struct image_desc {
void *kern_buf; /* Buffer address in kernel space */
dma_addr_t pci_buf; /* Buffer address in PCI address space */
unsigned long long size_buf; /* Buffer size */
- struct semaphore sem; /* Semaphore for locking image */
+ struct mutex mutex; /* Mutex for locking image */
struct device *device; /* Sysfs device */
struct vme_resource *resource; /* VME resource */
int users; /* Number of current users */
@@ -168,7 +168,7 @@ static int vme_user_open(struct inode *inode, struct file *file)
int err;
unsigned int minor = MINOR(inode->i_rdev);
- down(&image[minor].sem);
+ mutex_lock(&image[minor].mutex);
/* Allow device to be opened if a resource is needed and allocated. */
if (minor < CONTROL_MINOR && image[minor].resource == NULL) {
printk(KERN_ERR "No resources allocated for device\n");
@@ -179,12 +179,12 @@ static int vme_user_open(struct inode *inode, struct file *file)
/* Increment user count */
image[minor].users++;
- up(&image[minor].sem);
+ mutex_unlock(&image[minor].mutex);
return 0;
err_res:
- up(&image[minor].sem);
+ mutex_unlock(&image[minor].mutex);
return err;
}
@@ -193,12 +193,12 @@ static int vme_user_release(struct inode *inode, struct file *file)
{
unsigned int minor = MINOR(inode->i_rdev);
- down(&image[minor].sem);
+ mutex_lock(&image[minor].mutex);
/* Decrement user count */
image[minor].users--;
- up(&image[minor].sem);
+ mutex_unlock(&image[minor].mutex);
return 0;
}
@@ -325,14 +325,14 @@ static ssize_t vme_user_read(struct file *file, char __user *buf, size_t count,
if (minor == CONTROL_MINOR)
return 0;
- down(&image[minor].sem);
+ mutex_lock(&image[minor].mutex);
/* XXX Do we *really* want this helper - we can use vme_*_get ? */
image_size = vme_get_size(image[minor].resource);
/* Ensure we are starting at a valid location */
if ((*ppos < 0) || (*ppos > (image_size - 1))) {
- up(&image[minor].sem);
+ mutex_unlock(&image[minor].mutex);
return 0;
}
@@ -353,8 +353,7 @@ static ssize_t vme_user_read(struct file *file, char __user *buf, size_t count,
retval = -EINVAL;
}
- up(&image[minor].sem);
-
+ mutex_unlock(&image[minor].mutex);
if (retval > 0)
*ppos += retval;
@@ -372,13 +371,13 @@ static ssize_t vme_user_write(struct file *file, const char __user *buf,
if (minor == CONTROL_MINOR)
return 0;
- down(&image[minor].sem);
+ mutex_lock(&image[minor].mutex);
image_size = vme_get_size(image[minor].resource);
/* Ensure we are starting at a valid location */
if ((*ppos < 0) || (*ppos > (image_size - 1))) {
- up(&image[minor].sem);
+ mutex_unlock(&image[minor].mutex);
return 0;
}
@@ -398,8 +397,8 @@ static ssize_t vme_user_write(struct file *file, const char __user *buf,
default:
retval = -EINVAL;
}
-
- up(&image[minor].sem);
+
+ mutex_unlock(&image[minor].mutex);
if (retval > 0)
*ppos += retval;
@@ -416,7 +415,7 @@ static loff_t vme_user_llseek(struct file *file, loff_t off, int whence)
if (minor == CONTROL_MINOR)
return -EINVAL;
- down(&image[minor].sem);
+ mutex_lock(&image[minor].mutex);
image_size = vme_get_size(image[minor].resource);
switch (whence) {
@@ -430,19 +429,19 @@ static loff_t vme_user_llseek(struct file *file, loff_t off, int whence)
absolute = image_size + off;
break;
default:
- up(&image[minor].sem);
+ mutex_unlock(&image[minor].mutex);
return -EINVAL;
break;
}
if ((absolute < 0) || (absolute >= image_size)) {
- up(&image[minor].sem);
+ mutex_unlock(&image[minor].mutex);
return -EINVAL;
}
file->f_pos = absolute;
- up(&image[minor].sem);
+ mutex_unlock(&image[minor].mutex);
return absolute;
}
@@ -696,7 +695,7 @@ static int __devinit vme_user_probe(struct vme_dev *vdev)
for (i = 0; i < VME_DEVS; i++) {
image[i].kern_buf = NULL;
image[i].pci_buf = 0;
- sema_init(&image[i].sem, 1);
+ mutex_init(&image[i].mutex);
image[i].device = NULL;
image[i].resource = NULL;
image[i].users = 0;
@@ -858,8 +857,10 @@ static int __devexit vme_user_remove(struct vme_dev *dev)
int i;
/* Remove sysfs Entries */
- for (i = 0; i < VME_DEVS; i++)
+ for (i = 0; i < VME_DEVS; i++) {
+ mutex_destroy(&image[i].mutex);
device_destroy(vme_user_sysfs_class, MKDEV(VME_MAJOR, i));
+ }
class_destroy(vme_user_sysfs_class);
for (i = MASTER_MINOR; i < (MASTER_MAX + 1); i++) {
diff --git a/drivers/staging/vt6655/wpa.c b/drivers/staging/vt6655/wpa.c
index 61ac46fa505e..0afb9fe0379a 100644
--- a/drivers/staging/vt6655/wpa.c
+++ b/drivers/staging/vt6655/wpa.c
@@ -148,7 +148,7 @@ WPA_ParseRSN (
{
j = 0;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wPKCount: %d, sizeof(pBSSList->abyPKType): %zu\n", pRSN->wPKCount, sizeof(pBSSList->abyPKType));
- for(i = 0; (i < pRSN->wPKCount) && (j < sizeof(pBSSList->abyPKType)/sizeof(unsigned char)); i++) {
+ for(i = 0; (i < pRSN->wPKCount) && (j < ARRAY_SIZE(pBSSList->abyPKType)); i++) {
if(pRSN->len >= 12+i*4+4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*i)
if ( !memcmp(pRSN->PKSList[i].abyOUI, abyOUI00, 4))
pBSSList->abyPKType[j++] = WPA_NONE;
@@ -180,7 +180,7 @@ WPA_ParseRSN (
j = 0;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAuthCount: %d, sizeof(pBSSList->abyAuthType): %zu\n",
pIE_RSN_Auth->wAuthCount, sizeof(pBSSList->abyAuthType));
- for(i = 0; (i < pIE_RSN_Auth->wAuthCount) && (j < sizeof(pBSSList->abyAuthType)/sizeof(unsigned char)); i++) {
+ for(i = 0; (i < pIE_RSN_Auth->wAuthCount) && (j < ARRAY_SIZE(pBSSList->abyAuthType)); i++) {
if(pRSN->len >= 14+4+(m+i)*4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*m)+AKC(2)+AKS(4*i)
if ( !memcmp(pIE_RSN_Auth->AuthKSList[i].abyOUI, abyOUI01, 4))
pBSSList->abyAuthType[j++] = WPA_AUTH_IEEE802_1X;
diff --git a/drivers/staging/vt6656/dpc.c b/drivers/staging/vt6656/dpc.c
index c0edf97535dc..e4bdf2a2b582 100644
--- a/drivers/staging/vt6656/dpc.c
+++ b/drivers/staging/vt6656/dpc.c
@@ -452,7 +452,7 @@ RXbBulkInProcessData (
}
}
- if (!is_multicast_ether_addr(pMACHeader->abyAddr1) && !is_broadcast_ether_addr(pMACHeader->abyAddr1)) {
+ if (!is_multicast_ether_addr(pMACHeader->abyAddr1)) {
if ( WCTLbIsDuplicate(&(pDevice->sDupRxCache), (PS802_11Header) pbyFrame) ) {
pDevice->s802_11Counter.FrameDuplicateCount++;
return FALSE;
diff --git a/drivers/staging/vt6656/ioctl.c b/drivers/staging/vt6656/ioctl.c
index d59456c29df1..5b9a84f95185 100644
--- a/drivers/staging/vt6656/ioctl.c
+++ b/drivers/staging/vt6656/ioctl.c
@@ -90,18 +90,17 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq)
spin_lock_irq(&pDevice->lock);
if (memcmp(pMgmt->abyCurrBSSID, &abyNullAddr[0], 6) == 0)
- BSSvClearBSSList((void *)pDevice, FALSE);
+ BSSvClearBSSList(pDevice, FALSE);
else
- BSSvClearBSSList((void *)pDevice, pDevice->bLinkPass);
+ BSSvClearBSSList(pDevice, pDevice->bLinkPass);
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WLAN_CMD_BSS_SCAN..begin\n");
if (pItemSSID->len != 0)
- bScheduleCommand((void *)pDevice,
- WLAN_CMD_BSSID_SCAN,
+ bScheduleCommand(pDevice, WLAN_CMD_BSSID_SCAN,
abyScanSSID);
else
- bScheduleCommand((void *) pDevice, WLAN_CMD_BSSID_SCAN, NULL);
+ bScheduleCommand(pDevice, WLAN_CMD_BSSID_SCAN, NULL);
spin_unlock_irq(&pDevice->lock);
break;
@@ -150,6 +149,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq)
}
}
break;
+
case WLAN_CMD_BSS_JOIN:
if (copy_from_user(&sJoinCmd, pReq->data, sizeof(SCmdBSSJoin))) {
result = -EFAULT;
@@ -190,10 +190,9 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq)
netif_stop_queue(pDevice->dev);
spin_lock_irq(&pDevice->lock);
pMgmt->eCurrState = WMAC_STATE_IDLE;
- bScheduleCommand((void *) pDevice,
- WLAN_CMD_BSSID_SCAN,
+ bScheduleCommand(pDevice, WLAN_CMD_BSSID_SCAN,
pMgmt->abyDesireSSID);
- bScheduleCommand((void *) pDevice, WLAN_CMD_SSID, NULL);
+ bScheduleCommand(pDevice, WLAN_CMD_SSID, NULL);
spin_unlock_irq(&pDevice->lock);
break;
@@ -299,7 +298,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq)
result = -EINVAL;
break;
}
- pList = (PSBSSIDList)kmalloc(sizeof(SBSSIDList) + (sList.uItem * sizeof(SBSSIDItem)), (int)GFP_ATOMIC);
+ pList = kmalloc(sizeof(SBSSIDList) + (sList.uItem * sizeof(SBSSIDItem)), GFP_ATOMIC);
if (pList == NULL) {
result = -ENOMEM;
break;
@@ -313,7 +312,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq)
pList->sBSSIDList[ii].wBeaconInterval = pBSS->wBeaconInterval;
pList->sBSSIDList[ii].wCapInfo = pBSS->wCapInfo;
RFvRSSITodBm(pDevice, (BYTE)(pBSS->uRSSI), &ldBm);
- pList->sBSSIDList[ii].uRSSI = (unsigned int) ldBm;
+ pList->sBSSIDList[ii].uRSSI = (unsigned int)ldBm;
/* pList->sBSSIDList[ii].uRSSI = pBSS->uRSSI; */
memcpy(pList->sBSSIDList[ii].abyBSSID, pBSS->abyBSSID, WLAN_BSSID_LEN);
pItemSSID = (PWLAN_IE_SSID)pBSS->abySSID;
@@ -356,6 +355,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq)
break;
}
break;
+
case WLAN_CMD_STOP_MAC:
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "WLAN_CMD_STOP_MAC\n");
/* Todo xxxxxx */
@@ -534,7 +534,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq)
netif_stop_queue(pDevice->dev);
spin_lock_irq(&pDevice->lock);
- bScheduleCommand((void *)pDevice, WLAN_CMD_RUN_AP, NULL);
+ bScheduleCommand(pDevice, WLAN_CMD_RUN_AP, NULL);
spin_unlock_irq(&pDevice->lock);
break;
@@ -565,7 +565,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq)
result = -ENOMEM;
break;
}
- pNodeList = kmalloc(sizeof(SNodeList) + (sNodeList.uItem * sizeof(SNodeItem)), (int)GFP_ATOMIC);
+ pNodeList = kmalloc(sizeof(SNodeList) + (sNodeList.uItem * sizeof(SNodeItem)), GFP_ATOMIC);
if (pNodeList == NULL) {
result = -ENOMEM;
break;
diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c
index 763e028a5cc5..ee5261a36886 100644
--- a/drivers/staging/vt6656/main_usb.c
+++ b/drivers/staging/vt6656/main_usb.c
@@ -1257,9 +1257,7 @@ static void __devexit vt6656_disconnect(struct usb_interface *intf)
}
device_release_WPADEV(device);
-
- if (device->firmware)
- release_firmware(device->firmware);
+ release_firmware(device->firmware);
usb_set_intfdata(intf, NULL);
usb_put_dev(interface_to_usbdev(intf));
diff --git a/drivers/staging/vt6656/wpa.c b/drivers/staging/vt6656/wpa.c
index 7dde3d6941ab..b16d4ddc117b 100644
--- a/drivers/staging/vt6656/wpa.c
+++ b/drivers/staging/vt6656/wpa.c
@@ -149,7 +149,7 @@ WPA_ParseRSN(
j = 0;
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wPKCount: %d, sizeof(pBSSList->abyPKType): %zu\n", pRSN->wPKCount, sizeof(pBSSList->abyPKType));
for (i = 0; (i < pRSN->wPKCount) &&
- (j < sizeof(pBSSList->abyPKType)/sizeof(BYTE)); i++) {
+ (j < ARRAY_SIZE(pBSSList->abyPKType)); i++) {
if(pRSN->len >= 12+i*4+4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*i)
if ( !memcmp(pRSN->PKSList[i].abyOUI, abyOUI00, 4))
pBSSList->abyPKType[j++] = WPA_NONE;
@@ -182,7 +182,7 @@ WPA_ParseRSN(
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"wAuthCount: %d, sizeof(pBSSList->abyAuthType): %zu\n",
pIE_RSN_Auth->wAuthCount, sizeof(pBSSList->abyAuthType));
for (i = 0; (i < pIE_RSN_Auth->wAuthCount) &&
- (j < sizeof(pBSSList->abyAuthType)/sizeof(BYTE)); i++) {
+ (j < ARRAY_SIZE(pBSSList->abyAuthType)); i++) {
if(pRSN->len >= 14+4+(m+i)*4) { //oui1(4)+ver(2)+GKS(4)+PKSCnt(2)+PKS(4*m)+AKC(2)+AKS(4*i)
if ( !memcmp(pIE_RSN_Auth->AuthKSList[i].abyOUI, abyOUI01, 4))
pBSSList->abyAuthType[j++] = WPA_AUTH_IEEE802_1X;
diff --git a/drivers/staging/wlags49_h2/README.ubuntu b/drivers/staging/wlags49_h2/README.ubuntu
index edee8b9385be..5f1cfb8fd427 100644
--- a/drivers/staging/wlags49_h2/README.ubuntu
+++ b/drivers/staging/wlags49_h2/README.ubuntu
@@ -87,7 +87,7 @@ The linux driver files (wl_xxxx.c) are changed in the following ways:
-- Recovery actions added
The major problem was the order in which calls can be made. The original
-looks like a traditonal UNIX driver. To call an "ioctl" function you
+looks like a traditional UNIX driver. To call an "ioctl" function you
have to "open" the device first to get a handle and after "close" no
"ioctl" function can be called anymore. With the 2.6 driver this all
changed; the former ioctl functions are now called before "open" and
diff --git a/drivers/staging/wlags49_h2/hcf.c b/drivers/staging/wlags49_h2/hcf.c
index 5957c3a439ac..366e4a4b75c5 100644
--- a/drivers/staging/wlags49_h2/hcf.c
+++ b/drivers/staging/wlags49_h2/hcf.c
@@ -2871,8 +2871,8 @@ or
* The Assert validates the HCF assumption about Hermes implementation upon which the range of
* Pseudo-RIDs is based.
* Then the control fields up to the start of the 802.3 frame are read from the NIC into the lookahead buffer.
-* The status field is converted to native Endianess.
-* The length is, after implicit Endianess conversion if needed, and adjustment for the 14 bytes of the
+* The status field is converted to native Endianness.
+* The length is, after implicit Endianness conversion if needed, and adjustment for the 14 bytes of the
* 802.3 MAC header, stored in IFB_RxLen.
* In MAC Monitor mode, 802.11 control frames with a TOTAL length of 14 are received, so without this
* length adjustment, IFB_RxLen could not be used to distinguish these frames from "no frame".
@@ -2894,7 +2894,7 @@ or
* - the Hermes reported Tunnel encapsulation or
* - the Hermes reported 1042 Encapsulation and hcf_encap reports that the HCF would not have used
* 1042 as the encapsulation mechanism
-* Note that the first field of the RxFS in bufp has Native Endianess due to the conversion done by the
+* Note that the first field of the RxFS in bufp has Native Endianness due to the conversion done by the
* BE_PAR in get_frag.
*36: The Type field is the only word kept (after moving) of the just read 8 bytes, it is moved to the
* L-field. The original L-field and 6 byte SNAP header are discarded, so IFB_RxLen and buf_addr must
@@ -3831,7 +3831,7 @@ get_fid( IFBP ifbp )
*.DESCRIPTION
* process the single byte (if applicable) read by the previous get_frag and copy len (or len-1) bytes from
* NIC to bufp.
- * On a Big Endian platform, the parameter word_len controls the number of leading bytes whose endianess is
+ * On a Big Endian platform, the parameter word_len controls the number of leading bytes whose endianness is
* converted (i.e. byte swapped)
*
*
@@ -3980,7 +3980,7 @@ get_frag( IFBP ifbp, wci_bufp bufp, int len BE_PAR( int word_len ) )
* appropriate means on H-I: always
* and on H-II if F/W supplier reflects a primary (i.e. only after an Hermes Reset or Init
* command).
- * QUESTION ;? !!!!!! should, For each of the above RIDs the Endianess is converted to native Endianess.
+ * QUESTION ;? !!!!!! should, For each of the above RIDs the Endianness is converted to native Endianness.
* Only the return code of the first hcf_get_info is used. All hcf_get_info calls are made, regardless of
* the success or failure of the 1st hcf_get_info. The assumptions are:
* - if any call fails, they all fail, so remembering the result of the 1st call is adequate
diff --git a/drivers/staging/wlags49_h2/hcf.h b/drivers/staging/wlags49_h2/hcf.h
index 95527b5cf863..68e23303b5e8 100644
--- a/drivers/staging/wlags49_h2/hcf.h
+++ b/drivers/staging/wlags49_h2/hcf.h
@@ -90,7 +90,7 @@
#define LOF(x) (sizeof(x)/sizeof(hcf_16)-1)
-/* Endianess
+/* Endianness
* Little Endian (a.k.a. Intel), least significant byte first
* Big Endian (a.k.a. Motorola), most significant byte first
*
@@ -101,7 +101,7 @@
*/
/* To increase portability, use unsigned char and unsigned char * when accessing parts of larger
- * types to convert their Endianess
+ * types to convert their Endianness
*/
#define CNV_END_SHORT(w) (hcf_16)( ((hcf_16)(w) & 0x00FF) << 8 | ((hcf_16)(w) & 0xFF00) >> 8 )
@@ -109,14 +109,14 @@
#if HCF_BIG_ENDIAN
//******************************************** B I G E N D I A N *******************************************
-#define CNV_LITTLE_TO_SHORT(w) CNV_END_SHORT(w) // endianess conversion needed
-#define CNV_BIG_TO_SHORT(w) (w) // no endianess conversion needed
+#define CNV_LITTLE_TO_SHORT(w) CNV_END_SHORT(w) // endianness conversion needed
+#define CNV_BIG_TO_SHORT(w) (w) // no endianness conversion needed
#define CNV_LITTLE_TO_LONG(dw) CNV_END_LONG(dw)
#define CNV_LONG_TO_LITTLE(dw) CNV_END_LONG(dw)
#else
//****************************************** L I T T L E E N D I A N ****************************************
-#define CNV_LITTLE_TO_SHORT(w) (w) // no endianess conversion needed
-#define CNV_BIG_TO_SHORT(w) CNV_END_SHORT(w) // endianess conversion needed
+#define CNV_LITTLE_TO_SHORT(w) (w) // no endianness conversion needed
+#define CNV_BIG_TO_SHORT(w) CNV_END_SHORT(w) // endianness conversion needed
#define CNV_LITTLE_TO_LONG(dw) (dw)
#define CNV_LONG_TO_LITTLE(dw) (dw)
diff --git a/drivers/staging/wlags49_h2/mmd.c b/drivers/staging/wlags49_h2/mmd.c
index c8f52107e6ca..7204a373bc51 100644
--- a/drivers/staging/wlags49_h2/mmd.c
+++ b/drivers/staging/wlags49_h2/mmd.c
@@ -101,10 +101,10 @@
* supp address of the supplier specification
*
* Description: mmd_check_comp is a support routine to check the compatibility between an actor and a
-* supplier. mmd_check_comp is independent of the endianess of the actp and supp structures. This is
+* supplier. mmd_check_comp is independent of the endianness of the actp and supp structures. This is
* achieved by checking the "bottom" or "role" fields of these structures. Since these fields are restricted
* to a limited range, comparing the contents to a value with a known endian-ess gives a clue to their actual
-* endianess.
+* endianness.
*
*.DIAGRAM
*1a: The role-field of the actor structure has a known non-zero, not "byte symmetric" value (namely
@@ -114,16 +114,16 @@
* for a supplier. A supplier has always exactly 1 variant,top,bottom record with (officially, but see the
* note below) each of these 3 values in the range 1 through 99, so one byte of the word value of variant,
* top and bottom words is 0x00 and the other byte is non-zero. Whether the lowest address byte or the
-* highest address byte is non-zero depends on the Endianess of the LTV. If and only if the word value of
+* highest address byte is non-zero depends on the Endianness of the LTV. If and only if the word value of
* bottom is less than 0x0100, the supplier is Native Endian.
* NOTE: the variant field of the supplier structure can not be used for the Endian Detection Algorithm,
* because a a zero-valued variant has been used as Controlled Deployment indication in the past.
* Note: An actor may have multiple sets of variant,top,bottom records, including dummy sets with variant,
-* top and bottom fields with a zero-value. As a consequence the endianess of the actor can not be determined
+* top and bottom fields with a zero-value. As a consequence the endianness of the actor can not be determined
* based on its variant,top,bottom values.
*
* Note: the L and T field of the structures are always in Native Endian format, so you can not draw
-* conclusions concerning the Endianess of the structure based on these two fields.
+* conclusions concerning the Endianness of the structure based on these two fields.
*
*1b/2b
* The only purpose of the CFG_RANGE_SPEC_BYTE_STRCT is to give easy access to the non-zero byte of the word
@@ -149,7 +149,7 @@
*
* This is implemented as:
* #if HCF_BIG_ENDIAN == 0 //platform is LE
-* sup/act_endian becomes reverse of structure-endianess as determined in 1a/1b
+* sup/act_endian becomes reverse of structure-endianness as determined in 1a/1b
* #endif
*6: Each of the actor variant-bottom-top records is checked against the (single) supplier variant-bottom-top
* range till either an acceptable match is found or all actor records are tried. As explained above, due to
diff --git a/drivers/staging/wlags49_h2/wl_cs.c b/drivers/staging/wlags49_h2/wl_cs.c
index 7084f414846e..7c7c77f9c862 100644
--- a/drivers/staging/wlags49_h2/wl_cs.c
+++ b/drivers/staging/wlags49_h2/wl_cs.c
@@ -177,10 +177,9 @@ static void wl_adapter_detach(struct pcmcia_device *link)
if (dev) {
unregister_wlags_sysfs(dev);
unregister_netdev(dev);
+ wl_device_dealloc(dev);
}
- wl_device_dealloc(dev);
-
DBG_LEAVE(DbgInfo);
} /* wl_adapter_detach */
/*============================================================================*/
diff --git a/drivers/staging/wlags49_h2/wl_netdev.c b/drivers/staging/wlags49_h2/wl_netdev.c
index 90820ff1aced..824b85232353 100644
--- a/drivers/staging/wlags49_h2/wl_netdev.c
+++ b/drivers/staging/wlags49_h2/wl_netdev.c
@@ -1063,7 +1063,7 @@ void wl_multicast( struct net_device *dev )
#if DBG
if( DBG_FLAGS( DbgInfo ) & DBG_PARAM_ON ) {
DBG_PRINT(" flags: %s%s%s\n",
- ( dev->flags & IFF_PROMISC ) ? "Promiscous " : "",
+ ( dev->flags & IFF_PROMISC ) ? "Promiscuous " : "",
( dev->flags & IFF_MULTICAST ) ? "Multicast " : "",
( dev->flags & IFF_ALLMULTI ) ? "All-Multicast" : "" );
@@ -1510,8 +1510,11 @@ void wl_wds_device_alloc( struct wl_private *lp )
for( count = 0; count < NUM_WDS_PORTS; count++ ) {
struct net_device *dev_wds = NULL;
- dev_wds = kmalloc( sizeof( struct net_device ), GFP_KERNEL );
- memset( dev_wds, 0, sizeof( struct net_device ));
+ dev_wds = kzalloc(sizeof(struct net_device), GFP_KERNEL);
+ if (!dev_wds) {
+ DBG_LEAVE(DbgInfo);
+ return;
+ }
ether_setup( dev_wds );
diff --git a/drivers/staging/wlags49_h2/wl_pci.c b/drivers/staging/wlags49_h2/wl_pci.c
index 3df990c7306a..0b31b01bd490 100644
--- a/drivers/staging/wlags49_h2/wl_pci.c
+++ b/drivers/staging/wlags49_h2/wl_pci.c
@@ -524,6 +524,7 @@ int wl_pci_setup( struct pci_dev *pdev )
/* Make sure that space was allocated for our private adapter struct */
if( dev->priv == NULL ) {
DBG_ERROR( DbgInfo, "Private adapter struct was not allocated!!!\n" );
+ wl_device_dealloc(dev);
DBG_LEAVE( DbgInfo );
return -ENOMEM;
}
@@ -532,6 +533,7 @@ int wl_pci_setup( struct pci_dev *pdev )
/* Allocate DMA Descriptors */
if( wl_pci_dma_alloc( pdev, dev->priv ) < 0 ) {
DBG_ERROR( DbgInfo, "Could not allocate DMA descriptor memory!!!\n" );
+ wl_device_dealloc(dev);
DBG_LEAVE( DbgInfo );
return -ENOMEM;
}
@@ -561,6 +563,8 @@ int wl_pci_setup( struct pci_dev *pdev )
result = request_irq(dev->irq, wl_isr, SA_SHIRQ, dev->name, dev);
if( result ) {
DBG_WARNING( DbgInfo, "Could not register ISR!!!\n" );
+ wl_remove(dev);
+ wl_device_dealloc(dev);
DBG_LEAVE( DbgInfo );
return result;
}
diff --git a/drivers/staging/wlags49_h2/wl_profile.c b/drivers/staging/wlags49_h2/wl_profile.c
index b8c96cf18de5..0e49272bc7a8 100644
--- a/drivers/staging/wlags49_h2/wl_profile.c
+++ b/drivers/staging/wlags49_h2/wl_profile.c
@@ -401,7 +401,7 @@ void translate_option(char *buffer, struct wl_private *lp)
if ((value_convert >= PARM_MIN_BRSC) || (value_convert <= PARM_MAX_BRSC))
lp->brsc[0] = value_convert;
else
- DBG_WARNING(DbgInfo, "%s invaid; will be ignored\n", PARM_NAME_BRSC_2GHZ);
+ DBG_WARNING(DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_BRSC_2GHZ);
} else if (strcmp(key, PARM_NAME_BRSC_5GHZ) == 0) {
DBG_TRACE(DbgInfo, "%s, value: %s\n", PARM_NAME_BRSC_5GHZ, value);
@@ -409,7 +409,7 @@ void translate_option(char *buffer, struct wl_private *lp)
if ((value_convert >= PARM_MIN_BRSC) || (value_convert <= PARM_MAX_BRSC))
lp->brsc[1] = value_convert;
else
- DBG_WARNING(DbgInfo, "%s invaid; will be ignored\n", PARM_NAME_BRSC_5GHZ);
+ DBG_WARNING(DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_BRSC_5GHZ);
} else if ((strcmp(key, PARM_NAME_DESIRED_SSID) == 0) || (strcmp(key, PARM_NAME_OWN_SSID) == 0)) {
DBG_TRACE(DbgInfo, "SSID, value: %s\n", value);
@@ -556,7 +556,7 @@ void translate_option(char *buffer, struct wl_private *lp)
if ((value_convert >= PARM_MIN_SRSC) || (value_convert <= PARM_MAX_SRSC))
lp->srsc[0] = value_convert;
else
- DBG_WARNING(DbgInfo, "%s invaid; will be ignored\n", PARM_NAME_SRSC_2GHZ);
+ DBG_WARNING(DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_SRSC_2GHZ);
} else if (strcmp(key, PARM_NAME_SRSC_5GHZ) == 0) {
DBG_TRACE(DbgInfo, "%s, value: %s\n", PARM_NAME_SRSC_5GHZ, value);
@@ -564,7 +564,7 @@ void translate_option(char *buffer, struct wl_private *lp)
if ((value_convert >= PARM_MIN_SRSC) || (value_convert <= PARM_MAX_SRSC))
lp->srsc[1] = value_convert;
else
- DBG_WARNING(DbgInfo, "%s invaid; will be ignored\n", PARM_NAME_SRSC_5GHZ);
+ DBG_WARNING(DbgInfo, "%s invalid; will be ignored\n", PARM_NAME_SRSC_5GHZ);
} else if (strcmp(key, PARM_NAME_SYSTEM_SCALE) == 0) {
DBG_TRACE(DbgInfo, "%s, value: %s\n", PARM_NAME_SYSTEM_SCALE, value);
diff --git a/drivers/staging/wlags49_h2/wl_util.c b/drivers/staging/wlags49_h2/wl_util.c
index f104e6f1e980..404ec7da0348 100644
--- a/drivers/staging/wlags49_h2/wl_util.c
+++ b/drivers/staging/wlags49_h2/wl_util.c
@@ -98,8 +98,7 @@
******************************************************************************/
/* A matrix which maps channels to frequencies */
-#define MAX_CHAN_FREQ_MAP_ENTRIES 50
-static const long chan_freq_list[][MAX_CHAN_FREQ_MAP_ENTRIES] =
+static const long chan_freq_list[][2] =
{
{1,2412},
{2,2417},
@@ -846,7 +845,7 @@ int wl_is_a_valid_chan( int channel )
}
/* Iterate through the matrix and retrieve the frequency */
- for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
+ for( i = 0; i < ARRAY_SIZE(chan_freq_list); i++ ) {
if( chan_freq_list[i][0] == channel ) {
return 1;
}
@@ -884,7 +883,7 @@ int wl_is_a_valid_freq( long frequency )
/* Iterate through the matrix and retrieve the channel */
- for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
+ for( i = 0; i < ARRAY_SIZE(chan_freq_list); i++ ) {
if( chan_freq_list[i][1] == frequency ) {
return 1;
}
@@ -927,7 +926,7 @@ long wl_get_freq_from_chan( int channel )
}
/* Iterate through the matrix and retrieve the frequency */
- for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
+ for( i = 0; i < ARRAY_SIZE(chan_freq_list); i++ ) {
if( chan_freq_list[i][0] == channel ) {
return chan_freq_list[i][1];
}
@@ -965,7 +964,7 @@ int wl_get_chan_from_freq( long frequency )
/* Iterate through the matrix and retrieve the channel */
- for( i = 0; i < MAX_CHAN_FREQ_MAP_ENTRIES; i++ ) {
+ for( i = 0; i < ARRAY_SIZE(chan_freq_list); i++ ) {
if( chan_freq_list[i][1] == frequency ) {
return chan_freq_list[i][0];
}
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c
index 4cd3ba5d5646..8bc562b8c4d9 100644
--- a/drivers/staging/wlan-ng/cfg80211.c
+++ b/drivers/staging/wlan-ng/cfg80211.c
@@ -332,6 +332,7 @@ int prism2_scan(struct wiphy *wiphy, struct net_device *dev,
wlandevice_t *wlandev = dev->ml_priv;
struct p80211msg_dot11req_scan msg1;
struct p80211msg_dot11req_scan_results msg2;
+ struct cfg80211_bss *bss;
int result;
int err = 0;
int numbss = 0;
@@ -401,7 +402,7 @@ int prism2_scan(struct wiphy *wiphy, struct net_device *dev,
ie_buf[1] = msg2.ssid.data.len;
ie_len = ie_buf[1] + 2;
memcpy(&ie_buf[2], &(msg2.ssid.data.data), msg2.ssid.data.len);
- cfg80211_inform_bss(wiphy,
+ bss = cfg80211_inform_bss(wiphy,
ieee80211_get_channel(wiphy, ieee80211_dsss_chan_to_freq(msg2.dschannel.data)),
(const u8 *) &(msg2.bssid.data.data),
msg2.timestamp.data, msg2.capinfo.data,
@@ -411,6 +412,13 @@ int prism2_scan(struct wiphy *wiphy, struct net_device *dev,
(msg2.signal.data - 65536) * 100, /* Conversion to signed type */
GFP_KERNEL
);
+
+ if (!bss) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ cfg80211_put_bss(bss);
}
if (result)
diff --git a/drivers/staging/wlan-ng/prism2mgmt.c b/drivers/staging/wlan-ng/prism2mgmt.c
index c3bb05dd744f..4efa9bc0fcf0 100644
--- a/drivers/staging/wlan-ng/prism2mgmt.c
+++ b/drivers/staging/wlan-ng/prism2mgmt.c
@@ -380,8 +380,8 @@ int prism2mgmt_scan_results(wlandevice_t *wlandev, void *msgp)
}
count = (hw->scanresults->framelen - 3) / 32;
- if (count > 32)
- count = 32;
+ if (count > HFA384x_SCANRESULT_MAX)
+ count = HFA384x_SCANRESULT_MAX;
if (req->bssindex.data >= count) {
pr_debug("requested index (%d) out of range (%d)\n",
diff --git a/drivers/staging/xgifb/XGI_main.h b/drivers/staging/xgifb/XGI_main.h
index e828fd403c35..9c62aeb9ede9 100644
--- a/drivers/staging/xgifb/XGI_main.h
+++ b/drivers/staging/xgifb/XGI_main.h
@@ -12,9 +12,6 @@
#define XGIFAIL(x) do { printk(x "\n"); return -EINVAL; } while (0)
-#ifndef PCI_DEVICE_ID_XGI_41
-#define PCI_DEVICE_ID_XGI_41 0x041
-#endif
#ifndef PCI_DEVICE_ID_XGI_42
#define PCI_DEVICE_ID_XGI_42 0x042
#endif
@@ -82,177 +79,79 @@ static int XGIfb_tvplug = -1;
/* TW: For ioctl XGIFB_GET_INFO */
/* XGIfb_info XGIfbinfo; */
-#define MD_XGI300 1
-#define MD_XGI315 2
+#define MD_XGI315 1
/* mode table */
static const struct _XGIbios_mode {
- char name[15];
u8 mode_no;
u16 vesa_mode_no_1; /* "XGI defined" VESA mode number */
u16 vesa_mode_no_2; /* Real VESA mode numbers */
u16 xres;
u16 yres;
u16 bpp;
- u16 rate_idx;
- u16 cols;
- u16 rows;
u8 chipset;
} XGIbios_mode[] = {
- {"320x240x16", 0x56, 0x0000, 0x0000, 320, 240, 16, 1, 40, 15,
- MD_XGI315},
- {"320x480x8", 0x5A, 0x0000, 0x0000, 320, 480, 8, 1, 40, 30,
- MD_XGI315}, /* TW: FSTN */
- {"320x480x16", 0x5B, 0x0000, 0x0000, 320, 480, 16, 1, 40, 30,
- MD_XGI315}, /* TW: FSTN */
- {"640x480x8", 0x2E, 0x0101, 0x0101, 640, 480, 8, 1, 80, 30,
- MD_XGI300|MD_XGI315},
- {"640x480x16", 0x44, 0x0111, 0x0111, 640, 480, 16, 1, 80, 30,
- MD_XGI300|MD_XGI315},
- {"640x480x24", 0x62, 0x013a, 0x0112, 640, 480, 32, 1, 80, 30,
- MD_XGI300|MD_XGI315}, /* TW: That's for people who mix up color-
- and fb depth */
- {"640x480x32", 0x62, 0x013a, 0x0112, 640, 480, 32, 1, 80, 30,
- MD_XGI300|MD_XGI315},
- {"720x480x8", 0x31, 0x0000, 0x0000, 720, 480, 8, 1, 90, 30,
- MD_XGI300|MD_XGI315},
- {"720x480x16", 0x33, 0x0000, 0x0000, 720, 480, 16, 1, 90, 30,
- MD_XGI300|MD_XGI315},
- {"720x480x24", 0x35, 0x0000, 0x0000, 720, 480, 32, 1, 90, 30,
- MD_XGI300|MD_XGI315},
- {"720x480x32", 0x35, 0x0000, 0x0000, 720, 480, 32, 1, 90, 30,
- MD_XGI300|MD_XGI315},
- {"720x576x8", 0x32, 0x0000, 0x0000, 720, 576, 8, 1, 90, 36,
- MD_XGI300|MD_XGI315},
- {"720x576x16", 0x34, 0x0000, 0x0000, 720, 576, 16, 1, 90, 36,
- MD_XGI300|MD_XGI315},
- {"720x576x24", 0x36, 0x0000, 0x0000, 720, 576, 32, 1, 90, 36,
- MD_XGI300|MD_XGI315},
- {"720x576x32", 0x36, 0x0000, 0x0000, 720, 576, 32, 1, 90, 36,
- MD_XGI300|MD_XGI315},
- {"800x480x8", 0x70, 0x0000, 0x0000, 800, 480, 8, 1, 100, 30,
- MD_XGI300|MD_XGI315},
- {"800x480x16", 0x7a, 0x0000, 0x0000, 800, 480, 16, 1, 100, 30,
- MD_XGI300|MD_XGI315},
- {"800x480x24", 0x76, 0x0000, 0x0000, 800, 480, 32, 1, 100, 30,
- MD_XGI300|MD_XGI315},
- {"800x480x32", 0x76, 0x0000, 0x0000, 800, 480, 32, 1, 100, 30,
- MD_XGI300|MD_XGI315},
- {"800x600x8", 0x30, 0x0103, 0x0103, 800, 600, 8, 1, 100, 37,
- MD_XGI300|MD_XGI315},
-#define DEFAULT_MODE 20 /* index for 800x600x16 */
- {"800x600x16", 0x47, 0x0114, 0x0114, 800, 600, 16, 1, 100, 37,
- MD_XGI300|MD_XGI315},
- {"800x600x24", 0x63, 0x013b, 0x0115, 800, 600, 32, 1, 100, 37,
- MD_XGI300|MD_XGI315},
- {"800x600x32", 0x63, 0x013b, 0x0115, 800, 600, 32, 1, 100, 37,
- MD_XGI300|MD_XGI315},
- {"1024x576x8", 0x71, 0x0000, 0x0000, 1024, 576, 8, 1, 128, 36,
- MD_XGI300|MD_XGI315},
- {"1024x576x16", 0x74, 0x0000, 0x0000, 1024, 576, 16, 1, 128, 36,
- MD_XGI300|MD_XGI315},
- {"1024x576x24", 0x77, 0x0000, 0x0000, 1024, 576, 32, 1, 128, 36,
- MD_XGI300|MD_XGI315},
- {"1024x576x32", 0x77, 0x0000, 0x0000, 1024, 576, 32, 1, 128, 36,
- MD_XGI300|MD_XGI315},
- {"1024x600x8", 0x20, 0x0000, 0x0000, 1024, 600, 8, 1, 128, 37,
- MD_XGI300 }, /* TW: 300 series only */
- {"1024x600x16", 0x21, 0x0000, 0x0000, 1024, 600, 16, 1, 128, 37,
- MD_XGI300 },
- {"1024x600x24", 0x22, 0x0000, 0x0000, 1024, 600, 32, 1, 128, 37,
- MD_XGI300 },
- {"1024x600x32", 0x22, 0x0000, 0x0000, 1024, 600, 32, 1, 128, 37,
- MD_XGI300 },
- {"1024x768x8", 0x38, 0x0105, 0x0105, 1024, 768, 8, 1, 128, 48,
- MD_XGI300|MD_XGI315},
- {"1024x768x16", 0x4A, 0x0117, 0x0117, 1024, 768, 16, 1, 128, 48,
- MD_XGI300|MD_XGI315},
- {"1024x768x24", 0x64, 0x013c, 0x0118, 1024, 768, 32, 1, 128, 48,
- MD_XGI300|MD_XGI315},
- {"1024x768x32", 0x64, 0x013c, 0x0118, 1024, 768, 32, 1, 128, 48,
- MD_XGI300|MD_XGI315},
- {"1152x768x8", 0x23, 0x0000, 0x0000, 1152, 768, 8, 1, 144, 48,
- MD_XGI300 }, /* TW: 300 series only */
- {"1152x768x16", 0x24, 0x0000, 0x0000, 1152, 768, 16, 1, 144, 48,
- MD_XGI300 },
- {"1152x768x24", 0x25, 0x0000, 0x0000, 1152, 768, 32, 1, 144, 48,
- MD_XGI300 },
- {"1152x768x32", 0x25, 0x0000, 0x0000, 1152, 768, 32, 1, 144, 48,
- MD_XGI300 },
- {"1280x720x8", 0x79, 0x0000, 0x0000, 1280, 720, 8, 1, 160, 45,
- MD_XGI300|MD_XGI315},
- {"1280x720x16", 0x75, 0x0000, 0x0000, 1280, 720, 16, 1, 160, 45,
- MD_XGI300|MD_XGI315},
- {"1280x720x24", 0x78, 0x0000, 0x0000, 1280, 720, 32, 1, 160, 45,
- MD_XGI300|MD_XGI315},
- {"1280x720x32", 0x78, 0x0000, 0x0000, 1280, 720, 32, 1, 160, 45,
- MD_XGI300|MD_XGI315},
- {"1280x768x8", 0x23, 0x0000, 0x0000, 1280, 768, 8, 1, 160, 48,
- MD_XGI315}, /* TW: 310/325 series only */
- {"1280x768x16", 0x24, 0x0000, 0x0000, 1280, 768, 16, 1, 160, 48,
- MD_XGI315},
- {"1280x768x24", 0x25, 0x0000, 0x0000, 1280, 768, 32, 1, 160, 48,
- MD_XGI315},
- {"1280x768x32", 0x25, 0x0000, 0x0000, 1280, 768, 32, 1, 160, 48,
- MD_XGI315},
- {"1280x960x8", 0x7C, 0x0000, 0x0000, 1280, 960, 8, 1, 160, 60,
- MD_XGI300|MD_XGI315},
- {"1280x960x16", 0x7D, 0x0000, 0x0000, 1280, 960, 16, 1, 160, 60,
- MD_XGI300|MD_XGI315},
- {"1280x960x24", 0x7E, 0x0000, 0x0000, 1280, 960, 32, 1, 160, 60,
- MD_XGI300|MD_XGI315},
- {"1280x960x32", 0x7E, 0x0000, 0x0000, 1280, 960, 32, 1, 160, 60,
- MD_XGI300|MD_XGI315},
- {"1280x1024x8", 0x3A, 0x0107, 0x0107, 1280, 1024, 8, 1, 160, 64,
- MD_XGI300|MD_XGI315},
- {"1280x1024x16", 0x4D, 0x011a, 0x011a, 1280, 1024, 16, 1, 160, 64,
- MD_XGI300|MD_XGI315},
- {"1280x1024x24", 0x65, 0x013d, 0x011b, 1280, 1024, 32, 1, 160, 64,
- MD_XGI300|MD_XGI315},
- {"1280x1024x32", 0x65, 0x013d, 0x011b, 1280, 1024, 32, 1, 160, 64,
- MD_XGI300|MD_XGI315},
- {"1400x1050x8", 0x26, 0x0000, 0x0000, 1400, 1050, 8, 1, 175, 65,
- MD_XGI315}, /* TW: 310/325 series only */
- {"1400x1050x16", 0x27, 0x0000, 0x0000, 1400, 1050, 16, 1, 175, 65,
- MD_XGI315},
- {"1400x1050x24", 0x28, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65,
- MD_XGI315},
- {"1400x1050x32", 0x28, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65,
- MD_XGI315},
- {"1600x1200x8", 0x3C, 0x0130, 0x011c, 1600, 1200, 8, 1, 200, 75,
- MD_XGI300|MD_XGI315},
- {"1600x1200x16", 0x3D, 0x0131, 0x011e, 1600, 1200, 16, 1, 200, 75,
- MD_XGI300|MD_XGI315},
- {"1600x1200x24", 0x66, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75,
- MD_XGI300|MD_XGI315},
- {"1600x1200x32", 0x66, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75,
- MD_XGI300|MD_XGI315},
- {"1920x1440x8", 0x68, 0x013f, 0x0000, 1920, 1440, 8, 1, 240, 75,
- MD_XGI300|MD_XGI315},
- {"1920x1440x16", 0x69, 0x0140, 0x0000, 1920, 1440, 16, 1, 240, 75,
- MD_XGI300|MD_XGI315},
- {"1920x1440x24", 0x6B, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75,
- MD_XGI300|MD_XGI315},
- {"1920x1440x32", 0x6B, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75,
- MD_XGI300|MD_XGI315},
- {"2048x1536x8", 0x6c, 0x0000, 0x0000, 2048, 1536, 8, 1, 256, 96,
- MD_XGI315}, /* TW: 310/325 series only */
- {"2048x1536x16", 0x6d, 0x0000, 0x0000, 2048, 1536, 16, 1, 256, 96,
- MD_XGI315},
- {"2048x1536x24", 0x6e, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96,
- MD_XGI315},
- {"2048x1536x32", 0x6e, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96,
- MD_XGI315},
- {"\0", 0x00, 0, 0, 0, 0, 0, 0, 0}
+ { 0x56, 0x0000, 0x0000, 320, 240, 16, MD_XGI315 },
+ { 0x5A, 0x0000, 0x0000, 320, 480, 8, MD_XGI315 },
+ { 0x5B, 0x0000, 0x0000, 320, 480, 16, MD_XGI315 },
+ { 0x2E, 0x0101, 0x0101, 640, 480, 8, MD_XGI315 },
+ { 0x44, 0x0111, 0x0111, 640, 480, 16, MD_XGI315 },
+ { 0x62, 0x013a, 0x0112, 640, 480, 32, MD_XGI315 },
+ { 0x31, 0x0000, 0x0000, 720, 480, 8, MD_XGI315 },
+ { 0x33, 0x0000, 0x0000, 720, 480, 16, MD_XGI315 },
+ { 0x35, 0x0000, 0x0000, 720, 480, 32, MD_XGI315 },
+ { 0x32, 0x0000, 0x0000, 720, 576, 8, MD_XGI315 },
+ { 0x34, 0x0000, 0x0000, 720, 576, 16, MD_XGI315 },
+ { 0x36, 0x0000, 0x0000, 720, 576, 32, MD_XGI315 },
+ { 0x36, 0x0000, 0x0000, 720, 576, 32, MD_XGI315 },
+ { 0x70, 0x0000, 0x0000, 800, 480, 8, MD_XGI315 },
+ { 0x7a, 0x0000, 0x0000, 800, 480, 16, MD_XGI315 },
+ { 0x76, 0x0000, 0x0000, 800, 480, 32, MD_XGI315 },
+ { 0x30, 0x0103, 0x0103, 800, 600, 8, MD_XGI315 },
+#define DEFAULT_MODE 17 /* index for 800x600x16 */
+ { 0x47, 0x0114, 0x0114, 800, 600, 16, MD_XGI315 },
+ { 0x63, 0x013b, 0x0115, 800, 600, 32, MD_XGI315 },
+ { 0x71, 0x0000, 0x0000, 1024, 576, 8, MD_XGI315 },
+ { 0x74, 0x0000, 0x0000, 1024, 576, 16, MD_XGI315 },
+ { 0x77, 0x0000, 0x0000, 1024, 576, 32, MD_XGI315 },
+ { 0x77, 0x0000, 0x0000, 1024, 576, 32, MD_XGI315 },
+ { 0x20, 0x0000, 0x0000, 1024, 600, 8, },
+ { 0x21, 0x0000, 0x0000, 1024, 600, 16, },
+ { 0x22, 0x0000, 0x0000, 1024, 600, 32, },
+ { 0x38, 0x0105, 0x0105, 1024, 768, 8, MD_XGI315 },
+ { 0x4A, 0x0117, 0x0117, 1024, 768, 16, MD_XGI315 },
+ { 0x64, 0x013c, 0x0118, 1024, 768, 32, MD_XGI315 },
+ { 0x64, 0x013c, 0x0118, 1024, 768, 32, MD_XGI315 },
+ { 0x23, 0x0000, 0x0000, 1152, 768, 8, },
+ { 0x24, 0x0000, 0x0000, 1152, 768, 16, },
+ { 0x25, 0x0000, 0x0000, 1152, 768, 32, },
+ { 0x79, 0x0000, 0x0000, 1280, 720, 8, MD_XGI315 },
+ { 0x75, 0x0000, 0x0000, 1280, 720, 16, MD_XGI315 },
+ { 0x78, 0x0000, 0x0000, 1280, 720, 32, MD_XGI315 },
+ { 0x23, 0x0000, 0x0000, 1280, 768, 8, MD_XGI315 },
+ { 0x24, 0x0000, 0x0000, 1280, 768, 16, MD_XGI315 },
+ { 0x25, 0x0000, 0x0000, 1280, 768, 32, MD_XGI315 },
+ { 0x7C, 0x0000, 0x0000, 1280, 960, 8, MD_XGI315 },
+ { 0x7D, 0x0000, 0x0000, 1280, 960, 16, MD_XGI315 },
+ { 0x7E, 0x0000, 0x0000, 1280, 960, 32, MD_XGI315 },
+ { 0x3A, 0x0107, 0x0107, 1280, 1024, 8, MD_XGI315 },
+ { 0x4D, 0x011a, 0x011a, 1280, 1024, 16, MD_XGI315 },
+ { 0x65, 0x013d, 0x011b, 1280, 1024, 32, MD_XGI315 },
+ { 0x26, 0x0000, 0x0000, 1400, 1050, 8, MD_XGI315 },
+ { 0x27, 0x0000, 0x0000, 1400, 1050, 16, MD_XGI315 },
+ { 0x28, 0x0000, 0x0000, 1400, 1050, 32, MD_XGI315 },
+ { 0x3C, 0x0130, 0x011c, 1600, 1200, 8, MD_XGI315 },
+ { 0x3D, 0x0131, 0x011e, 1600, 1200, 16, MD_XGI315 },
+ { 0x66, 0x013e, 0x011f, 1600, 1200, 32, MD_XGI315 },
+ { 0x68, 0x013f, 0x0000, 1920, 1440, 8, MD_XGI315 },
+ { 0x69, 0x0140, 0x0000, 1920, 1440, 16, MD_XGI315 },
+ { 0x6B, 0x0141, 0x0000, 1920, 1440, 32, MD_XGI315 },
+ { 0x6c, 0x0000, 0x0000, 2048, 1536, 8, MD_XGI315 },
+ { 0x6d, 0x0000, 0x0000, 2048, 1536, 16, MD_XGI315 },
+ { 0x6e, 0x0000, 0x0000, 2048, 1536, 32, MD_XGI315 },
+ { 0 },
};
-/* TW: CR36 evaluation */
-static const unsigned short XGI300paneltype[] = {
- LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024,
- LCD_1280x960, LCD_640x480, LCD_1024x600, LCD_1152x768,
- LCD_1024x768, LCD_1024x768, LCD_1024x768,
- LCD_1024x768, LCD_1024x768, LCD_1024x768, LCD_1024x768};
-
static const unsigned short XGI310paneltype[] = {
LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024,
LCD_640x480, LCD_1024x600, LCD_1152x864, LCD_1280x960,
diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c
index 21c037827de4..85dbf32b1f66 100644
--- a/drivers/staging/xgifb/XGI_main_26.c
+++ b/drivers/staging/xgifb/XGI_main_26.c
@@ -156,25 +156,14 @@ static int XGIfb_mode_rate_to_dclock(struct vb_device_info *XGI_Pr,
unsigned short ModeNo = modeno;
unsigned short ModeIdIndex = 0, ClockIndex = 0;
unsigned short RefreshRateTableIndex = 0;
-
- /* unsigned long temp = 0; */
int Clock;
InitTo330Pointer(HwDeviceExtension->jChipType, XGI_Pr);
+ XGI_SearchModeID(ModeNo, &ModeIdIndex, XGI_Pr);
+
RefreshRateTableIndex = XGI_GetRatePtrCRT2(HwDeviceExtension, ModeNo,
ModeIdIndex, XGI_Pr);
- /*
- temp = XGI_SearchModeID(ModeNo , &ModeIdIndex, XGI_Pr) ;
- if (!temp) {
- printk(KERN_ERR "Could not find mode %x\n", ModeNo);
- return 65000;
- }
-
- RefreshRateTableIndex = XGI_Pr->EModeIDTable[ModeIdIndex].REFindex;
- RefreshRateTableIndex += (rateindex - 1);
-
- */
ClockIndex = XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
Clock = XGI_Pr->VCLKData[ClockIndex].CLOCK * 1000;
@@ -190,7 +179,7 @@ static int XGIfb_mode_rate_to_ddata(struct vb_device_info *XGI_Pr,
u32 *vmode)
{
unsigned short ModeNo = modeno;
- unsigned short ModeIdIndex = 0, index = 0;
+ unsigned short ModeIdIndex, index = 0;
unsigned short RefreshRateTableIndex = 0;
unsigned short VRE, VBE, VRS, VBS, VDE, VT;
@@ -199,16 +188,10 @@ static int XGIfb_mode_rate_to_ddata(struct vb_device_info *XGI_Pr,
unsigned long cr_data3;
int A, B, C, D, E, F, temp, j;
InitTo330Pointer(HwDeviceExtension->jChipType, XGI_Pr);
+ if (!XGI_SearchModeID(ModeNo, &ModeIdIndex, XGI_Pr))
+ return 0;
RefreshRateTableIndex = XGI_GetRatePtrCRT2(HwDeviceExtension, ModeNo,
ModeIdIndex, XGI_Pr);
- /*
- temp = XGI_SearchModeID(ModeNo, &ModeIdIndex, XGI_Pr);
- if (!temp)
- return 0;
-
- RefreshRateTableIndex = XGI_Pr->EModeIDTable[ModeIdIndex].REFindex;
- RefreshRateTableIndex += (rateindex - 1);
- */
index = XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
sr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[5];
@@ -219,12 +202,6 @@ static int XGIfb_mode_rate_to_ddata(struct vb_device_info *XGI_Pr,
HT = (cr_data & 0xff) | ((unsigned short) (sr_data & 0x03) << 8);
A = HT + 5;
- /*
- cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[1];
-
- Horizontal display enable end
- HDE = (cr_data & 0xff) | ((unsigned short) (sr_data & 0x0C) << 6);
- */
HDE = (XGI_Pr->RefIndex[RefreshRateTableIndex].XRes >> 3) - 1;
E = HDE + 1;
@@ -358,7 +335,6 @@ static int XGIfb_mode_rate_to_ddata(struct vb_device_info *XGI_Pr,
static void XGIRegInit(struct vb_device_info *XGI_Pr, unsigned long BaseAddr)
{
- XGI_Pr->RelIO = BaseAddr;
XGI_Pr->P3c4 = BaseAddr + 0x14;
XGI_Pr->P3d4 = BaseAddr + 0x24;
XGI_Pr->P3c0 = BaseAddr + 0x10;
@@ -414,19 +390,26 @@ static int XGIfb_GetXG21DefaultLVDSModeIdx(struct xgifb_video_info *xgifb_info)
static void XGIfb_search_mode(struct xgifb_video_info *xgifb_info,
const char *name)
{
- int i = 0, j = 0, l;
+ unsigned int xres;
+ unsigned int yres;
+ unsigned int bpp;
+ int i;
- while (XGIbios_mode[i].mode_no != 0) {
- l = min(strlen(name), strlen(XGIbios_mode[i].name));
- if (!strncmp(name, XGIbios_mode[i].name, l)) {
+ if (sscanf(name, "%ux%ux%u", &xres, &yres, &bpp) != 3)
+ goto invalid_mode;
+
+ if (bpp == 24)
+ bpp = 32; /* That's for people who mix up color and fb depth. */
+
+ for (i = 0; XGIbios_mode[i].mode_no != 0; i++)
+ if (XGIbios_mode[i].xres == xres &&
+ XGIbios_mode[i].yres == yres &&
+ XGIbios_mode[i].bpp == bpp) {
xgifb_info->mode_idx = i;
- j = 1;
- break;
+ return;
}
- i++;
- }
- if (!j)
- pr_info("Invalid mode '%s'\n", name);
+invalid_mode:
+ pr_info("Invalid mode '%s'\n", name);
}
static void XGIfb_search_vesamode(struct xgifb_video_info *xgifb_info,
@@ -1088,7 +1071,7 @@ static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
unsigned int vtotal = var->upper_margin + var->yres + var->lower_margin
+ var->vsync_len;
#if defined(__powerpc__)
- u8 sr_data, cr_data;
+ u8 cr_data;
#endif
unsigned int drate = 0, hrate = 0;
int found_mode = 0;
@@ -1162,8 +1145,7 @@ static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
if (XGIfb_search_refresh_rate(xgifb_info,
xgifb_info->refresh_rate) == 0) {
- xgifb_info->rate_idx =
- XGIbios_mode[xgifb_info->mode_idx].rate_idx;
+ xgifb_info->rate_idx = 1;
xgifb_info->refresh_rate = 60;
}
@@ -1680,17 +1662,6 @@ static int XGIfb_get_dram_size(struct xgifb_video_info *xgifb_info)
ChannelNum = 1;
break;
- case XG45:
- if (tmp == 1)
- ChannelNum = 2;
- else if (tmp == 2)
- ChannelNum = 3;
- else if (tmp == 3)
- ChannelNum = 4;
- else
- ChannelNum = 1;
- break;
-
case XG40:
default:
if (tmp == 2)
@@ -1911,11 +1882,9 @@ static int __devinit xgifb_probe(struct pci_dev *pdev,
xgifb_info->mmio_base = pci_resource_start(pdev, 1);
xgifb_info->mmio_size = pci_resource_len(pdev, 1);
xgifb_info->vga_base = pci_resource_start(pdev, 2) + 0x30;
- hw_info->pjIOAddress = (unsigned char *)xgifb_info->vga_base;
- /* XGI_Pr.RelIO = ioremap(pci_resource_start(pdev, 2), 128) + 0x30; */
- pr_info("Relocate IO address: %lx [%08lx]\n",
- (unsigned long)pci_resource_start(pdev, 2),
- xgifb_info->dev_info.RelIO);
+ pr_info("Relocate IO address: %Lx [%08lx]\n",
+ (u64) pci_resource_start(pdev, 2),
+ xgifb_info->vga_base);
if (pci_enable_device(pdev)) {
ret = -EIO;
@@ -1927,7 +1896,7 @@ static int __devinit xgifb_probe(struct pci_dev *pdev,
xgifb_info->display2_force = true;
}
- XGIRegInit(&xgifb_info->dev_info, (unsigned long)hw_info->pjIOAddress);
+ XGIRegInit(&xgifb_info->dev_info, xgifb_info->vga_base);
xgifb_reg_set(XGISR, IND_SIS_PASSWORD, SIS_PASSWORD);
reg1 = xgifb_reg_get(XGISR, IND_SIS_PASSWORD);
@@ -1950,9 +1919,6 @@ static int __devinit xgifb_probe(struct pci_dev *pdev,
case PCI_DEVICE_ID_XGI_40:
xgifb_info->chip = XG40;
break;
- case PCI_DEVICE_ID_XGI_41:
- xgifb_info->chip = XG41;
- break;
case PCI_DEVICE_ID_XGI_42:
xgifb_info->chip = XG42;
break;
@@ -2006,13 +1972,13 @@ static int __devinit xgifb_probe(struct pci_dev *pdev,
xgifb_info->mmio_vbase = ioremap(xgifb_info->mmio_base,
xgifb_info->mmio_size);
- pr_info("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
- xgifb_info->video_base,
+ pr_info("Framebuffer at 0x%Lx, mapped to 0x%p, size %dk\n",
+ (u64) xgifb_info->video_base,
xgifb_info->video_vbase,
xgifb_info->video_size / 1024);
- pr_info("MMIO at 0x%lx, mapped to 0x%p, size %ldk\n",
- xgifb_info->mmio_base, xgifb_info->mmio_vbase,
+ pr_info("MMIO at 0x%Lx, mapped to 0x%p, size %ldk\n",
+ (u64) xgifb_info->mmio_base, xgifb_info->mmio_vbase,
xgifb_info->mmio_size / 1024);
pci_set_drvdata(pdev, xgifb_info);
@@ -2174,8 +2140,7 @@ static int __devinit xgifb_probe(struct pci_dev *pdev,
xgifb_info->refresh_rate = 60;
if (XGIfb_search_refresh_rate(xgifb_info,
xgifb_info->refresh_rate) == 0) {
- xgifb_info->rate_idx =
- XGIbios_mode[xgifb_info->mode_idx].rate_idx;
+ xgifb_info->rate_idx = 1;
xgifb_info->refresh_rate = 60;
}
diff --git a/drivers/staging/xgifb/XGIfb.h b/drivers/staging/xgifb/XGIfb.h
index 37bb730de047..9068c5ad76ec 100644
--- a/drivers/staging/xgifb/XGIfb.h
+++ b/drivers/staging/xgifb/XGIfb.h
@@ -23,9 +23,7 @@ enum xgifb_display_type {
enum XGI_CHIP_TYPE {
XG40 = 32,
- XG41,
XG42,
- XG45,
XG20 = 48,
XG21,
XG27,
@@ -66,9 +64,9 @@ struct xgifb_video_info {
int chip_id;
unsigned int video_size;
- unsigned long video_base;
+ phys_addr_t video_base;
void __iomem *video_vbase;
- unsigned long mmio_base;
+ phys_addr_t mmio_base;
unsigned long mmio_size;
void __iomem *mmio_vbase;
unsigned long vga_base;
diff --git a/drivers/staging/xgifb/vb_init.c b/drivers/staging/xgifb/vb_init.c
index 3650bbff7686..c222d611431d 100644
--- a/drivers/staging/xgifb/vb_init.c
+++ b/drivers/staging/xgifb/vb_init.c
@@ -353,7 +353,6 @@ static void XGINew_DDR1x_DefaultRegister(
XGINew_SetMemoryClock(HwDeviceExtension, pVBInfo);
switch (HwDeviceExtension->jChipType) {
- case XG41:
case XG42:
/* CR82 */
xgifb_reg_set(P3d4,
@@ -556,8 +555,7 @@ static void XGINew_SetDRAMDefaultRegister340(
xgifb_reg_set(P3d4, (0x8A + j),
pVBInfo->CR40[1 + j][pVBInfo->ram_type]);
- if ((HwDeviceExtension->jChipType == XG41) ||
- (HwDeviceExtension->jChipType == XG42))
+ if (HwDeviceExtension->jChipType == XG42)
xgifb_reg_set(P3d4, 0x8C, 0x87);
xgifb_reg_set(P3d4,
@@ -854,78 +852,6 @@ static void XGINew_CheckChannel(struct xgi_hw_device_info *HwDeviceExtension,
pVBInfo->ram_channel = 1; /* Single channel */
xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x51); /* 32Mx16 bit*/
break;
- case XG41:
- if (XGINew_CheckFrequence(pVBInfo) == 1) {
- pVBInfo->ram_bus = 32; /* 32 bits */
- pVBInfo->ram_channel = 3; /* Quad Channel */
- xgifb_reg_set(pVBInfo->P3c4, 0x13, 0xA1);
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x4C);
-
- if (XGINew_ReadWriteRest(25, 23, pVBInfo) == 1)
- return;
-
- pVBInfo->ram_channel = 2; /* Dual channels */
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x48);
-
- if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1)
- return;
-
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x49);
-
- if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1)
- return;
-
- pVBInfo->ram_channel = 3;
- xgifb_reg_set(pVBInfo->P3c4, 0x13, 0x21);
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x3C);
-
- if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1)
- return;
-
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x38);
-
- if (XGINew_ReadWriteRest(8, 4, pVBInfo) == 1)
- return;
- else
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x39);
- } else { /* DDR */
- pVBInfo->ram_bus = 64; /* 64 bits */
- pVBInfo->ram_channel = 2; /* Dual channels */
- xgifb_reg_set(pVBInfo->P3c4, 0x13, 0xA1);
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x5A);
-
- if (XGINew_ReadWriteRest(25, 24, pVBInfo) == 1)
- return;
-
- pVBInfo->ram_channel = 1; /* Single channels */
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x52);
-
- if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1)
- return;
-
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x53);
-
- if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1)
- return;
-
- pVBInfo->ram_channel = 2; /* Dual channels */
- xgifb_reg_set(pVBInfo->P3c4, 0x13, 0x21);
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x4A);
-
- if (XGINew_ReadWriteRest(24, 23, pVBInfo) == 1)
- return;
-
- pVBInfo->ram_channel = 1; /* Single channels */
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x42);
-
- if (XGINew_ReadWriteRest(8, 4, pVBInfo) == 1)
- return;
- else
- xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x43);
- }
-
- break;
-
case XG42:
/*
XG42 SR14 D[3] Reserve
@@ -1478,7 +1404,7 @@ unsigned char XGIInitNew(struct pci_dev *pdev)
pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress;
- pVBInfo->BaseAddr = (unsigned long) HwDeviceExtension->pjIOAddress;
+ pVBInfo->BaseAddr = xgifb_info->vga_base;
/* Newdebugcode(0x99); */
diff --git a/drivers/staging/xgifb/vb_setmode.c b/drivers/staging/xgifb/vb_setmode.c
index 60d4adf99923..b2f4338b1109 100644
--- a/drivers/staging/xgifb/vb_setmode.c
+++ b/drivers/staging/xgifb/vb_setmode.c
@@ -16,36 +16,6 @@
#define IndexMask 0xff
-static const unsigned short XGINew_MDA_DAC[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
- 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
- 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F};
-
-static const unsigned short XGINew_CGA_DAC[] = {
- 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
- 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
- 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
- 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
- 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
- 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
- 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
- 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F};
-
-static const unsigned short XGINew_EGA_DAC[] = {
- 0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15,
- 0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35,
- 0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D,
- 0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D,
- 0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17,
- 0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37,
- 0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F,
- 0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F};
-
static const unsigned short XGINew_VGA_DAC[] = {
0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
@@ -60,8 +30,7 @@ static const unsigned short XGINew_VGA_DAC[] = {
void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo)
{
- pVBInfo->SModeIDTable = (struct XGI_StStruct *) XGI330_SModeIDTable;
- pVBInfo->StandTable = (struct SiS_StandTable_S *) XGI330_StandTable;
+ pVBInfo->StandTable = (struct SiS_StandTable_S *) &XGI330_StandTable;
pVBInfo->EModeIDTable = (struct XGI_ExtStruct *) XGI330_EModeIDTable;
pVBInfo->RefIndex = (struct XGI_Ext2Struct *) XGI330_RefIndex;
pVBInfo->XGINEWUB_CRT1Table
@@ -182,38 +151,17 @@ void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo)
}
-static unsigned char XGI_GetModePtr(unsigned short ModeNo,
- unsigned short ModeIdIndex,
- struct vb_device_info *pVBInfo)
-{
- unsigned char index;
-
- if (ModeNo <= 0x13)
- index = pVBInfo->SModeIDTable[ModeIdIndex].St_StTableIndex;
- else {
- if (pVBInfo->ModeType <= 0x02)
- index = 0x1B; /* 02 -> ModeEGA */
- else
- index = 0x0F;
- }
- return index; /* Get pVBInfo->StandTable index */
-}
-
static void XGI_SetSeqRegs(unsigned short ModeNo,
- unsigned short StandTableIndex,
unsigned short ModeIdIndex,
struct vb_device_info *pVBInfo)
{
unsigned char tempah, SRdata;
unsigned short i, modeflag;
- if (ModeNo <= 0x13)
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
xgifb_reg_set(pVBInfo->P3c4, 0x00, 0x03); /* Set SR0 */
- tempah = pVBInfo->StandTable[StandTableIndex].SR[0];
+ tempah = pVBInfo->StandTable->SR[0];
i = XGI_SetCRT2ToLCDA;
if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) {
@@ -230,13 +178,12 @@ static void XGI_SetSeqRegs(unsigned short ModeNo,
for (i = 02; i <= 04; i++) {
/* Get SR2,3,4 from file */
- SRdata = pVBInfo->StandTable[StandTableIndex].SR[i - 1];
+ SRdata = pVBInfo->StandTable->SR[i - 1];
xgifb_reg_set(pVBInfo->P3c4, i, SRdata); /* Set SR2 3 4 */
}
}
static void XGI_SetCRTCRegs(struct xgi_hw_device_info *HwDeviceExtension,
- unsigned short StandTableIndex,
struct vb_device_info *pVBInfo)
{
unsigned char CRTCdata;
@@ -248,26 +195,22 @@ static void XGI_SetCRTCRegs(struct xgi_hw_device_info *HwDeviceExtension,
for (i = 0; i <= 0x18; i++) {
/* Get CRTC from file */
- CRTCdata = pVBInfo->StandTable[StandTableIndex].CRTC[i];
+ CRTCdata = pVBInfo->StandTable->CRTC[i];
xgifb_reg_set(pVBInfo->P3d4, i, CRTCdata); /* Set CRTC(3d4) */
}
}
static void XGI_SetATTRegs(unsigned short ModeNo,
- unsigned short StandTableIndex,
unsigned short ModeIdIndex,
struct vb_device_info *pVBInfo)
{
unsigned char ARdata;
unsigned short i, modeflag;
- if (ModeNo <= 0x13)
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
for (i = 0; i <= 0x13; i++) {
- ARdata = pVBInfo->StandTable[StandTableIndex].ATTR[i];
+ ARdata = pVBInfo->StandTable->ATTR[i];
if (modeflag & Charx8Dot) { /* ifndef Dot9 */
if (i == 0x13) {
if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) {
@@ -295,15 +238,14 @@ static void XGI_SetATTRegs(unsigned short ModeNo,
outb(0x20, pVBInfo->P3c0);
}
-static void XGI_SetGRCRegs(unsigned short StandTableIndex,
- struct vb_device_info *pVBInfo)
+static void XGI_SetGRCRegs(struct vb_device_info *pVBInfo)
{
unsigned char GRdata;
unsigned short i;
for (i = 0; i <= 0x08; i++) {
/* Get GR from file */
- GRdata = pVBInfo->StandTable[StandTableIndex].GRC[i];
+ GRdata = pVBInfo->StandTable->GRC[i];
xgifb_reg_set(pVBInfo->P3ce, i, GRdata); /* Set GR(3ce) */
}
@@ -344,12 +286,7 @@ static unsigned char XGI_AjustCRT2Rate(unsigned short ModeNo,
{
unsigned short tempax, tempbx, resinfo, modeflag, infoflag;
- if (ModeNo <= 0x13)
- /* si+St_ModeFlag */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
tempbx = pVBInfo->RefIndex[RefreshRateTableIndex + (*i)].ModeID;
tempax = 0;
@@ -584,11 +521,7 @@ static void XGI_SetCRT1Timing_V(unsigned short ModeIdIndex,
data &= 0x80;
data = data >> 2;
- if (ModeNo <= 0x13)
- i = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- i = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-
+ i = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
i &= DoubleScanMode;
if (i)
data |= 0x80;
@@ -641,158 +574,97 @@ static void XGI_SetXG21CRTC(unsigned short ModeNo, unsigned short ModeIdIndex,
unsigned short RefreshRateTableIndex,
struct vb_device_info *pVBInfo)
{
- unsigned char StandTableIndex, index, Tempax, Tempbx, Tempcx, Tempdx;
+ unsigned char index, Tempax, Tempbx, Tempcx, Tempdx;
unsigned short Temp1, Temp2, Temp3;
- if (ModeNo <= 0x13) {
- StandTableIndex = XGI_GetModePtr(ModeNo, ModeIdIndex, pVBInfo);
- /* CR04 HRS */
- Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[4];
- /* SR2E [7:0]->HRS */
- xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax);
- /* Tempbx: CR05 HRE */
- Tempbx = pVBInfo->StandTable[StandTableIndex].CRTC[5];
- Tempbx &= 0x1F; /* Tempbx: HRE[4:0] */
- Tempcx = Tempax;
- Tempcx &= 0xE0; /* Tempcx: HRS[7:5] */
- Tempdx = Tempcx | Tempbx; /* Tempdx(HRE): HRS[7:5]HRE[4:0] */
- if (Tempbx < (Tempax & 0x1F)) /* IF HRE < HRS */
- Tempdx |= 0x20; /* Tempdx: HRE = HRE + 0x20 */
- Tempdx <<= 2; /* Tempdx << 2 */
- /* SR2F [7:2]->HRE */
- xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempdx);
- xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00);
-
- /* Tempax: CR16 VRS */
- Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[16];
- Tempbx = Tempax; /* Tempbx=Tempax */
- Tempax &= 0x01; /* Tempax: VRS[0] */
- xgifb_reg_or(pVBInfo->P3c4, 0x33, Tempax); /* SR33[0]->VRS */
-
- /* Tempax: CR7 VRS */
- Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[7];
- Tempdx = Tempbx >> 1; /* Tempdx: VRS[7:1] */
- Tempcx = Tempax & 0x04; /* Tempcx: CR7[2] */
- Tempcx <<= 5; /* Tempcx[7]: VRS[8] */
- Tempdx |= Tempcx; /* Tempdx: VRS[8:1] */
- /* SR34[7:0]: VRS[8:1] */
- xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempdx);
-
- /* Temp1[8]: VRS[8] unsigned char -> unsigned short */
- Temp1 = Tempcx << 1;
- Temp1 |= Tempbx; /* Temp1[8:0]: VRS[8:0] */
- Tempax &= 0x80; /* Tempax[7]: CR7[7] */
- Temp2 = Tempax << 2; /* Temp2[9]: VRS[9] */
- Temp1 |= Temp2; /* Temp1[9:0]: VRS[9:0] */
-
- /* CR16 VRE */
- Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[17];
- Tempax &= 0x0F; /* Tempax[3:0]: VRE[3:0] */
- Temp2 = Temp1 & 0x3F0; /* Temp2[9:4]: VRS[9:4] */
- Temp2 |= Tempax; /* Temp2[9:0]: VRE[9:0] */
- Temp3 = Temp1 & 0x0F; /* Temp3[3:0]: VRS[3:0] */
- if (Tempax < Temp3) /* VRE[3:0]<VRS[3:0] */
- Temp2 |= 0x10; /* Temp2: VRE + 0x10 */
- Temp2 &= 0xFF; /* Temp2[7:0]: VRE[7:0] */
- Tempax = (unsigned char) Temp2; /* Tempax[7:0]: VRE[7:0] */
- Tempax <<= 2; /* Tempax << 2: VRE[5:0] */
- Temp1 &= 0x600; /* Temp1[10:9]: VRS[10:9] */
- Temp1 >>= 9; /* [10:9]->[1:0] */
- Tempbx = (unsigned char) Temp1; /* Tempbx[1:0]: VRS[10:9] */
- Tempax |= Tempbx; /* VRE[5:0]VRS[10:9] */
- Tempax &= 0x7F;
- /* SR3F D[7:2]->VRE D[1:0]->VRS */
- xgifb_reg_set(pVBInfo->P3c4, 0x3F, Tempax);
- } else {
- index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
- /* Tempax: CR4 HRS */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3];
- Tempcx = Tempax; /* Tempcx: HRS */
- /* SR2E[7:0]->HRS */
- xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax);
-
- Tempdx = pVBInfo->XGINEWUB_CRT1Table[index].CR[5]; /* SRB */
- Tempdx &= 0xC0; /* Tempdx[7:6]: SRB[7:6] */
- Temp1 = Tempdx; /* Temp1[7:6]: HRS[9:8] */
- Temp1 <<= 2; /* Temp1[9:8]: HRS[9:8] */
- Temp1 |= Tempax; /* Temp1[9:0]: HRS[9:0] */
-
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[4]; /* CR5 HRE */
- Tempax &= 0x1F; /* Tempax[4:0]: HRE[4:0] */
-
- Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[6]; /* SRC */
- Tempbx &= 0x04; /* Tempbx[2]: HRE[5] */
- Tempbx <<= 3; /* Tempbx[5]: HRE[5] */
- Tempax |= Tempbx; /* Tempax[5:0]: HRE[5:0] */
-
- Temp2 = Temp1 & 0x3C0; /* Temp2[9:6]: HRS[9:6] */
- Temp2 |= Tempax; /* Temp2[9:0]: HRE[9:0] */
-
- Tempcx &= 0x3F; /* Tempcx[5:0]: HRS[5:0] */
- if (Tempax < Tempcx) /* HRE < HRS */
- Temp2 |= 0x40; /* Temp2 + 0x40 */
-
- Temp2 &= 0xFF;
- Tempax = (unsigned char) Temp2; /* Tempax: HRE[7:0] */
- Tempax <<= 2; /* Tempax[7:2]: HRE[5:0] */
- Tempdx >>= 6; /* Tempdx[7:6]->[1:0] HRS[9:8] */
- Tempax |= Tempdx; /* HRE[5:0]HRS[9:8] */
- /* SR2F D[7:2]->HRE, D[1:0]->HRS */
- xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempax);
- xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00);
-
- /* CR10 VRS */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[10];
- Tempbx = Tempax; /* Tempbx: VRS */
- Tempax &= 0x01; /* Tempax[0]: VRS[0] */
- xgifb_reg_or(pVBInfo->P3c4, 0x33, Tempax); /* SR33[0]->VRS[0] */
- /* CR7[2][7] VRE */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[9];
- Tempcx = Tempbx >> 1; /* Tempcx[6:0]: VRS[7:1] */
- Tempdx = Tempax & 0x04; /* Tempdx[2]: CR7[2] */
- Tempdx <<= 5; /* Tempdx[7]: VRS[8] */
- Tempcx |= Tempdx; /* Tempcx[7:0]: VRS[8:1] */
- xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempcx); /* SR34[8:1]->VRS */
-
- Temp1 = Tempdx; /* Temp1[7]: Tempdx[7] */
- Temp1 <<= 1; /* Temp1[8]: VRS[8] */
- Temp1 |= Tempbx; /* Temp1[8:0]: VRS[8:0] */
- Tempax &= 0x80;
- Temp2 = Tempax << 2; /* Temp2[9]: VRS[9] */
- Temp1 |= Temp2; /* Temp1[9:0]: VRS[9:0] */
- /* Tempax: SRA */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
- Tempax &= 0x08; /* Tempax[3]: VRS[3] */
- Temp2 = Tempax;
- Temp2 <<= 7; /* Temp2[10]: VRS[10] */
- Temp1 |= Temp2; /* Temp1[10:0]: VRS[10:0] */
-
- /* Tempax: CR11 VRE */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[11];
- Tempax &= 0x0F; /* Tempax[3:0]: VRE[3:0] */
- /* Tempbx: SRA */
- Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
- Tempbx &= 0x20; /* Tempbx[5]: VRE[5] */
- Tempbx >>= 1; /* Tempbx[4]: VRE[4] */
- Tempax |= Tempbx; /* Tempax[4:0]: VRE[4:0] */
- Temp2 = Temp1 & 0x7E0; /* Temp2[10:5]: VRS[10:5] */
- Temp2 |= Tempax; /* Temp2[10:5]: VRE[10:5] */
-
- Temp3 = Temp1 & 0x1F; /* Temp3[4:0]: VRS[4:0] */
- if (Tempax < Temp3) /* VRE < VRS */
- Temp2 |= 0x20; /* VRE + 0x20 */
-
- Temp2 &= 0xFF;
- Tempax = (unsigned char) Temp2; /* Tempax: VRE[7:0] */
- Tempax <<= 2; /* Tempax[7:0]; VRE[5:0]00 */
- Temp1 &= 0x600; /* Temp1[10:9]: VRS[10:9] */
- Temp1 >>= 9; /* Temp1[1:0]: VRS[10:9] */
- Tempbx = (unsigned char) Temp1;
- Tempax |= Tempbx; /* Tempax[7:0]: VRE[5:0]VRS[10:9] */
- Tempax &= 0x7F;
- /* SR3F D[7:2]->VRE D[1:0]->VRS */
- xgifb_reg_set(pVBInfo->P3c4, 0x3F, Tempax);
- }
+ index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+ /* Tempax: CR4 HRS */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3];
+ Tempcx = Tempax; /* Tempcx: HRS */
+ /* SR2E[7:0]->HRS */
+ xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax);
+
+ Tempdx = pVBInfo->XGINEWUB_CRT1Table[index].CR[5]; /* SRB */
+ Tempdx &= 0xC0; /* Tempdx[7:6]: SRB[7:6] */
+ Temp1 = Tempdx; /* Temp1[7:6]: HRS[9:8] */
+ Temp1 <<= 2; /* Temp1[9:8]: HRS[9:8] */
+ Temp1 |= Tempax; /* Temp1[9:0]: HRS[9:0] */
+
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[4]; /* CR5 HRE */
+ Tempax &= 0x1F; /* Tempax[4:0]: HRE[4:0] */
+
+ Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[6]; /* SRC */
+ Tempbx &= 0x04; /* Tempbx[2]: HRE[5] */
+ Tempbx <<= 3; /* Tempbx[5]: HRE[5] */
+ Tempax |= Tempbx; /* Tempax[5:0]: HRE[5:0] */
+
+ Temp2 = Temp1 & 0x3C0; /* Temp2[9:6]: HRS[9:6] */
+ Temp2 |= Tempax; /* Temp2[9:0]: HRE[9:0] */
+
+ Tempcx &= 0x3F; /* Tempcx[5:0]: HRS[5:0] */
+ if (Tempax < Tempcx) /* HRE < HRS */
+ Temp2 |= 0x40; /* Temp2 + 0x40 */
+
+ Temp2 &= 0xFF;
+ Tempax = (unsigned char) Temp2; /* Tempax: HRE[7:0] */
+ Tempax <<= 2; /* Tempax[7:2]: HRE[5:0] */
+ Tempdx >>= 6; /* Tempdx[7:6]->[1:0] HRS[9:8] */
+ Tempax |= Tempdx; /* HRE[5:0]HRS[9:8] */
+ /* SR2F D[7:2]->HRE, D[1:0]->HRS */
+ xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempax);
+ xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00);
+
+ /* CR10 VRS */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[10];
+ Tempbx = Tempax; /* Tempbx: VRS */
+ Tempax &= 0x01; /* Tempax[0]: VRS[0] */
+ xgifb_reg_or(pVBInfo->P3c4, 0x33, Tempax); /* SR33[0]->VRS[0] */
+ /* CR7[2][7] VRE */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[9];
+ Tempcx = Tempbx >> 1; /* Tempcx[6:0]: VRS[7:1] */
+ Tempdx = Tempax & 0x04; /* Tempdx[2]: CR7[2] */
+ Tempdx <<= 5; /* Tempdx[7]: VRS[8] */
+ Tempcx |= Tempdx; /* Tempcx[7:0]: VRS[8:1] */
+ xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempcx); /* SR34[8:1]->VRS */
+
+ Temp1 = Tempdx; /* Temp1[7]: Tempdx[7] */
+ Temp1 <<= 1; /* Temp1[8]: VRS[8] */
+ Temp1 |= Tempbx; /* Temp1[8:0]: VRS[8:0] */
+ Tempax &= 0x80;
+ Temp2 = Tempax << 2; /* Temp2[9]: VRS[9] */
+ Temp1 |= Temp2; /* Temp1[9:0]: VRS[9:0] */
+ /* Tempax: SRA */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
+ Tempax &= 0x08; /* Tempax[3]: VRS[3] */
+ Temp2 = Tempax;
+ Temp2 <<= 7; /* Temp2[10]: VRS[10] */
+ Temp1 |= Temp2; /* Temp1[10:0]: VRS[10:0] */
+
+ /* Tempax: CR11 VRE */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[11];
+ Tempax &= 0x0F; /* Tempax[3:0]: VRE[3:0] */
+ /* Tempbx: SRA */
+ Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
+ Tempbx &= 0x20; /* Tempbx[5]: VRE[5] */
+ Tempbx >>= 1; /* Tempbx[4]: VRE[4] */
+ Tempax |= Tempbx; /* Tempax[4:0]: VRE[4:0] */
+ Temp2 = Temp1 & 0x7E0; /* Temp2[10:5]: VRS[10:5] */
+ Temp2 |= Tempax; /* Temp2[10:5]: VRE[10:5] */
+
+ Temp3 = Temp1 & 0x1F; /* Temp3[4:0]: VRS[4:0] */
+ if (Tempax < Temp3) /* VRE < VRS */
+ Temp2 |= 0x20; /* VRE + 0x20 */
+
+ Temp2 &= 0xFF;
+ Tempax = (unsigned char) Temp2; /* Tempax: VRE[7:0] */
+ Tempax <<= 2; /* Tempax[7:0]; VRE[5:0]00 */
+ Temp1 &= 0x600; /* Temp1[10:9]: VRS[10:9] */
+ Temp1 >>= 9; /* Temp1[1:0]: VRS[10:9] */
+ Tempbx = (unsigned char) Temp1;
+ Tempax |= Tempbx; /* Tempax[7:0]: VRE[5:0]VRS[10:9] */
+ Tempax &= 0x7F;
+ /* SR3F D[7:2]->VRE D[1:0]->VRS */
+ xgifb_reg_set(pVBInfo->P3c4, 0x3F, Tempax);
}
static void XGI_SetXG27CRTC(unsigned short ModeNo,
@@ -800,139 +672,88 @@ static void XGI_SetXG27CRTC(unsigned short ModeNo,
unsigned short RefreshRateTableIndex,
struct vb_device_info *pVBInfo)
{
- unsigned short StandTableIndex, index, Tempax, Tempbx, Tempcx, Tempdx;
-
- if (ModeNo <= 0x13) {
- StandTableIndex = XGI_GetModePtr(ModeNo, ModeIdIndex, pVBInfo);
- /* CR04 HRS */
- Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[4];
- /* SR2E [7:0]->HRS */
- xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax);
- /* Tempbx: CR05 HRE */
- Tempbx = pVBInfo->StandTable[StandTableIndex].CRTC[5];
- Tempbx &= 0x1F; /* Tempbx: HRE[4:0] */
- Tempcx = Tempax;
- Tempcx &= 0xE0; /* Tempcx: HRS[7:5] */
- Tempdx = Tempcx | Tempbx; /* Tempdx(HRE): HRS[7:5]HRE[4:0] */
- if (Tempbx < (Tempax & 0x1F)) /* IF HRE < HRS */
- Tempdx |= 0x20; /* Tempdx: HRE = HRE + 0x20 */
- Tempdx <<= 2; /* Tempdx << 2 */
- /* SR2F [7:2]->HRE */
- xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempdx);
- xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00);
-
- /* Tempax: CR10 VRS */
- Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[16];
- xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempax); /* SR34[7:0]->VRS */
- Tempcx = Tempax; /* Tempcx=Tempax=VRS[7:0] */
- /* Tempax[7][2]: CR7[7][2] VRS[9][8] */
- Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[7];
- Tempbx = Tempax; /* Tempbx=CR07 */
- Tempax &= 0x04; /* Tempax[2]: CR07[2] VRS[8] */
- Tempax >>= 2;
- /* SR35 D[0]->VRS D[8] */
- xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x01, Tempax);
- Tempcx |= (Tempax << 8); /* Tempcx[8] |= VRS[8] */
- Tempcx |= (Tempbx & 0x80) << 2; /* Tempcx[9] |= VRS[9] */
-
- /* CR11 VRE */
- Tempax = pVBInfo->StandTable[StandTableIndex].CRTC[17];
- Tempax &= 0x0F; /* Tempax: VRE[3:0] */
- Tempbx = Tempcx; /* Tempbx=Tempcx=VRS[9:0] */
- Tempbx &= 0x3F0; /* Tempbx[9:4]: VRS[9:4] */
- Tempbx |= Tempax; /* Tempbx[9:0]: VRE[9:0] */
- if (Tempax <= (Tempcx & 0x0F)) /* VRE[3:0]<=VRS[3:0] */
- Tempbx |= 0x10; /* Tempbx: VRE + 0x10 */
- /* Tempax[7:0]: VRE[7:0] */
- Tempax = (unsigned char) Tempbx & 0xFF;
- Tempax <<= 2; /* Tempax << 2: VRE[5:0] */
- Tempcx = (Tempcx & 0x600) >> 8; /* Tempcx VRS[10:9] */
- /* SR3F D[7:2]->VRE D[5:0] */
- xgifb_reg_and_or(pVBInfo->P3c4, 0x3F, ~0xFC, Tempax);
- /* SR35 D[2:1]->VRS[10:9] */
- xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x06, Tempcx);
- } else {
- index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
- /* Tempax: CR4 HRS */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3];
- Tempbx = Tempax; /* Tempbx: HRS[7:0] */
- /* SR2E[7:0]->HRS */
- xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax);
-
- /* SR0B */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[5];
- Tempax &= 0xC0; /* Tempax[7:6]: SR0B[7:6]: HRS[9:8]*/
- Tempbx |= (Tempax << 2); /* Tempbx: HRS[9:0] */
-
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[4]; /* CR5 HRE */
- Tempax &= 0x1F; /* Tempax[4:0]: HRE[4:0] */
- Tempcx = Tempax; /* Tempcx: HRE[4:0] */
-
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[6]; /* SRC */
- Tempax &= 0x04; /* Tempax[2]: HRE[5] */
- Tempax <<= 3; /* Tempax[5]: HRE[5] */
- Tempcx |= Tempax; /* Tempcx[5:0]: HRE[5:0] */
-
- Tempbx = Tempbx & 0x3C0; /* Tempbx[9:6]: HRS[9:6] */
- Tempbx |= Tempcx; /* Tempbx: HRS[9:6]HRE[5:0] */
-
- /* Tempax: CR4 HRS */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3];
- Tempax &= 0x3F; /* Tempax: HRS[5:0] */
- if (Tempcx <= Tempax) /* HRE[5:0] < HRS[5:0] */
- Tempbx += 0x40; /* Tempbx= Tempbx + 0x40 : HRE[9:0]*/
-
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[5]; /* SR0B */
- Tempax &= 0xC0; /* Tempax[7:6]: SR0B[7:6]: HRS[9:8]*/
- Tempax >>= 6; /* Tempax[1:0]: HRS[9:8]*/
- Tempax |= ((Tempbx << 2) & 0xFF); /* Tempax[7:2]: HRE[5:0] */
- /* SR2F [7:2][1:0]: HRE[5:0]HRS[9:8] */
- xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempax);
- xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00);
-
- /* CR10 VRS */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[10];
- /* SR34[7:0]->VRS[7:0] */
- xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempax);
-
- Tempcx = Tempax; /* Tempcx <= VRS[7:0] */
- /* CR7[7][2] VRS[9][8] */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[9];
- Tempbx = Tempax; /* Tempbx <= CR07[7:0] */
- Tempax = Tempax & 0x04; /* Tempax[2]: CR7[2]: VRS[8] */
- Tempax >>= 2; /* Tempax[0]: VRS[8] */
- /* SR35[0]: VRS[8] */
- xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x01, Tempax);
- Tempcx |= (Tempax << 8); /* Tempcx <= VRS[8:0] */
- Tempcx |= ((Tempbx & 0x80) << 2); /* Tempcx <= VRS[9:0] */
- /* Tempax: SR0A */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
- Tempax &= 0x08; /* SR0A[3] VRS[10] */
- Tempcx |= (Tempax << 7); /* Tempcx <= VRS[10:0] */
-
- /* Tempax: CR11 VRE */
- Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[11];
- Tempax &= 0x0F; /* Tempax[3:0]: VRE[3:0] */
- /* Tempbx: SR0A */
- Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
- Tempbx &= 0x20; /* Tempbx[5]: SR0A[5]: VRE[4] */
- Tempbx >>= 1; /* Tempbx[4]: VRE[4] */
- Tempax |= Tempbx; /* Tempax[4:0]: VRE[4:0] */
- Tempbx = Tempcx; /* Tempbx: VRS[10:0] */
- Tempbx &= 0x7E0; /* Tempbx[10:5]: VRS[10:5] */
- Tempbx |= Tempax; /* Tempbx: VRS[10:5]VRE[4:0] */
-
- if (Tempbx <= Tempcx) /* VRE <= VRS */
- Tempbx |= 0x20; /* VRE + 0x20 */
-
- /* Tempax: Tempax[7:0]; VRE[5:0]00 */
- Tempax = (Tempbx << 2) & 0xFF;
- /* SR3F[7:2]:VRE[5:0] */
- xgifb_reg_and_or(pVBInfo->P3c4, 0x3F, ~0xFC, Tempax);
- Tempax = Tempcx >> 8;
- /* SR35[2:0]:VRS[10:8] */
- xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x07, Tempax);
- }
+ unsigned short index, Tempax, Tempbx, Tempcx;
+
+ index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+ /* Tempax: CR4 HRS */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3];
+ Tempbx = Tempax; /* Tempbx: HRS[7:0] */
+ /* SR2E[7:0]->HRS */
+ xgifb_reg_set(pVBInfo->P3c4, 0x2E, Tempax);
+
+ /* SR0B */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[5];
+ Tempax &= 0xC0; /* Tempax[7:6]: SR0B[7:6]: HRS[9:8]*/
+ Tempbx |= (Tempax << 2); /* Tempbx: HRS[9:0] */
+
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[4]; /* CR5 HRE */
+ Tempax &= 0x1F; /* Tempax[4:0]: HRE[4:0] */
+ Tempcx = Tempax; /* Tempcx: HRE[4:0] */
+
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[6]; /* SRC */
+ Tempax &= 0x04; /* Tempax[2]: HRE[5] */
+ Tempax <<= 3; /* Tempax[5]: HRE[5] */
+ Tempcx |= Tempax; /* Tempcx[5:0]: HRE[5:0] */
+
+ Tempbx = Tempbx & 0x3C0; /* Tempbx[9:6]: HRS[9:6] */
+ Tempbx |= Tempcx; /* Tempbx: HRS[9:6]HRE[5:0] */
+
+ /* Tempax: CR4 HRS */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[3];
+ Tempax &= 0x3F; /* Tempax: HRS[5:0] */
+ if (Tempcx <= Tempax) /* HRE[5:0] < HRS[5:0] */
+ Tempbx += 0x40; /* Tempbx= Tempbx + 0x40 : HRE[9:0]*/
+
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[5]; /* SR0B */
+ Tempax &= 0xC0; /* Tempax[7:6]: SR0B[7:6]: HRS[9:8]*/
+ Tempax >>= 6; /* Tempax[1:0]: HRS[9:8]*/
+ Tempax |= ((Tempbx << 2) & 0xFF); /* Tempax[7:2]: HRE[5:0] */
+ /* SR2F [7:2][1:0]: HRE[5:0]HRS[9:8] */
+ xgifb_reg_set(pVBInfo->P3c4, 0x2F, Tempax);
+ xgifb_reg_and_or(pVBInfo->P3c4, 0x30, 0xE3, 00);
+
+ /* CR10 VRS */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[10];
+ /* SR34[7:0]->VRS[7:0] */
+ xgifb_reg_set(pVBInfo->P3c4, 0x34, Tempax);
+
+ Tempcx = Tempax; /* Tempcx <= VRS[7:0] */
+ /* CR7[7][2] VRS[9][8] */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[9];
+ Tempbx = Tempax; /* Tempbx <= CR07[7:0] */
+ Tempax = Tempax & 0x04; /* Tempax[2]: CR7[2]: VRS[8] */
+ Tempax >>= 2; /* Tempax[0]: VRS[8] */
+ /* SR35[0]: VRS[8] */
+ xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x01, Tempax);
+ Tempcx |= (Tempax << 8); /* Tempcx <= VRS[8:0] */
+ Tempcx |= ((Tempbx & 0x80) << 2); /* Tempcx <= VRS[9:0] */
+ /* Tempax: SR0A */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
+ Tempax &= 0x08; /* SR0A[3] VRS[10] */
+ Tempcx |= (Tempax << 7); /* Tempcx <= VRS[10:0] */
+
+ /* Tempax: CR11 VRE */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[index].CR[11];
+ Tempax &= 0x0F; /* Tempax[3:0]: VRE[3:0] */
+ /* Tempbx: SR0A */
+ Tempbx = pVBInfo->XGINEWUB_CRT1Table[index].CR[14];
+ Tempbx &= 0x20; /* Tempbx[5]: SR0A[5]: VRE[4] */
+ Tempbx >>= 1; /* Tempbx[4]: VRE[4] */
+ Tempax |= Tempbx; /* Tempax[4:0]: VRE[4:0] */
+ Tempbx = Tempcx; /* Tempbx: VRS[10:0] */
+ Tempbx &= 0x7E0; /* Tempbx[10:5]: VRS[10:5] */
+ Tempbx |= Tempax; /* Tempbx: VRS[10:5]VRE[4:0] */
+
+ if (Tempbx <= Tempcx) /* VRE <= VRS */
+ Tempbx |= 0x20; /* VRE + 0x20 */
+
+ /* Tempax: Tempax[7:0]; VRE[5:0]00 */
+ Tempax = (Tempbx << 2) & 0xFF;
+ /* SR3F[7:2]:VRE[5:0] */
+ xgifb_reg_and_or(pVBInfo->P3c4, 0x3F, ~0xFC, Tempax);
+ Tempax = Tempcx >> 8;
+ /* SR35[2:0]:VRS[10:8] */
+ xgifb_reg_and_or(pVBInfo->P3c4, 0x35, ~0x07, Tempax);
}
static void XGI_SetXG27FPBits(struct vb_device_info *pVBInfo)
@@ -954,7 +775,7 @@ static void xgifb_set_lcd(int chip_id,
unsigned short RefreshRateTableIndex,
unsigned short ModeNo)
{
- unsigned short Data, Temp, b3CC;
+ unsigned short Data, Temp;
unsigned short XGI_P3cc;
XGI_P3cc = pVBInfo->P3cc;
@@ -995,23 +816,13 @@ static void xgifb_set_lcd(int chip_id,
xgifb_reg_and(pVBInfo->P3c4, 0x30, ~0x20); /* Hsync polarity */
xgifb_reg_and(pVBInfo->P3c4, 0x35, ~0x80); /* Vsync polarity */
- if (ModeNo <= 0x13) {
- b3CC = (unsigned char) inb(XGI_P3cc);
- if (b3CC & 0x40)
- /* Hsync polarity */
- xgifb_reg_or(pVBInfo->P3c4, 0x30, 0x20);
- if (b3CC & 0x80)
- /* Vsync polarity */
- xgifb_reg_or(pVBInfo->P3c4, 0x35, 0x80);
- } else {
- Data = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
- if (Data & 0x4000)
- /* Hsync polarity */
- xgifb_reg_or(pVBInfo->P3c4, 0x30, 0x20);
- if (Data & 0x8000)
- /* Vsync polarity */
- xgifb_reg_or(pVBInfo->P3c4, 0x35, 0x80);
- }
+ Data = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+ if (Data & 0x4000)
+ /* Hsync polarity */
+ xgifb_reg_or(pVBInfo->P3c4, 0x30, 0x20);
+ if (Data & 0x8000)
+ /* Vsync polarity */
+ xgifb_reg_or(pVBInfo->P3c4, 0x35, 0x80);
}
/* --------------------------------------------------------------------- */
@@ -1024,30 +835,22 @@ static void XGI_UpdateXG21CRTC(unsigned short ModeNo,
struct vb_device_info *pVBInfo,
unsigned short RefreshRateTableIndex)
{
- int i, index = -1;
+ int index = -1;
xgifb_reg_and(pVBInfo->P3d4, 0x11, 0x7F); /* Unlock CR0~7 */
- if (ModeNo <= 0x13) {
- for (i = 0; i < 12; i++) {
- if (ModeNo == pVBInfo->UpdateCRT1[i].ModeID)
- index = i;
- }
- } else {
- if (ModeNo == 0x2E &&
- (pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC ==
- RES640x480x60))
- index = 12;
- else if (ModeNo == 0x2E &&
- (pVBInfo->RefIndex[RefreshRateTableIndex].
+ if (ModeNo == 0x2E &&
+ (pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC ==
+ RES640x480x60))
+ index = 12;
+ else if (ModeNo == 0x2E && (pVBInfo->RefIndex[RefreshRateTableIndex].
Ext_CRT1CRTC == RES640x480x72))
- index = 13;
- else if (ModeNo == 0x2F)
- index = 14;
- else if (ModeNo == 0x50)
- index = 15;
- else if (ModeNo == 0x59)
- index = 16;
- }
+ index = 13;
+ else if (ModeNo == 0x2F)
+ index = 14;
+ else if (ModeNo == 0x50)
+ index = 15;
+ else if (ModeNo == 0x59)
+ index = 16;
if (index != -1) {
xgifb_reg_set(pVBInfo->P3d4, 0x02,
@@ -1061,20 +864,6 @@ static void XGI_UpdateXG21CRTC(unsigned short ModeNo,
}
}
-static unsigned short XGI_GetResInfo(unsigned short ModeNo,
- unsigned short ModeIdIndex, struct vb_device_info *pVBInfo)
-{
- unsigned short resindex;
-
- if (ModeNo <= 0x13)
- /* si+St_ResInfo */
- resindex = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
- else
- /* si+Ext_ResInfo */
- resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- return resindex;
-}
-
static void XGI_SetCRT1DE(struct xgi_hw_device_info *HwDeviceExtension,
unsigned short ModeNo, unsigned short ModeIdIndex,
unsigned short RefreshRateTableIndex,
@@ -1084,33 +873,25 @@ static void XGI_SetCRT1DE(struct xgi_hw_device_info *HwDeviceExtension,
unsigned char data;
- resindex = XGI_GetResInfo(ModeNo, ModeIdIndex, pVBInfo);
+ resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- if (ModeNo <= 0x13) {
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- tempax = pVBInfo->StResInfo[resindex].HTotal;
- tempbx = pVBInfo->StResInfo[resindex].VTotal;
- } else {
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- tempax = pVBInfo->ModeResInfo[resindex].HTotal;
- tempbx = pVBInfo->ModeResInfo[resindex].VTotal;
- }
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ tempax = pVBInfo->ModeResInfo[resindex].HTotal;
+ tempbx = pVBInfo->ModeResInfo[resindex].VTotal;
if (modeflag & HalfDCLK)
tempax = tempax >> 1;
- if (ModeNo > 0x13) {
- if (modeflag & HalfDCLK)
- tempax = tempax << 1;
+ if (modeflag & HalfDCLK)
+ tempax = tempax << 1;
- temp = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+ temp = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
- if (temp & InterlaceMode)
- tempbx = tempbx >> 1;
+ if (temp & InterlaceMode)
+ tempbx = tempbx >> 1;
- if (modeflag & DoubleScanMode)
- tempbx = tempbx << 1;
- }
+ if (modeflag & DoubleScanMode)
+ tempbx = tempbx << 1;
tempcx = 8;
@@ -1258,18 +1039,10 @@ static unsigned short XGI_GetVCLK2Ptr(unsigned short ModeNo,
unsigned short CRT2Index, VCLKIndex;
unsigned short modeflag, resinfo;
- if (ModeNo <= 0x13) {
- /* si+St_ResInfo */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- resinfo = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
- CRT2Index = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC;
- } else {
- /* si+Ext_ResInfo */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- CRT2Index = pVBInfo->RefIndex[RefreshRateTableIndex].
- Ext_CRT2CRTC;
- }
+ /* si+Ext_ResInfo */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+ CRT2Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
if (pVBInfo->IF_DEF_LVDS == 0) {
CRT2Index = CRT2Index >> 6; /* for LCD */
@@ -1318,23 +1091,13 @@ static unsigned short XGI_GetVCLK2Ptr(unsigned short ModeNo,
VCLKIndex += 25;
}
} else { /* for CRT2 */
- /* Port 3cch */
- VCLKIndex = (unsigned char) inb((pVBInfo->P3ca + 0x02));
- VCLKIndex = ((VCLKIndex >> 2) & 0x03);
- if (ModeNo > 0x13) {
- /* di+Ext_CRTVCLK */
- VCLKIndex = pVBInfo->RefIndex[
- RefreshRateTableIndex].
+ /* di+Ext_CRTVCLK */
+ VCLKIndex = pVBInfo->RefIndex[RefreshRateTableIndex].
Ext_CRTVCLK;
- VCLKIndex &= IndexMask;
- }
+ VCLKIndex &= IndexMask;
}
} else { /* LVDS */
- if (ModeNo <= 0x13)
- VCLKIndex = CRT2Index;
- else
- VCLKIndex = CRT2Index;
-
+ VCLKIndex = CRT2Index;
VCLKIndex = VCLKIndex >> 6;
if ((pVBInfo->LCDResInfo == Panel_800x600) ||
(pVBInfo->LCDResInfo == Panel_320x480))
@@ -1431,27 +1194,13 @@ static void XGI_SetCRT1FIFO(unsigned short ModeNo,
data &= 0xfe;
xgifb_reg_set(pVBInfo->P3c4, 0x3D, data); /* diable auto-threshold */
- if (ModeNo > 0x13) {
- xgifb_reg_set(pVBInfo->P3c4, 0x08, 0x34);
- data = xgifb_reg_get(pVBInfo->P3c4, 0x09);
- data &= 0xC0;
- xgifb_reg_set(pVBInfo->P3c4, 0x09, data | 0x30);
- data = xgifb_reg_get(pVBInfo->P3c4, 0x3D);
- data |= 0x01;
- xgifb_reg_set(pVBInfo->P3c4, 0x3D, data);
- } else {
- if (HwDeviceExtension->jChipType == XG27) {
- xgifb_reg_set(pVBInfo->P3c4, 0x08, 0x0E);
- data = xgifb_reg_get(pVBInfo->P3c4, 0x09);
- data &= 0xC0;
- xgifb_reg_set(pVBInfo->P3c4, 0x09, data | 0x20);
- } else {
- xgifb_reg_set(pVBInfo->P3c4, 0x08, 0xAE);
- data = xgifb_reg_get(pVBInfo->P3c4, 0x09);
- data &= 0xF0;
- xgifb_reg_set(pVBInfo->P3c4, 0x09, data);
- }
- }
+ xgifb_reg_set(pVBInfo->P3c4, 0x08, 0x34);
+ data = xgifb_reg_get(pVBInfo->P3c4, 0x09);
+ data &= 0xC0;
+ xgifb_reg_set(pVBInfo->P3c4, 0x09, data | 0x30);
+ data = xgifb_reg_get(pVBInfo->P3c4, 0x3D);
+ data |= 0x01;
+ xgifb_reg_set(pVBInfo->P3c4, 0x3D, data);
if (HwDeviceExtension->jChipType == XG21)
XGI_SetXG21FPBits(pVBInfo); /* Fix SR9[7:6] can't read back */
@@ -1466,13 +1215,9 @@ static void XGI_SetVCLKState(struct xgi_hw_device_info *HwDeviceExtension,
unsigned char index;
- if (ModeNo <= 0x13)
- VCLK = 0;
- else {
- index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
- index &= IndexMask;
- VCLK = pVBInfo->VCLKData[index].CLOCK;
- }
+ index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+ index &= IndexMask;
+ VCLK = pVBInfo->VCLKData[index].CLOCK;
data = xgifb_reg_get(pVBInfo->P3c4, 0x32);
data &= 0xf3;
@@ -1508,44 +1253,26 @@ static void XGI_SetCRT1ModeRegs(struct xgi_hw_device_info *HwDeviceExtension,
unsigned short data, data2, data3, infoflag = 0, modeflag, resindex,
xres;
- if (ModeNo > 0x13) {
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- infoflag = pVBInfo->RefIndex[RefreshRateTableIndex].
- Ext_InfoFlag;
- } else
- /* si+St_ModeFlag */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ infoflag = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
if (xgifb_reg_get(pVBInfo->P3d4, 0x31) & 0x01)
xgifb_reg_and_or(pVBInfo->P3c4, 0x1F, 0x3F, 0x00);
- if (ModeNo > 0x13)
- data = infoflag;
- else
- data = 0;
-
+ data = infoflag;
data2 = 0;
-
- if (ModeNo > 0x13) {
- if (pVBInfo->ModeType > 0x02) {
- data2 |= 0x02;
- data3 = pVBInfo->ModeType - ModeVGA;
- data3 = data3 << 2;
- data2 |= data3;
- }
- }
-
+ data2 |= 0x02;
+ data3 = pVBInfo->ModeType - ModeVGA;
+ data3 = data3 << 2;
+ data2 |= data3;
data &= InterlaceMode;
if (data)
data2 |= 0x20;
xgifb_reg_and_or(pVBInfo->P3c4, 0x06, ~0x3F, data2);
- resindex = XGI_GetResInfo(ModeNo, ModeIdIndex, pVBInfo);
- if (ModeNo <= 0x13)
- xres = pVBInfo->StResInfo[resindex].HTotal;
- else
- xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
+ resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+ xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
data = 0x0000;
if (infoflag & InterlaceMode) {
@@ -1568,18 +1295,10 @@ static void XGI_SetCRT1ModeRegs(struct xgi_hw_device_info *HwDeviceExtension,
if (modeflag & LineCompareOff)
data2 |= 0x08;
- if (ModeNo > 0x13) {
- if (pVBInfo->ModeType == ModeEGA)
- data2 |= 0x40;
- }
-
xgifb_reg_and_or(pVBInfo->P3c4, 0x0F, ~0x48, data2);
data = 0x60;
- if (pVBInfo->ModeType != ModeText) {
- data = data ^ 0x60;
- if (pVBInfo->ModeType != ModeEGA)
- data = data ^ 0xA0;
- }
+ data = data ^ 0x60;
+ data = data ^ 0xA0;
xgifb_reg_and_or(pVBInfo->P3c4, 0x21, 0x1F, data);
XGI_SetVCLKState(HwDeviceExtension, ModeNo, RefreshRateTableIndex,
@@ -1644,38 +1363,13 @@ static void XGI_WriteDAC(unsigned short dl,
static void XGI_LoadDAC(unsigned short ModeNo, unsigned short ModeIdIndex,
struct vb_device_info *pVBInfo)
{
- unsigned short data, data2, time, i, j, k, m, n, o, si, di, bx, dl, al,
- ah, dh;
- const unsigned short *table = NULL;
-
- if (ModeNo <= 0x13)
- data = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- data = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-
- data &= DACInfoFlag;
- time = 64;
-
- if (data == 0x00)
- table = XGINew_MDA_DAC;
- else if (data == 0x08)
- table = XGINew_CGA_DAC;
- else if (data == 0x10)
- table = XGINew_EGA_DAC;
- else if (data == 0x18) {
- time = 256;
- table = XGINew_VGA_DAC;
- }
-
- if (time == 256)
- j = 16;
- else
- j = time;
+ unsigned short data, data2, i, k, m, n, o, si, di, bx, dl, al, ah, dh;
+ const unsigned short *table = XGINew_VGA_DAC;
outb(0xFF, pVBInfo->P3c6);
outb(0x00, pVBInfo->P3c8);
- for (i = 0; i < j; i++) {
+ for (i = 0; i < 16; i++) {
data = table[i];
for (k = 0; k < 3; k++) {
@@ -1692,45 +1386,43 @@ static void XGI_LoadDAC(unsigned short ModeNo, unsigned short ModeIdIndex,
}
}
- if (time == 256) {
- for (i = 16; i < 32; i++) {
- data = table[i];
-
- for (k = 0; k < 3; k++)
- outb(data, pVBInfo->P3c9);
- }
+ for (i = 16; i < 32; i++) {
+ data = table[i];
- si = 32;
+ for (k = 0; k < 3; k++)
+ outb(data, pVBInfo->P3c9);
+ }
- for (m = 0; m < 9; m++) {
- di = si;
- bx = si + 0x04;
- dl = 0;
+ si = 32;
- for (n = 0; n < 3; n++) {
- for (o = 0; o < 5; o++) {
- dh = table[si];
- ah = table[di];
- al = table[bx];
- si++;
- XGI_WriteDAC(dl, ah, al, dh, pVBInfo);
- }
+ for (m = 0; m < 9; m++) {
+ di = si;
+ bx = si + 0x04;
+ dl = 0;
- si -= 2;
+ for (n = 0; n < 3; n++) {
+ for (o = 0; o < 5; o++) {
+ dh = table[si];
+ ah = table[di];
+ al = table[bx];
+ si++;
+ XGI_WriteDAC(dl, ah, al, dh, pVBInfo);
+ }
- for (o = 0; o < 3; o++) {
- dh = table[bx];
- ah = table[di];
- al = table[si];
- si--;
- XGI_WriteDAC(dl, ah, al, dh, pVBInfo);
- }
+ si -= 2;
- dl++;
+ for (o = 0; o < 3; o++) {
+ dh = table[bx];
+ ah = table[di];
+ al = table[si];
+ si--;
+ XGI_WriteDAC(dl, ah, al, dh, pVBInfo);
}
- si += 5;
+ dl++;
}
+
+ si += 5;
}
}
@@ -1740,34 +1432,20 @@ static void XGI_GetLVDSResInfo(unsigned short ModeNo,
{
unsigned short resindex, xres, yres, modeflag;
- if (ModeNo <= 0x13)
- /* si+St_ResInfo */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
- else
- /* si+Ext_ResInfo */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+ /* si+Ext_ResInfo */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- if (ModeNo <= 0x13)
- /* si+St_ResInfo */
- resindex = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
- else
- /* si+Ext_ResInfo */
- resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+ /* si+Ext_ResInfo */
+ resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- if (ModeNo <= 0x13) {
- xres = pVBInfo->StResInfo[resindex].HTotal;
- yres = pVBInfo->StResInfo[resindex].VTotal;
- } else {
- xres = pVBInfo->ModeResInfo[resindex].HTotal;
- yres = pVBInfo->ModeResInfo[resindex].VTotal;
- }
- if (ModeNo > 0x13) {
- if (modeflag & HalfDCLK)
- xres = xres << 1;
+ xres = pVBInfo->ModeResInfo[resindex].HTotal;
+ yres = pVBInfo->ModeResInfo[resindex].VTotal;
- if (modeflag & DoubleScanMode)
- yres = yres << 1;
- }
+ if (modeflag & HalfDCLK)
+ xres = xres << 1;
+
+ if (modeflag & DoubleScanMode)
+ yres = yres << 1;
if (xres == 720)
xres = 640;
@@ -1789,32 +1467,16 @@ static void *XGI_GetLcdPtr(unsigned short BX, unsigned short ModeNo,
tempbx = BX;
- if (ModeNo <= 0x13) {
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- tempal = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC;
- } else {
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
- }
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
tempal = tempal & 0x0f;
if (tempbx <= 1) { /* ExpLink */
- if (ModeNo <= 0x13) {
- /* find no Ext_CRT2CRTC2 */
- tempal = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC;
- } else {
- tempal = pVBInfo->RefIndex[RefreshRateTableIndex].
- Ext_CRT2CRTC;
- }
+ tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) {
- if (ModeNo <= 0x13)
- tempal = pVBInfo->SModeIDTable[ModeIdIndex].
- St_CRT2CRTC2;
- else
- tempal = pVBInfo->RefIndex[
- RefreshRateTableIndex].
+ tempal = pVBInfo->RefIndex[RefreshRateTableIndex].
Ext_CRT2CRTC2;
}
@@ -1882,9 +1544,6 @@ static void *XGI_GetLcdPtr(unsigned short BX, unsigned short ModeNo,
tempbx = tempdi[i].MASK;
tempdx = pVBInfo->LCDInfo;
- if (ModeNo <= 0x13) /* alan 09/10/2003 */
- tempdx |= SetLCDStdMode;
-
if (modeflag & HalfDCLK)
tempdx |= SetLCDLowResolution;
@@ -2238,15 +1897,8 @@ static void *XGI_GetTVPtr(unsigned short BX, unsigned short ModeNo,
struct XGI330_TVDataTablStruct *tempdi = NULL;
tempbx = BX;
-
- if (ModeNo <= 0x13) {
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- tempal = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC;
- } else {
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
- }
-
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
tempal = tempal & 0x3f;
table = tempbx;
@@ -2413,11 +2065,7 @@ static void XGI_ModCRT1Regs(unsigned short ModeNo, unsigned short ModeIdIndex,
struct XGI_LVDSCRT1HDataStruct *LCDPtr = NULL;
struct XGI_LVDSCRT1VDataStruct *LCDPtr1 = NULL;
- if (ModeNo <= 0x13)
- index = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC;
- else
- index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
-
+ index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
index = index & IndexMask;
tempbx = 0;
@@ -2530,14 +2178,10 @@ static void XGI_SetLVDSRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
{
unsigned short tempbx, tempax, tempcx, tempdx, push1, push2, modeflag;
unsigned long temp, temp1, temp2, temp3, push3;
- struct XGI330_LCDDataDesStruct *LCDPtr = NULL;
+ struct XGI_LCDDesStruct *LCDPtr = NULL;
struct XGI330_LCDDataDesStruct2 *LCDPtr1 = NULL;
- if (ModeNo > 0x13)
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- else
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
-
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
tempbx = 3;
if (pVBInfo->LCDInfo & EnableScalingLCD)
LCDPtr1 =
@@ -2550,7 +2194,7 @@ static void XGI_SetLVDSRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
pVBInfo);
else
LCDPtr =
- (struct XGI330_LCDDataDesStruct *)
+ (struct XGI_LCDDesStruct *)
XGI_GetLcdPtr(
tempbx,
ModeNo,
@@ -2829,12 +2473,8 @@ static unsigned char XGI_GetVCLKPtr(unsigned short RefreshRateTableIndex,
unsigned short index, modeflag;
unsigned char tempal;
- if (ModeNo <= 0x13)
- /* si+St_ResInfo */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- /* si+Ext_ResInfo */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ /* si+Ext_ResInfo */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
if ((pVBInfo->SetFlag & ProgrammingCRT2) &&
(!(pVBInfo->LCDInfo & EnableScalingLCD))) { /* {LCDA/LCDB} */
@@ -2895,9 +2535,6 @@ static unsigned char XGI_GetVCLKPtr(unsigned short RefreshRateTableIndex,
if ((pVBInfo->LCDInfo & EnableScalingLCD) && (modeflag & Charx8Dot))
tempal = tempal ^ tempal; /* ; set to VCLK25MHz always */
- if (ModeNo <= 0x13)
- return tempal;
-
tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
return tempal;
}
@@ -3079,11 +2716,7 @@ static void XGI_GetVBInfo(unsigned short ModeNo, unsigned short ModeIdIndex,
{
unsigned short tempax, push, tempbx, temp, modeflag;
- if (ModeNo <= 0x13)
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
pVBInfo->SetFlag = 0;
pVBInfo->ModeType = modeflag & ModeTypeMask;
tempbx = 0;
@@ -3283,17 +2916,8 @@ static void XGI_GetTVInfo(unsigned short ModeNo, unsigned short ModeIdIndex,
resinfo = 0;
if (pVBInfo->VBInfo & SetCRT2ToTV) {
- if (ModeNo <= 0x13) {
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].
- St_ModeFlag; /* si+St_ModeFlag */
- resinfo = pVBInfo->SModeIDTable[ModeIdIndex].
- St_ResInfo; /* si+St_ResInfo */
- } else {
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].
- Ext_ModeFlag;
- resinfo = pVBInfo->EModeIDTable[ModeIdIndex].
- Ext_RESINFO; /* si+Ext_ResInfo */
- }
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
if (pVBInfo->VBInfo & SetCRT2ToTV) {
temp = xgifb_reg_get(pVBInfo->P3d4, 0x35);
@@ -3380,15 +3004,9 @@ static unsigned char XGI_GetLCDInfo(unsigned short ModeNo,
pVBInfo->LCDTypeInfo = 0;
pVBInfo->LCDInfo = 0;
- if (ModeNo <= 0x13) {
- /* si+St_ModeFlag // */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- } else {
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- /* si+Ext_ResInfo // */
- resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- }
-
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ /* si+Ext_ResInfo // */
+ resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
temp = xgifb_reg_get(pVBInfo->P3d4, 0x36); /* Get LCD Res.Info */
tempbx = temp & 0x0F;
@@ -3442,8 +3060,8 @@ static unsigned char XGI_GetLCDInfo(unsigned short ModeNo,
if (pVBInfo->IF_DEF_LVDS == 0) {
if ((pVBInfo->LCDResInfo == Panel_1400x1050) && (pVBInfo->VBInfo
- & SetCRT2ToLCD) && (ModeNo > 0x13) && (resinfo
- == 9) && (!(tempbx & EnableScalingLCD)))
+ & SetCRT2ToLCD) && (resinfo == 9) &&
+ (!(tempbx & EnableScalingLCD)))
/* set to center in 1280x1024 LCDB for Panel_1400x1050 */
tempbx |= SetLCDtoNonExpanding;
}
@@ -3453,12 +3071,9 @@ static unsigned char XGI_GetLCDInfo(unsigned short ModeNo,
if (!(tempbx & SetLCDtoNonExpanding)) {
tempbx |= XGI_EnableLVDSDDA;
} else {
- if (ModeNo > 0x13) {
- if (pVBInfo->LCDResInfo
- == Panel_1024x768) {
- if (resinfo == 4) {/* 512x384 */
- tempbx |= XGI_EnableLVDSDDA;
- }
+ if (pVBInfo->LCDResInfo == Panel_1024x768) {
+ if (resinfo == 4) {/* 512x384 */
+ tempbx |= XGI_EnableLVDSDDA;
}
}
}
@@ -3474,56 +3089,17 @@ static unsigned char XGI_GetLCDInfo(unsigned short ModeNo,
pVBInfo->LCDInfo = tempbx;
- if (pVBInfo->IF_DEF_LVDS == 0) {
- if (tempax & (LockLCDBToA | StLCDBToA)) {
- if (pVBInfo->VBInfo & SetInSlaveMode) {
- if (!(tempax & LockLCDBToA)) {
- if (ModeNo <= 0x13) {
- pVBInfo->VBInfo &=
- ~(SetSimuScanMode |
- SetInSlaveMode |
- SetCRT2ToLCD);
- pVBInfo->VBInfo |=
- XGI_SetCRT2ToLCDA |
- SetCRT2ToDualEdge;
- }
- }
- }
- }
- }
-
return 1;
}
unsigned char XGI_SearchModeID(unsigned short ModeNo,
unsigned short *ModeIdIndex, struct vb_device_info *pVBInfo)
{
- if (ModeNo <= 5)
- ModeNo |= 1;
- if (ModeNo <= 0x13) {
- for (*ModeIdIndex = 0;; (*ModeIdIndex)++) {
- if (pVBInfo->SModeIDTable[*ModeIdIndex].St_ModeID ==
- ModeNo)
- break;
- if (pVBInfo->SModeIDTable[*ModeIdIndex].St_ModeID ==
- 0xFF)
- return 0;
- }
-
- if (ModeNo == 0x07)
- (*ModeIdIndex)++; /* 400 lines */
- if (ModeNo <= 3)
- (*ModeIdIndex) += 2; /* 400 lines */
- /* else 350 lines */
- } else {
- for (*ModeIdIndex = 0;; (*ModeIdIndex)++) {
- if (pVBInfo->EModeIDTable[*ModeIdIndex].Ext_ModeID ==
- ModeNo)
- break;
- if (pVBInfo->EModeIDTable[*ModeIdIndex].Ext_ModeID ==
- 0xFF)
- return 0;
- }
+ for (*ModeIdIndex = 0;; (*ModeIdIndex)++) {
+ if (pVBInfo->EModeIDTable[*ModeIdIndex].Ext_ModeID == ModeNo)
+ break;
+ if (pVBInfo->EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF)
+ return 0;
}
return 1;
@@ -3789,22 +3365,17 @@ static void XGI_GetCRT2ResInfo(unsigned short ModeNo,
{
unsigned short xres, yres, modeflag, resindex;
- resindex = XGI_GetResInfo(ModeNo, ModeIdIndex, pVBInfo);
- if (ModeNo <= 0x13) {
- xres = pVBInfo->StResInfo[resindex].HTotal;
- yres = pVBInfo->StResInfo[resindex].VTotal;
- } else {
- xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
- yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */
- /* si+St_ModeFlag */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+ xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
+ yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */
+ /* si+St_ModeFlag */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- if (modeflag & HalfDCLK)
- xres *= 2;
+ if (modeflag & HalfDCLK)
+ xres *= 2;
- if (modeflag & DoubleScanMode)
- yres *= 2;
- }
+ if (modeflag & DoubleScanMode)
+ yres *= 2;
if (pVBInfo->VBInfo & SetCRT2ToLCD) {
if (pVBInfo->IF_DEF_LVDS == 0) {
@@ -3868,37 +3439,23 @@ static void XGI_GetRAMDAC2DATA(unsigned short ModeNo,
struct vb_device_info *pVBInfo)
{
unsigned short tempax, tempbx, temp1, temp2, modeflag = 0, tempcx,
- StandTableIndex, CRT1Index;
+ CRT1Index;
pVBInfo->RVBHCMAX = 1;
pVBInfo->RVBHCFACT = 1;
-
- if (ModeNo <= 0x13) {
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- StandTableIndex = XGI_GetModePtr(ModeNo, ModeIdIndex, pVBInfo);
- tempax = pVBInfo->StandTable[StandTableIndex].CRTC[0];
- tempbx = pVBInfo->StandTable[StandTableIndex].CRTC[6];
- temp1 = pVBInfo->StandTable[StandTableIndex].CRTC[7];
- } else {
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].
- Ext_CRT1CRTC;
- CRT1Index &= IndexMask;
- temp1 = (unsigned short) pVBInfo->
- XGINEWUB_CRT1Table[CRT1Index].CR[0];
- temp2 = (unsigned short) pVBInfo->
- XGINEWUB_CRT1Table[CRT1Index].CR[5];
- tempax = (temp1 & 0xFF) | ((temp2 & 0x03) << 8);
- tempbx = (unsigned short) pVBInfo->
- XGINEWUB_CRT1Table[CRT1Index].CR[8];
- tempcx = (unsigned short) pVBInfo->
- XGINEWUB_CRT1Table[CRT1Index].CR[14] << 8;
- tempcx &= 0x0100;
- tempcx = tempcx << 2;
- tempbx |= tempcx;
- temp1 = (unsigned short) pVBInfo->
- XGINEWUB_CRT1Table[CRT1Index].CR[9];
- }
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+ CRT1Index &= IndexMask;
+ temp1 = (unsigned short) pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[0];
+ temp2 = (unsigned short) pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[5];
+ tempax = (temp1 & 0xFF) | ((temp2 & 0x03) << 8);
+ tempbx = (unsigned short) pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[8];
+ tempcx = (unsigned short)
+ pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[14] << 8;
+ tempcx &= 0x0100;
+ tempcx = tempcx << 2;
+ tempbx |= tempcx;
+ temp1 = (unsigned short) pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[9];
if (temp1 & 0x01)
tempbx |= 0x0100;
@@ -3928,16 +3485,9 @@ static void XGI_GetCRT2Data(unsigned short ModeNo, unsigned short ModeIdIndex,
struct SiS_LCDData *LCDPtr = NULL;
struct SiS_TVData *TVPtr = NULL;
- if (ModeNo <= 0x13) {
- /* si+St_ResInfo */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- resinfo = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
- } else {
- /* si+Ext_ResInfo */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- }
-
+ /* si+Ext_ResInfo */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
pVBInfo->NewFlickerMode = 0;
pVBInfo->RVBHRS = 50;
@@ -4141,11 +3691,7 @@ static unsigned short XGI_GetColorDepth(unsigned short ModeNo,
short index;
unsigned short modeflag;
- if (ModeNo <= 0x13)
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
index = (modeflag & ModeTypeMask) - ModeEGA;
if (index < 0)
@@ -4164,11 +3710,7 @@ static unsigned short XGI_GetOffset(unsigned short ModeNo,
ColorDepth[] = { 0x01, 0x02, 0x04 };
modeinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeInfo;
- if (ModeNo <= 0x14)
- infoflag = 0;
- else
- infoflag = pVBInfo->
- RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
+ infoflag = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_InfoFlag;
index = (modeinfo >> 8) & 0xFF;
@@ -4228,12 +3770,9 @@ static void XGI_PreSetGroup1(unsigned short ModeNo, unsigned short ModeIdIndex,
{
unsigned short tempcx = 0, CRT1Index = 0, resinfo = 0;
- if (ModeNo > 0x13) {
- CRT1Index = pVBInfo->
- RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
- CRT1Index &= IndexMask;
- resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- }
+ CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+ CRT1Index &= IndexMask;
+ resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
XGI_SetCRT2Offset(ModeNo, ModeIdIndex, RefreshRateTableIndex,
HwDeviceExtension, pVBInfo);
@@ -4254,17 +3793,10 @@ static void XGI_SetGroup1(unsigned short ModeNo, unsigned short ModeIdIndex,
unsigned short temp = 0, tempax = 0, tempbx = 0, tempcx = 0,
pushbx = 0, CRT1Index = 0, modeflag, resinfo = 0;
- if (ModeNo > 0x13) {
- CRT1Index = pVBInfo->
- RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
- CRT1Index &= IndexMask;
- resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- }
-
- if (ModeNo <= 0x13)
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+ CRT1Index &= IndexMask;
+ resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
/* bainy change table name */
if (modeflag & HalfDCLK) {
@@ -4422,18 +3954,11 @@ static void XGI_SetLockRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
unsigned short push1, push2, tempax, tempbx = 0, tempcx, temp, resinfo,
modeflag, CRT1Index;
- if (ModeNo <= 0x13) {
- /* si+St_ResInfo */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- resinfo = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
- } else {
- /* si+Ext_ResInfo */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- CRT1Index = pVBInfo->
- RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
- CRT1Index &= IndexMask;
- }
+ /* si+Ext_ResInfo */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+ CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+ CRT1Index &= IndexMask;
if (!(pVBInfo->VBInfo & SetInSlaveMode))
return;
@@ -4500,8 +4025,7 @@ static void XGI_SetLockRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
temp -= 6;
if (pVBInfo->TVInfo & TVSimuMode) {
temp -= 4;
- if (ModeNo > 0x13)
- temp -= 10;
+ temp -= 10;
}
}
} else {
@@ -4523,14 +4047,6 @@ static void XGI_SetLockRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
if (pVBInfo->LCDResInfo != Panel_1280x960 &&
pVBInfo->VGAHDE >= 800) {
temp -= 7;
- if (pVBInfo->ModeType == ModeEGA &&
- pVBInfo->VGAVDE == 1024) {
- temp += 15;
- if (pVBInfo->LCDResInfo !=
- Panel_1280x1024)
- temp += 7;
- }
-
if (pVBInfo->VGAHDE >= 1280 &&
pVBInfo->LCDResInfo != Panel_1280x960 &&
(pVBInfo->LCDInfo & LCDNonExpanding))
@@ -4546,48 +4062,7 @@ static void XGI_SetLockRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
if (pVBInfo->VBInfo & SetCRT2ToTV) {
if (pVBInfo->TVInfo & TVSimuMode) {
- if ((ModeNo == 0x06) || (ModeNo == 0x10) || (ModeNo
- == 0x11) || (ModeNo == 0x13) || (ModeNo
- == 0x0F)) {
- xgifb_reg_set(pVBInfo->Part1Port, 0x07, 0x5b);
- xgifb_reg_set(pVBInfo->Part1Port, 0x08, 0x03);
- }
-
- if ((ModeNo == 0x00) || (ModeNo == 0x01)) {
- if (pVBInfo->TVInfo & SetNTSCTV) {
- xgifb_reg_set(pVBInfo->Part1Port,
- 0x07, 0x2A);
- xgifb_reg_set(pVBInfo->Part1Port,
- 0x08, 0x61);
- } else {
- xgifb_reg_set(pVBInfo->Part1Port,
- 0x07, 0x2A);
- xgifb_reg_set(pVBInfo->Part1Port,
- 0x08, 0x41);
- xgifb_reg_set(pVBInfo->Part1Port,
- 0x0C, 0xF0);
- }
- }
-
- if ((ModeNo == 0x02) || (ModeNo == 0x03) || (ModeNo
- == 0x07)) {
- if (pVBInfo->TVInfo & SetNTSCTV) {
- xgifb_reg_set(pVBInfo->Part1Port,
- 0x07, 0x54);
- xgifb_reg_set(pVBInfo->Part1Port,
- 0x08, 0x00);
- } else {
- xgifb_reg_set(pVBInfo->Part1Port,
- 0x07, 0x55);
- xgifb_reg_set(pVBInfo->Part1Port,
- 0x08, 0x00);
- xgifb_reg_set(pVBInfo->Part1Port,
- 0x0C, 0xF0);
- }
- }
-
- if ((ModeNo == 0x04) || (ModeNo == 0x05) || (ModeNo
- == 0x0D) || (ModeNo == 0x50)) {
+ if (ModeNo == 0x50) {
if (pVBInfo->TVInfo & SetNTSCTV) {
xgifb_reg_set(pVBInfo->Part1Port,
0x07, 0x30);
@@ -4796,18 +4271,10 @@ static void XGI_SetGroup2(unsigned short ModeNo, unsigned short ModeIdIndex,
unsigned long longtemp, tempeax, tempebx, temp2, tempecx;
- if (ModeNo <= 0x13) {
- /* si+St_ResInfo */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- resinfo = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
- crt2crtc = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC;
- } else {
- /* si+Ext_ResInfo */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- crt2crtc = pVBInfo->RefIndex[RefreshRateTableIndex].
- Ext_CRT2CRTC;
- }
+ /* si+Ext_ResInfo */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+ crt2crtc = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
tempax = 0;
@@ -5245,18 +4712,11 @@ static void XGI_SetLCDRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
struct XGI_LCDDesStruct *LCDBDesPtr = NULL;
- if (ModeNo <= 0x13) {
- /* si+St_ResInfo */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- resinfo = pVBInfo->SModeIDTable[ModeIdIndex].St_ResInfo;
- } else {
- /* si+Ext_ResInfo */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
- CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].
- Ext_CRT1CRTC;
- CRT1Index &= IndexMask;
- }
+ /* si+Ext_ResInfo */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ resinfo = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+ CRT1Index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+ CRT1Index &= IndexMask;
if (!(pVBInfo->VBInfo & SetCRT2ToLCD))
return;
@@ -5274,16 +4734,6 @@ static void XGI_SetLCDRegs(unsigned short ModeNo, unsigned short ModeIdIndex,
xgifb_reg_and_or(pVBInfo->Part2Port, 0x2B, 0x0F, temp);
temp = 0x01;
- if (pVBInfo->LCDResInfo == Panel_1280x1024) {
- if (pVBInfo->ModeType == ModeEGA) {
- if (pVBInfo->VGAHDE >= 1024) {
- temp = 0x02;
- if (pVBInfo->LCDInfo & XGI_LCDVESATiming)
- temp = 0x01;
- }
- }
- }
-
xgifb_reg_set(pVBInfo->Part2Port, 0x0B, temp);
tempbx = pVBInfo->VDE; /* RTVACTEO=(VDE-1)&0xFF */
push1 = tempbx;
@@ -5542,12 +4992,8 @@ static void XGI_SetGroup3(unsigned short ModeNo, unsigned short ModeIdIndex,
unsigned char *tempdi;
unsigned short modeflag;
- if (ModeNo <= 0x13)
- /* si+St_ResInfo */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- /* si+Ext_ResInfo */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
+ /* si+Ext_ResInfo */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
xgifb_reg_set(pVBInfo->Part3Port, 0x00, 0x00);
if (pVBInfo->TVInfo & TVSetPAL) {
@@ -5605,13 +5051,8 @@ static void XGI_SetGroup4(unsigned short ModeNo, unsigned short ModeIdIndex,
unsigned long tempebx, tempeax, templong;
- if (ModeNo <= 0x13)
- /* si+St_ResInfo */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- /* si+Ext_ResInfo */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-
+ /* si+Ext_ResInfo */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
temp = pVBInfo->RVBHCFACT;
xgifb_reg_set(pVBInfo->Part4Port, 0x13, temp);
@@ -5818,32 +5259,22 @@ static unsigned char XGI_XG21CheckLVDSMode(struct xgifb_video_info *xgifb_info,
{
unsigned short xres, yres, colordepth, modeflag, resindex;
- resindex = XGI_GetResInfo(ModeNo, ModeIdIndex, pVBInfo);
- if (ModeNo <= 0x13) {
- xres = pVBInfo->StResInfo[resindex].HTotal;
- yres = pVBInfo->StResInfo[resindex].VTotal;
- /* si+St_ResInfo */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- } else {
- xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
- yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */
- /* si+St_ModeFlag */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- }
+ resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+ xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
+ yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */
+ /* si+St_ModeFlag */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
if (!(modeflag & Charx8Dot)) {
xres /= 9;
xres *= 8;
}
- if (ModeNo > 0x13) {
- if ((ModeNo > 0x13) && (modeflag & HalfDCLK))
- xres *= 2;
-
- if ((ModeNo > 0x13) && (modeflag & DoubleScanMode))
- yres *= 2;
+ if ((ModeNo > 0x13) && (modeflag & HalfDCLK))
+ xres *= 2;
- }
+ if ((ModeNo > 0x13) && (modeflag & DoubleScanMode))
+ yres *= 2;
if (xres > xgifb_info->lvds_data.LVDSHDE)
return 0;
@@ -5851,16 +5282,11 @@ static unsigned char XGI_XG21CheckLVDSMode(struct xgifb_video_info *xgifb_info,
if (yres > xgifb_info->lvds_data.LVDSVDE)
return 0;
- if (ModeNo > 0x13) {
- if (xres != xgifb_info->lvds_data.LVDSHDE ||
- yres != xgifb_info->lvds_data.LVDSVDE) {
- colordepth = XGI_GetColorDepth(ModeNo,
- ModeIdIndex,
- pVBInfo);
- if (colordepth > 2)
- return 0;
-
- }
+ if (xres != xgifb_info->lvds_data.LVDSHDE ||
+ yres != xgifb_info->lvds_data.LVDSVDE) {
+ colordepth = XGI_GetColorDepth(ModeNo, ModeIdIndex, pVBInfo);
+ if (colordepth > 2)
+ return 0;
}
return 1;
}
@@ -5895,18 +5321,11 @@ static void xgifb_set_lvds(struct xgifb_video_info *xgifb_info,
else
XGI_SetXG21FPBits(pVBInfo);
- resindex = XGI_GetResInfo(ModeNo, ModeIdIndex, pVBInfo);
- if (ModeNo <= 0x13) {
- xres = pVBInfo->StResInfo[resindex].HTotal;
- yres = pVBInfo->StResInfo[resindex].VTotal;
- /* si+St_ResInfo */
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- } else {
- xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
- yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */
- /* si+St_ModeFlag */
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
- }
+ resindex = pVBInfo->EModeIDTable[ModeIdIndex].Ext_RESINFO;
+ xres = pVBInfo->ModeResInfo[resindex].HTotal; /* xres->ax */
+ yres = pVBInfo->ModeResInfo[resindex].VTotal; /* yres->bx */
+ /* si+St_ModeFlag */
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
if (!(modeflag & Charx8Dot))
xres = xres * 8 / 9;
@@ -5914,8 +5333,6 @@ static void xgifb_set_lvds(struct xgifb_video_info *xgifb_info,
LVDSHT = xgifb_info->lvds_data.LVDSHT;
LVDSHBS = xres + (xgifb_info->lvds_data.LVDSHDE - xres) / 2;
- if ((ModeNo <= 0x13) && (modeflag & HalfDCLK))
- LVDSHBS -= xres / 4;
if (LVDSHBS > LVDSHT)
LVDSHBS -= LVDSHT;
@@ -5933,7 +5350,7 @@ static void xgifb_set_lvds(struct xgifb_video_info *xgifb_info,
LVDSVT = xgifb_info->lvds_data.LVDSVT;
LVDSVBS = yres + (xgifb_info->lvds_data.LVDSVDE - yres) / 2;
- if ((ModeNo > 0x13) && (modeflag & DoubleScanMode))
+ if (modeflag & DoubleScanMode)
LVDSVBS += yres / 2;
if (LVDSVBS > LVDSVT)
@@ -6527,7 +5944,7 @@ static void XGI_SetAntiFlicker(unsigned short ModeNo,
unsigned short ModeIdIndex,
struct vb_device_info *pVBInfo)
{
- unsigned short tempbx, index;
+ unsigned short tempbx;
unsigned char tempah;
@@ -6536,13 +5953,6 @@ static void XGI_SetAntiFlicker(unsigned short ModeNo,
tempbx = XGI_GetTVPtrIndex(pVBInfo);
tempbx &= 0xFE;
-
- if (ModeNo <= 0x13)
- index = pVBInfo->SModeIDTable[ModeIdIndex].VB_StTVFlickerIndex;
- else
- index = pVBInfo->EModeIDTable[ModeIdIndex].VB_ExtTVFlickerIndex;
-
- tempbx += index;
tempah = TVAntiFlickList[tempbx];
tempah = tempah << 4;
@@ -6553,19 +5963,12 @@ static void XGI_SetEdgeEnhance(unsigned short ModeNo,
unsigned short ModeIdIndex,
struct vb_device_info *pVBInfo)
{
- unsigned short tempbx, index;
+ unsigned short tempbx;
unsigned char tempah;
tempbx = XGI_GetTVPtrIndex(pVBInfo);
tempbx &= 0xFE;
-
- if (ModeNo <= 0x13)
- index = pVBInfo->SModeIDTable[ModeIdIndex].VB_StTVEdgeIndex;
- else
- index = pVBInfo->EModeIDTable[ModeIdIndex].VB_ExtTVEdgeIndex;
-
- tempbx += index;
tempah = TVEdgeList[tempbx];
tempah = tempah << 5;
@@ -6631,13 +6034,7 @@ static void XGI_SetYFilter(unsigned short ModeNo, unsigned short ModeIdIndex,
return;
}
- if (ModeNo <= 0x13)
- tempal = pVBInfo->SModeIDTable[ModeIdIndex].
- VB_StTVYFilterIndex;
- else
- tempal = pVBInfo->EModeIDTable[ModeIdIndex].
- VB_ExtTVYFilterIndex;
-
+ tempal = pVBInfo->EModeIDTable[ModeIdIndex].VB_ExtTVYFilterIndex;
if (tempcl == 0)
index = tempal * 4;
else
@@ -6712,16 +6109,14 @@ static void XGI_SetCRT2ModeRegs(unsigned short ModeNo,
if (pVBInfo->VBInfo & (SetCRT2ToRAMDAC | SetCRT2ToTV
| SetCRT2ToLCD)) {
tempah = 0x40; /* BTDRAM */
- if (ModeNo > 0x13) {
- tempcl = pVBInfo->ModeType;
- tempcl -= ModeVGA;
- if (tempcl >= 0) {
- /* BT Color */
- tempah = (0x008 >> tempcl);
- if (tempah == 0)
- tempah = 1;
- tempah |= 0x040;
- }
+ tempcl = pVBInfo->ModeType;
+ tempcl -= ModeVGA;
+ if (tempcl >= 0) {
+ /* BT Color */
+ tempah = (0x008 >> tempcl);
+ if (tempah == 0)
+ tempah = 1;
+ tempah |= 0x040;
}
if (pVBInfo->VBInfo & SetInSlaveMode)
tempah ^= 0x50; /* BTDAC */
@@ -6797,10 +6192,8 @@ static void XGI_SetCRT2ModeRegs(unsigned short ModeNo,
if (pVBInfo->VBInfo & SetCRT2ToTV) {
tempah |= 0x020;
- if (ModeNo > 0x13) {
- if (pVBInfo->VBInfo & DriverMode)
- tempah = tempah ^ 0x20;
- }
+ if (pVBInfo->VBInfo & DriverMode)
+ tempah = tempah ^ 0x20;
}
xgifb_reg_and_or(pVBInfo->Part4Port, 0x0D, ~0x0BF, tempah);
@@ -6925,13 +6318,7 @@ unsigned short XGI_GetRatePtrCRT2(struct xgi_hw_device_info *pXGIHWDE,
unsigned short RefreshRateTableIndex, i, modeflag, index, temp;
- if (ModeNo <= 0x13)
- modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag;
- else
- modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
-
- if (ModeNo < 0x14)
- return 0xFFFF;
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag;
index = xgifb_reg_get(pVBInfo->P3d4, 0x33);
index = index >> pVBInfo->SelectCRT2Rate;
@@ -7297,16 +6684,13 @@ static void XGI_SetCRT1Group(struct xgifb_video_info *xgifb_info,
unsigned short ModeNo, unsigned short ModeIdIndex,
struct vb_device_info *pVBInfo)
{
- unsigned short StandTableIndex, RefreshRateTableIndex, b3CC, temp;
+ unsigned short RefreshRateTableIndex, temp;
- unsigned short XGINew_P3cc = pVBInfo->P3cc;
-
- StandTableIndex = XGI_GetModePtr(ModeNo, ModeIdIndex, pVBInfo);
- XGI_SetSeqRegs(ModeNo, StandTableIndex, ModeIdIndex, pVBInfo);
- outb(pVBInfo->StandTable[StandTableIndex].MISC, pVBInfo->P3c2);
- XGI_SetCRTCRegs(HwDeviceExtension, StandTableIndex, pVBInfo);
- XGI_SetATTRegs(ModeNo, StandTableIndex, ModeIdIndex, pVBInfo);
- XGI_SetGRCRegs(StandTableIndex, pVBInfo);
+ XGI_SetSeqRegs(ModeNo, ModeIdIndex, pVBInfo);
+ outb(pVBInfo->StandTable->MISC, pVBInfo->P3c2);
+ XGI_SetCRTCRegs(HwDeviceExtension, pVBInfo);
+ XGI_SetATTRegs(ModeNo, ModeIdIndex, pVBInfo);
+ XGI_SetGRCRegs(pVBInfo);
XGI_ClearExt1Regs(pVBInfo);
if (HwDeviceExtension->jChipType == XG27) {
@@ -7340,22 +6724,6 @@ static void XGI_SetCRT1Group(struct xgifb_video_info *xgifb_info,
RefreshRateTableIndex, pVBInfo);
}
- if ((HwDeviceExtension->jChipType >= XG20) &&
- (HwDeviceExtension->jChipType < XG27)) { /* fix H/W DCLK/2 bug */
- if ((ModeNo == 0x00) | (ModeNo == 0x01)) {
- xgifb_reg_set(pVBInfo->P3c4, 0x2B, 0x4E);
- xgifb_reg_set(pVBInfo->P3c4, 0x2C, 0xE9);
- b3CC = (unsigned char) inb(XGINew_P3cc);
- outb((b3CC |= 0x0C), XGINew_P3cc);
- } else if ((ModeNo == 0x04) | (ModeNo == 0x05) | (ModeNo
- == 0x0D)) {
- xgifb_reg_set(pVBInfo->P3c4, 0x2B, 0x1B);
- xgifb_reg_set(pVBInfo->P3c4, 0x2C, 0xE3);
- b3CC = (unsigned char) inb(XGINew_P3cc);
- outb((b3CC |= 0x0C), XGINew_P3cc);
- }
- }
-
if (HwDeviceExtension->jChipType >= XG21) {
temp = xgifb_reg_get(pVBInfo->P3d4, 0x38);
if (temp & 0xA0) {
@@ -7394,7 +6762,7 @@ unsigned char XGISetModeNew(struct xgifb_video_info *xgifb_info,
unsigned short ModeIdIndex;
struct vb_device_info VBINF;
struct vb_device_info *pVBInfo = &VBINF;
- pVBInfo->BaseAddr = (unsigned long) HwDeviceExtension->pjIOAddress;
+ pVBInfo->BaseAddr = xgifb_info->vga_base;
pVBInfo->IF_DEF_LVDS = 0;
pVBInfo->IF_DEF_LCDA = 1;
@@ -7509,13 +6877,8 @@ unsigned char XGISetModeNew(struct xgifb_video_info *xgifb_info,
pVBInfo))
return 0;
- if (ModeNo <= 0x13) {
- pVBInfo->ModeType = pVBInfo->SModeIDTable[ModeIdIndex].
- St_ModeFlag & ModeTypeMask;
- } else {
- pVBInfo->ModeType = pVBInfo->EModeIDTable[ModeIdIndex].
+ pVBInfo->ModeType = pVBInfo->EModeIDTable[ModeIdIndex].
Ext_ModeFlag & ModeTypeMask;
- }
pVBInfo->SetFlag = 0;
pVBInfo->VBInfo = DisableCRT2Display;
diff --git a/drivers/staging/xgifb/vb_struct.h b/drivers/staging/xgifb/vb_struct.h
index a5bd56af92b1..38f47ffc69c4 100644
--- a/drivers/staging/xgifb/vb_struct.h
+++ b/drivers/staging/xgifb/vb_struct.h
@@ -10,28 +10,11 @@ struct XGI_LVDSCRT1VDataStruct {
unsigned char Reg[7];
};
-struct XGI_StStruct {
- unsigned char St_ModeID;
- unsigned short St_ModeFlag;
- unsigned char St_StTableIndex;
- unsigned char St_CRT2CRTC;
- unsigned char St_CRT2CRTC2;
- unsigned char St_ResInfo;
- unsigned char VB_StTVFlickerIndex;
- unsigned char VB_StTVEdgeIndex;
- unsigned char VB_StTVYFilterIndex;
-};
-
struct XGI_ExtStruct {
unsigned char Ext_ModeID;
unsigned short Ext_ModeFlag;
unsigned short Ext_ModeInfo;
- unsigned short Ext_Point;
- unsigned short Ext_VESAID;
- unsigned char Ext_VESAMEMSize;
unsigned char Ext_RESINFO;
- unsigned char VB_ExtTVFlickerIndex;
- unsigned char VB_ExtTVEdgeIndex;
unsigned char VB_ExtTVYFilterIndex;
unsigned char REFindex;
};
@@ -68,14 +51,6 @@ struct XGI_LCDDataTablStruct {
unsigned short DATAPTR;
};
-struct XGI330_LCDDataDesStruct {
- unsigned short LCDHDES;
- unsigned short LCDHRS;
- unsigned short LCDVDES;
- unsigned short LCDVRS;
-};
-
-
struct XGI330_LVDSDataStruct {
unsigned short VGAHT;
unsigned short VGAVT;
@@ -236,7 +211,6 @@ struct vb_device_info {
void __iomem *FBAddr;
unsigned long BaseAddr;
- unsigned long RelIO;
unsigned char (*CR6B)[4];
unsigned char (*CR6E)[4];
@@ -314,7 +288,6 @@ struct vb_device_info {
struct XGI_TimingHStruct *TimingH;
struct XGI_TimingVStruct *TimingV;
- struct XGI_StStruct *SModeIDTable;
struct SiS_StandTable_S *StandTable;
struct XGI_ExtStruct *EModeIDTable;
struct XGI_Ext2Struct *RefIndex;
diff --git a/drivers/staging/xgifb/vb_table.h b/drivers/staging/xgifb/vb_table.h
index e8d6f674b274..d22e599cb305 100644
--- a/drivers/staging/xgifb/vb_table.h
+++ b/drivers/staging/xgifb/vb_table.h
@@ -135,609 +135,92 @@ static unsigned char XGI330_SR33;
static unsigned char XG40_CRCF = 0x13;
static unsigned char XG40_DRAMTypeDefinition = 0xFF ;
-static struct XGI_StStruct XGI330_SModeIDTable[] = {
- {0x01, 0x9208, 0x01, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00},
- {0x01, 0x1210, 0x14, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00},
- {0x01, 0x1010, 0x17, 0x02, 0x11, 0x00, 0x00, 0x01, 0x01},
- {0x03, 0x8208, 0x03, 0x00, 0x14, 0x00, 0x00, 0x01, 0x02},
- {0x03, 0x0210, 0x16, 0x01, 0x04, 0x01, 0x00, 0x01, 0x02},
- {0x03, 0x0010, 0x18, 0x02, 0x15, 0x00, 0x00, 0x01, 0x03},
- {0x05, 0x9209, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04},
- {0x06, 0x8209, 0x06, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05},
- {0x07, 0x0000, 0x07, 0x03, 0x05, 0x03, 0x00, 0x01, 0x03},
- {0x07, 0x0000, 0x19, 0x02, 0x15, 0x02, 0x00, 0x01, 0x03},
- {0x0d, 0x920a, 0x0d, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04},
- {0x0e, 0x820a, 0x0e, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05},
- {0x0f, 0x0202, 0x11, 0x01, 0x04, 0x01, 0x00, 0x00, 0x05},
- {0x10, 0x0212, 0x12, 0x01, 0x04, 0x01, 0x00, 0x00, 0x05},
- {0x11, 0x0212, 0x1a, 0x04, 0x24, 0x04, 0x00, 0x00, 0x05},
- {0x12, 0x0212, 0x1b, 0x04, 0x24, 0x04, 0x00, 0x00, 0x05},
- {0x13, 0x021b, 0x1c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04},
- {0x12, 0x0010, 0x18, 0x02, 0x24, 0x02, 0x00, 0x00, 0x05},/* St_CRT2CRTC2
- not sure */
- {0x12, 0x0210, 0x18, 0x01, 0x24, 0x01, 0x00, 0x00, 0x05},/* St_CRT2CRTC2
- not sure */
- {0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
-};
-
-
static struct XGI_ExtStruct XGI330_EModeIDTable[] = {
- {0x6a, 0x2212, 0x0407, 0x3a81, 0x0102, 0x08,
- 0x07, 0x00, 0x00, 0x07, 0x0e},
- {0x2e, 0x0a1b, 0x0306, 0x3a57, 0x0101, 0x08,
- 0x06, 0x00, 0x00, 0x05, 0x06},
- {0x2f, 0x0a1b, 0x0305, 0x3a50, 0x0100, 0x08,
- 0x05, 0x00, 0x00, 0x05, 0x05},
- {0x30, 0x2a1b, 0x0407, 0x3a81, 0x0103, 0x08,
- 0x07, 0x00, 0x00, 0x07, 0x0e},
- {0x31, 0x0a1b, 0x030d, 0x3b85, 0x0000, 0x08,
- 0x0d, 0x00, 0x00, 0x06, 0x3d},
- {0x32, 0x0a1b, 0x0a0e, 0x3b8c, 0x0000, 0x08,
- 0x0e, 0x00, 0x00, 0x06, 0x3e},
- {0x33, 0x0a1d, 0x0a0d, 0x3b85, 0x0000, 0x08,
- 0x0d, 0x00, 0x00, 0x06, 0x3d},
- {0x34, 0x2a1d, 0x0a0e, 0x3b8c, 0x0000, 0x08,
- 0x0e, 0x00, 0x00, 0x06, 0x3e},
- {0x35, 0x0a1f, 0x0a0d, 0x3b85, 0x0000, 0x08,
- 0x0d, 0x00, 0x00, 0x06, 0x3d},
- {0x36, 0x2a1f, 0x0a0e, 0x3b8c, 0x0000, 0x08,
- 0x0e, 0x00, 0x00, 0x06, 0x3e},
- {0x37, 0x0212, 0x0508, 0x3aab, 0x0104, 0x08,
- 0x08, 0x00, 0x00, 0x00, 0x16},
- {0x38, 0x0a1b, 0x0508, 0x3aab, 0x0105, 0x08,
- 0x08, 0x00, 0x00, 0x00, 0x16},
- {0x3a, 0x0e3b, 0x0609, 0x3adc, 0x0107, 0x08,
- 0x09, 0x00, 0x00, 0x00, 0x1e},
- {0x3c, 0x0e3b, 0x070a, 0x3af2, 0x0130, 0x08,
- 0x0a, 0x00, 0x00, 0x00, 0x22}, /* mode 1600x1200
+ {0x2e, 0x0a1b, 0x0306, 0x06, 0x05, 0x06},
+ {0x2f, 0x0a1b, 0x0305, 0x05, 0x05, 0x05},
+ {0x30, 0x2a1b, 0x0407, 0x07, 0x07, 0x0e},
+ {0x31, 0x0a1b, 0x030d, 0x0d, 0x06, 0x3d},
+ {0x32, 0x0a1b, 0x0a0e, 0x0e, 0x06, 0x3e},
+ {0x33, 0x0a1d, 0x0a0d, 0x0d, 0x06, 0x3d},
+ {0x34, 0x2a1d, 0x0a0e, 0x0e, 0x06, 0x3e},
+ {0x35, 0x0a1f, 0x0a0d, 0x0d, 0x06, 0x3d},
+ {0x36, 0x2a1f, 0x0a0e, 0x0e, 0x06, 0x3e},
+ {0x38, 0x0a1b, 0x0508, 0x08, 0x00, 0x16},
+ {0x3a, 0x0e3b, 0x0609, 0x09, 0x00, 0x1e},
+ {0x3c, 0x0e3b, 0x070a, 0x0a, 0x00, 0x22}, /* mode 1600x1200
add CRT2MODE [2003/10/07] */
- {0x3d, 0x0e7d, 0x070a, 0x3af2, 0x0131, 0x08,
- 0x0a, 0x00, 0x00, 0x00, 0x22}, /* mode 1600x1200
+ {0x3d, 0x0e7d, 0x070a, 0x0a, 0x00, 0x22}, /* mode 1600x1200
add CRT2MODE */
- {0x40, 0x9a1c, 0x0000, 0x3a34, 0x010d, 0x08,
- 0x00, 0x00, 0x00, 0x04, 0x00},
- {0x41, 0x9a1d, 0x0000, 0x3a34, 0x010e, 0x08,
- 0x00, 0x00, 0x00, 0x04, 0x00}, /* ModeIdIndex = 0x10 */
- {0x43, 0x0a1c, 0x0306, 0x3a57, 0x0110, 0x08,
- 0x06, 0x00, 0x00, 0x05, 0x06},
- {0x44, 0x0a1d, 0x0306, 0x3a57, 0x0111, 0x08,
- 0x06, 0x00, 0x00, 0x05, 0x06},
- {0x46, 0x2a1c, 0x0407, 0x3a81, 0x0113, 0x08,
- 0x07, 0x00, 0x00, 0x07, 0x0e},
- {0x47, 0x2a1d, 0x0407, 0x3a81, 0x0114, 0x08,
- 0x07, 0x00, 0x00, 0x07, 0x0e},
- {0x49, 0x0a3c, 0x0508, 0x3aab, 0x0116, 0x08,
- 0x08, 0x00, 0x00, 0x00, 0x16},
- {0x4a, 0x0a3d, 0x0508, 0x3aab, 0x0117, 0x08,
- 0x08, 0x00, 0x00, 0x00, 0x16},
- {0x4c, 0x0e7c, 0x0609, 0x3adc, 0x0119, 0x08,
- 0x09, 0x00, 0x00, 0x00, 0x1e},
- {0x4d, 0x0e7d, 0x0609, 0x3adc, 0x011a, 0x08,
- 0x09, 0x00, 0x00, 0x00, 0x1e},
- {0x50, 0x9a1b, 0x0001, 0x3a3b, 0x0132, 0x08,
- 0x01, 0x00, 0x00, 0x04, 0x02},
- {0x51, 0xba1b, 0x0103, 0x3a42, 0x0133, 0x08,
- 0x03, 0x00, 0x00, 0x07, 0x03},
- {0x52, 0x9a1b, 0x0204, 0x3a49, 0x0134, 0x08,
- 0x04, 0x00, 0x00, 0x00, 0x04},
- {0x56, 0x9a1d, 0x0001, 0x3a3b, 0x0135, 0x08,
- 0x01, 0x00, 0x00, 0x04, 0x02},
- {0x57, 0xba1d, 0x0103, 0x3a42, 0x0136, 0x08,
- 0x03, 0x00, 0x00, 0x07, 0x03},
- {0x58, 0x9a1d, 0x0204, 0x3a49, 0x0137, 0x08,
- 0x04, 0x00, 0x00, 0x00, 0x04},
- {0x59, 0x9a1b, 0x0000, 0x3a34, 0x0138, 0x08,
- 0x00, 0x00, 0x00, 0x04, 0x00},
- {0x5A, 0x021b, 0x0014, 0x3b83, 0x0138, 0x08,
- 0x01, 0x00, 0x00, 0x04, 0x3f}, /* ModeIdIndex = 0x20 */
- {0x5B, 0x0a1d, 0x0014, 0x3b83, 0x0135, 0x08,
- 0x01, 0x00, 0x00, 0x04, 0x3f},
- {0x5d, 0x0a1d, 0x0305, 0x3a50, 0x0139, 0x08,
- 0x05, 0x00, 0x00, 0x07, 0x05},
- {0x62, 0x0a3f, 0x0306, 0x3a57, 0x013a, 0x08,
- 0x06, 0x00, 0x00, 0x05, 0x06},
- {0x63, 0x2a3f, 0x0407, 0x3a81, 0x013b, 0x08,
- 0x07, 0x00, 0x00, 0x07, 0x0e},
- {0x64, 0x0a7f, 0x0508, 0x3aab, 0x013c, 0x08,
- 0x08, 0x00, 0x00, 0x00, 0x16},
- {0x65, 0x0eff, 0x0609, 0x3adc, 0x013d, 0x08,
- 0x09, 0x00, 0x00, 0x00, 0x1e},
- {0x66, 0x0eff, 0x070a, 0x3af2, 0x013e, 0x08,
- 0x0a, 0x00, 0x00, 0x00, 0x22}, /* mode 1600x1200
+ {0x40, 0x9a1c, 0x0000, 0x00, 0x04, 0x00},
+ {0x41, 0x9a1d, 0x0000, 0x00, 0x04, 0x00},
+ {0x43, 0x0a1c, 0x0306, 0x06, 0x05, 0x06},
+ {0x44, 0x0a1d, 0x0306, 0x06, 0x05, 0x06},
+ {0x46, 0x2a1c, 0x0407, 0x07, 0x07, 0x0e},
+ {0x47, 0x2a1d, 0x0407, 0x07, 0x07, 0x0e},
+ {0x49, 0x0a3c, 0x0508, 0x08, 0x00, 0x16},
+ {0x4a, 0x0a3d, 0x0508, 0x08, 0x00, 0x16},
+ {0x4c, 0x0e7c, 0x0609, 0x09, 0x00, 0x1e},
+ {0x4d, 0x0e7d, 0x0609, 0x09, 0x00, 0x1e},
+ {0x50, 0x9a1b, 0x0001, 0x01, 0x04, 0x02},
+ {0x51, 0xba1b, 0x0103, 0x03, 0x07, 0x03},
+ {0x52, 0x9a1b, 0x0204, 0x04, 0x00, 0x04},
+ {0x56, 0x9a1d, 0x0001, 0x01, 0x04, 0x02},
+ {0x57, 0xba1d, 0x0103, 0x03, 0x07, 0x03},
+ {0x58, 0x9a1d, 0x0204, 0x04, 0x00, 0x04},
+ {0x59, 0x9a1b, 0x0000, 0x00, 0x04, 0x00},
+ {0x5A, 0x021b, 0x0014, 0x01, 0x04, 0x3f},
+ {0x5B, 0x0a1d, 0x0014, 0x01, 0x04, 0x3f},
+ {0x5d, 0x0a1d, 0x0305, 0x05, 0x07, 0x05},
+ {0x62, 0x0a3f, 0x0306, 0x06, 0x05, 0x06},
+ {0x63, 0x2a3f, 0x0407, 0x07, 0x07, 0x0e},
+ {0x64, 0x0a7f, 0x0508, 0x08, 0x00, 0x16},
+ {0x65, 0x0eff, 0x0609, 0x09, 0x00, 0x1e},
+ {0x66, 0x0eff, 0x070a, 0x0a, 0x00, 0x22}, /* mode 1600x1200
add CRT2MODE */
- {0x68, 0x067b, 0x080b, 0x3b17, 0x013f, 0x08,
- 0x0b, 0x00, 0x00, 0x00, 0x29},
- {0x69, 0x06fd, 0x080b, 0x3b17, 0x0140, 0x08,
- 0x0b, 0x00, 0x00, 0x00, 0x29},
- {0x6b, 0x07ff, 0x080b, 0x3b17, 0x0141, 0x10,
- 0x0b, 0x00, 0x00, 0x00, 0x29},
- {0x6c, 0x067b, 0x090c, 0x3b37, 0x0000, 0x08,
- 0x0c, 0x00, 0x00, 0x00, 0x2f},
- {0x6d, 0x06fd, 0x090c, 0x3b37, 0x0000, 0x10,
- 0x0c, 0x00, 0x00, 0x00, 0x2f},
- {0x6e, 0x07ff, 0x090c, 0x3b37, 0x0000, 0x10,
- 0x0c, 0x00, 0x00, 0x00, 0x2f},
- {0x70, 0x2a1b, 0x0410, 0x3b52, 0x0000, 0x08,
- 0x10, 0x00, 0x00, 0x07, 0x34},
- {0x71, 0x0a1b, 0x0511, 0x3b63, 0x0000, 0x08,
- 0x11, 0x00, 0x00, 0x00, 0x37},
- {0x74, 0x0a1d, 0x0511, 0x3b63, 0x0000, 0x08,
- 0x11, 0x00, 0x00, 0x00, 0x37}, /* ModeIdIndex = 0x30 */
- {0x75, 0x0a3d, 0x0612, 0x3b74, 0x0000, 0x08,
- 0x12, 0x00, 0x00, 0x00, 0x3a},
- {0x76, 0x2a1f, 0x0410, 0x3b52, 0x0000, 0x08,
- 0x10, 0x00, 0x00, 0x07, 0x34},
- {0x77, 0x0a1f, 0x0511, 0x3b63, 0x0000, 0x08,
- 0x11, 0x00, 0x00, 0x00, 0x37},
- {0x78, 0x0a3f, 0x0612, 0x3b74, 0x0000, 0x08,
- 0x12, 0x00, 0x00, 0x00, 0x3a},
- {0x79, 0x0a3b, 0x0612, 0x3b74, 0x0000, 0x08,
- 0x12, 0x00, 0x00, 0x00, 0x3a},
- {0x7a, 0x2a1d, 0x0410, 0x3b52, 0x0000, 0x08,
- 0x10, 0x00, 0x00, 0x07, 0x34},
- {0x7b, 0x0e3b, 0x060f, 0x3ad0, 0x0000, 0x08,
- 0x0f, 0x00, 0x00, 0x00, 0x1d},
- {0x7c, 0x0e7d, 0x060f, 0x3ad0, 0x0000, 0x08,
- 0x0f, 0x00, 0x00, 0x00, 0x1d},
- {0x7d, 0x0eff, 0x060f, 0x3ad0, 0x0000, 0x08,
- 0x0f, 0x00, 0x00, 0x00, 0x1d},
- {0x20, 0x0e3b, 0x0D16, 0x49e0, 0x0000, 0x08,
- 0x16, 0x00, 0x00, 0x00, 0x43},
- {0x21, 0x0e7d, 0x0D16, 0x49e0, 0x0000, 0x08,
- 0x16, 0x00, 0x00, 0x00, 0x43},
- {0x22, 0x0eff, 0x0D16, 0x49e0, 0x0000, 0x08,
- 0x16, 0x00, 0x00, 0x00, 0x43},
- {0x23, 0x0e3b, 0x0614, 0x49d5, 0x0000, 0x08,
- 0x14, 0x00, 0x00, 0x00, 0x41},
- {0x24, 0x0e7d, 0x0614, 0x49d5, 0x0000, 0x08,
- 0x14, 0x00, 0x00, 0x00, 0x41},
- {0x25, 0x0eff, 0x0614, 0x49d5, 0x0000, 0x08,
- 0x14, 0x00, 0x00, 0x00, 0x41},
- {0x26, 0x063b, 0x0c15, 0x49dc, 0x0000, 0x08,
- 0x15, 0x00, 0x00, 0x00, 0x42}, /* ModeIdIndex = 0x40 */
- {0x27, 0x067d, 0x0c15, 0x49dc, 0x0000, 0x08,
- 0x15, 0x00, 0x00, 0x00, 0x42},
- {0x28, 0x06ff, 0x0c15, 0x49dc, 0x0000, 0x08,
- 0x15, 0x00, 0x00, 0x00, 0x42},
- {0xff, 0x0000, 0x0000, 0x0000, 0x0000, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00}
-};
-
-static struct SiS_StandTable_S XGI330_StandTable[] = {
-/* MD_0_200 */
- {
- 0x28, 0x18, 0x08, 0x0800,
- {0x09, 0x03, 0x00, 0x02},
- 0x63,
- {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f,
- 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x08, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
- 0xff}
- },
-/* MD_1_200 */
- {
- 0x28, 0x18, 0x08, 0x0800,
- {0x09, 0x03, 0x00, 0x02},
- 0x63,
- {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f,
- 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x08, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
- 0xff}
- },
-/* MD_2_200 */
- {
- 0x50, 0x18, 0x08, 0x1000,
- {0x01, 0x03, 0x00, 0x02},
- 0x63,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x08, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
- 0xff}
- },
-/* MD_3_200 */
- {
- 0x50, 0x18, 0x08, 0x1000,
- {0x01, 0x03, 0x00, 0x02},
- 0x63,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0xc7, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x08, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
- 0xff}
- },
-/* MD_4 */
- {
- 0x28, 0x18, 0x08, 0x4000,
- {0x09, 0x03, 0x00, 0x02},
- 0x63,
- {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f,
- 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2,
- 0xff},
- {0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x01, 0x00, 0x03, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x00,
- 0xff}
- },
-/* MD_5 */
- {
- 0x28, 0x18, 0x08, 0x4000,
- {0x09, 0x03, 0x00, 0x02},
- 0x63,
- {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f,
- 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xa2,
- 0xff},
- {0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x01, 0x00, 0x03, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0f, 0x00,
- 0xff}
- },
-/* MD_6 */
- {
- 0x50, 0x18, 0x08, 0x4000,
- {0x01, 0x01, 0x00, 0x06},
- 0x63,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xc2,
- 0xff},
- {0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
- 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
- 0x01, 0x00, 0x01, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00,
- 0xff}
- },
-/* MD_7 */
- {
- 0x50, 0x18, 0x0e, 0x1000,
- {0x00, 0x03, 0x00, 0x03},
- 0xa6,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00,
- 0x83, 0x85, 0x5d, 0x28, 0x0d, 0x63, 0xba, 0xa3,
- 0xff},
- {0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
- 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x0e, 0x00, 0x0f, 0x08},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00,
- 0xff}
- },
-/* MDA_DAC */
- {
- 0x00, 0x00, 0x00, 0x0000,
- {0x00, 0x00, 0x00, 0x15},
- 0x15,
- {0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
- 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x3f, 0x3f,
- 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00, 0x00,
- 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x15, 0x15,
- 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
- 0x15, 0x15, 0x15, 0x15},
- {0x15, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
- 0x3f}
- },
-/* CGA_DAC */
- {
- 0x00, 0x10, 0x04, 0x0114,
- {0x11, 0x09, 0x15, 0x00},
- 0x10,
- {0x04, 0x14, 0x01, 0x11, 0x09, 0x15, 0x2a, 0x3a,
- 0x2e, 0x3e, 0x2b, 0x3b, 0x2f, 0x3f, 0x2a, 0x3a,
- 0x2e, 0x3e, 0x2b, 0x3b, 0x2f, 0x3f, 0x00, 0x10,
- 0x04},
- {0x14, 0x01, 0x11, 0x09, 0x15, 0x00, 0x10, 0x04,
- 0x14, 0x01, 0x11, 0x09, 0x15, 0x2a, 0x3a, 0x2e,
- 0x3e, 0x2b, 0x3b, 0x2f},
- {0x3f, 0x2a, 0x3a, 0x2e, 0x3e, 0x2b, 0x3b, 0x2f,
- 0x3f}
- },
-/* EGA_DAC */
- {
- 0x00, 0x10, 0x04, 0x0114,
- {0x11, 0x05, 0x15, 0x20},
- 0x30,
- {0x24, 0x34, 0x21, 0x31, 0x25, 0x35, 0x08, 0x18,
- 0x0c, 0x1c, 0x09, 0x19, 0x0d, 0x1d, 0x28, 0x38,
- 0x2c, 0x3c, 0x29, 0x39, 0x2d, 0x3d, 0x02, 0x12,
- 0x06},
- {0x16, 0x03, 0x13, 0x07, 0x17, 0x22, 0x32, 0x26,
- 0x36, 0x23, 0x33, 0x27, 0x37, 0x0a, 0x1a, 0x0e,
- 0x1e, 0x0b, 0x1b, 0x0f},
- {0x1f, 0x2a, 0x3a, 0x2e, 0x3e, 0x2b, 0x3b, 0x2f,
- 0x3f}
- },
-/* VGA_DAC */
- {
- 0x00, 0x10, 0x04, 0x0114,
- {0x11, 0x09, 0x15, 0x2a},
- 0x3a,
- {0x2e, 0x3e, 0x2b, 0x3b, 0x2f, 0x3f, 0x00, 0x05,
- 0x08, 0x0b, 0x0e, 0x11, 0x14, 0x18, 0x1c, 0x20,
- 0x24, 0x28, 0x2d, 0x32, 0x38, 0x3f, 0x00, 0x10,
- 0x1f},
- {0x2f, 0x3f, 0x1f, 0x27, 0x2f, 0x37, 0x3f, 0x2d,
- 0x31, 0x36, 0x3a, 0x3f, 0x00, 0x07, 0x0e, 0x15,
- 0x1c, 0x0e, 0x11, 0x15},
- {0x18, 0x1c, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x00,
- 0x04}
- },
- {
- 0x08, 0x0c, 0x10, 0x0a08,
- {0x0c, 0x0e, 0x10, 0x0b},
- 0x0c,
- {0x0d, 0x0f, 0x10, 0x10, 0x01, 0x08, 0x00, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x02, 0x02, 0x01, 0x00,
- 0x04, 0x04, 0x01, 0x00, 0x05, 0x02, 0x05, 0x00,
- 0x06},
- {0x01, 0x06, 0x05, 0x06, 0x00, 0x08, 0x01, 0x08,
- 0x00, 0x07, 0x02, 0x07, 0x06, 0x07, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00}
- },
-/* MD_D */
- {
- 0x28, 0x18, 0x08, 0x2000,
- {0x09, 0x0f, 0x00, 0x06},
- 0x63,
- {0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f,
- 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x14, 0x00, 0x96, 0xb9, 0xe3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x01, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f,
- 0xff}
- },
-/* MD_E */
- {
- 0x50, 0x18, 0x08, 0x4000,
- {0x01, 0x0f, 0x00, 0x06},
- 0x63,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x28, 0x00, 0x96, 0xb9, 0xe3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x01, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f,
- 0xff}
- },
+ {0x68, 0x067b, 0x080b, 0x0b, 0x00, 0x29},
+ {0x69, 0x06fd, 0x080b, 0x0b, 0x00, 0x29},
+ {0x6b, 0x07ff, 0x080b, 0x0b, 0x00, 0x29},
+ {0x6c, 0x067b, 0x090c, 0x0c, 0x00, 0x2f},
+ {0x6d, 0x06fd, 0x090c, 0x0c, 0x00, 0x2f},
+ {0x6e, 0x07ff, 0x090c, 0x0c, 0x00, 0x2f},
+ {0x70, 0x2a1b, 0x0410, 0x10, 0x07, 0x34},
+ {0x71, 0x0a1b, 0x0511, 0x11, 0x00, 0x37},
+ {0x74, 0x0a1d, 0x0511, 0x11, 0x00, 0x37},
+ {0x75, 0x0a3d, 0x0612, 0x12, 0x00, 0x3a},
+ {0x76, 0x2a1f, 0x0410, 0x10, 0x07, 0x34},
+ {0x77, 0x0a1f, 0x0511, 0x11, 0x00, 0x37},
+ {0x78, 0x0a3f, 0x0612, 0x12, 0x00, 0x3a},
+ {0x79, 0x0a3b, 0x0612, 0x12, 0x00, 0x3a},
+ {0x7a, 0x2a1d, 0x0410, 0x10, 0x07, 0x34},
+ {0x7b, 0x0e3b, 0x060f, 0x0f, 0x00, 0x1d},
+ {0x7c, 0x0e7d, 0x060f, 0x0f, 0x00, 0x1d},
+ {0x7d, 0x0eff, 0x060f, 0x0f, 0x00, 0x1d},
+ {0x20, 0x0e3b, 0x0D16, 0x16, 0x00, 0x43},
+ {0x21, 0x0e7d, 0x0D16, 0x16, 0x00, 0x43},
+ {0x22, 0x0eff, 0x0D16, 0x16, 0x00, 0x43},
+ {0x23, 0x0e3b, 0x0614, 0x14, 0x00, 0x41},
+ {0x24, 0x0e7d, 0x0614, 0x14, 0x00, 0x41},
+ {0x25, 0x0eff, 0x0614, 0x14, 0x00, 0x41},
+ {0x26, 0x063b, 0x0c15, 0x15, 0x00, 0x42},
+ {0x27, 0x067d, 0x0c15, 0x15, 0x00, 0x42},
+ {0x28, 0x06ff, 0x0c15, 0x15, 0x00, 0x42},
+ {0xff, 0x0000, 0x0000, 0x00, 0x00, 0x00}
+};
+
+static struct SiS_StandTable_S XGI330_StandTable = {
/* ExtVGATable */
- {
- 0x00, 0x00, 0x00, 0x0000,
- {0x01, 0x0f, 0x00, 0x0e},
- 0x23,
- {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
- 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x01, 0x00, 0x00, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f,
- 0xff}
- },
-/* ROM_SAVEPTR */
- {
- 0x9f, 0x3b, 0x00, 0x00c0,
- {0x00, 0x00, 0x00, 0x00},
- 0x00,
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x3f,
- 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x1a, 0x00, 0xac, 0x3e, 0x00, 0xc0,
- 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00}
- },
-/* MD_F */
- {
- 0x50, 0x18, 0x0e, 0x8000,
- {0x01, 0x0f, 0x00, 0x06},
- 0xa2,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x82, 0x84, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3,
- 0xff},
- {0x00, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
- 0x00, 0x08, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
- 0x0b, 0x00, 0x05, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x05,
- 0xff}
- },
-/* MD_10 */
- {
- 0x50, 0x18, 0x0e, 0x8000,
- {0x01, 0x0f, 0x00, 0x06},
- 0xa3,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x82, 0x84, 0x5d, 0x28, 0x0f, 0x63, 0xba, 0xe3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x01, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f,
- 0xff}
- },
-/* MD_0_350 */
- {
- 0x28, 0x18, 0x0e, 0x0800,
- {0x09, 0x03, 0x00, 0x02},
- 0xa3,
- {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xb1, 0xbf, 0x1f,
- 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00,
- 0x83, 0x85, 0x5d, 0x14, 0x1f, 0x63, 0xba, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x08, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
- 0xff}
- },
-/* MD_1_350 */
- {
- 0x28, 0x18, 0x0e, 0x0800,
- {0x09, 0x03, 0x00, 0x02},
- 0xa3,
- {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xa0, 0xbf, 0x1f,
- 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00,
- 0x83, 0x85, 0x5d, 0x14, 0x1f, 0x63, 0xba, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x08, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
- 0xff}
- },
-/* MD_2_350 */
- {
- 0x50, 0x18, 0x0e, 0x1000,
- {0x01, 0x03, 0x00, 0x02},
- 0xa3,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00,
- 0x83, 0x85, 0x5d, 0x28, 0x1f, 0x63, 0xba, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x08, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
- 0xff}
- },
-/* MD_3_350 */
- {
- 0x50, 0x18, 0x0e, 0x1000,
- {0x01, 0x03, 0x00, 0x02},
- 0xa3,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0x4d, 0x0b, 0x0c, 0x00, 0x00, 0x00, 0x00,
- 0x83, 0x85, 0x5d, 0x28, 0x1f, 0x63, 0xba, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x08, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
- 0xff}
- },
-/* MD_0_1_400 */
- {
- 0x28, 0x18, 0x10, 0x0800,
- {0x08, 0x03, 0x00, 0x02},
- 0x67,
- {0x2d, 0x27, 0x28, 0x90, 0x2b, 0xb1, 0xbf, 0x1f,
- 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x14, 0x1f, 0x96, 0xb9, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x0c, 0x00, 0x0f, 0x08},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
- 0xff}
- },
-/* MD_2_3_400 */
- {
- 0x50, 0x18, 0x10, 0x1000,
- {0x00, 0x03, 0x00, 0x02},
- 0x67,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x0c, 0x00, 0x0f, 0x08},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00,
- 0xff}
- },
-/* MD_7_400 */
- {
- 0x50, 0x18, 0x10, 0x1000,
- {0x00, 0x03, 0x00, 0x02},
- 0x66,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x28, 0x0f, 0x96, 0xb9, 0xa3,
- 0xff},
- {0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
- 0x10, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x0e, 0x00, 0x0f, 0x08},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00,
- 0xff}
- },
-/* MD_11 */
- {
- 0x50, 0x1d, 0x10, 0xa000,
- {0x01, 0x0f, 0x00, 0x06},
- 0xe3,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e,
- 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xc3,
- 0xff},
- {0x00, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
- 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
- 0x01, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x01,
- 0xff}
- },
-/* ExtEGATable */
- {
- 0x50, 0x1d, 0x10, 0xa000,
- {0x01, 0x0f, 0x00, 0x06},
- 0xe3,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0x0b, 0x3e,
- 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xe9, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
- 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
- 0x01, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f,
- 0xff}
- },
-/* MD_13 */
- {
- 0x28, 0x18, 0x08, 0x2000,
- {0x01, 0x0f, 0x00, 0x0e},
- 0x63,
- {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
- 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9c, 0x8e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3,
- 0xff},
- {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x41, 0x00, 0x0f, 0x00},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f,
- 0xff}
- }
+ 0x00, 0x00, 0x00, 0x0000,
+ {0x01, 0x0f, 0x00, 0x0e},
+ 0x23,
+ {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3,
+ 0xff},
+ {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x01, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f,
+ 0xff}
};
static struct XGI_TimingHStruct XGI_TimingH[1];
@@ -1143,7 +626,7 @@ static struct XGI330_LCDDataStruct XGI_NoScalingDatax75[] = {
{1, 1, 1688, 806, 1688, 806} /* ; 0A (1280x768x75Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1024x768Data[] = {
+static struct XGI_LCDDesStruct XGI_ExtLCDDes1024x768Data[] = {
{9, 1057, 0, 771}, /* ; 00 (320x200,320x400,640x200,640x400) */
{9, 1057, 0, 771}, /* ; 01 (320x350,640x350) */
{9, 1057, 0, 771}, /* ; 02 (360x400,720x400) */
@@ -1153,7 +636,7 @@ static struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1024x768Data[] = {
{9, 1057, 805, 770} /* ; 06 (1024x768x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_StLCDDes1024x768Data[] = {
+static struct XGI_LCDDesStruct XGI_StLCDDes1024x768Data[] = {
{9, 1057, 737, 703}, /* ; 00 (320x200,320x400,640x200,640x400) */
{9, 1057, 686, 651}, /* ; 01 (320x350,640x350) */
{9, 1057, 737, 703}, /* ; 02 (360x400,720x400) */
@@ -1163,7 +646,7 @@ static struct XGI330_LCDDataDesStruct XGI_StLCDDes1024x768Data[] = {
{9, 1057, 805, 770} /* ; 06 (1024x768x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1024x768Data[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDes1024x768Data[] = {
{1152, 856, 622, 587}, /* ; 00 (320x200,320x400,640x200,640x400) */
{1152, 856, 597, 562}, /* ; 01 (320x350,640x350) */
{1152, 856, 622, 587}, /* ; 02 (360x400,720x400) */
@@ -1173,7 +656,7 @@ static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1024x768Data[] = {
{0, 1048, 805, 770} /* ; 06 (1024x768x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1280x1024Data[] = {
+static struct XGI_LCDDesStruct XGI_ExtLCDDLDes1280x1024Data[] = {
{18, 1346, 981, 940}, /* 00 (320x200,320x400,640x200,640x400) */
{18, 1346, 926, 865}, /* 01 (320x350,640x350) */
{18, 1346, 981, 940}, /* 02 (360x400,720x400) */
@@ -1184,7 +667,7 @@ static struct XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1280x1024Data[] = {
{18, 1346, 1065, 1024} /* 07 (1280x1024x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_StLCDDLDes1280x1024Data[] = {
+static struct XGI_LCDDesStruct XGI_StLCDDLDes1280x1024Data[] = {
{18, 1346, 970, 907}, /* 00 (320x200,320x400,640x200,640x400) */
{18, 1346, 917, 854}, /* 01 (320x350,640x350) */
{18, 1346, 970, 907}, /* 02 (360x400,720x400) */
@@ -1195,7 +678,7 @@ static struct XGI330_LCDDataDesStruct XGI_StLCDDLDes1280x1024Data[] = {
{18, 1346, 1065, 1024} /* 07 (1280x1024x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_CetLCDDLDes1280x1024Data[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDLDes1280x1024Data[] = {
{1368, 1008, 752, 711}, /* 00 (320x200,320x400,640x200,640x400) */
{1368, 1008, 729, 688}, /* 01 (320x350,640x350) */
{1368, 1008, 752, 711}, /* 02 (360x400,720x400) */
@@ -1206,7 +689,7 @@ static struct XGI330_LCDDataDesStruct XGI_CetLCDDLDes1280x1024Data[] = {
{18, 1346, 1065, 1024} /* 07 (1280x1024x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1280x1024Data[] = {
+static struct XGI_LCDDesStruct XGI_ExtLCDDes1280x1024Data[] = {
{9, 1337, 981, 940}, /* ; 00 (320x200,320x400,640x200,640x400) */
{9, 1337, 926, 884}, /* ; 01 (320x350,640x350) alan, 2003/09/30 */
{9, 1337, 981, 940}, /* ; 02 (360x400,720x400) */
@@ -1217,7 +700,7 @@ static struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1280x1024Data[] = {
{9, 1337, 1065, 1024} /* ; 07 (1280x1024x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_StLCDDes1280x1024Data[] = {
+static struct XGI_LCDDesStruct XGI_StLCDDes1280x1024Data[] = {
{9, 1337, 970, 907}, /* ; 00 (320x200,320x400,640x200,640x400) */
{9, 1337, 917, 854}, /* ; 01 (320x350,640x350) */
{9, 1337, 970, 907}, /* ; 02 (360x400,720x400) */
@@ -1228,7 +711,7 @@ static struct XGI330_LCDDataDesStruct XGI_StLCDDes1280x1024Data[] = {
{9, 1337, 1065, 1024} /* ; 07 (1280x1024x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1280x1024Data[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDes1280x1024Data[] = {
{1368, 1008, 752, 711}, /* 00 (320x200,320x400,640x200,640x400) */
{1368, 1008, 729, 688}, /* 01 (320x350,640x350) */
{1368, 1008, 752, 711}, /* 02 (360x400,720x400) */
@@ -1239,7 +722,7 @@ static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1280x1024Data[] = {
{9, 1337, 1065, 1024} /* 07 (1280x1024x60Hz) */
};
-static struct XGI330_LCDDataDesStruct xgifb_lcddldes_1400x1050[] = {
+static struct XGI_LCDDesStruct xgifb_lcddldes_1400x1050[] = {
{18, 1464, 0, 1051}, /* 00 (320x200,320x400,640x200,640x400) */
{18, 1464, 0, 1051}, /* 01 (320x350,640x350) */
{18, 1464, 0, 1051}, /* 02 (360x400,720x400) */
@@ -1251,7 +734,7 @@ static struct XGI330_LCDDataDesStruct xgifb_lcddldes_1400x1050[] = {
{18, 1464, 0, 1051} /* 08 (1400x1050x60Hz) */
};
-static struct XGI330_LCDDataDesStruct xgifb_lcddes_1400x1050[] = {
+static struct XGI_LCDDesStruct xgifb_lcddes_1400x1050[] = {
{9, 1455, 0, 1051}, /* 00 (320x200,320x400,640x200,640x400) */
{9, 1455, 0, 1051}, /* 01 (320x350,640x350) */
{9, 1455, 0, 1051}, /* 02 (360x400,720x400) */
@@ -1263,7 +746,7 @@ static struct XGI330_LCDDataDesStruct xgifb_lcddes_1400x1050[] = {
{9, 1455, 0, 1051} /* 08 (1400x1050x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1400x1050Data[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDes1400x1050Data[] = {
{1308, 1068, 781, 766}, /* 00 (320x200,320x400,640x200,640x400) */
{1308, 1068, 781, 766}, /* 01 (320x350,640x350) */
{1308, 1068, 781, 766}, /* 02 (360x400,720x400) */
@@ -1275,7 +758,7 @@ static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1400x1050Data[] = {
{18, 1464, 0, 1051} /* 08 (1400x1050x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1400x1050Data2[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDes1400x1050Data2[] = {
{0, 1448, 0, 1051}, /* 00 (320x200,320x400,640x200,640x400) */
{0, 1448, 0, 1051}, /* 01 (320x350,640x350) */
{0, 1448, 0, 1051}, /* 02 (360x400,720x400) */
@@ -1283,7 +766,7 @@ static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1400x1050Data2[] = {
{0, 1448, 0, 1051} /* 04 (640x480x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1600x1200Data[] = {
+static struct XGI_LCDDesStruct XGI_ExtLCDDLDes1600x1200Data[] = {
{18, 1682, 0, 1201}, /* 00 (320x200,320x400,640x200,640x400) */
{18, 1682, 0, 1201}, /* 01 (320x350,640x350) */
{18, 1682, 0, 1201}, /* 02 (360x400,720x400) */
@@ -1296,7 +779,7 @@ static struct XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1600x1200Data[] = {
{18, 1682, 0, 1201} /* 09 (1600x1200x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_StLCDDLDes1600x1200Data[] = {
+static struct XGI_LCDDesStruct XGI_StLCDDLDes1600x1200Data[] = {
{18, 1682, 1150, 1101}, /* 00 (320x200,320x400,640x200,640x400) */
{18, 1682, 1083, 1034}, /* 01 (320x350,640x350) */
{18, 1682, 1150, 1101}, /* 02 (360x400,720x400) */
@@ -1309,7 +792,7 @@ static struct XGI330_LCDDataDesStruct XGI_StLCDDLDes1600x1200Data[] = {
{18, 1682, 0, 1201} /* 09 (1600x1200x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1600x1200Data[] = {
+static struct XGI_LCDDesStruct XGI_ExtLCDDes1600x1200Data[] = {
{9, 1673, 0, 1201}, /* 00 (320x200,320x400,640x200,640x400) */
{9, 1673, 0, 1201}, /* 01 (320x350,640x350) */
{9, 1673, 0, 1201}, /* 02 (360x400,720x400) */
@@ -1322,7 +805,7 @@ static struct XGI330_LCDDataDesStruct XGI_ExtLCDDes1600x1200Data[] = {
{9, 1673, 0, 1201} /* 09 (1600x1200x60Hz) */
};
-static struct XGI330_LCDDataDesStruct XGI_StLCDDes1600x1200Data[] = {
+static struct XGI_LCDDesStruct XGI_StLCDDes1600x1200Data[] = {
{9, 1673, 1150, 1101}, /* 00 (320x200,320x400,640x200,640x400) */
{9, 1673, 1083, 1034}, /* 01 (320x350,640x350) */
{9, 1673, 1150, 1101}, /* 02 (360x400,720x400) */
@@ -1352,7 +835,7 @@ static struct XGI330_LCDDataDesStruct2 XGI_NoScalingDesData[] = {
};
/* ;;1024x768x75Hz */
-static struct XGI330_LCDDataDesStruct xgifb_lcddes_1024x768x75[] = {
+static struct XGI_LCDDesStruct xgifb_lcddes_1024x768x75[] = {
{9, 1049, 0, 769}, /* ; 00 (320x200,320x400,640x200,640x400) */
{9, 1049, 0, 769}, /* ; 01 (320x350,640x350) */
{9, 1049, 0, 769}, /* ; 02 (360x400,720x400) */
@@ -1363,7 +846,7 @@ static struct XGI330_LCDDataDesStruct xgifb_lcddes_1024x768x75[] = {
};
/* ;;1024x768x75Hz */
-static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1024x768x75Data[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDes1024x768x75Data[] = {
{1152, 856, 622, 587}, /* ; 00 (320x200,320x400,640x200,640x400) */
{1152, 856, 597, 562}, /* ; 01 (320x350,640x350) */
{1192, 896, 622, 587}, /* ; 02 (360x400,720x400) */
@@ -1374,7 +857,7 @@ static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1024x768x75Data[] = {
};
/* ;;1280x1024x75Hz */
-static struct XGI330_LCDDataDesStruct xgifb_lcddldes_1280x1024x75[] = {
+static struct XGI_LCDDesStruct xgifb_lcddldes_1280x1024x75[] = {
{18, 1314, 0, 1025}, /* ; 00 (320x200,320x400,640x200,640x400) */
{18, 1314, 0, 1025}, /* ; 01 (320x350,640x350) */
{18, 1314, 0, 1025}, /* ; 02 (360x400,720x400) */
@@ -1386,7 +869,7 @@ static struct XGI330_LCDDataDesStruct xgifb_lcddldes_1280x1024x75[] = {
};
/* 1280x1024x75Hz */
-static struct XGI330_LCDDataDesStruct XGI_CetLCDDLDes1280x1024x75Data[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDLDes1280x1024x75Data[] = {
{1368, 1008, 752, 711}, /* ; 00 (320x200,320x400,640x200,640x400) */
{1368, 1008, 729, 688}, /* ; 01 (320x350,640x350) */
{1408, 1048, 752, 711}, /* ; 02 (360x400,720x400) */
@@ -1398,7 +881,7 @@ static struct XGI330_LCDDataDesStruct XGI_CetLCDDLDes1280x1024x75Data[] = {
};
/* ;;1280x1024x75Hz */
-static struct XGI330_LCDDataDesStruct xgifb_lcddes_1280x1024x75[] = {
+static struct XGI_LCDDesStruct xgifb_lcddes_1280x1024x75[] = {
{9, 1305, 0, 1025}, /* ; 00 (320x200,320x400,640x200,640x400) */
{9, 1305, 0, 1025}, /* ; 01 (320x350,640x350) */
{9, 1305, 0, 1025}, /* ; 02 (360x400,720x400) */
@@ -1410,7 +893,7 @@ static struct XGI330_LCDDataDesStruct xgifb_lcddes_1280x1024x75[] = {
};
/* 1280x1024x75Hz */
-static struct XGI330_LCDDataDesStruct XGI_CetLCDDes1280x1024x75Data[] = {
+static struct XGI_LCDDesStruct XGI_CetLCDDes1280x1024x75Data[] = {
{1368, 1008, 752, 711}, /* ; 00 (320x200,320x400,640x200,640x400) */
{1368, 1008, 729, 688}, /* ; 01 (320x350,640x350) */
{1408, 1048, 752, 711}, /* ; 02 (360x400,720x400) */
diff --git a/drivers/staging/xgifb/vgatypes.h b/drivers/staging/xgifb/vgatypes.h
index a7208e315815..30cdd1af81f1 100644
--- a/drivers/staging/xgifb/vgatypes.h
+++ b/drivers/staging/xgifb/vgatypes.h
@@ -66,8 +66,6 @@ struct xgi_hw_device_info {
unsigned long ulVideoMemorySize; /* size, in bytes, of the
memory on the board */
- unsigned char *pjIOAddress; /* base I/O address of VGA ports (0x3B0) */
-
unsigned char jChipType; /* Used to Identify Graphics Chip */
/* defined in the data structure type */
/* "XGI_CHIP_TYPE" */
diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c b/drivers/staging/zsmalloc/zsmalloc-main.c
index 917461c66014..449673773286 100644
--- a/drivers/staging/zsmalloc/zsmalloc-main.c
+++ b/drivers/staging/zsmalloc/zsmalloc-main.c
@@ -45,12 +45,12 @@ static DEFINE_PER_CPU(struct mapping_area, zs_map_area);
static int is_first_page(struct page *page)
{
- return test_bit(PG_private, &page->flags);
+ return PagePrivate(page);
}
static int is_last_page(struct page *page)
{
- return test_bit(PG_private_2, &page->flags);
+ return PagePrivate2(page);
}
static void get_zspage_mapping(struct page *page, unsigned int *class_idx,
@@ -180,7 +180,7 @@ out:
* link together 3 PAGE_SIZE sized pages to form a zspage
* since then we can perfectly fit in 8 such objects.
*/
-static int get_zspage_order(int class_size)
+static int get_pages_per_zspage(int class_size)
{
int i, max_usedpc = 0;
/* zspage order which gives maximum used size per KB */
@@ -368,7 +368,7 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags)
* identify the last page.
*/
error = -ENOMEM;
- for (i = 0; i < class->zspage_order; i++) {
+ for (i = 0; i < class->pages_per_zspage; i++) {
struct page *page, *prev_page;
page = alloc_page(flags);
@@ -377,7 +377,7 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags)
INIT_LIST_HEAD(&page->lru);
if (i == 0) { /* first page */
- set_bit(PG_private, &page->flags);
+ SetPagePrivate(page);
set_page_private(page, 0);
first_page = page;
first_page->inuse = 0;
@@ -388,9 +388,8 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags)
page->first_page = first_page;
if (i >= 2)
list_add(&page->lru, &prev_page->lru);
- if (i == class->zspage_order - 1) /* last page */
- set_bit(PG_private_2, &page->flags);
-
+ if (i == class->pages_per_zspage - 1) /* last page */
+ SetPagePrivate2(page);
prev_page = page;
}
@@ -398,7 +397,7 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags)
first_page->freelist = obj_location_to_handle(first_page, 0);
/* Maximum number of objects we can store in this zspage */
- first_page->objects = class->zspage_order * PAGE_SIZE / class->size;
+ first_page->objects = class->pages_per_zspage * PAGE_SIZE / class->size;
error = 0; /* Success */
@@ -513,7 +512,7 @@ struct zs_pool *zs_create_pool(const char *name, gfp_t flags)
class->size = size;
class->index = i;
spin_lock_init(&class->lock);
- class->zspage_order = get_zspage_order(size);
+ class->pages_per_zspage = get_pages_per_zspage(size);
}
@@ -567,13 +566,9 @@ EXPORT_SYMBOL_GPL(zs_destroy_pool);
* zs_malloc - Allocate block of given size from pool.
* @pool: pool to allocate from
* @size: size of block to allocate
- * @page: page no. that holds the object
- * @offset: location of object within page
- *
- * On success, <page, offset> identifies block allocated
- * and 0 is returned. On failure, <page, offset> is set to
- * 0 and -ENOMEM is returned.
*
+ * On success, handle to the allocated object is returned,
+ * otherwise NULL.
* Allocation requests with size > ZS_MAX_ALLOC_SIZE will fail.
*/
void *zs_malloc(struct zs_pool *pool, size_t size)
@@ -604,7 +599,7 @@ void *zs_malloc(struct zs_pool *pool, size_t size)
set_zspage_mapping(first_page, class->index, ZS_EMPTY);
spin_lock(&class->lock);
- class->pages_allocated += class->zspage_order;
+ class->pages_allocated += class->pages_per_zspage;
}
obj = first_page->freelist;
@@ -659,7 +654,7 @@ void zs_free(struct zs_pool *pool, void *obj)
fullness = fix_fullness_group(pool, first_page);
if (fullness == ZS_EMPTY)
- class->pages_allocated -= class->zspage_order;
+ class->pages_allocated -= class->pages_per_zspage;
spin_unlock(&class->lock);
@@ -668,6 +663,15 @@ void zs_free(struct zs_pool *pool, void *obj)
}
EXPORT_SYMBOL_GPL(zs_free);
+/**
+ * zs_map_object - get address of allocated object from handle.
+ * @pool: pool from which the object was allocated
+ * @handle: handle returned from zs_malloc
+ *
+ * Before using an object allocated from zs_malloc, it must be mapped using
+ * this function. When done with the object, it must be unmapped using
+ * zs_unmap_object
+*/
void *zs_map_object(struct zs_pool *pool, void *handle)
{
struct page *page;
diff --git a/drivers/staging/zsmalloc/zsmalloc_int.h b/drivers/staging/zsmalloc/zsmalloc_int.h
index 92eefc663afc..6fd32a9e0315 100644
--- a/drivers/staging/zsmalloc/zsmalloc_int.h
+++ b/drivers/staging/zsmalloc/zsmalloc_int.h
@@ -124,7 +124,7 @@ struct size_class {
unsigned int index;
/* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
- int zspage_order;
+ int pages_per_zspage;
spinlock_t lock;
diff --git a/drivers/target/Kconfig b/drivers/target/Kconfig
index b28794b72125..18303686eb58 100644
--- a/drivers/target/Kconfig
+++ b/drivers/target/Kconfig
@@ -32,5 +32,6 @@ config TCM_PSCSI
source "drivers/target/loopback/Kconfig"
source "drivers/target/tcm_fc/Kconfig"
source "drivers/target/iscsi/Kconfig"
+source "drivers/target/sbp/Kconfig"
endif
diff --git a/drivers/target/Makefile b/drivers/target/Makefile
index 62e54053bcd8..61648d84fbb6 100644
--- a/drivers/target/Makefile
+++ b/drivers/target/Makefile
@@ -25,3 +25,4 @@ obj-$(CONFIG_TCM_PSCSI) += target_core_pscsi.o
obj-$(CONFIG_LOOPBACK_TARGET) += loopback/
obj-$(CONFIG_TCM_FC) += tcm_fc/
obj-$(CONFIG_ISCSI_TARGET) += iscsi/
+obj-$(CONFIG_SBP_TARGET) += sbp/
diff --git a/drivers/target/sbp/Kconfig b/drivers/target/sbp/Kconfig
new file mode 100644
index 000000000000..132da544eafc
--- /dev/null
+++ b/drivers/target/sbp/Kconfig
@@ -0,0 +1,11 @@
+config SBP_TARGET
+ tristate "FireWire SBP-2 fabric module"
+ depends on FIREWIRE && EXPERIMENTAL
+ help
+ Say Y or M here to enable SCSI target functionality over FireWire.
+ This enables you to expose SCSI devices to other nodes on the FireWire
+ bus, for example hard disks. Similar to FireWire Target Disk mode on
+ many Apple computers.
+
+ To compile this driver as a module, say M here: The module will be
+ called sbp-target.
diff --git a/drivers/target/sbp/Makefile b/drivers/target/sbp/Makefile
new file mode 100644
index 000000000000..27747ad054c4
--- /dev/null
+++ b/drivers/target/sbp/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SBP_TARGET) += sbp_target.o
diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c
new file mode 100644
index 000000000000..37c609898f84
--- /dev/null
+++ b/drivers/target/sbp/sbp_target.c
@@ -0,0 +1,2621 @@
+/*
+ * SBP2 target driver (SCSI over IEEE1394 in target mode)
+ *
+ * Copyright (C) 2011 Chris Boot <bootc@bootc.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define KMSG_COMPONENT "sbp_target"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/configfs.h>
+#include <linux/ctype.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_tcq.h>
+#include <target/target_core_base.h>
+#include <target/target_core_backend.h>
+#include <target/target_core_fabric.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/target_core_configfs.h>
+#include <target/configfs_macros.h>
+#include <asm/unaligned.h>
+
+#include "sbp_target.h"
+
+/* Local pointer to allocated TCM configfs fabric module */
+static struct target_fabric_configfs *sbp_fabric_configfs;
+
+/* FireWire address region for management and command block address handlers */
+static const struct fw_address_region sbp_register_region = {
+ .start = CSR_REGISTER_BASE + 0x10000,
+ .end = 0x1000000000000ULL,
+};
+
+static const u32 sbp_unit_directory_template[] = {
+ 0x1200609e, /* unit_specifier_id: NCITS/T10 */
+ 0x13010483, /* unit_sw_version: 1155D Rev 4 */
+ 0x3800609e, /* command_set_specifier_id: NCITS/T10 */
+ 0x390104d8, /* command_set: SPC-2 */
+ 0x3b000000, /* command_set_revision: 0 */
+ 0x3c000001, /* firmware_revision: 1 */
+};
+
+#define SESSION_MAINTENANCE_INTERVAL HZ
+
+static atomic_t login_id = ATOMIC_INIT(0);
+
+static void session_maintenance_work(struct work_struct *);
+static int sbp_run_transaction(struct fw_card *, int, int, int, int,
+ unsigned long long, void *, size_t);
+
+static int read_peer_guid(u64 *guid, const struct sbp_management_request *req)
+{
+ int ret;
+ __be32 high, low;
+
+ ret = sbp_run_transaction(req->card, TCODE_READ_QUADLET_REQUEST,
+ req->node_addr, req->generation, req->speed,
+ (CSR_REGISTER_BASE | CSR_CONFIG_ROM) + 3 * 4,
+ &high, sizeof(high));
+ if (ret != RCODE_COMPLETE)
+ return ret;
+
+ ret = sbp_run_transaction(req->card, TCODE_READ_QUADLET_REQUEST,
+ req->node_addr, req->generation, req->speed,
+ (CSR_REGISTER_BASE | CSR_CONFIG_ROM) + 4 * 4,
+ &low, sizeof(low));
+ if (ret != RCODE_COMPLETE)
+ return ret;
+
+ *guid = (u64)be32_to_cpu(high) << 32 | be32_to_cpu(low);
+
+ return RCODE_COMPLETE;
+}
+
+static struct sbp_session *sbp_session_find_by_guid(
+ struct sbp_tpg *tpg, u64 guid)
+{
+ struct se_session *se_sess;
+ struct sbp_session *sess, *found = NULL;
+
+ spin_lock_bh(&tpg->se_tpg.session_lock);
+ list_for_each_entry(se_sess, &tpg->se_tpg.tpg_sess_list, sess_list) {
+ sess = se_sess->fabric_sess_ptr;
+ if (sess->guid == guid)
+ found = sess;
+ }
+ spin_unlock_bh(&tpg->se_tpg.session_lock);
+
+ return found;
+}
+
+static struct sbp_login_descriptor *sbp_login_find_by_lun(
+ struct sbp_session *session, struct se_lun *lun)
+{
+ struct sbp_login_descriptor *login, *found = NULL;
+
+ spin_lock_bh(&session->lock);
+ list_for_each_entry(login, &session->login_list, link) {
+ if (login->lun == lun)
+ found = login;
+ }
+ spin_unlock_bh(&session->lock);
+
+ return found;
+}
+
+static int sbp_login_count_all_by_lun(
+ struct sbp_tpg *tpg,
+ struct se_lun *lun,
+ int exclusive)
+{
+ struct se_session *se_sess;
+ struct sbp_session *sess;
+ struct sbp_login_descriptor *login;
+ int count = 0;
+
+ spin_lock_bh(&tpg->se_tpg.session_lock);
+ list_for_each_entry(se_sess, &tpg->se_tpg.tpg_sess_list, sess_list) {
+ sess = se_sess->fabric_sess_ptr;
+
+ spin_lock_bh(&sess->lock);
+ list_for_each_entry(login, &sess->login_list, link) {
+ if (login->lun != lun)
+ continue;
+
+ if (!exclusive || login->exclusive)
+ count++;
+ }
+ spin_unlock_bh(&sess->lock);
+ }
+ spin_unlock_bh(&tpg->se_tpg.session_lock);
+
+ return count;
+}
+
+static struct sbp_login_descriptor *sbp_login_find_by_id(
+ struct sbp_tpg *tpg, int login_id)
+{
+ struct se_session *se_sess;
+ struct sbp_session *sess;
+ struct sbp_login_descriptor *login, *found = NULL;
+
+ spin_lock_bh(&tpg->se_tpg.session_lock);
+ list_for_each_entry(se_sess, &tpg->se_tpg.tpg_sess_list, sess_list) {
+ sess = se_sess->fabric_sess_ptr;
+
+ spin_lock_bh(&sess->lock);
+ list_for_each_entry(login, &sess->login_list, link) {
+ if (login->login_id == login_id)
+ found = login;
+ }
+ spin_unlock_bh(&sess->lock);
+ }
+ spin_unlock_bh(&tpg->se_tpg.session_lock);
+
+ return found;
+}
+
+static struct se_lun *sbp_get_lun_from_tpg(struct sbp_tpg *tpg, int lun)
+{
+ struct se_portal_group *se_tpg = &tpg->se_tpg;
+ struct se_lun *se_lun;
+
+ if (lun >= TRANSPORT_MAX_LUNS_PER_TPG)
+ return ERR_PTR(-EINVAL);
+
+ spin_lock(&se_tpg->tpg_lun_lock);
+ se_lun = se_tpg->tpg_lun_list[lun];
+
+ if (se_lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE)
+ se_lun = ERR_PTR(-ENODEV);
+
+ spin_unlock(&se_tpg->tpg_lun_lock);
+
+ return se_lun;
+}
+
+static struct sbp_session *sbp_session_create(
+ struct sbp_tpg *tpg,
+ u64 guid)
+{
+ struct sbp_session *sess;
+ int ret;
+ char guid_str[17];
+ struct se_node_acl *se_nacl;
+
+ sess = kmalloc(sizeof(*sess), GFP_KERNEL);
+ if (!sess) {
+ pr_err("failed to allocate session descriptor\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ sess->se_sess = transport_init_session();
+ if (IS_ERR(sess->se_sess)) {
+ pr_err("failed to init se_session\n");
+
+ ret = PTR_ERR(sess->se_sess);
+ kfree(sess);
+ return ERR_PTR(ret);
+ }
+
+ snprintf(guid_str, sizeof(guid_str), "%016llx", guid);
+
+ se_nacl = core_tpg_check_initiator_node_acl(&tpg->se_tpg, guid_str);
+ if (!se_nacl) {
+ pr_warn("Node ACL not found for %s\n", guid_str);
+
+ transport_free_session(sess->se_sess);
+ kfree(sess);
+
+ return ERR_PTR(-EPERM);
+ }
+
+ sess->se_sess->se_node_acl = se_nacl;
+
+ spin_lock_init(&sess->lock);
+ INIT_LIST_HEAD(&sess->login_list);
+ INIT_DELAYED_WORK(&sess->maint_work, session_maintenance_work);
+
+ sess->guid = guid;
+
+ transport_register_session(&tpg->se_tpg, se_nacl, sess->se_sess, sess);
+
+ return sess;
+}
+
+static void sbp_session_release(struct sbp_session *sess, bool cancel_work)
+{
+ spin_lock_bh(&sess->lock);
+ if (!list_empty(&sess->login_list)) {
+ spin_unlock_bh(&sess->lock);
+ return;
+ }
+ spin_unlock_bh(&sess->lock);
+
+ if (cancel_work)
+ cancel_delayed_work_sync(&sess->maint_work);
+
+ transport_deregister_session_configfs(sess->se_sess);
+ transport_deregister_session(sess->se_sess);
+
+ if (sess->card)
+ fw_card_put(sess->card);
+
+ kfree(sess);
+}
+
+static void sbp_target_agent_unregister(struct sbp_target_agent *);
+
+static void sbp_login_release(struct sbp_login_descriptor *login,
+ bool cancel_work)
+{
+ struct sbp_session *sess = login->sess;
+
+ /* FIXME: abort/wait on tasks */
+
+ sbp_target_agent_unregister(login->tgt_agt);
+
+ if (sess) {
+ spin_lock_bh(&sess->lock);
+ list_del(&login->link);
+ spin_unlock_bh(&sess->lock);
+
+ sbp_session_release(sess, cancel_work);
+ }
+
+ kfree(login);
+}
+
+static struct sbp_target_agent *sbp_target_agent_register(
+ struct sbp_login_descriptor *);
+
+static void sbp_management_request_login(
+ struct sbp_management_agent *agent, struct sbp_management_request *req,
+ int *status_data_size)
+{
+ struct sbp_tport *tport = agent->tport;
+ struct sbp_tpg *tpg = tport->tpg;
+ struct se_lun *se_lun;
+ int ret;
+ u64 guid;
+ struct sbp_session *sess;
+ struct sbp_login_descriptor *login;
+ struct sbp_login_response_block *response;
+ int login_response_len;
+
+ se_lun = sbp_get_lun_from_tpg(tpg,
+ LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc)));
+ if (IS_ERR(se_lun)) {
+ pr_notice("login to unknown LUN: %d\n",
+ LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc)));
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_LUN_NOTSUPP));
+ return;
+ }
+
+ ret = read_peer_guid(&guid, req);
+ if (ret != RCODE_COMPLETE) {
+ pr_warn("failed to read peer GUID: %d\n", ret);
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+ return;
+ }
+
+ pr_notice("mgt_agent LOGIN to LUN %d from %016llx\n",
+ se_lun->unpacked_lun, guid);
+
+ sess = sbp_session_find_by_guid(tpg, guid);
+ if (sess) {
+ login = sbp_login_find_by_lun(sess, se_lun);
+ if (login) {
+ pr_notice("initiator already logged-in\n");
+
+ /*
+ * SBP-2 R4 says we should return access denied, but
+ * that can confuse initiators. Instead we need to
+ * treat this like a reconnect, but send the login
+ * response block like a fresh login.
+ *
+ * This is required particularly in the case of Apple
+ * devices booting off the FireWire target, where
+ * the firmware has an active login to the target. When
+ * the OS takes control of the session it issues its own
+ * LOGIN rather than a RECONNECT. To avoid the machine
+ * waiting until the reconnect_hold expires, we can skip
+ * the ACCESS_DENIED errors to speed things up.
+ */
+
+ goto already_logged_in;
+ }
+ }
+
+ /*
+ * check exclusive bit in login request
+ * reject with access_denied if any logins present
+ */
+ if (LOGIN_ORB_EXCLUSIVE(be32_to_cpu(req->orb.misc)) &&
+ sbp_login_count_all_by_lun(tpg, se_lun, 0)) {
+ pr_warn("refusing exclusive login with other active logins\n");
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+ return;
+ }
+
+ /*
+ * check exclusive bit in any existing login descriptor
+ * reject with access_denied if any exclusive logins present
+ */
+ if (sbp_login_count_all_by_lun(tpg, se_lun, 1)) {
+ pr_warn("refusing login while another exclusive login present\n");
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+ return;
+ }
+
+ /*
+ * check we haven't exceeded the number of allowed logins
+ * reject with resources_unavailable if we have
+ */
+ if (sbp_login_count_all_by_lun(tpg, se_lun, 0) >=
+ tport->max_logins_per_lun) {
+ pr_warn("max number of logins reached\n");
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+ return;
+ }
+
+ if (!sess) {
+ sess = sbp_session_create(tpg, guid);
+ if (IS_ERR(sess)) {
+ switch (PTR_ERR(sess)) {
+ case -EPERM:
+ ret = SBP_STATUS_ACCESS_DENIED;
+ break;
+ default:
+ ret = SBP_STATUS_RESOURCES_UNAVAIL;
+ break;
+ }
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(
+ STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(ret));
+ return;
+ }
+
+ sess->node_id = req->node_addr;
+ sess->card = fw_card_get(req->card);
+ sess->generation = req->generation;
+ sess->speed = req->speed;
+
+ schedule_delayed_work(&sess->maint_work,
+ SESSION_MAINTENANCE_INTERVAL);
+ }
+
+ /* only take the latest reconnect_hold into account */
+ sess->reconnect_hold = min(
+ 1 << LOGIN_ORB_RECONNECT(be32_to_cpu(req->orb.misc)),
+ tport->max_reconnect_timeout) - 1;
+
+ login = kmalloc(sizeof(*login), GFP_KERNEL);
+ if (!login) {
+ pr_err("failed to allocate login descriptor\n");
+
+ sbp_session_release(sess, true);
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+ return;
+ }
+
+ login->sess = sess;
+ login->lun = se_lun;
+ login->status_fifo_addr = sbp2_pointer_to_addr(&req->orb.status_fifo);
+ login->exclusive = LOGIN_ORB_EXCLUSIVE(be32_to_cpu(req->orb.misc));
+ login->login_id = atomic_inc_return(&login_id);
+
+ login->tgt_agt = sbp_target_agent_register(login);
+ if (IS_ERR(login->tgt_agt)) {
+ ret = PTR_ERR(login->tgt_agt);
+ pr_err("failed to map command block handler: %d\n", ret);
+
+ sbp_session_release(sess, true);
+ kfree(login);
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+ return;
+ }
+
+ spin_lock_bh(&sess->lock);
+ list_add_tail(&login->link, &sess->login_list);
+ spin_unlock_bh(&sess->lock);
+
+already_logged_in:
+ response = kzalloc(sizeof(*response), GFP_KERNEL);
+ if (!response) {
+ pr_err("failed to allocate login response block\n");
+
+ sbp_login_release(login, true);
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+ return;
+ }
+
+ login_response_len = clamp_val(
+ LOGIN_ORB_RESPONSE_LENGTH(be32_to_cpu(req->orb.length)),
+ 12, sizeof(*response));
+ response->misc = cpu_to_be32(
+ ((login_response_len & 0xffff) << 16) |
+ (login->login_id & 0xffff));
+ response->reconnect_hold = cpu_to_be32(sess->reconnect_hold & 0xffff);
+ addr_to_sbp2_pointer(login->tgt_agt->handler.offset,
+ &response->command_block_agent);
+
+ ret = sbp_run_transaction(sess->card, TCODE_WRITE_BLOCK_REQUEST,
+ sess->node_id, sess->generation, sess->speed,
+ sbp2_pointer_to_addr(&req->orb.ptr2), response,
+ login_response_len);
+ if (ret != RCODE_COMPLETE) {
+ pr_debug("failed to write login response block: %x\n", ret);
+
+ kfree(response);
+ sbp_login_release(login, true);
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+ return;
+ }
+
+ kfree(response);
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+static void sbp_management_request_query_logins(
+ struct sbp_management_agent *agent, struct sbp_management_request *req,
+ int *status_data_size)
+{
+ pr_notice("QUERY LOGINS not implemented\n");
+ /* FIXME: implement */
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+}
+
+static void sbp_management_request_reconnect(
+ struct sbp_management_agent *agent, struct sbp_management_request *req,
+ int *status_data_size)
+{
+ struct sbp_tport *tport = agent->tport;
+ struct sbp_tpg *tpg = tport->tpg;
+ int ret;
+ u64 guid;
+ struct sbp_login_descriptor *login;
+
+ ret = read_peer_guid(&guid, req);
+ if (ret != RCODE_COMPLETE) {
+ pr_warn("failed to read peer GUID: %d\n", ret);
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+ return;
+ }
+
+ pr_notice("mgt_agent RECONNECT from %016llx\n", guid);
+
+ login = sbp_login_find_by_id(tpg,
+ RECONNECT_ORB_LOGIN_ID(be32_to_cpu(req->orb.misc)));
+
+ if (!login) {
+ pr_err("mgt_agent RECONNECT unknown login ID\n");
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+ return;
+ }
+
+ if (login->sess->guid != guid) {
+ pr_err("mgt_agent RECONNECT login GUID doesn't match\n");
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+ return;
+ }
+
+ spin_lock_bh(&login->sess->lock);
+ if (login->sess->card)
+ fw_card_put(login->sess->card);
+
+ /* update the node details */
+ login->sess->generation = req->generation;
+ login->sess->node_id = req->node_addr;
+ login->sess->card = fw_card_get(req->card);
+ login->sess->speed = req->speed;
+ spin_unlock_bh(&login->sess->lock);
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+static void sbp_management_request_logout(
+ struct sbp_management_agent *agent, struct sbp_management_request *req,
+ int *status_data_size)
+{
+ struct sbp_tport *tport = agent->tport;
+ struct sbp_tpg *tpg = tport->tpg;
+ int login_id;
+ struct sbp_login_descriptor *login;
+
+ login_id = LOGOUT_ORB_LOGIN_ID(be32_to_cpu(req->orb.misc));
+
+ login = sbp_login_find_by_id(tpg, login_id);
+ if (!login) {
+ pr_warn("cannot find login: %d\n", login_id);
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_LOGIN_ID_UNKNOWN));
+ return;
+ }
+
+ pr_info("mgt_agent LOGOUT from LUN %d session %d\n",
+ login->lun->unpacked_lun, login->login_id);
+
+ if (req->node_addr != login->sess->node_id) {
+ pr_warn("logout from different node ID\n");
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+ return;
+ }
+
+ sbp_login_release(login, true);
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+static void session_check_for_reset(struct sbp_session *sess)
+{
+ bool card_valid = false;
+
+ spin_lock_bh(&sess->lock);
+
+ if (sess->card) {
+ spin_lock_irq(&sess->card->lock);
+ card_valid = (sess->card->local_node != NULL);
+ spin_unlock_irq(&sess->card->lock);
+
+ if (!card_valid) {
+ fw_card_put(sess->card);
+ sess->card = NULL;
+ }
+ }
+
+ if (!card_valid || (sess->generation != sess->card->generation)) {
+ pr_info("Waiting for reconnect from node: %016llx\n",
+ sess->guid);
+
+ sess->node_id = -1;
+ sess->reconnect_expires = get_jiffies_64() +
+ ((sess->reconnect_hold + 1) * HZ);
+ }
+
+ spin_unlock_bh(&sess->lock);
+}
+
+static void session_reconnect_expired(struct sbp_session *sess)
+{
+ struct sbp_login_descriptor *login, *temp;
+ LIST_HEAD(login_list);
+
+ pr_info("Reconnect timer expired for node: %016llx\n", sess->guid);
+
+ spin_lock_bh(&sess->lock);
+ list_for_each_entry_safe(login, temp, &sess->login_list, link) {
+ login->sess = NULL;
+ list_del(&login->link);
+ list_add_tail(&login->link, &login_list);
+ }
+ spin_unlock_bh(&sess->lock);
+
+ list_for_each_entry_safe(login, temp, &login_list, link) {
+ list_del(&login->link);
+ sbp_login_release(login, false);
+ }
+
+ sbp_session_release(sess, false);
+}
+
+static void session_maintenance_work(struct work_struct *work)
+{
+ struct sbp_session *sess = container_of(work, struct sbp_session,
+ maint_work.work);
+
+ /* could be called while tearing down the session */
+ spin_lock_bh(&sess->lock);
+ if (list_empty(&sess->login_list)) {
+ spin_unlock_bh(&sess->lock);
+ return;
+ }
+ spin_unlock_bh(&sess->lock);
+
+ if (sess->node_id != -1) {
+ /* check for bus reset and make node_id invalid */
+ session_check_for_reset(sess);
+
+ schedule_delayed_work(&sess->maint_work,
+ SESSION_MAINTENANCE_INTERVAL);
+ } else if (!time_after64(get_jiffies_64(), sess->reconnect_expires)) {
+ /* still waiting for reconnect */
+ schedule_delayed_work(&sess->maint_work,
+ SESSION_MAINTENANCE_INTERVAL);
+ } else {
+ /* reconnect timeout has expired */
+ session_reconnect_expired(sess);
+ }
+}
+
+static int tgt_agent_rw_agent_state(struct fw_card *card, int tcode, void *data,
+ struct sbp_target_agent *agent)
+{
+ __be32 state;
+
+ switch (tcode) {
+ case TCODE_READ_QUADLET_REQUEST:
+ pr_debug("tgt_agent AGENT_STATE READ\n");
+
+ spin_lock_bh(&agent->lock);
+ state = cpu_to_be32(agent->state);
+ spin_unlock_bh(&agent->lock);
+ memcpy(data, &state, sizeof(state));
+
+ return RCODE_COMPLETE;
+
+ case TCODE_WRITE_QUADLET_REQUEST:
+ /* ignored */
+ return RCODE_COMPLETE;
+
+ default:
+ return RCODE_TYPE_ERROR;
+ }
+}
+
+static int tgt_agent_rw_agent_reset(struct fw_card *card, int tcode, void *data,
+ struct sbp_target_agent *agent)
+{
+ switch (tcode) {
+ case TCODE_WRITE_QUADLET_REQUEST:
+ pr_debug("tgt_agent AGENT_RESET\n");
+ spin_lock_bh(&agent->lock);
+ agent->state = AGENT_STATE_RESET;
+ spin_unlock_bh(&agent->lock);
+ return RCODE_COMPLETE;
+
+ default:
+ return RCODE_TYPE_ERROR;
+ }
+}
+
+static int tgt_agent_rw_orb_pointer(struct fw_card *card, int tcode, void *data,
+ struct sbp_target_agent *agent)
+{
+ struct sbp2_pointer *ptr = data;
+
+ switch (tcode) {
+ case TCODE_WRITE_BLOCK_REQUEST:
+ spin_lock_bh(&agent->lock);
+ if (agent->state != AGENT_STATE_SUSPENDED &&
+ agent->state != AGENT_STATE_RESET) {
+ spin_unlock_bh(&agent->lock);
+ pr_notice("Ignoring ORB_POINTER write while active.\n");
+ return RCODE_CONFLICT_ERROR;
+ }
+ agent->state = AGENT_STATE_ACTIVE;
+ spin_unlock_bh(&agent->lock);
+
+ agent->orb_pointer = sbp2_pointer_to_addr(ptr);
+ agent->doorbell = false;
+
+ pr_debug("tgt_agent ORB_POINTER write: 0x%llx\n",
+ agent->orb_pointer);
+
+ queue_work(system_unbound_wq, &agent->work);
+
+ return RCODE_COMPLETE;
+
+ case TCODE_READ_BLOCK_REQUEST:
+ pr_debug("tgt_agent ORB_POINTER READ\n");
+ spin_lock_bh(&agent->lock);
+ addr_to_sbp2_pointer(agent->orb_pointer, ptr);
+ spin_unlock_bh(&agent->lock);
+ return RCODE_COMPLETE;
+
+ default:
+ return RCODE_TYPE_ERROR;
+ }
+}
+
+static int tgt_agent_rw_doorbell(struct fw_card *card, int tcode, void *data,
+ struct sbp_target_agent *agent)
+{
+ switch (tcode) {
+ case TCODE_WRITE_QUADLET_REQUEST:
+ spin_lock_bh(&agent->lock);
+ if (agent->state != AGENT_STATE_SUSPENDED) {
+ spin_unlock_bh(&agent->lock);
+ pr_debug("Ignoring DOORBELL while active.\n");
+ return RCODE_CONFLICT_ERROR;
+ }
+ agent->state = AGENT_STATE_ACTIVE;
+ spin_unlock_bh(&agent->lock);
+
+ agent->doorbell = true;
+
+ pr_debug("tgt_agent DOORBELL\n");
+
+ queue_work(system_unbound_wq, &agent->work);
+
+ return RCODE_COMPLETE;
+
+ case TCODE_READ_QUADLET_REQUEST:
+ return RCODE_COMPLETE;
+
+ default:
+ return RCODE_TYPE_ERROR;
+ }
+}
+
+static int tgt_agent_rw_unsolicited_status_enable(struct fw_card *card,
+ int tcode, void *data, struct sbp_target_agent *agent)
+{
+ switch (tcode) {
+ case TCODE_WRITE_QUADLET_REQUEST:
+ pr_debug("tgt_agent UNSOLICITED_STATUS_ENABLE\n");
+ /* ignored as we don't send unsolicited status */
+ return RCODE_COMPLETE;
+
+ case TCODE_READ_QUADLET_REQUEST:
+ return RCODE_COMPLETE;
+
+ default:
+ return RCODE_TYPE_ERROR;
+ }
+}
+
+static void tgt_agent_rw(struct fw_card *card, struct fw_request *request,
+ int tcode, int destination, int source, int generation,
+ unsigned long long offset, void *data, size_t length,
+ void *callback_data)
+{
+ struct sbp_target_agent *agent = callback_data;
+ struct sbp_session *sess = agent->login->sess;
+ int sess_gen, sess_node, rcode;
+
+ spin_lock_bh(&sess->lock);
+ sess_gen = sess->generation;
+ sess_node = sess->node_id;
+ spin_unlock_bh(&sess->lock);
+
+ if (generation != sess_gen) {
+ pr_notice("ignoring request with wrong generation\n");
+ rcode = RCODE_TYPE_ERROR;
+ goto out;
+ }
+
+ if (source != sess_node) {
+ pr_notice("ignoring request from foreign node (%x != %x)\n",
+ source, sess_node);
+ rcode = RCODE_TYPE_ERROR;
+ goto out;
+ }
+
+ /* turn offset into the offset from the start of the block */
+ offset -= agent->handler.offset;
+
+ if (offset == 0x00 && length == 4) {
+ /* AGENT_STATE */
+ rcode = tgt_agent_rw_agent_state(card, tcode, data, agent);
+ } else if (offset == 0x04 && length == 4) {
+ /* AGENT_RESET */
+ rcode = tgt_agent_rw_agent_reset(card, tcode, data, agent);
+ } else if (offset == 0x08 && length == 8) {
+ /* ORB_POINTER */
+ rcode = tgt_agent_rw_orb_pointer(card, tcode, data, agent);
+ } else if (offset == 0x10 && length == 4) {
+ /* DOORBELL */
+ rcode = tgt_agent_rw_doorbell(card, tcode, data, agent);
+ } else if (offset == 0x14 && length == 4) {
+ /* UNSOLICITED_STATUS_ENABLE */
+ rcode = tgt_agent_rw_unsolicited_status_enable(card, tcode,
+ data, agent);
+ } else {
+ rcode = RCODE_ADDRESS_ERROR;
+ }
+
+out:
+ fw_send_response(card, request, rcode);
+}
+
+static void sbp_handle_command(struct sbp_target_request *);
+static int sbp_send_status(struct sbp_target_request *);
+static void sbp_free_request(struct sbp_target_request *);
+
+static void tgt_agent_process_work(struct work_struct *work)
+{
+ struct sbp_target_request *req =
+ container_of(work, struct sbp_target_request, work);
+
+ pr_debug("tgt_orb ptr:0x%llx next_ORB:0x%llx data_descriptor:0x%llx misc:0x%x\n",
+ req->orb_pointer,
+ sbp2_pointer_to_addr(&req->orb.next_orb),
+ sbp2_pointer_to_addr(&req->orb.data_descriptor),
+ be32_to_cpu(req->orb.misc));
+
+ if (req->orb_pointer >> 32)
+ pr_debug("ORB with high bits set\n");
+
+ switch (ORB_REQUEST_FORMAT(be32_to_cpu(req->orb.misc))) {
+ case 0:/* Format specified by this standard */
+ sbp_handle_command(req);
+ return;
+ case 1: /* Reserved for future standardization */
+ case 2: /* Vendor-dependent */
+ req->status.status |= cpu_to_be32(
+ STATUS_BLOCK_RESP(
+ STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_DEAD(0) |
+ STATUS_BLOCK_LEN(1) |
+ STATUS_BLOCK_SBP_STATUS(
+ SBP_STATUS_REQ_TYPE_NOTSUPP));
+ sbp_send_status(req);
+ sbp_free_request(req);
+ return;
+ case 3: /* Dummy ORB */
+ req->status.status |= cpu_to_be32(
+ STATUS_BLOCK_RESP(
+ STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_DEAD(0) |
+ STATUS_BLOCK_LEN(1) |
+ STATUS_BLOCK_SBP_STATUS(
+ SBP_STATUS_DUMMY_ORB_COMPLETE));
+ sbp_send_status(req);
+ sbp_free_request(req);
+ return;
+ default:
+ BUG();
+ }
+}
+
+/* used to double-check we haven't been issued an AGENT_RESET */
+static inline bool tgt_agent_check_active(struct sbp_target_agent *agent)
+{
+ bool active;
+
+ spin_lock_bh(&agent->lock);
+ active = (agent->state == AGENT_STATE_ACTIVE);
+ spin_unlock_bh(&agent->lock);
+
+ return active;
+}
+
+static void tgt_agent_fetch_work(struct work_struct *work)
+{
+ struct sbp_target_agent *agent =
+ container_of(work, struct sbp_target_agent, work);
+ struct sbp_session *sess = agent->login->sess;
+ struct sbp_target_request *req;
+ int ret;
+ bool doorbell = agent->doorbell;
+ u64 next_orb = agent->orb_pointer;
+
+ while (next_orb && tgt_agent_check_active(agent)) {
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (!req) {
+ spin_lock_bh(&agent->lock);
+ agent->state = AGENT_STATE_DEAD;
+ spin_unlock_bh(&agent->lock);
+ return;
+ }
+
+ req->login = agent->login;
+ req->orb_pointer = next_orb;
+
+ req->status.status = cpu_to_be32(STATUS_BLOCK_ORB_OFFSET_HIGH(
+ req->orb_pointer >> 32));
+ req->status.orb_low = cpu_to_be32(
+ req->orb_pointer & 0xfffffffc);
+
+ /* read in the ORB */
+ ret = sbp_run_transaction(sess->card, TCODE_READ_BLOCK_REQUEST,
+ sess->node_id, sess->generation, sess->speed,
+ req->orb_pointer, &req->orb, sizeof(req->orb));
+ if (ret != RCODE_COMPLETE) {
+ pr_debug("tgt_orb fetch failed: %x\n", ret);
+ req->status.status |= cpu_to_be32(
+ STATUS_BLOCK_SRC(
+ STATUS_SRC_ORB_FINISHED) |
+ STATUS_BLOCK_RESP(
+ STATUS_RESP_TRANSPORT_FAILURE) |
+ STATUS_BLOCK_DEAD(1) |
+ STATUS_BLOCK_LEN(1) |
+ STATUS_BLOCK_SBP_STATUS(
+ SBP_STATUS_UNSPECIFIED_ERROR));
+ spin_lock_bh(&agent->lock);
+ agent->state = AGENT_STATE_DEAD;
+ spin_unlock_bh(&agent->lock);
+
+ sbp_send_status(req);
+ sbp_free_request(req);
+ return;
+ }
+
+ /* check the next_ORB field */
+ if (be32_to_cpu(req->orb.next_orb.high) & 0x80000000) {
+ next_orb = 0;
+ req->status.status |= cpu_to_be32(STATUS_BLOCK_SRC(
+ STATUS_SRC_ORB_FINISHED));
+ } else {
+ next_orb = sbp2_pointer_to_addr(&req->orb.next_orb);
+ req->status.status |= cpu_to_be32(STATUS_BLOCK_SRC(
+ STATUS_SRC_ORB_CONTINUING));
+ }
+
+ if (tgt_agent_check_active(agent) && !doorbell) {
+ INIT_WORK(&req->work, tgt_agent_process_work);
+ queue_work(system_unbound_wq, &req->work);
+ } else {
+ /* don't process this request, just check next_ORB */
+ sbp_free_request(req);
+ }
+
+ spin_lock_bh(&agent->lock);
+ doorbell = agent->doorbell = false;
+
+ /* check if we should carry on processing */
+ if (next_orb)
+ agent->orb_pointer = next_orb;
+ else
+ agent->state = AGENT_STATE_SUSPENDED;
+
+ spin_unlock_bh(&agent->lock);
+ };
+}
+
+static struct sbp_target_agent *sbp_target_agent_register(
+ struct sbp_login_descriptor *login)
+{
+ struct sbp_target_agent *agent;
+ int ret;
+
+ agent = kmalloc(sizeof(*agent), GFP_KERNEL);
+ if (!agent)
+ return ERR_PTR(-ENOMEM);
+
+ spin_lock_init(&agent->lock);
+
+ agent->handler.length = 0x20;
+ agent->handler.address_callback = tgt_agent_rw;
+ agent->handler.callback_data = agent;
+
+ agent->login = login;
+ agent->state = AGENT_STATE_RESET;
+ INIT_WORK(&agent->work, tgt_agent_fetch_work);
+ agent->orb_pointer = 0;
+ agent->doorbell = false;
+
+ ret = fw_core_add_address_handler(&agent->handler,
+ &sbp_register_region);
+ if (ret < 0) {
+ kfree(agent);
+ return ERR_PTR(ret);
+ }
+
+ return agent;
+}
+
+static void sbp_target_agent_unregister(struct sbp_target_agent *agent)
+{
+ fw_core_remove_address_handler(&agent->handler);
+ cancel_work_sync(&agent->work);
+ kfree(agent);
+}
+
+/*
+ * Simple wrapper around fw_run_transaction that retries the transaction several
+ * times in case of failure, with an exponential backoff.
+ */
+static int sbp_run_transaction(struct fw_card *card, int tcode, int destination_id,
+ int generation, int speed, unsigned long long offset,
+ void *payload, size_t length)
+{
+ int attempt, ret, delay;
+
+ for (attempt = 1; attempt <= 5; attempt++) {
+ ret = fw_run_transaction(card, tcode, destination_id,
+ generation, speed, offset, payload, length);
+
+ switch (ret) {
+ case RCODE_COMPLETE:
+ case RCODE_TYPE_ERROR:
+ case RCODE_ADDRESS_ERROR:
+ case RCODE_GENERATION:
+ return ret;
+
+ default:
+ delay = 5 * attempt * attempt;
+ usleep_range(delay, delay * 2);
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Wrapper around sbp_run_transaction that gets the card, destination,
+ * generation and speed out of the request's session.
+ */
+static int sbp_run_request_transaction(struct sbp_target_request *req,
+ int tcode, unsigned long long offset, void *payload,
+ size_t length)
+{
+ struct sbp_login_descriptor *login = req->login;
+ struct sbp_session *sess = login->sess;
+ struct fw_card *card;
+ int node_id, generation, speed, ret;
+
+ spin_lock_bh(&sess->lock);
+ card = fw_card_get(sess->card);
+ node_id = sess->node_id;
+ generation = sess->generation;
+ speed = sess->speed;
+ spin_unlock_bh(&sess->lock);
+
+ ret = sbp_run_transaction(card, tcode, node_id, generation, speed,
+ offset, payload, length);
+
+ fw_card_put(card);
+
+ return ret;
+}
+
+static int sbp_fetch_command(struct sbp_target_request *req)
+{
+ int ret, cmd_len, copy_len;
+
+ cmd_len = scsi_command_size(req->orb.command_block);
+
+ req->cmd_buf = kmalloc(cmd_len, GFP_KERNEL);
+ if (!req->cmd_buf)
+ return -ENOMEM;
+
+ memcpy(req->cmd_buf, req->orb.command_block,
+ min_t(int, cmd_len, sizeof(req->orb.command_block)));
+
+ if (cmd_len > sizeof(req->orb.command_block)) {
+ pr_debug("sbp_fetch_command: filling in long command\n");
+ copy_len = cmd_len - sizeof(req->orb.command_block);
+
+ ret = sbp_run_request_transaction(req,
+ TCODE_READ_BLOCK_REQUEST,
+ req->orb_pointer + sizeof(req->orb),
+ req->cmd_buf + sizeof(req->orb.command_block),
+ copy_len);
+ if (ret != RCODE_COMPLETE)
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int sbp_fetch_page_table(struct sbp_target_request *req)
+{
+ int pg_tbl_sz, ret;
+ struct sbp_page_table_entry *pg_tbl;
+
+ if (!CMDBLK_ORB_PG_TBL_PRESENT(be32_to_cpu(req->orb.misc)))
+ return 0;
+
+ pg_tbl_sz = CMDBLK_ORB_DATA_SIZE(be32_to_cpu(req->orb.misc)) *
+ sizeof(struct sbp_page_table_entry);
+
+ pg_tbl = kmalloc(pg_tbl_sz, GFP_KERNEL);
+ if (!pg_tbl)
+ return -ENOMEM;
+
+ ret = sbp_run_request_transaction(req, TCODE_READ_BLOCK_REQUEST,
+ sbp2_pointer_to_addr(&req->orb.data_descriptor),
+ pg_tbl, pg_tbl_sz);
+ if (ret != RCODE_COMPLETE) {
+ kfree(pg_tbl);
+ return -EIO;
+ }
+
+ req->pg_tbl = pg_tbl;
+ return 0;
+}
+
+static void sbp_calc_data_length_direction(struct sbp_target_request *req,
+ u32 *data_len, enum dma_data_direction *data_dir)
+{
+ int data_size, direction, idx;
+
+ data_size = CMDBLK_ORB_DATA_SIZE(be32_to_cpu(req->orb.misc));
+ direction = CMDBLK_ORB_DIRECTION(be32_to_cpu(req->orb.misc));
+
+ if (!data_size) {
+ *data_len = 0;
+ *data_dir = DMA_NONE;
+ return;
+ }
+
+ *data_dir = direction ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+ if (req->pg_tbl) {
+ *data_len = 0;
+ for (idx = 0; idx < data_size; idx++) {
+ *data_len += be16_to_cpu(
+ req->pg_tbl[idx].segment_length);
+ }
+ } else {
+ *data_len = data_size;
+ }
+}
+
+static void sbp_handle_command(struct sbp_target_request *req)
+{
+ struct sbp_login_descriptor *login = req->login;
+ struct sbp_session *sess = login->sess;
+ int ret, unpacked_lun;
+ u32 data_length;
+ enum dma_data_direction data_dir;
+
+ ret = sbp_fetch_command(req);
+ if (ret) {
+ pr_debug("sbp_handle_command: fetch command failed: %d\n", ret);
+ req->status.status |= cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+ STATUS_BLOCK_DEAD(0) |
+ STATUS_BLOCK_LEN(1) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+ sbp_send_status(req);
+ sbp_free_request(req);
+ return;
+ }
+
+ ret = sbp_fetch_page_table(req);
+ if (ret) {
+ pr_debug("sbp_handle_command: fetch page table failed: %d\n",
+ ret);
+ req->status.status |= cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+ STATUS_BLOCK_DEAD(0) |
+ STATUS_BLOCK_LEN(1) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+ sbp_send_status(req);
+ sbp_free_request(req);
+ return;
+ }
+
+ unpacked_lun = req->login->lun->unpacked_lun;
+ sbp_calc_data_length_direction(req, &data_length, &data_dir);
+
+ pr_debug("sbp_handle_command ORB:0x%llx unpacked_lun:%d data_len:%d data_dir:%d\n",
+ req->orb_pointer, unpacked_lun, data_length, data_dir);
+
+ target_submit_cmd(&req->se_cmd, sess->se_sess, req->cmd_buf,
+ req->sense_buf, unpacked_lun, data_length,
+ MSG_SIMPLE_TAG, data_dir, 0);
+}
+
+/*
+ * DMA_TO_DEVICE = read from initiator (SCSI WRITE)
+ * DMA_FROM_DEVICE = write to initiator (SCSI READ)
+ */
+static int sbp_rw_data(struct sbp_target_request *req)
+{
+ struct sbp_session *sess = req->login->sess;
+ int tcode, sg_miter_flags, max_payload, pg_size, speed, node_id,
+ generation, num_pte, length, tfr_length,
+ rcode = RCODE_COMPLETE;
+ struct sbp_page_table_entry *pte;
+ unsigned long long offset;
+ struct fw_card *card;
+ struct sg_mapping_iter iter;
+
+ if (req->se_cmd.data_direction == DMA_FROM_DEVICE) {
+ tcode = TCODE_WRITE_BLOCK_REQUEST;
+ sg_miter_flags = SG_MITER_FROM_SG;
+ } else {
+ tcode = TCODE_READ_BLOCK_REQUEST;
+ sg_miter_flags = SG_MITER_TO_SG;
+ }
+
+ max_payload = 4 << CMDBLK_ORB_MAX_PAYLOAD(be32_to_cpu(req->orb.misc));
+ speed = CMDBLK_ORB_SPEED(be32_to_cpu(req->orb.misc));
+
+ pg_size = CMDBLK_ORB_PG_SIZE(be32_to_cpu(req->orb.misc));
+ if (pg_size) {
+ pr_err("sbp_run_transaction: page size ignored\n");
+ pg_size = 0x100 << pg_size;
+ }
+
+ spin_lock_bh(&sess->lock);
+ card = fw_card_get(sess->card);
+ node_id = sess->node_id;
+ generation = sess->generation;
+ spin_unlock_bh(&sess->lock);
+
+ if (req->pg_tbl) {
+ pte = req->pg_tbl;
+ num_pte = CMDBLK_ORB_DATA_SIZE(be32_to_cpu(req->orb.misc));
+
+ offset = 0;
+ length = 0;
+ } else {
+ pte = NULL;
+ num_pte = 0;
+
+ offset = sbp2_pointer_to_addr(&req->orb.data_descriptor);
+ length = req->se_cmd.data_length;
+ }
+
+ sg_miter_start(&iter, req->se_cmd.t_data_sg, req->se_cmd.t_data_nents,
+ sg_miter_flags);
+
+ while (length || num_pte) {
+ if (!length) {
+ offset = (u64)be16_to_cpu(pte->segment_base_hi) << 32 |
+ be32_to_cpu(pte->segment_base_lo);
+ length = be16_to_cpu(pte->segment_length);
+
+ pte++;
+ num_pte--;
+ }
+
+ sg_miter_next(&iter);
+
+ tfr_length = min3(length, max_payload, (int)iter.length);
+
+ /* FIXME: take page_size into account */
+
+ rcode = sbp_run_transaction(card, tcode, node_id,
+ generation, speed,
+ offset, iter.addr, tfr_length);
+
+ if (rcode != RCODE_COMPLETE)
+ break;
+
+ length -= tfr_length;
+ offset += tfr_length;
+ iter.consumed = tfr_length;
+ }
+
+ sg_miter_stop(&iter);
+ fw_card_put(card);
+
+ if (rcode == RCODE_COMPLETE) {
+ WARN_ON(length != 0);
+ return 0;
+ } else {
+ return -EIO;
+ }
+}
+
+static int sbp_send_status(struct sbp_target_request *req)
+{
+ int ret, length;
+ struct sbp_login_descriptor *login = req->login;
+
+ length = (((be32_to_cpu(req->status.status) >> 24) & 0x07) + 1) * 4;
+
+ ret = sbp_run_request_transaction(req, TCODE_WRITE_BLOCK_REQUEST,
+ login->status_fifo_addr, &req->status, length);
+ if (ret != RCODE_COMPLETE) {
+ pr_debug("sbp_send_status: write failed: 0x%x\n", ret);
+ return -EIO;
+ }
+
+ pr_debug("sbp_send_status: status write complete for ORB: 0x%llx\n",
+ req->orb_pointer);
+
+ return 0;
+}
+
+static void sbp_sense_mangle(struct sbp_target_request *req)
+{
+ struct se_cmd *se_cmd = &req->se_cmd;
+ u8 *sense = req->sense_buf;
+ u8 *status = req->status.data;
+
+ WARN_ON(se_cmd->scsi_sense_length < 18);
+
+ switch (sense[0] & 0x7f) { /* sfmt */
+ case 0x70: /* current, fixed */
+ status[0] = 0 << 6;
+ break;
+ case 0x71: /* deferred, fixed */
+ status[0] = 1 << 6;
+ break;
+ case 0x72: /* current, descriptor */
+ case 0x73: /* deferred, descriptor */
+ default:
+ /*
+ * TODO: SBP-3 specifies what we should do with descriptor
+ * format sense data
+ */
+ pr_err("sbp_send_sense: unknown sense format: 0x%x\n",
+ sense[0]);
+ req->status.status |= cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_DEAD(0) |
+ STATUS_BLOCK_LEN(1) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQUEST_ABORTED));
+ return;
+ }
+
+ status[0] |= se_cmd->scsi_status & 0x3f;/* status */
+ status[1] =
+ (sense[0] & 0x80) | /* valid */
+ ((sense[2] & 0xe0) >> 1) | /* mark, eom, ili */
+ (sense[2] & 0x0f); /* sense_key */
+ status[2] = se_cmd->scsi_asc; /* sense_code */
+ status[3] = se_cmd->scsi_ascq; /* sense_qualifier */
+
+ /* information */
+ status[4] = sense[3];
+ status[5] = sense[4];
+ status[6] = sense[5];
+ status[7] = sense[6];
+
+ /* CDB-dependent */
+ status[8] = sense[8];
+ status[9] = sense[9];
+ status[10] = sense[10];
+ status[11] = sense[11];
+
+ /* fru */
+ status[12] = sense[14];
+
+ /* sense_key-dependent */
+ status[13] = sense[15];
+ status[14] = sense[16];
+ status[15] = sense[17];
+
+ req->status.status |= cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_DEAD(0) |
+ STATUS_BLOCK_LEN(5) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+static int sbp_send_sense(struct sbp_target_request *req)
+{
+ struct se_cmd *se_cmd = &req->se_cmd;
+
+ if (se_cmd->scsi_sense_length) {
+ sbp_sense_mangle(req);
+ } else {
+ req->status.status |= cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_DEAD(0) |
+ STATUS_BLOCK_LEN(1) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+ }
+
+ return sbp_send_status(req);
+}
+
+static void sbp_free_request(struct sbp_target_request *req)
+{
+ kfree(req->pg_tbl);
+ kfree(req->cmd_buf);
+ kfree(req);
+}
+
+static void sbp_mgt_agent_process(struct work_struct *work)
+{
+ struct sbp_management_agent *agent =
+ container_of(work, struct sbp_management_agent, work);
+ struct sbp_management_request *req = agent->request;
+ int ret;
+ int status_data_len = 0;
+
+ /* fetch the ORB from the initiator */
+ ret = sbp_run_transaction(req->card, TCODE_READ_BLOCK_REQUEST,
+ req->node_addr, req->generation, req->speed,
+ agent->orb_offset, &req->orb, sizeof(req->orb));
+ if (ret != RCODE_COMPLETE) {
+ pr_debug("mgt_orb fetch failed: %x\n", ret);
+ goto out;
+ }
+
+ pr_debug("mgt_orb ptr1:0x%llx ptr2:0x%llx misc:0x%x len:0x%x status_fifo:0x%llx\n",
+ sbp2_pointer_to_addr(&req->orb.ptr1),
+ sbp2_pointer_to_addr(&req->orb.ptr2),
+ be32_to_cpu(req->orb.misc), be32_to_cpu(req->orb.length),
+ sbp2_pointer_to_addr(&req->orb.status_fifo));
+
+ if (!ORB_NOTIFY(be32_to_cpu(req->orb.misc)) ||
+ ORB_REQUEST_FORMAT(be32_to_cpu(req->orb.misc)) != 0) {
+ pr_err("mgt_orb bad request\n");
+ goto out;
+ }
+
+ switch (MANAGEMENT_ORB_FUNCTION(be32_to_cpu(req->orb.misc))) {
+ case MANAGEMENT_ORB_FUNCTION_LOGIN:
+ sbp_management_request_login(agent, req, &status_data_len);
+ break;
+
+ case MANAGEMENT_ORB_FUNCTION_QUERY_LOGINS:
+ sbp_management_request_query_logins(agent, req,
+ &status_data_len);
+ break;
+
+ case MANAGEMENT_ORB_FUNCTION_RECONNECT:
+ sbp_management_request_reconnect(agent, req, &status_data_len);
+ break;
+
+ case MANAGEMENT_ORB_FUNCTION_SET_PASSWORD:
+ pr_notice("SET PASSWORD not implemented\n");
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+ break;
+
+ case MANAGEMENT_ORB_FUNCTION_LOGOUT:
+ sbp_management_request_logout(agent, req, &status_data_len);
+ break;
+
+ case MANAGEMENT_ORB_FUNCTION_ABORT_TASK:
+ pr_notice("ABORT TASK not implemented\n");
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+ break;
+
+ case MANAGEMENT_ORB_FUNCTION_ABORT_TASK_SET:
+ pr_notice("ABORT TASK SET not implemented\n");
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+ break;
+
+ case MANAGEMENT_ORB_FUNCTION_LOGICAL_UNIT_RESET:
+ pr_notice("LOGICAL UNIT RESET not implemented\n");
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+ break;
+
+ case MANAGEMENT_ORB_FUNCTION_TARGET_RESET:
+ pr_notice("TARGET RESET not implemented\n");
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+ break;
+
+ default:
+ pr_notice("unknown management function 0x%x\n",
+ MANAGEMENT_ORB_FUNCTION(be32_to_cpu(req->orb.misc)));
+
+ req->status.status = cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+ break;
+ }
+
+ req->status.status |= cpu_to_be32(
+ STATUS_BLOCK_SRC(1) | /* Response to ORB, next_ORB absent */
+ STATUS_BLOCK_LEN(DIV_ROUND_UP(status_data_len, 4) + 1) |
+ STATUS_BLOCK_ORB_OFFSET_HIGH(agent->orb_offset >> 32));
+ req->status.orb_low = cpu_to_be32(agent->orb_offset);
+
+ /* write the status block back to the initiator */
+ ret = sbp_run_transaction(req->card, TCODE_WRITE_BLOCK_REQUEST,
+ req->node_addr, req->generation, req->speed,
+ sbp2_pointer_to_addr(&req->orb.status_fifo),
+ &req->status, 8 + status_data_len);
+ if (ret != RCODE_COMPLETE) {
+ pr_debug("mgt_orb status write failed: %x\n", ret);
+ goto out;
+ }
+
+out:
+ fw_card_put(req->card);
+ kfree(req);
+
+ spin_lock_bh(&agent->lock);
+ agent->state = MANAGEMENT_AGENT_STATE_IDLE;
+ spin_unlock_bh(&agent->lock);
+}
+
+static void sbp_mgt_agent_rw(struct fw_card *card,
+ struct fw_request *request, int tcode, int destination, int source,
+ int generation, unsigned long long offset, void *data, size_t length,
+ void *callback_data)
+{
+ struct sbp_management_agent *agent = callback_data;
+ struct sbp2_pointer *ptr = data;
+ int rcode = RCODE_ADDRESS_ERROR;
+
+ if (!agent->tport->enable)
+ goto out;
+
+ if ((offset != agent->handler.offset) || (length != 8))
+ goto out;
+
+ if (tcode == TCODE_WRITE_BLOCK_REQUEST) {
+ struct sbp_management_request *req;
+ int prev_state;
+
+ spin_lock_bh(&agent->lock);
+ prev_state = agent->state;
+ agent->state = MANAGEMENT_AGENT_STATE_BUSY;
+ spin_unlock_bh(&agent->lock);
+
+ if (prev_state == MANAGEMENT_AGENT_STATE_BUSY) {
+ pr_notice("ignoring management request while busy\n");
+ rcode = RCODE_CONFLICT_ERROR;
+ goto out;
+ }
+
+ req = kzalloc(sizeof(*req), GFP_ATOMIC);
+ if (!req) {
+ rcode = RCODE_CONFLICT_ERROR;
+ goto out;
+ }
+
+ req->card = fw_card_get(card);
+ req->generation = generation;
+ req->node_addr = source;
+ req->speed = fw_get_request_speed(request);
+
+ agent->orb_offset = sbp2_pointer_to_addr(ptr);
+ agent->request = req;
+
+ queue_work(system_unbound_wq, &agent->work);
+ rcode = RCODE_COMPLETE;
+ } else if (tcode == TCODE_READ_BLOCK_REQUEST) {
+ addr_to_sbp2_pointer(agent->orb_offset, ptr);
+ rcode = RCODE_COMPLETE;
+ } else {
+ rcode = RCODE_TYPE_ERROR;
+ }
+
+out:
+ fw_send_response(card, request, rcode);
+}
+
+static struct sbp_management_agent *sbp_management_agent_register(
+ struct sbp_tport *tport)
+{
+ int ret;
+ struct sbp_management_agent *agent;
+
+ agent = kmalloc(sizeof(*agent), GFP_KERNEL);
+ if (!agent)
+ return ERR_PTR(-ENOMEM);
+
+ spin_lock_init(&agent->lock);
+ agent->tport = tport;
+ agent->handler.length = 0x08;
+ agent->handler.address_callback = sbp_mgt_agent_rw;
+ agent->handler.callback_data = agent;
+ agent->state = MANAGEMENT_AGENT_STATE_IDLE;
+ INIT_WORK(&agent->work, sbp_mgt_agent_process);
+ agent->orb_offset = 0;
+ agent->request = NULL;
+
+ ret = fw_core_add_address_handler(&agent->handler,
+ &sbp_register_region);
+ if (ret < 0) {
+ kfree(agent);
+ return ERR_PTR(ret);
+ }
+
+ return agent;
+}
+
+static void sbp_management_agent_unregister(struct sbp_management_agent *agent)
+{
+ fw_core_remove_address_handler(&agent->handler);
+ cancel_work_sync(&agent->work);
+ kfree(agent);
+}
+
+static int sbp_check_true(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static int sbp_check_false(struct se_portal_group *se_tpg)
+{
+ return 0;
+}
+
+static char *sbp_get_fabric_name(void)
+{
+ return "sbp";
+}
+
+static char *sbp_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+
+ return &tport->tport_name[0];
+}
+
+static u16 sbp_get_tag(struct se_portal_group *se_tpg)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ return tpg->tport_tpgt;
+}
+
+static u32 sbp_get_default_depth(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static struct se_node_acl *sbp_alloc_fabric_acl(struct se_portal_group *se_tpg)
+{
+ struct sbp_nacl *nacl;
+
+ nacl = kzalloc(sizeof(struct sbp_nacl), GFP_KERNEL);
+ if (!nacl) {
+ pr_err("Unable to alocate struct sbp_nacl\n");
+ return NULL;
+ }
+
+ return &nacl->se_node_acl;
+}
+
+static void sbp_release_fabric_acl(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl)
+{
+ struct sbp_nacl *nacl =
+ container_of(se_nacl, struct sbp_nacl, se_node_acl);
+ kfree(nacl);
+}
+
+static u32 sbp_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+ return 1;
+}
+
+static void sbp_release_cmd(struct se_cmd *se_cmd)
+{
+ struct sbp_target_request *req = container_of(se_cmd,
+ struct sbp_target_request, se_cmd);
+
+ sbp_free_request(req);
+}
+
+static int sbp_shutdown_session(struct se_session *se_sess)
+{
+ return 0;
+}
+
+static void sbp_close_session(struct se_session *se_sess)
+{
+ return;
+}
+
+static u32 sbp_sess_get_index(struct se_session *se_sess)
+{
+ return 0;
+}
+
+static int sbp_write_pending(struct se_cmd *se_cmd)
+{
+ struct sbp_target_request *req = container_of(se_cmd,
+ struct sbp_target_request, se_cmd);
+ int ret;
+
+ ret = sbp_rw_data(req);
+ if (ret) {
+ req->status.status |= cpu_to_be32(
+ STATUS_BLOCK_RESP(
+ STATUS_RESP_TRANSPORT_FAILURE) |
+ STATUS_BLOCK_DEAD(0) |
+ STATUS_BLOCK_LEN(1) |
+ STATUS_BLOCK_SBP_STATUS(
+ SBP_STATUS_UNSPECIFIED_ERROR));
+ sbp_send_status(req);
+ return ret;
+ }
+
+ transport_generic_process_write(se_cmd);
+
+ return 0;
+}
+
+static int sbp_write_pending_status(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static void sbp_set_default_node_attrs(struct se_node_acl *nacl)
+{
+ return;
+}
+
+static u32 sbp_get_task_tag(struct se_cmd *se_cmd)
+{
+ struct sbp_target_request *req = container_of(se_cmd,
+ struct sbp_target_request, se_cmd);
+
+ /* only used for printk until we do TMRs */
+ return (u32)req->orb_pointer;
+}
+
+static int sbp_get_cmd_state(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static int sbp_queue_data_in(struct se_cmd *se_cmd)
+{
+ struct sbp_target_request *req = container_of(se_cmd,
+ struct sbp_target_request, se_cmd);
+ int ret;
+
+ ret = sbp_rw_data(req);
+ if (ret) {
+ req->status.status |= cpu_to_be32(
+ STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+ STATUS_BLOCK_DEAD(0) |
+ STATUS_BLOCK_LEN(1) |
+ STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+ sbp_send_status(req);
+ return ret;
+ }
+
+ return sbp_send_sense(req);
+}
+
+/*
+ * Called after command (no data transfer) or after the write (to device)
+ * operation is completed
+ */
+static int sbp_queue_status(struct se_cmd *se_cmd)
+{
+ struct sbp_target_request *req = container_of(se_cmd,
+ struct sbp_target_request, se_cmd);
+
+ return sbp_send_sense(req);
+}
+
+static int sbp_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+ return 0;
+}
+
+static u16 sbp_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
+{
+ return 0;
+}
+
+static u16 sbp_get_fabric_sense_len(void)
+{
+ return 0;
+}
+
+static int sbp_check_stop_free(struct se_cmd *se_cmd)
+{
+ struct sbp_target_request *req = container_of(se_cmd,
+ struct sbp_target_request, se_cmd);
+
+ transport_generic_free_cmd(&req->se_cmd, 0);
+ return 1;
+}
+
+/*
+ * Handlers for Serial Bus Protocol 2/3 (SBP-2 / SBP-3)
+ */
+static u8 sbp_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+ /*
+ * Return a IEEE 1394 SCSI Protocol identifier for loopback operations
+ * This is defined in section 7.5.1 Table 362 in spc4r17
+ */
+ return SCSI_PROTOCOL_SBP;
+}
+
+static u32 sbp_get_pr_transport_id(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code,
+ unsigned char *buf)
+{
+ int ret;
+
+ /*
+ * Set PROTOCOL IDENTIFIER to 3h for SBP
+ */
+ buf[0] = SCSI_PROTOCOL_SBP;
+ /*
+ * From spc4r17, 7.5.4.4 TransportID for initiator ports using SCSI
+ * over IEEE 1394
+ */
+ ret = hex2bin(&buf[8], se_nacl->initiatorname, 8);
+ if (ret < 0)
+ pr_debug("sbp transport_id: invalid hex string\n");
+
+ /*
+ * The IEEE 1394 Transport ID is a hardcoded 24-byte length
+ */
+ return 24;
+}
+
+static u32 sbp_get_pr_transport_id_len(
+ struct se_portal_group *se_tpg,
+ struct se_node_acl *se_nacl,
+ struct t10_pr_registration *pr_reg,
+ int *format_code)
+{
+ *format_code = 0;
+ /*
+ * From spc4r17, 7.5.4.4 TransportID for initiator ports using SCSI
+ * over IEEE 1394
+ *
+ * The SBP Transport ID is a hardcoded 24-byte length
+ */
+ return 24;
+}
+
+/*
+ * Used for handling SCSI fabric dependent TransportIDs in SPC-3 and above
+ * Persistent Reservation SPEC_I_PT=1 and PROUT REGISTER_AND_MOVE operations.
+ */
+static char *sbp_parse_pr_out_transport_id(
+ struct se_portal_group *se_tpg,
+ const char *buf,
+ u32 *out_tid_len,
+ char **port_nexus_ptr)
+{
+ /*
+ * Assume the FORMAT CODE 00b from spc4r17, 7.5.4.4 TransportID
+ * for initiator ports using SCSI over SBP Serial SCSI Protocol
+ *
+ * The TransportID for a IEEE 1394 Initiator Port is of fixed size of
+ * 24 bytes, and IEEE 1394 does not contain a I_T nexus identifier,
+ * so we return the **port_nexus_ptr set to NULL.
+ */
+ *port_nexus_ptr = NULL;
+ *out_tid_len = 24;
+
+ return (char *)&buf[8];
+}
+
+static int sbp_count_se_tpg_luns(struct se_portal_group *tpg)
+{
+ int i, count = 0;
+
+ spin_lock(&tpg->tpg_lun_lock);
+ for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+ struct se_lun *se_lun = tpg->tpg_lun_list[i];
+
+ if (se_lun->lun_status == TRANSPORT_LUN_STATUS_FREE)
+ continue;
+
+ count++;
+ }
+ spin_unlock(&tpg->tpg_lun_lock);
+
+ return count;
+}
+
+static int sbp_update_unit_directory(struct sbp_tport *tport)
+{
+ int num_luns, num_entries, idx = 0, mgt_agt_addr, ret, i;
+ u32 *data;
+
+ if (tport->unit_directory.data) {
+ fw_core_remove_descriptor(&tport->unit_directory);
+ kfree(tport->unit_directory.data);
+ tport->unit_directory.data = NULL;
+ }
+
+ if (!tport->enable || !tport->tpg)
+ return 0;
+
+ num_luns = sbp_count_se_tpg_luns(&tport->tpg->se_tpg);
+
+ /*
+ * Number of entries in the final unit directory:
+ * - all of those in the template
+ * - management_agent
+ * - unit_characteristics
+ * - reconnect_timeout
+ * - unit unique ID
+ * - one for each LUN
+ *
+ * MUST NOT include leaf or sub-directory entries
+ */
+ num_entries = ARRAY_SIZE(sbp_unit_directory_template) + 4 + num_luns;
+
+ if (tport->directory_id != -1)
+ num_entries++;
+
+ /* allocate num_entries + 4 for the header and unique ID leaf */
+ data = kcalloc((num_entries + 4), sizeof(u32), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ /* directory_length */
+ data[idx++] = num_entries << 16;
+
+ /* directory_id */
+ if (tport->directory_id != -1)
+ data[idx++] = (CSR_DIRECTORY_ID << 24) | tport->directory_id;
+
+ /* unit directory template */
+ memcpy(&data[idx], sbp_unit_directory_template,
+ sizeof(sbp_unit_directory_template));
+ idx += ARRAY_SIZE(sbp_unit_directory_template);
+
+ /* management_agent */
+ mgt_agt_addr = (tport->mgt_agt->handler.offset - CSR_REGISTER_BASE) / 4;
+ data[idx++] = 0x54000000 | (mgt_agt_addr & 0x00ffffff);
+
+ /* unit_characteristics */
+ data[idx++] = 0x3a000000 |
+ (((tport->mgt_orb_timeout * 2) << 8) & 0xff00) |
+ SBP_ORB_FETCH_SIZE;
+
+ /* reconnect_timeout */
+ data[idx++] = 0x3d000000 | (tport->max_reconnect_timeout & 0xffff);
+
+ /* unit unique ID (leaf is just after LUNs) */
+ data[idx++] = 0x8d000000 | (num_luns + 1);
+
+ spin_lock(&tport->tpg->se_tpg.tpg_lun_lock);
+ for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+ struct se_lun *se_lun = tport->tpg->se_tpg.tpg_lun_list[i];
+ struct se_device *dev;
+ int type;
+
+ if (se_lun->lun_status == TRANSPORT_LUN_STATUS_FREE)
+ continue;
+
+ spin_unlock(&tport->tpg->se_tpg.tpg_lun_lock);
+
+ dev = se_lun->lun_se_dev;
+ type = dev->transport->get_device_type(dev);
+
+ /* logical_unit_number */
+ data[idx++] = 0x14000000 |
+ ((type << 16) & 0x1f0000) |
+ (se_lun->unpacked_lun & 0xffff);
+
+ spin_lock(&tport->tpg->se_tpg.tpg_lun_lock);
+ }
+ spin_unlock(&tport->tpg->se_tpg.tpg_lun_lock);
+
+ /* unit unique ID leaf */
+ data[idx++] = 2 << 16;
+ data[idx++] = tport->guid >> 32;
+ data[idx++] = tport->guid;
+
+ tport->unit_directory.length = idx;
+ tport->unit_directory.key = (CSR_DIRECTORY | CSR_UNIT) << 24;
+ tport->unit_directory.data = data;
+
+ ret = fw_core_add_descriptor(&tport->unit_directory);
+ if (ret < 0) {
+ kfree(tport->unit_directory.data);
+ tport->unit_directory.data = NULL;
+ }
+
+ return ret;
+}
+
+static ssize_t sbp_parse_wwn(const char *name, u64 *wwn, int strict)
+{
+ const char *cp;
+ char c, nibble;
+ int pos = 0, err;
+
+ *wwn = 0;
+ for (cp = name; cp < &name[SBP_NAMELEN - 1]; cp++) {
+ c = *cp;
+ if (c == '\n' && cp[1] == '\0')
+ continue;
+ if (c == '\0') {
+ err = 2;
+ if (pos != 16)
+ goto fail;
+ return cp - name;
+ }
+ err = 3;
+ if (isdigit(c))
+ nibble = c - '0';
+ else if (isxdigit(c) && (islower(c) || !strict))
+ nibble = tolower(c) - 'a' + 10;
+ else
+ goto fail;
+ *wwn = (*wwn << 4) | nibble;
+ pos++;
+ }
+ err = 4;
+fail:
+ printk(KERN_INFO "err %u len %zu pos %u\n",
+ err, cp - name, pos);
+ return -1;
+}
+
+static ssize_t sbp_format_wwn(char *buf, size_t len, u64 wwn)
+{
+ return snprintf(buf, len, "%016llx", wwn);
+}
+
+static struct se_node_acl *sbp_make_nodeacl(
+ struct se_portal_group *se_tpg,
+ struct config_group *group,
+ const char *name)
+{
+ struct se_node_acl *se_nacl, *se_nacl_new;
+ struct sbp_nacl *nacl;
+ u64 guid = 0;
+ u32 nexus_depth = 1;
+
+ if (sbp_parse_wwn(name, &guid, 1) < 0)
+ return ERR_PTR(-EINVAL);
+
+ se_nacl_new = sbp_alloc_fabric_acl(se_tpg);
+ if (!se_nacl_new)
+ return ERR_PTR(-ENOMEM);
+
+ /*
+ * se_nacl_new may be released by core_tpg_add_initiator_node_acl()
+ * when converting a NodeACL from demo mode -> explict
+ */
+ se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,
+ name, nexus_depth);
+ if (IS_ERR(se_nacl)) {
+ sbp_release_fabric_acl(se_tpg, se_nacl_new);
+ return se_nacl;
+ }
+
+ nacl = container_of(se_nacl, struct sbp_nacl, se_node_acl);
+ nacl->guid = guid;
+ sbp_format_wwn(nacl->iport_name, SBP_NAMELEN, guid);
+
+ return se_nacl;
+}
+
+static void sbp_drop_nodeacl(struct se_node_acl *se_acl)
+{
+ struct sbp_nacl *nacl =
+ container_of(se_acl, struct sbp_nacl, se_node_acl);
+
+ core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1);
+ kfree(nacl);
+}
+
+static int sbp_post_link_lun(
+ struct se_portal_group *se_tpg,
+ struct se_lun *se_lun)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+
+ return sbp_update_unit_directory(tpg->tport);
+}
+
+static void sbp_pre_unlink_lun(
+ struct se_portal_group *se_tpg,
+ struct se_lun *se_lun)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+ int ret;
+
+ if (sbp_count_se_tpg_luns(&tpg->se_tpg) == 0)
+ tport->enable = 0;
+
+ ret = sbp_update_unit_directory(tport);
+ if (ret < 0)
+ pr_err("unlink LUN: failed to update unit directory\n");
+}
+
+static struct se_portal_group *sbp_make_tpg(
+ struct se_wwn *wwn,
+ struct config_group *group,
+ const char *name)
+{
+ struct sbp_tport *tport =
+ container_of(wwn, struct sbp_tport, tport_wwn);
+
+ struct sbp_tpg *tpg;
+ unsigned long tpgt;
+ int ret;
+
+ if (strstr(name, "tpgt_") != name)
+ return ERR_PTR(-EINVAL);
+ if (kstrtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX)
+ return ERR_PTR(-EINVAL);
+
+ if (tport->tpg) {
+ pr_err("Only one TPG per Unit is possible.\n");
+ return ERR_PTR(-EBUSY);
+ }
+
+ tpg = kzalloc(sizeof(*tpg), GFP_KERNEL);
+ if (!tpg) {
+ pr_err("Unable to allocate struct sbp_tpg\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ tpg->tport = tport;
+ tpg->tport_tpgt = tpgt;
+ tport->tpg = tpg;
+
+ /* default attribute values */
+ tport->enable = 0;
+ tport->directory_id = -1;
+ tport->mgt_orb_timeout = 15;
+ tport->max_reconnect_timeout = 5;
+ tport->max_logins_per_lun = 1;
+
+ tport->mgt_agt = sbp_management_agent_register(tport);
+ if (IS_ERR(tport->mgt_agt)) {
+ ret = PTR_ERR(tport->mgt_agt);
+ kfree(tpg);
+ return ERR_PTR(ret);
+ }
+
+ ret = core_tpg_register(&sbp_fabric_configfs->tf_ops, wwn,
+ &tpg->se_tpg, (void *)tpg,
+ TRANSPORT_TPG_TYPE_NORMAL);
+ if (ret < 0) {
+ sbp_management_agent_unregister(tport->mgt_agt);
+ kfree(tpg);
+ return ERR_PTR(ret);
+ }
+
+ return &tpg->se_tpg;
+}
+
+static void sbp_drop_tpg(struct se_portal_group *se_tpg)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+
+ core_tpg_deregister(se_tpg);
+ sbp_management_agent_unregister(tport->mgt_agt);
+ tport->tpg = NULL;
+ kfree(tpg);
+}
+
+static struct se_wwn *sbp_make_tport(
+ struct target_fabric_configfs *tf,
+ struct config_group *group,
+ const char *name)
+{
+ struct sbp_tport *tport;
+ u64 guid = 0;
+
+ if (sbp_parse_wwn(name, &guid, 1) < 0)
+ return ERR_PTR(-EINVAL);
+
+ tport = kzalloc(sizeof(*tport), GFP_KERNEL);
+ if (!tport) {
+ pr_err("Unable to allocate struct sbp_tport\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ tport->guid = guid;
+ sbp_format_wwn(tport->tport_name, SBP_NAMELEN, guid);
+
+ return &tport->tport_wwn;
+}
+
+static void sbp_drop_tport(struct se_wwn *wwn)
+{
+ struct sbp_tport *tport =
+ container_of(wwn, struct sbp_tport, tport_wwn);
+
+ kfree(tport);
+}
+
+static ssize_t sbp_wwn_show_attr_version(
+ struct target_fabric_configfs *tf,
+ char *page)
+{
+ return sprintf(page, "FireWire SBP fabric module %s\n", SBP_VERSION);
+}
+
+TF_WWN_ATTR_RO(sbp, version);
+
+static struct configfs_attribute *sbp_wwn_attrs[] = {
+ &sbp_wwn_version.attr,
+ NULL,
+};
+
+static ssize_t sbp_tpg_show_directory_id(
+ struct se_portal_group *se_tpg,
+ char *page)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+
+ if (tport->directory_id == -1)
+ return sprintf(page, "implicit\n");
+ else
+ return sprintf(page, "%06x\n", tport->directory_id);
+}
+
+static ssize_t sbp_tpg_store_directory_id(
+ struct se_portal_group *se_tpg,
+ const char *page,
+ size_t count)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+ unsigned long val;
+
+ if (tport->enable) {
+ pr_err("Cannot change the directory_id on an active target.\n");
+ return -EBUSY;
+ }
+
+ if (strstr(page, "implicit") == page) {
+ tport->directory_id = -1;
+ } else {
+ if (kstrtoul(page, 16, &val) < 0)
+ return -EINVAL;
+ if (val > 0xffffff)
+ return -EINVAL;
+
+ tport->directory_id = val;
+ }
+
+ return count;
+}
+
+static ssize_t sbp_tpg_show_enable(
+ struct se_portal_group *se_tpg,
+ char *page)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+ return sprintf(page, "%d\n", tport->enable);
+}
+
+static ssize_t sbp_tpg_store_enable(
+ struct se_portal_group *se_tpg,
+ const char *page,
+ size_t count)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+ unsigned long val;
+ int ret;
+
+ if (kstrtoul(page, 0, &val) < 0)
+ return -EINVAL;
+ if ((val != 0) && (val != 1))
+ return -EINVAL;
+
+ if (tport->enable == val)
+ return count;
+
+ if (val) {
+ if (sbp_count_se_tpg_luns(&tpg->se_tpg) == 0) {
+ pr_err("Cannot enable a target with no LUNs!\n");
+ return -EINVAL;
+ }
+ } else {
+ /* XXX: force-shutdown sessions instead? */
+ spin_lock_bh(&se_tpg->session_lock);
+ if (!list_empty(&se_tpg->tpg_sess_list)) {
+ spin_unlock_bh(&se_tpg->session_lock);
+ return -EBUSY;
+ }
+ spin_unlock_bh(&se_tpg->session_lock);
+ }
+
+ tport->enable = val;
+
+ ret = sbp_update_unit_directory(tport);
+ if (ret < 0) {
+ pr_err("Could not update Config ROM\n");
+ return ret;
+ }
+
+ return count;
+}
+
+TF_TPG_BASE_ATTR(sbp, directory_id, S_IRUGO | S_IWUSR);
+TF_TPG_BASE_ATTR(sbp, enable, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *sbp_tpg_base_attrs[] = {
+ &sbp_tpg_directory_id.attr,
+ &sbp_tpg_enable.attr,
+ NULL,
+};
+
+static ssize_t sbp_tpg_attrib_show_mgt_orb_timeout(
+ struct se_portal_group *se_tpg,
+ char *page)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+ return sprintf(page, "%d\n", tport->mgt_orb_timeout);
+}
+
+static ssize_t sbp_tpg_attrib_store_mgt_orb_timeout(
+ struct se_portal_group *se_tpg,
+ const char *page,
+ size_t count)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+ unsigned long val;
+ int ret;
+
+ if (kstrtoul(page, 0, &val) < 0)
+ return -EINVAL;
+ if ((val < 1) || (val > 127))
+ return -EINVAL;
+
+ if (tport->mgt_orb_timeout == val)
+ return count;
+
+ tport->mgt_orb_timeout = val;
+
+ ret = sbp_update_unit_directory(tport);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static ssize_t sbp_tpg_attrib_show_max_reconnect_timeout(
+ struct se_portal_group *se_tpg,
+ char *page)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+ return sprintf(page, "%d\n", tport->max_reconnect_timeout);
+}
+
+static ssize_t sbp_tpg_attrib_store_max_reconnect_timeout(
+ struct se_portal_group *se_tpg,
+ const char *page,
+ size_t count)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+ unsigned long val;
+ int ret;
+
+ if (kstrtoul(page, 0, &val) < 0)
+ return -EINVAL;
+ if ((val < 1) || (val > 32767))
+ return -EINVAL;
+
+ if (tport->max_reconnect_timeout == val)
+ return count;
+
+ tport->max_reconnect_timeout = val;
+
+ ret = sbp_update_unit_directory(tport);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static ssize_t sbp_tpg_attrib_show_max_logins_per_lun(
+ struct se_portal_group *se_tpg,
+ char *page)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+ return sprintf(page, "%d\n", tport->max_logins_per_lun);
+}
+
+static ssize_t sbp_tpg_attrib_store_max_logins_per_lun(
+ struct se_portal_group *se_tpg,
+ const char *page,
+ size_t count)
+{
+ struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+ struct sbp_tport *tport = tpg->tport;
+ unsigned long val;
+
+ if (kstrtoul(page, 0, &val) < 0)
+ return -EINVAL;
+ if ((val < 1) || (val > 127))
+ return -EINVAL;
+
+ /* XXX: also check against current count? */
+
+ tport->max_logins_per_lun = val;
+
+ return count;
+}
+
+TF_TPG_ATTRIB_ATTR(sbp, mgt_orb_timeout, S_IRUGO | S_IWUSR);
+TF_TPG_ATTRIB_ATTR(sbp, max_reconnect_timeout, S_IRUGO | S_IWUSR);
+TF_TPG_ATTRIB_ATTR(sbp, max_logins_per_lun, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *sbp_tpg_attrib_attrs[] = {
+ &sbp_tpg_attrib_mgt_orb_timeout.attr,
+ &sbp_tpg_attrib_max_reconnect_timeout.attr,
+ &sbp_tpg_attrib_max_logins_per_lun.attr,
+ NULL,
+};
+
+static struct target_core_fabric_ops sbp_ops = {
+ .get_fabric_name = sbp_get_fabric_name,
+ .get_fabric_proto_ident = sbp_get_fabric_proto_ident,
+ .tpg_get_wwn = sbp_get_fabric_wwn,
+ .tpg_get_tag = sbp_get_tag,
+ .tpg_get_default_depth = sbp_get_default_depth,
+ .tpg_get_pr_transport_id = sbp_get_pr_transport_id,
+ .tpg_get_pr_transport_id_len = sbp_get_pr_transport_id_len,
+ .tpg_parse_pr_out_transport_id = sbp_parse_pr_out_transport_id,
+ .tpg_check_demo_mode = sbp_check_true,
+ .tpg_check_demo_mode_cache = sbp_check_true,
+ .tpg_check_demo_mode_write_protect = sbp_check_false,
+ .tpg_check_prod_mode_write_protect = sbp_check_false,
+ .tpg_alloc_fabric_acl = sbp_alloc_fabric_acl,
+ .tpg_release_fabric_acl = sbp_release_fabric_acl,
+ .tpg_get_inst_index = sbp_tpg_get_inst_index,
+ .release_cmd = sbp_release_cmd,
+ .shutdown_session = sbp_shutdown_session,
+ .close_session = sbp_close_session,
+ .sess_get_index = sbp_sess_get_index,
+ .write_pending = sbp_write_pending,
+ .write_pending_status = sbp_write_pending_status,
+ .set_default_node_attributes = sbp_set_default_node_attrs,
+ .get_task_tag = sbp_get_task_tag,
+ .get_cmd_state = sbp_get_cmd_state,
+ .queue_data_in = sbp_queue_data_in,
+ .queue_status = sbp_queue_status,
+ .queue_tm_rsp = sbp_queue_tm_rsp,
+ .get_fabric_sense_len = sbp_get_fabric_sense_len,
+ .set_fabric_sense_len = sbp_set_fabric_sense_len,
+ .check_stop_free = sbp_check_stop_free,
+
+ .fabric_make_wwn = sbp_make_tport,
+ .fabric_drop_wwn = sbp_drop_tport,
+ .fabric_make_tpg = sbp_make_tpg,
+ .fabric_drop_tpg = sbp_drop_tpg,
+ .fabric_post_link = sbp_post_link_lun,
+ .fabric_pre_unlink = sbp_pre_unlink_lun,
+ .fabric_make_np = NULL,
+ .fabric_drop_np = NULL,
+ .fabric_make_nodeacl = sbp_make_nodeacl,
+ .fabric_drop_nodeacl = sbp_drop_nodeacl,
+};
+
+static int sbp_register_configfs(void)
+{
+ struct target_fabric_configfs *fabric;
+ int ret;
+
+ fabric = target_fabric_configfs_init(THIS_MODULE, "sbp");
+ if (!fabric) {
+ pr_err("target_fabric_configfs_init() failed\n");
+ return -ENOMEM;
+ }
+
+ fabric->tf_ops = sbp_ops;
+
+ /*
+ * Setup default attribute lists for various fabric->tf_cit_tmpl
+ */
+ TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = sbp_wwn_attrs;
+ TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = sbp_tpg_base_attrs;
+ TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = sbp_tpg_attrib_attrs;
+ TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
+ TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;
+
+ ret = target_fabric_configfs_register(fabric);
+ if (ret < 0) {
+ pr_err("target_fabric_configfs_register() failed for SBP\n");
+ return ret;
+ }
+
+ sbp_fabric_configfs = fabric;
+
+ return 0;
+};
+
+static void sbp_deregister_configfs(void)
+{
+ if (!sbp_fabric_configfs)
+ return;
+
+ target_fabric_configfs_deregister(sbp_fabric_configfs);
+ sbp_fabric_configfs = NULL;
+};
+
+static int __init sbp_init(void)
+{
+ int ret;
+
+ ret = sbp_register_configfs();
+ if (ret < 0)
+ return ret;
+
+ return 0;
+};
+
+static void sbp_exit(void)
+{
+ sbp_deregister_configfs();
+};
+
+MODULE_DESCRIPTION("FireWire SBP fabric driver");
+MODULE_LICENSE("GPL");
+module_init(sbp_init);
+module_exit(sbp_exit);
diff --git a/drivers/target/sbp/sbp_target.h b/drivers/target/sbp/sbp_target.h
new file mode 100644
index 000000000000..6d0d74a2c545
--- /dev/null
+++ b/drivers/target/sbp/sbp_target.h
@@ -0,0 +1,251 @@
+#ifndef _SBP_BASE_H
+#define _SBP_BASE_H
+
+#include <linux/firewire.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include <target/target_core_base.h>
+
+#define SBP_VERSION "v0.1"
+#define SBP_NAMELEN 32
+
+#define SBP_ORB_FETCH_SIZE 8
+
+#define MANAGEMENT_AGENT_STATE_IDLE 0
+#define MANAGEMENT_AGENT_STATE_BUSY 1
+
+#define ORB_NOTIFY(v) (((v) >> 31) & 0x01)
+#define ORB_REQUEST_FORMAT(v) (((v) >> 29) & 0x03)
+
+#define MANAGEMENT_ORB_FUNCTION(v) (((v) >> 16) & 0x0f)
+
+#define MANAGEMENT_ORB_FUNCTION_LOGIN 0x0
+#define MANAGEMENT_ORB_FUNCTION_QUERY_LOGINS 0x1
+#define MANAGEMENT_ORB_FUNCTION_RECONNECT 0x3
+#define MANAGEMENT_ORB_FUNCTION_SET_PASSWORD 0x4
+#define MANAGEMENT_ORB_FUNCTION_LOGOUT 0x7
+#define MANAGEMENT_ORB_FUNCTION_ABORT_TASK 0xb
+#define MANAGEMENT_ORB_FUNCTION_ABORT_TASK_SET 0xc
+#define MANAGEMENT_ORB_FUNCTION_LOGICAL_UNIT_RESET 0xe
+#define MANAGEMENT_ORB_FUNCTION_TARGET_RESET 0xf
+
+#define LOGIN_ORB_EXCLUSIVE(v) (((v) >> 28) & 0x01)
+#define LOGIN_ORB_RESERVED(v) (((v) >> 24) & 0x0f)
+#define LOGIN_ORB_RECONNECT(v) (((v) >> 20) & 0x0f)
+#define LOGIN_ORB_LUN(v) (((v) >> 0) & 0xffff)
+#define LOGIN_ORB_PASSWORD_LENGTH(v) (((v) >> 16) & 0xffff)
+#define LOGIN_ORB_RESPONSE_LENGTH(v) (((v) >> 0) & 0xffff)
+
+#define RECONNECT_ORB_LOGIN_ID(v) (((v) >> 0) & 0xffff)
+#define LOGOUT_ORB_LOGIN_ID(v) (((v) >> 0) & 0xffff)
+
+#define CMDBLK_ORB_DIRECTION(v) (((v) >> 27) & 0x01)
+#define CMDBLK_ORB_SPEED(v) (((v) >> 24) & 0x07)
+#define CMDBLK_ORB_MAX_PAYLOAD(v) (((v) >> 20) & 0x0f)
+#define CMDBLK_ORB_PG_TBL_PRESENT(v) (((v) >> 19) & 0x01)
+#define CMDBLK_ORB_PG_SIZE(v) (((v) >> 16) & 0x07)
+#define CMDBLK_ORB_DATA_SIZE(v) (((v) >> 0) & 0xffff)
+
+#define STATUS_BLOCK_SRC(v) (((v) & 0x03) << 30)
+#define STATUS_BLOCK_RESP(v) (((v) & 0x03) << 28)
+#define STATUS_BLOCK_DEAD(v) (((v) ? 1 : 0) << 27)
+#define STATUS_BLOCK_LEN(v) (((v) & 0x07) << 24)
+#define STATUS_BLOCK_SBP_STATUS(v) (((v) & 0xff) << 16)
+#define STATUS_BLOCK_ORB_OFFSET_HIGH(v) (((v) & 0xffff) << 0)
+
+#define STATUS_SRC_ORB_CONTINUING 0
+#define STATUS_SRC_ORB_FINISHED 1
+#define STATUS_SRC_UNSOLICITED 2
+
+#define STATUS_RESP_REQUEST_COMPLETE 0
+#define STATUS_RESP_TRANSPORT_FAILURE 1
+#define STATUS_RESP_ILLEGAL_REQUEST 2
+#define STATUS_RESP_VENDOR_DEPENDENT 3
+
+#define SBP_STATUS_OK 0
+#define SBP_STATUS_REQ_TYPE_NOTSUPP 1
+#define SBP_STATUS_SPEED_NOTSUPP 2
+#define SBP_STATUS_PAGE_SIZE_NOTSUPP 3
+#define SBP_STATUS_ACCESS_DENIED 4
+#define SBP_STATUS_LUN_NOTSUPP 5
+#define SBP_STATUS_PAYLOAD_TOO_SMALL 6
+/* 7 is reserved */
+#define SBP_STATUS_RESOURCES_UNAVAIL 8
+#define SBP_STATUS_FUNCTION_REJECTED 9
+#define SBP_STATUS_LOGIN_ID_UNKNOWN 10
+#define SBP_STATUS_DUMMY_ORB_COMPLETE 11
+#define SBP_STATUS_REQUEST_ABORTED 12
+#define SBP_STATUS_UNSPECIFIED_ERROR 0xff
+
+#define AGENT_STATE_RESET 0
+#define AGENT_STATE_ACTIVE 1
+#define AGENT_STATE_SUSPENDED 2
+#define AGENT_STATE_DEAD 3
+
+struct sbp2_pointer {
+ __be32 high;
+ __be32 low;
+};
+
+struct sbp_command_block_orb {
+ struct sbp2_pointer next_orb;
+ struct sbp2_pointer data_descriptor;
+ __be32 misc;
+ u8 command_block[12];
+};
+
+struct sbp_page_table_entry {
+ __be16 segment_length;
+ __be16 segment_base_hi;
+ __be32 segment_base_lo;
+};
+
+struct sbp_management_orb {
+ struct sbp2_pointer ptr1;
+ struct sbp2_pointer ptr2;
+ __be32 misc;
+ __be32 length;
+ struct sbp2_pointer status_fifo;
+};
+
+struct sbp_status_block {
+ __be32 status;
+ __be32 orb_low;
+ u8 data[24];
+};
+
+struct sbp_login_response_block {
+ __be32 misc;
+ struct sbp2_pointer command_block_agent;
+ __be32 reconnect_hold;
+};
+
+struct sbp_login_descriptor {
+ struct sbp_session *sess;
+ struct list_head link;
+
+ struct se_lun *lun;
+
+ u64 status_fifo_addr;
+ int exclusive;
+ u16 login_id;
+
+ struct sbp_target_agent *tgt_agt;
+};
+
+struct sbp_session {
+ spinlock_t lock;
+ struct se_session *se_sess;
+ struct list_head login_list;
+ struct delayed_work maint_work;
+
+ u64 guid; /* login_owner_EUI_64 */
+ int node_id; /* login_owner_ID */
+
+ struct fw_card *card;
+ int generation;
+ int speed;
+
+ int reconnect_hold;
+ u64 reconnect_expires;
+};
+
+struct sbp_nacl {
+ /* Initiator EUI-64 */
+ u64 guid;
+ /* ASCII formatted GUID for SBP Initiator port */
+ char iport_name[SBP_NAMELEN];
+ /* Returned by sbp_make_nodeacl() */
+ struct se_node_acl se_node_acl;
+};
+
+struct sbp_tpg {
+ /* Target portal group tag for TCM */
+ u16 tport_tpgt;
+ /* Pointer back to sbp_tport */
+ struct sbp_tport *tport;
+ /* Returned by sbp_make_tpg() */
+ struct se_portal_group se_tpg;
+};
+
+struct sbp_tport {
+ /* Target Unit Identifier (EUI-64) */
+ u64 guid;
+ /* Target port name */
+ char tport_name[SBP_NAMELEN];
+ /* Returned by sbp_make_tport() */
+ struct se_wwn tport_wwn;
+
+ struct sbp_tpg *tpg;
+
+ /* FireWire unit directory */
+ struct fw_descriptor unit_directory;
+
+ /* SBP Management Agent */
+ struct sbp_management_agent *mgt_agt;
+
+ /* Parameters */
+ int enable;
+ s32 directory_id;
+ int mgt_orb_timeout;
+ int max_reconnect_timeout;
+ int max_logins_per_lun;
+};
+
+static inline u64 sbp2_pointer_to_addr(const struct sbp2_pointer *ptr)
+{
+ return (u64)(be32_to_cpu(ptr->high) & 0x0000ffff) << 32 |
+ (be32_to_cpu(ptr->low) & 0xfffffffc);
+}
+
+static inline void addr_to_sbp2_pointer(u64 addr, struct sbp2_pointer *ptr)
+{
+ ptr->high = cpu_to_be32(addr >> 32);
+ ptr->low = cpu_to_be32(addr);
+}
+
+struct sbp_target_agent {
+ spinlock_t lock;
+ struct fw_address_handler handler;
+ struct sbp_login_descriptor *login;
+ int state;
+ struct work_struct work;
+ u64 orb_pointer;
+ bool doorbell;
+};
+
+struct sbp_target_request {
+ struct sbp_login_descriptor *login;
+ u64 orb_pointer;
+ struct sbp_command_block_orb orb;
+ struct sbp_status_block status;
+ struct work_struct work;
+
+ struct se_cmd se_cmd;
+ struct sbp_page_table_entry *pg_tbl;
+ void *cmd_buf;
+
+ unsigned char sense_buf[TRANSPORT_SENSE_BUFFER];
+};
+
+struct sbp_management_agent {
+ spinlock_t lock;
+ struct sbp_tport *tport;
+ struct fw_address_handler handler;
+ int state;
+ struct work_struct work;
+ u64 orb_offset;
+ struct sbp_management_request *request;
+};
+
+struct sbp_management_request {
+ struct sbp_management_orb orb;
+ struct sbp_status_block status;
+ struct fw_card *card;
+ int generation;
+ int node_addr;
+ int speed;
+};
+
+#endif
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index 6cc4358f68c1..35819e312624 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -1033,7 +1033,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
if (!retinfo)
return -EFAULT;
memset(&tmp, 0, sizeof(tmp));
- tty_lock();
+ tty_lock(tty);
tmp.line = tty->index;
tmp.port = state->port;
tmp.flags = state->tport.flags;
@@ -1042,7 +1042,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
tmp.close_delay = state->tport.close_delay;
tmp.closing_wait = state->tport.closing_wait;
tmp.custom_divisor = state->custom_divisor;
- tty_unlock();
+ tty_unlock(tty);
if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
return -EFAULT;
return 0;
@@ -1059,12 +1059,12 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
return -EFAULT;
- tty_lock();
+ tty_lock(tty);
change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) ||
new_serial.custom_divisor != state->custom_divisor;
if (new_serial.irq || new_serial.port != state->port ||
new_serial.xmit_fifo_size != state->xmit_fifo_size) {
- tty_unlock();
+ tty_unlock(tty);
return -EINVAL;
}
@@ -1074,7 +1074,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
(new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
((new_serial.flags & ~ASYNC_USR_MASK) !=
(port->flags & ~ASYNC_USR_MASK))) {
- tty_unlock();
+ tty_unlock(tty);
return -EPERM;
}
port->flags = ((port->flags & ~ASYNC_USR_MASK) |
@@ -1084,7 +1084,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
}
if (new_serial.baud_base < 9600) {
- tty_unlock();
+ tty_unlock(tty);
return -EINVAL;
}
@@ -1116,7 +1116,7 @@ check_and_exit:
}
} else
retval = startup(tty, state);
- tty_unlock();
+ tty_unlock(tty);
return retval;
}
diff --git a/drivers/tty/bfin_jtag_comm.c b/drivers/tty/bfin_jtag_comm.c
index 946f799861f5..61fc74fe1747 100644
--- a/drivers/tty/bfin_jtag_comm.c
+++ b/drivers/tty/bfin_jtag_comm.c
@@ -62,9 +62,7 @@ static inline uint32_t bfin_write_emudat_chars(char a, char b, char c, char d)
static struct tty_driver *bfin_jc_driver;
static struct task_struct *bfin_jc_kthread;
-static struct tty_struct * volatile bfin_jc_tty;
-static unsigned long bfin_jc_count;
-static DEFINE_MUTEX(bfin_jc_tty_mutex);
+static struct tty_port port;
static volatile struct circ_buf bfin_jc_write_buf;
static int
@@ -73,18 +71,21 @@ bfin_jc_emudat_manager(void *arg)
uint32_t inbound_len = 0, outbound_len = 0;
while (!kthread_should_stop()) {
+ struct tty_struct *tty = tty_port_tty_get(&port);
/* no one left to give data to, so sleep */
- if (bfin_jc_tty == NULL && circ_empty(&bfin_jc_write_buf)) {
+ if (tty == NULL && circ_empty(&bfin_jc_write_buf)) {
pr_debug("waiting for readers\n");
__set_current_state(TASK_UNINTERRUPTIBLE);
schedule();
__set_current_state(TASK_RUNNING);
+ continue;
}
/* no data available, so just chill */
if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) {
pr_debug("waiting for data (in_len = %i) (circ: %i %i)\n",
inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head);
+ tty_kref_put(tty);
if (inbound_len)
schedule();
else
@@ -94,9 +95,6 @@ bfin_jc_emudat_manager(void *arg)
/* if incoming data is ready, eat it */
if (bfin_read_DBGSTAT() & EMUDIF) {
- struct tty_struct *tty;
- mutex_lock(&bfin_jc_tty_mutex);
- tty = (struct tty_struct *)bfin_jc_tty;
if (tty != NULL) {
uint32_t emudat = bfin_read_emudat();
if (inbound_len == 0) {
@@ -110,7 +108,6 @@ bfin_jc_emudat_manager(void *arg)
tty_flip_buffer_push(tty);
}
}
- mutex_unlock(&bfin_jc_tty_mutex);
}
/* if outgoing data is ready, post it */
@@ -120,7 +117,6 @@ bfin_jc_emudat_manager(void *arg)
bfin_write_emudat(outbound_len);
pr_debug("outgoing length: 0x%08x\n", outbound_len);
} else {
- struct tty_struct *tty;
int tail = bfin_jc_write_buf.tail;
size_t ate = (4 <= outbound_len ? 4 : outbound_len);
uint32_t emudat =
@@ -132,14 +128,12 @@ bfin_jc_emudat_manager(void *arg)
);
bfin_jc_write_buf.tail += ate;
outbound_len -= ate;
- mutex_lock(&bfin_jc_tty_mutex);
- tty = (struct tty_struct *)bfin_jc_tty;
if (tty)
tty_wakeup(tty);
- mutex_unlock(&bfin_jc_tty_mutex);
pr_debug(" outgoing data: 0x%08x (pushing %zu)\n", emudat, ate);
}
}
+ tty_kref_put(tty);
}
__set_current_state(TASK_RUNNING);
@@ -149,24 +143,28 @@ bfin_jc_emudat_manager(void *arg)
static int
bfin_jc_open(struct tty_struct *tty, struct file *filp)
{
- mutex_lock(&bfin_jc_tty_mutex);
- pr_debug("open %lu\n", bfin_jc_count);
- ++bfin_jc_count;
- bfin_jc_tty = tty;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port.lock, flags);
+ port.count++;
+ spin_unlock_irqrestore(&port.lock, flags);
+ tty_port_tty_set(&port, tty);
wake_up_process(bfin_jc_kthread);
- mutex_unlock(&bfin_jc_tty_mutex);
return 0;
}
static void
bfin_jc_close(struct tty_struct *tty, struct file *filp)
{
- mutex_lock(&bfin_jc_tty_mutex);
- pr_debug("close %lu\n", bfin_jc_count);
- if (--bfin_jc_count == 0)
- bfin_jc_tty = NULL;
+ unsigned long flags;
+ bool last;
+
+ spin_lock_irqsave(&port.lock, flags);
+ last = --port.count == 0;
+ spin_unlock_irqrestore(&port.lock, flags);
+ if (last)
+ tty_port_tty_set(&port, NULL);
wake_up_process(bfin_jc_kthread);
- mutex_unlock(&bfin_jc_tty_mutex);
}
/* XXX: we dont handle the put_char() case where we must handle count = 1 */
@@ -242,6 +240,8 @@ static int __init bfin_jc_init(void)
{
int ret;
+ tty_port_init(&port);
+
bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME);
if (IS_ERR(bfin_jc_kthread))
return PTR_ERR(bfin_jc_kthread);
diff --git a/drivers/tty/cyclades.c b/drivers/tty/cyclades.c
index e61cabdd69df..6984e1a2686a 100644
--- a/drivers/tty/cyclades.c
+++ b/drivers/tty/cyclades.c
@@ -1599,7 +1599,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
* If the port is the middle of closing, bail out now
*/
if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
- wait_event_interruptible_tty(info->port.close_wait,
+ wait_event_interruptible_tty(tty, info->port.close_wait,
!(info->port.flags & ASYNC_CLOSING));
return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
}
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c
index 8880adf5fc6f..2d691eb7c40a 100644
--- a/drivers/tty/hvc/hvc_console.c
+++ b/drivers/tty/hvc/hvc_console.c
@@ -107,7 +107,7 @@ static struct hvc_struct *hvc_get_by_index(int index)
list_for_each_entry(hp, &hvc_structs, next) {
spin_lock_irqsave(&hp->lock, flags);
if (hp->index == index) {
- kref_get(&hp->kref);
+ tty_port_get(&hp->port);
spin_unlock_irqrestore(&hp->lock, flags);
spin_unlock(&hvc_structs_lock);
return hp;
@@ -229,9 +229,9 @@ static int __init hvc_console_init(void)
console_initcall(hvc_console_init);
/* callback when the kboject ref count reaches zero. */
-static void destroy_hvc_struct(struct kref *kref)
+static void hvc_port_destruct(struct tty_port *port)
{
- struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref);
+ struct hvc_struct *hp = container_of(port, struct hvc_struct, port);
unsigned long flags;
spin_lock(&hvc_structs_lock);
@@ -264,7 +264,7 @@ int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops)
/* make sure no no tty has been registered in this index */
hp = hvc_get_by_index(index);
if (hp) {
- kref_put(&hp->kref, destroy_hvc_struct);
+ tty_port_put(&hp->port);
return -1;
}
@@ -313,20 +313,17 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
if (!(hp = hvc_get_by_index(tty->index)))
return -ENODEV;
- spin_lock_irqsave(&hp->lock, flags);
+ spin_lock_irqsave(&hp->port.lock, flags);
/* Check and then increment for fast path open. */
- if (hp->count++ > 0) {
- tty_kref_get(tty);
- spin_unlock_irqrestore(&hp->lock, flags);
+ if (hp->port.count++ > 0) {
+ spin_unlock_irqrestore(&hp->port.lock, flags);
hvc_kick();
return 0;
} /* else count == 0 */
+ spin_unlock_irqrestore(&hp->port.lock, flags);
tty->driver_data = hp;
-
- hp->tty = tty_kref_get(tty);
-
- spin_unlock_irqrestore(&hp->lock, flags);
+ tty_port_tty_set(&hp->port, tty);
if (hp->ops->notifier_add)
rc = hp->ops->notifier_add(hp, hp->data);
@@ -338,12 +335,9 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
* tty fields and return the kref reference.
*/
if (rc) {
- spin_lock_irqsave(&hp->lock, flags);
- hp->tty = NULL;
- spin_unlock_irqrestore(&hp->lock, flags);
- tty_kref_put(tty);
+ tty_port_tty_set(&hp->port, NULL);
tty->driver_data = NULL;
- kref_put(&hp->kref, destroy_hvc_struct);
+ tty_port_put(&hp->port);
printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
}
/* Force wakeup of the polling thread */
@@ -370,12 +364,12 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
hp = tty->driver_data;
- spin_lock_irqsave(&hp->lock, flags);
+ spin_lock_irqsave(&hp->port.lock, flags);
- if (--hp->count == 0) {
+ if (--hp->port.count == 0) {
+ spin_unlock_irqrestore(&hp->port.lock, flags);
/* We are done with the tty pointer now. */
- hp->tty = NULL;
- spin_unlock_irqrestore(&hp->lock, flags);
+ tty_port_tty_set(&hp->port, NULL);
if (hp->ops->notifier_del)
hp->ops->notifier_del(hp, hp->data);
@@ -390,14 +384,13 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
*/
tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT);
} else {
- if (hp->count < 0)
+ if (hp->port.count < 0)
printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
- hp->vtermno, hp->count);
- spin_unlock_irqrestore(&hp->lock, flags);
+ hp->vtermno, hp->port.count);
+ spin_unlock_irqrestore(&hp->port.lock, flags);
}
- tty_kref_put(tty);
- kref_put(&hp->kref, destroy_hvc_struct);
+ tty_port_put(&hp->port);
}
static void hvc_hangup(struct tty_struct *tty)
@@ -412,32 +405,31 @@ static void hvc_hangup(struct tty_struct *tty)
/* cancel pending tty resize work */
cancel_work_sync(&hp->tty_resize);
- spin_lock_irqsave(&hp->lock, flags);
+ spin_lock_irqsave(&hp->port.lock, flags);
/*
* The N_TTY line discipline has problems such that in a close vs
* open->hangup case this can be called after the final close so prevent
* that from happening for now.
*/
- if (hp->count <= 0) {
- spin_unlock_irqrestore(&hp->lock, flags);
+ if (hp->port.count <= 0) {
+ spin_unlock_irqrestore(&hp->port.lock, flags);
return;
}
- temp_open_count = hp->count;
- hp->count = 0;
- hp->n_outbuf = 0;
- hp->tty = NULL;
+ temp_open_count = hp->port.count;
+ hp->port.count = 0;
+ spin_unlock_irqrestore(&hp->port.lock, flags);
+ tty_port_tty_set(&hp->port, NULL);
- spin_unlock_irqrestore(&hp->lock, flags);
+ hp->n_outbuf = 0;
if (hp->ops->notifier_hangup)
hp->ops->notifier_hangup(hp, hp->data);
while(temp_open_count) {
--temp_open_count;
- tty_kref_put(tty);
- kref_put(&hp->kref, destroy_hvc_struct);
+ tty_port_put(&hp->port);
}
}
@@ -478,7 +470,8 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count
if (!hp)
return -EPIPE;
- if (hp->count <= 0)
+ /* FIXME what's this (unprotected) check for? */
+ if (hp->port.count <= 0)
return -EIO;
spin_lock_irqsave(&hp->lock, flags);
@@ -526,13 +519,12 @@ static void hvc_set_winsz(struct work_struct *work)
hp = container_of(work, struct hvc_struct, tty_resize);
- spin_lock_irqsave(&hp->lock, hvc_flags);
- if (!hp->tty) {
- spin_unlock_irqrestore(&hp->lock, hvc_flags);
+ tty = tty_port_tty_get(&hp->port);
+ if (!tty)
return;
- }
- ws = hp->ws;
- tty = tty_kref_get(hp->tty);
+
+ spin_lock_irqsave(&hp->lock, hvc_flags);
+ ws = hp->ws;
spin_unlock_irqrestore(&hp->lock, hvc_flags);
tty_do_resize(tty, &ws);
@@ -601,7 +593,7 @@ int hvc_poll(struct hvc_struct *hp)
}
/* No tty attached, just skip */
- tty = tty_kref_get(hp->tty);
+ tty = tty_port_tty_get(&hp->port);
if (tty == NULL)
goto bail;
@@ -681,8 +673,7 @@ int hvc_poll(struct hvc_struct *hp)
tty_flip_buffer_push(tty);
}
- if (tty)
- tty_kref_put(tty);
+ tty_kref_put(tty);
return poll_mask;
}
@@ -817,6 +808,10 @@ static const struct tty_operations hvc_ops = {
#endif
};
+static const struct tty_port_operations hvc_port_ops = {
+ .destruct = hvc_port_destruct,
+};
+
struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
const struct hv_ops *ops,
int outbuf_size)
@@ -842,7 +837,8 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
hp->outbuf_size = outbuf_size;
hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))];
- kref_init(&hp->kref);
+ tty_port_init(&hp->port);
+ hp->port.ops = &hvc_port_ops;
INIT_WORK(&hp->tty_resize, hvc_set_winsz);
spin_lock_init(&hp->lock);
@@ -875,9 +871,9 @@ int hvc_remove(struct hvc_struct *hp)
unsigned long flags;
struct tty_struct *tty;
- spin_lock_irqsave(&hp->lock, flags);
- tty = tty_kref_get(hp->tty);
+ tty = tty_port_tty_get(&hp->port);
+ spin_lock_irqsave(&hp->lock, flags);
if (hp->index < MAX_NR_HVC_CONSOLES)
vtermnos[hp->index] = -1;
@@ -891,7 +887,7 @@ int hvc_remove(struct hvc_struct *hp)
* kref cause it to be removed, which will probably be the tty_vhangup
* below.
*/
- kref_put(&hp->kref, destroy_hvc_struct);
+ tty_port_put(&hp->port);
/*
* This function call will auto chain call hvc_hangup.
diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h
index c335a1492a54..674d23cb919a 100644
--- a/drivers/tty/hvc/hvc_console.h
+++ b/drivers/tty/hvc/hvc_console.h
@@ -46,10 +46,9 @@
#define HVC_ALLOC_TTY_ADAPTERS 8
struct hvc_struct {
+ struct tty_port port;
spinlock_t lock;
int index;
- struct tty_struct *tty;
- int count;
int do_wakeup;
char *outbuf;
int outbuf_size;
@@ -61,7 +60,6 @@ struct hvc_struct {
struct winsize ws;
struct work_struct tty_resize;
struct list_head next;
- struct kref kref; /* ref count & hvc_struct lifetime */
};
/* implemented by a low level driver */
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
index 83d5c88e7165..d3d91dae065c 100644
--- a/drivers/tty/hvc/hvc_xen.c
+++ b/drivers/tty/hvc/hvc_xen.c
@@ -430,9 +430,9 @@ static int __devinit xencons_probe(struct xenbus_device *dev,
if (devid == 0)
return -ENODEV;
- info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL | __GFP_ZERO);
+ info = kzalloc(sizeof(struct xencons_info), GFP_KERNEL);
if (!info)
- goto error_nomem;
+ return -ENOMEM;
dev_set_drvdata(&dev->dev, info);
info->xbdev = dev;
info->vtermno = xenbus_devid_to_vtermno(devid);
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c
index 3436436fe2d7..d56788c83974 100644
--- a/drivers/tty/hvc/hvcs.c
+++ b/drivers/tty/hvc/hvcs.c
@@ -261,6 +261,7 @@ static DEFINE_SPINLOCK(hvcs_pi_lock);
/* One vty-server per hvcs_struct */
struct hvcs_struct {
+ struct tty_port port;
spinlock_t lock;
/*
@@ -269,9 +270,6 @@ struct hvcs_struct {
*/
unsigned int index;
- struct tty_struct *tty;
- int open_count;
-
/*
* Used to tell the driver kernel_thread what operations need to take
* place upon this hvcs_struct instance.
@@ -290,12 +288,11 @@ struct hvcs_struct {
int chars_in_buffer;
/*
- * Any variable below the kref is valid before a tty is connected and
+ * Any variable below is valid before a tty is connected and
* stays valid after the tty is disconnected. These shouldn't be
* whacked until the kobject refcount reaches zero though some entries
* may be changed via sysfs initiatives.
*/
- struct kref kref; /* ref count & hvcs_struct lifetime */
int connected; /* is the vty-server currently connected to a vty? */
uint32_t p_unit_address; /* partner unit address */
uint32_t p_partition_ID; /* partner partition ID */
@@ -304,9 +301,6 @@ struct hvcs_struct {
struct vio_dev *vdev;
};
-/* Required to back map a kref to its containing object */
-#define from_kref(k) container_of(k, struct hvcs_struct, kref)
-
static LIST_HEAD(hvcs_structs);
static DEFINE_SPINLOCK(hvcs_structs_lock);
static DEFINE_MUTEX(hvcs_init_mutex);
@@ -422,7 +416,7 @@ static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribut
spin_lock_irqsave(&hvcsd->lock, flags);
- if (hvcsd->open_count > 0) {
+ if (hvcsd->port.count > 0) {
spin_unlock_irqrestore(&hvcsd->lock, flags);
printk(KERN_INFO "HVCS: vterm state unchanged. "
"The hvcs device node is still in use.\n");
@@ -564,7 +558,7 @@ static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance)
static void hvcs_try_write(struct hvcs_struct *hvcsd)
{
uint32_t unit_address = hvcsd->vdev->unit_address;
- struct tty_struct *tty = hvcsd->tty;
+ struct tty_struct *tty = hvcsd->port.tty;
int sent;
if (hvcsd->todo_mask & HVCS_TRY_WRITE) {
@@ -602,7 +596,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd)
spin_lock_irqsave(&hvcsd->lock, flags);
unit_address = hvcsd->vdev->unit_address;
- tty = hvcsd->tty;
+ tty = hvcsd->port.tty;
hvcs_try_write(hvcsd);
@@ -701,10 +695,9 @@ static void hvcs_return_index(int index)
hvcs_index_list[index] = -1;
}
-/* callback when the kref ref count reaches zero */
-static void destroy_hvcs_struct(struct kref *kref)
+static void hvcs_destruct_port(struct tty_port *p)
{
- struct hvcs_struct *hvcsd = from_kref(kref);
+ struct hvcs_struct *hvcsd = container_of(p, struct hvcs_struct, port);
struct vio_dev *vdev;
unsigned long flags;
@@ -741,6 +734,10 @@ static void destroy_hvcs_struct(struct kref *kref)
kfree(hvcsd);
}
+static const struct tty_port_operations hvcs_port_ops = {
+ .destruct = hvcs_destruct_port,
+};
+
static int hvcs_get_index(void)
{
int i;
@@ -789,10 +786,9 @@ static int __devinit hvcs_probe(
if (!hvcsd)
return -ENODEV;
-
+ tty_port_init(&hvcsd->port);
+ hvcsd->port.ops = &hvcs_port_ops;
spin_lock_init(&hvcsd->lock);
- /* Automatically incs the refcount the first time */
- kref_init(&hvcsd->kref);
hvcsd->vdev = dev;
dev_set_drvdata(&dev->dev, hvcsd);
@@ -852,7 +848,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev)
spin_lock_irqsave(&hvcsd->lock, flags);
- tty = hvcsd->tty;
+ tty = hvcsd->port.tty;
spin_unlock_irqrestore(&hvcsd->lock, flags);
@@ -860,7 +856,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev)
* Let the last holder of this object cause it to be removed, which
* would probably be tty_hangup below.
*/
- kref_put(&hvcsd->kref, destroy_hvcs_struct);
+ tty_port_put(&hvcsd->port);
/*
* The hangup is a scheduled function which will auto chain call
@@ -1094,7 +1090,7 @@ static struct hvcs_struct *hvcs_get_by_index(int index)
list_for_each_entry(hvcsd, &hvcs_structs, next) {
spin_lock_irqsave(&hvcsd->lock, flags);
if (hvcsd->index == index) {
- kref_get(&hvcsd->kref);
+ tty_port_get(&hvcsd->port);
spin_unlock_irqrestore(&hvcsd->lock, flags);
spin_unlock(&hvcs_structs_lock);
return hvcsd;
@@ -1138,8 +1134,8 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
if ((retval = hvcs_partner_connect(hvcsd)))
goto error_release;
- hvcsd->open_count = 1;
- hvcsd->tty = tty;
+ hvcsd->port.count = 1;
+ hvcsd->port.tty = tty;
tty->driver_data = hvcsd;
memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN);
@@ -1160,7 +1156,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
* and will grab the spinlock and free the connection if it fails.
*/
if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) {
- kref_put(&hvcsd->kref, destroy_hvcs_struct);
+ tty_port_put(&hvcsd->port);
printk(KERN_WARNING "HVCS: enable device failed.\n");
return rc;
}
@@ -1171,8 +1167,8 @@ fast_open:
hvcsd = tty->driver_data;
spin_lock_irqsave(&hvcsd->lock, flags);
- kref_get(&hvcsd->kref);
- hvcsd->open_count++;
+ tty_port_get(&hvcsd->port);
+ hvcsd->port.count++;
hvcsd->todo_mask |= HVCS_SCHED_READ;
spin_unlock_irqrestore(&hvcsd->lock, flags);
@@ -1186,7 +1182,7 @@ open_success:
error_release:
spin_unlock_irqrestore(&hvcsd->lock, flags);
- kref_put(&hvcsd->kref, destroy_hvcs_struct);
+ tty_port_put(&hvcsd->port);
printk(KERN_WARNING "HVCS: partner connect failed.\n");
return retval;
@@ -1216,7 +1212,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
hvcsd = tty->driver_data;
spin_lock_irqsave(&hvcsd->lock, flags);
- if (--hvcsd->open_count == 0) {
+ if (--hvcsd->port.count == 0) {
vio_disable_interrupts(hvcsd->vdev);
@@ -1225,7 +1221,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
* execute any operations on the TTY even though it is obligated
* to deliver any pending I/O to the hypervisor.
*/
- hvcsd->tty = NULL;
+ hvcsd->port.tty = NULL;
irq = hvcsd->vdev->irq;
spin_unlock_irqrestore(&hvcsd->lock, flags);
@@ -1240,16 +1236,16 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
tty->driver_data = NULL;
free_irq(irq, hvcsd);
- kref_put(&hvcsd->kref, destroy_hvcs_struct);
+ tty_port_put(&hvcsd->port);
return;
- } else if (hvcsd->open_count < 0) {
+ } else if (hvcsd->port.count < 0) {
printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"
" is missmanaged.\n",
- hvcsd->vdev->unit_address, hvcsd->open_count);
+ hvcsd->vdev->unit_address, hvcsd->port.count);
}
spin_unlock_irqrestore(&hvcsd->lock, flags);
- kref_put(&hvcsd->kref, destroy_hvcs_struct);
+ tty_port_put(&hvcsd->port);
}
static void hvcs_hangup(struct tty_struct * tty)
@@ -1261,7 +1257,7 @@ static void hvcs_hangup(struct tty_struct * tty)
spin_lock_irqsave(&hvcsd->lock, flags);
/* Preserve this so that we know how many kref refs to put */
- temp_open_count = hvcsd->open_count;
+ temp_open_count = hvcsd->port.count;
/*
* Don't kref put inside the spinlock because the destruction
@@ -1273,10 +1269,10 @@ static void hvcs_hangup(struct tty_struct * tty)
hvcsd->todo_mask = 0;
/* I don't think the tty needs the hvcs_struct pointer after a hangup */
- hvcsd->tty->driver_data = NULL;
- hvcsd->tty = NULL;
+ tty->driver_data = NULL;
+ hvcsd->port.tty = NULL;
- hvcsd->open_count = 0;
+ hvcsd->port.count = 0;
/* This will drop any buffered data on the floor which is OK in a hangup
* scenario. */
@@ -1301,7 +1297,7 @@ static void hvcs_hangup(struct tty_struct * tty)
* NOTE: If this hangup was signaled from user space then the
* final put will never happen.
*/
- kref_put(&hvcsd->kref, destroy_hvcs_struct);
+ tty_port_put(&hvcsd->port);
}
}
@@ -1347,7 +1343,7 @@ static int hvcs_write(struct tty_struct *tty,
* the middle of a write operation? This is a crummy place to do this
* but we want to keep it all in the spinlock.
*/
- if (hvcsd->open_count <= 0) {
+ if (hvcsd->port.count <= 0) {
spin_unlock_irqrestore(&hvcsd->lock, flags);
return -ENODEV;
}
@@ -1421,7 +1417,7 @@ static int hvcs_write_room(struct tty_struct *tty)
{
struct hvcs_struct *hvcsd = tty->driver_data;
- if (!hvcsd || hvcsd->open_count <= 0)
+ if (!hvcsd || hvcsd->port.count <= 0)
return 0;
return HVCS_BUFF_LEN - hvcsd->chars_in_buffer;
diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c
index a7488b748647..6f5bc49c441f 100644
--- a/drivers/tty/hvc/hvsi.c
+++ b/drivers/tty/hvc/hvsi.c
@@ -69,14 +69,13 @@
#define __ALIGNED__ __attribute__((__aligned__(sizeof(long))))
struct hvsi_struct {
+ struct tty_port port;
struct delayed_work writer;
struct work_struct handshaker;
wait_queue_head_t emptyq; /* woken when outbuf is emptied */
wait_queue_head_t stateq; /* woken when HVSI state changes */
spinlock_t lock;
int index;
- struct tty_struct *tty;
- int count;
uint8_t throttle_buf[128];
uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */
/* inbuf is for packet reassembly. leave a little room for leftovers. */
@@ -237,7 +236,7 @@ static int hvsi_read(struct hvsi_struct *hp, char *buf, int count)
}
static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,
- struct tty_struct **to_hangup, struct hvsi_struct **to_handshake)
+ struct tty_struct *tty, struct hvsi_struct **to_handshake)
{
struct hvsi_control *header = (struct hvsi_control *)packet;
@@ -247,9 +246,8 @@ static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,
/* CD went away; no more connection */
pr_debug("hvsi%i: CD dropped\n", hp->index);
hp->mctrl &= TIOCM_CD;
- /* If userland hasn't done an open(2) yet, hp->tty is NULL. */
- if (hp->tty && !(hp->tty->flags & CLOCAL))
- *to_hangup = hp->tty;
+ if (tty && !C_CLOCAL(tty))
+ tty_hangup(tty);
}
break;
case VSV_CLOSE_PROTOCOL:
@@ -331,7 +329,8 @@ static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet)
}
}
-static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
+static void hvsi_insert_chars(struct hvsi_struct *hp, struct tty_struct *tty,
+ const char *buf, int len)
{
int i;
@@ -347,7 +346,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
continue;
}
#endif /* CONFIG_MAGIC_SYSRQ */
- tty_insert_flip_char(hp->tty, c, 0);
+ tty_insert_flip_char(tty, c, 0);
}
}
@@ -360,7 +359,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
* revisited.
*/
#define TTY_THRESHOLD_THROTTLE 128
-static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
+static bool hvsi_recv_data(struct hvsi_struct *hp, struct tty_struct *tty,
const uint8_t *packet)
{
const struct hvsi_header *header = (const struct hvsi_header *)packet;
@@ -371,14 +370,14 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data);
if (datalen == 0)
- return NULL;
+ return false;
if (overflow > 0) {
pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__);
datalen = TTY_THRESHOLD_THROTTLE;
}
- hvsi_insert_chars(hp, data, datalen);
+ hvsi_insert_chars(hp, tty, data, datalen);
if (overflow > 0) {
/*
@@ -390,7 +389,7 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
hp->n_throttle = overflow;
}
- return hp->tty;
+ return true;
}
/*
@@ -399,14 +398,13 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
* machine during console handshaking (in which case tty = NULL and we ignore
* incoming data).
*/
-static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
- struct tty_struct **hangup, struct hvsi_struct **handshake)
+static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct *tty,
+ struct hvsi_struct **handshake)
{
uint8_t *packet = hp->inbuf;
int chunklen;
+ bool flip = false;
- *flip = NULL;
- *hangup = NULL;
*handshake = NULL;
chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ);
@@ -440,12 +438,12 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
case VS_DATA_PACKET_HEADER:
if (!is_open(hp))
break;
- if (hp->tty == NULL)
+ if (tty == NULL)
break; /* no tty buffer to put data in */
- *flip = hvsi_recv_data(hp, packet);
+ flip = hvsi_recv_data(hp, tty, packet);
break;
case VS_CONTROL_PACKET_HEADER:
- hvsi_recv_control(hp, packet, hangup, handshake);
+ hvsi_recv_control(hp, packet, tty, handshake);
break;
case VS_QUERY_RESPONSE_PACKET_HEADER:
hvsi_recv_response(hp, packet);
@@ -462,28 +460,26 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
packet += len_packet(packet);
- if (*hangup || *handshake) {
- pr_debug("%s: hangup or handshake\n", __func__);
- /*
- * we need to send the hangup now before receiving any more data.
- * If we get "data, hangup, data", we can't deliver the second
- * data before the hangup.
- */
+ if (*handshake) {
+ pr_debug("%s: handshake\n", __func__);
break;
}
}
compact_inbuf(hp, packet);
+ if (flip)
+ tty_flip_buffer_push(tty);
+
return 1;
}
-static void hvsi_send_overflow(struct hvsi_struct *hp)
+static void hvsi_send_overflow(struct hvsi_struct *hp, struct tty_struct *tty)
{
pr_debug("%s: delivering %i bytes overflow\n", __func__,
hp->n_throttle);
- hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle);
+ hvsi_insert_chars(hp, tty, hp->throttle_buf, hp->n_throttle);
hp->n_throttle = 0;
}
@@ -494,35 +490,20 @@ static void hvsi_send_overflow(struct hvsi_struct *hp)
static irqreturn_t hvsi_interrupt(int irq, void *arg)
{
struct hvsi_struct *hp = (struct hvsi_struct *)arg;
- struct tty_struct *flip;
- struct tty_struct *hangup;
struct hvsi_struct *handshake;
+ struct tty_struct *tty;
unsigned long flags;
int again = 1;
pr_debug("%s\n", __func__);
+ tty = tty_port_tty_get(&hp->port);
+
while (again) {
spin_lock_irqsave(&hp->lock, flags);
- again = hvsi_load_chunk(hp, &flip, &hangup, &handshake);
+ again = hvsi_load_chunk(hp, tty, &handshake);
spin_unlock_irqrestore(&hp->lock, flags);
- /*
- * we have to call tty_flip_buffer_push() and tty_hangup() outside our
- * spinlock. But we also have to keep going until we've read all the
- * available data.
- */
-
- if (flip) {
- /* there was data put in the tty flip buffer */
- tty_flip_buffer_push(flip);
- flip = NULL;
- }
-
- if (hangup) {
- tty_hangup(hangup);
- }
-
if (handshake) {
pr_debug("hvsi%i: attempting re-handshake\n", handshake->index);
schedule_work(&handshake->handshaker);
@@ -530,18 +511,15 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg)
}
spin_lock_irqsave(&hp->lock, flags);
- if (hp->tty && hp->n_throttle
- && (!test_bit(TTY_THROTTLED, &hp->tty->flags))) {
- /* we weren't hung up and we weren't throttled, so we can deliver the
- * rest now */
- flip = hp->tty;
- hvsi_send_overflow(hp);
+ if (tty && hp->n_throttle && !test_bit(TTY_THROTTLED, &tty->flags)) {
+ /* we weren't hung up and we weren't throttled, so we can
+ * deliver the rest now */
+ hvsi_send_overflow(hp, tty);
+ tty_flip_buffer_push(tty);
}
spin_unlock_irqrestore(&hp->lock, flags);
- if (flip) {
- tty_flip_buffer_push(flip);
- }
+ tty_kref_put(tty);
return IRQ_HANDLED;
}
@@ -749,9 +727,9 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp)
if (hp->state == HVSI_FSP_DIED)
return -EIO;
+ tty_port_tty_set(&hp->port, tty);
spin_lock_irqsave(&hp->lock, flags);
- hp->tty = tty;
- hp->count++;
+ hp->port.count++;
atomic_set(&hp->seqno, 0);
h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
spin_unlock_irqrestore(&hp->lock, flags);
@@ -808,8 +786,8 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp)
spin_lock_irqsave(&hp->lock, flags);
- if (--hp->count == 0) {
- hp->tty = NULL;
+ if (--hp->port.count == 0) {
+ tty_port_tty_set(&hp->port, NULL);
hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */
/* only close down connection if it is not the console */
@@ -841,9 +819,9 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp)
spin_lock_irqsave(&hp->lock, flags);
}
- } else if (hp->count < 0)
+ } else if (hp->port.count < 0)
printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n",
- hp - hvsi_ports, hp->count);
+ hp - hvsi_ports, hp->port.count);
spin_unlock_irqrestore(&hp->lock, flags);
}
@@ -855,12 +833,11 @@ static void hvsi_hangup(struct tty_struct *tty)
pr_debug("%s\n", __func__);
- spin_lock_irqsave(&hp->lock, flags);
+ tty_port_tty_set(&hp->port, NULL);
- hp->count = 0;
+ spin_lock_irqsave(&hp->lock, flags);
+ hp->port.count = 0;
hp->n_outbuf = 0;
- hp->tty = NULL;
-
spin_unlock_irqrestore(&hp->lock, flags);
}
@@ -888,6 +865,7 @@ static void hvsi_write_worker(struct work_struct *work)
{
struct hvsi_struct *hp =
container_of(work, struct hvsi_struct, writer.work);
+ struct tty_struct *tty;
unsigned long flags;
#ifdef DEBUG
static long start_j = 0;
@@ -921,7 +899,11 @@ static void hvsi_write_worker(struct work_struct *work)
start_j = 0;
#endif /* DEBUG */
wake_up_all(&hp->emptyq);
- tty_wakeup(hp->tty);
+ tty = tty_port_tty_get(&hp->port);
+ if (tty) {
+ tty_wakeup(tty);
+ tty_kref_put(tty);
+ }
}
out:
@@ -966,8 +948,8 @@ static int hvsi_write(struct tty_struct *tty,
* and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls
* will see there is no room in outbuf and return.
*/
- while ((count > 0) && (hvsi_write_room(hp->tty) > 0)) {
- int chunksize = min(count, hvsi_write_room(hp->tty));
+ while ((count > 0) && (hvsi_write_room(tty) > 0)) {
+ int chunksize = min(count, hvsi_write_room(tty));
BUG_ON(hp->n_outbuf < 0);
memcpy(hp->outbuf + hp->n_outbuf, source, chunksize);
@@ -1014,19 +996,16 @@ static void hvsi_unthrottle(struct tty_struct *tty)
{
struct hvsi_struct *hp = tty->driver_data;
unsigned long flags;
- int shouldflip = 0;
pr_debug("%s\n", __func__);
spin_lock_irqsave(&hp->lock, flags);
if (hp->n_throttle) {
- hvsi_send_overflow(hp);
- shouldflip = 1;
+ hvsi_send_overflow(hp, tty);
+ tty_flip_buffer_push(tty);
}
spin_unlock_irqrestore(&hp->lock, flags);
- if (shouldflip)
- tty_flip_buffer_push(hp->tty);
h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
}
@@ -1228,6 +1207,7 @@ static int __init hvsi_console_init(void)
init_waitqueue_head(&hp->emptyq);
init_waitqueue_head(&hp->stateq);
spin_lock_init(&hp->lock);
+ tty_port_init(&hp->port);
hp->index = hvsi_count;
hp->inbuf_end = hp->inbuf;
hp->state = HVSI_CLOSED;
diff --git a/drivers/tty/hvc/hvsi_lib.c b/drivers/tty/hvc/hvsi_lib.c
index 6f4dd83d8695..59c135dd5d20 100644
--- a/drivers/tty/hvc/hvsi_lib.c
+++ b/drivers/tty/hvc/hvsi_lib.c
@@ -377,7 +377,7 @@ int hvsilib_open(struct hvsi_priv *pv, struct hvc_struct *hp)
pr_devel("HVSI@%x: open !\n", pv->termno);
/* Keep track of the tty data structure */
- pv->tty = tty_kref_get(hp->tty);
+ pv->tty = tty_port_tty_get(&hp->port);
hvsilib_establish(pv);
diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c
index 4daf962f7055..f8b5fa0093a3 100644
--- a/drivers/tty/ipwireless/tty.c
+++ b/drivers/tty/ipwireless/tty.c
@@ -44,14 +44,13 @@
#define TTYTYPE_RAS_RAW (2)
struct ipw_tty {
+ struct tty_port port;
int index;
struct ipw_hardware *hardware;
unsigned int channel_idx;
unsigned int secondary_channel_idx;
int tty_type;
struct ipw_network *network;
- struct tty_struct *linux_tty;
- int open_count;
unsigned int control_lines;
struct mutex ipw_tty_mutex;
int tx_bytes_queued;
@@ -73,23 +72,6 @@ static char *tty_type_name(int tty_type)
return channel_names[tty_type];
}
-static void report_registering(struct ipw_tty *tty)
-{
- char *iftype = tty_type_name(tty->tty_type);
-
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME
- ": registering %s device ttyIPWp%d\n", iftype, tty->index);
-}
-
-static void report_deregistering(struct ipw_tty *tty)
-{
- char *iftype = tty_type_name(tty->tty_type);
-
- printk(KERN_INFO IPWIRELESS_PCCARD_NAME
- ": deregistering %s device ttyIPWp%d\n", iftype,
- tty->index);
-}
-
static struct ipw_tty *get_tty(int index)
{
/*
@@ -117,12 +99,12 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
mutex_unlock(&tty->ipw_tty_mutex);
return -ENODEV;
}
- if (tty->open_count == 0)
+ if (tty->port.count == 0)
tty->tx_bytes_queued = 0;
- tty->open_count++;
+ tty->port.count++;
- tty->linux_tty = linux_tty;
+ tty->port.tty = linux_tty;
linux_tty->driver_data = tty;
linux_tty->low_latency = 1;
@@ -136,13 +118,13 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
static void do_ipw_close(struct ipw_tty *tty)
{
- tty->open_count--;
+ tty->port.count--;
- if (tty->open_count == 0) {
- struct tty_struct *linux_tty = tty->linux_tty;
+ if (tty->port.count == 0) {
+ struct tty_struct *linux_tty = tty->port.tty;
if (linux_tty != NULL) {
- tty->linux_tty = NULL;
+ tty->port.tty = NULL;
linux_tty->driver_data = NULL;
if (tty->tty_type == TTYTYPE_MODEM)
@@ -159,7 +141,7 @@ static void ipw_hangup(struct tty_struct *linux_tty)
return;
mutex_lock(&tty->ipw_tty_mutex);
- if (tty->open_count == 0) {
+ if (tty->port.count == 0) {
mutex_unlock(&tty->ipw_tty_mutex);
return;
}
@@ -182,13 +164,13 @@ void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
int work = 0;
mutex_lock(&tty->ipw_tty_mutex);
- linux_tty = tty->linux_tty;
+ linux_tty = tty->port.tty;
if (linux_tty == NULL) {
mutex_unlock(&tty->ipw_tty_mutex);
return;
}
- if (!tty->open_count) {
+ if (!tty->port.count) {
mutex_unlock(&tty->ipw_tty_mutex);
return;
}
@@ -230,7 +212,7 @@ static int ipw_write(struct tty_struct *linux_tty,
return -ENODEV;
mutex_lock(&tty->ipw_tty_mutex);
- if (!tty->open_count) {
+ if (!tty->port.count) {
mutex_unlock(&tty->ipw_tty_mutex);
return -EINVAL;
}
@@ -270,7 +252,7 @@ static int ipw_write_room(struct tty_struct *linux_tty)
if (!tty)
return -ENODEV;
- if (!tty->open_count)
+ if (!tty->port.count)
return -EINVAL;
room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued;
@@ -312,7 +294,7 @@ static int ipw_chars_in_buffer(struct tty_struct *linux_tty)
if (!tty)
return 0;
- if (!tty->open_count)
+ if (!tty->port.count)
return 0;
return tty->tx_bytes_queued;
@@ -393,7 +375,7 @@ static int ipw_tiocmget(struct tty_struct *linux_tty)
if (!tty)
return -ENODEV;
- if (!tty->open_count)
+ if (!tty->port.count)
return -EINVAL;
return get_control_lines(tty);
@@ -409,7 +391,7 @@ ipw_tiocmset(struct tty_struct *linux_tty,
if (!tty)
return -ENODEV;
- if (!tty->open_count)
+ if (!tty->port.count)
return -EINVAL;
return set_control_lines(tty, set, clear);
@@ -423,7 +405,7 @@ static int ipw_ioctl(struct tty_struct *linux_tty,
if (!tty)
return -ENODEV;
- if (!tty->open_count)
+ if (!tty->port.count)
return -EINVAL;
/* FIXME: Exactly how is the tty object locked here .. */
@@ -492,6 +474,7 @@ static int add_tty(int j,
ttys[j]->network = network;
ttys[j]->tty_type = tty_type;
mutex_init(&ttys[j]->ipw_tty_mutex);
+ tty_port_init(&ttys[j]->port);
tty_register_device(ipw_tty_driver, j, NULL);
ipwireless_associate_network_tty(network, channel_idx, ttys[j]);
@@ -500,8 +483,12 @@ static int add_tty(int j,
ipwireless_associate_network_tty(network,
secondary_channel_idx,
ttys[j]);
- if (get_tty(j) == ttys[j])
- report_registering(ttys[j]);
+ /* check if we provide raw device (if loopback is enabled) */
+ if (get_tty(j))
+ printk(KERN_INFO IPWIRELESS_PCCARD_NAME
+ ": registering %s device ttyIPWp%d\n",
+ tty_type_name(tty_type), j);
+
return 0;
}
@@ -560,19 +547,21 @@ void ipwireless_tty_free(struct ipw_tty *tty)
if (ttyj) {
mutex_lock(&ttyj->ipw_tty_mutex);
- if (get_tty(j) == ttyj)
- report_deregistering(ttyj);
+ if (get_tty(j))
+ printk(KERN_INFO IPWIRELESS_PCCARD_NAME
+ ": deregistering %s device ttyIPWp%d\n",
+ tty_type_name(ttyj->tty_type), j);
ttyj->closing = 1;
- if (ttyj->linux_tty != NULL) {
+ if (ttyj->port.tty != NULL) {
mutex_unlock(&ttyj->ipw_tty_mutex);
- tty_hangup(ttyj->linux_tty);
- /* Wait till the tty_hangup has completed */
- flush_work_sync(&ttyj->linux_tty->hangup_work);
+ tty_vhangup(ttyj->port.tty);
/* FIXME: Exactly how is the tty object locked here
against a parallel ioctl etc */
+ /* FIXME2: hangup does not mean all processes
+ * are gone */
mutex_lock(&ttyj->ipw_tty_mutex);
}
- while (ttyj->open_count)
+ while (ttyj->port.count)
do_ipw_close(ttyj);
ipwireless_disassociate_network_ttys(network,
ttyj->channel_idx);
@@ -661,8 +650,8 @@ ipwireless_tty_notify_control_line_change(struct ipw_tty *tty,
*/
if ((old_control_lines & IPW_CONTROL_LINE_DCD)
&& !(tty->control_lines & IPW_CONTROL_LINE_DCD)
- && tty->linux_tty) {
- tty_hangup(tty->linux_tty);
+ && tty->port.tty) {
+ tty_hangup(tty->port.tty);
}
}
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index c6f372dd5623..90cc680c4f0e 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -2326,7 +2326,7 @@ static const struct tty_operations mxser_ops = {
.get_icount = mxser_get_icount,
};
-struct tty_port_operations mxser_port_ops = {
+static struct tty_port_operations mxser_port_ops = {
.carrier_raised = mxser_carrier_raised,
.dtr_rts = mxser_dtr_rts,
.activate = mxser_activate,
diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c
index 5c6c31459a2f..656ad93bbc96 100644
--- a/drivers/tty/n_r3964.c
+++ b/drivers/tty/n_r3964.c
@@ -1065,7 +1065,8 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
TRACE_L("read()");
- tty_lock();
+ /* FIXME: should use a private lock */
+ tty_lock(tty);
pClient = findClient(pInfo, task_pid(current));
if (pClient) {
@@ -1077,7 +1078,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
goto unlock;
}
/* block until there is a message: */
- wait_event_interruptible_tty(pInfo->read_wait,
+ wait_event_interruptible_tty(tty, pInfo->read_wait,
(pMsg = remove_msg(pInfo, pClient)));
}
@@ -1107,7 +1108,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
}
ret = -EPERM;
unlock:
- tty_unlock();
+ tty_unlock(tty);
return ret;
}
@@ -1156,7 +1157,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
pHeader->locks = 0;
pHeader->owner = NULL;
- tty_lock();
+ tty_lock(tty);
pClient = findClient(pInfo, task_pid(current));
if (pClient) {
@@ -1175,7 +1176,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
add_tx_queue(pInfo, pHeader);
trigger_transmit(pInfo);
- tty_unlock();
+ tty_unlock(tty);
return 0;
}
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 94b6eda87afd..ee1c268f5f9d 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1630,6 +1630,7 @@ static int copy_from_read_buf(struct tty_struct *tty,
int retval;
size_t n;
unsigned long flags;
+ bool is_eof;
retval = 0;
spin_lock_irqsave(&tty->read_lock, flags);
@@ -1639,15 +1640,15 @@ static int copy_from_read_buf(struct tty_struct *tty,
if (n) {
retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
n -= retval;
+ is_eof = n == 1 &&
+ tty->read_buf[tty->read_tail] == EOF_CHAR(tty);
tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
spin_lock_irqsave(&tty->read_lock, flags);
tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
tty->read_cnt -= n;
/* Turn single EOF into zero-length read */
- if (L_EXTPROC(tty) && tty->icanon && n == 1) {
- if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty))
- n--;
- }
+ if (L_EXTPROC(tty) && tty->icanon && is_eof && !tty->read_cnt)
+ n = 0;
spin_unlock_irqrestore(&tty->read_lock, flags);
*b += n;
*nr -= n;
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index eeae7fafe9a7..59af3945ea85 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -26,11 +26,13 @@
#include <linux/bitops.h>
#include <linux/devpts_fs.h>
#include <linux/slab.h>
+#include <linux/mutex.h>
#ifdef CONFIG_UNIX98_PTYS
static struct tty_driver *ptm_driver;
static struct tty_driver *pts_driver;
+static DEFINE_MUTEX(devpts_mutex);
#endif
static void pty_close(struct tty_struct *tty, struct file *filp)
@@ -45,6 +47,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
wake_up_interruptible(&tty->read_wait);
wake_up_interruptible(&tty->write_wait);
tty->packet = 0;
+ /* Review - krefs on tty_link ?? */
if (!tty->link)
return;
tty->link->packet = 0;
@@ -54,12 +57,15 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
if (tty->driver->subtype == PTY_TYPE_MASTER) {
set_bit(TTY_OTHER_CLOSED, &tty->flags);
#ifdef CONFIG_UNIX98_PTYS
- if (tty->driver == ptm_driver)
+ if (tty->driver == ptm_driver) {
+ mutex_lock(&devpts_mutex);
devpts_pty_kill(tty->link);
+ mutex_unlock(&devpts_mutex);
+ }
#endif
- tty_unlock();
+ tty_unlock(tty);
tty_vhangup(tty->link);
- tty_lock();
+ tty_lock(tty);
}
}
@@ -475,13 +481,17 @@ static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver,
* @idx: tty index
*
* Look up a pty master device. Called under the tty_mutex for now.
- * This provides our locking.
+ * This provides our locking for the tty pointer.
*/
static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
struct inode *pts_inode, int idx)
{
- struct tty_struct *tty = devpts_get_tty(pts_inode, idx);
+ struct tty_struct *tty;
+
+ mutex_lock(&devpts_mutex);
+ tty = devpts_get_tty(pts_inode, idx);
+ mutex_unlock(&devpts_mutex);
/* Master must be open before slave */
if (!tty)
return ERR_PTR(-EIO);
@@ -613,24 +623,29 @@ static int ptmx_open(struct inode *inode, struct file *filp)
return retval;
/* find a device that is not in use. */
- tty_lock();
+ mutex_lock(&devpts_mutex);
index = devpts_new_index(inode);
- tty_unlock();
if (index < 0) {
retval = index;
goto err_file;
}
+ mutex_unlock(&devpts_mutex);
+
mutex_lock(&tty_mutex);
- tty_lock();
+ mutex_lock(&devpts_mutex);
tty = tty_init_dev(ptm_driver, index);
- mutex_unlock(&tty_mutex);
if (IS_ERR(tty)) {
retval = PTR_ERR(tty);
goto out;
}
+ /* The tty returned here is locked so we can safely
+ drop the mutex */
+ mutex_unlock(&devpts_mutex);
+ mutex_unlock(&tty_mutex);
+
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
tty_add_file(tty, filp);
@@ -643,16 +658,17 @@ static int ptmx_open(struct inode *inode, struct file *filp)
if (retval)
goto err_release;
- tty_unlock();
+ tty_unlock(tty);
return 0;
err_release:
- tty_unlock();
+ tty_unlock(tty);
tty_release(inode, filp);
return retval;
out:
+ mutex_unlock(&tty_mutex);
devpts_kill_index(inode, index);
- tty_unlock();
err_file:
+ mutex_unlock(&devpts_mutex);
tty_free_file(filp);
return retval;
}
diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c
index 5ce782529d65..3ed20e435e59 100644
--- a/drivers/tty/serial/68328serial.c
+++ b/drivers/tty/serial/68328serial.c
@@ -17,6 +17,7 @@
#include <asm/dbg.h>
#include <linux/module.h>
#include <linux/errno.h>
+#include <linux/serial.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/timer.h>
@@ -56,8 +57,6 @@
#endif /* CONFIG_M68VZ328 */
#endif /* CONFIG_M68EZ328 */
-#include "68328serial.h"
-
/* Turn off usage of real serial interrupt code, to "support" Copilot */
#ifdef CONFIG_XCOPILOT_BUGS
#undef USE_INTS
@@ -65,33 +64,82 @@
#define USE_INTS
#endif
-static struct m68k_serial m68k_soft[NR_PORTS];
+/*
+ * I believe this is the optimal setting that reduces the number of interrupts.
+ * At high speeds the output might become a little "bursted" (use USTCNT_TXHE
+ * if that bothers you), but in most cases it will not, since we try to
+ * transmit characters every time rs_interrupt is called. Thus, quite often
+ * you'll see that a receive interrupt occures before the transmit one.
+ * -- Vladimir Gurevich
+ */
+#define USTCNT_TX_INTR_MASK (USTCNT_TXEE)
-static unsigned int uart_irqs[NR_PORTS] = UART_IRQ_DEFNS;
+/*
+ * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special
+ * "Old data interrupt" which occures whenever the data stay in the FIFO
+ * longer than 30 bits time. This allows us to use FIFO without compromising
+ * latency. '328 does not have this feature and without the real 328-based
+ * board I would assume that RXRE is the safest setting.
+ *
+ * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of
+ * interrupts. RXFE (receive queue full) causes the system to lose data
+ * at least at 115200 baud
+ *
+ * If your board is busy doing other stuff, you might consider to use
+ * RXRE (data ready intrrupt) instead.
+ *
+ * The other option is to make these INTR masks run-time configurable, so
+ * that people can dynamically adapt them according to the current usage.
+ * -- Vladimir Gurevich
+ */
-/* multiple ports are contiguous in memory */
-m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR;
+/* (es) */
+#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328)
+#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN)
+#elif defined(CONFIG_M68328)
+#define USTCNT_RX_INTR_MASK (USTCNT_RXRE)
+#else
+#error Please, define the Rx interrupt events for your CPU
+#endif
+/* (/es) */
-struct tty_struct m68k_ttys;
-struct m68k_serial *m68k_consinfo = 0;
+/*
+ * This is our internal structure for each serial port's state.
+ */
+struct m68k_serial {
+ struct tty_port tport;
+ char is_cons; /* Is this our console. */
+ int magic;
+ int baud_base;
+ int port;
+ int irq;
+ int type; /* UART type */
+ int custom_divisor;
+ int x_char; /* xon/xoff character */
+ int line;
+ unsigned char *xmit_buf;
+ int xmit_head;
+ int xmit_tail;
+ int xmit_cnt;
+};
-#define M68K_CLOCK (16667000) /* FIXME: 16MHz is likely wrong */
+#define SERIAL_MAGIC 0x5301
-struct tty_driver *serial_driver;
+/*
+ * Define the number of ports supported and their irqs.
+ */
+#define NR_PORTS 1
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
+static struct m68k_serial m68k_soft[NR_PORTS];
-/* Debugging... DEBUG_INTR is bad to use when one of the zs
- * lines is your console ;(
- */
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
+static unsigned int uart_irqs[NR_PORTS] = { UART_IRQ_NUM };
-#define RS_ISR_PASS_LIMIT 256
+/* multiple ports are contiguous in memory */
+m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR;
+
+struct tty_driver *serial_driver;
-static void change_speed(struct m68k_serial *info);
+static void change_speed(struct m68k_serial *info, struct tty_struct *tty);
/*
* Setup for console. Argument comes from the boot command line.
@@ -143,17 +191,6 @@ static int baud_table[] = {
0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
9600, 19200, 38400, 57600, 115200, 0 };
-/* Sets or clears DTR/RTS on the requested line */
-static inline void m68k_rtsdtr(struct m68k_serial *ss, int set)
-{
- if (set) {
- /* set the RTS/CTS line */
- } else {
- /* clear it */
- }
- return;
-}
-
/* Utility routines */
static inline int get_baud(struct m68k_serial *ss)
{
@@ -189,7 +226,8 @@ static void rs_stop(struct tty_struct *tty)
static int rs_put_char(char ch)
{
- int flags, loops = 0;
+ unsigned long flags;
+ int loops = 0;
local_irq_save(flags);
@@ -224,28 +262,9 @@ static void rs_start(struct tty_struct *tty)
local_irq_restore(flags);
}
-/* Drop into either the boot monitor or kadb upon receiving a break
- * from keyboard/console input.
- */
-static void batten_down_hatches(void)
-{
- /* Drop into the debugger */
-}
-
-static void status_handle(struct m68k_serial *info, unsigned short status)
+static void receive_chars(struct m68k_serial *info, struct tty_struct *tty,
+ unsigned short rx)
{
- /* If this is console input and this is a
- * 'break asserted' status change interrupt
- * see if we can drop into the debugger
- */
- if((status & URX_BREAK) && info->break_abort)
- batten_down_hatches();
- return;
-}
-
-static void receive_chars(struct m68k_serial *info, unsigned short rx)
-{
- struct tty_struct *tty = info->tty;
m68328_uart *uart = &uart_addr[info->line];
unsigned char ch, flag;
@@ -259,7 +278,6 @@ static void receive_chars(struct m68k_serial *info, unsigned short rx)
if(info->is_cons) {
if(URX_BREAK & rx) { /* whee, break received */
- status_handle(info, rx);
return;
#ifdef CONFIG_MAGIC_SYSRQ
} else if (ch == 0x10) { /* ^P */
@@ -280,16 +298,13 @@ static void receive_chars(struct m68k_serial *info, unsigned short rx)
flag = TTY_NORMAL;
- if(rx & URX_PARITY_ERROR) {
+ if (rx & URX_PARITY_ERROR)
flag = TTY_PARITY;
- status_handle(info, rx);
- } else if(rx & URX_OVRUN) {
+ else if (rx & URX_OVRUN)
flag = TTY_OVERRUN;
- status_handle(info, rx);
- } else if(rx & URX_FRAME_ERROR) {
+ else if (rx & URX_FRAME_ERROR)
flag = TTY_FRAME;
- status_handle(info, rx);
- }
+
tty_insert_flip_char(tty, ch, flag);
#ifndef CONFIG_XCOPILOT_BUGS
} while((rx = uart->urx.w) & URX_DATA_READY);
@@ -301,7 +316,7 @@ clear_and_exit:
return;
}
-static void transmit_chars(struct m68k_serial *info)
+static void transmit_chars(struct m68k_serial *info, struct tty_struct *tty)
{
m68328_uart *uart = &uart_addr[info->line];
@@ -312,7 +327,7 @@ static void transmit_chars(struct m68k_serial *info)
goto clear_and_return;
}
- if((info->xmit_cnt <= 0) || info->tty->stopped) {
+ if ((info->xmit_cnt <= 0) || !tty || tty->stopped) {
/* That's peculiar... TX ints off */
uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
goto clear_and_return;
@@ -340,6 +355,7 @@ clear_and_return:
irqreturn_t rs_interrupt(int irq, void *dev_id)
{
struct m68k_serial *info = dev_id;
+ struct tty_struct *tty = tty_port_tty_get(&info->tport);
m68328_uart *uart;
unsigned short rx;
unsigned short tx;
@@ -350,20 +366,24 @@ irqreturn_t rs_interrupt(int irq, void *dev_id)
#ifdef USE_INTS
tx = uart->utx.w;
- if (rx & URX_DATA_READY) receive_chars(info, rx);
- if (tx & UTX_TX_AVAIL) transmit_chars(info);
+ if (rx & URX_DATA_READY)
+ receive_chars(info, tty, rx);
+ if (tx & UTX_TX_AVAIL)
+ transmit_chars(info, tty);
#else
- receive_chars(info, rx);
+ receive_chars(info, tty, rx);
#endif
+ tty_kref_put(tty);
+
return IRQ_HANDLED;
}
-static int startup(struct m68k_serial * info)
+static int startup(struct m68k_serial *info, struct tty_struct *tty)
{
m68328_uart *uart = &uart_addr[info->line];
unsigned long flags;
- if (info->flags & S_INITIALIZED)
+ if (info->tport.flags & ASYNC_INITIALIZED)
return 0;
if (!info->xmit_buf) {
@@ -380,7 +400,6 @@ static int startup(struct m68k_serial * info)
*/
uart->ustcnt = USTCNT_UEN;
- info->xmit_fifo_size = 1;
uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN;
(void)uart->urx.w;
@@ -394,17 +413,17 @@ static int startup(struct m68k_serial * info)
uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK;
#endif
- if (info->tty)
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ if (tty)
+ clear_bit(TTY_IO_ERROR, &tty->flags);
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
/*
* and set the speed of the serial port
*/
- change_speed(info);
+ change_speed(info, tty);
- info->flags |= S_INITIALIZED;
+ info->tport.flags |= ASYNC_INITIALIZED;
local_irq_restore(flags);
return 0;
}
@@ -413,13 +432,13 @@ static int startup(struct m68k_serial * info)
* This routine will shutdown a serial port; interrupts are disabled, and
* DTR is dropped if the hangup on close termio flag is on.
*/
-static void shutdown(struct m68k_serial * info)
+static void shutdown(struct m68k_serial *info, struct tty_struct *tty)
{
m68328_uart *uart = &uart_addr[info->line];
unsigned long flags;
uart->ustcnt = 0; /* All off! */
- if (!(info->flags & S_INITIALIZED))
+ if (!(info->tport.flags & ASYNC_INITIALIZED))
return;
local_irq_save(flags);
@@ -429,10 +448,10 @@ static void shutdown(struct m68k_serial * info)
info->xmit_buf = 0;
}
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
+ if (tty)
+ set_bit(TTY_IO_ERROR, &tty->flags);
- info->flags &= ~S_INITIALIZED;
+ info->tport.flags &= ~ASYNC_INITIALIZED;
local_irq_restore(flags);
}
@@ -488,7 +507,7 @@ struct {
* This routine is called to set the UART divisor registers to match
* the specified baud rate for a serial port.
*/
-static void change_speed(struct m68k_serial *info)
+static void change_speed(struct m68k_serial *info, struct tty_struct *tty)
{
m68328_uart *uart = &uart_addr[info->line];
unsigned short port;
@@ -496,9 +515,7 @@ static void change_speed(struct m68k_serial *info)
unsigned cflag;
int i;
- if (!info->tty || !info->tty->termios)
- return;
- cflag = info->tty->termios->c_cflag;
+ cflag = tty->termios->c_cflag;
if (!(port = info->port))
return;
@@ -510,7 +527,6 @@ static void change_speed(struct m68k_serial *info)
i = (i & ~CBAUDEX) + B38400;
}
- info->baud = baud_table[i];
uart->ubaud = PUT_FIELD(UBAUD_DIVIDE, hw_baud_table[i].divisor) |
PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
@@ -807,10 +823,10 @@ static int get_serial_info(struct m68k_serial * info,
tmp.line = info->line;
tmp.port = info->port;
tmp.irq = info->irq;
- tmp.flags = info->flags;
+ tmp.flags = info->tport.flags;
tmp.baud_base = info->baud_base;
- tmp.close_delay = info->close_delay;
- tmp.closing_wait = info->closing_wait;
+ tmp.close_delay = info->tport.close_delay;
+ tmp.closing_wait = info->tport.closing_wait;
tmp.custom_divisor = info->custom_divisor;
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT;
@@ -818,9 +834,10 @@ static int get_serial_info(struct m68k_serial * info,
return 0;
}
-static int set_serial_info(struct m68k_serial * info,
+static int set_serial_info(struct m68k_serial *info, struct tty_struct *tty,
struct serial_struct * new_info)
{
+ struct tty_port *port = &info->tport;
struct serial_struct new_serial;
struct m68k_serial old_info;
int retval = 0;
@@ -834,17 +851,17 @@ static int set_serial_info(struct m68k_serial * info,
if (!capable(CAP_SYS_ADMIN)) {
if ((new_serial.baud_base != info->baud_base) ||
(new_serial.type != info->type) ||
- (new_serial.close_delay != info->close_delay) ||
- ((new_serial.flags & ~S_USR_MASK) !=
- (info->flags & ~S_USR_MASK)))
+ (new_serial.close_delay != port->close_delay) ||
+ ((new_serial.flags & ~ASYNC_USR_MASK) !=
+ (port->flags & ~ASYNC_USR_MASK)))
return -EPERM;
- info->flags = ((info->flags & ~S_USR_MASK) |
- (new_serial.flags & S_USR_MASK));
+ port->flags = ((port->flags & ~ASYNC_USR_MASK) |
+ (new_serial.flags & ASYNC_USR_MASK));
info->custom_divisor = new_serial.custom_divisor;
goto check_and_exit;
}
- if (info->count > 1)
+ if (port->count > 1)
return -EBUSY;
/*
@@ -853,14 +870,14 @@ static int set_serial_info(struct m68k_serial * info,
*/
info->baud_base = new_serial.baud_base;
- info->flags = ((info->flags & ~S_FLAGS) |
- (new_serial.flags & S_FLAGS));
+ port->flags = ((port->flags & ~ASYNC_FLAGS) |
+ (new_serial.flags & ASYNC_FLAGS));
info->type = new_serial.type;
- info->close_delay = new_serial.close_delay;
- info->closing_wait = new_serial.closing_wait;
+ port->close_delay = new_serial.close_delay;
+ port->closing_wait = new_serial.closing_wait;
check_and_exit:
- retval = startup(info);
+ retval = startup(info, tty);
return retval;
}
@@ -946,7 +963,7 @@ static int rs_ioctl(struct tty_struct *tty,
return get_serial_info(info,
(struct serial_struct *) arg);
case TIOCSSERIAL:
- return set_serial_info(info,
+ return set_serial_info(info, tty,
(struct serial_struct *) arg);
case TIOCSERGETLSR: /* Get line status register */
return get_lsr_info(info, (unsigned int *) arg);
@@ -965,7 +982,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- change_speed(info);
+ change_speed(info, tty);
if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) {
@@ -988,6 +1005,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
static void rs_close(struct tty_struct *tty, struct file * filp)
{
struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
+ struct tty_port *port = &info->tport;
m68328_uart *uart = &uart_addr[info->line];
unsigned long flags;
@@ -1001,7 +1019,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
return;
}
- if ((tty->count == 1) && (info->count != 1)) {
+ if ((tty->count == 1) && (port->count != 1)) {
/*
* Uh, oh. tty->count is 1, which means that the tty
* structure will be freed. Info->count should always
@@ -1010,26 +1028,26 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
* serial port won't be shutdown.
*/
printk("rs_close: bad serial port count; tty->count is 1, "
- "info->count is %d\n", info->count);
- info->count = 1;
+ "port->count is %d\n", port->count);
+ port->count = 1;
}
- if (--info->count < 0) {
+ if (--port->count < 0) {
printk("rs_close: bad serial port count for ttyS%d: %d\n",
- info->line, info->count);
- info->count = 0;
+ info->line, port->count);
+ port->count = 0;
}
- if (info->count) {
+ if (port->count) {
local_irq_restore(flags);
return;
}
- info->flags |= S_CLOSING;
+ port->flags |= ASYNC_CLOSING;
/*
* Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters.
*/
tty->closing = 1;
- if (info->closing_wait != S_CLOSING_WAIT_NONE)
- tty_wait_until_sent(tty, info->closing_wait);
+ if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, port->closing_wait);
/*
* At this point we stop accepting input. To do this, we
* disable the receive line status interrupts, and tell the
@@ -1040,13 +1058,12 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
uart->ustcnt &= ~USTCNT_RXEN;
uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK);
- shutdown(info);
+ shutdown(info, tty);
rs_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
- info->event = 0;
- info->tty = NULL;
+ tty_port_tty_set(&info->tport, NULL);
#warning "This is not and has never been valid so fix it"
#if 0
if (tty->ldisc.num != ldiscs[N_TTY].num) {
@@ -1058,14 +1075,13 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
(tty->ldisc.open)(tty);
}
#endif
- if (info->blocked_open) {
- if (info->close_delay) {
- msleep_interruptible(jiffies_to_msecs(info->close_delay));
- }
- wake_up_interruptible(&info->open_wait);
+ if (port->blocked_open) {
+ if (port->close_delay)
+ msleep_interruptible(jiffies_to_msecs(port->close_delay));
+ wake_up_interruptible(&port->open_wait);
}
- info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING);
- wake_up_interruptible(&info->close_wait);
+ port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
+ wake_up_interruptible(&port->close_wait);
local_irq_restore(flags);
}
@@ -1080,107 +1096,14 @@ void rs_hangup(struct tty_struct *tty)
return;
rs_flush_buffer(tty);
- shutdown(info);
- info->event = 0;
- info->count = 0;
- info->flags &= ~S_NORMAL_ACTIVE;
- info->tty = NULL;
- wake_up_interruptible(&info->open_wait);
+ shutdown(info, tty);
+ info->tport.count = 0;
+ info->tport.flags &= ~ASYNC_NORMAL_ACTIVE;
+ tty_port_tty_set(&info->tport, NULL);
+ wake_up_interruptible(&info->tport.open_wait);
}
/*
- * ------------------------------------------------------------
- * rs_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
- struct m68k_serial *info)
-{
- DECLARE_WAITQUEUE(wait, current);
- int retval;
- int do_clocal = 0;
-
- /*
- * If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (info->flags & S_CLOSING) {
- interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
- if (info->flags & S_HUP_NOTIFY)
- return -EAGAIN;
- else
- return -ERESTARTSYS;
-#else
- return -EAGAIN;
-#endif
- }
-
- /*
- * If non-blocking mode is set, or the port is not enabled,
- * then make the check up front and then exit.
- */
- if ((filp->f_flags & O_NONBLOCK) ||
- (tty->flags & (1 << TTY_IO_ERROR))) {
- info->flags |= S_NORMAL_ACTIVE;
- return 0;
- }
-
- if (tty->termios->c_cflag & CLOCAL)
- do_clocal = 1;
-
- /*
- * Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, info->count is dropped by one, so that
- * rs_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
- retval = 0;
- add_wait_queue(&info->open_wait, &wait);
-
- info->count--;
- info->blocked_open++;
- while (1) {
- local_irq_disable();
- m68k_rtsdtr(info, 1);
- local_irq_enable();
- current->state = TASK_INTERRUPTIBLE;
- if (tty_hung_up_p(filp) ||
- !(info->flags & S_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
- if (info->flags & S_HUP_NOTIFY)
- retval = -EAGAIN;
- else
- retval = -ERESTARTSYS;
-#else
- retval = -EAGAIN;
-#endif
- break;
- }
- if (!(info->flags & S_CLOSING) && do_clocal)
- break;
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- tty_unlock();
- schedule();
- tty_lock();
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&info->open_wait, &wait);
- if (!tty_hung_up_p(filp))
- info->count++;
- info->blocked_open--;
-
- if (retval)
- return retval;
- info->flags |= S_NORMAL_ACTIVE;
- return 0;
-}
-
-/*
* This routine is called whenever a serial port is opened. It
* enables interrupts for a serial port, linking in its S structure into
* the IRQ chain. It also performs the serial-specific
@@ -1196,18 +1119,18 @@ int rs_open(struct tty_struct *tty, struct file * filp)
if (serial_paranoia_check(info, tty->name, "rs_open"))
return -ENODEV;
- info->count++;
+ info->tport.count++;
tty->driver_data = info;
- info->tty = tty;
+ tty_port_tty_set(&info->tport, tty);
/*
* Start up serial port
*/
- retval = startup(info);
+ retval = startup(info, tty);
if (retval)
return retval;
- return block_til_ready(tty, filp, info);
+ return tty_port_block_til_ready(&info->tport, tty, filp);
}
/* Finally, routines used to initialize the serial driver. */
@@ -1235,11 +1158,15 @@ static const struct tty_operations rs_ops = {
.set_ldisc = rs_set_ldisc,
};
+static const struct tty_port_operations rs_port_ops = {
+};
+
/* rs_init inits the driver */
static int __init
rs68328_init(void)
{
- int flags, i;
+ unsigned long flags;
+ int i;
struct m68k_serial *info;
serial_driver = alloc_tty_driver(NR_PORTS);
@@ -1273,19 +1200,13 @@ rs68328_init(void)
for(i=0;i<NR_PORTS;i++) {
info = &m68k_soft[i];
+ tty_port_init(&info->tport);
+ info->tport.ops = &rs_port_ops;
info->magic = SERIAL_MAGIC;
info->port = (int) &uart_addr[i];
- info->tty = NULL;
info->irq = uart_irqs[i];
info->custom_divisor = 16;
- info->close_delay = 50;
- info->closing_wait = 3000;
info->x_char = 0;
- info->event = 0;
- info->count = 0;
- info->blocked_open = 0;
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
info->line = i;
info->is_cons = 1; /* Means shortcuts work */
diff --git a/drivers/tty/serial/68328serial.h b/drivers/tty/serial/68328serial.h
deleted file mode 100644
index 3d2faabd766f..000000000000
--- a/drivers/tty/serial/68328serial.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/* 68328serial.h: Definitions for the mc68328 serial driver.
- *
- * Copyright (C) 1995 David S. Miller <davem@caip.rutgers.edu>
- * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>
- * Copyright (C) 1998, 1999 D. Jeff Dionne <jeff@uclinux.org>
- * Copyright (C) 1999 Vladimir Gurevich <vgurevic@cisco.com>
- *
- * VZ Support/Fixes Evan Stawnyczy <e@lineo.ca>
- */
-
-#ifndef _MC683XX_SERIAL_H
-#define _MC683XX_SERIAL_H
-
-
-struct serial_struct {
- int type;
- int line;
- int port;
- int irq;
- int flags;
- int xmit_fifo_size;
- int custom_divisor;
- int baud_base;
- unsigned short close_delay;
- char reserved_char[2];
- int hub6; /* FIXME: We don't have AT&T Hub6 boards! */
- unsigned short closing_wait; /* time to wait before closing */
- unsigned short closing_wait2; /* no longer used... */
- int reserved[4];
-};
-
-/*
- * For the close wait times, 0 means wait forever for serial port to
- * flush its output. 65535 means don't wait at all.
- */
-#define S_CLOSING_WAIT_INF 0
-#define S_CLOSING_WAIT_NONE 65535
-
-/*
- * Definitions for S_struct (and serial_struct) flags field
- */
-#define S_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes
- on the callout port */
-#define S_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */
-#define S_SAK 0x0004 /* Secure Attention Key (Orange book) */
-#define S_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
-
-#define S_SPD_MASK 0x0030
-#define S_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */
-
-#define S_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */
-#define S_SPD_CUST 0x0030 /* Use user-specified divisor */
-
-#define S_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */
-#define S_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */
-#define S_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
-#define S_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */
-#define S_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */
-
-#define S_FLAGS 0x0FFF /* Possible legal S flags */
-#define S_USR_MASK 0x0430 /* Legal flags that non-privileged
- * users can set or reset */
-
-/* Internal flags used only by kernel/chr_drv/serial.c */
-#define S_INITIALIZED 0x80000000 /* Serial port was initialized */
-#define S_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
-#define S_NORMAL_ACTIVE 0x20000000 /* Normal device is active */
-#define S_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */
-#define S_CLOSING 0x08000000 /* Serial port is closing */
-#define S_CTS_FLOW 0x04000000 /* Do CTS flow control */
-#define S_CHECK_CD 0x02000000 /* i.e., CLOCAL */
-
-/* Software state per channel */
-
-#ifdef __KERNEL__
-
-/*
- * I believe this is the optimal setting that reduces the number of interrupts.
- * At high speeds the output might become a little "bursted" (use USTCNT_TXHE
- * if that bothers you), but in most cases it will not, since we try to
- * transmit characters every time rs_interrupt is called. Thus, quite often
- * you'll see that a receive interrupt occures before the transmit one.
- * -- Vladimir Gurevich
- */
-#define USTCNT_TX_INTR_MASK (USTCNT_TXEE)
-
-/*
- * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special
- * "Old data interrupt" which occures whenever the data stay in the FIFO
- * longer than 30 bits time. This allows us to use FIFO without compromising
- * latency. '328 does not have this feature and without the real 328-based
- * board I would assume that RXRE is the safest setting.
- *
- * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of
- * interrupts. RXFE (receive queue full) causes the system to lose data
- * at least at 115200 baud
- *
- * If your board is busy doing other stuff, you might consider to use
- * RXRE (data ready intrrupt) instead.
- *
- * The other option is to make these INTR masks run-time configurable, so
- * that people can dynamically adapt them according to the current usage.
- * -- Vladimir Gurevich
- */
-
-/* (es) */
-#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328)
-#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN)
-#elif defined(CONFIG_M68328)
-#define USTCNT_RX_INTR_MASK (USTCNT_RXRE)
-#else
-#error Please, define the Rx interrupt events for your CPU
-#endif
-/* (/es) */
-
-/*
- * This is our internal structure for each serial port's state.
- *
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
- *
- * For definitions of the flags field, see tty.h
- */
-
-struct m68k_serial {
- char soft_carrier; /* Use soft carrier on this channel */
- char break_abort; /* Is serial console in, so process brk/abrt */
- char is_cons; /* Is this our console. */
-
- /* We need to know the current clock divisor
- * to read the bps rate the chip has currently
- * loaded.
- */
- unsigned char clk_divisor; /* May be 1, 16, 32, or 64 */
- int baud;
- int magic;
- int baud_base;
- int port;
- int irq;
- int flags; /* defined in tty.h */
- int type; /* UART type */
- struct tty_struct *tty;
- int read_status_mask;
- int ignore_status_mask;
- int timeout;
- int xmit_fifo_size;
- int custom_divisor;
- int x_char; /* xon/xoff character */
- int close_delay;
- unsigned short closing_wait;
- unsigned short closing_wait2;
- unsigned long event;
- unsigned long last_active;
- int line;
- int count; /* # of fd on device */
- int blocked_open; /* # of blocked opens */
- unsigned char *xmit_buf;
- int xmit_head;
- int xmit_tail;
- int xmit_cnt;
- wait_queue_head_t open_wait;
- wait_queue_head_t close_wait;
-};
-
-
-#define SERIAL_MAGIC 0x5301
-
-/*
- * The size of the serial xmit buffer is 1 page, or 4096 bytes
- */
-#define SERIAL_XMIT_SIZE 4096
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define RS_EVENT_WRITE_WAKEUP 0
-
-/*
- * Define the number of ports supported and their irqs.
- */
-#define NR_PORTS 1
-#define UART_IRQ_DEFNS {UART_IRQ_NUM}
-
-#endif /* __KERNEL__ */
-#endif /* !(_MC683XX_SERIAL_H) */
diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c
index 5c27f7e6c9f1..47d061b9ad4d 100644
--- a/drivers/tty/serial/8250/8250.c
+++ b/drivers/tty/serial/8250/8250.c
@@ -284,7 +284,20 @@ static const struct serial8250_config uart_config[] = {
},
};
-#if defined(CONFIG_MIPS_ALCHEMY)
+/* Uart divisor latch read */
+static int default_serial_dl_read(struct uart_8250_port *up)
+{
+ return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8;
+}
+
+/* Uart divisor latch write */
+static void default_serial_dl_write(struct uart_8250_port *up, int value)
+{
+ serial_out(up, UART_DLL, value & 0xff);
+ serial_out(up, UART_DLM, value >> 8 & 0xff);
+}
+
+#ifdef CONFIG_MIPS_ALCHEMY
/* Au1x00 UART hardware has a weird register layout */
static const u8 au_io_in_map[] = {
@@ -305,22 +318,32 @@ static const u8 au_io_out_map[] = {
[UART_MCR] = 6,
};
-/* sane hardware needs no mapping */
-static inline int map_8250_in_reg(struct uart_port *p, int offset)
+static unsigned int au_serial_in(struct uart_port *p, int offset)
+{
+ offset = au_io_in_map[offset] << p->regshift;
+ return __raw_readl(p->membase + offset);
+}
+
+static void au_serial_out(struct uart_port *p, int offset, int value)
+{
+ offset = au_io_out_map[offset] << p->regshift;
+ __raw_writel(value, p->membase + offset);
+}
+
+/* Au1x00 haven't got a standard divisor latch */
+static int au_serial_dl_read(struct uart_8250_port *up)
{
- if (p->iotype != UPIO_AU)
- return offset;
- return au_io_in_map[offset];
+ return __raw_readl(up->port.membase + 0x28);
}
-static inline int map_8250_out_reg(struct uart_port *p, int offset)
+static void au_serial_dl_write(struct uart_8250_port *up, int value)
{
- if (p->iotype != UPIO_AU)
- return offset;
- return au_io_out_map[offset];
+ __raw_writel(value, up->port.membase + 0x28);
}
-#elif defined(CONFIG_SERIAL_8250_RM9K)
+#endif
+
+#ifdef CONFIG_SERIAL_8250_RM9K
static const u8
regmap_in[8] = {
@@ -344,87 +367,79 @@ static const u8
[UART_SCR] = 0x2c
};
-static inline int map_8250_in_reg(struct uart_port *p, int offset)
+static unsigned int rm9k_serial_in(struct uart_port *p, int offset)
{
- if (p->iotype != UPIO_RM9000)
- return offset;
- return regmap_in[offset];
+ offset = regmap_in[offset] << p->regshift;
+ return readl(p->membase + offset);
}
-static inline int map_8250_out_reg(struct uart_port *p, int offset)
+static void rm9k_serial_out(struct uart_port *p, int offset, int value)
{
- if (p->iotype != UPIO_RM9000)
- return offset;
- return regmap_out[offset];
+ offset = regmap_out[offset] << p->regshift;
+ writel(value, p->membase + offset);
}
-#else
+static int rm9k_serial_dl_read(struct uart_8250_port *up)
+{
+ return ((__raw_readl(up->port.membase + 0x10) << 8) |
+ (__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff;
+}
-/* sane hardware needs no mapping */
-#define map_8250_in_reg(up, offset) (offset)
-#define map_8250_out_reg(up, offset) (offset)
+static void rm9k_serial_dl_write(struct uart_8250_port *up, int value)
+{
+ __raw_writel(value, up->port.membase + 0x08);
+ __raw_writel(value >> 8, up->port.membase + 0x10);
+}
#endif
static unsigned int hub6_serial_in(struct uart_port *p, int offset)
{
- offset = map_8250_in_reg(p, offset) << p->regshift;
+ offset = offset << p->regshift;
outb(p->hub6 - 1 + offset, p->iobase);
return inb(p->iobase + 1);
}
static void hub6_serial_out(struct uart_port *p, int offset, int value)
{
- offset = map_8250_out_reg(p, offset) << p->regshift;
+ offset = offset << p->regshift;
outb(p->hub6 - 1 + offset, p->iobase);
outb(value, p->iobase + 1);
}
static unsigned int mem_serial_in(struct uart_port *p, int offset)
{
- offset = map_8250_in_reg(p, offset) << p->regshift;
+ offset = offset << p->regshift;
return readb(p->membase + offset);
}
static void mem_serial_out(struct uart_port *p, int offset, int value)
{
- offset = map_8250_out_reg(p, offset) << p->regshift;
+ offset = offset << p->regshift;
writeb(value, p->membase + offset);
}
static void mem32_serial_out(struct uart_port *p, int offset, int value)
{
- offset = map_8250_out_reg(p, offset) << p->regshift;
+ offset = offset << p->regshift;
writel(value, p->membase + offset);
}
static unsigned int mem32_serial_in(struct uart_port *p, int offset)
{
- offset = map_8250_in_reg(p, offset) << p->regshift;
+ offset = offset << p->regshift;
return readl(p->membase + offset);
}
-static unsigned int au_serial_in(struct uart_port *p, int offset)
-{
- offset = map_8250_in_reg(p, offset) << p->regshift;
- return __raw_readl(p->membase + offset);
-}
-
-static void au_serial_out(struct uart_port *p, int offset, int value)
-{
- offset = map_8250_out_reg(p, offset) << p->regshift;
- __raw_writel(value, p->membase + offset);
-}
-
static unsigned int io_serial_in(struct uart_port *p, int offset)
{
- offset = map_8250_in_reg(p, offset) << p->regshift;
+ offset = offset << p->regshift;
return inb(p->iobase + offset);
}
static void io_serial_out(struct uart_port *p, int offset, int value)
{
- offset = map_8250_out_reg(p, offset) << p->regshift;
+ offset = offset << p->regshift;
outb(value, p->iobase + offset);
}
@@ -434,6 +449,10 @@ static void set_io_from_upio(struct uart_port *p)
{
struct uart_8250_port *up =
container_of(p, struct uart_8250_port, port);
+
+ up->dl_read = default_serial_dl_read;
+ up->dl_write = default_serial_dl_write;
+
switch (p->iotype) {
case UPIO_HUB6:
p->serial_in = hub6_serial_in;
@@ -445,16 +464,28 @@ static void set_io_from_upio(struct uart_port *p)
p->serial_out = mem_serial_out;
break;
- case UPIO_RM9000:
case UPIO_MEM32:
p->serial_in = mem32_serial_in;
p->serial_out = mem32_serial_out;
break;
+#ifdef CONFIG_SERIAL_8250_RM9K
+ case UPIO_RM9000:
+ p->serial_in = rm9k_serial_in;
+ p->serial_out = rm9k_serial_out;
+ up->dl_read = rm9k_serial_dl_read;
+ up->dl_write = rm9k_serial_dl_write;
+ break;
+#endif
+
+#ifdef CONFIG_MIPS_ALCHEMY
case UPIO_AU:
p->serial_in = au_serial_in;
p->serial_out = au_serial_out;
+ up->dl_read = au_serial_dl_read;
+ up->dl_write = au_serial_dl_write;
break;
+#endif
default:
p->serial_in = io_serial_in;
@@ -481,59 +512,6 @@ serial_port_out_sync(struct uart_port *p, int offset, int value)
}
}
-/* Uart divisor latch read */
-static inline int _serial_dl_read(struct uart_8250_port *up)
-{
- return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8;
-}
-
-/* Uart divisor latch write */
-static inline void _serial_dl_write(struct uart_8250_port *up, int value)
-{
- serial_out(up, UART_DLL, value & 0xff);
- serial_out(up, UART_DLM, value >> 8 & 0xff);
-}
-
-#if defined(CONFIG_MIPS_ALCHEMY)
-/* Au1x00 haven't got a standard divisor latch */
-static int serial_dl_read(struct uart_8250_port *up)
-{
- if (up->port.iotype == UPIO_AU)
- return __raw_readl(up->port.membase + 0x28);
- else
- return _serial_dl_read(up);
-}
-
-static void serial_dl_write(struct uart_8250_port *up, int value)
-{
- if (up->port.iotype == UPIO_AU)
- __raw_writel(value, up->port.membase + 0x28);
- else
- _serial_dl_write(up, value);
-}
-#elif defined(CONFIG_SERIAL_8250_RM9K)
-static int serial_dl_read(struct uart_8250_port *up)
-{
- return (up->port.iotype == UPIO_RM9000) ?
- (((__raw_readl(up->port.membase + 0x10) << 8) |
- (__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff) :
- _serial_dl_read(up);
-}
-
-static void serial_dl_write(struct uart_8250_port *up, int value)
-{
- if (up->port.iotype == UPIO_RM9000) {
- __raw_writel(value, up->port.membase + 0x08);
- __raw_writel(value >> 8, up->port.membase + 0x10);
- } else {
- _serial_dl_write(up, value);
- }
-}
-#else
-#define serial_dl_read(up) _serial_dl_read(up)
-#define serial_dl_write(up, value) _serial_dl_write(up, value)
-#endif
-
/*
* For the 16C950
*/
@@ -568,6 +546,16 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
}
}
+void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p)
+{
+ unsigned char fcr;
+
+ serial8250_clear_fifos(p);
+ fcr = uart_config[p->port.type].fcr;
+ serial_out(p, UART_FCR, fcr);
+}
+EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos);
+
/*
* IER sleep support. UARTs which have EFRs need the "extended
* capability" bit enabled. Note that on XR16C850s, we need to
@@ -1332,27 +1320,6 @@ static void serial8250_enable_ms(struct uart_port *port)
}
/*
- * Clear the Tegra rx fifo after a break
- *
- * FIXME: This needs to become a port specific callback once we have a
- * framework for this
- */
-static void clear_rx_fifo(struct uart_8250_port *up)
-{
- unsigned int status, tmout = 10000;
- do {
- status = serial_in(up, UART_LSR);
- if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
- status = serial_in(up, UART_RX);
- else
- break;
- if (--tmout == 0)
- break;
- udelay(1);
- } while (1);
-}
-
-/*
* serial8250_rx_chars: processes according to the passed in LSR
* value, and returns the remaining LSR bits not handled
* by this Rx routine.
@@ -1386,20 +1353,10 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
up->lsr_saved_flags = 0;
if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
- /*
- * For statistics only
- */
if (lsr & UART_LSR_BI) {
lsr &= ~(UART_LSR_FE | UART_LSR_PE);
port->icount.brk++;
/*
- * If tegra port then clear the rx fifo to
- * accept another break/character.
- */
- if (port->type == PORT_TEGRA)
- clear_rx_fifo(up);
-
- /*
* We do the SysRQ and SAK checking
* here because otherwise the break
* may get masked by ignore_status_mask
@@ -2280,10 +2237,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
quot++;
if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) {
- if (baud < 2400)
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
- else
- fcr = uart_config[port->type].fcr;
+ fcr = uart_config[port->type].fcr;
+ if (baud < 2400) {
+ fcr &= ~UART_FCR_TRIGGER_MASK;
+ fcr |= UART_FCR_TRIGGER_1;
+ }
}
/*
@@ -3037,6 +2995,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
port.serial_in = p->serial_in;
port.serial_out = p->serial_out;
port.handle_irq = p->handle_irq;
+ port.handle_break = p->handle_break;
port.set_termios = p->set_termios;
port.pm = p->pm;
port.dev = &dev->dev;
@@ -3153,7 +3112,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
}
/**
- * serial8250_register_port - register a serial port
+ * serial8250_register_8250_port - register a serial port
* @port: serial port template
*
* Configure the serial port specified by the request. If the
@@ -3165,50 +3124,56 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *
*
* On success the port is ready to use and the line number is returned.
*/
-int serial8250_register_port(struct uart_port *port)
+int serial8250_register_8250_port(struct uart_8250_port *up)
{
struct uart_8250_port *uart;
int ret = -ENOSPC;
- if (port->uartclk == 0)
+ if (up->port.uartclk == 0)
return -EINVAL;
mutex_lock(&serial_mutex);
- uart = serial8250_find_match_or_unused(port);
+ uart = serial8250_find_match_or_unused(&up->port);
if (uart) {
uart_remove_one_port(&serial8250_reg, &uart->port);
- uart->port.iobase = port->iobase;
- uart->port.membase = port->membase;
- uart->port.irq = port->irq;
- uart->port.irqflags = port->irqflags;
- uart->port.uartclk = port->uartclk;
- uart->port.fifosize = port->fifosize;
- uart->port.regshift = port->regshift;
- uart->port.iotype = port->iotype;
- uart->port.flags = port->flags | UPF_BOOT_AUTOCONF;
- uart->port.mapbase = port->mapbase;
- uart->port.private_data = port->private_data;
- if (port->dev)
- uart->port.dev = port->dev;
-
- if (port->flags & UPF_FIXED_TYPE)
- serial8250_init_fixed_type_port(uart, port->type);
+ uart->port.iobase = up->port.iobase;
+ uart->port.membase = up->port.membase;
+ uart->port.irq = up->port.irq;
+ uart->port.irqflags = up->port.irqflags;
+ uart->port.uartclk = up->port.uartclk;
+ uart->port.fifosize = up->port.fifosize;
+ uart->port.regshift = up->port.regshift;
+ uart->port.iotype = up->port.iotype;
+ uart->port.flags = up->port.flags | UPF_BOOT_AUTOCONF;
+ uart->port.mapbase = up->port.mapbase;
+ uart->port.private_data = up->port.private_data;
+ if (up->port.dev)
+ uart->port.dev = up->port.dev;
+
+ if (up->port.flags & UPF_FIXED_TYPE)
+ serial8250_init_fixed_type_port(uart, up->port.type);
set_io_from_upio(&uart->port);
/* Possibly override default I/O functions. */
- if (port->serial_in)
- uart->port.serial_in = port->serial_in;
- if (port->serial_out)
- uart->port.serial_out = port->serial_out;
- if (port->handle_irq)
- uart->port.handle_irq = port->handle_irq;
+ if (up->port.serial_in)
+ uart->port.serial_in = up->port.serial_in;
+ if (up->port.serial_out)
+ uart->port.serial_out = up->port.serial_out;
+ if (up->port.handle_irq)
+ uart->port.handle_irq = up->port.handle_irq;
/* Possibly override set_termios call */
- if (port->set_termios)
- uart->port.set_termios = port->set_termios;
- if (port->pm)
- uart->port.pm = port->pm;
+ if (up->port.set_termios)
+ uart->port.set_termios = up->port.set_termios;
+ if (up->port.pm)
+ uart->port.pm = up->port.pm;
+ if (up->port.handle_break)
+ uart->port.handle_break = up->port.handle_break;
+ if (up->dl_read)
+ uart->dl_read = up->dl_read;
+ if (up->dl_write)
+ uart->dl_write = up->dl_write;
if (serial8250_isa_config != NULL)
serial8250_isa_config(0, &uart->port,
@@ -3222,6 +3187,29 @@ int serial8250_register_port(struct uart_port *port)
return ret;
}
+EXPORT_SYMBOL(serial8250_register_8250_port);
+
+/**
+ * serial8250_register_port - register a serial port
+ * @port: serial port template
+ *
+ * Configure the serial port specified by the request. If the
+ * port exists and is in use, it is hung up and unregistered
+ * first.
+ *
+ * The port is then probed and if necessary the IRQ is autodetected
+ * If this fails an error is returned.
+ *
+ * On success the port is ready to use and the line number is returned.
+ */
+int serial8250_register_port(struct uart_port *port)
+{
+ struct uart_8250_port up;
+
+ memset(&up, 0, sizeof(up));
+ memcpy(&up.port, port, sizeof(*port));
+ return serial8250_register_8250_port(&up);
+}
EXPORT_SYMBOL(serial8250_register_port);
/**
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 2868a1da254d..f9719d167c8d 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -37,6 +37,10 @@ struct uart_8250_port {
unsigned char lsr_saved_flags;
#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
unsigned char msr_saved_flags;
+
+ /* 8250 specific callbacks */
+ int (*dl_read)(struct uart_8250_port *);
+ void (*dl_write)(struct uart_8250_port *, int);
};
struct old_serial_port {
@@ -96,6 +100,18 @@ static inline void serial_out(struct uart_8250_port *up, int offset, int value)
up->port.serial_out(&up->port, offset, value);
}
+void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p);
+
+static inline int serial_dl_read(struct uart_8250_port *up)
+{
+ return up->dl_read(up);
+}
+
+static inline void serial_dl_write(struct uart_8250_port *up, int value)
+{
+ up->dl_write(up, value);
+}
+
#if defined(__alpha__) && !defined(CONFIG_PCI)
/*
* Digital did something really horribly wrong with the OUT1 and OUT2
diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c
new file mode 100644
index 000000000000..3a0363e7f3a7
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_em.c
@@ -0,0 +1,186 @@
+/*
+ * Renesas Emma Mobile 8250 driver
+ *
+ * Copyright (C) 2012 Magnus Damm
+ *
+ * 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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+
+#include "8250.h"
+
+#define UART_DLL_EM 9
+#define UART_DLM_EM 10
+
+struct serial8250_em_priv {
+ struct clk *sclk;
+ int line;
+};
+
+static void serial8250_em_serial_out(struct uart_port *p, int offset, int value)
+{
+ switch (offset) {
+ case UART_TX: /* TX @ 0x00 */
+ writeb(value, p->membase);
+ break;
+ case UART_FCR: /* FCR @ 0x0c (+1) */
+ case UART_LCR: /* LCR @ 0x10 (+1) */
+ case UART_MCR: /* MCR @ 0x14 (+1) */
+ case UART_SCR: /* SCR @ 0x20 (+1) */
+ writel(value, p->membase + ((offset + 1) << 2));
+ break;
+ case UART_IER: /* IER @ 0x04 */
+ value &= 0x0f; /* only 4 valid bits - not Xscale */
+ /* fall-through */
+ case UART_DLL_EM: /* DLL @ 0x24 (+9) */
+ case UART_DLM_EM: /* DLM @ 0x28 (+9) */
+ writel(value, p->membase + (offset << 2));
+ }
+}
+
+static unsigned int serial8250_em_serial_in(struct uart_port *p, int offset)
+{
+ switch (offset) {
+ case UART_RX: /* RX @ 0x00 */
+ return readb(p->membase);
+ case UART_MCR: /* MCR @ 0x14 (+1) */
+ case UART_LSR: /* LSR @ 0x18 (+1) */
+ case UART_MSR: /* MSR @ 0x1c (+1) */
+ case UART_SCR: /* SCR @ 0x20 (+1) */
+ return readl(p->membase + ((offset + 1) << 2));
+ case UART_IER: /* IER @ 0x04 */
+ case UART_IIR: /* IIR @ 0x08 */
+ case UART_DLL_EM: /* DLL @ 0x24 (+9) */
+ case UART_DLM_EM: /* DLM @ 0x28 (+9) */
+ return readl(p->membase + (offset << 2));
+ }
+ return 0;
+}
+
+static int serial8250_em_serial_dl_read(struct uart_8250_port *up)
+{
+ return serial_in(up, UART_DLL_EM) | serial_in(up, UART_DLM_EM) << 8;
+}
+
+static void serial8250_em_serial_dl_write(struct uart_8250_port *up, int value)
+{
+ serial_out(up, UART_DLL_EM, value & 0xff);
+ serial_out(up, UART_DLM_EM, value >> 8 & 0xff);
+}
+
+static int __devinit serial8250_em_probe(struct platform_device *pdev)
+{
+ struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ struct serial8250_em_priv *priv;
+ struct uart_8250_port up;
+ int ret = -EINVAL;
+
+ if (!regs || !irq) {
+ dev_err(&pdev->dev, "missing registers or irq\n");
+ goto err0;
+ }
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(&pdev->dev, "unable to allocate private data\n");
+ ret = -ENOMEM;
+ goto err0;
+ }
+
+ priv->sclk = clk_get(&pdev->dev, "sclk");
+ if (IS_ERR(priv->sclk)) {
+ dev_err(&pdev->dev, "unable to get clock\n");
+ ret = PTR_ERR(priv->sclk);
+ goto err1;
+ }
+
+ memset(&up, 0, sizeof(up));
+ up.port.mapbase = regs->start;
+ up.port.irq = irq->start;
+ up.port.type = PORT_UNKNOWN;
+ up.port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP;
+ up.port.dev = &pdev->dev;
+ up.port.private_data = priv;
+
+ clk_enable(priv->sclk);
+ up.port.uartclk = clk_get_rate(priv->sclk);
+
+ up.port.iotype = UPIO_MEM32;
+ up.port.serial_in = serial8250_em_serial_in;
+ up.port.serial_out = serial8250_em_serial_out;
+ up.dl_read = serial8250_em_serial_dl_read;
+ up.dl_write = serial8250_em_serial_dl_write;
+
+ ret = serial8250_register_8250_port(&up);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "unable to register 8250 port\n");
+ goto err2;
+ }
+
+ priv->line = ret;
+ platform_set_drvdata(pdev, priv);
+ return 0;
+
+ err2:
+ clk_disable(priv->sclk);
+ clk_put(priv->sclk);
+ err1:
+ kfree(priv);
+ err0:
+ return ret;
+}
+
+static int __devexit serial8250_em_remove(struct platform_device *pdev)
+{
+ struct serial8250_em_priv *priv = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(priv->line);
+ clk_disable(priv->sclk);
+ clk_put(priv->sclk);
+ kfree(priv);
+ return 0;
+}
+
+static const struct of_device_id serial8250_em_dt_ids[] __devinitconst = {
+ { .compatible = "renesas,em-uart", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, serial8250_em_dt_ids);
+
+static struct platform_driver serial8250_em_platform_driver = {
+ .driver = {
+ .name = "serial8250-em",
+ .of_match_table = serial8250_em_dt_ids,
+ .owner = THIS_MODULE,
+ },
+ .probe = serial8250_em_probe,
+ .remove = __devexit_p(serial8250_em_remove),
+};
+
+module_platform_driver(serial8250_em_platform_driver);
+
+MODULE_AUTHOR("Magnus Damm");
+MODULE_DESCRIPTION("Renesas Emma Mobile 8250 Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/8250/8250_mca.c b/drivers/tty/serial/8250/8250_mca.c
deleted file mode 100644
index d20abf04541e..000000000000
--- a/drivers/tty/serial/8250/8250_mca.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2005 Russell King.
- * Data taken from include/asm-i386/serial.h
- *
- * 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/module.h>
-#include <linux/init.h>
-#include <linux/mca.h>
-#include <linux/serial_8250.h>
-
-/*
- * FIXME: Should we be doing AUTO_IRQ here?
- */
-#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
-#define MCA_FLAGS UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ
-#else
-#define MCA_FLAGS UPF_BOOT_AUTOCONF | UPF_SKIP_TEST
-#endif
-
-#define PORT(_base,_irq) \
- { \
- .iobase = _base, \
- .irq = _irq, \
- .uartclk = 1843200, \
- .iotype = UPIO_PORT, \
- .flags = MCA_FLAGS, \
- }
-
-static struct plat_serial8250_port mca_data[] = {
- PORT(0x3220, 3),
- PORT(0x3228, 3),
- PORT(0x4220, 3),
- PORT(0x4228, 3),
- PORT(0x5220, 3),
- PORT(0x5228, 3),
- { },
-};
-
-static struct platform_device mca_device = {
- .name = "serial8250",
- .id = PLAT8250_DEV_MCA,
- .dev = {
- .platform_data = mca_data,
- },
-};
-
-static int __init mca_init(void)
-{
- if (!MCA_bus)
- return -ENODEV;
- return platform_device_register(&mca_device);
-}
-
-module_init(mca_init);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("8250 serial probe module for MCA ports");
-MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index 858dca865d6a..28e7c7cce893 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/tty.h>
+#include <linux/serial_reg.h>
#include <linux/serial_core.h>
#include <linux/8250_pci.h>
#include <linux/bitops.h>
@@ -1092,11 +1093,49 @@ static int skip_tx_en_setup(struct serial_private *priv,
return pci_default_setup(priv, board, port, idx);
}
+static void kt_handle_break(struct uart_port *p)
+{
+ struct uart_8250_port *up =
+ container_of(p, struct uart_8250_port, port);
+ /*
+ * On receipt of a BI, serial device in Intel ME (Intel
+ * management engine) needs to have its fifos cleared for sane
+ * SOL (Serial Over Lan) output.
+ */
+ serial8250_clear_and_reinit_fifos(up);
+}
+
+static unsigned int kt_serial_in(struct uart_port *p, int offset)
+{
+ struct uart_8250_port *up =
+ container_of(p, struct uart_8250_port, port);
+ unsigned int val;
+
+ /*
+ * When the Intel ME (management engine) gets reset its serial
+ * port registers could return 0 momentarily. Functions like
+ * serial8250_console_write, read and save the IER, perform
+ * some operation and then restore it. In order to avoid
+ * setting IER register inadvertently to 0, if the value read
+ * is 0, double check with ier value in uart_8250_port and use
+ * that instead. up->ier should be the same value as what is
+ * currently configured.
+ */
+ val = inb(p->iobase + offset);
+ if (offset == UART_IER) {
+ if (val == 0)
+ val = up->ier;
+ }
+ return val;
+}
+
static int kt_serial_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_port *port, int idx)
{
port->flags |= UPF_BUG_THRE;
+ port->serial_in = kt_serial_in;
+ port->handle_break = kt_handle_break;
return skip_tx_en_setup(priv, board, port, idx);
}
@@ -1609,54 +1648,72 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = 0x8811,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = 0x8812,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = 0x8813,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = 0x8814,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = 0x10DB,
.device = 0x8027,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = 0x10DB,
.device = 0x8028,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = 0x10DB,
.device = 0x8029,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = 0x10DB,
.device = 0x800C,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
{
.vendor = 0x10DB,
.device = 0x800D,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
.init = pci_eg20t_init,
.setup = pci_default_setup,
},
@@ -2775,6 +2832,12 @@ void pciserial_suspend_ports(struct serial_private *priv)
for (i = 0; i < priv->nr; i++)
if (priv->line[i] >= 0)
serial8250_suspend_port(priv->line[i]);
+
+ /*
+ * Ensure that every init quirk is properly torn down
+ */
+ if (priv->quirk->exit)
+ priv->quirk->exit(priv->dev);
}
EXPORT_SYMBOL_GPL(pciserial_suspend_ports);
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 591f8018e7dd..a27dd0569bd7 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -241,15 +241,6 @@ config SERIAL_8250_RSA
help
::: To be written :::
-config SERIAL_8250_MCA
- tristate "Support 8250-type ports on MCA buses"
- depends on SERIAL_8250 != n && MCA
- help
- Say Y here if you have a MCA serial ports.
-
- To compile this driver as a module, choose M here: the module
- will be called 8250_mca.
-
config SERIAL_8250_ACORN
tristate "Acorn expansion card serial port support"
depends on ARCH_ACORN && SERIAL_8250
@@ -278,3 +269,11 @@ config SERIAL_8250_DW
help
Selecting this option will enable handling of the extra features
present in the Synopsys DesignWare APB UART.
+
+config SERIAL_8250_EM
+ tristate "Support for Emma Mobile intergrated serial port"
+ depends on SERIAL_8250 && ARM && HAVE_CLK
+ help
+ Selecting this option will add support for the integrated serial
+ port hardware found on the Emma Mobile line of processors.
+ If unsure, say N.
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 867bba738908..d7533c7d2c1a 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -15,6 +15,6 @@ obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o
obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o
obj-$(CONFIG_SERIAL_8250_EXAR_ST16C554) += 8250_exar_st16c554.o
obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
-obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o
obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
+obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 3d569cd68f58..4ad721fb8405 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -52,6 +52,7 @@
#include <linux/scatterlist.h>
#include <linux/delay.h>
#include <linux/types.h>
+#include <linux/pinctrl/consumer.h>
#include <asm/io.h>
#include <asm/sizes.h>
@@ -67,30 +68,6 @@
#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
#define UART_DUMMY_DR_RX (1 << 16)
-
-#define UART_WA_SAVE_NR 14
-
-static void pl011_lockup_wa(unsigned long data);
-static const u32 uart_wa_reg[UART_WA_SAVE_NR] = {
- ST_UART011_DMAWM,
- ST_UART011_TIMEOUT,
- ST_UART011_LCRH_RX,
- UART011_IBRD,
- UART011_FBRD,
- ST_UART011_LCRH_TX,
- UART011_IFLS,
- ST_UART011_XFCR,
- ST_UART011_XON1,
- ST_UART011_XON2,
- ST_UART011_XOFF1,
- ST_UART011_XOFF2,
- UART011_CR,
- UART011_IMSC
-};
-
-static u32 uart_wa_regdata[UART_WA_SAVE_NR];
-static DECLARE_TASKLET(pl011_lockup_tlet, pl011_lockup_wa, 0);
-
/* There is by now at least one vendor with differing details, so handle it */
struct vendor_data {
unsigned int ifls;
@@ -100,6 +77,7 @@ struct vendor_data {
bool oversampling;
bool interrupt_may_hang; /* vendor-specific */
bool dma_threshold;
+ bool cts_event_workaround;
};
static struct vendor_data vendor_arm = {
@@ -109,6 +87,7 @@ static struct vendor_data vendor_arm = {
.lcrh_rx = UART011_LCRH,
.oversampling = false,
.dma_threshold = false,
+ .cts_event_workaround = false,
};
static struct vendor_data vendor_st = {
@@ -119,6 +98,7 @@ static struct vendor_data vendor_st = {
.oversampling = true,
.interrupt_may_hang = true,
.dma_threshold = true,
+ .cts_event_workaround = true,
};
static struct uart_amba_port *amba_ports[UART_NR];
@@ -1054,69 +1034,6 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
#define pl011_dma_flush_buffer NULL
#endif
-
-/*
- * pl011_lockup_wa
- * This workaround aims to break the deadlock situation
- * when after long transfer over uart in hardware flow
- * control, uart interrupt registers cannot be cleared.
- * Hence uart transfer gets blocked.
- *
- * It is seen that during such deadlock condition ICR
- * don't get cleared even on multiple write. This leads
- * pass_counter to decrease and finally reach zero. This
- * can be taken as trigger point to run this UART_BT_WA.
- *
- */
-static void pl011_lockup_wa(unsigned long data)
-{
- struct uart_amba_port *uap = amba_ports[0];
- void __iomem *base = uap->port.membase;
- struct circ_buf *xmit = &uap->port.state->xmit;
- struct tty_struct *tty = uap->port.state->port.tty;
- int buf_empty_retries = 200;
- int loop;
-
- /* Stop HCI layer from submitting data for tx */
- tty->hw_stopped = 1;
- while (!uart_circ_empty(xmit)) {
- if (buf_empty_retries-- == 0)
- break;
- udelay(100);
- }
-
- /* Backup registers */
- for (loop = 0; loop < UART_WA_SAVE_NR; loop++)
- uart_wa_regdata[loop] = readl(base + uart_wa_reg[loop]);
-
- /* Disable UART so that FIFO data is flushed out */
- writew(0x00, uap->port.membase + UART011_CR);
-
- /* Soft reset UART module */
- if (uap->port.dev->platform_data) {
- struct amba_pl011_data *plat;
-
- plat = uap->port.dev->platform_data;
- if (plat->reset)
- plat->reset();
- }
-
- /* Restore registers */
- for (loop = 0; loop < UART_WA_SAVE_NR; loop++)
- writew(uart_wa_regdata[loop] ,
- uap->port.membase + uart_wa_reg[loop]);
-
- /* Initialise the old status of the modem signals */
- uap->old_status = readw(uap->port.membase + UART01x_FR) &
- UART01x_FR_MODEM_ANY;
-
- if (readl(base + UART011_MIS) & 0x2)
- printk(KERN_EMERG "UART_BT_WA: ***FAILED***\n");
-
- /* Start Tx/Rx */
- tty->hw_stopped = 0;
-}
-
static void pl011_stop_tx(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -1245,12 +1162,26 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
unsigned long flags;
unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
int handled = 0;
+ unsigned int dummy_read;
spin_lock_irqsave(&uap->port.lock, flags);
status = readw(uap->port.membase + UART011_MIS);
if (status) {
do {
+ if (uap->vendor->cts_event_workaround) {
+ /* workaround to make sure that all bits are unlocked.. */
+ writew(0x00, uap->port.membase + UART011_ICR);
+
+ /*
+ * WA: introduce 26ns(1 uart clk) delay before W1C;
+ * single apb access will incur 2 pclk(133.12Mhz) delay,
+ * so add 2 dummy reads
+ */
+ dummy_read = readw(uap->port.membase + UART011_ICR);
+ dummy_read = readw(uap->port.membase + UART011_ICR);
+ }
+
writew(status & ~(UART011_TXIS|UART011_RTIS|
UART011_RXIS),
uap->port.membase + UART011_ICR);
@@ -1267,11 +1198,8 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
if (status & UART011_TXIS)
pl011_tx_chars(uap);
- if (pass_counter-- == 0) {
- if (uap->interrupt_may_hang)
- tasklet_schedule(&pl011_lockup_tlet);
+ if (pass_counter-- == 0)
break;
- }
status = readw(uap->port.membase + UART011_MIS);
} while (status != 0);
@@ -1916,6 +1844,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
{
struct uart_amba_port *uap;
struct vendor_data *vendor = id->data;
+ struct pinctrl *pinctrl;
void __iomem *base;
int i, ret;
@@ -1940,6 +1869,12 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
goto free;
}
+ pinctrl = devm_pinctrl_get_select_default(&dev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ goto unmap;
+ }
+
uap->clk = clk_get(&dev->dev, NULL);
if (IS_ERR(uap->clk)) {
ret = PTR_ERR(uap->clk);
diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c
index 5832fdef11e9..bd97db23985b 100644
--- a/drivers/tty/serial/bfin_uart.c
+++ b/drivers/tty/serial/bfin_uart.c
@@ -1,7 +1,7 @@
/*
* Blackfin On-Chip Serial Driver
*
- * Copyright 2006-2010 Analog Devices Inc.
+ * Copyright 2006-2011 Analog Devices Inc.
*
* Enter bugs at http://blackfin.uclinux.org/
*
@@ -35,10 +35,6 @@
#include <asm/portmux.h>
#include <asm/cacheflush.h>
#include <asm/dma.h>
-
-#define port_membase(uart) (((struct bfin_serial_port *)(uart))->port.membase)
-#define get_lsr_cache(uart) (((struct bfin_serial_port *)(uart))->lsr)
-#define put_lsr_cache(uart, v) (((struct bfin_serial_port *)(uart))->lsr = (v))
#include <asm/bfin_serial.h>
#ifdef CONFIG_SERIAL_BFIN_MODULE
@@ -166,7 +162,7 @@ static void bfin_serial_stop_tx(struct uart_port *port)
uart->tx_count = 0;
uart->tx_done = 1;
#else
-#ifdef CONFIG_BF54x
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF60x)
/* Clear TFI bit */
UART_PUT_LSR(uart, TFI);
#endif
@@ -337,7 +333,7 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
struct circ_buf *xmit = &uart->port.state->xmit;
if (uart_circ_empty(xmit) || uart_tx_stopped(&uart->port)) {
-#ifdef CONFIG_BF54x
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF60x)
/* Clear TFI bit */
UART_PUT_LSR(uart, TFI);
#endif
@@ -536,7 +532,7 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
*/
UART_CLEAR_IER(uart, ETBEI);
uart->port.icount.tx += uart->tx_count;
- if (!uart_circ_empty(xmit)) {
+ if (!(xmit->tail == 0 && xmit->head == 0)) {
xmit->tail = (xmit->tail + uart->tx_count) & (UART_XMIT_SIZE - 1);
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
@@ -553,7 +549,7 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
{
struct bfin_serial_port *uart = dev_id;
- unsigned short irqstat;
+ unsigned int irqstat;
int x_pos, pos;
spin_lock(&uart->rx_lock);
@@ -586,7 +582,7 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
static unsigned int bfin_serial_tx_empty(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
- unsigned short lsr;
+ unsigned int lsr;
lsr = UART_GET_LSR(uart);
if (lsr & TEMT)
@@ -598,7 +594,7 @@ static unsigned int bfin_serial_tx_empty(struct uart_port *port)
static void bfin_serial_break_ctl(struct uart_port *port, int break_state)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
- u16 lcr = UART_GET_LCR(uart);
+ u32 lcr = UART_GET_LCR(uart);
if (break_state)
lcr |= SB;
else
@@ -745,7 +741,7 @@ static int bfin_serial_startup(struct uart_port *port)
}
/* CTS RTS PINs are negative assertive. */
- UART_PUT_MCR(uart, ACTS);
+ UART_PUT_MCR(uart, UART_GET_MCR(uart) | ACTS);
UART_SET_IER(uart, EDSSI);
}
#endif
@@ -803,7 +799,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
unsigned long flags;
unsigned int baud, quot;
- unsigned short val, ier, lcr = 0;
+ unsigned int ier, lcr = 0;
switch (termios->c_cflag & CSIZE) {
case CS8:
@@ -875,26 +871,23 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
/* Disable UART */
ier = UART_GET_IER(uart);
+ UART_PUT_GCTL(uart, UART_GET_GCTL(uart) & ~UCEN);
UART_DISABLE_INTS(uart);
- /* Set DLAB in LCR to Access DLL and DLH */
+ /* Set DLAB in LCR to Access CLK */
UART_SET_DLAB(uart);
- UART_PUT_DLL(uart, quot & 0xFF);
- UART_PUT_DLH(uart, (quot >> 8) & 0xFF);
+ UART_PUT_CLK(uart, quot);
SSYNC();
/* Clear DLAB in LCR to Access THR RBR IER */
UART_CLEAR_DLAB(uart);
- UART_PUT_LCR(uart, lcr);
+ UART_PUT_LCR(uart, (UART_GET_LCR(uart) & ~LCR_MASK) | lcr);
/* Enable UART */
UART_ENABLE_INTS(uart, ier);
-
- val = UART_GET_GCTL(uart);
- val |= UCEN;
- UART_PUT_GCTL(uart, val);
+ UART_PUT_GCTL(uart, UART_GET_GCTL(uart) | UCEN);
/* Port speed changed, update the per-port timeout. */
uart_update_timeout(port, termios->c_cflag, baud);
@@ -954,17 +947,17 @@ bfin_serial_verify_port(struct uart_port *port, struct serial_struct *ser)
static void bfin_serial_set_ldisc(struct uart_port *port, int ld)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
- unsigned short val;
+ unsigned int val;
switch (ld) {
case N_IRDA:
val = UART_GET_GCTL(uart);
- val |= (IREN | RPOLC);
+ val |= (UMOD_IRDA | RPOLC);
UART_PUT_GCTL(uart, val);
break;
default:
val = UART_GET_GCTL(uart);
- val &= ~(IREN | RPOLC);
+ val &= ~(UMOD_MASK | RPOLC);
UART_PUT_GCTL(uart, val);
}
}
@@ -972,13 +965,13 @@ static void bfin_serial_set_ldisc(struct uart_port *port, int ld)
static void bfin_serial_reset_irda(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
- unsigned short val;
+ unsigned int val;
val = UART_GET_GCTL(uart);
- val &= ~(IREN | RPOLC);
+ val &= ~(UMOD_MASK | RPOLC);
UART_PUT_GCTL(uart, val);
SSYNC();
- val |= (IREN | RPOLC);
+ val |= (UMOD_IRDA | RPOLC);
UART_PUT_GCTL(uart, val);
SSYNC();
}
@@ -1070,12 +1063,12 @@ static void __init
bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
int *parity, int *bits)
{
- unsigned short status;
+ unsigned int status;
status = UART_GET_IER(uart) & (ERBFI | ETBEI);
if (status == (ERBFI | ETBEI)) {
/* ok, the port was enabled */
- u16 lcr, dlh, dll;
+ u32 lcr, clk;
lcr = UART_GET_LCR(uart);
@@ -1086,30 +1079,17 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
else
*parity = 'o';
}
- switch (lcr & 0x03) {
- case 0:
- *bits = 5;
- break;
- case 1:
- *bits = 6;
- break;
- case 2:
- *bits = 7;
- break;
- case 3:
- *bits = 8;
- break;
- }
- /* Set DLAB in LCR to Access DLL and DLH */
+ *bits = ((lcr & WLS_MASK) >> WLS_OFFSET) + 5;
+
+ /* Set DLAB in LCR to Access CLK */
UART_SET_DLAB(uart);
- dll = UART_GET_DLL(uart);
- dlh = UART_GET_DLH(uart);
+ clk = UART_GET_CLK(uart);
/* Clear DLAB in LCR to Access THR RBR IER */
UART_CLEAR_DLAB(uart);
- *baud = get_sclk() / (16*(dll | dlh << 8));
+ *baud = get_sclk() / (16*clk);
}
pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits);
}
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index 836fe2731234..d0f719fafc84 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -40,7 +40,6 @@
#include <mach/hardware.h>
#include <asm/irq.h>
-#include <asm/hardware/clps7111.h>
#define UART_NR 2
diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c
index 5b07c0c3a10c..7264d4d26717 100644
--- a/drivers/tty/serial/crisv10.c
+++ b/drivers/tty/serial/crisv10.c
@@ -952,19 +952,6 @@ static const struct control_pins e100_modem_pins[NR_PORTS] =
/* Input */
#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask)
-
-/*
- * tmp_buf is used as a temporary buffer by serial_write. We need to
- * lock it in case the memcpy_fromfs blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char *tmp_buf;
-static DEFINE_MUTEX(tmp_buf_mutex);
-
/* Calculate the chartime depending on baudrate, numbor of bits etc. */
static void update_char_time(struct e100_serial * info)
{
@@ -3150,7 +3137,7 @@ static int rs_raw_write(struct tty_struct *tty,
/* first some sanity checks */
- if (!tty || !info->xmit.buf || !tmp_buf)
+ if (!tty || !info->xmit.buf)
return 0;
#ifdef SERIAL_DEBUG_DATA
@@ -3989,7 +3976,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
*/
if (tty_hung_up_p(filp) ||
(info->flags & ASYNC_CLOSING)) {
- wait_event_interruptible_tty(info->close_wait,
+ wait_event_interruptible_tty(tty, info->close_wait,
!(info->flags & ASYNC_CLOSING));
#ifdef SERIAL_DO_RESTART
if (info->flags & ASYNC_HUP_NOTIFY)
@@ -4065,9 +4052,9 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
printk("block_til_ready blocking: ttyS%d, count = %d\n",
info->line, info->count);
#endif
- tty_unlock();
+ tty_unlock(tty);
schedule();
- tty_lock();
+ tty_lock(tty);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&info->open_wait, &wait);
@@ -4106,7 +4093,6 @@ rs_open(struct tty_struct *tty, struct file * filp)
{
struct e100_serial *info;
int retval;
- unsigned long page;
int allocated_resources = 0;
info = rs_table + tty->index;
@@ -4124,23 +4110,12 @@ rs_open(struct tty_struct *tty, struct file * filp)
tty->low_latency = !!(info->flags & ASYNC_LOW_LATENCY);
- if (!tmp_buf) {
- page = get_zeroed_page(GFP_KERNEL);
- if (!page) {
- return -ENOMEM;
- }
- if (tmp_buf)
- free_page(page);
- else
- tmp_buf = (unsigned char *) page;
- }
-
/*
* If the port is in the middle of closing, bail out now
*/
if (tty_hung_up_p(filp) ||
(info->flags & ASYNC_CLOSING)) {
- wait_event_interruptible_tty(info->close_wait,
+ wait_event_interruptible_tty(tty, info->close_wait,
!(info->flags & ASYNC_CLOSING));
#ifdef SERIAL_DO_RESTART
return ((info->flags & ASYNC_HUP_NOTIFY) ?
@@ -4487,6 +4462,7 @@ static int __init rs_init(void)
info->enabled = 0;
}
}
+ tty_port_init(&info->port);
info->uses_dma_in = 0;
info->uses_dma_out = 0;
info->line = i;
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index e7feceeebc2f..ec206732f68c 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -47,6 +47,7 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -1464,6 +1465,7 @@ static int serial_imx_probe(struct platform_device *pdev)
void __iomem *base;
int ret = 0;
struct resource *res;
+ struct pinctrl *pinctrl;
sport = kzalloc(sizeof(*sport), GFP_KERNEL);
if (!sport)
@@ -1503,6 +1505,12 @@ static int serial_imx_probe(struct platform_device *pdev)
sport->timer.function = imx_timeout;
sport->timer.data = (unsigned long)sport;
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ goto unmap;
+ }
+
sport->clk = clk_get(&pdev->dev, "uart");
if (IS_ERR(sport->clk)) {
ret = PTR_ERR(sport->clk);
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index 55fd362b9879..ec56d8397aae 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -32,6 +32,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
+#include <linux/pinctrl/consumer.h>
#include <asm/cacheflush.h>
@@ -369,6 +370,8 @@ static void mxs_auart_settermios(struct uart_port *u,
writel(ctrl, u->membase + AUART_LINECTRL);
writel(ctrl2, u->membase + AUART_CTRL2);
+
+ uart_update_timeout(u, termios->c_cflag, baud);
}
static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
@@ -678,6 +681,7 @@ static int __devinit mxs_auart_probe(struct platform_device *pdev)
u32 version;
int ret = 0;
struct resource *r;
+ struct pinctrl *pinctrl;
s = kzalloc(sizeof(struct mxs_auart_port), GFP_KERNEL);
if (!s) {
@@ -685,6 +689,12 @@ static int __devinit mxs_auart_probe(struct platform_device *pdev)
goto out;
}
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ goto out_free;
+ }
+
s->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(s->clk)) {
ret = PTR_ERR(s->clk);
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index e8c9cee07d00..5410c0637266 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -12,10 +12,13 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/delay.h>
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
+#include <linux/of_serial.h>
#include <linux/of_platform.h>
#include <linux/nwpserial.h>
@@ -24,6 +27,26 @@ struct of_serial_info {
int line;
};
+#ifdef CONFIG_ARCH_TEGRA
+void tegra_serial_handle_break(struct uart_port *p)
+{
+ unsigned int status, tmout = 10000;
+
+ do {
+ status = p->serial_in(p, UART_LSR);
+ if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS))
+ status = p->serial_in(p, UART_RX);
+ else
+ break;
+ if (--tmout == 0)
+ break;
+ udelay(1);
+ } while (1);
+}
+/* FIXME remove this export when tegra finishes conversion to open firmware */
+EXPORT_SYMBOL_GPL(tegra_serial_handle_break);
+#endif
+
/*
* Fill a struct uart_port for a given device node
*/
@@ -84,6 +107,9 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
| UPF_FIXED_PORT | UPF_FIXED_TYPE;
port->dev = &ofdev->dev;
+ if (type == PORT_TEGRA)
+ port->handle_break = tegra_serial_handle_break;
+
return 0;
}
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index d00b38eb268e..d3cda0cb2df0 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -44,6 +44,13 @@
#include <plat/dmtimer.h>
#include <plat/omap-serial.h>
+#define UART_BUILD_REVISION(x, y) (((x) << 8) | (y))
+
+#define OMAP_UART_REV_42 0x0402
+#define OMAP_UART_REV_46 0x0406
+#define OMAP_UART_REV_52 0x0502
+#define OMAP_UART_REV_63 0x0603
+
#define DEFAULT_CLK_SPEED 48000000 /* 48Mhz*/
/* SCR register bitmasks */
@@ -53,6 +60,17 @@
#define OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT 6
#define OMAP_UART_FCR_RX_FIFO_TRIG_MASK (0x3 << 6)
+/* MVR register bitmasks */
+#define OMAP_UART_MVR_SCHEME_SHIFT 30
+
+#define OMAP_UART_LEGACY_MVR_MAJ_MASK 0xf0
+#define OMAP_UART_LEGACY_MVR_MAJ_SHIFT 4
+#define OMAP_UART_LEGACY_MVR_MIN_MASK 0x0f
+
+#define OMAP_UART_MVR_MAJ_MASK 0x700
+#define OMAP_UART_MVR_MAJ_SHIFT 8
+#define OMAP_UART_MVR_MIN_MASK 0x3f
+
static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
/* Forward declaration of functions */
@@ -1346,6 +1364,59 @@ static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)
return;
}
+static void omap_serial_fill_features_erratas(struct uart_omap_port *up)
+{
+ u32 mvr, scheme;
+ u16 revision, major, minor;
+
+ mvr = serial_in(up, UART_OMAP_MVER);
+
+ /* Check revision register scheme */
+ scheme = mvr >> OMAP_UART_MVR_SCHEME_SHIFT;
+
+ switch (scheme) {
+ case 0: /* Legacy Scheme: OMAP2/3 */
+ /* MINOR_REV[0:4], MAJOR_REV[4:7] */
+ major = (mvr & OMAP_UART_LEGACY_MVR_MAJ_MASK) >>
+ OMAP_UART_LEGACY_MVR_MAJ_SHIFT;
+ minor = (mvr & OMAP_UART_LEGACY_MVR_MIN_MASK);
+ break;
+ case 1:
+ /* New Scheme: OMAP4+ */
+ /* MINOR_REV[0:5], MAJOR_REV[8:10] */
+ major = (mvr & OMAP_UART_MVR_MAJ_MASK) >>
+ OMAP_UART_MVR_MAJ_SHIFT;
+ minor = (mvr & OMAP_UART_MVR_MIN_MASK);
+ break;
+ default:
+ dev_warn(&up->pdev->dev,
+ "Unknown %s revision, defaulting to highest\n",
+ up->name);
+ /* highest possible revision */
+ major = 0xff;
+ minor = 0xff;
+ }
+
+ /* normalize revision for the driver */
+ revision = UART_BUILD_REVISION(major, minor);
+
+ switch (revision) {
+ case OMAP_UART_REV_46:
+ up->errata |= (UART_ERRATA_i202_MDR1_ACCESS |
+ UART_ERRATA_i291_DMA_FORCEIDLE);
+ break;
+ case OMAP_UART_REV_52:
+ up->errata |= (UART_ERRATA_i202_MDR1_ACCESS |
+ UART_ERRATA_i291_DMA_FORCEIDLE);
+ break;
+ case OMAP_UART_REV_63:
+ up->errata |= UART_ERRATA_i202_MDR1_ACCESS;
+ break;
+ default:
+ break;
+ }
+}
+
static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev)
{
struct omap_uart_port_info *omap_up_info;
@@ -1439,7 +1510,6 @@ static int serial_omap_probe(struct platform_device *pdev)
"%d\n", DEFAULT_CLK_SPEED);
}
up->uart_dma.uart_base = mem->start;
- up->errata = omap_up_info->errata;
if (omap_up_info->dma_enabled) {
up->uart_dma.uart_dma_tx = dma_tx->start;
@@ -1469,6 +1539,8 @@ static int serial_omap_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
+ omap_serial_fill_features_erratas(up);
+
ui[up->port.line] = up;
serial_omap_add_console_port(up);
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index c2816f494807..4fdec6a6b758 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -39,6 +39,7 @@ enum {
PCH_UART_HANDLED_RX_ERR_INT_SHIFT,
PCH_UART_HANDLED_RX_TRG_INT_SHIFT,
PCH_UART_HANDLED_MS_INT_SHIFT,
+ PCH_UART_HANDLED_LS_INT_SHIFT,
};
enum {
@@ -63,6 +64,8 @@ enum {
PCH_UART_HANDLED_RX_TRG_INT_SHIFT)<<1))
#define PCH_UART_HANDLED_MS_INT (1<<((PCH_UART_HANDLED_MS_INT_SHIFT)<<1))
+#define PCH_UART_HANDLED_LS_INT (1<<((PCH_UART_HANDLED_LS_INT_SHIFT)<<1))
+
#define PCH_UART_RBR 0x00
#define PCH_UART_THR 0x00
@@ -229,7 +232,6 @@ struct eg20t_port {
int start_tx;
int start_rx;
int tx_empty;
- int int_dis_flag;
int trigger;
int trigger_level;
struct pch_uart_buffer rxbuf;
@@ -237,7 +239,6 @@ struct eg20t_port {
unsigned int fcr;
unsigned int mcr;
unsigned int use_dma;
- unsigned int use_dma_flag;
struct dma_async_tx_descriptor *desc_tx;
struct dma_async_tx_descriptor *desc_rx;
struct pch_dma_slave param_tx;
@@ -560,14 +561,10 @@ static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf,
return i;
}
-static unsigned int pch_uart_hal_get_iid(struct eg20t_port *priv)
+static unsigned char pch_uart_hal_get_iid(struct eg20t_port *priv)
{
- unsigned int iir;
- int ret;
-
- iir = ioread8(priv->membase + UART_IIR);
- ret = (iir & (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP));
- return ret;
+ return ioread8(priv->membase + UART_IIR) &\
+ (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP);
}
static u8 pch_uart_hal_get_line_status(struct eg20t_port *priv)
@@ -666,10 +663,13 @@ static void pch_free_dma(struct uart_port *port)
dma_release_channel(priv->chan_rx);
priv->chan_rx = NULL;
}
- if (sg_dma_address(&priv->sg_rx))
- dma_free_coherent(port->dev, port->fifosize,
- sg_virt(&priv->sg_rx),
- sg_dma_address(&priv->sg_rx));
+
+ if (priv->rx_buf_dma) {
+ dma_free_coherent(port->dev, port->fifosize, priv->rx_buf_virt,
+ priv->rx_buf_dma);
+ priv->rx_buf_virt = NULL;
+ priv->rx_buf_dma = 0;
+ }
return;
}
@@ -1053,12 +1053,17 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
unsigned int handled;
u8 lsr;
int ret = 0;
- unsigned int iid;
+ unsigned char iid;
unsigned long flags;
+ int next = 1;
+ u8 msr;
spin_lock_irqsave(&priv->port.lock, flags);
handled = 0;
- while ((iid = pch_uart_hal_get_iid(priv)) > 1) {
+ while (next) {
+ iid = pch_uart_hal_get_iid(priv);
+ if (iid & PCH_UART_IIR_IP) /* No Interrupt */
+ break;
switch (iid) {
case PCH_UART_IID_RLS: /* Receiver Line Status */
lsr = pch_uart_hal_get_line_status(priv);
@@ -1066,6 +1071,8 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
UART_LSR_PE | UART_LSR_OE)) {
pch_uart_err_ir(priv, lsr);
ret = PCH_UART_HANDLED_RX_ERR_INT;
+ } else {
+ ret = PCH_UART_HANDLED_LS_INT;
}
break;
case PCH_UART_IID_RDR: /* Received Data Ready */
@@ -1092,20 +1099,22 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
ret = handle_tx(priv);
break;
case PCH_UART_IID_MS: /* Modem Status */
- ret = PCH_UART_HANDLED_MS_INT;
+ msr = pch_uart_hal_get_modem(priv);
+ next = 0; /* MS ir prioirty is the lowest. So, MS ir
+ means final interrupt */
+ if ((msr & UART_MSR_ANY_DELTA) == 0)
+ break;
+ ret |= PCH_UART_HANDLED_MS_INT;
break;
default: /* Never junp to this label */
- dev_err(priv->port.dev, "%s:iid=%d (%lu)\n", __func__,
+ dev_err(priv->port.dev, "%s:iid=%02x (%lu)\n", __func__,
iid, jiffies);
ret = -1;
+ next = 0;
break;
}
handled |= (unsigned int)ret;
}
- if (handled == 0 && iid <= 1) {
- if (priv->int_dis_flag)
- priv->int_dis_flag = 0;
- }
spin_unlock_irqrestore(&priv->port.lock, flags);
return IRQ_RETVAL(handled);
@@ -1200,7 +1209,6 @@ static void pch_uart_stop_rx(struct uart_port *port)
priv = container_of(port, struct eg20t_port, port);
priv->start_rx = 0;
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT);
- priv->int_dis_flag = 1;
}
/* Enable the modem status interrupts. */
@@ -1447,7 +1455,6 @@ static int pch_uart_verify_port(struct uart_port *port,
__func__);
return -EOPNOTSUPP;
#endif
- priv->use_dma_flag = 1;
dev_info(priv->port.dev, "PCH UART : Use DMA Mode\n");
if (!priv->use_dma)
pch_request_dma(port);
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 9c4c05b2825b..246b823c1b27 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -2282,6 +2282,7 @@ void uart_unregister_driver(struct uart_driver *drv)
tty_unregister_driver(p);
put_tty_driver(p);
kfree(drv->state);
+ drv->state = NULL;
drv->tty_driver = NULL;
}
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 3158e17b665c..4604153b7954 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1052,9 +1052,17 @@ static int sci_request_irq(struct sci_port *port)
if (SCIx_IRQ_IS_MUXED(port)) {
i = SCIx_MUX_IRQ;
irq = up->irq;
- } else
+ } else {
irq = port->cfg->irqs[i];
+ /*
+ * Certain port types won't support all of the
+ * available interrupt sources.
+ */
+ if (unlikely(!irq))
+ continue;
+ }
+
desc = sci_irq_desc + i;
port->irqstr[j] = kasprintf(GFP_KERNEL, "%s:%s",
dev_name(up->dev), desc->desc);
@@ -1094,6 +1102,15 @@ static void sci_free_irq(struct sci_port *port)
* IRQ first.
*/
for (i = 0; i < SCIx_NR_IRQS; i++) {
+ unsigned int irq = port->cfg->irqs[i];
+
+ /*
+ * Certain port types won't support all of the available
+ * interrupt sources.
+ */
+ if (unlikely(!irq))
+ continue;
+
free_irq(port->cfg->irqs[i], port);
kfree(port->irqstr[i]);
@@ -1564,10 +1581,32 @@ static void sci_enable_ms(struct uart_port *port)
static void sci_break_ctl(struct uart_port *port, int break_state)
{
- /*
- * Not supported by hardware. Most parts couple break and rx
- * interrupts together, with break detection always enabled.
- */
+ struct sci_port *s = to_sci_port(port);
+ struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR;
+ unsigned short scscr, scsptr;
+
+ /* check wheter the port has SCSPTR */
+ if (!reg->size) {
+ /*
+ * Not supported by hardware. Most parts couple break and rx
+ * interrupts together, with break detection always enabled.
+ */
+ return;
+ }
+
+ scsptr = serial_port_in(port, SCSPTR);
+ scscr = serial_port_in(port, SCSCR);
+
+ if (break_state == -1) {
+ scsptr = (scsptr | SCSPTR_SPB2IO) & ~SCSPTR_SPB2DT;
+ scscr &= ~SCSCR_TE;
+ } else {
+ scsptr = (scsptr | SCSPTR_SPB2DT) & ~SCSPTR_SPB2IO;
+ scscr |= SCSCR_TE;
+ }
+
+ serial_port_out(port, SCSPTR, scsptr);
+ serial_port_out(port, SCSCR, scscr);
}
#ifdef CONFIG_SERIAL_SH_SCI_DMA
diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c
index 593d40ad0a6b..5ed0daae6564 100644
--- a/drivers/tty/synclink.c
+++ b/drivers/tty/synclink.c
@@ -3338,9 +3338,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
printk("%s(%d):block_til_ready blocking on %s count=%d\n",
__FILE__,__LINE__, tty->driver->name, port->count );
- tty_unlock();
+ tty_unlock(tty);
schedule();
- tty_lock();
+ tty_lock(tty);
}
set_current_state(TASK_RUNNING);
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index aa1debf97cc7..45b43f11ca39 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -3336,9 +3336,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
}
DBGINFO(("%s block_til_ready wait\n", tty->driver->name));
- tty_unlock();
+ tty_unlock(tty);
schedule();
- tty_lock();
+ tty_lock(tty);
}
set_current_state(TASK_RUNNING);
diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c
index a3dddc12d2fe..4a1e4f07765b 100644
--- a/drivers/tty/synclinkmp.c
+++ b/drivers/tty/synclinkmp.c
@@ -3357,9 +3357,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
printk("%s(%d):%s block_til_ready() count=%d\n",
__FILE__,__LINE__, tty->driver->name, port->count );
- tty_unlock();
+ tty_unlock(tty);
schedule();
- tty_lock();
+ tty_lock(tty);
}
set_current_state(TASK_RUNNING);
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 6c9b7cd6778a..91e326ffe7db 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -185,25 +185,19 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
/* Should possibly check if this fails for the largest buffer we
have queued and recycle that ? */
}
-
/**
- * tty_buffer_request_room - grow tty buffer if needed
+ * __tty_buffer_request_room - grow tty buffer if needed
* @tty: tty structure
* @size: size desired
*
* Make at least size bytes of linear space available for the tty
* buffer. If we fail return the size we managed to find.
- *
- * Locking: Takes tty->buf.lock
+ * Locking: Caller must hold tty->buf.lock
*/
-int tty_buffer_request_room(struct tty_struct *tty, size_t size)
+static int __tty_buffer_request_room(struct tty_struct *tty, size_t size)
{
struct tty_buffer *b, *n;
int left;
- unsigned long flags;
-
- spin_lock_irqsave(&tty->buf.lock, flags);
-
/* OPTIMISATION: We could keep a per tty "zero" sized buffer to
remove this conditional if its worth it. This would be invisible
to the callers */
@@ -225,9 +219,30 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)
size = left;
}
- spin_unlock_irqrestore(&tty->buf.lock, flags);
return size;
}
+
+
+/**
+ * tty_buffer_request_room - grow tty buffer if needed
+ * @tty: tty structure
+ * @size: size desired
+ *
+ * Make at least size bytes of linear space available for the tty
+ * buffer. If we fail return the size we managed to find.
+ *
+ * Locking: Takes tty->buf.lock
+ */
+int tty_buffer_request_room(struct tty_struct *tty, size_t size)
+{
+ unsigned long flags;
+ int length;
+
+ spin_lock_irqsave(&tty->buf.lock, flags);
+ length = __tty_buffer_request_room(tty, size);
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
+ return length;
+}
EXPORT_SYMBOL_GPL(tty_buffer_request_room);
/**
@@ -249,14 +264,22 @@ int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
int copied = 0;
do {
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
- int space = tty_buffer_request_room(tty, goal);
- struct tty_buffer *tb = tty->buf.tail;
+ int space;
+ unsigned long flags;
+ struct tty_buffer *tb;
+
+ spin_lock_irqsave(&tty->buf.lock, flags);
+ space = __tty_buffer_request_room(tty, goal);
+ tb = tty->buf.tail;
/* If there is no space then tb may be NULL */
- if (unlikely(space == 0))
+ if (unlikely(space == 0)) {
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
break;
+ }
memcpy(tb->char_buf_ptr + tb->used, chars, space);
memset(tb->flag_buf_ptr + tb->used, flag, space);
tb->used += space;
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
copied += space;
chars += space;
/* There is a small chance that we need to split the data over
@@ -286,14 +309,22 @@ int tty_insert_flip_string_flags(struct tty_struct *tty,
int copied = 0;
do {
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
- int space = tty_buffer_request_room(tty, goal);
- struct tty_buffer *tb = tty->buf.tail;
+ int space;
+ unsigned long __flags;
+ struct tty_buffer *tb;
+
+ spin_lock_irqsave(&tty->buf.lock, __flags);
+ space = __tty_buffer_request_room(tty, goal);
+ tb = tty->buf.tail;
/* If there is no space then tb may be NULL */
- if (unlikely(space == 0))
+ if (unlikely(space == 0)) {
+ spin_unlock_irqrestore(&tty->buf.lock, __flags);
break;
+ }
memcpy(tb->char_buf_ptr + tb->used, chars, space);
memcpy(tb->flag_buf_ptr + tb->used, flags, space);
tb->used += space;
+ spin_unlock_irqrestore(&tty->buf.lock, __flags);
copied += space;
chars += space;
flags += space;
@@ -344,13 +375,20 @@ EXPORT_SYMBOL(tty_schedule_flip);
int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars,
size_t size)
{
- int space = tty_buffer_request_room(tty, size);
+ int space;
+ unsigned long flags;
+ struct tty_buffer *tb;
+
+ spin_lock_irqsave(&tty->buf.lock, flags);
+ space = __tty_buffer_request_room(tty, size);
+
+ tb = tty->buf.tail;
if (likely(space)) {
- struct tty_buffer *tb = tty->buf.tail;
*chars = tb->char_buf_ptr + tb->used;
memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
tb->used += space;
}
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
return space;
}
EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
@@ -374,13 +412,20 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
int tty_prepare_flip_string_flags(struct tty_struct *tty,
unsigned char **chars, char **flags, size_t size)
{
- int space = tty_buffer_request_room(tty, size);
+ int space;
+ unsigned long __flags;
+ struct tty_buffer *tb;
+
+ spin_lock_irqsave(&tty->buf.lock, __flags);
+ space = __tty_buffer_request_room(tty, size);
+
+ tb = tty->buf.tail;
if (likely(space)) {
- struct tty_buffer *tb = tty->buf.tail;
*chars = tb->char_buf_ptr + tb->used;
*flags = tb->flag_buf_ptr + tb->used;
tb->used += space;
}
+ spin_unlock_irqrestore(&tty->buf.lock, __flags);
return space;
}
EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index d939bd705c71..9e930c009bf2 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -185,6 +185,7 @@ void free_tty_struct(struct tty_struct *tty)
put_device(tty->dev);
kfree(tty->write_buf);
tty_buffer_free_all(tty);
+ tty->magic = 0xDEADDEAD;
kfree(tty);
}
@@ -573,7 +574,7 @@ void __tty_hangup(struct tty_struct *tty)
}
spin_unlock(&redirect_lock);
- tty_lock();
+ tty_lock(tty);
/* some functions below drop BTM, so we need this bit */
set_bit(TTY_HUPPING, &tty->flags);
@@ -666,7 +667,7 @@ void __tty_hangup(struct tty_struct *tty)
clear_bit(TTY_HUPPING, &tty->flags);
tty_ldisc_enable(tty);
- tty_unlock();
+ tty_unlock(tty);
if (f)
fput(f);
@@ -855,10 +856,11 @@ void disassociate_ctty(int on_exit)
*/
void no_tty(void)
{
+ /* FIXME: Review locking here. The tty_lock never covered any race
+ between a new association and proc_clear_tty but possible we need
+ to protect against this anyway */
struct task_struct *tsk = current;
- tty_lock();
disassociate_ctty(0);
- tty_unlock();
proc_clear_tty(tsk);
}
@@ -1102,12 +1104,12 @@ void tty_write_message(struct tty_struct *tty, char *msg)
{
if (tty) {
mutex_lock(&tty->atomic_write_lock);
- tty_lock();
+ tty_lock(tty);
if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
- tty_unlock();
+ tty_unlock(tty);
tty->ops->write(tty, msg, strlen(msg));
} else
- tty_unlock();
+ tty_unlock(tty);
tty_write_unlock(tty);
}
return;
@@ -1402,6 +1404,7 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
}
initialize_tty_struct(tty, driver, idx);
+ tty_lock(tty);
retval = tty_driver_install_tty(driver, tty);
if (retval < 0)
goto err_deinit_tty;
@@ -1414,9 +1417,11 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
retval = tty_ldisc_setup(tty, tty->link);
if (retval)
goto err_release_tty;
+ /* Return the tty locked so that it cannot vanish under the caller */
return tty;
err_deinit_tty:
+ tty_unlock(tty);
deinitialize_tty_struct(tty);
free_tty_struct(tty);
err_module_put:
@@ -1425,6 +1430,7 @@ err_module_put:
/* call the tty release_tty routine to clean out this slot */
err_release_tty:
+ tty_unlock(tty);
printk_ratelimited(KERN_INFO "tty_init_dev: ldisc open failed, "
"clearing slot %d\n", idx);
release_tty(tty, idx);
@@ -1627,7 +1633,7 @@ int tty_release(struct inode *inode, struct file *filp)
if (tty_paranoia_check(tty, inode, __func__))
return 0;
- tty_lock();
+ tty_lock(tty);
check_tty_count(tty, __func__);
__tty_fasync(-1, filp, 0);
@@ -1636,10 +1642,11 @@ int tty_release(struct inode *inode, struct file *filp)
pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER);
devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
+ /* Review: parallel close */
o_tty = tty->link;
if (tty_release_checks(tty, o_tty, idx)) {
- tty_unlock();
+ tty_unlock(tty);
return 0;
}
@@ -1651,7 +1658,7 @@ int tty_release(struct inode *inode, struct file *filp)
if (tty->ops->close)
tty->ops->close(tty, filp);
- tty_unlock();
+ tty_unlock(tty);
/*
* Sanity check: if tty->count is going to zero, there shouldn't be
* any waiters on tty->read_wait or tty->write_wait. We test the
@@ -1674,7 +1681,7 @@ int tty_release(struct inode *inode, struct file *filp)
opens on /dev/tty */
mutex_lock(&tty_mutex);
- tty_lock();
+ tty_lock_pair(tty, o_tty);
tty_closing = tty->count <= 1;
o_tty_closing = o_tty &&
(o_tty->count <= (pty_master ? 1 : 0));
@@ -1705,7 +1712,7 @@ int tty_release(struct inode *inode, struct file *filp)
printk(KERN_WARNING "%s: %s: read/write wait queue active!\n",
__func__, tty_name(tty, buf));
- tty_unlock();
+ tty_unlock_pair(tty, o_tty);
mutex_unlock(&tty_mutex);
schedule();
}
@@ -1768,7 +1775,7 @@ int tty_release(struct inode *inode, struct file *filp)
/* check whether both sides are closing ... */
if (!tty_closing || (o_tty && !o_tty_closing)) {
- tty_unlock();
+ tty_unlock_pair(tty, o_tty);
return 0;
}
@@ -1781,14 +1788,16 @@ int tty_release(struct inode *inode, struct file *filp)
tty_ldisc_release(tty, o_tty);
/*
* The release_tty function takes care of the details of clearing
- * the slots and preserving the termios structure.
+ * the slots and preserving the termios structure. The tty_unlock_pair
+ * should be safe as we keep a kref while the tty is locked (so the
+ * unlock never unlocks a freed tty).
*/
release_tty(tty, idx);
+ tty_unlock_pair(tty, o_tty);
/* Make this pty number available for reallocation */
if (devpts)
devpts_kill_index(inode, idx);
- tty_unlock();
return 0;
}
@@ -1800,6 +1809,9 @@ int tty_release(struct inode *inode, struct file *filp)
*
* We cannot return driver and index like for the other nodes because
* devpts will not work then. It expects inodes to be from devpts FS.
+ *
+ * We need to move to returning a refcounted object from all the lookup
+ * paths including this one.
*/
static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
{
@@ -1816,6 +1828,7 @@ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)
/* noctty = 1; */
tty_kref_put(tty);
/* FIXME: we put a reference and return a TTY! */
+ /* This is only safe because the caller holds tty_mutex */
return tty;
}
@@ -1888,6 +1901,9 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
* Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev.
* tty->count should protect the rest.
* ->siglock protects ->signal/->sighand
+ *
+ * Note: the tty_unlock/lock cases without a ref are only safe due to
+ * tty_mutex
*/
static int tty_open(struct inode *inode, struct file *filp)
@@ -1911,8 +1927,7 @@ retry_open:
retval = 0;
mutex_lock(&tty_mutex);
- tty_lock();
-
+ /* This is protected by the tty_mutex */
tty = tty_open_current_tty(device, filp);
if (IS_ERR(tty)) {
retval = PTR_ERR(tty);
@@ -1933,17 +1948,19 @@ retry_open:
}
if (tty) {
+ tty_lock(tty);
retval = tty_reopen(tty);
- if (retval)
+ if (retval < 0) {
+ tty_unlock(tty);
tty = ERR_PTR(retval);
- } else
+ }
+ } else /* Returns with the tty_lock held for now */
tty = tty_init_dev(driver, index);
mutex_unlock(&tty_mutex);
if (driver)
tty_driver_kref_put(driver);
if (IS_ERR(tty)) {
- tty_unlock();
retval = PTR_ERR(tty);
goto err_file;
}
@@ -1972,7 +1989,7 @@ retry_open:
printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__,
retval, tty->name);
#endif
- tty_unlock(); /* need to call tty_release without BTM */
+ tty_unlock(tty); /* need to call tty_release without BTM */
tty_release(inode, filp);
if (retval != -ERESTARTSYS)
return retval;
@@ -1984,17 +2001,15 @@ retry_open:
/*
* Need to reset f_op in case a hangup happened.
*/
- tty_lock();
if (filp->f_op == &hung_up_tty_fops)
filp->f_op = &tty_fops;
- tty_unlock();
goto retry_open;
}
- tty_unlock();
+ tty_unlock(tty);
mutex_lock(&tty_mutex);
- tty_lock();
+ tty_lock(tty);
spin_lock_irq(&current->sighand->siglock);
if (!noctty &&
current->signal->leader &&
@@ -2002,11 +2017,10 @@ retry_open:
tty->session == NULL)
__proc_set_tty(current, tty);
spin_unlock_irq(&current->sighand->siglock);
- tty_unlock();
+ tty_unlock(tty);
mutex_unlock(&tty_mutex);
return 0;
err_unlock:
- tty_unlock();
mutex_unlock(&tty_mutex);
/* after locks to avoid deadlock */
if (!IS_ERR_OR_NULL(driver))
@@ -2089,10 +2103,13 @@ out:
static int tty_fasync(int fd, struct file *filp, int on)
{
+ struct tty_struct *tty = file_tty(filp);
int retval;
- tty_lock();
+
+ tty_lock(tty);
retval = __tty_fasync(fd, filp, on);
- tty_unlock();
+ tty_unlock(tty);
+
return retval;
}
@@ -2929,6 +2946,7 @@ void initialize_tty_struct(struct tty_struct *tty,
tty->pgrp = NULL;
tty->overrun_time = jiffies;
tty_buffer_init(tty);
+ mutex_init(&tty->legacy_mutex);
mutex_init(&tty->termios_mutex);
mutex_init(&tty->ldisc_mutex);
init_waitqueue_head(&tty->write_wait);
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 24b95db75d84..173a9000a6cb 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -28,7 +28,6 @@
static DEFINE_SPINLOCK(tty_ldisc_lock);
static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
-static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_idle);
/* Line disc dispatch table */
static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
@@ -65,7 +64,7 @@ static void put_ldisc(struct tty_ldisc *ld)
return;
}
local_irq_restore(flags);
- wake_up(&tty_ldisc_idle);
+ wake_up(&ld->wq_idle);
}
/**
@@ -200,6 +199,8 @@ static struct tty_ldisc *tty_ldisc_get(int disc)
ld->ops = ldops;
atomic_set(&ld->users, 1);
+ init_waitqueue_head(&ld->wq_idle);
+
return ld;
}
@@ -538,7 +539,7 @@ static void tty_ldisc_flush_works(struct tty_struct *tty)
static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout)
{
long ret;
- ret = wait_event_timeout(tty_ldisc_idle,
+ ret = wait_event_timeout(tty->ldisc->wq_idle,
atomic_read(&tty->ldisc->users) == 1, timeout);
return ret > 0 ? 0 : -EBUSY;
}
@@ -567,7 +568,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
if (IS_ERR(new_ldisc))
return PTR_ERR(new_ldisc);
- tty_lock();
+ tty_lock(tty);
/*
* We need to look at the tty locking here for pty/tty pairs
* when both sides try to change in parallel.
@@ -581,12 +582,12 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
*/
if (tty->ldisc->ops->num == ldisc) {
- tty_unlock();
+ tty_unlock(tty);
tty_ldisc_put(new_ldisc);
return 0;
}
- tty_unlock();
+ tty_unlock(tty);
/*
* Problem: What do we do if this blocks ?
* We could deadlock here
@@ -594,7 +595,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
tty_wait_until_sent(tty, 0);
- tty_lock();
+ tty_lock(tty);
mutex_lock(&tty->ldisc_mutex);
/*
@@ -604,10 +605,10 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
mutex_unlock(&tty->ldisc_mutex);
- tty_unlock();
+ tty_unlock(tty);
wait_event(tty_ldisc_wait,
test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
- tty_lock();
+ tty_lock(tty);
mutex_lock(&tty->ldisc_mutex);
}
@@ -622,7 +623,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
o_ldisc = tty->ldisc;
- tty_unlock();
+ tty_unlock(tty);
/*
* Make sure we don't change while someone holds a
* reference to the line discipline. The TTY_LDISC bit
@@ -649,7 +650,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
retval = tty_ldisc_wait_idle(tty, 5 * HZ);
- tty_lock();
+ tty_lock(tty);
mutex_lock(&tty->ldisc_mutex);
/* handle wait idle failure locked */
@@ -664,7 +665,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
clear_bit(TTY_LDISC_CHANGING, &tty->flags);
mutex_unlock(&tty->ldisc_mutex);
tty_ldisc_put(new_ldisc);
- tty_unlock();
+ tty_unlock(tty);
return -EIO;
}
@@ -707,7 +708,7 @@ enable:
if (o_work)
schedule_work(&o_tty->buf.work);
mutex_unlock(&tty->ldisc_mutex);
- tty_unlock();
+ tty_unlock(tty);
return retval;
}
@@ -815,11 +816,11 @@ void tty_ldisc_hangup(struct tty_struct *tty)
* need to wait for another function taking the BTM
*/
clear_bit(TTY_LDISC, &tty->flags);
- tty_unlock();
+ tty_unlock(tty);
cancel_work_sync(&tty->buf.work);
mutex_unlock(&tty->ldisc_mutex);
retry:
- tty_lock();
+ tty_lock(tty);
mutex_lock(&tty->ldisc_mutex);
/* At this point we have a closed ldisc and we want to
@@ -830,7 +831,7 @@ retry:
if (atomic_read(&tty->ldisc->users) != 1) {
char cur_n[TASK_COMM_LEN], tty_n[64];
long timeout = 3 * HZ;
- tty_unlock();
+ tty_unlock(tty);
while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
timeout = MAX_SCHEDULE_TIMEOUT;
@@ -911,10 +912,10 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
* race with the set_ldisc code path.
*/
- tty_unlock();
+ tty_unlock(tty);
tty_ldisc_halt(tty);
tty_ldisc_flush_works(tty);
- tty_lock();
+ tty_lock(tty);
mutex_lock(&tty->ldisc_mutex);
/*
diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c
index 9ff986c32a21..69adc80c98cd 100644
--- a/drivers/tty/tty_mutex.c
+++ b/drivers/tty/tty_mutex.c
@@ -4,29 +4,59 @@
#include <linux/semaphore.h>
#include <linux/sched.h>
-/*
- * The 'big tty mutex'
- *
- * This mutex is taken and released by tty_lock() and tty_unlock(),
- * replacing the older big kernel lock.
- * It can no longer be taken recursively, and does not get
- * released implicitly while sleeping.
- *
- * Don't use in new code.
- */
-static DEFINE_MUTEX(big_tty_mutex);
+/* Legacy tty mutex glue */
/*
* Getting the big tty mutex.
*/
-void __lockfunc tty_lock(void)
+
+void __lockfunc tty_lock(struct tty_struct *tty)
{
- mutex_lock(&big_tty_mutex);
+ if (tty->magic != TTY_MAGIC) {
+ printk(KERN_ERR "L Bad %p\n", tty);
+ WARN_ON(1);
+ return;
+ }
+ tty_kref_get(tty);
+ mutex_lock(&tty->legacy_mutex);
}
EXPORT_SYMBOL(tty_lock);
-void __lockfunc tty_unlock(void)
+void __lockfunc tty_unlock(struct tty_struct *tty)
{
- mutex_unlock(&big_tty_mutex);
+ if (tty->magic != TTY_MAGIC) {
+ printk(KERN_ERR "U Bad %p\n", tty);
+ WARN_ON(1);
+ return;
+ }
+ mutex_unlock(&tty->legacy_mutex);
+ tty_kref_put(tty);
}
EXPORT_SYMBOL(tty_unlock);
+
+/*
+ * Getting the big tty mutex for a pair of ttys with lock ordering
+ * On a non pty/tty pair tty2 can be NULL which is just fine.
+ */
+void __lockfunc tty_lock_pair(struct tty_struct *tty,
+ struct tty_struct *tty2)
+{
+ if (tty < tty2) {
+ tty_lock(tty);
+ tty_lock(tty2);
+ } else {
+ if (tty2 && tty2 != tty)
+ tty_lock(tty2);
+ tty_lock(tty);
+ }
+}
+EXPORT_SYMBOL(tty_lock_pair);
+
+void __lockfunc tty_unlock_pair(struct tty_struct *tty,
+ struct tty_struct *tty2)
+{
+ tty_unlock(tty);
+ if (tty2 && tty2 != tty)
+ tty_unlock(tty2);
+}
+EXPORT_SYMBOL(tty_unlock_pair);
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index bf6e238146ae..d9cca95a5452 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -230,7 +230,7 @@ int tty_port_block_til_ready(struct tty_port *port,
/* block if port is in the process of being closed */
if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
- wait_event_interruptible_tty(port->close_wait,
+ wait_event_interruptible_tty(tty, port->close_wait,
!(port->flags & ASYNC_CLOSING));
if (port->flags & ASYNC_HUP_NOTIFY)
return -EAGAIN;
@@ -296,9 +296,9 @@ int tty_port_block_til_ready(struct tty_port *port,
retval = -ERESTARTSYS;
break;
}
- tty_unlock();
+ tty_unlock(tty);
schedule();
- tty_lock();
+ tty_lock(tty);
}
finish_wait(&port->open_wait, &wait);
diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c
index 8308fc7cdc26..2aaa0c228409 100644
--- a/drivers/tty/vt/consolemap.c
+++ b/drivers/tty/vt/consolemap.c
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/tty.h>
#include <asm/uaccess.h>
+#include <linux/console.h>
#include <linux/consolemap.h>
#include <linux/vt_kern.h>
@@ -312,6 +313,7 @@ int con_set_trans_old(unsigned char __user * arg)
if (!access_ok(VERIFY_READ, arg, E_TABSZ))
return -EFAULT;
+ console_lock();
for (i=0; i<E_TABSZ ; i++) {
unsigned char uc;
__get_user(uc, arg+i);
@@ -319,6 +321,7 @@ int con_set_trans_old(unsigned char __user * arg)
}
update_user_maps();
+ console_unlock();
return 0;
}
@@ -330,11 +333,13 @@ int con_get_trans_old(unsigned char __user * arg)
if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
return -EFAULT;
+ console_lock();
for (i=0; i<E_TABSZ ; i++)
- {
- ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
- __put_user((ch & ~0xff) ? 0 : ch, arg+i);
- }
+ {
+ ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
+ __put_user((ch & ~0xff) ? 0 : ch, arg+i);
+ }
+ console_unlock();
return 0;
}
@@ -346,6 +351,7 @@ int con_set_trans_new(ushort __user * arg)
if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
return -EFAULT;
+ console_lock();
for (i=0; i<E_TABSZ ; i++) {
unsigned short us;
__get_user(us, arg+i);
@@ -353,6 +359,7 @@ int con_set_trans_new(ushort __user * arg)
}
update_user_maps();
+ console_unlock();
return 0;
}
@@ -364,8 +371,10 @@ int con_get_trans_new(ushort __user * arg)
if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
return -EFAULT;
+ console_lock();
for (i=0; i<E_TABSZ ; i++)
__put_user(p[i], arg+i);
+ console_unlock();
return 0;
}
@@ -407,6 +416,7 @@ static void con_release_unimap(struct uni_pagedir *p)
}
}
+/* Caller must hold the console lock */
void con_free_unimap(struct vc_data *vc)
{
struct uni_pagedir *p;
@@ -487,17 +497,21 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
return 0;
}
-/* ui is a leftover from using a hashtable, but might be used again */
-int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
+/* ui is a leftover from using a hashtable, but might be used again
+ Caller must hold the lock */
+static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
{
struct uni_pagedir *p, *q;
-
+
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
- if (p && p->readonly) return -EIO;
+ if (p && p->readonly)
+ return -EIO;
+
if (!p || --p->refcount) {
q = kzalloc(sizeof(*p), GFP_KERNEL);
if (!q) {
- if (p) p->refcount++;
+ if (p)
+ p->refcount++;
return -ENOMEM;
}
q->refcount=1;
@@ -511,23 +525,43 @@ int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
return 0;
}
+int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
+{
+ int ret;
+ console_lock();
+ ret = con_do_clear_unimap(vc, ui);
+ console_unlock();
+ return ret;
+}
+
int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
{
int err = 0, err1, i;
struct uni_pagedir *p, *q;
+ console_lock();
+
/* Save original vc_unipagdir_loc in case we allocate a new one */
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
- if (p->readonly) return -EIO;
+ if (p->readonly) {
+ console_unlock();
+ return -EIO;
+ }
- if (!ct) return 0;
+ if (!ct) {
+ console_unlock();
+ return 0;
+ }
if (p->refcount > 1) {
int j, k;
u16 **p1, *p2, l;
- err1 = con_clear_unimap(vc, NULL);
- if (err1) return err1;
+ err1 = con_do_clear_unimap(vc, NULL);
+ if (err1) {
+ console_unlock();
+ return err1;
+ }
/*
* Since refcount was > 1, con_clear_unimap() allocated a
@@ -558,7 +592,8 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
*vc->vc_uni_pagedir_loc = (unsigned long)p;
con_release_unimap(q);
kfree(q);
- return err1;
+ console_unlock();
+ return err1;
}
}
} else {
@@ -592,21 +627,30 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
/*
* Merge with fontmaps of any other virtual consoles.
*/
- if (con_unify_unimap(vc, p))
+ if (con_unify_unimap(vc, p)) {
+ console_unlock();
return err;
+ }
for (i = 0; i <= 3; i++)
set_inverse_transl(vc, p, i); /* Update inverse translations */
set_inverse_trans_unicode(vc, p);
-
+
+ console_unlock();
return err;
}
-/* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
- The representation used was the most compact I could come up
- with. This routine is executed at sys_setup time, and when the
- PIO_FONTRESET ioctl is called. */
-
+/**
+ * con_set_default_unimap - set default unicode map
+ * @vc: the console we are updating
+ *
+ * Loads the unimap for the hardware font, as defined in uni_hash.tbl.
+ * The representation used was the most compact I could come up
+ * with. This routine is executed at video setup, and when the
+ * PIO_FONTRESET ioctl is called.
+ *
+ * The caller must hold the console lock
+ */
int con_set_default_unimap(struct vc_data *vc)
{
int i, j, err = 0, err1;
@@ -617,6 +661,7 @@ int con_set_default_unimap(struct vc_data *vc)
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
if (p == dflt)
return 0;
+
dflt->refcount++;
*vc->vc_uni_pagedir_loc = (unsigned long)dflt;
if (p && !--p->refcount) {
@@ -628,8 +673,9 @@ int con_set_default_unimap(struct vc_data *vc)
/* The default font is always 256 characters */
- err = con_clear_unimap(vc, NULL);
- if (err) return err;
+ err = con_do_clear_unimap(vc, NULL);
+ if (err)
+ return err;
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
q = dfont_unitable;
@@ -654,6 +700,13 @@ int con_set_default_unimap(struct vc_data *vc)
}
EXPORT_SYMBOL(con_set_default_unimap);
+/**
+ * con_copy_unimap - copy unimap between two vts
+ * @dst_vc: target
+ * @src_vt: source
+ *
+ * The caller must hold the console lock when invoking this method
+ */
int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
{
struct uni_pagedir *q;
@@ -668,13 +721,23 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
*dst_vc->vc_uni_pagedir_loc = (long)q;
return 0;
}
+EXPORT_SYMBOL(con_copy_unimap);
+/**
+ * con_get_unimap - get the unicode map
+ * @vc: the console to read from
+ *
+ * Read the console unicode data for this console. Called from the ioctl
+ * handlers.
+ */
int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
{
int i, j, k, ect;
u16 **p1, *p2;
struct uni_pagedir *p;
+ console_lock();
+
ect = 0;
if (*vc->vc_uni_pagedir_loc) {
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
@@ -694,22 +757,19 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni
}
}
__put_user(ect, uct);
+ console_unlock();
return ((ect <= ct) ? 0 : -ENOMEM);
}
-void con_protect_unimap(struct vc_data *vc, int rdonly)
-{
- struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-
- if (p)
- p->readonly = rdonly;
-}
-
/*
* Always use USER_MAP. These functions are used by the keyboard,
* which shouldn't be affected by G0/G1 switching, etc.
* If the user map still contains default values, i.e. the
* direct-to-font mapping, then assume user is using Latin1.
+ *
+ * FIXME: at some point we need to decide if we want to lock the table
+ * update element itself via the keyboard_event_lock for consistency with the
+ * keyboard driver as well as the consoles
*/
/* may be called during an interrupt */
u32 conv_8bit_to_uni(unsigned char c)
@@ -777,4 +837,3 @@ console_map_init(void)
con_set_default_unimap(vc_cons[i].d);
}
-EXPORT_SYMBOL(con_copy_unimap);
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index 3b0c4e32ed7b..48cc6f25cfd3 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -53,17 +53,13 @@ extern void ctrl_alt_del(void);
#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
-/*
- * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on.
- * This seems a good reason to start with NumLock off. On HIL keyboards
- * of PARISC machines however there is no NumLock key and everyone expects the
- * keypad to be used for numbers.
- */
-
-#if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD))
-#define KBD_DEFLEDS (1 << VC_NUMLOCK)
+#if defined(CONFIG_X86) || defined(CONFIG_PARISC)
+#include <asm/kbdleds.h>
#else
-#define KBD_DEFLEDS 0
+static inline int kbd_defleds(void)
+{
+ return 0;
+}
#endif
#define KBD_DEFLOCK 0
@@ -1524,8 +1520,8 @@ int __init kbd_init(void)
int error;
for (i = 0; i < MAX_NR_CONSOLES; i++) {
- kbd_table[i].ledflagstate = KBD_DEFLEDS;
- kbd_table[i].default_ledflagstate = KBD_DEFLEDS;
+ kbd_table[i].ledflagstate = kbd_defleds();
+ kbd_table[i].default_ledflagstate = kbd_defleds();
kbd_table[i].ledmode = LED_SHOW_FLAGS;
kbd_table[i].lockstate = KBD_DEFLOCK;
kbd_table[i].slockstate = 0;
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 2156188db4a6..84cbf298c094 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -3892,36 +3892,6 @@ static void set_palette(struct vc_data *vc)
vc->vc_sw->con_set_palette(vc, color_table);
}
-static int set_get_cmap(unsigned char __user *arg, int set)
-{
- int i, j, k;
-
- WARN_CONSOLE_UNLOCKED();
-
- for (i = 0; i < 16; i++)
- if (set) {
- get_user(default_red[i], arg++);
- get_user(default_grn[i], arg++);
- get_user(default_blu[i], arg++);
- } else {
- put_user(default_red[i], arg++);
- put_user(default_grn[i], arg++);
- put_user(default_blu[i], arg++);
- }
- if (set) {
- for (i = 0; i < MAX_NR_CONSOLES; i++)
- if (vc_cons_allocated(i)) {
- for (j = k = 0; j < 16; j++) {
- vc_cons[i].d->vc_palette[k++] = default_red[j];
- vc_cons[i].d->vc_palette[k++] = default_grn[j];
- vc_cons[i].d->vc_palette[k++] = default_blu[j];
- }
- set_palette(vc_cons[i].d);
- }
- }
- return 0;
-}
-
/*
* Load palette into the DAC registers. arg points to a colour
* map, 3 bytes per colour, 16 colours, range from 0 to 255.
@@ -3929,24 +3899,50 @@ static int set_get_cmap(unsigned char __user *arg, int set)
int con_set_cmap(unsigned char __user *arg)
{
- int rc;
+ int i, j, k;
+ unsigned char colormap[3*16];
+
+ if (copy_from_user(colormap, arg, sizeof(colormap)))
+ return -EFAULT;
console_lock();
- rc = set_get_cmap (arg,1);
+ for (i = k = 0; i < 16; i++) {
+ default_red[i] = colormap[k++];
+ default_grn[i] = colormap[k++];
+ default_blu[i] = colormap[k++];
+ }
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ if (!vc_cons_allocated(i))
+ continue;
+ for (j = k = 0; j < 16; j++) {
+ vc_cons[i].d->vc_palette[k++] = default_red[j];
+ vc_cons[i].d->vc_palette[k++] = default_grn[j];
+ vc_cons[i].d->vc_palette[k++] = default_blu[j];
+ }
+ set_palette(vc_cons[i].d);
+ }
console_unlock();
- return rc;
+ return 0;
}
int con_get_cmap(unsigned char __user *arg)
{
- int rc;
+ int i, k;
+ unsigned char colormap[3*16];
console_lock();
- rc = set_get_cmap (arg,0);
+ for (i = k = 0; i < 16; i++) {
+ colormap[k++] = default_red[i];
+ colormap[k++] = default_grn[i];
+ colormap[k++] = default_blu[i];
+ }
console_unlock();
- return rc;
+ if (copy_to_user(arg, colormap, sizeof(colormap)))
+ return -EFAULT;
+
+ return 0;
}
void reset_palette(struct vc_data *vc)
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index ede2ef18d2fb..64618547be11 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -910,7 +910,9 @@ int vt_ioctl(struct tty_struct *tty,
ret = con_font_op(vc_cons[fg_console].d, &op);
if (ret)
break;
+ console_lock();
con_set_default_unimap(vc_cons[fg_console].d);
+ console_unlock();
break;
}
#endif
@@ -934,33 +936,23 @@ int vt_ioctl(struct tty_struct *tty,
case PIO_SCRNMAP:
if (!perm)
ret = -EPERM;
- else {
- tty_lock();
+ else
ret = con_set_trans_old(up);
- tty_unlock();
- }
break;
case GIO_SCRNMAP:
- tty_lock();
ret = con_get_trans_old(up);
- tty_unlock();
break;
case PIO_UNISCRNMAP:
if (!perm)
ret = -EPERM;
- else {
- tty_lock();
+ else
ret = con_set_trans_new(up);
- tty_unlock();
- }
break;
case GIO_UNISCRNMAP:
- tty_lock();
ret = con_get_trans_new(up);
- tty_unlock();
break;
case PIO_UNIMAPCLR:
@@ -970,19 +962,14 @@ int vt_ioctl(struct tty_struct *tty,
ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
if (ret)
ret = -EFAULT;
- else {
- tty_lock();
+ else
con_clear_unimap(vc, &ui);
- tty_unlock();
- }
break;
}
case PIO_UNIMAP:
case GIO_UNIMAP:
- tty_lock();
ret = do_unimap_ioctl(cmd, up, perm, vc);
- tty_unlock();
break;
case VT_LOCKSWITCH:
@@ -1196,9 +1183,7 @@ long vt_compat_ioctl(struct tty_struct *tty,
case PIO_UNIMAP:
case GIO_UNIMAP:
- tty_lock();
ret = compat_unimap_ioctl(cmd, up, perm, vc);
- tty_unlock();
break;
/*
diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c
index b98371d93a92..42202cd83158 100644
--- a/drivers/uio/uio_pdrv_genirq.c
+++ b/drivers/uio/uio_pdrv_genirq.c
@@ -146,6 +146,14 @@ static int uio_pdrv_genirq_probe(struct platform_device *pdev)
priv->flags = 0; /* interrupt is enabled to begin with */
priv->pdev = pdev;
+ if (!uioinfo->irq) {
+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to get IRQ\n");
+ goto bad0;
+ }
+ uioinfo->irq = ret;
+ }
uiomem = &uioinfo->mem[0];
for (i = 0; i < pdev->num_resources; ++i) {
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 76316a33061b..a7773a3e02b1 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -133,6 +133,8 @@ source "drivers/usb/host/Kconfig"
source "drivers/usb/musb/Kconfig"
+source "drivers/usb/chipidea/Kconfig"
+
source "drivers/usb/renesas_usbhs/Kconfig"
source "drivers/usb/class/Kconfig"
@@ -177,6 +179,8 @@ source "drivers/usb/serial/Kconfig"
source "drivers/usb/misc/Kconfig"
+source "drivers/usb/phy/Kconfig"
+
source "drivers/usb/atm/Kconfig"
source "drivers/usb/gadget/Kconfig"
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 53a7bc07dd8d..c691eea51537 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -46,12 +46,14 @@ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SERIAL) += serial/
obj-$(CONFIG_USB) += misc/
+obj-$(CONFIG_USB) += phy/
obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/
obj-$(CONFIG_USB_ATM) += atm/
obj-$(CONFIG_USB_SPEEDTOUCH) += atm/
obj-$(CONFIG_USB_MUSB_HDRC) += musb/
+obj-$(CONFIG_USB_CHIPIDEA) += chipidea/
obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/
obj-$(CONFIG_USB_GADGET) += gadget/
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index 98b89fe19867..b7eb86ad6bf2 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -674,7 +674,7 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
}
ret = offd;
- dbg("cm %#x", cm);
+ usb_dbg(instance->usbatm, "cm %#x\n", cm);
fail:
mutex_unlock(&instance->cm_serialize);
err:
@@ -733,7 +733,7 @@ static int cxacru_card_status(struct cxacru_data *instance)
{
int ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0);
if (ret < 0) { /* firmware not loaded */
- dbg("cxacru_adsl_start: CARD_GET_STATUS returned %d", ret);
+ usb_dbg(instance->usbatm, "cxacru_adsl_start: CARD_GET_STATUS returned %d\n", ret);
return ret;
}
return 0;
@@ -758,7 +758,7 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance,
int ret;
int start_polling = 1;
- dbg("cxacru_atm_start");
+ dev_dbg(&intf->dev, "%s\n", __func__);
/* Read MAC address */
ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_MAC_ADDRESS, NULL, 0,
@@ -962,13 +962,13 @@ static int cxacru_fw(struct usb_device *usb_dev, enum cxacru_fw_request fw,
ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_CMD),
buf, offb, NULL, CMD_TIMEOUT);
if (ret < 0) {
- dbg("sending fw %#x failed", fw);
+ dev_dbg(&usb_dev->dev, "sending fw %#x failed\n", fw);
goto cleanup;
}
offb = 0;
}
} while (offd < size);
- dbg("sent fw %#x", fw);
+ dev_dbg(&usb_dev->dev, "sent fw %#x\n", fw);
ret = 0;
@@ -988,7 +988,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
usb_dev->descriptor.idProduct };
__le32 val;
- dbg("cxacru_upload_firmware");
+ usb_dbg(usbatm, "%s\n", __func__);
/* FirmwarePllFClkValue */
val = cpu_to_le32(instance->modem_type->pll_f_clk);
@@ -1074,7 +1074,7 @@ static int cxacru_find_firmware(struct cxacru_data *instance,
char buf[16];
sprintf(buf, "cxacru-%s.bin", phase);
- dbg("cxacru_find_firmware: looking for %s", buf);
+ usb_dbg(usbatm, "cxacru_find_firmware: looking for %s\n", buf);
if (request_firmware(fw_p, buf, dev)) {
usb_dbg(usbatm, "no stage %s firmware found\n", phase);
@@ -1115,9 +1115,9 @@ static int cxacru_heavy_init(struct usbatm_data *usbatm_instance,
ret = cxacru_card_status(instance);
if (ret)
- dbg("modem initialisation failed");
+ usb_dbg(usbatm_instance, "modem initialisation failed\n");
else
- dbg("done setting up the modem");
+ usb_dbg(usbatm_instance, "done setting up the modem\n");
return ret;
}
@@ -1133,7 +1133,7 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance,
/* instance init */
instance = kzalloc(sizeof(*instance), GFP_KERNEL);
if (!instance) {
- dbg("cxacru_bind: no memory for instance data");
+ usb_dbg(usbatm_instance, "cxacru_bind: no memory for instance data\n");
return -ENOMEM;
}
@@ -1149,31 +1149,31 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance,
instance->rcv_buf = (u8 *) __get_free_page(GFP_KERNEL);
if (!instance->rcv_buf) {
- dbg("cxacru_bind: no memory for rcv_buf");
+ usb_dbg(usbatm_instance, "cxacru_bind: no memory for rcv_buf\n");
ret = -ENOMEM;
goto fail;
}
instance->snd_buf = (u8 *) __get_free_page(GFP_KERNEL);
if (!instance->snd_buf) {
- dbg("cxacru_bind: no memory for snd_buf");
+ usb_dbg(usbatm_instance, "cxacru_bind: no memory for snd_buf\n");
ret = -ENOMEM;
goto fail;
}
instance->rcv_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!instance->rcv_urb) {
- dbg("cxacru_bind: no memory for rcv_urb");
+ usb_dbg(usbatm_instance, "cxacru_bind: no memory for rcv_urb\n");
ret = -ENOMEM;
goto fail;
}
instance->snd_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!instance->snd_urb) {
- dbg("cxacru_bind: no memory for snd_urb");
+ usb_dbg(usbatm_instance, "cxacru_bind: no memory for snd_urb\n");
ret = -ENOMEM;
goto fail;
}
if (!cmd_ep) {
- dbg("cxacru_bind: no command endpoint");
+ usb_dbg(usbatm_instance, "cxacru_bind: no command endpoint\n");
ret = -ENODEV;
goto fail;
}
@@ -1227,10 +1227,10 @@ static void cxacru_unbind(struct usbatm_data *usbatm_instance,
struct cxacru_data *instance = usbatm_instance->driver_data;
int is_polling = 1;
- dbg("cxacru_unbind entered");
+ usb_dbg(usbatm_instance, "cxacru_unbind entered\n");
if (!instance) {
- dbg("cxacru_unbind: NULL instance!");
+ usb_dbg(usbatm_instance, "cxacru_unbind: NULL instance!\n");
return;
}
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 98dd9e49b684..975e9c6691d6 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -170,7 +170,7 @@ static void speedtch_set_swbuff(struct speedtch_instance_data *instance, int sta
"%sabling SW buffering: usb_control_msg returned %d\n",
state ? "En" : "Dis", ret);
else
- dbg("speedtch_set_swbuff: %sbled SW buffering", state ? "En" : "Dis");
+ usb_dbg(usbatm, "speedtch_set_swbuff: %sbled SW buffering\n", state ? "En" : "Dis");
}
static void speedtch_test_sequence(struct speedtch_instance_data *instance)
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index 01ea5d7421d4..d7e422dc0ef7 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -1357,10 +1357,8 @@ static int uea_stat_e1(struct uea_softc *sc)
/* release the dsp firmware as it is not needed until
* the next failure
*/
- if (sc->dsp_firm) {
- release_firmware(sc->dsp_firm);
- sc->dsp_firm = NULL;
- }
+ release_firmware(sc->dsp_firm);
+ sc->dsp_firm = NULL;
}
/* always update it as atm layer could not be init when we switch to
@@ -1496,10 +1494,8 @@ static int uea_stat_e4(struct uea_softc *sc)
/* release the dsp firmware as it is not needed until
* the next failure
*/
- if (sc->dsp_firm) {
- release_firmware(sc->dsp_firm);
- sc->dsp_firm = NULL;
- }
+ release_firmware(sc->dsp_firm);
+ sc->dsp_firm = NULL;
}
/* always update it as atm layer could not be init when we switch to
@@ -2240,8 +2236,7 @@ static void uea_stop(struct uea_softc *sc)
/* flush the work item, when no one can schedule it */
flush_work_sync(&sc->task);
- if (sc->dsp_firm)
- release_firmware(sc->dsp_firm);
+ release_firmware(sc->dsp_firm);
uea_leaves(INS_TO_USBDEV(sc));
}
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index d3448ca110ce..ee62b3576f94 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -86,7 +86,7 @@
#ifdef VERBOSE_DEBUG
static int usbatm_print_packet(const unsigned char *data, int len);
#define PACKETDEBUG(arg...) usbatm_print_packet(arg)
-#define vdbg(arg...) dbg(arg)
+#define vdbg(arg...) dev_dbg(arg)
#else
#define PACKETDEBUG(arg...)
#define vdbg(arg...)
@@ -714,7 +714,7 @@ static void usbatm_destroy_instance(struct kref *kref)
{
struct usbatm_data *instance = container_of(kref, struct usbatm_data, refcount);
- dbg("%s", __func__);
+ usb_dbg(instance, "%s\n", __func__);
tasklet_kill(&instance->rx_channel.tasklet);
tasklet_kill(&instance->tx_channel.tasklet);
@@ -724,14 +724,14 @@ static void usbatm_destroy_instance(struct kref *kref)
static void usbatm_get_instance(struct usbatm_data *instance)
{
- dbg("%s", __func__);
+ usb_dbg(instance, "%s\n", __func__);
kref_get(&instance->refcount);
}
static void usbatm_put_instance(struct usbatm_data *instance)
{
- dbg("%s", __func__);
+ usb_dbg(instance, "%s\n", __func__);
kref_put(&instance->refcount, usbatm_destroy_instance);
}
@@ -745,11 +745,10 @@ static void usbatm_atm_dev_close(struct atm_dev *atm_dev)
{
struct usbatm_data *instance = atm_dev->dev_data;
- dbg("%s", __func__);
-
if (!instance)
return;
+ usb_dbg(instance, "%s\n", __func__);
atm_dev->dev_data = NULL; /* catch bugs */
usbatm_put_instance(instance); /* taken in usbatm_atm_init */
}
@@ -759,10 +758,8 @@ static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *pag
struct usbatm_data *instance = atm_dev->dev_data;
int left = *pos;
- if (!instance) {
- dbg("%s: NULL instance!", __func__);
+ if (!instance)
return -ENODEV;
- }
if (!left--)
return sprintf(page, "%s\n", instance->description);
@@ -804,10 +801,8 @@ static int usbatm_atm_open(struct atm_vcc *vcc)
int vci = vcc->vci;
short vpi = vcc->vpi;
- if (!instance) {
- dbg("%s: NULL data!", __func__);
+ if (!instance)
return -ENODEV;
- }
atm_dbg(instance, "%s: vpi %hd, vci %d\n", __func__, vpi, vci);
@@ -884,10 +879,8 @@ static void usbatm_atm_close(struct atm_vcc *vcc)
struct usbatm_data *instance = vcc->dev->dev_data;
struct usbatm_vcc_data *vcc_data = vcc->dev_data;
- if (!instance || !vcc_data) {
- dbg("%s: NULL data!", __func__);
+ if (!instance || !vcc_data)
return;
- }
atm_dbg(instance, "%s entered\n", __func__);
@@ -929,10 +922,8 @@ static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd,
{
struct usbatm_data *instance = atm_dev->dev_data;
- if (!instance || instance->disconnected) {
- dbg("%s: %s!", __func__, instance ? "disconnected" : "NULL instance");
+ if (!instance || instance->disconnected)
return -ENODEV;
- }
switch (cmd) {
case ATM_QUERYLOOP:
@@ -1336,8 +1327,6 @@ EXPORT_SYMBOL_GPL(usbatm_usb_disconnect);
static int __init usbatm_usb_init(void)
{
- dbg("%s: driver version %s", __func__, DRIVER_VERSION);
-
if (sizeof(struct usbatm_control) > FIELD_SIZEOF(struct sk_buff, cb)) {
printk(KERN_ERR "%s unusable with this kernel!\n", usbatm_driver_name);
return -EIO;
@@ -1357,7 +1346,6 @@ module_init(usbatm_usb_init);
static void __exit usbatm_usb_exit(void)
{
- dbg("%s", __func__);
}
module_exit(usbatm_usb_exit);
diff --git a/drivers/usb/atm/xusbatm.c b/drivers/usb/atm/xusbatm.c
index 48ee0c5ff282..14ec9f0c5924 100644
--- a/drivers/usb/atm/xusbatm.c
+++ b/drivers/usb/atm/xusbatm.c
@@ -187,8 +187,6 @@ static int __init xusbatm_init(void)
{
int i;
- dbg("xusbatm_init");
-
if (!num_vendor ||
num_vendor != num_product ||
num_vendor != num_rx_endpoint ||
@@ -221,8 +219,6 @@ module_init(xusbatm_init);
static void __exit xusbatm_exit(void)
{
- dbg("xusbatm_exit entered");
-
usb_deregister(&xusbatm_usb_driver);
}
module_exit(xusbatm_exit);
diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig
new file mode 100644
index 000000000000..fd36dc8b889b
--- /dev/null
+++ b/drivers/usb/chipidea/Kconfig
@@ -0,0 +1,32 @@
+config USB_CHIPIDEA
+ tristate "ChipIdea Highspeed Dual Role Controller"
+ depends on USB
+ help
+ Say Y here if your system has a dual role high speed USB
+ controller based on ChipIdea silicon IP. Currently, only the
+ peripheral mode is supported.
+
+ When compiled dynamically, the module will be called ci-hdrc.ko.
+
+if USB_CHIPIDEA
+
+config USB_CHIPIDEA_UDC
+ bool "ChipIdea device controller"
+ depends on USB_GADGET
+ select USB_GADGET_DUALSPEED
+ help
+ Say Y here to enable device controller functionality of the
+ ChipIdea driver.
+
+config USB_CHIPIDEA_HOST
+ bool "ChipIdea host controller"
+ help
+ Say Y here to enable host controller functionality of the
+ ChipIdea driver.
+
+config USB_CHIPIDEA_DEBUG
+ bool "ChipIdea driver debug"
+ help
+ Say Y here to enable debugging output of the ChipIdea driver.
+
+endif
diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile
new file mode 100644
index 000000000000..cc3493769724
--- /dev/null
+++ b/drivers/usb/chipidea/Makefile
@@ -0,0 +1,14 @@
+obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc.o
+
+ci_hdrc-y := core.o
+ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC) += udc.o
+ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST) += host.o
+ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG) += debug.o
+
+ifneq ($(CONFIG_PCI),)
+ obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_pci.o
+endif
+
+ifneq ($(CONFIG_ARCH_MSM),)
+ obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_msm.o
+endif
diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h
new file mode 100644
index 000000000000..050de8562a04
--- /dev/null
+++ b/drivers/usb/chipidea/bits.h
@@ -0,0 +1,90 @@
+/*
+ * bits.h - register bits of the ChipIdea USB IP core
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * 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 __DRIVERS_USB_CHIPIDEA_BITS_H
+#define __DRIVERS_USB_CHIPIDEA_BITS_H
+
+#include <linux/usb/ehci_def.h>
+
+/* HCCPARAMS */
+#define HCCPARAMS_LEN BIT(17)
+
+/* DCCPARAMS */
+#define DCCPARAMS_DEN (0x1F << 0)
+#define DCCPARAMS_DC BIT(7)
+#define DCCPARAMS_HC BIT(8)
+
+/* TESTMODE */
+#define TESTMODE_FORCE BIT(0)
+
+/* USBCMD */
+#define USBCMD_RS BIT(0)
+#define USBCMD_RST BIT(1)
+#define USBCMD_SUTW BIT(13)
+#define USBCMD_ATDTW BIT(14)
+
+/* USBSTS & USBINTR */
+#define USBi_UI BIT(0)
+#define USBi_UEI BIT(1)
+#define USBi_PCI BIT(2)
+#define USBi_URI BIT(6)
+#define USBi_SLI BIT(8)
+
+/* DEVICEADDR */
+#define DEVICEADDR_USBADRA BIT(24)
+#define DEVICEADDR_USBADR (0x7FUL << 25)
+
+/* PORTSC */
+#define PORTSC_FPR BIT(6)
+#define PORTSC_SUSP BIT(7)
+#define PORTSC_HSP BIT(9)
+#define PORTSC_PTC (0x0FUL << 16)
+
+/* DEVLC */
+#define DEVLC_PSPD (0x03UL << 25)
+#define DEVLC_PSPD_HS (0x02UL << 25)
+
+/* OTGSC */
+#define OTGSC_IDPU BIT(5)
+#define OTGSC_ID BIT(8)
+#define OTGSC_AVV BIT(9)
+#define OTGSC_ASV BIT(10)
+#define OTGSC_BSV BIT(11)
+#define OTGSC_BSE BIT(12)
+#define OTGSC_IDIS BIT(16)
+#define OTGSC_AVVIS BIT(17)
+#define OTGSC_ASVIS BIT(18)
+#define OTGSC_BSVIS BIT(19)
+#define OTGSC_BSEIS BIT(20)
+#define OTGSC_IDIE BIT(24)
+#define OTGSC_AVVIE BIT(25)
+#define OTGSC_ASVIE BIT(26)
+#define OTGSC_BSVIE BIT(27)
+#define OTGSC_BSEIE BIT(28)
+
+/* USBMODE */
+#define USBMODE_CM (0x03UL << 0)
+#define USBMODE_CM_DC (0x02UL << 0)
+#define USBMODE_SLOM BIT(3)
+#define USBMODE_CI_SDIS BIT(4)
+
+/* ENDPTCTRL */
+#define ENDPTCTRL_RXS BIT(0)
+#define ENDPTCTRL_RXT (0x03UL << 2)
+#define ENDPTCTRL_RXR BIT(6) /* reserved for port 0 */
+#define ENDPTCTRL_RXE BIT(7)
+#define ENDPTCTRL_TXS BIT(16)
+#define ENDPTCTRL_TXT (0x03UL << 18)
+#define ENDPTCTRL_TXR BIT(22) /* reserved for port 0 */
+#define ENDPTCTRL_TXE BIT(23)
+
+#endif /* __DRIVERS_USB_CHIPIDEA_BITS_H */
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
new file mode 100644
index 000000000000..50911f8490d4
--- /dev/null
+++ b/drivers/usb/chipidea/ci.h
@@ -0,0 +1,313 @@
+/*
+ * ci.h - common structures, functions, and macros of the ChipIdea driver
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * 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 __DRIVERS_USB_CHIPIDEA_CI_H
+#define __DRIVERS_USB_CHIPIDEA_CI_H
+
+#include <linux/list.h>
+#include <linux/irqreturn.h>
+#include <linux/usb.h>
+#include <linux/usb/gadget.h>
+
+/******************************************************************************
+ * DEFINE
+ *****************************************************************************/
+#define CI13XXX_PAGE_SIZE 4096ul /* page size for TD's */
+#define ENDPT_MAX 32
+
+/******************************************************************************
+ * STRUCTURES
+ *****************************************************************************/
+/**
+ * struct ci13xxx_ep - endpoint representation
+ * @ep: endpoint structure for gadget drivers
+ * @dir: endpoint direction (TX/RX)
+ * @num: endpoint number
+ * @type: endpoint type
+ * @name: string description of the endpoint
+ * @qh: queue head for this endpoint
+ * @wedge: is the endpoint wedged
+ * @udc: pointer to the controller
+ * @lock: pointer to controller's spinlock
+ * @td_pool: pointer to controller's TD pool
+ */
+struct ci13xxx_ep {
+ struct usb_ep ep;
+ u8 dir;
+ u8 num;
+ u8 type;
+ char name[16];
+ struct {
+ struct list_head queue;
+ struct ci13xxx_qh *ptr;
+ dma_addr_t dma;
+ } qh;
+ int wedge;
+
+ /* global resources */
+ struct ci13xxx *udc;
+ spinlock_t *lock;
+ struct dma_pool *td_pool;
+};
+
+enum ci_role {
+ CI_ROLE_HOST = 0,
+ CI_ROLE_GADGET,
+ CI_ROLE_END,
+};
+
+/**
+ * struct ci_role_driver - host/gadget role driver
+ * start: start this role
+ * stop: stop this role
+ * irq: irq handler for this role
+ * name: role name string (host/gadget)
+ */
+struct ci_role_driver {
+ int (*start)(struct ci13xxx *);
+ void (*stop)(struct ci13xxx *);
+ irqreturn_t (*irq)(struct ci13xxx *);
+ const char *name;
+};
+
+/**
+ * struct hw_bank - hardware register mapping representation
+ * @lpm: set if the device is LPM capable
+ * @phys: physical address of the controller's registers
+ * @abs: absolute address of the beginning of register window
+ * @cap: capability registers
+ * @op: operational registers
+ * @size: size of the register window
+ * @regmap: register lookup table
+ */
+struct hw_bank {
+ unsigned lpm;
+ resource_size_t phys;
+ void __iomem *abs;
+ void __iomem *cap;
+ void __iomem *op;
+ size_t size;
+ void __iomem **regmap;
+};
+
+/**
+ * struct ci13xxx - chipidea device representation
+ * @dev: pointer to parent device
+ * @lock: access synchronization
+ * @hw_bank: hardware register mapping
+ * @irq: IRQ number
+ * @roles: array of supported roles for this controller
+ * @role: current role
+ * @is_otg: if the device is otg-capable
+ * @work: work for role changing
+ * @wq: workqueue thread
+ * @qh_pool: allocation pool for queue heads
+ * @td_pool: allocation pool for transfer descriptors
+ * @gadget: device side representation for peripheral controller
+ * @driver: gadget driver
+ * @hw_ep_max: total number of endpoints supported by hardware
+ * @ci13xxx_ep: array of endpoints
+ * @ep0_dir: ep0 direction
+ * @ep0out: pointer to ep0 OUT endpoint
+ * @ep0in: pointer to ep0 IN endpoint
+ * @status: ep0 status request
+ * @setaddr: if we should set the address on status completion
+ * @address: usb address received from the host
+ * @remote_wakeup: host-enabled remote wakeup
+ * @suspended: suspended by host
+ * @test_mode: the selected test mode
+ * @udc_driver: platform specific information supplied by parent device
+ * @vbus_active: is VBUS active
+ * @transceiver: pointer to USB PHY, if any
+ * @hcd: pointer to usb_hcd for ehci host driver
+ */
+struct ci13xxx {
+ struct device *dev;
+ spinlock_t lock;
+ struct hw_bank hw_bank;
+ int irq;
+ struct ci_role_driver *roles[CI_ROLE_END];
+ enum ci_role role;
+ bool is_otg;
+ struct work_struct work;
+ struct workqueue_struct *wq;
+
+ struct dma_pool *qh_pool;
+ struct dma_pool *td_pool;
+
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ unsigned hw_ep_max;
+ struct ci13xxx_ep ci13xxx_ep[ENDPT_MAX];
+ u32 ep0_dir;
+ struct ci13xxx_ep *ep0out, *ep0in;
+
+ struct usb_request *status;
+ bool setaddr;
+ u8 address;
+ u8 remote_wakeup;
+ u8 suspended;
+ u8 test_mode;
+
+ struct ci13xxx_udc_driver *udc_driver;
+ int vbus_active;
+ struct usb_phy *transceiver;
+ struct usb_hcd *hcd;
+};
+
+static inline struct ci_role_driver *ci_role(struct ci13xxx *ci)
+{
+ BUG_ON(ci->role >= CI_ROLE_END || !ci->roles[ci->role]);
+ return ci->roles[ci->role];
+}
+
+static inline int ci_role_start(struct ci13xxx *ci, enum ci_role role)
+{
+ int ret;
+
+ if (role >= CI_ROLE_END)
+ return -EINVAL;
+
+ if (!ci->roles[role])
+ return -ENXIO;
+
+ ret = ci->roles[role]->start(ci);
+ if (!ret)
+ ci->role = role;
+ return ret;
+}
+
+static inline void ci_role_stop(struct ci13xxx *ci)
+{
+ enum ci_role role = ci->role;
+
+ if (role == CI_ROLE_END)
+ return;
+
+ ci->role = CI_ROLE_END;
+
+ ci->roles[role]->stop(ci);
+}
+
+/******************************************************************************
+ * REGISTERS
+ *****************************************************************************/
+/* register size */
+#define REG_BITS (32)
+
+/* register indices */
+enum ci13xxx_regs {
+ CAP_CAPLENGTH,
+ CAP_HCCPARAMS,
+ CAP_DCCPARAMS,
+ CAP_TESTMODE,
+ CAP_LAST = CAP_TESTMODE,
+ OP_USBCMD,
+ OP_USBSTS,
+ OP_USBINTR,
+ OP_DEVICEADDR,
+ OP_ENDPTLISTADDR,
+ OP_PORTSC,
+ OP_DEVLC,
+ OP_OTGSC,
+ OP_USBMODE,
+ OP_ENDPTSETUPSTAT,
+ OP_ENDPTPRIME,
+ OP_ENDPTFLUSH,
+ OP_ENDPTSTAT,
+ OP_ENDPTCOMPLETE,
+ OP_ENDPTCTRL,
+ /* endptctrl1..15 follow */
+ OP_LAST = OP_ENDPTCTRL + ENDPT_MAX / 2,
+};
+
+/**
+ * ffs_nr: find first (least significant) bit set
+ * @x: the word to search
+ *
+ * This function returns bit number (instead of position)
+ */
+static inline int ffs_nr(u32 x)
+{
+ int n = ffs(x);
+
+ return n ? n-1 : 32;
+}
+
+/**
+ * hw_read: reads from a hw register
+ * @reg: register index
+ * @mask: bitfield mask
+ *
+ * This function returns register contents
+ */
+static inline u32 hw_read(struct ci13xxx *udc, enum ci13xxx_regs reg, u32 mask)
+{
+ return ioread32(udc->hw_bank.regmap[reg]) & mask;
+}
+
+/**
+ * hw_write: writes to a hw register
+ * @reg: register index
+ * @mask: bitfield mask
+ * @data: new value
+ */
+static inline void hw_write(struct ci13xxx *udc, enum ci13xxx_regs reg,
+ u32 mask, u32 data)
+{
+ if (~mask)
+ data = (ioread32(udc->hw_bank.regmap[reg]) & ~mask)
+ | (data & mask);
+
+ iowrite32(data, udc->hw_bank.regmap[reg]);
+}
+
+/**
+ * hw_test_and_clear: tests & clears a hw register
+ * @reg: register index
+ * @mask: bitfield mask
+ *
+ * This function returns register contents
+ */
+static inline u32 hw_test_and_clear(struct ci13xxx *udc, enum ci13xxx_regs reg,
+ u32 mask)
+{
+ u32 val = ioread32(udc->hw_bank.regmap[reg]) & mask;
+
+ iowrite32(val, udc->hw_bank.regmap[reg]);
+ return val;
+}
+
+/**
+ * hw_test_and_write: tests & writes a hw register
+ * @reg: register index
+ * @mask: bitfield mask
+ * @data: new value
+ *
+ * This function returns register contents
+ */
+static inline u32 hw_test_and_write(struct ci13xxx *udc, enum ci13xxx_regs reg,
+ u32 mask, u32 data)
+{
+ u32 val = hw_read(udc, reg, ~0);
+
+ hw_write(udc, reg, mask, data);
+ return (val & mask) >> ffs_nr(mask);
+}
+
+int hw_device_reset(struct ci13xxx *ci, u32 mode);
+
+int hw_port_test_set(struct ci13xxx *ci, u8 mode);
+
+u8 hw_port_test_get(struct ci13xxx *ci);
+
+#endif /* __DRIVERS_USB_CHIPIDEA_CI_H */
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/chipidea/ci13xxx_msm.c
index d07e44c05e9b..958069ef95e3 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/chipidea/ci13xxx_msm.c
@@ -10,15 +10,12 @@
#include <linux/pm_runtime.h>
#include <linux/usb/msm_hsusb_hw.h>
#include <linux/usb/ulpi.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/chipidea.h>
-#include "ci13xxx_udc.c"
+#include "ci.h"
-#define MSM_USB_BASE (udc->regs)
-
-static irqreturn_t msm_udc_irq(int irq, void *data)
-{
- return udc_irq();
-}
+#define MSM_USB_BASE (udc->hw_bank.abs)
static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event)
{
@@ -60,53 +57,40 @@ static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = {
static int ci13xxx_msm_probe(struct platform_device *pdev)
{
- struct resource *res;
- void __iomem *regs;
- int irq;
+ struct platform_device *plat_ci;
int ret;
dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n");
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "failed to get platform resource mem\n");
- return -ENXIO;
- }
-
- regs = ioremap(res->start, resource_size(res));
- if (!regs) {
- dev_err(&pdev->dev, "ioremap failed\n");
+ plat_ci = platform_device_alloc("ci_hdrc", -1);
+ if (!plat_ci) {
+ dev_err(&pdev->dev, "can't allocate ci_hdrc platform device\n");
return -ENOMEM;
}
- ret = udc_probe(&ci13xxx_msm_udc_driver, &pdev->dev, regs);
- if (ret < 0) {
- dev_err(&pdev->dev, "udc_probe failed\n");
- goto iounmap;
+ ret = platform_device_add_resources(plat_ci, pdev->resource,
+ pdev->num_resources);
+ if (ret) {
+ dev_err(&pdev->dev, "can't add resources to platform device\n");
+ goto put_platform;
}
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "IRQ not found\n");
- ret = -ENXIO;
- goto udc_remove;
- }
+ ret = platform_device_add_data(plat_ci, &ci13xxx_msm_udc_driver,
+ sizeof(ci13xxx_msm_udc_driver));
+ if (ret)
+ goto put_platform;
- ret = request_irq(irq, msm_udc_irq, IRQF_SHARED, pdev->name, pdev);
- if (ret < 0) {
- dev_err(&pdev->dev, "request_irq failed\n");
- goto udc_remove;
- }
+ ret = platform_device_add(plat_ci);
+ if (ret)
+ goto put_platform;
pm_runtime_no_callbacks(&pdev->dev);
pm_runtime_enable(&pdev->dev);
return 0;
-udc_remove:
- udc_remove();
-iounmap:
- iounmap(regs);
+put_platform:
+ platform_device_put(plat_ci);
return ret;
}
diff --git a/drivers/usb/gadget/ci13xxx_pci.c b/drivers/usb/chipidea/ci13xxx_pci.c
index 883ab5e832d1..e3dab27f5c75 100644
--- a/drivers/usb/gadget/ci13xxx_pci.c
+++ b/drivers/usb/chipidea/ci13xxx_pci.c
@@ -10,10 +10,12 @@
* published by the Free Software Foundation.
*/
+#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/pci.h>
-
-#include "ci13xxx_udc.c"
+#include <linux/interrupt.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/chipidea.h>
/* driver name */
#define UDC_DRIVER_NAME "ci13xxx_pci"
@@ -21,25 +23,20 @@
/******************************************************************************
* PCI block
*****************************************************************************/
-/**
- * ci13xxx_pci_irq: interrut handler
- * @irq: irq number
- * @pdev: USB Device Controller interrupt source
- *
- * This function returns IRQ_HANDLED if the IRQ has been handled
- * This is an ISR don't trace, use attribute interface instead
- */
-static irqreturn_t ci13xxx_pci_irq(int irq, void *pdev)
-{
- if (irq == 0) {
- dev_err(&((struct pci_dev *)pdev)->dev, "Invalid IRQ0 usage!");
- return IRQ_HANDLED;
- }
- return udc_irq();
-}
+struct ci13xxx_udc_driver pci_driver = {
+ .name = UDC_DRIVER_NAME,
+ .capoffset = DEF_CAPOFFSET,
+};
-static struct ci13xxx_udc_driver ci13xxx_pci_udc_driver = {
+struct ci13xxx_udc_driver langwell_pci_driver = {
.name = UDC_DRIVER_NAME,
+ .capoffset = 0,
+};
+
+struct ci13xxx_udc_driver penwell_pci_driver = {
+ .name = UDC_DRIVER_NAME,
+ .capoffset = 0,
+ .power_budget = 200,
};
/**
@@ -54,11 +51,15 @@ static struct ci13xxx_udc_driver ci13xxx_pci_udc_driver = {
static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
- void __iomem *regs = NULL;
- int retval = 0;
-
- if (id == NULL)
- return -EINVAL;
+ struct ci13xxx_udc_driver *driver = (void *)id->driver_data;
+ struct platform_device *plat_ci;
+ struct resource res[3];
+ int retval = 0, nres = 2;
+
+ if (!driver) {
+ dev_err(&pdev->dev, "device doesn't provide driver data\n");
+ return -ENODEV;
+ }
retval = pci_enable_device(pdev);
if (retval)
@@ -70,41 +71,50 @@ static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
goto disable_device;
}
- retval = pci_request_regions(pdev, UDC_DRIVER_NAME);
- if (retval)
- goto disable_device;
+ pci_set_power_state(pdev, PCI_D0);
+ pci_set_master(pdev);
+ pci_try_set_mwi(pdev);
- /* BAR 0 holds all the registers */
- regs = pci_iomap(pdev, 0, 0);
- if (!regs) {
- dev_err(&pdev->dev, "Error mapping memory!");
- retval = -EFAULT;
- goto release_regions;
+ plat_ci = platform_device_alloc("ci_hdrc", -1);
+ if (!plat_ci) {
+ dev_err(&pdev->dev, "can't allocate ci_hdrc platform device\n");
+ retval = -ENOMEM;
+ goto disable_device;
}
- pci_set_drvdata(pdev, (__force void *)regs);
- pci_set_master(pdev);
- pci_try_set_mwi(pdev);
+ memset(res, 0, sizeof(res));
+ res[0].start = pci_resource_start(pdev, 0);
+ res[0].end = pci_resource_end(pdev, 0);
+ res[0].flags = IORESOURCE_MEM;
+ res[1].start = pdev->irq;
+ res[1].flags = IORESOURCE_IRQ;
+
+ retval = platform_device_add_resources(plat_ci, res, nres);
+ if (retval) {
+ dev_err(&pdev->dev, "can't add resources to platform device\n");
+ goto put_platform;
+ }
- retval = udc_probe(&ci13xxx_pci_udc_driver, &pdev->dev, regs);
+ retval = platform_device_add_data(plat_ci, driver, sizeof(*driver));
if (retval)
- goto iounmap;
+ goto put_platform;
+
+ dma_set_coherent_mask(&plat_ci->dev, pdev->dev.coherent_dma_mask);
+ plat_ci->dev.dma_mask = pdev->dev.dma_mask;
+ plat_ci->dev.dma_parms = pdev->dev.dma_parms;
+ plat_ci->dev.parent = &pdev->dev;
- /* our device does not have MSI capability */
+ pci_set_drvdata(pdev, plat_ci);
- retval = request_irq(pdev->irq, ci13xxx_pci_irq, IRQF_SHARED,
- UDC_DRIVER_NAME, pdev);
+ retval = platform_device_add(plat_ci);
if (retval)
- goto gadget_remove;
+ goto put_platform;
return 0;
- gadget_remove:
- udc_remove();
- iounmap:
- pci_iounmap(pdev, regs);
- release_regions:
- pci_release_regions(pdev);
+ put_platform:
+ pci_set_drvdata(pdev, NULL);
+ platform_device_put(plat_ci);
disable_device:
pci_disable_device(pdev);
done:
@@ -121,10 +131,10 @@ static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev,
*/
static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev)
{
- free_irq(pdev->irq, pdev);
- udc_remove();
- pci_iounmap(pdev, (__force void __iomem *)pci_get_drvdata(pdev));
- pci_release_regions(pdev);
+ struct platform_device *plat_ci = pci_get_drvdata(pdev);
+
+ platform_device_unregister(plat_ci);
+ pci_set_drvdata(pdev, NULL);
pci_disable_device(pdev);
}
@@ -135,8 +145,22 @@ static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev)
* Check "pci.h" for details
*/
static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = {
- { PCI_DEVICE(0x153F, 0x1004) },
- { PCI_DEVICE(0x153F, 0x1006) },
+ {
+ PCI_DEVICE(0x153F, 0x1004),
+ .driver_data = (kernel_ulong_t)&pci_driver,
+ },
+ {
+ PCI_DEVICE(0x153F, 0x1006),
+ .driver_data = (kernel_ulong_t)&pci_driver,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0811),
+ .driver_data = (kernel_ulong_t)&langwell_pci_driver,
+ },
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0829),
+ .driver_data = (kernel_ulong_t)&penwell_pci_driver,
+ },
{ 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE(pci, ci13xxx_pci_id_table);
@@ -148,27 +172,7 @@ static struct pci_driver ci13xxx_pci_driver = {
.remove = __devexit_p(ci13xxx_pci_remove),
};
-/**
- * ci13xxx_pci_init: module init
- *
- * Driver load
- */
-static int __init ci13xxx_pci_init(void)
-{
- return pci_register_driver(&ci13xxx_pci_driver);
-}
-module_init(ci13xxx_pci_init);
-
-/**
- * ci13xxx_pci_exit: module exit
- *
- * Driver unload
- */
-static void __exit ci13xxx_pci_exit(void)
-{
- pci_unregister_driver(&ci13xxx_pci_driver);
-}
-module_exit(ci13xxx_pci_exit);
+module_pci_driver(ci13xxx_pci_driver);
MODULE_AUTHOR("MIPS - David Lopo <dlopo@chipidea.mips.com>");
MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller");
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
new file mode 100644
index 000000000000..15e03b308f8a
--- /dev/null
+++ b/drivers/usb/chipidea/core.c
@@ -0,0 +1,474 @@
+/*
+ * core.c - ChipIdea USB IP core family device controller
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * 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.
+ */
+
+/*
+ * Description: ChipIdea USB IP core family device controller
+ *
+ * This driver is composed of several blocks:
+ * - HW: hardware interface
+ * - DBG: debug facilities (optional)
+ * - UTIL: utilities
+ * - ISR: interrupts handling
+ * - ENDPT: endpoint operations (Gadget API)
+ * - GADGET: gadget operations (Gadget API)
+ * - BUS: bus glue code, bus abstraction layer
+ *
+ * Compile Options
+ * - CONFIG_USB_GADGET_DEBUG_FILES: enable debug facilities
+ * - STALL_IN: non-empty bulk-in pipes cannot be halted
+ * if defined mass storage compliance succeeds but with warnings
+ * => case 4: Hi > Dn
+ * => case 5: Hi > Di
+ * => case 8: Hi <> Do
+ * if undefined usbtest 13 fails
+ * - TRACE: enable function tracing (depends on DEBUG)
+ *
+ * Main Features
+ * - Chapter 9 & Mass Storage Compliance with Gadget File Storage
+ * - Chapter 9 Compliance with Gadget Zero (STALL_IN undefined)
+ * - Normal & LPM support
+ *
+ * USBTEST Report
+ * - OK: 0-12, 13 (STALL_IN defined) & 14
+ * - Not Supported: 15 & 16 (ISO)
+ *
+ * TODO List
+ * - OTG
+ * - Isochronous & Interrupt Traffic
+ * - Handle requests which spawns into several TDs
+ * - GET_STATUS(device) - always reports 0
+ * - Gadget API (majority of optional features)
+ * - Suspend & Remote Wakeup
+ */
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/chipidea.h>
+
+#include "ci.h"
+#include "udc.h"
+#include "bits.h"
+#include "host.h"
+#include "debug.h"
+
+/* Controller register map */
+static uintptr_t ci_regs_nolpm[] = {
+ [CAP_CAPLENGTH] = 0x000UL,
+ [CAP_HCCPARAMS] = 0x008UL,
+ [CAP_DCCPARAMS] = 0x024UL,
+ [CAP_TESTMODE] = 0x038UL,
+ [OP_USBCMD] = 0x000UL,
+ [OP_USBSTS] = 0x004UL,
+ [OP_USBINTR] = 0x008UL,
+ [OP_DEVICEADDR] = 0x014UL,
+ [OP_ENDPTLISTADDR] = 0x018UL,
+ [OP_PORTSC] = 0x044UL,
+ [OP_DEVLC] = 0x084UL,
+ [OP_OTGSC] = 0x064UL,
+ [OP_USBMODE] = 0x068UL,
+ [OP_ENDPTSETUPSTAT] = 0x06CUL,
+ [OP_ENDPTPRIME] = 0x070UL,
+ [OP_ENDPTFLUSH] = 0x074UL,
+ [OP_ENDPTSTAT] = 0x078UL,
+ [OP_ENDPTCOMPLETE] = 0x07CUL,
+ [OP_ENDPTCTRL] = 0x080UL,
+};
+
+static uintptr_t ci_regs_lpm[] = {
+ [CAP_CAPLENGTH] = 0x000UL,
+ [CAP_HCCPARAMS] = 0x008UL,
+ [CAP_DCCPARAMS] = 0x024UL,
+ [CAP_TESTMODE] = 0x0FCUL,
+ [OP_USBCMD] = 0x000UL,
+ [OP_USBSTS] = 0x004UL,
+ [OP_USBINTR] = 0x008UL,
+ [OP_DEVICEADDR] = 0x014UL,
+ [OP_ENDPTLISTADDR] = 0x018UL,
+ [OP_PORTSC] = 0x044UL,
+ [OP_DEVLC] = 0x084UL,
+ [OP_OTGSC] = 0x0C4UL,
+ [OP_USBMODE] = 0x0C8UL,
+ [OP_ENDPTSETUPSTAT] = 0x0D8UL,
+ [OP_ENDPTPRIME] = 0x0DCUL,
+ [OP_ENDPTFLUSH] = 0x0E0UL,
+ [OP_ENDPTSTAT] = 0x0E4UL,
+ [OP_ENDPTCOMPLETE] = 0x0E8UL,
+ [OP_ENDPTCTRL] = 0x0ECUL,
+};
+
+static int hw_alloc_regmap(struct ci13xxx *ci, bool is_lpm)
+{
+ int i;
+
+ kfree(ci->hw_bank.regmap);
+
+ ci->hw_bank.regmap = kzalloc((OP_LAST + 1) * sizeof(void *),
+ GFP_KERNEL);
+ if (!ci->hw_bank.regmap)
+ return -ENOMEM;
+
+ for (i = 0; i < OP_ENDPTCTRL; i++)
+ ci->hw_bank.regmap[i] =
+ (i <= CAP_LAST ? ci->hw_bank.cap : ci->hw_bank.op) +
+ (is_lpm ? ci_regs_lpm[i] : ci_regs_nolpm[i]);
+
+ for (; i <= OP_LAST; i++)
+ ci->hw_bank.regmap[i] = ci->hw_bank.op +
+ 4 * (i - OP_ENDPTCTRL) +
+ (is_lpm
+ ? ci_regs_lpm[OP_ENDPTCTRL]
+ : ci_regs_nolpm[OP_ENDPTCTRL]);
+
+ return 0;
+}
+
+/**
+ * hw_port_test_set: writes port test mode (execute without interruption)
+ * @mode: new value
+ *
+ * This function returns an error code
+ */
+int hw_port_test_set(struct ci13xxx *ci, u8 mode)
+{
+ const u8 TEST_MODE_MAX = 7;
+
+ if (mode > TEST_MODE_MAX)
+ return -EINVAL;
+
+ hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC));
+ return 0;
+}
+
+/**
+ * hw_port_test_get: reads port test mode value
+ *
+ * This function returns port test mode value
+ */
+u8 hw_port_test_get(struct ci13xxx *ci)
+{
+ return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC);
+}
+
+static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
+{
+ u32 reg;
+
+ /* bank is a module variable */
+ ci->hw_bank.abs = base;
+
+ ci->hw_bank.cap = ci->hw_bank.abs;
+ ci->hw_bank.cap += ci->udc_driver->capoffset;
+ ci->hw_bank.op = ci->hw_bank.cap + ioread8(ci->hw_bank.cap);
+
+ hw_alloc_regmap(ci, false);
+ reg = hw_read(ci, CAP_HCCPARAMS, HCCPARAMS_LEN) >>
+ ffs_nr(HCCPARAMS_LEN);
+ ci->hw_bank.lpm = reg;
+ hw_alloc_regmap(ci, !!reg);
+ ci->hw_bank.size = ci->hw_bank.op - ci->hw_bank.abs;
+ ci->hw_bank.size += OP_LAST;
+ ci->hw_bank.size /= sizeof(u32);
+
+ reg = hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DEN) >>
+ ffs_nr(DCCPARAMS_DEN);
+ ci->hw_ep_max = reg * 2; /* cache hw ENDPT_MAX */
+
+ if (ci->hw_ep_max > ENDPT_MAX)
+ return -ENODEV;
+
+ dev_dbg(ci->dev, "ChipIdea HDRC found, lpm: %d; cap: %p op: %p\n",
+ ci->hw_bank.lpm, ci->hw_bank.cap, ci->hw_bank.op);
+
+ /* setup lock mode ? */
+
+ /* ENDPTSETUPSTAT is '0' by default */
+
+ /* HCSPARAMS.bf.ppc SHOULD BE zero for device */
+
+ return 0;
+}
+
+/**
+ * hw_device_reset: resets chip (execute without interruption)
+ * @ci: the controller
+ *
+ * This function returns an error code
+ */
+int hw_device_reset(struct ci13xxx *ci, u32 mode)
+{
+ /* should flush & stop before reset */
+ hw_write(ci, OP_ENDPTFLUSH, ~0, ~0);
+ hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
+
+ hw_write(ci, OP_USBCMD, USBCMD_RST, USBCMD_RST);
+ while (hw_read(ci, OP_USBCMD, USBCMD_RST))
+ udelay(10); /* not RTOS friendly */
+
+
+ if (ci->udc_driver->notify_event)
+ ci->udc_driver->notify_event(ci,
+ CI13XXX_CONTROLLER_RESET_EVENT);
+
+ if (ci->udc_driver->flags & CI13XXX_DISABLE_STREAMING)
+ hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
+
+ /* USBMODE should be configured step by step */
+ hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
+ hw_write(ci, OP_USBMODE, USBMODE_CM, mode);
+ /* HW >= 2.3 */
+ hw_write(ci, OP_USBMODE, USBMODE_SLOM, USBMODE_SLOM);
+
+ if (hw_read(ci, OP_USBMODE, USBMODE_CM) != mode) {
+ pr_err("cannot enter in %s mode", ci_role(ci)->name);
+ pr_err("lpm = %i", ci->hw_bank.lpm);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/**
+ * ci_otg_role - pick role based on ID pin state
+ * @ci: the controller
+ */
+static enum ci_role ci_otg_role(struct ci13xxx *ci)
+{
+ u32 sts = hw_read(ci, OP_OTGSC, ~0);
+ enum ci_role role = sts & OTGSC_ID
+ ? CI_ROLE_GADGET
+ : CI_ROLE_HOST;
+
+ return role;
+}
+
+/**
+ * ci_role_work - perform role changing based on ID pin
+ * @work: work struct
+ */
+static void ci_role_work(struct work_struct *work)
+{
+ struct ci13xxx *ci = container_of(work, struct ci13xxx, work);
+ enum ci_role role = ci_otg_role(ci);
+
+ hw_write(ci, OP_OTGSC, OTGSC_IDIS, OTGSC_IDIS);
+
+ if (role != ci->role) {
+ dev_dbg(ci->dev, "switching from %s to %s\n",
+ ci_role(ci)->name, ci->roles[role]->name);
+
+ ci_role_stop(ci);
+ ci_role_start(ci, role);
+ }
+}
+
+static ssize_t show_role(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ci13xxx *ci = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", ci_role(ci)->name);
+}
+
+static ssize_t store_role(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ci13xxx *ci = dev_get_drvdata(dev);
+ enum ci_role role;
+ int ret;
+
+ for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
+ if (ci->roles[role] && !strcmp(buf, ci->roles[role]->name))
+ break;
+
+ if (role == CI_ROLE_END || role == ci->role)
+ return -EINVAL;
+
+ ci_role_stop(ci);
+ ret = ci_role_start(ci, role);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR(role, S_IRUSR | S_IWUSR, show_role, store_role);
+
+static irqreturn_t ci_irq(int irq, void *data)
+{
+ struct ci13xxx *ci = data;
+ irqreturn_t ret = IRQ_NONE;
+
+ if (ci->is_otg) {
+ u32 sts = hw_read(ci, OP_OTGSC, ~0);
+
+ if (sts & OTGSC_IDIS) {
+ queue_work(ci->wq, &ci->work);
+ ret = IRQ_HANDLED;
+ }
+ }
+
+ return ci->role == CI_ROLE_END ? ret : ci_role(ci)->irq(ci);
+}
+
+static int __devinit ci_hdrc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ci13xxx *ci;
+ struct resource *res;
+ void __iomem *base;
+ int ret;
+
+ if (!dev->platform_data) {
+ dev_err(dev, "platform data missing\n");
+ return -ENODEV;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "missing resource\n");
+ return -ENODEV;
+ }
+
+ base = devm_request_and_ioremap(dev, res);
+ if (!res) {
+ dev_err(dev, "can't request and ioremap resource\n");
+ return -ENOMEM;
+ }
+
+ ci = devm_kzalloc(dev, sizeof(*ci), GFP_KERNEL);
+ if (!ci) {
+ dev_err(dev, "can't allocate device\n");
+ return -ENOMEM;
+ }
+
+ ci->dev = dev;
+ ci->udc_driver = dev->platform_data;
+
+ ret = hw_device_init(ci, base);
+ if (ret < 0) {
+ dev_err(dev, "can't initialize hardware\n");
+ return -ENODEV;
+ }
+
+ ci->hw_bank.phys = res->start;
+
+ ci->irq = platform_get_irq(pdev, 0);
+ if (ci->irq < 0) {
+ dev_err(dev, "missing IRQ\n");
+ return -ENODEV;
+ }
+
+ INIT_WORK(&ci->work, ci_role_work);
+ ci->wq = create_singlethread_workqueue("ci_otg");
+ if (!ci->wq) {
+ dev_err(dev, "can't create workqueue\n");
+ return -ENODEV;
+ }
+
+ /* initialize role(s) before the interrupt is requested */
+ ret = ci_hdrc_host_init(ci);
+ if (ret)
+ dev_info(dev, "doesn't support host\n");
+
+ ret = ci_hdrc_gadget_init(ci);
+ if (ret)
+ dev_info(dev, "doesn't support gadget\n");
+
+ if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) {
+ dev_err(dev, "no supported roles\n");
+ ret = -ENODEV;
+ goto rm_wq;
+ }
+
+ if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) {
+ ci->is_otg = true;
+ ci->role = ci_otg_role(ci);
+ } else {
+ ci->role = ci->roles[CI_ROLE_HOST]
+ ? CI_ROLE_HOST
+ : CI_ROLE_GADGET;
+ }
+
+ ret = ci_role_start(ci, ci->role);
+ if (ret) {
+ dev_err(dev, "can't start %s role\n", ci_role(ci)->name);
+ ret = -ENODEV;
+ goto rm_wq;
+ }
+
+ platform_set_drvdata(pdev, ci);
+ ret = request_irq(ci->irq, ci_irq, IRQF_SHARED, ci->udc_driver->name,
+ ci);
+ if (ret)
+ goto stop;
+
+ ret = device_create_file(dev, &dev_attr_role);
+ if (ret)
+ goto rm_attr;
+
+ if (ci->is_otg)
+ hw_write(ci, OP_OTGSC, OTGSC_IDIE, OTGSC_IDIE);
+
+ return ret;
+
+rm_attr:
+ device_remove_file(dev, &dev_attr_role);
+stop:
+ ci_role_stop(ci);
+rm_wq:
+ flush_workqueue(ci->wq);
+ destroy_workqueue(ci->wq);
+
+ return ret;
+}
+
+static int __devexit ci_hdrc_remove(struct platform_device *pdev)
+{
+ struct ci13xxx *ci = platform_get_drvdata(pdev);
+
+ flush_workqueue(ci->wq);
+ destroy_workqueue(ci->wq);
+ device_remove_file(ci->dev, &dev_attr_role);
+ free_irq(ci->irq, ci);
+ ci_role_stop(ci);
+
+ return 0;
+}
+
+static struct platform_driver ci_hdrc_driver = {
+ .probe = ci_hdrc_probe,
+ .remove = __devexit_p(ci_hdrc_remove),
+ .driver = {
+ .name = "ci_hdrc",
+ },
+};
+
+module_platform_driver(ci_hdrc_driver);
+
+MODULE_ALIAS("platform:ci_hdrc");
+MODULE_ALIAS("platform:ci13xxx");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("David Lopo <dlopo@chipidea.mips.com>");
+MODULE_DESCRIPTION("ChipIdea HDRC Driver");
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
new file mode 100644
index 000000000000..c4b3e15532db
--- /dev/null
+++ b/drivers/usb/chipidea/debug.c
@@ -0,0 +1,804 @@
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/chipidea.h>
+
+#include "ci.h"
+#include "udc.h"
+#include "bits.h"
+#include "debug.h"
+
+/* Interrupt statistics */
+#define ISR_MASK 0x1F
+static struct isr_statistics {
+ u32 test;
+ u32 ui;
+ u32 uei;
+ u32 pci;
+ u32 uri;
+ u32 sli;
+ u32 none;
+ struct {
+ u32 cnt;
+ u32 buf[ISR_MASK+1];
+ u32 idx;
+ } hndl;
+} isr_statistics;
+
+void dbg_interrupt(u32 intmask)
+{
+ if (!intmask) {
+ isr_statistics.none++;
+ return;
+ }
+
+ isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intmask;
+ isr_statistics.hndl.idx &= ISR_MASK;
+ isr_statistics.hndl.cnt++;
+
+ if (USBi_URI & intmask)
+ isr_statistics.uri++;
+ if (USBi_PCI & intmask)
+ isr_statistics.pci++;
+ if (USBi_UEI & intmask)
+ isr_statistics.uei++;
+ if (USBi_UI & intmask)
+ isr_statistics.ui++;
+ if (USBi_SLI & intmask)
+ isr_statistics.sli++;
+}
+
+/**
+ * hw_register_read: reads all device registers (execute without interruption)
+ * @buf: destination buffer
+ * @size: buffer size
+ *
+ * This function returns number of registers read
+ */
+static size_t hw_register_read(struct ci13xxx *udc, u32 *buf, size_t size)
+{
+ unsigned i;
+
+ if (size > udc->hw_bank.size)
+ size = udc->hw_bank.size;
+
+ for (i = 0; i < size; i++)
+ buf[i] = hw_read(udc, i * sizeof(u32), ~0);
+
+ return size;
+}
+
+/**
+ * hw_register_write: writes to register
+ * @addr: register address
+ * @data: register value
+ *
+ * This function returns an error code
+ */
+static int hw_register_write(struct ci13xxx *udc, u16 addr, u32 data)
+{
+ /* align */
+ addr /= sizeof(u32);
+
+ if (addr >= udc->hw_bank.size)
+ return -EINVAL;
+
+ /* align */
+ addr *= sizeof(u32);
+
+ hw_write(udc, addr, ~0, data);
+ return 0;
+}
+
+/**
+ * hw_intr_clear: disables interrupt & clears interrupt status (execute without
+ * interruption)
+ * @n: interrupt bit
+ *
+ * This function returns an error code
+ */
+static int hw_intr_clear(struct ci13xxx *udc, int n)
+{
+ if (n >= REG_BITS)
+ return -EINVAL;
+
+ hw_write(udc, OP_USBINTR, BIT(n), 0);
+ hw_write(udc, OP_USBSTS, BIT(n), BIT(n));
+ return 0;
+}
+
+/**
+ * hw_intr_force: enables interrupt & forces interrupt status (execute without
+ * interruption)
+ * @n: interrupt bit
+ *
+ * This function returns an error code
+ */
+static int hw_intr_force(struct ci13xxx *udc, int n)
+{
+ if (n >= REG_BITS)
+ return -EINVAL;
+
+ hw_write(udc, CAP_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE);
+ hw_write(udc, OP_USBINTR, BIT(n), BIT(n));
+ hw_write(udc, OP_USBSTS, BIT(n), BIT(n));
+ hw_write(udc, CAP_TESTMODE, TESTMODE_FORCE, 0);
+ return 0;
+}
+
+/**
+ * show_device: prints information about device capabilities and status
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_device(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ struct usb_gadget *gadget = &udc->gadget;
+ int n = 0;
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+ return 0;
+ }
+
+ n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n",
+ gadget->speed);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed = %d\n",
+ gadget->max_speed);
+ /* TODO: Scheduled for removal in 3.8. */
+ n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed = %d\n",
+ gadget_is_dualspeed(gadget));
+ n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n",
+ gadget->is_otg);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n",
+ gadget->is_a_peripheral);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable = %d\n",
+ gadget->b_hnp_enable);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support = %d\n",
+ gadget->a_hnp_support);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n",
+ gadget->a_alt_hnp_support);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "name = %s\n",
+ (gadget->name ? gadget->name : ""));
+
+ return n;
+}
+static DEVICE_ATTR(device, S_IRUSR, show_device, NULL);
+
+/**
+ * show_driver: prints information about attached gadget (if any)
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_driver(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ struct usb_gadget_driver *driver = udc->driver;
+ int n = 0;
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(dev, "[%s] EINVAL\n", __func__);
+ return 0;
+ }
+
+ if (driver == NULL)
+ return scnprintf(buf, PAGE_SIZE,
+ "There is no gadget attached!\n");
+
+ n += scnprintf(buf + n, PAGE_SIZE - n, "function = %s\n",
+ (driver->function ? driver->function : ""));
+ n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n",
+ driver->max_speed);
+
+ return n;
+}
+static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL);
+
+/* Maximum event message length */
+#define DBG_DATA_MSG 64UL
+
+/* Maximum event messages */
+#define DBG_DATA_MAX 128UL
+
+/* Event buffer descriptor */
+static struct {
+ char (buf[DBG_DATA_MAX])[DBG_DATA_MSG]; /* buffer */
+ unsigned idx; /* index */
+ unsigned tty; /* print to console? */
+ rwlock_t lck; /* lock */
+} dbg_data = {
+ .idx = 0,
+ .tty = 0,
+ .lck = __RW_LOCK_UNLOCKED(lck)
+};
+
+/**
+ * dbg_dec: decrements debug event index
+ * @idx: buffer index
+ */
+static void dbg_dec(unsigned *idx)
+{
+ *idx = (*idx - 1) & (DBG_DATA_MAX-1);
+}
+
+/**
+ * dbg_inc: increments debug event index
+ * @idx: buffer index
+ */
+static void dbg_inc(unsigned *idx)
+{
+ *idx = (*idx + 1) & (DBG_DATA_MAX-1);
+}
+
+/**
+ * dbg_print: prints the common part of the event
+ * @addr: endpoint address
+ * @name: event name
+ * @status: status
+ * @extra: extra information
+ */
+static void dbg_print(u8 addr, const char *name, int status, const char *extra)
+{
+ struct timeval tval;
+ unsigned int stamp;
+ unsigned long flags;
+
+ write_lock_irqsave(&dbg_data.lck, flags);
+
+ do_gettimeofday(&tval);
+ stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s */
+ stamp = stamp * 1000000 + tval.tv_usec;
+
+ scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG,
+ "%04X\t? %02X %-7.7s %4i ?\t%s\n",
+ stamp, addr, name, status, extra);
+
+ dbg_inc(&dbg_data.idx);
+
+ write_unlock_irqrestore(&dbg_data.lck, flags);
+
+ if (dbg_data.tty != 0)
+ pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n",
+ stamp, addr, name, status, extra);
+}
+
+/**
+ * dbg_done: prints a DONE event
+ * @addr: endpoint address
+ * @td: transfer descriptor
+ * @status: status
+ */
+void dbg_done(u8 addr, const u32 token, int status)
+{
+ char msg[DBG_DATA_MSG];
+
+ scnprintf(msg, sizeof(msg), "%d %02X",
+ (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES),
+ (int)(token & TD_STATUS) >> ffs_nr(TD_STATUS));
+ dbg_print(addr, "DONE", status, msg);
+}
+
+/**
+ * dbg_event: prints a generic event
+ * @addr: endpoint address
+ * @name: event name
+ * @status: status
+ */
+void dbg_event(u8 addr, const char *name, int status)
+{
+ if (name != NULL)
+ dbg_print(addr, name, status, "");
+}
+
+/*
+ * dbg_queue: prints a QUEUE event
+ * @addr: endpoint address
+ * @req: USB request
+ * @status: status
+ */
+void dbg_queue(u8 addr, const struct usb_request *req, int status)
+{
+ char msg[DBG_DATA_MSG];
+
+ if (req != NULL) {
+ scnprintf(msg, sizeof(msg),
+ "%d %d", !req->no_interrupt, req->length);
+ dbg_print(addr, "QUEUE", status, msg);
+ }
+}
+
+/**
+ * dbg_setup: prints a SETUP event
+ * @addr: endpoint address
+ * @req: setup request
+ */
+void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
+{
+ char msg[DBG_DATA_MSG];
+
+ if (req != NULL) {
+ scnprintf(msg, sizeof(msg),
+ "%02X %02X %04X %04X %d", req->bRequestType,
+ req->bRequest, le16_to_cpu(req->wValue),
+ le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength));
+ dbg_print(addr, "SETUP", 0, msg);
+ }
+}
+
+/**
+ * show_events: displays the event buffer
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_events(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ unsigned long flags;
+ unsigned i, j, n = 0;
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(dev->parent, "[%s] EINVAL\n", __func__);
+ return 0;
+ }
+
+ read_lock_irqsave(&dbg_data.lck, flags);
+
+ i = dbg_data.idx;
+ for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) {
+ n += strlen(dbg_data.buf[i]);
+ if (n >= PAGE_SIZE) {
+ n -= strlen(dbg_data.buf[i]);
+ break;
+ }
+ }
+ for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i))
+ j += scnprintf(buf + j, PAGE_SIZE - j,
+ "%s", dbg_data.buf[i]);
+
+ read_unlock_irqrestore(&dbg_data.lck, flags);
+
+ return n;
+}
+
+/**
+ * store_events: configure if events are going to be also printed to console
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_events(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned tty;
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(dev, "[%s] EINVAL\n", __func__);
+ goto done;
+ }
+
+ if (sscanf(buf, "%u", &tty) != 1 || tty > 1) {
+ dev_err(dev, "<1|0>: enable|disable console log\n");
+ goto done;
+ }
+
+ dbg_data.tty = tty;
+ dev_info(dev, "tty = %u", dbg_data.tty);
+
+ done:
+ return count;
+}
+static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events);
+
+/**
+ * show_inters: interrupt status, enable status and historic
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long flags;
+ u32 intr;
+ unsigned i, j, n = 0;
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+ return 0;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /*n += scnprintf(buf + n, PAGE_SIZE - n,
+ "status = %08x\n", hw_read_intr_status(udc));
+ n += scnprintf(buf + n, PAGE_SIZE - n,
+ "enable = %08x\n", hw_read_intr_enable(udc));*/
+
+ n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n",
+ isr_statistics.test);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "? ui = %d\n",
+ isr_statistics.ui);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n",
+ isr_statistics.uei);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n",
+ isr_statistics.pci);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n",
+ isr_statistics.uri);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n",
+ isr_statistics.sli);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n",
+ isr_statistics.none);
+ n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n",
+ isr_statistics.hndl.cnt);
+
+ for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) {
+ i &= ISR_MASK;
+ intr = isr_statistics.hndl.buf[i];
+
+ if (USBi_UI & intr)
+ n += scnprintf(buf + n, PAGE_SIZE - n, "ui ");
+ intr &= ~USBi_UI;
+ if (USBi_UEI & intr)
+ n += scnprintf(buf + n, PAGE_SIZE - n, "uei ");
+ intr &= ~USBi_UEI;
+ if (USBi_PCI & intr)
+ n += scnprintf(buf + n, PAGE_SIZE - n, "pci ");
+ intr &= ~USBi_PCI;
+ if (USBi_URI & intr)
+ n += scnprintf(buf + n, PAGE_SIZE - n, "uri ");
+ intr &= ~USBi_URI;
+ if (USBi_SLI & intr)
+ n += scnprintf(buf + n, PAGE_SIZE - n, "sli ");
+ intr &= ~USBi_SLI;
+ if (intr)
+ n += scnprintf(buf + n, PAGE_SIZE - n, "??? ");
+ if (isr_statistics.hndl.buf[i])
+ n += scnprintf(buf + n, PAGE_SIZE - n, "\n");
+ }
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return n;
+}
+
+/**
+ * store_inters: enable & force or disable an individual interrutps
+ * (to be used for test purposes only)
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_inters(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long flags;
+ unsigned en, bit;
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(udc->dev, "EINVAL\n");
+ goto done;
+ }
+
+ if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) {
+ dev_err(udc->dev, "<1|0> <bit>: enable|disable interrupt\n");
+ goto done;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+ if (en) {
+ if (hw_intr_force(udc, bit))
+ dev_err(dev, "invalid bit number\n");
+ else
+ isr_statistics.test++;
+ } else {
+ if (hw_intr_clear(udc, bit))
+ dev_err(dev, "invalid bit number\n");
+ }
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ done:
+ return count;
+}
+static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters);
+
+/**
+ * show_port_test: reads port test mode
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_port_test(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long flags;
+ unsigned mode;
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(udc->dev, "EINVAL\n");
+ return 0;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+ mode = hw_port_test_get(udc);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode);
+}
+
+/**
+ * store_port_test: writes port test mode
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_port_test(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long flags;
+ unsigned mode;
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+ goto done;
+ }
+
+ if (sscanf(buf, "%u", &mode) != 1) {
+ dev_err(udc->dev, "<mode>: set port test mode");
+ goto done;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+ if (hw_port_test_set(udc, mode))
+ dev_err(udc->dev, "invalid mode\n");
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ done:
+ return count;
+}
+static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR,
+ show_port_test, store_port_test);
+
+/**
+ * show_qheads: DMA contents of all queue heads
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long flags;
+ unsigned i, j, n = 0;
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+ return 0;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+ for (i = 0; i < udc->hw_ep_max/2; i++) {
+ struct ci13xxx_ep *mEpRx = &udc->ci13xxx_ep[i];
+ struct ci13xxx_ep *mEpTx =
+ &udc->ci13xxx_ep[i + udc->hw_ep_max/2];
+ n += scnprintf(buf + n, PAGE_SIZE - n,
+ "EP=%02i: RX=%08X TX=%08X\n",
+ i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
+ for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) {
+ n += scnprintf(buf + n, PAGE_SIZE - n,
+ " %04X: %08X %08X\n", j,
+ *((u32 *)mEpRx->qh.ptr + j),
+ *((u32 *)mEpTx->qh.ptr + j));
+ }
+ }
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return n;
+}
+static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL);
+
+/**
+ * show_registers: dumps all registers
+ *
+ * Check "device.h" for details
+ */
+#define DUMP_ENTRIES 512
+static ssize_t show_registers(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long flags;
+ u32 *dump;
+ unsigned i, k, n = 0;
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+ return 0;
+ }
+
+ dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
+ if (!dump) {
+ dev_err(udc->dev, "%s: out of memory\n", __func__);
+ return 0;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+ k = hw_register_read(udc, dump, DUMP_ENTRIES);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ for (i = 0; i < k; i++) {
+ n += scnprintf(buf + n, PAGE_SIZE - n,
+ "reg[0x%04X] = 0x%08X\n",
+ i * (unsigned)sizeof(u32), dump[i]);
+ }
+ kfree(dump);
+
+ return n;
+}
+
+/**
+ * store_registers: writes value to register address
+ *
+ * Check "device.h" for details
+ */
+static ssize_t store_registers(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long addr, data, flags;
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+ goto done;
+ }
+
+ if (sscanf(buf, "%li %li", &addr, &data) != 2) {
+ dev_err(udc->dev,
+ "<addr> <data>: write data to register address\n");
+ goto done;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+ if (hw_register_write(udc, addr, data))
+ dev_err(udc->dev, "invalid address range\n");
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ done:
+ return count;
+}
+static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR,
+ show_registers, store_registers);
+
+/**
+ * show_requests: DMA contents of all requests currently queued (all endpts)
+ *
+ * Check "device.h" for details
+ */
+static ssize_t show_requests(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
+ unsigned long flags;
+ struct list_head *ptr = NULL;
+ struct ci13xxx_req *req = NULL;
+ unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
+
+ if (attr == NULL || buf == NULL) {
+ dev_err(udc->dev, "[%s] EINVAL\n", __func__);
+ return 0;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+ for (i = 0; i < udc->hw_ep_max; i++)
+ list_for_each(ptr, &udc->ci13xxx_ep[i].qh.queue)
+ {
+ req = list_entry(ptr, struct ci13xxx_req, queue);
+
+ n += scnprintf(buf + n, PAGE_SIZE - n,
+ "EP=%02i: TD=%08X %s\n",
+ i % udc->hw_ep_max/2, (u32)req->dma,
+ ((i < udc->hw_ep_max/2) ? "RX" : "TX"));
+
+ for (j = 0; j < qSize; j++)
+ n += scnprintf(buf + n, PAGE_SIZE - n,
+ " %04X: %08X\n", j,
+ *((u32 *)req->ptr + j));
+ }
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return n;
+}
+static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL);
+
+/**
+ * dbg_create_files: initializes the attribute interface
+ * @dev: device
+ *
+ * This function returns an error code
+ */
+int dbg_create_files(struct device *dev)
+{
+ int retval = 0;
+
+ if (dev == NULL)
+ return -EINVAL;
+ retval = device_create_file(dev, &dev_attr_device);
+ if (retval)
+ goto done;
+ retval = device_create_file(dev, &dev_attr_driver);
+ if (retval)
+ goto rm_device;
+ retval = device_create_file(dev, &dev_attr_events);
+ if (retval)
+ goto rm_driver;
+ retval = device_create_file(dev, &dev_attr_inters);
+ if (retval)
+ goto rm_events;
+ retval = device_create_file(dev, &dev_attr_port_test);
+ if (retval)
+ goto rm_inters;
+ retval = device_create_file(dev, &dev_attr_qheads);
+ if (retval)
+ goto rm_port_test;
+ retval = device_create_file(dev, &dev_attr_registers);
+ if (retval)
+ goto rm_qheads;
+ retval = device_create_file(dev, &dev_attr_requests);
+ if (retval)
+ goto rm_registers;
+ return 0;
+
+ rm_registers:
+ device_remove_file(dev, &dev_attr_registers);
+ rm_qheads:
+ device_remove_file(dev, &dev_attr_qheads);
+ rm_port_test:
+ device_remove_file(dev, &dev_attr_port_test);
+ rm_inters:
+ device_remove_file(dev, &dev_attr_inters);
+ rm_events:
+ device_remove_file(dev, &dev_attr_events);
+ rm_driver:
+ device_remove_file(dev, &dev_attr_driver);
+ rm_device:
+ device_remove_file(dev, &dev_attr_device);
+ done:
+ return retval;
+}
+
+/**
+ * dbg_remove_files: destroys the attribute interface
+ * @dev: device
+ *
+ * This function returns an error code
+ */
+int dbg_remove_files(struct device *dev)
+{
+ if (dev == NULL)
+ return -EINVAL;
+ device_remove_file(dev, &dev_attr_requests);
+ device_remove_file(dev, &dev_attr_registers);
+ device_remove_file(dev, &dev_attr_qheads);
+ device_remove_file(dev, &dev_attr_port_test);
+ device_remove_file(dev, &dev_attr_inters);
+ device_remove_file(dev, &dev_attr_events);
+ device_remove_file(dev, &dev_attr_driver);
+ device_remove_file(dev, &dev_attr_device);
+ return 0;
+}
diff --git a/drivers/usb/chipidea/debug.h b/drivers/usb/chipidea/debug.h
new file mode 100644
index 000000000000..80d96865775c
--- /dev/null
+++ b/drivers/usb/chipidea/debug.h
@@ -0,0 +1,56 @@
+/*
+ * debug.h - ChipIdea USB driver debug interfaces
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * 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 __DRIVERS_USB_CHIPIDEA_DEBUG_H
+#define __DRIVERS_USB_CHIPIDEA_DEBUG_H
+
+#ifdef CONFIG_USB_CHIPIDEA_DEBUG
+void dbg_interrupt(u32 intmask);
+void dbg_done(u8 addr, const u32 token, int status);
+void dbg_event(u8 addr, const char *name, int status);
+void dbg_queue(u8 addr, const struct usb_request *req, int status);
+void dbg_setup(u8 addr, const struct usb_ctrlrequest *req);
+int dbg_create_files(struct device *dev);
+int dbg_remove_files(struct device *dev);
+#else
+static inline void dbg_interrupt(u32 intmask)
+{
+}
+
+static inline void dbg_done(u8 addr, const u32 token, int status)
+{
+}
+
+static inline void dbg_event(u8 addr, const char *name, int status)
+{
+}
+
+static inline void dbg_queue(u8 addr, const struct usb_request *req, int status)
+{
+}
+
+static inline void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
+{
+}
+
+static inline int dbg_create_files(struct device *dev)
+{
+ return 0;
+}
+
+static inline int dbg_remove_files(struct device *dev)
+{
+ return 0;
+}
+#endif
+
+#endif /* __DRIVERS_USB_CHIPIDEA_DEBUG_H */
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c
new file mode 100644
index 000000000000..9eacd21c0cd9
--- /dev/null
+++ b/drivers/usb/chipidea/host.c
@@ -0,0 +1,160 @@
+/*
+ * host.c - ChipIdea USB host controller driver
+ *
+ * Copyright (c) 2012 Intel Corporation
+ *
+ * Author: Alexander Shishkin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/usb/chipidea.h>
+
+#define CHIPIDEA_EHCI
+#include "../host/ehci-hcd.c"
+
+#include "ci.h"
+#include "bits.h"
+#include "host.h"
+
+static int ci_ehci_setup(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int ret;
+
+ hcd->has_tt = 1;
+
+ ret = ehci_setup(hcd);
+ if (ret)
+ return ret;
+
+ ehci_port_power(ehci, 0);
+
+ return ret;
+}
+
+static const struct hc_driver ci_ehci_hc_driver = {
+ .description = "ehci_hcd",
+ .product_desc = "ChipIdea HDRC EHCI",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = ci_ehci_setup,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ehci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+};
+
+static irqreturn_t host_irq(struct ci13xxx *ci)
+{
+ return usb_hcd_irq(ci->irq, ci->hcd);
+}
+
+static int host_start(struct ci13xxx *ci)
+{
+ struct usb_hcd *hcd;
+ struct ehci_hcd *ehci;
+ int ret;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ hcd = usb_create_hcd(&ci_ehci_hc_driver, ci->dev, dev_name(ci->dev));
+ if (!hcd)
+ return -ENOMEM;
+
+ dev_set_drvdata(ci->dev, ci);
+ hcd->rsrc_start = ci->hw_bank.phys;
+ hcd->rsrc_len = ci->hw_bank.size;
+ hcd->regs = ci->hw_bank.abs;
+ hcd->has_tt = 1;
+
+ hcd->power_budget = ci->udc_driver->power_budget;
+
+ ehci = hcd_to_ehci(hcd);
+ ehci->caps = ci->hw_bank.cap;
+ ehci->has_hostpc = ci->hw_bank.lpm;
+
+ ret = usb_add_hcd(hcd, 0, 0);
+ if (ret)
+ usb_put_hcd(hcd);
+ else
+ ci->hcd = hcd;
+
+ return ret;
+}
+
+static void host_stop(struct ci13xxx *ci)
+{
+ struct usb_hcd *hcd = ci->hcd;
+
+ usb_remove_hcd(hcd);
+ usb_put_hcd(hcd);
+}
+
+int ci_hdrc_host_init(struct ci13xxx *ci)
+{
+ struct ci_role_driver *rdrv;
+
+ if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_HC))
+ return -ENXIO;
+
+ rdrv = devm_kzalloc(ci->dev, sizeof(struct ci_role_driver), GFP_KERNEL);
+ if (!rdrv)
+ return -ENOMEM;
+
+ rdrv->start = host_start;
+ rdrv->stop = host_stop;
+ rdrv->irq = host_irq;
+ rdrv->name = "host";
+ ci->roles[CI_ROLE_HOST] = rdrv;
+
+ return 0;
+}
diff --git a/drivers/usb/chipidea/host.h b/drivers/usb/chipidea/host.h
new file mode 100644
index 000000000000..761fb1fd6d99
--- /dev/null
+++ b/drivers/usb/chipidea/host.h
@@ -0,0 +1,17 @@
+#ifndef __DRIVERS_USB_CHIPIDEA_HOST_H
+#define __DRIVERS_USB_CHIPIDEA_HOST_H
+
+#ifdef CONFIG_USB_CHIPIDEA_HOST
+
+int ci_hdrc_host_init(struct ci13xxx *ci);
+
+#else
+
+static inline int ci_hdrc_host_init(struct ci13xxx *ci)
+{
+ return -ENXIO;
+}
+
+#endif
+
+#endif /* __DRIVERS_USB_CHIPIDEA_HOST_H */
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
new file mode 100644
index 000000000000..51f96942dc5e
--- /dev/null
+++ b/drivers/usb/chipidea/udc.c
@@ -0,0 +1,1809 @@
+/*
+ * udc.c - ChipIdea UDC driver
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * 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/delay.h>
+#include <linux/device.h>
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/chipidea.h>
+
+#include "ci.h"
+#include "udc.h"
+#include "bits.h"
+#include "debug.h"
+
+/* control endpoint description */
+static const struct usb_endpoint_descriptor
+ctrl_endpt_out_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+ .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX),
+};
+
+static const struct usb_endpoint_descriptor
+ctrl_endpt_in_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+ .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX),
+};
+
+/**
+ * hw_ep_bit: calculates the bit number
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns bit number
+ */
+static inline int hw_ep_bit(int num, int dir)
+{
+ return num + (dir ? 16 : 0);
+}
+
+static inline int ep_to_bit(struct ci13xxx *udc, int n)
+{
+ int fill = 16 - udc->hw_ep_max / 2;
+
+ if (n >= udc->hw_ep_max / 2)
+ n += fill;
+
+ return n;
+}
+
+/**
+ * hw_device_state: enables/disables interrupts & starts/stops device (execute
+ * without interruption)
+ * @dma: 0 => disable, !0 => enable and set dma engine
+ *
+ * This function returns an error code
+ */
+static int hw_device_state(struct ci13xxx *udc, u32 dma)
+{
+ if (dma) {
+ hw_write(udc, OP_ENDPTLISTADDR, ~0, dma);
+ /* interrupt, error, port change, reset, sleep/suspend */
+ hw_write(udc, OP_USBINTR, ~0,
+ USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI);
+ hw_write(udc, OP_USBCMD, USBCMD_RS, USBCMD_RS);
+ } else {
+ hw_write(udc, OP_USBCMD, USBCMD_RS, 0);
+ hw_write(udc, OP_USBINTR, ~0, 0);
+ }
+ return 0;
+}
+
+/**
+ * hw_ep_flush: flush endpoint fifo (execute without interruption)
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns an error code
+ */
+static int hw_ep_flush(struct ci13xxx *udc, int num, int dir)
+{
+ int n = hw_ep_bit(num, dir);
+
+ do {
+ /* flush any pending transfer */
+ hw_write(udc, OP_ENDPTFLUSH, BIT(n), BIT(n));
+ while (hw_read(udc, OP_ENDPTFLUSH, BIT(n)))
+ cpu_relax();
+ } while (hw_read(udc, OP_ENDPTSTAT, BIT(n)));
+
+ return 0;
+}
+
+/**
+ * hw_ep_disable: disables endpoint (execute without interruption)
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns an error code
+ */
+static int hw_ep_disable(struct ci13xxx *udc, int num, int dir)
+{
+ hw_ep_flush(udc, num, dir);
+ hw_write(udc, OP_ENDPTCTRL + num,
+ dir ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0);
+ return 0;
+}
+
+/**
+ * hw_ep_enable: enables endpoint (execute without interruption)
+ * @num: endpoint number
+ * @dir: endpoint direction
+ * @type: endpoint type
+ *
+ * This function returns an error code
+ */
+static int hw_ep_enable(struct ci13xxx *udc, int num, int dir, int type)
+{
+ u32 mask, data;
+
+ if (dir) {
+ mask = ENDPTCTRL_TXT; /* type */
+ data = type << ffs_nr(mask);
+
+ mask |= ENDPTCTRL_TXS; /* unstall */
+ mask |= ENDPTCTRL_TXR; /* reset data toggle */
+ data |= ENDPTCTRL_TXR;
+ mask |= ENDPTCTRL_TXE; /* enable */
+ data |= ENDPTCTRL_TXE;
+ } else {
+ mask = ENDPTCTRL_RXT; /* type */
+ data = type << ffs_nr(mask);
+
+ mask |= ENDPTCTRL_RXS; /* unstall */
+ mask |= ENDPTCTRL_RXR; /* reset data toggle */
+ data |= ENDPTCTRL_RXR;
+ mask |= ENDPTCTRL_RXE; /* enable */
+ data |= ENDPTCTRL_RXE;
+ }
+ hw_write(udc, OP_ENDPTCTRL + num, mask, data);
+ return 0;
+}
+
+/**
+ * hw_ep_get_halt: return endpoint halt status
+ * @num: endpoint number
+ * @dir: endpoint direction
+ *
+ * This function returns 1 if endpoint halted
+ */
+static int hw_ep_get_halt(struct ci13xxx *udc, int num, int dir)
+{
+ u32 mask = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
+
+ return hw_read(udc, OP_ENDPTCTRL + num, mask) ? 1 : 0;
+}
+
+/**
+ * hw_test_and_clear_setup_status: test & clear setup status (execute without
+ * interruption)
+ * @n: endpoint number
+ *
+ * This function returns setup status
+ */
+static int hw_test_and_clear_setup_status(struct ci13xxx *udc, int n)
+{
+ n = ep_to_bit(udc, n);
+ return hw_test_and_clear(udc, OP_ENDPTSETUPSTAT, BIT(n));
+}
+
+/**
+ * hw_ep_prime: primes endpoint (execute without interruption)
+ * @num: endpoint number
+ * @dir: endpoint direction
+ * @is_ctrl: true if control endpoint
+ *
+ * This function returns an error code
+ */
+static int hw_ep_prime(struct ci13xxx *udc, int num, int dir, int is_ctrl)
+{
+ int n = hw_ep_bit(num, dir);
+
+ if (is_ctrl && dir == RX && hw_read(udc, OP_ENDPTSETUPSTAT, BIT(num)))
+ return -EAGAIN;
+
+ hw_write(udc, OP_ENDPTPRIME, BIT(n), BIT(n));
+
+ while (hw_read(udc, OP_ENDPTPRIME, BIT(n)))
+ cpu_relax();
+ if (is_ctrl && dir == RX && hw_read(udc, OP_ENDPTSETUPSTAT, BIT(num)))
+ return -EAGAIN;
+
+ /* status shoult be tested according with manual but it doesn't work */
+ return 0;
+}
+
+/**
+ * hw_ep_set_halt: configures ep halt & resets data toggle after clear (execute
+ * without interruption)
+ * @num: endpoint number
+ * @dir: endpoint direction
+ * @value: true => stall, false => unstall
+ *
+ * This function returns an error code
+ */
+static int hw_ep_set_halt(struct ci13xxx *udc, int num, int dir, int value)
+{
+ if (value != 0 && value != 1)
+ return -EINVAL;
+
+ do {
+ enum ci13xxx_regs reg = OP_ENDPTCTRL + num;
+ u32 mask_xs = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
+ u32 mask_xr = dir ? ENDPTCTRL_TXR : ENDPTCTRL_RXR;
+
+ /* data toggle - reserved for EP0 but it's in ESS */
+ hw_write(udc, reg, mask_xs|mask_xr,
+ value ? mask_xs : mask_xr);
+ } while (value != hw_ep_get_halt(udc, num, dir));
+
+ return 0;
+}
+
+/**
+ * hw_is_port_high_speed: test if port is high speed
+ *
+ * This function returns true if high speed port
+ */
+static int hw_port_is_high_speed(struct ci13xxx *udc)
+{
+ return udc->hw_bank.lpm ? hw_read(udc, OP_DEVLC, DEVLC_PSPD) :
+ hw_read(udc, OP_PORTSC, PORTSC_HSP);
+}
+
+/**
+ * hw_read_intr_enable: returns interrupt enable register
+ *
+ * This function returns register data
+ */
+static u32 hw_read_intr_enable(struct ci13xxx *udc)
+{
+ return hw_read(udc, OP_USBINTR, ~0);
+}
+
+/**
+ * hw_read_intr_status: returns interrupt status register
+ *
+ * This function returns register data
+ */
+static u32 hw_read_intr_status(struct ci13xxx *udc)
+{
+ return hw_read(udc, OP_USBSTS, ~0);
+}
+
+/**
+ * hw_test_and_clear_complete: test & clear complete status (execute without
+ * interruption)
+ * @n: endpoint number
+ *
+ * This function returns complete status
+ */
+static int hw_test_and_clear_complete(struct ci13xxx *udc, int n)
+{
+ n = ep_to_bit(udc, n);
+ return hw_test_and_clear(udc, OP_ENDPTCOMPLETE, BIT(n));
+}
+
+/**
+ * hw_test_and_clear_intr_active: test & clear active interrupts (execute
+ * without interruption)
+ *
+ * This function returns active interrutps
+ */
+static u32 hw_test_and_clear_intr_active(struct ci13xxx *udc)
+{
+ u32 reg = hw_read_intr_status(udc) & hw_read_intr_enable(udc);
+
+ hw_write(udc, OP_USBSTS, ~0, reg);
+ return reg;
+}
+
+/**
+ * hw_test_and_clear_setup_guard: test & clear setup guard (execute without
+ * interruption)
+ *
+ * This function returns guard value
+ */
+static int hw_test_and_clear_setup_guard(struct ci13xxx *udc)
+{
+ return hw_test_and_write(udc, OP_USBCMD, USBCMD_SUTW, 0);
+}
+
+/**
+ * hw_test_and_set_setup_guard: test & set setup guard (execute without
+ * interruption)
+ *
+ * This function returns guard value
+ */
+static int hw_test_and_set_setup_guard(struct ci13xxx *udc)
+{
+ return hw_test_and_write(udc, OP_USBCMD, USBCMD_SUTW, USBCMD_SUTW);
+}
+
+/**
+ * hw_usb_set_address: configures USB address (execute without interruption)
+ * @value: new USB address
+ *
+ * This function explicitly sets the address, without the "USBADRA" (advance)
+ * feature, which is not supported by older versions of the controller.
+ */
+static void hw_usb_set_address(struct ci13xxx *udc, u8 value)
+{
+ hw_write(udc, OP_DEVICEADDR, DEVICEADDR_USBADR,
+ value << ffs_nr(DEVICEADDR_USBADR));
+}
+
+/**
+ * hw_usb_reset: restart device after a bus reset (execute without
+ * interruption)
+ *
+ * This function returns an error code
+ */
+static int hw_usb_reset(struct ci13xxx *udc)
+{
+ hw_usb_set_address(udc, 0);
+
+ /* ESS flushes only at end?!? */
+ hw_write(udc, OP_ENDPTFLUSH, ~0, ~0);
+
+ /* clear setup token semaphores */
+ hw_write(udc, OP_ENDPTSETUPSTAT, 0, 0);
+
+ /* clear complete status */
+ hw_write(udc, OP_ENDPTCOMPLETE, 0, 0);
+
+ /* wait until all bits cleared */
+ while (hw_read(udc, OP_ENDPTPRIME, ~0))
+ udelay(10); /* not RTOS friendly */
+
+ /* reset all endpoints ? */
+
+ /* reset internal status and wait for further instructions
+ no need to verify the port reset status (ESS does it) */
+
+ return 0;
+}
+
+/******************************************************************************
+ * UTIL block
+ *****************************************************************************/
+/**
+ * _usb_addr: calculates endpoint address from direction & number
+ * @ep: endpoint
+ */
+static inline u8 _usb_addr(struct ci13xxx_ep *ep)
+{
+ return ((ep->dir == TX) ? USB_ENDPOINT_DIR_MASK : 0) | ep->num;
+}
+
+/**
+ * _hardware_queue: configures a request at hardware level
+ * @gadget: gadget
+ * @mEp: endpoint
+ *
+ * This function returns an error code
+ */
+static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
+{
+ struct ci13xxx *udc = mEp->udc;
+ unsigned i;
+ int ret = 0;
+ unsigned length = mReq->req.length;
+
+ /* don't queue twice */
+ if (mReq->req.status == -EALREADY)
+ return -EALREADY;
+
+ mReq->req.status = -EALREADY;
+
+ if (mReq->req.zero && length && (length % mEp->ep.maxpacket == 0)) {
+ mReq->zptr = dma_pool_alloc(mEp->td_pool, GFP_ATOMIC,
+ &mReq->zdma);
+ if (mReq->zptr == NULL)
+ return -ENOMEM;
+
+ memset(mReq->zptr, 0, sizeof(*mReq->zptr));
+ mReq->zptr->next = TD_TERMINATE;
+ mReq->zptr->token = TD_STATUS_ACTIVE;
+ if (!mReq->req.no_interrupt)
+ mReq->zptr->token |= TD_IOC;
+ }
+ ret = usb_gadget_map_request(&udc->gadget, &mReq->req, mEp->dir);
+ if (ret)
+ return ret;
+
+ /*
+ * TD configuration
+ * TODO - handle requests which spawns into several TDs
+ */
+ memset(mReq->ptr, 0, sizeof(*mReq->ptr));
+ mReq->ptr->token = length << ffs_nr(TD_TOTAL_BYTES);
+ mReq->ptr->token &= TD_TOTAL_BYTES;
+ mReq->ptr->token |= TD_STATUS_ACTIVE;
+ if (mReq->zptr) {
+ mReq->ptr->next = mReq->zdma;
+ } else {
+ mReq->ptr->next = TD_TERMINATE;
+ if (!mReq->req.no_interrupt)
+ mReq->ptr->token |= TD_IOC;
+ }
+ mReq->ptr->page[0] = mReq->req.dma;
+ for (i = 1; i < 5; i++)
+ mReq->ptr->page[i] =
+ (mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK;
+
+ if (!list_empty(&mEp->qh.queue)) {
+ struct ci13xxx_req *mReqPrev;
+ int n = hw_ep_bit(mEp->num, mEp->dir);
+ int tmp_stat;
+
+ mReqPrev = list_entry(mEp->qh.queue.prev,
+ struct ci13xxx_req, queue);
+ if (mReqPrev->zptr)
+ mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK;
+ else
+ mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK;
+ wmb();
+ if (hw_read(udc, OP_ENDPTPRIME, BIT(n)))
+ goto done;
+ do {
+ hw_write(udc, OP_USBCMD, USBCMD_ATDTW, USBCMD_ATDTW);
+ tmp_stat = hw_read(udc, OP_ENDPTSTAT, BIT(n));
+ } while (!hw_read(udc, OP_USBCMD, USBCMD_ATDTW));
+ hw_write(udc, OP_USBCMD, USBCMD_ATDTW, 0);
+ if (tmp_stat)
+ goto done;
+ }
+
+ /* QH configuration */
+ mEp->qh.ptr->td.next = mReq->dma; /* TERMINATE = 0 */
+ mEp->qh.ptr->td.token &= ~TD_STATUS; /* clear status */
+ mEp->qh.ptr->cap |= QH_ZLT;
+
+ wmb(); /* synchronize before ep prime */
+
+ ret = hw_ep_prime(udc, mEp->num, mEp->dir,
+ mEp->type == USB_ENDPOINT_XFER_CONTROL);
+done:
+ return ret;
+}
+
+/**
+ * _hardware_dequeue: handles a request at hardware level
+ * @gadget: gadget
+ * @mEp: endpoint
+ *
+ * This function returns an error code
+ */
+static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
+{
+ if (mReq->req.status != -EALREADY)
+ return -EINVAL;
+
+ if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0)
+ return -EBUSY;
+
+ if (mReq->zptr) {
+ if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0)
+ return -EBUSY;
+ dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
+ mReq->zptr = NULL;
+ }
+
+ mReq->req.status = 0;
+
+ usb_gadget_unmap_request(&mEp->udc->gadget, &mReq->req, mEp->dir);
+
+ mReq->req.status = mReq->ptr->token & TD_STATUS;
+ if ((TD_STATUS_HALTED & mReq->req.status) != 0)
+ mReq->req.status = -1;
+ else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0)
+ mReq->req.status = -1;
+ else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0)
+ mReq->req.status = -1;
+
+ mReq->req.actual = mReq->ptr->token & TD_TOTAL_BYTES;
+ mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES);
+ mReq->req.actual = mReq->req.length - mReq->req.actual;
+ mReq->req.actual = mReq->req.status ? 0 : mReq->req.actual;
+
+ return mReq->req.actual;
+}
+
+/**
+ * _ep_nuke: dequeues all endpoint requests
+ * @mEp: endpoint
+ *
+ * This function returns an error code
+ * Caller must hold lock
+ */
+static int _ep_nuke(struct ci13xxx_ep *mEp)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+ if (mEp == NULL)
+ return -EINVAL;
+
+ hw_ep_flush(mEp->udc, mEp->num, mEp->dir);
+
+ while (!list_empty(&mEp->qh.queue)) {
+
+ /* pop oldest request */
+ struct ci13xxx_req *mReq = \
+ list_entry(mEp->qh.queue.next,
+ struct ci13xxx_req, queue);
+ list_del_init(&mReq->queue);
+ mReq->req.status = -ESHUTDOWN;
+
+ if (mReq->req.complete != NULL) {
+ spin_unlock(mEp->lock);
+ mReq->req.complete(&mEp->ep, &mReq->req);
+ spin_lock(mEp->lock);
+ }
+ }
+ return 0;
+}
+
+/**
+ * _gadget_stop_activity: stops all USB activity, flushes & disables all endpts
+ * @gadget: gadget
+ *
+ * This function returns an error code
+ */
+static int _gadget_stop_activity(struct usb_gadget *gadget)
+{
+ struct usb_ep *ep;
+ struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget);
+ unsigned long flags;
+
+ spin_lock_irqsave(&udc->lock, flags);
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ udc->remote_wakeup = 0;
+ udc->suspended = 0;
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ /* flush all endpoints */
+ gadget_for_each_ep(ep, gadget) {
+ usb_ep_fifo_flush(ep);
+ }
+ usb_ep_fifo_flush(&udc->ep0out->ep);
+ usb_ep_fifo_flush(&udc->ep0in->ep);
+
+ if (udc->driver)
+ udc->driver->disconnect(gadget);
+
+ /* make sure to disable all endpoints */
+ gadget_for_each_ep(ep, gadget) {
+ usb_ep_disable(ep);
+ }
+
+ if (udc->status != NULL) {
+ usb_ep_free_request(&udc->ep0in->ep, udc->status);
+ udc->status = NULL;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ * ISR block
+ *****************************************************************************/
+/**
+ * isr_reset_handler: USB reset interrupt handler
+ * @udc: UDC device
+ *
+ * This function resets USB engine after a bus reset occurred
+ */
+static void isr_reset_handler(struct ci13xxx *udc)
+__releases(udc->lock)
+__acquires(udc->lock)
+{
+ int retval;
+
+ dbg_event(0xFF, "BUS RST", 0);
+
+ spin_unlock(&udc->lock);
+ retval = _gadget_stop_activity(&udc->gadget);
+ if (retval)
+ goto done;
+
+ retval = hw_usb_reset(udc);
+ if (retval)
+ goto done;
+
+ udc->status = usb_ep_alloc_request(&udc->ep0in->ep, GFP_ATOMIC);
+ if (udc->status == NULL)
+ retval = -ENOMEM;
+
+done:
+ spin_lock(&udc->lock);
+
+ if (retval)
+ dev_err(udc->dev, "error: %i\n", retval);
+}
+
+/**
+ * isr_get_status_complete: get_status request complete function
+ * @ep: endpoint
+ * @req: request handled
+ *
+ * Caller must release lock
+ */
+static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ if (ep == NULL || req == NULL)
+ return;
+
+ kfree(req->buf);
+ usb_ep_free_request(ep, req);
+}
+
+/**
+ * isr_get_status_response: get_status request response
+ * @udc: udc struct
+ * @setup: setup request packet
+ *
+ * This function returns an error code
+ */
+static int isr_get_status_response(struct ci13xxx *udc,
+ struct usb_ctrlrequest *setup)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+ struct ci13xxx_ep *mEp = udc->ep0in;
+ struct usb_request *req = NULL;
+ gfp_t gfp_flags = GFP_ATOMIC;
+ int dir, num, retval;
+
+ if (mEp == NULL || setup == NULL)
+ return -EINVAL;
+
+ spin_unlock(mEp->lock);
+ req = usb_ep_alloc_request(&mEp->ep, gfp_flags);
+ spin_lock(mEp->lock);
+ if (req == NULL)
+ return -ENOMEM;
+
+ req->complete = isr_get_status_complete;
+ req->length = 2;
+ req->buf = kzalloc(req->length, gfp_flags);
+ if (req->buf == NULL) {
+ retval = -ENOMEM;
+ goto err_free_req;
+ }
+
+ if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
+ /* Assume that device is bus powered for now. */
+ *(u16 *)req->buf = udc->remote_wakeup << 1;
+ retval = 0;
+ } else if ((setup->bRequestType & USB_RECIP_MASK) \
+ == USB_RECIP_ENDPOINT) {
+ dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ?
+ TX : RX;
+ num = le16_to_cpu(setup->wIndex) & USB_ENDPOINT_NUMBER_MASK;
+ *(u16 *)req->buf = hw_ep_get_halt(udc, num, dir);
+ }
+ /* else do nothing; reserved for future use */
+
+ spin_unlock(mEp->lock);
+ retval = usb_ep_queue(&mEp->ep, req, gfp_flags);
+ spin_lock(mEp->lock);
+ if (retval)
+ goto err_free_buf;
+
+ return 0;
+
+ err_free_buf:
+ kfree(req->buf);
+ err_free_req:
+ spin_unlock(mEp->lock);
+ usb_ep_free_request(&mEp->ep, req);
+ spin_lock(mEp->lock);
+ return retval;
+}
+
+/**
+ * isr_setup_status_complete: setup_status request complete function
+ * @ep: endpoint
+ * @req: request handled
+ *
+ * Caller must release lock. Put the port in test mode if test mode
+ * feature is selected.
+ */
+static void
+isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct ci13xxx *udc = req->context;
+ unsigned long flags;
+
+ if (udc->setaddr) {
+ hw_usb_set_address(udc, udc->address);
+ udc->setaddr = false;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+ if (udc->test_mode)
+ hw_port_test_set(udc, udc->test_mode);
+ spin_unlock_irqrestore(&udc->lock, flags);
+}
+
+/**
+ * isr_setup_status_phase: queues the status phase of a setup transation
+ * @udc: udc struct
+ *
+ * This function returns an error code
+ */
+static int isr_setup_status_phase(struct ci13xxx *udc)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+ int retval;
+ struct ci13xxx_ep *mEp;
+
+ mEp = (udc->ep0_dir == TX) ? udc->ep0out : udc->ep0in;
+ udc->status->context = udc;
+ udc->status->complete = isr_setup_status_complete;
+
+ spin_unlock(mEp->lock);
+ retval = usb_ep_queue(&mEp->ep, udc->status, GFP_ATOMIC);
+ spin_lock(mEp->lock);
+
+ return retval;
+}
+
+/**
+ * isr_tr_complete_low: transaction complete low level handler
+ * @mEp: endpoint
+ *
+ * This function returns an error code
+ * Caller must hold lock
+ */
+static int isr_tr_complete_low(struct ci13xxx_ep *mEp)
+__releases(mEp->lock)
+__acquires(mEp->lock)
+{
+ struct ci13xxx_req *mReq, *mReqTemp;
+ struct ci13xxx_ep *mEpTemp = mEp;
+ int uninitialized_var(retval);
+
+ if (list_empty(&mEp->qh.queue))
+ return -EINVAL;
+
+ list_for_each_entry_safe(mReq, mReqTemp, &mEp->qh.queue,
+ queue) {
+ retval = _hardware_dequeue(mEp, mReq);
+ if (retval < 0)
+ break;
+ list_del_init(&mReq->queue);
+ dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
+ if (mReq->req.complete != NULL) {
+ spin_unlock(mEp->lock);
+ if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
+ mReq->req.length)
+ mEpTemp = mEp->udc->ep0in;
+ mReq->req.complete(&mEpTemp->ep, &mReq->req);
+ spin_lock(mEp->lock);
+ }
+ }
+
+ if (retval == -EBUSY)
+ retval = 0;
+ if (retval < 0)
+ dbg_event(_usb_addr(mEp), "DONE", retval);
+
+ return retval;
+}
+
+/**
+ * isr_tr_complete_handler: transaction complete interrupt handler
+ * @udc: UDC descriptor
+ *
+ * This function handles traffic events
+ */
+static void isr_tr_complete_handler(struct ci13xxx *udc)
+__releases(udc->lock)
+__acquires(udc->lock)
+{
+ unsigned i;
+ u8 tmode = 0;
+
+ for (i = 0; i < udc->hw_ep_max; i++) {
+ struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
+ int type, num, dir, err = -EINVAL;
+ struct usb_ctrlrequest req;
+
+ if (mEp->ep.desc == NULL)
+ continue; /* not configured */
+
+ if (hw_test_and_clear_complete(udc, i)) {
+ err = isr_tr_complete_low(mEp);
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
+ if (err > 0) /* needs status phase */
+ err = isr_setup_status_phase(udc);
+ if (err < 0) {
+ dbg_event(_usb_addr(mEp),
+ "ERROR", err);
+ spin_unlock(&udc->lock);
+ if (usb_ep_set_halt(&mEp->ep))
+ dev_err(udc->dev,
+ "error: ep_set_halt\n");
+ spin_lock(&udc->lock);
+ }
+ }
+ }
+
+ if (mEp->type != USB_ENDPOINT_XFER_CONTROL ||
+ !hw_test_and_clear_setup_status(udc, i))
+ continue;
+
+ if (i != 0) {
+ dev_warn(udc->dev, "ctrl traffic at endpoint %d\n", i);
+ continue;
+ }
+
+ /*
+ * Flush data and handshake transactions of previous
+ * setup packet.
+ */
+ _ep_nuke(udc->ep0out);
+ _ep_nuke(udc->ep0in);
+
+ /* read_setup_packet */
+ do {
+ hw_test_and_set_setup_guard(udc);
+ memcpy(&req, &mEp->qh.ptr->setup, sizeof(req));
+ } while (!hw_test_and_clear_setup_guard(udc));
+
+ type = req.bRequestType;
+
+ udc->ep0_dir = (type & USB_DIR_IN) ? TX : RX;
+
+ dbg_setup(_usb_addr(mEp), &req);
+
+ switch (req.bRequest) {
+ case USB_REQ_CLEAR_FEATURE:
+ if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
+ le16_to_cpu(req.wValue) ==
+ USB_ENDPOINT_HALT) {
+ if (req.wLength != 0)
+ break;
+ num = le16_to_cpu(req.wIndex);
+ dir = num & USB_ENDPOINT_DIR_MASK;
+ num &= USB_ENDPOINT_NUMBER_MASK;
+ if (dir) /* TX */
+ num += udc->hw_ep_max/2;
+ if (!udc->ci13xxx_ep[num].wedge) {
+ spin_unlock(&udc->lock);
+ err = usb_ep_clear_halt(
+ &udc->ci13xxx_ep[num].ep);
+ spin_lock(&udc->lock);
+ if (err)
+ break;
+ }
+ err = isr_setup_status_phase(udc);
+ } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) &&
+ le16_to_cpu(req.wValue) ==
+ USB_DEVICE_REMOTE_WAKEUP) {
+ if (req.wLength != 0)
+ break;
+ udc->remote_wakeup = 0;
+ err = isr_setup_status_phase(udc);
+ } else {
+ goto delegate;
+ }
+ break;
+ case USB_REQ_GET_STATUS:
+ if (type != (USB_DIR_IN|USB_RECIP_DEVICE) &&
+ type != (USB_DIR_IN|USB_RECIP_ENDPOINT) &&
+ type != (USB_DIR_IN|USB_RECIP_INTERFACE))
+ goto delegate;
+ if (le16_to_cpu(req.wLength) != 2 ||
+ le16_to_cpu(req.wValue) != 0)
+ break;
+ err = isr_get_status_response(udc, &req);
+ break;
+ case USB_REQ_SET_ADDRESS:
+ if (type != (USB_DIR_OUT|USB_RECIP_DEVICE))
+ goto delegate;
+ if (le16_to_cpu(req.wLength) != 0 ||
+ le16_to_cpu(req.wIndex) != 0)
+ break;
+ udc->address = (u8)le16_to_cpu(req.wValue);
+ udc->setaddr = true;
+ err = isr_setup_status_phase(udc);
+ break;
+ case USB_REQ_SET_FEATURE:
+ if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
+ le16_to_cpu(req.wValue) ==
+ USB_ENDPOINT_HALT) {
+ if (req.wLength != 0)
+ break;
+ num = le16_to_cpu(req.wIndex);
+ dir = num & USB_ENDPOINT_DIR_MASK;
+ num &= USB_ENDPOINT_NUMBER_MASK;
+ if (dir) /* TX */
+ num += udc->hw_ep_max/2;
+
+ spin_unlock(&udc->lock);
+ err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep);
+ spin_lock(&udc->lock);
+ if (!err)
+ isr_setup_status_phase(udc);
+ } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) {
+ if (req.wLength != 0)
+ break;
+ switch (le16_to_cpu(req.wValue)) {
+ case USB_DEVICE_REMOTE_WAKEUP:
+ udc->remote_wakeup = 1;
+ err = isr_setup_status_phase(udc);
+ break;
+ case USB_DEVICE_TEST_MODE:
+ tmode = le16_to_cpu(req.wIndex) >> 8;
+ switch (tmode) {
+ case TEST_J:
+ case TEST_K:
+ case TEST_SE0_NAK:
+ case TEST_PACKET:
+ case TEST_FORCE_EN:
+ udc->test_mode = tmode;
+ err = isr_setup_status_phase(
+ udc);
+ break;
+ default:
+ break;
+ }
+ default:
+ goto delegate;
+ }
+ } else {
+ goto delegate;
+ }
+ break;
+ default:
+delegate:
+ if (req.wLength == 0) /* no data phase */
+ udc->ep0_dir = TX;
+
+ spin_unlock(&udc->lock);
+ err = udc->driver->setup(&udc->gadget, &req);
+ spin_lock(&udc->lock);
+ break;
+ }
+
+ if (err < 0) {
+ dbg_event(_usb_addr(mEp), "ERROR", err);
+
+ spin_unlock(&udc->lock);
+ if (usb_ep_set_halt(&mEp->ep))
+ dev_err(udc->dev, "error: ep_set_halt\n");
+ spin_lock(&udc->lock);
+ }
+ }
+}
+
+/******************************************************************************
+ * ENDPT block
+ *****************************************************************************/
+/**
+ * ep_enable: configure endpoint, making it usable
+ *
+ * Check usb_ep_enable() at "usb_gadget.h" for details
+ */
+static int ep_enable(struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ int retval = 0;
+ unsigned long flags;
+
+ if (ep == NULL || desc == NULL)
+ return -EINVAL;
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+ /* only internal SW should enable ctrl endpts */
+
+ mEp->ep.desc = desc;
+
+ if (!list_empty(&mEp->qh.queue))
+ dev_warn(mEp->udc->dev, "enabling a non-empty endpoint!\n");
+
+ mEp->dir = usb_endpoint_dir_in(desc) ? TX : RX;
+ mEp->num = usb_endpoint_num(desc);
+ mEp->type = usb_endpoint_type(desc);
+
+ mEp->ep.maxpacket = usb_endpoint_maxp(desc);
+
+ dbg_event(_usb_addr(mEp), "ENABLE", 0);
+
+ mEp->qh.ptr->cap = 0;
+
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+ mEp->qh.ptr->cap |= QH_IOS;
+ else if (mEp->type == USB_ENDPOINT_XFER_ISOC)
+ mEp->qh.ptr->cap &= ~QH_MULT;
+ else
+ mEp->qh.ptr->cap &= ~QH_ZLT;
+
+ mEp->qh.ptr->cap |=
+ (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT;
+ mEp->qh.ptr->td.next |= TD_TERMINATE; /* needed? */
+
+ /*
+ * Enable endpoints in the HW other than ep0 as ep0
+ * is always enabled
+ */
+ if (mEp->num)
+ retval |= hw_ep_enable(mEp->udc, mEp->num, mEp->dir, mEp->type);
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+ return retval;
+}
+
+/**
+ * ep_disable: endpoint is no longer usable
+ *
+ * Check usb_ep_disable() at "usb_gadget.h" for details
+ */
+static int ep_disable(struct usb_ep *ep)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ int direction, retval = 0;
+ unsigned long flags;
+
+ if (ep == NULL)
+ return -EINVAL;
+ else if (mEp->ep.desc == NULL)
+ return -EBUSY;
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+ /* only internal SW should disable ctrl endpts */
+
+ direction = mEp->dir;
+ do {
+ dbg_event(_usb_addr(mEp), "DISABLE", 0);
+
+ retval |= _ep_nuke(mEp);
+ retval |= hw_ep_disable(mEp->udc, mEp->num, mEp->dir);
+
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+ mEp->dir = (mEp->dir == TX) ? RX : TX;
+
+ } while (mEp->dir != direction);
+
+ mEp->ep.desc = NULL;
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+ return retval;
+}
+
+/**
+ * ep_alloc_request: allocate a request object to use with this endpoint
+ *
+ * Check usb_ep_alloc_request() at "usb_gadget.h" for details
+ */
+static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ struct ci13xxx_req *mReq = NULL;
+
+ if (ep == NULL)
+ return NULL;
+
+ mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags);
+ if (mReq != NULL) {
+ INIT_LIST_HEAD(&mReq->queue);
+
+ mReq->ptr = dma_pool_alloc(mEp->td_pool, gfp_flags,
+ &mReq->dma);
+ if (mReq->ptr == NULL) {
+ kfree(mReq);
+ mReq = NULL;
+ }
+ }
+
+ dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL);
+
+ return (mReq == NULL) ? NULL : &mReq->req;
+}
+
+/**
+ * ep_free_request: frees a request object
+ *
+ * Check usb_ep_free_request() at "usb_gadget.h" for details
+ */
+static void ep_free_request(struct usb_ep *ep, struct usb_request *req)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+ unsigned long flags;
+
+ if (ep == NULL || req == NULL) {
+ return;
+ } else if (!list_empty(&mReq->queue)) {
+ dev_err(mEp->udc->dev, "freeing queued request\n");
+ return;
+ }
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+ if (mReq->ptr)
+ dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma);
+ kfree(mReq);
+
+ dbg_event(_usb_addr(mEp), "FREE", 0);
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+}
+
+/**
+ * ep_queue: queues (submits) an I/O request to an endpoint
+ *
+ * Check usb_ep_queue()* at usb_gadget.h" for details
+ */
+static int ep_queue(struct usb_ep *ep, struct usb_request *req,
+ gfp_t __maybe_unused gfp_flags)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+ struct ci13xxx *udc = mEp->udc;
+ int retval = 0;
+ unsigned long flags;
+
+ if (ep == NULL || req == NULL || mEp->ep.desc == NULL)
+ return -EINVAL;
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
+ if (req->length)
+ mEp = (udc->ep0_dir == RX) ?
+ udc->ep0out : udc->ep0in;
+ if (!list_empty(&mEp->qh.queue)) {
+ _ep_nuke(mEp);
+ retval = -EOVERFLOW;
+ dev_warn(mEp->udc->dev, "endpoint ctrl %X nuked\n",
+ _usb_addr(mEp));
+ }
+ }
+
+ /* first nuke then test link, e.g. previous status has not sent */
+ if (!list_empty(&mReq->queue)) {
+ retval = -EBUSY;
+ dev_err(mEp->udc->dev, "request already in queue\n");
+ goto done;
+ }
+
+ if (req->length > 4 * CI13XXX_PAGE_SIZE) {
+ req->length = 4 * CI13XXX_PAGE_SIZE;
+ retval = -EMSGSIZE;
+ dev_warn(mEp->udc->dev, "request length truncated\n");
+ }
+
+ dbg_queue(_usb_addr(mEp), req, retval);
+
+ /* push request */
+ mReq->req.status = -EINPROGRESS;
+ mReq->req.actual = 0;
+
+ retval = _hardware_enqueue(mEp, mReq);
+
+ if (retval == -EALREADY) {
+ dbg_event(_usb_addr(mEp), "QUEUE", retval);
+ retval = 0;
+ }
+ if (!retval)
+ list_add_tail(&mReq->queue, &mEp->qh.queue);
+
+ done:
+ spin_unlock_irqrestore(mEp->lock, flags);
+ return retval;
+}
+
+/**
+ * ep_dequeue: dequeues (cancels, unlinks) an I/O request from an endpoint
+ *
+ * Check usb_ep_dequeue() at "usb_gadget.h" for details
+ */
+static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
+ unsigned long flags;
+
+ if (ep == NULL || req == NULL || mReq->req.status != -EALREADY ||
+ mEp->ep.desc == NULL || list_empty(&mReq->queue) ||
+ list_empty(&mEp->qh.queue))
+ return -EINVAL;
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+ dbg_event(_usb_addr(mEp), "DEQUEUE", 0);
+
+ hw_ep_flush(mEp->udc, mEp->num, mEp->dir);
+
+ /* pop request */
+ list_del_init(&mReq->queue);
+
+ usb_gadget_unmap_request(&mEp->udc->gadget, req, mEp->dir);
+
+ req->status = -ECONNRESET;
+
+ if (mReq->req.complete != NULL) {
+ spin_unlock(mEp->lock);
+ mReq->req.complete(&mEp->ep, &mReq->req);
+ spin_lock(mEp->lock);
+ }
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+ return 0;
+}
+
+/**
+ * ep_set_halt: sets the endpoint halt feature
+ *
+ * Check usb_ep_set_halt() at "usb_gadget.h" for details
+ */
+static int ep_set_halt(struct usb_ep *ep, int value)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ int direction, retval = 0;
+ unsigned long flags;
+
+ if (ep == NULL || mEp->ep.desc == NULL)
+ return -EINVAL;
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+#ifndef STALL_IN
+ /* g_file_storage MS compliant but g_zero fails chapter 9 compliance */
+ if (value && mEp->type == USB_ENDPOINT_XFER_BULK && mEp->dir == TX &&
+ !list_empty(&mEp->qh.queue)) {
+ spin_unlock_irqrestore(mEp->lock, flags);
+ return -EAGAIN;
+ }
+#endif
+
+ direction = mEp->dir;
+ do {
+ dbg_event(_usb_addr(mEp), "HALT", value);
+ retval |= hw_ep_set_halt(mEp->udc, mEp->num, mEp->dir, value);
+
+ if (!value)
+ mEp->wedge = 0;
+
+ if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
+ mEp->dir = (mEp->dir == TX) ? RX : TX;
+
+ } while (mEp->dir != direction);
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+ return retval;
+}
+
+/**
+ * ep_set_wedge: sets the halt feature and ignores clear requests
+ *
+ * Check usb_ep_set_wedge() at "usb_gadget.h" for details
+ */
+static int ep_set_wedge(struct usb_ep *ep)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ unsigned long flags;
+
+ if (ep == NULL || mEp->ep.desc == NULL)
+ return -EINVAL;
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+ dbg_event(_usb_addr(mEp), "WEDGE", 0);
+ mEp->wedge = 1;
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+
+ return usb_ep_set_halt(ep);
+}
+
+/**
+ * ep_fifo_flush: flushes contents of a fifo
+ *
+ * Check usb_ep_fifo_flush() at "usb_gadget.h" for details
+ */
+static void ep_fifo_flush(struct usb_ep *ep)
+{
+ struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
+ unsigned long flags;
+
+ if (ep == NULL) {
+ dev_err(mEp->udc->dev, "%02X: -EINVAL\n", _usb_addr(mEp));
+ return;
+ }
+
+ spin_lock_irqsave(mEp->lock, flags);
+
+ dbg_event(_usb_addr(mEp), "FFLUSH", 0);
+ hw_ep_flush(mEp->udc, mEp->num, mEp->dir);
+
+ spin_unlock_irqrestore(mEp->lock, flags);
+}
+
+/**
+ * Endpoint-specific part of the API to the USB controller hardware
+ * Check "usb_gadget.h" for details
+ */
+static const struct usb_ep_ops usb_ep_ops = {
+ .enable = ep_enable,
+ .disable = ep_disable,
+ .alloc_request = ep_alloc_request,
+ .free_request = ep_free_request,
+ .queue = ep_queue,
+ .dequeue = ep_dequeue,
+ .set_halt = ep_set_halt,
+ .set_wedge = ep_set_wedge,
+ .fifo_flush = ep_fifo_flush,
+};
+
+/******************************************************************************
+ * GADGET block
+ *****************************************************************************/
+static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
+{
+ struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
+ unsigned long flags;
+ int gadget_ready = 0;
+
+ if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS))
+ return -EOPNOTSUPP;
+
+ spin_lock_irqsave(&udc->lock, flags);
+ udc->vbus_active = is_active;
+ if (udc->driver)
+ gadget_ready = 1;
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ if (gadget_ready) {
+ if (is_active) {
+ pm_runtime_get_sync(&_gadget->dev);
+ hw_device_reset(udc, USBMODE_CM_DC);
+ hw_device_state(udc, udc->ep0out->qh.dma);
+ } else {
+ hw_device_state(udc, 0);
+ if (udc->udc_driver->notify_event)
+ udc->udc_driver->notify_event(udc,
+ CI13XXX_CONTROLLER_STOPPED_EVENT);
+ _gadget_stop_activity(&udc->gadget);
+ pm_runtime_put_sync(&_gadget->dev);
+ }
+ }
+
+ return 0;
+}
+
+static int ci13xxx_wakeup(struct usb_gadget *_gadget)
+{
+ struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&udc->lock, flags);
+ if (!udc->remote_wakeup) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+ if (!hw_read(udc, OP_PORTSC, PORTSC_SUSP)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ hw_write(udc, OP_PORTSC, PORTSC_FPR, PORTSC_FPR);
+out:
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return ret;
+}
+
+static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
+{
+ struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
+
+ if (udc->transceiver)
+ return usb_phy_set_power(udc->transceiver, mA);
+ return -ENOTSUPP;
+}
+
+static int ci13xxx_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
+static int ci13xxx_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
+/**
+ * Device operations part of the API to the USB controller hardware,
+ * which don't involve endpoints (or i/o)
+ * Check "usb_gadget.h" for details
+ */
+static const struct usb_gadget_ops usb_gadget_ops = {
+ .vbus_session = ci13xxx_vbus_session,
+ .wakeup = ci13xxx_wakeup,
+ .vbus_draw = ci13xxx_vbus_draw,
+ .udc_start = ci13xxx_start,
+ .udc_stop = ci13xxx_stop,
+};
+
+static int init_eps(struct ci13xxx *udc)
+{
+ int retval = 0, i, j;
+
+ for (i = 0; i < udc->hw_ep_max/2; i++)
+ for (j = RX; j <= TX; j++) {
+ int k = i + j * udc->hw_ep_max/2;
+ struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[k];
+
+ scnprintf(mEp->name, sizeof(mEp->name), "ep%i%s", i,
+ (j == TX) ? "in" : "out");
+
+ mEp->udc = udc;
+ mEp->lock = &udc->lock;
+ mEp->td_pool = udc->td_pool;
+
+ mEp->ep.name = mEp->name;
+ mEp->ep.ops = &usb_ep_ops;
+ mEp->ep.maxpacket = CTRL_PAYLOAD_MAX;
+
+ INIT_LIST_HEAD(&mEp->qh.queue);
+ mEp->qh.ptr = dma_pool_alloc(udc->qh_pool, GFP_KERNEL,
+ &mEp->qh.dma);
+ if (mEp->qh.ptr == NULL)
+ retval = -ENOMEM;
+ else
+ memset(mEp->qh.ptr, 0, sizeof(*mEp->qh.ptr));
+
+ /*
+ * set up shorthands for ep0 out and in endpoints,
+ * don't add to gadget's ep_list
+ */
+ if (i == 0) {
+ if (j == RX)
+ udc->ep0out = mEp;
+ else
+ udc->ep0in = mEp;
+
+ continue;
+ }
+
+ list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list);
+ }
+
+ return retval;
+}
+
+/**
+ * ci13xxx_start: register a gadget driver
+ * @gadget: our gadget
+ * @driver: the driver being registered
+ *
+ * Interrupts are enabled here.
+ */
+static int ci13xxx_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
+{
+ struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget);
+ unsigned long flags;
+ int retval = -ENOMEM;
+
+ if (driver->disconnect == NULL)
+ return -EINVAL;
+
+
+ udc->ep0out->ep.desc = &ctrl_endpt_out_desc;
+ retval = usb_ep_enable(&udc->ep0out->ep);
+ if (retval)
+ return retval;
+
+ udc->ep0in->ep.desc = &ctrl_endpt_in_desc;
+ retval = usb_ep_enable(&udc->ep0in->ep);
+ if (retval)
+ return retval;
+ spin_lock_irqsave(&udc->lock, flags);
+
+ udc->driver = driver;
+ pm_runtime_get_sync(&udc->gadget.dev);
+ if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) {
+ if (udc->vbus_active) {
+ if (udc->udc_driver->flags & CI13XXX_REGS_SHARED)
+ hw_device_reset(udc, USBMODE_CM_DC);
+ } else {
+ pm_runtime_put_sync(&udc->gadget.dev);
+ goto done;
+ }
+ }
+
+ retval = hw_device_state(udc, udc->ep0out->qh.dma);
+ if (retval)
+ pm_runtime_put_sync(&udc->gadget.dev);
+
+ done:
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return retval;
+}
+
+/**
+ * ci13xxx_stop: unregister a gadget driver
+ */
+static int ci13xxx_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
+{
+ struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget);
+ unsigned long flags;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) ||
+ udc->vbus_active) {
+ hw_device_state(udc, 0);
+ if (udc->udc_driver->notify_event)
+ udc->udc_driver->notify_event(udc,
+ CI13XXX_CONTROLLER_STOPPED_EVENT);
+ udc->driver = NULL;
+ spin_unlock_irqrestore(&udc->lock, flags);
+ _gadget_stop_activity(&udc->gadget);
+ spin_lock_irqsave(&udc->lock, flags);
+ pm_runtime_put(&udc->gadget.dev);
+ }
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+/******************************************************************************
+ * BUS block
+ *****************************************************************************/
+/**
+ * udc_irq: udc interrupt handler
+ *
+ * This function returns IRQ_HANDLED if the IRQ has been handled
+ * It locks access to registers
+ */
+static irqreturn_t udc_irq(struct ci13xxx *udc)
+{
+ irqreturn_t retval;
+ u32 intr;
+
+ if (udc == NULL)
+ return IRQ_HANDLED;
+
+ spin_lock(&udc->lock);
+
+ if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) {
+ if (hw_read(udc, OP_USBMODE, USBMODE_CM) !=
+ USBMODE_CM_DC) {
+ spin_unlock(&udc->lock);
+ return IRQ_NONE;
+ }
+ }
+ intr = hw_test_and_clear_intr_active(udc);
+ dbg_interrupt(intr);
+
+ if (intr) {
+ /* order defines priority - do NOT change it */
+ if (USBi_URI & intr)
+ isr_reset_handler(udc);
+
+ if (USBi_PCI & intr) {
+ udc->gadget.speed = hw_port_is_high_speed(udc) ?
+ USB_SPEED_HIGH : USB_SPEED_FULL;
+ if (udc->suspended && udc->driver->resume) {
+ spin_unlock(&udc->lock);
+ udc->driver->resume(&udc->gadget);
+ spin_lock(&udc->lock);
+ udc->suspended = 0;
+ }
+ }
+
+ if (USBi_UI & intr)
+ isr_tr_complete_handler(udc);
+
+ if (USBi_SLI & intr) {
+ if (udc->gadget.speed != USB_SPEED_UNKNOWN &&
+ udc->driver->suspend) {
+ udc->suspended = 1;
+ spin_unlock(&udc->lock);
+ udc->driver->suspend(&udc->gadget);
+ spin_lock(&udc->lock);
+ }
+ }
+ retval = IRQ_HANDLED;
+ } else {
+ retval = IRQ_NONE;
+ }
+ spin_unlock(&udc->lock);
+
+ return retval;
+}
+
+/**
+ * udc_release: driver release function
+ * @dev: device
+ *
+ * Currently does nothing
+ */
+static void udc_release(struct device *dev)
+{
+}
+
+/**
+ * udc_start: initialize gadget role
+ * @udc: chipidea controller
+ */
+static int udc_start(struct ci13xxx *udc)
+{
+ struct device *dev = udc->dev;
+ int retval = 0;
+
+ if (!udc)
+ return -EINVAL;
+
+ spin_lock_init(&udc->lock);
+
+ udc->gadget.ops = &usb_gadget_ops;
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ udc->gadget.max_speed = USB_SPEED_HIGH;
+ udc->gadget.is_otg = 0;
+ udc->gadget.name = udc->udc_driver->name;
+
+ INIT_LIST_HEAD(&udc->gadget.ep_list);
+
+ dev_set_name(&udc->gadget.dev, "gadget");
+ udc->gadget.dev.dma_mask = dev->dma_mask;
+ udc->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask;
+ udc->gadget.dev.parent = dev;
+ udc->gadget.dev.release = udc_release;
+
+ /* alloc resources */
+ udc->qh_pool = dma_pool_create("ci13xxx_qh", dev,
+ sizeof(struct ci13xxx_qh),
+ 64, CI13XXX_PAGE_SIZE);
+ if (udc->qh_pool == NULL)
+ return -ENOMEM;
+
+ udc->td_pool = dma_pool_create("ci13xxx_td", dev,
+ sizeof(struct ci13xxx_td),
+ 64, CI13XXX_PAGE_SIZE);
+ if (udc->td_pool == NULL) {
+ retval = -ENOMEM;
+ goto free_qh_pool;
+ }
+
+ retval = init_eps(udc);
+ if (retval)
+ goto free_pools;
+
+ udc->gadget.ep0 = &udc->ep0in->ep;
+
+ udc->transceiver = usb_get_transceiver();
+
+ if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
+ if (udc->transceiver == NULL) {
+ retval = -ENODEV;
+ goto free_pools;
+ }
+ }
+
+ if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) {
+ retval = hw_device_reset(udc, USBMODE_CM_DC);
+ if (retval)
+ goto put_transceiver;
+ }
+
+ retval = device_register(&udc->gadget.dev);
+ if (retval) {
+ put_device(&udc->gadget.dev);
+ goto put_transceiver;
+ }
+
+ retval = dbg_create_files(&udc->gadget.dev);
+ if (retval)
+ goto unreg_device;
+
+ if (udc->transceiver) {
+ retval = otg_set_peripheral(udc->transceiver->otg,
+ &udc->gadget);
+ if (retval)
+ goto remove_dbg;
+ }
+
+ retval = usb_add_gadget_udc(dev, &udc->gadget);
+ if (retval)
+ goto remove_trans;
+
+ pm_runtime_no_callbacks(&udc->gadget.dev);
+ pm_runtime_enable(&udc->gadget.dev);
+
+ return retval;
+
+remove_trans:
+ if (udc->transceiver) {
+ otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
+ usb_put_transceiver(udc->transceiver);
+ }
+
+ dev_err(dev, "error = %i\n", retval);
+remove_dbg:
+ dbg_remove_files(&udc->gadget.dev);
+unreg_device:
+ device_unregister(&udc->gadget.dev);
+put_transceiver:
+ if (udc->transceiver)
+ usb_put_transceiver(udc->transceiver);
+free_pools:
+ dma_pool_destroy(udc->td_pool);
+free_qh_pool:
+ dma_pool_destroy(udc->qh_pool);
+ return retval;
+}
+
+/**
+ * udc_remove: parent remove must call this to remove UDC
+ *
+ * No interrupts active, the IRQ has been released
+ */
+static void udc_stop(struct ci13xxx *udc)
+{
+ int i;
+
+ if (udc == NULL)
+ return;
+
+ usb_del_gadget_udc(&udc->gadget);
+
+ for (i = 0; i < udc->hw_ep_max; i++) {
+ struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
+
+ dma_pool_free(udc->qh_pool, mEp->qh.ptr, mEp->qh.dma);
+ }
+
+ dma_pool_destroy(udc->td_pool);
+ dma_pool_destroy(udc->qh_pool);
+
+ if (udc->transceiver) {
+ otg_set_peripheral(udc->transceiver->otg, NULL);
+ usb_put_transceiver(udc->transceiver);
+ }
+ dbg_remove_files(&udc->gadget.dev);
+ device_unregister(&udc->gadget.dev);
+ /* my kobject is dynamic, I swear! */
+ memset(&udc->gadget, 0, sizeof(udc->gadget));
+}
+
+/**
+ * ci_hdrc_gadget_init - initialize device related bits
+ * ci: the controller
+ *
+ * This function enables the gadget role, if the device is "device capable".
+ */
+int ci_hdrc_gadget_init(struct ci13xxx *ci)
+{
+ struct ci_role_driver *rdrv;
+
+ if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DC))
+ return -ENXIO;
+
+ rdrv = devm_kzalloc(ci->dev, sizeof(struct ci_role_driver), GFP_KERNEL);
+ if (!rdrv)
+ return -ENOMEM;
+
+ rdrv->start = udc_start;
+ rdrv->stop = udc_stop;
+ rdrv->irq = udc_irq;
+ rdrv->name = "gadget";
+ ci->roles[CI_ROLE_GADGET] = rdrv;
+
+ return 0;
+}
diff --git a/drivers/usb/chipidea/udc.h b/drivers/usb/chipidea/udc.h
new file mode 100644
index 000000000000..4ff2384d7ca8
--- /dev/null
+++ b/drivers/usb/chipidea/udc.h
@@ -0,0 +1,93 @@
+/*
+ * udc.h - ChipIdea UDC structures
+ *
+ * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
+ *
+ * Author: David Lopo
+ *
+ * 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 __DRIVERS_USB_CHIPIDEA_UDC_H
+#define __DRIVERS_USB_CHIPIDEA_UDC_H
+
+#include <linux/list.h>
+
+#define CTRL_PAYLOAD_MAX 64
+#define RX 0 /* similar to USB_DIR_OUT but can be used as an index */
+#define TX 1 /* similar to USB_DIR_IN but can be used as an index */
+
+/* DMA layout of transfer descriptors */
+struct ci13xxx_td {
+ /* 0 */
+ u32 next;
+#define TD_TERMINATE BIT(0)
+#define TD_ADDR_MASK (0xFFFFFFEUL << 5)
+ /* 1 */
+ u32 token;
+#define TD_STATUS (0x00FFUL << 0)
+#define TD_STATUS_TR_ERR BIT(3)
+#define TD_STATUS_DT_ERR BIT(5)
+#define TD_STATUS_HALTED BIT(6)
+#define TD_STATUS_ACTIVE BIT(7)
+#define TD_MULTO (0x0003UL << 10)
+#define TD_IOC BIT(15)
+#define TD_TOTAL_BYTES (0x7FFFUL << 16)
+ /* 2 */
+ u32 page[5];
+#define TD_CURR_OFFSET (0x0FFFUL << 0)
+#define TD_FRAME_NUM (0x07FFUL << 0)
+#define TD_RESERVED_MASK (0x0FFFUL << 0)
+} __attribute__ ((packed));
+
+/* DMA layout of queue heads */
+struct ci13xxx_qh {
+ /* 0 */
+ u32 cap;
+#define QH_IOS BIT(15)
+#define QH_MAX_PKT (0x07FFUL << 16)
+#define QH_ZLT BIT(29)
+#define QH_MULT (0x0003UL << 30)
+ /* 1 */
+ u32 curr;
+ /* 2 - 8 */
+ struct ci13xxx_td td;
+ /* 9 */
+ u32 RESERVED;
+ struct usb_ctrlrequest setup;
+} __attribute__ ((packed));
+
+/**
+ * struct ci13xxx_req - usb request representation
+ * @req: request structure for gadget drivers
+ * @queue: link to QH list
+ * @ptr: transfer descriptor for this request
+ * @dma: dma address for the transfer descriptor
+ * @zptr: transfer descriptor for the zero packet
+ * @zdma: dma address of the zero packet's transfer descriptor
+ */
+struct ci13xxx_req {
+ struct usb_request req;
+ struct list_head queue;
+ struct ci13xxx_td *ptr;
+ dma_addr_t dma;
+ struct ci13xxx_td *zptr;
+ dma_addr_t zdma;
+};
+
+#ifdef CONFIG_USB_CHIPIDEA_UDC
+
+int ci_hdrc_gadget_init(struct ci13xxx *ci);
+
+#else
+
+static inline int ci_hdrc_gadget_init(struct ci13xxx *ci)
+{
+ return -ENXIO;
+}
+
+#endif
+
+#endif /* __DRIVERS_USB_CHIPIDEA_UDC_H */
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index b32ccb461019..f2a120eea9d4 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1664,6 +1664,7 @@ static struct usb_driver acm_driver = {
#ifdef CONFIG_PM
.supports_autosuspend = 1,
#endif
+ .disable_hub_initiated_lpm = 1,
};
/*
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 0bb2b3248dad..ea8b304f0e85 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -309,9 +309,6 @@ static void free_urbs(struct wdm_device *desc)
static void cleanup(struct wdm_device *desc)
{
- spin_lock(&wdm_device_list_lock);
- list_del(&desc->device_list);
- spin_unlock(&wdm_device_list_lock);
kfree(desc->sbuf);
kfree(desc->inbuf);
kfree(desc->orq);
@@ -369,6 +366,7 @@ static ssize_t wdm_write
r = usb_autopm_get_interface(desc->intf);
if (r < 0) {
kfree(buf);
+ rv = usb_translate_errors(r);
goto outnp;
}
@@ -384,6 +382,7 @@ static ssize_t wdm_write
if (r < 0) {
kfree(buf);
+ rv = r;
goto out;
}
@@ -415,6 +414,7 @@ static ssize_t wdm_write
desc->outbuf = NULL;
clear_bit(WDM_IN_USE, &desc->flags);
dev_err(&desc->intf->dev, "Tx URB error: %d\n", rv);
+ rv = usb_translate_errors(rv);
} else {
dev_dbg(&desc->intf->dev, "Tx URB has been submitted index=%d",
req->wIndex);
@@ -530,11 +530,13 @@ static int wdm_flush(struct file *file, fl_owner_t id)
struct wdm_device *desc = file->private_data;
wait_event(desc->wait, !test_bit(WDM_IN_USE, &desc->flags));
- if (desc->werr < 0)
+
+ /* cannot dereference desc->intf if WDM_DISCONNECTING */
+ if (desc->werr < 0 && !test_bit(WDM_DISCONNECTING, &desc->flags))
dev_err(&desc->intf->dev, "Error in flush path: %d\n",
desc->werr);
- return desc->werr;
+ return usb_translate_errors(desc->werr);
}
static unsigned int wdm_poll(struct file *file, struct poll_table_struct *wait)
@@ -545,7 +547,7 @@ static unsigned int wdm_poll(struct file *file, struct poll_table_struct *wait)
spin_lock_irqsave(&desc->iuspin, flags);
if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
- mask = POLLERR;
+ mask = POLLHUP | POLLERR;
spin_unlock_irqrestore(&desc->iuspin, flags);
goto desc_out;
}
@@ -596,6 +598,7 @@ static int wdm_open(struct inode *inode, struct file *file)
desc->count--;
dev_err(&desc->intf->dev,
"Error submitting int urb - %d\n", rv);
+ rv = usb_translate_errors(rv);
}
} else {
rv = 0;
@@ -621,10 +624,15 @@ static int wdm_release(struct inode *inode, struct file *file)
mutex_unlock(&desc->wlock);
if (!desc->count) {
- dev_dbg(&desc->intf->dev, "wdm_release: cleanup");
- kill_urbs(desc);
- if (!test_bit(WDM_DISCONNECTING, &desc->flags))
+ if (!test_bit(WDM_DISCONNECTING, &desc->flags)) {
+ dev_dbg(&desc->intf->dev, "wdm_release: cleanup");
+ kill_urbs(desc);
desc->manage_power(desc->intf, 0);
+ } else {
+ /* must avoid dev_printk here as desc->intf is invalid */
+ pr_debug(KBUILD_MODNAME " %s: device gone - cleaning up\n", __func__);
+ cleanup(desc);
+ }
}
mutex_unlock(&wdm_mutex);
return 0;
@@ -771,6 +779,9 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor
out:
return rv;
err:
+ spin_lock(&wdm_device_list_lock);
+ list_del(&desc->device_list);
+ spin_unlock(&wdm_device_list_lock);
cleanup(desc);
return rv;
}
@@ -896,8 +907,16 @@ static void wdm_disconnect(struct usb_interface *intf)
cancel_work_sync(&desc->rxwork);
mutex_unlock(&desc->wlock);
mutex_unlock(&desc->rlock);
+
+ /* the desc->intf pointer used as list key is now invalid */
+ spin_lock(&wdm_device_list_lock);
+ list_del(&desc->device_list);
+ spin_unlock(&wdm_device_list_lock);
+
if (!desc->count)
cleanup(desc);
+ else
+ dev_dbg(&intf->dev, "%s: %d open files - postponing cleanup\n", __func__, desc->count);
mutex_unlock(&wdm_mutex);
}
@@ -1015,6 +1034,7 @@ static struct usb_driver wdm_driver = {
.post_reset = wdm_post_reset,
.id_table = wdm_ids,
.supports_autosuspend = 1,
+ .disable_hub_initiated_lpm = 1,
};
module_usb_driver(wdm_driver);
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index a68c1a63dc65..d4c47d5d7625 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -172,27 +172,31 @@ struct usblp {
#ifdef DEBUG
static void usblp_dump(struct usblp *usblp)
{
+ struct device *dev = &usblp->intf->dev;
int p;
- dbg("usblp=0x%p", usblp);
- dbg("dev=0x%p", usblp->dev);
- dbg("present=%d", usblp->present);
- dbg("readbuf=0x%p", usblp->readbuf);
- dbg("readcount=%d", usblp->readcount);
- dbg("ifnum=%d", usblp->ifnum);
- for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) {
- dbg("protocol[%d].alt_setting=%d", p, usblp->protocol[p].alt_setting);
- dbg("protocol[%d].epwrite=%p", p, usblp->protocol[p].epwrite);
- dbg("protocol[%d].epread=%p", p, usblp->protocol[p].epread);
- }
- dbg("current_protocol=%d", usblp->current_protocol);
- dbg("minor=%d", usblp->minor);
- dbg("wstatus=%d", usblp->wstatus);
- dbg("rstatus=%d", usblp->rstatus);
- dbg("quirks=%d", usblp->quirks);
- dbg("used=%d", usblp->used);
- dbg("bidir=%d", usblp->bidir);
- dbg("device_id_string=\"%s\"",
+ dev_dbg(dev, "usblp=0x%p\n", usblp);
+ dev_dbg(dev, "dev=0x%p\n", usblp->dev);
+ dev_dbg(dev, "present=%d\n", usblp->present);
+ dev_dbg(dev, "readbuf=0x%p\n", usblp->readbuf);
+ dev_dbg(dev, "readcount=%d\n", usblp->readcount);
+ dev_dbg(dev, "ifnum=%d\n", usblp->ifnum);
+ for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) {
+ dev_dbg(dev, "protocol[%d].alt_setting=%d\n", p,
+ usblp->protocol[p].alt_setting);
+ dev_dbg(dev, "protocol[%d].epwrite=%p\n", p,
+ usblp->protocol[p].epwrite);
+ dev_dbg(dev, "protocol[%d].epread=%p\n", p,
+ usblp->protocol[p].epread);
+ }
+ dev_dbg(dev, "current_protocol=%d\n", usblp->current_protocol);
+ dev_dbg(dev, "minor=%d\n", usblp->minor);
+ dev_dbg(dev, "wstatus=%d\n", usblp->wstatus);
+ dev_dbg(dev, "rstatus=%d\n", usblp->rstatus);
+ dev_dbg(dev, "quirks=%d\n", usblp->quirks);
+ dev_dbg(dev, "used=%d\n", usblp->used);
+ dev_dbg(dev, "bidir=%d\n", usblp->bidir);
+ dev_dbg(dev, "device_id_string=\"%s\"\n",
usblp->device_id_string ?
usblp->device_id_string + 2 :
(unsigned char *)"(null)");
@@ -262,7 +266,8 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i
retval = usb_control_msg(usblp->dev,
dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT);
- dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d",
+ dev_dbg(&usblp->intf->dev,
+ "usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d\n",
request, !!dir, recip, value, index, len, retval);
return retval < 0 ? retval : 0;
}
@@ -500,8 +505,9 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
goto done;
}
- dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd),
- _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd));
+ dev_dbg(&usblp->intf->dev,
+ "usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)\n", cmd,
+ _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd));
if (_IOC_TYPE(cmd) == 'P') /* new-style ioctl number */
@@ -594,7 +600,8 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
goto done;
}
- dbg("usblp%d requested/got HP channel %ld/%d",
+ dev_dbg(&usblp->intf->dev,
+ "usblp%d requested/got HP channel %ld/%d\n",
usblp->minor, arg, newChannel);
break;
@@ -614,7 +621,8 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
goto done;
}
- dbg("usblp%d is bus=%d, device=%d",
+ dev_dbg(&usblp->intf->dev,
+ "usblp%d is bus=%d, device=%d\n",
usblp->minor, twoints[0], twoints[1]);
break;
@@ -634,7 +642,8 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
goto done;
}
- dbg("usblp%d is VID=0x%4.4X, PID=0x%4.4X",
+ dev_dbg(&usblp->intf->dev,
+ "usblp%d is VID=0x%4.4X, PID=0x%4.4X\n",
usblp->minor, twoints[0], twoints[1]);
break;
@@ -987,7 +996,7 @@ static int usblp_submit_read(struct usblp *usblp)
usblp->rcomplete = 0;
spin_unlock_irqrestore(&usblp->lock, flags);
if ((rc = usb_submit_urb(urb, GFP_KERNEL)) < 0) {
- dbg("error submitting urb (%d)", rc);
+ dev_dbg(&usblp->intf->dev, "error submitting urb (%d)\n", rc);
spin_lock_irqsave(&usblp->lock, flags);
usblp->rstatus = rc;
usblp->rcomplete = 1;
@@ -1129,7 +1138,8 @@ static int usblp_probe(struct usb_interface *intf,
/* Analyze and pick initial alternate settings and endpoints. */
protocol = usblp_select_alts(usblp);
if (protocol < 0) {
- dbg("incompatible printer-class device 0x%4.4X/0x%4.4X",
+ dev_dbg(&intf->dev,
+ "incompatible printer-class device 0x%4.4X/0x%4.4X\n",
le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
retval = -ENODEV;
@@ -1158,14 +1168,14 @@ static int usblp_probe(struct usb_interface *intf,
retval = usb_register_dev(intf, &usblp_class);
if (retval) {
- printk(KERN_ERR "usblp: Not able to get a minor"
- " (base %u, slice default): %d\n",
- USBLP_MINOR_BASE, retval);
+ dev_err(&intf->dev,
+ "usblp: Not able to get a minor (base %u, slice default): %d\n",
+ USBLP_MINOR_BASE, retval);
goto abort_intfdata;
}
usblp->minor = intf->minor;
- printk(KERN_INFO "usblp%d: USB %sdirectional printer dev %d "
- "if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X\n",
+ dev_info(&intf->dev,
+ "usblp%d: USB %sdirectional printer dev %d if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X\n",
usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum,
usblp->ifnum,
usblp->protocol[usblp->current_protocol].alt_setting,
@@ -1302,7 +1312,8 @@ static int usblp_set_protocol(struct usblp *usblp, int protocol)
usblp->bidir = (usblp->protocol[protocol].epread != NULL);
usblp->current_protocol = protocol;
- dbg("usblp%d set protocol %d", usblp->minor, protocol);
+ dev_dbg(&usblp->intf->dev, "usblp%d set protocol %d\n",
+ usblp->minor, protocol);
return 0;
}
@@ -1315,7 +1326,8 @@ static int usblp_cache_device_id_string(struct usblp *usblp)
err = usblp_get_id(usblp, 0, usblp->device_id_string, USBLP_DEVICE_ID_SIZE - 1);
if (err < 0) {
- dbg("usblp%d: error = %d reading IEEE-1284 Device ID string",
+ dev_dbg(&usblp->intf->dev,
+ "usblp%d: error = %d reading IEEE-1284 Device ID string\n",
usblp->minor, err);
usblp->device_id_string[0] = usblp->device_id_string[1] = '\0';
return -EIO;
@@ -1331,7 +1343,7 @@ static int usblp_cache_device_id_string(struct usblp *usblp)
length = USBLP_DEVICE_ID_SIZE - 1;
usblp->device_id_string[length] = '\0';
- dbg("usblp%d Device ID string [len=%d]=\"%s\"",
+ dev_dbg(&usblp->intf->dev, "usblp%d Device ID string [len=%d]=\"%s\"\n",
usblp->minor, length, &usblp->device_id_string[2]);
return length;
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index 18d02e32a3d5..9981984b365b 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -27,58 +27,6 @@ config USB_ANNOUNCE_NEW_DEVICES
comment "Miscellaneous USB options"
depends on USB
-config USB_DEVICEFS
- bool "USB device filesystem (DEPRECATED)"
- depends on USB
- ---help---
- If you say Y here (and to "/proc file system support" in the "File
- systems" section, above), you will get a file /proc/bus/usb/devices
- which lists the devices currently connected to your USB bus or
- busses, and for every connected device a file named
- "/proc/bus/usb/xxx/yyy", where xxx is the bus number and yyy the
- device number; the latter files can be used by user space programs
- to talk directly to the device. These files are "virtual", meaning
- they are generated on the fly and not stored on the hard drive.
-
- You may need to mount the usbfs file system to see the files, use
- mount -t usbfs none /proc/bus/usb
-
- For the format of the various /proc/bus/usb/ files, please read
- <file:Documentation/usb/proc_usb_info.txt>.
-
- Modern Linux systems do not use this.
-
- Usbfs entries are files and not character devices; usbfs can't
- handle Access Control Lists (ACL) which are the default way to
- grant access to USB devices for untrusted users of a desktop
- system.
-
- The usbfs functionality is replaced by real device-nodes managed by
- udev. These nodes lived in /dev/bus/usb and are used by libusb.
-
-config USB_DEVICE_CLASS
- bool "USB device class-devices (DEPRECATED)"
- depends on USB
- default y
- ---help---
- Userspace access to USB devices is granted by device-nodes exported
- directly from the usbdev in sysfs. Old versions of the driver
- core and udev needed additional class devices to export device nodes.
-
- These additional devices are difficult to handle in userspace, if
- information about USB interfaces must be available. One device
- contains the device node, the other device contains the interface
- data. Both devices are at the same level in sysfs (siblings) and one
- can't access the other. The device node created directly by the
- usb device is the parent device of the interface and therefore
- easily accessible from the interface event.
-
- This option provides backward compatibility for libusb device
- nodes (lsusb) when usbfs is not used, and the following udev rule
- doesn't exist:
- SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", \
- NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644"
-
config USB_DYNAMIC_MINORS
bool "Dynamic USB minor allocation"
depends on USB
@@ -125,7 +73,6 @@ config USB_OTG_WHITELIST
bool "Rely on OTG Targeted Peripherals List"
depends on USB_OTG || EXPERT
default y if USB_OTG
- default n if EXPERT
help
If you say Y here, the "otg_whitelist.h" file will be used as a
product whitelist, so USB peripherals not listed there will be
diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
index 507a4e1b6360..26059b93dbf4 100644
--- a/drivers/usb/core/Makefile
+++ b/drivers/usb/core/Makefile
@@ -9,6 +9,6 @@ usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o
usbcore-y += devio.o notify.o generic.o quirks.o devices.o
usbcore-$(CONFIG_PCI) += hcd-pci.o
-usbcore-$(CONFIG_USB_DEVICEFS) += inode.o
+usbcore-$(CONFIG_ACPI) += usb-acpi.o
obj-$(CONFIG_USB) += usbcore.o
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 8df4b76465ac..e0f107948eba 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -333,17 +333,14 @@ static struct async *async_getcompleted(struct dev_state *ps)
static struct async *async_getpending(struct dev_state *ps,
void __user *userurb)
{
- unsigned long flags;
struct async *as;
- spin_lock_irqsave(&ps->lock, flags);
list_for_each_entry(as, &ps->async_pending, asynclist)
if (as->userurb == userurb) {
list_del_init(&as->asynclist);
- spin_unlock_irqrestore(&ps->lock, flags);
return as;
}
- spin_unlock_irqrestore(&ps->lock, flags);
+
return NULL;
}
@@ -398,6 +395,7 @@ static void cancel_bulk_urbs(struct dev_state *ps, unsigned bulk_addr)
__releases(ps->lock)
__acquires(ps->lock)
{
+ struct urb *urb;
struct async *as;
/* Mark all the pending URBs that match bulk_addr, up to but not
@@ -420,8 +418,11 @@ __acquires(ps->lock)
list_for_each_entry(as, &ps->async_pending, asynclist) {
if (as->bulk_status == AS_UNLINK) {
as->bulk_status = 0; /* Only once */
+ urb = as->urb;
+ usb_get_urb(urb);
spin_unlock(&ps->lock); /* Allow completions */
- usb_unlink_urb(as->urb);
+ usb_unlink_urb(urb);
+ usb_put_urb(urb);
spin_lock(&ps->lock);
goto rescan;
}
@@ -472,6 +473,7 @@ static void async_completed(struct urb *urb)
static void destroy_async(struct dev_state *ps, struct list_head *list)
{
+ struct urb *urb;
struct async *as;
unsigned long flags;
@@ -479,10 +481,13 @@ static void destroy_async(struct dev_state *ps, struct list_head *list)
while (!list_empty(list)) {
as = list_entry(list->next, struct async, asynclist);
list_del_init(&as->asynclist);
+ urb = as->urb;
+ usb_get_urb(urb);
/* drop the spinlock so the completion handler can run */
spin_unlock_irqrestore(&ps->lock, flags);
- usb_kill_urb(as->urb);
+ usb_kill_urb(urb);
+ usb_put_urb(urb);
spin_lock_irqsave(&ps->lock, flags);
}
spin_unlock_irqrestore(&ps->lock, flags);
@@ -727,17 +732,6 @@ static int usbdev_open(struct inode *inode, struct file *file)
if (imajor(inode) == USB_DEVICE_MAJOR)
dev = usbdev_lookup_by_devt(inode->i_rdev);
-#ifdef CONFIG_USB_DEVICEFS
- /* procfs file */
- if (!dev) {
- dev = inode->i_private;
- if (dev && dev->usbfs_dentry &&
- dev->usbfs_dentry->d_inode == inode)
- usb_get_dev(dev);
- else
- dev = NULL;
- }
-#endif
mutex_unlock(&usbfs_mutex);
if (!dev)
@@ -1410,12 +1404,24 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)
static int proc_unlinkurb(struct dev_state *ps, void __user *arg)
{
+ struct urb *urb;
struct async *as;
+ unsigned long flags;
+ spin_lock_irqsave(&ps->lock, flags);
as = async_getpending(ps, arg);
- if (!as)
+ if (!as) {
+ spin_unlock_irqrestore(&ps->lock, flags);
return -EINVAL;
- usb_kill_urb(as->urb);
+ }
+
+ urb = as->urb;
+ usb_get_urb(urb);
+ spin_unlock_irqrestore(&ps->lock, flags);
+
+ usb_kill_urb(urb);
+ usb_put_urb(urb);
+
return 0;
}
@@ -2062,44 +2068,13 @@ static void usbdev_remove(struct usb_device *udev)
}
}
-#ifdef CONFIG_USB_DEVICE_CLASS
-static struct class *usb_classdev_class;
-
-static int usb_classdev_add(struct usb_device *dev)
-{
- struct device *cldev;
-
- cldev = device_create(usb_classdev_class, &dev->dev, dev->dev.devt,
- NULL, "usbdev%d.%d", dev->bus->busnum,
- dev->devnum);
- if (IS_ERR(cldev))
- return PTR_ERR(cldev);
- dev->usb_classdev = cldev;
- return 0;
-}
-
-static void usb_classdev_remove(struct usb_device *dev)
-{
- if (dev->usb_classdev)
- device_unregister(dev->usb_classdev);
-}
-
-#else
-#define usb_classdev_add(dev) 0
-#define usb_classdev_remove(dev) do {} while (0)
-
-#endif
-
static int usbdev_notify(struct notifier_block *self,
unsigned long action, void *dev)
{
switch (action) {
case USB_DEVICE_ADD:
- if (usb_classdev_add(dev))
- return NOTIFY_BAD;
break;
case USB_DEVICE_REMOVE:
- usb_classdev_remove(dev);
usbdev_remove(dev);
break;
}
@@ -2129,21 +2104,6 @@ int __init usb_devio_init(void)
USB_DEVICE_MAJOR);
goto error_cdev;
}
-#ifdef CONFIG_USB_DEVICE_CLASS
- usb_classdev_class = class_create(THIS_MODULE, "usb_device");
- if (IS_ERR(usb_classdev_class)) {
- printk(KERN_ERR "Unable to register usb_device class\n");
- retval = PTR_ERR(usb_classdev_class);
- cdev_del(&usb_device_cdev);
- usb_classdev_class = NULL;
- goto out;
- }
- /* devices of this class shadow the major:minor of their parent
- * device, so clear ->dev_kobj to prevent adding duplicate entries
- * to /sys/dev
- */
- usb_classdev_class->dev_kobj = NULL;
-#endif
usb_register_notify(&usbdev_nb);
out:
return retval;
@@ -2156,9 +2116,6 @@ error_cdev:
void usb_devio_cleanup(void)
{
usb_unregister_notify(&usbdev_nb);
-#ifdef CONFIG_USB_DEVICE_CLASS
- class_destroy(usb_classdev_class);
-#endif
cdev_del(&usb_device_cdev);
unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
}
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 9a56635dc19c..f536aebc958e 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -79,6 +79,30 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,
}
EXPORT_SYMBOL_GPL(usb_store_new_id);
+ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf)
+{
+ struct usb_dynid *dynid;
+ size_t count = 0;
+
+ list_for_each_entry(dynid, &dynids->list, node)
+ if (dynid->id.bInterfaceClass != 0)
+ count += scnprintf(&buf[count], PAGE_SIZE - count, "%04x %04x %02x\n",
+ dynid->id.idVendor, dynid->id.idProduct,
+ dynid->id.bInterfaceClass);
+ else
+ count += scnprintf(&buf[count], PAGE_SIZE - count, "%04x %04x\n",
+ dynid->id.idVendor, dynid->id.idProduct);
+ return count;
+}
+EXPORT_SYMBOL_GPL(usb_show_dynids);
+
+static ssize_t show_dynids(struct device_driver *driver, char *buf)
+{
+ struct usb_driver *usb_drv = to_usb_driver(driver);
+
+ return usb_show_dynids(&usb_drv->dynids, buf);
+}
+
static ssize_t store_new_id(struct device_driver *driver,
const char *buf, size_t count)
{
@@ -86,7 +110,7 @@ static ssize_t store_new_id(struct device_driver *driver,
return usb_store_new_id(&usb_drv->dynids, driver, buf, count);
}
-static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
+static DRIVER_ATTR(new_id, S_IRUGO | S_IWUSR, show_dynids, store_new_id);
/**
* store_remove_id - remove a USB device ID from this driver
@@ -127,7 +151,7 @@ store_remove_id(struct device_driver *driver, const char *buf, size_t count)
return retval;
return count;
}
-static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id);
+static DRIVER_ATTR(remove_id, S_IRUGO | S_IWUSR, show_dynids, store_remove_id);
static int usb_create_newid_files(struct usb_driver *usb_drv)
{
@@ -264,6 +288,7 @@ static int usb_probe_interface(struct device *dev)
struct usb_device *udev = interface_to_usbdev(intf);
const struct usb_device_id *id;
int error = -ENODEV;
+ int lpm_disable_error;
dev_dbg(dev, "%s\n", __func__);
@@ -300,6 +325,25 @@ static int usb_probe_interface(struct device *dev)
if (driver->supports_autosuspend)
pm_runtime_enable(dev);
+ /* If the new driver doesn't allow hub-initiated LPM, and we can't
+ * disable hub-initiated LPM, then fail the probe.
+ *
+ * Otherwise, leaving LPM enabled should be harmless, because the
+ * endpoint intervals should remain the same, and the U1/U2 timeouts
+ * should remain the same.
+ *
+ * If we need to install alt setting 0 before probe, or another alt
+ * setting during probe, that should also be fine. usb_set_interface()
+ * will attempt to disable LPM, and fail if it can't disable it.
+ */
+ lpm_disable_error = usb_unlocked_disable_lpm(udev);
+ if (lpm_disable_error && driver->disable_hub_initiated_lpm) {
+ dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n.",
+ __func__, driver->name);
+ error = lpm_disable_error;
+ goto err;
+ }
+
/* Carry out a deferred switch to altsetting 0 */
if (intf->needs_altsetting0) {
error = usb_set_interface(udev, intf->altsetting[0].
@@ -314,6 +358,11 @@ static int usb_probe_interface(struct device *dev)
goto err;
intf->condition = USB_INTERFACE_BOUND;
+
+ /* If the LPM disable succeeded, balance the ref counts. */
+ if (!lpm_disable_error)
+ usb_unlocked_enable_lpm(udev);
+
usb_autosuspend_device(udev);
return error;
@@ -337,7 +386,7 @@ static int usb_unbind_interface(struct device *dev)
struct usb_driver *driver = to_usb_driver(dev->driver);
struct usb_interface *intf = to_usb_interface(dev);
struct usb_device *udev;
- int error, r;
+ int error, r, lpm_disable_error;
intf->condition = USB_INTERFACE_UNBINDING;
@@ -345,6 +394,13 @@ static int usb_unbind_interface(struct device *dev)
udev = interface_to_usbdev(intf);
error = usb_autoresume_device(udev);
+ /* Hub-initiated LPM policy may change, so attempt to disable LPM until
+ * the driver is unbound. If LPM isn't disabled, that's fine because it
+ * wouldn't be enabled unless all the bound interfaces supported
+ * hub-initiated LPM.
+ */
+ lpm_disable_error = usb_unlocked_disable_lpm(udev);
+
/* Terminate all URBs for this interface unless the driver
* supports "soft" unbinding.
*/
@@ -378,6 +434,10 @@ static int usb_unbind_interface(struct device *dev)
intf->condition = USB_INTERFACE_UNBOUND;
intf->needs_remote_wakeup = 0;
+ /* Attempt to re-enable USB3 LPM, if the disable succeeded. */
+ if (!lpm_disable_error)
+ usb_unlocked_enable_lpm(udev);
+
/* Unbound interfaces are always runtime-PM-disabled and -suspended */
if (driver->supports_autosuspend)
pm_runtime_disable(dev);
@@ -418,17 +478,29 @@ int usb_driver_claim_interface(struct usb_driver *driver,
struct usb_interface *iface, void *priv)
{
struct device *dev = &iface->dev;
+ struct usb_device *udev;
int retval = 0;
+ int lpm_disable_error;
if (dev->driver)
return -EBUSY;
+ udev = interface_to_usbdev(iface);
+
dev->driver = &driver->drvwrap.driver;
usb_set_intfdata(iface, priv);
iface->needs_binding = 0;
iface->condition = USB_INTERFACE_BOUND;
+ /* Disable LPM until this driver is bound. */
+ lpm_disable_error = usb_unlocked_disable_lpm(udev);
+ if (lpm_disable_error && driver->disable_hub_initiated_lpm) {
+ dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n.",
+ __func__, driver->name);
+ return -ENOMEM;
+ }
+
/* Claimed interfaces are initially inactive (suspended) and
* runtime-PM-enabled, but only if the driver has autosuspend
* support. Otherwise they are marked active, to prevent the
@@ -447,6 +519,10 @@ int usb_driver_claim_interface(struct usb_driver *driver,
if (device_is_registered(dev))
retval = device_bind_driver(dev);
+ /* Attempt to re-enable USB3 LPM, if the disable was successful. */
+ if (!lpm_disable_error)
+ usb_unlocked_enable_lpm(udev);
+
return retval;
}
EXPORT_SYMBOL_GPL(usb_driver_claim_interface);
@@ -726,16 +802,6 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
return -ENODEV;
}
-#ifdef CONFIG_USB_DEVICEFS
- /* If this is available, userspace programs can directly read
- * all the device descriptors we don't tell them about. Or
- * act as usermode drivers.
- */
- if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d",
- usb_dev->bus->busnum, usb_dev->devnum))
- return -ENOMEM;
-#endif
-
/* per-device configurations are common */
if (add_uevent_var(env, "PRODUCT=%x/%x/%x",
le16_to_cpu(usb_dev->descriptor.idVendor),
@@ -788,15 +854,13 @@ int usb_register_device_driver(struct usb_device_driver *new_udriver,
retval = driver_register(&new_udriver->drvwrap.driver);
- if (!retval) {
+ if (!retval)
pr_info("%s: registered new device driver %s\n",
usbcore_name, new_udriver->name);
- usbfs_update_special();
- } else {
+ else
printk(KERN_ERR "%s: error %d registering device "
" driver %s\n",
usbcore_name, retval, new_udriver->name);
- }
return retval;
}
@@ -815,7 +879,6 @@ void usb_deregister_device_driver(struct usb_device_driver *udriver)
usbcore_name, udriver->name);
driver_unregister(&udriver->drvwrap.driver);
- usbfs_update_special();
}
EXPORT_SYMBOL_GPL(usb_deregister_device_driver);
@@ -856,8 +919,6 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
if (retval)
goto out;
- usbfs_update_special();
-
retval = usb_create_newid_files(new_driver);
if (retval)
goto out_newid;
@@ -897,8 +958,6 @@ void usb_deregister(struct usb_driver *driver)
usb_remove_newid_files(driver);
driver_unregister(&driver->drvwrap.driver);
usb_free_dynids(driver);
-
- usbfs_update_special();
}
EXPORT_SYMBOL_GPL(usb_deregister);
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index d95760de9e8b..e673b26e598f 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -183,7 +183,7 @@ int usb_register_dev(struct usb_interface *intf,
if (retval)
return retval;
- dev_dbg(&intf->dev, "looking for a minor, starting at %d", minor_base);
+ dev_dbg(&intf->dev, "looking for a minor, starting at %d\n", minor_base);
down_write(&minor_rwsem);
for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
@@ -239,7 +239,7 @@ void usb_deregister_dev(struct usb_interface *intf,
if (intf->minor == -1)
return;
- dbg ("removing %d minor", intf->minor);
+ dev_dbg(&intf->dev, "removing %d minor\n", intf->minor);
down_write(&minor_rwsem);
usb_minors[intf->minor] = NULL;
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 140d3e11f212..190b1ec7bdcb 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -138,7 +138,7 @@ static const u8 usb3_rh_dev_descriptor[18] = {
0x03, /* __u8 bDeviceProtocol; USB 3.0 hub */
0x09, /* __u8 bMaxPacketSize0; 2^9 = 512 Bytes */
- 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */
+ 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation 0x1d6b */
0x03, 0x00, /* __le16 idProduct; device 0x0003 */
KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
@@ -159,7 +159,7 @@ static const u8 usb2_rh_dev_descriptor [18] = {
0x00, /* __u8 bDeviceProtocol; [ usb 2.0 no TT ] */
0x40, /* __u8 bMaxPacketSize0; 64 Bytes */
- 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */
+ 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation 0x1d6b */
0x02, 0x00, /* __le16 idProduct; device 0x0002 */
KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
@@ -182,7 +182,7 @@ static const u8 usb11_rh_dev_descriptor [18] = {
0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */
0x40, /* __u8 bMaxPacketSize0; 64 Bytes */
- 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */
+ 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation 0x1d6b */
0x01, 0x00, /* __le16 idProduct; device 0x0001 */
KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
@@ -997,6 +997,15 @@ static int register_root_hub(struct usb_hcd *hcd)
dev_name(&usb_dev->dev), retval);
return (retval < 0) ? retval : -EMSGSIZE;
}
+ if (usb_dev->speed == USB_SPEED_SUPER) {
+ retval = usb_get_bos_descriptor(usb_dev);
+ if (retval < 0) {
+ mutex_unlock(&usb_bus_list_lock);
+ dev_dbg(parent_dev, "can't read %s bos descriptor %d\n",
+ dev_name(&usb_dev->dev), retval);
+ return retval;
+ }
+ }
retval = usb_new_device (usb_dev);
if (retval) {
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index ec6c97dadbe4..04fb834c3fa1 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -177,6 +177,228 @@ static struct usb_hub *hdev_to_hub(struct usb_device *hdev)
return usb_get_intfdata(hdev->actconfig->interface[0]);
}
+static int usb_device_supports_lpm(struct usb_device *udev)
+{
+ /* USB 2.1 (and greater) devices indicate LPM support through
+ * their USB 2.0 Extended Capabilities BOS descriptor.
+ */
+ if (udev->speed == USB_SPEED_HIGH) {
+ if (udev->bos->ext_cap &&
+ (USB_LPM_SUPPORT &
+ le32_to_cpu(udev->bos->ext_cap->bmAttributes)))
+ return 1;
+ return 0;
+ }
+
+ /* All USB 3.0 must support LPM, but we need their max exit latency
+ * information from the SuperSpeed Extended Capabilities BOS descriptor.
+ */
+ if (!udev->bos->ss_cap) {
+ dev_warn(&udev->dev, "No LPM exit latency info found. "
+ "Power management will be impacted.\n");
+ return 0;
+ }
+ if (udev->parent->lpm_capable)
+ return 1;
+
+ dev_warn(&udev->dev, "Parent hub missing LPM exit latency info. "
+ "Power management will be impacted.\n");
+ return 0;
+}
+
+/*
+ * Set the Maximum Exit Latency (MEL) for the host to initiate a transition from
+ * either U1 or U2.
+ */
+static void usb_set_lpm_mel(struct usb_device *udev,
+ struct usb3_lpm_parameters *udev_lpm_params,
+ unsigned int udev_exit_latency,
+ struct usb_hub *hub,
+ struct usb3_lpm_parameters *hub_lpm_params,
+ unsigned int hub_exit_latency)
+{
+ unsigned int total_mel;
+ unsigned int device_mel;
+ unsigned int hub_mel;
+
+ /*
+ * Calculate the time it takes to transition all links from the roothub
+ * to the parent hub into U0. The parent hub must then decode the
+ * packet (hub header decode latency) to figure out which port it was
+ * bound for.
+ *
+ * The Hub Header decode latency is expressed in 0.1us intervals (0x1
+ * means 0.1us). Multiply that by 100 to get nanoseconds.
+ */
+ total_mel = hub_lpm_params->mel +
+ (hub->descriptor->u.ss.bHubHdrDecLat * 100);
+
+ /*
+ * How long will it take to transition the downstream hub's port into
+ * U0? The greater of either the hub exit latency or the device exit
+ * latency.
+ *
+ * The BOS U1/U2 exit latencies are expressed in 1us intervals.
+ * Multiply that by 1000 to get nanoseconds.
+ */
+ device_mel = udev_exit_latency * 1000;
+ hub_mel = hub_exit_latency * 1000;
+ if (device_mel > hub_mel)
+ total_mel += device_mel;
+ else
+ total_mel += hub_mel;
+
+ udev_lpm_params->mel = total_mel;
+}
+
+/*
+ * Set the maximum Device to Host Exit Latency (PEL) for the device to initiate
+ * a transition from either U1 or U2.
+ */
+static void usb_set_lpm_pel(struct usb_device *udev,
+ struct usb3_lpm_parameters *udev_lpm_params,
+ unsigned int udev_exit_latency,
+ struct usb_hub *hub,
+ struct usb3_lpm_parameters *hub_lpm_params,
+ unsigned int hub_exit_latency,
+ unsigned int port_to_port_exit_latency)
+{
+ unsigned int first_link_pel;
+ unsigned int hub_pel;
+
+ /*
+ * First, the device sends an LFPS to transition the link between the
+ * device and the parent hub into U0. The exit latency is the bigger of
+ * the device exit latency or the hub exit latency.
+ */
+ if (udev_exit_latency > hub_exit_latency)
+ first_link_pel = udev_exit_latency * 1000;
+ else
+ first_link_pel = hub_exit_latency * 1000;
+
+ /*
+ * When the hub starts to receive the LFPS, there is a slight delay for
+ * it to figure out that one of the ports is sending an LFPS. Then it
+ * will forward the LFPS to its upstream link. The exit latency is the
+ * delay, plus the PEL that we calculated for this hub.
+ */
+ hub_pel = port_to_port_exit_latency * 1000 + hub_lpm_params->pel;
+
+ /*
+ * According to figure C-7 in the USB 3.0 spec, the PEL for this device
+ * is the greater of the two exit latencies.
+ */
+ if (first_link_pel > hub_pel)
+ udev_lpm_params->pel = first_link_pel;
+ else
+ udev_lpm_params->pel = hub_pel;
+}
+
+/*
+ * Set the System Exit Latency (SEL) to indicate the total worst-case time from
+ * when a device initiates a transition to U0, until when it will receive the
+ * first packet from the host controller.
+ *
+ * Section C.1.5.1 describes the four components to this:
+ * - t1: device PEL
+ * - t2: time for the ERDY to make it from the device to the host.
+ * - t3: a host-specific delay to process the ERDY.
+ * - t4: time for the packet to make it from the host to the device.
+ *
+ * t3 is specific to both the xHCI host and the platform the host is integrated
+ * into. The Intel HW folks have said it's negligible, FIXME if a different
+ * vendor says otherwise.
+ */
+static void usb_set_lpm_sel(struct usb_device *udev,
+ struct usb3_lpm_parameters *udev_lpm_params)
+{
+ struct usb_device *parent;
+ unsigned int num_hubs;
+ unsigned int total_sel;
+
+ /* t1 = device PEL */
+ total_sel = udev_lpm_params->pel;
+ /* How many external hubs are in between the device & the root port. */
+ for (parent = udev->parent, num_hubs = 0; parent->parent;
+ parent = parent->parent)
+ num_hubs++;
+ /* t2 = 2.1us + 250ns * (num_hubs - 1) */
+ if (num_hubs > 0)
+ total_sel += 2100 + 250 * (num_hubs - 1);
+
+ /* t4 = 250ns * num_hubs */
+ total_sel += 250 * num_hubs;
+
+ udev_lpm_params->sel = total_sel;
+}
+
+static void usb_set_lpm_parameters(struct usb_device *udev)
+{
+ struct usb_hub *hub;
+ unsigned int port_to_port_delay;
+ unsigned int udev_u1_del;
+ unsigned int udev_u2_del;
+ unsigned int hub_u1_del;
+ unsigned int hub_u2_del;
+
+ if (!udev->lpm_capable || udev->speed != USB_SPEED_SUPER)
+ return;
+
+ hub = hdev_to_hub(udev->parent);
+ /* It doesn't take time to transition the roothub into U0, since it
+ * doesn't have an upstream link.
+ */
+ if (!hub)
+ return;
+
+ udev_u1_del = udev->bos->ss_cap->bU1devExitLat;
+ udev_u2_del = udev->bos->ss_cap->bU2DevExitLat;
+ hub_u1_del = udev->parent->bos->ss_cap->bU1devExitLat;
+ hub_u2_del = udev->parent->bos->ss_cap->bU2DevExitLat;
+
+ usb_set_lpm_mel(udev, &udev->u1_params, udev_u1_del,
+ hub, &udev->parent->u1_params, hub_u1_del);
+
+ usb_set_lpm_mel(udev, &udev->u2_params, udev_u2_del,
+ hub, &udev->parent->u2_params, hub_u2_del);
+
+ /*
+ * Appendix C, section C.2.2.2, says that there is a slight delay from
+ * when the parent hub notices the downstream port is trying to
+ * transition to U0 to when the hub initiates a U0 transition on its
+ * upstream port. The section says the delays are tPort2PortU1EL and
+ * tPort2PortU2EL, but it doesn't define what they are.
+ *
+ * The hub chapter, sections 10.4.2.4 and 10.4.2.5 seem to be talking
+ * about the same delays. Use the maximum delay calculations from those
+ * sections. For U1, it's tHubPort2PortExitLat, which is 1us max. For
+ * U2, it's tHubPort2PortExitLat + U2DevExitLat - U1DevExitLat. I
+ * assume the device exit latencies they are talking about are the hub
+ * exit latencies.
+ *
+ * What do we do if the U2 exit latency is less than the U1 exit
+ * latency? It's possible, although not likely...
+ */
+ port_to_port_delay = 1;
+
+ usb_set_lpm_pel(udev, &udev->u1_params, udev_u1_del,
+ hub, &udev->parent->u1_params, hub_u1_del,
+ port_to_port_delay);
+
+ if (hub_u2_del > hub_u1_del)
+ port_to_port_delay = 1 + hub_u2_del - hub_u1_del;
+ else
+ port_to_port_delay = 1 + hub_u1_del;
+
+ usb_set_lpm_pel(udev, &udev->u2_params, udev_u2_del,
+ hub, &udev->parent->u2_params, hub_u2_del,
+ port_to_port_delay);
+
+ /* Now that we've got PEL, calculate SEL. */
+ usb_set_lpm_sel(udev, &udev->u1_params);
+ usb_set_lpm_sel(udev, &udev->u2_params);
+}
+
/* USB 2.0 spec Section 11.24.4.5 */
static int get_hub_descriptor(struct usb_device *hdev, void *data)
{
@@ -2480,6 +2702,12 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
if (udev->usb2_hw_lpm_enabled == 1)
usb_set_usb2_hardware_lpm(udev, 0);
+ if (usb_unlocked_disable_lpm(udev)) {
+ dev_err(&udev->dev, "%s Failed to disable LPM before suspend\n.",
+ __func__);
+ return -ENOMEM;
+ }
+
/* see 7.1.7.6 */
if (hub_is_superspeed(hub->hdev))
status = set_port_feature(hub->hdev,
@@ -2499,6 +2727,13 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
NULL, 0,
USB_CTRL_SET_TIMEOUT);
+ /* Try to enable USB2 hardware LPM again */
+ if (udev->usb2_hw_lpm_capable == 1)
+ usb_set_usb2_hardware_lpm(udev, 1);
+
+ /* Try to enable USB3 LPM again */
+ usb_unlocked_enable_lpm(udev);
+
/* System sleep transitions should never fail */
if (!PMSG_IS_AUTO(msg))
status = 0;
@@ -2696,6 +2931,9 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
/* Try to enable USB2 hardware LPM */
if (udev->usb2_hw_lpm_capable == 1)
usb_set_usb2_hardware_lpm(udev, 1);
+
+ /* Try to enable USB3 LPM */
+ usb_unlocked_enable_lpm(udev);
}
return status;
@@ -2824,11 +3062,429 @@ void usb_root_hub_lost_power(struct usb_device *rhdev)
}
EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
+static const char * const usb3_lpm_names[] = {
+ "U0",
+ "U1",
+ "U2",
+ "U3",
+};
+
+/*
+ * Send a Set SEL control transfer to the device, prior to enabling
+ * device-initiated U1 or U2. This lets the device know the exit latencies from
+ * the time the device initiates a U1 or U2 exit, to the time it will receive a
+ * packet from the host.
+ *
+ * This function will fail if the SEL or PEL values for udev are greater than
+ * the maximum allowed values for the link state to be enabled.
+ */
+static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state)
+{
+ struct usb_set_sel_req *sel_values;
+ unsigned long long u1_sel;
+ unsigned long long u1_pel;
+ unsigned long long u2_sel;
+ unsigned long long u2_pel;
+ int ret;
+
+ /* Convert SEL and PEL stored in ns to us */
+ u1_sel = DIV_ROUND_UP(udev->u1_params.sel, 1000);
+ u1_pel = DIV_ROUND_UP(udev->u1_params.pel, 1000);
+ u2_sel = DIV_ROUND_UP(udev->u2_params.sel, 1000);
+ u2_pel = DIV_ROUND_UP(udev->u2_params.pel, 1000);
+
+ /*
+ * Make sure that the calculated SEL and PEL values for the link
+ * state we're enabling aren't bigger than the max SEL/PEL
+ * value that will fit in the SET SEL control transfer.
+ * Otherwise the device would get an incorrect idea of the exit
+ * latency for the link state, and could start a device-initiated
+ * U1/U2 when the exit latencies are too high.
+ */
+ if ((state == USB3_LPM_U1 &&
+ (u1_sel > USB3_LPM_MAX_U1_SEL_PEL ||
+ u1_pel > USB3_LPM_MAX_U1_SEL_PEL)) ||
+ (state == USB3_LPM_U2 &&
+ (u2_sel > USB3_LPM_MAX_U2_SEL_PEL ||
+ u2_pel > USB3_LPM_MAX_U2_SEL_PEL))) {
+ dev_dbg(&udev->dev, "Device-initiated %s disabled due "
+ "to long SEL %llu ms or PEL %llu ms\n",
+ usb3_lpm_names[state], u1_sel, u1_pel);
+ return -EINVAL;
+ }
+
+ /*
+ * If we're enabling device-initiated LPM for one link state,
+ * but the other link state has a too high SEL or PEL value,
+ * just set those values to the max in the Set SEL request.
+ */
+ if (u1_sel > USB3_LPM_MAX_U1_SEL_PEL)
+ u1_sel = USB3_LPM_MAX_U1_SEL_PEL;
+
+ if (u1_pel > USB3_LPM_MAX_U1_SEL_PEL)
+ u1_pel = USB3_LPM_MAX_U1_SEL_PEL;
+
+ if (u2_sel > USB3_LPM_MAX_U2_SEL_PEL)
+ u2_sel = USB3_LPM_MAX_U2_SEL_PEL;
+
+ if (u2_pel > USB3_LPM_MAX_U2_SEL_PEL)
+ u2_pel = USB3_LPM_MAX_U2_SEL_PEL;
+
+ /*
+ * usb_enable_lpm() can be called as part of a failed device reset,
+ * which may be initiated by an error path of a mass storage driver.
+ * Therefore, use GFP_NOIO.
+ */
+ sel_values = kmalloc(sizeof *(sel_values), GFP_NOIO);
+ if (!sel_values)
+ return -ENOMEM;
+
+ sel_values->u1_sel = u1_sel;
+ sel_values->u1_pel = u1_pel;
+ sel_values->u2_sel = cpu_to_le16(u2_sel);
+ sel_values->u2_pel = cpu_to_le16(u2_pel);
+
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_SET_SEL,
+ USB_RECIP_DEVICE,
+ 0, 0,
+ sel_values, sizeof *(sel_values),
+ USB_CTRL_SET_TIMEOUT);
+ kfree(sel_values);
+ return ret;
+}
+
+/*
+ * Enable or disable device-initiated U1 or U2 transitions.
+ */
+static int usb_set_device_initiated_lpm(struct usb_device *udev,
+ enum usb3_link_state state, bool enable)
+{
+ int ret;
+ int feature;
+
+ switch (state) {
+ case USB3_LPM_U1:
+ feature = USB_DEVICE_U1_ENABLE;
+ break;
+ case USB3_LPM_U2:
+ feature = USB_DEVICE_U2_ENABLE;
+ break;
+ default:
+ dev_warn(&udev->dev, "%s: Can't %s non-U1 or U2 state.\n",
+ __func__, enable ? "enable" : "disable");
+ return -EINVAL;
+ }
+
+ if (udev->state != USB_STATE_CONFIGURED) {
+ dev_dbg(&udev->dev, "%s: Can't %s %s state "
+ "for unconfigured device.\n",
+ __func__, enable ? "enable" : "disable",
+ usb3_lpm_names[state]);
+ return 0;
+ }
+
+ if (enable) {
+ /*
+ * First, let the device know about the exit latencies
+ * associated with the link state we're about to enable.
+ */
+ ret = usb_req_set_sel(udev, state);
+ if (ret < 0) {
+ dev_warn(&udev->dev, "Set SEL for device-initiated "
+ "%s failed.\n", usb3_lpm_names[state]);
+ return -EBUSY;
+ }
+ /*
+ * Now send the control transfer to enable device-initiated LPM
+ * for either U1 or U2.
+ */
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_SET_FEATURE,
+ USB_RECIP_DEVICE,
+ feature,
+ 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ } else {
+ ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_CLEAR_FEATURE,
+ USB_RECIP_DEVICE,
+ feature,
+ 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ }
+ if (ret < 0) {
+ dev_warn(&udev->dev, "%s of device-initiated %s failed.\n",
+ enable ? "Enable" : "Disable",
+ usb3_lpm_names[state]);
+ return -EBUSY;
+ }
+ return 0;
+}
+
+static int usb_set_lpm_timeout(struct usb_device *udev,
+ enum usb3_link_state state, int timeout)
+{
+ int ret;
+ int feature;
+
+ switch (state) {
+ case USB3_LPM_U1:
+ feature = USB_PORT_FEAT_U1_TIMEOUT;
+ break;
+ case USB3_LPM_U2:
+ feature = USB_PORT_FEAT_U2_TIMEOUT;
+ break;
+ default:
+ dev_warn(&udev->dev, "%s: Can't set timeout for non-U1 or U2 state.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (state == USB3_LPM_U1 && timeout > USB3_LPM_U1_MAX_TIMEOUT &&
+ timeout != USB3_LPM_DEVICE_INITIATED) {
+ dev_warn(&udev->dev, "Failed to set %s timeout to 0x%x, "
+ "which is a reserved value.\n",
+ usb3_lpm_names[state], timeout);
+ return -EINVAL;
+ }
+
+ ret = set_port_feature(udev->parent,
+ USB_PORT_LPM_TIMEOUT(timeout) | udev->portnum,
+ feature);
+ if (ret < 0) {
+ dev_warn(&udev->dev, "Failed to set %s timeout to 0x%x,"
+ "error code %i\n", usb3_lpm_names[state],
+ timeout, ret);
+ return -EBUSY;
+ }
+ if (state == USB3_LPM_U1)
+ udev->u1_params.timeout = timeout;
+ else
+ udev->u2_params.timeout = timeout;
+ return 0;
+}
+
+/*
+ * Enable the hub-initiated U1/U2 idle timeouts, and enable device-initiated
+ * U1/U2 entry.
+ *
+ * We will attempt to enable U1 or U2, but there are no guarantees that the
+ * control transfers to set the hub timeout or enable device-initiated U1/U2
+ * will be successful.
+ *
+ * If we cannot set the parent hub U1/U2 timeout, we attempt to let the xHCI
+ * driver know about it. If that call fails, it should be harmless, and just
+ * take up more slightly more bus bandwidth for unnecessary U1/U2 exit latency.
+ */
+static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
+ enum usb3_link_state state)
+{
+ int timeout;
+
+ /* We allow the host controller to set the U1/U2 timeout internally
+ * first, so that it can change its schedule to account for the
+ * additional latency to send data to a device in a lower power
+ * link state.
+ */
+ timeout = hcd->driver->enable_usb3_lpm_timeout(hcd, udev, state);
+
+ /* xHCI host controller doesn't want to enable this LPM state. */
+ if (timeout == 0)
+ return;
+
+ if (timeout < 0) {
+ dev_warn(&udev->dev, "Could not enable %s link state, "
+ "xHCI error %i.\n", usb3_lpm_names[state],
+ timeout);
+ return;
+ }
+
+ if (usb_set_lpm_timeout(udev, state, timeout))
+ /* If we can't set the parent hub U1/U2 timeout,
+ * device-initiated LPM won't be allowed either, so let the xHCI
+ * host know that this link state won't be enabled.
+ */
+ hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state);
+
+ /* Only a configured device will accept the Set Feature U1/U2_ENABLE */
+ else if (udev->actconfig)
+ usb_set_device_initiated_lpm(udev, state, true);
+
+}
+
+/*
+ * Disable the hub-initiated U1/U2 idle timeouts, and disable device-initiated
+ * U1/U2 entry.
+ *
+ * If this function returns -EBUSY, the parent hub will still allow U1/U2 entry.
+ * If zero is returned, the parent will not allow the link to go into U1/U2.
+ *
+ * If zero is returned, device-initiated U1/U2 entry may still be enabled, but
+ * it won't have an effect on the bus link state because the parent hub will
+ * still disallow device-initiated U1/U2 entry.
+ *
+ * If zero is returned, the xHCI host controller may still think U1/U2 entry is
+ * possible. The result will be slightly more bus bandwidth will be taken up
+ * (to account for U1/U2 exit latency), but it should be harmless.
+ */
+static int usb_disable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
+ enum usb3_link_state state)
+{
+ int feature;
+
+ switch (state) {
+ case USB3_LPM_U1:
+ feature = USB_PORT_FEAT_U1_TIMEOUT;
+ break;
+ case USB3_LPM_U2:
+ feature = USB_PORT_FEAT_U2_TIMEOUT;
+ break;
+ default:
+ dev_warn(&udev->dev, "%s: Can't disable non-U1 or U2 state.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (usb_set_lpm_timeout(udev, state, 0))
+ return -EBUSY;
+
+ usb_set_device_initiated_lpm(udev, state, false);
+
+ if (hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state))
+ dev_warn(&udev->dev, "Could not disable xHCI %s timeout, "
+ "bus schedule bandwidth may be impacted.\n",
+ usb3_lpm_names[state]);
+ return 0;
+}
+
+/*
+ * Disable hub-initiated and device-initiated U1 and U2 entry.
+ * Caller must own the bandwidth_mutex.
+ *
+ * This will call usb_enable_lpm() on failure, which will decrement
+ * lpm_disable_count, and will re-enable LPM if lpm_disable_count reaches zero.
+ */
+int usb_disable_lpm(struct usb_device *udev)
+{
+ struct usb_hcd *hcd;
+
+ if (!udev || !udev->parent ||
+ udev->speed != USB_SPEED_SUPER ||
+ !udev->lpm_capable)
+ return 0;
+
+ hcd = bus_to_hcd(udev->bus);
+ if (!hcd || !hcd->driver->disable_usb3_lpm_timeout)
+ return 0;
+
+ udev->lpm_disable_count++;
+ if ((udev->u1_params.timeout == 0 && udev->u1_params.timeout == 0))
+ return 0;
+
+ /* If LPM is enabled, attempt to disable it. */
+ if (usb_disable_link_state(hcd, udev, USB3_LPM_U1))
+ goto enable_lpm;
+ if (usb_disable_link_state(hcd, udev, USB3_LPM_U2))
+ goto enable_lpm;
+
+ return 0;
+
+enable_lpm:
+ usb_enable_lpm(udev);
+ return -EBUSY;
+}
+EXPORT_SYMBOL_GPL(usb_disable_lpm);
+
+/* Grab the bandwidth_mutex before calling usb_disable_lpm() */
+int usb_unlocked_disable_lpm(struct usb_device *udev)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+ int ret;
+
+ if (!hcd)
+ return -EINVAL;
+
+ mutex_lock(hcd->bandwidth_mutex);
+ ret = usb_disable_lpm(udev);
+ mutex_unlock(hcd->bandwidth_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(usb_unlocked_disable_lpm);
+
+/*
+ * Attempt to enable device-initiated and hub-initiated U1 and U2 entry. The
+ * xHCI host policy may prevent U1 or U2 from being enabled.
+ *
+ * Other callers may have disabled link PM, so U1 and U2 entry will be disabled
+ * until the lpm_disable_count drops to zero. Caller must own the
+ * bandwidth_mutex.
+ */
+void usb_enable_lpm(struct usb_device *udev)
+{
+ struct usb_hcd *hcd;
+
+ if (!udev || !udev->parent ||
+ udev->speed != USB_SPEED_SUPER ||
+ !udev->lpm_capable)
+ return;
+
+ udev->lpm_disable_count--;
+ hcd = bus_to_hcd(udev->bus);
+ /* Double check that we can both enable and disable LPM.
+ * Device must be configured to accept set feature U1/U2 timeout.
+ */
+ if (!hcd || !hcd->driver->enable_usb3_lpm_timeout ||
+ !hcd->driver->disable_usb3_lpm_timeout)
+ return;
+
+ if (udev->lpm_disable_count > 0)
+ return;
+
+ usb_enable_link_state(hcd, udev, USB3_LPM_U1);
+ usb_enable_link_state(hcd, udev, USB3_LPM_U2);
+}
+EXPORT_SYMBOL_GPL(usb_enable_lpm);
+
+/* Grab the bandwidth_mutex before calling usb_enable_lpm() */
+void usb_unlocked_enable_lpm(struct usb_device *udev)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ if (!hcd)
+ return;
+
+ mutex_lock(hcd->bandwidth_mutex);
+ usb_enable_lpm(udev);
+ mutex_unlock(hcd->bandwidth_mutex);
+}
+EXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm);
+
+
#else /* CONFIG_PM */
#define hub_suspend NULL
#define hub_resume NULL
#define hub_reset_resume NULL
+
+int usb_disable_lpm(struct usb_device *udev)
+{
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_disable_lpm);
+
+void usb_enable_lpm(struct usb_device *udev) { }
+EXPORT_SYMBOL_GPL(usb_enable_lpm);
+
+int usb_unlocked_disable_lpm(struct usb_device *udev)
+{
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_unlocked_disable_lpm);
+
+void usb_unlocked_enable_lpm(struct usb_device *udev) { }
+EXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm);
#endif
@@ -3208,9 +3864,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) {
retval = usb_get_bos_descriptor(udev);
if (!retval) {
- if (udev->bos->ext_cap && (USB_LPM_SUPPORT &
- le32_to_cpu(udev->bos->ext_cap->bmAttributes)))
- udev->lpm_capable = 1;
+ udev->lpm_capable = usb_device_supports_lpm(udev);
+ usb_set_lpm_parameters(udev);
}
}
@@ -4042,11 +4697,22 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
goto done;
mutex_lock(hcd->bandwidth_mutex);
+ /* Disable LPM while we reset the device and reinstall the alt settings.
+ * Device-initiated LPM settings, and system exit latency settings are
+ * cleared when the device is reset, so we have to set them up again.
+ */
+ ret = usb_disable_lpm(udev);
+ if (ret) {
+ dev_err(&udev->dev, "%s Failed to disable LPM\n.", __func__);
+ mutex_unlock(hcd->bandwidth_mutex);
+ goto done;
+ }
ret = usb_hcd_alloc_bandwidth(udev, udev->actconfig, NULL, NULL);
if (ret < 0) {
dev_warn(&udev->dev,
"Busted HC? Not enough HCD resources for "
"old configuration.\n");
+ usb_enable_lpm(udev);
mutex_unlock(hcd->bandwidth_mutex);
goto re_enumerate;
}
@@ -4058,6 +4724,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
dev_err(&udev->dev,
"can't restore configuration #%d (error=%d)\n",
udev->actconfig->desc.bConfigurationValue, ret);
+ usb_enable_lpm(udev);
mutex_unlock(hcd->bandwidth_mutex);
goto re_enumerate;
}
@@ -4096,10 +4763,13 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
desc->bInterfaceNumber,
desc->bAlternateSetting,
ret);
+ usb_unlocked_enable_lpm(udev);
goto re_enumerate;
}
}
+ /* Now that the alt settings are re-installed, enable LPM. */
+ usb_unlocked_enable_lpm(udev);
done:
return 0;
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
deleted file mode 100644
index d2b9af59cba9..000000000000
--- a/drivers/usb/core/inode.c
+++ /dev/null
@@ -1,748 +0,0 @@
-/*****************************************************************************/
-
-/*
- * inode.c -- Inode/Dentry functions for the USB device file system.
- *
- * Copyright (C) 2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
- * Copyright (C) 2001,2002,2004 Greg Kroah-Hartman (greg@kroah.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * History:
- * 0.1 04.01.2000 Created
- * 0.2 10.12.2001 converted to use the vfs layer better
- */
-
-/*****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/mount.h>
-#include <linux/pagemap.h>
-#include <linux/init.h>
-#include <linux/proc_fs.h>
-#include <linux/usb.h>
-#include <linux/namei.h>
-#include <linux/usbdevice_fs.h>
-#include <linux/parser.h>
-#include <linux/notifier.h>
-#include <linux/seq_file.h>
-#include <linux/usb/hcd.h>
-#include <asm/byteorder.h>
-#include "usb.h"
-
-#define USBFS_DEFAULT_DEVMODE (S_IWUSR | S_IRUGO)
-#define USBFS_DEFAULT_BUSMODE (S_IXUGO | S_IRUGO)
-#define USBFS_DEFAULT_LISTMODE S_IRUGO
-
-static const struct file_operations default_file_operations;
-static struct vfsmount *usbfs_mount;
-static int usbfs_mount_count; /* = 0 */
-
-static struct dentry *devices_usbfs_dentry;
-static int num_buses; /* = 0 */
-
-static uid_t devuid; /* = 0 */
-static uid_t busuid; /* = 0 */
-static uid_t listuid; /* = 0 */
-static gid_t devgid; /* = 0 */
-static gid_t busgid; /* = 0 */
-static gid_t listgid; /* = 0 */
-static umode_t devmode = USBFS_DEFAULT_DEVMODE;
-static umode_t busmode = USBFS_DEFAULT_BUSMODE;
-static umode_t listmode = USBFS_DEFAULT_LISTMODE;
-
-static int usbfs_show_options(struct seq_file *seq, struct dentry *root)
-{
- if (devuid != 0)
- seq_printf(seq, ",devuid=%u", devuid);
- if (devgid != 0)
- seq_printf(seq, ",devgid=%u", devgid);
- if (devmode != USBFS_DEFAULT_DEVMODE)
- seq_printf(seq, ",devmode=%o", devmode);
- if (busuid != 0)
- seq_printf(seq, ",busuid=%u", busuid);
- if (busgid != 0)
- seq_printf(seq, ",busgid=%u", busgid);
- if (busmode != USBFS_DEFAULT_BUSMODE)
- seq_printf(seq, ",busmode=%o", busmode);
- if (listuid != 0)
- seq_printf(seq, ",listuid=%u", listuid);
- if (listgid != 0)
- seq_printf(seq, ",listgid=%u", listgid);
- if (listmode != USBFS_DEFAULT_LISTMODE)
- seq_printf(seq, ",listmode=%o", listmode);
-
- return 0;
-}
-
-enum {
- Opt_devuid, Opt_devgid, Opt_devmode,
- Opt_busuid, Opt_busgid, Opt_busmode,
- Opt_listuid, Opt_listgid, Opt_listmode,
- Opt_err,
-};
-
-static const match_table_t tokens = {
- {Opt_devuid, "devuid=%u"},
- {Opt_devgid, "devgid=%u"},
- {Opt_devmode, "devmode=%o"},
- {Opt_busuid, "busuid=%u"},
- {Opt_busgid, "busgid=%u"},
- {Opt_busmode, "busmode=%o"},
- {Opt_listuid, "listuid=%u"},
- {Opt_listgid, "listgid=%u"},
- {Opt_listmode, "listmode=%o"},
- {Opt_err, NULL}
-};
-
-static int parse_options(struct super_block *s, char *data)
-{
- char *p;
- int option;
-
- /* (re)set to defaults. */
- devuid = 0;
- busuid = 0;
- listuid = 0;
- devgid = 0;
- busgid = 0;
- listgid = 0;
- devmode = USBFS_DEFAULT_DEVMODE;
- busmode = USBFS_DEFAULT_BUSMODE;
- listmode = USBFS_DEFAULT_LISTMODE;
-
- while ((p = strsep(&data, ",")) != NULL) {
- substring_t args[MAX_OPT_ARGS];
- int token;
- if (!*p)
- continue;
-
- token = match_token(p, tokens, args);
- switch (token) {
- case Opt_devuid:
- if (match_int(&args[0], &option))
- return -EINVAL;
- devuid = option;
- break;
- case Opt_devgid:
- if (match_int(&args[0], &option))
- return -EINVAL;
- devgid = option;
- break;
- case Opt_devmode:
- if (match_octal(&args[0], &option))
- return -EINVAL;
- devmode = option & S_IRWXUGO;
- break;
- case Opt_busuid:
- if (match_int(&args[0], &option))
- return -EINVAL;
- busuid = option;
- break;
- case Opt_busgid:
- if (match_int(&args[0], &option))
- return -EINVAL;
- busgid = option;
- break;
- case Opt_busmode:
- if (match_octal(&args[0], &option))
- return -EINVAL;
- busmode = option & S_IRWXUGO;
- break;
- case Opt_listuid:
- if (match_int(&args[0], &option))
- return -EINVAL;
- listuid = option;
- break;
- case Opt_listgid:
- if (match_int(&args[0], &option))
- return -EINVAL;
- listgid = option;
- break;
- case Opt_listmode:
- if (match_octal(&args[0], &option))
- return -EINVAL;
- listmode = option & S_IRWXUGO;
- break;
- default:
- printk(KERN_ERR "usbfs: unrecognised mount option "
- "\"%s\" or missing value\n", p);
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-static void update_special(struct dentry *special)
-{
- special->d_inode->i_uid = listuid;
- special->d_inode->i_gid = listgid;
- special->d_inode->i_mode = S_IFREG | listmode;
-}
-
-static void update_dev(struct dentry *dev)
-{
- dev->d_inode->i_uid = devuid;
- dev->d_inode->i_gid = devgid;
- dev->d_inode->i_mode = S_IFREG | devmode;
-}
-
-static void update_bus(struct dentry *bus)
-{
- struct dentry *dev = NULL;
-
- bus->d_inode->i_uid = busuid;
- bus->d_inode->i_gid = busgid;
- bus->d_inode->i_mode = S_IFDIR | busmode;
-
- mutex_lock(&bus->d_inode->i_mutex);
-
- list_for_each_entry(dev, &bus->d_subdirs, d_u.d_child)
- if (dev->d_inode)
- update_dev(dev);
-
- mutex_unlock(&bus->d_inode->i_mutex);
-}
-
-static void update_sb(struct super_block *sb)
-{
- struct dentry *root = sb->s_root;
- struct dentry *bus = NULL;
-
- if (!root)
- return;
-
- mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_PARENT);
-
- list_for_each_entry(bus, &root->d_subdirs, d_u.d_child) {
- if (bus->d_inode) {
- switch (S_IFMT & bus->d_inode->i_mode) {
- case S_IFDIR:
- update_bus(bus);
- break;
- case S_IFREG:
- update_special(bus);
- break;
- default:
- printk(KERN_WARNING "usbfs: Unknown node %s "
- "mode %x found on remount!\n",
- bus->d_name.name, bus->d_inode->i_mode);
- break;
- }
- }
- }
-
- mutex_unlock(&root->d_inode->i_mutex);
-}
-
-static int remount(struct super_block *sb, int *flags, char *data)
-{
- /* If this is not a real mount,
- * i.e. it's a simple_pin_fs from create_special_files,
- * then ignore it.
- */
- if (*flags & MS_KERNMOUNT)
- return 0;
-
- if (parse_options(sb, data)) {
- printk(KERN_WARNING "usbfs: mount parameter error.\n");
- return -EINVAL;
- }
-
- if (usbfs_mount)
- update_sb(usbfs_mount->mnt_sb);
-
- return 0;
-}
-
-static struct inode *usbfs_get_inode (struct super_block *sb, umode_t mode, dev_t dev)
-{
- struct inode *inode = new_inode(sb);
-
- if (inode) {
- inode->i_ino = get_next_ino();
- inode_init_owner(inode, NULL, mode);
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- switch (mode & S_IFMT) {
- default:
- init_special_inode(inode, mode, dev);
- break;
- case S_IFREG:
- inode->i_fop = &default_file_operations;
- break;
- case S_IFDIR:
- inode->i_op = &simple_dir_inode_operations;
- inode->i_fop = &simple_dir_operations;
-
- /* directory inodes start off with i_nlink == 2 (for "." entry) */
- inc_nlink(inode);
- break;
- }
- }
- return inode;
-}
-
-/* SMP-safe */
-static int usbfs_mknod (struct inode *dir, struct dentry *dentry, umode_t mode,
- dev_t dev)
-{
- struct inode *inode = usbfs_get_inode(dir->i_sb, mode, dev);
- int error = -EPERM;
-
- if (dentry->d_inode)
- return -EEXIST;
-
- if (inode) {
- d_instantiate(dentry, inode);
- dget(dentry);
- error = 0;
- }
- return error;
-}
-
-static int usbfs_mkdir (struct inode *dir, struct dentry *dentry, umode_t mode)
-{
- int res;
-
- mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
- res = usbfs_mknod (dir, dentry, mode, 0);
- if (!res)
- inc_nlink(dir);
- return res;
-}
-
-static int usbfs_create (struct inode *dir, struct dentry *dentry, umode_t mode)
-{
- mode = (mode & S_IALLUGO) | S_IFREG;
- return usbfs_mknod (dir, dentry, mode, 0);
-}
-
-static inline int usbfs_positive (struct dentry *dentry)
-{
- return dentry->d_inode && !d_unhashed(dentry);
-}
-
-static int usbfs_empty (struct dentry *dentry)
-{
- struct list_head *list;
-
- spin_lock(&dentry->d_lock);
- list_for_each(list, &dentry->d_subdirs) {
- struct dentry *de = list_entry(list, struct dentry, d_u.d_child);
-
- spin_lock_nested(&de->d_lock, DENTRY_D_LOCK_NESTED);
- if (usbfs_positive(de)) {
- spin_unlock(&de->d_lock);
- spin_unlock(&dentry->d_lock);
- return 0;
- }
- spin_unlock(&de->d_lock);
- }
- spin_unlock(&dentry->d_lock);
- return 1;
-}
-
-static int usbfs_unlink (struct inode *dir, struct dentry *dentry)
-{
- struct inode *inode = dentry->d_inode;
- mutex_lock(&inode->i_mutex);
- drop_nlink(dentry->d_inode);
- dput(dentry);
- mutex_unlock(&inode->i_mutex);
- d_delete(dentry);
- return 0;
-}
-
-static int usbfs_rmdir(struct inode *dir, struct dentry *dentry)
-{
- int error = -ENOTEMPTY;
- struct inode * inode = dentry->d_inode;
-
- mutex_lock(&inode->i_mutex);
- dentry_unhash(dentry);
- if (usbfs_empty(dentry)) {
- dont_mount(dentry);
- drop_nlink(dentry->d_inode);
- drop_nlink(dentry->d_inode);
- dput(dentry);
- inode->i_flags |= S_DEAD;
- drop_nlink(dir);
- error = 0;
- }
- mutex_unlock(&inode->i_mutex);
- if (!error)
- d_delete(dentry);
- return error;
-}
-
-
-/* default file operations */
-static ssize_t default_read_file (struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- return 0;
-}
-
-static ssize_t default_write_file (struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- return count;
-}
-
-static loff_t default_file_lseek (struct file *file, loff_t offset, int orig)
-{
- loff_t retval = -EINVAL;
-
- mutex_lock(&file->f_path.dentry->d_inode->i_mutex);
- switch(orig) {
- case 0:
- if (offset > 0) {
- file->f_pos = offset;
- retval = file->f_pos;
- }
- break;
- case 1:
- if ((offset + file->f_pos) > 0) {
- file->f_pos += offset;
- retval = file->f_pos;
- }
- break;
- default:
- break;
- }
- mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
- return retval;
-}
-
-static const struct file_operations default_file_operations = {
- .read = default_read_file,
- .write = default_write_file,
- .open = simple_open,
- .llseek = default_file_lseek,
-};
-
-static const struct super_operations usbfs_ops = {
- .statfs = simple_statfs,
- .drop_inode = generic_delete_inode,
- .remount_fs = remount,
- .show_options = usbfs_show_options,
-};
-
-static int usbfs_fill_super(struct super_block *sb, void *data, int silent)
-{
- struct inode *inode;
-
- sb->s_blocksize = PAGE_CACHE_SIZE;
- sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
- sb->s_magic = USBDEVICE_SUPER_MAGIC;
- sb->s_op = &usbfs_ops;
- sb->s_time_gran = 1;
- inode = usbfs_get_inode(sb, S_IFDIR | 0755, 0);
- sb->s_root = d_make_root(inode);
- if (!sb->s_root) {
- dbg("%s: could not get root dentry!",__func__);
- return -ENOMEM;
- }
- return 0;
-}
-
-/*
- * fs_create_by_name - create a file, given a name
- * @name: name of file
- * @mode: type of file
- * @parent: dentry of directory to create it in
- * @dentry: resulting dentry of file
- *
- * This function handles both regular files and directories.
- */
-static int fs_create_by_name (const char *name, umode_t mode,
- struct dentry *parent, struct dentry **dentry)
-{
- int error = 0;
-
- /* If the parent is not specified, we create it in the root.
- * We need the root dentry to do this, which is in the super
- * block. A pointer to that is in the struct vfsmount that we
- * have around.
- */
- if (!parent ) {
- if (usbfs_mount)
- parent = usbfs_mount->mnt_root;
- }
-
- if (!parent) {
- dbg("Ah! can not find a parent!");
- return -EFAULT;
- }
-
- *dentry = NULL;
- mutex_lock(&parent->d_inode->i_mutex);
- *dentry = lookup_one_len(name, parent, strlen(name));
- if (!IS_ERR(*dentry)) {
- if (S_ISDIR(mode))
- error = usbfs_mkdir (parent->d_inode, *dentry, mode);
- else
- error = usbfs_create (parent->d_inode, *dentry, mode);
- } else
- error = PTR_ERR(*dentry);
- mutex_unlock(&parent->d_inode->i_mutex);
-
- return error;
-}
-
-static struct dentry *fs_create_file (const char *name, umode_t mode,
- struct dentry *parent, void *data,
- const struct file_operations *fops,
- uid_t uid, gid_t gid)
-{
- struct dentry *dentry;
- int error;
-
- dbg("creating file '%s'",name);
-
- error = fs_create_by_name (name, mode, parent, &dentry);
- if (error) {
- dentry = NULL;
- } else {
- if (dentry->d_inode) {
- if (data)
- dentry->d_inode->i_private = data;
- if (fops)
- dentry->d_inode->i_fop = fops;
- dentry->d_inode->i_uid = uid;
- dentry->d_inode->i_gid = gid;
- }
- }
-
- return dentry;
-}
-
-static void fs_remove_file (struct dentry *dentry)
-{
- struct dentry *parent = dentry->d_parent;
-
- if (!parent || !parent->d_inode)
- return;
-
- mutex_lock_nested(&parent->d_inode->i_mutex, I_MUTEX_PARENT);
- if (usbfs_positive(dentry)) {
- if (dentry->d_inode) {
- if (S_ISDIR(dentry->d_inode->i_mode))
- usbfs_rmdir(parent->d_inode, dentry);
- else
- usbfs_unlink(parent->d_inode, dentry);
- dput(dentry);
- }
- }
- mutex_unlock(&parent->d_inode->i_mutex);
-}
-
-/* --------------------------------------------------------------------- */
-
-static struct dentry *usb_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
-{
- return mount_single(fs_type, flags, data, usbfs_fill_super);
-}
-
-static struct file_system_type usb_fs_type = {
- .owner = THIS_MODULE,
- .name = "usbfs",
- .mount = usb_mount,
- .kill_sb = kill_litter_super,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int create_special_files (void)
-{
- struct dentry *parent;
- int retval;
-
- /* create the devices special file */
- retval = simple_pin_fs(&usb_fs_type, &usbfs_mount, &usbfs_mount_count);
- if (retval) {
- printk(KERN_ERR "Unable to get usbfs mount\n");
- goto exit;
- }
-
- parent = usbfs_mount->mnt_root;
- devices_usbfs_dentry = fs_create_file ("devices",
- listmode | S_IFREG, parent,
- NULL, &usbfs_devices_fops,
- listuid, listgid);
- if (devices_usbfs_dentry == NULL) {
- printk(KERN_ERR "Unable to create devices usbfs file\n");
- retval = -ENODEV;
- goto error_clean_mounts;
- }
-
- goto exit;
-
-error_clean_mounts:
- simple_release_fs(&usbfs_mount, &usbfs_mount_count);
-exit:
- return retval;
-}
-
-static void remove_special_files (void)
-{
- if (devices_usbfs_dentry)
- fs_remove_file (devices_usbfs_dentry);
- devices_usbfs_dentry = NULL;
- simple_release_fs(&usbfs_mount, &usbfs_mount_count);
-}
-
-void usbfs_update_special (void)
-{
- struct inode *inode;
-
- if (devices_usbfs_dentry) {
- inode = devices_usbfs_dentry->d_inode;
- if (inode)
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- }
-}
-
-static void usbfs_add_bus(struct usb_bus *bus)
-{
- struct dentry *parent;
- char name[8];
- int retval;
-
- /* create the special files if this is the first bus added */
- if (num_buses == 0) {
- retval = create_special_files();
- if (retval)
- return;
- }
- ++num_buses;
-
- sprintf (name, "%03d", bus->busnum);
-
- parent = usbfs_mount->mnt_root;
- bus->usbfs_dentry = fs_create_file (name, busmode | S_IFDIR, parent,
- bus, NULL, busuid, busgid);
- if (bus->usbfs_dentry == NULL) {
- printk(KERN_ERR "Error creating usbfs bus entry\n");
- return;
- }
-}
-
-static void usbfs_remove_bus(struct usb_bus *bus)
-{
- if (bus->usbfs_dentry) {
- fs_remove_file (bus->usbfs_dentry);
- bus->usbfs_dentry = NULL;
- }
-
- --num_buses;
- if (num_buses <= 0) {
- remove_special_files();
- num_buses = 0;
- }
-}
-
-static void usbfs_add_device(struct usb_device *dev)
-{
- char name[8];
- int i;
- int i_size;
-
- sprintf (name, "%03d", dev->devnum);
- dev->usbfs_dentry = fs_create_file (name, devmode | S_IFREG,
- dev->bus->usbfs_dentry, dev,
- &usbdev_file_operations,
- devuid, devgid);
- if (dev->usbfs_dentry == NULL) {
- printk(KERN_ERR "Error creating usbfs device entry\n");
- return;
- }
-
- /* Set the size of the device's file to be
- * equal to the size of the device descriptors. */
- i_size = sizeof (struct usb_device_descriptor);
- for (i = 0; i < dev->descriptor.bNumConfigurations; ++i) {
- struct usb_config_descriptor *config =
- (struct usb_config_descriptor *)dev->rawdescriptors[i];
- i_size += le16_to_cpu(config->wTotalLength);
- }
- if (dev->usbfs_dentry->d_inode)
- dev->usbfs_dentry->d_inode->i_size = i_size;
-}
-
-static void usbfs_remove_device(struct usb_device *dev)
-{
- if (dev->usbfs_dentry) {
- fs_remove_file (dev->usbfs_dentry);
- dev->usbfs_dentry = NULL;
- }
-}
-
-static int usbfs_notify(struct notifier_block *self, unsigned long action, void *dev)
-{
- switch (action) {
- case USB_DEVICE_ADD:
- usbfs_add_device(dev);
- break;
- case USB_DEVICE_REMOVE:
- usbfs_remove_device(dev);
- break;
- case USB_BUS_ADD:
- usbfs_add_bus(dev);
- break;
- case USB_BUS_REMOVE:
- usbfs_remove_bus(dev);
- }
-
- usbfs_update_special();
- usbfs_conn_disc_event();
- return NOTIFY_OK;
-}
-
-static struct notifier_block usbfs_nb = {
- .notifier_call = usbfs_notify,
-};
-
-/* --------------------------------------------------------------------- */
-
-static struct proc_dir_entry *usbdir = NULL;
-
-int __init usbfs_init(void)
-{
- int retval;
-
- retval = register_filesystem(&usb_fs_type);
- if (retval)
- return retval;
-
- usb_register_notify(&usbfs_nb);
-
- /* create mount point for usbfs */
- usbdir = proc_mkdir("bus/usb", NULL);
-
- return 0;
-}
-
-void usbfs_cleanup(void)
-{
- usb_unregister_notify(&usbfs_nb);
- unregister_filesystem(&usb_fs_type);
- if (usbdir)
- remove_proc_entry("bus/usb", NULL);
-}
-
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index ca717da3be95..b548cf1dbc62 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1308,10 +1308,19 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
* Remove the current alt setting and add the new alt setting.
*/
mutex_lock(hcd->bandwidth_mutex);
+ /* Disable LPM, and re-enable it once the new alt setting is installed,
+ * so that the xHCI driver can recalculate the U1/U2 timeouts.
+ */
+ if (usb_disable_lpm(dev)) {
+ dev_err(&iface->dev, "%s Failed to disable LPM\n.", __func__);
+ mutex_unlock(hcd->bandwidth_mutex);
+ return -ENOMEM;
+ }
ret = usb_hcd_alloc_bandwidth(dev, NULL, iface->cur_altsetting, alt);
if (ret < 0) {
dev_info(&dev->dev, "Not enough bandwidth for altsetting %d\n",
alternate);
+ usb_enable_lpm(dev);
mutex_unlock(hcd->bandwidth_mutex);
return ret;
}
@@ -1334,6 +1343,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
} else if (ret < 0) {
/* Re-instate the old alt setting */
usb_hcd_alloc_bandwidth(dev, NULL, alt, iface->cur_altsetting);
+ usb_enable_lpm(dev);
mutex_unlock(hcd->bandwidth_mutex);
return ret;
}
@@ -1354,6 +1364,9 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
iface->cur_altsetting = alt;
+ /* Now that the interface is installed, re-enable LPM. */
+ usb_unlocked_enable_lpm(dev);
+
/* If the interface only has one altsetting and the device didn't
* accept the request, we attempt to carry out the equivalent action
* by manually clearing the HALT feature for each endpoint in the
@@ -1437,6 +1450,14 @@ int usb_reset_configuration(struct usb_device *dev)
config = dev->actconfig;
retval = 0;
mutex_lock(hcd->bandwidth_mutex);
+ /* Disable LPM, and re-enable it once the configuration is reset, so
+ * that the xHCI driver can recalculate the U1/U2 timeouts.
+ */
+ if (usb_disable_lpm(dev)) {
+ dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__);
+ mutex_unlock(hcd->bandwidth_mutex);
+ return -ENOMEM;
+ }
/* Make sure we have enough bandwidth for each alternate setting 0 */
for (i = 0; i < config->desc.bNumInterfaces; i++) {
struct usb_interface *intf = config->interface[i];
@@ -1465,6 +1486,7 @@ reset_old_alts:
usb_hcd_alloc_bandwidth(dev, NULL,
alt, intf->cur_altsetting);
}
+ usb_enable_lpm(dev);
mutex_unlock(hcd->bandwidth_mutex);
return retval;
}
@@ -1502,6 +1524,8 @@ reset_old_alts:
create_intf_ep_devs(intf);
}
}
+ /* Now that the interfaces are installed, re-enable LPM. */
+ usb_unlocked_enable_lpm(dev);
return 0;
}
EXPORT_SYMBOL_GPL(usb_reset_configuration);
@@ -1763,8 +1787,18 @@ free_interfaces:
* this call fails, the device state is unchanged.
*/
mutex_lock(hcd->bandwidth_mutex);
+ /* Disable LPM, and re-enable it once the new configuration is
+ * installed, so that the xHCI driver can recalculate the U1/U2
+ * timeouts.
+ */
+ if (usb_disable_lpm(dev)) {
+ dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__);
+ mutex_unlock(hcd->bandwidth_mutex);
+ return -ENOMEM;
+ }
ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);
if (ret < 0) {
+ usb_enable_lpm(dev);
mutex_unlock(hcd->bandwidth_mutex);
usb_autosuspend_device(dev);
goto free_interfaces;
@@ -1784,6 +1818,7 @@ free_interfaces:
if (!cp) {
usb_set_device_state(dev, USB_STATE_ADDRESS);
usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
+ usb_enable_lpm(dev);
mutex_unlock(hcd->bandwidth_mutex);
usb_autosuspend_device(dev);
goto free_interfaces;
@@ -1838,6 +1873,9 @@ free_interfaces:
!(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS))
cp->string = usb_cache_string(dev, cp->desc.iConfiguration);
+ /* Now that the interfaces are installed, re-enable LPM. */
+ usb_unlocked_enable_lpm(dev);
+
/* Now that all the interfaces are set up, register them
* to trigger binding of drivers to interfaces. probe()
* routines may install different altsettings and may
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 4c65eb6a867a..32d3adc315f5 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -123,6 +123,9 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Guillemot Webcam Hercules Dualpix Exchange*/
{ USB_DEVICE(0x06f8, 0x3005), .driver_info = USB_QUIRK_RESET_RESUME },
+ /* Midiman M-Audio Keystation 88es */
+ { USB_DEVICE(0x0763, 0x0192), .driver_info = USB_QUIRK_RESET_RESUME },
+
/* M-Systems Flash Disk Pioneers */
{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 566d9f94f735..9a56e3adf476 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -73,7 +73,7 @@ set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
return (value < 0) ? value : count;
}
-static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR,
+static DEVICE_ATTR_IGNORE_LOCKDEP(bConfigurationValue, S_IRUGO | S_IWUSR,
show_bConfigurationValue, set_bConfigurationValue);
/* String fields */
@@ -595,7 +595,7 @@ static ssize_t usb_dev_authorized_store(struct device *dev,
return result < 0? result : size;
}
-static DEVICE_ATTR(authorized, 0644,
+static DEVICE_ATTR_IGNORE_LOCKDEP(authorized, 0644,
usb_dev_authorized_show, usb_dev_authorized_store);
/* "Safely remove a device" */
@@ -618,7 +618,7 @@ static ssize_t usb_remove_store(struct device *dev,
usb_unlock_device(udev);
return rc;
}
-static DEVICE_ATTR(remove, 0200, NULL, usb_remove_store);
+static DEVICE_ATTR_IGNORE_LOCKDEP(remove, 0200, NULL, usb_remove_store);
static struct attribute *dev_attrs[] = {
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index cd9b3a2cd8a7..9d912bfdcffe 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -681,6 +681,27 @@ void usb_unpoison_urb(struct urb *urb)
EXPORT_SYMBOL_GPL(usb_unpoison_urb);
/**
+ * usb_block_urb - reliably prevent further use of an URB
+ * @urb: pointer to URB to be blocked, may be NULL
+ *
+ * After the routine has run, attempts to resubmit the URB will fail
+ * with error -EPERM. Thus even if the URB's completion handler always
+ * tries to resubmit, it will not succeed and the URB will become idle.
+ *
+ * The URB must not be deallocated while this routine is running. In
+ * particular, when a driver calls this routine, it must insure that the
+ * completion handler cannot deallocate the URB.
+ */
+void usb_block_urb(struct urb *urb)
+{
+ if (!urb)
+ return;
+
+ atomic_inc(&urb->reject);
+}
+EXPORT_SYMBOL_GPL(usb_block_urb);
+
+/**
* usb_kill_anchored_urbs - cancel transfer requests en masse
* @anchor: anchor the requests are bound to
*
diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c
new file mode 100644
index 000000000000..8947b203d5a4
--- /dev/null
+++ b/drivers/usb/core/usb-acpi.c
@@ -0,0 +1,117 @@
+/*
+ * USB-ACPI glue code
+ *
+ * Copyright 2012 Red Hat <mjg@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ *
+ */
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <linux/pci.h>
+#include <acpi/acpi_bus.h>
+
+#include "usb.h"
+
+static int usb_acpi_check_upc(struct usb_device *udev, acpi_handle handle)
+{
+ acpi_status status;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *upc;
+ int ret = 0;
+
+ status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer);
+
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ upc = buffer.pointer;
+
+ if (!upc || (upc->type != ACPI_TYPE_PACKAGE)
+ || upc->package.count != 4) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (upc->package.elements[0].integer.value)
+ udev->removable = USB_DEVICE_REMOVABLE;
+ else
+ udev->removable = USB_DEVICE_FIXED;
+
+out:
+ kfree(upc);
+ return ret;
+}
+
+static int usb_acpi_check_pld(struct usb_device *udev, acpi_handle handle)
+{
+ acpi_status status;
+ struct acpi_pld pld;
+
+ status = acpi_get_physical_device_location(handle, &pld);
+
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ if (pld.user_visible)
+ udev->removable = USB_DEVICE_REMOVABLE;
+ else
+ udev->removable = USB_DEVICE_FIXED;
+
+ return 0;
+}
+
+static int usb_acpi_find_device(struct device *dev, acpi_handle *handle)
+{
+ struct usb_device *udev;
+ struct device *parent;
+ acpi_handle *parent_handle;
+
+ if (!is_usb_device(dev))
+ return -ENODEV;
+
+ udev = to_usb_device(dev);
+ parent = dev->parent;
+ parent_handle = DEVICE_ACPI_HANDLE(parent);
+
+ if (!parent_handle)
+ return -ENODEV;
+
+ *handle = acpi_get_child(parent_handle, udev->portnum);
+
+ if (!*handle)
+ return -ENODEV;
+
+ /*
+ * PLD will tell us whether a port is removable to the user or
+ * not. If we don't get an answer from PLD (it's not present
+ * or it's malformed) then try to infer it from UPC. If a
+ * device isn't connectable then it's probably not removable.
+ */
+ if (usb_acpi_check_pld(udev, *handle) != 0)
+ usb_acpi_check_upc(udev, *handle);
+
+ return 0;
+}
+
+static struct acpi_bus_type usb_acpi_bus = {
+ .bus = &usb_bus_type,
+ .find_bridge = NULL,
+ .find_device = usb_acpi_find_device,
+};
+
+int usb_acpi_register(void)
+{
+ return register_acpi_bus_type(&usb_acpi_bus);
+}
+
+void usb_acpi_unregister(void)
+{
+ unregister_acpi_bus_type(&usb_acpi_bus);
+}
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index c74ba7bbc748..25d0c61c3f8a 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -1015,6 +1015,7 @@ static int __init usb_init(void)
if (retval)
goto out;
+ usb_acpi_register();
retval = bus_register(&usb_bus_type);
if (retval)
goto bus_register_failed;
@@ -1030,9 +1031,6 @@ static int __init usb_init(void)
retval = usb_devio_init();
if (retval)
goto usb_devio_init_failed;
- retval = usbfs_init();
- if (retval)
- goto fs_init_failed;
retval = usb_hub_init();
if (retval)
goto hub_init_failed;
@@ -1042,8 +1040,6 @@ static int __init usb_init(void)
usb_hub_cleanup();
hub_init_failed:
- usbfs_cleanup();
-fs_init_failed:
usb_devio_cleanup();
usb_devio_init_failed:
usb_deregister(&usbfs_driver);
@@ -1054,6 +1050,7 @@ major_init_failed:
bus_notifier_failed:
bus_unregister(&usb_bus_type);
bus_register_failed:
+ usb_acpi_unregister();
usb_debugfs_cleanup();
out:
return retval;
@@ -1070,12 +1067,12 @@ static void __exit usb_exit(void)
usb_deregister_device_driver(&usb_generic_driver);
usb_major_cleanup();
- usbfs_cleanup();
usb_deregister(&usbfs_driver);
usb_devio_cleanup();
usb_hub_cleanup();
bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
bus_unregister(&usb_bus_type);
+ usb_acpi_unregister();
usb_debugfs_cleanup();
}
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 71648dcbe438..5c5c538ea73d 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -156,3 +156,10 @@ extern void usb_notify_remove_device(struct usb_device *udev);
extern void usb_notify_add_bus(struct usb_bus *ubus);
extern void usb_notify_remove_bus(struct usb_bus *ubus);
+#ifdef CONFIG_ACPI
+extern int usb_acpi_register(void);
+extern void usb_acpi_unregister(void);
+#else
+static inline int usb_acpi_register(void) { return 0; };
+static inline void usb_acpi_unregister(void) { };
+#endif
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index d8f741f9e56e..d13c60f42139 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -4,7 +4,7 @@ config USB_DWC3
select USB_OTG_UTILS
select USB_GADGET_DUALSPEED
select USB_GADGET_SUPERSPEED
- select USB_XHCI_PLATFORM
+ select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD
help
Say Y or M here if your system has a Dual Role SuperSpeed
USB controller based on the DesignWare USB3 IP Core.
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 99b58d84553a..1040bdb8dc88 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -410,7 +410,6 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
int ret = -ENOMEM;
- int irq;
void __iomem *regs;
void *mem;
@@ -425,15 +424,28 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
dwc->mem = mem;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
- dev_err(dev, "missing resource\n");
+ dev_err(dev, "missing IRQ\n");
return -ENODEV;
}
+ dwc->xhci_resources[1] = *res;
- dwc->res = res;
-
- res = devm_request_mem_region(dev, res->start, resource_size(res),
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "missing memory resource\n");
+ return -ENODEV;
+ }
+ dwc->xhci_resources[0] = *res;
+ dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
+ DWC3_XHCI_REGS_END;
+
+ /*
+ * Request memory region but exclude xHCI regs,
+ * since it will be requested by the xhci-plat driver.
+ */
+ res = devm_request_mem_region(dev, res->start + DWC3_GLOBALS_REGS_START,
+ resource_size(res) - DWC3_GLOBALS_REGS_START,
dev_name(dev));
if (!res) {
dev_err(dev, "can't request mem region\n");
@@ -446,19 +458,12 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
return -ENOMEM;
}
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(dev, "missing IRQ\n");
- return -ENODEV;
- }
-
spin_lock_init(&dwc->lock);
platform_set_drvdata(pdev, dwc);
dwc->regs = regs;
dwc->regs_size = resource_size(res);
dwc->dev = dev;
- dwc->irq = irq;
if (!strncmp("super", maximum_speed, 5))
dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 6c7945b4cad3..f69c877add09 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -51,7 +51,9 @@
#include <linux/usb/gadget.h>
/* Global constants */
+#define DWC3_EP0_BOUNCE_SIZE 512
#define DWC3_ENDPOINTS_NUM 32
+#define DWC3_XHCI_RESOURCES_NUM 2
#define DWC3_EVENT_BUFFERS_SIZE PAGE_SIZE
#define DWC3_EVENT_TYPE_MASK 0xfe
@@ -75,6 +77,16 @@
#define DWC3_GSNPSID_MASK 0xffff0000
#define DWC3_GSNPSREV_MASK 0xffff
+/* DWC3 registers memory space boundries */
+#define DWC3_XHCI_REGS_START 0x0
+#define DWC3_XHCI_REGS_END 0x7fff
+#define DWC3_GLOBALS_REGS_START 0xc100
+#define DWC3_GLOBALS_REGS_END 0xc6ff
+#define DWC3_DEVICE_REGS_START 0xc700
+#define DWC3_DEVICE_REGS_END 0xcbff
+#define DWC3_OTG_REGS_START 0xcc00
+#define DWC3_OTG_REGS_END 0xccff
+
/* Global Registers */
#define DWC3_GSBUSCFG0 0xc100
#define DWC3_GSBUSCFG1 0xc104
@@ -183,6 +195,7 @@
#define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1
/* Device Configuration Register */
+#define DWC3_DCFG_LPM_CAP (1 << 22)
#define DWC3_DCFG_DEVADDR(addr) ((addr) << 3)
#define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f)
@@ -272,12 +285,14 @@
#define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c
#define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK 0x10
+#define DWC3_DGCMD_STATUS(n) (((n) >> 15) & 1)
+#define DWC3_DGCMD_CMDACT (1 << 10)
+
/* Device Endpoint Command Register */
#define DWC3_DEPCMD_PARAM_SHIFT 16
#define DWC3_DEPCMD_PARAM(x) ((x) << DWC3_DEPCMD_PARAM_SHIFT)
#define DWC3_DEPCMD_GET_RSC_IDX(x) (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
-#define DWC3_DEPCMD_STATUS_MASK (0x0f << 12)
-#define DWC3_DEPCMD_STATUS(x) (((x) & DWC3_DEPCMD_STATUS_MASK) >> 12)
+#define DWC3_DEPCMD_STATUS(x) (((x) >> 15) & 1)
#define DWC3_DEPCMD_HIPRI_FORCERM (1 << 11)
#define DWC3_DEPCMD_CMDACT (1 << 10)
#define DWC3_DEPCMD_CMDIOC (1 << 8)
@@ -361,7 +376,6 @@ struct dwc3_ep {
dma_addr_t trb_pool_dma;
u32 free_slot;
u32 busy_slot;
- const struct usb_endpoint_descriptor *desc;
const struct usb_ss_ep_comp_descriptor *comp_desc;
struct dwc3 *dwc;
@@ -561,6 +575,11 @@ struct dwc3_request {
* @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
* @needs_fifo_resize: not all users might want fifo resizing, flag it
* @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.
+ * @isoch_delay: wValue from Set Isochronous Delay request;
+ * @u2sel: parameter from Set SEL request.
+ * @u2pel: parameter from Set SEL request.
+ * @u1sel: parameter from Set SEL request.
+ * @u1pel: parameter from Set SEL request.
* @ep0_next_event: hold the next expected event
* @ep0state: state of endpoint zero
* @link_state: link state
@@ -583,7 +602,7 @@ struct dwc3 {
struct device *dev;
struct platform_device *xhci;
- struct resource *res;
+ struct resource xhci_resources[DWC3_XHCI_RESOURCES_NUM];
struct dwc3_event_buffer **ev_buffs;
struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM];
@@ -594,8 +613,6 @@ struct dwc3 {
void __iomem *regs;
size_t regs_size;
- int irq;
-
u32 num_event_buffers;
u32 u1u2;
u32 maximum_speed;
@@ -609,6 +626,10 @@ struct dwc3 {
#define DWC3_REVISION_185A 0x5533185a
#define DWC3_REVISION_188A 0x5533188a
#define DWC3_REVISION_190A 0x5533190a
+#define DWC3_REVISION_200A 0x5533200a
+#define DWC3_REVISION_202A 0x5533202a
+#define DWC3_REVISION_210A 0x5533210a
+#define DWC3_REVISION_220A 0x5533220a
unsigned is_selfpowered:1;
unsigned three_stage_setup:1;
@@ -625,7 +646,14 @@ struct dwc3 {
enum dwc3_link_state link_state;
enum dwc3_device_state dev_state;
+ u16 isoch_delay;
+ u16 u2sel;
+ u16 u2pel;
+ u8 u1sel;
+ u8 u1pel;
+
u8 speed;
+
void *mem;
struct dwc3_hwparams hwparams;
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index d7d9c0ec9515..479dc047da3a 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -49,7 +49,6 @@
#include <linux/of.h>
#include "core.h"
-#include "io.h"
/*
* All these registers belong to OMAP's Wrapper around the
@@ -143,6 +142,17 @@ struct dwc3_omap {
u32 dma_status:1;
};
+static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset)
+{
+ return readl(base + offset);
+}
+
+static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value)
+{
+ writel(value, base + offset);
+}
+
+
static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
{
struct dwc3_omap *omap = _omap;
@@ -150,7 +160,7 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
spin_lock(&omap->lock);
- reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_1);
+ reg = dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_1);
if (reg & USBOTGSS_IRQ1_DMADISABLECLR) {
dev_dbg(omap->dev, "DMA Disable was Cleared\n");
@@ -184,10 +194,10 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
if (reg & USBOTGSS_IRQ1_IDPULLUP_FALL)
dev_dbg(omap->dev, "IDPULLUP Fall\n");
- dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg);
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg);
- reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_0);
- dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg);
+ reg = dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_0);
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg);
spin_unlock(&omap->lock);
@@ -270,7 +280,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
omap->base = base;
omap->dwc3 = dwc3;
- reg = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
+ reg = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
utmi_mode = of_get_property(node, "utmi-mode", &size);
if (utmi_mode && size == sizeof(*utmi_mode)) {
@@ -293,10 +303,10 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
}
}
- dwc3_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
+ dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
/* check the DMA Status */
- reg = dwc3_readl(omap->base, USBOTGSS_SYSCONFIG);
+ reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
/* Set No-Idle and No-Standby */
@@ -306,7 +316,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
reg |= (USBOTGSS_SYSCONFIG_STANDBYMODE(USBOTGSS_STANDBYMODE_NO_STANDBY)
| USBOTGSS_SYSCONFIG_IDLEMODE(USBOTGSS_IDLEMODE_NO_IDLE));
- dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
+ dwc3_omap_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
"dwc3-omap", omap);
@@ -318,7 +328,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
/* enable all IRQs */
reg = USBOTGSS_IRQO_COREIRQ_ST;
- dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
reg = (USBOTGSS_IRQ1_OEVT |
USBOTGSS_IRQ1_DRVVBUS_RISE |
@@ -330,7 +340,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
USBOTGSS_IRQ1_DISCHRGVBUS_FALL |
USBOTGSS_IRQ1_IDPULLUP_FALL);
- dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
ret = platform_device_add_resources(dwc3, pdev->resource,
pdev->num_resources);
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 3584a169886f..9e8a3dce69fd 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -179,7 +179,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
int ret;
spin_lock_irqsave(&dwc->lock, flags);
- if (!dep->desc) {
+ if (!dep->endpoint.desc) {
dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
request, dep->name);
ret = -ESHUTDOWN;
@@ -261,6 +261,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
{
struct dwc3_ep *dep;
u32 recip;
+ u32 reg;
u16 usb_status = 0;
__le16 *response_pkt;
@@ -268,10 +269,18 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
switch (recip) {
case USB_RECIP_DEVICE:
/*
- * We are self-powered. U1/U2/LTM will be set later
- * once we handle this states. RemoteWakeup is 0 on SS
+ * LTM will be set once we know how to set this in HW.
*/
usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED;
+
+ if (dwc->speed == DWC3_DSTS_SUPERSPEED) {
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ if (reg & DWC3_DCTL_INITU1ENA)
+ usb_status |= 1 << USB_DEV_STAT_U1_ENABLED;
+ if (reg & DWC3_DCTL_INITU2ENA)
+ usb_status |= 1 << USB_DEV_STAT_U2_ENABLED;
+ }
+
break;
case USB_RECIP_INTERFACE:
@@ -312,6 +321,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
u32 recip;
u32 wValue;
u32 wIndex;
+ u32 reg;
int ret;
wValue = le16_to_cpu(ctrl->wValue);
@@ -320,29 +330,43 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
switch (recip) {
case USB_RECIP_DEVICE:
+ switch (wValue) {
+ case USB_DEVICE_REMOTE_WAKEUP:
+ break;
/*
* 9.4.1 says only only for SS, in AddressState only for
* default control pipe
*/
- switch (wValue) {
case USB_DEVICE_U1_ENABLE:
- case USB_DEVICE_U2_ENABLE:
- case USB_DEVICE_LTM_ENABLE:
if (dwc->dev_state != DWC3_CONFIGURED_STATE)
return -EINVAL;
if (dwc->speed != DWC3_DSTS_SUPERSPEED)
return -EINVAL;
- }
- /* XXX add U[12] & LTM */
- switch (wValue) {
- case USB_DEVICE_REMOTE_WAKEUP:
- break;
- case USB_DEVICE_U1_ENABLE:
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ if (set)
+ reg |= DWC3_DCTL_INITU1ENA;
+ else
+ reg &= ~DWC3_DCTL_INITU1ENA;
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
break;
+
case USB_DEVICE_U2_ENABLE:
+ if (dwc->dev_state != DWC3_CONFIGURED_STATE)
+ return -EINVAL;
+ if (dwc->speed != DWC3_DSTS_SUPERSPEED)
+ return -EINVAL;
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ if (set)
+ reg |= DWC3_DCTL_INITU2ENA;
+ else
+ reg &= ~DWC3_DCTL_INITU2ENA;
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
break;
+
case USB_DEVICE_LTM_ENABLE:
+ return -EINVAL;
break;
case USB_DEVICE_TEST_MODE:
@@ -469,6 +493,107 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
return ret;
}
+static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req)
+{
+ struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
+
+ u32 param = 0;
+ u32 reg;
+
+ struct timing {
+ u8 u1sel;
+ u8 u1pel;
+ u16 u2sel;
+ u16 u2pel;
+ } __packed timing;
+
+ int ret;
+
+ memcpy(&timing, req->buf, sizeof(timing));
+
+ dwc->u1sel = timing.u1sel;
+ dwc->u1pel = timing.u1pel;
+ dwc->u2sel = timing.u2sel;
+ dwc->u2pel = timing.u2pel;
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ if (reg & DWC3_DCTL_INITU2ENA)
+ param = dwc->u2pel;
+ if (reg & DWC3_DCTL_INITU1ENA)
+ param = dwc->u1pel;
+
+ /*
+ * According to Synopsys Databook, if parameter is
+ * greater than 125, a value of zero should be
+ * programmed in the register.
+ */
+ if (param > 125)
+ param = 0;
+
+ /* now that we have the time, issue DGCMD Set Sel */
+ ret = dwc3_send_gadget_generic_command(dwc,
+ DWC3_DGCMD_SET_PERIODIC_PAR, param);
+ WARN_ON(ret < 0);
+}
+
+static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+ struct dwc3_ep *dep;
+ u16 wLength;
+ u16 wValue;
+
+ if (dwc->dev_state == DWC3_DEFAULT_STATE)
+ return -EINVAL;
+
+ wValue = le16_to_cpu(ctrl->wValue);
+ wLength = le16_to_cpu(ctrl->wLength);
+
+ if (wLength != 6) {
+ dev_err(dwc->dev, "Set SEL should be 6 bytes, got %d\n",
+ wLength);
+ return -EINVAL;
+ }
+
+ /*
+ * To handle Set SEL we need to receive 6 bytes from Host. So let's
+ * queue a usb_request for 6 bytes.
+ *
+ * Remember, though, this controller can't handle non-wMaxPacketSize
+ * aligned transfers on the OUT direction, so we queue a request for
+ * wMaxPacketSize instead.
+ */
+ dep = dwc->eps[0];
+ dwc->ep0_usb_req.dep = dep;
+ dwc->ep0_usb_req.request.length = dep->endpoint.maxpacket;
+ dwc->ep0_usb_req.request.buf = dwc->setup_buf;
+ dwc->ep0_usb_req.request.complete = dwc3_ep0_set_sel_cmpl;
+
+ return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req);
+}
+
+static int dwc3_ep0_set_isoch_delay(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+ u16 wLength;
+ u16 wValue;
+ u16 wIndex;
+
+ wValue = le16_to_cpu(ctrl->wValue);
+ wLength = le16_to_cpu(ctrl->wLength);
+ wIndex = le16_to_cpu(ctrl->wIndex);
+
+ if (wIndex || wLength)
+ return -EINVAL;
+
+ /*
+ * REVISIT It's unclear from Databook what to do with this
+ * value. For now, just cache it.
+ */
+ dwc->isoch_delay = wValue;
+
+ return 0;
+}
+
static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
{
int ret;
@@ -494,6 +619,14 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
dev_vdbg(dwc->dev, "USB_REQ_SET_CONFIGURATION\n");
ret = dwc3_ep0_set_config(dwc, ctrl);
break;
+ case USB_REQ_SET_SEL:
+ dev_vdbg(dwc->dev, "USB_REQ_SET_SEL\n");
+ ret = dwc3_ep0_set_sel(dwc, ctrl);
+ break;
+ case USB_REQ_SET_ISOCH_DELAY:
+ dev_vdbg(dwc->dev, "USB_REQ_SET_ISOCH_DELAY\n");
+ ret = dwc3_ep0_set_isoch_delay(dwc, ctrl);
+ break;
default:
dev_vdbg(dwc->dev, "Forwarding to gadget driver\n");
ret = dwc3_ep0_delegate_req(dwc, ctrl);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 5255fe975ea1..3df1a1973b05 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -178,8 +178,8 @@ int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
if (!(dep->flags & DWC3_EP_ENABLED))
continue;
- if (usb_endpoint_xfer_bulk(dep->desc)
- || usb_endpoint_xfer_isoc(dep->desc))
+ if (usb_endpoint_xfer_bulk(dep->endpoint.desc)
+ || usb_endpoint_xfer_isoc(dep->endpoint.desc))
mult = 3;
/*
@@ -229,7 +229,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
* completed (not the LINK TRB).
*/
if (((dep->busy_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
- usb_endpoint_xfer_isoc(dep->desc))
+ usb_endpoint_xfer_isoc(dep->endpoint.desc))
dep->busy_slot++;
}
list_del(&req->list);
@@ -276,6 +276,33 @@ static const char *dwc3_gadget_ep_cmd_string(u8 cmd)
}
}
+int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param)
+{
+ u32 timeout = 500;
+ u32 reg;
+
+ dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param);
+ dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT);
+
+ do {
+ reg = dwc3_readl(dwc->regs, DWC3_DGCMD);
+ if (!(reg & DWC3_DGCMD_CMDACT)) {
+ dev_vdbg(dwc->dev, "Command Complete --> %d\n",
+ DWC3_DGCMD_STATUS(reg));
+ return 0;
+ }
+
+ /*
+ * We can't sleep here, because it's also called from
+ * interrupt context.
+ */
+ timeout--;
+ if (!timeout)
+ return -ETIMEDOUT;
+ udelay(1);
+ } while (1);
+}
+
int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
{
@@ -470,7 +497,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
if (ret)
return ret;
- dep->desc = desc;
+ dep->endpoint.desc = desc;
dep->comp_desc = comp_desc;
dep->type = usb_endpoint_type(desc);
dep->flags |= DWC3_EP_ENABLED;
@@ -533,7 +560,6 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
dep->stream_capable = false;
- dep->desc = NULL;
dep->endpoint.desc = NULL;
dep->comp_desc = NULL;
dep->type = 0;
@@ -694,7 +720,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
/* Skip the LINK-TRB on ISOC */
if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
- usb_endpoint_xfer_isoc(dep->desc))
+ usb_endpoint_xfer_isoc(dep->endpoint.desc))
return;
if (!req->trb) {
@@ -707,7 +733,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
trb->bpl = lower_32_bits(dma);
trb->bph = upper_32_bits(dma);
- switch (usb_endpoint_type(dep->desc)) {
+ switch (usb_endpoint_type(dep->endpoint.desc)) {
case USB_ENDPOINT_XFER_CONTROL:
trb->ctrl = DWC3_TRBCTL_CONTROL_SETUP;
break;
@@ -732,7 +758,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
BUG();
}
- if (usb_endpoint_xfer_isoc(dep->desc)) {
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
trb->ctrl |= DWC3_TRB_CTRL_CSP;
} else {
@@ -743,7 +769,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
trb->ctrl |= DWC3_TRB_CTRL_LST;
}
- if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
+ if (usb_endpoint_xfer_bulk(dep->endpoint.desc) && dep->stream_capable)
trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id);
trb->ctrl |= DWC3_TRB_CTRL_HWO;
@@ -771,7 +797,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
/* Can't wrap around on a non-isoc EP since there's no link TRB */
- if (!usb_endpoint_xfer_isoc(dep->desc)) {
+ if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
max = DWC3_TRB_NUM - (dep->free_slot & DWC3_TRB_MASK);
if (trbs_left > max)
trbs_left = max;
@@ -797,7 +823,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
* processed from the first TRB until the last one. Since we
* don't wrap around we have to start at the beginning.
*/
- if (usb_endpoint_xfer_isoc(dep->desc)) {
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
dep->busy_slot = 1;
dep->free_slot = 1;
} else {
@@ -807,7 +833,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
}
/* The last TRB is a link TRB, not used for xfer */
- if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->desc))
+ if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->endpoint.desc))
return;
list_for_each_entry_safe(req, n, &dep->request_list, list) {
@@ -930,10 +956,12 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
}
dep->flags |= DWC3_EP_BUSY;
- dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
- dep->number);
- WARN_ON_ONCE(!dep->res_trans_idx);
+ if (start_new) {
+ dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
+ dep->number);
+ WARN_ON_ONCE(!dep->res_trans_idx);
+ }
return 0;
}
@@ -967,28 +995,37 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
list_add_tail(&req->list, &dep->request_list);
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && (dep->flags & DWC3_EP_BUSY))
+ dep->flags |= DWC3_EP_PENDING_REQUEST;
+
/*
- * There is one special case: XferNotReady with
- * empty list of requests. We need to kick the
- * transfer here in that situation, otherwise
- * we will be NAKing forever.
+ * There are two special cases:
+ *
+ * 1. XferNotReady with empty list of requests. We need to kick the
+ * transfer here in that situation, otherwise we will be NAKing
+ * forever. If we get XferNotReady before gadget driver has a
+ * chance to queue a request, we will ACK the IRQ but won't be
+ * able to receive the data until the next request is queued.
+ * The following code is handling exactly that.
*
- * If we get XferNotReady before gadget driver
- * has a chance to queue a request, we will ACK
- * the IRQ but won't be able to receive the data
- * until the next request is queued. The following
- * code is handling exactly that.
+ * 2. XferInProgress on Isoc EP with an active transfer. We need to
+ * kick the transfer here after queuing a request, otherwise the
+ * core may not see the modified TRB(s).
*/
if (dep->flags & DWC3_EP_PENDING_REQUEST) {
- int ret;
- int start_trans;
+ int ret;
+ int start_trans = 1;
+ u8 trans_idx = dep->res_trans_idx;
- start_trans = 1;
- if (usb_endpoint_xfer_isoc(dep->desc) &&
- (dep->flags & DWC3_EP_BUSY))
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+ (dep->flags & DWC3_EP_BUSY)) {
start_trans = 0;
+ WARN_ON_ONCE(!trans_idx);
+ } else {
+ trans_idx = 0;
+ }
- ret = __dwc3_gadget_kick_transfer(dep, 0, start_trans);
+ ret = __dwc3_gadget_kick_transfer(dep, trans_idx, start_trans);
if (ret && ret != -EBUSY) {
struct dwc3 *dwc = dep->dwc;
@@ -1011,7 +1048,7 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
int ret;
- if (!dep->desc) {
+ if (!dep->endpoint.desc) {
dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
request, ep->name);
return -ESHUTDOWN;
@@ -1125,7 +1162,7 @@ static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value)
spin_lock_irqsave(&dwc->lock, flags);
- if (usb_endpoint_xfer_isoc(dep->desc)) {
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name);
ret = -EINVAL;
goto out;
@@ -1356,7 +1393,24 @@ static int dwc3_gadget_start(struct usb_gadget *g,
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg &= ~(DWC3_DCFG_SPEED_MASK);
- reg |= dwc->maximum_speed;
+
+ /**
+ * WORKAROUND: DWC3 revision < 2.20a have an issue
+ * which would cause metastability state on Run/Stop
+ * bit if we try to force the IP to USB2-only mode.
+ *
+ * Because of that, we cannot configure the IP to any
+ * speed other than the SuperSpeed
+ *
+ * Refers to:
+ *
+ * STAR#9000525659: Clock Domain Crossing on DCTL in
+ * USB 2.0 Mode
+ */
+ if (dwc->revision < DWC3_REVISION_220A)
+ reg |= DWC3_DCFG_SUPERSPEED;
+ else
+ reg |= dwc->maximum_speed;
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
dwc->start_config_issued = false;
@@ -1681,7 +1735,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
case DWC3_DEPEVT_XFERCOMPLETE:
dep->res_trans_idx = 0;
- if (usb_endpoint_xfer_isoc(dep->desc)) {
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n",
dep->name);
return;
@@ -1690,7 +1744,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
dwc3_endpoint_transfer_complete(dwc, dep, event, 1);
break;
case DWC3_DEPEVT_XFERINPROGRESS:
- if (!usb_endpoint_xfer_isoc(dep->desc)) {
+ if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
dev_dbg(dwc->dev, "%s is not an Isochronous endpoint\n",
dep->name);
return;
@@ -1699,7 +1753,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
dwc3_endpoint_transfer_complete(dwc, dep, event, 0);
break;
case DWC3_DEPEVT_XFERNOTREADY:
- if (usb_endpoint_xfer_isoc(dep->desc)) {
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
dwc3_gadget_start_isoc(dwc, dep, event);
} else {
int ret;
@@ -1720,7 +1774,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
break;
case DWC3_DEPEVT_STREAMEVT:
- if (!usb_endpoint_xfer_bulk(dep->desc)) {
+ if (!usb_endpoint_xfer_bulk(dep->endpoint.desc)) {
dev_err(dwc->dev, "Stream event for non-Bulk %s\n",
dep->name);
return;
@@ -1916,6 +1970,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_TSTCTRL_MASK;
+ reg &= ~(DWC3_DCTL_INITU1ENA | DWC3_DCTL_INITU2ENA);
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
dwc->test_mode = false;
@@ -2263,8 +2318,7 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
goto err1;
}
- dwc->setup_buf = kzalloc(sizeof(*dwc->setup_buf) * 2,
- GFP_KERNEL);
+ dwc->setup_buf = kzalloc(DWC3_EP0_BOUNCE_SIZE, GFP_KERNEL);
if (!dwc->setup_buf) {
dev_err(dwc->dev, "failed to allocate setup buffer\n");
ret = -ENOMEM;
@@ -2272,7 +2326,8 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
}
dwc->ep0_bounce = dma_alloc_coherent(dwc->dev,
- 512, &dwc->ep0_bounce_addr, GFP_KERNEL);
+ DWC3_EP0_BOUNCE_SIZE, &dwc->ep0_bounce_addr,
+ GFP_KERNEL);
if (!dwc->ep0_bounce) {
dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n");
ret = -ENOMEM;
@@ -2313,6 +2368,14 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
goto err5;
}
+ reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+ reg |= DWC3_DCFG_LPM_CAP;
+ dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ reg |= DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA;
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
/* Enable all but Start and End of Frame IRQs */
reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
DWC3_DEVTEN_EVNTOVERFLOWEN |
@@ -2351,8 +2414,8 @@ err5:
dwc3_gadget_free_endpoints(dwc);
err4:
- dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
- dwc->ep0_bounce_addr);
+ dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE,
+ dwc->ep0_bounce, dwc->ep0_bounce_addr);
err3:
kfree(dwc->setup_buf);
@@ -2381,8 +2444,8 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
dwc3_gadget_free_endpoints(dwc);
- dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
- dwc->ep0_bounce_addr);
+ dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE,
+ dwc->ep0_bounce, dwc->ep0_bounce_addr);
kfree(dwc->setup_buf);
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index a8600084348c..95ef6a2f7764 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -111,6 +111,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
+int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param);
/**
* dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index b108d18fd40d..56a62342884d 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -39,15 +39,6 @@
#include "core.h"
-static struct resource generic_resources[] = {
- {
- .flags = IORESOURCE_IRQ,
- },
- {
- .flags = IORESOURCE_MEM,
- },
-};
-
int dwc3_host_init(struct dwc3 *dwc)
{
struct platform_device *xhci;
@@ -68,14 +59,8 @@ int dwc3_host_init(struct dwc3 *dwc)
dwc->xhci = xhci;
- /* setup resources */
- generic_resources[0].start = dwc->irq;
-
- generic_resources[1].start = dwc->res->start;
- generic_resources[1].end = dwc->res->start + 0x7fff;
-
- ret = platform_device_add_resources(xhci, generic_resources,
- ARRAY_SIZE(generic_resources));
+ ret = platform_device_add_resources(xhci, dwc->xhci_resources,
+ DWC3_XHCI_RESOURCES_NUM);
if (ret) {
dev_err(dwc->dev, "couldn't add resources to xHCI device\n");
goto err1;
diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h
index 071d561f3e68..a50f76b9d19b 100644
--- a/drivers/usb/dwc3/io.h
+++ b/drivers/usb/dwc3/io.h
@@ -41,14 +41,26 @@
#include <linux/io.h>
+#include "core.h"
+
static inline u32 dwc3_readl(void __iomem *base, u32 offset)
{
- return readl(base + offset);
+ /*
+ * We requested the mem region starting from the Globals address
+ * space, see dwc3_probe in core.c.
+ * However, the offsets are given starting from xHCI address space.
+ */
+ return readl(base + (offset - DWC3_GLOBALS_REGS_START));
}
static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
{
- writel(value, base + offset);
+ /*
+ * We requested the mem region starting from the Globals address
+ * space, see dwc3_probe in core.c.
+ * However, the offsets are given starting from xHCI address space.
+ */
+ writel(value, base + (offset - DWC3_GLOBALS_REGS_START));
}
#endif /* __DRIVERS_USB_DWC3_IO_H */
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 569b33e754ba..bddc8fd9a7be 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -123,13 +123,7 @@ config USB_GADGET_STORAGE_NUM_BUFFERS
# - discrete ones (including all PCI-only controllers)
# - debug/dummy gadget+hcd is last.
#
-choice
- prompt "USB Peripheral Controller"
- help
- A USB device uses a controller to talk to its host.
- Systems should have only one such upstream link.
- Many controller drivers are platform-specific; these
- often need board-specific hooks.
+menu "USB Peripheral Controller"
#
# Integrated controllers
@@ -147,6 +141,17 @@ config USB_AT91
dynamically linked module called "at91_udc" and force all
gadget drivers to also be dynamically linked.
+config USB_LPC32XX
+ tristate "LPC32XX USB Peripheral Controller"
+ depends on ARCH_LPC32XX
+ select USB_ISP1301
+ help
+ This option selects the USB device controller in the LPC32xx SoC.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "lpc32xx_udc" and force all
+ gadget drivers to also be dynamically linked.
+
config USB_ATMEL_USBA
tristate "Atmel USBA"
select USB_GADGET_DUALSPEED
@@ -161,7 +166,7 @@ config USB_FSL_USB2
select USB_GADGET_DUALSPEED
select USB_FSL_MPH_DR_OF if OF
help
- Some of Freescale PowerPC processors have a High Speed
+ Some of Freescale PowerPC and i.MX processors have a High Speed
Dual-Role(DR) USB controller, which supports device mode.
The number of programmable endpoints is different through
@@ -373,18 +378,6 @@ config USB_FSL_QE
Set CONFIG_USB_GADGET to "m" to build this driver as a
dynamically linked module called "fsl_qe_udc".
-config USB_CI13XXX_PCI
- tristate "MIPS USB CI13xxx PCI UDC"
- depends on PCI
- select USB_GADGET_DUALSPEED
- help
- MIPS USB IP core family device controller
- Currently it only supports IP part number CI13412
-
- Say "y" to link the driver statically, or "m" to build a
- dynamically linked module called "ci13xxx_udc" and force all
- gadget drivers to also be dynamically linked.
-
config USB_NET2272
tristate "PLX NET2272"
select USB_GADGET_DUALSPEED
@@ -438,22 +431,6 @@ config USB_GOKU
dynamically linked module called "goku_udc" and to force all
gadget drivers to also be dynamically linked.
-config USB_LANGWELL
- tristate "Intel Langwell USB Device Controller"
- depends on PCI
- depends on !PHYS_ADDR_T_64BIT
- select USB_GADGET_DUALSPEED
- help
- Intel Langwell USB Device Controller is a High-Speed USB
- On-The-Go device controller.
-
- The number of programmable endpoints is different through
- controller revision.
-
- Say "y" to link the driver statically, or "m" to build a
- dynamically linked module called "langwell_udc" and force all
- gadget drivers to also be dynamically linked.
-
config USB_EG20T
tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC"
depends on PCI
@@ -477,23 +454,6 @@ config USB_EG20T
ML7213/ML7831 is companion chip for Intel Atom E6xx series.
ML7213/ML7831 is completely compatible for Intel EG20T PCH.
-config USB_CI13XXX_MSM
- tristate "MIPS USB CI13xxx for MSM"
- depends on ARCH_MSM
- select USB_GADGET_DUALSPEED
- select USB_MSM_OTG
- help
- MSM SoC has chipidea USB controller. This driver uses
- ci13xxx_udc core.
- This driver depends on OTG driver for PHY initialization,
- clock management, powering up VBUS, and power management.
- This driver is not supported on boards like trout which
- has an external PHY.
-
- Say "y" to link the driver statically, or "m" to build a
- dynamically linked module called "ci13xxx_msm" and force all
- gadget drivers to also be dynamically linked.
-
#
# LAST -- dummy/emulated controller
#
@@ -525,7 +485,7 @@ config USB_DUMMY_HCD
# NOTE: Please keep dummy_hcd LAST so that "real hardware" appears
# first and will be selected by default.
-endchoice
+endmenu
# Selected by UDC drivers that support high-speed operation.
config USB_GADGET_DUALSPEED
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index fc5b83683de5..1811513f1c27 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -22,14 +22,12 @@ fsl_usb2_udc-$(CONFIG_ARCH_MXC) += fsl_mxc_udc.o
obj-$(CONFIG_USB_M66592) += m66592-udc.o
obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o
obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o
-obj-$(CONFIG_USB_CI13XXX_PCI) += ci13xxx_pci.o
obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o
obj-$(CONFIG_USB_S3C_HSUDC) += s3c-hsudc.o
-obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o
+obj-$(CONFIG_USB_LPC32XX) += lpc32xx_udc.o
obj-$(CONFIG_USB_EG20T) += pch_udc.o
obj-$(CONFIG_USB_MV_UDC) += mv_udc.o
mv_udc-y := mv_udc_core.o
-obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o
obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o
#
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index 77779271f487..187d21181cd5 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -333,7 +333,7 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
return -ESHUTDOWN;
spin_lock_irqsave(&dev->lock, iflags);
- ep->desc = desc;
+ ep->ep.desc = desc;
ep->halted = 0;
@@ -442,7 +442,6 @@ static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep)
u32 tmp;
VDBG(ep->dev, "ep-%d reset\n", ep->num);
- ep->desc = NULL;
ep->ep.desc = NULL;
ep->ep.ops = &udc_ep_ops;
INIT_LIST_HEAD(&ep->queue);
@@ -489,7 +488,7 @@ static int udc_ep_disable(struct usb_ep *usbep)
return -EINVAL;
ep = container_of(usbep, struct udc_ep, ep);
- if (usbep->name == ep0_string || !ep->desc)
+ if (usbep->name == ep0_string || !ep->ep.desc)
return -EINVAL;
DBG(ep->dev, "Disable ep-%d\n", ep->num);
@@ -1066,7 +1065,7 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
return -EINVAL;
ep = container_of(usbep, struct udc_ep, ep);
- if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+ if (!ep->ep.desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
return -EINVAL;
VDBG(ep->dev, "udc_queue(): ep%d-in=%d\n", ep->num, ep->in);
@@ -1257,7 +1256,7 @@ static int udc_dequeue(struct usb_ep *usbep, struct usb_request *usbreq)
unsigned long iflags;
ep = container_of(usbep, struct udc_ep, ep);
- if (!usbep || !usbreq || (!ep->desc && (ep->num != 0
+ if (!usbep || !usbreq || (!ep->ep.desc && (ep->num != 0
&& ep->num != UDC_EP0OUT_IX)))
return -EINVAL;
@@ -1317,7 +1316,7 @@ udc_set_halt(struct usb_ep *usbep, int halt)
pr_debug("set_halt %s: halt=%d\n", usbep->name, halt);
ep = container_of(usbep, struct udc_ep, ep);
- if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+ if (!ep->ep.desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
return -EINVAL;
if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
return -ESHUTDOWN;
@@ -1539,7 +1538,7 @@ static void udc_setup_endpoints(struct udc *dev)
* disabling ep interrupts when ENUM interrupt occurs but ep is
* not enabled by gadget driver
*/
- if (!ep->desc)
+ if (!ep->ep.desc)
ep_init(dev->regs, ep);
if (use_dma) {
@@ -3402,19 +3401,7 @@ static struct pci_driver udc_pci_driver = {
.remove = udc_pci_remove,
};
-/* Inits driver */
-static int __init init(void)
-{
- return pci_register_driver(&udc_pci_driver);
-}
-module_init(init);
-
-/* Cleans driver */
-static void __exit cleanup(void)
-{
- pci_unregister_driver(&udc_pci_driver);
-}
-module_exit(cleanup);
+module_pci_driver(udc_pci_driver);
MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION);
MODULE_AUTHOR("Thomas Dahlmann");
diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h
index f87e29c65325..14af87d65caa 100644
--- a/drivers/usb/gadget/amd5536udc.h
+++ b/drivers/usb/gadget/amd5536udc.h
@@ -512,7 +512,6 @@ struct udc_ep {
/* queue for requests */
struct list_head queue;
- const struct usb_endpoint_descriptor *desc;
unsigned halted;
unsigned cancel_transfer;
unsigned num : 5,
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 9d7bcd910074..1a4430f315c3 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -212,7 +212,7 @@ static int proc_udc_show(struct seq_file *s, void *unused)
if (udc->enabled && udc->vbus) {
proc_ep_show(s, &udc->ep[0]);
list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {
- if (ep->desc)
+ if (ep->ep.desc)
proc_ep_show(s, ep);
}
}
@@ -475,7 +475,7 @@ static int at91_ep_enable(struct usb_ep *_ep,
unsigned long flags;
if (!_ep || !ep
- || !desc || ep->desc
+ || !desc || ep->ep.desc
|| _ep->name == ep0name
|| desc->bDescriptorType != USB_DT_ENDPOINT
|| (maxpacket = usb_endpoint_maxp(desc)) == 0
@@ -530,7 +530,7 @@ ok:
tmp |= AT91_UDP_EPEDS;
__raw_writel(tmp, ep->creg);
- ep->desc = desc;
+ ep->ep.desc = desc;
ep->ep.maxpacket = maxpacket;
/*
@@ -558,7 +558,6 @@ static int at91_ep_disable (struct usb_ep * _ep)
nuke(ep, -ESHUTDOWN);
/* restore the endpoint's pristine config */
- ep->desc = NULL;
ep->ep.desc = NULL;
ep->ep.maxpacket = ep->maxpacket;
@@ -618,7 +617,7 @@ static int at91_ep_queue(struct usb_ep *_ep,
return -EINVAL;
}
- if (!_ep || (!ep->desc && ep->ep.name != ep0name)) {
+ if (!_ep || (!ep->ep.desc && ep->ep.name != ep0name)) {
DBG("invalid ep\n");
return -EINVAL;
}
@@ -833,7 +832,7 @@ static void udc_reinit(struct at91_udc *udc)
if (i != 0)
list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
- ep->desc = NULL;
+ ep->ep.desc = NULL;
ep->stopped = 0;
ep->fifo_bank = 0;
ep->ep.maxpacket = ep->maxpacket;
@@ -978,18 +977,18 @@ static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on)
return 0;
}
-static int at91_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *));
-static int at91_stop(struct usb_gadget_driver *driver);
-
+static int at91_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
+static int at91_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
static const struct usb_gadget_ops at91_udc_ops = {
.get_frame = at91_get_frame,
.wakeup = at91_wakeup,
.set_selfpowered = at91_set_selfpowered,
.vbus_session = at91_vbus_session,
.pullup = at91_pullup,
- .start = at91_start,
- .stop = at91_stop,
+ .udc_start = at91_start,
+ .udc_stop = at91_stop,
/*
* VBUS-powered devices may also also want to support bigger
@@ -1172,7 +1171,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
| USB_REQ_GET_STATUS:
tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
ep = &udc->ep[tmp];
- if (tmp >= NUM_ENDPOINTS || (tmp && !ep->desc))
+ if (tmp >= NUM_ENDPOINTS || (tmp && !ep->ep.desc))
goto stall;
if (tmp) {
@@ -1197,7 +1196,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
ep = &udc->ep[tmp];
if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS)
goto stall;
- if (!ep->desc || ep->is_iso)
+ if (!ep->ep.desc || ep->is_iso)
goto stall;
if ((w_index & USB_DIR_IN)) {
if (!ep->is_in)
@@ -1218,7 +1217,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
goto stall;
if (tmp == 0)
goto succeed;
- if (!ep->desc || ep->is_iso)
+ if (!ep->ep.desc || ep->is_iso)
goto stall;
if ((w_index & USB_DIR_IN)) {
if (!ep->is_in)
@@ -1627,66 +1626,34 @@ static void at91_vbus_timer(unsigned long data)
schedule_work(&udc->vbus_timer_work);
}
-static int at91_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *))
+static int at91_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
- struct at91_udc *udc = &controller;
- int retval;
- unsigned long flags;
-
- if (!driver
- || driver->max_speed < USB_SPEED_FULL
- || !bind
- || !driver->setup) {
- DBG("bad parameter.\n");
- return -EINVAL;
- }
-
- if (udc->driver) {
- DBG("UDC already has a gadget driver\n");
- return -EBUSY;
- }
+ struct at91_udc *udc;
+ udc = container_of(gadget, struct at91_udc, gadget);
udc->driver = driver;
udc->gadget.dev.driver = &driver->driver;
dev_set_drvdata(&udc->gadget.dev, &driver->driver);
udc->enabled = 1;
udc->selfpowered = 1;
- retval = bind(&udc->gadget);
- if (retval) {
- DBG("bind() returned %d\n", retval);
- udc->driver = NULL;
- udc->gadget.dev.driver = NULL;
- dev_set_drvdata(&udc->gadget.dev, NULL);
- udc->enabled = 0;
- udc->selfpowered = 0;
- return retval;
- }
-
- spin_lock_irqsave(&udc->lock, flags);
- pullup(udc, 1);
- spin_unlock_irqrestore(&udc->lock, flags);
-
DBG("bound to %s\n", driver->driver.name);
return 0;
}
-static int at91_stop(struct usb_gadget_driver *driver)
+static int at91_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
- struct at91_udc *udc = &controller;
+ struct at91_udc *udc;
unsigned long flags;
- if (!driver || driver != udc->driver || !driver->unbind)
- return -EINVAL;
-
+ udc = container_of(gadget, struct at91_udc, gadget);
spin_lock_irqsave(&udc->lock, flags);
udc->enabled = 0;
at91_udp_write(udc, AT91_UDP_IDR, ~0);
- pullup(udc, 0);
spin_unlock_irqrestore(&udc->lock, flags);
- driver->unbind(&udc->gadget);
udc->gadget.dev.driver = NULL;
dev_set_drvdata(&udc->gadget.dev, NULL);
udc->driver = NULL;
diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h
index 3c0315b86ace..e647d1c2ada4 100644
--- a/drivers/usb/gadget/at91_udc.h
+++ b/drivers/usb/gadget/at91_udc.h
@@ -105,9 +105,6 @@ struct at91_ep {
unsigned is_in:1;
unsigned is_iso:1;
unsigned fifo_bank:1;
-
- const struct usb_endpoint_descriptor
- *desc;
};
/*
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index 9f98508966d1..e23bf7984aaf 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -599,13 +599,13 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
spin_lock_irqsave(&ep->udc->lock, flags);
- if (ep->desc) {
+ if (ep->ep.desc) {
spin_unlock_irqrestore(&ep->udc->lock, flags);
DBG(DBG_ERR, "ep%d already enabled\n", ep->index);
return -EBUSY;
}
- ep->desc = desc;
+ ep->ep.desc = desc;
ep->ep.maxpacket = maxpacket;
usba_ep_writel(ep, CFG, ept_cfg);
@@ -647,7 +647,7 @@ static int usba_ep_disable(struct usb_ep *_ep)
spin_lock_irqsave(&udc->lock, flags);
- if (!ep->desc) {
+ if (!ep->ep.desc) {
spin_unlock_irqrestore(&udc->lock, flags);
/* REVISIT because this driver disables endpoints in
* reset_all_endpoints() before calling disconnect(),
@@ -658,7 +658,6 @@ static int usba_ep_disable(struct usb_ep *_ep)
ep->ep.name);
return -EINVAL;
}
- ep->desc = NULL;
ep->ep.desc = NULL;
list_splice_init(&ep->queue, &req_list);
@@ -752,7 +751,7 @@ static int queue_dma(struct usba_udc *udc, struct usba_ep *ep,
*/
ret = -ESHUTDOWN;
spin_lock_irqsave(&udc->lock, flags);
- if (ep->desc) {
+ if (ep->ep.desc) {
if (list_empty(&ep->queue))
submit_request(ep, req);
@@ -776,7 +775,8 @@ usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
DBG(DBG_GADGET | DBG_QUEUE | DBG_REQ, "%s: queue req %p, len %u\n",
ep->ep.name, req, _req->length);
- if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || !ep->desc)
+ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN ||
+ !ep->ep.desc)
return -ESHUTDOWN;
req->submitted = 0;
@@ -792,7 +792,7 @@ usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
/* May have received a reset since last time we checked */
ret = -ESHUTDOWN;
spin_lock_irqsave(&udc->lock, flags);
- if (ep->desc) {
+ if (ep->ep.desc) {
list_add_tail(&req->queue, &ep->queue);
if ((!ep_is_control(ep) && ep->is_in) ||
@@ -905,7 +905,7 @@ static int usba_ep_set_halt(struct usb_ep *_ep, int value)
DBG(DBG_GADGET, "endpoint %s: %s HALT\n", ep->ep.name,
value ? "set" : "clear");
- if (!ep->desc) {
+ if (!ep->ep.desc) {
DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n",
ep->ep.name);
return -ENODEV;
@@ -1008,16 +1008,16 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
return 0;
}
-static int atmel_usba_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *));
-static int atmel_usba_stop(struct usb_gadget_driver *driver);
-
+static int atmel_usba_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
+static int atmel_usba_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
static const struct usb_gadget_ops usba_udc_ops = {
.get_frame = usba_udc_get_frame,
.wakeup = usba_udc_wakeup,
.set_selfpowered = usba_udc_set_selfpowered,
- .start = atmel_usba_start,
- .stop = atmel_usba_stop,
+ .udc_start = atmel_usba_start,
+ .udc_stop = atmel_usba_stop,
};
static struct usb_endpoint_descriptor usba_ep0_desc = {
@@ -1071,7 +1071,7 @@ static void reset_all_endpoints(struct usba_udc *udc)
* FIXME remove this code ... and retest thoroughly.
*/
list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
- if (ep->desc) {
+ if (ep->ep.desc) {
spin_unlock(&udc->lock);
usba_ep_disable(&ep->ep);
spin_lock(&udc->lock);
@@ -1089,9 +1089,9 @@ static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex)
list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {
u8 bEndpointAddress;
- if (!ep->desc)
+ if (!ep->ep.desc)
continue;
- bEndpointAddress = ep->desc->bEndpointAddress;
+ bEndpointAddress = ep->ep.desc->bEndpointAddress;
if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
continue;
if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)
@@ -1727,7 +1727,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
usb_speed_string(udc->gadget.speed));
ep0 = &usba_ep[0];
- ep0->desc = &usba_ep0_desc;
+ ep0->ep.desc = &usba_ep0_desc;
ep0->state = WAIT_FOR_SETUP;
usba_ep_writel(ep0, CFG,
(USBA_BF(EPT_SIZE, EP0_EPT_SIZE)
@@ -1795,21 +1795,13 @@ out:
return IRQ_HANDLED;
}
-static int atmel_usba_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *))
+static int atmel_usba_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
- struct usba_udc *udc = &the_udc;
+ struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget);
unsigned long flags;
- int ret;
-
- if (!udc->pdev)
- return -ENODEV;
spin_lock_irqsave(&udc->lock, flags);
- if (udc->driver) {
- spin_unlock_irqrestore(&udc->lock, flags);
- return -EBUSY;
- }
udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
udc->driver = driver;
@@ -1819,13 +1811,6 @@ static int atmel_usba_start(struct usb_gadget_driver *driver,
clk_enable(udc->pclk);
clk_enable(udc->hclk);
- ret = bind(&udc->gadget);
- if (ret) {
- DBG(DBG_ERR, "Could not bind to driver %s: error %d\n",
- driver->driver.name, ret);
- goto err_driver_bind;
- }
-
DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name);
udc->vbus_prev = 0;
@@ -1842,23 +1827,14 @@ static int atmel_usba_start(struct usb_gadget_driver *driver,
spin_unlock_irqrestore(&udc->lock, flags);
return 0;
-
-err_driver_bind:
- udc->driver = NULL;
- udc->gadget.dev.driver = NULL;
- return ret;
}
-static int atmel_usba_stop(struct usb_gadget_driver *driver)
+static int atmel_usba_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
- struct usba_udc *udc = &the_udc;
+ struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget);
unsigned long flags;
- if (!udc->pdev)
- return -ENODEV;
- if (driver != udc->driver || !driver->unbind)
- return -EINVAL;
-
if (gpio_is_valid(udc->vbus_pin))
disable_irq(gpio_to_irq(udc->vbus_pin));
@@ -1871,10 +1847,6 @@ static int atmel_usba_stop(struct usb_gadget_driver *driver)
toggle_bias(0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
- if (udc->driver->disconnect)
- udc->driver->disconnect(&udc->gadget);
-
- driver->unbind(&udc->gadget);
udc->gadget.dev.driver = NULL;
udc->driver = NULL;
diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h
index 88a2e07a11a8..9791259cbda7 100644
--- a/drivers/usb/gadget/atmel_usba_udc.h
+++ b/drivers/usb/gadget/atmel_usba_udc.h
@@ -280,7 +280,6 @@ struct usba_ep {
struct usba_udc *udc;
struct list_head queue;
- const struct usb_endpoint_descriptor *desc;
u16 fifo_size;
u8 nr_banks;
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
deleted file mode 100644
index 243ef1adf969..000000000000
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ /dev/null
@@ -1,2996 +0,0 @@
-/*
- * ci13xxx_udc.c - MIPS USB IP core family device controller
- *
- * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
- *
- * Author: David Lopo
- *
- * 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.
- */
-
-/*
- * Description: MIPS USB IP core family device controller
- * Currently it only supports IP part number CI13412
- *
- * This driver is composed of several blocks:
- * - HW: hardware interface
- * - DBG: debug facilities (optional)
- * - UTIL: utilities
- * - ISR: interrupts handling
- * - ENDPT: endpoint operations (Gadget API)
- * - GADGET: gadget operations (Gadget API)
- * - BUS: bus glue code, bus abstraction layer
- *
- * Compile Options
- * - CONFIG_USB_GADGET_DEBUG_FILES: enable debug facilities
- * - STALL_IN: non-empty bulk-in pipes cannot be halted
- * if defined mass storage compliance succeeds but with warnings
- * => case 4: Hi > Dn
- * => case 5: Hi > Di
- * => case 8: Hi <> Do
- * if undefined usbtest 13 fails
- * - TRACE: enable function tracing (depends on DEBUG)
- *
- * Main Features
- * - Chapter 9 & Mass Storage Compliance with Gadget File Storage
- * - Chapter 9 Compliance with Gadget Zero (STALL_IN undefined)
- * - Normal & LPM support
- *
- * USBTEST Report
- * - OK: 0-12, 13 (STALL_IN defined) & 14
- * - Not Supported: 15 & 16 (ISO)
- *
- * TODO List
- * - OTG
- * - Isochronous & Interrupt Traffic
- * - Handle requests which spawns into several TDs
- * - GET_STATUS(device) - always reports 0
- * - Gadget API (majority of optional features)
- * - Suspend & Remote Wakeup
- */
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/dmapool.h>
-#include <linux/dma-mapping.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/pm_runtime.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-#include <linux/usb/otg.h>
-
-#include "ci13xxx_udc.h"
-
-
-/******************************************************************************
- * DEFINE
- *****************************************************************************/
-
-#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-
-/* ctrl register bank access */
-static DEFINE_SPINLOCK(udc_lock);
-
-/* control endpoint description */
-static const struct usb_endpoint_descriptor
-ctrl_endpt_out_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- .bEndpointAddress = USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
- .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX),
-};
-
-static const struct usb_endpoint_descriptor
-ctrl_endpt_in_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
-
- .bEndpointAddress = USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
- .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX),
-};
-
-/* UDC descriptor */
-static struct ci13xxx *_udc;
-
-/* Interrupt statistics */
-#define ISR_MASK 0x1F
-static struct {
- u32 test;
- u32 ui;
- u32 uei;
- u32 pci;
- u32 uri;
- u32 sli;
- u32 none;
- struct {
- u32 cnt;
- u32 buf[ISR_MASK+1];
- u32 idx;
- } hndl;
-} isr_statistics;
-
-/**
- * ffs_nr: find first (least significant) bit set
- * @x: the word to search
- *
- * This function returns bit number (instead of position)
- */
-static int ffs_nr(u32 x)
-{
- int n = ffs(x);
-
- return n ? n-1 : 32;
-}
-
-/******************************************************************************
- * HW block
- *****************************************************************************/
-/* register bank descriptor */
-static struct {
- unsigned lpm; /* is LPM? */
- void __iomem *abs; /* bus map offset */
- void __iomem *cap; /* bus map offset + CAP offset + CAP data */
- size_t size; /* bank size */
-} hw_bank;
-
-/* MSM specific */
-#define ABS_AHBBURST (0x0090UL)
-#define ABS_AHBMODE (0x0098UL)
-/* UDC register map */
-#define ABS_CAPLENGTH (0x100UL)
-#define ABS_HCCPARAMS (0x108UL)
-#define ABS_DCCPARAMS (0x124UL)
-#define ABS_TESTMODE (hw_bank.lpm ? 0x0FCUL : 0x138UL)
-/* offset to CAPLENTGH (addr + data) */
-#define CAP_USBCMD (0x000UL)
-#define CAP_USBSTS (0x004UL)
-#define CAP_USBINTR (0x008UL)
-#define CAP_DEVICEADDR (0x014UL)
-#define CAP_ENDPTLISTADDR (0x018UL)
-#define CAP_PORTSC (0x044UL)
-#define CAP_DEVLC (0x084UL)
-#define CAP_USBMODE (hw_bank.lpm ? 0x0C8UL : 0x068UL)
-#define CAP_ENDPTSETUPSTAT (hw_bank.lpm ? 0x0D8UL : 0x06CUL)
-#define CAP_ENDPTPRIME (hw_bank.lpm ? 0x0DCUL : 0x070UL)
-#define CAP_ENDPTFLUSH (hw_bank.lpm ? 0x0E0UL : 0x074UL)
-#define CAP_ENDPTSTAT (hw_bank.lpm ? 0x0E4UL : 0x078UL)
-#define CAP_ENDPTCOMPLETE (hw_bank.lpm ? 0x0E8UL : 0x07CUL)
-#define CAP_ENDPTCTRL (hw_bank.lpm ? 0x0ECUL : 0x080UL)
-#define CAP_LAST (hw_bank.lpm ? 0x12CUL : 0x0C0UL)
-
-/* maximum number of enpoints: valid only after hw_device_reset() */
-static unsigned hw_ep_max;
-
-/**
- * hw_ep_bit: calculates the bit number
- * @num: endpoint number
- * @dir: endpoint direction
- *
- * This function returns bit number
- */
-static inline int hw_ep_bit(int num, int dir)
-{
- return num + (dir ? 16 : 0);
-}
-
-static int ep_to_bit(int n)
-{
- int fill = 16 - hw_ep_max / 2;
-
- if (n >= hw_ep_max / 2)
- n += fill;
-
- return n;
-}
-
-/**
- * hw_aread: reads from register bitfield
- * @addr: address relative to bus map
- * @mask: bitfield mask
- *
- * This function returns register bitfield data
- */
-static u32 hw_aread(u32 addr, u32 mask)
-{
- return ioread32(addr + hw_bank.abs) & mask;
-}
-
-/**
- * hw_awrite: writes to register bitfield
- * @addr: address relative to bus map
- * @mask: bitfield mask
- * @data: new data
- */
-static void hw_awrite(u32 addr, u32 mask, u32 data)
-{
- iowrite32(hw_aread(addr, ~mask) | (data & mask),
- addr + hw_bank.abs);
-}
-
-/**
- * hw_cread: reads from register bitfield
- * @addr: address relative to CAP offset plus content
- * @mask: bitfield mask
- *
- * This function returns register bitfield data
- */
-static u32 hw_cread(u32 addr, u32 mask)
-{
- return ioread32(addr + hw_bank.cap) & mask;
-}
-
-/**
- * hw_cwrite: writes to register bitfield
- * @addr: address relative to CAP offset plus content
- * @mask: bitfield mask
- * @data: new data
- */
-static void hw_cwrite(u32 addr, u32 mask, u32 data)
-{
- iowrite32(hw_cread(addr, ~mask) | (data & mask),
- addr + hw_bank.cap);
-}
-
-/**
- * hw_ctest_and_clear: tests & clears register bitfield
- * @addr: address relative to CAP offset plus content
- * @mask: bitfield mask
- *
- * This function returns register bitfield data
- */
-static u32 hw_ctest_and_clear(u32 addr, u32 mask)
-{
- u32 reg = hw_cread(addr, mask);
-
- iowrite32(reg, addr + hw_bank.cap);
- return reg;
-}
-
-/**
- * hw_ctest_and_write: tests & writes register bitfield
- * @addr: address relative to CAP offset plus content
- * @mask: bitfield mask
- * @data: new data
- *
- * This function returns register bitfield data
- */
-static u32 hw_ctest_and_write(u32 addr, u32 mask, u32 data)
-{
- u32 reg = hw_cread(addr, ~0);
-
- iowrite32((reg & ~mask) | (data & mask), addr + hw_bank.cap);
- return (reg & mask) >> ffs_nr(mask);
-}
-
-static int hw_device_init(void __iomem *base)
-{
- u32 reg;
-
- /* bank is a module variable */
- hw_bank.abs = base;
-
- hw_bank.cap = hw_bank.abs;
- hw_bank.cap += ABS_CAPLENGTH;
- hw_bank.cap += ioread8(hw_bank.cap);
-
- reg = hw_aread(ABS_HCCPARAMS, HCCPARAMS_LEN) >> ffs_nr(HCCPARAMS_LEN);
- hw_bank.lpm = reg;
- hw_bank.size = hw_bank.cap - hw_bank.abs;
- hw_bank.size += CAP_LAST;
- hw_bank.size /= sizeof(u32);
-
- reg = hw_aread(ABS_DCCPARAMS, DCCPARAMS_DEN) >> ffs_nr(DCCPARAMS_DEN);
- hw_ep_max = reg * 2; /* cache hw ENDPT_MAX */
-
- if (hw_ep_max == 0 || hw_ep_max > ENDPT_MAX)
- return -ENODEV;
-
- /* setup lock mode ? */
-
- /* ENDPTSETUPSTAT is '0' by default */
-
- /* HCSPARAMS.bf.ppc SHOULD BE zero for device */
-
- return 0;
-}
-/**
- * hw_device_reset: resets chip (execute without interruption)
- * @base: register base address
- *
- * This function returns an error code
- */
-static int hw_device_reset(struct ci13xxx *udc)
-{
- /* should flush & stop before reset */
- hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0);
- hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
-
- hw_cwrite(CAP_USBCMD, USBCMD_RST, USBCMD_RST);
- while (hw_cread(CAP_USBCMD, USBCMD_RST))
- udelay(10); /* not RTOS friendly */
-
-
- if (udc->udc_driver->notify_event)
- udc->udc_driver->notify_event(udc,
- CI13XXX_CONTROLLER_RESET_EVENT);
-
- if (udc->udc_driver->flags & CI13XXX_DISABLE_STREAMING)
- hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS);
-
- /* USBMODE should be configured step by step */
- hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
- hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_DEVICE);
- hw_cwrite(CAP_USBMODE, USBMODE_SLOM, USBMODE_SLOM); /* HW >= 2.3 */
-
- if (hw_cread(CAP_USBMODE, USBMODE_CM) != USBMODE_CM_DEVICE) {
- pr_err("cannot enter in device mode");
- pr_err("lpm = %i", hw_bank.lpm);
- return -ENODEV;
- }
-
- return 0;
-}
-
-/**
- * hw_device_state: enables/disables interrupts & starts/stops device (execute
- * without interruption)
- * @dma: 0 => disable, !0 => enable and set dma engine
- *
- * This function returns an error code
- */
-static int hw_device_state(u32 dma)
-{
- if (dma) {
- hw_cwrite(CAP_ENDPTLISTADDR, ~0, dma);
- /* interrupt, error, port change, reset, sleep/suspend */
- hw_cwrite(CAP_USBINTR, ~0,
- USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI);
- hw_cwrite(CAP_USBCMD, USBCMD_RS, USBCMD_RS);
- } else {
- hw_cwrite(CAP_USBCMD, USBCMD_RS, 0);
- hw_cwrite(CAP_USBINTR, ~0, 0);
- }
- return 0;
-}
-
-/**
- * hw_ep_flush: flush endpoint fifo (execute without interruption)
- * @num: endpoint number
- * @dir: endpoint direction
- *
- * This function returns an error code
- */
-static int hw_ep_flush(int num, int dir)
-{
- int n = hw_ep_bit(num, dir);
-
- do {
- /* flush any pending transfer */
- hw_cwrite(CAP_ENDPTFLUSH, BIT(n), BIT(n));
- while (hw_cread(CAP_ENDPTFLUSH, BIT(n)))
- cpu_relax();
- } while (hw_cread(CAP_ENDPTSTAT, BIT(n)));
-
- return 0;
-}
-
-/**
- * hw_ep_disable: disables endpoint (execute without interruption)
- * @num: endpoint number
- * @dir: endpoint direction
- *
- * This function returns an error code
- */
-static int hw_ep_disable(int num, int dir)
-{
- hw_ep_flush(num, dir);
- hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32),
- dir ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0);
- return 0;
-}
-
-/**
- * hw_ep_enable: enables endpoint (execute without interruption)
- * @num: endpoint number
- * @dir: endpoint direction
- * @type: endpoint type
- *
- * This function returns an error code
- */
-static int hw_ep_enable(int num, int dir, int type)
-{
- u32 mask, data;
-
- if (dir) {
- mask = ENDPTCTRL_TXT; /* type */
- data = type << ffs_nr(mask);
-
- mask |= ENDPTCTRL_TXS; /* unstall */
- mask |= ENDPTCTRL_TXR; /* reset data toggle */
- data |= ENDPTCTRL_TXR;
- mask |= ENDPTCTRL_TXE; /* enable */
- data |= ENDPTCTRL_TXE;
- } else {
- mask = ENDPTCTRL_RXT; /* type */
- data = type << ffs_nr(mask);
-
- mask |= ENDPTCTRL_RXS; /* unstall */
- mask |= ENDPTCTRL_RXR; /* reset data toggle */
- data |= ENDPTCTRL_RXR;
- mask |= ENDPTCTRL_RXE; /* enable */
- data |= ENDPTCTRL_RXE;
- }
- hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32), mask, data);
- return 0;
-}
-
-/**
- * hw_ep_get_halt: return endpoint halt status
- * @num: endpoint number
- * @dir: endpoint direction
- *
- * This function returns 1 if endpoint halted
- */
-static int hw_ep_get_halt(int num, int dir)
-{
- u32 mask = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
-
- return hw_cread(CAP_ENDPTCTRL + num * sizeof(u32), mask) ? 1 : 0;
-}
-
-/**
- * hw_test_and_clear_setup_status: test & clear setup status (execute without
- * interruption)
- * @n: endpoint number
- *
- * This function returns setup status
- */
-static int hw_test_and_clear_setup_status(int n)
-{
- n = ep_to_bit(n);
- return hw_ctest_and_clear(CAP_ENDPTSETUPSTAT, BIT(n));
-}
-
-/**
- * hw_ep_prime: primes endpoint (execute without interruption)
- * @num: endpoint number
- * @dir: endpoint direction
- * @is_ctrl: true if control endpoint
- *
- * This function returns an error code
- */
-static int hw_ep_prime(int num, int dir, int is_ctrl)
-{
- int n = hw_ep_bit(num, dir);
-
- if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num)))
- return -EAGAIN;
-
- hw_cwrite(CAP_ENDPTPRIME, BIT(n), BIT(n));
-
- while (hw_cread(CAP_ENDPTPRIME, BIT(n)))
- cpu_relax();
- if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num)))
- return -EAGAIN;
-
- /* status shoult be tested according with manual but it doesn't work */
- return 0;
-}
-
-/**
- * hw_ep_set_halt: configures ep halt & resets data toggle after clear (execute
- * without interruption)
- * @num: endpoint number
- * @dir: endpoint direction
- * @value: true => stall, false => unstall
- *
- * This function returns an error code
- */
-static int hw_ep_set_halt(int num, int dir, int value)
-{
- if (value != 0 && value != 1)
- return -EINVAL;
-
- do {
- u32 addr = CAP_ENDPTCTRL + num * sizeof(u32);
- u32 mask_xs = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS;
- u32 mask_xr = dir ? ENDPTCTRL_TXR : ENDPTCTRL_RXR;
-
- /* data toggle - reserved for EP0 but it's in ESS */
- hw_cwrite(addr, mask_xs|mask_xr, value ? mask_xs : mask_xr);
-
- } while (value != hw_ep_get_halt(num, dir));
-
- return 0;
-}
-
-/**
- * hw_intr_clear: disables interrupt & clears interrupt status (execute without
- * interruption)
- * @n: interrupt bit
- *
- * This function returns an error code
- */
-static int hw_intr_clear(int n)
-{
- if (n >= REG_BITS)
- return -EINVAL;
-
- hw_cwrite(CAP_USBINTR, BIT(n), 0);
- hw_cwrite(CAP_USBSTS, BIT(n), BIT(n));
- return 0;
-}
-
-/**
- * hw_intr_force: enables interrupt & forces interrupt status (execute without
- * interruption)
- * @n: interrupt bit
- *
- * This function returns an error code
- */
-static int hw_intr_force(int n)
-{
- if (n >= REG_BITS)
- return -EINVAL;
-
- hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE);
- hw_cwrite(CAP_USBINTR, BIT(n), BIT(n));
- hw_cwrite(CAP_USBSTS, BIT(n), BIT(n));
- hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, 0);
- return 0;
-}
-
-/**
- * hw_is_port_high_speed: test if port is high speed
- *
- * This function returns true if high speed port
- */
-static int hw_port_is_high_speed(void)
-{
- return hw_bank.lpm ? hw_cread(CAP_DEVLC, DEVLC_PSPD) :
- hw_cread(CAP_PORTSC, PORTSC_HSP);
-}
-
-/**
- * hw_port_test_get: reads port test mode value
- *
- * This function returns port test mode value
- */
-static u8 hw_port_test_get(void)
-{
- return hw_cread(CAP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC);
-}
-
-/**
- * hw_port_test_set: writes port test mode (execute without interruption)
- * @mode: new value
- *
- * This function returns an error code
- */
-static int hw_port_test_set(u8 mode)
-{
- const u8 TEST_MODE_MAX = 7;
-
- if (mode > TEST_MODE_MAX)
- return -EINVAL;
-
- hw_cwrite(CAP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC));
- return 0;
-}
-
-/**
- * hw_read_intr_enable: returns interrupt enable register
- *
- * This function returns register data
- */
-static u32 hw_read_intr_enable(void)
-{
- return hw_cread(CAP_USBINTR, ~0);
-}
-
-/**
- * hw_read_intr_status: returns interrupt status register
- *
- * This function returns register data
- */
-static u32 hw_read_intr_status(void)
-{
- return hw_cread(CAP_USBSTS, ~0);
-}
-
-/**
- * hw_register_read: reads all device registers (execute without interruption)
- * @buf: destination buffer
- * @size: buffer size
- *
- * This function returns number of registers read
- */
-static size_t hw_register_read(u32 *buf, size_t size)
-{
- unsigned i;
-
- if (size > hw_bank.size)
- size = hw_bank.size;
-
- for (i = 0; i < size; i++)
- buf[i] = hw_aread(i * sizeof(u32), ~0);
-
- return size;
-}
-
-/**
- * hw_register_write: writes to register
- * @addr: register address
- * @data: register value
- *
- * This function returns an error code
- */
-static int hw_register_write(u16 addr, u32 data)
-{
- /* align */
- addr /= sizeof(u32);
-
- if (addr >= hw_bank.size)
- return -EINVAL;
-
- /* align */
- addr *= sizeof(u32);
-
- hw_awrite(addr, ~0, data);
- return 0;
-}
-
-/**
- * hw_test_and_clear_complete: test & clear complete status (execute without
- * interruption)
- * @n: endpoint number
- *
- * This function returns complete status
- */
-static int hw_test_and_clear_complete(int n)
-{
- n = ep_to_bit(n);
- return hw_ctest_and_clear(CAP_ENDPTCOMPLETE, BIT(n));
-}
-
-/**
- * hw_test_and_clear_intr_active: test & clear active interrupts (execute
- * without interruption)
- *
- * This function returns active interrutps
- */
-static u32 hw_test_and_clear_intr_active(void)
-{
- u32 reg = hw_read_intr_status() & hw_read_intr_enable();
-
- hw_cwrite(CAP_USBSTS, ~0, reg);
- return reg;
-}
-
-/**
- * hw_test_and_clear_setup_guard: test & clear setup guard (execute without
- * interruption)
- *
- * This function returns guard value
- */
-static int hw_test_and_clear_setup_guard(void)
-{
- return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, 0);
-}
-
-/**
- * hw_test_and_set_setup_guard: test & set setup guard (execute without
- * interruption)
- *
- * This function returns guard value
- */
-static int hw_test_and_set_setup_guard(void)
-{
- return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, USBCMD_SUTW);
-}
-
-/**
- * hw_usb_set_address: configures USB address (execute without interruption)
- * @value: new USB address
- *
- * This function returns an error code
- */
-static int hw_usb_set_address(u8 value)
-{
- /* advance */
- hw_cwrite(CAP_DEVICEADDR, DEVICEADDR_USBADR | DEVICEADDR_USBADRA,
- value << ffs_nr(DEVICEADDR_USBADR) | DEVICEADDR_USBADRA);
- return 0;
-}
-
-/**
- * hw_usb_reset: restart device after a bus reset (execute without
- * interruption)
- *
- * This function returns an error code
- */
-static int hw_usb_reset(void)
-{
- hw_usb_set_address(0);
-
- /* ESS flushes only at end?!? */
- hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0); /* flush all EPs */
-
- /* clear setup token semaphores */
- hw_cwrite(CAP_ENDPTSETUPSTAT, 0, 0); /* writes its content */
-
- /* clear complete status */
- hw_cwrite(CAP_ENDPTCOMPLETE, 0, 0); /* writes its content */
-
- /* wait until all bits cleared */
- while (hw_cread(CAP_ENDPTPRIME, ~0))
- udelay(10); /* not RTOS friendly */
-
- /* reset all endpoints ? */
-
- /* reset internal status and wait for further instructions
- no need to verify the port reset status (ESS does it) */
-
- return 0;
-}
-
-/******************************************************************************
- * DBG block
- *****************************************************************************/
-/**
- * show_device: prints information about device capabilities and status
- *
- * Check "device.h" for details
- */
-static ssize_t show_device(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
- struct usb_gadget *gadget = &udc->gadget;
- int n = 0;
-
- dbg_trace("[%s] %p\n", __func__, buf);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
-
- n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n",
- gadget->speed);
- n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed = %d\n",
- gadget->max_speed);
- /* TODO: Scheduled for removal in 3.8. */
- n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed = %d\n",
- gadget_is_dualspeed(gadget));
- n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n",
- gadget->is_otg);
- n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n",
- gadget->is_a_peripheral);
- n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable = %d\n",
- gadget->b_hnp_enable);
- n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support = %d\n",
- gadget->a_hnp_support);
- n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n",
- gadget->a_alt_hnp_support);
- n += scnprintf(buf + n, PAGE_SIZE - n, "name = %s\n",
- (gadget->name ? gadget->name : ""));
-
- return n;
-}
-static DEVICE_ATTR(device, S_IRUSR, show_device, NULL);
-
-/**
- * show_driver: prints information about attached gadget (if any)
- *
- * Check "device.h" for details
- */
-static ssize_t show_driver(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
- struct usb_gadget_driver *driver = udc->driver;
- int n = 0;
-
- dbg_trace("[%s] %p\n", __func__, buf);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
-
- if (driver == NULL)
- return scnprintf(buf, PAGE_SIZE,
- "There is no gadget attached!\n");
-
- n += scnprintf(buf + n, PAGE_SIZE - n, "function = %s\n",
- (driver->function ? driver->function : ""));
- n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n",
- driver->max_speed);
-
- return n;
-}
-static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL);
-
-/* Maximum event message length */
-#define DBG_DATA_MSG 64UL
-
-/* Maximum event messages */
-#define DBG_DATA_MAX 128UL
-
-/* Event buffer descriptor */
-static struct {
- char (buf[DBG_DATA_MAX])[DBG_DATA_MSG]; /* buffer */
- unsigned idx; /* index */
- unsigned tty; /* print to console? */
- rwlock_t lck; /* lock */
-} dbg_data = {
- .idx = 0,
- .tty = 0,
- .lck = __RW_LOCK_UNLOCKED(lck)
-};
-
-/**
- * dbg_dec: decrements debug event index
- * @idx: buffer index
- */
-static void dbg_dec(unsigned *idx)
-{
- *idx = (*idx - 1) & (DBG_DATA_MAX-1);
-}
-
-/**
- * dbg_inc: increments debug event index
- * @idx: buffer index
- */
-static void dbg_inc(unsigned *idx)
-{
- *idx = (*idx + 1) & (DBG_DATA_MAX-1);
-}
-
-/**
- * dbg_print: prints the common part of the event
- * @addr: endpoint address
- * @name: event name
- * @status: status
- * @extra: extra information
- */
-static void dbg_print(u8 addr, const char *name, int status, const char *extra)
-{
- struct timeval tval;
- unsigned int stamp;
- unsigned long flags;
-
- write_lock_irqsave(&dbg_data.lck, flags);
-
- do_gettimeofday(&tval);
- stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s */
- stamp = stamp * 1000000 + tval.tv_usec;
-
- scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG,
- "%04X\t? %02X %-7.7s %4i ?\t%s\n",
- stamp, addr, name, status, extra);
-
- dbg_inc(&dbg_data.idx);
-
- write_unlock_irqrestore(&dbg_data.lck, flags);
-
- if (dbg_data.tty != 0)
- pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n",
- stamp, addr, name, status, extra);
-}
-
-/**
- * dbg_done: prints a DONE event
- * @addr: endpoint address
- * @td: transfer descriptor
- * @status: status
- */
-static void dbg_done(u8 addr, const u32 token, int status)
-{
- char msg[DBG_DATA_MSG];
-
- scnprintf(msg, sizeof(msg), "%d %02X",
- (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES),
- (int)(token & TD_STATUS) >> ffs_nr(TD_STATUS));
- dbg_print(addr, "DONE", status, msg);
-}
-
-/**
- * dbg_event: prints a generic event
- * @addr: endpoint address
- * @name: event name
- * @status: status
- */
-static void dbg_event(u8 addr, const char *name, int status)
-{
- if (name != NULL)
- dbg_print(addr, name, status, "");
-}
-
-/*
- * dbg_queue: prints a QUEUE event
- * @addr: endpoint address
- * @req: USB request
- * @status: status
- */
-static void dbg_queue(u8 addr, const struct usb_request *req, int status)
-{
- char msg[DBG_DATA_MSG];
-
- if (req != NULL) {
- scnprintf(msg, sizeof(msg),
- "%d %d", !req->no_interrupt, req->length);
- dbg_print(addr, "QUEUE", status, msg);
- }
-}
-
-/**
- * dbg_setup: prints a SETUP event
- * @addr: endpoint address
- * @req: setup request
- */
-static void dbg_setup(u8 addr, const struct usb_ctrlrequest *req)
-{
- char msg[DBG_DATA_MSG];
-
- if (req != NULL) {
- scnprintf(msg, sizeof(msg),
- "%02X %02X %04X %04X %d", req->bRequestType,
- req->bRequest, le16_to_cpu(req->wValue),
- le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength));
- dbg_print(addr, "SETUP", 0, msg);
- }
-}
-
-/**
- * show_events: displays the event buffer
- *
- * Check "device.h" for details
- */
-static ssize_t show_events(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- unsigned long flags;
- unsigned i, j, n = 0;
-
- dbg_trace("[%s] %p\n", __func__, buf);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
-
- read_lock_irqsave(&dbg_data.lck, flags);
-
- i = dbg_data.idx;
- for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) {
- n += strlen(dbg_data.buf[i]);
- if (n >= PAGE_SIZE) {
- n -= strlen(dbg_data.buf[i]);
- break;
- }
- }
- for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i))
- j += scnprintf(buf + j, PAGE_SIZE - j,
- "%s", dbg_data.buf[i]);
-
- read_unlock_irqrestore(&dbg_data.lck, flags);
-
- return n;
-}
-
-/**
- * store_events: configure if events are going to be also printed to console
- *
- * Check "device.h" for details
- */
-static ssize_t store_events(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- unsigned tty;
-
- dbg_trace("[%s] %p, %d\n", __func__, buf, count);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- goto done;
- }
-
- if (sscanf(buf, "%u", &tty) != 1 || tty > 1) {
- dev_err(dev, "<1|0>: enable|disable console log\n");
- goto done;
- }
-
- dbg_data.tty = tty;
- dev_info(dev, "tty = %u", dbg_data.tty);
-
- done:
- return count;
-}
-static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events);
-
-/**
- * show_inters: interrupt status, enable status and historic
- *
- * Check "device.h" for details
- */
-static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long flags;
- u32 intr;
- unsigned i, j, n = 0;
-
- dbg_trace("[%s] %p\n", __func__, buf);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
-
- spin_lock_irqsave(udc->lock, flags);
-
- n += scnprintf(buf + n, PAGE_SIZE - n,
- "status = %08x\n", hw_read_intr_status());
- n += scnprintf(buf + n, PAGE_SIZE - n,
- "enable = %08x\n", hw_read_intr_enable());
-
- n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n",
- isr_statistics.test);
- n += scnprintf(buf + n, PAGE_SIZE - n, "? ui = %d\n",
- isr_statistics.ui);
- n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n",
- isr_statistics.uei);
- n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n",
- isr_statistics.pci);
- n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n",
- isr_statistics.uri);
- n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n",
- isr_statistics.sli);
- n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n",
- isr_statistics.none);
- n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n",
- isr_statistics.hndl.cnt);
-
- for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) {
- i &= ISR_MASK;
- intr = isr_statistics.hndl.buf[i];
-
- if (USBi_UI & intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "ui ");
- intr &= ~USBi_UI;
- if (USBi_UEI & intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "uei ");
- intr &= ~USBi_UEI;
- if (USBi_PCI & intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "pci ");
- intr &= ~USBi_PCI;
- if (USBi_URI & intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "uri ");
- intr &= ~USBi_URI;
- if (USBi_SLI & intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "sli ");
- intr &= ~USBi_SLI;
- if (intr)
- n += scnprintf(buf + n, PAGE_SIZE - n, "??? ");
- if (isr_statistics.hndl.buf[i])
- n += scnprintf(buf + n, PAGE_SIZE - n, "\n");
- }
-
- spin_unlock_irqrestore(udc->lock, flags);
-
- return n;
-}
-
-/**
- * store_inters: enable & force or disable an individual interrutps
- * (to be used for test purposes only)
- *
- * Check "device.h" for details
- */
-static ssize_t store_inters(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long flags;
- unsigned en, bit;
-
- dbg_trace("[%s] %p, %d\n", __func__, buf, count);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- goto done;
- }
-
- if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) {
- dev_err(dev, "<1|0> <bit>: enable|disable interrupt");
- goto done;
- }
-
- spin_lock_irqsave(udc->lock, flags);
- if (en) {
- if (hw_intr_force(bit))
- dev_err(dev, "invalid bit number\n");
- else
- isr_statistics.test++;
- } else {
- if (hw_intr_clear(bit))
- dev_err(dev, "invalid bit number\n");
- }
- spin_unlock_irqrestore(udc->lock, flags);
-
- done:
- return count;
-}
-static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters);
-
-/**
- * show_port_test: reads port test mode
- *
- * Check "device.h" for details
- */
-static ssize_t show_port_test(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long flags;
- unsigned mode;
-
- dbg_trace("[%s] %p\n", __func__, buf);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
-
- spin_lock_irqsave(udc->lock, flags);
- mode = hw_port_test_get();
- spin_unlock_irqrestore(udc->lock, flags);
-
- return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode);
-}
-
-/**
- * store_port_test: writes port test mode
- *
- * Check "device.h" for details
- */
-static ssize_t store_port_test(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long flags;
- unsigned mode;
-
- dbg_trace("[%s] %p, %d\n", __func__, buf, count);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- goto done;
- }
-
- if (sscanf(buf, "%u", &mode) != 1) {
- dev_err(dev, "<mode>: set port test mode");
- goto done;
- }
-
- spin_lock_irqsave(udc->lock, flags);
- if (hw_port_test_set(mode))
- dev_err(dev, "invalid mode\n");
- spin_unlock_irqrestore(udc->lock, flags);
-
- done:
- return count;
-}
-static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR,
- show_port_test, store_port_test);
-
-/**
- * show_qheads: DMA contents of all queue heads
- *
- * Check "device.h" for details
- */
-static ssize_t show_qheads(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long flags;
- unsigned i, j, n = 0;
-
- dbg_trace("[%s] %p\n", __func__, buf);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
-
- spin_lock_irqsave(udc->lock, flags);
- for (i = 0; i < hw_ep_max/2; i++) {
- struct ci13xxx_ep *mEpRx = &udc->ci13xxx_ep[i];
- struct ci13xxx_ep *mEpTx = &udc->ci13xxx_ep[i + hw_ep_max/2];
- n += scnprintf(buf + n, PAGE_SIZE - n,
- "EP=%02i: RX=%08X TX=%08X\n",
- i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma);
- for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) {
- n += scnprintf(buf + n, PAGE_SIZE - n,
- " %04X: %08X %08X\n", j,
- *((u32 *)mEpRx->qh.ptr + j),
- *((u32 *)mEpTx->qh.ptr + j));
- }
- }
- spin_unlock_irqrestore(udc->lock, flags);
-
- return n;
-}
-static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL);
-
-/**
- * show_registers: dumps all registers
- *
- * Check "device.h" for details
- */
-#define DUMP_ENTRIES 512
-static ssize_t show_registers(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long flags;
- u32 *dump;
- unsigned i, k, n = 0;
-
- dbg_trace("[%s] %p\n", __func__, buf);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
-
- dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
- if (!dump) {
- dev_err(dev, "%s: out of memory\n", __func__);
- return 0;
- }
-
- spin_lock_irqsave(udc->lock, flags);
- k = hw_register_read(dump, DUMP_ENTRIES);
- spin_unlock_irqrestore(udc->lock, flags);
-
- for (i = 0; i < k; i++) {
- n += scnprintf(buf + n, PAGE_SIZE - n,
- "reg[0x%04X] = 0x%08X\n",
- i * (unsigned)sizeof(u32), dump[i]);
- }
- kfree(dump);
-
- return n;
-}
-
-/**
- * store_registers: writes value to register address
- *
- * Check "device.h" for details
- */
-static ssize_t store_registers(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long addr, data, flags;
-
- dbg_trace("[%s] %p, %d\n", __func__, buf, count);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- goto done;
- }
-
- if (sscanf(buf, "%li %li", &addr, &data) != 2) {
- dev_err(dev, "<addr> <data>: write data to register address");
- goto done;
- }
-
- spin_lock_irqsave(udc->lock, flags);
- if (hw_register_write(addr, data))
- dev_err(dev, "invalid address range\n");
- spin_unlock_irqrestore(udc->lock, flags);
-
- done:
- return count;
-}
-static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR,
- show_registers, store_registers);
-
-/**
- * show_requests: DMA contents of all requests currently queued (all endpts)
- *
- * Check "device.h" for details
- */
-static ssize_t show_requests(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
- unsigned long flags;
- struct list_head *ptr = NULL;
- struct ci13xxx_req *req = NULL;
- unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32);
-
- dbg_trace("[%s] %p\n", __func__, buf);
- if (attr == NULL || buf == NULL) {
- dev_err(dev, "[%s] EINVAL\n", __func__);
- return 0;
- }
-
- spin_lock_irqsave(udc->lock, flags);
- for (i = 0; i < hw_ep_max; i++)
- list_for_each(ptr, &udc->ci13xxx_ep[i].qh.queue)
- {
- req = list_entry(ptr, struct ci13xxx_req, queue);
-
- n += scnprintf(buf + n, PAGE_SIZE - n,
- "EP=%02i: TD=%08X %s\n",
- i % hw_ep_max/2, (u32)req->dma,
- ((i < hw_ep_max/2) ? "RX" : "TX"));
-
- for (j = 0; j < qSize; j++)
- n += scnprintf(buf + n, PAGE_SIZE - n,
- " %04X: %08X\n", j,
- *((u32 *)req->ptr + j));
- }
- spin_unlock_irqrestore(udc->lock, flags);
-
- return n;
-}
-static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL);
-
-/**
- * dbg_create_files: initializes the attribute interface
- * @dev: device
- *
- * This function returns an error code
- */
-__maybe_unused static int dbg_create_files(struct device *dev)
-{
- int retval = 0;
-
- if (dev == NULL)
- return -EINVAL;
- retval = device_create_file(dev, &dev_attr_device);
- if (retval)
- goto done;
- retval = device_create_file(dev, &dev_attr_driver);
- if (retval)
- goto rm_device;
- retval = device_create_file(dev, &dev_attr_events);
- if (retval)
- goto rm_driver;
- retval = device_create_file(dev, &dev_attr_inters);
- if (retval)
- goto rm_events;
- retval = device_create_file(dev, &dev_attr_port_test);
- if (retval)
- goto rm_inters;
- retval = device_create_file(dev, &dev_attr_qheads);
- if (retval)
- goto rm_port_test;
- retval = device_create_file(dev, &dev_attr_registers);
- if (retval)
- goto rm_qheads;
- retval = device_create_file(dev, &dev_attr_requests);
- if (retval)
- goto rm_registers;
- return 0;
-
- rm_registers:
- device_remove_file(dev, &dev_attr_registers);
- rm_qheads:
- device_remove_file(dev, &dev_attr_qheads);
- rm_port_test:
- device_remove_file(dev, &dev_attr_port_test);
- rm_inters:
- device_remove_file(dev, &dev_attr_inters);
- rm_events:
- device_remove_file(dev, &dev_attr_events);
- rm_driver:
- device_remove_file(dev, &dev_attr_driver);
- rm_device:
- device_remove_file(dev, &dev_attr_device);
- done:
- return retval;
-}
-
-/**
- * dbg_remove_files: destroys the attribute interface
- * @dev: device
- *
- * This function returns an error code
- */
-__maybe_unused static int dbg_remove_files(struct device *dev)
-{
- if (dev == NULL)
- return -EINVAL;
- device_remove_file(dev, &dev_attr_requests);
- device_remove_file(dev, &dev_attr_registers);
- device_remove_file(dev, &dev_attr_qheads);
- device_remove_file(dev, &dev_attr_port_test);
- device_remove_file(dev, &dev_attr_inters);
- device_remove_file(dev, &dev_attr_events);
- device_remove_file(dev, &dev_attr_driver);
- device_remove_file(dev, &dev_attr_device);
- return 0;
-}
-
-/******************************************************************************
- * UTIL block
- *****************************************************************************/
-/**
- * _usb_addr: calculates endpoint address from direction & number
- * @ep: endpoint
- */
-static inline u8 _usb_addr(struct ci13xxx_ep *ep)
-{
- return ((ep->dir == TX) ? USB_ENDPOINT_DIR_MASK : 0) | ep->num;
-}
-
-/**
- * _hardware_queue: configures a request at hardware level
- * @gadget: gadget
- * @mEp: endpoint
- *
- * This function returns an error code
- */
-static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
-{
- unsigned i;
- int ret = 0;
- unsigned length = mReq->req.length;
-
- trace("%p, %p", mEp, mReq);
-
- /* don't queue twice */
- if (mReq->req.status == -EALREADY)
- return -EALREADY;
-
- mReq->req.status = -EALREADY;
- if (length && mReq->req.dma == DMA_ADDR_INVALID) {
- mReq->req.dma = \
- dma_map_single(mEp->device, mReq->req.buf,
- length, mEp->dir ? DMA_TO_DEVICE :
- DMA_FROM_DEVICE);
- if (mReq->req.dma == 0)
- return -ENOMEM;
-
- mReq->map = 1;
- }
-
- if (mReq->req.zero && length && (length % mEp->ep.maxpacket == 0)) {
- mReq->zptr = dma_pool_alloc(mEp->td_pool, GFP_ATOMIC,
- &mReq->zdma);
- if (mReq->zptr == NULL) {
- if (mReq->map) {
- dma_unmap_single(mEp->device, mReq->req.dma,
- length, mEp->dir ? DMA_TO_DEVICE :
- DMA_FROM_DEVICE);
- mReq->req.dma = DMA_ADDR_INVALID;
- mReq->map = 0;
- }
- return -ENOMEM;
- }
- memset(mReq->zptr, 0, sizeof(*mReq->zptr));
- mReq->zptr->next = TD_TERMINATE;
- mReq->zptr->token = TD_STATUS_ACTIVE;
- if (!mReq->req.no_interrupt)
- mReq->zptr->token |= TD_IOC;
- }
- /*
- * TD configuration
- * TODO - handle requests which spawns into several TDs
- */
- memset(mReq->ptr, 0, sizeof(*mReq->ptr));
- mReq->ptr->token = length << ffs_nr(TD_TOTAL_BYTES);
- mReq->ptr->token &= TD_TOTAL_BYTES;
- mReq->ptr->token |= TD_STATUS_ACTIVE;
- if (mReq->zptr) {
- mReq->ptr->next = mReq->zdma;
- } else {
- mReq->ptr->next = TD_TERMINATE;
- if (!mReq->req.no_interrupt)
- mReq->ptr->token |= TD_IOC;
- }
- mReq->ptr->page[0] = mReq->req.dma;
- for (i = 1; i < 5; i++)
- mReq->ptr->page[i] =
- (mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK;
-
- if (!list_empty(&mEp->qh.queue)) {
- struct ci13xxx_req *mReqPrev;
- int n = hw_ep_bit(mEp->num, mEp->dir);
- int tmp_stat;
-
- mReqPrev = list_entry(mEp->qh.queue.prev,
- struct ci13xxx_req, queue);
- if (mReqPrev->zptr)
- mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK;
- else
- mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK;
- wmb();
- if (hw_cread(CAP_ENDPTPRIME, BIT(n)))
- goto done;
- do {
- hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, USBCMD_ATDTW);
- tmp_stat = hw_cread(CAP_ENDPTSTAT, BIT(n));
- } while (!hw_cread(CAP_USBCMD, USBCMD_ATDTW));
- hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, 0);
- if (tmp_stat)
- goto done;
- }
-
- /* QH configuration */
- mEp->qh.ptr->td.next = mReq->dma; /* TERMINATE = 0 */
- mEp->qh.ptr->td.token &= ~TD_STATUS; /* clear status */
- mEp->qh.ptr->cap |= QH_ZLT;
-
- wmb(); /* synchronize before ep prime */
-
- ret = hw_ep_prime(mEp->num, mEp->dir,
- mEp->type == USB_ENDPOINT_XFER_CONTROL);
-done:
- return ret;
-}
-
-/**
- * _hardware_dequeue: handles a request at hardware level
- * @gadget: gadget
- * @mEp: endpoint
- *
- * This function returns an error code
- */
-static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)
-{
- trace("%p, %p", mEp, mReq);
-
- if (mReq->req.status != -EALREADY)
- return -EINVAL;
-
- if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0)
- return -EBUSY;
-
- if (mReq->zptr) {
- if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0)
- return -EBUSY;
- dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);
- mReq->zptr = NULL;
- }
-
- mReq->req.status = 0;
-
- if (mReq->map) {
- dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length,
- mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- mReq->req.dma = DMA_ADDR_INVALID;
- mReq->map = 0;
- }
-
- mReq->req.status = mReq->ptr->token & TD_STATUS;
- if ((TD_STATUS_HALTED & mReq->req.status) != 0)
- mReq->req.status = -1;
- else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0)
- mReq->req.status = -1;
- else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0)
- mReq->req.status = -1;
-
- mReq->req.actual = mReq->ptr->token & TD_TOTAL_BYTES;
- mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES);
- mReq->req.actual = mReq->req.length - mReq->req.actual;
- mReq->req.actual = mReq->req.status ? 0 : mReq->req.actual;
-
- return mReq->req.actual;
-}
-
-/**
- * _ep_nuke: dequeues all endpoint requests
- * @mEp: endpoint
- *
- * This function returns an error code
- * Caller must hold lock
- */
-static int _ep_nuke(struct ci13xxx_ep *mEp)
-__releases(mEp->lock)
-__acquires(mEp->lock)
-{
- trace("%p", mEp);
-
- if (mEp == NULL)
- return -EINVAL;
-
- hw_ep_flush(mEp->num, mEp->dir);
-
- while (!list_empty(&mEp->qh.queue)) {
-
- /* pop oldest request */
- struct ci13xxx_req *mReq = \
- list_entry(mEp->qh.queue.next,
- struct ci13xxx_req, queue);
- list_del_init(&mReq->queue);
- mReq->req.status = -ESHUTDOWN;
-
- if (mReq->req.complete != NULL) {
- spin_unlock(mEp->lock);
- mReq->req.complete(&mEp->ep, &mReq->req);
- spin_lock(mEp->lock);
- }
- }
- return 0;
-}
-
-/**
- * _gadget_stop_activity: stops all USB activity, flushes & disables all endpts
- * @gadget: gadget
- *
- * This function returns an error code
- */
-static int _gadget_stop_activity(struct usb_gadget *gadget)
-{
- struct usb_ep *ep;
- struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget);
- unsigned long flags;
-
- trace("%p", gadget);
-
- if (gadget == NULL)
- return -EINVAL;
-
- spin_lock_irqsave(udc->lock, flags);
- udc->gadget.speed = USB_SPEED_UNKNOWN;
- udc->remote_wakeup = 0;
- udc->suspended = 0;
- spin_unlock_irqrestore(udc->lock, flags);
-
- /* flush all endpoints */
- gadget_for_each_ep(ep, gadget) {
- usb_ep_fifo_flush(ep);
- }
- usb_ep_fifo_flush(&udc->ep0out.ep);
- usb_ep_fifo_flush(&udc->ep0in.ep);
-
- udc->driver->disconnect(gadget);
-
- /* make sure to disable all endpoints */
- gadget_for_each_ep(ep, gadget) {
- usb_ep_disable(ep);
- }
-
- if (udc->status != NULL) {
- usb_ep_free_request(&udc->ep0in.ep, udc->status);
- udc->status = NULL;
- }
-
- return 0;
-}
-
-/******************************************************************************
- * ISR block
- *****************************************************************************/
-/**
- * isr_reset_handler: USB reset interrupt handler
- * @udc: UDC device
- *
- * This function resets USB engine after a bus reset occurred
- */
-static void isr_reset_handler(struct ci13xxx *udc)
-__releases(udc->lock)
-__acquires(udc->lock)
-{
- int retval;
-
- trace("%p", udc);
-
- if (udc == NULL) {
- err("EINVAL");
- return;
- }
-
- dbg_event(0xFF, "BUS RST", 0);
-
- spin_unlock(udc->lock);
- retval = _gadget_stop_activity(&udc->gadget);
- if (retval)
- goto done;
-
- retval = hw_usb_reset();
- if (retval)
- goto done;
-
- udc->status = usb_ep_alloc_request(&udc->ep0in.ep, GFP_ATOMIC);
- if (udc->status == NULL)
- retval = -ENOMEM;
-
- spin_lock(udc->lock);
-
- done:
- if (retval)
- err("error: %i", retval);
-}
-
-/**
- * isr_get_status_complete: get_status request complete function
- * @ep: endpoint
- * @req: request handled
- *
- * Caller must release lock
- */
-static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)
-{
- trace("%p, %p", ep, req);
-
- if (ep == NULL || req == NULL) {
- err("EINVAL");
- return;
- }
-
- kfree(req->buf);
- usb_ep_free_request(ep, req);
-}
-
-/**
- * isr_get_status_response: get_status request response
- * @udc: udc struct
- * @setup: setup request packet
- *
- * This function returns an error code
- */
-static int isr_get_status_response(struct ci13xxx *udc,
- struct usb_ctrlrequest *setup)
-__releases(mEp->lock)
-__acquires(mEp->lock)
-{
- struct ci13xxx_ep *mEp = &udc->ep0in;
- struct usb_request *req = NULL;
- gfp_t gfp_flags = GFP_ATOMIC;
- int dir, num, retval;
-
- trace("%p, %p", mEp, setup);
-
- if (mEp == NULL || setup == NULL)
- return -EINVAL;
-
- spin_unlock(mEp->lock);
- req = usb_ep_alloc_request(&mEp->ep, gfp_flags);
- spin_lock(mEp->lock);
- if (req == NULL)
- return -ENOMEM;
-
- req->complete = isr_get_status_complete;
- req->length = 2;
- req->buf = kzalloc(req->length, gfp_flags);
- if (req->buf == NULL) {
- retval = -ENOMEM;
- goto err_free_req;
- }
-
- if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
- /* Assume that device is bus powered for now. */
- *((u16 *)req->buf) = _udc->remote_wakeup << 1;
- retval = 0;
- } else if ((setup->bRequestType & USB_RECIP_MASK) \
- == USB_RECIP_ENDPOINT) {
- dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ?
- TX : RX;
- num = le16_to_cpu(setup->wIndex) & USB_ENDPOINT_NUMBER_MASK;
- *((u16 *)req->buf) = hw_ep_get_halt(num, dir);
- }
- /* else do nothing; reserved for future use */
-
- spin_unlock(mEp->lock);
- retval = usb_ep_queue(&mEp->ep, req, gfp_flags);
- spin_lock(mEp->lock);
- if (retval)
- goto err_free_buf;
-
- return 0;
-
- err_free_buf:
- kfree(req->buf);
- err_free_req:
- spin_unlock(mEp->lock);
- usb_ep_free_request(&mEp->ep, req);
- spin_lock(mEp->lock);
- return retval;
-}
-
-/**
- * isr_setup_status_complete: setup_status request complete function
- * @ep: endpoint
- * @req: request handled
- *
- * Caller must release lock. Put the port in test mode if test mode
- * feature is selected.
- */
-static void
-isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req)
-{
- struct ci13xxx *udc = req->context;
- unsigned long flags;
-
- trace("%p, %p", ep, req);
-
- spin_lock_irqsave(udc->lock, flags);
- if (udc->test_mode)
- hw_port_test_set(udc->test_mode);
- spin_unlock_irqrestore(udc->lock, flags);
-}
-
-/**
- * isr_setup_status_phase: queues the status phase of a setup transation
- * @udc: udc struct
- *
- * This function returns an error code
- */
-static int isr_setup_status_phase(struct ci13xxx *udc)
-__releases(mEp->lock)
-__acquires(mEp->lock)
-{
- int retval;
- struct ci13xxx_ep *mEp;
-
- trace("%p", udc);
-
- mEp = (udc->ep0_dir == TX) ? &udc->ep0out : &udc->ep0in;
- udc->status->context = udc;
- udc->status->complete = isr_setup_status_complete;
-
- spin_unlock(mEp->lock);
- retval = usb_ep_queue(&mEp->ep, udc->status, GFP_ATOMIC);
- spin_lock(mEp->lock);
-
- return retval;
-}
-
-/**
- * isr_tr_complete_low: transaction complete low level handler
- * @mEp: endpoint
- *
- * This function returns an error code
- * Caller must hold lock
- */
-static int isr_tr_complete_low(struct ci13xxx_ep *mEp)
-__releases(mEp->lock)
-__acquires(mEp->lock)
-{
- struct ci13xxx_req *mReq, *mReqTemp;
- struct ci13xxx_ep *mEpTemp = mEp;
- int uninitialized_var(retval);
-
- trace("%p", mEp);
-
- if (list_empty(&mEp->qh.queue))
- return -EINVAL;
-
- list_for_each_entry_safe(mReq, mReqTemp, &mEp->qh.queue,
- queue) {
- retval = _hardware_dequeue(mEp, mReq);
- if (retval < 0)
- break;
- list_del_init(&mReq->queue);
- dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);
- if (mReq->req.complete != NULL) {
- spin_unlock(mEp->lock);
- if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) &&
- mReq->req.length)
- mEpTemp = &_udc->ep0in;
- mReq->req.complete(&mEpTemp->ep, &mReq->req);
- spin_lock(mEp->lock);
- }
- }
-
- if (retval == -EBUSY)
- retval = 0;
- if (retval < 0)
- dbg_event(_usb_addr(mEp), "DONE", retval);
-
- return retval;
-}
-
-/**
- * isr_tr_complete_handler: transaction complete interrupt handler
- * @udc: UDC descriptor
- *
- * This function handles traffic events
- */
-static void isr_tr_complete_handler(struct ci13xxx *udc)
-__releases(udc->lock)
-__acquires(udc->lock)
-{
- unsigned i;
- u8 tmode = 0;
-
- trace("%p", udc);
-
- if (udc == NULL) {
- err("EINVAL");
- return;
- }
-
- for (i = 0; i < hw_ep_max; i++) {
- struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
- int type, num, dir, err = -EINVAL;
- struct usb_ctrlrequest req;
-
- if (mEp->desc == NULL)
- continue; /* not configured */
-
- if (hw_test_and_clear_complete(i)) {
- err = isr_tr_complete_low(mEp);
- if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
- if (err > 0) /* needs status phase */
- err = isr_setup_status_phase(udc);
- if (err < 0) {
- dbg_event(_usb_addr(mEp),
- "ERROR", err);
- spin_unlock(udc->lock);
- if (usb_ep_set_halt(&mEp->ep))
- err("error: ep_set_halt");
- spin_lock(udc->lock);
- }
- }
- }
-
- if (mEp->type != USB_ENDPOINT_XFER_CONTROL ||
- !hw_test_and_clear_setup_status(i))
- continue;
-
- if (i != 0) {
- warn("ctrl traffic received at endpoint");
- continue;
- }
-
- /*
- * Flush data and handshake transactions of previous
- * setup packet.
- */
- _ep_nuke(&udc->ep0out);
- _ep_nuke(&udc->ep0in);
-
- /* read_setup_packet */
- do {
- hw_test_and_set_setup_guard();
- memcpy(&req, &mEp->qh.ptr->setup, sizeof(req));
- } while (!hw_test_and_clear_setup_guard());
-
- type = req.bRequestType;
-
- udc->ep0_dir = (type & USB_DIR_IN) ? TX : RX;
-
- dbg_setup(_usb_addr(mEp), &req);
-
- switch (req.bRequest) {
- case USB_REQ_CLEAR_FEATURE:
- if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
- le16_to_cpu(req.wValue) ==
- USB_ENDPOINT_HALT) {
- if (req.wLength != 0)
- break;
- num = le16_to_cpu(req.wIndex);
- dir = num & USB_ENDPOINT_DIR_MASK;
- num &= USB_ENDPOINT_NUMBER_MASK;
- if (dir) /* TX */
- num += hw_ep_max/2;
- if (!udc->ci13xxx_ep[num].wedge) {
- spin_unlock(udc->lock);
- err = usb_ep_clear_halt(
- &udc->ci13xxx_ep[num].ep);
- spin_lock(udc->lock);
- if (err)
- break;
- }
- err = isr_setup_status_phase(udc);
- } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) &&
- le16_to_cpu(req.wValue) ==
- USB_DEVICE_REMOTE_WAKEUP) {
- if (req.wLength != 0)
- break;
- udc->remote_wakeup = 0;
- err = isr_setup_status_phase(udc);
- } else {
- goto delegate;
- }
- break;
- case USB_REQ_GET_STATUS:
- if (type != (USB_DIR_IN|USB_RECIP_DEVICE) &&
- type != (USB_DIR_IN|USB_RECIP_ENDPOINT) &&
- type != (USB_DIR_IN|USB_RECIP_INTERFACE))
- goto delegate;
- if (le16_to_cpu(req.wLength) != 2 ||
- le16_to_cpu(req.wValue) != 0)
- break;
- err = isr_get_status_response(udc, &req);
- break;
- case USB_REQ_SET_ADDRESS:
- if (type != (USB_DIR_OUT|USB_RECIP_DEVICE))
- goto delegate;
- if (le16_to_cpu(req.wLength) != 0 ||
- le16_to_cpu(req.wIndex) != 0)
- break;
- err = hw_usb_set_address((u8)le16_to_cpu(req.wValue));
- if (err)
- break;
- err = isr_setup_status_phase(udc);
- break;
- case USB_REQ_SET_FEATURE:
- if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) &&
- le16_to_cpu(req.wValue) ==
- USB_ENDPOINT_HALT) {
- if (req.wLength != 0)
- break;
- num = le16_to_cpu(req.wIndex);
- dir = num & USB_ENDPOINT_DIR_MASK;
- num &= USB_ENDPOINT_NUMBER_MASK;
- if (dir) /* TX */
- num += hw_ep_max/2;
-
- spin_unlock(udc->lock);
- err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep);
- spin_lock(udc->lock);
- if (!err)
- isr_setup_status_phase(udc);
- } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) {
- if (req.wLength != 0)
- break;
- switch (le16_to_cpu(req.wValue)) {
- case USB_DEVICE_REMOTE_WAKEUP:
- udc->remote_wakeup = 1;
- err = isr_setup_status_phase(udc);
- break;
- case USB_DEVICE_TEST_MODE:
- tmode = le16_to_cpu(req.wIndex) >> 8;
- switch (tmode) {
- case TEST_J:
- case TEST_K:
- case TEST_SE0_NAK:
- case TEST_PACKET:
- case TEST_FORCE_EN:
- udc->test_mode = tmode;
- err = isr_setup_status_phase(
- udc);
- break;
- default:
- break;
- }
- default:
- goto delegate;
- }
- } else {
- goto delegate;
- }
- break;
- default:
-delegate:
- if (req.wLength == 0) /* no data phase */
- udc->ep0_dir = TX;
-
- spin_unlock(udc->lock);
- err = udc->driver->setup(&udc->gadget, &req);
- spin_lock(udc->lock);
- break;
- }
-
- if (err < 0) {
- dbg_event(_usb_addr(mEp), "ERROR", err);
-
- spin_unlock(udc->lock);
- if (usb_ep_set_halt(&mEp->ep))
- err("error: ep_set_halt");
- spin_lock(udc->lock);
- }
- }
-}
-
-/******************************************************************************
- * ENDPT block
- *****************************************************************************/
-/**
- * ep_enable: configure endpoint, making it usable
- *
- * Check usb_ep_enable() at "usb_gadget.h" for details
- */
-static int ep_enable(struct usb_ep *ep,
- const struct usb_endpoint_descriptor *desc)
-{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- int retval = 0;
- unsigned long flags;
-
- trace("%p, %p", ep, desc);
-
- if (ep == NULL || desc == NULL)
- return -EINVAL;
-
- spin_lock_irqsave(mEp->lock, flags);
-
- /* only internal SW should enable ctrl endpts */
-
- mEp->desc = desc;
-
- if (!list_empty(&mEp->qh.queue))
- warn("enabling a non-empty endpoint!");
-
- mEp->dir = usb_endpoint_dir_in(desc) ? TX : RX;
- mEp->num = usb_endpoint_num(desc);
- mEp->type = usb_endpoint_type(desc);
-
- mEp->ep.maxpacket = usb_endpoint_maxp(desc);
-
- dbg_event(_usb_addr(mEp), "ENABLE", 0);
-
- mEp->qh.ptr->cap = 0;
-
- if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
- mEp->qh.ptr->cap |= QH_IOS;
- else if (mEp->type == USB_ENDPOINT_XFER_ISOC)
- mEp->qh.ptr->cap &= ~QH_MULT;
- else
- mEp->qh.ptr->cap &= ~QH_ZLT;
-
- mEp->qh.ptr->cap |=
- (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT;
- mEp->qh.ptr->td.next |= TD_TERMINATE; /* needed? */
-
- /*
- * Enable endpoints in the HW other than ep0 as ep0
- * is always enabled
- */
- if (mEp->num)
- retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type);
-
- spin_unlock_irqrestore(mEp->lock, flags);
- return retval;
-}
-
-/**
- * ep_disable: endpoint is no longer usable
- *
- * Check usb_ep_disable() at "usb_gadget.h" for details
- */
-static int ep_disable(struct usb_ep *ep)
-{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- int direction, retval = 0;
- unsigned long flags;
-
- trace("%p", ep);
-
- if (ep == NULL)
- return -EINVAL;
- else if (mEp->desc == NULL)
- return -EBUSY;
-
- spin_lock_irqsave(mEp->lock, flags);
-
- /* only internal SW should disable ctrl endpts */
-
- direction = mEp->dir;
- do {
- dbg_event(_usb_addr(mEp), "DISABLE", 0);
-
- retval |= _ep_nuke(mEp);
- retval |= hw_ep_disable(mEp->num, mEp->dir);
-
- if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
- mEp->dir = (mEp->dir == TX) ? RX : TX;
-
- } while (mEp->dir != direction);
-
- mEp->desc = NULL;
- mEp->ep.desc = NULL;
-
- spin_unlock_irqrestore(mEp->lock, flags);
- return retval;
-}
-
-/**
- * ep_alloc_request: allocate a request object to use with this endpoint
- *
- * Check usb_ep_alloc_request() at "usb_gadget.h" for details
- */
-static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)
-{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- struct ci13xxx_req *mReq = NULL;
-
- trace("%p, %i", ep, gfp_flags);
-
- if (ep == NULL) {
- err("EINVAL");
- return NULL;
- }
-
- mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags);
- if (mReq != NULL) {
- INIT_LIST_HEAD(&mReq->queue);
- mReq->req.dma = DMA_ADDR_INVALID;
-
- mReq->ptr = dma_pool_alloc(mEp->td_pool, gfp_flags,
- &mReq->dma);
- if (mReq->ptr == NULL) {
- kfree(mReq);
- mReq = NULL;
- }
- }
-
- dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL);
-
- return (mReq == NULL) ? NULL : &mReq->req;
-}
-
-/**
- * ep_free_request: frees a request object
- *
- * Check usb_ep_free_request() at "usb_gadget.h" for details
- */
-static void ep_free_request(struct usb_ep *ep, struct usb_request *req)
-{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
- unsigned long flags;
-
- trace("%p, %p", ep, req);
-
- if (ep == NULL || req == NULL) {
- err("EINVAL");
- return;
- } else if (!list_empty(&mReq->queue)) {
- err("EBUSY");
- return;
- }
-
- spin_lock_irqsave(mEp->lock, flags);
-
- if (mReq->ptr)
- dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma);
- kfree(mReq);
-
- dbg_event(_usb_addr(mEp), "FREE", 0);
-
- spin_unlock_irqrestore(mEp->lock, flags);
-}
-
-/**
- * ep_queue: queues (submits) an I/O request to an endpoint
- *
- * Check usb_ep_queue()* at usb_gadget.h" for details
- */
-static int ep_queue(struct usb_ep *ep, struct usb_request *req,
- gfp_t __maybe_unused gfp_flags)
-{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
- int retval = 0;
- unsigned long flags;
-
- trace("%p, %p, %X", ep, req, gfp_flags);
-
- if (ep == NULL || req == NULL || mEp->desc == NULL)
- return -EINVAL;
-
- spin_lock_irqsave(mEp->lock, flags);
-
- if (mEp->type == USB_ENDPOINT_XFER_CONTROL) {
- if (req->length)
- mEp = (_udc->ep0_dir == RX) ?
- &_udc->ep0out : &_udc->ep0in;
- if (!list_empty(&mEp->qh.queue)) {
- _ep_nuke(mEp);
- retval = -EOVERFLOW;
- warn("endpoint ctrl %X nuked", _usb_addr(mEp));
- }
- }
-
- /* first nuke then test link, e.g. previous status has not sent */
- if (!list_empty(&mReq->queue)) {
- retval = -EBUSY;
- err("request already in queue");
- goto done;
- }
-
- if (req->length > (4 * CI13XXX_PAGE_SIZE)) {
- req->length = (4 * CI13XXX_PAGE_SIZE);
- retval = -EMSGSIZE;
- warn("request length truncated");
- }
-
- dbg_queue(_usb_addr(mEp), req, retval);
-
- /* push request */
- mReq->req.status = -EINPROGRESS;
- mReq->req.actual = 0;
-
- retval = _hardware_enqueue(mEp, mReq);
-
- if (retval == -EALREADY) {
- dbg_event(_usb_addr(mEp), "QUEUE", retval);
- retval = 0;
- }
- if (!retval)
- list_add_tail(&mReq->queue, &mEp->qh.queue);
-
- done:
- spin_unlock_irqrestore(mEp->lock, flags);
- return retval;
-}
-
-/**
- * ep_dequeue: dequeues (cancels, unlinks) an I/O request from an endpoint
- *
- * Check usb_ep_dequeue() at "usb_gadget.h" for details
- */
-static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
-{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req);
- unsigned long flags;
-
- trace("%p, %p", ep, req);
-
- if (ep == NULL || req == NULL || mReq->req.status != -EALREADY ||
- mEp->desc == NULL || list_empty(&mReq->queue) ||
- list_empty(&mEp->qh.queue))
- return -EINVAL;
-
- spin_lock_irqsave(mEp->lock, flags);
-
- dbg_event(_usb_addr(mEp), "DEQUEUE", 0);
-
- hw_ep_flush(mEp->num, mEp->dir);
-
- /* pop request */
- list_del_init(&mReq->queue);
- if (mReq->map) {
- dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length,
- mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- mReq->req.dma = DMA_ADDR_INVALID;
- mReq->map = 0;
- }
- req->status = -ECONNRESET;
-
- if (mReq->req.complete != NULL) {
- spin_unlock(mEp->lock);
- mReq->req.complete(&mEp->ep, &mReq->req);
- spin_lock(mEp->lock);
- }
-
- spin_unlock_irqrestore(mEp->lock, flags);
- return 0;
-}
-
-/**
- * ep_set_halt: sets the endpoint halt feature
- *
- * Check usb_ep_set_halt() at "usb_gadget.h" for details
- */
-static int ep_set_halt(struct usb_ep *ep, int value)
-{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- int direction, retval = 0;
- unsigned long flags;
-
- trace("%p, %i", ep, value);
-
- if (ep == NULL || mEp->desc == NULL)
- return -EINVAL;
-
- spin_lock_irqsave(mEp->lock, flags);
-
-#ifndef STALL_IN
- /* g_file_storage MS compliant but g_zero fails chapter 9 compliance */
- if (value && mEp->type == USB_ENDPOINT_XFER_BULK && mEp->dir == TX &&
- !list_empty(&mEp->qh.queue)) {
- spin_unlock_irqrestore(mEp->lock, flags);
- return -EAGAIN;
- }
-#endif
-
- direction = mEp->dir;
- do {
- dbg_event(_usb_addr(mEp), "HALT", value);
- retval |= hw_ep_set_halt(mEp->num, mEp->dir, value);
-
- if (!value)
- mEp->wedge = 0;
-
- if (mEp->type == USB_ENDPOINT_XFER_CONTROL)
- mEp->dir = (mEp->dir == TX) ? RX : TX;
-
- } while (mEp->dir != direction);
-
- spin_unlock_irqrestore(mEp->lock, flags);
- return retval;
-}
-
-/**
- * ep_set_wedge: sets the halt feature and ignores clear requests
- *
- * Check usb_ep_set_wedge() at "usb_gadget.h" for details
- */
-static int ep_set_wedge(struct usb_ep *ep)
-{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- unsigned long flags;
-
- trace("%p", ep);
-
- if (ep == NULL || mEp->desc == NULL)
- return -EINVAL;
-
- spin_lock_irqsave(mEp->lock, flags);
-
- dbg_event(_usb_addr(mEp), "WEDGE", 0);
- mEp->wedge = 1;
-
- spin_unlock_irqrestore(mEp->lock, flags);
-
- return usb_ep_set_halt(ep);
-}
-
-/**
- * ep_fifo_flush: flushes contents of a fifo
- *
- * Check usb_ep_fifo_flush() at "usb_gadget.h" for details
- */
-static void ep_fifo_flush(struct usb_ep *ep)
-{
- struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);
- unsigned long flags;
-
- trace("%p", ep);
-
- if (ep == NULL) {
- err("%02X: -EINVAL", _usb_addr(mEp));
- return;
- }
-
- spin_lock_irqsave(mEp->lock, flags);
-
- dbg_event(_usb_addr(mEp), "FFLUSH", 0);
- hw_ep_flush(mEp->num, mEp->dir);
-
- spin_unlock_irqrestore(mEp->lock, flags);
-}
-
-/**
- * Endpoint-specific part of the API to the USB controller hardware
- * Check "usb_gadget.h" for details
- */
-static const struct usb_ep_ops usb_ep_ops = {
- .enable = ep_enable,
- .disable = ep_disable,
- .alloc_request = ep_alloc_request,
- .free_request = ep_free_request,
- .queue = ep_queue,
- .dequeue = ep_dequeue,
- .set_halt = ep_set_halt,
- .set_wedge = ep_set_wedge,
- .fifo_flush = ep_fifo_flush,
-};
-
-/******************************************************************************
- * GADGET block
- *****************************************************************************/
-static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
-{
- struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
- unsigned long flags;
- int gadget_ready = 0;
-
- if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS))
- return -EOPNOTSUPP;
-
- spin_lock_irqsave(udc->lock, flags);
- udc->vbus_active = is_active;
- if (udc->driver)
- gadget_ready = 1;
- spin_unlock_irqrestore(udc->lock, flags);
-
- if (gadget_ready) {
- if (is_active) {
- pm_runtime_get_sync(&_gadget->dev);
- hw_device_reset(udc);
- hw_device_state(udc->ep0out.qh.dma);
- } else {
- hw_device_state(0);
- if (udc->udc_driver->notify_event)
- udc->udc_driver->notify_event(udc,
- CI13XXX_CONTROLLER_STOPPED_EVENT);
- _gadget_stop_activity(&udc->gadget);
- pm_runtime_put_sync(&_gadget->dev);
- }
- }
-
- return 0;
-}
-
-static int ci13xxx_wakeup(struct usb_gadget *_gadget)
-{
- struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
- unsigned long flags;
- int ret = 0;
-
- trace();
-
- spin_lock_irqsave(udc->lock, flags);
- if (!udc->remote_wakeup) {
- ret = -EOPNOTSUPP;
- trace("remote wakeup feature is not enabled\n");
- goto out;
- }
- if (!hw_cread(CAP_PORTSC, PORTSC_SUSP)) {
- ret = -EINVAL;
- trace("port is not suspended\n");
- goto out;
- }
- hw_cwrite(CAP_PORTSC, PORTSC_FPR, PORTSC_FPR);
-out:
- spin_unlock_irqrestore(udc->lock, flags);
- return ret;
-}
-
-static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
-{
- struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
-
- if (udc->transceiver)
- return usb_phy_set_power(udc->transceiver, mA);
- return -ENOTSUPP;
-}
-
-static int ci13xxx_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *));
-static int ci13xxx_stop(struct usb_gadget_driver *driver);
-/**
- * Device operations part of the API to the USB controller hardware,
- * which don't involve endpoints (or i/o)
- * Check "usb_gadget.h" for details
- */
-static const struct usb_gadget_ops usb_gadget_ops = {
- .vbus_session = ci13xxx_vbus_session,
- .wakeup = ci13xxx_wakeup,
- .vbus_draw = ci13xxx_vbus_draw,
- .start = ci13xxx_start,
- .stop = ci13xxx_stop,
-};
-
-/**
- * ci13xxx_start: register a gadget driver
- * @driver: the driver being registered
- * @bind: the driver's bind callback
- *
- * Check ci13xxx_start() at <linux/usb/gadget.h> for details.
- * Interrupts are enabled here.
- */
-static int ci13xxx_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *))
-{
- struct ci13xxx *udc = _udc;
- unsigned long flags;
- int i, j;
- int retval = -ENOMEM;
-
- trace("%p", driver);
-
- if (driver == NULL ||
- bind == NULL ||
- driver->setup == NULL ||
- driver->disconnect == NULL)
- return -EINVAL;
- else if (udc == NULL)
- return -ENODEV;
- else if (udc->driver != NULL)
- return -EBUSY;
-
- /* alloc resources */
- udc->qh_pool = dma_pool_create("ci13xxx_qh", &udc->gadget.dev,
- sizeof(struct ci13xxx_qh),
- 64, CI13XXX_PAGE_SIZE);
- if (udc->qh_pool == NULL)
- return -ENOMEM;
-
- udc->td_pool = dma_pool_create("ci13xxx_td", &udc->gadget.dev,
- sizeof(struct ci13xxx_td),
- 64, CI13XXX_PAGE_SIZE);
- if (udc->td_pool == NULL) {
- dma_pool_destroy(udc->qh_pool);
- udc->qh_pool = NULL;
- return -ENOMEM;
- }
-
- spin_lock_irqsave(udc->lock, flags);
-
- info("hw_ep_max = %d", hw_ep_max);
-
- udc->gadget.dev.driver = NULL;
-
- retval = 0;
- for (i = 0; i < hw_ep_max/2; i++) {
- for (j = RX; j <= TX; j++) {
- int k = i + j * hw_ep_max/2;
- struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[k];
-
- scnprintf(mEp->name, sizeof(mEp->name), "ep%i%s", i,
- (j == TX) ? "in" : "out");
-
- mEp->lock = udc->lock;
- mEp->device = &udc->gadget.dev;
- mEp->td_pool = udc->td_pool;
-
- mEp->ep.name = mEp->name;
- mEp->ep.ops = &usb_ep_ops;
- mEp->ep.maxpacket = CTRL_PAYLOAD_MAX;
-
- INIT_LIST_HEAD(&mEp->qh.queue);
- spin_unlock_irqrestore(udc->lock, flags);
- mEp->qh.ptr = dma_pool_alloc(udc->qh_pool, GFP_KERNEL,
- &mEp->qh.dma);
- spin_lock_irqsave(udc->lock, flags);
- if (mEp->qh.ptr == NULL)
- retval = -ENOMEM;
- else
- memset(mEp->qh.ptr, 0, sizeof(*mEp->qh.ptr));
-
- /* skip ep0 out and in endpoints */
- if (i == 0)
- continue;
-
- list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list);
- }
- }
- if (retval)
- goto done;
- spin_unlock_irqrestore(udc->lock, flags);
- udc->ep0out.ep.desc = &ctrl_endpt_out_desc;
- retval = usb_ep_enable(&udc->ep0out.ep);
- if (retval)
- return retval;
-
- udc->ep0in.ep.desc = &ctrl_endpt_in_desc;
- retval = usb_ep_enable(&udc->ep0in.ep);
- if (retval)
- return retval;
- spin_lock_irqsave(udc->lock, flags);
-
- udc->gadget.ep0 = &udc->ep0in.ep;
- /* bind gadget */
- driver->driver.bus = NULL;
- udc->gadget.dev.driver = &driver->driver;
-
- spin_unlock_irqrestore(udc->lock, flags);
- retval = bind(&udc->gadget); /* MAY SLEEP */
- spin_lock_irqsave(udc->lock, flags);
-
- if (retval) {
- udc->gadget.dev.driver = NULL;
- goto done;
- }
-
- udc->driver = driver;
- pm_runtime_get_sync(&udc->gadget.dev);
- if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) {
- if (udc->vbus_active) {
- if (udc->udc_driver->flags & CI13XXX_REGS_SHARED)
- hw_device_reset(udc);
- } else {
- pm_runtime_put_sync(&udc->gadget.dev);
- goto done;
- }
- }
-
- retval = hw_device_state(udc->ep0out.qh.dma);
- if (retval)
- pm_runtime_put_sync(&udc->gadget.dev);
-
- done:
- spin_unlock_irqrestore(udc->lock, flags);
- return retval;
-}
-
-/**
- * ci13xxx_stop: unregister a gadget driver
- *
- * Check usb_gadget_unregister_driver() at "usb_gadget.h" for details
- */
-static int ci13xxx_stop(struct usb_gadget_driver *driver)
-{
- struct ci13xxx *udc = _udc;
- unsigned long i, flags;
-
- trace("%p", driver);
-
- if (driver == NULL ||
- driver->unbind == NULL ||
- driver->setup == NULL ||
- driver->disconnect == NULL ||
- driver != udc->driver)
- return -EINVAL;
-
- spin_lock_irqsave(udc->lock, flags);
-
- if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) ||
- udc->vbus_active) {
- hw_device_state(0);
- if (udc->udc_driver->notify_event)
- udc->udc_driver->notify_event(udc,
- CI13XXX_CONTROLLER_STOPPED_EVENT);
- spin_unlock_irqrestore(udc->lock, flags);
- _gadget_stop_activity(&udc->gadget);
- spin_lock_irqsave(udc->lock, flags);
- pm_runtime_put(&udc->gadget.dev);
- }
-
- /* unbind gadget */
- spin_unlock_irqrestore(udc->lock, flags);
- driver->unbind(&udc->gadget); /* MAY SLEEP */
- spin_lock_irqsave(udc->lock, flags);
-
- udc->gadget.dev.driver = NULL;
-
- /* free resources */
- for (i = 0; i < hw_ep_max; i++) {
- struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
-
- if (!list_empty(&mEp->ep.ep_list))
- list_del_init(&mEp->ep.ep_list);
-
- if (mEp->qh.ptr != NULL)
- dma_pool_free(udc->qh_pool, mEp->qh.ptr, mEp->qh.dma);
- }
-
- udc->gadget.ep0 = NULL;
- udc->driver = NULL;
-
- spin_unlock_irqrestore(udc->lock, flags);
-
- if (udc->td_pool != NULL) {
- dma_pool_destroy(udc->td_pool);
- udc->td_pool = NULL;
- }
- if (udc->qh_pool != NULL) {
- dma_pool_destroy(udc->qh_pool);
- udc->qh_pool = NULL;
- }
-
- return 0;
-}
-
-/******************************************************************************
- * BUS block
- *****************************************************************************/
-/**
- * udc_irq: global interrupt handler
- *
- * This function returns IRQ_HANDLED if the IRQ has been handled
- * It locks access to registers
- */
-static irqreturn_t udc_irq(void)
-{
- struct ci13xxx *udc = _udc;
- irqreturn_t retval;
- u32 intr;
-
- trace();
-
- if (udc == NULL) {
- err("ENODEV");
- return IRQ_HANDLED;
- }
-
- spin_lock(udc->lock);
-
- if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) {
- if (hw_cread(CAP_USBMODE, USBMODE_CM) !=
- USBMODE_CM_DEVICE) {
- spin_unlock(udc->lock);
- return IRQ_NONE;
- }
- }
- intr = hw_test_and_clear_intr_active();
- if (intr) {
- isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intr;
- isr_statistics.hndl.idx &= ISR_MASK;
- isr_statistics.hndl.cnt++;
-
- /* order defines priority - do NOT change it */
- if (USBi_URI & intr) {
- isr_statistics.uri++;
- isr_reset_handler(udc);
- }
- if (USBi_PCI & intr) {
- isr_statistics.pci++;
- udc->gadget.speed = hw_port_is_high_speed() ?
- USB_SPEED_HIGH : USB_SPEED_FULL;
- if (udc->suspended && udc->driver->resume) {
- spin_unlock(udc->lock);
- udc->driver->resume(&udc->gadget);
- spin_lock(udc->lock);
- udc->suspended = 0;
- }
- }
- if (USBi_UEI & intr)
- isr_statistics.uei++;
- if (USBi_UI & intr) {
- isr_statistics.ui++;
- isr_tr_complete_handler(udc);
- }
- if (USBi_SLI & intr) {
- if (udc->gadget.speed != USB_SPEED_UNKNOWN &&
- udc->driver->suspend) {
- udc->suspended = 1;
- spin_unlock(udc->lock);
- udc->driver->suspend(&udc->gadget);
- spin_lock(udc->lock);
- }
- isr_statistics.sli++;
- }
- retval = IRQ_HANDLED;
- } else {
- isr_statistics.none++;
- retval = IRQ_NONE;
- }
- spin_unlock(udc->lock);
-
- return retval;
-}
-
-/**
- * udc_release: driver release function
- * @dev: device
- *
- * Currently does nothing
- */
-static void udc_release(struct device *dev)
-{
- trace("%p", dev);
-
- if (dev == NULL)
- err("EINVAL");
-}
-
-/**
- * udc_probe: parent probe must call this to initialize UDC
- * @dev: parent device
- * @regs: registers base address
- * @name: driver name
- *
- * This function returns an error code
- * No interrupts active, the IRQ has not been requested yet
- * Kernel assumes 32-bit DMA operations by default, no need to dma_set_mask
- */
-static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
- void __iomem *regs)
-{
- struct ci13xxx *udc;
- int retval = 0;
-
- trace("%p, %p, %p", dev, regs, driver->name);
-
- if (dev == NULL || regs == NULL || driver == NULL ||
- driver->name == NULL)
- return -EINVAL;
-
- udc = kzalloc(sizeof(struct ci13xxx), GFP_KERNEL);
- if (udc == NULL)
- return -ENOMEM;
-
- udc->lock = &udc_lock;
- udc->regs = regs;
- udc->udc_driver = driver;
-
- udc->gadget.ops = &usb_gadget_ops;
- udc->gadget.speed = USB_SPEED_UNKNOWN;
- udc->gadget.max_speed = USB_SPEED_HIGH;
- udc->gadget.is_otg = 0;
- udc->gadget.name = driver->name;
-
- INIT_LIST_HEAD(&udc->gadget.ep_list);
- udc->gadget.ep0 = NULL;
-
- dev_set_name(&udc->gadget.dev, "gadget");
- udc->gadget.dev.dma_mask = dev->dma_mask;
- udc->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask;
- udc->gadget.dev.parent = dev;
- udc->gadget.dev.release = udc_release;
-
- retval = hw_device_init(regs);
- if (retval < 0)
- goto free_udc;
-
- udc->transceiver = usb_get_transceiver();
-
- if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
- if (udc->transceiver == NULL) {
- retval = -ENODEV;
- goto free_udc;
- }
- }
-
- if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) {
- retval = hw_device_reset(udc);
- if (retval)
- goto put_transceiver;
- }
-
- retval = device_register(&udc->gadget.dev);
- if (retval) {
- put_device(&udc->gadget.dev);
- goto put_transceiver;
- }
-
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
- retval = dbg_create_files(&udc->gadget.dev);
-#endif
- if (retval)
- goto unreg_device;
-
- if (udc->transceiver) {
- retval = otg_set_peripheral(udc->transceiver->otg,
- &udc->gadget);
- if (retval)
- goto remove_dbg;
- }
-
- retval = usb_add_gadget_udc(dev, &udc->gadget);
- if (retval)
- goto remove_trans;
-
- pm_runtime_no_callbacks(&udc->gadget.dev);
- pm_runtime_enable(&udc->gadget.dev);
-
- _udc = udc;
- return retval;
-
-remove_trans:
- if (udc->transceiver) {
- otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
- usb_put_transceiver(udc->transceiver);
- }
-
- err("error = %i", retval);
-remove_dbg:
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
- dbg_remove_files(&udc->gadget.dev);
-#endif
-unreg_device:
- device_unregister(&udc->gadget.dev);
-put_transceiver:
- if (udc->transceiver)
- usb_put_transceiver(udc->transceiver);
-free_udc:
- kfree(udc);
- _udc = NULL;
- return retval;
-}
-
-/**
- * udc_remove: parent remove must call this to remove UDC
- *
- * No interrupts active, the IRQ has been released
- */
-static void udc_remove(void)
-{
- struct ci13xxx *udc = _udc;
-
- if (udc == NULL) {
- err("EINVAL");
- return;
- }
- usb_del_gadget_udc(&udc->gadget);
-
- if (udc->transceiver) {
- otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
- usb_put_transceiver(udc->transceiver);
- }
-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
- dbg_remove_files(&udc->gadget.dev);
-#endif
- device_unregister(&udc->gadget.dev);
-
- kfree(udc);
- _udc = NULL;
-}
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
deleted file mode 100644
index 0d31af56c989..000000000000
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * ci13xxx_udc.h - structures, registers, and macros MIPS USB IP core
- *
- * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
- *
- * Author: David Lopo
- *
- * 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.
- *
- * Description: MIPS USB IP core family device controller
- * Structures, registers and logging macros
- */
-
-#ifndef _CI13XXX_h_
-#define _CI13XXX_h_
-
-/******************************************************************************
- * DEFINE
- *****************************************************************************/
-#define CI13XXX_PAGE_SIZE 4096ul /* page size for TD's */
-#define ENDPT_MAX (32)
-#define CTRL_PAYLOAD_MAX (64)
-#define RX (0) /* similar to USB_DIR_OUT but can be used as an index */
-#define TX (1) /* similar to USB_DIR_IN but can be used as an index */
-
-/******************************************************************************
- * STRUCTURES
- *****************************************************************************/
-/* DMA layout of transfer descriptors */
-struct ci13xxx_td {
- /* 0 */
- u32 next;
-#define TD_TERMINATE BIT(0)
-#define TD_ADDR_MASK (0xFFFFFFEUL << 5)
- /* 1 */
- u32 token;
-#define TD_STATUS (0x00FFUL << 0)
-#define TD_STATUS_TR_ERR BIT(3)
-#define TD_STATUS_DT_ERR BIT(5)
-#define TD_STATUS_HALTED BIT(6)
-#define TD_STATUS_ACTIVE BIT(7)
-#define TD_MULTO (0x0003UL << 10)
-#define TD_IOC BIT(15)
-#define TD_TOTAL_BYTES (0x7FFFUL << 16)
- /* 2 */
- u32 page[5];
-#define TD_CURR_OFFSET (0x0FFFUL << 0)
-#define TD_FRAME_NUM (0x07FFUL << 0)
-#define TD_RESERVED_MASK (0x0FFFUL << 0)
-} __attribute__ ((packed));
-
-/* DMA layout of queue heads */
-struct ci13xxx_qh {
- /* 0 */
- u32 cap;
-#define QH_IOS BIT(15)
-#define QH_MAX_PKT (0x07FFUL << 16)
-#define QH_ZLT BIT(29)
-#define QH_MULT (0x0003UL << 30)
- /* 1 */
- u32 curr;
- /* 2 - 8 */
- struct ci13xxx_td td;
- /* 9 */
- u32 RESERVED;
- struct usb_ctrlrequest setup;
-} __attribute__ ((packed));
-
-/* Extension of usb_request */
-struct ci13xxx_req {
- struct usb_request req;
- unsigned map;
- struct list_head queue;
- struct ci13xxx_td *ptr;
- dma_addr_t dma;
- struct ci13xxx_td *zptr;
- dma_addr_t zdma;
-};
-
-/* Extension of usb_ep */
-struct ci13xxx_ep {
- struct usb_ep ep;
- const struct usb_endpoint_descriptor *desc;
- u8 dir;
- u8 num;
- u8 type;
- char name[16];
- struct {
- struct list_head queue;
- struct ci13xxx_qh *ptr;
- dma_addr_t dma;
- } qh;
- int wedge;
-
- /* global resources */
- spinlock_t *lock;
- struct device *device;
- struct dma_pool *td_pool;
-};
-
-struct ci13xxx;
-struct ci13xxx_udc_driver {
- const char *name;
- unsigned long flags;
-#define CI13XXX_REGS_SHARED BIT(0)
-#define CI13XXX_REQUIRE_TRANSCEIVER BIT(1)
-#define CI13XXX_PULLUP_ON_VBUS BIT(2)
-#define CI13XXX_DISABLE_STREAMING BIT(3)
-
-#define CI13XXX_CONTROLLER_RESET_EVENT 0
-#define CI13XXX_CONTROLLER_STOPPED_EVENT 1
- void (*notify_event) (struct ci13xxx *udc, unsigned event);
-};
-
-/* CI13XXX UDC descriptor & global resources */
-struct ci13xxx {
- spinlock_t *lock; /* ctrl register bank access */
- void __iomem *regs; /* registers address space */
-
- struct dma_pool *qh_pool; /* DMA pool for queue heads */
- struct dma_pool *td_pool; /* DMA pool for transfer descs */
- struct usb_request *status; /* ep0 status request */
-
- struct usb_gadget gadget; /* USB slave device */
- struct ci13xxx_ep ci13xxx_ep[ENDPT_MAX]; /* extended endpts */
- u32 ep0_dir; /* ep0 direction */
-#define ep0out ci13xxx_ep[0]
-#define ep0in ci13xxx_ep[hw_ep_max / 2]
- u8 remote_wakeup; /* Is remote wakeup feature
- enabled by the host? */
- u8 suspended; /* suspended by the host */
- u8 test_mode; /* the selected test mode */
-
- struct usb_gadget_driver *driver; /* 3rd party gadget driver */
- struct ci13xxx_udc_driver *udc_driver; /* device controller driver */
- int vbus_active; /* is VBUS active */
- struct usb_phy *transceiver; /* Transceiver struct */
-};
-
-/******************************************************************************
- * REGISTERS
- *****************************************************************************/
-/* register size */
-#define REG_BITS (32)
-
-/* HCCPARAMS */
-#define HCCPARAMS_LEN BIT(17)
-
-/* DCCPARAMS */
-#define DCCPARAMS_DEN (0x1F << 0)
-#define DCCPARAMS_DC BIT(7)
-
-/* TESTMODE */
-#define TESTMODE_FORCE BIT(0)
-
-/* USBCMD */
-#define USBCMD_RS BIT(0)
-#define USBCMD_RST BIT(1)
-#define USBCMD_SUTW BIT(13)
-#define USBCMD_ATDTW BIT(14)
-
-/* USBSTS & USBINTR */
-#define USBi_UI BIT(0)
-#define USBi_UEI BIT(1)
-#define USBi_PCI BIT(2)
-#define USBi_URI BIT(6)
-#define USBi_SLI BIT(8)
-
-/* DEVICEADDR */
-#define DEVICEADDR_USBADRA BIT(24)
-#define DEVICEADDR_USBADR (0x7FUL << 25)
-
-/* PORTSC */
-#define PORTSC_FPR BIT(6)
-#define PORTSC_SUSP BIT(7)
-#define PORTSC_HSP BIT(9)
-#define PORTSC_PTC (0x0FUL << 16)
-
-/* DEVLC */
-#define DEVLC_PSPD (0x03UL << 25)
-#define DEVLC_PSPD_HS (0x02UL << 25)
-
-/* USBMODE */
-#define USBMODE_CM (0x03UL << 0)
-#define USBMODE_CM_IDLE (0x00UL << 0)
-#define USBMODE_CM_DEVICE (0x02UL << 0)
-#define USBMODE_CM_HOST (0x03UL << 0)
-#define USBMODE_SLOM BIT(3)
-#define USBMODE_SDIS BIT(4)
-
-/* ENDPTCTRL */
-#define ENDPTCTRL_RXS BIT(0)
-#define ENDPTCTRL_RXT (0x03UL << 2)
-#define ENDPTCTRL_RXR BIT(6) /* reserved for port 0 */
-#define ENDPTCTRL_RXE BIT(7)
-#define ENDPTCTRL_TXS BIT(16)
-#define ENDPTCTRL_TXT (0x03UL << 18)
-#define ENDPTCTRL_TXR BIT(22) /* reserved for port 0 */
-#define ENDPTCTRL_TXE BIT(23)
-
-/******************************************************************************
- * LOGGING
- *****************************************************************************/
-#define ci13xxx_printk(level, format, args...) \
-do { \
- if (_udc == NULL) \
- printk(level "[%s] " format "\n", __func__, ## args); \
- else \
- dev_printk(level, _udc->gadget.dev.parent, \
- "[%s] " format "\n", __func__, ## args); \
-} while (0)
-
-#define err(format, args...) ci13xxx_printk(KERN_ERR, format, ## args)
-#define warn(format, args...) ci13xxx_printk(KERN_WARNING, format, ## args)
-#define info(format, args...) ci13xxx_printk(KERN_INFO, format, ## args)
-
-#ifdef TRACE
-#define trace(format, args...) ci13xxx_printk(KERN_DEBUG, format, ## args)
-#define dbg_trace(format, args...) dev_dbg(dev, format, ##args)
-#else
-#define trace(format, args...) do {} while (0)
-#define dbg_trace(format, args...) do {} while (0)
-#endif
-
-#endif /* _CI13XXX_h_ */
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index baaebf2830fc..390749bbb0c3 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -40,27 +40,27 @@ static int (*composite_gadget_bind)(struct usb_composite_dev *cdev);
*/
static ushort idVendor;
-module_param(idVendor, ushort, 0);
+module_param(idVendor, ushort, 0644);
MODULE_PARM_DESC(idVendor, "USB Vendor ID");
static ushort idProduct;
-module_param(idProduct, ushort, 0);
+module_param(idProduct, ushort, 0644);
MODULE_PARM_DESC(idProduct, "USB Product ID");
static ushort bcdDevice;
-module_param(bcdDevice, ushort, 0);
+module_param(bcdDevice, ushort, 0644);
MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
static char *iManufacturer;
-module_param(iManufacturer, charp, 0);
+module_param(iManufacturer, charp, 0644);
MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
static char *iProduct;
-module_param(iProduct, charp, 0);
+module_param(iProduct, charp, 0644);
MODULE_PARM_DESC(iProduct, "USB Product string");
static char *iSerialNumber;
-module_param(iSerialNumber, charp, 0);
+module_param(iSerialNumber, charp, 0644);
MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");
static char composite_manufacturer[50];
@@ -734,9 +734,23 @@ int usb_add_config(struct usb_composite_dev *cdev,
INIT_LIST_HEAD(&config->functions);
config->next_interface_id = 0;
+ memset(config->interface, 0, sizeof(config->interface));
status = bind(config);
if (status < 0) {
+ while (!list_empty(&config->functions)) {
+ struct usb_function *f;
+
+ f = list_first_entry(&config->functions,
+ struct usb_function, list);
+ list_del(&f->list);
+ if (f->unbind) {
+ DBG(cdev, "unbind function '%s'/%p\n",
+ f->name, f);
+ f->unbind(config, f);
+ /* may free memory for "f" */
+ }
+ }
list_del(&config->list);
config->cdev = NULL;
} else {
@@ -774,6 +788,53 @@ done:
return status;
}
+static void remove_config(struct usb_composite_dev *cdev,
+ struct usb_configuration *config)
+{
+ while (!list_empty(&config->functions)) {
+ struct usb_function *f;
+
+ f = list_first_entry(&config->functions,
+ struct usb_function, list);
+ list_del(&f->list);
+ if (f->unbind) {
+ DBG(cdev, "unbind function '%s'/%p\n", f->name, f);
+ f->unbind(config, f);
+ /* may free memory for "f" */
+ }
+ }
+ list_del(&config->list);
+ if (config->unbind) {
+ DBG(cdev, "unbind config '%s'/%p\n", config->label, config);
+ config->unbind(config);
+ /* may free memory for "c" */
+ }
+}
+
+/**
+ * usb_remove_config() - remove a configuration from a device.
+ * @cdev: wraps the USB gadget
+ * @config: the configuration
+ *
+ * Drivers must call usb_gadget_disconnect before calling this function
+ * to disconnect the device from the host and make sure the host will not
+ * try to enumerate the device while we are changing the config list.
+ */
+void usb_remove_config(struct usb_composite_dev *cdev,
+ struct usb_configuration *config)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cdev->lock, flags);
+
+ if (cdev->config == config)
+ reset_config(cdev);
+
+ spin_unlock_irqrestore(&cdev->lock, flags);
+
+ remove_config(cdev, config);
+}
+
/*-------------------------------------------------------------------------*/
/* We support strings in multiple languages ... string descriptor zero
@@ -785,7 +846,7 @@ done:
static void collect_langs(struct usb_gadget_strings **sp, __le16 *buf)
{
const struct usb_gadget_strings *s;
- u16 language;
+ __le16 language;
__le16 *tmp;
while (*sp) {
@@ -877,7 +938,7 @@ static int get_string(struct usb_composite_dev *cdev,
else if (cdev->product_override == id)
str = iProduct ?: composite->iProduct;
else if (cdev->serial_override == id)
- str = iSerialNumber;
+ str = iSerialNumber ?: composite->iSerialNumber;
else
str = NULL;
if (str) {
@@ -1328,28 +1389,9 @@ composite_unbind(struct usb_gadget *gadget)
while (!list_empty(&cdev->configs)) {
struct usb_configuration *c;
-
c = list_first_entry(&cdev->configs,
struct usb_configuration, list);
- while (!list_empty(&c->functions)) {
- struct usb_function *f;
-
- f = list_first_entry(&c->functions,
- struct usb_function, list);
- list_del(&f->list);
- if (f->unbind) {
- DBG(cdev, "unbind function '%s'/%p\n",
- f->name, f);
- f->unbind(c, f);
- /* may free memory for "f" */
- }
- }
- list_del(&c->list);
- if (c->unbind) {
- DBG(cdev, "unbind config '%s'/%p\n", c->label, c);
- c->unbind(c);
- /* may free memory for "c" */
- }
+ remove_config(cdev, c);
}
if (composite->unbind)
composite->unbind(cdev);
@@ -1431,10 +1473,16 @@ static int composite_bind(struct usb_gadget *gadget)
/* standardized runtime overrides for device ID data */
if (idVendor)
cdev->desc.idVendor = cpu_to_le16(idVendor);
+ else
+ idVendor = le16_to_cpu(cdev->desc.idVendor);
if (idProduct)
cdev->desc.idProduct = cpu_to_le16(idProduct);
+ else
+ idProduct = le16_to_cpu(cdev->desc.idProduct);
if (bcdDevice)
cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
+ else
+ bcdDevice = le16_to_cpu(cdev->desc.bcdDevice);
/* string overrides */
if (iManufacturer || !cdev->desc.iManufacturer) {
@@ -1455,7 +1503,8 @@ static int composite_bind(struct usb_gadget *gadget)
cdev->product_override =
override_id(cdev, &cdev->desc.iProduct);
- if (iSerialNumber)
+ if (iSerialNumber ||
+ (!cdev->desc.iSerialNumber && composite->iSerialNumber))
cdev->serial_override =
override_id(cdev, &cdev->desc.iSerialNumber);
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 170cbe89d9f8..b799106027ad 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -595,14 +595,12 @@ static struct usb_request *dummy_alloc_request(struct usb_ep *_ep,
static void dummy_free_request(struct usb_ep *_ep, struct usb_request *_req)
{
- struct dummy_ep *ep;
struct dummy_request *req;
- if (!_ep || !_req)
- return;
- ep = usb_ep_to_dummy_ep(_ep);
- if (!ep->desc && _ep->name != ep0name)
+ if (!_ep || !_req) {
+ WARN_ON(1);
return;
+ }
req = usb_request_to_dummy_request(_req);
WARN_ON(!list_empty(&req->queue));
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index f52cb1ae45d9..dcd1c7fbb016 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -1031,6 +1031,12 @@ struct ffs_sb_fill_data {
struct ffs_file_perms perms;
umode_t root_mode;
const char *dev_name;
+ union {
+ /* set by ffs_fs_mount(), read by ffs_sb_fill() */
+ void *private_data;
+ /* set by ffs_sb_fill(), read by ffs_fs_mount */
+ struct ffs_data *ffs_data;
+ };
};
static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)
@@ -1047,8 +1053,14 @@ static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)
goto Enomem;
ffs->sb = sb;
- ffs->dev_name = data->dev_name;
+ ffs->dev_name = kstrdup(data->dev_name, GFP_KERNEL);
+ if (unlikely(!ffs->dev_name))
+ goto Enomem;
ffs->file_perms = data->perms;
+ ffs->private_data = data->private_data;
+
+ /* used by the caller of this function */
+ data->ffs_data = ffs;
sb->s_fs_info = ffs;
sb->s_blocksize = PAGE_CACHE_SIZE;
@@ -1167,20 +1179,29 @@ ffs_fs_mount(struct file_system_type *t, int flags,
},
.root_mode = S_IFDIR | 0500,
};
+ struct dentry *rv;
int ret;
+ void *ffs_dev;
ENTER();
- ret = functionfs_check_dev_callback(dev_name);
- if (unlikely(ret < 0))
- return ERR_PTR(ret);
-
ret = ffs_fs_parse_opts(&data, opts);
if (unlikely(ret < 0))
return ERR_PTR(ret);
+ ffs_dev = functionfs_acquire_dev_callback(dev_name);
+ if (IS_ERR(ffs_dev))
+ return ffs_dev;
+
data.dev_name = dev_name;
- return mount_single(t, flags, &data, ffs_sb_fill);
+ data.private_data = ffs_dev;
+ rv = mount_nodev(t, flags, &data, ffs_sb_fill);
+
+ /* data.ffs_data is set by ffs_sb_fill */
+ if (IS_ERR(rv))
+ functionfs_release_dev_callback(data.ffs_data);
+
+ return rv;
}
static void
@@ -1189,8 +1210,10 @@ ffs_fs_kill_sb(struct super_block *sb)
ENTER();
kill_litter_super(sb);
- if (sb->s_fs_info)
+ if (sb->s_fs_info) {
+ functionfs_release_dev_callback(sb->s_fs_info);
ffs_data_put(sb->s_fs_info);
+ }
}
static struct file_system_type ffs_fs_type = {
@@ -1256,6 +1279,7 @@ static void ffs_data_put(struct ffs_data *ffs)
ffs_data_clear(ffs);
BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
waitqueue_active(&ffs->ep0req_completion.wait));
+ kfree(ffs->dev_name);
kfree(ffs);
}
}
@@ -1473,8 +1497,22 @@ static int functionfs_bind_config(struct usb_composite_dev *cdev,
static void ffs_func_free(struct ffs_function *func)
{
+ struct ffs_ep *ep = func->eps;
+ unsigned count = func->ffs->eps_count;
+ unsigned long flags;
+
ENTER();
+ /* cleanup after autoconfig */
+ spin_lock_irqsave(&func->ffs->eps_lock, flags);
+ do {
+ if (ep->ep && ep->req)
+ usb_ep_free_request(ep->ep, ep->req);
+ ep->req = NULL;
+ ++ep;
+ } while (--count);
+ spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
+
ffs_data_put(func->ffs);
kfree(func->eps);
diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c
index b2113420b806..3b3932c55361 100644
--- a/drivers/usb/gadget/f_hid.c
+++ b/drivers/usb/gadget/f_hid.c
@@ -374,7 +374,7 @@ static int hidg_setup(struct usb_function *f,
break;
default:
- VDBG(cdev, "Unknown decriptor request 0x%x\n",
+ VDBG(cdev, "Unknown descriptor request 0x%x\n",
value >> 8);
goto stall;
break;
diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c
index 2c0cd824c667..7275706caeb0 100644
--- a/drivers/usb/gadget/f_loopback.c
+++ b/drivers/usb/gadget/f_loopback.c
@@ -286,7 +286,7 @@ static void disable_loopback(struct f_loopback *loop)
struct usb_composite_dev *cdev;
cdev = loop->function.config->cdev;
- disable_endpoints(cdev, loop->in_ep, loop->out_ep);
+ disable_endpoints(cdev, loop->in_ep, loop->out_ep, NULL, NULL);
VDBG(cdev, "%s disabled\n", loop->function.name);
}
@@ -329,7 +329,7 @@ fail0:
* than 'buflen' bytes each.
*/
for (i = 0; i < qlen && result == 0; i++) {
- req = alloc_ep_req(ep);
+ req = alloc_ep_req(ep, 0);
if (req) {
req->complete = loopback_complete;
result = usb_ep_queue(ep, req, GFP_ATOMIC);
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index cb8c162cae5a..f67b453740bd 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -3110,13 +3110,6 @@ static int fsg_bind_config(struct usb_composite_dev *cdev,
return rc;
}
-static inline int __deprecated __maybe_unused
-fsg_add(struct usb_composite_dev *cdev, struct usb_configuration *c,
- struct fsg_common *common)
-{
- return fsg_bind_config(cdev, c, common);
-}
-
/************************* Module parameters *************************/
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index d4f823f463e9..b1681e45aca7 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -71,6 +71,8 @@ struct f_rndis {
struct gether port;
u8 ctrl_id, data_id;
u8 ethaddr[ETH_ALEN];
+ u32 vendorID;
+ const char *manufacturer;
int config;
struct usb_ep *notify;
@@ -768,12 +770,10 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);
rndis_set_host_mac(rndis->config, rndis->ethaddr);
-#if 0
-// FIXME
- if (rndis_set_param_vendor(rndis->config, vendorID,
- manufacturer))
- goto fail0;
-#endif
+ if (rndis->manufacturer && rndis->vendorID &&
+ rndis_set_param_vendor(rndis->config, rndis->vendorID,
+ rndis->manufacturer))
+ goto fail;
/* NOTE: all that is done without knowing or caring about
* the network link ... which is unavailable to this code
@@ -820,6 +820,7 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f)
rndis_deregister(rndis->config);
rndis_exit();
+ rndis_string_defs[0].id = 0;
if (gadget_is_superspeed(c->cdev->gadget))
usb_free_descriptors(f->ss_descriptors);
@@ -840,20 +841,9 @@ static inline bool can_support_rndis(struct usb_configuration *c)
return true;
}
-/**
- * rndis_bind_config - add RNDIS network link to a configuration
- * @c: the configuration to support the network link
- * @ethaddr: a buffer in which the ethernet address of the host side
- * side of the link was recorded
- * Context: single threaded during gadget setup
- *
- * Returns zero on success, else negative errno.
- *
- * Caller must have called @gether_setup(). Caller is also responsible
- * for calling @gether_cleanup() before module unload.
- */
int
-rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+ u32 vendorID, const char *manufacturer)
{
struct f_rndis *rndis;
int status;
@@ -898,6 +888,8 @@ rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
goto fail;
memcpy(rndis->ethaddr, ethaddr, ETH_ALEN);
+ rndis->vendorID = vendorID;
+ rndis->manufacturer = manufacturer;
/* RNDIS activates when the host changes this filter */
rndis->port.cdc_filter = 0;
diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c
index 7aa7ac82c02c..5c1b68b63c98 100644
--- a/drivers/usb/gadget/f_sourcesink.c
+++ b/drivers/usb/gadget/f_sourcesink.c
@@ -51,6 +51,9 @@ struct f_sourcesink {
struct usb_ep *in_ep;
struct usb_ep *out_ep;
+ struct usb_ep *iso_in_ep;
+ struct usb_ep *iso_out_ep;
+ int cur_alt;
};
static inline struct f_sourcesink *func_to_ss(struct usb_function *f)
@@ -59,18 +62,45 @@ static inline struct f_sourcesink *func_to_ss(struct usb_function *f)
}
static unsigned pattern;
-module_param(pattern, uint, 0);
-MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63 ");
+module_param(pattern, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63, 2 = none");
+
+static unsigned isoc_interval = 4;
+module_param(isoc_interval, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(isoc_interval, "1 - 16");
+
+static unsigned isoc_maxpacket = 1024;
+module_param(isoc_maxpacket, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(isoc_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)");
+
+static unsigned isoc_mult;
+module_param(isoc_mult, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(isoc_mult, "0 - 2 (hs/ss only)");
+
+static unsigned isoc_maxburst;
+module_param(isoc_maxburst, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)");
/*-------------------------------------------------------------------------*/
-static struct usb_interface_descriptor source_sink_intf = {
- .bLength = sizeof source_sink_intf,
+static struct usb_interface_descriptor source_sink_intf_alt0 = {
+ .bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
+ .bAlternateSetting = 0,
.bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- /* .iInterface = DYNAMIC */
+ /* .iInterface = DYNAMIC */
+};
+
+static struct usb_interface_descriptor source_sink_intf_alt1 = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ .bAlternateSetting = 1,
+ .bNumEndpoints = 4,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ /* .iInterface = DYNAMIC */
};
/* full speed support: */
@@ -91,10 +121,36 @@ static struct usb_endpoint_descriptor fs_sink_desc = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
+static struct usb_endpoint_descriptor fs_iso_source_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
+ .wMaxPacketSize = cpu_to_le16(1023),
+ .bInterval = 4,
+};
+
+static struct usb_endpoint_descriptor fs_iso_sink_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
+ .wMaxPacketSize = cpu_to_le16(1023),
+ .bInterval = 4,
+};
+
static struct usb_descriptor_header *fs_source_sink_descs[] = {
- (struct usb_descriptor_header *) &source_sink_intf,
+ (struct usb_descriptor_header *) &source_sink_intf_alt0,
(struct usb_descriptor_header *) &fs_sink_desc,
(struct usb_descriptor_header *) &fs_source_desc,
+ (struct usb_descriptor_header *) &source_sink_intf_alt1,
+#define FS_ALT_IFC_1_OFFSET 3
+ (struct usb_descriptor_header *) &fs_sink_desc,
+ (struct usb_descriptor_header *) &fs_source_desc,
+ (struct usb_descriptor_header *) &fs_iso_sink_desc,
+ (struct usb_descriptor_header *) &fs_iso_source_desc,
NULL,
};
@@ -116,10 +172,34 @@ static struct usb_endpoint_descriptor hs_sink_desc = {
.wMaxPacketSize = cpu_to_le16(512),
};
+static struct usb_endpoint_descriptor hs_iso_source_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
+ .wMaxPacketSize = cpu_to_le16(1024),
+ .bInterval = 4,
+};
+
+static struct usb_endpoint_descriptor hs_iso_sink_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
+ .wMaxPacketSize = cpu_to_le16(1024),
+ .bInterval = 4,
+};
+
static struct usb_descriptor_header *hs_source_sink_descs[] = {
- (struct usb_descriptor_header *) &source_sink_intf,
+ (struct usb_descriptor_header *) &source_sink_intf_alt0,
(struct usb_descriptor_header *) &hs_source_desc,
(struct usb_descriptor_header *) &hs_sink_desc,
+ (struct usb_descriptor_header *) &source_sink_intf_alt1,
+#define HS_ALT_IFC_1_OFFSET 3
+ (struct usb_descriptor_header *) &hs_source_desc,
+ (struct usb_descriptor_header *) &hs_sink_desc,
+ (struct usb_descriptor_header *) &hs_iso_source_desc,
+ (struct usb_descriptor_header *) &hs_iso_sink_desc,
NULL,
};
@@ -136,6 +216,7 @@ static struct usb_endpoint_descriptor ss_source_desc = {
struct usb_ss_ep_comp_descriptor ss_source_comp_desc = {
.bLength = USB_DT_SS_EP_COMP_SIZE,
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+
.bMaxBurst = 0,
.bmAttributes = 0,
.wBytesPerInterval = 0,
@@ -152,17 +233,64 @@ static struct usb_endpoint_descriptor ss_sink_desc = {
struct usb_ss_ep_comp_descriptor ss_sink_comp_desc = {
.bLength = USB_DT_SS_EP_COMP_SIZE,
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+
.bMaxBurst = 0,
.bmAttributes = 0,
.wBytesPerInterval = 0,
};
+static struct usb_endpoint_descriptor ss_iso_source_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
+ .wMaxPacketSize = cpu_to_le16(1024),
+ .bInterval = 4,
+};
+
+struct usb_ss_ep_comp_descriptor ss_iso_source_comp_desc = {
+ .bLength = USB_DT_SS_EP_COMP_SIZE,
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+
+ .bMaxBurst = 0,
+ .bmAttributes = 0,
+ .wBytesPerInterval = cpu_to_le16(1024),
+};
+
+static struct usb_endpoint_descriptor ss_iso_sink_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC,
+ .wMaxPacketSize = cpu_to_le16(1024),
+ .bInterval = 4,
+};
+
+struct usb_ss_ep_comp_descriptor ss_iso_sink_comp_desc = {
+ .bLength = USB_DT_SS_EP_COMP_SIZE,
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+
+ .bMaxBurst = 0,
+ .bmAttributes = 0,
+ .wBytesPerInterval = cpu_to_le16(1024),
+};
+
static struct usb_descriptor_header *ss_source_sink_descs[] = {
- (struct usb_descriptor_header *) &source_sink_intf,
+ (struct usb_descriptor_header *) &source_sink_intf_alt0,
(struct usb_descriptor_header *) &ss_source_desc,
(struct usb_descriptor_header *) &ss_source_comp_desc,
(struct usb_descriptor_header *) &ss_sink_desc,
(struct usb_descriptor_header *) &ss_sink_comp_desc,
+ (struct usb_descriptor_header *) &source_sink_intf_alt1,
+#define SS_ALT_IFC_1_OFFSET 5
+ (struct usb_descriptor_header *) &ss_source_desc,
+ (struct usb_descriptor_header *) &ss_source_comp_desc,
+ (struct usb_descriptor_header *) &ss_sink_desc,
+ (struct usb_descriptor_header *) &ss_sink_comp_desc,
+ (struct usb_descriptor_header *) &ss_iso_source_desc,
+ (struct usb_descriptor_header *) &ss_iso_source_comp_desc,
+ (struct usb_descriptor_header *) &ss_iso_sink_desc,
+ (struct usb_descriptor_header *) &ss_iso_sink_comp_desc,
NULL,
};
@@ -196,9 +324,10 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
id = usb_interface_id(c, f);
if (id < 0)
return id;
- source_sink_intf.bInterfaceNumber = id;
+ source_sink_intf_alt0.bInterfaceNumber = id;
+ source_sink_intf_alt1.bInterfaceNumber = id;
- /* allocate endpoints */
+ /* allocate bulk endpoints */
ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc);
if (!ss->in_ep) {
autoconf_fail:
@@ -213,12 +342,74 @@ autoconf_fail:
goto autoconf_fail;
ss->out_ep->driver_data = cdev; /* claim */
+ /* sanity check the isoc module parameters */
+ if (isoc_interval < 1)
+ isoc_interval = 1;
+ if (isoc_interval > 16)
+ isoc_interval = 16;
+ if (isoc_mult > 2)
+ isoc_mult = 2;
+ if (isoc_maxburst > 15)
+ isoc_maxburst = 15;
+
+ /* fill in the FS isoc descriptors from the module parameters */
+ fs_iso_source_desc.wMaxPacketSize = isoc_maxpacket > 1023 ?
+ 1023 : isoc_maxpacket;
+ fs_iso_source_desc.bInterval = isoc_interval;
+ fs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket > 1023 ?
+ 1023 : isoc_maxpacket;
+ fs_iso_sink_desc.bInterval = isoc_interval;
+
+ /* allocate iso endpoints */
+ ss->iso_in_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_source_desc);
+ if (!ss->iso_in_ep)
+ goto no_iso;
+ ss->iso_in_ep->driver_data = cdev; /* claim */
+
+ ss->iso_out_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_sink_desc);
+ if (ss->iso_out_ep) {
+ ss->iso_out_ep->driver_data = cdev; /* claim */
+ } else {
+ ss->iso_in_ep->driver_data = NULL;
+ ss->iso_in_ep = NULL;
+no_iso:
+ /*
+ * We still want to work even if the UDC doesn't have isoc
+ * endpoints, so null out the alt interface that contains
+ * them and continue.
+ */
+ fs_source_sink_descs[FS_ALT_IFC_1_OFFSET] = NULL;
+ hs_source_sink_descs[HS_ALT_IFC_1_OFFSET] = NULL;
+ ss_source_sink_descs[SS_ALT_IFC_1_OFFSET] = NULL;
+ }
+
+ if (isoc_maxpacket > 1024)
+ isoc_maxpacket = 1024;
+
/* support high speed hardware */
if (gadget_is_dualspeed(c->cdev->gadget)) {
hs_source_desc.bEndpointAddress =
fs_source_desc.bEndpointAddress;
hs_sink_desc.bEndpointAddress =
fs_sink_desc.bEndpointAddress;
+
+ /*
+ * Fill in the HS isoc descriptors from the module parameters.
+ * We assume that the user knows what they are doing and won't
+ * give parameters that their UDC doesn't support.
+ */
+ hs_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
+ hs_iso_source_desc.wMaxPacketSize |= isoc_mult << 11;
+ hs_iso_source_desc.bInterval = isoc_interval;
+ hs_iso_source_desc.bEndpointAddress =
+ fs_iso_source_desc.bEndpointAddress;
+
+ hs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket;
+ hs_iso_sink_desc.wMaxPacketSize |= isoc_mult << 11;
+ hs_iso_sink_desc.bInterval = isoc_interval;
+ hs_iso_sink_desc.bEndpointAddress =
+ fs_iso_sink_desc.bEndpointAddress;
+
f->hs_descriptors = hs_source_sink_descs;
}
@@ -228,13 +419,39 @@ autoconf_fail:
fs_source_desc.bEndpointAddress;
ss_sink_desc.bEndpointAddress =
fs_sink_desc.bEndpointAddress;
+
+ /*
+ * Fill in the SS isoc descriptors from the module parameters.
+ * We assume that the user knows what they are doing and won't
+ * give parameters that their UDC doesn't support.
+ */
+ ss_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
+ ss_iso_source_desc.bInterval = isoc_interval;
+ ss_iso_source_comp_desc.bmAttributes = isoc_mult;
+ ss_iso_source_comp_desc.bMaxBurst = isoc_maxburst;
+ ss_iso_source_comp_desc.wBytesPerInterval =
+ isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1);
+ ss_iso_source_desc.bEndpointAddress =
+ fs_iso_source_desc.bEndpointAddress;
+
+ ss_iso_sink_desc.wMaxPacketSize = isoc_maxpacket;
+ ss_iso_sink_desc.bInterval = isoc_interval;
+ ss_iso_sink_comp_desc.bmAttributes = isoc_mult;
+ ss_iso_sink_comp_desc.bMaxBurst = isoc_maxburst;
+ ss_iso_sink_comp_desc.wBytesPerInterval =
+ isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1);
+ ss_iso_sink_desc.bEndpointAddress =
+ fs_iso_sink_desc.bEndpointAddress;
+
f->ss_descriptors = ss_source_sink_descs;
}
- DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
+ DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s\n",
(gadget_is_superspeed(c->cdev->gadget) ? "super" :
(gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),
- f->name, ss->in_ep->name, ss->out_ep->name);
+ f->name, ss->in_ep->name, ss->out_ep->name,
+ ss->iso_in_ep ? ss->iso_in_ep->name : "<none>",
+ ss->iso_out_ep ? ss->iso_out_ep->name : "<none>");
return 0;
}
@@ -251,6 +468,9 @@ static int check_read_data(struct f_sourcesink *ss, struct usb_request *req)
u8 *buf = req->buf;
struct usb_composite_dev *cdev = ss->function.config->cdev;
+ if (pattern == 2)
+ return 0;
+
for (i = 0; i < req->actual; i++, buf++) {
switch (pattern) {
@@ -265,7 +485,7 @@ static int check_read_data(struct f_sourcesink *ss, struct usb_request *req)
* each usb transfer request should be. Resync is done
* with set_interface or set_config. (We *WANT* it to
* get quickly out of sync if controllers or their drivers
- * stutter for any reason, including buffer duplcation...)
+ * stutter for any reason, including buffer duplication...)
*/
case 1:
if (*buf == (u8)(i % 63))
@@ -292,21 +512,30 @@ static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
for (i = 0; i < req->length; i++)
*buf++ = (u8) (i % 63);
break;
+ case 2:
+ break;
}
}
static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
{
- struct f_sourcesink *ss = ep->driver_data;
- struct usb_composite_dev *cdev = ss->function.config->cdev;
- int status = req->status;
+ struct usb_composite_dev *cdev;
+ struct f_sourcesink *ss = ep->driver_data;
+ int status = req->status;
+
+ /* driver_data will be null if ep has been disabled */
+ if (!ss)
+ return;
+
+ cdev = ss->function.config->cdev;
switch (status) {
case 0: /* normal completion? */
if (ep == ss->out_ep) {
check_read_data(ss, req);
- memset(req->buf, 0x55, req->length);
+ if (pattern != 2)
+ memset(req->buf, 0x55, req->length);
} else
reinit_write_data(ep, req);
break;
@@ -344,32 +573,57 @@ static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
}
}
-static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in)
+static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,
+ bool is_iso, int speed)
{
struct usb_ep *ep;
struct usb_request *req;
- int status;
+ int i, size, status;
+
+ for (i = 0; i < 8; i++) {
+ if (is_iso) {
+ switch (speed) {
+ case USB_SPEED_SUPER:
+ size = isoc_maxpacket * (isoc_mult + 1) *
+ (isoc_maxburst + 1);
+ break;
+ case USB_SPEED_HIGH:
+ size = isoc_maxpacket * (isoc_mult + 1);
+ break;
+ default:
+ size = isoc_maxpacket > 1023 ?
+ 1023 : isoc_maxpacket;
+ break;
+ }
+ ep = is_in ? ss->iso_in_ep : ss->iso_out_ep;
+ req = alloc_ep_req(ep, size);
+ } else {
+ ep = is_in ? ss->in_ep : ss->out_ep;
+ req = alloc_ep_req(ep, 0);
+ }
- ep = is_in ? ss->in_ep : ss->out_ep;
- req = alloc_ep_req(ep);
- if (!req)
- return -ENOMEM;
+ if (!req)
+ return -ENOMEM;
- req->complete = source_sink_complete;
- if (is_in)
- reinit_write_data(ep, req);
- else
- memset(req->buf, 0x55, req->length);
+ req->complete = source_sink_complete;
+ if (is_in)
+ reinit_write_data(ep, req);
+ else if (pattern != 2)
+ memset(req->buf, 0x55, req->length);
- status = usb_ep_queue(ep, req, GFP_ATOMIC);
- if (status) {
- struct usb_composite_dev *cdev;
+ status = usb_ep_queue(ep, req, GFP_ATOMIC);
+ if (status) {
+ struct usb_composite_dev *cdev;
- cdev = ss->function.config->cdev;
- ERROR(cdev, "start %s %s --> %d\n",
- is_in ? "IN" : "OUT",
- ep->name, status);
- free_ep_req(ep, req);
+ cdev = ss->function.config->cdev;
+ ERROR(cdev, "start %s%s %s --> %d\n",
+ is_iso ? "ISO-" : "", is_in ? "IN" : "OUT",
+ ep->name, status);
+ free_ep_req(ep, req);
+ }
+
+ if (!is_iso)
+ break;
}
return status;
@@ -380,17 +634,20 @@ static void disable_source_sink(struct f_sourcesink *ss)
struct usb_composite_dev *cdev;
cdev = ss->function.config->cdev;
- disable_endpoints(cdev, ss->in_ep, ss->out_ep);
+ disable_endpoints(cdev, ss->in_ep, ss->out_ep, ss->iso_in_ep,
+ ss->iso_out_ep);
VDBG(cdev, "%s disabled\n", ss->function.name);
}
static int
-enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss)
+enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss,
+ int alt)
{
int result = 0;
+ int speed = cdev->gadget->speed;
struct usb_ep *ep;
- /* one endpoint writes (sources) zeroes IN (to the host) */
+ /* one bulk endpoint writes (sources) zeroes IN (to the host) */
ep = ss->in_ep;
result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
if (result)
@@ -400,7 +657,7 @@ enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss)
return result;
ep->driver_data = ss;
- result = source_sink_start_ep(ss, true);
+ result = source_sink_start_ep(ss, true, false, speed);
if (result < 0) {
fail:
ep = ss->in_ep;
@@ -409,7 +666,7 @@ fail:
return result;
}
- /* one endpoint reads (sinks) anything OUT (from the host) */
+ /* one bulk endpoint reads (sinks) anything OUT (from the host) */
ep = ss->out_ep;
result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
if (result)
@@ -419,27 +676,82 @@ fail:
goto fail;
ep->driver_data = ss;
- result = source_sink_start_ep(ss, false);
+ result = source_sink_start_ep(ss, false, false, speed);
if (result < 0) {
+fail2:
+ ep = ss->out_ep;
usb_ep_disable(ep);
ep->driver_data = NULL;
goto fail;
}
- DBG(cdev, "%s enabled\n", ss->function.name);
+ if (alt == 0)
+ goto out;
+
+ /* one iso endpoint writes (sources) zeroes IN (to the host) */
+ ep = ss->iso_in_ep;
+ if (ep) {
+ result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
+ if (result)
+ goto fail2;
+ result = usb_ep_enable(ep);
+ if (result < 0)
+ goto fail2;
+ ep->driver_data = ss;
+
+ result = source_sink_start_ep(ss, true, true, speed);
+ if (result < 0) {
+fail3:
+ ep = ss->iso_in_ep;
+ if (ep) {
+ usb_ep_disable(ep);
+ ep->driver_data = NULL;
+ }
+ goto fail2;
+ }
+ }
+
+ /* one iso endpoint reads (sinks) anything OUT (from the host) */
+ ep = ss->iso_out_ep;
+ if (ep) {
+ result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
+ if (result)
+ goto fail3;
+ result = usb_ep_enable(ep);
+ if (result < 0)
+ goto fail3;
+ ep->driver_data = ss;
+
+ result = source_sink_start_ep(ss, false, true, speed);
+ if (result < 0) {
+ usb_ep_disable(ep);
+ ep->driver_data = NULL;
+ goto fail3;
+ }
+ }
+out:
+ ss->cur_alt = alt;
+
+ DBG(cdev, "%s enabled, alt intf %d\n", ss->function.name, alt);
return result;
}
static int sourcesink_set_alt(struct usb_function *f,
unsigned intf, unsigned alt)
{
- struct f_sourcesink *ss = func_to_ss(f);
- struct usb_composite_dev *cdev = f->config->cdev;
+ struct f_sourcesink *ss = func_to_ss(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
- /* we know alt is zero */
if (ss->in_ep->driver_data)
disable_source_sink(ss);
- return enable_source_sink(cdev, ss);
+ return enable_source_sink(cdev, ss, alt);
+}
+
+static int sourcesink_get_alt(struct usb_function *f, unsigned intf)
+{
+ struct f_sourcesink *ss = func_to_ss(f);
+
+ return ss->cur_alt;
}
static void sourcesink_disable(struct usb_function *f)
@@ -465,6 +777,7 @@ static int __init sourcesink_bind_config(struct usb_configuration *c)
ss->function.bind = sourcesink_bind;
ss->function.unbind = sourcesink_unbind;
ss->function.set_alt = sourcesink_set_alt;
+ ss->function.get_alt = sourcesink_get_alt;
ss->function.disable = sourcesink_disable;
status = usb_add_function(c, &ss->function);
@@ -536,7 +849,7 @@ unknown:
req->length = value;
value = usb_ep_queue(c->cdev->gadget->ep0, req, GFP_ATOMIC);
if (value < 0)
- ERROR(c->cdev, "source/sinkc response, err %d\n",
+ ERROR(c->cdev, "source/sink response, err %d\n",
value);
}
@@ -545,12 +858,12 @@ unknown:
}
static struct usb_configuration sourcesink_driver = {
- .label = "source/sink",
- .strings = sourcesink_strings,
- .setup = sourcesink_setup,
- .bConfigurationValue = 3,
- .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
- /* .iConfiguration = DYNAMIC */
+ .label = "source/sink",
+ .strings = sourcesink_strings,
+ .setup = sourcesink_setup,
+ .bConfigurationValue = 3,
+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+ /* .iConfiguration = DYNAMIC */
};
/**
@@ -567,7 +880,8 @@ int __init sourcesink_add(struct usb_composite_dev *cdev, bool autoresume)
return id;
strings_sourcesink[0].id = id;
- source_sink_intf.iInterface = id;
+ source_sink_intf_alt0.iInterface = id;
+ source_sink_intf_alt1.iInterface = id;
sourcesink_driver.iConfiguration = id;
/* support autoresume for remote wakeup testing */
diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c
index 877a2c46672b..51881f3bd07a 100644
--- a/drivers/usb/gadget/fsl_qe_udc.c
+++ b/drivers/usb/gadget/fsl_qe_udc.c
@@ -71,9 +71,6 @@ static struct usb_endpoint_descriptor qe_ep0_desc = {
.wMaxPacketSize = USB_MAX_CTRL_PAYLOAD,
};
-/* it is initialized in probe() */
-static struct qe_udc *udc_controller;
-
/********************************************************************
* Internal Used Function Start
********************************************************************/
@@ -188,8 +185,8 @@ static int qe_ep0_stall(struct qe_udc *udc)
{
qe_eptx_stall_change(&udc->eps[0], 1);
qe_eprx_stall_change(&udc->eps[0], 1);
- udc_controller->ep0_state = WAIT_FOR_SETUP;
- udc_controller->ep0_dir = 0;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
return 0;
}
@@ -450,13 +447,13 @@ static int qe_ep_rxbd_update(struct qe_ep *ep)
ep->rxbuf_d = virt_to_phys((void *)ep->rxbuffer);
if (ep->rxbuf_d == DMA_ADDR_INVALID) {
- ep->rxbuf_d = dma_map_single(udc_controller->gadget.dev.parent,
+ ep->rxbuf_d = dma_map_single(ep->udc->gadget.dev.parent,
ep->rxbuffer,
size,
DMA_FROM_DEVICE);
ep->rxbufmap = 1;
} else {
- dma_sync_single_for_device(udc_controller->gadget.dev.parent,
+ dma_sync_single_for_device(ep->udc->gadget.dev.parent,
ep->rxbuf_d, size,
DMA_FROM_DEVICE);
ep->rxbufmap = 0;
@@ -489,10 +486,10 @@ static int qe_ep_register_init(struct qe_udc *udc, unsigned char pipe_num)
epparam = udc->ep_param[pipe_num];
usep = 0;
- logepnum = (ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+ logepnum = (ep->ep.desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
usep |= (logepnum << USB_EPNUM_SHIFT);
- switch (ep->desc->bmAttributes & 0x03) {
+ switch (ep->ep.desc->bmAttributes & 0x03) {
case USB_ENDPOINT_XFER_BULK:
usep |= USB_TRANS_BULK;
break;
@@ -644,7 +641,7 @@ static int qe_ep_init(struct qe_udc *udc,
/* initialize ep structure */
ep->ep.maxpacket = max;
ep->tm = (u8)(desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
- ep->desc = desc;
+ ep->ep.desc = desc;
ep->stopped = 0;
ep->init = 1;
@@ -698,14 +695,14 @@ en_done:
return -ENODEV;
}
-static inline void qe_usb_enable(void)
+static inline void qe_usb_enable(struct qe_udc *udc)
{
- setbits8(&udc_controller->usb_regs->usb_usmod, USB_MODE_EN);
+ setbits8(&udc->usb_regs->usb_usmod, USB_MODE_EN);
}
-static inline void qe_usb_disable(void)
+static inline void qe_usb_disable(struct qe_udc *udc)
{
- clrbits8(&udc_controller->usb_regs->usb_usmod, USB_MODE_EN);
+ clrbits8(&udc->usb_regs->usb_usmod, USB_MODE_EN);
}
/*----------------------------------------------------------------------------*
@@ -1599,7 +1596,7 @@ static int qe_ep_enable(struct usb_ep *_ep,
ep = container_of(_ep, struct qe_ep, ep);
/* catch various bogus parameters */
- if (!_ep || !desc || ep->desc || _ep->name == ep_name[0] ||
+ if (!_ep || !desc || ep->ep.desc || _ep->name == ep_name[0] ||
(desc->bDescriptorType != USB_DT_ENDPOINT))
return -EINVAL;
@@ -1629,7 +1626,7 @@ static int qe_ep_disable(struct usb_ep *_ep)
ep = container_of(_ep, struct qe_ep, ep);
udc = ep->udc;
- if (!_ep || !ep->desc) {
+ if (!_ep || !ep->ep.desc) {
dev_dbg(udc->dev, "%s not enabled\n", _ep ? ep->ep.name : NULL);
return -EINVAL;
}
@@ -1637,7 +1634,6 @@ static int qe_ep_disable(struct usb_ep *_ep)
spin_lock_irqsave(&udc->lock, flags);
/* Nuke all pending requests (does flush) */
nuke(ep, -ESHUTDOWN);
- ep->desc = NULL;
ep->ep.desc = NULL;
ep->stopped = 1;
ep->tx_req = NULL;
@@ -1656,13 +1652,13 @@ static int qe_ep_disable(struct usb_ep *_ep)
if (ep->dir != USB_DIR_IN) {
kfree(ep->rxframe);
if (ep->rxbufmap) {
- dma_unmap_single(udc_controller->gadget.dev.parent,
+ dma_unmap_single(udc->gadget.dev.parent,
ep->rxbuf_d, size,
DMA_FROM_DEVICE);
ep->rxbuf_d = DMA_ADDR_INVALID;
} else {
dma_sync_single_for_cpu(
- udc_controller->gadget.dev.parent,
+ udc->gadget.dev.parent,
ep->rxbuf_d, size,
DMA_FROM_DEVICE);
}
@@ -1715,7 +1711,7 @@ static int __qe_ep_queue(struct usb_ep *_ep, struct usb_request *_req)
dev_dbg(udc->dev, "bad params\n");
return -EINVAL;
}
- if (!_ep || (!ep->desc && ep_index(ep))) {
+ if (!_ep || (!ep->ep.desc && ep_index(ep))) {
dev_dbg(udc->dev, "bad ep\n");
return -EINVAL;
}
@@ -1826,7 +1822,7 @@ static int qe_ep_set_halt(struct usb_ep *_ep, int value)
struct qe_udc *udc;
ep = container_of(_ep, struct qe_ep, ep);
- if (!_ep || !ep->desc) {
+ if (!_ep || !ep->ep.desc) {
status = -EINVAL;
goto out;
}
@@ -1880,9 +1876,10 @@ static struct usb_ep_ops qe_ep_ops = {
/* Get the current frame number */
static int qe_get_frame(struct usb_gadget *gadget)
{
+ struct qe_udc *udc = container_of(gadget, struct qe_udc, gadget);
u16 tmp;
- tmp = in_be16(&udc_controller->usb_param->frame_n);
+ tmp = in_be16(&udc->usb_param->frame_n);
if (tmp & 0x8000)
tmp = tmp & 0x07ff;
else
@@ -1891,57 +1888,16 @@ static int qe_get_frame(struct usb_gadget *gadget)
return (int)tmp;
}
-/* Tries to wake up the host connected to this gadget
- *
- * Return : 0-success
- * Negative-this feature not enabled by host or not supported by device hw
- */
-static int qe_wakeup(struct usb_gadget *gadget)
-{
- return -ENOTSUPP;
-}
-
-/* Notify controller that VBUS is powered, Called by whatever
- detects VBUS sessions */
-static int qe_vbus_session(struct usb_gadget *gadget, int is_active)
-{
- return -ENOTSUPP;
-}
-
-/* constrain controller's VBUS power usage
- * This call is used by gadget drivers during SET_CONFIGURATION calls,
- * reporting how much power the device may consume. For example, this
- * could affect how quickly batteries are recharged.
- *
- * Returns zero on success, else negative errno.
- */
-static int qe_vbus_draw(struct usb_gadget *gadget, unsigned mA)
-{
- return -ENOTSUPP;
-}
-
-/* Change Data+ pullup status
- * this func is used by usb_gadget_connect/disconnect
- */
-static int qe_pullup(struct usb_gadget *gadget, int is_on)
-{
- return -ENOTSUPP;
-}
-
-static int fsl_qe_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *));
-static int fsl_qe_stop(struct usb_gadget_driver *driver);
+static int fsl_qe_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
+static int fsl_qe_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
/* defined in usb_gadget.h */
static struct usb_gadget_ops qe_gadget_ops = {
.get_frame = qe_get_frame,
- .wakeup = qe_wakeup,
-/* .set_selfpowered = qe_set_selfpowered,*/ /* always selfpowered */
- .vbus_session = qe_vbus_session,
- .vbus_draw = qe_vbus_draw,
- .pullup = qe_pullup,
- .start = fsl_qe_start,
- .stop = fsl_qe_stop,
+ .udc_start = fsl_qe_start,
+ .udc_stop = fsl_qe_stop,
};
/*-------------------------------------------------------------------------
@@ -2015,7 +1971,7 @@ static void ch9getstatus(struct qe_udc *udc, u8 request_type, u16 value,
u16 usep;
/* stall if endpoint doesn't exist */
- if (!target_ep->desc)
+ if (!target_ep->ep.desc)
goto stall;
usep = in_be16(&udc->usb_regs->usb_usep[pipe]);
@@ -2190,7 +2146,7 @@ static int reset_irq(struct qe_udc *udc)
if (udc->usb_state == USB_STATE_DEFAULT)
return 0;
- qe_usb_disable();
+ qe_usb_disable(udc);
out_8(&udc->usb_regs->usb_usadr, 0);
for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
@@ -2202,7 +2158,7 @@ static int reset_irq(struct qe_udc *udc)
udc->usb_state = USB_STATE_DEFAULT;
udc->ep0_state = WAIT_FOR_SETUP;
udc->ep0_dir = USB_DIR_OUT;
- qe_usb_enable();
+ qe_usb_enable(udc);
return 0;
}
@@ -2327,92 +2283,65 @@ static irqreturn_t qe_udc_irq(int irq, void *_udc)
/*-------------------------------------------------------------------------
Gadget driver probe and unregister.
--------------------------------------------------------------------------*/
-static int fsl_qe_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *))
+static int fsl_qe_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
- int retval;
- unsigned long flags = 0;
-
- /* standard operations */
- if (!udc_controller)
- return -ENODEV;
-
- if (!driver || driver->max_speed < USB_SPEED_FULL
- || !bind || !driver->disconnect || !driver->setup)
- return -EINVAL;
-
- if (udc_controller->driver)
- return -EBUSY;
+ struct qe_udc *udc;
+ unsigned long flags;
+ udc = container_of(gadget, struct qe_udc, gadget);
/* lock is needed but whether should use this lock or another */
- spin_lock_irqsave(&udc_controller->lock, flags);
+ spin_lock_irqsave(&udc->lock, flags);
driver->driver.bus = NULL;
/* hook up the driver */
- udc_controller->driver = driver;
- udc_controller->gadget.dev.driver = &driver->driver;
- udc_controller->gadget.speed = driver->max_speed;
- spin_unlock_irqrestore(&udc_controller->lock, flags);
-
- retval = bind(&udc_controller->gadget);
- if (retval) {
- dev_err(udc_controller->dev, "bind to %s --> %d",
- driver->driver.name, retval);
- udc_controller->gadget.dev.driver = NULL;
- udc_controller->driver = NULL;
- return retval;
- }
+ udc->driver = driver;
+ udc->gadget.dev.driver = &driver->driver;
+ udc->gadget.speed = driver->max_speed;
/* Enable IRQ reg and Set usbcmd reg EN bit */
- qe_usb_enable();
-
- out_be16(&udc_controller->usb_regs->usb_usber, 0xffff);
- out_be16(&udc_controller->usb_regs->usb_usbmr, USB_E_DEFAULT_DEVICE);
- udc_controller->usb_state = USB_STATE_ATTACHED;
- udc_controller->ep0_state = WAIT_FOR_SETUP;
- udc_controller->ep0_dir = USB_DIR_OUT;
- dev_info(udc_controller->dev, "%s bind to driver %s \n",
- udc_controller->gadget.name, driver->driver.name);
+ qe_usb_enable(udc);
+
+ out_be16(&udc->usb_regs->usb_usber, 0xffff);
+ out_be16(&udc->usb_regs->usb_usbmr, USB_E_DEFAULT_DEVICE);
+ udc->usb_state = USB_STATE_ATTACHED;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = USB_DIR_OUT;
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ dev_info(udc->dev, "%s bind to driver %s\n", udc->gadget.name,
+ driver->driver.name);
return 0;
}
-static int fsl_qe_stop(struct usb_gadget_driver *driver)
+static int fsl_qe_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
+ struct qe_udc *udc;
struct qe_ep *loop_ep;
unsigned long flags;
- if (!udc_controller)
- return -ENODEV;
-
- if (!driver || driver != udc_controller->driver)
- return -EINVAL;
-
+ udc = container_of(gadget, struct qe_udc, gadget);
/* stop usb controller, disable intr */
- qe_usb_disable();
+ qe_usb_disable(udc);
/* in fact, no needed */
- udc_controller->usb_state = USB_STATE_ATTACHED;
- udc_controller->ep0_state = WAIT_FOR_SETUP;
- udc_controller->ep0_dir = 0;
+ udc->usb_state = USB_STATE_ATTACHED;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
/* stand operation */
- spin_lock_irqsave(&udc_controller->lock, flags);
- udc_controller->gadget.speed = USB_SPEED_UNKNOWN;
- nuke(&udc_controller->eps[0], -ESHUTDOWN);
- list_for_each_entry(loop_ep, &udc_controller->gadget.ep_list,
- ep.ep_list)
+ spin_lock_irqsave(&udc->lock, flags);
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ nuke(&udc->eps[0], -ESHUTDOWN);
+ list_for_each_entry(loop_ep, &udc->gadget.ep_list, ep.ep_list)
nuke(loop_ep, -ESHUTDOWN);
- spin_unlock_irqrestore(&udc_controller->lock, flags);
-
- /* report disconnect; the controller is already quiesced */
- driver->disconnect(&udc_controller->gadget);
+ spin_unlock_irqrestore(&udc->lock, flags);
- /* unbind gadget and unhook driver. */
- driver->unbind(&udc_controller->gadget);
- udc_controller->gadget.dev.driver = NULL;
- udc_controller->driver = NULL;
+ udc->gadget.dev.driver = NULL;
+ udc->driver = NULL;
- dev_info(udc_controller->dev, "unregistered gadget driver '%s'\r\n",
+ dev_info(udc->dev, "unregistered gadget driver '%s'\r\n",
driver->driver.name);
return 0;
}
@@ -2502,7 +2431,7 @@ static int __devinit qe_ep_config(struct qe_udc *udc, unsigned char pipe_num)
ep->ep.ops = &qe_ep_ops;
ep->stopped = 1;
ep->ep.maxpacket = (unsigned short) ~0;
- ep->desc = NULL;
+ ep->ep.desc = NULL;
ep->dir = 0xff;
ep->epnum = (u8)pipe_num;
ep->sent = 0;
@@ -2531,21 +2460,22 @@ static int __devinit qe_ep_config(struct qe_udc *udc, unsigned char pipe_num)
*----------------------------------------------------------------------*/
static void qe_udc_release(struct device *dev)
{
- int i = 0;
+ struct qe_udc *udc = container_of(dev, struct qe_udc, gadget.dev);
+ int i;
- complete(udc_controller->done);
- cpm_muram_free(cpm_muram_offset(udc_controller->ep_param[0]));
+ complete(udc->done);
+ cpm_muram_free(cpm_muram_offset(udc->ep_param[0]));
for (i = 0; i < USB_MAX_ENDPOINTS; i++)
- udc_controller->ep_param[i] = NULL;
+ udc->ep_param[i] = NULL;
- kfree(udc_controller);
- udc_controller = NULL;
+ kfree(udc);
}
/* Driver probe functions */
static const struct of_device_id qe_udc_match[];
static int __devinit qe_udc_probe(struct platform_device *ofdev)
{
+ struct qe_udc *udc;
const struct of_device_id *match;
struct device_node *np = ofdev->dev.of_node;
struct qe_ep *ep;
@@ -2562,44 +2492,44 @@ static int __devinit qe_udc_probe(struct platform_device *ofdev)
return -ENODEV;
/* Initialize the udc structure including QH member and other member */
- udc_controller = qe_udc_config(ofdev);
- if (!udc_controller) {
+ udc = qe_udc_config(ofdev);
+ if (!udc) {
dev_err(&ofdev->dev, "failed to initialize\n");
return -ENOMEM;
}
- udc_controller->soc_type = (unsigned long)match->data;
- udc_controller->usb_regs = of_iomap(np, 0);
- if (!udc_controller->usb_regs) {
+ udc->soc_type = (unsigned long)match->data;
+ udc->usb_regs = of_iomap(np, 0);
+ if (!udc->usb_regs) {
ret = -ENOMEM;
goto err1;
}
/* initialize usb hw reg except for regs for EP,
* leave usbintr reg untouched*/
- qe_udc_reg_init(udc_controller);
+ qe_udc_reg_init(udc);
/* here comes the stand operations for probe
* set the qe_udc->gadget.xxx */
- udc_controller->gadget.ops = &qe_gadget_ops;
+ udc->gadget.ops = &qe_gadget_ops;
/* gadget.ep0 is a pointer */
- udc_controller->gadget.ep0 = &udc_controller->eps[0].ep;
+ udc->gadget.ep0 = &udc->eps[0].ep;
- INIT_LIST_HEAD(&udc_controller->gadget.ep_list);
+ INIT_LIST_HEAD(&udc->gadget.ep_list);
/* modify in register gadget process */
- udc_controller->gadget.speed = USB_SPEED_UNKNOWN;
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
/* name: Identifies the controller hardware type. */
- udc_controller->gadget.name = driver_name;
+ udc->gadget.name = driver_name;
- device_initialize(&udc_controller->gadget.dev);
+ device_initialize(&udc->gadget.dev);
- dev_set_name(&udc_controller->gadget.dev, "gadget");
+ dev_set_name(&udc->gadget.dev, "gadget");
- udc_controller->gadget.dev.release = qe_udc_release;
- udc_controller->gadget.dev.parent = &ofdev->dev;
+ udc->gadget.dev.release = qe_udc_release;
+ udc->gadget.dev.parent = &ofdev->dev;
/* initialize qe_ep struct */
for (i = 0; i < USB_MAX_ENDPOINTS ; i++) {
@@ -2608,104 +2538,104 @@ static int __devinit qe_udc_probe(struct platform_device *ofdev)
/* setup the qe_ep struct and link ep.ep.list
* into gadget.ep_list */
- qe_ep_config(udc_controller, (unsigned char)i);
+ qe_ep_config(udc, (unsigned char)i);
}
/* ep0 initialization in here */
- ret = qe_ep_init(udc_controller, 0, &qe_ep0_desc);
+ ret = qe_ep_init(udc, 0, &qe_ep0_desc);
if (ret)
goto err2;
/* create a buf for ZLP send, need to remain zeroed */
- udc_controller->nullbuf = kzalloc(256, GFP_KERNEL);
- if (udc_controller->nullbuf == NULL) {
- dev_err(udc_controller->dev, "cannot alloc nullbuf\n");
+ udc->nullbuf = kzalloc(256, GFP_KERNEL);
+ if (udc->nullbuf == NULL) {
+ dev_err(udc->dev, "cannot alloc nullbuf\n");
ret = -ENOMEM;
goto err3;
}
/* buffer for data of get_status request */
- udc_controller->statusbuf = kzalloc(2, GFP_KERNEL);
- if (udc_controller->statusbuf == NULL) {
+ udc->statusbuf = kzalloc(2, GFP_KERNEL);
+ if (udc->statusbuf == NULL) {
ret = -ENOMEM;
goto err4;
}
- udc_controller->nullp = virt_to_phys((void *)udc_controller->nullbuf);
- if (udc_controller->nullp == DMA_ADDR_INVALID) {
- udc_controller->nullp = dma_map_single(
- udc_controller->gadget.dev.parent,
- udc_controller->nullbuf,
+ udc->nullp = virt_to_phys((void *)udc->nullbuf);
+ if (udc->nullp == DMA_ADDR_INVALID) {
+ udc->nullp = dma_map_single(
+ udc->gadget.dev.parent,
+ udc->nullbuf,
256,
DMA_TO_DEVICE);
- udc_controller->nullmap = 1;
+ udc->nullmap = 1;
} else {
- dma_sync_single_for_device(udc_controller->gadget.dev.parent,
- udc_controller->nullp, 256,
+ dma_sync_single_for_device(udc->gadget.dev.parent,
+ udc->nullp, 256,
DMA_TO_DEVICE);
}
- tasklet_init(&udc_controller->rx_tasklet, ep_rx_tasklet,
- (unsigned long)udc_controller);
+ tasklet_init(&udc->rx_tasklet, ep_rx_tasklet,
+ (unsigned long)udc);
/* request irq and disable DR */
- udc_controller->usb_irq = irq_of_parse_and_map(np, 0);
- if (!udc_controller->usb_irq) {
+ udc->usb_irq = irq_of_parse_and_map(np, 0);
+ if (!udc->usb_irq) {
ret = -EINVAL;
goto err_noirq;
}
- ret = request_irq(udc_controller->usb_irq, qe_udc_irq, 0,
- driver_name, udc_controller);
+ ret = request_irq(udc->usb_irq, qe_udc_irq, 0,
+ driver_name, udc);
if (ret) {
- dev_err(udc_controller->dev, "cannot request irq %d err %d \n",
- udc_controller->usb_irq, ret);
+ dev_err(udc->dev, "cannot request irq %d err %d\n",
+ udc->usb_irq, ret);
goto err5;
}
- ret = device_add(&udc_controller->gadget.dev);
+ ret = device_add(&udc->gadget.dev);
if (ret)
goto err6;
- ret = usb_add_gadget_udc(&ofdev->dev, &udc_controller->gadget);
+ ret = usb_add_gadget_udc(&ofdev->dev, &udc->gadget);
if (ret)
goto err7;
- dev_info(udc_controller->dev,
+ dev_set_drvdata(&ofdev->dev, udc);
+ dev_info(udc->dev,
"%s USB controller initialized as device\n",
- (udc_controller->soc_type == PORT_QE) ? "QE" : "CPM");
+ (udc->soc_type == PORT_QE) ? "QE" : "CPM");
return 0;
err7:
- device_unregister(&udc_controller->gadget.dev);
+ device_unregister(&udc->gadget.dev);
err6:
- free_irq(udc_controller->usb_irq, udc_controller);
+ free_irq(udc->usb_irq, udc);
err5:
- irq_dispose_mapping(udc_controller->usb_irq);
+ irq_dispose_mapping(udc->usb_irq);
err_noirq:
- if (udc_controller->nullmap) {
- dma_unmap_single(udc_controller->gadget.dev.parent,
- udc_controller->nullp, 256,
+ if (udc->nullmap) {
+ dma_unmap_single(udc->gadget.dev.parent,
+ udc->nullp, 256,
DMA_TO_DEVICE);
- udc_controller->nullp = DMA_ADDR_INVALID;
+ udc->nullp = DMA_ADDR_INVALID;
} else {
- dma_sync_single_for_cpu(udc_controller->gadget.dev.parent,
- udc_controller->nullp, 256,
+ dma_sync_single_for_cpu(udc->gadget.dev.parent,
+ udc->nullp, 256,
DMA_TO_DEVICE);
}
- kfree(udc_controller->statusbuf);
+ kfree(udc->statusbuf);
err4:
- kfree(udc_controller->nullbuf);
+ kfree(udc->nullbuf);
err3:
- ep = &udc_controller->eps[0];
+ ep = &udc->eps[0];
cpm_muram_free(cpm_muram_offset(ep->rxbase));
kfree(ep->rxframe);
kfree(ep->rxbuffer);
kfree(ep->txframe);
err2:
- iounmap(udc_controller->usb_regs);
+ iounmap(udc->usb_regs);
err1:
- kfree(udc_controller);
- udc_controller = NULL;
+ kfree(udc);
return ret;
}
@@ -2723,44 +2653,41 @@ static int qe_udc_resume(struct platform_device *dev)
static int __devexit qe_udc_remove(struct platform_device *ofdev)
{
+ struct qe_udc *udc = dev_get_drvdata(&ofdev->dev);
struct qe_ep *ep;
unsigned int size;
-
DECLARE_COMPLETION(done);
- if (!udc_controller)
- return -ENODEV;
-
- usb_del_gadget_udc(&udc_controller->gadget);
+ usb_del_gadget_udc(&udc->gadget);
- udc_controller->done = &done;
- tasklet_disable(&udc_controller->rx_tasklet);
+ udc->done = &done;
+ tasklet_disable(&udc->rx_tasklet);
- if (udc_controller->nullmap) {
- dma_unmap_single(udc_controller->gadget.dev.parent,
- udc_controller->nullp, 256,
+ if (udc->nullmap) {
+ dma_unmap_single(udc->gadget.dev.parent,
+ udc->nullp, 256,
DMA_TO_DEVICE);
- udc_controller->nullp = DMA_ADDR_INVALID;
+ udc->nullp = DMA_ADDR_INVALID;
} else {
- dma_sync_single_for_cpu(udc_controller->gadget.dev.parent,
- udc_controller->nullp, 256,
+ dma_sync_single_for_cpu(udc->gadget.dev.parent,
+ udc->nullp, 256,
DMA_TO_DEVICE);
}
- kfree(udc_controller->statusbuf);
- kfree(udc_controller->nullbuf);
+ kfree(udc->statusbuf);
+ kfree(udc->nullbuf);
- ep = &udc_controller->eps[0];
+ ep = &udc->eps[0];
cpm_muram_free(cpm_muram_offset(ep->rxbase));
size = (ep->ep.maxpacket + USB_CRC_SIZE + 2) * (USB_BDRING_LEN + 1);
kfree(ep->rxframe);
if (ep->rxbufmap) {
- dma_unmap_single(udc_controller->gadget.dev.parent,
+ dma_unmap_single(udc->gadget.dev.parent,
ep->rxbuf_d, size,
DMA_FROM_DEVICE);
ep->rxbuf_d = DMA_ADDR_INVALID;
} else {
- dma_sync_single_for_cpu(udc_controller->gadget.dev.parent,
+ dma_sync_single_for_cpu(udc->gadget.dev.parent,
ep->rxbuf_d, size,
DMA_FROM_DEVICE);
}
@@ -2768,14 +2695,14 @@ static int __devexit qe_udc_remove(struct platform_device *ofdev)
kfree(ep->rxbuffer);
kfree(ep->txframe);
- free_irq(udc_controller->usb_irq, udc_controller);
- irq_dispose_mapping(udc_controller->usb_irq);
+ free_irq(udc->usb_irq, udc);
+ irq_dispose_mapping(udc->usb_irq);
- tasklet_kill(&udc_controller->rx_tasklet);
+ tasklet_kill(&udc->rx_tasklet);
- iounmap(udc_controller->usb_regs);
+ iounmap(udc->usb_regs);
- device_unregister(&udc_controller->gadget.dev);
+ device_unregister(&udc->gadget.dev);
/* wait for release() of gadget.dev to free udc */
wait_for_completion(&done);
diff --git a/drivers/usb/gadget/fsl_qe_udc.h b/drivers/usb/gadget/fsl_qe_udc.h
index 1da5fb03d218..4c07ca9cebf3 100644
--- a/drivers/usb/gadget/fsl_qe_udc.h
+++ b/drivers/usb/gadget/fsl_qe_udc.h
@@ -266,7 +266,6 @@ struct qe_ep {
struct usb_ep ep;
struct list_head queue;
struct qe_udc *udc;
- const struct usb_endpoint_descriptor *desc;
struct usb_gadget *gadget;
u8 state;
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index 55abfb6bd612..28316858208b 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2007,2011 Freescale Semiconductor, Inc.
+ * Copyright (C) 2004-2007,2011-2012 Freescale Semiconductor, Inc.
* All rights reserved.
*
* Author: Li Yang <leoli@freescale.com>
@@ -58,9 +58,8 @@ static const char driver_name[] = "fsl-usb2-udc";
static const char driver_desc[] = DRIVER_DESC;
static struct usb_dr_device *dr_regs;
-#ifndef CONFIG_ARCH_MXC
+
static struct usb_sys_interface *usb_sys_regs;
-#endif
/* it is initialized in probe() */
static struct fsl_udc *udc_controller = NULL;
@@ -244,10 +243,9 @@ static int dr_controller_setup(struct fsl_udc *udc)
{
unsigned int tmp, portctrl, ep_num;
unsigned int max_no_of_ep;
-#ifndef CONFIG_ARCH_MXC
unsigned int ctrl;
-#endif
unsigned long timeout;
+
#define FSL_UDC_RESET_TIMEOUT 1000
/* Config PHY interface */
@@ -255,12 +253,32 @@ static int dr_controller_setup(struct fsl_udc *udc)
portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
switch (udc->phy_mode) {
case FSL_USB2_PHY_ULPI:
+ if (udc->pdata->have_sysif_regs) {
+ if (udc->pdata->controller_ver) {
+ /* controller version 1.6 or above */
+ ctrl = __raw_readl(&usb_sys_regs->control);
+ ctrl &= ~USB_CTRL_UTMI_PHY_EN;
+ ctrl |= USB_CTRL_USB_EN;
+ __raw_writel(ctrl, &usb_sys_regs->control);
+ }
+ }
portctrl |= PORTSCX_PTS_ULPI;
break;
case FSL_USB2_PHY_UTMI_WIDE:
portctrl |= PORTSCX_PTW_16BIT;
/* fall through */
case FSL_USB2_PHY_UTMI:
+ if (udc->pdata->have_sysif_regs) {
+ if (udc->pdata->controller_ver) {
+ /* controller version 1.6 or above */
+ ctrl = __raw_readl(&usb_sys_regs->control);
+ ctrl |= (USB_CTRL_UTMI_PHY_EN |
+ USB_CTRL_USB_EN);
+ __raw_writel(ctrl, &usb_sys_regs->control);
+ mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI
+ PHY CLK to become stable - 10ms*/
+ }
+ }
portctrl |= PORTSCX_PTS_UTMI;
break;
case FSL_USB2_PHY_SERIAL:
@@ -549,7 +567,7 @@ static int fsl_ep_enable(struct usb_ep *_ep,
ep = container_of(_ep, struct fsl_ep, ep);
/* catch various bogus parameters */
- if (!_ep || !desc || ep->desc
+ if (!_ep || !desc || ep->ep.desc
|| (desc->bDescriptorType != USB_DT_ENDPOINT))
return -EINVAL;
@@ -590,7 +608,7 @@ static int fsl_ep_enable(struct usb_ep *_ep,
spin_lock_irqsave(&udc->lock, flags);
ep->ep.maxpacket = max;
- ep->desc = desc;
+ ep->ep.desc = desc;
ep->stopped = 0;
/* Controller related setup */
@@ -614,7 +632,7 @@ static int fsl_ep_enable(struct usb_ep *_ep,
retval = 0;
VDBG("enabled %s (ep%d%s) maxpacket %d",ep->ep.name,
- ep->desc->bEndpointAddress & 0x0f,
+ ep->ep.desc->bEndpointAddress & 0x0f,
(desc->bEndpointAddress & USB_DIR_IN)
? "in" : "out", max);
en_done:
@@ -634,7 +652,7 @@ static int fsl_ep_disable(struct usb_ep *_ep)
int ep_num;
ep = container_of(_ep, struct fsl_ep, ep);
- if (!_ep || !ep->desc) {
+ if (!_ep || !ep->ep.desc) {
VDBG("%s not enabled", _ep ? ep->ep.name : NULL);
return -EINVAL;
}
@@ -657,7 +675,6 @@ static int fsl_ep_disable(struct usb_ep *_ep)
/* nuke all pending requests (does flush) */
nuke(ep, -ESHUTDOWN);
- ep->desc = NULL;
ep->ep.desc = NULL;
ep->stopped = 1;
spin_unlock_irqrestore(&udc->lock, flags);
@@ -736,6 +753,8 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
lastreq = list_entry(ep->queue.prev, struct fsl_req, queue);
lastreq->tail->next_td_ptr =
cpu_to_hc32(req->head->td_dma & DTD_ADDR_MASK);
+ /* Ensure dTD's next dtd pointer to be updated */
+ wmb();
/* Read prime bit, if 1 goto done */
if (fsl_readl(&dr_regs->endpointprime) & bitmask)
return;
@@ -874,11 +893,11 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
VDBG("%s, bad params", __func__);
return -EINVAL;
}
- if (unlikely(!_ep || !ep->desc)) {
+ if (unlikely(!_ep || !ep->ep.desc)) {
VDBG("%s, bad ep", __func__);
return -EINVAL;
}
- if (usb_endpoint_xfer_isoc(ep->desc)) {
+ if (usb_endpoint_xfer_isoc(ep->ep.desc)) {
if (req->req.length > ep->ep.maxpacket)
return -EMSGSIZE;
}
@@ -1017,12 +1036,12 @@ static int fsl_ep_set_halt(struct usb_ep *_ep, int value)
ep = container_of(_ep, struct fsl_ep, ep);
udc = ep->udc;
- if (!_ep || !ep->desc) {
+ if (!_ep || !ep->ep.desc) {
status = -EINVAL;
goto out;
}
- if (usb_endpoint_xfer_isoc(ep->desc)) {
+ if (usb_endpoint_xfer_isoc(ep->ep.desc)) {
status = -EOPNOTSUPP;
goto out;
}
@@ -1061,7 +1080,7 @@ static int fsl_ep_fifo_status(struct usb_ep *_ep)
struct ep_queue_head *qh;
ep = container_of(_ep, struct fsl_ep, ep);
- if (!_ep || (!ep->desc && ep_index(ep) != 0))
+ if (!_ep || (!ep->ep.desc && ep_index(ep) != 0))
return -ENODEV;
udc = (struct fsl_udc *)ep->udc;
@@ -1094,7 +1113,7 @@ static void fsl_ep_fifo_flush(struct usb_ep *_ep)
return;
} else {
ep = container_of(_ep, struct fsl_ep, ep);
- if (!ep->desc)
+ if (!ep->ep.desc)
return;
}
ep_num = ep_index(ep);
@@ -1349,7 +1368,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
target_ep = get_ep_by_pipe(udc, get_pipe_by_windex(index));
/* stall if endpoint doesn't exist */
- if (!target_ep->desc)
+ if (!target_ep->ep.desc)
goto stall;
tmp = dr_ep_get_stall(ep_index(target_ep), ep_is_in(target_ep))
<< USB_ENDPOINT_HALT;
@@ -2259,7 +2278,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
}
/* other gadget->eplist ep */
list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
- if (ep->desc) {
+ if (ep->ep.desc) {
t = scnprintf(next, size,
"\nFor %s Maxpkt is 0x%x "
"index is 0x%x\n",
diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h
index e651469fd39b..5cd7b7e7ddb4 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.h
+++ b/drivers/usb/gadget/fsl_usb2_udc.h
@@ -1,4 +1,12 @@
/*
+ * Copyright (C) 2004,2012 Freescale Semiconductor, Inc
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
* Freescale USB device/endpoint management registers
*/
#ifndef __FSL_USB2_UDC_H
@@ -348,6 +356,9 @@ struct usb_sys_interface {
/* control Register Bit Masks */
#define USB_CTRL_IOENB 0x00000004
#define USB_CTRL_ULPI_INT0EN 0x00000001
+#define USB_CTRL_UTMI_PHY_EN 0x00000200
+#define USB_CTRL_USB_EN 0x00000004
+#define USB_CTRL_ULPI_PHY_CLK_SEL 0x00000400
/* Endpoint Queue Head data struct
* Rem: all the variables of qh are LittleEndian Mode
@@ -450,7 +461,6 @@ struct fsl_ep {
struct list_head queue;
struct fsl_udc *udc;
struct ep_queue_head *qh;
- const struct usb_endpoint_descriptor *desc;
struct usb_gadget *gadget;
char name[14];
diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c
index 5831cb4a0b35..cdd94540e1cd 100644
--- a/drivers/usb/gadget/fusb300_udc.c
+++ b/drivers/usb/gadget/fusb300_udc.c
@@ -203,7 +203,7 @@ static int config_ep(struct fusb300_ep *ep,
struct fusb300 *fusb300 = ep->fusb300;
struct fusb300_ep_info info;
- ep->desc = desc;
+ ep->ep.desc = desc;
info.interval = 0;
info.addrofs = 0;
@@ -443,7 +443,7 @@ static int fusb300_queue(struct usb_ep *_ep, struct usb_request *_req,
req->req.actual = 0;
req->req.status = -EINPROGRESS;
- if (ep->desc == NULL) /* ep0 */
+ if (ep->ep.desc == NULL) /* ep0 */
ep0_queue(ep, req);
else if (request && !ep->stall)
enable_fifo_int(ep);
diff --git a/drivers/usb/gadget/fusb300_udc.h b/drivers/usb/gadget/fusb300_udc.h
index 92745bd03064..542cd83cc806 100644
--- a/drivers/usb/gadget/fusb300_udc.h
+++ b/drivers/usb/gadget/fusb300_udc.h
@@ -650,7 +650,6 @@ struct fusb300_ep {
unsigned char epnum;
unsigned char type;
- const struct usb_endpoint_descriptor *desc;
};
struct fusb300 {
diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c
index a85eaf40b948..d3ace9002a6a 100644
--- a/drivers/usb/gadget/g_ffs.c
+++ b/drivers/usb/gadget/g_ffs.c
@@ -67,6 +67,15 @@ MODULE_LICENSE("GPL");
#define GFS_VENDOR_ID 0x1d6b /* Linux Foundation */
#define GFS_PRODUCT_ID 0x0105 /* FunctionFS Gadget */
+#define GFS_MAX_DEVS 10
+
+struct gfs_ffs_obj {
+ const char *name;
+ bool mounted;
+ bool desc_ready;
+ struct ffs_data *ffs_data;
+};
+
static struct usb_device_descriptor gfs_dev_desc = {
.bLength = sizeof gfs_dev_desc,
.bDescriptorType = USB_DT_DEVICE,
@@ -78,12 +87,17 @@ static struct usb_device_descriptor gfs_dev_desc = {
.idProduct = cpu_to_le16(GFS_PRODUCT_ID),
};
+static char *func_names[GFS_MAX_DEVS];
+static unsigned int func_num;
+
module_param_named(bDeviceClass, gfs_dev_desc.bDeviceClass, byte, 0644);
MODULE_PARM_DESC(bDeviceClass, "USB Device class");
module_param_named(bDeviceSubClass, gfs_dev_desc.bDeviceSubClass, byte, 0644);
MODULE_PARM_DESC(bDeviceSubClass, "USB Device subclass");
module_param_named(bDeviceProtocol, gfs_dev_desc.bDeviceProtocol, byte, 0644);
MODULE_PARM_DESC(bDeviceProtocol, "USB Device protocol");
+module_param_array_named(functions, func_names, charp, &func_num, 0);
+MODULE_PARM_DESC(functions, "USB Functions list");
static const struct usb_descriptor_header *gfs_otg_desc[] = {
(const struct usb_descriptor_header *)
@@ -158,13 +172,34 @@ static struct usb_composite_driver gfs_driver = {
.iProduct = DRIVER_DESC,
};
-static struct ffs_data *gfs_ffs_data;
-static unsigned long gfs_registered;
+static DEFINE_MUTEX(gfs_lock);
+static unsigned int missing_funcs;
+static bool gfs_ether_setup;
+static bool gfs_registered;
+static bool gfs_single_func;
+static struct gfs_ffs_obj *ffs_tab;
static int __init gfs_init(void)
{
+ int i;
+
ENTER();
+ if (!func_num) {
+ gfs_single_func = true;
+ func_num = 1;
+ }
+
+ ffs_tab = kcalloc(func_num, sizeof *ffs_tab, GFP_KERNEL);
+ if (!ffs_tab)
+ return -ENOMEM;
+
+ if (!gfs_single_func)
+ for (i = 0; i < func_num; i++)
+ ffs_tab[i].name = func_names[i];
+
+ missing_funcs = func_num;
+
return functionfs_init();
}
module_init(gfs_init);
@@ -172,63 +207,165 @@ module_init(gfs_init);
static void __exit gfs_exit(void)
{
ENTER();
+ mutex_lock(&gfs_lock);
- if (test_and_clear_bit(0, &gfs_registered))
+ if (gfs_registered)
usb_composite_unregister(&gfs_driver);
+ gfs_registered = false;
functionfs_cleanup();
+
+ mutex_unlock(&gfs_lock);
+ kfree(ffs_tab);
}
module_exit(gfs_exit);
+static struct gfs_ffs_obj *gfs_find_dev(const char *dev_name)
+{
+ int i;
+
+ ENTER();
+
+ if (gfs_single_func)
+ return &ffs_tab[0];
+
+ for (i = 0; i < func_num; i++)
+ if (strcmp(ffs_tab[i].name, dev_name) == 0)
+ return &ffs_tab[i];
+
+ return NULL;
+}
+
static int functionfs_ready_callback(struct ffs_data *ffs)
{
+ struct gfs_ffs_obj *ffs_obj;
int ret;
ENTER();
+ mutex_lock(&gfs_lock);
+
+ ffs_obj = ffs->private_data;
+ if (!ffs_obj) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (WARN_ON(ffs_obj->desc_ready)) {
+ ret = -EBUSY;
+ goto done;
+ }
+ ffs_obj->desc_ready = true;
+ ffs_obj->ffs_data = ffs;
- if (WARN_ON(test_and_set_bit(0, &gfs_registered)))
- return -EBUSY;
+ if (--missing_funcs) {
+ ret = 0;
+ goto done;
+ }
+
+ if (gfs_registered) {
+ ret = -EBUSY;
+ goto done;
+ }
+ gfs_registered = true;
- gfs_ffs_data = ffs;
ret = usb_composite_probe(&gfs_driver, gfs_bind);
if (unlikely(ret < 0))
- clear_bit(0, &gfs_registered);
+ gfs_registered = false;
+
+done:
+ mutex_unlock(&gfs_lock);
return ret;
}
static void functionfs_closed_callback(struct ffs_data *ffs)
{
+ struct gfs_ffs_obj *ffs_obj;
+
ENTER();
+ mutex_lock(&gfs_lock);
- if (test_and_clear_bit(0, &gfs_registered))
+ ffs_obj = ffs->private_data;
+ if (!ffs_obj)
+ goto done;
+
+ ffs_obj->desc_ready = false;
+ missing_funcs++;
+
+ if (gfs_registered)
usb_composite_unregister(&gfs_driver);
+ gfs_registered = false;
+
+done:
+ mutex_unlock(&gfs_lock);
}
-static int functionfs_check_dev_callback(const char *dev_name)
+static void *functionfs_acquire_dev_callback(const char *dev_name)
{
- return 0;
+ struct gfs_ffs_obj *ffs_dev;
+
+ ENTER();
+ mutex_lock(&gfs_lock);
+
+ ffs_dev = gfs_find_dev(dev_name);
+ if (!ffs_dev) {
+ ffs_dev = ERR_PTR(-ENODEV);
+ goto done;
+ }
+
+ if (ffs_dev->mounted) {
+ ffs_dev = ERR_PTR(-EBUSY);
+ goto done;
+ }
+ ffs_dev->mounted = true;
+
+done:
+ mutex_unlock(&gfs_lock);
+ return ffs_dev;
}
+static void functionfs_release_dev_callback(struct ffs_data *ffs_data)
+{
+ struct gfs_ffs_obj *ffs_dev;
+
+ ENTER();
+ mutex_lock(&gfs_lock);
+
+ ffs_dev = ffs_data->private_data;
+ if (ffs_dev)
+ ffs_dev->mounted = false;
+
+ mutex_unlock(&gfs_lock);
+}
+
+/*
+ * It is assumed that gfs_bind is called from a context where gfs_lock is held
+ */
static int gfs_bind(struct usb_composite_dev *cdev)
{
int ret, i;
ENTER();
- if (WARN_ON(!gfs_ffs_data))
+ if (missing_funcs)
return -ENODEV;
ret = gether_setup(cdev->gadget, gfs_hostaddr);
if (unlikely(ret < 0))
goto error_quick;
+ gfs_ether_setup = true;
ret = usb_string_ids_tab(cdev, gfs_strings);
if (unlikely(ret < 0))
goto error;
- ret = functionfs_bind(gfs_ffs_data, cdev);
- if (unlikely(ret < 0))
- goto error;
+ for (i = func_num; --i; ) {
+ ret = functionfs_bind(ffs_tab[i].ffs_data, cdev);
+ if (unlikely(ret < 0)) {
+ while (++i < func_num)
+ functionfs_unbind(ffs_tab[i].ffs_data);
+ goto error;
+ }
+ }
for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) {
struct gfs_configuration *c = gfs_configurations + i;
@@ -246,16 +383,22 @@ static int gfs_bind(struct usb_composite_dev *cdev)
return 0;
error_unbind:
- functionfs_unbind(gfs_ffs_data);
+ for (i = 0; i < func_num; i++)
+ functionfs_unbind(ffs_tab[i].ffs_data);
error:
gether_cleanup();
error_quick:
- gfs_ffs_data = NULL;
+ gfs_ether_setup = false;
return ret;
}
+/*
+ * It is assumed that gfs_unbind is called from a context where gfs_lock is held
+ */
static int gfs_unbind(struct usb_composite_dev *cdev)
{
+ int i;
+
ENTER();
/*
@@ -266,22 +409,29 @@ static int gfs_unbind(struct usb_composite_dev *cdev)
* from composite on orror recovery, but what you're gonna
* do...?
*/
- if (gfs_ffs_data) {
+ if (gfs_ether_setup)
gether_cleanup();
- functionfs_unbind(gfs_ffs_data);
- gfs_ffs_data = NULL;
- }
+ gfs_ether_setup = false;
+
+ for (i = func_num; --i; )
+ if (ffs_tab[i].ffs_data)
+ functionfs_unbind(ffs_tab[i].ffs_data);
return 0;
}
+/*
+ * It is assumed that gfs_do_config is called from a context where
+ * gfs_lock is held
+ */
static int gfs_do_config(struct usb_configuration *c)
{
struct gfs_configuration *gc =
container_of(c, struct gfs_configuration, c);
+ int i;
int ret;
- if (WARN_ON(!gfs_ffs_data))
+ if (missing_funcs)
return -ENODEV;
if (gadget_is_otg(c->cdev->gadget)) {
@@ -295,9 +445,11 @@ static int gfs_do_config(struct usb_configuration *c)
return ret;
}
- ret = functionfs_bind_config(c->cdev, c, gfs_ffs_data);
- if (unlikely(ret < 0))
- return ret;
+ for (i = 0; i < func_num; i++) {
+ ret = functionfs_bind_config(c->cdev, c, ffs_tab[i].ffs_data);
+ if (unlikely(ret < 0))
+ return ret;
+ }
/*
* After previous do_configs there may be some invalid
diff --git a/drivers/usb/gadget/g_zero.h b/drivers/usb/gadget/g_zero.h
index e84b3c47ed3c..71ca193358b8 100644
--- a/drivers/usb/gadget/g_zero.h
+++ b/drivers/usb/gadget/g_zero.h
@@ -13,10 +13,11 @@ extern unsigned buflen;
extern const struct usb_descriptor_header *otg_desc[];
/* common utilities */
-struct usb_request *alloc_ep_req(struct usb_ep *ep);
+struct usb_request *alloc_ep_req(struct usb_ep *ep, int len);
void free_ep_req(struct usb_ep *ep, struct usb_request *req);
void disable_endpoints(struct usb_composite_dev *cdev,
- struct usb_ep *in, struct usb_ep *out);
+ struct usb_ep *in, struct usb_ep *out,
+ struct usb_ep *iso_in, struct usb_ep *iso_out);
/* configuration-specific linkup */
int sourcesink_add(struct usb_composite_dev *cdev, bool autoresume);
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index a8855d0b7f3b..b8b3a3411218 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -37,6 +37,7 @@
#define gadget_is_goku(g) (!strcmp("goku_udc", (g)->name))
#define gadget_is_imx(g) (!strcmp("imx_udc", (g)->name))
#define gadget_is_langwell(g) (!strcmp("langwell_udc", (g)->name))
+#define gadget_is_lpc32xx(g) (!strcmp("lpc32xx_udc", (g)->name))
#define gadget_is_m66592(g) (!strcmp("m66592_udc", (g)->name))
#define gadget_is_musbhdrc(g) (!strcmp("musb-hdrc", (g)->name))
#define gadget_is_net2272(g) (!strcmp("net2272", (g)->name))
@@ -118,6 +119,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x31;
else if (gadget_is_dwc3(gadget))
return 0x32;
+ else if (gadget_is_lpc32xx(gadget))
+ return 0x33;
return -ENOENT;
}
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index e151d6b87dee..b241e6c6a7f2 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -102,7 +102,7 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
unsigned long flags;
ep = container_of(_ep, struct goku_ep, ep);
- if (!_ep || !desc || ep->desc
+ if (!_ep || !desc || ep->ep.desc
|| desc->bDescriptorType != USB_DT_ENDPOINT)
return -EINVAL;
dev = ep->dev;
@@ -176,7 +176,7 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
command(ep->dev->regs, COMMAND_RESET, ep->num);
ep->ep.maxpacket = max;
ep->stopped = 0;
- ep->desc = desc;
+ ep->ep.desc = desc;
spin_unlock_irqrestore(&ep->dev->lock, flags);
DBG(dev, "enable %s %s %s maxpacket %u\n", ep->ep.name,
@@ -233,7 +233,6 @@ static void ep_reset(struct goku_udc_regs __iomem *regs, struct goku_ep *ep)
}
ep->ep.maxpacket = MAX_FIFO_SIZE;
- ep->desc = NULL;
ep->ep.desc = NULL;
ep->stopped = 1;
ep->irqs = 0;
@@ -247,7 +246,7 @@ static int goku_ep_disable(struct usb_ep *_ep)
unsigned long flags;
ep = container_of(_ep, struct goku_ep, ep);
- if (!_ep || !ep->desc)
+ if (!_ep || !ep->ep.desc)
return -ENODEV;
dev = ep->dev;
if (dev->ep0state == EP0_SUSPEND)
@@ -722,7 +721,7 @@ goku_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
|| !_req->buf || !list_empty(&req->queue)))
return -EINVAL;
ep = container_of(_ep, struct goku_ep, ep);
- if (unlikely(!_ep || (!ep->desc && ep->num != 0)))
+ if (unlikely(!_ep || (!ep->ep.desc && ep->num != 0)))
return -EINVAL;
dev = ep->dev;
if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN))
@@ -815,7 +814,7 @@ static int goku_dequeue(struct usb_ep *_ep, struct usb_request *_req)
unsigned long flags;
ep = container_of(_ep, struct goku_ep, ep);
- if (!_ep || !_req || (!ep->desc && ep->num != 0))
+ if (!_ep || !_req || (!ep->ep.desc && ep->num != 0))
return -EINVAL;
dev = ep->dev;
if (!dev->driver)
@@ -896,7 +895,7 @@ static int goku_set_halt(struct usb_ep *_ep, int value)
return -EINVAL;
/* don't change EPxSTATUS_EP_INVALID to READY */
- } else if (!ep->desc) {
+ } else if (!ep->ep.desc) {
DBG(ep->dev, "%s %s inactive?\n", __func__, ep->ep.name);
return -EINVAL;
}
@@ -955,7 +954,7 @@ static void goku_fifo_flush(struct usb_ep *_ep)
VDBG(ep->dev, "%s %s\n", __func__, ep->ep.name);
/* don't change EPxSTATUS_EP_INVALID to READY */
- if (!ep->desc && ep->num != 0) {
+ if (!ep->ep.desc && ep->num != 0) {
DBG(ep->dev, "%s %s inactive?\n", __func__, ep->ep.name);
return;
}
@@ -1152,7 +1151,7 @@ udc_proc_read(char *buffer, char **start, off_t off, int count,
struct goku_ep *ep = &dev->ep [i];
struct goku_request *req;
- if (i && !ep->desc)
+ if (i && !ep->ep.desc)
continue;
tmp = readl(ep->reg_status);
@@ -1473,7 +1472,8 @@ static void ep0_setup(struct goku_udc *dev)
case USB_RECIP_ENDPOINT:
tmp = le16_to_cpu(ctrl.wIndex) & 0x0f;
/* active endpoint */
- if (tmp > 3 || (!dev->ep[tmp].desc && tmp != 0))
+ if (tmp > 3 ||
+ (!dev->ep[tmp].ep.desc && tmp != 0))
goto stall;
if (ctrl.wIndex & cpu_to_le16(
USB_DIR_IN)) {
@@ -1895,14 +1895,4 @@ static struct pci_driver goku_pci_driver = {
/* FIXME add power management support */
};
-static int __init init (void)
-{
- return pci_register_driver (&goku_pci_driver);
-}
-module_init (init);
-
-static void __exit cleanup (void)
-{
- pci_unregister_driver (&goku_pci_driver);
-}
-module_exit (cleanup);
+module_pci_driver(goku_pci_driver);
diff --git a/drivers/usb/gadget/goku_udc.h b/drivers/usb/gadget/goku_udc.h
index e7e0c69d3b1f..85cdce0d1901 100644
--- a/drivers/usb/gadget/goku_udc.h
+++ b/drivers/usb/gadget/goku_udc.h
@@ -216,7 +216,6 @@ struct goku_ep {
/* analogous to a host-side qh */
struct list_head queue;
- const struct usb_endpoint_descriptor *desc;
u32 __iomem *reg_fifo;
u32 __iomem *reg_mode;
diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c
index 8d1c75abd73d..54034f84f992 100644
--- a/drivers/usb/gadget/imx_udc.c
+++ b/drivers/usb/gadget/imx_udc.c
@@ -1237,14 +1237,15 @@ irq_handler_t intr_handler(int i)
*******************************************************************************
*/
-static int imx_udc_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *));
-static int imx_udc_stop(struct usb_gadget_driver *driver);
+static int imx_udc_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
+static int imx_udc_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver);
static const struct usb_gadget_ops imx_udc_ops = {
- .get_frame = imx_udc_get_frame,
- .wakeup = imx_udc_wakeup,
- .start = imx_udc_start,
- .stop = imx_udc_stop,
+ .get_frame = imx_udc_get_frame,
+ .wakeup = imx_udc_wakeup,
+ .udc_start = imx_udc_start,
+ .udc_stop = imx_udc_stop,
};
static struct imx_udc_struct controller = {
@@ -1329,23 +1330,13 @@ static struct imx_udc_struct controller = {
* USB gadget driver functions
*******************************************************************************
*/
-static int imx_udc_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *))
+static int imx_udc_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
- struct imx_udc_struct *imx_usb = &controller;
+ struct imx_udc_struct *imx_usb;
int retval;
- if (!driver
- || driver->max_speed < USB_SPEED_FULL
- || !bind
- || !driver->disconnect
- || !driver->setup)
- return -EINVAL;
- if (!imx_usb)
- return -ENODEV;
- if (imx_usb->driver)
- return -EBUSY;
-
+ imx_usb = container_of(gadget, struct imx_udc_struct, gadget);
/* first hook up the driver ... */
imx_usb->driver = driver;
imx_usb->gadget.dev.driver = &driver->driver;
@@ -1353,14 +1344,6 @@ static int imx_udc_start(struct usb_gadget_driver *driver,
retval = device_add(&imx_usb->gadget.dev);
if (retval)
goto fail;
- retval = bind(&imx_usb->gadget);
- if (retval) {
- D_ERR(imx_usb->dev, "<%s> bind to driver %s --> error %d\n",
- __func__, driver->driver.name, retval);
- device_del(&imx_usb->gadget.dev);
-
- goto fail;
- }
D_INI(imx_usb->dev, "<%s> registered gadget driver '%s'\n",
__func__, driver->driver.name);
@@ -1374,20 +1357,16 @@ fail:
return retval;
}
-static int imx_udc_stop(struct usb_gadget_driver *driver)
+static int imx_udc_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
- struct imx_udc_struct *imx_usb = &controller;
-
- if (!imx_usb)
- return -ENODEV;
- if (!driver || driver != imx_usb->driver || !driver->unbind)
- return -EINVAL;
+ struct imx_udc_struct *imx_usb = container_of(gadget,
+ struct imx_udc_struct, gadget);
udc_stop_activity(imx_usb, driver);
imx_udc_disable(imx_usb);
del_timer(&imx_usb->timer);
- driver->unbind(&imx_usb->gadget);
imx_usb->gadget.dev.driver = NULL;
imx_usb->driver = NULL;
diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c
deleted file mode 100644
index f9cedd52cf20..000000000000
--- a/drivers/usb/gadget/langwell_udc.c
+++ /dev/null
@@ -1,3434 +0,0 @@
-/*
- * Intel Langwell USB Device Controller driver
- * Copyright (C) 2008-2009, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- */
-
-
-/* #undef DEBUG */
-/* #undef VERBOSE_DEBUG */
-
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
-#include <linux/moduleparam.h>
-#include <linux/device.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/gadget.h>
-#include <linux/usb/otg.h>
-#include <linux/pm.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <asm/unaligned.h>
-
-#include "langwell_udc.h"
-
-
-#define DRIVER_DESC "Intel Langwell USB Device Controller driver"
-#define DRIVER_VERSION "16 May 2009"
-
-static const char driver_name[] = "langwell_udc";
-static const char driver_desc[] = DRIVER_DESC;
-
-
-/* for endpoint 0 operations */
-static const struct usb_endpoint_descriptor
-langwell_ep0_desc = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0,
- .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
- .wMaxPacketSize = EP0_MAX_PKT_SIZE,
-};
-
-
-/*-------------------------------------------------------------------------*/
-/* debugging */
-
-#ifdef VERBOSE_DEBUG
-static inline void print_all_registers(struct langwell_udc *dev)
-{
- int i;
-
- /* Capability Registers */
- dev_dbg(&dev->pdev->dev,
- "Capability Registers (offset: 0x%04x, length: 0x%08x)\n",
- CAP_REG_OFFSET, (u32)sizeof(struct langwell_cap_regs));
- dev_dbg(&dev->pdev->dev, "caplength=0x%02x\n",
- readb(&dev->cap_regs->caplength));
- dev_dbg(&dev->pdev->dev, "hciversion=0x%04x\n",
- readw(&dev->cap_regs->hciversion));
- dev_dbg(&dev->pdev->dev, "hcsparams=0x%08x\n",
- readl(&dev->cap_regs->hcsparams));
- dev_dbg(&dev->pdev->dev, "hccparams=0x%08x\n",
- readl(&dev->cap_regs->hccparams));
- dev_dbg(&dev->pdev->dev, "dciversion=0x%04x\n",
- readw(&dev->cap_regs->dciversion));
- dev_dbg(&dev->pdev->dev, "dccparams=0x%08x\n",
- readl(&dev->cap_regs->dccparams));
-
- /* Operational Registers */
- dev_dbg(&dev->pdev->dev,
- "Operational Registers (offset: 0x%04x, length: 0x%08x)\n",
- OP_REG_OFFSET, (u32)sizeof(struct langwell_op_regs));
- dev_dbg(&dev->pdev->dev, "extsts=0x%08x\n",
- readl(&dev->op_regs->extsts));
- dev_dbg(&dev->pdev->dev, "extintr=0x%08x\n",
- readl(&dev->op_regs->extintr));
- dev_dbg(&dev->pdev->dev, "usbcmd=0x%08x\n",
- readl(&dev->op_regs->usbcmd));
- dev_dbg(&dev->pdev->dev, "usbsts=0x%08x\n",
- readl(&dev->op_regs->usbsts));
- dev_dbg(&dev->pdev->dev, "usbintr=0x%08x\n",
- readl(&dev->op_regs->usbintr));
- dev_dbg(&dev->pdev->dev, "frindex=0x%08x\n",
- readl(&dev->op_regs->frindex));
- dev_dbg(&dev->pdev->dev, "ctrldssegment=0x%08x\n",
- readl(&dev->op_regs->ctrldssegment));
- dev_dbg(&dev->pdev->dev, "deviceaddr=0x%08x\n",
- readl(&dev->op_regs->deviceaddr));
- dev_dbg(&dev->pdev->dev, "endpointlistaddr=0x%08x\n",
- readl(&dev->op_regs->endpointlistaddr));
- dev_dbg(&dev->pdev->dev, "ttctrl=0x%08x\n",
- readl(&dev->op_regs->ttctrl));
- dev_dbg(&dev->pdev->dev, "burstsize=0x%08x\n",
- readl(&dev->op_regs->burstsize));
- dev_dbg(&dev->pdev->dev, "txfilltuning=0x%08x\n",
- readl(&dev->op_regs->txfilltuning));
- dev_dbg(&dev->pdev->dev, "txttfilltuning=0x%08x\n",
- readl(&dev->op_regs->txttfilltuning));
- dev_dbg(&dev->pdev->dev, "ic_usb=0x%08x\n",
- readl(&dev->op_regs->ic_usb));
- dev_dbg(&dev->pdev->dev, "ulpi_viewport=0x%08x\n",
- readl(&dev->op_regs->ulpi_viewport));
- dev_dbg(&dev->pdev->dev, "configflag=0x%08x\n",
- readl(&dev->op_regs->configflag));
- dev_dbg(&dev->pdev->dev, "portsc1=0x%08x\n",
- readl(&dev->op_regs->portsc1));
- dev_dbg(&dev->pdev->dev, "devlc=0x%08x\n",
- readl(&dev->op_regs->devlc));
- dev_dbg(&dev->pdev->dev, "otgsc=0x%08x\n",
- readl(&dev->op_regs->otgsc));
- dev_dbg(&dev->pdev->dev, "usbmode=0x%08x\n",
- readl(&dev->op_regs->usbmode));
- dev_dbg(&dev->pdev->dev, "endptnak=0x%08x\n",
- readl(&dev->op_regs->endptnak));
- dev_dbg(&dev->pdev->dev, "endptnaken=0x%08x\n",
- readl(&dev->op_regs->endptnaken));
- dev_dbg(&dev->pdev->dev, "endptsetupstat=0x%08x\n",
- readl(&dev->op_regs->endptsetupstat));
- dev_dbg(&dev->pdev->dev, "endptprime=0x%08x\n",
- readl(&dev->op_regs->endptprime));
- dev_dbg(&dev->pdev->dev, "endptflush=0x%08x\n",
- readl(&dev->op_regs->endptflush));
- dev_dbg(&dev->pdev->dev, "endptstat=0x%08x\n",
- readl(&dev->op_regs->endptstat));
- dev_dbg(&dev->pdev->dev, "endptcomplete=0x%08x\n",
- readl(&dev->op_regs->endptcomplete));
-
- for (i = 0; i < dev->ep_max / 2; i++) {
- dev_dbg(&dev->pdev->dev, "endptctrl[%d]=0x%08x\n",
- i, readl(&dev->op_regs->endptctrl[i]));
- }
-}
-#else
-
-#define print_all_registers(dev) do { } while (0)
-
-#endif /* VERBOSE_DEBUG */
-
-
-/*-------------------------------------------------------------------------*/
-
-#define is_in(ep) (((ep)->ep_num == 0) ? ((ep)->dev->ep0_dir == \
- USB_DIR_IN) : (usb_endpoint_dir_in((ep)->desc)))
-
-#define DIR_STRING(ep) (is_in(ep) ? "in" : "out")
-
-
-static char *type_string(const struct usb_endpoint_descriptor *desc)
-{
- switch (usb_endpoint_type(desc)) {
- case USB_ENDPOINT_XFER_BULK:
- return "bulk";
- case USB_ENDPOINT_XFER_ISOC:
- return "iso";
- case USB_ENDPOINT_XFER_INT:
- return "int";
- };
-
- return "control";
-}
-
-
-/* configure endpoint control registers */
-static void ep_reset(struct langwell_ep *ep, unsigned char ep_num,
- unsigned char is_in, unsigned char ep_type)
-{
- struct langwell_udc *dev;
- u32 endptctrl;
-
- dev = ep->dev;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- endptctrl = readl(&dev->op_regs->endptctrl[ep_num]);
- if (is_in) { /* TX */
- if (ep_num)
- endptctrl |= EPCTRL_TXR;
- endptctrl |= EPCTRL_TXE;
- endptctrl |= ep_type << EPCTRL_TXT_SHIFT;
- } else { /* RX */
- if (ep_num)
- endptctrl |= EPCTRL_RXR;
- endptctrl |= EPCTRL_RXE;
- endptctrl |= ep_type << EPCTRL_RXT_SHIFT;
- }
-
- writel(endptctrl, &dev->op_regs->endptctrl[ep_num]);
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* reset ep0 dQH and endptctrl */
-static void ep0_reset(struct langwell_udc *dev)
-{
- struct langwell_ep *ep;
- int i;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* ep0 in and out */
- for (i = 0; i < 2; i++) {
- ep = &dev->ep[i];
- ep->dev = dev;
-
- /* ep0 dQH */
- ep->dqh = &dev->ep_dqh[i];
-
- /* configure ep0 endpoint capabilities in dQH */
- ep->dqh->dqh_ios = 1;
- ep->dqh->dqh_mpl = EP0_MAX_PKT_SIZE;
-
- /* enable ep0-in HW zero length termination select */
- if (is_in(ep))
- ep->dqh->dqh_zlt = 0;
- ep->dqh->dqh_mult = 0;
-
- ep->dqh->dtd_next = DTD_TERM;
-
- /* configure ep0 control registers */
- ep_reset(&dev->ep[0], 0, i, USB_ENDPOINT_XFER_CONTROL);
- }
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* endpoints operations */
-
-/* configure endpoint, making it usable */
-static int langwell_ep_enable(struct usb_ep *_ep,
- const struct usb_endpoint_descriptor *desc)
-{
- struct langwell_udc *dev;
- struct langwell_ep *ep;
- u16 max = 0;
- unsigned long flags;
- int i, retval = 0;
- unsigned char zlt, ios = 0, mult = 0;
-
- ep = container_of(_ep, struct langwell_ep, ep);
- dev = ep->dev;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (!_ep || !desc || ep->desc
- || desc->bDescriptorType != USB_DT_ENDPOINT)
- return -EINVAL;
-
- if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
- return -ESHUTDOWN;
-
- max = usb_endpoint_maxp(desc);
-
- /*
- * disable HW zero length termination select
- * driver handles zero length packet through req->req.zero
- */
- zlt = 1;
-
- /*
- * sanity check type, direction, address, and then
- * initialize the endpoint capabilities fields in dQH
- */
- switch (usb_endpoint_type(desc)) {
- case USB_ENDPOINT_XFER_CONTROL:
- ios = 1;
- break;
- case USB_ENDPOINT_XFER_BULK:
- if ((dev->gadget.speed == USB_SPEED_HIGH
- && max != 512)
- || (dev->gadget.speed == USB_SPEED_FULL
- && max > 64)) {
- goto done;
- }
- break;
- case USB_ENDPOINT_XFER_INT:
- if (strstr(ep->ep.name, "-iso")) /* bulk is ok */
- goto done;
-
- switch (dev->gadget.speed) {
- case USB_SPEED_HIGH:
- if (max <= 1024)
- break;
- case USB_SPEED_FULL:
- if (max <= 64)
- break;
- default:
- if (max <= 8)
- break;
- goto done;
- }
- break;
- case USB_ENDPOINT_XFER_ISOC:
- if (strstr(ep->ep.name, "-bulk")
- || strstr(ep->ep.name, "-int"))
- goto done;
-
- switch (dev->gadget.speed) {
- case USB_SPEED_HIGH:
- if (max <= 1024)
- break;
- case USB_SPEED_FULL:
- if (max <= 1023)
- break;
- default:
- goto done;
- }
- /*
- * FIXME:
- * calculate transactions needed for high bandwidth iso
- */
- mult = (unsigned char)(1 + ((max >> 11) & 0x03));
- max = max & 0x8ff; /* bit 0~10 */
- /* 3 transactions at most */
- if (mult > 3)
- goto done;
- break;
- default:
- goto done;
- }
-
- spin_lock_irqsave(&dev->lock, flags);
-
- ep->ep.maxpacket = max;
- ep->desc = desc;
- ep->stopped = 0;
- ep->ep_num = usb_endpoint_num(desc);
-
- /* ep_type */
- ep->ep_type = usb_endpoint_type(desc);
-
- /* configure endpoint control registers */
- ep_reset(ep, ep->ep_num, is_in(ep), ep->ep_type);
-
- /* configure endpoint capabilities in dQH */
- i = ep->ep_num * 2 + is_in(ep);
- ep->dqh = &dev->ep_dqh[i];
- ep->dqh->dqh_ios = ios;
- ep->dqh->dqh_mpl = cpu_to_le16(max);
- ep->dqh->dqh_zlt = zlt;
- ep->dqh->dqh_mult = mult;
- ep->dqh->dtd_next = DTD_TERM;
-
- dev_dbg(&dev->pdev->dev, "enabled %s (ep%d%s-%s), max %04x\n",
- _ep->name,
- ep->ep_num,
- DIR_STRING(ep),
- type_string(desc),
- max);
-
- spin_unlock_irqrestore(&dev->lock, flags);
-done:
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return retval;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* retire a request */
-static void done(struct langwell_ep *ep, struct langwell_request *req,
- int status)
-{
- struct langwell_udc *dev = ep->dev;
- unsigned stopped = ep->stopped;
- struct langwell_dtd *curr_dtd, *next_dtd;
- int i;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* remove the req from ep->queue */
- list_del_init(&req->queue);
-
- if (req->req.status == -EINPROGRESS)
- req->req.status = status;
- else
- status = req->req.status;
-
- /* free dTD for the request */
- next_dtd = req->head;
- for (i = 0; i < req->dtd_count; i++) {
- curr_dtd = next_dtd;
- if (i != req->dtd_count - 1)
- next_dtd = curr_dtd->next_dtd_virt;
- dma_pool_free(dev->dtd_pool, curr_dtd, curr_dtd->dtd_dma);
- }
-
- usb_gadget_unmap_request(&dev->gadget, &req->req, is_in(ep));
-
- if (status != -ESHUTDOWN)
- dev_dbg(&dev->pdev->dev,
- "complete %s, req %p, stat %d, len %u/%u\n",
- ep->ep.name, &req->req, status,
- req->req.actual, req->req.length);
-
- /* don't modify queue heads during completion callback */
- ep->stopped = 1;
-
- spin_unlock(&dev->lock);
- /* complete routine from gadget driver */
- if (req->req.complete)
- req->req.complete(&ep->ep, &req->req);
-
- spin_lock(&dev->lock);
- ep->stopped = stopped;
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-static void langwell_ep_fifo_flush(struct usb_ep *_ep);
-
-/* delete all endpoint requests, called with spinlock held */
-static void nuke(struct langwell_ep *ep, int status)
-{
- /* called with spinlock held */
- ep->stopped = 1;
-
- /* endpoint fifo flush */
- if (&ep->ep && ep->desc)
- langwell_ep_fifo_flush(&ep->ep);
-
- while (!list_empty(&ep->queue)) {
- struct langwell_request *req = NULL;
- req = list_entry(ep->queue.next, struct langwell_request,
- queue);
- done(ep, req, status);
- }
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* endpoint is no longer usable */
-static int langwell_ep_disable(struct usb_ep *_ep)
-{
- struct langwell_ep *ep;
- unsigned long flags;
- struct langwell_udc *dev;
- int ep_num;
- u32 endptctrl;
-
- ep = container_of(_ep, struct langwell_ep, ep);
- dev = ep->dev;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (!_ep || !ep->desc)
- return -EINVAL;
-
- spin_lock_irqsave(&dev->lock, flags);
-
- /* disable endpoint control register */
- ep_num = ep->ep_num;
- endptctrl = readl(&dev->op_regs->endptctrl[ep_num]);
- if (is_in(ep))
- endptctrl &= ~EPCTRL_TXE;
- else
- endptctrl &= ~EPCTRL_RXE;
- writel(endptctrl, &dev->op_regs->endptctrl[ep_num]);
-
- /* nuke all pending requests (does flush) */
- nuke(ep, -ESHUTDOWN);
-
- ep->desc = NULL;
- ep->ep.desc = NULL;
- ep->stopped = 1;
-
- spin_unlock_irqrestore(&dev->lock, flags);
-
- dev_dbg(&dev->pdev->dev, "disabled %s\n", _ep->name);
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-
- return 0;
-}
-
-
-/* allocate a request object to use with this endpoint */
-static struct usb_request *langwell_alloc_request(struct usb_ep *_ep,
- gfp_t gfp_flags)
-{
- struct langwell_ep *ep;
- struct langwell_udc *dev;
- struct langwell_request *req = NULL;
-
- if (!_ep)
- return NULL;
-
- ep = container_of(_ep, struct langwell_ep, ep);
- dev = ep->dev;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- req = kzalloc(sizeof(*req), gfp_flags);
- if (!req)
- return NULL;
-
- req->req.dma = DMA_ADDR_INVALID;
- INIT_LIST_HEAD(&req->queue);
-
- dev_vdbg(&dev->pdev->dev, "alloc request for %s\n", _ep->name);
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return &req->req;
-}
-
-
-/* free a request object */
-static void langwell_free_request(struct usb_ep *_ep,
- struct usb_request *_req)
-{
- struct langwell_ep *ep;
- struct langwell_udc *dev;
- struct langwell_request *req = NULL;
-
- ep = container_of(_ep, struct langwell_ep, ep);
- dev = ep->dev;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (!_ep || !_req)
- return;
-
- req = container_of(_req, struct langwell_request, req);
- WARN_ON(!list_empty(&req->queue));
-
- if (_req)
- kfree(req);
-
- dev_vdbg(&dev->pdev->dev, "free request for %s\n", _ep->name);
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* queue dTD and PRIME endpoint */
-static int queue_dtd(struct langwell_ep *ep, struct langwell_request *req)
-{
- u32 bit_mask, usbcmd, endptstat, dtd_dma;
- u8 dtd_status;
- int i;
- struct langwell_dqh *dqh;
- struct langwell_udc *dev;
-
- dev = ep->dev;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- i = ep->ep_num * 2 + is_in(ep);
- dqh = &dev->ep_dqh[i];
-
- if (ep->ep_num)
- dev_vdbg(&dev->pdev->dev, "%s\n", ep->name);
- else
- /* ep0 */
- dev_vdbg(&dev->pdev->dev, "%s-%s\n", ep->name, DIR_STRING(ep));
-
- dev_vdbg(&dev->pdev->dev, "ep_dqh[%d] addr: 0x%p\n",
- i, &(dev->ep_dqh[i]));
-
- bit_mask = is_in(ep) ?
- (1 << (ep->ep_num + 16)) : (1 << (ep->ep_num));
-
- dev_vdbg(&dev->pdev->dev, "bit_mask = 0x%08x\n", bit_mask);
-
- /* check if the pipe is empty */
- if (!(list_empty(&ep->queue))) {
- /* add dTD to the end of linked list */
- struct langwell_request *lastreq;
- lastreq = list_entry(ep->queue.prev,
- struct langwell_request, queue);
-
- lastreq->tail->dtd_next =
- cpu_to_le32(req->head->dtd_dma & DTD_NEXT_MASK);
-
- /* read prime bit, if 1 goto out */
- if (readl(&dev->op_regs->endptprime) & bit_mask)
- goto out;
-
- do {
- /* set ATDTW bit in USBCMD */
- usbcmd = readl(&dev->op_regs->usbcmd);
- writel(usbcmd | CMD_ATDTW, &dev->op_regs->usbcmd);
-
- /* read correct status bit */
- endptstat = readl(&dev->op_regs->endptstat) & bit_mask;
-
- } while (!(readl(&dev->op_regs->usbcmd) & CMD_ATDTW));
-
- /* write ATDTW bit to 0 */
- usbcmd = readl(&dev->op_regs->usbcmd);
- writel(usbcmd & ~CMD_ATDTW, &dev->op_regs->usbcmd);
-
- if (endptstat)
- goto out;
- }
-
- /* write dQH next pointer and terminate bit to 0 */
- dtd_dma = req->head->dtd_dma & DTD_NEXT_MASK;
- dqh->dtd_next = cpu_to_le32(dtd_dma);
-
- /* clear active and halt bit */
- dtd_status = (u8) ~(DTD_STS_ACTIVE | DTD_STS_HALTED);
- dqh->dtd_status &= dtd_status;
- dev_vdbg(&dev->pdev->dev, "dqh->dtd_status = 0x%x\n", dqh->dtd_status);
-
- /* ensure that updates to the dQH will occur before priming */
- wmb();
-
- /* write 1 to endptprime register to PRIME endpoint */
- bit_mask = is_in(ep) ? (1 << (ep->ep_num + 16)) : (1 << ep->ep_num);
- dev_vdbg(&dev->pdev->dev, "endprime bit_mask = 0x%08x\n", bit_mask);
- writel(bit_mask, &dev->op_regs->endptprime);
-out:
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-}
-
-
-/* fill in the dTD structure to build a transfer descriptor */
-static struct langwell_dtd *build_dtd(struct langwell_request *req,
- unsigned *length, dma_addr_t *dma, int *is_last)
-{
- u32 buf_ptr;
- struct langwell_dtd *dtd;
- struct langwell_udc *dev;
- int i;
-
- dev = req->ep->dev;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* the maximum transfer length, up to 16k bytes */
- *length = min(req->req.length - req->req.actual,
- (unsigned)DTD_MAX_TRANSFER_LENGTH);
-
- /* create dTD dma_pool resource */
- dtd = dma_pool_alloc(dev->dtd_pool, GFP_KERNEL, dma);
- if (dtd == NULL)
- return dtd;
- dtd->dtd_dma = *dma;
-
- /* initialize buffer page pointers */
- buf_ptr = (u32)(req->req.dma + req->req.actual);
- for (i = 0; i < 5; i++)
- dtd->dtd_buf[i] = cpu_to_le32(buf_ptr + i * PAGE_SIZE);
-
- req->req.actual += *length;
-
- /* fill in total bytes with transfer size */
- dtd->dtd_total = cpu_to_le16(*length);
- dev_vdbg(&dev->pdev->dev, "dtd->dtd_total = %d\n", dtd->dtd_total);
-
- /* set is_last flag if req->req.zero is set or not */
- if (req->req.zero) {
- if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0)
- *is_last = 1;
- else
- *is_last = 0;
- } else if (req->req.length == req->req.actual) {
- *is_last = 1;
- } else
- *is_last = 0;
-
- if (*is_last == 0)
- dev_vdbg(&dev->pdev->dev, "multi-dtd request!\n");
-
- /* set interrupt on complete bit for the last dTD */
- if (*is_last && !req->req.no_interrupt)
- dtd->dtd_ioc = 1;
-
- /* set multiplier override 0 for non-ISO and non-TX endpoint */
- dtd->dtd_multo = 0;
-
- /* set the active bit of status field to 1 */
- dtd->dtd_status = DTD_STS_ACTIVE;
- dev_vdbg(&dev->pdev->dev, "dtd->dtd_status = 0x%02x\n",
- dtd->dtd_status);
-
- dev_vdbg(&dev->pdev->dev, "length = %d, dma addr= 0x%08x\n",
- *length, (int)*dma);
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return dtd;
-}
-
-
-/* generate dTD linked list for a request */
-static int req_to_dtd(struct langwell_request *req)
-{
- unsigned count;
- int is_last, is_first = 1;
- struct langwell_dtd *dtd, *last_dtd = NULL;
- struct langwell_udc *dev;
- dma_addr_t dma;
-
- dev = req->ep->dev;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
- do {
- dtd = build_dtd(req, &count, &dma, &is_last);
- if (dtd == NULL)
- return -ENOMEM;
-
- if (is_first) {
- is_first = 0;
- req->head = dtd;
- } else {
- last_dtd->dtd_next = cpu_to_le32(dma);
- last_dtd->next_dtd_virt = dtd;
- }
- last_dtd = dtd;
- req->dtd_count++;
- } while (!is_last);
-
- /* set terminate bit to 1 for the last dTD */
- dtd->dtd_next = DTD_TERM;
-
- req->tail = dtd;
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* queue (submits) an I/O requests to an endpoint */
-static int langwell_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
- gfp_t gfp_flags)
-{
- struct langwell_request *req;
- struct langwell_ep *ep;
- struct langwell_udc *dev;
- unsigned long flags;
- int is_iso = 0;
- int ret;
-
- /* always require a cpu-view buffer */
- req = container_of(_req, struct langwell_request, req);
- ep = container_of(_ep, struct langwell_ep, ep);
-
- if (!_req || !_req->complete || !_req->buf
- || !list_empty(&req->queue)) {
- return -EINVAL;
- }
-
- if (unlikely(!_ep || !ep->desc))
- return -EINVAL;
-
- dev = ep->dev;
- req->ep = ep;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (usb_endpoint_xfer_isoc(ep->desc)) {
- if (req->req.length > ep->ep.maxpacket)
- return -EMSGSIZE;
- is_iso = 1;
- }
-
- if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN))
- return -ESHUTDOWN;
-
- /* set up dma mapping */
- ret = usb_gadget_map_request(&dev->gadget, &req->req, is_in(ep));
- if (ret)
- return ret;
-
- dev_dbg(&dev->pdev->dev,
- "%s queue req %p, len %u, buf %p, dma 0x%08x\n",
- _ep->name,
- _req, _req->length, _req->buf, (int)_req->dma);
-
- _req->status = -EINPROGRESS;
- _req->actual = 0;
- req->dtd_count = 0;
-
- spin_lock_irqsave(&dev->lock, flags);
-
- /* build and put dTDs to endpoint queue */
- if (!req_to_dtd(req)) {
- queue_dtd(ep, req);
- } else {
- spin_unlock_irqrestore(&dev->lock, flags);
- return -ENOMEM;
- }
-
- /* update ep0 state */
- if (ep->ep_num == 0)
- dev->ep0_state = DATA_STATE_XMIT;
-
- if (likely(req != NULL)) {
- list_add_tail(&req->queue, &ep->queue);
- dev_vdbg(&dev->pdev->dev, "list_add_tail()\n");
- }
-
- spin_unlock_irqrestore(&dev->lock, flags);
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-}
-
-
-/* dequeue (cancels, unlinks) an I/O request from an endpoint */
-static int langwell_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
-{
- struct langwell_ep *ep;
- struct langwell_udc *dev;
- struct langwell_request *req;
- unsigned long flags;
- int stopped, ep_num, retval = 0;
- u32 endptctrl;
-
- ep = container_of(_ep, struct langwell_ep, ep);
- dev = ep->dev;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (!_ep || !ep->desc || !_req)
- return -EINVAL;
-
- if (!dev->driver)
- return -ESHUTDOWN;
-
- spin_lock_irqsave(&dev->lock, flags);
- stopped = ep->stopped;
-
- /* quiesce dma while we patch the queue */
- ep->stopped = 1;
- ep_num = ep->ep_num;
-
- /* disable endpoint control register */
- endptctrl = readl(&dev->op_regs->endptctrl[ep_num]);
- if (is_in(ep))
- endptctrl &= ~EPCTRL_TXE;
- else
- endptctrl &= ~EPCTRL_RXE;
- writel(endptctrl, &dev->op_regs->endptctrl[ep_num]);
-
- /* make sure it's still queued on this endpoint */
- list_for_each_entry(req, &ep->queue, queue) {
- if (&req->req == _req)
- break;
- }
-
- if (&req->req != _req) {
- retval = -EINVAL;
- goto done;
- }
-
- /* queue head may be partially complete. */
- if (ep->queue.next == &req->queue) {
- dev_dbg(&dev->pdev->dev, "unlink (%s) dma\n", _ep->name);
- _req->status = -ECONNRESET;
- langwell_ep_fifo_flush(&ep->ep);
-
- /* not the last request in endpoint queue */
- if (likely(ep->queue.next == &req->queue)) {
- struct langwell_dqh *dqh;
- struct langwell_request *next_req;
-
- dqh = ep->dqh;
- next_req = list_entry(req->queue.next,
- struct langwell_request, queue);
-
- /* point the dQH to the first dTD of next request */
- writel((u32) next_req->head, &dqh->dqh_current);
- }
- } else {
- struct langwell_request *prev_req;
-
- prev_req = list_entry(req->queue.prev,
- struct langwell_request, queue);
- writel(readl(&req->tail->dtd_next),
- &prev_req->tail->dtd_next);
- }
-
- done(ep, req, -ECONNRESET);
-
-done:
- /* enable endpoint again */
- endptctrl = readl(&dev->op_regs->endptctrl[ep_num]);
- if (is_in(ep))
- endptctrl |= EPCTRL_TXE;
- else
- endptctrl |= EPCTRL_RXE;
- writel(endptctrl, &dev->op_regs->endptctrl[ep_num]);
-
- ep->stopped = stopped;
- spin_unlock_irqrestore(&dev->lock, flags);
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return retval;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* endpoint set/clear halt */
-static void ep_set_halt(struct langwell_ep *ep, int value)
-{
- u32 endptctrl = 0;
- int ep_num;
- struct langwell_udc *dev = ep->dev;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- ep_num = ep->ep_num;
- endptctrl = readl(&dev->op_regs->endptctrl[ep_num]);
-
- /* value: 1 - set halt, 0 - clear halt */
- if (value) {
- /* set the stall bit */
- if (is_in(ep))
- endptctrl |= EPCTRL_TXS;
- else
- endptctrl |= EPCTRL_RXS;
- } else {
- /* clear the stall bit and reset data toggle */
- if (is_in(ep)) {
- endptctrl &= ~EPCTRL_TXS;
- endptctrl |= EPCTRL_TXR;
- } else {
- endptctrl &= ~EPCTRL_RXS;
- endptctrl |= EPCTRL_RXR;
- }
- }
-
- writel(endptctrl, &dev->op_regs->endptctrl[ep_num]);
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* set the endpoint halt feature */
-static int langwell_ep_set_halt(struct usb_ep *_ep, int value)
-{
- struct langwell_ep *ep;
- struct langwell_udc *dev;
- unsigned long flags;
- int retval = 0;
-
- ep = container_of(_ep, struct langwell_ep, ep);
- dev = ep->dev;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (!_ep || !ep->desc)
- return -EINVAL;
-
- if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
- return -ESHUTDOWN;
-
- if (usb_endpoint_xfer_isoc(ep->desc))
- return -EOPNOTSUPP;
-
- spin_lock_irqsave(&dev->lock, flags);
-
- /*
- * attempt to halt IN ep will fail if any transfer requests
- * are still queue
- */
- if (!list_empty(&ep->queue) && is_in(ep) && value) {
- /* IN endpoint FIFO holds bytes */
- dev_dbg(&dev->pdev->dev, "%s FIFO holds bytes\n", _ep->name);
- retval = -EAGAIN;
- goto done;
- }
-
- /* endpoint set/clear halt */
- if (ep->ep_num) {
- ep_set_halt(ep, value);
- } else { /* endpoint 0 */
- dev->ep0_state = WAIT_FOR_SETUP;
- dev->ep0_dir = USB_DIR_OUT;
- }
-done:
- spin_unlock_irqrestore(&dev->lock, flags);
- dev_dbg(&dev->pdev->dev, "%s %s halt\n",
- _ep->name, value ? "set" : "clear");
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return retval;
-}
-
-
-/* set the halt feature and ignores clear requests */
-static int langwell_ep_set_wedge(struct usb_ep *_ep)
-{
- struct langwell_ep *ep;
- struct langwell_udc *dev;
-
- ep = container_of(_ep, struct langwell_ep, ep);
- dev = ep->dev;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (!_ep || !ep->desc)
- return -EINVAL;
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return usb_ep_set_halt(_ep);
-}
-
-
-/* flush contents of a fifo */
-static void langwell_ep_fifo_flush(struct usb_ep *_ep)
-{
- struct langwell_ep *ep;
- struct langwell_udc *dev;
- u32 flush_bit;
- unsigned long timeout;
-
- ep = container_of(_ep, struct langwell_ep, ep);
- dev = ep->dev;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (!_ep || !ep->desc) {
- dev_vdbg(&dev->pdev->dev, "ep or ep->desc is NULL\n");
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return;
- }
-
- dev_vdbg(&dev->pdev->dev, "%s-%s fifo flush\n",
- _ep->name, DIR_STRING(ep));
-
- /* flush endpoint buffer */
- if (ep->ep_num == 0)
- flush_bit = (1 << 16) | 1;
- else if (is_in(ep))
- flush_bit = 1 << (ep->ep_num + 16); /* TX */
- else
- flush_bit = 1 << ep->ep_num; /* RX */
-
- /* wait until flush complete */
- timeout = jiffies + FLUSH_TIMEOUT;
- do {
- writel(flush_bit, &dev->op_regs->endptflush);
- while (readl(&dev->op_regs->endptflush)) {
- if (time_after(jiffies, timeout)) {
- dev_err(&dev->pdev->dev, "ep flush timeout\n");
- goto done;
- }
- cpu_relax();
- }
- } while (readl(&dev->op_regs->endptstat) & flush_bit);
-done:
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* endpoints operations structure */
-static const struct usb_ep_ops langwell_ep_ops = {
-
- /* configure endpoint, making it usable */
- .enable = langwell_ep_enable,
-
- /* endpoint is no longer usable */
- .disable = langwell_ep_disable,
-
- /* allocate a request object to use with this endpoint */
- .alloc_request = langwell_alloc_request,
-
- /* free a request object */
- .free_request = langwell_free_request,
-
- /* queue (submits) an I/O requests to an endpoint */
- .queue = langwell_ep_queue,
-
- /* dequeue (cancels, unlinks) an I/O request from an endpoint */
- .dequeue = langwell_ep_dequeue,
-
- /* set the endpoint halt feature */
- .set_halt = langwell_ep_set_halt,
-
- /* set the halt feature and ignores clear requests */
- .set_wedge = langwell_ep_set_wedge,
-
- /* flush contents of a fifo */
- .fifo_flush = langwell_ep_fifo_flush,
-};
-
-
-/*-------------------------------------------------------------------------*/
-
-/* device controller usb_gadget_ops structure */
-
-/* returns the current frame number */
-static int langwell_get_frame(struct usb_gadget *_gadget)
-{
- struct langwell_udc *dev;
- u16 retval;
-
- if (!_gadget)
- return -ENODEV;
-
- dev = container_of(_gadget, struct langwell_udc, gadget);
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- retval = readl(&dev->op_regs->frindex) & FRINDEX_MASK;
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return retval;
-}
-
-
-/* enter or exit PHY low power state */
-static void langwell_phy_low_power(struct langwell_udc *dev, bool flag)
-{
- u32 devlc;
- u8 devlc_byte2;
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- devlc = readl(&dev->op_regs->devlc);
- dev_vdbg(&dev->pdev->dev, "devlc = 0x%08x\n", devlc);
-
- if (flag)
- devlc |= LPM_PHCD;
- else
- devlc &= ~LPM_PHCD;
-
- /* FIXME: workaround for Langwell A1/A2/A3 sighting */
- devlc_byte2 = (devlc >> 16) & 0xff;
- writeb(devlc_byte2, (u8 *)&dev->op_regs->devlc + 2);
-
- devlc = readl(&dev->op_regs->devlc);
- dev_vdbg(&dev->pdev->dev,
- "%s PHY low power suspend, devlc = 0x%08x\n",
- flag ? "enter" : "exit", devlc);
-}
-
-
-/* tries to wake up the host connected to this gadget */
-static int langwell_wakeup(struct usb_gadget *_gadget)
-{
- struct langwell_udc *dev;
- u32 portsc1;
- unsigned long flags;
-
- if (!_gadget)
- return 0;
-
- dev = container_of(_gadget, struct langwell_udc, gadget);
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* remote wakeup feature not enabled by host */
- if (!dev->remote_wakeup) {
- dev_info(&dev->pdev->dev, "remote wakeup is disabled\n");
- return -ENOTSUPP;
- }
-
- spin_lock_irqsave(&dev->lock, flags);
-
- portsc1 = readl(&dev->op_regs->portsc1);
- if (!(portsc1 & PORTS_SUSP)) {
- spin_unlock_irqrestore(&dev->lock, flags);
- return 0;
- }
-
- /* LPM L1 to L0 or legacy remote wakeup */
- if (dev->lpm && dev->lpm_state == LPM_L1)
- dev_info(&dev->pdev->dev, "LPM L1 to L0 remote wakeup\n");
- else
- dev_info(&dev->pdev->dev, "device remote wakeup\n");
-
- /* exit PHY low power suspend */
- if (dev->pdev->device != 0x0829)
- langwell_phy_low_power(dev, 0);
-
- /* force port resume */
- portsc1 |= PORTS_FPR;
- writel(portsc1, &dev->op_regs->portsc1);
-
- spin_unlock_irqrestore(&dev->lock, flags);
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-}
-
-
-/* notify controller that VBUS is powered or not */
-static int langwell_vbus_session(struct usb_gadget *_gadget, int is_active)
-{
- struct langwell_udc *dev;
- unsigned long flags;
- u32 usbcmd;
-
- if (!_gadget)
- return -ENODEV;
-
- dev = container_of(_gadget, struct langwell_udc, gadget);
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- spin_lock_irqsave(&dev->lock, flags);
- dev_vdbg(&dev->pdev->dev, "VBUS status: %s\n",
- is_active ? "on" : "off");
-
- dev->vbus_active = (is_active != 0);
- if (dev->driver && dev->softconnected && dev->vbus_active) {
- usbcmd = readl(&dev->op_regs->usbcmd);
- usbcmd |= CMD_RUNSTOP;
- writel(usbcmd, &dev->op_regs->usbcmd);
- } else {
- usbcmd = readl(&dev->op_regs->usbcmd);
- usbcmd &= ~CMD_RUNSTOP;
- writel(usbcmd, &dev->op_regs->usbcmd);
- }
-
- spin_unlock_irqrestore(&dev->lock, flags);
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-}
-
-
-/* constrain controller's VBUS power usage */
-static int langwell_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
-{
- struct langwell_udc *dev;
-
- if (!_gadget)
- return -ENODEV;
-
- dev = container_of(_gadget, struct langwell_udc, gadget);
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (dev->transceiver) {
- dev_vdbg(&dev->pdev->dev, "usb_phy_set_power\n");
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return usb_phy_set_power(dev->transceiver, mA);
- }
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return -ENOTSUPP;
-}
-
-
-/* D+ pullup, software-controlled connect/disconnect to USB host */
-static int langwell_pullup(struct usb_gadget *_gadget, int is_on)
-{
- struct langwell_udc *dev;
- u32 usbcmd;
- unsigned long flags;
-
- if (!_gadget)
- return -ENODEV;
-
- dev = container_of(_gadget, struct langwell_udc, gadget);
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- spin_lock_irqsave(&dev->lock, flags);
- dev->softconnected = (is_on != 0);
-
- if (dev->driver && dev->softconnected && dev->vbus_active) {
- usbcmd = readl(&dev->op_regs->usbcmd);
- usbcmd |= CMD_RUNSTOP;
- writel(usbcmd, &dev->op_regs->usbcmd);
- } else {
- usbcmd = readl(&dev->op_regs->usbcmd);
- usbcmd &= ~CMD_RUNSTOP;
- writel(usbcmd, &dev->op_regs->usbcmd);
- }
- spin_unlock_irqrestore(&dev->lock, flags);
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-}
-
-static int langwell_start(struct usb_gadget *g,
- struct usb_gadget_driver *driver);
-
-static int langwell_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver);
-
-/* device controller usb_gadget_ops structure */
-static const struct usb_gadget_ops langwell_ops = {
-
- /* returns the current frame number */
- .get_frame = langwell_get_frame,
-
- /* tries to wake up the host connected to this gadget */
- .wakeup = langwell_wakeup,
-
- /* set the device selfpowered feature, always selfpowered */
- /* .set_selfpowered = langwell_set_selfpowered, */
-
- /* notify controller that VBUS is powered or not */
- .vbus_session = langwell_vbus_session,
-
- /* constrain controller's VBUS power usage */
- .vbus_draw = langwell_vbus_draw,
-
- /* D+ pullup, software-controlled connect/disconnect to USB host */
- .pullup = langwell_pullup,
-
- .udc_start = langwell_start,
- .udc_stop = langwell_stop,
-};
-
-
-/*-------------------------------------------------------------------------*/
-
-/* device controller operations */
-
-/* reset device controller */
-static int langwell_udc_reset(struct langwell_udc *dev)
-{
- u32 usbcmd, usbmode, devlc, endpointlistaddr;
- u8 devlc_byte0, devlc_byte2;
- unsigned long timeout;
-
- if (!dev)
- return -EINVAL;
-
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* set controller to stop state */
- usbcmd = readl(&dev->op_regs->usbcmd);
- usbcmd &= ~CMD_RUNSTOP;
- writel(usbcmd, &dev->op_regs->usbcmd);
-
- /* reset device controller */
- usbcmd = readl(&dev->op_regs->usbcmd);
- usbcmd |= CMD_RST;
- writel(usbcmd, &dev->op_regs->usbcmd);
-
- /* wait for reset to complete */
- timeout = jiffies + RESET_TIMEOUT;
- while (readl(&dev->op_regs->usbcmd) & CMD_RST) {
- if (time_after(jiffies, timeout)) {
- dev_err(&dev->pdev->dev, "device reset timeout\n");
- return -ETIMEDOUT;
- }
- cpu_relax();
- }
-
- /* set controller to device mode */
- usbmode = readl(&dev->op_regs->usbmode);
- usbmode |= MODE_DEVICE;
-
- /* turn setup lockout off, require setup tripwire in usbcmd */
- usbmode |= MODE_SLOM;
-
- writel(usbmode, &dev->op_regs->usbmode);
- usbmode = readl(&dev->op_regs->usbmode);
- dev_vdbg(&dev->pdev->dev, "usbmode=0x%08x\n", usbmode);
-
- /* Write-Clear setup status */
- writel(0, &dev->op_regs->usbsts);
-
- /* if support USB LPM, ACK all LPM token */
- if (dev->lpm) {
- devlc = readl(&dev->op_regs->devlc);
- dev_vdbg(&dev->pdev->dev, "devlc = 0x%08x\n", devlc);
- /* FIXME: workaround for Langwell A1/A2/A3 sighting */
- devlc &= ~LPM_STL; /* don't STALL LPM token */
- devlc &= ~LPM_NYT_ACK; /* ACK LPM token */
- devlc_byte0 = devlc & 0xff;
- devlc_byte2 = (devlc >> 16) & 0xff;
- writeb(devlc_byte0, (u8 *)&dev->op_regs->devlc);
- writeb(devlc_byte2, (u8 *)&dev->op_regs->devlc + 2);
- devlc = readl(&dev->op_regs->devlc);
- dev_vdbg(&dev->pdev->dev,
- "ACK LPM token, devlc = 0x%08x\n", devlc);
- }
-
- /* fill endpointlistaddr register */
- endpointlistaddr = dev->ep_dqh_dma;
- endpointlistaddr &= ENDPOINTLISTADDR_MASK;
- writel(endpointlistaddr, &dev->op_regs->endpointlistaddr);
-
- dev_vdbg(&dev->pdev->dev,
- "dQH base (vir: %p, phy: 0x%08x), endpointlistaddr=0x%08x\n",
- dev->ep_dqh, endpointlistaddr,
- readl(&dev->op_regs->endpointlistaddr));
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-}
-
-
-/* reinitialize device controller endpoints */
-static int eps_reinit(struct langwell_udc *dev)
-{
- struct langwell_ep *ep;
- char name[14];
- int i;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* initialize ep0 */
- ep = &dev->ep[0];
- ep->dev = dev;
- strncpy(ep->name, "ep0", sizeof(ep->name));
- ep->ep.name = ep->name;
- ep->ep.ops = &langwell_ep_ops;
- ep->stopped = 0;
- ep->ep.maxpacket = EP0_MAX_PKT_SIZE;
- ep->ep_num = 0;
- ep->desc = &langwell_ep0_desc;
- INIT_LIST_HEAD(&ep->queue);
-
- ep->ep_type = USB_ENDPOINT_XFER_CONTROL;
-
- /* initialize other endpoints */
- for (i = 2; i < dev->ep_max; i++) {
- ep = &dev->ep[i];
- if (i % 2)
- snprintf(name, sizeof(name), "ep%din", i / 2);
- else
- snprintf(name, sizeof(name), "ep%dout", i / 2);
- ep->dev = dev;
- strncpy(ep->name, name, sizeof(ep->name));
- ep->ep.name = ep->name;
-
- ep->ep.ops = &langwell_ep_ops;
- ep->stopped = 0;
- ep->ep.maxpacket = (unsigned short) ~0;
- ep->ep_num = i / 2;
-
- INIT_LIST_HEAD(&ep->queue);
- list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
- }
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-}
-
-
-/* enable interrupt and set controller to run state */
-static void langwell_udc_start(struct langwell_udc *dev)
-{
- u32 usbintr, usbcmd;
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* enable interrupts */
- usbintr = INTR_ULPIE /* ULPI */
- | INTR_SLE /* suspend */
- /* | INTR_SRE SOF received */
- | INTR_URE /* USB reset */
- | INTR_AAE /* async advance */
- | INTR_SEE /* system error */
- | INTR_FRE /* frame list rollover */
- | INTR_PCE /* port change detect */
- | INTR_UEE /* USB error interrupt */
- | INTR_UE; /* USB interrupt */
- writel(usbintr, &dev->op_regs->usbintr);
-
- /* clear stopped bit */
- dev->stopped = 0;
-
- /* set controller to run */
- usbcmd = readl(&dev->op_regs->usbcmd);
- usbcmd |= CMD_RUNSTOP;
- writel(usbcmd, &dev->op_regs->usbcmd);
-
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* disable interrupt and set controller to stop state */
-static void langwell_udc_stop(struct langwell_udc *dev)
-{
- u32 usbcmd;
-
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* disable all interrupts */
- writel(0, &dev->op_regs->usbintr);
-
- /* set stopped bit */
- dev->stopped = 1;
-
- /* set controller to stop state */
- usbcmd = readl(&dev->op_regs->usbcmd);
- usbcmd &= ~CMD_RUNSTOP;
- writel(usbcmd, &dev->op_regs->usbcmd);
-
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* stop all USB activities */
-static void stop_activity(struct langwell_udc *dev)
-{
- struct langwell_ep *ep;
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- nuke(&dev->ep[0], -ESHUTDOWN);
-
- list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) {
- nuke(ep, -ESHUTDOWN);
- }
-
- /* report disconnect; the driver is already quiesced */
- if (dev->driver) {
- spin_unlock(&dev->lock);
- dev->driver->disconnect(&dev->gadget);
- spin_lock(&dev->lock);
- }
-
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* device "function" sysfs attribute file */
-static ssize_t show_function(struct device *_dev,
- struct device_attribute *attr, char *buf)
-{
- struct langwell_udc *dev = dev_get_drvdata(_dev);
-
- if (!dev->driver || !dev->driver->function
- || strlen(dev->driver->function) > PAGE_SIZE)
- return 0;
-
- return scnprintf(buf, PAGE_SIZE, "%s\n", dev->driver->function);
-}
-static DEVICE_ATTR(function, S_IRUGO, show_function, NULL);
-
-
-static inline enum usb_device_speed lpm_device_speed(u32 reg)
-{
- switch (LPM_PSPD(reg)) {
- case LPM_SPEED_HIGH:
- return USB_SPEED_HIGH;
- case LPM_SPEED_FULL:
- return USB_SPEED_FULL;
- case LPM_SPEED_LOW:
- return USB_SPEED_LOW;
- default:
- return USB_SPEED_UNKNOWN;
- }
-}
-
-/* device "langwell_udc" sysfs attribute file */
-static ssize_t show_langwell_udc(struct device *_dev,
- struct device_attribute *attr, char *buf)
-{
- struct langwell_udc *dev = dev_get_drvdata(_dev);
- struct langwell_request *req;
- struct langwell_ep *ep = NULL;
- char *next;
- unsigned size;
- unsigned t;
- unsigned i;
- unsigned long flags;
- u32 tmp_reg;
-
- next = buf;
- size = PAGE_SIZE;
- spin_lock_irqsave(&dev->lock, flags);
-
- /* driver basic information */
- t = scnprintf(next, size,
- DRIVER_DESC "\n"
- "%s version: %s\n"
- "Gadget driver: %s\n\n",
- driver_name, DRIVER_VERSION,
- dev->driver ? dev->driver->driver.name : "(none)");
- size -= t;
- next += t;
-
- /* device registers */
- tmp_reg = readl(&dev->op_regs->usbcmd);
- t = scnprintf(next, size,
- "USBCMD reg:\n"
- "SetupTW: %d\n"
- "Run/Stop: %s\n\n",
- (tmp_reg & CMD_SUTW) ? 1 : 0,
- (tmp_reg & CMD_RUNSTOP) ? "Run" : "Stop");
- size -= t;
- next += t;
-
- tmp_reg = readl(&dev->op_regs->usbsts);
- t = scnprintf(next, size,
- "USB Status Reg:\n"
- "Device Suspend: %d\n"
- "Reset Received: %d\n"
- "System Error: %s\n"
- "USB Error Interrupt: %s\n\n",
- (tmp_reg & STS_SLI) ? 1 : 0,
- (tmp_reg & STS_URI) ? 1 : 0,
- (tmp_reg & STS_SEI) ? "Error" : "No error",
- (tmp_reg & STS_UEI) ? "Error detected" : "No error");
- size -= t;
- next += t;
-
- tmp_reg = readl(&dev->op_regs->usbintr);
- t = scnprintf(next, size,
- "USB Intrrupt Enable Reg:\n"
- "Sleep Enable: %d\n"
- "SOF Received Enable: %d\n"
- "Reset Enable: %d\n"
- "System Error Enable: %d\n"
- "Port Change Dectected Enable: %d\n"
- "USB Error Intr Enable: %d\n"
- "USB Intr Enable: %d\n\n",
- (tmp_reg & INTR_SLE) ? 1 : 0,
- (tmp_reg & INTR_SRE) ? 1 : 0,
- (tmp_reg & INTR_URE) ? 1 : 0,
- (tmp_reg & INTR_SEE) ? 1 : 0,
- (tmp_reg & INTR_PCE) ? 1 : 0,
- (tmp_reg & INTR_UEE) ? 1 : 0,
- (tmp_reg & INTR_UE) ? 1 : 0);
- size -= t;
- next += t;
-
- tmp_reg = readl(&dev->op_regs->frindex);
- t = scnprintf(next, size,
- "USB Frame Index Reg:\n"
- "Frame Number is 0x%08x\n\n",
- (tmp_reg & FRINDEX_MASK));
- size -= t;
- next += t;
-
- tmp_reg = readl(&dev->op_regs->deviceaddr);
- t = scnprintf(next, size,
- "USB Device Address Reg:\n"
- "Device Addr is 0x%x\n\n",
- USBADR(tmp_reg));
- size -= t;
- next += t;
-
- tmp_reg = readl(&dev->op_regs->endpointlistaddr);
- t = scnprintf(next, size,
- "USB Endpoint List Address Reg:\n"
- "Endpoint List Pointer is 0x%x\n\n",
- EPBASE(tmp_reg));
- size -= t;
- next += t;
-
- tmp_reg = readl(&dev->op_regs->portsc1);
- t = scnprintf(next, size,
- "USB Port Status & Control Reg:\n"
- "Port Reset: %s\n"
- "Port Suspend Mode: %s\n"
- "Over-current Change: %s\n"
- "Port Enable/Disable Change: %s\n"
- "Port Enabled/Disabled: %s\n"
- "Current Connect Status: %s\n"
- "LPM Suspend Status: %s\n\n",
- (tmp_reg & PORTS_PR) ? "Reset" : "Not Reset",
- (tmp_reg & PORTS_SUSP) ? "Suspend " : "Not Suspend",
- (tmp_reg & PORTS_OCC) ? "Detected" : "No",
- (tmp_reg & PORTS_PEC) ? "Changed" : "Not Changed",
- (tmp_reg & PORTS_PE) ? "Enable" : "Not Correct",
- (tmp_reg & PORTS_CCS) ? "Attached" : "Not Attached",
- (tmp_reg & PORTS_SLP) ? "LPM L1" : "LPM L0");
- size -= t;
- next += t;
-
- tmp_reg = readl(&dev->op_regs->devlc);
- t = scnprintf(next, size,
- "Device LPM Control Reg:\n"
- "Parallel Transceiver : %d\n"
- "Serial Transceiver : %d\n"
- "Port Speed: %s\n"
- "Port Force Full Speed Connenct: %s\n"
- "PHY Low Power Suspend Clock: %s\n"
- "BmAttributes: %d\n\n",
- LPM_PTS(tmp_reg),
- (tmp_reg & LPM_STS) ? 1 : 0,
- usb_speed_string(lpm_device_speed(tmp_reg)),
- (tmp_reg & LPM_PFSC) ? "Force Full Speed" : "Not Force",
- (tmp_reg & LPM_PHCD) ? "Disabled" : "Enabled",
- LPM_BA(tmp_reg));
- size -= t;
- next += t;
-
- tmp_reg = readl(&dev->op_regs->usbmode);
- t = scnprintf(next, size,
- "USB Mode Reg:\n"
- "Controller Mode is : %s\n\n", ({
- char *s;
- switch (MODE_CM(tmp_reg)) {
- case MODE_IDLE:
- s = "Idle"; break;
- case MODE_DEVICE:
- s = "Device Controller"; break;
- case MODE_HOST:
- s = "Host Controller"; break;
- default:
- s = "None"; break;
- }
- s;
- }));
- size -= t;
- next += t;
-
- tmp_reg = readl(&dev->op_regs->endptsetupstat);
- t = scnprintf(next, size,
- "Endpoint Setup Status Reg:\n"
- "SETUP on ep 0x%04x\n\n",
- tmp_reg & SETUPSTAT_MASK);
- size -= t;
- next += t;
-
- for (i = 0; i < dev->ep_max / 2; i++) {
- tmp_reg = readl(&dev->op_regs->endptctrl[i]);
- t = scnprintf(next, size, "EP Ctrl Reg [%d]: 0x%08x\n",
- i, tmp_reg);
- size -= t;
- next += t;
- }
- tmp_reg = readl(&dev->op_regs->endptprime);
- t = scnprintf(next, size, "EP Prime Reg: 0x%08x\n\n", tmp_reg);
- size -= t;
- next += t;
-
- /* langwell_udc, langwell_ep, langwell_request structure information */
- ep = &dev->ep[0];
- t = scnprintf(next, size, "%s MaxPacketSize: 0x%x, ep_num: %d\n",
- ep->ep.name, ep->ep.maxpacket, ep->ep_num);
- size -= t;
- next += t;
-
- if (list_empty(&ep->queue)) {
- t = scnprintf(next, size, "its req queue is empty\n\n");
- size -= t;
- next += t;
- } else {
- list_for_each_entry(req, &ep->queue, queue) {
- t = scnprintf(next, size,
- "req %p actual 0x%x length 0x%x buf %p\n",
- &req->req, req->req.actual,
- req->req.length, req->req.buf);
- size -= t;
- next += t;
- }
- }
- /* other gadget->eplist ep */
- list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) {
- if (ep->desc) {
- t = scnprintf(next, size,
- "\n%s MaxPacketSize: 0x%x, "
- "ep_num: %d\n",
- ep->ep.name, ep->ep.maxpacket,
- ep->ep_num);
- size -= t;
- next += t;
-
- if (list_empty(&ep->queue)) {
- t = scnprintf(next, size,
- "its req queue is empty\n\n");
- size -= t;
- next += t;
- } else {
- list_for_each_entry(req, &ep->queue, queue) {
- t = scnprintf(next, size,
- "req %p actual 0x%x length "
- "0x%x buf %p\n",
- &req->req, req->req.actual,
- req->req.length, req->req.buf);
- size -= t;
- next += t;
- }
- }
- }
- }
-
- spin_unlock_irqrestore(&dev->lock, flags);
- return PAGE_SIZE - size;
-}
-static DEVICE_ATTR(langwell_udc, S_IRUGO, show_langwell_udc, NULL);
-
-
-/* device "remote_wakeup" sysfs attribute file */
-static ssize_t store_remote_wakeup(struct device *_dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct langwell_udc *dev = dev_get_drvdata(_dev);
- unsigned long flags;
- ssize_t rc = count;
-
- if (count > 2)
- return -EINVAL;
-
- if (count > 0 && buf[count-1] == '\n')
- ((char *) buf)[count-1] = 0;
-
- if (buf[0] != '1')
- return -EINVAL;
-
- /* force remote wakeup enabled in case gadget driver doesn't support */
- spin_lock_irqsave(&dev->lock, flags);
- dev->remote_wakeup = 1;
- dev->dev_status |= (1 << USB_DEVICE_REMOTE_WAKEUP);
- spin_unlock_irqrestore(&dev->lock, flags);
-
- langwell_wakeup(&dev->gadget);
-
- return rc;
-}
-static DEVICE_ATTR(remote_wakeup, S_IWUSR, NULL, store_remote_wakeup);
-
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * when a driver is successfully registered, it will receive
- * control requests including set_configuration(), which enables
- * non-control requests. then usb traffic follows until a
- * disconnect is reported. then a host may connect again, or
- * the driver might get unbound.
- */
-
-static int langwell_start(struct usb_gadget *g,
- struct usb_gadget_driver *driver)
-{
- struct langwell_udc *dev = gadget_to_langwell(g);
- unsigned long flags;
- int retval;
-
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- spin_lock_irqsave(&dev->lock, flags);
-
- /* hook up the driver ... */
- driver->driver.bus = NULL;
- dev->driver = driver;
- dev->gadget.dev.driver = &driver->driver;
-
- spin_unlock_irqrestore(&dev->lock, flags);
-
- retval = device_create_file(&dev->pdev->dev, &dev_attr_function);
- if (retval)
- goto err;
-
- dev->usb_state = USB_STATE_ATTACHED;
- dev->ep0_state = WAIT_FOR_SETUP;
- dev->ep0_dir = USB_DIR_OUT;
-
- /* enable interrupt and set controller to run state */
- if (dev->got_irq)
- langwell_udc_start(dev);
-
- dev_vdbg(&dev->pdev->dev,
- "After langwell_udc_start(), print all registers:\n");
- print_all_registers(dev);
-
- dev_info(&dev->pdev->dev, "register driver: %s\n",
- driver->driver.name);
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-
- return 0;
-
-err:
- dev->gadget.dev.driver = NULL;
- dev->driver = NULL;
-
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-
- return retval;
-}
-
-/* unregister gadget driver */
-static int langwell_stop(struct usb_gadget *g,
- struct usb_gadget_driver *driver)
-{
- struct langwell_udc *dev = gadget_to_langwell(g);
- unsigned long flags;
-
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* exit PHY low power suspend */
- if (dev->pdev->device != 0x0829)
- langwell_phy_low_power(dev, 0);
-
- /* unbind OTG transceiver */
- if (dev->transceiver)
- (void)otg_set_peripheral(dev->transceiver->otg, 0);
-
- /* disable interrupt and set controller to stop state */
- langwell_udc_stop(dev);
-
- dev->usb_state = USB_STATE_ATTACHED;
- dev->ep0_state = WAIT_FOR_SETUP;
- dev->ep0_dir = USB_DIR_OUT;
-
- spin_lock_irqsave(&dev->lock, flags);
-
- /* stop all usb activities */
- dev->gadget.speed = USB_SPEED_UNKNOWN;
- dev->gadget.dev.driver = NULL;
- dev->driver = NULL;
- stop_activity(dev);
- spin_unlock_irqrestore(&dev->lock, flags);
-
- device_remove_file(&dev->pdev->dev, &dev_attr_function);
-
- dev_info(&dev->pdev->dev, "unregistered driver '%s'\n",
- driver->driver.name);
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * setup tripwire is used as a semaphore to ensure that the setup data
- * payload is extracted from a dQH without being corrupted
- */
-static void setup_tripwire(struct langwell_udc *dev)
-{
- u32 usbcmd,
- endptsetupstat;
- unsigned long timeout;
- struct langwell_dqh *dqh;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* ep0 OUT dQH */
- dqh = &dev->ep_dqh[EP_DIR_OUT];
-
- /* Write-Clear endptsetupstat */
- endptsetupstat = readl(&dev->op_regs->endptsetupstat);
- writel(endptsetupstat, &dev->op_regs->endptsetupstat);
-
- /* wait until endptsetupstat is cleared */
- timeout = jiffies + SETUPSTAT_TIMEOUT;
- while (readl(&dev->op_regs->endptsetupstat)) {
- if (time_after(jiffies, timeout)) {
- dev_err(&dev->pdev->dev, "setup_tripwire timeout\n");
- break;
- }
- cpu_relax();
- }
-
- /* while a hazard exists when setup packet arrives */
- do {
- /* set setup tripwire bit */
- usbcmd = readl(&dev->op_regs->usbcmd);
- writel(usbcmd | CMD_SUTW, &dev->op_regs->usbcmd);
-
- /* copy the setup packet to local buffer */
- memcpy(&dev->local_setup_buff, &dqh->dqh_setup, 8);
- } while (!(readl(&dev->op_regs->usbcmd) & CMD_SUTW));
-
- /* Write-Clear setup tripwire bit */
- usbcmd = readl(&dev->op_regs->usbcmd);
- writel(usbcmd & ~CMD_SUTW, &dev->op_regs->usbcmd);
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* protocol ep0 stall, will automatically be cleared on new transaction */
-static void ep0_stall(struct langwell_udc *dev)
-{
- u32 endptctrl;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* set TX and RX to stall */
- endptctrl = readl(&dev->op_regs->endptctrl[0]);
- endptctrl |= EPCTRL_TXS | EPCTRL_RXS;
- writel(endptctrl, &dev->op_regs->endptctrl[0]);
-
- /* update ep0 state */
- dev->ep0_state = WAIT_FOR_SETUP;
- dev->ep0_dir = USB_DIR_OUT;
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* PRIME a status phase for ep0 */
-static int prime_status_phase(struct langwell_udc *dev, int dir)
-{
- struct langwell_request *req;
- struct langwell_ep *ep;
- int status = 0;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (dir == EP_DIR_IN)
- dev->ep0_dir = USB_DIR_IN;
- else
- dev->ep0_dir = USB_DIR_OUT;
-
- ep = &dev->ep[0];
- dev->ep0_state = WAIT_FOR_OUT_STATUS;
-
- req = dev->status_req;
-
- req->ep = ep;
- req->req.length = 0;
- req->req.status = -EINPROGRESS;
- req->req.actual = 0;
- req->req.complete = NULL;
- req->dtd_count = 0;
-
- if (!req_to_dtd(req))
- status = queue_dtd(ep, req);
- else
- return -ENOMEM;
-
- if (status)
- dev_err(&dev->pdev->dev, "can't queue ep0 status request\n");
-
- list_add_tail(&req->queue, &ep->queue);
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return status;
-}
-
-
-/* SET_ADDRESS request routine */
-static void set_address(struct langwell_udc *dev, u16 value,
- u16 index, u16 length)
-{
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* save the new address to device struct */
- dev->dev_addr = (u8) value;
- dev_vdbg(&dev->pdev->dev, "dev->dev_addr = %d\n", dev->dev_addr);
-
- /* update usb state */
- dev->usb_state = USB_STATE_ADDRESS;
-
- /* STATUS phase */
- if (prime_status_phase(dev, EP_DIR_IN))
- ep0_stall(dev);
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* return endpoint by windex */
-static struct langwell_ep *get_ep_by_windex(struct langwell_udc *dev,
- u16 wIndex)
-{
- struct langwell_ep *ep;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)
- return &dev->ep[0];
-
- list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) {
- u8 bEndpointAddress;
- if (!ep->desc)
- continue;
-
- bEndpointAddress = ep->desc->bEndpointAddress;
- if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
- continue;
-
- if ((wIndex & USB_ENDPOINT_NUMBER_MASK)
- == (bEndpointAddress & USB_ENDPOINT_NUMBER_MASK))
- return ep;
- }
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return NULL;
-}
-
-
-/* return whether endpoint is stalled, 0: not stalled; 1: stalled */
-static int ep_is_stall(struct langwell_ep *ep)
-{
- struct langwell_udc *dev = ep->dev;
- u32 endptctrl;
- int retval;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- endptctrl = readl(&dev->op_regs->endptctrl[ep->ep_num]);
- if (is_in(ep))
- retval = endptctrl & EPCTRL_TXS ? 1 : 0;
- else
- retval = endptctrl & EPCTRL_RXS ? 1 : 0;
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return retval;
-}
-
-
-/* GET_STATUS request routine */
-static void get_status(struct langwell_udc *dev, u8 request_type, u16 value,
- u16 index, u16 length)
-{
- struct langwell_request *req;
- struct langwell_ep *ep;
- u16 status_data = 0; /* 16 bits cpu view status data */
- int status = 0;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- ep = &dev->ep[0];
-
- if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
- /* get device status */
- status_data = dev->dev_status;
- } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
- /* get interface status */
- status_data = 0;
- } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) {
- /* get endpoint status */
- struct langwell_ep *epn;
- epn = get_ep_by_windex(dev, index);
- /* stall if endpoint doesn't exist */
- if (!epn)
- goto stall;
-
- status_data = ep_is_stall(epn) << USB_ENDPOINT_HALT;
- }
-
- dev_dbg(&dev->pdev->dev, "get status data: 0x%04x\n", status_data);
-
- dev->ep0_dir = USB_DIR_IN;
-
- /* borrow the per device status_req */
- req = dev->status_req;
-
- /* fill in the reqest structure */
- *((u16 *) req->req.buf) = cpu_to_le16(status_data);
- req->ep = ep;
- req->req.length = 2;
- req->req.status = -EINPROGRESS;
- req->req.actual = 0;
- req->req.complete = NULL;
- req->dtd_count = 0;
-
- /* prime the data phase */
- if (!req_to_dtd(req))
- status = queue_dtd(ep, req);
- else /* no mem */
- goto stall;
-
- if (status) {
- dev_err(&dev->pdev->dev,
- "response error on GET_STATUS request\n");
- goto stall;
- }
-
- list_add_tail(&req->queue, &ep->queue);
- dev->ep0_state = DATA_STATE_XMIT;
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return;
-stall:
- ep0_stall(dev);
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* setup packet interrupt handler */
-static void handle_setup_packet(struct langwell_udc *dev,
- struct usb_ctrlrequest *setup)
-{
- u16 wValue = le16_to_cpu(setup->wValue);
- u16 wIndex = le16_to_cpu(setup->wIndex);
- u16 wLength = le16_to_cpu(setup->wLength);
- u32 portsc1;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* ep0 fifo flush */
- nuke(&dev->ep[0], -ESHUTDOWN);
-
- dev_dbg(&dev->pdev->dev, "SETUP %02x.%02x v%04x i%04x l%04x\n",
- setup->bRequestType, setup->bRequest,
- wValue, wIndex, wLength);
-
- /* RNDIS gadget delegate */
- if ((setup->bRequestType == 0x21) && (setup->bRequest == 0x00)) {
- /* USB_CDC_SEND_ENCAPSULATED_COMMAND */
- goto delegate;
- }
-
- /* USB_CDC_GET_ENCAPSULATED_RESPONSE */
- if ((setup->bRequestType == 0xa1) && (setup->bRequest == 0x01)) {
- /* USB_CDC_GET_ENCAPSULATED_RESPONSE */
- goto delegate;
- }
-
- /* We process some stardard setup requests here */
- switch (setup->bRequest) {
- case USB_REQ_GET_STATUS:
- dev_dbg(&dev->pdev->dev, "SETUP: USB_REQ_GET_STATUS\n");
- /* get status, DATA and STATUS phase */
- if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK))
- != (USB_DIR_IN | USB_TYPE_STANDARD))
- break;
- get_status(dev, setup->bRequestType, wValue, wIndex, wLength);
- goto end;
-
- case USB_REQ_SET_ADDRESS:
- dev_dbg(&dev->pdev->dev, "SETUP: USB_REQ_SET_ADDRESS\n");
- /* STATUS phase */
- if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD
- | USB_RECIP_DEVICE))
- break;
- set_address(dev, wValue, wIndex, wLength);
- goto end;
-
- case USB_REQ_CLEAR_FEATURE:
- case USB_REQ_SET_FEATURE:
- /* STATUS phase */
- {
- int rc = -EOPNOTSUPP;
- if (setup->bRequest == USB_REQ_SET_FEATURE)
- dev_dbg(&dev->pdev->dev,
- "SETUP: USB_REQ_SET_FEATURE\n");
- else if (setup->bRequest == USB_REQ_CLEAR_FEATURE)
- dev_dbg(&dev->pdev->dev,
- "SETUP: USB_REQ_CLEAR_FEATURE\n");
-
- if ((setup->bRequestType & (USB_RECIP_MASK | USB_TYPE_MASK))
- == (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) {
- struct langwell_ep *epn;
- epn = get_ep_by_windex(dev, wIndex);
- /* stall if endpoint doesn't exist */
- if (!epn) {
- ep0_stall(dev);
- goto end;
- }
-
- if (wValue != 0 || wLength != 0
- || epn->ep_num > dev->ep_max)
- break;
-
- spin_unlock(&dev->lock);
- rc = langwell_ep_set_halt(&epn->ep,
- (setup->bRequest == USB_REQ_SET_FEATURE)
- ? 1 : 0);
- spin_lock(&dev->lock);
-
- } else if ((setup->bRequestType & (USB_RECIP_MASK
- | USB_TYPE_MASK)) == (USB_RECIP_DEVICE
- | USB_TYPE_STANDARD)) {
- rc = 0;
- switch (wValue) {
- case USB_DEVICE_REMOTE_WAKEUP:
- if (setup->bRequest == USB_REQ_SET_FEATURE) {
- dev->remote_wakeup = 1;
- dev->dev_status |= (1 << wValue);
- } else {
- dev->remote_wakeup = 0;
- dev->dev_status &= ~(1 << wValue);
- }
- break;
- case USB_DEVICE_TEST_MODE:
- dev_dbg(&dev->pdev->dev, "SETUP: TEST MODE\n");
- if ((wIndex & 0xff) ||
- (dev->gadget.speed != USB_SPEED_HIGH))
- ep0_stall(dev);
-
- switch (wIndex >> 8) {
- case TEST_J:
- case TEST_K:
- case TEST_SE0_NAK:
- case TEST_PACKET:
- case TEST_FORCE_EN:
- if (prime_status_phase(dev, EP_DIR_IN))
- ep0_stall(dev);
- portsc1 = readl(&dev->op_regs->portsc1);
- portsc1 |= (wIndex & 0xf00) << 8;
- writel(portsc1, &dev->op_regs->portsc1);
- goto end;
- default:
- rc = -EOPNOTSUPP;
- }
- break;
- default:
- rc = -EOPNOTSUPP;
- break;
- }
-
- if (!gadget_is_otg(&dev->gadget))
- break;
- else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
- dev->gadget.b_hnp_enable = 1;
- else if (setup->bRequest == USB_DEVICE_A_HNP_SUPPORT)
- dev->gadget.a_hnp_support = 1;
- else if (setup->bRequest ==
- USB_DEVICE_A_ALT_HNP_SUPPORT)
- dev->gadget.a_alt_hnp_support = 1;
- else
- break;
- } else
- break;
-
- if (rc == 0) {
- if (prime_status_phase(dev, EP_DIR_IN))
- ep0_stall(dev);
- }
- goto end;
- }
-
- case USB_REQ_GET_DESCRIPTOR:
- dev_dbg(&dev->pdev->dev,
- "SETUP: USB_REQ_GET_DESCRIPTOR\n");
- goto delegate;
-
- case USB_REQ_SET_DESCRIPTOR:
- dev_dbg(&dev->pdev->dev,
- "SETUP: USB_REQ_SET_DESCRIPTOR unsupported\n");
- goto delegate;
-
- case USB_REQ_GET_CONFIGURATION:
- dev_dbg(&dev->pdev->dev,
- "SETUP: USB_REQ_GET_CONFIGURATION\n");
- goto delegate;
-
- case USB_REQ_SET_CONFIGURATION:
- dev_dbg(&dev->pdev->dev,
- "SETUP: USB_REQ_SET_CONFIGURATION\n");
- goto delegate;
-
- case USB_REQ_GET_INTERFACE:
- dev_dbg(&dev->pdev->dev,
- "SETUP: USB_REQ_GET_INTERFACE\n");
- goto delegate;
-
- case USB_REQ_SET_INTERFACE:
- dev_dbg(&dev->pdev->dev,
- "SETUP: USB_REQ_SET_INTERFACE\n");
- goto delegate;
-
- case USB_REQ_SYNCH_FRAME:
- dev_dbg(&dev->pdev->dev,
- "SETUP: USB_REQ_SYNCH_FRAME unsupported\n");
- goto delegate;
-
- default:
- /* delegate USB standard requests to the gadget driver */
- goto delegate;
-delegate:
- /* USB requests handled by gadget */
- if (wLength) {
- /* DATA phase from gadget, STATUS phase from udc */
- dev->ep0_dir = (setup->bRequestType & USB_DIR_IN)
- ? USB_DIR_IN : USB_DIR_OUT;
- dev_vdbg(&dev->pdev->dev,
- "dev->ep0_dir = 0x%x, wLength = %d\n",
- dev->ep0_dir, wLength);
- spin_unlock(&dev->lock);
- if (dev->driver->setup(&dev->gadget,
- &dev->local_setup_buff) < 0)
- ep0_stall(dev);
- spin_lock(&dev->lock);
- dev->ep0_state = (setup->bRequestType & USB_DIR_IN)
- ? DATA_STATE_XMIT : DATA_STATE_RECV;
- } else {
- /* no DATA phase, IN STATUS phase from gadget */
- dev->ep0_dir = USB_DIR_IN;
- dev_vdbg(&dev->pdev->dev,
- "dev->ep0_dir = 0x%x, wLength = %d\n",
- dev->ep0_dir, wLength);
- spin_unlock(&dev->lock);
- if (dev->driver->setup(&dev->gadget,
- &dev->local_setup_buff) < 0)
- ep0_stall(dev);
- spin_lock(&dev->lock);
- dev->ep0_state = WAIT_FOR_OUT_STATUS;
- }
- break;
- }
-end:
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* transfer completion, process endpoint request and free the completed dTDs
- * for this request
- */
-static int process_ep_req(struct langwell_udc *dev, int index,
- struct langwell_request *curr_req)
-{
- struct langwell_dtd *curr_dtd;
- struct langwell_dqh *curr_dqh;
- int td_complete, actual, remaining_length;
- int i, dir;
- u8 dtd_status = 0;
- int retval = 0;
-
- curr_dqh = &dev->ep_dqh[index];
- dir = index % 2;
-
- curr_dtd = curr_req->head;
- td_complete = 0;
- actual = curr_req->req.length;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- for (i = 0; i < curr_req->dtd_count; i++) {
-
- /* command execution states by dTD */
- dtd_status = curr_dtd->dtd_status;
-
- barrier();
- remaining_length = le16_to_cpu(curr_dtd->dtd_total);
- actual -= remaining_length;
-
- if (!dtd_status) {
- /* transfers completed successfully */
- if (!remaining_length) {
- td_complete++;
- dev_vdbg(&dev->pdev->dev,
- "dTD transmitted successfully\n");
- } else {
- if (dir) {
- dev_vdbg(&dev->pdev->dev,
- "TX dTD remains data\n");
- retval = -EPROTO;
- break;
-
- } else {
- td_complete++;
- break;
- }
- }
- } else {
- /* transfers completed with errors */
- if (dtd_status & DTD_STS_ACTIVE) {
- dev_dbg(&dev->pdev->dev,
- "dTD status ACTIVE dQH[%d]\n", index);
- retval = 1;
- return retval;
- } else if (dtd_status & DTD_STS_HALTED) {
- dev_err(&dev->pdev->dev,
- "dTD error %08x dQH[%d]\n",
- dtd_status, index);
- /* clear the errors and halt condition */
- curr_dqh->dtd_status = 0;
- retval = -EPIPE;
- break;
- } else if (dtd_status & DTD_STS_DBE) {
- dev_dbg(&dev->pdev->dev,
- "data buffer (overflow) error\n");
- retval = -EPROTO;
- break;
- } else if (dtd_status & DTD_STS_TRE) {
- dev_dbg(&dev->pdev->dev,
- "transaction(ISO) error\n");
- retval = -EILSEQ;
- break;
- } else
- dev_err(&dev->pdev->dev,
- "unknown error (0x%x)!\n",
- dtd_status);
- }
-
- if (i != curr_req->dtd_count - 1)
- curr_dtd = (struct langwell_dtd *)
- curr_dtd->next_dtd_virt;
- }
-
- if (retval)
- return retval;
-
- curr_req->req.actual = actual;
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-}
-
-
-/* complete DATA or STATUS phase of ep0 prime status phase if needed */
-static void ep0_req_complete(struct langwell_udc *dev,
- struct langwell_ep *ep0, struct langwell_request *req)
-{
- u32 new_addr;
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (dev->usb_state == USB_STATE_ADDRESS) {
- /* set the new address */
- new_addr = (u32)dev->dev_addr;
- writel(new_addr << USBADR_SHIFT, &dev->op_regs->deviceaddr);
-
- new_addr = USBADR(readl(&dev->op_regs->deviceaddr));
- dev_vdbg(&dev->pdev->dev, "new_addr = %d\n", new_addr);
- }
-
- done(ep0, req, 0);
-
- switch (dev->ep0_state) {
- case DATA_STATE_XMIT:
- /* receive status phase */
- if (prime_status_phase(dev, EP_DIR_OUT))
- ep0_stall(dev);
- break;
- case DATA_STATE_RECV:
- /* send status phase */
- if (prime_status_phase(dev, EP_DIR_IN))
- ep0_stall(dev);
- break;
- case WAIT_FOR_OUT_STATUS:
- dev->ep0_state = WAIT_FOR_SETUP;
- break;
- case WAIT_FOR_SETUP:
- dev_err(&dev->pdev->dev, "unexpect ep0 packets\n");
- break;
- default:
- ep0_stall(dev);
- break;
- }
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* USB transfer completion interrupt */
-static void handle_trans_complete(struct langwell_udc *dev)
-{
- u32 complete_bits;
- int i, ep_num, dir, bit_mask, status;
- struct langwell_ep *epn;
- struct langwell_request *curr_req, *temp_req;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- complete_bits = readl(&dev->op_regs->endptcomplete);
- dev_vdbg(&dev->pdev->dev, "endptcomplete register: 0x%08x\n",
- complete_bits);
-
- /* Write-Clear the bits in endptcomplete register */
- writel(complete_bits, &dev->op_regs->endptcomplete);
-
- if (!complete_bits) {
- dev_dbg(&dev->pdev->dev, "complete_bits = 0\n");
- goto done;
- }
-
- for (i = 0; i < dev->ep_max; i++) {
- ep_num = i / 2;
- dir = i % 2;
-
- bit_mask = 1 << (ep_num + 16 * dir);
-
- if (!(complete_bits & bit_mask))
- continue;
-
- /* ep0 */
- if (i == 1)
- epn = &dev->ep[0];
- else
- epn = &dev->ep[i];
-
- if (epn->name == NULL) {
- dev_warn(&dev->pdev->dev, "invalid endpoint\n");
- continue;
- }
-
- if (i < 2)
- /* ep0 in and out */
- dev_dbg(&dev->pdev->dev, "%s-%s transfer completed\n",
- epn->name,
- is_in(epn) ? "in" : "out");
- else
- dev_dbg(&dev->pdev->dev, "%s transfer completed\n",
- epn->name);
-
- /* process the req queue until an uncomplete request */
- list_for_each_entry_safe(curr_req, temp_req,
- &epn->queue, queue) {
- status = process_ep_req(dev, i, curr_req);
- dev_vdbg(&dev->pdev->dev, "%s req status: %d\n",
- epn->name, status);
-
- if (status)
- break;
-
- /* write back status to req */
- curr_req->req.status = status;
-
- /* ep0 request completion */
- if (ep_num == 0) {
- ep0_req_complete(dev, epn, curr_req);
- break;
- } else {
- done(epn, curr_req, status);
- }
- }
- }
-done:
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-/* port change detect interrupt handler */
-static void handle_port_change(struct langwell_udc *dev)
-{
- u32 portsc1, devlc;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (dev->bus_reset)
- dev->bus_reset = 0;
-
- portsc1 = readl(&dev->op_regs->portsc1);
- devlc = readl(&dev->op_regs->devlc);
- dev_vdbg(&dev->pdev->dev, "portsc1 = 0x%08x, devlc = 0x%08x\n",
- portsc1, devlc);
-
- /* bus reset is finished */
- if (!(portsc1 & PORTS_PR)) {
- /* get the speed */
- dev->gadget.speed = lpm_device_speed(devlc);
- dev_vdbg(&dev->pdev->dev, "dev->gadget.speed = %d\n",
- dev->gadget.speed);
- }
-
- /* LPM L0 to L1 */
- if (dev->lpm && dev->lpm_state == LPM_L0)
- if (portsc1 & PORTS_SUSP && portsc1 & PORTS_SLP) {
- dev_info(&dev->pdev->dev, "LPM L0 to L1\n");
- dev->lpm_state = LPM_L1;
- }
-
- /* LPM L1 to L0, force resume or remote wakeup finished */
- if (dev->lpm && dev->lpm_state == LPM_L1)
- if (!(portsc1 & PORTS_SUSP)) {
- dev_info(&dev->pdev->dev, "LPM L1 to L0\n");
- dev->lpm_state = LPM_L0;
- }
-
- /* update USB state */
- if (!dev->resume_state)
- dev->usb_state = USB_STATE_DEFAULT;
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* USB reset interrupt handler */
-static void handle_usb_reset(struct langwell_udc *dev)
-{
- u32 deviceaddr,
- endptsetupstat,
- endptcomplete;
- unsigned long timeout;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* Write-Clear the device address */
- deviceaddr = readl(&dev->op_regs->deviceaddr);
- writel(deviceaddr & ~USBADR_MASK, &dev->op_regs->deviceaddr);
-
- dev->dev_addr = 0;
-
- /* clear usb state */
- dev->resume_state = 0;
-
- /* LPM L1 to L0, reset */
- if (dev->lpm)
- dev->lpm_state = LPM_L0;
-
- dev->ep0_dir = USB_DIR_OUT;
- dev->ep0_state = WAIT_FOR_SETUP;
-
- /* remote wakeup reset to 0 when the device is reset */
- dev->remote_wakeup = 0;
- dev->dev_status = 1 << USB_DEVICE_SELF_POWERED;
- dev->gadget.b_hnp_enable = 0;
- dev->gadget.a_hnp_support = 0;
- dev->gadget.a_alt_hnp_support = 0;
-
- /* Write-Clear all the setup token semaphores */
- endptsetupstat = readl(&dev->op_regs->endptsetupstat);
- writel(endptsetupstat, &dev->op_regs->endptsetupstat);
-
- /* Write-Clear all the endpoint complete status bits */
- endptcomplete = readl(&dev->op_regs->endptcomplete);
- writel(endptcomplete, &dev->op_regs->endptcomplete);
-
- /* wait until all endptprime bits cleared */
- timeout = jiffies + PRIME_TIMEOUT;
- while (readl(&dev->op_regs->endptprime)) {
- if (time_after(jiffies, timeout)) {
- dev_err(&dev->pdev->dev, "USB reset timeout\n");
- break;
- }
- cpu_relax();
- }
-
- /* write 1s to endptflush register to clear any primed buffers */
- writel((u32) ~0, &dev->op_regs->endptflush);
-
- if (readl(&dev->op_regs->portsc1) & PORTS_PR) {
- dev_vdbg(&dev->pdev->dev, "USB bus reset\n");
- /* bus is reseting */
- dev->bus_reset = 1;
-
- /* reset all the queues, stop all USB activities */
- stop_activity(dev);
- dev->usb_state = USB_STATE_DEFAULT;
- } else {
- dev_vdbg(&dev->pdev->dev, "device controller reset\n");
- /* controller reset */
- langwell_udc_reset(dev);
-
- /* reset all the queues, stop all USB activities */
- stop_activity(dev);
-
- /* reset ep0 dQH and endptctrl */
- ep0_reset(dev);
-
- /* enable interrupt and set controller to run state */
- langwell_udc_start(dev);
-
- dev->usb_state = USB_STATE_ATTACHED;
- }
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* USB bus suspend/resume interrupt */
-static void handle_bus_suspend(struct langwell_udc *dev)
-{
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- dev->resume_state = dev->usb_state;
- dev->usb_state = USB_STATE_SUSPENDED;
-
- /* report suspend to the driver */
- if (dev->driver) {
- if (dev->driver->suspend) {
- spin_unlock(&dev->lock);
- dev->driver->suspend(&dev->gadget);
- spin_lock(&dev->lock);
- dev_dbg(&dev->pdev->dev, "suspend %s\n",
- dev->driver->driver.name);
- }
- }
-
- /* enter PHY low power suspend */
- if (dev->pdev->device != 0x0829)
- langwell_phy_low_power(dev, 0);
-
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-static void handle_bus_resume(struct langwell_udc *dev)
-{
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- dev->usb_state = dev->resume_state;
- dev->resume_state = 0;
-
- /* exit PHY low power suspend */
- if (dev->pdev->device != 0x0829)
- langwell_phy_low_power(dev, 0);
-
- /* report resume to the driver */
- if (dev->driver) {
- if (dev->driver->resume) {
- spin_unlock(&dev->lock);
- dev->driver->resume(&dev->gadget);
- spin_lock(&dev->lock);
- dev_dbg(&dev->pdev->dev, "resume %s\n",
- dev->driver->driver.name);
- }
- }
-
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* USB device controller interrupt handler */
-static irqreturn_t langwell_irq(int irq, void *_dev)
-{
- struct langwell_udc *dev = _dev;
- u32 usbsts,
- usbintr,
- irq_sts,
- portsc1;
-
- dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- if (dev->stopped) {
- dev_vdbg(&dev->pdev->dev, "handle IRQ_NONE\n");
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return IRQ_NONE;
- }
-
- spin_lock(&dev->lock);
-
- /* USB status */
- usbsts = readl(&dev->op_regs->usbsts);
-
- /* USB interrupt enable */
- usbintr = readl(&dev->op_regs->usbintr);
-
- irq_sts = usbsts & usbintr;
- dev_vdbg(&dev->pdev->dev,
- "usbsts = 0x%08x, usbintr = 0x%08x, irq_sts = 0x%08x\n",
- usbsts, usbintr, irq_sts);
-
- if (!irq_sts) {
- dev_vdbg(&dev->pdev->dev, "handle IRQ_NONE\n");
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- spin_unlock(&dev->lock);
- return IRQ_NONE;
- }
-
- /* Write-Clear interrupt status bits */
- writel(irq_sts, &dev->op_regs->usbsts);
-
- /* resume from suspend */
- portsc1 = readl(&dev->op_regs->portsc1);
- if (dev->usb_state == USB_STATE_SUSPENDED)
- if (!(portsc1 & PORTS_SUSP))
- handle_bus_resume(dev);
-
- /* USB interrupt */
- if (irq_sts & STS_UI) {
- dev_vdbg(&dev->pdev->dev, "USB interrupt\n");
-
- /* setup packet received from ep0 */
- if (readl(&dev->op_regs->endptsetupstat)
- & EP0SETUPSTAT_MASK) {
- dev_vdbg(&dev->pdev->dev,
- "USB SETUP packet received interrupt\n");
- /* setup tripwire semaphone */
- setup_tripwire(dev);
- handle_setup_packet(dev, &dev->local_setup_buff);
- }
-
- /* USB transfer completion */
- if (readl(&dev->op_regs->endptcomplete)) {
- dev_vdbg(&dev->pdev->dev,
- "USB transfer completion interrupt\n");
- handle_trans_complete(dev);
- }
- }
-
- /* SOF received interrupt (for ISO transfer) */
- if (irq_sts & STS_SRI) {
- /* FIXME */
- /* dev_vdbg(&dev->pdev->dev, "SOF received interrupt\n"); */
- }
-
- /* port change detect interrupt */
- if (irq_sts & STS_PCI) {
- dev_vdbg(&dev->pdev->dev, "port change detect interrupt\n");
- handle_port_change(dev);
- }
-
- /* suspend interrupt */
- if (irq_sts & STS_SLI) {
- dev_vdbg(&dev->pdev->dev, "suspend interrupt\n");
- handle_bus_suspend(dev);
- }
-
- /* USB reset interrupt */
- if (irq_sts & STS_URI) {
- dev_vdbg(&dev->pdev->dev, "USB reset interrupt\n");
- handle_usb_reset(dev);
- }
-
- /* USB error or system error interrupt */
- if (irq_sts & (STS_UEI | STS_SEI)) {
- /* FIXME */
- dev_warn(&dev->pdev->dev, "error IRQ, irq_sts: %x\n", irq_sts);
- }
-
- spin_unlock(&dev->lock);
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return IRQ_HANDLED;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* release device structure */
-static void gadget_release(struct device *_dev)
-{
- struct langwell_udc *dev = dev_get_drvdata(_dev);
-
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- complete(dev->done);
-
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- kfree(dev);
-}
-
-
-/* enable SRAM caching if SRAM detected */
-static void sram_init(struct langwell_udc *dev)
-{
- struct pci_dev *pdev = dev->pdev;
-
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- dev->sram_addr = pci_resource_start(pdev, 1);
- dev->sram_size = pci_resource_len(pdev, 1);
- dev_info(&dev->pdev->dev, "Found private SRAM at %x size:%x\n",
- dev->sram_addr, dev->sram_size);
- dev->got_sram = 1;
-
- if (pci_request_region(pdev, 1, kobject_name(&pdev->dev.kobj))) {
- dev_warn(&dev->pdev->dev, "SRAM request failed\n");
- dev->got_sram = 0;
- } else if (!dma_declare_coherent_memory(&pdev->dev, dev->sram_addr,
- dev->sram_addr, dev->sram_size, DMA_MEMORY_MAP)) {
- dev_warn(&dev->pdev->dev, "SRAM DMA declare failed\n");
- pci_release_region(pdev, 1);
- dev->got_sram = 0;
- }
-
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* release SRAM caching */
-static void sram_deinit(struct langwell_udc *dev)
-{
- struct pci_dev *pdev = dev->pdev;
-
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- dma_release_declared_memory(&pdev->dev);
- pci_release_region(pdev, 1);
-
- dev->got_sram = 0;
-
- dev_info(&dev->pdev->dev, "release SRAM caching\n");
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-
-/* tear down the binding between this driver and the pci device */
-static void langwell_udc_remove(struct pci_dev *pdev)
-{
- struct langwell_udc *dev = pci_get_drvdata(pdev);
-
- DECLARE_COMPLETION(done);
-
- BUG_ON(dev->driver);
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- dev->done = &done;
-
- /* free dTD dma_pool and dQH */
- if (dev->dtd_pool)
- dma_pool_destroy(dev->dtd_pool);
-
- if (dev->ep_dqh)
- dma_free_coherent(&pdev->dev, dev->ep_dqh_size,
- dev->ep_dqh, dev->ep_dqh_dma);
-
- /* release SRAM caching */
- if (dev->has_sram && dev->got_sram)
- sram_deinit(dev);
-
- if (dev->status_req) {
- kfree(dev->status_req->req.buf);
- kfree(dev->status_req);
- }
-
- kfree(dev->ep);
-
- /* disable IRQ handler */
- if (dev->got_irq)
- free_irq(pdev->irq, dev);
-
- if (dev->cap_regs)
- iounmap(dev->cap_regs);
-
- if (dev->region)
- release_mem_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
-
- if (dev->enabled)
- pci_disable_device(pdev);
-
- dev->cap_regs = NULL;
-
- dev_info(&dev->pdev->dev, "unbind\n");
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-
- device_unregister(&dev->gadget.dev);
- device_remove_file(&pdev->dev, &dev_attr_langwell_udc);
- device_remove_file(&pdev->dev, &dev_attr_remote_wakeup);
-
- pci_set_drvdata(pdev, NULL);
-
- /* free dev, wait for the release() finished */
- wait_for_completion(&done);
-}
-
-
-/*
- * wrap this driver around the specified device, but
- * don't respond over USB until a gadget driver binds to us.
- */
-static int langwell_udc_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
-{
- struct langwell_udc *dev;
- unsigned long resource, len;
- void __iomem *base = NULL;
- size_t size;
- int retval;
-
- /* alloc, and start init */
- dev = kzalloc(sizeof *dev, GFP_KERNEL);
- if (dev == NULL) {
- retval = -ENOMEM;
- goto error;
- }
-
- /* initialize device spinlock */
- spin_lock_init(&dev->lock);
-
- dev->pdev = pdev;
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- pci_set_drvdata(pdev, dev);
-
- /* now all the pci goodies ... */
- if (pci_enable_device(pdev) < 0) {
- retval = -ENODEV;
- goto error;
- }
- dev->enabled = 1;
-
- /* control register: BAR 0 */
- resource = pci_resource_start(pdev, 0);
- len = pci_resource_len(pdev, 0);
- if (!request_mem_region(resource, len, driver_name)) {
- dev_err(&dev->pdev->dev, "controller already in use\n");
- retval = -EBUSY;
- goto error;
- }
- dev->region = 1;
-
- base = ioremap_nocache(resource, len);
- if (base == NULL) {
- dev_err(&dev->pdev->dev, "can't map memory\n");
- retval = -EFAULT;
- goto error;
- }
-
- dev->cap_regs = (struct langwell_cap_regs __iomem *) base;
- dev_vdbg(&dev->pdev->dev, "dev->cap_regs: %p\n", dev->cap_regs);
- dev->op_regs = (struct langwell_op_regs __iomem *)
- (base + OP_REG_OFFSET);
- dev_vdbg(&dev->pdev->dev, "dev->op_regs: %p\n", dev->op_regs);
-
- /* irq setup after old hardware is cleaned up */
- if (!pdev->irq) {
- dev_err(&dev->pdev->dev, "No IRQ. Check PCI setup!\n");
- retval = -ENODEV;
- goto error;
- }
-
- dev->has_sram = 1;
- dev->got_sram = 0;
- dev_vdbg(&dev->pdev->dev, "dev->has_sram: %d\n", dev->has_sram);
-
- /* enable SRAM caching if detected */
- if (dev->has_sram && !dev->got_sram)
- sram_init(dev);
-
- dev_info(&dev->pdev->dev,
- "irq %d, io mem: 0x%08lx, len: 0x%08lx, pci mem 0x%p\n",
- pdev->irq, resource, len, base);
- /* enables bus-mastering for device dev */
- pci_set_master(pdev);
-
- if (request_irq(pdev->irq, langwell_irq, IRQF_SHARED,
- driver_name, dev) != 0) {
- dev_err(&dev->pdev->dev,
- "request interrupt %d failed\n", pdev->irq);
- retval = -EBUSY;
- goto error;
- }
- dev->got_irq = 1;
-
- /* set stopped bit */
- dev->stopped = 1;
-
- /* capabilities and endpoint number */
- dev->lpm = (readl(&dev->cap_regs->hccparams) & HCC_LEN) ? 1 : 0;
- dev->dciversion = readw(&dev->cap_regs->dciversion);
- dev->devcap = (readl(&dev->cap_regs->dccparams) & DEVCAP) ? 1 : 0;
- dev_vdbg(&dev->pdev->dev, "dev->lpm: %d\n", dev->lpm);
- dev_vdbg(&dev->pdev->dev, "dev->dciversion: 0x%04x\n",
- dev->dciversion);
- dev_vdbg(&dev->pdev->dev, "dccparams: 0x%08x\n",
- readl(&dev->cap_regs->dccparams));
- dev_vdbg(&dev->pdev->dev, "dev->devcap: %d\n", dev->devcap);
- if (!dev->devcap) {
- dev_err(&dev->pdev->dev, "can't support device mode\n");
- retval = -ENODEV;
- goto error;
- }
-
- /* a pair of endpoints (out/in) for each address */
- dev->ep_max = DEN(readl(&dev->cap_regs->dccparams)) * 2;
- dev_vdbg(&dev->pdev->dev, "dev->ep_max: %d\n", dev->ep_max);
-
- /* allocate endpoints memory */
- dev->ep = kzalloc(sizeof(struct langwell_ep) * dev->ep_max,
- GFP_KERNEL);
- if (!dev->ep) {
- dev_err(&dev->pdev->dev, "allocate endpoints memory failed\n");
- retval = -ENOMEM;
- goto error;
- }
-
- /* allocate device dQH memory */
- size = dev->ep_max * sizeof(struct langwell_dqh);
- dev_vdbg(&dev->pdev->dev, "orig size = %zd\n", size);
- if (size < DQH_ALIGNMENT)
- size = DQH_ALIGNMENT;
- else if ((size % DQH_ALIGNMENT) != 0) {
- size += DQH_ALIGNMENT + 1;
- size &= ~(DQH_ALIGNMENT - 1);
- }
- dev->ep_dqh = dma_alloc_coherent(&pdev->dev, size,
- &dev->ep_dqh_dma, GFP_KERNEL);
- if (!dev->ep_dqh) {
- dev_err(&dev->pdev->dev, "allocate dQH memory failed\n");
- retval = -ENOMEM;
- goto error;
- }
- dev->ep_dqh_size = size;
- dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %zd\n", dev->ep_dqh_size);
-
- /* initialize ep0 status request structure */
- dev->status_req = kzalloc(sizeof(struct langwell_request), GFP_KERNEL);
- if (!dev->status_req) {
- dev_err(&dev->pdev->dev,
- "allocate status_req memory failed\n");
- retval = -ENOMEM;
- goto error;
- }
- INIT_LIST_HEAD(&dev->status_req->queue);
-
- /* allocate a small amount of memory to get valid address */
- dev->status_req->req.buf = kmalloc(8, GFP_KERNEL);
- dev->status_req->req.dma = virt_to_phys(dev->status_req->req.buf);
-
- dev->resume_state = USB_STATE_NOTATTACHED;
- dev->usb_state = USB_STATE_POWERED;
- dev->ep0_dir = USB_DIR_OUT;
-
- /* remote wakeup reset to 0 when the device is reset */
- dev->remote_wakeup = 0;
- dev->dev_status = 1 << USB_DEVICE_SELF_POWERED;
-
- /* reset device controller */
- langwell_udc_reset(dev);
-
- /* initialize gadget structure */
- dev->gadget.ops = &langwell_ops; /* usb_gadget_ops */
- dev->gadget.ep0 = &dev->ep[0].ep; /* gadget ep0 */
- INIT_LIST_HEAD(&dev->gadget.ep_list); /* ep_list */
- dev->gadget.speed = USB_SPEED_UNKNOWN; /* speed */
- dev->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */
-
- /* the "gadget" abstracts/virtualizes the controller */
- dev_set_name(&dev->gadget.dev, "gadget");
- dev->gadget.dev.parent = &pdev->dev;
- dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
- dev->gadget.dev.release = gadget_release;
- dev->gadget.name = driver_name; /* gadget name */
-
- /* controller endpoints reinit */
- eps_reinit(dev);
-
- /* reset ep0 dQH and endptctrl */
- ep0_reset(dev);
-
- /* create dTD dma_pool resource */
- dev->dtd_pool = dma_pool_create("langwell_dtd",
- &dev->pdev->dev,
- sizeof(struct langwell_dtd),
- DTD_ALIGNMENT,
- DMA_BOUNDARY);
-
- if (!dev->dtd_pool) {
- retval = -ENOMEM;
- goto error;
- }
-
- /* done */
- dev_info(&dev->pdev->dev, "%s\n", driver_desc);
- dev_info(&dev->pdev->dev, "irq %d, pci mem %p\n", pdev->irq, base);
- dev_info(&dev->pdev->dev, "Driver version: " DRIVER_VERSION "\n");
- dev_info(&dev->pdev->dev, "Support (max) %d endpoints\n", dev->ep_max);
- dev_info(&dev->pdev->dev, "Device interface version: 0x%04x\n",
- dev->dciversion);
- dev_info(&dev->pdev->dev, "Controller mode: %s\n",
- dev->devcap ? "Device" : "Host");
- dev_info(&dev->pdev->dev, "Support USB LPM: %s\n",
- dev->lpm ? "Yes" : "No");
-
- dev_vdbg(&dev->pdev->dev,
- "After langwell_udc_probe(), print all registers:\n");
- print_all_registers(dev);
-
- retval = device_register(&dev->gadget.dev);
- if (retval)
- goto error;
-
- retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
- if (retval)
- goto error;
-
- retval = device_create_file(&pdev->dev, &dev_attr_langwell_udc);
- if (retval)
- goto error;
-
- retval = device_create_file(&pdev->dev, &dev_attr_remote_wakeup);
- if (retval)
- goto error_attr1;
-
- dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-
-error_attr1:
- device_remove_file(&pdev->dev, &dev_attr_langwell_udc);
-error:
- if (dev) {
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- langwell_udc_remove(pdev);
- }
-
- return retval;
-}
-
-
-/* device controller suspend */
-static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- struct langwell_udc *dev = pci_get_drvdata(pdev);
-
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- usb_del_gadget_udc(&dev->gadget);
- /* disable interrupt and set controller to stop state */
- langwell_udc_stop(dev);
-
- /* disable IRQ handler */
- if (dev->got_irq)
- free_irq(pdev->irq, dev);
- dev->got_irq = 0;
-
- /* save PCI state */
- pci_save_state(pdev);
-
- spin_lock_irq(&dev->lock);
- /* stop all usb activities */
- stop_activity(dev);
- spin_unlock_irq(&dev->lock);
-
- /* free dTD dma_pool and dQH */
- if (dev->dtd_pool)
- dma_pool_destroy(dev->dtd_pool);
-
- if (dev->ep_dqh)
- dma_free_coherent(&pdev->dev, dev->ep_dqh_size,
- dev->ep_dqh, dev->ep_dqh_dma);
-
- /* release SRAM caching */
- if (dev->has_sram && dev->got_sram)
- sram_deinit(dev);
-
- /* set device power state */
- pci_set_power_state(pdev, PCI_D3hot);
-
- /* enter PHY low power suspend */
- if (dev->pdev->device != 0x0829)
- langwell_phy_low_power(dev, 1);
-
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-}
-
-
-/* device controller resume */
-static int langwell_udc_resume(struct pci_dev *pdev)
-{
- struct langwell_udc *dev = pci_get_drvdata(pdev);
- size_t size;
-
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* exit PHY low power suspend */
- if (dev->pdev->device != 0x0829)
- langwell_phy_low_power(dev, 0);
-
- /* set device D0 power state */
- pci_set_power_state(pdev, PCI_D0);
-
- /* enable SRAM caching if detected */
- if (dev->has_sram && !dev->got_sram)
- sram_init(dev);
-
- /* allocate device dQH memory */
- size = dev->ep_max * sizeof(struct langwell_dqh);
- dev_vdbg(&dev->pdev->dev, "orig size = %zd\n", size);
- if (size < DQH_ALIGNMENT)
- size = DQH_ALIGNMENT;
- else if ((size % DQH_ALIGNMENT) != 0) {
- size += DQH_ALIGNMENT + 1;
- size &= ~(DQH_ALIGNMENT - 1);
- }
- dev->ep_dqh = dma_alloc_coherent(&pdev->dev, size,
- &dev->ep_dqh_dma, GFP_KERNEL);
- if (!dev->ep_dqh) {
- dev_err(&dev->pdev->dev, "allocate dQH memory failed\n");
- return -ENOMEM;
- }
- dev->ep_dqh_size = size;
- dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %zd\n", dev->ep_dqh_size);
-
- /* create dTD dma_pool resource */
- dev->dtd_pool = dma_pool_create("langwell_dtd",
- &dev->pdev->dev,
- sizeof(struct langwell_dtd),
- DTD_ALIGNMENT,
- DMA_BOUNDARY);
-
- if (!dev->dtd_pool)
- return -ENOMEM;
-
- /* restore PCI state */
- pci_restore_state(pdev);
-
- /* enable IRQ handler */
- if (request_irq(pdev->irq, langwell_irq, IRQF_SHARED,
- driver_name, dev) != 0) {
- dev_err(&dev->pdev->dev, "request interrupt %d failed\n",
- pdev->irq);
- return -EBUSY;
- }
- dev->got_irq = 1;
-
- /* reset and start controller to run state */
- if (dev->stopped) {
- /* reset device controller */
- langwell_udc_reset(dev);
-
- /* reset ep0 dQH and endptctrl */
- ep0_reset(dev);
-
- /* start device if gadget is loaded */
- if (dev->driver)
- langwell_udc_start(dev);
- }
-
- /* reset USB status */
- dev->usb_state = USB_STATE_ATTACHED;
- dev->ep0_state = WAIT_FOR_SETUP;
- dev->ep0_dir = USB_DIR_OUT;
-
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return 0;
-}
-
-
-/* pci driver shutdown */
-static void langwell_udc_shutdown(struct pci_dev *pdev)
-{
- struct langwell_udc *dev = pci_get_drvdata(pdev);
- u32 usbmode;
-
- dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
-
- /* reset controller mode to IDLE */
- usbmode = readl(&dev->op_regs->usbmode);
- dev_dbg(&dev->pdev->dev, "usbmode = 0x%08x\n", usbmode);
- usbmode &= (~3 | MODE_IDLE);
- writel(usbmode, &dev->op_regs->usbmode);
-
- dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
-}
-
-/*-------------------------------------------------------------------------*/
-
-static const struct pci_device_id pci_ids[] = { {
- .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
- .class_mask = ~0,
- .vendor = 0x8086,
- .device = 0x0811,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
-}, { /* end: all zeroes */ }
-};
-
-MODULE_DEVICE_TABLE(pci, pci_ids);
-
-
-static struct pci_driver langwell_pci_driver = {
- .name = (char *) driver_name,
- .id_table = pci_ids,
-
- .probe = langwell_udc_probe,
- .remove = langwell_udc_remove,
-
- /* device controller suspend/resume */
- .suspend = langwell_udc_suspend,
- .resume = langwell_udc_resume,
-
- .shutdown = langwell_udc_shutdown,
-};
-
-
-static int __init init(void)
-{
- return pci_register_driver(&langwell_pci_driver);
-}
-module_init(init);
-
-
-static void __exit cleanup(void)
-{
- pci_unregister_driver(&langwell_pci_driver);
-}
-module_exit(cleanup);
-
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Xiaochen Shen <xiaochen.shen@intel.com>");
-MODULE_VERSION(DRIVER_VERSION);
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/usb/gadget/langwell_udc.h b/drivers/usb/gadget/langwell_udc.h
deleted file mode 100644
index 8c8087abb481..000000000000
--- a/drivers/usb/gadget/langwell_udc.h
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Intel Langwell USB Device Controller driver
- * Copyright (C) 2008-2009, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- */
-
-#include <linux/usb/langwell_udc.h>
-
-/*-------------------------------------------------------------------------*/
-
-/* driver data structures and utilities */
-
-/*
- * dTD: Device Endpoint Transfer Descriptor
- * describe to the device controller the location and quantity of
- * data to be send/received for given transfer
- */
-struct langwell_dtd {
- u32 dtd_next;
-/* bits 31:5, next transfer element pointer */
-#define DTD_NEXT(d) (((d)>>5)&0x7ffffff)
-#define DTD_NEXT_MASK (0x7ffffff << 5)
-/* terminate */
-#define DTD_TERM BIT(0)
- /* bits 7:0, execution back states */
- u32 dtd_status:8;
-#define DTD_STATUS(d) (((d)>>0)&0xff)
-#define DTD_STS_ACTIVE BIT(7) /* active */
-#define DTD_STS_HALTED BIT(6) /* halted */
-#define DTD_STS_DBE BIT(5) /* data buffer error */
-#define DTD_STS_TRE BIT(3) /* transaction error */
- /* bits 9:8 */
- u32 dtd_res0:2;
- /* bits 11:10, multipier override */
- u32 dtd_multo:2;
-#define DTD_MULTO (BIT(11) | BIT(10))
- /* bits 14:12 */
- u32 dtd_res1:3;
- /* bit 15, interrupt on complete */
- u32 dtd_ioc:1;
-#define DTD_IOC BIT(15)
- /* bits 30:16, total bytes */
- u32 dtd_total:15;
-#define DTD_TOTAL(d) (((d)>>16)&0x7fff)
-#define DTD_MAX_TRANSFER_LENGTH 0x4000
- /* bit 31 */
- u32 dtd_res2:1;
- /* dTD buffer pointer page 0 to 4 */
- u32 dtd_buf[5];
-#define DTD_OFFSET_MASK 0xfff
-/* bits 31:12, buffer pointer */
-#define DTD_BUFFER(d) (((d)>>12)&0x3ff)
-/* bits 11:0, current offset */
-#define DTD_C_OFFSET(d) (((d)>>0)&0xfff)
-/* bits 10:0, frame number */
-#define DTD_FRAME(d) (((d)>>0)&0x7ff)
-
- /* driver-private parts */
-
- /* dtd dma address */
- dma_addr_t dtd_dma;
- /* next dtd virtual address */
- struct langwell_dtd *next_dtd_virt;
-};
-
-
-/*
- * dQH: Device Endpoint Queue Head
- * describe where all transfers are managed
- * 48-byte data structure, aligned on 64-byte boundary
- *
- * These are associated with dTD structure
- */
-struct langwell_dqh {
- /* endpoint capabilities and characteristics */
- u32 dqh_res0:15; /* bits 14:0 */
- u32 dqh_ios:1; /* bit 15, interrupt on setup */
-#define DQH_IOS BIT(15)
- u32 dqh_mpl:11; /* bits 26:16, maximum packet length */
-#define DQH_MPL (0x7ff << 16)
- u32 dqh_res1:2; /* bits 28:27 */
- u32 dqh_zlt:1; /* bit 29, zero length termination */
-#define DQH_ZLT BIT(29)
- u32 dqh_mult:2; /* bits 31:30 */
-#define DQH_MULT (BIT(30) | BIT(31))
-
- /* current dTD pointer */
- u32 dqh_current; /* locate the transfer in progress */
-#define DQH_C_DTD(e) \
- (((e)>>5)&0x7ffffff) /* bits 31:5, current dTD pointer */
-
- /* transfer overlay, hardware parts of a struct langwell_dtd */
- u32 dtd_next;
- u32 dtd_status:8; /* bits 7:0, execution back states */
- u32 dtd_res0:2; /* bits 9:8 */
- u32 dtd_multo:2; /* bits 11:10, multipier override */
- u32 dtd_res1:3; /* bits 14:12 */
- u32 dtd_ioc:1; /* bit 15, interrupt on complete */
- u32 dtd_total:15; /* bits 30:16, total bytes */
- u32 dtd_res2:1; /* bit 31 */
- u32 dtd_buf[5]; /* dTD buffer pointer page 0 to 4 */
-
- u32 dqh_res2;
- struct usb_ctrlrequest dqh_setup; /* setup packet buffer */
-} __attribute__ ((aligned(64)));
-
-
-/* endpoint data structure */
-struct langwell_ep {
- struct usb_ep ep;
- dma_addr_t dma;
- struct langwell_udc *dev;
- unsigned long irqs;
- struct list_head queue;
- struct langwell_dqh *dqh;
- const struct usb_endpoint_descriptor *desc;
- char name[14];
- unsigned stopped:1,
- ep_type:2,
- ep_num:8;
-};
-
-
-/* request data structure */
-struct langwell_request {
- struct usb_request req;
- struct langwell_dtd *dtd, *head, *tail;
- struct langwell_ep *ep;
- dma_addr_t dtd_dma;
- struct list_head queue;
- unsigned dtd_count;
- unsigned mapped:1;
-};
-
-
-/* ep0 transfer state */
-enum ep0_state {
- WAIT_FOR_SETUP,
- DATA_STATE_XMIT,
- DATA_STATE_NEED_ZLP,
- WAIT_FOR_OUT_STATUS,
- DATA_STATE_RECV,
-};
-
-
-/* device suspend state */
-enum lpm_state {
- LPM_L0, /* on */
- LPM_L1, /* LPM L1 sleep */
- LPM_L2, /* suspend */
- LPM_L3, /* off */
-};
-
-
-/* device data structure */
-struct langwell_udc {
- /* each pci device provides one gadget, several endpoints */
- struct usb_gadget gadget;
- spinlock_t lock; /* device lock */
- struct langwell_ep *ep;
- struct usb_gadget_driver *driver;
- struct usb_phy *transceiver;
- u8 dev_addr;
- u32 usb_state;
- u32 resume_state;
- u32 bus_reset;
- enum lpm_state lpm_state;
- enum ep0_state ep0_state;
- u32 ep0_dir;
- u16 dciversion;
- unsigned ep_max;
- unsigned devcap:1,
- enabled:1,
- region:1,
- got_irq:1,
- powered:1,
- remote_wakeup:1,
- rate:1,
- is_reset:1,
- softconnected:1,
- vbus_active:1,
- suspended:1,
- stopped:1,
- lpm:1, /* LPM capability */
- has_sram:1, /* SRAM caching */
- got_sram:1;
-
- /* pci state used to access those endpoints */
- struct pci_dev *pdev;
-
- /* Langwell otg transceiver */
- struct langwell_otg *lotg;
-
- /* control registers */
- struct langwell_cap_regs __iomem *cap_regs;
- struct langwell_op_regs __iomem *op_regs;
-
- struct usb_ctrlrequest local_setup_buff;
- struct langwell_dqh *ep_dqh;
- size_t ep_dqh_size;
- dma_addr_t ep_dqh_dma;
-
- /* ep0 status request */
- struct langwell_request *status_req;
-
- /* dma pool */
- struct dma_pool *dtd_pool;
-
- /* make sure release() is done */
- struct completion *done;
-
- /* for private SRAM caching */
- unsigned int sram_addr;
- unsigned int sram_size;
-
- /* device status data for get_status request */
- u16 dev_status;
-};
-
-#define gadget_to_langwell(g) container_of((g), struct langwell_udc, gadget)
-
diff --git a/drivers/usb/gadget/lpc32xx_udc.c b/drivers/usb/gadget/lpc32xx_udc.c
new file mode 100644
index 000000000000..262acfd53e32
--- /dev/null
+++ b/drivers/usb/gadget/lpc32xx_udc.c
@@ -0,0 +1,3538 @@
+/*
+ * USB Gadget driver for LPC32xx
+ *
+ * Authors:
+ * Kevin Wells <kevin.wells@nxp.com>
+ * Mike James
+ * Roland Stigge <stigge@antcom.de>
+ *
+ * Copyright (C) 2006 Philips Semiconductors
+ * Copyright (C) 2009 NXP Semiconductors
+ * Copyright (C) 2012 Roland Stigge
+ *
+ * Note: This driver is based on original work done by Mike James for
+ * the LPC3180.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/clk.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/i2c.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/workqueue.h>
+#include <linux/of.h>
+#include <linux/usb/isp1301.h>
+
+#include <asm/byteorder.h>
+#include <mach/hardware.h>
+#include <linux/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include <mach/platform.h>
+#include <mach/irqs.h>
+#include <mach/board.h>
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+#include <linux/seq_file.h>
+#endif
+
+/*
+ * USB device configuration structure
+ */
+typedef void (*usc_chg_event)(int);
+struct lpc32xx_usbd_cfg {
+ int vbus_drv_pol; /* 0=active low drive for VBUS via ISP1301 */
+ usc_chg_event conn_chgb; /* Connection change event (optional) */
+ usc_chg_event susp_chgb; /* Suspend/resume event (optional) */
+ usc_chg_event rmwk_chgb; /* Enable/disable remote wakeup */
+};
+
+/*
+ * controller driver data structures
+ */
+
+/* 16 endpoints (not to be confused with 32 hardware endpoints) */
+#define NUM_ENDPOINTS 16
+
+/*
+ * IRQ indices make reading the code a little easier
+ */
+#define IRQ_USB_LP 0
+#define IRQ_USB_HP 1
+#define IRQ_USB_DEVDMA 2
+#define IRQ_USB_ATX 3
+
+#define EP_OUT 0 /* RX (from host) */
+#define EP_IN 1 /* TX (to host) */
+
+/* Returns the interrupt mask for the selected hardware endpoint */
+#define EP_MASK_SEL(ep, dir) (1 << (((ep) * 2) + dir))
+
+#define EP_INT_TYPE 0
+#define EP_ISO_TYPE 1
+#define EP_BLK_TYPE 2
+#define EP_CTL_TYPE 3
+
+/* EP0 states */
+#define WAIT_FOR_SETUP 0 /* Wait for setup packet */
+#define DATA_IN 1 /* Expect dev->host transfer */
+#define DATA_OUT 2 /* Expect host->dev transfer */
+
+/* DD (DMA Descriptor) structure, requires word alignment, this is already
+ * defined in the LPC32XX USB device header file, but this version is slightly
+ * modified to tag some work data with each DMA descriptor. */
+struct lpc32xx_usbd_dd_gad {
+ u32 dd_next_phy;
+ u32 dd_setup;
+ u32 dd_buffer_addr;
+ u32 dd_status;
+ u32 dd_iso_ps_mem_addr;
+ u32 this_dma;
+ u32 iso_status[6]; /* 5 spare */
+ u32 dd_next_v;
+};
+
+/*
+ * Logical endpoint structure
+ */
+struct lpc32xx_ep {
+ struct usb_ep ep;
+ struct list_head queue;
+ struct lpc32xx_udc *udc;
+
+ u32 hwep_num_base; /* Physical hardware EP */
+ u32 hwep_num; /* Maps to hardware endpoint */
+ u32 maxpacket;
+ u32 lep;
+
+ bool is_in;
+ bool req_pending;
+ u32 eptype;
+
+ u32 totalints;
+
+ bool wedge;
+
+ const struct usb_endpoint_descriptor *desc;
+};
+
+/*
+ * Common UDC structure
+ */
+struct lpc32xx_udc {
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ struct platform_device *pdev;
+ struct device *dev;
+ struct dentry *pde;
+ spinlock_t lock;
+ struct i2c_client *isp1301_i2c_client;
+
+ /* Board and device specific */
+ struct lpc32xx_usbd_cfg *board;
+ u32 io_p_start;
+ u32 io_p_size;
+ void __iomem *udp_baseaddr;
+ int udp_irq[4];
+ struct clk *usb_pll_clk;
+ struct clk *usb_slv_clk;
+
+ /* DMA support */
+ u32 *udca_v_base;
+ u32 udca_p_base;
+ struct dma_pool *dd_cache;
+
+ /* Common EP and control data */
+ u32 enabled_devints;
+ u32 enabled_hwepints;
+ u32 dev_status;
+ u32 realized_eps;
+
+ /* VBUS detection, pullup, and power flags */
+ u8 vbus;
+ u8 last_vbus;
+ int pullup;
+ int poweron;
+
+ /* Work queues related to I2C support */
+ struct work_struct pullup_job;
+ struct work_struct vbus_job;
+ struct work_struct power_job;
+
+ /* USB device peripheral - various */
+ struct lpc32xx_ep ep[NUM_ENDPOINTS];
+ bool enabled;
+ bool clocked;
+ bool suspended;
+ bool selfpowered;
+ int ep0state;
+ atomic_t enabled_ep_cnt;
+ wait_queue_head_t ep_disable_wait_queue;
+};
+
+/*
+ * Endpoint request
+ */
+struct lpc32xx_request {
+ struct usb_request req;
+ struct list_head queue;
+ struct lpc32xx_usbd_dd_gad *dd_desc_ptr;
+ bool mapped;
+ bool send_zlp;
+};
+
+static inline struct lpc32xx_udc *to_udc(struct usb_gadget *g)
+{
+ return container_of(g, struct lpc32xx_udc, gadget);
+}
+
+#define ep_dbg(epp, fmt, arg...) \
+ dev_dbg(epp->udc->dev, "%s: " fmt, __func__, ## arg)
+#define ep_err(epp, fmt, arg...) \
+ dev_err(epp->udc->dev, "%s: " fmt, __func__, ## arg)
+#define ep_info(epp, fmt, arg...) \
+ dev_info(epp->udc->dev, "%s: " fmt, __func__, ## arg)
+#define ep_warn(epp, fmt, arg...) \
+ dev_warn(epp->udc->dev, "%s:" fmt, __func__, ## arg)
+
+#define UDCA_BUFF_SIZE (128)
+
+/* TODO: When the clock framework is introduced in LPC32xx, IO_ADDRESS will
+ * be replaced with an inremap()ed pointer, see USB_OTG_CLK_CTRL()
+ * */
+#define USB_CTRL IO_ADDRESS(LPC32XX_CLK_PM_BASE + 0x64)
+#define USB_CLOCK_MASK (AHB_M_CLOCK_ON | OTG_CLOCK_ON | \
+ DEV_CLOCK_ON | I2C_CLOCK_ON)
+
+/* USB_CTRL bit defines */
+#define USB_SLAVE_HCLK_EN (1 << 24)
+#define USB_HOST_NEED_CLK_EN (1 << 21)
+#define USB_DEV_NEED_CLK_EN (1 << 22)
+
+#define USB_OTG_CLK_CTRL(udc) ((udc)->udp_baseaddr + 0xFF4)
+#define USB_OTG_CLK_STAT(udc) ((udc)->udp_baseaddr + 0xFF8)
+
+/* USB_OTG_CLK_CTRL bit defines */
+#define AHB_M_CLOCK_ON (1 << 4)
+#define OTG_CLOCK_ON (1 << 3)
+#define I2C_CLOCK_ON (1 << 2)
+#define DEV_CLOCK_ON (1 << 1)
+#define HOST_CLOCK_ON (1 << 0)
+
+#define USB_OTG_STAT_CONTROL(udc) (udc->udp_baseaddr + 0x110)
+
+/* USB_OTG_STAT_CONTROL bit defines */
+#define TRANSPARENT_I2C_EN (1 << 7)
+#define HOST_EN (1 << 0)
+
+/**********************************************************************
+ * USB device controller register offsets
+ **********************************************************************/
+
+#define USBD_DEVINTST(x) ((x) + 0x200)
+#define USBD_DEVINTEN(x) ((x) + 0x204)
+#define USBD_DEVINTCLR(x) ((x) + 0x208)
+#define USBD_DEVINTSET(x) ((x) + 0x20C)
+#define USBD_CMDCODE(x) ((x) + 0x210)
+#define USBD_CMDDATA(x) ((x) + 0x214)
+#define USBD_RXDATA(x) ((x) + 0x218)
+#define USBD_TXDATA(x) ((x) + 0x21C)
+#define USBD_RXPLEN(x) ((x) + 0x220)
+#define USBD_TXPLEN(x) ((x) + 0x224)
+#define USBD_CTRL(x) ((x) + 0x228)
+#define USBD_DEVINTPRI(x) ((x) + 0x22C)
+#define USBD_EPINTST(x) ((x) + 0x230)
+#define USBD_EPINTEN(x) ((x) + 0x234)
+#define USBD_EPINTCLR(x) ((x) + 0x238)
+#define USBD_EPINTSET(x) ((x) + 0x23C)
+#define USBD_EPINTPRI(x) ((x) + 0x240)
+#define USBD_REEP(x) ((x) + 0x244)
+#define USBD_EPIND(x) ((x) + 0x248)
+#define USBD_EPMAXPSIZE(x) ((x) + 0x24C)
+/* DMA support registers only below */
+/* Set, clear, or get enabled state of the DMA request status. If
+ * enabled, an IN or OUT token will start a DMA transfer for the EP */
+#define USBD_DMARST(x) ((x) + 0x250)
+#define USBD_DMARCLR(x) ((x) + 0x254)
+#define USBD_DMARSET(x) ((x) + 0x258)
+/* DMA UDCA head pointer */
+#define USBD_UDCAH(x) ((x) + 0x280)
+/* EP DMA status, enable, and disable. This is used to specifically
+ * enabled or disable DMA for a specific EP */
+#define USBD_EPDMAST(x) ((x) + 0x284)
+#define USBD_EPDMAEN(x) ((x) + 0x288)
+#define USBD_EPDMADIS(x) ((x) + 0x28C)
+/* DMA master interrupts enable and pending interrupts */
+#define USBD_DMAINTST(x) ((x) + 0x290)
+#define USBD_DMAINTEN(x) ((x) + 0x294)
+/* DMA end of transfer interrupt enable, disable, status */
+#define USBD_EOTINTST(x) ((x) + 0x2A0)
+#define USBD_EOTINTCLR(x) ((x) + 0x2A4)
+#define USBD_EOTINTSET(x) ((x) + 0x2A8)
+/* New DD request interrupt enable, disable, status */
+#define USBD_NDDRTINTST(x) ((x) + 0x2AC)
+#define USBD_NDDRTINTCLR(x) ((x) + 0x2B0)
+#define USBD_NDDRTINTSET(x) ((x) + 0x2B4)
+/* DMA error interrupt enable, disable, status */
+#define USBD_SYSERRTINTST(x) ((x) + 0x2B8)
+#define USBD_SYSERRTINTCLR(x) ((x) + 0x2BC)
+#define USBD_SYSERRTINTSET(x) ((x) + 0x2C0)
+
+/**********************************************************************
+ * USBD_DEVINTST/USBD_DEVINTEN/USBD_DEVINTCLR/USBD_DEVINTSET/
+ * USBD_DEVINTPRI register definitions
+ **********************************************************************/
+#define USBD_ERR_INT (1 << 9)
+#define USBD_EP_RLZED (1 << 8)
+#define USBD_TXENDPKT (1 << 7)
+#define USBD_RXENDPKT (1 << 6)
+#define USBD_CDFULL (1 << 5)
+#define USBD_CCEMPTY (1 << 4)
+#define USBD_DEV_STAT (1 << 3)
+#define USBD_EP_SLOW (1 << 2)
+#define USBD_EP_FAST (1 << 1)
+#define USBD_FRAME (1 << 0)
+
+/**********************************************************************
+ * USBD_EPINTST/USBD_EPINTEN/USBD_EPINTCLR/USBD_EPINTSET/
+ * USBD_EPINTPRI register definitions
+ **********************************************************************/
+/* End point selection macro (RX) */
+#define USBD_RX_EP_SEL(e) (1 << ((e) << 1))
+
+/* End point selection macro (TX) */
+#define USBD_TX_EP_SEL(e) (1 << (((e) << 1) + 1))
+
+/**********************************************************************
+ * USBD_REEP/USBD_DMARST/USBD_DMARCLR/USBD_DMARSET/USBD_EPDMAST/
+ * USBD_EPDMAEN/USBD_EPDMADIS/
+ * USBD_NDDRTINTST/USBD_NDDRTINTCLR/USBD_NDDRTINTSET/
+ * USBD_EOTINTST/USBD_EOTINTCLR/USBD_EOTINTSET/
+ * USBD_SYSERRTINTST/USBD_SYSERRTINTCLR/USBD_SYSERRTINTSET
+ * register definitions
+ **********************************************************************/
+/* Endpoint selection macro */
+#define USBD_EP_SEL(e) (1 << (e))
+
+/**********************************************************************
+ * SBD_DMAINTST/USBD_DMAINTEN
+ **********************************************************************/
+#define USBD_SYS_ERR_INT (1 << 2)
+#define USBD_NEW_DD_INT (1 << 1)
+#define USBD_EOT_INT (1 << 0)
+
+/**********************************************************************
+ * USBD_RXPLEN register definitions
+ **********************************************************************/
+#define USBD_PKT_RDY (1 << 11)
+#define USBD_DV (1 << 10)
+#define USBD_PK_LEN_MASK 0x3FF
+
+/**********************************************************************
+ * USBD_CTRL register definitions
+ **********************************************************************/
+#define USBD_LOG_ENDPOINT(e) ((e) << 2)
+#define USBD_WR_EN (1 << 1)
+#define USBD_RD_EN (1 << 0)
+
+/**********************************************************************
+ * USBD_CMDCODE register definitions
+ **********************************************************************/
+#define USBD_CMD_CODE(c) ((c) << 16)
+#define USBD_CMD_PHASE(p) ((p) << 8)
+
+/**********************************************************************
+ * USBD_DMARST/USBD_DMARCLR/USBD_DMARSET register definitions
+ **********************************************************************/
+#define USBD_DMAEP(e) (1 << (e))
+
+/* DD (DMA Descriptor) structure, requires word alignment */
+struct lpc32xx_usbd_dd {
+ u32 *dd_next;
+ u32 dd_setup;
+ u32 dd_buffer_addr;
+ u32 dd_status;
+ u32 dd_iso_ps_mem_addr;
+};
+
+/* dd_setup bit defines */
+#define DD_SETUP_ATLE_DMA_MODE 0x01
+#define DD_SETUP_NEXT_DD_VALID 0x04
+#define DD_SETUP_ISO_EP 0x10
+#define DD_SETUP_PACKETLEN(n) (((n) & 0x7FF) << 5)
+#define DD_SETUP_DMALENBYTES(n) (((n) & 0xFFFF) << 16)
+
+/* dd_status bit defines */
+#define DD_STATUS_DD_RETIRED 0x01
+#define DD_STATUS_STS_MASK 0x1E
+#define DD_STATUS_STS_NS 0x00 /* Not serviced */
+#define DD_STATUS_STS_BS 0x02 /* Being serviced */
+#define DD_STATUS_STS_NC 0x04 /* Normal completion */
+#define DD_STATUS_STS_DUR 0x06 /* Data underrun (short packet) */
+#define DD_STATUS_STS_DOR 0x08 /* Data overrun */
+#define DD_STATUS_STS_SE 0x12 /* System error */
+#define DD_STATUS_PKT_VAL 0x20 /* Packet valid */
+#define DD_STATUS_LSB_EX 0x40 /* LS byte extracted (ATLE) */
+#define DD_STATUS_MSB_EX 0x80 /* MS byte extracted (ATLE) */
+#define DD_STATUS_MLEN(n) (((n) >> 8) & 0x3F)
+#define DD_STATUS_CURDMACNT(n) (((n) >> 16) & 0xFFFF)
+
+/*
+ *
+ * Protocol engine bits below
+ *
+ */
+/* Device Interrupt Bit Definitions */
+#define FRAME_INT 0x00000001
+#define EP_FAST_INT 0x00000002
+#define EP_SLOW_INT 0x00000004
+#define DEV_STAT_INT 0x00000008
+#define CCEMTY_INT 0x00000010
+#define CDFULL_INT 0x00000020
+#define RxENDPKT_INT 0x00000040
+#define TxENDPKT_INT 0x00000080
+#define EP_RLZED_INT 0x00000100
+#define ERR_INT 0x00000200
+
+/* Rx & Tx Packet Length Definitions */
+#define PKT_LNGTH_MASK 0x000003FF
+#define PKT_DV 0x00000400
+#define PKT_RDY 0x00000800
+
+/* USB Control Definitions */
+#define CTRL_RD_EN 0x00000001
+#define CTRL_WR_EN 0x00000002
+
+/* Command Codes */
+#define CMD_SET_ADDR 0x00D00500
+#define CMD_CFG_DEV 0x00D80500
+#define CMD_SET_MODE 0x00F30500
+#define CMD_RD_FRAME 0x00F50500
+#define DAT_RD_FRAME 0x00F50200
+#define CMD_RD_TEST 0x00FD0500
+#define DAT_RD_TEST 0x00FD0200
+#define CMD_SET_DEV_STAT 0x00FE0500
+#define CMD_GET_DEV_STAT 0x00FE0500
+#define DAT_GET_DEV_STAT 0x00FE0200
+#define CMD_GET_ERR_CODE 0x00FF0500
+#define DAT_GET_ERR_CODE 0x00FF0200
+#define CMD_RD_ERR_STAT 0x00FB0500
+#define DAT_RD_ERR_STAT 0x00FB0200
+#define DAT_WR_BYTE(x) (0x00000100 | ((x) << 16))
+#define CMD_SEL_EP(x) (0x00000500 | ((x) << 16))
+#define DAT_SEL_EP(x) (0x00000200 | ((x) << 16))
+#define CMD_SEL_EP_CLRI(x) (0x00400500 | ((x) << 16))
+#define DAT_SEL_EP_CLRI(x) (0x00400200 | ((x) << 16))
+#define CMD_SET_EP_STAT(x) (0x00400500 | ((x) << 16))
+#define CMD_CLR_BUF 0x00F20500
+#define DAT_CLR_BUF 0x00F20200
+#define CMD_VALID_BUF 0x00FA0500
+
+/* Device Address Register Definitions */
+#define DEV_ADDR_MASK 0x7F
+#define DEV_EN 0x80
+
+/* Device Configure Register Definitions */
+#define CONF_DVICE 0x01
+
+/* Device Mode Register Definitions */
+#define AP_CLK 0x01
+#define INAK_CI 0x02
+#define INAK_CO 0x04
+#define INAK_II 0x08
+#define INAK_IO 0x10
+#define INAK_BI 0x20
+#define INAK_BO 0x40
+
+/* Device Status Register Definitions */
+#define DEV_CON 0x01
+#define DEV_CON_CH 0x02
+#define DEV_SUS 0x04
+#define DEV_SUS_CH 0x08
+#define DEV_RST 0x10
+
+/* Error Code Register Definitions */
+#define ERR_EC_MASK 0x0F
+#define ERR_EA 0x10
+
+/* Error Status Register Definitions */
+#define ERR_PID 0x01
+#define ERR_UEPKT 0x02
+#define ERR_DCRC 0x04
+#define ERR_TIMOUT 0x08
+#define ERR_EOP 0x10
+#define ERR_B_OVRN 0x20
+#define ERR_BTSTF 0x40
+#define ERR_TGL 0x80
+
+/* Endpoint Select Register Definitions */
+#define EP_SEL_F 0x01
+#define EP_SEL_ST 0x02
+#define EP_SEL_STP 0x04
+#define EP_SEL_PO 0x08
+#define EP_SEL_EPN 0x10
+#define EP_SEL_B_1_FULL 0x20
+#define EP_SEL_B_2_FULL 0x40
+
+/* Endpoint Status Register Definitions */
+#define EP_STAT_ST 0x01
+#define EP_STAT_DA 0x20
+#define EP_STAT_RF_MO 0x40
+#define EP_STAT_CND_ST 0x80
+
+/* Clear Buffer Register Definitions */
+#define CLR_BUF_PO 0x01
+
+/* DMA Interrupt Bit Definitions */
+#define EOT_INT 0x01
+#define NDD_REQ_INT 0x02
+#define SYS_ERR_INT 0x04
+
+#define DRIVER_VERSION "1.03"
+static const char driver_name[] = "lpc32xx_udc";
+
+/*
+ *
+ * proc interface support
+ *
+ */
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+static char *epnames[] = {"INT", "ISO", "BULK", "CTRL"};
+static const char debug_filename[] = "driver/udc";
+
+static void proc_ep_show(struct seq_file *s, struct lpc32xx_ep *ep)
+{
+ struct lpc32xx_request *req;
+
+ seq_printf(s, "\n");
+ seq_printf(s, "%12s, maxpacket %4d %3s",
+ ep->ep.name, ep->ep.maxpacket,
+ ep->is_in ? "in" : "out");
+ seq_printf(s, " type %4s", epnames[ep->eptype]);
+ seq_printf(s, " ints: %12d", ep->totalints);
+
+ if (list_empty(&ep->queue))
+ seq_printf(s, "\t(queue empty)\n");
+ else {
+ list_for_each_entry(req, &ep->queue, queue) {
+ u32 length = req->req.actual;
+
+ seq_printf(s, "\treq %p len %d/%d buf %p\n",
+ &req->req, length,
+ req->req.length, req->req.buf);
+ }
+ }
+}
+
+static int proc_udc_show(struct seq_file *s, void *unused)
+{
+ struct lpc32xx_udc *udc = s->private;
+ struct lpc32xx_ep *ep;
+ unsigned long flags;
+
+ seq_printf(s, "%s: version %s\n", driver_name, DRIVER_VERSION);
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ seq_printf(s, "vbus %s, pullup %s, %s powered%s, gadget %s\n\n",
+ udc->vbus ? "present" : "off",
+ udc->enabled ? (udc->vbus ? "active" : "enabled") :
+ "disabled",
+ udc->selfpowered ? "self" : "VBUS",
+ udc->suspended ? ", suspended" : "",
+ udc->driver ? udc->driver->driver.name : "(none)");
+
+ if (udc->enabled && udc->vbus) {
+ proc_ep_show(s, &udc->ep[0]);
+ list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
+ if (ep->desc)
+ proc_ep_show(s, ep);
+ }
+ }
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+static int proc_udc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_udc_show, PDE(inode)->data);
+}
+
+static const struct file_operations proc_ops = {
+ .owner = THIS_MODULE,
+ .open = proc_udc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void create_debug_file(struct lpc32xx_udc *udc)
+{
+ udc->pde = debugfs_create_file(debug_filename, 0, NULL, udc, &proc_ops);
+}
+
+static void remove_debug_file(struct lpc32xx_udc *udc)
+{
+ if (udc->pde)
+ debugfs_remove(udc->pde);
+}
+
+#else
+static inline void create_debug_file(struct lpc32xx_udc *udc) {}
+static inline void remove_debug_file(struct lpc32xx_udc *udc) {}
+#endif
+
+/* Primary initialization sequence for the ISP1301 transceiver */
+static void isp1301_udc_configure(struct lpc32xx_udc *udc)
+{
+ /* LPC32XX only supports DAT_SE0 USB mode */
+ /* This sequence is important */
+
+ /* Disable transparent UART mode first */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ (ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR),
+ MC1_UART_EN);
+
+ /* Set full speed and SE0 mode */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ (ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), ~0);
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_MODE_CONTROL_1, (MC1_SPEED_REG | MC1_DAT_SE0));
+
+ /*
+ * The PSW_OE enable bit state is reversed in the ISP1301 User's Guide
+ */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ (ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR), ~0);
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_MODE_CONTROL_2, (MC2_BI_DI | MC2_SPD_SUSP_CTRL));
+
+ /* Driver VBUS_DRV high or low depending on board setup */
+ if (udc->board->vbus_drv_pol != 0)
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DRV);
+ else
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR,
+ OTG1_VBUS_DRV);
+
+ /* Bi-directional mode with suspend control
+ * Enable both pulldowns for now - the pullup will be enable when VBUS
+ * is detected */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ (ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), ~0);
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_OTG_CONTROL_1,
+ (0 | OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN));
+
+ /* Discharge VBUS (just in case) */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DISCHRG);
+ msleep(1);
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ (ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR),
+ OTG1_VBUS_DISCHRG);
+
+ /* Clear and enable VBUS high edge interrupt */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR, ~0);
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR, ~0);
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_INTERRUPT_FALLING, INT_VBUS_VLD);
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR, ~0);
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_INTERRUPT_RISING, INT_VBUS_VLD);
+
+ /* Enable usb_need_clk clock after transceiver is initialized */
+ writel((readl(USB_CTRL) | (1 << 22)), USB_CTRL);
+
+ dev_info(udc->dev, "ISP1301 Vendor ID : 0x%04x\n",
+ i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x00));
+ dev_info(udc->dev, "ISP1301 Product ID : 0x%04x\n",
+ i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x02));
+ dev_info(udc->dev, "ISP1301 Version ID : 0x%04x\n",
+ i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x14));
+}
+
+/* Enables or disables the USB device pullup via the ISP1301 transceiver */
+static void isp1301_pullup_set(struct lpc32xx_udc *udc)
+{
+ if (udc->pullup)
+ /* Enable pullup for bus signalling */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_OTG_CONTROL_1, OTG1_DP_PULLUP);
+ else
+ /* Enable pullup for bus signalling */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR,
+ OTG1_DP_PULLUP);
+}
+
+static void pullup_work(struct work_struct *work)
+{
+ struct lpc32xx_udc *udc =
+ container_of(work, struct lpc32xx_udc, pullup_job);
+
+ isp1301_pullup_set(udc);
+}
+
+static void isp1301_pullup_enable(struct lpc32xx_udc *udc, int en_pullup,
+ int block)
+{
+ if (en_pullup == udc->pullup)
+ return;
+
+ udc->pullup = en_pullup;
+ if (block)
+ isp1301_pullup_set(udc);
+ else
+ /* defer slow i2c pull up setting */
+ schedule_work(&udc->pullup_job);
+}
+
+#ifdef CONFIG_PM
+/* Powers up or down the ISP1301 transceiver */
+static void isp1301_set_powerstate(struct lpc32xx_udc *udc, int enable)
+{
+ if (enable != 0)
+ /* Power up ISP1301 - this ISP1301 will automatically wakeup
+ when VBUS is detected */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR,
+ MC2_GLOBAL_PWR_DN);
+ else
+ /* Power down ISP1301 */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN);
+}
+
+static void power_work(struct work_struct *work)
+{
+ struct lpc32xx_udc *udc =
+ container_of(work, struct lpc32xx_udc, power_job);
+
+ isp1301_set_powerstate(udc, udc->poweron);
+}
+#endif
+
+/*
+ *
+ * USB protocol engine command/data read/write helper functions
+ *
+ */
+/* Issues a single command to the USB device state machine */
+static void udc_protocol_cmd_w(struct lpc32xx_udc *udc, u32 cmd)
+{
+ u32 pass = 0;
+ int to;
+
+ /* EP may lock on CLRI if this read isn't done */
+ u32 tmp = readl(USBD_DEVINTST(udc->udp_baseaddr));
+ (void) tmp;
+
+ while (pass == 0) {
+ writel(USBD_CCEMPTY, USBD_DEVINTCLR(udc->udp_baseaddr));
+
+ /* Write command code */
+ writel(cmd, USBD_CMDCODE(udc->udp_baseaddr));
+ to = 10000;
+ while (((readl(USBD_DEVINTST(udc->udp_baseaddr)) &
+ USBD_CCEMPTY) == 0) && (to > 0)) {
+ to--;
+ }
+
+ if (to > 0)
+ pass = 1;
+
+ cpu_relax();
+ }
+}
+
+/* Issues 2 commands (or command and data) to the USB device state machine */
+static inline void udc_protocol_cmd_data_w(struct lpc32xx_udc *udc, u32 cmd,
+ u32 data)
+{
+ udc_protocol_cmd_w(udc, cmd);
+ udc_protocol_cmd_w(udc, data);
+}
+
+/* Issues a single command to the USB device state machine and reads
+ * response data */
+static u32 udc_protocol_cmd_r(struct lpc32xx_udc *udc, u32 cmd)
+{
+ u32 tmp;
+ int to = 1000;
+
+ /* Write a command and read data from the protocol engine */
+ writel((USBD_CDFULL | USBD_CCEMPTY),
+ USBD_DEVINTCLR(udc->udp_baseaddr));
+
+ /* Write command code */
+ udc_protocol_cmd_w(udc, cmd);
+
+ tmp = readl(USBD_DEVINTST(udc->udp_baseaddr));
+ while ((!(readl(USBD_DEVINTST(udc->udp_baseaddr)) & USBD_CDFULL))
+ && (to > 0))
+ to--;
+ if (!to)
+ dev_dbg(udc->dev,
+ "Protocol engine didn't receive response (CDFULL)\n");
+
+ return readl(USBD_CMDDATA(udc->udp_baseaddr));
+}
+
+/*
+ *
+ * USB device interrupt mask support functions
+ *
+ */
+/* Enable one or more USB device interrupts */
+static inline void uda_enable_devint(struct lpc32xx_udc *udc, u32 devmask)
+{
+ udc->enabled_devints |= devmask;
+ writel(udc->enabled_devints, USBD_DEVINTEN(udc->udp_baseaddr));
+}
+
+/* Disable one or more USB device interrupts */
+static inline void uda_disable_devint(struct lpc32xx_udc *udc, u32 mask)
+{
+ udc->enabled_devints &= ~mask;
+ writel(udc->enabled_devints, USBD_DEVINTEN(udc->udp_baseaddr));
+}
+
+/* Clear one or more USB device interrupts */
+static inline void uda_clear_devint(struct lpc32xx_udc *udc, u32 mask)
+{
+ writel(mask, USBD_DEVINTCLR(udc->udp_baseaddr));
+}
+
+/*
+ *
+ * Endpoint interrupt disable/enable functions
+ *
+ */
+/* Enable one or more USB endpoint interrupts */
+static void uda_enable_hwepint(struct lpc32xx_udc *udc, u32 hwep)
+{
+ udc->enabled_hwepints |= (1 << hwep);
+ writel(udc->enabled_hwepints, USBD_EPINTEN(udc->udp_baseaddr));
+}
+
+/* Disable one or more USB endpoint interrupts */
+static void uda_disable_hwepint(struct lpc32xx_udc *udc, u32 hwep)
+{
+ udc->enabled_hwepints &= ~(1 << hwep);
+ writel(udc->enabled_hwepints, USBD_EPINTEN(udc->udp_baseaddr));
+}
+
+/* Clear one or more USB endpoint interrupts */
+static inline void uda_clear_hwepint(struct lpc32xx_udc *udc, u32 hwep)
+{
+ writel((1 << hwep), USBD_EPINTCLR(udc->udp_baseaddr));
+}
+
+/* Enable DMA for the HW channel */
+static inline void udc_ep_dma_enable(struct lpc32xx_udc *udc, u32 hwep)
+{
+ writel((1 << hwep), USBD_EPDMAEN(udc->udp_baseaddr));
+}
+
+/* Disable DMA for the HW channel */
+static inline void udc_ep_dma_disable(struct lpc32xx_udc *udc, u32 hwep)
+{
+ writel((1 << hwep), USBD_EPDMADIS(udc->udp_baseaddr));
+}
+
+/*
+ *
+ * Endpoint realize/unrealize functions
+ *
+ */
+/* Before an endpoint can be used, it needs to be realized
+ * in the USB protocol engine - this realizes the endpoint.
+ * The interrupt (FIFO or DMA) is not enabled with this function */
+static void udc_realize_hwep(struct lpc32xx_udc *udc, u32 hwep,
+ u32 maxpacket)
+{
+ int to = 1000;
+
+ writel(USBD_EP_RLZED, USBD_DEVINTCLR(udc->udp_baseaddr));
+ writel(hwep, USBD_EPIND(udc->udp_baseaddr));
+ udc->realized_eps |= (1 << hwep);
+ writel(udc->realized_eps, USBD_REEP(udc->udp_baseaddr));
+ writel(maxpacket, USBD_EPMAXPSIZE(udc->udp_baseaddr));
+
+ /* Wait until endpoint is realized in hardware */
+ while ((!(readl(USBD_DEVINTST(udc->udp_baseaddr)) &
+ USBD_EP_RLZED)) && (to > 0))
+ to--;
+ if (!to)
+ dev_dbg(udc->dev, "EP not correctly realized in hardware\n");
+
+ writel(USBD_EP_RLZED, USBD_DEVINTCLR(udc->udp_baseaddr));
+}
+
+/* Unrealize an EP */
+static void udc_unrealize_hwep(struct lpc32xx_udc *udc, u32 hwep)
+{
+ udc->realized_eps &= ~(1 << hwep);
+ writel(udc->realized_eps, USBD_REEP(udc->udp_baseaddr));
+}
+
+/*
+ *
+ * Endpoint support functions
+ *
+ */
+/* Select and clear endpoint interrupt */
+static u32 udc_selep_clrint(struct lpc32xx_udc *udc, u32 hwep)
+{
+ udc_protocol_cmd_w(udc, CMD_SEL_EP_CLRI(hwep));
+ return udc_protocol_cmd_r(udc, DAT_SEL_EP_CLRI(hwep));
+}
+
+/* Disables the endpoint in the USB protocol engine */
+static void udc_disable_hwep(struct lpc32xx_udc *udc, u32 hwep)
+{
+ udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(hwep),
+ DAT_WR_BYTE(EP_STAT_DA));
+}
+
+/* Stalls the endpoint - endpoint will return STALL */
+static void udc_stall_hwep(struct lpc32xx_udc *udc, u32 hwep)
+{
+ udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(hwep),
+ DAT_WR_BYTE(EP_STAT_ST));
+}
+
+/* Clear stall or reset endpoint */
+static void udc_clrstall_hwep(struct lpc32xx_udc *udc, u32 hwep)
+{
+ udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(hwep),
+ DAT_WR_BYTE(0));
+}
+
+/* Select an endpoint for endpoint status, clear, validate */
+static void udc_select_hwep(struct lpc32xx_udc *udc, u32 hwep)
+{
+ udc_protocol_cmd_w(udc, CMD_SEL_EP(hwep));
+}
+
+/*
+ *
+ * Endpoint buffer management functions
+ *
+ */
+/* Clear the current endpoint's buffer */
+static void udc_clr_buffer_hwep(struct lpc32xx_udc *udc, u32 hwep)
+{
+ udc_select_hwep(udc, hwep);
+ udc_protocol_cmd_w(udc, CMD_CLR_BUF);
+}
+
+/* Validate the current endpoint's buffer */
+static void udc_val_buffer_hwep(struct lpc32xx_udc *udc, u32 hwep)
+{
+ udc_select_hwep(udc, hwep);
+ udc_protocol_cmd_w(udc, CMD_VALID_BUF);
+}
+
+static inline u32 udc_clearep_getsts(struct lpc32xx_udc *udc, u32 hwep)
+{
+ /* Clear EP interrupt */
+ uda_clear_hwepint(udc, hwep);
+ return udc_selep_clrint(udc, hwep);
+}
+
+/*
+ *
+ * USB EP DMA support
+ *
+ */
+/* Allocate a DMA Descriptor */
+static struct lpc32xx_usbd_dd_gad *udc_dd_alloc(struct lpc32xx_udc *udc)
+{
+ dma_addr_t dma;
+ struct lpc32xx_usbd_dd_gad *dd;
+
+ dd = (struct lpc32xx_usbd_dd_gad *) dma_pool_alloc(
+ udc->dd_cache, (GFP_KERNEL | GFP_DMA), &dma);
+ if (dd)
+ dd->this_dma = dma;
+
+ return dd;
+}
+
+/* Free a DMA Descriptor */
+static void udc_dd_free(struct lpc32xx_udc *udc, struct lpc32xx_usbd_dd_gad *dd)
+{
+ dma_pool_free(udc->dd_cache, dd, dd->this_dma);
+}
+
+/*
+ *
+ * USB setup and shutdown functions
+ *
+ */
+/* Enables or disables most of the USB system clocks when low power mode is
+ * needed. Clocks are typically started on a connection event, and disabled
+ * when a cable is disconnected */
+#define OTGOFF_CLK_MASK (AHB_M_CLOCK_ON | I2C_CLOCK_ON)
+static void udc_clk_set(struct lpc32xx_udc *udc, int enable)
+{
+ int to = 1000;
+
+ if (enable != 0) {
+ if (udc->clocked)
+ return;
+
+ udc->clocked = 1;
+
+ /* 48MHz PLL up */
+ clk_enable(udc->usb_pll_clk);
+
+ /* Enable the USB device clock */
+ writel(readl(USB_CTRL) | USB_DEV_NEED_CLK_EN,
+ USB_CTRL);
+
+ /* Set to enable all needed USB OTG clocks */
+ writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL(udc));
+
+ while (((readl(USB_OTG_CLK_STAT(udc)) & USB_CLOCK_MASK) !=
+ USB_CLOCK_MASK) && (to > 0))
+ to--;
+ if (!to)
+ dev_dbg(udc->dev, "Cannot enable USB OTG clocking\n");
+ } else {
+ if (!udc->clocked)
+ return;
+
+ udc->clocked = 0;
+
+ /* Never disable the USB_HCLK during normal operation */
+
+ /* 48MHz PLL dpwn */
+ clk_disable(udc->usb_pll_clk);
+
+ /* Enable the USB device clock */
+ writel(readl(USB_CTRL) & ~USB_DEV_NEED_CLK_EN,
+ USB_CTRL);
+
+ /* Set to enable all needed USB OTG clocks */
+ writel(OTGOFF_CLK_MASK, USB_OTG_CLK_CTRL(udc));
+
+ while (((readl(USB_OTG_CLK_STAT(udc)) &
+ OTGOFF_CLK_MASK) !=
+ OTGOFF_CLK_MASK) && (to > 0))
+ to--;
+ if (!to)
+ dev_dbg(udc->dev, "Cannot disable USB OTG clocking\n");
+ }
+}
+
+/* Set/reset USB device address */
+static void udc_set_address(struct lpc32xx_udc *udc, u32 addr)
+{
+ /* Address will be latched at the end of the status phase, or
+ latched immediately if function is called twice */
+ udc_protocol_cmd_data_w(udc, CMD_SET_ADDR,
+ DAT_WR_BYTE(DEV_EN | addr));
+}
+
+/* Setup up a IN request for DMA transfer - this consists of determining the
+ * list of DMA addresses for the transfer, allocating DMA Descriptors,
+ * installing the DD into the UDCA, and then enabling the DMA for that EP */
+static int udc_ep_in_req_dma(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep)
+{
+ struct lpc32xx_request *req;
+ u32 hwep = ep->hwep_num;
+
+ ep->req_pending = 1;
+
+ /* There will always be a request waiting here */
+ req = list_entry(ep->queue.next, struct lpc32xx_request, queue);
+
+ /* Place the DD Descriptor into the UDCA */
+ udc->udca_v_base[hwep] = req->dd_desc_ptr->this_dma;
+
+ /* Enable DMA and interrupt for the HW EP */
+ udc_ep_dma_enable(udc, hwep);
+
+ /* Clear ZLP if last packet is not of MAXP size */
+ if (req->req.length % ep->ep.maxpacket)
+ req->send_zlp = 0;
+
+ return 0;
+}
+
+/* Setup up a OUT request for DMA transfer - this consists of determining the
+ * list of DMA addresses for the transfer, allocating DMA Descriptors,
+ * installing the DD into the UDCA, and then enabling the DMA for that EP */
+static int udc_ep_out_req_dma(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep)
+{
+ struct lpc32xx_request *req;
+ u32 hwep = ep->hwep_num;
+
+ ep->req_pending = 1;
+
+ /* There will always be a request waiting here */
+ req = list_entry(ep->queue.next, struct lpc32xx_request, queue);
+
+ /* Place the DD Descriptor into the UDCA */
+ udc->udca_v_base[hwep] = req->dd_desc_ptr->this_dma;
+
+ /* Enable DMA and interrupt for the HW EP */
+ udc_ep_dma_enable(udc, hwep);
+ return 0;
+}
+
+static void udc_disable(struct lpc32xx_udc *udc)
+{
+ u32 i;
+
+ /* Disable device */
+ udc_protocol_cmd_data_w(udc, CMD_CFG_DEV, DAT_WR_BYTE(0));
+ udc_protocol_cmd_data_w(udc, CMD_SET_DEV_STAT, DAT_WR_BYTE(0));
+
+ /* Disable all device interrupts (including EP0) */
+ uda_disable_devint(udc, 0x3FF);
+
+ /* Disable and reset all endpoint interrupts */
+ for (i = 0; i < 32; i++) {
+ uda_disable_hwepint(udc, i);
+ uda_clear_hwepint(udc, i);
+ udc_disable_hwep(udc, i);
+ udc_unrealize_hwep(udc, i);
+ udc->udca_v_base[i] = 0;
+
+ /* Disable and clear all interrupts and DMA */
+ udc_ep_dma_disable(udc, i);
+ writel((1 << i), USBD_EOTINTCLR(udc->udp_baseaddr));
+ writel((1 << i), USBD_NDDRTINTCLR(udc->udp_baseaddr));
+ writel((1 << i), USBD_SYSERRTINTCLR(udc->udp_baseaddr));
+ writel((1 << i), USBD_DMARCLR(udc->udp_baseaddr));
+ }
+
+ /* Disable DMA interrupts */
+ writel(0, USBD_DMAINTEN(udc->udp_baseaddr));
+
+ writel(0, USBD_UDCAH(udc->udp_baseaddr));
+}
+
+static void udc_enable(struct lpc32xx_udc *udc)
+{
+ u32 i;
+ struct lpc32xx_ep *ep = &udc->ep[0];
+
+ /* Start with known state */
+ udc_disable(udc);
+
+ /* Enable device */
+ udc_protocol_cmd_data_w(udc, CMD_SET_DEV_STAT, DAT_WR_BYTE(DEV_CON));
+
+ /* EP interrupts on high priority, FRAME interrupt on low priority */
+ writel(USBD_EP_FAST, USBD_DEVINTPRI(udc->udp_baseaddr));
+ writel(0xFFFF, USBD_EPINTPRI(udc->udp_baseaddr));
+
+ /* Clear any pending device interrupts */
+ writel(0x3FF, USBD_DEVINTCLR(udc->udp_baseaddr));
+
+ /* Setup UDCA - not yet used (DMA) */
+ writel(udc->udca_p_base, USBD_UDCAH(udc->udp_baseaddr));
+
+ /* Only enable EP0 in and out for now, EP0 only works in FIFO mode */
+ for (i = 0; i <= 1; i++) {
+ udc_realize_hwep(udc, i, ep->ep.maxpacket);
+ uda_enable_hwepint(udc, i);
+ udc_select_hwep(udc, i);
+ udc_clrstall_hwep(udc, i);
+ udc_clr_buffer_hwep(udc, i);
+ }
+
+ /* Device interrupt setup */
+ uda_clear_devint(udc, (USBD_ERR_INT | USBD_DEV_STAT | USBD_EP_SLOW |
+ USBD_EP_FAST));
+ uda_enable_devint(udc, (USBD_ERR_INT | USBD_DEV_STAT | USBD_EP_SLOW |
+ USBD_EP_FAST));
+
+ /* Set device address to 0 - called twice to force a latch in the USB
+ engine without the need of a setup packet status closure */
+ udc_set_address(udc, 0);
+ udc_set_address(udc, 0);
+
+ /* Enable master DMA interrupts */
+ writel((USBD_SYS_ERR_INT | USBD_EOT_INT),
+ USBD_DMAINTEN(udc->udp_baseaddr));
+
+ udc->dev_status = 0;
+}
+
+/*
+ *
+ * USB device board specific events handled via callbacks
+ *
+ */
+/* Connection change event - notify board function of change */
+static void uda_power_event(struct lpc32xx_udc *udc, u32 conn)
+{
+ /* Just notify of a connection change event (optional) */
+ if (udc->board->conn_chgb != NULL)
+ udc->board->conn_chgb(conn);
+}
+
+/* Suspend/resume event - notify board function of change */
+static void uda_resm_susp_event(struct lpc32xx_udc *udc, u32 conn)
+{
+ /* Just notify of a Suspend/resume change event (optional) */
+ if (udc->board->susp_chgb != NULL)
+ udc->board->susp_chgb(conn);
+
+ if (conn)
+ udc->suspended = 0;
+ else
+ udc->suspended = 1;
+}
+
+/* Remote wakeup enable/disable - notify board function of change */
+static void uda_remwkp_cgh(struct lpc32xx_udc *udc)
+{
+ if (udc->board->rmwk_chgb != NULL)
+ udc->board->rmwk_chgb(udc->dev_status &
+ (1 << USB_DEVICE_REMOTE_WAKEUP));
+}
+
+/* Reads data from FIFO, adjusts for alignment and data size */
+static void udc_pop_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes)
+{
+ int n, i, bl;
+ u16 *p16;
+ u32 *p32, tmp, cbytes;
+
+ /* Use optimal data transfer method based on source address and size */
+ switch (((u32) data) & 0x3) {
+ case 0: /* 32-bit aligned */
+ p32 = (u32 *) data;
+ cbytes = (bytes & ~0x3);
+
+ /* Copy 32-bit aligned data first */
+ for (n = 0; n < cbytes; n += 4)
+ *p32++ = readl(USBD_RXDATA(udc->udp_baseaddr));
+
+ /* Handle any remaining bytes */
+ bl = bytes - cbytes;
+ if (bl) {
+ tmp = readl(USBD_RXDATA(udc->udp_baseaddr));
+ for (n = 0; n < bl; n++)
+ data[cbytes + n] = ((tmp >> (n * 8)) & 0xFF);
+
+ }
+ break;
+
+ case 1: /* 8-bit aligned */
+ case 3:
+ /* Each byte has to be handled independently */
+ for (n = 0; n < bytes; n += 4) {
+ tmp = readl(USBD_RXDATA(udc->udp_baseaddr));
+
+ bl = bytes - n;
+ if (bl > 3)
+ bl = 3;
+
+ for (i = 0; i < bl; i++)
+ data[n + i] = (u8) ((tmp >> (n * 8)) & 0xFF);
+ }
+ break;
+
+ case 2: /* 16-bit aligned */
+ p16 = (u16 *) data;
+ cbytes = (bytes & ~0x3);
+
+ /* Copy 32-bit sized objects first with 16-bit alignment */
+ for (n = 0; n < cbytes; n += 4) {
+ tmp = readl(USBD_RXDATA(udc->udp_baseaddr));
+ *p16++ = (u16)(tmp & 0xFFFF);
+ *p16++ = (u16)((tmp >> 16) & 0xFFFF);
+ }
+
+ /* Handle any remaining bytes */
+ bl = bytes - cbytes;
+ if (bl) {
+ tmp = readl(USBD_RXDATA(udc->udp_baseaddr));
+ for (n = 0; n < bl; n++)
+ data[cbytes + n] = ((tmp >> (n * 8)) & 0xFF);
+ }
+ break;
+ }
+}
+
+/* Read data from the FIFO for an endpoint. This function is for endpoints (such
+ * as EP0) that don't use DMA. This function should only be called if a packet
+ * is known to be ready to read for the endpoint. Note that the endpoint must
+ * be selected in the protocol engine prior to this call. */
+static u32 udc_read_hwep(struct lpc32xx_udc *udc, u32 hwep, u32 *data,
+ u32 bytes)
+{
+ u32 tmpv;
+ int to = 1000;
+ u32 tmp, hwrep = ((hwep & 0x1E) << 1) | CTRL_RD_EN;
+
+ /* Setup read of endpoint */
+ writel(hwrep, USBD_CTRL(udc->udp_baseaddr));
+
+ /* Wait until packet is ready */
+ while ((((tmpv = readl(USBD_RXPLEN(udc->udp_baseaddr))) &
+ PKT_RDY) == 0) && (to > 0))
+ to--;
+ if (!to)
+ dev_dbg(udc->dev, "No packet ready on FIFO EP read\n");
+
+ /* Mask out count */
+ tmp = tmpv & PKT_LNGTH_MASK;
+ if (bytes < tmp)
+ tmp = bytes;
+
+ if ((tmp > 0) && (data != NULL))
+ udc_pop_fifo(udc, (u8 *) data, tmp);
+
+ writel(((hwep & 0x1E) << 1), USBD_CTRL(udc->udp_baseaddr));
+
+ /* Clear the buffer */
+ udc_clr_buffer_hwep(udc, hwep);
+
+ return tmp;
+}
+
+/* Stuffs data into the FIFO, adjusts for alignment and data size */
+static void udc_stuff_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes)
+{
+ int n, i, bl;
+ u16 *p16;
+ u32 *p32, tmp, cbytes;
+
+ /* Use optimal data transfer method based on source address and size */
+ switch (((u32) data) & 0x3) {
+ case 0: /* 32-bit aligned */
+ p32 = (u32 *) data;
+ cbytes = (bytes & ~0x3);
+
+ /* Copy 32-bit aligned data first */
+ for (n = 0; n < cbytes; n += 4)
+ writel(*p32++, USBD_TXDATA(udc->udp_baseaddr));
+
+ /* Handle any remaining bytes */
+ bl = bytes - cbytes;
+ if (bl) {
+ tmp = 0;
+ for (n = 0; n < bl; n++)
+ tmp |= data[cbytes + n] << (n * 8);
+
+ writel(tmp, USBD_TXDATA(udc->udp_baseaddr));
+ }
+ break;
+
+ case 1: /* 8-bit aligned */
+ case 3:
+ /* Each byte has to be handled independently */
+ for (n = 0; n < bytes; n += 4) {
+ bl = bytes - n;
+ if (bl > 4)
+ bl = 4;
+
+ tmp = 0;
+ for (i = 0; i < bl; i++)
+ tmp |= data[n + i] << (i * 8);
+
+ writel(tmp, USBD_TXDATA(udc->udp_baseaddr));
+ }
+ break;
+
+ case 2: /* 16-bit aligned */
+ p16 = (u16 *) data;
+ cbytes = (bytes & ~0x3);
+
+ /* Copy 32-bit aligned data first */
+ for (n = 0; n < cbytes; n += 4) {
+ tmp = *p16++ & 0xFFFF;
+ tmp |= (*p16++ & 0xFFFF) << 16;
+ writel(tmp, USBD_TXDATA(udc->udp_baseaddr));
+ }
+
+ /* Handle any remaining bytes */
+ bl = bytes - cbytes;
+ if (bl) {
+ tmp = 0;
+ for (n = 0; n < bl; n++)
+ tmp |= data[cbytes + n] << (n * 8);
+
+ writel(tmp, USBD_TXDATA(udc->udp_baseaddr));
+ }
+ break;
+ }
+}
+
+/* Write data to the FIFO for an endpoint. This function is for endpoints (such
+ * as EP0) that don't use DMA. Note that the endpoint must be selected in the
+ * protocol engine prior to this call. */
+static void udc_write_hwep(struct lpc32xx_udc *udc, u32 hwep, u32 *data,
+ u32 bytes)
+{
+ u32 hwwep = ((hwep & 0x1E) << 1) | CTRL_WR_EN;
+
+ if ((bytes > 0) && (data == NULL))
+ return;
+
+ /* Setup write of endpoint */
+ writel(hwwep, USBD_CTRL(udc->udp_baseaddr));
+
+ writel(bytes, USBD_TXPLEN(udc->udp_baseaddr));
+
+ /* Need at least 1 byte to trigger TX */
+ if (bytes == 0)
+ writel(0, USBD_TXDATA(udc->udp_baseaddr));
+ else
+ udc_stuff_fifo(udc, (u8 *) data, bytes);
+
+ writel(((hwep & 0x1E) << 1), USBD_CTRL(udc->udp_baseaddr));
+
+ udc_val_buffer_hwep(udc, hwep);
+}
+
+/* USB device reset - resets USB to a default state with just EP0
+ enabled */
+static void uda_usb_reset(struct lpc32xx_udc *udc)
+{
+ u32 i = 0;
+ /* Re-init device controller and EP0 */
+ udc_enable(udc);
+ udc->gadget.speed = USB_SPEED_FULL;
+
+ for (i = 1; i < NUM_ENDPOINTS; i++) {
+ struct lpc32xx_ep *ep = &udc->ep[i];
+ ep->req_pending = 0;
+ }
+}
+
+/* Send a ZLP on EP0 */
+static void udc_ep0_send_zlp(struct lpc32xx_udc *udc)
+{
+ udc_write_hwep(udc, EP_IN, NULL, 0);
+}
+
+/* Get current frame number */
+static u16 udc_get_current_frame(struct lpc32xx_udc *udc)
+{
+ u16 flo, fhi;
+
+ udc_protocol_cmd_w(udc, CMD_RD_FRAME);
+ flo = (u16) udc_protocol_cmd_r(udc, DAT_RD_FRAME);
+ fhi = (u16) udc_protocol_cmd_r(udc, DAT_RD_FRAME);
+
+ return (fhi << 8) | flo;
+}
+
+/* Set the device as configured - enables all endpoints */
+static inline void udc_set_device_configured(struct lpc32xx_udc *udc)
+{
+ udc_protocol_cmd_data_w(udc, CMD_CFG_DEV, DAT_WR_BYTE(CONF_DVICE));
+}
+
+/* Set the device as unconfigured - disables all endpoints */
+static inline void udc_set_device_unconfigured(struct lpc32xx_udc *udc)
+{
+ udc_protocol_cmd_data_w(udc, CMD_CFG_DEV, DAT_WR_BYTE(0));
+}
+
+/* reinit == restore initial software state */
+static void udc_reinit(struct lpc32xx_udc *udc)
+{
+ u32 i;
+
+ INIT_LIST_HEAD(&udc->gadget.ep_list);
+ INIT_LIST_HEAD(&udc->gadget.ep0->ep_list);
+
+ for (i = 0; i < NUM_ENDPOINTS; i++) {
+ struct lpc32xx_ep *ep = &udc->ep[i];
+
+ if (i != 0)
+ list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+ ep->desc = NULL;
+ ep->ep.maxpacket = ep->maxpacket;
+ INIT_LIST_HEAD(&ep->queue);
+ ep->req_pending = 0;
+ }
+
+ udc->ep0state = WAIT_FOR_SETUP;
+}
+
+/* Must be called with lock */
+static void done(struct lpc32xx_ep *ep, struct lpc32xx_request *req, int status)
+{
+ struct lpc32xx_udc *udc = ep->udc;
+
+ list_del_init(&req->queue);
+ if (req->req.status == -EINPROGRESS)
+ req->req.status = status;
+ else
+ status = req->req.status;
+
+ if (ep->lep) {
+ enum dma_data_direction direction;
+
+ if (ep->is_in)
+ direction = DMA_TO_DEVICE;
+ else
+ direction = DMA_FROM_DEVICE;
+
+ if (req->mapped) {
+ dma_unmap_single(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ direction);
+ req->req.dma = 0;
+ req->mapped = 0;
+ } else
+ dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ direction);
+
+ /* Free DDs */
+ udc_dd_free(udc, req->dd_desc_ptr);
+ }
+
+ if (status && status != -ESHUTDOWN)
+ ep_dbg(ep, "%s done %p, status %d\n", ep->ep.name, req, status);
+
+ ep->req_pending = 0;
+ spin_unlock(&udc->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&udc->lock);
+}
+
+/* Must be called with lock */
+static void nuke(struct lpc32xx_ep *ep, int status)
+{
+ struct lpc32xx_request *req;
+
+ while (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next, struct lpc32xx_request, queue);
+ done(ep, req, status);
+ }
+
+ if (ep->desc && status == -ESHUTDOWN) {
+ uda_disable_hwepint(ep->udc, ep->hwep_num);
+ udc_disable_hwep(ep->udc, ep->hwep_num);
+ }
+}
+
+/* IN endpoint 0 transfer */
+static int udc_ep0_in_req(struct lpc32xx_udc *udc)
+{
+ struct lpc32xx_request *req;
+ struct lpc32xx_ep *ep0 = &udc->ep[0];
+ u32 tsend, ts = 0;
+
+ if (list_empty(&ep0->queue))
+ /* Nothing to send */
+ return 0;
+ else
+ req = list_entry(ep0->queue.next, struct lpc32xx_request,
+ queue);
+
+ tsend = ts = req->req.length - req->req.actual;
+ if (ts == 0) {
+ /* Send a ZLP */
+ udc_ep0_send_zlp(udc);
+ done(ep0, req, 0);
+ return 1;
+ } else if (ts > ep0->ep.maxpacket)
+ ts = ep0->ep.maxpacket; /* Just send what we can */
+
+ /* Write data to the EP0 FIFO and start transfer */
+ udc_write_hwep(udc, EP_IN, (req->req.buf + req->req.actual), ts);
+
+ /* Increment data pointer */
+ req->req.actual += ts;
+
+ if (tsend >= ep0->ep.maxpacket)
+ return 0; /* Stay in data transfer state */
+
+ /* Transfer request is complete */
+ udc->ep0state = WAIT_FOR_SETUP;
+ done(ep0, req, 0);
+ return 1;
+}
+
+/* OUT endpoint 0 transfer */
+static int udc_ep0_out_req(struct lpc32xx_udc *udc)
+{
+ struct lpc32xx_request *req;
+ struct lpc32xx_ep *ep0 = &udc->ep[0];
+ u32 tr, bufferspace;
+
+ if (list_empty(&ep0->queue))
+ return 0;
+ else
+ req = list_entry(ep0->queue.next, struct lpc32xx_request,
+ queue);
+
+ if (req) {
+ if (req->req.length == 0) {
+ /* Just dequeue request */
+ done(ep0, req, 0);
+ udc->ep0state = WAIT_FOR_SETUP;
+ return 1;
+ }
+
+ /* Get data from FIFO */
+ bufferspace = req->req.length - req->req.actual;
+ if (bufferspace > ep0->ep.maxpacket)
+ bufferspace = ep0->ep.maxpacket;
+
+ /* Copy data to buffer */
+ prefetchw(req->req.buf + req->req.actual);
+ tr = udc_read_hwep(udc, EP_OUT, req->req.buf + req->req.actual,
+ bufferspace);
+ req->req.actual += bufferspace;
+
+ if (tr < ep0->ep.maxpacket) {
+ /* This is the last packet */
+ done(ep0, req, 0);
+ udc->ep0state = WAIT_FOR_SETUP;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Must be called with lock */
+static void stop_activity(struct lpc32xx_udc *udc)
+{
+ struct usb_gadget_driver *driver = udc->driver;
+ int i;
+
+ if (udc->gadget.speed == USB_SPEED_UNKNOWN)
+ driver = NULL;
+
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ udc->suspended = 0;
+
+ for (i = 0; i < NUM_ENDPOINTS; i++) {
+ struct lpc32xx_ep *ep = &udc->ep[i];
+ nuke(ep, -ESHUTDOWN);
+ }
+ if (driver) {
+ spin_unlock(&udc->lock);
+ driver->disconnect(&udc->gadget);
+ spin_lock(&udc->lock);
+ }
+
+ isp1301_pullup_enable(udc, 0, 0);
+ udc_disable(udc);
+ udc_reinit(udc);
+}
+
+/*
+ * Activate or kill host pullup
+ * Can be called with or without lock
+ */
+static void pullup(struct lpc32xx_udc *udc, int is_on)
+{
+ if (!udc->clocked)
+ return;
+
+ if (!udc->enabled || !udc->vbus)
+ is_on = 0;
+
+ if (is_on != udc->pullup)
+ isp1301_pullup_enable(udc, is_on, 0);
+}
+
+/* Must be called without lock */
+static int lpc32xx_ep_disable(struct usb_ep *_ep)
+{
+ struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep);
+ struct lpc32xx_udc *udc = ep->udc;
+ unsigned long flags;
+
+ if ((ep->hwep_num_base == 0) || (ep->hwep_num == 0))
+ return -EINVAL;
+ spin_lock_irqsave(&udc->lock, flags);
+
+ nuke(ep, -ESHUTDOWN);
+
+ /* restore the endpoint's pristine config */
+ ep->desc = NULL;
+
+ /* Clear all DMA statuses for this EP */
+ udc_ep_dma_disable(udc, ep->hwep_num);
+ writel(1 << ep->hwep_num, USBD_EOTINTCLR(udc->udp_baseaddr));
+ writel(1 << ep->hwep_num, USBD_NDDRTINTCLR(udc->udp_baseaddr));
+ writel(1 << ep->hwep_num, USBD_SYSERRTINTCLR(udc->udp_baseaddr));
+ writel(1 << ep->hwep_num, USBD_DMARCLR(udc->udp_baseaddr));
+
+ /* Remove the DD pointer in the UDCA */
+ udc->udca_v_base[ep->hwep_num] = 0;
+
+ /* Disable and reset endpoint and interrupt */
+ uda_clear_hwepint(udc, ep->hwep_num);
+ udc_unrealize_hwep(udc, ep->hwep_num);
+
+ ep->hwep_num = 0;
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ atomic_dec(&udc->enabled_ep_cnt);
+ wake_up(&udc->ep_disable_wait_queue);
+
+ return 0;
+}
+
+/* Must be called without lock */
+static int lpc32xx_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep);
+ struct lpc32xx_udc *udc = ep->udc;
+ u16 maxpacket;
+ u32 tmp;
+ unsigned long flags;
+
+ /* Verify EP data */
+ if ((!_ep) || (!ep) || (!desc) || (ep->desc) ||
+ (desc->bDescriptorType != USB_DT_ENDPOINT)) {
+ dev_dbg(udc->dev, "bad ep or descriptor\n");
+ return -EINVAL;
+ }
+ maxpacket = usb_endpoint_maxp(desc);
+ if ((maxpacket == 0) || (maxpacket > ep->maxpacket)) {
+ dev_dbg(udc->dev, "bad ep descriptor's packet size\n");
+ return -EINVAL;
+ }
+
+ /* Don't touch EP0 */
+ if (ep->hwep_num_base == 0) {
+ dev_dbg(udc->dev, "Can't re-enable EP0!!!\n");
+ return -EINVAL;
+ }
+
+ /* Is driver ready? */
+ if ((!udc->driver) || (udc->gadget.speed == USB_SPEED_UNKNOWN)) {
+ dev_dbg(udc->dev, "bogus device state\n");
+ return -ESHUTDOWN;
+ }
+
+ tmp = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+ switch (tmp) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ return -EINVAL;
+
+ case USB_ENDPOINT_XFER_INT:
+ if (maxpacket > ep->maxpacket) {
+ dev_dbg(udc->dev,
+ "Bad INT endpoint maxpacket %d\n", maxpacket);
+ return -EINVAL;
+ }
+ break;
+
+ case USB_ENDPOINT_XFER_BULK:
+ switch (maxpacket) {
+ case 8:
+ case 16:
+ case 32:
+ case 64:
+ break;
+
+ default:
+ dev_dbg(udc->dev,
+ "Bad BULK endpoint maxpacket %d\n", maxpacket);
+ return -EINVAL;
+ }
+ break;
+
+ case USB_ENDPOINT_XFER_ISOC:
+ break;
+ }
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* Initialize endpoint to match the selected descriptor */
+ ep->is_in = (desc->bEndpointAddress & USB_DIR_IN) != 0;
+ ep->desc = desc;
+ ep->ep.maxpacket = maxpacket;
+
+ /* Map hardware endpoint from base and direction */
+ if (ep->is_in)
+ /* IN endpoints are offset 1 from the OUT endpoint */
+ ep->hwep_num = ep->hwep_num_base + EP_IN;
+ else
+ ep->hwep_num = ep->hwep_num_base;
+
+ ep_dbg(ep, "EP enabled: %s, HW:%d, MP:%d IN:%d\n", ep->ep.name,
+ ep->hwep_num, maxpacket, (ep->is_in == 1));
+
+ /* Realize the endpoint, interrupt is enabled later when
+ * buffers are queued, IN EPs will NAK until buffers are ready */
+ udc_realize_hwep(udc, ep->hwep_num, ep->ep.maxpacket);
+ udc_clr_buffer_hwep(udc, ep->hwep_num);
+ uda_disable_hwepint(udc, ep->hwep_num);
+ udc_clrstall_hwep(udc, ep->hwep_num);
+
+ /* Clear all DMA statuses for this EP */
+ udc_ep_dma_disable(udc, ep->hwep_num);
+ writel(1 << ep->hwep_num, USBD_EOTINTCLR(udc->udp_baseaddr));
+ writel(1 << ep->hwep_num, USBD_NDDRTINTCLR(udc->udp_baseaddr));
+ writel(1 << ep->hwep_num, USBD_SYSERRTINTCLR(udc->udp_baseaddr));
+ writel(1 << ep->hwep_num, USBD_DMARCLR(udc->udp_baseaddr));
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ atomic_inc(&udc->enabled_ep_cnt);
+ return 0;
+}
+
+/*
+ * Allocate a USB request list
+ * Can be called with or without lock
+ */
+static struct usb_request *lpc32xx_ep_alloc_request(struct usb_ep *_ep,
+ gfp_t gfp_flags)
+{
+ struct lpc32xx_request *req;
+
+ req = kzalloc(sizeof(struct lpc32xx_request), gfp_flags);
+ if (!req)
+ return NULL;
+
+ INIT_LIST_HEAD(&req->queue);
+ return &req->req;
+}
+
+/*
+ * De-allocate a USB request list
+ * Can be called with or without lock
+ */
+static void lpc32xx_ep_free_request(struct usb_ep *_ep,
+ struct usb_request *_req)
+{
+ struct lpc32xx_request *req;
+
+ req = container_of(_req, struct lpc32xx_request, req);
+ BUG_ON(!list_empty(&req->queue));
+ kfree(req);
+}
+
+/* Must be called without lock */
+static int lpc32xx_ep_queue(struct usb_ep *_ep,
+ struct usb_request *_req, gfp_t gfp_flags)
+{
+ struct lpc32xx_request *req;
+ struct lpc32xx_ep *ep;
+ struct lpc32xx_udc *udc;
+ unsigned long flags;
+ int status = 0;
+
+ req = container_of(_req, struct lpc32xx_request, req);
+ ep = container_of(_ep, struct lpc32xx_ep, ep);
+
+ if (!_req || !_req->complete || !_req->buf ||
+ !list_empty(&req->queue))
+ return -EINVAL;
+
+ udc = ep->udc;
+
+ if (!_ep || (!ep->desc && ep->hwep_num_base != 0)) {
+ dev_dbg(udc->dev, "invalid ep\n");
+ return -EINVAL;
+ }
+
+
+ if ((!udc) || (!udc->driver) ||
+ (udc->gadget.speed == USB_SPEED_UNKNOWN)) {
+ dev_dbg(udc->dev, "invalid device\n");
+ return -EINVAL;
+ }
+
+ if (ep->lep) {
+ enum dma_data_direction direction;
+ struct lpc32xx_usbd_dd_gad *dd;
+
+ /* Map DMA pointer */
+ if (ep->is_in)
+ direction = DMA_TO_DEVICE;
+ else
+ direction = DMA_FROM_DEVICE;
+
+ if (req->req.dma == 0) {
+ req->req.dma = dma_map_single(
+ ep->udc->gadget.dev.parent,
+ req->req.buf, req->req.length, direction);
+ req->mapped = 1;
+ } else {
+ dma_sync_single_for_device(
+ ep->udc->gadget.dev.parent, req->req.dma,
+ req->req.length, direction);
+ req->mapped = 0;
+ }
+
+ /* For the request, build a list of DDs */
+ dd = udc_dd_alloc(udc);
+ if (!dd) {
+ /* Error allocating DD */
+ return -ENOMEM;
+ }
+ req->dd_desc_ptr = dd;
+
+ /* Setup the DMA descriptor */
+ dd->dd_next_phy = dd->dd_next_v = 0;
+ dd->dd_buffer_addr = req->req.dma;
+ dd->dd_status = 0;
+
+ /* Special handling for ISO EPs */
+ if (ep->eptype == EP_ISO_TYPE) {
+ dd->dd_setup = DD_SETUP_ISO_EP |
+ DD_SETUP_PACKETLEN(0) |
+ DD_SETUP_DMALENBYTES(1);
+ dd->dd_iso_ps_mem_addr = dd->this_dma + 24;
+ if (ep->is_in)
+ dd->iso_status[0] = req->req.length;
+ else
+ dd->iso_status[0] = 0;
+ } else
+ dd->dd_setup = DD_SETUP_PACKETLEN(ep->ep.maxpacket) |
+ DD_SETUP_DMALENBYTES(req->req.length);
+ }
+
+ ep_dbg(ep, "%s queue req %p len %d buf %p (in=%d) z=%d\n", _ep->name,
+ _req, _req->length, _req->buf, ep->is_in, _req->zero);
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ _req->status = -EINPROGRESS;
+ _req->actual = 0;
+ req->send_zlp = _req->zero;
+
+ /* Kickstart empty queues */
+ if (list_empty(&ep->queue)) {
+ list_add_tail(&req->queue, &ep->queue);
+
+ if (ep->hwep_num_base == 0) {
+ /* Handle expected data direction */
+ if (ep->is_in) {
+ /* IN packet to host */
+ udc->ep0state = DATA_IN;
+ status = udc_ep0_in_req(udc);
+ } else {
+ /* OUT packet from host */
+ udc->ep0state = DATA_OUT;
+ status = udc_ep0_out_req(udc);
+ }
+ } else if (ep->is_in) {
+ /* IN packet to host and kick off transfer */
+ if (!ep->req_pending)
+ udc_ep_in_req_dma(udc, ep);
+ } else
+ /* OUT packet from host and kick off list */
+ if (!ep->req_pending)
+ udc_ep_out_req_dma(udc, ep);
+ } else
+ list_add_tail(&req->queue, &ep->queue);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return (status < 0) ? status : 0;
+}
+
+/* Must be called without lock */
+static int lpc32xx_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct lpc32xx_ep *ep;
+ struct lpc32xx_request *req;
+ unsigned long flags;
+
+ ep = container_of(_ep, struct lpc32xx_ep, ep);
+ if (!_ep || ep->hwep_num_base == 0)
+ return -EINVAL;
+
+ spin_lock_irqsave(&ep->udc->lock, flags);
+
+ /* make sure it's actually queued on this endpoint */
+ list_for_each_entry(req, &ep->queue, queue) {
+ if (&req->req == _req)
+ break;
+ }
+ if (&req->req != _req) {
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+ return -EINVAL;
+ }
+
+ done(ep, req, -ECONNRESET);
+
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+
+ return 0;
+}
+
+/* Must be called without lock */
+static int lpc32xx_ep_set_halt(struct usb_ep *_ep, int value)
+{
+ struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep);
+ struct lpc32xx_udc *udc = ep->udc;
+ unsigned long flags;
+
+ if ((!ep) || (ep->desc == NULL) || (ep->hwep_num <= 1))
+ return -EINVAL;
+
+ /* Don't halt an IN EP */
+ if (ep->is_in)
+ return -EAGAIN;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ if (value == 1) {
+ /* stall */
+ udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(ep->hwep_num),
+ DAT_WR_BYTE(EP_STAT_ST));
+ } else {
+ /* End stall */
+ ep->wedge = 0;
+ udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(ep->hwep_num),
+ DAT_WR_BYTE(0));
+ }
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+/* set the halt feature and ignores clear requests */
+static int lpc32xx_ep_set_wedge(struct usb_ep *_ep)
+{
+ struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep);
+
+ if (!_ep || !ep->udc)
+ return -EINVAL;
+
+ ep->wedge = 1;
+
+ return usb_ep_set_halt(_ep);
+}
+
+static const struct usb_ep_ops lpc32xx_ep_ops = {
+ .enable = lpc32xx_ep_enable,
+ .disable = lpc32xx_ep_disable,
+ .alloc_request = lpc32xx_ep_alloc_request,
+ .free_request = lpc32xx_ep_free_request,
+ .queue = lpc32xx_ep_queue,
+ .dequeue = lpc32xx_ep_dequeue,
+ .set_halt = lpc32xx_ep_set_halt,
+ .set_wedge = lpc32xx_ep_set_wedge,
+};
+
+/* Send a ZLP on a non-0 IN EP */
+void udc_send_in_zlp(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep)
+{
+ /* Clear EP status */
+ udc_clearep_getsts(udc, ep->hwep_num);
+
+ /* Send ZLP via FIFO mechanism */
+ udc_write_hwep(udc, ep->hwep_num, NULL, 0);
+}
+
+/*
+ * Handle EP completion for ZLP
+ * This function will only be called when a delayed ZLP needs to be sent out
+ * after a DMA transfer has filled both buffers.
+ */
+void udc_handle_eps(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep)
+{
+ u32 epstatus;
+ struct lpc32xx_request *req;
+
+ if (ep->hwep_num <= 0)
+ return;
+
+ uda_clear_hwepint(udc, ep->hwep_num);
+
+ /* If this interrupt isn't enabled, return now */
+ if (!(udc->enabled_hwepints & (1 << ep->hwep_num)))
+ return;
+
+ /* Get endpoint status */
+ epstatus = udc_clearep_getsts(udc, ep->hwep_num);
+
+ /*
+ * This should never happen, but protect against writing to the
+ * buffer when full.
+ */
+ if (epstatus & EP_SEL_F)
+ return;
+
+ if (ep->is_in) {
+ udc_send_in_zlp(udc, ep);
+ uda_disable_hwepint(udc, ep->hwep_num);
+ } else
+ return;
+
+ /* If there isn't a request waiting, something went wrong */
+ req = list_entry(ep->queue.next, struct lpc32xx_request, queue);
+ if (req) {
+ done(ep, req, 0);
+
+ /* Start another request if ready */
+ if (!list_empty(&ep->queue)) {
+ if (ep->is_in)
+ udc_ep_in_req_dma(udc, ep);
+ else
+ udc_ep_out_req_dma(udc, ep);
+ } else
+ ep->req_pending = 0;
+ }
+}
+
+
+/* DMA end of transfer completion */
+static void udc_handle_dma_ep(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep)
+{
+ u32 status, epstatus;
+ struct lpc32xx_request *req;
+ struct lpc32xx_usbd_dd_gad *dd;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+ ep->totalints++;
+#endif
+
+ req = list_entry(ep->queue.next, struct lpc32xx_request, queue);
+ if (!req) {
+ ep_err(ep, "DMA interrupt on no req!\n");
+ return;
+ }
+ dd = req->dd_desc_ptr;
+
+ /* DMA descriptor should always be retired for this call */
+ if (!(dd->dd_status & DD_STATUS_DD_RETIRED))
+ ep_warn(ep, "DMA descriptor did not retire\n");
+
+ /* Disable DMA */
+ udc_ep_dma_disable(udc, ep->hwep_num);
+ writel((1 << ep->hwep_num), USBD_EOTINTCLR(udc->udp_baseaddr));
+ writel((1 << ep->hwep_num), USBD_NDDRTINTCLR(udc->udp_baseaddr));
+
+ /* System error? */
+ if (readl(USBD_SYSERRTINTST(udc->udp_baseaddr)) &
+ (1 << ep->hwep_num)) {
+ writel((1 << ep->hwep_num),
+ USBD_SYSERRTINTCLR(udc->udp_baseaddr));
+ ep_err(ep, "AHB critical error!\n");
+ ep->req_pending = 0;
+
+ /* The error could have occurred on a packet of a multipacket
+ * transfer, so recovering the transfer is not possible. Close
+ * the request with an error */
+ done(ep, req, -ECONNABORTED);
+ return;
+ }
+
+ /* Handle the current DD's status */
+ status = dd->dd_status;
+ switch (status & DD_STATUS_STS_MASK) {
+ case DD_STATUS_STS_NS:
+ /* DD not serviced? This shouldn't happen! */
+ ep->req_pending = 0;
+ ep_err(ep, "DMA critical EP error: DD not serviced (0x%x)!\n",
+ status);
+
+ done(ep, req, -ECONNABORTED);
+ return;
+
+ case DD_STATUS_STS_BS:
+ /* Interrupt only fires on EOT - This shouldn't happen! */
+ ep->req_pending = 0;
+ ep_err(ep, "DMA critical EP error: EOT prior to service completion (0x%x)!\n",
+ status);
+ done(ep, req, -ECONNABORTED);
+ return;
+
+ case DD_STATUS_STS_NC:
+ case DD_STATUS_STS_DUR:
+ /* Really just a short packet, not an underrun */
+ /* This is a good status and what we expect */
+ break;
+
+ default:
+ /* Data overrun, system error, or unknown */
+ ep->req_pending = 0;
+ ep_err(ep, "DMA critical EP error: System error (0x%x)!\n",
+ status);
+ done(ep, req, -ECONNABORTED);
+ return;
+ }
+
+ /* ISO endpoints are handled differently */
+ if (ep->eptype == EP_ISO_TYPE) {
+ if (ep->is_in)
+ req->req.actual = req->req.length;
+ else
+ req->req.actual = dd->iso_status[0] & 0xFFFF;
+ } else
+ req->req.actual += DD_STATUS_CURDMACNT(status);
+
+ /* Send a ZLP if necessary. This will be done for non-int
+ * packets which have a size that is a divisor of MAXP */
+ if (req->send_zlp) {
+ /*
+ * If at least 1 buffer is available, send the ZLP now.
+ * Otherwise, the ZLP send needs to be deferred until a
+ * buffer is available.
+ */
+ if (udc_clearep_getsts(udc, ep->hwep_num) & EP_SEL_F) {
+ udc_clearep_getsts(udc, ep->hwep_num);
+ uda_enable_hwepint(udc, ep->hwep_num);
+ epstatus = udc_clearep_getsts(udc, ep->hwep_num);
+
+ /* Let the EP interrupt handle the ZLP */
+ return;
+ } else
+ udc_send_in_zlp(udc, ep);
+ }
+
+ /* Transfer request is complete */
+ done(ep, req, 0);
+
+ /* Start another request if ready */
+ udc_clearep_getsts(udc, ep->hwep_num);
+ if (!list_empty((&ep->queue))) {
+ if (ep->is_in)
+ udc_ep_in_req_dma(udc, ep);
+ else
+ udc_ep_out_req_dma(udc, ep);
+ } else
+ ep->req_pending = 0;
+
+}
+
+/*
+ *
+ * Endpoint 0 functions
+ *
+ */
+static void udc_handle_dev(struct lpc32xx_udc *udc)
+{
+ u32 tmp;
+
+ udc_protocol_cmd_w(udc, CMD_GET_DEV_STAT);
+ tmp = udc_protocol_cmd_r(udc, DAT_GET_DEV_STAT);
+
+ if (tmp & DEV_RST)
+ uda_usb_reset(udc);
+ else if (tmp & DEV_CON_CH)
+ uda_power_event(udc, (tmp & DEV_CON));
+ else if (tmp & DEV_SUS_CH) {
+ if (tmp & DEV_SUS) {
+ if (udc->vbus == 0)
+ stop_activity(udc);
+ else if ((udc->gadget.speed != USB_SPEED_UNKNOWN) &&
+ udc->driver) {
+ /* Power down transceiver */
+ udc->poweron = 0;
+ schedule_work(&udc->pullup_job);
+ uda_resm_susp_event(udc, 1);
+ }
+ } else if ((udc->gadget.speed != USB_SPEED_UNKNOWN) &&
+ udc->driver && udc->vbus) {
+ uda_resm_susp_event(udc, 0);
+ /* Power up transceiver */
+ udc->poweron = 1;
+ schedule_work(&udc->pullup_job);
+ }
+ }
+}
+
+static int udc_get_status(struct lpc32xx_udc *udc, u16 reqtype, u16 wIndex)
+{
+ struct lpc32xx_ep *ep;
+ u32 ep0buff = 0, tmp;
+
+ switch (reqtype & USB_RECIP_MASK) {
+ case USB_RECIP_INTERFACE:
+ break; /* Not supported */
+
+ case USB_RECIP_DEVICE:
+ ep0buff = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
+ if (udc->dev_status & (1 << USB_DEVICE_REMOTE_WAKEUP))
+ ep0buff |= (1 << USB_DEVICE_REMOTE_WAKEUP);
+ break;
+
+ case USB_RECIP_ENDPOINT:
+ tmp = wIndex & USB_ENDPOINT_NUMBER_MASK;
+ ep = &udc->ep[tmp];
+ if ((tmp == 0) || (tmp >= NUM_ENDPOINTS) || (tmp && !ep->desc))
+ return -EOPNOTSUPP;
+
+ if (wIndex & USB_DIR_IN) {
+ if (!ep->is_in)
+ return -EOPNOTSUPP; /* Something's wrong */
+ } else if (ep->is_in)
+ return -EOPNOTSUPP; /* Not an IN endpoint */
+
+ /* Get status of the endpoint */
+ udc_protocol_cmd_w(udc, CMD_SEL_EP(ep->hwep_num));
+ tmp = udc_protocol_cmd_r(udc, DAT_SEL_EP(ep->hwep_num));
+
+ if (tmp & EP_SEL_ST)
+ ep0buff = (1 << USB_ENDPOINT_HALT);
+ else
+ ep0buff = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Return data */
+ udc_write_hwep(udc, EP_IN, &ep0buff, 2);
+
+ return 0;
+}
+
+static void udc_handle_ep0_setup(struct lpc32xx_udc *udc)
+{
+ struct lpc32xx_ep *ep, *ep0 = &udc->ep[0];
+ struct usb_ctrlrequest ctrlpkt;
+ int i, bytes;
+ u16 wIndex, wValue, wLength, reqtype, req, tmp;
+
+ /* Nuke previous transfers */
+ nuke(ep0, -EPROTO);
+
+ /* Get setup packet */
+ bytes = udc_read_hwep(udc, EP_OUT, (u32 *) &ctrlpkt, 8);
+ if (bytes != 8) {
+ ep_warn(ep0, "Incorrectly sized setup packet (s/b 8, is %d)!\n",
+ bytes);
+ return;
+ }
+
+ /* Native endianness */
+ wIndex = le16_to_cpu(ctrlpkt.wIndex);
+ wValue = le16_to_cpu(ctrlpkt.wValue);
+ wLength = le16_to_cpu(ctrlpkt.wLength);
+ reqtype = le16_to_cpu(ctrlpkt.bRequestType);
+
+ /* Set direction of EP0 */
+ if (likely(reqtype & USB_DIR_IN))
+ ep0->is_in = 1;
+ else
+ ep0->is_in = 0;
+
+ /* Handle SETUP packet */
+ req = le16_to_cpu(ctrlpkt.bRequest);
+ switch (req) {
+ case USB_REQ_CLEAR_FEATURE:
+ case USB_REQ_SET_FEATURE:
+ switch (reqtype) {
+ case (USB_TYPE_STANDARD | USB_RECIP_DEVICE):
+ if (wValue != USB_DEVICE_REMOTE_WAKEUP)
+ goto stall; /* Nothing else handled */
+
+ /* Tell board about event */
+ if (req == USB_REQ_CLEAR_FEATURE)
+ udc->dev_status &=
+ ~(1 << USB_DEVICE_REMOTE_WAKEUP);
+ else
+ udc->dev_status |=
+ (1 << USB_DEVICE_REMOTE_WAKEUP);
+ uda_remwkp_cgh(udc);
+ goto zlp_send;
+
+ case (USB_TYPE_STANDARD | USB_RECIP_ENDPOINT):
+ tmp = wIndex & USB_ENDPOINT_NUMBER_MASK;
+ if ((wValue != USB_ENDPOINT_HALT) ||
+ (tmp >= NUM_ENDPOINTS))
+ break;
+
+ /* Find hardware endpoint from logical endpoint */
+ ep = &udc->ep[tmp];
+ tmp = ep->hwep_num;
+ if (tmp == 0)
+ break;
+
+ if (req == USB_REQ_SET_FEATURE)
+ udc_stall_hwep(udc, tmp);
+ else if (!ep->wedge)
+ udc_clrstall_hwep(udc, tmp);
+
+ goto zlp_send;
+
+ default:
+ break;
+ }
+
+
+ case USB_REQ_SET_ADDRESS:
+ if (reqtype == (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) {
+ udc_set_address(udc, wValue);
+ goto zlp_send;
+ }
+ break;
+
+ case USB_REQ_GET_STATUS:
+ udc_get_status(udc, reqtype, wIndex);
+ return;
+
+ default:
+ break; /* Let GadgetFS handle the descriptor instead */
+ }
+
+ if (likely(udc->driver)) {
+ /* device-2-host (IN) or no data setup command, process
+ * immediately */
+ spin_unlock(&udc->lock);
+ i = udc->driver->setup(&udc->gadget, &ctrlpkt);
+
+ spin_lock(&udc->lock);
+ if (req == USB_REQ_SET_CONFIGURATION) {
+ /* Configuration is set after endpoints are realized */
+ if (wValue) {
+ /* Set configuration */
+ udc_set_device_configured(udc);
+
+ udc_protocol_cmd_data_w(udc, CMD_SET_MODE,
+ DAT_WR_BYTE(AP_CLK |
+ INAK_BI | INAK_II));
+ } else {
+ /* Clear configuration */
+ udc_set_device_unconfigured(udc);
+
+ /* Disable NAK interrupts */
+ udc_protocol_cmd_data_w(udc, CMD_SET_MODE,
+ DAT_WR_BYTE(AP_CLK));
+ }
+ }
+
+ if (i < 0) {
+ /* setup processing failed, force stall */
+ dev_err(udc->dev,
+ "req %02x.%02x protocol STALL; stat %d\n",
+ reqtype, req, i);
+ udc->ep0state = WAIT_FOR_SETUP;
+ goto stall;
+ }
+ }
+
+ if (!ep0->is_in)
+ udc_ep0_send_zlp(udc); /* ZLP IN packet on data phase */
+
+ return;
+
+stall:
+ udc_stall_hwep(udc, EP_IN);
+ return;
+
+zlp_send:
+ udc_ep0_send_zlp(udc);
+ return;
+}
+
+/* IN endpoint 0 transfer */
+static void udc_handle_ep0_in(struct lpc32xx_udc *udc)
+{
+ struct lpc32xx_ep *ep0 = &udc->ep[0];
+ u32 epstatus;
+
+ /* Clear EP interrupt */
+ epstatus = udc_clearep_getsts(udc, EP_IN);
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+ ep0->totalints++;
+#endif
+
+ /* Stalled? Clear stall and reset buffers */
+ if (epstatus & EP_SEL_ST) {
+ udc_clrstall_hwep(udc, EP_IN);
+ nuke(ep0, -ECONNABORTED);
+ udc->ep0state = WAIT_FOR_SETUP;
+ return;
+ }
+
+ /* Is a buffer available? */
+ if (!(epstatus & EP_SEL_F)) {
+ /* Handle based on current state */
+ if (udc->ep0state == DATA_IN)
+ udc_ep0_in_req(udc);
+ else {
+ /* Unknown state for EP0 oe end of DATA IN phase */
+ nuke(ep0, -ECONNABORTED);
+ udc->ep0state = WAIT_FOR_SETUP;
+ }
+ }
+}
+
+/* OUT endpoint 0 transfer */
+static void udc_handle_ep0_out(struct lpc32xx_udc *udc)
+{
+ struct lpc32xx_ep *ep0 = &udc->ep[0];
+ u32 epstatus;
+
+ /* Clear EP interrupt */
+ epstatus = udc_clearep_getsts(udc, EP_OUT);
+
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+ ep0->totalints++;
+#endif
+
+ /* Stalled? */
+ if (epstatus & EP_SEL_ST) {
+ udc_clrstall_hwep(udc, EP_OUT);
+ nuke(ep0, -ECONNABORTED);
+ udc->ep0state = WAIT_FOR_SETUP;
+ return;
+ }
+
+ /* A NAK may occur if a packet couldn't be received yet */
+ if (epstatus & EP_SEL_EPN)
+ return;
+ /* Setup packet incoming? */
+ if (epstatus & EP_SEL_STP) {
+ nuke(ep0, 0);
+ udc->ep0state = WAIT_FOR_SETUP;
+ }
+
+ /* Data available? */
+ if (epstatus & EP_SEL_F)
+ /* Handle based on current state */
+ switch (udc->ep0state) {
+ case WAIT_FOR_SETUP:
+ udc_handle_ep0_setup(udc);
+ break;
+
+ case DATA_OUT:
+ udc_ep0_out_req(udc);
+ break;
+
+ default:
+ /* Unknown state for EP0 */
+ nuke(ep0, -ECONNABORTED);
+ udc->ep0state = WAIT_FOR_SETUP;
+ }
+}
+
+/* Must be called without lock */
+static int lpc32xx_get_frame(struct usb_gadget *gadget)
+{
+ int frame;
+ unsigned long flags;
+ struct lpc32xx_udc *udc = to_udc(gadget);
+
+ if (!udc->clocked)
+ return -EINVAL;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ frame = (int) udc_get_current_frame(udc);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return frame;
+}
+
+static int lpc32xx_wakeup(struct usb_gadget *gadget)
+{
+ return -ENOTSUPP;
+}
+
+static int lpc32xx_set_selfpowered(struct usb_gadget *gadget, int is_on)
+{
+ struct lpc32xx_udc *udc = to_udc(gadget);
+
+ /* Always self-powered */
+ udc->selfpowered = (is_on != 0);
+
+ return 0;
+}
+
+/*
+ * vbus is here! turn everything on that's ready
+ * Must be called without lock
+ */
+static int lpc32xx_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+ unsigned long flags;
+ struct lpc32xx_udc *udc = to_udc(gadget);
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* Doesn't need lock */
+ if (udc->driver) {
+ udc_clk_set(udc, 1);
+ udc_enable(udc);
+ pullup(udc, is_active);
+ } else {
+ stop_activity(udc);
+ pullup(udc, 0);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+ /*
+ * Wait for all the endpoints to disable,
+ * before disabling clocks. Don't wait if
+ * endpoints are not enabled.
+ */
+ if (atomic_read(&udc->enabled_ep_cnt))
+ wait_event_interruptible(udc->ep_disable_wait_queue,
+ (atomic_read(&udc->enabled_ep_cnt) == 0));
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ udc_clk_set(udc, 0);
+ }
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+/* Can be called with or without lock */
+static int lpc32xx_pullup(struct usb_gadget *gadget, int is_on)
+{
+ struct lpc32xx_udc *udc = to_udc(gadget);
+
+ /* Doesn't need lock */
+ pullup(udc, is_on);
+
+ return 0;
+}
+
+static int lpc32xx_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int lpc32xx_stop(struct usb_gadget_driver *driver);
+
+static const struct usb_gadget_ops lpc32xx_udc_ops = {
+ .get_frame = lpc32xx_get_frame,
+ .wakeup = lpc32xx_wakeup,
+ .set_selfpowered = lpc32xx_set_selfpowered,
+ .vbus_session = lpc32xx_vbus_session,
+ .pullup = lpc32xx_pullup,
+ .start = lpc32xx_start,
+ .stop = lpc32xx_stop,
+};
+
+static void nop_release(struct device *dev)
+{
+ /* nothing to free */
+}
+
+static struct lpc32xx_udc controller = {
+ .gadget = {
+ .ops = &lpc32xx_udc_ops,
+ .ep0 = &controller.ep[0].ep,
+ .name = driver_name,
+ .dev = {
+ .init_name = "gadget",
+ .release = nop_release,
+ }
+ },
+ .ep[0] = {
+ .ep = {
+ .name = "ep0",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 64,
+ .hwep_num_base = 0,
+ .hwep_num = 0, /* Can be 0 or 1, has special handling */
+ .lep = 0,
+ .eptype = EP_CTL_TYPE,
+ },
+ .ep[1] = {
+ .ep = {
+ .name = "ep1-int",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 64,
+ .hwep_num_base = 2,
+ .hwep_num = 0, /* 2 or 3, will be set later */
+ .lep = 1,
+ .eptype = EP_INT_TYPE,
+ },
+ .ep[2] = {
+ .ep = {
+ .name = "ep2-bulk",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 64,
+ .hwep_num_base = 4,
+ .hwep_num = 0, /* 4 or 5, will be set later */
+ .lep = 2,
+ .eptype = EP_BLK_TYPE,
+ },
+ .ep[3] = {
+ .ep = {
+ .name = "ep3-iso",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 1023,
+ .hwep_num_base = 6,
+ .hwep_num = 0, /* 6 or 7, will be set later */
+ .lep = 3,
+ .eptype = EP_ISO_TYPE,
+ },
+ .ep[4] = {
+ .ep = {
+ .name = "ep4-int",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 64,
+ .hwep_num_base = 8,
+ .hwep_num = 0, /* 8 or 9, will be set later */
+ .lep = 4,
+ .eptype = EP_INT_TYPE,
+ },
+ .ep[5] = {
+ .ep = {
+ .name = "ep5-bulk",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 64,
+ .hwep_num_base = 10,
+ .hwep_num = 0, /* 10 or 11, will be set later */
+ .lep = 5,
+ .eptype = EP_BLK_TYPE,
+ },
+ .ep[6] = {
+ .ep = {
+ .name = "ep6-iso",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 1023,
+ .hwep_num_base = 12,
+ .hwep_num = 0, /* 12 or 13, will be set later */
+ .lep = 6,
+ .eptype = EP_ISO_TYPE,
+ },
+ .ep[7] = {
+ .ep = {
+ .name = "ep7-int",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 64,
+ .hwep_num_base = 14,
+ .hwep_num = 0,
+ .lep = 7,
+ .eptype = EP_INT_TYPE,
+ },
+ .ep[8] = {
+ .ep = {
+ .name = "ep8-bulk",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 64,
+ .hwep_num_base = 16,
+ .hwep_num = 0,
+ .lep = 8,
+ .eptype = EP_BLK_TYPE,
+ },
+ .ep[9] = {
+ .ep = {
+ .name = "ep9-iso",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 1023,
+ .hwep_num_base = 18,
+ .hwep_num = 0,
+ .lep = 9,
+ .eptype = EP_ISO_TYPE,
+ },
+ .ep[10] = {
+ .ep = {
+ .name = "ep10-int",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 64,
+ .hwep_num_base = 20,
+ .hwep_num = 0,
+ .lep = 10,
+ .eptype = EP_INT_TYPE,
+ },
+ .ep[11] = {
+ .ep = {
+ .name = "ep11-bulk",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 64,
+ .hwep_num_base = 22,
+ .hwep_num = 0,
+ .lep = 11,
+ .eptype = EP_BLK_TYPE,
+ },
+ .ep[12] = {
+ .ep = {
+ .name = "ep12-iso",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 1023,
+ .hwep_num_base = 24,
+ .hwep_num = 0,
+ .lep = 12,
+ .eptype = EP_ISO_TYPE,
+ },
+ .ep[13] = {
+ .ep = {
+ .name = "ep13-int",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 64,
+ .hwep_num_base = 26,
+ .hwep_num = 0,
+ .lep = 13,
+ .eptype = EP_INT_TYPE,
+ },
+ .ep[14] = {
+ .ep = {
+ .name = "ep14-bulk",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 64,
+ .hwep_num_base = 28,
+ .hwep_num = 0,
+ .lep = 14,
+ .eptype = EP_BLK_TYPE,
+ },
+ .ep[15] = {
+ .ep = {
+ .name = "ep15-bulk",
+ .ops = &lpc32xx_ep_ops,
+ },
+ .udc = &controller,
+ .maxpacket = 1023,
+ .hwep_num_base = 30,
+ .hwep_num = 0,
+ .lep = 15,
+ .eptype = EP_BLK_TYPE,
+ },
+};
+
+/* ISO and status interrupts */
+static irqreturn_t lpc32xx_usb_lp_irq(int irq, void *_udc)
+{
+ u32 tmp, devstat;
+ struct lpc32xx_udc *udc = _udc;
+
+ spin_lock(&udc->lock);
+
+ /* Read the device status register */
+ devstat = readl(USBD_DEVINTST(udc->udp_baseaddr));
+
+ devstat &= ~USBD_EP_FAST;
+ writel(devstat, USBD_DEVINTCLR(udc->udp_baseaddr));
+ devstat = devstat & udc->enabled_devints;
+
+ /* Device specific handling needed? */
+ if (devstat & USBD_DEV_STAT)
+ udc_handle_dev(udc);
+
+ /* Start of frame? (devstat & FRAME_INT):
+ * The frame interrupt isn't really needed for ISO support,
+ * as the driver will queue the necessary packets */
+
+ /* Error? */
+ if (devstat & ERR_INT) {
+ /* All types of errors, from cable removal during transfer to
+ * misc protocol and bit errors. These are mostly for just info,
+ * as the USB hardware will work around these. If these errors
+ * happen alot, something is wrong. */
+ udc_protocol_cmd_w(udc, CMD_RD_ERR_STAT);
+ tmp = udc_protocol_cmd_r(udc, DAT_RD_ERR_STAT);
+ dev_dbg(udc->dev, "Device error (0x%x)!\n", tmp);
+ }
+
+ spin_unlock(&udc->lock);
+
+ return IRQ_HANDLED;
+}
+
+/* EP interrupts */
+static irqreturn_t lpc32xx_usb_hp_irq(int irq, void *_udc)
+{
+ u32 tmp;
+ struct lpc32xx_udc *udc = _udc;
+
+ spin_lock(&udc->lock);
+
+ /* Read the device status register */
+ writel(USBD_EP_FAST, USBD_DEVINTCLR(udc->udp_baseaddr));
+
+ /* Endpoints */
+ tmp = readl(USBD_EPINTST(udc->udp_baseaddr));
+
+ /* Special handling for EP0 */
+ if (tmp & (EP_MASK_SEL(0, EP_OUT) | EP_MASK_SEL(0, EP_IN))) {
+ /* Handle EP0 IN */
+ if (tmp & (EP_MASK_SEL(0, EP_IN)))
+ udc_handle_ep0_in(udc);
+
+ /* Handle EP0 OUT */
+ if (tmp & (EP_MASK_SEL(0, EP_OUT)))
+ udc_handle_ep0_out(udc);
+ }
+
+ /* All other EPs */
+ if (tmp & ~(EP_MASK_SEL(0, EP_OUT) | EP_MASK_SEL(0, EP_IN))) {
+ int i;
+
+ /* Handle other EP interrupts */
+ for (i = 1; i < NUM_ENDPOINTS; i++) {
+ if (tmp & (1 << udc->ep[i].hwep_num))
+ udc_handle_eps(udc, &udc->ep[i]);
+ }
+ }
+
+ spin_unlock(&udc->lock);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t lpc32xx_usb_devdma_irq(int irq, void *_udc)
+{
+ struct lpc32xx_udc *udc = _udc;
+
+ int i;
+ u32 tmp;
+
+ spin_lock(&udc->lock);
+
+ /* Handle EP DMA EOT interrupts */
+ tmp = readl(USBD_EOTINTST(udc->udp_baseaddr)) |
+ (readl(USBD_EPDMAST(udc->udp_baseaddr)) &
+ readl(USBD_NDDRTINTST(udc->udp_baseaddr))) |
+ readl(USBD_SYSERRTINTST(udc->udp_baseaddr));
+ for (i = 1; i < NUM_ENDPOINTS; i++) {
+ if (tmp & (1 << udc->ep[i].hwep_num))
+ udc_handle_dma_ep(udc, &udc->ep[i]);
+ }
+
+ spin_unlock(&udc->lock);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ *
+ * VBUS detection, pullup handler, and Gadget cable state notification
+ *
+ */
+static void vbus_work(struct work_struct *work)
+{
+ u8 value;
+ struct lpc32xx_udc *udc = container_of(work, struct lpc32xx_udc,
+ vbus_job);
+
+ if (udc->enabled != 0) {
+ /* Discharge VBUS real quick */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DISCHRG);
+
+ /* Give VBUS some time (100mS) to discharge */
+ msleep(100);
+
+ /* Disable VBUS discharge resistor */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR,
+ OTG1_VBUS_DISCHRG);
+
+ /* Clear interrupt */
+ i2c_smbus_write_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_INTERRUPT_LATCH |
+ ISP1301_I2C_REG_CLEAR_ADDR, ~0);
+
+ /* Get the VBUS status from the transceiver */
+ value = i2c_smbus_read_byte_data(udc->isp1301_i2c_client,
+ ISP1301_I2C_OTG_CONTROL_2);
+
+ /* VBUS on or off? */
+ if (value & OTG_B_SESS_VLD)
+ udc->vbus = 1;
+ else
+ udc->vbus = 0;
+
+ /* VBUS changed? */
+ if (udc->last_vbus != udc->vbus) {
+ udc->last_vbus = udc->vbus;
+ lpc32xx_vbus_session(&udc->gadget, udc->vbus);
+ }
+ }
+
+ /* Re-enable after completion */
+ enable_irq(udc->udp_irq[IRQ_USB_ATX]);
+}
+
+static irqreturn_t lpc32xx_usb_vbus_irq(int irq, void *_udc)
+{
+ struct lpc32xx_udc *udc = _udc;
+
+ /* Defer handling of VBUS IRQ to work queue */
+ disable_irq_nosync(udc->udp_irq[IRQ_USB_ATX]);
+ schedule_work(&udc->vbus_job);
+
+ return IRQ_HANDLED;
+}
+
+static int lpc32xx_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *))
+{
+ struct lpc32xx_udc *udc = &controller;
+ int retval, i;
+
+ if (!driver || driver->max_speed < USB_SPEED_FULL ||
+ !bind || !driver->setup) {
+ dev_err(udc->dev, "bad parameter.\n");
+ return -EINVAL;
+ }
+
+ if (udc->driver) {
+ dev_err(udc->dev, "UDC already has a gadget driver\n");
+ return -EBUSY;
+ }
+
+ udc->driver = driver;
+ udc->gadget.dev.driver = &driver->driver;
+ udc->enabled = 1;
+ udc->selfpowered = 1;
+ udc->vbus = 0;
+
+ retval = bind(&udc->gadget);
+ if (retval) {
+ dev_err(udc->dev, "bind() returned %d\n", retval);
+ udc->enabled = 0;
+ udc->selfpowered = 0;
+ udc->driver = NULL;
+ udc->gadget.dev.driver = NULL;
+ return retval;
+ }
+
+ dev_dbg(udc->dev, "bound to %s\n", driver->driver.name);
+
+ /* Force VBUS process once to check for cable insertion */
+ udc->last_vbus = udc->vbus = 0;
+ schedule_work(&udc->vbus_job);
+
+ /* Do not re-enable ATX IRQ (3) */
+ for (i = IRQ_USB_LP; i < IRQ_USB_ATX; i++)
+ enable_irq(udc->udp_irq[i]);
+
+ return 0;
+}
+
+static int lpc32xx_stop(struct usb_gadget_driver *driver)
+{
+ int i;
+ struct lpc32xx_udc *udc = &controller;
+
+ if (!driver || driver != udc->driver || !driver->unbind)
+ return -EINVAL;
+
+ /* Disable USB pullup */
+ isp1301_pullup_enable(udc, 0, 1);
+
+ for (i = IRQ_USB_LP; i <= IRQ_USB_ATX; i++)
+ disable_irq(udc->udp_irq[i]);
+
+ if (udc->clocked) {
+
+ spin_lock(&udc->lock);
+ stop_activity(udc);
+ spin_unlock(&udc->lock);
+
+ /*
+ * Wait for all the endpoints to disable,
+ * before disabling clocks. Don't wait if
+ * endpoints are not enabled.
+ */
+ if (atomic_read(&udc->enabled_ep_cnt))
+ wait_event_interruptible(udc->ep_disable_wait_queue,
+ (atomic_read(&udc->enabled_ep_cnt) == 0));
+
+ spin_lock(&udc->lock);
+ udc_clk_set(udc, 0);
+ spin_unlock(&udc->lock);
+ }
+
+ udc->enabled = 0;
+ pullup(udc, 0);
+
+ driver->unbind(&udc->gadget);
+ udc->gadget.dev.driver = NULL;
+ udc->driver = NULL;
+
+ dev_dbg(udc->dev, "unbound from %s\n", driver->driver.name);
+ return 0;
+}
+
+static void lpc32xx_udc_shutdown(struct platform_device *dev)
+{
+ /* Force disconnect on reboot */
+ struct lpc32xx_udc *udc = &controller;
+
+ pullup(udc, 0);
+}
+
+/*
+ * Callbacks to be overridden by options passed via OF (TODO)
+ */
+
+static void lpc32xx_usbd_conn_chg(int conn)
+{
+ /* Do nothing, it might be nice to enable an LED
+ * based on conn state being !0 */
+}
+
+static void lpc32xx_usbd_susp_chg(int susp)
+{
+ /* Device suspend if susp != 0 */
+}
+
+static void lpc32xx_rmwkup_chg(int remote_wakup_enable)
+{
+ /* Enable or disable USB remote wakeup */
+}
+
+struct lpc32xx_usbd_cfg lpc32xx_usbddata = {
+ .vbus_drv_pol = 0,
+ .conn_chgb = &lpc32xx_usbd_conn_chg,
+ .susp_chgb = &lpc32xx_usbd_susp_chg,
+ .rmwk_chgb = &lpc32xx_rmwkup_chg,
+};
+
+
+static u64 lpc32xx_usbd_dmamask = ~(u32) 0x7F;
+
+static int __init lpc32xx_udc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct lpc32xx_udc *udc = &controller;
+ int retval, i;
+ struct resource *res;
+ dma_addr_t dma_handle;
+ struct device_node *isp1301_node;
+
+ /* init software state */
+ udc->gadget.dev.parent = dev;
+ udc->pdev = pdev;
+ udc->dev = &pdev->dev;
+ udc->enabled = 0;
+
+ if (pdev->dev.of_node) {
+ isp1301_node = of_parse_phandle(pdev->dev.of_node,
+ "transceiver", 0);
+ } else {
+ isp1301_node = NULL;
+ }
+
+ udc->isp1301_i2c_client = isp1301_get_client(isp1301_node);
+ if (!udc->isp1301_i2c_client)
+ return -EPROBE_DEFER;
+
+ dev_info(udc->dev, "ISP1301 I2C device at address 0x%x\n",
+ udc->isp1301_i2c_client->addr);
+
+ pdev->dev.dma_mask = &lpc32xx_usbd_dmamask;
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+ udc->board = &lpc32xx_usbddata;
+
+ /*
+ * Resources are mapped as follows:
+ * IORESOURCE_MEM, base address and size of USB space
+ * IORESOURCE_IRQ, USB device low priority interrupt number
+ * IORESOURCE_IRQ, USB device high priority interrupt number
+ * IORESOURCE_IRQ, USB device interrupt number
+ * IORESOURCE_IRQ, USB transceiver interrupt number
+ */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENXIO;
+
+ spin_lock_init(&udc->lock);
+
+ /* Get IRQs */
+ for (i = 0; i < 4; i++) {
+ udc->udp_irq[i] = platform_get_irq(pdev, i);
+ if (udc->udp_irq[i] < 0) {
+ dev_err(udc->dev,
+ "irq resource %d not available!\n", i);
+ return udc->udp_irq[i];
+ }
+ }
+
+ udc->io_p_start = res->start;
+ udc->io_p_size = resource_size(res);
+ if (!request_mem_region(udc->io_p_start, udc->io_p_size, driver_name)) {
+ dev_err(udc->dev, "someone's using UDC memory\n");
+ return -EBUSY;
+ }
+
+ udc->udp_baseaddr = ioremap(udc->io_p_start, udc->io_p_size);
+ if (!udc->udp_baseaddr) {
+ retval = -ENOMEM;
+ dev_err(udc->dev, "IO map failure\n");
+ goto io_map_fail;
+ }
+
+ /* Enable AHB slave USB clock, needed for further USB clock control */
+ writel(USB_SLAVE_HCLK_EN | (1 << 19), USB_CTRL);
+
+ /* Get required clocks */
+ udc->usb_pll_clk = clk_get(&pdev->dev, "ck_pll5");
+ if (IS_ERR(udc->usb_pll_clk)) {
+ dev_err(udc->dev, "failed to acquire USB PLL\n");
+ retval = PTR_ERR(udc->usb_pll_clk);
+ goto pll_get_fail;
+ }
+ udc->usb_slv_clk = clk_get(&pdev->dev, "ck_usbd");
+ if (IS_ERR(udc->usb_slv_clk)) {
+ dev_err(udc->dev, "failed to acquire USB device clock\n");
+ retval = PTR_ERR(udc->usb_slv_clk);
+ goto usb_clk_get_fail;
+ }
+
+ /* Setup PLL clock to 48MHz */
+ retval = clk_enable(udc->usb_pll_clk);
+ if (retval < 0) {
+ dev_err(udc->dev, "failed to start USB PLL\n");
+ goto pll_enable_fail;
+ }
+
+ retval = clk_set_rate(udc->usb_pll_clk, 48000);
+ if (retval < 0) {
+ dev_err(udc->dev, "failed to set USB clock rate\n");
+ goto pll_set_fail;
+ }
+
+ writel(readl(USB_CTRL) | USB_DEV_NEED_CLK_EN, USB_CTRL);
+
+ /* Enable USB device clock */
+ retval = clk_enable(udc->usb_slv_clk);
+ if (retval < 0) {
+ dev_err(udc->dev, "failed to start USB device clock\n");
+ goto usb_clk_enable_fail;
+ }
+
+ /* Set to enable all needed USB OTG clocks */
+ writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL(udc));
+
+ i = 1000;
+ while (((readl(USB_OTG_CLK_STAT(udc)) & USB_CLOCK_MASK) !=
+ USB_CLOCK_MASK) && (i > 0))
+ i--;
+ if (!i)
+ dev_dbg(udc->dev, "USB OTG clocks not correctly enabled\n");
+
+ /* Setup deferred workqueue data */
+ udc->poweron = udc->pullup = 0;
+ INIT_WORK(&udc->pullup_job, pullup_work);
+ INIT_WORK(&udc->vbus_job, vbus_work);
+#ifdef CONFIG_PM
+ INIT_WORK(&udc->power_job, power_work);
+#endif
+
+ /* All clocks are now on */
+ udc->clocked = 1;
+
+ isp1301_udc_configure(udc);
+ /* Allocate memory for the UDCA */
+ udc->udca_v_base = dma_alloc_coherent(&pdev->dev, UDCA_BUFF_SIZE,
+ &dma_handle,
+ (GFP_KERNEL | GFP_DMA));
+ if (!udc->udca_v_base) {
+ dev_err(udc->dev, "error getting UDCA region\n");
+ retval = -ENOMEM;
+ goto i2c_fail;
+ }
+ udc->udca_p_base = dma_handle;
+ dev_dbg(udc->dev, "DMA buffer(0x%x bytes), P:0x%08x, V:0x%p\n",
+ UDCA_BUFF_SIZE, udc->udca_p_base, udc->udca_v_base);
+
+ /* Setup the DD DMA memory pool */
+ udc->dd_cache = dma_pool_create("udc_dd", udc->dev,
+ sizeof(struct lpc32xx_usbd_dd_gad),
+ sizeof(u32), 0);
+ if (!udc->dd_cache) {
+ dev_err(udc->dev, "error getting DD DMA region\n");
+ retval = -ENOMEM;
+ goto dma_alloc_fail;
+ }
+
+ /* Clear USB peripheral and initialize gadget endpoints */
+ udc_disable(udc);
+ udc_reinit(udc);
+
+ retval = device_register(&udc->gadget.dev);
+ if (retval < 0) {
+ dev_err(udc->dev, "Device registration failure\n");
+ goto dev_register_fail;
+ }
+
+ /* Request IRQs - low and high priority USB device IRQs are routed to
+ * the same handler, while the DMA interrupt is routed elsewhere */
+ retval = request_irq(udc->udp_irq[IRQ_USB_LP], lpc32xx_usb_lp_irq,
+ 0, "udc_lp", udc);
+ if (retval < 0) {
+ dev_err(udc->dev, "LP request irq %d failed\n",
+ udc->udp_irq[IRQ_USB_LP]);
+ goto irq_lp_fail;
+ }
+ retval = request_irq(udc->udp_irq[IRQ_USB_HP], lpc32xx_usb_hp_irq,
+ 0, "udc_hp", udc);
+ if (retval < 0) {
+ dev_err(udc->dev, "HP request irq %d failed\n",
+ udc->udp_irq[IRQ_USB_HP]);
+ goto irq_hp_fail;
+ }
+
+ retval = request_irq(udc->udp_irq[IRQ_USB_DEVDMA],
+ lpc32xx_usb_devdma_irq, 0, "udc_dma", udc);
+ if (retval < 0) {
+ dev_err(udc->dev, "DEV request irq %d failed\n",
+ udc->udp_irq[IRQ_USB_DEVDMA]);
+ goto irq_dev_fail;
+ }
+
+ /* The transceiver interrupt is used for VBUS detection and will
+ kick off the VBUS handler function */
+ retval = request_irq(udc->udp_irq[IRQ_USB_ATX], lpc32xx_usb_vbus_irq,
+ 0, "udc_otg", udc);
+ if (retval < 0) {
+ dev_err(udc->dev, "VBUS request irq %d failed\n",
+ udc->udp_irq[IRQ_USB_ATX]);
+ goto irq_xcvr_fail;
+ }
+
+ /* Initialize wait queue */
+ init_waitqueue_head(&udc->ep_disable_wait_queue);
+ atomic_set(&udc->enabled_ep_cnt, 0);
+
+ /* Keep all IRQs disabled until GadgetFS starts up */
+ for (i = IRQ_USB_LP; i <= IRQ_USB_ATX; i++)
+ disable_irq(udc->udp_irq[i]);
+
+ retval = usb_add_gadget_udc(dev, &udc->gadget);
+ if (retval < 0)
+ goto add_gadget_fail;
+
+ dev_set_drvdata(dev, udc);
+ device_init_wakeup(dev, 1);
+ create_debug_file(udc);
+
+ /* Disable clocks for now */
+ udc_clk_set(udc, 0);
+
+ dev_info(udc->dev, "%s version %s\n", driver_name, DRIVER_VERSION);
+ return 0;
+
+add_gadget_fail:
+ free_irq(udc->udp_irq[IRQ_USB_ATX], udc);
+irq_xcvr_fail:
+ free_irq(udc->udp_irq[IRQ_USB_DEVDMA], udc);
+irq_dev_fail:
+ free_irq(udc->udp_irq[IRQ_USB_HP], udc);
+irq_hp_fail:
+ free_irq(udc->udp_irq[IRQ_USB_LP], udc);
+irq_lp_fail:
+ device_unregister(&udc->gadget.dev);
+dev_register_fail:
+ dma_pool_destroy(udc->dd_cache);
+dma_alloc_fail:
+ dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE,
+ udc->udca_v_base, udc->udca_p_base);
+i2c_fail:
+ clk_disable(udc->usb_slv_clk);
+usb_clk_enable_fail:
+pll_set_fail:
+ clk_disable(udc->usb_pll_clk);
+pll_enable_fail:
+ clk_put(udc->usb_slv_clk);
+usb_clk_get_fail:
+ clk_put(udc->usb_pll_clk);
+pll_get_fail:
+ iounmap(udc->udp_baseaddr);
+io_map_fail:
+ release_mem_region(udc->io_p_start, udc->io_p_size);
+ dev_err(udc->dev, "%s probe failed, %d\n", driver_name, retval);
+
+ return retval;
+}
+
+static int __devexit lpc32xx_udc_remove(struct platform_device *pdev)
+{
+ struct lpc32xx_udc *udc = platform_get_drvdata(pdev);
+
+ usb_del_gadget_udc(&udc->gadget);
+ if (udc->driver)
+ return -EBUSY;
+
+ udc_clk_set(udc, 1);
+ udc_disable(udc);
+ pullup(udc, 0);
+
+ free_irq(udc->udp_irq[IRQ_USB_ATX], udc);
+
+ device_init_wakeup(&pdev->dev, 0);
+ remove_debug_file(udc);
+
+ dma_pool_destroy(udc->dd_cache);
+ dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE,
+ udc->udca_v_base, udc->udca_p_base);
+ free_irq(udc->udp_irq[IRQ_USB_DEVDMA], udc);
+ free_irq(udc->udp_irq[IRQ_USB_HP], udc);
+ free_irq(udc->udp_irq[IRQ_USB_LP], udc);
+
+ device_unregister(&udc->gadget.dev);
+
+ clk_disable(udc->usb_slv_clk);
+ clk_put(udc->usb_slv_clk);
+ clk_disable(udc->usb_pll_clk);
+ clk_put(udc->usb_pll_clk);
+ iounmap(udc->udp_baseaddr);
+ release_mem_region(udc->io_p_start, udc->io_p_size);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int lpc32xx_udc_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ int to = 1000;
+ struct lpc32xx_udc *udc = platform_get_drvdata(pdev);
+
+ if (udc->clocked) {
+ /* Power down ISP */
+ udc->poweron = 0;
+ isp1301_set_powerstate(udc, 0);
+
+ /* Disable clocking */
+ udc_clk_set(udc, 0);
+
+ /* Keep clock flag on, so we know to re-enable clocks
+ on resume */
+ udc->clocked = 1;
+
+ /* Kill OTG and I2C clocks */
+ writel(0, USB_OTG_CLK_CTRL(udc));
+ while (((readl(USB_OTG_CLK_STAT(udc)) & OTGOFF_CLK_MASK) !=
+ OTGOFF_CLK_MASK) && (to > 0))
+ to--;
+ if (!to)
+ dev_dbg(udc->dev,
+ "USB OTG clocks not correctly enabled\n");
+
+ /* Kill global USB clock */
+ clk_disable(udc->usb_slv_clk);
+ }
+
+ return 0;
+}
+
+static int lpc32xx_udc_resume(struct platform_device *pdev)
+{
+ struct lpc32xx_udc *udc = platform_get_drvdata(pdev);
+
+ if (udc->clocked) {
+ /* Enable global USB clock */
+ clk_enable(udc->usb_slv_clk);
+
+ /* Enable clocking */
+ udc_clk_set(udc, 1);
+
+ /* ISP back to normal power mode */
+ udc->poweron = 1;
+ isp1301_set_powerstate(udc, 1);
+ }
+
+ return 0;
+}
+#else
+#define lpc32xx_udc_suspend NULL
+#define lpc32xx_udc_resume NULL
+#endif
+
+#ifdef CONFIG_OF
+static struct of_device_id lpc32xx_udc_of_match[] = {
+ { .compatible = "nxp,lpc3220-udc", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, lpc32xx_udc_of_match);
+#endif
+
+static struct platform_driver lpc32xx_udc_driver = {
+ .remove = __devexit_p(lpc32xx_udc_remove),
+ .shutdown = lpc32xx_udc_shutdown,
+ .suspend = lpc32xx_udc_suspend,
+ .resume = lpc32xx_udc_resume,
+ .driver = {
+ .name = (char *) driver_name,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(lpc32xx_udc_of_match),
+ },
+};
+
+static int __init udc_init_module(void)
+{
+ return platform_driver_probe(&lpc32xx_udc_driver, lpc32xx_udc_probe);
+}
+module_init(udc_init_module);
+
+static void __exit udc_exit_module(void)
+{
+ platform_driver_unregister(&lpc32xx_udc_driver);
+}
+module_exit(udc_exit_module);
+
+MODULE_DESCRIPTION("LPC32XX udc driver");
+MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>");
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:lpc32xx_udc");
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index 3608b3bd5732..8981fbb5748c 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -390,7 +390,7 @@ static int alloc_pipe_config(struct m66592_ep *ep,
int *counter;
int ret;
- ep->desc = desc;
+ ep->ep.desc = desc;
BUG_ON(ep->pipenum);
@@ -558,7 +558,7 @@ static void start_packet_read(struct m66592_ep *ep, struct m66592_request *req)
static void start_packet(struct m66592_ep *ep, struct m66592_request *req)
{
- if (ep->desc->bEndpointAddress & USB_DIR_IN)
+ if (ep->ep.desc->bEndpointAddress & USB_DIR_IN)
start_packet_write(ep, req);
else
start_packet_read(ep, req);
@@ -734,7 +734,7 @@ __acquires(m66592->lock)
if (restart) {
req = list_entry(ep->queue.next, struct m66592_request, queue);
- if (ep->desc)
+ if (ep->ep.desc)
start_packet(ep, req);
}
}
@@ -917,7 +917,7 @@ static void irq_pipe_ready(struct m66592 *m66592, u16 status, u16 enb)
ep = m66592->pipenum2ep[pipenum];
req = list_entry(ep->queue.next,
struct m66592_request, queue);
- if (ep->desc->bEndpointAddress & USB_DIR_IN)
+ if (ep->ep.desc->bEndpointAddress & USB_DIR_IN)
irq_packet_write(ep, req);
else
irq_packet_read(ep, req);
@@ -1377,7 +1377,7 @@ static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req,
req->req.actual = 0;
req->req.status = -EINPROGRESS;
- if (ep->desc == NULL) /* control */
+ if (ep->ep.desc == NULL) /* control */
start_ep0(ep, req);
else {
if (request && !ep->busy)
diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h
index 9d9f7e39f037..88c85b4116a2 100644
--- a/drivers/usb/gadget/m66592-udc.h
+++ b/drivers/usb/gadget/m66592-udc.h
@@ -456,7 +456,7 @@ struct m66592_ep {
unsigned use_dma:1;
u16 pipenum;
u16 type;
- const struct usb_endpoint_descriptor *desc;
+
/* register address */
unsigned long fifoaddr;
unsigned long fifosel;
diff --git a/drivers/usb/gadget/mv_udc.h b/drivers/usb/gadget/mv_udc.h
index e2be9519abbe..9073436d8b24 100644
--- a/drivers/usb/gadget/mv_udc.h
+++ b/drivers/usb/gadget/mv_udc.h
@@ -232,7 +232,6 @@ struct mv_ep {
struct mv_udc *udc;
struct list_head queue;
struct mv_dqh *dqh;
- const struct usb_endpoint_descriptor *desc;
u32 direction;
char name[14];
unsigned stopped:1,
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index a73cf406e2a4..dbcd1329495e 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -464,7 +464,7 @@ static int mv_ep_enable(struct usb_ep *_ep,
ep = container_of(_ep, struct mv_ep, ep);
udc = ep->udc;
- if (!_ep || !desc || ep->desc
+ if (!_ep || !desc || ep->ep.desc
|| desc->bDescriptorType != USB_DT_ENDPOINT)
return -EINVAL;
@@ -528,7 +528,7 @@ static int mv_ep_enable(struct usb_ep *_ep,
dqh->size_ioc_int_sts = 0;
ep->ep.maxpacket = max;
- ep->desc = desc;
+ ep->ep.desc = desc;
ep->stopped = 0;
/* Enable the endpoint for Rx or Tx and set the endpoint type */
@@ -580,7 +580,7 @@ static int mv_ep_disable(struct usb_ep *_ep)
unsigned long flags;
ep = container_of(_ep, struct mv_ep, ep);
- if ((_ep == NULL) || !ep->desc)
+ if ((_ep == NULL) || !ep->ep.desc)
return -EINVAL;
udc = ep->udc;
@@ -606,7 +606,6 @@ static int mv_ep_disable(struct usb_ep *_ep)
/* nuke all pending requests (does flush) */
nuke(ep, -ESHUTDOWN);
- ep->desc = NULL;
ep->ep.desc = NULL;
ep->stopped = 1;
@@ -651,7 +650,7 @@ static void mv_ep_fifo_flush(struct usb_ep *_ep)
return;
ep = container_of(_ep, struct mv_ep, ep);
- if (!ep->desc)
+ if (!ep->ep.desc)
return;
udc = ep->udc;
@@ -715,11 +714,11 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
dev_err(&udc->dev->dev, "%s, bad params", __func__);
return -EINVAL;
}
- if (unlikely(!_ep || !ep->desc)) {
+ if (unlikely(!_ep || !ep->ep.desc)) {
dev_err(&udc->dev->dev, "%s, bad ep", __func__);
return -EINVAL;
}
- if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+ if (ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
if (req->req.length > ep->ep.maxpacket)
return -EMSGSIZE;
}
@@ -925,12 +924,12 @@ static int mv_ep_set_halt_wedge(struct usb_ep *_ep, int halt, int wedge)
ep = container_of(_ep, struct mv_ep, ep);
udc = ep->udc;
- if (!_ep || !ep->desc) {
+ if (!_ep || !ep->ep.desc) {
status = -EINVAL;
goto out;
}
- if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+ if (ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
status = -EOPNOTSUPP;
goto out;
}
@@ -1279,7 +1278,7 @@ static int eps_init(struct mv_udc *udc)
ep->stopped = 0;
ep->ep.maxpacket = EP0_MAX_PKT_SIZE;
ep->ep_num = 0;
- ep->desc = &mv_ep0_desc;
+ ep->ep.desc = &mv_ep0_desc;
INIT_LIST_HEAD(&ep->queue);
ep->ep_type = USB_ENDPOINT_XFER_CONTROL;
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 3b4b6dd0f95a..7ba32469c5bd 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -153,7 +153,7 @@ static int omap_ep_enable(struct usb_ep *_ep,
u16 maxp;
/* catch various bogus parameters */
- if (!_ep || !desc || ep->desc
+ if (!_ep || !desc || ep->ep.desc
|| desc->bDescriptorType != USB_DT_ENDPOINT
|| ep->bEndpointAddress != desc->bEndpointAddress
|| ep->maxpacket < usb_endpoint_maxp(desc)) {
@@ -200,7 +200,7 @@ static int omap_ep_enable(struct usb_ep *_ep,
spin_lock_irqsave(&udc->lock, flags);
- ep->desc = desc;
+ ep->ep.desc = desc;
ep->irqs = 0;
ep->stopped = 0;
ep->ep.maxpacket = maxp;
@@ -242,14 +242,13 @@ static int omap_ep_disable(struct usb_ep *_ep)
struct omap_ep *ep = container_of(_ep, struct omap_ep, ep);
unsigned long flags;
- if (!_ep || !ep->desc) {
+ if (!_ep || !ep->ep.desc) {
DBG("%s, %s not enabled\n", __func__,
_ep ? ep->ep.name : NULL);
return -EINVAL;
}
spin_lock_irqsave(&ep->udc->lock, flags);
- ep->desc = NULL;
ep->ep.desc = NULL;
nuke (ep, -ESHUTDOWN);
ep->ep.maxpacket = ep->maxpacket;
@@ -917,7 +916,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
DBG("%s, bad params\n", __func__);
return -EINVAL;
}
- if (!_ep || (!ep->desc && ep->bEndpointAddress)) {
+ if (!_ep || (!ep->ep.desc && ep->bEndpointAddress)) {
DBG("%s, bad ep\n", __func__);
return -EINVAL;
}
@@ -1121,7 +1120,7 @@ static int omap_ep_set_halt(struct usb_ep *_ep, int value)
status = 0;
/* otherwise, all active non-ISO endpoints can halt */
- } else if (ep->bmAttributes != USB_ENDPOINT_XFER_ISOC && ep->desc) {
+ } else if (ep->bmAttributes != USB_ENDPOINT_XFER_ISOC && ep->ep.desc) {
/* IN endpoints must already be idle */
if ((ep->bEndpointAddress & USB_DIR_IN)
@@ -1625,7 +1624,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
if (w_index & USB_DIR_IN)
ep += 16;
if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
- || !ep->desc)
+ || !ep->ep.desc)
goto do_stall;
use_ep(ep, 0);
omap_writew(udc->clr_halt, UDC_CTRL);
@@ -1653,7 +1652,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
if (w_index & USB_DIR_IN)
ep += 16;
if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
- || ep == ep0 || !ep->desc)
+ || ep == ep0 || !ep->ep.desc)
goto do_stall;
if (use_dma && ep->has_dma) {
/* this has rude side-effects (aborts) and
@@ -1688,7 +1687,7 @@ ep0out_status_stage:
ep = &udc->ep[w_index & 0xf];
if (w_index & USB_DIR_IN)
ep += 16;
- if (!ep->desc)
+ if (!ep->ep.desc)
goto do_stall;
/* iso never stalls */
@@ -2509,7 +2508,7 @@ static int proc_udc_show(struct seq_file *s, void *_)
if (tmp & UDC_ADD) {
list_for_each_entry (ep, &udc->gadget.ep_list,
ep.ep_list) {
- if (ep->desc)
+ if (ep->ep.desc)
proc_ep_show(s, ep);
}
}
diff --git a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/omap_udc.h
index 59d3b2213cb1..cfadeb5fc5de 100644
--- a/drivers/usb/gadget/omap_udc.h
+++ b/drivers/usb/gadget/omap_udc.h
@@ -140,7 +140,6 @@ struct omap_ep {
struct list_head queue;
unsigned long irqs;
struct list_head iso;
- const struct usb_endpoint_descriptor *desc;
char name[14];
u16 maxpacket;
u8 bEndpointAddress;
diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
index 65307064a6fd..1cfcc9ecbfbc 100644
--- a/drivers/usb/gadget/pch_udc.c
+++ b/drivers/usb/gadget/pch_udc.c
@@ -295,7 +295,6 @@ struct pch_udc_ep {
struct pch_udc_data_dma_desc *td_data;
struct pch_udc_dev *dev;
unsigned long offset_addr;
- const struct usb_endpoint_descriptor *desc;
struct list_head queue;
unsigned num:5,
in:1,
@@ -1705,7 +1704,7 @@ static int pch_udc_pcd_ep_enable(struct usb_ep *usbep,
if (!dev->driver || (dev->gadget.speed == USB_SPEED_UNKNOWN))
return -ESHUTDOWN;
spin_lock_irqsave(&dev->lock, iflags);
- ep->desc = desc;
+ ep->ep.desc = desc;
ep->halted = 0;
pch_udc_ep_enable(ep, &ep->dev->cfg_data, desc);
ep->ep.maxpacket = usb_endpoint_maxp(desc);
@@ -1734,7 +1733,7 @@ static int pch_udc_pcd_ep_disable(struct usb_ep *usbep)
ep = container_of(usbep, struct pch_udc_ep, ep);
dev = ep->dev;
- if ((usbep->name == ep0_string) || !ep->desc)
+ if ((usbep->name == ep0_string) || !ep->ep.desc)
return -EINVAL;
spin_lock_irqsave(&ep->dev->lock, iflags);
@@ -1742,7 +1741,6 @@ static int pch_udc_pcd_ep_disable(struct usb_ep *usbep)
ep->halted = 1;
pch_udc_ep_disable(ep);
pch_udc_disable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num));
- ep->desc = NULL;
ep->ep.desc = NULL;
INIT_LIST_HEAD(&ep->queue);
spin_unlock_irqrestore(&ep->dev->lock, iflags);
@@ -1849,7 +1847,7 @@ static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq,
return -EINVAL;
ep = container_of(usbep, struct pch_udc_ep, ep);
dev = ep->dev;
- if (!ep->desc && ep->num)
+ if (!ep->ep.desc && ep->num)
return -EINVAL;
req = container_of(usbreq, struct pch_udc_request, req);
if (!list_empty(&req->queue))
@@ -1949,7 +1947,7 @@ static int pch_udc_pcd_dequeue(struct usb_ep *usbep,
ep = container_of(usbep, struct pch_udc_ep, ep);
dev = ep->dev;
- if (!usbep || !usbreq || (!ep->desc && ep->num))
+ if (!usbep || !usbreq || (!ep->ep.desc && ep->num))
return ret;
req = container_of(usbreq, struct pch_udc_request, req);
spin_lock_irqsave(&ep->dev->lock, flags);
@@ -1988,7 +1986,7 @@ static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt)
return -EINVAL;
ep = container_of(usbep, struct pch_udc_ep, ep);
dev = ep->dev;
- if (!ep->desc && !ep->num)
+ if (!ep->ep.desc && !ep->num)
return -EINVAL;
if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN))
return -ESHUTDOWN;
@@ -2033,7 +2031,7 @@ static int pch_udc_pcd_set_wedge(struct usb_ep *usbep)
return -EINVAL;
ep = container_of(usbep, struct pch_udc_ep, ep);
dev = ep->dev;
- if (!ep->desc && !ep->num)
+ if (!ep->ep.desc && !ep->num)
return -EINVAL;
if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN))
return -ESHUTDOWN;
@@ -2065,7 +2063,7 @@ static void pch_udc_pcd_fifo_flush(struct usb_ep *usbep)
return;
ep = container_of(usbep, struct pch_udc_ep, ep);
- if (ep->desc || !ep->num)
+ if (ep->ep.desc || !ep->num)
pch_udc_ep_fifo_flush(ep, ep->in);
}
@@ -3282,7 +3280,6 @@ static DEFINE_PCI_DEVICE_TABLE(pch_udc_pcidev_id) = {
MODULE_DEVICE_TABLE(pci, pch_udc_pcidev_id);
-
static struct pci_driver pch_udc_driver = {
.name = KBUILD_MODNAME,
.id_table = pch_udc_pcidev_id,
@@ -3293,17 +3290,7 @@ static struct pci_driver pch_udc_driver = {
.shutdown = pch_udc_shutdown,
};
-static int __init pch_udc_pci_init(void)
-{
- return pci_register_driver(&pch_udc_driver);
-}
-module_init(pch_udc_pci_init);
-
-static void __exit pch_udc_pci_exit(void)
-{
- pci_unregister_driver(&pch_udc_driver);
-}
-module_exit(pch_udc_pci_exit);
+module_pci_driver(pch_udc_driver);
MODULE_DESCRIPTION("Intel EG20T USB Device Controller");
MODULE_AUTHOR("LAPIS Semiconductor, <tomoya-linux@dsn.lapis-semi.com>");
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
index 4e4dc1f5f388..f1f9290a2f47 100644
--- a/drivers/usb/gadget/printer.c
+++ b/drivers/usb/gadget/printer.c
@@ -51,6 +51,7 @@
* the runtime footprint, and giving us at least some parts of what
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
*/
+#include "composite.c"
#include "usbstring.c"
#include "config.c"
#include "epautoconf.c"
@@ -75,8 +76,6 @@ struct printer_dev {
/* lock buffer lists during read/write calls */
struct mutex lock_printer_io;
struct usb_gadget *gadget;
- struct usb_request *req; /* for control responses */
- u8 config;
s8 interface;
struct usb_ep *in_ep, *out_ep;
@@ -100,6 +99,7 @@ struct printer_dev {
struct device *pdev;
u8 printer_cdev_open;
wait_queue_head_t wait;
+ struct usb_function function;
};
static struct printer_dev usb_printer_gadget;
@@ -120,26 +120,6 @@ static struct printer_dev usb_printer_gadget;
* parameters are in UTF-8 (superset of ASCII's 7 bit characters).
*/
-static ushort idVendor;
-module_param(idVendor, ushort, S_IRUGO);
-MODULE_PARM_DESC(idVendor, "USB Vendor ID");
-
-static ushort idProduct;
-module_param(idProduct, ushort, S_IRUGO);
-MODULE_PARM_DESC(idProduct, "USB Product ID");
-
-static ushort bcdDevice;
-module_param(bcdDevice, ushort, S_IRUGO);
-MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
-
-static char *iManufacturer;
-module_param(iManufacturer, charp, S_IRUGO);
-MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
-
-static char *iProduct;
-module_param(iProduct, charp, S_IRUGO);
-MODULE_PARM_DESC(iProduct, "USB Product string");
-
static char *iSerialNum;
module_param(iSerialNum, charp, S_IRUGO);
MODULE_PARM_DESC(iSerialNum, "1");
@@ -154,47 +134,8 @@ module_param(qlen, uint, S_IRUGO|S_IWUSR);
#define QLEN qlen
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-#define DEVSPEED USB_SPEED_HIGH
-#else /* full speed (low speed doesn't do bulk) */
-#define DEVSPEED USB_SPEED_FULL
-#endif
-
/*-------------------------------------------------------------------------*/
-#define xprintk(d, level, fmt, args...) \
- printk(level "%s: " fmt, DRIVER_DESC, ## args)
-
-#ifdef DEBUG
-#define DBG(dev, fmt, args...) \
- xprintk(dev, KERN_DEBUG, fmt, ## args)
-#else
-#define DBG(dev, fmt, args...) \
- do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE
-#define VDBG(dev, fmt, args...) \
- xprintk(dev, KERN_DEBUG, fmt, ## args)
-#else
-#define VDBG(dev, fmt, args...) \
- do { } while (0)
-#endif /* VERBOSE */
-
-#define ERROR(dev, fmt, args...) \
- xprintk(dev, KERN_ERR, fmt, ## args)
-#define WARNING(dev, fmt, args...) \
- xprintk(dev, KERN_WARNING, fmt, ## args)
-#define INFO(dev, fmt, args...) \
- xprintk(dev, KERN_INFO, fmt, ## args)
-
-/*-------------------------------------------------------------------------*/
-
-/* USB DRIVER HOOKUP (to the hardware driver, below us), mostly
- * ep0 implementation: descriptors, config management, setup().
- * also optional class-specific notification interrupt transfer.
- */
-
/*
* DESCRIPTORS ... most are static, but strings and (full) configuration
* descriptors are built on demand.
@@ -227,24 +168,6 @@ static struct usb_device_descriptor device_desc = {
.bNumConfigurations = 1
};
-static struct usb_otg_descriptor otg_desc = {
- .bLength = sizeof otg_desc,
- .bDescriptorType = USB_DT_OTG,
- .bmAttributes = USB_OTG_SRP
-};
-
-static struct usb_config_descriptor config_desc = {
- .bLength = sizeof config_desc,
- .bDescriptorType = USB_DT_CONFIG,
-
- /* compute wTotalLength on the fly */
- .bNumInterfaces = 1,
- .bConfigurationValue = DEV_CONFIG_VALUE,
- .iConfiguration = 0,
- .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
- .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2,
-};
-
static struct usb_interface_descriptor intf_desc = {
.bLength = sizeof intf_desc,
.bDescriptorType = USB_DT_INTERFACE,
@@ -270,16 +193,13 @@ static struct usb_endpoint_descriptor fs_ep_out_desc = {
.bmAttributes = USB_ENDPOINT_XFER_BULK
};
-static const struct usb_descriptor_header *fs_printer_function [11] = {
- (struct usb_descriptor_header *) &otg_desc,
+static struct usb_descriptor_header *fs_printer_function[] = {
(struct usb_descriptor_header *) &intf_desc,
(struct usb_descriptor_header *) &fs_ep_in_desc,
(struct usb_descriptor_header *) &fs_ep_out_desc,
NULL
};
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-
/*
* usb 2.0 devices need to expose both high speed and full speed
* descriptors, unless they only run at full speed.
@@ -307,23 +227,26 @@ static struct usb_qualifier_descriptor dev_qualifier = {
.bNumConfigurations = 1
};
-static const struct usb_descriptor_header *hs_printer_function [11] = {
- (struct usb_descriptor_header *) &otg_desc,
+static struct usb_descriptor_header *hs_printer_function[] = {
(struct usb_descriptor_header *) &intf_desc,
(struct usb_descriptor_header *) &hs_ep_in_desc,
(struct usb_descriptor_header *) &hs_ep_out_desc,
NULL
};
-/* maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g, hs, fs) (((g)->speed == USB_SPEED_HIGH)?(hs):(fs))
-
-#else
+static struct usb_otg_descriptor otg_descriptor = {
+ .bLength = sizeof otg_descriptor,
+ .bDescriptorType = USB_DT_OTG,
+ .bmAttributes = USB_OTG_SRP,
+};
-/* if there's no high speed support, maxpacket doesn't change. */
-#define ep_desc(g, hs, fs) (((void)(g)), (fs))
+static const struct usb_descriptor_header *otg_desc[] = {
+ (struct usb_descriptor_header *) &otg_descriptor,
+ NULL,
+};
-#endif /* !CONFIG_USB_GADGET_DUALSPEED */
+/* maxpacket and other transfer characteristics vary by speed. */
+#define ep_desc(g, hs, fs) (((g)->speed == USB_SPEED_HIGH)?(hs):(fs))
/*-------------------------------------------------------------------------*/
@@ -343,11 +266,16 @@ static struct usb_string strings [] = {
{ } /* end of list */
};
-static struct usb_gadget_strings stringtab = {
+static struct usb_gadget_strings stringtab_dev = {
.language = 0x0409, /* en-us */
.strings = strings,
};
+static struct usb_gadget_strings *dev_strings[] = {
+ &stringtab_dev,
+ NULL,
+};
+
/*-------------------------------------------------------------------------*/
static struct usb_request *
@@ -937,82 +865,8 @@ static void printer_reset_interface(struct printer_dev *dev)
dev->interface = -1;
}
-/* change our operational config. must agree with the code
- * that returns config descriptors, and altsetting code.
- */
-static int
-printer_set_config(struct printer_dev *dev, unsigned number)
-{
- int result = 0;
- struct usb_gadget *gadget = dev->gadget;
-
- switch (number) {
- case DEV_CONFIG_VALUE:
- result = 0;
- break;
- default:
- result = -EINVAL;
- /* FALL THROUGH */
- case 0:
- break;
- }
-
- if (result) {
- usb_gadget_vbus_draw(dev->gadget,
- dev->gadget->is_otg ? 8 : 100);
- } else {
- unsigned power;
-
- power = 2 * config_desc.bMaxPower;
- usb_gadget_vbus_draw(dev->gadget, power);
-
- dev->config = number;
- INFO(dev, "%s config #%d: %d mA, %s\n",
- usb_speed_string(gadget->speed),
- number, power, driver_desc);
- }
- return result;
-}
-
-static int
-config_buf(enum usb_device_speed speed, u8 *buf, u8 type, unsigned index,
- int is_otg)
-{
- int len;
- const struct usb_descriptor_header **function;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- int hs = (speed == USB_SPEED_HIGH);
-
- if (type == USB_DT_OTHER_SPEED_CONFIG)
- hs = !hs;
-
- if (hs) {
- function = hs_printer_function;
- } else {
- function = fs_printer_function;
- }
-#else
- function = fs_printer_function;
-#endif
-
- if (index >= device_desc.bNumConfigurations)
- return -EINVAL;
-
- /* for now, don't advertise srp-only devices */
- if (!is_otg)
- function++;
-
- len = usb_gadget_config_buf(&config_desc, buf, USB_DESC_BUFSIZE,
- function);
- if (len < 0)
- return len;
- ((struct usb_config_descriptor *) buf)->bDescriptorType = type;
- return len;
-}
-
/* Change our operational Interface. */
-static int
-set_interface(struct printer_dev *dev, unsigned number)
+static int set_interface(struct printer_dev *dev, unsigned number)
{
int result = 0;
@@ -1043,14 +897,6 @@ set_interface(struct printer_dev *dev, unsigned number)
return result;
}
-static void printer_setup_complete(struct usb_ep *ep, struct usb_request *req)
-{
- if (req->status || req->actual != req->length)
- DBG((struct printer_dev *) ep->driver_data,
- "setup complete --> %d, %d/%d\n",
- req->status, req->actual, req->length);
-}
-
static void printer_soft_reset(struct printer_dev *dev)
{
struct usb_request *req;
@@ -1107,11 +953,12 @@ static void printer_soft_reset(struct printer_dev *dev)
* The setup() callback implements all the ep0 functionality that's not
* handled lower down.
*/
-static int
-printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+static int printer_func_setup(struct usb_function *f,
+ const struct usb_ctrlrequest *ctrl)
{
- struct printer_dev *dev = get_gadget_data(gadget);
- struct usb_request *req = dev->req;
+ struct printer_dev *dev = container_of(f, struct printer_dev, function);
+ struct usb_composite_dev *cdev = f->config->cdev;
+ struct usb_request *req = cdev->req;
int value = -EOPNOTSUPP;
u16 wIndex = le16_to_cpu(ctrl->wIndex);
u16 wValue = le16_to_cpu(ctrl->wValue);
@@ -1120,102 +967,7 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
DBG(dev, "ctrl req%02x.%02x v%04x i%04x l%d\n",
ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength);
- req->complete = printer_setup_complete;
-
switch (ctrl->bRequestType&USB_TYPE_MASK) {
-
- case USB_TYPE_STANDARD:
- switch (ctrl->bRequest) {
-
- case USB_REQ_GET_DESCRIPTOR:
- if (ctrl->bRequestType != USB_DIR_IN)
- break;
- switch (wValue >> 8) {
-
- case USB_DT_DEVICE:
- device_desc.bMaxPacketSize0 =
- gadget->ep0->maxpacket;
- value = min(wLength, (u16) sizeof device_desc);
- memcpy(req->buf, &device_desc, value);
- break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- case USB_DT_DEVICE_QUALIFIER:
- if (!gadget_is_dualspeed(gadget))
- break;
- /*
- * assumes ep0 uses the same value for both
- * speeds
- */
- dev_qualifier.bMaxPacketSize0 =
- gadget->ep0->maxpacket;
- value = min(wLength,
- (u16) sizeof dev_qualifier);
- memcpy(req->buf, &dev_qualifier, value);
- break;
-
- case USB_DT_OTHER_SPEED_CONFIG:
- if (!gadget_is_dualspeed(gadget))
- break;
- /* FALLTHROUGH */
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
- case USB_DT_CONFIG:
- value = config_buf(gadget->speed, req->buf,
- wValue >> 8,
- wValue & 0xff,
- gadget->is_otg);
- if (value >= 0)
- value = min(wLength, (u16) value);
- break;
-
- case USB_DT_STRING:
- value = usb_gadget_get_string(&stringtab,
- wValue & 0xff, req->buf);
- if (value >= 0)
- value = min(wLength, (u16) value);
- break;
- }
- break;
-
- case USB_REQ_SET_CONFIGURATION:
- if (ctrl->bRequestType != 0)
- break;
- if (gadget->a_hnp_support)
- DBG(dev, "HNP available\n");
- else if (gadget->a_alt_hnp_support)
- DBG(dev, "HNP needs a different root port\n");
- value = printer_set_config(dev, wValue);
- if (!value)
- value = set_interface(dev, PRINTER_INTERFACE);
- break;
- case USB_REQ_GET_CONFIGURATION:
- if (ctrl->bRequestType != USB_DIR_IN)
- break;
- *(u8 *)req->buf = dev->config;
- value = min(wLength, (u16) 1);
- break;
-
- case USB_REQ_SET_INTERFACE:
- if (ctrl->bRequestType != USB_RECIP_INTERFACE ||
- !dev->config)
- break;
-
- value = set_interface(dev, PRINTER_INTERFACE);
- break;
- case USB_REQ_GET_INTERFACE:
- if (ctrl->bRequestType !=
- (USB_DIR_IN|USB_RECIP_INTERFACE)
- || !dev->config)
- break;
-
- *(u8 *)req->buf = dev->interface;
- value = min(wLength, (u16) 1);
- break;
-
- default:
- goto unknown;
- }
- break;
-
case USB_TYPE_CLASS:
switch (ctrl->bRequest) {
case 0: /* Get the IEEE-1284 PNP String */
@@ -1261,44 +1013,50 @@ unknown:
wValue, wIndex, wLength);
break;
}
-
- /* respond with data transfer before status phase? */
- if (value >= 0) {
- req->length = value;
- req->zero = value < wLength;
- value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
- if (value < 0) {
- DBG(dev, "ep_queue --> %d\n", value);
- req->status = 0;
- printer_setup_complete(gadget->ep0, req);
- }
- }
-
/* host either stalls (value < 0) or reports success */
return value;
}
-static void
-printer_disconnect(struct usb_gadget *gadget)
+static int __init printer_func_bind(struct usb_configuration *c,
+ struct usb_function *f)
{
- struct printer_dev *dev = get_gadget_data(gadget);
+ return 0;
+}
+
+static void printer_func_unbind(struct usb_configuration *c,
+ struct usb_function *f)
+{
+}
+
+static int printer_func_set_alt(struct usb_function *f,
+ unsigned intf, unsigned alt)
+{
+ struct printer_dev *dev = container_of(f, struct printer_dev, function);
+ int ret = -ENOTSUPP;
+
+ if (!alt)
+ ret = set_interface(dev, PRINTER_INTERFACE);
+ return ret;
+}
+
+static void printer_func_disable(struct usb_function *f)
+{
+ struct printer_dev *dev = container_of(f, struct printer_dev, function);
unsigned long flags;
DBG(dev, "%s\n", __func__);
spin_lock_irqsave(&dev->lock, flags);
-
printer_reset_interface(dev);
-
spin_unlock_irqrestore(&dev->lock, flags);
}
-static void
-printer_unbind(struct usb_gadget *gadget)
+static void printer_cfg_unbind(struct usb_configuration *c)
{
- struct printer_dev *dev = get_gadget_data(gadget);
+ struct printer_dev *dev;
struct usb_request *req;
+ dev = &usb_printer_gadget;
DBG(dev, "%s\n", __func__);
@@ -1336,18 +1094,18 @@ printer_unbind(struct usb_gadget *gadget)
list_del(&req->list);
printer_req_free(dev->out_ep, req);
}
-
- if (dev->req) {
- printer_req_free(gadget->ep0, dev->req);
- dev->req = NULL;
- }
-
- set_gadget_data(gadget, NULL);
}
-static int __init
-printer_bind(struct usb_gadget *gadget)
+static struct usb_configuration printer_cfg_driver = {
+ .label = "printer",
+ .unbind = printer_cfg_unbind,
+ .bConfigurationValue = 1,
+ .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+};
+
+static int __init printer_bind_config(struct usb_configuration *c)
{
+ struct usb_gadget *gadget = c->cdev->gadget;
struct printer_dev *dev;
struct usb_ep *in_ep, *out_ep;
int status = -ENOMEM;
@@ -1358,6 +1116,14 @@ printer_bind(struct usb_gadget *gadget)
dev = &usb_printer_gadget;
+ dev->function.name = shortname;
+ dev->function.descriptors = fs_printer_function;
+ dev->function.hs_descriptors = hs_printer_function;
+ dev->function.bind = printer_func_bind;
+ dev->function.setup = printer_func_setup;
+ dev->function.unbind = printer_func_unbind;
+ dev->function.set_alt = printer_func_set_alt;
+ dev->function.disable = printer_func_disable;
/* Setup the sysfs files for the printer gadget. */
dev->pdev = device_create(usb_gadget_class, NULL, g_printer_devno,
@@ -1393,29 +1159,6 @@ printer_bind(struct usb_gadget *gadget)
init_utsname()->sysname, init_utsname()->release,
gadget->name);
- device_desc.idVendor =
- cpu_to_le16(PRINTER_VENDOR_NUM);
- device_desc.idProduct =
- cpu_to_le16(PRINTER_PRODUCT_NUM);
-
- /* support optional vendor/distro customization */
- if (idVendor) {
- if (!idProduct) {
- dev_err(&gadget->dev, "idVendor needs idProduct!\n");
- return -ENODEV;
- }
- device_desc.idVendor = cpu_to_le16(idVendor);
- device_desc.idProduct = cpu_to_le16(idProduct);
- if (bcdDevice)
- device_desc.bcdDevice = cpu_to_le16(bcdDevice);
- }
-
- if (iManufacturer)
- strlcpy(manufacturer, iManufacturer, sizeof manufacturer);
-
- if (iProduct)
- strlcpy(product_desc, iProduct, sizeof product_desc);
-
if (iSerialNum)
strlcpy(serial_num, iSerialNum, sizeof serial_num);
@@ -1442,17 +1185,16 @@ autoconf_fail:
goto autoconf_fail;
out_ep->driver_data = out_ep; /* claim */
-#ifdef CONFIG_USB_GADGET_DUALSPEED
/* assumes that all endpoints are dual-speed */
hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
-#endif /* DUALSPEED */
usb_gadget_set_selfpowered(gadget);
if (gadget->is_otg) {
- otg_desc.bmAttributes |= USB_OTG_HNP,
- config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ otg_descriptor.bmAttributes |= USB_OTG_HNP;
+ printer_cfg_driver.descriptors = otg_desc;
+ printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
spin_lock_init(&dev->lock);
@@ -1466,7 +1208,6 @@ autoconf_fail:
init_waitqueue_head(&dev->tx_wait);
init_waitqueue_head(&dev->tx_flush_wait);
- dev->config = 0;
dev->interface = -1;
dev->printer_cdev_open = 0;
dev->printer_status = PRINTER_NOT_ERROR;
@@ -1477,14 +1218,6 @@ autoconf_fail:
dev->in_ep = in_ep;
dev->out_ep = out_ep;
- /* preallocate control message data and buffer */
- dev->req = printer_req_alloc(gadget->ep0, USB_DESC_BUFSIZE,
- GFP_KERNEL);
- if (!dev->req) {
- status = -ENOMEM;
- goto fail;
- }
-
for (i = 0; i < QLEN; i++) {
req = printer_req_alloc(dev->in_ep, USB_BUFSIZE, GFP_KERNEL);
if (!req) {
@@ -1513,45 +1246,37 @@ autoconf_fail:
list_add(&req->list, &dev->rx_reqs);
}
- dev->req->complete = printer_setup_complete;
-
/* finish hookup to lower layer ... */
dev->gadget = gadget;
- set_gadget_data(gadget, dev);
- gadget->ep0->driver_data = dev;
INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc);
INFO(dev, "using %s, OUT %s IN %s\n", gadget->name, out_ep->name,
in_ep->name);
-
return 0;
fail:
- printer_unbind(gadget);
+ printer_cfg_unbind(c);
return status;
}
-/*-------------------------------------------------------------------------*/
+static int printer_unbind(struct usb_composite_dev *cdev)
+{
+ return 0;
+}
-static struct usb_gadget_driver printer_driver = {
- .max_speed = DEVSPEED,
+static int __init printer_bind(struct usb_composite_dev *cdev)
+{
+ return usb_add_config(cdev, &printer_cfg_driver, printer_bind_config);
+}
- .function = (char *) driver_desc,
+static struct usb_composite_driver printer_driver = {
+ .name = shortname,
+ .dev = &device_desc,
+ .strings = dev_strings,
+ .max_speed = USB_SPEED_HIGH,
.unbind = printer_unbind,
-
- .setup = printer_setup,
- .disconnect = printer_disconnect,
-
- .driver = {
- .name = (char *) shortname,
- .owner = THIS_MODULE,
- },
};
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR("Craig Nadler");
-MODULE_LICENSE("GPL");
-
static int __init
init(void)
{
@@ -1560,23 +1285,23 @@ init(void)
usb_gadget_class = class_create(THIS_MODULE, "usb_printer_gadget");
if (IS_ERR(usb_gadget_class)) {
status = PTR_ERR(usb_gadget_class);
- ERROR(dev, "unable to create usb_gadget class %d\n", status);
+ pr_err("unable to create usb_gadget class %d\n", status);
return status;
}
status = alloc_chrdev_region(&g_printer_devno, 0, 1,
"USB printer gadget");
if (status) {
- ERROR(dev, "alloc_chrdev_region %d\n", status);
+ pr_err("alloc_chrdev_region %d\n", status);
class_destroy(usb_gadget_class);
return status;
}
- status = usb_gadget_probe_driver(&printer_driver, printer_bind);
+ status = usb_composite_probe(&printer_driver, printer_bind);
if (status) {
class_destroy(usb_gadget_class);
unregister_chrdev_region(g_printer_devno, 1);
- DBG(dev, "usb_gadget_probe_driver %x\n", status);
+ pr_err("usb_gadget_probe_driver %x\n", status);
}
return status;
@@ -1586,15 +1311,14 @@ module_init(init);
static void __exit
cleanup(void)
{
- int status;
-
mutex_lock(&usb_printer_gadget.lock_printer_io);
- status = usb_gadget_unregister_driver(&printer_driver);
- if (status)
- ERROR(dev, "usb_gadget_unregister_driver %x\n", status);
-
+ usb_composite_unregister(&printer_driver);
unregister_chrdev_region(g_printer_devno, 1);
class_destroy(usb_gadget_class);
mutex_unlock(&usb_printer_gadget.lock_printer_io);
}
module_exit(cleanup);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Craig Nadler");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index 41ed69c96d8c..d7c8cb3bf759 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -218,7 +218,7 @@ static int pxa25x_ep_enable (struct usb_ep *_ep,
struct pxa25x_udc *dev;
ep = container_of (_ep, struct pxa25x_ep, ep);
- if (!_ep || !desc || ep->desc || _ep->name == ep0name
+ if (!_ep || !desc || ep->ep.desc || _ep->name == ep0name
|| desc->bDescriptorType != USB_DT_ENDPOINT
|| ep->bEndpointAddress != desc->bEndpointAddress
|| ep->fifo_size < usb_endpoint_maxp (desc)) {
@@ -249,7 +249,7 @@ static int pxa25x_ep_enable (struct usb_ep *_ep,
return -ESHUTDOWN;
}
- ep->desc = desc;
+ ep->ep.desc = desc;
ep->stopped = 0;
ep->pio_irqs = 0;
ep->ep.maxpacket = usb_endpoint_maxp (desc);
@@ -269,7 +269,7 @@ static int pxa25x_ep_disable (struct usb_ep *_ep)
unsigned long flags;
ep = container_of (_ep, struct pxa25x_ep, ep);
- if (!_ep || !ep->desc) {
+ if (!_ep || !ep->ep.desc) {
DMSG("%s, %s not enabled\n", __func__,
_ep ? ep->ep.name : NULL);
return -EINVAL;
@@ -281,7 +281,6 @@ static int pxa25x_ep_disable (struct usb_ep *_ep)
/* flush fifo (mostly for IN buffers) */
pxa25x_ep_fifo_flush (_ep);
- ep->desc = NULL;
ep->ep.desc = NULL;
ep->stopped = 1;
@@ -390,7 +389,7 @@ write_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req)
{
unsigned max;
- max = usb_endpoint_maxp(ep->desc);
+ max = usb_endpoint_maxp(ep->ep.desc);
do {
unsigned count;
int is_last, is_short;
@@ -644,7 +643,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
}
ep = container_of(_ep, struct pxa25x_ep, ep);
- if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+ if (unlikely(!_ep || (!ep->ep.desc && ep->ep.name != ep0name))) {
DMSG("%s, bad ep\n", __func__);
return -EINVAL;
}
@@ -660,7 +659,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
* we can report per-packet status. that also helps with dma.
*/
if (unlikely (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
- && req->req.length > usb_endpoint_maxp (ep->desc)))
+ && req->req.length > usb_endpoint_maxp(ep->ep.desc)))
return -EMSGSIZE;
DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n",
@@ -673,7 +672,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
/* kickstart this i/o queue? */
if (list_empty(&ep->queue) && !ep->stopped) {
- if (ep->desc == NULL/* ep0 */) {
+ if (ep->ep.desc == NULL/* ep0 */) {
unsigned length = _req->length;
switch (dev->ep0state) {
@@ -722,7 +721,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
req = NULL;
}
- if (likely (req && ep->desc))
+ if (likely(req && ep->ep.desc))
pio_irq_enable(ep->bEndpointAddress);
}
@@ -749,7 +748,7 @@ static void nuke(struct pxa25x_ep *ep, int status)
queue);
done(ep, req, status);
}
- if (ep->desc)
+ if (ep->ep.desc)
pio_irq_disable (ep->bEndpointAddress);
}
@@ -792,7 +791,7 @@ static int pxa25x_ep_set_halt(struct usb_ep *_ep, int value)
ep = container_of(_ep, struct pxa25x_ep, ep);
if (unlikely (!_ep
- || (!ep->desc && ep->ep.name != ep0name))
+ || (!ep->ep.desc && ep->ep.name != ep0name))
|| ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
DMSG("%s, bad ep\n", __func__);
return -EINVAL;
@@ -820,7 +819,7 @@ static int pxa25x_ep_set_halt(struct usb_ep *_ep, int value)
*ep->reg_udccs = UDCCS_BI_FST|UDCCS_BI_FTF;
/* ep0 needs special care */
- if (!ep->desc) {
+ if (!ep->ep.desc) {
start_watchdog(ep->dev);
ep->dev->req_pending = 0;
ep->dev->ep0state = EP0_STALL;
@@ -1087,7 +1086,7 @@ udc_seq_show(struct seq_file *m, void *_d)
if (i != 0) {
const struct usb_endpoint_descriptor *desc;
- desc = ep->desc;
+ desc = ep->ep.desc;
if (!desc)
continue;
tmp = *dev->ep [i].reg_udccs;
@@ -1191,7 +1190,6 @@ static void udc_reinit(struct pxa25x_udc *dev)
if (i != 0)
list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);
- ep->desc = NULL;
ep->ep.desc = NULL;
ep->stopped = 0;
INIT_LIST_HEAD (&ep->queue);
diff --git a/drivers/usb/gadget/pxa25x_udc.h b/drivers/usb/gadget/pxa25x_udc.h
index 893e917f048e..861f4df6ea22 100644
--- a/drivers/usb/gadget/pxa25x_udc.h
+++ b/drivers/usb/gadget/pxa25x_udc.h
@@ -41,7 +41,6 @@ struct pxa25x_ep {
struct usb_ep ep;
struct pxa25x_udc *dev;
- const struct usb_endpoint_descriptor *desc;
struct list_head queue;
unsigned long pio_irqs;
diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c
index c4401e7dd3a6..f3ac2a20c27c 100644
--- a/drivers/usb/gadget/r8a66597-udc.c
+++ b/drivers/usb/gadget/r8a66597-udc.c
@@ -459,7 +459,7 @@ static int alloc_pipe_config(struct r8a66597_ep *ep,
unsigned char *counter;
int ret;
- ep->desc = desc;
+ ep->ep.desc = desc;
if (ep->pipenum) /* already allocated pipe */
return 0;
@@ -648,7 +648,7 @@ static int sudmac_alloc_channel(struct r8a66597 *r8a66597,
/* set SUDMAC parameters */
dma = &r8a66597->dma;
dma->used = 1;
- if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+ if (ep->ep.desc->bEndpointAddress & USB_DIR_IN) {
dma->dir = 1;
} else {
dma->dir = 0;
@@ -770,7 +770,7 @@ static void start_packet_read(struct r8a66597_ep *ep,
static void start_packet(struct r8a66597_ep *ep, struct r8a66597_request *req)
{
- if (ep->desc->bEndpointAddress & USB_DIR_IN)
+ if (ep->ep.desc->bEndpointAddress & USB_DIR_IN)
start_packet_write(ep, req);
else
start_packet_read(ep, req);
@@ -930,7 +930,7 @@ __acquires(r8a66597->lock)
if (restart) {
req = get_request_from_ep(ep);
- if (ep->desc)
+ if (ep->ep.desc)
start_packet(ep, req);
}
}
@@ -1116,7 +1116,7 @@ static void irq_pipe_ready(struct r8a66597 *r8a66597, u16 status, u16 enb)
r8a66597_write(r8a66597, ~check, BRDYSTS);
ep = r8a66597->pipenum2ep[pipenum];
req = get_request_from_ep(ep);
- if (ep->desc->bEndpointAddress & USB_DIR_IN)
+ if (ep->ep.desc->bEndpointAddress & USB_DIR_IN)
irq_packet_write(ep, req);
else
irq_packet_read(ep, req);
@@ -1170,7 +1170,7 @@ __acquires(r8a66597->lock)
switch (ctrl->bRequestType & USB_RECIP_MASK) {
case USB_RECIP_DEVICE:
- status = 1 << USB_DEVICE_SELF_POWERED;
+ status = r8a66597->device_status;
break;
case USB_RECIP_INTERFACE:
status = 0;
@@ -1627,7 +1627,7 @@ static int r8a66597_queue(struct usb_ep *_ep, struct usb_request *_req,
req->req.actual = 0;
req->req.status = -EINPROGRESS;
- if (ep->desc == NULL) /* control */
+ if (ep->ep.desc == NULL) /* control */
start_ep0(ep, req);
else {
if (request && !ep->busy)
@@ -1692,7 +1692,7 @@ static int r8a66597_set_wedge(struct usb_ep *_ep)
ep = container_of(_ep, struct r8a66597_ep, ep);
- if (!ep || !ep->desc)
+ if (!ep || !ep->ep.desc)
return -EINVAL;
spin_lock_irqsave(&ep->r8a66597->lock, flags);
@@ -1800,11 +1800,24 @@ static int r8a66597_pullup(struct usb_gadget *gadget, int is_on)
return 0;
}
+static int r8a66597_set_selfpowered(struct usb_gadget *gadget, int is_self)
+{
+ struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget);
+
+ if (is_self)
+ r8a66597->device_status |= 1 << USB_DEVICE_SELF_POWERED;
+ else
+ r8a66597->device_status &= ~(1 << USB_DEVICE_SELF_POWERED);
+
+ return 0;
+}
+
static struct usb_gadget_ops r8a66597_gadget_ops = {
.get_frame = r8a66597_get_frame,
.udc_start = r8a66597_start,
.udc_stop = r8a66597_stop,
.pullup = r8a66597_pullup,
+ .set_selfpowered = r8a66597_set_selfpowered,
};
static int __exit r8a66597_remove(struct platform_device *pdev)
diff --git a/drivers/usb/gadget/r8a66597-udc.h b/drivers/usb/gadget/r8a66597-udc.h
index 8e3de61cd4b8..99908c76ccd1 100644
--- a/drivers/usb/gadget/r8a66597-udc.h
+++ b/drivers/usb/gadget/r8a66597-udc.h
@@ -72,7 +72,7 @@ struct r8a66597_ep {
unsigned use_dma:1;
u16 pipenum;
u16 type;
- const struct usb_endpoint_descriptor *desc;
+
/* register address */
unsigned char fifoaddr;
unsigned char fifosel;
@@ -111,6 +111,7 @@ struct r8a66597 {
u16 old_vbus;
u16 scount;
u16 old_dvsq;
+ u16 device_status; /* for GET_STATUS */
/* pipe config */
unsigned char bulk;
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
index 105b206cd844..f4abb0ed9872 100644
--- a/drivers/usb/gadget/s3c-hsotg.c
+++ b/drivers/usb/gadget/s3c-hsotg.c
@@ -1,4 +1,5 @@
-/* linux/drivers/usb/gadget/s3c-hsotg.c
+/**
+ * linux/drivers/usb/gadget/s3c-hsotg.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
@@ -13,7 +14,7 @@
* 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/kernel.h>
#include <linux/module.h>
@@ -27,21 +28,25 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+#include <linux/platform_data/s3c-hsotg.h>
#include <mach/map.h>
-#include <plat/regs-usb-hsotg-phy.h>
-#include <plat/regs-usb-hsotg.h>
-#include <mach/regs-sys.h>
-#include <plat/udc-hs.h>
-#include <plat/cpu.h>
+#include "s3c-hsotg.h"
#define DMA_ADDR_INVALID (~((dma_addr_t)0))
-/* EP0_MPS_LIMIT
+static const char * const s3c_hsotg_supply_names[] = {
+ "vusb_d", /* digital USB supply, 1.2V */
+ "vusb_a", /* analog USB supply, 1.1V */
+};
+
+/*
+ * EP0_MPS_LIMIT
*
* Unfortunately there seems to be a limit of the amount of data that can
* be transferred by IN transactions on EP0. This is either 127 bytes or 3
@@ -125,8 +130,6 @@ struct s3c_hsotg_ep {
char name[10];
};
-#define S3C_HSOTG_EPS (8+1) /* limit to 9 for the moment */
-
/**
* struct s3c_hsotg - driver state.
* @dev: The parent device supplied to the probe function
@@ -135,7 +138,9 @@ struct s3c_hsotg_ep {
* @regs: The memory area mapped for accessing registers.
* @regs_res: The resource that was allocated when claiming register space.
* @irq: The IRQ number we are using
+ * @supplies: Definition of USB power supplies
* @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos.
+ * @num_of_eps: Number of available EPs (excluding EP0)
* @debug_root: root directrory for debugfs.
* @debug_file: main status file for debugfs.
* @debug_fifo: FIFO status file for debugfs.
@@ -143,6 +148,8 @@ struct s3c_hsotg_ep {
* @ep0_buff: Buffer for EP0 reply data, if needed.
* @ctrl_buff: Buffer for EP0 control requests.
* @ctrl_req: Request for EP0 control packets.
+ * @setup: NAK management for EP0 SETUP
+ * @last_rst: Time of last reset
* @eps: The endpoints being supplied to the gadget framework
*/
struct s3c_hsotg {
@@ -155,7 +162,10 @@ struct s3c_hsotg {
int irq;
struct clk *clk;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)];
+
unsigned int dedicated_fifos:1;
+ unsigned char num_of_eps;
struct dentry *debug_root;
struct dentry *debug_file;
@@ -167,7 +177,9 @@ struct s3c_hsotg {
u8 ctrl_buff[8];
struct usb_gadget gadget;
- struct s3c_hsotg_ep eps[];
+ unsigned int setup;
+ unsigned long last_rst;
+ struct s3c_hsotg_ep *eps;
};
/**
@@ -244,14 +256,14 @@ static inline bool using_dma(struct s3c_hsotg *hsotg)
*/
static void s3c_hsotg_en_gsint(struct s3c_hsotg *hsotg, u32 ints)
{
- u32 gsintmsk = readl(hsotg->regs + S3C_GINTMSK);
+ u32 gsintmsk = readl(hsotg->regs + GINTMSK);
u32 new_gsintmsk;
new_gsintmsk = gsintmsk | ints;
if (new_gsintmsk != gsintmsk) {
dev_dbg(hsotg->dev, "gsintmsk now 0x%08x\n", new_gsintmsk);
- writel(new_gsintmsk, hsotg->regs + S3C_GINTMSK);
+ writel(new_gsintmsk, hsotg->regs + GINTMSK);
}
}
@@ -262,13 +274,13 @@ static void s3c_hsotg_en_gsint(struct s3c_hsotg *hsotg, u32 ints)
*/
static void s3c_hsotg_disable_gsint(struct s3c_hsotg *hsotg, u32 ints)
{
- u32 gsintmsk = readl(hsotg->regs + S3C_GINTMSK);
+ u32 gsintmsk = readl(hsotg->regs + GINTMSK);
u32 new_gsintmsk;
new_gsintmsk = gsintmsk & ~ints;
if (new_gsintmsk != gsintmsk)
- writel(new_gsintmsk, hsotg->regs + S3C_GINTMSK);
+ writel(new_gsintmsk, hsotg->regs + GINTMSK);
}
/**
@@ -293,12 +305,12 @@ static void s3c_hsotg_ctrl_epint(struct s3c_hsotg *hsotg,
bit <<= 16;
local_irq_save(flags);
- daint = readl(hsotg->regs + S3C_DAINTMSK);
+ daint = readl(hsotg->regs + DAINTMSK);
if (en)
daint |= bit;
else
daint &= ~bit;
- writel(daint, hsotg->regs + S3C_DAINTMSK);
+ writel(daint, hsotg->regs + DAINTMSK);
local_irq_restore(flags);
}
@@ -314,52 +326,51 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg)
int timeout;
u32 val;
- /* the ryu 2.6.24 release ahs
- writel(0x1C0, hsotg->regs + S3C_GRXFSIZ);
- writel(S3C_GNPTXFSIZ_NPTxFStAddr(0x200) |
- S3C_GNPTXFSIZ_NPTxFDep(0x1C0),
- hsotg->regs + S3C_GNPTXFSIZ);
- */
-
/* set FIFO sizes to 2048/1024 */
- writel(2048, hsotg->regs + S3C_GRXFSIZ);
- writel(S3C_GNPTXFSIZ_NPTxFStAddr(2048) |
- S3C_GNPTXFSIZ_NPTxFDep(1024),
- hsotg->regs + S3C_GNPTXFSIZ);
+ writel(2048, hsotg->regs + GRXFSIZ);
+ writel(GNPTXFSIZ_NPTxFStAddr(2048) |
+ GNPTXFSIZ_NPTxFDep(1024),
+ hsotg->regs + GNPTXFSIZ);
- /* arange all the rest of the TX FIFOs, as some versions of this
+ /*
+ * arange all the rest of the TX FIFOs, as some versions of this
* block have overlapping default addresses. This also ensures
* that if the settings have been changed, then they are set to
- * known values. */
+ * known values.
+ */
/* start at the end of the GNPTXFSIZ, rounded up */
addr = 2048 + 1024;
size = 768;
- /* currently we allocate TX FIFOs for all possible endpoints,
- * and assume that they are all the same size. */
+ /*
+ * currently we allocate TX FIFOs for all possible endpoints,
+ * and assume that they are all the same size.
+ */
for (ep = 1; ep <= 15; ep++) {
val = addr;
- val |= size << S3C_DPTXFSIZn_DPTxFSize_SHIFT;
+ val |= size << DPTXFSIZn_DPTxFSize_SHIFT;
addr += size;
- writel(val, hsotg->regs + S3C_DPTXFSIZn(ep));
+ writel(val, hsotg->regs + DPTXFSIZn(ep));
}
- /* according to p428 of the design guide, we need to ensure that
- * all fifos are flushed before continuing */
+ /*
+ * according to p428 of the design guide, we need to ensure that
+ * all fifos are flushed before continuing
+ */
- writel(S3C_GRSTCTL_TxFNum(0x10) | S3C_GRSTCTL_TxFFlsh |
- S3C_GRSTCTL_RxFFlsh, hsotg->regs + S3C_GRSTCTL);
+ writel(GRSTCTL_TxFNum(0x10) | GRSTCTL_TxFFlsh |
+ GRSTCTL_RxFFlsh, hsotg->regs + GRSTCTL);
/* wait until the fifos are both flushed */
timeout = 100;
while (1) {
- val = readl(hsotg->regs + S3C_GRSTCTL);
+ val = readl(hsotg->regs + GRSTCTL);
- if ((val & (S3C_GRSTCTL_TxFFlsh | S3C_GRSTCTL_RxFFlsh)) == 0)
+ if ((val & (GRSTCTL_TxFFlsh | GRSTCTL_RxFFlsh)) == 0)
break;
if (--timeout == 0) {
@@ -415,7 +426,7 @@ static inline int is_ep_periodic(struct s3c_hsotg_ep *hs_ep)
*
* This is the reverse of s3c_hsotg_map_dma(), called for the completion
* of a request to ensure the buffer is ready for access by the caller.
-*/
+ */
static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep,
struct s3c_hsotg_req *hs_req)
@@ -456,13 +467,13 @@ static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg,
* otherwise -ENOSPC is returned if the FIFO space was used up.
*
* This routine is only needed for PIO
-*/
+ */
static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep,
struct s3c_hsotg_req *hs_req)
{
bool periodic = is_ep_periodic(hs_ep);
- u32 gnptxsts = readl(hsotg->regs + S3C_GNPTXSTS);
+ u32 gnptxsts = readl(hsotg->regs + GNPTXSTS);
int buf_pos = hs_req->req.actual;
int to_write = hs_ep->size_loaded;
void *data;
@@ -476,20 +487,23 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
return 0;
if (periodic && !hsotg->dedicated_fifos) {
- u32 epsize = readl(hsotg->regs + S3C_DIEPTSIZ(hs_ep->index));
+ u32 epsize = readl(hsotg->regs + DIEPTSIZ(hs_ep->index));
int size_left;
int size_done;
- /* work out how much data was loaded so we can calculate
- * how much data is left in the fifo. */
+ /*
+ * work out how much data was loaded so we can calculate
+ * how much data is left in the fifo.
+ */
- size_left = S3C_DxEPTSIZ_XferSize_GET(epsize);
+ size_left = DxEPTSIZ_XferSize_GET(epsize);
- /* if shared fifo, we cannot write anything until the
+ /*
+ * if shared fifo, we cannot write anything until the
* previous data has been completely sent.
*/
if (hs_ep->fifo_load != 0) {
- s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_PTxFEmp);
+ s3c_hsotg_en_gsint(hsotg, GINTSTS_PTxFEmp);
return -ENOSPC;
}
@@ -510,47 +524,50 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
__func__, can_write);
if (can_write <= 0) {
- s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_PTxFEmp);
+ s3c_hsotg_en_gsint(hsotg, GINTSTS_PTxFEmp);
return -ENOSPC;
}
} else if (hsotg->dedicated_fifos && hs_ep->index != 0) {
- can_write = readl(hsotg->regs + S3C_DTXFSTS(hs_ep->index));
+ can_write = readl(hsotg->regs + DTXFSTS(hs_ep->index));
can_write &= 0xffff;
can_write *= 4;
} else {
- if (S3C_GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) {
+ if (GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) {
dev_dbg(hsotg->dev,
"%s: no queue slots available (0x%08x)\n",
__func__, gnptxsts);
- s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_NPTxFEmp);
+ s3c_hsotg_en_gsint(hsotg, GINTSTS_NPTxFEmp);
return -ENOSPC;
}
- can_write = S3C_GNPTXSTS_NPTxFSpcAvail_GET(gnptxsts);
+ can_write = GNPTXSTS_NPTxFSpcAvail_GET(gnptxsts);
can_write *= 4; /* fifo size is in 32bit quantities. */
}
dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, mps %d\n",
__func__, gnptxsts, can_write, to_write, hs_ep->ep.maxpacket);
- /* limit to 512 bytes of data, it seems at least on the non-periodic
+ /*
+ * limit to 512 bytes of data, it seems at least on the non-periodic
* FIFO, requests of >512 cause the endpoint to get stuck with a
* fragment of the end of the transfer in it.
*/
if (can_write > 512)
can_write = 512;
- /* limit the write to one max-packet size worth of data, but allow
+ /*
+ * limit the write to one max-packet size worth of data, but allow
* the transfer to return that it did not run out of fifo space
- * doing it. */
+ * doing it.
+ */
if (to_write > hs_ep->ep.maxpacket) {
to_write = hs_ep->ep.maxpacket;
s3c_hsotg_en_gsint(hsotg,
- periodic ? S3C_GINTSTS_PTxFEmp :
- S3C_GINTSTS_NPTxFEmp);
+ periodic ? GINTSTS_PTxFEmp :
+ GINTSTS_NPTxFEmp);
}
/* see if we can write data */
@@ -559,8 +576,8 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
to_write = can_write;
pkt_round = to_write % hs_ep->ep.maxpacket;
- /* Not sure, but we probably shouldn't be writing partial
- * packets into the FIFO, so round the write down to an
+ /*
+ * Round the write down to an
* exact number of packets.
*
* Note, we do not currently check to see if we can ever
@@ -570,12 +587,14 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
if (pkt_round)
to_write -= pkt_round;
- /* enable correct FIFO interrupt to alert us when there
- * is more room left. */
+ /*
+ * enable correct FIFO interrupt to alert us when there
+ * is more room left.
+ */
s3c_hsotg_en_gsint(hsotg,
- periodic ? S3C_GINTSTS_PTxFEmp :
- S3C_GINTSTS_NPTxFEmp);
+ periodic ? GINTSTS_PTxFEmp :
+ GINTSTS_NPTxFEmp);
}
dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n",
@@ -593,7 +612,7 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
to_write = DIV_ROUND_UP(to_write, 4);
data = hs_req->req.buf + buf_pos;
- writesl(hsotg->regs + S3C_EPFIFO(hs_ep->index), data, to_write);
+ writesl(hsotg->regs + EPFIFO(hs_ep->index), data, to_write);
return (to_write >= can_write) ? -ENOSPC : 0;
}
@@ -612,12 +631,12 @@ static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep)
unsigned maxpkt;
if (index != 0) {
- maxsize = S3C_DxEPTSIZ_XferSize_LIMIT + 1;
- maxpkt = S3C_DxEPTSIZ_PktCnt_LIMIT + 1;
+ maxsize = DxEPTSIZ_XferSize_LIMIT + 1;
+ maxpkt = DxEPTSIZ_PktCnt_LIMIT + 1;
} else {
maxsize = 64+64;
if (hs_ep->dir_in)
- maxpkt = S3C_DIEPTSIZ0_PktCnt_LIMIT + 1;
+ maxpkt = DIEPTSIZ0_PktCnt_LIMIT + 1;
else
maxpkt = 2;
}
@@ -626,8 +645,10 @@ static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep)
maxpkt--;
maxsize--;
- /* constrain by packet count if maxpkts*pktsize is greater
- * than the length register size. */
+ /*
+ * constrain by packet count if maxpkts*pktsize is greater
+ * than the length register size.
+ */
if ((maxpkt * hs_ep->ep.maxpacket) < maxsize)
maxsize = maxpkt * hs_ep->ep.maxpacket;
@@ -674,8 +695,8 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
}
}
- epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index);
- epsize_reg = dir_in ? S3C_DIEPTSIZ(index) : S3C_DOEPTSIZ(index);
+ epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
+ epsize_reg = dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index);
dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x, ep %d, dir %s\n",
__func__, readl(hsotg->regs + epctrl_reg), index,
@@ -684,13 +705,14 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
/* If endpoint is stalled, we will restart request later */
ctrl = readl(hsotg->regs + epctrl_reg);
- if (ctrl & S3C_DxEPCTL_Stall) {
+ if (ctrl & DxEPCTL_Stall) {
dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index);
return;
}
length = ureq->length - ureq->actual;
-
+ dev_dbg(hsotg->dev, "ureq->length:%d ureq->actual:%d\n",
+ ureq->length, ureq->actual);
if (0)
dev_dbg(hsotg->dev,
"REQ buf %p len %d dma 0x%08x noi=%d zp=%d snok=%d\n",
@@ -717,20 +739,22 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
packets = 1; /* send one packet if length is zero. */
if (dir_in && index != 0)
- epsize = S3C_DxEPTSIZ_MC(1);
+ epsize = DxEPTSIZ_MC(1);
else
epsize = 0;
if (index != 0 && ureq->zero) {
- /* test for the packets being exactly right for the
- * transfer */
+ /*
+ * test for the packets being exactly right for the
+ * transfer
+ */
if (length == (packets * hs_ep->ep.maxpacket))
packets++;
}
- epsize |= S3C_DxEPTSIZ_PktCnt(packets);
- epsize |= S3C_DxEPTSIZ_XferSize(length);
+ epsize |= DxEPTSIZ_PktCnt(packets);
+ epsize |= DxEPTSIZ_XferSize(length);
dev_dbg(hsotg->dev, "%s: %d@%d/%d, 0x%08x => 0x%08x\n",
__func__, packets, length, ureq->length, epsize, epsize_reg);
@@ -744,26 +768,38 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
if (using_dma(hsotg) && !continuing) {
unsigned int dma_reg;
- /* write DMA address to control register, buffer already
- * synced by s3c_hsotg_ep_queue(). */
+ /*
+ * write DMA address to control register, buffer already
+ * synced by s3c_hsotg_ep_queue().
+ */
- dma_reg = dir_in ? S3C_DIEPDMA(index) : S3C_DOEPDMA(index);
+ dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index);
writel(ureq->dma, hsotg->regs + dma_reg);
dev_dbg(hsotg->dev, "%s: 0x%08x => 0x%08x\n",
__func__, ureq->dma, dma_reg);
}
- ctrl |= S3C_DxEPCTL_EPEna; /* ensure ep enabled */
- ctrl |= S3C_DxEPCTL_USBActEp;
- ctrl |= S3C_DxEPCTL_CNAK; /* clear NAK set by core */
+ ctrl |= DxEPCTL_EPEna; /* ensure ep enabled */
+ ctrl |= DxEPCTL_USBActEp;
+
+ dev_dbg(hsotg->dev, "setup req:%d\n", hsotg->setup);
+
+ /* For Setup request do not clear NAK */
+ if (hsotg->setup && index == 0)
+ hsotg->setup = 0;
+ else
+ ctrl |= DxEPCTL_CNAK; /* clear NAK set by core */
+
dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl);
writel(ctrl, hsotg->regs + epctrl_reg);
- /* set these, it seems that DMA support increments past the end
+ /*
+ * set these, it seems that DMA support increments past the end
* of the packet buffer so we need to calculate the length from
- * this information. */
+ * this information.
+ */
hs_ep->size_loaded = length;
hs_ep->last_load = ureq->actual;
@@ -774,17 +810,21 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
s3c_hsotg_write_fifo(hsotg, hs_ep, hs_req);
}
- /* clear the INTknTXFEmpMsk when we start request, more as a aide
- * to debugging to see what is going on. */
+ /*
+ * clear the INTknTXFEmpMsk when we start request, more as a aide
+ * to debugging to see what is going on.
+ */
if (dir_in)
- writel(S3C_DIEPMSK_INTknTXFEmpMsk,
- hsotg->regs + S3C_DIEPINT(index));
+ writel(DIEPMSK_INTknTXFEmpMsk,
+ hsotg->regs + DIEPINT(index));
- /* Note, trying to clear the NAK here causes problems with transmit
- * on the S3C6400 ending up with the TXFIFO becoming full. */
+ /*
+ * Note, trying to clear the NAK here causes problems with transmit
+ * on the S3C6400 ending up with the TXFIFO becoming full.
+ */
/* check ep is enabled */
- if (!(readl(hsotg->regs + epctrl_reg) & S3C_DxEPCTL_EPEna))
+ if (!(readl(hsotg->regs + epctrl_reg) & DxEPCTL_EPEna))
dev_warn(hsotg->dev,
"ep%d: failed to become enabled (DxEPCTL=0x%08x)?\n",
index, readl(hsotg->regs + epctrl_reg));
@@ -804,7 +844,7 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
* then ensure the buffer has been synced to memory. If our buffer has no
* DMA memory, then we map the memory and mark our request to allow us to
* cleanup on completion.
-*/
+ */
static int s3c_hsotg_map_dma(struct s3c_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep,
struct usb_request *req)
@@ -922,7 +962,7 @@ static void s3c_hsotg_complete_oursetup(struct usb_ep *ep,
*
* Convert the given wIndex into a pointer to an driver endpoint
* structure, or return NULL if it is not a valid endpoint.
-*/
+ */
static struct s3c_hsotg_ep *ep_from_windex(struct s3c_hsotg *hsotg,
u32 windex)
{
@@ -933,7 +973,7 @@ static struct s3c_hsotg_ep *ep_from_windex(struct s3c_hsotg *hsotg,
if (windex >= 0x100)
return NULL;
- if (idx > S3C_HSOTG_EPS)
+ if (idx > hsotg->num_of_eps)
return NULL;
if (idx && ep->dir_in != dir)
@@ -1151,24 +1191,28 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg,
ctrl->bRequest, ctrl->bRequestType,
ctrl->wValue, ctrl->wLength);
- /* record the direction of the request, for later use when enquing
- * packets onto EP0. */
+ /*
+ * record the direction of the request, for later use when enquing
+ * packets onto EP0.
+ */
ep0->dir_in = (ctrl->bRequestType & USB_DIR_IN) ? 1 : 0;
dev_dbg(hsotg->dev, "ctrl: dir_in=%d\n", ep0->dir_in);
- /* if we've no data with this request, then the last part of the
- * transaction is going to implicitly be IN. */
+ /*
+ * if we've no data with this request, then the last part of the
+ * transaction is going to implicitly be IN.
+ */
if (ctrl->wLength == 0)
ep0->dir_in = 1;
if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
switch (ctrl->bRequest) {
case USB_REQ_SET_ADDRESS:
- dcfg = readl(hsotg->regs + S3C_DCFG);
- dcfg &= ~S3C_DCFG_DevAddr_MASK;
- dcfg |= ctrl->wValue << S3C_DCFG_DevAddr_SHIFT;
- writel(dcfg, hsotg->regs + S3C_DCFG);
+ dcfg = readl(hsotg->regs + DCFG);
+ dcfg &= ~DCFG_DevAddr_MASK;
+ dcfg |= ctrl->wValue << DCFG_DevAddr_SHIFT;
+ writel(dcfg, hsotg->regs + DCFG);
dev_info(hsotg->dev, "new address %d\n", ctrl->wValue);
@@ -1194,7 +1238,8 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg,
dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret);
}
- /* the request is either unhandlable, or is not formatted correctly
+ /*
+ * the request is either unhandlable, or is not formatted correctly
* so respond with a STALL for the status stage to indicate failure.
*/
@@ -1203,22 +1248,26 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg,
u32 ctrl;
dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in);
- reg = (ep0->dir_in) ? S3C_DIEPCTL0 : S3C_DOEPCTL0;
+ reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0;
- /* S3C_DxEPCTL_Stall will be cleared by EP once it has
- * taken effect, so no need to clear later. */
+ /*
+ * DxEPCTL_Stall will be cleared by EP once it has
+ * taken effect, so no need to clear later.
+ */
ctrl = readl(hsotg->regs + reg);
- ctrl |= S3C_DxEPCTL_Stall;
- ctrl |= S3C_DxEPCTL_CNAK;
+ ctrl |= DxEPCTL_Stall;
+ ctrl |= DxEPCTL_CNAK;
writel(ctrl, hsotg->regs + reg);
dev_dbg(hsotg->dev,
"written DxEPCTL=0x%08x to %08x (DxEPCTL=0x%08x)\n",
ctrl, reg, readl(hsotg->regs + reg));
- /* don't believe we need to anything more to get the EP
- * to reply with a STALL packet */
+ /*
+ * don't believe we need to anything more to get the EP
+ * to reply with a STALL packet
+ */
}
}
@@ -1279,8 +1328,10 @@ static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg)
ret = s3c_hsotg_ep_queue(&hsotg->eps[0].ep, req, GFP_ATOMIC);
if (ret < 0) {
dev_err(hsotg->dev, "%s: failed queue (%d)\n", __func__, ret);
- /* Don't think there's much we can do other than watch the
- * driver fail. */
+ /*
+ * Don't think there's much we can do other than watch the
+ * driver fail.
+ */
}
}
@@ -1296,7 +1347,7 @@ static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg)
* on the endpoint.
*
* Note, expects the ep to already be locked as appropriate.
-*/
+ */
static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep,
struct s3c_hsotg_req *hs_req,
@@ -1312,8 +1363,10 @@ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg,
dev_dbg(hsotg->dev, "complete: ep %p %s, req %p, %d => %p\n",
hs_ep, hs_ep->ep.name, hs_req, result, hs_req->req.complete);
- /* only replace the status if we've not already set an error
- * from a previous transaction */
+ /*
+ * only replace the status if we've not already set an error
+ * from a previous transaction
+ */
if (hs_req->req.status == -EINPROGRESS)
hs_req->req.status = result;
@@ -1324,8 +1377,10 @@ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg,
if (using_dma(hsotg))
s3c_hsotg_unmap_dma(hsotg, hs_ep, hs_req);
- /* call the complete request with the locks off, just in case the
- * request tries to queue more work for this endpoint. */
+ /*
+ * call the complete request with the locks off, just in case the
+ * request tries to queue more work for this endpoint.
+ */
if (hs_req->req.complete) {
spin_unlock(&hs_ep->lock);
@@ -1333,9 +1388,11 @@ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg,
spin_lock(&hs_ep->lock);
}
- /* Look to see if there is anything else to do. Note, the completion
+ /*
+ * Look to see if there is anything else to do. Note, the completion
* of the previous request may have caused a new request to be started
- * so be careful when doing this. */
+ * so be careful when doing this.
+ */
if (!hs_ep->req && result >= 0) {
restart = !list_empty(&hs_ep->queue);
@@ -1355,7 +1412,7 @@ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg,
*
* See s3c_hsotg_complete_request(), but called with the endpoint's
* lock held.
-*/
+ */
static void s3c_hsotg_complete_request_lock(struct s3c_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep,
struct s3c_hsotg_req *hs_req,
@@ -1382,13 +1439,13 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size)
{
struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep_idx];
struct s3c_hsotg_req *hs_req = hs_ep->req;
- void __iomem *fifo = hsotg->regs + S3C_EPFIFO(ep_idx);
+ void __iomem *fifo = hsotg->regs + EPFIFO(ep_idx);
int to_read;
int max_req;
int read_ptr;
if (!hs_req) {
- u32 epctl = readl(hsotg->regs + S3C_DOEPCTL(ep_idx));
+ u32 epctl = readl(hsotg->regs + DOEPCTL(ep_idx));
int ptr;
dev_warn(hsotg->dev,
@@ -1412,7 +1469,8 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size)
__func__, to_read, max_req, read_ptr, hs_req->req.length);
if (to_read > max_req) {
- /* more data appeared than we where willing
+ /*
+ * more data appeared than we where willing
* to deal with in this request.
*/
@@ -1424,8 +1482,10 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size)
hs_req->req.actual += to_read;
to_read = DIV_ROUND_UP(to_read, 4);
- /* note, we might over-write the buffer end by 3 bytes depending on
- * alignment of the data. */
+ /*
+ * note, we might over-write the buffer end by 3 bytes depending on
+ * alignment of the data.
+ */
readsl(fifo, hs_req->req.buf + read_ptr, to_read);
spin_unlock(&hs_ep->lock);
@@ -1465,14 +1525,14 @@ static void s3c_hsotg_send_zlp(struct s3c_hsotg *hsotg,
dev_dbg(hsotg->dev, "sending zero-length packet\n");
/* issue a zero-sized packet to terminate this */
- writel(S3C_DxEPTSIZ_MC(1) | S3C_DxEPTSIZ_PktCnt(1) |
- S3C_DxEPTSIZ_XferSize(0), hsotg->regs + S3C_DIEPTSIZ(0));
+ writel(DxEPTSIZ_MC(1) | DxEPTSIZ_PktCnt(1) |
+ DxEPTSIZ_XferSize(0), hsotg->regs + DIEPTSIZ(0));
- ctrl = readl(hsotg->regs + S3C_DIEPCTL0);
- ctrl |= S3C_DxEPCTL_CNAK; /* clear NAK set by core */
- ctrl |= S3C_DxEPCTL_EPEna; /* ensure ep enabled */
- ctrl |= S3C_DxEPCTL_USBActEp;
- writel(ctrl, hsotg->regs + S3C_DIEPCTL0);
+ ctrl = readl(hsotg->regs + DIEPCTL0);
+ ctrl |= DxEPCTL_CNAK; /* clear NAK set by core */
+ ctrl |= DxEPCTL_EPEna; /* ensure ep enabled */
+ ctrl |= DxEPCTL_USBActEp;
+ writel(ctrl, hsotg->regs + DIEPCTL0);
}
/**
@@ -1484,15 +1544,15 @@ static void s3c_hsotg_send_zlp(struct s3c_hsotg *hsotg,
* The RXFIFO has delivered an OutDone event, which means that the data
* transfer for an OUT endpoint has been completed, either by a short
* packet or by the finish of a transfer.
-*/
+ */
static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg,
int epnum, bool was_setup)
{
- u32 epsize = readl(hsotg->regs + S3C_DOEPTSIZ(epnum));
+ u32 epsize = readl(hsotg->regs + DOEPTSIZ(epnum));
struct s3c_hsotg_ep *hs_ep = &hsotg->eps[epnum];
struct s3c_hsotg_req *hs_req = hs_ep->req;
struct usb_request *req = &hs_req->req;
- unsigned size_left = S3C_DxEPTSIZ_XferSize_GET(epsize);
+ unsigned size_left = DxEPTSIZ_XferSize_GET(epsize);
int result = 0;
if (!hs_req) {
@@ -1503,7 +1563,8 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg,
if (using_dma(hsotg)) {
unsigned size_done;
- /* Calculate the size of the transfer by checking how much
+ /*
+ * Calculate the size of the transfer by checking how much
* is left in the endpoint size register and then working it
* out from the amount we loaded for the transfer.
*
@@ -1521,17 +1582,29 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg,
if (req->actual < req->length && size_left == 0) {
s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true);
return;
+ } else if (epnum == 0) {
+ /*
+ * After was_setup = 1 =>
+ * set CNAK for non Setup requests
+ */
+ hsotg->setup = was_setup ? 0 : 1;
}
if (req->actual < req->length && req->short_not_ok) {
dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n",
__func__, req->actual, req->length);
- /* todo - what should we return here? there's no one else
- * even bothering to check the status. */
+ /*
+ * todo - what should we return here? there's no one else
+ * even bothering to check the status.
+ */
}
if (epnum == 0) {
+ /*
+ * Condition req->complete != s3c_hsotg_complete_setup says:
+ * send ZLP when we have an asynchronous request from gadget
+ */
if (!was_setup && req->complete != s3c_hsotg_complete_setup)
s3c_hsotg_send_zlp(hsotg, hs_req);
}
@@ -1544,14 +1617,14 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg,
* @hsotg: The device instance
*
* Return the current frame number
-*/
+ */
static u32 s3c_hsotg_read_frameno(struct s3c_hsotg *hsotg)
{
u32 dsts;
- dsts = readl(hsotg->regs + S3C_DSTS);
- dsts &= S3C_DSTS_SOFFN_MASK;
- dsts >>= S3C_DSTS_SOFFN_SHIFT;
+ dsts = readl(hsotg->regs + DSTS);
+ dsts &= DSTS_SOFFN_MASK;
+ dsts >>= DSTS_SOFFN_SHIFT;
return dsts;
}
@@ -1574,29 +1647,29 @@ static u32 s3c_hsotg_read_frameno(struct s3c_hsotg *hsotg)
*/
static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg)
{
- u32 grxstsr = readl(hsotg->regs + S3C_GRXSTSP);
+ u32 grxstsr = readl(hsotg->regs + GRXSTSP);
u32 epnum, status, size;
WARN_ON(using_dma(hsotg));
- epnum = grxstsr & S3C_GRXSTS_EPNum_MASK;
- status = grxstsr & S3C_GRXSTS_PktSts_MASK;
+ epnum = grxstsr & GRXSTS_EPNum_MASK;
+ status = grxstsr & GRXSTS_PktSts_MASK;
- size = grxstsr & S3C_GRXSTS_ByteCnt_MASK;
- size >>= S3C_GRXSTS_ByteCnt_SHIFT;
+ size = grxstsr & GRXSTS_ByteCnt_MASK;
+ size >>= GRXSTS_ByteCnt_SHIFT;
if (1)
dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n",
__func__, grxstsr, size, epnum);
-#define __status(x) ((x) >> S3C_GRXSTS_PktSts_SHIFT)
+#define __status(x) ((x) >> GRXSTS_PktSts_SHIFT)
- switch (status >> S3C_GRXSTS_PktSts_SHIFT) {
- case __status(S3C_GRXSTS_PktSts_GlobalOutNAK):
+ switch (status >> GRXSTS_PktSts_SHIFT) {
+ case __status(GRXSTS_PktSts_GlobalOutNAK):
dev_dbg(hsotg->dev, "GlobalOutNAK\n");
break;
- case __status(S3C_GRXSTS_PktSts_OutDone):
+ case __status(GRXSTS_PktSts_OutDone):
dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n",
s3c_hsotg_read_frameno(hsotg));
@@ -1604,24 +1677,24 @@ static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg)
s3c_hsotg_handle_outdone(hsotg, epnum, false);
break;
- case __status(S3C_GRXSTS_PktSts_SetupDone):
+ case __status(GRXSTS_PktSts_SetupDone):
dev_dbg(hsotg->dev,
"SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n",
s3c_hsotg_read_frameno(hsotg),
- readl(hsotg->regs + S3C_DOEPCTL(0)));
+ readl(hsotg->regs + DOEPCTL(0)));
s3c_hsotg_handle_outdone(hsotg, epnum, true);
break;
- case __status(S3C_GRXSTS_PktSts_OutRX):
+ case __status(GRXSTS_PktSts_OutRX):
s3c_hsotg_rx_data(hsotg, epnum, size);
break;
- case __status(S3C_GRXSTS_PktSts_SetupRX):
+ case __status(GRXSTS_PktSts_SetupRX):
dev_dbg(hsotg->dev,
"SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n",
s3c_hsotg_read_frameno(hsotg),
- readl(hsotg->regs + S3C_DOEPCTL(0)));
+ readl(hsotg->regs + DOEPCTL(0)));
s3c_hsotg_rx_data(hsotg, epnum, size);
break;
@@ -1638,18 +1711,18 @@ static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg)
/**
* s3c_hsotg_ep0_mps - turn max packet size into register setting
* @mps: The maximum packet size in bytes.
-*/
+ */
static u32 s3c_hsotg_ep0_mps(unsigned int mps)
{
switch (mps) {
case 64:
- return S3C_D0EPCTL_MPS_64;
+ return D0EPCTL_MPS_64;
case 32:
- return S3C_D0EPCTL_MPS_32;
+ return D0EPCTL_MPS_32;
case 16:
- return S3C_D0EPCTL_MPS_16;
+ return D0EPCTL_MPS_16;
case 8:
- return S3C_D0EPCTL_MPS_8;
+ return D0EPCTL_MPS_8;
}
/* bad max packet size, warn and return invalid result */
@@ -1680,7 +1753,7 @@ static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg,
if (mpsval > 3)
goto bad_mps;
} else {
- if (mps >= S3C_DxEPCTL_MPS_LIMIT+1)
+ if (mps >= DxEPCTL_MPS_LIMIT+1)
goto bad_mps;
mpsval = mps;
@@ -1688,19 +1761,21 @@ static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg,
hs_ep->ep.maxpacket = mps;
- /* update both the in and out endpoint controldir_ registers, even
- * if one of the directions may not be in use. */
+ /*
+ * update both the in and out endpoint controldir_ registers, even
+ * if one of the directions may not be in use.
+ */
- reg = readl(regs + S3C_DIEPCTL(ep));
- reg &= ~S3C_DxEPCTL_MPS_MASK;
+ reg = readl(regs + DIEPCTL(ep));
+ reg &= ~DxEPCTL_MPS_MASK;
reg |= mpsval;
- writel(reg, regs + S3C_DIEPCTL(ep));
+ writel(reg, regs + DIEPCTL(ep));
if (ep) {
- reg = readl(regs + S3C_DOEPCTL(ep));
- reg &= ~S3C_DxEPCTL_MPS_MASK;
+ reg = readl(regs + DOEPCTL(ep));
+ reg &= ~DxEPCTL_MPS_MASK;
reg |= mpsval;
- writel(reg, regs + S3C_DOEPCTL(ep));
+ writel(reg, regs + DOEPCTL(ep));
}
return;
@@ -1719,16 +1794,16 @@ static void s3c_hsotg_txfifo_flush(struct s3c_hsotg *hsotg, unsigned int idx)
int timeout;
int val;
- writel(S3C_GRSTCTL_TxFNum(idx) | S3C_GRSTCTL_TxFFlsh,
- hsotg->regs + S3C_GRSTCTL);
+ writel(GRSTCTL_TxFNum(idx) | GRSTCTL_TxFFlsh,
+ hsotg->regs + GRSTCTL);
/* wait until the fifo is flushed */
timeout = 100;
while (1) {
- val = readl(hsotg->regs + S3C_GRSTCTL);
+ val = readl(hsotg->regs + GRSTCTL);
- if ((val & (S3C_GRSTCTL_TxFFlsh)) == 0)
+ if ((val & (GRSTCTL_TxFFlsh)) == 0)
break;
if (--timeout == 0) {
@@ -1778,7 +1853,7 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep)
{
struct s3c_hsotg_req *hs_req = hs_ep->req;
- u32 epsize = readl(hsotg->regs + S3C_DIEPTSIZ(hs_ep->index));
+ u32 epsize = readl(hsotg->regs + DIEPTSIZ(hs_ep->index));
int size_left, size_done;
if (!hs_req) {
@@ -1786,7 +1861,15 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg,
return;
}
- /* Calculate the size of the transfer by checking how much is left
+ /* Finish ZLP handling for IN EP0 transactions */
+ if (hsotg->eps[0].sent_zlp) {
+ dev_dbg(hsotg->dev, "zlp packet received\n");
+ s3c_hsotg_complete_request_lock(hsotg, hs_ep, hs_req, 0);
+ return;
+ }
+
+ /*
+ * Calculate the size of the transfer by checking how much is left
* in the endpoint size register and then working it out from
* the amount we loaded for the transfer.
*
@@ -1795,7 +1878,7 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg,
* aligned).
*/
- size_left = S3C_DxEPTSIZ_XferSize_GET(epsize);
+ size_left = DxEPTSIZ_XferSize_GET(epsize);
size_done = hs_ep->size_loaded - size_left;
size_done += hs_ep->last_load;
@@ -1805,9 +1888,28 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg,
__func__, hs_req->req.actual, size_done);
hs_req->req.actual = size_done;
+ dev_dbg(hsotg->dev, "req->length:%d req->actual:%d req->zero:%d\n",
+ hs_req->req.length, hs_req->req.actual, hs_req->req.zero);
+
+ /*
+ * Check if dealing with Maximum Packet Size(MPS) IN transfer at EP0
+ * When sent data is a multiple MPS size (e.g. 64B ,128B ,192B
+ * ,256B ... ), after last MPS sized packet send IN ZLP packet to
+ * inform the host that no more data is available.
+ * The state of req.zero member is checked to be sure that the value to
+ * send is smaller than wValue expected from host.
+ * Check req.length to NOT send another ZLP when the current one is
+ * under completion (the one for which this completion has been called).
+ */
+ if (hs_req->req.length && hs_ep->index == 0 && hs_req->req.zero &&
+ hs_req->req.length == hs_req->req.actual &&
+ !(hs_req->req.length % hs_ep->ep.maxpacket)) {
- /* if we did all of the transfer, and there is more data left
- * around, then try restarting the rest of the request */
+ dev_dbg(hsotg->dev, "ep0 zlp IN packet sent\n");
+ s3c_hsotg_send_zlp(hsotg, hs_req);
+
+ return;
+ }
if (!size_left && hs_req->req.actual < hs_req->req.length) {
dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__);
@@ -1823,14 +1925,14 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg,
* @dir_in: Set if this is an IN endpoint
*
* Process and clear any interrupt pending for an individual endpoint
-*/
+ */
static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
int dir_in)
{
struct s3c_hsotg_ep *hs_ep = &hsotg->eps[idx];
- u32 epint_reg = dir_in ? S3C_DIEPINT(idx) : S3C_DOEPINT(idx);
- u32 epctl_reg = dir_in ? S3C_DIEPCTL(idx) : S3C_DOEPCTL(idx);
- u32 epsiz_reg = dir_in ? S3C_DIEPTSIZ(idx) : S3C_DOEPTSIZ(idx);
+ u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx);
+ u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx);
+ u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx);
u32 ints;
ints = readl(hsotg->regs + epint_reg);
@@ -1841,28 +1943,32 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n",
__func__, idx, dir_in ? "in" : "out", ints);
- if (ints & S3C_DxEPINT_XferCompl) {
+ if (ints & DxEPINT_XferCompl) {
dev_dbg(hsotg->dev,
"%s: XferCompl: DxEPCTL=0x%08x, DxEPTSIZ=%08x\n",
__func__, readl(hsotg->regs + epctl_reg),
readl(hsotg->regs + epsiz_reg));
- /* we get OutDone from the FIFO, so we only need to look
- * at completing IN requests here */
+ /*
+ * we get OutDone from the FIFO, so we only need to look
+ * at completing IN requests here
+ */
if (dir_in) {
s3c_hsotg_complete_in(hsotg, hs_ep);
if (idx == 0 && !hs_ep->req)
s3c_hsotg_enqueue_setup(hsotg);
} else if (using_dma(hsotg)) {
- /* We're using DMA, we need to fire an OutDone here
- * as we ignore the RXFIFO. */
+ /*
+ * We're using DMA, we need to fire an OutDone here
+ * as we ignore the RXFIFO.
+ */
s3c_hsotg_handle_outdone(hsotg, idx, false);
}
}
- if (ints & S3C_DxEPINT_EPDisbld) {
+ if (ints & DxEPINT_EPDisbld) {
dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__);
if (dir_in) {
@@ -1870,27 +1976,29 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
s3c_hsotg_txfifo_flush(hsotg, idx);
- if ((epctl & S3C_DxEPCTL_Stall) &&
- (epctl & S3C_DxEPCTL_EPType_Bulk)) {
- int dctl = readl(hsotg->regs + S3C_DCTL);
+ if ((epctl & DxEPCTL_Stall) &&
+ (epctl & DxEPCTL_EPType_Bulk)) {
+ int dctl = readl(hsotg->regs + DCTL);
- dctl |= S3C_DCTL_CGNPInNAK;
- writel(dctl, hsotg->regs + S3C_DCTL);
+ dctl |= DCTL_CGNPInNAK;
+ writel(dctl, hsotg->regs + DCTL);
}
}
}
- if (ints & S3C_DxEPINT_AHBErr)
+ if (ints & DxEPINT_AHBErr)
dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__);
- if (ints & S3C_DxEPINT_Setup) { /* Setup or Timeout */
+ if (ints & DxEPINT_Setup) { /* Setup or Timeout */
dev_dbg(hsotg->dev, "%s: Setup/Timeout\n", __func__);
if (using_dma(hsotg) && idx == 0) {
- /* this is the notification we've received a
+ /*
+ * this is the notification we've received a
* setup packet. In non-DMA mode we'd get this
* from the RXFIFO, instead we need to process
- * the setup here. */
+ * the setup here.
+ */
if (dir_in)
WARN_ON_ONCE(1);
@@ -1899,26 +2007,25 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
}
}
- if (ints & S3C_DxEPINT_Back2BackSetup)
+ if (ints & DxEPINT_Back2BackSetup)
dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__);
if (dir_in) {
- /* not sure if this is important, but we'll clear it anyway
- */
- if (ints & S3C_DIEPMSK_INTknTXFEmpMsk) {
+ /* not sure if this is important, but we'll clear it anyway */
+ if (ints & DIEPMSK_INTknTXFEmpMsk) {
dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n",
__func__, idx);
}
/* this probably means something bad is happening */
- if (ints & S3C_DIEPMSK_INTknEPMisMsk) {
+ if (ints & DIEPMSK_INTknEPMisMsk) {
dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n",
__func__, idx);
}
/* FIFO has space or is empty (see GAHBCFG) */
if (hsotg->dedicated_fifos &&
- ints & S3C_DIEPMSK_TxFIFOEmpty) {
+ ints & DIEPMSK_TxFIFOEmpty) {
dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n",
__func__, idx);
if (!using_dma(hsotg))
@@ -1933,40 +2040,45 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
*
* Handle updating the device settings after the enumeration phase has
* been completed.
-*/
+ */
static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg)
{
- u32 dsts = readl(hsotg->regs + S3C_DSTS);
+ u32 dsts = readl(hsotg->regs + DSTS);
int ep0_mps = 0, ep_mps;
- /* This should signal the finish of the enumeration phase
+ /*
+ * This should signal the finish of the enumeration phase
* of the USB handshaking, so we should now know what rate
- * we connected at. */
+ * we connected at.
+ */
dev_dbg(hsotg->dev, "EnumDone (DSTS=0x%08x)\n", dsts);
- /* note, since we're limited by the size of transfer on EP0, and
+ /*
+ * note, since we're limited by the size of transfer on EP0, and
* it seems IN transfers must be a even number of packets we do
- * not advertise a 64byte MPS on EP0. */
+ * not advertise a 64byte MPS on EP0.
+ */
/* catch both EnumSpd_FS and EnumSpd_FS48 */
- switch (dsts & S3C_DSTS_EnumSpd_MASK) {
- case S3C_DSTS_EnumSpd_FS:
- case S3C_DSTS_EnumSpd_FS48:
+ switch (dsts & DSTS_EnumSpd_MASK) {
+ case DSTS_EnumSpd_FS:
+ case DSTS_EnumSpd_FS48:
hsotg->gadget.speed = USB_SPEED_FULL;
ep0_mps = EP0_MPS_LIMIT;
ep_mps = 64;
break;
- case S3C_DSTS_EnumSpd_HS:
+ case DSTS_EnumSpd_HS:
hsotg->gadget.speed = USB_SPEED_HIGH;
ep0_mps = EP0_MPS_LIMIT;
ep_mps = 512;
break;
- case S3C_DSTS_EnumSpd_LS:
+ case DSTS_EnumSpd_LS:
hsotg->gadget.speed = USB_SPEED_LOW;
- /* note, we don't actually support LS in this driver at the
+ /*
+ * note, we don't actually support LS in this driver at the
* moment, and the documentation seems to imply that it isn't
* supported by the PHYs on some of the devices.
*/
@@ -1975,13 +2087,15 @@ static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg)
dev_info(hsotg->dev, "new device is %s\n",
usb_speed_string(hsotg->gadget.speed));
- /* we should now know the maximum packet size for an
- * endpoint, so set the endpoints to a default value. */
+ /*
+ * we should now know the maximum packet size for an
+ * endpoint, so set the endpoints to a default value.
+ */
if (ep0_mps) {
int i;
s3c_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps);
- for (i = 1; i < S3C_HSOTG_EPS; i++)
+ for (i = 1; i < hsotg->num_of_eps; i++)
s3c_hsotg_set_ep_maxpacket(hsotg, i, ep_mps);
}
@@ -1990,8 +2104,8 @@ static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg)
s3c_hsotg_enqueue_setup(hsotg);
dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
- readl(hsotg->regs + S3C_DIEPCTL0),
- readl(hsotg->regs + S3C_DOEPCTL0));
+ readl(hsotg->regs + DIEPCTL0),
+ readl(hsotg->regs + DOEPCTL0));
}
/**
@@ -2014,8 +2128,10 @@ static void kill_all_requests(struct s3c_hsotg *hsotg,
spin_lock_irqsave(&ep->lock, flags);
list_for_each_entry_safe(req, treq, &ep->queue, queue) {
- /* currently, we can't do much about an already
- * running request on an in endpoint */
+ /*
+ * currently, we can't do much about an already
+ * running request on an in endpoint
+ */
if (ep->req == req && ep->dir_in && !force)
continue;
@@ -2033,18 +2149,18 @@ static void kill_all_requests(struct s3c_hsotg *hsotg,
(_hs)->driver->_entry(&(_hs)->gadget);
/**
- * s3c_hsotg_disconnect_irq - disconnect irq service
+ * s3c_hsotg_disconnect - disconnect service
* @hsotg: The device state.
*
- * A disconnect IRQ has been received, meaning that the host has
- * lost contact with the bus. Remove all current transactions
- * and signal the gadget driver that this has happened.
-*/
-static void s3c_hsotg_disconnect_irq(struct s3c_hsotg *hsotg)
+ * The device has been disconnected. Remove all current
+ * transactions and signal the gadget driver that this
+ * has happened.
+ */
+static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg)
{
unsigned ep;
- for (ep = 0; ep < S3C_HSOTG_EPS; ep++)
+ for (ep = 0; ep < hsotg->num_of_eps; ep++)
kill_all_requests(hsotg, &hsotg->eps[ep], -ESHUTDOWN, true);
call_gadget(hsotg, disconnect);
@@ -2062,7 +2178,7 @@ static void s3c_hsotg_irq_fifoempty(struct s3c_hsotg *hsotg, bool periodic)
/* look through for any more data to transmit */
- for (epno = 0; epno < S3C_HSOTG_EPS; epno++) {
+ for (epno = 0; epno < hsotg->num_of_eps; epno++) {
ep = &hsotg->eps[epno];
if (!ep->dir_in)
@@ -2078,12 +2194,187 @@ static void s3c_hsotg_irq_fifoempty(struct s3c_hsotg *hsotg, bool periodic)
}
}
-static struct s3c_hsotg *our_hsotg;
-
/* IRQ flags which will trigger a retry around the IRQ loop */
-#define IRQ_RETRY_MASK (S3C_GINTSTS_NPTxFEmp | \
- S3C_GINTSTS_PTxFEmp | \
- S3C_GINTSTS_RxFLvl)
+#define IRQ_RETRY_MASK (GINTSTS_NPTxFEmp | \
+ GINTSTS_PTxFEmp | \
+ GINTSTS_RxFLvl)
+
+/**
+ * s3c_hsotg_corereset - issue softreset to the core
+ * @hsotg: The device state
+ *
+ * Issue a soft reset to the core, and await the core finishing it.
+ */
+static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg)
+{
+ int timeout;
+ u32 grstctl;
+
+ dev_dbg(hsotg->dev, "resetting core\n");
+
+ /* issue soft reset */
+ writel(GRSTCTL_CSftRst, hsotg->regs + GRSTCTL);
+
+ timeout = 1000;
+ do {
+ grstctl = readl(hsotg->regs + GRSTCTL);
+ } while ((grstctl & GRSTCTL_CSftRst) && timeout-- > 0);
+
+ if (grstctl & GRSTCTL_CSftRst) {
+ dev_err(hsotg->dev, "Failed to get CSftRst asserted\n");
+ return -EINVAL;
+ }
+
+ timeout = 1000;
+
+ while (1) {
+ u32 grstctl = readl(hsotg->regs + GRSTCTL);
+
+ if (timeout-- < 0) {
+ dev_info(hsotg->dev,
+ "%s: reset failed, GRSTCTL=%08x\n",
+ __func__, grstctl);
+ return -ETIMEDOUT;
+ }
+
+ if (!(grstctl & GRSTCTL_AHBIdle))
+ continue;
+
+ break; /* reset done */
+ }
+
+ dev_dbg(hsotg->dev, "reset successful\n");
+ return 0;
+}
+
+/**
+ * s3c_hsotg_core_init - issue softreset to the core
+ * @hsotg: The device state
+ *
+ * Issue a soft reset to the core, and await the core finishing it.
+ */
+static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg)
+{
+ s3c_hsotg_corereset(hsotg);
+
+ /*
+ * we must now enable ep0 ready for host detection and then
+ * set configuration.
+ */
+
+ /* set the PLL on, remove the HNP/SRP and set the PHY */
+ writel(GUSBCFG_PHYIf16 | GUSBCFG_TOutCal(7) |
+ (0x5 << 10), hsotg->regs + GUSBCFG);
+
+ s3c_hsotg_init_fifo(hsotg);
+
+ __orr32(hsotg->regs + DCTL, DCTL_SftDiscon);
+
+ writel(1 << 18 | DCFG_DevSpd_HS, hsotg->regs + DCFG);
+
+ /* Clear any pending OTG interrupts */
+ writel(0xffffffff, hsotg->regs + GOTGINT);
+
+ /* Clear any pending interrupts */
+ writel(0xffffffff, hsotg->regs + GINTSTS);
+
+ writel(GINTSTS_ErlySusp | GINTSTS_SessReqInt |
+ GINTSTS_GOUTNakEff | GINTSTS_GINNakEff |
+ GINTSTS_ConIDStsChng | GINTSTS_USBRst |
+ GINTSTS_EnumDone | GINTSTS_OTGInt |
+ GINTSTS_USBSusp | GINTSTS_WkUpInt,
+ hsotg->regs + GINTMSK);
+
+ if (using_dma(hsotg))
+ writel(GAHBCFG_GlblIntrEn | GAHBCFG_DMAEn |
+ GAHBCFG_HBstLen_Incr4,
+ hsotg->regs + GAHBCFG);
+ else
+ writel(GAHBCFG_GlblIntrEn, hsotg->regs + GAHBCFG);
+
+ /*
+ * Enabling INTknTXFEmpMsk here seems to be a big mistake, we end
+ * up being flooded with interrupts if the host is polling the
+ * endpoint to try and read data.
+ */
+
+ writel(((hsotg->dedicated_fifos) ? DIEPMSK_TxFIFOEmpty : 0) |
+ DIEPMSK_EPDisbldMsk | DIEPMSK_XferComplMsk |
+ DIEPMSK_TimeOUTMsk | DIEPMSK_AHBErrMsk |
+ DIEPMSK_INTknEPMisMsk,
+ hsotg->regs + DIEPMSK);
+
+ /*
+ * don't need XferCompl, we get that from RXFIFO in slave mode. In
+ * DMA mode we may need this.
+ */
+ writel((using_dma(hsotg) ? (DIEPMSK_XferComplMsk |
+ DIEPMSK_TimeOUTMsk) : 0) |
+ DOEPMSK_EPDisbldMsk | DOEPMSK_AHBErrMsk |
+ DOEPMSK_SetupMsk,
+ hsotg->regs + DOEPMSK);
+
+ writel(0, hsotg->regs + DAINTMSK);
+
+ dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
+ readl(hsotg->regs + DIEPCTL0),
+ readl(hsotg->regs + DOEPCTL0));
+
+ /* enable in and out endpoint interrupts */
+ s3c_hsotg_en_gsint(hsotg, GINTSTS_OEPInt | GINTSTS_IEPInt);
+
+ /*
+ * Enable the RXFIFO when in slave mode, as this is how we collect
+ * the data. In DMA mode, we get events from the FIFO but also
+ * things we cannot process, so do not use it.
+ */
+ if (!using_dma(hsotg))
+ s3c_hsotg_en_gsint(hsotg, GINTSTS_RxFLvl);
+
+ /* Enable interrupts for EP0 in and out */
+ s3c_hsotg_ctrl_epint(hsotg, 0, 0, 1);
+ s3c_hsotg_ctrl_epint(hsotg, 0, 1, 1);
+
+ __orr32(hsotg->regs + DCTL, DCTL_PWROnPrgDone);
+ udelay(10); /* see openiboot */
+ __bic32(hsotg->regs + DCTL, DCTL_PWROnPrgDone);
+
+ dev_dbg(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + DCTL));
+
+ /*
+ * DxEPCTL_USBActEp says RO in manual, but seems to be set by
+ * writing to the EPCTL register..
+ */
+
+ /* set to read 1 8byte packet */
+ writel(DxEPTSIZ_MC(1) | DxEPTSIZ_PktCnt(1) |
+ DxEPTSIZ_XferSize(8), hsotg->regs + DOEPTSIZ0);
+
+ writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) |
+ DxEPCTL_CNAK | DxEPCTL_EPEna |
+ DxEPCTL_USBActEp,
+ hsotg->regs + DOEPCTL0);
+
+ /* enable, but don't activate EP0in */
+ writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) |
+ DxEPCTL_USBActEp, hsotg->regs + DIEPCTL0);
+
+ s3c_hsotg_enqueue_setup(hsotg);
+
+ dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
+ readl(hsotg->regs + DIEPCTL0),
+ readl(hsotg->regs + DOEPCTL0));
+
+ /* clear global NAKs */
+ writel(DCTL_CGOUTNak | DCTL_CGNPInNAK,
+ hsotg->regs + DCTL);
+
+ /* must be at-least 3ms to allow bus to see disconnect */
+ mdelay(3);
+
+ /* remove the soft-disconnect and let's go */
+ __bic32(hsotg->regs + DCTL, DCTL_SftDiscon);
+}
/**
* s3c_hsotg_irq - handle device interrupt
@@ -2098,52 +2389,45 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw)
u32 gintmsk;
irq_retry:
- gintsts = readl(hsotg->regs + S3C_GINTSTS);
- gintmsk = readl(hsotg->regs + S3C_GINTMSK);
+ gintsts = readl(hsotg->regs + GINTSTS);
+ gintmsk = readl(hsotg->regs + GINTMSK);
dev_dbg(hsotg->dev, "%s: %08x %08x (%08x) retry %d\n",
__func__, gintsts, gintsts & gintmsk, gintmsk, retry_count);
gintsts &= gintmsk;
- if (gintsts & S3C_GINTSTS_OTGInt) {
- u32 otgint = readl(hsotg->regs + S3C_GOTGINT);
+ if (gintsts & GINTSTS_OTGInt) {
+ u32 otgint = readl(hsotg->regs + GOTGINT);
dev_info(hsotg->dev, "OTGInt: %08x\n", otgint);
- writel(otgint, hsotg->regs + S3C_GOTGINT);
- }
-
- if (gintsts & S3C_GINTSTS_DisconnInt) {
- dev_dbg(hsotg->dev, "%s: DisconnInt\n", __func__);
- writel(S3C_GINTSTS_DisconnInt, hsotg->regs + S3C_GINTSTS);
-
- s3c_hsotg_disconnect_irq(hsotg);
+ writel(otgint, hsotg->regs + GOTGINT);
}
- if (gintsts & S3C_GINTSTS_SessReqInt) {
+ if (gintsts & GINTSTS_SessReqInt) {
dev_dbg(hsotg->dev, "%s: SessReqInt\n", __func__);
- writel(S3C_GINTSTS_SessReqInt, hsotg->regs + S3C_GINTSTS);
+ writel(GINTSTS_SessReqInt, hsotg->regs + GINTSTS);
}
- if (gintsts & S3C_GINTSTS_EnumDone) {
- writel(S3C_GINTSTS_EnumDone, hsotg->regs + S3C_GINTSTS);
+ if (gintsts & GINTSTS_EnumDone) {
+ writel(GINTSTS_EnumDone, hsotg->regs + GINTSTS);
s3c_hsotg_irq_enumdone(hsotg);
}
- if (gintsts & S3C_GINTSTS_ConIDStsChng) {
+ if (gintsts & GINTSTS_ConIDStsChng) {
dev_dbg(hsotg->dev, "ConIDStsChg (DSTS=0x%08x, GOTCTL=%08x)\n",
- readl(hsotg->regs + S3C_DSTS),
- readl(hsotg->regs + S3C_GOTGCTL));
+ readl(hsotg->regs + DSTS),
+ readl(hsotg->regs + GOTGCTL));
- writel(S3C_GINTSTS_ConIDStsChng, hsotg->regs + S3C_GINTSTS);
+ writel(GINTSTS_ConIDStsChng, hsotg->regs + GINTSTS);
}
- if (gintsts & (S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt)) {
- u32 daint = readl(hsotg->regs + S3C_DAINT);
- u32 daint_out = daint >> S3C_DAINT_OutEP_SHIFT;
- u32 daint_in = daint & ~(daint_out << S3C_DAINT_OutEP_SHIFT);
+ if (gintsts & (GINTSTS_OEPInt | GINTSTS_IEPInt)) {
+ u32 daint = readl(hsotg->regs + DAINT);
+ u32 daint_out = daint >> DAINT_OutEP_SHIFT;
+ u32 daint_in = daint & ~(daint_out << DAINT_OutEP_SHIFT);
int ep;
dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint);
@@ -2159,102 +2443,116 @@ irq_retry:
}
}
- if (gintsts & S3C_GINTSTS_USBRst) {
+ if (gintsts & GINTSTS_USBRst) {
+
+ u32 usb_status = readl(hsotg->regs + GOTGCTL);
+
dev_info(hsotg->dev, "%s: USBRst\n", __func__);
dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n",
- readl(hsotg->regs + S3C_GNPTXSTS));
+ readl(hsotg->regs + GNPTXSTS));
- writel(S3C_GINTSTS_USBRst, hsotg->regs + S3C_GINTSTS);
+ writel(GINTSTS_USBRst, hsotg->regs + GINTSTS);
- kill_all_requests(hsotg, &hsotg->eps[0], -ECONNRESET, true);
+ if (usb_status & GOTGCTL_BSESVLD) {
+ if (time_after(jiffies, hsotg->last_rst +
+ msecs_to_jiffies(200))) {
- /* it seems after a reset we can end up with a situation
- * where the TXFIFO still has data in it... the docs
- * suggest resetting all the fifos, so use the init_fifo
- * code to relayout and flush the fifos.
- */
+ kill_all_requests(hsotg, &hsotg->eps[0],
+ -ECONNRESET, true);
- s3c_hsotg_init_fifo(hsotg);
-
- s3c_hsotg_enqueue_setup(hsotg);
+ s3c_hsotg_core_init(hsotg);
+ hsotg->last_rst = jiffies;
+ }
+ }
}
/* check both FIFOs */
- if (gintsts & S3C_GINTSTS_NPTxFEmp) {
+ if (gintsts & GINTSTS_NPTxFEmp) {
dev_dbg(hsotg->dev, "NPTxFEmp\n");
- /* Disable the interrupt to stop it happening again
+ /*
+ * Disable the interrupt to stop it happening again
* unless one of these endpoint routines decides that
- * it needs re-enabling */
+ * it needs re-enabling
+ */
- s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_NPTxFEmp);
+ s3c_hsotg_disable_gsint(hsotg, GINTSTS_NPTxFEmp);
s3c_hsotg_irq_fifoempty(hsotg, false);
}
- if (gintsts & S3C_GINTSTS_PTxFEmp) {
+ if (gintsts & GINTSTS_PTxFEmp) {
dev_dbg(hsotg->dev, "PTxFEmp\n");
- /* See note in S3C_GINTSTS_NPTxFEmp */
+ /* See note in GINTSTS_NPTxFEmp */
- s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_PTxFEmp);
+ s3c_hsotg_disable_gsint(hsotg, GINTSTS_PTxFEmp);
s3c_hsotg_irq_fifoempty(hsotg, true);
}
- if (gintsts & S3C_GINTSTS_RxFLvl) {
- /* note, since GINTSTS_RxFLvl doubles as FIFO-not-empty,
+ if (gintsts & GINTSTS_RxFLvl) {
+ /*
+ * note, since GINTSTS_RxFLvl doubles as FIFO-not-empty,
* we need to retry s3c_hsotg_handle_rx if this is still
- * set. */
+ * set.
+ */
s3c_hsotg_handle_rx(hsotg);
}
- if (gintsts & S3C_GINTSTS_ModeMis) {
+ if (gintsts & GINTSTS_ModeMis) {
dev_warn(hsotg->dev, "warning, mode mismatch triggered\n");
- writel(S3C_GINTSTS_ModeMis, hsotg->regs + S3C_GINTSTS);
+ writel(GINTSTS_ModeMis, hsotg->regs + GINTSTS);
}
- if (gintsts & S3C_GINTSTS_USBSusp) {
- dev_info(hsotg->dev, "S3C_GINTSTS_USBSusp\n");
- writel(S3C_GINTSTS_USBSusp, hsotg->regs + S3C_GINTSTS);
+ if (gintsts & GINTSTS_USBSusp) {
+ dev_info(hsotg->dev, "GINTSTS_USBSusp\n");
+ writel(GINTSTS_USBSusp, hsotg->regs + GINTSTS);
call_gadget(hsotg, suspend);
+ s3c_hsotg_disconnect(hsotg);
}
- if (gintsts & S3C_GINTSTS_WkUpInt) {
- dev_info(hsotg->dev, "S3C_GINTSTS_WkUpIn\n");
- writel(S3C_GINTSTS_WkUpInt, hsotg->regs + S3C_GINTSTS);
+ if (gintsts & GINTSTS_WkUpInt) {
+ dev_info(hsotg->dev, "GINTSTS_WkUpIn\n");
+ writel(GINTSTS_WkUpInt, hsotg->regs + GINTSTS);
call_gadget(hsotg, resume);
}
- if (gintsts & S3C_GINTSTS_ErlySusp) {
- dev_dbg(hsotg->dev, "S3C_GINTSTS_ErlySusp\n");
- writel(S3C_GINTSTS_ErlySusp, hsotg->regs + S3C_GINTSTS);
+ if (gintsts & GINTSTS_ErlySusp) {
+ dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n");
+ writel(GINTSTS_ErlySusp, hsotg->regs + GINTSTS);
+
+ s3c_hsotg_disconnect(hsotg);
}
- /* these next two seem to crop-up occasionally causing the core
+ /*
+ * these next two seem to crop-up occasionally causing the core
* to shutdown the USB transfer, so try clearing them and logging
- * the occurrence. */
+ * the occurrence.
+ */
- if (gintsts & S3C_GINTSTS_GOUTNakEff) {
+ if (gintsts & GINTSTS_GOUTNakEff) {
dev_info(hsotg->dev, "GOUTNakEff triggered\n");
- writel(S3C_DCTL_CGOUTNak, hsotg->regs + S3C_DCTL);
+ writel(DCTL_CGOUTNak, hsotg->regs + DCTL);
s3c_hsotg_dump(hsotg);
}
- if (gintsts & S3C_GINTSTS_GINNakEff) {
+ if (gintsts & GINTSTS_GINNakEff) {
dev_info(hsotg->dev, "GINNakEff triggered\n");
- writel(S3C_DCTL_CGNPInNAK, hsotg->regs + S3C_DCTL);
+ writel(DCTL_CGNPInNAK, hsotg->regs + DCTL);
s3c_hsotg_dump(hsotg);
}
- /* if we've had fifo events, we should try and go around the
- * loop again to see if there's any point in returning yet. */
+ /*
+ * if we've had fifo events, we should try and go around the
+ * loop again to see if there's any point in returning yet.
+ */
if (gintsts & IRQ_RETRY_MASK && --retry_count > 0)
goto irq_retry;
@@ -2268,7 +2566,7 @@ irq_retry:
* @desc: The USB endpoint descriptor to configure with.
*
* This is called from the USB gadget code's usb_ep_enable().
-*/
+ */
static int s3c_hsotg_ep_enable(struct usb_ep *ep,
const struct usb_endpoint_descriptor *desc)
{
@@ -2300,7 +2598,7 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
/* note, we handle this here instead of s3c_hsotg_set_ep_maxpacket */
- epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index);
+ epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
epctrl = readl(hsotg->regs + epctrl_reg);
dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n",
@@ -2308,20 +2606,23 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
spin_lock_irqsave(&hs_ep->lock, flags);
- epctrl &= ~(S3C_DxEPCTL_EPType_MASK | S3C_DxEPCTL_MPS_MASK);
- epctrl |= S3C_DxEPCTL_MPS(mps);
+ epctrl &= ~(DxEPCTL_EPType_MASK | DxEPCTL_MPS_MASK);
+ epctrl |= DxEPCTL_MPS(mps);
- /* mark the endpoint as active, otherwise the core may ignore
- * transactions entirely for this endpoint */
- epctrl |= S3C_DxEPCTL_USBActEp;
+ /*
+ * mark the endpoint as active, otherwise the core may ignore
+ * transactions entirely for this endpoint
+ */
+ epctrl |= DxEPCTL_USBActEp;
- /* set the NAK status on the endpoint, otherwise we might try and
+ /*
+ * set the NAK status on the endpoint, otherwise we might try and
* do something with data that we've yet got a request to process
* since the RXFIFO will take data for an endpoint even if the
* size register hasn't been set.
*/
- epctrl |= S3C_DxEPCTL_SNAK;
+ epctrl |= DxEPCTL_SNAK;
/* update the endpoint state */
hs_ep->ep.maxpacket = mps;
@@ -2336,37 +2637,40 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
goto out;
case USB_ENDPOINT_XFER_BULK:
- epctrl |= S3C_DxEPCTL_EPType_Bulk;
+ epctrl |= DxEPCTL_EPType_Bulk;
break;
case USB_ENDPOINT_XFER_INT:
if (dir_in) {
- /* Allocate our TxFNum by simply using the index
+ /*
+ * Allocate our TxFNum by simply using the index
* of the endpoint for the moment. We could do
* something better if the host indicates how
- * many FIFOs we are expecting to use. */
+ * many FIFOs we are expecting to use.
+ */
hs_ep->periodic = 1;
- epctrl |= S3C_DxEPCTL_TxFNum(index);
+ epctrl |= DxEPCTL_TxFNum(index);
}
- epctrl |= S3C_DxEPCTL_EPType_Intterupt;
+ epctrl |= DxEPCTL_EPType_Intterupt;
break;
case USB_ENDPOINT_XFER_CONTROL:
- epctrl |= S3C_DxEPCTL_EPType_Control;
+ epctrl |= DxEPCTL_EPType_Control;
break;
}
- /* if the hardware has dedicated fifos, we must give each IN EP
+ /*
+ * if the hardware has dedicated fifos, we must give each IN EP
* a unique tx-fifo even if it is non-periodic.
*/
if (dir_in && hsotg->dedicated_fifos)
- epctrl |= S3C_DxEPCTL_TxFNum(index);
+ epctrl |= DxEPCTL_TxFNum(index);
/* for non control endpoints, set PID to D0 */
if (index)
- epctrl |= S3C_DxEPCTL_SetD0PID;
+ epctrl |= DxEPCTL_SetD0PID;
dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n",
__func__, epctrl);
@@ -2383,6 +2687,10 @@ out:
return ret;
}
+/**
+ * s3c_hsotg_ep_disable - disable given endpoint
+ * @ep: The endpoint to disable.
+ */
static int s3c_hsotg_ep_disable(struct usb_ep *ep)
{
struct s3c_hsotg_ep *hs_ep = our_ep(ep);
@@ -2400,7 +2708,7 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep)
return -EINVAL;
}
- epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index);
+ epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
/* terminate all requests with shutdown */
kill_all_requests(hsotg, hs_ep, -ESHUTDOWN, false);
@@ -2408,9 +2716,9 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep)
spin_lock_irqsave(&hs_ep->lock, flags);
ctrl = readl(hsotg->regs + epctrl_reg);
- ctrl &= ~S3C_DxEPCTL_EPEna;
- ctrl &= ~S3C_DxEPCTL_USBActEp;
- ctrl |= S3C_DxEPCTL_SNAK;
+ ctrl &= ~DxEPCTL_EPEna;
+ ctrl &= ~DxEPCTL_USBActEp;
+ ctrl |= DxEPCTL_SNAK;
dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl);
writel(ctrl, hsotg->regs + epctrl_reg);
@@ -2426,7 +2734,7 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep)
* on_list - check request is on the given endpoint
* @ep: The endpoint to check.
* @test: The request to test if it is on the endpoint.
-*/
+ */
static bool on_list(struct s3c_hsotg_ep *ep, struct s3c_hsotg_req *test)
{
struct s3c_hsotg_req *req, *treq;
@@ -2439,6 +2747,11 @@ static bool on_list(struct s3c_hsotg_ep *ep, struct s3c_hsotg_req *test)
return false;
}
+/**
+ * s3c_hsotg_ep_dequeue - dequeue given endpoint
+ * @ep: The endpoint to dequeue.
+ * @req: The request to be removed from a queue.
+ */
static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
{
struct s3c_hsotg_req *hs_req = our_req(req);
@@ -2461,6 +2774,11 @@ static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
return 0;
}
+/**
+ * s3c_hsotg_ep_sethalt - set halt on a given endpoint
+ * @ep: The endpoint to set halt.
+ * @value: Set or unset the halt.
+ */
static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)
{
struct s3c_hsotg_ep *hs_ep = our_ep(ep);
@@ -2477,34 +2795,34 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)
/* write both IN and OUT control registers */
- epreg = S3C_DIEPCTL(index);
+ epreg = DIEPCTL(index);
epctl = readl(hs->regs + epreg);
if (value) {
- epctl |= S3C_DxEPCTL_Stall + S3C_DxEPCTL_SNAK;
- if (epctl & S3C_DxEPCTL_EPEna)
- epctl |= S3C_DxEPCTL_EPDis;
+ epctl |= DxEPCTL_Stall + DxEPCTL_SNAK;
+ if (epctl & DxEPCTL_EPEna)
+ epctl |= DxEPCTL_EPDis;
} else {
- epctl &= ~S3C_DxEPCTL_Stall;
- xfertype = epctl & S3C_DxEPCTL_EPType_MASK;
- if (xfertype == S3C_DxEPCTL_EPType_Bulk ||
- xfertype == S3C_DxEPCTL_EPType_Intterupt)
- epctl |= S3C_DxEPCTL_SetD0PID;
+ epctl &= ~DxEPCTL_Stall;
+ xfertype = epctl & DxEPCTL_EPType_MASK;
+ if (xfertype == DxEPCTL_EPType_Bulk ||
+ xfertype == DxEPCTL_EPType_Intterupt)
+ epctl |= DxEPCTL_SetD0PID;
}
writel(epctl, hs->regs + epreg);
- epreg = S3C_DOEPCTL(index);
+ epreg = DOEPCTL(index);
epctl = readl(hs->regs + epreg);
if (value)
- epctl |= S3C_DxEPCTL_Stall;
+ epctl |= DxEPCTL_Stall;
else {
- epctl &= ~S3C_DxEPCTL_Stall;
- xfertype = epctl & S3C_DxEPCTL_EPType_MASK;
- if (xfertype == S3C_DxEPCTL_EPType_Bulk ||
- xfertype == S3C_DxEPCTL_EPType_Intterupt)
- epctl |= S3C_DxEPCTL_SetD0PID;
+ epctl &= ~DxEPCTL_Stall;
+ xfertype = epctl & DxEPCTL_EPType_MASK;
+ if (xfertype == DxEPCTL_EPType_Bulk ||
+ xfertype == DxEPCTL_EPType_Intterupt)
+ epctl |= DxEPCTL_SetD0PID;
}
writel(epctl, hs->regs + epreg);
@@ -2526,57 +2844,91 @@ static struct usb_ep_ops s3c_hsotg_ep_ops = {
};
/**
- * s3c_hsotg_corereset - issue softreset to the core
- * @hsotg: The device state
+ * s3c_hsotg_phy_enable - enable platform phy dev
+ * @hsotg: The driver state
*
- * Issue a soft reset to the core, and await the core finishing it.
-*/
-static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg)
+ * A wrapper for platform code responsible for controlling
+ * low-level USB code
+ */
+static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg)
{
- int timeout;
- u32 grstctl;
+ struct platform_device *pdev = to_platform_device(hsotg->dev);
- dev_dbg(hsotg->dev, "resetting core\n");
+ dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev);
+ if (hsotg->plat->phy_init)
+ hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);
+}
- /* issue soft reset */
- writel(S3C_GRSTCTL_CSftRst, hsotg->regs + S3C_GRSTCTL);
+/**
+ * s3c_hsotg_phy_disable - disable platform phy dev
+ * @hsotg: The driver state
+ *
+ * A wrapper for platform code responsible for controlling
+ * low-level USB code
+ */
+static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg)
+{
+ struct platform_device *pdev = to_platform_device(hsotg->dev);
- timeout = 1000;
- do {
- grstctl = readl(hsotg->regs + S3C_GRSTCTL);
- } while ((grstctl & S3C_GRSTCTL_CSftRst) && timeout-- > 0);
+ if (hsotg->plat->phy_exit)
+ hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);
+}
- if (grstctl & S3C_GRSTCTL_CSftRst) {
- dev_err(hsotg->dev, "Failed to get CSftRst asserted\n");
- return -EINVAL;
- }
+/**
+ * s3c_hsotg_init - initalize the usb core
+ * @hsotg: The driver state
+ */
+static void s3c_hsotg_init(struct s3c_hsotg *hsotg)
+{
+ /* unmask subset of endpoint interrupts */
- timeout = 1000;
+ writel(DIEPMSK_TimeOUTMsk | DIEPMSK_AHBErrMsk |
+ DIEPMSK_EPDisbldMsk | DIEPMSK_XferComplMsk,
+ hsotg->regs + DIEPMSK);
- while (1) {
- u32 grstctl = readl(hsotg->regs + S3C_GRSTCTL);
+ writel(DOEPMSK_SetupMsk | DOEPMSK_AHBErrMsk |
+ DOEPMSK_EPDisbldMsk | DOEPMSK_XferComplMsk,
+ hsotg->regs + DOEPMSK);
- if (timeout-- < 0) {
- dev_info(hsotg->dev,
- "%s: reset failed, GRSTCTL=%08x\n",
- __func__, grstctl);
- return -ETIMEDOUT;
- }
+ writel(0, hsotg->regs + DAINTMSK);
- if (!(grstctl & S3C_GRSTCTL_AHBIdle))
- continue;
+ /* Be in disconnected state until gadget is registered */
+ __orr32(hsotg->regs + DCTL, DCTL_SftDiscon);
- break; /* reset done */
+ if (0) {
+ /* post global nak until we're ready */
+ writel(DCTL_SGNPInNAK | DCTL_SGOUTNak,
+ hsotg->regs + DCTL);
}
- dev_dbg(hsotg->dev, "reset successful\n");
- return 0;
+ /* setup fifos */
+
+ dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n",
+ readl(hsotg->regs + GRXFSIZ),
+ readl(hsotg->regs + GNPTXFSIZ));
+
+ s3c_hsotg_init_fifo(hsotg);
+
+ /* set the PLL on, remove the HNP/SRP and set the PHY */
+ writel(GUSBCFG_PHYIf16 | GUSBCFG_TOutCal(7) | (0x5 << 10),
+ hsotg->regs + GUSBCFG);
+
+ writel(using_dma(hsotg) ? GAHBCFG_DMAEn : 0x0,
+ hsotg->regs + GAHBCFG);
}
-static int s3c_hsotg_start(struct usb_gadget_driver *driver,
- int (*bind)(struct usb_gadget *))
+/**
+ * s3c_hsotg_udc_start - prepare the udc for work
+ * @gadget: The usb gadget state
+ * @driver: The usb gadget driver
+ *
+ * Perform initialization to prepare udc device and driver
+ * to work.
+ */
+static int s3c_hsotg_udc_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
- struct s3c_hsotg *hsotg = our_hsotg;
+ struct s3c_hsotg *hsotg = to_hsotg(gadget);
int ret;
if (!hsotg) {
@@ -2592,7 +2944,7 @@ static int s3c_hsotg_start(struct usb_gadget_driver *driver,
if (driver->max_speed < USB_SPEED_FULL)
dev_err(hsotg->dev, "%s: bad speed\n", __func__);
- if (!bind || !driver->setup) {
+ if (!driver->setup) {
dev_err(hsotg->dev, "%s: missing entry points\n", __func__);
return -EINVAL;
}
@@ -2605,135 +2957,17 @@ static int s3c_hsotg_start(struct usb_gadget_driver *driver,
hsotg->gadget.dev.dma_mask = hsotg->dev->dma_mask;
hsotg->gadget.speed = USB_SPEED_UNKNOWN;
- ret = device_add(&hsotg->gadget.dev);
+ ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
+ hsotg->supplies);
if (ret) {
- dev_err(hsotg->dev, "failed to register gadget device\n");
+ dev_err(hsotg->dev, "failed to enable supplies: %d\n", ret);
goto err;
}
- ret = bind(&hsotg->gadget);
- if (ret) {
- dev_err(hsotg->dev, "failed bind %s\n", driver->driver.name);
-
- hsotg->gadget.dev.driver = NULL;
- hsotg->driver = NULL;
- goto err;
- }
-
- /* we must now enable ep0 ready for host detection and then
- * set configuration. */
-
- s3c_hsotg_corereset(hsotg);
-
- /* set the PLL on, remove the HNP/SRP and set the PHY */
- writel(S3C_GUSBCFG_PHYIf16 | S3C_GUSBCFG_TOutCal(7) |
- (0x5 << 10), hsotg->regs + S3C_GUSBCFG);
-
- /* looks like soft-reset changes state of FIFOs */
- s3c_hsotg_init_fifo(hsotg);
-
- __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon);
-
- writel(1 << 18 | S3C_DCFG_DevSpd_HS, hsotg->regs + S3C_DCFG);
-
- /* Clear any pending OTG interrupts */
- writel(0xffffffff, hsotg->regs + S3C_GOTGINT);
-
- /* Clear any pending interrupts */
- writel(0xffffffff, hsotg->regs + S3C_GINTSTS);
-
- writel(S3C_GINTSTS_DisconnInt | S3C_GINTSTS_SessReqInt |
- S3C_GINTSTS_ConIDStsChng | S3C_GINTSTS_USBRst |
- S3C_GINTSTS_EnumDone | S3C_GINTSTS_OTGInt |
- S3C_GINTSTS_USBSusp | S3C_GINTSTS_WkUpInt |
- S3C_GINTSTS_GOUTNakEff | S3C_GINTSTS_GINNakEff |
- S3C_GINTSTS_ErlySusp,
- hsotg->regs + S3C_GINTMSK);
-
- if (using_dma(hsotg))
- writel(S3C_GAHBCFG_GlblIntrEn | S3C_GAHBCFG_DMAEn |
- S3C_GAHBCFG_HBstLen_Incr4,
- hsotg->regs + S3C_GAHBCFG);
- else
- writel(S3C_GAHBCFG_GlblIntrEn, hsotg->regs + S3C_GAHBCFG);
-
- /* Enabling INTknTXFEmpMsk here seems to be a big mistake, we end
- * up being flooded with interrupts if the host is polling the
- * endpoint to try and read data. */
-
- writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk |
- S3C_DIEPMSK_INTknEPMisMsk |
- S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk |
- ((hsotg->dedicated_fifos) ? S3C_DIEPMSK_TxFIFOEmpty : 0),
- hsotg->regs + S3C_DIEPMSK);
-
- /* don't need XferCompl, we get that from RXFIFO in slave mode. In
- * DMA mode we may need this. */
- writel(S3C_DOEPMSK_SetupMsk | S3C_DOEPMSK_AHBErrMsk |
- S3C_DOEPMSK_EPDisbldMsk |
- (using_dma(hsotg) ? (S3C_DIEPMSK_XferComplMsk |
- S3C_DIEPMSK_TimeOUTMsk) : 0),
- hsotg->regs + S3C_DOEPMSK);
-
- writel(0, hsotg->regs + S3C_DAINTMSK);
-
- dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
- readl(hsotg->regs + S3C_DIEPCTL0),
- readl(hsotg->regs + S3C_DOEPCTL0));
-
- /* enable in and out endpoint interrupts */
- s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt);
-
- /* Enable the RXFIFO when in slave mode, as this is how we collect
- * the data. In DMA mode, we get events from the FIFO but also
- * things we cannot process, so do not use it. */
- if (!using_dma(hsotg))
- s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_RxFLvl);
-
- /* Enable interrupts for EP0 in and out */
- s3c_hsotg_ctrl_epint(hsotg, 0, 0, 1);
- s3c_hsotg_ctrl_epint(hsotg, 0, 1, 1);
-
- __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_PWROnPrgDone);
- udelay(10); /* see openiboot */
- __bic32(hsotg->regs + S3C_DCTL, S3C_DCTL_PWROnPrgDone);
-
- dev_dbg(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + S3C_DCTL));
-
- /* S3C_DxEPCTL_USBActEp says RO in manual, but seems to be set by
- writing to the EPCTL register.. */
-
- /* set to read 1 8byte packet */
- writel(S3C_DxEPTSIZ_MC(1) | S3C_DxEPTSIZ_PktCnt(1) |
- S3C_DxEPTSIZ_XferSize(8), hsotg->regs + DOEPTSIZ0);
-
- writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) |
- S3C_DxEPCTL_CNAK | S3C_DxEPCTL_EPEna |
- S3C_DxEPCTL_USBActEp,
- hsotg->regs + S3C_DOEPCTL0);
-
- /* enable, but don't activate EP0in */
- writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) |
- S3C_DxEPCTL_USBActEp, hsotg->regs + S3C_DIEPCTL0);
-
- s3c_hsotg_enqueue_setup(hsotg);
-
- dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
- readl(hsotg->regs + S3C_DIEPCTL0),
- readl(hsotg->regs + S3C_DOEPCTL0));
-
- /* clear global NAKs */
- writel(S3C_DCTL_CGOUTNak | S3C_DCTL_CGNPInNAK,
- hsotg->regs + S3C_DCTL);
-
- /* must be at-least 3ms to allow bus to see disconnect */
- msleep(3);
-
- /* remove the soft-disconnect and let's go */
- __bic32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon);
-
- /* report to the user, and return */
+ s3c_hsotg_phy_enable(hsotg);
+ s3c_hsotg_core_init(hsotg);
+ hsotg->last_rst = jiffies;
dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name);
return 0;
@@ -2743,9 +2977,17 @@ err:
return ret;
}
-static int s3c_hsotg_stop(struct usb_gadget_driver *driver)
+/**
+ * s3c_hsotg_udc_stop - stop the udc
+ * @gadget: The usb gadget state
+ * @driver: The usb gadget driver
+ *
+ * Stop udc hw block and stay tunned for future transmissions
+ */
+static int s3c_hsotg_udc_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
{
- struct s3c_hsotg *hsotg = our_hsotg;
+ struct s3c_hsotg *hsotg = to_hsotg(gadget);
int ep;
if (!hsotg)
@@ -2755,16 +2997,15 @@ static int s3c_hsotg_stop(struct usb_gadget_driver *driver)
return -EINVAL;
/* all endpoints should be shutdown */
- for (ep = 0; ep < S3C_HSOTG_EPS; ep++)
+ for (ep = 0; ep < hsotg->num_of_eps; ep++)
s3c_hsotg_ep_disable(&hsotg->eps[ep].ep);
- call_gadget(hsotg, disconnect);
+ s3c_hsotg_phy_disable(hsotg);
+ regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
- driver->unbind(&hsotg->gadget);
hsotg->driver = NULL;
hsotg->gadget.speed = USB_SPEED_UNKNOWN;
-
- device_del(&hsotg->gadget.dev);
+ hsotg->gadget.dev.driver = NULL;
dev_info(hsotg->dev, "unregistered gadget driver '%s'\n",
driver->driver.name);
@@ -2772,6 +3013,12 @@ static int s3c_hsotg_stop(struct usb_gadget_driver *driver)
return 0;
}
+/**
+ * s3c_hsotg_gadget_getframe - read the frame number
+ * @gadget: The usb gadget state
+ *
+ * Read the {micro} frame number
+ */
static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget)
{
return s3c_hsotg_read_frameno(to_hsotg(gadget));
@@ -2779,8 +3026,8 @@ static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget)
static struct usb_gadget_ops s3c_hsotg_gadget_ops = {
.get_frame = s3c_hsotg_gadget_getframe,
- .start = s3c_hsotg_start,
- .stop = s3c_hsotg_stop,
+ .udc_start = s3c_hsotg_udc_start,
+ .udc_stop = s3c_hsotg_udc_stop,
};
/**
@@ -2827,111 +3074,42 @@ static void __devinit s3c_hsotg_initep(struct s3c_hsotg *hsotg,
hs_ep->ep.maxpacket = epnum ? 512 : EP0_MPS_LIMIT;
hs_ep->ep.ops = &s3c_hsotg_ep_ops;
- /* Read the FIFO size for the Periodic TX FIFO, even if we're
+ /*
+ * Read the FIFO size for the Periodic TX FIFO, even if we're
* an OUT endpoint, we may as well do this if in future the
* code is changed to make each endpoint's direction changeable.
*/
- ptxfifo = readl(hsotg->regs + S3C_DPTXFSIZn(epnum));
- hs_ep->fifo_size = S3C_DPTXFSIZn_DPTxFSize_GET(ptxfifo) * 4;
+ ptxfifo = readl(hsotg->regs + DPTXFSIZn(epnum));
+ hs_ep->fifo_size = DPTXFSIZn_DPTxFSize_GET(ptxfifo) * 4;
- /* if we're using dma, we need to set the next-endpoint pointer
+ /*
+ * if we're using dma, we need to set the next-endpoint pointer
* to be something valid.
*/
if (using_dma(hsotg)) {
- u32 next = S3C_DxEPCTL_NextEp((epnum + 1) % 15);
- writel(next, hsotg->regs + S3C_DIEPCTL(epnum));
- writel(next, hsotg->regs + S3C_DOEPCTL(epnum));
+ u32 next = DxEPCTL_NextEp((epnum + 1) % 15);
+ writel(next, hsotg->regs + DIEPCTL(epnum));
+ writel(next, hsotg->regs + DOEPCTL(epnum));
}
}
/**
- * s3c_hsotg_otgreset - reset the OtG phy block
- * @hsotg: The host state.
+ * s3c_hsotg_hw_cfg - read HW configuration registers
+ * @param: The device state
*
- * Power up the phy, set the basic configuration and start the PHY.
+ * Read the USB core HW configuration registers
*/
-static void s3c_hsotg_otgreset(struct s3c_hsotg *hsotg)
-{
- struct clk *xusbxti;
- u32 pwr, osc;
-
- pwr = readl(S3C_PHYPWR);
- pwr &= ~0x19;
- writel(pwr, S3C_PHYPWR);
- mdelay(1);
-
- osc = hsotg->plat->is_osc ? S3C_PHYCLK_EXT_OSC : 0;
-
- xusbxti = clk_get(hsotg->dev, "xusbxti");
- if (xusbxti && !IS_ERR(xusbxti)) {
- switch (clk_get_rate(xusbxti)) {
- case 12*MHZ:
- osc |= S3C_PHYCLK_CLKSEL_12M;
- break;
- case 24*MHZ:
- osc |= S3C_PHYCLK_CLKSEL_24M;
- break;
- default:
- case 48*MHZ:
- /* default reference clock */
- break;
- }
- clk_put(xusbxti);
- }
-
- writel(osc | 0x10, S3C_PHYCLK);
-
- /* issue a full set of resets to the otg and core */
-
- writel(S3C_RSTCON_PHY, S3C_RSTCON);
- udelay(20); /* at-least 10uS */
- writel(0, S3C_RSTCON);
-}
-
-
-static void s3c_hsotg_init(struct s3c_hsotg *hsotg)
+static void s3c_hsotg_hw_cfg(struct s3c_hsotg *hsotg)
{
- u32 cfg4;
-
- /* unmask subset of endpoint interrupts */
-
- writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk |
- S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk,
- hsotg->regs + S3C_DIEPMSK);
-
- writel(S3C_DOEPMSK_SetupMsk | S3C_DOEPMSK_AHBErrMsk |
- S3C_DOEPMSK_EPDisbldMsk | S3C_DOEPMSK_XferComplMsk,
- hsotg->regs + S3C_DOEPMSK);
-
- writel(0, hsotg->regs + S3C_DAINTMSK);
-
- /* Be in disconnected state until gadget is registered */
- __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon);
-
- if (0) {
- /* post global nak until we're ready */
- writel(S3C_DCTL_SGNPInNAK | S3C_DCTL_SGOUTNak,
- hsotg->regs + S3C_DCTL);
- }
-
- /* setup fifos */
-
- dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n",
- readl(hsotg->regs + S3C_GRXFSIZ),
- readl(hsotg->regs + S3C_GNPTXFSIZ));
-
- s3c_hsotg_init_fifo(hsotg);
-
- /* set the PLL on, remove the HNP/SRP and set the PHY */
- writel(S3C_GUSBCFG_PHYIf16 | S3C_GUSBCFG_TOutCal(7) | (0x5 << 10),
- hsotg->regs + S3C_GUSBCFG);
+ u32 cfg2, cfg4;
+ /* check hardware configuration */
- writel(using_dma(hsotg) ? S3C_GAHBCFG_DMAEn : 0x0,
- hsotg->regs + S3C_GAHBCFG);
+ cfg2 = readl(hsotg->regs + 0x48);
+ hsotg->num_of_eps = (cfg2 >> 10) & 0xF;
- /* check hardware configuration */
+ dev_info(hsotg->dev, "EPs:%d\n", hsotg->num_of_eps);
cfg4 = readl(hsotg->regs + 0x50);
hsotg->dedicated_fifos = (cfg4 >> 25) & 1;
@@ -2940,6 +3118,10 @@ static void s3c_hsotg_init(struct s3c_hsotg *hsotg)
hsotg->dedicated_fifos ? "dedicated" : "shared");
}
+/**
+ * s3c_hsotg_dump - dump state of the udc
+ * @param: The device state
+ */
static void s3c_hsotg_dump(struct s3c_hsotg *hsotg)
{
#ifdef DEBUG
@@ -2949,46 +3131,45 @@ static void s3c_hsotg_dump(struct s3c_hsotg *hsotg)
int idx;
dev_info(dev, "DCFG=0x%08x, DCTL=0x%08x, DIEPMSK=%08x\n",
- readl(regs + S3C_DCFG), readl(regs + S3C_DCTL),
- readl(regs + S3C_DIEPMSK));
+ readl(regs + DCFG), readl(regs + DCTL),
+ readl(regs + DIEPMSK));
dev_info(dev, "GAHBCFG=0x%08x, 0x44=0x%08x\n",
- readl(regs + S3C_GAHBCFG), readl(regs + 0x44));
+ readl(regs + GAHBCFG), readl(regs + 0x44));
dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n",
- readl(regs + S3C_GRXFSIZ), readl(regs + S3C_GNPTXFSIZ));
+ readl(regs + GRXFSIZ), readl(regs + GNPTXFSIZ));
/* show periodic fifo settings */
for (idx = 1; idx <= 15; idx++) {
- val = readl(regs + S3C_DPTXFSIZn(idx));
+ val = readl(regs + DPTXFSIZn(idx));
dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx,
- val >> S3C_DPTXFSIZn_DPTxFSize_SHIFT,
- val & S3C_DPTXFSIZn_DPTxFStAddr_MASK);
+ val >> DPTXFSIZn_DPTxFSize_SHIFT,
+ val & DPTXFSIZn_DPTxFStAddr_MASK);
}
for (idx = 0; idx < 15; idx++) {
dev_info(dev,
"ep%d-in: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", idx,
- readl(regs + S3C_DIEPCTL(idx)),
- readl(regs + S3C_DIEPTSIZ(idx)),
- readl(regs + S3C_DIEPDMA(idx)));
+ readl(regs + DIEPCTL(idx)),
+ readl(regs + DIEPTSIZ(idx)),
+ readl(regs + DIEPDMA(idx)));
- val = readl(regs + S3C_DOEPCTL(idx));
+ val = readl(regs + DOEPCTL(idx));
dev_info(dev,
"ep%d-out: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n",
- idx, readl(regs + S3C_DOEPCTL(idx)),
- readl(regs + S3C_DOEPTSIZ(idx)),
- readl(regs + S3C_DOEPDMA(idx)));
+ idx, readl(regs + DOEPCTL(idx)),
+ readl(regs + DOEPTSIZ(idx)),
+ readl(regs + DOEPDMA(idx)));
}
dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n",
- readl(regs + S3C_DVBUSDIS), readl(regs + S3C_DVBUSPULSE));
+ readl(regs + DVBUSDIS), readl(regs + DVBUSPULSE));
#endif
}
-
/**
* state_show - debugfs: show overall driver and device state.
* @seq: The seq file to write to.
@@ -3005,38 +3186,38 @@ static int state_show(struct seq_file *seq, void *v)
int idx;
seq_printf(seq, "DCFG=0x%08x, DCTL=0x%08x, DSTS=0x%08x\n",
- readl(regs + S3C_DCFG),
- readl(regs + S3C_DCTL),
- readl(regs + S3C_DSTS));
+ readl(regs + DCFG),
+ readl(regs + DCTL),
+ readl(regs + DSTS));
seq_printf(seq, "DIEPMSK=0x%08x, DOEPMASK=0x%08x\n",
- readl(regs + S3C_DIEPMSK), readl(regs + S3C_DOEPMSK));
+ readl(regs + DIEPMSK), readl(regs + DOEPMSK));
seq_printf(seq, "GINTMSK=0x%08x, GINTSTS=0x%08x\n",
- readl(regs + S3C_GINTMSK),
- readl(regs + S3C_GINTSTS));
+ readl(regs + GINTMSK),
+ readl(regs + GINTSTS));
seq_printf(seq, "DAINTMSK=0x%08x, DAINT=0x%08x\n",
- readl(regs + S3C_DAINTMSK),
- readl(regs + S3C_DAINT));
+ readl(regs + DAINTMSK),
+ readl(regs + DAINT));
seq_printf(seq, "GNPTXSTS=0x%08x, GRXSTSR=%08x\n",
- readl(regs + S3C_GNPTXSTS),
- readl(regs + S3C_GRXSTSR));
+ readl(regs + GNPTXSTS),
+ readl(regs + GRXSTSR));
seq_printf(seq, "\nEndpoint status:\n");
for (idx = 0; idx < 15; idx++) {
u32 in, out;
- in = readl(regs + S3C_DIEPCTL(idx));
- out = readl(regs + S3C_DOEPCTL(idx));
+ in = readl(regs + DIEPCTL(idx));
+ out = readl(regs + DOEPCTL(idx));
seq_printf(seq, "ep%d: DIEPCTL=0x%08x, DOEPCTL=0x%08x",
idx, in, out);
- in = readl(regs + S3C_DIEPTSIZ(idx));
- out = readl(regs + S3C_DOEPTSIZ(idx));
+ in = readl(regs + DIEPTSIZ(idx));
+ out = readl(regs + DOEPTSIZ(idx));
seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x",
in, out);
@@ -3067,7 +3248,7 @@ static const struct file_operations state_fops = {
*
* Show the FIFO information for the overall fifo and all the
* periodic transmission FIFOs.
-*/
+ */
static int fifo_show(struct seq_file *seq, void *v)
{
struct s3c_hsotg *hsotg = seq->private;
@@ -3076,21 +3257,21 @@ static int fifo_show(struct seq_file *seq, void *v)
int idx;
seq_printf(seq, "Non-periodic FIFOs:\n");
- seq_printf(seq, "RXFIFO: Size %d\n", readl(regs + S3C_GRXFSIZ));
+ seq_printf(seq, "RXFIFO: Size %d\n", readl(regs + GRXFSIZ));
- val = readl(regs + S3C_GNPTXFSIZ);
+ val = readl(regs + GNPTXFSIZ);
seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n",
- val >> S3C_GNPTXFSIZ_NPTxFDep_SHIFT,
- val & S3C_GNPTXFSIZ_NPTxFStAddr_MASK);
+ val >> GNPTXFSIZ_NPTxFDep_SHIFT,
+ val & GNPTXFSIZ_NPTxFStAddr_MASK);
seq_printf(seq, "\nPeriodic TXFIFOs:\n");
for (idx = 1; idx <= 15; idx++) {
- val = readl(regs + S3C_DPTXFSIZn(idx));
+ val = readl(regs + DPTXFSIZn(idx));
seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx,
- val >> S3C_DPTXFSIZn_DPTxFSize_SHIFT,
- val & S3C_DPTXFSIZn_DPTxFStAddr_MASK);
+ val >> DPTXFSIZn_DPTxFSize_SHIFT,
+ val & DPTXFSIZn_DPTxFStAddr_MASK);
}
return 0;
@@ -3122,7 +3303,7 @@ static const char *decode_direction(int is_in)
*
* This debugfs entry shows the state of the given endpoint (one is
* registered for each available).
-*/
+ */
static int ep_show(struct seq_file *seq, void *v)
{
struct s3c_hsotg_ep *ep = seq->private;
@@ -3139,20 +3320,20 @@ static int ep_show(struct seq_file *seq, void *v)
/* first show the register state */
seq_printf(seq, "\tDIEPCTL=0x%08x, DOEPCTL=0x%08x\n",
- readl(regs + S3C_DIEPCTL(index)),
- readl(regs + S3C_DOEPCTL(index)));
+ readl(regs + DIEPCTL(index)),
+ readl(regs + DOEPCTL(index)));
seq_printf(seq, "\tDIEPDMA=0x%08x, DOEPDMA=0x%08x\n",
- readl(regs + S3C_DIEPDMA(index)),
- readl(regs + S3C_DOEPDMA(index)));
+ readl(regs + DIEPDMA(index)),
+ readl(regs + DOEPDMA(index)));
seq_printf(seq, "\tDIEPINT=0x%08x, DOEPINT=0x%08x\n",
- readl(regs + S3C_DIEPINT(index)),
- readl(regs + S3C_DOEPINT(index)));
+ readl(regs + DIEPINT(index)),
+ readl(regs + DOEPINT(index)));
seq_printf(seq, "\tDIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x\n",
- readl(regs + S3C_DIEPTSIZ(index)),
- readl(regs + S3C_DOEPTSIZ(index)));
+ readl(regs + DIEPTSIZ(index)),
+ readl(regs + DOEPTSIZ(index)));
seq_printf(seq, "\n");
seq_printf(seq, "mps %d\n", ep->ep.maxpacket);
@@ -3202,7 +3383,7 @@ static const struct file_operations ep_fops = {
* about the state of the system. The directory name is created
* with the same name as the device itself, in case we end up
* with multiple blocks in future systems.
-*/
+ */
static void __devinit s3c_hsotg_create_debug(struct s3c_hsotg *hsotg)
{
struct dentry *root;
@@ -3231,7 +3412,7 @@ static void __devinit s3c_hsotg_create_debug(struct s3c_hsotg *hsotg)
/* create one file for each endpoint */
- for (epidx = 0; epidx < S3C_HSOTG_EPS; epidx++) {
+ for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) {
struct s3c_hsotg_ep *ep = &hsotg->eps[epidx];
ep->debugfs = debugfs_create_file(ep->name, 0444,
@@ -3248,12 +3429,12 @@ static void __devinit s3c_hsotg_create_debug(struct s3c_hsotg *hsotg)
* @hsotg: The driver state
*
* Cleanup (remove) the debugfs files for use on module exit.
-*/
+ */
static void __devexit s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
{
unsigned epidx;
- for (epidx = 0; epidx < S3C_HSOTG_EPS; epidx++) {
+ for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) {
struct s3c_hsotg_ep *ep = &hsotg->eps[epidx];
debugfs_remove(ep->debugfs);
}
@@ -3264,48 +3445,39 @@ static void __devexit s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)
}
/**
- * s3c_hsotg_gate - set the hardware gate for the block
- * @pdev: The device we bound to
- * @on: On or off.
- *
- * Set the hardware gate setting into the block. If we end up on
- * something other than an S3C64XX, then we might need to change this
- * to using a platform data callback, or some other mechanism.
+ * s3c_hsotg_release - release callback for hsotg device
+ * @dev: Device to for which release is called
*/
-static void s3c_hsotg_gate(struct platform_device *pdev, bool on)
+static void s3c_hsotg_release(struct device *dev)
{
- unsigned long flags;
- u32 others;
-
- local_irq_save(flags);
-
- others = __raw_readl(S3C64XX_OTHERS);
- if (on)
- others |= S3C64XX_OTHERS_USBMASK;
- else
- others &= ~S3C64XX_OTHERS_USBMASK;
- __raw_writel(others, S3C64XX_OTHERS);
+ struct s3c_hsotg *hsotg = dev_get_drvdata(dev);
- local_irq_restore(flags);
+ kfree(hsotg);
}
-static struct s3c_hsotg_plat s3c_hsotg_default_pdata;
+/**
+ * s3c_hsotg_probe - probe function for hsotg driver
+ * @pdev: The platform information for the driver
+ */
static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
{
struct s3c_hsotg_plat *plat = pdev->dev.platform_data;
struct device *dev = &pdev->dev;
+ struct s3c_hsotg_ep *eps;
struct s3c_hsotg *hsotg;
struct resource *res;
int epnum;
int ret;
+ int i;
- if (!plat)
- plat = &s3c_hsotg_default_pdata;
+ plat = pdev->dev.platform_data;
+ if (!plat) {
+ dev_err(&pdev->dev, "no platform data defined\n");
+ return -EINVAL;
+ }
- hsotg = kzalloc(sizeof(struct s3c_hsotg) +
- sizeof(struct s3c_hsotg_ep) * S3C_HSOTG_EPS,
- GFP_KERNEL);
+ hsotg = kzalloc(sizeof(struct s3c_hsotg), GFP_KERNEL);
if (!hsotg) {
dev_err(dev, "cannot get memory\n");
return -ENOMEM;
@@ -3371,6 +3543,54 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
hsotg->gadget.dev.parent = dev;
hsotg->gadget.dev.dma_mask = dev->dma_mask;
+ hsotg->gadget.dev.release = s3c_hsotg_release;
+
+ /* reset the system */
+
+ clk_prepare_enable(hsotg->clk);
+
+ /* regulators */
+
+ for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++)
+ hsotg->supplies[i].supply = s3c_hsotg_supply_names[i];
+
+ ret = regulator_bulk_get(dev, ARRAY_SIZE(hsotg->supplies),
+ hsotg->supplies);
+ if (ret) {
+ dev_err(dev, "failed to request supplies: %d\n", ret);
+ goto err_irq;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies),
+ hsotg->supplies);
+
+ if (ret) {
+ dev_err(hsotg->dev, "failed to enable supplies: %d\n", ret);
+ goto err_supplies;
+ }
+
+ /* usb phy enable */
+ s3c_hsotg_phy_enable(hsotg);
+
+ s3c_hsotg_corereset(hsotg);
+ s3c_hsotg_init(hsotg);
+ s3c_hsotg_hw_cfg(hsotg);
+
+ /* hsotg->num_of_eps holds number of EPs other than ep0 */
+
+ if (hsotg->num_of_eps == 0) {
+ dev_err(dev, "wrong number of EPs (zero)\n");
+ goto err_supplies;
+ }
+
+ eps = kcalloc(hsotg->num_of_eps + 1, sizeof(struct s3c_hsotg_ep),
+ GFP_KERNEL);
+ if (!eps) {
+ dev_err(dev, "cannot get memory\n");
+ goto err_supplies;
+ }
+
+ hsotg->eps = eps;
/* setup endpoint information */
@@ -3383,39 +3603,47 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
GFP_KERNEL);
if (!hsotg->ctrl_req) {
dev_err(dev, "failed to allocate ctrl req\n");
- goto err_regs;
+ goto err_ep_mem;
}
- /* reset the system */
+ /* initialise the endpoints now the core has been initialised */
+ for (epnum = 0; epnum < hsotg->num_of_eps; epnum++)
+ s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum);
- clk_enable(hsotg->clk);
+ /* disable power and clock */
- s3c_hsotg_gate(pdev, true);
+ ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
+ hsotg->supplies);
+ if (ret) {
+ dev_err(hsotg->dev, "failed to disable supplies: %d\n", ret);
+ goto err_ep_mem;
+ }
- s3c_hsotg_otgreset(hsotg);
- s3c_hsotg_corereset(hsotg);
- s3c_hsotg_init(hsotg);
+ s3c_hsotg_phy_disable(hsotg);
- /* initialise the endpoints now the core has been initialised */
- for (epnum = 0; epnum < S3C_HSOTG_EPS; epnum++)
- s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum);
+ ret = device_add(&hsotg->gadget.dev);
+ if (ret) {
+ put_device(&hsotg->gadget.dev);
+ goto err_ep_mem;
+ }
ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget);
if (ret)
- goto err_add_udc;
+ goto err_ep_mem;
s3c_hsotg_create_debug(hsotg);
s3c_hsotg_dump(hsotg);
- our_hsotg = hsotg;
return 0;
-err_add_udc:
- s3c_hsotg_gate(pdev, false);
- clk_disable(hsotg->clk);
- clk_put(hsotg->clk);
-
+err_ep_mem:
+ kfree(eps);
+err_supplies:
+ s3c_hsotg_phy_disable(hsotg);
+ regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
+err_irq:
+ free_irq(hsotg->irq, hsotg);
err_regs:
iounmap(hsotg->regs);
@@ -3423,12 +3651,17 @@ err_regs_res:
release_resource(hsotg->regs_res);
kfree(hsotg->regs_res);
err_clk:
+ clk_disable_unprepare(hsotg->clk);
clk_put(hsotg->clk);
err_mem:
kfree(hsotg);
return ret;
}
+/**
+ * s3c_hsotg_remove - remove function for hsotg driver
+ * @pdev: The platform information for the driver
+ */
static int __devexit s3c_hsotg_remove(struct platform_device *pdev)
{
struct s3c_hsotg *hsotg = platform_get_drvdata(pdev);
@@ -3437,7 +3670,10 @@ static int __devexit s3c_hsotg_remove(struct platform_device *pdev)
s3c_hsotg_delete_debug(hsotg);
- usb_gadget_unregister_driver(hsotg->driver);
+ if (hsotg->driver) {
+ /* should have been done already by driver model core */
+ usb_gadget_unregister_driver(hsotg->driver);
+ }
free_irq(hsotg->irq, hsotg);
iounmap(hsotg->regs);
@@ -3445,12 +3681,13 @@ static int __devexit s3c_hsotg_remove(struct platform_device *pdev)
release_resource(hsotg->regs_res);
kfree(hsotg->regs_res);
- s3c_hsotg_gate(pdev, false);
+ s3c_hsotg_phy_disable(hsotg);
+ regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
- clk_disable(hsotg->clk);
+ clk_disable_unprepare(hsotg->clk);
clk_put(hsotg->clk);
- kfree(hsotg);
+ device_unregister(&hsotg->gadget.dev);
return 0;
}
diff --git a/drivers/usb/gadget/s3c-hsotg.h b/drivers/usb/gadget/s3c-hsotg.h
new file mode 100644
index 000000000000..d650b1295831
--- /dev/null
+++ b/drivers/usb/gadget/s3c-hsotg.h
@@ -0,0 +1,377 @@
+/* drivers/usb/gadget/s3c-hsotg.h
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * USB2.0 Highspeed/OtG Synopsis DWC2 device block registers
+ *
+ * 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_USB_HSOTG_H
+#define __REGS_USB_HSOTG_H __FILE__
+
+#define HSOTG_REG(x) (x)
+
+#define GOTGCTL HSOTG_REG(0x000)
+#define GOTGCTL_BSESVLD (1 << 19)
+#define GOTGCTL_ASESVLD (1 << 18)
+#define GOTGCTL_DBNC_SHORT (1 << 17)
+#define GOTGCTL_CONID_B (1 << 16)
+#define GOTGCTL_DEVHNPEN (1 << 11)
+#define GOTGCTL_HSSETHNPEN (1 << 10)
+#define GOTGCTL_HNPREQ (1 << 9)
+#define GOTGCTL_HSTNEGSCS (1 << 8)
+#define GOTGCTL_SESREQ (1 << 1)
+#define GOTGCTL_SESREQSCS (1 << 0)
+
+#define GOTGINT HSOTG_REG(0x004)
+#define GOTGINT_DbnceDone (1 << 19)
+#define GOTGINT_ADevTOUTChg (1 << 18)
+#define GOTGINT_HstNegDet (1 << 17)
+#define GOTGINT_HstnegSucStsChng (1 << 9)
+#define GOTGINT_SesReqSucStsChng (1 << 8)
+#define GOTGINT_SesEndDet (1 << 2)
+
+#define GAHBCFG HSOTG_REG(0x008)
+#define GAHBCFG_PTxFEmpLvl (1 << 8)
+#define GAHBCFG_NPTxFEmpLvl (1 << 7)
+#define GAHBCFG_DMAEn (1 << 5)
+#define GAHBCFG_HBstLen_MASK (0xf << 1)
+#define GAHBCFG_HBstLen_SHIFT (1)
+#define GAHBCFG_HBstLen_Single (0x0 << 1)
+#define GAHBCFG_HBstLen_Incr (0x1 << 1)
+#define GAHBCFG_HBstLen_Incr4 (0x3 << 1)
+#define GAHBCFG_HBstLen_Incr8 (0x5 << 1)
+#define GAHBCFG_HBstLen_Incr16 (0x7 << 1)
+#define GAHBCFG_GlblIntrEn (1 << 0)
+
+#define GUSBCFG HSOTG_REG(0x00C)
+#define GUSBCFG_PHYLPClkSel (1 << 15)
+#define GUSBCFG_HNPCap (1 << 9)
+#define GUSBCFG_SRPCap (1 << 8)
+#define GUSBCFG_PHYIf16 (1 << 3)
+#define GUSBCFG_TOutCal_MASK (0x7 << 0)
+#define GUSBCFG_TOutCal_SHIFT (0)
+#define GUSBCFG_TOutCal_LIMIT (0x7)
+#define GUSBCFG_TOutCal(_x) ((_x) << 0)
+
+#define GRSTCTL HSOTG_REG(0x010)
+
+#define GRSTCTL_AHBIdle (1 << 31)
+#define GRSTCTL_DMAReq (1 << 30)
+#define GRSTCTL_TxFNum_MASK (0x1f << 6)
+#define GRSTCTL_TxFNum_SHIFT (6)
+#define GRSTCTL_TxFNum_LIMIT (0x1f)
+#define GRSTCTL_TxFNum(_x) ((_x) << 6)
+#define GRSTCTL_TxFFlsh (1 << 5)
+#define GRSTCTL_RxFFlsh (1 << 4)
+#define GRSTCTL_INTknQFlsh (1 << 3)
+#define GRSTCTL_FrmCntrRst (1 << 2)
+#define GRSTCTL_HSftRst (1 << 1)
+#define GRSTCTL_CSftRst (1 << 0)
+
+#define GINTSTS HSOTG_REG(0x014)
+#define GINTMSK HSOTG_REG(0x018)
+
+#define GINTSTS_WkUpInt (1 << 31)
+#define GINTSTS_SessReqInt (1 << 30)
+#define GINTSTS_DisconnInt (1 << 29)
+#define GINTSTS_ConIDStsChng (1 << 28)
+#define GINTSTS_PTxFEmp (1 << 26)
+#define GINTSTS_HChInt (1 << 25)
+#define GINTSTS_PrtInt (1 << 24)
+#define GINTSTS_FetSusp (1 << 22)
+#define GINTSTS_incompIP (1 << 21)
+#define GINTSTS_IncomplSOIN (1 << 20)
+#define GINTSTS_OEPInt (1 << 19)
+#define GINTSTS_IEPInt (1 << 18)
+#define GINTSTS_EPMis (1 << 17)
+#define GINTSTS_EOPF (1 << 15)
+#define GINTSTS_ISOutDrop (1 << 14)
+#define GINTSTS_EnumDone (1 << 13)
+#define GINTSTS_USBRst (1 << 12)
+#define GINTSTS_USBSusp (1 << 11)
+#define GINTSTS_ErlySusp (1 << 10)
+#define GINTSTS_GOUTNakEff (1 << 7)
+#define GINTSTS_GINNakEff (1 << 6)
+#define GINTSTS_NPTxFEmp (1 << 5)
+#define GINTSTS_RxFLvl (1 << 4)
+#define GINTSTS_SOF (1 << 3)
+#define GINTSTS_OTGInt (1 << 2)
+#define GINTSTS_ModeMis (1 << 1)
+#define GINTSTS_CurMod_Host (1 << 0)
+
+#define GRXSTSR HSOTG_REG(0x01C)
+#define GRXSTSP HSOTG_REG(0x020)
+
+#define GRXSTS_FN_MASK (0x7f << 25)
+#define GRXSTS_FN_SHIFT (25)
+
+#define GRXSTS_PktSts_MASK (0xf << 17)
+#define GRXSTS_PktSts_SHIFT (17)
+#define GRXSTS_PktSts_GlobalOutNAK (0x1 << 17)
+#define GRXSTS_PktSts_OutRX (0x2 << 17)
+#define GRXSTS_PktSts_OutDone (0x3 << 17)
+#define GRXSTS_PktSts_SetupDone (0x4 << 17)
+#define GRXSTS_PktSts_SetupRX (0x6 << 17)
+
+#define GRXSTS_DPID_MASK (0x3 << 15)
+#define GRXSTS_DPID_SHIFT (15)
+#define GRXSTS_ByteCnt_MASK (0x7ff << 4)
+#define GRXSTS_ByteCnt_SHIFT (4)
+#define GRXSTS_EPNum_MASK (0xf << 0)
+#define GRXSTS_EPNum_SHIFT (0)
+
+#define GRXFSIZ HSOTG_REG(0x024)
+
+#define GNPTXFSIZ HSOTG_REG(0x028)
+
+#define GNPTXFSIZ_NPTxFDep_MASK (0xffff << 16)
+#define GNPTXFSIZ_NPTxFDep_SHIFT (16)
+#define GNPTXFSIZ_NPTxFDep_LIMIT (0xffff)
+#define GNPTXFSIZ_NPTxFDep(_x) ((_x) << 16)
+#define GNPTXFSIZ_NPTxFStAddr_MASK (0xffff << 0)
+#define GNPTXFSIZ_NPTxFStAddr_SHIFT (0)
+#define GNPTXFSIZ_NPTxFStAddr_LIMIT (0xffff)
+#define GNPTXFSIZ_NPTxFStAddr(_x) ((_x) << 0)
+
+#define GNPTXSTS HSOTG_REG(0x02C)
+
+#define GNPTXSTS_NPtxQTop_MASK (0x7f << 24)
+#define GNPTXSTS_NPtxQTop_SHIFT (24)
+
+#define GNPTXSTS_NPTxQSpcAvail_MASK (0xff << 16)
+#define GNPTXSTS_NPTxQSpcAvail_SHIFT (16)
+#define GNPTXSTS_NPTxQSpcAvail_GET(_v) (((_v) >> 16) & 0xff)
+
+#define GNPTXSTS_NPTxFSpcAvail_MASK (0xffff << 0)
+#define GNPTXSTS_NPTxFSpcAvail_SHIFT (0)
+#define GNPTXSTS_NPTxFSpcAvail_GET(_v) (((_v) >> 0) & 0xffff)
+
+
+#define HPTXFSIZ HSOTG_REG(0x100)
+
+#define DPTXFSIZn(_a) HSOTG_REG(0x104 + (((_a) - 1) * 4))
+
+#define DPTXFSIZn_DPTxFSize_MASK (0xffff << 16)
+#define DPTXFSIZn_DPTxFSize_SHIFT (16)
+#define DPTXFSIZn_DPTxFSize_GET(_v) (((_v) >> 16) & 0xffff)
+#define DPTXFSIZn_DPTxFSize_LIMIT (0xffff)
+#define DPTXFSIZn_DPTxFSize(_x) ((_x) << 16)
+
+#define DPTXFSIZn_DPTxFStAddr_MASK (0xffff << 0)
+#define DPTXFSIZn_DPTxFStAddr_SHIFT (0)
+
+/* Device mode registers */
+#define DCFG HSOTG_REG(0x800)
+
+#define DCFG_EPMisCnt_MASK (0x1f << 18)
+#define DCFG_EPMisCnt_SHIFT (18)
+#define DCFG_EPMisCnt_LIMIT (0x1f)
+#define DCFG_EPMisCnt(_x) ((_x) << 18)
+
+#define DCFG_PerFrInt_MASK (0x3 << 11)
+#define DCFG_PerFrInt_SHIFT (11)
+#define DCFG_PerFrInt_LIMIT (0x3)
+#define DCFG_PerFrInt(_x) ((_x) << 11)
+
+#define DCFG_DevAddr_MASK (0x7f << 4)
+#define DCFG_DevAddr_SHIFT (4)
+#define DCFG_DevAddr_LIMIT (0x7f)
+#define DCFG_DevAddr(_x) ((_x) << 4)
+
+#define DCFG_NZStsOUTHShk (1 << 2)
+
+#define DCFG_DevSpd_MASK (0x3 << 0)
+#define DCFG_DevSpd_SHIFT (0)
+#define DCFG_DevSpd_HS (0x0 << 0)
+#define DCFG_DevSpd_FS (0x1 << 0)
+#define DCFG_DevSpd_LS (0x2 << 0)
+#define DCFG_DevSpd_FS48 (0x3 << 0)
+
+#define DCTL HSOTG_REG(0x804)
+
+#define DCTL_PWROnPrgDone (1 << 11)
+#define DCTL_CGOUTNak (1 << 10)
+#define DCTL_SGOUTNak (1 << 9)
+#define DCTL_CGNPInNAK (1 << 8)
+#define DCTL_SGNPInNAK (1 << 7)
+#define DCTL_TstCtl_MASK (0x7 << 4)
+#define DCTL_TstCtl_SHIFT (4)
+#define DCTL_GOUTNakSts (1 << 3)
+#define DCTL_GNPINNakSts (1 << 2)
+#define DCTL_SftDiscon (1 << 1)
+#define DCTL_RmtWkUpSig (1 << 0)
+
+#define DSTS HSOTG_REG(0x808)
+
+#define DSTS_SOFFN_MASK (0x3fff << 8)
+#define DSTS_SOFFN_SHIFT (8)
+#define DSTS_SOFFN_LIMIT (0x3fff)
+#define DSTS_SOFFN(_x) ((_x) << 8)
+#define DSTS_ErraticErr (1 << 3)
+#define DSTS_EnumSpd_MASK (0x3 << 1)
+#define DSTS_EnumSpd_SHIFT (1)
+#define DSTS_EnumSpd_HS (0x0 << 1)
+#define DSTS_EnumSpd_FS (0x1 << 1)
+#define DSTS_EnumSpd_LS (0x2 << 1)
+#define DSTS_EnumSpd_FS48 (0x3 << 1)
+
+#define DSTS_SuspSts (1 << 0)
+
+#define DIEPMSK HSOTG_REG(0x810)
+
+#define DIEPMSK_TxFIFOEmpty (1 << 7)
+#define DIEPMSK_INEPNakEffMsk (1 << 6)
+#define DIEPMSK_INTknEPMisMsk (1 << 5)
+#define DIEPMSK_INTknTXFEmpMsk (1 << 4)
+#define DIEPMSK_TimeOUTMsk (1 << 3)
+#define DIEPMSK_AHBErrMsk (1 << 2)
+#define DIEPMSK_EPDisbldMsk (1 << 1)
+#define DIEPMSK_XferComplMsk (1 << 0)
+
+#define DOEPMSK HSOTG_REG(0x814)
+
+#define DOEPMSK_Back2BackSetup (1 << 6)
+#define DOEPMSK_OUTTknEPdisMsk (1 << 4)
+#define DOEPMSK_SetupMsk (1 << 3)
+#define DOEPMSK_AHBErrMsk (1 << 2)
+#define DOEPMSK_EPDisbldMsk (1 << 1)
+#define DOEPMSK_XferComplMsk (1 << 0)
+
+#define DAINT HSOTG_REG(0x818)
+#define DAINTMSK HSOTG_REG(0x81C)
+
+#define DAINT_OutEP_SHIFT (16)
+#define DAINT_OutEP(x) (1 << ((x) + 16))
+#define DAINT_InEP(x) (1 << (x))
+
+#define DTKNQR1 HSOTG_REG(0x820)
+#define DTKNQR2 HSOTG_REG(0x824)
+#define DTKNQR3 HSOTG_REG(0x830)
+#define DTKNQR4 HSOTG_REG(0x834)
+
+#define DVBUSDIS HSOTG_REG(0x828)
+#define DVBUSPULSE HSOTG_REG(0x82C)
+
+#define DIEPCTL0 HSOTG_REG(0x900)
+#define DOEPCTL0 HSOTG_REG(0xB00)
+#define DIEPCTL(_a) HSOTG_REG(0x900 + ((_a) * 0x20))
+#define DOEPCTL(_a) HSOTG_REG(0xB00 + ((_a) * 0x20))
+
+/* EP0 specialness:
+ * bits[29..28] - reserved (no SetD0PID, SetD1PID)
+ * bits[25..22] - should always be zero, this isn't a periodic endpoint
+ * bits[10..0] - MPS setting differenct for EP0
+ */
+#define D0EPCTL_MPS_MASK (0x3 << 0)
+#define D0EPCTL_MPS_SHIFT (0)
+#define D0EPCTL_MPS_64 (0x0 << 0)
+#define D0EPCTL_MPS_32 (0x1 << 0)
+#define D0EPCTL_MPS_16 (0x2 << 0)
+#define D0EPCTL_MPS_8 (0x3 << 0)
+
+#define DxEPCTL_EPEna (1 << 31)
+#define DxEPCTL_EPDis (1 << 30)
+#define DxEPCTL_SetD1PID (1 << 29)
+#define DxEPCTL_SetOddFr (1 << 29)
+#define DxEPCTL_SetD0PID (1 << 28)
+#define DxEPCTL_SetEvenFr (1 << 28)
+#define DxEPCTL_SNAK (1 << 27)
+#define DxEPCTL_CNAK (1 << 26)
+#define DxEPCTL_TxFNum_MASK (0xf << 22)
+#define DxEPCTL_TxFNum_SHIFT (22)
+#define DxEPCTL_TxFNum_LIMIT (0xf)
+#define DxEPCTL_TxFNum(_x) ((_x) << 22)
+
+#define DxEPCTL_Stall (1 << 21)
+#define DxEPCTL_Snp (1 << 20)
+#define DxEPCTL_EPType_MASK (0x3 << 18)
+#define DxEPCTL_EPType_SHIFT (18)
+#define DxEPCTL_EPType_Control (0x0 << 18)
+#define DxEPCTL_EPType_Iso (0x1 << 18)
+#define DxEPCTL_EPType_Bulk (0x2 << 18)
+#define DxEPCTL_EPType_Intterupt (0x3 << 18)
+
+#define DxEPCTL_NAKsts (1 << 17)
+#define DxEPCTL_DPID (1 << 16)
+#define DxEPCTL_EOFrNum (1 << 16)
+#define DxEPCTL_USBActEp (1 << 15)
+#define DxEPCTL_NextEp_MASK (0xf << 11)
+#define DxEPCTL_NextEp_SHIFT (11)
+#define DxEPCTL_NextEp_LIMIT (0xf)
+#define DxEPCTL_NextEp(_x) ((_x) << 11)
+
+#define DxEPCTL_MPS_MASK (0x7ff << 0)
+#define DxEPCTL_MPS_SHIFT (0)
+#define DxEPCTL_MPS_LIMIT (0x7ff)
+#define DxEPCTL_MPS(_x) ((_x) << 0)
+
+#define DIEPINT(_a) HSOTG_REG(0x908 + ((_a) * 0x20))
+#define DOEPINT(_a) HSOTG_REG(0xB08 + ((_a) * 0x20))
+
+#define DxEPINT_INEPNakEff (1 << 6)
+#define DxEPINT_Back2BackSetup (1 << 6)
+#define DxEPINT_INTknEPMis (1 << 5)
+#define DxEPINT_INTknTXFEmp (1 << 4)
+#define DxEPINT_OUTTknEPdis (1 << 4)
+#define DxEPINT_Timeout (1 << 3)
+#define DxEPINT_Setup (1 << 3)
+#define DxEPINT_AHBErr (1 << 2)
+#define DxEPINT_EPDisbld (1 << 1)
+#define DxEPINT_XferCompl (1 << 0)
+
+#define DIEPTSIZ0 HSOTG_REG(0x910)
+
+#define DIEPTSIZ0_PktCnt_MASK (0x3 << 19)
+#define DIEPTSIZ0_PktCnt_SHIFT (19)
+#define DIEPTSIZ0_PktCnt_LIMIT (0x3)
+#define DIEPTSIZ0_PktCnt(_x) ((_x) << 19)
+
+#define DIEPTSIZ0_XferSize_MASK (0x7f << 0)
+#define DIEPTSIZ0_XferSize_SHIFT (0)
+#define DIEPTSIZ0_XferSize_LIMIT (0x7f)
+#define DIEPTSIZ0_XferSize(_x) ((_x) << 0)
+
+#define DOEPTSIZ0 HSOTG_REG(0xB10)
+#define DOEPTSIZ0_SUPCnt_MASK (0x3 << 29)
+#define DOEPTSIZ0_SUPCnt_SHIFT (29)
+#define DOEPTSIZ0_SUPCnt_LIMIT (0x3)
+#define DOEPTSIZ0_SUPCnt(_x) ((_x) << 29)
+
+#define DOEPTSIZ0_PktCnt (1 << 19)
+#define DOEPTSIZ0_XferSize_MASK (0x7f << 0)
+#define DOEPTSIZ0_XferSize_SHIFT (0)
+
+#define DIEPTSIZ(_a) HSOTG_REG(0x910 + ((_a) * 0x20))
+#define DOEPTSIZ(_a) HSOTG_REG(0xB10 + ((_a) * 0x20))
+
+#define DxEPTSIZ_MC_MASK (0x3 << 29)
+#define DxEPTSIZ_MC_SHIFT (29)
+#define DxEPTSIZ_MC_LIMIT (0x3)
+#define DxEPTSIZ_MC(_x) ((_x) << 29)
+
+#define DxEPTSIZ_PktCnt_MASK (0x3ff << 19)
+#define DxEPTSIZ_PktCnt_SHIFT (19)
+#define DxEPTSIZ_PktCnt_GET(_v) (((_v) >> 19) & 0x3ff)
+#define DxEPTSIZ_PktCnt_LIMIT (0x3ff)
+#define DxEPTSIZ_PktCnt(_x) ((_x) << 19)
+
+#define DxEPTSIZ_XferSize_MASK (0x7ffff << 0)
+#define DxEPTSIZ_XferSize_SHIFT (0)
+#define DxEPTSIZ_XferSize_GET(_v) (((_v) >> 0) & 0x7ffff)
+#define DxEPTSIZ_XferSize_LIMIT (0x7ffff)
+#define DxEPTSIZ_XferSize(_x) ((_x) << 0)
+
+#define DIEPDMA(_a) HSOTG_REG(0x914 + ((_a) * 0x20))
+#define DOEPDMA(_a) HSOTG_REG(0xB14 + ((_a) * 0x20))
+#define DTXFSTS(_a) HSOTG_REG(0x918 + ((_a) * 0x20))
+
+#define EPFIFO(_a) HSOTG_REG(0x1000 + ((_a) * 0x1000))
+
+#endif /* __REGS_USB_HSOTG_H */
diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c
index cef9b82ff911..36c6836eeb0f 100644
--- a/drivers/usb/gadget/s3c-hsudc.c
+++ b/drivers/usb/gadget/s3c-hsudc.c
@@ -110,7 +110,6 @@ struct s3c_hsudc_ep {
struct usb_ep ep;
char name[20];
struct s3c_hsudc *dev;
- const struct usb_endpoint_descriptor *desc;
struct list_head queue;
u8 stopped;
u8 wedge;
@@ -761,7 +760,7 @@ static int s3c_hsudc_ep_enable(struct usb_ep *_ep,
u32 ecr = 0;
hsep = our_ep(_ep);
- if (!_ep || !desc || hsep->desc || _ep->name == ep0name
+ if (!_ep || !desc || hsep->ep.desc || _ep->name == ep0name
|| desc->bDescriptorType != USB_DT_ENDPOINT
|| hsep->bEndpointAddress != desc->bEndpointAddress
|| ep_maxpacket(hsep) < usb_endpoint_maxp(desc))
@@ -783,7 +782,7 @@ static int s3c_hsudc_ep_enable(struct usb_ep *_ep,
writel(ecr, hsudc->regs + S3C_ECR);
hsep->stopped = hsep->wedge = 0;
- hsep->desc = desc;
+ hsep->ep.desc = desc;
hsep->ep.maxpacket = usb_endpoint_maxp(desc);
s3c_hsudc_set_halt(_ep, 0);
@@ -806,7 +805,7 @@ static int s3c_hsudc_ep_disable(struct usb_ep *_ep)
struct s3c_hsudc *hsudc = hsep->dev;
unsigned long flags;
- if (!_ep || !hsep->desc)
+ if (!_ep || !hsep->ep.desc)
return -EINVAL;
spin_lock_irqsave(&hsudc->lock, flags);
@@ -816,7 +815,6 @@ static int s3c_hsudc_ep_disable(struct usb_ep *_ep)
s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN);
- hsep->desc = 0;
hsep->ep.desc = NULL;
hsep->stopped = 1;
@@ -1006,7 +1004,6 @@ static void s3c_hsudc_initep(struct s3c_hsudc *hsudc,
hsep->ep.maxpacket = epnum ? 512 : 64;
hsep->ep.ops = &s3c_hsudc_ep_ops;
hsep->fifo = hsudc->regs + S3C_BR(epnum);
- hsep->desc = 0;
hsep->ep.desc = NULL;
hsep->stopped = 0;
hsep->wedge = 0;
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index 195524cde6c3..3de71d37d75e 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -1062,7 +1062,7 @@ static int s3c2410_udc_ep_enable(struct usb_ep *_ep,
ep = to_s3c2410_ep(_ep);
- if (!_ep || !desc || ep->desc
+ if (!_ep || !desc || ep->ep.desc
|| _ep->name == ep0name
|| desc->bDescriptorType != USB_DT_ENDPOINT)
return -EINVAL;
@@ -1075,7 +1075,7 @@ static int s3c2410_udc_ep_enable(struct usb_ep *_ep,
local_irq_save (flags);
_ep->maxpacket = max & 0x7ff;
- ep->desc = desc;
+ ep->ep.desc = desc;
ep->halted = 0;
ep->bEndpointAddress = desc->bEndpointAddress;
@@ -1136,7 +1136,7 @@ static int s3c2410_udc_ep_disable(struct usb_ep *_ep)
unsigned long flags;
u32 int_en_reg;
- if (!_ep || !ep->desc) {
+ if (!_ep || !ep->ep.desc) {
dprintk(DEBUG_NORMAL, "%s not enabled\n",
_ep ? ep->ep.name : NULL);
return -EINVAL;
@@ -1146,7 +1146,6 @@ static int s3c2410_udc_ep_disable(struct usb_ep *_ep)
dprintk(DEBUG_NORMAL, "ep_disable: %s\n", _ep->name);
- ep->desc = NULL;
ep->ep.desc = NULL;
ep->halted = 1;
@@ -1195,7 +1194,7 @@ s3c2410_udc_free_request(struct usb_ep *_ep, struct usb_request *_req)
dprintk(DEBUG_VERBOSE, "%s(%p,%p)\n", __func__, _ep, _req);
- if (!ep || !_req || (!ep->desc && _ep->name != ep0name))
+ if (!ep || !_req || (!ep->ep.desc && _ep->name != ep0name))
return;
WARN_ON (!list_empty (&req->queue));
@@ -1215,7 +1214,7 @@ static int s3c2410_udc_queue(struct usb_ep *_ep, struct usb_request *_req,
int fifo_count = 0;
unsigned long flags;
- if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+ if (unlikely(!_ep || (!ep->ep.desc && ep->ep.name != ep0name))) {
dprintk(DEBUG_NORMAL, "%s: invalid args\n", __func__);
return -EINVAL;
}
@@ -1363,7 +1362,7 @@ static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value)
unsigned long flags;
u32 idx;
- if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+ if (unlikely(!_ep || (!ep->ep.desc && ep->ep.name != ep0name))) {
dprintk(DEBUG_NORMAL, "%s: inval 2\n", __func__);
return -EINVAL;
}
@@ -1629,7 +1628,6 @@ static void s3c2410_udc_reinit(struct s3c2410_udc *dev)
list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);
ep->dev = dev;
- ep->desc = NULL;
ep->ep.desc = NULL;
ep->halted = 0;
INIT_LIST_HEAD (&ep->queue);
diff --git a/drivers/usb/gadget/s3c2410_udc.h b/drivers/usb/gadget/s3c2410_udc.h
index 1653bae08b80..3e80fd5c820f 100644
--- a/drivers/usb/gadget/s3c2410_udc.h
+++ b/drivers/usb/gadget/s3c2410_udc.h
@@ -19,7 +19,6 @@ struct s3c2410_ep {
unsigned long last_io; /* jiffies timestamp */
struct usb_gadget *gadget;
struct s3c2410_udc *dev;
- const struct usb_endpoint_descriptor *desc;
struct usb_ep ep;
u8 num;
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 29c854bbca44..47cf48b51c9d 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -744,10 +744,11 @@ static struct device_type gadget_type = {
};
/**
- * gether_setup - initialize one ethernet-over-usb link
+ * gether_setup_name - initialize one ethernet-over-usb link
* @g: gadget to associated with these links
* @ethaddr: NULL, or a buffer in which the ethernet address of the
* host side of the link is recorded
+ * @netname: name for network device (for example, "usb")
* Context: may sleep
*
* This sets up the single network link that may be exported by a
@@ -756,7 +757,8 @@ static struct device_type gadget_type = {
*
* Returns negative errno, or zero on success
*/
-int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
+int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
+ const char *netname)
{
struct eth_dev *dev;
struct net_device *net;
@@ -780,7 +782,7 @@ int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
/* network device setup */
dev->net = net;
- strcpy(net->name, "usb%d");
+ snprintf(net->name, sizeof(net->name), "%s%%d", netname);
if (get_ether_addr(dev_addr, net->dev_addr))
dev_warn(&g->dev,
diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
index 8012357e98aa..6f4a1623d854 100644
--- a/drivers/usb/gadget/u_ether.h
+++ b/drivers/usb/gadget/u_ether.h
@@ -69,9 +69,28 @@ struct gether {
|USB_CDC_PACKET_TYPE_PROMISCUOUS \
|USB_CDC_PACKET_TYPE_DIRECTED)
+/* variant of gether_setup that allows customizing network device name */
+int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN],
+ const char *netname);
/* netdev setup/teardown as directed by the gadget driver */
-int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]);
+/* gether_setup - initialize one ethernet-over-usb link
+ * @g: gadget to associated with these links
+ * @ethaddr: NULL, or a buffer in which the ethernet address of the
+ * host side of the link is recorded
+ * Context: may sleep
+ *
+ * This sets up the single network link that may be exported by a
+ * gadget driver using this framework. The link layer addresses are
+ * set up using module parameters.
+ *
+ * Returns negative errno, or zero on success
+ */
+static inline int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
+{
+ return gether_setup_name(g, ethaddr, "usb");
+}
+
void gether_cleanup(void);
/* connect/disconnect is handled by individual functions */
@@ -99,16 +118,37 @@ int eem_bind_config(struct usb_configuration *c);
#ifdef USB_ETH_RNDIS
-int rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
+int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+ u32 vendorID, const char *manufacturer);
#else
static inline int
-rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN],
+ u32 vendorID, const char *manufacturer)
{
return 0;
}
#endif
+/**
+ * rndis_bind_config - add RNDIS network link to a configuration
+ * @c: the configuration to support the network link
+ * @ethaddr: a buffer in which the ethernet address of the host side
+ * side of the link was recorded
+ * Context: single threaded during gadget setup
+ *
+ * Returns zero on success, else negative errno.
+ *
+ * Caller must have called @gether_setup(). Caller is also responsible
+ * for calling @gether_cleanup() before module unload.
+ */
+static inline int rndis_bind_config(struct usb_configuration *c,
+ u8 ethaddr[ETH_ALEN])
+{
+ return rndis_bind_config_vendor(c, ethaddr, 0, NULL);
+}
+
+
#endif /* __U_ETHER_H */
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index 6c23938d2711..5b3f5fffea92 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -94,17 +94,14 @@ struct gs_buf {
* (and thus for each /dev/ node).
*/
struct gs_port {
+ struct tty_port port;
spinlock_t port_lock; /* guard port_* access */
struct gserial *port_usb;
- struct tty_struct *port_tty;
- unsigned open_count;
bool openclose; /* open/close in progress */
u8 port_num;
- wait_queue_head_t close_wait; /* wait for last close */
-
struct list_head read_pool;
int read_started;
int read_allocated;
@@ -412,8 +409,8 @@ __acquires(&port->port_lock)
break;
}
- if (do_tty_wake && port->port_tty)
- tty_wakeup(port->port_tty);
+ if (do_tty_wake && port->port.tty)
+ tty_wakeup(port->port.tty);
return status;
}
@@ -435,7 +432,7 @@ __acquires(&port->port_lock)
struct tty_struct *tty;
/* no more rx if closed */
- tty = port->port_tty;
+ tty = port->port.tty;
if (!tty)
break;
@@ -488,7 +485,7 @@ static void gs_rx_push(unsigned long _port)
/* hand any queued data to the tty */
spin_lock_irq(&port->port_lock);
- tty = port->port_tty;
+ tty = port->port.tty;
while (!list_empty(queue)) {
struct usb_request *req;
@@ -699,7 +696,7 @@ static int gs_start_io(struct gs_port *port)
/* unblock any pending writes into our circular buffer */
if (started) {
- tty_wakeup(port->port_tty);
+ tty_wakeup(port->port.tty);
} else {
gs_free_requests(ep, head, &port->read_allocated);
gs_free_requests(port->port_usb->in, &port->write_pool,
@@ -734,9 +731,9 @@ static int gs_open(struct tty_struct *tty, struct file *file)
spin_lock_irq(&port->port_lock);
/* already open? Great. */
- if (port->open_count) {
+ if (port->port.count) {
status = 0;
- port->open_count++;
+ port->port.count++;
/* currently opening/closing? wait ... */
} else if (port->openclose) {
@@ -793,9 +790,9 @@ static int gs_open(struct tty_struct *tty, struct file *file)
/* REVISIT maybe wait for "carrier detect" */
tty->driver_data = port;
- port->port_tty = tty;
+ port->port.tty = tty;
- port->open_count = 1;
+ port->port.count = 1;
port->openclose = false;
/* if connected, start the I/O stream */
@@ -837,11 +834,11 @@ static void gs_close(struct tty_struct *tty, struct file *file)
spin_lock_irq(&port->port_lock);
- if (port->open_count != 1) {
- if (port->open_count == 0)
+ if (port->port.count != 1) {
+ if (port->port.count == 0)
WARN_ON(1);
else
- --port->open_count;
+ --port->port.count;
goto exit;
}
@@ -851,7 +848,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
* and sleep if necessary
*/
port->openclose = true;
- port->open_count = 0;
+ port->port.count = 0;
gser = port->port_usb;
if (gser && gser->disconnect)
@@ -879,14 +876,14 @@ static void gs_close(struct tty_struct *tty, struct file *file)
gs_buf_clear(&port->port_write_buf);
tty->driver_data = NULL;
- port->port_tty = NULL;
+ port->port.tty = NULL;
port->openclose = false;
pr_debug("gs_close: ttyGS%d (%p,%p) done!\n",
port->port_num, tty, file);
- wake_up_interruptible(&port->close_wait);
+ wake_up_interruptible(&port->port.close_wait);
exit:
spin_unlock_irq(&port->port_lock);
}
@@ -917,7 +914,7 @@ static int gs_put_char(struct tty_struct *tty, unsigned char ch)
unsigned long flags;
int status;
- pr_vdebug("gs_put_char: (%d,%p) char=0x%x, called from %p\n",
+ pr_vdebug("gs_put_char: (%d,%p) char=0x%x, called from %pf\n",
port->port_num, tty, ch, __builtin_return_address(0));
spin_lock_irqsave(&port->port_lock, flags);
@@ -1025,7 +1022,7 @@ static const struct tty_operations gs_tty_ops = {
static struct tty_driver *gs_tty_driver;
-static int __init
+static int
gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
{
struct gs_port *port;
@@ -1034,8 +1031,8 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
if (port == NULL)
return -ENOMEM;
+ tty_port_init(&port->port);
spin_lock_init(&port->port_lock);
- init_waitqueue_head(&port->close_wait);
init_waitqueue_head(&port->drain_wait);
tasklet_init(&port->push, gs_rx_push, (unsigned long) port);
@@ -1071,7 +1068,7 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
*
* Returns negative errno or zero.
*/
-int __init gserial_setup(struct usb_gadget *g, unsigned count)
+int gserial_setup(struct usb_gadget *g, unsigned count)
{
unsigned i;
struct usb_cdc_line_coding coding;
@@ -1155,7 +1152,7 @@ static int gs_closed(struct gs_port *port)
int cond;
spin_lock_irq(&port->port_lock);
- cond = (port->open_count == 0) && !port->openclose;
+ cond = (port->port.count == 0) && !port->openclose;
spin_unlock_irq(&port->port_lock);
return cond;
}
@@ -1194,7 +1191,7 @@ void gserial_cleanup(void)
tasklet_kill(&port->push);
/* wait for old opens to finish */
- wait_event(port->close_wait, gs_closed(port));
+ wait_event(port->port.close_wait, gs_closed(port));
WARN_ON(port->port_usb != NULL);
@@ -1268,7 +1265,7 @@ int gserial_connect(struct gserial *gser, u8 port_num)
/* if it's already open, start I/O ... and notify the serial
* protocol about open/close status (connect/disconnect).
*/
- if (port->open_count) {
+ if (port->port.count) {
pr_debug("gserial_connect: start ttyGS%d\n", port->port_num);
gs_start_io(port);
if (gser->connect)
@@ -1315,10 +1312,10 @@ void gserial_disconnect(struct gserial *gser)
port->port_usb = NULL;
gser->ioport = NULL;
- if (port->open_count > 0 || port->openclose) {
+ if (port->port.count > 0 || port->openclose) {
wake_up_interruptible(&port->drain_wait);
- if (port->port_tty)
- tty_hangup(port->port_tty);
+ if (port->port.tty)
+ tty_hangup(port->port.tty);
}
spin_unlock_irqrestore(&port->port_lock, flags);
@@ -1331,7 +1328,7 @@ void gserial_disconnect(struct gserial *gser)
/* finally, free any unused/unusable I/O buffers */
spin_lock_irqsave(&port->port_lock, flags);
- if (port->open_count == 0 && !port->openclose)
+ if (port->port.count == 0 && !port->openclose)
gs_buf_free(&port->port_write_buf);
gs_free_requests(gser->out, &port->read_pool, NULL);
gs_free_requests(gser->out, &port->read_queue, NULL);
diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c
index 0cdf89d32a15..104ae9c81251 100644
--- a/drivers/usb/gadget/uvc_queue.c
+++ b/drivers/usb/gadget/uvc_queue.c
@@ -543,7 +543,7 @@ done:
return ret;
}
-/* called with queue->irqlock held.. */
+/* called with &queue_irqlock held.. */
static struct uvc_buffer *
uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf)
{
diff --git a/drivers/usb/gadget/uvc_v4l2.c b/drivers/usb/gadget/uvc_v4l2.c
index 54d7ca559cb2..2ca9386d655b 100644
--- a/drivers/usb/gadget/uvc_v4l2.c
+++ b/drivers/usb/gadget/uvc_v4l2.c
@@ -296,7 +296,7 @@ uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST)
return -EINVAL;
- return v4l2_event_subscribe(&handle->vfh, arg, 2);
+ return v4l2_event_subscribe(&handle->vfh, arg, 2, NULL);
}
case VIDIOC_UNSUBSCRIBE_EVENT:
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 31d34832907e..12ad516ada77 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -72,7 +72,7 @@
static const char longname[] = "Gadget Zero";
-unsigned buflen = 4096;
+unsigned buflen = 4096; /* only used for bulk endpoints */
module_param(buflen, uint, 0);
/*
@@ -170,14 +170,17 @@ static struct usb_gadget_strings *dev_strings[] = {
/*-------------------------------------------------------------------------*/
-struct usb_request *alloc_ep_req(struct usb_ep *ep)
+struct usb_request *alloc_ep_req(struct usb_ep *ep, int len)
{
struct usb_request *req;
req = usb_ep_alloc_request(ep, GFP_ATOMIC);
if (req) {
- req->length = buflen;
- req->buf = kmalloc(buflen, GFP_ATOMIC);
+ if (len)
+ req->length = len;
+ else
+ req->length = buflen;
+ req->buf = kmalloc(req->length, GFP_ATOMIC);
if (!req->buf) {
usb_ep_free_request(ep, req);
req = NULL;
@@ -206,10 +209,15 @@ static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep)
}
void disable_endpoints(struct usb_composite_dev *cdev,
- struct usb_ep *in, struct usb_ep *out)
+ struct usb_ep *in, struct usb_ep *out,
+ struct usb_ep *iso_in, struct usb_ep *iso_out)
{
disable_ep(cdev, in);
disable_ep(cdev, out);
+ if (iso_in)
+ disable_ep(cdev, iso_in);
+ if (iso_out)
+ disable_ep(cdev, iso_out);
}
/*-------------------------------------------------------------------------*/
@@ -311,7 +319,6 @@ static int __init zero_bind(struct usb_composite_dev *cdev)
device_desc.bcdDevice = cpu_to_le16(0x9999);
}
-
INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname);
snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index f788eb86707c..83e58df29fe3 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -65,7 +65,7 @@ config USB_EHCI_HCD
config USB_EHCI_ROOT_HUB_TT
bool "Root Hub Transaction Translators"
- depends on USB_EHCI_HCD
+ depends on USB_EHCI_HCD || USB_CHIPIDEA_HOST
---help---
Some EHCI chips have vendor-specific extensions to integrate
transaction translators, so that no OHCI or UHCI companion
@@ -77,7 +77,7 @@ config USB_EHCI_ROOT_HUB_TT
config USB_EHCI_TT_NEWSCHED
bool "Improved Transaction Translator scheduling"
- depends on USB_EHCI_HCD
+ depends on USB_EHCI_HCD || USB_CHIPIDEA_HOST
default y
---help---
This changes the periodic scheduling code to fill more of the low
@@ -110,13 +110,14 @@ config USB_EHCI_BIG_ENDIAN_MMIO
depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || \
ARCH_IXP4XX || XPS_USB_HCD_XILINX || \
PPC_MPC512x || CPU_CAVIUM_OCTEON || \
- PMC_MSP || SPARC_LEON)
+ PMC_MSP || SPARC_LEON || MIPS_SEAD3)
default y
config USB_EHCI_BIG_ENDIAN_DESC
bool
depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX || \
- PPC_MPC512x || PMC_MSP || SPARC_LEON)
+ PPC_MPC512x || PMC_MSP || SPARC_LEON || \
+ MIPS_SEAD3)
default y
config XPS_USB_HCD_XILINX
@@ -152,7 +153,7 @@ config USB_EHCI_HCD_OMAP
bool "EHCI support for OMAP3 and later chips"
depends on USB_EHCI_HCD && ARCH_OMAP
default y
- --- help ---
+ ---help---
Enables support for the on-chip EHCI controller on
OMAP3 and later chips.
@@ -291,6 +292,7 @@ config USB_OHCI_HCD
depends on USB && USB_ARCH_HAS_OHCI
select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
select USB_OTG_UTILS if ARCH_OMAP
+ select USB_ISP1301 if ARCH_LPC32XX || ARCH_PNX4008
---help---
The Open Host Controller Interface (OHCI) is a standard for accessing
USB 1.1 host controller hardware. It does more in hardware than Intel's
@@ -373,10 +375,15 @@ config USB_OHCI_HCD_PCI
If unsure, say Y.
config USB_OHCI_HCD_SSB
- bool "OHCI support for Broadcom SSB OHCI core"
+ bool "OHCI support for Broadcom SSB OHCI core (DEPRECATED)"
depends on USB_OHCI_HCD && (SSB = y || SSB = USB_OHCI_HCD) && EXPERIMENTAL
+ select USB_HCD_SSB
+ select USB_OHCI_HCD_PLATFORM
default n
---help---
+ This option is deprecated now and the driver was removed, use
+ USB_HCD_SSB and USB_OHCI_HCD_PLATFORM instead.
+
Support for the Sonics Silicon Backplane (SSB) attached
Broadcom USB OHCI core.
@@ -638,3 +645,27 @@ config USB_OCTEON_OHCI
config USB_OCTEON2_COMMON
bool
default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI
+
+config USB_HCD_BCMA
+ tristate "BCMA usb host driver"
+ depends on BCMA && EXPERIMENTAL
+ select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
+ select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
+ help
+ Enbale support for the EHCI and OCHI host controller on an bcma bus.
+ It converts the bcma driver into two platform device drivers
+ for ehci and ohci.
+
+ If unsure, say N.
+
+config USB_HCD_SSB
+ tristate "SSB usb host driver"
+ depends on SSB && EXPERIMENTAL
+ select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD
+ select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD
+ help
+ Enbale support for the EHCI and OCHI host controller on an bcma bus.
+ It converts the bcma driver into two platform device drivers
+ for ehci and ohci.
+
+ If unsure, say N.
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 0982bcc140bd..9e0a89ced15c 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -41,3 +41,5 @@ obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o
obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o
obj-$(CONFIG_MIPS_ALCHEMY) += alchemy-common.o
+obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o
+obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o
diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c
new file mode 100644
index 000000000000..443da21d73ca
--- /dev/null
+++ b/drivers/usb/host/bcma-hcd.c
@@ -0,0 +1,335 @@
+/*
+ * Broadcom specific Advanced Microcontroller Bus
+ * Broadcom USB-core driver (BCMA bus glue)
+ *
+ * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Based on ssb-ohci driver
+ * Copyright 2007 Michael Buesch <m@bues.ch>
+ *
+ * Derived from the OHCI-PCI driver
+ * Copyright 1999 Roman Weissgaerber
+ * Copyright 2000-2002 David Brownell
+ * Copyright 1999 Linus Torvalds
+ * Copyright 1999 Gregory P. Smith
+ *
+ * Derived from the USBcore related parts of Broadcom-SB
+ * Copyright 2005-2011 Broadcom Corporation
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+#include <linux/bcma/bcma.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb/ehci_pdriver.h>
+#include <linux/usb/ohci_pdriver.h>
+
+MODULE_AUTHOR("Hauke Mehrtens");
+MODULE_DESCRIPTION("Common USB driver for BCMA Bus");
+MODULE_LICENSE("GPL");
+
+struct bcma_hcd_device {
+ struct platform_device *ehci_dev;
+ struct platform_device *ohci_dev;
+};
+
+/* Wait for bitmask in a register to get set or cleared.
+ * timeout is in units of ten-microseconds.
+ */
+static int bcma_wait_bits(struct bcma_device *dev, u16 reg, u32 bitmask,
+ int timeout)
+{
+ int i;
+ u32 val;
+
+ for (i = 0; i < timeout; i++) {
+ val = bcma_read32(dev, reg);
+ if ((val & bitmask) == bitmask)
+ return 0;
+ udelay(10);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static void __devinit bcma_hcd_4716wa(struct bcma_device *dev)
+{
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+ /* Work around for 4716 failures. */
+ if (dev->bus->chipinfo.id == 0x4716) {
+ u32 tmp;
+
+ tmp = bcma_cpu_clock(&dev->bus->drv_mips);
+ if (tmp >= 480000000)
+ tmp = 0x1846b; /* set CDR to 0x11(fast) */
+ else if (tmp == 453000000)
+ tmp = 0x1046b; /* set CDR to 0x10(slow) */
+ else
+ tmp = 0;
+
+ /* Change Shim mdio control reg to fix host not acking at
+ * high frequencies
+ */
+ if (tmp) {
+ bcma_write32(dev, 0x524, 0x1); /* write sel to enable */
+ udelay(500);
+
+ bcma_write32(dev, 0x524, tmp);
+ udelay(500);
+ bcma_write32(dev, 0x524, 0x4ab);
+ udelay(500);
+ bcma_read32(dev, 0x528);
+ bcma_write32(dev, 0x528, 0x80000000);
+ }
+ }
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
+}
+
+/* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */
+static void __devinit bcma_hcd_init_chip(struct bcma_device *dev)
+{
+ u32 tmp;
+
+ /*
+ * USB 2.0 special considerations:
+ *
+ * 1. Since the core supports both OHCI and EHCI functions, it must
+ * only be reset once.
+ *
+ * 2. In addition to the standard SI reset sequence, the Host Control
+ * Register must be programmed to bring the USB core and various
+ * phy components out of reset.
+ */
+ if (!bcma_core_is_enabled(dev)) {
+ bcma_core_enable(dev, 0);
+ mdelay(10);
+ if (dev->id.rev >= 5) {
+ /* Enable Misc PLL */
+ tmp = bcma_read32(dev, 0x1e0);
+ tmp |= 0x100;
+ bcma_write32(dev, 0x1e0, tmp);
+ if (bcma_wait_bits(dev, 0x1e0, 1 << 24, 100))
+ printk(KERN_EMERG "Failed to enable misc PPL!\n");
+
+ /* Take out of resets */
+ bcma_write32(dev, 0x200, 0x4ff);
+ udelay(25);
+ bcma_write32(dev, 0x200, 0x6ff);
+ udelay(25);
+
+ /* Make sure digital and AFE are locked in USB PHY */
+ bcma_write32(dev, 0x524, 0x6b);
+ udelay(50);
+ tmp = bcma_read32(dev, 0x524);
+ udelay(50);
+ bcma_write32(dev, 0x524, 0xab);
+ udelay(50);
+ tmp = bcma_read32(dev, 0x524);
+ udelay(50);
+ bcma_write32(dev, 0x524, 0x2b);
+ udelay(50);
+ tmp = bcma_read32(dev, 0x524);
+ udelay(50);
+ bcma_write32(dev, 0x524, 0x10ab);
+ udelay(50);
+ tmp = bcma_read32(dev, 0x524);
+
+ if (bcma_wait_bits(dev, 0x528, 0xc000, 10000)) {
+ tmp = bcma_read32(dev, 0x528);
+ printk(KERN_EMERG
+ "USB20H mdio_rddata 0x%08x\n", tmp);
+ }
+ bcma_write32(dev, 0x528, 0x80000000);
+ tmp = bcma_read32(dev, 0x314);
+ udelay(265);
+ bcma_write32(dev, 0x200, 0x7ff);
+ udelay(10);
+
+ /* Take USB and HSIC out of non-driving modes */
+ bcma_write32(dev, 0x510, 0);
+ } else {
+ bcma_write32(dev, 0x200, 0x7ff);
+
+ udelay(1);
+ }
+
+ bcma_hcd_4716wa(dev);
+ }
+}
+
+static const struct usb_ehci_pdata ehci_pdata = {
+};
+
+static const struct usb_ohci_pdata ohci_pdata = {
+};
+
+static struct platform_device * __devinit
+bcma_hcd_create_pdev(struct bcma_device *dev, bool ohci, u32 addr)
+{
+ struct platform_device *hci_dev;
+ struct resource hci_res[2];
+ int ret = -ENOMEM;
+
+ memset(hci_res, 0, sizeof(hci_res));
+
+ hci_res[0].start = addr;
+ hci_res[0].end = hci_res[0].start + 0x1000 - 1;
+ hci_res[0].flags = IORESOURCE_MEM;
+
+ hci_res[1].start = dev->irq;
+ hci_res[1].flags = IORESOURCE_IRQ;
+
+ hci_dev = platform_device_alloc(ohci ? "ohci-platform" :
+ "ehci-platform" , 0);
+ if (!hci_dev)
+ return NULL;
+
+ hci_dev->dev.parent = &dev->dev;
+ hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask;
+
+ ret = platform_device_add_resources(hci_dev, hci_res,
+ ARRAY_SIZE(hci_res));
+ if (ret)
+ goto err_alloc;
+ if (ohci)
+ ret = platform_device_add_data(hci_dev, &ohci_pdata,
+ sizeof(ohci_pdata));
+ else
+ ret = platform_device_add_data(hci_dev, &ehci_pdata,
+ sizeof(ehci_pdata));
+ if (ret)
+ goto err_alloc;
+ ret = platform_device_add(hci_dev);
+ if (ret)
+ goto err_alloc;
+
+ return hci_dev;
+
+err_alloc:
+ platform_device_put(hci_dev);
+ return ERR_PTR(ret);
+}
+
+static int __devinit bcma_hcd_probe(struct bcma_device *dev)
+{
+ int err;
+ u16 chipid_top;
+ u32 ohci_addr;
+ struct bcma_hcd_device *usb_dev;
+ struct bcma_chipinfo *chipinfo;
+
+ chipinfo = &dev->bus->chipinfo;
+ /* USBcores are only connected on embedded devices. */
+ chipid_top = (chipinfo->id & 0xFF00);
+ if (chipid_top != 0x4700 && chipid_top != 0x5300)
+ return -ENODEV;
+
+ /* TODO: Probably need checks here; is the core connected? */
+
+ if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) ||
+ dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32)))
+ return -EOPNOTSUPP;
+
+ usb_dev = kzalloc(sizeof(struct bcma_hcd_device), GFP_KERNEL);
+ if (!usb_dev)
+ return -ENOMEM;
+
+ bcma_hcd_init_chip(dev);
+
+ /* In AI chips EHCI is addrspace 0, OHCI is 1 */
+ ohci_addr = dev->addr1;
+ if ((chipinfo->id == 0x5357 || chipinfo->id == 0x4749)
+ && chipinfo->rev == 0)
+ ohci_addr = 0x18009000;
+
+ usb_dev->ohci_dev = bcma_hcd_create_pdev(dev, true, ohci_addr);
+ if (IS_ERR(usb_dev->ohci_dev)) {
+ err = PTR_ERR(usb_dev->ohci_dev);
+ goto err_free_usb_dev;
+ }
+
+ usb_dev->ehci_dev = bcma_hcd_create_pdev(dev, false, dev->addr);
+ if (IS_ERR(usb_dev->ehci_dev)) {
+ err = PTR_ERR(usb_dev->ehci_dev);
+ goto err_unregister_ohci_dev;
+ }
+
+ bcma_set_drvdata(dev, usb_dev);
+ return 0;
+
+err_unregister_ohci_dev:
+ platform_device_unregister(usb_dev->ohci_dev);
+err_free_usb_dev:
+ kfree(usb_dev);
+ return err;
+}
+
+static void __devexit bcma_hcd_remove(struct bcma_device *dev)
+{
+ struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev);
+ struct platform_device *ohci_dev = usb_dev->ohci_dev;
+ struct platform_device *ehci_dev = usb_dev->ehci_dev;
+
+ if (ohci_dev)
+ platform_device_unregister(ohci_dev);
+ if (ehci_dev)
+ platform_device_unregister(ehci_dev);
+
+ bcma_core_disable(dev, 0);
+}
+
+static void bcma_hcd_shutdown(struct bcma_device *dev)
+{
+ bcma_core_disable(dev, 0);
+}
+
+#ifdef CONFIG_PM
+
+static int bcma_hcd_suspend(struct bcma_device *dev)
+{
+ bcma_core_disable(dev, 0);
+
+ return 0;
+}
+
+static int bcma_hcd_resume(struct bcma_device *dev)
+{
+ bcma_core_enable(dev, 0);
+
+ return 0;
+}
+
+#else /* !CONFIG_PM */
+#define bcma_hcd_suspend NULL
+#define bcma_hcd_resume NULL
+#endif /* CONFIG_PM */
+
+static const struct bcma_device_id bcma_hcd_table[] __devinitconst = {
+ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_USB20_HOST, BCMA_ANY_REV, BCMA_ANY_CLASS),
+ BCMA_CORETABLE_END
+};
+MODULE_DEVICE_TABLE(bcma, bcma_hcd_table);
+
+static struct bcma_driver bcma_hcd_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = bcma_hcd_table,
+ .probe = bcma_hcd_probe,
+ .remove = __devexit_p(bcma_hcd_remove),
+ .shutdown = bcma_hcd_shutdown,
+ .suspend = bcma_hcd_suspend,
+ .resume = bcma_hcd_resume,
+};
+
+static int __init bcma_hcd_init(void)
+{
+ return bcma_driver_register(&bcma_hcd_driver);
+}
+module_init(bcma_hcd_init);
+
+static void __exit bcma_hcd_exit(void)
+{
+ bcma_driver_unregister(&bcma_hcd_driver);
+}
+module_exit(bcma_hcd_exit);
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 680e1a31fb87..7561966fbdc4 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -1025,10 +1025,8 @@ static ssize_t debug_lpm_write(struct file *file, const char __user *user_buf,
if (strict_strtoul(buf + 5, 16, &hird))
return -EINVAL;
printk(KERN_INFO "setting hird %s %lu\n", buf + 6, hird);
- temp = ehci_readl(ehci, &ehci->regs->command);
- temp &= ~CMD_HIRD;
- temp |= hird << 24;
- ehci_writel(ehci, temp, &ehci->regs->command);
+ ehci->command = (ehci->command & ~CMD_HIRD) | (hird << 24);
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
} else if (strncmp(buf, "disable", 7) == 0) {
if (strict_strtoul(buf + 8, 10, &port))
return -EINVAL;
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index d0a84bd3f3eb..43362577b54a 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -1,6 +1,6 @@
/*
* Copyright 2005-2009 MontaVista Software, Inc.
- * Copyright 2008 Freescale Semiconductor, Inc.
+ * Copyright 2008,2012 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
@@ -150,8 +150,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
retval = otg_set_host(ehci->transceiver->otg,
&ehci_to_hcd(ehci)->self);
if (retval) {
- if (ehci->transceiver)
- put_device(ehci->transceiver->dev);
+ usb_put_transceiver(ehci->transceiver);
goto err4;
}
} else {
@@ -195,7 +194,7 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
if (ehci->transceiver) {
otg_set_host(ehci->transceiver->otg, NULL);
- put_device(ehci->transceiver->dev);
+ usb_put_transceiver(ehci->transceiver);
}
usb_remove_hcd(hcd);
@@ -211,22 +210,32 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
usb_put_hcd(hcd);
}
-static void ehci_fsl_setup_phy(struct ehci_hcd *ehci,
+static void ehci_fsl_setup_phy(struct usb_hcd *hcd,
enum fsl_usb2_phy_modes phy_mode,
unsigned int port_offset)
{
- u32 portsc;
- struct usb_hcd *hcd = ehci_to_hcd(ehci);
+ u32 portsc, temp;
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
void __iomem *non_ehci = hcd->regs;
- struct fsl_usb2_platform_data *pdata;
+ struct device *dev = hcd->self.controller;
+ struct fsl_usb2_platform_data *pdata = dev->platform_data;
- pdata = hcd->self.controller->platform_data;
+ if (pdata->controller_ver < 0) {
+ dev_warn(hcd->self.controller, "Could not get controller version\n");
+ return;
+ }
portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]);
portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW);
switch (phy_mode) {
case FSL_USB2_PHY_ULPI:
+ if (pdata->controller_ver) {
+ /* controller version 1.6 or above */
+ temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
+ out_be32(non_ehci + FSL_SOC_USB_CTRL, temp |
+ USB_CTRL_USB_EN | ULPI_PHY_CLK_SEL);
+ }
portsc |= PORT_PTS_ULPI;
break;
case FSL_USB2_PHY_SERIAL:
@@ -236,6 +245,14 @@ static void ehci_fsl_setup_phy(struct ehci_hcd *ehci,
portsc |= PORT_PTS_PTW;
/* fall through */
case FSL_USB2_PHY_UTMI:
+ if (pdata->controller_ver) {
+ /* controller version 1.6 or above */
+ temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
+ out_be32(non_ehci + FSL_SOC_USB_CTRL, temp |
+ UTMI_PHY_EN | USB_CTRL_USB_EN);
+ mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI PHY CLK to
+ become stable - 10ms*/
+ }
/* enable UTMI PHY */
if (pdata->have_sysif_regs)
setbits32(non_ehci + FSL_SOC_USB_CTRL,
@@ -276,7 +293,7 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
(pdata->operating_mode == FSL_USB2_DR_OTG))
- ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);
+ ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0);
if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
unsigned int chip, rev, svr;
@@ -290,9 +307,9 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
ehci->has_fsl_port_bug = 1;
if (pdata->port_enables & FSL_USB2_PORT0_ENABLED)
- ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);
+ ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0);
if (pdata->port_enables & FSL_USB2_PORT1_ENABLED)
- ehci_fsl_setup_phy(ehci, pdata->phy_mode, 1);
+ ehci_fsl_setup_phy(hcd, pdata->phy_mode, 1);
}
if (pdata->have_sysif_regs) {
diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h
index 863fb0c080d7..88403684d10b 100644
--- a/drivers/usb/host/ehci-fsl.h
+++ b/drivers/usb/host/ehci-fsl.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005-2010 Freescale Semiconductor, Inc.
+/* Copyright (C) 2005-2010,2012 Freescale Semiconductor, Inc.
* Copyright (c) 2005 MontaVista Software
*
* This program is free software; you can redistribute it and/or modify it
@@ -50,4 +50,15 @@
#define CTRL_UTMI_PHY_EN (1<<9)
#define CTRL_PHY_CLK_VALID (1 << 17)
#define SNOOP_SIZE_2GB 0x1e
+
+/* control Register Bit Masks */
+#define ULPI_INT_EN (1<<0)
+#define WU_INT_EN (1<<1)
+#define USB_CTRL_USB_EN (1<<2)
+#define LINE_STATE_FILTER__EN (1<<3)
+#define KEEP_OTG_ON (1<<4)
+#define OTG_PORT (1<<5)
+#define PLL_RESET (1<<8)
+#define UTMI_PHY_EN (1<<9)
+#define ULPI_PHY_CLK_SEL (1<<10)
#endif /* _EHCI_FSL_H */
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 4a3bc5b7a06f..b100f5f9f4b6 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -226,8 +226,13 @@ static int ehci_halt (struct ehci_hcd *ehci)
if ((temp & STS_HALT) != 0)
return 0;
+ /*
+ * This routine gets called during probe before ehci->command
+ * has been initialized, so we can't rely on its value.
+ */
+ ehci->command &= ~CMD_RUN;
temp = ehci_readl(ehci, &ehci->regs->command);
- temp &= ~CMD_RUN;
+ temp &= ~(CMD_RUN | CMD_IAAD);
ehci_writel(ehci, temp, &ehci->regs->command);
return handshake (ehci, &ehci->regs->status,
STS_HALT, STS_HALT, 16 * 125);
@@ -363,16 +368,14 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
#endif
/* wait for any schedule enables/disables to take effect */
- temp = ehci_readl(ehci, &ehci->regs->command) << 10;
- temp &= STS_ASS | STS_PSS;
+ temp = (ehci->command << 10) & (STS_ASS | STS_PSS);
if (handshake_on_error_set_halt(ehci, &ehci->regs->status,
STS_ASS | STS_PSS, temp, 16 * 125))
return;
/* then disable anything that's still active */
- temp = ehci_readl(ehci, &ehci->regs->command);
- temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
- ehci_writel(ehci, temp, &ehci->regs->command);
+ ehci->command &= ~(CMD_ASE | CMD_PSE);
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
/* hardware can take 16 microframes to turn off ... */
handshake_on_error_set_halt(ehci, &ehci->regs->status,
@@ -417,9 +420,6 @@ static void ehci_iaa_watchdog(unsigned long param)
* CMD_IAAD when it sets STS_IAA.)
*/
cmd = ehci_readl(ehci, &ehci->regs->command);
- if (cmd & CMD_IAAD)
- ehci_writel(ehci, cmd & ~CMD_IAAD,
- &ehci->regs->command);
/* If IAA is set here it either legitimately triggered
* before we cleared IAAD above (but _way_ late, so we'll
@@ -894,11 +894,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* complete the unlinking of some qh [4.15.2.3] */
if (status & STS_IAA) {
/* guard against (alleged) silicon errata */
- if (cmd & CMD_IAAD) {
- ehci_writel(ehci, cmd & ~CMD_IAAD,
- &ehci->regs->command);
+ if (cmd & CMD_IAAD)
ehci_dbg(ehci, "IAA with IAAD still set?\n");
- }
if (ehci->reclaim) {
COUNT(ehci->stats.reclaim);
end_unlink_async(ehci);
@@ -1248,6 +1245,13 @@ static int ehci_get_frame (struct usb_hcd *hcd)
}
/*-------------------------------------------------------------------------*/
+/*
+ * The EHCI in ChipIdea HDRC cannot be a separate module or device,
+ * because its registers (and irq) are shared between host/gadget/otg
+ * functions and in order to facilitate role switching we cannot
+ * give the ehci driver exclusive access to those.
+ */
+#ifndef CHIPIDEA_EHCI
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR (DRIVER_AUTHOR);
@@ -1378,6 +1382,11 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_ls1x_driver
#endif
+#ifdef CONFIG_MIPS_SEAD3
+#include "ehci-sead3.c"
+#define PLATFORM_DRIVER ehci_hcd_sead3_driver
+#endif
+
#ifdef CONFIG_USB_EHCI_HCD_PLATFORM
#include "ehci-platform.c"
#define PLATFORM_DRIVER ehci_platform_driver
@@ -1501,3 +1510,4 @@ static void __exit ehci_hcd_cleanup(void)
}
module_exit(ehci_hcd_cleanup);
+#endif /* CHIPIDEA_EHCI */
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 38fe07623152..fc9e7cc6ac9b 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -233,7 +233,6 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
/* stop schedules, clean any completed work */
if (ehci->rh_state == EHCI_RH_RUNNING)
ehci_quiesce (ehci);
- ehci->command = ehci_readl(ehci, &ehci->regs->command);
ehci_work(ehci);
/* Unlike other USB host controller types, EHCI doesn't have
@@ -374,6 +373,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next);
/* restore CMD_RUN, framelist size, and irq threshold */
+ ehci->command |= CMD_RUN;
ehci_writel(ehci, ehci->command, &ehci->regs->command);
ehci->rh_state = EHCI_RH_RUNNING;
@@ -531,7 +531,8 @@ static int check_reset_complete (
if (ehci->has_amcc_usb23)
set_ohci_hcfs(ehci, 1);
} else {
- ehci_dbg (ehci, "port %d high speed\n", index + 1);
+ ehci_dbg(ehci, "port %d reset complete, port enabled\n",
+ index + 1);
/* ensure 440EPx ohci controller state is suspended */
if (ehci->has_amcc_usb23)
set_ohci_hcfs(ehci, 0);
@@ -699,6 +700,7 @@ static int ehci_hub_control (
goto error;
wIndex--;
temp = ehci_readl(ehci, status_reg);
+ temp &= ~PORT_RWC_BITS;
/*
* Even if OWNER is set, so the port is owned by the
@@ -712,8 +714,7 @@ static int ehci_hub_control (
ehci_writel(ehci, temp & ~PORT_PE, status_reg);
break;
case USB_PORT_FEAT_C_ENABLE:
- ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC,
- status_reg);
+ ehci_writel(ehci, temp | PORT_PEC, status_reg);
break;
case USB_PORT_FEAT_SUSPEND:
if (temp & PORT_RESET)
@@ -742,7 +743,7 @@ static int ehci_hub_control (
spin_lock_irqsave(&ehci->lock, flags);
}
/* resume signaling for 20 msec */
- temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
+ temp &= ~PORT_WAKE_BITS;
ehci_writel(ehci, temp | PORT_RESUME, status_reg);
ehci->reset_done[wIndex] = jiffies
+ msecs_to_jiffies(20);
@@ -752,9 +753,8 @@ static int ehci_hub_control (
break;
case USB_PORT_FEAT_POWER:
if (HCS_PPC (ehci->hcs_params))
- ehci_writel(ehci,
- temp & ~(PORT_RWC_BITS | PORT_POWER),
- status_reg);
+ ehci_writel(ehci, temp & ~PORT_POWER,
+ status_reg);
break;
case USB_PORT_FEAT_C_CONNECTION:
if (ehci->has_lpm) {
@@ -762,12 +762,10 @@ static int ehci_hub_control (
temp &= ~PORT_LPM;
temp &= ~PORT_DEV_ADDR;
}
- ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC,
- status_reg);
+ ehci_writel(ehci, temp | PORT_CSC, status_reg);
break;
case USB_PORT_FEAT_C_OVER_CURRENT:
- ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_OCC,
- status_reg);
+ ehci_writel(ehci, temp | PORT_OCC, status_reg);
break;
case USB_PORT_FEAT_C_RESET:
/* GetPortStatus clears reset */
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index 5c78f9e71466..a44294d13494 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -242,15 +242,6 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
ehci_reset(omap_ehci);
- ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
- if (ret) {
- dev_err(dev, "failed to add hcd with err %d\n", ret);
- goto err_add_hcd;
- }
-
- /* root ports should always stay powered */
- ehci_port_power(omap_ehci, 1);
-
if (pdata->phy_reset) {
/* Hold the PHY in RESET for enough time till
* PHY is settled and ready
@@ -258,12 +249,21 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
udelay(10);
if (gpio_is_valid(pdata->reset_gpio_port[0]))
- gpio_set_value(pdata->reset_gpio_port[0], 1);
+ gpio_set_value_cansleep(pdata->reset_gpio_port[0], 1);
if (gpio_is_valid(pdata->reset_gpio_port[1]))
- gpio_set_value(pdata->reset_gpio_port[1], 1);
+ gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1);
}
+ ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
+ if (ret) {
+ dev_err(dev, "failed to add hcd with err %d\n", ret);
+ goto err_add_hcd;
+ }
+
+ /* root ports should always stay powered */
+ ehci_port_power(omap_ehci, 1);
+
return 0;
err_add_hcd:
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index fe8dc069164e..bc94d7bf072d 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -368,7 +368,9 @@ static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev)
{
return pdev->class == PCI_CLASS_SERIAL_USB_EHCI &&
pdev->vendor == PCI_VENDOR_ID_INTEL &&
- pdev->device == 0x1E26;
+ (pdev->device == 0x1E26 ||
+ pdev->device == 0x8C2D ||
+ pdev->device == 0x8C26);
}
static void ehci_enable_xhci_companion(void)
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index d238b4e24bb6..dfe881a34ae2 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -75,8 +75,6 @@ static const struct hc_driver ehci_platform_hc_driver = {
.relinquish_port = ehci_relinquish_port,
.port_handed_over = ehci_port_handed_over,
- .update_device = ehci_update_device,
-
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
@@ -94,12 +92,12 @@ static int __devinit ehci_platform_probe(struct platform_device *dev)
irq = platform_get_irq(dev, 0);
if (irq < 0) {
- pr_err("no irq provieded");
+ pr_err("no irq provided");
return irq;
}
res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!res_mem) {
- pr_err("no memory recourse provieded");
+ pr_err("no memory recourse provided");
return -ENXIO;
}
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 36ca5077cdf7..4378bf72bbac 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -943,7 +943,8 @@ qh_make (
}
break;
default:
- dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
+ ehci_dbg(ehci, "bogus dev %p speed %d\n", urb->dev,
+ urb->dev->speed);
done:
qh_put (qh);
return NULL;
@@ -981,14 +982,12 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
head = ehci->async;
timer_action_done (ehci, TIMER_ASYNC_OFF);
if (!head->qh_next.qh) {
- u32 cmd = ehci_readl(ehci, &ehci->regs->command);
-
- if (!(cmd & CMD_ASE)) {
+ if (!(ehci->command & CMD_ASE)) {
/* in case a clear of CMD_ASE didn't take yet */
(void)handshake(ehci, &ehci->regs->status,
STS_ASS, 0, 150);
- cmd |= CMD_ASE;
- ehci_writel(ehci, cmd, &ehci->regs->command);
+ ehci->command |= CMD_ASE;
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
/* posted write need not be known to HC yet ... */
}
}
@@ -1204,7 +1203,6 @@ static void end_unlink_async (struct ehci_hcd *ehci)
static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
- int cmd = ehci_readl(ehci, &ehci->regs->command);
struct ehci_qh *prev;
#ifdef DEBUG
@@ -1222,8 +1220,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (ehci->rh_state != EHCI_RH_HALTED
&& !ehci->reclaim) {
/* ... and CMD_IAAD clear */
- ehci_writel(ehci, cmd & ~CMD_ASE,
- &ehci->regs->command);
+ ehci->command &= ~CMD_ASE;
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
wmb ();
// handshake later, if we need to
timer_action_done (ehci, TIMER_ASYNC_OFF);
@@ -1253,8 +1251,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
return;
}
- cmd |= CMD_IAAD;
- ehci_writel(ehci, cmd, &ehci->regs->command);
+ ehci_writel(ehci, ehci->command | CMD_IAAD, &ehci->regs->command);
(void)ehci_readl(ehci, &ehci->regs->command);
iaa_watchdog_start(ehci);
}
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
index f098e2a291a0..c474cec064e4 100644
--- a/drivers/usb/host/ehci-s5p.c
+++ b/drivers/usb/host/ehci-s5p.c
@@ -232,6 +232,8 @@ static int s5p_ehci_suspend(struct device *dev)
if (pdata && pdata->phy_exit)
pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
+ clk_disable(s5p_ehci->clk);
+
return rc;
}
@@ -243,6 +245,8 @@ static int s5p_ehci_resume(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
+ clk_enable(s5p_ehci->clk);
+
if (pdata && pdata->phy_init)
pdata->phy_init(pdev, S5P_USB_PHY_HOST);
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index a60679cbbf85..33182c6d1ff9 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -481,7 +481,6 @@ static int tt_no_collision (
static int enable_periodic (struct ehci_hcd *ehci)
{
- u32 cmd;
int status;
if (ehci->periodic_sched++)
@@ -497,8 +496,8 @@ static int enable_periodic (struct ehci_hcd *ehci)
return status;
}
- cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
- ehci_writel(ehci, cmd, &ehci->regs->command);
+ ehci->command |= CMD_PSE;
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
/* posted write ... PSS happens later */
/* make sure ehci_work scans these */
@@ -511,7 +510,6 @@ static int enable_periodic (struct ehci_hcd *ehci)
static int disable_periodic (struct ehci_hcd *ehci)
{
- u32 cmd;
int status;
if (--ehci->periodic_sched)
@@ -537,8 +535,8 @@ static int disable_periodic (struct ehci_hcd *ehci)
return status;
}
- cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE;
- ehci_writel(ehci, cmd, &ehci->regs->command);
+ ehci->command &= ~CMD_PSE;
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
/* posted write ... */
free_cached_lists(ehci);
@@ -1333,34 +1331,36 @@ sitd_slot_ok (
if (mask & ~0xffff)
return 0;
+ /* check bandwidth */
+ uframe %= period_uframes;
+ frame = uframe >> 3;
+
+#ifdef CONFIG_USB_EHCI_TT_NEWSCHED
+ /* The tt's fullspeed bus bandwidth must be available.
+ * tt_available scheduling guarantees 10+% for control/bulk.
+ */
+ uf = uframe & 7;
+ if (!tt_available(ehci, period_uframes >> 3,
+ stream->udev, frame, uf, stream->tt_usecs))
+ return 0;
+#else
+ /* tt must be idle for start(s), any gap, and csplit.
+ * assume scheduling slop leaves 10+% for control/bulk.
+ */
+ if (!tt_no_collision(ehci, period_uframes >> 3,
+ stream->udev, frame, mask))
+ return 0;
+#endif
+
/* this multi-pass logic is simple, but performance may
* suffer when the schedule data isn't cached.
*/
-
- /* check bandwidth */
- uframe %= period_uframes;
do {
u32 max_used;
frame = uframe >> 3;
uf = uframe & 7;
-#ifdef CONFIG_USB_EHCI_TT_NEWSCHED
- /* The tt's fullspeed bus bandwidth must be available.
- * tt_available scheduling guarantees 10+% for control/bulk.
- */
- if (!tt_available (ehci, period_uframes << 3,
- stream->udev, frame, uf, stream->tt_usecs))
- return 0;
-#else
- /* tt must be idle for start(s), any gap, and csplit.
- * assume scheduling slop leaves 10+% for control/bulk.
- */
- if (!tt_no_collision (ehci, period_uframes << 3,
- stream->udev, frame, mask))
- return 0;
-#endif
-
/* check starts (OUT uses more than one) */
max_used = ehci->uframe_periodic_max - stream->usecs;
for (tmp = stream->raw_mask & 0xff; tmp; tmp >>= 1, uf++) {
@@ -2358,7 +2358,8 @@ restart:
* in the previous frame for completions.
*/
if (q.fstn->hw_prev != EHCI_LIST_END(ehci)) {
- dbg ("ignoring completions from FSTNs");
+ ehci_dbg(ehci,
+ "ignoring completions from FSTNs\n");
}
type = Q_NEXT_TYPE(ehci, q.fstn->hw_next);
q = q.fstn->fstn_next;
@@ -2441,7 +2442,7 @@ restart:
q = *q_p;
break;
default:
- dbg ("corrupt type %d frame %d shadow %p",
+ ehci_dbg(ehci, "corrupt type %d frame %d shadow %p\n",
type, frame, q.ptr);
// BUG ();
q.ptr = NULL;
diff --git a/drivers/usb/host/ehci-sead3.c b/drivers/usb/host/ehci-sead3.c
new file mode 100644
index 000000000000..cc199e87a7a9
--- /dev/null
+++ b/drivers/usb/host/ehci-sead3.c
@@ -0,0 +1,266 @@
+/*
+ * MIPS CI13320A EHCI Host Controller driver
+ * Based on "ehci-au1xxx.c" by K.Boge <karsten.boge@amd.com>
+ *
+ * Copyright (C) 2012 MIPS Technologies, 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/platform_device.h>
+
+static int ehci_sead3_setup(struct usb_hcd *hcd)
+{
+ int ret;
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+ ehci->caps = hcd->regs + 0x100;
+
+#ifdef __BIG_ENDIAN
+ ehci->big_endian_mmio = 1;
+ ehci->big_endian_desc = 1;
+#endif
+
+ ret = ehci_setup(hcd);
+ if (ret)
+ return ret;
+
+ ehci->need_io_watchdog = 0;
+
+ /* Set burst length to 16 words. */
+ ehci_writel(ehci, 0x1010, &ehci->regs->reserved[1]);
+
+ return ret;
+}
+
+const struct hc_driver ehci_sead3_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "SEAD-3 EHCI",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ /*
+ * basic lifecycle operations
+ *
+ */
+ .reset = ehci_sead3_setup,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ehci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+};
+
+static int ehci_hcd_sead3_drv_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+ struct resource *res;
+ int ret;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ if (pdev->resource[1].flags != IORESOURCE_IRQ) {
+ pr_debug("resource[1] is not IORESOURCE_IRQ");
+ return -ENOMEM;
+ }
+ hcd = usb_create_hcd(&ehci_sead3_hc_driver, &pdev->dev, "SEAD-3");
+ if (!hcd)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ pr_debug("request_mem_region failed");
+ ret = -EBUSY;
+ goto err1;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ pr_debug("ioremap failed");
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ /* Root hub has integrated TT. */
+ hcd->has_tt = 1;
+
+ ret = usb_add_hcd(hcd, pdev->resource[1].start,
+ IRQF_SHARED);
+ if (ret == 0) {
+ platform_set_drvdata(pdev, hcd);
+ return ret;
+ }
+
+ iounmap(hcd->regs);
+err2:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err1:
+ usb_put_hcd(hcd);
+ return ret;
+}
+
+static int ehci_hcd_sead3_drv_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ehci_hcd_sead3_drv_suspend(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ unsigned long flags;
+ int rc = 0;
+
+ if (time_before(jiffies, ehci->next_statechange))
+ msleep(20);
+
+ /* Root hub was already suspended. Disable irq emission and
+ * mark HW unaccessible. The PM and USB cores make sure that
+ * the root hub is either suspended or stopped.
+ */
+ ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
+ spin_lock_irqsave(&ehci->lock, flags);
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+ (void)ehci_readl(ehci, &ehci->regs->intr_enable);
+
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ spin_unlock_irqrestore(&ehci->lock, flags);
+
+ /* could save FLADJ in case of Vaux power loss
+ * ... we'd only use it to handle clock skew
+ */
+
+ return rc;
+}
+
+static int ehci_hcd_sead3_drv_resume(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+ /* maybe restore FLADJ. */
+
+ if (time_before(jiffies, ehci->next_statechange))
+ msleep(100);
+
+ /* Mark hardware accessible again as we are out of D3 state by now */
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+ /* If CF is still set, we maintained PCI Vaux power.
+ * Just undo the effect of ehci_pci_suspend().
+ */
+ if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
+ int mask = INTR_MASK;
+
+ ehci_prepare_ports_for_controller_resume(ehci);
+ if (!hcd->self.root_hub->do_remote_wakeup)
+ mask &= ~STS_PCD;
+ ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+ ehci_readl(ehci, &ehci->regs->intr_enable);
+ return 0;
+ }
+
+ ehci_dbg(ehci, "lost power, restarting\n");
+ usb_root_hub_lost_power(hcd->self.root_hub);
+
+ /* Else reset, to cope with power loss or flush-to-storage
+ * style "resume" having let BIOS kick in during reboot.
+ */
+ (void) ehci_halt(ehci);
+ (void) ehci_reset(ehci);
+
+ /* emptying the schedule aborts any urbs */
+ spin_lock_irq(&ehci->lock);
+ if (ehci->reclaim)
+ end_unlink_async(ehci);
+ ehci_work(ehci);
+ spin_unlock_irq(&ehci->lock);
+
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
+ ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+ ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
+
+ /* here we "know" root ports should always stay powered */
+ ehci_port_power(ehci, 1);
+
+ ehci->rh_state = EHCI_RH_SUSPENDED;
+
+ return 0;
+}
+
+static const struct dev_pm_ops sead3_ehci_pmops = {
+ .suspend = ehci_hcd_sead3_drv_suspend,
+ .resume = ehci_hcd_sead3_drv_resume,
+};
+
+#define SEAD3_EHCI_PMOPS (&sead3_ehci_pmops)
+
+#else
+#define SEAD3_EHCI_PMOPS NULL
+#endif
+
+static struct platform_driver ehci_hcd_sead3_driver = {
+ .probe = ehci_hcd_sead3_drv_probe,
+ .remove = ehci_hcd_sead3_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+ .driver = {
+ .name = "sead3-ehci",
+ .owner = THIS_MODULE,
+ .pm = SEAD3_EHCI_PMOPS,
+ }
+};
+
+MODULE_ALIAS("platform:sead3-ehci");
diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c
index 9d9cf47d80da..ca819cdd0c5e 100644
--- a/drivers/usb/host/ehci-sh.c
+++ b/drivers/usb/host/ehci-sh.c
@@ -11,6 +11,7 @@
*/
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/platform_data/ehci-sh.h>
struct ehci_sh_priv {
struct clk *iclk, *fclk;
@@ -100,6 +101,7 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev)
const struct hc_driver *driver = &ehci_sh_hc_driver;
struct resource *res;
struct ehci_sh_priv *priv;
+ struct ehci_sh_platdata *pdata;
struct usb_hcd *hcd;
int irq, ret;
@@ -124,6 +126,9 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev)
goto fail_create_hcd;
}
+ if (pdev->dev.platform_data != NULL)
+ pdata = pdev->dev.platform_data;
+
/* initialize hcd */
hcd = usb_create_hcd(&ehci_sh_hc_driver, &pdev->dev,
dev_name(&pdev->dev));
@@ -168,6 +173,9 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev)
clk_enable(priv->fclk);
clk_enable(priv->iclk);
+ if (pdata && pdata->phy_init)
+ pdata->phy_init();
+
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to add hcd");
diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c
index 6e928559169c..37ba8c8d2fd0 100644
--- a/drivers/usb/host/ehci-spear.c
+++ b/drivers/usb/host/ehci-spear.c
@@ -13,6 +13,7 @@
#include <linux/clk.h>
#include <linux/jiffies.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
@@ -25,12 +26,12 @@ struct spear_ehci {
static void spear_start_ehci(struct spear_ehci *ehci)
{
- clk_enable(ehci->clk);
+ clk_prepare_enable(ehci->clk);
}
static void spear_stop_ehci(struct spear_ehci *ehci)
{
- clk_disable(ehci->clk);
+ clk_disable_unprepare(ehci->clk);
}
static int ehci_spear_setup(struct usb_hcd *hcd)
@@ -168,6 +169,8 @@ static int ehci_spear_drv_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(ehci_spear_pm_ops, ehci_spear_drv_suspend,
ehci_spear_drv_resume);
+static u64 spear_ehci_dma_mask = DMA_BIT_MASK(32);
+
static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd ;
@@ -175,12 +178,9 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)
struct resource *res;
struct clk *usbh_clk;
const struct hc_driver *driver = &ehci_spear_hc_driver;
- int *pdata = pdev->dev.platform_data;
int irq, retval;
char clk_name[20] = "usbh_clk";
-
- if (pdata == NULL)
- return -EFAULT;
+ static int instance = -1;
if (usb_disabled())
return -ENODEV;
@@ -191,8 +191,22 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)
goto fail_irq_get;
}
- if (*pdata >= 0)
- sprintf(clk_name, "usbh.%01d_clk", *pdata);
+ /*
+ * Right now device-tree probed devices don't get dma_mask set.
+ * Since shared usb code relies on it, set it here for now.
+ * Once we have dma capability bindings this can go away.
+ */
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &spear_ehci_dma_mask;
+
+ /*
+ * Increment the device instance, when probing via device-tree
+ */
+ if (pdev->id < 0)
+ instance++;
+ else
+ instance = pdev->id;
+ sprintf(clk_name, "usbh.%01d_clk", instance);
usbh_clk = clk_get(NULL, clk_name);
if (IS_ERR(usbh_clk)) {
@@ -277,6 +291,11 @@ static int spear_ehci_hcd_drv_remove(struct platform_device *pdev)
return 0;
}
+static struct of_device_id spear_ehci_id_table[] __devinitdata = {
+ { .compatible = "st,spear600-ehci", },
+ { },
+};
+
static struct platform_driver spear_ehci_hcd_driver = {
.probe = spear_ehci_hcd_drv_probe,
.remove = spear_ehci_hcd_drv_remove,
@@ -285,6 +304,7 @@ static struct platform_driver spear_ehci_hcd_driver = {
.name = "spear-ehci",
.bus = &platform_bus_type,
.pm = &ehci_spear_pm_ops,
+ .of_match_table = of_match_ptr(spear_ehci_id_table),
}
};
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index f214a80cdee2..4a44bf833611 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -147,18 +147,7 @@ static int tegra_ehci_hub_control(
spin_lock_irqsave(&ehci->lock, flags);
- /*
- * In ehci_hub_control() for USB_PORT_FEAT_ENABLE clears the other bits
- * that are write on clear, by writing back the register read value, so
- * USB_PORT_FEAT_ENABLE is handled by masking the set on clear bits
- */
- if (typeReq == ClearPortFeature && wValue == USB_PORT_FEAT_ENABLE) {
- temp = ehci_readl(ehci, status_reg) & ~PORT_RWC_BITS;
- ehci_writel(ehci, temp & ~PORT_PE, status_reg);
- goto done;
- }
-
- else if (typeReq == GetPortStatus) {
+ if (typeReq == GetPortStatus) {
temp = ehci_readl(ehci, status_reg);
if (tegra->port_resuming && !(temp & PORT_SUSPEND)) {
/* Resume completed, re-enable disconnect detection */
@@ -174,7 +163,7 @@ static int tegra_ehci_hub_control(
goto done;
}
- temp &= ~PORT_WKCONN_E;
+ temp &= ~(PORT_RWC_BITS | PORT_WKCONN_E);
temp |= PORT_WKDISC_E | PORT_WKOC_E;
ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
@@ -319,26 +308,23 @@ static int tegra_ehci_setup(struct usb_hcd *hcd)
return retval;
}
-struct temp_buffer {
+struct dma_aligned_buffer {
void *kmalloc_ptr;
void *old_xfer_buffer;
u8 data[0];
};
-static void free_temp_buffer(struct urb *urb)
+static void free_dma_aligned_buffer(struct urb *urb)
{
- enum dma_data_direction dir;
- struct temp_buffer *temp;
+ struct dma_aligned_buffer *temp;
if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER))
return;
- dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
-
- temp = container_of(urb->transfer_buffer, struct temp_buffer,
- data);
+ temp = container_of(urb->transfer_buffer,
+ struct dma_aligned_buffer, data);
- if (dir == DMA_FROM_DEVICE)
+ if (usb_urb_dir_in(urb))
memcpy(temp->old_xfer_buffer, temp->data,
urb->transfer_buffer_length);
urb->transfer_buffer = temp->old_xfer_buffer;
@@ -347,10 +333,9 @@ static void free_temp_buffer(struct urb *urb)
urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER;
}
-static int alloc_temp_buffer(struct urb *urb, gfp_t mem_flags)
+static int alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags)
{
- enum dma_data_direction dir;
- struct temp_buffer *temp, *kmalloc_ptr;
+ struct dma_aligned_buffer *temp, *kmalloc_ptr;
size_t kmalloc_size;
if (urb->num_sgs || urb->sg ||
@@ -358,22 +343,19 @@ static int alloc_temp_buffer(struct urb *urb, gfp_t mem_flags)
!((uintptr_t)urb->transfer_buffer & (TEGRA_USB_DMA_ALIGN - 1)))
return 0;
- dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
-
/* Allocate a buffer with enough padding for alignment */
kmalloc_size = urb->transfer_buffer_length +
- sizeof(struct temp_buffer) + TEGRA_USB_DMA_ALIGN - 1;
+ sizeof(struct dma_aligned_buffer) + TEGRA_USB_DMA_ALIGN - 1;
kmalloc_ptr = kmalloc(kmalloc_size, mem_flags);
if (!kmalloc_ptr)
return -ENOMEM;
- /* Position our struct temp_buffer such that data is aligned */
+ /* Position our struct dma_aligned_buffer such that data is aligned */
temp = PTR_ALIGN(kmalloc_ptr + 1, TEGRA_USB_DMA_ALIGN) - 1;
-
temp->kmalloc_ptr = kmalloc_ptr;
temp->old_xfer_buffer = urb->transfer_buffer;
- if (dir == DMA_TO_DEVICE)
+ if (usb_urb_dir_out(urb))
memcpy(temp->data, urb->transfer_buffer,
urb->transfer_buffer_length);
urb->transfer_buffer = temp->data;
@@ -388,13 +370,13 @@ static int tegra_ehci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
{
int ret;
- ret = alloc_temp_buffer(urb, mem_flags);
+ ret = alloc_dma_aligned_buffer(urb, mem_flags);
if (ret)
return ret;
ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
if (ret)
- free_temp_buffer(urb);
+ free_dma_aligned_buffer(urb);
return ret;
}
@@ -402,49 +384,51 @@ static int tegra_ehci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
{
usb_hcd_unmap_urb_for_dma(hcd, urb);
- free_temp_buffer(urb);
+ free_dma_aligned_buffer(urb);
}
static const struct hc_driver tegra_ehci_hc_driver = {
.description = hcd_name,
.product_desc = "Tegra EHCI Host Controller",
.hcd_priv_size = sizeof(struct ehci_hcd),
-
.flags = HCD_USB2 | HCD_MEMORY,
- .reset = tegra_ehci_setup,
+ /* standard ehci functions */
.irq = ehci_irq,
-
.start = ehci_run,
.stop = ehci_stop,
- .shutdown = tegra_ehci_shutdown,
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
- .map_urb_for_dma = tegra_ehci_map_urb_for_dma,
- .unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma,
.endpoint_disable = ehci_endpoint_disable,
.endpoint_reset = ehci_endpoint_reset,
.get_frame_number = ehci_get_frame,
.hub_status_data = ehci_hub_status_data,
- .hub_control = tegra_ehci_hub_control,
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+
+ /* modified ehci functions for tegra */
+ .reset = tegra_ehci_setup,
+ .shutdown = tegra_ehci_shutdown,
+ .map_urb_for_dma = tegra_ehci_map_urb_for_dma,
+ .unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma,
+ .hub_control = tegra_ehci_hub_control,
#ifdef CONFIG_PM
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
#endif
- .relinquish_port = ehci_relinquish_port,
- .port_handed_over = ehci_port_handed_over,
};
-static int setup_vbus_gpio(struct platform_device *pdev)
+static int setup_vbus_gpio(struct platform_device *pdev,
+ struct tegra_ehci_platform_data *pdata)
{
int err = 0;
int gpio;
- if (!pdev->dev.of_node)
- return 0;
-
- gpio = of_get_named_gpio(pdev->dev.of_node, "nvidia,vbus-gpio", 0);
+ gpio = pdata->vbus_gpio;
+ if (!gpio_is_valid(gpio))
+ gpio = of_get_named_gpio(pdev->dev.of_node,
+ "nvidia,vbus-gpio", 0);
if (!gpio_is_valid(gpio))
return 0;
@@ -664,7 +648,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
if (!pdev->dev.dma_mask)
pdev->dev.dma_mask = &tegra_ehci_dma_mask;
- setup_vbus_gpio(pdev);
+ setup_vbus_gpio(pdev, pdata);
tegra = kzalloc(sizeof(struct tegra_ehci_hcd), GFP_KERNEL);
if (!tegra)
diff --git a/drivers/usb/host/fhci-tds.c b/drivers/usb/host/fhci-tds.c
index 0ea577bfca2a..c5ed88199292 100644
--- a/drivers/usb/host/fhci-tds.c
+++ b/drivers/usb/host/fhci-tds.c
@@ -155,7 +155,7 @@ u32 fhci_create_ep(struct fhci_usb *usb, enum fhci_mem_alloc data_mem,
struct endpoint *ep;
struct usb_td __iomem *td;
unsigned long ep_offset;
- char *err_for = "enpoint PRAM";
+ char *err_for = "endpoint PRAM";
int ep_mem_size;
u32 i;
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
index ab333ac6071d..22ff6b3a676f 100644
--- a/drivers/usb/host/fsl-mph-dr-of.c
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -119,6 +119,39 @@ error:
static const struct of_device_id fsl_usb2_mph_dr_of_match[];
+static int usb_get_ver_info(struct device_node *np)
+{
+ int ver = -1;
+
+ /*
+ * returns 1 for usb controller version 1.6
+ * returns 2 for usb controller version 2.2
+ * returns 0 otherwise
+ */
+ if (of_device_is_compatible(np, "fsl-usb2-dr")) {
+ if (of_device_is_compatible(np, "fsl-usb2-dr-v1.6"))
+ ver = FSL_USB_VER_1_6;
+ else if (of_device_is_compatible(np, "fsl-usb2-dr-v2.2"))
+ ver = FSL_USB_VER_2_2;
+ else /* for previous controller versions */
+ ver = FSL_USB_VER_OLD;
+
+ if (ver > -1)
+ return ver;
+ }
+
+ if (of_device_is_compatible(np, "fsl-usb2-mph")) {
+ if (of_device_is_compatible(np, "fsl-usb2-mph-v1.6"))
+ ver = FSL_USB_VER_1_6;
+ else if (of_device_is_compatible(np, "fsl-usb2-mph-v2.2"))
+ ver = FSL_USB_VER_2_2;
+ else /* for previous controller versions */
+ ver = FSL_USB_VER_OLD;
+ }
+
+ return ver;
+}
+
static int __devinit fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev)
{
struct device_node *np = ofdev->dev.of_node;
@@ -166,6 +199,14 @@ static int __devinit fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev)
prop = of_get_property(np, "phy_type", NULL);
pdata->phy_mode = determine_usb_phy(prop);
+ pdata->controller_ver = usb_get_ver_info(np);
+
+ if (pdata->have_sysif_regs) {
+ if (pdata->controller_ver < 0) {
+ dev_warn(&ofdev->dev, "Could not get controller version\n");
+ return -ENODEV;
+ }
+ }
for (i = 0; i < ARRAY_SIZE(dev_data->drivers); i++) {
if (!dev_data->drivers[i])
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
index fc72d44bf787..a35bbddf8968 100644
--- a/drivers/usb/host/isp1760-hcd.c
+++ b/drivers/usb/host/isp1760-hcd.c
@@ -1562,11 +1562,14 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
retval = -ESHUTDOWN;
+ qtd_list_free(&new_qtds);
goto out;
}
retval = usb_hcd_link_urb_to_ep(hcd, urb);
- if (retval)
+ if (retval) {
+ qtd_list_free(&new_qtds);
goto out;
+ }
qh = urb->ep->hcpriv;
if (qh) {
@@ -1584,6 +1587,7 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
if (!qh) {
retval = -ENOMEM;
usb_hcd_unlink_urb_from_ep(hcd, urb);
+ qtd_list_free(&new_qtds);
goto out;
}
list_add_tail(&qh->qh_list, ep_queue);
@@ -1683,6 +1687,7 @@ static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
list_for_each_entry(qtd, &qh->qtd_list, qtd_list)
if (qtd->urb == urb) {
dequeue_urb_from_qtd(hcd, qh, qtd);
+ list_move(&qtd->qtd_list, &qh->qtd_list);
break;
}
@@ -2176,7 +2181,7 @@ static const struct hc_driver isp1760_hc_driver = {
int __init init_kmem_once(void)
{
- urb_listitem_cachep = kmem_cache_create("isp1760 urb_listitem",
+ urb_listitem_cachep = kmem_cache_create("isp1760_urb_listitem",
sizeof(struct urb_listitem), 0, SLAB_TEMPORARY |
SLAB_MEM_SPREAD, NULL);
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c
index 4592dc17a9f9..fff114fd5461 100644
--- a/drivers/usb/host/isp1760-if.c
+++ b/drivers/usb/host/isp1760-if.c
@@ -398,6 +398,9 @@ static int __devinit isp1760_plat_probe(struct platform_device *pdev)
hcd = isp1760_register(mem_res->start, mem_size, irq_res->start,
irqflags, -ENOENT,
&pdev->dev, dev_name(&pdev->dev), devflags);
+
+ dev_set_drvdata(&pdev->dev, hcd);
+
if (IS_ERR(hcd)) {
pr_warning("isp1760: Failed to register the HCD device\n");
ret = -ENODEV;
@@ -417,11 +420,16 @@ static int __devexit isp1760_plat_remove(struct platform_device *pdev)
{
struct resource *mem_res;
resource_size_t mem_size;
+ struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev);
+
+ usb_remove_hcd(hcd);
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mem_size = resource_size(mem_res);
release_mem_region(mem_res->start, mem_size);
+ usb_put_hcd(hcd);
+
return 0;
}
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 13ebeca8e73e..a665b3eaa746 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -129,7 +129,7 @@ static int __devinit usb_hcd_at91_probe(const struct hc_driver *driver,
if (!hcd)
return -ENOMEM;
hcd->rsrc_start = pdev->resource[0].start;
- hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
+ hcd->rsrc_len = resource_size(&pdev->resource[0]);
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
pr_debug("request_mem_region failed\n");
@@ -223,7 +223,7 @@ static void __devexit usb_hcd_at91_remove(struct usb_hcd *hcd,
/*-------------------------------------------------------------------------*/
static int __devinit
-ohci_at91_start (struct usb_hcd *hcd)
+ohci_at91_reset (struct usb_hcd *hcd)
{
struct at91_usbh_data *board = hcd->self.controller->platform_data;
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
@@ -233,9 +233,18 @@ ohci_at91_start (struct usb_hcd *hcd)
return ret;
ohci->num_ports = board->ports;
+ return 0;
+}
+
+static int __devinit
+ohci_at91_start (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ int ret;
if ((ret = ohci_run(ohci)) < 0) {
- err("can't start %s", hcd->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s\n",
+ hcd->self.bus_name);
ohci_stop(hcd);
return ret;
}
@@ -418,6 +427,7 @@ static const struct hc_driver ohci_at91_hc_driver = {
/*
* basic lifecycle operations
*/
+ .reset = ohci_at91_reset,
.start = ohci_at91_start,
.stop = ohci_stop,
.shutdown = ohci_shutdown,
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index 4ea63b2cac42..c611699b4aa6 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -37,7 +37,8 @@ static int __devinit ohci_au1xxx_start(struct usb_hcd *hcd)
return ret;
if ((ret = ohci_run(ohci)) < 0) {
- err ("can't start %s", hcd->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s",
+ hcd->self.bus_name);
ohci_stop(hcd);
return ret;
}
diff --git a/drivers/usb/host/ohci-cns3xxx.c b/drivers/usb/host/ohci-cns3xxx.c
index 5a00a1e1c6ca..2c9f233047be 100644
--- a/drivers/usb/host/ohci-cns3xxx.c
+++ b/drivers/usb/host/ohci-cns3xxx.c
@@ -41,7 +41,8 @@ cns3xxx_ohci_start(struct usb_hcd *hcd)
ret = ohci_run(ohci);
if (ret < 0) {
- err("can't start %s", hcd->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s\n",
+ hcd->self.bus_name);
ohci_stop(hcd);
return ret;
}
diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c
index 843509778a33..269b1e0f7691 100644
--- a/drivers/usb/host/ohci-da8xx.c
+++ b/drivers/usb/host/ohci-da8xx.c
@@ -454,3 +454,5 @@ static struct platform_driver ohci_hcd_da8xx_driver = {
.name = "ohci",
},
};
+
+MODULE_ALIAS("platform:ohci");
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index e4bcb62b930a..31b81f9eacdc 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -29,14 +29,14 @@ urb_print(struct urb * urb, char * str, int small, int status)
unsigned int pipe= urb->pipe;
if (!urb->dev || !urb->dev->bus) {
- dbg("%s URB: no dev", str);
+ printk(KERN_DEBUG "%s URB: no dev\n", str);
return;
}
#ifndef OHCI_VERBOSE_DEBUG
if (status != 0)
#endif
- dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d",
+ printk(KERN_DEBUG "%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d\n",
str,
urb,
usb_pipedevice (pipe),
diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c
index 3d63574d2c7e..dbfbd1dfd2e2 100644
--- a/drivers/usb/host/ohci-ep93xx.c
+++ b/drivers/usb/host/ohci-ep93xx.c
@@ -47,7 +47,7 @@ static int usb_hcd_ep93xx_probe(const struct hc_driver *driver,
struct usb_hcd *hcd;
if (pdev->resource[1].flags != IORESOURCE_IRQ) {
- dbg("resource[1] is not IORESOURCE_IRQ");
+ dev_dbg(&pdev->dev, "resource[1] is not IORESOURCE_IRQ\n");
return -ENOMEM;
}
@@ -65,14 +65,14 @@ static int usb_hcd_ep93xx_probe(const struct hc_driver *driver,
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (hcd->regs == NULL) {
- dbg("ioremap failed");
+ dev_dbg(&pdev->dev, "ioremap failed\n");
retval = -ENOMEM;
goto err2;
}
usb_host_clock = clk_get(&pdev->dev, NULL);
if (IS_ERR(usb_host_clock)) {
- dbg("clk_get failed");
+ dev_dbg(&pdev->dev, "clk_get failed\n");
retval = PTR_ERR(usb_host_clock);
goto err3;
}
@@ -116,7 +116,8 @@ static int __devinit ohci_ep93xx_start(struct usb_hcd *hcd)
return ret;
if ((ret = ohci_run(ohci)) < 0) {
- err("can't start %s", hcd->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s\n",
+ hcd->self.bus_name);
ohci_stop(hcd);
return ret;
}
diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c
index 37bb20ebb6fc..2909621ea196 100644
--- a/drivers/usb/host/ohci-exynos.c
+++ b/drivers/usb/host/ohci-exynos.c
@@ -35,7 +35,8 @@ static int ohci_exynos_start(struct usb_hcd *hcd)
ret = ohci_run(ohci);
if (ret < 0) {
- err("can't start %s", hcd->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s\n",
+ hcd->self.bus_name);
ohci_stop(hcd);
return ret;
}
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 235171f29460..e0adf5c0cf55 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1080,11 +1080,6 @@ MODULE_LICENSE ("GPL");
#define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver
#endif
-#ifdef CONFIG_USB_OHCI_HCD_SSB
-#include "ohci-ssb.c"
-#define SSB_OHCI_DRIVER ssb_ohci_driver
-#endif
-
#ifdef CONFIG_MFD_SM501
#include "ohci-sm501.c"
#define SM501_OHCI_DRIVER ohci_hcd_sm501_driver
@@ -1128,8 +1123,7 @@ MODULE_LICENSE ("GPL");
!defined(SA1111_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER) && \
!defined(SM501_OHCI_DRIVER) && \
- !defined(TMIO_OHCI_DRIVER) && \
- !defined(SSB_OHCI_DRIVER)
+ !defined(TMIO_OHCI_DRIVER)
#error "missing bus glue for ohci-hcd"
#endif
@@ -1195,12 +1189,6 @@ static int __init ohci_hcd_mod_init(void)
goto error_pci;
#endif
-#ifdef SSB_OHCI_DRIVER
- retval = ssb_driver_register(&SSB_OHCI_DRIVER);
- if (retval)
- goto error_ssb;
-#endif
-
#ifdef SM501_OHCI_DRIVER
retval = platform_driver_register(&SM501_OHCI_DRIVER);
if (retval < 0)
@@ -1224,10 +1212,6 @@ static int __init ohci_hcd_mod_init(void)
platform_driver_unregister(&SM501_OHCI_DRIVER);
error_sm501:
#endif
-#ifdef SSB_OHCI_DRIVER
- ssb_driver_unregister(&SSB_OHCI_DRIVER);
- error_ssb:
-#endif
#ifdef PCI_DRIVER
pci_unregister_driver(&PCI_DRIVER);
error_pci:
@@ -1275,9 +1259,6 @@ static void __exit ohci_hcd_mod_exit(void)
#ifdef SM501_OHCI_DRIVER
platform_driver_unregister(&SM501_OHCI_DRIVER);
#endif
-#ifdef SSB_OHCI_DRIVER
- ssb_driver_unregister(&SSB_OHCI_DRIVER);
-#endif
#ifdef PCI_DRIVER
pci_unregister_driver(&PCI_DRIVER);
#endif
diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c
index 6618de1d881d..1e364ec962fb 100644
--- a/drivers/usb/host/ohci-nxp.c
+++ b/drivers/usb/host/ohci-nxp.c
@@ -22,6 +22,8 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
+#include <linux/of.h>
+#include <linux/usb/isp1301.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
@@ -29,7 +31,6 @@
#include <mach/platform.h>
#include <mach/irqs.h>
-#include <asm/gpio.h>
#define USB_CONFIG_BASE 0x31020000
#define PWRMAN_BASE 0x40004000
@@ -38,7 +39,9 @@
/* USB_CTRL bit defines */
#define USB_SLAVE_HCLK_EN (1 << 24)
+#define USB_DEV_NEED_CLK_EN (1 << 22)
#define USB_HOST_NEED_CLK_EN (1 << 21)
+#define PAD_CONTROL_LAST_DRIVEN (1 << 19)
#define USB_OTG_CLK_CTRL IO_ADDRESS(USB_CONFIG_BASE + 0xFF4)
#define USB_OTG_CLK_STAT IO_ADDRESS(USB_CONFIG_BASE + 0xFF8)
@@ -56,54 +59,6 @@
#define TRANSPARENT_I2C_EN (1 << 7)
#define HOST_EN (1 << 0)
-/* ISP1301 USB transceiver I2C registers */
-#define ISP1301_MODE_CONTROL_1 0x04 /* u8 read, set, +1 clear */
-
-#define MC1_SPEED_REG (1 << 0)
-#define MC1_SUSPEND_REG (1 << 1)
-#define MC1_DAT_SE0 (1 << 2)
-#define MC1_TRANSPARENT (1 << 3)
-#define MC1_BDIS_ACON_EN (1 << 4)
-#define MC1_OE_INT_EN (1 << 5)
-#define MC1_UART_EN (1 << 6)
-#define MC1_MASK 0x7f
-
-#define ISP1301_MODE_CONTROL_2 0x12 /* u8 read, set, +1 clear */
-
-#define MC2_GLOBAL_PWR_DN (1 << 0)
-#define MC2_SPD_SUSP_CTRL (1 << 1)
-#define MC2_BI_DI (1 << 2)
-#define MC2_TRANSP_BDIR0 (1 << 3)
-#define MC2_TRANSP_BDIR1 (1 << 4)
-#define MC2_AUDIO_EN (1 << 5)
-#define MC2_PSW_EN (1 << 6)
-#define MC2_EN2V7 (1 << 7)
-
-#define ISP1301_OTG_CONTROL_1 0x06 /* u8 read, set, +1 clear */
-# define OTG1_DP_PULLUP (1 << 0)
-# define OTG1_DM_PULLUP (1 << 1)
-# define OTG1_DP_PULLDOWN (1 << 2)
-# define OTG1_DM_PULLDOWN (1 << 3)
-# define OTG1_ID_PULLDOWN (1 << 4)
-# define OTG1_VBUS_DRV (1 << 5)
-# define OTG1_VBUS_DISCHRG (1 << 6)
-# define OTG1_VBUS_CHRG (1 << 7)
-#define ISP1301_OTG_STATUS 0x10 /* u8 readonly */
-# define OTG_B_SESS_END (1 << 6)
-# define OTG_B_SESS_VLD (1 << 7)
-
-#define ISP1301_I2C_ADDR 0x2C
-
-#define ISP1301_I2C_MODE_CONTROL_1 0x4
-#define ISP1301_I2C_MODE_CONTROL_2 0x12
-#define ISP1301_I2C_OTG_CONTROL_1 0x6
-#define ISP1301_I2C_OTG_CONTROL_2 0x10
-#define ISP1301_I2C_INTERRUPT_SOURCE 0x8
-#define ISP1301_I2C_INTERRUPT_LATCH 0xA
-#define ISP1301_I2C_INTERRUPT_FALLING 0xC
-#define ISP1301_I2C_INTERRUPT_RISING 0xE
-#define ISP1301_I2C_REG_CLEAR_ADDR 1
-
/* On LPC32xx, those are undefined */
#ifndef start_int_set_falling_edge
#define start_int_set_falling_edge(irq)
@@ -113,42 +68,12 @@
#define start_int_umask(irq)
#endif
-static struct i2c_driver isp1301_driver;
static struct i2c_client *isp1301_i2c_client;
extern int usb_disabled(void);
-extern int ocpi_enable(void);
static struct clk *usb_clk;
-static const unsigned short normal_i2c[] =
- { ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END };
-
-static int isp1301_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- return 0;
-}
-
-static int isp1301_remove(struct i2c_client *client)
-{
- return 0;
-}
-
-static const struct i2c_device_id isp1301_id[] = {
- { "isp1301_nxp", 0 },
- { }
-};
-
-static struct i2c_driver isp1301_driver = {
- .driver = {
- .name = "isp1301_nxp",
- },
- .probe = isp1301_probe,
- .remove = isp1301_remove,
- .id_table = isp1301_id,
-};
-
static void isp1301_configure_pnx4008(void)
{
/* PNX4008 only supports DAT_SE0 USB mode */
@@ -220,7 +145,7 @@ static void isp1301_configure_lpc32xx(void)
ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR, ~0);
/* Enable usb_need_clk clock after transceiver is initialized */
- __raw_writel((__raw_readl(USB_CTRL) | (1 << 22)), USB_CTRL);
+ __raw_writel(__raw_readl(USB_CTRL) | USB_HOST_NEED_CLK_EN, USB_CTRL);
printk(KERN_INFO "ISP1301 Vendor ID : 0x%04x\n",
i2c_smbus_read_word_data(isp1301_i2c_client, 0x00));
@@ -372,65 +297,55 @@ static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev)
struct usb_hcd *hcd = 0;
struct ohci_hcd *ohci;
const struct hc_driver *driver = &ohci_nxp_hc_driver;
- struct i2c_adapter *i2c_adap;
- struct i2c_board_info i2c_info;
-
+ struct resource *res;
int ret = 0, irq;
+ struct device_node *isp1301_node;
- dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (nxp)\n", hcd_name);
- if (usb_disabled()) {
- err("USB is disabled");
- ret = -ENODEV;
- goto out;
+ if (pdev->dev.of_node) {
+ isp1301_node = of_parse_phandle(pdev->dev.of_node,
+ "transceiver", 0);
+ } else {
+ isp1301_node = NULL;
}
- if (pdev->num_resources != 2
- || pdev->resource[0].flags != IORESOURCE_MEM
- || pdev->resource[1].flags != IORESOURCE_IRQ) {
- err("Invalid resource configuration");
- ret = -ENODEV;
+ isp1301_i2c_client = isp1301_get_client(isp1301_node);
+ if (!isp1301_i2c_client) {
+ ret = -EPROBE_DEFER;
goto out;
}
- /* Enable AHB slave USB clock, needed for further USB clock control */
- __raw_writel(USB_SLAVE_HCLK_EN | (1 << 19), USB_CTRL);
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
- ret = i2c_add_driver(&isp1301_driver);
- if (ret < 0) {
- err("failed to add ISP1301 driver");
- goto out;
- }
- i2c_adap = i2c_get_adapter(2);
- memset(&i2c_info, 0, sizeof(struct i2c_board_info));
- strlcpy(i2c_info.type, "isp1301_nxp", I2C_NAME_SIZE);
- isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,
- normal_i2c, NULL);
- i2c_put_adapter(i2c_adap);
- if (!isp1301_i2c_client) {
- err("failed to connect I2C to ISP1301 USB Transceiver");
+ dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (nxp)\n", hcd_name);
+ if (usb_disabled()) {
+ dev_err(&pdev->dev, "USB is disabled\n");
ret = -ENODEV;
- goto out_i2c_driver;
+ goto out;
}
+ /* Enable AHB slave USB clock, needed for further USB clock control */
+ __raw_writel(USB_SLAVE_HCLK_EN | PAD_CONTROL_LAST_DRIVEN, USB_CTRL);
+
isp1301_configure();
/* Enable USB PLL */
usb_clk = clk_get(&pdev->dev, "ck_pll5");
if (IS_ERR(usb_clk)) {
- err("failed to acquire USB PLL");
+ dev_err(&pdev->dev, "failed to acquire USB PLL\n");
ret = PTR_ERR(usb_clk);
goto out1;
}
ret = clk_enable(usb_clk);
if (ret < 0) {
- err("failed to start USB PLL");
+ dev_err(&pdev->dev, "failed to start USB PLL\n");
goto out2;
}
ret = clk_set_rate(usb_clk, 48000);
if (ret < 0) {
- err("failed to set USB clock rate");
+ dev_err(&pdev->dev, "failed to set USB clock rate\n");
goto out3;
}
@@ -442,9 +357,9 @@ static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev)
while ((__raw_readl(USB_OTG_CLK_STAT) & USB_CLOCK_MASK) !=
USB_CLOCK_MASK) ;
- hcd = usb_create_hcd (driver, &pdev->dev, dev_name(&pdev->dev));
+ hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
if (!hcd) {
- err("Failed to allocate HC buffer");
+ dev_err(&pdev->dev, "Failed to allocate HC buffer\n");
ret = -ENOMEM;
goto out3;
}
@@ -452,14 +367,21 @@ static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev)
/* Set all USB bits in the Start Enable register */
nxp_set_usb_bits();
- hcd->rsrc_start = pdev->resource[0].start;
- hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
- if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
- dev_dbg(&pdev->dev, "request_mem_region failed\n");
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get MEM resource\n");
+ ret = -ENOMEM;
+ goto out4;
+ }
+
+ hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
+ if (!hcd->regs) {
+ dev_err(&pdev->dev, "Failed to devm_request_and_ioremap\n");
ret = -ENOMEM;
goto out4;
}
- hcd->regs = (void __iomem *)pdev->resource[0].start;
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
@@ -486,10 +408,7 @@ out3:
out2:
clk_put(usb_clk);
out1:
- i2c_unregister_device(isp1301_i2c_client);
isp1301_i2c_client = NULL;
-out_i2c_driver:
- i2c_del_driver(&isp1301_driver);
out:
return ret;
}
@@ -507,7 +426,6 @@ static int usb_hcd_nxp_remove(struct platform_device *pdev)
clk_put(usb_clk);
i2c_unregister_device(isp1301_i2c_client);
isp1301_i2c_client = NULL;
- i2c_del_driver(&isp1301_driver);
platform_set_drvdata(pdev, NULL);
@@ -517,10 +435,19 @@ static int usb_hcd_nxp_remove(struct platform_device *pdev)
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:usb-ohci");
+#ifdef CONFIG_OF
+static const struct of_device_id usb_hcd_nxp_match[] = {
+ { .compatible = "nxp,ohci-nxp" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, usb_hcd_nxp_match);
+#endif
+
static struct platform_driver usb_hcd_nxp_driver = {
.driver = {
.name = "usb-ohci",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(usb_hcd_nxp_match),
},
.probe = usb_hcd_nxp_probe,
.remove = usb_hcd_nxp_remove,
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 96451e41ee8a..9ce35d0d9d5d 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -205,8 +205,9 @@ static int ohci_omap_init(struct usb_hcd *hcd)
need_transceiver = need_transceiver
|| machine_is_omap_h2() || machine_is_omap_h3();
- if (cpu_is_omap16xx())
- ocpi_enable();
+ /* XXX OMAP16xx only */
+ if (config->ocpi_enable)
+ config->ocpi_enable();
#ifdef CONFIG_USB_OTG
if (need_transceiver) {
@@ -217,8 +218,7 @@ static int ohci_omap_init(struct usb_hcd *hcd)
dev_dbg(hcd->self.controller, "init %s transceiver, status %d\n",
ohci->transceiver->label, status);
if (status) {
- if (ohci->transceiver)
- put_device(ohci->transceiver->dev);
+ usb_put_transceiver(ohci->transceiver);
return status;
}
} else {
@@ -405,7 +405,7 @@ usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)
usb_remove_hcd(hcd);
if (ohci->transceiver) {
(void) otg_set_host(ohci->transceiver->otg, 0);
- put_device(ohci->transceiver->dev);
+ usb_put_transceiver(ohci->transceiver);
}
if (machine_is_omap_osk())
gpio_free(9);
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index ec5c6791c8b4..670c7059c9ae 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -93,13 +93,13 @@ static int __devinit ohci_platform_probe(struct platform_device *dev)
irq = platform_get_irq(dev, 0);
if (irq < 0) {
- pr_err("no irq provieded");
+ pr_err("no irq provided");
return irq;
}
res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!res_mem) {
- pr_err("no memory recourse provieded");
+ pr_err("no memory recourse provided");
return -ENXIO;
}
diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c
index f13d08f94d6b..148d27d6a67c 100644
--- a/drivers/usb/host/ohci-pnx8550.c
+++ b/drivers/usb/host/ohci-pnx8550.c
@@ -157,7 +157,8 @@ ohci_pnx8550_start (struct usb_hcd *hcd)
return ret;
if ((ret = ohci_run (ohci)) < 0) {
- err ("can't start %s", hcd->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s",
+ hcd->self.bus_name);
ohci_stop (hcd);
return ret;
}
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index d24cc89de16f..e27d5ae2b9eb 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -29,7 +29,8 @@ ohci_ppc_of_start(struct usb_hcd *hcd)
return ret;
if ((ret = ohci_run(ohci)) < 0) {
- err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s\n",
+ hcd->self.bus_name);
ohci_stop(hcd);
return ret;
}
@@ -236,7 +237,7 @@ MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match);
#if !defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \
!defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE)
-#error "No endianess selected for ppc-of-ohci"
+#error "No endianness selected for ppc-of-ohci"
#endif
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index 1514b7067470..185c39ed81b7 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -130,7 +130,8 @@ ohci_ppc_soc_start(struct usb_hcd *hcd)
return ret;
if ((ret = ohci_run(ohci)) < 0) {
- err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s\n",
+ hcd->self.bus_name);
ohci_stop(hcd);
return ret;
}
diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c
index 6fd4fa1f19bb..2ee1d8d713d2 100644
--- a/drivers/usb/host/ohci-ps3.c
+++ b/drivers/usb/host/ohci-ps3.c
@@ -45,7 +45,8 @@ static int __devinit ps3_ohci_hc_start(struct usb_hcd *hcd)
result = ohci_run(ohci);
if (result < 0) {
- err("can't start %s", hcd->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s\n",
+ hcd->self.bus_name);
ohci_stop(hcd);
}
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index c31b2815be1c..e1a3cc6d28dc 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -419,7 +419,8 @@ ohci_pxa27x_start (struct usb_hcd *hcd)
return ret;
if ((ret = ohci_run (ohci)) < 0) {
- err ("can't start %s", hcd->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s",
+ hcd->self.bus_name);
ohci_stop (hcd);
return ret;
}
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index 56dcf069246d..664c869eb096 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -420,7 +420,8 @@ ohci_s3c2410_start(struct usb_hcd *hcd)
ret = ohci_run(ohci);
if (ret < 0) {
- err("can't start %s", hcd->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s\n",
+ hcd->self.bus_name);
ohci_stop(hcd);
return ret;
}
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index e1004fb37bd9..b6cc92520924 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -46,7 +46,7 @@ static void dump_hci_status(struct usb_hcd *hcd, const char *label)
{
unsigned long status = sa1111_readl(hcd->regs + USB_STATUS);
- dbg("%s USB_STATUS = { %s%s%s%s%s}", label,
+ printk(KERN_DEBUG "%s USB_STATUS = { %s%s%s%s%s}\n", label,
((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""),
((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""),
((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "),
@@ -193,7 +193,7 @@ static int ohci_hcd_sa1111_probe(struct sa1111_dev *dev)
hcd->rsrc_len = resource_size(&dev->res);
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
- dbg("request_mem_region failed");
+ dev_dbg(&dev->dev, "request_mem_region failed\n");
ret = -EBUSY;
goto err1;
}
diff --git a/drivers/usb/host/ohci-sh.c b/drivers/usb/host/ohci-sh.c
index 84686d90805b..76a20c278362 100644
--- a/drivers/usb/host/ohci-sh.c
+++ b/drivers/usb/host/ohci-sh.c
@@ -88,20 +88,20 @@ static int ohci_hcd_sh_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
- err("platform_get_resource error.");
+ dev_err(&pdev->dev, "platform_get_resource error.\n");
return -ENODEV;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
- err("platform_get_irq error.");
+ dev_err(&pdev->dev, "platform_get_irq error.\n");
return -ENODEV;
}
/* initialize hcd */
hcd = usb_create_hcd(&ohci_sh_hc_driver, &pdev->dev, (char *)hcd_name);
if (!hcd) {
- err("Failed to create hcd");
+ dev_err(&pdev->dev, "Failed to create hcd\n");
return -ENOMEM;
}
@@ -110,7 +110,7 @@ static int ohci_hcd_sh_probe(struct platform_device *pdev)
hcd->rsrc_len = resource_size(res);
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret != 0) {
- err("Failed to add hcd");
+ dev_err(&pdev->dev, "Failed to add hcd\n");
usb_put_hcd(hcd);
return ret;
}
diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c
index 95c16489e883..fc7305ee3c9c 100644
--- a/drivers/usb/host/ohci-spear.c
+++ b/drivers/usb/host/ohci-spear.c
@@ -14,6 +14,7 @@
#include <linux/signal.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/of.h>
struct spear_ohci {
struct ohci_hcd ohci;
@@ -24,12 +25,12 @@ struct spear_ohci {
static void spear_start_ohci(struct spear_ohci *ohci)
{
- clk_enable(ohci->clk);
+ clk_prepare_enable(ohci->clk);
}
static void spear_stop_ohci(struct spear_ohci *ohci)
{
- clk_disable(ohci->clk);
+ clk_disable_unprepare(ohci->clk);
}
static int __devinit ohci_spear_start(struct usb_hcd *hcd)
@@ -90,6 +91,8 @@ static const struct hc_driver ohci_spear_hc_driver = {
.start_port_reset = ohci_start_port_reset,
};
+static u64 spear_ohci_dma_mask = DMA_BIT_MASK(32);
+
static int spear_ohci_hcd_drv_probe(struct platform_device *pdev)
{
const struct hc_driver *driver = &ohci_spear_hc_driver;
@@ -98,11 +101,8 @@ static int spear_ohci_hcd_drv_probe(struct platform_device *pdev)
struct spear_ohci *ohci_p;
struct resource *res;
int retval, irq;
- int *pdata = pdev->dev.platform_data;
char clk_name[20] = "usbh_clk";
-
- if (pdata == NULL)
- return -EFAULT;
+ static int instance = -1;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
@@ -110,8 +110,22 @@ static int spear_ohci_hcd_drv_probe(struct platform_device *pdev)
goto fail_irq_get;
}
- if (*pdata >= 0)
- sprintf(clk_name, "usbh.%01d_clk", *pdata);
+ /*
+ * Right now device-tree probed devices don't get dma_mask set.
+ * Since shared usb code relies on it, set it here for now.
+ * Once we have dma capability bindings this can go away.
+ */
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &spear_ohci_dma_mask;
+
+ /*
+ * Increment the device instance, when probing via device-tree
+ */
+ if (pdev->id < 0)
+ instance++;
+ else
+ instance = pdev->id;
+ sprintf(clk_name, "usbh.%01d_clk", instance);
usbh_clk = clk_get(NULL, clk_name);
if (IS_ERR(usbh_clk)) {
@@ -222,6 +236,11 @@ static int spear_ohci_hcd_drv_resume(struct platform_device *dev)
}
#endif
+static struct of_device_id spear_ohci_id_table[] __devinitdata = {
+ { .compatible = "st,spear600-ohci", },
+ { },
+};
+
/* Driver definition to register with the platform bus */
static struct platform_driver spear_ohci_hcd_driver = {
.probe = spear_ohci_hcd_drv_probe,
@@ -233,6 +252,7 @@ static struct platform_driver spear_ohci_hcd_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "spear-ohci",
+ .of_match_table = of_match_ptr(spear_ohci_id_table),
},
};
diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c
deleted file mode 100644
index 5ba18595d6f7..000000000000
--- a/drivers/usb/host/ohci-ssb.c
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Sonics Silicon Backplane
- * Broadcom USB-core OHCI driver
- *
- * Copyright 2007 Michael Buesch <m@bues.ch>
- *
- * Derived from the OHCI-PCI driver
- * Copyright 1999 Roman Weissgaerber
- * Copyright 2000-2002 David Brownell
- * Copyright 1999 Linus Torvalds
- * Copyright 1999 Gregory P. Smith
- *
- * Derived from the USBcore related parts of Broadcom-SB
- * Copyright 2005 Broadcom Corporation
- *
- * Licensed under the GNU/GPL. See COPYING for details.
- */
-#include <linux/ssb/ssb.h>
-
-
-#define SSB_OHCI_TMSLOW_HOSTMODE (1 << 29)
-
-struct ssb_ohci_device {
- struct ohci_hcd ohci; /* _must_ be at the beginning. */
-
- u32 enable_flags;
-};
-
-static inline
-struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd)
-{
- return (struct ssb_ohci_device *)(hcd->hcd_priv);
-}
-
-
-static int ssb_ohci_reset(struct usb_hcd *hcd)
-{
- struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
- struct ohci_hcd *ohci = &ohcidev->ohci;
- int err;
-
- ohci_hcd_init(ohci);
- err = ohci_init(ohci);
-
- return err;
-}
-
-static int ssb_ohci_start(struct usb_hcd *hcd)
-{
- struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
- struct ohci_hcd *ohci = &ohcidev->ohci;
- int err;
-
- err = ohci_run(ohci);
- if (err < 0) {
- ohci_err(ohci, "can't start\n");
- ohci_stop(hcd);
- }
-
- return err;
-}
-
-static const struct hc_driver ssb_ohci_hc_driver = {
- .description = "ssb-usb-ohci",
- .product_desc = "SSB OHCI Controller",
- .hcd_priv_size = sizeof(struct ssb_ohci_device),
-
- .irq = ohci_irq,
- .flags = HCD_MEMORY | HCD_USB11,
-
- .reset = ssb_ohci_reset,
- .start = ssb_ohci_start,
- .stop = ohci_stop,
- .shutdown = ohci_shutdown,
-
- .urb_enqueue = ohci_urb_enqueue,
- .urb_dequeue = ohci_urb_dequeue,
- .endpoint_disable = ohci_endpoint_disable,
-
- .get_frame_number = ohci_get_frame,
-
- .hub_status_data = ohci_hub_status_data,
- .hub_control = ohci_hub_control,
-#ifdef CONFIG_PM
- .bus_suspend = ohci_bus_suspend,
- .bus_resume = ohci_bus_resume,
-#endif
-
- .start_port_reset = ohci_start_port_reset,
-};
-
-static void ssb_ohci_detach(struct ssb_device *dev)
-{
- struct usb_hcd *hcd = ssb_get_drvdata(dev);
-
- if (hcd->driver->shutdown)
- hcd->driver->shutdown(hcd);
- usb_remove_hcd(hcd);
- iounmap(hcd->regs);
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
- usb_put_hcd(hcd);
- ssb_device_disable(dev, 0);
-}
-
-static int ssb_ohci_attach(struct ssb_device *dev)
-{
- struct ssb_ohci_device *ohcidev;
- struct usb_hcd *hcd;
- int err = -ENOMEM;
- u32 tmp, flags = 0;
-
- if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) ||
- dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32)))
- return -EOPNOTSUPP;
-
- if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) {
- /* Put the device into host-mode. */
- flags |= SSB_OHCI_TMSLOW_HOSTMODE;
- ssb_device_enable(dev, flags);
- } else if (dev->id.coreid == SSB_DEV_USB20_HOST) {
- /*
- * USB 2.0 special considerations:
- *
- * In addition to the standard SSB reset sequence, the Host
- * Control Register must be programmed to bring the USB core
- * and various phy components out of reset.
- */
- ssb_device_enable(dev, 0);
- ssb_write32(dev, 0x200, 0x7ff);
-
- /* Change Flush control reg */
- tmp = ssb_read32(dev, 0x400);
- tmp &= ~8;
- ssb_write32(dev, 0x400, tmp);
- tmp = ssb_read32(dev, 0x400);
-
- /* Change Shim control reg */
- tmp = ssb_read32(dev, 0x304);
- tmp &= ~0x100;
- ssb_write32(dev, 0x304, tmp);
- tmp = ssb_read32(dev, 0x304);
-
- udelay(1);
-
- /* Work around for 5354 failures */
- if (dev->id.revision == 2 && dev->bus->chip_id == 0x5354) {
- /* Change syn01 reg */
- tmp = 0x00fe00fe;
- ssb_write32(dev, 0x894, tmp);
-
- /* Change syn03 reg */
- tmp = ssb_read32(dev, 0x89c);
- tmp |= 0x1;
- ssb_write32(dev, 0x89c, tmp);
- }
- } else
- ssb_device_enable(dev, 0);
-
- hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
- dev_name(dev->dev));
- if (!hcd)
- goto err_dev_disable;
- ohcidev = hcd_to_ssb_ohci(hcd);
- ohcidev->enable_flags = flags;
-
- tmp = ssb_read32(dev, SSB_ADMATCH0);
- hcd->rsrc_start = ssb_admatch_base(tmp);
- hcd->rsrc_len = ssb_admatch_size(tmp);
- hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
- if (!hcd->regs)
- goto err_put_hcd;
- err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED);
- if (err)
- goto err_iounmap;
-
- ssb_set_drvdata(dev, hcd);
-
- return err;
-
-err_iounmap:
- iounmap(hcd->regs);
-err_put_hcd:
- usb_put_hcd(hcd);
-err_dev_disable:
- ssb_device_disable(dev, flags);
- return err;
-}
-
-static int ssb_ohci_probe(struct ssb_device *dev,
- const struct ssb_device_id *id)
-{
- int err;
- u16 chipid_top;
-
- /* USBcores are only connected on embedded devices. */
- chipid_top = (dev->bus->chip_id & 0xFF00);
- if (chipid_top != 0x4700 && chipid_top != 0x5300)
- return -ENODEV;
-
- /* TODO: Probably need checks here; is the core connected? */
-
- if (usb_disabled())
- return -ENODEV;
-
- /* We currently always attach SSB_DEV_USB11_HOSTDEV
- * as HOST OHCI. If we want to attach it as Client device,
- * we must branch here and call into the (yet to
- * be written) Client mode driver. Same for remove(). */
-
- err = ssb_ohci_attach(dev);
-
- return err;
-}
-
-static void ssb_ohci_remove(struct ssb_device *dev)
-{
- ssb_ohci_detach(dev);
-}
-
-#ifdef CONFIG_PM
-
-static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state)
-{
- ssb_device_disable(dev, 0);
-
- return 0;
-}
-
-static int ssb_ohci_resume(struct ssb_device *dev)
-{
- struct usb_hcd *hcd = ssb_get_drvdata(dev);
- struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
-
- ssb_device_enable(dev, ohcidev->enable_flags);
-
- ohci_finish_controller_resume(hcd);
- return 0;
-}
-
-#else /* !CONFIG_PM */
-#define ssb_ohci_suspend NULL
-#define ssb_ohci_resume NULL
-#endif /* CONFIG_PM */
-
-static const struct ssb_device_id ssb_ohci_table[] = {
- SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
- SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
- SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
- SSB_DEVTABLE_END
-};
-MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
-
-static struct ssb_driver ssb_ohci_driver = {
- .name = KBUILD_MODNAME,
- .id_table = ssb_ohci_table,
- .probe = ssb_ohci_probe,
- .remove = ssb_ohci_remove,
- .suspend = ssb_ohci_suspend,
- .resume = ssb_ohci_resume,
-};
diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c
index 120bfe6ede38..60c2b0722f2e 100644
--- a/drivers/usb/host/ohci-tmio.c
+++ b/drivers/usb/host/ohci-tmio.c
@@ -140,7 +140,8 @@ static int ohci_tmio_start(struct usb_hcd *hcd)
return ret;
if ((ret = ohci_run(ohci)) < 0) {
- err("can't start %s", hcd->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s\n",
+ hcd->self.bus_name);
ohci_stop(hcd);
return ret;
}
diff --git a/drivers/usb/host/ohci-xls.c b/drivers/usb/host/ohci-xls.c
index a2247867af86..41e378f17c66 100644
--- a/drivers/usb/host/ohci-xls.c
+++ b/drivers/usb/host/ohci-xls.c
@@ -88,7 +88,8 @@ static int __devinit ohci_xls_start(struct usb_hcd *hcd)
ohci = hcd_to_ohci(hcd);
ret = ohci_run(ohci);
if (ret < 0) {
- err("can't start %s", hcd->self.bus_name);
+ dev_err(hcd->self.controller, "can't start %s\n",
+ hcd->self.bus_name);
ohci_stop(hcd);
return ret;
}
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
index 3b38030b02a8..4f0f0339532f 100644
--- a/drivers/usb/host/oxu210hp-hcd.c
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -1399,8 +1399,8 @@ static struct ehci_qh *qh_make(struct oxu_hcd *oxu,
* But interval 1 scheduling is simpler, and
* includes high bandwidth.
*/
- dbg("intr period %d uframes, NYET!",
- urb->interval);
+ oxu_dbg(oxu, "intr period %d uframes, NYET!\n",
+ urb->interval);
goto done;
}
} else {
@@ -1471,7 +1471,7 @@ static struct ehci_qh *qh_make(struct oxu_hcd *oxu,
}
break;
default:
- dbg("bogus dev %p speed %d", urb->dev, urb->dev->speed);
+ oxu_dbg(oxu, "bogus dev %p speed %d\n", urb->dev, urb->dev->speed);
done:
qh_put(qh);
return NULL;
@@ -2307,7 +2307,7 @@ restart:
qh_put(temp.qh);
break;
default:
- dbg("corrupt type %d frame %d shadow %p",
+ oxu_dbg(oxu, "corrupt type %d frame %d shadow %p\n",
type, frame, q.ptr);
q.ptr = NULL;
}
@@ -2991,8 +2991,9 @@ static int oxu_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
/* shouldn't happen often, but ...
* FIXME kill those tds' urbs
*/
- err("can't reschedule qh %p, err %d",
- qh, status);
+ dev_err(hcd->self.controller,
+ "can't reschedule qh %p, err %d\n", qh,
+ status);
}
return status;
}
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 32dada8c8b4f..df0828cb2aa3 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -9,6 +9,7 @@
*/
#include <linux/types.h>
+#include <linux/kconfig.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/init.h>
@@ -712,12 +713,28 @@ static int handshake(void __iomem *ptr, u32 mask, u32 done,
return -ETIMEDOUT;
}
-bool usb_is_intel_switchable_xhci(struct pci_dev *pdev)
+#define PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI 0x8C31
+
+bool usb_is_intel_ppt_switchable_xhci(struct pci_dev *pdev)
{
return pdev->class == PCI_CLASS_SERIAL_USB_XHCI &&
pdev->vendor == PCI_VENDOR_ID_INTEL &&
pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI;
}
+
+/* The Intel Lynx Point chipset also has switchable ports. */
+bool usb_is_intel_lpt_switchable_xhci(struct pci_dev *pdev)
+{
+ return pdev->class == PCI_CLASS_SERIAL_USB_XHCI &&
+ pdev->vendor == PCI_VENDOR_ID_INTEL &&
+ pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI;
+}
+
+bool usb_is_intel_switchable_xhci(struct pci_dev *pdev)
+{
+ return usb_is_intel_ppt_switchable_xhci(pdev) ||
+ usb_is_intel_lpt_switchable_xhci(pdev);
+}
EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci);
/*
@@ -742,6 +759,19 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
{
u32 ports_available;
+ /* Don't switchover the ports if the user hasn't compiled the xHCI
+ * driver. Otherwise they will see "dead" USB ports that don't power
+ * the devices.
+ */
+ if (!IS_ENABLED(CONFIG_USB_XHCI_HCD)) {
+ dev_warn(&xhci_pdev->dev,
+ "CONFIG_USB_XHCI_HCD is turned off, "
+ "defaulting to EHCI.\n");
+ dev_warn(&xhci_pdev->dev,
+ "USB 3.0 devices will work at USB 2.0 speeds.\n");
+ return;
+ }
+
ports_available = 0xffffffff;
/* Write USB3_PSSEN, the USB 3.0 Port SuperSpeed Enable
* Register, to turn on SuperSpeed terminations for all
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 2bf1320dc9c3..c868be65e763 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -401,7 +401,7 @@ static u8 alloc_usb_address(struct r8a66597 *r8a66597, struct urb *urb)
if (r8a66597->address_map & (1 << addr))
continue;
- dbg("alloc_address: r8a66597_addr=%d", addr);
+ dev_dbg(&urb->dev->dev, "alloc_address: r8a66597_addr=%d\n", addr);
r8a66597->address_map |= 1 << addr;
if (make_r8a66597_device(r8a66597, urb, addr) < 0)
@@ -426,7 +426,7 @@ static void free_usb_address(struct r8a66597 *r8a66597,
if (!dev)
return;
- dbg("free_addr: addr=%d", dev->address);
+ dev_dbg(&dev->udev->dev, "free_addr: addr=%d\n", dev->address);
dev->state = USB_STATE_DEFAULT;
r8a66597->address_map &= ~(1 << dev->address);
@@ -819,7 +819,7 @@ static void enable_r8a66597_pipe(struct r8a66597 *r8a66597, struct urb *urb,
struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb);
struct r8a66597_pipe *pipe = hep->hcpriv;
- dbg("enable_pipe:");
+ dev_dbg(&dev->udev->dev, "enable_pipe:\n");
pipe->info = *info;
set_pipe_reg_addr(pipe, R8A66597_PIPE_NO_DMA);
@@ -898,7 +898,7 @@ static void disable_r8a66597_pipe_all(struct r8a66597 *r8a66597,
force_dequeue(r8a66597, pipenum, dev->address);
}
- dbg("disable_pipe");
+ dev_dbg(&dev->udev->dev, "disable_pipe\n");
r8a66597->dma_map &= ~(dev->dma_map);
dev->dma_map = 0;
@@ -2264,7 +2264,7 @@ static int r8a66597_bus_suspend(struct usb_hcd *hcd)
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
int port;
- dbg("%s", __func__);
+ dev_dbg(&r8a66597->device0.udev->dev, "%s\n", __func__);
for (port = 0; port < r8a66597->max_root_hub; port++) {
struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
@@ -2273,7 +2273,7 @@ static int r8a66597_bus_suspend(struct usb_hcd *hcd)
if (!(rh->port & USB_PORT_STAT_ENABLE))
continue;
- dbg("suspend port = %d", port);
+ dev_dbg(&rh->dev->udev->dev, "suspend port = %d\n", port);
r8a66597_bclr(r8a66597, UACT, dvstctr_reg); /* suspend */
rh->port |= USB_PORT_STAT_SUSPEND;
@@ -2295,7 +2295,7 @@ static int r8a66597_bus_resume(struct usb_hcd *hcd)
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
int port;
- dbg("%s", __func__);
+ dev_dbg(&r8a66597->device0.udev->dev, "%s\n", __func__);
for (port = 0; port < r8a66597->max_root_hub; port++) {
struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
@@ -2304,7 +2304,7 @@ static int r8a66597_bus_resume(struct usb_hcd *hcd)
if (!(rh->port & USB_PORT_STAT_SUSPEND))
continue;
- dbg("resume port = %d", port);
+ dev_dbg(&rh->dev->udev->dev, "resume port = %d\n", port);
rh->port &= ~USB_PORT_STAT_SUSPEND;
rh->port |= USB_PORT_STAT_C_SUSPEND << 16;
r8a66597_mdfy(r8a66597, RESUME, RESUME | UACT, dvstctr_reg);
@@ -2360,7 +2360,7 @@ static int r8a66597_suspend(struct device *dev)
struct r8a66597 *r8a66597 = dev_get_drvdata(dev);
int port;
- dbg("%s", __func__);
+ dev_dbg(dev, "%s\n", __func__);
disable_controller(r8a66597);
@@ -2378,7 +2378,7 @@ static int r8a66597_resume(struct device *dev)
struct r8a66597 *r8a66597 = dev_get_drvdata(dev);
struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
- dbg("%s", __func__);
+ dev_dbg(dev, "%s\n", __func__);
enable_controller(r8a66597);
usb_root_hub_lost_power(hcd->self.root_hub);
diff --git a/drivers/usb/host/ssb-hcd.c b/drivers/usb/host/ssb-hcd.c
new file mode 100644
index 000000000000..c2a29faba076
--- /dev/null
+++ b/drivers/usb/host/ssb-hcd.c
@@ -0,0 +1,280 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom USB-core driver (SSB bus glue)
+ *
+ * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Based on ssb-ohci driver
+ * Copyright 2007 Michael Buesch <m@bues.ch>
+ *
+ * Derived from the OHCI-PCI driver
+ * Copyright 1999 Roman Weissgaerber
+ * Copyright 2000-2002 David Brownell
+ * Copyright 1999 Linus Torvalds
+ * Copyright 1999 Gregory P. Smith
+ *
+ * Derived from the USBcore related parts of Broadcom-SB
+ * Copyright 2005-2011 Broadcom Corporation
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+#include <linux/ssb/ssb.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb/ehci_pdriver.h>
+#include <linux/usb/ohci_pdriver.h>
+
+MODULE_AUTHOR("Hauke Mehrtens");
+MODULE_DESCRIPTION("Common USB driver for SSB Bus");
+MODULE_LICENSE("GPL");
+
+#define SSB_HCD_TMSLOW_HOSTMODE (1 << 29)
+
+struct ssb_hcd_device {
+ struct platform_device *ehci_dev;
+ struct platform_device *ohci_dev;
+
+ u32 enable_flags;
+};
+
+static void __devinit ssb_hcd_5354wa(struct ssb_device *dev)
+{
+#ifdef CONFIG_SSB_DRIVER_MIPS
+ /* Work around for 5354 failures */
+ if (dev->id.revision == 2 && dev->bus->chip_id == 0x5354) {
+ /* Change syn01 reg */
+ ssb_write32(dev, 0x894, 0x00fe00fe);
+
+ /* Change syn03 reg */
+ ssb_write32(dev, 0x89c, ssb_read32(dev, 0x89c) | 0x1);
+ }
+#endif
+}
+
+static void __devinit ssb_hcd_usb20wa(struct ssb_device *dev)
+{
+ if (dev->id.coreid == SSB_DEV_USB20_HOST) {
+ /*
+ * USB 2.0 special considerations:
+ *
+ * In addition to the standard SSB reset sequence, the Host
+ * Control Register must be programmed to bring the USB core
+ * and various phy components out of reset.
+ */
+ ssb_write32(dev, 0x200, 0x7ff);
+
+ /* Change Flush control reg */
+ ssb_write32(dev, 0x400, ssb_read32(dev, 0x400) & ~8);
+ ssb_read32(dev, 0x400);
+
+ /* Change Shim control reg */
+ ssb_write32(dev, 0x304, ssb_read32(dev, 0x304) & ~0x100);
+ ssb_read32(dev, 0x304);
+
+ udelay(1);
+
+ ssb_hcd_5354wa(dev);
+ }
+}
+
+/* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */
+static u32 __devinit ssb_hcd_init_chip(struct ssb_device *dev)
+{
+ u32 flags = 0;
+
+ if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
+ /* Put the device into host-mode. */
+ flags |= SSB_HCD_TMSLOW_HOSTMODE;
+
+ ssb_device_enable(dev, flags);
+
+ ssb_hcd_usb20wa(dev);
+
+ return flags;
+}
+
+static const struct usb_ehci_pdata ehci_pdata = {
+};
+
+static const struct usb_ohci_pdata ohci_pdata = {
+};
+
+static struct platform_device * __devinit
+ssb_hcd_create_pdev(struct ssb_device *dev, bool ohci, u32 addr, u32 len)
+{
+ struct platform_device *hci_dev;
+ struct resource hci_res[2];
+ int ret = -ENOMEM;
+
+ memset(hci_res, 0, sizeof(hci_res));
+
+ hci_res[0].start = addr;
+ hci_res[0].end = hci_res[0].start + len - 1;
+ hci_res[0].flags = IORESOURCE_MEM;
+
+ hci_res[1].start = dev->irq;
+ hci_res[1].flags = IORESOURCE_IRQ;
+
+ hci_dev = platform_device_alloc(ohci ? "ohci-platform" :
+ "ehci-platform" , 0);
+ if (!hci_dev)
+ return NULL;
+
+ hci_dev->dev.parent = dev->dev;
+ hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask;
+
+ ret = platform_device_add_resources(hci_dev, hci_res,
+ ARRAY_SIZE(hci_res));
+ if (ret)
+ goto err_alloc;
+ if (ohci)
+ ret = platform_device_add_data(hci_dev, &ohci_pdata,
+ sizeof(ohci_pdata));
+ else
+ ret = platform_device_add_data(hci_dev, &ehci_pdata,
+ sizeof(ehci_pdata));
+ if (ret)
+ goto err_alloc;
+ ret = platform_device_add(hci_dev);
+ if (ret)
+ goto err_alloc;
+
+ return hci_dev;
+
+err_alloc:
+ platform_device_put(hci_dev);
+ return ERR_PTR(ret);
+}
+
+static int __devinit ssb_hcd_probe(struct ssb_device *dev,
+ const struct ssb_device_id *id)
+{
+ int err, tmp;
+ int start, len;
+ u16 chipid_top;
+ u16 coreid = dev->id.coreid;
+ struct ssb_hcd_device *usb_dev;
+
+ /* USBcores are only connected on embedded devices. */
+ chipid_top = (dev->bus->chip_id & 0xFF00);
+ if (chipid_top != 0x4700 && chipid_top != 0x5300)
+ return -ENODEV;
+
+ /* TODO: Probably need checks here; is the core connected? */
+
+ if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) ||
+ dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32)))
+ return -EOPNOTSUPP;
+
+ usb_dev = kzalloc(sizeof(struct ssb_hcd_device), GFP_KERNEL);
+ if (!usb_dev)
+ return -ENOMEM;
+
+ /* We currently always attach SSB_DEV_USB11_HOSTDEV
+ * as HOST OHCI. If we want to attach it as Client device,
+ * we must branch here and call into the (yet to
+ * be written) Client mode driver. Same for remove(). */
+ usb_dev->enable_flags = ssb_hcd_init_chip(dev);
+
+ tmp = ssb_read32(dev, SSB_ADMATCH0);
+
+ start = ssb_admatch_base(tmp);
+ len = (coreid == SSB_DEV_USB20_HOST) ? 0x800 : ssb_admatch_size(tmp);
+ usb_dev->ohci_dev = ssb_hcd_create_pdev(dev, true, start, len);
+ if (IS_ERR(usb_dev->ohci_dev)) {
+ err = PTR_ERR(usb_dev->ohci_dev);
+ goto err_free_usb_dev;
+ }
+
+ if (coreid == SSB_DEV_USB20_HOST) {
+ start = ssb_admatch_base(tmp) + 0x800; /* ehci core offset */
+ usb_dev->ehci_dev = ssb_hcd_create_pdev(dev, false, start, len);
+ if (IS_ERR(usb_dev->ehci_dev)) {
+ err = PTR_ERR(usb_dev->ehci_dev);
+ goto err_unregister_ohci_dev;
+ }
+ }
+
+ ssb_set_drvdata(dev, usb_dev);
+ return 0;
+
+err_unregister_ohci_dev:
+ platform_device_unregister(usb_dev->ohci_dev);
+err_free_usb_dev:
+ kfree(usb_dev);
+ return err;
+}
+
+static void __devexit ssb_hcd_remove(struct ssb_device *dev)
+{
+ struct ssb_hcd_device *usb_dev = ssb_get_drvdata(dev);
+ struct platform_device *ohci_dev = usb_dev->ohci_dev;
+ struct platform_device *ehci_dev = usb_dev->ehci_dev;
+
+ if (ohci_dev)
+ platform_device_unregister(ohci_dev);
+ if (ehci_dev)
+ platform_device_unregister(ehci_dev);
+
+ ssb_device_disable(dev, 0);
+}
+
+static void __devexit ssb_hcd_shutdown(struct ssb_device *dev)
+{
+ ssb_device_disable(dev, 0);
+}
+
+#ifdef CONFIG_PM
+
+static int ssb_hcd_suspend(struct ssb_device *dev, pm_message_t state)
+{
+ ssb_device_disable(dev, 0);
+
+ return 0;
+}
+
+static int ssb_hcd_resume(struct ssb_device *dev)
+{
+ struct ssb_hcd_device *usb_dev = ssb_get_drvdata(dev);
+
+ ssb_device_enable(dev, usb_dev->enable_flags);
+
+ return 0;
+}
+
+#else /* !CONFIG_PM */
+#define ssb_hcd_suspend NULL
+#define ssb_hcd_resume NULL
+#endif /* CONFIG_PM */
+
+static const struct ssb_device_id ssb_hcd_table[] __devinitconst = {
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
+ SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
+ SSB_DEVTABLE_END
+};
+MODULE_DEVICE_TABLE(ssb, ssb_hcd_table);
+
+static struct ssb_driver ssb_hcd_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = ssb_hcd_table,
+ .probe = ssb_hcd_probe,
+ .remove = __devexit_p(ssb_hcd_remove),
+ .shutdown = ssb_hcd_shutdown,
+ .suspend = ssb_hcd_suspend,
+ .resume = ssb_hcd_resume,
+};
+
+static int __init ssb_hcd_init(void)
+{
+ return ssb_driver_register(&ssb_hcd_driver);
+}
+module_init(ssb_hcd_init);
+
+static void __exit ssb_hcd_exit(void)
+{
+ ssb_driver_unregister(&ssb_hcd_driver);
+}
+module_exit(ssb_hcd_exit);
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 673ad120c43e..2732ef660c5c 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -475,6 +475,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
struct xhci_bus_state *bus_state;
u16 link_state = 0;
u16 wake_mask = 0;
+ u16 timeout = 0;
max_ports = xhci_get_ports(hcd, &port_array);
bus_state = &xhci->bus_state[hcd_index(hcd)];
@@ -558,6 +559,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
xhci_dbg(xhci, "Resume USB2 port %d\n",
wIndex + 1);
bus_state->resume_done[wIndex] = 0;
+ clear_bit(wIndex, &bus_state->resuming_ports);
xhci_set_link_state(xhci, port_array, wIndex,
XDEV_U0);
xhci_dbg(xhci, "set port %d resume\n",
@@ -622,6 +624,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
link_state = (wIndex & 0xff00) >> 3;
if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK)
wake_mask = wIndex & 0xff00;
+ /* The MSB of wIndex is the U1/U2 timeout */
+ timeout = (wIndex & 0xff00) >> 8;
wIndex &= 0xff;
if (!wIndex || wIndex > max_ports)
goto error;
@@ -746,6 +750,22 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp = xhci_readl(xhci, port_array[wIndex]);
break;
+ case USB_PORT_FEAT_U1_TIMEOUT:
+ if (hcd->speed != HCD_USB3)
+ goto error;
+ temp = xhci_readl(xhci, port_array[wIndex] + 1);
+ temp &= ~PORT_U1_TIMEOUT_MASK;
+ temp |= PORT_U1_TIMEOUT(timeout);
+ xhci_writel(xhci, temp, port_array[wIndex] + 1);
+ break;
+ case USB_PORT_FEAT_U2_TIMEOUT:
+ if (hcd->speed != HCD_USB3)
+ goto error;
+ temp = xhci_readl(xhci, port_array[wIndex] + 1);
+ temp &= ~PORT_U2_TIMEOUT_MASK;
+ temp |= PORT_U2_TIMEOUT(timeout);
+ xhci_writel(xhci, temp, port_array[wIndex] + 1);
+ break;
default:
goto error;
}
@@ -845,7 +865,12 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
/* Initial status is no changes */
retval = (max_ports + 8) / 8;
memset(buf, 0, retval);
- status = 0;
+
+ /*
+ * Inform the usbcore about resume-in-progress by returning
+ * a non-zero value even if there are no status changes.
+ */
+ status = bus_state->resuming_ports;
mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC;
@@ -885,15 +910,11 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
spin_lock_irqsave(&xhci->lock, flags);
if (hcd->self.root_hub->do_remote_wakeup) {
- port_index = max_ports;
- while (port_index--) {
- if (bus_state->resume_done[port_index] != 0) {
- spin_unlock_irqrestore(&xhci->lock, flags);
- xhci_dbg(xhci, "suspend failed because "
- "port %d is resuming\n",
- port_index + 1);
- return -EBUSY;
- }
+ if (bus_state->resuming_ports) {
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ xhci_dbg(xhci, "suspend failed because "
+ "a port is resuming\n");
+ return -EBUSY;
}
}
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 68eaa908ac8e..ec4338eec826 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1791,6 +1791,14 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
{
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
struct dev_info *dev_info, *next;
+ struct list_head *tt_list_head;
+ struct list_head *tt;
+ struct list_head *endpoints;
+ struct list_head *ep, *q;
+ struct xhci_tt_bw_info *tt_info;
+ struct xhci_interval_bw_table *bwt;
+ struct xhci_virt_ep *virt_ep;
+
unsigned long flags;
int size;
int i;
@@ -1807,6 +1815,9 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
xhci->event_ring = NULL;
xhci_dbg(xhci, "Freed event ring\n");
+ if (xhci->lpm_command)
+ xhci_free_command(xhci, xhci->lpm_command);
+ xhci->cmd_ring_reserved_trbs = 0;
if (xhci->cmd_ring)
xhci_ring_free(xhci, xhci->cmd_ring);
xhci->cmd_ring = NULL;
@@ -1849,8 +1860,26 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
}
spin_unlock_irqrestore(&xhci->lock, flags);
+ bwt = &xhci->rh_bw->bw_table;
+ for (i = 0; i < XHCI_MAX_INTERVAL; i++) {
+ endpoints = &bwt->interval_bw[i].endpoints;
+ list_for_each_safe(ep, q, endpoints) {
+ virt_ep = list_entry(ep, struct xhci_virt_ep, bw_endpoint_list);
+ list_del(&virt_ep->bw_endpoint_list);
+ kfree(virt_ep);
+ }
+ }
+
+ tt_list_head = &xhci->rh_bw->tts;
+ list_for_each_safe(tt, q, tt_list_head) {
+ tt_info = list_entry(tt, struct xhci_tt_bw_info, tt_list);
+ list_del(tt);
+ kfree(tt_info);
+ }
+
xhci->num_usb2_ports = 0;
xhci->num_usb3_ports = 0;
+ xhci->num_active_eps = 0;
kfree(xhci->usb2_ports);
kfree(xhci->usb3_ports);
kfree(xhci->port_array);
@@ -2350,6 +2379,16 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
xhci_dbg_cmd_ptrs(xhci);
+ xhci->lpm_command = xhci_alloc_command(xhci, true, true, flags);
+ if (!xhci->lpm_command)
+ goto fail;
+
+ /* Reserve one command ring TRB for disabling LPM.
+ * Since the USB core grabs the shared usb_bus bandwidth mutex before
+ * disabling LPM, we only need to reserve one TRB for all devices.
+ */
+ xhci->cmd_ring_reserved_trbs++;
+
val = xhci_readl(xhci, &xhci->cap_regs->db_off);
val &= DBOFF_MASK;
xhci_dbg(xhci, "// Doorbell array is located at offset 0x%x"
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 7a856a767e77..18b231b0c5d3 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -72,6 +72,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
xhci_dbg(xhci, "QUIRK: Fresco Logic revision %u "
"has broken MSI implementation\n",
pdev->revision);
+ xhci->quirks |= XHCI_TRUST_TX_LENGTH;
}
if (pdev->vendor == PCI_VENDOR_ID_NEC)
@@ -83,6 +84,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
/* AMD PLL quirk */
if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info())
xhci->quirks |= XHCI_AMD_PLL_FIX;
+ if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
+ xhci->quirks |= XHCI_LPM_SUPPORT;
+ xhci->quirks |= XHCI_INTEL_HOST;
+ }
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) {
xhci->quirks |= XHCI_SPURIOUS_SUCCESS;
@@ -169,6 +174,13 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (retval)
goto put_usb3_hcd;
/* Roothub already marked as USB 3.0 speed */
+
+ /* We know the LPM timeout algorithms for this host, let the USB core
+ * enable and disable LPM for devices under the USB 3.0 roothub.
+ */
+ if (xhci->quirks & XHCI_LPM_SUPPORT)
+ hcd_to_bus(xhci->shared_hcd)->root_hub->lpm_capable = 1;
+
return 0;
put_usb3_hcd:
@@ -292,6 +304,8 @@ static const struct hc_driver xhci_pci_hc_driver = {
*/
.update_device = xhci_update_device,
.set_usb2_hw_lpm = xhci_set_usb2_hardware_lpm,
+ .enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout,
+ .disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout,
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 3d9422f16a20..23b4aefd1036 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1377,6 +1377,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
xhci_dbg(xhci, "resume HS port %d\n", port_id);
bus_state->resume_done[faked_port_index] = jiffies +
msecs_to_jiffies(20);
+ set_bit(faked_port_index, &bus_state->resuming_ports);
mod_timer(&hcd->rh_timer,
bus_state->resume_done[faked_port_index]);
/* Do the rest in GetPortStatus */
@@ -1786,8 +1787,12 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
/* handle completion code */
switch (trb_comp_code) {
case COMP_SUCCESS:
- frame->status = 0;
- break;
+ if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) {
+ frame->status = 0;
+ break;
+ }
+ if ((xhci->quirks & XHCI_TRUST_TX_LENGTH))
+ trb_comp_code = COMP_SHORT_TX;
case COMP_SHORT_TX:
frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ?
-EREMOTEIO : 0;
@@ -1803,6 +1808,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
break;
case COMP_DEV_ERR:
case COMP_STALL:
+ case COMP_TX_ERR:
frame->status = -EPROTO;
skip_td = true;
break;
@@ -1883,13 +1889,16 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
switch (trb_comp_code) {
case COMP_SUCCESS:
/* Double check that the HW transferred everything. */
- if (event_trb != td->last_trb) {
+ if (event_trb != td->last_trb ||
+ TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
xhci_warn(xhci, "WARN Successful completion "
"on short TX\n");
if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
*status = -EREMOTEIO;
else
*status = 0;
+ if ((xhci->quirks & XHCI_TRUST_TX_LENGTH))
+ trb_comp_code = COMP_SHORT_TX;
} else {
*status = 0;
}
@@ -2048,6 +2057,13 @@ static int handle_tx_event(struct xhci_hcd *xhci,
* transfer type
*/
case COMP_SUCCESS:
+ if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0)
+ break;
+ if (xhci->quirks & XHCI_TRUST_TX_LENGTH)
+ trb_comp_code = COMP_SHORT_TX;
+ else
+ xhci_warn(xhci, "WARN Successful completion on short TX: "
+ "needs XHCI_TRUST_TX_LENGTH quirk?\n");
case COMP_SHORT_TX:
break;
case COMP_STOP:
@@ -2270,7 +2286,7 @@ cleanup:
(status != 0 &&
!usb_endpoint_xfer_isoc(&urb->ep->desc)))
xhci_dbg(xhci, "Giveback URB %p, len = %d, "
- "expected = %x, status = %d\n",
+ "expected = %d, status = %d\n",
urb, urb->actual_length,
urb->transfer_buffer_length,
status);
@@ -3593,12 +3609,12 @@ int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
/* Queue an evaluate context command TRB */
int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
- u32 slot_id)
+ u32 slot_id, bool command_must_succeed)
{
return queue_command(xhci, lower_32_bits(in_ctx_ptr),
upper_32_bits(in_ctx_ptr), 0,
TRB_TYPE(TRB_EVAL_CONTEXT) | SLOT_ID_FOR_TRB(slot_id),
- false);
+ command_must_succeed);
}
/*
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 36641a7f2371..afdc73ee84a6 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -152,7 +152,7 @@ int xhci_reset(struct xhci_hcd *xhci)
{
u32 command;
u32 state;
- int ret;
+ int ret, i;
state = xhci_readl(xhci, &xhci->op_regs->status);
if ((state & STS_HALT) == 0) {
@@ -175,7 +175,15 @@ int xhci_reset(struct xhci_hcd *xhci)
* xHCI cannot write to any doorbells or operational registers other
* than status until the "Controller Not Ready" flag is cleared.
*/
- return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000);
+ ret = handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000);
+
+ for (i = 0; i < 2; ++i) {
+ xhci->bus_state[i].port_c_suspend = 0;
+ xhci->bus_state[i].suspended_ports = 0;
+ xhci->bus_state[i].resuming_ports = 0;
+ }
+
+ return ret;
}
#ifdef CONFIG_PCI
@@ -2438,7 +2446,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
udev->slot_id, must_succeed);
else
ret = xhci_queue_evaluate_context(xhci, in_ctx->dma,
- udev->slot_id);
+ udev->slot_id, must_succeed);
if (ret < 0) {
if (command)
list_del(&command->cmd_list);
@@ -3863,6 +3871,474 @@ int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
#endif /* CONFIG_USB_SUSPEND */
+/*---------------------- USB 3.0 Link PM functions ------------------------*/
+
+#ifdef CONFIG_PM
+/* Service interval in nanoseconds = 2^(bInterval - 1) * 125us * 1000ns / 1us */
+static unsigned long long xhci_service_interval_to_ns(
+ struct usb_endpoint_descriptor *desc)
+{
+ return (1 << (desc->bInterval - 1)) * 125 * 1000;
+}
+
+static u16 xhci_get_timeout_no_hub_lpm(struct usb_device *udev,
+ enum usb3_link_state state)
+{
+ unsigned long long sel;
+ unsigned long long pel;
+ unsigned int max_sel_pel;
+ char *state_name;
+
+ switch (state) {
+ case USB3_LPM_U1:
+ /* Convert SEL and PEL stored in nanoseconds to microseconds */
+ sel = DIV_ROUND_UP(udev->u1_params.sel, 1000);
+ pel = DIV_ROUND_UP(udev->u1_params.pel, 1000);
+ max_sel_pel = USB3_LPM_MAX_U1_SEL_PEL;
+ state_name = "U1";
+ break;
+ case USB3_LPM_U2:
+ sel = DIV_ROUND_UP(udev->u2_params.sel, 1000);
+ pel = DIV_ROUND_UP(udev->u2_params.pel, 1000);
+ max_sel_pel = USB3_LPM_MAX_U2_SEL_PEL;
+ state_name = "U2";
+ break;
+ default:
+ dev_warn(&udev->dev, "%s: Can't get timeout for non-U1 or U2 state.\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (sel <= max_sel_pel && pel <= max_sel_pel)
+ return USB3_LPM_DEVICE_INITIATED;
+
+ if (sel > max_sel_pel)
+ dev_dbg(&udev->dev, "Device-initiated %s disabled "
+ "due to long SEL %llu ms\n",
+ state_name, sel);
+ else
+ dev_dbg(&udev->dev, "Device-initiated %s disabled "
+ "due to long PEL %llu\n ms",
+ state_name, pel);
+ return USB3_LPM_DISABLED;
+}
+
+/* Returns the hub-encoded U1 timeout value.
+ * The U1 timeout should be the maximum of the following values:
+ * - For control endpoints, U1 system exit latency (SEL) * 3
+ * - For bulk endpoints, U1 SEL * 5
+ * - For interrupt endpoints:
+ * - Notification EPs, U1 SEL * 3
+ * - Periodic EPs, max(105% of bInterval, U1 SEL * 2)
+ * - For isochronous endpoints, max(105% of bInterval, U1 SEL * 2)
+ */
+static u16 xhci_calculate_intel_u1_timeout(struct usb_device *udev,
+ struct usb_endpoint_descriptor *desc)
+{
+ unsigned long long timeout_ns;
+ int ep_type;
+ int intr_type;
+
+ ep_type = usb_endpoint_type(desc);
+ switch (ep_type) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ timeout_ns = udev->u1_params.sel * 3;
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ timeout_ns = udev->u1_params.sel * 5;
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ intr_type = usb_endpoint_interrupt_type(desc);
+ if (intr_type == USB_ENDPOINT_INTR_NOTIFICATION) {
+ timeout_ns = udev->u1_params.sel * 3;
+ break;
+ }
+ /* Otherwise the calculation is the same as isoc eps */
+ case USB_ENDPOINT_XFER_ISOC:
+ timeout_ns = xhci_service_interval_to_ns(desc);
+ timeout_ns = DIV_ROUND_UP_ULL(timeout_ns * 105, 100);
+ if (timeout_ns < udev->u1_params.sel * 2)
+ timeout_ns = udev->u1_params.sel * 2;
+ break;
+ default:
+ return 0;
+ }
+
+ /* The U1 timeout is encoded in 1us intervals. */
+ timeout_ns = DIV_ROUND_UP_ULL(timeout_ns, 1000);
+ /* Don't return a timeout of zero, because that's USB3_LPM_DISABLED. */
+ if (timeout_ns == USB3_LPM_DISABLED)
+ timeout_ns++;
+
+ /* If the necessary timeout value is bigger than what we can set in the
+ * USB 3.0 hub, we have to disable hub-initiated U1.
+ */
+ if (timeout_ns <= USB3_LPM_U1_MAX_TIMEOUT)
+ return timeout_ns;
+ dev_dbg(&udev->dev, "Hub-initiated U1 disabled "
+ "due to long timeout %llu ms\n", timeout_ns);
+ return xhci_get_timeout_no_hub_lpm(udev, USB3_LPM_U1);
+}
+
+/* Returns the hub-encoded U2 timeout value.
+ * The U2 timeout should be the maximum of:
+ * - 10 ms (to avoid the bandwidth impact on the scheduler)
+ * - largest bInterval of any active periodic endpoint (to avoid going
+ * into lower power link states between intervals).
+ * - the U2 Exit Latency of the device
+ */
+static u16 xhci_calculate_intel_u2_timeout(struct usb_device *udev,
+ struct usb_endpoint_descriptor *desc)
+{
+ unsigned long long timeout_ns;
+ unsigned long long u2_del_ns;
+
+ timeout_ns = 10 * 1000 * 1000;
+
+ if ((usb_endpoint_xfer_int(desc) || usb_endpoint_xfer_isoc(desc)) &&
+ (xhci_service_interval_to_ns(desc) > timeout_ns))
+ timeout_ns = xhci_service_interval_to_ns(desc);
+
+ u2_del_ns = udev->bos->ss_cap->bU2DevExitLat * 1000;
+ if (u2_del_ns > timeout_ns)
+ timeout_ns = u2_del_ns;
+
+ /* The U2 timeout is encoded in 256us intervals */
+ timeout_ns = DIV_ROUND_UP_ULL(timeout_ns, 256 * 1000);
+ /* If the necessary timeout value is bigger than what we can set in the
+ * USB 3.0 hub, we have to disable hub-initiated U2.
+ */
+ if (timeout_ns <= USB3_LPM_U2_MAX_TIMEOUT)
+ return timeout_ns;
+ dev_dbg(&udev->dev, "Hub-initiated U2 disabled "
+ "due to long timeout %llu ms\n", timeout_ns);
+ return xhci_get_timeout_no_hub_lpm(udev, USB3_LPM_U2);
+}
+
+static u16 xhci_call_host_update_timeout_for_endpoint(struct xhci_hcd *xhci,
+ struct usb_device *udev,
+ struct usb_endpoint_descriptor *desc,
+ enum usb3_link_state state,
+ u16 *timeout)
+{
+ if (state == USB3_LPM_U1) {
+ if (xhci->quirks & XHCI_INTEL_HOST)
+ return xhci_calculate_intel_u1_timeout(udev, desc);
+ } else {
+ if (xhci->quirks & XHCI_INTEL_HOST)
+ return xhci_calculate_intel_u2_timeout(udev, desc);
+ }
+
+ return USB3_LPM_DISABLED;
+}
+
+static int xhci_update_timeout_for_endpoint(struct xhci_hcd *xhci,
+ struct usb_device *udev,
+ struct usb_endpoint_descriptor *desc,
+ enum usb3_link_state state,
+ u16 *timeout)
+{
+ u16 alt_timeout;
+
+ alt_timeout = xhci_call_host_update_timeout_for_endpoint(xhci, udev,
+ desc, state, timeout);
+
+ /* If we found we can't enable hub-initiated LPM, or
+ * the U1 or U2 exit latency was too high to allow
+ * device-initiated LPM as well, just stop searching.
+ */
+ if (alt_timeout == USB3_LPM_DISABLED ||
+ alt_timeout == USB3_LPM_DEVICE_INITIATED) {
+ *timeout = alt_timeout;
+ return -E2BIG;
+ }
+ if (alt_timeout > *timeout)
+ *timeout = alt_timeout;
+ return 0;
+}
+
+static int xhci_update_timeout_for_interface(struct xhci_hcd *xhci,
+ struct usb_device *udev,
+ struct usb_host_interface *alt,
+ enum usb3_link_state state,
+ u16 *timeout)
+{
+ int j;
+
+ for (j = 0; j < alt->desc.bNumEndpoints; j++) {
+ if (xhci_update_timeout_for_endpoint(xhci, udev,
+ &alt->endpoint[j].desc, state, timeout))
+ return -E2BIG;
+ continue;
+ }
+ return 0;
+}
+
+static int xhci_check_intel_tier_policy(struct usb_device *udev,
+ enum usb3_link_state state)
+{
+ struct usb_device *parent;
+ unsigned int num_hubs;
+
+ if (state == USB3_LPM_U2)
+ return 0;
+
+ /* Don't enable U1 if the device is on a 2nd tier hub or lower. */
+ for (parent = udev->parent, num_hubs = 0; parent->parent;
+ parent = parent->parent)
+ num_hubs++;
+
+ if (num_hubs < 2)
+ return 0;
+
+ dev_dbg(&udev->dev, "Disabling U1 link state for device"
+ " below second-tier hub.\n");
+ dev_dbg(&udev->dev, "Plug device into first-tier hub "
+ "to decrease power consumption.\n");
+ return -E2BIG;
+}
+
+static int xhci_check_tier_policy(struct xhci_hcd *xhci,
+ struct usb_device *udev,
+ enum usb3_link_state state)
+{
+ if (xhci->quirks & XHCI_INTEL_HOST)
+ return xhci_check_intel_tier_policy(udev, state);
+ return -EINVAL;
+}
+
+/* Returns the U1 or U2 timeout that should be enabled.
+ * If the tier check or timeout setting functions return with a non-zero exit
+ * code, that means the timeout value has been finalized and we shouldn't look
+ * at any more endpoints.
+ */
+static u16 xhci_calculate_lpm_timeout(struct usb_hcd *hcd,
+ struct usb_device *udev, enum usb3_link_state state)
+{
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct usb_host_config *config;
+ char *state_name;
+ int i;
+ u16 timeout = USB3_LPM_DISABLED;
+
+ if (state == USB3_LPM_U1)
+ state_name = "U1";
+ else if (state == USB3_LPM_U2)
+ state_name = "U2";
+ else {
+ dev_warn(&udev->dev, "Can't enable unknown link state %i\n",
+ state);
+ return timeout;
+ }
+
+ if (xhci_check_tier_policy(xhci, udev, state) < 0)
+ return timeout;
+
+ /* Gather some information about the currently installed configuration
+ * and alternate interface settings.
+ */
+ if (xhci_update_timeout_for_endpoint(xhci, udev, &udev->ep0.desc,
+ state, &timeout))
+ return timeout;
+
+ config = udev->actconfig;
+ if (!config)
+ return timeout;
+
+ for (i = 0; i < USB_MAXINTERFACES; i++) {
+ struct usb_driver *driver;
+ struct usb_interface *intf = config->interface[i];
+
+ if (!intf)
+ continue;
+
+ /* Check if any currently bound drivers want hub-initiated LPM
+ * disabled.
+ */
+ if (intf->dev.driver) {
+ driver = to_usb_driver(intf->dev.driver);
+ if (driver && driver->disable_hub_initiated_lpm) {
+ dev_dbg(&udev->dev, "Hub-initiated %s disabled "
+ "at request of driver %s\n",
+ state_name, driver->name);
+ return xhci_get_timeout_no_hub_lpm(udev, state);
+ }
+ }
+
+ /* Not sure how this could happen... */
+ if (!intf->cur_altsetting)
+ continue;
+
+ if (xhci_update_timeout_for_interface(xhci, udev,
+ intf->cur_altsetting,
+ state, &timeout))
+ return timeout;
+ }
+ return timeout;
+}
+
+/*
+ * Issue an Evaluate Context command to change the Maximum Exit Latency in the
+ * slot context. If that succeeds, store the new MEL in the xhci_virt_device.
+ */
+static int xhci_change_max_exit_latency(struct xhci_hcd *xhci,
+ struct usb_device *udev, u16 max_exit_latency)
+{
+ struct xhci_virt_device *virt_dev;
+ struct xhci_command *command;
+ struct xhci_input_control_ctx *ctrl_ctx;
+ struct xhci_slot_ctx *slot_ctx;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&xhci->lock, flags);
+ if (max_exit_latency == xhci->devs[udev->slot_id]->current_mel) {
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ return 0;
+ }
+
+ /* Attempt to issue an Evaluate Context command to change the MEL. */
+ virt_dev = xhci->devs[udev->slot_id];
+ command = xhci->lpm_command;
+ xhci_slot_copy(xhci, command->in_ctx, virt_dev->out_ctx);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+
+ ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx);
+ ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG);
+ slot_ctx = xhci_get_slot_ctx(xhci, command->in_ctx);
+ slot_ctx->dev_info2 &= cpu_to_le32(~((u32) MAX_EXIT));
+ slot_ctx->dev_info2 |= cpu_to_le32(max_exit_latency);
+
+ xhci_dbg(xhci, "Set up evaluate context for LPM MEL change.\n");
+ xhci_dbg(xhci, "Slot %u Input Context:\n", udev->slot_id);
+ xhci_dbg_ctx(xhci, command->in_ctx, 0);
+
+ /* Issue and wait for the evaluate context command. */
+ ret = xhci_configure_endpoint(xhci, udev, command,
+ true, true);
+ xhci_dbg(xhci, "Slot %u Output Context:\n", udev->slot_id);
+ xhci_dbg_ctx(xhci, virt_dev->out_ctx, 0);
+
+ if (!ret) {
+ spin_lock_irqsave(&xhci->lock, flags);
+ virt_dev->current_mel = max_exit_latency;
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ }
+ return ret;
+}
+
+static int calculate_max_exit_latency(struct usb_device *udev,
+ enum usb3_link_state state_changed,
+ u16 hub_encoded_timeout)
+{
+ unsigned long long u1_mel_us = 0;
+ unsigned long long u2_mel_us = 0;
+ unsigned long long mel_us = 0;
+ bool disabling_u1;
+ bool disabling_u2;
+ bool enabling_u1;
+ bool enabling_u2;
+
+ disabling_u1 = (state_changed == USB3_LPM_U1 &&
+ hub_encoded_timeout == USB3_LPM_DISABLED);
+ disabling_u2 = (state_changed == USB3_LPM_U2 &&
+ hub_encoded_timeout == USB3_LPM_DISABLED);
+
+ enabling_u1 = (state_changed == USB3_LPM_U1 &&
+ hub_encoded_timeout != USB3_LPM_DISABLED);
+ enabling_u2 = (state_changed == USB3_LPM_U2 &&
+ hub_encoded_timeout != USB3_LPM_DISABLED);
+
+ /* If U1 was already enabled and we're not disabling it,
+ * or we're going to enable U1, account for the U1 max exit latency.
+ */
+ if ((udev->u1_params.timeout != USB3_LPM_DISABLED && !disabling_u1) ||
+ enabling_u1)
+ u1_mel_us = DIV_ROUND_UP(udev->u1_params.mel, 1000);
+ if ((udev->u2_params.timeout != USB3_LPM_DISABLED && !disabling_u2) ||
+ enabling_u2)
+ u2_mel_us = DIV_ROUND_UP(udev->u2_params.mel, 1000);
+
+ if (u1_mel_us > u2_mel_us)
+ mel_us = u1_mel_us;
+ else
+ mel_us = u2_mel_us;
+ /* xHCI host controller max exit latency field is only 16 bits wide. */
+ if (mel_us > MAX_EXIT) {
+ dev_warn(&udev->dev, "Link PM max exit latency of %lluus "
+ "is too big.\n", mel_us);
+ return -E2BIG;
+ }
+ return mel_us;
+}
+
+/* Returns the USB3 hub-encoded value for the U1/U2 timeout. */
+int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
+ struct usb_device *udev, enum usb3_link_state state)
+{
+ struct xhci_hcd *xhci;
+ u16 hub_encoded_timeout;
+ int mel;
+ int ret;
+
+ xhci = hcd_to_xhci(hcd);
+ /* The LPM timeout values are pretty host-controller specific, so don't
+ * enable hub-initiated timeouts unless the vendor has provided
+ * information about their timeout algorithm.
+ */
+ if (!xhci || !(xhci->quirks & XHCI_LPM_SUPPORT) ||
+ !xhci->devs[udev->slot_id])
+ return USB3_LPM_DISABLED;
+
+ hub_encoded_timeout = xhci_calculate_lpm_timeout(hcd, udev, state);
+ mel = calculate_max_exit_latency(udev, state, hub_encoded_timeout);
+ if (mel < 0) {
+ /* Max Exit Latency is too big, disable LPM. */
+ hub_encoded_timeout = USB3_LPM_DISABLED;
+ mel = 0;
+ }
+
+ ret = xhci_change_max_exit_latency(xhci, udev, mel);
+ if (ret)
+ return ret;
+ return hub_encoded_timeout;
+}
+
+int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
+ struct usb_device *udev, enum usb3_link_state state)
+{
+ struct xhci_hcd *xhci;
+ u16 mel;
+ int ret;
+
+ xhci = hcd_to_xhci(hcd);
+ if (!xhci || !(xhci->quirks & XHCI_LPM_SUPPORT) ||
+ !xhci->devs[udev->slot_id])
+ return 0;
+
+ mel = calculate_max_exit_latency(udev, state, USB3_LPM_DISABLED);
+ ret = xhci_change_max_exit_latency(xhci, udev, mel);
+ if (ret)
+ return ret;
+ return 0;
+}
+#else /* CONFIG_PM */
+
+int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
+ struct usb_device *udev, enum usb3_link_state state)
+{
+ return USB3_LPM_DISABLED;
+}
+
+int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
+ struct usb_device *udev, enum usb3_link_state state)
+{
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+/*-------------------------------------------------------------------------*/
+
/* Once a hub descriptor is fetched for a device, we need to update the xHC's
* internal data structures for the device.
*/
@@ -4090,7 +4566,6 @@ static int __init xhci_hcd_init(void)
BUILD_BUG_ON(sizeof(struct xhci_intr_reg) != 8*32/8);
/* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */
BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8);
- BUILD_BUG_ON(sizeof(struct xhci_doorbell_array) != 256*32/8);
return 0;
unreg_pci:
xhci_unregister_pci();
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 3d69c4b2b542..de3d6e3e57be 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -362,8 +362,10 @@ struct xhci_op_regs {
* Timeout can be up to 127us. 0xFF means an infinite timeout.
*/
#define PORT_U1_TIMEOUT(p) ((p) & 0xff)
+#define PORT_U1_TIMEOUT_MASK 0xff
/* Inactivity timer value for transitions into U2 */
#define PORT_U2_TIMEOUT(p) (((p) & 0xff) << 8)
+#define PORT_U2_TIMEOUT_MASK (0xff << 8)
/* Bits 24:31 for port testing */
/* USB2 Protocol PORTSPMSC */
@@ -914,6 +916,8 @@ struct xhci_virt_device {
u8 real_port;
struct xhci_interval_bw_table *bw_table;
struct xhci_tt_bw_info *tt_info;
+ /* The current max exit latency for the enabled USB3 link states. */
+ u16 current_mel;
};
/*
@@ -1362,6 +1366,8 @@ struct xhci_bus_state {
u32 suspended_ports;
u32 port_remote_wakeup;
unsigned long resume_done[USB_MAXCHILDREN];
+ /* which ports have started to resume */
+ unsigned long resuming_ports;
};
static inline unsigned int hcd_index(struct usb_hcd *hcd)
@@ -1422,6 +1428,8 @@ struct xhci_hcd {
/* slot enabling and address device helpers */
struct completion addr_dev;
int slot_id;
+ /* For USB 3.0 LPM enable/disable. */
+ struct xhci_command *lpm_command;
/* Internal mirror of the HW's dcbaa */
struct xhci_virt_device *devs[MAX_HC_SLOTS];
/* For keeping track of bandwidth domains per roothub. */
@@ -1479,6 +1487,9 @@ struct xhci_hcd {
#define XHCI_RESET_ON_RESUME (1 << 7)
#define XHCI_SW_BW_CHECKING (1 << 8)
#define XHCI_AMD_0x96_HOST (1 << 9)
+#define XHCI_TRUST_TX_LENGTH (1 << 10)
+#define XHCI_LPM_SUPPORT (1 << 11)
+#define XHCI_INTEL_HOST (1 << 12)
unsigned int num_active_eps;
unsigned int limit_active_eps;
/* There are two roothubs to keep track of bus suspend info for */
@@ -1752,7 +1763,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
u32 slot_id, bool command_must_succeed);
int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
- u32 slot_id);
+ u32 slot_id, bool command_must_succeed);
int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id,
unsigned int ep_index);
int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id);
@@ -1776,6 +1787,10 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
/* xHCI roothub code */
void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
int port_id, u32 link_state);
+int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
+ struct usb_device *udev, enum usb3_link_state state);
+int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
+ struct usb_device *udev, enum usb3_link_state state);
void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
int port_id, u32 port_bit);
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index 575b56c79e97..7121b50098d3 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -284,18 +284,16 @@ static void mdc800_usb_irq (struct urb *urb)
int data_received=0, wake_up;
unsigned char* b=urb->transfer_buffer;
struct mdc800_data* mdc800=urb->context;
+ struct device *dev = &mdc800->dev->dev;
int status = urb->status;
if (status >= 0) {
-
- //dbg ("%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
-
if (mdc800_isBusy (b))
{
if (!mdc800->camera_busy)
{
mdc800->camera_busy=1;
- dbg ("gets busy");
+ dev_dbg(dev, "gets busy\n");
}
}
else
@@ -303,13 +301,13 @@ static void mdc800_usb_irq (struct urb *urb)
if (mdc800->camera_busy && mdc800_isReady (b))
{
mdc800->camera_busy=0;
- dbg ("gets ready");
+ dev_dbg(dev, "gets ready\n");
}
}
if (!(mdc800_isBusy (b) || mdc800_isReady (b)))
{
/* Store Data in camera_answer field */
- dbg ("%i %i %i %i %i %i %i %i ",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
+ dev_dbg(dev, "%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
memcpy (mdc800->camera_response,b,8);
data_received=1;
@@ -441,7 +439,7 @@ static int mdc800_usb_probe (struct usb_interface *intf,
int irq_interval=0;
int retval;
- dbg ("(mdc800_usb_probe) called.");
+ dev_dbg(&intf->dev, "(%s) called.\n", __func__);
if (mdc800->dev != NULL)
@@ -554,7 +552,7 @@ static void mdc800_usb_disconnect (struct usb_interface *intf)
{
struct mdc800_data* mdc800 = usb_get_intfdata(intf);
- dbg ("(mdc800_usb_disconnect) called");
+ dev_dbg(&intf->dev, "(%s) called\n", __func__);
if (mdc800) {
if (mdc800->state == NOT_CONNECTED)
@@ -656,7 +654,7 @@ static int mdc800_device_open (struct inode* inode, struct file *file)
}
mdc800->open=1;
- dbg ("Mustek MDC800 device opened.");
+ dev_dbg(&mdc800->dev->dev, "Mustek MDC800 device opened.\n");
error_out:
mutex_unlock(&mdc800->io_lock);
@@ -670,7 +668,6 @@ error_out:
static int mdc800_device_release (struct inode* inode, struct file *file)
{
int retval=0;
- dbg ("Mustek MDC800 device closed.");
mutex_lock(&mdc800->io_lock);
if (mdc800->open && (mdc800->state != NOT_CONNECTED))
@@ -927,7 +924,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
{
mdc800->pic_len=(int) 65536*(unsigned char) mdc800->camera_response[0]+256*(unsigned char) mdc800->camera_response[1]+(unsigned char) mdc800->camera_response[2];
- dbg ("cached imagesize = %i",mdc800->pic_len);
+ dev_dbg(&mdc800->dev->dev, "cached imagesize = %i\n", mdc800->pic_len);
}
}
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index ac0d75a9005a..0fc6e5fc745f 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -88,6 +88,7 @@ static struct workqueue_struct *wq;
static void appledisplay_complete(struct urb *urb)
{
struct appledisplay *pdata = urb->context;
+ struct device *dev = &pdata->udev->dev;
unsigned long flags;
int status = urb->status;
int retval;
@@ -97,18 +98,18 @@ static void appledisplay_complete(struct urb *urb)
/* success */
break;
case -EOVERFLOW:
- printk(KERN_ERR "appletouch: OVERFLOW with data "
- "length %d, actual length is %d\n",
+ dev_err(dev,
+ "OVERFLOW with data length %d, actual length is %d\n",
ACD_URB_BUFFER_LEN, pdata->urb->actual_length);
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* This urb is terminated, clean up */
- dbg("%s - urb shuttingdown with status: %d",
+ dev_dbg(dev, "%s - urb shuttingdown with status: %d\n",
__func__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d",
+ dev_dbg(dev, "%s - nonzero urb status received: %d/n",
__func__, status);
goto exit;
}
@@ -132,8 +133,7 @@ static void appledisplay_complete(struct urb *urb)
exit:
retval = usb_submit_urb(pdata->urb, GFP_ATOMIC);
if (retval) {
- dev_err(&pdata->udev->dev,
- "%s - usb_submit_urb failed with result %d\n",
+ dev_err(dev, "%s - usb_submit_urb failed with result %d\n",
__func__, retval);
}
}
diff --git a/drivers/usb/misc/emi26.c b/drivers/usb/misc/emi26.c
index da97dcec1f32..d65984dee751 100644
--- a/drivers/usb/misc/emi26.c
+++ b/drivers/usb/misc/emi26.c
@@ -78,18 +78,14 @@ static int emi26_load_firmware (struct usb_device *dev)
const struct firmware *bitstream_fw = NULL;
const struct firmware *firmware_fw = NULL;
const struct ihex_binrec *rec;
- int err;
+ int err = -ENOMEM;
int i;
__u32 addr; /* Address to write */
__u8 *buf;
buf = kmalloc(FW_LOAD_SIZE, GFP_KERNEL);
- if (!buf) {
- dev_err(&dev->dev, "%s - error loading firmware: error = %d\n",
- __func__, -ENOMEM);
- err = -ENOMEM;
+ if (!buf)
goto wraperr;
- }
err = request_ihex_firmware(&loader_fw, "emi26/loader.fw", &dev->dev);
if (err)
@@ -111,11 +107,8 @@ static int emi26_load_firmware (struct usb_device *dev)
/* Assert reset (stop the CPU in the EMI) */
err = emi26_set_reset(dev,1);
- if (err < 0) {
- dev_err(&dev->dev,"%s - error loading firmware: error = %d\n",
- __func__, err);
+ if (err < 0)
goto wraperr;
- }
rec = (const struct ihex_binrec *)loader_fw->data;
/* 1. We need to put the loader for the FPGA into the EZ-USB */
@@ -123,19 +116,15 @@ static int emi26_load_firmware (struct usb_device *dev)
err = emi26_writememory(dev, be32_to_cpu(rec->addr),
rec->data, be16_to_cpu(rec->len),
ANCHOR_LOAD_INTERNAL);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
rec = ihex_next_binrec(rec);
}
/* De-assert reset (let the CPU run) */
err = emi26_set_reset(dev,0);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
msleep(250); /* let device settle */
/* 2. We upload the FPGA firmware into the EMI
@@ -153,18 +142,14 @@ static int emi26_load_firmware (struct usb_device *dev)
rec = ihex_next_binrec(rec);
}
err = emi26_writememory(dev, addr, buf, i, ANCHOR_LOAD_FPGA);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
} while (rec);
/* Assert reset (stop the CPU in the EMI) */
err = emi26_set_reset(dev,1);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
/* 3. We need to put the loader for the firmware into the EZ-USB (again...) */
for (rec = (const struct ihex_binrec *)loader_fw->data;
@@ -172,19 +157,15 @@ static int emi26_load_firmware (struct usb_device *dev)
err = emi26_writememory(dev, be32_to_cpu(rec->addr),
rec->data, be16_to_cpu(rec->len),
ANCHOR_LOAD_INTERNAL);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
}
msleep(250); /* let device settle */
/* De-assert reset (let the CPU run) */
err = emi26_set_reset(dev,0);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
/* 4. We put the part of the firmware that lies in the external RAM into the EZ-USB */
@@ -194,19 +175,15 @@ static int emi26_load_firmware (struct usb_device *dev)
err = emi26_writememory(dev, be32_to_cpu(rec->addr),
rec->data, be16_to_cpu(rec->len),
ANCHOR_LOAD_EXTERNAL);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
}
}
-
+
/* Assert reset (stop the CPU in the EMI) */
err = emi26_set_reset(dev,1);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
for (rec = (const struct ihex_binrec *)firmware_fw->data;
rec; rec = ihex_next_binrec(rec)) {
@@ -214,19 +191,15 @@ static int emi26_load_firmware (struct usb_device *dev)
err = emi26_writememory(dev, be32_to_cpu(rec->addr),
rec->data, be16_to_cpu(rec->len),
ANCHOR_LOAD_INTERNAL);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
}
}
/* De-assert reset (let the CPU run) */
err = emi26_set_reset(dev,0);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
msleep(250); /* let device settle */
/* return 1 to fail the driver inialization
@@ -234,6 +207,10 @@ static int emi26_load_firmware (struct usb_device *dev)
err = 1;
wraperr:
+ if (err < 0)
+ dev_err(&dev->dev,"%s - error loading firmware: error = %d\n",
+ __func__, err);
+
release_firmware(loader_fw);
release_firmware(bitstream_fw);
release_firmware(firmware_fw);
diff --git a/drivers/usb/misc/emi62.c b/drivers/usb/misc/emi62.c
index 4e0f167a6c4e..ff08015b230c 100644
--- a/drivers/usb/misc/emi62.c
+++ b/drivers/usb/misc/emi62.c
@@ -56,7 +56,7 @@ static int emi62_writememory(struct usb_device *dev, int address,
unsigned char *buffer = kmemdup(data, length, GFP_KERNEL);
if (!buffer) {
- err("emi62: kmalloc(%d) failed.", length);
+ dev_err(&dev->dev, "kmalloc(%d) failed.\n", length);
return -ENOMEM;
}
/* Note: usb_control_msg returns negative value on error or length of the
@@ -73,9 +73,8 @@ static int emi62_set_reset (struct usb_device *dev, unsigned char reset_bit)
dev_info(&dev->dev, "%s - %d\n", __func__, reset_bit);
response = emi62_writememory (dev, CPUCS_REG, &reset_bit, 1, 0xa0);
- if (response < 0) {
- err("emi62: set_reset (%d) failed", reset_bit);
- }
+ if (response < 0)
+ dev_err(&dev->dev, "set_reset (%d) failed\n", reset_bit);
return response;
}
@@ -87,18 +86,15 @@ static int emi62_load_firmware (struct usb_device *dev)
const struct firmware *bitstream_fw = NULL;
const struct firmware *firmware_fw = NULL;
const struct ihex_binrec *rec;
- int err;
+ int err = -ENOMEM;
int i;
__u32 addr; /* Address to write */
__u8 *buf;
dev_dbg(&dev->dev, "load_firmware\n");
buf = kmalloc(FW_LOAD_SIZE, GFP_KERNEL);
- if (!buf) {
- err( "%s - error loading firmware: error = %d", __func__, -ENOMEM);
- err = -ENOMEM;
+ if (!buf)
goto wraperr;
- }
err = request_ihex_firmware(&loader_fw, "emi62/loader.fw", &dev->dev);
if (err)
@@ -112,16 +108,13 @@ static int emi62_load_firmware (struct usb_device *dev)
err = request_ihex_firmware(&firmware_fw, FIRMWARE_FW, &dev->dev);
if (err) {
nofw:
- err( "%s - request_firmware() failed", __func__);
goto wraperr;
}
/* Assert reset (stop the CPU in the EMI) */
err = emi62_set_reset(dev,1);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
rec = (const struct ihex_binrec *)loader_fw->data;
@@ -130,19 +123,15 @@ static int emi62_load_firmware (struct usb_device *dev)
err = emi62_writememory(dev, be32_to_cpu(rec->addr),
rec->data, be16_to_cpu(rec->len),
ANCHOR_LOAD_INTERNAL);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
rec = ihex_next_binrec(rec);
}
/* De-assert reset (let the CPU run) */
err = emi62_set_reset(dev,0);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
msleep(250); /* let device settle */
/* 2. We upload the FPGA firmware into the EMI
@@ -160,18 +149,14 @@ static int emi62_load_firmware (struct usb_device *dev)
rec = ihex_next_binrec(rec);
}
err = emi62_writememory(dev, addr, buf, i, ANCHOR_LOAD_FPGA);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
} while (rec);
/* Assert reset (stop the CPU in the EMI) */
err = emi62_set_reset(dev,1);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
/* 3. We need to put the loader for the firmware into the EZ-USB (again...) */
for (rec = (const struct ihex_binrec *)loader_fw->data;
@@ -179,18 +164,14 @@ static int emi62_load_firmware (struct usb_device *dev)
err = emi62_writememory(dev, be32_to_cpu(rec->addr),
rec->data, be16_to_cpu(rec->len),
ANCHOR_LOAD_INTERNAL);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
}
/* De-assert reset (let the CPU run) */
err = emi62_set_reset(dev,0);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
msleep(250); /* let device settle */
/* 4. We put the part of the firmware that lies in the external RAM into the EZ-USB */
@@ -201,19 +182,15 @@ static int emi62_load_firmware (struct usb_device *dev)
err = emi62_writememory(dev, be32_to_cpu(rec->addr),
rec->data, be16_to_cpu(rec->len),
ANCHOR_LOAD_EXTERNAL);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
}
}
/* Assert reset (stop the CPU in the EMI) */
err = emi62_set_reset(dev,1);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
for (rec = (const struct ihex_binrec *)firmware_fw->data;
rec; rec = ihex_next_binrec(rec)) {
@@ -221,19 +198,15 @@ static int emi62_load_firmware (struct usb_device *dev)
err = emi62_writememory(dev, be32_to_cpu(rec->addr),
rec->data, be16_to_cpu(rec->len),
ANCHOR_LOAD_EXTERNAL);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
}
}
/* De-assert reset (let the CPU run) */
err = emi62_set_reset(dev,0);
- if (err < 0) {
- err("%s - error loading firmware: error = %d", __func__, err);
+ if (err < 0)
goto wraperr;
- }
msleep(250); /* let device settle */
release_firmware(loader_fw);
@@ -247,6 +220,9 @@ static int emi62_load_firmware (struct usb_device *dev)
return 1;
wraperr:
+ if (err < 0)
+ dev_err(&dev->dev,"%s - error loading firmware: error = %d\n",
+ __func__, err);
release_firmware(loader_fw);
release_firmware(bitstream_fw);
release_firmware(firmware_fw);
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index 0dee24698504..ce978384fda1 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -200,7 +200,8 @@ reset:
return -EAGAIN;
/* should be IMGSIZE == 65040 */
- dbg("read %d bytes fingerprint data", bytes_read);
+ dev_dbg(&dev->interface->dev, "read %d bytes fingerprint data\n",
+ bytes_read);
return result;
}
@@ -366,14 +367,14 @@ static int idmouse_probe(struct usb_interface *interface,
kmalloc(IMGSIZE + dev->bulk_in_size, GFP_KERNEL);
if (!dev->bulk_in_buffer) {
- err("Unable to allocate input buffer.");
+ dev_err(&interface->dev, "Unable to allocate input buffer.\n");
idmouse_delete(dev);
return -ENOMEM;
}
}
if (!(dev->bulk_in_endpointAddr)) {
- err("Unable to find bulk-in endpoint.");
+ dev_err(&interface->dev, "Unable to find bulk-in endpoint.\n");
idmouse_delete(dev);
return -ENODEV;
}
@@ -385,7 +386,7 @@ static int idmouse_probe(struct usb_interface *interface,
result = usb_register_dev(interface, &idmouse_class);
if (result) {
/* something prevented us from registering this device */
- err("Unble to allocate minor number.");
+ dev_err(&interface->dev, "Unble to allocate minor number.\n");
usb_set_intfdata(interface, NULL);
idmouse_delete(dev);
return result;
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index 4fd0dc835ae5..db46143c67a6 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -610,8 +610,8 @@ static int iowarrior_open(struct inode *inode, struct file *file)
interface = usb_find_interface(&iowarrior_driver, subminor);
if (!interface) {
mutex_unlock(&iowarrior_mutex);
- err("%s - error, can't find device for minor %d", __func__,
- subminor);
+ printk(KERN_ERR "%s - error, can't find device for minor %d\n",
+ __func__, subminor);
return -ENODEV;
}
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index 5db4ab52061e..ac762299eaa8 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -334,8 +334,8 @@ static int ld_usb_open(struct inode *inode, struct file *file)
interface = usb_find_interface(&ld_usb_driver, subminor);
if (!interface) {
- err("%s - error, can't find device for minor %d\n",
- __func__, subminor);
+ printk(KERN_ERR "%s - error, can't find device for minor %d\n",
+ __func__, subminor);
return -ENODEV;
}
@@ -485,7 +485,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
/* verify that the device wasn't unplugged */
if (dev->intf == NULL) {
retval = -ENODEV;
- err("No device or device unplugged %d\n", retval);
+ printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval);
goto unlock_exit;
}
@@ -565,7 +565,7 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
/* verify that the device wasn't unplugged */
if (dev->intf == NULL) {
retval = -ENODEV;
- err("No device or device unplugged %d\n", retval);
+ printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval);
goto unlock_exit;
}
@@ -603,7 +603,9 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
bytes_to_write,
USB_CTRL_SET_TIMEOUT * HZ);
if (retval < 0)
- err("Couldn't submit HID_REQ_SET_REPORT %d\n", retval);
+ dev_err(&dev->intf->dev,
+ "Couldn't submit HID_REQ_SET_REPORT %d\n",
+ retval);
goto unlock_exit;
}
@@ -624,7 +626,8 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL);
if (retval) {
dev->interrupt_out_busy = 0;
- err("Couldn't submit interrupt_out_urb %d\n", retval);
+ dev_err(&dev->intf->dev,
+ "Couldn't submit interrupt_out_urb %d\n", retval);
goto unlock_exit;
}
retval = bytes_to_write;
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 575222042767..a2702cbfe804 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -354,8 +354,8 @@ static int tower_open (struct inode *inode, struct file *file)
interface = usb_find_interface (&tower_driver, subminor);
if (!interface) {
- err ("%s - error, can't find device for minor %d",
- __func__, subminor);
+ printk(KERN_ERR "%s - error, can't find device for minor %d\n",
+ __func__, subminor);
retval = -ENODEV;
goto exit;
}
@@ -397,7 +397,8 @@ static int tower_open (struct inode *inode, struct file *file)
sizeof(reset_reply),
1000);
if (result < 0) {
- err("LEGO USB Tower reset control request failed");
+ dev_err(&dev->udev->dev,
+ "LEGO USB Tower reset control request failed\n");
retval = result;
goto unlock_exit;
}
@@ -420,7 +421,8 @@ static int tower_open (struct inode *inode, struct file *file)
retval = usb_submit_urb (dev->interrupt_in_urb, GFP_KERNEL);
if (retval) {
- err("Couldn't submit interrupt_in_urb %d", retval);
+ dev_err(&dev->udev->dev,
+ "Couldn't submit interrupt_in_urb %d\n", retval);
dev->interrupt_in_running = 0;
dev->open_count = 0;
goto unlock_exit;
@@ -608,7 +610,7 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count,
/* verify that the device wasn't unplugged */
if (dev->udev == NULL) {
retval = -ENODEV;
- err("No device or device unplugged %d", retval);
+ printk(KERN_ERR "legousbtower: No device or device unplugged %d\n", retval);
goto unlock_exit;
}
@@ -697,7 +699,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
/* verify that the device wasn't unplugged */
if (dev->udev == NULL) {
retval = -ENODEV;
- err("No device or device unplugged %d", retval);
+ printk(KERN_ERR "legousbtower: No device or device unplugged %d\n", retval);
goto unlock_exit;
}
@@ -744,7 +746,8 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
retval = usb_submit_urb (dev->interrupt_out_urb, GFP_KERNEL);
if (retval) {
dev->interrupt_out_busy = 0;
- err("Couldn't submit interrupt_out_urb %d", retval);
+ dev_err(&dev->udev->dev,
+ "Couldn't submit interrupt_out_urb %d\n", retval);
goto unlock_exit;
}
retval = bytes_to_write;
@@ -803,9 +806,10 @@ resubmit:
/* resubmit if we're still running */
if (dev->interrupt_in_running && dev->udev) {
retval = usb_submit_urb (dev->interrupt_in_urb, GFP_ATOMIC);
- if (retval) {
- err("%s: usb_submit_urb failed (%d)", __func__, retval);
- }
+ if (retval)
+ dev_err(&dev->udev->dev,
+ "%s: usb_submit_urb failed (%d)\n",
+ __func__, retval);
}
exit:
@@ -852,6 +856,7 @@ static void tower_interrupt_out_callback (struct urb *urb)
*/
static int tower_probe (struct usb_interface *interface, const struct usb_device_id *id)
{
+ struct device *idev = &interface->dev;
struct usb_device *udev = interface_to_usbdev(interface);
struct lego_usb_tower *dev = NULL;
struct usb_host_interface *iface_desc;
@@ -871,7 +876,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
dev = kmalloc (sizeof(struct lego_usb_tower), GFP_KERNEL);
if (dev == NULL) {
- err ("Out of memory");
+ dev_err(idev, "Out of memory\n");
goto exit;
}
@@ -915,37 +920,37 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
}
}
if(dev->interrupt_in_endpoint == NULL) {
- err("interrupt in endpoint not found");
+ dev_err(idev, "interrupt in endpoint not found\n");
goto error;
}
if (dev->interrupt_out_endpoint == NULL) {
- err("interrupt out endpoint not found");
+ dev_err(idev, "interrupt out endpoint not found\n");
goto error;
}
dev->read_buffer = kmalloc (read_buffer_size, GFP_KERNEL);
if (!dev->read_buffer) {
- err("Couldn't allocate read_buffer");
+ dev_err(idev, "Couldn't allocate read_buffer\n");
goto error;
}
dev->interrupt_in_buffer = kmalloc (usb_endpoint_maxp(dev->interrupt_in_endpoint), GFP_KERNEL);
if (!dev->interrupt_in_buffer) {
- err("Couldn't allocate interrupt_in_buffer");
+ dev_err(idev, "Couldn't allocate interrupt_in_buffer\n");
goto error;
}
dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->interrupt_in_urb) {
- err("Couldn't allocate interrupt_in_urb");
+ dev_err(idev, "Couldn't allocate interrupt_in_urb\n");
goto error;
}
dev->interrupt_out_buffer = kmalloc (write_buffer_size, GFP_KERNEL);
if (!dev->interrupt_out_buffer) {
- err("Couldn't allocate interrupt_out_buffer");
+ dev_err(idev, "Couldn't allocate interrupt_out_buffer\n");
goto error;
}
dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->interrupt_out_urb) {
- err("Couldn't allocate interrupt_out_urb");
+ dev_err(idev, "Couldn't allocate interrupt_out_urb\n");
goto error;
}
dev->interrupt_in_interval = interrupt_in_interval ? interrupt_in_interval : dev->interrupt_in_endpoint->bInterval;
@@ -958,7 +963,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
if (retval) {
/* something prevented us from registering this driver */
- err ("Not able to get a minor for this device.");
+ dev_err(idev, "Not able to get a minor for this device.\n");
usb_set_intfdata (interface, NULL);
goto error;
}
@@ -980,7 +985,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
sizeof(get_version_reply),
1000);
if (result < 0) {
- err("LEGO USB Tower get version control request failed");
+ dev_err(idev, "LEGO USB Tower get version control request failed\n");
retval = result;
goto error;
}
diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
index 487a8ce0775e..1084124c4a44 100644
--- a/drivers/usb/misc/rio500.c
+++ b/drivers/usb/misc/rio500.c
@@ -153,10 +153,10 @@ static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg)
requesttype = rio_cmd.requesttype | USB_DIR_IN |
USB_TYPE_VENDOR | USB_RECIP_DEVICE;
- dbg
- ("sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x",
- requesttype, rio_cmd.request, rio_cmd.value,
- rio_cmd.index, rio_cmd.length);
+ dev_dbg(&rio->rio_dev->dev,
+ "sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n",
+ requesttype, rio_cmd.request, rio_cmd.value,
+ rio_cmd.index, rio_cmd.length);
/* Send rio control message */
retries = 3;
while (retries) {
@@ -171,11 +171,14 @@ static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg)
if (result == -ETIMEDOUT)
retries--;
else if (result < 0) {
- err("Error executing ioctrl. code = %d", result);
+ dev_err(&rio->rio_dev->dev,
+ "Error executing ioctrl. code = %d\n",
+ result);
retries = 0;
} else {
- dbg("Executed ioctl. Result = %d (data=%02x)",
- result, buffer[0]);
+ dev_dbg(&rio->rio_dev->dev,
+ "Executed ioctl. Result = %d (data=%02x)\n",
+ result, buffer[0]);
if (copy_to_user(rio_cmd.buffer, buffer,
rio_cmd.length)) {
free_page((unsigned long) buffer);
@@ -221,9 +224,10 @@ static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg)
requesttype = rio_cmd.requesttype | USB_DIR_OUT |
USB_TYPE_VENDOR | USB_RECIP_DEVICE;
- dbg("sending command: reqtype=%0x req=%0x value=%0x index=%0x len=%0x",
- requesttype, rio_cmd.request, rio_cmd.value,
- rio_cmd.index, rio_cmd.length);
+ dev_dbg(&rio->rio_dev->dev,
+ "sending command: reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n",
+ requesttype, rio_cmd.request, rio_cmd.value,
+ rio_cmd.index, rio_cmd.length);
/* Send rio control message */
retries = 3;
while (retries) {
@@ -238,10 +242,13 @@ static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg)
if (result == -ETIMEDOUT)
retries--;
else if (result < 0) {
- err("Error executing ioctrl. code = %d", result);
+ dev_err(&rio->rio_dev->dev,
+ "Error executing ioctrl. code = %d\n",
+ result);
retries = 0;
} else {
- dbg("Executed ioctl. Result = %d", result);
+ dev_dbg(&rio->rio_dev->dev,
+ "Executed ioctl. Result = %d\n", result);
retries = 0;
}
@@ -313,8 +320,9 @@ write_rio(struct file *file, const char __user *buffer,
usb_sndbulkpipe(rio->rio_dev, 2),
obuf, thistime, &partial, 5000);
- dbg("write stats: result:%d thistime:%lu partial:%u",
- result, thistime, partial);
+ dev_dbg(&rio->rio_dev->dev,
+ "write stats: result:%d thistime:%lu partial:%u\n",
+ result, thistime, partial);
if (result == -ETIMEDOUT) { /* NAK - so hold for a while */
if (!maxretry--) {
@@ -332,7 +340,8 @@ write_rio(struct file *file, const char __user *buffer,
break;
};
if (result) {
- err("Write Whoops - %x", result);
+ dev_err(&rio->rio_dev->dev, "Write Whoops - %x\n",
+ result);
errn = -EIO;
goto error;
}
@@ -393,15 +402,17 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
ibuf, this_read, &partial,
8000);
- dbg("read stats: result:%d this_read:%u partial:%u",
- result, this_read, partial);
+ dev_dbg(&rio->rio_dev->dev,
+ "read stats: result:%d this_read:%u partial:%u\n",
+ result, this_read, partial);
if (partial) {
count = this_read = partial;
} else if (result == -ETIMEDOUT || result == 15) { /* FIXME: 15 ??? */
if (!maxretry--) {
mutex_unlock(&(rio->lock));
- err("read_rio: maxretry timeout");
+ dev_err(&rio->rio_dev->dev,
+ "read_rio: maxretry timeout\n");
return -ETIME;
}
prepare_to_wait(&rio->wait_q, &wait, TASK_INTERRUPTIBLE);
@@ -410,8 +421,9 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
continue;
} else if (result != -EREMOTEIO) {
mutex_unlock(&(rio->lock));
- err("Read Whoops - result:%u partial:%u this_read:%u",
- result, partial, this_read);
+ dev_err(&rio->rio_dev->dev,
+ "Read Whoops - result:%u partial:%u this_read:%u\n",
+ result, partial, this_read);
return -EIO;
} else {
mutex_unlock(&(rio->lock));
@@ -459,26 +471,29 @@ static int probe_rio(struct usb_interface *intf,
retval = usb_register_dev(intf, &usb_rio_class);
if (retval) {
- err("Not able to get a minor for this device.");
+ dev_err(&dev->dev,
+ "Not able to get a minor for this device.\n");
return -ENOMEM;
}
rio->rio_dev = dev;
if (!(rio->obuf = kmalloc(OBUF_SIZE, GFP_KERNEL))) {
- err("probe_rio: Not enough memory for the output buffer");
+ dev_err(&dev->dev,
+ "probe_rio: Not enough memory for the output buffer\n");
usb_deregister_dev(intf, &usb_rio_class);
return -ENOMEM;
}
- dbg("probe_rio: obuf address:%p", rio->obuf);
+ dev_dbg(&intf->dev, "obuf address:%p\n", rio->obuf);
if (!(rio->ibuf = kmalloc(IBUF_SIZE, GFP_KERNEL))) {
- err("probe_rio: Not enough memory for the input buffer");
+ dev_err(&dev->dev,
+ "probe_rio: Not enough memory for the input buffer\n");
usb_deregister_dev(intf, &usb_rio_class);
kfree(rio->obuf);
return -ENOMEM;
}
- dbg("probe_rio: ibuf address:%p", rio->ibuf);
+ dev_dbg(&intf->dev, "ibuf address:%p\n", rio->ibuf);
mutex_init(&(rio->lock));
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index e2b4bd31c2b6..89927bcff974 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -87,8 +87,8 @@ static int lcd_open(struct inode *inode, struct file *file)
interface = usb_find_interface(&lcd_driver, subminor);
if (!interface) {
mutex_unlock(&lcd_mutex);
- err("USBLCD: %s - error, can't find device for minor %d",
- __func__, subminor);
+ printk(KERN_ERR "USBLCD: %s - error, can't find device for minor %d\n",
+ __func__, subminor);
return -ENODEV;
}
@@ -209,8 +209,8 @@ static void lcd_write_bulk_callback(struct urb *urb)
!(status == -ENOENT ||
status == -ECONNRESET ||
status == -ESHUTDOWN)) {
- dbg("USBLCD: %s - nonzero write bulk status received: %d",
- __func__, status);
+ dev_dbg(&dev->interface->dev,
+ "nonzero write bulk status received: %d\n", status);
}
/* free up our allocated buffer */
@@ -268,8 +268,9 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer,
/* send the data out the bulk port */
retval = usb_submit_urb(urb, GFP_KERNEL);
if (retval) {
- err("USBLCD: %s - failed submitting write urb, error %d",
- __func__, retval);
+ dev_err(&dev->udev->dev,
+ "%s - failed submitting write urb, error %d\n",
+ __func__, retval);
goto error_unanchor;
}
@@ -322,7 +323,7 @@ static int lcd_probe(struct usb_interface *interface,
/* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
- err("Out of memory");
+ dev_err(&interface->dev, "Out of memory\n");
goto error;
}
kref_init(&dev->kref);
@@ -352,7 +353,8 @@ static int lcd_probe(struct usb_interface *interface,
dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
if (!dev->bulk_in_buffer) {
- err("Could not allocate bulk_in_buffer");
+ dev_err(&interface->dev,
+ "Could not allocate bulk_in_buffer\n");
goto error;
}
}
@@ -364,7 +366,8 @@ static int lcd_probe(struct usb_interface *interface,
}
}
if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
- err("Could not find both bulk-in and bulk-out endpoints");
+ dev_err(&interface->dev,
+ "Could not find both bulk-in and bulk-out endpoints\n");
goto error;
}
@@ -375,7 +378,8 @@ static int lcd_probe(struct usb_interface *interface,
retval = usb_register_dev(interface, &lcd_class);
if (retval) {
/* something prevented us from registering this driver */
- err("Not able to get a minor for this device.");
+ dev_err(&interface->dev,
+ "Not able to get a minor for this device.\n");
usb_set_intfdata(interface, NULL);
goto error;
}
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 9dcb68f04f03..055b84adedac 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -1028,7 +1028,10 @@ test_ctrl_queue(struct usbtest_dev *dev, struct usbtest_param *param)
case 13: /* short read, resembling case 10 */
req.wValue = cpu_to_le16((USB_DT_CONFIG << 8) | 0);
/* last data packet "should" be DATA1, not DATA0 */
- len = 1024 - udev->descriptor.bMaxPacketSize0;
+ if (udev->speed == USB_SPEED_SUPER)
+ len = 1024 - 512;
+ else
+ len = 1024 - udev->descriptor.bMaxPacketSize0;
expected = -EREMOTEIO;
break;
case 14: /* short read; try to fill the last packet */
@@ -1387,11 +1390,15 @@ static int test_halt(struct usbtest_dev *tdev, int ep, struct urb *urb)
static int halt_simple(struct usbtest_dev *dev)
{
- int ep;
- int retval = 0;
- struct urb *urb;
+ int ep;
+ int retval = 0;
+ struct urb *urb;
+ struct usb_device *udev = testdev_to_usbdev(dev);
- urb = simple_alloc_urb(testdev_to_usbdev(dev), 0, 512);
+ if (udev->speed == USB_SPEED_SUPER)
+ urb = simple_alloc_urb(udev, 0, 1024);
+ else
+ urb = simple_alloc_urb(udev, 0, 512);
if (urb == NULL)
return -ENOMEM;
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index 8b1d94a76914..29cad9e0a7a9 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -85,9 +85,9 @@ static void destroy_priv(struct kref *kref)
{
struct parport_uss720_private *priv = container_of(kref, struct parport_uss720_private, ref_count);
+ dev_dbg(&priv->usbdev->dev, "destroying priv datastructure\n");
usb_put_dev(priv->usbdev);
kfree(priv);
- dbg("destroying priv datastructure");
}
static void destroy_async(struct kref *kref)
@@ -118,14 +118,17 @@ static void async_complete(struct urb *urb)
priv = rq->priv;
pp = priv->pp;
if (status) {
- err("async_complete: urb error %d", status);
+ dev_err(&urb->dev->dev, "async_complete: urb error %d\n",
+ status);
} else if (rq->dr.bRequest == 3) {
memcpy(priv->reg, rq->reg, sizeof(priv->reg));
#if 0
- dbg("async_complete regs %02x %02x %02x %02x %02x %02x %02x",
- (unsigned int)priv->reg[0], (unsigned int)priv->reg[1], (unsigned int)priv->reg[2],
- (unsigned int)priv->reg[3], (unsigned int)priv->reg[4], (unsigned int)priv->reg[5],
- (unsigned int)priv->reg[6]);
+ dev_dbg(&priv->usbdev->dev,
+ "async_complete regs %02x %02x %02x %02x %02x %02x %02x\n",
+ (unsigned int)priv->reg[0], (unsigned int)priv->reg[1],
+ (unsigned int)priv->reg[2], (unsigned int)priv->reg[3],
+ (unsigned int)priv->reg[4], (unsigned int)priv->reg[5],
+ (unsigned int)priv->reg[6]);
#endif
/* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
if (rq->reg[2] & rq->reg[1] & 0x10 && pp)
@@ -151,7 +154,7 @@ static struct uss720_async_request *submit_async_request(struct parport_uss720_p
return NULL;
rq = kmalloc(sizeof(struct uss720_async_request), mem_flags);
if (!rq) {
- err("submit_async_request out of memory");
+ dev_err(&usbdev->dev, "submit_async_request out of memory\n");
return NULL;
}
kref_init(&rq->ref_count);
@@ -162,7 +165,7 @@ static struct uss720_async_request *submit_async_request(struct parport_uss720_p
rq->urb = usb_alloc_urb(0, mem_flags);
if (!rq->urb) {
kref_put(&rq->ref_count, destroy_async);
- err("submit_async_request out of memory");
+ dev_err(&usbdev->dev, "submit_async_request out of memory\n");
return NULL;
}
rq->dr.bRequestType = requesttype;
@@ -182,7 +185,7 @@ static struct uss720_async_request *submit_async_request(struct parport_uss720_p
if (!ret)
return rq;
destroy_async(&rq->ref_count);
- err("submit_async_request submit_urb failed with %d", ret);
+ dev_err(&usbdev->dev, "submit_async_request submit_urb failed with %d\n", ret);
return NULL;
}
@@ -217,7 +220,8 @@ static int get_1284_register(struct parport *pp, unsigned char reg, unsigned cha
priv = pp->private_data;
rq = submit_async_request(priv, 3, 0xc0, ((unsigned int)reg) << 8, 0, mem_flags);
if (!rq) {
- err("get_1284_register(%u) failed", (unsigned int)reg);
+ dev_err(&priv->usbdev->dev, "get_1284_register(%u) failed",
+ (unsigned int)reg);
return -EIO;
}
if (!val) {
@@ -248,7 +252,8 @@ static int set_1284_register(struct parport *pp, unsigned char reg, unsigned cha
priv = pp->private_data;
rq = submit_async_request(priv, 4, 0x40, (((unsigned int)reg) << 8) | val, 0, mem_flags);
if (!rq) {
- err("set_1284_register(%u,%u) failed", (unsigned int)reg, (unsigned int)val);
+ dev_err(&priv->usbdev->dev, "set_1284_register(%u,%u) failed",
+ (unsigned int)reg, (unsigned int)val);
return -EIO;
}
kref_put(&rq->ref_count, destroy_async);
@@ -690,9 +695,9 @@ static int uss720_probe(struct usb_interface *intf,
unsigned char reg;
int i;
- dbg("probe: vendor id 0x%x, device id 0x%x\n",
- le16_to_cpu(usbdev->descriptor.idVendor),
- le16_to_cpu(usbdev->descriptor.idProduct));
+ dev_dbg(&intf->dev, "probe: vendor id 0x%x, device id 0x%x\n",
+ le16_to_cpu(usbdev->descriptor.idVendor),
+ le16_to_cpu(usbdev->descriptor.idProduct));
/* our known interfaces have 3 alternate settings */
if (intf->num_altsetting != 3) {
@@ -700,7 +705,7 @@ static int uss720_probe(struct usb_interface *intf,
return -ENODEV;
}
i = usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 2);
- dbg("set inteface result %d", i);
+ dev_dbg(&intf->dev, "set inteface result %d\n", i);
interface = intf->cur_altsetting;
@@ -731,11 +736,13 @@ static int uss720_probe(struct usb_interface *intf,
set_1284_register(pp, 2, 0x0c, GFP_KERNEL);
/* debugging */
get_1284_register(pp, 0, &reg, GFP_KERNEL);
- dbg("reg: %02x %02x %02x %02x %02x %02x %02x",
- priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3], priv->reg[4], priv->reg[5], priv->reg[6]);
+ dev_dbg(&intf->dev, "reg: %02x %02x %02x %02x %02x %02x %02x\n",
+ priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3],
+ priv->reg[4], priv->reg[5], priv->reg[6]);
endpoint = &interface->endpoint[2];
- dbg("epaddr %d interval %d", endpoint->desc.bEndpointAddress, endpoint->desc.bInterval);
+ dev_dbg(&intf->dev, "epaddr %d interval %d\n",
+ endpoint->desc.bEndpointAddress, endpoint->desc.bInterval);
parport_announce_port(pp);
usb_set_intfdata(intf, pp);
@@ -753,20 +760,20 @@ static void uss720_disconnect(struct usb_interface *intf)
struct parport_uss720_private *priv;
struct usb_device *usbdev;
- dbg("disconnect");
+ dev_dbg(&intf->dev, "disconnect\n");
usb_set_intfdata(intf, NULL);
if (pp) {
priv = pp->private_data;
usbdev = priv->usbdev;
priv->usbdev = NULL;
priv->pp = NULL;
- dbg("parport_remove_port");
+ dev_dbg(&intf->dev, "parport_remove_port\n");
parport_remove_port(pp);
parport_put_port(pp);
kill_all_async_requests_priv(priv);
kref_put(&priv->ref_count, destroy_priv);
}
- dbg("disconnect done");
+ dev_dbg(&intf->dev, "disconnect done\n");
}
/* table of cables that work through this driver */
diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c
index 70201462e19c..42ad2e6d86c4 100644
--- a/drivers/usb/misc/yurex.c
+++ b/drivers/usb/misc/yurex.c
@@ -83,7 +83,8 @@ static void yurex_control_callback(struct urb *urb)
int status = urb->status;
if (status) {
- err("%s - control failed: %d\n", __func__, status);
+ dev_err(&urb->dev->dev, "%s - control failed: %d\n",
+ __func__, status);
wake_up_interruptible(&dev->waitq);
return;
}
@@ -94,7 +95,7 @@ static void yurex_delete(struct kref *kref)
{
struct usb_yurex *dev = to_yurex_dev(kref);
- dbg("yurex_delete");
+ dev_dbg(&dev->interface->dev, "%s\n", __func__);
usb_put_dev(dev->udev);
if (dev->cntl_urb) {
@@ -137,8 +138,9 @@ static void yurex_interrupt(struct urb *urb)
case 0: /*success*/
break;
case -EOVERFLOW:
- err("%s - overflow with length %d, actual length is %d",
- __func__, YUREX_BUF_SIZE, dev->urb->actual_length);
+ dev_err(&dev->interface->dev,
+ "%s - overflow with length %d, actual length is %d\n",
+ __func__, YUREX_BUF_SIZE, dev->urb->actual_length);
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
@@ -146,7 +148,8 @@ static void yurex_interrupt(struct urb *urb)
/* The device is terminated, clean up */
return;
default:
- err("%s - unknown status received: %d", __func__, status);
+ dev_err(&dev->interface->dev,
+ "%s - unknown status received: %d\n", __func__, status);
goto exit;
}
@@ -162,16 +165,19 @@ static void yurex_interrupt(struct urb *urb)
if (i != 5)
dev->bbu <<= 8;
}
- dbg("%s count: %lld", __func__, dev->bbu);
+ dev_dbg(&dev->interface->dev, "%s count: %lld\n",
+ __func__, dev->bbu);
spin_unlock_irqrestore(&dev->lock, flags);
kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
}
else
- dbg("data format error - no EOF");
+ dev_dbg(&dev->interface->dev,
+ "data format error - no EOF\n");
break;
case CMD_ACK:
- dbg("%s ack: %c", __func__, buf[1]);
+ dev_dbg(&dev->interface->dev, "%s ack: %c\n",
+ __func__, buf[1]);
wake_up_interruptible(&dev->waitq);
break;
}
@@ -179,7 +185,7 @@ static void yurex_interrupt(struct urb *urb)
exit:
retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
if (retval) {
- err("%s - usb_submit_urb failed: %d",
+ dev_err(&dev->interface->dev, "%s - usb_submit_urb failed: %d\n",
__func__, retval);
}
}
@@ -196,7 +202,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
/* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) {
- err("Out of memory");
+ dev_err(&interface->dev, "Out of memory\n");
goto error;
}
kref_init(&dev->kref);
@@ -219,7 +225,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
}
if (!dev->int_in_endpointAddr) {
retval = -ENODEV;
- err("Could not find endpoints");
+ dev_err(&interface->dev, "Could not find endpoints\n");
goto error;
}
@@ -227,14 +233,14 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
/* allocate control URB */
dev->cntl_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->cntl_urb) {
- err("Could not allocate control URB");
+ dev_err(&interface->dev, "Could not allocate control URB\n");
goto error;
}
/* allocate buffer for control req */
dev->cntl_req = kmalloc(YUREX_BUF_SIZE, GFP_KERNEL);
if (!dev->cntl_req) {
- err("Could not allocate cntl_req");
+ dev_err(&interface->dev, "Could not allocate cntl_req\n");
goto error;
}
@@ -243,7 +249,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
GFP_KERNEL,
&dev->cntl_urb->transfer_dma);
if (!dev->cntl_buffer) {
- err("Could not allocate cntl_buffer");
+ dev_err(&interface->dev, "Could not allocate cntl_buffer\n");
goto error;
}
@@ -265,7 +271,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
/* allocate interrupt URB */
dev->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->urb) {
- err("Could not allocate URB");
+ dev_err(&interface->dev, "Could not allocate URB\n");
goto error;
}
@@ -273,7 +279,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
dev->int_buffer = usb_alloc_coherent(dev->udev, YUREX_BUF_SIZE,
GFP_KERNEL, &dev->urb->transfer_dma);
if (!dev->int_buffer) {
- err("Could not allocate int_buffer");
+ dev_err(&interface->dev, "Could not allocate int_buffer\n");
goto error;
}
@@ -285,7 +291,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
dev->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
if (usb_submit_urb(dev->urb, GFP_KERNEL)) {
retval = -EIO;
- err("Could not submitting URB");
+ dev_err(&interface->dev, "Could not submitting URB\n");
goto error;
}
@@ -295,7 +301,8 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
/* we can register the device now, as it is ready */
retval = usb_register_dev(interface, &yurex_class);
if (retval) {
- err("Not able to get a minor for this device.");
+ dev_err(&interface->dev,
+ "Not able to get a minor for this device.\n");
usb_set_intfdata(interface, NULL);
goto error;
}
@@ -368,8 +375,8 @@ static int yurex_open(struct inode *inode, struct file *file)
interface = usb_find_interface(&yurex_driver, subminor);
if (!interface) {
- err("%s - error, can't find device for minor %d",
- __func__, subminor);
+ printk(KERN_ERR "%s - error, can't find device for minor %d",
+ __func__, subminor);
retval = -ENODEV;
goto exit;
}
@@ -505,7 +512,8 @@ static ssize_t yurex_write(struct file *file, const char *user_buffer, size_t co
/* send the data as the control msg */
prepare_to_wait(&dev->waitq, &wait, TASK_INTERRUPTIBLE);
- dbg("%s - submit %c", __func__, dev->cntl_buffer[0]);
+ dev_dbg(&dev->interface->dev, "%s - submit %c\n", __func__,
+ dev->cntl_buffer[0]);
retval = usb_submit_urb(dev->cntl_urb, GFP_KERNEL);
if (retval >= 0)
timeout = schedule_timeout(YUREX_WRITE_TIMEOUT);
@@ -514,7 +522,9 @@ static ssize_t yurex_write(struct file *file, const char *user_buffer, size_t co
mutex_unlock(&dev->io_mutex);
if (retval < 0) {
- err("%s - failed to send bulk msg, error %d", __func__, retval);
+ dev_err(&dev->interface->dev,
+ "%s - failed to send bulk msg, error %d\n",
+ __func__, retval);
goto error;
}
if (set && timeout)
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index f70cab3beeec..ef0c3f9f0947 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -8,6 +8,7 @@ config USB_MUSB_HDRC
tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
depends on USB && USB_GADGET
select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN)
+ select NOP_USB_XCEIV if (SOC_OMAPTI81XX || SOC_OMAPAM33XX)
select TWL4030_USB if MACH_OMAP_3430SDP
select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA
select USB_OTG_UTILS
@@ -54,6 +55,10 @@ config USB_MUSB_AM35X
tristate "AM35x"
depends on ARCH_OMAP
+config USB_MUSB_DSPS
+ tristate "TI DSPS platforms"
+ depends on SOC_OMAPTI81XX || SOC_OMAPAM33XX
+
config USB_MUSB_BLACKFIN
tristate "Blackfin"
depends on (BF54x && !BF544) || (BF52x && ! BF522 && !BF523)
@@ -70,7 +75,8 @@ choice
default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN
default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI
default USB_TUSB_OMAP_DMA if USB_MUSB_TUSB6010
- default MUSB_PIO_ONLY if USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X
+ default MUSB_PIO_ONLY if USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X \
+ || USB_MUSB_DSPS
help
Unfortunately, only one option can be enabled here. Ideally one
should be able to build all these drivers into one kernel to
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
index 88bfb9dee4bf..3b858715b5ea 100644
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -13,6 +13,7 @@ musb_hdrc-$(CONFIG_DEBUG_FS) += musb_debugfs.o
# Hardware Glue Layer
obj-$(CONFIG_USB_MUSB_OMAP2PLUS) += omap2430.o
obj-$(CONFIG_USB_MUSB_AM35X) += am35x.o
+obj-$(CONFIG_USB_MUSB_DSPS) += musb_dsps.o
obj-$(CONFIG_USB_MUSB_TUSB6010) += tusb6010.o
obj-$(CONFIG_USB_MUSB_DAVINCI) += davinci.o
obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
index 66bc376005d2..8637c1f69fc3 100644
--- a/drivers/usb/musb/cppi_dma.c
+++ b/drivers/usb/musb/cppi_dma.c
@@ -6,6 +6,7 @@
* The TUSB6020, using VLYNQ, has CPPI that looks much like DaVinci.
*/
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/usb.h>
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 66aaccf04490..db3dff854b71 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1034,7 +1034,9 @@ static void musb_shutdown(struct platform_device *pdev)
|| defined(CONFIG_USB_MUSB_OMAP2PLUS) \
|| defined(CONFIG_USB_MUSB_OMAP2PLUS_MODULE) \
|| defined(CONFIG_USB_MUSB_AM35X) \
- || defined(CONFIG_USB_MUSB_AM35X_MODULE)
+ || defined(CONFIG_USB_MUSB_AM35X_MODULE) \
+ || defined(CONFIG_USB_MUSB_DSPS) \
+ || defined(CONFIG_USB_MUSB_DSPS_MODULE)
static ushort __devinitdata fifo_mode = 4;
#elif defined(CONFIG_USB_MUSB_UX500) \
|| defined(CONFIG_USB_MUSB_UX500_MODULE)
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
new file mode 100644
index 000000000000..23db42db761a
--- /dev/null
+++ b/drivers/usb/musb/musb_dsps.c
@@ -0,0 +1,711 @@
+/*
+ * Texas Instruments DSPS platforms "glue layer"
+ *
+ * Copyright (C) 2012, by Texas Instruments
+ *
+ * Based on the am35x "glue layer" code.
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux 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.
+ *
+ * The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307 USA
+ *
+ * musb_dsps.c will be a common file for all the TI DSPS platforms
+ * such as dm64x, dm36x, dm35x, da8x, am35x and ti81x.
+ * For now only ti81x is using this and in future davinci.c, am35x.c
+ * da8xx.c would be merged to this file after testing.
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
+#include <linux/module.h>
+
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+
+#include <plat/usb.h>
+
+#include "musb_core.h"
+
+/**
+ * avoid using musb_readx()/musb_writex() as glue layer should not be
+ * dependent on musb core layer symbols.
+ */
+static inline u8 dsps_readb(const void __iomem *addr, unsigned offset)
+ { return __raw_readb(addr + offset); }
+
+static inline u32 dsps_readl(const void __iomem *addr, unsigned offset)
+ { return __raw_readl(addr + offset); }
+
+static inline void dsps_writeb(void __iomem *addr, unsigned offset, u8 data)
+ { __raw_writeb(data, addr + offset); }
+
+static inline void dsps_writel(void __iomem *addr, unsigned offset, u32 data)
+ { __raw_writel(data, addr + offset); }
+
+/**
+ * DSPS musb wrapper register offset.
+ * FIXME: This should be expanded to have all the wrapper registers from TI DSPS
+ * musb ips.
+ */
+struct dsps_musb_wrapper {
+ u16 revision;
+ u16 control;
+ u16 status;
+ u16 eoi;
+ u16 epintr_set;
+ u16 epintr_clear;
+ u16 epintr_status;
+ u16 coreintr_set;
+ u16 coreintr_clear;
+ u16 coreintr_status;
+ u16 phy_utmi;
+ u16 mode;
+
+ /* bit positions for control */
+ unsigned reset:5;
+
+ /* bit positions for interrupt */
+ unsigned usb_shift:5;
+ u32 usb_mask;
+ u32 usb_bitmap;
+ unsigned drvvbus:5;
+
+ unsigned txep_shift:5;
+ u32 txep_mask;
+ u32 txep_bitmap;
+
+ unsigned rxep_shift:5;
+ u32 rxep_mask;
+ u32 rxep_bitmap;
+
+ /* bit positions for phy_utmi */
+ unsigned otg_disable:5;
+
+ /* bit positions for mode */
+ unsigned iddig:5;
+ /* miscellaneous stuff */
+ u32 musb_core_offset;
+ u8 poll_seconds;
+};
+
+/**
+ * DSPS glue structure.
+ */
+struct dsps_glue {
+ struct device *dev;
+ struct platform_device *musb; /* child musb pdev */
+ const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */
+ struct timer_list timer; /* otg_workaround timer */
+};
+
+/**
+ * dsps_musb_enable - enable interrupts
+ */
+static void dsps_musb_enable(struct musb *musb)
+{
+ struct device *dev = musb->controller;
+ struct platform_device *pdev = to_platform_device(dev->parent);
+ struct dsps_glue *glue = platform_get_drvdata(pdev);
+ const struct dsps_musb_wrapper *wrp = glue->wrp;
+ void __iomem *reg_base = musb->ctrl_base;
+ u32 epmask, coremask;
+
+ /* Workaround: setup IRQs through both register sets. */
+ epmask = ((musb->epmask & wrp->txep_mask) << wrp->txep_shift) |
+ ((musb->epmask & wrp->rxep_mask) << wrp->rxep_shift);
+ coremask = (wrp->usb_bitmap & ~MUSB_INTR_SOF);
+
+ dsps_writel(reg_base, wrp->epintr_set, epmask);
+ dsps_writel(reg_base, wrp->coreintr_set, coremask);
+ /* Force the DRVVBUS IRQ so we can start polling for ID change. */
+ if (is_otg_enabled(musb))
+ dsps_writel(reg_base, wrp->coreintr_set,
+ (1 << wrp->drvvbus) << wrp->usb_shift);
+}
+
+/**
+ * dsps_musb_disable - disable HDRC and flush interrupts
+ */
+static void dsps_musb_disable(struct musb *musb)
+{
+ struct device *dev = musb->controller;
+ struct platform_device *pdev = to_platform_device(dev->parent);
+ struct dsps_glue *glue = platform_get_drvdata(pdev);
+ const struct dsps_musb_wrapper *wrp = glue->wrp;
+ void __iomem *reg_base = musb->ctrl_base;
+
+ dsps_writel(reg_base, wrp->coreintr_clear, wrp->usb_bitmap);
+ dsps_writel(reg_base, wrp->epintr_clear,
+ wrp->txep_bitmap | wrp->rxep_bitmap);
+ dsps_writeb(musb->mregs, MUSB_DEVCTL, 0);
+ dsps_writel(reg_base, wrp->eoi, 0);
+}
+
+static void otg_timer(unsigned long _musb)
+{
+ struct musb *musb = (void *)_musb;
+ void __iomem *mregs = musb->mregs;
+ struct device *dev = musb->controller;
+ struct platform_device *pdev = to_platform_device(dev->parent);
+ struct dsps_glue *glue = platform_get_drvdata(pdev);
+ const struct dsps_musb_wrapper *wrp = glue->wrp;
+ u8 devctl;
+ unsigned long flags;
+
+ /*
+ * We poll because DSPS IP's won't expose several OTG-critical
+ * status change events (from the transceiver) otherwise.
+ */
+ devctl = dsps_readb(mregs, MUSB_DEVCTL);
+ dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
+ otg_state_string(musb->xceiv->state));
+
+ spin_lock_irqsave(&musb->lock, flags);
+ switch (musb->xceiv->state) {
+ case OTG_STATE_A_WAIT_BCON:
+ devctl &= ~MUSB_DEVCTL_SESSION;
+ dsps_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+ devctl = dsps_readb(musb->mregs, MUSB_DEVCTL);
+ if (devctl & MUSB_DEVCTL_BDEVICE) {
+ musb->xceiv->state = OTG_STATE_B_IDLE;
+ MUSB_DEV_MODE(musb);
+ } else {
+ musb->xceiv->state = OTG_STATE_A_IDLE;
+ MUSB_HST_MODE(musb);
+ }
+ break;
+ case OTG_STATE_A_WAIT_VFALL:
+ musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ dsps_writel(musb->ctrl_base, wrp->coreintr_set,
+ MUSB_INTR_VBUSERROR << wrp->usb_shift);
+ break;
+ case OTG_STATE_B_IDLE:
+ if (!is_peripheral_enabled(musb))
+ break;
+
+ devctl = dsps_readb(mregs, MUSB_DEVCTL);
+ if (devctl & MUSB_DEVCTL_BDEVICE)
+ mod_timer(&glue->timer,
+ jiffies + wrp->poll_seconds * HZ);
+ else
+ musb->xceiv->state = OTG_STATE_A_IDLE;
+ break;
+ default:
+ break;
+ }
+ spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
+{
+ struct device *dev = musb->controller;
+ struct platform_device *pdev = to_platform_device(dev->parent);
+ struct dsps_glue *glue = platform_get_drvdata(pdev);
+ static unsigned long last_timer;
+
+ if (!is_otg_enabled(musb))
+ return;
+
+ if (timeout == 0)
+ timeout = jiffies + msecs_to_jiffies(3);
+
+ /* Never idle if active, or when VBUS timeout is not set as host */
+ if (musb->is_active || (musb->a_wait_bcon == 0 &&
+ musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
+ dev_dbg(musb->controller, "%s active, deleting timer\n",
+ otg_state_string(musb->xceiv->state));
+ del_timer(&glue->timer);
+ last_timer = jiffies;
+ return;
+ }
+
+ if (time_after(last_timer, timeout) && timer_pending(&glue->timer)) {
+ dev_dbg(musb->controller,
+ "Longer idle timer already pending, ignoring...\n");
+ return;
+ }
+ last_timer = timeout;
+
+ dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
+ otg_state_string(musb->xceiv->state),
+ jiffies_to_msecs(timeout - jiffies));
+ mod_timer(&glue->timer, timeout);
+}
+
+static irqreturn_t dsps_interrupt(int irq, void *hci)
+{
+ struct musb *musb = hci;
+ void __iomem *reg_base = musb->ctrl_base;
+ struct device *dev = musb->controller;
+ struct platform_device *pdev = to_platform_device(dev->parent);
+ struct dsps_glue *glue = platform_get_drvdata(pdev);
+ const struct dsps_musb_wrapper *wrp = glue->wrp;
+ unsigned long flags;
+ irqreturn_t ret = IRQ_NONE;
+ u32 epintr, usbintr;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ /* Get endpoint interrupts */
+ epintr = dsps_readl(reg_base, wrp->epintr_status);
+ musb->int_rx = (epintr & wrp->rxep_bitmap) >> wrp->rxep_shift;
+ musb->int_tx = (epintr & wrp->txep_bitmap) >> wrp->txep_shift;
+
+ if (epintr)
+ dsps_writel(reg_base, wrp->epintr_status, epintr);
+
+ /* Get usb core interrupts */
+ usbintr = dsps_readl(reg_base, wrp->coreintr_status);
+ if (!usbintr && !epintr)
+ goto eoi;
+
+ musb->int_usb = (usbintr & wrp->usb_bitmap) >> wrp->usb_shift;
+ if (usbintr)
+ dsps_writel(reg_base, wrp->coreintr_status, usbintr);
+
+ dev_dbg(musb->controller, "usbintr (%x) epintr(%x)\n",
+ usbintr, epintr);
+ /*
+ * DRVVBUS IRQs are the only proxy we have (a very poor one!) for
+ * DSPS IP's missing ID change IRQ. We need an ID change IRQ to
+ * switch appropriately between halves of the OTG state machine.
+ * Managing DEVCTL.SESSION per Mentor docs requires that we know its
+ * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
+ * Also, DRVVBUS pulses for SRP (but not at 5V) ...
+ */
+ if ((usbintr & MUSB_INTR_BABBLE) && is_host_enabled(musb))
+ pr_info("CAUTION: musb: Babble Interrupt Occured\n");
+
+ if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) {
+ int drvvbus = dsps_readl(reg_base, wrp->status);
+ void __iomem *mregs = musb->mregs;
+ u8 devctl = dsps_readb(mregs, MUSB_DEVCTL);
+ int err;
+
+ err = is_host_enabled(musb) && (musb->int_usb &
+ MUSB_INTR_VBUSERROR);
+ if (err) {
+ /*
+ * The Mentor core doesn't debounce VBUS as needed
+ * to cope with device connect current spikes. This
+ * means it's not uncommon for bus-powered devices
+ * to get VBUS errors during enumeration.
+ *
+ * This is a workaround, but newer RTL from Mentor
+ * seems to allow a better one: "re"-starting sessions
+ * without waiting for VBUS to stop registering in
+ * devctl.
+ */
+ musb->int_usb &= ~MUSB_INTR_VBUSERROR;
+ musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+ mod_timer(&glue->timer,
+ jiffies + wrp->poll_seconds * HZ);
+ WARNING("VBUS error workaround (delay coming)\n");
+ } else if (is_host_enabled(musb) && drvvbus) {
+ musb->is_active = 1;
+ MUSB_HST_MODE(musb);
+ musb->xceiv->otg->default_a = 1;
+ musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ del_timer(&glue->timer);
+ } else {
+ musb->is_active = 0;
+ MUSB_DEV_MODE(musb);
+ musb->xceiv->otg->default_a = 0;
+ musb->xceiv->state = OTG_STATE_B_IDLE;
+ }
+
+ /* NOTE: this must complete power-on within 100 ms. */
+ dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
+ drvvbus ? "on" : "off",
+ otg_state_string(musb->xceiv->state),
+ err ? " ERROR" : "",
+ devctl);
+ ret = IRQ_HANDLED;
+ }
+
+ if (musb->int_tx || musb->int_rx || musb->int_usb)
+ ret |= musb_interrupt(musb);
+
+ eoi:
+ /* EOI needs to be written for the IRQ to be re-asserted. */
+ if (ret == IRQ_HANDLED || epintr || usbintr)
+ dsps_writel(reg_base, wrp->eoi, 1);
+
+ /* Poll for ID change */
+ if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE)
+ mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);
+
+ spin_unlock_irqrestore(&musb->lock, flags);
+
+ return ret;
+}
+
+static int dsps_musb_init(struct musb *musb)
+{
+ struct device *dev = musb->controller;
+ struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct platform_device *pdev = to_platform_device(dev->parent);
+ struct dsps_glue *glue = platform_get_drvdata(pdev);
+ const struct dsps_musb_wrapper *wrp = glue->wrp;
+ struct omap_musb_board_data *data = plat->board_data;
+ void __iomem *reg_base = musb->ctrl_base;
+ u32 rev, val;
+ int status;
+
+ /* mentor core register starts at offset of 0x400 from musb base */
+ musb->mregs += wrp->musb_core_offset;
+
+ /* NOP driver needs change if supporting dual instance */
+ usb_nop_xceiv_register();
+ musb->xceiv = usb_get_transceiver();
+ if (!musb->xceiv)
+ return -ENODEV;
+
+ /* Returns zero if e.g. not clocked */
+ rev = dsps_readl(reg_base, wrp->revision);
+ if (!rev) {
+ status = -ENODEV;
+ goto err0;
+ }
+
+ if (is_host_enabled(musb))
+ setup_timer(&glue->timer, otg_timer, (unsigned long) musb);
+
+ /* Reset the musb */
+ dsps_writel(reg_base, wrp->control, (1 << wrp->reset));
+
+ /* Start the on-chip PHY and its PLL. */
+ if (data->set_phy_power)
+ data->set_phy_power(1);
+
+ musb->isr = dsps_interrupt;
+
+ /* reset the otgdisable bit, needed for host mode to work */
+ val = dsps_readl(reg_base, wrp->phy_utmi);
+ val &= ~(1 << wrp->otg_disable);
+ dsps_writel(musb->ctrl_base, wrp->phy_utmi, val);
+
+ /* clear level interrupt */
+ dsps_writel(reg_base, wrp->eoi, 0);
+
+ return 0;
+err0:
+ usb_put_transceiver(musb->xceiv);
+ usb_nop_xceiv_unregister();
+ return status;
+}
+
+static int dsps_musb_exit(struct musb *musb)
+{
+ struct device *dev = musb->controller;
+ struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct omap_musb_board_data *data = plat->board_data;
+ struct platform_device *pdev = to_platform_device(dev->parent);
+ struct dsps_glue *glue = platform_get_drvdata(pdev);
+
+ if (is_host_enabled(musb))
+ del_timer_sync(&glue->timer);
+
+ /* Shutdown the on-chip PHY and its PLL. */
+ if (data->set_phy_power)
+ data->set_phy_power(0);
+
+ /* NOP driver needs change if supporting dual instance */
+ usb_put_transceiver(musb->xceiv);
+ usb_nop_xceiv_unregister();
+
+ return 0;
+}
+
+static struct musb_platform_ops dsps_ops = {
+ .init = dsps_musb_init,
+ .exit = dsps_musb_exit,
+
+ .enable = dsps_musb_enable,
+ .disable = dsps_musb_disable,
+
+ .try_idle = dsps_musb_try_idle,
+};
+
+static u64 musb_dmamask = DMA_BIT_MASK(32);
+
+static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id)
+{
+ struct device *dev = glue->dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct musb_hdrc_platform_data *pdata = dev->platform_data;
+ struct platform_device *musb;
+ struct resource *res;
+ struct resource resources[2];
+ char res_name[10];
+ int ret;
+
+ /* get memory resource */
+ sprintf(res_name, "musb%d", id);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name);
+ if (!res) {
+ dev_err(dev, "%s get mem resource failed\n", res_name);
+ ret = -ENODEV;
+ goto err0;
+ }
+ res->parent = NULL;
+ resources[0] = *res;
+
+ /* get irq resource */
+ sprintf(res_name, "musb%d-irq", id);
+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name);
+ if (!res) {
+ dev_err(dev, "%s get irq resource failed\n", res_name);
+ ret = -ENODEV;
+ goto err0;
+ }
+ strcpy((u8 *)res->name, "mc");
+ res->parent = NULL;
+ resources[1] = *res;
+
+ /* allocate the child platform device */
+ musb = platform_device_alloc("musb-hdrc", -1);
+ if (!musb) {
+ dev_err(dev, "failed to allocate musb device\n");
+ ret = -ENOMEM;
+ goto err0;
+ }
+
+ musb->dev.parent = dev;
+ musb->dev.dma_mask = &musb_dmamask;
+ musb->dev.coherent_dma_mask = musb_dmamask;
+
+ glue->musb = musb;
+
+ pdata->platform_ops = &dsps_ops;
+
+ ret = platform_device_add_resources(musb, resources, 2);
+ if (ret) {
+ dev_err(dev, "failed to add resources\n");
+ goto err1;
+ }
+
+ ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
+ if (ret) {
+ dev_err(dev, "failed to add platform_data\n");
+ goto err1;
+ }
+
+ ret = platform_device_add(musb);
+ if (ret) {
+ dev_err(dev, "failed to register musb device\n");
+ goto err1;
+ }
+
+ return 0;
+
+err1:
+ platform_device_put(musb);
+err0:
+ return ret;
+}
+
+static void __devexit dsps_delete_musb_pdev(struct dsps_glue *glue)
+{
+ platform_device_del(glue->musb);
+ platform_device_put(glue->musb);
+}
+
+static int __devinit dsps_probe(struct platform_device *pdev)
+{
+ const struct platform_device_id *id = platform_get_device_id(pdev);
+ const struct dsps_musb_wrapper *wrp =
+ (struct dsps_musb_wrapper *)id->driver_data;
+ struct dsps_glue *glue;
+ struct resource *iomem;
+ int ret;
+
+ /* allocate glue */
+ glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+ if (!glue) {
+ dev_err(&pdev->dev, "unable to allocate glue memory\n");
+ ret = -ENOMEM;
+ goto err0;
+ }
+
+ /* get memory resource */
+ iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!iomem) {
+ dev_err(&pdev->dev, "failed to get usbss mem resourse\n");
+ ret = -ENODEV;
+ goto err1;
+ }
+
+ glue->dev = &pdev->dev;
+
+ glue->wrp = kmemdup(wrp, sizeof(*wrp), GFP_KERNEL);
+ if (!glue->wrp) {
+ dev_err(&pdev->dev, "failed to duplicate wrapper struct memory\n");
+ ret = -ENOMEM;
+ goto err1;
+ }
+ platform_set_drvdata(pdev, glue);
+
+ /* create the child platform device for first instances of musb */
+ ret = dsps_create_musb_pdev(glue, 0);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "failed to create child pdev\n");
+ goto err2;
+ }
+
+ /* enable the usbss clocks */
+ pm_runtime_enable(&pdev->dev);
+
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "pm_runtime_get_sync FAILED");
+ goto err3;
+ }
+
+ return 0;
+
+err3:
+ pm_runtime_disable(&pdev->dev);
+err2:
+ kfree(glue->wrp);
+err1:
+ kfree(glue);
+err0:
+ return ret;
+}
+static int __devexit dsps_remove(struct platform_device *pdev)
+{
+ struct dsps_glue *glue = platform_get_drvdata(pdev);
+
+ /* delete the child platform device */
+ dsps_delete_musb_pdev(glue);
+
+ /* disable usbss clocks */
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ kfree(glue->wrp);
+ kfree(glue);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int dsps_suspend(struct device *dev)
+{
+ struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct omap_musb_board_data *data = plat->board_data;
+
+ /* Shutdown the on-chip PHY and its PLL. */
+ if (data->set_phy_power)
+ data->set_phy_power(0);
+
+ return 0;
+}
+
+static int dsps_resume(struct device *dev)
+{
+ struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct omap_musb_board_data *data = plat->board_data;
+
+ /* Start the on-chip PHY and its PLL. */
+ if (data->set_phy_power)
+ data->set_phy_power(1);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume);
+
+static const struct dsps_musb_wrapper ti81xx_driver_data __devinitconst = {
+ .revision = 0x00,
+ .control = 0x14,
+ .status = 0x18,
+ .eoi = 0x24,
+ .epintr_set = 0x38,
+ .epintr_clear = 0x40,
+ .epintr_status = 0x30,
+ .coreintr_set = 0x3c,
+ .coreintr_clear = 0x44,
+ .coreintr_status = 0x34,
+ .phy_utmi = 0xe0,
+ .mode = 0xe8,
+ .reset = 0,
+ .otg_disable = 21,
+ .iddig = 8,
+ .usb_shift = 0,
+ .usb_mask = 0x1ff,
+ .usb_bitmap = (0x1ff << 0),
+ .drvvbus = 8,
+ .txep_shift = 0,
+ .txep_mask = 0xffff,
+ .txep_bitmap = (0xffff << 0),
+ .rxep_shift = 16,
+ .rxep_mask = 0xfffe,
+ .rxep_bitmap = (0xfffe << 16),
+ .musb_core_offset = 0x400,
+ .poll_seconds = 2,
+};
+
+static const struct platform_device_id musb_dsps_id_table[] __devinitconst = {
+ {
+ .name = "musb-ti81xx",
+ .driver_data = (kernel_ulong_t) &ti81xx_driver_data,
+ },
+ { }, /* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(platform, musb_dsps_id_table);
+
+static const struct of_device_id musb_dsps_of_match[] __devinitconst = {
+ { .compatible = "musb-ti81xx", },
+ { .compatible = "ti,ti81xx-musb", },
+ { .compatible = "ti,am335x-musb", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, musb_dsps_of_match);
+
+static struct platform_driver dsps_usbss_driver = {
+ .probe = dsps_probe,
+ .remove = __devexit_p(dsps_remove),
+ .driver = {
+ .name = "musb-dsps",
+ .pm = &dsps_pm_ops,
+ .of_match_table = musb_dsps_of_match,
+ },
+ .id_table = musb_dsps_id_table,
+};
+
+MODULE_DESCRIPTION("TI DSPS MUSB Glue Layer");
+MODULE_AUTHOR("Ravi B <ravibabu@ti.com>");
+MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>");
+MODULE_LICENSE("GPL v2");
+
+static int __init dsps_init(void)
+{
+ return platform_driver_register(&dsps_usbss_driver);
+}
+subsys_initcall(dsps_init);
+
+static void __exit dsps_exit(void)
+{
+ platform_driver_unregister(&dsps_usbss_driver);
+}
+module_exit(dsps_exit);
diff --git a/drivers/usb/otg/gpio_vbus.c b/drivers/usb/otg/gpio_vbus.c
index a0a2178974fe..bde6298a9693 100644
--- a/drivers/usb/otg/gpio_vbus.c
+++ b/drivers/usb/otg/gpio_vbus.c
@@ -37,7 +37,9 @@ struct gpio_vbus_data {
struct regulator *vbus_draw;
int vbus_draw_enabled;
unsigned mA;
- struct work_struct work;
+ struct delayed_work work;
+ int vbus;
+ int irq;
};
@@ -51,8 +53,7 @@ struct gpio_vbus_data {
* edges might be workable.
*/
#define VBUS_IRQ_FLAGS \
- ( IRQF_SAMPLE_RANDOM | IRQF_SHARED \
- | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING )
+ (IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)
/* interface to regulator framework */
@@ -94,20 +95,26 @@ static int is_vbus_powered(struct gpio_vbus_mach_info *pdata)
static void gpio_vbus_work(struct work_struct *work)
{
struct gpio_vbus_data *gpio_vbus =
- container_of(work, struct gpio_vbus_data, work);
+ container_of(work, struct gpio_vbus_data, work.work);
struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data;
- int gpio, status;
+ int gpio, status, vbus;
if (!gpio_vbus->phy.otg->gadget)
return;
+ vbus = is_vbus_powered(pdata);
+ if ((vbus ^ gpio_vbus->vbus) == 0)
+ return;
+ gpio_vbus->vbus = vbus;
+
/* Peripheral controllers which manage the pullup themselves won't have
* gpio_pullup configured here. If it's configured here, we'll do what
* isp1301_omap::b_peripheral() does and enable the pullup here... although
* that may complicate usb_gadget_{,dis}connect() support.
*/
gpio = pdata->gpio_pullup;
- if (is_vbus_powered(pdata)) {
+
+ if (vbus) {
status = USB_EVENT_VBUS;
gpio_vbus->phy.state = OTG_STATE_B_PERIPHERAL;
gpio_vbus->phy.last_event = status;
@@ -152,7 +159,7 @@ static irqreturn_t gpio_vbus_irq(int irq, void *data)
otg->gadget ? otg->gadget->name : "none");
if (otg->gadget)
- schedule_work(&gpio_vbus->work);
+ schedule_delayed_work(&gpio_vbus->work, msecs_to_jiffies(100));
return IRQ_HANDLED;
}
@@ -166,12 +173,11 @@ static int gpio_vbus_set_peripheral(struct usb_otg *otg,
struct gpio_vbus_data *gpio_vbus;
struct gpio_vbus_mach_info *pdata;
struct platform_device *pdev;
- int gpio, irq;
+ int gpio;
gpio_vbus = container_of(otg->phy, struct gpio_vbus_data, phy);
pdev = to_platform_device(gpio_vbus->dev);
pdata = gpio_vbus->dev->platform_data;
- irq = gpio_to_irq(pdata->gpio_vbus);
gpio = pdata->gpio_pullup;
if (!gadget) {
@@ -195,7 +201,8 @@ static int gpio_vbus_set_peripheral(struct usb_otg *otg,
dev_dbg(&pdev->dev, "registered gadget '%s'\n", gadget->name);
/* initialize connection state */
- gpio_vbus_irq(irq, pdev);
+ gpio_vbus->vbus = 0; /* start with disconnected */
+ gpio_vbus_irq(gpio_vbus->irq, pdev);
return 0;
}
@@ -235,6 +242,7 @@ static int __init gpio_vbus_probe(struct platform_device *pdev)
struct gpio_vbus_data *gpio_vbus;
struct resource *res;
int err, gpio, irq;
+ unsigned long irqflags;
if (!pdata || !gpio_is_valid(pdata->gpio_vbus))
return -EINVAL;
@@ -271,10 +279,13 @@ static int __init gpio_vbus_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res) {
irq = res->start;
- res->flags &= IRQF_TRIGGER_MASK;
- res->flags |= IRQF_SAMPLE_RANDOM | IRQF_SHARED;
- } else
+ irqflags = (res->flags & IRQF_TRIGGER_MASK) | IRQF_SHARED;
+ } else {
irq = gpio_to_irq(gpio);
+ irqflags = VBUS_IRQ_FLAGS;
+ }
+
+ gpio_vbus->irq = irq;
/* if data line pullup is in use, initialize it to "not pulling up" */
gpio = pdata->gpio_pullup;
@@ -290,8 +301,7 @@ static int __init gpio_vbus_probe(struct platform_device *pdev)
gpio_direction_output(gpio, pdata->gpio_pullup_inverted);
}
- err = request_irq(irq, gpio_vbus_irq, VBUS_IRQ_FLAGS,
- "vbus_detect", pdev);
+ err = request_irq(irq, gpio_vbus_irq, irqflags, "vbus_detect", pdev);
if (err) {
dev_err(&pdev->dev, "can't request irq %i, err: %d\n",
irq, err);
@@ -300,7 +310,7 @@ static int __init gpio_vbus_probe(struct platform_device *pdev)
ATOMIC_INIT_NOTIFIER_HEAD(&gpio_vbus->phy.notifier);
- INIT_WORK(&gpio_vbus->work, gpio_vbus_work);
+ INIT_DELAYED_WORK(&gpio_vbus->work, gpio_vbus_work);
gpio_vbus->vbus_draw = regulator_get(&pdev->dev, "vbus_draw");
if (IS_ERR(gpio_vbus->vbus_draw)) {
@@ -317,9 +327,12 @@ static int __init gpio_vbus_probe(struct platform_device *pdev)
goto err_otg;
}
+ device_init_wakeup(&pdev->dev, pdata->wakeup);
+
return 0;
err_otg:
- free_irq(irq, &pdev->dev);
+ regulator_put(gpio_vbus->vbus_draw);
+ free_irq(irq, pdev);
err_irq:
if (gpio_is_valid(pdata->gpio_pullup))
gpio_free(pdata->gpio_pullup);
@@ -337,11 +350,13 @@ static int __exit gpio_vbus_remove(struct platform_device *pdev)
struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
int gpio = pdata->gpio_vbus;
+ device_init_wakeup(&pdev->dev, 0);
+ cancel_delayed_work_sync(&gpio_vbus->work);
regulator_put(gpio_vbus->vbus_draw);
usb_set_transceiver(NULL);
- free_irq(gpio_to_irq(gpio), &pdev->dev);
+ free_irq(gpio_vbus->irq, pdev);
if (gpio_is_valid(pdata->gpio_pullup))
gpio_free(pdata->gpio_pullup);
gpio_free(gpio);
@@ -352,6 +367,33 @@ static int __exit gpio_vbus_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
+static int gpio_vbus_pm_suspend(struct device *dev)
+{
+ struct gpio_vbus_data *gpio_vbus = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(gpio_vbus->irq);
+
+ return 0;
+}
+
+static int gpio_vbus_pm_resume(struct device *dev)
+{
+ struct gpio_vbus_data *gpio_vbus = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(gpio_vbus->irq);
+
+ return 0;
+}
+
+static const struct dev_pm_ops gpio_vbus_dev_pm_ops = {
+ .suspend = gpio_vbus_pm_suspend,
+ .resume = gpio_vbus_pm_resume,
+};
+#endif
+
/* NOTE: the gpio-vbus device may *NOT* be hotplugged */
MODULE_ALIAS("platform:gpio-vbus");
@@ -360,6 +402,9 @@ static struct platform_driver gpio_vbus_driver = {
.driver = {
.name = "gpio-vbus",
.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &gpio_vbus_dev_pm_ops,
+#endif
},
.remove = __exit_p(gpio_vbus_remove),
};
diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/otg/twl6030-usb.c
index e3fa387ca81e..d2a9a8e691b9 100644
--- a/drivers/usb/otg/twl6030-usb.c
+++ b/drivers/usb/otg/twl6030-usb.c
@@ -455,7 +455,7 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev)
twl->irq_enabled = true;
status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"twl6030_usb", twl);
if (status < 0) {
dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
@@ -467,7 +467,7 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev)
}
status = request_threaded_irq(twl->irq2, NULL, twl6030_usb_irq,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"twl6030_usb", twl);
if (status < 0) {
dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
new file mode 100644
index 000000000000..3cfabcba7447
--- /dev/null
+++ b/drivers/usb/phy/Kconfig
@@ -0,0 +1,17 @@
+#
+# Physical Layer USB driver configuration
+#
+comment "USB Physical Layer drivers"
+ depends on USB
+
+config USB_ISP1301
+ tristate "NXP ISP1301 USB transceiver support"
+ depends on USB
+ depends on I2C
+ help
+ Say Y here to add support for the NXP ISP1301 USB transceiver driver.
+ This chip is typically used as USB transceiver for USB host, gadget
+ and OTG drivers (to be selected separately).
+
+ To compile this driver as a module, choose M here: the
+ module will be called isp1301.
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
new file mode 100644
index 000000000000..eca095b1a890
--- /dev/null
+++ b/drivers/usb/phy/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for physical layer USB drivers
+#
+
+ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
+
+obj-$(CONFIG_USB_ISP1301) += isp1301.o
diff --git a/drivers/usb/phy/isp1301.c b/drivers/usb/phy/isp1301.c
new file mode 100644
index 000000000000..b19f4932a037
--- /dev/null
+++ b/drivers/usb/phy/isp1301.c
@@ -0,0 +1,77 @@
+/*
+ * NXP ISP1301 USB transceiver driver
+ *
+ * Copyright (C) 2012 Roland Stigge
+ *
+ * Author: Roland Stigge <stigge@antcom.de>
+ *
+ * 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/module.h>
+#include <linux/i2c.h>
+
+#define DRV_NAME "isp1301"
+
+#define ISP1301_I2C_ADDR 0x2C
+
+static const unsigned short normal_i2c[] = {
+ ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END
+};
+
+static const struct i2c_device_id isp1301_id[] = {
+ { "isp1301", 0 },
+ { }
+};
+
+static struct i2c_client *isp1301_i2c_client;
+
+static int isp1301_probe(struct i2c_client *client,
+ const struct i2c_device_id *i2c_id)
+{
+ isp1301_i2c_client = client;
+ return 0;
+}
+
+static int isp1301_remove(struct i2c_client *client)
+{
+ return 0;
+}
+
+static struct i2c_driver isp1301_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ },
+ .probe = isp1301_probe,
+ .remove = isp1301_remove,
+ .id_table = isp1301_id,
+};
+
+module_i2c_driver(isp1301_driver);
+
+static int match(struct device *dev, void *data)
+{
+ struct device_node *node = (struct device_node *)data;
+ return (dev->of_node == node) &&
+ (dev->driver == &isp1301_driver.driver);
+}
+
+struct i2c_client *isp1301_get_client(struct device_node *node)
+{
+ if (node) { /* reference of ISP1301 I2C node via DT */
+ struct device *dev = bus_find_device(&i2c_bus_type, NULL,
+ node, match);
+ if (!dev)
+ return NULL;
+ return to_i2c_client(dev);
+ } else { /* non-DT: only one ISP1301 chip supported */
+ return isp1301_i2c_client;
+ }
+}
+EXPORT_SYMBOL_GPL(isp1301_get_client);
+
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("NXP ISP1301 USB transceiver driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index 00bd2a5e0362..28478ce26c34 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -55,6 +55,7 @@ struct usbhsg_gpriv {
#define USBHSG_STATUS_STARTED (1 << 0)
#define USBHSG_STATUS_REGISTERD (1 << 1)
#define USBHSG_STATUS_WEDGE (1 << 2)
+#define USBHSG_STATUS_SELF_POWERED (1 << 3)
};
struct usbhsg_recip_handle {
@@ -333,7 +334,10 @@ static int usbhsg_recip_handler_std_get_device(struct usbhs_priv *priv,
struct usb_ctrlrequest *ctrl)
{
struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
- unsigned short status = 1 << USB_DEVICE_SELF_POWERED;
+ unsigned short status = 0;
+
+ if (usbhsg_status_has(gpriv, USBHSG_STATUS_SELF_POWERED))
+ status = 1 << USB_DEVICE_SELF_POWERED;
__usbhsg_recip_send_status(gpriv, status);
@@ -879,8 +883,21 @@ static int usbhsg_get_frame(struct usb_gadget *gadget)
return usbhs_frame_get_num(priv);
}
+static int usbhsg_set_selfpowered(struct usb_gadget *gadget, int is_self)
+{
+ struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget);
+
+ if (is_self)
+ usbhsg_status_set(gpriv, USBHSG_STATUS_SELF_POWERED);
+ else
+ usbhsg_status_clr(gpriv, USBHSG_STATUS_SELF_POWERED);
+
+ return 0;
+}
+
static struct usb_gadget_ops usbhsg_gadget_ops = {
.get_frame = usbhsg_get_frame,
+ .set_selfpowered = usbhsg_set_selfpowered,
.udc_start = usbhsg_gadget_start,
.udc_stop = usbhsg_gadget_stop,
};
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 7141d6599060..325d2910f9f9 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -669,6 +669,15 @@ config USB_SERIAL_SSU100
To compile this driver as a module, choose M here: the
module will be called ssu100.
+config USB_SERIAL_QT2
+ tristate "USB Quatech Serial Driver for USB 2 devices"
+ help
+ Say Y here if you want to use the Quatech USB 2
+ serial adapters.
+
+ To compile this driver as a module, choose M here: the
+ module will be called quatech-serial.
+
config USB_SERIAL_DEBUG
tristate "USB Debugging Device"
help
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 07f198ee0486..1dc483a8bfc7 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_USB_SERIAL_OTI6858) += oti6858.o
obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o
obj-$(CONFIG_USB_SERIAL_QCAUX) += qcaux.o
obj-$(CONFIG_USB_SERIAL_QUALCOMM) += qcserial.o
+obj-$(CONFIG_USB_SERIAL_QT2) += quatech2.o
obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o
obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI) += siemens_mpi.o
obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index eec4fb9a35c1..d634e6635632 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -111,13 +111,14 @@ static int aircable_probe(struct usb_serial *serial,
for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
endpoint = &iface_desc->endpoint[i].desc;
if (usb_endpoint_is_bulk_out(endpoint)) {
- dbg("found bulk out on endpoint %d", i);
+ dev_dbg(&serial->dev->dev,
+ "found bulk out on endpoint %d\n", i);
++num_bulk_out;
}
}
if (num_bulk_out == 0) {
- dbg("Invalid interface, discarding");
+ dev_dbg(&serial->dev->dev, "Invalid interface, discarding\n");
return -ENODEV;
}
@@ -133,7 +134,7 @@ static int aircable_process_packet(struct tty_struct *tty,
packet += HCI_HEADER_LENGTH;
}
if (len <= 0) {
- dbg("%s - malformed packet", __func__);
+ dev_dbg(&port->dev, "%s - malformed packet\n", __func__);
return 0;
}
@@ -170,13 +171,6 @@ static void aircable_process_read_urb(struct urb *urb)
tty_kref_put(tty);
}
-static struct usb_driver aircable_driver = {
- .name = "aircable",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver aircable_device = {
.driver = {
.owner = THIS_MODULE,
@@ -196,7 +190,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&aircable_device, NULL
};
-module_usb_serial_driver(aircable_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index f99f47100dd8..f8ce97d8b0ad 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -265,7 +265,7 @@ static void ark3116_set_termios(struct tty_struct *tty,
hcr = (cflag & CRTSCTS) ? 0x03 : 0x00;
/* calc baudrate */
- dbg("%s - setting bps to %d", __func__, bps);
+ dev_dbg(&port->dev, "%s - setting bps to %d\n", __func__, bps);
eval = 0;
switch (bps) {
case 0:
@@ -292,8 +292,8 @@ static void ark3116_set_termios(struct tty_struct *tty,
/* keep old LCR_SBC bit */
lcr |= (priv->lcr & UART_LCR_SBC);
- dbg("%s - setting hcr:0x%02x,lcr:0x%02x,quot:%d",
- __func__, hcr, lcr, quot);
+ dev_dbg(&port->dev, "%s - setting hcr:0x%02x,lcr:0x%02x,quot:%d\n",
+ __func__, hcr, lcr, quot);
/* handshake control */
if (priv->hcr != hcr) {
@@ -375,8 +375,9 @@ static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port)
result = usb_serial_generic_open(tty, port);
if (result) {
- dbg("%s - usb_serial_generic_open failed: %d",
- __func__, result);
+ dev_dbg(&port->dev,
+ "%s - usb_serial_generic_open failed: %d\n",
+ __func__, result);
goto err_out;
}
@@ -622,24 +623,26 @@ static void ark3116_read_int_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __func__, status);
+ dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
+ __func__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d",
- __func__, status);
+ dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
+ __func__, status);
break;
case 0: /* success */
/* discovered this by trail and error... */
if ((urb->actual_length == 4) && (data[0] == 0xe8)) {
const __u8 id = data[1]&UART_IIR_ID;
- dbg("%s: iir=%02x", __func__, data[1]);
+ dev_dbg(&port->dev, "%s: iir=%02x\n", __func__, data[1]);
if (id == UART_IIR_MSI) {
- dbg("%s: msr=%02x", __func__, data[3]);
+ dev_dbg(&port->dev, "%s: msr=%02x\n",
+ __func__, data[3]);
ark3116_update_msr(port, data[3]);
break;
} else if (id == UART_IIR_RLSI) {
- dbg("%s: lsr=%02x", __func__, data[2]);
+ dev_dbg(&port->dev, "%s: lsr=%02x\n",
+ __func__, data[2]);
ark3116_update_lsr(port, data[2]);
break;
}
@@ -714,13 +717,6 @@ static void ark3116_process_read_urb(struct urb *urb)
tty_kref_put(tty);
}
-static struct usb_driver ark3116_driver = {
- .name = "ark3116",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver ark3116_device = {
.driver = {
.owner = THIS_MODULE,
@@ -747,7 +743,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&ark3116_device, NULL
};
-module_usb_serial_driver(ark3116_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index a52e0d2cec31..6b7365632951 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -2,17 +2,17 @@
* Belkin USB Serial Adapter Driver
*
* Copyright (C) 2000 William Greathouse (wgreathouse@smva.com)
- * Copyright (C) 2000-2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2000-2001 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (C) 2010 Johan Hovold (jhovold@gmail.com)
*
* This program is largely derived from work by the linux-usb group
* and associated source files. Please see the usb/serial files for
* individual credits and copyrights.
*
- * 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 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.
*
* See Documentation/usb/usb-serial.txt for more information on using this
* driver
@@ -62,7 +62,7 @@ static int belkin_sa_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
-static const struct usb_device_id id_table_combined[] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(BELKIN_SA_VID, BELKIN_SA_PID) },
{ USB_DEVICE(BELKIN_OLD_VID, BELKIN_OLD_PID) },
{ USB_DEVICE(PERACOM_VID, PERACOM_PID) },
@@ -71,14 +71,7 @@ static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(BELKIN_DOCKSTATION_VID, BELKIN_DOCKSTATION_PID) },
{ } /* Terminating entry */
};
-MODULE_DEVICE_TABLE(usb, id_table_combined);
-
-static struct usb_driver belkin_driver = {
- .name = "belkin",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table_combined,
-};
+MODULE_DEVICE_TABLE(usb, id_table);
/* All of the device info needed for the serial converters */
static struct usb_serial_driver belkin_device = {
@@ -87,7 +80,7 @@ static struct usb_serial_driver belkin_device = {
.name = "belkin",
},
.description = "Belkin / Peracom / GoHubs USB Serial Adapter",
- .id_table = id_table_combined,
+ .id_table = id_table,
.num_ports = 1,
.open = belkin_sa_open,
.close = belkin_sa_close,
@@ -159,8 +152,6 @@ static void belkin_sa_release(struct usb_serial *serial)
{
int i;
- dbg("%s", __func__);
-
for (i = 0; i < serial->num_ports; ++i)
kfree(usb_get_serial_port_data(serial->port[i]));
}
@@ -170,8 +161,6 @@ static int belkin_sa_open(struct tty_struct *tty,
{
int retval;
- dbg("%s port %d", __func__, port->number);
-
retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (retval) {
dev_err(&port->dev, "usb_submit_urb(read int) failed\n");
@@ -187,8 +176,6 @@ static int belkin_sa_open(struct tty_struct *tty,
static void belkin_sa_close(struct usb_serial_port *port)
{
- dbg("%s port %d", __func__, port->number);
-
usb_serial_generic_close(port);
usb_kill_urb(port->interrupt_in_urb);
}
@@ -210,12 +197,12 @@ static void belkin_sa_read_int_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __func__, status);
+ dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
+ __func__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d",
- __func__, status);
+ dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
+ __func__, status);
goto exit;
}
@@ -403,7 +390,9 @@ static void belkin_sa_set_termios(struct tty_struct *tty,
case CS8:
urb_value = BELKIN_SA_DATA_BITS(8);
break;
- default: dbg("CSIZE was not CS5-CS8, using default of 8");
+ default:
+ dev_dbg(&port->dev,
+ "CSIZE was not CS5-CS8, using default of 8\n");
urb_value = BELKIN_SA_DATA_BITS(8);
break;
}
@@ -463,8 +452,6 @@ static int belkin_sa_tiocmget(struct tty_struct *tty)
unsigned long control_state;
unsigned long flags;
- dbg("%s", __func__);
-
spin_lock_irqsave(&priv->lock, flags);
control_state = priv->control_state;
spin_unlock_irqrestore(&priv->lock, flags);
@@ -484,8 +471,6 @@ static int belkin_sa_tiocmset(struct tty_struct *tty,
int rts = 0;
int dtr = 0;
- dbg("%s", __func__);
-
spin_lock_irqsave(&priv->lock, flags);
control_state = priv->control_state;
@@ -524,7 +509,7 @@ exit:
return retval;
}
-module_usb_serial_driver(belkin_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index ed8adb052ca7..f398d1e34474 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -124,8 +124,15 @@ static ssize_t store_new_id(struct device_driver *driver,
return retval;
}
+static ssize_t show_dynids(struct device_driver *driver, char *buf)
+{
+ struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
+
+ return usb_show_dynids(&usb_drv->dynids, buf);
+}
+
static struct driver_attribute drv_attrs[] = {
- __ATTR(new_id, S_IWUSR, NULL, store_new_id),
+ __ATTR(new_id, S_IRUGO | S_IWUSR, show_dynids, store_new_id),
__ATTR_NULL,
};
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index aaab32db31d0..cabd1b15ddce 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -125,8 +125,6 @@ static int ch341_set_baudrate(struct usb_device *dev,
unsigned long factor;
short divisor;
- dbg("ch341_set_baudrate(%d)", priv->baud_rate);
-
if (!priv->baud_rate)
return -EINVAL;
factor = (CH341_BAUDBASE_FACTOR / priv->baud_rate);
@@ -153,7 +151,6 @@ static int ch341_set_baudrate(struct usb_device *dev,
static int ch341_set_handshake(struct usb_device *dev, u8 control)
{
- dbg("ch341_set_handshake(0x%02x)", control);
return ch341_control_out(dev, 0xa4, ~control, 0);
}
@@ -164,8 +161,6 @@ static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
const unsigned size = 8;
unsigned long flags;
- dbg("ch341_get_status()");
-
buffer = kmalloc(size, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
@@ -196,8 +191,6 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
int r;
const unsigned size = 8;
- dbg("ch341_configure()");
-
buffer = kmalloc(size, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
@@ -254,8 +247,6 @@ static int ch341_attach(struct usb_serial *serial)
struct ch341_private *priv;
int r;
- dbg("ch341_attach()");
-
/* private data */
priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL);
if (!priv)
@@ -290,7 +281,6 @@ static void ch341_dtr_rts(struct usb_serial_port *port, int on)
struct ch341_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
/* drop DTR and RTS */
spin_lock_irqsave(&priv->lock, flags);
if (on)
@@ -304,8 +294,6 @@ static void ch341_dtr_rts(struct usb_serial_port *port, int on)
static void ch341_close(struct usb_serial_port *port)
{
- dbg("%s - port %d", __func__, port->number);
-
usb_serial_generic_close(port);
usb_kill_urb(port->interrupt_in_urb);
}
@@ -318,8 +306,6 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)
struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]);
int r;
- dbg("ch341_open()");
-
priv->baud_rate = DEFAULT_BAUD_RATE;
r = ch341_configure(serial->dev, priv);
@@ -358,8 +344,6 @@ static void ch341_set_termios(struct tty_struct *tty,
unsigned baud_rate;
unsigned long flags;
- dbg("ch341_set_termios()");
-
baud_rate = tty_get_baud_rate(tty);
priv->baud_rate = baud_rate;
@@ -393,8 +377,6 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state)
uint16_t reg_contents;
uint8_t *break_reg;
- dbg("%s()", __func__);
-
break_reg = kmalloc(2, GFP_KERNEL);
if (!break_reg) {
dev_err(&port->dev, "%s - kmalloc failed\n", __func__);
@@ -461,8 +443,6 @@ static void ch341_read_int_callback(struct urb *urb)
unsigned int actual_length = urb->actual_length;
int status;
- dbg("%s (%d)", __func__, port->number);
-
switch (urb->status) {
case 0:
/* success */
@@ -580,8 +560,6 @@ static int ch341_tiocmget(struct tty_struct *tty)
u8 status;
unsigned int result;
- dbg("%s (%d)", __func__, port->number);
-
spin_lock_irqsave(&priv->lock, flags);
mcr = priv->line_control;
status = priv->line_status;
@@ -599,35 +577,18 @@ static int ch341_tiocmget(struct tty_struct *tty)
return result;
}
-
-static int ch341_reset_resume(struct usb_interface *intf)
+static int ch341_reset_resume(struct usb_serial *serial)
{
- struct usb_device *dev = interface_to_usbdev(intf);
- struct usb_serial *serial = NULL;
struct ch341_private *priv;
- serial = usb_get_intfdata(intf);
priv = usb_get_serial_port_data(serial->port[0]);
- /*reconfigure ch341 serial port after bus-reset*/
- ch341_configure(dev, priv);
-
- usb_serial_resume(intf);
+ /* reconfigure ch341 serial port after bus-reset */
+ ch341_configure(serial->dev, priv);
return 0;
}
-static struct usb_driver ch341_driver = {
- .name = "ch341",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .suspend = usb_serial_suspend,
- .resume = usb_serial_resume,
- .reset_resume = ch341_reset_resume,
- .id_table = id_table,
- .supports_autosuspend = 1,
-};
-
static struct usb_serial_driver ch341_device = {
.driver = {
.owner = THIS_MODULE,
@@ -646,13 +607,14 @@ static struct usb_serial_driver ch341_device = {
.tiocmset = ch341_tiocmset,
.read_int_callback = ch341_read_int_callback,
.attach = ch341_attach,
+ .reset_resume = ch341_reset_resume,
};
static struct usb_serial_driver * const serial_drivers[] = {
&ch341_device, NULL
};
-module_usb_serial_driver(ch341_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index 1ee6b2ab0f89..b9cca6dcde07 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -113,7 +113,8 @@ static int usb_console_setup(struct console *co, char *options)
serial = usb_serial_get_by_index(co->index);
if (serial == NULL) {
/* no device is connected yet, sorry :( */
- err("No USB device connected to ttyUSB%i", co->index);
+ printk(KERN_ERR "No USB device connected to ttyUSB%i\n",
+ co->index);
return -ENODEV;
}
@@ -137,7 +138,7 @@ static int usb_console_setup(struct console *co, char *options)
tty = kzalloc(sizeof(*tty), GFP_KERNEL);
if (!tty) {
retval = -ENOMEM;
- err("no more memory");
+ dev_err(&port->dev, "no more memory\n");
goto reset_open_count;
}
kref_init(&tty->kref);
@@ -146,7 +147,7 @@ static int usb_console_setup(struct console *co, char *options)
tty->index = co->index;
if (tty_init_termios(tty)) {
retval = -ENOMEM;
- err("no more memory");
+ dev_err(&port->dev, "no more memory\n");
goto free_tty;
}
}
@@ -159,7 +160,7 @@ static int usb_console_setup(struct console *co, char *options)
retval = usb_serial_generic_open(NULL, port);
if (retval) {
- err("could not open USB console port");
+ dev_err(&port->dev, "could not open USB console port\n");
goto fail;
}
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index ec30f95ef399..1b1926200ba7 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -156,13 +156,6 @@ struct cp210x_port_private {
__u8 bInterfaceNumber;
};
-static struct usb_driver cp210x_driver = {
- .name = "cp210x",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver cp210x_device = {
.driver = {
.owner = THIS_MODULE,
@@ -188,8 +181,10 @@ static struct usb_serial_driver * const serial_drivers[] = {
};
/* Config request types */
-#define REQTYPE_HOST_TO_DEVICE 0x41
-#define REQTYPE_DEVICE_TO_HOST 0xc1
+#define REQTYPE_HOST_TO_INTERFACE 0x41
+#define REQTYPE_INTERFACE_TO_HOST 0xc1
+#define REQTYPE_HOST_TO_DEVICE 0x40
+#define REQTYPE_DEVICE_TO_HOST 0xc0
/* Config request codes */
#define CP210X_IFC_ENABLE 0x00
@@ -286,7 +281,7 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request,
/* Issue the request, attempting to read 'size' bytes */
result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
- request, REQTYPE_DEVICE_TO_HOST, 0x0000,
+ request, REQTYPE_INTERFACE_TO_HOST, 0x0000,
port_priv->bInterfaceNumber, buf, size,
USB_CTRL_GET_TIMEOUT);
@@ -340,13 +335,13 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request,
if (size > 2) {
result = usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
- request, REQTYPE_HOST_TO_DEVICE, 0x0000,
+ request, REQTYPE_HOST_TO_INTERFACE, 0x0000,
port_priv->bInterfaceNumber, buf, size,
USB_CTRL_SET_TIMEOUT);
} else {
result = usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
- request, REQTYPE_HOST_TO_DEVICE, data[0],
+ request, REQTYPE_HOST_TO_INTERFACE, data[0],
port_priv->bInterfaceNumber, NULL, 0,
USB_CTRL_SET_TIMEOUT);
}
@@ -422,8 +417,6 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
{
int result;
- dbg("%s - port %d", __func__, port->number);
-
result = cp210x_set_config_single(port, CP210X_IFC_ENABLE,
UART_ENABLE);
if (result) {
@@ -443,8 +436,6 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
static void cp210x_close(struct usb_serial_port *port)
{
- dbg("%s - port %d", __func__, port->number);
-
usb_serial_generic_close(port);
mutex_lock(&port->serial->disc_mutex);
@@ -488,8 +479,6 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,
unsigned int baud;
unsigned int bits;
- dbg("%s - port %d", __func__, port->number);
-
cp210x_get_config(port, CP210X_GET_BAUDRATE, &baud, 4);
dbg("%s - baud rate = %d", __func__, baud);
@@ -787,8 +776,6 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port,
{
unsigned int control = 0;
- dbg("%s - port %d", __func__, port->number);
-
if (set & TIOCM_RTS) {
control |= CONTROL_RTS;
control |= CONTROL_WRITE_RTS;
@@ -825,8 +812,6 @@ static int cp210x_tiocmget (struct tty_struct *tty)
unsigned int control;
int result;
- dbg("%s - port %d", __func__, port->number);
-
cp210x_get_config(port, CP210X_GET_MDMSTS, &control, 1);
result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0)
@@ -846,7 +831,6 @@ static void cp210x_break_ctl (struct tty_struct *tty, int break_state)
struct usb_serial_port *port = tty->driver_data;
unsigned int state;
- dbg("%s - port %d", __func__, port->number);
if (break_state == 0)
state = BREAK_OFF;
else
@@ -891,7 +875,7 @@ static void cp210x_release(struct usb_serial *serial)
}
}
-module_usb_serial_driver(cp210x_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index d39b9418f2fb..3aa0b530f68e 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -77,13 +77,6 @@ static const struct usb_device_id id_table[] = {
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver cyberjack_driver = {
- .name = "cyberjack",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver cyberjack_device = {
.driver = {
.owner = THIS_MODULE,
@@ -122,8 +115,6 @@ static int cyberjack_startup(struct usb_serial *serial)
struct cyberjack_private *priv;
int i;
- dbg("%s", __func__);
-
/* allocate the private data structure */
priv = kmalloc(sizeof(struct cyberjack_private), GFP_KERNEL);
if (!priv)
@@ -155,8 +146,6 @@ static void cyberjack_disconnect(struct usb_serial *serial)
{
int i;
- dbg("%s", __func__);
-
for (i = 0; i < serial->num_ports; ++i)
usb_kill_urb(serial->port[i]->interrupt_in_urb);
}
@@ -165,8 +154,6 @@ static void cyberjack_release(struct usb_serial *serial)
{
int i;
- dbg("%s", __func__);
-
for (i = 0; i < serial->num_ports; ++i) {
/* My special items, the standard routines free my urbs */
kfree(usb_get_serial_port_data(serial->port[i]));
@@ -180,8 +167,6 @@ static int cyberjack_open(struct tty_struct *tty,
unsigned long flags;
int result = 0;
- dbg("%s - port %d", __func__, port->number);
-
dbg("%s - usb_clear_halt", __func__);
usb_clear_halt(port->serial->dev, port->write_urb->pipe);
@@ -197,8 +182,6 @@ static int cyberjack_open(struct tty_struct *tty,
static void cyberjack_close(struct usb_serial_port *port)
{
- dbg("%s - port %d", __func__, port->number);
-
if (port->serial->dev) {
/* shutdown any bulk reads that might be going on */
usb_kill_urb(port->write_urb);
@@ -214,8 +197,6 @@ static int cyberjack_write(struct tty_struct *tty,
int result;
int wrexpected;
- dbg("%s - port %d", __func__, port->number);
-
if (count == 0) {
dbg("%s - write request of 0 bytes", __func__);
return 0;
@@ -307,8 +288,6 @@ static void cyberjack_read_int_callback(struct urb *urb)
int status = urb->status;
int result;
- dbg("%s - port %d", __func__, port->number);
-
/* the urb might have been killed. */
if (status)
return;
@@ -367,8 +346,6 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
int result;
int status = urb->status;
- dbg("%s - port %d", __func__, port->number);
-
usb_serial_debug_data(debug, &port->dev, __func__,
urb->actual_length, data);
if (status) {
@@ -417,8 +394,6 @@ static void cyberjack_write_bulk_callback(struct urb *urb)
struct cyberjack_private *priv = usb_get_serial_port_data(port);
int status = urb->status;
- dbg("%s - port %d", __func__, port->number);
-
set_bit(0, &port->write_urbs_free);
if (status) {
dbg("%s - nonzero write bulk status received: %d",
@@ -475,7 +450,7 @@ exit:
usb_serial_port_softint(port);
}
-module_usb_serial_driver(cyberjack_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index afc886c75d2f..b78c34eb5d3f 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -89,13 +89,6 @@ static const struct usb_device_id id_table_combined[] = {
MODULE_DEVICE_TABLE(usb, id_table_combined);
-static struct usb_driver cypress_driver = {
- .name = "cypress",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table_combined,
-};
-
enum packet_format {
packet_format_1, /* b0:status, b1:payload count */
packet_format_2 /* b0[7:3]:status, b0[2:0]:payload count */
@@ -305,8 +298,6 @@ static int cypress_serial_control(struct tty_struct *tty,
const unsigned int feature_len = 5;
unsigned long flags;
- dbg("%s", __func__);
-
priv = usb_get_serial_port_data(port);
if (!priv->comm_is_ok)
@@ -451,8 +442,6 @@ static int generic_startup(struct usb_serial *serial)
struct cypress_private *priv;
struct usb_serial_port *port = serial->port[0];
- dbg("%s - port %d", __func__, port->number);
-
priv = kzalloc(sizeof(struct cypress_private), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -505,8 +494,6 @@ static int cypress_earthmate_startup(struct usb_serial *serial)
struct cypress_private *priv;
struct usb_serial_port *port = serial->port[0];
- dbg("%s", __func__);
-
if (generic_startup(serial)) {
dbg("%s - Failed setting up port %d", __func__,
port->number);
@@ -537,8 +524,6 @@ static int cypress_hidcom_startup(struct usb_serial *serial)
{
struct cypress_private *priv;
- dbg("%s", __func__);
-
if (generic_startup(serial)) {
dbg("%s - Failed setting up port %d", __func__,
serial->port[0]->number);
@@ -556,8 +541,6 @@ static int cypress_ca42v2_startup(struct usb_serial *serial)
{
struct cypress_private *priv;
- dbg("%s", __func__);
-
if (generic_startup(serial)) {
dbg("%s - Failed setting up port %d", __func__,
serial->port[0]->number);
@@ -575,10 +558,7 @@ static void cypress_release(struct usb_serial *serial)
{
struct cypress_private *priv;
- dbg("%s - port %d", __func__, serial->port[0]->number);
-
/* all open ports are closed at this point */
-
priv = usb_get_serial_port_data(serial->port[0]);
if (priv) {
@@ -595,8 +575,6 @@ static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port)
unsigned long flags;
int result = 0;
- dbg("%s - port %d", __func__, port->number);
-
if (!priv->comm_is_ok)
return -EIO;
@@ -661,8 +639,6 @@ static void cypress_close(struct usb_serial_port *port)
struct cypress_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
/* writing is potentially harmful, lock must be taken */
mutex_lock(&port->serial->disc_mutex);
if (port->serial->disconnected) {
@@ -720,7 +696,6 @@ static void cypress_send(struct usb_serial_port *port)
if (!priv->comm_is_ok)
return;
- dbg("%s - port %d", __func__, port->number);
dbg("%s - interrupt out size is %d", __func__,
port->interrupt_out_size);
@@ -828,8 +803,6 @@ static int cypress_write_room(struct tty_struct *tty)
int room = 0;
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irqsave(&priv->lock, flags);
room = kfifo_avail(&priv->write_fifo);
spin_unlock_irqrestore(&priv->lock, flags);
@@ -847,8 +820,6 @@ static int cypress_tiocmget(struct tty_struct *tty)
unsigned int result = 0;
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irqsave(&priv->lock, flags);
control = priv->line_control;
status = priv->current_status;
@@ -874,8 +845,6 @@ static int cypress_tiocmset(struct tty_struct *tty,
struct cypress_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irqsave(&priv->lock, flags);
if (set & TIOCM_RTS)
priv->line_control |= CONTROL_RTS;
@@ -948,8 +917,6 @@ static void cypress_set_termios(struct tty_struct *tty,
__u8 oldlines;
int linechange = 0;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irqsave(&priv->lock, flags);
/* We can't clean this one up as we don't know the device type
early enough */
@@ -1096,8 +1063,6 @@ static int cypress_chars_in_buffer(struct tty_struct *tty)
int chars = 0;
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irqsave(&priv->lock, flags);
chars = kfifo_len(&priv->write_fifo);
spin_unlock_irqrestore(&priv->lock, flags);
@@ -1112,8 +1077,6 @@ static void cypress_throttle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
struct cypress_private *priv = usb_get_serial_port_data(port);
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irq(&priv->lock);
priv->rx_flags = THROTTLED;
spin_unlock_irq(&priv->lock);
@@ -1126,8 +1089,6 @@ static void cypress_unthrottle(struct tty_struct *tty)
struct cypress_private *priv = usb_get_serial_port_data(port);
int actually_throttled, result;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irq(&priv->lock);
actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
priv->rx_flags = 0;
@@ -1161,8 +1122,6 @@ static void cypress_read_int_callback(struct urb *urb)
int i = 0;
int status = urb->status;
- dbg("%s - port %d", __func__, port->number);
-
switch (status) {
case 0: /* success */
break;
@@ -1303,8 +1262,6 @@ static void cypress_write_int_callback(struct urb *urb)
int result;
int status = urb->status;
- dbg("%s - port %d", __func__, port->number);
-
switch (status) {
case 0:
/* success */
@@ -1346,7 +1303,7 @@ static void cypress_write_int_callback(struct urb *urb)
cypress_send(port);
}
-module_usb_serial_driver(cypress_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table_combined);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 999f91bf70de..b5cd838093ef 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -271,14 +271,6 @@ static const struct usb_device_id id_table_4[] = {
MODULE_DEVICE_TABLE(usb, id_table_combined);
-static struct usb_driver digi_driver = {
- .name = "digi_acceleport",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table_combined,
-};
-
-
/* device info needed for the Digi serial converter */
static struct usb_serial_driver digi_acceleport_2_device = {
@@ -657,9 +649,6 @@ static void digi_rx_throttle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
struct digi_port *priv = usb_get_serial_port_data(port);
-
- dbg("digi_rx_throttle: TOP: port=%d", priv->dp_port_num);
-
/* stop receiving characters by not resubmitting the read urb */
spin_lock_irqsave(&priv->dp_port_lock, flags);
priv->dp_throttled = 1;
@@ -675,8 +664,6 @@ static void digi_rx_unthrottle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
struct digi_port *priv = usb_get_serial_port_data(port);
- dbg("digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num);
-
spin_lock_irqsave(&priv->dp_port_lock, flags);
/* restart read chain */
@@ -904,8 +891,6 @@ static int digi_tiocmget(struct tty_struct *tty)
unsigned int val;
unsigned long flags;
- dbg("%s: TOP: port=%d", __func__, priv->dp_port_num);
-
spin_lock_irqsave(&priv->dp_port_lock, flags);
val = priv->dp_modem_signals;
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
@@ -921,8 +906,6 @@ static int digi_tiocmset(struct tty_struct *tty,
unsigned int val;
unsigned long flags;
- dbg("%s: TOP: port=%d", __func__, priv->dp_port_num);
-
spin_lock_irqsave(&priv->dp_port_lock, flags);
val = (priv->dp_modem_signals & ~clear) | set;
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
@@ -1013,8 +996,6 @@ static void digi_write_bulk_callback(struct urb *urb)
int ret = 0;
int status = urb->status;
- dbg("digi_write_bulk_callback: TOP, status=%d", status);
-
/* port and serial sanity check */
if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) {
pr_err("%s: port or port->private is NULL, status=%d\n",
@@ -1121,8 +1102,6 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port)
struct digi_port *priv = usb_get_serial_port_data(port);
struct ktermios not_termios;
- dbg("digi_open: TOP: port=%d", priv->dp_port_num);
-
/* be sure the device is started up */
if (digi_startup_device(port->serial) != 0)
return -ENXIO;
@@ -1160,8 +1139,6 @@ static void digi_close(struct usb_serial_port *port)
unsigned char buf[32];
struct digi_port *priv = usb_get_serial_port_data(port);
- dbg("digi_close: TOP: port=%d", priv->dp_port_num);
-
mutex_lock(&port->serial->disc_mutex);
/* if disconnected, just clear flags */
if (port->serial->disconnected)
@@ -1220,7 +1197,6 @@ exit:
wake_up_interruptible(&priv->dp_close_wait);
spin_unlock_irq(&priv->dp_port_lock);
mutex_unlock(&port->serial->disc_mutex);
- dbg("digi_close: done");
}
@@ -1269,8 +1245,6 @@ static int digi_startup(struct usb_serial *serial)
struct digi_port *priv;
struct digi_serial *serial_priv;
- dbg("digi_startup: TOP");
-
/* allocate the private data structures for all ports */
/* number of regular ports + 1 for the out-of-band port */
for (i = 0; i < serial->type->num_ports + 1; i++) {
@@ -1325,7 +1299,6 @@ static int digi_startup(struct usb_serial *serial)
static void digi_disconnect(struct usb_serial *serial)
{
int i;
- dbg("digi_disconnect: TOP, in_interrupt()=%ld", in_interrupt());
/* stop reads and writes on all ports */
for (i = 0; i < serial->type->num_ports + 1; i++) {
@@ -1338,7 +1311,6 @@ static void digi_disconnect(struct usb_serial *serial)
static void digi_release(struct usb_serial *serial)
{
int i;
- dbg("digi_release: TOP, in_interrupt()=%ld", in_interrupt());
/* free the private data structures for all ports */
/* number of regular ports + 1 for the out-of-band port */
@@ -1356,8 +1328,6 @@ static void digi_read_bulk_callback(struct urb *urb)
int ret;
int status = urb->status;
- dbg("digi_read_bulk_callback: TOP");
-
/* port sanity check, do not resubmit if port is not valid */
if (port == NULL)
return;
@@ -1507,9 +1477,6 @@ static int digi_read_oob_callback(struct urb *urb)
int i;
unsigned int rts;
- dbg("digi_read_oob_callback: port=%d, len=%d",
- priv->dp_port_num, urb->actual_length);
-
/* handle each oob command */
for (i = 0; i < urb->actual_length - 3;) {
opcode = ((unsigned char *)urb->transfer_buffer)[i++];
@@ -1580,7 +1547,7 @@ static int digi_read_oob_callback(struct urb *urb)
}
-module_usb_serial_driver(digi_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table_combined);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index 5b99fc09e327..cdf61dd07318 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -51,13 +51,6 @@ static const struct usb_device_id id_table[] = {
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver empeg_driver = {
- .name = "empeg",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver empeg_device = {
.driver = {
.owner = THIS_MODULE,
@@ -80,14 +73,12 @@ static int empeg_startup(struct usb_serial *serial)
{
int r;
- dbg("%s", __func__);
-
if (serial->dev->actconfig->desc.bConfigurationValue != 1) {
dev_err(&serial->dev->dev, "active config #%d != 1 ??\n",
serial->dev->actconfig->desc.bConfigurationValue);
return -ENODEV;
}
- dbg("%s - reset config", __func__);
+
r = usb_reset_configuration(serial->dev);
/* continue on with initialization */
@@ -138,7 +129,7 @@ static void empeg_init_termios(struct tty_struct *tty)
tty_encode_baud_rate(tty, 115200, 115200);
}
-module_usb_serial_driver(empeg_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/ezusb.c b/drivers/usb/serial/ezusb.c
index 3cfc762f5056..800e8eb60003 100644
--- a/drivers/usb/serial/ezusb.c
+++ b/drivers/usb/serial/ezusb.c
@@ -26,7 +26,6 @@ int ezusb_writememory(struct usb_serial *serial, int address,
int result;
unsigned char *transfer_buffer;
- /* dbg("ezusb_writememory %x, %d", address, length); */
if (!serial->dev) {
printk(KERN_ERR "ezusb: %s - no physical device present, "
"failing.\n", __func__);
@@ -50,7 +49,6 @@ int ezusb_set_reset(struct usb_serial *serial, unsigned char reset_bit)
{
int response;
- /* dbg("%s - %d", __func__, reset_bit); */
response = ezusb_writememory(serial, CPUCS_REG, &reset_bit, 1, 0xa0);
if (response < 0)
dev_err(&serial->dev->dev, "%s- %d failed\n",
diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
index 88c0b1963920..499b15fd82f1 100644
--- a/drivers/usb/serial/f81232.c
+++ b/drivers/usb/serial/f81232.c
@@ -68,8 +68,6 @@ static void f81232_read_int_callback(struct urb *urb)
int status = urb->status;
int retval;
- dbg("%s (%d)", __func__, port->number);
-
switch (status) {
case 0:
/* success */
@@ -78,12 +76,12 @@ static void f81232_read_int_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __func__,
- status);
+ dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
+ __func__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __func__,
- status);
+ dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
+ __func__, status);
goto exit;
}
@@ -133,7 +131,7 @@ static void f81232_process_read_urb(struct urb *urb)
tty_flag = TTY_PARITY;
else if (line_status & UART_FRAME_ERROR)
tty_flag = TTY_FRAME;
- dbg("%s - tty_flag = %d", __func__, tty_flag);
+ dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag);
/* overrun is special, not associated with a char */
if (line_status & UART_OVERRUN_ERROR)
@@ -203,7 +201,6 @@ static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port)
if (tty)
f81232_set_termios(tty, port, &tmp_termios);
- dbg("%s - submitting interrupt urb", __func__);
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result) {
dev_err(&port->dev, "%s - failed submitting interrupt urb,"
@@ -293,7 +290,9 @@ static int f81232_ioctl(struct tty_struct *tty,
{
struct serial_struct ser;
struct usb_serial_port *port = tty->driver_data;
- dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
+
+ dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__,
+ port->number, cmd);
switch (cmd) {
case TIOCGSERIAL:
@@ -309,10 +308,12 @@ static int f81232_ioctl(struct tty_struct *tty,
return 0;
case TIOCMIWAIT:
- dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
+ dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__,
+ port->number);
return wait_modem_info(port, arg);
default:
- dbg("%s not supported = 0x%04x", __func__, cmd);
+ dev_dbg(&port->dev, "%s not supported = 0x%04x\n",
+ __func__, cmd);
break;
}
return -ENOIOCTLCMD;
@@ -353,24 +354,12 @@ static void f81232_release(struct usb_serial *serial)
}
}
-static struct usb_driver f81232_driver = {
- .name = "f81232",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
- .suspend = usb_serial_suspend,
- .resume = usb_serial_resume,
- .no_dynamic_id = 1,
- .supports_autosuspend = 1,
-};
-
static struct usb_serial_driver f81232_device = {
.driver = {
.owner = THIS_MODULE,
.name = "f81232",
},
.id_table = id_table,
- .usb_driver = &f81232_driver,
.num_ports = 1,
.bulk_in_size = 256,
.bulk_out_size = 256,
@@ -394,7 +383,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
NULL,
};
-module_usb_serial_driver(f81232_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver");
MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org");
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 02e7f2d32d52..8c084ea34e26 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -809,6 +809,7 @@ static struct usb_device_id id_table_combined [] = {
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) },
{ USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) },
+ { USB_DEVICE(PI_VID, PI_E861_PID) },
{ USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) },
{ USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
@@ -861,13 +862,6 @@ static struct usb_device_id id_table_combined [] = {
MODULE_DEVICE_TABLE(usb, id_table_combined);
-static struct usb_driver ftdi_driver = {
- .name = "ftdi_sio",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table_combined,
-};
-
static const char *ftdi_chip_name[] = {
[SIO] = "SIO", /* the serial part of FT8U100AX */
[FT8U232AM] = "FT8U232AM",
@@ -1285,8 +1279,6 @@ static int read_latency_timer(struct usb_serial_port *port)
unsigned char *buf;
int rv;
- dbg("%s", __func__);
-
buf = kmalloc(1, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -1593,8 +1585,6 @@ static int create_sysfs_attrs(struct usb_serial_port *port)
struct ftdi_private *priv = usb_get_serial_port_data(port);
int retval = 0;
- dbg("%s", __func__);
-
/* XXX I've no idea if the original SIO supports the event_char
* sysfs parameter, so I'm playing it safe. */
if (priv->chip_type != SIO) {
@@ -1619,8 +1609,6 @@ static void remove_sysfs_attrs(struct usb_serial_port *port)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
- dbg("%s", __func__);
-
/* XXX see create_sysfs_attrs */
if (priv->chip_type != SIO) {
device_remove_file(&port->dev, &dev_attr_event_char);
@@ -1667,8 +1655,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial);
- dbg("%s", __func__);
-
priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL);
if (!priv) {
dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__,
@@ -1704,8 +1690,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
/* Called from usbserial:serial_probe */
static void ftdi_USB_UIRT_setup(struct ftdi_private *priv)
{
- dbg("%s", __func__);
-
priv->flags |= ASYNC_SPD_CUST;
priv->custom_divisor = 77;
priv->force_baud = 38400;
@@ -1716,8 +1700,6 @@ static void ftdi_USB_UIRT_setup(struct ftdi_private *priv)
static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv)
{
- dbg("%s", __func__);
-
priv->flags |= ASYNC_SPD_CUST;
priv->custom_divisor = 240;
priv->force_baud = 38400;
@@ -1767,8 +1749,6 @@ static int ftdi_jtag_probe(struct usb_serial *serial)
struct usb_device *udev = serial->dev;
struct usb_interface *interface = serial->interface;
- dbg("%s", __func__);
-
if (interface == udev->actconfig->interface[0]) {
dev_info(&udev->dev,
"Ignoring serial port reserved for JTAG\n");
@@ -1782,8 +1762,6 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial)
{
struct usb_device *udev = serial->dev;
- dbg("%s", __func__);
-
if ((udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems")) ||
(udev->product && !strcmp(udev->product, "BeagleBone/XDS100")))
return ftdi_jtag_probe(serial);
@@ -1800,8 +1778,6 @@ static int ftdi_stmclite_probe(struct usb_serial *serial)
struct usb_device *udev = serial->dev;
struct usb_interface *interface = serial->interface;
- dbg("%s", __func__);
-
if (interface == udev->actconfig->interface[2])
return 0;
@@ -1839,8 +1815,6 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
- dbg("%s", __func__);
-
priv->dev_gone = true;
wake_up_interruptible_all(&priv->delta_msr_wait);
@@ -1858,8 +1832,6 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
struct ftdi_private *priv = usb_get_serial_port_data(port);
int result;
- dbg("%s", __func__);
-
/* No error checking for this (will get errors later anyway) */
/* See ftdi_sio.h for description of what is reset */
usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
@@ -1918,8 +1890,6 @@ static void ftdi_close(struct usb_serial_port *port)
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
- dbg("%s", __func__);
-
usb_serial_generic_close(port);
kref_put(&priv->kref, ftdi_sio_priv_release);
}
@@ -1976,8 +1946,6 @@ static int ftdi_process_packet(struct tty_struct *tty,
char flag;
char *ch;
- dbg("%s - port %d", __func__, port->number);
-
if (len < 2) {
dbg("malformed packet");
return 0;
@@ -2121,8 +2089,6 @@ static void ftdi_set_termios(struct tty_struct *tty,
unsigned char vstop;
unsigned char vstart;
- dbg("%s", __func__);
-
/* Force baud rate if this device requires it, unless it is set to
B0. */
if (priv->force_baud && ((termios->c_cflag & CBAUD) != B0)) {
@@ -2295,8 +2261,6 @@ static int ftdi_tiocmget(struct tty_struct *tty)
int len;
int ret;
- dbg("%s TIOCMGET", __func__);
-
buf = kmalloc(2, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -2346,7 +2310,7 @@ static int ftdi_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
struct usb_serial_port *port = tty->driver_data;
- dbg("%s TIOCMSET", __func__);
+
return update_mctrl(port, set, clear);
}
@@ -2435,7 +2399,6 @@ static int __init ftdi_init(void)
{
int retval;
- dbg("%s", __func__);
if (vendor > 0 && product > 0) {
/* Add user specified VID/PID to reserved element of table. */
int i;
@@ -2445,7 +2408,7 @@ static int __init ftdi_init(void)
id_table_combined[i].idVendor = vendor;
id_table_combined[i].idProduct = product;
}
- retval = usb_serial_register_drivers(&ftdi_driver, serial_drivers);
+ retval = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table_combined);
if (retval == 0)
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
DRIVER_DESC "\n");
@@ -2454,9 +2417,7 @@ static int __init ftdi_init(void)
static void __exit ftdi_exit(void)
{
- dbg("%s", __func__);
-
- usb_serial_deregister_drivers(&ftdi_driver, serial_drivers);
+ usb_serial_deregister_drivers(serial_drivers);
}
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 0838baf892f3..f3c7c78ede33 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -785,6 +785,14 @@
#define RTSYSTEMS_SERIAL_VX7_PID 0x9e52 /* Serial converter for VX-7 Radios using FT232RL */
#define RTSYSTEMS_CT29B_PID 0x9e54 /* CT29B Radio Cable */
+
+/*
+ * Physik Instrumente
+ * http://www.physikinstrumente.com/en/products/
+ */
+#define PI_VID 0x1a72 /* Vendor ID */
+#define PI_E861_PID 0x1008 /* E-861 piezo controller USB connection */
+
/*
* Bayer Ascensia Contour blood glucose meter USB-converter cable.
* http://winglucofacts.com/cables/
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
index 4577b3607922..235707961ca3 100644
--- a/drivers/usb/serial/funsoft.c
+++ b/drivers/usb/serial/funsoft.c
@@ -24,13 +24,6 @@ static const struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver funsoft_driver = {
- .name = "funsoft",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver funsoft_device = {
.driver = {
.owner = THIS_MODULE,
@@ -44,7 +37,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&funsoft_device, NULL
};
-module_usb_serial_driver(funsoft_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index e8eb6347bf3a..346c15a51066 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -216,16 +216,8 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(GARMIN_VENDOR_ID, 3) },
{ } /* Terminating entry */
};
-
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver garmin_driver = {
- .name = "garmin_gps",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static inline int getLayerId(const __u8 *usbPacket)
{
@@ -345,8 +337,6 @@ static void pkt_clear(struct garmin_data *garmin_data_p)
unsigned long flags;
struct garmin_packet *result = NULL;
- dbg("%s", __func__);
-
spin_lock_irqsave(&garmin_data_p->lock, flags);
while (!list_empty(&garmin_data_p->pktlist)) {
result = (struct garmin_packet *)garmin_data_p->pktlist.next;
@@ -939,8 +929,6 @@ static int garmin_open(struct tty_struct *tty, struct usb_serial_port *port)
int status = 0;
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->mode = initial_mode;
garmin_data_p->count = 0;
@@ -996,8 +984,6 @@ static void garmin_write_bulk_callback(struct urb *urb)
struct garmin_data *garmin_data_p =
usb_get_serial_port_data(port);
- dbg("%s - port %d", __func__, port->number);
-
if (GARMIN_LAYERID_APPL == getLayerId(urb->transfer_buffer)) {
if (garmin_data_p->mode == MODE_GARMIN_SERIAL) {
@@ -1027,9 +1013,6 @@ static int garmin_write_bulk(struct usb_serial_port *port,
unsigned char *buffer;
int status;
- dbg("%s - port %d, state %d", __func__, port->number,
- garmin_data_p->state);
-
spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags &= ~FLAGS_DROP_DATA;
spin_unlock_irqrestore(&garmin_data_p->lock, flags);
@@ -1224,8 +1207,6 @@ static void garmin_read_bulk_callback(struct urb *urb)
int status = urb->status;
int retval;
- dbg("%s - port %d", __func__, port->number);
-
if (!serial) {
dbg("%s - bad serial pointer, exiting", __func__);
return;
@@ -1384,7 +1365,6 @@ static void garmin_throttle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
- dbg("%s - port %d", __func__, port->number);
/* set flag, data received will be put into a queue
for later processing */
spin_lock_irq(&garmin_data_p->lock);
@@ -1399,7 +1379,6 @@ static void garmin_unthrottle(struct tty_struct *tty)
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
int status;
- dbg("%s - port %d", __func__, port->number);
spin_lock_irq(&garmin_data_p->lock);
garmin_data_p->flags &= ~FLAGS_THROTTLED;
spin_unlock_irq(&garmin_data_p->lock);
@@ -1441,8 +1420,6 @@ static int garmin_attach(struct usb_serial *serial)
struct usb_serial_port *port = serial->port[0];
struct garmin_data *garmin_data_p = NULL;
- dbg("%s", __func__);
-
garmin_data_p = kzalloc(sizeof(struct garmin_data), GFP_KERNEL);
if (garmin_data_p == NULL) {
dev_err(&port->dev, "%s - Out of memory\n", __func__);
@@ -1471,8 +1448,6 @@ static void garmin_disconnect(struct usb_serial *serial)
struct usb_serial_port *port = serial->port[0];
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
- dbg("%s", __func__);
-
usb_kill_urb(port->interrupt_in_urb);
del_timer_sync(&garmin_data_p->timer);
}
@@ -1483,8 +1458,6 @@ static void garmin_release(struct usb_serial *serial)
struct usb_serial_port *port = serial->port[0];
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
- dbg("%s", __func__);
-
kfree(garmin_data_p);
}
@@ -1516,7 +1489,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&garmin_device, NULL
};
-module_usb_serial_driver(garmin_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 664deb63807c..105a6d898ca4 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -28,9 +28,6 @@ static int debug;
#ifdef CONFIG_USB_SERIAL_GENERIC
-static int generic_probe(struct usb_interface *interface,
- const struct usb_device_id *id);
-
static __u16 vendor = 0x05f9;
static __u16 product = 0xffff;
@@ -49,13 +46,6 @@ static const struct usb_device_id generic_serial_ids[] = {
{}
};
-static struct usb_driver generic_driver = {
- .name = "usbserial_generic",
- .probe = generic_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = generic_serial_ids,
-};
-
/* All of the device info needed for the Generic Serial Converter */
struct usb_serial_driver usb_serial_generic_device = {
.driver = {
@@ -75,16 +65,6 @@ static struct usb_serial_driver * const serial_drivers[] = {
&usb_serial_generic_device, NULL
};
-static int generic_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
-{
- const struct usb_device_id *id_pattern;
-
- id_pattern = usb_match_id(interface, generic_device_ids);
- if (id_pattern != NULL)
- return usb_serial_probe(interface, id);
- return -ENODEV;
-}
#endif
int usb_serial_generic_register(int _debug)
@@ -99,7 +79,7 @@ int usb_serial_generic_register(int _debug)
USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT;
/* register our generic driver with ourselves */
- retval = usb_serial_register_drivers(&generic_driver, serial_drivers);
+ retval = usb_serial_register_drivers(serial_drivers, "usbserial_generic", generic_serial_ids);
#endif
return retval;
}
@@ -108,7 +88,7 @@ void usb_serial_generic_deregister(void)
{
#ifdef CONFIG_USB_SERIAL_GENERIC
/* remove our generic driver */
- usb_serial_deregister_drivers(&generic_driver, serial_drivers);
+ usb_serial_deregister_drivers(serial_drivers);
#endif
}
@@ -117,8 +97,6 @@ int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port
int result = 0;
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
/* clear the throttle flags */
spin_lock_irqsave(&port->lock, flags);
port->throttled = 0;
@@ -139,12 +117,9 @@ static void generic_cleanup(struct usb_serial_port *port)
unsigned long flags;
int i;
- dbg("%s - port %d", __func__, port->number);
-
if (serial->dev) {
/* shutdown any bulk transfers that might be going on */
if (port->bulk_out_size) {
- usb_kill_urb(port->write_urb);
for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
usb_kill_urb(port->write_urbs[i]);
@@ -161,7 +136,6 @@ static void generic_cleanup(struct usb_serial_port *port)
void usb_serial_generic_close(struct usb_serial_port *port)
{
- dbg("%s - port %d", __func__, port->number);
generic_cleanup(port);
}
EXPORT_SYMBOL_GPL(usb_serial_generic_close);
@@ -249,8 +223,6 @@ int usb_serial_generic_write(struct tty_struct *tty,
{
int result;
- dbg("%s - port %d", __func__, port->number);
-
/* only do something if we have a bulk out endpoint */
if (!port->bulk_out_size)
return -ENODEV;
@@ -273,8 +245,6 @@ int usb_serial_generic_write_room(struct tty_struct *tty)
unsigned long flags;
int room;
- dbg("%s - port %d", __func__, port->number);
-
if (!port->bulk_out_size)
return 0;
@@ -282,7 +252,7 @@ int usb_serial_generic_write_room(struct tty_struct *tty)
room = kfifo_avail(&port->write_fifo);
spin_unlock_irqrestore(&port->lock, flags);
- dbg("%s - returns %d", __func__, room);
+ dev_dbg(&port->dev, "%s - returns %d\n", __func__, room);
return room;
}
@@ -292,8 +262,6 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
unsigned long flags;
int chars;
- dbg("%s - port %d", __func__, port->number);
-
if (!port->bulk_out_size)
return 0;
@@ -301,7 +269,7 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
chars = kfifo_len(&port->write_fifo) + port->tx_bytes;
spin_unlock_irqrestore(&port->lock, flags);
- dbg("%s - returns %d", __func__, chars);
+ dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars);
return chars;
}
@@ -313,7 +281,8 @@ static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,
if (!test_and_clear_bit(index, &port->read_urbs_free))
return 0;
- dbg("%s - port %d, urb %d\n", __func__, port->number, index);
+ dev_dbg(&port->dev, "%s - port %d, urb %d\n", __func__,
+ port->number, index);
res = usb_submit_urb(port->read_urbs[index], mem_flags);
if (res) {
@@ -335,8 +304,6 @@ int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port,
int res;
int i;
- dbg("%s - port %d", __func__, port->number);
-
for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
res = usb_serial_generic_submit_read_urb(port, i, mem_flags);
if (res)
@@ -395,10 +362,12 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb)
}
set_bit(i, &port->read_urbs_free);
- dbg("%s - port %d, urb %d, len %d\n", __func__, port->number, i,
- urb->actual_length);
+ dev_dbg(&port->dev, "%s - port %d, urb %d, len %d\n",
+ __func__, port->number, i, urb->actual_length);
+
if (urb->status) {
- dbg("%s - non-zero urb status: %d\n", __func__, urb->status);
+ dev_dbg(&port->dev, "%s - non-zero urb status: %d\n",
+ __func__, urb->status);
return;
}
@@ -424,8 +393,6 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb)
int status = urb->status;
int i;
- dbg("%s - port %d", __func__, port->number);
-
for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
if (port->write_urbs[i] == urb)
break;
@@ -436,7 +403,8 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb)
spin_unlock_irqrestore(&port->lock, flags);
if (status) {
- dbg("%s - non-zero urb status: %d", __func__, status);
+ dev_dbg(&port->dev, "%s - non-zero urb status: %d\n",
+ __func__, status);
spin_lock_irqsave(&port->lock, flags);
kfifo_reset_out(&port->write_fifo);
@@ -454,8 +422,6 @@ void usb_serial_generic_throttle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
/* Set the throttle request flag. It will be picked up
* by usb_serial_generic_read_bulk_callback(). */
spin_lock_irqsave(&port->lock, flags);
@@ -469,8 +435,6 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
int was_throttled;
- dbg("%s - port %d", __func__, port->number);
-
/* Clear the throttle flags */
spin_lock_irq(&port->lock);
was_throttled = port->throttled;
@@ -525,7 +489,8 @@ void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port,
{
struct tty_port *port = &usb_port->port;
- dbg("%s - port %d, status %d", __func__, usb_port->number, status);
+ dev_dbg(&usb_port->dev, "%s - port %d, status %d\n", __func__,
+ usb_port->number, status);
if (status)
wake_up_interruptible(&port->open_wait);
@@ -566,8 +531,6 @@ void usb_serial_generic_disconnect(struct usb_serial *serial)
{
int i;
- dbg("%s", __func__);
-
/* stop reads and writes on all ports */
for (i = 0; i < serial->num_ports; ++i)
generic_cleanup(serial->port[i]);
@@ -576,5 +539,4 @@ EXPORT_SYMBOL_GPL(usb_serial_generic_disconnect);
void usb_serial_generic_release(struct usb_serial *serial)
{
- dbg("%s", __func__);
}
diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c
index 2563e788c9b3..0bbaf21a9d1e 100644
--- a/drivers/usb/serial/hp4x.c
+++ b/drivers/usb/serial/hp4x.c
@@ -36,13 +36,6 @@ static const struct usb_device_id id_table[] = {
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver hp49gp_driver = {
- .name = "hp4X",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver hp49gp_device = {
.driver = {
.owner = THIS_MODULE,
@@ -56,7 +49,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&hp49gp_device, NULL
};
-module_usb_serial_driver(hp49gp_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 323e87235711..e1f5ccd1e8f8 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -3181,7 +3181,7 @@ static void edge_release(struct usb_serial *serial)
kfree(edge_serial);
}
-module_usb_serial_driver(io_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table_combined);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h
index d0e7c9affb6f..350afddb55ba 100644
--- a/drivers/usb/serial/io_tables.h
+++ b/drivers/usb/serial/io_tables.h
@@ -95,13 +95,6 @@ static const struct usb_device_id id_table_combined[] = {
MODULE_DEVICE_TABLE(usb, id_table_combined);
-static struct usb_driver io_driver = {
- .name = "io_edgeport",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table_combined,
-};
-
static struct usb_serial_driver edgeport_2port_device = {
.driver = {
.owner = THIS_MODULE,
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 40a95a7fe383..3936904c6419 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -197,14 +197,6 @@ static const struct usb_device_id id_table_combined[] = {
MODULE_DEVICE_TABLE(usb, id_table_combined);
-static struct usb_driver io_driver = {
- .name = "io_ti",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table_combined,
-};
-
-
static unsigned char OperationalMajorVersion;
static unsigned char OperationalMinorVersion;
static unsigned short OperationalBuildNumber;
@@ -547,6 +539,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout,
{
int baud_rate;
struct tty_struct *tty = tty_port_tty_get(&port->port->port);
+ struct usb_serial *serial = port->port->serial;
wait_queue_t wait;
unsigned long flags;
@@ -561,7 +554,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout,
set_current_state(TASK_INTERRUPTIBLE);
if (kfifo_len(&port->write_fifo) == 0
|| timeout == 0 || signal_pending(current)
- || !usb_get_intfdata(port->port->serial->interface))
+ || serial->disconnected)
/* disconnect */
break;
spin_unlock_irqrestore(&port->ep_lock, flags);
@@ -578,7 +571,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout,
/* wait for data to drain from the device */
timeout += jiffies;
while ((long)(jiffies - timeout) < 0 && !signal_pending(current)
- && usb_get_intfdata(port->port->serial->interface)) {
+ && !serial->disconnected) {
/* not disconnected */
if (!tx_active(port))
break;
@@ -586,7 +579,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout,
}
/* disconnected */
- if (!usb_get_intfdata(port->port->serial->interface))
+ if (serial->disconnected)
return;
/* wait one more character time, based on baud rate */
@@ -2003,8 +1996,8 @@ static void edge_close(struct usb_serial_port *port)
{
struct edgeport_serial *edge_serial;
struct edgeport_port *edge_port;
+ struct usb_serial *serial = port->serial;
int port_number;
- int status;
dbg("%s - port %d", __func__, port->number);
@@ -2028,12 +2021,18 @@ static void edge_close(struct usb_serial_port *port)
* send a close port command to it */
dbg("%s - send umpc_close_port", __func__);
port_number = port->number - port->serial->minor;
- status = send_cmd(port->serial->dev,
+
+ mutex_lock(&serial->disc_mutex);
+ if (!serial->disconnected) {
+ send_cmd(serial->dev,
UMPC_CLOSE_PORT,
(__u8)(UMPM_UART1_PORT + port_number),
0,
NULL,
0);
+ }
+ mutex_unlock(&serial->disc_mutex);
+
mutex_lock(&edge_serial->es_lock);
--edge_port->edge_serial->num_ports_open;
if (edge_port->edge_serial->num_ports_open <= 0) {
@@ -2783,7 +2782,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&edgeport_1port_device, &edgeport_2port_device, NULL
};
-module_usb_serial_driver(io_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table_combined);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 10c02b8b5664..c85a7eb87d4e 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -33,7 +33,6 @@
#define DRIVER_AUTHOR "Ganesh Varadarajan <ganesh@veritas.com>"
#define DRIVER_DESC "USB PocketPC PDA driver"
-static __u16 product, vendor;
static bool debug;
static int connect_retries = KP_RETRIES;
static int initial_wait;
@@ -45,8 +44,6 @@ static int ipaq_calc_num_ports(struct usb_serial *serial);
static int ipaq_startup(struct usb_serial *serial);
static struct usb_device_id ipaq_id_table [] = {
- /* The first entry is a placeholder for the insmod-specified device */
- { USB_DEVICE(0x049F, 0x0003) },
{ USB_DEVICE(0x0104, 0x00BE) }, /* Socket USB Sync */
{ USB_DEVICE(0x03F0, 0x1016) }, /* HP USB Sync */
{ USB_DEVICE(0x03F0, 0x1116) }, /* HP USB Sync 1611 */
@@ -505,13 +502,6 @@ static struct usb_device_id ipaq_id_table [] = {
MODULE_DEVICE_TABLE(usb, ipaq_id_table);
-static struct usb_driver ipaq_driver = {
- .name = "ipaq",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = ipaq_id_table,
-};
-
/* All of the device info needed for the Compaq iPAQ */
static struct usb_serial_driver ipaq_device = {
@@ -539,8 +529,6 @@ static int ipaq_open(struct tty_struct *tty,
int result = 0;
int retries = connect_retries;
- dbg("%s - port %d", __func__, port->number);
-
msleep(1000*initial_wait);
/*
@@ -577,7 +565,7 @@ static int ipaq_calc_num_ports(struct usb_serial *serial)
*/
int ipaq_num_ports = 1;
- dbg("%s - numberofendpoints: %d", __FUNCTION__,
+ dev_dbg(&serial->dev->dev, "%s - numberofendpoints: %d\n", __func__,
(int)serial->interface->cur_altsetting->desc.bNumEndpoints);
/*
@@ -596,8 +584,6 @@ static int ipaq_calc_num_ports(struct usb_serial *serial)
static int ipaq_startup(struct usb_serial *serial)
{
- dbg("%s", __func__);
-
/* Some of the devices in ipaq_id_table[] are composite, and we
* shouldn't bind to all the interfaces. This test will rule out
* some obviously invalid possibilities.
@@ -617,36 +603,14 @@ static int ipaq_startup(struct usb_serial *serial)
return -ENODEV;
}
- dbg("%s - iPAQ module configured for %d ports",
- __FUNCTION__, serial->num_ports);
+ dev_dbg(&serial->dev->dev,
+ "%s - iPAQ module configured for %d ports\n", __func__,
+ serial->num_ports);
return usb_reset_configuration(serial->dev);
}
-static int __init ipaq_init(void)
-{
- int retval;
-
- if (vendor) {
- ipaq_id_table[0].idVendor = vendor;
- ipaq_id_table[0].idProduct = product;
- }
-
- retval = usb_serial_register_drivers(&ipaq_driver, serial_drivers);
- if (retval == 0)
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- return retval;
-}
-
-static void __exit ipaq_exit(void)
-{
- usb_serial_deregister_drivers(&ipaq_driver, serial_drivers);
-}
-
-
-module_init(ipaq_init);
-module_exit(ipaq_exit);
+module_usb_serial_driver(serial_drivers, ipaq_id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
@@ -655,12 +619,6 @@ MODULE_LICENSE("GPL");
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
-module_param(vendor, ushort, 0);
-MODULE_PARM_DESC(vendor, "User specified USB idVendor");
-
-module_param(product, ushort, 0);
-MODULE_PARM_DESC(product, "User specified USB idProduct");
-
module_param(connect_retries, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(connect_retries,
"Maximum number of connect retries (one second each)");
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index 76a06406e26a..5811d34b6c6b 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -132,19 +132,11 @@ enum {
#define IPW_WANTS_TO_SEND 0x30
-static const struct usb_device_id usb_ipw_ids[] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(IPW_VID, IPW_PID) },
{ },
};
-
-MODULE_DEVICE_TABLE(usb, usb_ipw_ids);
-
-static struct usb_driver usb_ipw_driver = {
- .name = "ipwtty",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = usb_ipw_ids,
-};
+MODULE_DEVICE_TABLE(usb, id_table);
static bool debug;
@@ -155,8 +147,6 @@ static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port)
u8 *buf_flow_init;
int result;
- dbg("%s", __func__);
-
buf_flow_init = kmemdup(buf_flow_static, 16, GFP_KERNEL);
if (!buf_flow_init)
return -ENOMEM;
@@ -317,7 +307,7 @@ static struct usb_serial_driver ipw_device = {
.name = "ipw",
},
.description = "IPWireless converter",
- .id_table = usb_ipw_ids,
+ .id_table = id_table,
.num_ports = 1,
.disconnect = usb_wwan_disconnect,
.open = ipw_open,
@@ -333,7 +323,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&ipw_device, NULL
};
-module_usb_serial_driver(usb_ipw_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
/* Module information */
MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 84965cd65c76..fc09414c960f 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -77,13 +77,6 @@ static const struct usb_device_id ir_id_table[] = {
MODULE_DEVICE_TABLE(usb, ir_id_table);
-static struct usb_driver ir_driver = {
- .name = "ir-usb",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = ir_id_table,
-};
-
static struct usb_serial_driver ir_device = {
.driver = {
.owner = THIS_MODULE,
@@ -103,18 +96,21 @@ static struct usb_serial_driver * const serial_drivers[] = {
&ir_device, NULL
};
-static inline void irda_usb_dump_class_desc(struct usb_irda_cs_descriptor *desc)
+static inline void irda_usb_dump_class_desc(struct usb_serial *serial,
+ struct usb_irda_cs_descriptor *desc)
{
- dbg("bLength=%x", desc->bLength);
- dbg("bDescriptorType=%x", desc->bDescriptorType);
- dbg("bcdSpecRevision=%x", __le16_to_cpu(desc->bcdSpecRevision));
- dbg("bmDataSize=%x", desc->bmDataSize);
- dbg("bmWindowSize=%x", desc->bmWindowSize);
- dbg("bmMinTurnaroundTime=%d", desc->bmMinTurnaroundTime);
- dbg("wBaudRate=%x", __le16_to_cpu(desc->wBaudRate));
- dbg("bmAdditionalBOFs=%x", desc->bmAdditionalBOFs);
- dbg("bIrdaRateSniff=%x", desc->bIrdaRateSniff);
- dbg("bMaxUnicastList=%x", desc->bMaxUnicastList);
+ struct device *dev = &serial->dev->dev;
+
+ dev_dbg(dev, "bLength=%x\n", desc->bLength);
+ dev_dbg(dev, "bDescriptorType=%x\n", desc->bDescriptorType);
+ dev_dbg(dev, "bcdSpecRevision=%x\n", __le16_to_cpu(desc->bcdSpecRevision));
+ dev_dbg(dev, "bmDataSize=%x\n", desc->bmDataSize);
+ dev_dbg(dev, "bmWindowSize=%x\n", desc->bmWindowSize);
+ dev_dbg(dev, "bmMinTurnaroundTime=%d\n", desc->bmMinTurnaroundTime);
+ dev_dbg(dev, "wBaudRate=%x\n", __le16_to_cpu(desc->wBaudRate));
+ dev_dbg(dev, "bmAdditionalBOFs=%x\n", desc->bmAdditionalBOFs);
+ dev_dbg(dev, "bIrdaRateSniff=%x\n", desc->bIrdaRateSniff);
+ dev_dbg(dev, "bMaxUnicastList=%x\n", desc->bMaxUnicastList);
}
/*------------------------------------------------------------------*/
@@ -130,8 +126,9 @@ static inline void irda_usb_dump_class_desc(struct usb_irda_cs_descriptor *desc)
* Based on the same function in drivers/net/irda/irda-usb.c
*/
static struct usb_irda_cs_descriptor *
-irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum)
+irda_usb_find_class_desc(struct usb_serial *serial, unsigned int ifnum)
{
+ struct usb_device *dev = serial->dev;
struct usb_irda_cs_descriptor *desc;
int ret;
@@ -144,20 +141,20 @@ irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum)
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, ifnum, desc, sizeof(*desc), 1000);
- dbg("%s - ret=%d", __func__, ret);
+ dev_dbg(&serial->dev->dev, "%s - ret=%d\n", __func__, ret);
if (ret < sizeof(*desc)) {
- dbg("%s - class descriptor read %s (%d)",
- __func__,
- (ret < 0) ? "failed" : "too short",
- ret);
+ dev_dbg(&serial->dev->dev,
+ "%s - class descriptor read %s (%d)\n", __func__,
+ (ret < 0) ? "failed" : "too short", ret);
goto error;
}
if (desc->bDescriptorType != USB_DT_CS_IRDA) {
- dbg("%s - bad class descriptor type", __func__);
+ dev_dbg(&serial->dev->dev, "%s - bad class descriptor type\n",
+ __func__);
goto error;
}
- irda_usb_dump_class_desc(desc);
+ irda_usb_dump_class_desc(serial, desc);
return desc;
error:
@@ -207,14 +204,15 @@ static int ir_startup(struct usb_serial *serial)
{
struct usb_irda_cs_descriptor *irda_desc;
- irda_desc = irda_usb_find_class_desc(serial->dev, 0);
+ irda_desc = irda_usb_find_class_desc(serial, 0);
if (!irda_desc) {
dev_err(&serial->dev->dev,
"IRDA class descriptor not found, device not bound\n");
return -ENODEV;
}
- dbg("%s - Baud rates supported:%s%s%s%s%s%s%s%s%s",
+ dev_dbg(&serial->dev->dev,
+ "%s - Baud rates supported:%s%s%s%s%s%s%s%s%s\n",
__func__,
(irda_desc->wBaudRate & USB_IRDA_BR_2400) ? " 2400" : "",
(irda_desc->wBaudRate & USB_IRDA_BR_9600) ? " 9600" : "",
@@ -264,8 +262,6 @@ static int ir_open(struct tty_struct *tty, struct usb_serial_port *port)
{
int i;
- dbg("%s - port %d", __func__, port->number);
-
for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
port->write_urbs[i]->transfer_flags = URB_ZERO_PACKET;
@@ -322,15 +318,11 @@ static void ir_process_read_urb(struct urb *urb)
static void ir_set_termios_callback(struct urb *urb)
{
- struct usb_serial_port *port = urb->context;
- int status = urb->status;
-
- dbg("%s - port %d", __func__, port->number);
-
kfree(urb->transfer_buffer);
- if (status)
- dbg("%s - non-zero urb status: %d", __func__, status);
+ if (urb->status)
+ dev_dbg(&urb->dev->dev, "%s - non-zero urb status: %d\n",
+ __func__, urb->status);
}
static void ir_set_termios(struct tty_struct *tty,
@@ -342,8 +334,6 @@ static void ir_set_termios(struct tty_struct *tty,
speed_t baud;
int ir_baud;
- dbg("%s - port %d", __func__, port->number);
-
baud = tty_get_baud_rate(tty);
/*
@@ -447,7 +437,7 @@ static int __init ir_init(void)
ir_device.bulk_out_size = buffer_size;
}
- retval = usb_serial_register_drivers(&ir_driver, serial_drivers);
+ retval = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ir_id_table);
if (retval == 0)
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
DRIVER_DESC "\n");
@@ -456,7 +446,7 @@ static int __init ir_init(void)
static void __exit ir_exit(void)
{
- usb_serial_deregister_drivers(&ir_driver, serial_drivers);
+ usb_serial_deregister_drivers(serial_drivers);
}
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index f2192d527db0..22b1eb5040b7 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -51,13 +51,6 @@ static const struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver iuu_driver = {
- .name = "iuu_phoenix",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
/* turbo parameter */
static int boost = 100;
static int clockmode = 1;
@@ -135,8 +128,6 @@ static void iuu_release(struct usb_serial *serial)
if (!port)
return;
- dbg("%s", __func__);
-
if (priv) {
iuu_free_buf(priv);
dbg("%s - I will free all", __func__);
@@ -198,8 +189,6 @@ static void iuu_rxcmd(struct urb *urb)
int result;
int status = urb->status;
- dbg("%s - enter", __func__);
-
if (status) {
dbg("%s - status = %d", __func__, status);
/* error stop all */
@@ -221,7 +210,6 @@ static int iuu_reset(struct usb_serial_port *port, u8 wt)
struct iuu_private *priv = usb_get_serial_port_data(port);
int result;
char *buf_ptr = port->write_urb->transfer_buffer;
- dbg("%s - enter", __func__);
/* Prepare the reset sequence */
@@ -255,8 +243,6 @@ static void iuu_update_status_callback(struct urb *urb)
u8 *st;
int status = urb->status;
- dbg("%s - enter", __func__);
-
if (status) {
dbg("%s - status = %d", __func__, status);
/* error stop all */
@@ -299,8 +285,6 @@ static int iuu_status(struct usb_serial_port *port)
{
int result;
- dbg("%s - enter", __func__);
-
memset(port->write_urb->transfer_buffer, IUU_GET_STATE_REGISTER, 1);
usb_fill_bulk_urb(port->write_urb, port->serial->dev,
usb_sndbulkpipe(port->serial->dev,
@@ -318,8 +302,6 @@ static int bulk_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
struct usb_serial *serial = port->serial;
int actual = 0;
- dbg("%s - enter", __func__);
-
/* send the data out the bulk port */
status =
@@ -341,10 +323,7 @@ static int read_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
struct usb_serial *serial = port->serial;
int actual = 0;
- dbg("%s - enter", __func__);
-
/* send the data out the bulk port */
-
status =
usb_bulk_msg(serial->dev,
usb_rcvbulkpipe(serial->dev,
@@ -367,8 +346,6 @@ static int iuu_led(struct usb_serial_port *port, unsigned int R,
if (!buf)
return -ENOMEM;
- dbg("%s - enter", __func__);
-
buf[0] = IUU_SET_LED;
buf[1] = R & 0xFF;
buf[2] = (R >> 8) & 0xFF;
@@ -460,8 +437,6 @@ static int iuu_clk(struct usb_serial_port *port, int dwFrq)
unsigned int P2 = 0;
int frq = (int)dwFrq;
- dbg("%s - enter", __func__);
-
if (frq == 0) {
priv->buf[Count++] = IUU_UART_WRITE_I2C;
priv->buf[Count++] = FrqGenAdr << 1;
@@ -590,8 +565,6 @@ static int iuu_uart_flush(struct usb_serial_port *port)
u8 rxcmd = IUU_UART_RX;
struct iuu_private *priv = usb_get_serial_port_data(port);
- dbg("%s - enter", __func__);
-
if (iuu_led(port, 0xF000, 0, 0, 0xFF) < 0)
return -EIO;
@@ -630,8 +603,6 @@ static void read_buf_callback(struct urb *urb)
struct tty_struct *tty;
int status = urb->status;
- dbg("%s - status = %d", __func__, status);
-
if (status) {
if (status == -EPROTO) {
/* reschedule needed */
@@ -659,7 +630,6 @@ static int iuu_bulk_write(struct usb_serial_port *port)
int i;
int buf_len;
char *buf_ptr = port->write_urb->transfer_buffer;
- dbg("%s - enter", __func__);
spin_lock_irqsave(&priv->lock, flags);
*buf_ptr++ = IUU_UART_ESC;
@@ -691,7 +661,6 @@ static int iuu_bulk_write(struct usb_serial_port *port)
static int iuu_read_buf(struct usb_serial_port *port, int len)
{
int result;
- dbg("%s - enter", __func__);
usb_fill_bulk_urb(port->read_urb, port->serial->dev,
usb_rcvbulkpipe(port->serial->dev,
@@ -713,8 +682,6 @@ static void iuu_uart_read_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
priv->poll++;
- dbg("%s - enter", __func__);
-
if (status) {
dbg("%s - status = %d", __func__, status);
/* error stop all */
@@ -771,7 +738,6 @@ static int iuu_uart_write(struct tty_struct *tty, struct usb_serial_port *port,
{
struct iuu_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s - enter", __func__);
if (count > 256)
return -ENOMEM;
@@ -792,8 +758,6 @@ static void read_rxcmd_callback(struct urb *urb)
int result;
int status = urb->status;
- dbg("%s - status = %d", __func__, status);
-
if (status) {
/* error stop all */
return;
@@ -1015,8 +979,6 @@ static void iuu_close(struct usb_serial_port *port)
if (!serial)
return;
- dbg("%s - port %d", __func__, port->number);
-
iuu_uart_off(port);
if (serial->dev) {
/* free writebuf */
@@ -1031,7 +993,6 @@ static void iuu_close(struct usb_serial_port *port)
static void iuu_init_termios(struct tty_struct *tty)
{
- dbg("%s - enter", __func__);
*(tty->termios) = tty_std_termios;
tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600
| TIOCM_CTS | CSTOPB | PARENB;
@@ -1188,8 +1149,6 @@ static int iuu_vcc_set(struct usb_serial_port *port, unsigned int vcc)
if (!buf)
return -ENOMEM;
- dbg("%s - enter", __func__);
-
buf[0] = IUU_SET_VCC;
buf[1] = vcc & 0xFF;
buf[2] = (vcc >> 8) & 0xFF;
@@ -1250,15 +1209,11 @@ static DEVICE_ATTR(vcc_mode, S_IRUSR | S_IWUSR, show_vcc_mode,
static int iuu_create_sysfs_attrs(struct usb_serial_port *port)
{
- dbg("%s", __func__);
-
return device_create_file(&port->dev, &dev_attr_vcc_mode);
}
static int iuu_remove_sysfs_attrs(struct usb_serial_port *port)
{
- dbg("%s", __func__);
-
device_remove_file(&port->dev, &dev_attr_vcc_mode);
return 0;
}
@@ -1294,7 +1249,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&iuu_device, NULL
};
-module_usb_serial_driver(iuu_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR("Alain Degreffe eczema@ecze.com");
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index a39ddd1b0dca..a1b99243dac9 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -130,15 +130,13 @@ struct keyspan_port_private {
#include "keyspan_usa67msg.h"
-module_usb_serial_driver(keyspan_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, keyspan_ids_combined);
static void keyspan_break_ctl(struct tty_struct *tty, int break_state)
{
struct usb_serial_port *port = tty->driver_data;
struct keyspan_port_private *p_priv;
- dbg("%s", __func__);
-
p_priv = usb_get_serial_port_data(port);
if (break_state == -1)
@@ -158,8 +156,6 @@ static void keyspan_set_termios(struct tty_struct *tty,
const struct keyspan_device_details *d_details;
unsigned int cflag;
- dbg("%s", __func__);
-
p_priv = usb_get_serial_port_data(port);
d_details = p_priv->device_details;
cflag = tty->termios->c_cflag;
@@ -306,8 +302,6 @@ static void usa26_indat_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
- dbg("%s", __func__);
-
endpoint = usb_pipeendpoint(urb->pipe);
if (status) {
@@ -369,8 +363,6 @@ static void usa2x_outdat_callback(struct urb *urb)
static void usa26_inack_callback(struct urb *urb)
{
- dbg("%s", __func__);
-
}
static void usa26_outcont_callback(struct urb *urb)
@@ -452,7 +444,6 @@ exit: ;
static void usa26_glocont_callback(struct urb *urb)
{
- dbg("%s", __func__);
}
@@ -465,8 +456,6 @@ static void usa28_indat_callback(struct urb *urb)
struct keyspan_port_private *p_priv;
int status = urb->status;
- dbg("%s", __func__);
-
port = urb->context;
p_priv = usb_get_serial_port_data(port);
data = urb->transfer_buffer;
@@ -505,7 +494,6 @@ static void usa28_indat_callback(struct urb *urb)
static void usa28_inack_callback(struct urb *urb)
{
- dbg("%s", __func__);
}
static void usa28_outcont_callback(struct urb *urb)
@@ -585,7 +573,6 @@ exit: ;
static void usa28_glocont_callback(struct urb *urb)
{
- dbg("%s", __func__);
}
@@ -596,8 +583,6 @@ static void usa49_glocont_callback(struct urb *urb)
struct keyspan_port_private *p_priv;
int i;
- dbg("%s", __func__);
-
serial = urb->context;
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
@@ -625,8 +610,6 @@ static void usa49_instat_callback(struct urb *urb)
int old_dcd_state;
int status = urb->status;
- dbg("%s", __func__);
-
serial = urb->context;
if (status) {
@@ -679,7 +662,6 @@ exit: ;
static void usa49_inack_callback(struct urb *urb)
{
- dbg("%s", __func__);
}
static void usa49_indat_callback(struct urb *urb)
@@ -691,8 +673,6 @@ static void usa49_indat_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
- dbg("%s", __func__);
-
endpoint = usb_pipeendpoint(urb->pipe);
if (status) {
@@ -742,8 +722,6 @@ static void usa49wg_indat_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
- dbg("%s", __func__);
-
serial = urb->context;
if (status) {
@@ -806,7 +784,6 @@ static void usa49wg_indat_callback(struct urb *urb)
/* not used, usa-49 doesn't have per-port control endpoints */
static void usa49_outcont_callback(struct urb *urb)
{
- dbg("%s", __func__);
}
static void usa90_indat_callback(struct urb *urb)
@@ -819,8 +796,6 @@ static void usa90_indat_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
- dbg("%s", __func__);
-
endpoint = usb_pipeendpoint(urb->pipe);
if (status) {
@@ -957,8 +932,6 @@ static void usa67_instat_callback(struct urb *urb)
int old_dcd_state;
int status = urb->status;
- dbg("%s", __func__);
-
serial = urb->context;
if (status) {
@@ -1010,8 +983,6 @@ static void usa67_glocont_callback(struct urb *urb)
struct keyspan_port_private *p_priv;
int i;
- dbg("%s", __func__);
-
serial = urb->context;
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
@@ -1035,7 +1006,6 @@ static int keyspan_write_room(struct tty_struct *tty)
int data_len;
struct urb *this_urb;
- dbg("%s", __func__);
p_priv = usb_get_serial_port_data(port);
d_details = p_priv->device_details;
@@ -1078,8 +1048,6 @@ static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
p_priv = usb_get_serial_port_data(port);
d_details = p_priv->device_details;
- dbg("%s - port%d.", __func__, port->number);
-
/* Set some sane defaults */
p_priv->rts_state = 1;
p_priv->dtr_state = 1;
@@ -1165,7 +1133,6 @@ static void keyspan_close(struct usb_serial_port *port)
struct keyspan_serial_private *s_priv;
struct keyspan_port_private *p_priv;
- dbg("%s", __func__);
s_priv = usb_get_serial_data(serial);
p_priv = usb_get_serial_port_data(port);
@@ -1438,8 +1405,6 @@ static void keyspan_setup_urbs(struct usb_serial *serial)
struct callbacks *cback;
int endp;
- dbg("%s", __func__);
-
s_priv = usb_get_serial_data(serial);
d_details = s_priv->device_details;
@@ -1853,8 +1818,6 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial,
struct urb *this_urb;
int device_port, err;
- dbg("%s", __func__);
-
s_priv = usb_get_serial_data(serial);
p_priv = usb_get_serial_port_data(port);
d_details = s_priv->device_details;
@@ -1980,8 +1943,6 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
struct urb *this_urb;
int err, device_port;
- dbg("%s", __func__);
-
s_priv = usb_get_serial_data(serial);
p_priv = usb_get_serial_port_data(port);
d_details = s_priv->device_details;
@@ -2168,8 +2129,6 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial,
int err;
u8 prescaler;
- dbg("%s", __func__);
-
s_priv = usb_get_serial_data(serial);
p_priv = usb_get_serial_port_data(port);
d_details = s_priv->device_details;
@@ -2300,8 +2259,6 @@ static int keyspan_usa67_send_setup(struct usb_serial *serial,
struct urb *this_urb;
int err, device_port;
- dbg("%s", __func__);
-
s_priv = usb_get_serial_data(serial);
p_priv = usb_get_serial_port_data(port);
d_details = s_priv->device_details;
@@ -2442,8 +2399,6 @@ static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
struct keyspan_serial_private *s_priv;
const struct keyspan_device_details *d_details;
- dbg("%s", __func__);
-
s_priv = usb_get_serial_data(serial);
d_details = s_priv->device_details;
@@ -2477,8 +2432,6 @@ static int keyspan_startup(struct usb_serial *serial)
struct keyspan_port_private *p_priv;
const struct keyspan_device_details *d_details;
- dbg("%s", __func__);
-
for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
if (d_details->product_id ==
le16_to_cpu(serial->dev->descriptor.idProduct))
@@ -2538,8 +2491,6 @@ static void keyspan_disconnect(struct usb_serial *serial)
struct keyspan_serial_private *s_priv;
struct keyspan_port_private *p_priv;
- dbg("%s", __func__);
-
s_priv = usb_get_serial_data(serial);
/* Stop reading/writing urbs */
@@ -2579,8 +2530,6 @@ static void keyspan_release(struct usb_serial *serial)
struct usb_serial_port *port;
struct keyspan_serial_private *s_priv;
- dbg("%s", __func__);
-
s_priv = usb_get_serial_data(serial);
/* dbg("Freeing serial->private."); */
diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h
index 622853c9e384..fe1c5d91692c 100644
--- a/drivers/usb/serial/keyspan.h
+++ b/drivers/usb/serial/keyspan.h
@@ -487,13 +487,6 @@ static const struct usb_device_id keyspan_ids_combined[] = {
MODULE_DEVICE_TABLE(usb, keyspan_ids_combined);
-static struct usb_driver keyspan_driver = {
- .name = "keyspan",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = keyspan_ids_combined,
-};
-
/* usb_device_id table for the pre-firmware download keyspan devices */
static const struct usb_device_id keyspan_pre_ids[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) },
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 693bcdfcb3d5..a4ac3cfeffc4 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -86,13 +86,6 @@ static const struct usb_device_id id_table_combined[] = {
MODULE_DEVICE_TABLE(usb, id_table_combined);
-static struct usb_driver keyspan_pda_driver = {
- .name = "keyspan_pda",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table_combined,
-};
-
static const struct usb_device_id id_table_std[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) },
{ } /* Terminating entry */
@@ -131,7 +124,6 @@ static void keyspan_pda_request_unthrottle(struct work_struct *work)
struct usb_serial *serial = priv->serial;
int result;
- dbg(" request_unthrottle");
/* ask the device to tell us when the tx buffer becomes
sufficiently empty */
result = usb_control_msg(serial->dev,
@@ -226,7 +218,7 @@ static void keyspan_pda_rx_throttle(struct tty_struct *tty)
send an XOFF, although it might make sense to foist that off
upon the device too. */
struct usb_serial_port *port = tty->driver_data;
- dbg("keyspan_pda_rx_throttle port %d", port->number);
+
usb_kill_urb(port->interrupt_in_urb);
}
@@ -235,7 +227,7 @@ static void keyspan_pda_rx_unthrottle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
/* just restart the receive interrupt URB */
- dbg("keyspan_pda_rx_unthrottle port %d", port->number);
+
if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL))
dbg(" usb_submit_urb(read urb) failed");
}
@@ -466,7 +458,6 @@ static int keyspan_pda_write(struct tty_struct *tty,
select() or poll() too) until we receive that unthrottle interrupt.
Block if we can't write anything at all, otherwise write as much as
we can. */
- dbg("keyspan_pda_write(%d)", count);
if (count == 0) {
dbg(" write request of 0 bytes");
return 0;
@@ -766,8 +757,6 @@ static int keyspan_pda_startup(struct usb_serial *serial)
static void keyspan_pda_release(struct usb_serial *serial)
{
- dbg("%s", __func__);
-
kfree(usb_get_serial_port_data(serial->port[0]));
}
@@ -834,7 +823,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
NULL
};
-module_usb_serial_driver(keyspan_pda_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table_combined);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 10f05407e535..5bed59cd5776 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -86,13 +86,6 @@ static const struct usb_device_id id_table[] = {
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver kl5kusb105d_driver = {
- .name = "kl5kusb105d",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver kl5kusb105d_device = {
.driver = {
.owner = THIS_MODULE,
@@ -282,8 +275,6 @@ static void klsi_105_release(struct usb_serial *serial)
{
int i;
- dbg("%s", __func__);
-
for (i = 0; i < serial->num_ports; ++i)
kfree(usb_get_serial_port_data(serial->port[i]));
}
@@ -298,8 +289,6 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
struct klsi_105_port_settings *cfg;
unsigned long flags;
- dbg("%s port %d", __func__, port->number);
-
/* Do a defined restart:
* Set up sane default baud rate and send the 'READ_ON'
* vendor command.
@@ -376,8 +365,6 @@ static void klsi_105_close(struct usb_serial_port *port)
{
int rc;
- dbg("%s port %d", __func__, port->number);
-
mutex_lock(&port->serial->disc_mutex);
if (!port->serial->disconnected) {
/* send READ_OFF */
@@ -646,7 +633,6 @@ static int klsi_105_tiocmget(struct tty_struct *tty)
unsigned long flags;
int rc;
unsigned long line_state;
- dbg("%s - request, just guessing", __func__);
rc = klsi_105_get_line_state(port, &line_state);
if (rc < 0) {
@@ -668,8 +654,6 @@ static int klsi_105_tiocmset(struct tty_struct *tty,
{
int retval = -EINVAL;
- dbg("%s", __func__);
-
/* if this ever gets implemented, it should be done something like this:
struct usb_serial *serial = port->serial;
struct klsi_105_private *priv = usb_get_serial_port_data(port);
@@ -692,7 +676,7 @@ static int klsi_105_tiocmset(struct tty_struct *tty,
return retval;
}
-module_usb_serial_driver(kl5kusb105d_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 4a9a75eb9b95..fafeabb64c55 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -81,18 +81,8 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_KAAN_SIM_PRODUCT_ID) },
{ } /* Terminating entry */
};
-
-
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver kobil_driver = {
- .name = "kobil",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
-
static struct usb_serial_driver kobil_device = {
.driver = {
.owner = THIS_MODULE,
@@ -193,7 +183,6 @@ static int kobil_startup(struct usb_serial *serial)
static void kobil_release(struct usb_serial *serial)
{
int i;
- dbg("%s - port %d", __func__, serial->port[0]->number);
for (i = 0; i < serial->num_ports; ++i)
kfree(usb_get_serial_port_data(serial->port[i]));
@@ -217,7 +206,6 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
int transfer_buffer_length = 8;
int write_urb_transfer_buffer_length = 8;
- dbg("%s - port %d", __func__, port->number);
priv = usb_get_serial_port_data(port);
/* allocate memory for transfer buffer */
@@ -327,8 +315,6 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
static void kobil_close(struct usb_serial_port *port)
{
- dbg("%s - port %d", __func__, port->number);
-
/* FIXME: Add rts/dtr methods */
if (port->write_urb) {
usb_poison_urb(port->write_urb);
@@ -349,8 +335,6 @@ static void kobil_read_int_callback(struct urb *urb)
int status = urb->status;
/* char *dbg_data; */
- dbg("%s - port %d", __func__, port->number);
-
if (status) {
dbg("%s - port %d Read int status not zero: %d",
__func__, port->number, status);
@@ -474,7 +458,6 @@ static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port,
static int kobil_write_room(struct tty_struct *tty)
{
- /* dbg("%s - port %d", __func__, port->number); */
/* FIXME */
return 8;
}
@@ -683,7 +666,7 @@ static int kobil_ioctl(struct tty_struct *tty,
}
}
-module_usb_serial_driver(kobil_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 6edd26130e25..d0ec1aa52719 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -73,22 +73,14 @@ static void mct_u232_unthrottle(struct tty_struct *tty);
/*
* All of the device info needed for the MCT USB-RS232 converter.
*/
-static const struct usb_device_id id_table_combined[] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(MCT_U232_VID, MCT_U232_PID) },
{ USB_DEVICE(MCT_U232_VID, MCT_U232_SITECOM_PID) },
{ USB_DEVICE(MCT_U232_VID, MCT_U232_DU_H3SP_PID) },
{ USB_DEVICE(MCT_U232_BELKIN_F5U109_VID, MCT_U232_BELKIN_F5U109_PID) },
{ } /* Terminating entry */
};
-
-MODULE_DEVICE_TABLE(usb, id_table_combined);
-
-static struct usb_driver mct_u232_driver = {
- .name = "mct_u232",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table_combined,
-};
+MODULE_DEVICE_TABLE(usb, id_table);
static struct usb_serial_driver mct_u232_device = {
.driver = {
@@ -96,7 +88,7 @@ static struct usb_serial_driver mct_u232_device = {
.name = "mct_u232",
},
.description = "MCT U232",
- .id_table = id_table_combined,
+ .id_table = id_table,
.num_ports = 1,
.open = mct_u232_open,
.close = mct_u232_close,
@@ -427,8 +419,6 @@ static void mct_u232_release(struct usb_serial *serial)
struct mct_u232_private *priv;
int i;
- dbg("%s", __func__);
-
for (i = 0; i < serial->num_ports; ++i) {
/* My special items, the standard routines free my urbs */
priv = usb_get_serial_port_data(serial->port[i]);
@@ -446,8 +436,6 @@ static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port)
unsigned char last_lcr;
unsigned char last_msr;
- dbg("%s port %d", __func__, port->number);
-
/* Compensate for a hardware bug: although the Sitecom U232-P25
* device reports a maximum output packet size of 32 bytes,
* it seems to be able to accept only 16 bytes (and that's what
@@ -528,8 +516,6 @@ static void mct_u232_dtr_rts(struct usb_serial_port *port, int on)
static void mct_u232_close(struct usb_serial_port *port)
{
- dbg("%s port %d", __func__, port->number);
-
if (port->serial->dev) {
/* shutdown our urbs */
usb_kill_urb(port->write_urb);
@@ -572,7 +558,6 @@ static void mct_u232_read_int_callback(struct urb *urb)
return;
}
- dbg("%s - port %d", __func__, port->number);
usb_serial_debug_data(debug, &port->dev, __func__,
urb->actual_length, data);
@@ -733,8 +718,6 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state)
unsigned char lcr;
unsigned long flags;
- dbg("%sstate=%d", __func__, break_state);
-
spin_lock_irqsave(&priv->lock, flags);
lcr = priv->last_lcr;
@@ -753,8 +736,6 @@ static int mct_u232_tiocmget(struct tty_struct *tty)
unsigned int control_state;
unsigned long flags;
- dbg("%s", __func__);
-
spin_lock_irqsave(&priv->lock, flags);
control_state = priv->control_state;
spin_unlock_irqrestore(&priv->lock, flags);
@@ -771,8 +752,6 @@ static int mct_u232_tiocmset(struct tty_struct *tty,
unsigned int control_state;
unsigned long flags;
- dbg("%s", __func__);
-
spin_lock_irqsave(&priv->lock, flags);
control_state = priv->control_state;
@@ -796,8 +775,6 @@ static void mct_u232_throttle(struct tty_struct *tty)
struct mct_u232_private *priv = usb_get_serial_port_data(port);
unsigned int control_state;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irq(&priv->lock);
priv->rx_flags |= THROTTLED;
if (C_CRTSCTS(tty)) {
@@ -816,8 +793,6 @@ static void mct_u232_unthrottle(struct tty_struct *tty)
struct mct_u232_private *priv = usb_get_serial_port_data(port);
unsigned int control_state;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irq(&priv->lock);
if ((priv->rx_flags & THROTTLED) && C_CRTSCTS(tty)) {
priv->rx_flags &= ~THROTTLED;
@@ -906,7 +881,7 @@ static int mct_u232_get_icount(struct tty_struct *tty,
return 0;
}
-module_usb_serial_driver(mct_u232_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c
index 08d16e8c002d..81423f7361db 100644
--- a/drivers/usb/serial/metro-usb.c
+++ b/drivers/usb/serial/metro-usb.c
@@ -17,7 +17,6 @@
#include <linux/tty_flip.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
-#include <linux/errno.h>
#include <linux/uaccess.h>
#include <linux/usb/serial.h>
@@ -56,6 +55,47 @@ MODULE_DEVICE_TABLE(usb, id_table);
/* Input parameter constants. */
static bool debug;
+/* UNI-Directional mode commands for device configure */
+#define UNI_CMD_OPEN 0x80
+#define UNI_CMD_CLOSE 0xFF
+
+inline int metrousb_is_unidirectional_mode(struct usb_serial_port *port)
+{
+ __u16 product_id = le16_to_cpu(
+ port->serial->dev->descriptor.idProduct);
+
+ return product_id == FOCUS_PRODUCT_ID_UNI;
+}
+
+static int metrousb_send_unidirectional_cmd(u8 cmd, struct usb_serial_port *port)
+{
+ int ret;
+ int actual_len;
+ u8 *buffer_cmd = NULL;
+
+ if (!metrousb_is_unidirectional_mode(port))
+ return 0;
+
+ buffer_cmd = kzalloc(sizeof(cmd), GFP_KERNEL);
+ if (!buffer_cmd)
+ return -ENOMEM;
+
+ *buffer_cmd = cmd;
+
+ ret = usb_interrupt_msg(port->serial->dev,
+ usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress),
+ buffer_cmd, sizeof(cmd),
+ &actual_len, USB_CTRL_SET_TIMEOUT);
+
+ kfree(buffer_cmd);
+
+ if (ret < 0)
+ return ret;
+ else if (actual_len != sizeof(cmd))
+ return -EIO;
+ return 0;
+}
+
static void metrousb_read_int_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
@@ -78,12 +118,12 @@ static void metrousb_read_int_callback(struct urb *urb)
/* urb has been terminated. */
dev_dbg(&port->dev,
"%s - urb shutting down, error code=%d\n",
- __func__, result);
+ __func__, urb->status);
return;
default:
dev_dbg(&port->dev,
"%s - non-zero urb received, error code=%d\n",
- __func__, result);
+ __func__, urb->status);
goto exit;
}
@@ -91,7 +131,7 @@ static void metrousb_read_int_callback(struct urb *urb)
/* Set the data read from the usb port into the serial port buffer. */
tty = tty_port_tty_get(&port->port);
if (!tty) {
- dev_dbg(&port->dev, "%s - bad tty pointer - exiting\n",
+ dev_err(&port->dev, "%s - bad tty pointer - exiting\n",
__func__);
return;
}
@@ -121,7 +161,7 @@ static void metrousb_read_int_callback(struct urb *urb)
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
if (result)
- dev_dbg(&port->dev,
+ dev_err(&port->dev,
"%s - failed submitting interrupt in urb, error code=%d\n",
__func__, result);
}
@@ -131,11 +171,19 @@ exit:
/* Try to resubmit the urb. */
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
- dev_dbg(&port->dev,
+ dev_err(&port->dev,
"%s - failed submitting interrupt in urb, error code=%d\n",
__func__, result);
}
+static void metrousb_write_int_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = urb->context;
+
+ dev_warn(&port->dev, "%s not implemented yet.\n",
+ __func__);
+}
+
static void metrousb_cleanup(struct usb_serial_port *port)
{
dev_dbg(&port->dev, "%s\n", __func__);
@@ -146,6 +194,9 @@ static void metrousb_cleanup(struct usb_serial_port *port)
usb_unlink_urb(port->interrupt_in_urb);
usb_kill_urb(port->interrupt_in_urb);
}
+
+ /* Send deactivate cmd to device */
+ metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port);
}
}
@@ -160,7 +211,7 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
/* Make sure the urb is initialized. */
if (!port->interrupt_in_urb) {
- dev_dbg(&port->dev, "%s - interrupt urb not initialized\n",
+ dev_err(&port->dev, "%s - interrupt urb not initialized\n",
__func__);
return -ENODEV;
}
@@ -191,12 +242,21 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result) {
- dev_dbg(&port->dev,
+ dev_err(&port->dev,
"%s - failed submitting interrupt in urb, error code=%d\n",
__func__, result);
goto exit;
}
+ /* Send activate cmd to device */
+ result = metrousb_send_unidirectional_cmd(UNI_CMD_OPEN, port);
+ if (result) {
+ dev_err(&port->dev,
+ "%s - failed to configure device for port number=%d, error code=%d\n",
+ __func__, port->number, result);
+ goto exit;
+ }
+
dev_dbg(&port->dev, "%s - port open\n", __func__);
exit:
return result;
@@ -221,7 +281,7 @@ static int metrousb_set_modem_ctrl(struct usb_serial *serial, unsigned int contr
METROUSB_SET_REQUEST_TYPE, METROUSB_SET_MODEM_CTRL_REQUEST,
control_state, 0, NULL, 0, WDR_TIMEOUT);
if (retval < 0)
- dev_dbg(&serial->dev->dev,
+ dev_err(&serial->dev->dev,
"%s - set modem ctrl=0x%x failed, error code=%d\n",
__func__, mcr, retval);
@@ -354,29 +414,23 @@ static void metrousb_unthrottle(struct tty_struct *tty)
port->interrupt_in_urb->dev = port->serial->dev;
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
if (result)
- dev_dbg(tty->dev,
+ dev_err(tty->dev,
"failed submitting interrupt in urb error code=%d\n",
result);
}
-static struct usb_driver metrousb_driver = {
- .name = "metro-usb",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table
-};
-
static struct usb_serial_driver metrousb_device = {
.driver = {
.owner = THIS_MODULE,
.name = "metro-usb",
},
- .description = "Metrologic USB to serial converter.",
+ .description = "Metrologic USB to Serial",
.id_table = id_table,
.num_ports = 1,
.open = metrousb_open,
.close = metrousb_cleanup,
.read_int_callback = metrousb_read_int_callback,
+ .write_int_callback = metrousb_write_int_callback,
.attach = metrousb_startup,
.release = metrousb_shutdown,
.throttle = metrousb_throttle,
@@ -390,7 +444,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
NULL,
};
-module_usb_serial_driver(metrousb_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Philip Nicastro");
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index bdce82034122..a07dd3c8cfef 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -79,12 +79,12 @@ static struct usb_serial_driver moschip7720_2port_driver;
#define MOSCHIP_DEVICE_ID_7720 0x7720
#define MOSCHIP_DEVICE_ID_7715 0x7715
-static const struct usb_device_id moschip_port_id_table[] = {
+static const struct usb_device_id id_table[] = {
{ USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7720) },
{ USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7715) },
{ } /* terminating entry */
};
-MODULE_DEVICE_TABLE(usb, moschip_port_id_table);
+MODULE_DEVICE_TABLE(usb, id_table);
#ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT
@@ -257,7 +257,6 @@ static void destroy_mos_parport(struct kref *kref)
struct mos7715_parport *mos_parport =
container_of(kref, struct mos7715_parport, ref_count);
- dbg("%s called", __func__);
kfree(mos_parport);
}
@@ -266,7 +265,7 @@ static void destroy_urbtracker(struct kref *kref)
struct urbtracker *urbtrack =
container_of(kref, struct urbtracker, ref_count);
struct mos7715_parport *mos_parport = urbtrack->mos_parport;
- dbg("%s called", __func__);
+
usb_free_urb(urbtrack->urb);
kfree(urbtrack);
kref_put(&mos_parport->ref_count, destroy_mos_parport);
@@ -285,8 +284,6 @@ static void send_deferred_urbs(unsigned long _mos_parport)
struct urbtracker *urbtrack;
struct list_head *cursor, *next;
- dbg("%s called", __func__);
-
/* if release function ran, game over */
if (unlikely(mos_parport->serial == NULL))
return;
@@ -335,7 +332,7 @@ static void async_complete(struct urb *urb)
{
struct urbtracker *urbtrack = urb->context;
int status = urb->status;
- dbg("%s called", __func__);
+
if (unlikely(status))
dbg("%s - nonzero urb status received: %d", __func__, status);
@@ -355,7 +352,6 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport,
struct usb_ctrlrequest setup;
struct usb_serial *serial = mos_parport->serial;
struct usb_device *usbdev = serial->dev;
- dbg("%s called", __func__);
/* create and initialize the control urb and containing urbtracker */
urbtrack = kmalloc(sizeof(struct urbtracker), GFP_ATOMIC);
@@ -476,7 +472,7 @@ static inline void parport_epilogue(struct parport *pp)
static void parport_mos7715_write_data(struct parport *pp, unsigned char d)
{
struct mos7715_parport *mos_parport = pp->private_data;
- dbg("%s called: %2.2x", __func__, d);
+
if (parport_prologue(pp) < 0)
return;
mos7715_change_mode(mos_parport, SPP);
@@ -488,7 +484,7 @@ static unsigned char parport_mos7715_read_data(struct parport *pp)
{
struct mos7715_parport *mos_parport = pp->private_data;
unsigned char d;
- dbg("%s called", __func__);
+
if (parport_prologue(pp) < 0)
return 0;
read_mos_reg(mos_parport->serial, dummy, DPR, &d);
@@ -500,7 +496,7 @@ static void parport_mos7715_write_control(struct parport *pp, unsigned char d)
{
struct mos7715_parport *mos_parport = pp->private_data;
__u8 data;
- dbg("%s called: %2.2x", __func__, d);
+
if (parport_prologue(pp) < 0)
return;
data = ((__u8)d & 0x0f) | (mos_parport->shadowDCR & 0xf0);
@@ -513,7 +509,7 @@ static unsigned char parport_mos7715_read_control(struct parport *pp)
{
struct mos7715_parport *mos_parport = pp->private_data;
__u8 dcr;
- dbg("%s called", __func__);
+
spin_lock(&release_lock);
mos_parport = pp->private_data;
if (unlikely(mos_parport == NULL)) {
@@ -531,7 +527,7 @@ static unsigned char parport_mos7715_frob_control(struct parport *pp,
{
struct mos7715_parport *mos_parport = pp->private_data;
__u8 dcr;
- dbg("%s called", __func__);
+
mask &= 0x0f;
val &= 0x0f;
if (parport_prologue(pp) < 0)
@@ -547,7 +543,7 @@ static unsigned char parport_mos7715_read_status(struct parport *pp)
{
unsigned char status;
struct mos7715_parport *mos_parport = pp->private_data;
- dbg("%s called", __func__);
+
spin_lock(&release_lock);
mos_parport = pp->private_data;
if (unlikely(mos_parport == NULL)) { /* release called */
@@ -561,17 +557,16 @@ static unsigned char parport_mos7715_read_status(struct parport *pp)
static void parport_mos7715_enable_irq(struct parport *pp)
{
- dbg("%s called", __func__);
}
+
static void parport_mos7715_disable_irq(struct parport *pp)
{
- dbg("%s called", __func__);
}
static void parport_mos7715_data_forward(struct parport *pp)
{
struct mos7715_parport *mos_parport = pp->private_data;
- dbg("%s called", __func__);
+
if (parport_prologue(pp) < 0)
return;
mos7715_change_mode(mos_parport, PS2);
@@ -583,7 +578,7 @@ static void parport_mos7715_data_forward(struct parport *pp)
static void parport_mos7715_data_reverse(struct parport *pp)
{
struct mos7715_parport *mos_parport = pp->private_data;
- dbg("%s called", __func__);
+
if (parport_prologue(pp) < 0)
return;
mos7715_change_mode(mos_parport, PS2);
@@ -595,7 +590,6 @@ static void parport_mos7715_data_reverse(struct parport *pp)
static void parport_mos7715_init_state(struct pardevice *dev,
struct parport_state *s)
{
- dbg("%s called", __func__);
s->u.pc.ctr = DCR_INIT_VAL;
s->u.pc.ecr = ECR_INIT_VAL;
}
@@ -605,7 +599,7 @@ static void parport_mos7715_save_state(struct parport *pp,
struct parport_state *s)
{
struct mos7715_parport *mos_parport;
- dbg("%s called", __func__);
+
spin_lock(&release_lock);
mos_parport = pp->private_data;
if (unlikely(mos_parport == NULL)) { /* release called */
@@ -622,7 +616,7 @@ static void parport_mos7715_restore_state(struct parport *pp,
struct parport_state *s)
{
struct mos7715_parport *mos_parport;
- dbg("%s called", __func__);
+
spin_lock(&release_lock);
mos_parport = pp->private_data;
if (unlikely(mos_parport == NULL)) { /* release called */
@@ -641,7 +635,7 @@ static size_t parport_mos7715_write_compat(struct parport *pp,
int retval;
struct mos7715_parport *mos_parport = pp->private_data;
int actual_len;
- dbg("%s called: %u chars", __func__, (unsigned int)len);
+
if (parport_prologue(pp) < 0)
return 0;
mos7715_change_mode(mos_parport, PPF);
@@ -2164,20 +2158,13 @@ static void mos7720_release(struct usb_serial *serial)
kfree(usb_get_serial_port_data(serial->port[i]));
}
-static struct usb_driver usb_driver = {
- .name = "moschip7720",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = moschip_port_id_table,
-};
-
static struct usb_serial_driver moschip7720_2port_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "moschip7720",
},
.description = "Moschip 2 port adapter",
- .id_table = moschip_port_id_table,
+ .id_table = id_table,
.calc_num_ports = mos77xx_calc_num_ports,
.open = mos7720_open,
.close = mos7720_close,
@@ -2203,7 +2190,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&moschip7720_2port_driver, NULL
};
-module_usb_serial_driver(usb_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index c526550694a0..29160f8b5101 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -114,10 +114,10 @@
#define USB_VENDOR_ID_MOSCHIP 0x9710
#define MOSCHIP_DEVICE_ID_7840 0x7840
#define MOSCHIP_DEVICE_ID_7820 0x7820
+#define MOSCHIP_DEVICE_ID_7810 0x7810
/* The native component can have its vendor/device id's overridden
* in vendor-specific implementations. Such devices can be handled
- * by making a change here, in moschip_port_id_table, and in
- * moschip_id_table_combined
+ * by making a change here, in id_table.
*/
#define USB_VENDOR_ID_BANDB 0x0856
#define BANDB_DEVICE_ID_USO9ML2_2 0xAC22
@@ -184,31 +184,16 @@
#define NUM_URBS 16 /* URB Count */
#define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */
+/* LED on/off milliseconds*/
+#define LED_ON_MS 500
+#define LED_OFF_MS 500
-static const struct usb_device_id moschip_port_id_table[] = {
- {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
- {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4P)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_2)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_4)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_2)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2P)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4P)},
- {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)},
- {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)},
- {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)},
- {} /* terminating entry */
-};
+static int device_type;
-static const struct usb_device_id moschip_id_table_combined[] __devinitconst = {
+static const struct usb_device_id id_table[] __devinitconst = {
{USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
{USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)},
+ {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7810)},
{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)},
{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)},
{USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)},
@@ -226,8 +211,7 @@ static const struct usb_device_id moschip_id_table_combined[] __devinitconst = {
{USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)},
{} /* terminating entry */
};
-
-MODULE_DEVICE_TABLE(usb, moschip_id_table_combined);
+MODULE_DEVICE_TABLE(usb, id_table);
/* This structure holds all of the local port information */
@@ -261,8 +245,13 @@ struct moschip_port {
struct urb *write_urb_pool[NUM_URBS];
char busy[NUM_URBS];
bool read_urb_busy;
-};
+ /* For device(s) with LED indicator */
+ bool has_led;
+ bool led_flag;
+ struct timer_list led_timer1; /* Timer for LED on */
+ struct timer_list led_timer2; /* Timer for LED off */
+};
static bool debug;
@@ -572,6 +561,69 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
return ret;
}
+static void mos7840_set_led_callback(struct urb *urb)
+{
+ switch (urb->status) {
+ case 0:
+ /* Success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* This urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d", __func__,
+ urb->status);
+ break;
+ default:
+ dbg("%s - nonzero urb status received: %d", __func__,
+ urb->status);
+ }
+}
+
+static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval,
+ __u16 reg)
+{
+ struct usb_device *dev = mcs->port->serial->dev;
+ struct usb_ctrlrequest *dr = mcs->dr;
+
+ dr->bRequestType = MCS_WR_RTYPE;
+ dr->bRequest = MCS_WRREQ;
+ dr->wValue = cpu_to_le16(wval);
+ dr->wIndex = cpu_to_le16(reg);
+ dr->wLength = cpu_to_le16(0);
+
+ usb_fill_control_urb(mcs->control_urb, dev, usb_sndctrlpipe(dev, 0),
+ (unsigned char *)dr, NULL, 0, mos7840_set_led_callback, NULL);
+
+ usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
+}
+
+static void mos7840_set_led_sync(struct usb_serial_port *port, __u16 reg,
+ __u16 val)
+{
+ struct usb_device *dev = port->serial->dev;
+
+ usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ, MCS_WR_RTYPE,
+ val, reg, NULL, 0, MOS_WDR_TIMEOUT);
+}
+
+static void mos7840_led_off(unsigned long arg)
+{
+ struct moschip_port *mcs = (struct moschip_port *) arg;
+
+ /* Turn off LED */
+ mos7840_set_led_async(mcs, 0x0300, MODEM_CONTROL_REGISTER);
+ mod_timer(&mcs->led_timer2,
+ jiffies + msecs_to_jiffies(LED_OFF_MS));
+}
+
+static void mos7840_led_flag_off(unsigned long arg)
+{
+ struct moschip_port *mcs = (struct moschip_port *) arg;
+
+ mcs->led_flag = false;
+}
+
/*****************************************************************************
* mos7840_interrupt_callback
* this is the callback function for when we have received data on the
@@ -591,8 +643,6 @@ static void mos7840_interrupt_callback(struct urb *urb)
__u16 wval, wreg = 0;
int status = urb->status;
- dbg("%s", " : Entering");
-
switch (status) {
case 0:
/* success */
@@ -766,12 +816,8 @@ static void mos7840_bulk_in_callback(struct urb *urb)
return;
}
- dbg("%s", "Entering... ");
-
data = urb->transfer_buffer;
- dbg("%s", "Entering ...........");
-
if (urb->actual_length) {
tty = tty_port_tty_get(&mos7840_port->port->port);
if (tty) {
@@ -792,6 +838,14 @@ static void mos7840_bulk_in_callback(struct urb *urb)
return;
}
+ /* Turn on LED */
+ if (mos7840_port->has_led && !mos7840_port->led_flag) {
+ mos7840_port->led_flag = true;
+ mos7840_set_led_async(mos7840_port, 0x0301,
+ MODEM_CONTROL_REGISTER);
+ mod_timer(&mos7840_port->led_timer1,
+ jiffies + msecs_to_jiffies(LED_ON_MS));
+ }
mos7840_port->read_urb_busy = true;
retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
@@ -835,8 +889,6 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
return;
}
- dbg("%s", "Entering .........");
-
tty = tty_port_tty_get(&mos7840_port->port->port);
if (tty && mos7840_port->open)
tty_wakeup(tty);
@@ -878,8 +930,6 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
struct moschip_port *mos7840_port;
struct moschip_port *port0;
- dbg ("%s enter", __func__);
-
if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Port Paranoia failed");
return -ENODEV;
@@ -1151,10 +1201,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
dbg("usb_serial serial:%p mos7840_port:%p\n usb_serial_port port:%p",
serial, mos7840_port, port);
- dbg ("%s leave", __func__);
-
return 0;
-
}
/*****************************************************************************
@@ -1175,18 +1222,14 @@ static int mos7840_chars_in_buffer(struct tty_struct *tty)
unsigned long flags;
struct moschip_port *mos7840_port;
- dbg("%s", " mos7840_chars_in_buffer:entering ...........");
-
if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Invalid port");
return 0;
}
mos7840_port = mos7840_get_port_private(port);
- if (mos7840_port == NULL) {
- dbg("%s", "mos7840_break:leaving ...........");
+ if (mos7840_port == NULL)
return 0;
- }
spin_lock_irqsave(&mos7840_port->pool_lock, flags);
for (i = 0; i < NUM_URBS; ++i)
@@ -1211,8 +1254,6 @@ static void mos7840_close(struct usb_serial_port *port)
int j;
__u16 Data;
- dbg("%s", "mos7840_close:entering...");
-
if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Port Paranoia failed");
return;
@@ -1287,8 +1328,6 @@ static void mos7840_close(struct usb_serial_port *port)
mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
mos7840_port->open = 0;
-
- dbg("%s", "Leaving ............");
}
/************************************************************************
@@ -1343,9 +1382,6 @@ static void mos7840_break(struct tty_struct *tty, int break_state)
struct usb_serial *serial;
struct moschip_port *mos7840_port;
- dbg("%s", "Entering ...........");
- dbg("mos7840_break: Start");
-
if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Port Paranoia failed");
return;
@@ -1395,8 +1431,6 @@ static int mos7840_write_room(struct tty_struct *tty)
unsigned long flags;
struct moschip_port *mos7840_port;
- dbg("%s", " mos7840_write_room:entering ...........");
-
if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Invalid port");
dbg("%s", " mos7840_write_room:leaving ...........");
@@ -1445,9 +1479,6 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
/* __u16 Data; */
const unsigned char *current_position = data;
unsigned char *data1;
- dbg("%s", "entering ...........");
- /* dbg("mos7840_write: mos7840_port->shadowLCR is %x",
- mos7840_port->shadowLCR); */
#ifdef NOTMOS7840
Data = 0x00;
@@ -1554,6 +1585,14 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
data1 = urb->transfer_buffer;
dbg("bulkout endpoint is %d", port->bulk_out_endpointAddress);
+ /* Turn on LED */
+ if (mos7840_port->has_led && !mos7840_port->led_flag) {
+ mos7840_port->led_flag = true;
+ mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0301);
+ mod_timer(&mos7840_port->led_timer1,
+ jiffies + msecs_to_jiffies(LED_ON_MS));
+ }
+
/* send it down the pipe */
status = usb_submit_urb(urb, GFP_ATOMIC);
@@ -1602,8 +1641,6 @@ static void mos7840_throttle(struct tty_struct *tty)
return;
}
- dbg("%s", "Entering ..........");
-
/* if we are implementing XON/XOFF, send the stop character */
if (I_IXOFF(tty)) {
unsigned char stop_char = STOP_CHAR(tty);
@@ -1646,8 +1683,6 @@ static void mos7840_unthrottle(struct tty_struct *tty)
return;
}
- dbg("%s", "Entering ..........");
-
/* if we are implementing XON/XOFF, send the start character */
if (I_IXOFF(tty)) {
unsigned char start_char = START_CHAR(tty);
@@ -1676,8 +1711,6 @@ static int mos7840_tiocmget(struct tty_struct *tty)
int status;
mos7840_port = mos7840_get_port_private(port);
- dbg("%s - port %d", __func__, port->number);
-
if (mos7840_port == NULL)
return -ENODEV;
@@ -1704,8 +1737,6 @@ static int mos7840_tiocmset(struct tty_struct *tty,
unsigned int mcr;
int status;
- dbg("%s - port %d", __func__, port->number);
-
mos7840_port = mos7840_get_port_private(port);
if (mos7840_port == NULL)
@@ -1746,7 +1777,6 @@ static int mos7840_tiocmset(struct tty_struct *tty,
static int mos7840_calc_baud_rate_divisor(int baudRate, int *divisor,
__u16 *clk_sel_val)
{
-
dbg("%s - %d", __func__, baudRate);
if (baudRate <= 115200) {
@@ -1839,8 +1869,6 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port,
return -1;
}
- dbg("%s", "Entering ..........");
-
number = mos7840_port->port->number - mos7840_port->port->serial->minor;
dbg("%s - port = %d, baud = %d", __func__,
@@ -1966,8 +1994,6 @@ static void mos7840_change_port_settings(struct tty_struct *tty,
return;
}
- dbg("%s", "Entering ..........");
-
lData = LCR_BITS_8;
lStop = LCR_STOP_1;
lParity = LCR_PAR_NONE;
@@ -2108,7 +2134,7 @@ static void mos7840_set_termios(struct tty_struct *tty,
unsigned int cflag;
struct usb_serial *serial;
struct moschip_port *mos7840_port;
- dbg("mos7840_set_termios: START");
+
if (mos7840_port_paranoia_check(port, __func__)) {
dbg("%s", "Invalid port");
return;
@@ -2327,28 +2353,74 @@ static int mos7840_ioctl(struct tty_struct *tty,
return -ENOIOCTLCMD;
}
+static int mos7810_check(struct usb_serial *serial)
+{
+ int i, pass_count = 0;
+ __u16 data = 0, mcr_data = 0;
+ __u16 test_pattern = 0x55AA;
+
+ /* Store MCR setting */
+ usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ MCS_RDREQ, MCS_RD_RTYPE, 0x0300, MODEM_CONTROL_REGISTER,
+ &mcr_data, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
+
+ for (i = 0; i < 16; i++) {
+ /* Send the 1-bit test pattern out to MCS7810 test pin */
+ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ MCS_WRREQ, MCS_WR_RTYPE,
+ (0x0300 | (((test_pattern >> i) & 0x0001) << 1)),
+ MODEM_CONTROL_REGISTER, NULL, 0, MOS_WDR_TIMEOUT);
+
+ /* Read the test pattern back */
+ usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &data,
+ VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
+
+ /* If this is a MCS7810 device, both test patterns must match */
+ if (((test_pattern >> i) ^ (~data >> 1)) & 0x0001)
+ break;
+
+ pass_count++;
+ }
+
+ /* Restore MCR setting */
+ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), MCS_WRREQ,
+ MCS_WR_RTYPE, 0x0300 | mcr_data, MODEM_CONTROL_REGISTER, NULL,
+ 0, MOS_WDR_TIMEOUT);
+
+ if (pass_count == 16)
+ return 1;
+
+ return 0;
+}
+
static int mos7840_calc_num_ports(struct usb_serial *serial)
{
- __u16 Data = 0x00;
- int ret = 0;
+ __u16 data = 0x00;
int mos7840_num_ports;
- ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
- MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &Data,
+ usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &data,
VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
- if ((Data & 0x01) == 0) {
- mos7840_num_ports = 2;
- serial->num_bulk_in = 2;
- serial->num_bulk_out = 2;
- serial->num_ports = 2;
+ if (serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7810 ||
+ serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7820) {
+ device_type = serial->dev->descriptor.idProduct;
} else {
- mos7840_num_ports = 4;
- serial->num_bulk_in = 4;
- serial->num_bulk_out = 4;
- serial->num_ports = 4;
+ /* For a MCS7840 device GPIO0 must be set to 1 */
+ if ((data & 0x01) == 1)
+ device_type = MOSCHIP_DEVICE_ID_7840;
+ else if (mos7810_check(serial))
+ device_type = MOSCHIP_DEVICE_ID_7810;
+ else
+ device_type = MOSCHIP_DEVICE_ID_7820;
}
+ mos7840_num_ports = (device_type >> 4) & 0x000F;
+ serial->num_bulk_in = mos7840_num_ports;
+ serial->num_bulk_out = mos7840_num_ports;
+ serial->num_ports = mos7840_num_ports;
+
return mos7840_num_ports;
}
@@ -2361,9 +2433,7 @@ static int mos7840_startup(struct usb_serial *serial)
struct moschip_port *mos7840_port;
struct usb_device *dev;
int i, status;
-
__u16 Data;
- dbg("%s", "mos7840_startup :Entering..........");
if (!serial) {
dbg("%s", "Invalid Handler");
@@ -2372,9 +2442,6 @@ static int mos7840_startup(struct usb_serial *serial)
dev = serial->dev;
- dbg("%s", "Entering...");
- dbg ("mos7840_startup: serial = %p", serial);
-
/* we set up the pointers to the endpoints in the mos7840_open *
* function, as the structures aren't created yet. */
@@ -2563,6 +2630,34 @@ static int mos7840_startup(struct usb_serial *serial)
status = -ENOMEM;
goto error;
}
+
+ mos7840_port->has_led = false;
+
+ /* Initialize LED timers */
+ if (device_type == MOSCHIP_DEVICE_ID_7810) {
+ mos7840_port->has_led = true;
+
+ init_timer(&mos7840_port->led_timer1);
+ mos7840_port->led_timer1.function = mos7840_led_off;
+ mos7840_port->led_timer1.expires =
+ jiffies + msecs_to_jiffies(LED_ON_MS);
+ mos7840_port->led_timer1.data =
+ (unsigned long)mos7840_port;
+
+ init_timer(&mos7840_port->led_timer2);
+ mos7840_port->led_timer2.function =
+ mos7840_led_flag_off;
+ mos7840_port->led_timer2.expires =
+ jiffies + msecs_to_jiffies(LED_OFF_MS);
+ mos7840_port->led_timer2.data =
+ (unsigned long)mos7840_port;
+
+ mos7840_port->led_flag = false;
+
+ /* Turn off LED */
+ mos7840_set_led_sync(serial->port[i],
+ MODEM_CONTROL_REGISTER, 0x0300);
+ }
}
dbg ("mos7840_startup: all ports configured...........");
@@ -2602,7 +2697,6 @@ static void mos7840_disconnect(struct usb_serial *serial)
int i;
unsigned long flags;
struct moschip_port *mos7840_port;
- dbg("%s", " disconnect :entering..........");
if (!serial) {
dbg("%s", "Invalid Handler");
@@ -2624,9 +2718,6 @@ static void mos7840_disconnect(struct usb_serial *serial)
usb_kill_urb(mos7840_port->control_urb);
}
}
-
- dbg("%s", "Thank u :: ");
-
}
/****************************************************************************
@@ -2638,7 +2729,6 @@ static void mos7840_release(struct usb_serial *serial)
{
int i;
struct moschip_port *mos7840_port;
- dbg("%s", " release :entering..........");
if (!serial) {
dbg("%s", "Invalid Handler");
@@ -2654,30 +2744,28 @@ static void mos7840_release(struct usb_serial *serial)
mos7840_port = mos7840_get_port_private(serial->port[i]);
dbg("mos7840_port %d = %p", i, mos7840_port);
if (mos7840_port) {
+ if (mos7840_port->has_led) {
+ /* Turn off LED */
+ mos7840_set_led_sync(mos7840_port->port,
+ MODEM_CONTROL_REGISTER, 0x0300);
+
+ del_timer_sync(&mos7840_port->led_timer1);
+ del_timer_sync(&mos7840_port->led_timer2);
+ }
kfree(mos7840_port->ctrl_buf);
kfree(mos7840_port->dr);
kfree(mos7840_port);
}
}
-
- dbg("%s", "Thank u :: ");
-
}
-static struct usb_driver io_driver = {
- .name = "mos7840",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = moschip_id_table_combined,
-};
-
static struct usb_serial_driver moschip7840_4port_device = {
.driver = {
.owner = THIS_MODULE,
.name = "mos7840",
},
.description = DRIVER_DESC,
- .id_table = moschip_port_id_table,
+ .id_table = id_table,
.num_ports = 4,
.open = mos7840_open,
.close = mos7840_close,
@@ -2707,7 +2795,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&moschip7840_4port_device, NULL
};
-module_usb_serial_driver(io_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/moto_modem.c b/drivers/usb/serial/moto_modem.c
index 3ab6214b4bbf..c5ff6c7795a6 100644
--- a/drivers/usb/serial/moto_modem.c
+++ b/drivers/usb/serial/moto_modem.c
@@ -31,13 +31,6 @@ static const struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver moto_driver = {
- .name = "moto-modem",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver moto_device = {
.driver = {
.owner = THIS_MODULE,
@@ -51,5 +44,5 @@ static struct usb_serial_driver * const serial_drivers[] = {
&moto_device, NULL
};
-module_usb_serial_driver(moto_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
index 29ab6eb5b536..d95452cc076d 100644
--- a/drivers/usb/serial/navman.c
+++ b/drivers/usb/serial/navman.c
@@ -30,13 +30,6 @@ static const struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver navman_driver = {
- .name = "navman",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static void navman_read_int_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
@@ -53,12 +46,12 @@ static void navman_read_int_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __func__, status);
+ dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
+ __func__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d",
- __func__, status);
+ dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
+ __func__, status);
goto exit;
}
@@ -84,10 +77,9 @@ static int navman_open(struct tty_struct *tty, struct usb_serial_port *port)
{
int result = 0;
- dbg("%s - port %d", __func__, port->number);
-
if (port->interrupt_in_urb) {
- dbg("%s - adding interrupt input for treo", __func__);
+ dev_dbg(&port->dev, "%s - adding interrupt input for treo\n",
+ __func__);
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result)
dev_err(&port->dev,
@@ -99,16 +91,12 @@ static int navman_open(struct tty_struct *tty, struct usb_serial_port *port)
static void navman_close(struct usb_serial_port *port)
{
- dbg("%s - port %d", __func__, port->number);
-
usb_kill_urb(port->interrupt_in_urb);
}
static int navman_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count)
{
- dbg("%s - port %d", __func__, port->number);
-
/*
* This device can't write any data, only read from the device
*/
@@ -132,7 +120,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&navman_device, NULL
};
-module_usb_serial_driver(navman_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 88dc785bb298..6f3d7051c7f4 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -54,17 +54,8 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(ZYXEL_VENDOR_ID, BT_IGNITIONPRO_ID) },
{ } /* Terminating entry */
};
-
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver omninet_driver = {
- .name = "omninet",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
-
static struct usb_serial_driver zyxel_omninet_device = {
.driver = {
.owner = THIS_MODULE,
@@ -144,8 +135,6 @@ static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port)
struct usb_serial_port *wport;
int result = 0;
- dbg("%s - port %d", __func__, port->number);
-
wport = serial->port[1];
tty_port_tty_set(&wport->port, tty);
@@ -160,7 +149,6 @@ static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port)
static void omninet_close(struct usb_serial_port *port)
{
- dbg("%s - port %d", __func__, port->number);
usb_kill_urb(port->read_urb);
}
@@ -178,8 +166,6 @@ static void omninet_read_bulk_callback(struct urb *urb)
int result;
int i;
- dbg("%s - port %d", __func__, port->number);
-
if (status) {
dbg("%s - nonzero read bulk status received: %d",
__func__, status);
@@ -225,8 +211,6 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
int result;
- dbg("%s - port %d", __func__, port->number);
-
if (count == 0) {
dbg("%s - write request of 0 bytes", __func__);
return 0;
@@ -289,8 +273,6 @@ static void omninet_write_bulk_callback(struct urb *urb)
struct usb_serial_port *port = urb->context;
int status = urb->status;
- dbg("%s - port %0x", __func__, port->number);
-
set_bit(0, &port->write_urbs_free);
if (status) {
dbg("%s - nonzero write bulk status received: %d",
@@ -306,8 +288,6 @@ static void omninet_disconnect(struct usb_serial *serial)
{
struct usb_serial_port *wport = serial->port[1];
- dbg("%s", __func__);
-
usb_kill_urb(wport->write_urb);
}
@@ -316,12 +296,10 @@ static void omninet_release(struct usb_serial *serial)
{
struct usb_serial_port *port = serial->port[0];
- dbg("%s", __func__);
-
kfree(usb_get_serial_port_data(port));
}
-module_usb_serial_driver(omninet_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c
index 82cc9d202b83..02cb1b7f6559 100644
--- a/drivers/usb/serial/opticon.c
+++ b/drivers/usb/serial/opticon.c
@@ -70,8 +70,6 @@ static void opticon_read_bulk_callback(struct urb *urb)
int data_length;
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
switch (status) {
case 0:
/* success */
@@ -179,8 +177,6 @@ static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port)
unsigned long flags;
int result = 0;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irqsave(&priv->lock, flags);
priv->throttled = false;
priv->actually_throttled = false;
@@ -216,8 +212,6 @@ static void opticon_close(struct usb_serial_port *port)
{
struct opticon_private *priv = usb_get_serial_data(port->serial);
- dbg("%s - port %d", __func__, port->number);
-
/* shutdown our urbs */
usb_kill_urb(priv->bulk_read_urb);
}
@@ -256,8 +250,6 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port,
int status;
struct usb_ctrlrequest *dr;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irqsave(&priv->lock, flags);
if (priv->outstanding_urbs > URB_UPPER_LIMIT) {
spin_unlock_irqrestore(&priv->lock, flags);
@@ -338,8 +330,6 @@ static int opticon_write_room(struct tty_struct *tty)
struct opticon_private *priv = usb_get_serial_data(port->serial);
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
/*
* We really can take almost anything the user throws at us
* but let's pick a nice big number to tell the tty
@@ -362,7 +352,6 @@ static void opticon_throttle(struct tty_struct *tty)
struct opticon_private *priv = usb_get_serial_data(port->serial);
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
priv->throttled = true;
spin_unlock_irqrestore(&priv->lock, flags);
@@ -376,8 +365,6 @@ static void opticon_unthrottle(struct tty_struct *tty)
unsigned long flags;
int result, was_throttled;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irqsave(&priv->lock, flags);
priv->throttled = false;
was_throttled = priv->actually_throttled;
@@ -400,10 +387,6 @@ static int opticon_tiocmget(struct tty_struct *tty)
unsigned long flags;
int result = 0;
- dbg("%s - port %d", __func__, port->number);
- if (!usb_get_intfdata(port->serial->interface))
- return -ENODEV;
-
spin_lock_irqsave(&priv->lock, flags);
if (priv->rts)
result |= TIOCM_RTS;
@@ -419,13 +402,13 @@ static int opticon_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
struct usb_serial_port *port = tty->driver_data;
+ struct usb_serial *serial = port->serial;
struct opticon_private *priv = usb_get_serial_data(port->serial);
unsigned long flags;
bool rts;
bool changed = false;
+ int ret;
- if (!usb_get_intfdata(port->serial->interface))
- return -ENODEV;
/* We only support RTS so we only handle that */
spin_lock_irqsave(&priv->lock, flags);
@@ -441,7 +424,14 @@ static int opticon_tiocmset(struct tty_struct *tty,
return 0;
/* Send the new RTS state to the connected device */
- return send_control_msg(port, CONTROL_RTS, !rts);
+ mutex_lock(&serial->disc_mutex);
+ if (!serial->disconnected)
+ ret = send_control_msg(port, CONTROL_RTS, !rts);
+ else
+ ret = -ENODEV;
+ mutex_unlock(&serial->disc_mutex);
+
+ return ret;
}
static int get_serial_info(struct opticon_private *priv,
@@ -555,8 +545,6 @@ static void opticon_disconnect(struct usb_serial *serial)
{
struct opticon_private *priv = usb_get_serial_data(serial);
- dbg("%s", __func__);
-
usb_kill_urb(priv->bulk_read_urb);
usb_free_urb(priv->bulk_read_urb);
}
@@ -565,24 +553,20 @@ static void opticon_release(struct usb_serial *serial)
{
struct opticon_private *priv = usb_get_serial_data(serial);
- dbg("%s", __func__);
-
kfree(priv->bulk_in_buffer);
kfree(priv);
}
-static int opticon_suspend(struct usb_interface *intf, pm_message_t message)
+static int opticon_suspend(struct usb_serial *serial, pm_message_t message)
{
- struct usb_serial *serial = usb_get_intfdata(intf);
struct opticon_private *priv = usb_get_serial_data(serial);
usb_kill_urb(priv->bulk_read_urb);
return 0;
}
-static int opticon_resume(struct usb_interface *intf)
+static int opticon_resume(struct usb_serial *serial)
{
- struct usb_serial *serial = usb_get_intfdata(intf);
struct opticon_private *priv = usb_get_serial_data(serial);
struct usb_serial_port *port = serial->port[0];
int result;
@@ -597,15 +581,6 @@ static int opticon_resume(struct usb_interface *intf)
return result;
}
-static struct usb_driver opticon_driver = {
- .name = "opticon",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .suspend = opticon_suspend,
- .resume = opticon_resume,
- .id_table = id_table,
-};
-
static struct usb_serial_driver opticon_device = {
.driver = {
.owner = THIS_MODULE,
@@ -625,13 +600,15 @@ static struct usb_serial_driver opticon_device = {
.ioctl = opticon_ioctl,
.tiocmget = opticon_tiocmget,
.tiocmset = opticon_tiocmset,
+ .suspend = opticon_suspend,
+ .resume = opticon_resume,
};
static struct usb_serial_driver * const serial_drivers[] = {
&opticon_device, NULL
};
-module_usb_serial_driver(opticon_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index f4465ccddc35..1aae9028cd0b 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -1220,18 +1220,6 @@ static const struct usb_device_id option_ids[] = {
};
MODULE_DEVICE_TABLE(usb, option_ids);
-static struct usb_driver option_driver = {
- .name = "option",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
-#ifdef CONFIG_PM
- .suspend = usb_serial_suspend,
- .resume = usb_serial_resume,
- .supports_autosuspend = 1,
-#endif
- .id_table = option_ids,
-};
-
/* The card has three separate interfaces, which the serial driver
* recognizes separately, thus num_port=1.
*/
@@ -1300,7 +1288,7 @@ struct option_port_private {
unsigned long tx_start_time[N_OUT_URB];
};
-module_usb_serial_driver(option_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, option_ids);
static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason,
const struct option_blacklist_info *blacklist)
@@ -1375,7 +1363,6 @@ static void option_instat_callback(struct urb *urb)
struct usb_serial_port *port = urb->context;
struct option_port_private *portdata = usb_get_serial_port_data(port);
- dbg("%s", __func__);
dbg("%s: urb %p port %p has data %p", __func__, urb, port, portdata);
if (status == 0) {
@@ -1413,7 +1400,7 @@ static void option_instat_callback(struct urb *urb)
req_pkt->bRequestType, req_pkt->bRequest);
}
} else
- err("%s: error %d", __func__, status);
+ dev_err(&port->dev, "%s: error %d\n", __func__, status);
/* Resubmit urb so we continue receiving IRQ data */
if (status != -ESHUTDOWN && status != -ENOENT) {
@@ -1437,7 +1424,6 @@ static int option_send_setup(struct usb_serial_port *port)
struct option_port_private *portdata;
int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
int val = 0;
- dbg("%s", __func__);
if (is_blacklisted(ifNum, OPTION_BLACKLIST_SENDSETUP,
(struct option_blacklist_info *) intfdata->private)) {
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index 5fdc33c6a3c0..5976b65ab6ee 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -66,13 +66,6 @@ static const struct usb_device_id id_table[] = {
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver oti6858_driver = {
- .name = "oti6858",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static bool debug;
/* requests */
@@ -211,8 +204,6 @@ static void setup_line(struct work_struct *work)
unsigned long flags;
int result;
- dbg("%s(port = %d)", __func__, port->number);
-
new_setup = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL);
if (new_setup == NULL) {
dev_err(&port->dev, "%s(): out of memory!\n", __func__);
@@ -282,8 +273,6 @@ static void send_data(struct work_struct *work)
unsigned long flags;
u8 *allow;
- dbg("%s(port = %d)", __func__, port->number);
-
spin_lock_irqsave(&priv->lock, flags);
if (priv->flags.write_urb_in_use) {
spin_unlock_irqrestore(&priv->lock, flags);
@@ -379,8 +368,6 @@ static int oti6858_startup(struct usb_serial *serial)
static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *buf, int count)
{
- dbg("%s(port = %d, count = %d)", __func__, port->number, count);
-
if (!count)
return count;
@@ -395,8 +382,6 @@ static int oti6858_write_room(struct tty_struct *tty)
int room = 0;
unsigned long flags;
- dbg("%s(port = %d)", __func__, port->number);
-
spin_lock_irqsave(&port->lock, flags);
room = kfifo_avail(&port->write_fifo);
spin_unlock_irqrestore(&port->lock, flags);
@@ -410,8 +395,6 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty)
int chars = 0;
unsigned long flags;
- dbg("%s(port = %d)", __func__, port->number);
-
spin_lock_irqsave(&port->lock, flags);
chars = kfifo_len(&port->write_fifo);
spin_unlock_irqrestore(&port->lock, flags);
@@ -437,8 +420,6 @@ static void oti6858_set_termios(struct tty_struct *tty,
__le16 divisor;
int br;
- dbg("%s(port = %d)", __func__, port->number);
-
if (!tty) {
dbg("%s(): no tty structures", __func__);
return;
@@ -545,8 +526,6 @@ static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port)
unsigned long flags;
int result;
- dbg("%s(port = %d)", __func__, port->number);
-
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
@@ -602,8 +581,6 @@ static void oti6858_close(struct usb_serial_port *port)
struct oti6858_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
- dbg("%s(port = %d)", __func__, port->number);
-
spin_lock_irqsave(&port->lock, flags);
/* clear out any remaining data in the buffer */
kfifo_reset_out(&port->write_fifo);
@@ -633,9 +610,6 @@ static int oti6858_tiocmset(struct tty_struct *tty,
dbg("%s(port = %d, set = 0x%08x, clear = 0x%08x)",
__func__, port->number, set, clear);
- if (!usb_get_intfdata(port->serial->interface))
- return -ENODEV;
-
/* FIXME: check if this is correct (active high/low) */
spin_lock_irqsave(&priv->lock, flags);
control = priv->pending_setup.control;
@@ -663,11 +637,6 @@ static int oti6858_tiocmget(struct tty_struct *tty)
unsigned pin_state;
unsigned result = 0;
- dbg("%s(port = %d)", __func__, port->number);
-
- if (!usb_get_intfdata(port->serial->interface))
- return -ENODEV;
-
spin_lock_irqsave(&priv->lock, flags);
pin_state = priv->status.pin_state & PIN_MASK;
spin_unlock_irqrestore(&priv->lock, flags);
@@ -750,8 +719,6 @@ static void oti6858_release(struct usb_serial *serial)
{
int i;
- dbg("%s()", __func__);
-
for (i = 0; i < serial->num_ports; ++i)
kfree(usb_get_serial_port_data(serial->port[i]));
}
@@ -763,9 +730,6 @@ static void oti6858_read_int_callback(struct urb *urb)
int transient = 0, can_recv = 0, resubmit = 1;
int status = urb->status;
- dbg("%s(port = %d, status = %d)",
- __func__, port->number, status);
-
switch (status) {
case 0:
/* success */
@@ -882,9 +846,6 @@ static void oti6858_read_bulk_callback(struct urb *urb)
int status = urb->status;
int result;
- dbg("%s(port = %d, status = %d)",
- __func__, port->number, status);
-
spin_lock_irqsave(&priv->lock, flags);
priv->flags.read_urb_in_use = 0;
spin_unlock_irqrestore(&priv->lock, flags);
@@ -916,9 +877,6 @@ static void oti6858_write_bulk_callback(struct urb *urb)
int status = urb->status;
int result;
- dbg("%s(port = %d, status = %d)",
- __func__, port->number, status);
-
switch (status) {
case 0:
/* success */
@@ -958,7 +916,7 @@ static void oti6858_write_bulk_callback(struct urb *urb)
}
}
-module_usb_serial_driver(oti6858_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_DESCRIPTION(OTI6858_DESCRIPTION);
MODULE_AUTHOR(OTI6858_AUTHOR);
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index a1a9062954c4..13b8dd6481f5 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -38,8 +38,6 @@
static bool debug;
-#define PL2303_CLOSING_WAIT (30*HZ)
-
static const struct usb_device_id id_table[] = {
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
@@ -97,16 +95,6 @@ static const struct usb_device_id id_table[] = {
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver pl2303_driver = {
- .name = "pl2303",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
- .suspend = usb_serial_suspend,
- .resume = usb_serial_resume,
- .supports_autosuspend = 1,
-};
-
#define SET_LINE_REQUEST_TYPE 0x21
#define SET_LINE_REQUEST 0x20
@@ -161,8 +149,9 @@ static int pl2303_vendor_read(__u16 value, __u16 index,
int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
value, index, buf, 1, 100);
- dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE,
- VENDOR_READ_REQUEST, value, index, res, buf[0]);
+ dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x %d - %x\n",
+ VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, value, index,
+ res, buf[0]);
return res;
}
@@ -172,8 +161,9 @@ static int pl2303_vendor_write(__u16 value, __u16 index,
int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
value, index, NULL, 0, 100);
- dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE,
- VENDOR_WRITE_REQUEST, value, index, res);
+ dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x %d\n",
+ VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, value, index,
+ res);
return res;
}
@@ -196,7 +186,7 @@ static int pl2303_startup(struct usb_serial *serial)
type = type_1;
else if (serial->dev->descriptor.bDeviceClass == 0xFF)
type = type_1;
- dbg("device type: %d", type);
+ dev_dbg(&serial->interface->dev, "device type: %d\n", type);
for (i = 0; i < serial->num_ports; ++i) {
priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
@@ -243,7 +233,8 @@ static int set_control_lines(struct usb_device *dev, u8 value)
retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
value, 0, NULL, 0, 100);
- dbg("%s - value = %d, retval = %d", __func__, value, retval);
+ dev_dbg(&dev->dev, "%s - value = %d, retval = %d\n", __func__,
+ value, retval);
return retval;
}
@@ -265,8 +256,6 @@ static void pl2303_set_termios(struct tty_struct *tty,
int baud_floor, baud_ceil;
int k;
- dbg("%s - port %d", __func__, port->number);
-
/* The PL2303 is reported to lose bytes if you change
serial settings even to the same values as before. Thus
we actually need to filter in this specific case */
@@ -287,7 +276,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
0, 0, buf, 7, 100);
- dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
+ dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x\n", i,
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
if (cflag & CSIZE) {
@@ -306,7 +295,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
buf[6] = 8;
break;
}
- dbg("%s - data bits = %d", __func__, buf[6]);
+ dev_dbg(&port->dev, "data bits = %d\n", buf[6]);
}
/* For reference buf[0]:buf[3] baud rate value */
@@ -315,7 +304,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
* 9600 baud (at least my PL2303X always does)
*/
baud = tty_get_baud_rate(tty);
- dbg("%s - baud requested = %d", __func__, baud);
+ dev_dbg(&port->dev, "baud requested = %d\n", baud);
if (baud) {
/* Set baudrate to nearest supported value */
for (k=0; k<ARRAY_SIZE(baud_sup); k++) {
@@ -341,7 +330,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
else if (baud > 6000000)
baud = 6000000;
}
- dbg("%s - baud set = %d", __func__, baud);
+ dev_dbg(&port->dev, "baud set = %d\n", baud);
if (baud <= 115200) {
buf[0] = baud & 0xff;
buf[1] = (baud >> 8) & 0xff;
@@ -372,14 +361,14 @@ static void pl2303_set_termios(struct tty_struct *tty,
*/
if ((cflag & CSIZE) == CS5) {
buf[4] = 1;
- dbg("%s - stop bits = 1.5", __func__);
+ dev_dbg(&port->dev, "stop bits = 1.5\n");
} else {
buf[4] = 2;
- dbg("%s - stop bits = 2", __func__);
+ dev_dbg(&port->dev, "stop bits = 2\n");
}
} else {
buf[4] = 0;
- dbg("%s - stop bits = 1", __func__);
+ dev_dbg(&port->dev, "stop bits = 1\n");
}
if (cflag & PARENB) {
@@ -391,29 +380,29 @@ static void pl2303_set_termios(struct tty_struct *tty,
if (cflag & PARODD) {
if (cflag & CMSPAR) {
buf[5] = 3;
- dbg("%s - parity = mark", __func__);
+ dev_dbg(&port->dev, "parity = mark\n");
} else {
buf[5] = 1;
- dbg("%s - parity = odd", __func__);
+ dev_dbg(&port->dev, "parity = odd\n");
}
} else {
if (cflag & CMSPAR) {
buf[5] = 4;
- dbg("%s - parity = space", __func__);
+ dev_dbg(&port->dev, "parity = space\n");
} else {
buf[5] = 2;
- dbg("%s - parity = even", __func__);
+ dev_dbg(&port->dev, "parity = even\n");
}
}
} else {
buf[5] = 0;
- dbg("%s - parity = none", __func__);
+ dev_dbg(&port->dev, "parity = none\n");
}
i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
0, 0, buf, 7, 100);
- dbg("0x21:0x20:0:0 %d", i);
+ dev_dbg(&port->dev, "0x21:0x20:0:0 %d\n", i);
/* change control lines if we are switching to or from B0 */
spin_lock_irqsave(&priv->lock, flags);
@@ -435,7 +424,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
0, 0, buf, 7, 100);
- dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
+ dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x\n", i,
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
if (cflag & CRTSCTS) {
@@ -473,8 +462,6 @@ static void pl2303_dtr_rts(struct usb_serial_port *port, int on)
static void pl2303_close(struct usb_serial_port *port)
{
- dbg("%s - port %d", __func__, port->number);
-
usb_serial_generic_close(port);
usb_kill_urb(port->interrupt_in_urb);
}
@@ -486,8 +473,6 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
struct pl2303_private *priv = usb_get_serial_port_data(port);
int result;
- dbg("%s - port %d", __func__, port->number);
-
if (priv->type != HX) {
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
@@ -501,7 +486,6 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
if (tty)
pl2303_set_termios(tty, port, &tmp_termios);
- dbg("%s - submitting interrupt urb", __func__);
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result) {
dev_err(&port->dev, "%s - failed submitting interrupt urb,"
@@ -523,12 +507,11 @@ static int pl2303_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear)
{
struct usb_serial_port *port = tty->driver_data;
+ struct usb_serial *serial = port->serial;
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
u8 control;
-
- if (!usb_get_intfdata(port->serial->interface))
- return -ENODEV;
+ int ret;
spin_lock_irqsave(&priv->lock, flags);
if (set & TIOCM_RTS)
@@ -542,7 +525,14 @@ static int pl2303_tiocmset(struct tty_struct *tty,
control = priv->line_control;
spin_unlock_irqrestore(&priv->lock, flags);
- return set_control_lines(port->serial->dev, control);
+ mutex_lock(&serial->disc_mutex);
+ if (!serial->disconnected)
+ ret = set_control_lines(serial->dev, control);
+ else
+ ret = -ENODEV;
+ mutex_unlock(&serial->disc_mutex);
+
+ return ret;
}
static int pl2303_tiocmget(struct tty_struct *tty)
@@ -554,11 +544,6 @@ static int pl2303_tiocmget(struct tty_struct *tty)
unsigned int status;
unsigned int result;
- dbg("%s (%d)", __func__, port->number);
-
- if (!usb_get_intfdata(port->serial->interface))
- return -ENODEV;
-
spin_lock_irqsave(&priv->lock, flags);
mcr = priv->line_control;
status = priv->line_status;
@@ -571,7 +556,7 @@ static int pl2303_tiocmget(struct tty_struct *tty)
| ((status & UART_RING) ? TIOCM_RI : 0)
| ((status & UART_DCD) ? TIOCM_CD : 0);
- dbg("%s - result = %x", __func__, result);
+ dev_dbg(&port->dev, "%s - result = %x\n", __func__, result);
return result;
}
@@ -625,7 +610,8 @@ static int pl2303_ioctl(struct tty_struct *tty,
{
struct serial_struct ser;
struct usb_serial_port *port = tty->driver_data;
- dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
+
+ dev_dbg(&port->dev, "%s cmd = 0x%04x\n", __func__, cmd);
switch (cmd) {
case TIOCGSERIAL:
@@ -641,10 +627,10 @@ static int pl2303_ioctl(struct tty_struct *tty,
return 0;
case TIOCMIWAIT:
- dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
+ dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__);
return wait_modem_info(port, arg);
default:
- dbg("%s not supported = 0x%04x", __func__, cmd);
+ dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd);
break;
}
return -ENOIOCTLCMD;
@@ -657,20 +643,18 @@ static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
u16 state;
int result;
- dbg("%s - port %d", __func__, port->number);
-
if (break_state == 0)
state = BREAK_OFF;
else
state = BREAK_ON;
- dbg("%s - turning break %s", __func__,
+ dev_dbg(&port->dev, "%s - turning break %s\n", __func__,
state == BREAK_OFF ? "off" : "on");
result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
0, NULL, 0, 100);
if (result)
- dbg("%s - error sending break = %d", __func__, result);
+ dev_err(&port->dev, "error sending break = %d\n", result);
}
static void pl2303_release(struct usb_serial *serial)
@@ -678,8 +662,6 @@ static void pl2303_release(struct usb_serial *serial)
int i;
struct pl2303_private *priv;
- dbg("%s", __func__);
-
for (i = 0; i < serial->num_ports; ++i) {
priv = usb_get_serial_port_data(serial->port[i]);
kfree(priv);
@@ -742,8 +724,6 @@ static void pl2303_read_int_callback(struct urb *urb)
int status = urb->status;
int retval;
- dbg("%s (%d)", __func__, port->number);
-
switch (status) {
case 0:
/* success */
@@ -752,12 +732,12 @@ static void pl2303_read_int_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __func__,
- status);
+ dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
+ __func__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __func__,
- status);
+ dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
+ __func__, status);
goto exit;
}
@@ -769,7 +749,7 @@ static void pl2303_read_int_callback(struct urb *urb)
exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
- dev_err(&urb->dev->dev,
+ dev_err(&port->dev,
"%s - usb_submit_urb failed with result %d\n",
__func__, retval);
}
@@ -807,7 +787,7 @@ static void pl2303_process_read_urb(struct urb *urb)
tty_flag = TTY_PARITY;
else if (line_status & UART_FRAME_ERROR)
tty_flag = TTY_FRAME;
- dbg("%s - tty_flag = %d", __func__, tty_flag);
+ dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag);
/* overrun is special, not associated with a char */
if (line_status & UART_OVERRUN_ERROR)
@@ -855,7 +835,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&pl2303_device, NULL
};
-module_usb_serial_driver(pl2303_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/qcaux.c b/drivers/usb/serial/qcaux.c
index 966245680f55..a4edc7ee9c8a 100644
--- a/drivers/usb/serial/qcaux.c
+++ b/drivers/usb/serial/qcaux.c
@@ -77,13 +77,6 @@ static struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver qcaux_driver = {
- .name = "qcaux",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver qcaux_device = {
.driver = {
.owner = THIS_MODULE,
@@ -97,5 +90,5 @@ static struct usb_serial_driver * const serial_drivers[] = {
&qcaux_device, NULL
};
-module_usb_serial_driver(qcaux_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index 0206b10c9e6e..0d5fe59ebb9e 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -112,32 +112,22 @@ static const struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver qcdriver = {
- .name = "qcserial",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
- .suspend = usb_serial_suspend,
- .resume = usb_serial_resume,
- .supports_autosuspend = true,
-};
-
static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
{
struct usb_wwan_intf_private *data;
struct usb_host_interface *intf = serial->interface->cur_altsetting;
+ struct device *dev = &serial->dev->dev;
int retval = -ENODEV;
__u8 nintf;
__u8 ifnum;
bool is_gobi1k = id->driver_info ? true : false;
- dbg("%s", __func__);
- dbg("Is Gobi 1000 = %d", is_gobi1k);
+ dev_dbg(dev, "Is Gobi 1000 = %d\n", is_gobi1k);
nintf = serial->dev->actconfig->desc.bNumInterfaces;
- dbg("Num Interfaces = %d", nintf);
+ dev_dbg(dev, "Num Interfaces = %d\n", nintf);
ifnum = intf->desc.bInterfaceNumber;
- dbg("This Interface = %d", ifnum);
+ dev_dbg(dev, "This Interface = %d\n", ifnum);
data = kzalloc(sizeof(struct usb_wwan_intf_private),
GFP_KERNEL);
@@ -158,7 +148,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
if (intf->desc.bNumEndpoints == 2 &&
usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) &&
usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) {
- dbg("QDL port found");
+ dev_dbg(dev, "QDL port found\n");
if (serial->interface->num_altsetting == 1) {
retval = 0; /* Success */
@@ -167,7 +157,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
retval = usb_set_interface(serial->dev, ifnum, 1);
if (retval < 0) {
- dev_err(&serial->dev->dev,
+ dev_err(dev,
"Could not set interface, error %d\n",
retval);
retval = -ENODEV;
@@ -196,20 +186,20 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
*/
if (ifnum == 1 && !is_gobi1k) {
- dbg("Gobi 2K+ DM/DIAG interface found");
+ dev_dbg(dev, "Gobi 2K+ DM/DIAG interface found\n");
retval = usb_set_interface(serial->dev, ifnum, 0);
if (retval < 0) {
- dev_err(&serial->dev->dev,
+ dev_err(dev,
"Could not set interface, error %d\n",
retval);
retval = -ENODEV;
kfree(data);
}
} else if (ifnum == 2) {
- dbg("Modem port found");
+ dev_dbg(dev, "Modem port found\n");
retval = usb_set_interface(serial->dev, ifnum, 0);
if (retval < 0) {
- dev_err(&serial->dev->dev,
+ dev_err(dev,
"Could not set interface, error %d\n",
retval);
retval = -ENODEV;
@@ -221,10 +211,10 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
* # echo "\$GPS_START" > /dev/ttyUSBx
* # echo "\$GPS_STOP" > /dev/ttyUSBx
*/
- dbg("Gobi 2K+ NMEA GPS interface found");
+ dev_dbg(dev, "Gobi 2K+ NMEA GPS interface found\n");
retval = usb_set_interface(serial->dev, ifnum, 0);
if (retval < 0) {
- dev_err(&serial->dev->dev,
+ dev_err(dev,
"Could not set interface, error %d\n",
retval);
retval = -ENODEV;
@@ -234,8 +224,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
break;
default:
- dev_err(&serial->dev->dev,
- "unknown number of interfaces: %d\n", nintf);
+ dev_err(dev, "unknown number of interfaces: %d\n", nintf);
kfree(data);
retval = -ENODEV;
}
@@ -250,8 +239,6 @@ static void qc_release(struct usb_serial *serial)
{
struct usb_wwan_intf_private *priv = usb_get_serial_data(serial);
- dbg("%s", __func__);
-
/* Call usb_wwan release & free the private data allocated in qcprobe */
usb_wwan_release(serial);
usb_set_serial_data(serial, NULL);
@@ -285,7 +272,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&qcdevice, NULL
};
-module_usb_serial_driver(qcdriver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c
new file mode 100644
index 000000000000..8dd88ebe9863
--- /dev/null
+++ b/drivers/usb/serial/quatech2.c
@@ -0,0 +1,1155 @@
+/*
+ * usb-serial driver for Quatech USB 2 devices
+ *
+ * Copyright (C) 2012 Bill Pemberton (wfp5p@virginia.edu)
+ *
+ * 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.
+ *
+ *
+ * These devices all have only 1 bulk in and 1 bulk out that is shared
+ * for all serial ports.
+ *
+ */
+
+#include <asm/unaligned.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/uaccess.h>
+
+static bool debug;
+
+/* default urb timeout for usb operations */
+#define QT2_USB_TIMEOUT USB_CTRL_SET_TIMEOUT
+
+#define QT_OPEN_CLOSE_CHANNEL 0xca
+#define QT_SET_GET_DEVICE 0xc2
+#define QT_SET_GET_REGISTER 0xc0
+#define QT_GET_SET_PREBUF_TRIG_LVL 0xcc
+#define QT_SET_ATF 0xcd
+#define QT_TRANSFER_IN 0xc0
+#define QT_HW_FLOW_CONTROL_MASK 0xc5
+#define QT_SW_FLOW_CONTROL_MASK 0xc6
+#define QT2_BREAK_CONTROL 0xc8
+#define QT2_GET_SET_UART 0xc1
+#define QT2_FLUSH_DEVICE 0xc4
+#define QT2_GET_SET_QMCR 0xe1
+#define QT2_QMCR_RS232 0x40
+#define QT2_QMCR_RS422 0x10
+
+#define SERIAL_CRTSCTS ((UART_MCR_RTS << 8) | UART_MSR_CTS)
+
+#define SERIAL_EVEN_PARITY (UART_LCR_PARITY | UART_LCR_EPAR)
+
+/* status bytes for the device */
+#define QT2_CONTROL_BYTE 0x1b
+#define QT2_LINE_STATUS 0x00 /* following 1 byte is line status */
+#define QT2_MODEM_STATUS 0x01 /* following 1 byte is modem status */
+#define QT2_XMIT_HOLD 0x02 /* following 2 bytes are ?? */
+#define QT2_CHANGE_PORT 0x03 /* following 1 byte is port to change to */
+#define QT2_REC_FLUSH 0x04 /* no following info */
+#define QT2_XMIT_FLUSH 0x05 /* no following info */
+#define QT2_CONTROL_ESCAPE 0xff /* pass through previous 2 control bytes */
+
+#define MAX_BAUD_RATE 921600
+#define DEFAULT_BAUD_RATE 9600
+
+#define QT2_WRITE_BUFFER_SIZE 512 /* size of write buffer */
+#define QT2_WRITE_CONTROL_SIZE 5 /* control bytes used for a write */
+
+/* Version Information */
+#define DRIVER_VERSION "v0.1"
+#define DRIVER_DESC "Quatech 2nd gen USB to Serial Driver"
+
+#define USB_VENDOR_ID_QUATECH 0x061d
+#define QUATECH_SSU2_100 0xC120 /* RS232 single port */
+#define QUATECH_DSU2_100 0xC140 /* RS232 dual port */
+#define QUATECH_DSU2_400 0xC150 /* RS232/422/485 dual port */
+#define QUATECH_QSU2_100 0xC160 /* RS232 four port */
+#define QUATECH_QSU2_400 0xC170 /* RS232/422/485 four port */
+#define QUATECH_ESU2_100 0xC1A0 /* RS232 eight port */
+#define QUATECH_ESU2_400 0xC180 /* RS232/422/485 eight port */
+
+struct qt2_device_detail {
+ int product_id;
+ int num_ports;
+};
+
+#define QT_DETAILS(prod, ports) \
+ .product_id = (prod), \
+ .num_ports = (ports)
+
+static const struct qt2_device_detail qt2_device_details[] = {
+ {QT_DETAILS(QUATECH_SSU2_100, 1)},
+ {QT_DETAILS(QUATECH_DSU2_400, 2)},
+ {QT_DETAILS(QUATECH_DSU2_100, 2)},
+ {QT_DETAILS(QUATECH_QSU2_400, 4)},
+ {QT_DETAILS(QUATECH_QSU2_100, 4)},
+ {QT_DETAILS(QUATECH_ESU2_400, 8)},
+ {QT_DETAILS(QUATECH_ESU2_100, 8)},
+ {QT_DETAILS(0, 0)} /* Terminating entry */
+};
+
+static const struct usb_device_id id_table[] = {
+ {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU2_100)},
+ {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_100)},
+ {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_400)},
+ {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_100)},
+ {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_400)},
+ {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_100)},
+ {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_400)},
+ {} /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+struct qt2_serial_private {
+ unsigned char current_port; /* current port for incoming data */
+
+ struct urb *read_urb; /* shared among all ports */
+ char read_buffer[512];
+};
+
+struct qt2_port_private {
+ bool is_open;
+ u8 device_port;
+
+ spinlock_t urb_lock;
+ bool urb_in_use;
+ struct urb *write_urb;
+ char write_buffer[QT2_WRITE_BUFFER_SIZE];
+
+ spinlock_t lock;
+ u8 shadowLSR;
+ u8 shadowMSR;
+
+ wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
+ struct async_icount icount;
+
+ struct usb_serial_port *port;
+};
+
+static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch);
+static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch);
+static void qt2_write_bulk_callback(struct urb *urb);
+static void qt2_read_bulk_callback(struct urb *urb);
+
+static void qt2_release(struct usb_serial *serial)
+{
+ int i;
+
+ kfree(usb_get_serial_data(serial));
+
+ for (i = 0; i < serial->num_ports; i++)
+ kfree(usb_get_serial_port_data(serial->port[i]));
+}
+
+static inline int calc_baud_divisor(int baudrate)
+{
+ int divisor, rem;
+
+ divisor = MAX_BAUD_RATE / baudrate;
+ rem = MAX_BAUD_RATE % baudrate;
+ /* Round to nearest divisor */
+ if (((rem * 2) >= baudrate) && (baudrate != 110))
+ divisor++;
+
+ return divisor;
+}
+
+static inline int qt2_set_port_config(struct usb_device *dev,
+ unsigned char port_number,
+ u16 baudrate, u16 lcr)
+{
+ int divisor = calc_baud_divisor(baudrate);
+ u16 index = ((u16) (lcr << 8) | (u16) (port_number));
+
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ QT2_GET_SET_UART, 0x40,
+ divisor, index, NULL, 0, QT2_USB_TIMEOUT);
+}
+
+static inline int qt2_control_msg(struct usb_device *dev,
+ u8 request, u16 data, u16 index)
+{
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ request, 0x40, data, index,
+ NULL, 0, QT2_USB_TIMEOUT);
+}
+
+static inline int qt2_setdevice(struct usb_device *dev, u8 *data)
+{
+ u16 x = ((u16) (data[1] << 8) | (u16) (data[0]));
+
+ return qt2_control_msg(dev, QT_SET_GET_DEVICE, x, 0);
+}
+
+
+static inline int qt2_getdevice(struct usb_device *dev, u8 *data)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ QT_SET_GET_DEVICE, 0xc0, 0, 0,
+ data, 3, QT2_USB_TIMEOUT);
+}
+
+static inline int qt2_getregister(struct usb_device *dev,
+ u8 uart,
+ u8 reg,
+ u8 *data)
+{
+ return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ QT_SET_GET_REGISTER, 0xc0, reg,
+ uart, data, sizeof(*data), QT2_USB_TIMEOUT);
+
+}
+
+static inline int qt2_setregister(struct usb_device *dev,
+ u8 uart, u8 reg, u16 data)
+{
+ u16 value = (data << 8) | reg;
+
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ QT_SET_GET_REGISTER, 0x40, value, uart,
+ NULL, 0, QT2_USB_TIMEOUT);
+}
+
+static inline int update_mctrl(struct qt2_port_private *port_priv,
+ unsigned int set, unsigned int clear)
+{
+ struct usb_serial_port *port = port_priv->port;
+ struct usb_device *dev = port->serial->dev;
+ unsigned urb_value;
+ int status;
+
+ if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) {
+ dev_dbg(&port->dev,
+ "update_mctrl - DTR|RTS not being set|cleared\n");
+ return 0; /* no change */
+ }
+
+ clear &= ~set; /* 'set' takes precedence over 'clear' */
+ urb_value = 0;
+ if (set & TIOCM_DTR)
+ urb_value |= UART_MCR_DTR;
+ if (set & TIOCM_RTS)
+ urb_value |= UART_MCR_RTS;
+
+ status = qt2_setregister(dev, port_priv->device_port, UART_MCR,
+ urb_value);
+ if (status < 0)
+ dev_err(&port->dev,
+ "update_mctrl - Error from MODEM_CTRL urb: %i\n",
+ status);
+ return status;
+}
+
+static int qt2_calc_num_ports(struct usb_serial *serial)
+{
+ struct qt2_device_detail d;
+ int i;
+
+ for (i = 0; d = qt2_device_details[i], d.product_id != 0; i++) {
+ if (d.product_id == le16_to_cpu(serial->dev->descriptor.idProduct))
+ return d.num_ports;
+ }
+
+ /* we didn't recognize the device */
+ dev_err(&serial->dev->dev,
+ "don't know the number of ports, assuming 1\n");
+
+ return 1;
+}
+
+static void qt2_set_termios(struct tty_struct *tty,
+ struct usb_serial_port *port,
+ struct ktermios *old_termios)
+{
+ struct usb_device *dev = port->serial->dev;
+ struct qt2_port_private *port_priv;
+ struct ktermios *termios = tty->termios;
+ u16 baud;
+ unsigned int cflag = termios->c_cflag;
+ u16 new_lcr = 0;
+ int status;
+
+ port_priv = usb_get_serial_port_data(port);
+
+ if (cflag & PARENB) {
+ if (cflag & PARODD)
+ new_lcr |= UART_LCR_PARITY;
+ else
+ new_lcr |= SERIAL_EVEN_PARITY;
+ }
+
+ switch (cflag & CSIZE) {
+ case CS5:
+ new_lcr |= UART_LCR_WLEN5;
+ break;
+ case CS6:
+ new_lcr |= UART_LCR_WLEN6;
+ break;
+ case CS7:
+ new_lcr |= UART_LCR_WLEN7;
+ break;
+ default:
+ case CS8:
+ new_lcr |= UART_LCR_WLEN8;
+ break;
+ }
+
+ baud = tty_get_baud_rate(tty);
+ if (!baud)
+ baud = 9600;
+
+ status = qt2_set_port_config(dev, port_priv->device_port, baud,
+ new_lcr);
+ if (status < 0)
+ dev_err(&port->dev, "%s - qt2_set_port_config failed: %i\n",
+ __func__, status);
+
+ if (cflag & CRTSCTS)
+ status = qt2_control_msg(dev, QT_HW_FLOW_CONTROL_MASK,
+ SERIAL_CRTSCTS,
+ port_priv->device_port);
+ else
+ status = qt2_control_msg(dev, QT_HW_FLOW_CONTROL_MASK,
+ 0, port_priv->device_port);
+ if (status < 0)
+ dev_err(&port->dev, "%s - set HW flow control failed: %i\n",
+ __func__, status);
+
+ if (I_IXOFF(tty) || I_IXON(tty)) {
+ u16 x = ((u16) (START_CHAR(tty) << 8) | (u16) (STOP_CHAR(tty)));
+
+ status = qt2_control_msg(dev, QT_SW_FLOW_CONTROL_MASK,
+ x, port_priv->device_port);
+ } else
+ status = qt2_control_msg(dev, QT_SW_FLOW_CONTROL_MASK,
+ 0, port_priv->device_port);
+
+ if (status < 0)
+ dev_err(&port->dev, "%s - set SW flow control failed: %i\n",
+ __func__, status);
+
+}
+
+static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)
+{
+ struct usb_serial *serial;
+ struct qt2_serial_private *serial_priv;
+ struct qt2_port_private *port_priv;
+ u8 *data;
+ u16 device_port;
+ int status;
+ unsigned long flags;
+
+ device_port = (u16) (port->number - port->serial->minor);
+
+ serial = port->serial;
+
+ port_priv = usb_get_serial_port_data(port);
+ serial_priv = usb_get_serial_data(serial);
+
+ /* set the port to RS232 mode */
+ status = qt2_control_msg(serial->dev, QT2_GET_SET_QMCR,
+ QT2_QMCR_RS232, device_port);
+ if (status < 0) {
+ dev_err(&port->dev,
+ "%s failed to set RS232 mode for port %i error %i\n",
+ __func__, device_port, status);
+ return status;
+ }
+
+ data = kzalloc(2, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ /* open the port */
+ status = usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ QT_OPEN_CLOSE_CHANNEL,
+ 0xc0, 0,
+ device_port, data, 2, QT2_USB_TIMEOUT);
+
+ if (status < 0) {
+ dev_err(&port->dev, "%s - open port failed %i", __func__,
+ status);
+ kfree(data);
+ return status;
+ }
+
+ spin_lock_irqsave(&port_priv->lock, flags);
+ port_priv->shadowLSR = data[0];
+ port_priv->shadowMSR = data[1];
+ spin_unlock_irqrestore(&port_priv->lock, flags);
+
+ kfree(data);
+
+ /* set to default speed and 8bit word size */
+ status = qt2_set_port_config(serial->dev, device_port,
+ DEFAULT_BAUD_RATE, UART_LCR_WLEN8);
+ if (status < 0) {
+ dev_err(&port->dev,
+ "%s - initial setup failed for port %i (%i)\n",
+ __func__, port->number, device_port);
+ return status;
+ }
+
+ port_priv->is_open = true;
+ port_priv->device_port = (u8) device_port;
+
+ if (tty)
+ qt2_set_termios(tty, port, tty->termios);
+
+ return 0;
+
+}
+
+static void qt2_close(struct usb_serial_port *port)
+{
+ struct usb_serial *serial;
+ struct qt2_serial_private *serial_priv;
+ struct qt2_port_private *port_priv;
+ unsigned long flags;
+ int i;
+
+ serial = port->serial;
+ serial_priv = usb_get_serial_data(serial);
+ port_priv = usb_get_serial_port_data(port);
+
+ port_priv->is_open = false;
+
+ spin_lock_irqsave(&port_priv->urb_lock, flags);
+ if (port_priv->write_urb->status == -EINPROGRESS)
+ usb_kill_urb(port_priv->write_urb);
+ port_priv->urb_in_use = false;
+ spin_unlock_irqrestore(&port_priv->urb_lock, flags);
+
+ /* flush the port transmit buffer */
+ i = usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ QT2_FLUSH_DEVICE, 0x40, 1,
+ port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT);
+
+ if (i < 0)
+ dev_err(&port->dev, "%s - transmit buffer flush failed: %i\n",
+ __func__, i);
+
+ /* flush the port receive buffer */
+ i = usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ QT2_FLUSH_DEVICE, 0x40, 0,
+ port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT);
+
+ if (i < 0)
+ dev_err(&port->dev, "%s - receive buffer flush failed: %i\n",
+ __func__, i);
+
+ /* close the port */
+ i = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ QT_OPEN_CLOSE_CHANNEL,
+ 0x40, 0,
+ port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT);
+
+ if (i < 0)
+ dev_err(&port->dev, "%s - close port failed %i\n",
+ __func__, i);
+
+}
+
+static void qt2_disconnect(struct usb_serial *serial)
+{
+ struct qt2_serial_private *serial_priv = usb_get_serial_data(serial);
+ struct qt2_port_private *port_priv;
+ int i;
+
+ if (serial_priv->read_urb->status == -EINPROGRESS)
+ usb_kill_urb(serial_priv->read_urb);
+
+ usb_free_urb(serial_priv->read_urb);
+
+ for (i = 0; i < serial->num_ports; i++) {
+ port_priv = usb_get_serial_port_data(serial->port[i]);
+
+ if (port_priv->write_urb->status == -EINPROGRESS)
+ usb_kill_urb(port_priv->write_urb);
+ usb_free_urb(port_priv->write_urb);
+ }
+}
+
+static int get_serial_info(struct usb_serial_port *port,
+ struct serial_struct __user *retinfo)
+{
+ struct serial_struct tmp;
+
+ if (!retinfo)
+ return -EFAULT;
+
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.line = port->serial->minor;
+ tmp.port = 0;
+ tmp.irq = 0;
+ tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
+ tmp.xmit_fifo_size = port->bulk_out_size;
+ tmp.baud_base = 9600;
+ tmp.close_delay = 5*HZ;
+ tmp.closing_wait = 30*HZ;
+
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return -EFAULT;
+ return 0;
+}
+
+static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
+{
+ struct qt2_port_private *priv = usb_get_serial_port_data(port);
+ struct async_icount prev, cur;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ prev = priv->icount;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ while (1) {
+ wait_event_interruptible(priv->delta_msr_wait,
+ ((priv->icount.rng != prev.rng) ||
+ (priv->icount.dsr != prev.dsr) ||
+ (priv->icount.dcd != prev.dcd) ||
+ (priv->icount.cts != prev.cts)));
+
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ cur = priv->icount;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if ((prev.rng == cur.rng) &&
+ (prev.dsr == cur.dsr) &&
+ (prev.dcd == cur.dcd) &&
+ (prev.cts == cur.cts))
+ return -EIO;
+
+ if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) ||
+ (arg & TIOCM_DSR && (prev.dsr != cur.dsr)) ||
+ (arg & TIOCM_CD && (prev.dcd != cur.dcd)) ||
+ (arg & TIOCM_CTS && (prev.cts != cur.cts)))
+ return 0;
+ }
+ return 0;
+}
+
+static int qt2_get_icount(struct tty_struct *tty,
+ struct serial_icounter_struct *icount)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct qt2_port_private *priv = usb_get_serial_port_data(port);
+ struct async_icount cnow = priv->icount;
+
+ icount->cts = cnow.cts;
+ icount->dsr = cnow.dsr;
+ icount->rng = cnow.rng;
+ icount->dcd = cnow.dcd;
+ icount->rx = cnow.rx;
+ icount->tx = cnow.tx;
+ icount->frame = cnow.frame;
+ icount->overrun = cnow.overrun;
+ icount->parity = cnow.parity;
+ icount->brk = cnow.brk;
+ icount->buf_overrun = cnow.buf_overrun;
+
+ return 0;
+}
+
+static int qt2_ioctl(struct tty_struct *tty,
+ unsigned int cmd, unsigned long arg)
+{
+ struct usb_serial_port *port = tty->driver_data;
+
+ switch (cmd) {
+ case TIOCGSERIAL:
+ return get_serial_info(port,
+ (struct serial_struct __user *)arg);
+
+ case TIOCMIWAIT:
+ return wait_modem_info(port, arg);
+
+ default:
+ break;
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+static void qt2_process_status(struct usb_serial_port *port, unsigned char *ch)
+{
+ switch (*ch) {
+ case QT2_LINE_STATUS:
+ qt2_update_lsr(port, ch + 1);
+ break;
+ case QT2_MODEM_STATUS:
+ qt2_update_msr(port, ch + 1);
+ break;
+ }
+}
+
+/* not needed, kept to document functionality */
+static void qt2_process_xmit_empty(struct usb_serial_port *port,
+ unsigned char *ch)
+{
+ int bytes_written;
+
+ bytes_written = (int)(*ch) + (int)(*(ch + 1) << 4);
+}
+
+/* not needed, kept to document functionality */
+static void qt2_process_flush(struct usb_serial_port *port, unsigned char *ch)
+{
+ return;
+}
+
+void qt2_process_read_urb(struct urb *urb)
+{
+ struct usb_serial *serial;
+ struct qt2_serial_private *serial_priv;
+ struct usb_serial_port *port;
+ struct qt2_port_private *port_priv;
+ struct tty_struct *tty;
+ bool escapeflag;
+ unsigned char *ch;
+ int i;
+ unsigned char newport;
+ int len = urb->actual_length;
+
+ if (!len)
+ return;
+
+ ch = urb->transfer_buffer;
+ tty = NULL;
+ serial = urb->context;
+ serial_priv = usb_get_serial_data(serial);
+ port = serial->port[serial_priv->current_port];
+ port_priv = usb_get_serial_port_data(port);
+
+ if (port_priv->is_open)
+ tty = tty_port_tty_get(&port->port);
+
+ for (i = 0; i < urb->actual_length; i++) {
+ ch = (unsigned char *)urb->transfer_buffer + i;
+ if ((i <= (len - 3)) &&
+ (*ch == QT2_CONTROL_BYTE) &&
+ (*(ch + 1) == QT2_CONTROL_BYTE)) {
+ escapeflag = false;
+ switch (*(ch + 2)) {
+ case QT2_LINE_STATUS:
+ case QT2_MODEM_STATUS:
+ if (i > (len - 4)) {
+ dev_warn(&port->dev,
+ "%s - status message too short\n",
+ __func__);
+ break;
+ }
+ qt2_process_status(port, ch + 2);
+ i += 3;
+ escapeflag = true;
+ break;
+ case QT2_XMIT_HOLD:
+ if (i > (len - 5)) {
+ dev_warn(&port->dev,
+ "%s - xmit_empty message too short\n",
+ __func__);
+ break;
+ }
+ qt2_process_xmit_empty(port, ch + 3);
+ i += 4;
+ escapeflag = true;
+ break;
+ case QT2_CHANGE_PORT:
+ if (i > (len - 4)) {
+ dev_warn(&port->dev,
+ "%s - change_port message too short\n",
+ __func__);
+ break;
+ }
+ if (tty) {
+ tty_flip_buffer_push(tty);
+ tty_kref_put(tty);
+ }
+
+ newport = *(ch + 3);
+
+ if (newport > serial->num_ports) {
+ dev_err(&port->dev,
+ "%s - port change to invalid port: %i\n",
+ __func__, newport);
+ break;
+ }
+
+ serial_priv->current_port = newport;
+ port = serial->port[serial_priv->current_port];
+ port_priv = usb_get_serial_port_data(port);
+ if (port_priv->is_open)
+ tty = tty_port_tty_get(&port->port);
+ else
+ tty = NULL;
+ i += 3;
+ escapeflag = true;
+ break;
+ case QT2_REC_FLUSH:
+ case QT2_XMIT_FLUSH:
+ qt2_process_flush(port, ch + 2);
+ i += 2;
+ escapeflag = true;
+ break;
+ case QT2_CONTROL_ESCAPE:
+ tty_buffer_request_room(tty, 2);
+ tty_insert_flip_string(tty, ch, 2);
+ i += 2;
+ escapeflag = true;
+ break;
+ default:
+ dev_warn(&port->dev,
+ "%s - unsupported command %i\n",
+ __func__, *(ch + 2));
+ break;
+ }
+ if (escapeflag)
+ continue;
+ }
+
+ if (tty) {
+ tty_buffer_request_room(tty, 1);
+ tty_insert_flip_string(tty, ch, 1);
+ }
+ }
+
+ if (tty) {
+ tty_flip_buffer_push(tty);
+ tty_kref_put(tty);
+ }
+}
+
+static void qt2_write_bulk_callback(struct urb *urb)
+{
+ struct usb_serial_port *port;
+ struct qt2_port_private *port_priv;
+
+ port = urb->context;
+ port_priv = usb_get_serial_port_data(port);
+
+ spin_lock(&port_priv->urb_lock);
+
+ port_priv->urb_in_use = false;
+ usb_serial_port_softint(port);
+
+ spin_unlock(&port_priv->urb_lock);
+
+}
+
+static void qt2_read_bulk_callback(struct urb *urb)
+{
+ struct usb_serial *serial = urb->context;
+ int status;
+
+ if (urb->status) {
+ dev_warn(&serial->dev->dev,
+ "%s - non-zero urb status: %i\n", __func__,
+ urb->status);
+ return;
+ }
+
+ qt2_process_read_urb(urb);
+
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status != 0)
+ dev_err(&serial->dev->dev,
+ "%s - resubmit read urb failed: %i\n",
+ __func__, status);
+}
+
+static int qt2_setup_urbs(struct usb_serial *serial)
+{
+ struct usb_serial_port *port;
+ struct usb_serial_port *port0;
+ struct qt2_serial_private *serial_priv;
+ struct qt2_port_private *port_priv;
+ int pcount, status;
+
+ port0 = serial->port[0];
+
+ serial_priv = usb_get_serial_data(serial);
+ serial_priv->read_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!serial_priv->read_urb) {
+ dev_err(&serial->dev->dev, "No free urbs available\n");
+ return -ENOMEM;
+ }
+
+ usb_fill_bulk_urb(serial_priv->read_urb, serial->dev,
+ usb_rcvbulkpipe(serial->dev,
+ port0->bulk_in_endpointAddress),
+ serial_priv->read_buffer,
+ sizeof(serial_priv->read_buffer),
+ qt2_read_bulk_callback, serial);
+
+ /* setup write_urb for each port */
+ for (pcount = 0; pcount < serial->num_ports; pcount++) {
+
+ port = serial->port[pcount];
+ port_priv = usb_get_serial_port_data(port);
+
+ port_priv->write_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!port_priv->write_urb) {
+ dev_err(&serial->dev->dev,
+ "failed to alloc write_urb for port %i\n",
+ pcount);
+ return -ENOMEM;
+ }
+
+ usb_fill_bulk_urb(port_priv->write_urb,
+ serial->dev,
+ usb_sndbulkpipe(serial->dev,
+ port0->
+ bulk_out_endpointAddress),
+ port_priv->write_buffer,
+ sizeof(port_priv->write_buffer),
+ qt2_write_bulk_callback, port);
+ }
+
+ status = usb_submit_urb(serial_priv->read_urb, GFP_KERNEL);
+ if (status != 0) {
+ dev_err(&serial->dev->dev,
+ "%s - submit read urb failed %i\n", __func__, status);
+ return status;
+ }
+
+ return 0;
+
+}
+
+static int qt2_attach(struct usb_serial *serial)
+{
+ struct qt2_serial_private *serial_priv;
+ struct qt2_port_private *port_priv;
+ int status, pcount;
+
+ /* power on unit */
+ status = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ 0xc2, 0x40, 0x8000, 0, NULL, 0,
+ QT2_USB_TIMEOUT);
+ if (status < 0) {
+ dev_err(&serial->dev->dev,
+ "%s - failed to power on unit: %i\n", __func__, status);
+ return status;
+ }
+
+ serial_priv = kzalloc(sizeof(*serial_priv), GFP_KERNEL);
+ if (!serial_priv) {
+ dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ usb_set_serial_data(serial, serial_priv);
+
+ for (pcount = 0; pcount < serial->num_ports; pcount++) {
+ port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL);
+ if (!port_priv) {
+ dev_err(&serial->dev->dev,
+ "%s- kmalloc(%Zd) failed.\n", __func__,
+ sizeof(*port_priv));
+ pcount--;
+ status = -ENOMEM;
+ goto attach_failed;
+ }
+
+ spin_lock_init(&port_priv->lock);
+ spin_lock_init(&port_priv->urb_lock);
+ init_waitqueue_head(&port_priv->delta_msr_wait);
+
+ port_priv->port = serial->port[pcount];
+
+ usb_set_serial_port_data(serial->port[pcount], port_priv);
+ }
+
+ status = qt2_setup_urbs(serial);
+ if (status != 0)
+ goto attach_failed;
+
+ return 0;
+
+attach_failed:
+ for (/* empty */; pcount >= 0; pcount--) {
+ port_priv = usb_get_serial_port_data(serial->port[pcount]);
+ kfree(port_priv);
+ }
+ kfree(serial_priv);
+ return status;
+}
+
+static int qt2_tiocmget(struct tty_struct *tty)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct usb_device *dev = port->serial->dev;
+ struct qt2_port_private *port_priv = usb_get_serial_port_data(port);
+ u8 *d;
+ int r;
+
+ d = kzalloc(2, GFP_KERNEL);
+ if (!d)
+ return -ENOMEM;
+
+ r = qt2_getregister(dev, port_priv->device_port, UART_MCR, d);
+ if (r < 0)
+ goto mget_out;
+
+ r = qt2_getregister(dev, port_priv->device_port, UART_MSR, d + 1);
+ if (r < 0)
+ goto mget_out;
+
+ r = (d[0] & UART_MCR_DTR ? TIOCM_DTR : 0) |
+ (d[0] & UART_MCR_RTS ? TIOCM_RTS : 0) |
+ (d[1] & UART_MSR_CTS ? TIOCM_CTS : 0) |
+ (d[1] & UART_MSR_DCD ? TIOCM_CAR : 0) |
+ (d[1] & UART_MSR_RI ? TIOCM_RI : 0) |
+ (d[1] & UART_MSR_DSR ? TIOCM_DSR : 0);
+
+mget_out:
+ kfree(d);
+ return r;
+}
+
+static int qt2_tiocmset(struct tty_struct *tty,
+ unsigned int set, unsigned int clear)
+{
+ struct qt2_port_private *port_priv;
+
+ port_priv = usb_get_serial_port_data(tty->driver_data);
+ return update_mctrl(port_priv, set, clear);
+}
+
+static void qt2_break_ctl(struct tty_struct *tty, int break_state)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct qt2_port_private *port_priv;
+ int status;
+ u16 val;
+
+ port_priv = usb_get_serial_port_data(port);
+
+ if (!port_priv->is_open) {
+ dev_err(&port->dev,
+ "%s - port is not open\n", __func__);
+ return;
+ }
+
+ val = (break_state == -1) ? 1 : 0;
+
+ status = qt2_control_msg(port->serial->dev, QT2_BREAK_CONTROL,
+ val, port_priv->device_port);
+ if (status < 0)
+ dev_warn(&port->dev,
+ "%s - failed to send control message: %i\n", __func__,
+ status);
+}
+
+
+
+static void qt2_dtr_rts(struct usb_serial_port *port, int on)
+{
+ struct usb_device *dev = port->serial->dev;
+ struct qt2_port_private *port_priv = usb_get_serial_port_data(port);
+
+ mutex_lock(&port->serial->disc_mutex);
+ if (!port->serial->disconnected) {
+ /* Disable flow control */
+ if (!on && qt2_setregister(dev, port_priv->device_port,
+ UART_MCR, 0) < 0)
+ dev_warn(&port->dev, "error from flowcontrol urb\n");
+ /* drop RTS and DTR */
+ if (on)
+ update_mctrl(port_priv, TIOCM_DTR | TIOCM_RTS, 0);
+ else
+ update_mctrl(port_priv, 0, TIOCM_DTR | TIOCM_RTS);
+ }
+ mutex_unlock(&port->serial->disc_mutex);
+}
+
+static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch)
+{
+ struct qt2_port_private *port_priv;
+ u8 newMSR = (u8) *ch;
+ unsigned long flags;
+
+ port_priv = usb_get_serial_port_data(port);
+
+ spin_lock_irqsave(&port_priv->lock, flags);
+ port_priv->shadowMSR = newMSR;
+ spin_unlock_irqrestore(&port_priv->lock, flags);
+
+ if (newMSR & UART_MSR_ANY_DELTA) {
+ /* update input line counters */
+ if (newMSR & UART_MSR_DCTS)
+ port_priv->icount.cts++;
+
+ if (newMSR & UART_MSR_DDSR)
+ port_priv->icount.dsr++;
+
+ if (newMSR & UART_MSR_DDCD)
+ port_priv->icount.dcd++;
+
+ if (newMSR & UART_MSR_TERI)
+ port_priv->icount.rng++;
+
+ wake_up_interruptible(&port_priv->delta_msr_wait);
+ }
+}
+
+static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch)
+{
+ struct qt2_port_private *port_priv;
+ struct async_icount *icount;
+ unsigned long flags;
+ u8 newLSR = (u8) *ch;
+
+ port_priv = usb_get_serial_port_data(port);
+
+ if (newLSR & UART_LSR_BI)
+ newLSR &= (u8) (UART_LSR_OE | UART_LSR_BI);
+
+ spin_lock_irqsave(&port_priv->lock, flags);
+ port_priv->shadowLSR = newLSR;
+ spin_unlock_irqrestore(&port_priv->lock, flags);
+
+ icount = &port_priv->icount;
+
+ if (newLSR & UART_LSR_BRK_ERROR_BITS) {
+
+ if (newLSR & UART_LSR_BI)
+ icount->brk++;
+
+ if (newLSR & UART_LSR_OE)
+ icount->overrun++;
+
+ if (newLSR & UART_LSR_PE)
+ icount->parity++;
+
+ if (newLSR & UART_LSR_FE)
+ icount->frame++;
+ }
+
+}
+
+static int qt2_write_room(struct tty_struct *tty)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct qt2_port_private *port_priv;
+ unsigned long flags = 0;
+ int r;
+
+ port_priv = usb_get_serial_port_data(port);
+
+ spin_lock_irqsave(&port_priv->urb_lock, flags);
+
+ if (port_priv->urb_in_use)
+ r = 0;
+ else
+ r = QT2_WRITE_BUFFER_SIZE - QT2_WRITE_CONTROL_SIZE;
+
+ spin_unlock_irqrestore(&port_priv->urb_lock, flags);
+
+ return r;
+}
+
+static int qt2_write(struct tty_struct *tty,
+ struct usb_serial_port *port,
+ const unsigned char *buf, int count)
+{
+ struct qt2_port_private *port_priv;
+ struct urb *write_urb;
+ unsigned char *data;
+ unsigned long flags;
+ int status;
+ int bytes_out = 0;
+
+ port_priv = usb_get_serial_port_data(port);
+
+ if (port_priv->write_urb == NULL) {
+ dev_err(&port->dev, "%s - no output urb\n", __func__);
+ return 0;
+ }
+ write_urb = port_priv->write_urb;
+
+ count = min(count, QT2_WRITE_BUFFER_SIZE - QT2_WRITE_CONTROL_SIZE);
+
+ data = write_urb->transfer_buffer;
+ spin_lock_irqsave(&port_priv->urb_lock, flags);
+ if (port_priv->urb_in_use == true) {
+ printk(KERN_INFO "qt2_write - urb is in use\n");
+ goto write_out;
+ }
+
+ *data++ = QT2_CONTROL_BYTE;
+ *data++ = QT2_CONTROL_BYTE;
+ *data++ = port_priv->device_port;
+ put_unaligned_le16(count, data);
+ data += 2;
+ memcpy(data, buf, count);
+
+ write_urb->transfer_buffer_length = count + QT2_WRITE_CONTROL_SIZE;
+
+ status = usb_submit_urb(write_urb, GFP_ATOMIC);
+ if (status == 0) {
+ port_priv->urb_in_use = true;
+ bytes_out += count;
+ }
+
+write_out:
+ spin_unlock_irqrestore(&port_priv->urb_lock, flags);
+ return bytes_out;
+}
+
+
+static struct usb_serial_driver qt2_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "quatech-serial",
+ },
+ .description = DRIVER_DESC,
+ .id_table = id_table,
+ .open = qt2_open,
+ .close = qt2_close,
+ .write = qt2_write,
+ .write_room = qt2_write_room,
+ .calc_num_ports = qt2_calc_num_ports,
+ .attach = qt2_attach,
+ .release = qt2_release,
+ .disconnect = qt2_disconnect,
+ .dtr_rts = qt2_dtr_rts,
+ .break_ctl = qt2_break_ctl,
+ .tiocmget = qt2_tiocmget,
+ .tiocmset = qt2_tiocmset,
+ .get_icount = qt2_get_icount,
+ .ioctl = qt2_ioctl,
+ .set_termios = qt2_set_termios,
+};
+
+static struct usb_serial_driver *const serial_drivers[] = {
+ &qt2_device, NULL
+};
+
+module_usb_serial_driver(serial_drivers, id_table);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index ae4ee30c7411..36e9d9fc0618 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -151,13 +151,6 @@ static struct usb_device_id id_table[] = {
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver safe_driver = {
- .name = "safe_serial",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static const __u16 crc10_table[256] = {
0x000, 0x233, 0x255, 0x066, 0x299, 0x0aa, 0x0cc, 0x2ff,
0x301, 0x132, 0x154, 0x367, 0x198, 0x3ab, 0x3cd, 0x1fe,
@@ -339,12 +332,12 @@ static int __init safe_init(void)
}
}
- return usb_serial_register_drivers(&safe_driver, serial_drivers);
+ return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table);
}
static void __exit safe_exit(void)
{
- usb_serial_deregister_drivers(&safe_driver, serial_drivers);
+ usb_serial_deregister_drivers(serial_drivers);
}
module_init(safe_init);
diff --git a/drivers/usb/serial/siemens_mpi.c b/drivers/usb/serial/siemens_mpi.c
index 46c0430fd38b..e4a1787cdbac 100644
--- a/drivers/usb/serial/siemens_mpi.c
+++ b/drivers/usb/serial/siemens_mpi.c
@@ -29,13 +29,6 @@ static const struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver siemens_usb_mpi_driver = {
- .name = "siemens_mpi",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver siemens_usb_mpi_device = {
.driver = {
.owner = THIS_MODULE,
@@ -49,7 +42,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&siemens_usb_mpi_device, NULL
};
-module_usb_serial_driver(siemens_usb_mpi_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 8c8bf806f6fa..ba54a0a8235c 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -63,9 +63,7 @@ struct sierra_intf_private {
static int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
{
- int result;
- dev_dbg(&udev->dev, "%s\n", __func__);
- result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
SWIMS_USB_REQUEST_SetPower, /* __u8 request */
USB_TYPE_VENDOR, /* __u8 request type */
swiState, /* __u16 value */
@@ -73,14 +71,11 @@ static int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
NULL, /* void *data */
0, /* __u16 size */
USB_CTRL_SET_TIMEOUT); /* int timeout */
- return result;
}
static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable)
{
- int result;
- dev_dbg(&udev->dev, "%s\n", __func__);
- result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
SWIMS_USB_REQUEST_SetNmea, /* __u8 request */
USB_TYPE_VENDOR, /* __u8 request type */
enable, /* __u16 value */
@@ -88,7 +83,6 @@ static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable)
NULL, /* void *data */
0, /* __u16 size */
USB_CTRL_SET_TIMEOUT); /* int timeout */
- return result;
}
static int sierra_calc_num_ports(struct usb_serial *serial)
@@ -96,8 +90,6 @@ static int sierra_calc_num_ports(struct usb_serial *serial)
int num_ports = 0;
u8 ifnum, numendpoints;
- dev_dbg(&serial->dev->dev, "%s\n", __func__);
-
ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
numendpoints = serial->interface->cur_altsetting->desc.bNumEndpoints;
@@ -150,7 +142,6 @@ static int sierra_calc_interface(struct usb_serial *serial)
int interface;
struct usb_interface *p_interface;
struct usb_host_interface *p_host_interface;
- dev_dbg(&serial->dev->dev, "%s\n", __func__);
/* Get the interface structure pointer from the serial struct */
p_interface = serial->interface;
@@ -175,9 +166,8 @@ static int sierra_probe(struct usb_serial *serial,
u8 ifnum;
udev = serial->dev;
- dev_dbg(&udev->dev, "%s\n", __func__);
-
ifnum = sierra_calc_interface(serial);
+
/*
* If this interface supports more than 1 alternate
* select the 2nd one
@@ -344,8 +334,6 @@ static int sierra_send_setup(struct usb_serial_port *port)
int do_send = 0;
int retval;
- dev_dbg(&port->dev, "%s\n", __func__);
-
portdata = usb_get_serial_port_data(port);
if (portdata->dtr_state)
@@ -393,7 +381,6 @@ static int sierra_send_setup(struct usb_serial_port *port)
static void sierra_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old_termios)
{
- dev_dbg(&port->dev, "%s\n", __func__);
tty_termios_copy_hw(tty->termios, old_termios);
sierra_send_setup(port);
}
@@ -404,7 +391,6 @@ static int sierra_tiocmget(struct tty_struct *tty)
unsigned int value;
struct sierra_port_private *portdata;
- dev_dbg(&port->dev, "%s\n", __func__);
portdata = usb_get_serial_port_data(port);
value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
@@ -441,8 +427,7 @@ static void sierra_release_urb(struct urb *urb)
{
struct usb_serial_port *port;
if (urb) {
- port = urb->context;
- dev_dbg(&port->dev, "%s: %p\n", __func__, urb);
+ port = urb->context;
kfree(urb->transfer_buffer);
usb_free_urb(urb);
}
@@ -455,7 +440,6 @@ static void sierra_outdat_callback(struct urb *urb)
struct sierra_intf_private *intfdata;
int status = urb->status;
- dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number);
intfdata = port->serial->private;
/* free up the transfer buffer, as usb_free_urb() does not do this */
@@ -598,8 +582,6 @@ static void sierra_indat_callback(struct urb *urb)
endpoint = usb_pipeendpoint(urb->pipe);
port = urb->context;
- dev_dbg(&port->dev, "%s: %p\n", __func__, urb);
-
if (status) {
dev_dbg(&port->dev, "%s: nonzero status: %d on"
" endpoint %02x\n", __func__, status, endpoint);
@@ -697,8 +679,6 @@ static int sierra_write_room(struct tty_struct *tty)
struct sierra_port_private *portdata = usb_get_serial_port_data(port);
unsigned long flags;
- dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number);
-
/* try to give a good number back based on if we have any free urbs at
* this point in time */
spin_lock_irqsave(&portdata->lock, flags);
@@ -805,8 +785,6 @@ static void sierra_close(struct usb_serial_port *port)
struct sierra_port_private *portdata;
struct sierra_intf_private *intfdata = port->serial->private;
-
- dev_dbg(&port->dev, "%s\n", __func__);
portdata = usb_get_serial_port_data(port);
portdata->rts_state = 0;
@@ -851,8 +829,6 @@ static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port)
portdata = usb_get_serial_port_data(port);
- dev_dbg(&port->dev, "%s\n", __func__);
-
/* Set some sane defaults */
portdata->rts_state = 1;
portdata->dtr_state = 1;
@@ -915,8 +891,6 @@ static int sierra_startup(struct usb_serial *serial)
int i;
u8 ifnum;
- dev_dbg(&serial->dev->dev, "%s\n", __func__);
-
/* Set Device mode to D0 */
sierra_set_power_state(serial->dev, 0x0000);
@@ -977,8 +951,6 @@ static void sierra_release(struct usb_serial *serial)
struct usb_serial_port *port;
struct sierra_port_private *portdata;
- dev_dbg(&serial->dev->dev, "%s\n", __func__);
-
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
if (!port)
@@ -1067,29 +1039,11 @@ static int sierra_resume(struct usb_serial *serial)
return ec ? -EIO : 0;
}
-static int sierra_reset_resume(struct usb_interface *intf)
-{
- struct usb_serial *serial = usb_get_intfdata(intf);
- dev_err(&serial->dev->dev, "%s\n", __func__);
- return usb_serial_resume(intf);
-}
#else
#define sierra_suspend NULL
#define sierra_resume NULL
-#define sierra_reset_resume NULL
#endif
-static struct usb_driver sierra_driver = {
- .name = "sierra",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .suspend = usb_serial_suspend,
- .resume = usb_serial_resume,
- .reset_resume = sierra_reset_resume,
- .id_table = id_table,
- .supports_autosuspend = 1,
-};
-
static struct usb_serial_driver sierra_device = {
.driver = {
.owner = THIS_MODULE,
@@ -1118,7 +1072,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&sierra_device, NULL
};
-module_usb_serial_driver(sierra_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index f06c9a8f3d37..cad608984710 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -151,14 +151,6 @@ enum spcp8x5_type {
SPCP835_TYPE,
};
-static struct usb_driver spcp8x5_driver = {
- .name = "spcp8x5",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
-
struct spcp8x5_private {
spinlock_t lock;
enum spcp8x5_type type;
@@ -433,7 +425,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
if (i < 0)
dev_err(&port->dev, "Set UART format %#x failed (error = %d)\n",
uartdata, i);
- dbg("0x21:0x40:0:0 %d", i);
+ dev_dbg(&port->dev, "0x21:0x40:0:0 %d\n", i);
if (cflag & CRTSCTS) {
/* enable hardware flow control */
@@ -454,8 +446,6 @@ static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port)
u8 status = 0x30;
/* status 0x30 means DSR and CTS = 1 other CDC RI and delta = 0 */
- dbg("%s - port %d", __func__, port->number);
-
usb_clear_halt(serial->dev, port->write_urb->pipe);
usb_clear_halt(serial->dev, port->read_urb->pipe);
@@ -579,15 +569,19 @@ static int spcp8x5_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
struct usb_serial_port *port = tty->driver_data;
- dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
+
+ dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__,
+ port->number, cmd);
switch (cmd) {
case TIOCMIWAIT:
- dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
+ dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__,
+ port->number);
return spcp8x5_wait_modem_info(port, arg);
default:
- dbg("%s not supported = 0x%04x", __func__, cmd);
+ dev_dbg(&port->dev, "%s not supported = 0x%04x", __func__,
+ cmd);
break;
}
@@ -666,7 +660,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&spcp8x5_device, NULL
};
-module_usb_serial_driver(spcp8x5_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c
index 3cdc8a52de44..3fee23bf0c14 100644
--- a/drivers/usb/serial/ssu100.c
+++ b/drivers/usb/serial/ssu100.c
@@ -59,20 +59,8 @@ static const struct usb_device_id id_table[] = {
{USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU100)},
{} /* Terminating entry */
};
-
MODULE_DEVICE_TABLE(usb, id_table);
-
-static struct usb_driver ssu100_driver = {
- .name = "ssu100",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
- .suspend = usb_serial_suspend,
- .resume = usb_serial_resume,
- .supports_autosuspend = 1,
-};
-
struct ssu100_port_private {
spinlock_t status_lock;
u8 shadowLSR;
@@ -85,7 +73,6 @@ static void ssu100_release(struct usb_serial *serial)
{
struct ssu100_port_private *priv = usb_get_serial_port_data(*serial->port);
- dbg("%s", __func__);
kfree(priv);
}
@@ -171,8 +158,6 @@ static int ssu100_initdevice(struct usb_device *dev)
u8 *data;
int result = 0;
- dbg("%s", __func__);
-
data = kzalloc(3, GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -237,8 +222,6 @@ static void ssu100_set_termios(struct tty_struct *tty,
u16 urb_value = 0; /* will hold the new flags */
int result;
- dbg("%s", __func__);
-
if (cflag & PARENB) {
if (cflag & PARODD)
urb_value |= UART_LCR_PARITY;
@@ -312,8 +295,6 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port)
int result;
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
data = kzalloc(2, GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -348,7 +329,6 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port)
static void ssu100_close(struct usb_serial_port *port)
{
- dbg("%s", __func__);
usb_serial_generic_close(port);
}
@@ -467,8 +447,6 @@ static int ssu100_attach(struct usb_serial *serial)
struct ssu100_port_private *priv;
struct usb_serial_port *port = *serial->port;
- dbg("%s", __func__);
-
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__,
@@ -490,8 +468,6 @@ static int ssu100_tiocmget(struct tty_struct *tty)
u8 *d;
int r;
- dbg("%s\n", __func__);
-
d = kzalloc(2, GFP_KERNEL);
if (!d)
return -ENOMEM;
@@ -522,7 +498,6 @@ static int ssu100_tiocmset(struct tty_struct *tty,
struct usb_serial_port *port = tty->driver_data;
struct usb_device *dev = port->serial->dev;
- dbg("%s\n", __func__);
return update_mctrl(dev, set, clear);
}
@@ -530,8 +505,6 @@ static void ssu100_dtr_rts(struct usb_serial_port *port, int on)
{
struct usb_device *dev = port->serial->dev;
- dbg("%s\n", __func__);
-
mutex_lock(&port->serial->disc_mutex);
if (!port->serial->disconnected) {
/* Disable flow control */
@@ -618,8 +591,6 @@ static int ssu100_process_packet(struct urb *urb,
int i;
char *ch;
- dbg("%s - port %d", __func__, port->number);
-
if ((len >= 4) &&
(packet[0] == 0x1b) && (packet[1] == 0x1b) &&
((packet[2] == 0x00) || (packet[2] == 0x01))) {
@@ -656,8 +627,6 @@ static void ssu100_process_read_urb(struct urb *urb)
struct tty_struct *tty;
int count;
- dbg("%s", __func__);
-
tty = tty_port_tty_get(&port->port);
if (!tty)
return;
@@ -695,7 +664,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&ssu100_device, NULL
};
-module_usb_serial_driver(ssu100_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c
index 1a5be136e6cf..e53d2aac35c5 100644
--- a/drivers/usb/serial/symbolserial.c
+++ b/drivers/usb/serial/symbolserial.c
@@ -54,8 +54,6 @@ static void symbol_int_callback(struct urb *urb)
int result;
int data_length;
- dbg("%s - port %d", __func__, port->number);
-
switch (status) {
case 0:
/* success */
@@ -64,12 +62,12 @@ static void symbol_int_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __func__, status);
+ dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
+ __func__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d",
- __func__, status);
+ dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
+ __func__, status);
goto exit;
}
@@ -125,8 +123,6 @@ static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port)
unsigned long flags;
int result = 0;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irqsave(&priv->lock, flags);
priv->throttled = false;
priv->actually_throttled = false;
@@ -150,8 +146,6 @@ static void symbol_close(struct usb_serial_port *port)
{
struct symbol_private *priv = usb_get_serial_data(port->serial);
- dbg("%s - port %d", __func__, port->number);
-
/* shutdown our urbs */
usb_kill_urb(priv->int_urb);
}
@@ -161,7 +155,6 @@ static void symbol_throttle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
struct symbol_private *priv = usb_get_serial_data(port->serial);
- dbg("%s - port %d", __func__, port->number);
spin_lock_irq(&priv->lock);
priv->throttled = true;
spin_unlock_irq(&priv->lock);
@@ -174,8 +167,6 @@ static void symbol_unthrottle(struct tty_struct *tty)
int result;
bool was_throttled;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irq(&priv->lock);
priv->throttled = false;
was_throttled = priv->actually_throttled;
@@ -266,8 +257,6 @@ static void symbol_disconnect(struct usb_serial *serial)
{
struct symbol_private *priv = usb_get_serial_data(serial);
- dbg("%s", __func__);
-
usb_kill_urb(priv->int_urb);
usb_free_urb(priv->int_urb);
}
@@ -276,19 +265,10 @@ static void symbol_release(struct usb_serial *serial)
{
struct symbol_private *priv = usb_get_serial_data(serial);
- dbg("%s", __func__);
-
kfree(priv->int_buffer);
kfree(priv);
}
-static struct usb_driver symbol_driver = {
- .name = "symbol",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver symbol_device = {
.driver = {
.owner = THIS_MODULE,
@@ -309,7 +289,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&symbol_device, NULL
};
-module_usb_serial_driver(symbol_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index ab74123d658e..a4404f5ad68e 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -165,7 +165,7 @@ static unsigned int product_5052_count;
/* the array dimension is the number of default entries plus */
/* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */
/* null entry */
-static struct usb_device_id ti_id_table_3410[14+TI_EXTRA_VID_PID_COUNT+1] = {
+static struct usb_device_id ti_id_table_3410[15+TI_EXTRA_VID_PID_COUNT+1] = {
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
{ USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
@@ -180,6 +180,7 @@ static struct usb_device_id ti_id_table_3410[14+TI_EXTRA_VID_PID_COUNT+1] = {
{ USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) },
{ USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) },
{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) },
+ { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
};
static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = {
@@ -189,7 +190,7 @@ static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = {
{ USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) },
};
-static struct usb_device_id ti_id_table_combined[18+2*TI_EXTRA_VID_PID_COUNT+1] = {
+static struct usb_device_id ti_id_table_combined[19+2*TI_EXTRA_VID_PID_COUNT+1] = {
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
{ USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
@@ -208,16 +209,10 @@ static struct usb_device_id ti_id_table_combined[18+2*TI_EXTRA_VID_PID_COUNT+1]
{ USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) },
{ USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) },
{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) },
+ { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
{ }
};
-static struct usb_driver ti_usb_driver = {
- .name = "ti_usb_3410_5052",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = ti_id_table_combined,
-};
-
static struct usb_serial_driver ti_1port_device = {
.driver = {
.owner = THIS_MODULE,
@@ -344,20 +339,18 @@ static int __init ti_init(void)
ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
}
- ret = usb_serial_register_drivers(&ti_usb_driver, serial_drivers);
+ ret = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ti_id_table_combined);
if (ret == 0)
printk(KERN_INFO KBUILD_MODNAME ": " TI_DRIVER_VERSION ":"
TI_DRIVER_DESC "\n");
return ret;
}
-
static void __exit ti_exit(void)
{
- usb_serial_deregister_drivers(&ti_usb_driver, serial_drivers);
+ usb_serial_deregister_drivers(serial_drivers);
}
-
module_init(ti_init);
module_exit(ti_exit);
@@ -394,7 +387,9 @@ static int ti_startup(struct usb_serial *serial)
/* if we have only 1 configuration, download firmware */
if (dev->descriptor.bNumConfigurations == 1) {
- if ((status = ti_download_firmware(tdev)) != 0)
+ status = ti_download_firmware(tdev);
+
+ if (status != 0)
goto free_tdev;
/* 3410 must be reset, 5052 resets itself */
@@ -463,8 +458,6 @@ static void ti_release(struct usb_serial *serial)
struct ti_device *tdev = usb_get_serial_data(serial);
struct ti_port *tport;
- dbg("%s", __func__);
-
for (i = 0; i < serial->num_ports; ++i) {
tport = usb_get_serial_port_data(serial->port[i]);
if (tport) {
@@ -489,8 +482,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
TI_PIPE_TIMEOUT_ENABLE |
(TI_TRANSFER_TIMEOUT << 2));
- dbg("%s - port %d", __func__, port->number);
-
if (tport == NULL)
return -ENODEV;
@@ -631,8 +622,6 @@ static void ti_close(struct usb_serial_port *port)
int status;
int do_unlock;
- dbg("%s - port %d", __func__, port->number);
-
tdev = usb_get_serial_data(port->serial);
tport = usb_get_serial_port_data(port);
if (tdev == NULL || tport == NULL)
@@ -666,8 +655,6 @@ static void ti_close(struct usb_serial_port *port)
}
if (do_unlock)
mutex_unlock(&tdev->td_open_close_lock);
-
- dbg("%s - exit", __func__);
}
@@ -676,8 +663,6 @@ static int ti_write(struct tty_struct *tty, struct usb_serial_port *port,
{
struct ti_port *tport = usb_get_serial_port_data(port);
- dbg("%s - port %d", __func__, port->number);
-
if (count == 0) {
dbg("%s - write request of 0 bytes", __func__);
return 0;
@@ -701,8 +686,6 @@ static int ti_write_room(struct tty_struct *tty)
int room = 0;
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
if (tport == NULL)
return 0;
@@ -722,8 +705,6 @@ static int ti_chars_in_buffer(struct tty_struct *tty)
int chars = 0;
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
if (tport == NULL)
return 0;
@@ -741,8 +722,6 @@ static void ti_throttle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
struct ti_port *tport = usb_get_serial_port_data(port);
- dbg("%s - port %d", __func__, port->number);
-
if (tport == NULL)
return;
@@ -758,8 +737,6 @@ static void ti_unthrottle(struct tty_struct *tty)
struct ti_port *tport = usb_get_serial_port_data(port);
int status;
- dbg("%s - port %d", __func__, port->number);
-
if (tport == NULL)
return;
@@ -854,8 +831,6 @@ static void ti_set_termios(struct tty_struct *tty,
int port_number = port->number - port->serial->minor;
unsigned int mcr;
- dbg("%s - port %d", __func__, port->number);
-
cflag = tty->termios->c_cflag;
iflag = tty->termios->c_iflag;
@@ -988,8 +963,6 @@ static int ti_tiocmget(struct tty_struct *tty)
unsigned int mcr;
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
if (tport == NULL)
return -ENODEV;
@@ -1020,8 +993,6 @@ static int ti_tiocmset(struct tty_struct *tty,
unsigned int mcr;
unsigned long flags;
- dbg("%s - port %d", __func__, port->number);
-
if (tport == NULL)
return -ENODEV;
@@ -1084,8 +1055,6 @@ static void ti_interrupt_callback(struct urb *urb)
int retval;
__u8 msr;
- dbg("%s", __func__);
-
switch (status) {
case 0:
break;
@@ -1165,8 +1134,6 @@ static void ti_bulk_in_callback(struct urb *urb)
int retval = 0;
struct tty_struct *tty;
- dbg("%s", __func__);
-
switch (status) {
case 0:
break;
@@ -1233,8 +1200,6 @@ static void ti_bulk_out_callback(struct urb *urb)
struct usb_serial_port *port = tport->tp_port;
int status = urb->status;
- dbg("%s - port %d", __func__, port->number);
-
tport->tp_write_urb_in_use = 0;
switch (status) {
@@ -1287,9 +1252,6 @@ static void ti_send(struct ti_port *tport)
struct tty_struct *tty = tty_port_tty_get(&port->port); /* FIXME */
unsigned long flags;
-
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irqsave(&tport->tp_lock, flags);
if (tport->tp_write_urb_in_use)
@@ -1366,8 +1328,6 @@ static int ti_get_lsr(struct ti_port *tport)
int port_number = port->number - port->serial->minor;
struct ti_port_status *data;
- dbg("%s - port %d", __func__, port->number);
-
size = sizeof(struct ti_port_status);
data = kmalloc(size, GFP_KERNEL);
if (!data) {
@@ -1480,8 +1440,6 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush)
struct usb_serial_port *port = tport->tp_port;
wait_queue_t wait;
- dbg("%s - port %d", __func__, port->number);
-
spin_lock_irq(&tport->tp_lock);
/* wait for data to drain from the buffer */
@@ -1679,11 +1637,12 @@ static int ti_download_firmware(struct ti_device *tdev)
const struct firmware *fw_p;
char buf[32];
- dbg("%s\n", __func__);
/* try ID specific firmware first, then try generic firmware */
sprintf(buf, "ti_usb-v%04x-p%04x.fw", dev->descriptor.idVendor,
dev->descriptor.idProduct);
- if ((status = request_firmware(&fw_p, buf, &dev->dev)) != 0) {
+ status = request_firmware(&fw_p, buf, &dev->dev);
+
+ if (status != 0) {
buf[0] = '\0';
if (dev->descriptor.idVendor == MTS_VENDOR_ID) {
switch (dev->descriptor.idProduct) {
diff --git a/drivers/usb/serial/ti_usb_3410_5052.h b/drivers/usb/serial/ti_usb_3410_5052.h
index f140f1b9d5c0..b353e7e3d480 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.h
+++ b/drivers/usb/serial/ti_usb_3410_5052.h
@@ -37,6 +37,7 @@
#define TI_5152_BOOT_PRODUCT_ID 0x5152 /* no EEPROM, no firmware */
#define TI_5052_EEPROM_PRODUCT_ID 0x505A /* EEPROM, no firmware */
#define TI_5052_FIRMWARE_PRODUCT_ID 0x505F /* firmware is running */
+#define FRI2_PRODUCT_ID 0x5053 /* Fish River Island II */
/* Multi-Tech vendor and product ids */
#define MTS_VENDOR_ID 0x06E0
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 97355a15bbea..6a1b609a0d94 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -1,7 +1,7 @@
/*
* USB Serial Converter driver
*
- * Copyright (C) 1999 - 2005 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 1999 - 2012 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (C) 2000 Peter Berger (pberger@brimson.com)
* Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com)
*
@@ -43,17 +43,6 @@
#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/"
#define DRIVER_DESC "USB Serial Driver core"
-/* Driver structure we register with the USB core */
-static struct usb_driver usb_serial_driver = {
- .name = "usbserial",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .suspend = usb_serial_suspend,
- .resume = usb_serial_resume,
- .no_dynamic_id = 1,
- .supports_autosuspend = 1,
-};
-
/* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead
the MODULE_DEVICE_TABLE declarations in each serial driver
cause the "hotplug" program to pull in whatever module is necessary
@@ -710,7 +699,7 @@ static const struct tty_port_operations serial_port_ops = {
.shutdown = serial_down,
};
-int usb_serial_probe(struct usb_interface *interface,
+static int usb_serial_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(interface);
@@ -856,6 +845,8 @@ int usb_serial_probe(struct usb_interface *interface,
module_put(type->driver.owner);
return -EIO;
}
+ dev_info(&interface->dev, "The \"generic\" usb-serial driver is only for testing and one-off prototypes.\n");
+ dev_info(&interface->dev, "Tell linux-usb@vger.kernel.org to add your device to a proper driver.\n");
}
#endif
if (!num_ports) {
@@ -1043,6 +1034,8 @@ int usb_serial_probe(struct usb_interface *interface,
dbg("the device claims to support interrupt out transfers, but write_int_callback is not defined");
}
+ usb_set_intfdata(interface, serial);
+
/* if this device type has an attach function, call it */
if (type->attach) {
retval = type->attach(serial);
@@ -1087,10 +1080,7 @@ int usb_serial_probe(struct usb_interface *interface,
serial->disconnected = 0;
usb_serial_console_init(debug, minor);
-
exit:
- /* success */
- usb_set_intfdata(interface, serial);
module_put(type->driver.owner);
return 0;
@@ -1099,9 +1089,8 @@ probe_error:
module_put(type->driver.owner);
return -EIO;
}
-EXPORT_SYMBOL_GPL(usb_serial_probe);
-void usb_serial_disconnect(struct usb_interface *interface)
+static void usb_serial_disconnect(struct usb_interface *interface)
{
int i;
struct usb_serial *serial = usb_get_intfdata(interface);
@@ -1112,7 +1101,6 @@ void usb_serial_disconnect(struct usb_interface *interface)
dbg("%s", __func__);
mutex_lock(&serial->disc_mutex);
- usb_set_intfdata(interface, NULL);
/* must set a flag, to signal subdrivers */
serial->disconnected = 1;
mutex_unlock(&serial->disc_mutex);
@@ -1137,7 +1125,6 @@ void usb_serial_disconnect(struct usb_interface *interface)
usb_serial_put(serial);
dev_info(dev, "device disconnected\n");
}
-EXPORT_SYMBOL_GPL(usb_serial_disconnect);
int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
{
@@ -1181,6 +1168,22 @@ int usb_serial_resume(struct usb_interface *intf)
}
EXPORT_SYMBOL(usb_serial_resume);
+static int usb_serial_reset_resume(struct usb_interface *intf)
+{
+ struct usb_serial *serial = usb_get_intfdata(intf);
+ int rv;
+
+ serial->suspending = 0;
+ if (serial->type->reset_resume)
+ rv = serial->type->reset_resume(serial);
+ else {
+ rv = -EOPNOTSUPP;
+ intf->needs_binding = 1;
+ }
+
+ return rv;
+}
+
static const struct tty_operations serial_ops = {
.open = serial_open,
.close = serial_close,
@@ -1204,6 +1207,17 @@ static const struct tty_operations serial_ops = {
struct tty_driver *usb_serial_tty_driver;
+/* Driver structure we register with the USB core */
+static struct usb_driver usb_serial_driver = {
+ .name = "usbserial",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .suspend = usb_serial_suspend,
+ .resume = usb_serial_resume,
+ .no_dynamic_id = 1,
+ .supports_autosuspend = 1,
+};
+
static int __init usb_serial_init(void)
{
int i;
@@ -1338,7 +1352,6 @@ static int usb_serial_register(struct usb_serial_driver *driver)
driver->description);
return -EINVAL;
}
- driver->usb_driver->supports_autosuspend = 1;
/* Add this device to our list of devices */
mutex_lock(&table_lock);
@@ -1369,18 +1382,19 @@ static void usb_serial_deregister(struct usb_serial_driver *device)
/**
* usb_serial_register_drivers - register drivers for a usb-serial module
- * @udriver: usb_driver used for matching devices/interfaces
* @serial_drivers: NULL-terminated array of pointers to drivers to be registered
+ * @name: name of the usb_driver for this set of @serial_drivers
+ * @id_table: list of all devices this @serial_drivers set binds to
*
- * Registers @udriver and all the drivers in the @serial_drivers array.
- * Automatically fills in the .no_dynamic_id field in @udriver and
- * the .usb_driver field in each serial driver.
+ * Registers all the drivers in the @serial_drivers array, and dynamically
+ * creates a struct usb_driver with the name @name and id_table of @id_table.
*/
-int usb_serial_register_drivers(struct usb_driver *udriver,
- struct usb_serial_driver * const serial_drivers[])
+int usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers[],
+ const char *name,
+ const struct usb_device_id *id_table)
{
int rc;
- const struct usb_device_id *saved_id_table;
+ struct usb_driver *udriver;
struct usb_serial_driver * const *sd;
/*
@@ -1391,12 +1405,30 @@ int usb_serial_register_drivers(struct usb_driver *udriver,
* Performance hack: We don't want udriver to be probed until
* the serial drivers are registered, because the probe would
* simply fail for lack of a matching serial driver.
- * Therefore save off udriver's id_table until we are all set.
+ * So we leave udriver's id_table set to NULL until we are all set.
+ *
+ * Suspend/resume support is implemented in the usb-serial core,
+ * so fill in the PM-related fields in udriver.
*/
- saved_id_table = udriver->id_table;
- udriver->id_table = NULL;
+ udriver = kzalloc(sizeof(*udriver), GFP_KERNEL);
+ if (!udriver)
+ return -ENOMEM;
+ udriver->name = name;
udriver->no_dynamic_id = 1;
+ udriver->supports_autosuspend = 1;
+ udriver->suspend = usb_serial_suspend;
+ udriver->resume = usb_serial_resume;
+ udriver->probe = usb_serial_probe;
+ udriver->disconnect = usb_serial_disconnect;
+
+ /* we only set the reset_resume field if the serial_driver has one */
+ for (sd = serial_drivers; *sd; ++sd) {
+ if ((*sd)->reset_resume)
+ udriver->reset_resume = usb_serial_reset_resume;
+ break;
+ }
+
rc = usb_register(udriver);
if (rc)
return rc;
@@ -1408,8 +1440,8 @@ int usb_serial_register_drivers(struct usb_driver *udriver,
goto failed;
}
- /* Now restore udriver's id_table and look for matches */
- udriver->id_table = saved_id_table;
+ /* Now set udriver's id_table and look for matches */
+ udriver->id_table = id_table;
rc = driver_attach(&udriver->drvwrap.driver);
return 0;
@@ -1423,17 +1455,20 @@ EXPORT_SYMBOL_GPL(usb_serial_register_drivers);
/**
* usb_serial_deregister_drivers - deregister drivers for a usb-serial module
- * @udriver: usb_driver to unregister
* @serial_drivers: NULL-terminated array of pointers to drivers to be deregistered
*
- * Deregisters @udriver and all the drivers in the @serial_drivers array.
+ * Deregisters all the drivers in the @serial_drivers array and deregisters and
+ * frees the struct usb_driver that was created by the call to
+ * usb_serial_register_drivers().
*/
-void usb_serial_deregister_drivers(struct usb_driver *udriver,
- struct usb_serial_driver * const serial_drivers[])
+void usb_serial_deregister_drivers(struct usb_serial_driver *const serial_drivers[])
{
+ struct usb_driver *udriver = (*serial_drivers)->usb_driver;
+
for (; *serial_drivers; ++serial_drivers)
usb_serial_deregister(*serial_drivers);
usb_deregister(udriver);
+ kfree(udriver);
}
EXPORT_SYMBOL_GPL(usb_serial_deregister_drivers);
diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c
index e3e8995a4739..5760f97ee508 100644
--- a/drivers/usb/serial/usb_debug.c
+++ b/drivers/usb/serial/usb_debug.c
@@ -35,13 +35,6 @@ static const struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver debug_driver = {
- .name = "debug",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
/* This HW really does not support a serial break, so one will be
* emulated when ever the break state is set to true.
*/
@@ -83,5 +76,5 @@ static struct usb_serial_driver * const serial_drivers[] = {
&debug_device, NULL
};
-module_usb_serial_driver(debug_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index c88657dd31c8..f35971dff4a5 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -43,11 +43,8 @@ void usb_wwan_dtr_rts(struct usb_serial_port *port, int on)
{
struct usb_serial *serial = port->serial;
struct usb_wwan_port_private *portdata;
-
struct usb_wwan_intf_private *intfdata;
- dbg("%s", __func__);
-
intfdata = port->serial->private;
if (!intfdata->send_setup)
@@ -69,8 +66,6 @@ void usb_wwan_set_termios(struct tty_struct *tty,
{
struct usb_wwan_intf_private *intfdata = port->serial->private;
- dbg("%s", __func__);
-
/* Doesn't support option setting */
tty_termios_copy_hw(tty->termios, old_termios);
@@ -286,8 +281,6 @@ static void usb_wwan_indat_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
- dbg("%s: %p", __func__, urb);
-
endpoint = usb_pipeendpoint(urb->pipe);
port = urb->context;
@@ -307,20 +300,17 @@ static void usb_wwan_indat_callback(struct urb *urb)
}
/* Resubmit urb so we continue receiving */
- if (status != -ESHUTDOWN) {
- err = usb_submit_urb(urb, GFP_ATOMIC);
- if (err) {
- if (err != -EPERM) {
- printk(KERN_ERR "%s: resubmit read urb failed. "
- "(%d)", __func__, err);
- /* busy also in error unless we are killed */
- usb_mark_last_busy(port->serial->dev);
- }
- } else {
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err) {
+ if (err != -EPERM) {
+ printk(KERN_ERR "%s: resubmit read urb failed. "
+ "(%d)", __func__, err);
+ /* busy also in error unless we are killed */
usb_mark_last_busy(port->serial->dev);
}
+ } else {
+ usb_mark_last_busy(port->serial->dev);
}
-
}
}
@@ -331,8 +321,6 @@ static void usb_wwan_outdat_callback(struct urb *urb)
struct usb_wwan_intf_private *intfdata;
int i;
- dbg("%s", __func__);
-
port = urb->context;
intfdata = port->serial->private;
@@ -406,8 +394,6 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port)
portdata = usb_get_serial_port_data(port);
intfdata = serial->private;
- dbg("%s", __func__);
-
/* Start reading from the IN endpoint */
for (i = 0; i < N_IN_URB; i++) {
urb = portdata->in_urbs[i];
@@ -441,7 +427,6 @@ void usb_wwan_close(struct usb_serial_port *port)
struct usb_wwan_port_private *portdata;
struct usb_wwan_intf_private *intfdata = port->serial->private;
- dbg("%s", __func__);
portdata = usb_get_serial_port_data(port);
if (serial->dev) {
@@ -492,8 +477,6 @@ static void usb_wwan_setup_urbs(struct usb_serial *serial)
struct usb_serial_port *port;
struct usb_wwan_port_private *portdata;
- dbg("%s", __func__);
-
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
portdata = usb_get_serial_port_data(port);
@@ -534,8 +517,6 @@ int usb_wwan_startup(struct usb_serial *serial)
struct usb_wwan_port_private *portdata;
u8 *buffer;
- dbg("%s", __func__);
-
/* Now setup per port private data */
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
@@ -603,8 +584,6 @@ static void stop_read_write_urbs(struct usb_serial *serial)
void usb_wwan_disconnect(struct usb_serial *serial)
{
- dbg("%s", __func__);
-
stop_read_write_urbs(serial);
}
EXPORT_SYMBOL(usb_wwan_disconnect);
@@ -615,8 +594,6 @@ void usb_wwan_release(struct usb_serial *serial)
struct usb_serial_port *port;
struct usb_wwan_port_private *portdata;
- dbg("%s", __func__);
-
/* Now free them */
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
@@ -649,8 +626,6 @@ int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message)
struct usb_wwan_intf_private *intfdata = serial->private;
int b;
- dbg("%s entered", __func__);
-
if (PMSG_IS_AUTO(message)) {
spin_lock_irq(&intfdata->susp_lock);
b = intfdata->in_flight;
@@ -714,7 +689,6 @@ int usb_wwan_resume(struct usb_serial *serial)
struct urb *urb;
int err = 0;
- dbg("%s entered", __func__);
/* get the interrupt URBs resubmitted unconditionally */
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
@@ -725,8 +699,8 @@ int usb_wwan_resume(struct usb_serial *serial)
err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
dbg("Submitted interrupt URB for port %d (result %d)", i, err);
if (err < 0) {
- err("%s: Error %d for interrupt URB of port%d",
- __func__, err, i);
+ dev_err(&port->dev, "%s: Error %d for interrupt URB\n",
+ __func__, err);
goto err_out;
}
}
@@ -747,8 +721,8 @@ int usb_wwan_resume(struct usb_serial *serial)
urb = portdata->in_urbs[j];
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
- err("%s: Error %d for bulk URB %d",
- __func__, err, i);
+ dev_err(&port->dev, "%s: Error %d for bulk URB %d\n",
+ __func__, err, i);
spin_unlock_irq(&intfdata->susp_lock);
goto err_out;
}
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 71d696474f24..f253c91383da 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -53,8 +53,6 @@ static int palm_os_4_probe(struct usb_serial *serial,
/* Parameters that may be passed into the module. */
static bool debug;
-static __u16 vendor;
-static __u16 product;
static struct usb_device_id id_table [] = {
{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID),
@@ -115,14 +113,12 @@ static struct usb_device_id id_table [] = {
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(FOSSIL_VENDOR_ID, FOSSIL_ABACUS_ID),
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
- { }, /* optional parameter entry */
{ } /* Terminating entry */
};
static struct usb_device_id clie_id_5_table [] = {
{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID),
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
- { }, /* optional parameter entry */
{ } /* Terminating entry */
};
@@ -162,19 +158,11 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID) },
{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_7135_ID) },
{ USB_DEVICE(FOSSIL_VENDOR_ID, FOSSIL_ABACUS_ID) },
- { }, /* optional parameter entry */
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, id_table_combined);
-static struct usb_driver visor_driver = {
- .name = "visor",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table_combined,
-};
-
/* All of the device info needed for the Handspring Visor,
and Palm 4.0 devices */
static struct usb_serial_driver handspring_device = {
@@ -244,8 +232,6 @@ static int visor_open(struct tty_struct *tty, struct usb_serial_port *port)
{
int result = 0;
- dbg("%s - port %d", __func__, port->number);
-
if (!port->read_urb) {
/* this is needed for some brain dead Sony devices */
dev_err(&port->dev, "Device lied about number of ports, please use a lower one.\n");
@@ -258,7 +244,7 @@ static int visor_open(struct tty_struct *tty, struct usb_serial_port *port)
goto exit;
if (port->interrupt_in_urb) {
- dbg("%s - adding interrupt input for treo", __func__);
+ dev_dbg(&port->dev, "adding interrupt input for treo\n");
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result)
dev_err(&port->dev,
@@ -274,8 +260,6 @@ static void visor_close(struct usb_serial_port *port)
{
unsigned char *transfer_buffer;
- dbg("%s - port %d", __func__, port->number);
-
/* shutdown our urbs */
usb_serial_generic_close(port);
usb_kill_urb(port->interrupt_in_urb);
@@ -310,12 +294,12 @@ static void visor_read_int_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __func__, status);
+ dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n",
+ __func__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d",
- __func__, status);
+ dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n",
+ __func__, status);
goto exit;
}
@@ -348,8 +332,6 @@ static int palm_os_3_probe(struct usb_serial *serial,
int i;
int num_ports = 0;
- dbg("%s", __func__);
-
transfer_buffer = kmalloc(sizeof(*connection_info), GFP_KERNEL);
if (!transfer_buffer) {
dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__,
@@ -445,8 +427,6 @@ static int palm_os_4_probe(struct usb_serial *serial,
unsigned char *transfer_buffer;
int retval;
- dbg("%s", __func__);
-
transfer_buffer = kmalloc(sizeof(*connection_info), GFP_KERNEL);
if (!transfer_buffer) {
dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__,
@@ -478,8 +458,6 @@ static int visor_probe(struct usb_serial *serial,
int (*startup)(struct usb_serial *serial,
const struct usb_device_id *id);
- dbg("%s", __func__);
-
/*
* some Samsung Android phones in modem mode have the same ID
* as SPH-I500, but they are ACM devices, so dont bind to them
@@ -521,8 +499,6 @@ static int clie_3_5_startup(struct usb_serial *serial)
int result;
u8 *data;
- dbg("%s", __func__);
-
data = kmalloc(1, GFP_KERNEL);
if (!data)
return -ENOMEM;
@@ -585,8 +561,6 @@ static int treo_attach(struct usb_serial *serial)
(serial->num_interrupt_in == 0))
return 0;
- dbg("%s", __func__);
-
/*
* It appears that Treos and Kyoceras want to use the
* 1st bulk in endpoint to communicate with the 2nd bulk out endpoint,
@@ -622,8 +596,6 @@ static int clie_5_attach(struct usb_serial *serial)
unsigned int pipe;
int j;
- dbg("%s", __func__);
-
/* TH55 registers 2 ports.
Communication in from the UX50/TH55 uses bulk_in_endpointAddress
from port 0. Communication out to the UX50/TH55 uses
@@ -648,59 +620,7 @@ static int clie_5_attach(struct usb_serial *serial)
return 0;
}
-static int __init visor_init(void)
-{
- int i, retval;
- /* Only if parameters were passed to us */
- if (vendor > 0 && product > 0) {
- struct usb_device_id usb_dev_temp[] = {
- {
- USB_DEVICE(vendor, product),
- .driver_info =
- (kernel_ulong_t) &palm_os_4_probe
- }
- };
-
- /* Find the last entry in id_table */
- for (i = 0;; i++) {
- if (id_table[i].idVendor == 0) {
- id_table[i] = usb_dev_temp[0];
- break;
- }
- }
- /* Find the last entry in id_table_combined */
- for (i = 0;; i++) {
- if (id_table_combined[i].idVendor == 0) {
- id_table_combined[i] = usb_dev_temp[0];
- break;
- }
- }
- printk(KERN_INFO KBUILD_MODNAME
- ": Untested USB device specified at time of module insertion\n");
- printk(KERN_INFO KBUILD_MODNAME
- ": Warning: This is not guaranteed to work\n");
- printk(KERN_INFO KBUILD_MODNAME
- ": Using a newer kernel is preferred to this method\n");
- printk(KERN_INFO KBUILD_MODNAME
- ": Adding Palm OS protocol 4.x support for unknown device: 0x%x/0x%x\n",
- vendor, product);
- }
-
- retval = usb_serial_register_drivers(&visor_driver, serial_drivers);
- if (retval == 0)
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
- return retval;
-}
-
-
-static void __exit visor_exit (void)
-{
- usb_serial_deregister_drivers(&visor_driver, serial_drivers);
-}
-
-
-module_init(visor_init);
-module_exit(visor_exit);
+module_usb_serial_driver(serial_drivers, id_table_combined);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
@@ -708,9 +628,3 @@ MODULE_LICENSE("GPL");
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
-
-module_param(vendor, ushort, 0);
-MODULE_PARM_DESC(vendor, "User specified vendor ID");
-module_param(product, ushort, 0);
-MODULE_PARM_DESC(product, "User specified product ID");
-
diff --git a/drivers/usb/serial/vivopay-serial.c b/drivers/usb/serial/vivopay-serial.c
index 078f338b5feb..0c0aa876c209 100644
--- a/drivers/usb/serial/vivopay-serial.c
+++ b/drivers/usb/serial/vivopay-serial.c
@@ -25,13 +25,6 @@ static struct usb_device_id id_table [] = {
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver vivopay_serial_driver = {
- .name = "vivopay-serial",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver vivopay_serial_device = {
.driver = {
.owner = THIS_MODULE,
@@ -45,7 +38,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
&vivopay_serial_device, NULL
};
-module_usb_serial_driver(vivopay_serial_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_AUTHOR("Forest Bond <forest.bond@outpostembedded.com>");
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 407e23c87946..473635e7f5db 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -45,7 +45,6 @@ static bool debug;
/*
* Version Information
*/
-#define DRIVER_VERSION "v2.0"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Stuart MacDonald <stuartm@connecttech.com>"
#define DRIVER_DESC "USB ConnectTech WhiteHEAT driver"
@@ -78,12 +77,6 @@ static const struct usb_device_id id_table_combined[] = {
MODULE_DEVICE_TABLE(usb, id_table_combined);
-static struct usb_driver whiteheat_driver = {
- .name = "whiteheat",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table_combined,
-};
/* function prototypes for the Connect Tech WhiteHEAT prerenumeration device */
static int whiteheat_firmware_download(struct usb_serial *serial,
@@ -96,10 +89,6 @@ static void whiteheat_release(struct usb_serial *serial);
static int whiteheat_open(struct tty_struct *tty,
struct usb_serial_port *port);
static void whiteheat_close(struct usb_serial_port *port);
-static int whiteheat_write(struct tty_struct *tty,
- struct usb_serial_port *port,
- const unsigned char *buf, int count);
-static int whiteheat_write_room(struct tty_struct *tty);
static int whiteheat_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg);
static void whiteheat_set_termios(struct tty_struct *tty,
@@ -108,11 +97,6 @@ static int whiteheat_tiocmget(struct tty_struct *tty);
static int whiteheat_tiocmset(struct tty_struct *tty,
unsigned int set, unsigned int clear);
static void whiteheat_break_ctl(struct tty_struct *tty, int break_state);
-static int whiteheat_chars_in_buffer(struct tty_struct *tty);
-static void whiteheat_throttle(struct tty_struct *tty);
-static void whiteheat_unthrottle(struct tty_struct *tty);
-static void whiteheat_read_callback(struct urb *urb);
-static void whiteheat_write_callback(struct urb *urb);
static struct usb_serial_driver whiteheat_fake_device = {
.driver = {
@@ -138,18 +122,13 @@ static struct usb_serial_driver whiteheat_device = {
.release = whiteheat_release,
.open = whiteheat_open,
.close = whiteheat_close,
- .write = whiteheat_write,
- .write_room = whiteheat_write_room,
.ioctl = whiteheat_ioctl,
.set_termios = whiteheat_set_termios,
.break_ctl = whiteheat_break_ctl,
.tiocmget = whiteheat_tiocmget,
.tiocmset = whiteheat_tiocmset,
- .chars_in_buffer = whiteheat_chars_in_buffer,
- .throttle = whiteheat_throttle,
- .unthrottle = whiteheat_unthrottle,
- .read_bulk_callback = whiteheat_read_callback,
- .write_bulk_callback = whiteheat_write_callback,
+ .throttle = usb_serial_generic_throttle,
+ .unthrottle = usb_serial_generic_unthrottle,
};
static struct usb_serial_driver * const serial_drivers[] = {
@@ -166,29 +145,8 @@ struct whiteheat_command_private {
__u8 result_buffer[64];
};
-
-#define THROTTLED 0x01
-#define ACTUALLY_THROTTLED 0x02
-
-static int urb_pool_size = 8;
-
-struct whiteheat_urb_wrap {
- struct list_head list;
- struct urb *urb;
-};
-
struct whiteheat_private {
- spinlock_t lock;
- __u8 flags;
__u8 mcr; /* FIXME: no locking on mcr */
- struct list_head rx_urbs_free;
- struct list_head rx_urbs_submitted;
- struct list_head rx_urb_q;
- struct work_struct rx_work;
- struct usb_serial_port *port;
- struct list_head tx_urbs_free;
- struct list_head tx_urbs_submitted;
- struct mutex deathwarrant;
};
@@ -198,12 +156,6 @@ static void stop_command_port(struct usb_serial *serial);
static void command_port_write_callback(struct urb *urb);
static void command_port_read_callback(struct urb *urb);
-static int start_port_read(struct usb_serial_port *port);
-static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb,
- struct list_head *head);
-static struct list_head *list_first(struct list_head *head);
-static void rx_data_softint(struct work_struct *work);
-
static int firm_send_command(struct usb_serial_port *port, __u8 command,
__u8 *data, __u8 datasize);
static int firm_open(struct usb_serial_port *port);
@@ -247,8 +199,6 @@ static int whiteheat_firmware_download(struct usb_serial *serial,
const struct firmware *loader_fw = NULL, *firmware_fw = NULL;
const struct ihex_binrec *record;
- dbg("%s", __func__);
-
if (request_ihex_firmware(&firmware_fw, "whiteheat.fw",
&serial->dev->dev)) {
dev_err(&serial->dev->dev,
@@ -349,11 +299,6 @@ static int whiteheat_attach(struct usb_serial *serial)
__u8 *command;
__u8 *result;
int i;
- int j;
- struct urb *urb;
- int buf_size;
- struct whiteheat_urb_wrap *wrap;
- struct list_head *tmp;
command_port = serial->port[COMMAND_PORT];
@@ -408,8 +353,8 @@ static int whiteheat_attach(struct usb_serial *serial)
hw_info = (struct whiteheat_hw_info *)&result[1];
- dev_info(&serial->dev->dev, "%s: Driver %s: Firmware v%d.%02d\n",
- serial->type->description, DRIVER_VERSION,
+ dev_info(&serial->dev->dev, "%s: Firmware v%d.%02d\n",
+ serial->type->description,
hw_info->sw_major_rev, hw_info->sw_minor_rev);
for (i = 0; i < serial->num_ports; i++) {
@@ -423,72 +368,7 @@ static int whiteheat_attach(struct usb_serial *serial)
goto no_private;
}
- spin_lock_init(&info->lock);
- mutex_init(&info->deathwarrant);
- info->flags = 0;
info->mcr = 0;
- INIT_WORK(&info->rx_work, rx_data_softint);
- info->port = port;
-
- INIT_LIST_HEAD(&info->rx_urbs_free);
- INIT_LIST_HEAD(&info->rx_urbs_submitted);
- INIT_LIST_HEAD(&info->rx_urb_q);
- INIT_LIST_HEAD(&info->tx_urbs_free);
- INIT_LIST_HEAD(&info->tx_urbs_submitted);
-
- for (j = 0; j < urb_pool_size; j++) {
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb) {
- dev_err(&port->dev, "No free urbs available\n");
- goto no_rx_urb;
- }
- buf_size = port->read_urb->transfer_buffer_length;
- urb->transfer_buffer = kmalloc(buf_size, GFP_KERNEL);
- if (!urb->transfer_buffer) {
- dev_err(&port->dev,
- "Couldn't allocate urb buffer\n");
- goto no_rx_buf;
- }
- wrap = kmalloc(sizeof(*wrap), GFP_KERNEL);
- if (!wrap) {
- dev_err(&port->dev,
- "Couldn't allocate urb wrapper\n");
- goto no_rx_wrap;
- }
- usb_fill_bulk_urb(urb, serial->dev,
- usb_rcvbulkpipe(serial->dev,
- port->bulk_in_endpointAddress),
- urb->transfer_buffer, buf_size,
- whiteheat_read_callback, port);
- wrap->urb = urb;
- list_add(&wrap->list, &info->rx_urbs_free);
-
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb) {
- dev_err(&port->dev, "No free urbs available\n");
- goto no_tx_urb;
- }
- buf_size = port->write_urb->transfer_buffer_length;
- urb->transfer_buffer = kmalloc(buf_size, GFP_KERNEL);
- if (!urb->transfer_buffer) {
- dev_err(&port->dev,
- "Couldn't allocate urb buffer\n");
- goto no_tx_buf;
- }
- wrap = kmalloc(sizeof(*wrap), GFP_KERNEL);
- if (!wrap) {
- dev_err(&port->dev,
- "Couldn't allocate urb wrapper\n");
- goto no_tx_wrap;
- }
- usb_fill_bulk_urb(urb, serial->dev,
- usb_sndbulkpipe(serial->dev,
- port->bulk_out_endpointAddress),
- urb->transfer_buffer, buf_size,
- whiteheat_write_callback, port);
- wrap->urb = urb;
- list_add(&wrap->list, &info->tx_urbs_free);
- }
usb_set_serial_port_data(port, info);
}
@@ -531,29 +411,6 @@ no_command_private:
for (i = serial->num_ports - 1; i >= 0; i--) {
port = serial->port[i];
info = usb_get_serial_port_data(port);
- for (j = urb_pool_size - 1; j >= 0; j--) {
- tmp = list_first(&info->tx_urbs_free);
- list_del(tmp);
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- urb = wrap->urb;
- kfree(wrap);
-no_tx_wrap:
- kfree(urb->transfer_buffer);
-no_tx_buf:
- usb_free_urb(urb);
-no_tx_urb:
- tmp = list_first(&info->rx_urbs_free);
- list_del(tmp);
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- urb = wrap->urb;
- kfree(wrap);
-no_rx_wrap:
- kfree(urb->transfer_buffer);
-no_rx_buf:
- usb_free_urb(urb);
-no_rx_urb:
- ;
- }
kfree(info);
no_private:
;
@@ -569,56 +426,27 @@ no_command_buffer:
static void whiteheat_release(struct usb_serial *serial)
{
struct usb_serial_port *command_port;
- struct usb_serial_port *port;
struct whiteheat_private *info;
- struct whiteheat_urb_wrap *wrap;
- struct urb *urb;
- struct list_head *tmp;
- struct list_head *tmp2;
int i;
- dbg("%s", __func__);
-
/* free up our private data for our command port */
command_port = serial->port[COMMAND_PORT];
kfree(usb_get_serial_port_data(command_port));
for (i = 0; i < serial->num_ports; i++) {
- port = serial->port[i];
- info = usb_get_serial_port_data(port);
- list_for_each_safe(tmp, tmp2, &info->rx_urbs_free) {
- list_del(tmp);
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- urb = wrap->urb;
- kfree(wrap);
- kfree(urb->transfer_buffer);
- usb_free_urb(urb);
- }
- list_for_each_safe(tmp, tmp2, &info->tx_urbs_free) {
- list_del(tmp);
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- urb = wrap->urb;
- kfree(wrap);
- kfree(urb->transfer_buffer);
- usb_free_urb(urb);
- }
+ info = usb_get_serial_port_data(serial->port[i]);
kfree(info);
}
}
static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port)
{
- int retval = 0;
-
- dbg("%s - port %d", __func__, port->number);
+ int retval;
retval = start_command_port(port->serial);
if (retval)
goto exit;
- if (tty)
- tty->low_latency = 1;
-
/* send an open port command */
retval = firm_open(port);
if (retval) {
@@ -640,144 +468,25 @@ static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port)
usb_clear_halt(port->serial->dev, port->read_urb->pipe);
usb_clear_halt(port->serial->dev, port->write_urb->pipe);
- /* Start reading from the device */
- retval = start_port_read(port);
+ retval = usb_serial_generic_open(tty, port);
if (retval) {
- dev_err(&port->dev,
- "%s - failed submitting read urb, error %d\n",
- __func__, retval);
firm_close(port);
stop_command_port(port->serial);
goto exit;
}
-
exit:
- dbg("%s - exit, retval = %d", __func__, retval);
return retval;
}
static void whiteheat_close(struct usb_serial_port *port)
{
- struct whiteheat_private *info = usb_get_serial_port_data(port);
- struct whiteheat_urb_wrap *wrap;
- struct urb *urb;
- struct list_head *tmp;
- struct list_head *tmp2;
-
- dbg("%s - port %d", __func__, port->number);
-
firm_report_tx_done(port);
firm_close(port);
- /* shutdown our bulk reads and writes */
- mutex_lock(&info->deathwarrant);
- spin_lock_irq(&info->lock);
- list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) {
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- urb = wrap->urb;
- list_del(tmp);
- spin_unlock_irq(&info->lock);
- usb_kill_urb(urb);
- spin_lock_irq(&info->lock);
- list_add(tmp, &info->rx_urbs_free);
- }
- list_for_each_safe(tmp, tmp2, &info->rx_urb_q)
- list_move(tmp, &info->rx_urbs_free);
- list_for_each_safe(tmp, tmp2, &info->tx_urbs_submitted) {
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- urb = wrap->urb;
- list_del(tmp);
- spin_unlock_irq(&info->lock);
- usb_kill_urb(urb);
- spin_lock_irq(&info->lock);
- list_add(tmp, &info->tx_urbs_free);
- }
- spin_unlock_irq(&info->lock);
- mutex_unlock(&info->deathwarrant);
- stop_command_port(port->serial);
-}
-
-
-static int whiteheat_write(struct tty_struct *tty,
- struct usb_serial_port *port, const unsigned char *buf, int count)
-{
- struct whiteheat_private *info = usb_get_serial_port_data(port);
- struct whiteheat_urb_wrap *wrap;
- struct urb *urb;
- int result;
- int bytes;
- int sent = 0;
- unsigned long flags;
- struct list_head *tmp;
-
- dbg("%s - port %d", __func__, port->number);
-
- if (count == 0) {
- dbg("%s - write request of 0 bytes", __func__);
- return (0);
- }
-
- while (count) {
- spin_lock_irqsave(&info->lock, flags);
- if (list_empty(&info->tx_urbs_free)) {
- spin_unlock_irqrestore(&info->lock, flags);
- break;
- }
- tmp = list_first(&info->tx_urbs_free);
- list_del(tmp);
- spin_unlock_irqrestore(&info->lock, flags);
-
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- urb = wrap->urb;
- bytes = (count > port->bulk_out_size) ?
- port->bulk_out_size : count;
- memcpy(urb->transfer_buffer, buf + sent, bytes);
-
- usb_serial_debug_data(debug, &port->dev,
- __func__, bytes, urb->transfer_buffer);
-
- urb->transfer_buffer_length = bytes;
- result = usb_submit_urb(urb, GFP_ATOMIC);
- if (result) {
- dev_err_console(port,
- "%s - failed submitting write urb, error %d\n",
- __func__, result);
- sent = result;
- spin_lock_irqsave(&info->lock, flags);
- list_add(tmp, &info->tx_urbs_free);
- spin_unlock_irqrestore(&info->lock, flags);
- break;
- } else {
- sent += bytes;
- count -= bytes;
- spin_lock_irqsave(&info->lock, flags);
- list_add(tmp, &info->tx_urbs_submitted);
- spin_unlock_irqrestore(&info->lock, flags);
- }
- }
-
- return sent;
-}
-
-static int whiteheat_write_room(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct whiteheat_private *info = usb_get_serial_port_data(port);
- struct list_head *tmp;
- int room = 0;
- unsigned long flags;
-
- dbg("%s - port %d", __func__, port->number);
+ usb_serial_generic_close(port);
- spin_lock_irqsave(&info->lock, flags);
- list_for_each(tmp, &info->tx_urbs_free)
- room++;
- spin_unlock_irqrestore(&info->lock, flags);
- room *= port->bulk_out_size;
-
- dbg("%s - returns %d", __func__, room);
- return (room);
+ stop_command_port(port->serial);
}
static int whiteheat_tiocmget(struct tty_struct *tty)
@@ -786,8 +495,6 @@ static int whiteheat_tiocmget(struct tty_struct *tty)
struct whiteheat_private *info = usb_get_serial_port_data(port);
unsigned int modem_signals = 0;
- dbg("%s - port %d", __func__, port->number);
-
firm_get_dtr_rts(port);
if (info->mcr & UART_MCR_DTR)
modem_signals |= TIOCM_DTR;
@@ -803,8 +510,6 @@ static int whiteheat_tiocmset(struct tty_struct *tty,
struct usb_serial_port *port = tty->driver_data;
struct whiteheat_private *info = usb_get_serial_port_data(port);
- dbg("%s - port %d", __func__, port->number);
-
if (set & TIOCM_RTS)
info->mcr |= UART_MCR_RTS;
if (set & TIOCM_DTR)
@@ -837,7 +542,7 @@ static int whiteheat_ioctl(struct tty_struct *tty,
serstruct.line = port->serial->minor;
serstruct.port = port->number;
serstruct.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
- serstruct.xmit_fifo_size = port->bulk_out_size;
+ serstruct.xmit_fifo_size = kfifo_size(&port->write_fifo);
serstruct.custom_divisor = 0;
serstruct.baud_base = 460800;
serstruct.close_delay = CLOSING_DELAY;
@@ -867,60 +572,6 @@ static void whiteheat_break_ctl(struct tty_struct *tty, int break_state)
}
-static int whiteheat_chars_in_buffer(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct whiteheat_private *info = usb_get_serial_port_data(port);
- struct list_head *tmp;
- struct whiteheat_urb_wrap *wrap;
- int chars = 0;
- unsigned long flags;
-
- dbg("%s - port %d", __func__, port->number);
-
- spin_lock_irqsave(&info->lock, flags);
- list_for_each(tmp, &info->tx_urbs_submitted) {
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- chars += wrap->urb->transfer_buffer_length;
- }
- spin_unlock_irqrestore(&info->lock, flags);
-
- dbg("%s - returns %d", __func__, chars);
- return chars;
-}
-
-
-static void whiteheat_throttle(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct whiteheat_private *info = usb_get_serial_port_data(port);
-
- dbg("%s - port %d", __func__, port->number);
-
- spin_lock_irq(&info->lock);
- info->flags |= THROTTLED;
- spin_unlock_irq(&info->lock);
-}
-
-
-static void whiteheat_unthrottle(struct tty_struct *tty)
-{
- struct usb_serial_port *port = tty->driver_data;
- struct whiteheat_private *info = usb_get_serial_port_data(port);
- int actually_throttled;
-
- dbg("%s - port %d", __func__, port->number);
-
- spin_lock_irq(&info->lock);
- actually_throttled = info->flags & ACTUALLY_THROTTLED;
- info->flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
- spin_unlock_irq(&info->lock);
-
- if (actually_throttled)
- rx_data_softint(&info->rx_work);
-}
-
-
/*****************************************************************************
* Connect Tech's White Heat callback routines
*****************************************************************************/
@@ -928,8 +579,6 @@ static void command_port_write_callback(struct urb *urb)
{
int status = urb->status;
- dbg("%s", __func__);
-
if (status) {
dbg("nonzero urb status: %d", status);
return;
@@ -945,8 +594,6 @@ static void command_port_read_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
int result;
- dbg("%s", __func__);
-
command_info = usb_get_serial_port_data(command_port);
if (!command_info) {
dbg("%s - command_info is NULL, exiting.", __func__);
@@ -989,80 +636,6 @@ static void command_port_read_callback(struct urb *urb)
}
-static void whiteheat_read_callback(struct urb *urb)
-{
- struct usb_serial_port *port = urb->context;
- struct whiteheat_urb_wrap *wrap;
- unsigned char *data = urb->transfer_buffer;
- struct whiteheat_private *info = usb_get_serial_port_data(port);
- int status = urb->status;
-
- dbg("%s - port %d", __func__, port->number);
-
- spin_lock(&info->lock);
- wrap = urb_to_wrap(urb, &info->rx_urbs_submitted);
- if (!wrap) {
- spin_unlock(&info->lock);
- dev_err(&port->dev, "%s - Not my urb!\n", __func__);
- return;
- }
- list_del(&wrap->list);
- spin_unlock(&info->lock);
-
- if (status) {
- dbg("%s - nonzero read bulk status received: %d",
- __func__, status);
- spin_lock(&info->lock);
- list_add(&wrap->list, &info->rx_urbs_free);
- spin_unlock(&info->lock);
- return;
- }
-
- usb_serial_debug_data(debug, &port->dev,
- __func__, urb->actual_length, data);
-
- spin_lock(&info->lock);
- list_add_tail(&wrap->list, &info->rx_urb_q);
- if (info->flags & THROTTLED) {
- info->flags |= ACTUALLY_THROTTLED;
- spin_unlock(&info->lock);
- return;
- }
- spin_unlock(&info->lock);
-
- schedule_work(&info->rx_work);
-}
-
-
-static void whiteheat_write_callback(struct urb *urb)
-{
- struct usb_serial_port *port = urb->context;
- struct whiteheat_private *info = usb_get_serial_port_data(port);
- struct whiteheat_urb_wrap *wrap;
- int status = urb->status;
-
- dbg("%s - port %d", __func__, port->number);
-
- spin_lock(&info->lock);
- wrap = urb_to_wrap(urb, &info->tx_urbs_submitted);
- if (!wrap) {
- spin_unlock(&info->lock);
- dev_err(&port->dev, "%s - Not my urb!\n", __func__);
- return;
- }
- list_move(&wrap->list, &info->tx_urbs_free);
- spin_unlock(&info->lock);
-
- if (status) {
- dbg("%s - nonzero write bulk status received: %d",
- __func__, status);
- return;
- }
-
- usb_serial_port_softint(port);
-}
-
-
/*****************************************************************************
* Connect Tech's White Heat firmware interface
*****************************************************************************/
@@ -1337,124 +910,7 @@ static void stop_command_port(struct usb_serial *serial)
mutex_unlock(&command_info->mutex);
}
-
-static int start_port_read(struct usb_serial_port *port)
-{
- struct whiteheat_private *info = usb_get_serial_port_data(port);
- struct whiteheat_urb_wrap *wrap;
- struct urb *urb;
- int retval = 0;
- unsigned long flags;
- struct list_head *tmp;
- struct list_head *tmp2;
-
- spin_lock_irqsave(&info->lock, flags);
-
- list_for_each_safe(tmp, tmp2, &info->rx_urbs_free) {
- list_del(tmp);
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- urb = wrap->urb;
- spin_unlock_irqrestore(&info->lock, flags);
- retval = usb_submit_urb(urb, GFP_KERNEL);
- if (retval) {
- spin_lock_irqsave(&info->lock, flags);
- list_add(tmp, &info->rx_urbs_free);
- list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) {
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- urb = wrap->urb;
- list_del(tmp);
- spin_unlock_irqrestore(&info->lock, flags);
- usb_kill_urb(urb);
- spin_lock_irqsave(&info->lock, flags);
- list_add(tmp, &info->rx_urbs_free);
- }
- break;
- }
- spin_lock_irqsave(&info->lock, flags);
- list_add(tmp, &info->rx_urbs_submitted);
- }
-
- spin_unlock_irqrestore(&info->lock, flags);
-
- return retval;
-}
-
-
-static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb,
- struct list_head *head)
-{
- struct whiteheat_urb_wrap *wrap;
- struct list_head *tmp;
-
- list_for_each(tmp, head) {
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- if (wrap->urb == urb)
- return wrap;
- }
-
- return NULL;
-}
-
-
-static struct list_head *list_first(struct list_head *head)
-{
- return head->next;
-}
-
-
-static void rx_data_softint(struct work_struct *work)
-{
- struct whiteheat_private *info =
- container_of(work, struct whiteheat_private, rx_work);
- struct usb_serial_port *port = info->port;
- struct tty_struct *tty = tty_port_tty_get(&port->port);
- struct whiteheat_urb_wrap *wrap;
- struct urb *urb;
- unsigned long flags;
- struct list_head *tmp;
- struct list_head *tmp2;
- int result;
- int sent = 0;
-
- spin_lock_irqsave(&info->lock, flags);
- if (info->flags & THROTTLED) {
- spin_unlock_irqrestore(&info->lock, flags);
- goto out;
- }
-
- list_for_each_safe(tmp, tmp2, &info->rx_urb_q) {
- list_del(tmp);
- spin_unlock_irqrestore(&info->lock, flags);
-
- wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
- urb = wrap->urb;
-
- if (tty && urb->actual_length)
- sent += tty_insert_flip_string(tty,
- urb->transfer_buffer, urb->actual_length);
-
- result = usb_submit_urb(urb, GFP_ATOMIC);
- if (result) {
- dev_err(&port->dev,
- "%s - failed resubmitting read urb, error %d\n",
- __func__, result);
- spin_lock_irqsave(&info->lock, flags);
- list_add(tmp, &info->rx_urbs_free);
- continue;
- }
-
- spin_lock_irqsave(&info->lock, flags);
- list_add(tmp, &info->rx_urbs_submitted);
- }
- spin_unlock_irqrestore(&info->lock, flags);
-
- if (sent)
- tty_flip_buffer_push(tty);
-out:
- tty_kref_put(tty);
-}
-
-module_usb_serial_driver(whiteheat_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table_combined);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
@@ -1463,8 +919,5 @@ MODULE_LICENSE("GPL");
MODULE_FIRMWARE("whiteheat.fw");
MODULE_FIRMWARE("whiteheat_loader.fw");
-module_param(urb_pool_size, int, 0);
-MODULE_PARM_DESC(urb_pool_size, "Number of urbs to use for buffering");
-
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/zio.c b/drivers/usb/serial/zio.c
index 9d0bb3752cd4..c043aa84a0ba 100644
--- a/drivers/usb/serial/zio.c
+++ b/drivers/usb/serial/zio.c
@@ -22,13 +22,6 @@ static const struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-static struct usb_driver zio_driver = {
- .name = "zio",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
-};
-
static struct usb_serial_driver zio_device = {
.driver = {
.owner = THIS_MODULE,
@@ -42,5 +35,5 @@ static struct usb_serial_driver * const serial_drivers[] = {
&zio_device, NULL
};
-module_usb_serial_driver(zio_driver, serial_drivers);
+module_usb_serial_driver(serial_drivers, id_table);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c
index e7e678109500..b28f2ad127d4 100644
--- a/drivers/usb/storage/ene_ub6250.c
+++ b/drivers/usb/storage/ene_ub6250.c
@@ -1933,11 +1933,7 @@ static int ene_load_bincode(struct us_data *us, unsigned char flag)
kfree(buf);
nofw:
- if (sd_fw != NULL) {
- release_firmware(sd_fw);
- sd_fw = NULL;
- }
-
+ release_firmware(sd_fw);
return result;
}
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 856ad92c40de..1719886bb9be 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -110,7 +110,7 @@ UNUSUAL_DEV( 0x040d, 0x6205, 0x0003, 0x0003,
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
-/* Deduced by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
+/* Deduced by Jonathan Woithe <jwoithe@just42.net>
* Entry needed for flags: US_FL_FIX_INQUIRY because initial inquiry message
* always fails and confuses drive.
*/
@@ -1885,6 +1885,13 @@ UNUSUAL_DEV( 0x1652, 0x6600, 0x0201, 0x0201,
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* Reported by Jesse Feddema <jdfeddema@gmail.com> */
+UNUSUAL_DEV( 0x177f, 0x0400, 0x0000, 0x0000,
+ "Yarvik",
+ "PMP400",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_BULK_IGNORE_TAG | US_FL_MAX_SECTORS_64 ),
+
/* Reported by Hans de Goede <hdegoede@redhat.com>
* These Appotech controllers are found in Picture Frames, they provide a
* (buggy) emulation of a cdrom drive which contains the windows software
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 2653e73db623..e23c30ab66da 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -121,7 +121,7 @@ MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks");
}
static struct us_unusual_dev us_unusual_dev_list[] = {
-# include "unusual_devs.h"
+# include "unusual_devs.h"
{ } /* Terminating entry */
};
@@ -261,17 +261,17 @@ EXPORT_SYMBOL_GPL(usb_stor_post_reset);
void fill_inquiry_response(struct us_data *us, unsigned char *data,
unsigned int data_len)
{
- if (data_len<36) // You lose.
+ if (data_len < 36) /* You lose. */
return;
memset(data+8, ' ', 28);
- if(data[0]&0x20) { /* USB device currently not connected. Return
+ if (data[0]&0x20) { /* USB device currently not connected. Return
peripheral qualifier 001b ("...however, the
physical device is not currently connected
to this logical unit") and leave vendor and
product identification empty. ("If the target
does store some of the INQUIRY data on the
- device, it may return zeros or ASCII spaces
+ device, it may return zeros or ASCII spaces
(20h) in those fields until the data is
available from the device."). */
} else {
@@ -298,7 +298,7 @@ static int usb_stor_control_thread(void * __us)
struct us_data *us = (struct us_data *)__us;
struct Scsi_Host *host = us_to_host(us);
- for(;;) {
+ for (;;) {
US_DEBUGP("*** thread sleeping.\n");
if (wait_for_completion_interruptible(&us->cmnd_ready))
break;
@@ -327,7 +327,7 @@ static int usb_stor_control_thread(void * __us)
scsi_unlock(host);
- /* reject the command if the direction indicator
+ /* reject the command if the direction indicator
* is UNKNOWN
*/
if (us->srb->sc_data_direction == DMA_BIDIRECTIONAL) {
@@ -338,7 +338,7 @@ static int usb_stor_control_thread(void * __us)
/* reject if target != 0 or if LUN is higher than
* the maximum known LUN
*/
- else if (us->srb->device->id &&
+ else if (us->srb->device->id &&
!(us->fflags & US_FL_SCM_MULT_TARG)) {
US_DEBUGP("Bad target number (%d:%d)\n",
us->srb->device->id, us->srb->device->lun);
@@ -351,7 +351,7 @@ static int usb_stor_control_thread(void * __us)
us->srb->result = DID_BAD_TARGET << 16;
}
- /* Handle those devices which need us to fake
+ /* Handle those devices which need us to fake
* their inquiry data */
else if ((us->srb->cmnd[0] == INQUIRY) &&
(us->fflags & US_FL_FIX_INQUIRY)) {
@@ -376,7 +376,7 @@ static int usb_stor_control_thread(void * __us)
/* indicate that the command is done */
if (us->srb->result != DID_ABORT << 16) {
- US_DEBUGP("scsi cmd done, result=0x%x\n",
+ US_DEBUGP("scsi cmd done, result=0x%x\n",
us->srb->result);
us->srb->scsi_done(us->srb);
} else {
@@ -414,7 +414,7 @@ SkipForAbort:
}
__set_current_state(TASK_RUNNING);
return 0;
-}
+}
/***********************************************************************
* Device probing and disconnecting
@@ -732,7 +732,7 @@ static int get_pipes(struct us_data *us)
us->recv_ctrl_pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
us->send_bulk_pipe = usb_sndbulkpipe(us->pusb_dev,
usb_endpoint_num(ep_out));
- us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev,
+ us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev,
usb_endpoint_num(ep_in));
if (ep_int) {
us->recv_intr_pipe = usb_rcvintpipe(us->pusb_dev,
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index b4a71679c933..0616f235bd6b 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -93,8 +93,8 @@ static int skel_open(struct inode *inode, struct file *file)
interface = usb_find_interface(&skel_driver, subminor);
if (!interface) {
- err("%s - error, can't find device for minor %d",
- __func__, subminor);
+ pr_err("%s - error, can't find device for minor %d\n",
+ __func__, subminor);
retval = -ENODEV;
goto exit;
}
@@ -179,8 +179,9 @@ static void skel_read_bulk_callback(struct urb *urb)
if (!(urb->status == -ENOENT ||
urb->status == -ECONNRESET ||
urb->status == -ESHUTDOWN))
- err("%s - nonzero write bulk status received: %d",
- __func__, urb->status);
+ dev_err(&dev->interface->dev,
+ "%s - nonzero write bulk status received: %d\n",
+ __func__, urb->status);
dev->errors = urb->status;
} else {
@@ -213,7 +214,8 @@ static int skel_do_read_io(struct usb_skel *dev, size_t count)
/* do it */
rv = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL);
if (rv < 0) {
- err("%s - failed submitting read urb, error %d",
+ dev_err(&dev->interface->dev,
+ "%s - failed submitting read urb, error %d\n",
__func__, rv);
dev->bulk_in_filled = 0;
rv = (rv == -ENOMEM) ? rv : -EIO;
@@ -364,8 +366,9 @@ static void skel_write_bulk_callback(struct urb *urb)
if (!(urb->status == -ENOENT ||
urb->status == -ECONNRESET ||
urb->status == -ESHUTDOWN))
- err("%s - nonzero write bulk status received: %d",
- __func__, urb->status);
+ dev_err(&dev->interface->dev,
+ "%s - nonzero write bulk status received: %d\n",
+ __func__, urb->status);
spin_lock(&dev->err_lock);
dev->errors = urb->status;
@@ -459,8 +462,9 @@ static ssize_t skel_write(struct file *file, const char *user_buffer,
retval = usb_submit_urb(urb, GFP_KERNEL);
mutex_unlock(&dev->io_mutex);
if (retval) {
- err("%s - failed submitting write urb, error %d", __func__,
- retval);
+ dev_err(&dev->interface->dev,
+ "%s - failed submitting write urb, error %d\n",
+ __func__, retval);
goto error_unanchor;
}
@@ -519,7 +523,7 @@ static int skel_probe(struct usb_interface *interface,
/* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) {
- err("Out of memory");
+ dev_err(&interface->dev, "Out of memory\n");
goto error;
}
kref_init(&dev->kref);
@@ -546,12 +550,14 @@ static int skel_probe(struct usb_interface *interface,
dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
if (!dev->bulk_in_buffer) {
- err("Could not allocate bulk_in_buffer");
+ dev_err(&interface->dev,
+ "Could not allocate bulk_in_buffer\n");
goto error;
}
dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->bulk_in_urb) {
- err("Could not allocate bulk_in_urb");
+ dev_err(&interface->dev,
+ "Could not allocate bulk_in_urb\n");
goto error;
}
}
@@ -563,7 +569,8 @@ static int skel_probe(struct usb_interface *interface,
}
}
if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
- err("Could not find both bulk-in and bulk-out endpoints");
+ dev_err(&interface->dev,
+ "Could not find both bulk-in and bulk-out endpoints\n");
goto error;
}
@@ -574,7 +581,8 @@ static int skel_probe(struct usb_interface *interface,
retval = usb_register_dev(interface, &skel_class);
if (retval) {
/* something prevented us from registering this driver */
- err("Not able to get a minor for this device.");
+ dev_err(&interface->dev,
+ "Not able to get a minor for this device.\n");
usb_set_intfdata(interface, NULL);
goto error;
}
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c
index ffbce4525468..fe3b6ec87122 100644
--- a/drivers/video/au1100fb.c
+++ b/drivers/video/au1100fb.c
@@ -536,7 +536,7 @@ static int __devinit au1100fb_drv_probe(struct platform_device *dev)
for (page = (unsigned long)fbdev->fb_mem;
page < PAGE_ALIGN((unsigned long)fbdev->fb_mem + fbdev->fb_len);
page += PAGE_SIZE) {
-#if CONFIG_DMA_NONCOHERENT
+#ifdef CONFIG_DMA_NONCOHERENT
SetPageReserved(virt_to_page(CAC_ADDR((void *)page)));
#else
SetPageReserved(virt_to_page(page));
diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c
index 99b354b8e257..f994c8b8f10a 100644
--- a/drivers/video/clps711xfb.c
+++ b/drivers/video/clps711xfb.c
@@ -33,7 +33,6 @@
#include <asm/mach-types.h>
#include <linux/uaccess.h>
-#include <asm/hardware/clps7111.h>
#include <mach/syspld.h>
struct fb_info *cfb;
diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c
index 784139aed079..b4a632ada401 100644
--- a/drivers/video/efifb.c
+++ b/drivers/video/efifb.c
@@ -18,6 +18,8 @@
static bool request_mem_succeeded = false;
+static struct pci_dev *default_vga;
+
static struct fb_var_screeninfo efifb_defined __devinitdata = {
.activate = FB_ACTIVATE_NOW,
.height = -1,
@@ -298,35 +300,72 @@ static struct fb_ops efifb_ops = {
.fb_imageblit = cfb_imageblit,
};
+struct pci_dev *vga_default_device(void)
+{
+ return default_vga;
+}
+
+EXPORT_SYMBOL_GPL(vga_default_device);
+
+void vga_set_default_device(struct pci_dev *pdev)
+{
+ default_vga = pdev;
+}
+
static int __init efifb_setup(char *options)
{
char *this_opt;
int i;
+ struct pci_dev *dev = NULL;
+
+ if (options && *options) {
+ while ((this_opt = strsep(&options, ",")) != NULL) {
+ if (!*this_opt) continue;
+
+ for (i = 0; i < M_UNKNOWN; i++) {
+ if (!strcmp(this_opt, dmi_list[i].optname) &&
+ dmi_list[i].base != 0) {
+ screen_info.lfb_base = dmi_list[i].base;
+ screen_info.lfb_linelength = dmi_list[i].stride;
+ screen_info.lfb_width = dmi_list[i].width;
+ screen_info.lfb_height = dmi_list[i].height;
+ }
+ }
+ if (!strncmp(this_opt, "base:", 5))
+ screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0);
+ else if (!strncmp(this_opt, "stride:", 7))
+ screen_info.lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4;
+ else if (!strncmp(this_opt, "height:", 7))
+ screen_info.lfb_height = simple_strtoul(this_opt+7, NULL, 0);
+ else if (!strncmp(this_opt, "width:", 6))
+ screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0);
+ }
+ }
- if (!options || !*options)
- return 0;
+ for_each_pci_dev(dev) {
+ int i;
- while ((this_opt = strsep(&options, ",")) != NULL) {
- if (!*this_opt) continue;
+ if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
+ continue;
- for (i = 0; i < M_UNKNOWN; i++) {
- if (!strcmp(this_opt, dmi_list[i].optname) &&
- dmi_list[i].base != 0) {
- screen_info.lfb_base = dmi_list[i].base;
- screen_info.lfb_linelength = dmi_list[i].stride;
- screen_info.lfb_width = dmi_list[i].width;
- screen_info.lfb_height = dmi_list[i].height;
- }
+ for (i=0; i < DEVICE_COUNT_RESOURCE; i++) {
+ resource_size_t start, end;
+
+ if (!(pci_resource_flags(dev, i) & IORESOURCE_MEM))
+ continue;
+
+ start = pci_resource_start(dev, i);
+ end = pci_resource_end(dev, i);
+
+ if (!start || !end)
+ continue;
+
+ if (screen_info.lfb_base >= start &&
+ (screen_info.lfb_base + screen_info.lfb_size) < end)
+ default_vga = dev;
}
- if (!strncmp(this_opt, "base:", 5))
- screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0);
- else if (!strncmp(this_opt, "stride:", 7))
- screen_info.lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4;
- else if (!strncmp(this_opt, "height:", 7))
- screen_info.lfb_height = simple_strtoul(this_opt+7, NULL, 0);
- else if (!strncmp(this_opt, "width:", 6))
- screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0);
}
+
return 0;
}
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c
index 4a89f889852d..6c6bc578d0fc 100644
--- a/drivers/video/mxsfb.c
+++ b/drivers/video/mxsfb.c
@@ -45,6 +45,7 @@
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
+#include <linux/pinctrl/consumer.h>
#include <mach/mxsfb.h>
#define REG_SET 4
@@ -756,6 +757,7 @@ static int __devinit mxsfb_probe(struct platform_device *pdev)
struct mxsfb_info *host;
struct fb_info *fb_info;
struct fb_modelist *modelist;
+ struct pinctrl *pinctrl;
int i, ret;
if (!pdata) {
@@ -793,6 +795,12 @@ static int __devinit mxsfb_probe(struct platform_device *pdev)
host->devdata = &mxsfb_devdata[pdev->id_entry->driver_data];
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ goto error_getpin;
+ }
+
host->clk = clk_get(&host->pdev->dev, NULL);
if (IS_ERR(host->clk)) {
ret = PTR_ERR(host->clk);
@@ -848,6 +856,7 @@ error_init_fb:
error_pseudo_pallette:
clk_put(host->clk);
error_getclock:
+error_getpin:
iounmap(host->base);
error_ioremap:
framebuffer_release(fb_info);
diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
index 408a9927be92..c3853c92279b 100644
--- a/drivers/video/omap2/displays/Kconfig
+++ b/drivers/video/omap2/displays/Kconfig
@@ -10,12 +10,12 @@ config PANEL_GENERIC_DPI
Supports LCD Panel used in TI SDP3430 and EVM boards,
OMAP3517 EVM boards and CM-T35.
-config PANEL_DVI
- tristate "DVI output"
+config PANEL_TFP410
+ tristate "TFP410 DPI-to-DVI chip"
depends on OMAP2_DSS_DPI && I2C
help
- Driver for external monitors, connected via DVI. The driver uses i2c
- to read EDID information from the monitor.
+ Driver for TFP410 DPI-to-DVI chip. The driver uses i2c to read EDID
+ information from the monitor.
config PANEL_LGPHILIPS_LB035Q02
tristate "LG.Philips LB035Q02 LCD Panel"
diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile
index fbfafc6eebb4..58a5176b07b0 100644
--- a/drivers/video/omap2/displays/Makefile
+++ b/drivers/video/omap2/displays/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_PANEL_GENERIC_DPI) += panel-generic-dpi.o
-obj-$(CONFIG_PANEL_DVI) += panel-dvi.o
+obj-$(CONFIG_PANEL_TFP410) += panel-tfp410.o
obj-$(CONFIG_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o
obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
obj-$(CONFIG_PANEL_NEC_NL8048HL11_01B) += panel-nec-nl8048hl11-01b.o
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
index 0f21fa5a16ae..b2dd88b48420 100644
--- a/drivers/video/omap2/displays/panel-taal.c
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -993,6 +993,15 @@ static int taal_probe(struct omap_dss_device *dssdev)
dev_set_drvdata(&dssdev->dev, td);
+ if (gpio_is_valid(panel_data->reset_gpio)) {
+ r = gpio_request_one(panel_data->reset_gpio, GPIOF_OUT_INIT_LOW,
+ "taal rst");
+ if (r) {
+ dev_err(&dssdev->dev, "failed to request reset gpio\n");
+ goto err_rst_gpio;
+ }
+ }
+
taal_hw_reset(dssdev);
if (panel_data->use_dsi_backlight) {
@@ -1073,6 +1082,9 @@ err_gpio:
if (bldev != NULL)
backlight_device_unregister(bldev);
err_bl:
+ if (gpio_is_valid(panel_data->reset_gpio))
+ gpio_free(panel_data->reset_gpio);
+err_rst_gpio:
destroy_workqueue(td->workqueue);
err_wq:
free_regulators(panel_config->regulators, panel_config->num_regulators);
@@ -1116,15 +1128,25 @@ static void __exit taal_remove(struct omap_dss_device *dssdev)
free_regulators(td->panel_config->regulators,
td->panel_config->num_regulators);
+ if (gpio_is_valid(panel_data->reset_gpio))
+ gpio_free(panel_data->reset_gpio);
+
kfree(td);
}
static int taal_power_on(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
+ struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
u8 id1, id2, id3;
int r;
+ r = omapdss_dsi_configure_pins(dssdev, &panel_data->pin_config);
+ if (r) {
+ dev_err(&dssdev->dev, "failed to configure DSI pins\n");
+ goto err0;
+ };
+
r = omapdss_dsi_display_enable(dssdev);
if (r) {
dev_err(&dssdev->dev, "failed to enable DSI\n");
diff --git a/drivers/video/omap2/displays/panel-dvi.c b/drivers/video/omap2/displays/panel-tfp410.c
index 03eb14af33e0..52637fa8fda8 100644
--- a/drivers/video/omap2/displays/panel-dvi.c
+++ b/drivers/video/omap2/displays/panel-tfp410.c
@@ -1,5 +1,5 @@
/*
- * DVI output support
+ * TFP410 DPI-to-DVI chip
*
* Copyright (C) 2011 Texas Instruments Inc
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
@@ -21,11 +21,12 @@
#include <linux/slab.h>
#include <video/omapdss.h>
#include <linux/i2c.h>
+#include <linux/gpio.h>
#include <drm/drm_edid.h>
-#include <video/omap-panel-dvi.h>
+#include <video/omap-panel-tfp410.h>
-static const struct omap_video_timings panel_dvi_default_timings = {
+static const struct omap_video_timings tfp410_default_timings = {
.x_res = 640,
.y_res = 480,
@@ -44,17 +45,19 @@ struct panel_drv_data {
struct omap_dss_device *dssdev;
struct mutex lock;
+
+ int pd_gpio;
};
-static inline struct panel_dvi_platform_data
+static inline struct tfp410_platform_data
*get_pdata(const struct omap_dss_device *dssdev)
{
return dssdev->data;
}
-static int panel_dvi_power_on(struct omap_dss_device *dssdev)
+static int tfp410_power_on(struct omap_dss_device *dssdev)
{
- struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
+ struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
int r;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
@@ -64,57 +67,72 @@ static int panel_dvi_power_on(struct omap_dss_device *dssdev)
if (r)
goto err0;
- if (pdata->platform_enable) {
- r = pdata->platform_enable(dssdev);
- if (r)
- goto err1;
- }
+ if (gpio_is_valid(ddata->pd_gpio))
+ gpio_set_value(ddata->pd_gpio, 1);
return 0;
-err1:
- omapdss_dpi_display_disable(dssdev);
err0:
return r;
}
-static void panel_dvi_power_off(struct omap_dss_device *dssdev)
+static void tfp410_power_off(struct omap_dss_device *dssdev)
{
- struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
+ struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return;
- if (pdata->platform_disable)
- pdata->platform_disable(dssdev);
+ if (gpio_is_valid(ddata->pd_gpio))
+ gpio_set_value(ddata->pd_gpio, 0);
omapdss_dpi_display_disable(dssdev);
}
-static int panel_dvi_probe(struct omap_dss_device *dssdev)
+static int tfp410_probe(struct omap_dss_device *dssdev)
{
+ struct tfp410_platform_data *pdata = get_pdata(dssdev);
struct panel_drv_data *ddata;
+ int r;
ddata = kzalloc(sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENOMEM;
- dssdev->panel.timings = panel_dvi_default_timings;
+ dssdev->panel.timings = tfp410_default_timings;
dssdev->panel.config = OMAP_DSS_LCD_TFT;
ddata->dssdev = dssdev;
mutex_init(&ddata->lock);
+ if (pdata)
+ ddata->pd_gpio = pdata->power_down_gpio;
+ else
+ ddata->pd_gpio = -1;
+
+ if (gpio_is_valid(ddata->pd_gpio)) {
+ r = gpio_request_one(ddata->pd_gpio, GPIOF_OUT_INIT_LOW,
+ "tfp410 pd");
+ if (r) {
+ dev_err(&dssdev->dev, "Failed to request PD GPIO %d\n",
+ ddata->pd_gpio);
+ ddata->pd_gpio = -1;
+ }
+ }
+
dev_set_drvdata(&dssdev->dev, ddata);
return 0;
}
-static void __exit panel_dvi_remove(struct omap_dss_device *dssdev)
+static void __exit tfp410_remove(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
mutex_lock(&ddata->lock);
+ if (gpio_is_valid(ddata->pd_gpio))
+ gpio_free(ddata->pd_gpio);
+
dev_set_drvdata(&dssdev->dev, NULL);
mutex_unlock(&ddata->lock);
@@ -122,14 +140,14 @@ static void __exit panel_dvi_remove(struct omap_dss_device *dssdev)
kfree(ddata);
}
-static int panel_dvi_enable(struct omap_dss_device *dssdev)
+static int tfp410_enable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
int r;
mutex_lock(&ddata->lock);
- r = panel_dvi_power_on(dssdev);
+ r = tfp410_power_on(dssdev);
if (r == 0)
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
@@ -138,26 +156,26 @@ static int panel_dvi_enable(struct omap_dss_device *dssdev)
return r;
}
-static void panel_dvi_disable(struct omap_dss_device *dssdev)
+static void tfp410_disable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
mutex_lock(&ddata->lock);
- panel_dvi_power_off(dssdev);
+ tfp410_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
mutex_unlock(&ddata->lock);
}
-static int panel_dvi_suspend(struct omap_dss_device *dssdev)
+static int tfp410_suspend(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
mutex_lock(&ddata->lock);
- panel_dvi_power_off(dssdev);
+ tfp410_power_off(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
@@ -166,14 +184,14 @@ static int panel_dvi_suspend(struct omap_dss_device *dssdev)
return 0;
}
-static int panel_dvi_resume(struct omap_dss_device *dssdev)
+static int tfp410_resume(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
int r;
mutex_lock(&ddata->lock);
- r = panel_dvi_power_on(dssdev);
+ r = tfp410_power_on(dssdev);
if (r == 0)
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
@@ -182,7 +200,7 @@ static int panel_dvi_resume(struct omap_dss_device *dssdev)
return r;
}
-static void panel_dvi_set_timings(struct omap_dss_device *dssdev,
+static void tfp410_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
@@ -192,7 +210,7 @@ static void panel_dvi_set_timings(struct omap_dss_device *dssdev,
mutex_unlock(&ddata->lock);
}
-static void panel_dvi_get_timings(struct omap_dss_device *dssdev,
+static void tfp410_get_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
@@ -202,7 +220,7 @@ static void panel_dvi_get_timings(struct omap_dss_device *dssdev,
mutex_unlock(&ddata->lock);
}
-static int panel_dvi_check_timings(struct omap_dss_device *dssdev,
+static int tfp410_check_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
@@ -216,7 +234,7 @@ static int panel_dvi_check_timings(struct omap_dss_device *dssdev,
}
-static int panel_dvi_ddc_read(struct i2c_adapter *adapter,
+static int tfp410_ddc_read(struct i2c_adapter *adapter,
unsigned char *buf, u16 count, u8 offset)
{
int r, retries;
@@ -247,11 +265,11 @@ static int panel_dvi_ddc_read(struct i2c_adapter *adapter,
return r < 0 ? r : -EIO;
}
-static int panel_dvi_read_edid(struct omap_dss_device *dssdev,
+static int tfp410_read_edid(struct omap_dss_device *dssdev,
u8 *edid, int len)
{
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
- struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
+ struct tfp410_platform_data *pdata = get_pdata(dssdev);
struct i2c_adapter *adapter;
int r, l, bytes_read;
@@ -271,7 +289,7 @@ static int panel_dvi_read_edid(struct omap_dss_device *dssdev,
}
l = min(EDID_LENGTH, len);
- r = panel_dvi_ddc_read(adapter, edid, l, 0);
+ r = tfp410_ddc_read(adapter, edid, l, 0);
if (r)
goto err;
@@ -281,7 +299,7 @@ static int panel_dvi_read_edid(struct omap_dss_device *dssdev,
if (len > EDID_LENGTH && edid[0x7e] > 0) {
l = min(EDID_LENGTH, len - EDID_LENGTH);
- r = panel_dvi_ddc_read(adapter, edid + EDID_LENGTH,
+ r = tfp410_ddc_read(adapter, edid + EDID_LENGTH,
l, EDID_LENGTH);
if (r)
goto err;
@@ -298,10 +316,10 @@ err:
return r;
}
-static bool panel_dvi_detect(struct omap_dss_device *dssdev)
+static bool tfp410_detect(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev);
- struct panel_dvi_platform_data *pdata = get_pdata(dssdev);
+ struct tfp410_platform_data *pdata = get_pdata(dssdev);
struct i2c_adapter *adapter;
unsigned char out;
int r;
@@ -315,7 +333,7 @@ static bool panel_dvi_detect(struct omap_dss_device *dssdev)
if (!adapter)
goto out;
- r = panel_dvi_ddc_read(adapter, &out, 1, 0);
+ r = tfp410_ddc_read(adapter, &out, 1, 0);
mutex_unlock(&ddata->lock);
@@ -326,38 +344,38 @@ out:
return true;
}
-static struct omap_dss_driver panel_dvi_driver = {
- .probe = panel_dvi_probe,
- .remove = __exit_p(panel_dvi_remove),
+static struct omap_dss_driver tfp410_driver = {
+ .probe = tfp410_probe,
+ .remove = __exit_p(tfp410_remove),
- .enable = panel_dvi_enable,
- .disable = panel_dvi_disable,
- .suspend = panel_dvi_suspend,
- .resume = panel_dvi_resume,
+ .enable = tfp410_enable,
+ .disable = tfp410_disable,
+ .suspend = tfp410_suspend,
+ .resume = tfp410_resume,
- .set_timings = panel_dvi_set_timings,
- .get_timings = panel_dvi_get_timings,
- .check_timings = panel_dvi_check_timings,
+ .set_timings = tfp410_set_timings,
+ .get_timings = tfp410_get_timings,
+ .check_timings = tfp410_check_timings,
- .read_edid = panel_dvi_read_edid,
- .detect = panel_dvi_detect,
+ .read_edid = tfp410_read_edid,
+ .detect = tfp410_detect,
.driver = {
- .name = "dvi",
+ .name = "tfp410",
.owner = THIS_MODULE,
},
};
-static int __init panel_dvi_init(void)
+static int __init tfp410_init(void)
{
- return omap_dss_register_driver(&panel_dvi_driver);
+ return omap_dss_register_driver(&tfp410_driver);
}
-static void __exit panel_dvi_exit(void)
+static void __exit tfp410_exit(void)
{
- omap_dss_unregister_driver(&panel_dvi_driver);
+ omap_dss_unregister_driver(&tfp410_driver);
}
-module_init(panel_dvi_init);
-module_exit(panel_dvi_exit);
+module_init(tfp410_init);
+module_exit(tfp410_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
index 662d14f8c2c3..210a3c4f6150 100644
--- a/drivers/video/omap2/dss/dsi.c
+++ b/drivers/video/omap2/dss/dsi.c
@@ -2076,65 +2076,6 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev)
}
}
-static int dsi_parse_lane_config(struct omap_dss_device *dssdev)
-{
- struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- u8 lanes[DSI_MAX_NR_LANES];
- u8 polarities[DSI_MAX_NR_LANES];
- int num_lanes, i;
-
- static const enum dsi_lane_function functions[] = {
- DSI_LANE_CLK,
- DSI_LANE_DATA1,
- DSI_LANE_DATA2,
- DSI_LANE_DATA3,
- DSI_LANE_DATA4,
- };
-
- lanes[0] = dssdev->phy.dsi.clk_lane;
- lanes[1] = dssdev->phy.dsi.data1_lane;
- lanes[2] = dssdev->phy.dsi.data2_lane;
- lanes[3] = dssdev->phy.dsi.data3_lane;
- lanes[4] = dssdev->phy.dsi.data4_lane;
- polarities[0] = dssdev->phy.dsi.clk_pol;
- polarities[1] = dssdev->phy.dsi.data1_pol;
- polarities[2] = dssdev->phy.dsi.data2_pol;
- polarities[3] = dssdev->phy.dsi.data3_pol;
- polarities[4] = dssdev->phy.dsi.data4_pol;
-
- num_lanes = 0;
-
- for (i = 0; i < dsi->num_lanes_supported; ++i)
- dsi->lanes[i].function = DSI_LANE_UNUSED;
-
- for (i = 0; i < dsi->num_lanes_supported; ++i) {
- int num;
-
- if (lanes[i] == DSI_LANE_UNUSED)
- break;
-
- num = lanes[i] - 1;
-
- if (num >= dsi->num_lanes_supported)
- return -EINVAL;
-
- if (dsi->lanes[num].function != DSI_LANE_UNUSED)
- return -EINVAL;
-
- dsi->lanes[num].function = functions[i];
- dsi->lanes[num].polarity = polarities[i];
- num_lanes++;
- }
-
- if (num_lanes < 2 || num_lanes > dsi->num_lanes_supported)
- return -EINVAL;
-
- dsi->num_lanes_used = num_lanes;
-
- return 0;
-}
-
static int dsi_set_lane_config(struct omap_dss_device *dssdev)
{
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
@@ -3975,6 +3916,74 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev)
}
}
+int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev,
+ const struct omap_dsi_pin_config *pin_cfg)
+{
+ struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ int num_pins;
+ const int *pins;
+ struct dsi_lane_config lanes[DSI_MAX_NR_LANES];
+ int num_lanes;
+ int i;
+
+ static const enum dsi_lane_function functions[] = {
+ DSI_LANE_CLK,
+ DSI_LANE_DATA1,
+ DSI_LANE_DATA2,
+ DSI_LANE_DATA3,
+ DSI_LANE_DATA4,
+ };
+
+ num_pins = pin_cfg->num_pins;
+ pins = pin_cfg->pins;
+
+ if (num_pins < 4 || num_pins > dsi->num_lanes_supported * 2
+ || num_pins % 2 != 0)
+ return -EINVAL;
+
+ for (i = 0; i < DSI_MAX_NR_LANES; ++i)
+ lanes[i].function = DSI_LANE_UNUSED;
+
+ num_lanes = 0;
+
+ for (i = 0; i < num_pins; i += 2) {
+ u8 lane, pol;
+ int dx, dy;
+
+ dx = pins[i];
+ dy = pins[i + 1];
+
+ if (dx < 0 || dx >= dsi->num_lanes_supported * 2)
+ return -EINVAL;
+
+ if (dy < 0 || dy >= dsi->num_lanes_supported * 2)
+ 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;
+
+ lanes[lane].function = functions[i / 2];
+ lanes[lane].polarity = pol;
+ num_lanes++;
+ }
+
+ memcpy(dsi->lanes, lanes, sizeof(dsi->lanes));
+ dsi->num_lanes_used = num_lanes;
+
+ return 0;
+}
+EXPORT_SYMBOL(omapdss_dsi_configure_pins);
+
int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
{
struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev);
@@ -4339,12 +4348,6 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
int dsi_module = dsi_get_dsidev_id(dsidev);
int r;
- r = dsi_parse_lane_config(dssdev);
- if (r) {
- DSSERR("illegal lane config");
- goto err0;
- }
-
r = dsi_pll_init(dsidev, true, true);
if (r)
goto err0;
diff --git a/drivers/video/udlfb.c b/drivers/video/udlfb.c
index a159b63e18b9..7af1e8166182 100644
--- a/drivers/video/udlfb.c
+++ b/drivers/video/udlfb.c
@@ -1594,7 +1594,7 @@ static int dlfb_usb_probe(struct usb_interface *interface,
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
- err("dlfb_usb_probe: failed alloc of dev struct\n");
+ dev_err(&interface->dev, "dlfb_usb_probe: failed alloc of dev struct\n");
goto error;
}
diff --git a/drivers/staging/vme/Kconfig b/drivers/vme/Kconfig
index 6411ae51ed3f..c5c22465a805 100644
--- a/drivers/staging/vme/Kconfig
+++ b/drivers/vme/Kconfig
@@ -10,10 +10,10 @@ menuconfig VME_BUS
if VME_BUS
-source "drivers/staging/vme/bridges/Kconfig"
+source "drivers/vme/bridges/Kconfig"
-source "drivers/staging/vme/devices/Kconfig"
+source "drivers/vme/boards/Kconfig"
-source "drivers/staging/vme/boards/Kconfig"
+source "drivers/staging/vme/devices/Kconfig"
endif # VME
diff --git a/drivers/vme/Makefile b/drivers/vme/Makefile
new file mode 100644
index 000000000000..d7bfcb9fd5a1
--- /dev/null
+++ b/drivers/vme/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the VME bridge device drivers.
+#
+obj-$(CONFIG_VME_BUS) += vme.o
+
+obj-y += bridges/
+obj-y += boards/
diff --git a/drivers/staging/vme/boards/Kconfig b/drivers/vme/boards/Kconfig
index 761631353527..761631353527 100644
--- a/drivers/staging/vme/boards/Kconfig
+++ b/drivers/vme/boards/Kconfig
diff --git a/drivers/staging/vme/boards/Makefile b/drivers/vme/boards/Makefile
index 43658340885d..43658340885d 100644
--- a/drivers/staging/vme/boards/Makefile
+++ b/drivers/vme/boards/Makefile
diff --git a/drivers/staging/vme/boards/vme_vmivme7805.c b/drivers/vme/boards/vme_vmivme7805.c
index 8e05bb4e135a..8e05bb4e135a 100644
--- a/drivers/staging/vme/boards/vme_vmivme7805.c
+++ b/drivers/vme/boards/vme_vmivme7805.c
diff --git a/drivers/staging/vme/boards/vme_vmivme7805.h b/drivers/vme/boards/vme_vmivme7805.h
index 44c2c449808c..44c2c449808c 100644
--- a/drivers/staging/vme/boards/vme_vmivme7805.h
+++ b/drivers/vme/boards/vme_vmivme7805.h
diff --git a/drivers/staging/vme/bridges/Kconfig b/drivers/vme/bridges/Kconfig
index 9331064e0476..9331064e0476 100644
--- a/drivers/staging/vme/bridges/Kconfig
+++ b/drivers/vme/bridges/Kconfig
diff --git a/drivers/staging/vme/bridges/Makefile b/drivers/vme/bridges/Makefile
index 59638afcd502..59638afcd502 100644
--- a/drivers/staging/vme/bridges/Makefile
+++ b/drivers/vme/bridges/Makefile
diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.c b/drivers/vme/bridges/vme_ca91cx42.c
index 515b8b8e32a8..e0df92ec44bd 100644
--- a/drivers/staging/vme/bridges/vme_ca91cx42.c
+++ b/drivers/vme/bridges/vme_ca91cx42.c
@@ -29,8 +29,8 @@
#include <linux/time.h>
#include <linux/io.h>
#include <linux/uaccess.h>
+#include <linux/vme.h>
-#include "../vme.h"
#include "../vme_bridge.h"
#include "vme_ca91cx42.h"
@@ -1501,7 +1501,7 @@ static int ca91cx42_slot_get(struct vme_bridge *ca91cx42_bridge)
}
-void *ca91cx42_alloc_consistent(struct device *parent, size_t size,
+static void *ca91cx42_alloc_consistent(struct device *parent, size_t size,
dma_addr_t *dma)
{
struct pci_dev *pdev;
@@ -1512,8 +1512,8 @@ void *ca91cx42_alloc_consistent(struct device *parent, size_t size,
return pci_alloc_consistent(pdev, size, dma);
}
-void ca91cx42_free_consistent(struct device *parent, size_t size, void *vaddr,
- dma_addr_t dma)
+static void ca91cx42_free_consistent(struct device *parent, size_t size,
+ void *vaddr, dma_addr_t dma)
{
struct pci_dev *pdev;
diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.h b/drivers/vme/bridges/vme_ca91cx42.h
index 02a7c794db05..02a7c794db05 100644
--- a/drivers/staging/vme/bridges/vme_ca91cx42.h
+++ b/drivers/vme/bridges/vme_ca91cx42.h
diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/vme/bridges/vme_tsi148.c
index f50582169b24..f6385f7a66d9 100644
--- a/drivers/staging/vme/bridges/vme_tsi148.c
+++ b/drivers/vme/bridges/vme_tsi148.c
@@ -29,8 +29,9 @@
#include <linux/time.h>
#include <linux/io.h>
#include <linux/uaccess.h>
+#include <linux/byteorder/generic.h>
+#include <linux/vme.h>
-#include "../vme.h"
#include "../vme_bridge.h"
#include "vme_tsi148.h"
@@ -1415,51 +1416,55 @@ static unsigned int tsi148_master_rmw(struct vme_master_resource *image,
return result;
}
-static int tsi148_dma_set_vme_src_attributes(struct device *dev, u32 *attr,
+static int tsi148_dma_set_vme_src_attributes(struct device *dev, __be32 *attr,
u32 aspace, u32 cycle, u32 dwidth)
{
+ u32 val;
+
+ val = be32_to_cpu(*attr);
+
/* Setup 2eSST speeds */
switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
case VME_2eSST160:
- *attr |= TSI148_LCSR_DSAT_2eSSTM_160;
+ val |= TSI148_LCSR_DSAT_2eSSTM_160;
break;
case VME_2eSST267:
- *attr |= TSI148_LCSR_DSAT_2eSSTM_267;
+ val |= TSI148_LCSR_DSAT_2eSSTM_267;
break;
case VME_2eSST320:
- *attr |= TSI148_LCSR_DSAT_2eSSTM_320;
+ val |= TSI148_LCSR_DSAT_2eSSTM_320;
break;
}
/* Setup cycle types */
if (cycle & VME_SCT)
- *attr |= TSI148_LCSR_DSAT_TM_SCT;
+ val |= TSI148_LCSR_DSAT_TM_SCT;
if (cycle & VME_BLT)
- *attr |= TSI148_LCSR_DSAT_TM_BLT;
+ val |= TSI148_LCSR_DSAT_TM_BLT;
if (cycle & VME_MBLT)
- *attr |= TSI148_LCSR_DSAT_TM_MBLT;
+ val |= TSI148_LCSR_DSAT_TM_MBLT;
if (cycle & VME_2eVME)
- *attr |= TSI148_LCSR_DSAT_TM_2eVME;
+ val |= TSI148_LCSR_DSAT_TM_2eVME;
if (cycle & VME_2eSST)
- *attr |= TSI148_LCSR_DSAT_TM_2eSST;
+ val |= TSI148_LCSR_DSAT_TM_2eSST;
if (cycle & VME_2eSSTB) {
dev_err(dev, "Currently not setting Broadcast Select "
"Registers\n");
- *attr |= TSI148_LCSR_DSAT_TM_2eSSTB;
+ val |= TSI148_LCSR_DSAT_TM_2eSSTB;
}
/* Setup data width */
switch (dwidth) {
case VME_D16:
- *attr |= TSI148_LCSR_DSAT_DBW_16;
+ val |= TSI148_LCSR_DSAT_DBW_16;
break;
case VME_D32:
- *attr |= TSI148_LCSR_DSAT_DBW_32;
+ val |= TSI148_LCSR_DSAT_DBW_32;
break;
default:
dev_err(dev, "Invalid data width\n");
@@ -1469,31 +1474,31 @@ static int tsi148_dma_set_vme_src_attributes(struct device *dev, u32 *attr,
/* Setup address space */
switch (aspace) {
case VME_A16:
- *attr |= TSI148_LCSR_DSAT_AMODE_A16;
+ val |= TSI148_LCSR_DSAT_AMODE_A16;
break;
case VME_A24:
- *attr |= TSI148_LCSR_DSAT_AMODE_A24;
+ val |= TSI148_LCSR_DSAT_AMODE_A24;
break;
case VME_A32:
- *attr |= TSI148_LCSR_DSAT_AMODE_A32;
+ val |= TSI148_LCSR_DSAT_AMODE_A32;
break;
case VME_A64:
- *attr |= TSI148_LCSR_DSAT_AMODE_A64;
+ val |= TSI148_LCSR_DSAT_AMODE_A64;
break;
case VME_CRCSR:
- *attr |= TSI148_LCSR_DSAT_AMODE_CRCSR;
+ val |= TSI148_LCSR_DSAT_AMODE_CRCSR;
break;
case VME_USER1:
- *attr |= TSI148_LCSR_DSAT_AMODE_USER1;
+ val |= TSI148_LCSR_DSAT_AMODE_USER1;
break;
case VME_USER2:
- *attr |= TSI148_LCSR_DSAT_AMODE_USER2;
+ val |= TSI148_LCSR_DSAT_AMODE_USER2;
break;
case VME_USER3:
- *attr |= TSI148_LCSR_DSAT_AMODE_USER3;
+ val |= TSI148_LCSR_DSAT_AMODE_USER3;
break;
case VME_USER4:
- *attr |= TSI148_LCSR_DSAT_AMODE_USER4;
+ val |= TSI148_LCSR_DSAT_AMODE_USER4;
break;
default:
dev_err(dev, "Invalid address space\n");
@@ -1502,58 +1507,64 @@ static int tsi148_dma_set_vme_src_attributes(struct device *dev, u32 *attr,
}
if (cycle & VME_SUPER)
- *attr |= TSI148_LCSR_DSAT_SUP;
+ val |= TSI148_LCSR_DSAT_SUP;
if (cycle & VME_PROG)
- *attr |= TSI148_LCSR_DSAT_PGM;
+ val |= TSI148_LCSR_DSAT_PGM;
+
+ *attr = cpu_to_be32(val);
return 0;
}
-static int tsi148_dma_set_vme_dest_attributes(struct device *dev, u32 *attr,
+static int tsi148_dma_set_vme_dest_attributes(struct device *dev, __be32 *attr,
u32 aspace, u32 cycle, u32 dwidth)
{
+ u32 val;
+
+ val = be32_to_cpu(*attr);
+
/* Setup 2eSST speeds */
switch (cycle & (VME_2eSST160 | VME_2eSST267 | VME_2eSST320)) {
case VME_2eSST160:
- *attr |= TSI148_LCSR_DDAT_2eSSTM_160;
+ val |= TSI148_LCSR_DDAT_2eSSTM_160;
break;
case VME_2eSST267:
- *attr |= TSI148_LCSR_DDAT_2eSSTM_267;
+ val |= TSI148_LCSR_DDAT_2eSSTM_267;
break;
case VME_2eSST320:
- *attr |= TSI148_LCSR_DDAT_2eSSTM_320;
+ val |= TSI148_LCSR_DDAT_2eSSTM_320;
break;
}
/* Setup cycle types */
if (cycle & VME_SCT)
- *attr |= TSI148_LCSR_DDAT_TM_SCT;
+ val |= TSI148_LCSR_DDAT_TM_SCT;
if (cycle & VME_BLT)
- *attr |= TSI148_LCSR_DDAT_TM_BLT;
+ val |= TSI148_LCSR_DDAT_TM_BLT;
if (cycle & VME_MBLT)
- *attr |= TSI148_LCSR_DDAT_TM_MBLT;
+ val |= TSI148_LCSR_DDAT_TM_MBLT;
if (cycle & VME_2eVME)
- *attr |= TSI148_LCSR_DDAT_TM_2eVME;
+ val |= TSI148_LCSR_DDAT_TM_2eVME;
if (cycle & VME_2eSST)
- *attr |= TSI148_LCSR_DDAT_TM_2eSST;
+ val |= TSI148_LCSR_DDAT_TM_2eSST;
if (cycle & VME_2eSSTB) {
dev_err(dev, "Currently not setting Broadcast Select "
"Registers\n");
- *attr |= TSI148_LCSR_DDAT_TM_2eSSTB;
+ val |= TSI148_LCSR_DDAT_TM_2eSSTB;
}
/* Setup data width */
switch (dwidth) {
case VME_D16:
- *attr |= TSI148_LCSR_DDAT_DBW_16;
+ val |= TSI148_LCSR_DDAT_DBW_16;
break;
case VME_D32:
- *attr |= TSI148_LCSR_DDAT_DBW_32;
+ val |= TSI148_LCSR_DDAT_DBW_32;
break;
default:
dev_err(dev, "Invalid data width\n");
@@ -1563,31 +1574,31 @@ static int tsi148_dma_set_vme_dest_attributes(struct device *dev, u32 *attr,
/* Setup address space */
switch (aspace) {
case VME_A16:
- *attr |= TSI148_LCSR_DDAT_AMODE_A16;
+ val |= TSI148_LCSR_DDAT_AMODE_A16;
break;
case VME_A24:
- *attr |= TSI148_LCSR_DDAT_AMODE_A24;
+ val |= TSI148_LCSR_DDAT_AMODE_A24;
break;
case VME_A32:
- *attr |= TSI148_LCSR_DDAT_AMODE_A32;
+ val |= TSI148_LCSR_DDAT_AMODE_A32;
break;
case VME_A64:
- *attr |= TSI148_LCSR_DDAT_AMODE_A64;
+ val |= TSI148_LCSR_DDAT_AMODE_A64;
break;
case VME_CRCSR:
- *attr |= TSI148_LCSR_DDAT_AMODE_CRCSR;
+ val |= TSI148_LCSR_DDAT_AMODE_CRCSR;
break;
case VME_USER1:
- *attr |= TSI148_LCSR_DDAT_AMODE_USER1;
+ val |= TSI148_LCSR_DDAT_AMODE_USER1;
break;
case VME_USER2:
- *attr |= TSI148_LCSR_DDAT_AMODE_USER2;
+ val |= TSI148_LCSR_DDAT_AMODE_USER2;
break;
case VME_USER3:
- *attr |= TSI148_LCSR_DDAT_AMODE_USER3;
+ val |= TSI148_LCSR_DDAT_AMODE_USER3;
break;
case VME_USER4:
- *attr |= TSI148_LCSR_DDAT_AMODE_USER4;
+ val |= TSI148_LCSR_DDAT_AMODE_USER4;
break;
default:
dev_err(dev, "Invalid address space\n");
@@ -1596,25 +1607,28 @@ static int tsi148_dma_set_vme_dest_attributes(struct device *dev, u32 *attr,
}
if (cycle & VME_SUPER)
- *attr |= TSI148_LCSR_DDAT_SUP;
+ val |= TSI148_LCSR_DDAT_SUP;
if (cycle & VME_PROG)
- *attr |= TSI148_LCSR_DDAT_PGM;
+ val |= TSI148_LCSR_DDAT_PGM;
+
+ *attr = cpu_to_be32(val);
return 0;
}
/*
* Add a link list descriptor to the list
+ *
+ * Note: DMA engine expects the DMA descriptor to be big endian.
*/
static int tsi148_dma_list_add(struct vme_dma_list *list,
struct vme_dma_attr *src, struct vme_dma_attr *dest, size_t count)
{
struct tsi148_dma_entry *entry, *prev;
- u32 address_high, address_low;
+ u32 address_high, address_low, val;
struct vme_dma_pattern *pattern_attr;
struct vme_dma_pci *pci_attr;
struct vme_dma_vme *vme_attr;
- dma_addr_t desc_ptr;
int retval = 0;
struct vme_bridge *tsi148_bridge;
@@ -1648,34 +1662,36 @@ static int tsi148_dma_list_add(struct vme_dma_list *list,
case VME_DMA_PATTERN:
pattern_attr = src->private;
- entry->descriptor.dsal = pattern_attr->pattern;
- entry->descriptor.dsat = TSI148_LCSR_DSAT_TYP_PAT;
+ entry->descriptor.dsal = cpu_to_be32(pattern_attr->pattern);
+
+ val = TSI148_LCSR_DSAT_TYP_PAT;
+
/* Default behaviour is 32 bit pattern */
if (pattern_attr->type & VME_DMA_PATTERN_BYTE)
- entry->descriptor.dsat |= TSI148_LCSR_DSAT_PSZ;
+ val |= TSI148_LCSR_DSAT_PSZ;
/* It seems that the default behaviour is to increment */
if ((pattern_attr->type & VME_DMA_PATTERN_INCREMENT) == 0)
- entry->descriptor.dsat |= TSI148_LCSR_DSAT_NIN;
-
+ val |= TSI148_LCSR_DSAT_NIN;
+ entry->descriptor.dsat = cpu_to_be32(val);
break;
case VME_DMA_PCI:
pci_attr = src->private;
reg_split((unsigned long long)pci_attr->address, &address_high,
&address_low);
- entry->descriptor.dsau = address_high;
- entry->descriptor.dsal = address_low;
- entry->descriptor.dsat = TSI148_LCSR_DSAT_TYP_PCI;
+ entry->descriptor.dsau = cpu_to_be32(address_high);
+ entry->descriptor.dsal = cpu_to_be32(address_low);
+ entry->descriptor.dsat = cpu_to_be32(TSI148_LCSR_DSAT_TYP_PCI);
break;
case VME_DMA_VME:
vme_attr = src->private;
reg_split((unsigned long long)vme_attr->address, &address_high,
&address_low);
- entry->descriptor.dsau = address_high;
- entry->descriptor.dsal = address_low;
- entry->descriptor.dsat = TSI148_LCSR_DSAT_TYP_VME;
+ entry->descriptor.dsau = cpu_to_be32(address_high);
+ entry->descriptor.dsal = cpu_to_be32(address_low);
+ entry->descriptor.dsat = cpu_to_be32(TSI148_LCSR_DSAT_TYP_VME);
retval = tsi148_dma_set_vme_src_attributes(
tsi148_bridge->parent, &entry->descriptor.dsat,
@@ -1691,9 +1707,8 @@ static int tsi148_dma_list_add(struct vme_dma_list *list,
}
/* Assume last link - this will be over-written by adding another */
- entry->descriptor.dnlau = 0;
- entry->descriptor.dnlal = TSI148_LCSR_DNLAL_LLA;
-
+ entry->descriptor.dnlau = cpu_to_be32(0);
+ entry->descriptor.dnlal = cpu_to_be32(TSI148_LCSR_DNLAL_LLA);
/* Fill out destination part */
switch (dest->type) {
@@ -1702,18 +1717,18 @@ static int tsi148_dma_list_add(struct vme_dma_list *list,
reg_split((unsigned long long)pci_attr->address, &address_high,
&address_low);
- entry->descriptor.ddau = address_high;
- entry->descriptor.ddal = address_low;
- entry->descriptor.ddat = TSI148_LCSR_DDAT_TYP_PCI;
+ entry->descriptor.ddau = cpu_to_be32(address_high);
+ entry->descriptor.ddal = cpu_to_be32(address_low);
+ entry->descriptor.ddat = cpu_to_be32(TSI148_LCSR_DDAT_TYP_PCI);
break;
case VME_DMA_VME:
vme_attr = dest->private;
reg_split((unsigned long long)vme_attr->address, &address_high,
&address_low);
- entry->descriptor.ddau = address_high;
- entry->descriptor.ddal = address_low;
- entry->descriptor.ddat = TSI148_LCSR_DDAT_TYP_VME;
+ entry->descriptor.ddau = cpu_to_be32(address_high);
+ entry->descriptor.ddal = cpu_to_be32(address_low);
+ entry->descriptor.ddat = cpu_to_be32(TSI148_LCSR_DDAT_TYP_VME);
retval = tsi148_dma_set_vme_dest_attributes(
tsi148_bridge->parent, &entry->descriptor.ddat,
@@ -1729,7 +1744,7 @@ static int tsi148_dma_list_add(struct vme_dma_list *list,
}
/* Fill out count */
- entry->descriptor.dcnt = (u32)count;
+ entry->descriptor.dcnt = cpu_to_be32((u32)count);
/* Add to list */
list_add_tail(&entry->list, &list->entries);
@@ -1739,9 +1754,15 @@ static int tsi148_dma_list_add(struct vme_dma_list *list,
prev = list_entry(entry->list.prev, struct tsi148_dma_entry,
list);
/* We need the bus address for the pointer */
- desc_ptr = virt_to_bus(&entry->descriptor);
- reg_split(desc_ptr, &prev->descriptor.dnlau,
- &prev->descriptor.dnlal);
+ entry->dma_handle = dma_map_single(tsi148_bridge->parent,
+ &entry->descriptor,
+ sizeof(struct tsi148_dma_descriptor), DMA_TO_DEVICE);
+
+ reg_split((unsigned long long)entry->dma_handle, &address_high,
+ &address_low);
+ entry->descriptor.dnlau = cpu_to_be32(address_high);
+ entry->descriptor.dnlal = cpu_to_be32(address_low);
+
}
return 0;
@@ -1784,7 +1805,6 @@ static int tsi148_dma_list_exec(struct vme_dma_list *list)
struct vme_dma_resource *ctrlr;
int channel, retval = 0;
struct tsi148_dma_entry *entry;
- dma_addr_t bus_addr;
u32 bus_addr_high, bus_addr_low;
u32 val, dctlreg = 0;
struct vme_bridge *tsi148_bridge;
@@ -1817,23 +1837,29 @@ static int tsi148_dma_list_exec(struct vme_dma_list *list)
entry = list_first_entry(&list->entries, struct tsi148_dma_entry,
list);
- bus_addr = virt_to_bus(&entry->descriptor);
+ entry->dma_handle = dma_map_single(tsi148_bridge->parent,
+ &entry->descriptor,
+ sizeof(struct tsi148_dma_descriptor), DMA_TO_DEVICE);
mutex_unlock(&ctrlr->mtx);
- reg_split(bus_addr, &bus_addr_high, &bus_addr_low);
+ reg_split(entry->dma_handle, &bus_addr_high, &bus_addr_low);
iowrite32be(bus_addr_high, bridge->base +
TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DNLAU);
iowrite32be(bus_addr_low, bridge->base +
TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DNLAL);
+ dctlreg = ioread32be(bridge->base + TSI148_LCSR_DMA[channel] +
+ TSI148_LCSR_OFFSET_DCTL);
+
/* Start the operation */
iowrite32be(dctlreg | TSI148_LCSR_DCTL_DGO, bridge->base +
TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DCTL);
wait_event_interruptible(bridge->dma_queue[channel],
tsi148_dma_busy(ctrlr->parent, channel));
+
/*
* Read status register, this register is valid until we kick off a
* new transfer.
@@ -1864,10 +1890,15 @@ static int tsi148_dma_list_empty(struct vme_dma_list *list)
struct list_head *pos, *temp;
struct tsi148_dma_entry *entry;
+ struct vme_bridge *tsi148_bridge = list->parent->parent;
+
/* detach and free each entry */
list_for_each_safe(pos, temp, &list->entries) {
list_del(pos);
entry = list_entry(pos, struct tsi148_dma_entry, list);
+
+ dma_unmap_single(tsi148_bridge->parent, entry->dma_handle,
+ sizeof(struct tsi148_dma_descriptor), DMA_TO_DEVICE);
kfree(entry);
}
@@ -2110,7 +2141,7 @@ static int tsi148_slot_get(struct vme_bridge *tsi148_bridge)
return (int)slot;
}
-void *tsi148_alloc_consistent(struct device *parent, size_t size,
+static void *tsi148_alloc_consistent(struct device *parent, size_t size,
dma_addr_t *dma)
{
struct pci_dev *pdev;
@@ -2121,8 +2152,8 @@ void *tsi148_alloc_consistent(struct device *parent, size_t size,
return pci_alloc_consistent(pdev, size, dma);
}
-void tsi148_free_consistent(struct device *parent, size_t size, void *vaddr,
- dma_addr_t dma)
+static void tsi148_free_consistent(struct device *parent, size_t size,
+ void *vaddr, dma_addr_t dma)
{
struct pci_dev *pdev;
diff --git a/drivers/staging/vme/bridges/vme_tsi148.h b/drivers/vme/bridges/vme_tsi148.h
index a3ac2fe98816..f5ed14382a8d 100644
--- a/drivers/staging/vme/bridges/vme_tsi148.h
+++ b/drivers/vme/bridges/vme_tsi148.h
@@ -56,16 +56,16 @@ struct tsi148_driver {
* correctly laid out - It must also be aligned on 64-bit boundaries.
*/
struct tsi148_dma_descriptor {
- u32 dsau; /* Source Address */
- u32 dsal;
- u32 ddau; /* Destination Address */
- u32 ddal;
- u32 dsat; /* Source attributes */
- u32 ddat; /* Destination attributes */
- u32 dnlau; /* Next link address */
- u32 dnlal;
- u32 dcnt; /* Byte count */
- u32 ddbs; /* 2eSST Broadcast select */
+ __be32 dsau; /* Source Address */
+ __be32 dsal;
+ __be32 ddau; /* Destination Address */
+ __be32 ddal;
+ __be32 dsat; /* Source attributes */
+ __be32 ddat; /* Destination attributes */
+ __be32 dnlau; /* Next link address */
+ __be32 dnlal;
+ __be32 dcnt; /* Byte count */
+ __be32 ddbs; /* 2eSST Broadcast select */
};
struct tsi148_dma_entry {
@@ -75,6 +75,7 @@ struct tsi148_dma_entry {
*/
struct tsi148_dma_descriptor descriptor;
struct list_head list;
+ dma_addr_t dma_handle;
};
/*
diff --git a/drivers/staging/vme/vme.c b/drivers/vme/vme.c
index 70722ae52321..95a9f71d793e 100644
--- a/drivers/staging/vme/vme.c
+++ b/drivers/vme/vme.c
@@ -30,8 +30,8 @@
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
+#include <linux/vme.h>
-#include "vme.h"
#include "vme_bridge.h"
/* Bitmask and list of registered buses both protected by common mutex */
@@ -98,14 +98,13 @@ void *vme_alloc_consistent(struct vme_resource *resource, size_t size,
}
if (bridge->parent == NULL) {
- printk(KERN_ERR "Dev entry NULL for"
- " bridge %s\n", bridge->name);
+ printk(KERN_ERR "Dev entry NULL for bridge %s\n", bridge->name);
return NULL;
}
if (bridge->alloc_consistent == NULL) {
- printk(KERN_ERR "alloc_consistent not supported by"
- " bridge %s\n", bridge->name);
+ printk(KERN_ERR "alloc_consistent not supported by bridge %s\n",
+ bridge->name);
return NULL;
}
@@ -133,14 +132,13 @@ void vme_free_consistent(struct vme_resource *resource, size_t size,
}
if (bridge->parent == NULL) {
- printk(KERN_ERR "Dev entry NULL for"
- " bridge %s\n", bridge->name);
+ printk(KERN_ERR "Dev entry NULL for bridge %s\n", bridge->name);
return;
}
if (bridge->free_consistent == NULL) {
- printk(KERN_ERR "free_consistent not supported by"
- " bridge %s\n", bridge->name);
+ printk(KERN_ERR "free_consistent not supported by bridge %s\n",
+ bridge->name);
return;
}
@@ -747,15 +745,13 @@ struct vme_dma_attr *vme_dma_pattern_attribute(u32 pattern, u32 type)
attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL);
if (attributes == NULL) {
- printk(KERN_ERR "Unable to allocate memory for attributes "
- "structure\n");
+ printk(KERN_ERR "Unable to allocate memory for attributes structure\n");
goto err_attr;
}
pattern_attr = kmalloc(sizeof(struct vme_dma_pattern), GFP_KERNEL);
if (pattern_attr == NULL) {
- printk(KERN_ERR "Unable to allocate memory for pattern "
- "attributes\n");
+ printk(KERN_ERR "Unable to allocate memory for pattern attributes\n");
goto err_pat;
}
@@ -786,15 +782,13 @@ struct vme_dma_attr *vme_dma_pci_attribute(dma_addr_t address)
attributes = kmalloc(sizeof(struct vme_dma_attr), GFP_KERNEL);
if (attributes == NULL) {
- printk(KERN_ERR "Unable to allocate memory for attributes "
- "structure\n");
+ printk(KERN_ERR "Unable to allocate memory for attributes structure\n");
goto err_attr;
}
pci_attr = kmalloc(sizeof(struct vme_dma_pci), GFP_KERNEL);
if (pci_attr == NULL) {
- printk(KERN_ERR "Unable to allocate memory for pci "
- "attributes\n");
+ printk(KERN_ERR "Unable to allocate memory for pci attributes\n");
goto err_pci;
}
@@ -826,15 +820,13 @@ struct vme_dma_attr *vme_dma_vme_attribute(unsigned long long address,
attributes = kmalloc(
sizeof(struct vme_dma_attr), GFP_KERNEL);
if (attributes == NULL) {
- printk(KERN_ERR "Unable to allocate memory for attributes "
- "structure\n");
+ printk(KERN_ERR "Unable to allocate memory for attributes structure\n");
goto err_attr;
}
vme_attr = kmalloc(sizeof(struct vme_dma_vme), GFP_KERNEL);
if (vme_attr == NULL) {
- printk(KERN_ERR "Unable to allocate memory for vme "
- "attributes\n");
+ printk(KERN_ERR "Unable to allocate memory for vme attributes\n");
goto err_vme;
}
@@ -982,8 +974,8 @@ void vme_irq_handler(struct vme_bridge *bridge, int level, int statid)
if (call != NULL)
call(level, statid, priv_data);
else
- printk(KERN_WARNING "Spurilous VME interrupt, level:%x, "
- "vector:%x\n", level, statid);
+ printk(KERN_WARNING "Spurilous VME interrupt, level:%x, vector:%x\n",
+ level, statid);
}
EXPORT_SYMBOL(vme_irq_handler);
@@ -1112,8 +1104,7 @@ struct vme_resource *vme_lm_request(struct vme_dev *vdev)
struct vme_lm_resource, list);
if (lm == NULL) {
- printk(KERN_ERR "Registered NULL Location Monitor "
- "resource\n");
+ printk(KERN_ERR "Registered NULL Location Monitor resource\n");
continue;
}
diff --git a/drivers/staging/vme/vme_bridge.h b/drivers/vme/vme_bridge.h
index 934949abd745..934949abd745 100644
--- a/drivers/staging/vme/vme_bridge.h
+++ b/drivers/vme/vme_bridge.h
diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig
index fd2c7bd9dfbe..6743bde038cc 100644
--- a/drivers/w1/Kconfig
+++ b/drivers/w1/Kconfig
@@ -16,7 +16,7 @@ config W1_CON
depends on CONNECTOR
bool "Userspace communication over connector"
default y
- --- help ---
+ ---help---
This allows to communicate with userspace using connector. For more
information see <file:Documentation/connector/connector.txt>.
There are three types of messages between w1 core and userspace:
diff --git a/drivers/w1/slaves/w1_ds2408.c b/drivers/w1/slaves/w1_ds2408.c
index 7c8cdb8aed26..8e813eed0f0a 100644
--- a/drivers/w1/slaves/w1_ds2408.c
+++ b/drivers/w1/slaves/w1_ds2408.c
@@ -332,7 +332,6 @@ static struct bin_attribute w1_f29_sysfs_bin_files[NB_SYSFS_BIN_FILES] = {
},
.size = 1,
.read = w1_f29_read_cond_search_mask,
- .write = 0,
},
{
.attr = {
@@ -341,7 +340,6 @@ static struct bin_attribute w1_f29_sysfs_bin_files[NB_SYSFS_BIN_FILES] = {
},
.size = 1,
.read = w1_f29_read_cond_search_polarity,
- .write = 0,
},
{
.attr = {
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 9761950697b4..2f2e894ea0c8 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -1027,7 +1027,7 @@ static int __init w1_init(void)
retval = driver_register(&w1_slave_driver);
if (retval) {
printk(KERN_ERR
- "Failed to register master driver. err=%d.\n",
+ "Failed to register slave driver. err=%d.\n",
retval);
goto err_out_master_unregister;
}
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c
index 3135b2c63998..e10acc237733 100644
--- a/drivers/w1/w1_io.c
+++ b/drivers/w1/w1_io.c
@@ -31,6 +31,9 @@
static int w1_delay_parm = 1;
module_param_named(delay_coef, w1_delay_parm, int, 0);
+static int w1_disable_irqs = 0;
+module_param_named(disable_irqs, w1_disable_irqs, int, 0);
+
static u8 w1_crc8_table[] = {
0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
@@ -79,6 +82,10 @@ static u8 w1_touch_bit(struct w1_master *dev, int bit)
*/
static void w1_write_bit(struct w1_master *dev, int bit)
{
+ unsigned long flags = 0;
+
+ if(w1_disable_irqs) local_irq_save(flags);
+
if (bit) {
dev->bus_master->write_bit(dev->bus_master->data, 0);
w1_delay(6);
@@ -90,6 +97,8 @@ static void w1_write_bit(struct w1_master *dev, int bit)
dev->bus_master->write_bit(dev->bus_master->data, 1);
w1_delay(10);
}
+
+ if(w1_disable_irqs) local_irq_restore(flags);
}
/**
@@ -158,7 +167,7 @@ EXPORT_SYMBOL_GPL(w1_write_8);
static u8 w1_read_bit(struct w1_master *dev)
{
int result;
- unsigned long flags;
+ unsigned long flags = 0;
/* sample timing is critical here */
local_irq_save(flags);
@@ -318,6 +327,9 @@ EXPORT_SYMBOL_GPL(w1_read_block);
int w1_reset_bus(struct w1_master *dev)
{
int result;
+ unsigned long flags = 0;
+
+ if(w1_disable_irqs) local_irq_save(flags);
if (dev->bus_master->reset_bus)
result = dev->bus_master->reset_bus(dev->bus_master->data) & 0x1;
@@ -330,19 +342,21 @@ int w1_reset_bus(struct w1_master *dev)
* cpu for such a short amount of time AND get it back in
* the maximum amount of time.
*/
- w1_delay(480);
+ w1_delay(500);
dev->bus_master->write_bit(dev->bus_master->data, 1);
w1_delay(70);
result = dev->bus_master->read_bit(dev->bus_master->data) & 0x1;
- /* minmum 70 (above) + 410 = 480 us
+ /* minmum 70 (above) + 430 = 500 us
* There aren't any timing requirements between a reset and
* the following transactions. Sleeping is safe here.
*/
- /* w1_delay(410); min required time */
+ /* w1_delay(430); min required time */
msleep(1);
}
+ if(w1_disable_irqs) local_irq_restore(flags);
+
return result;
}
EXPORT_SYMBOL_GPL(w1_reset_bus);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 37096246c937..a18bf6358eb8 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -129,17 +129,6 @@ config 977_WATCHDOG
Not sure? It's safe to say N.
-config IXP2000_WATCHDOG
- tristate "IXP2000 Watchdog"
- depends on ARCH_IXP2000
- help
- Say Y here if to include support for the watchdog timer
- in the Intel IXP2000(2400, 2800, 2850) network processors.
- This driver can be built as a module by choosing M. The module
- will be called ixp2000_wdt.
-
- Say N if you are unsure.
-
config IXP4XX_WATCHDOG
tristate "IXP4xx Watchdog"
depends on ARCH_IXP4XX
@@ -543,7 +532,7 @@ config WAFER_WDT
config I6300ESB_WDT
tristate "Intel 6300ESB Timer/Watchdog"
- depends on X86 && PCI
+ depends on PCI
---help---
Hardware driver for the watchdog timer built into the Intel
6300ESB controller hub.
@@ -551,6 +540,19 @@ config I6300ESB_WDT
To compile this driver as a module, choose M here: the
module will be called i6300esb.
+config IE6XX_WDT
+ tristate "Intel Atom E6xx Watchdog"
+ depends on X86 && PCI
+ select WATCHDOG_CORE
+ select MFD_CORE
+ select LPC_SCH
+ ---help---
+ Hardware driver for the watchdog timer built into the Intel
+ Atom E6XX (TunnelCreek) processor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ie6xx_wdt.
+
config INTEL_SCU_WATCHDOG
bool "Intel SCU Watchdog for Mobile Platforms"
depends on X86_MRST
@@ -607,7 +609,12 @@ config IT87_WDT
depends on X86 && EXPERIMENTAL
---help---
This is the driver for the hardware watchdog on the ITE IT8702,
- IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 Super I/O chips.
+ IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 and IT8728
+ Super I/O chips.
+
+ If the driver does not work, then make sure that the game port in
+ the BIOS is enabled.
+
This watchdog simply watches your kernel to make sure it doesn't
freeze, and if it does, it reboots your computer after a certain
amount of time.
@@ -780,7 +787,7 @@ config SMSC37B787_WDT
config VIA_WDT
tristate "VIA Watchdog Timer"
- depends on X86
+ depends on X86 && PCI
select WATCHDOG_CORE
---help---
This is the driver for the hardware watchdog timer on VIA
@@ -937,7 +944,7 @@ config BCM47XX_WDT
tristate "Broadcom BCM47xx Watchdog Timer"
depends on BCM47XX
help
- Hardware driver for the Broadcom BCM47xx Watchog Timer.
+ Hardware driver for the Broadcom BCM47xx Watchdog Timer.
config RC32434_WDT
tristate "IDT RC32434 SoC Watchdog Timer"
@@ -1138,6 +1145,7 @@ config ZVM_WATCHDOG
config SH_WDT
tristate "SuperH Watchdog"
depends on SUPERH && (CPU_SH3 || CPU_SH4)
+ select WATCHDOG_CORE
help
This driver adds watchdog support for the integrated watchdog in the
SuperH processors. If you have one of these processors and wish
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index e8f479a16402..442bfbe0882a 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -36,7 +36,6 @@ obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
obj-$(CONFIG_TWL4030_WATCHDOG) += twl4030_wdt.o
obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
obj-$(CONFIG_977_WATCHDOG) += wdt977.o
-obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o
obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
@@ -81,6 +80,7 @@ obj-$(CONFIG_IB700_WDT) += ib700wdt.o
obj-$(CONFIG_IBMASR) += ibmasr.o
obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o
+obj-$(CONFIG_IE6XX_WDT) += ie6xx_wdt.o
obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o
ifeq ($(CONFIG_ITCO_VENDOR_SUPPORT),y)
obj-$(CONFIG_ITCO_WDT) += iTCO_vendor_support.o
diff --git a/drivers/watchdog/ar7_wdt.c b/drivers/watchdog/ar7_wdt.c
index 639ae9a23fbc..dc30dbd21cf1 100644
--- a/drivers/watchdog/ar7_wdt.c
+++ b/drivers/watchdog/ar7_wdt.c
@@ -282,29 +282,19 @@ static int __devinit ar7_wdt_probe(struct platform_device *pdev)
platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
if (!ar7_regs_wdt) {
pr_err("could not get registers resource\n");
- rc = -ENODEV;
- goto out;
- }
-
- if (!request_mem_region(ar7_regs_wdt->start,
- resource_size(ar7_regs_wdt), LONGNAME)) {
- pr_warn("watchdog I/O region busy\n");
- rc = -EBUSY;
- goto out;
+ return -ENODEV;
}
- ar7_wdt = ioremap(ar7_regs_wdt->start, resource_size(ar7_regs_wdt));
+ ar7_wdt = devm_request_and_ioremap(&pdev->dev, ar7_regs_wdt);
if (!ar7_wdt) {
pr_err("could not ioremap registers\n");
- rc = -ENXIO;
- goto out_mem_region;
+ return -ENXIO;
}
vbus_clk = clk_get(NULL, "vbus");
if (IS_ERR(vbus_clk)) {
pr_err("could not get vbus clock\n");
- rc = PTR_ERR(vbus_clk);
- goto out_mem_region;
+ return PTR_ERR(vbus_clk);
}
ar7_wdt_disable_wdt();
@@ -314,24 +304,21 @@ static int __devinit ar7_wdt_probe(struct platform_device *pdev)
rc = misc_register(&ar7_wdt_miscdev);
if (rc) {
pr_err("unable to register misc device\n");
- goto out_alloc;
+ goto out;
}
- goto out;
+ return 0;
-out_alloc:
- iounmap(ar7_wdt);
-out_mem_region:
- release_mem_region(ar7_regs_wdt->start, resource_size(ar7_regs_wdt));
out:
+ clk_put(vbus_clk);
+ vbus_clk = NULL;
return rc;
}
static int __devexit ar7_wdt_remove(struct platform_device *pdev)
{
misc_deregister(&ar7_wdt_miscdev);
- iounmap(ar7_wdt);
- release_mem_region(ar7_regs_wdt->start, resource_size(ar7_regs_wdt));
-
+ clk_put(vbus_clk);
+ vbus_clk = NULL;
return 0;
}
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 23885f2d56a0..2b763815aeec 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -861,16 +861,6 @@ static struct pci_driver hpwdt_driver = {
.remove = __devexit_p(hpwdt_exit),
};
-static void __exit hpwdt_cleanup(void)
-{
- pci_unregister_driver(&hpwdt_driver);
-}
-
-static int __init hpwdt_init(void)
-{
- return pci_register_driver(&hpwdt_driver);
-}
-
MODULE_AUTHOR("Tom Mingarelli");
MODULE_DESCRIPTION("hp watchdog driver");
MODULE_LICENSE("GPL");
@@ -889,5 +879,4 @@ module_param(allow_kdump, int, 0);
MODULE_PARM_DESC(allow_kdump, "Start a kernel dump after NMI occurs");
#endif /* !CONFIG_HPWDT_NMI_DECODING */
-module_init(hpwdt_init);
-module_exit(hpwdt_cleanup);
+module_pci_driver(hpwdt_driver);
diff --git a/drivers/watchdog/i6300esb.c b/drivers/watchdog/i6300esb.c
index 738032a36bcf..276877d5b6a3 100644
--- a/drivers/watchdog/i6300esb.c
+++ b/drivers/watchdog/i6300esb.c
@@ -492,19 +492,7 @@ static struct pci_driver esb_driver = {
.shutdown = esb_shutdown,
};
-static int __init watchdog_init(void)
-{
- return pci_register_driver(&esb_driver);
-}
-
-static void __exit watchdog_cleanup(void)
-{
- pci_unregister_driver(&esb_driver);
- pr_info("Watchdog Module Unloaded\n");
-}
-
-module_init(watchdog_init);
-module_exit(watchdog_cleanup);
+module_pci_driver(esb_driver);
MODULE_AUTHOR("Ross Biro and David Härdeman");
MODULE_DESCRIPTION("Watchdog driver for Intel 6300ESB chipsets");
diff --git a/drivers/watchdog/ie6xx_wdt.c b/drivers/watchdog/ie6xx_wdt.c
new file mode 100644
index 000000000000..5f0d776f902c
--- /dev/null
+++ b/drivers/watchdog/ie6xx_wdt.c
@@ -0,0 +1,348 @@
+/*
+ * Intel Atom E6xx Watchdog driver
+ *
+ * Copyright (C) 2011 Alexander Stein
+ * <alexander.stein@systec-electronic.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General
+ * Public License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ * The full GNU General Public License is included in this
+ * distribution in the file called COPYING.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+#include <linux/miscdevice.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+
+#define DRIVER_NAME "ie6xx_wdt"
+
+#define PV1 0x00
+#define PV2 0x04
+
+#define RR0 0x0c
+#define RR1 0x0d
+#define WDT_RELOAD 0x01
+#define WDT_TOUT 0x02
+
+#define WDTCR 0x10
+#define WDT_PRE_SEL 0x04
+#define WDT_RESET_SEL 0x08
+#define WDT_RESET_EN 0x10
+#define WDT_TOUT_EN 0x20
+
+#define DCR 0x14
+
+#define WDTLR 0x18
+#define WDT_LOCK 0x01
+#define WDT_ENABLE 0x02
+#define WDT_TOUT_CNF 0x03
+
+#define MIN_TIME 1
+#define MAX_TIME (10 * 60) /* 10 minutes */
+#define DEFAULT_TIME 60
+
+static unsigned int timeout = DEFAULT_TIME;
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout,
+ "Default Watchdog timer setting ("
+ __MODULE_STRING(DEFAULT_TIME) "s)."
+ "The range is from 1 to 600");
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+ "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static u8 resetmode = 0x10;
+module_param(resetmode, byte, 0);
+MODULE_PARM_DESC(resetmode,
+ "Resetmode bits: 0x08 warm reset (cold reset otherwise), "
+ "0x10 reset enable, 0x20 disable toggle GPIO[4] (default=0x10)");
+
+static struct {
+ unsigned short sch_wdtba;
+ struct spinlock unlock_sequence;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs;
+#endif
+} ie6xx_wdt_data;
+
+/*
+ * This is needed to write to preload and reload registers
+ * struct ie6xx_wdt_data.unlock_sequence must be used
+ * to prevent sequence interrupts
+ */
+static void ie6xx_wdt_unlock_registers(void)
+{
+ outb(0x80, ie6xx_wdt_data.sch_wdtba + RR0);
+ outb(0x86, ie6xx_wdt_data.sch_wdtba + RR0);
+}
+
+static int ie6xx_wdt_ping(struct watchdog_device *wdd)
+{
+ spin_lock(&ie6xx_wdt_data.unlock_sequence);
+ ie6xx_wdt_unlock_registers();
+ outb(WDT_RELOAD, ie6xx_wdt_data.sch_wdtba + RR1);
+ spin_unlock(&ie6xx_wdt_data.unlock_sequence);
+ return 0;
+}
+
+static int ie6xx_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t)
+{
+ u32 preload;
+ u64 clock;
+ u8 wdtcr;
+
+ /* Watchdog clock is PCI Clock (33MHz) */
+ clock = 33000000;
+ /* and the preload value is loaded into [34:15] of the down counter */
+ preload = (t * clock) >> 15;
+ /*
+ * Manual states preload must be one less.
+ * Does not wrap as t is at least 1
+ */
+ preload -= 1;
+
+ spin_lock(&ie6xx_wdt_data.unlock_sequence);
+
+ /* Set ResetMode & Enable prescaler for range 10ms to 10 min */
+ wdtcr = resetmode & 0x38;
+ outb(wdtcr, ie6xx_wdt_data.sch_wdtba + WDTCR);
+
+ ie6xx_wdt_unlock_registers();
+ outl(0, ie6xx_wdt_data.sch_wdtba + PV1);
+
+ ie6xx_wdt_unlock_registers();
+ outl(preload, ie6xx_wdt_data.sch_wdtba + PV2);
+
+ ie6xx_wdt_unlock_registers();
+ outb(WDT_RELOAD | WDT_TOUT, ie6xx_wdt_data.sch_wdtba + RR1);
+
+ spin_unlock(&ie6xx_wdt_data.unlock_sequence);
+
+ wdd->timeout = t;
+ return 0;
+}
+
+static int ie6xx_wdt_start(struct watchdog_device *wdd)
+{
+ ie6xx_wdt_set_timeout(wdd, wdd->timeout);
+
+ /* Enable the watchdog timer */
+ spin_lock(&ie6xx_wdt_data.unlock_sequence);
+ outb(WDT_ENABLE, ie6xx_wdt_data.sch_wdtba + WDTLR);
+ spin_unlock(&ie6xx_wdt_data.unlock_sequence);
+
+ return 0;
+}
+
+static int ie6xx_wdt_stop(struct watchdog_device *wdd)
+{
+ if (inb(ie6xx_wdt_data.sch_wdtba + WDTLR) & WDT_LOCK)
+ return -1;
+
+ /* Disable the watchdog timer */
+ spin_lock(&ie6xx_wdt_data.unlock_sequence);
+ outb(0, ie6xx_wdt_data.sch_wdtba + WDTLR);
+ spin_unlock(&ie6xx_wdt_data.unlock_sequence);
+
+ return 0;
+}
+
+static const struct watchdog_info ie6xx_wdt_info = {
+ .identity = "Intel Atom E6xx Watchdog",
+ .options = WDIOF_SETTIMEOUT |
+ WDIOF_MAGICCLOSE |
+ WDIOF_KEEPALIVEPING,
+};
+
+static const struct watchdog_ops ie6xx_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = ie6xx_wdt_start,
+ .stop = ie6xx_wdt_stop,
+ .ping = ie6xx_wdt_ping,
+ .set_timeout = ie6xx_wdt_set_timeout,
+};
+
+static struct watchdog_device ie6xx_wdt_dev = {
+ .info = &ie6xx_wdt_info,
+ .ops = &ie6xx_wdt_ops,
+ .min_timeout = MIN_TIME,
+ .max_timeout = MAX_TIME,
+};
+
+#ifdef CONFIG_DEBUG_FS
+
+static int ie6xx_wdt_dbg_show(struct seq_file *s, void *unused)
+{
+ seq_printf(s, "PV1 = 0x%08x\n",
+ inl(ie6xx_wdt_data.sch_wdtba + PV1));
+ seq_printf(s, "PV2 = 0x%08x\n",
+ inl(ie6xx_wdt_data.sch_wdtba + PV2));
+ seq_printf(s, "RR = 0x%08x\n",
+ inw(ie6xx_wdt_data.sch_wdtba + RR0));
+ seq_printf(s, "WDTCR = 0x%08x\n",
+ inw(ie6xx_wdt_data.sch_wdtba + WDTCR));
+ seq_printf(s, "DCR = 0x%08x\n",
+ inl(ie6xx_wdt_data.sch_wdtba + DCR));
+ seq_printf(s, "WDTLR = 0x%08x\n",
+ inw(ie6xx_wdt_data.sch_wdtba + WDTLR));
+
+ seq_printf(s, "\n");
+ return 0;
+}
+
+static int ie6xx_wdt_dbg_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ie6xx_wdt_dbg_show, NULL);
+}
+
+static const struct file_operations ie6xx_wdt_dbg_operations = {
+ .open = ie6xx_wdt_dbg_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void __devinit ie6xx_wdt_debugfs_init(void)
+{
+ /* /sys/kernel/debug/ie6xx_wdt */
+ ie6xx_wdt_data.debugfs = debugfs_create_file("ie6xx_wdt",
+ S_IFREG | S_IRUGO, NULL, NULL, &ie6xx_wdt_dbg_operations);
+}
+
+static void __devexit ie6xx_wdt_debugfs_exit(void)
+{
+ debugfs_remove(ie6xx_wdt_data.debugfs);
+}
+
+#else
+static void __devinit ie6xx_wdt_debugfs_init(void)
+{
+}
+
+static void __devexit ie6xx_wdt_debugfs_exit(void)
+{
+}
+#endif
+
+static int __devinit ie6xx_wdt_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ u8 wdtlr;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!res)
+ return -ENODEV;
+
+ if (!request_region(res->start, resource_size(res), pdev->name)) {
+ dev_err(&pdev->dev, "Watchdog region 0x%llx already in use!\n",
+ (u64)res->start);
+ return -EBUSY;
+ }
+
+ ie6xx_wdt_data.sch_wdtba = res->start;
+ dev_dbg(&pdev->dev, "WDT = 0x%X\n", ie6xx_wdt_data.sch_wdtba);
+
+ ie6xx_wdt_dev.timeout = timeout;
+ watchdog_set_nowayout(&ie6xx_wdt_dev, nowayout);
+
+ spin_lock_init(&ie6xx_wdt_data.unlock_sequence);
+
+ wdtlr = inb(ie6xx_wdt_data.sch_wdtba + WDTLR);
+ if (wdtlr & WDT_LOCK)
+ dev_warn(&pdev->dev,
+ "Watchdog Timer is Locked (Reg=0x%x)\n", wdtlr);
+
+ ie6xx_wdt_debugfs_init();
+
+ ret = watchdog_register_device(&ie6xx_wdt_dev);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Watchdog timer: cannot register device (err =%d)\n",
+ ret);
+ goto misc_register_error;
+ }
+
+ return 0;
+
+misc_register_error:
+ ie6xx_wdt_debugfs_exit();
+ release_region(res->start, resource_size(res));
+ ie6xx_wdt_data.sch_wdtba = 0;
+ return ret;
+}
+
+static int __devexit ie6xx_wdt_remove(struct platform_device *pdev)
+{
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ ie6xx_wdt_stop(NULL);
+ watchdog_unregister_device(&ie6xx_wdt_dev);
+ ie6xx_wdt_debugfs_exit();
+ release_region(res->start, resource_size(res));
+ ie6xx_wdt_data.sch_wdtba = 0;
+
+ return 0;
+}
+
+static struct platform_driver ie6xx_wdt_driver = {
+ .probe = ie6xx_wdt_probe,
+ .remove = __devexit_p(ie6xx_wdt_remove),
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ie6xx_wdt_init(void)
+{
+ /* Check boot parameters to verify that their initial values */
+ /* are in range. */
+ if ((timeout < MIN_TIME) ||
+ (timeout > MAX_TIME)) {
+ pr_err("Watchdog timer: value of timeout %d (dec) "
+ "is out of range from %d to %d (dec)\n",
+ timeout, MIN_TIME, MAX_TIME);
+ return -EINVAL;
+ }
+
+ return platform_driver_register(&ie6xx_wdt_driver);
+}
+
+static void __exit ie6xx_wdt_exit(void)
+{
+ platform_driver_unregister(&ie6xx_wdt_driver);
+}
+
+late_initcall(ie6xx_wdt_init);
+module_exit(ie6xx_wdt_exit);
+
+MODULE_AUTHOR("Alexander Stein <alexander.stein@systec-electronic.com>");
+MODULE_DESCRIPTION("Intel Atom E6xx Watchdog Device Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c
index 8a741bcb5124..d3dcc6988b5f 100644
--- a/drivers/watchdog/it87_wdt.c
+++ b/drivers/watchdog/it87_wdt.c
@@ -12,7 +12,8 @@
* http://www.ite.com.tw/
*
* Support of the watchdog timers, which are available on
- * IT8702, IT8712, IT8716, IT8718, IT8720, IT8721 and IT8726.
+ * IT8702, IT8712, IT8716, IT8718, IT8720, IT8721, IT8726
+ * and IT8728.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -84,6 +85,7 @@
#define IT8720_ID 0x8720
#define IT8721_ID 0x8721
#define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */
+#define IT8728_ID 0x8728
/* GPIO Configuration Registers LDN=0x07 */
#define WDTCTRL 0x71
@@ -95,7 +97,7 @@
#define WDT_CIRINT 0x80
#define WDT_MOUSEINT 0x40
#define WDT_KYBINT 0x20
-#define WDT_GAMEPORT 0x10 /* not in it8718, it8720, it8721 */
+#define WDT_GAMEPORT 0x10 /* not in it8718, it8720, it8721, it8728 */
#define WDT_FORCE 0x02
#define WDT_ZERO 0x01
@@ -616,6 +618,7 @@ static int __init it87_wdt_init(void)
case IT8718_ID:
case IT8720_ID:
case IT8721_ID:
+ case IT8728_ID:
max_units = 65535;
try_gameport = 0;
break;
diff --git a/drivers/watchdog/ixp2000_wdt.c b/drivers/watchdog/ixp2000_wdt.c
deleted file mode 100644
index 3f047a58d3ae..000000000000
--- a/drivers/watchdog/ixp2000_wdt.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * drivers/char/watchdog/ixp2000_wdt.c
- *
- * Watchdog driver for Intel IXP2000 network processors
- *
- * Adapted from the IXP4xx watchdog driver by Lennert Buytenhek.
- * The original version carries these notices:
- *
- * Author: Deepak Saxena <dsaxena@plexity.net>
- *
- * Copyright 2004 (c) MontaVista, Software, Inc.
- * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/timer.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <linux/uaccess.h>
-#include <mach/hardware.h>
-
-static bool nowayout = WATCHDOG_NOWAYOUT;
-static unsigned int heartbeat = 60; /* (secs) Default is 1 minute */
-static unsigned long wdt_status;
-static DEFINE_SPINLOCK(wdt_lock);
-
-#define WDT_IN_USE 0
-#define WDT_OK_TO_CLOSE 1
-
-static unsigned long wdt_tick_rate;
-
-static void wdt_enable(void)
-{
- spin_lock(&wdt_lock);
- ixp2000_reg_write(IXP2000_RESET0, *(IXP2000_RESET0) | WDT_RESET_ENABLE);
- ixp2000_reg_write(IXP2000_TWDE, WDT_ENABLE);
- ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
- ixp2000_reg_write(IXP2000_T4_CTL, TIMER_DIVIDER_256 | TIMER_ENABLE);
- spin_unlock(&wdt_lock);
-}
-
-static void wdt_disable(void)
-{
- spin_lock(&wdt_lock);
- ixp2000_reg_write(IXP2000_T4_CTL, 0);
- spin_unlock(&wdt_lock);
-}
-
-static void wdt_keepalive(void)
-{
- spin_lock(&wdt_lock);
- ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
- spin_unlock(&wdt_lock);
-}
-
-static int ixp2000_wdt_open(struct inode *inode, struct file *file)
-{
- if (test_and_set_bit(WDT_IN_USE, &wdt_status))
- return -EBUSY;
-
- clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
- wdt_enable();
-
- return nonseekable_open(inode, file);
-}
-
-static ssize_t ixp2000_wdt_write(struct file *file, const char *data,
- size_t len, loff_t *ppos)
-{
- if (len) {
- if (!nowayout) {
- size_t i;
-
- clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
- for (i = 0; i != len; i++) {
- char c;
-
- if (get_user(c, data + i))
- return -EFAULT;
- if (c == 'V')
- set_bit(WDT_OK_TO_CLOSE, &wdt_status);
- }
- }
- wdt_keepalive();
- }
-
- return len;
-}
-
-
-static const struct watchdog_info ident = {
- .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
- WDIOF_KEEPALIVEPING,
- .identity = "IXP2000 Watchdog",
-};
-
-static long ixp2000_wdt_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- int ret = -ENOTTY;
- int time;
-
- switch (cmd) {
- case WDIOC_GETSUPPORT:
- ret = copy_to_user((struct watchdog_info *)arg, &ident,
- sizeof(ident)) ? -EFAULT : 0;
- break;
-
- case WDIOC_GETSTATUS:
- ret = put_user(0, (int *)arg);
- break;
-
- case WDIOC_GETBOOTSTATUS:
- ret = put_user(0, (int *)arg);
- break;
-
- case WDIOC_KEEPALIVE:
- wdt_enable();
- ret = 0;
- break;
-
- case WDIOC_SETTIMEOUT:
- ret = get_user(time, (int *)arg);
- if (ret)
- break;
-
- if (time <= 0 || time > 60) {
- ret = -EINVAL;
- break;
- }
-
- heartbeat = time;
- wdt_keepalive();
- /* Fall through */
-
- case WDIOC_GETTIMEOUT:
- ret = put_user(heartbeat, (int *)arg);
- break;
- }
-
- return ret;
-}
-
-static int ixp2000_wdt_release(struct inode *inode, struct file *file)
-{
- if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
- wdt_disable();
- else
- pr_crit("Device closed unexpectedly - timer will not stop\n");
- clear_bit(WDT_IN_USE, &wdt_status);
- clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-
- return 0;
-}
-
-
-static const struct file_operations ixp2000_wdt_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = ixp2000_wdt_write,
- .unlocked_ioctl = ixp2000_wdt_ioctl,
- .open = ixp2000_wdt_open,
- .release = ixp2000_wdt_release,
-};
-
-static struct miscdevice ixp2000_wdt_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &ixp2000_wdt_fops,
-};
-
-static int __init ixp2000_wdt_init(void)
-{
- if ((*IXP2000_PRODUCT_ID & 0x001ffef0) == 0x00000000) {
- pr_info("Unable to use IXP2000 watchdog due to IXP2800 erratum #25\n");
- return -EIO;
- }
- wdt_tick_rate = (*IXP2000_T1_CLD * HZ) / 256;
- return misc_register(&ixp2000_wdt_miscdev);
-}
-
-static void __exit ixp2000_wdt_exit(void)
-{
- misc_deregister(&ixp2000_wdt_miscdev);
-}
-
-module_init(ixp2000_wdt_init);
-module_exit(ixp2000_wdt_exit);
-
-MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
-MODULE_DESCRIPTION("IXP2000 Network Processor Watchdog");
-
-module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)");
-
-module_param(nowayout, bool, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
-
diff --git a/drivers/watchdog/pcwd_pci.c b/drivers/watchdog/pcwd_pci.c
index c891399bed6a..ee6900da8678 100644
--- a/drivers/watchdog/pcwd_pci.c
+++ b/drivers/watchdog/pcwd_pci.c
@@ -707,6 +707,7 @@ static int __devinit pcipcwd_card_init(struct pci_dev *pdev,
goto err_out_disable_device;
}
+ spin_lock_init(&pcipcwd_private.io_lock);
pcipcwd_private.pdev = pdev;
pcipcwd_private.io_addr = pci_resource_start(pdev, 0);
@@ -814,22 +815,7 @@ static struct pci_driver pcipcwd_driver = {
.remove = __devexit_p(pcipcwd_card_exit),
};
-static int __init pcipcwd_init_module(void)
-{
- spin_lock_init(&pcipcwd_private.io_lock);
-
- return pci_register_driver(&pcipcwd_driver);
-}
-
-static void __exit pcipcwd_cleanup_module(void)
-{
- pci_unregister_driver(&pcipcwd_driver);
-
- pr_info("Watchdog Module Unloaded\n");
-}
-
-module_init(pcipcwd_init_module);
-module_exit(pcipcwd_cleanup_module);
+module_pci_driver(pcipcwd_driver);
MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
MODULE_DESCRIPTION("Berkshire PCI-PC Watchdog driver");
diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c
index 6b8432f61d05..87722e126058 100644
--- a/drivers/watchdog/pnx4008_wdt.c
+++ b/drivers/watchdog/pnx4008_wdt.c
@@ -32,6 +32,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/err.h>
+#include <linux/of.h>
#include <mach/hardware.h>
/* WatchDog Timer - Chapter 23 Page 207 */
@@ -201,10 +202,19 @@ static int __devexit pnx4008_wdt_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id pnx4008_wdt_match[] = {
+ { .compatible = "nxp,pnx4008-wdt" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pnx4008_wdt_match);
+#endif
+
static struct platform_driver platform_wdt_driver = {
.driver = {
.name = "pnx4008-watchdog",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(pnx4008_wdt_match),
},
.probe = pnx4008_wdt_probe,
.remove = __devexit_p(pnx4008_wdt_remove),
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index 04e5a6de47d7..200ece5e2a22 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -40,6 +40,7 @@
#include <linux/cpufreq.h>
#include <linux/slab.h>
#include <linux/err.h>
+#include <linux/of.h>
#include <mach/map.h>
@@ -201,7 +202,7 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeou
writel(count, wdt_base + S3C2410_WTDAT);
writel(wtcon, wdt_base + S3C2410_WTCON);
- wdd->timeout = timeout;
+ wdd->timeout = (count * divisor) / freq;
return 0;
}
@@ -503,8 +504,6 @@ static const struct of_device_id s3c2410_wdt_match[] = {
{},
};
MODULE_DEVICE_TABLE(of, s3c2410_wdt_match);
-#else
-#define s3c2410_wdt_match NULL
#endif
static struct platform_driver s3c2410wdt_driver = {
@@ -516,7 +515,7 @@ static struct platform_driver s3c2410wdt_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "s3c2410-wdt",
- .of_match_table = s3c2410_wdt_match,
+ .of_match_table = of_match_ptr(s3c2410_wdt_match),
},
};
diff --git a/drivers/watchdog/sch311x_wdt.c b/drivers/watchdog/sch311x_wdt.c
index bd86f32d63ab..f8477002b728 100644
--- a/drivers/watchdog/sch311x_wdt.c
+++ b/drivers/watchdog/sch311x_wdt.c
@@ -41,7 +41,6 @@
#define DRV_NAME "sch311x_wdt"
/* Runtime registers */
-#define RESGEN 0x1d
#define GP60 0x47
#define WDT_TIME_OUT 0x65
#define WDT_VAL 0x66
@@ -69,10 +68,6 @@ static unsigned short force_id;
module_param(force_id, ushort, 0);
MODULE_PARM_DESC(force_id, "Override the detected device ID");
-static unsigned short therm_trip;
-module_param(therm_trip, ushort, 0);
-MODULE_PARM_DESC(therm_trip, "Should a ThermTrip trigger the reset generator");
-
#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
module_param(timeout, int, 0);
@@ -358,26 +353,16 @@ static struct miscdevice sch311x_wdt_miscdev = {
static int __devinit sch311x_wdt_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- unsigned char val;
int err;
spin_lock_init(&sch311x_wdt_data.io_lock);
- if (!request_region(sch311x_wdt_data.runtime_reg + RESGEN, 1,
- DRV_NAME)) {
- dev_err(dev, "Failed to request region 0x%04x-0x%04x.\n",
- sch311x_wdt_data.runtime_reg + RESGEN,
- sch311x_wdt_data.runtime_reg + RESGEN);
- err = -EBUSY;
- goto exit;
- }
-
if (!request_region(sch311x_wdt_data.runtime_reg + GP60, 1, DRV_NAME)) {
dev_err(dev, "Failed to request region 0x%04x-0x%04x.\n",
sch311x_wdt_data.runtime_reg + GP60,
sch311x_wdt_data.runtime_reg + GP60);
err = -EBUSY;
- goto exit_release_region;
+ goto exit;
}
if (!request_region(sch311x_wdt_data.runtime_reg + WDT_TIME_OUT, 4,
@@ -386,7 +371,7 @@ static int __devinit sch311x_wdt_probe(struct platform_device *pdev)
sch311x_wdt_data.runtime_reg + WDT_TIME_OUT,
sch311x_wdt_data.runtime_reg + WDT_CTRL);
err = -EBUSY;
- goto exit_release_region2;
+ goto exit_release_region;
}
/* Make sure that the watchdog is not running */
@@ -414,24 +399,13 @@ static int __devinit sch311x_wdt_probe(struct platform_device *pdev)
/* Get status at boot */
sch311x_wdt_get_status(&sch311x_wdt_data.boot_status);
- /* enable watchdog */
- /* -- Reset Generator --
- * Bit 0 Enable Watchdog Timer Generation: 0* = Enabled, 1 = Disabled
- * Bit 1 Thermtrip Source Select: O* = No Source, 1 = Source
- * Bit 2 WDT2_CTL: WDT input bit
- * Bit 3-7 Reserved
- */
- outb(0, sch311x_wdt_data.runtime_reg + RESGEN);
- val = therm_trip ? 0x06 : 0x04;
- outb(val, sch311x_wdt_data.runtime_reg + RESGEN);
-
sch311x_wdt_miscdev.parent = dev;
err = misc_register(&sch311x_wdt_miscdev);
if (err != 0) {
dev_err(dev, "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, err);
- goto exit_release_region3;
+ goto exit_release_region2;
}
dev_info(dev,
@@ -440,12 +414,10 @@ static int __devinit sch311x_wdt_probe(struct platform_device *pdev)
return 0;
-exit_release_region3:
- release_region(sch311x_wdt_data.runtime_reg + WDT_TIME_OUT, 4);
exit_release_region2:
- release_region(sch311x_wdt_data.runtime_reg + GP60, 1);
+ release_region(sch311x_wdt_data.runtime_reg + WDT_TIME_OUT, 4);
exit_release_region:
- release_region(sch311x_wdt_data.runtime_reg + RESGEN, 1);
+ release_region(sch311x_wdt_data.runtime_reg + GP60, 1);
sch311x_wdt_data.runtime_reg = 0;
exit:
return err;
@@ -461,7 +433,6 @@ static int __devexit sch311x_wdt_remove(struct platform_device *pdev)
misc_deregister(&sch311x_wdt_miscdev);
release_region(sch311x_wdt_data.runtime_reg + WDT_TIME_OUT, 4);
release_region(sch311x_wdt_data.runtime_reg + GP60, 1);
- release_region(sch311x_wdt_data.runtime_reg + RESGEN, 1);
sch311x_wdt_data.runtime_reg = 0;
return 0;
}
diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c
index 93958a7763e6..e5b59bebcdb1 100644
--- a/drivers/watchdog/shwdt.c
+++ b/drivers/watchdog/shwdt.c
@@ -3,7 +3,7 @@
*
* Watchdog driver for integrated watchdog in the SuperH processors.
*
- * Copyright (C) 2001 - 2010 Paul Mundt <lethal@linux-sh.org>
+ * Copyright (C) 2001 - 2012 Paul Mundt <lethal@linux-sh.org>
*
* 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
@@ -25,16 +25,15 @@
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/types.h>
+#include <linux/spinlock.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
-#include <linux/reboot.h>
-#include <linux/notifier.h>
-#include <linux/ioport.h>
+#include <linux/pm_runtime.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/io.h>
-#include <linux/uaccess.h>
+#include <linux/clk.h>
#include <asm/watchdog.h>
#define DRV_NAME "sh-wdt"
@@ -69,10 +68,6 @@
static int clock_division_ratio = WTCSR_CKS_4096;
#define next_ping_period(cks) (jiffies + msecs_to_jiffies(cks - 4))
-static const struct watchdog_info sh_wdt_info;
-static struct platform_device *sh_wdt_dev;
-static DEFINE_SPINLOCK(shwdt_lock);
-
#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */
static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
static bool nowayout = WATCHDOG_NOWAYOUT;
@@ -81,19 +76,22 @@ static unsigned long next_heartbeat;
struct sh_wdt {
void __iomem *base;
struct device *dev;
+ struct clk *clk;
+ spinlock_t lock;
struct timer_list timer;
-
- unsigned long enabled;
- char expect_close;
};
-static void sh_wdt_start(struct sh_wdt *wdt)
+static int sh_wdt_start(struct watchdog_device *wdt_dev)
{
+ struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
unsigned long flags;
u8 csr;
- spin_lock_irqsave(&shwdt_lock, flags);
+ pm_runtime_get_sync(wdt->dev);
+ clk_enable(wdt->clk);
+
+ spin_lock_irqsave(&wdt->lock, flags);
next_heartbeat = jiffies + (heartbeat * HZ);
mod_timer(&wdt->timer, next_ping_period(clock_division_ratio));
@@ -122,15 +120,18 @@ static void sh_wdt_start(struct sh_wdt *wdt)
csr &= ~RSTCSR_RSTS;
sh_wdt_write_rstcsr(csr);
#endif
- spin_unlock_irqrestore(&shwdt_lock, flags);
+ spin_unlock_irqrestore(&wdt->lock, flags);
+
+ return 0;
}
-static void sh_wdt_stop(struct sh_wdt *wdt)
+static int sh_wdt_stop(struct watchdog_device *wdt_dev)
{
+ struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
unsigned long flags;
u8 csr;
- spin_lock_irqsave(&shwdt_lock, flags);
+ spin_lock_irqsave(&wdt->lock, flags);
del_timer(&wdt->timer);
@@ -138,28 +139,39 @@ static void sh_wdt_stop(struct sh_wdt *wdt)
csr &= ~WTCSR_TME;
sh_wdt_write_csr(csr);
- spin_unlock_irqrestore(&shwdt_lock, flags);
+ spin_unlock_irqrestore(&wdt->lock, flags);
+
+ clk_disable(wdt->clk);
+ pm_runtime_put_sync(wdt->dev);
+
+ return 0;
}
-static inline void sh_wdt_keepalive(struct sh_wdt *wdt)
+static int sh_wdt_keepalive(struct watchdog_device *wdt_dev)
{
+ struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
unsigned long flags;
- spin_lock_irqsave(&shwdt_lock, flags);
+ spin_lock_irqsave(&wdt->lock, flags);
next_heartbeat = jiffies + (heartbeat * HZ);
- spin_unlock_irqrestore(&shwdt_lock, flags);
+ spin_unlock_irqrestore(&wdt->lock, flags);
+
+ return 0;
}
-static int sh_wdt_set_heartbeat(int t)
+static int sh_wdt_set_heartbeat(struct watchdog_device *wdt_dev, unsigned t)
{
+ struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
unsigned long flags;
if (unlikely(t < 1 || t > 3600)) /* arbitrary upper limit */
return -EINVAL;
- spin_lock_irqsave(&shwdt_lock, flags);
+ spin_lock_irqsave(&wdt->lock, flags);
heartbeat = t;
- spin_unlock_irqrestore(&shwdt_lock, flags);
+ wdt_dev->timeout = t;
+ spin_unlock_irqrestore(&wdt->lock, flags);
+
return 0;
}
@@ -168,7 +180,7 @@ static void sh_wdt_ping(unsigned long data)
struct sh_wdt *wdt = (struct sh_wdt *)data;
unsigned long flags;
- spin_lock_irqsave(&shwdt_lock, flags);
+ spin_lock_irqsave(&wdt->lock, flags);
if (time_before(jiffies, next_heartbeat)) {
u8 csr;
@@ -182,137 +194,9 @@ static void sh_wdt_ping(unsigned long data)
} else
dev_warn(wdt->dev, "Heartbeat lost! Will not ping "
"the watchdog\n");
- spin_unlock_irqrestore(&shwdt_lock, flags);
-}
-
-static int sh_wdt_open(struct inode *inode, struct file *file)
-{
- struct sh_wdt *wdt = platform_get_drvdata(sh_wdt_dev);
-
- if (test_and_set_bit(0, &wdt->enabled))
- return -EBUSY;
- if (nowayout)
- __module_get(THIS_MODULE);
-
- file->private_data = wdt;
-
- sh_wdt_start(wdt);
-
- return nonseekable_open(inode, file);
-}
-
-static int sh_wdt_close(struct inode *inode, struct file *file)
-{
- struct sh_wdt *wdt = file->private_data;
-
- if (wdt->expect_close == 42) {
- sh_wdt_stop(wdt);
- } else {
- dev_crit(wdt->dev, "Unexpected close, not "
- "stopping watchdog!\n");
- sh_wdt_keepalive(wdt);
- }
-
- clear_bit(0, &wdt->enabled);
- wdt->expect_close = 0;
-
- return 0;
-}
-
-static ssize_t sh_wdt_write(struct file *file, const char *buf,
- size_t count, loff_t *ppos)
-{
- struct sh_wdt *wdt = file->private_data;
-
- if (count) {
- if (!nowayout) {
- size_t i;
-
- wdt->expect_close = 0;
-
- for (i = 0; i != count; i++) {
- char c;
- if (get_user(c, buf + i))
- return -EFAULT;
- if (c == 'V')
- wdt->expect_close = 42;
- }
- }
- sh_wdt_keepalive(wdt);
- }
-
- return count;
+ spin_unlock_irqrestore(&wdt->lock, flags);
}
-static long sh_wdt_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct sh_wdt *wdt = file->private_data;
- int new_heartbeat;
- int options, retval = -EINVAL;
-
- switch (cmd) {
- case WDIOC_GETSUPPORT:
- return copy_to_user((struct watchdog_info *)arg,
- &sh_wdt_info, sizeof(sh_wdt_info)) ? -EFAULT : 0;
- case WDIOC_GETSTATUS:
- case WDIOC_GETBOOTSTATUS:
- return put_user(0, (int *)arg);
- case WDIOC_SETOPTIONS:
- if (get_user(options, (int *)arg))
- return -EFAULT;
-
- if (options & WDIOS_DISABLECARD) {
- sh_wdt_stop(wdt);
- retval = 0;
- }
-
- if (options & WDIOS_ENABLECARD) {
- sh_wdt_start(wdt);
- retval = 0;
- }
-
- return retval;
- case WDIOC_KEEPALIVE:
- sh_wdt_keepalive(wdt);
- return 0;
- case WDIOC_SETTIMEOUT:
- if (get_user(new_heartbeat, (int *)arg))
- return -EFAULT;
-
- if (sh_wdt_set_heartbeat(new_heartbeat))
- return -EINVAL;
-
- sh_wdt_keepalive(wdt);
- /* Fall */
- case WDIOC_GETTIMEOUT:
- return put_user(heartbeat, (int *)arg);
- default:
- return -ENOTTY;
- }
- return 0;
-}
-
-static int sh_wdt_notify_sys(struct notifier_block *this,
- unsigned long code, void *unused)
-{
- struct sh_wdt *wdt = platform_get_drvdata(sh_wdt_dev);
-
- if (code == SYS_DOWN || code == SYS_HALT)
- sh_wdt_stop(wdt);
-
- return NOTIFY_DONE;
-}
-
-static const struct file_operations sh_wdt_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = sh_wdt_write,
- .unlocked_ioctl = sh_wdt_ioctl,
- .open = sh_wdt_open,
- .release = sh_wdt_close,
-};
-
static const struct watchdog_info sh_wdt_info = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE,
@@ -320,14 +204,17 @@ static const struct watchdog_info sh_wdt_info = {
.identity = "SH WDT",
};
-static struct notifier_block sh_wdt_notifier = {
- .notifier_call = sh_wdt_notify_sys,
+static const struct watchdog_ops sh_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = sh_wdt_start,
+ .stop = sh_wdt_stop,
+ .ping = sh_wdt_keepalive,
+ .set_timeout = sh_wdt_set_heartbeat,
};
-static struct miscdevice sh_wdt_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &sh_wdt_fops,
+static struct watchdog_device sh_wdt_dev = {
+ .info = &sh_wdt_info,
+ .ops = &sh_wdt_ops,
};
static int __devinit sh_wdt_probe(struct platform_device *pdev)
@@ -347,39 +234,49 @@ static int __devinit sh_wdt_probe(struct platform_device *pdev)
if (unlikely(!res))
return -EINVAL;
- if (!devm_request_mem_region(&pdev->dev, res->start,
- resource_size(res), DRV_NAME))
- return -EBUSY;
-
wdt = devm_kzalloc(&pdev->dev, sizeof(struct sh_wdt), GFP_KERNEL);
- if (unlikely(!wdt)) {
- rc = -ENOMEM;
- goto out_release;
- }
+ if (unlikely(!wdt))
+ return -ENOMEM;
wdt->dev = &pdev->dev;
- wdt->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ wdt->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(wdt->clk)) {
+ /*
+ * Clock framework support is optional, continue on
+ * anyways if we don't find a matching clock.
+ */
+ wdt->clk = NULL;
+ }
+
+ wdt->base = devm_request_and_ioremap(wdt->dev, res);
if (unlikely(!wdt->base)) {
- rc = -ENXIO;
- goto out_err;
+ rc = -EADDRNOTAVAIL;
+ goto err;
}
- rc = register_reboot_notifier(&sh_wdt_notifier);
+ watchdog_set_nowayout(&sh_wdt_dev, nowayout);
+ watchdog_set_drvdata(&sh_wdt_dev, wdt);
+
+ spin_lock_init(&wdt->lock);
+
+ rc = sh_wdt_set_heartbeat(&sh_wdt_dev, heartbeat);
if (unlikely(rc)) {
- dev_err(&pdev->dev,
- "Can't register reboot notifier (err=%d)\n", rc);
- goto out_unmap;
+ /* Default timeout if invalid */
+ sh_wdt_set_heartbeat(&sh_wdt_dev, WATCHDOG_HEARTBEAT);
+
+ dev_warn(&pdev->dev,
+ "heartbeat value must be 1<=x<=3600, using %d\n",
+ sh_wdt_dev.timeout);
}
- sh_wdt_miscdev.parent = wdt->dev;
+ dev_info(&pdev->dev, "configured with heartbeat=%d sec (nowayout=%d)\n",
+ sh_wdt_dev.timeout, nowayout);
- rc = misc_register(&sh_wdt_miscdev);
+ rc = watchdog_register_device(&sh_wdt_dev);
if (unlikely(rc)) {
- dev_err(&pdev->dev,
- "Can't register miscdev on minor=%d (err=%d)\n",
- sh_wdt_miscdev.minor, rc);
- goto out_unreg;
+ dev_err(&pdev->dev, "Can't register watchdog (err=%d)\n", rc);
+ goto err;
}
init_timer(&wdt->timer);
@@ -388,20 +285,15 @@ static int __devinit sh_wdt_probe(struct platform_device *pdev)
wdt->timer.expires = next_ping_period(clock_division_ratio);
platform_set_drvdata(pdev, wdt);
- sh_wdt_dev = pdev;
dev_info(&pdev->dev, "initialized.\n");
+ pm_runtime_enable(&pdev->dev);
+
return 0;
-out_unreg:
- unregister_reboot_notifier(&sh_wdt_notifier);
-out_unmap:
- devm_iounmap(&pdev->dev, wdt->base);
-out_err:
- devm_kfree(&pdev->dev, wdt);
-out_release:
- devm_release_mem_region(&pdev->dev, res->start, resource_size(res));
+err:
+ clk_put(wdt->clk);
return rc;
}
@@ -409,36 +301,35 @@ out_release:
static int __devexit sh_wdt_remove(struct platform_device *pdev)
{
struct sh_wdt *wdt = platform_get_drvdata(pdev);
- struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
platform_set_drvdata(pdev, NULL);
- misc_deregister(&sh_wdt_miscdev);
+ watchdog_unregister_device(&sh_wdt_dev);
- sh_wdt_dev = NULL;
-
- unregister_reboot_notifier(&sh_wdt_notifier);
- devm_release_mem_region(&pdev->dev, res->start, resource_size(res));
- devm_iounmap(&pdev->dev, wdt->base);
- devm_kfree(&pdev->dev, wdt);
+ pm_runtime_disable(&pdev->dev);
+ clk_put(wdt->clk);
return 0;
}
+static void sh_wdt_shutdown(struct platform_device *pdev)
+{
+ sh_wdt_stop(&sh_wdt_dev);
+}
+
static struct platform_driver sh_wdt_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
- .probe = sh_wdt_probe,
- .remove = __devexit_p(sh_wdt_remove),
+ .probe = sh_wdt_probe,
+ .remove = __devexit_p(sh_wdt_remove),
+ .shutdown = sh_wdt_shutdown,
};
static int __init sh_wdt_init(void)
{
- int rc;
-
if (unlikely(clock_division_ratio < 0x5 ||
clock_division_ratio > 0x7)) {
clock_division_ratio = WTCSR_CKS_4096;
@@ -447,17 +338,6 @@ static int __init sh_wdt_init(void)
clock_division_ratio);
}
- rc = sh_wdt_set_heartbeat(heartbeat);
- if (unlikely(rc)) {
- heartbeat = WATCHDOG_HEARTBEAT;
-
- pr_info("heartbeat value must be 1<=x<=3600, using %d\n",
- heartbeat);
- }
-
- pr_info("configured with heartbeat=%d sec (nowayout=%d)\n",
- heartbeat, nowayout);
-
return platform_driver_register(&sh_wdt_driver);
}
diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c
index 59108e48ada3..ae5e82cb83fa 100644
--- a/drivers/watchdog/sp5100_tco.c
+++ b/drivers/watchdog/sp5100_tco.c
@@ -313,7 +313,7 @@ static unsigned char __devinit sp5100_tco_setupdevice(void)
tcobase_phys = val;
tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE);
- if (tcobase == 0) {
+ if (!tcobase) {
pr_err("failed to get tcobase address\n");
goto unreg_mem_region;
}
diff --git a/drivers/watchdog/via_wdt.c b/drivers/watchdog/via_wdt.c
index 465e08273c97..5603e31afdab 100644
--- a/drivers/watchdog/via_wdt.c
+++ b/drivers/watchdog/via_wdt.c
@@ -202,6 +202,9 @@ static int __devinit wdt_probe(struct pci_dev *pdev,
goto err_out_release;
}
+ if (timeout < 1 || timeout > WDT_TIMEOUT_MAX)
+ timeout = WDT_TIMEOUT;
+
wdt_dev.timeout = timeout;
watchdog_set_nowayout(&wdt_dev, nowayout);
if (readl(wdt_mem) & VIA_WDT_FIRED)
@@ -250,20 +253,7 @@ static struct pci_driver wdt_driver = {
.remove = __devexit_p(wdt_remove),
};
-static int __init wdt_init(void)
-{
- if (timeout < 1 || timeout > WDT_TIMEOUT_MAX)
- timeout = WDT_TIMEOUT;
- return pci_register_driver(&wdt_driver);
-}
-
-static void __exit wdt_exit(void)
-{
- pci_unregister_driver(&wdt_driver);
-}
-
-module_init(wdt_init);
-module_exit(wdt_exit);
+module_pci_driver(wdt_driver);
MODULE_AUTHOR("Marc Vertes");
MODULE_DESCRIPTION("Driver for watchdog timer on VIA chipset");
diff --git a/drivers/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c
index 1c888c7d4cce..e32654efdbb6 100644
--- a/drivers/watchdog/wdt_pci.c
+++ b/drivers/watchdog/wdt_pci.c
@@ -739,39 +739,7 @@ static struct pci_driver wdtpci_driver = {
.remove = __devexit_p(wdtpci_remove_one),
};
-
-/**
- * wdtpci_cleanup:
- *
- * Unload the watchdog. You cannot do this with any file handles open.
- * If your watchdog is set to continue ticking on close and you unload
- * it, well it keeps ticking. We won't get the interrupt but the board
- * will not touch PC memory so all is fine. You just have to load a new
- * module in xx seconds or reboot.
- */
-
-static void __exit wdtpci_cleanup(void)
-{
- pci_unregister_driver(&wdtpci_driver);
-}
-
-
-/**
- * wdtpci_init:
- *
- * Set up the WDT watchdog board. All we have to do is grab the
- * resources we require and bitch if anyone beat us to them.
- * The open() function will actually kick the board off.
- */
-
-static int __init wdtpci_init(void)
-{
- return pci_register_driver(&wdtpci_driver);
-}
-
-
-module_init(wdtpci_init);
-module_exit(wdtpci_cleanup);
+module_pci_driver(wdtpci_driver);
MODULE_AUTHOR("JP Nollmann, Alan Cox");
MODULE_DESCRIPTION("Driver for the ICS PCI-WDT500/501 watchdog cards");
diff --git a/drivers/watchdog/wm831x_wdt.c b/drivers/watchdog/wm831x_wdt.c
index b1815c5ed7a7..87d66d236c3e 100644
--- a/drivers/watchdog/wm831x_wdt.c
+++ b/drivers/watchdog/wm831x_wdt.c
@@ -247,8 +247,9 @@ static int __devinit wm831x_wdt_probe(struct platform_device *pdev)
reg |= pdata->software << WM831X_WDOG_RST_SRC_SHIFT;
if (pdata->update_gpio) {
- ret = gpio_request(pdata->update_gpio,
- "Watchdog update");
+ ret = gpio_request_one(pdata->update_gpio,
+ GPIOF_DIR_OUT | GPIOF_INIT_LOW,
+ "Watchdog update");
if (ret < 0) {
dev_err(wm831x->dev,
"Failed to request update GPIO: %d\n",
@@ -256,14 +257,6 @@ static int __devinit wm831x_wdt_probe(struct platform_device *pdev)
goto err;
}
- ret = gpio_direction_output(pdata->update_gpio, 0);
- if (ret != 0) {
- dev_err(wm831x->dev,
- "gpio_direction_output returned: %d\n",
- ret);
- goto err_gpio;
- }
-
driver_data->update_gpio = pdata->update_gpio;
/* Make sure the watchdog takes hardware updates */
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index ea20c51d24c7..8d2501e604dd 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -71,7 +71,7 @@ config XEN_DEV_EVTCHN
tristate "Xen /dev/xen/evtchn device"
default y
help
- The evtchn driver allows a userspace process to triger event
+ The evtchn driver allows a userspace process to trigger event
channels and to receive notification of an event channel
firing.
If in doubt, say yes.
diff --git a/fs/attr.c b/fs/attr.c
index 73f69a6ce9ed..584620e5dee5 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -47,14 +47,14 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)
/* Make sure a caller can chown. */
if ((ia_valid & ATTR_UID) &&
- (current_fsuid() != inode->i_uid ||
- attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN))
+ (!uid_eq(current_fsuid(), inode->i_uid) ||
+ !uid_eq(attr->ia_uid, inode->i_uid)) && !capable(CAP_CHOWN))
return -EPERM;
/* Make sure caller can chgrp. */
if ((ia_valid & ATTR_GID) &&
- (current_fsuid() != inode->i_uid ||
- (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) &&
+ (!uid_eq(current_fsuid(), inode->i_uid) ||
+ (!in_group_p(attr->ia_gid) && !gid_eq(attr->ia_gid, inode->i_gid))) &&
!capable(CAP_CHOWN))
return -EPERM;
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 16f735417072..e658dd134b95 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -226,10 +226,10 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
NEW_AUX_ENT(AT_BASE, interp_load_addr);
NEW_AUX_ENT(AT_FLAGS, 0);
NEW_AUX_ENT(AT_ENTRY, exec->e_entry);
- NEW_AUX_ENT(AT_UID, cred->uid);
- NEW_AUX_ENT(AT_EUID, cred->euid);
- NEW_AUX_ENT(AT_GID, cred->gid);
- NEW_AUX_ENT(AT_EGID, cred->egid);
+ NEW_AUX_ENT(AT_UID, from_kuid_munged(cred->user_ns, cred->uid));
+ NEW_AUX_ENT(AT_EUID, from_kuid_munged(cred->user_ns, cred->euid));
+ NEW_AUX_ENT(AT_GID, from_kgid_munged(cred->user_ns, cred->gid));
+ NEW_AUX_ENT(AT_EGID, from_kgid_munged(cred->user_ns, cred->egid));
NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm));
NEW_AUX_ENT(AT_RANDOM, (elf_addr_t)(unsigned long)u_rand_bytes);
NEW_AUX_ENT(AT_EXECFN, bprm->exec);
@@ -1356,8 +1356,8 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
psinfo->pr_flag = p->flags;
rcu_read_lock();
cred = __task_cred(p);
- SET_UID(psinfo->pr_uid, cred->uid);
- SET_GID(psinfo->pr_gid, cred->gid);
+ SET_UID(psinfo->pr_uid, from_kuid_munged(cred->user_ns, cred->uid));
+ SET_GID(psinfo->pr_gid, from_kgid_munged(cred->user_ns, cred->gid));
rcu_read_unlock();
strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname));
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index d390a0fffc65..3d77cf81ba3c 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -627,10 +627,10 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
NEW_AUX_ENT(AT_BASE, interp_params->elfhdr_addr);
NEW_AUX_ENT(AT_FLAGS, 0);
NEW_AUX_ENT(AT_ENTRY, exec_params->entry_addr);
- NEW_AUX_ENT(AT_UID, (elf_addr_t) cred->uid);
- NEW_AUX_ENT(AT_EUID, (elf_addr_t) cred->euid);
- NEW_AUX_ENT(AT_GID, (elf_addr_t) cred->gid);
- NEW_AUX_ENT(AT_EGID, (elf_addr_t) cred->egid);
+ NEW_AUX_ENT(AT_UID, (elf_addr_t) from_kuid_munged(cred->user_ns, cred->uid));
+ NEW_AUX_ENT(AT_EUID, (elf_addr_t) from_kuid_munged(cred->user_ns, cred->euid));
+ NEW_AUX_ENT(AT_GID, (elf_addr_t) from_kgid_munged(cred->user_ns, cred->gid));
+ NEW_AUX_ENT(AT_EGID, (elf_addr_t) from_kgid_munged(cred->user_ns, cred->egid));
NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm));
NEW_AUX_ENT(AT_EXECFN, bprm->exec);
@@ -1421,8 +1421,8 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
psinfo->pr_flag = p->flags;
rcu_read_lock();
cred = __task_cred(p);
- SET_UID(psinfo->pr_uid, cred->uid);
- SET_GID(psinfo->pr_gid, cred->gid);
+ SET_UID(psinfo->pr_uid, from_kuid_munged(cred->user_ns, cred->uid));
+ SET_GID(psinfo->pr_gid, from_kgid_munged(cred->user_ns, cred->gid));
rcu_read_unlock();
strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname));
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index a7ffc88a7dbe..e1fe74a2ce16 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2753,7 +2753,7 @@ static int write_dev_flush(struct btrfs_device *device, int wait)
* one reference for us, and we leave it for the
* caller
*/
- device->flush_bio = NULL;;
+ device->flush_bio = NULL;
bio = bio_alloc(GFP_NOFS, 0);
if (!bio)
return -ENOMEM;
diff --git a/fs/compat.c b/fs/compat.c
index f2944ace7a7b..0781e619a62a 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -144,8 +144,8 @@ static int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
tmp.st_nlink = stat->nlink;
if (tmp.st_nlink != stat->nlink)
return -EOVERFLOW;
- SET_UID(tmp.st_uid, stat->uid);
- SET_GID(tmp.st_gid, stat->gid);
+ SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid));
+ SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid));
tmp.st_rdev = old_encode_dev(stat->rdev);
if ((u64) stat->size > MAX_NON_LFS)
return -EOVERFLOW;
diff --git a/fs/dcache.c b/fs/dcache.c
index 8c1ab8fb5012..4435d8b32904 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -3093,6 +3093,7 @@ static void __init dcache_init_early(void)
HASH_EARLY,
&d_hash_shift,
&d_hash_mask,
+ 0,
0);
for (loop = 0; loop < (1U << d_hash_shift); loop++)
@@ -3123,6 +3124,7 @@ static void __init dcache_init(void)
0,
&d_hash_shift,
&d_hash_mask,
+ 0,
0);
for (loop = 0; loop < (1U << d_hash_shift); loop++)
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index 10f5e0b484db..979c1e309c73 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -98,8 +98,8 @@ static struct vfsmount *devpts_mnt;
struct pts_mount_opts {
int setuid;
int setgid;
- uid_t uid;
- gid_t gid;
+ kuid_t uid;
+ kgid_t gid;
umode_t mode;
umode_t ptmxmode;
int newinstance;
@@ -158,11 +158,13 @@ static inline struct super_block *pts_sb_from_inode(struct inode *inode)
static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts)
{
char *p;
+ kuid_t uid;
+ kgid_t gid;
opts->setuid = 0;
opts->setgid = 0;
- opts->uid = 0;
- opts->gid = 0;
+ opts->uid = GLOBAL_ROOT_UID;
+ opts->gid = GLOBAL_ROOT_GID;
opts->mode = DEVPTS_DEFAULT_MODE;
opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
opts->max = NR_UNIX98_PTY_MAX;
@@ -184,13 +186,19 @@ static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts)
case Opt_uid:
if (match_int(&args[0], &option))
return -EINVAL;
- opts->uid = option;
+ uid = make_kuid(current_user_ns(), option);
+ if (!uid_valid(uid))
+ return -EINVAL;
+ opts->uid = uid;
opts->setuid = 1;
break;
case Opt_gid:
if (match_int(&args[0], &option))
return -EINVAL;
- opts->gid = option;
+ gid = make_kgid(current_user_ns(), option);
+ if (!gid_valid(gid))
+ return -EINVAL;
+ opts->gid = gid;
opts->setgid = 1;
break;
case Opt_mode:
@@ -315,9 +323,9 @@ static int devpts_show_options(struct seq_file *seq, struct dentry *root)
struct pts_mount_opts *opts = &fsi->mount_opts;
if (opts->setuid)
- seq_printf(seq, ",uid=%u", opts->uid);
+ seq_printf(seq, ",uid=%u", from_kuid_munged(&init_user_ns, opts->uid));
if (opts->setgid)
- seq_printf(seq, ",gid=%u", opts->gid);
+ seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, opts->gid));
seq_printf(seq, ",mode=%03o", opts->mode);
#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode);
diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c
index 90e5997262ea..63dc19c54d5a 100644
--- a/fs/dlm/ast.c
+++ b/fs/dlm/ast.c
@@ -310,6 +310,7 @@ void dlm_callback_resume(struct dlm_ls *ls)
}
mutex_unlock(&ls->ls_cb_mutex);
- log_debug(ls, "dlm_callback_resume %d", count);
+ if (count)
+ log_debug(ls, "dlm_callback_resume %d", count);
}
diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h
index 3a564d197e99..bc342f7ac3af 100644
--- a/fs/dlm/dlm_internal.h
+++ b/fs/dlm/dlm_internal.h
@@ -38,6 +38,7 @@
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/idr.h>
+#include <linux/ratelimit.h>
#include <asm/uaccess.h>
#include <linux/dlm.h>
@@ -74,6 +75,13 @@ do { \
(ls)->ls_name , ##args); \
} while (0)
+#define log_limit(ls, fmt, args...) \
+do { \
+ if (dlm_config.ci_log_debug) \
+ printk_ratelimited(KERN_DEBUG "dlm: %s: " fmt "\n", \
+ (ls)->ls_name , ##args); \
+} while (0)
+
#define DLM_ASSERT(x, do) \
{ \
if (!(x)) \
@@ -263,6 +271,8 @@ struct dlm_lkb {
ktime_t lkb_last_cast_time; /* for debugging */
ktime_t lkb_last_bast_time; /* for debugging */
+ uint64_t lkb_recover_seq; /* from ls_recover_seq */
+
char *lkb_lvbptr;
struct dlm_lksb *lkb_lksb; /* caller's status block */
void (*lkb_astfn) (void *astparam);
@@ -317,7 +327,7 @@ enum rsb_flags {
RSB_NEW_MASTER,
RSB_NEW_MASTER2,
RSB_RECOVER_CONVERT,
- RSB_LOCKS_PURGED,
+ RSB_RECOVER_GRANT,
};
static inline void rsb_set_flag(struct dlm_rsb *r, enum rsb_flags flag)
@@ -563,6 +573,7 @@ struct dlm_ls {
struct mutex ls_requestqueue_mutex;
struct dlm_rcom *ls_recover_buf;
int ls_recover_nodeid; /* for debugging */
+ unsigned int ls_recover_locks_in; /* for log info */
uint64_t ls_rcom_seq;
spinlock_t ls_rcom_spin;
struct list_head ls_recover_list;
@@ -589,6 +600,7 @@ struct dlm_ls {
#define LSFL_UEVENT_WAIT 5
#define LSFL_TIMEWARN 6
#define LSFL_CB_DELAY 7
+#define LSFL_NODIR 8
/* much of this is just saving user space pointers associated with the
lock that we pass back to the user lib with an ast */
@@ -636,7 +648,7 @@ static inline int dlm_recovery_stopped(struct dlm_ls *ls)
static inline int dlm_no_directory(struct dlm_ls *ls)
{
- return (ls->ls_exflags & DLM_LSFL_NODIR) ? 1 : 0;
+ return test_bit(LSFL_NODIR, &ls->ls_flags);
}
int dlm_netlink_init(void);
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c
index 4c58d4a3adc4..bdafb65a5234 100644
--- a/fs/dlm/lock.c
+++ b/fs/dlm/lock.c
@@ -160,11 +160,12 @@ static const int __quecvt_compat_matrix[8][8] = {
void dlm_print_lkb(struct dlm_lkb *lkb)
{
- printk(KERN_ERR "lkb: nodeid %d id %x remid %x exflags %x flags %x\n"
- " status %d rqmode %d grmode %d wait_type %d\n",
+ printk(KERN_ERR "lkb: nodeid %d id %x remid %x exflags %x flags %x "
+ "sts %d rq %d gr %d wait_type %d wait_nodeid %d seq %llu\n",
lkb->lkb_nodeid, lkb->lkb_id, lkb->lkb_remid, lkb->lkb_exflags,
lkb->lkb_flags, lkb->lkb_status, lkb->lkb_rqmode,
- lkb->lkb_grmode, lkb->lkb_wait_type);
+ lkb->lkb_grmode, lkb->lkb_wait_type, lkb->lkb_wait_nodeid,
+ (unsigned long long)lkb->lkb_recover_seq);
}
static void dlm_print_rsb(struct dlm_rsb *r)
@@ -251,8 +252,6 @@ static inline int is_process_copy(struct dlm_lkb *lkb)
static inline int is_master_copy(struct dlm_lkb *lkb)
{
- if (lkb->lkb_flags & DLM_IFL_MSTCPY)
- DLM_ASSERT(lkb->lkb_nodeid, dlm_print_lkb(lkb););
return (lkb->lkb_flags & DLM_IFL_MSTCPY) ? 1 : 0;
}
@@ -479,6 +478,9 @@ static int _search_rsb(struct dlm_ls *ls, char *name, int len, int b,
kref_get(&r->res_ref);
goto out;
}
+ if (error == -ENOTBLK)
+ goto out;
+
error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, flags, &r);
if (error)
goto out;
@@ -586,6 +588,23 @@ static int find_rsb(struct dlm_ls *ls, char *name, int namelen,
return error;
}
+static void dlm_dump_rsb_hash(struct dlm_ls *ls, uint32_t hash)
+{
+ struct rb_node *n;
+ struct dlm_rsb *r;
+ int i;
+
+ for (i = 0; i < ls->ls_rsbtbl_size; i++) {
+ spin_lock(&ls->ls_rsbtbl[i].lock);
+ for (n = rb_first(&ls->ls_rsbtbl[i].keep); n; n = rb_next(n)) {
+ r = rb_entry(n, struct dlm_rsb, res_hashnode);
+ if (r->res_hash == hash)
+ dlm_dump_rsb(r);
+ }
+ spin_unlock(&ls->ls_rsbtbl[i].lock);
+ }
+}
+
/* This is only called to add a reference when the code already holds
a valid reference to the rsb, so there's no need for locking. */
@@ -1064,8 +1083,9 @@ static int _remove_from_waiters(struct dlm_lkb *lkb, int mstype,
goto out_del;
}
- log_error(ls, "remwait error %x reply %d flags %x no wait_type",
- lkb->lkb_id, mstype, lkb->lkb_flags);
+ log_error(ls, "remwait error %x remote %d %x msg %d flags %x no wait",
+ lkb->lkb_id, ms ? ms->m_header.h_nodeid : 0, lkb->lkb_remid,
+ mstype, lkb->lkb_flags);
return -1;
out_del:
@@ -1498,13 +1518,13 @@ static void _grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
}
lkb->lkb_rqmode = DLM_LOCK_IV;
+ lkb->lkb_highbast = 0;
}
static void grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
{
set_lvb_lock(r, lkb);
_grant_lock(r, lkb);
- lkb->lkb_highbast = 0;
}
static void grant_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb,
@@ -1866,7 +1886,8 @@ static int can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now,
/* Returns the highest requested mode of all blocked conversions; sets
cw if there's a blocked conversion to DLM_LOCK_CW. */
-static int grant_pending_convert(struct dlm_rsb *r, int high, int *cw)
+static int grant_pending_convert(struct dlm_rsb *r, int high, int *cw,
+ unsigned int *count)
{
struct dlm_lkb *lkb, *s;
int hi, demoted, quit, grant_restart, demote_restart;
@@ -1885,6 +1906,8 @@ static int grant_pending_convert(struct dlm_rsb *r, int high, int *cw)
if (can_be_granted(r, lkb, 0, &deadlk)) {
grant_lock_pending(r, lkb);
grant_restart = 1;
+ if (count)
+ (*count)++;
continue;
}
@@ -1918,14 +1941,17 @@ static int grant_pending_convert(struct dlm_rsb *r, int high, int *cw)
return max_t(int, high, hi);
}
-static int grant_pending_wait(struct dlm_rsb *r, int high, int *cw)
+static int grant_pending_wait(struct dlm_rsb *r, int high, int *cw,
+ unsigned int *count)
{
struct dlm_lkb *lkb, *s;
list_for_each_entry_safe(lkb, s, &r->res_waitqueue, lkb_statequeue) {
- if (can_be_granted(r, lkb, 0, NULL))
+ if (can_be_granted(r, lkb, 0, NULL)) {
grant_lock_pending(r, lkb);
- else {
+ if (count)
+ (*count)++;
+ } else {
high = max_t(int, lkb->lkb_rqmode, high);
if (lkb->lkb_rqmode == DLM_LOCK_CW)
*cw = 1;
@@ -1954,16 +1980,20 @@ static int lock_requires_bast(struct dlm_lkb *gr, int high, int cw)
return 0;
}
-static void grant_pending_locks(struct dlm_rsb *r)
+static void grant_pending_locks(struct dlm_rsb *r, unsigned int *count)
{
struct dlm_lkb *lkb, *s;
int high = DLM_LOCK_IV;
int cw = 0;
- DLM_ASSERT(is_master(r), dlm_dump_rsb(r););
+ if (!is_master(r)) {
+ log_print("grant_pending_locks r nodeid %d", r->res_nodeid);
+ dlm_dump_rsb(r);
+ return;
+ }
- high = grant_pending_convert(r, high, &cw);
- high = grant_pending_wait(r, high, &cw);
+ high = grant_pending_convert(r, high, &cw, count);
+ high = grant_pending_wait(r, high, &cw, count);
if (high == DLM_LOCK_IV)
return;
@@ -2499,7 +2529,7 @@ static int do_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
before we try again to grant this one. */
if (is_demoted(lkb)) {
- grant_pending_convert(r, DLM_LOCK_IV, NULL);
+ grant_pending_convert(r, DLM_LOCK_IV, NULL, NULL);
if (_can_be_granted(r, lkb, 1)) {
grant_lock(r, lkb);
queue_cast(r, lkb, 0);
@@ -2527,7 +2557,7 @@ static void do_convert_effects(struct dlm_rsb *r, struct dlm_lkb *lkb,
{
switch (error) {
case 0:
- grant_pending_locks(r);
+ grant_pending_locks(r, NULL);
/* grant_pending_locks also sends basts */
break;
case -EAGAIN:
@@ -2550,7 +2580,7 @@ static int do_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb)
static void do_unlock_effects(struct dlm_rsb *r, struct dlm_lkb *lkb,
int error)
{
- grant_pending_locks(r);
+ grant_pending_locks(r, NULL);
}
/* returns: 0 did nothing, -DLM_ECANCEL canceled lock */
@@ -2571,7 +2601,7 @@ static void do_cancel_effects(struct dlm_rsb *r, struct dlm_lkb *lkb,
int error)
{
if (error)
- grant_pending_locks(r);
+ grant_pending_locks(r, NULL);
}
/*
@@ -3372,7 +3402,7 @@ static int validate_message(struct dlm_lkb *lkb, struct dlm_message *ms)
return error;
}
-static void receive_request(struct dlm_ls *ls, struct dlm_message *ms)
+static int receive_request(struct dlm_ls *ls, struct dlm_message *ms)
{
struct dlm_lkb *lkb;
struct dlm_rsb *r;
@@ -3412,14 +3442,15 @@ static void receive_request(struct dlm_ls *ls, struct dlm_message *ms)
error = 0;
if (error)
dlm_put_lkb(lkb);
- return;
+ return 0;
fail:
setup_stub_lkb(ls, ms);
send_request_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
+ return error;
}
-static void receive_convert(struct dlm_ls *ls, struct dlm_message *ms)
+static int receive_convert(struct dlm_ls *ls, struct dlm_message *ms)
{
struct dlm_lkb *lkb;
struct dlm_rsb *r;
@@ -3429,6 +3460,15 @@ static void receive_convert(struct dlm_ls *ls, struct dlm_message *ms)
if (error)
goto fail;
+ if (lkb->lkb_remid != ms->m_lkid) {
+ log_error(ls, "receive_convert %x remid %x recover_seq %llu "
+ "remote %d %x", lkb->lkb_id, lkb->lkb_remid,
+ (unsigned long long)lkb->lkb_recover_seq,
+ ms->m_header.h_nodeid, ms->m_lkid);
+ error = -ENOENT;
+ goto fail;
+ }
+
r = lkb->lkb_resource;
hold_rsb(r);
@@ -3456,14 +3496,15 @@ static void receive_convert(struct dlm_ls *ls, struct dlm_message *ms)
unlock_rsb(r);
put_rsb(r);
dlm_put_lkb(lkb);
- return;
+ return 0;
fail:
setup_stub_lkb(ls, ms);
send_convert_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
+ return error;
}
-static void receive_unlock(struct dlm_ls *ls, struct dlm_message *ms)
+static int receive_unlock(struct dlm_ls *ls, struct dlm_message *ms)
{
struct dlm_lkb *lkb;
struct dlm_rsb *r;
@@ -3473,6 +3514,14 @@ static void receive_unlock(struct dlm_ls *ls, struct dlm_message *ms)
if (error)
goto fail;
+ if (lkb->lkb_remid != ms->m_lkid) {
+ log_error(ls, "receive_unlock %x remid %x remote %d %x",
+ lkb->lkb_id, lkb->lkb_remid,
+ ms->m_header.h_nodeid, ms->m_lkid);
+ error = -ENOENT;
+ goto fail;
+ }
+
r = lkb->lkb_resource;
hold_rsb(r);
@@ -3497,14 +3546,15 @@ static void receive_unlock(struct dlm_ls *ls, struct dlm_message *ms)
unlock_rsb(r);
put_rsb(r);
dlm_put_lkb(lkb);
- return;
+ return 0;
fail:
setup_stub_lkb(ls, ms);
send_unlock_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
+ return error;
}
-static void receive_cancel(struct dlm_ls *ls, struct dlm_message *ms)
+static int receive_cancel(struct dlm_ls *ls, struct dlm_message *ms)
{
struct dlm_lkb *lkb;
struct dlm_rsb *r;
@@ -3532,25 +3582,23 @@ static void receive_cancel(struct dlm_ls *ls, struct dlm_message *ms)
unlock_rsb(r);
put_rsb(r);
dlm_put_lkb(lkb);
- return;
+ return 0;
fail:
setup_stub_lkb(ls, ms);
send_cancel_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
+ return error;
}
-static void receive_grant(struct dlm_ls *ls, struct dlm_message *ms)
+static int receive_grant(struct dlm_ls *ls, struct dlm_message *ms)
{
struct dlm_lkb *lkb;
struct dlm_rsb *r;
int error;
error = find_lkb(ls, ms->m_remid, &lkb);
- if (error) {
- log_debug(ls, "receive_grant from %d no lkb %x",
- ms->m_header.h_nodeid, ms->m_remid);
- return;
- }
+ if (error)
+ return error;
r = lkb->lkb_resource;
@@ -3570,20 +3618,18 @@ static void receive_grant(struct dlm_ls *ls, struct dlm_message *ms)
unlock_rsb(r);
put_rsb(r);
dlm_put_lkb(lkb);
+ return 0;
}
-static void receive_bast(struct dlm_ls *ls, struct dlm_message *ms)
+static int receive_bast(struct dlm_ls *ls, struct dlm_message *ms)
{
struct dlm_lkb *lkb;
struct dlm_rsb *r;
int error;
error = find_lkb(ls, ms->m_remid, &lkb);
- if (error) {
- log_debug(ls, "receive_bast from %d no lkb %x",
- ms->m_header.h_nodeid, ms->m_remid);
- return;
- }
+ if (error)
+ return error;
r = lkb->lkb_resource;
@@ -3595,10 +3641,12 @@ static void receive_bast(struct dlm_ls *ls, struct dlm_message *ms)
goto out;
queue_bast(r, lkb, ms->m_bastmode);
+ lkb->lkb_highbast = ms->m_bastmode;
out:
unlock_rsb(r);
put_rsb(r);
dlm_put_lkb(lkb);
+ return 0;
}
static void receive_lookup(struct dlm_ls *ls, struct dlm_message *ms)
@@ -3653,18 +3701,15 @@ static void receive_purge(struct dlm_ls *ls, struct dlm_message *ms)
do_purge(ls, ms->m_nodeid, ms->m_pid);
}
-static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)
+static int receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)
{
struct dlm_lkb *lkb;
struct dlm_rsb *r;
int error, mstype, result;
error = find_lkb(ls, ms->m_remid, &lkb);
- if (error) {
- log_debug(ls, "receive_request_reply from %d no lkb %x",
- ms->m_header.h_nodeid, ms->m_remid);
- return;
- }
+ if (error)
+ return error;
r = lkb->lkb_resource;
hold_rsb(r);
@@ -3676,8 +3721,13 @@ static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)
mstype = lkb->lkb_wait_type;
error = remove_from_waiters(lkb, DLM_MSG_REQUEST_REPLY);
- if (error)
+ if (error) {
+ log_error(ls, "receive_request_reply %x remote %d %x result %d",
+ lkb->lkb_id, ms->m_header.h_nodeid, ms->m_lkid,
+ ms->m_result);
+ dlm_dump_rsb(r);
goto out;
+ }
/* Optimization: the dir node was also the master, so it took our
lookup as a request and sent request reply instead of lookup reply */
@@ -3755,6 +3805,7 @@ static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)
unlock_rsb(r);
put_rsb(r);
dlm_put_lkb(lkb);
+ return 0;
}
static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
@@ -3793,8 +3844,11 @@ static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
break;
default:
- log_error(r->res_ls, "receive_convert_reply %x error %d",
- lkb->lkb_id, ms->m_result);
+ log_error(r->res_ls, "receive_convert_reply %x remote %d %x %d",
+ lkb->lkb_id, ms->m_header.h_nodeid, ms->m_lkid,
+ ms->m_result);
+ dlm_print_rsb(r);
+ dlm_print_lkb(lkb);
}
}
@@ -3821,20 +3875,18 @@ static void _receive_convert_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
put_rsb(r);
}
-static void receive_convert_reply(struct dlm_ls *ls, struct dlm_message *ms)
+static int receive_convert_reply(struct dlm_ls *ls, struct dlm_message *ms)
{
struct dlm_lkb *lkb;
int error;
error = find_lkb(ls, ms->m_remid, &lkb);
- if (error) {
- log_debug(ls, "receive_convert_reply from %d no lkb %x",
- ms->m_header.h_nodeid, ms->m_remid);
- return;
- }
+ if (error)
+ return error;
_receive_convert_reply(lkb, ms);
dlm_put_lkb(lkb);
+ return 0;
}
static void _receive_unlock_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
@@ -3873,20 +3925,18 @@ static void _receive_unlock_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
put_rsb(r);
}
-static void receive_unlock_reply(struct dlm_ls *ls, struct dlm_message *ms)
+static int receive_unlock_reply(struct dlm_ls *ls, struct dlm_message *ms)
{
struct dlm_lkb *lkb;
int error;
error = find_lkb(ls, ms->m_remid, &lkb);
- if (error) {
- log_debug(ls, "receive_unlock_reply from %d no lkb %x",
- ms->m_header.h_nodeid, ms->m_remid);
- return;
- }
+ if (error)
+ return error;
_receive_unlock_reply(lkb, ms);
dlm_put_lkb(lkb);
+ return 0;
}
static void _receive_cancel_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
@@ -3925,20 +3975,18 @@ static void _receive_cancel_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
put_rsb(r);
}
-static void receive_cancel_reply(struct dlm_ls *ls, struct dlm_message *ms)
+static int receive_cancel_reply(struct dlm_ls *ls, struct dlm_message *ms)
{
struct dlm_lkb *lkb;
int error;
error = find_lkb(ls, ms->m_remid, &lkb);
- if (error) {
- log_debug(ls, "receive_cancel_reply from %d no lkb %x",
- ms->m_header.h_nodeid, ms->m_remid);
- return;
- }
+ if (error)
+ return error;
_receive_cancel_reply(lkb, ms);
dlm_put_lkb(lkb);
+ return 0;
}
static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms)
@@ -3949,7 +3997,7 @@ static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms)
error = find_lkb(ls, ms->m_lkid, &lkb);
if (error) {
- log_error(ls, "receive_lookup_reply no lkb");
+ log_error(ls, "receive_lookup_reply no lkid %x", ms->m_lkid);
return;
}
@@ -3993,8 +4041,11 @@ static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms)
dlm_put_lkb(lkb);
}
-static void _receive_message(struct dlm_ls *ls, struct dlm_message *ms)
+static void _receive_message(struct dlm_ls *ls, struct dlm_message *ms,
+ uint32_t saved_seq)
{
+ int error = 0, noent = 0;
+
if (!dlm_is_member(ls, ms->m_header.h_nodeid)) {
log_debug(ls, "ignore non-member message %d from %d %x %x %d",
ms->m_type, ms->m_header.h_nodeid, ms->m_lkid,
@@ -4007,47 +4058,50 @@ static void _receive_message(struct dlm_ls *ls, struct dlm_message *ms)
/* messages sent to a master node */
case DLM_MSG_REQUEST:
- receive_request(ls, ms);
+ error = receive_request(ls, ms);
break;
case DLM_MSG_CONVERT:
- receive_convert(ls, ms);
+ error = receive_convert(ls, ms);
break;
case DLM_MSG_UNLOCK:
- receive_unlock(ls, ms);
+ error = receive_unlock(ls, ms);
break;
case DLM_MSG_CANCEL:
- receive_cancel(ls, ms);
+ noent = 1;
+ error = receive_cancel(ls, ms);
break;
/* messages sent from a master node (replies to above) */
case DLM_MSG_REQUEST_REPLY:
- receive_request_reply(ls, ms);
+ error = receive_request_reply(ls, ms);
break;
case DLM_MSG_CONVERT_REPLY:
- receive_convert_reply(ls, ms);
+ error = receive_convert_reply(ls, ms);
break;
case DLM_MSG_UNLOCK_REPLY:
- receive_unlock_reply(ls, ms);
+ error = receive_unlock_reply(ls, ms);
break;
case DLM_MSG_CANCEL_REPLY:
- receive_cancel_reply(ls, ms);
+ error = receive_cancel_reply(ls, ms);
break;
/* messages sent from a master node (only two types of async msg) */
case DLM_MSG_GRANT:
- receive_grant(ls, ms);
+ noent = 1;
+ error = receive_grant(ls, ms);
break;
case DLM_MSG_BAST:
- receive_bast(ls, ms);
+ noent = 1;
+ error = receive_bast(ls, ms);
break;
/* messages sent to a dir node */
@@ -4075,6 +4129,37 @@ static void _receive_message(struct dlm_ls *ls, struct dlm_message *ms)
default:
log_error(ls, "unknown message type %d", ms->m_type);
}
+
+ /*
+ * When checking for ENOENT, we're checking the result of
+ * find_lkb(m_remid):
+ *
+ * The lock id referenced in the message wasn't found. This may
+ * happen in normal usage for the async messages and cancel, so
+ * only use log_debug for them.
+ *
+ * Some errors are expected and normal.
+ */
+
+ if (error == -ENOENT && noent) {
+ log_debug(ls, "receive %d no %x remote %d %x saved_seq %u",
+ ms->m_type, ms->m_remid, ms->m_header.h_nodeid,
+ ms->m_lkid, saved_seq);
+ } else if (error == -ENOENT) {
+ log_error(ls, "receive %d no %x remote %d %x saved_seq %u",
+ ms->m_type, ms->m_remid, ms->m_header.h_nodeid,
+ ms->m_lkid, saved_seq);
+
+ if (ms->m_type == DLM_MSG_CONVERT)
+ dlm_dump_rsb_hash(ls, ms->m_hash);
+ }
+
+ if (error == -EINVAL) {
+ log_error(ls, "receive %d inval from %d lkid %x remid %x "
+ "saved_seq %u",
+ ms->m_type, ms->m_header.h_nodeid,
+ ms->m_lkid, ms->m_remid, saved_seq);
+ }
}
/* If the lockspace is in recovery mode (locking stopped), then normal
@@ -4092,16 +4177,17 @@ static void dlm_receive_message(struct dlm_ls *ls, struct dlm_message *ms,
dlm_add_requestqueue(ls, nodeid, ms);
} else {
dlm_wait_requestqueue(ls);
- _receive_message(ls, ms);
+ _receive_message(ls, ms, 0);
}
}
/* This is called by dlm_recoverd to process messages that were saved on
the requestqueue. */
-void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms)
+void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms,
+ uint32_t saved_seq)
{
- _receive_message(ls, ms);
+ _receive_message(ls, ms, saved_seq);
}
/* This is called by the midcomms layer when something is received for
@@ -4137,9 +4223,11 @@ void dlm_receive_buffer(union dlm_packet *p, int nodeid)
ls = dlm_find_lockspace_global(hd->h_lockspace);
if (!ls) {
- if (dlm_config.ci_log_debug)
- log_print("invalid lockspace %x from %d cmd %d type %d",
- hd->h_lockspace, nodeid, hd->h_cmd, type);
+ if (dlm_config.ci_log_debug) {
+ printk_ratelimited(KERN_DEBUG "dlm: invalid lockspace "
+ "%u from %d cmd %d type %d\n",
+ hd->h_lockspace, nodeid, hd->h_cmd, type);
+ }
if (hd->h_cmd == DLM_RCOM && type == DLM_RCOM_STATUS)
dlm_send_ls_not_ready(nodeid, &p->rcom);
@@ -4187,15 +4275,13 @@ static void recover_convert_waiter(struct dlm_ls *ls, struct dlm_lkb *lkb,
/* A waiting lkb needs recovery if the master node has failed, or
the master node is changing (only when no directory is used) */
-static int waiter_needs_recovery(struct dlm_ls *ls, struct dlm_lkb *lkb)
+static int waiter_needs_recovery(struct dlm_ls *ls, struct dlm_lkb *lkb,
+ int dir_nodeid)
{
- if (dlm_is_removed(ls, lkb->lkb_nodeid))
+ if (dlm_no_directory(ls))
return 1;
- if (!dlm_no_directory(ls))
- return 0;
-
- if (dlm_dir_nodeid(lkb->lkb_resource) != lkb->lkb_nodeid)
+ if (dlm_is_removed(ls, lkb->lkb_wait_nodeid))
return 1;
return 0;
@@ -4212,6 +4298,7 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls)
struct dlm_lkb *lkb, *safe;
struct dlm_message *ms_stub;
int wait_type, stub_unlock_result, stub_cancel_result;
+ int dir_nodeid;
ms_stub = kmalloc(sizeof(struct dlm_message), GFP_KERNEL);
if (!ms_stub) {
@@ -4223,13 +4310,21 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls)
list_for_each_entry_safe(lkb, safe, &ls->ls_waiters, lkb_wait_reply) {
+ dir_nodeid = dlm_dir_nodeid(lkb->lkb_resource);
+
/* exclude debug messages about unlocks because there can be so
many and they aren't very interesting */
if (lkb->lkb_wait_type != DLM_MSG_UNLOCK) {
- log_debug(ls, "recover_waiter %x nodeid %d "
- "msg %d to %d", lkb->lkb_id, lkb->lkb_nodeid,
- lkb->lkb_wait_type, lkb->lkb_wait_nodeid);
+ log_debug(ls, "waiter %x remote %x msg %d r_nodeid %d "
+ "lkb_nodeid %d wait_nodeid %d dir_nodeid %d",
+ lkb->lkb_id,
+ lkb->lkb_remid,
+ lkb->lkb_wait_type,
+ lkb->lkb_resource->res_nodeid,
+ lkb->lkb_nodeid,
+ lkb->lkb_wait_nodeid,
+ dir_nodeid);
}
/* all outstanding lookups, regardless of destination will be
@@ -4240,7 +4335,7 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls)
continue;
}
- if (!waiter_needs_recovery(ls, lkb))
+ if (!waiter_needs_recovery(ls, lkb, dir_nodeid))
continue;
wait_type = lkb->lkb_wait_type;
@@ -4373,8 +4468,11 @@ int dlm_recover_waiters_post(struct dlm_ls *ls)
ou = is_overlap_unlock(lkb);
err = 0;
- log_debug(ls, "recover_waiter %x nodeid %d msg %d r_nodeid %d",
- lkb->lkb_id, lkb->lkb_nodeid, mstype, r->res_nodeid);
+ log_debug(ls, "waiter %x remote %x msg %d r_nodeid %d "
+ "lkb_nodeid %d wait_nodeid %d dir_nodeid %d "
+ "overlap %d %d", lkb->lkb_id, lkb->lkb_remid, mstype,
+ r->res_nodeid, lkb->lkb_nodeid, lkb->lkb_wait_nodeid,
+ dlm_dir_nodeid(r), oc, ou);
/* At this point we assume that we won't get a reply to any
previous op or overlap op on this lock. First, do a big
@@ -4426,9 +4524,12 @@ int dlm_recover_waiters_post(struct dlm_ls *ls)
}
}
- if (err)
- log_error(ls, "recover_waiters_post %x %d %x %d %d",
- lkb->lkb_id, mstype, lkb->lkb_flags, oc, ou);
+ if (err) {
+ log_error(ls, "waiter %x msg %d r_nodeid %d "
+ "dir_nodeid %d overlap %d %d",
+ lkb->lkb_id, mstype, r->res_nodeid,
+ dlm_dir_nodeid(r), oc, ou);
+ }
unlock_rsb(r);
put_rsb(r);
dlm_put_lkb(lkb);
@@ -4437,112 +4538,177 @@ int dlm_recover_waiters_post(struct dlm_ls *ls)
return error;
}
-static void purge_queue(struct dlm_rsb *r, struct list_head *queue,
- int (*test)(struct dlm_ls *ls, struct dlm_lkb *lkb))
+static void purge_mstcpy_list(struct dlm_ls *ls, struct dlm_rsb *r,
+ struct list_head *list)
{
- struct dlm_ls *ls = r->res_ls;
struct dlm_lkb *lkb, *safe;
- list_for_each_entry_safe(lkb, safe, queue, lkb_statequeue) {
- if (test(ls, lkb)) {
- rsb_set_flag(r, RSB_LOCKS_PURGED);
- del_lkb(r, lkb);
- /* this put should free the lkb */
- if (!dlm_put_lkb(lkb))
- log_error(ls, "purged lkb not released");
- }
+ list_for_each_entry_safe(lkb, safe, list, lkb_statequeue) {
+ if (!is_master_copy(lkb))
+ continue;
+
+ /* don't purge lkbs we've added in recover_master_copy for
+ the current recovery seq */
+
+ if (lkb->lkb_recover_seq == ls->ls_recover_seq)
+ continue;
+
+ del_lkb(r, lkb);
+
+ /* this put should free the lkb */
+ if (!dlm_put_lkb(lkb))
+ log_error(ls, "purged mstcpy lkb not released");
}
}
-static int purge_dead_test(struct dlm_ls *ls, struct dlm_lkb *lkb)
+void dlm_purge_mstcpy_locks(struct dlm_rsb *r)
{
- return (is_master_copy(lkb) && dlm_is_removed(ls, lkb->lkb_nodeid));
-}
+ struct dlm_ls *ls = r->res_ls;
-static int purge_mstcpy_test(struct dlm_ls *ls, struct dlm_lkb *lkb)
-{
- return is_master_copy(lkb);
+ purge_mstcpy_list(ls, r, &r->res_grantqueue);
+ purge_mstcpy_list(ls, r, &r->res_convertqueue);
+ purge_mstcpy_list(ls, r, &r->res_waitqueue);
}
-static void purge_dead_locks(struct dlm_rsb *r)
+static void purge_dead_list(struct dlm_ls *ls, struct dlm_rsb *r,
+ struct list_head *list,
+ int nodeid_gone, unsigned int *count)
{
- purge_queue(r, &r->res_grantqueue, &purge_dead_test);
- purge_queue(r, &r->res_convertqueue, &purge_dead_test);
- purge_queue(r, &r->res_waitqueue, &purge_dead_test);
-}
+ struct dlm_lkb *lkb, *safe;
-void dlm_purge_mstcpy_locks(struct dlm_rsb *r)
-{
- purge_queue(r, &r->res_grantqueue, &purge_mstcpy_test);
- purge_queue(r, &r->res_convertqueue, &purge_mstcpy_test);
- purge_queue(r, &r->res_waitqueue, &purge_mstcpy_test);
+ list_for_each_entry_safe(lkb, safe, list, lkb_statequeue) {
+ if (!is_master_copy(lkb))
+ continue;
+
+ if ((lkb->lkb_nodeid == nodeid_gone) ||
+ dlm_is_removed(ls, lkb->lkb_nodeid)) {
+
+ del_lkb(r, lkb);
+
+ /* this put should free the lkb */
+ if (!dlm_put_lkb(lkb))
+ log_error(ls, "purged dead lkb not released");
+
+ rsb_set_flag(r, RSB_RECOVER_GRANT);
+
+ (*count)++;
+ }
+ }
}
/* Get rid of locks held by nodes that are gone. */
-int dlm_purge_locks(struct dlm_ls *ls)
+void dlm_recover_purge(struct dlm_ls *ls)
{
struct dlm_rsb *r;
+ struct dlm_member *memb;
+ int nodes_count = 0;
+ int nodeid_gone = 0;
+ unsigned int lkb_count = 0;
- log_debug(ls, "dlm_purge_locks");
+ /* cache one removed nodeid to optimize the common
+ case of a single node removed */
+
+ list_for_each_entry(memb, &ls->ls_nodes_gone, list) {
+ nodes_count++;
+ nodeid_gone = memb->nodeid;
+ }
+
+ if (!nodes_count)
+ return;
down_write(&ls->ls_root_sem);
list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
hold_rsb(r);
lock_rsb(r);
- if (is_master(r))
- purge_dead_locks(r);
+ if (is_master(r)) {
+ purge_dead_list(ls, r, &r->res_grantqueue,
+ nodeid_gone, &lkb_count);
+ purge_dead_list(ls, r, &r->res_convertqueue,
+ nodeid_gone, &lkb_count);
+ purge_dead_list(ls, r, &r->res_waitqueue,
+ nodeid_gone, &lkb_count);
+ }
unlock_rsb(r);
unhold_rsb(r);
-
- schedule();
+ cond_resched();
}
up_write(&ls->ls_root_sem);
- return 0;
+ if (lkb_count)
+ log_debug(ls, "dlm_recover_purge %u locks for %u nodes",
+ lkb_count, nodes_count);
}
-static struct dlm_rsb *find_purged_rsb(struct dlm_ls *ls, int bucket)
+static struct dlm_rsb *find_grant_rsb(struct dlm_ls *ls, int bucket)
{
struct rb_node *n;
- struct dlm_rsb *r, *r_ret = NULL;
+ struct dlm_rsb *r;
spin_lock(&ls->ls_rsbtbl[bucket].lock);
for (n = rb_first(&ls->ls_rsbtbl[bucket].keep); n; n = rb_next(n)) {
r = rb_entry(n, struct dlm_rsb, res_hashnode);
- if (!rsb_flag(r, RSB_LOCKS_PURGED))
+
+ if (!rsb_flag(r, RSB_RECOVER_GRANT))
+ continue;
+ rsb_clear_flag(r, RSB_RECOVER_GRANT);
+ if (!is_master(r))
continue;
hold_rsb(r);
- rsb_clear_flag(r, RSB_LOCKS_PURGED);
- r_ret = r;
- break;
+ spin_unlock(&ls->ls_rsbtbl[bucket].lock);
+ return r;
}
spin_unlock(&ls->ls_rsbtbl[bucket].lock);
- return r_ret;
+ return NULL;
}
-void dlm_grant_after_purge(struct dlm_ls *ls)
+/*
+ * Attempt to grant locks on resources that we are the master of.
+ * Locks may have become grantable during recovery because locks
+ * from departed nodes have been purged (or not rebuilt), allowing
+ * previously blocked locks to now be granted. The subset of rsb's
+ * we are interested in are those with lkb's on either the convert or
+ * waiting queues.
+ *
+ * Simplest would be to go through each master rsb and check for non-empty
+ * convert or waiting queues, and attempt to grant on those rsbs.
+ * Checking the queues requires lock_rsb, though, for which we'd need
+ * to release the rsbtbl lock. This would make iterating through all
+ * rsb's very inefficient. So, we rely on earlier recovery routines
+ * to set RECOVER_GRANT on any rsb's that we should attempt to grant
+ * locks for.
+ */
+
+void dlm_recover_grant(struct dlm_ls *ls)
{
struct dlm_rsb *r;
int bucket = 0;
+ unsigned int count = 0;
+ unsigned int rsb_count = 0;
+ unsigned int lkb_count = 0;
while (1) {
- r = find_purged_rsb(ls, bucket);
+ r = find_grant_rsb(ls, bucket);
if (!r) {
if (bucket == ls->ls_rsbtbl_size - 1)
break;
bucket++;
continue;
}
+ rsb_count++;
+ count = 0;
lock_rsb(r);
- if (is_master(r)) {
- grant_pending_locks(r);
- confirm_master(r, 0);
- }
+ grant_pending_locks(r, &count);
+ lkb_count += count;
+ confirm_master(r, 0);
unlock_rsb(r);
put_rsb(r);
- schedule();
+ cond_resched();
}
+
+ if (lkb_count)
+ log_debug(ls, "dlm_recover_grant %u locks on %u resources",
+ lkb_count, rsb_count);
}
static struct dlm_lkb *search_remid_list(struct list_head *head, int nodeid,
@@ -4631,6 +4797,7 @@ int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;
struct dlm_rsb *r;
struct dlm_lkb *lkb;
+ uint32_t remid = 0;
int error;
if (rl->rl_parent_lkid) {
@@ -4638,14 +4805,31 @@ int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
goto out;
}
- error = find_rsb(ls, rl->rl_name, le16_to_cpu(rl->rl_namelen),
- R_MASTER, &r);
+ remid = le32_to_cpu(rl->rl_lkid);
+
+ /* In general we expect the rsb returned to be R_MASTER, but we don't
+ have to require it. Recovery of masters on one node can overlap
+ recovery of locks on another node, so one node can send us MSTCPY
+ locks before we've made ourselves master of this rsb. We can still
+ add new MSTCPY locks that we receive here without any harm; when
+ we make ourselves master, dlm_recover_masters() won't touch the
+ MSTCPY locks we've received early. */
+
+ error = find_rsb(ls, rl->rl_name, le16_to_cpu(rl->rl_namelen), 0, &r);
if (error)
goto out;
+ if (dlm_no_directory(ls) && (dlm_dir_nodeid(r) != dlm_our_nodeid())) {
+ log_error(ls, "dlm_recover_master_copy remote %d %x not dir",
+ rc->rc_header.h_nodeid, remid);
+ error = -EBADR;
+ put_rsb(r);
+ goto out;
+ }
+
lock_rsb(r);
- lkb = search_remid(r, rc->rc_header.h_nodeid, le32_to_cpu(rl->rl_lkid));
+ lkb = search_remid(r, rc->rc_header.h_nodeid, remid);
if (lkb) {
error = -EEXIST;
goto out_remid;
@@ -4664,19 +4848,25 @@ int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
attach_lkb(r, lkb);
add_lkb(r, lkb, rl->rl_status);
error = 0;
+ ls->ls_recover_locks_in++;
+
+ if (!list_empty(&r->res_waitqueue) || !list_empty(&r->res_convertqueue))
+ rsb_set_flag(r, RSB_RECOVER_GRANT);
out_remid:
/* this is the new value returned to the lock holder for
saving in its process-copy lkb */
rl->rl_remid = cpu_to_le32(lkb->lkb_id);
+ lkb->lkb_recover_seq = ls->ls_recover_seq;
+
out_unlock:
unlock_rsb(r);
put_rsb(r);
out:
- if (error)
- log_debug(ls, "recover_master_copy %d %x", error,
- le32_to_cpu(rl->rl_lkid));
+ if (error && error != -EEXIST)
+ log_debug(ls, "dlm_recover_master_copy remote %d %x error %d",
+ rc->rc_header.h_nodeid, remid, error);
rl->rl_result = cpu_to_le32(error);
return error;
}
@@ -4687,41 +4877,52 @@ int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;
struct dlm_rsb *r;
struct dlm_lkb *lkb;
- int error;
+ uint32_t lkid, remid;
+ int error, result;
+
+ lkid = le32_to_cpu(rl->rl_lkid);
+ remid = le32_to_cpu(rl->rl_remid);
+ result = le32_to_cpu(rl->rl_result);
- error = find_lkb(ls, le32_to_cpu(rl->rl_lkid), &lkb);
+ error = find_lkb(ls, lkid, &lkb);
if (error) {
- log_error(ls, "recover_process_copy no lkid %x",
- le32_to_cpu(rl->rl_lkid));
+ log_error(ls, "dlm_recover_process_copy no %x remote %d %x %d",
+ lkid, rc->rc_header.h_nodeid, remid, result);
return error;
}
- DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
-
- error = le32_to_cpu(rl->rl_result);
-
r = lkb->lkb_resource;
hold_rsb(r);
lock_rsb(r);
- switch (error) {
+ if (!is_process_copy(lkb)) {
+ log_error(ls, "dlm_recover_process_copy bad %x remote %d %x %d",
+ lkid, rc->rc_header.h_nodeid, remid, result);
+ dlm_dump_rsb(r);
+ unlock_rsb(r);
+ put_rsb(r);
+ dlm_put_lkb(lkb);
+ return -EINVAL;
+ }
+
+ switch (result) {
case -EBADR:
/* There's a chance the new master received our lock before
dlm_recover_master_reply(), this wouldn't happen if we did
a barrier between recover_masters and recover_locks. */
- log_debug(ls, "master copy not ready %x r %lx %s", lkb->lkb_id,
- (unsigned long)r, r->res_name);
+
+ log_debug(ls, "dlm_recover_process_copy %x remote %d %x %d",
+ lkid, rc->rc_header.h_nodeid, remid, result);
+
dlm_send_rcom_lock(r, lkb);
goto out;
case -EEXIST:
- log_debug(ls, "master copy exists %x", lkb->lkb_id);
- /* fall through */
case 0:
- lkb->lkb_remid = le32_to_cpu(rl->rl_remid);
+ lkb->lkb_remid = remid;
break;
default:
- log_error(ls, "dlm_recover_process_copy unknown error %d %x",
- error, lkb->lkb_id);
+ log_error(ls, "dlm_recover_process_copy %x remote %d %x %d unk",
+ lkid, rc->rc_header.h_nodeid, remid, result);
}
/* an ack for dlm_recover_locks() which waits for replies from
diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h
index 1a255307f6ff..c8b226c62807 100644
--- a/fs/dlm/lock.h
+++ b/fs/dlm/lock.h
@@ -15,7 +15,8 @@
void dlm_dump_rsb(struct dlm_rsb *r);
void dlm_print_lkb(struct dlm_lkb *lkb);
-void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms);
+void dlm_receive_message_saved(struct dlm_ls *ls, struct dlm_message *ms,
+ uint32_t saved_seq);
void dlm_receive_buffer(union dlm_packet *p, int nodeid);
int dlm_modes_compat(int mode1, int mode2);
void dlm_put_rsb(struct dlm_rsb *r);
@@ -31,9 +32,9 @@ void dlm_adjust_timeouts(struct dlm_ls *ls);
int dlm_search_rsb_tree(struct rb_root *tree, char *name, int len,
unsigned int flags, struct dlm_rsb **r_ret);
-int dlm_purge_locks(struct dlm_ls *ls);
+void dlm_recover_purge(struct dlm_ls *ls);
void dlm_purge_mstcpy_locks(struct dlm_rsb *r);
-void dlm_grant_after_purge(struct dlm_ls *ls);
+void dlm_recover_grant(struct dlm_ls *ls);
int dlm_recover_waiters_post(struct dlm_ls *ls);
void dlm_recover_waiters_pre(struct dlm_ls *ls);
int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc);
diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c
index a1ea25face82..ca506abbdd3b 100644
--- a/fs/dlm/lockspace.c
+++ b/fs/dlm/lockspace.c
@@ -74,6 +74,19 @@ static ssize_t dlm_id_store(struct dlm_ls *ls, const char *buf, size_t len)
return len;
}
+static ssize_t dlm_nodir_show(struct dlm_ls *ls, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n", dlm_no_directory(ls));
+}
+
+static ssize_t dlm_nodir_store(struct dlm_ls *ls, const char *buf, size_t len)
+{
+ int val = simple_strtoul(buf, NULL, 0);
+ if (val == 1)
+ set_bit(LSFL_NODIR, &ls->ls_flags);
+ return len;
+}
+
static ssize_t dlm_recover_status_show(struct dlm_ls *ls, char *buf)
{
uint32_t status = dlm_recover_status(ls);
@@ -107,6 +120,12 @@ static struct dlm_attr dlm_attr_id = {
.store = dlm_id_store
};
+static struct dlm_attr dlm_attr_nodir = {
+ .attr = {.name = "nodir", .mode = S_IRUGO | S_IWUSR},
+ .show = dlm_nodir_show,
+ .store = dlm_nodir_store
+};
+
static struct dlm_attr dlm_attr_recover_status = {
.attr = {.name = "recover_status", .mode = S_IRUGO},
.show = dlm_recover_status_show
@@ -121,6 +140,7 @@ static struct attribute *dlm_attrs[] = {
&dlm_attr_control.attr,
&dlm_attr_event.attr,
&dlm_attr_id.attr,
+ &dlm_attr_nodir.attr,
&dlm_attr_recover_status.attr,
&dlm_attr_recover_nodeid.attr,
NULL,
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index 133ef6dc7cb7..5c1b0e38c7a4 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -142,6 +142,7 @@ struct writequeue_entry {
static struct sockaddr_storage *dlm_local_addr[DLM_MAX_ADDR_COUNT];
static int dlm_local_count;
+static int dlm_allow_conn;
/* Work queues */
static struct workqueue_struct *recv_workqueue;
@@ -710,6 +711,13 @@ static int tcp_accept_from_sock(struct connection *con)
struct connection *newcon;
struct connection *addcon;
+ mutex_lock(&connections_lock);
+ if (!dlm_allow_conn) {
+ mutex_unlock(&connections_lock);
+ return -1;
+ }
+ mutex_unlock(&connections_lock);
+
memset(&peeraddr, 0, sizeof(peeraddr));
result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_STREAM,
IPPROTO_TCP, &newsock);
@@ -1503,6 +1511,7 @@ void dlm_lowcomms_stop(void)
socket activity.
*/
mutex_lock(&connections_lock);
+ dlm_allow_conn = 0;
foreach_conn(stop_conn);
mutex_unlock(&connections_lock);
@@ -1530,7 +1539,7 @@ int dlm_lowcomms_start(void)
if (!dlm_local_count) {
error = -ENOTCONN;
log_print("no local IP address has been set");
- goto out;
+ goto fail;
}
error = -ENOMEM;
@@ -1538,7 +1547,13 @@ int dlm_lowcomms_start(void)
__alignof__(struct connection), 0,
NULL);
if (!con_cache)
- goto out;
+ goto fail;
+
+ error = work_start();
+ if (error)
+ goto fail_destroy;
+
+ dlm_allow_conn = 1;
/* Start listening */
if (dlm_config.ci_protocol == 0)
@@ -1548,20 +1563,17 @@ int dlm_lowcomms_start(void)
if (error)
goto fail_unlisten;
- error = work_start();
- if (error)
- goto fail_unlisten;
-
return 0;
fail_unlisten:
+ dlm_allow_conn = 0;
con = nodeid2con(0,0);
if (con) {
close_connection(con, false);
kmem_cache_free(con_cache, con);
}
+fail_destroy:
kmem_cache_destroy(con_cache);
-
-out:
+fail:
return error;
}
diff --git a/fs/dlm/memory.c b/fs/dlm/memory.c
index da64df7576e1..7cd24bccd4fe 100644
--- a/fs/dlm/memory.c
+++ b/fs/dlm/memory.c
@@ -21,21 +21,19 @@ static struct kmem_cache *rsb_cache;
int __init dlm_memory_init(void)
{
- int ret = 0;
-
lkb_cache = kmem_cache_create("dlm_lkb", sizeof(struct dlm_lkb),
__alignof__(struct dlm_lkb), 0, NULL);
if (!lkb_cache)
- ret = -ENOMEM;
+ return -ENOMEM;
rsb_cache = kmem_cache_create("dlm_rsb", sizeof(struct dlm_rsb),
__alignof__(struct dlm_rsb), 0, NULL);
if (!rsb_cache) {
kmem_cache_destroy(lkb_cache);
- ret = -ENOMEM;
+ return -ENOMEM;
}
- return ret;
+ return 0;
}
void dlm_memory_exit(void)
diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c
index ac5c616c9696..64d3e2b958c7 100644
--- a/fs/dlm/rcom.c
+++ b/fs/dlm/rcom.c
@@ -486,47 +486,50 @@ int dlm_send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in)
return 0;
}
-static int is_old_reply(struct dlm_ls *ls, struct dlm_rcom *rc)
+/* Called by dlm_recv; corresponds to dlm_receive_message() but special
+ recovery-only comms are sent through here. */
+
+void dlm_receive_rcom(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid)
{
+ int lock_size = sizeof(struct dlm_rcom) + sizeof(struct rcom_lock);
+ int stop, reply = 0, lock = 0;
+ uint32_t status;
uint64_t seq;
- int rv = 0;
switch (rc->rc_type) {
+ case DLM_RCOM_LOCK:
+ lock = 1;
+ break;
+ case DLM_RCOM_LOCK_REPLY:
+ lock = 1;
+ reply = 1;
+ break;
case DLM_RCOM_STATUS_REPLY:
case DLM_RCOM_NAMES_REPLY:
case DLM_RCOM_LOOKUP_REPLY:
- case DLM_RCOM_LOCK_REPLY:
- spin_lock(&ls->ls_recover_lock);
- seq = ls->ls_recover_seq;
- spin_unlock(&ls->ls_recover_lock);
- if (rc->rc_seq_reply != seq) {
- log_debug(ls, "ignoring old reply %x from %d "
- "seq_reply %llx expect %llx",
- rc->rc_type, rc->rc_header.h_nodeid,
- (unsigned long long)rc->rc_seq_reply,
- (unsigned long long)seq);
- rv = 1;
- }
- }
- return rv;
-}
-
-/* Called by dlm_recv; corresponds to dlm_receive_message() but special
- recovery-only comms are sent through here. */
+ reply = 1;
+ };
-void dlm_receive_rcom(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid)
-{
- int lock_size = sizeof(struct dlm_rcom) + sizeof(struct rcom_lock);
+ spin_lock(&ls->ls_recover_lock);
+ status = ls->ls_recover_status;
+ stop = test_bit(LSFL_RECOVERY_STOP, &ls->ls_flags);
+ seq = ls->ls_recover_seq;
+ spin_unlock(&ls->ls_recover_lock);
- if (dlm_recovery_stopped(ls) && (rc->rc_type != DLM_RCOM_STATUS)) {
- log_debug(ls, "ignoring recovery message %x from %d",
- rc->rc_type, nodeid);
+ if ((stop && (rc->rc_type != DLM_RCOM_STATUS)) ||
+ (reply && (rc->rc_seq_reply != seq)) ||
+ (lock && !(status & DLM_RS_DIR))) {
+ log_limit(ls, "dlm_receive_rcom ignore msg %d "
+ "from %d %llu %llu recover seq %llu sts %x gen %u",
+ rc->rc_type,
+ nodeid,
+ (unsigned long long)rc->rc_seq,
+ (unsigned long long)rc->rc_seq_reply,
+ (unsigned long long)seq,
+ status, ls->ls_generation);
goto out;
}
- if (is_old_reply(ls, rc))
- goto out;
-
switch (rc->rc_type) {
case DLM_RCOM_STATUS:
receive_rcom_status(ls, rc);
diff --git a/fs/dlm/recover.c b/fs/dlm/recover.c
index 34d5adf1fce7..7554e4dac6bb 100644
--- a/fs/dlm/recover.c
+++ b/fs/dlm/recover.c
@@ -339,9 +339,12 @@ static void set_lock_master(struct list_head *queue, int nodeid)
{
struct dlm_lkb *lkb;
- list_for_each_entry(lkb, queue, lkb_statequeue)
- if (!(lkb->lkb_flags & DLM_IFL_MSTCPY))
+ list_for_each_entry(lkb, queue, lkb_statequeue) {
+ if (!(lkb->lkb_flags & DLM_IFL_MSTCPY)) {
lkb->lkb_nodeid = nodeid;
+ lkb->lkb_remid = 0;
+ }
+ }
}
static void set_master_lkbs(struct dlm_rsb *r)
@@ -354,18 +357,16 @@ static void set_master_lkbs(struct dlm_rsb *r)
/*
* Propagate the new master nodeid to locks
* The NEW_MASTER flag tells dlm_recover_locks() which rsb's to consider.
- * The NEW_MASTER2 flag tells recover_lvb() and set_locks_purged() which
+ * The NEW_MASTER2 flag tells recover_lvb() and recover_grant() which
* rsb's to consider.
*/
static void set_new_master(struct dlm_rsb *r, int nodeid)
{
- lock_rsb(r);
r->res_nodeid = nodeid;
set_master_lkbs(r);
rsb_set_flag(r, RSB_NEW_MASTER);
rsb_set_flag(r, RSB_NEW_MASTER2);
- unlock_rsb(r);
}
/*
@@ -376,9 +377,9 @@ static void set_new_master(struct dlm_rsb *r, int nodeid)
static int recover_master(struct dlm_rsb *r)
{
struct dlm_ls *ls = r->res_ls;
- int error, dir_nodeid, ret_nodeid, our_nodeid = dlm_our_nodeid();
-
- dir_nodeid = dlm_dir_nodeid(r);
+ int error, ret_nodeid;
+ int our_nodeid = dlm_our_nodeid();
+ int dir_nodeid = dlm_dir_nodeid(r);
if (dir_nodeid == our_nodeid) {
error = dlm_dir_lookup(ls, our_nodeid, r->res_name,
@@ -388,7 +389,9 @@ static int recover_master(struct dlm_rsb *r)
if (ret_nodeid == our_nodeid)
ret_nodeid = 0;
+ lock_rsb(r);
set_new_master(r, ret_nodeid);
+ unlock_rsb(r);
} else {
recover_list_add(r);
error = dlm_send_rcom_lookup(r, dir_nodeid);
@@ -398,24 +401,33 @@ static int recover_master(struct dlm_rsb *r)
}
/*
- * When not using a directory, most resource names will hash to a new static
- * master nodeid and the resource will need to be remastered.
+ * All MSTCPY locks are purged and rebuilt, even if the master stayed the same.
+ * This is necessary because recovery can be started, aborted and restarted,
+ * causing the master nodeid to briefly change during the aborted recovery, and
+ * change back to the original value in the second recovery. The MSTCPY locks
+ * may or may not have been purged during the aborted recovery. Another node
+ * with an outstanding request in waiters list and a request reply saved in the
+ * requestqueue, cannot know whether it should ignore the reply and resend the
+ * request, or accept the reply and complete the request. It must do the
+ * former if the remote node purged MSTCPY locks, and it must do the later if
+ * the remote node did not. This is solved by always purging MSTCPY locks, in
+ * which case, the request reply would always be ignored and the request
+ * resent.
*/
static int recover_master_static(struct dlm_rsb *r)
{
- int master = dlm_dir_nodeid(r);
+ int dir_nodeid = dlm_dir_nodeid(r);
+ int new_master = dir_nodeid;
- if (master == dlm_our_nodeid())
- master = 0;
+ if (dir_nodeid == dlm_our_nodeid())
+ new_master = 0;
- if (r->res_nodeid != master) {
- if (is_master(r))
- dlm_purge_mstcpy_locks(r);
- set_new_master(r, master);
- return 1;
- }
- return 0;
+ lock_rsb(r);
+ dlm_purge_mstcpy_locks(r);
+ set_new_master(r, new_master);
+ unlock_rsb(r);
+ return 1;
}
/*
@@ -481,7 +493,9 @@ int dlm_recover_master_reply(struct dlm_ls *ls, struct dlm_rcom *rc)
if (nodeid == dlm_our_nodeid())
nodeid = 0;
+ lock_rsb(r);
set_new_master(r, nodeid);
+ unlock_rsb(r);
recover_list_del(r);
if (recover_list_empty(ls))
@@ -556,8 +570,6 @@ int dlm_recover_locks(struct dlm_ls *ls)
struct dlm_rsb *r;
int error, count = 0;
- log_debug(ls, "dlm_recover_locks");
-
down_read(&ls->ls_root_sem);
list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
if (is_master(r)) {
@@ -584,7 +596,7 @@ int dlm_recover_locks(struct dlm_ls *ls)
}
up_read(&ls->ls_root_sem);
- log_debug(ls, "dlm_recover_locks %d locks", count);
+ log_debug(ls, "dlm_recover_locks %d out", count);
error = dlm_wait_function(ls, &recover_list_empty);
out:
@@ -721,21 +733,19 @@ static void recover_conversion(struct dlm_rsb *r)
}
/* We've become the new master for this rsb and waiting/converting locks may
- need to be granted in dlm_grant_after_purge() due to locks that may have
+ need to be granted in dlm_recover_grant() due to locks that may have
existed from a removed node. */
-static void set_locks_purged(struct dlm_rsb *r)
+static void recover_grant(struct dlm_rsb *r)
{
if (!list_empty(&r->res_waitqueue) || !list_empty(&r->res_convertqueue))
- rsb_set_flag(r, RSB_LOCKS_PURGED);
+ rsb_set_flag(r, RSB_RECOVER_GRANT);
}
void dlm_recover_rsbs(struct dlm_ls *ls)
{
struct dlm_rsb *r;
- int count = 0;
-
- log_debug(ls, "dlm_recover_rsbs");
+ unsigned int count = 0;
down_read(&ls->ls_root_sem);
list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
@@ -744,7 +754,7 @@ void dlm_recover_rsbs(struct dlm_ls *ls)
if (rsb_flag(r, RSB_RECOVER_CONVERT))
recover_conversion(r);
if (rsb_flag(r, RSB_NEW_MASTER2))
- set_locks_purged(r);
+ recover_grant(r);
recover_lvb(r);
count++;
}
@@ -754,7 +764,8 @@ void dlm_recover_rsbs(struct dlm_ls *ls)
}
up_read(&ls->ls_root_sem);
- log_debug(ls, "dlm_recover_rsbs %d rsbs", count);
+ if (count)
+ log_debug(ls, "dlm_recover_rsbs %d done", count);
}
/* Create a single list of all root rsb's to be used during recovery */
diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c
index 3780caf7ae0c..f1a9073c0835 100644
--- a/fs/dlm/recoverd.c
+++ b/fs/dlm/recoverd.c
@@ -54,7 +54,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
unsigned long start;
int error, neg = 0;
- log_debug(ls, "dlm_recover %llx", (unsigned long long)rv->seq);
+ log_debug(ls, "dlm_recover %llu", (unsigned long long)rv->seq);
mutex_lock(&ls->ls_recoverd_active);
@@ -84,6 +84,8 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
goto fail;
}
+ ls->ls_recover_locks_in = 0;
+
dlm_set_recover_status(ls, DLM_RS_NODES);
error = dlm_recover_members_wait(ls);
@@ -130,7 +132,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
* Clear lkb's for departed nodes.
*/
- dlm_purge_locks(ls);
+ dlm_recover_purge(ls);
/*
* Get new master nodeid's for rsb's that were mastered on
@@ -161,6 +163,9 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
goto fail;
}
+ log_debug(ls, "dlm_recover_locks %u in",
+ ls->ls_recover_locks_in);
+
/*
* Finalize state in master rsb's now that all locks can be
* checked. This includes conversion resolution and lvb
@@ -225,9 +230,9 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
goto fail;
}
- dlm_grant_after_purge(ls);
+ dlm_recover_grant(ls);
- log_debug(ls, "dlm_recover %llx generation %u done: %u ms",
+ log_debug(ls, "dlm_recover %llu generation %u done: %u ms",
(unsigned long long)rv->seq, ls->ls_generation,
jiffies_to_msecs(jiffies - start));
mutex_unlock(&ls->ls_recoverd_active);
@@ -237,7 +242,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
fail:
dlm_release_root_list(ls);
- log_debug(ls, "dlm_recover %llx error %d",
+ log_debug(ls, "dlm_recover %llu error %d",
(unsigned long long)rv->seq, error);
mutex_unlock(&ls->ls_recoverd_active);
return error;
diff --git a/fs/dlm/requestqueue.c b/fs/dlm/requestqueue.c
index a44fa22890e1..1695f1b0dd45 100644
--- a/fs/dlm/requestqueue.c
+++ b/fs/dlm/requestqueue.c
@@ -19,6 +19,7 @@
struct rq_entry {
struct list_head list;
+ uint32_t recover_seq;
int nodeid;
struct dlm_message request;
};
@@ -41,6 +42,7 @@ void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_message *ms)
return;
}
+ e->recover_seq = ls->ls_recover_seq & 0xFFFFFFFF;
e->nodeid = nodeid;
memcpy(&e->request, ms, ms->m_header.h_length);
@@ -63,6 +65,7 @@ void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_message *ms)
int dlm_process_requestqueue(struct dlm_ls *ls)
{
struct rq_entry *e;
+ struct dlm_message *ms;
int error = 0;
mutex_lock(&ls->ls_requestqueue_mutex);
@@ -76,7 +79,15 @@ int dlm_process_requestqueue(struct dlm_ls *ls)
e = list_entry(ls->ls_requestqueue.next, struct rq_entry, list);
mutex_unlock(&ls->ls_requestqueue_mutex);
- dlm_receive_message_saved(ls, &e->request);
+ ms = &e->request;
+
+ log_limit(ls, "dlm_process_requestqueue msg %d from %d "
+ "lkid %x remid %x result %d seq %u",
+ ms->m_type, ms->m_header.h_nodeid,
+ ms->m_lkid, ms->m_remid, ms->m_result,
+ e->recover_seq);
+
+ dlm_receive_message_saved(ls, &e->request, e->recover_seq);
mutex_lock(&ls->ls_requestqueue_mutex);
list_del(&e->list);
@@ -138,35 +149,7 @@ static int purge_request(struct dlm_ls *ls, struct dlm_message *ms, int nodeid)
if (!dlm_no_directory(ls))
return 0;
- /* with no directory, the master is likely to change as a part of
- recovery; requests to/from the defunct master need to be purged */
-
- switch (type) {
- case DLM_MSG_REQUEST:
- case DLM_MSG_CONVERT:
- case DLM_MSG_UNLOCK:
- case DLM_MSG_CANCEL:
- /* we're no longer the master of this resource, the sender
- will resend to the new master (see waiter_needs_recovery) */
-
- if (dlm_hash2nodeid(ls, ms->m_hash) != dlm_our_nodeid())
- return 1;
- break;
-
- case DLM_MSG_REQUEST_REPLY:
- case DLM_MSG_CONVERT_REPLY:
- case DLM_MSG_UNLOCK_REPLY:
- case DLM_MSG_CANCEL_REPLY:
- case DLM_MSG_GRANT:
- /* this reply is from the former master of the resource,
- we'll resend to the new master if needed */
-
- if (dlm_hash2nodeid(ls, ms->m_hash) != nodeid)
- return 1;
- break;
- }
-
- return 0;
+ return 1;
}
void dlm_purge_requestqueue(struct dlm_ls *ls)
diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c
index ab2248090515..a750f957b145 100644
--- a/fs/ecryptfs/messaging.c
+++ b/fs/ecryptfs/messaging.c
@@ -303,7 +303,7 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
mutex_unlock(&ecryptfs_daemon_hash_mux);
goto wake_up;
}
- tsk_user_ns = __task_cred(msg_ctx->task)->user->user_ns;
+ tsk_user_ns = __task_cred(msg_ctx->task)->user_ns;
ctx_euid = task_euid(msg_ctx->task);
rc = ecryptfs_find_daemon_by_euid(&daemon, ctx_euid, tsk_user_ns);
rcu_read_unlock();
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index c0b3c70ee87a..079d1be65ba9 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -33,6 +33,7 @@
#include <linux/bitops.h>
#include <linux/mutex.h>
#include <linux/anon_inodes.h>
+#include <linux/device.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/mman.h>
@@ -87,7 +88,7 @@
*/
/* Epoll private bits inside the event mask */
-#define EP_PRIVATE_BITS (EPOLLONESHOT | EPOLLET)
+#define EP_PRIVATE_BITS (EPOLLWAKEUP | EPOLLONESHOT | EPOLLET)
/* Maximum number of nesting allowed inside epoll sets */
#define EP_MAX_NESTS 4
@@ -154,6 +155,9 @@ struct epitem {
/* List header used to link this item to the "struct file" items list */
struct list_head fllink;
+ /* wakeup_source used when EPOLLWAKEUP is set */
+ struct wakeup_source *ws;
+
/* The structure that describe the interested events and the source fd */
struct epoll_event event;
};
@@ -194,6 +198,9 @@ struct eventpoll {
*/
struct epitem *ovflist;
+ /* wakeup_source used when ep_scan_ready_list is running */
+ struct wakeup_source *ws;
+
/* The user that created the eventpoll descriptor */
struct user_struct *user;
@@ -588,8 +595,10 @@ static int ep_scan_ready_list(struct eventpoll *ep,
* queued into ->ovflist but the "txlist" might already
* contain them, and the list_splice() below takes care of them.
*/
- if (!ep_is_linked(&epi->rdllink))
+ if (!ep_is_linked(&epi->rdllink)) {
list_add_tail(&epi->rdllink, &ep->rdllist);
+ __pm_stay_awake(epi->ws);
+ }
}
/*
* We need to set back ep->ovflist to EP_UNACTIVE_PTR, so that after
@@ -602,6 +611,7 @@ static int ep_scan_ready_list(struct eventpoll *ep,
* Quickly re-inject items left on "txlist".
*/
list_splice(&txlist, &ep->rdllist);
+ __pm_relax(ep->ws);
if (!list_empty(&ep->rdllist)) {
/*
@@ -656,6 +666,8 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi)
list_del_init(&epi->rdllink);
spin_unlock_irqrestore(&ep->lock, flags);
+ wakeup_source_unregister(epi->ws);
+
/* At this point it is safe to free the eventpoll item */
kmem_cache_free(epi_cache, epi);
@@ -706,6 +718,7 @@ static void ep_free(struct eventpoll *ep)
mutex_unlock(&epmutex);
mutex_destroy(&ep->mtx);
free_uid(ep->user);
+ wakeup_source_unregister(ep->ws);
kfree(ep);
}
@@ -737,6 +750,7 @@ static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head,
* callback, but it's not actually ready, as far as
* caller requested events goes. We can remove it here.
*/
+ __pm_relax(epi->ws);
list_del_init(&epi->rdllink);
}
}
@@ -927,13 +941,23 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k
if (epi->next == EP_UNACTIVE_PTR) {
epi->next = ep->ovflist;
ep->ovflist = epi;
+ if (epi->ws) {
+ /*
+ * Activate ep->ws since epi->ws may get
+ * deactivated at any time.
+ */
+ __pm_stay_awake(ep->ws);
+ }
+
}
goto out_unlock;
}
/* If this file is already in the ready list we exit soon */
- if (!ep_is_linked(&epi->rdllink))
+ if (!ep_is_linked(&epi->rdllink)) {
list_add_tail(&epi->rdllink, &ep->rdllist);
+ __pm_stay_awake(epi->ws);
+ }
/*
* Wake up ( if active ) both the eventpoll wait list and the ->poll()
@@ -1091,6 +1115,30 @@ static int reverse_path_check(void)
return error;
}
+static int ep_create_wakeup_source(struct epitem *epi)
+{
+ const char *name;
+
+ if (!epi->ep->ws) {
+ epi->ep->ws = wakeup_source_register("eventpoll");
+ if (!epi->ep->ws)
+ return -ENOMEM;
+ }
+
+ name = epi->ffd.file->f_path.dentry->d_name.name;
+ epi->ws = wakeup_source_register(name);
+ if (!epi->ws)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void ep_destroy_wakeup_source(struct epitem *epi)
+{
+ wakeup_source_unregister(epi->ws);
+ epi->ws = NULL;
+}
+
/*
* Must be called with "mtx" held.
*/
@@ -1118,6 +1166,13 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
epi->event = *event;
epi->nwait = 0;
epi->next = EP_UNACTIVE_PTR;
+ if (epi->event.events & EPOLLWAKEUP) {
+ error = ep_create_wakeup_source(epi);
+ if (error)
+ goto error_create_wakeup_source;
+ } else {
+ epi->ws = NULL;
+ }
/* Initialize the poll table using the queue callback */
epq.epi = epi;
@@ -1164,6 +1219,7 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
/* If the file is already "ready" we drop it inside the ready list */
if ((revents & event->events) && !ep_is_linked(&epi->rdllink)) {
list_add_tail(&epi->rdllink, &ep->rdllist);
+ __pm_stay_awake(epi->ws);
/* Notify waiting tasks that events are available */
if (waitqueue_active(&ep->wq))
@@ -1204,6 +1260,9 @@ error_unregister:
list_del_init(&epi->rdllink);
spin_unlock_irqrestore(&ep->lock, flags);
+ wakeup_source_unregister(epi->ws);
+
+error_create_wakeup_source:
kmem_cache_free(epi_cache, epi);
return error;
@@ -1229,6 +1288,12 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
epi->event.events = event->events;
pt._key = event->events;
epi->event.data = event->data; /* protected by mtx */
+ if (epi->event.events & EPOLLWAKEUP) {
+ if (!epi->ws)
+ ep_create_wakeup_source(epi);
+ } else if (epi->ws) {
+ ep_destroy_wakeup_source(epi);
+ }
/*
* Get current event bits. We can safely use the file* here because
@@ -1244,6 +1309,7 @@ static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_even
spin_lock_irq(&ep->lock);
if (!ep_is_linked(&epi->rdllink)) {
list_add_tail(&epi->rdllink, &ep->rdllist);
+ __pm_stay_awake(epi->ws);
/* Notify waiting tasks that events are available */
if (waitqueue_active(&ep->wq))
@@ -1282,6 +1348,18 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head,
!list_empty(head) && eventcnt < esed->maxevents;) {
epi = list_first_entry(head, struct epitem, rdllink);
+ /*
+ * Activate ep->ws before deactivating epi->ws to prevent
+ * triggering auto-suspend here (in case we reactive epi->ws
+ * below).
+ *
+ * This could be rearranged to delay the deactivation of epi->ws
+ * instead, but then epi->ws would temporarily be out of sync
+ * with ep_is_linked().
+ */
+ if (epi->ws && epi->ws->active)
+ __pm_stay_awake(ep->ws);
+ __pm_relax(epi->ws);
list_del_init(&epi->rdllink);
pt._key = epi->event.events;
@@ -1298,6 +1376,7 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head,
if (__put_user(revents, &uevent->events) ||
__put_user(epi->event.data, &uevent->data)) {
list_add(&epi->rdllink, head);
+ __pm_stay_awake(epi->ws);
return eventcnt ? eventcnt : -EFAULT;
}
eventcnt++;
@@ -1317,6 +1396,7 @@ static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head,
* poll callback will queue them in ep->ovflist.
*/
list_add_tail(&epi->rdllink, &ep->rdllist);
+ __pm_stay_awake(epi->ws);
}
}
}
@@ -1629,6 +1709,10 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd,
if (!tfile->f_op || !tfile->f_op->poll)
goto error_tgt_fput;
+ /* Check if EPOLLWAKEUP is allowed */
+ if ((epds.events & EPOLLWAKEUP) && !capable(CAP_EPOLLWAKEUP))
+ epds.events &= ~EPOLLWAKEUP;
+
/*
* We have to check that the file structure underneath the file descriptor
* the user passed to us _is_ an eventpoll file. And also we do not permit
diff --git a/fs/exec.c b/fs/exec.c
index d038968b54b4..52c9e2ff6e6b 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1139,7 +1139,7 @@ void setup_new_exec(struct linux_binprm * bprm)
/* This is the point of no return */
current->sas_ss_sp = current->sas_ss_size = 0;
- if (current_euid() == current_uid() && current_egid() == current_gid())
+ if (uid_eq(current_euid(), current_uid()) && gid_eq(current_egid(), current_gid()))
set_dumpable(current->mm, 1);
else
set_dumpable(current->mm, suid_dumpable);
@@ -1153,8 +1153,8 @@ void setup_new_exec(struct linux_binprm * bprm)
current->mm->task_size = TASK_SIZE;
/* install the new credentials */
- if (bprm->cred->uid != current_euid() ||
- bprm->cred->gid != current_egid()) {
+ if (!uid_eq(bprm->cred->uid, current_euid()) ||
+ !gid_eq(bprm->cred->gid, current_egid())) {
current->pdeath_signal = 0;
} else {
would_dump(bprm, bprm->file);
@@ -1299,8 +1299,11 @@ int prepare_binprm(struct linux_binprm *bprm)
!current->no_new_privs) {
/* Set-uid? */
if (mode & S_ISUID) {
+ if (!kuid_has_mapping(bprm->cred->user_ns, inode->i_uid))
+ return -EPERM;
bprm->per_clear |= PER_CLEAR_ON_SETID;
bprm->cred->euid = inode->i_uid;
+
}
/* Set-gid? */
@@ -1310,6 +1313,8 @@ int prepare_binprm(struct linux_binprm *bprm)
* executable.
*/
if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
+ if (!kgid_has_mapping(bprm->cred->user_ns, inode->i_gid))
+ return -EPERM;
bprm->per_clear |= PER_CLEAR_ON_SETID;
bprm->cred->egid = inode->i_gid;
}
@@ -1938,8 +1943,21 @@ static int coredump_wait(int exit_code, struct core_state *core_state)
core_waiters = zap_threads(tsk, mm, core_state, exit_code);
up_write(&mm->mmap_sem);
- if (core_waiters > 0)
+ if (core_waiters > 0) {
+ struct core_thread *ptr;
+
wait_for_completion(&core_state->startup);
+ /*
+ * Wait for all the threads to become inactive, so that
+ * all the thread context (extended register state, like
+ * fpu etc) gets copied to the memory.
+ */
+ ptr = core_state->dumper.next;
+ while (ptr != NULL) {
+ wait_task_inactive(ptr->task, 0);
+ ptr = ptr->next;
+ }
+ }
return core_waiters;
}
@@ -2129,7 +2147,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
if (__get_dumpable(cprm.mm_flags) == 2) {
/* Setuid core dump mode */
flag = O_EXCL; /* Stop rewrite attacks */
- cred->fsuid = 0; /* Dump root private */
+ cred->fsuid = GLOBAL_ROOT_UID; /* Dump root private */
}
retval = coredump_wait(exit_code, &core_state);
@@ -2230,7 +2248,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
* Dont allow local users get cute and trick others to coredump
* into their pre-created files.
*/
- if (inode->i_uid != current_fsuid())
+ if (!uid_eq(inode->i_uid, current_fsuid()))
goto close_fail;
if (!cprm.file->f_op || !cprm.file->f_op->write)
goto close_fail;
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index a8cbe1bc6ad4..030c6d277e14 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -1193,8 +1193,9 @@ static int ext2_has_free_blocks(struct ext2_sb_info *sbi)
free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count);
if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) &&
- sbi->s_resuid != current_fsuid() &&
- (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) {
+ !uid_eq(sbi->s_resuid, current_fsuid()) &&
+ (gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) ||
+ !in_group_p (sbi->s_resgid))) {
return 0;
}
return 1;
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index 0b2b4db5bdcd..d9a17d0b124d 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -82,8 +82,8 @@ struct ext2_sb_info {
struct buffer_head ** s_group_desc;
unsigned long s_mount_opt;
unsigned long s_sb_block;
- uid_t s_resuid;
- gid_t s_resgid;
+ kuid_t s_resuid;
+ kgid_t s_resgid;
unsigned short s_mount_state;
unsigned short s_pad;
int s_addr_per_block_bits;
@@ -637,8 +637,8 @@ static inline void verify_offsets(void)
*/
struct ext2_mount_options {
unsigned long s_mount_opt;
- uid_t s_resuid;
- gid_t s_resgid;
+ kuid_t s_resuid;
+ kgid_t s_resgid;
};
/*
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 740cad8dcd8d..f9fa95f8443d 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -1293,6 +1293,8 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
struct inode *inode;
long ret = -EIO;
int n;
+ uid_t i_uid;
+ gid_t i_gid;
inode = iget_locked(sb, ino);
if (!inode)
@@ -1310,12 +1312,14 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
}
inode->i_mode = le16_to_cpu(raw_inode->i_mode);
- inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
- inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
+ i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
+ i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
if (!(test_opt (inode->i_sb, NO_UID32))) {
- inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
- inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
+ i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
+ i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
}
+ i_uid_write(inode, i_uid);
+ i_gid_write(inode, i_gid);
set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));
inode->i_size = le32_to_cpu(raw_inode->i_size);
inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime);
@@ -1413,8 +1417,8 @@ static int __ext2_write_inode(struct inode *inode, int do_sync)
struct ext2_inode_info *ei = EXT2_I(inode);
struct super_block *sb = inode->i_sb;
ino_t ino = inode->i_ino;
- uid_t uid = inode->i_uid;
- gid_t gid = inode->i_gid;
+ uid_t uid = i_uid_read(inode);
+ gid_t gid = i_gid_read(inode);
struct buffer_head * bh;
struct ext2_inode * raw_inode = ext2_get_inode(sb, ino, &bh);
int n;
@@ -1529,8 +1533,8 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
if (is_quota_modification(inode, iattr))
dquot_initialize(inode);
- if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) ||
- (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) {
+ if ((iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)) ||
+ (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))) {
error = dquot_transfer(inode, iattr);
if (error)
return error;
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index e1025c7a437a..38f816071ddb 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -228,13 +228,15 @@ static int ext2_show_options(struct seq_file *seq, struct dentry *root)
seq_puts(seq, ",grpid");
if (!test_opt(sb, GRPID) && (def_mount_opts & EXT2_DEFM_BSDGROUPS))
seq_puts(seq, ",nogrpid");
- if (sbi->s_resuid != EXT2_DEF_RESUID ||
+ if (!uid_eq(sbi->s_resuid, make_kuid(&init_user_ns, EXT2_DEF_RESUID)) ||
le16_to_cpu(es->s_def_resuid) != EXT2_DEF_RESUID) {
- seq_printf(seq, ",resuid=%u", sbi->s_resuid);
+ seq_printf(seq, ",resuid=%u",
+ from_kuid_munged(&init_user_ns, sbi->s_resuid));
}
- if (sbi->s_resgid != EXT2_DEF_RESGID ||
+ if (!gid_eq(sbi->s_resgid, make_kgid(&init_user_ns, EXT2_DEF_RESGID)) ||
le16_to_cpu(es->s_def_resgid) != EXT2_DEF_RESGID) {
- seq_printf(seq, ",resgid=%u", sbi->s_resgid);
+ seq_printf(seq, ",resgid=%u",
+ from_kgid_munged(&init_user_ns, sbi->s_resgid));
}
if (test_opt(sb, ERRORS_RO)) {
int def_errors = le16_to_cpu(es->s_errors);
@@ -436,6 +438,8 @@ static int parse_options(char *options, struct super_block *sb)
struct ext2_sb_info *sbi = EXT2_SB(sb);
substring_t args[MAX_OPT_ARGS];
int option;
+ kuid_t uid;
+ kgid_t gid;
if (!options)
return 1;
@@ -462,12 +466,23 @@ static int parse_options(char *options, struct super_block *sb)
case Opt_resuid:
if (match_int(&args[0], &option))
return 0;
- sbi->s_resuid = option;
+ uid = make_kuid(current_user_ns(), option);
+ if (!uid_valid(uid)) {
+ ext2_msg(sb, KERN_ERR, "Invalid uid value %d", option);
+ return -1;
+
+ }
+ sbi->s_resuid = uid;
break;
case Opt_resgid:
if (match_int(&args[0], &option))
return 0;
- sbi->s_resgid = option;
+ gid = make_kgid(current_user_ns(), option);
+ if (!gid_valid(gid)) {
+ ext2_msg(sb, KERN_ERR, "Invalid gid value %d", option);
+ return -1;
+ }
+ sbi->s_resgid = gid;
break;
case Opt_sb:
/* handled by get_sb_block() instead of here */
@@ -841,8 +856,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
else
set_opt(sbi->s_mount_opt, ERRORS_RO);
- sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
- sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
+ sbi->s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid));
+ sbi->s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid));
set_opt(sbi->s_mount_opt, RESERVATION);
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index baac1b129fba..25cd60892116 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -1439,8 +1439,9 @@ static int ext3_has_free_blocks(struct ext3_sb_info *sbi, int use_reservation)
free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count);
if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) &&
- !use_reservation && sbi->s_resuid != current_fsuid() &&
- (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) {
+ !use_reservation && !uid_eq(sbi->s_resuid, current_fsuid()) &&
+ (gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) ||
+ !in_group_p (sbi->s_resgid))) {
return 0;
}
return 1;
diff --git a/fs/ext3/ext3.h b/fs/ext3/ext3.h
index b6515fd7e56c..7977973a24f0 100644
--- a/fs/ext3/ext3.h
+++ b/fs/ext3/ext3.h
@@ -243,8 +243,8 @@ struct ext3_new_group_data {
*/
struct ext3_mount_options {
unsigned long s_mount_opt;
- uid_t s_resuid;
- gid_t s_resgid;
+ kuid_t s_resuid;
+ kgid_t s_resgid;
unsigned long s_commit_interval;
#ifdef CONFIG_QUOTA
int s_jquota_fmt;
@@ -637,8 +637,8 @@ struct ext3_sb_info {
struct buffer_head ** s_group_desc;
unsigned long s_mount_opt;
ext3_fsblk_t s_sb_block;
- uid_t s_resuid;
- gid_t s_resgid;
+ kuid_t s_resuid;
+ kgid_t s_resgid;
unsigned short s_mount_state;
unsigned short s_pad;
int s_addr_per_block_bits;
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 10d7812f6021..a09790a412b1 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -2891,6 +2891,8 @@ struct inode *ext3_iget(struct super_block *sb, unsigned long ino)
transaction_t *transaction;
long ret;
int block;
+ uid_t i_uid;
+ gid_t i_gid;
inode = iget_locked(sb, ino);
if (!inode)
@@ -2907,12 +2909,14 @@ struct inode *ext3_iget(struct super_block *sb, unsigned long ino)
bh = iloc.bh;
raw_inode = ext3_raw_inode(&iloc);
inode->i_mode = le16_to_cpu(raw_inode->i_mode);
- inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
- inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
+ i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
+ i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
if(!(test_opt (inode->i_sb, NO_UID32))) {
- inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
- inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
+ i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
+ i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
}
+ i_uid_write(inode, i_uid);
+ i_gid_write(inode, i_gid);
set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));
inode->i_size = le32_to_cpu(raw_inode->i_size);
inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime);
@@ -3068,6 +3072,8 @@ static int ext3_do_update_inode(handle_t *handle,
struct ext3_inode_info *ei = EXT3_I(inode);
struct buffer_head *bh = iloc->bh;
int err = 0, rc, block;
+ uid_t i_uid;
+ gid_t i_gid;
again:
/* we can't allow multiple procs in here at once, its a bit racey */
@@ -3080,27 +3086,29 @@ again:
ext3_get_inode_flags(ei);
raw_inode->i_mode = cpu_to_le16(inode->i_mode);
+ i_uid = i_uid_read(inode);
+ i_gid = i_gid_read(inode);
if(!(test_opt(inode->i_sb, NO_UID32))) {
- raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
- raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid));
+ raw_inode->i_uid_low = cpu_to_le16(low_16_bits(i_uid));
+ raw_inode->i_gid_low = cpu_to_le16(low_16_bits(i_gid));
/*
* Fix up interoperability with old kernels. Otherwise, old inodes get
* re-used with the upper 16 bits of the uid/gid intact
*/
if(!ei->i_dtime) {
raw_inode->i_uid_high =
- cpu_to_le16(high_16_bits(inode->i_uid));
+ cpu_to_le16(high_16_bits(i_uid));
raw_inode->i_gid_high =
- cpu_to_le16(high_16_bits(inode->i_gid));
+ cpu_to_le16(high_16_bits(i_gid));
} else {
raw_inode->i_uid_high = 0;
raw_inode->i_gid_high = 0;
}
} else {
raw_inode->i_uid_low =
- cpu_to_le16(fs_high2lowuid(inode->i_uid));
+ cpu_to_le16(fs_high2lowuid(i_uid));
raw_inode->i_gid_low =
- cpu_to_le16(fs_high2lowgid(inode->i_gid));
+ cpu_to_le16(fs_high2lowgid(i_gid));
raw_inode->i_uid_high = 0;
raw_inode->i_gid_high = 0;
}
@@ -3262,8 +3270,8 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr)
if (is_quota_modification(inode, attr))
dquot_initialize(inode);
- if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
- (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
+ if ((ia_valid & ATTR_UID && !uid_eq(attr->ia_uid, inode->i_uid)) ||
+ (ia_valid & ATTR_GID && !gid_eq(attr->ia_gid, inode->i_gid))) {
handle_t *handle;
/* (user+group)*(old+new) structure, inode write (sb,
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index cf0b5921cf0f..94ef7e616129 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -617,13 +617,15 @@ static int ext3_show_options(struct seq_file *seq, struct dentry *root)
seq_puts(seq, ",grpid");
if (!test_opt(sb, GRPID) && (def_mount_opts & EXT3_DEFM_BSDGROUPS))
seq_puts(seq, ",nogrpid");
- if (sbi->s_resuid != EXT3_DEF_RESUID ||
+ if (!uid_eq(sbi->s_resuid, make_kuid(&init_user_ns, EXT3_DEF_RESUID)) ||
le16_to_cpu(es->s_def_resuid) != EXT3_DEF_RESUID) {
- seq_printf(seq, ",resuid=%u", sbi->s_resuid);
+ seq_printf(seq, ",resuid=%u",
+ from_kuid_munged(&init_user_ns, sbi->s_resuid));
}
- if (sbi->s_resgid != EXT3_DEF_RESGID ||
+ if (!gid_eq(sbi->s_resgid, make_kgid(&init_user_ns, EXT3_DEF_RESGID)) ||
le16_to_cpu(es->s_def_resgid) != EXT3_DEF_RESGID) {
- seq_printf(seq, ",resgid=%u", sbi->s_resgid);
+ seq_printf(seq, ",resgid=%u",
+ from_kgid_munged(&init_user_ns, sbi->s_resgid));
}
if (test_opt(sb, ERRORS_RO)) {
int def_errors = le16_to_cpu(es->s_errors);
@@ -967,6 +969,8 @@ static int parse_options (char *options, struct super_block *sb,
substring_t args[MAX_OPT_ARGS];
int data_opt = 0;
int option;
+ kuid_t uid;
+ kgid_t gid;
#ifdef CONFIG_QUOTA
int qfmt;
#endif
@@ -1000,12 +1004,23 @@ static int parse_options (char *options, struct super_block *sb,
case Opt_resuid:
if (match_int(&args[0], &option))
return 0;
- sbi->s_resuid = option;
+ uid = make_kuid(current_user_ns(), option);
+ if (!uid_valid(uid)) {
+ ext3_msg(sb, KERN_ERR, "Invalid uid value %d", option);
+ return -1;
+
+ }
+ sbi->s_resuid = uid;
break;
case Opt_resgid:
if (match_int(&args[0], &option))
return 0;
- sbi->s_resgid = option;
+ gid = make_kgid(current_user_ns(), option);
+ if (!gid_valid(gid)) {
+ ext3_msg(sb, KERN_ERR, "Invalid gid value %d", option);
+ return -1;
+ }
+ sbi->s_resgid = gid;
break;
case Opt_sb:
/* handled by get_sb_block() instead of here */
@@ -1651,8 +1666,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
}
sb->s_fs_info = sbi;
sbi->s_mount_opt = 0;
- sbi->s_resuid = EXT3_DEF_RESUID;
- sbi->s_resgid = EXT3_DEF_RESGID;
+ sbi->s_resuid = make_kuid(&init_user_ns, EXT3_DEF_RESUID);
+ sbi->s_resgid = make_kgid(&init_user_ns, EXT3_DEF_RESGID);
sbi->s_sb_block = sb_block;
blocksize = sb_min_blocksize(sb, EXT3_MIN_BLOCK_SIZE);
@@ -1716,8 +1731,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
else
set_opt(sbi->s_mount_opt, ERRORS_RO);
- sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
- sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
+ sbi->s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid));
+ sbi->s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid));
/* enable barriers by default */
set_opt(sbi->s_mount_opt, BARRIER);
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index 4bbd07a6fa18..c45c41129a35 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -461,8 +461,8 @@ static int ext4_has_free_clusters(struct ext4_sb_info *sbi,
return 1;
/* Hm, nope. Are (enough) root reserved clusters available? */
- if (sbi->s_resuid == current_fsuid() ||
- ((sbi->s_resgid != 0) && in_group_p(sbi->s_resgid)) ||
+ if (uid_eq(sbi->s_resuid, current_fsuid()) ||
+ (!gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) && in_group_p(sbi->s_resgid)) ||
capable(CAP_SYS_RESOURCE) ||
(flags & EXT4_MB_USE_ROOT_BLOCKS)) {
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 0e01e90add8b..c21b1de51afb 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1153,8 +1153,8 @@ struct ext4_sb_info {
unsigned int s_mount_flags;
unsigned int s_def_mount_opt;
ext4_fsblk_t s_sb_block;
- uid_t s_resuid;
- gid_t s_resgid;
+ kuid_t s_resuid;
+ kgid_t s_resgid;
unsigned short s_mount_state;
unsigned short s_pad;
int s_addr_per_block_bits;
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 409c2ee7750a..9f9acac6c43f 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -808,8 +808,8 @@ got:
}
if (owner) {
inode->i_mode = mode;
- inode->i_uid = owner[0];
- inode->i_gid = owner[1];
+ i_uid_write(inode, owner[0]);
+ i_gid_write(inode, owner[1]);
} else if (test_opt(sb, GRPID)) {
inode->i_mode = mode;
inode->i_uid = current_fsuid();
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index c77b0bd2c711..07eaf565fdcb 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3630,6 +3630,8 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
journal_t *journal = EXT4_SB(sb)->s_journal;
long ret;
int block;
+ uid_t i_uid;
+ gid_t i_gid;
inode = iget_locked(sb, ino);
if (!inode)
@@ -3645,12 +3647,14 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
goto bad_inode;
raw_inode = ext4_raw_inode(&iloc);
inode->i_mode = le16_to_cpu(raw_inode->i_mode);
- inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
- inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
+ i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
+ i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
if (!(test_opt(inode->i_sb, NO_UID32))) {
- inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
- inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
+ i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
+ i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
}
+ i_uid_write(inode, i_uid);
+ i_gid_write(inode, i_gid);
set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));
ext4_clear_state_flags(ei); /* Only relevant on 32-bit archs */
@@ -3870,6 +3874,8 @@ static int ext4_do_update_inode(handle_t *handle,
struct ext4_inode_info *ei = EXT4_I(inode);
struct buffer_head *bh = iloc->bh;
int err = 0, rc, block;
+ uid_t i_uid;
+ gid_t i_gid;
/* For fields not not tracking in the in-memory inode,
* initialise them to zero for new inodes. */
@@ -3878,27 +3884,27 @@ static int ext4_do_update_inode(handle_t *handle,
ext4_get_inode_flags(ei);
raw_inode->i_mode = cpu_to_le16(inode->i_mode);
+ i_uid = i_uid_read(inode);
+ i_gid = i_gid_read(inode);
if (!(test_opt(inode->i_sb, NO_UID32))) {
- raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
- raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid));
+ raw_inode->i_uid_low = cpu_to_le16(low_16_bits(i_uid));
+ raw_inode->i_gid_low = cpu_to_le16(low_16_bits(i_gid));
/*
* Fix up interoperability with old kernels. Otherwise, old inodes get
* re-used with the upper 16 bits of the uid/gid intact
*/
if (!ei->i_dtime) {
raw_inode->i_uid_high =
- cpu_to_le16(high_16_bits(inode->i_uid));
+ cpu_to_le16(high_16_bits(i_uid));
raw_inode->i_gid_high =
- cpu_to_le16(high_16_bits(inode->i_gid));
+ cpu_to_le16(high_16_bits(i_gid));
} else {
raw_inode->i_uid_high = 0;
raw_inode->i_gid_high = 0;
}
} else {
- raw_inode->i_uid_low =
- cpu_to_le16(fs_high2lowuid(inode->i_uid));
- raw_inode->i_gid_low =
- cpu_to_le16(fs_high2lowgid(inode->i_gid));
+ raw_inode->i_uid_low = cpu_to_le16(fs_high2lowuid(i_uid));
+ raw_inode->i_gid_low = cpu_to_le16(fs_high2lowgid(i_gid));
raw_inode->i_uid_high = 0;
raw_inode->i_gid_high = 0;
}
@@ -4084,8 +4090,8 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
if (is_quota_modification(inode, attr))
dquot_initialize(inode);
- if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
- (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
+ if ((ia_valid & ATTR_UID && !uid_eq(attr->ia_uid, inode->i_uid)) ||
+ (ia_valid & ATTR_GID && !gid_eq(attr->ia_gid, inode->i_gid))) {
handle_t *handle;
/* (user+group)*(old+new) structure, inode write (sb,
diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c
index f39f80f8f2c5..f1bb32ec0169 100644
--- a/fs/ext4/migrate.c
+++ b/fs/ext4/migrate.c
@@ -466,8 +466,8 @@ int ext4_ext_migrate(struct inode *inode)
}
goal = (((inode->i_ino - 1) / EXT4_INODES_PER_GROUP(inode->i_sb)) *
EXT4_INODES_PER_GROUP(inode->i_sb)) + 1;
- owner[0] = inode->i_uid;
- owner[1] = inode->i_gid;
+ owner[0] = i_uid_read(inode);
+ owner[1] = i_gid_read(inode);
tmp_inode = ext4_new_inode(handle, inode->i_sb->s_root->d_inode,
S_IFREG, NULL, goal, owner);
if (IS_ERR(tmp_inode)) {
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index e1fb1d5de58e..436b4223df66 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1448,6 +1448,8 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
{
struct ext4_sb_info *sbi = EXT4_SB(sb);
const struct mount_opts *m;
+ kuid_t uid;
+ kgid_t gid;
int arg = 0;
#ifdef CONFIG_QUOTA
@@ -1474,10 +1476,20 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
"Ignoring removed %s option", opt);
return 1;
case Opt_resuid:
- sbi->s_resuid = arg;
+ uid = make_kuid(current_user_ns(), arg);
+ if (!uid_valid(uid)) {
+ ext4_msg(sb, KERN_ERR, "Invalid uid value %d", arg);
+ return -1;
+ }
+ sbi->s_resuid = uid;
return 1;
case Opt_resgid:
- sbi->s_resgid = arg;
+ gid = make_kgid(current_user_ns(), arg);
+ if (!gid_valid(gid)) {
+ ext4_msg(sb, KERN_ERR, "Invalid gid value %d", arg);
+ return -1;
+ }
+ sbi->s_resgid = gid;
return 1;
case Opt_abort:
sbi->s_mount_flags |= EXT4_MF_FS_ABORTED;
@@ -1732,12 +1744,14 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
SEQ_OPTS_PRINT("%s", token2str(m->token));
}
- if (nodefs || sbi->s_resuid != EXT4_DEF_RESUID ||
+ if (nodefs || !uid_eq(sbi->s_resuid, make_kuid(&init_user_ns, EXT4_DEF_RESUID)) ||
le16_to_cpu(es->s_def_resuid) != EXT4_DEF_RESUID)
- SEQ_OPTS_PRINT("resuid=%u", sbi->s_resuid);
- if (nodefs || sbi->s_resgid != EXT4_DEF_RESGID ||
+ SEQ_OPTS_PRINT("resuid=%u",
+ from_kuid_munged(&init_user_ns, sbi->s_resuid));
+ if (nodefs || !gid_eq(sbi->s_resgid, make_kgid(&init_user_ns, EXT4_DEF_RESGID)) ||
le16_to_cpu(es->s_def_resgid) != EXT4_DEF_RESGID)
- SEQ_OPTS_PRINT("resgid=%u", sbi->s_resgid);
+ SEQ_OPTS_PRINT("resgid=%u",
+ from_kgid_munged(&init_user_ns, sbi->s_resgid));
def_errors = nodefs ? -1 : le16_to_cpu(es->s_errors);
if (test_opt(sb, ERRORS_RO) && def_errors != EXT4_ERRORS_RO)
SEQ_OPTS_PUTS("errors=remount-ro");
@@ -2980,8 +2994,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
}
sb->s_fs_info = sbi;
sbi->s_mount_opt = 0;
- sbi->s_resuid = EXT4_DEF_RESUID;
- sbi->s_resgid = EXT4_DEF_RESGID;
+ sbi->s_resuid = make_kuid(&init_user_ns, EXT4_DEF_RESUID);
+ sbi->s_resgid = make_kgid(&init_user_ns, EXT4_DEF_RESGID);
sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS;
sbi->s_sb_block = sb_block;
if (sb->s_bdev->bd_part)
@@ -3060,8 +3074,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
if (def_mount_opts & EXT4_DEFM_DISCARD)
set_opt(sb, DISCARD);
- sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
- sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
+ sbi->s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid));
+ sbi->s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid));
sbi->s_commit_interval = JBD2_DEFAULT_MAX_COMMIT_AGE * HZ;
sbi->s_min_batch_time = EXT4_DEF_MIN_BATCH_TIME;
sbi->s_max_batch_time = EXT4_DEF_MAX_BATCH_TIME;
@@ -4213,8 +4227,8 @@ static int ext4_unfreeze(struct super_block *sb)
struct ext4_mount_options {
unsigned long s_mount_opt;
unsigned long s_mount_opt2;
- uid_t s_resuid;
- gid_t s_resgid;
+ kuid_t s_resuid;
+ kgid_t s_resgid;
unsigned long s_commit_interval;
u32 s_min_batch_time, s_max_batch_time;
#ifdef CONFIG_QUOTA
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 75e7c1f3a080..d078b75572a7 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -532,9 +532,9 @@ static inline int sigio_perm(struct task_struct *p,
rcu_read_lock();
cred = __task_cred(p);
- ret = ((fown->euid == 0 ||
- fown->euid == cred->suid || fown->euid == cred->uid ||
- fown->uid == cred->suid || fown->uid == cred->uid) &&
+ ret = ((uid_eq(fown->euid, GLOBAL_ROOT_UID) ||
+ uid_eq(fown->euid, cred->suid) || uid_eq(fown->euid, cred->uid) ||
+ uid_eq(fown->uid, cred->suid) || uid_eq(fown->uid, cred->uid)) &&
!security_file_send_sigiotask(p, fown, sig));
rcu_read_unlock();
return ret;
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index aa9949e5de26..67fd6beffece 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -543,7 +543,6 @@ struct gfs2_sb_host {
struct lm_lockstruct {
int ls_jid;
unsigned int ls_first;
- unsigned int ls_nodir;
const struct lm_lockops *ls_ops;
dlm_lockspace_t *ls_dlm;
diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c
index 5f5e70e047dc..4a38db739ca0 100644
--- a/fs/gfs2/lock_dlm.c
+++ b/fs/gfs2/lock_dlm.c
@@ -1209,8 +1209,6 @@ static int gdlm_mount(struct gfs2_sbd *sdp, const char *table)
fsname++;
flags = DLM_LSFL_FS | DLM_LSFL_NEWEXCL;
- if (ls->ls_nodir)
- flags |= DLM_LSFL_NODIR;
/*
* create/join lockspace
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index c5871ae40561..b8c250fc4922 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -993,6 +993,7 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent)
ls->ls_jid = option;
break;
case Opt_id:
+ case Opt_nodir:
/* Obsolete, but left for backward compat purposes */
break;
case Opt_first:
@@ -1001,12 +1002,6 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent)
goto hostdata_error;
ls->ls_first = option;
break;
- case Opt_nodir:
- ret = match_int(&tmp[0], &option);
- if (ret || (option != 0 && option != 1))
- goto hostdata_error;
- ls->ls_nodir = option;
- break;
case Opt_err:
default:
hostdata_error:
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c
index d33172c291ba..9c2592b1d5ff 100644
--- a/fs/gfs2/sys.c
+++ b/fs/gfs2/sys.c
@@ -368,10 +368,7 @@ int gfs2_recover_set(struct gfs2_sbd *sdp, unsigned jid)
struct gfs2_jdesc *jd;
int rv;
- rv = -ESHUTDOWN;
spin_lock(&sdp->sd_jindex_spin);
- if (test_bit(SDF_NORECOVERY, &sdp->sd_flags))
- goto out;
rv = -EBUSY;
if (sdp->sd_jdesc->jd_jid == jid)
goto out;
@@ -396,8 +393,13 @@ static ssize_t recover_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
if (rv != 1)
return -EINVAL;
- rv = gfs2_recover_set(sdp, jid);
+ if (test_bit(SDF_NORECOVERY, &sdp->sd_flags)) {
+ rv = -ESHUTDOWN;
+ goto out;
+ }
+ rv = gfs2_recover_set(sdp, jid);
+out:
return rv ? rv : len;
}
diff --git a/fs/inode.c b/fs/inode.c
index 9f4f5fecc096..da93f7d160d4 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -135,8 +135,8 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
inode->i_fop = &empty_fops;
inode->__i_nlink = 1;
inode->i_opflags = 0;
- inode->i_uid = 0;
- inode->i_gid = 0;
+ i_uid_write(inode, 0);
+ i_gid_write(inode, 0);
atomic_set(&inode->i_writecount, 0);
inode->i_size = 0;
inode->i_blocks = 0;
@@ -1647,6 +1647,7 @@ void __init inode_init_early(void)
HASH_EARLY,
&i_hash_shift,
&i_hash_mask,
+ 0,
0);
for (loop = 0; loop < (1U << i_hash_shift); loop++)
@@ -1677,6 +1678,7 @@ void __init inode_init(void)
0,
&i_hash_shift,
&i_hash_mask,
+ 0,
0);
for (loop = 0; loop < (1U << i_hash_shift); loop++)
@@ -1732,11 +1734,9 @@ EXPORT_SYMBOL(inode_init_owner);
*/
bool inode_owner_or_capable(const struct inode *inode)
{
- struct user_namespace *ns = inode_userns(inode);
-
- if (current_user_ns() == ns && current_fsuid() == inode->i_uid)
+ if (uid_eq(current_fsuid(), inode->i_uid))
return true;
- if (ns_capable(ns, CAP_FOWNER))
+ if (inode_capable(inode, CAP_FOWNER))
return true;
return false;
}
diff --git a/fs/ioprio.c b/fs/ioprio.c
index 0f1b9515213b..5e6dbe8958fc 100644
--- a/fs/ioprio.c
+++ b/fs/ioprio.c
@@ -37,8 +37,8 @@ int set_task_ioprio(struct task_struct *task, int ioprio)
rcu_read_lock();
tcred = __task_cred(task);
- if (tcred->uid != cred->euid &&
- tcred->uid != cred->uid && !capable(CAP_SYS_NICE)) {
+ if (!uid_eq(tcred->uid, cred->euid) &&
+ !uid_eq(tcred->uid, cred->uid) && !capable(CAP_SYS_NICE)) {
rcu_read_unlock();
return -EPERM;
}
@@ -65,6 +65,7 @@ SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio)
struct task_struct *p, *g;
struct user_struct *user;
struct pid *pgrp;
+ kuid_t uid;
int ret;
switch (class) {
@@ -110,16 +111,19 @@ SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio)
} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
break;
case IOPRIO_WHO_USER:
+ uid = make_kuid(current_user_ns(), who);
+ if (!uid_valid(uid))
+ break;
if (!who)
user = current_user();
else
- user = find_user(who);
+ user = find_user(uid);
if (!user)
break;
do_each_thread(g, p) {
- if (__task_cred(p)->uid != who)
+ if (!uid_eq(task_uid(p), uid))
continue;
ret = set_task_ioprio(p, ioprio);
if (ret)
@@ -174,6 +178,7 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who)
struct task_struct *g, *p;
struct user_struct *user;
struct pid *pgrp;
+ kuid_t uid;
int ret = -ESRCH;
int tmpio;
@@ -203,16 +208,17 @@ SYSCALL_DEFINE2(ioprio_get, int, which, int, who)
} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
break;
case IOPRIO_WHO_USER:
+ uid = make_kuid(current_user_ns(), who);
if (!who)
user = current_user();
else
- user = find_user(who);
+ user = find_user(uid);
if (!user)
break;
do_each_thread(g, p) {
- if (__task_cred(p)->uid != user->uid)
+ if (!uid_eq(task_uid(p), user->uid))
continue;
tmpio = get_task_ioprio(p);
if (tmpio < 0)
diff --git a/fs/locks.c b/fs/locks.c
index 0d68f1f81799..4f441e46cef4 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1446,7 +1446,7 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
struct inode *inode = dentry->d_inode;
int error;
- if ((current_fsuid() != inode->i_uid) && !capable(CAP_LEASE))
+ if ((!uid_eq(current_fsuid(), inode->i_uid)) && !capable(CAP_LEASE))
return -EACCES;
if (!S_ISREG(inode->i_mode))
return -EINVAL;
diff --git a/fs/namei.c b/fs/namei.c
index 8d2ba420e42f..93ff12b1a1de 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -219,10 +219,7 @@ static int acl_permission_check(struct inode *inode, int mask)
{
unsigned int mode = inode->i_mode;
- if (current_user_ns() != inode_userns(inode))
- goto other_perms;
-
- if (likely(current_fsuid() == inode->i_uid))
+ if (likely(uid_eq(current_fsuid(), inode->i_uid)))
mode >>= 6;
else {
if (IS_POSIXACL(inode) && (mode & S_IRWXG)) {
@@ -235,7 +232,6 @@ static int acl_permission_check(struct inode *inode, int mask)
mode >>= 3;
}
-other_perms:
/*
* If the DACs are ok we don't need any capability check.
*/
@@ -271,10 +267,10 @@ int generic_permission(struct inode *inode, int mask)
if (S_ISDIR(inode->i_mode)) {
/* DACs are overridable for directories */
- if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE))
+ if (inode_capable(inode, CAP_DAC_OVERRIDE))
return 0;
if (!(mask & MAY_WRITE))
- if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH))
+ if (inode_capable(inode, CAP_DAC_READ_SEARCH))
return 0;
return -EACCES;
}
@@ -284,7 +280,7 @@ int generic_permission(struct inode *inode, int mask)
* at least one exec bit set.
*/
if (!(mask & MAY_EXEC) || (inode->i_mode & S_IXUGO))
- if (ns_capable(inode_userns(inode), CAP_DAC_OVERRIDE))
+ if (inode_capable(inode, CAP_DAC_OVERRIDE))
return 0;
/*
@@ -292,7 +288,7 @@ int generic_permission(struct inode *inode, int mask)
*/
mask &= MAY_READ | MAY_WRITE | MAY_EXEC;
if (mask == MAY_READ)
- if (ns_capable(inode_userns(inode), CAP_DAC_READ_SEARCH))
+ if (inode_capable(inode, CAP_DAC_READ_SEARCH))
return 0;
return -EACCES;
@@ -1935,19 +1931,15 @@ static int user_path_parent(int dfd, const char __user *path,
*/
static inline int check_sticky(struct inode *dir, struct inode *inode)
{
- uid_t fsuid = current_fsuid();
+ kuid_t fsuid = current_fsuid();
if (!(dir->i_mode & S_ISVTX))
return 0;
- if (current_user_ns() != inode_userns(inode))
- goto other_userns;
- if (inode->i_uid == fsuid)
+ if (uid_eq(inode->i_uid, fsuid))
return 0;
- if (dir->i_uid == fsuid)
+ if (uid_eq(dir->i_uid, fsuid))
return 0;
-
-other_userns:
- return !ns_capable(inode_userns(inode), CAP_FOWNER);
+ return !inode_capable(inode, CAP_FOWNER);
}
/*
@@ -2535,8 +2527,7 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
if (error)
return error;
- if ((S_ISCHR(mode) || S_ISBLK(mode)) &&
- !ns_capable(inode_userns(dir), CAP_MKNOD))
+ if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD))
return -EPERM;
if (!dir->i_op->mknod)
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
index 79717a40daba..204438cc914e 100644
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -1,6 +1,7 @@
/* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> */
#include <linux/sched.h>
+#include <linux/user_namespace.h>
#include "nfsd.h"
#include "auth.h"
@@ -56,8 +57,8 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
goto oom;
for (i = 0; i < rqgi->ngroups; i++) {
- if (!GROUP_AT(rqgi, i))
- GROUP_AT(gi, i) = exp->ex_anon_gid;
+ if (gid_eq(GLOBAL_ROOT_GID, GROUP_AT(rqgi, i)))
+ GROUP_AT(gi, i) = make_kgid(&init_user_ns, exp->ex_anon_gid);
else
GROUP_AT(gi, i) = GROUP_AT(rqgi, i);
}
diff --git a/fs/open.c b/fs/open.c
index 5eccdcea2d1b..d54301219d04 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -316,7 +316,8 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
if (!issecure(SECURE_NO_SETUID_FIXUP)) {
/* Clear the capabilities if we switch to a non-root user */
- if (override_cred->uid)
+ kuid_t root_uid = make_kuid(override_cred->user_ns, 0);
+ if (!uid_eq(override_cred->uid, root_uid))
cap_clear(override_cred->cap_effective);
else
override_cred->cap_effective =
@@ -505,15 +506,24 @@ static int chown_common(struct path *path, uid_t user, gid_t group)
struct inode *inode = path->dentry->d_inode;
int error;
struct iattr newattrs;
+ kuid_t uid;
+ kgid_t gid;
+
+ uid = make_kuid(current_user_ns(), user);
+ gid = make_kgid(current_user_ns(), group);
newattrs.ia_valid = ATTR_CTIME;
if (user != (uid_t) -1) {
+ if (!uid_valid(uid))
+ return -EINVAL;
newattrs.ia_valid |= ATTR_UID;
- newattrs.ia_uid = user;
+ newattrs.ia_uid = uid;
}
if (group != (gid_t) -1) {
+ if (!gid_valid(gid))
+ return -EINVAL;
newattrs.ia_valid |= ATTR_GID;
- newattrs.ia_gid = group;
+ newattrs.ia_gid = gid;
}
if (!S_ISDIR(inode->i_mode))
newattrs.ia_valid |=
diff --git a/fs/proc/array.c b/fs/proc/array.c
index f9bd395b3473..dc4c5a7b9ece 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -81,6 +81,7 @@
#include <linux/pid_namespace.h>
#include <linux/ptrace.h>
#include <linux/tracehook.h>
+#include <linux/user_namespace.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
@@ -161,6 +162,7 @@ static inline const char *get_task_state(struct task_struct *tsk)
static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
struct pid *pid, struct task_struct *p)
{
+ struct user_namespace *user_ns = current_user_ns();
struct group_info *group_info;
int g;
struct fdtable *fdt = NULL;
@@ -189,8 +191,14 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
task_tgid_nr_ns(p, ns),
pid_nr_ns(pid, ns),
ppid, tpid,
- cred->uid, cred->euid, cred->suid, cred->fsuid,
- cred->gid, cred->egid, cred->sgid, cred->fsgid);
+ from_kuid_munged(user_ns, cred->uid),
+ from_kuid_munged(user_ns, cred->euid),
+ from_kuid_munged(user_ns, cred->suid),
+ from_kuid_munged(user_ns, cred->fsuid),
+ from_kgid_munged(user_ns, cred->gid),
+ from_kgid_munged(user_ns, cred->egid),
+ from_kgid_munged(user_ns, cred->sgid),
+ from_kgid_munged(user_ns, cred->fsgid));
task_lock(p);
if (p->files)
@@ -205,7 +213,8 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
task_unlock(p);
for (g = 0; g < min(group_info->ngroups, NGROUPS_SMALL); g++)
- seq_printf(m, "%d ", GROUP_AT(group_info, g));
+ seq_printf(m, "%d ",
+ from_kgid_munged(user_ns, GROUP_AT(group_info, g)));
put_cred(cred);
seq_putc(m, '\n');
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 57b8159f26f3..d2d3108a611c 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -81,6 +81,7 @@
#include <linux/oom.h>
#include <linux/elf.h>
#include <linux/pid_namespace.h>
+#include <linux/user_namespace.h>
#include <linux/fs_struct.h>
#include <linux/slab.h>
#include <linux/flex_array.h>
@@ -1561,8 +1562,8 @@ int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
generic_fillattr(inode, stat);
rcu_read_lock();
- stat->uid = 0;
- stat->gid = 0;
+ stat->uid = GLOBAL_ROOT_UID;
+ stat->gid = GLOBAL_ROOT_GID;
task = pid_task(proc_pid(inode), PIDTYPE_PID);
if (task) {
if (!has_pid_permissions(pid, task, 2)) {
@@ -1622,8 +1623,8 @@ int pid_revalidate(struct dentry *dentry, struct nameidata *nd)
inode->i_gid = cred->egid;
rcu_read_unlock();
} else {
- inode->i_uid = 0;
- inode->i_gid = 0;
+ inode->i_uid = GLOBAL_ROOT_UID;
+ inode->i_gid = GLOBAL_ROOT_GID;
}
inode->i_mode &= ~(S_ISUID | S_ISGID);
security_task_to_inode(task, inode);
@@ -1815,8 +1816,8 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
inode->i_gid = cred->egid;
rcu_read_unlock();
} else {
- inode->i_uid = 0;
- inode->i_gid = 0;
+ inode->i_uid = GLOBAL_ROOT_UID;
+ inode->i_gid = GLOBAL_ROOT_GID;
}
i_mode = S_IFLNK;
@@ -2045,8 +2046,8 @@ static int map_files_d_revalidate(struct dentry *dentry, struct nameidata *nd)
inode->i_gid = cred->egid;
rcu_read_unlock();
} else {
- inode->i_uid = 0;
- inode->i_gid = 0;
+ inode->i_uid = GLOBAL_ROOT_UID;
+ inode->i_gid = GLOBAL_ROOT_GID;
}
security_task_to_inode(task, inode);
status = 1;
@@ -2924,6 +2925,74 @@ static int proc_tgid_io_accounting(struct task_struct *task, char *buffer)
}
#endif /* CONFIG_TASK_IO_ACCOUNTING */
+#ifdef CONFIG_USER_NS
+static int proc_id_map_open(struct inode *inode, struct file *file,
+ struct seq_operations *seq_ops)
+{
+ struct user_namespace *ns = NULL;
+ struct task_struct *task;
+ struct seq_file *seq;
+ int ret = -EINVAL;
+
+ task = get_proc_task(inode);
+ if (task) {
+ rcu_read_lock();
+ ns = get_user_ns(task_cred_xxx(task, user_ns));
+ rcu_read_unlock();
+ put_task_struct(task);
+ }
+ if (!ns)
+ goto err;
+
+ ret = seq_open(file, seq_ops);
+ if (ret)
+ goto err_put_ns;
+
+ seq = file->private_data;
+ seq->private = ns;
+
+ return 0;
+err_put_ns:
+ put_user_ns(ns);
+err:
+ return ret;
+}
+
+static int proc_id_map_release(struct inode *inode, struct file *file)
+{
+ struct seq_file *seq = file->private_data;
+ struct user_namespace *ns = seq->private;
+ put_user_ns(ns);
+ return seq_release(inode, file);
+}
+
+static int proc_uid_map_open(struct inode *inode, struct file *file)
+{
+ return proc_id_map_open(inode, file, &proc_uid_seq_operations);
+}
+
+static int proc_gid_map_open(struct inode *inode, struct file *file)
+{
+ return proc_id_map_open(inode, file, &proc_gid_seq_operations);
+}
+
+static const struct file_operations proc_uid_map_operations = {
+ .open = proc_uid_map_open,
+ .write = proc_uid_map_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = proc_id_map_release,
+};
+
+static const struct file_operations proc_gid_map_operations = {
+ .open = proc_gid_map_open,
+ .write = proc_gid_map_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = proc_id_map_release,
+};
+#endif /* CONFIG_USER_NS */
+
static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns,
struct pid *pid, struct task_struct *task)
{
@@ -3026,6 +3095,10 @@ static const struct pid_entry tgid_base_stuff[] = {
#ifdef CONFIG_HARDWALL
INF("hardwall", S_IRUGO, proc_pid_hardwall),
#endif
+#ifdef CONFIG_USER_NS
+ REG("uid_map", S_IRUGO|S_IWUSR, proc_uid_map_operations),
+ REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations),
+#endif
};
static int proc_tgid_base_readdir(struct file * filp,
@@ -3381,6 +3454,10 @@ static const struct pid_entry tid_base_stuff[] = {
#ifdef CONFIG_HARDWALL
INF("hardwall", S_IRUGO, proc_pid_hardwall),
#endif
+#ifdef CONFIG_USER_NS
+ REG("uid_map", S_IRUGO|S_IWUSR, proc_uid_map_operations),
+ REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations),
+#endif
};
static int proc_tid_base_readdir(struct file * filp,
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 205c92280838..554ecc54799f 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -108,8 +108,8 @@ static int proc_show_options(struct seq_file *seq, struct dentry *root)
struct super_block *sb = root->d_sb;
struct pid_namespace *pid = sb->s_fs_info;
- if (pid->pid_gid)
- seq_printf(seq, ",gid=%lu", (unsigned long)pid->pid_gid);
+ if (!gid_eq(pid->pid_gid, GLOBAL_ROOT_GID))
+ seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, pid->pid_gid));
if (pid->hide_pid != 0)
seq_printf(seq, ",hidepid=%u", pid->hide_pid);
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 21d836f40292..3476bca8f7af 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -371,9 +371,9 @@ void register_sysctl_root(struct ctl_table_root *root)
static int test_perm(int mode, int op)
{
- if (!current_euid())
+ if (uid_eq(current_euid(), GLOBAL_ROOT_UID))
mode >>= 6;
- else if (in_egroup_p(0))
+ else if (in_egroup_p(GLOBAL_ROOT_GID))
mode >>= 3;
if ((op & ~mode & (MAY_READ|MAY_WRITE|MAY_EXEC)) == 0)
return 0;
diff --git a/fs/proc/root.c b/fs/proc/root.c
index eed44bfc85db..7c30fce037c0 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -67,7 +67,7 @@ static int proc_parse_options(char *options, struct pid_namespace *pid)
case Opt_gid:
if (match_int(&args[0], &option))
return 0;
- pid->pid_gid = option;
+ pid->pid_gid = make_kgid(current_user_ns(), option);
break;
case Opt_hidepid:
if (match_int(&args[0], &option))
diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig
index 8007ae7c0d8c..23ade2680a4a 100644
--- a/fs/pstore/Kconfig
+++ b/fs/pstore/Kconfig
@@ -11,3 +11,20 @@ config PSTORE
(e.g. ACPI_APEI on X86) which will select this for you.
If you don't have a platform persistent store driver,
say N.
+
+config PSTORE_RAM
+ tristate "Log panic/oops to a RAM buffer"
+ depends on PSTORE
+ depends on HAS_IOMEM
+ depends on HAVE_MEMBLOCK
+ select REED_SOLOMON
+ select REED_SOLOMON_ENC8
+ select REED_SOLOMON_DEC8
+ help
+ This enables panic and oops messages to be logged to a circular
+ buffer in RAM where it can be read back at some later point.
+
+ Note that for historical reasons, the module will be named
+ "ramoops.ko".
+
+ For more information, see Documentation/ramoops.txt.
diff --git a/fs/pstore/Makefile b/fs/pstore/Makefile
index 760f4bce7d1d..278a44e0d4e1 100644
--- a/fs/pstore/Makefile
+++ b/fs/pstore/Makefile
@@ -5,3 +5,6 @@
obj-y += pstore.o
pstore-objs += inode.o platform.o
+
+ramoops-objs += ram.o ram_core.o
+obj-$(CONFIG_PSTORE_RAM) += ramoops.o
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
new file mode 100644
index 000000000000..9123cce28c1e
--- /dev/null
+++ b/fs/pstore/ram.c
@@ -0,0 +1,383 @@
+/*
+ * RAM Oops/Panic logger
+ *
+ * Copyright (C) 2010 Marco Stornelli <marco.stornelli@gmail.com>
+ * Copyright (C) 2011 Kees Cook <keescook@chromium.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/pstore.h>
+#include <linux/time.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/pstore_ram.h>
+
+#define RAMOOPS_KERNMSG_HDR "===="
+#define MIN_MEM_SIZE 4096UL
+
+static ulong record_size = MIN_MEM_SIZE;
+module_param(record_size, ulong, 0400);
+MODULE_PARM_DESC(record_size,
+ "size of each dump done on oops/panic");
+
+static ulong mem_address;
+module_param(mem_address, ulong, 0400);
+MODULE_PARM_DESC(mem_address,
+ "start of reserved RAM used to store oops/panic logs");
+
+static ulong mem_size;
+module_param(mem_size, ulong, 0400);
+MODULE_PARM_DESC(mem_size,
+ "size of reserved RAM used to store oops/panic logs");
+
+static int dump_oops = 1;
+module_param(dump_oops, int, 0600);
+MODULE_PARM_DESC(dump_oops,
+ "set to 1 to dump oopses, 0 to only dump panics (default 1)");
+
+static int ramoops_ecc;
+module_param_named(ecc, ramoops_ecc, int, 0600);
+MODULE_PARM_DESC(ramoops_ecc,
+ "set to 1 to enable ECC support");
+
+struct ramoops_context {
+ struct persistent_ram_zone **przs;
+ phys_addr_t phys_addr;
+ unsigned long size;
+ size_t record_size;
+ int dump_oops;
+ bool ecc;
+ unsigned int count;
+ unsigned int max_count;
+ unsigned int read_count;
+ struct pstore_info pstore;
+};
+
+static struct platform_device *dummy;
+static struct ramoops_platform_data *dummy_data;
+
+static int ramoops_pstore_open(struct pstore_info *psi)
+{
+ struct ramoops_context *cxt = psi->data;
+
+ cxt->read_count = 0;
+ return 0;
+}
+
+static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
+ struct timespec *time,
+ char **buf,
+ struct pstore_info *psi)
+{
+ ssize_t size;
+ struct ramoops_context *cxt = psi->data;
+ struct persistent_ram_zone *prz;
+
+ if (cxt->read_count >= cxt->max_count)
+ return -EINVAL;
+
+ *id = cxt->read_count++;
+ prz = cxt->przs[*id];
+
+ /* Only supports dmesg output so far. */
+ *type = PSTORE_TYPE_DMESG;
+ /* TODO(kees): Bogus time for the moment. */
+ time->tv_sec = 0;
+ time->tv_nsec = 0;
+
+ size = persistent_ram_old_size(prz);
+ *buf = kmalloc(size, GFP_KERNEL);
+ if (*buf == NULL)
+ return -ENOMEM;
+ memcpy(*buf, persistent_ram_old(prz), size);
+
+ return size;
+}
+
+static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz)
+{
+ char *hdr;
+ struct timeval timestamp;
+ size_t len;
+
+ do_gettimeofday(&timestamp);
+ hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR "%lu.%lu\n",
+ (long)timestamp.tv_sec, (long)timestamp.tv_usec);
+ WARN_ON_ONCE(!hdr);
+ len = hdr ? strlen(hdr) : 0;
+ persistent_ram_write(prz, hdr, len);
+ kfree(hdr);
+
+ return len;
+}
+
+static int ramoops_pstore_write(enum pstore_type_id type,
+ enum kmsg_dump_reason reason,
+ u64 *id,
+ unsigned int part,
+ size_t size, struct pstore_info *psi)
+{
+ struct ramoops_context *cxt = psi->data;
+ struct persistent_ram_zone *prz = cxt->przs[cxt->count];
+ size_t hlen;
+
+ /* Currently ramoops is designed to only store dmesg dumps. */
+ if (type != PSTORE_TYPE_DMESG)
+ return -EINVAL;
+
+ /* Out of the various dmesg dump types, ramoops is currently designed
+ * to only store crash logs, rather than storing general kernel logs.
+ */
+ if (reason != KMSG_DUMP_OOPS &&
+ reason != KMSG_DUMP_PANIC)
+ return -EINVAL;
+
+ /* Skip Oopes when configured to do so. */
+ if (reason == KMSG_DUMP_OOPS && !cxt->dump_oops)
+ return -EINVAL;
+
+ /* Explicitly only take the first part of any new crash.
+ * If our buffer is larger than kmsg_bytes, this can never happen,
+ * and if our buffer is smaller than kmsg_bytes, we don't want the
+ * report split across multiple records.
+ */
+ if (part != 1)
+ return -ENOSPC;
+
+ hlen = ramoops_write_kmsg_hdr(prz);
+ if (size + hlen > prz->buffer_size)
+ size = prz->buffer_size - hlen;
+ persistent_ram_write(prz, cxt->pstore.buf, size);
+
+ cxt->count = (cxt->count + 1) % cxt->max_count;
+
+ return 0;
+}
+
+static int ramoops_pstore_erase(enum pstore_type_id type, u64 id,
+ struct pstore_info *psi)
+{
+ struct ramoops_context *cxt = psi->data;
+
+ if (id >= cxt->max_count)
+ return -EINVAL;
+
+ persistent_ram_free_old(cxt->przs[id]);
+
+ return 0;
+}
+
+static struct ramoops_context oops_cxt = {
+ .pstore = {
+ .owner = THIS_MODULE,
+ .name = "ramoops",
+ .open = ramoops_pstore_open,
+ .read = ramoops_pstore_read,
+ .write = ramoops_pstore_write,
+ .erase = ramoops_pstore_erase,
+ },
+};
+
+static int __init ramoops_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct ramoops_platform_data *pdata = pdev->dev.platform_data;
+ struct ramoops_context *cxt = &oops_cxt;
+ int err = -EINVAL;
+ int i;
+
+ /* Only a single ramoops area allowed at a time, so fail extra
+ * probes.
+ */
+ if (cxt->max_count)
+ goto fail_out;
+
+ if (!pdata->mem_size || !pdata->record_size) {
+ pr_err("The memory size and the record size must be "
+ "non-zero\n");
+ goto fail_out;
+ }
+
+ pdata->mem_size = rounddown_pow_of_two(pdata->mem_size);
+ pdata->record_size = rounddown_pow_of_two(pdata->record_size);
+
+ /* Check for the minimum memory size */
+ if (pdata->mem_size < MIN_MEM_SIZE &&
+ pdata->record_size < MIN_MEM_SIZE) {
+ pr_err("memory size too small, minimum is %lu\n",
+ MIN_MEM_SIZE);
+ goto fail_out;
+ }
+
+ if (pdata->mem_size < pdata->record_size) {
+ pr_err("The memory size must be larger than the "
+ "records size\n");
+ goto fail_out;
+ }
+
+ cxt->max_count = pdata->mem_size / pdata->record_size;
+ cxt->count = 0;
+ cxt->size = pdata->mem_size;
+ cxt->phys_addr = pdata->mem_address;
+ cxt->record_size = pdata->record_size;
+ cxt->dump_oops = pdata->dump_oops;
+ cxt->ecc = pdata->ecc;
+
+ cxt->przs = kzalloc(sizeof(*cxt->przs) * cxt->max_count, GFP_KERNEL);
+ if (!cxt->przs) {
+ err = -ENOMEM;
+ dev_err(dev, "failed to initialize a prz array\n");
+ goto fail_out;
+ }
+
+ for (i = 0; i < cxt->max_count; i++) {
+ size_t sz = cxt->record_size;
+ phys_addr_t start = cxt->phys_addr + sz * i;
+
+ cxt->przs[i] = persistent_ram_new(start, sz, cxt->ecc);
+ if (IS_ERR(cxt->przs[i])) {
+ err = PTR_ERR(cxt->przs[i]);
+ dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n",
+ sz, (unsigned long long)start, err);
+ goto fail_przs;
+ }
+ }
+
+ cxt->pstore.data = cxt;
+ cxt->pstore.bufsize = cxt->przs[0]->buffer_size;
+ cxt->pstore.buf = kmalloc(cxt->pstore.bufsize, GFP_KERNEL);
+ spin_lock_init(&cxt->pstore.buf_lock);
+ if (!cxt->pstore.buf) {
+ pr_err("cannot allocate pstore buffer\n");
+ goto fail_clear;
+ }
+
+ err = pstore_register(&cxt->pstore);
+ if (err) {
+ pr_err("registering with pstore failed\n");
+ goto fail_buf;
+ }
+
+ /*
+ * Update the module parameter variables as well so they are visible
+ * through /sys/module/ramoops/parameters/
+ */
+ mem_size = pdata->mem_size;
+ mem_address = pdata->mem_address;
+ record_size = pdata->record_size;
+ dump_oops = pdata->dump_oops;
+
+ pr_info("attached 0x%lx@0x%llx (%ux0x%zx), ecc: %s\n",
+ cxt->size, (unsigned long long)cxt->phys_addr,
+ cxt->max_count, cxt->record_size,
+ ramoops_ecc ? "on" : "off");
+
+ return 0;
+
+fail_buf:
+ kfree(cxt->pstore.buf);
+fail_clear:
+ cxt->pstore.bufsize = 0;
+ cxt->max_count = 0;
+fail_przs:
+ for (i = 0; cxt->przs[i]; i++)
+ persistent_ram_free(cxt->przs[i]);
+ kfree(cxt->przs);
+fail_out:
+ return err;
+}
+
+static int __exit ramoops_remove(struct platform_device *pdev)
+{
+#if 0
+ /* TODO(kees): We cannot unload ramoops since pstore doesn't support
+ * unregistering yet.
+ */
+ struct ramoops_context *cxt = &oops_cxt;
+
+ iounmap(cxt->virt_addr);
+ release_mem_region(cxt->phys_addr, cxt->size);
+ cxt->max_count = 0;
+
+ /* TODO(kees): When pstore supports unregistering, call it here. */
+ kfree(cxt->pstore.buf);
+ cxt->pstore.bufsize = 0;
+
+ return 0;
+#endif
+ return -EBUSY;
+}
+
+static struct platform_driver ramoops_driver = {
+ .remove = __exit_p(ramoops_remove),
+ .driver = {
+ .name = "ramoops",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ramoops_init(void)
+{
+ int ret;
+ ret = platform_driver_probe(&ramoops_driver, ramoops_probe);
+ if (ret == -ENODEV) {
+ /*
+ * If we didn't find a platform device, we use module parameters
+ * building platform data on the fly.
+ */
+ pr_info("platform device not found, using module parameters\n");
+ dummy_data = kzalloc(sizeof(struct ramoops_platform_data),
+ GFP_KERNEL);
+ if (!dummy_data)
+ return -ENOMEM;
+ dummy_data->mem_size = mem_size;
+ dummy_data->mem_address = mem_address;
+ dummy_data->record_size = record_size;
+ dummy_data->dump_oops = dump_oops;
+ dummy_data->ecc = ramoops_ecc;
+ dummy = platform_create_bundle(&ramoops_driver, ramoops_probe,
+ NULL, 0, dummy_data,
+ sizeof(struct ramoops_platform_data));
+
+ if (IS_ERR(dummy))
+ ret = PTR_ERR(dummy);
+ else
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static void __exit ramoops_exit(void)
+{
+ platform_driver_unregister(&ramoops_driver);
+ kfree(dummy_data);
+}
+
+module_init(ramoops_init);
+module_exit(ramoops_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marco Stornelli <marco.stornelli@gmail.com>");
+MODULE_DESCRIPTION("RAM Oops/Panic logger/driver");
diff --git a/drivers/staging/android/persistent_ram.c b/fs/pstore/ram_core.c
index 8d8c1e33e0ff..31f8d184f3a0 100644
--- a/drivers/staging/android/persistent_ram.c
+++ b/fs/pstore/ram_core.c
@@ -23,7 +23,8 @@
#include <linux/rslib.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
-#include "persistent_ram.h"
+#include <linux/pstore_ram.h>
+#include <asm/page.h>
struct persistent_ram_buffer {
uint32_t sig;
@@ -79,23 +80,6 @@ static inline void buffer_size_add(struct persistent_ram_zone *prz, size_t a)
} while (atomic_cmpxchg(&prz->buffer->size, old, new) != old);
}
-/* increase the size counter, retuning an error if it hits the max size */
-static inline ssize_t buffer_size_add_clamp(struct persistent_ram_zone *prz,
- size_t a)
-{
- size_t old;
- size_t new;
-
- do {
- old = atomic_read(&prz->buffer->size);
- new = old + a;
- if (new > prz->buffer_size)
- return -ENOMEM;
- } while (atomic_cmpxchg(&prz->buffer->size, old, new) != old);
-
- return 0;
-}
-
static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz,
uint8_t *data, size_t len, uint8_t *ecc)
{
@@ -300,7 +284,7 @@ int notrace persistent_ram_write(struct persistent_ram_zone *prz,
c = prz->buffer_size;
}
- buffer_size_add_clamp(prz, c);
+ buffer_size_add(prz, c);
start = buffer_start_add(prz, c);
@@ -335,14 +319,14 @@ void persistent_ram_free_old(struct persistent_ram_zone *prz)
prz->old_log_size = 0;
}
-static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
- struct persistent_ram_zone *prz)
+static void *persistent_ram_vmap(phys_addr_t start, size_t size)
{
struct page **pages;
phys_addr_t page_start;
unsigned int page_count;
pgprot_t prot;
unsigned int i;
+ void *vaddr;
page_start = start - offset_in_page(start);
page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE);
@@ -353,17 +337,44 @@ static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
if (!pages) {
pr_err("%s: Failed to allocate array for %u pages\n", __func__,
page_count);
- return -ENOMEM;
+ return NULL;
}
for (i = 0; i < page_count; i++) {
phys_addr_t addr = page_start + i * PAGE_SIZE;
pages[i] = pfn_to_page(addr >> PAGE_SHIFT);
}
- prz->vaddr = vmap(pages, page_count, VM_MAP, prot);
+ vaddr = vmap(pages, page_count, VM_MAP, prot);
kfree(pages);
+
+ return vaddr;
+}
+
+static void *persistent_ram_iomap(phys_addr_t start, size_t size)
+{
+ if (!request_mem_region(start, size, "persistent_ram")) {
+ pr_err("request mem region (0x%llx@0x%llx) failed\n",
+ (unsigned long long)size, (unsigned long long)start);
+ return NULL;
+ }
+
+ return ioremap(start, size);
+}
+
+static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
+ struct persistent_ram_zone *prz)
+{
+ prz->paddr = start;
+ prz->size = size;
+
+ if (pfn_valid(start >> PAGE_SHIFT))
+ prz->vaddr = persistent_ram_vmap(start, size);
+ else
+ prz->vaddr = persistent_ram_iomap(start, size);
+
if (!prz->vaddr) {
- pr_err("%s: Failed to map %u pages\n", __func__, page_count);
+ pr_err("%s: Failed to map 0x%llx pages at 0x%llx\n", __func__,
+ (unsigned long long)size, (unsigned long long)start);
return -ENOMEM;
}
@@ -373,6 +384,79 @@ static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
return 0;
}
+static int __init persistent_ram_post_init(struct persistent_ram_zone *prz, bool ecc)
+{
+ int ret;
+
+ prz->ecc = ecc;
+
+ ret = persistent_ram_init_ecc(prz, prz->buffer_size);
+ if (ret)
+ return ret;
+
+ if (prz->buffer->sig == PERSISTENT_RAM_SIG) {
+ if (buffer_size(prz) > prz->buffer_size ||
+ buffer_start(prz) > buffer_size(prz))
+ pr_info("persistent_ram: found existing invalid buffer,"
+ " size %zu, start %zu\n",
+ buffer_size(prz), buffer_start(prz));
+ else {
+ pr_info("persistent_ram: found existing buffer,"
+ " size %zu, start %zu\n",
+ buffer_size(prz), buffer_start(prz));
+ persistent_ram_save_old(prz);
+ }
+ } else {
+ pr_info("persistent_ram: no valid data in buffer"
+ " (sig = 0x%08x)\n", prz->buffer->sig);
+ }
+
+ prz->buffer->sig = PERSISTENT_RAM_SIG;
+ atomic_set(&prz->buffer->start, 0);
+ atomic_set(&prz->buffer->size, 0);
+
+ return 0;
+}
+
+void persistent_ram_free(struct persistent_ram_zone *prz)
+{
+ if (pfn_valid(prz->paddr >> PAGE_SHIFT)) {
+ vunmap(prz->vaddr);
+ } else {
+ iounmap(prz->vaddr);
+ release_mem_region(prz->paddr, prz->size);
+ }
+ persistent_ram_free_old(prz);
+ kfree(prz);
+}
+
+struct persistent_ram_zone * __init persistent_ram_new(phys_addr_t start,
+ size_t size,
+ bool ecc)
+{
+ struct persistent_ram_zone *prz;
+ int ret = -ENOMEM;
+
+ prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL);
+ if (!prz) {
+ pr_err("persistent_ram: failed to allocate persistent ram zone\n");
+ goto err;
+ }
+
+ ret = persistent_ram_buffer_map(start, size, prz);
+ if (ret)
+ goto err;
+
+ persistent_ram_post_init(prz, ecc);
+ persistent_ram_update_header_ecc(prz);
+
+ return prz;
+err:
+ kfree(prz);
+ return ERR_PTR(ret);
+}
+
+#ifndef MODULE
static int __init persistent_ram_buffer_init(const char *name,
struct persistent_ram_zone *prz)
{
@@ -407,39 +491,13 @@ struct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc)
goto err;
}
- INIT_LIST_HEAD(&prz->node);
-
ret = persistent_ram_buffer_init(dev_name(dev), prz);
if (ret) {
pr_err("persistent_ram: failed to initialize buffer\n");
goto err;
}
- prz->ecc = ecc;
- ret = persistent_ram_init_ecc(prz, prz->buffer_size);
- if (ret)
- goto err;
-
- if (prz->buffer->sig == PERSISTENT_RAM_SIG) {
- if (buffer_size(prz) > prz->buffer_size ||
- buffer_start(prz) > buffer_size(prz))
- pr_info("persistent_ram: found existing invalid buffer,"
- " size %ld, start %ld\n",
- buffer_size(prz), buffer_start(prz));
- else {
- pr_info("persistent_ram: found existing buffer,"
- " size %ld, start %ld\n",
- buffer_size(prz), buffer_start(prz));
- persistent_ram_save_old(prz);
- }
- } else {
- pr_info("persistent_ram: no valid data in buffer"
- " (sig = 0x%08x)\n", prz->buffer->sig);
- }
-
- prz->buffer->sig = PERSISTENT_RAM_SIG;
- atomic_set(&prz->buffer->start, 0);
- atomic_set(&prz->buffer->size, 0);
+ persistent_ram_post_init(prz, ecc);
return prz;
err:
@@ -471,3 +529,4 @@ int __init persistent_ram_early_init(struct persistent_ram *ram)
return 0;
}
+#endif
diff --git a/fs/stat.c b/fs/stat.c
index 0cef3366a919..b6ff11825fc8 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -138,8 +138,8 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta
tmp.st_nlink = stat->nlink;
if (tmp.st_nlink != stat->nlink)
return -EOVERFLOW;
- SET_UID(tmp.st_uid, stat->uid);
- SET_GID(tmp.st_gid, stat->gid);
+ SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid));
+ SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid));
tmp.st_rdev = old_encode_dev(stat->rdev);
#if BITS_PER_LONG == 32
if (stat->size > MAX_NON_LFS)
@@ -224,8 +224,8 @@ static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf)
tmp.st_nlink = stat->nlink;
if (tmp.st_nlink != stat->nlink)
return -EOVERFLOW;
- SET_UID(tmp.st_uid, stat->uid);
- SET_GID(tmp.st_gid, stat->gid);
+ SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid));
+ SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid));
tmp.st_rdev = encode_dev(stat->rdev);
tmp.st_size = stat->size;
tmp.st_atime = stat->atime.tv_sec;
@@ -355,8 +355,8 @@ static long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf)
#endif
tmp.st_mode = stat->mode;
tmp.st_nlink = stat->nlink;
- tmp.st_uid = stat->uid;
- tmp.st_gid = stat->gid;
+ tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid);
+ tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid);
tmp.st_atime = stat->atime.tv_sec;
tmp.st_atime_nsec = stat->atime.tv_nsec;
tmp.st_mtime = stat->mtime.tv_sec;
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 35a36d39fa2c..e6bb9b2a4cbe 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -132,6 +132,24 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
rb_erase(&sd->s_rb, &sd->s_parent->s_dir.children);
}
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+
+/* Test for attributes that want to ignore lockdep for read-locking */
+static bool ignore_lockdep(struct sysfs_dirent *sd)
+{
+ return sysfs_type(sd) == SYSFS_KOBJ_ATTR &&
+ sd->s_attr.attr->ignore_lockdep;
+}
+
+#else
+
+static inline bool ignore_lockdep(struct sysfs_dirent *sd)
+{
+ return true;
+}
+
+#endif
+
/**
* sysfs_get_active - get an active reference to sysfs_dirent
* @sd: sysfs_dirent to get an active reference to
@@ -155,15 +173,17 @@ struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd)
return NULL;
t = atomic_cmpxchg(&sd->s_active, v, v + 1);
- if (likely(t == v)) {
- rwsem_acquire_read(&sd->dep_map, 0, 1, _RET_IP_);
- return sd;
- }
+ if (likely(t == v))
+ break;
if (t < 0)
return NULL;
cpu_relax();
}
+
+ if (likely(!ignore_lockdep(sd)))
+ rwsem_acquire_read(&sd->dep_map, 0, 1, _RET_IP_);
+ return sd;
}
/**
@@ -180,7 +200,8 @@ void sysfs_put_active(struct sysfs_dirent *sd)
if (unlikely(!sd))
return;
- rwsem_release(&sd->dep_map, 1, _RET_IP_);
+ if (likely(!ignore_lockdep(sd)))
+ rwsem_release(&sd->dep_map, 1, _RET_IP_);
v = atomic_dec_return(&sd->s_active);
if (likely(v != SD_DEACTIVATED_BIAS))
return;
@@ -858,7 +879,6 @@ int sysfs_rename(struct sysfs_dirent *sd,
struct sysfs_dirent *new_parent_sd, const void *new_ns,
const char *new_name)
{
- const char *dup_name = NULL;
int error;
mutex_lock(&sysfs_mutex);
@@ -875,11 +895,11 @@ int sysfs_rename(struct sysfs_dirent *sd,
/* rename sysfs_dirent */
if (strcmp(sd->s_name, new_name) != 0) {
error = -ENOMEM;
- new_name = dup_name = kstrdup(new_name, GFP_KERNEL);
+ new_name = kstrdup(new_name, GFP_KERNEL);
if (!new_name)
goto out;
- dup_name = sd->s_name;
+ kfree(sd->s_name);
sd->s_name = new_name;
}
@@ -895,7 +915,6 @@ int sysfs_rename(struct sysfs_dirent *sd,
error = 0;
out:
mutex_unlock(&sysfs_mutex);
- kfree(dup_name);
return error;
}
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index feb2d69396cf..907c2b3af758 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -62,8 +62,8 @@ static struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd)
/* assign default attributes */
iattrs->ia_mode = sd->s_mode;
- iattrs->ia_uid = 0;
- iattrs->ia_gid = 0;
+ iattrs->ia_uid = GLOBAL_ROOT_UID;
+ iattrs->ia_gid = GLOBAL_ROOT_GID;
iattrs->ia_atime = iattrs->ia_mtime = iattrs->ia_ctime = CURRENT_TIME;
return attrs;
diff --git a/fs/ubifs/Kconfig b/fs/ubifs/Kconfig
index f8b0160da2da..ba66d508006a 100644
--- a/fs/ubifs/Kconfig
+++ b/fs/ubifs/Kconfig
@@ -11,12 +11,6 @@ config UBIFS_FS
help
UBIFS is a file system for flash devices which works on top of UBI.
-config UBIFS_FS_XATTR
- bool "Extended attributes support"
- depends on UBIFS_FS
- help
- This option enables support of extended attributes.
-
config UBIFS_FS_ADVANCED_COMPR
bool "Advanced compression options"
depends on UBIFS_FS
@@ -41,20 +35,3 @@ config UBIFS_FS_ZLIB
default y
help
Zlib compresses better than LZO but it is slower. Say 'Y' if unsure.
-
-# Debugging-related stuff
-config UBIFS_FS_DEBUG
- bool "Enable debugging support"
- depends on UBIFS_FS
- select DEBUG_FS
- select KALLSYMS
- help
- This option enables UBIFS debugging support. It makes sure various
- assertions, self-checks, debugging messages and test modes are compiled
- in (this all is compiled out otherwise). Assertions are light-weight
- and this option also enables them. Self-checks, debugging messages and
- test modes are switched off by default. Thus, it is safe and actually
- recommended to have debugging support enabled, and it should not slow
- down UBIFS. You can then further enable / disable individual debugging
- features using UBIFS module parameters and the corresponding sysfs
- interfaces.
diff --git a/fs/ubifs/Makefile b/fs/ubifs/Makefile
index 80e93c35e496..2c6f0cb816b4 100644
--- a/fs/ubifs/Makefile
+++ b/fs/ubifs/Makefile
@@ -3,7 +3,4 @@ obj-$(CONFIG_UBIFS_FS) += ubifs.o
ubifs-y += shrinker.o journal.o file.o dir.o super.o sb.o io.o
ubifs-y += tnc.o master.o scan.o replay.o log.o commit.o gc.o orphan.o
ubifs-y += budget.o find.o tnc_commit.o compress.o lpt.o lprops.o
-ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o
-
-ubifs-$(CONFIG_UBIFS_FS_DEBUG) += debug.o
-ubifs-$(CONFIG_UBIFS_FS_XATTR) += xattr.o
+ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o xattr.o debug.o
diff --git a/fs/ubifs/commit.c b/fs/ubifs/commit.c
index fb3b5c813a30..8eda717cb99b 100644
--- a/fs/ubifs/commit.c
+++ b/fs/ubifs/commit.c
@@ -496,7 +496,9 @@ int ubifs_gc_should_commit(struct ubifs_info *c)
return ret;
}
-#ifdef CONFIG_UBIFS_FS_DEBUG
+/*
+ * Everything below is related to debugging.
+ */
/**
* struct idx_node - hold index nodes during index tree traversal.
@@ -714,14 +716,14 @@ out:
return 0;
out_dump:
- dbg_err("dumping index node (iip=%d)", i->iip);
- dbg_dump_node(c, idx);
+ ubifs_err("dumping index node (iip=%d)", i->iip);
+ ubifs_dump_node(c, idx);
list_del(&i->list);
kfree(i);
if (!list_empty(&list)) {
i = list_entry(list.prev, struct idx_node, list);
- dbg_err("dumping parent index node");
- dbg_dump_node(c, &i->idx);
+ ubifs_err("dumping parent index node");
+ ubifs_dump_node(c, &i->idx);
}
out_free:
while (!list_empty(&list)) {
@@ -734,5 +736,3 @@ out_free:
err = -EINVAL;
return err;
}
-
-#endif /* CONFIG_UBIFS_FS_DEBUG */
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
index 1934084e2088..685a83756b2b 100644
--- a/fs/ubifs/debug.c
+++ b/fs/ubifs/debug.c
@@ -34,8 +34,6 @@
#include <linux/random.h>
#include "ubifs.h"
-#ifdef CONFIG_UBIFS_FS_DEBUG
-
static DEFINE_SPINLOCK(dbg_lock);
static const char *get_key_fmt(int fmt)
@@ -232,7 +230,7 @@ static void dump_ch(const struct ubifs_ch *ch)
printk(KERN_ERR "\tlen %u\n", le32_to_cpu(ch->len));
}
-void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode)
+void ubifs_dump_inode(struct ubifs_info *c, const struct inode *inode)
{
const struct ubifs_inode *ui = ubifs_inode(inode);
struct qstr nm = { .name = NULL };
@@ -300,7 +298,7 @@ void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode)
kfree(pdent);
}
-void dbg_dump_node(const struct ubifs_info *c, const void *node)
+void ubifs_dump_node(const struct ubifs_info *c, const void *node)
{
int i, n;
union ubifs_key key;
@@ -603,7 +601,7 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node)
spin_unlock(&dbg_lock);
}
-void dbg_dump_budget_req(const struct ubifs_budget_req *req)
+void ubifs_dump_budget_req(const struct ubifs_budget_req *req)
{
spin_lock(&dbg_lock);
printk(KERN_ERR "Budgeting request: new_ino %d, dirtied_ino %d\n",
@@ -620,7 +618,7 @@ void dbg_dump_budget_req(const struct ubifs_budget_req *req)
spin_unlock(&dbg_lock);
}
-void dbg_dump_lstats(const struct ubifs_lp_stats *lst)
+void ubifs_dump_lstats(const struct ubifs_lp_stats *lst)
{
spin_lock(&dbg_lock);
printk(KERN_ERR "(pid %d) Lprops statistics: empty_lebs %d, "
@@ -634,7 +632,7 @@ void dbg_dump_lstats(const struct ubifs_lp_stats *lst)
spin_unlock(&dbg_lock);
}
-void dbg_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi)
+void ubifs_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi)
{
int i;
struct rb_node *rb;
@@ -707,7 +705,7 @@ out_unlock:
spin_unlock(&c->space_lock);
}
-void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
+void ubifs_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
{
int i, spc, dark = 0, dead = 0;
struct rb_node *rb;
@@ -801,7 +799,7 @@ void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
printk(KERN_CONT ")\n");
}
-void dbg_dump_lprops(struct ubifs_info *c)
+void ubifs_dump_lprops(struct ubifs_info *c)
{
int lnum, err;
struct ubifs_lprops lp;
@@ -810,20 +808,20 @@ void dbg_dump_lprops(struct ubifs_info *c)
printk(KERN_ERR "(pid %d) start dumping LEB properties\n",
current->pid);
ubifs_get_lp_stats(c, &lst);
- dbg_dump_lstats(&lst);
+ ubifs_dump_lstats(&lst);
for (lnum = c->main_first; lnum < c->leb_cnt; lnum++) {
err = ubifs_read_one_lp(c, lnum, &lp);
if (err)
ubifs_err("cannot read lprops for LEB %d", lnum);
- dbg_dump_lprop(c, &lp);
+ ubifs_dump_lprop(c, &lp);
}
printk(KERN_ERR "(pid %d) finish dumping LEB properties\n",
current->pid);
}
-void dbg_dump_lpt_info(struct ubifs_info *c)
+void ubifs_dump_lpt_info(struct ubifs_info *c)
{
int i;
@@ -862,8 +860,8 @@ void dbg_dump_lpt_info(struct ubifs_info *c)
spin_unlock(&dbg_lock);
}
-void dbg_dump_sleb(const struct ubifs_info *c,
- const struct ubifs_scan_leb *sleb, int offs)
+void ubifs_dump_sleb(const struct ubifs_info *c,
+ const struct ubifs_scan_leb *sleb, int offs)
{
struct ubifs_scan_node *snod;
@@ -874,11 +872,11 @@ void dbg_dump_sleb(const struct ubifs_info *c,
cond_resched();
printk(KERN_ERR "Dumping node at LEB %d:%d len %d\n", sleb->lnum,
snod->offs, snod->len);
- dbg_dump_node(c, snod->node);
+ ubifs_dump_node(c, snod->node);
}
}
-void dbg_dump_leb(const struct ubifs_info *c, int lnum)
+void ubifs_dump_leb(const struct ubifs_info *c, int lnum)
{
struct ubifs_scan_leb *sleb;
struct ubifs_scan_node *snod;
@@ -909,7 +907,7 @@ void dbg_dump_leb(const struct ubifs_info *c, int lnum)
cond_resched();
printk(KERN_ERR "Dumping node at LEB %d:%d len %d\n", lnum,
snod->offs, snod->len);
- dbg_dump_node(c, snod->node);
+ ubifs_dump_node(c, snod->node);
}
printk(KERN_ERR "(pid %d) finish dumping LEB %d\n",
@@ -921,8 +919,8 @@ out:
return;
}
-void dbg_dump_znode(const struct ubifs_info *c,
- const struct ubifs_znode *znode)
+void ubifs_dump_znode(const struct ubifs_info *c,
+ const struct ubifs_znode *znode)
{
int n;
const struct ubifs_zbranch *zbr;
@@ -965,7 +963,7 @@ void dbg_dump_znode(const struct ubifs_info *c,
spin_unlock(&dbg_lock);
}
-void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat)
+void ubifs_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat)
{
int i;
@@ -981,8 +979,8 @@ void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat)
printk(KERN_ERR "(pid %d) finish dumping heap\n", current->pid);
}
-void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
- struct ubifs_nnode *parent, int iip)
+void ubifs_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
+ struct ubifs_nnode *parent, int iip)
{
int i;
@@ -999,7 +997,7 @@ void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
}
}
-void dbg_dump_tnc(struct ubifs_info *c)
+void ubifs_dump_tnc(struct ubifs_info *c)
{
struct ubifs_znode *znode;
int level;
@@ -1014,7 +1012,7 @@ void dbg_dump_tnc(struct ubifs_info *c)
level = znode->level;
printk(KERN_ERR "== Level %d ==\n", level);
}
- dbg_dump_znode(c, znode);
+ ubifs_dump_znode(c, znode);
znode = ubifs_tnc_levelorder_next(c->zroot.znode, znode);
}
printk(KERN_ERR "(pid %d) finish dumping TNC tree\n", current->pid);
@@ -1023,18 +1021,18 @@ void dbg_dump_tnc(struct ubifs_info *c)
static int dump_znode(struct ubifs_info *c, struct ubifs_znode *znode,
void *priv)
{
- dbg_dump_znode(c, znode);
+ ubifs_dump_znode(c, znode);
return 0;
}
/**
- * dbg_dump_index - dump the on-flash index.
+ * ubifs_dump_index - dump the on-flash index.
* @c: UBIFS file-system description object
*
- * This function dumps whole UBIFS indexing B-tree, unlike 'dbg_dump_tnc()'
+ * This function dumps whole UBIFS indexing B-tree, unlike 'ubifs_dump_tnc()'
* which dumps only in-memory znodes and does not read znodes which from flash.
*/
-void dbg_dump_index(struct ubifs_info *c)
+void ubifs_dump_index(struct ubifs_info *c)
{
dbg_walk_index(c, NULL, dump_znode, NULL);
}
@@ -1120,15 +1118,15 @@ int dbg_check_space_info(struct ubifs_info *c)
out:
ubifs_msg("saved lprops statistics dump");
- dbg_dump_lstats(&d->saved_lst);
+ ubifs_dump_lstats(&d->saved_lst);
ubifs_msg("saved budgeting info dump");
- dbg_dump_budg(c, &d->saved_bi);
+ ubifs_dump_budg(c, &d->saved_bi);
ubifs_msg("saved idx_gc_cnt %d", d->saved_idx_gc_cnt);
ubifs_msg("current lprops statistics dump");
ubifs_get_lp_stats(c, &lst);
- dbg_dump_lstats(&lst);
+ ubifs_dump_lstats(&lst);
ubifs_msg("current budgeting info dump");
- dbg_dump_budg(c, &c->bi);
+ ubifs_dump_budg(c, &c->bi);
dump_stack();
return -EINVAL;
}
@@ -1160,7 +1158,7 @@ int dbg_check_synced_i_size(const struct ubifs_info *c, struct inode *inode)
"is clean", ui->ui_size, ui->synced_i_size);
ubifs_err("i_ino %lu, i_mode %#x, i_size %lld", inode->i_ino,
inode->i_mode, i_size_read(inode));
- dbg_dump_stack();
+ dump_stack();
err = -EINVAL;
}
spin_unlock(&ui->ui_lock);
@@ -1223,14 +1221,14 @@ int dbg_check_dir(struct ubifs_info *c, const struct inode *dir)
"but calculated size is %llu", dir->i_ino,
(unsigned long long)i_size_read(dir),
(unsigned long long)size);
- dbg_dump_inode(c, dir);
+ ubifs_dump_inode(c, dir);
dump_stack();
return -EINVAL;
}
if (dir->i_nlink != nlink) {
ubifs_err("directory inode %lu has nlink %u, but calculated "
"nlink is %u", dir->i_ino, dir->i_nlink, nlink);
- dbg_dump_inode(c, dir);
+ ubifs_dump_inode(c, dir);
dump_stack();
return -EINVAL;
}
@@ -1287,25 +1285,25 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
err = 1;
key_read(c, &dent1->key, &key);
if (keys_cmp(c, &zbr1->key, &key)) {
- dbg_err("1st entry at %d:%d has key %s", zbr1->lnum,
- zbr1->offs, dbg_snprintf_key(c, &key, key_buf,
- DBG_KEY_BUF_LEN));
- dbg_err("but it should have key %s according to tnc",
- dbg_snprintf_key(c, &zbr1->key, key_buf,
- DBG_KEY_BUF_LEN));
- dbg_dump_node(c, dent1);
+ ubifs_err("1st entry at %d:%d has key %s", zbr1->lnum,
+ zbr1->offs, dbg_snprintf_key(c, &key, key_buf,
+ DBG_KEY_BUF_LEN));
+ ubifs_err("but it should have key %s according to tnc",
+ dbg_snprintf_key(c, &zbr1->key, key_buf,
+ DBG_KEY_BUF_LEN));
+ ubifs_dump_node(c, dent1);
goto out_free;
}
key_read(c, &dent2->key, &key);
if (keys_cmp(c, &zbr2->key, &key)) {
- dbg_err("2nd entry at %d:%d has key %s", zbr1->lnum,
- zbr1->offs, dbg_snprintf_key(c, &key, key_buf,
- DBG_KEY_BUF_LEN));
- dbg_err("but it should have key %s according to tnc",
- dbg_snprintf_key(c, &zbr2->key, key_buf,
- DBG_KEY_BUF_LEN));
- dbg_dump_node(c, dent2);
+ ubifs_err("2nd entry at %d:%d has key %s", zbr1->lnum,
+ zbr1->offs, dbg_snprintf_key(c, &key, key_buf,
+ DBG_KEY_BUF_LEN));
+ ubifs_err("but it should have key %s according to tnc",
+ dbg_snprintf_key(c, &zbr2->key, key_buf,
+ DBG_KEY_BUF_LEN));
+ ubifs_dump_node(c, dent2);
goto out_free;
}
@@ -1318,15 +1316,15 @@ static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
goto out_free;
}
if (cmp == 0 && nlen1 == nlen2)
- dbg_err("2 xent/dent nodes with the same name");
+ ubifs_err("2 xent/dent nodes with the same name");
else
- dbg_err("bad order of colliding key %s",
- dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
+ ubifs_err("bad order of colliding key %s",
+ dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
ubifs_msg("first node at %d:%d\n", zbr1->lnum, zbr1->offs);
- dbg_dump_node(c, dent1);
+ ubifs_dump_node(c, dent1);
ubifs_msg("second node at %d:%d\n", zbr2->lnum, zbr2->offs);
- dbg_dump_node(c, dent2);
+ ubifs_dump_node(c, dent2);
out_free:
kfree(dent2);
@@ -1529,10 +1527,10 @@ static int dbg_check_znode(struct ubifs_info *c, struct ubifs_zbranch *zbr)
out:
ubifs_err("failed, error %d", err);
ubifs_msg("dump of the znode");
- dbg_dump_znode(c, znode);
+ ubifs_dump_znode(c, znode);
if (zp) {
ubifs_msg("dump of the parent znode");
- dbg_dump_znode(c, zp);
+ ubifs_dump_znode(c, zp);
}
dump_stack();
return -EINVAL;
@@ -1599,9 +1597,9 @@ int dbg_check_tnc(struct ubifs_info *c, int extra)
return err;
if (err) {
ubifs_msg("first znode");
- dbg_dump_znode(c, prev);
+ ubifs_dump_znode(c, prev);
ubifs_msg("second znode");
- dbg_dump_znode(c, znode);
+ ubifs_dump_znode(c, znode);
return -EINVAL;
}
}
@@ -1690,7 +1688,7 @@ int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb,
if (err) {
ubifs_err("znode checking function returned "
"error %d", err);
- dbg_dump_znode(c, znode);
+ ubifs_dump_znode(c, znode);
goto out_dump;
}
}
@@ -1758,7 +1756,7 @@ out_dump:
else
zbr = &c->zroot;
ubifs_msg("dump of znode at LEB %d:%d", zbr->lnum, zbr->offs);
- dbg_dump_znode(c, znode);
+ ubifs_dump_znode(c, znode);
out_unlock:
mutex_unlock(&c->tnc_mutex);
return err;
@@ -2194,7 +2192,7 @@ out:
out_dump:
ubifs_msg("dump of node at LEB %d:%d", zbr->lnum, zbr->offs);
- dbg_dump_node(c, node);
+ ubifs_dump_node(c, node);
out_free:
kfree(node);
return err;
@@ -2352,7 +2350,7 @@ out_dump:
ubifs_msg("dump of the inode %lu sitting in LEB %d:%d",
(unsigned long)fscki->inum, zbr->lnum, zbr->offs);
- dbg_dump_node(c, ino);
+ ubifs_dump_node(c, ino);
kfree(ino);
return -EINVAL;
}
@@ -2423,12 +2421,12 @@ int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head)
if (sa->type != UBIFS_DATA_NODE) {
ubifs_err("bad node type %d", sa->type);
- dbg_dump_node(c, sa->node);
+ ubifs_dump_node(c, sa->node);
return -EINVAL;
}
if (sb->type != UBIFS_DATA_NODE) {
ubifs_err("bad node type %d", sb->type);
- dbg_dump_node(c, sb->node);
+ ubifs_dump_node(c, sb->node);
return -EINVAL;
}
@@ -2459,8 +2457,8 @@ int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head)
return 0;
error_dump:
- dbg_dump_node(c, sa->node);
- dbg_dump_node(c, sb->node);
+ ubifs_dump_node(c, sa->node);
+ ubifs_dump_node(c, sb->node);
return -EINVAL;
}
@@ -2491,13 +2489,13 @@ int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head)
if (sa->type != UBIFS_INO_NODE && sa->type != UBIFS_DENT_NODE &&
sa->type != UBIFS_XENT_NODE) {
ubifs_err("bad node type %d", sa->type);
- dbg_dump_node(c, sa->node);
+ ubifs_dump_node(c, sa->node);
return -EINVAL;
}
if (sa->type != UBIFS_INO_NODE && sa->type != UBIFS_DENT_NODE &&
sa->type != UBIFS_XENT_NODE) {
ubifs_err("bad node type %d", sb->type);
- dbg_dump_node(c, sb->node);
+ ubifs_dump_node(c, sb->node);
return -EINVAL;
}
@@ -2547,9 +2545,9 @@ int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head)
error_dump:
ubifs_msg("dumping first node");
- dbg_dump_node(c, sa->node);
+ ubifs_dump_node(c, sa->node);
ubifs_msg("dumping second node");
- dbg_dump_node(c, sb->node);
+ ubifs_dump_node(c, sb->node);
return -EINVAL;
return 0;
}
@@ -2678,7 +2676,7 @@ static void cut_data(const void *buf, unsigned int len)
}
int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf,
- int offs, int len, int dtype)
+ int offs, int len)
{
int err, failing;
@@ -2688,7 +2686,7 @@ int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf,
failing = power_cut_emulated(c, lnum, 1);
if (failing)
cut_data(buf, len);
- err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
+ err = ubi_leb_write(c->ubi, lnum, buf, offs, len);
if (err)
return err;
if (failing)
@@ -2697,7 +2695,7 @@ int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf,
}
int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf,
- int len, int dtype)
+ int len)
{
int err;
@@ -2705,7 +2703,7 @@ int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf,
return -EROFS;
if (power_cut_emulated(c, lnum, 1))
return -EROFS;
- err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
+ err = ubi_leb_change(c->ubi, lnum, buf, len);
if (err)
return err;
if (power_cut_emulated(c, lnum, 1))
@@ -2729,7 +2727,7 @@ int dbg_leb_unmap(struct ubifs_info *c, int lnum)
return 0;
}
-int dbg_leb_map(struct ubifs_info *c, int lnum, int dtype)
+int dbg_leb_map(struct ubifs_info *c, int lnum)
{
int err;
@@ -2737,7 +2735,7 @@ int dbg_leb_map(struct ubifs_info *c, int lnum, int dtype)
return -EROFS;
if (power_cut_emulated(c, lnum, 0))
return -EROFS;
- err = ubi_leb_map(c->ubi, lnum, dtype);
+ err = ubi_leb_map(c->ubi, lnum);
if (err)
return err;
if (power_cut_emulated(c, lnum, 0))
@@ -2857,16 +2855,16 @@ static ssize_t dfs_file_write(struct file *file, const char __user *u,
* 'ubifs-debug' file-system instead.
*/
if (file->f_path.dentry == d->dfs_dump_lprops) {
- dbg_dump_lprops(c);
+ ubifs_dump_lprops(c);
return count;
}
if (file->f_path.dentry == d->dfs_dump_budg) {
- dbg_dump_budg(c, &c->bi);
+ ubifs_dump_budg(c, &c->bi);
return count;
}
if (file->f_path.dentry == d->dfs_dump_tnc) {
mutex_lock(&c->tnc_mutex);
- dbg_dump_tnc(c);
+ ubifs_dump_tnc(c);
mutex_unlock(&c->tnc_mutex);
return count;
}
@@ -3189,5 +3187,3 @@ void ubifs_debugging_exit(struct ubifs_info *c)
{
kfree(c->dbg);
}
-
-#endif /* CONFIG_UBIFS_FS_DEBUG */
diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h
index 9f717655df18..486a8e024fb6 100644
--- a/fs/ubifs/debug.h
+++ b/fs/ubifs/debug.h
@@ -29,8 +29,6 @@ typedef int (*dbg_leaf_callback)(struct ubifs_info *c,
typedef int (*dbg_znode_callback)(struct ubifs_info *c,
struct ubifs_znode *znode, void *priv);
-#ifdef CONFIG_UBIFS_FS_DEBUG
-
/*
* The UBIFS debugfs directory name pattern and maximum name length (3 for "ubi"
* + 1 for "_" and plus 2x2 for 2 UBI numbers and 1 for the trailing zero byte.
@@ -149,7 +147,7 @@ struct ubifs_global_debug_info {
if (unlikely(!(expr))) { \
printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \
__func__, __LINE__, current->pid); \
- dbg_dump_stack(); \
+ dump_stack(); \
} \
} while (0)
@@ -161,12 +159,6 @@ struct ubifs_global_debug_info {
} \
} while (0)
-#define dbg_dump_stack() dump_stack()
-
-#define dbg_err(fmt, ...) do { \
- ubifs_err(fmt, ##__VA_ARGS__); \
-} while (0)
-
#define ubifs_dbg_msg(type, fmt, ...) \
pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__)
@@ -257,27 +249,27 @@ const char *dbg_get_key_dump(const struct ubifs_info *c,
const union ubifs_key *key);
const char *dbg_snprintf_key(const struct ubifs_info *c,
const union ubifs_key *key, char *buffer, int len);
-void dbg_dump_inode(struct ubifs_info *c, const struct inode *inode);
-void dbg_dump_node(const struct ubifs_info *c, const void *node);
-void dbg_dump_lpt_node(const struct ubifs_info *c, void *node, int lnum,
- int offs);
-void dbg_dump_budget_req(const struct ubifs_budget_req *req);
-void dbg_dump_lstats(const struct ubifs_lp_stats *lst);
-void dbg_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi);
-void dbg_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp);
-void dbg_dump_lprops(struct ubifs_info *c);
-void dbg_dump_lpt_info(struct ubifs_info *c);
-void dbg_dump_leb(const struct ubifs_info *c, int lnum);
-void dbg_dump_sleb(const struct ubifs_info *c,
- const struct ubifs_scan_leb *sleb, int offs);
-void dbg_dump_znode(const struct ubifs_info *c,
- const struct ubifs_znode *znode);
-void dbg_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat);
-void dbg_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
- struct ubifs_nnode *parent, int iip);
-void dbg_dump_tnc(struct ubifs_info *c);
-void dbg_dump_index(struct ubifs_info *c);
-void dbg_dump_lpt_lebs(const struct ubifs_info *c);
+void ubifs_dump_inode(struct ubifs_info *c, const struct inode *inode);
+void ubifs_dump_node(const struct ubifs_info *c, const void *node);
+void ubifs_dump_budget_req(const struct ubifs_budget_req *req);
+void ubifs_dump_lstats(const struct ubifs_lp_stats *lst);
+void ubifs_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi);
+void ubifs_dump_lprop(const struct ubifs_info *c,
+ const struct ubifs_lprops *lp);
+void ubifs_dump_lprops(struct ubifs_info *c);
+void ubifs_dump_lpt_info(struct ubifs_info *c);
+void ubifs_dump_leb(const struct ubifs_info *c, int lnum);
+void ubifs_dump_sleb(const struct ubifs_info *c,
+ const struct ubifs_scan_leb *sleb, int offs);
+void ubifs_dump_znode(const struct ubifs_info *c,
+ const struct ubifs_znode *znode);
+void ubifs_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap,
+ int cat);
+void ubifs_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
+ struct ubifs_nnode *parent, int iip);
+void ubifs_dump_tnc(struct ubifs_info *c);
+void ubifs_dump_index(struct ubifs_info *c);
+void ubifs_dump_lpt_lebs(const struct ubifs_info *c);
int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb,
dbg_znode_callback znode_cb, void *priv);
@@ -307,11 +299,10 @@ int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head);
int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head);
int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
- int len, int dtype);
-int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
- int dtype);
+ int len);
+int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len);
int dbg_leb_unmap(struct ubifs_info *c, int lnum);
-int dbg_leb_map(struct ubifs_info *c, int lnum, int dtype);
+int dbg_leb_map(struct ubifs_info *c, int lnum);
/* Debugfs-related stuff */
int dbg_debugfs_init(void);
@@ -319,162 +310,4 @@ void dbg_debugfs_exit(void);
int dbg_debugfs_init_fs(struct ubifs_info *c);
void dbg_debugfs_exit_fs(struct ubifs_info *c);
-#else /* !CONFIG_UBIFS_FS_DEBUG */
-
-/* Use "if (0)" to make compiler check arguments even if debugging is off */
-#define ubifs_assert(expr) do { \
- if (0) \
- printk(KERN_CRIT "UBIFS assert failed in %s at %u (pid %d)\n", \
- __func__, __LINE__, current->pid); \
-} while (0)
-
-#define dbg_err(fmt, ...) do { \
- if (0) \
- ubifs_err(fmt, ##__VA_ARGS__); \
-} while (0)
-
-#define DBGKEY(key) ((char *)(key))
-#define DBGKEY1(key) ((char *)(key))
-
-#define ubifs_dbg_msg(fmt, ...) do { \
- if (0) \
- printk(KERN_DEBUG fmt "\n", ##__VA_ARGS__); \
-} while (0)
-
-#define dbg_dump_stack()
-#define ubifs_assert_cmt_locked(c)
-
-#define dbg_msg(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_gen(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_jnl(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_jnlk(key, fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_tnc(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_tnck(key, fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_lp(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_find(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_mnt(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_mntk(key, fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_io(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_cmt(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_budg(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_log(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_gc(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_scan(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-#define dbg_rcvry(fmt, ...) ubifs_dbg_msg(fmt, ##__VA_ARGS__)
-
-static inline int ubifs_debugging_init(struct ubifs_info *c) { return 0; }
-static inline void ubifs_debugging_exit(struct ubifs_info *c) { return; }
-static inline const char *dbg_ntype(int type) { return ""; }
-static inline const char *dbg_cstate(int cmt_state) { return ""; }
-static inline const char *dbg_jhead(int jhead) { return ""; }
-static inline const char *
-dbg_get_key_dump(const struct ubifs_info *c,
- const union ubifs_key *key) { return ""; }
-static inline const char *
-dbg_snprintf_key(const struct ubifs_info *c,
- const union ubifs_key *key, char *buffer,
- int len) { return ""; }
-static inline void dbg_dump_inode(struct ubifs_info *c,
- const struct inode *inode) { return; }
-static inline void dbg_dump_node(const struct ubifs_info *c,
- const void *node) { return; }
-static inline void dbg_dump_lpt_node(const struct ubifs_info *c,
- void *node, int lnum,
- int offs) { return; }
-static inline void
-dbg_dump_budget_req(const struct ubifs_budget_req *req) { return; }
-static inline void
-dbg_dump_lstats(const struct ubifs_lp_stats *lst) { return; }
-static inline void
-dbg_dump_budg(struct ubifs_info *c,
- const struct ubifs_budg_info *bi) { return; }
-static inline void dbg_dump_lprop(const struct ubifs_info *c,
- const struct ubifs_lprops *lp) { return; }
-static inline void dbg_dump_lprops(struct ubifs_info *c) { return; }
-static inline void dbg_dump_lpt_info(struct ubifs_info *c) { return; }
-static inline void dbg_dump_leb(const struct ubifs_info *c,
- int lnum) { return; }
-static inline void
-dbg_dump_sleb(const struct ubifs_info *c,
- const struct ubifs_scan_leb *sleb, int offs) { return; }
-static inline void
-dbg_dump_znode(const struct ubifs_info *c,
- const struct ubifs_znode *znode) { return; }
-static inline void dbg_dump_heap(struct ubifs_info *c,
- struct ubifs_lpt_heap *heap,
- int cat) { return; }
-static inline void dbg_dump_pnode(struct ubifs_info *c,
- struct ubifs_pnode *pnode,
- struct ubifs_nnode *parent,
- int iip) { return; }
-static inline void dbg_dump_tnc(struct ubifs_info *c) { return; }
-static inline void dbg_dump_index(struct ubifs_info *c) { return; }
-static inline void dbg_dump_lpt_lebs(const struct ubifs_info *c) { return; }
-
-static inline int dbg_walk_index(struct ubifs_info *c,
- dbg_leaf_callback leaf_cb,
- dbg_znode_callback znode_cb,
- void *priv) { return 0; }
-static inline void dbg_save_space_info(struct ubifs_info *c) { return; }
-static inline int dbg_check_space_info(struct ubifs_info *c) { return 0; }
-static inline int dbg_check_lprops(struct ubifs_info *c) { return 0; }
-static inline int
-dbg_old_index_check_init(struct ubifs_info *c,
- struct ubifs_zbranch *zroot) { return 0; }
-static inline int
-dbg_check_old_index(struct ubifs_info *c,
- struct ubifs_zbranch *zroot) { return 0; }
-static inline int dbg_check_cats(struct ubifs_info *c) { return 0; }
-static inline int dbg_check_ltab(struct ubifs_info *c) { return 0; }
-static inline int dbg_chk_lpt_free_spc(struct ubifs_info *c) { return 0; }
-static inline int dbg_chk_lpt_sz(struct ubifs_info *c,
- int action, int len) { return 0; }
-static inline int
-dbg_check_synced_i_size(const struct ubifs_info *c,
- struct inode *inode) { return 0; }
-static inline int dbg_check_dir(struct ubifs_info *c,
- const struct inode *dir) { return 0; }
-static inline int dbg_check_tnc(struct ubifs_info *c, int extra) { return 0; }
-static inline int dbg_check_idx_size(struct ubifs_info *c,
- long long idx_size) { return 0; }
-static inline int dbg_check_filesystem(struct ubifs_info *c) { return 0; }
-static inline void dbg_check_heap(struct ubifs_info *c,
- struct ubifs_lpt_heap *heap,
- int cat, int add_pos) { return; }
-static inline int dbg_check_lpt_nodes(struct ubifs_info *c,
- struct ubifs_cnode *cnode, int row, int col) { return 0; }
-static inline int dbg_check_inode_size(struct ubifs_info *c,
- const struct inode *inode,
- loff_t size) { return 0; }
-static inline int
-dbg_check_data_nodes_order(struct ubifs_info *c,
- struct list_head *head) { return 0; }
-static inline int
-dbg_check_nondata_nodes_order(struct ubifs_info *c,
- struct list_head *head) { return 0; }
-
-static inline int dbg_leb_write(struct ubifs_info *c, int lnum,
- const void *buf, int offset,
- int len, int dtype) { return 0; }
-static inline int dbg_leb_change(struct ubifs_info *c, int lnum,
- const void *buf, int len,
- int dtype) { return 0; }
-static inline int dbg_leb_unmap(struct ubifs_info *c, int lnum) { return 0; }
-static inline int dbg_leb_map(struct ubifs_info *c, int lnum,
- int dtype) { return 0; }
-
-static inline int dbg_is_chk_gen(const struct ubifs_info *c) { return 0; }
-static inline int dbg_is_chk_index(const struct ubifs_info *c) { return 0; }
-static inline int dbg_is_chk_orph(const struct ubifs_info *c) { return 0; }
-static inline int dbg_is_chk_lprops(const struct ubifs_info *c) { return 0; }
-static inline int dbg_is_chk_fs(const struct ubifs_info *c) { return 0; }
-static inline int dbg_is_tst_rcvry(const struct ubifs_info *c) { return 0; }
-static inline int dbg_is_power_cut(const struct ubifs_info *c) { return 0; }
-
-static inline int dbg_debugfs_init(void) { return 0; }
-static inline void dbg_debugfs_exit(void) { return; }
-static inline int dbg_debugfs_init_fs(struct ubifs_info *c) { return 0; }
-static inline int dbg_debugfs_exit_fs(struct ubifs_info *c) { return 0; }
-
-#endif /* !CONFIG_UBIFS_FS_DEBUG */
#endif /* !__UBIFS_DEBUG_H__ */
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index ec9f1870ab7f..62a2727f4ecf 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -170,8 +170,6 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
return inode;
}
-#ifdef CONFIG_UBIFS_FS_DEBUG
-
static int dbg_check_name(const struct ubifs_info *c,
const struct ubifs_dent_node *dent,
const struct qstr *nm)
@@ -185,12 +183,6 @@ static int dbg_check_name(const struct ubifs_info *c,
return 0;
}
-#else
-
-#define dbg_check_name(c, dent, nm) 0
-
-#endif
-
static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nd)
{
@@ -1187,12 +1179,10 @@ const struct inode_operations ubifs_dir_inode_operations = {
.rename = ubifs_rename,
.setattr = ubifs_setattr,
.getattr = ubifs_getattr,
-#ifdef CONFIG_UBIFS_FS_XATTR
.setxattr = ubifs_setxattr,
.getxattr = ubifs_getxattr,
.listxattr = ubifs_listxattr,
.removexattr = ubifs_removexattr,
-#endif
};
const struct file_operations ubifs_dir_operations = {
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index 5c8f6dc1d28b..35389ca2d267 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -97,7 +97,7 @@ static int read_block(struct inode *inode, void *addr, unsigned int block,
dump:
ubifs_err("bad data node (block %u, inode %lu)",
block, inode->i_ino);
- dbg_dump_node(c, dn);
+ ubifs_dump_node(c, dn);
return -EINVAL;
}
@@ -1562,12 +1562,10 @@ const struct address_space_operations ubifs_file_address_operations = {
const struct inode_operations ubifs_file_inode_operations = {
.setattr = ubifs_setattr,
.getattr = ubifs_getattr,
-#ifdef CONFIG_UBIFS_FS_XATTR
.setxattr = ubifs_setxattr,
.getxattr = ubifs_getxattr,
.listxattr = ubifs_listxattr,
.removexattr = ubifs_removexattr,
-#endif
};
const struct inode_operations ubifs_symlink_inode_operations = {
diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c
index ded29f6224c2..04dd6f47635e 100644
--- a/fs/ubifs/gc.c
+++ b/fs/ubifs/gc.c
@@ -109,7 +109,7 @@ static int switch_gc_head(struct ubifs_info *c)
return err;
c->gc_lnum = -1;
- err = ubifs_wbuf_seek_nolock(wbuf, gc_lnum, 0, UBI_LONGTERM);
+ err = ubifs_wbuf_seek_nolock(wbuf, gc_lnum, 0);
return err;
}
diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c
index 9228950a658f..e18b9889a51b 100644
--- a/fs/ubifs/io.c
+++ b/fs/ubifs/io.c
@@ -109,13 +109,13 @@ int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs,
if (err && (err != -EBADMSG || even_ebadmsg)) {
ubifs_err("reading %d bytes from LEB %d:%d failed, error %d",
len, lnum, offs, err);
- dbg_dump_stack();
+ dump_stack();
}
return err;
}
int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
- int len, int dtype)
+ int len)
{
int err;
@@ -123,20 +123,19 @@ int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
if (c->ro_error)
return -EROFS;
if (!dbg_is_tst_rcvry(c))
- err = ubi_leb_write(c->ubi, lnum, buf, offs, len, dtype);
+ err = ubi_leb_write(c->ubi, lnum, buf, offs, len);
else
- err = dbg_leb_write(c, lnum, buf, offs, len, dtype);
+ err = dbg_leb_write(c, lnum, buf, offs, len);
if (err) {
ubifs_err("writing %d bytes to LEB %d:%d failed, error %d",
len, lnum, offs, err);
ubifs_ro_mode(c, err);
- dbg_dump_stack();
+ dump_stack();
}
return err;
}
-int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
- int dtype)
+int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len)
{
int err;
@@ -144,14 +143,14 @@ int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
if (c->ro_error)
return -EROFS;
if (!dbg_is_tst_rcvry(c))
- err = ubi_leb_change(c->ubi, lnum, buf, len, dtype);
+ err = ubi_leb_change(c->ubi, lnum, buf, len);
else
- err = dbg_leb_change(c, lnum, buf, len, dtype);
+ err = dbg_leb_change(c, lnum, buf, len);
if (err) {
ubifs_err("changing %d bytes in LEB %d failed, error %d",
len, lnum, err);
ubifs_ro_mode(c, err);
- dbg_dump_stack();
+ dump_stack();
}
return err;
}
@@ -170,12 +169,12 @@ int ubifs_leb_unmap(struct ubifs_info *c, int lnum)
if (err) {
ubifs_err("unmap LEB %d failed, error %d", lnum, err);
ubifs_ro_mode(c, err);
- dbg_dump_stack();
+ dump_stack();
}
return err;
}
-int ubifs_leb_map(struct ubifs_info *c, int lnum, int dtype)
+int ubifs_leb_map(struct ubifs_info *c, int lnum)
{
int err;
@@ -183,13 +182,13 @@ int ubifs_leb_map(struct ubifs_info *c, int lnum, int dtype)
if (c->ro_error)
return -EROFS;
if (!dbg_is_tst_rcvry(c))
- err = ubi_leb_map(c->ubi, lnum, dtype);
+ err = ubi_leb_map(c->ubi, lnum);
else
- err = dbg_leb_map(c, lnum, dtype);
+ err = dbg_leb_map(c, lnum);
if (err) {
ubifs_err("mapping LEB %d failed, error %d", lnum, err);
ubifs_ro_mode(c, err);
- dbg_dump_stack();
+ dump_stack();
}
return err;
}
@@ -202,7 +201,7 @@ int ubifs_is_mapped(const struct ubifs_info *c, int lnum)
if (err < 0) {
ubifs_err("ubi_is_mapped failed for LEB %d, error %d",
lnum, err);
- dbg_dump_stack();
+ dump_stack();
}
return err;
}
@@ -294,8 +293,8 @@ out_len:
out:
if (!quiet) {
ubifs_err("bad node at LEB %d:%d", lnum, offs);
- dbg_dump_node(c, buf);
- dbg_dump_stack();
+ ubifs_dump_node(c, buf);
+ dump_stack();
}
return err;
}
@@ -523,8 +522,7 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
dirt = sync_len - wbuf->used;
if (dirt)
ubifs_pad(c, wbuf->buf + wbuf->used, dirt);
- err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs, sync_len,
- wbuf->dtype);
+ err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs, sync_len);
if (err)
return err;
@@ -562,14 +560,12 @@ int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
* @wbuf: write-buffer
* @lnum: logical eraseblock number to seek to
* @offs: logical eraseblock offset to seek to
- * @dtype: data type
*
* This function targets the write-buffer to logical eraseblock @lnum:@offs.
* The write-buffer has to be empty. Returns zero in case of success and a
* negative error code in case of failure.
*/
-int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
- int dtype)
+int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs)
{
const struct ubifs_info *c = wbuf->c;
@@ -592,7 +588,6 @@ int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
wbuf->avail = wbuf->size;
wbuf->used = 0;
spin_unlock(&wbuf->lock);
- wbuf->dtype = dtype;
return 0;
}
@@ -719,8 +714,7 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
dbg_io("flush jhead %s wbuf to LEB %d:%d",
dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf,
- wbuf->offs, wbuf->size,
- wbuf->dtype);
+ wbuf->offs, wbuf->size);
if (err)
goto out;
@@ -756,7 +750,7 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail);
err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs,
- wbuf->size, wbuf->dtype);
+ wbuf->size);
if (err)
goto out;
@@ -775,7 +769,7 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
dbg_io("write %d bytes to LEB %d:%d",
wbuf->size, wbuf->lnum, wbuf->offs);
err = ubifs_leb_write(c, wbuf->lnum, buf, wbuf->offs,
- wbuf->size, wbuf->dtype);
+ wbuf->size);
if (err)
goto out;
@@ -797,7 +791,7 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum,
wbuf->offs);
err = ubifs_leb_write(c, wbuf->lnum, buf + written,
- wbuf->offs, n, wbuf->dtype);
+ wbuf->offs, n);
if (err)
goto out;
wbuf->offs += n;
@@ -841,9 +835,9 @@ exit:
out:
ubifs_err("cannot write %d bytes to LEB %d:%d, error %d",
len, wbuf->lnum, wbuf->offs, err);
- dbg_dump_node(c, buf);
- dbg_dump_stack();
- dbg_dump_leb(c, wbuf->lnum);
+ ubifs_dump_node(c, buf);
+ dump_stack();
+ ubifs_dump_leb(c, wbuf->lnum);
return err;
}
@@ -854,7 +848,6 @@ out:
* @len: node length
* @lnum: logical eraseblock number
* @offs: offset within the logical eraseblock
- * @dtype: node life-time hint (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN)
*
* This function automatically fills node magic number, assigns sequence
* number, and calculates node CRC checksum. The length of the @buf buffer has
@@ -863,7 +856,7 @@ out:
* success and a negative error code in case of failure.
*/
int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
- int offs, int dtype)
+ int offs)
{
int err, buf_len = ALIGN(len, c->min_io_size);
@@ -879,9 +872,9 @@ int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
return -EROFS;
ubifs_prepare_node(c, buf, len, 1);
- err = ubifs_leb_write(c, lnum, buf, offs, buf_len, dtype);
+ err = ubifs_leb_write(c, lnum, buf, offs, buf_len);
if (err)
- dbg_dump_node(c, buf);
+ ubifs_dump_node(c, buf);
return err;
}
@@ -960,8 +953,8 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
out:
ubifs_err("bad node at LEB %d:%d", lnum, offs);
- dbg_dump_node(c, buf);
- dbg_dump_stack();
+ ubifs_dump_node(c, buf);
+ dump_stack();
return -EINVAL;
}
@@ -1017,8 +1010,8 @@ int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
out:
ubifs_err("bad node at LEB %d:%d, LEB mapping status %d", lnum, offs,
ubi_is_mapped(c->ubi, lnum));
- dbg_dump_node(c, buf);
- dbg_dump_stack();
+ ubifs_dump_node(c, buf);
+ dump_stack();
return -EINVAL;
}
@@ -1056,7 +1049,6 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
*/
size = c->max_write_size - (c->leb_start % c->max_write_size);
wbuf->avail = wbuf->size = size;
- wbuf->dtype = UBI_UNKNOWN;
wbuf->sync_callback = NULL;
mutex_init(&wbuf->io_mutex);
spin_lock_init(&wbuf->lock);
diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c
index 2f438ab2e7a2..12c0f154ca83 100644
--- a/fs/ubifs/journal.c
+++ b/fs/ubifs/journal.c
@@ -214,7 +214,7 @@ out:
err = ubifs_add_bud_to_log(c, jhead, lnum, offs);
if (err)
goto out_return;
- err = ubifs_wbuf_seek_nolock(wbuf, lnum, offs, wbuf->dtype);
+ err = ubifs_wbuf_seek_nolock(wbuf, lnum, offs);
if (err)
goto out_unlock;
@@ -385,9 +385,9 @@ out:
if (err == -ENOSPC) {
/* This are some budgeting problems, print useful information */
down_write(&c->commit_sem);
- dbg_dump_stack();
- dbg_dump_budg(c, &c->bi);
- dbg_dump_lprops(c);
+ dump_stack();
+ ubifs_dump_budg(c, &c->bi);
+ ubifs_dump_lprops(c);
cmt_retries = dbg_check_lprops(c);
up_write(&c->commit_sem);
}
@@ -1267,7 +1267,6 @@ out_free:
return err;
}
-#ifdef CONFIG_UBIFS_FS_XATTR
/**
* ubifs_jnl_delete_xattr - delete an extended attribute.
@@ -1462,4 +1461,3 @@ out_free:
return err;
}
-#endif /* CONFIG_UBIFS_FS_XATTR */
diff --git a/fs/ubifs/log.c b/fs/ubifs/log.c
index f9fd068d1ae0..c80b15d6c8de 100644
--- a/fs/ubifs/log.c
+++ b/fs/ubifs/log.c
@@ -29,11 +29,7 @@
#include "ubifs.h"
-#ifdef CONFIG_UBIFS_FS_DEBUG
static int dbg_check_bud_bytes(struct ubifs_info *c);
-#else
-#define dbg_check_bud_bytes(c) 0
-#endif
/**
* ubifs_search_bud - search bud LEB.
@@ -262,7 +258,7 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
* an unclean reboot, because the target LEB might have been
* unmapped, but not yet physically erased.
*/
- err = ubifs_leb_map(c, bud->lnum, UBI_SHORTTERM);
+ err = ubifs_leb_map(c, bud->lnum);
if (err)
goto out_unlock;
}
@@ -270,7 +266,7 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
dbg_log("write ref LEB %d:%d",
c->lhead_lnum, c->lhead_offs);
err = ubifs_write_node(c, ref, UBIFS_REF_NODE_SZ, c->lhead_lnum,
- c->lhead_offs, UBI_SHORTTERM);
+ c->lhead_offs);
if (err)
goto out_unlock;
@@ -422,7 +418,7 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
len = ALIGN(len, c->min_io_size);
dbg_log("writing commit start at LEB %d:0, len %d", c->lhead_lnum, len);
- err = ubifs_leb_write(c, c->lhead_lnum, cs, 0, len, UBI_SHORTTERM);
+ err = ubifs_leb_write(c, c->lhead_lnum, cs, 0, len);
if (err)
goto out;
@@ -623,7 +619,7 @@ static int add_node(struct ubifs_info *c, void *buf, int *lnum, int *offs,
int sz = ALIGN(*offs, c->min_io_size), err;
ubifs_pad(c, buf + *offs, sz - *offs);
- err = ubifs_leb_change(c, *lnum, buf, sz, UBI_SHORTTERM);
+ err = ubifs_leb_change(c, *lnum, buf, sz);
if (err)
return err;
*lnum = ubifs_next_log_lnum(c, *lnum);
@@ -702,7 +698,7 @@ int ubifs_consolidate_log(struct ubifs_info *c)
int sz = ALIGN(offs, c->min_io_size);
ubifs_pad(c, buf + offs, sz - offs);
- err = ubifs_leb_change(c, write_lnum, buf, sz, UBI_SHORTTERM);
+ err = ubifs_leb_change(c, write_lnum, buf, sz);
if (err)
goto out_free;
offs = ALIGN(offs, c->min_io_size);
@@ -734,8 +730,6 @@ out_free:
return err;
}
-#ifdef CONFIG_UBIFS_FS_DEBUG
-
/**
* dbg_check_bud_bytes - make sure bud bytes calculation are all right.
* @c: UBIFS file-system description object
@@ -767,5 +761,3 @@ static int dbg_check_bud_bytes(struct ubifs_info *c)
return err;
}
-
-#endif /* CONFIG_UBIFS_FS_DEBUG */
diff --git a/fs/ubifs/lprops.c b/fs/ubifs/lprops.c
index f8a181e647cc..86eb8e533249 100644
--- a/fs/ubifs/lprops.c
+++ b/fs/ubifs/lprops.c
@@ -447,7 +447,7 @@ static void change_category(struct ubifs_info *c, struct ubifs_lprops *lprops)
int new_cat = ubifs_categorize_lprops(c, lprops);
if (old_cat == new_cat) {
- struct ubifs_lpt_heap *heap = &c->lpt_heap[new_cat - 1];
+ struct ubifs_lpt_heap *heap;
/* lprops on a heap now must be moved up or down */
if (new_cat < 1 || new_cat > LPROPS_HEAP_CNT)
@@ -846,7 +846,9 @@ const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c)
return lprops;
}
-#ifdef CONFIG_UBIFS_FS_DEBUG
+/*
+ * Everything below is related to debugging.
+ */
/**
* dbg_check_cats - check category heaps and lists.
@@ -1001,8 +1003,8 @@ void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat,
out:
if (err) {
dbg_msg("failed cat %d hpos %d err %d", cat, i, err);
- dbg_dump_stack();
- dbg_dump_heap(c, heap, cat);
+ dump_stack();
+ ubifs_dump_heap(c, heap, cat);
}
}
@@ -1109,8 +1111,8 @@ static int scan_check_cb(struct ubifs_info *c,
if (IS_ERR(sleb)) {
ret = PTR_ERR(sleb);
if (ret == -EUCLEAN) {
- dbg_dump_lprops(c);
- dbg_dump_budg(c, &c->bi);
+ ubifs_dump_lprops(c);
+ ubifs_dump_budg(c, &c->bi);
}
goto out;
}
@@ -1237,7 +1239,7 @@ out_print:
ubifs_err("bad accounting of LEB %d: free %d, dirty %d flags %#x, "
"should be free %d, dirty %d",
lnum, lp->free, lp->dirty, lp->flags, free, dirty);
- dbg_dump_leb(c, lnum);
+ ubifs_dump_leb(c, lnum);
out_destroy:
ubifs_scan_destroy(sleb);
ret = -EINVAL;
@@ -1315,5 +1317,3 @@ int dbg_check_lprops(struct ubifs_info *c)
out:
return err;
}
-
-#endif /* CONFIG_UBIFS_FS_DEBUG */
diff --git a/fs/ubifs/lpt.c b/fs/ubifs/lpt.c
index 66d59d0a1402..ce33b2beb151 100644
--- a/fs/ubifs/lpt.c
+++ b/fs/ubifs/lpt.c
@@ -701,8 +701,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
alen = ALIGN(len, c->min_io_size);
set_ltab(c, lnum, c->leb_size - alen, alen - len);
memset(p, 0xff, alen - len);
- err = ubifs_leb_change(c, lnum++, buf, alen,
- UBI_SHORTTERM);
+ err = ubifs_leb_change(c, lnum++, buf, alen);
if (err)
goto out;
p = buf;
@@ -732,8 +731,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
set_ltab(c, lnum, c->leb_size - alen,
alen - len);
memset(p, 0xff, alen - len);
- err = ubifs_leb_change(c, lnum++, buf, alen,
- UBI_SHORTTERM);
+ err = ubifs_leb_change(c, lnum++, buf, alen);
if (err)
goto out;
p = buf;
@@ -780,8 +778,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
alen = ALIGN(len, c->min_io_size);
set_ltab(c, lnum, c->leb_size - alen, alen - len);
memset(p, 0xff, alen - len);
- err = ubifs_leb_change(c, lnum++, buf, alen,
- UBI_SHORTTERM);
+ err = ubifs_leb_change(c, lnum++, buf, alen);
if (err)
goto out;
p = buf;
@@ -806,7 +803,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
alen = ALIGN(len, c->min_io_size);
set_ltab(c, lnum, c->leb_size - alen, alen - len);
memset(p, 0xff, alen - len);
- err = ubifs_leb_change(c, lnum++, buf, alen, UBI_SHORTTERM);
+ err = ubifs_leb_change(c, lnum++, buf, alen);
if (err)
goto out;
p = buf;
@@ -826,7 +823,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
/* Write remaining buffer */
memset(p, 0xff, alen - len);
- err = ubifs_leb_change(c, lnum, buf, alen, UBI_SHORTTERM);
+ err = ubifs_leb_change(c, lnum, buf, alen);
if (err)
goto out;
@@ -926,7 +923,7 @@ static int check_lpt_crc(void *buf, int len)
if (crc != calc_crc) {
ubifs_err("invalid crc in LPT node: crc %hx calc %hx", crc,
calc_crc);
- dbg_dump_stack();
+ dump_stack();
return -EINVAL;
}
return 0;
@@ -949,7 +946,7 @@ static int check_lpt_type(uint8_t **addr, int *pos, int type)
if (node_type != type) {
ubifs_err("invalid type (%d) in LPT node type %d", node_type,
type);
- dbg_dump_stack();
+ dump_stack();
return -EINVAL;
}
return 0;
@@ -1247,7 +1244,7 @@ int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
out:
ubifs_err("error %d reading nnode at %d:%d", err, lnum, offs);
- dbg_dump_stack();
+ dump_stack();
kfree(nnode);
return err;
}
@@ -1312,8 +1309,8 @@ static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
out:
ubifs_err("error %d reading pnode at %d:%d", err, lnum, offs);
- dbg_dump_pnode(c, pnode, parent, iip);
- dbg_dump_stack();
+ ubifs_dump_pnode(c, pnode, parent, iip);
+ dump_stack();
dbg_msg("calc num: %d", calc_pnode_num_from_parent(c, parent, iip));
kfree(pnode);
return err;
@@ -1740,16 +1737,20 @@ int ubifs_lpt_init(struct ubifs_info *c, int rd, int wr)
if (rd) {
err = lpt_init_rd(c);
if (err)
- return err;
+ goto out_err;
}
if (wr) {
err = lpt_init_wr(c);
if (err)
- return err;
+ goto out_err;
}
return 0;
+
+out_err:
+ ubifs_lpt_free(c, 0);
+ return err;
}
/**
@@ -2080,8 +2081,6 @@ out:
return err;
}
-#ifdef CONFIG_UBIFS_FS_DEBUG
-
/**
* dbg_chk_pnode - check a pnode.
* @c: the UBIFS file-system description object
@@ -2096,8 +2095,8 @@ static int dbg_chk_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
int i;
if (pnode->num != col) {
- dbg_err("pnode num %d expected %d parent num %d iip %d",
- pnode->num, col, pnode->parent->num, pnode->iip);
+ ubifs_err("pnode num %d expected %d parent num %d iip %d",
+ pnode->num, col, pnode->parent->num, pnode->iip);
return -EINVAL;
}
for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
@@ -2111,14 +2110,14 @@ static int dbg_chk_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
if (lnum >= c->leb_cnt)
continue;
if (lprops->lnum != lnum) {
- dbg_err("bad LEB number %d expected %d",
- lprops->lnum, lnum);
+ ubifs_err("bad LEB number %d expected %d",
+ lprops->lnum, lnum);
return -EINVAL;
}
if (lprops->flags & LPROPS_TAKEN) {
if (cat != LPROPS_UNCAT) {
- dbg_err("LEB %d taken but not uncat %d",
- lprops->lnum, cat);
+ ubifs_err("LEB %d taken but not uncat %d",
+ lprops->lnum, cat);
return -EINVAL;
}
continue;
@@ -2130,8 +2129,8 @@ static int dbg_chk_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
case LPROPS_FRDI_IDX:
break;
default:
- dbg_err("LEB %d index but cat %d",
- lprops->lnum, cat);
+ ubifs_err("LEB %d index but cat %d",
+ lprops->lnum, cat);
return -EINVAL;
}
} else {
@@ -2143,8 +2142,8 @@ static int dbg_chk_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
case LPROPS_FREEABLE:
break;
default:
- dbg_err("LEB %d not index but cat %d",
- lprops->lnum, cat);
+ ubifs_err("LEB %d not index but cat %d",
+ lprops->lnum, cat);
return -EINVAL;
}
}
@@ -2184,24 +2183,24 @@ static int dbg_chk_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
break;
}
if (!found) {
- dbg_err("LEB %d cat %d not found in cat heap/list",
- lprops->lnum, cat);
+ ubifs_err("LEB %d cat %d not found in cat heap/list",
+ lprops->lnum, cat);
return -EINVAL;
}
switch (cat) {
case LPROPS_EMPTY:
if (lprops->free != c->leb_size) {
- dbg_err("LEB %d cat %d free %d dirty %d",
- lprops->lnum, cat, lprops->free,
- lprops->dirty);
+ ubifs_err("LEB %d cat %d free %d dirty %d",
+ lprops->lnum, cat, lprops->free,
+ lprops->dirty);
return -EINVAL;
}
case LPROPS_FREEABLE:
case LPROPS_FRDI_IDX:
if (lprops->free + lprops->dirty != c->leb_size) {
- dbg_err("LEB %d cat %d free %d dirty %d",
- lprops->lnum, cat, lprops->free,
- lprops->dirty);
+ ubifs_err("LEB %d cat %d free %d dirty %d",
+ lprops->lnum, cat, lprops->free,
+ lprops->dirty);
return -EINVAL;
}
}
@@ -2235,9 +2234,10 @@ int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
/* cnode is a nnode */
num = calc_nnode_num(row, col);
if (cnode->num != num) {
- dbg_err("nnode num %d expected %d "
- "parent num %d iip %d", cnode->num, num,
- (nnode ? nnode->num : 0), cnode->iip);
+ ubifs_err("nnode num %d expected %d "
+ "parent num %d iip %d",
+ cnode->num, num,
+ (nnode ? nnode->num : 0), cnode->iip);
return -EINVAL;
}
nn = (struct ubifs_nnode *)cnode;
@@ -2274,5 +2274,3 @@ int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
}
return 0;
}
-
-#endif /* CONFIG_UBIFS_FS_DEBUG */
diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c
index cddd6bd214f4..4fa70734e6e7 100644
--- a/fs/ubifs/lpt_commit.c
+++ b/fs/ubifs/lpt_commit.c
@@ -30,11 +30,7 @@
#include <linux/random.h>
#include "ubifs.h"
-#ifdef CONFIG_UBIFS_FS_DEBUG
static int dbg_populate_lsave(struct ubifs_info *c);
-#else
-#define dbg_populate_lsave(c) 0
-#endif
/**
* first_dirty_cnode - find first dirty cnode.
@@ -324,11 +320,10 @@ static int layout_cnodes(struct ubifs_info *c)
return 0;
no_space:
- ubifs_err("LPT out of space");
- dbg_err("LPT out of space at LEB %d:%d needing %d, done_ltab %d, "
- "done_lsave %d", lnum, offs, len, done_ltab, done_lsave);
- dbg_dump_lpt_info(c);
- dbg_dump_lpt_lebs(c);
+ ubifs_err("LPT out of space at LEB %d:%d needing %d, done_ltab %d, "
+ "done_lsave %d", lnum, offs, len, done_ltab, done_lsave);
+ ubifs_dump_lpt_info(c);
+ ubifs_dump_lpt_lebs(c);
dump_stack();
return err;
}
@@ -421,7 +416,7 @@ static int write_cnodes(struct ubifs_info *c)
alen = ALIGN(wlen, c->min_io_size);
memset(buf + offs, 0xff, alen - wlen);
err = ubifs_leb_write(c, lnum, buf + from, from,
- alen, UBI_SHORTTERM);
+ alen);
if (err)
return err;
}
@@ -479,8 +474,7 @@ static int write_cnodes(struct ubifs_info *c)
wlen = offs - from;
alen = ALIGN(wlen, c->min_io_size);
memset(buf + offs, 0xff, alen - wlen);
- err = ubifs_leb_write(c, lnum, buf + from, from, alen,
- UBI_SHORTTERM);
+ err = ubifs_leb_write(c, lnum, buf + from, from, alen);
if (err)
return err;
dbg_chk_lpt_sz(c, 2, c->leb_size - offs);
@@ -506,8 +500,7 @@ static int write_cnodes(struct ubifs_info *c)
wlen = offs - from;
alen = ALIGN(wlen, c->min_io_size);
memset(buf + offs, 0xff, alen - wlen);
- err = ubifs_leb_write(c, lnum, buf + from, from, alen,
- UBI_SHORTTERM);
+ err = ubifs_leb_write(c, lnum, buf + from, from, alen);
if (err)
return err;
dbg_chk_lpt_sz(c, 2, c->leb_size - offs);
@@ -531,7 +524,7 @@ static int write_cnodes(struct ubifs_info *c)
wlen = offs - from;
alen = ALIGN(wlen, c->min_io_size);
memset(buf + offs, 0xff, alen - wlen);
- err = ubifs_leb_write(c, lnum, buf + from, from, alen, UBI_SHORTTERM);
+ err = ubifs_leb_write(c, lnum, buf + from, from, alen);
if (err)
return err;
@@ -552,11 +545,10 @@ static int write_cnodes(struct ubifs_info *c)
return 0;
no_space:
- ubifs_err("LPT out of space mismatch");
- dbg_err("LPT out of space mismatch at LEB %d:%d needing %d, done_ltab "
- "%d, done_lsave %d", lnum, offs, len, done_ltab, done_lsave);
- dbg_dump_lpt_info(c);
- dbg_dump_lpt_lebs(c);
+ ubifs_err("LPT out of space mismatch at LEB %d:%d needing %d, done_ltab "
+ "%d, done_lsave %d", lnum, offs, len, done_ltab, done_lsave);
+ ubifs_dump_lpt_info(c);
+ ubifs_dump_lpt_lebs(c);
dump_stack();
return err;
}
@@ -1497,7 +1489,9 @@ void ubifs_lpt_free(struct ubifs_info *c, int wr_only)
kfree(c->lpt_nod_buf);
}
-#ifdef CONFIG_UBIFS_FS_DEBUG
+/*
+ * Everything below is related to debugging.
+ */
/**
* dbg_is_all_ff - determine if a buffer contains only 0xFF bytes.
@@ -1735,7 +1729,7 @@ int dbg_check_ltab(struct ubifs_info *c)
for (lnum = c->lpt_first; lnum <= c->lpt_last; lnum++) {
err = dbg_check_ltab_lnum(c, lnum);
if (err) {
- dbg_err("failed at LEB %d", lnum);
+ ubifs_err("failed at LEB %d", lnum);
return err;
}
}
@@ -1767,10 +1761,10 @@ int dbg_chk_lpt_free_spc(struct ubifs_info *c)
free += c->leb_size;
}
if (free < c->lpt_sz) {
- dbg_err("LPT space error: free %lld lpt_sz %lld",
- free, c->lpt_sz);
- dbg_dump_lpt_info(c);
- dbg_dump_lpt_lebs(c);
+ ubifs_err("LPT space error: free %lld lpt_sz %lld",
+ free, c->lpt_sz);
+ ubifs_dump_lpt_info(c);
+ ubifs_dump_lpt_lebs(c);
dump_stack();
return -EINVAL;
}
@@ -1807,13 +1801,13 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
d->chk_lpt_lebs = 0;
d->chk_lpt_wastage = 0;
if (c->dirty_pn_cnt > c->pnode_cnt) {
- dbg_err("dirty pnodes %d exceed max %d",
- c->dirty_pn_cnt, c->pnode_cnt);
+ ubifs_err("dirty pnodes %d exceed max %d",
+ c->dirty_pn_cnt, c->pnode_cnt);
err = -EINVAL;
}
if (c->dirty_nn_cnt > c->nnode_cnt) {
- dbg_err("dirty nnodes %d exceed max %d",
- c->dirty_nn_cnt, c->nnode_cnt);
+ ubifs_err("dirty nnodes %d exceed max %d",
+ c->dirty_nn_cnt, c->nnode_cnt);
err = -EINVAL;
}
return err;
@@ -1830,23 +1824,23 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
chk_lpt_sz *= d->chk_lpt_lebs;
chk_lpt_sz += len - c->nhead_offs;
if (d->chk_lpt_sz != chk_lpt_sz) {
- dbg_err("LPT wrote %lld but space used was %lld",
- d->chk_lpt_sz, chk_lpt_sz);
+ ubifs_err("LPT wrote %lld but space used was %lld",
+ d->chk_lpt_sz, chk_lpt_sz);
err = -EINVAL;
}
if (d->chk_lpt_sz > c->lpt_sz) {
- dbg_err("LPT wrote %lld but lpt_sz is %lld",
- d->chk_lpt_sz, c->lpt_sz);
+ ubifs_err("LPT wrote %lld but lpt_sz is %lld",
+ d->chk_lpt_sz, c->lpt_sz);
err = -EINVAL;
}
if (d->chk_lpt_sz2 && d->chk_lpt_sz != d->chk_lpt_sz2) {
- dbg_err("LPT layout size %lld but wrote %lld",
- d->chk_lpt_sz, d->chk_lpt_sz2);
+ ubifs_err("LPT layout size %lld but wrote %lld",
+ d->chk_lpt_sz, d->chk_lpt_sz2);
err = -EINVAL;
}
if (d->chk_lpt_sz2 && d->new_nhead_offs != len) {
- dbg_err("LPT new nhead offs: expected %d was %d",
- d->new_nhead_offs, len);
+ ubifs_err("LPT new nhead offs: expected %d was %d",
+ d->new_nhead_offs, len);
err = -EINVAL;
}
lpt_sz = (long long)c->pnode_cnt * c->pnode_sz;
@@ -1855,13 +1849,13 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
if (c->big_lpt)
lpt_sz += c->lsave_sz;
if (d->chk_lpt_sz - d->chk_lpt_wastage > lpt_sz) {
- dbg_err("LPT chk_lpt_sz %lld + waste %lld exceeds %lld",
- d->chk_lpt_sz, d->chk_lpt_wastage, lpt_sz);
+ ubifs_err("LPT chk_lpt_sz %lld + waste %lld exceeds %lld",
+ d->chk_lpt_sz, d->chk_lpt_wastage, lpt_sz);
err = -EINVAL;
}
if (err) {
- dbg_dump_lpt_info(c);
- dbg_dump_lpt_lebs(c);
+ ubifs_dump_lpt_info(c);
+ ubifs_dump_lpt_lebs(c);
dump_stack();
}
d->chk_lpt_sz2 = d->chk_lpt_sz;
@@ -1880,7 +1874,7 @@ int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
}
/**
- * dbg_dump_lpt_leb - dump an LPT LEB.
+ * ubifs_dump_lpt_leb - dump an LPT LEB.
* @c: UBIFS file-system description object
* @lnum: LEB number to dump
*
@@ -1986,13 +1980,13 @@ out:
}
/**
- * dbg_dump_lpt_lebs - dump LPT lebs.
+ * ubifs_dump_lpt_lebs - dump LPT lebs.
* @c: UBIFS file-system description object
*
* This function dumps all LPT LEBs. The caller has to make sure the LPT is
* locked.
*/
-void dbg_dump_lpt_lebs(const struct ubifs_info *c)
+void ubifs_dump_lpt_lebs(const struct ubifs_info *c)
{
int i;
@@ -2046,5 +2040,3 @@ static int dbg_populate_lsave(struct ubifs_info *c)
return 1;
}
-
-#endif /* CONFIG_UBIFS_FS_DEBUG */
diff --git a/fs/ubifs/master.c b/fs/ubifs/master.c
index 278c2382e8c2..ab83ace9910a 100644
--- a/fs/ubifs/master.c
+++ b/fs/ubifs/master.c
@@ -241,7 +241,7 @@ static int validate_master(const struct ubifs_info *c)
out:
ubifs_err("bad master node at offset %d error %d", c->mst_offs, err);
- dbg_dump_node(c, c->mst_node);
+ ubifs_dump_node(c, c->mst_node);
return -EINVAL;
}
@@ -317,7 +317,7 @@ int ubifs_read_master(struct ubifs_info *c)
if (c->leb_cnt < old_leb_cnt ||
c->leb_cnt < UBIFS_MIN_LEB_CNT) {
ubifs_err("bad leb_cnt on master node");
- dbg_dump_node(c, c->mst_node);
+ ubifs_dump_node(c, c->mst_node);
return -EINVAL;
}
@@ -379,7 +379,7 @@ int ubifs_write_master(struct ubifs_info *c)
c->mst_offs = offs;
c->mst_node->highest_inum = cpu_to_le64(c->highest_inum);
- err = ubifs_write_node(c, c->mst_node, len, lnum, offs, UBI_SHORTTERM);
+ err = ubifs_write_node(c, c->mst_node, len, lnum, offs);
if (err)
return err;
@@ -390,7 +390,7 @@ int ubifs_write_master(struct ubifs_info *c)
if (err)
return err;
}
- err = ubifs_write_node(c, c->mst_node, len, lnum, offs, UBI_SHORTTERM);
+ err = ubifs_write_node(c, c->mst_node, len, lnum, offs);
return err;
}
diff --git a/fs/ubifs/orphan.c b/fs/ubifs/orphan.c
index c542c73cfa3c..b02734db187c 100644
--- a/fs/ubifs/orphan.c
+++ b/fs/ubifs/orphan.c
@@ -52,11 +52,7 @@
* than the maximum number of orphans allowed.
*/
-#ifdef CONFIG_UBIFS_FS_DEBUG
static int dbg_check_orphans(struct ubifs_info *c);
-#else
-#define dbg_check_orphans(c) 0
-#endif
/**
* ubifs_add_orphan - add an orphan.
@@ -92,7 +88,7 @@ int ubifs_add_orphan(struct ubifs_info *c, ino_t inum)
else if (inum > o->inum)
p = &(*p)->rb_right;
else {
- dbg_err("orphaned twice");
+ ubifs_err("orphaned twice");
spin_unlock(&c->orphan_lock);
kfree(orphan);
return 0;
@@ -158,8 +154,8 @@ void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum)
}
}
spin_unlock(&c->orphan_lock);
- dbg_err("missing orphan ino %lu", (unsigned long)inum);
- dbg_dump_stack();
+ ubifs_err("missing orphan ino %lu", (unsigned long)inum);
+ dump_stack();
}
/**
@@ -248,8 +244,7 @@ static int do_write_orph_node(struct ubifs_info *c, int len, int atomic)
ubifs_assert(c->ohead_offs == 0);
ubifs_prepare_node(c, c->orph_buf, len, 1);
len = ALIGN(len, c->min_io_size);
- err = ubifs_leb_change(c, c->ohead_lnum, c->orph_buf, len,
- UBI_SHORTTERM);
+ err = ubifs_leb_change(c, c->ohead_lnum, c->orph_buf, len);
} else {
if (c->ohead_offs == 0) {
/* Ensure LEB has been unmapped */
@@ -258,7 +253,7 @@ static int do_write_orph_node(struct ubifs_info *c, int len, int atomic)
return err;
}
err = ubifs_write_node(c, c->orph_buf, len, c->ohead_lnum,
- c->ohead_offs, UBI_SHORTTERM);
+ c->ohead_offs);
}
return err;
}
@@ -569,7 +564,7 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
if (snod->type != UBIFS_ORPH_NODE) {
ubifs_err("invalid node type %d in orphan area at "
"%d:%d", snod->type, sleb->lnum, snod->offs);
- dbg_dump_node(c, snod->node);
+ ubifs_dump_node(c, snod->node);
return -EINVAL;
}
@@ -597,7 +592,7 @@ static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
ubifs_err("out of order commit number %llu in "
"orphan node at %d:%d",
cmt_no, sleb->lnum, snod->offs);
- dbg_dump_node(c, snod->node);
+ ubifs_dump_node(c, snod->node);
return -EINVAL;
}
dbg_rcvry("out of date LEB %d", sleb->lnum);
@@ -725,7 +720,9 @@ int ubifs_mount_orphans(struct ubifs_info *c, int unclean, int read_only)
return err;
}
-#ifdef CONFIG_UBIFS_FS_DEBUG
+/*
+ * Everything below is related to debugging.
+ */
struct check_orphan {
struct rb_node rb;
@@ -968,5 +965,3 @@ out:
kfree(ci.node);
return err;
}
-
-#endif /* CONFIG_UBIFS_FS_DEBUG */
diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
index 2a935b317232..c30d976b4be8 100644
--- a/fs/ubifs/recovery.c
+++ b/fs/ubifs/recovery.c
@@ -213,10 +213,10 @@ static int write_rcvrd_mst_node(struct ubifs_info *c,
mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY);
ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1);
- err = ubifs_leb_change(c, lnum, mst, sz, UBI_SHORTTERM);
+ err = ubifs_leb_change(c, lnum, mst, sz);
if (err)
goto out;
- err = ubifs_leb_change(c, lnum + 1, mst, sz, UBI_SHORTTERM);
+ err = ubifs_leb_change(c, lnum + 1, mst, sz);
if (err)
goto out;
out:
@@ -362,12 +362,12 @@ out_err:
out_free:
ubifs_err("failed to recover master node");
if (mst1) {
- dbg_err("dumping first master node");
- dbg_dump_node(c, mst1);
+ ubifs_err("dumping first master node");
+ ubifs_dump_node(c, mst1);
}
if (mst2) {
- dbg_err("dumping second master node");
- dbg_dump_node(c, mst2);
+ ubifs_err("dumping second master node");
+ ubifs_dump_node(c, mst2);
}
vfree(buf2);
vfree(buf1);
@@ -555,8 +555,7 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
ubifs_pad(c, buf, pad_len);
}
}
- err = ubifs_leb_change(c, lnum, sleb->buf, len,
- UBI_UNKNOWN);
+ err = ubifs_leb_change(c, lnum, sleb->buf, len);
if (err)
return err;
}
@@ -683,7 +682,7 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
ret, lnum, offs);
break;
} else {
- dbg_err("unexpected return value %d", ret);
+ ubifs_err("unexpected return value %d", ret);
err = -EINVAL;
goto error;
}
@@ -789,7 +788,7 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
corrupted_rescan:
/* Re-scan the corrupted data with verbose messages */
- dbg_err("corruptio %d", ret);
+ ubifs_err("corruptio %d", ret);
ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
corrupted:
ubifs_scanned_corruption(c, lnum, offs, buf);
@@ -827,17 +826,17 @@ static int get_cs_sqnum(struct ubifs_info *c, int lnum, int offs,
goto out_free;
ret = ubifs_scan_a_node(c, cs_node, UBIFS_CS_NODE_SZ, lnum, offs, 0);
if (ret != SCANNED_A_NODE) {
- dbg_err("Not a valid node");
+ ubifs_err("Not a valid node");
goto out_err;
}
if (cs_node->ch.node_type != UBIFS_CS_NODE) {
- dbg_err("Node a CS node, type is %d", cs_node->ch.node_type);
+ ubifs_err("Node a CS node, type is %d", cs_node->ch.node_type);
goto out_err;
}
if (le64_to_cpu(cs_node->cmt_no) != c->cmt_no) {
- dbg_err("CS node cmt_no %llu != current cmt_no %llu",
- (unsigned long long)le64_to_cpu(cs_node->cmt_no),
- c->cmt_no);
+ ubifs_err("CS node cmt_no %llu != current cmt_no %llu",
+ (unsigned long long)le64_to_cpu(cs_node->cmt_no),
+ c->cmt_no);
goto out_err;
}
*cs_sqnum = le64_to_cpu(cs_node->ch.sqnum);
@@ -941,7 +940,7 @@ static int recover_head(struct ubifs_info *c, int lnum, int offs, void *sbuf)
err = ubifs_leb_read(c, lnum, sbuf, 0, offs, 1);
if (err)
return err;
- return ubifs_leb_change(c, lnum, sbuf, offs, UBI_UNKNOWN);
+ return ubifs_leb_change(c, lnum, sbuf, offs);
}
return 0;
@@ -1071,7 +1070,7 @@ static int clean_an_unclean_leb(struct ubifs_info *c,
}
/* Write back the LEB atomically */
- err = ubifs_leb_change(c, lnum, sbuf, len, UBI_UNKNOWN);
+ err = ubifs_leb_change(c, lnum, sbuf, len);
if (err)
return err;
@@ -1138,9 +1137,9 @@ static int grab_empty_leb(struct ubifs_info *c)
*/
lnum = ubifs_find_free_leb_for_idx(c);
if (lnum < 0) {
- dbg_err("could not find an empty LEB");
- dbg_dump_lprops(c);
- dbg_dump_budg(c, &c->bi);
+ ubifs_err("could not find an empty LEB");
+ ubifs_dump_lprops(c);
+ ubifs_dump_budg(c, &c->bi);
return lnum;
}
@@ -1218,7 +1217,7 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c)
}
mutex_unlock(&wbuf->io_mutex);
if (err < 0) {
- dbg_err("GC failed, error %d", err);
+ ubifs_err("GC failed, error %d", err);
if (err == -EAGAIN)
err = -EINVAL;
return err;
@@ -1472,7 +1471,7 @@ static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
len -= 1;
len = ALIGN(len + 1, c->min_io_size);
/* Atomically write the fixed LEB back again */
- err = ubifs_leb_change(c, lnum, c->sbuf, len, UBI_UNKNOWN);
+ err = ubifs_leb_change(c, lnum, c->sbuf, len);
if (err)
goto out;
dbg_rcvry("inode %lu at %d:%d size %lld -> %lld",
diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index b007637f0406..3a2da7e476e5 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -154,8 +154,7 @@ static int set_bud_lprops(struct ubifs_info *c, struct bud_entry *b)
/* Make sure the journal head points to the latest bud */
err = ubifs_wbuf_seek_nolock(&c->jheads[b->bud->jhead].wbuf,
- b->bud->lnum, c->leb_size - b->free,
- UBI_SHORTTERM);
+ b->bud->lnum, c->leb_size - b->free);
out:
ubifs_release_lprops(c);
@@ -686,7 +685,7 @@ out:
out_dump:
ubifs_err("bad node is at LEB %d:%d", lnum, snod->offs);
- dbg_dump_node(c, snod->node);
+ ubifs_dump_node(c, snod->node);
ubifs_scan_destroy(sleb);
return -EINVAL;
}
@@ -861,16 +860,16 @@ static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf)
* numbers.
*/
if (snod->type != UBIFS_CS_NODE) {
- dbg_err("first log node at LEB %d:%d is not CS node",
- lnum, offs);
+ ubifs_err("first log node at LEB %d:%d is not CS node",
+ lnum, offs);
goto out_dump;
}
if (le64_to_cpu(node->cmt_no) != c->cmt_no) {
- dbg_err("first CS node at LEB %d:%d has wrong "
- "commit number %llu expected %llu",
- lnum, offs,
- (unsigned long long)le64_to_cpu(node->cmt_no),
- c->cmt_no);
+ ubifs_err("first CS node at LEB %d:%d has wrong "
+ "commit number %llu expected %llu",
+ lnum, offs,
+ (unsigned long long)le64_to_cpu(node->cmt_no),
+ c->cmt_no);
goto out_dump;
}
@@ -892,7 +891,7 @@ static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf)
/* Make sure the first node sits at offset zero of the LEB */
if (snod->offs != 0) {
- dbg_err("first node is not at zero offset");
+ ubifs_err("first node is not at zero offset");
goto out_dump;
}
@@ -905,8 +904,8 @@ static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf)
}
if (snod->sqnum < c->cs_sqnum) {
- dbg_err("bad sqnum %llu, commit sqnum %llu",
- snod->sqnum, c->cs_sqnum);
+ ubifs_err("bad sqnum %llu, commit sqnum %llu",
+ snod->sqnum, c->cs_sqnum);
goto out_dump;
}
@@ -958,7 +957,7 @@ out:
out_dump:
ubifs_err("log error detected while replaying the log at LEB %d:%d",
lnum, offs + snod->offs);
- dbg_dump_node(c, snod->node);
+ ubifs_dump_node(c, snod->node);
ubifs_scan_destroy(sleb);
return -EINVAL;
}
diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
index 771f7fb6ce92..ef3d1ba6d992 100644
--- a/fs/ubifs/sb.c
+++ b/fs/ubifs/sb.c
@@ -130,7 +130,6 @@ static int create_default_filesystem(struct ubifs_info *c)
* orphan node.
*/
orph_lebs = UBIFS_MIN_ORPH_LEBS;
-#ifdef CONFIG_UBIFS_FS_DEBUG
if (c->leb_cnt - min_leb_cnt > 1)
/*
* For debugging purposes it is better to have at least 2
@@ -138,7 +137,6 @@ static int create_default_filesystem(struct ubifs_info *c)
* consolidations and would be stressed more.
*/
orph_lebs += 1;
-#endif
main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS - log_lebs;
main_lebs -= orph_lebs;
@@ -196,7 +194,7 @@ static int create_default_filesystem(struct ubifs_info *c)
sup->rp_size = cpu_to_le64(tmp64);
sup->ro_compat_version = cpu_to_le32(UBIFS_RO_COMPAT_VERSION);
- err = ubifs_write_node(c, sup, UBIFS_SB_NODE_SZ, 0, 0, UBI_LONGTERM);
+ err = ubifs_write_node(c, sup, UBIFS_SB_NODE_SZ, 0, 0);
kfree(sup);
if (err)
return err;
@@ -252,14 +250,13 @@ static int create_default_filesystem(struct ubifs_info *c)
mst->total_used = cpu_to_le64(UBIFS_INO_NODE_SZ);
- err = ubifs_write_node(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM, 0,
- UBI_UNKNOWN);
+ err = ubifs_write_node(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM, 0);
if (err) {
kfree(mst);
return err;
}
- err = ubifs_write_node(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM + 1, 0,
- UBI_UNKNOWN);
+ err = ubifs_write_node(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM + 1,
+ 0);
kfree(mst);
if (err)
return err;
@@ -282,8 +279,7 @@ static int create_default_filesystem(struct ubifs_info *c)
key_write_idx(c, &key, &br->key);
br->lnum = cpu_to_le32(main_first + DEFAULT_DATA_LEB);
br->len = cpu_to_le32(UBIFS_INO_NODE_SZ);
- err = ubifs_write_node(c, idx, tmp, main_first + DEFAULT_IDX_LEB, 0,
- UBI_UNKNOWN);
+ err = ubifs_write_node(c, idx, tmp, main_first + DEFAULT_IDX_LEB, 0);
kfree(idx);
if (err)
return err;
@@ -315,8 +311,7 @@ static int create_default_filesystem(struct ubifs_info *c)
ino->flags = cpu_to_le32(UBIFS_COMPR_FL);
err = ubifs_write_node(c, ino, UBIFS_INO_NODE_SZ,
- main_first + DEFAULT_DATA_LEB, 0,
- UBI_UNKNOWN);
+ main_first + DEFAULT_DATA_LEB, 0);
kfree(ino);
if (err)
return err;
@@ -335,8 +330,7 @@ static int create_default_filesystem(struct ubifs_info *c)
return -ENOMEM;
cs->ch.node_type = UBIFS_CS_NODE;
- err = ubifs_write_node(c, cs, UBIFS_CS_NODE_SZ, UBIFS_LOG_LNUM,
- 0, UBI_UNKNOWN);
+ err = ubifs_write_node(c, cs, UBIFS_CS_NODE_SZ, UBIFS_LOG_LNUM, 0);
kfree(cs);
ubifs_msg("default file-system created");
@@ -475,7 +469,7 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
failed:
ubifs_err("bad superblock, error %d", err);
- dbg_dump_node(c, sup);
+ ubifs_dump_node(c, sup);
return -EINVAL;
}
@@ -518,7 +512,7 @@ int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup)
int len = ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size);
ubifs_prepare_node(c, sup, UBIFS_SB_NODE_SZ, 1);
- return ubifs_leb_change(c, UBIFS_SB_LNUM, sup, len, UBI_LONGTERM);
+ return ubifs_leb_change(c, UBIFS_SB_LNUM, sup, len);
}
/**
@@ -691,7 +685,7 @@ static int fixup_leb(struct ubifs_info *c, int lnum, int len)
if (err)
return err;
- return ubifs_leb_change(c, lnum, c->sbuf, len, UBI_UNKNOWN);
+ return ubifs_leb_change(c, lnum, c->sbuf, len);
}
/**
diff --git a/fs/ubifs/scan.c b/fs/ubifs/scan.c
index 37383e8011b1..7c40e6025fd6 100644
--- a/fs/ubifs/scan.c
+++ b/fs/ubifs/scan.c
@@ -101,7 +101,7 @@ int ubifs_scan_a_node(const struct ubifs_info *c, void *buf, int len, int lnum,
if (!quiet) {
ubifs_err("bad pad node at LEB %d:%d",
lnum, offs);
- dbg_dump_node(c, pad);
+ ubifs_dump_node(c, pad);
}
return SCANNED_A_BAD_PAD_NODE;
}
@@ -109,8 +109,8 @@ int ubifs_scan_a_node(const struct ubifs_info *c, void *buf, int len, int lnum,
/* Make the node pads to 8-byte boundary */
if ((node_len + pad_len) & 7) {
if (!quiet)
- dbg_err("bad padding length %d - %d",
- offs, offs + node_len + pad_len);
+ ubifs_err("bad padding length %d - %d",
+ offs, offs + node_len + pad_len);
return SCANNED_A_BAD_PAD_NODE;
}
@@ -245,7 +245,7 @@ void ubifs_scanned_corruption(const struct ubifs_info *c, int lnum, int offs,
len = c->leb_size - offs;
if (len > 8192)
len = 8192;
- dbg_err("first %d bytes from LEB %d:%d", len, lnum, offs);
+ ubifs_err("first %d bytes from LEB %d:%d", len, lnum, offs);
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 4, buf, len, 1);
}
@@ -300,16 +300,16 @@ struct ubifs_scan_leb *ubifs_scan(const struct ubifs_info *c, int lnum,
switch (ret) {
case SCANNED_GARBAGE:
- dbg_err("garbage");
+ ubifs_err("garbage");
goto corrupted;
case SCANNED_A_NODE:
break;
case SCANNED_A_CORRUPT_NODE:
case SCANNED_A_BAD_PAD_NODE:
- dbg_err("bad node");
+ ubifs_err("bad node");
goto corrupted;
default:
- dbg_err("unknown");
+ ubifs_err("unknown");
err = -EINVAL;
goto error;
}
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 76e4e0566ad6..001acccac0d6 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -246,8 +246,8 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
out_invalid:
ubifs_err("inode %lu validation failed, error %d", inode->i_ino, err);
- dbg_dump_node(c, ino);
- dbg_dump_inode(c, inode);
+ ubifs_dump_node(c, ino);
+ ubifs_dump_inode(c, inode);
err = -EINVAL;
out_ino:
kfree(ino);
@@ -668,8 +668,8 @@ static int init_constants_sb(struct ubifs_info *c)
tmp = UBIFS_CS_NODE_SZ + UBIFS_REF_NODE_SZ * c->jhead_cnt;
tmp = ALIGN(tmp, c->min_io_size);
if (tmp > c->leb_size) {
- dbg_err("too small LEB size %d, at least %d needed",
- c->leb_size, tmp);
+ ubifs_err("too small LEB size %d, at least %d needed",
+ c->leb_size, tmp);
return -EINVAL;
}
@@ -683,8 +683,8 @@ static int init_constants_sb(struct ubifs_info *c)
tmp /= c->leb_size;
tmp += 1;
if (c->log_lebs < tmp) {
- dbg_err("too small log %d LEBs, required min. %d LEBs",
- c->log_lebs, tmp);
+ ubifs_err("too small log %d LEBs, required min. %d LEBs",
+ c->log_lebs, tmp);
return -EINVAL;
}
@@ -813,13 +813,10 @@ static int alloc_wbufs(struct ubifs_info *c)
c->jheads[i].grouped = 1;
}
- c->jheads[BASEHD].wbuf.dtype = UBI_SHORTTERM;
/*
- * Garbage Collector head likely contains long-term data and
- * does not need to be synchronized by timer. Also GC head nodes are
- * not grouped.
+ * Garbage Collector head does not need to be synchronized by timer.
+ * Also GC head nodes are not grouped.
*/
- c->jheads[GCHD].wbuf.dtype = UBI_LONGTERM;
c->jheads[GCHD].wbuf.no_timer = 1;
c->jheads[GCHD].grouped = 0;
@@ -863,7 +860,7 @@ static void free_orphans(struct ubifs_info *c)
orph = list_entry(c->orph_list.next, struct ubifs_orphan, list);
list_del(&orph->list);
kfree(orph);
- dbg_err("orphan list not empty at unmount");
+ ubifs_err("orphan list not empty at unmount");
}
vfree(c->orph_buf);
@@ -1147,8 +1144,8 @@ static int check_free_space(struct ubifs_info *c)
ubifs_assert(c->dark_wm > 0);
if (c->lst.total_free + c->lst.total_dirty < c->dark_wm) {
ubifs_err("insufficient free space to mount in R/W mode");
- dbg_dump_budg(c, &c->bi);
- dbg_dump_lprops(c);
+ ubifs_dump_budg(c, &c->bi);
+ ubifs_dump_lprops(c);
return -ENOSPC;
}
return 0;
@@ -1301,7 +1298,7 @@ static int mount_ubifs(struct ubifs_info *c)
if (!c->ro_mount && c->space_fixup) {
err = ubifs_fixup_free_space(c);
if (err)
- goto out_master;
+ goto out_lpt;
}
if (!c->ro_mount) {
@@ -2126,8 +2123,8 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
*/
ubi = open_ubi(name, UBI_READONLY);
if (IS_ERR(ubi)) {
- dbg_err("cannot open \"%s\", error %d",
- name, (int)PTR_ERR(ubi));
+ ubifs_err("cannot open \"%s\", error %d",
+ name, (int)PTR_ERR(ubi));
return ERR_CAST(ubi);
}
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
index abd51331345e..349f31a30f40 100644
--- a/fs/ubifs/tnc.c
+++ b/fs/ubifs/tnc.c
@@ -339,8 +339,8 @@ static int lnc_add(struct ubifs_info *c, struct ubifs_zbranch *zbr,
err = ubifs_validate_entry(c, dent);
if (err) {
- dbg_dump_stack();
- dbg_dump_node(c, dent);
+ dump_stack();
+ ubifs_dump_node(c, dent);
return err;
}
@@ -372,8 +372,8 @@ static int lnc_add_directly(struct ubifs_info *c, struct ubifs_zbranch *zbr,
err = ubifs_validate_entry(c, node);
if (err) {
- dbg_dump_stack();
- dbg_dump_node(c, node);
+ dump_stack();
+ ubifs_dump_node(c, node);
return err;
}
@@ -1733,8 +1733,8 @@ out_err:
err = -EINVAL;
out:
ubifs_err("bad node at LEB %d:%d", zbr->lnum, zbr->offs);
- dbg_dump_node(c, buf);
- dbg_dump_stack();
+ ubifs_dump_node(c, buf);
+ dump_stack();
return err;
}
@@ -1775,7 +1775,7 @@ int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
if (err && err != -EBADMSG) {
ubifs_err("failed to read from LEB %d:%d, error %d",
lnum, offs, err);
- dbg_dump_stack();
+ dump_stack();
dbg_tnck(&bu->key, "key ");
return err;
}
@@ -2403,7 +2403,7 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
err = ubifs_add_dirt(c, zbr->lnum, zbr->len);
if (err) {
- dbg_dump_znode(c, znode);
+ ubifs_dump_znode(c, znode);
return err;
}
@@ -2649,7 +2649,7 @@ int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
err = ubifs_add_dirt(c, znode->zbranch[i].lnum,
znode->zbranch[i].len);
if (err) {
- dbg_dump_znode(c, znode);
+ ubifs_dump_znode(c, znode);
goto out_unlock;
}
dbg_tnck(key, "removing key ");
@@ -3275,8 +3275,6 @@ out_unlock:
return err;
}
-#ifdef CONFIG_UBIFS_FS_DEBUG
-
/**
* dbg_check_inode_size - check if inode size is correct.
* @c: UBIFS file-system description object
@@ -3335,13 +3333,11 @@ out_dump:
(unsigned long)inode->i_ino, size,
((loff_t)block) << UBIFS_BLOCK_SHIFT);
mutex_unlock(&c->tnc_mutex);
- dbg_dump_inode(c, inode);
- dbg_dump_stack();
+ ubifs_dump_inode(c, inode);
+ dump_stack();
return -EINVAL;
out_unlock:
mutex_unlock(&c->tnc_mutex);
return err;
}
-
-#endif /* CONFIG_UBIFS_FS_DEBUG */
diff --git a/fs/ubifs/tnc_commit.c b/fs/ubifs/tnc_commit.c
index 4c15f07a8bb2..523bbad69c0c 100644
--- a/fs/ubifs/tnc_commit.c
+++ b/fs/ubifs/tnc_commit.c
@@ -54,18 +54,16 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
br->len = cpu_to_le32(zbr->len);
if (!zbr->lnum || !zbr->len) {
ubifs_err("bad ref in znode");
- dbg_dump_znode(c, znode);
+ ubifs_dump_znode(c, znode);
if (zbr->znode)
- dbg_dump_znode(c, zbr->znode);
+ ubifs_dump_znode(c, zbr->znode);
}
}
ubifs_prepare_node(c, idx, len, 0);
-#ifdef CONFIG_UBIFS_FS_DEBUG
znode->lnum = lnum;
znode->offs = offs;
znode->len = len;
-#endif
err = insert_old_idx_znode(c, znode);
@@ -322,8 +320,7 @@ static int layout_leb_in_gaps(struct ubifs_info *c, int *p)
0, 0, 0);
if (err)
return err;
- err = ubifs_leb_change(c, lnum, c->ileb_buf, c->ileb_len,
- UBI_SHORTTERM);
+ err = ubifs_leb_change(c, lnum, c->ileb_buf, c->ileb_len);
if (err)
return err;
dbg_gc("LEB %d wrote %d index nodes", lnum, tot_written);
@@ -388,8 +385,8 @@ static int layout_in_gaps(struct ubifs_info *c, int cnt)
* option which forces in-the-gaps is enabled.
*/
ubifs_warn("out of space");
- dbg_dump_budg(c, &c->bi);
- dbg_dump_lprops(c);
+ ubifs_dump_budg(c, &c->bi);
+ ubifs_dump_lprops(c);
}
/* Try to commit anyway */
err = 0;
@@ -456,11 +453,9 @@ static int layout_in_empty_space(struct ubifs_info *c)
offs = buf_offs + used;
-#ifdef CONFIG_UBIFS_FS_DEBUG
znode->lnum = lnum;
znode->offs = offs;
znode->len = len;
-#endif
/* Update the parent */
zp = znode->parent;
@@ -536,10 +531,8 @@ static int layout_in_empty_space(struct ubifs_info *c)
break;
}
-#ifdef CONFIG_UBIFS_FS_DEBUG
c->dbg->new_ihead_lnum = lnum;
c->dbg->new_ihead_offs = buf_offs;
-#endif
return 0;
}
@@ -864,9 +857,9 @@ static int write_index(struct ubifs_info *c)
br->len = cpu_to_le32(zbr->len);
if (!zbr->lnum || !zbr->len) {
ubifs_err("bad ref in znode");
- dbg_dump_znode(c, znode);
+ ubifs_dump_znode(c, znode);
if (zbr->znode)
- dbg_dump_znode(c, zbr->znode);
+ ubifs_dump_znode(c, zbr->znode);
}
}
len = ubifs_idx_node_sz(c, znode->child_cnt);
@@ -881,13 +874,11 @@ static int write_index(struct ubifs_info *c)
}
offs = buf_offs + used;
-#ifdef CONFIG_UBIFS_FS_DEBUG
if (lnum != znode->lnum || offs != znode->offs ||
len != znode->len) {
ubifs_err("inconsistent znode posn");
return -EINVAL;
}
-#endif
/* Grab some stuff from znode while we still can */
cnext = znode->cnext;
@@ -959,8 +950,7 @@ static int write_index(struct ubifs_info *c)
}
/* The buffer is full or there are no more znodes to do */
- err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs, blen,
- UBI_SHORTTERM);
+ err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs, blen);
if (err)
return err;
buf_offs += blen;
@@ -982,13 +972,11 @@ static int write_index(struct ubifs_info *c)
break;
}
-#ifdef CONFIG_UBIFS_FS_DEBUG
if (lnum != c->dbg->new_ihead_lnum ||
buf_offs != c->dbg->new_ihead_offs) {
ubifs_err("inconsistent ihead");
return -EINVAL;
}
-#endif
c->ihead_lnum = lnum;
c->ihead_offs = buf_offs;
diff --git a/fs/ubifs/tnc_misc.c b/fs/ubifs/tnc_misc.c
index dc28fe6ec07a..d38ac7f9654b 100644
--- a/fs/ubifs/tnc_misc.c
+++ b/fs/ubifs/tnc_misc.c
@@ -293,10 +293,10 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
lnum, offs, znode->level, znode->child_cnt);
if (znode->child_cnt > c->fanout || znode->level > UBIFS_MAX_LEVELS) {
- dbg_err("current fanout %d, branch count %d",
- c->fanout, znode->child_cnt);
- dbg_err("max levels %d, znode level %d",
- UBIFS_MAX_LEVELS, znode->level);
+ ubifs_err("current fanout %d, branch count %d",
+ c->fanout, znode->child_cnt);
+ ubifs_err("max levels %d, znode level %d",
+ UBIFS_MAX_LEVELS, znode->level);
err = 1;
goto out_dump;
}
@@ -316,7 +316,7 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
if (zbr->lnum < c->main_first ||
zbr->lnum >= c->leb_cnt || zbr->offs < 0 ||
zbr->offs + zbr->len > c->leb_size || zbr->offs & 7) {
- dbg_err("bad branch %d", i);
+ ubifs_err("bad branch %d", i);
err = 2;
goto out_dump;
}
@@ -340,19 +340,19 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
type = key_type(c, &zbr->key);
if (c->ranges[type].max_len == 0) {
if (zbr->len != c->ranges[type].len) {
- dbg_err("bad target node (type %d) length (%d)",
- type, zbr->len);
- dbg_err("have to be %d", c->ranges[type].len);
+ ubifs_err("bad target node (type %d) length (%d)",
+ type, zbr->len);
+ ubifs_err("have to be %d", c->ranges[type].len);
err = 4;
goto out_dump;
}
} else if (zbr->len < c->ranges[type].min_len ||
zbr->len > c->ranges[type].max_len) {
- dbg_err("bad target node (type %d) length (%d)",
- type, zbr->len);
- dbg_err("have to be in range of %d-%d",
- c->ranges[type].min_len,
- c->ranges[type].max_len);
+ ubifs_err("bad target node (type %d) length (%d)",
+ type, zbr->len);
+ ubifs_err("have to be in range of %d-%d",
+ c->ranges[type].min_len,
+ c->ranges[type].max_len);
err = 5;
goto out_dump;
}
@@ -370,13 +370,13 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
cmp = keys_cmp(c, key1, key2);
if (cmp > 0) {
- dbg_err("bad key order (keys %d and %d)", i, i + 1);
+ ubifs_err("bad key order (keys %d and %d)", i, i + 1);
err = 6;
goto out_dump;
} else if (cmp == 0 && !is_hash_key(c, key1)) {
/* These can only be keys with colliding hash */
- dbg_err("keys %d and %d are not hashed but equivalent",
- i, i + 1);
+ ubifs_err("keys %d and %d are not hashed but equivalent",
+ i, i + 1);
err = 7;
goto out_dump;
}
@@ -387,7 +387,7 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len,
out_dump:
ubifs_err("bad indexing node at LEB %d:%d, error %d", lnum, offs, err);
- dbg_dump_node(c, idx);
+ ubifs_dump_node(c, idx);
kfree(idx);
return -EINVAL;
}
@@ -486,7 +486,7 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
zbr->lnum, zbr->offs);
dbg_tnck(key, "looked for key ");
dbg_tnck(&key1, "but found node's key ");
- dbg_dump_node(c, node);
+ ubifs_dump_node(c, node);
return -EINVAL;
}
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 93d59aceaaef..1e5a08623d11 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -650,8 +650,6 @@ typedef int (*ubifs_lpt_scan_callback)(struct ubifs_info *c,
* @avail: number of bytes available in the write-buffer
* @used: number of used bytes in the write-buffer
* @size: write-buffer size (in [@c->min_io_size, @c->max_write_size] range)
- * @dtype: type of data stored in this LEB (%UBI_LONGTERM, %UBI_SHORTTERM,
- * %UBI_UNKNOWN)
* @jhead: journal head the mutex belongs to (note, needed only to shut lockdep
* up by 'mutex_lock_nested()).
* @sync_callback: write-buffer synchronization callback
@@ -685,7 +683,6 @@ struct ubifs_wbuf {
int avail;
int used;
int size;
- int dtype;
int jhead;
int (*sync_callback)(struct ubifs_info *c, int lnum, int free, int pad);
struct mutex io_mutex;
@@ -762,6 +759,9 @@ struct ubifs_zbranch {
* @offs: offset of the corresponding indexing node
* @len: length of the corresponding indexing node
* @zbranch: array of znode branches (@c->fanout elements)
+ *
+ * Note! The @lnum, @offs, and @len fields are not really needed - we have them
+ * only for internal consistency check. They could be removed to save some RAM.
*/
struct ubifs_znode {
struct ubifs_znode *parent;
@@ -772,9 +772,9 @@ struct ubifs_znode {
int child_cnt;
int iip;
int alt;
-#ifdef CONFIG_UBIFS_FS_DEBUG
- int lnum, offs, len;
-#endif
+ int lnum;
+ int offs;
+ int len;
struct ubifs_zbranch zbranch[];
};
@@ -1444,9 +1444,7 @@ struct ubifs_info {
struct rb_root size_tree;
struct ubifs_mount_opts mount_opts;
-#ifdef CONFIG_UBIFS_FS_DEBUG
struct ubifs_debug_info *dbg;
-#endif
};
extern struct list_head ubifs_infos;
@@ -1468,22 +1466,20 @@ void ubifs_ro_mode(struct ubifs_info *c, int err);
int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs,
int len, int even_ebadmsg);
int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
- int len, int dtype);
-int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len,
- int dtype);
+ int len);
+int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len);
int ubifs_leb_unmap(struct ubifs_info *c, int lnum);
-int ubifs_leb_map(struct ubifs_info *c, int lnum, int dtype);
+int ubifs_leb_map(struct ubifs_info *c, int lnum);
int ubifs_is_mapped(const struct ubifs_info *c, int lnum);
int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len);
-int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs,
- int dtype);
+int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs);
int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf);
int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
int lnum, int offs);
int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
int lnum, int offs);
int ubifs_write_node(struct ubifs_info *c, void *node, int len, int lnum,
- int offs, int dtype);
+ int offs);
int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
int offs, int quiet, int must_chk_crc);
void ubifs_prepare_node(struct ubifs_info *c, void *buf, int len, int pad);
diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
index 7a8bafa19c9f..0f7139bdb2c2 100644
--- a/fs/ubifs/xattr.c
+++ b/fs/ubifs/xattr.c
@@ -399,8 +399,8 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf,
if (buf) {
/* If @buf is %NULL we are supposed to return the length */
if (ui->data_len > size) {
- dbg_err("buffer size %zd, xattr len %d",
- size, ui->data_len);
+ ubifs_err("buffer size %zd, xattr len %d",
+ size, ui->data_len);
err = -ERANGE;
goto out_iput;
}
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index 0a9977983f92..d2bf974b1a2f 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -33,6 +33,7 @@ xfs-y += xfs_aops.o \
xfs_discard.o \
xfs_error.o \
xfs_export.o \
+ xfs_extent_busy.o \
xfs_file.o \
xfs_filestream.o \
xfs_fsops.o \
@@ -49,7 +50,6 @@ xfs-y += xfs_aops.o \
xfs_sync.o \
xfs_xattr.o \
xfs_rename.o \
- xfs_rw.o \
xfs_utils.o \
xfs_vnodeops.o \
kmem.o \
diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h
index 4805f009f923..44d65c1533c0 100644
--- a/fs/xfs/xfs_ag.h
+++ b/fs/xfs/xfs_ag.h
@@ -175,24 +175,6 @@ typedef struct xfs_agfl {
} xfs_agfl_t;
/*
- * Busy block/extent entry. Indexed by a rbtree in perag to mark blocks that
- * have been freed but whose transactions aren't committed to disk yet.
- *
- * Note that we use the transaction ID to record the transaction, not the
- * transaction structure itself. See xfs_alloc_busy_insert() for details.
- */
-struct xfs_busy_extent {
- struct rb_node rb_node; /* ag by-bno indexed search tree */
- struct list_head list; /* transaction busy extent list */
- xfs_agnumber_t agno;
- xfs_agblock_t bno;
- xfs_extlen_t length;
- unsigned int flags;
-#define XFS_ALLOC_BUSY_DISCARDED 0x01 /* undergoing a discard op. */
-#define XFS_ALLOC_BUSY_SKIP_DISCARD 0x02 /* do not discard */
-};
-
-/*
* Per-ag incore structure, copies of information in agf and agi,
* to improve the performance of allocation group selection.
*/
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c
index 0f0df2759b09..229641fb8e67 100644
--- a/fs/xfs/xfs_alloc.c
+++ b/fs/xfs/xfs_alloc.c
@@ -20,7 +20,6 @@
#include "xfs_types.h"
#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
@@ -32,6 +31,7 @@
#include "xfs_inode.h"
#include "xfs_btree.h"
#include "xfs_alloc.h"
+#include "xfs_extent_busy.h"
#include "xfs_error.h"
#include "xfs_trace.h"
@@ -47,8 +47,6 @@ STATIC int xfs_alloc_ag_vextent_near(xfs_alloc_arg_t *);
STATIC int xfs_alloc_ag_vextent_size(xfs_alloc_arg_t *);
STATIC int xfs_alloc_ag_vextent_small(xfs_alloc_arg_t *,
xfs_btree_cur_t *, xfs_agblock_t *, xfs_extlen_t *, int *);
-STATIC void xfs_alloc_busy_trim(struct xfs_alloc_arg *,
- xfs_agblock_t, xfs_extlen_t, xfs_agblock_t *, xfs_extlen_t *);
/*
* Lookup the record equal to [bno, len] in the btree given by cur.
@@ -152,7 +150,7 @@ xfs_alloc_compute_aligned(
xfs_extlen_t len;
/* Trim busy sections out of found extent */
- xfs_alloc_busy_trim(args, foundbno, foundlen, &bno, &len);
+ xfs_extent_busy_trim(args, foundbno, foundlen, &bno, &len);
if (args->alignment > 1 && len >= args->minlen) {
xfs_agblock_t aligned_bno = roundup(bno, args->alignment);
@@ -536,7 +534,7 @@ xfs_alloc_ag_vextent(
if (error)
return error;
- ASSERT(!xfs_alloc_busy_search(args->mp, args->agno,
+ ASSERT(!xfs_extent_busy_search(args->mp, args->agno,
args->agbno, args->len));
}
@@ -603,7 +601,7 @@ xfs_alloc_ag_vextent_exact(
/*
* Check for overlapping busy extents.
*/
- xfs_alloc_busy_trim(args, fbno, flen, &tbno, &tlen);
+ xfs_extent_busy_trim(args, fbno, flen, &tbno, &tlen);
/*
* Give up if the start of the extent is busy, or the freespace isn't
@@ -1391,7 +1389,7 @@ xfs_alloc_ag_vextent_small(
if (error)
goto error0;
if (fbno != NULLAGBLOCK) {
- xfs_alloc_busy_reuse(args->mp, args->agno, fbno, 1,
+ xfs_extent_busy_reuse(args->mp, args->agno, fbno, 1,
args->userdata);
if (args->userdata) {
@@ -2496,579 +2494,8 @@ xfs_free_extent(
error = xfs_free_ag_extent(tp, args.agbp, args.agno, args.agbno, len, 0);
if (!error)
- xfs_alloc_busy_insert(tp, args.agno, args.agbno, len, 0);
+ xfs_extent_busy_insert(tp, args.agno, args.agbno, len, 0);
error0:
xfs_perag_put(args.pag);
return error;
}
-
-void
-xfs_alloc_busy_insert(
- struct xfs_trans *tp,
- xfs_agnumber_t agno,
- xfs_agblock_t bno,
- xfs_extlen_t len,
- unsigned int flags)
-{
- struct xfs_busy_extent *new;
- struct xfs_busy_extent *busyp;
- struct xfs_perag *pag;
- struct rb_node **rbp;
- struct rb_node *parent = NULL;
-
- new = kmem_zalloc(sizeof(struct xfs_busy_extent), KM_MAYFAIL);
- if (!new) {
- /*
- * No Memory! Since it is now not possible to track the free
- * block, make this a synchronous transaction to insure that
- * the block is not reused before this transaction commits.
- */
- trace_xfs_alloc_busy_enomem(tp->t_mountp, agno, bno, len);
- xfs_trans_set_sync(tp);
- return;
- }
-
- new->agno = agno;
- new->bno = bno;
- new->length = len;
- INIT_LIST_HEAD(&new->list);
- new->flags = flags;
-
- /* trace before insert to be able to see failed inserts */
- trace_xfs_alloc_busy(tp->t_mountp, agno, bno, len);
-
- pag = xfs_perag_get(tp->t_mountp, new->agno);
- spin_lock(&pag->pagb_lock);
- rbp = &pag->pagb_tree.rb_node;
- while (*rbp) {
- parent = *rbp;
- busyp = rb_entry(parent, struct xfs_busy_extent, rb_node);
-
- if (new->bno < busyp->bno) {
- rbp = &(*rbp)->rb_left;
- ASSERT(new->bno + new->length <= busyp->bno);
- } else if (new->bno > busyp->bno) {
- rbp = &(*rbp)->rb_right;
- ASSERT(bno >= busyp->bno + busyp->length);
- } else {
- ASSERT(0);
- }
- }
-
- rb_link_node(&new->rb_node, parent, rbp);
- rb_insert_color(&new->rb_node, &pag->pagb_tree);
-
- list_add(&new->list, &tp->t_busy);
- spin_unlock(&pag->pagb_lock);
- xfs_perag_put(pag);
-}
-
-/*
- * Search for a busy extent within the range of the extent we are about to
- * allocate. You need to be holding the busy extent tree lock when calling
- * xfs_alloc_busy_search(). This function returns 0 for no overlapping busy
- * extent, -1 for an overlapping but not exact busy extent, and 1 for an exact
- * match. This is done so that a non-zero return indicates an overlap that
- * will require a synchronous transaction, but it can still be
- * used to distinguish between a partial or exact match.
- */
-int
-xfs_alloc_busy_search(
- struct xfs_mount *mp,
- xfs_agnumber_t agno,
- xfs_agblock_t bno,
- xfs_extlen_t len)
-{
- struct xfs_perag *pag;
- struct rb_node *rbp;
- struct xfs_busy_extent *busyp;
- int match = 0;
-
- pag = xfs_perag_get(mp, agno);
- spin_lock(&pag->pagb_lock);
-
- rbp = pag->pagb_tree.rb_node;
-
- /* find closest start bno overlap */
- while (rbp) {
- busyp = rb_entry(rbp, struct xfs_busy_extent, rb_node);
- if (bno < busyp->bno) {
- /* may overlap, but exact start block is lower */
- if (bno + len > busyp->bno)
- match = -1;
- rbp = rbp->rb_left;
- } else if (bno > busyp->bno) {
- /* may overlap, but exact start block is higher */
- if (bno < busyp->bno + busyp->length)
- match = -1;
- rbp = rbp->rb_right;
- } else {
- /* bno matches busyp, length determines exact match */
- match = (busyp->length == len) ? 1 : -1;
- break;
- }
- }
- spin_unlock(&pag->pagb_lock);
- xfs_perag_put(pag);
- return match;
-}
-
-/*
- * The found free extent [fbno, fend] overlaps part or all of the given busy
- * extent. If the overlap covers the beginning, the end, or all of the busy
- * extent, the overlapping portion can be made unbusy and used for the
- * allocation. We can't split a busy extent because we can't modify a
- * transaction/CIL context busy list, but we can update an entries block
- * number or length.
- *
- * Returns true if the extent can safely be reused, or false if the search
- * needs to be restarted.
- */
-STATIC bool
-xfs_alloc_busy_update_extent(
- struct xfs_mount *mp,
- struct xfs_perag *pag,
- struct xfs_busy_extent *busyp,
- xfs_agblock_t fbno,
- xfs_extlen_t flen,
- bool userdata)
-{
- xfs_agblock_t fend = fbno + flen;
- xfs_agblock_t bbno = busyp->bno;
- xfs_agblock_t bend = bbno + busyp->length;
-
- /*
- * This extent is currently being discarded. Give the thread
- * performing the discard a chance to mark the extent unbusy
- * and retry.
- */
- if (busyp->flags & XFS_ALLOC_BUSY_DISCARDED) {
- spin_unlock(&pag->pagb_lock);
- delay(1);
- spin_lock(&pag->pagb_lock);
- return false;
- }
-
- /*
- * If there is a busy extent overlapping a user allocation, we have
- * no choice but to force the log and retry the search.
- *
- * Fortunately this does not happen during normal operation, but
- * only if the filesystem is very low on space and has to dip into
- * the AGFL for normal allocations.
- */
- if (userdata)
- goto out_force_log;
-
- if (bbno < fbno && bend > fend) {
- /*
- * Case 1:
- * bbno bend
- * +BBBBBBBBBBBBBBBBB+
- * +---------+
- * fbno fend
- */
-
- /*
- * We would have to split the busy extent to be able to track
- * it correct, which we cannot do because we would have to
- * modify the list of busy extents attached to the transaction
- * or CIL context, which is immutable.
- *
- * Force out the log to clear the busy extent and retry the
- * search.
- */
- goto out_force_log;
- } else if (bbno >= fbno && bend <= fend) {
- /*
- * Case 2:
- * bbno bend
- * +BBBBBBBBBBBBBBBBB+
- * +-----------------+
- * fbno fend
- *
- * Case 3:
- * bbno bend
- * +BBBBBBBBBBBBBBBBB+
- * +--------------------------+
- * fbno fend
- *
- * Case 4:
- * bbno bend
- * +BBBBBBBBBBBBBBBBB+
- * +--------------------------+
- * fbno fend
- *
- * Case 5:
- * bbno bend
- * +BBBBBBBBBBBBBBBBB+
- * +-----------------------------------+
- * fbno fend
- *
- */
-
- /*
- * The busy extent is fully covered by the extent we are
- * allocating, and can simply be removed from the rbtree.
- * However we cannot remove it from the immutable list
- * tracking busy extents in the transaction or CIL context,
- * so set the length to zero to mark it invalid.
- *
- * We also need to restart the busy extent search from the
- * tree root, because erasing the node can rearrange the
- * tree topology.
- */
- rb_erase(&busyp->rb_node, &pag->pagb_tree);
- busyp->length = 0;
- return false;
- } else if (fend < bend) {
- /*
- * Case 6:
- * bbno bend
- * +BBBBBBBBBBBBBBBBB+
- * +---------+
- * fbno fend
- *
- * Case 7:
- * bbno bend
- * +BBBBBBBBBBBBBBBBB+
- * +------------------+
- * fbno fend
- *
- */
- busyp->bno = fend;
- } else if (bbno < fbno) {
- /*
- * Case 8:
- * bbno bend
- * +BBBBBBBBBBBBBBBBB+
- * +-------------+
- * fbno fend
- *
- * Case 9:
- * bbno bend
- * +BBBBBBBBBBBBBBBBB+
- * +----------------------+
- * fbno fend
- */
- busyp->length = fbno - busyp->bno;
- } else {
- ASSERT(0);
- }
-
- trace_xfs_alloc_busy_reuse(mp, pag->pag_agno, fbno, flen);
- return true;
-
-out_force_log:
- spin_unlock(&pag->pagb_lock);
- xfs_log_force(mp, XFS_LOG_SYNC);
- trace_xfs_alloc_busy_force(mp, pag->pag_agno, fbno, flen);
- spin_lock(&pag->pagb_lock);
- return false;
-}
-
-
-/*
- * For a given extent [fbno, flen], make sure we can reuse it safely.
- */
-void
-xfs_alloc_busy_reuse(
- struct xfs_mount *mp,
- xfs_agnumber_t agno,
- xfs_agblock_t fbno,
- xfs_extlen_t flen,
- bool userdata)
-{
- struct xfs_perag *pag;
- struct rb_node *rbp;
-
- ASSERT(flen > 0);
-
- pag = xfs_perag_get(mp, agno);
- spin_lock(&pag->pagb_lock);
-restart:
- rbp = pag->pagb_tree.rb_node;
- while (rbp) {
- struct xfs_busy_extent *busyp =
- rb_entry(rbp, struct xfs_busy_extent, rb_node);
- xfs_agblock_t bbno = busyp->bno;
- xfs_agblock_t bend = bbno + busyp->length;
-
- if (fbno + flen <= bbno) {
- rbp = rbp->rb_left;
- continue;
- } else if (fbno >= bend) {
- rbp = rbp->rb_right;
- continue;
- }
-
- if (!xfs_alloc_busy_update_extent(mp, pag, busyp, fbno, flen,
- userdata))
- goto restart;
- }
- spin_unlock(&pag->pagb_lock);
- xfs_perag_put(pag);
-}
-
-/*
- * For a given extent [fbno, flen], search the busy extent list to find a
- * subset of the extent that is not busy. If *rlen is smaller than
- * args->minlen no suitable extent could be found, and the higher level
- * code needs to force out the log and retry the allocation.
- */
-STATIC void
-xfs_alloc_busy_trim(
- struct xfs_alloc_arg *args,
- xfs_agblock_t bno,
- xfs_extlen_t len,
- xfs_agblock_t *rbno,
- xfs_extlen_t *rlen)
-{
- xfs_agblock_t fbno;
- xfs_extlen_t flen;
- struct rb_node *rbp;
-
- ASSERT(len > 0);
-
- spin_lock(&args->pag->pagb_lock);
-restart:
- fbno = bno;
- flen = len;
- rbp = args->pag->pagb_tree.rb_node;
- while (rbp && flen >= args->minlen) {
- struct xfs_busy_extent *busyp =
- rb_entry(rbp, struct xfs_busy_extent, rb_node);
- xfs_agblock_t fend = fbno + flen;
- xfs_agblock_t bbno = busyp->bno;
- xfs_agblock_t bend = bbno + busyp->length;
-
- if (fend <= bbno) {
- rbp = rbp->rb_left;
- continue;
- } else if (fbno >= bend) {
- rbp = rbp->rb_right;
- continue;
- }
-
- /*
- * If this is a metadata allocation, try to reuse the busy
- * extent instead of trimming the allocation.
- */
- if (!args->userdata &&
- !(busyp->flags & XFS_ALLOC_BUSY_DISCARDED)) {
- if (!xfs_alloc_busy_update_extent(args->mp, args->pag,
- busyp, fbno, flen,
- false))
- goto restart;
- continue;
- }
-
- if (bbno <= fbno) {
- /* start overlap */
-
- /*
- * Case 1:
- * bbno bend
- * +BBBBBBBBBBBBBBBBB+
- * +---------+
- * fbno fend
- *
- * Case 2:
- * bbno bend
- * +BBBBBBBBBBBBBBBBB+
- * +-------------+
- * fbno fend
- *
- * Case 3:
- * bbno bend
- * +BBBBBBBBBBBBBBBBB+
- * +-------------+
- * fbno fend
- *
- * Case 4:
- * bbno bend
- * +BBBBBBBBBBBBBBBBB+
- * +-----------------+
- * fbno fend
- *
- * No unbusy region in extent, return failure.
- */
- if (fend <= bend)
- goto fail;
-
- /*
- * Case 5:
- * bbno bend
- * +BBBBBBBBBBBBBBBBB+
- * +----------------------+
- * fbno fend
- *
- * Case 6:
- * bbno bend
- * +BBBBBBBBBBBBBBBBB+
- * +--------------------------+
- * fbno fend
- *
- * Needs to be trimmed to:
- * +-------+
- * fbno fend
- */
- fbno = bend;
- } else if (bend >= fend) {
- /* end overlap */
-
- /*
- * Case 7:
- * bbno bend
- * +BBBBBBBBBBBBBBBBB+
- * +------------------+
- * fbno fend
- *
- * Case 8:
- * bbno bend
- * +BBBBBBBBBBBBBBBBB+
- * +--------------------------+
- * fbno fend
- *
- * Needs to be trimmed to:
- * +-------+
- * fbno fend
- */
- fend = bbno;
- } else {
- /* middle overlap */
-
- /*
- * Case 9:
- * bbno bend
- * +BBBBBBBBBBBBBBBBB+
- * +-----------------------------------+
- * fbno fend
- *
- * Can be trimmed to:
- * +-------+ OR +-------+
- * fbno fend fbno fend
- *
- * Backward allocation leads to significant
- * fragmentation of directories, which degrades
- * directory performance, therefore we always want to
- * choose the option that produces forward allocation
- * patterns.
- * Preferring the lower bno extent will make the next
- * request use "fend" as the start of the next
- * allocation; if the segment is no longer busy at
- * that point, we'll get a contiguous allocation, but
- * even if it is still busy, we will get a forward
- * allocation.
- * We try to avoid choosing the segment at "bend",
- * because that can lead to the next allocation
- * taking the segment at "fbno", which would be a
- * backward allocation. We only use the segment at
- * "fbno" if it is much larger than the current
- * requested size, because in that case there's a
- * good chance subsequent allocations will be
- * contiguous.
- */
- if (bbno - fbno >= args->maxlen) {
- /* left candidate fits perfect */
- fend = bbno;
- } else if (fend - bend >= args->maxlen * 4) {
- /* right candidate has enough free space */
- fbno = bend;
- } else if (bbno - fbno >= args->minlen) {
- /* left candidate fits minimum requirement */
- fend = bbno;
- } else {
- goto fail;
- }
- }
-
- flen = fend - fbno;
- }
- spin_unlock(&args->pag->pagb_lock);
-
- if (fbno != bno || flen != len) {
- trace_xfs_alloc_busy_trim(args->mp, args->agno, bno, len,
- fbno, flen);
- }
- *rbno = fbno;
- *rlen = flen;
- return;
-fail:
- /*
- * Return a zero extent length as failure indications. All callers
- * re-check if the trimmed extent satisfies the minlen requirement.
- */
- spin_unlock(&args->pag->pagb_lock);
- trace_xfs_alloc_busy_trim(args->mp, args->agno, bno, len, fbno, 0);
- *rbno = fbno;
- *rlen = 0;
-}
-
-static void
-xfs_alloc_busy_clear_one(
- struct xfs_mount *mp,
- struct xfs_perag *pag,
- struct xfs_busy_extent *busyp)
-{
- if (busyp->length) {
- trace_xfs_alloc_busy_clear(mp, busyp->agno, busyp->bno,
- busyp->length);
- rb_erase(&busyp->rb_node, &pag->pagb_tree);
- }
-
- list_del_init(&busyp->list);
- kmem_free(busyp);
-}
-
-/*
- * Remove all extents on the passed in list from the busy extents tree.
- * If do_discard is set skip extents that need to be discarded, and mark
- * these as undergoing a discard operation instead.
- */
-void
-xfs_alloc_busy_clear(
- struct xfs_mount *mp,
- struct list_head *list,
- bool do_discard)
-{
- struct xfs_busy_extent *busyp, *n;
- struct xfs_perag *pag = NULL;
- xfs_agnumber_t agno = NULLAGNUMBER;
-
- list_for_each_entry_safe(busyp, n, list, list) {
- if (busyp->agno != agno) {
- if (pag) {
- spin_unlock(&pag->pagb_lock);
- xfs_perag_put(pag);
- }
- pag = xfs_perag_get(mp, busyp->agno);
- spin_lock(&pag->pagb_lock);
- agno = busyp->agno;
- }
-
- if (do_discard && busyp->length &&
- !(busyp->flags & XFS_ALLOC_BUSY_SKIP_DISCARD))
- busyp->flags = XFS_ALLOC_BUSY_DISCARDED;
- else
- xfs_alloc_busy_clear_one(mp, pag, busyp);
- }
-
- if (pag) {
- spin_unlock(&pag->pagb_lock);
- xfs_perag_put(pag);
- }
-}
-
-/*
- * Callback for list_sort to sort busy extents by the AG they reside in.
- */
-int
-xfs_busy_extent_ag_cmp(
- void *priv,
- struct list_head *a,
- struct list_head *b)
-{
- return container_of(a, struct xfs_busy_extent, list)->agno -
- container_of(b, struct xfs_busy_extent, list)->agno;
-}
diff --git a/fs/xfs/xfs_alloc.h b/fs/xfs/xfs_alloc.h
index 3a7e7d8f8ded..93be4a667ca1 100644
--- a/fs/xfs/xfs_alloc.h
+++ b/fs/xfs/xfs_alloc.h
@@ -23,7 +23,6 @@ struct xfs_btree_cur;
struct xfs_mount;
struct xfs_perag;
struct xfs_trans;
-struct xfs_busy_extent;
extern struct workqueue_struct *xfs_alloc_wq;
@@ -139,33 +138,6 @@ xfs_extlen_t
xfs_alloc_longest_free_extent(struct xfs_mount *mp,
struct xfs_perag *pag);
-#ifdef __KERNEL__
-void
-xfs_alloc_busy_insert(struct xfs_trans *tp, xfs_agnumber_t agno,
- xfs_agblock_t bno, xfs_extlen_t len, unsigned int flags);
-
-void
-xfs_alloc_busy_clear(struct xfs_mount *mp, struct list_head *list,
- bool do_discard);
-
-int
-xfs_alloc_busy_search(struct xfs_mount *mp, xfs_agnumber_t agno,
- xfs_agblock_t bno, xfs_extlen_t len);
-
-void
-xfs_alloc_busy_reuse(struct xfs_mount *mp, xfs_agnumber_t agno,
- xfs_agblock_t fbno, xfs_extlen_t flen, bool userdata);
-
-int
-xfs_busy_extent_ag_cmp(void *priv, struct list_head *a, struct list_head *b);
-
-static inline void xfs_alloc_busy_sort(struct list_head *list)
-{
- list_sort(NULL, list, xfs_busy_extent_ag_cmp);
-}
-
-#endif /* __KERNEL__ */
-
/*
* Compute and fill in value of m_ag_maxlevels.
*/
diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c
index ffb3386e45c1..f1647caace8f 100644
--- a/fs/xfs/xfs_alloc_btree.c
+++ b/fs/xfs/xfs_alloc_btree.c
@@ -18,9 +18,7 @@
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_types.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
@@ -32,6 +30,7 @@
#include "xfs_inode.h"
#include "xfs_btree.h"
#include "xfs_alloc.h"
+#include "xfs_extent_busy.h"
#include "xfs_error.h"
#include "xfs_trace.h"
@@ -94,7 +93,7 @@ xfs_allocbt_alloc_block(
return 0;
}
- xfs_alloc_busy_reuse(cur->bc_mp, cur->bc_private.a.agno, bno, 1, false);
+ xfs_extent_busy_reuse(cur->bc_mp, cur->bc_private.a.agno, bno, 1, false);
xfs_trans_agbtree_delta(cur->bc_tp, 1);
new->s = cpu_to_be32(bno);
@@ -119,8 +118,8 @@ xfs_allocbt_free_block(
if (error)
return error;
- xfs_alloc_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1,
- XFS_ALLOC_BUSY_SKIP_DISCARD);
+ xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1,
+ XFS_EXTENT_BUSY_SKIP_DISCARD);
xfs_trans_agbtree_delta(cur->bc_tp, -1);
return 0;
}
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index 0dbb9e70fe21..ae31c313a79e 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -16,9 +16,7 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "xfs.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_trans.h"
@@ -29,7 +27,6 @@
#include "xfs_inode_item.h"
#include "xfs_alloc.h"
#include "xfs_error.h"
-#include "xfs_rw.h"
#include "xfs_iomap.h"
#include "xfs_vnodeops.h"
#include "xfs_trace.h"
@@ -623,7 +620,7 @@ xfs_map_at_offset(
* or delayed allocate extent.
*/
STATIC int
-xfs_is_delayed_page(
+xfs_check_page_type(
struct page *page,
unsigned int type)
{
@@ -637,11 +634,11 @@ xfs_is_delayed_page(
bh = head = page_buffers(page);
do {
if (buffer_unwritten(bh))
- acceptable = (type == IO_UNWRITTEN);
+ acceptable += (type == IO_UNWRITTEN);
else if (buffer_delay(bh))
- acceptable = (type == IO_DELALLOC);
+ acceptable += (type == IO_DELALLOC);
else if (buffer_dirty(bh) && buffer_mapped(bh))
- acceptable = (type == IO_OVERWRITE);
+ acceptable += (type == IO_OVERWRITE);
else
break;
} while ((bh = bh->b_this_page) != head);
@@ -684,7 +681,7 @@ xfs_convert_page(
goto fail_unlock_page;
if (page->mapping != inode->i_mapping)
goto fail_unlock_page;
- if (!xfs_is_delayed_page(page, (*ioendp)->io_type))
+ if (!xfs_check_page_type(page, (*ioendp)->io_type))
goto fail_unlock_page;
/*
@@ -834,7 +831,7 @@ xfs_aops_discard_page(
struct buffer_head *bh, *head;
loff_t offset = page_offset(page);
- if (!xfs_is_delayed_page(page, IO_DELALLOC))
+ if (!xfs_check_page_type(page, IO_DELALLOC))
goto out_invalidate;
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
@@ -1146,7 +1143,14 @@ __xfs_get_blocks(
if (!create && direct && offset >= i_size_read(inode))
return 0;
- if (create) {
+ /*
+ * Direct I/O is usually done on preallocated files, so try getting
+ * a block mapping without an exclusive lock first. For buffered
+ * writes we already have the exclusive iolock anyway, so avoiding
+ * a lock roundtrip here by taking the ilock exclusive from the
+ * beginning is a useful micro optimization.
+ */
+ if (create && !direct) {
lockmode = XFS_ILOCK_EXCL;
xfs_ilock(ip, lockmode);
} else {
@@ -1168,23 +1172,45 @@ __xfs_get_blocks(
(!nimaps ||
(imap.br_startblock == HOLESTARTBLOCK ||
imap.br_startblock == DELAYSTARTBLOCK))) {
- if (direct) {
+ if (direct || xfs_get_extsz_hint(ip)) {
+ /*
+ * Drop the ilock in preparation for starting the block
+ * allocation transaction. It will be retaken
+ * exclusively inside xfs_iomap_write_direct for the
+ * actual allocation.
+ */
+ xfs_iunlock(ip, lockmode);
error = xfs_iomap_write_direct(ip, offset, size,
&imap, nimaps);
+ if (error)
+ return -error;
+ new = 1;
} else {
+ /*
+ * Delalloc reservations do not require a transaction,
+ * we can go on without dropping the lock here. If we
+ * are allocating a new delalloc block, make sure that
+ * we set the new flag so that we mark the buffer new so
+ * that we know that it is newly allocated if the write
+ * fails.
+ */
+ if (nimaps && imap.br_startblock == HOLESTARTBLOCK)
+ new = 1;
error = xfs_iomap_write_delay(ip, offset, size, &imap);
+ if (error)
+ goto out_unlock;
+
+ xfs_iunlock(ip, lockmode);
}
- if (error)
- goto out_unlock;
trace_xfs_get_blocks_alloc(ip, offset, size, 0, &imap);
} else if (nimaps) {
trace_xfs_get_blocks_found(ip, offset, size, 0, &imap);
+ xfs_iunlock(ip, lockmode);
} else {
trace_xfs_get_blocks_notfound(ip, offset, size);
goto out_unlock;
}
- xfs_iunlock(ip, lockmode);
if (imap.br_startblock != HOLESTARTBLOCK &&
imap.br_startblock != DELAYSTARTBLOCK) {
@@ -1386,52 +1412,91 @@ out_destroy_ioend:
return ret;
}
+/*
+ * Punch out the delalloc blocks we have already allocated.
+ *
+ * Don't bother with xfs_setattr given that nothing can have made it to disk yet
+ * as the page is still locked at this point.
+ */
+STATIC void
+xfs_vm_kill_delalloc_range(
+ struct inode *inode,
+ loff_t start,
+ loff_t end)
+{
+ struct xfs_inode *ip = XFS_I(inode);
+ xfs_fileoff_t start_fsb;
+ xfs_fileoff_t end_fsb;
+ int error;
+
+ start_fsb = XFS_B_TO_FSB(ip->i_mount, start);
+ end_fsb = XFS_B_TO_FSB(ip->i_mount, end);
+ if (end_fsb <= start_fsb)
+ return;
+
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
+ error = xfs_bmap_punch_delalloc_range(ip, start_fsb,
+ end_fsb - start_fsb);
+ if (error) {
+ /* something screwed, just bail */
+ if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
+ xfs_alert(ip->i_mount,
+ "xfs_vm_write_failed: unable to clean up ino %lld",
+ ip->i_ino);
+ }
+ }
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+}
+
STATIC void
xfs_vm_write_failed(
- struct address_space *mapping,
- loff_t to)
+ struct inode *inode,
+ struct page *page,
+ loff_t pos,
+ unsigned len)
{
- struct inode *inode = mapping->host;
+ loff_t block_offset = pos & PAGE_MASK;
+ loff_t block_start;
+ loff_t block_end;
+ loff_t from = pos & (PAGE_CACHE_SIZE - 1);
+ loff_t to = from + len;
+ struct buffer_head *bh, *head;
- if (to > inode->i_size) {
- /*
- * Punch out the delalloc blocks we have already allocated.
- *
- * Don't bother with xfs_setattr given that nothing can have
- * made it to disk yet as the page is still locked at this
- * point.
- */
- struct xfs_inode *ip = XFS_I(inode);
- xfs_fileoff_t start_fsb;
- xfs_fileoff_t end_fsb;
- int error;
+ ASSERT(block_offset + from == pos);
- truncate_pagecache(inode, to, inode->i_size);
+ head = page_buffers(page);
+ block_start = 0;
+ for (bh = head; bh != head || !block_start;
+ bh = bh->b_this_page, block_start = block_end,
+ block_offset += bh->b_size) {
+ block_end = block_start + bh->b_size;
- /*
- * Check if there are any blocks that are outside of i_size
- * that need to be trimmed back.
- */
- start_fsb = XFS_B_TO_FSB(ip->i_mount, inode->i_size) + 1;
- end_fsb = XFS_B_TO_FSB(ip->i_mount, to);
- if (end_fsb <= start_fsb)
- return;
-
- xfs_ilock(ip, XFS_ILOCK_EXCL);
- error = xfs_bmap_punch_delalloc_range(ip, start_fsb,
- end_fsb - start_fsb);
- if (error) {
- /* something screwed, just bail */
- if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
- xfs_alert(ip->i_mount,
- "xfs_vm_write_failed: unable to clean up ino %lld",
- ip->i_ino);
- }
- }
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ /* skip buffers before the write */
+ if (block_end <= from)
+ continue;
+
+ /* if the buffer is after the write, we're done */
+ if (block_start >= to)
+ break;
+
+ if (!buffer_delay(bh))
+ continue;
+
+ if (!buffer_new(bh) && block_offset < i_size_read(inode))
+ continue;
+
+ xfs_vm_kill_delalloc_range(inode, block_offset,
+ block_offset + bh->b_size);
}
+
}
+/*
+ * This used to call block_write_begin(), but it unlocks and releases the page
+ * on error, and we need that page to be able to punch stale delalloc blocks out
+ * on failure. hence we copy-n-waste it here and call xfs_vm_write_failed() at
+ * the appropriate point.
+ */
STATIC int
xfs_vm_write_begin(
struct file *file,
@@ -1442,15 +1507,40 @@ xfs_vm_write_begin(
struct page **pagep,
void **fsdata)
{
- int ret;
+ pgoff_t index = pos >> PAGE_CACHE_SHIFT;
+ struct page *page;
+ int status;
- ret = block_write_begin(mapping, pos, len, flags | AOP_FLAG_NOFS,
- pagep, xfs_get_blocks);
- if (unlikely(ret))
- xfs_vm_write_failed(mapping, pos + len);
- return ret;
+ ASSERT(len <= PAGE_CACHE_SIZE);
+
+ page = grab_cache_page_write_begin(mapping, index,
+ flags | AOP_FLAG_NOFS);
+ if (!page)
+ return -ENOMEM;
+
+ status = __block_write_begin(page, pos, len, xfs_get_blocks);
+ if (unlikely(status)) {
+ struct inode *inode = mapping->host;
+
+ xfs_vm_write_failed(inode, page, pos, len);
+ unlock_page(page);
+
+ if (pos + len > i_size_read(inode))
+ truncate_pagecache(inode, pos + len, i_size_read(inode));
+
+ page_cache_release(page);
+ page = NULL;
+ }
+
+ *pagep = page;
+ return status;
}
+/*
+ * On failure, we only need to kill delalloc blocks beyond EOF because they
+ * will never be written. For blocks within EOF, generic_write_end() zeros them
+ * so they are safe to leave alone and be written with all the other valid data.
+ */
STATIC int
xfs_vm_write_end(
struct file *file,
@@ -1463,9 +1553,19 @@ xfs_vm_write_end(
{
int ret;
+ ASSERT(len <= PAGE_CACHE_SIZE);
+
ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
- if (unlikely(ret < len))
- xfs_vm_write_failed(mapping, pos + len);
+ if (unlikely(ret < len)) {
+ struct inode *inode = mapping->host;
+ size_t isize = i_size_read(inode);
+ loff_t to = pos + len;
+
+ if (to > isize) {
+ truncate_pagecache(inode, to, isize);
+ xfs_vm_kill_delalloc_range(inode, isize, to);
+ }
+ }
return ret;
}
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c
index 65d61b948ead..a17ff01b5adf 100644
--- a/fs/xfs/xfs_attr.c
+++ b/fs/xfs/xfs_attr.c
@@ -21,7 +21,6 @@
#include "xfs_types.h"
#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
@@ -39,7 +38,6 @@
#include "xfs_error.h"
#include "xfs_quota.h"
#include "xfs_trans_space.h"
-#include "xfs_rw.h"
#include "xfs_vnodeops.h"
#include "xfs_trace.h"
@@ -1987,14 +1985,12 @@ xfs_attr_rmtval_get(xfs_da_args_t *args)
(map[i].br_startblock != HOLESTARTBLOCK));
dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock);
blkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount);
- error = xfs_read_buf(mp, mp->m_ddev_targp, dblkno,
- blkcnt, XBF_LOCK | XBF_DONT_BLOCK,
- &bp);
+ error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
+ dblkno, blkcnt, 0, &bp);
if (error)
return(error);
- tmp = (valuelen < XFS_BUF_SIZE(bp))
- ? valuelen : XFS_BUF_SIZE(bp);
+ tmp = min_t(int, valuelen, BBTOB(bp->b_length));
xfs_buf_iomove(bp, 0, tmp, dst, XBRW_READ);
xfs_buf_relse(bp);
dst += tmp;
@@ -2097,6 +2093,8 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)
lblkno = args->rmtblkno;
valuelen = args->valuelen;
while (valuelen > 0) {
+ int buflen;
+
/*
* Try to remember where we decided to put the value.
*/
@@ -2114,15 +2112,16 @@ xfs_attr_rmtval_set(xfs_da_args_t *args)
dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock),
blkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount);
- bp = xfs_buf_get(mp->m_ddev_targp, dblkno, blkcnt,
- XBF_LOCK | XBF_DONT_BLOCK);
+ bp = xfs_buf_get(mp->m_ddev_targp, dblkno, blkcnt, 0);
if (!bp)
return ENOMEM;
- tmp = (valuelen < XFS_BUF_SIZE(bp)) ? valuelen :
- XFS_BUF_SIZE(bp);
+
+ buflen = BBTOB(bp->b_length);
+ tmp = min_t(int, valuelen, buflen);
xfs_buf_iomove(bp, 0, tmp, src, XBRW_WRITE);
- if (tmp < XFS_BUF_SIZE(bp))
- xfs_buf_zero(bp, tmp, XFS_BUF_SIZE(bp) - tmp);
+ if (tmp < buflen)
+ xfs_buf_zero(bp, tmp, buflen - tmp);
+
error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */
xfs_buf_relse(bp);
if (error)
diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c
index 76d93dc953e1..7d89d800f517 100644
--- a/fs/xfs/xfs_attr_leaf.c
+++ b/fs/xfs/xfs_attr_leaf.c
@@ -20,7 +20,6 @@
#include "xfs_types.h"
#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
@@ -2983,7 +2982,7 @@ xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp,
map.br_blockcount);
bp = xfs_trans_get_buf(*trans,
dp->i_mount->m_ddev_targp,
- dblkno, dblkcnt, XBF_LOCK);
+ dblkno, dblkcnt, 0);
if (!bp)
return ENOMEM;
xfs_trans_binval(*trans, bp);
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index 85e7e327bcd8..58b815ec8c91 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -41,7 +41,6 @@
#include "xfs_rtalloc.h"
#include "xfs_error.h"
#include "xfs_attr_leaf.h"
-#include "xfs_rw.h"
#include "xfs_quota.h"
#include "xfs_trans_space.h"
#include "xfs_buf_item.h"
@@ -4527,7 +4526,7 @@ out_unreserve_blocks:
xfs_icsb_modify_counters(mp, XFS_SBS_FDBLOCKS, alen, 0);
out_unreserve_quota:
if (XFS_IS_QUOTA_ON(mp))
- xfs_trans_unreserve_quota_nblks(NULL, ip, alen, 0, rt ?
+ xfs_trans_unreserve_quota_nblks(NULL, ip, (long)alen, 0, rt ?
XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS);
return error;
}
@@ -5621,8 +5620,20 @@ xfs_getbmap(
XFS_FSB_TO_BB(mp, map[i].br_blockcount);
out[cur_ext].bmv_unused1 = 0;
out[cur_ext].bmv_unused2 = 0;
- ASSERT(((iflags & BMV_IF_DELALLOC) != 0) ||
- (map[i].br_startblock != DELAYSTARTBLOCK));
+
+ /*
+ * delayed allocation extents that start beyond EOF can
+ * occur due to speculative EOF allocation when the
+ * delalloc extent is larger than the largest freespace
+ * extent at conversion time. These extents cannot be
+ * converted by data writeback, so can exist here even
+ * if we are not supposed to be finding delalloc
+ * extents.
+ */
+ if (map[i].br_startblock == DELAYSTARTBLOCK &&
+ map[i].br_startoff <= XFS_B_TO_FSB(mp, XFS_ISIZE(ip)))
+ ASSERT((iflags & BMV_IF_DELALLOC) != 0);
+
if (map[i].br_startblock == HOLESTARTBLOCK &&
whichfork == XFS_ATTR_FORK) {
/* came to the end of attribute fork */
@@ -6157,3 +6168,16 @@ next_block:
return error;
}
+
+/*
+ * Convert the given file system block to a disk block. We have to treat it
+ * differently based on whether the file is a real time file or not, because the
+ * bmap code does.
+ */
+xfs_daddr_t
+xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb)
+{
+ return (XFS_IS_REALTIME_INODE(ip) ? \
+ (xfs_daddr_t)XFS_FSB_TO_BB((ip)->i_mount, (fsb)) : \
+ XFS_FSB_TO_DADDR((ip)->i_mount, (fsb)));
+}
diff --git a/fs/xfs/xfs_bmap.h b/fs/xfs/xfs_bmap.h
index 89ee672d378a..803b56d7ce16 100644
--- a/fs/xfs/xfs_bmap.h
+++ b/fs/xfs/xfs_bmap.h
@@ -211,6 +211,9 @@ int xfs_bmap_count_blocks(struct xfs_trans *tp, struct xfs_inode *ip,
int whichfork, int *count);
int xfs_bmap_punch_delalloc_range(struct xfs_inode *ip,
xfs_fileoff_t start_fsb, xfs_fileoff_t length);
+
+xfs_daddr_t xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb);
+
#endif /* __KERNEL__ */
#endif /* __XFS_BMAP_H__ */
diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c
index e2f5d59cbeaf..862084a47a7e 100644
--- a/fs/xfs/xfs_bmap_btree.c
+++ b/fs/xfs/xfs_bmap_btree.c
@@ -20,7 +20,6 @@
#include "xfs_types.h"
#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c
index 1f19f03af9d3..e53e317b1582 100644
--- a/fs/xfs/xfs_btree.c
+++ b/fs/xfs/xfs_btree.c
@@ -20,7 +20,6 @@
#include "xfs_types.h"
#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
index 6819b5163e33..172d3cc8f8cb 100644
--- a/fs/xfs/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
@@ -35,14 +35,12 @@
#include <linux/freezer.h>
#include "xfs_sb.h"
-#include "xfs_inum.h"
#include "xfs_log.h"
#include "xfs_ag.h"
#include "xfs_mount.h"
#include "xfs_trace.h"
static kmem_zone_t *xfs_buf_zone;
-STATIC int xfsbufd(void *);
static struct workqueue_struct *xfslogd_workqueue;
@@ -57,11 +55,7 @@ static struct workqueue_struct *xfslogd_workqueue;
#endif
#define xb_to_gfp(flags) \
- ((((flags) & XBF_READ_AHEAD) ? __GFP_NORETRY : \
- ((flags) & XBF_DONT_BLOCK) ? GFP_NOFS : GFP_KERNEL) | __GFP_NOWARN)
-
-#define xb_to_km(flags) \
- (((flags) & XBF_DONT_BLOCK) ? KM_NOFS : KM_SLEEP)
+ ((((flags) & XBF_READ_AHEAD) ? __GFP_NORETRY : GFP_NOFS) | __GFP_NOWARN)
static inline int
@@ -71,11 +65,11 @@ xfs_buf_is_vmapped(
/*
* Return true if the buffer is vmapped.
*
- * The XBF_MAPPED flag is set if the buffer should be mapped, but the
- * code is clever enough to know it doesn't have to map a single page,
- * so the check has to be both for XBF_MAPPED and bp->b_page_count > 1.
+ * b_addr is null if the buffer is not mapped, but the code is clever
+ * enough to know it doesn't have to map a single page, so the check has
+ * to be both for b_addr and bp->b_page_count > 1.
*/
- return (bp->b_flags & XBF_MAPPED) && bp->b_page_count > 1;
+ return bp->b_addr && bp->b_page_count > 1;
}
static inline int
@@ -144,8 +138,17 @@ void
xfs_buf_stale(
struct xfs_buf *bp)
{
+ ASSERT(xfs_buf_islocked(bp));
+
bp->b_flags |= XBF_STALE;
- xfs_buf_delwri_dequeue(bp);
+
+ /*
+ * Clear the delwri status so that a delwri queue walker will not
+ * flush this buffer to disk now that it is stale. The delwri queue has
+ * a reference to the buffer, so this is safe to do.
+ */
+ bp->b_flags &= ~_XBF_DELWRI_Q;
+
atomic_set(&(bp)->b_lru_ref, 0);
if (!list_empty(&bp->b_lru)) {
struct xfs_buftarg *btp = bp->b_target;
@@ -164,22 +167,22 @@ xfs_buf_stale(
struct xfs_buf *
xfs_buf_alloc(
struct xfs_buftarg *target,
- xfs_off_t range_base,
- size_t range_length,
+ xfs_daddr_t blkno,
+ size_t numblks,
xfs_buf_flags_t flags)
{
struct xfs_buf *bp;
- bp = kmem_zone_alloc(xfs_buf_zone, xb_to_km(flags));
+ bp = kmem_zone_zalloc(xfs_buf_zone, KM_NOFS);
if (unlikely(!bp))
return NULL;
/*
- * We don't want certain flags to appear in b_flags.
+ * We don't want certain flags to appear in b_flags unless they are
+ * specifically set by later operations on the buffer.
*/
- flags &= ~(XBF_LOCK|XBF_MAPPED|XBF_DONT_BLOCK|XBF_READ_AHEAD);
+ flags &= ~(XBF_UNMAPPED | XBF_TRYLOCK | XBF_ASYNC | XBF_READ_AHEAD);
- memset(bp, 0, sizeof(xfs_buf_t));
atomic_set(&bp->b_hold, 1);
atomic_set(&bp->b_lru_ref, 1);
init_completion(&bp->b_iowait);
@@ -189,14 +192,22 @@ xfs_buf_alloc(
sema_init(&bp->b_sema, 0); /* held, no waiters */
XB_SET_OWNER(bp);
bp->b_target = target;
- bp->b_file_offset = range_base;
+
/*
- * Set buffer_length and count_desired to the same value initially.
- * I/O routines should use count_desired, which will be the same in
+ * Set length and io_length to the same value initially.
+ * I/O routines should use io_length, which will be the same in
* most cases but may be reset (e.g. XFS recovery).
*/
- bp->b_buffer_length = bp->b_count_desired = range_length;
+ bp->b_length = numblks;
+ bp->b_io_length = numblks;
bp->b_flags = flags;
+
+ /*
+ * We do not set the block number here in the buffer because we have not
+ * finished initialising the buffer. We insert the buffer into the cache
+ * in this state, so this ensures that we are unable to do IO on a
+ * buffer that hasn't been fully initialised.
+ */
bp->b_bn = XFS_BUF_DADDR_NULL;
atomic_set(&bp->b_pin_count, 0);
init_waitqueue_head(&bp->b_waiters);
@@ -219,13 +230,12 @@ _xfs_buf_get_pages(
{
/* Make sure that we have a page list */
if (bp->b_pages == NULL) {
- bp->b_offset = xfs_buf_poff(bp->b_file_offset);
bp->b_page_count = page_count;
if (page_count <= XB_PAGES) {
bp->b_pages = bp->b_page_array;
} else {
bp->b_pages = kmem_alloc(sizeof(struct page *) *
- page_count, xb_to_km(flags));
+ page_count, KM_NOFS);
if (bp->b_pages == NULL)
return -ENOMEM;
}
@@ -288,11 +298,11 @@ xfs_buf_allocate_memory(
xfs_buf_t *bp,
uint flags)
{
- size_t size = bp->b_count_desired;
+ size_t size;
size_t nbytes, offset;
gfp_t gfp_mask = xb_to_gfp(flags);
unsigned short page_count, i;
- xfs_off_t end;
+ xfs_off_t start, end;
int error;
/*
@@ -300,15 +310,15 @@ xfs_buf_allocate_memory(
* the memory from the heap - there's no need for the complexity of
* page arrays to keep allocation down to order 0.
*/
- if (bp->b_buffer_length < PAGE_SIZE) {
- bp->b_addr = kmem_alloc(bp->b_buffer_length, xb_to_km(flags));
+ size = BBTOB(bp->b_length);
+ if (size < PAGE_SIZE) {
+ bp->b_addr = kmem_alloc(size, KM_NOFS);
if (!bp->b_addr) {
/* low memory - use alloc_page loop instead */
goto use_alloc_page;
}
- if (((unsigned long)(bp->b_addr + bp->b_buffer_length - 1) &
- PAGE_MASK) !=
+ if (((unsigned long)(bp->b_addr + size - 1) & PAGE_MASK) !=
((unsigned long)bp->b_addr & PAGE_MASK)) {
/* b_addr spans two pages - use alloc_page instead */
kmem_free(bp->b_addr);
@@ -319,13 +329,14 @@ xfs_buf_allocate_memory(
bp->b_pages = bp->b_page_array;
bp->b_pages[0] = virt_to_page(bp->b_addr);
bp->b_page_count = 1;
- bp->b_flags |= XBF_MAPPED | _XBF_KMEM;
+ bp->b_flags |= _XBF_KMEM;
return 0;
}
use_alloc_page:
- end = bp->b_file_offset + bp->b_buffer_length;
- page_count = xfs_buf_btoc(end) - xfs_buf_btoct(bp->b_file_offset);
+ start = BBTOB(bp->b_bn) >> PAGE_SHIFT;
+ end = (BBTOB(bp->b_bn + bp->b_length) + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ page_count = end - start;
error = _xfs_buf_get_pages(bp, page_count, flags);
if (unlikely(error))
return error;
@@ -388,8 +399,9 @@ _xfs_buf_map_pages(
if (bp->b_page_count == 1) {
/* A single page buffer is always mappable */
bp->b_addr = page_address(bp->b_pages[0]) + bp->b_offset;
- bp->b_flags |= XBF_MAPPED;
- } else if (flags & XBF_MAPPED) {
+ } else if (flags & XBF_UNMAPPED) {
+ bp->b_addr = NULL;
+ } else {
int retried = 0;
do {
@@ -403,7 +415,6 @@ _xfs_buf_map_pages(
if (!bp->b_addr)
return -ENOMEM;
bp->b_addr += bp->b_offset;
- bp->b_flags |= XBF_MAPPED;
}
return 0;
@@ -420,29 +431,27 @@ _xfs_buf_map_pages(
*/
xfs_buf_t *
_xfs_buf_find(
- xfs_buftarg_t *btp, /* block device target */
- xfs_off_t ioff, /* starting offset of range */
- size_t isize, /* length of range */
+ struct xfs_buftarg *btp,
+ xfs_daddr_t blkno,
+ size_t numblks,
xfs_buf_flags_t flags,
xfs_buf_t *new_bp)
{
- xfs_off_t range_base;
- size_t range_length;
+ size_t numbytes;
struct xfs_perag *pag;
struct rb_node **rbp;
struct rb_node *parent;
xfs_buf_t *bp;
- range_base = (ioff << BBSHIFT);
- range_length = (isize << BBSHIFT);
+ numbytes = BBTOB(numblks);
/* Check for IOs smaller than the sector size / not sector aligned */
- ASSERT(!(range_length < (1 << btp->bt_sshift)));
- ASSERT(!(range_base & (xfs_off_t)btp->bt_smask));
+ ASSERT(!(numbytes < (1 << btp->bt_sshift)));
+ ASSERT(!(BBTOB(blkno) & (xfs_off_t)btp->bt_smask));
/* get tree root */
pag = xfs_perag_get(btp->bt_mount,
- xfs_daddr_to_agno(btp->bt_mount, ioff));
+ xfs_daddr_to_agno(btp->bt_mount, blkno));
/* walk tree */
spin_lock(&pag->pag_buf_lock);
@@ -453,20 +462,20 @@ _xfs_buf_find(
parent = *rbp;
bp = rb_entry(parent, struct xfs_buf, b_rbnode);
- if (range_base < bp->b_file_offset)
+ if (blkno < bp->b_bn)
rbp = &(*rbp)->rb_left;
- else if (range_base > bp->b_file_offset)
+ else if (blkno > bp->b_bn)
rbp = &(*rbp)->rb_right;
else {
/*
- * found a block offset match. If the range doesn't
+ * found a block number match. If the range doesn't
* match, the only way this is allowed is if the buffer
* in the cache is stale and the transaction that made
* it stale has not yet committed. i.e. we are
* reallocating a busy extent. Skip this buffer and
* continue searching to the right for an exact match.
*/
- if (bp->b_buffer_length != range_length) {
+ if (bp->b_length != numblks) {
ASSERT(bp->b_flags & XBF_STALE);
rbp = &(*rbp)->rb_right;
continue;
@@ -511,7 +520,7 @@ found:
*/
if (bp->b_flags & XBF_STALE) {
ASSERT((bp->b_flags & _XBF_DELWRI_Q) == 0);
- bp->b_flags &= XBF_MAPPED | _XBF_KMEM | _XBF_PAGES;
+ bp->b_flags &= _XBF_KMEM | _XBF_PAGES;
}
trace_xfs_buf_find(bp, flags, _RET_IP_);
@@ -526,63 +535,59 @@ found:
*/
struct xfs_buf *
xfs_buf_get(
- xfs_buftarg_t *target,/* target for buffer */
- xfs_off_t ioff, /* starting offset of range */
- size_t isize, /* length of range */
+ xfs_buftarg_t *target,
+ xfs_daddr_t blkno,
+ size_t numblks,
xfs_buf_flags_t flags)
{
struct xfs_buf *bp;
struct xfs_buf *new_bp;
int error = 0;
- bp = _xfs_buf_find(target, ioff, isize, flags, NULL);
+ bp = _xfs_buf_find(target, blkno, numblks, flags, NULL);
if (likely(bp))
goto found;
- new_bp = xfs_buf_alloc(target, ioff << BBSHIFT, isize << BBSHIFT,
- flags);
+ new_bp = xfs_buf_alloc(target, blkno, numblks, flags);
if (unlikely(!new_bp))
return NULL;
- bp = _xfs_buf_find(target, ioff, isize, flags, new_bp);
- if (!bp) {
+ error = xfs_buf_allocate_memory(new_bp, flags);
+ if (error) {
kmem_zone_free(xfs_buf_zone, new_bp);
return NULL;
}
- if (bp == new_bp) {
- error = xfs_buf_allocate_memory(bp, flags);
- if (error)
- goto no_buffer;
- } else
- kmem_zone_free(xfs_buf_zone, new_bp);
+ bp = _xfs_buf_find(target, blkno, numblks, flags, new_bp);
+ if (!bp) {
+ xfs_buf_free(new_bp);
+ return NULL;
+ }
+
+ if (bp != new_bp)
+ xfs_buf_free(new_bp);
/*
* Now we have a workable buffer, fill in the block number so
* that we can do IO on it.
*/
- bp->b_bn = ioff;
- bp->b_count_desired = bp->b_buffer_length;
+ bp->b_bn = blkno;
+ bp->b_io_length = bp->b_length;
found:
- if (!(bp->b_flags & XBF_MAPPED)) {
+ if (!bp->b_addr) {
error = _xfs_buf_map_pages(bp, flags);
if (unlikely(error)) {
xfs_warn(target->bt_mount,
"%s: failed to map pages\n", __func__);
- goto no_buffer;
+ xfs_buf_relse(bp);
+ return NULL;
}
}
XFS_STATS_INC(xb_get);
trace_xfs_buf_get(bp, flags, _RET_IP_);
return bp;
-
-no_buffer:
- if (flags & (XBF_LOCK | XBF_TRYLOCK))
- xfs_buf_unlock(bp);
- xfs_buf_rele(bp);
- return NULL;
}
STATIC int
@@ -590,32 +595,30 @@ _xfs_buf_read(
xfs_buf_t *bp,
xfs_buf_flags_t flags)
{
- int status;
-
- ASSERT(!(flags & (XBF_DELWRI|XBF_WRITE)));
+ ASSERT(!(flags & XBF_WRITE));
ASSERT(bp->b_bn != XFS_BUF_DADDR_NULL);
- bp->b_flags &= ~(XBF_WRITE | XBF_ASYNC | XBF_DELWRI | XBF_READ_AHEAD);
+ bp->b_flags &= ~(XBF_WRITE | XBF_ASYNC | XBF_READ_AHEAD);
bp->b_flags |= flags & (XBF_READ | XBF_ASYNC | XBF_READ_AHEAD);
- status = xfs_buf_iorequest(bp);
- if (status || bp->b_error || (flags & XBF_ASYNC))
- return status;
+ xfs_buf_iorequest(bp);
+ if (flags & XBF_ASYNC)
+ return 0;
return xfs_buf_iowait(bp);
}
xfs_buf_t *
xfs_buf_read(
xfs_buftarg_t *target,
- xfs_off_t ioff,
- size_t isize,
+ xfs_daddr_t blkno,
+ size_t numblks,
xfs_buf_flags_t flags)
{
xfs_buf_t *bp;
flags |= XBF_READ;
- bp = xfs_buf_get(target, ioff, isize, flags);
+ bp = xfs_buf_get(target, blkno, numblks, flags);
if (bp) {
trace_xfs_buf_read(bp, flags, _RET_IP_);
@@ -627,7 +630,8 @@ xfs_buf_read(
* Read ahead call which is already satisfied,
* drop the buffer
*/
- goto no_buffer;
+ xfs_buf_relse(bp);
+ return NULL;
} else {
/* We do not want read in the flags */
bp->b_flags &= ~XBF_READ;
@@ -635,12 +639,6 @@ xfs_buf_read(
}
return bp;
-
- no_buffer:
- if (flags & (XBF_LOCK | XBF_TRYLOCK))
- xfs_buf_unlock(bp);
- xfs_buf_rele(bp);
- return NULL;
}
/*
@@ -650,14 +648,14 @@ xfs_buf_read(
void
xfs_buf_readahead(
xfs_buftarg_t *target,
- xfs_off_t ioff,
- size_t isize)
+ xfs_daddr_t blkno,
+ size_t numblks)
{
if (bdi_read_congested(target->bt_bdi))
return;
- xfs_buf_read(target, ioff, isize,
- XBF_TRYLOCK|XBF_ASYNC|XBF_READ_AHEAD|XBF_DONT_BLOCK);
+ xfs_buf_read(target, blkno, numblks,
+ XBF_TRYLOCK|XBF_ASYNC|XBF_READ_AHEAD);
}
/*
@@ -666,16 +664,15 @@ xfs_buf_readahead(
*/
struct xfs_buf *
xfs_buf_read_uncached(
- struct xfs_mount *mp,
struct xfs_buftarg *target,
xfs_daddr_t daddr,
- size_t length,
+ size_t numblks,
int flags)
{
xfs_buf_t *bp;
int error;
- bp = xfs_buf_get_uncached(target, length, flags);
+ bp = xfs_buf_get_uncached(target, numblks, flags);
if (!bp)
return NULL;
@@ -683,9 +680,9 @@ xfs_buf_read_uncached(
XFS_BUF_SET_ADDR(bp, daddr);
XFS_BUF_READ(bp);
- xfsbdstrat(mp, bp);
+ xfsbdstrat(target->bt_mount, bp);
error = xfs_buf_iowait(bp);
- if (error || bp->b_error) {
+ if (error) {
xfs_buf_relse(bp);
return NULL;
}
@@ -699,7 +696,7 @@ xfs_buf_read_uncached(
void
xfs_buf_set_empty(
struct xfs_buf *bp,
- size_t len)
+ size_t numblks)
{
if (bp->b_pages)
_xfs_buf_free_pages(bp);
@@ -707,10 +704,9 @@ xfs_buf_set_empty(
bp->b_pages = NULL;
bp->b_page_count = 0;
bp->b_addr = NULL;
- bp->b_file_offset = 0;
- bp->b_buffer_length = bp->b_count_desired = len;
+ bp->b_length = numblks;
+ bp->b_io_length = numblks;
bp->b_bn = XFS_BUF_DADDR_NULL;
- bp->b_flags &= ~XBF_MAPPED;
}
static inline struct page *
@@ -749,7 +745,7 @@ xfs_buf_associate_memory(
bp->b_pages = NULL;
bp->b_addr = mem;
- rval = _xfs_buf_get_pages(bp, page_count, XBF_DONT_BLOCK);
+ rval = _xfs_buf_get_pages(bp, page_count, 0);
if (rval)
return rval;
@@ -760,9 +756,8 @@ xfs_buf_associate_memory(
pageaddr += PAGE_SIZE;
}
- bp->b_count_desired = len;
- bp->b_buffer_length = buflen;
- bp->b_flags |= XBF_MAPPED;
+ bp->b_io_length = BTOBB(len);
+ bp->b_length = BTOBB(buflen);
return 0;
}
@@ -770,17 +765,18 @@ xfs_buf_associate_memory(
xfs_buf_t *
xfs_buf_get_uncached(
struct xfs_buftarg *target,
- size_t len,
+ size_t numblks,
int flags)
{
- unsigned long page_count = PAGE_ALIGN(len) >> PAGE_SHIFT;
+ unsigned long page_count;
int error, i;
xfs_buf_t *bp;
- bp = xfs_buf_alloc(target, 0, len, 0);
+ bp = xfs_buf_alloc(target, 0, numblks, 0);
if (unlikely(bp == NULL))
goto fail;
+ page_count = PAGE_ALIGN(numblks << BBSHIFT) >> PAGE_SHIFT;
error = _xfs_buf_get_pages(bp, page_count, 0);
if (error)
goto fail_free_buf;
@@ -792,7 +788,7 @@ xfs_buf_get_uncached(
}
bp->b_flags |= _XBF_PAGES;
- error = _xfs_buf_map_pages(bp, XBF_MAPPED);
+ error = _xfs_buf_map_pages(bp, 0);
if (unlikely(error)) {
xfs_warn(target->bt_mount,
"%s: failed to map pages\n", __func__);
@@ -855,7 +851,7 @@ xfs_buf_rele(
spin_unlock(&pag->pag_buf_lock);
} else {
xfs_buf_lru_del(bp);
- ASSERT(!(bp->b_flags & (XBF_DELWRI|_XBF_DELWRI_Q)));
+ ASSERT(!(bp->b_flags & _XBF_DELWRI_Q));
rb_erase(&bp->b_rbnode, &pag->pag_buf_tree);
spin_unlock(&pag->pag_buf_lock);
xfs_perag_put(pag);
@@ -915,13 +911,6 @@ xfs_buf_lock(
trace_xfs_buf_lock_done(bp, _RET_IP_);
}
-/*
- * Releases the lock on the buffer object.
- * If the buffer is marked delwri but is not queued, do so before we
- * unlock the buffer as we need to set flags correctly. We also need to
- * take a reference for the delwri queue because the unlocker is going to
- * drop their's and they don't know we just queued it.
- */
void
xfs_buf_unlock(
struct xfs_buf *bp)
@@ -1008,9 +997,8 @@ xfs_buf_ioerror_alert(
const char *func)
{
xfs_alert(bp->b_target->bt_mount,
-"metadata I/O error: block 0x%llx (\"%s\") error %d buf count %zd",
- (__uint64_t)XFS_BUF_ADDR(bp), func,
- bp->b_error, XFS_BUF_COUNT(bp));
+"metadata I/O error: block 0x%llx (\"%s\") error %d numblks %d",
+ (__uint64_t)XFS_BUF_ADDR(bp), func, bp->b_error, bp->b_length);
}
int
@@ -1019,10 +1007,11 @@ xfs_bwrite(
{
int error;
+ ASSERT(xfs_buf_islocked(bp));
+
bp->b_flags |= XBF_WRITE;
- bp->b_flags &= ~(XBF_ASYNC | XBF_READ);
+ bp->b_flags &= ~(XBF_ASYNC | XBF_READ | _XBF_DELWRI_Q);
- xfs_buf_delwri_dequeue(bp);
xfs_bdstrat_cb(bp);
error = xfs_buf_iowait(bp);
@@ -1181,7 +1170,7 @@ _xfs_buf_ioapply(
int rw, map_i, total_nr_pages, nr_pages;
struct bio *bio;
int offset = bp->b_offset;
- int size = bp->b_count_desired;
+ int size = BBTOB(bp->b_io_length);
sector_t sector = bp->b_bn;
total_nr_pages = bp->b_page_count;
@@ -1229,7 +1218,7 @@ next_chunk:
break;
offset = 0;
- sector += nbytes >> BBSHIFT;
+ sector += BTOBB(nbytes);
size -= nbytes;
total_nr_pages--;
}
@@ -1248,13 +1237,13 @@ next_chunk:
}
}
-int
+void
xfs_buf_iorequest(
xfs_buf_t *bp)
{
trace_xfs_buf_iorequest(bp, _RET_IP_);
- ASSERT(!(bp->b_flags & XBF_DELWRI));
+ ASSERT(!(bp->b_flags & _XBF_DELWRI_Q));
if (bp->b_flags & XBF_WRITE)
xfs_buf_wait_unpin(bp);
@@ -1269,13 +1258,12 @@ xfs_buf_iorequest(
_xfs_buf_ioend(bp, 0);
xfs_buf_rele(bp);
- return 0;
}
/*
- * Waits for I/O to complete on the buffer supplied.
- * It returns immediately if no I/O is pending.
- * It returns the I/O error code, if any, or 0 if there was no error.
+ * Waits for I/O to complete on the buffer supplied. It returns immediately if
+ * no I/O is pending or there is already a pending error on the buffer. It
+ * returns the I/O error code, if any, or 0 if there was no error.
*/
int
xfs_buf_iowait(
@@ -1283,7 +1271,8 @@ xfs_buf_iowait(
{
trace_xfs_buf_iowait(bp, _RET_IP_);
- wait_for_completion(&bp->b_iowait);
+ if (!bp->b_error)
+ wait_for_completion(&bp->b_iowait);
trace_xfs_buf_iowait_done(bp, _RET_IP_);
return bp->b_error;
@@ -1296,7 +1285,7 @@ xfs_buf_offset(
{
struct page *page;
- if (bp->b_flags & XBF_MAPPED)
+ if (bp->b_addr)
return bp->b_addr + offset;
offset += bp->b_offset;
@@ -1315,27 +1304,30 @@ xfs_buf_iomove(
void *data, /* data address */
xfs_buf_rw_t mode) /* read/write/zero flag */
{
- size_t bend, cpoff, csize;
- struct page *page;
+ size_t bend;
bend = boff + bsize;
while (boff < bend) {
- page = bp->b_pages[xfs_buf_btoct(boff + bp->b_offset)];
- cpoff = xfs_buf_poff(boff + bp->b_offset);
- csize = min_t(size_t,
- PAGE_SIZE-cpoff, bp->b_count_desired-boff);
+ struct page *page;
+ int page_index, page_offset, csize;
+
+ page_index = (boff + bp->b_offset) >> PAGE_SHIFT;
+ page_offset = (boff + bp->b_offset) & ~PAGE_MASK;
+ page = bp->b_pages[page_index];
+ csize = min_t(size_t, PAGE_SIZE - page_offset,
+ BBTOB(bp->b_io_length) - boff);
- ASSERT(((csize + cpoff) <= PAGE_SIZE));
+ ASSERT((csize + page_offset) <= PAGE_SIZE);
switch (mode) {
case XBRW_ZERO:
- memset(page_address(page) + cpoff, 0, csize);
+ memset(page_address(page) + page_offset, 0, csize);
break;
case XBRW_READ:
- memcpy(data, page_address(page) + cpoff, csize);
+ memcpy(data, page_address(page) + page_offset, csize);
break;
case XBRW_WRITE:
- memcpy(page_address(page) + cpoff, data, csize);
+ memcpy(page_address(page) + page_offset, data, csize);
}
boff += csize;
@@ -1435,11 +1427,9 @@ xfs_free_buftarg(
{
unregister_shrinker(&btp->bt_shrinker);
- xfs_flush_buftarg(btp, 1);
if (mp->m_flags & XFS_MOUNT_BARRIER)
xfs_blkdev_issue_flush(btp);
- kthread_stop(btp->bt_task);
kmem_free(btp);
}
@@ -1491,20 +1481,6 @@ xfs_setsize_buftarg(
return xfs_setsize_buftarg_flags(btp, blocksize, sectorsize, 1);
}
-STATIC int
-xfs_alloc_delwri_queue(
- xfs_buftarg_t *btp,
- const char *fsname)
-{
- INIT_LIST_HEAD(&btp->bt_delwri_queue);
- spin_lock_init(&btp->bt_delwri_lock);
- btp->bt_flags = 0;
- btp->bt_task = kthread_run(xfsbufd, btp, "xfsbufd/%s", fsname);
- if (IS_ERR(btp->bt_task))
- return PTR_ERR(btp->bt_task);
- return 0;
-}
-
xfs_buftarg_t *
xfs_alloc_buftarg(
struct xfs_mount *mp,
@@ -1527,8 +1503,6 @@ xfs_alloc_buftarg(
spin_lock_init(&btp->bt_lru_lock);
if (xfs_setsize_buftarg_early(btp, bdev))
goto error;
- if (xfs_alloc_delwri_queue(btp, fsname))
- goto error;
btp->bt_shrinker.shrink = xfs_buftarg_shrink;
btp->bt_shrinker.seeks = DEFAULT_SEEKS;
register_shrinker(&btp->bt_shrinker);
@@ -1539,125 +1513,52 @@ error:
return NULL;
}
-
/*
- * Delayed write buffer handling
+ * Add a buffer to the delayed write list.
+ *
+ * This queues a buffer for writeout if it hasn't already been. Note that
+ * neither this routine nor the buffer list submission functions perform
+ * any internal synchronization. It is expected that the lists are thread-local
+ * to the callers.
+ *
+ * Returns true if we queued up the buffer, or false if it already had
+ * been on the buffer list.
*/
-void
+bool
xfs_buf_delwri_queue(
- xfs_buf_t *bp)
+ struct xfs_buf *bp,
+ struct list_head *list)
{
- struct xfs_buftarg *btp = bp->b_target;
-
- trace_xfs_buf_delwri_queue(bp, _RET_IP_);
-
+ ASSERT(xfs_buf_islocked(bp));
ASSERT(!(bp->b_flags & XBF_READ));
- spin_lock(&btp->bt_delwri_lock);
- if (!list_empty(&bp->b_list)) {
- /* if already in the queue, move it to the tail */
- ASSERT(bp->b_flags & _XBF_DELWRI_Q);
- list_move_tail(&bp->b_list, &btp->bt_delwri_queue);
- } else {
- /* start xfsbufd as it is about to have something to do */
- if (list_empty(&btp->bt_delwri_queue))
- wake_up_process(bp->b_target->bt_task);
-
- atomic_inc(&bp->b_hold);
- bp->b_flags |= XBF_DELWRI | _XBF_DELWRI_Q | XBF_ASYNC;
- list_add_tail(&bp->b_list, &btp->bt_delwri_queue);
- }
- bp->b_queuetime = jiffies;
- spin_unlock(&btp->bt_delwri_lock);
-}
-
-void
-xfs_buf_delwri_dequeue(
- xfs_buf_t *bp)
-{
- int dequeued = 0;
-
- spin_lock(&bp->b_target->bt_delwri_lock);
- if ((bp->b_flags & XBF_DELWRI) && !list_empty(&bp->b_list)) {
- ASSERT(bp->b_flags & _XBF_DELWRI_Q);
- list_del_init(&bp->b_list);
- dequeued = 1;
+ /*
+ * If the buffer is already marked delwri it already is queued up
+ * by someone else for imediate writeout. Just ignore it in that
+ * case.
+ */
+ if (bp->b_flags & _XBF_DELWRI_Q) {
+ trace_xfs_buf_delwri_queued(bp, _RET_IP_);
+ return false;
}
- bp->b_flags &= ~(XBF_DELWRI|_XBF_DELWRI_Q);
- spin_unlock(&bp->b_target->bt_delwri_lock);
-
- if (dequeued)
- xfs_buf_rele(bp);
-
- trace_xfs_buf_delwri_dequeue(bp, _RET_IP_);
-}
-
-/*
- * If a delwri buffer needs to be pushed before it has aged out, then promote
- * it to the head of the delwri queue so that it will be flushed on the next
- * xfsbufd run. We do this by resetting the queuetime of the buffer to be older
- * than the age currently needed to flush the buffer. Hence the next time the
- * xfsbufd sees it is guaranteed to be considered old enough to flush.
- */
-void
-xfs_buf_delwri_promote(
- struct xfs_buf *bp)
-{
- struct xfs_buftarg *btp = bp->b_target;
- long age = xfs_buf_age_centisecs * msecs_to_jiffies(10) + 1;
- ASSERT(bp->b_flags & XBF_DELWRI);
- ASSERT(bp->b_flags & _XBF_DELWRI_Q);
+ trace_xfs_buf_delwri_queue(bp, _RET_IP_);
/*
- * Check the buffer age before locking the delayed write queue as we
- * don't need to promote buffers that are already past the flush age.
+ * If a buffer gets written out synchronously or marked stale while it
+ * is on a delwri list we lazily remove it. To do this, the other party
+ * clears the _XBF_DELWRI_Q flag but otherwise leaves the buffer alone.
+ * It remains referenced and on the list. In a rare corner case it
+ * might get readded to a delwri list after the synchronous writeout, in
+ * which case we need just need to re-add the flag here.
*/
- if (bp->b_queuetime < jiffies - age)
- return;
- bp->b_queuetime = jiffies - age;
- spin_lock(&btp->bt_delwri_lock);
- list_move(&bp->b_list, &btp->bt_delwri_queue);
- spin_unlock(&btp->bt_delwri_lock);
-}
-
-/*
- * Move as many buffers as specified to the supplied list
- * idicating if we skipped any buffers to prevent deadlocks.
- */
-STATIC int
-xfs_buf_delwri_split(
- xfs_buftarg_t *target,
- struct list_head *list,
- unsigned long age)
-{
- xfs_buf_t *bp, *n;
- int skipped = 0;
- int force;
-
- force = test_and_clear_bit(XBT_FORCE_FLUSH, &target->bt_flags);
- INIT_LIST_HEAD(list);
- spin_lock(&target->bt_delwri_lock);
- list_for_each_entry_safe(bp, n, &target->bt_delwri_queue, b_list) {
- ASSERT(bp->b_flags & XBF_DELWRI);
-
- if (!xfs_buf_ispinned(bp) && xfs_buf_trylock(bp)) {
- if (!force &&
- time_before(jiffies, bp->b_queuetime + age)) {
- xfs_buf_unlock(bp);
- break;
- }
-
- bp->b_flags &= ~(XBF_DELWRI | _XBF_DELWRI_Q);
- bp->b_flags |= XBF_WRITE;
- list_move_tail(&bp->b_list, list);
- trace_xfs_buf_delwri_split(bp, _RET_IP_);
- } else
- skipped++;
+ bp->b_flags |= _XBF_DELWRI_Q;
+ if (list_empty(&bp->b_list)) {
+ atomic_inc(&bp->b_hold);
+ list_add_tail(&bp->b_list, list);
}
- spin_unlock(&target->bt_delwri_lock);
- return skipped;
+ return true;
}
/*
@@ -1683,99 +1584,109 @@ xfs_buf_cmp(
return 0;
}
-STATIC int
-xfsbufd(
- void *data)
+static int
+__xfs_buf_delwri_submit(
+ struct list_head *buffer_list,
+ struct list_head *io_list,
+ bool wait)
{
- xfs_buftarg_t *target = (xfs_buftarg_t *)data;
-
- current->flags |= PF_MEMALLOC;
-
- set_freezable();
+ struct blk_plug plug;
+ struct xfs_buf *bp, *n;
+ int pinned = 0;
+
+ list_for_each_entry_safe(bp, n, buffer_list, b_list) {
+ if (!wait) {
+ if (xfs_buf_ispinned(bp)) {
+ pinned++;
+ continue;
+ }
+ if (!xfs_buf_trylock(bp))
+ continue;
+ } else {
+ xfs_buf_lock(bp);
+ }
- do {
- long age = xfs_buf_age_centisecs * msecs_to_jiffies(10);
- long tout = xfs_buf_timer_centisecs * msecs_to_jiffies(10);
- struct list_head tmp;
- struct blk_plug plug;
+ /*
+ * Someone else might have written the buffer synchronously or
+ * marked it stale in the meantime. In that case only the
+ * _XBF_DELWRI_Q flag got cleared, and we have to drop the
+ * reference and remove it from the list here.
+ */
+ if (!(bp->b_flags & _XBF_DELWRI_Q)) {
+ list_del_init(&bp->b_list);
+ xfs_buf_relse(bp);
+ continue;
+ }
- if (unlikely(freezing(current)))
- try_to_freeze();
+ list_move_tail(&bp->b_list, io_list);
+ trace_xfs_buf_delwri_split(bp, _RET_IP_);
+ }
- /* sleep for a long time if there is nothing to do. */
- if (list_empty(&target->bt_delwri_queue))
- tout = MAX_SCHEDULE_TIMEOUT;
- schedule_timeout_interruptible(tout);
+ list_sort(NULL, io_list, xfs_buf_cmp);
- xfs_buf_delwri_split(target, &tmp, age);
- list_sort(NULL, &tmp, xfs_buf_cmp);
+ blk_start_plug(&plug);
+ list_for_each_entry_safe(bp, n, io_list, b_list) {
+ bp->b_flags &= ~(_XBF_DELWRI_Q | XBF_ASYNC);
+ bp->b_flags |= XBF_WRITE;
- blk_start_plug(&plug);
- while (!list_empty(&tmp)) {
- struct xfs_buf *bp;
- bp = list_first_entry(&tmp, struct xfs_buf, b_list);
+ if (!wait) {
+ bp->b_flags |= XBF_ASYNC;
list_del_init(&bp->b_list);
- xfs_bdstrat_cb(bp);
}
- blk_finish_plug(&plug);
- } while (!kthread_should_stop());
+ xfs_bdstrat_cb(bp);
+ }
+ blk_finish_plug(&plug);
- return 0;
+ return pinned;
}
/*
- * Go through all incore buffers, and release buffers if they belong to
- * the given device. This is used in filesystem error handling to
- * preserve the consistency of its metadata.
+ * Write out a buffer list asynchronously.
+ *
+ * This will take the @buffer_list, write all non-locked and non-pinned buffers
+ * out and not wait for I/O completion on any of the buffers. This interface
+ * is only safely useable for callers that can track I/O completion by higher
+ * level means, e.g. AIL pushing as the @buffer_list is consumed in this
+ * function.
*/
int
-xfs_flush_buftarg(
- xfs_buftarg_t *target,
- int wait)
+xfs_buf_delwri_submit_nowait(
+ struct list_head *buffer_list)
{
- xfs_buf_t *bp;
- int pincount = 0;
- LIST_HEAD(tmp_list);
- LIST_HEAD(wait_list);
- struct blk_plug plug;
+ LIST_HEAD (io_list);
+ return __xfs_buf_delwri_submit(buffer_list, &io_list, false);
+}
- flush_workqueue(xfslogd_workqueue);
+/*
+ * Write out a buffer list synchronously.
+ *
+ * This will take the @buffer_list, write all buffers out and wait for I/O
+ * completion on all of the buffers. @buffer_list is consumed by the function,
+ * so callers must have some other way of tracking buffers if they require such
+ * functionality.
+ */
+int
+xfs_buf_delwri_submit(
+ struct list_head *buffer_list)
+{
+ LIST_HEAD (io_list);
+ int error = 0, error2;
+ struct xfs_buf *bp;
- set_bit(XBT_FORCE_FLUSH, &target->bt_flags);
- pincount = xfs_buf_delwri_split(target, &tmp_list, 0);
+ __xfs_buf_delwri_submit(buffer_list, &io_list, true);
- /*
- * Dropped the delayed write list lock, now walk the temporary list.
- * All I/O is issued async and then if we need to wait for completion
- * we do that after issuing all the IO.
- */
- list_sort(NULL, &tmp_list, xfs_buf_cmp);
+ /* Wait for IO to complete. */
+ while (!list_empty(&io_list)) {
+ bp = list_first_entry(&io_list, struct xfs_buf, b_list);
- blk_start_plug(&plug);
- while (!list_empty(&tmp_list)) {
- bp = list_first_entry(&tmp_list, struct xfs_buf, b_list);
- ASSERT(target == bp->b_target);
list_del_init(&bp->b_list);
- if (wait) {
- bp->b_flags &= ~XBF_ASYNC;
- list_add(&bp->b_list, &wait_list);
- }
- xfs_bdstrat_cb(bp);
- }
- blk_finish_plug(&plug);
-
- if (wait) {
- /* Wait for IO to complete. */
- while (!list_empty(&wait_list)) {
- bp = list_first_entry(&wait_list, struct xfs_buf, b_list);
-
- list_del_init(&bp->b_list);
- xfs_buf_iowait(bp);
- xfs_buf_relse(bp);
- }
+ error2 = xfs_buf_iowait(bp);
+ xfs_buf_relse(bp);
+ if (!error)
+ error = error2;
}
- return pincount;
+ return error;
}
int __init
diff --git a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h
index 5bf3be45f543..7f1d1392ce37 100644
--- a/fs/xfs/xfs_buf.h
+++ b/fs/xfs/xfs_buf.h
@@ -32,11 +32,6 @@
#define XFS_BUF_DADDR_NULL ((xfs_daddr_t) (-1LL))
-#define xfs_buf_ctob(pp) ((pp) * PAGE_CACHE_SIZE)
-#define xfs_buf_btoc(dd) (((dd) + PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT)
-#define xfs_buf_btoct(dd) ((dd) >> PAGE_CACHE_SHIFT)
-#define xfs_buf_poff(aa) ((aa) & ~PAGE_CACHE_MASK)
-
typedef enum {
XBRW_READ = 1, /* transfer into target memory */
XBRW_WRITE = 2, /* transfer from target memory */
@@ -46,11 +41,9 @@ typedef enum {
#define XBF_READ (1 << 0) /* buffer intended for reading from device */
#define XBF_WRITE (1 << 1) /* buffer intended for writing to device */
#define XBF_READ_AHEAD (1 << 2) /* asynchronous read-ahead */
-#define XBF_MAPPED (1 << 3) /* buffer mapped (b_addr valid) */
#define XBF_ASYNC (1 << 4) /* initiator will not wait for completion */
#define XBF_DONE (1 << 5) /* all pages in the buffer uptodate */
-#define XBF_DELWRI (1 << 6) /* buffer has dirty pages */
-#define XBF_STALE (1 << 7) /* buffer has been staled, do not find it */
+#define XBF_STALE (1 << 6) /* buffer has been staled, do not find it */
/* I/O hints for the BIO layer */
#define XBF_SYNCIO (1 << 10)/* treat this buffer as synchronous I/O */
@@ -58,14 +51,13 @@ typedef enum {
#define XBF_FLUSH (1 << 12)/* flush the disk cache before a write */
/* flags used only as arguments to access routines */
-#define XBF_LOCK (1 << 15)/* lock requested */
#define XBF_TRYLOCK (1 << 16)/* lock requested, but do not wait */
-#define XBF_DONT_BLOCK (1 << 17)/* do not block in current thread */
+#define XBF_UNMAPPED (1 << 17)/* do not map the buffer */
/* flags used only internally */
#define _XBF_PAGES (1 << 20)/* backed by refcounted pages */
#define _XBF_KMEM (1 << 21)/* backed by heap memory */
-#define _XBF_DELWRI_Q (1 << 22)/* buffer on delwri queue */
+#define _XBF_DELWRI_Q (1 << 22)/* buffer on a delwri queue */
typedef unsigned int xfs_buf_flags_t;
@@ -73,25 +65,18 @@ typedef unsigned int xfs_buf_flags_t;
{ XBF_READ, "READ" }, \
{ XBF_WRITE, "WRITE" }, \
{ XBF_READ_AHEAD, "READ_AHEAD" }, \
- { XBF_MAPPED, "MAPPED" }, \
{ XBF_ASYNC, "ASYNC" }, \
{ XBF_DONE, "DONE" }, \
- { XBF_DELWRI, "DELWRI" }, \
{ XBF_STALE, "STALE" }, \
{ XBF_SYNCIO, "SYNCIO" }, \
{ XBF_FUA, "FUA" }, \
{ XBF_FLUSH, "FLUSH" }, \
- { XBF_LOCK, "LOCK" }, /* should never be set */\
- { XBF_TRYLOCK, "TRYLOCK" }, /* ditto */\
- { XBF_DONT_BLOCK, "DONT_BLOCK" }, /* ditto */\
+ { XBF_TRYLOCK, "TRYLOCK" }, /* should never be set */\
+ { XBF_UNMAPPED, "UNMAPPED" }, /* ditto */\
{ _XBF_PAGES, "PAGES" }, \
{ _XBF_KMEM, "KMEM" }, \
{ _XBF_DELWRI_Q, "DELWRI_Q" }
-typedef enum {
- XBT_FORCE_FLUSH = 0,
-} xfs_buftarg_flags_t;
-
typedef struct xfs_buftarg {
dev_t bt_dev;
struct block_device *bt_bdev;
@@ -101,12 +86,6 @@ typedef struct xfs_buftarg {
unsigned int bt_sshift;
size_t bt_smask;
- /* per device delwri queue */
- struct task_struct *bt_task;
- struct list_head bt_delwri_queue;
- spinlock_t bt_delwri_lock;
- unsigned long bt_flags;
-
/* LRU control structures */
struct shrinker bt_shrinker;
struct list_head bt_lru;
@@ -128,8 +107,8 @@ typedef struct xfs_buf {
* fast-path on locking.
*/
struct rb_node b_rbnode; /* rbtree node */
- xfs_off_t b_file_offset; /* offset in file */
- size_t b_buffer_length;/* size of buffer in bytes */
+ xfs_daddr_t b_bn; /* block number for I/O */
+ int b_length; /* size of buffer in BBs */
atomic_t b_hold; /* reference count */
atomic_t b_lru_ref; /* lru reclaim ref count */
xfs_buf_flags_t b_flags; /* status flags */
@@ -140,8 +119,6 @@ typedef struct xfs_buf {
struct list_head b_list;
struct xfs_perag *b_pag; /* contains rbtree root */
xfs_buftarg_t *b_target; /* buffer target (device) */
- xfs_daddr_t b_bn; /* block number for I/O */
- size_t b_count_desired;/* desired transfer size */
void *b_addr; /* virtual address of buffer */
struct work_struct b_iodone_work;
xfs_buf_iodone_t b_iodone; /* I/O completion function */
@@ -150,7 +127,7 @@ typedef struct xfs_buf {
struct xfs_trans *b_transp;
struct page **b_pages; /* array of page pointers */
struct page *b_page_array[XB_PAGES]; /* inline pages */
- unsigned long b_queuetime; /* time buffer was queued */
+ int b_io_length; /* IO size in BBs */
atomic_t b_pin_count; /* pin count */
atomic_t b_io_remaining; /* #outstanding I/O requests */
unsigned int b_page_count; /* size of page array */
@@ -163,26 +140,30 @@ typedef struct xfs_buf {
/* Finding and Reading Buffers */
-extern xfs_buf_t *_xfs_buf_find(xfs_buftarg_t *, xfs_off_t, size_t,
- xfs_buf_flags_t, xfs_buf_t *);
+struct xfs_buf *_xfs_buf_find(struct xfs_buftarg *target, xfs_daddr_t blkno,
+ size_t numblks, xfs_buf_flags_t flags,
+ struct xfs_buf *new_bp);
#define xfs_incore(buftarg,blkno,len,lockit) \
_xfs_buf_find(buftarg, blkno ,len, lockit, NULL)
-extern xfs_buf_t *xfs_buf_get(xfs_buftarg_t *, xfs_off_t, size_t,
- xfs_buf_flags_t);
-extern xfs_buf_t *xfs_buf_read(xfs_buftarg_t *, xfs_off_t, size_t,
- xfs_buf_flags_t);
-
-struct xfs_buf *xfs_buf_alloc(struct xfs_buftarg *, xfs_off_t, size_t,
- xfs_buf_flags_t);
-extern void xfs_buf_set_empty(struct xfs_buf *bp, size_t len);
-extern xfs_buf_t *xfs_buf_get_uncached(struct xfs_buftarg *, size_t, int);
-extern int xfs_buf_associate_memory(xfs_buf_t *, void *, size_t);
-extern void xfs_buf_hold(xfs_buf_t *);
-extern void xfs_buf_readahead(xfs_buftarg_t *, xfs_off_t, size_t);
-struct xfs_buf *xfs_buf_read_uncached(struct xfs_mount *mp,
- struct xfs_buftarg *target,
- xfs_daddr_t daddr, size_t length, int flags);
+struct xfs_buf *xfs_buf_get(struct xfs_buftarg *target, xfs_daddr_t blkno,
+ size_t numblks, xfs_buf_flags_t flags);
+struct xfs_buf *xfs_buf_read(struct xfs_buftarg *target, xfs_daddr_t blkno,
+ size_t numblks, xfs_buf_flags_t flags);
+void xfs_buf_readahead(struct xfs_buftarg *target, xfs_daddr_t blkno,
+ size_t numblks);
+
+struct xfs_buf *xfs_buf_get_empty(struct xfs_buftarg *target, size_t numblks);
+struct xfs_buf *xfs_buf_alloc(struct xfs_buftarg *target, xfs_daddr_t blkno,
+ size_t numblks, xfs_buf_flags_t flags);
+void xfs_buf_set_empty(struct xfs_buf *bp, size_t numblks);
+int xfs_buf_associate_memory(struct xfs_buf *bp, void *mem, size_t length);
+
+struct xfs_buf *xfs_buf_get_uncached(struct xfs_buftarg *target, size_t numblks,
+ int flags);
+struct xfs_buf *xfs_buf_read_uncached(struct xfs_buftarg *target,
+ xfs_daddr_t daddr, size_t numblks, int flags);
+void xfs_buf_hold(struct xfs_buf *bp);
/* Releasing Buffers */
extern void xfs_buf_free(xfs_buf_t *);
@@ -204,7 +185,7 @@ extern int xfs_bdstrat_cb(struct xfs_buf *);
extern void xfs_buf_ioend(xfs_buf_t *, int);
extern void xfs_buf_ioerror(xfs_buf_t *, int);
extern void xfs_buf_ioerror_alert(struct xfs_buf *, const char *func);
-extern int xfs_buf_iorequest(xfs_buf_t *);
+extern void xfs_buf_iorequest(xfs_buf_t *);
extern int xfs_buf_iowait(xfs_buf_t *);
extern void xfs_buf_iomove(xfs_buf_t *, size_t, size_t, void *,
xfs_buf_rw_t);
@@ -220,24 +201,22 @@ static inline int xfs_buf_geterror(xfs_buf_t *bp)
extern xfs_caddr_t xfs_buf_offset(xfs_buf_t *, size_t);
/* Delayed Write Buffer Routines */
-extern void xfs_buf_delwri_queue(struct xfs_buf *);
-extern void xfs_buf_delwri_dequeue(struct xfs_buf *);
-extern void xfs_buf_delwri_promote(struct xfs_buf *);
+extern bool xfs_buf_delwri_queue(struct xfs_buf *, struct list_head *);
+extern int xfs_buf_delwri_submit(struct list_head *);
+extern int xfs_buf_delwri_submit_nowait(struct list_head *);
/* Buffer Daemon Setup Routines */
extern int xfs_buf_init(void);
extern void xfs_buf_terminate(void);
#define XFS_BUF_ZEROFLAGS(bp) \
- ((bp)->b_flags &= ~(XBF_READ|XBF_WRITE|XBF_ASYNC|XBF_DELWRI| \
+ ((bp)->b_flags &= ~(XBF_READ|XBF_WRITE|XBF_ASYNC| \
XBF_SYNCIO|XBF_FUA|XBF_FLUSH))
void xfs_buf_stale(struct xfs_buf *bp);
#define XFS_BUF_UNSTALE(bp) ((bp)->b_flags &= ~XBF_STALE)
#define XFS_BUF_ISSTALE(bp) ((bp)->b_flags & XBF_STALE)
-#define XFS_BUF_ISDELAYWRITE(bp) ((bp)->b_flags & XBF_DELWRI)
-
#define XFS_BUF_DONE(bp) ((bp)->b_flags |= XBF_DONE)
#define XFS_BUF_UNDONE(bp) ((bp)->b_flags &= ~XBF_DONE)
#define XFS_BUF_ISDONE(bp) ((bp)->b_flags & XBF_DONE)
@@ -256,12 +235,6 @@ void xfs_buf_stale(struct xfs_buf *bp);
#define XFS_BUF_ADDR(bp) ((bp)->b_bn)
#define XFS_BUF_SET_ADDR(bp, bno) ((bp)->b_bn = (xfs_daddr_t)(bno))
-#define XFS_BUF_OFFSET(bp) ((bp)->b_file_offset)
-#define XFS_BUF_SET_OFFSET(bp, off) ((bp)->b_file_offset = (off))
-#define XFS_BUF_COUNT(bp) ((bp)->b_count_desired)
-#define XFS_BUF_SET_COUNT(bp, cnt) ((bp)->b_count_desired = (cnt))
-#define XFS_BUF_SIZE(bp) ((bp)->b_buffer_length)
-#define XFS_BUF_SET_SIZE(bp, cnt) ((bp)->b_buffer_length = (cnt))
static inline void xfs_buf_set_ref(struct xfs_buf *bp, int lru_ref)
{
@@ -287,7 +260,6 @@ extern xfs_buftarg_t *xfs_alloc_buftarg(struct xfs_mount *,
extern void xfs_free_buftarg(struct xfs_mount *, struct xfs_buftarg *);
extern void xfs_wait_buftarg(xfs_buftarg_t *);
extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int, unsigned int);
-extern int xfs_flush_buftarg(xfs_buftarg_t *, int);
#define xfs_getsize_buftarg(buftarg) block_size((buftarg)->bt_bdev)
#define xfs_readonly_buftarg(buftarg) bdev_read_only((buftarg)->bt_bdev)
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index eac97ef81e2a..45df2b857d48 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -20,7 +20,6 @@
#include "xfs_types.h"
#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
@@ -123,11 +122,11 @@ xfs_buf_item_log_check(
ASSERT(bip->bli_logged != NULL);
bp = bip->bli_buf;
- ASSERT(XFS_BUF_COUNT(bp) > 0);
+ ASSERT(bp->b_length > 0);
ASSERT(bp->b_addr != NULL);
orig = bip->bli_orig;
buffer = bp->b_addr;
- for (x = 0; x < XFS_BUF_COUNT(bp); x++) {
+ for (x = 0; x < BBTOB(bp->b_length); x++) {
if (orig[x] != buffer[x] && !btst(bip->bli_logged, x)) {
xfs_emerg(bp->b_mount,
"%s: bip %x buffer %x orig %x index %d",
@@ -418,7 +417,6 @@ xfs_buf_item_unpin(
if (freed && stale) {
ASSERT(bip->bli_flags & XFS_BLI_STALE);
ASSERT(xfs_buf_islocked(bp));
- ASSERT(!(XFS_BUF_ISDELAYWRITE(bp)));
ASSERT(XFS_BUF_ISSTALE(bp));
ASSERT(bip->bli_format.blf_flags & XFS_BLF_CANCEL);
@@ -455,42 +453,42 @@ xfs_buf_item_unpin(
bp->b_iodone = NULL;
} else {
spin_lock(&ailp->xa_lock);
- xfs_trans_ail_delete(ailp, (xfs_log_item_t *)bip);
+ xfs_trans_ail_delete(ailp, lip, SHUTDOWN_LOG_IO_ERROR);
xfs_buf_item_relse(bp);
ASSERT(bp->b_fspriv == NULL);
}
xfs_buf_relse(bp);
+ } else if (freed && remove) {
+ xfs_buf_lock(bp);
+ xfs_buf_ioerror(bp, EIO);
+ XFS_BUF_UNDONE(bp);
+ xfs_buf_stale(bp);
+ xfs_buf_ioend(bp, 0);
}
}
-/*
- * This is called to attempt to lock the buffer associated with this
- * buf log item. Don't sleep on the buffer lock. If we can't get
- * the lock right away, return 0. If we can get the lock, take a
- * reference to the buffer. If this is a delayed write buffer that
- * needs AIL help to be written back, invoke the pushbuf routine
- * rather than the normal success path.
- */
STATIC uint
-xfs_buf_item_trylock(
- struct xfs_log_item *lip)
+xfs_buf_item_push(
+ struct xfs_log_item *lip,
+ struct list_head *buffer_list)
{
struct xfs_buf_log_item *bip = BUF_ITEM(lip);
struct xfs_buf *bp = bip->bli_buf;
+ uint rval = XFS_ITEM_SUCCESS;
if (xfs_buf_ispinned(bp))
return XFS_ITEM_PINNED;
if (!xfs_buf_trylock(bp))
return XFS_ITEM_LOCKED;
- /* take a reference to the buffer. */
- xfs_buf_hold(bp);
-
ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
- trace_xfs_buf_item_trylock(bip);
- if (XFS_BUF_ISDELAYWRITE(bp))
- return XFS_ITEM_PUSHBUF;
- return XFS_ITEM_SUCCESS;
+
+ trace_xfs_buf_item_push(bip);
+
+ if (!xfs_buf_delwri_queue(bp, buffer_list))
+ rval = XFS_ITEM_FLUSHING;
+ xfs_buf_unlock(bp);
+ return rval;
}
/*
@@ -603,49 +601,6 @@ xfs_buf_item_committed(
return lsn;
}
-/*
- * The buffer is locked, but is not a delayed write buffer. This happens
- * if we race with IO completion and hence we don't want to try to write it
- * again. Just release the buffer.
- */
-STATIC void
-xfs_buf_item_push(
- struct xfs_log_item *lip)
-{
- struct xfs_buf_log_item *bip = BUF_ITEM(lip);
- struct xfs_buf *bp = bip->bli_buf;
-
- ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
- ASSERT(!XFS_BUF_ISDELAYWRITE(bp));
-
- trace_xfs_buf_item_push(bip);
-
- xfs_buf_relse(bp);
-}
-
-/*
- * The buffer is locked and is a delayed write buffer. Promote the buffer
- * in the delayed write queue as the caller knows that they must invoke
- * the xfsbufd to get this buffer written. We have to unlock the buffer
- * to allow the xfsbufd to write it, too.
- */
-STATIC bool
-xfs_buf_item_pushbuf(
- struct xfs_log_item *lip)
-{
- struct xfs_buf_log_item *bip = BUF_ITEM(lip);
- struct xfs_buf *bp = bip->bli_buf;
-
- ASSERT(!(bip->bli_flags & XFS_BLI_STALE));
- ASSERT(XFS_BUF_ISDELAYWRITE(bp));
-
- trace_xfs_buf_item_pushbuf(bip);
-
- xfs_buf_delwri_promote(bp);
- xfs_buf_relse(bp);
- return true;
-}
-
STATIC void
xfs_buf_item_committing(
struct xfs_log_item *lip,
@@ -661,11 +616,9 @@ static const struct xfs_item_ops xfs_buf_item_ops = {
.iop_format = xfs_buf_item_format,
.iop_pin = xfs_buf_item_pin,
.iop_unpin = xfs_buf_item_unpin,
- .iop_trylock = xfs_buf_item_trylock,
.iop_unlock = xfs_buf_item_unlock,
.iop_committed = xfs_buf_item_committed,
.iop_push = xfs_buf_item_push,
- .iop_pushbuf = xfs_buf_item_pushbuf,
.iop_committing = xfs_buf_item_committing
};
@@ -703,7 +656,8 @@ xfs_buf_item_init(
* truncate any pieces. map_size is the size of the
* bitmap needed to describe the chunks of the buffer.
*/
- chunks = (int)((XFS_BUF_COUNT(bp) + (XFS_BLF_CHUNK - 1)) >> XFS_BLF_SHIFT);
+ chunks = (int)((BBTOB(bp->b_length) + (XFS_BLF_CHUNK - 1)) >>
+ XFS_BLF_SHIFT);
map_size = (int)((chunks + NBWORD) >> BIT_TO_WORD_SHIFT);
bip = (xfs_buf_log_item_t*)kmem_zone_zalloc(xfs_buf_item_zone,
@@ -713,7 +667,7 @@ xfs_buf_item_init(
xfs_buf_hold(bp);
bip->bli_format.blf_type = XFS_LI_BUF;
bip->bli_format.blf_blkno = (__int64_t)XFS_BUF_ADDR(bp);
- bip->bli_format.blf_len = (ushort)BTOBB(XFS_BUF_COUNT(bp));
+ bip->bli_format.blf_len = (ushort)bp->b_length;
bip->bli_format.blf_map_size = map_size;
#ifdef XFS_TRANS_DEBUG
@@ -725,9 +679,9 @@ xfs_buf_item_init(
* the buffer to indicate which bytes the callers have asked
* to have logged.
*/
- bip->bli_orig = (char *)kmem_alloc(XFS_BUF_COUNT(bp), KM_SLEEP);
- memcpy(bip->bli_orig, bp->b_addr, XFS_BUF_COUNT(bp));
- bip->bli_logged = (char *)kmem_zalloc(XFS_BUF_COUNT(bp) / NBBY, KM_SLEEP);
+ bip->bli_orig = kmem_alloc(BBTOB(bp->b_length), KM_SLEEP);
+ memcpy(bip->bli_orig, bp->b_addr, BBTOB(bp->b_length));
+ bip->bli_logged = kmem_zalloc(BBTOB(bp->b_length) / NBBY, KM_SLEEP);
#endif
/*
@@ -984,20 +938,27 @@ xfs_buf_iodone_callbacks(
* If the write was asynchronous then no one will be looking for the
* error. Clear the error state and write the buffer out again.
*
- * During sync or umount we'll write all pending buffers again
- * synchronous, which will catch these errors if they keep hanging
- * around.
+ * XXX: This helps against transient write errors, but we need to find
+ * a way to shut the filesystem down if the writes keep failing.
+ *
+ * In practice we'll shut the filesystem down soon as non-transient
+ * erorrs tend to affect the whole device and a failing log write
+ * will make us give up. But we really ought to do better here.
*/
if (XFS_BUF_ISASYNC(bp)) {
+ ASSERT(bp->b_iodone != NULL);
+
+ trace_xfs_buf_item_iodone_async(bp, _RET_IP_);
+
xfs_buf_ioerror(bp, 0); /* errno of 0 unsets the flag */
if (!XFS_BUF_ISSTALE(bp)) {
- xfs_buf_delwri_queue(bp);
- XFS_BUF_DONE(bp);
+ bp->b_flags |= XBF_WRITE | XBF_ASYNC | XBF_DONE;
+ xfs_bdstrat_cb(bp);
+ } else {
+ xfs_buf_relse(bp);
}
- ASSERT(bp->b_iodone != NULL);
- trace_xfs_buf_item_iodone_async(bp, _RET_IP_);
- xfs_buf_relse(bp);
+
return;
}
@@ -1045,6 +1006,6 @@ xfs_buf_iodone(
* Either way, AIL is useless if we're forcing a shutdown.
*/
spin_lock(&ailp->xa_lock);
- xfs_trans_ail_delete(ailp, lip);
+ xfs_trans_ail_delete(ailp, lip, SHUTDOWN_CORRUPT_INCORE);
xfs_buf_item_free(BUF_ITEM(lip));
}
diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c
index 7f1a6f5b05a6..015b946c5808 100644
--- a/fs/xfs/xfs_da_btree.c
+++ b/fs/xfs/xfs_da_btree.c
@@ -20,7 +20,6 @@
#include "xfs_types.h"
#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
@@ -2277,20 +2276,20 @@ xfs_da_buf_make(int nbuf, xfs_buf_t **bps)
if (nbuf == 1) {
dabuf->nbuf = 1;
bp = bps[0];
- dabuf->bbcount = (short)BTOBB(XFS_BUF_COUNT(bp));
+ dabuf->bbcount = bp->b_length;
dabuf->data = bp->b_addr;
dabuf->bps[0] = bp;
} else {
dabuf->nbuf = nbuf;
for (i = 0, dabuf->bbcount = 0; i < nbuf; i++) {
dabuf->bps[i] = bp = bps[i];
- dabuf->bbcount += BTOBB(XFS_BUF_COUNT(bp));
+ dabuf->bbcount += bp->b_length;
}
dabuf->data = kmem_alloc(BBTOB(dabuf->bbcount), KM_SLEEP);
- for (i = off = 0; i < nbuf; i++, off += XFS_BUF_COUNT(bp)) {
+ for (i = off = 0; i < nbuf; i++, off += BBTOB(bp->b_length)) {
bp = bps[i];
memcpy((char *)dabuf->data + off, bp->b_addr,
- XFS_BUF_COUNT(bp));
+ BBTOB(bp->b_length));
}
}
return dabuf;
@@ -2310,10 +2309,10 @@ xfs_da_buf_clean(xfs_dabuf_t *dabuf)
ASSERT(dabuf->nbuf > 1);
dabuf->dirty = 0;
for (i = off = 0; i < dabuf->nbuf;
- i++, off += XFS_BUF_COUNT(bp)) {
+ i++, off += BBTOB(bp->b_length)) {
bp = dabuf->bps[i];
memcpy(bp->b_addr, dabuf->data + off,
- XFS_BUF_COUNT(bp));
+ BBTOB(bp->b_length));
}
}
}
@@ -2356,10 +2355,10 @@ xfs_da_log_buf(xfs_trans_t *tp, xfs_dabuf_t *dabuf, uint first, uint last)
}
dabuf->dirty = 1;
ASSERT(first <= last);
- for (i = off = 0; i < dabuf->nbuf; i++, off += XFS_BUF_COUNT(bp)) {
+ for (i = off = 0; i < dabuf->nbuf; i++, off += BBTOB(bp->b_length)) {
bp = dabuf->bps[i];
f = off;
- l = f + XFS_BUF_COUNT(bp) - 1;
+ l = f + BBTOB(bp->b_length) - 1;
if (f < first)
f = first;
if (l > last)
diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c
index 1137bbc5eccb..e00de08dc8ac 100644
--- a/fs/xfs/xfs_dfrag.c
+++ b/fs/xfs/xfs_dfrag.c
@@ -18,9 +18,7 @@
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_types.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c
index a2e27010c7fb..67a250c36d41 100644
--- a/fs/xfs/xfs_dir2.c
+++ b/fs/xfs/xfs_dir2.c
@@ -18,7 +18,6 @@
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_types.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
#include "xfs_inum.h"
#include "xfs_trans.h"
diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c
index d3b63aefd01d..586732f2d80d 100644
--- a/fs/xfs/xfs_dir2_block.c
+++ b/fs/xfs/xfs_dir2_block.c
@@ -19,7 +19,6 @@
#include "xfs_fs.h"
#include "xfs_types.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
diff --git a/fs/xfs/xfs_dir2_data.c b/fs/xfs/xfs_dir2_data.c
index 5bbe2a8a023f..2046988e9eb2 100644
--- a/fs/xfs/xfs_dir2_data.c
+++ b/fs/xfs/xfs_dir2_data.c
@@ -19,7 +19,6 @@
#include "xfs_fs.h"
#include "xfs_types.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c
index 66e108f561a3..397ffbcbab1d 100644
--- a/fs/xfs/xfs_dir2_leaf.c
+++ b/fs/xfs/xfs_dir2_leaf.c
@@ -20,7 +20,6 @@
#include "xfs_types.h"
#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c
index 0179a41d9e5a..b0f26780449d 100644
--- a/fs/xfs/xfs_dir2_node.c
+++ b/fs/xfs/xfs_dir2_node.c
@@ -19,7 +19,6 @@
#include "xfs_fs.h"
#include "xfs_types.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
diff --git a/fs/xfs/xfs_dir2_sf.c b/fs/xfs/xfs_dir2_sf.c
index 79d05e84e296..19bf0c5e38f4 100644
--- a/fs/xfs/xfs_dir2_sf.c
+++ b/fs/xfs/xfs_dir2_sf.c
@@ -19,7 +19,6 @@
#include "xfs_fs.h"
#include "xfs_types.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
diff --git a/fs/xfs/xfs_discard.c b/fs/xfs/xfs_discard.c
index 1ad3a4b8ca40..f9c3fe304a17 100644
--- a/fs/xfs/xfs_discard.c
+++ b/fs/xfs/xfs_discard.c
@@ -17,7 +17,6 @@
*/
#include "xfs.h"
#include "xfs_sb.h"
-#include "xfs_inum.h"
#include "xfs_log.h"
#include "xfs_ag.h"
#include "xfs_mount.h"
@@ -30,6 +29,7 @@
#include "xfs_inode.h"
#include "xfs_alloc.h"
#include "xfs_error.h"
+#include "xfs_extent_busy.h"
#include "xfs_discard.h"
#include "xfs_trace.h"
@@ -118,7 +118,7 @@ xfs_trim_extents(
* If any blocks in the range are still busy, skip the
* discard and try again the next time.
*/
- if (xfs_alloc_busy_search(mp, agno, fbno, flen)) {
+ if (xfs_extent_busy_search(mp, agno, fbno, flen)) {
trace_xfs_discard_busy(mp, agno, fbno, flen);
goto next_extent;
}
@@ -212,7 +212,7 @@ xfs_discard_extents(
struct xfs_mount *mp,
struct list_head *list)
{
- struct xfs_busy_extent *busyp;
+ struct xfs_extent_busy *busyp;
int error = 0;
list_for_each_entry(busyp, list, list) {
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 1155208fa830..bf27fcca4843 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -19,7 +19,6 @@
#include "xfs_fs.h"
#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
@@ -857,7 +856,7 @@ xfs_qm_dqflush_done(
/* xfs_trans_ail_delete() drops the AIL lock. */
spin_lock(&ailp->xa_lock);
if (lip->li_lsn == qip->qli_flush_lsn)
- xfs_trans_ail_delete(ailp, lip);
+ xfs_trans_ail_delete(ailp, lip, SHUTDOWN_CORRUPT_INCORE);
else
spin_unlock(&ailp->xa_lock);
}
@@ -878,8 +877,8 @@ xfs_qm_dqflush_done(
*/
int
xfs_qm_dqflush(
- xfs_dquot_t *dqp,
- uint flags)
+ struct xfs_dquot *dqp,
+ struct xfs_buf **bpp)
{
struct xfs_mount *mp = dqp->q_mount;
struct xfs_buf *bp;
@@ -891,25 +890,30 @@ xfs_qm_dqflush(
trace_xfs_dqflush(dqp);
- /*
- * If not dirty, or it's pinned and we are not supposed to block, nada.
- */
- if (!XFS_DQ_IS_DIRTY(dqp) ||
- ((flags & SYNC_TRYLOCK) && atomic_read(&dqp->q_pincount) > 0)) {
- xfs_dqfunlock(dqp);
- return 0;
- }
+ *bpp = NULL;
+
xfs_qm_dqunpin_wait(dqp);
/*
* This may have been unpinned because the filesystem is shutting
* down forcibly. If that's the case we must not write this dquot
- * to disk, because the log record didn't make it to disk!
+ * to disk, because the log record didn't make it to disk.
+ *
+ * We also have to remove the log item from the AIL in this case,
+ * as we wait for an emptry AIL as part of the unmount process.
*/
if (XFS_FORCED_SHUTDOWN(mp)) {
+ struct xfs_log_item *lip = &dqp->q_logitem.qli_item;
dqp->dq_flags &= ~XFS_DQ_DIRTY;
- xfs_dqfunlock(dqp);
- return XFS_ERROR(EIO);
+
+ spin_lock(&mp->m_ail->xa_lock);
+ if (lip->li_flags & XFS_LI_IN_AIL)
+ xfs_trans_ail_delete(mp->m_ail, lip,
+ SHUTDOWN_CORRUPT_INCORE);
+ else
+ spin_unlock(&mp->m_ail->xa_lock);
+ error = XFS_ERROR(EIO);
+ goto out_unlock;
}
/*
@@ -917,11 +921,8 @@ xfs_qm_dqflush(
*/
error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dqp->q_blkno,
mp->m_quotainfo->qi_dqchunklen, 0, &bp);
- if (error) {
- ASSERT(error != ENOENT);
- xfs_dqfunlock(dqp);
- return error;
- }
+ if (error)
+ goto out_unlock;
/*
* Calculate the location of the dquot inside the buffer.
@@ -967,20 +968,13 @@ xfs_qm_dqflush(
xfs_log_force(mp, 0);
}
- if (flags & SYNC_WAIT)
- error = xfs_bwrite(bp);
- else
- xfs_buf_delwri_queue(bp);
-
- xfs_buf_relse(bp);
-
trace_xfs_dqflush_done(dqp);
+ *bpp = bp;
+ return 0;
- /*
- * dqp is still locked, but caller is free to unlock it now.
- */
- return error;
-
+out_unlock:
+ xfs_dqfunlock(dqp);
+ return XFS_ERROR(EIO);
}
/*
@@ -1011,39 +1005,6 @@ xfs_dqlock2(
}
}
-/*
- * Give the buffer a little push if it is incore and
- * wait on the flush lock.
- */
-void
-xfs_dqflock_pushbuf_wait(
- xfs_dquot_t *dqp)
-{
- xfs_mount_t *mp = dqp->q_mount;
- xfs_buf_t *bp;
-
- /*
- * Check to see if the dquot has been flushed delayed
- * write. If so, grab its buffer and send it
- * out immediately. We'll be able to acquire
- * the flush lock when the I/O completes.
- */
- bp = xfs_incore(mp->m_ddev_targp, dqp->q_blkno,
- mp->m_quotainfo->qi_dqchunklen, XBF_TRYLOCK);
- if (!bp)
- goto out_lock;
-
- if (XFS_BUF_ISDELAYWRITE(bp)) {
- if (xfs_buf_ispinned(bp))
- xfs_log_force(mp, 0);
- xfs_buf_delwri_promote(bp);
- wake_up_process(bp->b_target->bt_task);
- }
- xfs_buf_relse(bp);
-out_lock:
- xfs_dqflock(dqp);
-}
-
int __init
xfs_qm_init(void)
{
diff --git a/fs/xfs/xfs_dquot.h b/fs/xfs/xfs_dquot.h
index ef9190bd8b30..7d20af27346d 100644
--- a/fs/xfs/xfs_dquot.h
+++ b/fs/xfs/xfs_dquot.h
@@ -141,7 +141,7 @@ static inline xfs_dquot_t *xfs_inode_dquot(struct xfs_inode *ip, int type)
extern int xfs_qm_dqread(struct xfs_mount *, xfs_dqid_t, uint,
uint, struct xfs_dquot **);
extern void xfs_qm_dqdestroy(xfs_dquot_t *);
-extern int xfs_qm_dqflush(xfs_dquot_t *, uint);
+extern int xfs_qm_dqflush(struct xfs_dquot *, struct xfs_buf **);
extern void xfs_qm_dqunpin_wait(xfs_dquot_t *);
extern void xfs_qm_adjust_dqtimers(xfs_mount_t *,
xfs_disk_dquot_t *);
@@ -152,7 +152,6 @@ extern int xfs_qm_dqget(xfs_mount_t *, xfs_inode_t *,
extern void xfs_qm_dqput(xfs_dquot_t *);
extern void xfs_dqlock2(struct xfs_dquot *, struct xfs_dquot *);
-extern void xfs_dqflock_pushbuf_wait(struct xfs_dquot *dqp);
static inline struct xfs_dquot *xfs_qm_dqhold(struct xfs_dquot *dqp)
{
diff --git a/fs/xfs/xfs_dquot_item.c b/fs/xfs/xfs_dquot_item.c
index 34baeae45265..57aa4b03720c 100644
--- a/fs/xfs/xfs_dquot_item.c
+++ b/fs/xfs/xfs_dquot_item.c
@@ -17,9 +17,7 @@
*/
#include "xfs.h"
#include "xfs_fs.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
@@ -108,38 +106,6 @@ xfs_qm_dquot_logitem_unpin(
wake_up(&dqp->q_pinwait);
}
-/*
- * Given the logitem, this writes the corresponding dquot entry to disk
- * asynchronously. This is called with the dquot entry securely locked;
- * we simply get xfs_qm_dqflush() to do the work, and unlock the dquot
- * at the end.
- */
-STATIC void
-xfs_qm_dquot_logitem_push(
- struct xfs_log_item *lip)
-{
- struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot;
- int error;
-
- ASSERT(XFS_DQ_IS_LOCKED(dqp));
- ASSERT(!completion_done(&dqp->q_flush));
-
- /*
- * Since we were able to lock the dquot's flush lock and
- * we found it on the AIL, the dquot must be dirty. This
- * is because the dquot is removed from the AIL while still
- * holding the flush lock in xfs_dqflush_done(). Thus, if
- * we found it in the AIL and were able to obtain the flush
- * lock without sleeping, then there must not have been
- * anyone in the process of flushing the dquot.
- */
- error = xfs_qm_dqflush(dqp, SYNC_TRYLOCK);
- if (error)
- xfs_warn(dqp->q_mount, "%s: push error %d on dqp %p",
- __func__, error, dqp);
- xfs_dqunlock(dqp);
-}
-
STATIC xfs_lsn_t
xfs_qm_dquot_logitem_committed(
struct xfs_log_item *lip,
@@ -171,67 +137,15 @@ xfs_qm_dqunpin_wait(
wait_event(dqp->q_pinwait, (atomic_read(&dqp->q_pincount) == 0));
}
-/*
- * This is called when IOP_TRYLOCK returns XFS_ITEM_PUSHBUF to indicate that
- * the dquot is locked by us, but the flush lock isn't. So, here we are
- * going to see if the relevant dquot buffer is incore, waiting on DELWRI.
- * If so, we want to push it out to help us take this item off the AIL as soon
- * as possible.
- *
- * We must not be holding the AIL lock at this point. Calling incore() to
- * search the buffer cache can be a time consuming thing, and AIL lock is a
- * spinlock.
- */
-STATIC bool
-xfs_qm_dquot_logitem_pushbuf(
- struct xfs_log_item *lip)
-{
- struct xfs_dq_logitem *qlip = DQUOT_ITEM(lip);
- struct xfs_dquot *dqp = qlip->qli_dquot;
- struct xfs_buf *bp;
- bool ret = true;
-
- ASSERT(XFS_DQ_IS_LOCKED(dqp));
-
- /*
- * If flushlock isn't locked anymore, chances are that the
- * inode flush completed and the inode was taken off the AIL.
- * So, just get out.
- */
- if (completion_done(&dqp->q_flush) ||
- !(lip->li_flags & XFS_LI_IN_AIL)) {
- xfs_dqunlock(dqp);
- return true;
- }
-
- bp = xfs_incore(dqp->q_mount->m_ddev_targp, qlip->qli_format.qlf_blkno,
- dqp->q_mount->m_quotainfo->qi_dqchunklen, XBF_TRYLOCK);
- xfs_dqunlock(dqp);
- if (!bp)
- return true;
- if (XFS_BUF_ISDELAYWRITE(bp))
- xfs_buf_delwri_promote(bp);
- if (xfs_buf_ispinned(bp))
- ret = false;
- xfs_buf_relse(bp);
- return ret;
-}
-
-/*
- * This is called to attempt to lock the dquot associated with this
- * dquot log item. Don't sleep on the dquot lock or the flush lock.
- * If the flush lock is already held, indicating that the dquot has
- * been or is in the process of being flushed, then see if we can
- * find the dquot's buffer in the buffer cache without sleeping. If
- * we can and it is marked delayed write, then we want to send it out.
- * We delay doing so until the push routine, though, to avoid sleeping
- * in any device strategy routines.
- */
STATIC uint
-xfs_qm_dquot_logitem_trylock(
- struct xfs_log_item *lip)
+xfs_qm_dquot_logitem_push(
+ struct xfs_log_item *lip,
+ struct list_head *buffer_list)
{
struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot;
+ struct xfs_buf *bp = NULL;
+ uint rval = XFS_ITEM_SUCCESS;
+ int error;
if (atomic_read(&dqp->q_pincount) > 0)
return XFS_ITEM_PINNED;
@@ -239,16 +153,41 @@ xfs_qm_dquot_logitem_trylock(
if (!xfs_dqlock_nowait(dqp))
return XFS_ITEM_LOCKED;
+ /*
+ * Re-check the pincount now that we stabilized the value by
+ * taking the quota lock.
+ */
+ if (atomic_read(&dqp->q_pincount) > 0) {
+ rval = XFS_ITEM_PINNED;
+ goto out_unlock;
+ }
+
+ /*
+ * Someone else is already flushing the dquot. Nothing we can do
+ * here but wait for the flush to finish and remove the item from
+ * the AIL.
+ */
if (!xfs_dqflock_nowait(dqp)) {
- /*
- * dquot has already been flushed to the backing buffer,
- * leave it locked, pushbuf routine will unlock it.
- */
- return XFS_ITEM_PUSHBUF;
+ rval = XFS_ITEM_FLUSHING;
+ goto out_unlock;
}
- ASSERT(lip->li_flags & XFS_LI_IN_AIL);
- return XFS_ITEM_SUCCESS;
+ spin_unlock(&lip->li_ailp->xa_lock);
+
+ error = xfs_qm_dqflush(dqp, &bp);
+ if (error) {
+ xfs_warn(dqp->q_mount, "%s: push error %d on dqp %p",
+ __func__, error, dqp);
+ } else {
+ if (!xfs_buf_delwri_queue(bp, buffer_list))
+ rval = XFS_ITEM_FLUSHING;
+ xfs_buf_relse(bp);
+ }
+
+ spin_lock(&lip->li_ailp->xa_lock);
+out_unlock:
+ xfs_dqunlock(dqp);
+ return rval;
}
/*
@@ -299,11 +238,9 @@ static const struct xfs_item_ops xfs_dquot_item_ops = {
.iop_format = xfs_qm_dquot_logitem_format,
.iop_pin = xfs_qm_dquot_logitem_pin,
.iop_unpin = xfs_qm_dquot_logitem_unpin,
- .iop_trylock = xfs_qm_dquot_logitem_trylock,
.iop_unlock = xfs_qm_dquot_logitem_unlock,
.iop_committed = xfs_qm_dquot_logitem_committed,
.iop_push = xfs_qm_dquot_logitem_push,
- .iop_pushbuf = xfs_qm_dquot_logitem_pushbuf,
.iop_committing = xfs_qm_dquot_logitem_committing
};
@@ -398,11 +335,13 @@ xfs_qm_qoff_logitem_unpin(
}
/*
- * Quotaoff items have no locking, so just return success.
+ * There isn't much you can do to push a quotaoff item. It is simply
+ * stuck waiting for the log to be flushed to disk.
*/
STATIC uint
-xfs_qm_qoff_logitem_trylock(
- struct xfs_log_item *lip)
+xfs_qm_qoff_logitem_push(
+ struct xfs_log_item *lip,
+ struct list_head *buffer_list)
{
return XFS_ITEM_LOCKED;
}
@@ -429,17 +368,6 @@ xfs_qm_qoff_logitem_committed(
return lsn;
}
-/*
- * There isn't much you can do to push on an quotaoff item. It is simply
- * stuck waiting for the log to be flushed to disk.
- */
-STATIC void
-xfs_qm_qoff_logitem_push(
- struct xfs_log_item *lip)
-{
-}
-
-
STATIC xfs_lsn_t
xfs_qm_qoffend_logitem_committed(
struct xfs_log_item *lip,
@@ -454,7 +382,7 @@ xfs_qm_qoffend_logitem_committed(
* xfs_trans_ail_delete() drops the AIL lock.
*/
spin_lock(&ailp->xa_lock);
- xfs_trans_ail_delete(ailp, (xfs_log_item_t *)qfs);
+ xfs_trans_ail_delete(ailp, &qfs->qql_item, SHUTDOWN_LOG_IO_ERROR);
kmem_free(qfs);
kmem_free(qfe);
@@ -487,7 +415,6 @@ static const struct xfs_item_ops xfs_qm_qoffend_logitem_ops = {
.iop_format = xfs_qm_qoff_logitem_format,
.iop_pin = xfs_qm_qoff_logitem_pin,
.iop_unpin = xfs_qm_qoff_logitem_unpin,
- .iop_trylock = xfs_qm_qoff_logitem_trylock,
.iop_unlock = xfs_qm_qoff_logitem_unlock,
.iop_committed = xfs_qm_qoffend_logitem_committed,
.iop_push = xfs_qm_qoff_logitem_push,
@@ -502,7 +429,6 @@ static const struct xfs_item_ops xfs_qm_qoff_logitem_ops = {
.iop_format = xfs_qm_qoff_logitem_format,
.iop_pin = xfs_qm_qoff_logitem_pin,
.iop_unpin = xfs_qm_qoff_logitem_unpin,
- .iop_trylock = xfs_qm_qoff_logitem_trylock,
.iop_unlock = xfs_qm_qoff_logitem_unlock,
.iop_committed = xfs_qm_qoff_logitem_committed,
.iop_push = xfs_qm_qoff_logitem_push,
diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
index 39f06336b99d..610456054dc2 100644
--- a/fs/xfs/xfs_error.c
+++ b/fs/xfs/xfs_error.c
@@ -19,7 +19,6 @@
#include "xfs_fs.h"
#include "xfs_types.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
diff --git a/fs/xfs/xfs_export.c b/fs/xfs/xfs_export.c
index 558910f5e3c0..2d25d19c4ea1 100644
--- a/fs/xfs/xfs_export.c
+++ b/fs/xfs/xfs_export.c
@@ -17,7 +17,6 @@
*/
#include "xfs.h"
#include "xfs_types.h"
-#include "xfs_inum.h"
#include "xfs_log.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
diff --git a/fs/xfs/xfs_extent_busy.c b/fs/xfs/xfs_extent_busy.c
new file mode 100644
index 000000000000..85e9f87a1a7c
--- /dev/null
+++ b/fs/xfs/xfs_extent_busy.c
@@ -0,0 +1,603 @@
+/*
+ * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
+ * Copyright (c) 2010 David Chinner.
+ * Copyright (c) 2011 Christoph Hellwig.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_types.h"
+#include "xfs_log.h"
+#include "xfs_trans.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_mount.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_alloc.h"
+#include "xfs_inode.h"
+#include "xfs_extent_busy.h"
+#include "xfs_trace.h"
+
+void
+xfs_extent_busy_insert(
+ struct xfs_trans *tp,
+ xfs_agnumber_t agno,
+ xfs_agblock_t bno,
+ xfs_extlen_t len,
+ unsigned int flags)
+{
+ struct xfs_extent_busy *new;
+ struct xfs_extent_busy *busyp;
+ struct xfs_perag *pag;
+ struct rb_node **rbp;
+ struct rb_node *parent = NULL;
+
+ new = kmem_zalloc(sizeof(struct xfs_extent_busy), KM_MAYFAIL);
+ if (!new) {
+ /*
+ * No Memory! Since it is now not possible to track the free
+ * block, make this a synchronous transaction to insure that
+ * the block is not reused before this transaction commits.
+ */
+ trace_xfs_extent_busy_enomem(tp->t_mountp, agno, bno, len);
+ xfs_trans_set_sync(tp);
+ return;
+ }
+
+ new->agno = agno;
+ new->bno = bno;
+ new->length = len;
+ INIT_LIST_HEAD(&new->list);
+ new->flags = flags;
+
+ /* trace before insert to be able to see failed inserts */
+ trace_xfs_extent_busy(tp->t_mountp, agno, bno, len);
+
+ pag = xfs_perag_get(tp->t_mountp, new->agno);
+ spin_lock(&pag->pagb_lock);
+ rbp = &pag->pagb_tree.rb_node;
+ while (*rbp) {
+ parent = *rbp;
+ busyp = rb_entry(parent, struct xfs_extent_busy, rb_node);
+
+ if (new->bno < busyp->bno) {
+ rbp = &(*rbp)->rb_left;
+ ASSERT(new->bno + new->length <= busyp->bno);
+ } else if (new->bno > busyp->bno) {
+ rbp = &(*rbp)->rb_right;
+ ASSERT(bno >= busyp->bno + busyp->length);
+ } else {
+ ASSERT(0);
+ }
+ }
+
+ rb_link_node(&new->rb_node, parent, rbp);
+ rb_insert_color(&new->rb_node, &pag->pagb_tree);
+
+ list_add(&new->list, &tp->t_busy);
+ spin_unlock(&pag->pagb_lock);
+ xfs_perag_put(pag);
+}
+
+/*
+ * Search for a busy extent within the range of the extent we are about to
+ * allocate. You need to be holding the busy extent tree lock when calling
+ * xfs_extent_busy_search(). This function returns 0 for no overlapping busy
+ * extent, -1 for an overlapping but not exact busy extent, and 1 for an exact
+ * match. This is done so that a non-zero return indicates an overlap that
+ * will require a synchronous transaction, but it can still be
+ * used to distinguish between a partial or exact match.
+ */
+int
+xfs_extent_busy_search(
+ struct xfs_mount *mp,
+ xfs_agnumber_t agno,
+ xfs_agblock_t bno,
+ xfs_extlen_t len)
+{
+ struct xfs_perag *pag;
+ struct rb_node *rbp;
+ struct xfs_extent_busy *busyp;
+ int match = 0;
+
+ pag = xfs_perag_get(mp, agno);
+ spin_lock(&pag->pagb_lock);
+
+ rbp = pag->pagb_tree.rb_node;
+
+ /* find closest start bno overlap */
+ while (rbp) {
+ busyp = rb_entry(rbp, struct xfs_extent_busy, rb_node);
+ if (bno < busyp->bno) {
+ /* may overlap, but exact start block is lower */
+ if (bno + len > busyp->bno)
+ match = -1;
+ rbp = rbp->rb_left;
+ } else if (bno > busyp->bno) {
+ /* may overlap, but exact start block is higher */
+ if (bno < busyp->bno + busyp->length)
+ match = -1;
+ rbp = rbp->rb_right;
+ } else {
+ /* bno matches busyp, length determines exact match */
+ match = (busyp->length == len) ? 1 : -1;
+ break;
+ }
+ }
+ spin_unlock(&pag->pagb_lock);
+ xfs_perag_put(pag);
+ return match;
+}
+
+/*
+ * The found free extent [fbno, fend] overlaps part or all of the given busy
+ * extent. If the overlap covers the beginning, the end, or all of the busy
+ * extent, the overlapping portion can be made unbusy and used for the
+ * allocation. We can't split a busy extent because we can't modify a
+ * transaction/CIL context busy list, but we can update an entries block
+ * number or length.
+ *
+ * Returns true if the extent can safely be reused, or false if the search
+ * needs to be restarted.
+ */
+STATIC bool
+xfs_extent_busy_update_extent(
+ struct xfs_mount *mp,
+ struct xfs_perag *pag,
+ struct xfs_extent_busy *busyp,
+ xfs_agblock_t fbno,
+ xfs_extlen_t flen,
+ bool userdata)
+{
+ xfs_agblock_t fend = fbno + flen;
+ xfs_agblock_t bbno = busyp->bno;
+ xfs_agblock_t bend = bbno + busyp->length;
+
+ /*
+ * This extent is currently being discarded. Give the thread
+ * performing the discard a chance to mark the extent unbusy
+ * and retry.
+ */
+ if (busyp->flags & XFS_EXTENT_BUSY_DISCARDED) {
+ spin_unlock(&pag->pagb_lock);
+ delay(1);
+ spin_lock(&pag->pagb_lock);
+ return false;
+ }
+
+ /*
+ * If there is a busy extent overlapping a user allocation, we have
+ * no choice but to force the log and retry the search.
+ *
+ * Fortunately this does not happen during normal operation, but
+ * only if the filesystem is very low on space and has to dip into
+ * the AGFL for normal allocations.
+ */
+ if (userdata)
+ goto out_force_log;
+
+ if (bbno < fbno && bend > fend) {
+ /*
+ * Case 1:
+ * bbno bend
+ * +BBBBBBBBBBBBBBBBB+
+ * +---------+
+ * fbno fend
+ */
+
+ /*
+ * We would have to split the busy extent to be able to track
+ * it correct, which we cannot do because we would have to
+ * modify the list of busy extents attached to the transaction
+ * or CIL context, which is immutable.
+ *
+ * Force out the log to clear the busy extent and retry the
+ * search.
+ */
+ goto out_force_log;
+ } else if (bbno >= fbno && bend <= fend) {
+ /*
+ * Case 2:
+ * bbno bend
+ * +BBBBBBBBBBBBBBBBB+
+ * +-----------------+
+ * fbno fend
+ *
+ * Case 3:
+ * bbno bend
+ * +BBBBBBBBBBBBBBBBB+
+ * +--------------------------+
+ * fbno fend
+ *
+ * Case 4:
+ * bbno bend
+ * +BBBBBBBBBBBBBBBBB+
+ * +--------------------------+
+ * fbno fend
+ *
+ * Case 5:
+ * bbno bend
+ * +BBBBBBBBBBBBBBBBB+
+ * +-----------------------------------+
+ * fbno fend
+ *
+ */
+
+ /*
+ * The busy extent is fully covered by the extent we are
+ * allocating, and can simply be removed from the rbtree.
+ * However we cannot remove it from the immutable list
+ * tracking busy extents in the transaction or CIL context,
+ * so set the length to zero to mark it invalid.
+ *
+ * We also need to restart the busy extent search from the
+ * tree root, because erasing the node can rearrange the
+ * tree topology.
+ */
+ rb_erase(&busyp->rb_node, &pag->pagb_tree);
+ busyp->length = 0;
+ return false;
+ } else if (fend < bend) {
+ /*
+ * Case 6:
+ * bbno bend
+ * +BBBBBBBBBBBBBBBBB+
+ * +---------+
+ * fbno fend
+ *
+ * Case 7:
+ * bbno bend
+ * +BBBBBBBBBBBBBBBBB+
+ * +------------------+
+ * fbno fend
+ *
+ */
+ busyp->bno = fend;
+ } else if (bbno < fbno) {
+ /*
+ * Case 8:
+ * bbno bend
+ * +BBBBBBBBBBBBBBBBB+
+ * +-------------+
+ * fbno fend
+ *
+ * Case 9:
+ * bbno bend
+ * +BBBBBBBBBBBBBBBBB+
+ * +----------------------+
+ * fbno fend
+ */
+ busyp->length = fbno - busyp->bno;
+ } else {
+ ASSERT(0);
+ }
+
+ trace_xfs_extent_busy_reuse(mp, pag->pag_agno, fbno, flen);
+ return true;
+
+out_force_log:
+ spin_unlock(&pag->pagb_lock);
+ xfs_log_force(mp, XFS_LOG_SYNC);
+ trace_xfs_extent_busy_force(mp, pag->pag_agno, fbno, flen);
+ spin_lock(&pag->pagb_lock);
+ return false;
+}
+
+
+/*
+ * For a given extent [fbno, flen], make sure we can reuse it safely.
+ */
+void
+xfs_extent_busy_reuse(
+ struct xfs_mount *mp,
+ xfs_agnumber_t agno,
+ xfs_agblock_t fbno,
+ xfs_extlen_t flen,
+ bool userdata)
+{
+ struct xfs_perag *pag;
+ struct rb_node *rbp;
+
+ ASSERT(flen > 0);
+
+ pag = xfs_perag_get(mp, agno);
+ spin_lock(&pag->pagb_lock);
+restart:
+ rbp = pag->pagb_tree.rb_node;
+ while (rbp) {
+ struct xfs_extent_busy *busyp =
+ rb_entry(rbp, struct xfs_extent_busy, rb_node);
+ xfs_agblock_t bbno = busyp->bno;
+ xfs_agblock_t bend = bbno + busyp->length;
+
+ if (fbno + flen <= bbno) {
+ rbp = rbp->rb_left;
+ continue;
+ } else if (fbno >= bend) {
+ rbp = rbp->rb_right;
+ continue;
+ }
+
+ if (!xfs_extent_busy_update_extent(mp, pag, busyp, fbno, flen,
+ userdata))
+ goto restart;
+ }
+ spin_unlock(&pag->pagb_lock);
+ xfs_perag_put(pag);
+}
+
+/*
+ * For a given extent [fbno, flen], search the busy extent list to find a
+ * subset of the extent that is not busy. If *rlen is smaller than
+ * args->minlen no suitable extent could be found, and the higher level
+ * code needs to force out the log and retry the allocation.
+ */
+void
+xfs_extent_busy_trim(
+ struct xfs_alloc_arg *args,
+ xfs_agblock_t bno,
+ xfs_extlen_t len,
+ xfs_agblock_t *rbno,
+ xfs_extlen_t *rlen)
+{
+ xfs_agblock_t fbno;
+ xfs_extlen_t flen;
+ struct rb_node *rbp;
+
+ ASSERT(len > 0);
+
+ spin_lock(&args->pag->pagb_lock);
+restart:
+ fbno = bno;
+ flen = len;
+ rbp = args->pag->pagb_tree.rb_node;
+ while (rbp && flen >= args->minlen) {
+ struct xfs_extent_busy *busyp =
+ rb_entry(rbp, struct xfs_extent_busy, rb_node);
+ xfs_agblock_t fend = fbno + flen;
+ xfs_agblock_t bbno = busyp->bno;
+ xfs_agblock_t bend = bbno + busyp->length;
+
+ if (fend <= bbno) {
+ rbp = rbp->rb_left;
+ continue;
+ } else if (fbno >= bend) {
+ rbp = rbp->rb_right;
+ continue;
+ }
+
+ /*
+ * If this is a metadata allocation, try to reuse the busy
+ * extent instead of trimming the allocation.
+ */
+ if (!args->userdata &&
+ !(busyp->flags & XFS_EXTENT_BUSY_DISCARDED)) {
+ if (!xfs_extent_busy_update_extent(args->mp, args->pag,
+ busyp, fbno, flen,
+ false))
+ goto restart;
+ continue;
+ }
+
+ if (bbno <= fbno) {
+ /* start overlap */
+
+ /*
+ * Case 1:
+ * bbno bend
+ * +BBBBBBBBBBBBBBBBB+
+ * +---------+
+ * fbno fend
+ *
+ * Case 2:
+ * bbno bend
+ * +BBBBBBBBBBBBBBBBB+
+ * +-------------+
+ * fbno fend
+ *
+ * Case 3:
+ * bbno bend
+ * +BBBBBBBBBBBBBBBBB+
+ * +-------------+
+ * fbno fend
+ *
+ * Case 4:
+ * bbno bend
+ * +BBBBBBBBBBBBBBBBB+
+ * +-----------------+
+ * fbno fend
+ *
+ * No unbusy region in extent, return failure.
+ */
+ if (fend <= bend)
+ goto fail;
+
+ /*
+ * Case 5:
+ * bbno bend
+ * +BBBBBBBBBBBBBBBBB+
+ * +----------------------+
+ * fbno fend
+ *
+ * Case 6:
+ * bbno bend
+ * +BBBBBBBBBBBBBBBBB+
+ * +--------------------------+
+ * fbno fend
+ *
+ * Needs to be trimmed to:
+ * +-------+
+ * fbno fend
+ */
+ fbno = bend;
+ } else if (bend >= fend) {
+ /* end overlap */
+
+ /*
+ * Case 7:
+ * bbno bend
+ * +BBBBBBBBBBBBBBBBB+
+ * +------------------+
+ * fbno fend
+ *
+ * Case 8:
+ * bbno bend
+ * +BBBBBBBBBBBBBBBBB+
+ * +--------------------------+
+ * fbno fend
+ *
+ * Needs to be trimmed to:
+ * +-------+
+ * fbno fend
+ */
+ fend = bbno;
+ } else {
+ /* middle overlap */
+
+ /*
+ * Case 9:
+ * bbno bend
+ * +BBBBBBBBBBBBBBBBB+
+ * +-----------------------------------+
+ * fbno fend
+ *
+ * Can be trimmed to:
+ * +-------+ OR +-------+
+ * fbno fend fbno fend
+ *
+ * Backward allocation leads to significant
+ * fragmentation of directories, which degrades
+ * directory performance, therefore we always want to
+ * choose the option that produces forward allocation
+ * patterns.
+ * Preferring the lower bno extent will make the next
+ * request use "fend" as the start of the next
+ * allocation; if the segment is no longer busy at
+ * that point, we'll get a contiguous allocation, but
+ * even if it is still busy, we will get a forward
+ * allocation.
+ * We try to avoid choosing the segment at "bend",
+ * because that can lead to the next allocation
+ * taking the segment at "fbno", which would be a
+ * backward allocation. We only use the segment at
+ * "fbno" if it is much larger than the current
+ * requested size, because in that case there's a
+ * good chance subsequent allocations will be
+ * contiguous.
+ */
+ if (bbno - fbno >= args->maxlen) {
+ /* left candidate fits perfect */
+ fend = bbno;
+ } else if (fend - bend >= args->maxlen * 4) {
+ /* right candidate has enough free space */
+ fbno = bend;
+ } else if (bbno - fbno >= args->minlen) {
+ /* left candidate fits minimum requirement */
+ fend = bbno;
+ } else {
+ goto fail;
+ }
+ }
+
+ flen = fend - fbno;
+ }
+ spin_unlock(&args->pag->pagb_lock);
+
+ if (fbno != bno || flen != len) {
+ trace_xfs_extent_busy_trim(args->mp, args->agno, bno, len,
+ fbno, flen);
+ }
+ *rbno = fbno;
+ *rlen = flen;
+ return;
+fail:
+ /*
+ * Return a zero extent length as failure indications. All callers
+ * re-check if the trimmed extent satisfies the minlen requirement.
+ */
+ spin_unlock(&args->pag->pagb_lock);
+ trace_xfs_extent_busy_trim(args->mp, args->agno, bno, len, fbno, 0);
+ *rbno = fbno;
+ *rlen = 0;
+}
+
+STATIC void
+xfs_extent_busy_clear_one(
+ struct xfs_mount *mp,
+ struct xfs_perag *pag,
+ struct xfs_extent_busy *busyp)
+{
+ if (busyp->length) {
+ trace_xfs_extent_busy_clear(mp, busyp->agno, busyp->bno,
+ busyp->length);
+ rb_erase(&busyp->rb_node, &pag->pagb_tree);
+ }
+
+ list_del_init(&busyp->list);
+ kmem_free(busyp);
+}
+
+/*
+ * Remove all extents on the passed in list from the busy extents tree.
+ * If do_discard is set skip extents that need to be discarded, and mark
+ * these as undergoing a discard operation instead.
+ */
+void
+xfs_extent_busy_clear(
+ struct xfs_mount *mp,
+ struct list_head *list,
+ bool do_discard)
+{
+ struct xfs_extent_busy *busyp, *n;
+ struct xfs_perag *pag = NULL;
+ xfs_agnumber_t agno = NULLAGNUMBER;
+
+ list_for_each_entry_safe(busyp, n, list, list) {
+ if (busyp->agno != agno) {
+ if (pag) {
+ spin_unlock(&pag->pagb_lock);
+ xfs_perag_put(pag);
+ }
+ pag = xfs_perag_get(mp, busyp->agno);
+ spin_lock(&pag->pagb_lock);
+ agno = busyp->agno;
+ }
+
+ if (do_discard && busyp->length &&
+ !(busyp->flags & XFS_EXTENT_BUSY_SKIP_DISCARD))
+ busyp->flags = XFS_EXTENT_BUSY_DISCARDED;
+ else
+ xfs_extent_busy_clear_one(mp, pag, busyp);
+ }
+
+ if (pag) {
+ spin_unlock(&pag->pagb_lock);
+ xfs_perag_put(pag);
+ }
+}
+
+/*
+ * Callback for list_sort to sort busy extents by the AG they reside in.
+ */
+int
+xfs_extent_busy_ag_cmp(
+ void *priv,
+ struct list_head *a,
+ struct list_head *b)
+{
+ return container_of(a, struct xfs_extent_busy, list)->agno -
+ container_of(b, struct xfs_extent_busy, list)->agno;
+}
diff --git a/fs/xfs/xfs_extent_busy.h b/fs/xfs/xfs_extent_busy.h
new file mode 100644
index 000000000000..985412d65ba5
--- /dev/null
+++ b/fs/xfs/xfs_extent_busy.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
+ * Copyright (c) 2010 David Chinner.
+ * Copyright (c) 2011 Christoph Hellwig.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __XFS_EXTENT_BUSY_H__
+#define __XFS_EXTENT_BUSY_H__
+
+/*
+ * Busy block/extent entry. Indexed by a rbtree in perag to mark blocks that
+ * have been freed but whose transactions aren't committed to disk yet.
+ *
+ * Note that we use the transaction ID to record the transaction, not the
+ * transaction structure itself. See xfs_extent_busy_insert() for details.
+ */
+struct xfs_extent_busy {
+ struct rb_node rb_node; /* ag by-bno indexed search tree */
+ struct list_head list; /* transaction busy extent list */
+ xfs_agnumber_t agno;
+ xfs_agblock_t bno;
+ xfs_extlen_t length;
+ unsigned int flags;
+#define XFS_EXTENT_BUSY_DISCARDED 0x01 /* undergoing a discard op. */
+#define XFS_EXTENT_BUSY_SKIP_DISCARD 0x02 /* do not discard */
+};
+
+void
+xfs_extent_busy_insert(struct xfs_trans *tp, xfs_agnumber_t agno,
+ xfs_agblock_t bno, xfs_extlen_t len, unsigned int flags);
+
+void
+xfs_extent_busy_clear(struct xfs_mount *mp, struct list_head *list,
+ bool do_discard);
+
+int
+xfs_extent_busy_search(struct xfs_mount *mp, xfs_agnumber_t agno,
+ xfs_agblock_t bno, xfs_extlen_t len);
+
+void
+xfs_extent_busy_reuse(struct xfs_mount *mp, xfs_agnumber_t agno,
+ xfs_agblock_t fbno, xfs_extlen_t flen, bool userdata);
+
+void
+xfs_extent_busy_trim(struct xfs_alloc_arg *args, xfs_agblock_t bno,
+ xfs_extlen_t len, xfs_agblock_t *rbno, xfs_extlen_t *rlen);
+
+int
+xfs_extent_busy_ag_cmp(void *priv, struct list_head *a, struct list_head *b);
+
+static inline void xfs_extent_busy_sort(struct list_head *list)
+{
+ list_sort(NULL, list, xfs_extent_busy_ag_cmp);
+}
+
+#endif /* __XFS_EXTENT_BUSY_H__ */
diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c
index 35c2aff38b20..feb36d7551ae 100644
--- a/fs/xfs/xfs_extfree_item.c
+++ b/fs/xfs/xfs_extfree_item.c
@@ -19,7 +19,6 @@
#include "xfs_fs.h"
#include "xfs_types.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_buf_item.h"
#include "xfs_sb.h"
@@ -64,7 +63,8 @@ __xfs_efi_release(
if (!test_and_clear_bit(XFS_EFI_COMMITTED, &efip->efi_flags)) {
spin_lock(&ailp->xa_lock);
/* xfs_trans_ail_delete() drops the AIL lock. */
- xfs_trans_ail_delete(ailp, &efip->efi_item);
+ xfs_trans_ail_delete(ailp, &efip->efi_item,
+ SHUTDOWN_LOG_IO_ERROR);
xfs_efi_item_free(efip);
}
}
@@ -147,22 +147,20 @@ xfs_efi_item_unpin(
}
/*
- * Efi items have no locking or pushing. However, since EFIs are
- * pulled from the AIL when their corresponding EFDs are committed
- * to disk, their situation is very similar to being pinned. Return
- * XFS_ITEM_PINNED so that the caller will eventually flush the log.
- * This should help in getting the EFI out of the AIL.
+ * Efi items have no locking or pushing. However, since EFIs are pulled from
+ * the AIL when their corresponding EFDs are committed to disk, their situation
+ * is very similar to being pinned. Return XFS_ITEM_PINNED so that the caller
+ * will eventually flush the log. This should help in getting the EFI out of
+ * the AIL.
*/
STATIC uint
-xfs_efi_item_trylock(
- struct xfs_log_item *lip)
+xfs_efi_item_push(
+ struct xfs_log_item *lip,
+ struct list_head *buffer_list)
{
return XFS_ITEM_PINNED;
}
-/*
- * Efi items have no locking, so just return.
- */
STATIC void
xfs_efi_item_unlock(
struct xfs_log_item *lip)
@@ -190,17 +188,6 @@ xfs_efi_item_committed(
}
/*
- * There isn't much you can do to push on an efi item. It is simply
- * stuck waiting for all of its corresponding efd items to be
- * committed to disk.
- */
-STATIC void
-xfs_efi_item_push(
- struct xfs_log_item *lip)
-{
-}
-
-/*
* The EFI dependency tracking op doesn't do squat. It can't because
* it doesn't know where the free extent is coming from. The dependency
* tracking has to be handled by the "enclosing" metadata object. For
@@ -222,7 +209,6 @@ static const struct xfs_item_ops xfs_efi_item_ops = {
.iop_format = xfs_efi_item_format,
.iop_pin = xfs_efi_item_pin,
.iop_unpin = xfs_efi_item_unpin,
- .iop_trylock = xfs_efi_item_trylock,
.iop_unlock = xfs_efi_item_unlock,
.iop_committed = xfs_efi_item_committed,
.iop_push = xfs_efi_item_push,
@@ -404,19 +390,17 @@ xfs_efd_item_unpin(
}
/*
- * Efd items have no locking, so just return success.
+ * There isn't much you can do to push on an efd item. It is simply stuck
+ * waiting for the log to be flushed to disk.
*/
STATIC uint
-xfs_efd_item_trylock(
- struct xfs_log_item *lip)
+xfs_efd_item_push(
+ struct xfs_log_item *lip,
+ struct list_head *buffer_list)
{
- return XFS_ITEM_LOCKED;
+ return XFS_ITEM_PINNED;
}
-/*
- * Efd items have no locking or pushing, so return failure
- * so that the caller doesn't bother with us.
- */
STATIC void
xfs_efd_item_unlock(
struct xfs_log_item *lip)
@@ -451,16 +435,6 @@ xfs_efd_item_committed(
}
/*
- * There isn't much you can do to push on an efd item. It is simply
- * stuck waiting for the log to be flushed to disk.
- */
-STATIC void
-xfs_efd_item_push(
- struct xfs_log_item *lip)
-{
-}
-
-/*
* The EFD dependency tracking op doesn't do squat. It can't because
* it doesn't know where the free extent is coming from. The dependency
* tracking has to be handled by the "enclosing" metadata object. For
@@ -482,7 +456,6 @@ static const struct xfs_item_ops xfs_efd_item_ops = {
.iop_format = xfs_efd_item_format,
.iop_pin = xfs_efd_item_pin,
.iop_unpin = xfs_efd_item_unpin,
- .iop_trylock = xfs_efd_item_trylock,
.iop_unlock = xfs_efd_item_unlock,
.iop_committed = xfs_efd_item_committed,
.iop_push = xfs_efd_item_push,
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index 54a67dd9ac0a..8d214b87f6bb 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -17,9 +17,7 @@
*/
#include "xfs.h"
#include "xfs_fs.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_trans.h"
@@ -396,114 +394,96 @@ xfs_file_splice_write(
}
/*
- * This routine is called to handle zeroing any space in the last
- * block of the file that is beyond the EOF. We do this since the
- * size is being increased without writing anything to that block
- * and we don't want anyone to read the garbage on the disk.
+ * This routine is called to handle zeroing any space in the last block of the
+ * file that is beyond the EOF. We do this since the size is being increased
+ * without writing anything to that block and we don't want to read the
+ * garbage on the disk.
*/
STATIC int /* error (positive) */
xfs_zero_last_block(
- xfs_inode_t *ip,
- xfs_fsize_t offset,
- xfs_fsize_t isize)
+ struct xfs_inode *ip,
+ xfs_fsize_t offset,
+ xfs_fsize_t isize)
{
- xfs_fileoff_t last_fsb;
- xfs_mount_t *mp = ip->i_mount;
- int nimaps;
- int zero_offset;
- int zero_len;
- int error = 0;
- xfs_bmbt_irec_t imap;
-
- ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-
- zero_offset = XFS_B_FSB_OFFSET(mp, isize);
- if (zero_offset == 0) {
- /*
- * There are no extra bytes in the last block on disk to
- * zero, so return.
- */
- return 0;
- }
+ struct xfs_mount *mp = ip->i_mount;
+ xfs_fileoff_t last_fsb = XFS_B_TO_FSBT(mp, isize);
+ int zero_offset = XFS_B_FSB_OFFSET(mp, isize);
+ int zero_len;
+ int nimaps = 1;
+ int error = 0;
+ struct xfs_bmbt_irec imap;
- last_fsb = XFS_B_TO_FSBT(mp, isize);
- nimaps = 1;
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
error = xfs_bmapi_read(ip, last_fsb, 1, &imap, &nimaps, 0);
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
if (error)
return error;
+
ASSERT(nimaps > 0);
+
/*
* If the block underlying isize is just a hole, then there
* is nothing to zero.
*/
- if (imap.br_startblock == HOLESTARTBLOCK) {
+ if (imap.br_startblock == HOLESTARTBLOCK)
return 0;
- }
- /*
- * Zero the part of the last block beyond the EOF, and write it
- * out sync. We need to drop the ilock while we do this so we
- * don't deadlock when the buffer cache calls back to us.
- */
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
zero_len = mp->m_sb.sb_blocksize - zero_offset;
if (isize + zero_len > offset)
zero_len = offset - isize;
- error = xfs_iozero(ip, isize, zero_len);
-
- xfs_ilock(ip, XFS_ILOCK_EXCL);
- ASSERT(error >= 0);
- return error;
+ return xfs_iozero(ip, isize, zero_len);
}
/*
- * Zero any on disk space between the current EOF and the new,
- * larger EOF. This handles the normal case of zeroing the remainder
- * of the last block in the file and the unusual case of zeroing blocks
- * out beyond the size of the file. This second case only happens
- * with fixed size extents and when the system crashes before the inode
- * size was updated but after blocks were allocated. If fill is set,
- * then any holes in the range are filled and zeroed. If not, the holes
- * are left alone as holes.
+ * Zero any on disk space between the current EOF and the new, larger EOF.
+ *
+ * This handles the normal case of zeroing the remainder of the last block in
+ * the file and the unusual case of zeroing blocks out beyond the size of the
+ * file. This second case only happens with fixed size extents and when the
+ * system crashes before the inode size was updated but after blocks were
+ * allocated.
+ *
+ * Expects the iolock to be held exclusive, and will take the ilock internally.
*/
-
int /* error (positive) */
xfs_zero_eof(
- xfs_inode_t *ip,
- xfs_off_t offset, /* starting I/O offset */
- xfs_fsize_t isize) /* current inode size */
+ struct xfs_inode *ip,
+ xfs_off_t offset, /* starting I/O offset */
+ xfs_fsize_t isize) /* current inode size */
{
- xfs_mount_t *mp = ip->i_mount;
- xfs_fileoff_t start_zero_fsb;
- xfs_fileoff_t end_zero_fsb;
- xfs_fileoff_t zero_count_fsb;
- xfs_fileoff_t last_fsb;
- xfs_fileoff_t zero_off;
- xfs_fsize_t zero_len;
- int nimaps;
- int error = 0;
- xfs_bmbt_irec_t imap;
-
- ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL));
+ struct xfs_mount *mp = ip->i_mount;
+ xfs_fileoff_t start_zero_fsb;
+ xfs_fileoff_t end_zero_fsb;
+ xfs_fileoff_t zero_count_fsb;
+ xfs_fileoff_t last_fsb;
+ xfs_fileoff_t zero_off;
+ xfs_fsize_t zero_len;
+ int nimaps;
+ int error = 0;
+ struct xfs_bmbt_irec imap;
+
+ ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
ASSERT(offset > isize);
/*
* First handle zeroing the block on which isize resides.
+ *
* We only zero a part of that block so it is handled specially.
*/
- error = xfs_zero_last_block(ip, offset, isize);
- if (error) {
- ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL));
- return error;
+ if (XFS_B_FSB_OFFSET(mp, isize) != 0) {
+ error = xfs_zero_last_block(ip, offset, isize);
+ if (error)
+ return error;
}
/*
- * Calculate the range between the new size and the old
- * where blocks needing to be zeroed may exist. To get the
- * block where the last byte in the file currently resides,
- * we need to subtract one from the size and truncate back
- * to a block boundary. We subtract 1 in case the size is
- * exactly on a block boundary.
+ * Calculate the range between the new size and the old where blocks
+ * needing to be zeroed may exist.
+ *
+ * To get the block where the last byte in the file currently resides,
+ * we need to subtract one from the size and truncate back to a block
+ * boundary. We subtract 1 in case the size is exactly on a block
+ * boundary.
*/
last_fsb = isize ? XFS_B_TO_FSBT(mp, isize - 1) : (xfs_fileoff_t)-1;
start_zero_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)isize);
@@ -521,23 +501,18 @@ xfs_zero_eof(
while (start_zero_fsb <= end_zero_fsb) {
nimaps = 1;
zero_count_fsb = end_zero_fsb - start_zero_fsb + 1;
+
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
error = xfs_bmapi_read(ip, start_zero_fsb, zero_count_fsb,
&imap, &nimaps, 0);
- if (error) {
- ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL));
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ if (error)
return error;
- }
+
ASSERT(nimaps > 0);
if (imap.br_state == XFS_EXT_UNWRITTEN ||
imap.br_startblock == HOLESTARTBLOCK) {
- /*
- * This loop handles initializing pages that were
- * partially initialized by the code below this
- * loop. It basically zeroes the part of the page
- * that sits on a hole and sets the page as P_HOLE
- * and calls remapf if it is a mapped file.
- */
start_zero_fsb = imap.br_startoff + imap.br_blockcount;
ASSERT(start_zero_fsb <= (end_zero_fsb + 1));
continue;
@@ -545,11 +520,7 @@ xfs_zero_eof(
/*
* There are blocks we need to zero.
- * Drop the inode lock while we're doing the I/O.
- * We'll still have the iolock to protect us.
*/
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
-
zero_off = XFS_FSB_TO_B(mp, start_zero_fsb);
zero_len = XFS_FSB_TO_B(mp, imap.br_blockcount);
@@ -557,22 +528,14 @@ xfs_zero_eof(
zero_len = offset - zero_off;
error = xfs_iozero(ip, zero_off, zero_len);
- if (error) {
- goto out_lock;
- }
+ if (error)
+ return error;
start_zero_fsb = imap.br_startoff + imap.br_blockcount;
ASSERT(start_zero_fsb <= (end_zero_fsb + 1));
-
- xfs_ilock(ip, XFS_ILOCK_EXCL);
}
return 0;
-
-out_lock:
- xfs_ilock(ip, XFS_ILOCK_EXCL);
- ASSERT(error >= 0);
- return error;
}
/*
@@ -593,35 +556,29 @@ xfs_file_aio_write_checks(
struct xfs_inode *ip = XFS_I(inode);
int error = 0;
- xfs_rw_ilock(ip, XFS_ILOCK_EXCL);
restart:
error = generic_write_checks(file, pos, count, S_ISBLK(inode->i_mode));
- if (error) {
- xfs_rw_iunlock(ip, XFS_ILOCK_EXCL);
+ if (error)
return error;
- }
/*
* If the offset is beyond the size of the file, we need to zero any
* blocks that fall between the existing EOF and the start of this
* write. If zeroing is needed and we are currently holding the
- * iolock shared, we need to update it to exclusive which involves
- * dropping all locks and relocking to maintain correct locking order.
- * If we do this, restart the function to ensure all checks and values
- * are still valid.
+ * iolock shared, we need to update it to exclusive which implies
+ * having to redo all checks before.
*/
if (*pos > i_size_read(inode)) {
if (*iolock == XFS_IOLOCK_SHARED) {
- xfs_rw_iunlock(ip, XFS_ILOCK_EXCL | *iolock);
+ xfs_rw_iunlock(ip, *iolock);
*iolock = XFS_IOLOCK_EXCL;
- xfs_rw_ilock(ip, XFS_ILOCK_EXCL | *iolock);
+ xfs_rw_ilock(ip, *iolock);
goto restart;
}
error = -xfs_zero_eof(ip, *pos, i_size_read(inode));
+ if (error)
+ return error;
}
- xfs_rw_iunlock(ip, XFS_ILOCK_EXCL);
- if (error)
- return error;
/*
* Updating the timestamps will grab the ilock again from
@@ -638,7 +595,6 @@ restart:
* people from modifying setuid and setgid binaries.
*/
return file_remove_suid(file);
-
}
/*
@@ -1007,8 +963,149 @@ xfs_vm_page_mkwrite(
return block_page_mkwrite(vma, vmf, xfs_get_blocks);
}
+STATIC loff_t
+xfs_seek_data(
+ struct file *file,
+ loff_t start,
+ u32 type)
+{
+ struct inode *inode = file->f_mapping->host;
+ struct xfs_inode *ip = XFS_I(inode);
+ struct xfs_mount *mp = ip->i_mount;
+ struct xfs_bmbt_irec map[2];
+ int nmap = 2;
+ loff_t uninitialized_var(offset);
+ xfs_fsize_t isize;
+ xfs_fileoff_t fsbno;
+ xfs_filblks_t end;
+ uint lock;
+ int error;
+
+ lock = xfs_ilock_map_shared(ip);
+
+ isize = i_size_read(inode);
+ if (start >= isize) {
+ error = ENXIO;
+ goto out_unlock;
+ }
+
+ fsbno = XFS_B_TO_FSBT(mp, start);
+
+ /*
+ * Try to read extents from the first block indicated
+ * by fsbno to the end block of the file.
+ */
+ end = XFS_B_TO_FSB(mp, isize);
+
+ error = xfs_bmapi_read(ip, fsbno, end - fsbno, map, &nmap,
+ XFS_BMAPI_ENTIRE);
+ if (error)
+ goto out_unlock;
+
+ /*
+ * Treat unwritten extent as data extent since it might
+ * contains dirty data in page cache.
+ */
+ if (map[0].br_startblock != HOLESTARTBLOCK) {
+ offset = max_t(loff_t, start,
+ XFS_FSB_TO_B(mp, map[0].br_startoff));
+ } else {
+ if (nmap == 1) {
+ error = ENXIO;
+ goto out_unlock;
+ }
+
+ offset = max_t(loff_t, start,
+ XFS_FSB_TO_B(mp, map[1].br_startoff));
+ }
+
+ if (offset != file->f_pos)
+ file->f_pos = offset;
+
+out_unlock:
+ xfs_iunlock_map_shared(ip, lock);
+
+ if (error)
+ return -error;
+ return offset;
+}
+
+STATIC loff_t
+xfs_seek_hole(
+ struct file *file,
+ loff_t start,
+ u32 type)
+{
+ struct inode *inode = file->f_mapping->host;
+ struct xfs_inode *ip = XFS_I(inode);
+ struct xfs_mount *mp = ip->i_mount;
+ loff_t uninitialized_var(offset);
+ loff_t holeoff;
+ xfs_fsize_t isize;
+ xfs_fileoff_t fsbno;
+ uint lock;
+ int error;
+
+ if (XFS_FORCED_SHUTDOWN(mp))
+ return -XFS_ERROR(EIO);
+
+ lock = xfs_ilock_map_shared(ip);
+
+ isize = i_size_read(inode);
+ if (start >= isize) {
+ error = ENXIO;
+ goto out_unlock;
+ }
+
+ fsbno = XFS_B_TO_FSBT(mp, start);
+ error = xfs_bmap_first_unused(NULL, ip, 1, &fsbno, XFS_DATA_FORK);
+ if (error)
+ goto out_unlock;
+
+ holeoff = XFS_FSB_TO_B(mp, fsbno);
+ if (holeoff <= start)
+ offset = start;
+ else {
+ /*
+ * xfs_bmap_first_unused() could return a value bigger than
+ * isize if there are no more holes past the supplied offset.
+ */
+ offset = min_t(loff_t, holeoff, isize);
+ }
+
+ if (offset != file->f_pos)
+ file->f_pos = offset;
+
+out_unlock:
+ xfs_iunlock_map_shared(ip, lock);
+
+ if (error)
+ return -error;
+ return offset;
+}
+
+STATIC loff_t
+xfs_file_llseek(
+ struct file *file,
+ loff_t offset,
+ int origin)
+{
+ switch (origin) {
+ case SEEK_END:
+ case SEEK_CUR:
+ case SEEK_SET:
+ return generic_file_llseek(file, offset, origin);
+ case SEEK_DATA:
+ return xfs_seek_data(file, offset, origin);
+ case SEEK_HOLE:
+ return xfs_seek_hole(file, offset, origin);
+ default:
+ return -EINVAL;
+ }
+}
+
const struct file_operations xfs_file_operations = {
- .llseek = generic_file_llseek,
+ .llseek = xfs_file_llseek,
.read = do_sync_read,
.write = do_sync_write,
.aio_read = xfs_file_aio_read,
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index 1c6fdeb702ff..c25b094efbf7 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -18,8 +18,6 @@
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_types.h"
-#include "xfs_bit.h"
-#include "xfs_inum.h"
#include "xfs_log.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
@@ -39,7 +37,6 @@
#include "xfs_itable.h"
#include "xfs_trans_space.h"
#include "xfs_rtalloc.h"
-#include "xfs_rw.h"
#include "xfs_filestream.h"
#include "xfs_trace.h"
@@ -147,9 +144,9 @@ xfs_growfs_data_private(
if ((error = xfs_sb_validate_fsb_count(&mp->m_sb, nb)))
return error;
dpct = pct - mp->m_sb.sb_imax_pct;
- bp = xfs_buf_read_uncached(mp, mp->m_ddev_targp,
+ bp = xfs_buf_read_uncached(mp->m_ddev_targp,
XFS_FSB_TO_BB(mp, nb) - XFS_FSS_TO_BB(mp, 1),
- BBTOB(XFS_FSS_TO_BB(mp, 1)), 0);
+ XFS_FSS_TO_BB(mp, 1), 0);
if (!bp)
return EIO;
xfs_buf_relse(bp);
@@ -193,7 +190,7 @@ xfs_growfs_data_private(
*/
bp = xfs_buf_get(mp->m_ddev_targp,
XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
- XFS_FSS_TO_BB(mp, 1), XBF_LOCK | XBF_MAPPED);
+ XFS_FSS_TO_BB(mp, 1), 0);
if (!bp) {
error = ENOMEM;
goto error0;
@@ -230,7 +227,7 @@ xfs_growfs_data_private(
*/
bp = xfs_buf_get(mp->m_ddev_targp,
XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)),
- XFS_FSS_TO_BB(mp, 1), XBF_LOCK | XBF_MAPPED);
+ XFS_FSS_TO_BB(mp, 1), 0);
if (!bp) {
error = ENOMEM;
goto error0;
@@ -259,8 +256,7 @@ xfs_growfs_data_private(
*/
bp = xfs_buf_get(mp->m_ddev_targp,
XFS_AGB_TO_DADDR(mp, agno, XFS_BNO_BLOCK(mp)),
- BTOBB(mp->m_sb.sb_blocksize),
- XBF_LOCK | XBF_MAPPED);
+ BTOBB(mp->m_sb.sb_blocksize), 0);
if (!bp) {
error = ENOMEM;
goto error0;
@@ -286,8 +282,7 @@ xfs_growfs_data_private(
*/
bp = xfs_buf_get(mp->m_ddev_targp,
XFS_AGB_TO_DADDR(mp, agno, XFS_CNT_BLOCK(mp)),
- BTOBB(mp->m_sb.sb_blocksize),
- XBF_LOCK | XBF_MAPPED);
+ BTOBB(mp->m_sb.sb_blocksize), 0);
if (!bp) {
error = ENOMEM;
goto error0;
@@ -314,8 +309,7 @@ xfs_growfs_data_private(
*/
bp = xfs_buf_get(mp->m_ddev_targp,
XFS_AGB_TO_DADDR(mp, agno, XFS_IBT_BLOCK(mp)),
- BTOBB(mp->m_sb.sb_blocksize),
- XBF_LOCK | XBF_MAPPED);
+ BTOBB(mp->m_sb.sb_blocksize), 0);
if (!bp) {
error = ENOMEM;
goto error0;
@@ -405,7 +399,7 @@ xfs_growfs_data_private(
/* update secondary superblocks. */
for (agno = 1; agno < nagcount; agno++) {
- error = xfs_read_buf(mp, mp->m_ddev_targp,
+ error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp,
XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)),
XFS_FSS_TO_BB(mp, 1), 0, &bp);
if (error) {
@@ -693,3 +687,63 @@ xfs_fs_goingdown(
return 0;
}
+
+/*
+ * Force a shutdown of the filesystem instantly while keeping the filesystem
+ * consistent. We don't do an unmount here; just shutdown the shop, make sure
+ * that absolutely nothing persistent happens to this filesystem after this
+ * point.
+ */
+void
+xfs_do_force_shutdown(
+ xfs_mount_t *mp,
+ int flags,
+ char *fname,
+ int lnnum)
+{
+ int logerror;
+
+ logerror = flags & SHUTDOWN_LOG_IO_ERROR;
+
+ if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
+ xfs_notice(mp,
+ "%s(0x%x) called from line %d of file %s. Return address = 0x%p",
+ __func__, flags, lnnum, fname, __return_address);
+ }
+ /*
+ * No need to duplicate efforts.
+ */
+ if (XFS_FORCED_SHUTDOWN(mp) && !logerror)
+ return;
+
+ /*
+ * This flags XFS_MOUNT_FS_SHUTDOWN, makes sure that we don't
+ * queue up anybody new on the log reservations, and wakes up
+ * everybody who's sleeping on log reservations to tell them
+ * the bad news.
+ */
+ if (xfs_log_force_umount(mp, logerror))
+ return;
+
+ if (flags & SHUTDOWN_CORRUPT_INCORE) {
+ xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_CORRUPT,
+ "Corruption of in-memory data detected. Shutting down filesystem");
+ if (XFS_ERRLEVEL_HIGH <= xfs_error_level)
+ xfs_stack_trace();
+ } else if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
+ if (logerror) {
+ xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_LOGERROR,
+ "Log I/O Error Detected. Shutting down filesystem");
+ } else if (flags & SHUTDOWN_DEVICE_REQ) {
+ xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR,
+ "All device paths lost. Shutting down filesystem");
+ } else if (!(flags & SHUTDOWN_REMOTE_REQ)) {
+ xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR,
+ "I/O Error Detected. Shutting down filesystem");
+ }
+ }
+ if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
+ xfs_alert(mp,
+ "Please umount the filesystem and rectify the problem(s)");
+ }
+}
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c
index dad1a31aa4fc..177a21a7ac49 100644
--- a/fs/xfs/xfs_ialloc.c
+++ b/fs/xfs/xfs_ialloc.c
@@ -200,8 +200,7 @@ xfs_ialloc_inode_init(
*/
d = XFS_AGB_TO_DADDR(mp, agno, agbno + (j * blks_per_cluster));
fbuf = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
- mp->m_bsize * blks_per_cluster,
- XBF_LOCK);
+ mp->m_bsize * blks_per_cluster, 0);
if (!fbuf)
return ENOMEM;
/*
@@ -610,6 +609,13 @@ xfs_ialloc_get_rec(
/*
* Visible inode allocation functions.
*/
+/*
+ * Find a free (set) bit in the inode bitmask.
+ */
+static inline int xfs_ialloc_find_free(xfs_inofree_t *fp)
+{
+ return xfs_lowbit64(*fp);
+}
/*
* Allocate an inode on disk.
diff --git a/fs/xfs/xfs_ialloc.h b/fs/xfs/xfs_ialloc.h
index 666a037398d6..65ac57c8063c 100644
--- a/fs/xfs/xfs_ialloc.h
+++ b/fs/xfs/xfs_ialloc.h
@@ -47,15 +47,6 @@ xfs_make_iptr(struct xfs_mount *mp, struct xfs_buf *b, int o)
}
/*
- * Find a free (set) bit in the inode bitmask.
- */
-static inline int xfs_ialloc_find_free(xfs_inofree_t *fp)
-{
- return xfs_lowbit64(*fp);
-}
-
-
-/*
* Allocate an inode on disk.
* Mode is used to tell whether the new inode will need space, and whether
* it is a directory.
diff --git a/fs/xfs/xfs_ialloc_btree.c b/fs/xfs/xfs_ialloc_btree.c
index c6a75815aea0..2b8b7a37aa18 100644
--- a/fs/xfs/xfs_ialloc_btree.c
+++ b/fs/xfs/xfs_ialloc_btree.c
@@ -20,7 +20,6 @@
#include "xfs_types.h"
#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
index bcc6c249b2c7..1bb4365e8c25 100644
--- a/fs/xfs/xfs_iget.c
+++ b/fs/xfs/xfs_iget.c
@@ -19,7 +19,6 @@
#include "xfs_fs.h"
#include "xfs_types.h"
#include "xfs_acl.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
#include "xfs_inum.h"
#include "xfs_trans.h"
@@ -123,23 +122,7 @@ xfs_inode_free(
xfs_idestroy_fork(ip, XFS_ATTR_FORK);
if (ip->i_itemp) {
- /*
- * Only if we are shutting down the fs will we see an
- * inode still in the AIL. If it is there, we should remove
- * it to prevent a use-after-free from occurring.
- */
- xfs_log_item_t *lip = &ip->i_itemp->ili_item;
- struct xfs_ail *ailp = lip->li_ailp;
-
- ASSERT(((lip->li_flags & XFS_LI_IN_AIL) == 0) ||
- XFS_FORCED_SHUTDOWN(ip->i_mount));
- if (lip->li_flags & XFS_LI_IN_AIL) {
- spin_lock(&ailp->xa_lock);
- if (lip->li_flags & XFS_LI_IN_AIL)
- xfs_trans_ail_delete(ailp, lip);
- else
- spin_unlock(&ailp->xa_lock);
- }
+ ASSERT(!(ip->i_itemp->ili_item.li_flags & XFS_LI_IN_AIL));
xfs_inode_item_destroy(ip);
ip->i_itemp = NULL;
}
@@ -334,9 +317,10 @@ xfs_iget_cache_miss(
/*
* Preload the radix tree so we can insert safely under the
* write spinlock. Note that we cannot sleep inside the preload
- * region.
+ * region. Since we can be called from transaction context, don't
+ * recurse into the file system.
*/
- if (radix_tree_preload(GFP_KERNEL)) {
+ if (radix_tree_preload(GFP_NOFS)) {
error = EAGAIN;
goto out_destroy;
}
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index bc46c0a133d3..a59eea09930a 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -20,7 +20,6 @@
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_types.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
#include "xfs_inum.h"
#include "xfs_trans.h"
@@ -61,6 +60,20 @@ STATIC int xfs_iformat_local(xfs_inode_t *, xfs_dinode_t *, int, int);
STATIC int xfs_iformat_extents(xfs_inode_t *, xfs_dinode_t *, int);
STATIC int xfs_iformat_btree(xfs_inode_t *, xfs_dinode_t *, int);
+/*
+ * helper function to extract extent size hint from inode
+ */
+xfs_extlen_t
+xfs_get_extsz_hint(
+ struct xfs_inode *ip)
+{
+ if ((ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE) && ip->i_d.di_extsize)
+ return ip->i_d.di_extsize;
+ if (XFS_IS_REALTIME_INODE(ip))
+ return ip->i_mount->m_sb.sb_rextsize;
+ return 0;
+}
+
#ifdef DEBUG
/*
* Make sure that the extents in the given memory buffer
@@ -137,6 +150,7 @@ xfs_imap_to_bp(
int ni;
xfs_buf_t *bp;
+ buf_flags |= XBF_UNMAPPED;
error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap->im_blkno,
(int)imap->im_len, buf_flags, &bp);
if (error) {
@@ -226,7 +240,7 @@ xfs_inotobp(
if (error)
return error;
- error = xfs_imap_to_bp(mp, tp, &imap, &bp, XBF_LOCK, imap_flags);
+ error = xfs_imap_to_bp(mp, tp, &imap, &bp, 0, imap_flags);
if (error)
return error;
@@ -782,8 +796,7 @@ xfs_iread(
/*
* Get pointers to the on-disk inode and the buffer containing it.
*/
- error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &bp,
- XBF_LOCK, iget_flags);
+ error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &bp, 0, iget_flags);
if (error)
return error;
dip = (xfs_dinode_t *)xfs_buf_offset(bp, ip->i_imap.im_boffset);
@@ -1342,7 +1355,7 @@ xfs_iunlink(
* Here we put the head pointer into our next pointer,
* and then we fall through to point the head at us.
*/
- error = xfs_itobp(mp, tp, ip, &dip, &ibp, XBF_LOCK);
+ error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0);
if (error)
return error;
@@ -1423,7 +1436,7 @@ xfs_iunlink_remove(
* of dealing with the buffer when there is no need to
* change it.
*/
- error = xfs_itobp(mp, tp, ip, &dip, &ibp, XBF_LOCK);
+ error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0);
if (error) {
xfs_warn(mp, "%s: xfs_itobp() returned error %d.",
__func__, error);
@@ -1484,7 +1497,7 @@ xfs_iunlink_remove(
* Now last_ibp points to the buffer previous to us on
* the unlinked list. Pull us from the list.
*/
- error = xfs_itobp(mp, tp, ip, &dip, &ibp, XBF_LOCK);
+ error = xfs_itobp(mp, tp, ip, &dip, &ibp, 0);
if (error) {
xfs_warn(mp, "%s: xfs_itobp(2) returned error %d.",
__func__, error);
@@ -1566,8 +1579,7 @@ xfs_ifree_cluster(
* to mark all the active inodes on the buffer stale.
*/
bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, blkno,
- mp->m_bsize * blks_per_cluster,
- XBF_LOCK);
+ mp->m_bsize * blks_per_cluster, 0);
if (!bp)
return ENOMEM;
@@ -1737,7 +1749,7 @@ xfs_ifree(
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
- error = xfs_itobp(ip->i_mount, tp, ip, &dip, &ibp, XBF_LOCK);
+ error = xfs_itobp(ip->i_mount, tp, ip, &dip, &ibp, 0);
if (error)
return error;
@@ -2347,11 +2359,11 @@ cluster_corrupt_out:
*/
rcu_read_unlock();
/*
- * Clean up the buffer. If it was B_DELWRI, just release it --
+ * Clean up the buffer. If it was delwri, just release it --
* brelse can handle it with no problems. If not, shut down the
* filesystem before releasing the buffer.
*/
- bufwasdelwri = XFS_BUF_ISDELAYWRITE(bp);
+ bufwasdelwri = (bp->b_flags & _XBF_DELWRI_Q);
if (bufwasdelwri)
xfs_buf_relse(bp);
@@ -2377,30 +2389,29 @@ cluster_corrupt_out:
/*
* Unlocks the flush lock
*/
- xfs_iflush_abort(iq);
+ xfs_iflush_abort(iq, false);
kmem_free(ilist);
xfs_perag_put(pag);
return XFS_ERROR(EFSCORRUPTED);
}
/*
- * xfs_iflush() will write a modified inode's changes out to the
- * inode's on disk home. The caller must have the inode lock held
- * in at least shared mode and the inode flush completion must be
- * active as well. The inode lock will still be held upon return from
- * the call and the caller is free to unlock it.
- * The inode flush will be completed when the inode reaches the disk.
- * The flags indicate how the inode's buffer should be written out.
+ * Flush dirty inode metadata into the backing buffer.
+ *
+ * The caller must have the inode lock and the inode flush lock held. The
+ * inode lock will still be held upon return to the caller, and the inode
+ * flush lock will be released after the inode has reached the disk.
+ *
+ * The caller must write out the buffer returned in *bpp and release it.
*/
int
xfs_iflush(
- xfs_inode_t *ip,
- uint flags)
+ struct xfs_inode *ip,
+ struct xfs_buf **bpp)
{
- xfs_inode_log_item_t *iip;
- xfs_buf_t *bp;
- xfs_dinode_t *dip;
- xfs_mount_t *mp;
+ struct xfs_mount *mp = ip->i_mount;
+ struct xfs_buf *bp;
+ struct xfs_dinode *dip;
int error;
XFS_STATS_INC(xs_iflush_count);
@@ -2410,25 +2421,8 @@ xfs_iflush(
ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
ip->i_d.di_nextents > XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK));
- iip = ip->i_itemp;
- mp = ip->i_mount;
+ *bpp = NULL;
- /*
- * We can't flush the inode until it is unpinned, so wait for it if we
- * are allowed to block. We know no one new can pin it, because we are
- * holding the inode lock shared and you need to hold it exclusively to
- * pin the inode.
- *
- * If we are not allowed to block, force the log out asynchronously so
- * that when we come back the inode will be unpinned. If other inodes
- * in the same cluster are dirty, they will probably write the inode
- * out for us if they occur after the log force completes.
- */
- if (!(flags & SYNC_WAIT) && xfs_ipincount(ip)) {
- xfs_iunpin(ip);
- xfs_ifunlock(ip);
- return EAGAIN;
- }
xfs_iunpin_wait(ip);
/*
@@ -2447,20 +2441,20 @@ xfs_iflush(
/*
* This may have been unpinned because the filesystem is shutting
* down forcibly. If that's the case we must not write this inode
- * to disk, because the log record didn't make it to disk!
+ * to disk, because the log record didn't make it to disk.
+ *
+ * We also have to remove the log item from the AIL in this case,
+ * as we wait for an empty AIL as part of the unmount process.
*/
if (XFS_FORCED_SHUTDOWN(mp)) {
- if (iip)
- iip->ili_fields = 0;
- xfs_ifunlock(ip);
- return XFS_ERROR(EIO);
+ error = XFS_ERROR(EIO);
+ goto abort_out;
}
/*
* Get the buffer containing the on-disk inode.
*/
- error = xfs_itobp(mp, NULL, ip, &dip, &bp,
- (flags & SYNC_TRYLOCK) ? XBF_TRYLOCK : XBF_LOCK);
+ error = xfs_itobp(mp, NULL, ip, &dip, &bp, XBF_TRYLOCK);
if (error || !bp) {
xfs_ifunlock(ip);
return error;
@@ -2488,23 +2482,20 @@ xfs_iflush(
if (error)
goto cluster_corrupt_out;
- if (flags & SYNC_WAIT)
- error = xfs_bwrite(bp);
- else
- xfs_buf_delwri_queue(bp);
-
- xfs_buf_relse(bp);
- return error;
+ *bpp = bp;
+ return 0;
corrupt_out:
xfs_buf_relse(bp);
xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
cluster_corrupt_out:
+ error = XFS_ERROR(EFSCORRUPTED);
+abort_out:
/*
* Unlocks the flush lock
*/
- xfs_iflush_abort(ip);
- return XFS_ERROR(EFSCORRUPTED);
+ xfs_iflush_abort(ip, false);
+ return error;
}
@@ -2706,27 +2697,6 @@ corrupt_out:
return XFS_ERROR(EFSCORRUPTED);
}
-void
-xfs_promote_inode(
- struct xfs_inode *ip)
-{
- struct xfs_buf *bp;
-
- ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
-
- bp = xfs_incore(ip->i_mount->m_ddev_targp, ip->i_imap.im_blkno,
- ip->i_imap.im_len, XBF_TRYLOCK);
- if (!bp)
- return;
-
- if (XFS_BUF_ISDELAYWRITE(bp)) {
- xfs_buf_delwri_promote(bp);
- wake_up_process(ip->i_mount->m_ddev_targp->bt_task);
- }
-
- xfs_buf_relse(bp);
-}
-
/*
* Return a pointer to the extent record at file index idx.
*/
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index 7fee3387e1c8..1efff36a75b6 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -529,11 +529,12 @@ int xfs_iunlink(struct xfs_trans *, xfs_inode_t *);
void xfs_iext_realloc(xfs_inode_t *, int, int);
void xfs_iunpin_wait(xfs_inode_t *);
-int xfs_iflush(xfs_inode_t *, uint);
-void xfs_promote_inode(struct xfs_inode *);
+int xfs_iflush(struct xfs_inode *, struct xfs_buf **);
void xfs_lock_inodes(xfs_inode_t **, int, uint);
void xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint);
+xfs_extlen_t xfs_get_extsz_hint(struct xfs_inode *ip);
+
#define IHOLD(ip) \
do { \
ASSERT(atomic_read(&VFS_I(ip)->i_count) > 0) ; \
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index 05d924efceaf..6cdbf90c6f7b 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -18,9 +18,7 @@
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_types.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
@@ -480,25 +478,16 @@ xfs_inode_item_unpin(
wake_up_bit(&ip->i_flags, __XFS_IPINNED_BIT);
}
-/*
- * This is called to attempt to lock the inode associated with this
- * inode log item, in preparation for the push routine which does the actual
- * iflush. Don't sleep on the inode lock or the flush lock.
- *
- * If the flush lock is already held, indicating that the inode has
- * been or is in the process of being flushed, then (ideally) we'd like to
- * see if the inode's buffer is still incore, and if so give it a nudge.
- * We delay doing so until the pushbuf routine, though, to avoid holding
- * the AIL lock across a call to the blackhole which is the buffer cache.
- * Also we don't want to sleep in any device strategy routines, which can happen
- * if we do the subsequent bawrite in here.
- */
STATIC uint
-xfs_inode_item_trylock(
- struct xfs_log_item *lip)
+xfs_inode_item_push(
+ struct xfs_log_item *lip,
+ struct list_head *buffer_list)
{
struct xfs_inode_log_item *iip = INODE_ITEM(lip);
struct xfs_inode *ip = iip->ili_inode;
+ struct xfs_buf *bp = NULL;
+ uint rval = XFS_ITEM_SUCCESS;
+ int error;
if (xfs_ipincount(ip) > 0)
return XFS_ITEM_PINNED;
@@ -506,30 +495,50 @@ xfs_inode_item_trylock(
if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED))
return XFS_ITEM_LOCKED;
+ /*
+ * Re-check the pincount now that we stabilized the value by
+ * taking the ilock.
+ */
+ if (xfs_ipincount(ip) > 0) {
+ rval = XFS_ITEM_PINNED;
+ goto out_unlock;
+ }
+
+ /*
+ * Someone else is already flushing the inode. Nothing we can do
+ * here but wait for the flush to finish and remove the item from
+ * the AIL.
+ */
if (!xfs_iflock_nowait(ip)) {
- /*
- * inode has already been flushed to the backing buffer,
- * leave it locked in shared mode, pushbuf routine will
- * unlock it.
- */
- return XFS_ITEM_PUSHBUF;
+ rval = XFS_ITEM_FLUSHING;
+ goto out_unlock;
}
- /* Stale items should force out the iclog */
+ /*
+ * Stale inode items should force out the iclog.
+ */
if (ip->i_flags & XFS_ISTALE) {
xfs_ifunlock(ip);
xfs_iunlock(ip, XFS_ILOCK_SHARED);
return XFS_ITEM_PINNED;
}
-#ifdef DEBUG
- if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
- ASSERT(iip->ili_fields != 0);
- ASSERT(iip->ili_logged == 0);
- ASSERT(lip->li_flags & XFS_LI_IN_AIL);
+ ASSERT(iip->ili_fields != 0 || XFS_FORCED_SHUTDOWN(ip->i_mount));
+ ASSERT(iip->ili_logged == 0 || XFS_FORCED_SHUTDOWN(ip->i_mount));
+
+ spin_unlock(&lip->li_ailp->xa_lock);
+
+ error = xfs_iflush(ip, &bp);
+ if (!error) {
+ if (!xfs_buf_delwri_queue(bp, buffer_list))
+ rval = XFS_ITEM_FLUSHING;
+ xfs_buf_relse(bp);
}
-#endif
- return XFS_ITEM_SUCCESS;
+
+ spin_lock(&lip->li_ailp->xa_lock);
+out_unlock:
+ xfs_iunlock(ip, XFS_ILOCK_SHARED);
+ return rval;
}
/*
@@ -614,86 +623,6 @@ xfs_inode_item_committed(
}
/*
- * This gets called by xfs_trans_push_ail(), when IOP_TRYLOCK
- * failed to get the inode flush lock but did get the inode locked SHARED.
- * Here we're trying to see if the inode buffer is incore, and if so whether it's
- * marked delayed write. If that's the case, we'll promote it and that will
- * allow the caller to write the buffer by triggering the xfsbufd to run.
- */
-STATIC bool
-xfs_inode_item_pushbuf(
- struct xfs_log_item *lip)
-{
- struct xfs_inode_log_item *iip = INODE_ITEM(lip);
- struct xfs_inode *ip = iip->ili_inode;
- struct xfs_buf *bp;
- bool ret = true;
-
- ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED));
-
- /*
- * If a flush is not in progress anymore, chances are that the
- * inode was taken off the AIL. So, just get out.
- */
- if (!xfs_isiflocked(ip) ||
- !(lip->li_flags & XFS_LI_IN_AIL)) {
- xfs_iunlock(ip, XFS_ILOCK_SHARED);
- return true;
- }
-
- bp = xfs_incore(ip->i_mount->m_ddev_targp, iip->ili_format.ilf_blkno,
- iip->ili_format.ilf_len, XBF_TRYLOCK);
-
- xfs_iunlock(ip, XFS_ILOCK_SHARED);
- if (!bp)
- return true;
- if (XFS_BUF_ISDELAYWRITE(bp))
- xfs_buf_delwri_promote(bp);
- if (xfs_buf_ispinned(bp))
- ret = false;
- xfs_buf_relse(bp);
- return ret;
-}
-
-/*
- * This is called to asynchronously write the inode associated with this
- * inode log item out to disk. The inode will already have been locked by
- * a successful call to xfs_inode_item_trylock().
- */
-STATIC void
-xfs_inode_item_push(
- struct xfs_log_item *lip)
-{
- struct xfs_inode_log_item *iip = INODE_ITEM(lip);
- struct xfs_inode *ip = iip->ili_inode;
-
- ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED));
- ASSERT(xfs_isiflocked(ip));
-
- /*
- * Since we were able to lock the inode's flush lock and
- * we found it on the AIL, the inode must be dirty. This
- * is because the inode is removed from the AIL while still
- * holding the flush lock in xfs_iflush_done(). Thus, if
- * we found it in the AIL and were able to obtain the flush
- * lock without sleeping, then there must not have been
- * anyone in the process of flushing the inode.
- */
- ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || iip->ili_fields != 0);
-
- /*
- * Push the inode to it's backing buffer. This will not remove the
- * inode from the AIL - a further push will be required to trigger a
- * buffer push. However, this allows all the dirty inodes to be pushed
- * to the buffer before it is pushed to disk. The buffer IO completion
- * will pull the inode from the AIL, mark it clean and unlock the flush
- * lock.
- */
- (void) xfs_iflush(ip, SYNC_TRYLOCK);
- xfs_iunlock(ip, XFS_ILOCK_SHARED);
-}
-
-/*
* XXX rcc - this one really has to do something. Probably needs
* to stamp in a new field in the incore inode.
*/
@@ -713,11 +642,9 @@ static const struct xfs_item_ops xfs_inode_item_ops = {
.iop_format = xfs_inode_item_format,
.iop_pin = xfs_inode_item_pin,
.iop_unpin = xfs_inode_item_unpin,
- .iop_trylock = xfs_inode_item_trylock,
.iop_unlock = xfs_inode_item_unlock,
.iop_committed = xfs_inode_item_committed,
.iop_push = xfs_inode_item_push,
- .iop_pushbuf = xfs_inode_item_pushbuf,
.iop_committing = xfs_inode_item_committing
};
@@ -848,7 +775,8 @@ xfs_iflush_done(
ASSERT(i <= need_ail);
}
/* xfs_trans_ail_delete_bulk() drops the AIL lock. */
- xfs_trans_ail_delete_bulk(ailp, log_items, i);
+ xfs_trans_ail_delete_bulk(ailp, log_items, i,
+ SHUTDOWN_CORRUPT_INCORE);
}
@@ -869,16 +797,15 @@ xfs_iflush_done(
}
/*
- * This is the inode flushing abort routine. It is called
- * from xfs_iflush when the filesystem is shutting down to clean
- * up the inode state.
- * It is responsible for removing the inode item
- * from the AIL if it has not been re-logged, and unlocking the inode's
- * flush lock.
+ * This is the inode flushing abort routine. It is called from xfs_iflush when
+ * the filesystem is shutting down to clean up the inode state. It is
+ * responsible for removing the inode item from the AIL if it has not been
+ * re-logged, and unlocking the inode's flush lock.
*/
void
xfs_iflush_abort(
- xfs_inode_t *ip)
+ xfs_inode_t *ip,
+ bool stale)
{
xfs_inode_log_item_t *iip = ip->i_itemp;
@@ -888,7 +815,10 @@ xfs_iflush_abort(
spin_lock(&ailp->xa_lock);
if (iip->ili_item.li_flags & XFS_LI_IN_AIL) {
/* xfs_trans_ail_delete() drops the AIL lock. */
- xfs_trans_ail_delete(ailp, (xfs_log_item_t *)iip);
+ xfs_trans_ail_delete(ailp, &iip->ili_item,
+ stale ?
+ SHUTDOWN_LOG_IO_ERROR :
+ SHUTDOWN_CORRUPT_INCORE);
} else
spin_unlock(&ailp->xa_lock);
}
@@ -915,7 +845,7 @@ xfs_istale_done(
struct xfs_buf *bp,
struct xfs_log_item *lip)
{
- xfs_iflush_abort(INODE_ITEM(lip)->ili_inode);
+ xfs_iflush_abort(INODE_ITEM(lip)->ili_inode, true);
}
/*
diff --git a/fs/xfs/xfs_inode_item.h b/fs/xfs/xfs_inode_item.h
index 41d61c3b7a36..376d4d0b2635 100644
--- a/fs/xfs/xfs_inode_item.h
+++ b/fs/xfs/xfs_inode_item.h
@@ -165,7 +165,7 @@ extern void xfs_inode_item_init(struct xfs_inode *, struct xfs_mount *);
extern void xfs_inode_item_destroy(struct xfs_inode *);
extern void xfs_iflush_done(struct xfs_buf *, struct xfs_log_item *);
extern void xfs_istale_done(struct xfs_buf *, struct xfs_log_item *);
-extern void xfs_iflush_abort(struct xfs_inode *);
+extern void xfs_iflush_abort(struct xfs_inode *, bool);
extern int xfs_inode_item_format_convert(xfs_log_iovec_t *,
xfs_inode_log_format_t *);
diff --git a/fs/xfs/xfs_inum.h b/fs/xfs/xfs_inum.h
index b253c0ea5bec..90efdaf1706f 100644
--- a/fs/xfs/xfs_inum.h
+++ b/fs/xfs/xfs_inum.h
@@ -26,11 +26,6 @@
* high agno_log-agblklog-inopblog bits - 0
*/
-typedef __uint32_t xfs_agino_t; /* within allocation grp inode number */
-
-#define NULLFSINO ((xfs_ino_t)-1)
-#define NULLAGINO ((xfs_agino_t)-1)
-
struct xfs_mount;
#define XFS_INO_MASK(k) (__uint32_t)((1ULL << (k)) - 1)
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 91f8ff547ab3..3a05a41b5d76 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -17,9 +17,7 @@
*/
#include "xfs.h"
#include "xfs_fs.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c
index a849a5473aff..c4f2da0d2bf5 100644
--- a/fs/xfs/xfs_ioctl32.c
+++ b/fs/xfs/xfs_ioctl32.c
@@ -22,9 +22,7 @@
#include <asm/uaccess.h>
#include "xfs.h"
#include "xfs_fs.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 71a464503c43..aadfce6681ee 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -17,9 +17,7 @@
*/
#include "xfs.h"
#include "xfs_fs.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
@@ -37,7 +35,6 @@
#include "xfs_rtalloc.h"
#include "xfs_error.h"
#include "xfs_itable.h"
-#include "xfs_rw.h"
#include "xfs_attr.h"
#include "xfs_buf_item.h"
#include "xfs_trans_space.h"
@@ -142,11 +139,7 @@ xfs_iomap_write_direct(
int committed;
int error;
- /*
- * Make sure that the dquots are there. This doesn't hold
- * the ilock across a disk read.
- */
- error = xfs_qm_dqattach_locked(ip, 0);
+ error = xfs_qm_dqattach(ip, 0);
if (error)
return XFS_ERROR(error);
@@ -158,7 +151,7 @@ xfs_iomap_write_direct(
if ((offset + count) > XFS_ISIZE(ip)) {
error = xfs_iomap_eof_align_last_fsb(mp, ip, extsz, &last_fsb);
if (error)
- goto error_out;
+ return XFS_ERROR(error);
} else {
if (nmaps && (imap->br_startblock == HOLESTARTBLOCK))
last_fsb = MIN(last_fsb, (xfs_fileoff_t)
@@ -190,7 +183,6 @@ xfs_iomap_write_direct(
/*
* Allocate and setup the transaction
*/
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
error = xfs_trans_reserve(tp, resblks,
XFS_WRITE_LOG_RES(mp), resrtextents,
@@ -199,15 +191,16 @@ xfs_iomap_write_direct(
/*
* Check for running out of space, note: need lock to return
*/
- if (error)
+ if (error) {
xfs_trans_cancel(tp, 0);
+ return XFS_ERROR(error);
+ }
+
xfs_ilock(ip, XFS_ILOCK_EXCL);
- if (error)
- goto error_out;
error = xfs_trans_reserve_quota_nblks(tp, ip, qblocks, 0, quota_flag);
if (error)
- goto error1;
+ goto out_trans_cancel;
xfs_trans_ijoin(tp, ip, 0);
@@ -224,42 +217,39 @@ xfs_iomap_write_direct(
error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb, bmapi_flag,
&firstfsb, 0, imap, &nimaps, &free_list);
if (error)
- goto error0;
+ goto out_bmap_cancel;
/*
* Complete the transaction
*/
error = xfs_bmap_finish(&tp, &free_list, &committed);
if (error)
- goto error0;
+ goto out_bmap_cancel;
error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
if (error)
- goto error_out;
+ goto out_unlock;
/*
* Copy any maps to caller's array and return any error.
*/
if (nimaps == 0) {
- error = ENOSPC;
- goto error_out;
+ error = XFS_ERROR(ENOSPC);
+ goto out_unlock;
}
- if (!(imap->br_startblock || XFS_IS_REALTIME_INODE(ip))) {
+ if (!(imap->br_startblock || XFS_IS_REALTIME_INODE(ip)))
error = xfs_alert_fsblock_zero(ip, imap);
- goto error_out;
- }
- return 0;
+out_unlock:
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ return error;
-error0: /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */
+out_bmap_cancel:
xfs_bmap_cancel(&free_list);
- xfs_trans_unreserve_quota_nblks(tp, ip, qblocks, 0, quota_flag);
-
-error1: /* Just cancel transaction */
+ xfs_trans_unreserve_quota_nblks(tp, ip, (long)qblocks, 0, quota_flag);
+out_trans_cancel:
xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
-
-error_out:
- return XFS_ERROR(error);
+ goto out_unlock;
}
/*
@@ -422,6 +412,15 @@ retry:
return error;
}
+ /*
+ * Make sure preallocation does not create extents beyond the range we
+ * actually support in this filesystem.
+ */
+ if (last_fsb > XFS_B_TO_FSB(mp, mp->m_maxioffset))
+ last_fsb = XFS_B_TO_FSB(mp, mp->m_maxioffset);
+
+ ASSERT(last_fsb > offset_fsb);
+
nimaps = XFS_WRITE_IMAPS;
error = xfs_bmapi_delay(ip, offset_fsb, last_fsb - offset_fsb,
imap, &nimaps, XFS_BMAPI_ENTIRE);
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 3011b879f850..1a25fd802798 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -18,9 +18,7 @@
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_acl.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
@@ -34,7 +32,6 @@
#include "xfs_rtalloc.h"
#include "xfs_error.h"
#include "xfs_itable.h"
-#include "xfs_rw.h"
#include "xfs_attr.h"
#include "xfs_buf_item.h"
#include "xfs_utils.h"
@@ -700,7 +697,7 @@ xfs_setattr_size(
xfs_off_t oldsize, newsize;
struct xfs_trans *tp;
int error;
- uint lock_flags;
+ uint lock_flags = 0;
uint commit_flags = 0;
trace_xfs_setattr(ip);
@@ -720,10 +717,10 @@ xfs_setattr_size(
ATTR_MTIME_SET|ATTR_KILL_SUID|ATTR_KILL_SGID|
ATTR_KILL_PRIV|ATTR_TIMES_SET)) == 0);
- lock_flags = XFS_ILOCK_EXCL;
- if (!(flags & XFS_ATTR_NOLOCK))
+ if (!(flags & XFS_ATTR_NOLOCK)) {
lock_flags |= XFS_IOLOCK_EXCL;
- xfs_ilock(ip, lock_flags);
+ xfs_ilock(ip, lock_flags);
+ }
oldsize = inode->i_size;
newsize = iattr->ia_size;
@@ -746,7 +743,7 @@ xfs_setattr_size(
/*
* Make sure that the dquots are attached to the inode.
*/
- error = xfs_qm_dqattach_locked(ip, 0);
+ error = xfs_qm_dqattach(ip, 0);
if (error)
goto out_unlock;
@@ -768,8 +765,6 @@ xfs_setattr_size(
if (error)
goto out_unlock;
}
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
- lock_flags &= ~XFS_ILOCK_EXCL;
/*
* We are going to log the inode size change in this transaction so
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index acc2bf264dab..eff577a9b67f 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -18,7 +18,6 @@
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_types.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
#include "xfs_inum.h"
#include "xfs_trans.h"
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index 6db1fef38bff..6b965bf450e4 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -18,9 +18,7 @@
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_types.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
@@ -35,7 +33,6 @@
#include "xfs_trans_priv.h"
#include "xfs_dinode.h"
#include "xfs_inode.h"
-#include "xfs_rw.h"
#include "xfs_trace.h"
kmem_zone_t *xfs_log_ticket_zone;
@@ -916,27 +913,42 @@ xfs_log_need_covered(xfs_mount_t *mp)
* We may be holding the log iclog lock upon entering this routine.
*/
xfs_lsn_t
-xlog_assign_tail_lsn(
+xlog_assign_tail_lsn_locked(
struct xfs_mount *mp)
{
- xfs_lsn_t tail_lsn;
struct log *log = mp->m_log;
+ struct xfs_log_item *lip;
+ xfs_lsn_t tail_lsn;
+
+ assert_spin_locked(&mp->m_ail->xa_lock);
/*
* To make sure we always have a valid LSN for the log tail we keep
* track of the last LSN which was committed in log->l_last_sync_lsn,
- * and use that when the AIL was empty and xfs_ail_min_lsn returns 0.
- *
- * If the AIL has been emptied we also need to wake any process
- * waiting for this condition.
+ * and use that when the AIL was empty.
*/
- tail_lsn = xfs_ail_min_lsn(mp->m_ail);
- if (!tail_lsn)
+ lip = xfs_ail_min(mp->m_ail);
+ if (lip)
+ tail_lsn = lip->li_lsn;
+ else
tail_lsn = atomic64_read(&log->l_last_sync_lsn);
atomic64_set(&log->l_tail_lsn, tail_lsn);
return tail_lsn;
}
+xfs_lsn_t
+xlog_assign_tail_lsn(
+ struct xfs_mount *mp)
+{
+ xfs_lsn_t tail_lsn;
+
+ spin_lock(&mp->m_ail->xa_lock);
+ tail_lsn = xlog_assign_tail_lsn_locked(mp);
+ spin_unlock(&mp->m_ail->xa_lock);
+
+ return tail_lsn;
+}
+
/*
* Return the space in the log between the tail and the head. The head
* is passed in the cycle/bytes formal parms. In the special case where
@@ -1172,7 +1184,7 @@ xlog_alloc_log(xfs_mount_t *mp,
xlog_get_iclog_buffer_size(mp, log);
error = ENOMEM;
- bp = xfs_buf_alloc(mp->m_logdev_targp, 0, log->l_iclog_size, 0);
+ bp = xfs_buf_alloc(mp->m_logdev_targp, 0, BTOBB(log->l_iclog_size), 0);
if (!bp)
goto out_free_log;
bp->b_iodone = xlog_iodone;
@@ -1182,9 +1194,6 @@ xlog_alloc_log(xfs_mount_t *mp,
spin_lock_init(&log->l_icloglock);
init_waitqueue_head(&log->l_flush_wait);
- /* log record size must be multiple of BBSIZE; see xlog_rec_header_t */
- ASSERT((XFS_BUF_SIZE(bp) & BBMASK) == 0);
-
iclogp = &log->l_iclog;
/*
* The amount of memory to allocate for the iclog structure is
@@ -1204,7 +1213,7 @@ xlog_alloc_log(xfs_mount_t *mp,
prev_iclog = iclog;
bp = xfs_buf_get_uncached(mp->m_logdev_targp,
- log->l_iclog_size, 0);
+ BTOBB(log->l_iclog_size), 0);
if (!bp)
goto out_free_iclog;
@@ -1224,7 +1233,7 @@ xlog_alloc_log(xfs_mount_t *mp,
head->h_fmt = cpu_to_be32(XLOG_FMT);
memcpy(&head->h_fs_uuid, &mp->m_sb.sb_uuid, sizeof(uuid_t));
- iclog->ic_size = XFS_BUF_SIZE(bp) - log->l_iclog_hsize;
+ iclog->ic_size = BBTOB(bp->b_length) - log->l_iclog_hsize;
iclog->ic_state = XLOG_STATE_ACTIVE;
iclog->ic_log = log;
atomic_set(&iclog->ic_refcnt, 0);
@@ -1475,7 +1484,7 @@ xlog_sync(xlog_t *log,
} else {
iclog->ic_bwritecnt = 1;
}
- XFS_BUF_SET_COUNT(bp, count);
+ bp->b_io_length = BTOBB(count);
bp->b_fspriv = iclog;
XFS_BUF_ZEROFLAGS(bp);
XFS_BUF_ASYNC(bp);
@@ -1573,7 +1582,7 @@ xlog_dealloc_log(xlog_t *log)
* always need to ensure that the extra buffer does not point to memory
* owned by another log buffer before we free it.
*/
- xfs_buf_set_empty(log->l_xbuf, log->l_iclog_size);
+ xfs_buf_set_empty(log->l_xbuf, BTOBB(log->l_iclog_size));
xfs_buf_free(log->l_xbuf);
iclog = log->l_iclog;
@@ -2932,6 +2941,7 @@ xfs_log_force(
{
int error;
+ trace_xfs_log_force(mp, 0);
error = _xfs_log_force(mp, flags, NULL);
if (error)
xfs_warn(mp, "%s: error %d returned.", __func__, error);
@@ -3080,6 +3090,7 @@ xfs_log_force_lsn(
{
int error;
+ trace_xfs_log_force(mp, lsn);
error = _xfs_log_force_lsn(mp, lsn, flags, NULL);
if (error)
xfs_warn(mp, "%s: error %d returned.", __func__, error);
diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h
index 2c622bedb302..748d312850e2 100644
--- a/fs/xfs/xfs_log.h
+++ b/fs/xfs/xfs_log.h
@@ -152,6 +152,7 @@ int xfs_log_mount(struct xfs_mount *mp,
int num_bblocks);
int xfs_log_mount_finish(struct xfs_mount *mp);
xfs_lsn_t xlog_assign_tail_lsn(struct xfs_mount *mp);
+xfs_lsn_t xlog_assign_tail_lsn_locked(struct xfs_mount *mp);
void xfs_log_space_wake(struct xfs_mount *mp);
int xfs_log_notify(struct xfs_mount *mp,
struct xlog_in_core *iclog,
diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c
index d4fadbe8ac90..7d6197c58493 100644
--- a/fs/xfs/xfs_log_cil.c
+++ b/fs/xfs/xfs_log_cil.c
@@ -18,9 +18,7 @@
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_types.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_trans_priv.h"
#include "xfs_log_priv.h"
@@ -29,61 +27,10 @@
#include "xfs_mount.h"
#include "xfs_error.h"
#include "xfs_alloc.h"
+#include "xfs_extent_busy.h"
#include "xfs_discard.h"
/*
- * Perform initial CIL structure initialisation.
- */
-int
-xlog_cil_init(
- struct log *log)
-{
- struct xfs_cil *cil;
- struct xfs_cil_ctx *ctx;
-
- cil = kmem_zalloc(sizeof(*cil), KM_SLEEP|KM_MAYFAIL);
- if (!cil)
- return ENOMEM;
-
- ctx = kmem_zalloc(sizeof(*ctx), KM_SLEEP|KM_MAYFAIL);
- if (!ctx) {
- kmem_free(cil);
- return ENOMEM;
- }
-
- INIT_LIST_HEAD(&cil->xc_cil);
- INIT_LIST_HEAD(&cil->xc_committing);
- spin_lock_init(&cil->xc_cil_lock);
- init_rwsem(&cil->xc_ctx_lock);
- init_waitqueue_head(&cil->xc_commit_wait);
-
- INIT_LIST_HEAD(&ctx->committing);
- INIT_LIST_HEAD(&ctx->busy_extents);
- ctx->sequence = 1;
- ctx->cil = cil;
- cil->xc_ctx = ctx;
- cil->xc_current_sequence = ctx->sequence;
-
- cil->xc_log = log;
- log->l_cilp = cil;
- return 0;
-}
-
-void
-xlog_cil_destroy(
- struct log *log)
-{
- if (log->l_cilp->xc_ctx) {
- if (log->l_cilp->xc_ctx->ticket)
- xfs_log_ticket_put(log->l_cilp->xc_ctx->ticket);
- kmem_free(log->l_cilp->xc_ctx);
- }
-
- ASSERT(list_empty(&log->l_cilp->xc_cil));
- kmem_free(log->l_cilp);
-}
-
-/*
* Allocate a new ticket. Failing to get a new ticket makes it really hard to
* recover, so we don't allow failure here. Also, we allocate in a context that
* we don't want to be issuing transactions from, so we need to tell the
@@ -390,8 +337,8 @@ xlog_cil_committed(
xfs_trans_committed_bulk(ctx->cil->xc_log->l_ailp, ctx->lv_chain,
ctx->start_lsn, abort);
- xfs_alloc_busy_sort(&ctx->busy_extents);
- xfs_alloc_busy_clear(mp, &ctx->busy_extents,
+ xfs_extent_busy_sort(&ctx->busy_extents);
+ xfs_extent_busy_clear(mp, &ctx->busy_extents,
(mp->m_flags & XFS_MOUNT_DISCARD) && !abort);
spin_lock(&ctx->cil->xc_cil_lock);
@@ -404,7 +351,7 @@ xlog_cil_committed(
ASSERT(mp->m_flags & XFS_MOUNT_DISCARD);
xfs_discard_extents(mp, &ctx->busy_extents);
- xfs_alloc_busy_clear(mp, &ctx->busy_extents, false);
+ xfs_extent_busy_clear(mp, &ctx->busy_extents, false);
}
kmem_free(ctx);
@@ -426,8 +373,7 @@ xlog_cil_committed(
*/
STATIC int
xlog_cil_push(
- struct log *log,
- xfs_lsn_t push_seq)
+ struct log *log)
{
struct xfs_cil *cil = log->l_cilp;
struct xfs_log_vec *lv;
@@ -443,39 +389,36 @@ xlog_cil_push(
struct xfs_log_iovec lhdr;
struct xfs_log_vec lvhdr = { NULL };
xfs_lsn_t commit_lsn;
+ xfs_lsn_t push_seq;
if (!cil)
return 0;
- ASSERT(!push_seq || push_seq <= cil->xc_ctx->sequence);
-
new_ctx = kmem_zalloc(sizeof(*new_ctx), KM_SLEEP|KM_NOFS);
new_ctx->ticket = xlog_cil_ticket_alloc(log);
- /*
- * Lock out transaction commit, but don't block for background pushes
- * unless we are well over the CIL space limit. See the definition of
- * XLOG_CIL_HARD_SPACE_LIMIT() for the full explanation of the logic
- * used here.
- */
- if (!down_write_trylock(&cil->xc_ctx_lock)) {
- if (!push_seq &&
- cil->xc_ctx->space_used < XLOG_CIL_HARD_SPACE_LIMIT(log))
- goto out_free_ticket;
- down_write(&cil->xc_ctx_lock);
- }
+ down_write(&cil->xc_ctx_lock);
ctx = cil->xc_ctx;
- /* check if we've anything to push */
- if (list_empty(&cil->xc_cil))
- goto out_skip;
+ spin_lock(&cil->xc_cil_lock);
+ push_seq = cil->xc_push_seq;
+ ASSERT(push_seq <= ctx->sequence);
- /* check for spurious background flush */
- if (!push_seq && cil->xc_ctx->space_used < XLOG_CIL_SPACE_LIMIT(log))
+ /*
+ * Check if we've anything to push. If there is nothing, then we don't
+ * move on to a new sequence number and so we have to be able to push
+ * this sequence again later.
+ */
+ if (list_empty(&cil->xc_cil)) {
+ cil->xc_push_seq = 0;
+ spin_unlock(&cil->xc_cil_lock);
goto out_skip;
+ }
+ spin_unlock(&cil->xc_cil_lock);
+
/* check for a previously pushed seqeunce */
- if (push_seq && push_seq < cil->xc_ctx->sequence)
+ if (push_seq < cil->xc_ctx->sequence)
goto out_skip;
/*
@@ -629,7 +572,6 @@ restart:
out_skip:
up_write(&cil->xc_ctx_lock);
-out_free_ticket:
xfs_log_ticket_put(new_ctx->ticket);
kmem_free(new_ctx);
return 0;
@@ -641,6 +583,82 @@ out_abort:
return XFS_ERROR(EIO);
}
+static void
+xlog_cil_push_work(
+ struct work_struct *work)
+{
+ struct xfs_cil *cil = container_of(work, struct xfs_cil,
+ xc_push_work);
+ xlog_cil_push(cil->xc_log);
+}
+
+/*
+ * We need to push CIL every so often so we don't cache more than we can fit in
+ * the log. The limit really is that a checkpoint can't be more than half the
+ * log (the current checkpoint is not allowed to overwrite the previous
+ * checkpoint), but commit latency and memory usage limit this to a smaller
+ * size.
+ */
+static void
+xlog_cil_push_background(
+ struct log *log)
+{
+ struct xfs_cil *cil = log->l_cilp;
+
+ /*
+ * The cil won't be empty because we are called while holding the
+ * context lock so whatever we added to the CIL will still be there
+ */
+ ASSERT(!list_empty(&cil->xc_cil));
+
+ /*
+ * don't do a background push if we haven't used up all the
+ * space available yet.
+ */
+ if (cil->xc_ctx->space_used < XLOG_CIL_SPACE_LIMIT(log))
+ return;
+
+ spin_lock(&cil->xc_cil_lock);
+ if (cil->xc_push_seq < cil->xc_current_sequence) {
+ cil->xc_push_seq = cil->xc_current_sequence;
+ queue_work(log->l_mp->m_cil_workqueue, &cil->xc_push_work);
+ }
+ spin_unlock(&cil->xc_cil_lock);
+
+}
+
+static void
+xlog_cil_push_foreground(
+ struct log *log,
+ xfs_lsn_t push_seq)
+{
+ struct xfs_cil *cil = log->l_cilp;
+
+ if (!cil)
+ return;
+
+ ASSERT(push_seq && push_seq <= cil->xc_current_sequence);
+
+ /* start on any pending background push to minimise wait time on it */
+ flush_work(&cil->xc_push_work);
+
+ /*
+ * If the CIL is empty or we've already pushed the sequence then
+ * there's no work we need to do.
+ */
+ spin_lock(&cil->xc_cil_lock);
+ if (list_empty(&cil->xc_cil) || push_seq <= cil->xc_push_seq) {
+ spin_unlock(&cil->xc_cil_lock);
+ return;
+ }
+
+ cil->xc_push_seq = push_seq;
+ spin_unlock(&cil->xc_cil_lock);
+
+ /* do the push now */
+ xlog_cil_push(log);
+}
+
/*
* Commit a transaction with the given vector to the Committed Item List.
*
@@ -667,7 +685,6 @@ xfs_log_commit_cil(
{
struct log *log = mp->m_log;
int log_flags = 0;
- int push = 0;
struct xfs_log_vec *log_vector;
if (flags & XFS_TRANS_RELEASE_LOG_RES)
@@ -719,21 +736,9 @@ xfs_log_commit_cil(
*/
xfs_trans_free_items(tp, *commit_lsn, 0);
- /* check for background commit before unlock */
- if (log->l_cilp->xc_ctx->space_used > XLOG_CIL_SPACE_LIMIT(log))
- push = 1;
+ xlog_cil_push_background(log);
up_read(&log->l_cilp->xc_ctx_lock);
-
- /*
- * We need to push CIL every so often so we don't cache more than we
- * can fit in the log. The limit really is that a checkpoint can't be
- * more than half the log (the current checkpoint is not allowed to
- * overwrite the previous checkpoint), but commit latency and memory
- * usage limit this to a smaller size in most cases.
- */
- if (push)
- xlog_cil_push(log, 0);
return 0;
}
@@ -746,9 +751,6 @@ xfs_log_commit_cil(
*
* We return the current commit lsn to allow the callers to determine if a
* iclog flush is necessary following this call.
- *
- * XXX: Initially, just push the CIL unconditionally and return whatever
- * commit lsn is there. It'll be empty, so this is broken for now.
*/
xfs_lsn_t
xlog_cil_force_lsn(
@@ -766,8 +768,7 @@ xlog_cil_force_lsn(
* xlog_cil_push() handles racing pushes for the same sequence,
* so no need to deal with it here.
*/
- if (sequence == cil->xc_current_sequence)
- xlog_cil_push(log, sequence);
+ xlog_cil_push_foreground(log, sequence);
/*
* See if we can find a previous sequence still committing.
@@ -826,3 +827,57 @@ xfs_log_item_in_current_chkpt(
return false;
return true;
}
+
+/*
+ * Perform initial CIL structure initialisation.
+ */
+int
+xlog_cil_init(
+ struct log *log)
+{
+ struct xfs_cil *cil;
+ struct xfs_cil_ctx *ctx;
+
+ cil = kmem_zalloc(sizeof(*cil), KM_SLEEP|KM_MAYFAIL);
+ if (!cil)
+ return ENOMEM;
+
+ ctx = kmem_zalloc(sizeof(*ctx), KM_SLEEP|KM_MAYFAIL);
+ if (!ctx) {
+ kmem_free(cil);
+ return ENOMEM;
+ }
+
+ INIT_WORK(&cil->xc_push_work, xlog_cil_push_work);
+ INIT_LIST_HEAD(&cil->xc_cil);
+ INIT_LIST_HEAD(&cil->xc_committing);
+ spin_lock_init(&cil->xc_cil_lock);
+ init_rwsem(&cil->xc_ctx_lock);
+ init_waitqueue_head(&cil->xc_commit_wait);
+
+ INIT_LIST_HEAD(&ctx->committing);
+ INIT_LIST_HEAD(&ctx->busy_extents);
+ ctx->sequence = 1;
+ ctx->cil = cil;
+ cil->xc_ctx = ctx;
+ cil->xc_current_sequence = ctx->sequence;
+
+ cil->xc_log = log;
+ log->l_cilp = cil;
+ return 0;
+}
+
+void
+xlog_cil_destroy(
+ struct log *log)
+{
+ if (log->l_cilp->xc_ctx) {
+ if (log->l_cilp->xc_ctx->ticket)
+ xfs_log_ticket_put(log->l_cilp->xc_ctx->ticket);
+ kmem_free(log->l_cilp->xc_ctx);
+ }
+
+ ASSERT(list_empty(&log->l_cilp->xc_cil));
+ kmem_free(log->l_cilp);
+}
+
diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h
index 2152900b79d4..735ff1ee53da 100644
--- a/fs/xfs/xfs_log_priv.h
+++ b/fs/xfs/xfs_log_priv.h
@@ -417,6 +417,8 @@ struct xfs_cil {
struct list_head xc_committing;
wait_queue_head_t xc_commit_wait;
xfs_lsn_t xc_current_sequence;
+ struct work_struct xc_push_work;
+ xfs_lsn_t xc_push_seq;
};
/*
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 8ecad5bad66c..ca386909131a 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -40,7 +40,6 @@
#include "xfs_extfree_item.h"
#include "xfs_trans_priv.h"
#include "xfs_quota.h"
-#include "xfs_rw.h"
#include "xfs_utils.h"
#include "xfs_trace.h"
@@ -120,7 +119,7 @@ xlog_get_bp(
nbblks += log->l_sectBBsize;
nbblks = round_up(nbblks, log->l_sectBBsize);
- bp = xfs_buf_get_uncached(log->l_mp->m_logdev_targp, BBTOB(nbblks), 0);
+ bp = xfs_buf_get_uncached(log->l_mp->m_logdev_targp, nbblks, 0);
if (bp)
xfs_buf_unlock(bp);
return bp;
@@ -146,7 +145,7 @@ xlog_align(
{
xfs_daddr_t offset = blk_no & ((xfs_daddr_t)log->l_sectBBsize - 1);
- ASSERT(BBTOB(offset + nbblks) <= XFS_BUF_SIZE(bp));
+ ASSERT(offset + nbblks <= bp->b_length);
return bp->b_addr + BBTOB(offset);
}
@@ -174,11 +173,12 @@ xlog_bread_noalign(
nbblks = round_up(nbblks, log->l_sectBBsize);
ASSERT(nbblks > 0);
- ASSERT(BBTOB(nbblks) <= XFS_BUF_SIZE(bp));
+ ASSERT(nbblks <= bp->b_length);
XFS_BUF_SET_ADDR(bp, log->l_logBBstart + blk_no);
XFS_BUF_READ(bp);
- XFS_BUF_SET_COUNT(bp, BBTOB(nbblks));
+ bp->b_io_length = nbblks;
+ bp->b_error = 0;
xfsbdstrat(log->l_mp, bp);
error = xfs_buf_iowait(bp);
@@ -218,7 +218,7 @@ xlog_bread_offset(
xfs_caddr_t offset)
{
xfs_caddr_t orig_offset = bp->b_addr;
- int orig_len = bp->b_buffer_length;
+ int orig_len = BBTOB(bp->b_length);
int error, error2;
error = xfs_buf_associate_memory(bp, offset, BBTOB(nbblks));
@@ -259,13 +259,14 @@ xlog_bwrite(
nbblks = round_up(nbblks, log->l_sectBBsize);
ASSERT(nbblks > 0);
- ASSERT(BBTOB(nbblks) <= XFS_BUF_SIZE(bp));
+ ASSERT(nbblks <= bp->b_length);
XFS_BUF_SET_ADDR(bp, log->l_logBBstart + blk_no);
XFS_BUF_ZEROFLAGS(bp);
xfs_buf_hold(bp);
xfs_buf_lock(bp);
- XFS_BUF_SET_COUNT(bp, BBTOB(nbblks));
+ bp->b_io_length = nbblks;
+ bp->b_error = 0;
error = xfs_bwrite(bp);
if (error)
@@ -440,6 +441,8 @@ xlog_find_verify_cycle(
* a log sector, or we're out of luck.
*/
bufblks = 1 << ffs(nbblks);
+ while (bufblks > log->l_logBBsize)
+ bufblks >>= 1;
while (!(bp = xlog_get_bp(log, bufblks))) {
bufblks >>= 1;
if (bufblks < log->l_sectBBsize)
@@ -1225,6 +1228,8 @@ xlog_write_log_records(
* log sector, or we're out of luck.
*/
bufblks = 1 << ffs(blocks);
+ while (bufblks > log->l_logBBsize)
+ bufblks >>= 1;
while (!(bp = xlog_get_bp(log, bufblks))) {
bufblks >>= 1;
if (bufblks < sectbb)
@@ -1772,7 +1777,7 @@ xlog_recover_do_inode_buffer(
trace_xfs_log_recover_buf_inode_buf(mp->m_log, buf_f);
- inodes_per_buf = XFS_BUF_COUNT(bp) >> mp->m_sb.sb_inodelog;
+ inodes_per_buf = BBTOB(bp->b_io_length) >> mp->m_sb.sb_inodelog;
for (i = 0; i < inodes_per_buf; i++) {
next_unlinked_offset = (i * mp->m_sb.sb_inodesize) +
offsetof(xfs_dinode_t, di_next_unlinked);
@@ -1814,7 +1819,8 @@ xlog_recover_do_inode_buffer(
ASSERT(item->ri_buf[item_index].i_addr != NULL);
ASSERT((item->ri_buf[item_index].i_len % XFS_BLF_CHUNK) == 0);
- ASSERT((reg_buf_offset + reg_buf_bytes) <= XFS_BUF_COUNT(bp));
+ ASSERT((reg_buf_offset + reg_buf_bytes) <=
+ BBTOB(bp->b_io_length));
/*
* The current logged region contains a copy of the
@@ -1873,8 +1879,8 @@ xlog_recover_do_reg_buffer(
ASSERT(nbits > 0);
ASSERT(item->ri_buf[i].i_addr != NULL);
ASSERT(item->ri_buf[i].i_len % XFS_BLF_CHUNK == 0);
- ASSERT(XFS_BUF_COUNT(bp) >=
- ((uint)bit << XFS_BLF_SHIFT)+(nbits<<XFS_BLF_SHIFT));
+ ASSERT(BBTOB(bp->b_io_length) >=
+ ((uint)bit << XFS_BLF_SHIFT) + (nbits << XFS_BLF_SHIFT));
/*
* Do a sanity check if this is a dquot buffer. Just checking
@@ -2103,6 +2109,7 @@ xlog_recover_do_dquot_buffer(
STATIC int
xlog_recover_buffer_pass2(
xlog_t *log,
+ struct list_head *buffer_list,
xlog_recover_item_t *item)
{
xfs_buf_log_format_t *buf_f = item->ri_buf[0].i_addr;
@@ -2123,9 +2130,9 @@ xlog_recover_buffer_pass2(
trace_xfs_log_recover_buf_recover(log, buf_f);
- buf_flags = XBF_LOCK;
- if (!(buf_f->blf_flags & XFS_BLF_INODE_BUF))
- buf_flags |= XBF_MAPPED;
+ buf_flags = 0;
+ if (buf_f->blf_flags & XFS_BLF_INODE_BUF)
+ buf_flags |= XBF_UNMAPPED;
bp = xfs_buf_read(mp->m_ddev_targp, buf_f->blf_blkno, buf_f->blf_len,
buf_flags);
@@ -2166,14 +2173,14 @@ xlog_recover_buffer_pass2(
*/
if (XFS_DINODE_MAGIC ==
be16_to_cpu(*((__be16 *)xfs_buf_offset(bp, 0))) &&
- (XFS_BUF_COUNT(bp) != MAX(log->l_mp->m_sb.sb_blocksize,
+ (BBTOB(bp->b_io_length) != MAX(log->l_mp->m_sb.sb_blocksize,
(__uint32_t)XFS_INODE_CLUSTER_SIZE(log->l_mp)))) {
xfs_buf_stale(bp);
error = xfs_bwrite(bp);
} else {
ASSERT(bp->b_target->bt_mount == mp);
bp->b_iodone = xlog_recover_iodone;
- xfs_buf_delwri_queue(bp);
+ xfs_buf_delwri_queue(bp, buffer_list);
}
xfs_buf_relse(bp);
@@ -2183,6 +2190,7 @@ xlog_recover_buffer_pass2(
STATIC int
xlog_recover_inode_pass2(
xlog_t *log,
+ struct list_head *buffer_list,
xlog_recover_item_t *item)
{
xfs_inode_log_format_t *in_f;
@@ -2220,8 +2228,7 @@ xlog_recover_inode_pass2(
}
trace_xfs_log_recover_inode_recover(log, in_f);
- bp = xfs_buf_read(mp->m_ddev_targp, in_f->ilf_blkno, in_f->ilf_len,
- XBF_LOCK);
+ bp = xfs_buf_read(mp->m_ddev_targp, in_f->ilf_blkno, in_f->ilf_len, 0);
if (!bp) {
error = ENOMEM;
goto error;
@@ -2436,7 +2443,7 @@ xlog_recover_inode_pass2(
write_inode_buffer:
ASSERT(bp->b_target->bt_mount == mp);
bp->b_iodone = xlog_recover_iodone;
- xfs_buf_delwri_queue(bp);
+ xfs_buf_delwri_queue(bp, buffer_list);
xfs_buf_relse(bp);
error:
if (need_free)
@@ -2477,6 +2484,7 @@ xlog_recover_quotaoff_pass1(
STATIC int
xlog_recover_dquot_pass2(
xlog_t *log,
+ struct list_head *buffer_list,
xlog_recover_item_t *item)
{
xfs_mount_t *mp = log->l_mp;
@@ -2530,14 +2538,11 @@ xlog_recover_dquot_pass2(
return XFS_ERROR(EIO);
ASSERT(dq_f->qlf_len == 1);
- error = xfs_read_buf(mp, mp->m_ddev_targp,
- dq_f->qlf_blkno,
- XFS_FSB_TO_BB(mp, dq_f->qlf_len),
- 0, &bp);
- if (error) {
- xfs_buf_ioerror_alert(bp, "xlog_recover_do..(read#3)");
+ error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dq_f->qlf_blkno,
+ XFS_FSB_TO_BB(mp, dq_f->qlf_len), 0, &bp);
+ if (error)
return error;
- }
+
ASSERT(bp);
ddq = (xfs_disk_dquot_t *)xfs_buf_offset(bp, dq_f->qlf_boffset);
@@ -2558,7 +2563,7 @@ xlog_recover_dquot_pass2(
ASSERT(dq_f->qlf_size == 2);
ASSERT(bp->b_target->bt_mount == mp);
bp->b_iodone = xlog_recover_iodone;
- xfs_buf_delwri_queue(bp);
+ xfs_buf_delwri_queue(bp, buffer_list);
xfs_buf_relse(bp);
return (0);
@@ -2642,7 +2647,8 @@ xlog_recover_efd_pass2(
* xfs_trans_ail_delete() drops the
* AIL lock.
*/
- xfs_trans_ail_delete(ailp, lip);
+ xfs_trans_ail_delete(ailp, lip,
+ SHUTDOWN_CORRUPT_INCORE);
xfs_efi_item_free(efip);
spin_lock(&ailp->xa_lock);
break;
@@ -2712,21 +2718,22 @@ STATIC int
xlog_recover_commit_pass2(
struct log *log,
struct xlog_recover *trans,
+ struct list_head *buffer_list,
xlog_recover_item_t *item)
{
trace_xfs_log_recover_item_recover(log, trans, item, XLOG_RECOVER_PASS2);
switch (ITEM_TYPE(item)) {
case XFS_LI_BUF:
- return xlog_recover_buffer_pass2(log, item);
+ return xlog_recover_buffer_pass2(log, buffer_list, item);
case XFS_LI_INODE:
- return xlog_recover_inode_pass2(log, item);
+ return xlog_recover_inode_pass2(log, buffer_list, item);
case XFS_LI_EFI:
return xlog_recover_efi_pass2(log, item, trans->r_lsn);
case XFS_LI_EFD:
return xlog_recover_efd_pass2(log, item);
case XFS_LI_DQUOT:
- return xlog_recover_dquot_pass2(log, item);
+ return xlog_recover_dquot_pass2(log, buffer_list, item);
case XFS_LI_QUOTAOFF:
/* nothing to do in pass2 */
return 0;
@@ -2750,8 +2757,9 @@ xlog_recover_commit_trans(
struct xlog_recover *trans,
int pass)
{
- int error = 0;
+ int error = 0, error2;
xlog_recover_item_t *item;
+ LIST_HEAD (buffer_list);
hlist_del(&trans->r_list);
@@ -2760,16 +2768,27 @@ xlog_recover_commit_trans(
return error;
list_for_each_entry(item, &trans->r_itemq, ri_list) {
- if (pass == XLOG_RECOVER_PASS1)
+ switch (pass) {
+ case XLOG_RECOVER_PASS1:
error = xlog_recover_commit_pass1(log, trans, item);
- else
- error = xlog_recover_commit_pass2(log, trans, item);
+ break;
+ case XLOG_RECOVER_PASS2:
+ error = xlog_recover_commit_pass2(log, trans,
+ &buffer_list, item);
+ break;
+ default:
+ ASSERT(0);
+ }
+
if (error)
- return error;
+ goto out;
}
xlog_recover_free_trans(trans);
- return 0;
+
+out:
+ error2 = xfs_buf_delwri_submit(&buffer_list);
+ return error ? error : error2;
}
STATIC int
@@ -3079,7 +3098,7 @@ xlog_recover_process_one_iunlink(
/*
* Get the on disk inode to find the next inode in the bucket.
*/
- error = xfs_itobp(mp, NULL, ip, &dip, &ibp, XBF_LOCK);
+ error = xfs_itobp(mp, NULL, ip, &dip, &ibp, 0);
if (error)
goto fail_iput;
@@ -3639,11 +3658,8 @@ xlog_do_recover(
* First replay the images in the log.
*/
error = xlog_do_log_recovery(log, head_blk, tail_blk);
- if (error) {
+ if (error)
return error;
- }
-
- xfs_flush_buftarg(log->l_mp->m_ddev_targp, 1);
/*
* If IO errors happened during recovery, bail out.
@@ -3670,7 +3686,6 @@ xlog_do_recover(
bp = xfs_getsb(log->l_mp, 0);
XFS_BUF_UNDONE(bp);
ASSERT(!(XFS_BUF_ISWRITE(bp)));
- ASSERT(!(XFS_BUF_ISDELAYWRITE(bp)));
XFS_BUF_READ(bp);
XFS_BUF_UNASYNC(bp);
xfsbdstrat(log->l_mp, bp);
diff --git a/fs/xfs/xfs_message.c b/fs/xfs/xfs_message.c
index bd672def95ac..331cd9f83a7f 100644
--- a/fs/xfs/xfs_message.c
+++ b/fs/xfs/xfs_message.c
@@ -19,7 +19,6 @@
#include "xfs_fs.h"
#include "xfs_types.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 1ffead4b2296..536021fb3d4e 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -22,6 +22,7 @@
#include "xfs_log.h"
#include "xfs_inum.h"
#include "xfs_trans.h"
+#include "xfs_trans_priv.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_dir2.h"
@@ -37,7 +38,6 @@
#include "xfs_rtalloc.h"
#include "xfs_bmap.h"
#include "xfs_error.h"
-#include "xfs_rw.h"
#include "xfs_quota.h"
#include "xfs_fsops.h"
#include "xfs_utils.h"
@@ -683,8 +683,8 @@ xfs_readsb(xfs_mount_t *mp, int flags)
sector_size = xfs_getsize_buftarg(mp->m_ddev_targp);
reread:
- bp = xfs_buf_read_uncached(mp, mp->m_ddev_targp,
- XFS_SB_DADDR, sector_size, 0);
+ bp = xfs_buf_read_uncached(mp->m_ddev_targp, XFS_SB_DADDR,
+ BTOBB(sector_size), 0);
if (!bp) {
if (loud)
xfs_warn(mp, "SB buffer read failed");
@@ -1032,9 +1032,9 @@ xfs_check_sizes(xfs_mount_t *mp)
xfs_warn(mp, "filesystem size mismatch detected");
return XFS_ERROR(EFBIG);
}
- bp = xfs_buf_read_uncached(mp, mp->m_ddev_targp,
+ bp = xfs_buf_read_uncached(mp->m_ddev_targp,
d - XFS_FSS_TO_BB(mp, 1),
- BBTOB(XFS_FSS_TO_BB(mp, 1)), 0);
+ XFS_FSS_TO_BB(mp, 1), 0);
if (!bp) {
xfs_warn(mp, "last sector read failed");
return EIO;
@@ -1047,9 +1047,9 @@ xfs_check_sizes(xfs_mount_t *mp)
xfs_warn(mp, "log size mismatch detected");
return XFS_ERROR(EFBIG);
}
- bp = xfs_buf_read_uncached(mp, mp->m_logdev_targp,
+ bp = xfs_buf_read_uncached(mp->m_logdev_targp,
d - XFS_FSB_TO_BB(mp, 1),
- XFS_FSB_TO_B(mp, 1), 0);
+ XFS_FSB_TO_BB(mp, 1), 0);
if (!bp) {
xfs_warn(mp, "log device read failed");
return EIO;
@@ -1288,7 +1288,7 @@ xfs_mountfs(
XFS_FSB_TO_BB(mp, sbp->sb_logblocks));
if (error) {
xfs_warn(mp, "log mount failed");
- goto out_free_perag;
+ goto out_fail_wait;
}
/*
@@ -1315,7 +1315,7 @@ xfs_mountfs(
!mp->m_sb.sb_inprogress) {
error = xfs_initialize_perag_data(mp, sbp->sb_agcount);
if (error)
- goto out_free_perag;
+ goto out_fail_wait;
}
/*
@@ -1439,6 +1439,10 @@ xfs_mountfs(
IRELE(rip);
out_log_dealloc:
xfs_log_unmount(mp);
+ out_fail_wait:
+ if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp)
+ xfs_wait_buftarg(mp->m_logdev_targp);
+ xfs_wait_buftarg(mp->m_ddev_targp);
out_free_perag:
xfs_free_perag(mp);
out_remove_uuid:
@@ -1475,15 +1479,15 @@ xfs_unmountfs(
xfs_log_force(mp, XFS_LOG_SYNC);
/*
- * Do a delwri reclaim pass first so that as many dirty inodes are
- * queued up for IO as possible. Then flush the buffers before making
- * a synchronous path to catch all the remaining inodes are reclaimed.
- * This makes the reclaim process as quick as possible by avoiding
- * synchronous writeout and blocking on inodes already in the delwri
- * state as much as possible.
+ * Flush all pending changes from the AIL.
+ */
+ xfs_ail_push_all_sync(mp->m_ail);
+
+ /*
+ * And reclaim all inodes. At this point there should be no dirty
+ * inode, and none should be pinned or locked, but use synchronous
+ * reclaim just to be sure.
*/
- xfs_reclaim_inodes(mp, 0);
- xfs_flush_buftarg(mp->m_ddev_targp, 1);
xfs_reclaim_inodes(mp, SYNC_WAIT);
xfs_qm_unmount(mp);
@@ -1519,15 +1523,12 @@ xfs_unmountfs(
if (error)
xfs_warn(mp, "Unable to update superblock counters. "
"Freespace may not be correct on next mount.");
- xfs_unmountfs_writesb(mp);
/*
- * Make sure all buffers have been flushed and completed before
- * unmounting the log.
+ * At this point we might have modified the superblock again and thus
+ * added an item to the AIL, thus flush it again.
*/
- error = xfs_flush_buftarg(mp->m_ddev_targp, 1);
- if (error)
- xfs_warn(mp, "%d busy buffers during unmount.", error);
+ xfs_ail_push_all_sync(mp->m_ail);
xfs_wait_buftarg(mp->m_ddev_targp);
xfs_log_unmount_write(mp);
@@ -1588,36 +1589,6 @@ xfs_log_sbcount(xfs_mount_t *mp)
return error;
}
-int
-xfs_unmountfs_writesb(xfs_mount_t *mp)
-{
- xfs_buf_t *sbp;
- int error = 0;
-
- /*
- * skip superblock write if fs is read-only, or
- * if we are doing a forced umount.
- */
- if (!((mp->m_flags & XFS_MOUNT_RDONLY) ||
- XFS_FORCED_SHUTDOWN(mp))) {
-
- sbp = xfs_getsb(mp, 0);
-
- XFS_BUF_UNDONE(sbp);
- XFS_BUF_UNREAD(sbp);
- xfs_buf_delwri_dequeue(sbp);
- XFS_BUF_WRITE(sbp);
- XFS_BUF_UNASYNC(sbp);
- ASSERT(sbp->b_target == mp->m_ddev_targp);
- xfsbdstrat(mp, sbp);
- error = xfs_buf_iowait(sbp);
- if (error)
- xfs_buf_ioerror_alert(sbp, __func__);
- xfs_buf_relse(sbp);
- }
- return error;
-}
-
/*
* xfs_mod_sb() can be used to copy arbitrary changes to the
* in-core superblock into the superblock buffer to be logged.
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 9eba73887829..8b89c5ac72d9 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -214,6 +214,7 @@ typedef struct xfs_mount {
struct workqueue_struct *m_data_workqueue;
struct workqueue_struct *m_unwritten_workqueue;
+ struct workqueue_struct *m_cil_workqueue;
} xfs_mount_t;
/*
@@ -378,7 +379,6 @@ extern __uint64_t xfs_default_resblks(xfs_mount_t *mp);
extern int xfs_mountfs(xfs_mount_t *mp);
extern void xfs_unmountfs(xfs_mount_t *);
-extern int xfs_unmountfs_writesb(xfs_mount_t *);
extern int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int64_t, int);
extern int xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *,
uint, int);
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index 55c6afedc879..249db1987764 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -19,7 +19,6 @@
#include "xfs_fs.h"
#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
@@ -65,7 +64,8 @@ STATIC int
xfs_qm_dquot_walk(
struct xfs_mount *mp,
int type,
- int (*execute)(struct xfs_dquot *dqp))
+ int (*execute)(struct xfs_dquot *dqp, void *data),
+ void *data)
{
struct xfs_quotainfo *qi = mp->m_quotainfo;
struct radix_tree_root *tree = XFS_DQUOT_TREE(qi, type);
@@ -97,7 +97,7 @@ restart:
next_index = be32_to_cpu(dqp->q_core.d_id) + 1;
- error = execute(batch[i]);
+ error = execute(batch[i], data);
if (error == EAGAIN) {
skipped++;
continue;
@@ -129,7 +129,8 @@ restart:
*/
STATIC int
xfs_qm_dqpurge(
- struct xfs_dquot *dqp)
+ struct xfs_dquot *dqp,
+ void *data)
{
struct xfs_mount *mp = dqp->q_mount;
struct xfs_quotainfo *qi = mp->m_quotainfo;
@@ -153,21 +154,7 @@ xfs_qm_dqpurge(
dqp->dq_flags |= XFS_DQ_FREEING;
- /*
- * If we're turning off quotas, we have to make sure that, for
- * example, we don't delete quota disk blocks while dquots are
- * in the process of getting written to those disk blocks.
- * This dquot might well be on AIL, and we can't leave it there
- * if we're turning off quotas. Basically, we need this flush
- * lock, and are willing to block on it.
- */
- if (!xfs_dqflock_nowait(dqp)) {
- /*
- * Block on the flush lock after nudging dquot buffer,
- * if it is incore.
- */
- xfs_dqflock_pushbuf_wait(dqp);
- }
+ xfs_dqflock(dqp);
/*
* If we are turning this type of quotas off, we don't care
@@ -175,16 +162,21 @@ xfs_qm_dqpurge(
* we're unmounting, we do care, so we flush it and wait.
*/
if (XFS_DQ_IS_DIRTY(dqp)) {
- int error;
+ struct xfs_buf *bp = NULL;
+ int error;
/*
* We don't care about getting disk errors here. We need
* to purge this dquot anyway, so we go ahead regardless.
*/
- error = xfs_qm_dqflush(dqp, SYNC_WAIT);
- if (error)
+ error = xfs_qm_dqflush(dqp, &bp);
+ if (error) {
xfs_warn(mp, "%s: dquot %p flush failed",
__func__, dqp);
+ } else {
+ error = xfs_bwrite(bp);
+ xfs_buf_relse(bp);
+ }
xfs_dqflock(dqp);
}
@@ -226,11 +218,11 @@ xfs_qm_dqpurge_all(
uint flags)
{
if (flags & XFS_QMOPT_UQUOTA)
- xfs_qm_dquot_walk(mp, XFS_DQ_USER, xfs_qm_dqpurge);
+ xfs_qm_dquot_walk(mp, XFS_DQ_USER, xfs_qm_dqpurge, NULL);
if (flags & XFS_QMOPT_GQUOTA)
- xfs_qm_dquot_walk(mp, XFS_DQ_GROUP, xfs_qm_dqpurge);
+ xfs_qm_dquot_walk(mp, XFS_DQ_GROUP, xfs_qm_dqpurge, NULL);
if (flags & XFS_QMOPT_PQUOTA)
- xfs_qm_dquot_walk(mp, XFS_DQ_PROJ, xfs_qm_dqpurge);
+ xfs_qm_dquot_walk(mp, XFS_DQ_PROJ, xfs_qm_dqpurge, NULL);
}
/*
@@ -483,6 +475,23 @@ done:
xfs_dqunlock(udq);
}
+static bool
+xfs_qm_need_dqattach(
+ struct xfs_inode *ip)
+{
+ struct xfs_mount *mp = ip->i_mount;
+
+ if (!XFS_IS_QUOTA_RUNNING(mp))
+ return false;
+ if (!XFS_IS_QUOTA_ON(mp))
+ return false;
+ if (!XFS_NOT_DQATTACHED(mp, ip))
+ return false;
+ if (ip->i_ino == mp->m_sb.sb_uquotino ||
+ ip->i_ino == mp->m_sb.sb_gquotino)
+ return false;
+ return true;
+}
/*
* Given a locked inode, attach dquot(s) to it, taking U/G/P-QUOTAON
@@ -500,11 +509,7 @@ xfs_qm_dqattach_locked(
uint nquotas = 0;
int error = 0;
- if (!XFS_IS_QUOTA_RUNNING(mp) ||
- !XFS_IS_QUOTA_ON(mp) ||
- !XFS_NOT_DQATTACHED(mp, ip) ||
- ip->i_ino == mp->m_sb.sb_uquotino ||
- ip->i_ino == mp->m_sb.sb_gquotino)
+ if (!xfs_qm_need_dqattach(ip))
return 0;
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
@@ -575,6 +580,9 @@ xfs_qm_dqattach(
{
int error;
+ if (!xfs_qm_need_dqattach(ip))
+ return 0;
+
xfs_ilock(ip, XFS_ILOCK_EXCL);
error = xfs_qm_dqattach_locked(ip, flags);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
@@ -855,15 +863,16 @@ xfs_qm_reset_dqcounts(
STATIC int
xfs_qm_dqiter_bufs(
- xfs_mount_t *mp,
- xfs_dqid_t firstid,
- xfs_fsblock_t bno,
- xfs_filblks_t blkcnt,
- uint flags)
+ struct xfs_mount *mp,
+ xfs_dqid_t firstid,
+ xfs_fsblock_t bno,
+ xfs_filblks_t blkcnt,
+ uint flags,
+ struct list_head *buffer_list)
{
- xfs_buf_t *bp;
- int error;
- int type;
+ struct xfs_buf *bp;
+ int error;
+ int type;
ASSERT(blkcnt > 0);
type = flags & XFS_QMOPT_UQUOTA ? XFS_DQ_USER :
@@ -887,7 +896,7 @@ xfs_qm_dqiter_bufs(
break;
xfs_qm_reset_dqcounts(mp, bp, firstid, type);
- xfs_buf_delwri_queue(bp);
+ xfs_buf_delwri_queue(bp, buffer_list);
xfs_buf_relse(bp);
/*
* goto the next block.
@@ -895,6 +904,7 @@ xfs_qm_dqiter_bufs(
bno++;
firstid += mp->m_quotainfo->qi_dqperchunk;
}
+
return error;
}
@@ -904,11 +914,12 @@ xfs_qm_dqiter_bufs(
*/
STATIC int
xfs_qm_dqiterate(
- xfs_mount_t *mp,
- xfs_inode_t *qip,
- uint flags)
+ struct xfs_mount *mp,
+ struct xfs_inode *qip,
+ uint flags,
+ struct list_head *buffer_list)
{
- xfs_bmbt_irec_t *map;
+ struct xfs_bmbt_irec *map;
int i, nmaps; /* number of map entries */
int error; /* return value */
xfs_fileoff_t lblkno;
@@ -975,21 +986,17 @@ xfs_qm_dqiterate(
* Iterate thru all the blks in the extent and
* reset the counters of all the dquots inside them.
*/
- if ((error = xfs_qm_dqiter_bufs(mp,
- firstid,
- map[i].br_startblock,
- map[i].br_blockcount,
- flags))) {
- break;
- }
+ error = xfs_qm_dqiter_bufs(mp, firstid,
+ map[i].br_startblock,
+ map[i].br_blockcount,
+ flags, buffer_list);
+ if (error)
+ goto out;
}
-
- if (error)
- break;
} while (nmaps > 0);
+out:
kmem_free(map);
-
return error;
}
@@ -1182,8 +1189,11 @@ error0:
STATIC int
xfs_qm_flush_one(
- struct xfs_dquot *dqp)
+ struct xfs_dquot *dqp,
+ void *data)
{
+ struct list_head *buffer_list = data;
+ struct xfs_buf *bp = NULL;
int error = 0;
xfs_dqlock(dqp);
@@ -1192,11 +1202,13 @@ xfs_qm_flush_one(
if (!XFS_DQ_IS_DIRTY(dqp))
goto out_unlock;
- if (!xfs_dqflock_nowait(dqp))
- xfs_dqflock_pushbuf_wait(dqp);
-
- error = xfs_qm_dqflush(dqp, 0);
+ xfs_dqflock(dqp);
+ error = xfs_qm_dqflush(dqp, &bp);
+ if (error)
+ goto out_unlock;
+ xfs_buf_delwri_queue(bp, buffer_list);
+ xfs_buf_relse(bp);
out_unlock:
xfs_dqunlock(dqp);
return error;
@@ -1215,6 +1227,7 @@ xfs_qm_quotacheck(
size_t structsz;
xfs_inode_t *uip, *gip;
uint flags;
+ LIST_HEAD (buffer_list);
count = INT_MAX;
structsz = 1;
@@ -1233,7 +1246,8 @@ xfs_qm_quotacheck(
*/
uip = mp->m_quotainfo->qi_uquotaip;
if (uip) {
- error = xfs_qm_dqiterate(mp, uip, XFS_QMOPT_UQUOTA);
+ error = xfs_qm_dqiterate(mp, uip, XFS_QMOPT_UQUOTA,
+ &buffer_list);
if (error)
goto error_return;
flags |= XFS_UQUOTA_CHKD;
@@ -1242,7 +1256,8 @@ xfs_qm_quotacheck(
gip = mp->m_quotainfo->qi_gquotaip;
if (gip) {
error = xfs_qm_dqiterate(mp, gip, XFS_IS_GQUOTA_ON(mp) ?
- XFS_QMOPT_GQUOTA : XFS_QMOPT_PQUOTA);
+ XFS_QMOPT_GQUOTA : XFS_QMOPT_PQUOTA,
+ &buffer_list);
if (error)
goto error_return;
flags |= XFS_OQUOTA_CHKD;
@@ -1265,19 +1280,27 @@ xfs_qm_quotacheck(
* We've made all the changes that we need to make incore. Flush them
* down to disk buffers if everything was updated successfully.
*/
- if (XFS_IS_UQUOTA_ON(mp))
- error = xfs_qm_dquot_walk(mp, XFS_DQ_USER, xfs_qm_flush_one);
+ if (XFS_IS_UQUOTA_ON(mp)) {
+ error = xfs_qm_dquot_walk(mp, XFS_DQ_USER, xfs_qm_flush_one,
+ &buffer_list);
+ }
if (XFS_IS_GQUOTA_ON(mp)) {
- error2 = xfs_qm_dquot_walk(mp, XFS_DQ_GROUP, xfs_qm_flush_one);
+ error2 = xfs_qm_dquot_walk(mp, XFS_DQ_GROUP, xfs_qm_flush_one,
+ &buffer_list);
if (!error)
error = error2;
}
if (XFS_IS_PQUOTA_ON(mp)) {
- error2 = xfs_qm_dquot_walk(mp, XFS_DQ_PROJ, xfs_qm_flush_one);
+ error2 = xfs_qm_dquot_walk(mp, XFS_DQ_PROJ, xfs_qm_flush_one,
+ &buffer_list);
if (!error)
error = error2;
}
+ error2 = xfs_buf_delwri_submit(&buffer_list);
+ if (!error)
+ error = error2;
+
/*
* We can get this error if we couldn't do a dquot allocation inside
* xfs_qm_dqusage_adjust (via bulkstat). We don't care about the
@@ -1291,15 +1314,6 @@ xfs_qm_quotacheck(
}
/*
- * We didn't log anything, because if we crashed, we'll have to
- * start the quotacheck from scratch anyway. However, we must make
- * sure that our dquot changes are secure before we put the
- * quotacheck'd stamp on the superblock. So, here we do a synchronous
- * flush.
- */
- xfs_flush_buftarg(mp->m_ddev_targp, 1);
-
- /*
* If one type of quotas is off, then it will lose its
* quotachecked status, since we won't be doing accounting for
* that type anymore.
@@ -1308,6 +1322,13 @@ xfs_qm_quotacheck(
mp->m_qflags |= flags;
error_return:
+ while (!list_empty(&buffer_list)) {
+ struct xfs_buf *bp =
+ list_first_entry(&buffer_list, struct xfs_buf, b_list);
+ list_del_init(&bp->b_list);
+ xfs_buf_relse(bp);
+ }
+
if (error) {
xfs_warn(mp,
"Quotacheck: Unsuccessful (Error %d): Disabling quotas.",
@@ -1424,6 +1445,7 @@ xfs_qm_dqfree_one(
STATIC void
xfs_qm_dqreclaim_one(
struct xfs_dquot *dqp,
+ struct list_head *buffer_list,
struct list_head *dispose_list)
{
struct xfs_mount *mp = dqp->q_mount;
@@ -1456,25 +1478,20 @@ xfs_qm_dqreclaim_one(
if (!xfs_dqflock_nowait(dqp))
goto out_busy;
- /*
- * We have the flush lock so we know that this is not in the
- * process of being flushed. So, if this is dirty, flush it
- * DELWRI so that we don't get a freelist infested with
- * dirty dquots.
- */
if (XFS_DQ_IS_DIRTY(dqp)) {
+ struct xfs_buf *bp = NULL;
+
trace_xfs_dqreclaim_dirty(dqp);
- /*
- * We flush it delayed write, so don't bother releasing the
- * freelist lock.
- */
- error = xfs_qm_dqflush(dqp, 0);
+ error = xfs_qm_dqflush(dqp, &bp);
if (error) {
xfs_warn(mp, "%s: dquot %p flush failed",
__func__, dqp);
+ goto out_busy;
}
+ xfs_buf_delwri_queue(bp, buffer_list);
+ xfs_buf_relse(bp);
/*
* Give the dquot another try on the freelist, as the
* flushing will take some time.
@@ -1518,8 +1535,10 @@ xfs_qm_shake(
struct xfs_quotainfo *qi =
container_of(shrink, struct xfs_quotainfo, qi_shrinker);
int nr_to_scan = sc->nr_to_scan;
+ LIST_HEAD (buffer_list);
LIST_HEAD (dispose_list);
struct xfs_dquot *dqp;
+ int error;
if ((sc->gfp_mask & (__GFP_FS|__GFP_WAIT)) != (__GFP_FS|__GFP_WAIT))
return 0;
@@ -1532,15 +1551,20 @@ xfs_qm_shake(
break;
dqp = list_first_entry(&qi->qi_lru_list, struct xfs_dquot,
q_lru);
- xfs_qm_dqreclaim_one(dqp, &dispose_list);
+ xfs_qm_dqreclaim_one(dqp, &buffer_list, &dispose_list);
}
mutex_unlock(&qi->qi_lru_lock);
+ error = xfs_buf_delwri_submit(&buffer_list);
+ if (error)
+ xfs_warn(NULL, "%s: dquot reclaim failed", __func__);
+
while (!list_empty(&dispose_list)) {
dqp = list_first_entry(&dispose_list, struct xfs_dquot, q_lru);
list_del_init(&dqp->q_lru);
xfs_qm_dqfree_one(dqp);
}
+
out:
return (qi->qi_lru_count / 100) * sysctl_vfs_cache_pressure;
}
diff --git a/fs/xfs/xfs_qm_bhv.c b/fs/xfs/xfs_qm_bhv.c
index e6986b5d80d8..6b39115bf145 100644
--- a/fs/xfs/xfs_qm_bhv.c
+++ b/fs/xfs/xfs_qm_bhv.c
@@ -17,9 +17,7 @@
*/
#include "xfs.h"
#include "xfs_fs.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index c4f396e437a8..858a3b186110 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -22,7 +22,6 @@
#include "xfs_fs.h"
#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
diff --git a/fs/xfs/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
index 7e76f537abb7..fed504fc2999 100644
--- a/fs/xfs/xfs_quotaops.c
+++ b/fs/xfs/xfs_quotaops.c
@@ -17,7 +17,6 @@
*/
#include "xfs.h"
#include "xfs_sb.h"
-#include "xfs_inum.h"
#include "xfs_log.h"
#include "xfs_ag.h"
#include "xfs_mount.h"
diff --git a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c
index e44ef7ee8ce8..30ff5f401d28 100644
--- a/fs/xfs/xfs_rename.c
+++ b/fs/xfs/xfs_rename.c
@@ -19,7 +19,6 @@
#include "xfs_fs.h"
#include "xfs_types.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c
index ca4f31534a0a..92d4331cd4f1 100644
--- a/fs/xfs/xfs_rtalloc.c
+++ b/fs/xfs/xfs_rtalloc.c
@@ -20,7 +20,6 @@
#include "xfs_types.h"
#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
@@ -34,7 +33,6 @@
#include "xfs_rtalloc.h"
#include "xfs_fsops.h"
#include "xfs_error.h"
-#include "xfs_rw.h"
#include "xfs_inode_item.h"
#include "xfs_trans_space.h"
#include "xfs_utils.h"
@@ -1872,9 +1870,9 @@ xfs_growfs_rt(
/*
* Read in the last block of the device, make sure it exists.
*/
- bp = xfs_buf_read_uncached(mp, mp->m_rtdev_targp,
+ bp = xfs_buf_read_uncached(mp->m_rtdev_targp,
XFS_FSB_TO_BB(mp, nrblocks - 1),
- XFS_FSB_TO_B(mp, 1), 0);
+ XFS_FSB_TO_BB(mp, 1), 0);
if (!bp)
return EIO;
xfs_buf_relse(bp);
@@ -2219,9 +2217,9 @@ xfs_rtmount_init(
(unsigned long long) mp->m_sb.sb_rblocks);
return XFS_ERROR(EFBIG);
}
- bp = xfs_buf_read_uncached(mp, mp->m_rtdev_targp,
+ bp = xfs_buf_read_uncached(mp->m_rtdev_targp,
d - XFS_FSB_TO_BB(mp, 1),
- XFS_FSB_TO_B(mp, 1), 0);
+ XFS_FSB_TO_BB(mp, 1), 0);
if (!bp) {
xfs_warn(mp, "realtime device size check failed");
return EIO;
diff --git a/fs/xfs/xfs_rw.c b/fs/xfs/xfs_rw.c
deleted file mode 100644
index 597d044a09a1..000000000000
--- a/fs/xfs/xfs_rw.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (c) 2000-2006 Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include "xfs.h"
-#include "xfs_fs.h"
-#include "xfs_types.h"
-#include "xfs_bit.h"
-#include "xfs_log.h"
-#include "xfs_inum.h"
-#include "xfs_trans.h"
-#include "xfs_sb.h"
-#include "xfs_ag.h"
-#include "xfs_mount.h"
-#include "xfs_bmap_btree.h"
-#include "xfs_dinode.h"
-#include "xfs_inode.h"
-#include "xfs_error.h"
-#include "xfs_rw.h"
-
-/*
- * Force a shutdown of the filesystem instantly while keeping
- * the filesystem consistent. We don't do an unmount here; just shutdown
- * the shop, make sure that absolutely nothing persistent happens to
- * this filesystem after this point.
- */
-void
-xfs_do_force_shutdown(
- xfs_mount_t *mp,
- int flags,
- char *fname,
- int lnnum)
-{
- int logerror;
-
- logerror = flags & SHUTDOWN_LOG_IO_ERROR;
-
- if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
- xfs_notice(mp,
- "%s(0x%x) called from line %d of file %s. Return address = 0x%p",
- __func__, flags, lnnum, fname, __return_address);
- }
- /*
- * No need to duplicate efforts.
- */
- if (XFS_FORCED_SHUTDOWN(mp) && !logerror)
- return;
-
- /*
- * This flags XFS_MOUNT_FS_SHUTDOWN, makes sure that we don't
- * queue up anybody new on the log reservations, and wakes up
- * everybody who's sleeping on log reservations to tell them
- * the bad news.
- */
- if (xfs_log_force_umount(mp, logerror))
- return;
-
- if (flags & SHUTDOWN_CORRUPT_INCORE) {
- xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_CORRUPT,
- "Corruption of in-memory data detected. Shutting down filesystem");
- if (XFS_ERRLEVEL_HIGH <= xfs_error_level)
- xfs_stack_trace();
- } else if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
- if (logerror) {
- xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_LOGERROR,
- "Log I/O Error Detected. Shutting down filesystem");
- } else if (flags & SHUTDOWN_DEVICE_REQ) {
- xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR,
- "All device paths lost. Shutting down filesystem");
- } else if (!(flags & SHUTDOWN_REMOTE_REQ)) {
- xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR,
- "I/O Error Detected. Shutting down filesystem");
- }
- }
- if (!(flags & SHUTDOWN_FORCE_UMOUNT)) {
- xfs_alert(mp,
- "Please umount the filesystem and rectify the problem(s)");
- }
-}
-
-/*
- * This isn't an absolute requirement, but it is
- * just a good idea to call xfs_read_buf instead of
- * directly doing a read_buf call. For one, we shouldn't
- * be doing this disk read if we are in SHUTDOWN state anyway,
- * so this stops that from happening. Secondly, this does all
- * the error checking stuff and the brelse if appropriate for
- * the caller, so the code can be a little leaner.
- */
-
-int
-xfs_read_buf(
- struct xfs_mount *mp,
- xfs_buftarg_t *target,
- xfs_daddr_t blkno,
- int len,
- uint flags,
- xfs_buf_t **bpp)
-{
- xfs_buf_t *bp;
- int error;
-
- if (!flags)
- flags = XBF_LOCK | XBF_MAPPED;
-
- bp = xfs_buf_read(target, blkno, len, flags);
- if (!bp)
- return XFS_ERROR(EIO);
- error = bp->b_error;
- if (!error && !XFS_FORCED_SHUTDOWN(mp)) {
- *bpp = bp;
- } else {
- *bpp = NULL;
- if (error) {
- xfs_buf_ioerror_alert(bp, __func__);
- } else {
- error = XFS_ERROR(EIO);
- }
- if (bp) {
- XFS_BUF_UNDONE(bp);
- xfs_buf_stale(bp);
- /*
- * brelse clears B_ERROR and b_error
- */
- xfs_buf_relse(bp);
- }
- }
- return (error);
-}
-
-/*
- * helper function to extract extent size hint from inode
- */
-xfs_extlen_t
-xfs_get_extsz_hint(
- struct xfs_inode *ip)
-{
- if ((ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE) && ip->i_d.di_extsize)
- return ip->i_d.di_extsize;
- if (XFS_IS_REALTIME_INODE(ip))
- return ip->i_mount->m_sb.sb_rextsize;
- return 0;
-}
diff --git a/fs/xfs/xfs_rw.h b/fs/xfs/xfs_rw.h
deleted file mode 100644
index bbdb9ad6a4ba..000000000000
--- a/fs/xfs/xfs_rw.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2000-2006 Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#ifndef __XFS_RW_H__
-#define __XFS_RW_H__
-
-struct xfs_buf;
-struct xfs_inode;
-struct xfs_mount;
-
-/*
- * Convert the given file system block to a disk block.
- * We have to treat it differently based on whether the
- * file is a real time file or not, because the bmap code
- * does.
- */
-static inline xfs_daddr_t
-xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb)
-{
- return (XFS_IS_REALTIME_INODE(ip) ? \
- (xfs_daddr_t)XFS_FSB_TO_BB((ip)->i_mount, (fsb)) : \
- XFS_FSB_TO_DADDR((ip)->i_mount, (fsb)));
-}
-
-/*
- * Prototypes for functions in xfs_rw.c.
- */
-extern int xfs_read_buf(struct xfs_mount *mp, xfs_buftarg_t *btp,
- xfs_daddr_t blkno, int len, uint flags,
- struct xfs_buf **bpp);
-extern xfs_extlen_t xfs_get_extsz_hint(struct xfs_inode *ip);
-
-#endif /* __XFS_RW_H__ */
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index dab9a5f6dfd6..2fcfd5b0b046 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -17,7 +17,6 @@
*/
#include "xfs.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
#include "xfs_inum.h"
#include "xfs_trans.h"
@@ -622,7 +621,7 @@ void
xfs_blkdev_issue_flush(
xfs_buftarg_t *buftarg)
{
- blkdev_issue_flush(buftarg->bt_bdev, GFP_KERNEL, NULL);
+ blkdev_issue_flush(buftarg->bt_bdev, GFP_NOFS, NULL);
}
STATIC void
@@ -773,8 +772,14 @@ xfs_init_mount_workqueues(
if (!mp->m_unwritten_workqueue)
goto out_destroy_data_iodone_queue;
+ mp->m_cil_workqueue = alloc_workqueue("xfs-cil/%s",
+ WQ_MEM_RECLAIM, 0, mp->m_fsname);
+ if (!mp->m_cil_workqueue)
+ goto out_destroy_unwritten;
return 0;
+out_destroy_unwritten:
+ destroy_workqueue(mp->m_unwritten_workqueue);
out_destroy_data_iodone_queue:
destroy_workqueue(mp->m_data_workqueue);
out:
@@ -785,6 +790,7 @@ STATIC void
xfs_destroy_mount_workqueues(
struct xfs_mount *mp)
{
+ destroy_workqueue(mp->m_cil_workqueue);
destroy_workqueue(mp->m_data_workqueue);
destroy_workqueue(mp->m_unwritten_workqueue);
}
@@ -981,18 +987,9 @@ xfs_fs_put_super(
{
struct xfs_mount *mp = XFS_M(sb);
- xfs_syncd_stop(mp);
-
- /*
- * Blow away any referenced inode in the filestreams cache.
- * This can and will cause log traffic as inodes go inactive
- * here.
- */
xfs_filestream_unmount(mp);
-
- xfs_flush_buftarg(mp->m_ddev_targp, 1);
-
xfs_unmountfs(mp);
+ xfs_syncd_stop(mp);
xfs_freesb(mp);
xfs_icsb_destroy_counters(mp);
xfs_destroy_mount_workqueues(mp);
@@ -1072,7 +1069,7 @@ xfs_fs_statfs(
spin_unlock(&mp->m_sb_lock);
- if ((ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) ||
+ if ((ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
((mp->m_qflags & (XFS_PQUOTA_ACCT|XFS_OQUOTA_ENFD))) ==
(XFS_PQUOTA_ACCT|XFS_OQUOTA_ENFD))
xfs_qm_statvfs(ip, statp);
@@ -1362,31 +1359,32 @@ xfs_fs_fill_super(
sb->s_time_gran = 1;
set_posix_acl_flag(sb);
- error = xfs_mountfs(mp);
+ error = xfs_syncd_init(mp);
if (error)
goto out_filestream_unmount;
- error = xfs_syncd_init(mp);
+ error = xfs_mountfs(mp);
if (error)
- goto out_unmount;
+ goto out_syncd_stop;
root = igrab(VFS_I(mp->m_rootip));
if (!root) {
error = ENOENT;
- goto out_syncd_stop;
+ goto out_unmount;
}
if (is_bad_inode(root)) {
error = EINVAL;
- goto out_syncd_stop;
+ goto out_unmount;
}
sb->s_root = d_make_root(root);
if (!sb->s_root) {
error = ENOMEM;
- goto out_syncd_stop;
+ goto out_unmount;
}
return 0;
-
+ out_syncd_stop:
+ xfs_syncd_stop(mp);
out_filestream_unmount:
xfs_filestream_unmount(mp);
out_free_sb:
@@ -1403,19 +1401,10 @@ out_destroy_workqueues:
out:
return -error;
- out_syncd_stop:
- xfs_syncd_stop(mp);
out_unmount:
- /*
- * Blow away any referenced inode in the filestreams cache.
- * This can and will cause log traffic as inodes go inactive
- * here.
- */
xfs_filestream_unmount(mp);
-
- xfs_flush_buftarg(mp->m_ddev_targp, 1);
-
xfs_unmountfs(mp);
+ xfs_syncd_stop(mp);
goto out_free_sb;
}
diff --git a/fs/xfs/xfs_sync.c b/fs/xfs/xfs_sync.c
index 205ebcb34d9e..c9d3409c5ca3 100644
--- a/fs/xfs/xfs_sync.c
+++ b/fs/xfs/xfs_sync.c
@@ -18,7 +18,6 @@
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_types.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
#include "xfs_inum.h"
#include "xfs_trans.h"
@@ -241,45 +240,6 @@ xfs_sync_inode_data(
return error;
}
-STATIC int
-xfs_sync_inode_attr(
- struct xfs_inode *ip,
- struct xfs_perag *pag,
- int flags)
-{
- int error = 0;
-
- xfs_ilock(ip, XFS_ILOCK_SHARED);
- if (xfs_inode_clean(ip))
- goto out_unlock;
- if (!xfs_iflock_nowait(ip)) {
- if (!(flags & SYNC_WAIT))
- goto out_unlock;
- xfs_iflock(ip);
- }
-
- if (xfs_inode_clean(ip)) {
- xfs_ifunlock(ip);
- goto out_unlock;
- }
-
- error = xfs_iflush(ip, flags);
-
- /*
- * We don't want to try again on non-blocking flushes that can't run
- * again immediately. If an inode really must be written, then that's
- * what the SYNC_WAIT flag is for.
- */
- if (error == EAGAIN) {
- ASSERT(!(flags & SYNC_WAIT));
- error = 0;
- }
-
- out_unlock:
- xfs_iunlock(ip, XFS_ILOCK_SHARED);
- return error;
-}
-
/*
* Write out pagecache data for the whole filesystem.
*/
@@ -300,19 +260,6 @@ xfs_sync_data(
return 0;
}
-/*
- * Write out inode metadata (attributes) for the whole filesystem.
- */
-STATIC int
-xfs_sync_attr(
- struct xfs_mount *mp,
- int flags)
-{
- ASSERT((flags & ~SYNC_WAIT) == 0);
-
- return xfs_inode_ag_iterator(mp, xfs_sync_inode_attr, flags);
-}
-
STATIC int
xfs_sync_fsdata(
struct xfs_mount *mp)
@@ -350,7 +297,7 @@ xfs_sync_fsdata(
* First stage of freeze - no writers will make progress now we are here,
* so we flush delwri and delalloc buffers here, then wait for all I/O to
* complete. Data is frozen at that point. Metadata is not frozen,
- * transactions can still occur here so don't bother flushing the buftarg
+ * transactions can still occur here so don't bother emptying the AIL
* because it'll just get dirty again.
*/
int
@@ -365,47 +312,13 @@ xfs_quiesce_data(
/* write superblock and hoover up shutdown errors */
error = xfs_sync_fsdata(mp);
- /* make sure all delwri buffers are written out */
- xfs_flush_buftarg(mp->m_ddev_targp, 1);
-
/* mark the log as covered if needed */
if (xfs_log_need_covered(mp))
error2 = xfs_fs_log_dummy(mp);
- /* flush data-only devices */
- if (mp->m_rtdev_targp)
- xfs_flush_buftarg(mp->m_rtdev_targp, 1);
-
return error ? error : error2;
}
-STATIC void
-xfs_quiesce_fs(
- struct xfs_mount *mp)
-{
- int count = 0, pincount;
-
- xfs_reclaim_inodes(mp, 0);
- xfs_flush_buftarg(mp->m_ddev_targp, 0);
-
- /*
- * This loop must run at least twice. The first instance of the loop
- * will flush most meta data but that will generate more meta data
- * (typically directory updates). Which then must be flushed and
- * logged before we can write the unmount record. We also so sync
- * reclaim of inodes to catch any that the above delwri flush skipped.
- */
- do {
- xfs_reclaim_inodes(mp, SYNC_WAIT);
- xfs_sync_attr(mp, SYNC_WAIT);
- pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1);
- if (!pincount) {
- delay(50);
- count++;
- }
- } while (count < 2);
-}
-
/*
* Second stage of a quiesce. The data is already synced, now we have to take
* care of the metadata. New transactions are already blocked, so we need to
@@ -421,8 +334,12 @@ xfs_quiesce_attr(
while (atomic_read(&mp->m_active_trans) > 0)
delay(100);
- /* flush inodes and push all remaining buffers out to disk */
- xfs_quiesce_fs(mp);
+ /* reclaim inodes to do any IO before the freeze completes */
+ xfs_reclaim_inodes(mp, 0);
+ xfs_reclaim_inodes(mp, SYNC_WAIT);
+
+ /* flush all pending changes from the AIL */
+ xfs_ail_push_all_sync(mp->m_ail);
/*
* Just warn here till VFS can correctly support
@@ -436,7 +353,12 @@ xfs_quiesce_attr(
xfs_warn(mp, "xfs_attr_quiesce: failed to log sb changes. "
"Frozen image may not be consistent.");
xfs_log_unmount_write(mp);
- xfs_unmountfs_writesb(mp);
+
+ /*
+ * At this point we might have modified the superblock again and thus
+ * added an item to the AIL, thus flush it again.
+ */
+ xfs_ail_push_all_sync(mp->m_ail);
}
static void
@@ -460,16 +382,27 @@ xfs_sync_worker(
struct xfs_mount, m_sync_work);
int error;
- if (!(mp->m_flags & XFS_MOUNT_RDONLY)) {
- /* dgc: errors ignored here */
- if (mp->m_super->s_frozen == SB_UNFROZEN &&
- xfs_log_need_covered(mp))
- error = xfs_fs_log_dummy(mp);
- else
- xfs_log_force(mp, 0);
-
- /* start pushing all the metadata that is currently dirty */
- xfs_ail_push_all(mp->m_ail);
+ /*
+ * We shouldn't write/force the log if we are in the mount/unmount
+ * process or on a read only filesystem. The workqueue still needs to be
+ * active in both cases, however, because it is used for inode reclaim
+ * during these times. Use the s_umount semaphore to provide exclusion
+ * with unmount.
+ */
+ if (down_read_trylock(&mp->m_super->s_umount)) {
+ if (!(mp->m_flags & XFS_MOUNT_RDONLY)) {
+ /* dgc: errors ignored here */
+ if (mp->m_super->s_frozen == SB_UNFROZEN &&
+ xfs_log_need_covered(mp))
+ error = xfs_fs_log_dummy(mp);
+ else
+ xfs_log_force(mp, 0);
+
+ /* start pushing all the metadata that is currently
+ * dirty */
+ xfs_ail_push_all(mp->m_ail);
+ }
+ up_read(&mp->m_super->s_umount);
}
/* queue us up again */
@@ -488,14 +421,6 @@ xfs_syncd_queue_reclaim(
struct xfs_mount *mp)
{
- /*
- * We can have inodes enter reclaim after we've shut down the syncd
- * workqueue during unmount, so don't allow reclaim work to be queued
- * during unmount.
- */
- if (!(mp->m_super->s_flags & MS_ACTIVE))
- return;
-
rcu_read_lock();
if (radix_tree_tagged(&mp->m_perag_tree, XFS_ICI_RECLAIM_TAG)) {
queue_delayed_work(xfs_syncd_wq, &mp->m_reclaim_work,
@@ -564,7 +489,6 @@ xfs_syncd_init(
INIT_DELAYED_WORK(&mp->m_reclaim_work, xfs_reclaim_worker);
xfs_syncd_queue_sync(mp);
- xfs_syncd_queue_reclaim(mp);
return 0;
}
@@ -702,11 +626,8 @@ xfs_reclaim_inode_grab(
}
/*
- * Inodes in different states need to be treated differently, and the return
- * value of xfs_iflush is not sufficient to get this right. The following table
- * lists the inode states and the reclaim actions necessary for non-blocking
- * reclaim:
- *
+ * Inodes in different states need to be treated differently. The following
+ * table lists the inode states and the reclaim actions necessary:
*
* inode state iflush ret required action
* --------------- ---------- ---------------
@@ -716,39 +637,31 @@ xfs_reclaim_inode_grab(
* stale, unpinned 0 reclaim
* clean, pinned(*) 0 requeue
* stale, pinned EAGAIN requeue
- * dirty, delwri ok 0 requeue
- * dirty, delwri blocked EAGAIN requeue
- * dirty, sync flush 0 reclaim
+ * dirty, async - requeue
+ * dirty, sync 0 reclaim
*
* (*) dgc: I don't think the clean, pinned state is possible but it gets
* handled anyway given the order of checks implemented.
*
- * As can be seen from the table, the return value of xfs_iflush() is not
- * sufficient to correctly decide the reclaim action here. The checks in
- * xfs_iflush() might look like duplicates, but they are not.
- *
* Also, because we get the flush lock first, we know that any inode that has
* been flushed delwri has had the flush completed by the time we check that
- * the inode is clean. The clean inode check needs to be done before flushing
- * the inode delwri otherwise we would loop forever requeuing clean inodes as
- * we cannot tell apart a successful delwri flush and a clean inode from the
- * return value of xfs_iflush().
+ * the inode is clean.
*
- * Note that because the inode is flushed delayed write by background
- * writeback, the flush lock may already be held here and waiting on it can
- * result in very long latencies. Hence for sync reclaims, where we wait on the
- * flush lock, the caller should push out delayed write inodes first before
- * trying to reclaim them to minimise the amount of time spent waiting. For
- * background relaim, we just requeue the inode for the next pass.
+ * Note that because the inode is flushed delayed write by AIL pushing, the
+ * flush lock may already be held here and waiting on it can result in very
+ * long latencies. Hence for sync reclaims, where we wait on the flush lock,
+ * the caller should push the AIL first before trying to reclaim inodes to
+ * minimise the amount of time spent waiting. For background relaim, we only
+ * bother to reclaim clean inodes anyway.
*
* Hence the order of actions after gaining the locks should be:
* bad => reclaim
* shutdown => unpin and reclaim
- * pinned, delwri => requeue
+ * pinned, async => requeue
* pinned, sync => unpin
* stale => reclaim
* clean => reclaim
- * dirty, delwri => flush and requeue
+ * dirty, async => requeue
* dirty, sync => flush, wait and reclaim
*/
STATIC int
@@ -757,7 +670,8 @@ xfs_reclaim_inode(
struct xfs_perag *pag,
int sync_mode)
{
- int error;
+ struct xfs_buf *bp = NULL;
+ int error;
restart:
error = 0;
@@ -765,17 +679,6 @@ restart:
if (!xfs_iflock_nowait(ip)) {
if (!(sync_mode & SYNC_WAIT))
goto out;
-
- /*
- * If we only have a single dirty inode in a cluster there is
- * a fair chance that the AIL push may have pushed it into
- * the buffer, but xfsbufd won't touch it until 30 seconds
- * from now, and thus we will lock up here.
- *
- * Promote the inode buffer to the front of the delwri list
- * and wake up xfsbufd now.
- */
- xfs_promote_inode(ip);
xfs_iflock(ip);
}
@@ -783,13 +686,12 @@ restart:
goto reclaim;
if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
xfs_iunpin_wait(ip);
+ xfs_iflush_abort(ip, false);
goto reclaim;
}
if (xfs_ipincount(ip)) {
- if (!(sync_mode & SYNC_WAIT)) {
- xfs_ifunlock(ip);
- goto out;
- }
+ if (!(sync_mode & SYNC_WAIT))
+ goto out_ifunlock;
xfs_iunpin_wait(ip);
}
if (xfs_iflags_test(ip, XFS_ISTALE))
@@ -798,60 +700,42 @@ restart:
goto reclaim;
/*
+ * Never flush out dirty data during non-blocking reclaim, as it would
+ * just contend with AIL pushing trying to do the same job.
+ */
+ if (!(sync_mode & SYNC_WAIT))
+ goto out_ifunlock;
+
+ /*
* Now we have an inode that needs flushing.
*
- * We do a nonblocking flush here even if we are doing a SYNC_WAIT
- * reclaim as we can deadlock with inode cluster removal.
+ * Note that xfs_iflush will never block on the inode buffer lock, as
* xfs_ifree_cluster() can lock the inode buffer before it locks the
- * ip->i_lock, and we are doing the exact opposite here. As a result,
- * doing a blocking xfs_itobp() to get the cluster buffer will result
+ * ip->i_lock, and we are doing the exact opposite here. As a result,
+ * doing a blocking xfs_itobp() to get the cluster buffer would result
* in an ABBA deadlock with xfs_ifree_cluster().
*
* As xfs_ifree_cluser() must gather all inodes that are active in the
* cache to mark them stale, if we hit this case we don't actually want
* to do IO here - we want the inode marked stale so we can simply
- * reclaim it. Hence if we get an EAGAIN error on a SYNC_WAIT flush,
- * just unlock the inode, back off and try again. Hopefully the next
- * pass through will see the stale flag set on the inode.
+ * reclaim it. Hence if we get an EAGAIN error here, just unlock the
+ * inode, back off and try again. Hopefully the next pass through will
+ * see the stale flag set on the inode.
*/
- error = xfs_iflush(ip, SYNC_TRYLOCK | sync_mode);
- if (sync_mode & SYNC_WAIT) {
- if (error == EAGAIN) {
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
- /* backoff longer than in xfs_ifree_cluster */
- delay(2);
- goto restart;
- }
- xfs_iflock(ip);
- goto reclaim;
+ error = xfs_iflush(ip, &bp);
+ if (error == EAGAIN) {
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ /* backoff longer than in xfs_ifree_cluster */
+ delay(2);
+ goto restart;
}
- /*
- * When we have to flush an inode but don't have SYNC_WAIT set, we
- * flush the inode out using a delwri buffer and wait for the next
- * call into reclaim to find it in a clean state instead of waiting for
- * it now. We also don't return errors here - if the error is transient
- * then the next reclaim pass will flush the inode, and if the error
- * is permanent then the next sync reclaim will reclaim the inode and
- * pass on the error.
- */
- if (error && error != EAGAIN && !XFS_FORCED_SHUTDOWN(ip->i_mount)) {
- xfs_warn(ip->i_mount,
- "inode 0x%llx background reclaim flush failed with %d",
- (long long)ip->i_ino, error);
+ if (!error) {
+ error = xfs_bwrite(bp);
+ xfs_buf_relse(bp);
}
-out:
- xfs_iflags_clear(ip, XFS_IRECLAIM);
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
- /*
- * We could return EAGAIN here to make reclaim rescan the inode tree in
- * a short while. However, this just burns CPU time scanning the tree
- * waiting for IO to complete and xfssyncd never goes back to the idle
- * state. Instead, return 0 to let the next scheduled background reclaim
- * attempt to reclaim the inode again.
- */
- return 0;
+ xfs_iflock(ip);
reclaim:
xfs_ifunlock(ip);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
@@ -884,8 +768,21 @@ reclaim:
xfs_iunlock(ip, XFS_ILOCK_EXCL);
xfs_inode_free(ip);
-
return error;
+
+out_ifunlock:
+ xfs_ifunlock(ip);
+out:
+ xfs_iflags_clear(ip, XFS_IRECLAIM);
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ /*
+ * We could return EAGAIN here to make reclaim rescan the inode tree in
+ * a short while. However, this just burns CPU time scanning the tree
+ * waiting for IO to complete and xfssyncd never goes back to the idle
+ * state. Instead, return 0 to let the next scheduled background reclaim
+ * attempt to reclaim the inode again.
+ */
+ return 0;
}
/*
diff --git a/fs/xfs/xfs_trace.c b/fs/xfs/xfs_trace.c
index 9010ce885e6a..624bedd81357 100644
--- a/fs/xfs/xfs_trace.c
+++ b/fs/xfs/xfs_trace.c
@@ -18,9 +18,7 @@
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_types.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index 06838c42b2a0..7cf9d3529e51 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -281,7 +281,7 @@ DECLARE_EVENT_CLASS(xfs_buf_class,
TP_STRUCT__entry(
__field(dev_t, dev)
__field(xfs_daddr_t, bno)
- __field(size_t, buffer_length)
+ __field(int, nblks)
__field(int, hold)
__field(int, pincount)
__field(unsigned, lockval)
@@ -291,18 +291,18 @@ DECLARE_EVENT_CLASS(xfs_buf_class,
TP_fast_assign(
__entry->dev = bp->b_target->bt_dev;
__entry->bno = bp->b_bn;
- __entry->buffer_length = bp->b_buffer_length;
+ __entry->nblks = bp->b_length;
__entry->hold = atomic_read(&bp->b_hold);
__entry->pincount = atomic_read(&bp->b_pin_count);
__entry->lockval = bp->b_sema.count;
__entry->flags = bp->b_flags;
__entry->caller_ip = caller_ip;
),
- TP_printk("dev %d:%d bno 0x%llx len 0x%zx hold %d pincount %d "
+ TP_printk("dev %d:%d bno 0x%llx nblks 0x%x hold %d pincount %d "
"lock %d flags %s caller %pf",
MAJOR(__entry->dev), MINOR(__entry->dev),
(unsigned long long)__entry->bno,
- __entry->buffer_length,
+ __entry->nblks,
__entry->hold,
__entry->pincount,
__entry->lockval,
@@ -328,7 +328,7 @@ DEFINE_BUF_EVENT(xfs_buf_unlock);
DEFINE_BUF_EVENT(xfs_buf_iowait);
DEFINE_BUF_EVENT(xfs_buf_iowait_done);
DEFINE_BUF_EVENT(xfs_buf_delwri_queue);
-DEFINE_BUF_EVENT(xfs_buf_delwri_dequeue);
+DEFINE_BUF_EVENT(xfs_buf_delwri_queued);
DEFINE_BUF_EVENT(xfs_buf_delwri_split);
DEFINE_BUF_EVENT(xfs_buf_get_uncached);
DEFINE_BUF_EVENT(xfs_bdstrat_shut);
@@ -362,7 +362,7 @@ DECLARE_EVENT_CLASS(xfs_buf_flags_class,
TP_fast_assign(
__entry->dev = bp->b_target->bt_dev;
__entry->bno = bp->b_bn;
- __entry->buffer_length = bp->b_buffer_length;
+ __entry->buffer_length = BBTOB(bp->b_length);
__entry->flags = flags;
__entry->hold = atomic_read(&bp->b_hold);
__entry->pincount = atomic_read(&bp->b_pin_count);
@@ -406,7 +406,7 @@ TRACE_EVENT(xfs_buf_ioerror,
TP_fast_assign(
__entry->dev = bp->b_target->bt_dev;
__entry->bno = bp->b_bn;
- __entry->buffer_length = bp->b_buffer_length;
+ __entry->buffer_length = BBTOB(bp->b_length);
__entry->hold = atomic_read(&bp->b_hold);
__entry->pincount = atomic_read(&bp->b_pin_count);
__entry->lockval = bp->b_sema.count;
@@ -450,7 +450,7 @@ DECLARE_EVENT_CLASS(xfs_buf_item_class,
__entry->bli_recur = bip->bli_recur;
__entry->bli_refcount = atomic_read(&bip->bli_refcount);
__entry->buf_bno = bip->bli_buf->b_bn;
- __entry->buf_len = bip->bli_buf->b_buffer_length;
+ __entry->buf_len = BBTOB(bip->bli_buf->b_length);
__entry->buf_flags = bip->bli_buf->b_flags;
__entry->buf_hold = atomic_read(&bip->bli_buf->b_hold);
__entry->buf_pincount = atomic_read(&bip->bli_buf->b_pin_count);
@@ -486,12 +486,10 @@ DEFINE_BUF_ITEM_EVENT(xfs_buf_item_format_stale);
DEFINE_BUF_ITEM_EVENT(xfs_buf_item_pin);
DEFINE_BUF_ITEM_EVENT(xfs_buf_item_unpin);
DEFINE_BUF_ITEM_EVENT(xfs_buf_item_unpin_stale);
-DEFINE_BUF_ITEM_EVENT(xfs_buf_item_trylock);
DEFINE_BUF_ITEM_EVENT(xfs_buf_item_unlock);
DEFINE_BUF_ITEM_EVENT(xfs_buf_item_unlock_stale);
DEFINE_BUF_ITEM_EVENT(xfs_buf_item_committed);
DEFINE_BUF_ITEM_EVENT(xfs_buf_item_push);
-DEFINE_BUF_ITEM_EVENT(xfs_buf_item_pushbuf);
DEFINE_BUF_ITEM_EVENT(xfs_trans_get_buf);
DEFINE_BUF_ITEM_EVENT(xfs_trans_get_buf_recur);
DEFINE_BUF_ITEM_EVENT(xfs_trans_getsb);
@@ -876,15 +874,30 @@ DECLARE_EVENT_CLASS(xfs_log_item_class,
__print_flags(__entry->flags, "|", XFS_LI_FLAGS))
)
+TRACE_EVENT(xfs_log_force,
+ TP_PROTO(struct xfs_mount *mp, xfs_lsn_t lsn),
+ TP_ARGS(mp, lsn),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(xfs_lsn_t, lsn)
+ ),
+ TP_fast_assign(
+ __entry->dev = mp->m_super->s_dev;
+ __entry->lsn = lsn;
+ ),
+ TP_printk("dev %d:%d lsn 0x%llx",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __entry->lsn)
+)
+
#define DEFINE_LOG_ITEM_EVENT(name) \
DEFINE_EVENT(xfs_log_item_class, name, \
TP_PROTO(struct xfs_log_item *lip), \
TP_ARGS(lip))
DEFINE_LOG_ITEM_EVENT(xfs_ail_push);
-DEFINE_LOG_ITEM_EVENT(xfs_ail_pushbuf);
-DEFINE_LOG_ITEM_EVENT(xfs_ail_pushbuf_pinned);
DEFINE_LOG_ITEM_EVENT(xfs_ail_pinned);
DEFINE_LOG_ITEM_EVENT(xfs_ail_locked);
+DEFINE_LOG_ITEM_EVENT(xfs_ail_flushing);
DECLARE_EVENT_CLASS(xfs_file_class,
@@ -1145,7 +1158,7 @@ TRACE_EVENT(xfs_bunmap,
);
-DECLARE_EVENT_CLASS(xfs_busy_class,
+DECLARE_EVENT_CLASS(xfs_extent_busy_class,
TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno,
xfs_agblock_t agbno, xfs_extlen_t len),
TP_ARGS(mp, agno, agbno, len),
@@ -1168,17 +1181,17 @@ DECLARE_EVENT_CLASS(xfs_busy_class,
__entry->len)
);
#define DEFINE_BUSY_EVENT(name) \
-DEFINE_EVENT(xfs_busy_class, name, \
+DEFINE_EVENT(xfs_extent_busy_class, name, \
TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, \
xfs_agblock_t agbno, xfs_extlen_t len), \
TP_ARGS(mp, agno, agbno, len))
-DEFINE_BUSY_EVENT(xfs_alloc_busy);
-DEFINE_BUSY_EVENT(xfs_alloc_busy_enomem);
-DEFINE_BUSY_EVENT(xfs_alloc_busy_force);
-DEFINE_BUSY_EVENT(xfs_alloc_busy_reuse);
-DEFINE_BUSY_EVENT(xfs_alloc_busy_clear);
+DEFINE_BUSY_EVENT(xfs_extent_busy);
+DEFINE_BUSY_EVENT(xfs_extent_busy_enomem);
+DEFINE_BUSY_EVENT(xfs_extent_busy_force);
+DEFINE_BUSY_EVENT(xfs_extent_busy_reuse);
+DEFINE_BUSY_EVENT(xfs_extent_busy_clear);
-TRACE_EVENT(xfs_alloc_busy_trim,
+TRACE_EVENT(xfs_extent_busy_trim,
TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno,
xfs_agblock_t agbno, xfs_extlen_t len,
xfs_agblock_t tbno, xfs_extlen_t tlen),
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index 103b00c90004..cdf896fcbfa4 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -19,9 +19,7 @@
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_types.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
@@ -36,6 +34,7 @@
#include "xfs_btree.h"
#include "xfs_ialloc.h"
#include "xfs_alloc.h"
+#include "xfs_extent_busy.h"
#include "xfs_bmap.h"
#include "xfs_quota.h"
#include "xfs_trans_priv.h"
@@ -608,8 +607,8 @@ STATIC void
xfs_trans_free(
struct xfs_trans *tp)
{
- xfs_alloc_busy_sort(&tp->t_busy);
- xfs_alloc_busy_clear(tp->t_mountp, &tp->t_busy, false);
+ xfs_extent_busy_sort(&tp->t_busy);
+ xfs_extent_busy_clear(tp->t_mountp, &tp->t_busy, false);
atomic_dec(&tp->t_mountp->m_active_trans);
xfs_trans_free_dqinfo(tp);
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index f6118703f20d..7ab99e1898c8 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -345,11 +345,9 @@ struct xfs_item_ops {
void (*iop_format)(xfs_log_item_t *, struct xfs_log_iovec *);
void (*iop_pin)(xfs_log_item_t *);
void (*iop_unpin)(xfs_log_item_t *, int remove);
- uint (*iop_trylock)(xfs_log_item_t *);
+ uint (*iop_push)(struct xfs_log_item *, struct list_head *);
void (*iop_unlock)(xfs_log_item_t *);
xfs_lsn_t (*iop_committed)(xfs_log_item_t *, xfs_lsn_t);
- void (*iop_push)(xfs_log_item_t *);
- bool (*iop_pushbuf)(xfs_log_item_t *);
void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t);
};
@@ -357,20 +355,18 @@ struct xfs_item_ops {
#define IOP_FORMAT(ip,vp) (*(ip)->li_ops->iop_format)(ip, vp)
#define IOP_PIN(ip) (*(ip)->li_ops->iop_pin)(ip)
#define IOP_UNPIN(ip, remove) (*(ip)->li_ops->iop_unpin)(ip, remove)
-#define IOP_TRYLOCK(ip) (*(ip)->li_ops->iop_trylock)(ip)
+#define IOP_PUSH(ip, list) (*(ip)->li_ops->iop_push)(ip, list)
#define IOP_UNLOCK(ip) (*(ip)->li_ops->iop_unlock)(ip)
#define IOP_COMMITTED(ip, lsn) (*(ip)->li_ops->iop_committed)(ip, lsn)
-#define IOP_PUSH(ip) (*(ip)->li_ops->iop_push)(ip)
-#define IOP_PUSHBUF(ip) (*(ip)->li_ops->iop_pushbuf)(ip)
#define IOP_COMMITTING(ip, lsn) (*(ip)->li_ops->iop_committing)(ip, lsn)
/*
- * Return values for the IOP_TRYLOCK() routines.
+ * Return values for the IOP_PUSH() routines.
*/
-#define XFS_ITEM_SUCCESS 0
-#define XFS_ITEM_PINNED 1
-#define XFS_ITEM_LOCKED 2
-#define XFS_ITEM_PUSHBUF 3
+#define XFS_ITEM_SUCCESS 0
+#define XFS_ITEM_PINNED 1
+#define XFS_ITEM_LOCKED 2
+#define XFS_ITEM_FLUSHING 3
/*
* This is the type of function which can be given to xfs_trans_callback()
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
index 1dead07f092c..9c514483e599 100644
--- a/fs/xfs/xfs_trans_ail.c
+++ b/fs/xfs/xfs_trans_ail.c
@@ -20,7 +20,6 @@
#include "xfs_fs.h"
#include "xfs_types.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
@@ -79,7 +78,7 @@ xfs_ail_check(
* Return a pointer to the first item in the AIL. If the AIL is empty, then
* return NULL.
*/
-static xfs_log_item_t *
+xfs_log_item_t *
xfs_ail_min(
struct xfs_ail *ailp)
{
@@ -364,30 +363,31 @@ xfsaild_push(
xfs_log_item_t *lip;
xfs_lsn_t lsn;
xfs_lsn_t target;
- long tout = 10;
+ long tout;
int stuck = 0;
+ int flushing = 0;
int count = 0;
- int push_xfsbufd = 0;
/*
- * If last time we ran we encountered pinned items, force the log first
- * and wait for it before pushing again.
+ * If we encountered pinned items or did not finish writing out all
+ * buffers the last time we ran, force the log first and wait for it
+ * before pushing again.
*/
- spin_lock(&ailp->xa_lock);
- if (ailp->xa_last_pushed_lsn == 0 && ailp->xa_log_flush &&
- !list_empty(&ailp->xa_ail)) {
+ if (ailp->xa_log_flush && ailp->xa_last_pushed_lsn == 0 &&
+ (!list_empty_careful(&ailp->xa_buf_list) ||
+ xfs_ail_min_lsn(ailp))) {
ailp->xa_log_flush = 0;
- spin_unlock(&ailp->xa_lock);
+
XFS_STATS_INC(xs_push_ail_flush);
xfs_log_force(mp, XFS_LOG_SYNC);
- spin_lock(&ailp->xa_lock);
}
- target = ailp->xa_target;
+ spin_lock(&ailp->xa_lock);
lip = xfs_trans_ail_cursor_first(ailp, &cur, ailp->xa_last_pushed_lsn);
- if (!lip || XFS_FORCED_SHUTDOWN(mp)) {
+ if (!lip) {
/*
- * AIL is empty or our push has reached the end.
+ * If the AIL is empty or our push has reached the end we are
+ * done now.
*/
xfs_trans_ail_cursor_done(ailp, &cur);
spin_unlock(&ailp->xa_lock);
@@ -396,54 +396,42 @@ xfsaild_push(
XFS_STATS_INC(xs_push_ail);
- /*
- * While the item we are looking at is below the given threshold
- * try to flush it out. We'd like not to stop until we've at least
- * tried to push on everything in the AIL with an LSN less than
- * the given threshold.
- *
- * However, we will stop after a certain number of pushes and wait
- * for a reduced timeout to fire before pushing further. This
- * prevents use from spinning when we can't do anything or there is
- * lots of contention on the AIL lists.
- */
lsn = lip->li_lsn;
+ target = ailp->xa_target;
while ((XFS_LSN_CMP(lip->li_lsn, target) <= 0)) {
int lock_result;
+
/*
- * If we can lock the item without sleeping, unlock the AIL
- * lock and flush the item. Then re-grab the AIL lock so we
- * can look for the next item on the AIL. List changes are
- * handled by the AIL lookup functions internally
- *
- * If we can't lock the item, either its holder will flush it
- * or it is already being flushed or it is being relogged. In
- * any of these case it is being taken care of and we can just
- * skip to the next item in the list.
+ * Note that IOP_PUSH may unlock and reacquire the AIL lock. We
+ * rely on the AIL cursor implementation to be able to deal with
+ * the dropped lock.
*/
- lock_result = IOP_TRYLOCK(lip);
- spin_unlock(&ailp->xa_lock);
+ lock_result = IOP_PUSH(lip, &ailp->xa_buf_list);
switch (lock_result) {
case XFS_ITEM_SUCCESS:
XFS_STATS_INC(xs_push_ail_success);
trace_xfs_ail_push(lip);
- IOP_PUSH(lip);
ailp->xa_last_pushed_lsn = lsn;
break;
- case XFS_ITEM_PUSHBUF:
- XFS_STATS_INC(xs_push_ail_pushbuf);
- trace_xfs_ail_pushbuf(lip);
-
- if (!IOP_PUSHBUF(lip)) {
- trace_xfs_ail_pushbuf_pinned(lip);
- stuck++;
- ailp->xa_log_flush++;
- } else {
- ailp->xa_last_pushed_lsn = lsn;
- }
- push_xfsbufd = 1;
+ case XFS_ITEM_FLUSHING:
+ /*
+ * The item or its backing buffer is already beeing
+ * flushed. The typical reason for that is that an
+ * inode buffer is locked because we already pushed the
+ * updates to it as part of inode clustering.
+ *
+ * We do not want to to stop flushing just because lots
+ * of items are already beeing flushed, but we need to
+ * re-try the flushing relatively soon if most of the
+ * AIL is beeing flushed.
+ */
+ XFS_STATS_INC(xs_push_ail_flushing);
+ trace_xfs_ail_flushing(lip);
+
+ flushing++;
+ ailp->xa_last_pushed_lsn = lsn;
break;
case XFS_ITEM_PINNED:
@@ -453,28 +441,22 @@ xfsaild_push(
stuck++;
ailp->xa_log_flush++;
break;
-
case XFS_ITEM_LOCKED:
XFS_STATS_INC(xs_push_ail_locked);
trace_xfs_ail_locked(lip);
+
stuck++;
break;
-
default:
ASSERT(0);
break;
}
- spin_lock(&ailp->xa_lock);
- /* should we bother continuing? */
- if (XFS_FORCED_SHUTDOWN(mp))
- break;
- ASSERT(mp->m_log);
-
count++;
/*
* Are there too many items we can't do anything with?
+ *
* If we we are skipping too many items because we can't flush
* them or they are already being flushed, we back off and
* given them time to complete whatever operation is being
@@ -496,42 +478,36 @@ xfsaild_push(
xfs_trans_ail_cursor_done(ailp, &cur);
spin_unlock(&ailp->xa_lock);
- if (push_xfsbufd) {
- /* we've got delayed write buffers to flush */
- wake_up_process(mp->m_ddev_targp->bt_task);
- }
+ if (xfs_buf_delwri_submit_nowait(&ailp->xa_buf_list))
+ ailp->xa_log_flush++;
- /* assume we have more work to do in a short while */
+ if (!count || XFS_LSN_CMP(lsn, target) >= 0) {
out_done:
- if (!count) {
- /* We're past our target or empty, so idle */
- ailp->xa_last_pushed_lsn = 0;
- ailp->xa_log_flush = 0;
-
- tout = 50;
- } else if (XFS_LSN_CMP(lsn, target) >= 0) {
/*
- * We reached the target so wait a bit longer for I/O to
- * complete and remove pushed items from the AIL before we
- * start the next scan from the start of the AIL.
+ * We reached the target or the AIL is empty, so wait a bit
+ * longer for I/O to complete and remove pushed items from the
+ * AIL before we start the next scan from the start of the AIL.
*/
tout = 50;
ailp->xa_last_pushed_lsn = 0;
- } else if ((stuck * 100) / count > 90) {
+ } else if (((stuck + flushing) * 100) / count > 90) {
/*
- * Either there is a lot of contention on the AIL or we
- * are stuck due to operations in progress. "Stuck" in this
- * case is defined as >90% of the items we tried to push
- * were stuck.
+ * Either there is a lot of contention on the AIL or we are
+ * stuck due to operations in progress. "Stuck" in this case
+ * is defined as >90% of the items we tried to push were stuck.
*
* Backoff a bit more to allow some I/O to complete before
- * restarting from the start of the AIL. This prevents us
- * from spinning on the same items, and if they are pinned will
- * all the restart to issue a log force to unpin the stuck
- * items.
+ * restarting from the start of the AIL. This prevents us from
+ * spinning on the same items, and if they are pinned will all
+ * the restart to issue a log force to unpin the stuck items.
*/
tout = 20;
ailp->xa_last_pushed_lsn = 0;
+ } else {
+ /*
+ * Assume we have more work to do in a short while.
+ */
+ tout = 10;
}
return tout;
@@ -544,6 +520,8 @@ xfsaild(
struct xfs_ail *ailp = data;
long tout = 0; /* milliseconds */
+ current->flags |= PF_MEMALLOC;
+
while (!kthread_should_stop()) {
if (tout && tout <= 20)
__set_current_state(TASK_KILLABLE);
@@ -611,6 +589,30 @@ xfs_ail_push_all(
}
/*
+ * Push out all items in the AIL immediately and wait until the AIL is empty.
+ */
+void
+xfs_ail_push_all_sync(
+ struct xfs_ail *ailp)
+{
+ struct xfs_log_item *lip;
+ DEFINE_WAIT(wait);
+
+ spin_lock(&ailp->xa_lock);
+ while ((lip = xfs_ail_max(ailp)) != NULL) {
+ prepare_to_wait(&ailp->xa_empty, &wait, TASK_UNINTERRUPTIBLE);
+ ailp->xa_target = lip->li_lsn;
+ wake_up_process(ailp->xa_task);
+ spin_unlock(&ailp->xa_lock);
+ schedule();
+ spin_lock(&ailp->xa_lock);
+ }
+ spin_unlock(&ailp->xa_lock);
+
+ finish_wait(&ailp->xa_empty, &wait);
+}
+
+/*
* xfs_trans_ail_update - bulk AIL insertion operation.
*
* @xfs_trans_ail_update takes an array of log items that all need to be
@@ -667,11 +669,15 @@ xfs_trans_ail_update_bulk(
if (!list_empty(&tmp))
xfs_ail_splice(ailp, cur, &tmp, lsn);
- spin_unlock(&ailp->xa_lock);
- if (mlip_changed && !XFS_FORCED_SHUTDOWN(ailp->xa_mount)) {
- xlog_assign_tail_lsn(ailp->xa_mount);
+ if (mlip_changed) {
+ if (!XFS_FORCED_SHUTDOWN(ailp->xa_mount))
+ xlog_assign_tail_lsn_locked(ailp->xa_mount);
+ spin_unlock(&ailp->xa_lock);
+
xfs_log_space_wake(ailp->xa_mount);
+ } else {
+ spin_unlock(&ailp->xa_lock);
}
}
@@ -700,7 +706,8 @@ void
xfs_trans_ail_delete_bulk(
struct xfs_ail *ailp,
struct xfs_log_item **log_items,
- int nr_items) __releases(ailp->xa_lock)
+ int nr_items,
+ int shutdown_type) __releases(ailp->xa_lock)
{
xfs_log_item_t *mlip;
int mlip_changed = 0;
@@ -718,7 +725,7 @@ xfs_trans_ail_delete_bulk(
xfs_alert_tag(mp, XFS_PTAG_AILDELETE,
"%s: attempting to delete a log item that is not in the AIL",
__func__);
- xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
+ xfs_force_shutdown(mp, shutdown_type);
}
return;
}
@@ -729,28 +736,20 @@ xfs_trans_ail_delete_bulk(
if (mlip == lip)
mlip_changed = 1;
}
- spin_unlock(&ailp->xa_lock);
- if (mlip_changed && !XFS_FORCED_SHUTDOWN(ailp->xa_mount)) {
- xlog_assign_tail_lsn(ailp->xa_mount);
+ if (mlip_changed) {
+ if (!XFS_FORCED_SHUTDOWN(ailp->xa_mount))
+ xlog_assign_tail_lsn_locked(ailp->xa_mount);
+ if (list_empty(&ailp->xa_ail))
+ wake_up_all(&ailp->xa_empty);
+ spin_unlock(&ailp->xa_lock);
+
xfs_log_space_wake(ailp->xa_mount);
+ } else {
+ spin_unlock(&ailp->xa_lock);
}
}
-/*
- * The active item list (AIL) is a doubly linked list of log
- * items sorted by ascending lsn. The base of the list is
- * a forw/back pointer pair embedded in the xfs mount structure.
- * The base is initialized with both pointers pointing to the
- * base. This case always needs to be distinguished, because
- * the base has no lsn to look at. We almost always insert
- * at the end of the list, so on inserts we search from the
- * end of the list to find where the new item belongs.
- */
-
-/*
- * Initialize the doubly linked list to point only to itself.
- */
int
xfs_trans_ail_init(
xfs_mount_t *mp)
@@ -765,6 +764,8 @@ xfs_trans_ail_init(
INIT_LIST_HEAD(&ailp->xa_ail);
INIT_LIST_HEAD(&ailp->xa_cursors);
spin_lock_init(&ailp->xa_lock);
+ INIT_LIST_HEAD(&ailp->xa_buf_list);
+ init_waitqueue_head(&ailp->xa_empty);
ailp->xa_task = kthread_run(xfsaild, ailp, "xfsaild/%s",
ailp->xa_mount->m_fsname);
diff --git a/fs/xfs/xfs_trans_buf.c b/fs/xfs/xfs_trans_buf.c
index 1302d1d95a58..21c5a5e3700d 100644
--- a/fs/xfs/xfs_trans_buf.c
+++ b/fs/xfs/xfs_trans_buf.c
@@ -18,9 +18,7 @@
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_types.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
@@ -33,7 +31,6 @@
#include "xfs_buf_item.h"
#include "xfs_trans_priv.h"
#include "xfs_error.h"
-#include "xfs_rw.h"
#include "xfs_trace.h"
/*
@@ -56,7 +53,7 @@ xfs_trans_buf_item_match(
if (blip->bli_item.li_type == XFS_LI_BUF &&
blip->bli_buf->b_target == target &&
XFS_BUF_ADDR(blip->bli_buf) == blkno &&
- XFS_BUF_COUNT(blip->bli_buf) == len)
+ BBTOB(blip->bli_buf->b_length) == len)
return blip->bli_buf;
}
@@ -141,15 +138,11 @@ xfs_trans_get_buf(xfs_trans_t *tp,
xfs_buf_t *bp;
xfs_buf_log_item_t *bip;
- if (flags == 0)
- flags = XBF_LOCK | XBF_MAPPED;
-
/*
* Default to a normal get_buf() call if the tp is NULL.
*/
if (tp == NULL)
- return xfs_buf_get(target_dev, blkno, len,
- flags | XBF_DONT_BLOCK);
+ return xfs_buf_get(target_dev, blkno, len, flags);
/*
* If we find the buffer in the cache with this transaction
@@ -165,14 +158,6 @@ xfs_trans_get_buf(xfs_trans_t *tp,
XFS_BUF_DONE(bp);
}
- /*
- * If the buffer is stale then it was binval'ed
- * since last read. This doesn't matter since the
- * caller isn't allowed to use the data anyway.
- */
- else if (XFS_BUF_ISSTALE(bp))
- ASSERT(!XFS_BUF_ISDELAYWRITE(bp));
-
ASSERT(bp->b_transp == tp);
bip = bp->b_fspriv;
ASSERT(bip != NULL);
@@ -182,15 +167,7 @@ xfs_trans_get_buf(xfs_trans_t *tp,
return (bp);
}
- /*
- * We always specify the XBF_DONT_BLOCK flag within a transaction
- * so that get_buf does not try to push out a delayed write buffer
- * which might cause another transaction to take place (if the
- * buffer was delayed alloc). Such recursive transactions can
- * easily deadlock with our current transaction as well as cause
- * us to run out of stack space.
- */
- bp = xfs_buf_get(target_dev, blkno, len, flags | XBF_DONT_BLOCK);
+ bp = xfs_buf_get(target_dev, blkno, len, flags);
if (bp == NULL) {
return NULL;
}
@@ -282,14 +259,13 @@ xfs_trans_read_buf(
xfs_buf_log_item_t *bip;
int error;
- if (flags == 0)
- flags = XBF_LOCK | XBF_MAPPED;
+ *bpp = NULL;
/*
* Default to a normal get_buf() call if the tp is NULL.
*/
if (tp == NULL) {
- bp = xfs_buf_read(target, blkno, len, flags | XBF_DONT_BLOCK);
+ bp = xfs_buf_read(target, blkno, len, flags);
if (!bp)
return (flags & XBF_TRYLOCK) ?
EAGAIN : XFS_ERROR(ENOMEM);
@@ -297,6 +273,8 @@ xfs_trans_read_buf(
if (bp->b_error) {
error = bp->b_error;
xfs_buf_ioerror_alert(bp, __func__);
+ XFS_BUF_UNDONE(bp);
+ xfs_buf_stale(bp);
xfs_buf_relse(bp);
return error;
}
@@ -371,15 +349,7 @@ xfs_trans_read_buf(
return 0;
}
- /*
- * We always specify the XBF_DONT_BLOCK flag within a transaction
- * so that get_buf does not try to push out a delayed write buffer
- * which might cause another transaction to take place (if the
- * buffer was delayed alloc). Such recursive transactions can
- * easily deadlock with our current transaction as well as cause
- * us to run out of stack space.
- */
- bp = xfs_buf_read(target, blkno, len, flags | XBF_DONT_BLOCK);
+ bp = xfs_buf_read(target, blkno, len, flags);
if (bp == NULL) {
*bpp = NULL;
return (flags & XBF_TRYLOCK) ?
@@ -418,19 +388,6 @@ xfs_trans_read_buf(
return 0;
shutdown_abort:
- /*
- * the theory here is that buffer is good but we're
- * bailing out because the filesystem is being forcibly
- * shut down. So we should leave the b_flags alone since
- * the buffer's not staled and just get out.
- */
-#if defined(DEBUG)
- if (XFS_BUF_ISSTALE(bp) && XFS_BUF_ISDELAYWRITE(bp))
- xfs_notice(mp, "about to pop assert, bp == 0x%p", bp);
-#endif
- ASSERT((bp->b_flags & (XBF_STALE|XBF_DELWRI)) !=
- (XBF_STALE|XBF_DELWRI));
-
trace_xfs_trans_read_buf_shut(bp, _RET_IP_);
xfs_buf_relse(bp);
*bpp = NULL;
@@ -606,7 +563,7 @@ xfs_trans_log_buf(xfs_trans_t *tp,
ASSERT(bp->b_transp == tp);
ASSERT(bip != NULL);
- ASSERT((first <= last) && (last < XFS_BUF_COUNT(bp)));
+ ASSERT(first <= last && last < BBTOB(bp->b_length));
ASSERT(bp->b_iodone == NULL ||
bp->b_iodone == xfs_buf_iodone_callbacks);
@@ -626,8 +583,6 @@ xfs_trans_log_buf(xfs_trans_t *tp,
bp->b_iodone = xfs_buf_iodone_callbacks;
bip->bli_item.li_cb = xfs_buf_iodone;
- xfs_buf_delwri_queue(bp);
-
trace_xfs_trans_log_buf(bip);
/*
@@ -651,22 +606,33 @@ xfs_trans_log_buf(xfs_trans_t *tp,
/*
- * This called to invalidate a buffer that is being used within
- * a transaction. Typically this is because the blocks in the
- * buffer are being freed, so we need to prevent it from being
- * written out when we're done. Allowing it to be written again
- * might overwrite data in the free blocks if they are reallocated
- * to a file.
+ * Invalidate a buffer that is being used within a transaction.
+ *
+ * Typically this is because the blocks in the buffer are being freed, so we
+ * need to prevent it from being written out when we're done. Allowing it
+ * to be written again might overwrite data in the free blocks if they are
+ * reallocated to a file.
+ *
+ * We prevent the buffer from being written out by marking it stale. We can't
+ * get rid of the buf log item at this point because the buffer may still be
+ * pinned by another transaction. If that is the case, then we'll wait until
+ * the buffer is committed to disk for the last time (we can tell by the ref
+ * count) and free it in xfs_buf_item_unpin(). Until that happens we will
+ * keep the buffer locked so that the buffer and buf log item are not reused.
+ *
+ * We also set the XFS_BLF_CANCEL flag in the buf log format structure and log
+ * the buf item. This will be used at recovery time to determine that copies
+ * of the buffer in the log before this should not be replayed.
*
- * We prevent the buffer from being written out by clearing the
- * B_DELWRI flag. We can't always
- * get rid of the buf log item at this point, though, because
- * the buffer may still be pinned by another transaction. If that
- * is the case, then we'll wait until the buffer is committed to
- * disk for the last time (we can tell by the ref count) and
- * free it in xfs_buf_item_unpin(). Until it is cleaned up we
- * will keep the buffer locked so that the buffer and buf log item
- * are not reused.
+ * We mark the item descriptor and the transaction dirty so that we'll hold
+ * the buffer until after the commit.
+ *
+ * Since we're invalidating the buffer, we also clear the state about which
+ * parts of the buffer have been logged. We also clear the flag indicating
+ * that this is an inode buffer since the data in the buffer will no longer
+ * be valid.
+ *
+ * We set the stale bit in the buffer as well since we're getting rid of it.
*/
void
xfs_trans_binval(
@@ -686,7 +652,6 @@ xfs_trans_binval(
* If the buffer is already invalidated, then
* just return.
*/
- ASSERT(!(XFS_BUF_ISDELAYWRITE(bp)));
ASSERT(XFS_BUF_ISSTALE(bp));
ASSERT(!(bip->bli_flags & (XFS_BLI_LOGGED | XFS_BLI_DIRTY)));
ASSERT(!(bip->bli_format.blf_flags & XFS_BLF_INODE_BUF));
@@ -696,27 +661,8 @@ xfs_trans_binval(
return;
}
- /*
- * Clear the dirty bit in the buffer and set the STALE flag
- * in the buf log item. The STALE flag will be used in
- * xfs_buf_item_unpin() to determine if it should clean up
- * when the last reference to the buf item is given up.
- * We set the XFS_BLF_CANCEL flag in the buf log format structure
- * and log the buf item. This will be used at recovery time
- * to determine that copies of the buffer in the log before
- * this should not be replayed.
- * We mark the item descriptor and the transaction dirty so
- * that we'll hold the buffer until after the commit.
- *
- * Since we're invalidating the buffer, we also clear the state
- * about which parts of the buffer have been logged. We also
- * clear the flag indicating that this is an inode buffer since
- * the data in the buffer will no longer be valid.
- *
- * We set the stale bit in the buffer as well since we're getting
- * rid of it.
- */
xfs_buf_stale(bp);
+
bip->bli_flags |= XFS_BLI_STALE;
bip->bli_flags &= ~(XFS_BLI_INODE_BUF | XFS_BLI_LOGGED | XFS_BLI_DIRTY);
bip->bli_format.blf_flags &= ~XFS_BLF_INODE_BUF;
diff --git a/fs/xfs/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
index 279099717ed2..bcb60542fcf1 100644
--- a/fs/xfs/xfs_trans_dquot.c
+++ b/fs/xfs/xfs_trans_dquot.c
@@ -17,9 +17,7 @@
*/
#include "xfs.h"
#include "xfs_fs.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
diff --git a/fs/xfs/xfs_trans_extfree.c b/fs/xfs/xfs_trans_extfree.c
index f7590f5badea..8d71b16eccae 100644
--- a/fs/xfs/xfs_trans_extfree.c
+++ b/fs/xfs/xfs_trans_extfree.c
@@ -19,7 +19,6 @@
#include "xfs_fs.h"
#include "xfs_types.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
diff --git a/fs/xfs/xfs_trans_inode.c b/fs/xfs/xfs_trans_inode.c
index 7a7442c03f2b..d2eee20d5f5b 100644
--- a/fs/xfs/xfs_trans_inode.c
+++ b/fs/xfs/xfs_trans_inode.c
@@ -18,9 +18,7 @@
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_types.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h
index 8ab2ced415f1..fb62377d1cbc 100644
--- a/fs/xfs/xfs_trans_priv.h
+++ b/fs/xfs/xfs_trans_priv.h
@@ -71,6 +71,8 @@ struct xfs_ail {
spinlock_t xa_lock;
xfs_lsn_t xa_last_pushed_lsn;
int xa_log_flush;
+ struct list_head xa_buf_list;
+ wait_queue_head_t xa_empty;
};
/*
@@ -90,18 +92,22 @@ xfs_trans_ail_update(
}
void xfs_trans_ail_delete_bulk(struct xfs_ail *ailp,
- struct xfs_log_item **log_items, int nr_items)
+ struct xfs_log_item **log_items, int nr_items,
+ int shutdown_type)
__releases(ailp->xa_lock);
static inline void
xfs_trans_ail_delete(
struct xfs_ail *ailp,
- xfs_log_item_t *lip) __releases(ailp->xa_lock)
+ xfs_log_item_t *lip,
+ int shutdown_type) __releases(ailp->xa_lock)
{
- xfs_trans_ail_delete_bulk(ailp, &lip, 1);
+ xfs_trans_ail_delete_bulk(ailp, &lip, 1, shutdown_type);
}
void xfs_ail_push(struct xfs_ail *, xfs_lsn_t);
void xfs_ail_push_all(struct xfs_ail *);
+void xfs_ail_push_all_sync(struct xfs_ail *);
+struct xfs_log_item *xfs_ail_min(struct xfs_ail *ailp);
xfs_lsn_t xfs_ail_min_lsn(struct xfs_ail *ailp);
struct xfs_log_item * xfs_trans_ail_cursor_first(struct xfs_ail *ailp,
diff --git a/fs/xfs/xfs_types.h b/fs/xfs/xfs_types.h
index 65584b55607d..398cf681d025 100644
--- a/fs/xfs/xfs_types.h
+++ b/fs/xfs/xfs_types.h
@@ -57,6 +57,7 @@ typedef __uint64_t __psunsigned_t;
#endif /* __KERNEL__ */
typedef __uint32_t xfs_agblock_t; /* blockno in alloc. group */
+typedef __uint32_t xfs_agino_t; /* inode # within allocation grp */
typedef __uint32_t xfs_extlen_t; /* extent length in blocks */
typedef __uint32_t xfs_agnumber_t; /* allocation group number */
typedef __int32_t xfs_extnum_t; /* # of extents in a file */
@@ -101,6 +102,7 @@ typedef __uint64_t xfs_fileoff_t; /* block number in a file */
typedef __int64_t xfs_sfiloff_t; /* signed block number in a file */
typedef __uint64_t xfs_filblks_t; /* number of blocks in a file */
+
/*
* Null values for the types.
*/
@@ -120,6 +122,9 @@ typedef __uint64_t xfs_filblks_t; /* number of blocks in a file */
#define NULLCOMMITLSN ((xfs_lsn_t)-1)
+#define NULLFSINO ((xfs_ino_t)-1)
+#define NULLAGINO ((xfs_agino_t)-1)
+
/*
* Max values for extlen, extnum, aextnum.
*/
diff --git a/fs/xfs/xfs_utils.c b/fs/xfs/xfs_utils.c
index 79c05ac85bfe..4e5b9ad5cb97 100644
--- a/fs/xfs/xfs_utils.c
+++ b/fs/xfs/xfs_utils.c
@@ -18,9 +18,7 @@
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_types.h"
-#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 64981d7e7375..b6a82d817a82 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -21,7 +21,6 @@
#include "xfs_types.h"
#include "xfs_bit.h"
#include "xfs_log.h"
-#include "xfs_inum.h"
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
@@ -39,7 +38,6 @@
#include "xfs_bmap.h"
#include "xfs_acl.h"
#include "xfs_attr.h"
-#include "xfs_rw.h"
#include "xfs_error.h"
#include "xfs_quota.h"
#include "xfs_utils.h"
@@ -81,8 +79,7 @@ xfs_readlink_bmap(
d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock);
byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount);
- bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt),
- XBF_LOCK | XBF_MAPPED | XBF_DONT_BLOCK);
+ bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0);
if (!bp)
return XFS_ERROR(ENOMEM);
error = bp->b_error;
@@ -1919,7 +1916,7 @@ xfs_alloc_file_space(
error0: /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */
xfs_bmap_cancel(&free_list);
- xfs_trans_unreserve_quota_nblks(tp, ip, qblocks, 0, quota_flag);
+ xfs_trans_unreserve_quota_nblks(tp, ip, (long)qblocks, 0, quota_flag);
error1: /* Just cancel transaction */
xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
@@ -1966,7 +1963,7 @@ xfs_zero_remaining_bytes(
bp = xfs_buf_get_uncached(XFS_IS_REALTIME_INODE(ip) ?
mp->m_rtdev_targp : mp->m_ddev_targp,
- mp->m_sb.sb_blocksize, XBF_DONT_BLOCK);
+ BTOBB(mp->m_sb.sb_blocksize), 0);
if (!bp)
return XFS_ERROR(ENOMEM);
@@ -2315,17 +2312,33 @@ xfs_change_file_space(
case XFS_IOC_ALLOCSP64:
case XFS_IOC_FREESP:
case XFS_IOC_FREESP64:
+ /*
+ * These operations actually do IO when extending the file, but
+ * the allocation is done seperately to the zeroing that is
+ * done. This set of operations need to be serialised against
+ * other IO operations, such as truncate and buffered IO. We
+ * need to take the IOLOCK here to serialise the allocation and
+ * zeroing IO to prevent other IOLOCK holders (e.g. getbmap,
+ * truncate, direct IO) from racing against the transient
+ * allocated but not written state we can have here.
+ */
+ xfs_ilock(ip, XFS_IOLOCK_EXCL);
if (startoffset > fsize) {
error = xfs_alloc_file_space(ip, fsize,
- startoffset - fsize, 0, attr_flags);
- if (error)
+ startoffset - fsize, 0,
+ attr_flags | XFS_ATTR_NOLOCK);
+ if (error) {
+ xfs_iunlock(ip, XFS_IOLOCK_EXCL);
break;
+ }
}
iattr.ia_valid = ATTR_SIZE;
iattr.ia_size = startoffset;
- error = xfs_setattr_size(ip, &iattr, attr_flags);
+ error = xfs_setattr_size(ip, &iattr,
+ attr_flags | XFS_ATTR_NOLOCK);
+ xfs_iunlock(ip, XFS_IOLOCK_EXCL);
if (error)
return error;
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index f1c8ca60e824..b0d62820ada1 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -51,6 +51,37 @@ acpi_evaluate_reference(acpi_handle handle,
struct acpi_object_list *arguments,
struct acpi_handle_list *list);
+struct acpi_pld {
+ unsigned int revision:7; /* 0 */
+ unsigned int ignore_colour:1; /* 7 */
+ unsigned int colour:24; /* 8 */
+ unsigned int width:16; /* 32 */
+ unsigned int height:16; /* 48 */
+ unsigned int user_visible:1; /* 64 */
+ unsigned int dock:1; /* 65 */
+ unsigned int lid:1; /* 66 */
+ unsigned int panel:3; /* 67 */
+ unsigned int vertical_pos:2; /* 70 */
+ unsigned int horizontal_pos:2; /* 72 */
+ unsigned int shape:4; /* 74 */
+ unsigned int group_orientation:1; /* 78 */
+ unsigned int group_token:8; /* 79 */
+ unsigned int group_position:8; /* 87 */
+ unsigned int bay:1; /* 95 */
+ unsigned int ejectable:1; /* 96 */
+ unsigned int ospm_eject_required:1; /* 97 */
+ unsigned int cabinet_number:8; /* 98 */
+ unsigned int card_cage_number:8; /* 106 */
+ unsigned int reference:1; /* 114 */
+ unsigned int rotation:4; /* 115 */
+ unsigned int order:5; /* 119 */
+ unsigned int reserved:4; /* 124 */
+ unsigned int vertical_offset:16; /* 128 */
+ unsigned int horizontal_offset:16; /* 144 */
+} __attribute__((__packed__));
+
+acpi_status
+acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld *pld);
#ifdef CONFIG_ACPI
#include <linux/proc_fs.h>
@@ -407,6 +438,11 @@ static inline int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
}
#endif
+#else /* CONFIG_ACPI */
+
+static int register_acpi_bus_type(struct acpi_bus_type *bus) { return 0; }
+static int unregister_acpi_bus_type(struct acpi_bus_type *bus) { return 0; }
+
#endif /* CONFIG_ACPI */
#endif /*__ACPI_BUS_H__*/
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 5f52690c3c8f..365ea09ed3b0 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -142,9 +142,9 @@ extern int __must_check gpiochip_reserve(int start, int ngpio);
/* add/remove chips */
extern int gpiochip_add(struct gpio_chip *chip);
extern int __must_check gpiochip_remove(struct gpio_chip *chip);
-extern struct gpio_chip *gpiochip_find(const void *data,
+extern struct gpio_chip *gpiochip_find(void *data,
int (*match)(struct gpio_chip *chip,
- const void *data));
+ void *data));
/* Always use the library code for GPIO management calls,
@@ -179,6 +179,8 @@ extern void gpio_free_array(const struct gpio *array, size_t num);
/* bindings for managed devices that want to request gpios */
int devm_gpio_request(struct device *dev, unsigned gpio, const char *label);
+int devm_gpio_request_one(struct device *dev, unsigned gpio,
+ unsigned long flags, const char *label);
void devm_gpio_free(struct device *dev, unsigned int gpio);
#ifdef CONFIG_GPIO_SYSFS
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 8aeadf6b553a..4e2e1cc505ab 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -486,8 +486,8 @@
CPU_DISCARD(init.data) \
MEM_DISCARD(init.data) \
KERNEL_CTORS() \
- *(.init.rodata) \
MCOUNT_REC() \
+ *(.init.rodata) \
FTRACE_EVENTS() \
TRACE_SYSCALLS() \
DEV_DISCARD(init.rodata) \
diff --git a/include/drm/drm.h b/include/drm/drm.h
index 64ff02d5b730..e51035a3757f 100644
--- a/include/drm/drm.h
+++ b/include/drm/drm.h
@@ -730,6 +730,8 @@ struct drm_prime_handle {
#define DRM_IOCTL_MODE_GETPLANE DRM_IOWR(0xB6, struct drm_mode_get_plane)
#define DRM_IOCTL_MODE_SETPLANE DRM_IOWR(0xB7, struct drm_mode_set_plane)
#define DRM_IOCTL_MODE_ADDFB2 DRM_IOWR(0xB8, struct drm_mode_fb_cmd2)
+#define DRM_IOCTL_MODE_OBJ_GETPROPERTIES DRM_IOWR(0xB9, struct drm_mode_obj_get_properties)
+#define DRM_IOCTL_MODE_OBJ_SETPROPERTY DRM_IOWR(0xBA, struct drm_mode_obj_set_property)
/**
* Device specific ioctls should only be in their respective headers
@@ -775,6 +777,10 @@ struct drm_event_vblank {
#define DRM_CAP_VBLANK_HIGH_CRTC 0x2
#define DRM_CAP_DUMB_PREFERRED_DEPTH 0x3
#define DRM_CAP_DUMB_PREFER_SHADOW 0x4
+#define DRM_CAP_PRIME 0x5
+
+#define DRM_PRIME_CAP_IMPORT 0x1
+#define DRM_PRIME_CAP_EXPORT 0x2
/* typedef area */
#ifndef __KERNEL__
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index dd731043fecd..31ad880ca2ef 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -755,11 +755,11 @@ struct drm_driver {
* @dev: DRM device
* @crtc: counter to fetch
*
- * Driver callback for fetching a raw hardware vblank counter
- * for @crtc. If a device doesn't have a hardware counter, the
- * driver can simply return the value of drm_vblank_count and
- * make the enable_vblank() and disable_vblank() hooks into no-ops,
- * leaving interrupts enabled at all times.
+ * Driver callback for fetching a raw hardware vblank counter for @crtc.
+ * If a device doesn't have a hardware counter, the driver can simply
+ * return the value of drm_vblank_count. The DRM core will account for
+ * missed vblank events while interrupts where disabled based on system
+ * timestamps.
*
* Wraparound handling and loss of events due to modesetting is dealt
* with in the DRM core code.
@@ -941,7 +941,7 @@ struct drm_driver {
uint32_t handle);
/* Driver private ops for this object */
- struct vm_operations_struct *gem_vm_ops;
+ const struct vm_operations_struct *gem_vm_ops;
int major;
int minor;
@@ -1309,8 +1309,8 @@ extern int drm_release(struct inode *inode, struct file *filp);
/* Mapping support (drm_vm.h) */
extern int drm_mmap(struct file *filp, struct vm_area_struct *vma);
extern int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma);
-extern void drm_vm_open_locked(struct vm_area_struct *vma);
-extern void drm_vm_close_locked(struct vm_area_struct *vma);
+extern void drm_vm_open_locked(struct drm_device *dev, struct vm_area_struct *vma);
+extern void drm_vm_close_locked(struct drm_device *dev, struct vm_area_struct *vma);
extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait);
/* Memory management support (drm_memory.h) */
@@ -1378,6 +1378,7 @@ extern int drm_remove_magic(struct drm_master *master, drm_magic_t magic);
/* Cache management (drm_cache.c) */
void drm_clflush_pages(struct page *pages[], unsigned long num_pages);
+void drm_clflush_virt_range(char *addr, unsigned long length);
/* Locking IOCTL support (drm_lock.h) */
extern int drm_lock(struct drm_device *dev, void *data,
@@ -1557,6 +1558,8 @@ extern int drm_prime_handle_to_fd_ioctl(struct drm_device *dev, void *data,
extern int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+extern int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
+ dma_addr_t *addrs, int max_pages);
extern struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages);
extern void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index e250eda4e3a8..73e45600f95d 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -36,6 +36,7 @@
struct drm_device;
struct drm_mode_set;
struct drm_framebuffer;
+struct drm_object_properties;
#define DRM_MODE_OBJECT_CRTC 0xcccccccc
@@ -50,6 +51,14 @@ struct drm_framebuffer;
struct drm_mode_object {
uint32_t id;
uint32_t type;
+ struct drm_object_properties *properties;
+};
+
+#define DRM_OBJECT_MAX_PROPERTY 16
+struct drm_object_properties {
+ int count;
+ uint32_t ids[DRM_OBJECT_MAX_PROPERTY];
+ uint64_t values[DRM_OBJECT_MAX_PROPERTY];
};
/*
@@ -285,19 +294,16 @@ struct drm_plane;
/**
* drm_crtc_funcs - control CRTCs for a given device
- * @reset: reset CRTC after state has been invalidate (e.g. resume)
- * @dpms: control display power levels
* @save: save CRTC state
- * @resore: restore CRTC state
- * @lock: lock the CRTC
- * @unlock: unlock the CRTC
- * @shadow_allocate: allocate shadow pixmap
- * @shadow_create: create shadow pixmap for rotation support
- * @shadow_destroy: free shadow pixmap
- * @mode_fixup: fixup proposed mode
- * @mode_set: set the desired mode on the CRTC
+ * @restore: restore CRTC state
+ * @reset: reset CRTC after state has been invalidate (e.g. resume)
+ * @cursor_set: setup the cursor
+ * @cursor_move: move the cursor
* @gamma_set: specify color ramp for CRTC
- * @destroy: deinit and free object.
+ * @destroy: deinit and free object
+ * @set_property: called when a property is changed
+ * @set_config: apply a new CRTC configuration
+ * @page_flip: initiate a page flip
*
* The drm_crtc_funcs structure is the central CRTC management structure
* in the DRM. Each CRTC controls one or more connectors (note that the name
@@ -341,6 +347,9 @@ struct drm_crtc_funcs {
int (*page_flip)(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event);
+
+ int (*set_property)(struct drm_crtc *crtc,
+ struct drm_property *property, uint64_t val);
};
/**
@@ -360,6 +369,7 @@ struct drm_crtc_funcs {
* @framedur_ns: precise line timing
* @pixeldur_ns: precise pixel timing
* @helper_private: mid-layer private data
+ * @properties: property tracking for this CRTC
*
* Each CRTC may have one or more connectors associated with it. This structure
* allows the CRTC to be controlled.
@@ -395,6 +405,8 @@ struct drm_crtc {
/* if you are using the helper */
void *helper_private;
+
+ struct drm_object_properties properties;
};
@@ -404,11 +416,8 @@ struct drm_crtc {
* @save: save connector state
* @restore: restore connector state
* @reset: reset connector after state has been invalidate (e.g. resume)
- * @mode_valid: is this mode valid on the given connector?
- * @mode_fixup: try to fixup proposed mode for this connector
- * @mode_set: set this mode
* @detect: is this connector active?
- * @get_modes: get mode list for this connector
+ * @fill_modes: fill mode list for this connector
* @set_property: property for this connector may need update
* @destroy: make object go away
* @force: notify the driver the connector is forced on
@@ -451,7 +460,6 @@ struct drm_encoder_funcs {
};
#define DRM_CONNECTOR_MAX_UMODES 16
-#define DRM_CONNECTOR_MAX_PROPERTY 16
#define DRM_CONNECTOR_LEN 32
#define DRM_CONNECTOR_MAX_ENCODER 3
@@ -520,8 +528,7 @@ enum drm_connector_force {
* @funcs: connector control functions
* @user_modes: user added mode list
* @edid_blob_ptr: DRM property containing EDID if present
- * @property_ids: property tracking for this connector
- * @property_values: value pointers or data for properties
+ * @properties: property tracking for this connector
* @polled: a %DRM_CONNECTOR_POLL_<foo> value for core driven polling
* @dpms: current dpms state
* @helper_private: mid-layer private data
@@ -565,8 +572,7 @@ struct drm_connector {
struct list_head user_modes;
struct drm_property_blob *edid_blob_ptr;
- u32 property_ids[DRM_CONNECTOR_MAX_PROPERTY];
- uint64_t property_values[DRM_CONNECTOR_MAX_PROPERTY];
+ struct drm_object_properties properties;
uint8_t polled; /* DRM_CONNECTOR_POLL_* */
@@ -595,6 +601,7 @@ struct drm_connector {
* @update_plane: update the plane configuration
* @disable_plane: shut down the plane
* @destroy: clean up plane resources
+ * @set_property: called when a property is changed
*/
struct drm_plane_funcs {
int (*update_plane)(struct drm_plane *plane,
@@ -605,6 +612,9 @@ struct drm_plane_funcs {
uint32_t src_w, uint32_t src_h);
int (*disable_plane)(struct drm_plane *plane);
void (*destroy)(struct drm_plane *plane);
+
+ int (*set_property)(struct drm_plane *plane,
+ struct drm_property *property, uint64_t val);
};
/**
@@ -622,6 +632,7 @@ struct drm_plane_funcs {
* @enabled: enabled flag
* @funcs: helper functions
* @helper_private: storage for drver layer
+ * @properties: property tracking for this plane
*/
struct drm_plane {
struct drm_device *dev;
@@ -644,6 +655,8 @@ struct drm_plane {
const struct drm_plane_funcs *funcs;
void *helper_private;
+
+ struct drm_object_properties properties;
};
/**
@@ -761,7 +774,7 @@ struct drm_mode_config {
int min_width, min_height;
int max_width, max_height;
- struct drm_mode_config_funcs *funcs;
+ const struct drm_mode_config_funcs *funcs;
resource_size_t fb_base;
/* output poll support */
@@ -898,6 +911,12 @@ extern int drm_connector_property_set_value(struct drm_connector *connector,
extern int drm_connector_property_get_value(struct drm_connector *connector,
struct drm_property *property,
uint64_t *value);
+extern int drm_object_property_set_value(struct drm_mode_object *obj,
+ struct drm_property *property,
+ uint64_t val);
+extern int drm_object_property_get_value(struct drm_mode_object *obj,
+ struct drm_property *property,
+ uint64_t *value);
extern struct drm_display_mode *drm_crtc_mode_create(struct drm_device *dev);
extern void drm_framebuffer_set_object(struct drm_device *dev,
unsigned long handle);
@@ -910,14 +929,21 @@ extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
extern void drm_crtc_probe_connector_modes(struct drm_device *dev, int maxX, int maxY);
extern bool drm_crtc_in_use(struct drm_crtc *crtc);
-extern int drm_connector_attach_property(struct drm_connector *connector,
- struct drm_property *property, uint64_t init_val);
+extern void drm_connector_attach_property(struct drm_connector *connector,
+ struct drm_property *property, uint64_t init_val);
+extern void drm_object_attach_property(struct drm_mode_object *obj,
+ struct drm_property *property,
+ uint64_t init_val);
extern struct drm_property *drm_property_create(struct drm_device *dev, int flags,
const char *name, int num_values);
extern struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
const char *name,
const struct drm_prop_enum_list *props,
int num_values);
+struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
+ int flags, const char *name,
+ const struct drm_prop_enum_list *props,
+ int num_values);
struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
const char *name,
uint64_t min, uint64_t max);
@@ -1012,10 +1038,11 @@ extern int drm_add_modes_noedid(struct drm_connector *connector,
int hdisplay, int vdisplay);
extern int drm_edid_header_is_valid(const u8 *raw_edid);
-extern bool drm_edid_block_valid(u8 *raw_edid);
+extern bool drm_edid_block_valid(u8 *raw_edid, int block);
extern bool drm_edid_is_valid(struct edid *edid);
struct drm_display_mode *drm_mode_find_dmt(struct drm_device *dev,
- int hsize, int vsize, int fresh);
+ int hsize, int vsize, int fresh,
+ bool rb);
extern int drm_mode_create_dumb_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv);
@@ -1023,7 +1050,16 @@ extern int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv);
extern int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv);
+extern int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+extern int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
int *bpp);
+extern int drm_format_num_planes(uint32_t format);
+extern int drm_format_plane_cpp(uint32_t format, int plane);
+extern int drm_format_horz_chroma_subsampling(uint32_t format);
+extern int drm_format_vert_chroma_subsampling(uint32_t format);
+
#endif /* __DRM_CRTC_H__ */
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index 37515d1afab3..7988e55c98d0 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -44,6 +44,13 @@ enum mode_set_atomic {
ENTER_ATOMIC_MODE_SET,
};
+/**
+ * drm_crtc_helper_funcs - helper operations for CRTCs
+ * @mode_fixup: try to fixup proposed mode for this connector
+ * @mode_set: set this mode
+ *
+ * The helper operations are called by the mid-layer CRTC helper.
+ */
struct drm_crtc_helper_funcs {
/*
* Control power levels on the CRTC. If the mode passed in is
@@ -76,6 +83,13 @@ struct drm_crtc_helper_funcs {
void (*disable)(struct drm_crtc *crtc);
};
+/**
+ * drm_encoder_helper_funcs - helper operations for encoders
+ * @mode_fixup: try to fixup proposed mode for this connector
+ * @mode_set: set this mode
+ *
+ * The helper operations are called by the mid-layer CRTC helper.
+ */
struct drm_encoder_helper_funcs {
void (*dpms)(struct drm_encoder *encoder, int mode);
void (*save)(struct drm_encoder *encoder);
@@ -97,6 +111,13 @@ struct drm_encoder_helper_funcs {
void (*disable)(struct drm_encoder *encoder);
};
+/**
+ * drm_connector_helper_funcs - helper operations for connectors
+ * @get_modes: get mode list for this connector
+ * @mode_valid: is this mode valid on the given connector?
+ *
+ * The helper operations are called by the mid-layer CRTC helper.
+ */
struct drm_connector_helper_funcs {
int (*get_modes)(struct drm_connector *connector);
int (*mode_valid)(struct drm_connector *connector,
@@ -145,6 +166,4 @@ extern void drm_helper_hpd_irq_event(struct drm_device *dev);
extern void drm_kms_helper_poll_disable(struct drm_device *dev);
extern void drm_kms_helper_poll_enable(struct drm_device *dev);
-extern int drm_format_num_planes(uint32_t format);
-
#endif
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
index 93df2d72750b..1744b18c06b3 100644
--- a/include/drm/drm_dp_helper.h
+++ b/include/drm/drm_dp_helper.h
@@ -72,6 +72,10 @@
#define DP_MAIN_LINK_CHANNEL_CODING 0x006
+#define DP_DOWN_STREAM_PORT_COUNT 0x007
+#define DP_PORT_COUNT_MASK 0x0f
+#define DP_OUI_SUPPORT (1 << 7)
+
#define DP_EDP_CONFIGURATION_CAP 0x00d
#define DP_TRAINING_AUX_RD_INTERVAL 0x00e
@@ -213,6 +217,10 @@
# define DP_TEST_NAK (1 << 1)
# define DP_TEST_EDID_CHECKSUM_WRITE (1 << 2)
+#define DP_SOURCE_OUI 0x300
+#define DP_SINK_OUI 0x400
+#define DP_BRANCH_OUI 0x500
+
#define DP_SET_POWER 0x600
# define DP_SET_POWER_D0 0x1
# define DP_SET_POWER_D3 0x2
diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h
index bcb9a66baa8c..0cac551c5347 100644
--- a/include/drm/drm_edid.h
+++ b/include/drm/drm_edid.h
@@ -90,12 +90,26 @@ struct detailed_data_monitor_range {
u8 min_hfreq_khz;
u8 max_hfreq_khz;
u8 pixel_clock_mhz; /* need to multiply by 10 */
- __le16 sec_gtf_toggle; /* A000=use above, 20=use below */
- u8 hfreq_start_khz; /* need to multiply by 2 */
- u8 c; /* need to divide by 2 */
- __le16 m;
- u8 k;
- u8 j; /* need to divide by 2 */
+ u8 flags;
+ union {
+ struct {
+ u8 reserved;
+ u8 hfreq_start_khz; /* need to multiply by 2 */
+ u8 c; /* need to divide by 2 */
+ __le16 m;
+ u8 k;
+ u8 j; /* need to divide by 2 */
+ } __attribute__((packed)) gtf2;
+ struct {
+ u8 version;
+ u8 data1; /* high 6 bits: extra clock resolution */
+ u8 data2; /* plus low 2 of above: max hactive */
+ u8 supported_aspects;
+ u8 flags; /* preferred aspect and blanking support */
+ u8 supported_scalings;
+ u8 preferred_refresh;
+ } __attribute__((packed)) cvt;
+ } formula;
} __attribute__((packed));
struct detailed_data_wpindex {
diff --git a/include/drm/drm_fixed.h b/include/drm/drm_fixed.h
index 4a08a664ff1f..0ead502e17d2 100644
--- a/include/drm/drm_fixed.h
+++ b/include/drm/drm_fixed.h
@@ -37,6 +37,7 @@ typedef union dfixed {
#define dfixed_init(A) { .full = dfixed_const((A)) }
#define dfixed_init_half(A) { .full = dfixed_const_half((A)) }
#define dfixed_trunc(A) ((A).full >> 12)
+#define dfixed_frac(A) ((A).full & ((1 << 12) - 1))
static inline u32 dfixed_floor(fixed20_12 A)
{
diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h
index 4a0aae38e160..5581980b14f6 100644
--- a/include/drm/drm_mode.h
+++ b/include/drm/drm_mode.h
@@ -230,6 +230,7 @@ struct drm_mode_get_connector {
#define DRM_MODE_PROP_IMMUTABLE (1<<2)
#define DRM_MODE_PROP_ENUM (1<<3) /* enumerated type with text strings */
#define DRM_MODE_PROP_BLOB (1<<4)
+#define DRM_MODE_PROP_BITMASK (1<<5) /* bitmask of enumerated types */
struct drm_mode_property_enum {
__u64 value;
@@ -254,6 +255,21 @@ struct drm_mode_connector_set_property {
__u32 connector_id;
};
+struct drm_mode_obj_get_properties {
+ __u64 props_ptr;
+ __u64 prop_values_ptr;
+ __u32 count_props;
+ __u32 obj_id;
+ __u32 obj_type;
+};
+
+struct drm_mode_obj_set_property {
+ __u64 value;
+ __u32 prop_id;
+ __u32 obj_id;
+ __u32 obj_type;
+};
+
struct drm_mode_get_blob {
__u32 blob_id;
__u32 length;
diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h
index e478de4e5d56..b6d7ce92eadd 100644
--- a/include/drm/exynos_drm.h
+++ b/include/drm/exynos_drm.h
@@ -29,6 +29,8 @@
#ifndef _EXYNOS_DRM_H_
#define _EXYNOS_DRM_H_
+#include "drm.h"
+
/**
* User-desired buffer creation information structure.
*
@@ -75,6 +77,21 @@ struct drm_exynos_gem_mmap {
};
/**
+ * A structure to gem information.
+ *
+ * @handle: a handle to gem object created.
+ * @flags: flag value including memory type and cache attribute and
+ * this value would be set by driver.
+ * @size: size to memory region allocated by gem and this size would
+ * be set by driver.
+ */
+struct drm_exynos_gem_info {
+ unsigned int handle;
+ unsigned int flags;
+ uint64_t size;
+};
+
+/**
* A structure for user connection request of virtual display.
*
* @connection: indicate whether doing connetion or not by user.
@@ -95,18 +112,64 @@ struct drm_exynos_plane_set_zpos {
/* memory type definitions. */
enum e_drm_exynos_gem_mem_type {
+ /* Physically Continuous memory and used as default. */
+ EXYNOS_BO_CONTIG = 0 << 0,
/* Physically Non-Continuous memory. */
EXYNOS_BO_NONCONTIG = 1 << 0,
- EXYNOS_BO_MASK = EXYNOS_BO_NONCONTIG
+ /* non-cachable mapping and used as default. */
+ EXYNOS_BO_NONCACHABLE = 0 << 1,
+ /* cachable mapping. */
+ EXYNOS_BO_CACHABLE = 1 << 1,
+ /* write-combine mapping. */
+ EXYNOS_BO_WC = 1 << 2,
+ EXYNOS_BO_MASK = EXYNOS_BO_NONCONTIG | EXYNOS_BO_CACHABLE |
+ EXYNOS_BO_WC
+};
+
+struct drm_exynos_g2d_get_ver {
+ __u32 major;
+ __u32 minor;
+};
+
+struct drm_exynos_g2d_cmd {
+ __u32 offset;
+ __u32 data;
+};
+
+enum drm_exynos_g2d_event_type {
+ G2D_EVENT_NOT,
+ G2D_EVENT_NONSTOP,
+ G2D_EVENT_STOP, /* not yet */
+};
+
+struct drm_exynos_g2d_set_cmdlist {
+ __u64 cmd;
+ __u64 cmd_gem;
+ __u32 cmd_nr;
+ __u32 cmd_gem_nr;
+
+ /* for g2d event */
+ __u64 event_type;
+ __u64 user_data;
+};
+
+struct drm_exynos_g2d_exec {
+ __u64 async;
};
#define DRM_EXYNOS_GEM_CREATE 0x00
#define DRM_EXYNOS_GEM_MAP_OFFSET 0x01
#define DRM_EXYNOS_GEM_MMAP 0x02
/* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */
+#define DRM_EXYNOS_GEM_GET 0x04
#define DRM_EXYNOS_PLANE_SET_ZPOS 0x06
#define DRM_EXYNOS_VIDI_CONNECTION 0x07
+/* G2D */
+#define DRM_EXYNOS_G2D_GET_VER 0x20
+#define DRM_EXYNOS_G2D_SET_CMDLIST 0x21
+#define DRM_EXYNOS_G2D_EXEC 0x22
+
#define DRM_IOCTL_EXYNOS_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \
DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create)
@@ -116,12 +179,34 @@ enum e_drm_exynos_gem_mem_type {
#define DRM_IOCTL_EXYNOS_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + \
DRM_EXYNOS_GEM_MMAP, struct drm_exynos_gem_mmap)
+#define DRM_IOCTL_EXYNOS_GEM_GET DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_EXYNOS_GEM_GET, struct drm_exynos_gem_info)
+
#define DRM_IOCTL_EXYNOS_PLANE_SET_ZPOS DRM_IOWR(DRM_COMMAND_BASE + \
DRM_EXYNOS_PLANE_SET_ZPOS, struct drm_exynos_plane_set_zpos)
#define DRM_IOCTL_EXYNOS_VIDI_CONNECTION DRM_IOWR(DRM_COMMAND_BASE + \
DRM_EXYNOS_VIDI_CONNECTION, struct drm_exynos_vidi_connection)
+#define DRM_IOCTL_EXYNOS_G2D_GET_VER DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_EXYNOS_G2D_GET_VER, struct drm_exynos_g2d_get_ver)
+#define DRM_IOCTL_EXYNOS_G2D_SET_CMDLIST DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_EXYNOS_G2D_SET_CMDLIST, struct drm_exynos_g2d_set_cmdlist)
+#define DRM_IOCTL_EXYNOS_G2D_EXEC DRM_IOWR(DRM_COMMAND_BASE + \
+ DRM_EXYNOS_G2D_EXEC, struct drm_exynos_g2d_exec)
+
+/* EXYNOS specific events */
+#define DRM_EXYNOS_G2D_EVENT 0x80000000
+
+struct drm_exynos_g2d_event {
+ struct drm_event base;
+ __u64 user_data;
+ __u32 tv_sec;
+ __u32 tv_usec;
+ __u32 cmdlist_no;
+ __u32 reserved;
+};
+
#ifdef __KERNEL__
/**
@@ -169,16 +254,14 @@ struct exynos_drm_common_hdmi_pd {
/**
* Platform Specific Structure for DRM based HDMI core.
*
- * @timing: default video mode for initializing
- * @default_win: default window layer number to be used for UI.
- * @bpp: default bit per pixel.
* @is_v13: set if hdmi version 13 is.
+ * @cfg_hpd: function pointer to configure hdmi hotplug detection pin
+ * @get_hpd: function pointer to get value of hdmi hotplug detection pin
*/
struct exynos_drm_hdmi_pdata {
- struct fb_videomode timing;
- unsigned int default_win;
- unsigned int bpp;
- unsigned int is_v13:1;
+ bool is_v13;
+ void (*cfg_hpd)(bool external);
+ int (*get_hpd)(void);
};
#endif /* __KERNEL__ */
diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h
index da929bb5b788..f3f82242bf1d 100644
--- a/include/drm/i915_drm.h
+++ b/include/drm/i915_drm.h
@@ -296,7 +296,8 @@ typedef struct drm_i915_irq_wait {
#define I915_PARAM_HAS_EXEC_CONSTANTS 14
#define I915_PARAM_HAS_RELAXED_DELTA 15
#define I915_PARAM_HAS_GEN7_SOL_RESET 16
-#define I915_PARAM_HAS_LLC 17
+#define I915_PARAM_HAS_LLC 17
+#define I915_PARAM_HAS_ALIASING_PPGTT 18
typedef struct drm_i915_getparam {
int param;
diff --git a/include/drm/radeon_drm.h b/include/drm/radeon_drm.h
index 7c491b4bcf65..58056865b8e9 100644
--- a/include/drm/radeon_drm.h
+++ b/include/drm/radeon_drm.h
@@ -926,7 +926,6 @@ struct drm_radeon_cs_chunk {
};
/* drm_radeon_cs_reloc.flags */
-#define RADEON_RELOC_DONT_SYNC 0x01
struct drm_radeon_cs_reloc {
uint32_t handle;
diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h
index 974c8f801c39..e15f2a89a270 100644
--- a/include/drm/ttm/ttm_bo_api.h
+++ b/include/drm/ttm/ttm_bo_api.h
@@ -124,11 +124,15 @@ struct ttm_mem_reg {
*
* @ttm_bo_type_kernel: These buffers are like ttm_bo_type_device buffers,
* but they cannot be accessed from user-space. For kernel-only use.
+ *
+ * @ttm_bo_type_sg: Buffer made from dmabuf sg table shared with another
+ * driver.
*/
enum ttm_bo_type {
ttm_bo_type_device,
- ttm_bo_type_kernel
+ ttm_bo_type_kernel,
+ ttm_bo_type_sg
};
struct ttm_tt;
@@ -271,6 +275,8 @@ struct ttm_buffer_object {
unsigned long offset;
uint32_t cur_placement;
+
+ struct sg_table *sg;
};
/**
@@ -503,6 +509,7 @@ extern int ttm_bo_init(struct ttm_bo_device *bdev,
bool interrubtible,
struct file *persistent_swap_storage,
size_t acc_size,
+ struct sg_table *sg,
void (*destroy) (struct ttm_buffer_object *));
/**
diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h
index d43e892307ff..a05f1b55714d 100644
--- a/include/drm/ttm/ttm_bo_driver.h
+++ b/include/drm/ttm/ttm_bo_driver.h
@@ -81,6 +81,7 @@ struct ttm_backend_func {
#define TTM_PAGE_FLAG_PERSISTENT_SWAP (1 << 5)
#define TTM_PAGE_FLAG_ZERO_ALLOC (1 << 6)
#define TTM_PAGE_FLAG_DMA32 (1 << 7)
+#define TTM_PAGE_FLAG_SG (1 << 8)
enum ttm_caching_state {
tt_uncached,
@@ -116,6 +117,7 @@ struct ttm_tt {
struct page **pages;
uint32_t page_flags;
unsigned long num_pages;
+ struct sg_table *sg; /* for SG objects via dma-buf */
struct ttm_bo_global *glob;
struct ttm_backend *be;
struct file *swap_storage;
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 0237b84ba541..4cd59b95858f 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -238,6 +238,7 @@ header-y += map_to_7segment.h
header-y += matroxfb.h
header-y += mdio.h
header-y += media.h
+header-y += mei.h
header-y += mempolicy.h
header-y += meye.h
header-y += mii.h
@@ -269,6 +270,7 @@ header-y += netfilter_ipv4.h
header-y += netfilter_ipv6.h
header-y += netlink.h
header-y += netrom.h
+header-y += nfc.h
header-y += nfs.h
header-y += nfs2.h
header-y += nfs3.h
@@ -380,7 +382,9 @@ header-y += unistd.h
header-y += usbdevice_fs.h
header-y += utime.h
header-y += utsname.h
+header-y += uuid.h
header-y += uvcvideo.h
+header-y += v4l2-dv-timings.h
header-y += v4l2-mediabus.h
header-y += v4l2-subdev.h
header-y += veth.h
diff --git a/include/linux/alarmtimer.h b/include/linux/alarmtimer.h
index 975009e1cbe6..96c5c249b086 100644
--- a/include/linux/alarmtimer.h
+++ b/include/linux/alarmtimer.h
@@ -76,4 +76,7 @@ static inline int alarmtimer_callback_running(struct alarm *timer)
}
+/* Provide way to access the rtc device being used by alarmtimers */
+struct rtc_device *alarmtimer_get_rtcdev(void);
+
#endif
diff --git a/include/linux/basic_mmio_gpio.h b/include/linux/basic_mmio_gpio.h
index feb912196745..1c504ca5bdb3 100644
--- a/include/linux/basic_mmio_gpio.h
+++ b/include/linux/basic_mmio_gpio.h
@@ -67,6 +67,10 @@ int bgpio_remove(struct bgpio_chip *bgc);
int bgpio_init(struct bgpio_chip *bgc, struct device *dev,
unsigned long sz, void __iomem *dat, void __iomem *set,
void __iomem *clr, void __iomem *dirout, void __iomem *dirin,
- bool big_endian);
+ unsigned long flags);
+
+#define BGPIOF_BIG_ENDIAN BIT(0)
+#define BGPIOF_UNREADABLE_REG_SET BIT(1) /* reg_set is unreadable */
+#define BGPIOF_UNREADABLE_REG_DIR BIT(2) /* reg_dir is unreadable */
#endif /* __BASIC_MMIO_GPIO_H */
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index 5af9a075498f..8deaf6d050c3 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -26,6 +26,11 @@ struct bcma_chipinfo {
u8 pkg;
};
+struct bcma_boardinfo {
+ u16 vendor;
+ u16 type;
+};
+
enum bcma_clkmode {
BCMA_CLKMODE_FAST,
BCMA_CLKMODE_DYNAMIC,
@@ -139,6 +144,7 @@ struct bcma_device {
u8 core_unit;
u32 addr;
+ u32 addr1;
u32 wrap;
void __iomem *io_addr;
@@ -198,6 +204,8 @@ struct bcma_bus {
struct bcma_chipinfo chipinfo;
+ struct bcma_boardinfo boardinfo;
+
struct bcma_device *mapped_core;
struct list_head cores;
u8 nr_cores;
diff --git a/include/linux/bcma/bcma_driver_pci.h b/include/linux/bcma/bcma_driver_pci.h
index 46c71e27d31f..41da581e1612 100644
--- a/include/linux/bcma/bcma_driver_pci.h
+++ b/include/linux/bcma/bcma_driver_pci.h
@@ -87,6 +87,13 @@ struct pci_dev;
#define BCMA_CORE_PCI_PCICFG2 0x0600 /* PCI config space 2 (rev >= 8) */
#define BCMA_CORE_PCI_PCICFG3 0x0700 /* PCI config space 3 (rev >= 8) */
#define BCMA_CORE_PCI_SPROM(wordoffset) (0x0800 + ((wordoffset) * 2)) /* SPROM shadow area (72 bytes) */
+#define BCMA_CORE_PCI_SPROM_PI_OFFSET 0 /* first word */
+#define BCMA_CORE_PCI_SPROM_PI_MASK 0xf000 /* bit 15:12 */
+#define BCMA_CORE_PCI_SPROM_PI_SHIFT 12 /* bit 15:12 */
+#define BCMA_CORE_PCI_SPROM_MISC_CONFIG 5 /* word 5 */
+#define BCMA_CORE_PCI_SPROM_L23READY_EXIT_NOPERST 0x8000 /* bit 15 */
+#define BCMA_CORE_PCI_SPROM_CLKREQ_OFFSET_REV5 20 /* word 20 for srom rev <= 5 */
+#define BCMA_CORE_PCI_SPROM_CLKREQ_ENB 0x0800 /* bit 11 */
/* SBtoPCIx */
#define BCMA_CORE_PCI_SBTOPCI_MEM 0x00000000
@@ -133,6 +140,7 @@ struct pci_dev;
#define BCMA_CORE_PCI_DLLP_LRREG 0x120 /* Link Replay */
#define BCMA_CORE_PCI_DLLP_LACKTOREG 0x124 /* Link Ack Timeout */
#define BCMA_CORE_PCI_DLLP_PMTHRESHREG 0x128 /* Power Management Threshold */
+#define BCMA_CORE_PCI_ASPMTIMER_EXTEND 0x01000000 /* > rev7: enable extend ASPM timer */
#define BCMA_CORE_PCI_DLLP_RTRYWPREG 0x12C /* Retry buffer write ptr */
#define BCMA_CORE_PCI_DLLP_RTRYRPREG 0x130 /* Retry buffer Read ptr */
#define BCMA_CORE_PCI_DLLP_RTRYPPREG 0x134 /* Retry buffer Purged ptr */
@@ -201,12 +209,15 @@ struct bcma_drv_pci {
};
/* Register access */
+#define pcicore_read16(pc, offset) bcma_read16((pc)->core, offset)
#define pcicore_read32(pc, offset) bcma_read32((pc)->core, offset)
+#define pcicore_write16(pc, offset, val) bcma_write16((pc)->core, offset, val)
#define pcicore_write32(pc, offset, val) bcma_write32((pc)->core, offset, val)
extern void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc);
extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc,
struct bcma_device *core, bool enable);
+extern void bcma_core_pci_extend_L1timer(struct bcma_drv_pci *pc, bool extend);
extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev);
extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev);
diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h
index 66d3e954eb6c..1a0cd270bb7a 100644
--- a/include/linux/bootmem.h
+++ b/include/linux/bootmem.h
@@ -154,7 +154,8 @@ extern void *alloc_large_system_hash(const char *tablename,
int flags,
unsigned int *_hash_shift,
unsigned int *_hash_mask,
- unsigned long limit);
+ unsigned long low_limit,
+ unsigned long high_limit);
#define HASH_EARLY 0x00000001 /* Allocating during early boot? */
#define HASH_SMALL 0x00000002 /* sub-page allocation allowed, min
diff --git a/include/linux/capability.h b/include/linux/capability.h
index 12d52dedb229..68d56effc328 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -360,8 +360,11 @@ struct cpu_vfs_cap_data {
#define CAP_WAKE_ALARM 35
+/* Allow preventing system suspends while epoll events are pending */
-#define CAP_LAST_CAP CAP_WAKE_ALARM
+#define CAP_EPOLLWAKEUP 36
+
+#define CAP_LAST_CAP CAP_EPOLLWAKEUP
#define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
@@ -374,6 +377,7 @@ struct cpu_vfs_cap_data {
#ifdef __KERNEL__
+struct inode;
struct dentry;
struct user_namespace;
@@ -548,6 +552,7 @@ extern bool has_ns_capability_noaudit(struct task_struct *t,
extern bool capable(int cap);
extern bool ns_capable(struct user_namespace *ns, int cap);
extern bool nsown_capable(int cap);
+extern bool inode_capable(const struct inode *inode, int cap);
/* audit system wants to get cap info from files as well */
extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps);
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 5a85b3415c1b..d3f5fba2c159 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -16,6 +16,7 @@
#include <linux/prio_heap.h>
#include <linux/rwsem.h>
#include <linux/idr.h>
+#include <linux/workqueue.h>
#ifdef CONFIG_CGROUPS
@@ -76,12 +77,16 @@ struct cgroup_subsys_state {
unsigned long flags;
/* ID for this css, if possible */
struct css_id __rcu *id;
+
+ /* Used to put @cgroup->dentry on the last css_put() */
+ struct work_struct dput_work;
};
/* bits in struct cgroup_subsys_state flags field */
enum {
CSS_ROOT, /* This CSS is the root of the subsystem */
CSS_REMOVED, /* This CSS is dead */
+ CSS_CLEAR_CSS_REFS, /* @ss->__DEPRECATED_clear_css_refs */
};
/* Caller must verify that the css is not for root cgroup */
@@ -115,16 +120,12 @@ static inline bool css_is_removed(struct cgroup_subsys_state *css)
* the css has been destroyed.
*/
+extern bool __css_tryget(struct cgroup_subsys_state *css);
static inline bool css_tryget(struct cgroup_subsys_state *css)
{
if (test_bit(CSS_ROOT, &css->flags))
return true;
- while (!atomic_inc_not_zero(&css->refcnt)) {
- if (test_bit(CSS_REMOVED, &css->flags))
- return false;
- cpu_relax();
- }
- return true;
+ return __css_tryget(css);
}
/*
@@ -132,11 +133,11 @@ static inline bool css_tryget(struct cgroup_subsys_state *css)
* css_get() or css_tryget()
*/
-extern void __css_put(struct cgroup_subsys_state *css, int count);
+extern void __css_put(struct cgroup_subsys_state *css);
static inline void css_put(struct cgroup_subsys_state *css)
{
if (!test_bit(CSS_ROOT, &css->flags))
- __css_put(css, 1);
+ __css_put(css);
}
/* bits in struct cgroup flags field */
@@ -175,6 +176,7 @@ struct cgroup {
*/
struct list_head sibling; /* my parent's children */
struct list_head children; /* my children */
+ struct list_head files; /* my files */
struct cgroup *parent; /* my parent */
struct dentry __rcu *dentry; /* cgroup fs entry, RCU protected */
@@ -191,6 +193,9 @@ struct cgroup {
*/
struct list_head css_sets;
+ struct list_head allcg_node; /* cgroupfs_root->allcg_list */
+ struct list_head cft_q_node; /* used during cftype add/rm */
+
/*
* Linked list running through all cgroups that can
* potentially be reaped by the release agent. Protected by
@@ -275,11 +280,17 @@ struct cgroup_map_cb {
* - the 'cftype' of the file is file->f_dentry->d_fsdata
*/
-#define MAX_CFTYPE_NAME 64
+/* cftype->flags */
+#define CFTYPE_ONLY_ON_ROOT (1U << 0) /* only create on root cg */
+#define CFTYPE_NOT_ON_ROOT (1U << 1) /* don't create onp root cg */
+
+#define MAX_CFTYPE_NAME 64
+
struct cftype {
/*
* By convention, the name should begin with the name of the
- * subsystem, followed by a period
+ * subsystem, followed by a period. Zero length string indicates
+ * end of cftype array.
*/
char name[MAX_CFTYPE_NAME];
int private;
@@ -295,6 +306,9 @@ struct cftype {
*/
size_t max_write_len;
+ /* CFTYPE_* flags */
+ unsigned int flags;
+
int (*open)(struct inode *inode, struct file *file);
ssize_t (*read)(struct cgroup *cgrp, struct cftype *cft,
struct file *file,
@@ -373,6 +387,16 @@ struct cftype {
struct eventfd_ctx *eventfd);
};
+/*
+ * cftype_sets describe cftypes belonging to a subsystem and are chained at
+ * cgroup_subsys->cftsets. Each cftset points to an array of cftypes
+ * terminated by zero length name.
+ */
+struct cftype_set {
+ struct list_head node; /* chained at subsys->cftsets */
+ const struct cftype *cfts;
+};
+
struct cgroup_scanner {
struct cgroup *cg;
int (*test_task)(struct task_struct *p, struct cgroup_scanner *scan);
@@ -382,21 +406,8 @@ struct cgroup_scanner {
void *data;
};
-/*
- * Add a new file to the given cgroup directory. Should only be
- * called by subsystems from within a populate() method
- */
-int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys,
- const struct cftype *cft);
-
-/*
- * Add a set of new files to the given cgroup directory. Should
- * only be called by subsystems from within a populate() method
- */
-int cgroup_add_files(struct cgroup *cgrp,
- struct cgroup_subsys *subsys,
- const struct cftype cft[],
- int count);
+int cgroup_add_cftypes(struct cgroup_subsys *ss, const struct cftype *cfts);
+int cgroup_rm_cftypes(struct cgroup_subsys *ss, const struct cftype *cfts);
int cgroup_is_removed(const struct cgroup *cgrp);
@@ -461,7 +472,6 @@ struct cgroup_subsys {
void (*fork)(struct task_struct *task);
void (*exit)(struct cgroup *cgrp, struct cgroup *old_cgrp,
struct task_struct *task);
- int (*populate)(struct cgroup_subsys *ss, struct cgroup *cgrp);
void (*post_clone)(struct cgroup *cgrp);
void (*bind)(struct cgroup *root);
@@ -474,6 +484,18 @@ struct cgroup_subsys {
* (not available in early_init time.)
*/
bool use_id;
+
+ /*
+ * If %true, cgroup removal will try to clear css refs by retrying
+ * ss->pre_destroy() until there's no css ref left. This behavior
+ * is strictly for backward compatibility and will be removed as
+ * soon as the current user (memcg) is updated.
+ *
+ * If %false, ss->pre_destroy() can't fail and cgroup removal won't
+ * wait for css refs to drop to zero before proceeding.
+ */
+ bool __DEPRECATED_clear_css_refs;
+
#define MAX_CGROUP_TYPE_NAMELEN 32
const char *name;
@@ -500,6 +522,13 @@ struct cgroup_subsys {
struct idr idr;
spinlock_t id_lock;
+ /* list of cftype_sets */
+ struct list_head cftsets;
+
+ /* base cftypes, automatically [de]registered with subsys itself */
+ struct cftype *base_cftypes;
+ struct cftype_set base_cftset;
+
/* should be defined only by modular subsystems */
struct module *module;
};
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index ee28844ae68e..7230bb59a06f 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -36,8 +36,6 @@ extern void cpu_remove_dev_attr(struct device_attribute *attr);
extern int cpu_add_dev_attr_group(struct attribute_group *attrs);
extern void cpu_remove_dev_attr_group(struct attribute_group *attrs);
-extern int sched_create_sysfs_power_savings_entries(struct device *dev);
-
#ifdef CONFIG_HOTPLUG_CPU
extern void unregister_cpu(struct cpu *cpu);
extern ssize_t arch_cpu_probe(const char *, size_t);
diff --git a/include/linux/cred.h b/include/linux/cred.h
index adadf71a7327..917dc5aeb1d4 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -17,6 +17,7 @@
#include <linux/key.h>
#include <linux/selinux.h>
#include <linux/atomic.h>
+#include <linux/uidgid.h>
struct user_struct;
struct cred;
@@ -26,14 +27,14 @@ struct inode;
* COW Supplementary groups list
*/
#define NGROUPS_SMALL 32
-#define NGROUPS_PER_BLOCK ((unsigned int)(PAGE_SIZE / sizeof(gid_t)))
+#define NGROUPS_PER_BLOCK ((unsigned int)(PAGE_SIZE / sizeof(kgid_t)))
struct group_info {
atomic_t usage;
int ngroups;
int nblocks;
- gid_t small_block[NGROUPS_SMALL];
- gid_t *blocks[0];
+ kgid_t small_block[NGROUPS_SMALL];
+ kgid_t *blocks[0];
};
/**
@@ -66,14 +67,14 @@ extern struct group_info init_groups;
extern void groups_free(struct group_info *);
extern int set_current_groups(struct group_info *);
extern int set_groups(struct cred *, struct group_info *);
-extern int groups_search(const struct group_info *, gid_t);
+extern int groups_search(const struct group_info *, kgid_t);
/* access the groups "array" with this macro */
#define GROUP_AT(gi, i) \
((gi)->blocks[(i) / NGROUPS_PER_BLOCK][(i) % NGROUPS_PER_BLOCK])
-extern int in_group_p(gid_t);
-extern int in_egroup_p(gid_t);
+extern int in_group_p(kgid_t);
+extern int in_egroup_p(kgid_t);
/*
* The common credentials for a thread group
@@ -122,14 +123,14 @@ struct cred {
#define CRED_MAGIC 0x43736564
#define CRED_MAGIC_DEAD 0x44656144
#endif
- uid_t uid; /* real UID of the task */
- gid_t gid; /* real GID of the task */
- uid_t suid; /* saved UID of the task */
- gid_t sgid; /* saved GID of the task */
- uid_t euid; /* effective UID of the task */
- gid_t egid; /* effective GID of the task */
- uid_t fsuid; /* UID for VFS ops */
- gid_t fsgid; /* GID for VFS ops */
+ kuid_t uid; /* real UID of the task */
+ kgid_t gid; /* real GID of the task */
+ kuid_t suid; /* saved UID of the task */
+ kgid_t sgid; /* saved GID of the task */
+ kuid_t euid; /* effective UID of the task */
+ kgid_t egid; /* effective GID of the task */
+ kuid_t fsuid; /* UID for VFS ops */
+ kgid_t fsgid; /* GID for VFS ops */
unsigned securebits; /* SUID-less security management */
kernel_cap_t cap_inheritable; /* caps our children can inherit */
kernel_cap_t cap_permitted; /* caps we're permitted */
@@ -146,7 +147,7 @@ struct cred {
void *security; /* subjective LSM security */
#endif
struct user_struct *user; /* real user ID subscription */
- struct user_namespace *user_ns; /* cached user->user_ns */
+ struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */
struct group_info *group_info; /* supplementary groups for euid/fsgid */
struct rcu_head rcu; /* RCU deletion hook */
};
@@ -357,11 +358,11 @@ static inline void put_cred(const struct cred *_cred)
#define current_user() (current_cred_xxx(user))
#define current_security() (current_cred_xxx(security))
+extern struct user_namespace init_user_ns;
#ifdef CONFIG_USER_NS
#define current_user_ns() (current_cred_xxx(user_ns))
#define task_user_ns(task) (task_cred_xxx((task), user_ns))
#else
-extern struct user_namespace init_user_ns;
#define current_user_ns() (&init_user_ns)
#define task_user_ns(task) (&init_user_ns)
#endif
diff --git a/include/linux/cs5535.h b/include/linux/cs5535.h
index c077aec3a6ff..cfe83239d7f0 100644
--- a/include/linux/cs5535.h
+++ b/include/linux/cs5535.h
@@ -95,6 +95,7 @@ static inline int cs5535_pic_unreqz_select_high(unsigned int group,
/* CS5536_PM1_STS bits */
#define CS5536_WAK_FLAG (1 << 15)
+#define CS5536_RTC_FLAG (1 << 10)
#define CS5536_PWRBTN_FLAG (1 << 8)
/* CS5536_PM1_EN bits */
diff --git a/include/linux/device.h b/include/linux/device.h
index 5ad17cccdd71..e04f5776f6d0 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -23,6 +23,7 @@
#include <linux/mutex.h>
#include <linux/pm.h>
#include <linux/atomic.h>
+#include <linux/ratelimit.h>
#include <asm/device.h>
struct device;
@@ -502,7 +503,10 @@ ssize_t device_store_int(struct device *dev, struct device_attribute *attr,
{ __ATTR(_name, _mode, device_show_ulong, device_store_ulong), &(_var) }
#define DEVICE_INT_ATTR(_name, _mode, _var) \
struct dev_ext_attribute dev_attr_##_name = \
- { __ATTR(_name, _mode, device_show_ulong, device_store_ulong), &(_var) }
+ { __ATTR(_name, _mode, device_show_int, device_store_int), &(_var) }
+#define DEVICE_ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) \
+ struct device_attribute dev_attr_##_name = \
+ __ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store)
extern int device_create_file(struct device *device,
const struct device_attribute *entry);
@@ -541,6 +545,8 @@ extern void *devres_remove(struct device *dev, dr_release_t release,
dr_match_t match, void *match_data);
extern int devres_destroy(struct device *dev, dr_release_t release,
dr_match_t match, void *match_data);
+extern int devres_release(struct device *dev, dr_release_t release,
+ dr_match_t match, void *match_data);
/* devres group */
extern void * __must_check devres_open_group(struct device *dev, void *id,
@@ -931,6 +937,32 @@ int _dev_info(const struct device *dev, const char *fmt, ...)
#endif
+#define dev_level_ratelimited(dev_level, dev, fmt, ...) \
+do { \
+ static DEFINE_RATELIMIT_STATE(_rs, \
+ DEFAULT_RATELIMIT_INTERVAL, \
+ DEFAULT_RATELIMIT_BURST); \
+ if (__ratelimit(&_rs)) \
+ dev_level(dev, fmt, ##__VA_ARGS__); \
+} while (0)
+
+#define dev_emerg_ratelimited(dev, fmt, ...) \
+ dev_level_ratelimited(dev_emerg, dev, fmt, ##__VA_ARGS__)
+#define dev_alert_ratelimited(dev, fmt, ...) \
+ dev_level_ratelimited(dev_alert, dev, fmt, ##__VA_ARGS__)
+#define dev_crit_ratelimited(dev, fmt, ...) \
+ dev_level_ratelimited(dev_crit, dev, fmt, ##__VA_ARGS__)
+#define dev_err_ratelimited(dev, fmt, ...) \
+ dev_level_ratelimited(dev_err, dev, fmt, ##__VA_ARGS__)
+#define dev_warn_ratelimited(dev, fmt, ...) \
+ dev_level_ratelimited(dev_warn, dev, fmt, ##__VA_ARGS__)
+#define dev_notice_ratelimited(dev, fmt, ...) \
+ dev_level_ratelimited(dev_notice, dev, fmt, ##__VA_ARGS__)
+#define dev_info_ratelimited(dev, fmt, ...) \
+ dev_level_ratelimited(dev_info, dev, fmt, ##__VA_ARGS__)
+#define dev_dbg_ratelimited(dev, fmt, ...) \
+ dev_level_ratelimited(dev_dbg, dev, fmt, ##__VA_ARGS__)
+
/*
* Stupid hackaround for existing uses of non-printk uses dev_info
*
diff --git a/include/linux/dlm.h b/include/linux/dlm.h
index 6c7f6e9546c7..520152411cd1 100644
--- a/include/linux/dlm.h
+++ b/include/linux/dlm.h
@@ -67,7 +67,6 @@ struct dlm_lksb {
/* dlm_new_lockspace() flags */
-#define DLM_LSFL_NODIR 0x00000001
#define DLM_LSFL_TIMEWARN 0x00000002
#define DLM_LSFL_FS 0x00000004
#define DLM_LSFL_NEWEXCL 0x00000008
diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h
index cb4428ab81ed..f50d4058c5fb 100644
--- a/include/linux/dvb/frontend.h
+++ b/include/linux/dvb/frontend.h
@@ -320,7 +320,24 @@ struct dvb_frontend_event {
#define DTV_ENUM_DELSYS 44
-#define DTV_MAX_COMMAND DTV_ENUM_DELSYS
+/* ATSC-MH */
+#define DTV_ATSCMH_FIC_VER 45
+#define DTV_ATSCMH_PARADE_ID 46
+#define DTV_ATSCMH_NOG 47
+#define DTV_ATSCMH_TNOG 48
+#define DTV_ATSCMH_SGN 49
+#define DTV_ATSCMH_PRC 50
+#define DTV_ATSCMH_RS_FRAME_MODE 51
+#define DTV_ATSCMH_RS_FRAME_ENSEMBLE 52
+#define DTV_ATSCMH_RS_CODE_MODE_PRI 53
+#define DTV_ATSCMH_RS_CODE_MODE_SEC 54
+#define DTV_ATSCMH_SCCC_BLOCK_MODE 55
+#define DTV_ATSCMH_SCCC_CODE_MODE_A 56
+#define DTV_ATSCMH_SCCC_CODE_MODE_B 57
+#define DTV_ATSCMH_SCCC_CODE_MODE_C 58
+#define DTV_ATSCMH_SCCC_CODE_MODE_D 59
+
+#define DTV_MAX_COMMAND DTV_ATSCMH_SCCC_CODE_MODE_D
typedef enum fe_pilot {
PILOT_ON,
@@ -360,6 +377,38 @@ typedef enum fe_delivery_system {
#define SYS_DVBC_ANNEX_AC SYS_DVBC_ANNEX_A
+/* ATSC-MH */
+
+enum atscmh_sccc_block_mode {
+ ATSCMH_SCCC_BLK_SEP = 0,
+ ATSCMH_SCCC_BLK_COMB = 1,
+ ATSCMH_SCCC_BLK_RES = 2,
+};
+
+enum atscmh_sccc_code_mode {
+ ATSCMH_SCCC_CODE_HLF = 0,
+ ATSCMH_SCCC_CODE_QTR = 1,
+ ATSCMH_SCCC_CODE_RES = 2,
+};
+
+enum atscmh_rs_frame_ensemble {
+ ATSCMH_RSFRAME_ENS_PRI = 0,
+ ATSCMH_RSFRAME_ENS_SEC = 1,
+};
+
+enum atscmh_rs_frame_mode {
+ ATSCMH_RSFRAME_PRI_ONLY = 0,
+ ATSCMH_RSFRAME_PRI_SEC = 1,
+ ATSCMH_RSFRAME_RES = 2,
+};
+
+enum atscmh_rs_code_mode {
+ ATSCMH_RSCODE_211_187 = 0,
+ ATSCMH_RSCODE_223_187 = 1,
+ ATSCMH_RSCODE_235_187 = 2,
+ ATSCMH_RSCODE_RES = 3,
+};
+
struct dtv_cmds_h {
char *name; /* A display name for debugging purposes */
diff --git a/include/linux/dvb/version.h b/include/linux/dvb/version.h
index 0559e2bd38f9..43d9e8d462d4 100644
--- a/include/linux/dvb/version.h
+++ b/include/linux/dvb/version.h
@@ -24,6 +24,6 @@
#define _DVBVERSION_H_
#define DVB_API_VERSION 5
-#define DVB_API_VERSION_MINOR 5
+#define DVB_API_VERSION_MINOR 6
#endif /*_DVBVERSION_H_*/
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index 7e3c53a900d8..c18257b0fa72 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -17,8 +17,8 @@ struct _ddebug {
const char *format;
unsigned int lineno:18;
/*
- * The flags field controls the behaviour at the callsite.
- * The bits here are changed dynamically when the user
+ * The flags field controls the behaviour at the callsite.
+ * The bits here are changed dynamically when the user
* writes commands to <debugfs>/dynamic_debug/control
*/
#define _DPRINTK_FLAGS_NONE 0
@@ -44,6 +44,9 @@ extern int ddebug_remove_module(const char *mod_name);
extern __printf(2, 3)
int __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...);
+extern int ddebug_dyndbg_module_param_cb(char *param, char *val,
+ const char *modname);
+
struct device;
extern __printf(3, 4)
@@ -94,11 +97,26 @@ do { \
#else
+#include <linux/string.h>
+#include <linux/errno.h>
+
static inline int ddebug_remove_module(const char *mod)
{
return 0;
}
+static inline int ddebug_dyndbg_module_param_cb(char *param, char *val,
+ const char *modname)
+{
+ if (strstr(param, "dyndbg")) {
+ /* avoid pr_warn(), which wants pr_fmt() fully defined */
+ printk(KERN_WARNING "dyndbg param is supported only in "
+ "CONFIG_DYNAMIC_DEBUG builds\n");
+ return 0; /* allow and ignore */
+ }
+ return -EINVAL;
+}
+
#define dynamic_pr_debug(fmt, ...) \
do { if (0) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); } while (0)
#define dynamic_dev_dbg(dev, fmt, ...) \
diff --git a/include/linux/eventpoll.h b/include/linux/eventpoll.h
index 657ab55beda0..6f8be328770a 100644
--- a/include/linux/eventpoll.h
+++ b/include/linux/eventpoll.h
@@ -26,6 +26,18 @@
#define EPOLL_CTL_DEL 2
#define EPOLL_CTL_MOD 3
+/*
+ * Request the handling of system wakeup events so as to prevent system suspends
+ * from happening while those events are being processed.
+ *
+ * Assuming neither EPOLLET nor EPOLLONESHOT is set, system suspends will not be
+ * re-allowed until epoll_wait is called again after consuming the wakeup
+ * event(s).
+ *
+ * Requires CAP_EPOLLWAKEUP
+ */
+#define EPOLLWAKEUP (1 << 29)
+
/* Set the One Shot behaviour for the target file descriptor */
#define EPOLLONESHOT (1 << 30)
diff --git a/include/linux/extcon.h b/include/linux/extcon.h
new file mode 100644
index 000000000000..cdd401477656
--- /dev/null
+++ b/include/linux/extcon.h
@@ -0,0 +1,324 @@
+/*
+ * External connector (extcon) class driver
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Author: Donggeun Kim <dg77.kim@samsung.com>
+ * Author: MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * based on switch class driver
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __LINUX_EXTCON_H__
+#define __LINUX_EXTCON_H__
+
+#include <linux/notifier.h>
+
+#define SUPPORTED_CABLE_MAX 32
+#define CABLE_NAME_MAX 30
+
+/*
+ * The standard cable name is to help support general notifier
+ * and notifee device drivers to share the common names.
+ * Please use standard cable names unless your notifier device has
+ * a very unique and abnormal cable or
+ * the cable type is supposed to be used with only one unique
+ * pair of notifier/notifee devices.
+ *
+ * Please add any other "standard" cables used with extcon dev.
+ *
+ * You may add a dot and number to specify version or specification
+ * of the specific cable if it is required. (e.g., "Fast-charger.18"
+ * and "Fast-charger.10" for 1.8A and 1.0A chargers)
+ * However, the notifee and notifier should be able to handle such
+ * string and if the notifee can negotiate the protocol or idenify,
+ * you don't need such convention. This convention is helpful when
+ * notifier can distinguish but notifiee cannot.
+ */
+enum extcon_cable_name {
+ EXTCON_USB = 0,
+ EXTCON_USB_HOST,
+ EXTCON_TA, /* Travel Adaptor */
+ EXTCON_FAST_CHARGER,
+ EXTCON_SLOW_CHARGER,
+ EXTCON_CHARGE_DOWNSTREAM, /* Charging an external device */
+ EXTCON_HDMI,
+ EXTCON_MHL,
+ EXTCON_DVI,
+ EXTCON_VGA,
+ EXTCON_DOCK,
+ EXTCON_LINE_IN,
+ EXTCON_LINE_OUT,
+ EXTCON_MIC_IN,
+ EXTCON_HEADPHONE_OUT,
+ EXTCON_SPDIF_IN,
+ EXTCON_SPDIF_OUT,
+ EXTCON_VIDEO_IN,
+ EXTCON_VIDEO_OUT,
+ EXTCON_MECHANICAL,
+};
+extern const char *extcon_cable_name[];
+
+struct extcon_cable;
+
+/**
+ * struct extcon_dev - An extcon device represents one external connector.
+ * @name The name of this extcon device. Parent device name is used
+ * if NULL.
+ * @supported_cable Array of supported cable name ending with NULL.
+ * If supported_cable is NULL, cable name related APIs
+ * are disabled.
+ * @mutually_exclusive Array of mutually exclusive set of cables that cannot
+ * be attached simultaneously. The array should be
+ * ending with NULL or be NULL (no mutually exclusive
+ * cables). For example, if it is { 0x7, 0x30, 0}, then,
+ * {0, 1}, {0, 1, 2}, {0, 2}, {1, 2}, or {4, 5} cannot
+ * be attached simulataneously. {0x7, 0} is equivalent to
+ * {0x3, 0x6, 0x5, 0}. If it is {0xFFFFFFFF, 0}, there
+ * can be no simultaneous connections.
+ * @print_name An optional callback to override the method to print the
+ * name of the extcon device.
+ * @print_state An optional callback to override the method to print the
+ * status of the extcon device.
+ * @dev Device of this extcon. Do not provide at register-time.
+ * @state Attach/detach state of this extcon. Do not provide at
+ * register-time
+ * @nh Notifier for the state change events from this extcon
+ * @entry To support list of extcon devices so that uses can search
+ * for extcon devices based on the extcon name.
+ * @lock
+ * @max_supported Internal value to store the number of cables.
+ * @extcon_dev_type Device_type struct to provide attribute_groups
+ * customized for each extcon device.
+ * @cables Sysfs subdirectories. Each represents one cable.
+ *
+ * In most cases, users only need to provide "User initializing data" of
+ * this struct when registering an extcon. In some exceptional cases,
+ * optional callbacks may be needed. However, the values in "internal data"
+ * are overwritten by register function.
+ */
+struct extcon_dev {
+ /* --- Optional user initializing data --- */
+ const char *name;
+ const char **supported_cable;
+ const u32 *mutually_exclusive;
+
+ /* --- Optional callbacks to override class functions --- */
+ ssize_t (*print_name)(struct extcon_dev *edev, char *buf);
+ ssize_t (*print_state)(struct extcon_dev *edev, char *buf);
+
+ /* --- Internal data. Please do not set. --- */
+ struct device *dev;
+ u32 state;
+ struct raw_notifier_head nh;
+ struct list_head entry;
+ spinlock_t lock; /* could be called by irq handler */
+ int max_supported;
+
+ /* /sys/class/extcon/.../cable.n/... */
+ struct device_type extcon_dev_type;
+ struct extcon_cable *cables;
+ /* /sys/class/extcon/.../mutually_exclusive/... */
+ struct attribute_group attr_g_muex;
+ struct attribute **attrs_muex;
+ struct device_attribute *d_attrs_muex;
+};
+
+/**
+ * struct extcon_cable - An internal data for each cable of extcon device.
+ * @edev The extcon device
+ * @cable_index Index of this cable in the edev
+ * @attr_g Attribute group for the cable
+ * @attr_name "name" sysfs entry
+ * @attr_state "state" sysfs entry
+ * @attrs Array pointing to attr_name and attr_state for attr_g
+ */
+struct extcon_cable {
+ struct extcon_dev *edev;
+ int cable_index;
+
+ struct attribute_group attr_g;
+ struct device_attribute attr_name;
+ struct device_attribute attr_state;
+
+ struct attribute *attrs[3]; /* to be fed to attr_g.attrs */
+};
+
+/**
+ * struct extcon_specific_cable_nb - An internal data for
+ * extcon_register_interest().
+ * @internal_nb a notifier block bridging extcon notifier and cable notifier.
+ * @user_nb user provided notifier block for events from a specific cable.
+ * @cable_index the target cable.
+ * @edev the target extcon device.
+ * @previous_value the saved previous event value.
+ */
+struct extcon_specific_cable_nb {
+ struct notifier_block internal_nb;
+ struct notifier_block *user_nb;
+ int cable_index;
+ struct extcon_dev *edev;
+ unsigned long previous_value;
+};
+
+#if IS_ENABLED(CONFIG_EXTCON)
+
+/*
+ * Following APIs are for notifiers or configurations.
+ * Notifiers are the external port and connection devices.
+ */
+extern int extcon_dev_register(struct extcon_dev *edev, struct device *dev);
+extern void extcon_dev_unregister(struct extcon_dev *edev);
+extern struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name);
+
+/*
+ * get/set/update_state access the 32b encoded state value, which represents
+ * states of all possible cables of the multistate port. For example, if one
+ * calls extcon_set_state(edev, 0x7), it may mean that all the three cables
+ * are attached to the port.
+ */
+static inline u32 extcon_get_state(struct extcon_dev *edev)
+{
+ return edev->state;
+}
+
+extern int extcon_set_state(struct extcon_dev *edev, u32 state);
+extern int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state);
+
+/*
+ * get/set_cable_state access each bit of the 32b encoded state value.
+ * They are used to access the status of each cable based on the cable_name
+ * or cable_index, which is retrived by extcon_find_cable_index
+ */
+extern int extcon_find_cable_index(struct extcon_dev *sdev,
+ const char *cable_name);
+extern int extcon_get_cable_state_(struct extcon_dev *edev, int cable_index);
+extern int extcon_set_cable_state_(struct extcon_dev *edev, int cable_index,
+ bool cable_state);
+
+extern int extcon_get_cable_state(struct extcon_dev *edev,
+ const char *cable_name);
+extern int extcon_set_cable_state(struct extcon_dev *edev,
+ const char *cable_name, bool cable_state);
+
+/*
+ * Following APIs are for notifiees (those who want to be notified)
+ * to register a callback for events from a specific cable of the extcon.
+ * Notifiees are the connected device drivers wanting to get notified by
+ * a specific external port of a connection device.
+ */
+extern int extcon_register_interest(struct extcon_specific_cable_nb *obj,
+ const char *extcon_name,
+ const char *cable_name,
+ struct notifier_block *nb);
+extern int extcon_unregister_interest(struct extcon_specific_cable_nb *nb);
+
+/*
+ * Following APIs are to monitor every action of a notifier.
+ * Registerer gets notified for every external port of a connection device.
+ * Probably this could be used to debug an action of notifier; however,
+ * we do not recommend to use this at normal 'notifiee' device drivers who
+ * want to be notified by a specific external port of the notifier.
+ */
+extern int extcon_register_notifier(struct extcon_dev *edev,
+ struct notifier_block *nb);
+extern int extcon_unregister_notifier(struct extcon_dev *edev,
+ struct notifier_block *nb);
+#else /* CONFIG_EXTCON */
+static inline int extcon_dev_register(struct extcon_dev *edev,
+ struct device *dev)
+{
+ return 0;
+}
+
+static inline void extcon_dev_unregister(struct extcon_dev *edev) { }
+
+static inline u32 extcon_get_state(struct extcon_dev *edev)
+{
+ return 0;
+}
+
+static inline int extcon_set_state(struct extcon_dev *edev, u32 state)
+{
+ return 0;
+}
+
+static inline int extcon_update_state(struct extcon_dev *edev, u32 mask,
+ u32 state)
+{
+ return 0;
+}
+
+static inline int extcon_find_cable_index(struct extcon_dev *edev,
+ const char *cable_name)
+{
+ return 0;
+}
+
+static inline int extcon_get_cable_state_(struct extcon_dev *edev,
+ int cable_index)
+{
+ return 0;
+}
+
+static inline int extcon_set_cable_state_(struct extcon_dev *edev,
+ int cable_index, bool cable_state)
+{
+ return 0;
+}
+
+static inline int extcon_get_cable_state(struct extcon_dev *edev,
+ const char *cable_name)
+{
+ return 0;
+}
+
+static inline int extcon_set_cable_state(struct extcon_dev *edev,
+ const char *cable_name, int state)
+{
+ return 0;
+}
+
+static inline struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name)
+{
+ return NULL;
+}
+
+static inline int extcon_register_notifier(struct extcon_dev *edev,
+ struct notifier_block *nb)
+{
+ return 0;
+}
+
+static inline int extcon_unregister_notifier(struct extcon_dev *edev,
+ struct notifier_block *nb)
+{
+ return 0;
+}
+
+static inline int extcon_register_interest(struct extcon_specific_cable_nb *obj,
+ const char *extcon_name,
+ const char *cable_name,
+ struct notifier_block *nb)
+{
+ return 0;
+}
+
+static inline int extcon_unregister_interest(struct extcon_specific_cable_nb
+ *obj)
+{
+ return 0;
+}
+#endif /* CONFIG_EXTCON */
+#endif /* __LINUX_EXTCON_H__ */
diff --git a/include/linux/extcon/extcon_gpio.h b/include/linux/extcon/extcon_gpio.h
new file mode 100644
index 000000000000..a2129b73dcb1
--- /dev/null
+++ b/include/linux/extcon/extcon_gpio.h
@@ -0,0 +1,52 @@
+/*
+ * External connector (extcon) class generic GPIO driver
+ *
+ * Copyright (C) 2012 Samsung Electronics
+ * Author: MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * based on switch class driver
+ * Copyright (C) 2008 Google, Inc.
+ * Author: Mike Lockwood <lockwood@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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 __EXTCON_GPIO_H__
+#define __EXTCON_GPIO_H__ __FILE__
+
+#include <linux/extcon.h>
+
+/**
+ * struct gpio_extcon_platform_data - A simple GPIO-controlled extcon device.
+ * @name The name of this GPIO extcon device.
+ * @gpio Corresponding GPIO.
+ * @debounce Debounce time for GPIO IRQ in ms.
+ * @irq_flags IRQ Flags (e.g., IRQF_TRIGGER_LOW).
+ * @state_on print_state is overriden with state_on if attached. If Null,
+ * default method of extcon class is used.
+ * @state_off print_state is overriden with state_on if dettached. If Null,
+ * default method of extcon class is used.
+ *
+ * Note that in order for state_on or state_off to be valid, both state_on
+ * and state_off should be not NULL. If at least one of them is NULL,
+ * the print_state is not overriden.
+ */
+struct gpio_extcon_platform_data {
+ const char *name;
+ unsigned gpio;
+ unsigned long debounce;
+ unsigned long irq_flags;
+
+ /* if NULL, "0" or "1" will be printed */
+ const char *state_on;
+ const char *state_off;
+};
+
+#endif /* __EXTCON_GPIO_H__ */
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
index cdc9b719e9c7..7edcf1031718 100644
--- a/include/linux/firewire.h
+++ b/include/linux/firewire.h
@@ -135,6 +135,20 @@ struct fw_card {
__be32 maint_utility_register;
};
+static inline struct fw_card *fw_card_get(struct fw_card *card)
+{
+ kref_get(&card->kref);
+
+ return card;
+}
+
+void fw_card_release(struct kref *kref);
+
+static inline void fw_card_put(struct fw_card *card)
+{
+ kref_put(&card->kref, fw_card_release);
+}
+
struct fw_attribute_group {
struct attribute_group *groups[2];
struct attribute_group group;
@@ -325,6 +339,7 @@ int fw_core_add_address_handler(struct fw_address_handler *handler,
void fw_core_remove_address_handler(struct fw_address_handler *handler);
void fw_send_response(struct fw_card *card,
struct fw_request *request, int rcode);
+int fw_get_request_speed(struct fw_request *request);
void fw_send_request(struct fw_card *card, struct fw_transaction *t,
int tcode, int destination_id, int generation, int speed,
unsigned long long offset, void *payload, size_t length,
@@ -334,6 +349,7 @@ int fw_cancel_transaction(struct fw_card *card,
int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
int generation, int speed, unsigned long long offset,
void *payload, size_t length);
+const char *fw_rcode_string(int rcode);
static inline int fw_stream_packet_destination_id(int tag, int channel, int sy)
{
@@ -391,6 +407,7 @@ struct fw_iso_buffer {
enum dma_data_direction direction;
struct page **pages;
int page_count;
+ int page_count_mapped;
};
int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
diff --git a/drivers/input/fixp-arith.h b/include/linux/fixp-arith.h
index 3089d7382325..3089d7382325 100644
--- a/drivers/input/fixp-arith.h
+++ b/include/linux/fixp-arith.h
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 25c40b9f848a..c0e53372b082 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -402,6 +402,7 @@ struct inodes_stat_t {
#include <linux/atomic.h>
#include <linux/shrinker.h>
#include <linux/migrate_mode.h>
+#include <linux/uidgid.h>
#include <asm/byteorder.h>
@@ -469,8 +470,8 @@ typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
struct iattr {
unsigned int ia_valid;
umode_t ia_mode;
- uid_t ia_uid;
- gid_t ia_gid;
+ kuid_t ia_uid;
+ kgid_t ia_gid;
loff_t ia_size;
struct timespec ia_atime;
struct timespec ia_mtime;
@@ -761,8 +762,8 @@ struct posix_acl;
struct inode {
umode_t i_mode;
unsigned short i_opflags;
- uid_t i_uid;
- gid_t i_gid;
+ kuid_t i_uid;
+ kgid_t i_gid;
unsigned int i_flags;
#ifdef CONFIG_FS_POSIX_ACL
@@ -927,6 +928,31 @@ static inline void i_size_write(struct inode *inode, loff_t i_size)
#endif
}
+/* Helper functions so that in most cases filesystems will
+ * not need to deal directly with kuid_t and kgid_t and can
+ * instead deal with the raw numeric values that are stored
+ * in the filesystem.
+ */
+static inline uid_t i_uid_read(const struct inode *inode)
+{
+ return from_kuid(&init_user_ns, inode->i_uid);
+}
+
+static inline gid_t i_gid_read(const struct inode *inode)
+{
+ return from_kgid(&init_user_ns, inode->i_gid);
+}
+
+static inline void i_uid_write(struct inode *inode, uid_t uid)
+{
+ inode->i_uid = make_kuid(&init_user_ns, uid);
+}
+
+static inline void i_gid_write(struct inode *inode, gid_t gid)
+{
+ inode->i_gid = make_kgid(&init_user_ns, gid);
+}
+
static inline unsigned iminor(const struct inode *inode)
{
return MINOR(inode->i_rdev);
@@ -943,7 +969,7 @@ struct fown_struct {
rwlock_t lock; /* protects pid, uid, euid fields */
struct pid *pid; /* pid or -pgrp where SIGIO should be sent */
enum pid_type pid_type; /* Kind of process group SIGIO should be sent to */
- uid_t uid, euid; /* uid/euid of process setting the owner */
+ kuid_t uid, euid; /* uid/euid of process setting the owner */
int signum; /* posix.1b rt signal to be delivered on IO */
};
@@ -1527,12 +1553,6 @@ enum {
#define vfs_check_frozen(sb, level) \
wait_event((sb)->s_wait_unfrozen, ((sb)->s_frozen < (level)))
-/*
- * until VFS tracks user namespaces for inodes, just make all files
- * belong to init_user_ns
- */
-extern struct user_namespace init_user_ns;
-#define inode_userns(inode) (&init_user_ns)
extern bool inode_owner_or_capable(const struct inode *inode);
/* not quite ready to be deprecated, but... */
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index fffdf00f87b9..15be561e7397 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -6,7 +6,7 @@
*
* Maintainer: Kumar Gala <galak@kernel.crashing.org>
*
- * Copyright 2004 Freescale Semiconductor, Inc
+ * Copyright 2004,2012 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
@@ -17,6 +17,12 @@
#ifndef _FSL_DEVICE_H_
#define _FSL_DEVICE_H_
+#define FSL_UTMI_PHY_DLY 10 /*As per P1010RM, delay for UTMI
+ PHY CLK to become stable - 10ms*/
+#define FSL_USB_VER_OLD 0
+#define FSL_USB_VER_1_6 1
+#define FSL_USB_VER_2_2 2
+
#include <linux/types.h>
/*
@@ -63,6 +69,7 @@ struct platform_device;
struct fsl_usb2_platform_data {
/* board specific information */
+ int controller_ver;
enum fsl_usb2_operating_modes operating_mode;
enum fsl_usb2_phy_modes phy_mode;
unsigned int port_enables;
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 72a6cabb4d5b..55e6d63d46d0 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -286,10 +286,16 @@ struct ftrace_rec_iter *ftrace_rec_iter_start(void);
struct ftrace_rec_iter *ftrace_rec_iter_next(struct ftrace_rec_iter *iter);
struct dyn_ftrace *ftrace_rec_iter_record(struct ftrace_rec_iter *iter);
+#define for_ftrace_rec_iter(iter) \
+ for (iter = ftrace_rec_iter_start(); \
+ iter; \
+ iter = ftrace_rec_iter_next(iter))
+
+
int ftrace_update_record(struct dyn_ftrace *rec, int enable);
int ftrace_test_record(struct dyn_ftrace *rec, int enable);
void ftrace_run_stop_machine(int command);
-int ftrace_location(unsigned long ip);
+unsigned long ftrace_location(unsigned long ip);
extern ftrace_func_t ftrace_trace_function;
@@ -308,11 +314,14 @@ ftrace_set_early_filter(struct ftrace_ops *ops, char *buf, int enable);
/* defined in arch */
extern int ftrace_ip_converted(unsigned long ip);
extern int ftrace_dyn_arch_init(void *data);
+extern void ftrace_replace_code(int enable);
extern int ftrace_update_ftrace_func(ftrace_func_t func);
extern void ftrace_caller(void);
extern void ftrace_call(void);
extern void mcount_call(void);
+void ftrace_modify_all_code(int command);
+
#ifndef FTRACE_ADDR
#define FTRACE_ADDR ((unsigned long)ftrace_caller)
#endif
@@ -485,8 +494,12 @@ static inline void __ftrace_enabled_restore(int enabled)
extern void trace_preempt_on(unsigned long a0, unsigned long a1);
extern void trace_preempt_off(unsigned long a0, unsigned long a1);
#else
- static inline void trace_preempt_on(unsigned long a0, unsigned long a1) { }
- static inline void trace_preempt_off(unsigned long a0, unsigned long a1) { }
+/*
+ * Use defines instead of static inlines because some arches will make code out
+ * of the CALLER_ADDR, when we really want these to be a real nop.
+ */
+# define trace_preempt_on(a0, a1) do { } while (0)
+# define trace_preempt_off(a0, a1) do { } while (0)
#endif
#ifdef CONFIG_FTRACE_MCOUNT_RECORD
diff --git a/include/linux/gameport.h b/include/linux/gameport.h
index b456b08d70ed..b986be513406 100644
--- a/include/linux/gameport.h
+++ b/include/linux/gameport.h
@@ -153,6 +153,19 @@ int __must_check __gameport_register_driver(struct gameport_driver *drv,
void gameport_unregister_driver(struct gameport_driver *drv);
+/**
+ * module_gameport_driver() - Helper macro for registering a gameport driver
+ * @__gameport_driver: gameport_driver struct
+ *
+ * Helper macro for gameport drivers which do not do anything special in
+ * module init/exit. This eliminates a lot of boilerplate. Each module may
+ * only use this macro once, and calling it replaces module_init() and
+ * module_exit().
+ */
+#define module_gameport_driver(__gameport_driver) \
+ module_driver(__gameport_driver, gameport_register_driver, \
+ gameport_unregister_driver)
+
#endif /* __KERNEL__ */
#define GAMEPORT_MODE_DISABLED 0
diff --git a/include/linux/generic_serial.h b/include/linux/generic_serial.h
index fadff28505bb..79b3eb37243a 100644
--- a/include/linux/generic_serial.h
+++ b/include/linux/generic_serial.h
@@ -4,7 +4,6 @@
* Copyright (C) 1998 R.E.Wolff@BitWizard.nl
*
* written for the SX serial driver.
- * Contains the code that should be shared over all the serial drivers.
*
* Version 0.1 -- December, 1998.
*/
@@ -12,45 +11,8 @@
#ifndef GENERIC_SERIAL_H
#define GENERIC_SERIAL_H
-#ifdef __KERNEL__
-#include <linux/mutex.h>
-#include <linux/tty.h>
-
-struct real_driver {
- void (*disable_tx_interrupts) (void *);
- void (*enable_tx_interrupts) (void *);
- void (*disable_rx_interrupts) (void *);
- void (*enable_rx_interrupts) (void *);
- void (*shutdown_port) (void*);
- int (*set_real_termios) (void*);
- int (*chars_in_buffer) (void*);
- void (*close) (void*);
- void (*hungup) (void*);
- void (*getserial) (void*, struct serial_struct *sp);
-};
-
-
-
-struct gs_port {
- int magic;
- struct tty_port port;
- unsigned char *xmit_buf;
- int xmit_head;
- int xmit_tail;
- int xmit_cnt;
- struct mutex port_write_mutex;
- unsigned long event;
- unsigned short closing_wait;
- int close_delay;
- struct real_driver *rd;
- int wakeup_chars;
- int baud_base;
- int baud;
- int custom_divisor;
- spinlock_t driver_lock;
-};
-
-#endif /* __KERNEL__ */
+#warning Use of this header is deprecated.
+#warning Since nobody sets the constants defined here for you, you should not, in any case, use them. Including the header is thus pointless.
/* Flags */
/* Warning: serial.h defines some ASYNC_ flags, they say they are "only"
@@ -60,8 +22,6 @@ struct gs_port {
#define GS_RX_INTEN 0x00400000
#define GS_ACTIVE 0x00200000
-
-
#define GS_TYPE_NORMAL 1
#define GS_DEBUG_FLUSH 0x00000001
@@ -72,24 +32,4 @@ struct gs_port {
#define GS_DEBUG_FLOW 0x00000020
#define GS_DEBUG_WRITE 0x00000040
-#ifdef __KERNEL__
-int gs_put_char(struct tty_struct *tty, unsigned char ch);
-int gs_write(struct tty_struct *tty,
- const unsigned char *buf, int count);
-int gs_write_room(struct tty_struct *tty);
-int gs_chars_in_buffer(struct tty_struct *tty);
-void gs_flush_buffer(struct tty_struct *tty);
-void gs_flush_chars(struct tty_struct *tty);
-void gs_stop(struct tty_struct *tty);
-void gs_start(struct tty_struct *tty);
-void gs_hangup(struct tty_struct *tty);
-int gs_block_til_ready(void *port, struct file *filp);
-void gs_close(struct tty_struct *tty, struct file *filp);
-void gs_set_termios (struct tty_struct * tty,
- struct ktermios * old_termios);
-int gs_init_port(struct gs_port *port);
-int gs_setserial(struct gs_port *port, struct serial_struct __user *sp);
-int gs_getserial(struct gs_port *port, struct serial_struct __user *sp);
-void gs_got_break(struct gs_port *port);
-#endif /* __KERNEL__ */
#endif
diff --git a/include/linux/gpio.h b/include/linux/gpio.h
index 6155ecf192b0..f07fc2d08159 100644
--- a/include/linux/gpio.h
+++ b/include/linux/gpio.h
@@ -1,6 +1,8 @@
#ifndef __LINUX_GPIO_H
#define __LINUX_GPIO_H
+#include <linux/errno.h>
+
/* see Documentation/gpio.txt */
/* make these flag values available regardless of GPIO kconfig options */
@@ -20,6 +22,11 @@
/* Gpio pin is open source */
#define GPIOF_OPEN_SOURCE (1 << 3)
+#define GPIOF_EXPORT (1 << 2)
+#define GPIOF_EXPORT_CHANGEABLE (1 << 3)
+#define GPIOF_EXPORT_DIR_FIXED (GPIOF_EXPORT)
+#define GPIOF_EXPORT_DIR_CHANGEABLE (GPIOF_EXPORT | GPIOF_EXPORT_CHANGEABLE)
+
/**
* struct gpio - a structure describing a GPIO with configuration
* @gpio: the GPIO number
@@ -33,7 +40,39 @@ struct gpio {
};
#ifdef CONFIG_GENERIC_GPIO
+
+#ifdef CONFIG_ARCH_HAVE_CUSTOM_GPIO_H
#include <asm/gpio.h>
+#else
+
+#include <asm-generic/gpio.h>
+
+static inline int gpio_get_value(unsigned int gpio)
+{
+ return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned int gpio, int value)
+{
+ __gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned int gpio)
+{
+ return __gpio_cansleep(gpio);
+}
+
+static inline int gpio_to_irq(unsigned int gpio)
+{
+ return __gpio_to_irq(gpio);
+}
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+ return -EINVAL;
+}
+
+#endif
#else
@@ -55,12 +94,24 @@ static inline int gpio_request(unsigned gpio, const char *label)
return -ENOSYS;
}
+static inline int devm_gpio_request(struct device *dev, unsigned gpio,
+ const char *label)
+{
+ return -ENOSYS;
+}
+
static inline int gpio_request_one(unsigned gpio,
unsigned long flags, const char *label)
{
return -ENOSYS;
}
+static inline int devm_gpio_request_one(struct device *dev, unsigned gpio,
+ unsigned long flags, const char *label)
+{
+ return -ENOSYS;
+}
+
static inline int gpio_request_array(const struct gpio *array, size_t num)
{
return -ENOSYS;
@@ -74,6 +125,14 @@ static inline void gpio_free(unsigned gpio)
WARN_ON(1);
}
+static inline void devm_gpio_free(struct device *dev, unsigned gpio)
+{
+ might_sleep();
+
+ /* GPIO can never have been requested */
+ WARN_ON(1);
+}
+
static inline void gpio_free_array(const struct gpio *array, size_t num)
{
might_sleep();
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 3a95da60fd3e..449fa385703d 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -317,7 +317,6 @@ struct hid_item {
#define HID_QUIRK_BADPAD 0x00000020
#define HID_QUIRK_MULTI_INPUT 0x00000040
#define HID_QUIRK_HIDINPUT_FORCE 0x00000080
-#define HID_QUIRK_MULTITOUCH 0x00000100
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000
#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000
#define HID_QUIRK_NO_INIT_REPORTS 0x20000000
@@ -325,6 +324,12 @@ struct hid_item {
#define HID_QUIRK_NO_INPUT_SYNC 0x80000000
/*
+ * HID device groups
+ */
+#define HID_GROUP_GENERIC 0x0001
+#define HID_GROUP_MULTITOUCH 0x0002
+
+/*
* This is the global environment of the parser. This information is
* persistent for main-items. The global environment can be saved and
* restored with PUSH/POP statements.
@@ -467,6 +472,8 @@ struct hid_driver;
struct hid_ll_driver;
struct hid_device { /* device report descriptor */
+ __u8 *dev_rdesc;
+ unsigned dev_rsize;
__u8 *rdesc;
unsigned rsize;
struct hid_collection *collection; /* List of HID collections */
@@ -474,6 +481,7 @@ struct hid_device { /* device report descriptor */
unsigned maxcollection; /* Number of parsed collections */
unsigned maxapplication; /* Number of applications */
__u16 bus; /* BUS ID */
+ __u16 group; /* Report group */
__u32 vendor; /* Vendor ID */
__u32 product; /* Product ID */
__u32 version; /* HID version */
@@ -578,12 +586,12 @@ struct hid_descriptor {
struct hid_class_descriptor desc[1];
} __attribute__ ((packed));
-#define HID_DEVICE(b, ven, prod) \
- .bus = (b), \
- .vendor = (ven), .product = (prod)
-
-#define HID_USB_DEVICE(ven, prod) HID_DEVICE(BUS_USB, ven, prod)
-#define HID_BLUETOOTH_DEVICE(ven, prod) HID_DEVICE(BUS_BLUETOOTH, ven, prod)
+#define HID_DEVICE(b, g, ven, prod) \
+ .bus = (b), .group = (g), .vendor = (ven), .product = (prod)
+#define HID_USB_DEVICE(ven, prod) \
+ .bus = BUS_USB, .vendor = (ven), .product = (prod)
+#define HID_BLUETOOTH_DEVICE(ven, prod) \
+ .bus = BUS_BLUETOOTH, .vendor = (ven), .product = (prod)
#define HID_REPORT_ID(rep) \
.report_type = (rep)
@@ -735,6 +743,7 @@ void hid_output_report(struct hid_report *report, __u8 *data);
struct hid_device *hid_allocate_device(void);
struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id);
int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
+int hid_open_report(struct hid_device *device);
int hid_check_keys_pressed(struct hid_device *hid);
int hid_connect(struct hid_device *hid, unsigned int connect_mask);
void hid_disconnect(struct hid_device *hid);
@@ -805,16 +814,7 @@ static inline void hid_map_usage_clear(struct hid_input *hidinput,
*/
static inline int __must_check hid_parse(struct hid_device *hdev)
{
- int ret;
-
- if (hdev->status & HID_STAT_PARSED)
- return 0;
-
- ret = hdev->ll_driver->parse(hdev);
- if (!ret)
- hdev->status |= HID_STAT_PARSED;
-
- return ret;
+ return hid_open_report(hdev);
}
/**
@@ -896,7 +896,7 @@ static inline int hid_hw_power(struct hid_device *hdev, int level)
return hdev->ll_driver->power ? hdev->ll_driver->power(hdev, level) : 0;
}
-void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
+int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
int interrupt);
extern int hid_generic_init(void);
diff --git a/include/linux/hidraw.h b/include/linux/hidraw.h
index 4b88e697c4e9..45e9fcb8d877 100644
--- a/include/linux/hidraw.h
+++ b/include/linux/hidraw.h
@@ -76,13 +76,13 @@ struct hidraw_list {
#ifdef CONFIG_HIDRAW
int hidraw_init(void);
void hidraw_exit(void);
-void hidraw_report_event(struct hid_device *, u8 *, int);
+int hidraw_report_event(struct hid_device *, u8 *, int);
int hidraw_connect(struct hid_device *);
void hidraw_disconnect(struct hid_device *);
#else
static inline int hidraw_init(void) { return 0; }
static inline void hidraw_exit(void) { }
-static inline void hidraw_report_event(struct hid_device *hid, u8 *data, int len) { }
+static inline int hidraw_report_event(struct hid_device *hid, u8 *data, int len) { return 0; }
static inline int hidraw_connect(struct hid_device *hid) { return -1; }
static inline void hidraw_disconnect(struct hid_device *hid) { }
#endif
diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h
index 6af8738ae7e9..68ed7f7e1fc9 100644
--- a/include/linux/hyperv.h
+++ b/include/linux/hyperv.h
@@ -1062,8 +1062,10 @@ struct hyperv_service_callback {
void (*callback) (void *context);
};
+#define MAX_SRV_VER 0x7ffffff
extern void vmbus_prep_negotiate_resp(struct icmsg_hdr *,
- struct icmsg_negotiate *, u8 *);
+ struct icmsg_negotiate *, u8 *, int,
+ int);
int hv_kvp_init(struct hv_util_service *);
void hv_kvp_deinit(void);
diff --git a/include/linux/i2c-pnx.h b/include/linux/i2c-pnx.h
index a87124d4d533..1bc74afe7a35 100644
--- a/include/linux/i2c-pnx.h
+++ b/include/linux/i2c-pnx.h
@@ -29,14 +29,10 @@ struct i2c_pnx_algo_data {
struct i2c_pnx_mif mif;
int last;
struct clk *clk;
- struct i2c_pnx_data *i2c_pnx;
struct i2c_adapter adapter;
-};
-
-struct i2c_pnx_data {
- const char *name;
- u32 base;
- int irq;
+ phys_addr_t base;
+ int irq;
+ u32 timeout;
};
#endif /* __I2C_PNX_H__ */
diff --git a/include/linux/i2c/adp5588.h b/include/linux/i2c/adp5588.h
index cec17cf6cac2..d8341cb47b60 100644
--- a/include/linux/i2c/adp5588.h
+++ b/include/linux/i2c/adp5588.h
@@ -157,6 +157,7 @@ struct i2c_client; /* forward declaration */
struct adp5588_gpio_platform_data {
int gpio_start; /* GPIO Chip base # */
+ const char *const *names;
unsigned irq_base; /* interrupt base # */
unsigned pullup_dis_mask; /* Pull-Up Disable Mask */
int (*setup)(struct i2c_client *client,
diff --git a/include/linux/i2o-dev.h b/include/linux/i2o-dev.h
index a0b23dd45239..a8093bfec3a6 100644
--- a/include/linux/i2o-dev.h
+++ b/include/linux/i2o-dev.h
@@ -124,7 +124,7 @@ typedef struct i2o_sg_io_hdr {
#define I2O_BUS_LOCAL 0
#define I2O_BUS_ISA 1
#define I2O_BUS_EISA 2
-#define I2O_BUS_MCA 3
+/* was I2O_BUS_MCA 3 */
#define I2O_BUS_PCI 4
#define I2O_BUS_PCMCIA 5
#define I2O_BUS_NUBUS 6
diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h
index 26cb3c2c5c71..f0e69c6e8208 100644
--- a/include/linux/if_arp.h
+++ b/include/linux/if_arp.h
@@ -82,7 +82,7 @@
#define ARPHRD_FCPL 786 /* Fibrechannel public loop */
#define ARPHRD_FCFABRIC 787 /* Fibrechannel fabric */
/* 787->799 reserved for fibrechannel media types */
-/* 800 used to be used for token ring */
+#define ARPHRD_IEEE802_TR 800 /* Magic type ident for TR */
#define ARPHRD_IEEE80211 801 /* IEEE 802.11 */
#define ARPHRD_IEEE80211_PRISM 802 /* IEEE 802.11 + Prism2 header */
#define ARPHRD_IEEE80211_RADIOTAP 803 /* IEEE 802.11 + radiotap header */
diff --git a/drivers/staging/iio/buffer.h b/include/linux/iio/buffer.h
index df2046dcb623..fb0fe46fd659 100644
--- a/drivers/staging/iio/buffer.h
+++ b/include/linux/iio/buffer.h
@@ -10,7 +10,7 @@
#ifndef _IIO_BUFFER_GENERIC_H_
#define _IIO_BUFFER_GENERIC_H_
#include <linux/sysfs.h>
-#include "iio.h"
+#include <linux/iio/iio.h>
#ifdef CONFIG_IIO_BUFFER
@@ -56,7 +56,6 @@ struct iio_buffer_access_funcs {
* @scan_el_attrs: [DRIVER] control of scan elements if that scan mode
* control method is used
* @scan_mask: [INTERN] bitmask used in masking scan mode elements
- * @scan_index_timestamp:[INTERN] cache of the index to the timestamp
* @scan_timestamp: [INTERN] does the scan mode include a timestamp
* @access: [DRIVER] buffer access functions associated with the
* implementation.
@@ -74,7 +73,6 @@ struct iio_buffer {
struct attribute_group *scan_el_attrs;
long *scan_mask;
bool scan_timestamp;
- unsigned scan_index_timestamp;
const struct iio_buffer_access_funcs *access;
struct list_head scan_el_dev_attr_list;
struct attribute_group scan_el_group;
diff --git a/drivers/staging/iio/consumer.h b/include/linux/iio/consumer.h
index 36a060cd3a21..1a15e560a5a1 100644
--- a/drivers/staging/iio/consumer.h
+++ b/include/linux/iio/consumer.h
@@ -9,7 +9,7 @@
*/
#ifndef _IIO_INKERN_CONSUMER_H_
#define _IIO_INKERN_CONSUMER_H
-#include "types.h"
+#include <linux/iio/types.h>
struct iio_dev;
struct iio_chan_spec;
diff --git a/drivers/staging/iio/driver.h b/include/linux/iio/driver.h
index a4f8b2e05af5..a4f8b2e05af5 100644
--- a/drivers/staging/iio/driver.h
+++ b/include/linux/iio/driver.h
diff --git a/drivers/staging/iio/events.h b/include/linux/iio/events.h
index c25f0e3c92e9..b5acbf93c5da 100644
--- a/drivers/staging/iio/events.h
+++ b/include/linux/iio/events.h
@@ -11,7 +11,7 @@
#include <linux/ioctl.h>
#include <linux/types.h>
-#include "types.h"
+#include <linux/iio/types.h>
/**
* struct iio_event_data - The actual event being pushed to userspace
diff --git a/drivers/staging/iio/iio.h b/include/linux/iio/iio.h
index b9cd454f69e2..3a4f6a3ab80d 100644
--- a/drivers/staging/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -12,22 +12,17 @@
#include <linux/device.h>
#include <linux/cdev.h>
-#include "types.h"
+#include <linux/iio/types.h>
/* IIO TODO LIST */
/*
* Provide means of adjusting timer accuracy.
* Currently assumes nano seconds.
*/
-enum iio_data_type {
- IIO_RAW,
- IIO_PROCESSED,
-};
-
-/* Could add the raw attributes as well - allowing buffer only devices */
enum iio_chan_info_enum {
- /* 0 is reserved for raw attributes */
- IIO_CHAN_INFO_SCALE = 1,
+ IIO_CHAN_INFO_RAW = 0,
+ IIO_CHAN_INFO_PROCESSED,
+ IIO_CHAN_INFO_SCALE,
IIO_CHAN_INFO_OFFSET,
IIO_CHAN_INFO_CALIBSCALE,
IIO_CHAN_INFO_CALIBBIAS,
@@ -36,11 +31,19 @@ enum iio_chan_info_enum {
IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW,
IIO_CHAN_INFO_AVERAGE_RAW,
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY,
+ IIO_CHAN_INFO_SAMP_FREQ,
+ IIO_CHAN_INFO_FREQUENCY,
+ IIO_CHAN_INFO_PHASE,
+ IIO_CHAN_INFO_HARDWAREGAIN,
};
#define IIO_CHAN_INFO_SHARED_BIT(type) BIT(type*2)
#define IIO_CHAN_INFO_SEPARATE_BIT(type) BIT(type*2 + 1)
+#define IIO_CHAN_INFO_RAW_SEPARATE_BIT \
+ IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_RAW)
+#define IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT \
+ IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_PROCESSED)
#define IIO_CHAN_INFO_SCALE_SEPARATE_BIT \
IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_SCALE)
#define IIO_CHAN_INFO_SCALE_SHARED_BIT \
@@ -81,6 +84,22 @@ enum iio_chan_info_enum {
#define IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY_SEPARATE_BIT \
IIO_CHAN_INFO_SEPARATE_BIT( \
IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY)
+#define IIO_CHAN_INFO_SAMP_FREQ_SEPARATE_BIT \
+ IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_SAMP_FREQ)
+#define IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT \
+ IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_SAMP_FREQ)
+#define IIO_CHAN_INFO_FREQUENCY_SEPARATE_BIT \
+ IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_FREQUENCY)
+#define IIO_CHAN_INFO_FREQUENCY_SHARED_BIT \
+ IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_FREQUENCY)
+#define IIO_CHAN_INFO_PHASE_SEPARATE_BIT \
+ IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_PHASE)
+#define IIO_CHAN_INFO_PHASE_SHARED_BIT \
+ IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_PHASE)
+#define IIO_CHAN_INFO_HARDWAREGAIN_SEPARATE_BIT \
+ IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_HARDWAREGAIN)
+#define IIO_CHAN_INFO_HARDWAREGAIN_SHARED_BIT \
+ IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_HARDWAREGAIN)
enum iio_endian {
IIO_CPU,
@@ -97,14 +116,17 @@ struct iio_dev;
* @shared: Whether this attribute is shared between all channels.
* @read: Read callback for this info attribute, may be NULL.
* @write: Write callback for this info attribute, may be NULL.
+ * @private: Data private to the driver.
*/
struct iio_chan_spec_ext_info {
const char *name;
bool shared;
- ssize_t (*read)(struct iio_dev *, struct iio_chan_spec const *,
- char *buf);
- ssize_t (*write)(struct iio_dev *, struct iio_chan_spec const *,
- const char *buf, size_t len);
+ ssize_t (*read)(struct iio_dev *, uintptr_t private,
+ struct iio_chan_spec const *, char *buf);
+ ssize_t (*write)(struct iio_dev *, uintptr_t private,
+ struct iio_chan_spec const *, const char *buf,
+ size_t len);
+ uintptr_t private;
};
/**
@@ -136,8 +158,6 @@ struct iio_chan_spec_ext_info {
* correspond to the first name that the channel is referred
* to by in the datasheet (e.g. IND), or the nearest
* possible compound name (e.g. IND-INC).
- * @processed_val: Flag to specify the data access attribute should be
- * *_input rather than *_raw.
* @modified: Does a modifier apply to this channel. What these are
* depends on the channel type. Modifier is set in
* channel2. Examples are IIO_MOD_X for axial sensors about
@@ -164,9 +184,8 @@ struct iio_chan_spec {
long info_mask;
long event_mask;
const struct iio_chan_spec_ext_info *ext_info;
- char *extend_name;
+ const char *extend_name;
const char *datasheet_name;
- unsigned processed_val:1;
unsigned modified:1;
unsigned indexed:1;
unsigned output:1;
@@ -176,23 +195,6 @@ struct iio_chan_spec {
#define IIO_ST(si, rb, sb, sh) \
{ .sign = si, .realbits = rb, .storagebits = sb, .shift = sh }
-/* Macro assumes input channels */
-#define IIO_CHAN(_type, _mod, _indexed, _proc, _name, _chan, _chan2, \
- _inf_mask, _address, _si, _stype, _event_mask) \
- { .type = _type, \
- .output = 0, \
- .modified = _mod, \
- .indexed = _indexed, \
- .processed_val = _proc, \
- .extend_name = _name, \
- .channel = _chan, \
- .channel2 = _chan2, \
- .info_mask = _inf_mask, \
- .address = _address, \
- .scan_index = _si, \
- .scan_type = _stype, \
- .event_mask = _event_mask }
-
#define IIO_CHAN_SOFT_TIMESTAMP(_si) \
{ .type = IIO_TIMESTAMP, .channel = -1, \
.scan_index = _si, .scan_type = IIO_ST('s', 64, 64, 0) }
@@ -315,12 +317,15 @@ struct iio_buffer_setup_ops {
* and owner
* @event_interface: [INTERN] event chrdevs associated with interrupt lines
* @buffer: [DRIVER] any buffer present
+ * @scan_bytes: [INTERN] num bytes captured to be fed to buffer demux
* @mlock: [INTERN] lock used to prevent simultaneous device state
* changes
* @available_scan_masks: [DRIVER] optional array of allowed bitmasks
* @masklength: [INTERN] the length of the mask established from
* channels
* @active_scan_mask: [INTERN] union of all scan masks requested by buffers
+ * @scan_timestamp: [INTERN] set if any buffers have requested timestamp
+ * @scan_index_timestamp:[INTERN] cache of the index to the timestamp
* @trig: [INTERN] current device trigger (buffer modes)
* @pollfunc: [DRIVER] function run on trigger being received
* @channels: [DRIVER] channel specification structure table
@@ -331,6 +336,8 @@ struct iio_buffer_setup_ops {
* @name: [DRIVER] name of the device.
* @info: [DRIVER] callbacks and constant info from driver
* @info_exist_lock: [INTERN] lock to prevent use during removal
+ * @setup_ops: [DRIVER] callbacks to call before and after buffer
+ * enable/disable
* @chrdev: [INTERN] associated character device
* @groups: [INTERN] attribute groups
* @groupcounter: [INTERN] index of next attribute group
@@ -348,11 +355,14 @@ struct iio_dev {
struct iio_event_interface *event_interface;
struct iio_buffer *buffer;
+ int scan_bytes;
struct mutex mlock;
const unsigned long *available_scan_masks;
unsigned masklength;
const unsigned long *active_scan_mask;
+ bool scan_timestamp;
+ unsigned scan_index_timestamp;
struct iio_trigger *trig;
struct iio_poll_func *pollfunc;
@@ -408,22 +418,33 @@ int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp);
extern struct bus_type iio_bus_type;
/**
- * iio_put_device() - reference counted deallocation of struct device
+ * iio_device_put() - reference counted deallocation of struct device
* @dev: the iio_device containing the device
**/
-static inline void iio_put_device(struct iio_dev *indio_dev)
+static inline void iio_device_put(struct iio_dev *indio_dev)
{
if (indio_dev)
put_device(&indio_dev->dev);
};
+/**
+ * dev_to_iio_dev() - Get IIO device struct from a device struct
+ * @dev: The device embedded in the IIO device
+ *
+ * Note: The device must be a IIO device, otherwise the result is undefined.
+ */
+static inline struct iio_dev *dev_to_iio_dev(struct device *dev)
+{
+ return container_of(dev, struct iio_dev, dev);
+}
+
/* Can we make this smaller? */
#define IIO_ALIGN L1_CACHE_BYTES
/**
- * iio_allocate_device() - allocate an iio_dev from a driver
+ * iio_device_alloc() - allocate an iio_dev from a driver
* @sizeof_priv: Space to allocate for private structure.
**/
-struct iio_dev *iio_allocate_device(int sizeof_priv);
+struct iio_dev *iio_device_alloc(int sizeof_priv);
static inline void *iio_priv(const struct iio_dev *indio_dev)
{
@@ -437,10 +458,10 @@ static inline struct iio_dev *iio_priv_to_dev(void *priv)
}
/**
- * iio_free_device() - free an iio_dev from a driver
+ * iio_device_free() - free an iio_dev from a driver
* @dev: the iio_dev associated with the device
**/
-void iio_free_device(struct iio_dev *indio_dev);
+void iio_device_free(struct iio_dev *indio_dev);
/**
* iio_buffer_enabled() - helper function to test if the buffer is enabled
diff --git a/drivers/staging/iio/kfifo_buf.h b/include/linux/iio/kfifo_buf.h
index 9f7da016af04..014d5a13b32b 100644
--- a/drivers/staging/iio/kfifo_buf.h
+++ b/include/linux/iio/kfifo_buf.h
@@ -1,7 +1,7 @@
#include <linux/kfifo.h>
-#include "iio.h"
-#include "buffer.h"
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev);
void iio_kfifo_free(struct iio_buffer *r);
diff --git a/drivers/staging/iio/machine.h b/include/linux/iio/machine.h
index 0b1f19bfdc44..0b1f19bfdc44 100644
--- a/drivers/staging/iio/machine.h
+++ b/include/linux/iio/machine.h
diff --git a/drivers/staging/iio/sysfs.h b/include/linux/iio/sysfs.h
index bfedb73b850e..bfedb73b850e 100644
--- a/drivers/staging/iio/sysfs.h
+++ b/include/linux/iio/sysfs.h
diff --git a/drivers/staging/iio/trigger.h b/include/linux/iio/trigger.h
index 1cfca231db8f..a9819940a84c 100644
--- a/drivers/staging/iio/trigger.h
+++ b/include/linux/iio/trigger.h
@@ -78,13 +78,13 @@ static inline struct iio_trigger *to_iio_trigger(struct device *d)
return container_of(d, struct iio_trigger, dev);
};
-static inline void iio_put_trigger(struct iio_trigger *trig)
+static inline void iio_trigger_put(struct iio_trigger *trig)
{
module_put(trig->ops->owner);
put_device(&trig->dev);
};
-static inline void iio_get_trigger(struct iio_trigger *trig)
+static inline void iio_trigger_get(struct iio_trigger *trig)
{
get_device(&trig->dev);
__module_get(trig->ops->owner);
@@ -113,7 +113,7 @@ void iio_trigger_poll_chained(struct iio_trigger *trig, s64 time);
irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private);
-__printf(1, 2) struct iio_trigger *iio_allocate_trigger(const char *fmt, ...);
-void iio_free_trigger(struct iio_trigger *trig);
+__printf(1, 2) struct iio_trigger *iio_trigger_alloc(const char *fmt, ...);
+void iio_trigger_free(struct iio_trigger *trig);
#endif /* _IIO_TRIGGER_H_ */
diff --git a/drivers/staging/iio/trigger_consumer.h b/include/linux/iio/trigger_consumer.h
index 60d64b356945..60d64b356945 100644
--- a/drivers/staging/iio/trigger_consumer.h
+++ b/include/linux/iio/trigger_consumer.h
diff --git a/drivers/staging/iio/types.h b/include/linux/iio/types.h
index 0c3213666901..1b073b1cc7c2 100644
--- a/drivers/staging/iio/types.h
+++ b/include/linux/iio/types.h
@@ -27,6 +27,7 @@ enum iio_chan_type {
IIO_ANGL,
IIO_TIMESTAMP,
IIO_CAPACITANCE,
+ IIO_ALTVOLTAGE,
};
enum iio_modifier {
@@ -49,5 +50,6 @@ enum iio_modifier {
#define IIO_VAL_INT 1
#define IIO_VAL_INT_PLUS_MICRO 2
#define IIO_VAL_INT_PLUS_NANO 3
+#define IIO_VAL_INT_PLUS_MICRO_DB 4
#endif /* _IIO_TYPES_H_ */
diff --git a/include/linux/input/lm8333.h b/include/linux/input/lm8333.h
new file mode 100644
index 000000000000..79f918c6e8c5
--- /dev/null
+++ b/include/linux/input/lm8333.h
@@ -0,0 +1,24 @@
+/*
+ * public include for LM8333 keypad driver - same license as driver
+ * Copyright (C) 2012 Wolfram Sang, Pengutronix <w.sang@pengutronix.de>
+ */
+
+#ifndef _LM8333_H
+#define _LM8333_H
+
+struct lm8333;
+
+struct lm8333_platform_data {
+ /* Keymap data */
+ const struct matrix_keymap_data *matrix_data;
+ /* Active timeout before enter HALT mode in microseconds */
+ unsigned active_time;
+ /* Debounce interval in microseconds */
+ unsigned debounce_time;
+};
+
+extern int lm8333_read8(struct lm8333 *lm8333, u8 cmd);
+extern int lm8333_write8(struct lm8333 *lm8333, u8 cmd, u8 val);
+extern int lm8333_read_block(struct lm8333 *lm8333, u8 cmd, u8 len, u8 *buf);
+
+#endif /* _LM8333_H */
diff --git a/include/linux/input/matrix_keypad.h b/include/linux/input/matrix_keypad.h
index 6c07ced0af81..5f3aa6b11bfa 100644
--- a/include/linux/input/matrix_keypad.h
+++ b/include/linux/input/matrix_keypad.h
@@ -75,54 +75,10 @@ struct matrix_keypad_platform_data {
bool no_autorepeat;
};
-/**
- * matrix_keypad_build_keymap - convert platform keymap into matrix keymap
- * @keymap_data: keymap supplied by the platform code
- * @row_shift: number of bits to shift row value by to advance to the next
- * line in the keymap
- * @keymap: expanded version of keymap that is suitable for use by
- * matrix keyboad driver
- * @keybit: pointer to bitmap of keys supported by input device
- *
- * This function converts platform keymap (encoded with KEY() macro) into
- * an array of keycodes that is suitable for using in a standard matrix
- * keyboard driver that uses row and col as indices.
- */
-static inline void
-matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data,
- unsigned int row_shift,
- unsigned short *keymap, unsigned long *keybit)
-{
- int i;
-
- for (i = 0; i < keymap_data->keymap_size; i++) {
- unsigned int key = keymap_data->keymap[i];
- unsigned int row = KEY_ROW(key);
- unsigned int col = KEY_COL(key);
- unsigned short code = KEY_VAL(key);
-
- keymap[MATRIX_SCAN_CODE(row, col, row_shift)] = code;
- __set_bit(code, keybit);
- }
- __clear_bit(KEY_RESERVED, keybit);
-}
-
-#ifdef CONFIG_INPUT_OF_MATRIX_KEYMAP
-struct matrix_keymap_data *
-matrix_keyboard_of_fill_keymap(struct device_node *np, const char *propname);
-
-void matrix_keyboard_of_free_keymap(const struct matrix_keymap_data *kd);
-#else
-static inline struct matrix_keymap_data *
-matrix_keyboard_of_fill_keymap(struct device_node *np, const char *propname)
-{
- return NULL;
-}
-
-static inline void
-matrix_keyboard_of_free_keymap(const struct matrix_keymap_data *kd)
-{
-}
-#endif
+int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data,
+ const char *keymap_name,
+ unsigned int rows, unsigned int cols,
+ unsigned short *keymap,
+ struct input_dev *input_dev);
#endif /* _MATRIX_KEYPAD_H */
diff --git a/include/linux/input/navpoint.h b/include/linux/input/navpoint.h
new file mode 100644
index 000000000000..45050eb34de3
--- /dev/null
+++ b/include/linux/input/navpoint.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (C) 2012 Paul Parsons <lost.distance@yahoo.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.
+ */
+
+struct navpoint_platform_data {
+ int port; /* PXA SSP port for pxa_ssp_request() */
+ int gpio; /* GPIO for power on/off */
+};
diff --git a/include/linux/ipx.h b/include/linux/ipx.h
index 8f0243982eb6..3d48014cdd71 100644
--- a/include/linux/ipx.h
+++ b/include/linux/ipx.h
@@ -38,7 +38,7 @@ struct ipx_interface_definition {
#define IPX_FRAME_8022 2
#define IPX_FRAME_ETHERII 3
#define IPX_FRAME_8023 4
-/* obsolete token ring was 5 */
+#define IPX_FRAME_TR_8022 5 /* obsolete */
unsigned char ipx_special;
#define IPX_SPECIAL_NONE 0
#define IPX_PRIMARY 1
diff --git a/include/linux/irq.h b/include/linux/irq.h
index b27cfcfd3a59..61f5cec031e0 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -335,11 +335,6 @@ struct irq_chip {
void (*irq_print_chip)(struct irq_data *data, struct seq_file *p);
unsigned long flags;
-
- /* Currently used only by UML, might disappear one day.*/
-#ifdef CONFIG_IRQ_RELEASE_METHOD
- void (*release)(unsigned int irq, void *dev_id);
-#endif
};
/*
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index c65740d76e66..5abb533eb8eb 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -141,9 +141,8 @@ static inline struct irq_domain *irq_domain_add_legacy_isa(
return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops,
host_data);
}
-extern struct irq_domain *irq_find_host(struct device_node *node);
-extern void irq_set_default_host(struct irq_domain *host);
+extern void irq_domain_remove(struct irq_domain *host);
extern unsigned int irq_create_mapping(struct irq_domain *host,
irq_hw_number_t hwirq);
diff --git a/include/linux/isdn.h b/include/linux/isdn.h
index 292f27a793d4..215c41602af8 100644
--- a/include/linux/isdn.h
+++ b/include/linux/isdn.h
@@ -15,6 +15,7 @@
#define __ISDN_H__
#include <linux/ioctl.h>
+#include <linux/tty.h>
#define ISDN_MAX_DRIVERS 32
#define ISDN_MAX_CHANNELS 64
@@ -392,21 +393,8 @@ typedef struct isdn_net_dev_s {
/*======================= Start of ISDN-tty stuff ===========================*/
#define ISDN_ASYNC_MAGIC 0x49344C01 /* for paranoia-checking */
-#define ISDN_ASYNC_INITIALIZED 0x80000000 /* port was initialized */
-#define ISDN_ASYNC_CALLOUT_ACTIVE 0x40000000 /* Call out device active */
-#define ISDN_ASYNC_NORMAL_ACTIVE 0x20000000 /* Normal device active */
-#define ISDN_ASYNC_CLOSING 0x08000000 /* Serial port is closing */
-#define ISDN_ASYNC_CTS_FLOW 0x04000000 /* Do CTS flow control */
-#define ISDN_ASYNC_CHECK_CD 0x02000000 /* i.e., CLOCAL */
-#define ISDN_ASYNC_HUP_NOTIFY 0x0001 /* Notify tty on hangups/closes */
-#define ISDN_ASYNC_SESSION_LOCKOUT 0x0100 /* Lock cua opens on session */
-#define ISDN_ASYNC_PGRP_LOCKOUT 0x0200 /* Lock cua opens on pgrp */
-#define ISDN_ASYNC_CALLOUT_NOHUP 0x0400 /* No hangup for cui */
-#define ISDN_ASYNC_SPLIT_TERMIOS 0x0008 /* Sep. termios for dialin/out */
#define ISDN_SERIAL_XMIT_SIZE 1024 /* Default bufsize for write */
#define ISDN_SERIAL_XMIT_MAX 4000 /* Maximum bufsize for write */
-#define ISDN_SERIAL_TYPE_NORMAL 1
-#define ISDN_SERIAL_TYPE_CALLOUT 2
#ifdef CONFIG_ISDN_AUDIO
/* For using sk_buffs with audio we need some private variables
@@ -448,17 +436,12 @@ typedef struct atemu {
/* Private data (similar to async_struct in <linux/serial.h>) */
typedef struct modem_info {
int magic;
- struct module *owner;
- int flags; /* defined in tty.h */
+ struct tty_port port;
int x_char; /* xon/xoff character */
int mcr; /* Modem control register */
int msr; /* Modem status register */
int lsr; /* Line status register */
int line;
- int count; /* # of fd on device */
- int blocked_open; /* # of blocked opens */
- long session; /* Session of opening process */
- long pgrp; /* pgrp of opening process */
int online; /* 1 = B-Channel is up, drop data */
/* 2 = B-Channel is up, deliver d.*/
int dialing; /* Dial in progress or ATA */
@@ -478,7 +461,6 @@ typedef struct modem_info {
int send_outstanding;/* # of outstanding send-requests */
int xmit_size; /* max. # of chars in xmit_buf */
int xmit_count; /* # of chars in xmit_buf */
- unsigned char *xmit_buf; /* transmit buffer */
struct sk_buff_head xmit_queue; /* transmit queue */
atomic_t xmit_lock; /* Semaphore for isdn_tty_write */
#ifdef CONFIG_ISDN_AUDIO
@@ -496,11 +478,7 @@ typedef struct modem_info {
struct T30_s *fax; /* T30 Fax Group 3 data/interface */
int faxonline; /* Fax-channel status */
#endif
- struct tty_struct *tty; /* Pointer to corresponding tty */
atemu emu; /* AT-emulator data */
- struct ktermios normal_termios; /* For saving termios structs */
- struct ktermios callout_termios;
- wait_queue_head_t open_wait, close_wait;
spinlock_t readlock;
} modem_info;
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index fbe9bfacb8db..ec55a3c8ba77 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -482,15 +482,16 @@ do { \
#define trace_printk(fmt, args...) \
do { \
+ static const char *trace_printk_fmt \
+ __attribute__((section("__trace_printk_fmt"))) = \
+ __builtin_constant_p(fmt) ? fmt : NULL; \
+ \
__trace_printk_check_format(fmt, ##args); \
- if (__builtin_constant_p(fmt)) { \
- static const char *trace_printk_fmt \
- __attribute__((section("__trace_printk_fmt"))) = \
- __builtin_constant_p(fmt) ? fmt : NULL; \
\
+ if (__builtin_constant_p(fmt)) \
__trace_bprintk(_THIS_IP_, trace_printk_fmt, ##args); \
- } else \
- __trace_printk(_THIS_IP_, fmt, ##args); \
+ else \
+ __trace_printk(_THIS_IP_, fmt, ##args); \
} while (0)
extern __printf(2, 3)
diff --git a/include/linux/libata.h b/include/linux/libata.h
index e926df7b54c9..6e887c742a27 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -247,6 +247,7 @@ enum {
ATA_HOST_SIMPLEX = (1 << 0), /* Host is simplex, one DMA channel per host only */
ATA_HOST_STARTED = (1 << 1), /* Host started */
ATA_HOST_PARALLEL_SCAN = (1 << 2), /* Ports on this host can be scanned in parallel */
+ ATA_HOST_IGNORE_ATA = (1 << 3), /* Ignore ATA devices on this host. */
/* bits 24:31 of host->flags are reserved for LLD specific flags */
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index d36619ead3ba..00e46376e28f 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -157,6 +157,24 @@ struct lockdep_map {
#endif
};
+static inline void lockdep_copy_map(struct lockdep_map *to,
+ struct lockdep_map *from)
+{
+ int i;
+
+ *to = *from;
+ /*
+ * Since the class cache can be modified concurrently we could observe
+ * half pointers (64bit arch using 32bit copy insns). Therefore clear
+ * the caches and take the performance hit.
+ *
+ * XXX it doesn't work well with lockdep_set_class_and_subclass(), since
+ * that relies on cache abuse.
+ */
+ for (i = 0; i < NR_LOCKDEP_CACHING_CLASSES; i++)
+ to->class_cache[i] = NULL;
+}
+
/*
* Every lock has a list of other locks that were taken after it.
* We only grow the list, never remove from it:
diff --git a/include/linux/mca-legacy.h b/include/linux/mca-legacy.h
deleted file mode 100644
index 7a3aea845902..000000000000
--- a/include/linux/mca-legacy.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8 -*- */
-
-/* This is the function prototypes for the old legacy MCA interface
- *
- * Please move your driver to the new sysfs based one instead */
-
-#ifndef _LINUX_MCA_LEGACY_H
-#define _LINUX_MCA_LEGACY_H
-
-#include <linux/mca.h>
-
-#warning "MCA legacy - please move your driver to the new sysfs api"
-
-/* MCA_NOTFOUND is an error condition. The other two indicate
- * motherboard POS registers contain the adapter. They might be
- * returned by the mca_find_adapter() function, and can be used as
- * arguments to mca_read_stored_pos(). I'm not going to allow direct
- * access to the motherboard registers until we run across an adapter
- * that requires it. We don't know enough about them to know if it's
- * safe.
- *
- * See Documentation/mca.txt or one of the existing drivers for
- * more information.
- */
-#define MCA_NOTFOUND (-1)
-
-
-
-/* Returns the slot of the first enabled adapter matching id. User can
- * specify a starting slot beyond zero, to deal with detecting multiple
- * devices. Returns MCA_NOTFOUND if id not found. Also checks the
- * integrated adapters.
- */
-extern int mca_find_adapter(int id, int start);
-extern int mca_find_unused_adapter(int id, int start);
-
-extern int mca_mark_as_used(int slot);
-extern void mca_mark_as_unused(int slot);
-
-/* gets a byte out of POS register (stored in memory) */
-extern unsigned char mca_read_stored_pos(int slot, int reg);
-
-/* This can be expanded later. Right now, it gives us a way of
- * getting meaningful information into the MCA_info structure,
- * so we can have a more interesting /proc/mca.
- */
-extern void mca_set_adapter_name(int slot, char* name);
-
-/* These routines actually mess with the hardware POS registers. They
- * temporarily disable the device (and interrupts), so make sure you know
- * what you're doing if you use them. Furthermore, writing to a POS may
- * result in two devices trying to share a resource, which in turn can
- * result in multiple devices sharing memory spaces, IRQs, or even trashing
- * hardware. YOU HAVE BEEN WARNED.
- *
- * You can only access slots with this. Motherboard registers are off
- * limits.
- */
-
-/* read a byte from the specified POS register. */
-extern unsigned char mca_read_pos(int slot, int reg);
-
-/* write a byte to the specified POS register. */
-extern void mca_write_pos(int slot, int reg, unsigned char byte);
-
-#endif
diff --git a/include/linux/mca.h b/include/linux/mca.h
deleted file mode 100644
index 37972704617f..000000000000
--- a/include/linux/mca.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Header for Microchannel Architecture Bus
- * Written by Martin Kolinek, February 1996
- */
-
-#ifndef _LINUX_MCA_H
-#define _LINUX_MCA_H
-
-#include <linux/device.h>
-
-#ifdef CONFIG_MCA
-#include <asm/mca.h>
-
-extern int MCA_bus;
-#else
-#define MCA_bus 0
-#endif
-
-/* This sets up an information callback for /proc/mca/slot?. The
- * function is called with the buffer, slot, and device pointer (or
- * some equally informative context information, or nothing, if you
- * prefer), and is expected to put useful information into the
- * buffer. The adapter name, id, and POS registers get printed
- * before this is called though, so don't do it again.
- *
- * This should be called with a NULL procfn when a module
- * unregisters, thus preventing kernel crashes and other such
- * nastiness.
- */
-typedef int (*MCA_ProcFn)(char* buf, int slot, void* dev);
-
-/* Should only be called by the NMI interrupt handler, this will do some
- * fancy stuff to figure out what might have generated a NMI.
- */
-extern void mca_handle_nmi(void);
-
-enum MCA_AdapterStatus {
- MCA_ADAPTER_NORMAL = 0,
- MCA_ADAPTER_NONE = 1,
- MCA_ADAPTER_DISABLED = 2,
- MCA_ADAPTER_ERROR = 3
-};
-
-struct mca_device {
- u64 dma_mask;
- int pos_id;
- int slot;
-
- /* index into id_table, set by the bus match routine */
- int index;
-
- /* is there a driver installed? 0 - No, 1 - Yes */
- int driver_loaded;
- /* POS registers */
- unsigned char pos[8];
- /* if a pseudo adapter of the motherboard, this is the motherboard
- * register value to use for setup cycles */
- short pos_register;
-
- enum MCA_AdapterStatus status;
-#ifdef CONFIG_MCA_PROC_FS
- /* name of the proc/mca file */
- char procname[8];
- /* /proc info callback */
- MCA_ProcFn procfn;
- /* device/context info for proc callback */
- void *proc_dev;
-#endif
- struct device dev;
- char name[32];
-};
-#define to_mca_device(mdev) container_of(mdev, struct mca_device, dev)
-
-struct mca_bus_accessor_functions {
- unsigned char (*mca_read_pos)(struct mca_device *, int reg);
- void (*mca_write_pos)(struct mca_device *, int reg,
- unsigned char byte);
- int (*mca_transform_irq)(struct mca_device *, int irq);
- int (*mca_transform_ioport)(struct mca_device *,
- int region);
- void * (*mca_transform_memory)(struct mca_device *,
- void *memory);
-};
-
-struct mca_bus {
- u64 default_dma_mask;
- int number;
- struct mca_bus_accessor_functions f;
- struct device dev;
- char name[32];
-};
-#define to_mca_bus(mdev) container_of(mdev, struct mca_bus, dev)
-
-struct mca_driver {
- const short *id_table;
- void *driver_data;
- int integrated_id;
- struct device_driver driver;
-};
-#define to_mca_driver(mdriver) container_of(mdriver, struct mca_driver, driver)
-
-/* Ongoing supported API functions */
-extern struct mca_device *mca_find_device_by_slot(int slot);
-extern int mca_system_init(void);
-extern struct mca_bus *mca_attach_bus(int);
-
-extern unsigned char mca_device_read_stored_pos(struct mca_device *mca_dev,
- int reg);
-extern unsigned char mca_device_read_pos(struct mca_device *mca_dev, int reg);
-extern void mca_device_write_pos(struct mca_device *mca_dev, int reg,
- unsigned char byte);
-extern int mca_device_transform_irq(struct mca_device *mca_dev, int irq);
-extern int mca_device_transform_ioport(struct mca_device *mca_dev, int port);
-extern void *mca_device_transform_memory(struct mca_device *mca_dev,
- void *mem);
-extern int mca_device_claimed(struct mca_device *mca_dev);
-extern void mca_device_set_claim(struct mca_device *mca_dev, int val);
-extern void mca_device_set_name(struct mca_device *mca_dev, const char *name);
-static inline char *mca_device_get_name(struct mca_device *mca_dev)
-{
- return mca_dev ? mca_dev->name : NULL;
-}
-
-extern enum MCA_AdapterStatus mca_device_status(struct mca_device *mca_dev);
-
-extern struct bus_type mca_bus_type;
-
-extern int mca_register_driver(struct mca_driver *drv);
-extern int mca_register_driver_integrated(struct mca_driver *, int);
-extern void mca_unregister_driver(struct mca_driver *drv);
-
-/* WARNING: only called by the boot time device setup */
-extern int mca_register_device(int bus, struct mca_device *mca_dev);
-
-#ifdef CONFIG_MCA_PROC_FS
-extern void mca_do_proc_init(void);
-extern void mca_set_adapter_procfn(int slot, MCA_ProcFn, void* dev);
-#else
-static inline void mca_do_proc_init(void)
-{
-}
-
-static inline void mca_set_adapter_procfn(int slot, MCA_ProcFn fn, void* dev)
-{
-}
-#endif
-
-#endif /* _LINUX_MCA_H */
diff --git a/drivers/staging/mei/mei.h b/include/linux/mei.h
index bc0d8b69c49e..bc0d8b69c49e 100644
--- a/drivers/staging/mei/mei.h
+++ b/include/linux/mei.h
diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h
index ee96cd51d8b2..1318ca622633 100644
--- a/include/linux/mfd/abx500.h
+++ b/include/linux/mfd/abx500.h
@@ -6,7 +6,7 @@
*
* ABX500 core access functions.
* The abx500 interface is used for the Analog Baseband chip
- * ab3100, ab5500, and ab8500.
+ * ab3100 and ab8500.
*
* Author: Mattias Wallin <mattias.wallin@stericsson.com>
* Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
@@ -30,9 +30,6 @@ struct device;
#define AB3100_P1G 0xc6
#define AB3100_R2A 0xc7
#define AB3100_R2B 0xc8
-#define AB5500_1_0 0x20
-#define AB5500_1_1 0x21
-#define AB5500_2_0 0x24
/*
* AB3100, EVENTA1, A2 and A3 event register flags
diff --git a/include/linux/mfd/abx500/ab5500.h b/include/linux/mfd/abx500/ab5500.h
deleted file mode 100644
index 54f820ed73bb..000000000000
--- a/include/linux/mfd/abx500/ab5500.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson 2011
- *
- * License Terms: GNU General Public License v2
- */
-#ifndef MFD_AB5500_H
-#define MFD_AB5500_H
-
-struct device;
-
-enum ab5500_devid {
- AB5500_DEVID_ADC,
- AB5500_DEVID_LEDS,
- AB5500_DEVID_POWER,
- AB5500_DEVID_REGULATORS,
- AB5500_DEVID_SIM,
- AB5500_DEVID_RTC,
- AB5500_DEVID_CHARGER,
- AB5500_DEVID_FUELGAUGE,
- AB5500_DEVID_VIBRATOR,
- AB5500_DEVID_CODEC,
- AB5500_DEVID_USB,
- AB5500_DEVID_OTP,
- AB5500_DEVID_VIDEO,
- AB5500_DEVID_DBIECI,
- AB5500_DEVID_ONSWA,
- AB5500_NUM_DEVICES,
-};
-
-enum ab5500_banks {
- AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP = 0,
- AB5500_BANK_VDDDIG_IO_I2C_CLK_TST = 1,
- AB5500_BANK_VDENC = 2,
- AB5500_BANK_SIM_USBSIM = 3,
- AB5500_BANK_LED = 4,
- AB5500_BANK_ADC = 5,
- AB5500_BANK_RTC = 6,
- AB5500_BANK_STARTUP = 7,
- AB5500_BANK_DBI_ECI = 8,
- AB5500_BANK_CHG = 9,
- AB5500_BANK_FG_BATTCOM_ACC = 10,
- AB5500_BANK_USB = 11,
- AB5500_BANK_IT = 12,
- AB5500_BANK_VIBRA = 13,
- AB5500_BANK_AUDIO_HEADSETUSB = 14,
- AB5500_NUM_BANKS = 15,
-};
-
-enum ab5500_banks_addr {
- AB5500_ADDR_VIT_IO_I2C_CLK_TST_OTP = 0x4A,
- AB5500_ADDR_VDDDIG_IO_I2C_CLK_TST = 0x4B,
- AB5500_ADDR_VDENC = 0x06,
- AB5500_ADDR_SIM_USBSIM = 0x04,
- AB5500_ADDR_LED = 0x10,
- AB5500_ADDR_ADC = 0x0A,
- AB5500_ADDR_RTC = 0x0F,
- AB5500_ADDR_STARTUP = 0x03,
- AB5500_ADDR_DBI_ECI = 0x07,
- AB5500_ADDR_CHG = 0x0B,
- AB5500_ADDR_FG_BATTCOM_ACC = 0x0C,
- AB5500_ADDR_USB = 0x05,
- AB5500_ADDR_IT = 0x0E,
- AB5500_ADDR_VIBRA = 0x02,
- AB5500_ADDR_AUDIO_HEADSETUSB = 0x0D,
-};
-
-/*
- * Interrupt register offsets
- * Bank : 0x0E
- */
-#define AB5500_IT_SOURCE0_REG 0x20
-#define AB5500_IT_SOURCE1_REG 0x21
-#define AB5500_IT_SOURCE2_REG 0x22
-#define AB5500_IT_SOURCE3_REG 0x23
-#define AB5500_IT_SOURCE4_REG 0x24
-#define AB5500_IT_SOURCE5_REG 0x25
-#define AB5500_IT_SOURCE6_REG 0x26
-#define AB5500_IT_SOURCE7_REG 0x27
-#define AB5500_IT_SOURCE8_REG 0x28
-#define AB5500_IT_SOURCE9_REG 0x29
-#define AB5500_IT_SOURCE10_REG 0x2A
-#define AB5500_IT_SOURCE11_REG 0x2B
-#define AB5500_IT_SOURCE12_REG 0x2C
-#define AB5500_IT_SOURCE13_REG 0x2D
-#define AB5500_IT_SOURCE14_REG 0x2E
-#define AB5500_IT_SOURCE15_REG 0x2F
-#define AB5500_IT_SOURCE16_REG 0x30
-#define AB5500_IT_SOURCE17_REG 0x31
-#define AB5500_IT_SOURCE18_REG 0x32
-#define AB5500_IT_SOURCE19_REG 0x33
-#define AB5500_IT_SOURCE20_REG 0x34
-#define AB5500_IT_SOURCE21_REG 0x35
-#define AB5500_IT_SOURCE22_REG 0x36
-#define AB5500_IT_SOURCE23_REG 0x37
-
-#define AB5500_NUM_IRQ_REGS 23
-
-/**
- * struct ab5500
- * @access_mutex: lock out concurrent accesses to the AB registers
- * @dev: a pointer to the device struct for this chip driver
- * @ab5500_irq: the analog baseband irq
- * @irq_base: the platform configuration irq base for subdevices
- * @chip_name: name of this chip variant
- * @chip_id: 8 bit chip ID for this chip variant
- * @irq_lock: a lock to protect the mask
- * @abb_events: a local bit mask of the prcmu wakeup events
- * @event_mask: a local copy of the mask event registers
- * @last_event_mask: a copy of the last event_mask written to hardware
- * @startup_events: a copy of the first reading of the event registers
- * @startup_events_read: whether the first events have been read
- */
-struct ab5500 {
- struct mutex access_mutex;
- struct device *dev;
- unsigned int ab5500_irq;
- unsigned int irq_base;
- char chip_name[32];
- u8 chip_id;
- struct mutex irq_lock;
- u32 abb_events;
- u8 mask[AB5500_NUM_IRQ_REGS];
- u8 oldmask[AB5500_NUM_IRQ_REGS];
- u8 startup_events[AB5500_NUM_IRQ_REGS];
- bool startup_events_read;
-#ifdef CONFIG_DEBUG_FS
- unsigned int debug_bank;
- unsigned int debug_address;
-#endif
-};
-
-struct ab5500_platform_data {
- struct {unsigned int base; unsigned int count; } irq;
- void *dev_data[AB5500_NUM_DEVICES];
- struct abx500_init_settings *init_settings;
- unsigned int init_settings_sz;
- bool pm_power_off;
-};
-
-#endif /* MFD_AB5500_H */
diff --git a/include/linux/mfd/asic3.h b/include/linux/mfd/asic3.h
index ed793b77a1c5..ef6faa5cee46 100644
--- a/include/linux/mfd/asic3.h
+++ b/include/linux/mfd/asic3.h
@@ -138,6 +138,7 @@ struct asic3_platform_data {
#define ASIC3_GPIOC13_nPWAIT ASIC3_CONFIG_GPIO(45, 1, 1, 0)
#define ASIC3_GPIOC14_nPIOIS16 ASIC3_CONFIG_GPIO(46, 1, 1, 0)
#define ASIC3_GPIOC15_nPIOR ASIC3_CONFIG_GPIO(47, 1, 0, 0)
+#define ASIC3_GPIOD4_CF_nCD ASIC3_CONFIG_GPIO(52, 1, 0, 0)
#define ASIC3_GPIOD11_nCIOIS16 ASIC3_CONFIG_GPIO(59, 1, 0, 0)
#define ASIC3_GPIOD12_nCWAIT ASIC3_CONFIG_GPIO(60, 1, 0, 0)
#define ASIC3_GPIOD15_nPIOW ASIC3_CONFIG_GPIO(63, 1, 0, 0)
diff --git a/include/linux/mfd/db5500-prcmu.h b/include/linux/mfd/db5500-prcmu.h
deleted file mode 100644
index 5a049dfaf153..000000000000
--- a/include/linux/mfd/db5500-prcmu.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License Terms: GNU General Public License v2
- *
- * U5500 PRCMU API.
- */
-#ifndef __MFD_DB5500_PRCMU_H
-#define __MFD_DB5500_PRCMU_H
-
-static inline int prcmu_resetout(u8 resoutn, u8 state)
-{
- return 0;
-}
-
-static inline int db5500_prcmu_set_epod(u16 epod_id, u8 epod_state)
-{
- return 0;
-}
-
-static inline int db5500_prcmu_request_clock(u8 clock, bool enable)
-{
- return 0;
-}
-
-static inline int db5500_prcmu_set_power_state(u8 state, bool keep_ulp_clk,
- bool keep_ap_pll)
-{
- return 0;
-}
-
-static inline int db5500_prcmu_config_esram0_deep_sleep(u8 state)
-{
- return 0;
-}
-
-static inline u16 db5500_prcmu_get_reset_code(void)
-{
- return 0;
-}
-
-static inline bool db5500_prcmu_is_ac_wake_requested(void)
-{
- return 0;
-}
-
-static inline int db5500_prcmu_set_arm_opp(u8 opp)
-{
- return 0;
-}
-
-static inline int db5500_prcmu_get_arm_opp(void)
-{
- return 0;
-}
-
-static inline void db5500_prcmu_config_abb_event_readout(u32 abb_events) {}
-
-static inline void db5500_prcmu_get_abb_event_buffer(void __iomem **buf) {}
-
-static inline void db5500_prcmu_system_reset(u16 reset_code) {}
-
-static inline void db5500_prcmu_enable_wakeups(u32 wakeups) {}
-
-#ifdef CONFIG_MFD_DB5500_PRCMU
-
-void db5500_prcmu_early_init(void);
-int db5500_prcmu_set_display_clocks(void);
-int db5500_prcmu_disable_dsipll(void);
-int db5500_prcmu_enable_dsipll(void);
-int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
-int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
-
-#else /* !CONFIG_UX500_SOC_DB5500 */
-
-static inline void db5500_prcmu_early_init(void) {}
-
-static inline int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
-{
- return -ENOSYS;
-}
-
-static inline int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
-{
- return -ENOSYS;
-}
-
-static inline int db5500_prcmu_set_display_clocks(void)
-{
- return 0;
-}
-
-static inline int db5500_prcmu_disable_dsipll(void)
-{
- return 0;
-}
-
-static inline int db5500_prcmu_enable_dsipll(void)
-{
- return 0;
-}
-
-#endif /* CONFIG_MFD_DB5500_PRCMU */
-
-#endif /* __MFD_DB5500_PRCMU_H */
diff --git a/include/linux/mfd/dbx500-prcmu.h b/include/linux/mfd/dbx500-prcmu.h
index d7674eb7305f..5a13f93d8f1c 100644
--- a/include/linux/mfd/dbx500-prcmu.h
+++ b/include/linux/mfd/dbx500-prcmu.h
@@ -55,17 +55,6 @@ enum prcmu_wakeup_index {
#define NUM_EPOD_ID 8
/*
- * DB5500 EPODs
- */
-#define DB5500_EPOD_ID_BASE 0x0100
-#define DB5500_EPOD_ID_SGA (DB5500_EPOD_ID_BASE + 0)
-#define DB5500_EPOD_ID_HVA (DB5500_EPOD_ID_BASE + 1)
-#define DB5500_EPOD_ID_SIA (DB5500_EPOD_ID_BASE + 2)
-#define DB5500_EPOD_ID_DISP (DB5500_EPOD_ID_BASE + 3)
-#define DB5500_EPOD_ID_ESRAM12 (DB5500_EPOD_ID_BASE + 6)
-#define DB5500_NUM_EPOD_ID 7
-
-/*
* state definition for EPOD (power domain)
* - EPOD_STATE_NO_CHANGE: The EPOD should remain unchanged
* - EPOD_STATE_OFF: The EPOD is switched off
@@ -80,29 +69,6 @@ enum prcmu_wakeup_index {
#define EPOD_STATE_ON_CLK_OFF 0x03
#define EPOD_STATE_ON 0x04
-/* DB5500 CLKOUT IDs */
-enum {
- DB5500_CLKOUT0 = 0,
- DB5500_CLKOUT1,
-};
-
-/* DB5500 CLKOUTx sources */
-enum {
- DB5500_CLKOUT_REF_CLK_SEL0,
- DB5500_CLKOUT_RTC_CLK0_SEL0,
- DB5500_CLKOUT_ULP_CLK_SEL0,
- DB5500_CLKOUT_STATIC0,
- DB5500_CLKOUT_REFCLK,
- DB5500_CLKOUT_ULPCLK,
- DB5500_CLKOUT_ARMCLK,
- DB5500_CLKOUT_SYSACC0CLK,
- DB5500_CLKOUT_SOC0PLLCLK,
- DB5500_CLKOUT_SOC1PLLCLK,
- DB5500_CLKOUT_DDRPLLCLK,
- DB5500_CLKOUT_TVCLK,
- DB5500_CLKOUT_IRDACLK,
-};
-
/*
* CLKOUT sources
*/
@@ -248,101 +214,66 @@ enum ddr_pwrst {
};
#include <linux/mfd/db8500-prcmu.h>
-#include <linux/mfd/db5500-prcmu.h>
-#if defined(CONFIG_UX500_SOC_DB8500) || defined(CONFIG_UX500_SOC_DB5500)
+#if defined(CONFIG_UX500_SOC_DB8500)
#include <mach/id.h>
static inline void __init prcmu_early_init(void)
{
- if (cpu_is_u5500())
- return db5500_prcmu_early_init();
- else
- return db8500_prcmu_early_init();
+ return db8500_prcmu_early_init();
}
static inline int prcmu_set_power_state(u8 state, bool keep_ulp_clk,
bool keep_ap_pll)
{
- if (cpu_is_u5500())
- return db5500_prcmu_set_power_state(state, keep_ulp_clk,
- keep_ap_pll);
- else
- return db8500_prcmu_set_power_state(state, keep_ulp_clk,
- keep_ap_pll);
+ return db8500_prcmu_set_power_state(state, keep_ulp_clk,
+ keep_ap_pll);
}
static inline u8 prcmu_get_power_state_result(void)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_get_power_state_result();
+ return db8500_prcmu_get_power_state_result();
}
static inline int prcmu_gic_decouple(void)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_gic_decouple();
+ return db8500_prcmu_gic_decouple();
}
static inline int prcmu_gic_recouple(void)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_gic_recouple();
+ return db8500_prcmu_gic_recouple();
}
static inline bool prcmu_gic_pending_irq(void)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_gic_pending_irq();
+ return db8500_prcmu_gic_pending_irq();
}
static inline bool prcmu_is_cpu_in_wfi(int cpu)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_is_cpu_in_wfi(cpu);
+ return db8500_prcmu_is_cpu_in_wfi(cpu);
}
static inline int prcmu_copy_gic_settings(void)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_copy_gic_settings();
+ return db8500_prcmu_copy_gic_settings();
}
static inline bool prcmu_pending_irq(void)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_pending_irq();
+ return db8500_prcmu_pending_irq();
}
static inline int prcmu_set_epod(u16 epod_id, u8 epod_state)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_set_epod(epod_id, epod_state);
+ return db8500_prcmu_set_epod(epod_id, epod_state);
}
static inline void prcmu_enable_wakeups(u32 wakeups)
{
- if (cpu_is_u5500())
- db5500_prcmu_enable_wakeups(wakeups);
- else
- db8500_prcmu_enable_wakeups(wakeups);
+ db8500_prcmu_enable_wakeups(wakeups);
}
static inline void prcmu_disable_wakeups(void)
@@ -352,18 +283,12 @@ static inline void prcmu_disable_wakeups(void)
static inline void prcmu_config_abb_event_readout(u32 abb_events)
{
- if (cpu_is_u5500())
- db5500_prcmu_config_abb_event_readout(abb_events);
- else
- db8500_prcmu_config_abb_event_readout(abb_events);
+ db8500_prcmu_config_abb_event_readout(abb_events);
}
static inline void prcmu_get_abb_event_buffer(void __iomem **buf)
{
- if (cpu_is_u5500())
- db5500_prcmu_get_abb_event_buffer(buf);
- else
- db8500_prcmu_get_abb_event_buffer(buf);
+ db8500_prcmu_get_abb_event_buffer(buf);
}
int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
@@ -374,10 +299,7 @@ int prcmu_config_clkout(u8 clkout, u8 source, u8 div);
static inline int prcmu_request_clock(u8 clock, bool enable)
{
- if (cpu_is_u5500())
- return db5500_prcmu_request_clock(clock, enable);
- else
- return db8500_prcmu_request_clock(clock, enable);
+ return db8500_prcmu_request_clock(clock, enable);
}
unsigned long prcmu_clock_rate(u8 clock);
@@ -386,211 +308,133 @@ int prcmu_set_clock_rate(u8 clock, unsigned long rate);
static inline int prcmu_set_ddr_opp(u8 opp)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_set_ddr_opp(opp);
+ return db8500_prcmu_set_ddr_opp(opp);
}
static inline int prcmu_get_ddr_opp(void)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_get_ddr_opp();
+ return db8500_prcmu_get_ddr_opp();
}
static inline int prcmu_set_arm_opp(u8 opp)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_set_arm_opp(opp);
+ return db8500_prcmu_set_arm_opp(opp);
}
static inline int prcmu_get_arm_opp(void)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_get_arm_opp();
+ return db8500_prcmu_get_arm_opp();
}
static inline int prcmu_set_ape_opp(u8 opp)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_set_ape_opp(opp);
+ return db8500_prcmu_set_ape_opp(opp);
}
static inline int prcmu_get_ape_opp(void)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_get_ape_opp();
+ return db8500_prcmu_get_ape_opp();
}
static inline void prcmu_system_reset(u16 reset_code)
{
- if (cpu_is_u5500())
- return db5500_prcmu_system_reset(reset_code);
- else
- return db8500_prcmu_system_reset(reset_code);
+ return db8500_prcmu_system_reset(reset_code);
}
static inline u16 prcmu_get_reset_code(void)
{
- if (cpu_is_u5500())
- return db5500_prcmu_get_reset_code();
- else
- return db8500_prcmu_get_reset_code();
+ return db8500_prcmu_get_reset_code();
}
void prcmu_ac_wake_req(void);
void prcmu_ac_sleep_req(void);
static inline void prcmu_modem_reset(void)
{
- if (cpu_is_u5500())
- return;
- else
- return db8500_prcmu_modem_reset();
+ return db8500_prcmu_modem_reset();
}
static inline bool prcmu_is_ac_wake_requested(void)
{
- if (cpu_is_u5500())
- return db5500_prcmu_is_ac_wake_requested();
- else
- return db8500_prcmu_is_ac_wake_requested();
+ return db8500_prcmu_is_ac_wake_requested();
}
static inline int prcmu_set_display_clocks(void)
{
- if (cpu_is_u5500())
- return db5500_prcmu_set_display_clocks();
- else
- return db8500_prcmu_set_display_clocks();
+ return db8500_prcmu_set_display_clocks();
}
static inline int prcmu_disable_dsipll(void)
{
- if (cpu_is_u5500())
- return db5500_prcmu_disable_dsipll();
- else
- return db8500_prcmu_disable_dsipll();
+ return db8500_prcmu_disable_dsipll();
}
static inline int prcmu_enable_dsipll(void)
{
- if (cpu_is_u5500())
- return db5500_prcmu_enable_dsipll();
- else
- return db8500_prcmu_enable_dsipll();
+ return db8500_prcmu_enable_dsipll();
}
static inline int prcmu_config_esram0_deep_sleep(u8 state)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_config_esram0_deep_sleep(state);
+ return db8500_prcmu_config_esram0_deep_sleep(state);
}
static inline int prcmu_config_hotdog(u8 threshold)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_config_hotdog(threshold);
+ return db8500_prcmu_config_hotdog(threshold);
}
static inline int prcmu_config_hotmon(u8 low, u8 high)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_config_hotmon(low, high);
+ return db8500_prcmu_config_hotmon(low, high);
}
static inline int prcmu_start_temp_sense(u16 cycles32k)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_start_temp_sense(cycles32k);
+ return db8500_prcmu_start_temp_sense(cycles32k);
}
static inline int prcmu_stop_temp_sense(void)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_stop_temp_sense();
+ return db8500_prcmu_stop_temp_sense();
}
static inline u32 prcmu_read(unsigned int reg)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_read(reg);
+ return db8500_prcmu_read(reg);
}
static inline void prcmu_write(unsigned int reg, u32 value)
{
- if (cpu_is_u5500())
- return;
- else
- db8500_prcmu_write(reg, value);
+ db8500_prcmu_write(reg, value);
}
static inline void prcmu_write_masked(unsigned int reg, u32 mask, u32 value)
{
- if (cpu_is_u5500())
- return;
- else
- db8500_prcmu_write_masked(reg, mask, value);
+ db8500_prcmu_write_masked(reg, mask, value);
}
static inline int prcmu_enable_a9wdog(u8 id)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_enable_a9wdog(id);
+ return db8500_prcmu_enable_a9wdog(id);
}
static inline int prcmu_disable_a9wdog(u8 id)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_disable_a9wdog(id);
+ return db8500_prcmu_disable_a9wdog(id);
}
static inline int prcmu_kick_a9wdog(u8 id)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_kick_a9wdog(id);
+ return db8500_prcmu_kick_a9wdog(id);
}
static inline int prcmu_load_a9wdog(u8 id, u32 timeout)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_load_a9wdog(id, timeout);
+ return db8500_prcmu_load_a9wdog(id, timeout);
}
static inline int prcmu_config_a9wdog(u8 num, bool sleep_auto_off)
{
- if (cpu_is_u5500())
- return -EINVAL;
- else
- return db8500_prcmu_config_a9wdog(num, sleep_auto_off);
+ return db8500_prcmu_config_a9wdog(num, sleep_auto_off);
}
#else
@@ -768,7 +612,7 @@ static inline void prcmu_clear(unsigned int reg, u32 bits)
prcmu_write_masked(reg, bits, 0);
}
-#if defined(CONFIG_UX500_SOC_DB8500) || defined(CONFIG_UX500_SOC_DB5500)
+#if defined(CONFIG_UX500_SOC_DB8500)
/**
* prcmu_enable_spi2 - Enables pin muxing for SPI2 on OtherAlternateC1.
diff --git a/include/linux/mfd/max8997.h b/include/linux/mfd/max8997.h
index 28726dd540f2..b40c08cd30bc 100644
--- a/include/linux/mfd/max8997.h
+++ b/include/linux/mfd/max8997.h
@@ -99,34 +99,11 @@ struct max8997_muic_reg_data {
/**
* struct max8997_muic_platform_data
- * @usb_callback: callback function for USB
- * inform callee of USB type (HOST or DEVICE)
- * and attached state(true or false)
- * @charger_callback: callback function for charger
- * inform callee of charger_type
- * and attached state(true or false)
- * @deskdock_callback: callback function for desk dock
- * inform callee of attached state(true or false)
- * @cardock_callback: callback function for car dock
- * inform callee of attached state(true or false)
- * @mhl_callback: callback function for MHL (Mobile High-definition Link)
- * inform callee of attached state(true or false)
- * @uart_callback: callback function for JIG UART
- * inform callee of attached state(true or false)
* @init_data: array of max8997_muic_reg_data
* used for initializing registers of MAX8997 MUIC device
* @num_init_data: array size of init_data
*/
struct max8997_muic_platform_data {
- void (*usb_callback)(enum max8997_muic_usb_type usb_type,
- bool attached);
- void (*charger_callback)(bool attached,
- enum max8997_muic_charger_type charger_type);
- void (*deskdock_callback) (bool attached);
- void (*cardock_callback) (bool attached);
- void (*mhl_callback) (bool attached);
- void (*uart_callback) (bool attached);
-
struct max8997_muic_reg_data *init_data;
int num_init_data;
};
diff --git a/include/linux/mfd/mc13xxx.h b/include/linux/mfd/mc13xxx.h
index 10e038bac8dd..bf070755982e 100644
--- a/include/linux/mfd/mc13xxx.h
+++ b/include/linux/mfd/mc13xxx.h
@@ -170,6 +170,16 @@ struct mc13xxx_ts_platform_data {
bool atox;
};
+enum mc13783_ssi_port {
+ MC13783_SSI1_PORT,
+ MC13783_SSI2_PORT,
+};
+
+struct mc13xxx_codec_platform_data {
+ enum mc13783_ssi_port adc_ssi_port;
+ enum mc13783_ssi_port dac_ssi_port;
+};
+
struct mc13xxx_platform_data {
#define MC13XXX_USE_TOUCHSCREEN (1 << 0)
#define MC13XXX_USE_CODEC (1 << 1)
@@ -181,6 +191,7 @@ struct mc13xxx_platform_data {
struct mc13xxx_leds_platform_data *leds;
struct mc13xxx_buttons_platform_data *buttons;
struct mc13xxx_ts_platform_data touch;
+ struct mc13xxx_codec_platform_data *codec;
};
#define MC13XXX_ADC_MODE_TS 1
diff --git a/include/linux/mfd/rc5t583.h b/include/linux/mfd/rc5t583.h
index c42fe92a727d..3661c59aa1e9 100644
--- a/include/linux/mfd/rc5t583.h
+++ b/include/linux/mfd/rc5t583.h
@@ -292,6 +292,7 @@ struct rc5t583 {
* rc5t583_platform_data: Platform data for ricoh rc5t583 pmu.
* The board specific data is provided through this structure.
* @irq_base: Irq base number on which this device registers their interrupts.
+ * @gpio_base: GPIO base from which gpio of this device will start.
* @enable_shutdown: Enable shutdown through the input pin "shutdown".
* @regulator_deepsleep_slot: The slot number on which device goes to sleep
* in device sleep mode.
@@ -303,6 +304,7 @@ struct rc5t583 {
struct rc5t583_platform_data {
int irq_base;
+ int gpio_base;
bool enable_shutdown;
int regulator_deepsleep_slot[RC5T583_REGULATOR_MAX];
unsigned long regulator_ext_pwr_control[RC5T583_REGULATOR_MAX];
diff --git a/include/linux/mfd/wm831x/pdata.h b/include/linux/mfd/wm831x/pdata.h
index 1d7a3f7b3b5d..dcc9631b3052 100644
--- a/include/linux/mfd/wm831x/pdata.h
+++ b/include/linux/mfd/wm831x/pdata.h
@@ -26,7 +26,7 @@ struct wm831x_backlight_pdata {
struct wm831x_backup_pdata {
int charger_enable;
int no_constant_voltage; /** Disable constant voltage charging */
- int vlim; /** Voltage limit in milivolts */
+ int vlim; /** Voltage limit in millivolts */
int ilim; /** Current limit in microamps */
};
diff --git a/include/linux/micrel_phy.h b/include/linux/micrel_phy.h
index dd8da342a991..61f0905bdc48 100644
--- a/include/linux/micrel_phy.h
+++ b/include/linux/micrel_phy.h
@@ -3,7 +3,7 @@
#define MICREL_PHY_ID_MASK 0x00fffff0
-#define PHY_ID_KSZ9021 0x00221611
+#define PHY_ID_KSZ9021 0x00221610
#define PHY_ID_KS8737 0x00221720
#define PHY_ID_KS8041 0x00221510
#define PHY_ID_KS8051 0x00221550
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 3cc3062b3767..26574c726121 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -12,6 +12,7 @@
#include <linux/completion.h>
#include <linux/cpumask.h>
#include <linux/page-debug-flags.h>
+#include <linux/uprobes.h>
#include <asm/page.h>
#include <asm/mmu.h>
@@ -388,6 +389,7 @@ struct mm_struct {
#ifdef CONFIG_CPUMASK_OFFSTACK
struct cpumask cpumask_allocation;
#endif
+ struct uprobes_state uprobes_state;
};
static inline void mm_init_cpumask(struct mm_struct *mm)
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index dff711509661..41aa49b74821 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -30,7 +30,7 @@
/*
* PAGE_ALLOC_COSTLY_ORDER is the order at which allocations are deemed
* costly to service. That is between allocation orders which should
- * coelesce naturally under reasonable reclaim pressure and those which
+ * coalesce naturally under reasonable reclaim pressure and those which
* will not.
*/
#define PAGE_ALLOC_COSTLY_ORDER 3
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 501da4cb8a6d..5db93821f9c7 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -132,10 +132,12 @@ struct usb_device_id {
#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200
#define HID_ANY_ID (~0)
+#define HID_BUS_ANY 0xffff
+#define HID_GROUP_ANY 0x0000
struct hid_device_id {
__u16 bus;
- __u16 pad1;
+ __u16 group;
__u32 vendor;
__u32 product;
kernel_ulong_t driver_data
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
index ea36486378d8..1b14d25162cb 100644
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -320,7 +320,8 @@ extern int parse_args(const char *name,
unsigned num,
s16 level_min,
s16 level_max,
- int (*unknown)(char *param, char *val));
+ int (*unknown)(char *param, char *val,
+ const char *doing));
/* Called by module remove. */
#ifdef CONFIG_SYSFS
diff --git a/include/linux/mtd/ubi.h b/include/linux/mtd/ubi.h
index db4836bed514..c3918a0684fe 100644
--- a/include/linux/mtd/ubi.h
+++ b/include/linux/mtd/ubi.h
@@ -25,6 +25,9 @@
#include <linux/types.h>
#include <mtd/ubi-user.h>
+/* All voumes/LEBs */
+#define UBI_ALL -1
+
/*
* enum ubi_open_mode - UBI volume open mode constants.
*
@@ -208,14 +211,15 @@ void ubi_close_volume(struct ubi_volume_desc *desc);
int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
int len, int check);
int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf,
- int offset, int len, int dtype);
+ int offset, int len);
int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf,
- int len, int dtype);
+ int len);
int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum);
int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum);
-int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype);
+int ubi_leb_map(struct ubi_volume_desc *desc, int lnum);
int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum);
int ubi_sync(int ubi_num);
+int ubi_flush(int ubi_num, int vol_id, int lnum);
/*
* This function is the same as the 'ubi_leb_read()' function, but it does not
@@ -226,25 +230,4 @@ static inline int ubi_read(struct ubi_volume_desc *desc, int lnum, char *buf,
{
return ubi_leb_read(desc, lnum, buf, offset, len, 0);
}
-
-/*
- * This function is the same as the 'ubi_leb_write()' functions, but it does
- * not have the data type argument.
- */
-static inline int ubi_write(struct ubi_volume_desc *desc, int lnum,
- const void *buf, int offset, int len)
-{
- return ubi_leb_write(desc, lnum, buf, offset, len, UBI_UNKNOWN);
-}
-
-/*
- * This function is the same as the 'ubi_leb_change()' functions, but it does
- * not have the data type argument.
- */
-static inline int ubi_change(struct ubi_volume_desc *desc, int lnum,
- const void *buf, int len)
-{
- return ubi_leb_change(desc, lnum, buf, len, UBI_UNKNOWN);
-}
-
#endif /* !__LINUX_UBI_H__ */
diff --git a/include/linux/nfc/pn544.h b/include/linux/nfc/pn544.h
index 7ab8521f2347..9890bbaf4328 100644
--- a/include/linux/nfc/pn544.h
+++ b/include/linux/nfc/pn544.h
@@ -84,6 +84,12 @@ struct pn544_fw_packet {
};
#ifdef __KERNEL__
+enum {
+ NFC_GPIO_ENABLE,
+ NFC_GPIO_FW_RESET,
+ NFC_GPIO_IRQ
+};
+
/* board config */
struct pn544_nfc_platform_data {
int (*request_resources) (struct i2c_client *client);
@@ -91,6 +97,7 @@ struct pn544_nfc_platform_data {
void (*enable) (int fw);
int (*test) (void);
void (*disable) (void);
+ int (*get_gpio)(int type);
};
#endif /* __KERNEL__ */
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 2540e86d99ab..a6959f72745e 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1594,6 +1594,8 @@ enum nl80211_sta_flags {
NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
};
+#define NL80211_STA_FLAG_MAX_OLD_API NL80211_STA_FLAG_TDLS_PEER
+
/**
* struct nl80211_sta_flag_update - station flags mask/set
* @mask: mask of station flags to set
@@ -1994,9 +1996,9 @@ enum nl80211_reg_rule_flags {
* enum nl80211_dfs_regions - regulatory DFS regions
*
* @NL80211_DFS_UNSET: Country has no DFS master region specified
- * @NL80211_DFS_FCC_: Country follows DFS master rules from FCC
- * @NL80211_DFS_FCC_: Country follows DFS master rules from ETSI
- * @NL80211_DFS_JP_: Country follows DFS master rules from JP/MKK/Telec
+ * @NL80211_DFS_FCC: Country follows DFS master rules from FCC
+ * @NL80211_DFS_ETSI: Country follows DFS master rules from ETSI
+ * @NL80211_DFS_JP: Country follows DFS master rules from JP/MKK/Telec
*/
enum nl80211_dfs_regions {
NL80211_DFS_UNSET = 0,
diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h
index 81733d12cbea..c454f5796747 100644
--- a/include/linux/of_gpio.h
+++ b/include/linux/of_gpio.h
@@ -58,7 +58,6 @@ extern int of_mm_gpiochip_add(struct device_node *np,
extern void of_gpiochip_add(struct gpio_chip *gc);
extern void of_gpiochip_remove(struct gpio_chip *gc);
-extern struct gpio_chip *of_node_to_gpiochip(struct device_node *np);
extern int of_gpio_simple_xlate(struct gpio_chip *gc,
const struct of_phandle_args *gpiospec,
u32 *flags);
diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h
index d229ad3edee0..1717cd935e1c 100644
--- a/include/linux/of_irq.h
+++ b/include/linux/of_irq.h
@@ -11,7 +11,7 @@ struct of_irq;
#include <linux/of.h>
/*
- * irq_of_parse_and_map() is used ba all OF enabled platforms; but SPARC
+ * irq_of_parse_and_map() is used by all OF enabled platforms; but SPARC
* implements it differently. However, the prototype is the same for all,
* so declare it here regardless of the CONFIG_OF_IRQ setting.
*/
@@ -76,5 +76,13 @@ extern struct device_node *of_irq_find_parent(struct device_node *child);
extern void of_irq_init(const struct of_device_id *matches);
#endif /* CONFIG_OF_IRQ */
-#endif /* CONFIG_OF */
+
+#else /* !CONFIG_OF */
+static inline unsigned int irq_of_parse_and_map(struct device_node *dev,
+ int index)
+{
+ return 0;
+}
+#endif /* !CONFIG_OF */
+
#endif /* __OF_IRQ_H */
diff --git a/include/linux/of_serial.h b/include/linux/of_serial.h
new file mode 100644
index 000000000000..4a73ed80b4c0
--- /dev/null
+++ b/include/linux/of_serial.h
@@ -0,0 +1,17 @@
+#ifndef __LINUX_OF_SERIAL_H
+#define __LINUX_OF_SERIAL_H
+
+/*
+ * FIXME remove this file when tegra finishes conversion to open firmware,
+ * expectation is that all quirks will then be self-contained in
+ * drivers/tty/serial/of_serial.c.
+ */
+#ifdef CONFIG_ARCH_TEGRA
+extern void tegra_serial_handle_break(struct uart_port *port);
+#else
+static inline void tegra_serial_handle_break(struct uart_port *port)
+{
+}
+#endif
+
+#endif /* __LINUX_OF_SERIAL */
diff --git a/include/linux/of_spi.h b/include/linux/of_spi.h
deleted file mode 100644
index 9e3e70f78ae6..000000000000
--- a/include/linux/of_spi.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * OpenFirmware SPI support routines
- * Copyright (C) 2008 Secret Lab Technologies Ltd.
- *
- * Support routines for deriving SPI device attachments from the device
- * tree.
- */
-
-#ifndef __LINUX_OF_SPI_H
-#define __LINUX_OF_SPI_H
-
-#include <linux/spi/spi.h>
-
-#if defined(CONFIG_OF_SPI) || defined(CONFIG_OF_SPI_MODULE)
-extern void of_register_spi_devices(struct spi_master *master);
-#else
-static inline void of_register_spi_devices(struct spi_master *master)
-{
- return;
-}
-#endif /* CONFIG_OF_SPI */
-
-#endif /* __LINUX_OF_SPI */
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index cfaaa6949b8b..efa26b4da8d2 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -426,7 +426,7 @@ static inline int fault_in_pages_writeable(char __user *uaddr, int size)
*/
if (((unsigned long)uaddr & PAGE_MASK) !=
((unsigned long)end & PAGE_MASK))
- ret = __put_user(0, end);
+ ret = __put_user(0, end);
}
return ret;
}
@@ -445,13 +445,73 @@ static inline int fault_in_pages_readable(const char __user *uaddr, int size)
if (((unsigned long)uaddr & PAGE_MASK) !=
((unsigned long)end & PAGE_MASK)) {
- ret = __get_user(c, end);
+ ret = __get_user(c, end);
(void)c;
}
}
return ret;
}
+/*
+ * Multipage variants of the above prefault helpers, useful if more than
+ * PAGE_SIZE of data needs to be prefaulted. These are separate from the above
+ * functions (which only handle up to PAGE_SIZE) to avoid clobbering the
+ * filemap.c hotpaths.
+ */
+static inline int fault_in_multipages_writeable(char __user *uaddr, int size)
+{
+ int ret;
+ char __user *end = uaddr + size - 1;
+
+ if (unlikely(size == 0))
+ return 0;
+
+ /*
+ * Writing zeroes into userspace here is OK, because we know that if
+ * the zero gets there, we'll be overwriting it.
+ */
+ while (uaddr <= end) {
+ ret = __put_user(0, uaddr);
+ if (ret != 0)
+ return ret;
+ uaddr += PAGE_SIZE;
+ }
+
+ /* Check whether the range spilled into the next page. */
+ if (((unsigned long)uaddr & PAGE_MASK) ==
+ ((unsigned long)end & PAGE_MASK))
+ ret = __put_user(0, end);
+
+ return ret;
+}
+
+static inline int fault_in_multipages_readable(const char __user *uaddr,
+ int size)
+{
+ volatile char c;
+ int ret;
+ const char __user *end = uaddr + size - 1;
+
+ if (unlikely(size == 0))
+ return 0;
+
+ while (uaddr <= end) {
+ ret = __get_user(c, uaddr);
+ if (ret != 0)
+ return ret;
+ uaddr += PAGE_SIZE;
+ }
+
+ /* Check whether the range spilled into the next page. */
+ if (((unsigned long)uaddr & PAGE_MASK) ==
+ ((unsigned long)end & PAGE_MASK)) {
+ ret = __get_user(c, end);
+ (void)c;
+ }
+
+ return ret;
+}
+
int add_to_page_cache_locked(struct page *page, struct address_space *mapping,
pgoff_t index, gfp_t gfp_mask);
int add_to_page_cache_lru(struct page *page, struct address_space *mapping,
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index 21638ae14e07..2b9f82c037c9 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -166,60 +166,6 @@ extern phys_addr_t per_cpu_ptr_to_phys(void *addr);
(typeof(type) __percpu *)__alloc_percpu(sizeof(type), __alignof__(type))
/*
- * Optional methods for optimized non-lvalue per-cpu variable access.
- *
- * @var can be a percpu variable or a field of it and its size should
- * equal char, int or long. percpu_read() evaluates to a lvalue and
- * all others to void.
- *
- * These operations are guaranteed to be atomic.
- * The generic versions disable interrupts. Archs are
- * encouraged to implement single-instruction alternatives which don't
- * require protection.
- */
-#ifndef percpu_read
-# define percpu_read(var) \
- ({ \
- typeof(var) *pr_ptr__ = &(var); \
- typeof(var) pr_ret__; \
- pr_ret__ = get_cpu_var(*pr_ptr__); \
- put_cpu_var(*pr_ptr__); \
- pr_ret__; \
- })
-#endif
-
-#define __percpu_generic_to_op(var, val, op) \
-do { \
- typeof(var) *pgto_ptr__ = &(var); \
- get_cpu_var(*pgto_ptr__) op val; \
- put_cpu_var(*pgto_ptr__); \
-} while (0)
-
-#ifndef percpu_write
-# define percpu_write(var, val) __percpu_generic_to_op(var, (val), =)
-#endif
-
-#ifndef percpu_add
-# define percpu_add(var, val) __percpu_generic_to_op(var, (val), +=)
-#endif
-
-#ifndef percpu_sub
-# define percpu_sub(var, val) __percpu_generic_to_op(var, (val), -=)
-#endif
-
-#ifndef percpu_and
-# define percpu_and(var, val) __percpu_generic_to_op(var, (val), &=)
-#endif
-
-#ifndef percpu_or
-# define percpu_or(var, val) __percpu_generic_to_op(var, (val), |=)
-#endif
-
-#ifndef percpu_xor
-# define percpu_xor(var, val) __percpu_generic_to_op(var, (val), ^=)
-#endif
-
-/*
* Branching function to split up a function into a set of functions that
* are called for different scalar sizes of the objects handled.
*/
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index ddbb6a901f65..f32578634d9d 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -1132,11 +1132,14 @@ struct perf_sample_data {
struct perf_branch_stack *br_stack;
};
-static inline void perf_sample_data_init(struct perf_sample_data *data, u64 addr)
+static inline void perf_sample_data_init(struct perf_sample_data *data,
+ u64 addr, u64 period)
{
+ /* remaining struct members initialized in perf_prepare_sample() */
data->addr = addr;
data->raw = NULL;
data->br_stack = NULL;
+ data->period = period;
}
extern void perf_output_sample(struct perf_output_handle *handle,
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
index b067bd8c49d0..00474b047145 100644
--- a/include/linux/pid_namespace.h
+++ b/include/linux/pid_namespace.h
@@ -31,7 +31,7 @@ struct pid_namespace {
#ifdef CONFIG_BSD_PROCESS_ACCT
struct bsd_acct_struct *bacct;
#endif
- gid_t pid_gid;
+ kgid_t pid_gid;
int hide_pid;
int reboot; /* group exit code if this pidns was rebooted */
};
diff --git a/include/linux/pinctrl/pinctrl-state.h b/include/linux/pinctrl/pinctrl-state.h
index 3920e28b4da7..634608dc6c89 100644
--- a/include/linux/pinctrl/pinctrl-state.h
+++ b/include/linux/pinctrl/pinctrl-state.h
@@ -2,5 +2,18 @@
* Standard pin control state definitions
*/
+/**
+ * @PINCTRL_STATE_DEFAULT: the state the pinctrl handle shall be put
+ * into as default, usually this means the pins are up and ready to
+ * be used by the device driver. This state is commonly used by
+ * hogs to configure muxing and pins at boot.
+ * @PINCTRL_STATE_IDLE: the state the pinctrl handle shall be put into
+ * when the pins are idle. Could typically be set from a
+ * pm_runtime_suspend() operation.
+ * @PINCTRL_STATE_SLEEP: the state the pinctrl handle shall be put into
+ * when the pins are sleeping. Could typically be set from a
+ * common suspend() function.
+ */
#define PINCTRL_STATE_DEFAULT "default"
#define PINCTRL_STATE_IDLE "idle"
+#define PINCTRL_STATE_SLEEP "sleep"
diff --git a/include/linux/platform_data/at91_adc.h b/include/linux/platform_data/at91_adc.h
new file mode 100644
index 000000000000..e15745b4f3a5
--- /dev/null
+++ b/include/linux/platform_data/at91_adc.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011 Free Electrons
+ *
+ * Licensed under the GPLv2 or later.
+ */
+
+#ifndef _AT91_ADC_H_
+#define _AT91_ADC_H_
+
+/**
+ * struct at91_adc_reg_desc - Various informations relative to registers
+ * @channel_base: Base offset for the channel data registers
+ * @drdy_mask: Mask of the DRDY field in the relevant registers
+ (Interruptions registers mostly)
+ * @status_register: Offset of the Interrupt Status Register
+ * @trigger_register: Offset of the Trigger setup register
+ */
+struct at91_adc_reg_desc {
+ u8 channel_base;
+ u32 drdy_mask;
+ u8 status_register;
+ u8 trigger_register;
+};
+
+/**
+ * struct at91_adc_trigger - description of triggers
+ * @name: name of the trigger advertised to the user
+ * @value: value to set in the ADC's trigger setup register
+ to enable the trigger
+ * @is_external: Does the trigger rely on an external pin?
+ */
+struct at91_adc_trigger {
+ const char *name;
+ u8 value;
+ bool is_external;
+};
+
+/**
+ * struct at91_adc_data - platform data for ADC driver
+ * @channels_used: channels in use on the board as a bitmask
+ * @num_channels: global number of channels available on the board
+ * @registers: Registers definition on the board
+ * @startup_time: startup time of the ADC in microseconds
+ * @trigger_list: Triggers available in the ADC
+ * @trigger_number: Number of triggers available in the ADC
+ * @use_external_triggers: does the board has external triggers availables
+ * @vref: Reference voltage for the ADC in millivolts
+ */
+struct at91_adc_data {
+ unsigned long channels_used;
+ u8 num_channels;
+ struct at91_adc_reg_desc *registers;
+ u8 startup_time;
+ struct at91_adc_trigger *trigger_list;
+ u8 trigger_number;
+ bool use_external_triggers;
+ u16 vref;
+};
+
+extern void __init at91_add_device_adc(struct at91_adc_data *data);
+#endif
diff --git a/include/linux/platform_data/ehci-sh.h b/include/linux/platform_data/ehci-sh.h
new file mode 100644
index 000000000000..5c15a738e116
--- /dev/null
+++ b/include/linux/platform_data/ehci-sh.h
@@ -0,0 +1,28 @@
+/*
+ * EHCI SuperH driver platform data
+ *
+ * Copyright (C) 2012 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __USB_EHCI_SH_H
+#define __USB_EHCI_SH_H
+
+struct ehci_sh_platdata {
+ void (*phy_init)(void); /* Phy init function */
+};
+
+#endif /* __USB_EHCI_SH_H */
diff --git a/include/linux/platform_data/emif_plat.h b/include/linux/platform_data/emif_plat.h
new file mode 100644
index 000000000000..03378ca84061
--- /dev/null
+++ b/include/linux/platform_data/emif_plat.h
@@ -0,0 +1,128 @@
+/*
+ * Definitions for TI EMIF device platform data
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Aneesh V <aneesh@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.
+ */
+#ifndef __EMIF_PLAT_H
+#define __EMIF_PLAT_H
+
+/* Low power modes - EMIF_PWR_MGMT_CTRL */
+#define EMIF_LP_MODE_DISABLE 0
+#define EMIF_LP_MODE_CLOCK_STOP 1
+#define EMIF_LP_MODE_SELF_REFRESH 2
+#define EMIF_LP_MODE_PWR_DN 4
+
+/* Hardware capabilities */
+#define EMIF_HW_CAPS_LL_INTERFACE 0x00000001
+
+/*
+ * EMIF IP Revisions
+ * EMIF4D - Used in OMAP4
+ * EMIF4D5 - Used in OMAP5
+ */
+#define EMIF_4D 1
+#define EMIF_4D5 2
+
+/*
+ * PHY types
+ * ATTILAPHY - Used in OMAP4
+ * INTELLIPHY - Used in OMAP5
+ */
+#define EMIF_PHY_TYPE_ATTILAPHY 1
+#define EMIF_PHY_TYPE_INTELLIPHY 2
+
+/* Custom config requests */
+#define EMIF_CUSTOM_CONFIG_LPMODE 0x00000001
+#define EMIF_CUSTOM_CONFIG_TEMP_ALERT_POLL_INTERVAL 0x00000002
+
+#ifndef __ASSEMBLY__
+/**
+ * struct ddr_device_info - All information about the DDR device except AC
+ * timing parameters
+ * @type: Device type (LPDDR2-S4, LPDDR2-S2 etc)
+ * @density: Device density
+ * @io_width: Bus width
+ * @cs1_used: Whether there is a DDR device attached to the second
+ * chip-select(CS1) of this EMIF instance
+ * @cal_resistors_per_cs: Whether there is one calibration resistor per
+ * chip-select or whether it's a single one for both
+ * @manufacturer: Manufacturer name string
+ */
+struct ddr_device_info {
+ u32 type;
+ u32 density;
+ u32 io_width;
+ u32 cs1_used;
+ u32 cal_resistors_per_cs;
+ char manufacturer[10];
+};
+
+/**
+ * struct emif_custom_configs - Custom configuration parameters/policies
+ * passed from the platform layer
+ * @mask: Mask to indicate which configs are requested
+ * @lpmode: LPMODE to be used in PWR_MGMT_CTRL register
+ * @lpmode_timeout_performance: Timeout before LPMODE entry when higher
+ * performance is desired at the cost of power (typically
+ * at higher OPPs)
+ * @lpmode_timeout_power: Timeout before LPMODE entry when better power
+ * savings is desired and performance is not important
+ * (typically at lower loads indicated by lower OPPs)
+ * @lpmode_freq_threshold: The DDR frequency threshold to identify between
+ * the above two cases:
+ * timeout = (freq >= lpmode_freq_threshold) ?
+ * lpmode_timeout_performance :
+ * lpmode_timeout_power;
+ * @temp_alert_poll_interval_ms: LPDDR2 MR4 polling interval at nominal
+ * temperature(in milliseconds). When temperature is high
+ * polling is done 4 times as frequently.
+ */
+struct emif_custom_configs {
+ u32 mask;
+ u32 lpmode;
+ u32 lpmode_timeout_performance;
+ u32 lpmode_timeout_power;
+ u32 lpmode_freq_threshold;
+ u32 temp_alert_poll_interval_ms;
+};
+
+/**
+ * struct emif_platform_data - Platform data passed on EMIF platform
+ * device creation. Used by the driver.
+ * @hw_caps: Hw capabilities of the EMIF IP in the respective SoC
+ * @device_info: Device info structure containing information such
+ * as type, bus width, density etc
+ * @timings: Timings information from device datasheet passed
+ * as an array of 'struct lpddr2_timings'. Can be NULL
+ * if if default timings are ok
+ * @timings_arr_size: Size of the timings array. Depends on the number
+ * of different frequencies for which timings data
+ * is provided
+ * @min_tck: Minimum value of some timing parameters in terms
+ * of number of cycles. Can be NULL if default values
+ * are ok
+ * @custom_configs: Custom configurations requested by SoC or board
+ * code and the data for them. Can be NULL if default
+ * configurations done by the driver are ok. See
+ * documentation for 'struct emif_custom_configs' for
+ * more details
+ */
+struct emif_platform_data {
+ u32 hw_caps;
+ struct ddr_device_info *device_info;
+ const struct lpddr2_timings *timings;
+ u32 timings_arr_size;
+ const struct lpddr2_min_tck *min_tck;
+ struct emif_custom_configs *custom_configs;
+ u32 ip_rev;
+ u32 phy_type;
+};
+#endif /* __ASSEMBLY__ */
+
+#endif /* __LINUX_EMIF_H */
diff --git a/include/linux/platform_data/gpio-em.h b/include/linux/platform_data/gpio-em.h
new file mode 100644
index 000000000000..573edfb046c4
--- /dev/null
+++ b/include/linux/platform_data/gpio-em.h
@@ -0,0 +1,10 @@
+#ifndef __GPIO_EM_H__
+#define __GPIO_EM_H__
+
+struct gpio_em_config {
+ unsigned int gpio_base;
+ unsigned int irq_base;
+ unsigned int number_of_pins;
+};
+
+#endif /* __GPIO_EM_H__ */
diff --git a/include/linux/platform_data/ina2xx.h b/include/linux/platform_data/ina2xx.h
new file mode 100644
index 000000000000..9abc0ca7259b
--- /dev/null
+++ b/include/linux/platform_data/ina2xx.h
@@ -0,0 +1,19 @@
+/*
+ * Driver for Texas Instruments INA219, INA226 power monitor chips
+ *
+ * Copyright (C) 2012 Lothar Felten <l-felten@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.
+ *
+ * For further information, see the Documentation/hwmon/ina2xx file.
+ */
+
+/**
+ * struct ina2xx_platform_data - ina2xx info
+ * @shunt_uohms shunt resistance in microohms
+ */
+struct ina2xx_platform_data {
+ long shunt_uohms;
+};
diff --git a/arch/arm/plat-samsung/include/plat/udc-hs.h b/include/linux/platform_data/s3c-hsotg.h
index c9e3667cb2b1..97ec12c2ded4 100644
--- a/arch/arm/plat-samsung/include/plat/udc-hs.h
+++ b/include/linux/platform_data/s3c-hsotg.h
@@ -1,4 +1,4 @@
-/* arch/arm/plat-s3c/include/plat/udc-hs.h
+/* include/linux/platform_data/s3c-hsotg.h
*
* Copyright 2008 Openmoko, Inc.
* Copyright 2008 Simtec Electronics
@@ -25,7 +25,8 @@ enum s3c_hsotg_dmamode {
*/
struct s3c_hsotg_plat {
enum s3c_hsotg_dmamode dma;
- unsigned int is_osc : 1;
+ unsigned int is_osc:1;
+ int phy_type;
int (*phy_init)(struct platform_device *pdev, int type);
int (*phy_exit)(struct platform_device *pdev, int type);
diff --git a/include/linux/platform_data/tegra_usb.h b/include/linux/platform_data/tegra_usb.h
index 6bca5b569acb..66c673fef408 100644
--- a/include/linux/platform_data/tegra_usb.h
+++ b/include/linux/platform_data/tegra_usb.h
@@ -26,6 +26,7 @@ struct tegra_ehci_platform_data {
/* power down the phy on bus suspend */
int power_down_on_bus_suspend;
void *phy_config;
+ int vbus_gpio;
};
#endif /* _TEGRA_USB_H_ */
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 715305e05123..f067e60a3832 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -544,8 +544,6 @@ struct dev_pm_info {
unsigned long active_jiffies;
unsigned long suspended_jiffies;
unsigned long accounting_timestamp;
- ktime_t suspend_time;
- s64 max_time_suspended_ns;
struct dev_pm_qos_request *pq_req;
#endif
struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 91f8286106ea..30f794eb3826 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -14,6 +14,7 @@
#include <linux/pm.h>
#include <linux/err.h>
#include <linux/of.h>
+#include <linux/notifier.h>
enum gpd_status {
GPD_STATE_ACTIVE = 0, /* PM domain is active */
@@ -70,9 +71,9 @@ struct generic_pm_domain {
int (*power_on)(struct generic_pm_domain *domain);
s64 power_on_latency_ns;
struct gpd_dev_ops dev_ops;
- s64 break_even_ns; /* Power break even for the entire domain. */
s64 max_off_time_ns; /* Maximum allowed "suspended" time. */
- ktime_t power_off_time;
+ bool max_off_time_changed;
+ bool cached_power_down_ok;
struct device_node *of_node; /* Node in device tree */
};
@@ -93,13 +94,17 @@ struct gpd_timing_data {
s64 start_latency_ns;
s64 save_state_latency_ns;
s64 restore_state_latency_ns;
- s64 break_even_ns;
+ s64 effective_constraint_ns;
+ bool constraint_changed;
+ bool cached_stop_ok;
};
struct generic_pm_domain_data {
struct pm_domain_data base;
struct gpd_dev_ops ops;
struct gpd_timing_data td;
+ struct notifier_block nb;
+ struct mutex lock;
bool need_restore;
bool always_on;
};
@@ -141,6 +146,7 @@ static inline int pm_genpd_of_add_device(struct device_node *genpd_node,
extern int pm_genpd_remove_device(struct generic_pm_domain *genpd,
struct device *dev);
extern void pm_genpd_dev_always_on(struct device *dev, bool val);
+extern void pm_genpd_dev_need_restore(struct device *dev, bool val);
extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
struct generic_pm_domain *new_subdomain);
extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
@@ -184,6 +190,7 @@ static inline int pm_genpd_remove_device(struct generic_pm_domain *genpd,
return -ENOSYS;
}
static inline void pm_genpd_dev_always_on(struct device *dev, bool val) {}
+static inline void pm_genpd_dev_need_restore(struct device *dev, bool val) {}
static inline int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
struct generic_pm_domain *new_sd)
{
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index 609daae7a014..f271860c78d5 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -150,9 +150,6 @@ static inline void pm_runtime_set_autosuspend_delay(struct device *dev,
static inline unsigned long pm_runtime_autosuspend_expiration(
struct device *dev) { return 0; }
-static inline void pm_runtime_update_max_time_suspended(struct device *dev,
- s64 delta_ns) {}
-
#endif /* !CONFIG_PM_RUNTIME */
static inline int pm_runtime_idle(struct device *dev)
diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h
index d9f05113e5fb..569781faa504 100644
--- a/include/linux/pm_wakeup.h
+++ b/include/linux/pm_wakeup.h
@@ -33,12 +33,15 @@
*
* @total_time: Total time this wakeup source has been active.
* @max_time: Maximum time this wakeup source has been continuously active.
- * @last_time: Monotonic clock when the wakeup source's was activated last time.
+ * @last_time: Monotonic clock when the wakeup source's was touched last time.
+ * @prevent_sleep_time: Total time this source has been preventing autosleep.
* @event_count: Number of signaled wakeup events.
* @active_count: Number of times the wakeup sorce was activated.
* @relax_count: Number of times the wakeup sorce was deactivated.
- * @hit_count: Number of times the wakeup sorce might abort system suspend.
+ * @expire_count: Number of times the wakeup source's timeout has expired.
+ * @wakeup_count: Number of times the wakeup source might abort suspend.
* @active: Status of the wakeup source.
+ * @has_timeout: The wakeup source has been activated with a timeout.
*/
struct wakeup_source {
const char *name;
@@ -49,11 +52,15 @@ struct wakeup_source {
ktime_t total_time;
ktime_t max_time;
ktime_t last_time;
+ ktime_t start_prevent_time;
+ ktime_t prevent_sleep_time;
unsigned long event_count;
unsigned long active_count;
unsigned long relax_count;
- unsigned long hit_count;
- unsigned int active:1;
+ unsigned long expire_count;
+ unsigned long wakeup_count;
+ bool active:1;
+ bool autosleep_enabled:1;
};
#ifdef CONFIG_PM_SLEEP
diff --git a/include/linux/printk.h b/include/linux/printk.h
index 0525927f203f..1bec2f7a2d42 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -95,8 +95,19 @@ extern int printk_needs_cpu(int cpu);
extern void printk_tick(void);
#ifdef CONFIG_PRINTK
+asmlinkage __printf(5, 0)
+int vprintk_emit(int facility, int level,
+ const char *dict, size_t dictlen,
+ const char *fmt, va_list args);
+
asmlinkage __printf(1, 0)
int vprintk(const char *fmt, va_list args);
+
+asmlinkage __printf(5, 6) __cold
+asmlinkage int printk_emit(int facility, int level,
+ const char *dict, size_t dictlen,
+ const char *fmt, ...);
+
asmlinkage __printf(1, 2) __cold
int printk(const char *fmt, ...);
@@ -289,6 +300,8 @@ extern void dump_stack(void) __cold;
no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
#endif
+extern const struct file_operations kmsg_fops;
+
enum {
DUMP_PREFIX_NONE,
DUMP_PREFIX_ADDRESS,
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 85c507306239..3fd2e871ff1b 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -52,8 +52,8 @@ struct proc_dir_entry {
unsigned int low_ino;
umode_t mode;
nlink_t nlink;
- uid_t uid;
- gid_t gid;
+ kuid_t uid;
+ kgid_t gid;
loff_t size;
const struct inode_operations *proc_iops;
/*
diff --git a/drivers/staging/android/persistent_ram.h b/include/linux/pstore_ram.h
index f41e2086c645..7ed7fd4dba49 100644
--- a/drivers/staging/android/persistent_ram.h
+++ b/include/linux/pstore_ram.h
@@ -1,4 +1,6 @@
/*
+ * Copyright (C) 2010 Marco Stornelli <marco.stornelli@gmail.com>
+ * Copyright (C) 2011 Kees Cook <keescook@chromium.org>
* Copyright (C) 2011 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
@@ -12,13 +14,14 @@
*
*/
-#ifndef __LINUX_PERSISTENT_RAM_H__
-#define __LINUX_PERSISTENT_RAM_H__
+#ifndef __LINUX_PSTORE_RAM_H__
+#define __LINUX_PSTORE_RAM_H__
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/types.h>
+#include <linux/init.h>
struct persistent_ram_buffer;
@@ -38,7 +41,8 @@ struct persistent_ram {
};
struct persistent_ram_zone {
- struct list_head node;
+ phys_addr_t paddr;
+ size_t size;
void *vaddr;
struct persistent_ram_buffer *buffer;
size_t buffer_size;
@@ -57,12 +61,14 @@ struct persistent_ram_zone {
char *old_log;
size_t old_log_size;
- size_t old_log_footer_size;
- bool early;
};
int persistent_ram_early_init(struct persistent_ram *ram);
+struct persistent_ram_zone * __init persistent_ram_new(phys_addr_t start,
+ size_t size,
+ bool ecc);
+void persistent_ram_free(struct persistent_ram_zone *prz);
struct persistent_ram_zone *persistent_ram_init_ringbuffer(struct device *dev,
bool ecc);
@@ -75,4 +81,18 @@ void persistent_ram_free_old(struct persistent_ram_zone *prz);
ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
char *str, size_t len);
+/*
+ * Ramoops platform data
+ * @mem_size memory size for ramoops
+ * @mem_address physical memory address to contain ramoops
+ */
+
+struct ramoops_platform_data {
+ unsigned long mem_size;
+ unsigned long mem_address;
+ unsigned long record_size;
+ int dump_oops;
+ bool ecc;
+};
+
#endif
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index d93f95e6177c..17b977304a09 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -22,8 +22,8 @@ static inline struct quota_info *sb_dqopt(struct super_block *sb)
static inline bool is_quota_modification(struct inode *inode, struct iattr *ia)
{
return (ia->ia_valid & ATTR_SIZE && ia->ia_size != inode->i_size) ||
- (ia->ia_valid & ATTR_UID && ia->ia_uid != inode->i_uid) ||
- (ia->ia_valid & ATTR_GID && ia->ia_gid != inode->i_gid);
+ (ia->ia_valid & ATTR_UID && !uid_eq(ia->ia_uid, inode->i_uid)) ||
+ (ia->ia_valid & ATTR_GID && !gid_eq(ia->ia_gid, inode->i_gid));
}
#if defined(CONFIG_QUOTA)
diff --git a/include/linux/raid/md_p.h b/include/linux/raid/md_p.h
index 8c0a3adc5df5..ee753536ab70 100644
--- a/include/linux/raid/md_p.h
+++ b/include/linux/raid/md_p.h
@@ -233,7 +233,10 @@ struct mdp_superblock_1 {
__le32 delta_disks; /* change in number of raid_disks */
__le32 new_layout; /* new layout */
__le32 new_chunk; /* new chunk size (512byte sectors) */
- __u8 pad1[128-124]; /* set to 0 when written */
+ __le32 new_offset; /* signed number to add to data_offset in new
+ * layout. 0 == no-change. This can be
+ * different on each device in the array.
+ */
/* constant this-device information - 64 bytes */
__le64 data_offset; /* sector start of data, often 0 */
@@ -281,10 +284,18 @@ struct mdp_superblock_1 {
* active device with same 'role'.
* 'recovery_offset' is also set.
*/
+#define MD_FEATURE_RESHAPE_BACKWARDS 32 /* Reshape doesn't change number
+ * of devices, but is going
+ * backwards anyway.
+ */
+#define MD_FEATURE_NEW_OFFSET 64 /* new_offset must be honoured */
#define MD_FEATURE_ALL (MD_FEATURE_BITMAP_OFFSET \
|MD_FEATURE_RECOVERY_OFFSET \
|MD_FEATURE_RESHAPE_ACTIVE \
|MD_FEATURE_BAD_BLOCKS \
- |MD_FEATURE_REPLACEMENT)
+ |MD_FEATURE_REPLACEMENT \
+ |MD_FEATURE_RESHAPE_BACKWARDS \
+ |MD_FEATURE_NEW_OFFSET \
+ )
#endif
diff --git a/include/linux/raid/pq.h b/include/linux/raid/pq.h
index 53272e9860a7..640c69ceec96 100644
--- a/include/linux/raid/pq.h
+++ b/include/linux/raid/pq.h
@@ -99,8 +99,20 @@ extern const struct raid6_calls raid6_altivec2;
extern const struct raid6_calls raid6_altivec4;
extern const struct raid6_calls raid6_altivec8;
+struct raid6_recov_calls {
+ void (*data2)(int, size_t, int, int, void **);
+ void (*datap)(int, size_t, int, void **);
+ int (*valid)(void);
+ const char *name;
+ int priority;
+};
+
+extern const struct raid6_recov_calls raid6_recov_intx1;
+extern const struct raid6_recov_calls raid6_recov_ssse3;
+
/* Algorithm list */
extern const struct raid6_calls * const raid6_algos[];
+extern const struct raid6_recov_calls *const raid6_recov_algos[];
int raid6_select_algo(void);
/* Return values from chk_syndrome */
@@ -111,14 +123,16 @@ int raid6_select_algo(void);
/* Galois field tables */
extern const u8 raid6_gfmul[256][256] __attribute__((aligned(256)));
+extern const u8 raid6_vgfmul[256][32] __attribute__((aligned(256)));
extern const u8 raid6_gfexp[256] __attribute__((aligned(256)));
extern const u8 raid6_gfinv[256] __attribute__((aligned(256)));
extern const u8 raid6_gfexi[256] __attribute__((aligned(256)));
/* Recovery routines */
-void raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
+extern void (*raid6_2data_recov)(int disks, size_t bytes, int faila, int failb,
void **ptrs);
-void raid6_datap_recov(int disks, size_t bytes, int faila, void **ptrs);
+extern void (*raid6_datap_recov)(int disks, size_t bytes, int faila,
+ void **ptrs);
void raid6_dual_recov(int disks, size_t bytes, int faila, int failb,
void **ptrs);
diff --git a/include/linux/ramoops.h b/include/linux/ramoops.h
deleted file mode 100644
index 484fef81cd3a..000000000000
--- a/include/linux/ramoops.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef __RAMOOPS_H
-#define __RAMOOPS_H
-
-/*
- * Ramoops platform data
- * @mem_size memory size for ramoops
- * @mem_address physical memory address to contain ramoops
- */
-
-struct ramoops_platform_data {
- unsigned long mem_size;
- unsigned long mem_address;
- unsigned long record_size;
- int dump_oops;
-};
-
-#endif
diff --git a/include/linux/rational.h b/include/linux/rational.h
index 4f532fcd9eea..bfa6a2bcfb32 100644
--- a/include/linux/rational.h
+++ b/include/linux/rational.h
@@ -1,7 +1,7 @@
/*
* rational fractions
*
- * Copyright (C) 2009 emlix GmbH, Oskar Schirmer <os@emlix.com>
+ * Copyright (C) 2009 emlix GmbH, Oskar Schirmer <oskar@scara.com>
*
* helper functions when coping with rational numbers,
* e.g. when calculating optimum numerator/denominator pairs for
diff --git a/include/linux/res_counter.h b/include/linux/res_counter.h
index da81af086eaf..fb201896a8b0 100644
--- a/include/linux/res_counter.h
+++ b/include/linux/res_counter.h
@@ -116,7 +116,7 @@ void res_counter_init(struct res_counter *counter, struct res_counter *parent);
*/
int __must_check res_counter_charge_locked(struct res_counter *counter,
- unsigned long val);
+ unsigned long val, bool force);
int __must_check res_counter_charge(struct res_counter *counter,
unsigned long val, struct res_counter **limit_fail_at);
int __must_check res_counter_charge_nofail(struct res_counter *counter,
diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
index 7be2e88f23fd..6c8835f74f79 100644
--- a/include/linux/ring_buffer.h
+++ b/include/linux/ring_buffer.h
@@ -96,9 +96,11 @@ __ring_buffer_alloc(unsigned long size, unsigned flags, struct lock_class_key *k
__ring_buffer_alloc((size), (flags), &__key); \
})
+#define RING_BUFFER_ALL_CPUS -1
+
void ring_buffer_free(struct ring_buffer *buffer);
-int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size);
+int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size, int cpu);
void ring_buffer_change_overwrite(struct ring_buffer *buffer, int val);
@@ -129,7 +131,7 @@ ring_buffer_read(struct ring_buffer_iter *iter, u64 *ts);
void ring_buffer_iter_reset(struct ring_buffer_iter *iter);
int ring_buffer_iter_empty(struct ring_buffer_iter *iter);
-unsigned long ring_buffer_size(struct ring_buffer *buffer);
+unsigned long ring_buffer_size(struct ring_buffer *buffer, int cpu);
void ring_buffer_reset_cpu(struct ring_buffer *buffer, int cpu);
void ring_buffer_reset(struct ring_buffer *buffer);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index f774d88cd0aa..f45c0b280b5d 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -90,6 +90,7 @@ struct sched_param {
#include <linux/latencytop.h>
#include <linux/cred.h>
#include <linux/llist.h>
+#include <linux/uidgid.h>
#include <asm/processor.h>
@@ -728,8 +729,7 @@ struct user_struct {
/* Hash table maintenance information */
struct hlist_node uidhash_node;
- uid_t uid;
- struct user_namespace *user_ns;
+ kuid_t uid;
#ifdef CONFIG_PERF_EVENTS
atomic_long_t locked_vm;
@@ -738,7 +738,7 @@ struct user_struct {
extern int uids_sysfs_init(void);
-extern struct user_struct *find_user(uid_t);
+extern struct user_struct *find_user(kuid_t);
extern struct user_struct root_user;
#define INIT_USER (&root_user)
@@ -855,61 +855,14 @@ enum cpu_idle_type {
#define SD_WAKE_AFFINE 0x0020 /* Wake task to waking CPU */
#define SD_PREFER_LOCAL 0x0040 /* Prefer to keep tasks local to this domain */
#define SD_SHARE_CPUPOWER 0x0080 /* Domain members share cpu power */
-#define SD_POWERSAVINGS_BALANCE 0x0100 /* Balance for power savings */
#define SD_SHARE_PKG_RESOURCES 0x0200 /* Domain members share cpu pkg resources */
#define SD_SERIALIZE 0x0400 /* Only a single load balancing instance */
#define SD_ASYM_PACKING 0x0800 /* Place busy groups earlier in the domain */
#define SD_PREFER_SIBLING 0x1000 /* Prefer to place tasks in a sibling domain */
#define SD_OVERLAP 0x2000 /* sched_domains of this level overlap */
-enum powersavings_balance_level {
- POWERSAVINGS_BALANCE_NONE = 0, /* No power saving load balance */
- POWERSAVINGS_BALANCE_BASIC, /* Fill one thread/core/package
- * first for long running threads
- */
- POWERSAVINGS_BALANCE_WAKEUP, /* Also bias task wakeups to semi-idle
- * cpu package for power savings
- */
- MAX_POWERSAVINGS_BALANCE_LEVELS
-};
-
-extern int sched_mc_power_savings, sched_smt_power_savings;
-
-static inline int sd_balance_for_mc_power(void)
-{
- if (sched_smt_power_savings)
- return SD_POWERSAVINGS_BALANCE;
-
- if (!sched_mc_power_savings)
- return SD_PREFER_SIBLING;
-
- return 0;
-}
-
-static inline int sd_balance_for_package_power(void)
-{
- if (sched_mc_power_savings | sched_smt_power_savings)
- return SD_POWERSAVINGS_BALANCE;
-
- return SD_PREFER_SIBLING;
-}
-
extern int __weak arch_sd_sibiling_asym_packing(void);
-/*
- * Optimise SD flags for power savings:
- * SD_BALANCE_NEWIDLE helps aggressive task consolidation and power savings.
- * Keep default SD flags if sched_{smt,mc}_power_saving=0
- */
-
-static inline int sd_power_saving_flags(void)
-{
- if (sched_mc_power_savings | sched_smt_power_savings)
- return SD_BALANCE_NEWIDLE;
-
- return 0;
-}
-
struct sched_group_power {
atomic_t ref;
/*
@@ -1619,6 +1572,10 @@ struct task_struct {
#ifdef CONFIG_HAVE_HW_BREAKPOINT
atomic_t ptrace_bp_refcnt;
#endif
+#ifdef CONFIG_UPROBES
+ struct uprobe_task *utask;
+ int uprobe_srcu_id;
+#endif
};
/* Future-safe accessor for struct task_struct's cpus_allowed. */
@@ -1962,7 +1919,7 @@ static inline int set_cpus_allowed(struct task_struct *p, cpumask_t new_mask)
*/
extern unsigned long long notrace sched_clock(void);
/*
- * See the comment in kernel/sched_clock.c
+ * See the comment in kernel/sched/clock.c
*/
extern u64 cpu_clock(int cpu);
extern u64 local_clock(void);
@@ -2189,14 +2146,13 @@ extern struct task_struct *find_task_by_pid_ns(pid_t nr,
extern void __set_special_pids(struct pid *pid);
/* per-UID process charging. */
-extern struct user_struct * alloc_uid(struct user_namespace *, uid_t);
+extern struct user_struct * alloc_uid(kuid_t);
static inline struct user_struct *get_uid(struct user_struct *u)
{
atomic_inc(&u->__count);
return u;
}
extern void free_uid(struct user_struct *);
-extern void release_uids(struct user_namespace *ns);
#include <asm/current.h>
diff --git a/include/linux/serial.h b/include/linux/serial.h
index 441980ecc4e5..90e9f981358a 100644
--- a/include/linux/serial.h
+++ b/include/linux/serial.h
@@ -130,7 +130,6 @@ struct serial_uart_config {
#define ASYNCB_CHECK_CD 25 /* i.e., CLOCAL */
#define ASYNCB_SHARE_IRQ 24 /* for multifunction cards, no longer used */
#define ASYNCB_CONS_FLOW 23 /* flow control for console */
-#define ASYNCB_BOOT_ONLYMCA 22 /* Probe only if MCA bus */
#define ASYNCB_FIRST_KERNEL 22
#define ASYNC_HUP_NOTIFY (1U << ASYNCB_HUP_NOTIFY)
@@ -166,7 +165,6 @@ struct serial_uart_config {
#define ASYNC_CHECK_CD (1U << ASYNCB_CHECK_CD)
#define ASYNC_SHARE_IRQ (1U << ASYNCB_SHARE_IRQ)
#define ASYNC_CONS_FLOW (1U << ASYNCB_CONS_FLOW)
-#define ASYNC_BOOT_ONLYMCA (1U << ASYNCB_BOOT_ONLYMCA)
#define ASYNC_INTERNAL_FLAGS (~((1U << ASYNCB_FIRST_KERNEL) - 1))
/*
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index 8f012f8ac8e9..a416e92012ef 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -38,6 +38,7 @@ struct plat_serial8250_port {
int (*handle_irq)(struct uart_port *);
void (*pm)(struct uart_port *, unsigned int state,
unsigned old);
+ void (*handle_break)(struct uart_port *);
};
/*
@@ -54,7 +55,6 @@ enum {
PLAT8250_DEV_BOCA,
PLAT8250_DEV_EXAR_ST16C554,
PLAT8250_DEV_HUB6,
- PLAT8250_DEV_MCA,
PLAT8250_DEV_AU1X00,
PLAT8250_DEV_SM501,
};
@@ -68,6 +68,7 @@ enum {
struct uart_port;
struct uart_8250_port;
+int serial8250_register_8250_port(struct uart_8250_port *);
int serial8250_register_port(struct uart_port *);
void serial8250_unregister_port(int line);
void serial8250_suspend_port(int line);
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 2db407a40051..65db9928e15f 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -310,6 +310,7 @@ struct uart_port {
int (*handle_irq)(struct uart_port *);
void (*pm)(struct uart_port *, unsigned int state,
unsigned int old);
+ void (*handle_break)(struct uart_port *);
unsigned int irq; /* irq number */
unsigned long irqflags; /* irq flags */
unsigned int uartclk; /* base uart clock */
@@ -533,6 +534,10 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
static inline int uart_handle_break(struct uart_port *port)
{
struct uart_state *state = port->state;
+
+ if (port->handle_break)
+ port->handle_break(port);
+
#ifdef SUPPORT_SYSRQ
if (port->cons && port->cons->index == port->line) {
if (!port->sysrq) {
diff --git a/include/linux/serial_sci.h b/include/linux/serial_sci.h
index 78779074f6e8..eb763adf9815 100644
--- a/include/linux/serial_sci.h
+++ b/include/linux/serial_sci.h
@@ -52,6 +52,8 @@ enum {
/* SCSPTR, optional */
#define SCSPTR_RTSIO (1 << 7)
#define SCSPTR_CTSIO (1 << 5)
+#define SCSPTR_SPB2IO (1 << 1)
+#define SCSPTR_SPB2DT (1 << 0)
/* Offsets into the sci_port->irqs array */
enum {
diff --git a/include/linux/serio.h b/include/linux/serio.h
index ca82861b0e46..6d6cfd3e94a3 100644
--- a/include/linux/serio.h
+++ b/include/linux/serio.h
@@ -96,6 +96,19 @@ int __must_check __serio_register_driver(struct serio_driver *drv,
void serio_unregister_driver(struct serio_driver *drv);
+/**
+ * module_serio_driver() - Helper macro for registering a serio driver
+ * @__serio_driver: serio_driver struct
+ *
+ * Helper macro for serio drivers which do not do anything special in
+ * module init/exit. This eliminates a lot of boilerplate. Each module
+ * may only use this macro once, and calling it replaces module_init()
+ * and module_exit().
+ */
+#define module_serio_driver(__serio_driver) \
+ module_driver(__serio_driver, serio_register_driver, \
+ serio_unregister_driver)
+
static inline int serio_write(struct serio *serio, unsigned char data)
{
if (serio->write)
diff --git a/include/linux/sh_clk.h b/include/linux/sh_clk.h
index 0a9d8f2ac519..c513b73cd7cb 100644
--- a/include/linux/sh_clk.h
+++ b/include/linux/sh_clk.h
@@ -59,7 +59,15 @@ struct clk {
unsigned int nr_freqs;
};
-#define CLK_ENABLE_ON_INIT (1 << 0)
+#define CLK_ENABLE_ON_INIT BIT(0)
+
+#define CLK_ENABLE_REG_32BIT BIT(1) /* default access size */
+#define CLK_ENABLE_REG_16BIT BIT(2)
+#define CLK_ENABLE_REG_8BIT BIT(3)
+
+#define CLK_ENABLE_REG_MASK (CLK_ENABLE_REG_32BIT | \
+ CLK_ENABLE_REG_16BIT | \
+ CLK_ENABLE_REG_8BIT)
/* drivers/sh/clk.c */
unsigned long followparent_recalc(struct clk *);
@@ -102,7 +110,7 @@ long clk_round_parent(struct clk *clk, unsigned long target,
unsigned long *best_freq, unsigned long *parent_freq,
unsigned int div_min, unsigned int div_max);
-#define SH_CLK_MSTP32(_parent, _enable_reg, _enable_bit, _flags) \
+#define SH_CLK_MSTP(_parent, _enable_reg, _enable_bit, _flags) \
{ \
.parent = _parent, \
.enable_reg = (void __iomem *)_enable_reg, \
@@ -110,7 +118,27 @@ long clk_round_parent(struct clk *clk, unsigned long target,
.flags = _flags, \
}
-int sh_clk_mstp32_register(struct clk *clks, int nr);
+#define SH_CLK_MSTP32(_p, _r, _b, _f) \
+ SH_CLK_MSTP(_p, _r, _b, _f | CLK_ENABLE_REG_32BIT)
+
+#define SH_CLK_MSTP16(_p, _r, _b, _f) \
+ SH_CLK_MSTP(_p, _r, _b, _f | CLK_ENABLE_REG_16BIT)
+
+#define SH_CLK_MSTP8(_p, _r, _b, _f) \
+ SH_CLK_MSTP(_p, _r, _b, _f | CLK_ENABLE_REG_8BIT)
+
+int sh_clk_mstp_register(struct clk *clks, int nr);
+
+/*
+ * MSTP registration never really cared about access size, despite the
+ * original enable/disable pairs assuming a 32-bit access. Clocks are
+ * responsible for defining their access sizes either directly or via the
+ * clock definition wrappers.
+ */
+static inline int __deprecated sh_clk_mstp32_register(struct clk *clks, int nr)
+{
+ return sh_clk_mstp_register(clks, nr);
+}
#define SH_CLK_DIV4(_parent, _reg, _shift, _div_bitmap, _flags) \
{ \
diff --git a/include/linux/sh_intc.h b/include/linux/sh_intc.h
index 6aed0805927f..32383285da68 100644
--- a/include/linux/sh_intc.h
+++ b/include/linux/sh_intc.h
@@ -133,7 +133,6 @@ struct intc_desc symbol __initdata = { \
}
int register_intc_controller(struct intc_desc *desc);
-void reserve_intc_vectors(struct intc_vect *vectors, unsigned int nr_vecs);
int intc_set_priority(unsigned int irq, unsigned int prio);
int intc_irq_lookup(const char *chipname, intc_enum enum_id);
void intc_finalize(void);
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index 79ab2555b3b0..bef2cf00b3be 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -28,8 +28,8 @@ struct shmem_sb_info {
unsigned long max_inodes; /* How many inodes are allowed */
unsigned long free_inodes; /* How many are left for allocation */
spinlock_t stat_lock; /* Serialize shmem_sb_info changes */
- uid_t uid; /* Mount uid for root directory */
- gid_t gid; /* Mount gid for root directory */
+ kuid_t uid; /* Mount uid for root directory */
+ kgid_t gid; /* Mount gid for root directory */
umode_t mode; /* Mount mode for root directory */
struct mempolicy *mpol; /* default memory policy for mappings */
};
diff --git a/include/linux/signal.h b/include/linux/signal.h
index 7987ce74874b..17046cc484bc 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -252,6 +252,7 @@ extern int do_sigtimedwait(const sigset_t *, siginfo_t *,
extern int sigprocmask(int, sigset_t *, sigset_t *);
extern void set_current_blocked(const sigset_t *);
extern int show_unhandled_signals;
+extern int sigsuspend(sigset_t *);
extern int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, struct pt_regs *regs, void *cookie);
extern void block_sigmask(struct k_sigaction *ka, int signr);
diff --git a/include/linux/spi/eeprom.h b/include/linux/spi/eeprom.h
index 306e7b1c69ed..403e007aef68 100644
--- a/include/linux/spi/eeprom.h
+++ b/include/linux/spi/eeprom.h
@@ -20,6 +20,16 @@ struct spi_eeprom {
#define EE_ADDR3 0x0004 /* 24 bit addrs */
#define EE_READONLY 0x0008 /* disallow writes */
+ /*
+ * Certain EEPROMS have a size that is larger than the number of address
+ * bytes would allow (e.g. like M95040 from ST that has 512 Byte size
+ * but uses only one address byte (A0 to A7) for addressing.) For
+ * the extra address bit (A8, A16 or A24) bit 3 of the instruction byte
+ * is used. This instruction bit is normally defined as don't care for
+ * other AT25 like chips.
+ */
+#define EE_INSTR_BIT3_IS_ADDR 0x0010
+
/* for exporting this chip's data to other kernel code */
void (*setup)(struct memory_accessor *mem, void *context);
void *context;
diff --git a/include/linux/spi/rspi.h b/include/linux/spi/rspi.h
new file mode 100644
index 000000000000..900f0e328235
--- /dev/null
+++ b/include/linux/spi/rspi.h
@@ -0,0 +1,31 @@
+/*
+ * Renesas SPI driver
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __LINUX_SPI_RENESAS_SPI_H__
+#define __LINUX_SPI_RENESAS_SPI_H__
+
+struct rspi_plat_data {
+ unsigned int dma_tx_id;
+ unsigned int dma_rx_id;
+
+ unsigned dma_width_16bit:1; /* DMAC read/write width = 16-bit */
+};
+
+#endif
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
index d27683180025..bc14bd738ade 100644
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -188,7 +188,6 @@ struct ssb_sprom {
struct ssb_boardinfo {
u16 vendor;
u16 type;
- u8 rev;
};
diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h
index 40b1ef8595ee..a0525019e1d1 100644
--- a/include/linux/ssb/ssb_regs.h
+++ b/include/linux/ssb/ssb_regs.h
@@ -228,6 +228,7 @@
#define SSB_SPROM1_AGAIN_BG_SHIFT 0
#define SSB_SPROM1_AGAIN_A 0xFF00 /* A-PHY */
#define SSB_SPROM1_AGAIN_A_SHIFT 8
+#define SSB_SPROM1_CCODE 0x0076
/* SPROM Revision 2 (inherits from rev 1) */
#define SSB_SPROM2_BFLHI 0x0038 /* Boardflags (high 16 bits) */
@@ -267,6 +268,7 @@
#define SSB_SPROM3_OFDMGPO 0x107A /* G-PHY OFDM Power Offset (4 bytes, BigEndian) */
/* SPROM Revision 4 */
+#define SSB_SPROM4_BOARDREV 0x0042 /* Board revision */
#define SSB_SPROM4_BFLLO 0x0044 /* Boardflags (low 16 bits) */
#define SSB_SPROM4_BFLHI 0x0046 /* Board Flags Hi */
#define SSB_SPROM4_BFL2LO 0x0048 /* Board flags 2 (low 16 bits) */
@@ -389,6 +391,11 @@
#define SSB_SPROM8_GPIOB_P2 0x00FF /* Pin 2 */
#define SSB_SPROM8_GPIOB_P3 0xFF00 /* Pin 3 */
#define SSB_SPROM8_GPIOB_P3_SHIFT 8
+#define SSB_SPROM8_LEDDC 0x009A
+#define SSB_SPROM8_LEDDC_ON 0xFF00 /* oncount */
+#define SSB_SPROM8_LEDDC_ON_SHIFT 8
+#define SSB_SPROM8_LEDDC_OFF 0x00FF /* offcount */
+#define SSB_SPROM8_LEDDC_OFF_SHIFT 0
#define SSB_SPROM8_ANTAVAIL 0x009C /* Antenna available bitfields*/
#define SSB_SPROM8_ANTAVAIL_A 0xFF00 /* A-PHY bitfield */
#define SSB_SPROM8_ANTAVAIL_A_SHIFT 8
@@ -404,6 +411,13 @@
#define SSB_SPROM8_AGAIN2_SHIFT 0
#define SSB_SPROM8_AGAIN3 0xFF00 /* Antenna 3 */
#define SSB_SPROM8_AGAIN3_SHIFT 8
+#define SSB_SPROM8_TXRXC 0x00A2
+#define SSB_SPROM8_TXRXC_TXCHAIN 0x000f
+#define SSB_SPROM8_TXRXC_TXCHAIN_SHIFT 0
+#define SSB_SPROM8_TXRXC_RXCHAIN 0x00f0
+#define SSB_SPROM8_TXRXC_RXCHAIN_SHIFT 4
+#define SSB_SPROM8_TXRXC_SWITCH 0xff00
+#define SSB_SPROM8_TXRXC_SWITCH_SHIFT 8
#define SSB_SPROM8_RSSIPARM2G 0x00A4 /* RSSI params for 2GHz */
#define SSB_SPROM8_RSSISMF2G 0x000F
#define SSB_SPROM8_RSSISMC2G 0x00F0
@@ -430,6 +444,7 @@
#define SSB_SPROM8_TRI5GH_SHIFT 8
#define SSB_SPROM8_RXPO 0x00AC /* RX power offsets */
#define SSB_SPROM8_RXPO2G 0x00FF /* 2GHz RX power offset */
+#define SSB_SPROM8_RXPO2G_SHIFT 0
#define SSB_SPROM8_RXPO5G 0xFF00 /* 5GHz RX power offset */
#define SSB_SPROM8_RXPO5G_SHIFT 8
#define SSB_SPROM8_FEM2G 0x00AE
@@ -445,10 +460,38 @@
#define SSB_SROM8_FEM_ANTSWLUT 0xF800
#define SSB_SROM8_FEM_ANTSWLUT_SHIFT 11
#define SSB_SPROM8_THERMAL 0x00B2
-#define SSB_SPROM8_MPWR_RAWTS 0x00B4
-#define SSB_SPROM8_TS_SLP_OPT_CORRX 0x00B6
-#define SSB_SPROM8_FOC_HWIQ_IQSWP 0x00B8
-#define SSB_SPROM8_PHYCAL_TEMPDELTA 0x00BA
+#define SSB_SPROM8_THERMAL_OFFSET 0x00ff
+#define SSB_SPROM8_THERMAL_OFFSET_SHIFT 0
+#define SSB_SPROM8_THERMAL_TRESH 0xff00
+#define SSB_SPROM8_THERMAL_TRESH_SHIFT 8
+/* Temp sense related entries */
+#define SSB_SPROM8_RAWTS 0x00B4
+#define SSB_SPROM8_RAWTS_RAWTEMP 0x01ff
+#define SSB_SPROM8_RAWTS_RAWTEMP_SHIFT 0
+#define SSB_SPROM8_RAWTS_MEASPOWER 0xfe00
+#define SSB_SPROM8_RAWTS_MEASPOWER_SHIFT 9
+#define SSB_SPROM8_OPT_CORRX 0x00B6
+#define SSB_SPROM8_OPT_CORRX_TEMP_SLOPE 0x00ff
+#define SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT 0
+#define SSB_SPROM8_OPT_CORRX_TEMPCORRX 0xfc00
+#define SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT 10
+#define SSB_SPROM8_OPT_CORRX_TEMP_OPTION 0x0300
+#define SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT 8
+/* FOC: freiquency offset correction, HWIQ: H/W IOCAL enable, IQSWP: IQ CAL swap disable */
+#define SSB_SPROM8_HWIQ_IQSWP 0x00B8
+#define SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR 0x000f
+#define SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT 0
+#define SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP 0x0010
+#define SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT 4
+#define SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL 0x0020
+#define SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT 5
+#define SSB_SPROM8_TEMPDELTA 0x00BA
+#define SSB_SPROM8_TEMPDELTA_PHYCAL 0x00ff
+#define SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT 0
+#define SSB_SPROM8_TEMPDELTA_PERIOD 0x0f00
+#define SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT 8
+#define SSB_SPROM8_TEMPDELTA_HYSTERESIS 0xf000
+#define SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT 12
/* There are 4 blocks with power info sharing the same layout */
#define SSB_SROM8_PWR_INFO_CORE0 0x00C0
@@ -513,6 +556,16 @@
#define SSB_SPROM8_OFDM5GLPO 0x014A /* 5.2GHz OFDM power offset */
#define SSB_SPROM8_OFDM5GHPO 0x014E /* 5.8GHz OFDM power offset */
+#define SSB_SPROM8_2G_MCSPO 0x0152
+#define SSB_SPROM8_5G_MCSPO 0x0162
+#define SSB_SPROM8_5GL_MCSPO 0x0172
+#define SSB_SPROM8_5GH_MCSPO 0x0182
+
+#define SSB_SPROM8_CDDPO 0x0192
+#define SSB_SPROM8_STBCPO 0x0194
+#define SSB_SPROM8_BW40PO 0x0196
+#define SSB_SPROM8_BWDUPPO 0x0198
+
/* Values for boardflags_lo read from SPROM */
#define SSB_BFL_BTCOEXIST 0x0001 /* implements Bluetooth coexistance */
#define SSB_BFL_PACTRL 0x0002 /* GPIO 9 controlling the PA */
diff --git a/include/linux/stat.h b/include/linux/stat.h
index 611c398dab72..46132409a3f7 100644
--- a/include/linux/stat.h
+++ b/include/linux/stat.h
@@ -58,14 +58,15 @@
#include <linux/types.h>
#include <linux/time.h>
+#include <linux/uidgid.h>
struct kstat {
u64 ino;
dev_t dev;
umode_t mode;
unsigned int nlink;
- uid_t uid;
- gid_t gid;
+ kuid_t uid;
+ kgid_t gid;
dev_t rdev;
loff_t size;
struct timespec atime;
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index ac1c114c499d..cd83059fb592 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -356,8 +356,9 @@ extern int unregister_pm_notifier(struct notifier_block *nb);
extern bool events_check_enabled;
extern bool pm_wakeup_pending(void);
-extern bool pm_get_wakeup_count(unsigned int *count);
+extern bool pm_get_wakeup_count(unsigned int *count, bool block);
extern bool pm_save_wakeup_count(unsigned int count);
+extern void pm_wakep_autosleep_enabled(bool set);
static inline void lock_system_sleep(void)
{
@@ -407,6 +408,17 @@ static inline void unlock_system_sleep(void) {}
#endif /* !CONFIG_PM_SLEEP */
+#ifdef CONFIG_PM_AUTOSLEEP
+
+/* kernel/power/autosleep.c */
+void queue_up_suspend_work(void);
+
+#else /* !CONFIG_PM_AUTOSLEEP */
+
+static inline void queue_up_suspend_work(void) {}
+
+#endif /* !CONFIG_PM_AUTOSLEEP */
+
#ifdef CONFIG_ARCH_SAVE_PAGE_KEYS
/*
* The ARCH_SAVE_PAGE_KEYS functions can be used by an architecture
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index 0010009b2f00..381f06db2fe5 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -27,6 +27,7 @@ struct attribute {
const char *name;
umode_t mode;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
+ bool ignore_lockdep:1;
struct lock_class_key *key;
struct lock_class_key skey;
#endif
@@ -80,6 +81,17 @@ struct attribute_group {
#define __ATTR_NULL { .attr = { .name = NULL } }
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+#define __ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) { \
+ .attr = {.name = __stringify(_name), .mode = _mode, \
+ .ignore_lockdep = true }, \
+ .show = _show, \
+ .store = _store, \
+}
+#else
+#define __ATTR_IGNORE_LOCKDEP __ATTR
+#endif
+
#define attr_name(_attr) (_attr).attr.name
struct file;
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index d9b42c5be088..4c5b63283377 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -426,7 +426,7 @@ struct tcp_sock {
struct sk_buff_head out_of_order_queue; /* Out of order segments go here */
- /* SACKs data, these 2 need to be together (see tcp_build_and_update_options) */
+ /* SACKs data, these 2 need to be together (see tcp_options_write) */
struct tcp_sack_block duplicate_sack[1]; /* D-SACK block */
struct tcp_sack_block selective_acks[4]; /* The SACKS themselves*/
diff --git a/include/linux/ti_wilink_st.h b/include/linux/ti_wilink_st.h
index 2ef4385da6bf..3ca0269dd0b5 100644
--- a/include/linux/ti_wilink_st.h
+++ b/include/linux/ti_wilink_st.h
@@ -25,6 +25,8 @@
#ifndef TI_WILINK_ST_H
#define TI_WILINK_ST_H
+#include <linux/skbuff.h>
+
/**
* enum proto-type - The protocol on WiLink chips which share a
* common physical interface like UART.
diff --git a/include/linux/time.h b/include/linux/time.h
index 33a92ead4d88..179f4d6755fc 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -167,7 +167,6 @@ extern void get_monotonic_boottime(struct timespec *ts);
extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
extern int timekeeping_valid_for_hres(void);
extern u64 timekeeping_max_deferment(void);
-extern void timekeeping_leap_insert(int leapsecond);
extern int timekeeping_inject_offset(struct timespec *ts);
struct tms;
diff --git a/include/linux/topology.h b/include/linux/topology.h
index e26db031303b..e91cd43394df 100644
--- a/include/linux/topology.h
+++ b/include/linux/topology.h
@@ -70,7 +70,6 @@ int arch_update_cpu_topology(void);
* Below are the 3 major initializers used in building sched_domains:
* SD_SIBLING_INIT, for SMT domains
* SD_CPU_INIT, for SMP domains
- * SD_NODE_INIT, for NUMA domains
*
* Any architecture that cares to do any tuning to these values should do so
* by defining their own arch-specific initializer in include/asm/topology.h.
@@ -99,7 +98,6 @@ int arch_update_cpu_topology(void);
| 0*SD_BALANCE_WAKE \
| 1*SD_WAKE_AFFINE \
| 1*SD_SHARE_CPUPOWER \
- | 0*SD_POWERSAVINGS_BALANCE \
| 1*SD_SHARE_PKG_RESOURCES \
| 0*SD_SERIALIZE \
| 0*SD_PREFER_SIBLING \
@@ -135,8 +133,6 @@ int arch_update_cpu_topology(void);
| 0*SD_SHARE_CPUPOWER \
| 1*SD_SHARE_PKG_RESOURCES \
| 0*SD_SERIALIZE \
- | sd_balance_for_mc_power() \
- | sd_power_saving_flags() \
, \
.last_balance = jiffies, \
.balance_interval = 1, \
@@ -168,56 +164,18 @@ int arch_update_cpu_topology(void);
| 0*SD_SHARE_CPUPOWER \
| 0*SD_SHARE_PKG_RESOURCES \
| 0*SD_SERIALIZE \
- | sd_balance_for_package_power() \
- | sd_power_saving_flags() \
, \
.last_balance = jiffies, \
.balance_interval = 1, \
}
#endif
-/* sched_domains SD_ALLNODES_INIT for NUMA machines */
-#define SD_ALLNODES_INIT (struct sched_domain) { \
- .min_interval = 64, \
- .max_interval = 64*num_online_cpus(), \
- .busy_factor = 128, \
- .imbalance_pct = 133, \
- .cache_nice_tries = 1, \
- .busy_idx = 3, \
- .idle_idx = 3, \
- .flags = 1*SD_LOAD_BALANCE \
- | 1*SD_BALANCE_NEWIDLE \
- | 0*SD_BALANCE_EXEC \
- | 0*SD_BALANCE_FORK \
- | 0*SD_BALANCE_WAKE \
- | 0*SD_WAKE_AFFINE \
- | 0*SD_SHARE_CPUPOWER \
- | 0*SD_POWERSAVINGS_BALANCE \
- | 0*SD_SHARE_PKG_RESOURCES \
- | 1*SD_SERIALIZE \
- | 0*SD_PREFER_SIBLING \
- , \
- .last_balance = jiffies, \
- .balance_interval = 64, \
-}
-
-#ifndef SD_NODES_PER_DOMAIN
-#define SD_NODES_PER_DOMAIN 16
-#endif
-
#ifdef CONFIG_SCHED_BOOK
#ifndef SD_BOOK_INIT
#error Please define an appropriate SD_BOOK_INIT in include/asm/topology.h!!!
#endif
#endif /* CONFIG_SCHED_BOOK */
-#ifdef CONFIG_NUMA
-#ifndef SD_NODE_INIT
-#error Please define an appropriate SD_NODE_INIT in include/asm/topology.h!!!
-#endif
-
-#endif /* CONFIG_NUMA */
-
#ifdef CONFIG_USE_PERCPU_NUMA_NODE_ID
DECLARE_PER_CPU(int, numa_node);
@@ -239,7 +197,7 @@ static inline int cpu_to_node(int cpu)
#ifndef set_numa_node
static inline void set_numa_node(int node)
{
- percpu_write(numa_node, node);
+ this_cpu_write(numa_node, node);
}
#endif
@@ -274,7 +232,7 @@ DECLARE_PER_CPU(int, _numa_mem_);
#ifndef set_numa_mem
static inline void set_numa_mem(int node)
{
- percpu_write(_numa_mem_, node);
+ this_cpu_write(_numa_mem_, node);
}
#endif
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 9f47ab540f65..4990ef2b1fb7 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -268,6 +268,7 @@ struct tty_struct {
struct mutex ldisc_mutex;
struct tty_ldisc *ldisc;
+ struct mutex legacy_mutex;
struct mutex termios_mutex;
spinlock_t ctrl_lock;
/* Termios values are protected by the termios mutex */
@@ -605,8 +606,12 @@ extern long vt_compat_ioctl(struct tty_struct *tty,
/* tty_mutex.c */
/* functions for preparation of BKL removal */
-extern void __lockfunc tty_lock(void) __acquires(tty_lock);
-extern void __lockfunc tty_unlock(void) __releases(tty_lock);
+extern void __lockfunc tty_lock(struct tty_struct *tty);
+extern void __lockfunc tty_unlock(struct tty_struct *tty);
+extern void __lockfunc tty_lock_pair(struct tty_struct *tty,
+ struct tty_struct *tty2);
+extern void __lockfunc tty_unlock_pair(struct tty_struct *tty,
+ struct tty_struct *tty2);
/*
* this shall be called only from where BTM is held (like close)
@@ -621,9 +626,9 @@ extern void __lockfunc tty_unlock(void) __releases(tty_lock);
static inline void tty_wait_until_sent_from_close(struct tty_struct *tty,
long timeout)
{
- tty_unlock(); /* tty->ops->close holds the BTM, drop it while waiting */
+ tty_unlock(tty); /* tty->ops->close holds the BTM, drop it while waiting */
tty_wait_until_sent(tty, timeout);
- tty_lock();
+ tty_lock(tty);
}
/*
@@ -638,16 +643,16 @@ static inline void tty_wait_until_sent_from_close(struct tty_struct *tty,
*
* Do not use in new code.
*/
-#define wait_event_interruptible_tty(wq, condition) \
+#define wait_event_interruptible_tty(tty, wq, condition) \
({ \
int __ret = 0; \
if (!(condition)) { \
- __wait_event_interruptible_tty(wq, condition, __ret); \
+ __wait_event_interruptible_tty(tty, wq, condition, __ret); \
} \
__ret; \
})
-#define __wait_event_interruptible_tty(wq, condition, ret) \
+#define __wait_event_interruptible_tty(tty, wq, condition, ret) \
do { \
DEFINE_WAIT(__wait); \
\
@@ -656,9 +661,9 @@ do { \
if (condition) \
break; \
if (!signal_pending(current)) { \
- tty_unlock(); \
+ tty_unlock(tty); \
schedule(); \
- tty_lock(); \
+ tty_lock(tty); \
continue; \
} \
ret = -ERESTARTSYS; \
diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h
index ff7dc08696a8..fb79dd8d1537 100644
--- a/include/linux/tty_ldisc.h
+++ b/include/linux/tty_ldisc.h
@@ -110,6 +110,7 @@
#include <linux/fs.h>
#include <linux/wait.h>
#include <linux/pps_kernel.h>
+#include <linux/wait.h>
struct tty_ldisc_ops {
int magic;
@@ -154,6 +155,7 @@ struct tty_ldisc_ops {
struct tty_ldisc {
struct tty_ldisc_ops *ops;
atomic_t users;
+ wait_queue_head_t wq_idle;
};
#define TTY_LDISC_MAGIC 0x5403
diff --git a/include/linux/uidgid.h b/include/linux/uidgid.h
new file mode 100644
index 000000000000..8e522cbcef29
--- /dev/null
+++ b/include/linux/uidgid.h
@@ -0,0 +1,200 @@
+#ifndef _LINUX_UIDGID_H
+#define _LINUX_UIDGID_H
+
+/*
+ * A set of types for the internal kernel types representing uids and gids.
+ *
+ * The types defined in this header allow distinguishing which uids and gids in
+ * the kernel are values used by userspace and which uid and gid values are
+ * the internal kernel values. With the addition of user namespaces the values
+ * can be different. Using the type system makes it possible for the compiler
+ * to detect when we overlook these differences.
+ *
+ */
+#include <linux/types.h>
+#include <linux/highuid.h>
+
+struct user_namespace;
+extern struct user_namespace init_user_ns;
+
+#ifdef CONFIG_UIDGID_STRICT_TYPE_CHECKS
+
+typedef struct {
+ uid_t val;
+} kuid_t;
+
+
+typedef struct {
+ gid_t val;
+} kgid_t;
+
+#define KUIDT_INIT(value) (kuid_t){ value }
+#define KGIDT_INIT(value) (kgid_t){ value }
+
+static inline uid_t __kuid_val(kuid_t uid)
+{
+ return uid.val;
+}
+
+static inline gid_t __kgid_val(kgid_t gid)
+{
+ return gid.val;
+}
+
+#else
+
+typedef uid_t kuid_t;
+typedef gid_t kgid_t;
+
+static inline uid_t __kuid_val(kuid_t uid)
+{
+ return uid;
+}
+
+static inline gid_t __kgid_val(kgid_t gid)
+{
+ return gid;
+}
+
+#define KUIDT_INIT(value) ((kuid_t) value )
+#define KGIDT_INIT(value) ((kgid_t) value )
+
+#endif
+
+#define GLOBAL_ROOT_UID KUIDT_INIT(0)
+#define GLOBAL_ROOT_GID KGIDT_INIT(0)
+
+#define INVALID_UID KUIDT_INIT(-1)
+#define INVALID_GID KGIDT_INIT(-1)
+
+static inline bool uid_eq(kuid_t left, kuid_t right)
+{
+ return __kuid_val(left) == __kuid_val(right);
+}
+
+static inline bool gid_eq(kgid_t left, kgid_t right)
+{
+ return __kgid_val(left) == __kgid_val(right);
+}
+
+static inline bool uid_gt(kuid_t left, kuid_t right)
+{
+ return __kuid_val(left) > __kuid_val(right);
+}
+
+static inline bool gid_gt(kgid_t left, kgid_t right)
+{
+ return __kgid_val(left) > __kgid_val(right);
+}
+
+static inline bool uid_gte(kuid_t left, kuid_t right)
+{
+ return __kuid_val(left) >= __kuid_val(right);
+}
+
+static inline bool gid_gte(kgid_t left, kgid_t right)
+{
+ return __kgid_val(left) >= __kgid_val(right);
+}
+
+static inline bool uid_lt(kuid_t left, kuid_t right)
+{
+ return __kuid_val(left) < __kuid_val(right);
+}
+
+static inline bool gid_lt(kgid_t left, kgid_t right)
+{
+ return __kgid_val(left) < __kgid_val(right);
+}
+
+static inline bool uid_lte(kuid_t left, kuid_t right)
+{
+ return __kuid_val(left) <= __kuid_val(right);
+}
+
+static inline bool gid_lte(kgid_t left, kgid_t right)
+{
+ return __kgid_val(left) <= __kgid_val(right);
+}
+
+static inline bool uid_valid(kuid_t uid)
+{
+ return !uid_eq(uid, INVALID_UID);
+}
+
+static inline bool gid_valid(kgid_t gid)
+{
+ return !gid_eq(gid, INVALID_GID);
+}
+
+#ifdef CONFIG_USER_NS
+
+extern kuid_t make_kuid(struct user_namespace *from, uid_t uid);
+extern kgid_t make_kgid(struct user_namespace *from, gid_t gid);
+
+extern uid_t from_kuid(struct user_namespace *to, kuid_t uid);
+extern gid_t from_kgid(struct user_namespace *to, kgid_t gid);
+extern uid_t from_kuid_munged(struct user_namespace *to, kuid_t uid);
+extern gid_t from_kgid_munged(struct user_namespace *to, kgid_t gid);
+
+static inline bool kuid_has_mapping(struct user_namespace *ns, kuid_t uid)
+{
+ return from_kuid(ns, uid) != (uid_t) -1;
+}
+
+static inline bool kgid_has_mapping(struct user_namespace *ns, kgid_t gid)
+{
+ return from_kgid(ns, gid) != (gid_t) -1;
+}
+
+#else
+
+static inline kuid_t make_kuid(struct user_namespace *from, uid_t uid)
+{
+ return KUIDT_INIT(uid);
+}
+
+static inline kgid_t make_kgid(struct user_namespace *from, gid_t gid)
+{
+ return KGIDT_INIT(gid);
+}
+
+static inline uid_t from_kuid(struct user_namespace *to, kuid_t kuid)
+{
+ return __kuid_val(kuid);
+}
+
+static inline gid_t from_kgid(struct user_namespace *to, kgid_t kgid)
+{
+ return __kgid_val(kgid);
+}
+
+static inline uid_t from_kuid_munged(struct user_namespace *to, kuid_t kuid)
+{
+ uid_t uid = from_kuid(to, kuid);
+ if (uid == (uid_t)-1)
+ uid = overflowuid;
+ return uid;
+}
+
+static inline gid_t from_kgid_munged(struct user_namespace *to, kgid_t kgid)
+{
+ gid_t gid = from_kgid(to, kgid);
+ if (gid == (gid_t)-1)
+ gid = overflowgid;
+ return gid;
+}
+
+static inline bool kuid_has_mapping(struct user_namespace *ns, kuid_t uid)
+{
+ return true;
+}
+
+static inline bool kgid_has_mapping(struct user_namespace *ns, kgid_t gid)
+{
+ return true;
+}
+
+#endif /* CONFIG_USER_NS */
+
+#endif /* _LINUX_UIDGID_H */
diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
new file mode 100644
index 000000000000..efe4b3308c74
--- /dev/null
+++ b/include/linux/uprobes.h
@@ -0,0 +1,165 @@
+#ifndef _LINUX_UPROBES_H
+#define _LINUX_UPROBES_H
+/*
+ * User-space Probes (UProbes)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2008-2012
+ * Authors:
+ * Srikar Dronamraju
+ * Jim Keniston
+ * Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ */
+
+#include <linux/errno.h>
+#include <linux/rbtree.h>
+
+struct vm_area_struct;
+struct mm_struct;
+struct inode;
+
+#ifdef CONFIG_ARCH_SUPPORTS_UPROBES
+# include <asm/uprobes.h>
+#endif
+
+/* flags that denote/change uprobes behaviour */
+
+/* Have a copy of original instruction */
+#define UPROBE_COPY_INSN 0x1
+
+/* Dont run handlers when first register/ last unregister in progress*/
+#define UPROBE_RUN_HANDLER 0x2
+/* Can skip singlestep */
+#define UPROBE_SKIP_SSTEP 0x4
+
+struct uprobe_consumer {
+ int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs);
+ /*
+ * filter is optional; If a filter exists, handler is run
+ * if and only if filter returns true.
+ */
+ bool (*filter)(struct uprobe_consumer *self, struct task_struct *task);
+
+ struct uprobe_consumer *next;
+};
+
+#ifdef CONFIG_UPROBES
+enum uprobe_task_state {
+ UTASK_RUNNING,
+ UTASK_BP_HIT,
+ UTASK_SSTEP,
+ UTASK_SSTEP_ACK,
+ UTASK_SSTEP_TRAPPED,
+};
+
+/*
+ * uprobe_task: Metadata of a task while it singlesteps.
+ */
+struct uprobe_task {
+ enum uprobe_task_state state;
+ struct arch_uprobe_task autask;
+
+ struct uprobe *active_uprobe;
+
+ unsigned long xol_vaddr;
+ unsigned long vaddr;
+};
+
+/*
+ * On a breakpoint hit, thread contests for a slot. It frees the
+ * slot after singlestep. Currently a fixed number of slots are
+ * allocated.
+ */
+struct xol_area {
+ wait_queue_head_t wq; /* if all slots are busy */
+ atomic_t slot_count; /* number of in-use slots */
+ unsigned long *bitmap; /* 0 = free slot */
+ struct page *page;
+
+ /*
+ * We keep the vma's vm_start rather than a pointer to the vma
+ * itself. The probed process or a naughty kernel module could make
+ * the vma go away, and we must handle that reasonably gracefully.
+ */
+ unsigned long vaddr; /* Page(s) of instruction slots */
+};
+
+struct uprobes_state {
+ struct xol_area *xol_area;
+ atomic_t count;
+};
+extern int __weak set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr);
+extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr, bool verify);
+extern bool __weak is_swbp_insn(uprobe_opcode_t *insn);
+extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
+extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
+extern int uprobe_mmap(struct vm_area_struct *vma);
+extern void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end);
+extern void uprobe_free_utask(struct task_struct *t);
+extern void uprobe_copy_process(struct task_struct *t);
+extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs);
+extern int uprobe_post_sstep_notifier(struct pt_regs *regs);
+extern int uprobe_pre_sstep_notifier(struct pt_regs *regs);
+extern void uprobe_notify_resume(struct pt_regs *regs);
+extern bool uprobe_deny_signal(void);
+extern bool __weak arch_uprobe_skip_sstep(struct arch_uprobe *aup, struct pt_regs *regs);
+extern void uprobe_clear_state(struct mm_struct *mm);
+extern void uprobe_reset_state(struct mm_struct *mm);
+#else /* !CONFIG_UPROBES */
+struct uprobes_state {
+};
+static inline int
+uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc)
+{
+ return -ENOSYS;
+}
+static inline void
+uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc)
+{
+}
+static inline int uprobe_mmap(struct vm_area_struct *vma)
+{
+ return 0;
+}
+static inline void
+uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end)
+{
+}
+static inline void uprobe_notify_resume(struct pt_regs *regs)
+{
+}
+static inline bool uprobe_deny_signal(void)
+{
+ return false;
+}
+static inline unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
+{
+ return 0;
+}
+static inline void uprobe_free_utask(struct task_struct *t)
+{
+}
+static inline void uprobe_copy_process(struct task_struct *t)
+{
+}
+static inline void uprobe_clear_state(struct mm_struct *mm)
+{
+}
+static inline void uprobe_reset_state(struct mm_struct *mm)
+{
+}
+#endif /* !CONFIG_UPROBES */
+#endif /* _LINUX_UPROBES_H */
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 73b68d1f2cb0..dea39dc551d4 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -351,10 +351,6 @@ struct usb_bus {
int bandwidth_int_reqs; /* number of Interrupt requests */
int bandwidth_isoc_reqs; /* number of Isoc. requests */
-#ifdef CONFIG_USB_DEVICEFS
- struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */
-#endif
-
#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
struct mon_bus *mon_bus; /* non-null when associated */
int monitored; /* non-zero when monitored */
@@ -382,6 +378,45 @@ enum usb_device_removable {
USB_DEVICE_FIXED,
};
+/*
+ * USB 3.0 Link Power Management (LPM) parameters.
+ *
+ * PEL and SEL are USB 3.0 Link PM latencies for device-initiated LPM exit.
+ * MEL is the USB 3.0 Link PM latency for host-initiated LPM exit.
+ * All three are stored in nanoseconds.
+ */
+struct usb3_lpm_parameters {
+ /*
+ * Maximum exit latency (MEL) for the host to send a packet to the
+ * device (either a Ping for isoc endpoints, or a data packet for
+ * interrupt endpoints), the hubs to decode the packet, and for all hubs
+ * in the path to transition the links to U0.
+ */
+ unsigned int mel;
+ /*
+ * Maximum exit latency for a device-initiated LPM transition to bring
+ * all links into U0. Abbreviated as "PEL" in section 9.4.12 of the USB
+ * 3.0 spec, with no explanation of what "P" stands for. "Path"?
+ */
+ unsigned int pel;
+
+ /*
+ * The System Exit Latency (SEL) includes PEL, and three other
+ * latencies. After a device initiates a U0 transition, it will take
+ * some time from when the device sends the ERDY to when it will finally
+ * receive the data packet. Basically, SEL should be the worse-case
+ * latency from when a device starts initiating a U0 transition to when
+ * it will get data.
+ */
+ unsigned int sel;
+ /*
+ * The idle timeout value that is currently programmed into the parent
+ * hub for this device. When the timer counts to zero, the parent hub
+ * will initiate an LPM transition to either U1 or U2.
+ */
+ int timeout;
+};
+
/**
* struct usb_device - kernel's representation of a USB device
* @devnum: device number; address on a USB bus
@@ -439,6 +474,12 @@ enum usb_device_removable {
* specific data for the device.
* @slot_id: Slot ID assigned by xHCI
* @removable: Device can be physically removed from this port
+ * @u1_params: exit latencies for USB3 U1 LPM state, and hub-initiated timeout.
+ * @u2_params: exit latencies for USB3 U2 LPM state, and hub-initiated timeout.
+ * @lpm_disable_count: Ref count used by usb_disable_lpm() and usb_enable_lpm()
+ * to keep track of the number of functions that require USB 3.0 Link Power
+ * Management to be disabled for this usb_device. This count should only
+ * be manipulated by those functions, with the bandwidth_mutex is held.
*
* Notes:
* Usbcore drivers should not set usbdev->state directly. Instead use
@@ -485,6 +526,7 @@ struct usb_device {
unsigned lpm_capable:1;
unsigned usb2_hw_lpm_capable:1;
unsigned usb2_hw_lpm_enabled:1;
+ unsigned usb3_lpm_enabled:1;
int string_langid;
/* static strings from the device */
@@ -493,12 +535,6 @@ struct usb_device {
char *serial;
struct list_head filelist;
-#ifdef CONFIG_USB_DEVICE_CLASS
- struct device *usb_classdev;
-#endif
-#ifdef CONFIG_USB_DEVICEFS
- struct dentry *usbfs_dentry;
-#endif
int maxchild;
struct usb_device **children;
@@ -517,6 +553,10 @@ struct usb_device {
struct wusb_dev *wusb_dev;
int slot_id;
enum usb_device_removable removable;
+ struct usb3_lpm_parameters u1_params;
+ struct usb3_lpm_parameters u2_params;
+ unsigned lpm_disable_count;
+ unsigned hub_initiated_lpm_disable_count;
};
#define to_usb_device(d) container_of(d, struct usb_device, dev)
@@ -583,6 +623,12 @@ static inline void usb_mark_last_busy(struct usb_device *udev)
{ }
#endif
+extern int usb_disable_lpm(struct usb_device *udev);
+extern void usb_enable_lpm(struct usb_device *udev);
+/* Same as above, but these functions lock/unlock the bandwidth_mutex. */
+extern int usb_unlocked_disable_lpm(struct usb_device *udev);
+extern void usb_unlocked_enable_lpm(struct usb_device *udev);
+
/*-------------------------------------------------------------------------*/
/* for drivers using iso endpoints */
@@ -800,6 +846,8 @@ extern ssize_t usb_store_new_id(struct usb_dynids *dynids,
struct device_driver *driver,
const char *buf, size_t count);
+extern ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf);
+
/**
* struct usbdrv_wrap - wrapper for driver-model structure
* @driver: The driver-model core driver structure.
@@ -850,6 +898,9 @@ struct usbdrv_wrap {
* for interfaces bound to this driver.
* @soft_unbind: if set to 1, the USB core will not kill URBs and disable
* endpoints before calling the driver's disconnect method.
+ * @disable_hub_initiated_lpm: if set to 0, the USB core will not allow hubs
+ * to initiate lower power link state transitions when an idle timeout
+ * occurs. Device-initiated USB 3.0 link PM will still be allowed.
*
* USB interface drivers must provide a name, probe() and disconnect()
* methods, and an id_table. Other driver fields are optional.
@@ -890,6 +941,7 @@ struct usb_driver {
struct usbdrv_wrap drvwrap;
unsigned int no_dynamic_id:1;
unsigned int supports_autosuspend:1;
+ unsigned int disable_hub_initiated_lpm:1;
unsigned int soft_unbind:1;
};
#define to_usb_driver(d) container_of(d, struct usb_driver, drvwrap.driver)
@@ -1379,6 +1431,7 @@ extern int usb_unlink_urb(struct urb *urb);
extern void usb_kill_urb(struct urb *urb);
extern void usb_poison_urb(struct urb *urb);
extern void usb_unpoison_urb(struct urb *urb);
+extern void usb_block_urb(struct urb *urb);
extern void usb_kill_anchored_urbs(struct usb_anchor *anchor);
extern void usb_poison_anchored_urbs(struct usb_anchor *anchor);
extern void usb_unpoison_anchored_urbs(struct usb_anchor *anchor);
@@ -1391,6 +1444,8 @@ extern struct urb *usb_get_from_anchor(struct usb_anchor *anchor);
extern void usb_scuttle_anchored_urbs(struct usb_anchor *anchor);
extern int usb_anchor_empty(struct usb_anchor *anchor);
+#define usb_unblock_urb usb_unpoison_urb
+
/**
* usb_urb_dir_in - check if an URB describes an IN transfer
* @urb: URB to be checked
@@ -1627,6 +1682,7 @@ static inline int usb_translate_errors(int error_code)
case 0:
case -ENOMEM:
case -ENODEV:
+ case -EOPNOTSUPP:
return error_code;
default:
return -EIO;
@@ -1652,9 +1708,6 @@ do { \
} while (0)
#endif
-#define err(format, arg...) \
- printk(KERN_ERR KBUILD_MODNAME ": " format "\n", ##arg)
-
/* debugfs stuff */
extern struct dentry *usb_debug_root;
diff --git a/include/linux/usb/ch11.h b/include/linux/usb/ch11.h
index f1d26b6067f1..b6c2863b2c94 100644
--- a/include/linux/usb/ch11.h
+++ b/include/linux/usb/ch11.h
@@ -76,6 +76,8 @@
#define USB_PORT_FEAT_C_BH_PORT_RESET 29
#define USB_PORT_FEAT_FORCE_LINKPM_ACCEPT 30
+#define USB_PORT_LPM_TIMEOUT(p) (((p) & 0xff) << 8)
+
/* USB 3.0 hub remote wake mask bits, see table 10-14 */
#define USB_PORT_FEAT_REMOTE_WAKE_CONNECT (1 << 8)
#define USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT (1 << 9)
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index af21f3115919..d1d732c2838d 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -88,6 +88,8 @@
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
+#define USB_REQ_SET_SEL 0x30
+#define USB_REQ_SET_ISOCH_DELAY 0x31
#define USB_REQ_SET_ENCRYPTION 0x0D /* Wireless USB */
#define USB_REQ_GET_ENCRYPTION 0x0E
@@ -390,6 +392,11 @@ struct usb_endpoint_descriptor {
#define USB_ENDPOINT_XFER_INT 3
#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80
+/* The USB 3.0 spec redefines bits 5:4 of bmAttributes as interrupt ep type. */
+#define USB_ENDPOINT_INTRTYPE 0x30
+#define USB_ENDPOINT_INTR_PERIODIC (0 << 4)
+#define USB_ENDPOINT_INTR_NOTIFICATION (1 << 4)
+
#define USB_ENDPOINT_SYNCTYPE 0x0c
#define USB_ENDPOINT_SYNC_NONE (0 << 2)
#define USB_ENDPOINT_SYNC_ASYNC (1 << 2)
@@ -592,6 +599,12 @@ static inline int usb_endpoint_maxp(const struct usb_endpoint_descriptor *epd)
return __le16_to_cpu(epd->wMaxPacketSize);
}
+static inline int usb_endpoint_interrupt_type(
+ const struct usb_endpoint_descriptor *epd)
+{
+ return epd->bmAttributes & USB_ENDPOINT_INTRTYPE;
+}
+
/*-------------------------------------------------------------------------*/
/* USB_DT_SS_ENDPOINT_COMP: SuperSpeed Endpoint Companion descriptor */
@@ -933,6 +946,51 @@ enum usb_device_state {
*/
};
+enum usb3_link_state {
+ USB3_LPM_U0 = 0,
+ USB3_LPM_U1,
+ USB3_LPM_U2,
+ USB3_LPM_U3
+};
+
+/*
+ * A U1 timeout of 0x0 means the parent hub will reject any transitions to U1.
+ * 0xff means the parent hub will accept transitions to U1, but will not
+ * initiate a transition.
+ *
+ * A U1 timeout of 0x1 to 0x7F also causes the hub to initiate a transition to
+ * U1 after that many microseconds. Timeouts of 0x80 to 0xFE are reserved
+ * values.
+ *
+ * A U2 timeout of 0x0 means the parent hub will reject any transitions to U2.
+ * 0xff means the parent hub will accept transitions to U2, but will not
+ * initiate a transition.
+ *
+ * A U2 timeout of 0x1 to 0xFE also causes the hub to initiate a transition to
+ * U2 after N*256 microseconds. Therefore a U2 timeout value of 0x1 means a U2
+ * idle timer of 256 microseconds, 0x2 means 512 microseconds, 0xFE means
+ * 65.024ms.
+ */
+#define USB3_LPM_DISABLED 0x0
+#define USB3_LPM_U1_MAX_TIMEOUT 0x7F
+#define USB3_LPM_U2_MAX_TIMEOUT 0xFE
+#define USB3_LPM_DEVICE_INITIATED 0xFF
+
+struct usb_set_sel_req {
+ __u8 u1_sel;
+ __u8 u1_pel;
+ __le16 u2_sel;
+ __le16 u2_pel;
+} __attribute__ ((packed));
+
+/*
+ * The Set System Exit Latency control transfer provides one byte each for
+ * U1 SEL and U1 PEL, so the max exit latency is 0xFF. U2 SEL and U2 PEL each
+ * are two bytes long.
+ */
+#define USB3_LPM_MAX_U1_SEL_PEL 0xFF
+#define USB3_LPM_MAX_U2_SEL_PEL 0xFFFF
+
/*-------------------------------------------------------------------------*/
/*
diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h
new file mode 100644
index 000000000000..edb90d6cfd12
--- /dev/null
+++ b/include/linux/usb/chipidea.h
@@ -0,0 +1,28 @@
+/*
+ * Platform data for the chipidea USB dual role controller
+ */
+
+#ifndef __LINUX_USB_CHIPIDEA_H
+#define __LINUX_USB_CHIPIDEA_H
+
+struct ci13xxx;
+struct ci13xxx_udc_driver {
+ const char *name;
+ /* offset of the capability registers */
+ uintptr_t capoffset;
+ unsigned power_budget;
+ unsigned long flags;
+#define CI13XXX_REGS_SHARED BIT(0)
+#define CI13XXX_REQUIRE_TRANSCEIVER BIT(1)
+#define CI13XXX_PULLUP_ON_VBUS BIT(2)
+#define CI13XXX_DISABLE_STREAMING BIT(3)
+
+#define CI13XXX_CONTROLLER_RESET_EVENT 0
+#define CI13XXX_CONTROLLER_STOPPED_EVENT 1
+ void (*notify_event) (struct ci13xxx *udc, unsigned event);
+};
+
+/* Default offset of capability registers */
+#define DEF_CAPOFFSET 0x100
+
+#endif
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index a316fba73518..9d8c3b634493 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -242,6 +242,9 @@ int usb_add_config(struct usb_composite_dev *,
struct usb_configuration *,
int (*)(struct usb_configuration *));
+void usb_remove_config(struct usb_composite_dev *,
+ struct usb_configuration *);
+
/**
* struct usb_composite_driver - groups configurations into a gadget
* @name: For diagnostics, identifies the driver.
@@ -250,6 +253,8 @@ int usb_add_config(struct usb_composite_dev *,
* @iManufacturer: Used as iManufacturer override if @dev->iManufacturer is
* not set. If NULL a default "<system> <release> with <udc>" value
* will be used.
+ * @iSerialNumber: Used as iSerialNumber override if @dev->iSerialNumber is
+ * not set.
* @dev: Template descriptor for the device, including default device
* identifiers.
* @strings: tables of strings, keyed by identifiers assigned during bind()
@@ -280,6 +285,7 @@ struct usb_composite_driver {
const char *name;
const char *iProduct;
const char *iManufacturer;
+ const char *iSerialNumber;
const struct usb_device_descriptor *dev;
struct usb_gadget_strings **strings;
enum usb_device_speed max_speed;
diff --git a/include/linux/usb/functionfs.h b/include/linux/usb/functionfs.h
index 7587ef934ba8..a843d0851364 100644
--- a/include/linux/usb/functionfs.h
+++ b/include/linux/usb/functionfs.h
@@ -190,8 +190,10 @@ static int functionfs_ready_callback(struct ffs_data *ffs)
__attribute__((warn_unused_result, nonnull));
static void functionfs_closed_callback(struct ffs_data *ffs)
__attribute__((nonnull));
-static int functionfs_check_dev_callback(const char *dev_name)
+static void *functionfs_acquire_dev_callback(const char *dev_name)
__attribute__((warn_unused_result, nonnull));
+static void functionfs_release_dev_callback(struct ffs_data *ffs_data)
+ __attribute__((nonnull));
#endif
diff --git a/include/linux/usb/gpio_vbus.h b/include/linux/usb/gpio_vbus.h
index d9f03ccc2d60..837bba604a0b 100644
--- a/include/linux/usb/gpio_vbus.h
+++ b/include/linux/usb/gpio_vbus.h
@@ -17,6 +17,7 @@
* @gpio_pullup: optional D+ or D- pullup GPIO (else negative/invalid)
* @gpio_vbus_inverted: true if gpio_vbus is active low
* @gpio_pullup_inverted: true if gpio_pullup is active low
+ * @wakeup: configure gpio_vbus as a wake-up source
*
* The VBUS sensing GPIO should have a pulldown, which will normally be
* part of a resistor ladder turning a 4.0V-5.25V level on VBUS into a
@@ -27,4 +28,5 @@ struct gpio_vbus_mach_info {
int gpio_pullup;
bool gpio_vbus_inverted;
bool gpio_pullup_inverted;
+ bool wakeup;
};
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index d28cc78a38e4..7f855d50cdf5 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -344,6 +344,15 @@ struct hc_driver {
*/
int (*update_device)(struct usb_hcd *, struct usb_device *);
int (*set_usb2_hw_lpm)(struct usb_hcd *, struct usb_device *, int);
+ /* USB 3.0 Link Power Management */
+ /* Returns the USB3 hub-encoded value for the U1/U2 timeout. */
+ int (*enable_usb3_lpm_timeout)(struct usb_hcd *,
+ struct usb_device *, enum usb3_link_state state);
+ /* The xHCI host controller can still fail the command to
+ * disable the LPM timeouts, so this can return an error code.
+ */
+ int (*disable_usb3_lpm_timeout)(struct usb_hcd *,
+ struct usb_device *, enum usb3_link_state state);
};
extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
@@ -584,29 +593,6 @@ static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
}
#endif /* CONFIG_USB_SUSPEND */
-
-/*
- * USB device fs stuff
- */
-
-#ifdef CONFIG_USB_DEVICEFS
-
-/*
- * these are expected to be called from the USB core/hub thread
- * with the kernel lock held
- */
-extern void usbfs_update_special(void);
-extern int usbfs_init(void);
-extern void usbfs_cleanup(void);
-
-#else /* CONFIG_USB_DEVICEFS */
-
-static inline void usbfs_update_special(void) {}
-static inline int usbfs_init(void) { return 0; }
-static inline void usbfs_cleanup(void) { }
-
-#endif /* CONFIG_USB_DEVICEFS */
-
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_USB_MON) || defined(CONFIG_USB_MON_MODULE)
diff --git a/include/linux/usb/isp1301.h b/include/linux/usb/isp1301.h
new file mode 100644
index 000000000000..d3a851c28b6a
--- /dev/null
+++ b/include/linux/usb/isp1301.h
@@ -0,0 +1,80 @@
+/*
+ * NXP ISP1301 USB transceiver driver
+ *
+ * Copyright (C) 2012 Roland Stigge <stigge@antcom.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 __LINUX_USB_ISP1301_H
+#define __LINUX_USB_ISP1301_H
+
+#include <linux/of.h>
+
+/* I2C Register definitions: */
+
+#define ISP1301_I2C_MODE_CONTROL_1 0x04 /* u8 read, set, +1 clear */
+
+#define MC1_SPEED_REG (1 << 0)
+#define MC1_SUSPEND_REG (1 << 1)
+#define MC1_DAT_SE0 (1 << 2)
+#define MC1_TRANSPARENT (1 << 3)
+#define MC1_BDIS_ACON_EN (1 << 4)
+#define MC1_OE_INT_EN (1 << 5)
+#define MC1_UART_EN (1 << 6)
+#define MC1_MASK 0x7f
+
+#define ISP1301_I2C_MODE_CONTROL_2 0x12 /* u8 read, set, +1 clear */
+
+#define MC2_GLOBAL_PWR_DN (1 << 0)
+#define MC2_SPD_SUSP_CTRL (1 << 1)
+#define MC2_BI_DI (1 << 2)
+#define MC2_TRANSP_BDIR0 (1 << 3)
+#define MC2_TRANSP_BDIR1 (1 << 4)
+#define MC2_AUDIO_EN (1 << 5)
+#define MC2_PSW_EN (1 << 6)
+#define MC2_EN2V7 (1 << 7)
+
+#define ISP1301_I2C_OTG_CONTROL_1 0x06 /* u8 read, set, +1 clear */
+
+#define OTG1_DP_PULLUP (1 << 0)
+#define OTG1_DM_PULLUP (1 << 1)
+#define OTG1_DP_PULLDOWN (1 << 2)
+#define OTG1_DM_PULLDOWN (1 << 3)
+#define OTG1_ID_PULLDOWN (1 << 4)
+#define OTG1_VBUS_DRV (1 << 5)
+#define OTG1_VBUS_DISCHRG (1 << 6)
+#define OTG1_VBUS_CHRG (1 << 7)
+
+#define ISP1301_I2C_OTG_CONTROL_2 0x10 /* u8 readonly */
+
+#define OTG_B_SESS_END (1 << 6)
+#define OTG_B_SESS_VLD (1 << 7)
+
+#define ISP1301_I2C_INTERRUPT_SOURCE 0x8
+#define ISP1301_I2C_INTERRUPT_LATCH 0xA
+#define ISP1301_I2C_INTERRUPT_FALLING 0xC
+#define ISP1301_I2C_INTERRUPT_RISING 0xE
+
+#define INT_VBUS_VLD (1 << 0)
+#define INT_SESS_VLD (1 << 1)
+#define INT_DP_HI (1 << 2)
+#define INT_ID_GND (1 << 3)
+#define INT_DM_HI (1 << 4)
+#define INT_ID_FLOAT (1 << 5)
+#define INT_BDIS_ACON (1 << 6)
+#define INT_CR_INT (1 << 7)
+
+#define ISP1301_I2C_REG_CLEAR_ADDR 1 /* Register Address Modifier */
+
+struct i2c_client *isp1301_get_client(struct device_node *node);
+
+#endif /* __LINUX_USB_ISP1301_H */
diff --git a/include/linux/usb/langwell_udc.h b/include/linux/usb/langwell_udc.h
deleted file mode 100644
index 2d2d1bbad9d2..000000000000
--- a/include/linux/usb/langwell_udc.h
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * Intel Langwell USB Device Controller driver
- * Copyright (C) 2008-2009, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#ifndef __LANGWELL_UDC_H
-#define __LANGWELL_UDC_H
-
-
-/* MACRO defines */
-#define CAP_REG_OFFSET 0x0
-#define OP_REG_OFFSET 0x28
-
-#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-
-#define DQH_ALIGNMENT 2048
-#define DTD_ALIGNMENT 64
-#define DMA_BOUNDARY 4096
-
-#define EP0_MAX_PKT_SIZE 64
-#define EP_DIR_IN 1
-#define EP_DIR_OUT 0
-
-#define FLUSH_TIMEOUT 1000
-#define RESET_TIMEOUT 1000
-#define SETUPSTAT_TIMEOUT 100
-#define PRIME_TIMEOUT 100
-
-
-/* device memory space registers */
-
-/* Capability Registers, BAR0 + CAP_REG_OFFSET */
-struct langwell_cap_regs {
- /* offset: 0x0 */
- u8 caplength; /* offset of Operational Register */
- u8 _reserved3;
- u16 hciversion; /* H: BCD encoding of host version */
- u32 hcsparams; /* H: host port steering logic capability */
- u32 hccparams; /* H: host multiple mode control capability */
-#define HCC_LEN BIT(17) /* Link power management (LPM) capability */
- u8 _reserved4[0x20-0xc];
- /* offset: 0x20 */
- u16 dciversion; /* BCD encoding of device version */
- u8 _reserved5[0x24-0x22];
- u32 dccparams; /* overall device controller capability */
-#define HOSTCAP BIT(8) /* host capable */
-#define DEVCAP BIT(7) /* device capable */
-#define DEN(d) \
- (((d)>>0)&0x1f) /* bits 4:0, device endpoint number */
-} __attribute__ ((packed));
-
-
-/* Operational Registers, BAR0 + OP_REG_OFFSET */
-struct langwell_op_regs {
- /* offset: 0x28 */
- u32 extsts;
-#define EXTS_TI1 BIT(4) /* general purpose timer interrupt 1 */
-#define EXTS_TI1TI0 BIT(3) /* general purpose timer interrupt 0 */
-#define EXTS_TI1UPI BIT(2) /* USB host periodic interrupt */
-#define EXTS_TI1UAI BIT(1) /* USB host asynchronous interrupt */
-#define EXTS_TI1NAKI BIT(0) /* NAK interrupt */
- u32 extintr;
-#define EXTI_TIE1 BIT(4) /* general purpose timer interrupt enable 1 */
-#define EXTI_TIE0 BIT(3) /* general purpose timer interrupt enable 0 */
-#define EXTI_UPIE BIT(2) /* USB host periodic interrupt enable */
-#define EXTI_UAIE BIT(1) /* USB host asynchronous interrupt enable */
-#define EXTI_NAKE BIT(0) /* NAK interrupt enable */
- /* offset: 0x30 */
- u32 usbcmd;
-#define CMD_HIRD(u) \
- (((u)>>24)&0xf) /* bits 27:24, host init resume duration */
-#define CMD_ITC(u) \
- (((u)>>16)&0xff) /* bits 23:16, interrupt threshold control */
-#define CMD_PPE BIT(15) /* per-port change events enable */
-#define CMD_ATDTW BIT(14) /* add dTD tripwire */
-#define CMD_SUTW BIT(13) /* setup tripwire */
-#define CMD_ASPE BIT(11) /* asynchronous schedule park mode enable */
-#define CMD_FS2 BIT(10) /* frame list size */
-#define CMD_ASP1 BIT(9) /* asynchronous schedule park mode count */
-#define CMD_ASP0 BIT(8)
-#define CMD_LR BIT(7) /* light host/device controller reset */
-#define CMD_IAA BIT(6) /* interrupt on async advance doorbell */
-#define CMD_ASE BIT(5) /* asynchronous schedule enable */
-#define CMD_PSE BIT(4) /* periodic schedule enable */
-#define CMD_FS1 BIT(3)
-#define CMD_FS0 BIT(2)
-#define CMD_RST BIT(1) /* controller reset */
-#define CMD_RUNSTOP BIT(0) /* run/stop */
- u32 usbsts;
-#define STS_PPCI(u) \
- (((u)>>16)&0xffff) /* bits 31:16, port-n change detect */
-#define STS_AS BIT(15) /* asynchronous schedule status */
-#define STS_PS BIT(14) /* periodic schedule status */
-#define STS_RCL BIT(13) /* reclamation */
-#define STS_HCH BIT(12) /* HC halted */
-#define STS_ULPII BIT(10) /* ULPI interrupt */
-#define STS_SLI BIT(8) /* DC suspend */
-#define STS_SRI BIT(7) /* SOF received */
-#define STS_URI BIT(6) /* USB reset received */
-#define STS_AAI BIT(5) /* interrupt on async advance */
-#define STS_SEI BIT(4) /* system error */
-#define STS_FRI BIT(3) /* frame list rollover */
-#define STS_PCI BIT(2) /* port change detect */
-#define STS_UEI BIT(1) /* USB error interrupt */
-#define STS_UI BIT(0) /* USB interrupt */
- u32 usbintr;
-/* bits 31:16, per-port interrupt enable */
-#define INTR_PPCE(u) (((u)>>16)&0xffff)
-#define INTR_ULPIE BIT(10) /* ULPI enable */
-#define INTR_SLE BIT(8) /* DC sleep/suspend enable */
-#define INTR_SRE BIT(7) /* SOF received enable */
-#define INTR_URE BIT(6) /* USB reset enable */
-#define INTR_AAE BIT(5) /* interrupt on async advance enable */
-#define INTR_SEE BIT(4) /* system error enable */
-#define INTR_FRE BIT(3) /* frame list rollover enable */
-#define INTR_PCE BIT(2) /* port change detect enable */
-#define INTR_UEE BIT(1) /* USB error interrupt enable */
-#define INTR_UE BIT(0) /* USB interrupt enable */
- u32 frindex; /* frame index */
-#define FRINDEX_MASK (0x3fff << 0)
- u32 ctrldssegment; /* not used */
- u32 deviceaddr;
-#define USBADR_SHIFT 25
-#define USBADR(d) \
- (((d)>>25)&0x7f) /* bits 31:25, device address */
-#define USBADR_MASK (0x7f << 25)
-#define USBADRA BIT(24) /* device address advance */
- u32 endpointlistaddr;/* endpoint list top memory address */
-/* bits 31:11, endpoint list pointer */
-#define EPBASE(d) (((d)>>11)&0x1fffff)
-#define ENDPOINTLISTADDR_MASK (0x1fffff << 11)
- u32 ttctrl; /* H: TT operatin, not used */
- /* offset: 0x50 */
- u32 burstsize; /* burst size of data movement */
-#define TXPBURST(b) \
- (((b)>>8)&0xff) /* bits 15:8, TX burst length */
-#define RXPBURST(b) \
- (((b)>>0)&0xff) /* bits 7:0, RX burst length */
- u32 txfilltuning; /* TX tuning */
- u32 txttfilltuning; /* H: TX TT tuning */
- u32 ic_usb; /* control the IC_USB FS/LS transceiver */
- /* offset: 0x60 */
- u32 ulpi_viewport; /* indirect access to ULPI PHY */
-#define ULPIWU BIT(31) /* ULPI wakeup */
-#define ULPIRUN BIT(30) /* ULPI read/write run */
-#define ULPIRW BIT(29) /* ULPI read/write control */
-#define ULPISS BIT(27) /* ULPI sync state */
-#define ULPIPORT(u) \
- (((u)>>24)&7) /* bits 26:24, ULPI port number */
-#define ULPIADDR(u) \
- (((u)>>16)&0xff) /* bits 23:16, ULPI data address */
-#define ULPIDATRD(u) \
- (((u)>>8)&0xff) /* bits 15:8, ULPI data read */
-#define ULPIDATWR(u) \
- (((u)>>0)&0xff) /* bits 7:0, ULPI date write */
- u8 _reserved6[0x70-0x64];
- /* offset: 0x70 */
- u32 configflag; /* H: not used */
- u32 portsc1; /* port status */
-#define DA(p) \
- (((p)>>25)&0x7f) /* bits 31:25, device address */
-#define PORTS_SSTS (BIT(24) | BIT(23)) /* suspend status */
-#define PORTS_WKOC BIT(22) /* wake on over-current enable */
-#define PORTS_WKDS BIT(21) /* wake on disconnect enable */
-#define PORTS_WKCN BIT(20) /* wake on connect enable */
-#define PORTS_PTC(p) (((p)>>16)&0xf) /* bits 19:16, port test control */
-#define PORTS_PIC (BIT(15) | BIT(14)) /* port indicator control */
-#define PORTS_PO BIT(13) /* port owner */
-#define PORTS_PP BIT(12) /* port power */
-#define PORTS_LS (BIT(11) | BIT(10)) /* line status */
-#define PORTS_SLP BIT(9) /* suspend using L1 */
-#define PORTS_PR BIT(8) /* port reset */
-#define PORTS_SUSP BIT(7) /* suspend */
-#define PORTS_FPR BIT(6) /* force port resume */
-#define PORTS_OCC BIT(5) /* over-current change */
-#define PORTS_OCA BIT(4) /* over-current active */
-#define PORTS_PEC BIT(3) /* port enable/disable change */
-#define PORTS_PE BIT(2) /* port enable/disable */
-#define PORTS_CSC BIT(1) /* connect status change */
-#define PORTS_CCS BIT(0) /* current connect status */
- u8 _reserved7[0xb4-0x78];
- /* offset: 0xb4 */
- u32 devlc; /* control LPM and each USB port behavior */
-/* bits 31:29, parallel transceiver select */
-#define LPM_PTS(d) (((d)>>29)&7)
-#define LPM_STS BIT(28) /* serial transceiver select */
-#define LPM_PTW BIT(27) /* parallel transceiver width */
-#define LPM_PSPD(d) (((d)>>25)&3) /* bits 26:25, port speed */
-#define LPM_PSPD_MASK (BIT(26) | BIT(25))
-#define LPM_SPEED_FULL 0
-#define LPM_SPEED_LOW 1
-#define LPM_SPEED_HIGH 2
-#define LPM_SRT BIT(24) /* shorten reset time */
-#define LPM_PFSC BIT(23) /* port force full speed connect */
-#define LPM_PHCD BIT(22) /* PHY low power suspend clock disable */
-#define LPM_STL BIT(16) /* STALL reply to LPM token */
-#define LPM_BA(d) \
- (((d)>>1)&0x7ff) /* bits 11:1, BmAttributes */
-#define LPM_NYT_ACK BIT(0) /* NYET/ACK reply to LPM token */
- u8 _reserved8[0xf4-0xb8];
- /* offset: 0xf4 */
- u32 otgsc; /* On-The-Go status and control */
-#define OTGSC_DPIE BIT(30) /* data pulse interrupt enable */
-#define OTGSC_MSE BIT(29) /* 1 ms timer interrupt enable */
-#define OTGSC_BSEIE BIT(28) /* B session end interrupt enable */
-#define OTGSC_BSVIE BIT(27) /* B session valid interrupt enable */
-#define OTGSC_ASVIE BIT(26) /* A session valid interrupt enable */
-#define OTGSC_AVVIE BIT(25) /* A VBUS valid interrupt enable */
-#define OTGSC_IDIE BIT(24) /* USB ID interrupt enable */
-#define OTGSC_DPIS BIT(22) /* data pulse interrupt status */
-#define OTGSC_MSS BIT(21) /* 1 ms timer interrupt status */
-#define OTGSC_BSEIS BIT(20) /* B session end interrupt status */
-#define OTGSC_BSVIS BIT(19) /* B session valid interrupt status */
-#define OTGSC_ASVIS BIT(18) /* A session valid interrupt status */
-#define OTGSC_AVVIS BIT(17) /* A VBUS valid interrupt status */
-#define OTGSC_IDIS BIT(16) /* USB ID interrupt status */
-#define OTGSC_DPS BIT(14) /* data bus pulsing status */
-#define OTGSC_MST BIT(13) /* 1 ms timer toggle */
-#define OTGSC_BSE BIT(12) /* B session end */
-#define OTGSC_BSV BIT(11) /* B session valid */
-#define OTGSC_ASV BIT(10) /* A session valid */
-#define OTGSC_AVV BIT(9) /* A VBUS valid */
-#define OTGSC_USBID BIT(8) /* USB ID */
-#define OTGSC_HABA BIT(7) /* hw assist B-disconnect to A-connect */
-#define OTGSC_HADP BIT(6) /* hw assist data pulse */
-#define OTGSC_IDPU BIT(5) /* ID pullup */
-#define OTGSC_DP BIT(4) /* data pulsing */
-#define OTGSC_OT BIT(3) /* OTG termination */
-#define OTGSC_HAAR BIT(2) /* hw assist auto reset */
-#define OTGSC_VC BIT(1) /* VBUS charge */
-#define OTGSC_VD BIT(0) /* VBUS discharge */
- u32 usbmode;
-#define MODE_VBPS BIT(5) /* R/W VBUS power select */
-#define MODE_SDIS BIT(4) /* R/W stream disable mode */
-#define MODE_SLOM BIT(3) /* R/W setup lockout mode */
-#define MODE_ENSE BIT(2) /* endian select */
-#define MODE_CM(u) (((u)>>0)&3) /* bits 1:0, controller mode */
-#define MODE_IDLE 0
-#define MODE_DEVICE 2
-#define MODE_HOST 3
- u8 _reserved9[0x100-0xfc];
- /* offset: 0x100 */
- u32 endptnak;
-#define EPTN(e) \
- (((e)>>16)&0xffff) /* bits 31:16, TX endpoint NAK */
-#define EPRN(e) \
- (((e)>>0)&0xffff) /* bits 15:0, RX endpoint NAK */
- u32 endptnaken;
-#define EPTNE(e) \
- (((e)>>16)&0xffff) /* bits 31:16, TX endpoint NAK enable */
-#define EPRNE(e) \
- (((e)>>0)&0xffff) /* bits 15:0, RX endpoint NAK enable */
- u32 endptsetupstat;
-#define SETUPSTAT_MASK (0xffff << 0) /* bits 15:0 */
-#define EP0SETUPSTAT_MASK 1
- u32 endptprime;
-/* bits 31:16, prime endpoint transmit buffer */
-#define PETB(e) (((e)>>16)&0xffff)
-/* bits 15:0, prime endpoint receive buffer */
-#define PERB(e) (((e)>>0)&0xffff)
- /* offset: 0x110 */
- u32 endptflush;
-/* bits 31:16, flush endpoint transmit buffer */
-#define FETB(e) (((e)>>16)&0xffff)
-/* bits 15:0, flush endpoint receive buffer */
-#define FERB(e) (((e)>>0)&0xffff)
- u32 endptstat;
-/* bits 31:16, endpoint transmit buffer ready */
-#define ETBR(e) (((e)>>16)&0xffff)
-/* bits 15:0, endpoint receive buffer ready */
-#define ERBR(e) (((e)>>0)&0xffff)
- u32 endptcomplete;
-/* bits 31:16, endpoint transmit complete event */
-#define ETCE(e) (((e)>>16)&0xffff)
-/* bits 15:0, endpoint receive complete event */
-#define ERCE(e) (((e)>>0)&0xffff)
- /* offset: 0x11c */
- u32 endptctrl[16];
-#define EPCTRL_TXE BIT(23) /* TX endpoint enable */
-#define EPCTRL_TXR BIT(22) /* TX data toggle reset */
-#define EPCTRL_TXI BIT(21) /* TX data toggle inhibit */
-#define EPCTRL_TXT(e) (((e)>>18)&3) /* bits 19:18, TX endpoint type */
-#define EPCTRL_TXT_SHIFT 18
-#define EPCTRL_TXD BIT(17) /* TX endpoint data source */
-#define EPCTRL_TXS BIT(16) /* TX endpoint STALL */
-#define EPCTRL_RXE BIT(7) /* RX endpoint enable */
-#define EPCTRL_RXR BIT(6) /* RX data toggle reset */
-#define EPCTRL_RXI BIT(5) /* RX data toggle inhibit */
-#define EPCTRL_RXT(e) (((e)>>2)&3) /* bits 3:2, RX endpoint type */
-#define EPCTRL_RXT_SHIFT 2 /* bits 19:18, TX endpoint type */
-#define EPCTRL_RXD BIT(1) /* RX endpoint data sink */
-#define EPCTRL_RXS BIT(0) /* RX endpoint STALL */
-} __attribute__ ((packed));
-
-#endif /* __LANGWELL_UDC_H */
-
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
index 474283888233..86c0b451745d 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -1,7 +1,7 @@
/*
* USB Serial Converter stuff
*
- * Copyright (C) 1999 - 2005
+ * Copyright (C) 1999 - 2012
* Greg Kroah-Hartman (greg@kroah.com)
*
* This program is free software; you can redistribute it and/or modify
@@ -249,6 +249,7 @@ struct usb_serial_driver {
int (*suspend)(struct usb_serial *serial, pm_message_t message);
int (*resume)(struct usb_serial *serial);
+ int (*reset_resume)(struct usb_serial *serial);
/* serial function calls */
/* Called by console and by the tty layer */
@@ -292,16 +293,11 @@ struct usb_serial_driver {
#define to_usb_serial_driver(d) \
container_of(d, struct usb_serial_driver, driver)
-extern int usb_serial_register_drivers(struct usb_driver *udriver,
- struct usb_serial_driver * const serial_drivers[]);
-extern void usb_serial_deregister_drivers(struct usb_driver *udriver,
- struct usb_serial_driver * const serial_drivers[]);
+extern int usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers[],
+ const char *name, const struct usb_device_id *id_table);
+extern void usb_serial_deregister_drivers(struct usb_serial_driver *const serial_drivers[]);
extern void usb_serial_port_softint(struct usb_serial_port *port);
-extern int usb_serial_probe(struct usb_interface *iface,
- const struct usb_device_id *id);
-extern void usb_serial_disconnect(struct usb_interface *iface);
-
extern int usb_serial_suspend(struct usb_interface *intf, pm_message_t message);
extern int usb_serial_resume(struct usb_interface *intf);
@@ -400,8 +396,8 @@ do { \
/*
* module_usb_serial_driver() - Helper macro for registering a USB Serial driver
- * @__usb_driver: usb_driver struct to register
* @__serial_drivers: list of usb_serial drivers to register
+ * @__ids: all device ids that @__serial_drivers bind to
*
* Helper macro for USB serial drivers which do not do anything special
* in module init/exit. This eliminates a lot of boilerplate. Each
@@ -409,9 +405,21 @@ do { \
* module_init() and module_exit()
*
*/
-#define module_usb_serial_driver(__usb_driver, __serial_drivers) \
- module_driver(__usb_driver, usb_serial_register_drivers, \
- usb_serial_deregister_drivers, __serial_drivers)
+#define usb_serial_module_driver(__name, __serial_drivers, __ids) \
+static int __init usb_serial_module_init(void) \
+{ \
+ return usb_serial_register_drivers(__serial_drivers, \
+ __name, __ids); \
+} \
+module_init(usb_serial_module_init); \
+static void __exit usb_serial_module_exit(void) \
+{ \
+ usb_serial_deregister_drivers(__serial_drivers); \
+} \
+module_exit(usb_serial_module_exit);
+
+#define module_usb_serial_driver(__serial_drivers, __ids) \
+ usb_serial_module_driver(KBUILD_MODNAME, __serial_drivers, __ids)
#endif /* __LINUX_USB_SERIAL_H */
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
index faf467944baf..4e72922e5a75 100644
--- a/include/linux/user_namespace.h
+++ b/include/linux/user_namespace.h
@@ -6,14 +6,24 @@
#include <linux/sched.h>
#include <linux/err.h>
-#define UIDHASH_BITS (CONFIG_BASE_SMALL ? 3 : 7)
-#define UIDHASH_SZ (1 << UIDHASH_BITS)
+#define UID_GID_MAP_MAX_EXTENTS 5
+
+struct uid_gid_map { /* 64 bytes -- 1 cache line */
+ u32 nr_extents;
+ struct uid_gid_extent {
+ u32 first;
+ u32 lower_first;
+ u32 count;
+ } extent[UID_GID_MAP_MAX_EXTENTS];
+};
struct user_namespace {
+ struct uid_gid_map uid_map;
+ struct uid_gid_map gid_map;
struct kref kref;
- struct hlist_head uidhash_table[UIDHASH_SZ];
- struct user_struct *creator;
- struct work_struct destroyer;
+ struct user_namespace *parent;
+ kuid_t owner;
+ kgid_t group;
};
extern struct user_namespace init_user_ns;
@@ -36,9 +46,11 @@ static inline void put_user_ns(struct user_namespace *ns)
kref_put(&ns->kref, free_user_ns);
}
-uid_t user_ns_map_uid(struct user_namespace *to, const struct cred *cred, uid_t uid);
-gid_t user_ns_map_gid(struct user_namespace *to, const struct cred *cred, gid_t gid);
-
+struct seq_operations;
+extern struct seq_operations proc_uid_seq_operations;
+extern struct seq_operations proc_gid_seq_operations;
+extern ssize_t proc_uid_map_write(struct file *, const char __user *, size_t, loff_t *);
+extern ssize_t proc_gid_map_write(struct file *, const char __user *, size_t, loff_t *);
#else
static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
@@ -55,17 +67,6 @@ static inline void put_user_ns(struct user_namespace *ns)
{
}
-static inline uid_t user_ns_map_uid(struct user_namespace *to,
- const struct cred *cred, uid_t uid)
-{
- return uid;
-}
-static inline gid_t user_ns_map_gid(struct user_namespace *to,
- const struct cred *cred, gid_t gid)
-{
- return gid;
-}
-
#endif
#endif /* _LINUX_USER_H */
diff --git a/include/linux/uuid.h b/include/linux/uuid.h
index 5b7efbfcee4e..f86c37bfd4a0 100644
--- a/include/linux/uuid.h
+++ b/include/linux/uuid.h
@@ -54,6 +54,8 @@ typedef struct {
UUID_BE(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00)
+#ifdef __KERNEL__
+
static inline int uuid_le_cmp(const uuid_le u1, const uuid_le u2)
{
return memcmp(&u1, &u2, sizeof(uuid_le));
@@ -67,4 +69,6 @@ static inline int uuid_be_cmp(const uuid_be u1, const uuid_be u2)
extern void uuid_le_gen(uuid_le *u);
extern void uuid_be_gen(uuid_be *u);
+#endif /* __KERNEL__ */
+
#endif
diff --git a/include/linux/v4l2-dv-timings.h b/include/linux/v4l2-dv-timings.h
new file mode 100644
index 000000000000..9ef8172e5ed0
--- /dev/null
+++ b/include/linux/v4l2-dv-timings.h
@@ -0,0 +1,816 @@
+/*
+ * V4L2 DV timings header.
+ *
+ * Copyright (C) 2012 Hans Verkuil <hans.verkuil@cisco.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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef _V4L2_DV_TIMINGS_H
+#define _V4L2_DV_TIMINGS_H
+
+#if __GNUC__ < 4 || (__GNUC__ == 4 && (__GNUC_MINOR__ < 6))
+/* Sadly gcc versions older than 4.6 have a bug in how they initialize
+ anonymous unions where they require additional curly brackets.
+ This violates the C1x standard. This workaround adds the curly brackets
+ if needed. */
+#define V4L2_INIT_BT_TIMINGS(_width, args...) \
+ { .bt = { _width , ## args } }
+#else
+#define V4L2_INIT_BT_TIMINGS(_width, args...) \
+ .bt = { _width , ## args }
+#endif
+
+/* CEA-861-E timings (i.e. standard HDTV timings) */
+
+#define V4L2_DV_BT_CEA_640X480P59_94 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(640, 480, 0, 0, \
+ 25175000, 16, 96, 48, 10, 2, 33, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CEA861, 0) \
+}
+
+#define V4L2_DV_BT_CEA_720X480P59_94 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(720, 480, 0, 0, \
+ 27000000, 16, 62, 60, 9, 6, 30, 0, 0, 0, \
+ V4L2_DV_BT_STD_CEA861, 0) \
+}
+
+#define V4L2_DV_BT_CEA_720X576P50 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(720, 576, 0, 0, \
+ 27000000, 12, 64, 68, 5, 5, 39, 0, 0, 0, \
+ V4L2_DV_BT_STD_CEA861, 0) \
+}
+
+#define V4L2_DV_BT_CEA_1280X720P24 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1280, 720, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 59400000, 1760, 40, 220, 5, 5, 20, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CEA861, \
+ V4L2_DV_FL_CAN_REDUCE_FPS) \
+}
+
+#define V4L2_DV_BT_CEA_1280X720P25 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1280, 720, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 74250000, 2420, 40, 220, 5, 5, 20, 0, 0, 0, \
+ V4L2_DV_BT_STD_CEA861, 0) \
+}
+
+#define V4L2_DV_BT_CEA_1280X720P30 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1280, 720, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 74250000, 1760, 40, 220, 5, 5, 20, 0, 0, 0, \
+ V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \
+}
+
+#define V4L2_DV_BT_CEA_1280X720P50 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1280, 720, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 74250000, 440, 40, 220, 5, 5, 20, 0, 0, 0, \
+ V4L2_DV_BT_STD_CEA861, 0) \
+}
+
+#define V4L2_DV_BT_CEA_1280X720P60 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1280, 720, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 74250000, 110, 40, 220, 5, 5, 20, 0, 0, 0, \
+ V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \
+}
+
+#define V4L2_DV_BT_CEA_1920X1080P24 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1920, 1080, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 74250000, 638, 44, 148, 4, 5, 36, 0, 0, 0, \
+ V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \
+}
+
+#define V4L2_DV_BT_CEA_1920X1080P25 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1920, 1080, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 74250000, 528, 44, 148, 4, 5, 36, 0, 0, 0, \
+ V4L2_DV_BT_STD_CEA861, 0) \
+}
+
+#define V4L2_DV_BT_CEA_1920X1080P30 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1920, 1080, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 74250000, 88, 44, 148, 4, 5, 36, 0, 0, 0, \
+ V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_CAN_REDUCE_FPS) \
+}
+
+#define V4L2_DV_BT_CEA_1920X1080I50 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1920, 1080, 1, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 74250000, 528, 44, 148, 2, 5, 15, 2, 5, 16, \
+ V4L2_DV_BT_STD_CEA861, V4L2_DV_FL_HALF_LINE) \
+}
+
+#define V4L2_DV_BT_CEA_1920X1080P50 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1920, 1080, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 148500000, 528, 44, 148, 4, 5, 36, 0, 0, 0, \
+ V4L2_DV_BT_STD_CEA861, 0) \
+}
+
+#define V4L2_DV_BT_CEA_1920X1080I60 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1920, 1080, 1, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 74250000, 88, 44, 148, 2, 5, 15, 2, 5, 16, \
+ V4L2_DV_BT_STD_CEA861, \
+ V4L2_DV_FL_CAN_REDUCE_FPS | V4L2_DV_FL_HALF_LINE) \
+}
+
+#define V4L2_DV_BT_CEA_1920X1080P60 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1920, 1080, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 148500000, 88, 44, 148, 4, 5, 36, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CEA861, \
+ V4L2_DV_FL_CAN_REDUCE_FPS) \
+}
+
+
+/* VESA Discrete Monitor Timings as per version 1.0, revision 12 */
+
+#define V4L2_DV_BT_DMT_640X350P85 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(640, 350, 0, V4L2_DV_HSYNC_POS_POL, \
+ 31500000, 32, 64, 96, 32, 3, 60, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_640X400P85 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(640, 400, 0, V4L2_DV_VSYNC_POS_POL, \
+ 31500000, 32, 64, 96, 1, 3, 41, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_720X400P85 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(720, 400, 0, V4L2_DV_VSYNC_POS_POL, \
+ 35500000, 36, 72, 108, 1, 3, 42, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+/* VGA resolutions */
+#define V4L2_DV_BT_DMT_640X480P60 V4L2_DV_BT_CEA_640X480P59_94
+
+#define V4L2_DV_BT_DMT_640X480P72 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(640, 480, 0, 0, \
+ 31500000, 24, 40, 128, 9, 3, 28, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_640X480P75 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(640, 480, 0, 0, \
+ 31500000, 16, 64, 120, 1, 3, 16, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_640X480P85 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(640, 480, 0, 0, \
+ 36000000, 56, 56, 80, 1, 3, 25, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+/* SVGA resolutions */
+#define V4L2_DV_BT_DMT_800X600P56 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(800, 600, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 36000000, 24, 72, 128, 1, 2, 22, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_800X600P60 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(800, 600, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 40000000, 40, 128, 88, 1, 4, 23, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_800X600P72 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(800, 600, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 50000000, 56, 120, 64, 37, 6, 23, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_800X600P75 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(800, 600, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 49500000, 16, 80, 160, 1, 3, 21, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_800X600P85 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(800, 600, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 56250000, 32, 64, 152, 1, 3, 27, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_800X600P120_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(800, 600, 0, V4L2_DV_HSYNC_POS_POL, \
+ 73250000, 48, 32, 80, 3, 4, 29, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+ V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_848X480P60 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(848, 480, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 33750000, 16, 112, 112, 6, 8, 23, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1024X768I43 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1024, 768, 1, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 44900000, 8, 176, 56, 0, 4, 20, 0, 4, 21, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+/* XGA resolutions */
+#define V4L2_DV_BT_DMT_1024X768P60 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1024, 768, 0, 0, \
+ 65000000, 24, 136, 160, 3, 6, 29, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1024X768P70 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1024, 768, 0, 0, \
+ 75000000, 24, 136, 144, 3, 6, 29, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1024X768P75 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1024, 768, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 78750000, 16, 96, 176, 1, 3, 28, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1024X768P85 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1024, 768, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 94500000, 48, 96, 208, 1, 3, 36, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1024X768P120_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1024, 768, 0, V4L2_DV_HSYNC_POS_POL, \
+ 115500000, 48, 32, 80, 3, 4, 38, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+ V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+/* XGA+ resolution */
+#define V4L2_DV_BT_DMT_1152X864P75 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1152, 864, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 108000000, 64, 128, 256, 1, 3, 32, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X720P60 V4L2_DV_BT_CEA_1280X720P60
+
+/* WXGA resolutions */
+#define V4L2_DV_BT_DMT_1280X768P60_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1280, 768, 0, V4L2_DV_HSYNC_POS_POL, \
+ 68250000, 48, 32, 80, 3, 7, 12, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+ V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1280X768P60 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1280, 768, 0, V4L2_DV_VSYNC_POS_POL, \
+ 79500000, 64, 128, 192, 3, 7, 20, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X768P75 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1280, 768, 0, V4L2_DV_VSYNC_POS_POL, \
+ 102250000, 80, 128, 208, 3, 7, 27, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X768P85 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1280, 768, 0, V4L2_DV_VSYNC_POS_POL, \
+ 117500000, 80, 136, 216, 3, 7, 31, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X768P120_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1280, 768, 0, V4L2_DV_HSYNC_POS_POL, \
+ 140250000, 48, 32, 80, 3, 7, 35, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+ V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1280X800P60_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1280, 800, 0, V4L2_DV_HSYNC_POS_POL, \
+ 71000000, 48, 32, 80, 3, 6, 14, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+ V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1280X800P60 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1280, 800, 0, V4L2_DV_VSYNC_POS_POL, \
+ 83500000, 72, 128, 200, 3, 6, 22, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X800P75 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1280, 800, 0, V4L2_DV_VSYNC_POS_POL, \
+ 106500000, 80, 128, 208, 3, 6, 29, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X800P85 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1280, 800, 0, V4L2_DV_VSYNC_POS_POL, \
+ 122500000, 80, 136, 216, 3, 6, 34, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X800P120_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1280, 800, 0, V4L2_DV_HSYNC_POS_POL, \
+ 146250000, 48, 32, 80, 3, 6, 38, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+ V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1280X960P60 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1280, 960, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 108000000, 96, 112, 312, 1, 3, 36, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X960P85 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1280, 960, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 148500000, 64, 160, 224, 1, 3, 47, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X960P120_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1280, 960, 0, V4L2_DV_HSYNC_POS_POL, \
+ 175500000, 48, 32, 80, 3, 4, 50, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+ V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+/* SXGA resolutions */
+#define V4L2_DV_BT_DMT_1280X1024P60 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1280, 1024, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 108000000, 48, 112, 248, 1, 3, 38, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X1024P75 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1280, 1024, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 135000000, 16, 144, 248, 1, 3, 38, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X1024P85 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1280, 1024, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 157500000, 64, 160, 224, 1, 3, 44, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1280X1024P120_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1280, 1024, 0, V4L2_DV_HSYNC_POS_POL, \
+ 187250000, 48, 32, 80, 3, 7, 50, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+ V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1360X768P60 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1360, 768, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 85500000, 64, 112, 256, 3, 6, 18, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1360X768P120_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1360, 768, 0, V4L2_DV_HSYNC_POS_POL, \
+ 148250000, 48, 32, 80, 3, 5, 37, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+ V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1366X768P60 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1366, 768, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 85500000, 70, 143, 213, 3, 3, 24, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1366X768P60_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1366, 768, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 72000000, 14, 56, 64, 1, 3, 28, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+/* SXGA+ resolutions */
+#define V4L2_DV_BT_DMT_1400X1050P60_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1400, 1050, 0, V4L2_DV_HSYNC_POS_POL, \
+ 101000000, 48, 32, 80, 3, 4, 23, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+ V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1400X1050P60 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1400, 1050, 0, V4L2_DV_VSYNC_POS_POL, \
+ 121750000, 88, 144, 232, 3, 4, 32, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1400X1050P75 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1400, 1050, 0, V4L2_DV_VSYNC_POS_POL, \
+ 156000000, 104, 144, 248, 3, 4, 42, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1400X1050P85 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1400, 1050, 0, V4L2_DV_VSYNC_POS_POL, \
+ 179500000, 104, 152, 256, 3, 4, 48, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1400X1050P120_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1400, 1050, 0, V4L2_DV_HSYNC_POS_POL, \
+ 208000000, 48, 32, 80, 3, 4, 55, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+ V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+/* WXGA+ resolutions */
+#define V4L2_DV_BT_DMT_1440X900P60_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1440, 900, 0, V4L2_DV_HSYNC_POS_POL, \
+ 88750000, 48, 32, 80, 3, 6, 17, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+ V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1440X900P60 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1440, 900, 0, V4L2_DV_VSYNC_POS_POL, \
+ 106500000, 80, 152, 232, 3, 6, 25, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1440X900P75 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1440, 900, 0, V4L2_DV_VSYNC_POS_POL, \
+ 136750000, 96, 152, 248, 3, 6, 33, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1440X900P85 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1440, 900, 0, V4L2_DV_VSYNC_POS_POL, \
+ 157000000, 104, 152, 256, 3, 6, 39, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1440X900P120_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1440, 900, 0, V4L2_DV_HSYNC_POS_POL, \
+ 182750000, 48, 32, 80, 3, 6, 44, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+ V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1600X900P60_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1600, 900, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 108000000, 24, 80, 96, 1, 3, 96, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+/* UXGA resolutions */
+#define V4L2_DV_BT_DMT_1600X1200P60 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1600, 1200, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 162000000, 64, 192, 304, 1, 3, 46, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1600X1200P65 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1600, 1200, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 175500000, 64, 192, 304, 1, 3, 46, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1600X1200P70 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1600, 1200, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 189000000, 64, 192, 304, 1, 3, 46, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1600X1200P75 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1600, 1200, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 202500000, 64, 192, 304, 1, 3, 46, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1600X1200P85 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1600, 1200, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 229500000, 64, 192, 304, 1, 3, 46, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1600X1200P120_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1600, 1200, 0, V4L2_DV_HSYNC_POS_POL, \
+ 268250000, 48, 32, 80, 3, 4, 64, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+ V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+/* WSXGA+ resolutions */
+#define V4L2_DV_BT_DMT_1680X1050P60_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1680, 1050, 0, V4L2_DV_HSYNC_POS_POL, \
+ 119000000, 48, 32, 80, 3, 6, 21, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+ V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1680X1050P60 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1680, 1050, 0, V4L2_DV_VSYNC_POS_POL, \
+ 146250000, 104, 176, 280, 3, 6, 30, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1680X1050P75 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1680, 1050, 0, V4L2_DV_VSYNC_POS_POL, \
+ 187000000, 120, 176, 296, 3, 6, 40, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1680X1050P85 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1680, 1050, 0, V4L2_DV_VSYNC_POS_POL, \
+ 214750000, 128, 176, 304, 3, 6, 46, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1680X1050P120_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1680, 1050, 0, V4L2_DV_HSYNC_POS_POL, \
+ 245500000, 48, 32, 80, 3, 6, 53, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+ V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1792X1344P60 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1792, 1344, 0, V4L2_DV_VSYNC_POS_POL, \
+ 204750000, 128, 200, 328, 1, 3, 46, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1792X1344P75 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1792, 1344, 0, V4L2_DV_VSYNC_POS_POL, \
+ 261000000, 96, 216, 352, 1, 3, 69, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1792X1344P120_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1792, 1344, 0, V4L2_DV_HSYNC_POS_POL, \
+ 333250000, 48, 32, 80, 3, 4, 72, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+ V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1856X1392P60 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1856, 1392, 0, V4L2_DV_VSYNC_POS_POL, \
+ 218250000, 96, 224, 352, 1, 3, 43, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1856X1392P75 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1856, 1392, 0, V4L2_DV_VSYNC_POS_POL, \
+ 288000000, 128, 224, 352, 1, 3, 104, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1856X1392P120_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1856, 1392, 0, V4L2_DV_HSYNC_POS_POL, \
+ 356500000, 48, 32, 80, 3, 4, 75, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+ V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1920X1080P60 V4L2_DV_BT_CEA_1920X1080P60
+
+/* WUXGA resolutions */
+#define V4L2_DV_BT_DMT_1920X1200P60_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1920, 1200, 0, V4L2_DV_HSYNC_POS_POL, \
+ 154000000, 48, 32, 80, 3, 6, 26, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+ V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1920X1200P60 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1920, 1200, 0, V4L2_DV_VSYNC_POS_POL, \
+ 193250000, 136, 200, 336, 3, 6, 36, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1920X1200P75 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1920, 1200, 0, V4L2_DV_VSYNC_POS_POL, \
+ 245250000, 136, 208, 344, 3, 6, 46, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1920X1200P85 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1920, 1200, 0, V4L2_DV_VSYNC_POS_POL, \
+ 281250000, 144, 208, 352, 3, 6, 53, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1920X1200P120_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1920, 1200, 0, V4L2_DV_HSYNC_POS_POL, \
+ 317000000, 48, 32, 80, 3, 6, 62, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+ V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1920X1440P60 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1920, 1440, 0, V4L2_DV_VSYNC_POS_POL, \
+ 234000000, 128, 208, 344, 1, 3, 56, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1920X1440P75 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1920, 1440, 0, V4L2_DV_VSYNC_POS_POL, \
+ 297000000, 144, 224, 352, 1, 3, 56, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_1920X1440P120_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1920, 1440, 0, V4L2_DV_HSYNC_POS_POL, \
+ 380500000, 48, 32, 80, 3, 4, 78, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+ V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_2048X1152P60_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(2048, 1152, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 162000000, 26, 80, 96, 1, 3, 44, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+/* WQXGA resolutions */
+#define V4L2_DV_BT_DMT_2560X1600P60_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(2560, 1600, 0, V4L2_DV_HSYNC_POS_POL, \
+ 268500000, 48, 32, 80, 3, 6, 37, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+ V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_2560X1600P60 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(2560, 1600, 0, V4L2_DV_VSYNC_POS_POL, \
+ 348500000, 192, 280, 472, 3, 6, 49, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_2560X1600P75 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(2560, 1600, 0, V4L2_DV_VSYNC_POS_POL, \
+ 443250000, 208, 280, 488, 3, 6, 63, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_2560X1600P85 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(2560, 1600, 0, V4L2_DV_VSYNC_POS_POL, \
+ 505250000, 208, 280, 488, 3, 6, 73, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_DMT_2560X1600P120_RB { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(2560, 1600, 0, V4L2_DV_HSYNC_POS_POL, \
+ 552750000, 48, 32, 80, 3, 6, 85, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+ V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_DMT_1366X768P60 { \
+ .type = V4L2_DV_BT_656_1120, \
+ V4L2_INIT_BT_TIMINGS(1366, 768, 0, \
+ V4L2_DV_HSYNC_POS_POL | V4L2_DV_VSYNC_POS_POL, \
+ 85500000, 70, 143, 213, 3, 3, 24, 0, 0, 0, \
+ V4L2_DV_BT_STD_DMT, 0) \
+}
+
+#endif
diff --git a/include/linux/v4l2-subdev.h b/include/linux/v4l2-subdev.h
index ed29cbbebfef..812019ee1e06 100644
--- a/include/linux/v4l2-subdev.h
+++ b/include/linux/v4l2-subdev.h
@@ -123,6 +123,43 @@ struct v4l2_subdev_frame_interval_enum {
__u32 reserved[9];
};
+#define V4L2_SUBDEV_SEL_FLAG_SIZE_GE (1 << 0)
+#define V4L2_SUBDEV_SEL_FLAG_SIZE_LE (1 << 1)
+#define V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG (1 << 2)
+
+/* active cropping area */
+#define V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL 0x0000
+/* cropping bounds */
+#define V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS 0x0002
+/* current composing area */
+#define V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL 0x0100
+/* composing bounds */
+#define V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS 0x0102
+
+
+/**
+ * struct v4l2_subdev_selection - selection info
+ *
+ * @which: either V4L2_SUBDEV_FORMAT_ACTIVE or V4L2_SUBDEV_FORMAT_TRY
+ * @pad: pad number, as reported by the media API
+ * @target: selection target, used to choose one of possible rectangles
+ * @flags: constraint flags
+ * @r: coordinates of the selection window
+ * @reserved: for future use, set to zero for now
+ *
+ * Hardware may use multiple helper windows to process a video stream.
+ * The structure is used to exchange this selection areas between
+ * an application and a driver.
+ */
+struct v4l2_subdev_selection {
+ __u32 which;
+ __u32 pad;
+ __u32 target;
+ __u32 flags;
+ struct v4l2_rect r;
+ __u32 reserved[8];
+};
+
#define VIDIOC_SUBDEV_G_FMT _IOWR('V', 4, struct v4l2_subdev_format)
#define VIDIOC_SUBDEV_S_FMT _IOWR('V', 5, struct v4l2_subdev_format)
#define VIDIOC_SUBDEV_G_FRAME_INTERVAL \
@@ -137,5 +174,9 @@ struct v4l2_subdev_frame_interval_enum {
_IOWR('V', 75, struct v4l2_subdev_frame_interval_enum)
#define VIDIOC_SUBDEV_G_CROP _IOWR('V', 59, struct v4l2_subdev_crop)
#define VIDIOC_SUBDEV_S_CROP _IOWR('V', 60, struct v4l2_subdev_crop)
+#define VIDIOC_SUBDEV_G_SELECTION \
+ _IOWR('V', 61, struct v4l2_subdev_selection)
+#define VIDIOC_SUBDEV_S_SELECTION \
+ _IOWR('V', 62, struct v4l2_subdev_selection)
#endif
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index 4b9a7f596f92..b455c7c212eb 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -28,13 +28,19 @@ struct vga_switcheroo_handler {
int (*get_client_id)(struct pci_dev *pdev);
};
+struct vga_switcheroo_client_ops {
+ void (*set_gpu_state)(struct pci_dev *dev, enum vga_switcheroo_state);
+ void (*reprobe)(struct pci_dev *dev);
+ bool (*can_switch)(struct pci_dev *dev);
+};
#if defined(CONFIG_VGA_SWITCHEROO)
void vga_switcheroo_unregister_client(struct pci_dev *dev);
int vga_switcheroo_register_client(struct pci_dev *dev,
- void (*set_gpu_state)(struct pci_dev *dev, enum vga_switcheroo_state),
- void (*reprobe)(struct pci_dev *dev),
- bool (*can_switch)(struct pci_dev *dev));
+ const struct vga_switcheroo_client_ops *ops);
+int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
+ const struct vga_switcheroo_client_ops *ops,
+ int id, bool active);
void vga_switcheroo_client_fb_set(struct pci_dev *dev,
struct fb_info *info);
@@ -48,11 +54,12 @@ int vga_switcheroo_process_delayed_switch(void);
static inline void vga_switcheroo_unregister_client(struct pci_dev *dev) {}
static inline int vga_switcheroo_register_client(struct pci_dev *dev,
- void (*set_gpu_state)(struct pci_dev *dev, enum vga_switcheroo_state),
- void (*reprobe)(struct pci_dev *dev),
- bool (*can_switch)(struct pci_dev *dev)) { return 0; }
+ const struct vga_switcheroo_client_ops *ops) { return 0; }
static inline void vga_switcheroo_client_fb_set(struct pci_dev *dev, struct fb_info *info) {}
static inline int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler) { return 0; }
+static inline int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
+ const struct vga_switcheroo_client_ops *ops,
+ int id, bool active) { return 0; }
static inline void vga_switcheroo_unregister_handler(void) {}
static inline int vga_switcheroo_process_delayed_switch(void) { return 0; }
diff --git a/include/linux/vgaarb.h b/include/linux/vgaarb.h
index b572f80bdfd5..0ee42d9acdc0 100644
--- a/include/linux/vgaarb.h
+++ b/include/linux/vgaarb.h
@@ -31,6 +31,7 @@
#ifndef LINUX_VGA_H
#define LINUX_VGA_H
+#include <video/vga.h>
/* Legacy VGA regions */
#define VGA_RSRC_NONE 0x00
@@ -182,7 +183,13 @@ extern void vga_put(struct pci_dev *pdev, unsigned int rsrc);
*/
#ifndef __ARCH_HAS_VGA_DEFAULT_DEVICE
+#ifdef CONFIG_VGA_ARB
extern struct pci_dev *vga_default_device(void);
+extern void vga_set_default_device(struct pci_dev *pdev);
+#else
+static inline struct pci_dev *vga_default_device(void) { return NULL; };
+static inline void vga_set_default_device(struct pci_dev *pdev) { };
+#endif
#endif
/**
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index c9c9a4680cc5..370d11106c11 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -292,10 +292,10 @@ struct v4l2_pix_format {
__u32 width;
__u32 height;
__u32 pixelformat;
- enum v4l2_field field;
+ __u32 field; /* enum v4l2_field */
__u32 bytesperline; /* for padding, zero if unused */
__u32 sizeimage;
- enum v4l2_colorspace colorspace;
+ __u32 colorspace; /* enum v4l2_colorspace */
__u32 priv; /* private data, depends on pixelformat */
};
@@ -378,7 +378,10 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_SGRBG12 v4l2_fourcc('B', 'A', '1', '2') /* 12 GRGR.. BGBG.. */
#define V4L2_PIX_FMT_SRGGB12 v4l2_fourcc('R', 'G', '1', '2') /* 12 RGRG.. GBGB.. */
/* 10bit raw bayer DPCM compressed to 8 bits */
+#define V4L2_PIX_FMT_SBGGR10DPCM8 v4l2_fourcc('b', 'B', 'A', '8')
+#define V4L2_PIX_FMT_SGBRG10DPCM8 v4l2_fourcc('b', 'G', 'A', '8')
#define V4L2_PIX_FMT_SGRBG10DPCM8 v4l2_fourcc('B', 'D', '1', '0')
+#define V4L2_PIX_FMT_SRGGB10DPCM8 v4l2_fourcc('b', 'R', 'A', '8')
/*
* 10bit raw bayer, expanded to 16 bits
* xxxxrrrrrrrrrrxxxxgggggggggg xxxxggggggggggxxxxbbbbbbbbbb...
@@ -432,7 +435,7 @@ struct v4l2_pix_format {
*/
struct v4l2_fmtdesc {
__u32 index; /* Format number */
- enum v4l2_buf_type type; /* buffer type */
+ __u32 type; /* enum v4l2_buf_type */
__u32 flags;
__u8 description[32]; /* Description string */
__u32 pixelformat; /* Format fourcc */
@@ -573,8 +576,8 @@ struct v4l2_jpegcompression {
*/
struct v4l2_requestbuffers {
__u32 count;
- enum v4l2_buf_type type;
- enum v4l2_memory memory;
+ __u32 type; /* enum v4l2_buf_type */
+ __u32 memory; /* enum v4l2_memory */
__u32 reserved[2];
};
@@ -610,15 +613,17 @@ struct v4l2_plane {
/**
* struct v4l2_buffer - video buffer info
* @index: id number of the buffer
- * @type: buffer type (type == *_MPLANE for multiplanar buffers)
+ * @type: enum v4l2_buf_type; buffer type (type == *_MPLANE for
+ * multiplanar buffers);
* @bytesused: number of bytes occupied by data in the buffer (payload);
* unused (set to 0) for multiplanar buffers
* @flags: buffer informational flags
- * @field: field order of the image in the buffer
+ * @field: enum v4l2_field; field order of the image in the buffer
* @timestamp: frame timestamp
* @timecode: frame timecode
* @sequence: sequence count of this frame
- * @memory: the method, in which the actual video data is passed
+ * @memory: enum v4l2_memory; the method, in which the actual video data is
+ * passed
* @offset: for non-multiplanar buffers with memory == V4L2_MEMORY_MMAP;
* offset from the start of the device memory for this plane,
* (or a "cookie" that should be passed to mmap() as offset)
@@ -636,16 +641,16 @@ struct v4l2_plane {
*/
struct v4l2_buffer {
__u32 index;
- enum v4l2_buf_type type;
+ __u32 type;
__u32 bytesused;
__u32 flags;
- enum v4l2_field field;
+ __u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
/* memory location */
- enum v4l2_memory memory;
+ __u32 memory;
union {
__u32 offset;
unsigned long userptr;
@@ -708,7 +713,7 @@ struct v4l2_clip {
struct v4l2_window {
struct v4l2_rect w;
- enum v4l2_field field;
+ __u32 field; /* enum v4l2_field */
__u32 chromakey;
struct v4l2_clip __user *clips;
__u32 clipcount;
@@ -745,14 +750,14 @@ struct v4l2_outputparm {
* I N P U T I M A G E C R O P P I N G
*/
struct v4l2_cropcap {
- enum v4l2_buf_type type;
+ __u32 type; /* enum v4l2_buf_type */
struct v4l2_rect bounds;
struct v4l2_rect defrect;
struct v4l2_fract pixelaspect;
};
struct v4l2_crop {
- enum v4l2_buf_type type;
+ __u32 type; /* enum v4l2_buf_type */
struct v4l2_rect c;
};
@@ -939,6 +944,9 @@ struct v4l2_standard {
__u32 reserved[4];
};
+/* The DV Preset API is deprecated in favor of the DV Timings API.
+ New drivers shouldn't use this anymore! */
+
/*
* V I D E O T I M I N G S D V P R E S E T
*/
@@ -986,29 +994,56 @@ struct v4l2_dv_enum_preset {
* D V B T T I M I N G S
*/
-/* BT.656/BT.1120 timing data */
+/** struct v4l2_bt_timings - BT.656/BT.1120 timing data
+ * @width: total width of the active video in pixels
+ * @height: total height of the active video in lines
+ * @interlaced: Interlaced or progressive
+ * @polarities: Positive or negative polarities
+ * @pixelclock: Pixel clock in HZ. Ex. 74.25MHz->74250000
+ * @hfrontporch:Horizontal front porch in pixels
+ * @hsync: Horizontal Sync length in pixels
+ * @hbackporch: Horizontal back porch in pixels
+ * @vfrontporch:Vertical front porch in lines
+ * @vsync: Vertical Sync length in lines
+ * @vbackporch: Vertical back porch in lines
+ * @il_vfrontporch:Vertical front porch for the even field
+ * (aka field 2) of interlaced field formats
+ * @il_vsync: Vertical Sync length for the even field
+ * (aka field 2) of interlaced field formats
+ * @il_vbackporch:Vertical back porch for the even field
+ * (aka field 2) of interlaced field formats
+ * @standards: Standards the timing belongs to
+ * @flags: Flags
+ * @reserved: Reserved fields, must be zeroed.
+ *
+ * A note regarding vertical interlaced timings: height refers to the total
+ * height of the active video frame (= two fields). The blanking timings refer
+ * to the blanking of each field. So the height of the total frame is
+ * calculated as follows:
+ *
+ * tot_height = height + vfrontporch + vsync + vbackporch +
+ * il_vfrontporch + il_vsync + il_vbackporch
+ *
+ * The active height of each field is height / 2.
+ */
struct v4l2_bt_timings {
- __u32 width; /* width in pixels */
- __u32 height; /* height in lines */
- __u32 interlaced; /* Interlaced or progressive */
- __u32 polarities; /* Positive or negative polarity */
- __u64 pixelclock; /* Pixel clock in HZ. Ex. 74.25MHz->74250000 */
- __u32 hfrontporch; /* Horizpontal front porch in pixels */
- __u32 hsync; /* Horizontal Sync length in pixels */
- __u32 hbackporch; /* Horizontal back porch in pixels */
- __u32 vfrontporch; /* Vertical front porch in pixels */
- __u32 vsync; /* Vertical Sync length in lines */
- __u32 vbackporch; /* Vertical back porch in lines */
- __u32 il_vfrontporch; /* Vertical front porch for bottom field of
- * interlaced field formats
- */
- __u32 il_vsync; /* Vertical sync length for bottom field of
- * interlaced field formats
- */
- __u32 il_vbackporch; /* Vertical back porch for bottom field of
- * interlaced field formats
- */
- __u32 reserved[16];
+ __u32 width;
+ __u32 height;
+ __u32 interlaced;
+ __u32 polarities;
+ __u64 pixelclock;
+ __u32 hfrontporch;
+ __u32 hsync;
+ __u32 hbackporch;
+ __u32 vfrontporch;
+ __u32 vsync;
+ __u32 vbackporch;
+ __u32 il_vfrontporch;
+ __u32 il_vsync;
+ __u32 il_vbackporch;
+ __u32 standards;
+ __u32 flags;
+ __u32 reserved[14];
} __attribute__ ((packed));
/* Interlaced or progressive format */
@@ -1019,8 +1054,42 @@ struct v4l2_bt_timings {
#define V4L2_DV_VSYNC_POS_POL 0x00000001
#define V4L2_DV_HSYNC_POS_POL 0x00000002
-
-/* DV timings */
+/* Timings standards */
+#define V4L2_DV_BT_STD_CEA861 (1 << 0) /* CEA-861 Digital TV Profile */
+#define V4L2_DV_BT_STD_DMT (1 << 1) /* VESA Discrete Monitor Timings */
+#define V4L2_DV_BT_STD_CVT (1 << 2) /* VESA Coordinated Video Timings */
+#define V4L2_DV_BT_STD_GTF (1 << 3) /* VESA Generalized Timings Formula */
+
+/* Flags */
+
+/* CVT/GTF specific: timing uses reduced blanking (CVT) or the 'Secondary
+ GTF' curve (GTF). In both cases the horizontal and/or vertical blanking
+ intervals are reduced, allowing a higher resolution over the same
+ bandwidth. This is a read-only flag. */
+#define V4L2_DV_FL_REDUCED_BLANKING (1 << 0)
+/* CEA-861 specific: set for CEA-861 formats with a framerate of a multiple
+ of six. These formats can be optionally played at 1 / 1.001 speed.
+ This is a read-only flag. */
+#define V4L2_DV_FL_CAN_REDUCE_FPS (1 << 1)
+/* CEA-861 specific: only valid for video transmitters, the flag is cleared
+ by receivers.
+ If the framerate of the format is a multiple of six, then the pixelclock
+ used to set up the transmitter is divided by 1.001 to make it compatible
+ with 60 Hz based standards such as NTSC and PAL-M that use a framerate of
+ 29.97 Hz. Otherwise this flag is cleared. If the transmitter can't generate
+ such frequencies, then the flag will also be cleared. */
+#define V4L2_DV_FL_REDUCED_FPS (1 << 2)
+/* Specific to interlaced formats: if set, then field 1 is really one half-line
+ longer and field 2 is really one half-line shorter, so each field has
+ exactly the same number of half-lines. Whether half-lines can be detected
+ or used depends on the hardware. */
+#define V4L2_DV_FL_HALF_LINE (1 << 0)
+
+
+/** struct v4l2_dv_timings - DV timings
+ * @type: the type of the timings
+ * @bt: BT656/1120 timings
+ */
struct v4l2_dv_timings {
__u32 type;
union {
@@ -1032,6 +1101,64 @@ struct v4l2_dv_timings {
/* Values for the type field */
#define V4L2_DV_BT_656_1120 0 /* BT.656/1120 timing type */
+
+/** struct v4l2_enum_dv_timings - DV timings enumeration
+ * @index: enumeration index
+ * @reserved: must be zeroed
+ * @timings: the timings for the given index
+ */
+struct v4l2_enum_dv_timings {
+ __u32 index;
+ __u32 reserved[3];
+ struct v4l2_dv_timings timings;
+};
+
+/** struct v4l2_bt_timings_cap - BT.656/BT.1120 timing capabilities
+ * @min_width: width in pixels
+ * @max_width: width in pixels
+ * @min_height: height in lines
+ * @max_height: height in lines
+ * @min_pixelclock: Pixel clock in HZ. Ex. 74.25MHz->74250000
+ * @max_pixelclock: Pixel clock in HZ. Ex. 74.25MHz->74250000
+ * @standards: Supported standards
+ * @capabilities: Supported capabilities
+ * @reserved: Must be zeroed
+ */
+struct v4l2_bt_timings_cap {
+ __u32 min_width;
+ __u32 max_width;
+ __u32 min_height;
+ __u32 max_height;
+ __u64 min_pixelclock;
+ __u64 max_pixelclock;
+ __u32 standards;
+ __u32 capabilities;
+ __u32 reserved[16];
+} __attribute__ ((packed));
+
+/* Supports interlaced formats */
+#define V4L2_DV_BT_CAP_INTERLACED (1 << 0)
+/* Supports progressive formats */
+#define V4L2_DV_BT_CAP_PROGRESSIVE (1 << 1)
+/* Supports CVT/GTF reduced blanking */
+#define V4L2_DV_BT_CAP_REDUCED_BLANKING (1 << 2)
+/* Supports custom formats */
+#define V4L2_DV_BT_CAP_CUSTOM (1 << 3)
+
+/** struct v4l2_dv_timings_cap - DV timings capabilities
+ * @type: the type of the timings (same as in struct v4l2_dv_timings)
+ * @bt: the BT656/1120 timings capabilities
+ */
+struct v4l2_dv_timings_cap {
+ __u32 type;
+ __u32 reserved[3];
+ union {
+ struct v4l2_bt_timings_cap bt;
+ __u32 raw_data[32];
+ };
+};
+
+
/*
* V I D E O I N P U T S
*/
@@ -1040,7 +1167,7 @@ struct v4l2_input {
__u8 name[32]; /* Label */
__u32 type; /* Type of input */
__u32 audioset; /* Associated audios (bitfield) */
- __u32 tuner; /* Associated tuner */
+ __u32 tuner; /* enum v4l2_tuner_type */
v4l2_std_id std;
__u32 status;
__u32 capabilities;
@@ -1137,6 +1264,8 @@ struct v4l2_ext_controls {
#define V4L2_CTRL_CLASS_FM_TX 0x009b0000 /* FM Modulator control class */
#define V4L2_CTRL_CLASS_FLASH 0x009c0000 /* Camera flash controls */
#define V4L2_CTRL_CLASS_JPEG 0x009d0000 /* JPEG-compression controls */
+#define V4L2_CTRL_CLASS_IMAGE_SOURCE 0x009e0000 /* Image source controls */
+#define V4L2_CTRL_CLASS_IMAGE_PROC 0x009f0000 /* Image processing controls */
#define V4L2_CTRL_ID_MASK (0x0fffffff)
#define V4L2_CTRL_ID2CLASS(id) ((id) & 0x0fff0000UL)
@@ -1151,12 +1280,13 @@ enum v4l2_ctrl_type {
V4L2_CTRL_TYPE_CTRL_CLASS = 6,
V4L2_CTRL_TYPE_STRING = 7,
V4L2_CTRL_TYPE_BITMASK = 8,
+ V4L2_CTRL_TYPE_INTEGER_MENU = 9,
};
/* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
struct v4l2_queryctrl {
__u32 id;
- enum v4l2_ctrl_type type;
+ __u32 type; /* enum v4l2_ctrl_type */
__u8 name[32]; /* Whatever */
__s32 minimum; /* Note signedness */
__s32 maximum;
@@ -1170,9 +1300,12 @@ struct v4l2_queryctrl {
struct v4l2_querymenu {
__u32 id;
__u32 index;
- __u8 name[32]; /* Whatever */
+ union {
+ __u8 name[32]; /* Whatever */
+ __s64 value;
+ };
__u32 reserved;
-};
+} __attribute__ ((packed));
/* Control flags */
#define V4L2_CTRL_FLAG_DISABLED 0x0001
@@ -1237,16 +1370,22 @@ enum v4l2_power_line_frequency {
#define V4L2_CID_COLOR_KILLER (V4L2_CID_BASE+30)
#define V4L2_CID_COLORFX (V4L2_CID_BASE+31)
enum v4l2_colorfx {
- V4L2_COLORFX_NONE = 0,
- V4L2_COLORFX_BW = 1,
- V4L2_COLORFX_SEPIA = 2,
- V4L2_COLORFX_NEGATIVE = 3,
- V4L2_COLORFX_EMBOSS = 4,
- V4L2_COLORFX_SKETCH = 5,
- V4L2_COLORFX_SKY_BLUE = 6,
- V4L2_COLORFX_GRASS_GREEN = 7,
- V4L2_COLORFX_SKIN_WHITEN = 8,
- V4L2_COLORFX_VIVID = 9,
+ V4L2_COLORFX_NONE = 0,
+ V4L2_COLORFX_BW = 1,
+ V4L2_COLORFX_SEPIA = 2,
+ V4L2_COLORFX_NEGATIVE = 3,
+ V4L2_COLORFX_EMBOSS = 4,
+ V4L2_COLORFX_SKETCH = 5,
+ V4L2_COLORFX_SKY_BLUE = 6,
+ V4L2_COLORFX_GRASS_GREEN = 7,
+ V4L2_COLORFX_SKIN_WHITEN = 8,
+ V4L2_COLORFX_VIVID = 9,
+ V4L2_COLORFX_AQUA = 10,
+ V4L2_COLORFX_ART_FREEZE = 11,
+ V4L2_COLORFX_SILHOUETTE = 12,
+ V4L2_COLORFX_SOLARIZATION = 13,
+ V4L2_COLORFX_ANTIQUE = 14,
+ V4L2_COLORFX_SET_CBCR = 15,
};
#define V4L2_CID_AUTOBRIGHTNESS (V4L2_CID_BASE+32)
#define V4L2_CID_BAND_STOP_FILTER (V4L2_CID_BASE+33)
@@ -1263,9 +1402,10 @@ enum v4l2_colorfx {
#define V4L2_CID_MIN_BUFFERS_FOR_OUTPUT (V4L2_CID_BASE+40)
#define V4L2_CID_ALPHA_COMPONENT (V4L2_CID_BASE+41)
+#define V4L2_CID_COLORFX_CBCR (V4L2_CID_BASE+42)
/* last CID + 1 */
-#define V4L2_CID_LASTP1 (V4L2_CID_BASE+42)
+#define V4L2_CID_LASTP1 (V4L2_CID_BASE+43)
/* MPEG-class control IDs defined by V4L2 */
#define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900)
@@ -1689,6 +1829,78 @@ enum v4l2_exposure_auto_type {
#define V4L2_CID_IRIS_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+17)
#define V4L2_CID_IRIS_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+18)
+#define V4L2_CID_AUTO_EXPOSURE_BIAS (V4L2_CID_CAMERA_CLASS_BASE+19)
+
+#define V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE (V4L2_CID_CAMERA_CLASS_BASE+20)
+enum v4l2_auto_n_preset_white_balance {
+ V4L2_WHITE_BALANCE_MANUAL = 0,
+ V4L2_WHITE_BALANCE_AUTO = 1,
+ V4L2_WHITE_BALANCE_INCANDESCENT = 2,
+ V4L2_WHITE_BALANCE_FLUORESCENT = 3,
+ V4L2_WHITE_BALANCE_FLUORESCENT_H = 4,
+ V4L2_WHITE_BALANCE_HORIZON = 5,
+ V4L2_WHITE_BALANCE_DAYLIGHT = 6,
+ V4L2_WHITE_BALANCE_FLASH = 7,
+ V4L2_WHITE_BALANCE_CLOUDY = 8,
+ V4L2_WHITE_BALANCE_SHADE = 9,
+};
+
+#define V4L2_CID_WIDE_DYNAMIC_RANGE (V4L2_CID_CAMERA_CLASS_BASE+21)
+#define V4L2_CID_IMAGE_STABILIZATION (V4L2_CID_CAMERA_CLASS_BASE+22)
+
+#define V4L2_CID_ISO_SENSITIVITY (V4L2_CID_CAMERA_CLASS_BASE+23)
+#define V4L2_CID_ISO_SENSITIVITY_AUTO (V4L2_CID_CAMERA_CLASS_BASE+24)
+enum v4l2_iso_sensitivity_auto_type {
+ V4L2_ISO_SENSITIVITY_MANUAL = 0,
+ V4L2_ISO_SENSITIVITY_AUTO = 1,
+};
+
+#define V4L2_CID_EXPOSURE_METERING (V4L2_CID_CAMERA_CLASS_BASE+25)
+enum v4l2_exposure_metering {
+ V4L2_EXPOSURE_METERING_AVERAGE = 0,
+ V4L2_EXPOSURE_METERING_CENTER_WEIGHTED = 1,
+ V4L2_EXPOSURE_METERING_SPOT = 2,
+};
+
+#define V4L2_CID_SCENE_MODE (V4L2_CID_CAMERA_CLASS_BASE+26)
+enum v4l2_scene_mode {
+ V4L2_SCENE_MODE_NONE = 0,
+ V4L2_SCENE_MODE_BACKLIGHT = 1,
+ V4L2_SCENE_MODE_BEACH_SNOW = 2,
+ V4L2_SCENE_MODE_CANDLE_LIGHT = 3,
+ V4L2_SCENE_MODE_DAWN_DUSK = 4,
+ V4L2_SCENE_MODE_FALL_COLORS = 5,
+ V4L2_SCENE_MODE_FIREWORKS = 6,
+ V4L2_SCENE_MODE_LANDSCAPE = 7,
+ V4L2_SCENE_MODE_NIGHT = 8,
+ V4L2_SCENE_MODE_PARTY_INDOOR = 9,
+ V4L2_SCENE_MODE_PORTRAIT = 10,
+ V4L2_SCENE_MODE_SPORTS = 11,
+ V4L2_SCENE_MODE_SUNSET = 12,
+ V4L2_SCENE_MODE_TEXT = 13,
+};
+
+#define V4L2_CID_3A_LOCK (V4L2_CID_CAMERA_CLASS_BASE+27)
+#define V4L2_LOCK_EXPOSURE (1 << 0)
+#define V4L2_LOCK_WHITE_BALANCE (1 << 1)
+#define V4L2_LOCK_FOCUS (1 << 2)
+
+#define V4L2_CID_AUTO_FOCUS_START (V4L2_CID_CAMERA_CLASS_BASE+28)
+#define V4L2_CID_AUTO_FOCUS_STOP (V4L2_CID_CAMERA_CLASS_BASE+29)
+#define V4L2_CID_AUTO_FOCUS_STATUS (V4L2_CID_CAMERA_CLASS_BASE+30)
+#define V4L2_AUTO_FOCUS_STATUS_IDLE (0 << 0)
+#define V4L2_AUTO_FOCUS_STATUS_BUSY (1 << 0)
+#define V4L2_AUTO_FOCUS_STATUS_REACHED (1 << 1)
+#define V4L2_AUTO_FOCUS_STATUS_FAILED (1 << 2)
+
+#define V4L2_CID_AUTO_FOCUS_RANGE (V4L2_CID_CAMERA_CLASS_BASE+31)
+enum v4l2_auto_focus_range {
+ V4L2_AUTO_FOCUS_RANGE_AUTO = 0,
+ V4L2_AUTO_FOCUS_RANGE_NORMAL = 1,
+ V4L2_AUTO_FOCUS_RANGE_MACRO = 2,
+ V4L2_AUTO_FOCUS_RANGE_INFINITY = 3,
+};
+
/* FM Modulator class control IDs */
#define V4L2_CID_FM_TX_CLASS_BASE (V4L2_CTRL_CLASS_FM_TX | 0x900)
#define V4L2_CID_FM_TX_CLASS (V4L2_CTRL_CLASS_FM_TX | 1)
@@ -1782,13 +1994,28 @@ enum v4l2_jpeg_chroma_subsampling {
#define V4L2_JPEG_ACTIVE_MARKER_DQT (1 << 17)
#define V4L2_JPEG_ACTIVE_MARKER_DHT (1 << 18)
+/* Image source controls */
+#define V4L2_CID_IMAGE_SOURCE_CLASS_BASE (V4L2_CTRL_CLASS_IMAGE_SOURCE | 0x900)
+#define V4L2_CID_IMAGE_SOURCE_CLASS (V4L2_CTRL_CLASS_IMAGE_SOURCE | 1)
+
+#define V4L2_CID_VBLANK (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 1)
+#define V4L2_CID_HBLANK (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 2)
+#define V4L2_CID_ANALOGUE_GAIN (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 3)
+
+/* Image processing controls */
+#define V4L2_CID_IMAGE_PROC_CLASS_BASE (V4L2_CTRL_CLASS_IMAGE_PROC | 0x900)
+#define V4L2_CID_IMAGE_PROC_CLASS (V4L2_CTRL_CLASS_IMAGE_PROC | 1)
+
+#define V4L2_CID_LINK_FREQ (V4L2_CID_IMAGE_PROC_CLASS_BASE + 1)
+#define V4L2_CID_PIXEL_RATE (V4L2_CID_IMAGE_PROC_CLASS_BASE + 2)
+
/*
* T U N I N G
*/
struct v4l2_tuner {
__u32 index;
__u8 name[32];
- enum v4l2_tuner_type type;
+ __u32 type; /* enum v4l2_tuner_type */
__u32 capability;
__u32 rangelow;
__u32 rangehigh;
@@ -1838,14 +2065,14 @@ struct v4l2_modulator {
struct v4l2_frequency {
__u32 tuner;
- enum v4l2_tuner_type type;
+ __u32 type; /* enum v4l2_tuner_type */
__u32 frequency;
__u32 reserved[8];
};
struct v4l2_hw_freq_seek {
__u32 tuner;
- enum v4l2_tuner_type type;
+ __u32 type; /* enum v4l2_tuner_type */
__u32 seek_upward;
__u32 wrap_around;
__u32 spacing;
@@ -2056,7 +2283,7 @@ struct v4l2_sliced_vbi_cap {
(equals frame lines 313-336 for 625 line video
standards, 263-286 for 525 line standards) */
__u16 service_lines[2][24];
- enum v4l2_buf_type type;
+ __u32 type; /* enum v4l2_buf_type */
__u32 reserved[3]; /* must be 0 */
};
@@ -2137,8 +2364,8 @@ struct v4l2_plane_pix_format {
* @width: image width in pixels
* @height: image height in pixels
* @pixelformat: little endian four character code (fourcc)
- * @field: field order (for interlaced video)
- * @colorspace: supplemental to pixelformat
+ * @field: enum v4l2_field; field order (for interlaced video)
+ * @colorspace: enum v4l2_colorspace; supplemental to pixelformat
* @plane_fmt: per-plane information
* @num_planes: number of planes for this format
*/
@@ -2146,8 +2373,8 @@ struct v4l2_pix_format_mplane {
__u32 width;
__u32 height;
__u32 pixelformat;
- enum v4l2_field field;
- enum v4l2_colorspace colorspace;
+ __u32 field;
+ __u32 colorspace;
struct v4l2_plane_pix_format plane_fmt[VIDEO_MAX_PLANES];
__u8 num_planes;
@@ -2156,7 +2383,7 @@ struct v4l2_pix_format_mplane {
/**
* struct v4l2_format - stream data format
- * @type: type of the data stream
+ * @type: enum v4l2_buf_type; type of the data stream
* @pix: definition of an image format
* @pix_mp: definition of a multiplanar image format
* @win: definition of an overlaid image
@@ -2165,7 +2392,7 @@ struct v4l2_pix_format_mplane {
* @raw_data: placeholder for future extensions and custom formats
*/
struct v4l2_format {
- enum v4l2_buf_type type;
+ __u32 type;
union {
struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
struct v4l2_pix_format_mplane pix_mp; /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
@@ -2179,7 +2406,7 @@ struct v4l2_format {
/* Stream type-dependent parameters
*/
struct v4l2_streamparm {
- enum v4l2_buf_type type;
+ __u32 type; /* enum v4l2_buf_type */
union {
struct v4l2_captureparm capture;
struct v4l2_outputparm output;
@@ -2292,14 +2519,14 @@ struct v4l2_dbg_chip_ident {
* @index: on return, index of the first created buffer
* @count: entry: number of requested buffers,
* return: number of created buffers
- * @memory: buffer memory type
+ * @memory: enum v4l2_memory; buffer memory type
* @format: frame format, for which buffers are requested
* @reserved: future extensions
*/
struct v4l2_create_buffers {
__u32 index;
__u32 count;
- enum v4l2_memory memory;
+ __u32 memory;
struct v4l2_format format;
__u32 reserved[8];
};
@@ -2356,8 +2583,8 @@ struct v4l2_create_buffers {
#define VIDIOC_TRY_FMT _IOWR('V', 64, struct v4l2_format)
#define VIDIOC_ENUMAUDIO _IOWR('V', 65, struct v4l2_audio)
#define VIDIOC_ENUMAUDOUT _IOWR('V', 66, struct v4l2_audioout)
-#define VIDIOC_G_PRIORITY _IOR('V', 67, enum v4l2_priority)
-#define VIDIOC_S_PRIORITY _IOW('V', 68, enum v4l2_priority)
+#define VIDIOC_G_PRIORITY _IOR('V', 67, __u32) /* enum v4l2_priority */
+#define VIDIOC_S_PRIORITY _IOW('V', 68, __u32) /* enum v4l2_priority */
#define VIDIOC_G_SLICED_VBI_CAP _IOWR('V', 69, struct v4l2_sliced_vbi_cap)
#define VIDIOC_LOG_STATUS _IO('V', 70)
#define VIDIOC_G_EXT_CTRLS _IOWR('V', 71, struct v4l2_ext_controls)
@@ -2384,6 +2611,9 @@ struct v4l2_create_buffers {
#endif
#define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek)
+
+/* These four DV Preset ioctls are deprecated in favor of the DV Timings
+ ioctls. */
#define VIDIOC_ENUM_DV_PRESETS _IOWR('V', 83, struct v4l2_dv_enum_preset)
#define VIDIOC_S_DV_PRESET _IOWR('V', 84, struct v4l2_dv_preset)
#define VIDIOC_G_DV_PRESET _IOWR('V', 85, struct v4l2_dv_preset)
@@ -2408,6 +2638,12 @@ struct v4l2_create_buffers {
#define VIDIOC_DECODER_CMD _IOWR('V', 96, struct v4l2_decoder_cmd)
#define VIDIOC_TRY_DECODER_CMD _IOWR('V', 97, struct v4l2_decoder_cmd)
+/* Experimental, these three ioctls may change over the next couple of kernel
+ versions. */
+#define VIDIOC_ENUM_DV_TIMINGS _IOWR('V', 96, struct v4l2_enum_dv_timings)
+#define VIDIOC_QUERY_DV_TIMINGS _IOR('V', 97, struct v4l2_dv_timings)
+#define VIDIOC_DV_TIMINGS_CAP _IOWR('V', 98, struct v4l2_dv_timings_cap)
+
/* Reminder: when adding new ioctls please add support for them to
drivers/media/video/v4l2-compat-ioctl32.c as well! */
diff --git a/drivers/staging/vme/vme.h b/include/linux/vme.h
index c9d65bf14cec..c9d65bf14cec 100644
--- a/drivers/staging/vme/vme.h
+++ b/include/linux/vme.h
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h
index e33d77f15bda..50ae7d0c279e 100644
--- a/include/linux/vt_kern.h
+++ b/include/linux/vt_kern.h
@@ -70,7 +70,6 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list);
int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list);
int con_set_default_unimap(struct vc_data *vc);
void con_free_unimap(struct vc_data *vc);
-void con_protect_unimap(struct vc_data *vc, int rdonly);
int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc);
#define vc_translate(vc, c) ((vc)->vc_translate[(c) | \
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index 29e7bba78ffe..0c16f518ee09 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -46,6 +46,7 @@ struct media_entity_operations {
int (*link_setup)(struct media_entity *entity,
const struct media_pad *local,
const struct media_pad *remote, u32 flags);
+ int (*link_validate)(struct media_link *link);
};
struct media_entity {
@@ -140,8 +141,8 @@ void media_entity_graph_walk_start(struct media_entity_graph *graph,
struct media_entity *entity);
struct media_entity *
media_entity_graph_walk_next(struct media_entity_graph *graph);
-void media_entity_pipeline_start(struct media_entity *entity,
- struct media_pipeline *pipe);
+__must_check int media_entity_pipeline_start(struct media_entity *entity,
+ struct media_pipeline *pipe);
void media_entity_pipeline_stop(struct media_entity *entity);
#define media_entity_call(entity, operation, args...) \
diff --git a/include/media/mt9p031.h b/include/media/mt9p031.h
index 96448c7a318b..0c97b19af293 100644
--- a/include/media/mt9p031.h
+++ b/include/media/mt9p031.h
@@ -3,17 +3,18 @@
struct v4l2_subdev;
-enum {
- MT9P031_COLOR_VERSION,
- MT9P031_MONOCHROME_VERSION,
-};
-
+/*
+ * struct mt9p031_platform_data - MT9P031 platform data
+ * @set_xclk: Clock frequency set callback
+ * @reset: Chip reset GPIO (set to -1 if not used)
+ * @ext_freq: Input clock frequency
+ * @target_freq: Pixel clock frequency
+ */
struct mt9p031_platform_data {
int (*set_xclk)(struct v4l2_subdev *subdev, int hz);
- int (*reset)(struct v4l2_subdev *subdev, int active);
- int ext_freq; /* input frequency to the mt9p031 for PLL dividers */
- int target_freq; /* frequency target for the PLL */
- int version; /* MT9P031_COLOR_VERSION or MT9P031_MONOCHROME_VERSION */
+ int reset;
+ int ext_freq;
+ int target_freq;
};
#endif
diff --git a/include/media/omap3isp.h b/include/media/omap3isp.h
index 042849a34640..4d94be5226af 100644
--- a/include/media/omap3isp.h
+++ b/include/media/omap3isp.h
@@ -29,6 +29,10 @@
struct i2c_board_info;
struct isp_device;
+#define ISP_XCLK_NONE 0
+#define ISP_XCLK_A 1
+#define ISP_XCLK_B 2
+
enum isp_interface_type {
ISP_INTERFACE_PARALLEL,
ISP_INTERFACE_CSI2A_PHY2,
@@ -87,6 +91,29 @@ enum {
};
/**
+ * struct isp_csiphy_lane: CCP2/CSI2 lane position and polarity
+ * @pos: position of the lane
+ * @pol: polarity of the lane
+ */
+struct isp_csiphy_lane {
+ u8 pos;
+ u8 pol;
+};
+
+#define ISP_CSIPHY1_NUM_DATA_LANES 1
+#define ISP_CSIPHY2_NUM_DATA_LANES 2
+
+/**
+ * struct isp_csiphy_lanes_cfg - CCP2/CSI2 lane configuration
+ * @data: Configuration of one or two data lanes
+ * @clk: Clock lane configuration
+ */
+struct isp_csiphy_lanes_cfg {
+ struct isp_csiphy_lane data[ISP_CSIPHY2_NUM_DATA_LANES];
+ struct isp_csiphy_lane clk;
+};
+
+/**
* struct isp_ccp2_platform_data - CCP2 interface platform data
* @strobe_clk_pol: Strobe/clock polarity
* 0 - Non Inverted, 1 - Inverted
@@ -105,6 +132,7 @@ struct isp_ccp2_platform_data {
unsigned int ccp2_mode:1;
unsigned int phy_layer:1;
unsigned int vpclk_div:2;
+ struct isp_csiphy_lanes_cfg lanecfg;
};
/**
@@ -115,6 +143,7 @@ struct isp_ccp2_platform_data {
struct isp_csi2_platform_data {
unsigned crc:1;
unsigned vpclk_div:2;
+ struct isp_csiphy_lanes_cfg lanecfg;
};
struct isp_subdev_i2c_board_info {
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 8db6741c1256..cfd5163ff7f3 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -62,6 +62,7 @@ void rc_map_init(void);
#define RC_MAP_ANYSEE "rc-anysee"
#define RC_MAP_APAC_VIEWCOMP "rc-apac-viewcomp"
#define RC_MAP_ASUS_PC39 "rc-asus-pc39"
+#define RC_MAP_ASUS_PS3_100 "rc-asus-ps3-100"
#define RC_MAP_ATI_TV_WONDER_HD_600 "rc-ati-tv-wonder-hd-600"
#define RC_MAP_ATI_X10 "rc-ati-x10"
#define RC_MAP_AVERMEDIA_A16D "rc-avermedia-a16d"
@@ -113,6 +114,8 @@ void rc_map_init(void);
#define RC_MAP_LME2510 "rc-lme2510"
#define RC_MAP_MANLI "rc-manli"
#define RC_MAP_MEDION_X10 "rc-medion-x10"
+#define RC_MAP_MEDION_X10_DIGITAINER "rc-medion-x10-digitainer"
+#define RC_MAP_MEDION_X10_OR2X "rc-medion-x10-or2x"
#define RC_MAP_MSI_DIGIVOX_II "rc-msi-digivox-ii"
#define RC_MAP_MSI_DIGIVOX_III "rc-msi-digivox-iii"
#define RC_MAP_MSI_TVANYWHERE_PLUS "rc-msi-tvanywhere-plus"
diff --git a/include/media/s5p_fimc.h b/include/media/s5p_fimc.h
index 688fb3f1dc35..8587aaf73646 100644
--- a/include/media/s5p_fimc.h
+++ b/include/media/s5p_fimc.h
@@ -64,4 +64,20 @@ struct s5p_platform_fimc {
*/
#define S5P_FIMC_TX_END_NOTIFY _IO('e', 0)
+enum fimc_subdev_index {
+ IDX_SENSOR,
+ IDX_CSIS,
+ IDX_FLITE,
+ IDX_FIMC,
+ IDX_MAX,
+};
+
+struct media_pipeline;
+struct v4l2_subdev;
+
+struct fimc_pipeline {
+ struct v4l2_subdev *subdevs[IDX_MAX];
+ struct media_pipeline *m_pipeline;
+};
+
#endif /* S5P_FIMC_H_ */
diff --git a/include/media/saa7146.h b/include/media/saa7146.h
index 0f037e8edf9a..773e527deabe 100644
--- a/include/media/saa7146.h
+++ b/include/media/saa7146.h
@@ -13,12 +13,11 @@
#include <linux/mutex.h>
#include <linux/scatterlist.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
#include <linux/vmalloc.h> /* for vmalloc() */
#include <linux/mm.h> /* for vmalloc_to_page() */
-#define SAA7146_VERSION_CODE 0x000600 /* 0.6.0 */
-
#define saa7146_write(sxy,adr,dat) writel((dat),(sxy->mem+(adr)))
#define saa7146_read(sxy,adr) readl(sxy->mem+(adr))
@@ -121,6 +120,7 @@ struct saa7146_dev
struct list_head item;
struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler ctrl_handler;
/* different device locks */
spinlock_t slock;
diff --git a/include/media/saa7146_vv.h b/include/media/saa7146_vv.h
index 4aeff96ff7d8..944ecdf3530f 100644
--- a/include/media/saa7146_vv.h
+++ b/include/media/saa7146_vv.h
@@ -3,6 +3,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
#include <media/saa7146.h>
#include <media/videobuf-dma-sg.h>
@@ -84,21 +85,15 @@ struct saa7146_overlay {
/* per open data */
struct saa7146_fh {
+ /* Must be the first field! */
+ struct v4l2_fh fh;
struct saa7146_dev *dev;
- /* if this is a vbi or capture open */
- enum v4l2_buf_type type;
-
- /* video overlay */
- struct saa7146_overlay ov;
/* video capture */
struct videobuf_queue video_q;
- struct v4l2_pix_format video_fmt;
/* vbi capture */
struct videobuf_queue vbi_q;
- struct v4l2_vbi_format vbi_fmt;
- struct timer_list vbi_read_timeout;
unsigned int resources; /* resource management for device open */
};
@@ -109,7 +104,9 @@ struct saa7146_fh {
struct saa7146_vv
{
/* vbi capture */
- struct saa7146_dmaqueue vbi_q;
+ struct saa7146_dmaqueue vbi_dmaq;
+ struct v4l2_vbi_format vbi_fmt;
+ struct timer_list vbi_read_timeout;
/* vbi workaround interrupt queue */
wait_queue_head_t vbi_wq;
int vbi_fieldcount;
@@ -119,13 +116,14 @@ struct saa7146_vv
struct saa7146_fh *video_fh;
/* video overlay */
+ struct saa7146_overlay ov;
struct v4l2_framebuffer ov_fb;
struct saa7146_format *ov_fmt;
- struct saa7146_overlay *ov_data;
struct saa7146_fh *ov_suspend;
/* video capture */
- struct saa7146_dmaqueue video_q;
+ struct saa7146_dmaqueue video_dmaq;
+ struct v4l2_pix_format video_fmt;
enum v4l2_field last_field;
/* common: fixme? shouldn't this be in saa7146_fh?
@@ -163,7 +161,8 @@ struct saa7146_ext_vv
int (*std_callback)(struct saa7146_dev*, struct saa7146_standard *);
/* the extension can override this */
- struct v4l2_ioctl_ops ops;
+ struct v4l2_ioctl_ops vid_ops;
+ struct v4l2_ioctl_ops vbi_ops;
/* pointer to the saa7146 core ops */
const struct v4l2_ioctl_ops *core_ops;
@@ -202,10 +201,12 @@ void saa7146_set_gpio(struct saa7146_dev *saa, u8 pin, u8 data);
/* from saa7146_video.c */
extern const struct v4l2_ioctl_ops saa7146_video_ioctl_ops;
+extern const struct v4l2_ioctl_ops saa7146_vbi_ioctl_ops;
extern struct saa7146_use_ops saa7146_video_uops;
int saa7146_start_preview(struct saa7146_fh *fh);
int saa7146_stop_preview(struct saa7146_fh *fh);
long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg);
+int saa7146_s_ctrl(struct v4l2_ctrl *ctrl);
/* from saa7146_vbi.c */
extern struct saa7146_use_ops saa7146_vbi_uops;
diff --git a/include/media/sh_mobile_ceu.h b/include/media/sh_mobile_ceu.h
index a90a765f18da..6fdb6adf6b2b 100644
--- a/include/media/sh_mobile_ceu.h
+++ b/include/media/sh_mobile_ceu.h
@@ -5,6 +5,7 @@
#define SH_CEU_FLAG_USE_16BIT_BUS (1 << 1) /* use 16bit bus width */
#define SH_CEU_FLAG_HSYNC_LOW (1 << 2) /* default High if possible */
#define SH_CEU_FLAG_VSYNC_LOW (1 << 3) /* default High if possible */
+#define SH_CEU_FLAG_LOWER_8BIT (1 << 4) /* default upper 8bit */
struct device;
struct resource;
diff --git a/include/media/smiapp.h b/include/media/smiapp.h
new file mode 100644
index 000000000000..9ab07fd45d5c
--- /dev/null
+++ b/include/media/smiapp.h
@@ -0,0 +1,84 @@
+/*
+ * include/media/smiapp.h
+ *
+ * Generic driver for SMIA/SMIA++ compliant camera modules
+ *
+ * Copyright (C) 2011--2012 Nokia Corporation
+ * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __SMIAPP_H_
+#define __SMIAPP_H_
+
+#include <media/v4l2-subdev.h>
+
+#define SMIAPP_NAME "smiapp"
+
+#define SMIAPP_DFL_I2C_ADDR (0x20 >> 1) /* Default I2C Address */
+#define SMIAPP_ALT_I2C_ADDR (0x6e >> 1) /* Alternate I2C Address */
+
+#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK 0
+#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE 1
+#define SMIAPP_CSI_SIGNALLING_MODE_CSI2 2
+
+#define SMIAPP_NO_XSHUTDOWN -1
+
+/*
+ * Sometimes due to board layout considerations the camera module can be
+ * mounted rotated. The typical rotation used is 180 degrees which can be
+ * corrected by giving a default H-FLIP and V-FLIP in the sensor readout.
+ * FIXME: rotation also changes the bayer pattern.
+ */
+enum smiapp_module_board_orient {
+ SMIAPP_MODULE_BOARD_ORIENT_0 = 0,
+ SMIAPP_MODULE_BOARD_ORIENT_180,
+};
+
+struct smiapp_flash_strobe_parms {
+ u8 mode;
+ u32 strobe_width_high_us;
+ u16 strobe_delay;
+ u16 stobe_start_point;
+ u8 trigger;
+};
+
+struct smiapp_platform_data {
+ /*
+ * Change the cci address if i2c_addr_alt is set.
+ * Both default and alternate cci addr need to be present
+ */
+ unsigned short i2c_addr_dfl; /* Default i2c addr */
+ unsigned short i2c_addr_alt; /* Alternate i2c addr */
+
+ unsigned int nvm_size; /* bytes */
+ unsigned int ext_clk; /* sensor external clk */
+
+ unsigned int lanes; /* Number of CSI-2 lanes */
+ u8 csi_signalling_mode; /* SMIAPP_CSI_SIGNALLING_MODE_* */
+ const s64 *op_sys_clock;
+
+ enum smiapp_module_board_orient module_board_orient;
+
+ struct smiapp_flash_strobe_parms *strobe_setup;
+
+ int (*set_xclk)(struct v4l2_subdev *sd, int hz);
+ char *ext_clk_name;
+ int xshutdown; /* gpio or SMIAPP_NO_XSHUTDOWN */
+};
+
+#endif /* __SMIAPP_H_ */
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index cad374bdcf4b..d865dcf9879f 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -56,11 +56,15 @@ struct soc_camera_device {
};
};
+/* Host supports programmable stride */
+#define SOCAM_HOST_CAP_STRIDE (1 << 0)
+
struct soc_camera_host {
struct v4l2_device v4l2_dev;
struct list_head list;
struct mutex host_lock; /* Protect during probing */
unsigned char nr; /* Host number */
+ u32 capabilities;
void *priv;
const char *drv_name;
struct soc_camera_host_ops *ops;
@@ -98,7 +102,7 @@ struct soc_camera_host_ops {
int (*set_bus_param)(struct soc_camera_device *);
int (*get_parm)(struct soc_camera_device *, struct v4l2_streamparm *);
int (*set_parm)(struct soc_camera_device *, struct v4l2_streamparm *);
- int (*enum_fsizes)(struct soc_camera_device *, struct v4l2_frmsizeenum *);
+ int (*enum_framesizes)(struct soc_camera_device *, struct v4l2_frmsizeenum *);
unsigned int (*poll)(struct file *, poll_table *);
};
diff --git a/include/media/soc_mediabus.h b/include/media/soc_mediabus.h
index 73f1e7eb60f3..0dc6f4625b92 100644
--- a/include/media/soc_mediabus.h
+++ b/include/media/soc_mediabus.h
@@ -47,6 +47,24 @@ enum soc_mbus_order {
};
/**
+ * enum soc_mbus_layout - planes layout in memory
+ * @SOC_MBUS_LAYOUT_PACKED: color components packed
+ * @SOC_MBUS_LAYOUT_PLANAR_2Y_U_V: YUV components stored in 3 planes (4:2:2)
+ * @SOC_MBUS_LAYOUT_PLANAR_2Y_C: YUV components stored in a luma and a
+ * chroma plane (C plane is half the size
+ * of Y plane)
+ * @SOC_MBUS_LAYOUT_PLANAR_Y_C: YUV components stored in a luma and a
+ * chroma plane (C plane is the same size
+ * as Y plane)
+ */
+enum soc_mbus_layout {
+ SOC_MBUS_LAYOUT_PACKED = 0,
+ SOC_MBUS_LAYOUT_PLANAR_2Y_U_V,
+ SOC_MBUS_LAYOUT_PLANAR_2Y_C,
+ SOC_MBUS_LAYOUT_PLANAR_Y_C,
+};
+
+/**
* struct soc_mbus_pixelfmt - Data format on the media bus
* @name: Name of the format
* @fourcc: Fourcc code, that will be obtained if the data is
@@ -60,6 +78,7 @@ struct soc_mbus_pixelfmt {
u32 fourcc;
enum soc_mbus_packing packing;
enum soc_mbus_order order;
+ enum soc_mbus_layout layout;
u8 bits_per_sample;
};
@@ -80,6 +99,8 @@ const struct soc_mbus_pixelfmt *soc_mbus_find_fmtdesc(
const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc(
enum v4l2_mbus_pixelcode code);
s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf);
+s32 soc_mbus_image_size(const struct soc_mbus_pixelfmt *mf,
+ u32 bytes_per_line, u32 height);
int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf,
unsigned int *numerator, unsigned int *denominator);
unsigned int soc_mbus_config_compatible(const struct v4l2_mbus_config *cfg,
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index 11e67562b3ac..776605f1cbe2 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -25,6 +25,7 @@
#include <linux/videodev2.h>
/* forward references */
+struct file;
struct v4l2_ctrl_handler;
struct v4l2_ctrl_helper;
struct v4l2_ctrl;
@@ -129,7 +130,10 @@ struct v4l2_ctrl {
u32 step;
u32 menu_skip_mask;
};
- const char * const *qmenu;
+ union {
+ const char * const *qmenu;
+ const s64 *qmenu_int;
+ };
unsigned long flags;
union {
s32 val;
@@ -164,7 +168,9 @@ struct v4l2_ctrl_ref {
/** struct v4l2_ctrl_handler - The control handler keeps track of all the
* controls: both the controls owned by the handler and those inherited
* from other handlers.
+ * @_lock: Default for "lock".
* @lock: Lock to control access to this handler and its controls.
+ * May be replaced by the user right after init.
* @ctrls: The list of controls owned by this handler.
* @ctrl_refs: The list of control references.
* @cached: The last found control reference. It is common that the same
@@ -175,7 +181,8 @@ struct v4l2_ctrl_ref {
* @error: The error code of the first failed control addition.
*/
struct v4l2_ctrl_handler {
- struct mutex lock;
+ struct mutex _lock;
+ struct mutex *lock;
struct list_head ctrls;
struct list_head ctrl_refs;
struct v4l2_ctrl_ref *cached;
@@ -219,6 +226,7 @@ struct v4l2_ctrl_config {
u32 flags;
u32 menu_skip_mask;
const char * const *qmenu;
+ const s64 *qmenu_int;
unsigned int is_private:1;
};
@@ -343,6 +351,23 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
const struct v4l2_ctrl_ops *ops,
u32 id, s32 max, s32 mask, s32 def);
+/** v4l2_ctrl_new_int_menu() - Create a new standard V4L2 integer menu control.
+ * @hdl: The control handler.
+ * @ops: The control ops.
+ * @id: The control ID.
+ * @max: The control's maximum value.
+ * @def: The control's default value.
+ * @qmenu_int: The control's menu entries.
+ *
+ * Same as v4l2_ctrl_new_std_menu(), but @mask is set to 0 and it additionaly
+ * takes as an argument an array of integers determining the menu items.
+ *
+ * If @id refers to a non-integer-menu control, then this function will return NULL.
+ */
+struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_ops *ops,
+ u32 id, s32 max, s32 def, const s64 *qmenu_int);
+
/** v4l2_ctrl_add_ctrl() - Add a control from another handler to this handler.
* @hdl: The control handler.
* @ctrl: The control to add.
@@ -451,7 +476,7 @@ void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed);
*/
static inline void v4l2_ctrl_lock(struct v4l2_ctrl *ctrl)
{
- mutex_lock(&ctrl->handler->lock);
+ mutex_lock(ctrl->handler->lock);
}
/** v4l2_ctrl_lock() - Helper function to unlock the handler
@@ -460,7 +485,7 @@ static inline void v4l2_ctrl_lock(struct v4l2_ctrl *ctrl)
*/
static inline void v4l2_ctrl_unlock(struct v4l2_ctrl *ctrl)
{
- mutex_unlock(&ctrl->handler->lock);
+ mutex_unlock(ctrl->handler->lock);
}
/** v4l2_ctrl_g_ctrl() - Helper function to get the control's value from within a driver.
@@ -487,10 +512,9 @@ s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl);
int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val);
/* Internal helper functions that deal with control events. */
-void v4l2_ctrl_add_event(struct v4l2_ctrl *ctrl,
- struct v4l2_subscribed_event *sev);
-void v4l2_ctrl_del_event(struct v4l2_ctrl *ctrl,
- struct v4l2_subscribed_event *sev);
+extern const struct v4l2_subscribed_event_ops v4l2_ctrl_sub_ev_ops;
+void v4l2_ctrl_replace(struct v4l2_event *old, const struct v4l2_event *new);
+void v4l2_ctrl_merge(const struct v4l2_event *old, struct v4l2_event *new);
/* Can be used as a vidioc_log_status function that just dumps all controls
associated with the filehandle. */
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index 96d22215cc88..a056e6ee1b68 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -39,6 +39,9 @@ struct v4l2_ctrl_handler;
#define V4L2_FL_USES_V4L2_FH (1)
/* Use the prio field of v4l2_fh for core priority checking */
#define V4L2_FL_USE_FH_PRIO (2)
+/* If ioctl core locking is in use, then apply that also to all
+ file operations. Don't use this flag in new drivers! */
+#define V4L2_FL_LOCK_ALL_FOPS (3)
/* Priority helper functions */
@@ -126,8 +129,10 @@ struct video_device
/* ioctl callbacks */
const struct v4l2_ioctl_ops *ioctl_ops;
+ DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE);
/* serialization lock */
+ DECLARE_BITMAP(disable_locking, BASE_VIDIOC_PRIVATE);
struct mutex *lock;
};
@@ -173,6 +178,26 @@ void video_device_release(struct video_device *vdev);
a dubious construction at best. */
void video_device_release_empty(struct video_device *vdev);
+/* returns true if cmd is a known V4L2 ioctl */
+bool v4l2_is_known_ioctl(unsigned int cmd);
+
+/* mark that this command shouldn't use core locking */
+static inline void v4l2_disable_ioctl_locking(struct video_device *vdev, unsigned int cmd)
+{
+ if (_IOC_NR(cmd) < BASE_VIDIOC_PRIVATE)
+ set_bit(_IOC_NR(cmd), vdev->disable_locking);
+}
+
+/* Mark that this command isn't implemented. This must be called before
+ video_device_register. See also the comments in determine_valid_ioctls().
+ This function allows drivers to provide just one v4l2_ioctl_ops struct, but
+ disable ioctls based on the specific card that is actually found. */
+static inline void v4l2_disable_ioctl(struct video_device *vdev, unsigned int cmd)
+{
+ if (_IOC_NR(cmd) < BASE_VIDIOC_PRIVATE)
+ set_bit(_IOC_NR(cmd), vdev->valid_ioctls);
+}
+
/* helper functions to access driver private data. */
static inline void *video_get_drvdata(struct video_device *vdev)
{
diff --git a/include/media/v4l2-event.h b/include/media/v4l2-event.h
index 5f14e8895ce2..2885a810a128 100644
--- a/include/media/v4l2-event.h
+++ b/include/media/v4l2-event.h
@@ -78,6 +78,19 @@ struct v4l2_kevent {
struct v4l2_event event;
};
+/** struct v4l2_subscribed_event_ops - Subscribed event operations.
+ * @add: Optional callback, called when a new listener is added
+ * @del: Optional callback, called when a listener stops listening
+ * @replace: Optional callback that can replace event 'old' with event 'new'.
+ * @merge: Optional callback that can merge event 'old' into event 'new'.
+ */
+struct v4l2_subscribed_event_ops {
+ int (*add)(struct v4l2_subscribed_event *sev, unsigned elems);
+ void (*del)(struct v4l2_subscribed_event *sev);
+ void (*replace)(struct v4l2_event *old, const struct v4l2_event *new);
+ void (*merge)(const struct v4l2_event *old, struct v4l2_event *new);
+};
+
/** struct v4l2_subscribed_event - Internal struct representing a subscribed event.
* @list: List node for the v4l2_fh->subscribed list.
* @type: Event type.
@@ -85,8 +98,7 @@ struct v4l2_kevent {
* @flags: Copy of v4l2_event_subscription->flags.
* @fh: Filehandle that subscribed to this event.
* @node: List node that hooks into the object's event list (if there is one).
- * @replace: Optional callback that can replace event 'old' with event 'new'.
- * @merge: Optional callback that can merge event 'old' into event 'new'.
+ * @ops: v4l2_subscribed_event_ops
* @elems: The number of elements in the events array.
* @first: The index of the events containing the oldest available event.
* @in_use: The number of queued events.
@@ -99,10 +111,7 @@ struct v4l2_subscribed_event {
u32 flags;
struct v4l2_fh *fh;
struct list_head node;
- void (*replace)(struct v4l2_event *old,
- const struct v4l2_event *new);
- void (*merge)(const struct v4l2_event *old,
- struct v4l2_event *new);
+ const struct v4l2_subscribed_event_ops *ops;
unsigned elems;
unsigned first;
unsigned in_use;
@@ -115,7 +124,8 @@ void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev);
void v4l2_event_queue_fh(struct v4l2_fh *fh, const struct v4l2_event *ev);
int v4l2_event_pending(struct v4l2_fh *fh);
int v4l2_event_subscribe(struct v4l2_fh *fh,
- struct v4l2_event_subscription *sub, unsigned elems);
+ struct v4l2_event_subscription *sub, unsigned elems,
+ const struct v4l2_subscribed_event_ops *ops);
int v4l2_event_unsubscribe(struct v4l2_fh *fh,
struct v4l2_event_subscription *sub);
void v4l2_event_unsubscribe_all(struct v4l2_fh *fh);
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index 3cb939cd03f9..d8b76f7392f8 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -271,6 +271,12 @@ struct v4l2_ioctl_ops {
struct v4l2_dv_timings *timings);
int (*vidioc_g_dv_timings) (struct file *file, void *fh,
struct v4l2_dv_timings *timings);
+ int (*vidioc_query_dv_timings) (struct file *file, void *fh,
+ struct v4l2_dv_timings *timings);
+ int (*vidioc_enum_dv_timings) (struct file *file, void *fh,
+ struct v4l2_enum_dv_timings *timings);
+ int (*vidioc_dv_timings_cap) (struct file *file, void *fh,
+ struct v4l2_dv_timings_cap *cap);
int (*vidioc_subscribe_event) (struct v4l2_fh *fh,
struct v4l2_event_subscription *sub);
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index f0f3358d1b1b..c35a3545e273 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -307,6 +307,12 @@ struct v4l2_subdev_video_ops {
struct v4l2_dv_timings *timings);
int (*g_dv_timings)(struct v4l2_subdev *sd,
struct v4l2_dv_timings *timings);
+ int (*enum_dv_timings)(struct v4l2_subdev *sd,
+ struct v4l2_enum_dv_timings *timings);
+ int (*query_dv_timings)(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings *timings);
+ int (*dv_timings_cap)(struct v4l2_subdev *sd,
+ struct v4l2_dv_timings_cap *cap);
int (*enum_mbus_fmt)(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code);
int (*enum_mbus_fsizes)(struct v4l2_subdev *sd,
@@ -466,6 +472,15 @@ struct v4l2_subdev_pad_ops {
struct v4l2_subdev_crop *crop);
int (*get_crop)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
struct v4l2_subdev_crop *crop);
+ int (*get_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel);
+ int (*set_selection)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ int (*link_validate)(struct v4l2_subdev *sd, struct media_link *link,
+ struct v4l2_subdev_format *source_fmt,
+ struct v4l2_subdev_format *sink_fmt);
+#endif /* CONFIG_MEDIA_CONTROLLER */
};
struct v4l2_subdev_ops {
@@ -541,7 +556,7 @@ struct v4l2_subdev {
#define media_entity_to_v4l2_subdev(ent) \
container_of(ent, struct v4l2_subdev, entity)
#define vdev_to_v4l2_subdev(vdev) \
- video_get_drvdata(vdev)
+ ((struct v4l2_subdev *)video_get_drvdata(vdev))
/*
* Used for storing subdev information per file handle
@@ -549,8 +564,11 @@ struct v4l2_subdev {
struct v4l2_subdev_fh {
struct v4l2_fh vfh;
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
- struct v4l2_mbus_framefmt *try_fmt;
- struct v4l2_rect *try_crop;
+ struct {
+ struct v4l2_mbus_framefmt try_fmt;
+ struct v4l2_rect try_crop;
+ struct v4l2_rect try_compose;
+ } *pad;
#endif
};
@@ -558,17 +576,19 @@ struct v4l2_subdev_fh {
container_of(fh, struct v4l2_subdev_fh, vfh)
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
-static inline struct v4l2_mbus_framefmt *
-v4l2_subdev_get_try_format(struct v4l2_subdev_fh *fh, unsigned int pad)
-{
- return &fh->try_fmt[pad];
-}
-
-static inline struct v4l2_rect *
-v4l2_subdev_get_try_crop(struct v4l2_subdev_fh *fh, unsigned int pad)
-{
- return &fh->try_crop[pad];
-}
+#define __V4L2_SUBDEV_MK_GET_TRY(rtype, fun_name, field_name) \
+ static inline struct rtype * \
+ v4l2_subdev_get_try_##fun_name(struct v4l2_subdev_fh *fh, \
+ unsigned int pad) \
+ { \
+ BUG_ON(unlikely(pad >= vdev_to_v4l2_subdev( \
+ fh->vfh.vdev)->entity.num_pads)); \
+ return &fh->pad[pad].field_name; \
+ }
+
+__V4L2_SUBDEV_MK_GET_TRY(v4l2_mbus_framefmt, format, try_fmt)
+__V4L2_SUBDEV_MK_GET_TRY(v4l2_rect, crop, try_compose)
+__V4L2_SUBDEV_MK_GET_TRY(v4l2_rect, compose, try_compose)
#endif
extern const struct v4l2_file_operations v4l2_subdev_fops;
@@ -593,6 +613,13 @@ static inline void *v4l2_get_subdev_hostdata(const struct v4l2_subdev *sd)
return sd->host_priv;
}
+#ifdef CONFIG_MEDIA_CONTROLLER
+int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
+ struct media_link *link,
+ struct v4l2_subdev_format *source_fmt,
+ struct v4l2_subdev_format *sink_fmt);
+int v4l2_subdev_link_validate(struct media_link *link);
+#endif /* CONFIG_MEDIA_CONTROLLER */
void v4l2_subdev_init(struct v4l2_subdev *sd,
const struct v4l2_subdev_ops *ops);
diff --git a/include/media/videobuf-dma-contig.h b/include/media/videobuf-dma-contig.h
index f0ed82543d9f..f473aeb86d3f 100644
--- a/include/media/videobuf-dma-contig.h
+++ b/include/media/videobuf-dma-contig.h
@@ -26,6 +26,16 @@ void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
void *priv,
struct mutex *ext_lock);
+void videobuf_queue_dma_contig_init_cached(struct videobuf_queue *q,
+ const struct videobuf_queue_ops *ops,
+ struct device *dev,
+ spinlock_t *irqlock,
+ enum v4l2_buf_type type,
+ enum v4l2_field field,
+ unsigned int msize,
+ void *priv,
+ struct mutex *ext_lock);
+
dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf);
void videobuf_dma_contig_free(struct videobuf_queue *q,
struct videobuf_buffer *buf);
diff --git a/include/memory/jedec_ddr.h b/include/memory/jedec_ddr.h
new file mode 100644
index 000000000000..ddad0f870e5d
--- /dev/null
+++ b/include/memory/jedec_ddr.h
@@ -0,0 +1,175 @@
+/*
+ * Definitions for DDR memories based on JEDEC specs
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Aneesh V <aneesh@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.
+ */
+#ifndef __LINUX_JEDEC_DDR_H
+#define __LINUX_JEDEC_DDR_H
+
+#include <linux/types.h>
+
+/* DDR Densities */
+#define DDR_DENSITY_64Mb 1
+#define DDR_DENSITY_128Mb 2
+#define DDR_DENSITY_256Mb 3
+#define DDR_DENSITY_512Mb 4
+#define DDR_DENSITY_1Gb 5
+#define DDR_DENSITY_2Gb 6
+#define DDR_DENSITY_4Gb 7
+#define DDR_DENSITY_8Gb 8
+#define DDR_DENSITY_16Gb 9
+#define DDR_DENSITY_32Gb 10
+
+/* DDR type */
+#define DDR_TYPE_DDR2 1
+#define DDR_TYPE_DDR3 2
+#define DDR_TYPE_LPDDR2_S4 3
+#define DDR_TYPE_LPDDR2_S2 4
+#define DDR_TYPE_LPDDR2_NVM 5
+
+/* DDR IO width */
+#define DDR_IO_WIDTH_4 1
+#define DDR_IO_WIDTH_8 2
+#define DDR_IO_WIDTH_16 3
+#define DDR_IO_WIDTH_32 4
+
+/* Number of Row bits */
+#define R9 9
+#define R10 10
+#define R11 11
+#define R12 12
+#define R13 13
+#define R14 14
+#define R15 15
+#define R16 16
+
+/* Number of Column bits */
+#define C7 7
+#define C8 8
+#define C9 9
+#define C10 10
+#define C11 11
+#define C12 12
+
+/* Number of Banks */
+#define B1 0
+#define B2 1
+#define B4 2
+#define B8 3
+
+/* Refresh rate in nano-seconds */
+#define T_REFI_15_6 15600
+#define T_REFI_7_8 7800
+#define T_REFI_3_9 3900
+
+/* tRFC values */
+#define T_RFC_90 90000
+#define T_RFC_110 110000
+#define T_RFC_130 130000
+#define T_RFC_160 160000
+#define T_RFC_210 210000
+#define T_RFC_300 300000
+#define T_RFC_350 350000
+
+/* Mode register numbers */
+#define DDR_MR0 0
+#define DDR_MR1 1
+#define DDR_MR2 2
+#define DDR_MR3 3
+#define DDR_MR4 4
+#define DDR_MR5 5
+#define DDR_MR6 6
+#define DDR_MR7 7
+#define DDR_MR8 8
+#define DDR_MR9 9
+#define DDR_MR10 10
+#define DDR_MR11 11
+#define DDR_MR16 16
+#define DDR_MR17 17
+#define DDR_MR18 18
+
+/*
+ * LPDDR2 related defines
+ */
+
+/* MR4 register fields */
+#define MR4_SDRAM_REF_RATE_SHIFT 0
+#define MR4_SDRAM_REF_RATE_MASK 7
+#define MR4_TUF_SHIFT 7
+#define MR4_TUF_MASK (1 << 7)
+
+/* MR4 SDRAM Refresh Rate field values */
+#define SDRAM_TEMP_NOMINAL 0x3
+#define SDRAM_TEMP_RESERVED_4 0x4
+#define SDRAM_TEMP_HIGH_DERATE_REFRESH 0x5
+#define SDRAM_TEMP_HIGH_DERATE_REFRESH_AND_TIMINGS 0x6
+#define SDRAM_TEMP_VERY_HIGH_SHUTDOWN 0x7
+
+#define NUM_DDR_ADDR_TABLE_ENTRIES 11
+#define NUM_DDR_TIMING_TABLE_ENTRIES 4
+
+/* Structure for DDR addressing info from the JEDEC spec */
+struct lpddr2_addressing {
+ u32 num_banks;
+ u32 tREFI_ns;
+ u32 tRFCab_ps;
+};
+
+/*
+ * Structure for timings from the LPDDR2 datasheet
+ * All parameters are in pico seconds(ps) unless explicitly indicated
+ * with a suffix like tRAS_max_ns below
+ */
+struct lpddr2_timings {
+ u32 max_freq;
+ u32 min_freq;
+ u32 tRPab;
+ u32 tRCD;
+ u32 tWR;
+ u32 tRAS_min;
+ u32 tRRD;
+ u32 tWTR;
+ u32 tXP;
+ u32 tRTP;
+ u32 tCKESR;
+ u32 tDQSCK_max;
+ u32 tDQSCK_max_derated;
+ u32 tFAW;
+ u32 tZQCS;
+ u32 tZQCL;
+ u32 tZQinit;
+ u32 tRAS_max_ns;
+};
+
+/*
+ * Min value for some parameters in terms of number of tCK cycles(nCK)
+ * Please set to zero parameters that are not valid for a given memory
+ * type
+ */
+struct lpddr2_min_tck {
+ u32 tRPab;
+ u32 tRCD;
+ u32 tWR;
+ u32 tRASmin;
+ u32 tRRD;
+ u32 tWTR;
+ u32 tXP;
+ u32 tRTP;
+ u32 tCKE;
+ u32 tCKESR;
+ u32 tFAW;
+};
+
+extern const struct lpddr2_addressing
+ lpddr2_jedec_addressing_table[NUM_DDR_ADDR_TABLE_ENTRIES];
+extern const struct lpddr2_timings
+ lpddr2_jedec_timings[NUM_DDR_TIMING_TABLE_ENTRIES];
+extern const struct lpddr2_min_tck lpddr2_jedec_min_tck;
+
+#endif /* __LINUX_JEDEC_DDR_H */
diff --git a/include/mtd/ubi-user.h b/include/mtd/ubi-user.h
index 3c4109777aff..8787349fbafe 100644
--- a/include/mtd/ubi-user.h
+++ b/include/mtd/ubi-user.h
@@ -196,23 +196,6 @@
#define UBI_MAX_RNVOL 32
/*
- * UBI data type hint constants.
- *
- * UBI_LONGTERM: long-term data
- * UBI_SHORTTERM: short-term data
- * UBI_UNKNOWN: data persistence is unknown
- *
- * These constants are used when data is written to UBI volumes in order to
- * help the UBI wear-leveling unit to find more appropriate physical
- * eraseblocks.
- */
-enum {
- UBI_LONGTERM = 1,
- UBI_SHORTTERM = 2,
- UBI_UNKNOWN = 3,
-};
-
-/*
* UBI volume type constants.
*
* @UBI_DYNAMIC_VOLUME: dynamic volume
@@ -375,25 +358,34 @@ struct ubi_rnvol_req {
* requests.
* @lnum: logical eraseblock number to change
* @bytes: how many bytes will be written to the logical eraseblock
- * @dtype: data type (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN)
+ * @dtype: pass "3" for better compatibility with old kernels
* @padding: reserved for future, not used, has to be zeroed
+ *
+ * The @dtype field used to inform UBI about what kind of data will be written
+ * to the LEB: long term (value 1), short term (value 2), unknown (value 3).
+ * UBI tried to pick a PEB with lower erase counter for short term data and a
+ * PEB with higher erase counter for long term data. But this was not really
+ * used because users usually do not know this and could easily mislead UBI. We
+ * removed this feature in May 2012. UBI currently just ignores the @dtype
+ * field. But for better compatibility with older kernels it is recommended to
+ * set @dtype to 3 (unknown).
*/
struct ubi_leb_change_req {
__s32 lnum;
__s32 bytes;
- __s8 dtype;
+ __s8 dtype; /* obsolete, do not use! */
__s8 padding[7];
} __packed;
/**
* struct ubi_map_req - a data structure used in map LEB requests.
+ * @dtype: pass "3" for better compatibility with old kernels
* @lnum: logical eraseblock number to unmap
- * @dtype: data type (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN)
* @padding: reserved for future, not used, has to be zeroed
*/
struct ubi_map_req {
__s32 lnum;
- __s8 dtype;
+ __s8 dtype; /* obsolete, do not use! */
__s8 padding[3];
} __packed;
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index a65910bda381..961669b648fd 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -163,6 +163,11 @@ typedef struct {
__u8 b[6];
} __packed bdaddr_t;
+/* BD Address type */
+#define BDADDR_BREDR 0x00
+#define BDADDR_LE_PUBLIC 0x01
+#define BDADDR_LE_RANDOM 0x02
+
#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}})
@@ -178,7 +183,6 @@ static inline void bacpy(bdaddr_t *dst, bdaddr_t *src)
void baswap(bdaddr_t *dst, bdaddr_t *src);
char *batostr(bdaddr_t *ba);
-bdaddr_t *strtoba(char *str);
/* Common socket structures and functions */
@@ -190,8 +194,12 @@ struct bt_sock {
bdaddr_t dst;
struct list_head accept_q;
struct sock *parent;
- u32 defer_setup;
- bool suspended;
+ unsigned long flags;
+};
+
+enum {
+ BT_SK_DEFER_SETUP,
+ BT_SK_SUSPEND,
};
struct bt_sock_list {
@@ -216,14 +224,24 @@ void bt_accept_unlink(struct sock *sk);
struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock);
/* Skb helpers */
+struct l2cap_ctrl {
+ unsigned int sframe : 1,
+ poll : 1,
+ final : 1,
+ fcs : 1,
+ sar : 2,
+ super : 2;
+ __u16 reqseq;
+ __u16 txseq;
+ __u8 retries;
+};
+
struct bt_skb_cb {
__u8 pkt_type;
__u8 incoming;
__u16 expect;
- __u16 tx_seq;
- __u8 retries;
- __u8 sar;
__u8 force_active;
+ struct l2cap_ctrl control;
};
#define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb))
@@ -243,12 +261,10 @@ static inline struct sk_buff *bt_skb_send_alloc(struct sock *sk,
{
struct sk_buff *skb;
- release_sock(sk);
if ((skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err))) {
skb_reserve(skb, BT_SKB_RESERVE);
bt_cb(skb)->incoming = 0;
}
- lock_sock(sk);
if (!skb && *err)
return NULL;
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index d47e523c9d83..66a7b579e31c 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -102,6 +102,7 @@ enum {
HCI_DISCOVERABLE,
HCI_LINK_SECURITY,
HCI_PENDING_CLASS,
+ HCI_PERIODIC_INQ,
};
/* HCI ioctl defines */
@@ -324,6 +325,8 @@ struct hci_cp_inquiry {
#define HCI_OP_INQUIRY_CANCEL 0x0402
+#define HCI_OP_PERIODIC_INQ 0x0403
+
#define HCI_OP_EXIT_PERIODIC_INQ 0x0404
#define HCI_OP_CREATE_CONN 0x0405
@@ -717,6 +720,10 @@ struct hci_rp_read_local_oob_data {
} __packed;
#define HCI_OP_READ_INQ_RSP_TX_POWER 0x0c58
+struct hci_rp_read_inq_rsp_tx_power {
+ __u8 status;
+ __s8 tx_power;
+} __packed;
#define HCI_OP_READ_FLOW_CONTROL_MODE 0x0c66
struct hci_rp_read_flow_control_mode {
@@ -1431,6 +1438,5 @@ struct hci_inquiry_req {
#define IREQ_CACHE_FLUSH 0x0001
extern bool enable_hs;
-extern bool enable_le;
#endif /* __HCI_H */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index db1c5df45224..9fc7728f94e4 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -155,9 +155,14 @@ struct hci_dev {
__u16 hci_rev;
__u8 lmp_ver;
__u16 manufacturer;
- __le16 lmp_subver;
+ __u16 lmp_subver;
__u16 voice_setting;
__u8 io_capability;
+ __s8 inq_tx_power;
+ __u16 devid_source;
+ __u16 devid_vendor;
+ __u16 devid_product;
+ __u16 devid_version;
__u16 pkt_type;
__u16 esco_type;
@@ -250,9 +255,6 @@ struct hci_dev {
struct list_head remote_oob_data;
- struct list_head adv_entries;
- struct delayed_work adv_work;
-
struct hci_dev_stats stat;
struct sk_buff_head driver_init;
@@ -263,7 +265,6 @@ struct hci_dev {
struct dentry *debugfs;
- struct device *parent;
struct device dev;
struct rfkill *rfkill;
@@ -571,7 +572,7 @@ int hci_chan_del(struct hci_chan *chan);
void hci_chan_list_flush(struct hci_conn *conn);
struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
- __u8 sec_level, __u8 auth_type);
+ __u8 dst_type, __u8 sec_level, __u8 auth_type);
int hci_conn_check_link_mode(struct hci_conn *conn);
int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level);
int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type);
@@ -673,8 +674,8 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len);
struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]);
int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type,
- int new_key, u8 authenticated, u8 tk[16], u8 enc_size, u16 ediv,
- u8 rand[8]);
+ int new_key, u8 authenticated, u8 tk[16], u8 enc_size,
+ __le16 ediv, u8 rand[8]);
struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 addr_type);
int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr);
@@ -688,14 +689,6 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
u8 *randomizer);
int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr);
-#define ADV_CLEAR_TIMEOUT (3*60*HZ) /* Three minutes */
-int hci_adv_entries_clear(struct hci_dev *hdev);
-struct adv_entry *hci_find_adv_entry(struct hci_dev *hdev, bdaddr_t *bdaddr);
-int hci_add_adv_entry(struct hci_dev *hdev,
- struct hci_ev_le_advertising_info *ev);
-
-void hci_del_off_timer(struct hci_dev *hdev);
-
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
int hci_recv_frame(struct sk_buff *skb);
@@ -709,7 +702,7 @@ void hci_conn_init_sysfs(struct hci_conn *conn);
void hci_conn_add_sysfs(struct hci_conn *conn);
void hci_conn_del_sysfs(struct hci_conn *conn);
-#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->parent = (pdev))
+#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->dev.parent = (pdev))
/* ----- LMP capabilities ----- */
#define lmp_rswitch_capable(dev) ((dev)->features[0] & LMP_RSWITCH)
@@ -933,6 +926,23 @@ static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type)
return false;
}
+static inline size_t eir_get_length(u8 *eir, size_t eir_len)
+{
+ size_t parsed = 0;
+
+ while (parsed < eir_len) {
+ u8 field_len = eir[0];
+
+ if (field_len == 0)
+ return parsed;
+
+ parsed += field_len + 1;
+ eir += field_len + 1;
+ }
+
+ return eir_len;
+}
+
static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
u8 data_len)
{
@@ -961,17 +971,12 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb);
void hci_sock_dev_event(struct hci_dev *hdev, int event);
/* Management interface */
-#define MGMT_ADDR_BREDR 0x00
-#define MGMT_ADDR_LE_PUBLIC 0x01
-#define MGMT_ADDR_LE_RANDOM 0x02
-#define MGMT_ADDR_INVALID 0xff
-
-#define DISCOV_TYPE_BREDR (BIT(MGMT_ADDR_BREDR))
-#define DISCOV_TYPE_LE (BIT(MGMT_ADDR_LE_PUBLIC) | \
- BIT(MGMT_ADDR_LE_RANDOM))
-#define DISCOV_TYPE_INTERLEAVED (BIT(MGMT_ADDR_BREDR) | \
- BIT(MGMT_ADDR_LE_PUBLIC) | \
- BIT(MGMT_ADDR_LE_RANDOM))
+#define DISCOV_TYPE_BREDR (BIT(BDADDR_BREDR))
+#define DISCOV_TYPE_LE (BIT(BDADDR_LE_PUBLIC) | \
+ BIT(BDADDR_LE_RANDOM))
+#define DISCOV_TYPE_INTERLEAVED (BIT(BDADDR_BREDR) | \
+ BIT(BDADDR_LE_PUBLIC) | \
+ BIT(BDADDR_LE_RANDOM))
int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
int mgmt_index_added(struct hci_dev *hdev);
@@ -1067,12 +1072,12 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
u16 latency, u16 to_multiplier);
void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
__u8 ltk[16]);
-void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16]);
-void hci_le_ltk_neg_reply(struct hci_conn *conn);
-
int hci_do_inquiry(struct hci_dev *hdev, u8 length);
int hci_cancel_inquiry(struct hci_dev *hdev);
int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window,
int timeout);
+int hci_cancel_le_scan(struct hci_dev *hdev);
+
+u8 bdaddr_to_le(u8 bdaddr_type);
#endif /* __HCI_CORE_H */
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 9b242c6bf55b..1c7d1cd5e679 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -44,6 +44,7 @@
#define L2CAP_DEFAULT_MAX_SDU_SIZE 0xFFFF
#define L2CAP_DEFAULT_SDU_ITIME 0xFFFFFFFF
#define L2CAP_DEFAULT_ACC_LAT 0xFFFFFFFF
+#define L2CAP_BREDR_MAX_PAYLOAD 1019 /* 3-DH5 packet */
#define L2CAP_DISC_TIMEOUT msecs_to_jiffies(100)
#define L2CAP_DISC_REJ_TIMEOUT msecs_to_jiffies(5000)
@@ -57,6 +58,7 @@ struct sockaddr_l2 {
__le16 l2_psm;
bdaddr_t l2_bdaddr;
__le16 l2_cid;
+ __u8 l2_bdaddr_type;
};
/* L2CAP socket options */
@@ -139,6 +141,8 @@ struct l2cap_conninfo {
#define L2CAP_CTRL_TXSEQ_SHIFT 1
#define L2CAP_CTRL_SUPER_SHIFT 2
+#define L2CAP_CTRL_POLL_SHIFT 4
+#define L2CAP_CTRL_FINAL_SHIFT 7
#define L2CAP_CTRL_REQSEQ_SHIFT 8
#define L2CAP_CTRL_SAR_SHIFT 14
@@ -152,9 +156,11 @@ struct l2cap_conninfo {
#define L2CAP_EXT_CTRL_FINAL 0x00000002
#define L2CAP_EXT_CTRL_FRAME_TYPE 0x00000001 /* I- or S-Frame */
+#define L2CAP_EXT_CTRL_FINAL_SHIFT 1
#define L2CAP_EXT_CTRL_REQSEQ_SHIFT 2
#define L2CAP_EXT_CTRL_SAR_SHIFT 16
#define L2CAP_EXT_CTRL_SUPER_SHIFT 16
+#define L2CAP_EXT_CTRL_POLL_SHIFT 18
#define L2CAP_EXT_CTRL_TXSEQ_SHIFT 18
/* L2CAP Supervisory Function */
@@ -186,6 +192,8 @@ struct l2cap_hdr {
#define L2CAP_FCS_SIZE 2
#define L2CAP_SDULEN_SIZE 2
#define L2CAP_PSMLEN_SIZE 2
+#define L2CAP_ENH_CTRL_SIZE 2
+#define L2CAP_EXT_CTRL_SIZE 4
struct l2cap_cmd_hdr {
__u8 code;
@@ -401,6 +409,16 @@ struct l2cap_conn_param_update_rsp {
#define L2CAP_CONN_PARAM_REJECTED 0x0001
/* ----- L2CAP channels and connections ----- */
+struct l2cap_seq_list {
+ __u16 head;
+ __u16 tail;
+ __u16 mask;
+ __u16 *list;
+};
+
+#define L2CAP_SEQ_LIST_CLEAR 0xFFFF
+#define L2CAP_SEQ_LIST_TAIL 0x8000
+
struct srej_list {
__u16 tx_seq;
struct list_head list;
@@ -446,6 +464,9 @@ struct l2cap_chan {
__u16 monitor_timeout;
__u16 mps;
+ __u8 tx_state;
+ __u8 rx_state;
+
unsigned long conf_state;
unsigned long conn_state;
unsigned long flags;
@@ -456,9 +477,11 @@ struct l2cap_chan {
__u16 buffer_seq;
__u16 buffer_seq_srej;
__u16 srej_save_reqseq;
+ __u16 last_acked_seq;
__u16 frames_sent;
__u16 unacked_frames;
__u8 retry_count;
+ __u16 srej_queue_next;
__u8 num_acked;
__u16 sdu_len;
struct sk_buff *sdu;
@@ -490,6 +513,8 @@ struct l2cap_chan {
struct sk_buff *tx_send_head;
struct sk_buff_head tx_q;
struct sk_buff_head srej_q;
+ struct l2cap_seq_list srej_list;
+ struct l2cap_seq_list retrans_list;
struct list_head srej_l;
struct list_head list;
@@ -508,8 +533,7 @@ struct l2cap_ops {
void (*close) (void *data);
void (*state_change) (void *data, int state);
struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan,
- unsigned long len, int nb, int *err);
-
+ unsigned long len, int nb);
};
struct l2cap_conn {
@@ -600,6 +624,44 @@ enum {
FLAG_EFS_ENABLE,
};
+enum {
+ L2CAP_TX_STATE_XMIT,
+ L2CAP_TX_STATE_WAIT_F,
+};
+
+enum {
+ L2CAP_RX_STATE_RECV,
+ L2CAP_RX_STATE_SREJ_SENT,
+};
+
+enum {
+ L2CAP_TXSEQ_EXPECTED,
+ L2CAP_TXSEQ_EXPECTED_SREJ,
+ L2CAP_TXSEQ_UNEXPECTED,
+ L2CAP_TXSEQ_UNEXPECTED_SREJ,
+ L2CAP_TXSEQ_DUPLICATE,
+ L2CAP_TXSEQ_DUPLICATE_SREJ,
+ L2CAP_TXSEQ_INVALID,
+ L2CAP_TXSEQ_INVALID_IGNORE,
+};
+
+enum {
+ L2CAP_EV_DATA_REQUEST,
+ L2CAP_EV_LOCAL_BUSY_DETECTED,
+ L2CAP_EV_LOCAL_BUSY_CLEAR,
+ L2CAP_EV_RECV_REQSEQ_AND_FBIT,
+ L2CAP_EV_RECV_FBIT,
+ L2CAP_EV_RETRANS_TO,
+ L2CAP_EV_MONITOR_TO,
+ L2CAP_EV_EXPLICIT_POLL,
+ L2CAP_EV_RECV_IFRAME,
+ L2CAP_EV_RECV_RR,
+ L2CAP_EV_RECV_REJ,
+ L2CAP_EV_RECV_RNR,
+ L2CAP_EV_RECV_SREJ,
+ L2CAP_EV_RECV_FRAME,
+};
+
static inline void l2cap_chan_hold(struct l2cap_chan *c)
{
atomic_inc(&c->refcnt);
@@ -622,21 +684,26 @@ static inline void l2cap_chan_unlock(struct l2cap_chan *chan)
}
static inline void l2cap_set_timer(struct l2cap_chan *chan,
- struct delayed_work *work, long timeout)
+ struct delayed_work *work, long timeout)
{
BT_DBG("chan %p state %s timeout %ld", chan,
- state_to_string(chan->state), timeout);
+ state_to_string(chan->state), timeout);
+ /* If delayed work cancelled do not hold(chan)
+ since it is already done with previous set_timer */
if (!cancel_delayed_work(work))
l2cap_chan_hold(chan);
+
schedule_delayed_work(work, timeout);
}
static inline bool l2cap_clear_timer(struct l2cap_chan *chan,
- struct delayed_work *work)
+ struct delayed_work *work)
{
bool ret;
+ /* put(chan) if delayed work cancelled otherwise it
+ is done in delayed work function */
ret = cancel_delayed_work(work);
if (ret)
l2cap_chan_put(chan);
@@ -658,13 +725,10 @@ static inline bool l2cap_clear_timer(struct l2cap_chan *chan,
static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2)
{
- int offset;
-
- offset = (seq1 - seq2) % (chan->tx_win_max + 1);
- if (offset < 0)
- offset += (chan->tx_win_max + 1);
-
- return offset;
+ if (seq1 >= seq2)
+ return seq1 - seq2;
+ else
+ return chan->tx_win_max + 1 - seq2 + seq1;
}
static inline __u16 __next_seq(struct l2cap_chan *chan, __u16 seq)
@@ -852,14 +916,15 @@ int __l2cap_wait_ack(struct sock *sk);
int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm);
int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid);
-struct l2cap_chan *l2cap_chan_create(struct sock *sk);
+struct l2cap_chan *l2cap_chan_create(void);
void l2cap_chan_close(struct l2cap_chan *chan, int reason);
void l2cap_chan_destroy(struct l2cap_chan *chan);
int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
- bdaddr_t *dst);
+ bdaddr_t *dst, u8 dst_type);
int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
u32 priority);
void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
int l2cap_chan_check_security(struct l2cap_chan *chan);
+void l2cap_chan_set_defaults(struct l2cap_chan *chan);
#endif /* __L2CAP_H */
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index ebfd91fc20f8..23fd0546fccb 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -341,6 +341,15 @@ struct mgmt_cp_unblock_device {
} __packed;
#define MGMT_UNBLOCK_DEVICE_SIZE MGMT_ADDR_INFO_SIZE
+#define MGMT_OP_SET_DEVICE_ID 0x0028
+struct mgmt_cp_set_device_id {
+ __le16 source;
+ __le16 vendor;
+ __le16 product;
+ __le16 version;
+} __packed;
+#define MGMT_SET_DEVICE_ID_SIZE 8
+
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
diff --git a/include/net/bluetooth/smp.h b/include/net/bluetooth/smp.h
index 7b3acdd29134..ca356a734920 100644
--- a/include/net/bluetooth/smp.h
+++ b/include/net/bluetooth/smp.h
@@ -77,7 +77,7 @@ struct smp_cmd_encrypt_info {
#define SMP_CMD_MASTER_IDENT 0x07
struct smp_cmd_master_ident {
- __u16 ediv;
+ __le16 ediv;
__u8 rand[8];
} __packed;
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index adb2320bccdf..0289d4ce7070 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -3365,9 +3365,9 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy,
* @chan: main channel
* @channel_type: HT mode
*/
-int cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
- struct ieee80211_channel *chan,
- enum nl80211_channel_type channel_type);
+bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type);
/*
* cfg80211_ch_switch_notify - update wdev channel and notify userspace
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 4d6e6c6818d0..1937c7d98304 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -667,6 +667,9 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
* @RX_FLAG_SHORT_GI: Short guard interval was used
* @RX_FLAG_NO_SIGNAL_VAL: The signal strength value is not present.
* Valid only for data frames (mainly A-MPDU)
+ * @RX_FLAG_HT_GF: This frame was received in a HT-greenfield transmission, if
+ * the driver fills this value it should add %IEEE80211_RADIOTAP_MCS_HAVE_FMT
+ * to hw.radiotap_mcs_details to advertise that fact
*/
enum mac80211_rx_flags {
RX_FLAG_MMIC_ERROR = 1<<0,
@@ -681,6 +684,7 @@ enum mac80211_rx_flags {
RX_FLAG_40MHZ = 1<<10,
RX_FLAG_SHORT_GI = 1<<11,
RX_FLAG_NO_SIGNAL_VAL = 1<<12,
+ RX_FLAG_HT_GF = 1<<13,
};
/**
@@ -939,7 +943,7 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
* CCMP key if it requires CCMP encryption of management frames (MFP) to
* be done in software.
* @IEEE80211_KEY_FLAG_PUT_IV_SPACE: This flag should be set by the driver
- * for a CCMP key if space should be prepared for the IV, but the IV
+ * if space should be prepared for the IV, but the IV
* itself should not be generated. Do not set together with
* @IEEE80211_KEY_FLAG_GENERATE_IV on the same key.
*/
@@ -1288,6 +1292,11 @@ enum ieee80211_hw_flags {
*
* @offchannel_tx_hw_queue: HW queue ID to use for offchannel TX
* (if %IEEE80211_HW_QUEUE_CONTROL is set)
+ *
+ * @radiotap_mcs_details: lists which MCS information can the HW
+ * reports, by default it is set to _MCS, _GI and _BW but doesn't
+ * include _FMT. Use %IEEE80211_RADIOTAP_MCS_HAVE_* values, only
+ * adding _BW is supported today.
*/
struct ieee80211_hw {
struct ieee80211_conf conf;
@@ -1309,6 +1318,7 @@ struct ieee80211_hw {
u8 max_rx_aggregation_subframes;
u8 max_tx_aggregation_subframes;
u8 offchannel_tx_hw_queue;
+ u8 radiotap_mcs_details;
};
/**
diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h
index aca65a5a9d0d..4467c9460857 100644
--- a/include/net/nfc/hci.h
+++ b/include/net/nfc/hci.h
@@ -39,6 +39,8 @@ struct nfc_hci_ops {
int (*data_exchange) (struct nfc_hci_dev *hdev,
struct nfc_target *target,
struct sk_buff *skb, struct sk_buff **res_skb);
+ int (*check_presence)(struct nfc_hci_dev *hdev,
+ struct nfc_target *target);
};
#define NFC_HCI_MAX_CUSTOM_GATES 15
@@ -82,10 +84,6 @@ struct nfc_hci_dev {
u8 gate2pipe[NFC_HCI_MAX_GATES];
- bool poll_started;
- struct nfc_target *targets;
- int target_count;
-
u8 sw_romlib;
u8 sw_patch;
u8 sw_flashlib_major;
diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h
index 9a2505a5b8de..b7ca4a2a1d72 100644
--- a/include/net/nfc/nfc.h
+++ b/include/net/nfc/nfc.h
@@ -48,26 +48,28 @@ struct nfc_dev;
typedef void (*data_exchange_cb_t)(void *context, struct sk_buff *skb,
int err);
+struct nfc_target;
+
struct nfc_ops {
int (*dev_up)(struct nfc_dev *dev);
int (*dev_down)(struct nfc_dev *dev);
int (*start_poll)(struct nfc_dev *dev, u32 protocols);
void (*stop_poll)(struct nfc_dev *dev);
- int (*dep_link_up)(struct nfc_dev *dev, int target_idx, u8 comm_mode,
- u8 *gb, size_t gb_len);
+ int (*dep_link_up)(struct nfc_dev *dev, struct nfc_target *target,
+ u8 comm_mode, u8 *gb, size_t gb_len);
int (*dep_link_down)(struct nfc_dev *dev);
- int (*activate_target)(struct nfc_dev *dev, u32 target_idx,
+ int (*activate_target)(struct nfc_dev *dev, struct nfc_target *target,
u32 protocol);
- void (*deactivate_target)(struct nfc_dev *dev, u32 target_idx);
- int (*data_exchange)(struct nfc_dev *dev, u32 target_idx,
+ void (*deactivate_target)(struct nfc_dev *dev,
+ struct nfc_target *target);
+ int (*data_exchange)(struct nfc_dev *dev, struct nfc_target *target,
struct sk_buff *skb, data_exchange_cb_t cb,
void *cb_context);
- int (*check_presence)(struct nfc_dev *dev, u32 target_idx);
+ int (*check_presence)(struct nfc_dev *dev, struct nfc_target *target);
};
#define NFC_TARGET_IDX_ANY -1
#define NFC_MAX_GT_LEN 48
-#define NFC_TARGET_IDX_NONE 0xffffffff
struct nfc_target {
u32 idx;
@@ -95,11 +97,10 @@ struct nfc_dev {
struct nfc_target *targets;
int n_targets;
int targets_generation;
- spinlock_t targets_lock;
struct device dev;
bool dev_up;
bool polling;
- u32 activated_target_idx;
+ struct nfc_target *active_target;
bool dep_link_up;
u32 dep_rf_mode;
struct nfc_genl_data genl_data;
diff --git a/include/net/nfc/shdlc.h b/include/net/nfc/shdlc.h
index 1071987d0408..ab06afd462da 100644
--- a/include/net/nfc/shdlc.h
+++ b/include/net/nfc/shdlc.h
@@ -35,6 +35,8 @@ struct nfc_shdlc_ops {
int (*data_exchange) (struct nfc_shdlc *shdlc,
struct nfc_target *target,
struct sk_buff *skb, struct sk_buff **res_skb);
+ int (*check_presence)(struct nfc_shdlc *shdlc,
+ struct nfc_target *target);
};
enum shdlc_state {
diff --git a/include/net/sock.h b/include/net/sock.h
index da931555e000..d89f0582b6b6 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -70,16 +70,16 @@
struct cgroup;
struct cgroup_subsys;
#ifdef CONFIG_NET
-int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss);
-void mem_cgroup_sockets_destroy(struct cgroup *cgrp);
+int mem_cgroup_sockets_init(struct mem_cgroup *memcg, struct cgroup_subsys *ss);
+void mem_cgroup_sockets_destroy(struct mem_cgroup *memcg);
#else
static inline
-int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss)
+int mem_cgroup_sockets_init(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
{
return 0;
}
static inline
-void mem_cgroup_sockets_destroy(struct cgroup *cgrp)
+void mem_cgroup_sockets_destroy(struct mem_cgroup *memcg)
{
}
#endif
@@ -914,9 +914,9 @@ struct proto {
* This function has to setup any files the protocol want to
* appear in the kmem cgroup filesystem.
*/
- int (*init_cgroup)(struct cgroup *cgrp,
+ int (*init_cgroup)(struct mem_cgroup *memcg,
struct cgroup_subsys *ss);
- void (*destroy_cgroup)(struct cgroup *cgrp);
+ void (*destroy_cgroup)(struct mem_cgroup *memcg);
struct cg_proto *(*proto_cgroup)(struct mem_cgroup *memcg);
#endif
};
diff --git a/include/net/tcp_memcontrol.h b/include/net/tcp_memcontrol.h
index 48410ff25c9e..7df18bc43a97 100644
--- a/include/net/tcp_memcontrol.h
+++ b/include/net/tcp_memcontrol.h
@@ -12,8 +12,8 @@ struct tcp_memcontrol {
};
struct cg_proto *tcp_proto_cgroup(struct mem_cgroup *memcg);
-int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss);
-void tcp_destroy_cgroup(struct cgroup *cgrp);
+int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss);
+void tcp_destroy_cgroup(struct mem_cgroup *memcg);
unsigned long long tcp_max_memory(const struct mem_cgroup *memcg);
void tcp_prot_mem(struct mem_cgroup *memcg, long val, int idx);
#endif /* _TCP_MEMCG_H */
diff --git a/include/sound/asound.h b/include/sound/asound.h
index a2e4ff5ba9e9..0876a1e76aef 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -70,6 +70,20 @@ struct snd_aes_iec958 {
/****************************************************************************
* *
+ * CEA-861 Audio InfoFrame. Used in HDMI and DisplayPort *
+ * *
+ ****************************************************************************/
+
+struct snd_cea_861_aud_if {
+ unsigned char db1_ct_cc; /* coding type and channel count */
+ unsigned char db2_sf_ss; /* sample frequency and size */
+ unsigned char db3; /* not used, all zeros */
+ unsigned char db4_ca; /* channel allocation code */
+ unsigned char db5_dminh_lsv; /* downmix inhibit & level-shit values */
+};
+
+/****************************************************************************
+ * *
* Section for driver hardware dependent interface - /dev/snd/hw? *
* *
****************************************************************************/
diff --git a/include/sound/asoundef.h b/include/sound/asoundef.h
index 20ebf3298eba..bb05c02f89b0 100644
--- a/include/sound/asoundef.h
+++ b/include/sound/asoundef.h
@@ -170,6 +170,47 @@
#define IEC958_AES5_CON_CGMSA_COPYNOMORE (2<<0) /* condition not be used */
#define IEC958_AES5_CON_CGMSA_COPYNEVER (3<<0) /* no copying is permitted */
+/****************************************************************************
+ * *
+ * CEA-861 Audio InfoFrame. Used in HDMI and DisplayPort *
+ * *
+ ****************************************************************************/
+#define CEA861_AUDIO_INFOFRAME_DB1CC (7<<0) /* mask - channel count */
+#define CEA861_AUDIO_INFOFRAME_DB1CT (0xf<<4) /* mask - coding type */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM (0<<4) /* refer to stream */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_IEC60958 (1<<4) /* IEC-60958 L-PCM */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_AC3 (2<<4) /* AC-3 */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_MPEG1 (3<<4) /* MPEG1 Layers 1 & 2 */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_MP3 (4<<4) /* MPEG1 Layer 3 */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_MPEG2_MULTICH (5<<4) /* MPEG2 Multichannel */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_AAC (6<<4) /* AAC */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_DTS (7<<4) /* DTS */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_ATRAC (8<<4) /* ATRAC */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_ONEBIT (9<<4) /* One Bit Audio */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_DOLBY_DIG_PLUS (10<<4) /* Dolby Digital + */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_DTS_HD (11<<4) /* DTS-HD */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_MAT (12<<4) /* MAT (MLP) */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_DST (13<<4) /* DST */
+#define CEA861_AUDIO_INFOFRAME_DB1CT_WMA_PRO (14<<4) /* WMA Pro */
+#define CEA861_AUDIO_INFOFRAME_DB2SF (7<<2) /* mask - sample frequency */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM (0<<2) /* refer to stream */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_32000 (1<<2) /* 32kHz */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_44100 (2<<2) /* 44.1kHz */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_48000 (3<<2) /* 48kHz */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_88200 (4<<2) /* 88.2kHz */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_96000 (5<<2) /* 96kHz */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_176400 (6<<2) /* 176.4kHz */
+#define CEA861_AUDIO_INFOFRAME_DB2SF_192000 (7<<2) /* 192kHz */
+#define CEA861_AUDIO_INFOFRAME_DB2SS (3<<0) /* mask - sample size */
+#define CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM (0<<0) /* refer to stream */
+#define CEA861_AUDIO_INFOFRAME_DB2SS_16BIT (1<<0) /* 16 bits */
+#define CEA861_AUDIO_INFOFRAME_DB2SS_20BIT (2<<0) /* 20 bits */
+#define CEA861_AUDIO_INFOFRAME_DB2SS_24BIT (3<<0) /* 24 bits */
+#define CEA861_AUDIO_INFOFRAME_DB5_DM_INH (1<<7) /* mask - inhibit downmixing */
+#define CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PERMITTED (0<<7) /* stereo downmix permitted */
+#define CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED (1<<7) /* stereo downmis prohibited */
+#define CEA861_AUDIO_INFOFRAME_DB5_LSV (0xf<<3) /* mask - level-shift values */
+
/*****************************************************************************
* *
* MIDI v1.0 interface *
diff --git a/include/sound/cs42l52.h b/include/sound/cs42l52.h
new file mode 100644
index 000000000000..4c68955f7330
--- /dev/null
+++ b/include/sound/cs42l52.h
@@ -0,0 +1,36 @@
+/*
+ * linux/sound/cs42l52.h -- Platform data for CS42L52
+ *
+ * Copyright (c) 2012 Cirrus Logic Inc.
+ *
+ * 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 __CS42L52_H
+#define __CS42L52_H
+
+struct cs42l52_platform_data {
+
+ /* MICBIAS Level. Check datasheet Pg48 */
+ unsigned int micbias_lvl;
+
+ /* MICA mode selection 0=Single 1=Differential */
+ unsigned int mica_cfg;
+
+ /* MICB mode selection 0=Single 1=Differential */
+ unsigned int micb_cfg;
+
+ /* MICA Select 0=MIC1A 1=MIC2A */
+ unsigned int mica_sel;
+
+ /* MICB Select 0=MIC2A 1=MIC2B */
+ unsigned int micb_sel;
+
+ /* Charge Pump Freq. Check datasheet Pg73 */
+ unsigned int chgfreq;
+
+};
+
+#endif /* __CS42L52_H */
diff --git a/include/sound/max98095.h b/include/sound/max98095.h
index 7513a42dd4aa..e87ae67b0a55 100644
--- a/include/sound/max98095.h
+++ b/include/sound/max98095.h
@@ -49,6 +49,18 @@ struct max98095_pdata {
*/
unsigned int digmic_left_mode:1;
unsigned int digmic_right_mode:1;
+
+ /* Pin5 is the mechanical method of sensing jack insertion
+ * but it is something that might not be supported.
+ * 0 = PIN5 not supported
+ * 1 = PIN5 supported
+ */
+ unsigned int jack_detect_pin5en:1;
+
+ /* Slew amount for jack detection. Calculated as 4 * (delay + 1).
+ * Default delay is 24 to get a time of 100ms.
+ */
+ unsigned int jack_detect_delay;
};
#endif
diff --git a/include/sound/sh_fsi.h b/include/sound/sh_fsi.h
index b457e87fbd08..906010344dd7 100644
--- a/include/sound/sh_fsi.h
+++ b/include/sound/sh_fsi.h
@@ -21,10 +21,11 @@
/*
* flags format
*
- * 0x000000BA
+ * 0x00000CBA
*
* A: inversion
* B: format mode
+ * C: chip specific
*/
/* A: clock inversion */
@@ -39,6 +40,9 @@
#define SH_FSI_FMT_DAI (0 << 4)
#define SH_FSI_FMT_SPDIF (1 << 4)
+/* C: chip specific */
+#define SH_FSI_OPTION_MASK 0x00000F00
+#define SH_FSI_ENABLE_STREAM_MODE (1 << 8) /* for 16bit data */
/*
* set_rate return value
@@ -84,16 +88,4 @@ struct sh_fsi_platform_info {
struct sh_fsi_port_info port_b;
};
-/*
- * for fsi-ak4642
- */
-struct fsi_ak4642_info {
- const char *name;
- const char *card;
- const char *cpu_dai;
- const char *codec;
- const char *platform;
- int id;
-};
-
#endif /* __SOUND_FSI_H */
diff --git a/include/sound/simple_card.h b/include/sound/simple_card.h
new file mode 100644
index 000000000000..4b62b8dc6a4f
--- /dev/null
+++ b/include/sound/simple_card.h
@@ -0,0 +1,38 @@
+/*
+ * ASoC simple sound card support
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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 __SIMPLE_CARD_H
+#define __SIMPLE_CARD_H
+
+#include <sound/soc.h>
+
+struct asoc_simple_dai_init_info {
+ unsigned int fmt;
+ unsigned int cpu_daifmt;
+ unsigned int codec_daifmt;
+ unsigned int sysclk;
+};
+
+struct asoc_simple_card_info {
+ const char *name;
+ const char *card;
+ const char *cpu_dai;
+ const char *codec;
+ const char *platform;
+ const char *codec_dai;
+ struct asoc_simple_dai_init_info *init; /* for snd_link.init */
+
+ /* used in simple-card.c */
+ struct snd_soc_dai_link snd_link;
+ struct snd_soc_card snd_card;
+};
+
+#endif /* __SIMPLE_CARD_H */
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index c429f248cf4e..1f69e0af2941 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -173,6 +173,8 @@ struct snd_soc_dai_ops {
struct snd_soc_dai *);
int (*trigger)(struct snd_pcm_substream *, int,
struct snd_soc_dai *);
+ int (*bespoke_trigger)(struct snd_pcm_substream *, int,
+ struct snd_soc_dai *);
/*
* For hardware based FIFO caused delay reporting.
* Optional.
@@ -196,6 +198,7 @@ struct snd_soc_dai_driver {
const char *name;
unsigned int id;
int ac97_control;
+ unsigned int base;
/* DAI driver callbacks */
int (*probe)(struct snd_soc_dai *dai);
@@ -241,6 +244,7 @@ struct snd_soc_dai {
struct snd_soc_dapm_widget *playback_widget;
struct snd_soc_dapm_widget *capture_widget;
+ struct snd_soc_dapm_context dapm;
/* DAI DMA data */
void *playback_dma_data;
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 8da3c2409060..e3833d9f1914 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -141,10 +141,6 @@ struct device;
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrol_news = wcontrols, \
.num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags}
-#define SND_SOC_DAPM_MICBIAS_E(wname, wreg, wshift, winvert, wevent, wflags) \
-{ .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
- .invert = winvert, .kcontrol_news = NULL, .num_kcontrols = 0, \
- .event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \
wevent, wflags) \
{ .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
@@ -324,6 +320,8 @@ struct snd_soc_dapm_path;
struct snd_soc_dapm_pin;
struct snd_soc_dapm_route;
struct snd_soc_dapm_context;
+struct regulator;
+struct snd_soc_dapm_widget_list;
int dapm_reg_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
@@ -359,6 +357,10 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
struct snd_soc_dai *dai);
int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card);
+int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
+ const struct snd_soc_pcm_stream *params,
+ struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink);
/* dapm path setup */
int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm);
@@ -369,8 +371,8 @@ int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route, int num);
/* dapm events */
-int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
- struct snd_soc_dai *dai, int event);
+void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
+ int event);
void snd_soc_dapm_shutdown(struct snd_soc_card *card);
/* external DAPM widget events */
@@ -402,6 +404,10 @@ void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec);
/* Mostly internal - should not normally be used */
void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason);
+/* dapm path query */
+int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
+ struct snd_soc_dapm_widget_list **list);
+
/* dapm widget types */
enum snd_soc_dapm_type {
snd_soc_dapm_input = 0, /* input pin */
@@ -430,6 +436,12 @@ enum snd_soc_dapm_type {
snd_soc_dapm_aif_out, /* audio interface output */
snd_soc_dapm_siggen, /* signal generator */
snd_soc_dapm_dai, /* link to DAI structure */
+ snd_soc_dapm_dai_link, /* link between two DAI structures */
+};
+
+enum snd_soc_dapm_subclass {
+ SND_SOC_DAPM_CLASS_INIT = 0,
+ SND_SOC_DAPM_CLASS_RUNTIME = 1,
};
/*
@@ -482,9 +494,11 @@ struct snd_soc_dapm_widget {
struct snd_soc_dapm_context *dapm;
void *priv; /* widget specific data */
+ struct regulator *regulator; /* attached regulator */
+ const struct snd_soc_pcm_stream *params; /* params for dai links */
/* dapm control */
- short reg; /* negative reg = no direct dapm */
+ int reg; /* negative reg = no direct dapm */
unsigned char shift; /* bits to shift */
unsigned int saved_value; /* widget saved value */
unsigned int value; /* widget current value */
diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h
new file mode 100644
index 000000000000..04598f1efd77
--- /dev/null
+++ b/include/sound/soc-dpcm.h
@@ -0,0 +1,138 @@
+/*
+ * linux/sound/soc-dpcm.h -- ALSA SoC Dynamic PCM Support
+ *
+ * Author: Liam Girdwood <lrg@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.
+ */
+
+#ifndef __LINUX_SND_SOC_DPCM_H
+#define __LINUX_SND_SOC_DPCM_H
+
+#include <linux/list.h>
+#include <sound/pcm.h>
+
+struct snd_soc_pcm_runtime;
+
+/*
+ * Types of runtime_update to perform. e.g. originated from FE PCM ops
+ * or audio route changes triggered by muxes/mixers.
+ */
+enum snd_soc_dpcm_update {
+ SND_SOC_DPCM_UPDATE_NO = 0,
+ SND_SOC_DPCM_UPDATE_BE,
+ SND_SOC_DPCM_UPDATE_FE,
+};
+
+/*
+ * Dynamic PCM Frontend -> Backend link management states.
+ */
+enum snd_soc_dpcm_link_state {
+ SND_SOC_DPCM_LINK_STATE_NEW = 0, /* newly created link */
+ SND_SOC_DPCM_LINK_STATE_FREE, /* link to be dismantled */
+};
+
+/*
+ * Dynamic PCM Frontend -> Backend link PCM states.
+ */
+enum snd_soc_dpcm_state {
+ SND_SOC_DPCM_STATE_NEW = 0,
+ SND_SOC_DPCM_STATE_OPEN,
+ SND_SOC_DPCM_STATE_HW_PARAMS,
+ SND_SOC_DPCM_STATE_PREPARE,
+ SND_SOC_DPCM_STATE_START,
+ SND_SOC_DPCM_STATE_STOP,
+ SND_SOC_DPCM_STATE_PAUSED,
+ SND_SOC_DPCM_STATE_SUSPEND,
+ SND_SOC_DPCM_STATE_HW_FREE,
+ SND_SOC_DPCM_STATE_CLOSE,
+};
+
+/*
+ * Dynamic PCM trigger ordering. Triggering flexibility is required as some
+ * DSPs require triggering before/after their CPU platform and DAIs.
+ *
+ * i.e. some clients may want to manually order this call in their PCM
+ * trigger() whilst others will just use the regular core ordering.
+ */
+enum snd_soc_dpcm_trigger {
+ SND_SOC_DPCM_TRIGGER_PRE = 0,
+ SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_BESPOKE,
+};
+
+/*
+ * Dynamic PCM link
+ * This links together a FE and BE DAI at runtime and stores the link
+ * state information and the hw_params configuration.
+ */
+struct snd_soc_dpcm {
+ /* FE and BE DAIs*/
+ struct snd_soc_pcm_runtime *be;
+ struct snd_soc_pcm_runtime *fe;
+
+ /* link state */
+ enum snd_soc_dpcm_link_state state;
+
+ /* list of BE and FE for this DPCM link */
+ struct list_head list_be;
+ struct list_head list_fe;
+
+ /* hw params for this link - may be different for each link */
+ struct snd_pcm_hw_params hw_params;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs_state;
+#endif
+};
+
+/*
+ * Dynamic PCM runtime data.
+ */
+struct snd_soc_dpcm_runtime {
+ struct list_head be_clients;
+ struct list_head fe_clients;
+
+ int users;
+ struct snd_pcm_runtime *runtime;
+ struct snd_pcm_hw_params hw_params;
+
+ /* state and update */
+ enum snd_soc_dpcm_update runtime_update;
+ enum snd_soc_dpcm_state state;
+};
+
+/* can this BE stop and free */
+int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
+ struct snd_soc_pcm_runtime *be, int stream);
+
+/* can this BE perform a hw_params() */
+int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
+ struct snd_soc_pcm_runtime *be, int stream);
+
+/* is the current PCM operation for this FE ? */
+int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream);
+
+/* is the current PCM operation for this BE ? */
+int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
+ struct snd_soc_pcm_runtime *be, int stream);
+
+/* get the substream for this BE */
+struct snd_pcm_substream *
+ snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream);
+
+/* get the BE runtime state */
+enum snd_soc_dpcm_state
+ snd_soc_dpcm_be_get_state(struct snd_soc_pcm_runtime *be, int stream);
+
+/* set the BE runtime state */
+void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be, int stream,
+ enum snd_soc_dpcm_state state);
+
+/* internal use only */
+int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute);
+int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd);
+int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *);
+
+#endif
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 2ebf7877c148..c703871f5f65 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -55,6 +55,18 @@
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
.put = snd_soc_put_volsw, \
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
+#define SOC_SINGLE_SX_TLV(xname, xreg, xshift, xmin, xmax, tlv_array) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+ SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .tlv.p = (tlv_array),\
+ .info = snd_soc_info_volsw, \
+ .get = snd_soc_get_volsw_sx,\
+ .put = snd_soc_put_volsw_sx, \
+ .private_value = (unsigned long)&(struct soc_mixer_control) \
+ {.reg = xreg, .rreg = xreg, \
+ .shift = xshift, .rshift = xshift, \
+ .max = xmax, .min = xmin} }
#define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
@@ -85,6 +97,18 @@
.get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \
.private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
xmax, xinvert) }
+#define SOC_DOUBLE_R_SX_TLV(xname, xreg, xrreg, xshift, xmin, xmax, tlv_array) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+ SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .tlv.p = (tlv_array), \
+ .info = snd_soc_info_volsw, \
+ .get = snd_soc_get_volsw_sx, \
+ .put = snd_soc_put_volsw_sx, \
+ .private_value = (unsigned long)&(struct soc_mixer_control) \
+ {.reg = xreg, .rreg = xrreg, \
+ .shift = xshift, .rshift = xshift, \
+ .max = xmax, .min = xmin} }
#define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
@@ -171,20 +195,6 @@
.get = xhandler_get, .put = xhandler_put, \
.private_value = (unsigned long)&xenum }
-#define SOC_DOUBLE_R_SX_TLV(xname, xreg_left, xreg_right, xshift,\
- xmin, xmax, tlv_array) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
- .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
- SNDRV_CTL_ELEM_ACCESS_READWRITE, \
- .tlv.p = (tlv_array), \
- .info = snd_soc_info_volsw_2r_sx, \
- .get = snd_soc_get_volsw_2r_sx, \
- .put = snd_soc_put_volsw_2r_sx, \
- .private_value = (unsigned long)&(struct soc_mixer_control) \
- {.reg = xreg_left, \
- .rreg = xreg_right, .shift = xshift, \
- .min = xmin, .max = xmax} }
-
#define SND_SOC_BYTES(xname, xbase, xregs) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \
@@ -200,6 +210,19 @@
{.base = xbase, .num_regs = xregs, \
.mask = xmask }) }
+#define SOC_SINGLE_XR_SX(xname, xregbase, xregcount, xnbits, \
+ xmin, xmax, xinvert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .info = snd_soc_info_xr_sx, .get = snd_soc_get_xr_sx, \
+ .put = snd_soc_put_xr_sx, \
+ .private_value = (unsigned long)&(struct soc_mreg_control) \
+ {.regbase = xregbase, .regcount = xregcount, .nbits = xnbits, \
+ .invert = xinvert, .min = xmin, .max = xmax} }
+
+#define SOC_SINGLE_STROBE(xname, xreg, xshift, xinvert) \
+ SOC_SINGLE_EXT(xname, xreg, xshift, 1, xinvert, \
+ snd_soc_get_strobe, snd_soc_put_strobe)
+
/*
* Simplified versions of above macros, declaring a struct and calculating
* ARRAY_SIZE internally
@@ -264,6 +287,7 @@ struct snd_soc_jack_zone;
struct snd_soc_jack_pin;
struct snd_soc_cache_ops;
#include <sound/soc-dapm.h>
+#include <sound/soc-dpcm.h>
#ifdef CONFIG_GPIOLIB
struct snd_soc_jack_gpio;
@@ -288,6 +312,11 @@ enum snd_soc_pcm_subclass {
SND_SOC_PCM_CLASS_BE = 1,
};
+enum snd_soc_card_subclass {
+ SND_SOC_CARD_CLASS_INIT = 0,
+ SND_SOC_CARD_CLASS_RUNTIME = 1,
+};
+
int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id,
int source, unsigned int freq, int dir);
int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
@@ -333,6 +362,11 @@ int snd_soc_platform_write(struct snd_soc_platform *platform,
unsigned int reg, unsigned int val);
int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num);
+struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
+ const char *dai_link, int stream);
+struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
+ const char *dai_link);
+
/* Utility functions to get clock rates from various things */
int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
@@ -343,6 +377,9 @@ int snd_soc_params_to_bclk(struct snd_pcm_hw_params *parms);
int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
const struct snd_pcm_hardware *hw);
+int snd_soc_platform_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_platform *platform);
+
/* Jack reporting */
int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
struct snd_soc_jack *jack);
@@ -413,6 +450,10 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
#define snd_soc_get_volsw_2r snd_soc_get_volsw
#define snd_soc_put_volsw_2r snd_soc_put_volsw
+int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo);
int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
@@ -421,19 +462,22 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_limit_volume(struct snd_soc_codec *codec,
const char *name, int max);
-int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo);
-int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
-int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo);
int snd_soc_bytes_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
-
+int snd_soc_info_xr_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_soc_get_strobe(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_strobe(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
/**
* struct snd_soc_reg_access - Describes whether a given register is
@@ -513,6 +557,7 @@ struct snd_soc_jack_gpio {
#endif
struct snd_soc_jack {
+ struct mutex mutex;
struct snd_jack *jack;
struct snd_soc_codec *codec;
struct list_head pins;
@@ -711,6 +756,7 @@ struct snd_soc_platform_driver {
/* platform IO - used for platform DAPM */
unsigned int (*read)(struct snd_soc_platform *, unsigned int);
int (*write)(struct snd_soc_platform *, unsigned int, unsigned int);
+ int (*bespoke_trigger)(struct snd_pcm_substream *, int);
};
struct snd_soc_platform {
@@ -746,21 +792,36 @@ struct snd_soc_dai_link {
const char *cpu_dai_name;
const struct device_node *cpu_dai_of_node;
const char *codec_dai_name;
+ int be_id; /* optional ID for machine driver BE identification */
+
+ const struct snd_soc_pcm_stream *params;
unsigned int dai_fmt; /* format to set on init */
+ enum snd_soc_dpcm_trigger trigger[2]; /* trigger type for DPCM */
+
/* Keep DAI active over suspend */
unsigned int ignore_suspend:1;
/* Symmetry requirements */
unsigned int symmetric_rates:1;
+ /* Do not create a PCM for this DAI link (Backend link) */
+ unsigned int no_pcm:1;
+
+ /* This DAI link can route to other DAI links at runtime (Frontend)*/
+ unsigned int dynamic:1;
+
/* pmdown_time is ignored at stop */
unsigned int ignore_pmdown_time:1;
/* codec/machine specific init - e.g. add machine controls */
int (*init)(struct snd_soc_pcm_runtime *rtd);
+ /* optional hw_params re-writing for BE and FE sync */
+ int (*be_hw_params_fixup)(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params);
+
/* machine stream operations */
struct snd_soc_ops *ops;
};
@@ -800,6 +861,7 @@ struct snd_soc_card {
struct list_head list;
struct mutex mutex;
+ struct mutex dapm_mutex;
bool instantiated;
@@ -889,9 +951,11 @@ struct snd_soc_pcm_runtime {
enum snd_soc_pcm_subclass pcm_subclass;
struct snd_pcm_ops ops;
- unsigned int complete:1;
unsigned int dev_registered:1;
+ /* Dynamic PCM BE runtime data */
+ struct snd_soc_dpcm_runtime dpcm[2];
+
long pmdown_time;
/* runtime devices */
@@ -902,6 +966,10 @@ struct snd_soc_pcm_runtime {
struct snd_soc_dai *cpu_dai;
struct delayed_work delayed_work;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs_dpcm_root;
+ struct dentry *debugfs_dpcm_state;
+#endif
};
/* mixer control */
@@ -916,6 +984,12 @@ struct soc_bytes {
u32 mask;
};
+/* multi register control */
+struct soc_mreg_control {
+ long min, max;
+ unsigned int regbase, regcount, nbits, invert;
+};
+
/* enumerated kcontrol */
struct soc_enum {
unsigned short reg;
diff --git a/include/trace/events/asoc.h b/include/trace/events/asoc.h
index ab26f8aa3c78..5fc2dcdd21cd 100644
--- a/include/trace/events/asoc.h
+++ b/include/trace/events/asoc.h
@@ -7,6 +7,8 @@
#include <linux/ktime.h>
#include <linux/tracepoint.h>
+#define DAPM_DIRECT "(direct)"
+
struct snd_soc_jack;
struct snd_soc_codec;
struct snd_soc_platform;
@@ -241,6 +243,84 @@ TRACE_EVENT(snd_soc_dapm_walk_done,
(int)__entry->path_checks, (int)__entry->neighbour_checks)
);
+TRACE_EVENT(snd_soc_dapm_output_path,
+
+ TP_PROTO(struct snd_soc_dapm_widget *widget,
+ struct snd_soc_dapm_path *path),
+
+ TP_ARGS(widget, path),
+
+ TP_STRUCT__entry(
+ __string( wname, widget->name )
+ __string( pname, path->name ? path->name : DAPM_DIRECT)
+ __string( psname, path->sink->name )
+ __field( int, path_sink )
+ __field( int, path_connect )
+ ),
+
+ TP_fast_assign(
+ __assign_str(wname, widget->name);
+ __assign_str(pname, path->name ? path->name : DAPM_DIRECT);
+ __assign_str(psname, path->sink->name);
+ __entry->path_connect = path->connect;
+ __entry->path_sink = (long)path->sink;
+ ),
+
+ TP_printk("%c%s -> %s -> %s\n",
+ (int) __entry->path_sink &&
+ (int) __entry->path_connect ? '*' : ' ',
+ __get_str(wname), __get_str(pname), __get_str(psname))
+);
+
+TRACE_EVENT(snd_soc_dapm_input_path,
+
+ TP_PROTO(struct snd_soc_dapm_widget *widget,
+ struct snd_soc_dapm_path *path),
+
+ TP_ARGS(widget, path),
+
+ TP_STRUCT__entry(
+ __string( wname, widget->name )
+ __string( pname, path->name ? path->name : DAPM_DIRECT)
+ __string( psname, path->source->name )
+ __field( int, path_source )
+ __field( int, path_connect )
+ ),
+
+ TP_fast_assign(
+ __assign_str(wname, widget->name);
+ __assign_str(pname, path->name ? path->name : DAPM_DIRECT);
+ __assign_str(psname, path->source->name);
+ __entry->path_connect = path->connect;
+ __entry->path_source = (long)path->source;
+ ),
+
+ TP_printk("%c%s <- %s <- %s\n",
+ (int) __entry->path_source &&
+ (int) __entry->path_connect ? '*' : ' ',
+ __get_str(wname), __get_str(pname), __get_str(psname))
+);
+
+TRACE_EVENT(snd_soc_dapm_connected,
+
+ TP_PROTO(int paths, int stream),
+
+ TP_ARGS(paths, stream),
+
+ TP_STRUCT__entry(
+ __field( int, paths )
+ __field( int, stream )
+ ),
+
+ TP_fast_assign(
+ __entry->paths = paths;
+ __entry->stream = stream;
+ ),
+
+ TP_printk("%s: found %d paths\n",
+ __entry->stream ? "capture" : "playback", __entry->paths)
+);
+
TRACE_EVENT(snd_soc_jack_irq,
TP_PROTO(const char *name),
diff --git a/include/trace/events/ext3.h b/include/trace/events/ext3.h
index 7b53c0573dc9..15d11a39be47 100644
--- a/include/trace/events/ext3.h
+++ b/include/trace/events/ext3.h
@@ -24,8 +24,8 @@ TRACE_EVENT(ext3_free_inode,
__entry->dev = inode->i_sb->s_dev;
__entry->ino = inode->i_ino;
__entry->mode = inode->i_mode;
- __entry->uid = inode->i_uid;
- __entry->gid = inode->i_gid;
+ __entry->uid = i_uid_read(inode);
+ __entry->gid = i_gid_read(inode);
__entry->blocks = inode->i_blocks;
),
diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h
index 319538bf17d2..69d8a69ea831 100644
--- a/include/trace/events/ext4.h
+++ b/include/trace/events/ext4.h
@@ -36,8 +36,8 @@ TRACE_EVENT(ext4_free_inode,
__entry->dev = inode->i_sb->s_dev;
__entry->ino = inode->i_ino;
__entry->mode = inode->i_mode;
- __entry->uid = inode->i_uid;
- __entry->gid = inode->i_gid;
+ __entry->uid = i_uid_read(inode);
+ __entry->gid = i_gid_read(inode);
__entry->blocks = inode->i_blocks;
),
diff --git a/include/trace/events/power.h b/include/trace/events/power.h
index cae9a94f025d..0c9783841a30 100644
--- a/include/trace/events/power.h
+++ b/include/trace/events/power.h
@@ -65,6 +65,40 @@ TRACE_EVENT(machine_suspend,
TP_printk("state=%lu", (unsigned long)__entry->state)
);
+DECLARE_EVENT_CLASS(wakeup_source,
+
+ TP_PROTO(const char *name, unsigned int state),
+
+ TP_ARGS(name, state),
+
+ TP_STRUCT__entry(
+ __string( name, name )
+ __field( u64, state )
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, name);
+ __entry->state = state;
+ ),
+
+ TP_printk("%s state=0x%lx", __get_str(name),
+ (unsigned long)__entry->state)
+);
+
+DEFINE_EVENT(wakeup_source, wakeup_source_activate,
+
+ TP_PROTO(const char *name, unsigned int state),
+
+ TP_ARGS(name, state)
+);
+
+DEFINE_EVENT(wakeup_source, wakeup_source_deactivate,
+
+ TP_PROTO(const char *name, unsigned int state),
+
+ TP_ARGS(name, state)
+);
+
#ifdef CONFIG_EVENT_POWER_TRACING_DEPRECATED
/*
diff --git a/include/trace/events/workqueue.h b/include/trace/events/workqueue.h
index 7d497291c85d..4018f5058f27 100644
--- a/include/trace/events/workqueue.h
+++ b/include/trace/events/workqueue.h
@@ -103,7 +103,7 @@ TRACE_EVENT(workqueue_execute_start,
);
/**
- * workqueue_execute_end - called immediately before the workqueue callback
+ * workqueue_execute_end - called immediately after the workqueue callback
* @work: pointer to struct work_struct
*
* Allows to track workqueue execution.
diff --git a/include/video/omap-panel-nokia-dsi.h b/include/video/omap-panel-nokia-dsi.h
index 7dc71f9c13e6..04219a295539 100644
--- a/include/video/omap-panel-nokia-dsi.h
+++ b/include/video/omap-panel-nokia-dsi.h
@@ -11,6 +11,7 @@ struct omap_dss_device;
* @esd_interval: interval of ESD checks, 0 = disabled (ms)
* @ulps_timeout: time to wait before entering ULPS, 0 = disabled (ms)
* @use_dsi_backlight: true if panel uses DSI command to control backlight
+ * @pin_config: DSI pin configuration
*/
struct nokia_dsi_panel_data {
const char *name;
@@ -24,6 +25,8 @@ struct nokia_dsi_panel_data {
unsigned ulps_timeout;
bool use_dsi_backlight;
+
+ struct omap_dsi_pin_config pin_config;
};
#endif /* __OMAP_NOKIA_DSI_PANEL_H */
diff --git a/include/video/omap-panel-dvi.h b/include/video/omap-panel-tfp410.h
index 87ad567b4229..68c31d79c571 100644
--- a/include/video/omap-panel-dvi.h
+++ b/include/video/omap-panel-tfp410.h
@@ -1,5 +1,5 @@
/*
- * Header for DVI output driver
+ * Header for TFP410 chip driver
*
* Copyright (C) 2011 Texas Instruments Inc
* Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
@@ -17,21 +17,19 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef __OMAP_PANEL_DVI_H
-#define __OMAP_PANEL_DVI_H
+#ifndef __OMAP_PANEL_TFP410_H
+#define __OMAP_PANEL_TFP410_H
struct omap_dss_device;
/**
- * struct panel_dvi_platform_data - panel driver configuration data
- * @platform_enable: platform specific panel enable function
- * @platform_disable: platform specific panel disable function
+ * struct tfp410_platform_data - panel driver configuration data
* @i2c_bus_num: i2c bus id for the panel
+ * @power_down_gpio: gpio number for PD pin (or -1 if not available)
*/
-struct panel_dvi_platform_data {
- int (*platform_enable)(struct omap_dss_device *dssdev);
- void (*platform_disable)(struct omap_dss_device *dssdev);
+struct tfp410_platform_data {
u16 i2c_bus_num;
+ int power_down_gpio;
};
-#endif /* __OMAP_PANEL_DVI_H */
+#endif /* __OMAP_PANEL_TFP410_H */
diff --git a/include/video/omapdss.h b/include/video/omapdss.h
index 483f67caa7ad..1c46a14341dd 100644
--- a/include/video/omapdss.h
+++ b/include/video/omapdss.h
@@ -468,6 +468,21 @@ struct omap_overlay_manager {
int (*wait_for_vsync)(struct omap_overlay_manager *mgr);
};
+/* 22 pins means 1 clk lane and 10 data lanes */
+#define OMAP_DSS_MAX_DSI_PINS 22
+
+struct omap_dsi_pin_config {
+ int num_pins;
+ /*
+ * pin numbers in the following order:
+ * clk+, clk-
+ * data1+, data1-
+ * data2+, data2-
+ * ...
+ */
+ int pins[OMAP_DSS_MAX_DSI_PINS];
+};
+
struct omap_dss_device {
struct device dev;
@@ -490,17 +505,6 @@ struct omap_dss_device {
} sdi;
struct {
- u8 clk_lane;
- u8 clk_pol;
- u8 data1_lane;
- u8 data1_pol;
- u8 data2_lane;
- u8 data2_pol;
- u8 data3_lane;
- u8 data3_pol;
- u8 data4_lane;
- u8 data4_pol;
-
int module;
bool ext_te;
@@ -687,6 +691,8 @@ int omap_dsi_update(struct omap_dss_device *dssdev, int channel,
int omap_dsi_request_vc(struct omap_dss_device *dssdev, int *channel);
int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id);
void omap_dsi_release_vc(struct omap_dss_device *dssdev, int channel);
+int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev,
+ const struct omap_dsi_pin_config *pin_cfg);
int omapdss_dsi_display_enable(struct omap_dss_device *dssdev);
void omapdss_dsi_display_disable(struct omap_dss_device *dssdev,
diff --git a/init/Kconfig b/init/Kconfig
index 6d18ef8071b5..81816b82860b 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -27,6 +27,9 @@ config IRQ_WORK
bool
depends on HAVE_IRQ_WORK
+config BUILDTIME_EXTABLE_SORT
+ bool
+
menu "General setup"
config EXPERIMENTAL
@@ -387,6 +390,7 @@ config AUDIT_LOGINUID_IMMUTABLE
but may not be backwards compatible with older init systems.
source "kernel/irq/Kconfig"
+source "kernel/time/Kconfig"
menu "RCU Subsystem"
@@ -870,7 +874,10 @@ config IPC_NS
config USER_NS
bool "User namespace (EXPERIMENTAL)"
depends on EXPERIMENTAL
- default y
+ depends on UIDGID_CONVERTED
+ select UIDGID_STRICT_TYPE_CHECKS
+
+ default n
help
This allows containers, i.e. vservers, to use user namespaces
to provide different user info for different servers.
@@ -894,6 +901,131 @@ config NET_NS
endif # NAMESPACES
+config UIDGID_CONVERTED
+ # True if all of the selected software conmponents are known
+ # to have uid_t and gid_t converted to kuid_t and kgid_t
+ # where appropriate and are otherwise safe to use with
+ # the user namespace.
+ bool
+ default y
+
+ # List of kernel pieces that need user namespace work
+ # Features
+ depends on SYSVIPC = n
+ depends on IMA = n
+ depends on EVM = n
+ depends on KEYS = n
+ depends on AUDIT = n
+ depends on AUDITSYSCALL = n
+ depends on TASKSTATS = n
+ depends on TRACING = n
+ depends on FS_POSIX_ACL = n
+ depends on QUOTA = n
+ depends on QUOTACTL = n
+ depends on DEBUG_CREDENTIALS = n
+ depends on BSD_PROCESS_ACCT = n
+ depends on DRM = n
+ depends on PROC_EVENTS = n
+
+ # Networking
+ depends on NET = n
+ depends on NET_9P = n
+ depends on IPX = n
+ depends on PHONET = n
+ depends on NET_CLS_FLOW = n
+ depends on NETFILTER_XT_MATCH_OWNER = n
+ depends on NETFILTER_XT_MATCH_RECENT = n
+ depends on NETFILTER_XT_TARGET_LOG = n
+ depends on NETFILTER_NETLINK_LOG = n
+ depends on INET = n
+ depends on IPV6 = n
+ depends on IP_SCTP = n
+ depends on AF_RXRPC = n
+ depends on LLC2 = n
+ depends on NET_KEY = n
+ depends on INET_DIAG = n
+ depends on DNS_RESOLVER = n
+ depends on AX25 = n
+ depends on ATALK = n
+
+ # Filesystems
+ depends on USB_DEVICEFS = n
+ depends on USB_GADGETFS = n
+ depends on USB_FUNCTIONFS = n
+ depends on DEVTMPFS = n
+ depends on XENFS = n
+
+ depends on 9P_FS = n
+ depends on ADFS_FS = n
+ depends on AFFS_FS = n
+ depends on AFS_FS = n
+ depends on AUTOFS4_FS = n
+ depends on BEFS_FS = n
+ depends on BFS_FS = n
+ depends on BTRFS_FS = n
+ depends on CEPH_FS = n
+ depends on CIFS = n
+ depends on CODA_FS = n
+ depends on CONFIGFS_FS = n
+ depends on CRAMFS = n
+ depends on DEBUG_FS = n
+ depends on ECRYPT_FS = n
+ depends on EFS_FS = n
+ depends on EXOFS_FS = n
+ depends on FAT_FS = n
+ depends on FUSE_FS = n
+ depends on GFS2_FS = n
+ depends on HFS_FS = n
+ depends on HFSPLUS_FS = n
+ depends on HPFS_FS = n
+ depends on HUGETLBFS = n
+ depends on ISO9660_FS = n
+ depends on JFFS2_FS = n
+ depends on JFS_FS = n
+ depends on LOGFS = n
+ depends on MINIX_FS = n
+ depends on NCP_FS = n
+ depends on NFSD = n
+ depends on NFS_FS = n
+ depends on NILFS2_FS = n
+ depends on NTFS_FS = n
+ depends on OCFS2_FS = n
+ depends on OMFS_FS = n
+ depends on QNX4FS_FS = n
+ depends on QNX6FS_FS = n
+ depends on REISERFS_FS = n
+ depends on SQUASHFS = n
+ depends on SYSV_FS = n
+ depends on UBIFS_FS = n
+ depends on UDF_FS = n
+ depends on UFS_FS = n
+ depends on VXFS_FS = n
+ depends on XFS_FS = n
+
+ depends on !UML || HOSTFS = n
+
+ # The rare drivers that won't build
+ depends on AIRO = n
+ depends on AIRO_CS = n
+ depends on TUN = n
+ depends on INFINIBAND_QIB = n
+ depends on BLK_DEV_LOOP = n
+ depends on ANDROID_BINDER_IPC = n
+
+ # Security modules
+ depends on SECURITY_TOMOYO = n
+ depends on SECURITY_APPARMOR = n
+
+config UIDGID_STRICT_TYPE_CHECKS
+ bool "Require conversions between uid/gids and their internal representation"
+ depends on UIDGID_CONVERTED
+ default n
+ help
+ While the nececessary conversions are being added to all subsystems this option allows
+ the code to continue to build for unconverted subsystems.
+
+ Say Y here if you want the strict type checking enabled
+
config SCHED_AUTOGROUP
bool "Automatic process group scheduling"
select EVENTFD
@@ -1198,7 +1330,7 @@ menu "Kernel Performance Events And Counters"
config PERF_EVENTS
bool "Kernel performance events and counters"
- default y if (PROFILING || PERF_COUNTERS)
+ default y if PROFILING
depends on HAVE_PERF_EVENTS
select ANON_INODES
select IRQ_WORK
@@ -1225,18 +1357,6 @@ config PERF_EVENTS
Say Y if unsure.
-config PERF_COUNTERS
- bool "Kernel performance counters (old config option)"
- depends on HAVE_PERF_EVENTS
- help
- This config has been obsoleted by the PERF_EVENTS
- config option - please see that one for details.
-
- It has no effect on the kernel whether you enable
- it or not, it is a compatibility placeholder.
-
- Say N if unsure.
-
config DEBUG_PERF_USE_VMALLOC
default n
bool "Debug: use vmalloc to back perf mmap() buffers"
diff --git a/init/main.c b/init/main.c
index cb54cd3dbf05..1ca6b32c4828 100644
--- a/init/main.c
+++ b/init/main.c
@@ -226,7 +226,7 @@ static int __init loglevel(char *str)
early_param("loglevel", loglevel);
/* Change NUL term back to "=", to make "param" the whole string. */
-static int __init repair_env_string(char *param, char *val)
+static int __init repair_env_string(char *param, char *val, const char *unused)
{
if (val) {
/* param=val or param="val"? */
@@ -246,9 +246,9 @@ static int __init repair_env_string(char *param, char *val)
* Unknown boot options get handed to init, unless they look like
* unused parameters (modprobe will find them in /proc/cmdline).
*/
-static int __init unknown_bootoption(char *param, char *val)
+static int __init unknown_bootoption(char *param, char *val, const char *unused)
{
- repair_env_string(param, val);
+ repair_env_string(param, val, unused);
/* Handle obsolete-style parameters */
if (obsolete_checksetup(param))
@@ -385,7 +385,7 @@ static noinline void __init_refok rest_init(void)
}
/* Check for early params. */
-static int __init do_early_param(char *param, char *val)
+static int __init do_early_param(char *param, char *val, const char *unused)
{
const struct obs_kernel_param *p;
@@ -725,14 +725,14 @@ static initcall_t *initcall_levels[] __initdata = {
};
static char *initcall_level_names[] __initdata = {
- "early parameters",
- "core parameters",
- "postcore parameters",
- "arch parameters",
- "subsys parameters",
- "fs parameters",
- "device parameters",
- "late parameters",
+ "early",
+ "core",
+ "postcore",
+ "arch",
+ "subsys",
+ "fs",
+ "device",
+ "late",
};
static void __init do_initcall_level(int level)
@@ -745,7 +745,7 @@ static void __init do_initcall_level(int level)
static_command_line, __start___param,
__stop___param - __start___param,
level, level,
- repair_env_string);
+ &repair_env_string);
for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
do_one_initcall(*fn);
@@ -755,8 +755,13 @@ static void __init do_initcalls(void)
{
int level;
- for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++)
+ for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++) {
+ pr_info("initlevel:%d=%s, %d registered initcalls\n",
+ level, initcall_level_names[level],
+ (int) (initcall_levels[level+1]
+ - initcall_levels[level]));
do_initcall_level(level);
+ }
}
/*
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 28bd64ddeda3..b6a0d46fbad7 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -66,6 +66,7 @@ struct mqueue_inode_info {
struct sigevent notify;
struct pid* notify_owner;
+ struct user_namespace *notify_user_ns;
struct user_struct *user; /* user who created, for accounting */
struct sock *notify_sock;
struct sk_buff *notify_cookie;
@@ -139,6 +140,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
INIT_LIST_HEAD(&info->e_wait_q[0].list);
INIT_LIST_HEAD(&info->e_wait_q[1].list);
info->notify_owner = NULL;
+ info->notify_user_ns = NULL;
info->qsize = 0;
info->user = NULL; /* set when all is ok */
memset(&info->attr, 0, sizeof(info->attr));
@@ -536,8 +538,7 @@ static void __do_notify(struct mqueue_inode_info *info)
rcu_read_lock();
sig_i.si_pid = task_tgid_nr_ns(current,
ns_of_pid(info->notify_owner));
- sig_i.si_uid = user_ns_map_uid(info->user->user_ns,
- current_cred(), current_uid());
+ sig_i.si_uid = from_kuid_munged(info->notify_user_ns, current_uid());
rcu_read_unlock();
kill_pid_info(info->notify.sigev_signo,
@@ -550,7 +551,9 @@ static void __do_notify(struct mqueue_inode_info *info)
}
/* after notification unregisters process */
put_pid(info->notify_owner);
+ put_user_ns(info->notify_user_ns);
info->notify_owner = NULL;
+ info->notify_user_ns = NULL;
}
wake_up(&info->wait_q);
}
@@ -575,7 +578,9 @@ static void remove_notification(struct mqueue_inode_info *info)
netlink_sendskb(info->notify_sock, info->notify_cookie);
}
put_pid(info->notify_owner);
+ put_user_ns(info->notify_user_ns);
info->notify_owner = NULL;
+ info->notify_user_ns = NULL;
}
static int mq_attr_ok(struct ipc_namespace *ipc_ns, struct mq_attr *attr)
@@ -1140,6 +1145,7 @@ retry:
}
info->notify_owner = get_pid(task_tgid(current));
+ info->notify_user_ns = get_user_ns(current_user_ns());
inode->i_atime = inode->i_ctime = CURRENT_TIME;
}
spin_unlock(&info->lock);
diff --git a/ipc/namespace.c b/ipc/namespace.c
index ce0a647869b1..f362298c5ce4 100644
--- a/ipc/namespace.c
+++ b/ipc/namespace.c
@@ -46,7 +46,7 @@ static struct ipc_namespace *create_ipc_ns(struct task_struct *tsk,
ipcns_notify(IPCNS_CREATED);
register_ipcns_notifier(ns);
- ns->user_ns = get_user_ns(task_cred_xxx(tsk, user)->user_ns);
+ ns->user_ns = get_user_ns(task_cred_xxx(tsk, user_ns));
return ns;
}
diff --git a/kernel/capability.c b/kernel/capability.c
index 3f1adb6c6470..493d97259484 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -419,3 +419,24 @@ bool nsown_capable(int cap)
{
return ns_capable(current_user_ns(), cap);
}
+
+/**
+ * inode_capable - Check superior capability over inode
+ * @inode: The inode in question
+ * @cap: The capability in question
+ *
+ * Return true if the current task has the given superior capability
+ * targeted at it's own user namespace and that the given inode is owned
+ * by the current user namespace or a child namespace.
+ *
+ * Currently we check to see if an inode is owned by the current
+ * user namespace by seeing if the inode's owner maps into the
+ * current user namespace.
+ *
+ */
+bool inode_capable(const struct inode *inode, int cap)
+{
+ struct user_namespace *ns = current_user_ns();
+
+ return ns_capable(ns, cap) && kuid_has_mapping(ns, inode->i_uid);
+}
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index ed64ccac67c9..a0c6af34d500 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -60,9 +60,13 @@
#include <linux/eventfd.h>
#include <linux/poll.h>
#include <linux/flex_array.h> /* used in cgroup_attach_proc */
+#include <linux/kthread.h>
#include <linux/atomic.h>
+/* css deactivation bias, makes css->refcnt negative to deny new trygets */
+#define CSS_DEACT_BIAS INT_MIN
+
/*
* cgroup_mutex is the master lock. Any modification to cgroup or its
* hierarchy must be performed while holding it.
@@ -127,6 +131,9 @@ struct cgroupfs_root {
/* A list running through the active hierarchies */
struct list_head root_list;
+ /* All cgroups on this root, cgroup_mutex protected */
+ struct list_head allcg_list;
+
/* Hierarchy-specific flags */
unsigned long flags;
@@ -145,6 +152,15 @@ struct cgroupfs_root {
static struct cgroupfs_root rootnode;
/*
+ * cgroupfs file entry, pointed to from leaf dentry->d_fsdata.
+ */
+struct cfent {
+ struct list_head node;
+ struct dentry *dentry;
+ struct cftype *type;
+};
+
+/*
* CSS ID -- ID per subsys's Cgroup Subsys State(CSS). used only when
* cgroup_subsys->use_id != 0.
*/
@@ -239,6 +255,14 @@ int cgroup_lock_is_held(void)
EXPORT_SYMBOL_GPL(cgroup_lock_is_held);
+/* the current nr of refs, always >= 0 whether @css is deactivated or not */
+static int css_refcnt(struct cgroup_subsys_state *css)
+{
+ int v = atomic_read(&css->refcnt);
+
+ return v >= 0 ? v : v - CSS_DEACT_BIAS;
+}
+
/* convenient tests for these bits */
inline int cgroup_is_removed(const struct cgroup *cgrp)
{
@@ -279,6 +303,21 @@ list_for_each_entry(_ss, &_root->subsys_list, sibling)
#define for_each_active_root(_root) \
list_for_each_entry(_root, &roots, root_list)
+static inline struct cgroup *__d_cgrp(struct dentry *dentry)
+{
+ return dentry->d_fsdata;
+}
+
+static inline struct cfent *__d_cfe(struct dentry *dentry)
+{
+ return dentry->d_fsdata;
+}
+
+static inline struct cftype *__d_cft(struct dentry *dentry)
+{
+ return __d_cfe(dentry)->type;
+}
+
/* the list of cgroups eligible for automatic release. Protected by
* release_list_lock */
static LIST_HEAD(release_list);
@@ -816,12 +855,17 @@ static int cgroup_call_pre_destroy(struct cgroup *cgrp)
struct cgroup_subsys *ss;
int ret = 0;
- for_each_subsys(cgrp->root, ss)
- if (ss->pre_destroy) {
- ret = ss->pre_destroy(cgrp);
- if (ret)
- break;
+ for_each_subsys(cgrp->root, ss) {
+ if (!ss->pre_destroy)
+ continue;
+
+ ret = ss->pre_destroy(cgrp);
+ if (ret) {
+ /* ->pre_destroy() failure is being deprecated */
+ WARN_ON_ONCE(!ss->__DEPRECATED_clear_css_refs);
+ break;
}
+ }
return ret;
}
@@ -864,6 +908,14 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
BUG_ON(!list_empty(&cgrp->pidlists));
kfree_rcu(cgrp, rcu_head);
+ } else {
+ struct cfent *cfe = __d_cfe(dentry);
+ struct cgroup *cgrp = dentry->d_parent->d_fsdata;
+
+ WARN_ONCE(!list_empty(&cfe->node) &&
+ cgrp != &cgrp->root->top_cgroup,
+ "cfe still linked for %s\n", cfe->type->name);
+ kfree(cfe);
}
iput(inode);
}
@@ -882,34 +934,36 @@ static void remove_dir(struct dentry *d)
dput(parent);
}
-static void cgroup_clear_directory(struct dentry *dentry)
-{
- struct list_head *node;
-
- BUG_ON(!mutex_is_locked(&dentry->d_inode->i_mutex));
- spin_lock(&dentry->d_lock);
- node = dentry->d_subdirs.next;
- while (node != &dentry->d_subdirs) {
- struct dentry *d = list_entry(node, struct dentry, d_u.d_child);
-
- spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED);
- list_del_init(node);
- if (d->d_inode) {
- /* This should never be called on a cgroup
- * directory with child cgroups */
- BUG_ON(d->d_inode->i_mode & S_IFDIR);
- dget_dlock(d);
- spin_unlock(&d->d_lock);
- spin_unlock(&dentry->d_lock);
- d_delete(d);
- simple_unlink(dentry->d_inode, d);
- dput(d);
- spin_lock(&dentry->d_lock);
- } else
- spin_unlock(&d->d_lock);
- node = dentry->d_subdirs.next;
+static int cgroup_rm_file(struct cgroup *cgrp, const struct cftype *cft)
+{
+ struct cfent *cfe;
+
+ lockdep_assert_held(&cgrp->dentry->d_inode->i_mutex);
+ lockdep_assert_held(&cgroup_mutex);
+
+ list_for_each_entry(cfe, &cgrp->files, node) {
+ struct dentry *d = cfe->dentry;
+
+ if (cft && cfe->type != cft)
+ continue;
+
+ dget(d);
+ d_delete(d);
+ simple_unlink(d->d_inode, d);
+ list_del_init(&cfe->node);
+ dput(d);
+
+ return 0;
}
- spin_unlock(&dentry->d_lock);
+ return -ENOENT;
+}
+
+static void cgroup_clear_directory(struct dentry *dir)
+{
+ struct cgroup *cgrp = __d_cgrp(dir);
+
+ while (!list_empty(&cgrp->files))
+ cgroup_rm_file(cgrp, NULL);
}
/*
@@ -1294,6 +1348,11 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data)
if (ret)
goto out_unlock;
+ /* See feature-removal-schedule.txt */
+ if (opts.subsys_bits != root->actual_subsys_bits || opts.release_agent)
+ pr_warning("cgroup: option changes via remount are deprecated (pid=%d comm=%s)\n",
+ task_tgid_nr(current), current->comm);
+
/* Don't allow flags or name to change at remount */
if (opts.flags != root->flags ||
(opts.name && strcmp(opts.name, root->name))) {
@@ -1308,7 +1367,8 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data)
goto out_unlock;
}
- /* (re)populate subsystem files */
+ /* clear out any existing files and repopulate subsystem files */
+ cgroup_clear_directory(cgrp->dentry);
cgroup_populate_dir(cgrp);
if (opts.release_agent)
@@ -1333,6 +1393,7 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp)
{
INIT_LIST_HEAD(&cgrp->sibling);
INIT_LIST_HEAD(&cgrp->children);
+ INIT_LIST_HEAD(&cgrp->files);
INIT_LIST_HEAD(&cgrp->css_sets);
INIT_LIST_HEAD(&cgrp->release_list);
INIT_LIST_HEAD(&cgrp->pidlists);
@@ -1344,11 +1405,14 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp)
static void init_cgroup_root(struct cgroupfs_root *root)
{
struct cgroup *cgrp = &root->top_cgroup;
+
INIT_LIST_HEAD(&root->subsys_list);
INIT_LIST_HEAD(&root->root_list);
+ INIT_LIST_HEAD(&root->allcg_list);
root->number_of_cgroups = 1;
cgrp->root = root;
cgrp->top_cgroup = cgrp;
+ list_add_tail(&cgrp->allcg_node, &root->allcg_list);
init_cgroup_housekeeping(cgrp);
}
@@ -1692,16 +1756,6 @@ static struct file_system_type cgroup_fs_type = {
static struct kobject *cgroup_kobj;
-static inline struct cgroup *__d_cgrp(struct dentry *dentry)
-{
- return dentry->d_fsdata;
-}
-
-static inline struct cftype *__d_cft(struct dentry *dentry)
-{
- return dentry->d_fsdata;
-}
-
/**
* cgroup_path - generate the path of a cgroup
* @cgrp: the cgroup in question
@@ -2160,9 +2214,9 @@ retry_find_task:
* only need to check permissions on one of them.
*/
tcred = __task_cred(tsk);
- if (cred->euid &&
- cred->euid != tcred->uid &&
- cred->euid != tcred->suid) {
+ if (!uid_eq(cred->euid, GLOBAL_ROOT_UID) &&
+ !uid_eq(cred->euid, tcred->uid) &&
+ !uid_eq(cred->euid, tcred->suid)) {
rcu_read_unlock();
ret = -EACCES;
goto out_unlock_cgroup;
@@ -2172,6 +2226,18 @@ retry_find_task:
if (threadgroup)
tsk = tsk->group_leader;
+
+ /*
+ * Workqueue threads may acquire PF_THREAD_BOUND and become
+ * trapped in a cpuset, or RT worker may be born in a cgroup
+ * with no rt_runtime allocated. Just say no.
+ */
+ if (tsk == kthreadd_task || (tsk->flags & PF_THREAD_BOUND)) {
+ ret = -EINVAL;
+ rcu_read_unlock();
+ goto out_unlock_cgroup;
+ }
+
get_task_struct(tsk);
rcu_read_unlock();
@@ -2603,50 +2669,191 @@ static umode_t cgroup_file_mode(const struct cftype *cft)
return mode;
}
-int cgroup_add_file(struct cgroup *cgrp,
- struct cgroup_subsys *subsys,
- const struct cftype *cft)
+static int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys,
+ const struct cftype *cft)
{
struct dentry *dir = cgrp->dentry;
+ struct cgroup *parent = __d_cgrp(dir);
struct dentry *dentry;
+ struct cfent *cfe;
int error;
umode_t mode;
-
char name[MAX_CGROUP_TYPE_NAMELEN + MAX_CFTYPE_NAME + 2] = { 0 };
+
+ /* does @cft->flags tell us to skip creation on @cgrp? */
+ if ((cft->flags & CFTYPE_NOT_ON_ROOT) && !cgrp->parent)
+ return 0;
+ if ((cft->flags & CFTYPE_ONLY_ON_ROOT) && cgrp->parent)
+ return 0;
+
if (subsys && !test_bit(ROOT_NOPREFIX, &cgrp->root->flags)) {
strcpy(name, subsys->name);
strcat(name, ".");
}
strcat(name, cft->name);
+
BUG_ON(!mutex_is_locked(&dir->d_inode->i_mutex));
+
+ cfe = kzalloc(sizeof(*cfe), GFP_KERNEL);
+ if (!cfe)
+ return -ENOMEM;
+
dentry = lookup_one_len(name, dir, strlen(name));
- if (!IS_ERR(dentry)) {
- mode = cgroup_file_mode(cft);
- error = cgroup_create_file(dentry, mode | S_IFREG,
- cgrp->root->sb);
- if (!error)
- dentry->d_fsdata = (void *)cft;
- dput(dentry);
- } else
+ if (IS_ERR(dentry)) {
error = PTR_ERR(dentry);
+ goto out;
+ }
+
+ mode = cgroup_file_mode(cft);
+ error = cgroup_create_file(dentry, mode | S_IFREG, cgrp->root->sb);
+ if (!error) {
+ cfe->type = (void *)cft;
+ cfe->dentry = dentry;
+ dentry->d_fsdata = cfe;
+ list_add_tail(&cfe->node, &parent->files);
+ cfe = NULL;
+ }
+ dput(dentry);
+out:
+ kfree(cfe);
return error;
}
-EXPORT_SYMBOL_GPL(cgroup_add_file);
-int cgroup_add_files(struct cgroup *cgrp,
- struct cgroup_subsys *subsys,
- const struct cftype cft[],
- int count)
+static int cgroup_addrm_files(struct cgroup *cgrp, struct cgroup_subsys *subsys,
+ const struct cftype cfts[], bool is_add)
{
- int i, err;
- for (i = 0; i < count; i++) {
- err = cgroup_add_file(cgrp, subsys, &cft[i]);
- if (err)
- return err;
+ const struct cftype *cft;
+ int err, ret = 0;
+
+ for (cft = cfts; cft->name[0] != '\0'; cft++) {
+ if (is_add)
+ err = cgroup_add_file(cgrp, subsys, cft);
+ else
+ err = cgroup_rm_file(cgrp, cft);
+ if (err) {
+ pr_warning("cgroup_addrm_files: failed to %s %s, err=%d\n",
+ is_add ? "add" : "remove", cft->name, err);
+ ret = err;
+ }
+ }
+ return ret;
+}
+
+static DEFINE_MUTEX(cgroup_cft_mutex);
+
+static void cgroup_cfts_prepare(void)
+ __acquires(&cgroup_cft_mutex) __acquires(&cgroup_mutex)
+{
+ /*
+ * Thanks to the entanglement with vfs inode locking, we can't walk
+ * the existing cgroups under cgroup_mutex and create files.
+ * Instead, we increment reference on all cgroups and build list of
+ * them using @cgrp->cft_q_node. Grab cgroup_cft_mutex to ensure
+ * exclusive access to the field.
+ */
+ mutex_lock(&cgroup_cft_mutex);
+ mutex_lock(&cgroup_mutex);
+}
+
+static void cgroup_cfts_commit(struct cgroup_subsys *ss,
+ const struct cftype *cfts, bool is_add)
+ __releases(&cgroup_mutex) __releases(&cgroup_cft_mutex)
+{
+ LIST_HEAD(pending);
+ struct cgroup *cgrp, *n;
+
+ /* %NULL @cfts indicates abort and don't bother if @ss isn't attached */
+ if (cfts && ss->root != &rootnode) {
+ list_for_each_entry(cgrp, &ss->root->allcg_list, allcg_node) {
+ dget(cgrp->dentry);
+ list_add_tail(&cgrp->cft_q_node, &pending);
+ }
+ }
+
+ mutex_unlock(&cgroup_mutex);
+
+ /*
+ * All new cgroups will see @cfts update on @ss->cftsets. Add/rm
+ * files for all cgroups which were created before.
+ */
+ list_for_each_entry_safe(cgrp, n, &pending, cft_q_node) {
+ struct inode *inode = cgrp->dentry->d_inode;
+
+ mutex_lock(&inode->i_mutex);
+ mutex_lock(&cgroup_mutex);
+ if (!cgroup_is_removed(cgrp))
+ cgroup_addrm_files(cgrp, ss, cfts, is_add);
+ mutex_unlock(&cgroup_mutex);
+ mutex_unlock(&inode->i_mutex);
+
+ list_del_init(&cgrp->cft_q_node);
+ dput(cgrp->dentry);
}
+
+ mutex_unlock(&cgroup_cft_mutex);
+}
+
+/**
+ * cgroup_add_cftypes - add an array of cftypes to a subsystem
+ * @ss: target cgroup subsystem
+ * @cfts: zero-length name terminated array of cftypes
+ *
+ * Register @cfts to @ss. Files described by @cfts are created for all
+ * existing cgroups to which @ss is attached and all future cgroups will
+ * have them too. This function can be called anytime whether @ss is
+ * attached or not.
+ *
+ * Returns 0 on successful registration, -errno on failure. Note that this
+ * function currently returns 0 as long as @cfts registration is successful
+ * even if some file creation attempts on existing cgroups fail.
+ */
+int cgroup_add_cftypes(struct cgroup_subsys *ss, const struct cftype *cfts)
+{
+ struct cftype_set *set;
+
+ set = kzalloc(sizeof(*set), GFP_KERNEL);
+ if (!set)
+ return -ENOMEM;
+
+ cgroup_cfts_prepare();
+ set->cfts = cfts;
+ list_add_tail(&set->node, &ss->cftsets);
+ cgroup_cfts_commit(ss, cfts, true);
+
return 0;
}
-EXPORT_SYMBOL_GPL(cgroup_add_files);
+EXPORT_SYMBOL_GPL(cgroup_add_cftypes);
+
+/**
+ * cgroup_rm_cftypes - remove an array of cftypes from a subsystem
+ * @ss: target cgroup subsystem
+ * @cfts: zero-length name terminated array of cftypes
+ *
+ * Unregister @cfts from @ss. Files described by @cfts are removed from
+ * all existing cgroups to which @ss is attached and all future cgroups
+ * won't have them either. This function can be called anytime whether @ss
+ * is attached or not.
+ *
+ * Returns 0 on successful unregistration, -ENOENT if @cfts is not
+ * registered with @ss.
+ */
+int cgroup_rm_cftypes(struct cgroup_subsys *ss, const struct cftype *cfts)
+{
+ struct cftype_set *set;
+
+ cgroup_cfts_prepare();
+
+ list_for_each_entry(set, &ss->cftsets, node) {
+ if (set->cfts == cfts) {
+ list_del_init(&set->node);
+ cgroup_cfts_commit(ss, cfts, false);
+ return 0;
+ }
+ }
+
+ cgroup_cfts_commit(ss, NULL, false);
+ return -ENOENT;
+}
/**
* cgroup_task_count - count the number of tasks in a cgroup.
@@ -3625,13 +3832,14 @@ static struct cftype files[] = {
.read_u64 = cgroup_clone_children_read,
.write_u64 = cgroup_clone_children_write,
},
-};
-
-static struct cftype cft_release_agent = {
- .name = "release_agent",
- .read_seq_string = cgroup_release_agent_show,
- .write_string = cgroup_release_agent_write,
- .max_write_len = PATH_MAX,
+ {
+ .name = "release_agent",
+ .flags = CFTYPE_ONLY_ON_ROOT,
+ .read_seq_string = cgroup_release_agent_show,
+ .write_string = cgroup_release_agent_write,
+ .max_write_len = PATH_MAX,
+ },
+ { } /* terminate */
};
static int cgroup_populate_dir(struct cgroup *cgrp)
@@ -3639,22 +3847,18 @@ static int cgroup_populate_dir(struct cgroup *cgrp)
int err;
struct cgroup_subsys *ss;
- /* First clear out any existing files */
- cgroup_clear_directory(cgrp->dentry);
-
- err = cgroup_add_files(cgrp, NULL, files, ARRAY_SIZE(files));
+ err = cgroup_addrm_files(cgrp, NULL, files, true);
if (err < 0)
return err;
- if (cgrp == cgrp->top_cgroup) {
- if ((err = cgroup_add_file(cgrp, NULL, &cft_release_agent)) < 0)
- return err;
- }
-
+ /* process cftsets of each subsystem */
for_each_subsys(cgrp->root, ss) {
- if (ss->populate && (err = ss->populate(ss, cgrp)) < 0)
- return err;
+ struct cftype_set *set;
+
+ list_for_each_entry(set, &ss->cftsets, node)
+ cgroup_addrm_files(cgrp, ss, set->cfts, true);
}
+
/* This cgroup is ready now */
for_each_subsys(cgrp->root, ss) {
struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
@@ -3670,6 +3874,14 @@ static int cgroup_populate_dir(struct cgroup *cgrp)
return 0;
}
+static void css_dput_fn(struct work_struct *work)
+{
+ struct cgroup_subsys_state *css =
+ container_of(work, struct cgroup_subsys_state, dput_work);
+
+ dput(css->cgroup->dentry);
+}
+
static void init_cgroup_css(struct cgroup_subsys_state *css,
struct cgroup_subsys *ss,
struct cgroup *cgrp)
@@ -3682,6 +3894,16 @@ static void init_cgroup_css(struct cgroup_subsys_state *css,
set_bit(CSS_ROOT, &css->flags);
BUG_ON(cgrp->subsys[ss->subsys_id]);
cgrp->subsys[ss->subsys_id] = css;
+
+ /*
+ * If !clear_css_refs, css holds an extra ref to @cgrp->dentry
+ * which is put on the last css_put(). dput() requires process
+ * context, which css_put() may be called without. @css->dput_work
+ * will be used to invoke dput() asynchronously from css_put().
+ */
+ INIT_WORK(&css->dput_work, css_dput_fn);
+ if (ss->__DEPRECATED_clear_css_refs)
+ set_bit(CSS_CLEAR_CSS_REFS, &css->flags);
}
static void cgroup_lock_hierarchy(struct cgroupfs_root *root)
@@ -3784,9 +4006,16 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
if (err < 0)
goto err_remove;
+ /* If !clear_css_refs, each css holds a ref to the cgroup's dentry */
+ for_each_subsys(root, ss)
+ if (!ss->__DEPRECATED_clear_css_refs)
+ dget(dentry);
+
/* The cgroup directory was pre-locked for us */
BUG_ON(!mutex_is_locked(&cgrp->dentry->d_inode->i_mutex));
+ list_add_tail(&cgrp->allcg_node, &root->allcg_list);
+
err = cgroup_populate_dir(cgrp);
/* If err < 0, we have a half-filled directory - oh well ;) */
@@ -3826,18 +4055,19 @@ static int cgroup_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
return cgroup_create(c_parent, dentry, mode | S_IFDIR);
}
+/*
+ * Check the reference count on each subsystem. Since we already
+ * established that there are no tasks in the cgroup, if the css refcount
+ * is also 1, then there should be no outstanding references, so the
+ * subsystem is safe to destroy. We scan across all subsystems rather than
+ * using the per-hierarchy linked list of mounted subsystems since we can
+ * be called via check_for_release() with no synchronization other than
+ * RCU, and the subsystem linked list isn't RCU-safe.
+ */
static int cgroup_has_css_refs(struct cgroup *cgrp)
{
- /* Check the reference count on each subsystem. Since we
- * already established that there are no tasks in the
- * cgroup, if the css refcount is also 1, then there should
- * be no outstanding references, so the subsystem is safe to
- * destroy. We scan across all subsystems rather than using
- * the per-hierarchy linked list of mounted subsystems since
- * we can be called via check_for_release() with no
- * synchronization other than RCU, and the subsystem linked
- * list isn't RCU-safe */
int i;
+
/*
* We won't need to lock the subsys array, because the subsystems
* we're concerned about aren't going anywhere since our cgroup root
@@ -3846,17 +4076,21 @@ static int cgroup_has_css_refs(struct cgroup *cgrp)
for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
struct cgroup_subsys *ss = subsys[i];
struct cgroup_subsys_state *css;
+
/* Skip subsystems not present or not in this hierarchy */
if (ss == NULL || ss->root != cgrp->root)
continue;
+
css = cgrp->subsys[ss->subsys_id];
- /* When called from check_for_release() it's possible
+ /*
+ * When called from check_for_release() it's possible
* that by this point the cgroup has been removed
* and the css deleted. But a false-positive doesn't
* matter, since it can only happen if the cgroup
* has been deleted and hence no longer needs the
- * release agent to be called anyway. */
- if (css && (atomic_read(&css->refcnt) > 1))
+ * release agent to be called anyway.
+ */
+ if (css && css_refcnt(css) > 1)
return 1;
}
return 0;
@@ -3866,51 +4100,63 @@ static int cgroup_has_css_refs(struct cgroup *cgrp)
* Atomically mark all (or else none) of the cgroup's CSS objects as
* CSS_REMOVED. Return true on success, or false if the cgroup has
* busy subsystems. Call with cgroup_mutex held
+ *
+ * Depending on whether a subsys has __DEPRECATED_clear_css_refs set or
+ * not, cgroup removal behaves differently.
+ *
+ * If clear is set, css refcnt for the subsystem should be zero before
+ * cgroup removal can be committed. This is implemented by
+ * CGRP_WAIT_ON_RMDIR and retry logic around ->pre_destroy(), which may be
+ * called multiple times until all css refcnts reach zero and is allowed to
+ * veto removal on any invocation. This behavior is deprecated and will be
+ * removed as soon as the existing user (memcg) is updated.
+ *
+ * If clear is not set, each css holds an extra reference to the cgroup's
+ * dentry and cgroup removal proceeds regardless of css refs.
+ * ->pre_destroy() will be called at least once and is not allowed to fail.
+ * On the last put of each css, whenever that may be, the extra dentry ref
+ * is put so that dentry destruction happens only after all css's are
+ * released.
*/
-
static int cgroup_clear_css_refs(struct cgroup *cgrp)
{
struct cgroup_subsys *ss;
unsigned long flags;
bool failed = false;
+
local_irq_save(flags);
+
+ /*
+ * Block new css_tryget() by deactivating refcnt. If all refcnts
+ * for subsystems w/ clear_css_refs set were 1 at the moment of
+ * deactivation, we succeeded.
+ */
for_each_subsys(cgrp->root, ss) {
struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
- int refcnt;
- while (1) {
- /* We can only remove a CSS with a refcnt==1 */
- refcnt = atomic_read(&css->refcnt);
- if (refcnt > 1) {
- failed = true;
- goto done;
- }
- BUG_ON(!refcnt);
- /*
- * Drop the refcnt to 0 while we check other
- * subsystems. This will cause any racing
- * css_tryget() to spin until we set the
- * CSS_REMOVED bits or abort
- */
- if (atomic_cmpxchg(&css->refcnt, refcnt, 0) == refcnt)
- break;
- cpu_relax();
- }
+
+ WARN_ON(atomic_read(&css->refcnt) < 0);
+ atomic_add(CSS_DEACT_BIAS, &css->refcnt);
+
+ if (ss->__DEPRECATED_clear_css_refs)
+ failed |= css_refcnt(css) != 1;
}
- done:
+
+ /*
+ * If succeeded, set REMOVED and put all the base refs; otherwise,
+ * restore refcnts to positive values. Either way, all in-progress
+ * css_tryget() will be released.
+ */
for_each_subsys(cgrp->root, ss) {
struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
- if (failed) {
- /*
- * Restore old refcnt if we previously managed
- * to clear it from 1 to 0
- */
- if (!atomic_read(&css->refcnt))
- atomic_set(&css->refcnt, 1);
- } else {
- /* Commit the fact that the CSS is removed */
+
+ if (!failed) {
set_bit(CSS_REMOVED, &css->flags);
+ css_put(css);
+ } else {
+ atomic_sub(CSS_DEACT_BIAS, &css->refcnt);
}
}
+
local_irq_restore(flags);
return !failed;
}
@@ -3995,6 +4241,8 @@ again:
list_del_init(&cgrp->sibling);
cgroup_unlock_hierarchy(cgrp->root);
+ list_del_init(&cgrp->allcg_node);
+
d = dget(cgrp->dentry);
cgroup_d_remove_dir(d);
@@ -4021,12 +4269,29 @@ again:
return 0;
}
+static void __init_or_module cgroup_init_cftsets(struct cgroup_subsys *ss)
+{
+ INIT_LIST_HEAD(&ss->cftsets);
+
+ /*
+ * base_cftset is embedded in subsys itself, no need to worry about
+ * deregistration.
+ */
+ if (ss->base_cftypes) {
+ ss->base_cftset.cfts = ss->base_cftypes;
+ list_add_tail(&ss->base_cftset.node, &ss->cftsets);
+ }
+}
+
static void __init cgroup_init_subsys(struct cgroup_subsys *ss)
{
struct cgroup_subsys_state *css;
printk(KERN_INFO "Initializing cgroup subsys %s\n", ss->name);
+ /* init base cftset */
+ cgroup_init_cftsets(ss);
+
/* Create the top cgroup state for this subsystem */
list_add(&ss->sibling, &rootnode.subsys_list);
ss->root = &rootnode;
@@ -4096,6 +4361,9 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)
return 0;
}
+ /* init base cftset */
+ cgroup_init_cftsets(ss);
+
/*
* need to register a subsys id before anything else - for example,
* init_cgroup_css needs it.
@@ -4685,21 +4953,41 @@ static void check_for_release(struct cgroup *cgrp)
}
/* Caller must verify that the css is not for root cgroup */
-void __css_put(struct cgroup_subsys_state *css, int count)
+bool __css_tryget(struct cgroup_subsys_state *css)
+{
+ do {
+ int v = css_refcnt(css);
+
+ if (atomic_cmpxchg(&css->refcnt, v, v + 1) == v)
+ return true;
+ cpu_relax();
+ } while (!test_bit(CSS_REMOVED, &css->flags));
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(__css_tryget);
+
+/* Caller must verify that the css is not for root cgroup */
+void __css_put(struct cgroup_subsys_state *css)
{
struct cgroup *cgrp = css->cgroup;
- int val;
+
rcu_read_lock();
- val = atomic_sub_return(count, &css->refcnt);
- if (val == 1) {
+ atomic_dec(&css->refcnt);
+ switch (css_refcnt(css)) {
+ case 1:
if (notify_on_release(cgrp)) {
set_bit(CGRP_RELEASABLE, &cgrp->flags);
check_for_release(cgrp);
}
cgroup_wakeup_rmdir_waiter(cgrp);
+ break;
+ case 0:
+ if (!test_bit(CSS_CLEAR_CSS_REFS, &css->flags))
+ schedule_work(&css->dput_work);
+ break;
}
rcu_read_unlock();
- WARN_ON_ONCE(val < 1);
}
EXPORT_SYMBOL_GPL(__css_put);
@@ -4818,7 +5106,7 @@ unsigned short css_id(struct cgroup_subsys_state *css)
* on this or this is under rcu_read_lock(). Once css->id is allocated,
* it's unchanged until freed.
*/
- cssid = rcu_dereference_check(css->id, atomic_read(&css->refcnt));
+ cssid = rcu_dereference_check(css->id, css_refcnt(css));
if (cssid)
return cssid->id;
@@ -4830,7 +5118,7 @@ unsigned short css_depth(struct cgroup_subsys_state *css)
{
struct css_id *cssid;
- cssid = rcu_dereference_check(css->id, atomic_read(&css->refcnt));
+ cssid = rcu_dereference_check(css->id, css_refcnt(css));
if (cssid)
return cssid->depth;
@@ -5211,19 +5499,15 @@ static struct cftype debug_files[] = {
.name = "releasable",
.read_u64 = releasable_read,
},
-};
-static int debug_populate(struct cgroup_subsys *ss, struct cgroup *cont)
-{
- return cgroup_add_files(cont, ss, debug_files,
- ARRAY_SIZE(debug_files));
-}
+ { } /* terminate */
+};
struct cgroup_subsys debug_subsys = {
.name = "debug",
.create = debug_create,
.destroy = debug_destroy,
- .populate = debug_populate,
.subsys_id = debug_subsys_id,
+ .base_cftypes = debug_files,
};
#endif /* CONFIG_CGROUP_DEBUG */
diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c
index f86e93920b62..3649fc6b3eaa 100644
--- a/kernel/cgroup_freezer.c
+++ b/kernel/cgroup_freezer.c
@@ -358,24 +358,19 @@ static int freezer_write(struct cgroup *cgroup,
static struct cftype files[] = {
{
.name = "state",
+ .flags = CFTYPE_NOT_ON_ROOT,
.read_seq_string = freezer_read,
.write_string = freezer_write,
},
+ { } /* terminate */
};
-static int freezer_populate(struct cgroup_subsys *ss, struct cgroup *cgroup)
-{
- if (!cgroup->parent)
- return 0;
- return cgroup_add_files(cgroup, ss, files, ARRAY_SIZE(files));
-}
-
struct cgroup_subsys freezer_subsys = {
.name = "freezer",
.create = freezer_create,
.destroy = freezer_destroy,
- .populate = freezer_populate,
.subsys_id = freezer_subsys_id,
.can_attach = freezer_can_attach,
.fork = freezer_fork,
+ .base_cftypes = files,
};
diff --git a/kernel/compat.c b/kernel/compat.c
index d2c67aa49ae6..c28a306ae05c 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -1073,15 +1073,7 @@ asmlinkage long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, compat
if (copy_from_user(&newset32, unewset, sizeof(compat_sigset_t)))
return -EFAULT;
sigset_from_compat(&newset, &newset32);
- sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP));
-
- current->saved_sigmask = current->blocked;
- set_current_blocked(&newset);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_restore_sigmask();
- return -ERESTARTNOHAND;
+ return sigsuspend(&newset);
}
#endif /* __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND */
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 14f7070b4ba2..8c8bd652dd12 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -1765,28 +1765,17 @@ static struct cftype files[] = {
.write_u64 = cpuset_write_u64,
.private = FILE_SPREAD_SLAB,
},
-};
-
-static struct cftype cft_memory_pressure_enabled = {
- .name = "memory_pressure_enabled",
- .read_u64 = cpuset_read_u64,
- .write_u64 = cpuset_write_u64,
- .private = FILE_MEMORY_PRESSURE_ENABLED,
-};
-static int cpuset_populate(struct cgroup_subsys *ss, struct cgroup *cont)
-{
- int err;
+ {
+ .name = "memory_pressure_enabled",
+ .flags = CFTYPE_ONLY_ON_ROOT,
+ .read_u64 = cpuset_read_u64,
+ .write_u64 = cpuset_write_u64,
+ .private = FILE_MEMORY_PRESSURE_ENABLED,
+ },
- err = cgroup_add_files(cont, ss, files, ARRAY_SIZE(files));
- if (err)
- return err;
- /* memory_pressure_enabled is in root cpuset only */
- if (!cont->parent)
- err = cgroup_add_file(cont, ss,
- &cft_memory_pressure_enabled);
- return err;
-}
+ { } /* terminate */
+};
/*
* post_clone() is called during cgroup_create() when the
@@ -1887,9 +1876,9 @@ struct cgroup_subsys cpuset_subsys = {
.destroy = cpuset_destroy,
.can_attach = cpuset_can_attach,
.attach = cpuset_attach,
- .populate = cpuset_populate,
.post_clone = cpuset_post_clone,
.subsys_id = cpuset_subsys_id,
+ .base_cftypes = files,
.early_init = 1,
};
diff --git a/kernel/cred.c b/kernel/cred.c
index e70683d9ec32..430557ea488f 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -49,6 +49,14 @@ struct cred init_cred = {
.subscribers = ATOMIC_INIT(2),
.magic = CRED_MAGIC,
#endif
+ .uid = GLOBAL_ROOT_UID,
+ .gid = GLOBAL_ROOT_GID,
+ .suid = GLOBAL_ROOT_UID,
+ .sgid = GLOBAL_ROOT_GID,
+ .euid = GLOBAL_ROOT_UID,
+ .egid = GLOBAL_ROOT_GID,
+ .fsuid = GLOBAL_ROOT_UID,
+ .fsgid = GLOBAL_ROOT_GID,
.securebits = SECUREBITS_DEFAULT,
.cap_inheritable = CAP_EMPTY_SET,
.cap_permitted = CAP_FULL_SET,
@@ -148,6 +156,7 @@ static void put_cred_rcu(struct rcu_head *rcu)
if (cred->group_info)
put_group_info(cred->group_info);
free_uid(cred->user);
+ put_user_ns(cred->user_ns);
kmem_cache_free(cred_jar, cred);
}
@@ -303,6 +312,7 @@ struct cred *prepare_creds(void)
set_cred_subscribers(new, 0);
get_group_info(new->group_info);
get_uid(new->user);
+ get_user_ns(new->user_ns);
#ifdef CONFIG_KEYS
key_get(new->thread_keyring);
@@ -414,11 +424,6 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
goto error_put;
}
- /* cache user_ns in cred. Doesn't need a refcount because it will
- * stay pinned by cred->user
- */
- new->user_ns = new->user->user_ns;
-
#ifdef CONFIG_KEYS
/* new threads get their own thread keyrings if their parent already
* had one */
@@ -493,10 +498,10 @@ int commit_creds(struct cred *new)
get_cred(new); /* we will require a ref for the subj creds too */
/* dumpability changes */
- if (old->euid != new->euid ||
- old->egid != new->egid ||
- old->fsuid != new->fsuid ||
- old->fsgid != new->fsgid ||
+ if (!uid_eq(old->euid, new->euid) ||
+ !gid_eq(old->egid, new->egid) ||
+ !uid_eq(old->fsuid, new->fsuid) ||
+ !gid_eq(old->fsgid, new->fsgid) ||
!cap_issubset(new->cap_permitted, old->cap_permitted)) {
if (task->mm)
set_dumpable(task->mm, suid_dumpable);
@@ -505,9 +510,9 @@ int commit_creds(struct cred *new)
}
/* alter the thread keyring */
- if (new->fsuid != old->fsuid)
+ if (!uid_eq(new->fsuid, old->fsuid))
key_fsuid_changed(task);
- if (new->fsgid != old->fsgid)
+ if (!gid_eq(new->fsgid, old->fsgid))
key_fsgid_changed(task);
/* do it
@@ -524,16 +529,16 @@ int commit_creds(struct cred *new)
alter_cred_subscribers(old, -2);
/* send notifications */
- if (new->uid != old->uid ||
- new->euid != old->euid ||
- new->suid != old->suid ||
- new->fsuid != old->fsuid)
+ if (!uid_eq(new->uid, old->uid) ||
+ !uid_eq(new->euid, old->euid) ||
+ !uid_eq(new->suid, old->suid) ||
+ !uid_eq(new->fsuid, old->fsuid))
proc_id_connector(task, PROC_EVENT_UID);
- if (new->gid != old->gid ||
- new->egid != old->egid ||
- new->sgid != old->sgid ||
- new->fsgid != old->fsgid)
+ if (!gid_eq(new->gid, old->gid) ||
+ !gid_eq(new->egid, old->egid) ||
+ !gid_eq(new->sgid, old->sgid) ||
+ !gid_eq(new->fsgid, old->fsgid))
proc_id_connector(task, PROC_EVENT_GID);
/* release the old obj and subj refs both */
@@ -678,6 +683,7 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)
atomic_set(&new->usage, 1);
set_cred_subscribers(new, 0);
get_uid(new->user);
+ get_user_ns(new->user_ns);
get_group_info(new->group_info);
#ifdef CONFIG_KEYS
diff --git a/kernel/events/Makefile b/kernel/events/Makefile
index 22d901f9caf4..103f5d147b2f 100644
--- a/kernel/events/Makefile
+++ b/kernel/events/Makefile
@@ -3,4 +3,7 @@ CFLAGS_REMOVE_core.o = -pg
endif
obj-y := core.o ring_buffer.o callchain.o
+
obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
+obj-$(CONFIG_UPROBES) += uprobes.o
+
diff --git a/kernel/events/core.c b/kernel/events/core.c
index fd126f82b57c..5b06cbbf6931 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -4957,7 +4957,7 @@ void __perf_sw_event(u32 event_id, u64 nr, struct pt_regs *regs, u64 addr)
if (rctx < 0)
return;
- perf_sample_data_init(&data, addr);
+ perf_sample_data_init(&data, addr, 0);
do_perf_sw_event(PERF_TYPE_SOFTWARE, event_id, nr, &data, regs);
@@ -5215,7 +5215,7 @@ void perf_tp_event(u64 addr, u64 count, void *record, int entry_size,
.data = record,
};
- perf_sample_data_init(&data, addr);
+ perf_sample_data_init(&data, addr, 0);
data.raw = &raw;
hlist_for_each_entry_rcu(event, node, head, hlist_entry) {
@@ -5318,7 +5318,7 @@ void perf_bp_event(struct perf_event *bp, void *data)
struct perf_sample_data sample;
struct pt_regs *regs = data;
- perf_sample_data_init(&sample, bp->attr.bp_addr);
+ perf_sample_data_init(&sample, bp->attr.bp_addr, 0);
if (!bp->hw.state && !perf_exclude_event(bp, regs))
perf_swevent_event(bp, 1, &sample, regs);
@@ -5344,13 +5344,12 @@ static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer)
event->pmu->read(event);
- perf_sample_data_init(&data, 0);
- data.period = event->hw.last_period;
+ perf_sample_data_init(&data, 0, event->hw.last_period);
regs = get_irq_regs();
if (regs && !perf_exclude_event(event, regs)) {
if (!(event->attr.exclude_idle && is_idle_task(current)))
- if (perf_event_overflow(event, &data, regs))
+ if (__perf_event_overflow(event, 1, &data, regs))
ret = HRTIMER_NORESTART;
}
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
new file mode 100644
index 000000000000..985be4d80fe8
--- /dev/null
+++ b/kernel/events/uprobes.c
@@ -0,0 +1,1667 @@
+/*
+ * User-space Probes (UProbes)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2008-2012
+ * Authors:
+ * Srikar Dronamraju
+ * Jim Keniston
+ * Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h> /* read_mapping_page */
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/rmap.h> /* anon_vma_prepare */
+#include <linux/mmu_notifier.h> /* set_pte_at_notify */
+#include <linux/swap.h> /* try_to_free_swap */
+#include <linux/ptrace.h> /* user_enable_single_step */
+#include <linux/kdebug.h> /* notifier mechanism */
+
+#include <linux/uprobes.h>
+
+#define UINSNS_PER_PAGE (PAGE_SIZE/UPROBE_XOL_SLOT_BYTES)
+#define MAX_UPROBE_XOL_SLOTS UINSNS_PER_PAGE
+
+static struct srcu_struct uprobes_srcu;
+static struct rb_root uprobes_tree = RB_ROOT;
+
+static DEFINE_SPINLOCK(uprobes_treelock); /* serialize rbtree access */
+
+#define UPROBES_HASH_SZ 13
+
+/* serialize (un)register */
+static struct mutex uprobes_mutex[UPROBES_HASH_SZ];
+
+#define uprobes_hash(v) (&uprobes_mutex[((unsigned long)(v)) % UPROBES_HASH_SZ])
+
+/* serialize uprobe->pending_list */
+static struct mutex uprobes_mmap_mutex[UPROBES_HASH_SZ];
+#define uprobes_mmap_hash(v) (&uprobes_mmap_mutex[((unsigned long)(v)) % UPROBES_HASH_SZ])
+
+/*
+ * uprobe_events allows us to skip the uprobe_mmap if there are no uprobe
+ * events active at this time. Probably a fine grained per inode count is
+ * better?
+ */
+static atomic_t uprobe_events = ATOMIC_INIT(0);
+
+/*
+ * Maintain a temporary per vma info that can be used to search if a vma
+ * has already been handled. This structure is introduced since extending
+ * vm_area_struct wasnt recommended.
+ */
+struct vma_info {
+ struct list_head probe_list;
+ struct mm_struct *mm;
+ loff_t vaddr;
+};
+
+struct uprobe {
+ struct rb_node rb_node; /* node in the rb tree */
+ atomic_t ref;
+ struct rw_semaphore consumer_rwsem;
+ struct list_head pending_list;
+ struct uprobe_consumer *consumers;
+ struct inode *inode; /* Also hold a ref to inode */
+ loff_t offset;
+ int flags;
+ struct arch_uprobe arch;
+};
+
+/*
+ * valid_vma: Verify if the specified vma is an executable vma
+ * Relax restrictions while unregistering: vm_flags might have
+ * changed after breakpoint was inserted.
+ * - is_register: indicates if we are in register context.
+ * - Return 1 if the specified virtual address is in an
+ * executable vma.
+ */
+static bool valid_vma(struct vm_area_struct *vma, bool is_register)
+{
+ if (!vma->vm_file)
+ return false;
+
+ if (!is_register)
+ return true;
+
+ if ((vma->vm_flags & (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)) == (VM_READ|VM_EXEC))
+ return true;
+
+ return false;
+}
+
+static loff_t vma_address(struct vm_area_struct *vma, loff_t offset)
+{
+ loff_t vaddr;
+
+ vaddr = vma->vm_start + offset;
+ vaddr -= vma->vm_pgoff << PAGE_SHIFT;
+
+ return vaddr;
+}
+
+/**
+ * __replace_page - replace page in vma by new page.
+ * based on replace_page in mm/ksm.c
+ *
+ * @vma: vma that holds the pte pointing to page
+ * @page: the cowed page we are replacing by kpage
+ * @kpage: the modified page we replace page by
+ *
+ * Returns 0 on success, -EFAULT on failure.
+ */
+static int __replace_page(struct vm_area_struct *vma, struct page *page, struct page *kpage)
+{
+ struct mm_struct *mm = vma->vm_mm;
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *ptep;
+ spinlock_t *ptl;
+ unsigned long addr;
+ int err = -EFAULT;
+
+ addr = page_address_in_vma(page, vma);
+ if (addr == -EFAULT)
+ goto out;
+
+ pgd = pgd_offset(mm, addr);
+ if (!pgd_present(*pgd))
+ goto out;
+
+ pud = pud_offset(pgd, addr);
+ if (!pud_present(*pud))
+ goto out;
+
+ pmd = pmd_offset(pud, addr);
+ if (!pmd_present(*pmd))
+ goto out;
+
+ ptep = pte_offset_map_lock(mm, pmd, addr, &ptl);
+ if (!ptep)
+ goto out;
+
+ get_page(kpage);
+ page_add_new_anon_rmap(kpage, vma, addr);
+
+ if (!PageAnon(page)) {
+ dec_mm_counter(mm, MM_FILEPAGES);
+ inc_mm_counter(mm, MM_ANONPAGES);
+ }
+
+ flush_cache_page(vma, addr, pte_pfn(*ptep));
+ ptep_clear_flush(vma, addr, ptep);
+ set_pte_at_notify(mm, addr, ptep, mk_pte(kpage, vma->vm_page_prot));
+
+ page_remove_rmap(page);
+ if (!page_mapped(page))
+ try_to_free_swap(page);
+ put_page(page);
+ pte_unmap_unlock(ptep, ptl);
+ err = 0;
+
+out:
+ return err;
+}
+
+/**
+ * is_swbp_insn - check if instruction is breakpoint instruction.
+ * @insn: instruction to be checked.
+ * Default implementation of is_swbp_insn
+ * Returns true if @insn is a breakpoint instruction.
+ */
+bool __weak is_swbp_insn(uprobe_opcode_t *insn)
+{
+ return *insn == UPROBE_SWBP_INSN;
+}
+
+/*
+ * NOTE:
+ * Expect the breakpoint instruction to be the smallest size instruction for
+ * the architecture. If an arch has variable length instruction and the
+ * breakpoint instruction is not of the smallest length instruction
+ * supported by that architecture then we need to modify read_opcode /
+ * write_opcode accordingly. This would never be a problem for archs that
+ * have fixed length instructions.
+ */
+
+/*
+ * write_opcode - write the opcode at a given virtual address.
+ * @auprobe: arch breakpointing information.
+ * @mm: the probed process address space.
+ * @vaddr: the virtual address to store the opcode.
+ * @opcode: opcode to be written at @vaddr.
+ *
+ * Called with mm->mmap_sem held (for read and with a reference to
+ * mm).
+ *
+ * For mm @mm, write the opcode at @vaddr.
+ * Return 0 (success) or a negative errno.
+ */
+static int write_opcode(struct arch_uprobe *auprobe, struct mm_struct *mm,
+ unsigned long vaddr, uprobe_opcode_t opcode)
+{
+ struct page *old_page, *new_page;
+ struct address_space *mapping;
+ void *vaddr_old, *vaddr_new;
+ struct vm_area_struct *vma;
+ struct uprobe *uprobe;
+ loff_t addr;
+ int ret;
+
+ /* Read the page with vaddr into memory */
+ ret = get_user_pages(NULL, mm, vaddr, 1, 0, 0, &old_page, &vma);
+ if (ret <= 0)
+ return ret;
+
+ ret = -EINVAL;
+
+ /*
+ * We are interested in text pages only. Our pages of interest
+ * should be mapped for read and execute only. We desist from
+ * adding probes in write mapped pages since the breakpoints
+ * might end up in the file copy.
+ */
+ if (!valid_vma(vma, is_swbp_insn(&opcode)))
+ goto put_out;
+
+ uprobe = container_of(auprobe, struct uprobe, arch);
+ mapping = uprobe->inode->i_mapping;
+ if (mapping != vma->vm_file->f_mapping)
+ goto put_out;
+
+ addr = vma_address(vma, uprobe->offset);
+ if (vaddr != (unsigned long)addr)
+ goto put_out;
+
+ ret = -ENOMEM;
+ new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, vaddr);
+ if (!new_page)
+ goto put_out;
+
+ __SetPageUptodate(new_page);
+
+ /*
+ * lock page will serialize against do_wp_page()'s
+ * PageAnon() handling
+ */
+ lock_page(old_page);
+ /* copy the page now that we've got it stable */
+ vaddr_old = kmap_atomic(old_page);
+ vaddr_new = kmap_atomic(new_page);
+
+ memcpy(vaddr_new, vaddr_old, PAGE_SIZE);
+
+ /* poke the new insn in, ASSUMES we don't cross page boundary */
+ vaddr &= ~PAGE_MASK;
+ BUG_ON(vaddr + UPROBE_SWBP_INSN_SIZE > PAGE_SIZE);
+ memcpy(vaddr_new + vaddr, &opcode, UPROBE_SWBP_INSN_SIZE);
+
+ kunmap_atomic(vaddr_new);
+ kunmap_atomic(vaddr_old);
+
+ ret = anon_vma_prepare(vma);
+ if (ret)
+ goto unlock_out;
+
+ lock_page(new_page);
+ ret = __replace_page(vma, old_page, new_page);
+ unlock_page(new_page);
+
+unlock_out:
+ unlock_page(old_page);
+ page_cache_release(new_page);
+
+put_out:
+ put_page(old_page);
+
+ return ret;
+}
+
+/**
+ * read_opcode - read the opcode at a given virtual address.
+ * @mm: the probed process address space.
+ * @vaddr: the virtual address to read the opcode.
+ * @opcode: location to store the read opcode.
+ *
+ * Called with mm->mmap_sem held (for read and with a reference to
+ * mm.
+ *
+ * For mm @mm, read the opcode at @vaddr and store it in @opcode.
+ * Return 0 (success) or a negative errno.
+ */
+static int read_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_t *opcode)
+{
+ struct page *page;
+ void *vaddr_new;
+ int ret;
+
+ ret = get_user_pages(NULL, mm, vaddr, 1, 0, 0, &page, NULL);
+ if (ret <= 0)
+ return ret;
+
+ lock_page(page);
+ vaddr_new = kmap_atomic(page);
+ vaddr &= ~PAGE_MASK;
+ memcpy(opcode, vaddr_new + vaddr, UPROBE_SWBP_INSN_SIZE);
+ kunmap_atomic(vaddr_new);
+ unlock_page(page);
+
+ put_page(page);
+
+ return 0;
+}
+
+static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr)
+{
+ uprobe_opcode_t opcode;
+ int result;
+
+ result = read_opcode(mm, vaddr, &opcode);
+ if (result)
+ return result;
+
+ if (is_swbp_insn(&opcode))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * set_swbp - store breakpoint at a given address.
+ * @auprobe: arch specific probepoint information.
+ * @mm: the probed process address space.
+ * @vaddr: the virtual address to insert the opcode.
+ *
+ * For mm @mm, store the breakpoint instruction at @vaddr.
+ * Return 0 (success) or a negative errno.
+ */
+int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr)
+{
+ int result;
+
+ result = is_swbp_at_addr(mm, vaddr);
+ if (result == 1)
+ return -EEXIST;
+
+ if (result)
+ return result;
+
+ return write_opcode(auprobe, mm, vaddr, UPROBE_SWBP_INSN);
+}
+
+/**
+ * set_orig_insn - Restore the original instruction.
+ * @mm: the probed process address space.
+ * @auprobe: arch specific probepoint information.
+ * @vaddr: the virtual address to insert the opcode.
+ * @verify: if true, verify existance of breakpoint instruction.
+ *
+ * For mm @mm, restore the original opcode (opcode) at @vaddr.
+ * Return 0 (success) or a negative errno.
+ */
+int __weak
+set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr, bool verify)
+{
+ if (verify) {
+ int result;
+
+ result = is_swbp_at_addr(mm, vaddr);
+ if (!result)
+ return -EINVAL;
+
+ if (result != 1)
+ return result;
+ }
+ return write_opcode(auprobe, mm, vaddr, *(uprobe_opcode_t *)auprobe->insn);
+}
+
+static int match_uprobe(struct uprobe *l, struct uprobe *r)
+{
+ if (l->inode < r->inode)
+ return -1;
+
+ if (l->inode > r->inode)
+ return 1;
+
+ if (l->offset < r->offset)
+ return -1;
+
+ if (l->offset > r->offset)
+ return 1;
+
+ return 0;
+}
+
+static struct uprobe *__find_uprobe(struct inode *inode, loff_t offset)
+{
+ struct uprobe u = { .inode = inode, .offset = offset };
+ struct rb_node *n = uprobes_tree.rb_node;
+ struct uprobe *uprobe;
+ int match;
+
+ while (n) {
+ uprobe = rb_entry(n, struct uprobe, rb_node);
+ match = match_uprobe(&u, uprobe);
+ if (!match) {
+ atomic_inc(&uprobe->ref);
+ return uprobe;
+ }
+
+ if (match < 0)
+ n = n->rb_left;
+ else
+ n = n->rb_right;
+ }
+ return NULL;
+}
+
+/*
+ * Find a uprobe corresponding to a given inode:offset
+ * Acquires uprobes_treelock
+ */
+static struct uprobe *find_uprobe(struct inode *inode, loff_t offset)
+{
+ struct uprobe *uprobe;
+ unsigned long flags;
+
+ spin_lock_irqsave(&uprobes_treelock, flags);
+ uprobe = __find_uprobe(inode, offset);
+ spin_unlock_irqrestore(&uprobes_treelock, flags);
+
+ return uprobe;
+}
+
+static struct uprobe *__insert_uprobe(struct uprobe *uprobe)
+{
+ struct rb_node **p = &uprobes_tree.rb_node;
+ struct rb_node *parent = NULL;
+ struct uprobe *u;
+ int match;
+
+ while (*p) {
+ parent = *p;
+ u = rb_entry(parent, struct uprobe, rb_node);
+ match = match_uprobe(uprobe, u);
+ if (!match) {
+ atomic_inc(&u->ref);
+ return u;
+ }
+
+ if (match < 0)
+ p = &parent->rb_left;
+ else
+ p = &parent->rb_right;
+
+ }
+
+ u = NULL;
+ rb_link_node(&uprobe->rb_node, parent, p);
+ rb_insert_color(&uprobe->rb_node, &uprobes_tree);
+ /* get access + creation ref */
+ atomic_set(&uprobe->ref, 2);
+
+ return u;
+}
+
+/*
+ * Acquire uprobes_treelock.
+ * Matching uprobe already exists in rbtree;
+ * increment (access refcount) and return the matching uprobe.
+ *
+ * No matching uprobe; insert the uprobe in rb_tree;
+ * get a double refcount (access + creation) and return NULL.
+ */
+static struct uprobe *insert_uprobe(struct uprobe *uprobe)
+{
+ unsigned long flags;
+ struct uprobe *u;
+
+ spin_lock_irqsave(&uprobes_treelock, flags);
+ u = __insert_uprobe(uprobe);
+ spin_unlock_irqrestore(&uprobes_treelock, flags);
+
+ /* For now assume that the instruction need not be single-stepped */
+ uprobe->flags |= UPROBE_SKIP_SSTEP;
+
+ return u;
+}
+
+static void put_uprobe(struct uprobe *uprobe)
+{
+ if (atomic_dec_and_test(&uprobe->ref))
+ kfree(uprobe);
+}
+
+static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset)
+{
+ struct uprobe *uprobe, *cur_uprobe;
+
+ uprobe = kzalloc(sizeof(struct uprobe), GFP_KERNEL);
+ if (!uprobe)
+ return NULL;
+
+ uprobe->inode = igrab(inode);
+ uprobe->offset = offset;
+ init_rwsem(&uprobe->consumer_rwsem);
+ INIT_LIST_HEAD(&uprobe->pending_list);
+
+ /* add to uprobes_tree, sorted on inode:offset */
+ cur_uprobe = insert_uprobe(uprobe);
+
+ /* a uprobe exists for this inode:offset combination */
+ if (cur_uprobe) {
+ kfree(uprobe);
+ uprobe = cur_uprobe;
+ iput(inode);
+ } else {
+ atomic_inc(&uprobe_events);
+ }
+
+ return uprobe;
+}
+
+static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
+{
+ struct uprobe_consumer *uc;
+
+ if (!(uprobe->flags & UPROBE_RUN_HANDLER))
+ return;
+
+ down_read(&uprobe->consumer_rwsem);
+ for (uc = uprobe->consumers; uc; uc = uc->next) {
+ if (!uc->filter || uc->filter(uc, current))
+ uc->handler(uc, regs);
+ }
+ up_read(&uprobe->consumer_rwsem);
+}
+
+/* Returns the previous consumer */
+static struct uprobe_consumer *
+consumer_add(struct uprobe *uprobe, struct uprobe_consumer *uc)
+{
+ down_write(&uprobe->consumer_rwsem);
+ uc->next = uprobe->consumers;
+ uprobe->consumers = uc;
+ up_write(&uprobe->consumer_rwsem);
+
+ return uc->next;
+}
+
+/*
+ * For uprobe @uprobe, delete the consumer @uc.
+ * Return true if the @uc is deleted successfully
+ * or return false.
+ */
+static bool consumer_del(struct uprobe *uprobe, struct uprobe_consumer *uc)
+{
+ struct uprobe_consumer **con;
+ bool ret = false;
+
+ down_write(&uprobe->consumer_rwsem);
+ for (con = &uprobe->consumers; *con; con = &(*con)->next) {
+ if (*con == uc) {
+ *con = uc->next;
+ ret = true;
+ break;
+ }
+ }
+ up_write(&uprobe->consumer_rwsem);
+
+ return ret;
+}
+
+static int
+__copy_insn(struct address_space *mapping, struct vm_area_struct *vma, char *insn,
+ unsigned long nbytes, unsigned long offset)
+{
+ struct file *filp = vma->vm_file;
+ struct page *page;
+ void *vaddr;
+ unsigned long off1;
+ unsigned long idx;
+
+ if (!filp)
+ return -EINVAL;
+
+ idx = (unsigned long)(offset >> PAGE_CACHE_SHIFT);
+ off1 = offset &= ~PAGE_MASK;
+
+ /*
+ * Ensure that the page that has the original instruction is
+ * populated and in page-cache.
+ */
+ page = read_mapping_page(mapping, idx, filp);
+ if (IS_ERR(page))
+ return PTR_ERR(page);
+
+ vaddr = kmap_atomic(page);
+ memcpy(insn, vaddr + off1, nbytes);
+ kunmap_atomic(vaddr);
+ page_cache_release(page);
+
+ return 0;
+}
+
+static int
+copy_insn(struct uprobe *uprobe, struct vm_area_struct *vma, unsigned long addr)
+{
+ struct address_space *mapping;
+ unsigned long nbytes;
+ int bytes;
+
+ addr &= ~PAGE_MASK;
+ nbytes = PAGE_SIZE - addr;
+ mapping = uprobe->inode->i_mapping;
+
+ /* Instruction at end of binary; copy only available bytes */
+ if (uprobe->offset + MAX_UINSN_BYTES > uprobe->inode->i_size)
+ bytes = uprobe->inode->i_size - uprobe->offset;
+ else
+ bytes = MAX_UINSN_BYTES;
+
+ /* Instruction at the page-boundary; copy bytes in second page */
+ if (nbytes < bytes) {
+ if (__copy_insn(mapping, vma, uprobe->arch.insn + nbytes,
+ bytes - nbytes, uprobe->offset + nbytes))
+ return -ENOMEM;
+
+ bytes = nbytes;
+ }
+ return __copy_insn(mapping, vma, uprobe->arch.insn, bytes, uprobe->offset);
+}
+
+/*
+ * How mm->uprobes_state.count gets updated
+ * uprobe_mmap() increments the count if
+ * - it successfully adds a breakpoint.
+ * - it cannot add a breakpoint, but sees that there is a underlying
+ * breakpoint (via a is_swbp_at_addr()).
+ *
+ * uprobe_munmap() decrements the count if
+ * - it sees a underlying breakpoint, (via is_swbp_at_addr)
+ * (Subsequent uprobe_unregister wouldnt find the breakpoint
+ * unless a uprobe_mmap kicks in, since the old vma would be
+ * dropped just after uprobe_munmap.)
+ *
+ * uprobe_register increments the count if:
+ * - it successfully adds a breakpoint.
+ *
+ * uprobe_unregister decrements the count if:
+ * - it sees a underlying breakpoint and removes successfully.
+ * (via is_swbp_at_addr)
+ * (Subsequent uprobe_munmap wouldnt find the breakpoint
+ * since there is no underlying breakpoint after the
+ * breakpoint removal.)
+ */
+static int
+install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm,
+ struct vm_area_struct *vma, loff_t vaddr)
+{
+ unsigned long addr;
+ int ret;
+
+ /*
+ * If probe is being deleted, unregister thread could be done with
+ * the vma-rmap-walk through. Adding a probe now can be fatal since
+ * nobody will be able to cleanup. Also we could be from fork or
+ * mremap path, where the probe might have already been inserted.
+ * Hence behave as if probe already existed.
+ */
+ if (!uprobe->consumers)
+ return -EEXIST;
+
+ addr = (unsigned long)vaddr;
+
+ if (!(uprobe->flags & UPROBE_COPY_INSN)) {
+ ret = copy_insn(uprobe, vma, addr);
+ if (ret)
+ return ret;
+
+ if (is_swbp_insn((uprobe_opcode_t *)uprobe->arch.insn))
+ return -EEXIST;
+
+ ret = arch_uprobe_analyze_insn(&uprobe->arch, mm);
+ if (ret)
+ return ret;
+
+ uprobe->flags |= UPROBE_COPY_INSN;
+ }
+
+ /*
+ * Ideally, should be updating the probe count after the breakpoint
+ * has been successfully inserted. However a thread could hit the
+ * breakpoint we just inserted even before the probe count is
+ * incremented. If this is the first breakpoint placed, breakpoint
+ * notifier might ignore uprobes and pass the trap to the thread.
+ * Hence increment before and decrement on failure.
+ */
+ atomic_inc(&mm->uprobes_state.count);
+ ret = set_swbp(&uprobe->arch, mm, addr);
+ if (ret)
+ atomic_dec(&mm->uprobes_state.count);
+
+ return ret;
+}
+
+static void
+remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, loff_t vaddr)
+{
+ if (!set_orig_insn(&uprobe->arch, mm, (unsigned long)vaddr, true))
+ atomic_dec(&mm->uprobes_state.count);
+}
+
+/*
+ * There could be threads that have hit the breakpoint and are entering the
+ * notifier code and trying to acquire the uprobes_treelock. The thread
+ * calling delete_uprobe() that is removing the uprobe from the rb_tree can
+ * race with these threads and might acquire the uprobes_treelock compared
+ * to some of the breakpoint hit threads. In such a case, the breakpoint
+ * hit threads will not find the uprobe. The current unregistering thread
+ * waits till all other threads have hit a breakpoint, to acquire the
+ * uprobes_treelock before the uprobe is removed from the rbtree.
+ */
+static void delete_uprobe(struct uprobe *uprobe)
+{
+ unsigned long flags;
+
+ synchronize_srcu(&uprobes_srcu);
+ spin_lock_irqsave(&uprobes_treelock, flags);
+ rb_erase(&uprobe->rb_node, &uprobes_tree);
+ spin_unlock_irqrestore(&uprobes_treelock, flags);
+ iput(uprobe->inode);
+ put_uprobe(uprobe);
+ atomic_dec(&uprobe_events);
+}
+
+static struct vma_info *
+__find_next_vma_info(struct address_space *mapping, struct list_head *head,
+ struct vma_info *vi, loff_t offset, bool is_register)
+{
+ struct prio_tree_iter iter;
+ struct vm_area_struct *vma;
+ struct vma_info *tmpvi;
+ unsigned long pgoff;
+ int existing_vma;
+ loff_t vaddr;
+
+ pgoff = offset >> PAGE_SHIFT;
+
+ vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
+ if (!valid_vma(vma, is_register))
+ continue;
+
+ existing_vma = 0;
+ vaddr = vma_address(vma, offset);
+
+ list_for_each_entry(tmpvi, head, probe_list) {
+ if (tmpvi->mm == vma->vm_mm && tmpvi->vaddr == vaddr) {
+ existing_vma = 1;
+ break;
+ }
+ }
+
+ /*
+ * Another vma needs a probe to be installed. However skip
+ * installing the probe if the vma is about to be unlinked.
+ */
+ if (!existing_vma && atomic_inc_not_zero(&vma->vm_mm->mm_users)) {
+ vi->mm = vma->vm_mm;
+ vi->vaddr = vaddr;
+ list_add(&vi->probe_list, head);
+
+ return vi;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Iterate in the rmap prio tree and find a vma where a probe has not
+ * yet been inserted.
+ */
+static struct vma_info *
+find_next_vma_info(struct address_space *mapping, struct list_head *head,
+ loff_t offset, bool is_register)
+{
+ struct vma_info *vi, *retvi;
+
+ vi = kzalloc(sizeof(struct vma_info), GFP_KERNEL);
+ if (!vi)
+ return ERR_PTR(-ENOMEM);
+
+ mutex_lock(&mapping->i_mmap_mutex);
+ retvi = __find_next_vma_info(mapping, head, vi, offset, is_register);
+ mutex_unlock(&mapping->i_mmap_mutex);
+
+ if (!retvi)
+ kfree(vi);
+
+ return retvi;
+}
+
+static int register_for_each_vma(struct uprobe *uprobe, bool is_register)
+{
+ struct list_head try_list;
+ struct vm_area_struct *vma;
+ struct address_space *mapping;
+ struct vma_info *vi, *tmpvi;
+ struct mm_struct *mm;
+ loff_t vaddr;
+ int ret;
+
+ mapping = uprobe->inode->i_mapping;
+ INIT_LIST_HEAD(&try_list);
+
+ ret = 0;
+
+ for (;;) {
+ vi = find_next_vma_info(mapping, &try_list, uprobe->offset, is_register);
+ if (!vi)
+ break;
+
+ if (IS_ERR(vi)) {
+ ret = PTR_ERR(vi);
+ break;
+ }
+
+ mm = vi->mm;
+ down_read(&mm->mmap_sem);
+ vma = find_vma(mm, (unsigned long)vi->vaddr);
+ if (!vma || !valid_vma(vma, is_register)) {
+ list_del(&vi->probe_list);
+ kfree(vi);
+ up_read(&mm->mmap_sem);
+ mmput(mm);
+ continue;
+ }
+ vaddr = vma_address(vma, uprobe->offset);
+ if (vma->vm_file->f_mapping->host != uprobe->inode ||
+ vaddr != vi->vaddr) {
+ list_del(&vi->probe_list);
+ kfree(vi);
+ up_read(&mm->mmap_sem);
+ mmput(mm);
+ continue;
+ }
+
+ if (is_register)
+ ret = install_breakpoint(uprobe, mm, vma, vi->vaddr);
+ else
+ remove_breakpoint(uprobe, mm, vi->vaddr);
+
+ up_read(&mm->mmap_sem);
+ mmput(mm);
+ if (is_register) {
+ if (ret && ret == -EEXIST)
+ ret = 0;
+ if (ret)
+ break;
+ }
+ }
+
+ list_for_each_entry_safe(vi, tmpvi, &try_list, probe_list) {
+ list_del(&vi->probe_list);
+ kfree(vi);
+ }
+
+ return ret;
+}
+
+static int __uprobe_register(struct uprobe *uprobe)
+{
+ return register_for_each_vma(uprobe, true);
+}
+
+static void __uprobe_unregister(struct uprobe *uprobe)
+{
+ if (!register_for_each_vma(uprobe, false))
+ delete_uprobe(uprobe);
+
+ /* TODO : cant unregister? schedule a worker thread */
+}
+
+/*
+ * uprobe_register - register a probe
+ * @inode: the file in which the probe has to be placed.
+ * @offset: offset from the start of the file.
+ * @uc: information on howto handle the probe..
+ *
+ * Apart from the access refcount, uprobe_register() takes a creation
+ * refcount (thro alloc_uprobe) if and only if this @uprobe is getting
+ * inserted into the rbtree (i.e first consumer for a @inode:@offset
+ * tuple). Creation refcount stops uprobe_unregister from freeing the
+ * @uprobe even before the register operation is complete. Creation
+ * refcount is released when the last @uc for the @uprobe
+ * unregisters.
+ *
+ * Return errno if it cannot successully install probes
+ * else return 0 (success)
+ */
+int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc)
+{
+ struct uprobe *uprobe;
+ int ret;
+
+ if (!inode || !uc || uc->next)
+ return -EINVAL;
+
+ if (offset > i_size_read(inode))
+ return -EINVAL;
+
+ ret = 0;
+ mutex_lock(uprobes_hash(inode));
+ uprobe = alloc_uprobe(inode, offset);
+
+ if (uprobe && !consumer_add(uprobe, uc)) {
+ ret = __uprobe_register(uprobe);
+ if (ret) {
+ uprobe->consumers = NULL;
+ __uprobe_unregister(uprobe);
+ } else {
+ uprobe->flags |= UPROBE_RUN_HANDLER;
+ }
+ }
+
+ mutex_unlock(uprobes_hash(inode));
+ put_uprobe(uprobe);
+
+ return ret;
+}
+
+/*
+ * uprobe_unregister - unregister a already registered probe.
+ * @inode: the file in which the probe has to be removed.
+ * @offset: offset from the start of the file.
+ * @uc: identify which probe if multiple probes are colocated.
+ */
+void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc)
+{
+ struct uprobe *uprobe;
+
+ if (!inode || !uc)
+ return;
+
+ uprobe = find_uprobe(inode, offset);
+ if (!uprobe)
+ return;
+
+ mutex_lock(uprobes_hash(inode));
+
+ if (consumer_del(uprobe, uc)) {
+ if (!uprobe->consumers) {
+ __uprobe_unregister(uprobe);
+ uprobe->flags &= ~UPROBE_RUN_HANDLER;
+ }
+ }
+
+ mutex_unlock(uprobes_hash(inode));
+ if (uprobe)
+ put_uprobe(uprobe);
+}
+
+/*
+ * Of all the nodes that correspond to the given inode, return the node
+ * with the least offset.
+ */
+static struct rb_node *find_least_offset_node(struct inode *inode)
+{
+ struct uprobe u = { .inode = inode, .offset = 0};
+ struct rb_node *n = uprobes_tree.rb_node;
+ struct rb_node *close_node = NULL;
+ struct uprobe *uprobe;
+ int match;
+
+ while (n) {
+ uprobe = rb_entry(n, struct uprobe, rb_node);
+ match = match_uprobe(&u, uprobe);
+
+ if (uprobe->inode == inode)
+ close_node = n;
+
+ if (!match)
+ return close_node;
+
+ if (match < 0)
+ n = n->rb_left;
+ else
+ n = n->rb_right;
+ }
+
+ return close_node;
+}
+
+/*
+ * For a given inode, build a list of probes that need to be inserted.
+ */
+static void build_probe_list(struct inode *inode, struct list_head *head)
+{
+ struct uprobe *uprobe;
+ unsigned long flags;
+ struct rb_node *n;
+
+ spin_lock_irqsave(&uprobes_treelock, flags);
+
+ n = find_least_offset_node(inode);
+
+ for (; n; n = rb_next(n)) {
+ uprobe = rb_entry(n, struct uprobe, rb_node);
+ if (uprobe->inode != inode)
+ break;
+
+ list_add(&uprobe->pending_list, head);
+ atomic_inc(&uprobe->ref);
+ }
+
+ spin_unlock_irqrestore(&uprobes_treelock, flags);
+}
+
+/*
+ * Called from mmap_region.
+ * called with mm->mmap_sem acquired.
+ *
+ * Return -ve no if we fail to insert probes and we cannot
+ * bail-out.
+ * Return 0 otherwise. i.e:
+ *
+ * - successful insertion of probes
+ * - (or) no possible probes to be inserted.
+ * - (or) insertion of probes failed but we can bail-out.
+ */
+int uprobe_mmap(struct vm_area_struct *vma)
+{
+ struct list_head tmp_list;
+ struct uprobe *uprobe, *u;
+ struct inode *inode;
+ int ret, count;
+
+ if (!atomic_read(&uprobe_events) || !valid_vma(vma, true))
+ return 0;
+
+ inode = vma->vm_file->f_mapping->host;
+ if (!inode)
+ return 0;
+
+ INIT_LIST_HEAD(&tmp_list);
+ mutex_lock(uprobes_mmap_hash(inode));
+ build_probe_list(inode, &tmp_list);
+
+ ret = 0;
+ count = 0;
+
+ list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) {
+ loff_t vaddr;
+
+ list_del(&uprobe->pending_list);
+ if (!ret) {
+ vaddr = vma_address(vma, uprobe->offset);
+
+ if (vaddr < vma->vm_start || vaddr >= vma->vm_end) {
+ put_uprobe(uprobe);
+ continue;
+ }
+
+ ret = install_breakpoint(uprobe, vma->vm_mm, vma, vaddr);
+
+ /* Ignore double add: */
+ if (ret == -EEXIST) {
+ ret = 0;
+
+ if (!is_swbp_at_addr(vma->vm_mm, vaddr))
+ continue;
+
+ /*
+ * Unable to insert a breakpoint, but
+ * breakpoint lies underneath. Increment the
+ * probe count.
+ */
+ atomic_inc(&vma->vm_mm->uprobes_state.count);
+ }
+
+ if (!ret)
+ count++;
+ }
+ put_uprobe(uprobe);
+ }
+
+ mutex_unlock(uprobes_mmap_hash(inode));
+
+ if (ret)
+ atomic_sub(count, &vma->vm_mm->uprobes_state.count);
+
+ return ret;
+}
+
+/*
+ * Called in context of a munmap of a vma.
+ */
+void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end)
+{
+ struct list_head tmp_list;
+ struct uprobe *uprobe, *u;
+ struct inode *inode;
+
+ if (!atomic_read(&uprobe_events) || !valid_vma(vma, false))
+ return;
+
+ if (!atomic_read(&vma->vm_mm->uprobes_state.count))
+ return;
+
+ inode = vma->vm_file->f_mapping->host;
+ if (!inode)
+ return;
+
+ INIT_LIST_HEAD(&tmp_list);
+ mutex_lock(uprobes_mmap_hash(inode));
+ build_probe_list(inode, &tmp_list);
+
+ list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) {
+ loff_t vaddr;
+
+ list_del(&uprobe->pending_list);
+ vaddr = vma_address(vma, uprobe->offset);
+
+ if (vaddr >= start && vaddr < end) {
+ /*
+ * An unregister could have removed the probe before
+ * unmap. So check before we decrement the count.
+ */
+ if (is_swbp_at_addr(vma->vm_mm, vaddr) == 1)
+ atomic_dec(&vma->vm_mm->uprobes_state.count);
+ }
+ put_uprobe(uprobe);
+ }
+ mutex_unlock(uprobes_mmap_hash(inode));
+}
+
+/* Slot allocation for XOL */
+static int xol_add_vma(struct xol_area *area)
+{
+ struct mm_struct *mm;
+ int ret;
+
+ area->page = alloc_page(GFP_HIGHUSER);
+ if (!area->page)
+ return -ENOMEM;
+
+ ret = -EALREADY;
+ mm = current->mm;
+
+ down_write(&mm->mmap_sem);
+ if (mm->uprobes_state.xol_area)
+ goto fail;
+
+ ret = -ENOMEM;
+
+ /* Try to map as high as possible, this is only a hint. */
+ area->vaddr = get_unmapped_area(NULL, TASK_SIZE - PAGE_SIZE, PAGE_SIZE, 0, 0);
+ if (area->vaddr & ~PAGE_MASK) {
+ ret = area->vaddr;
+ goto fail;
+ }
+
+ ret = install_special_mapping(mm, area->vaddr, PAGE_SIZE,
+ VM_EXEC|VM_MAYEXEC|VM_DONTCOPY|VM_IO, &area->page);
+ if (ret)
+ goto fail;
+
+ smp_wmb(); /* pairs with get_xol_area() */
+ mm->uprobes_state.xol_area = area;
+ ret = 0;
+
+fail:
+ up_write(&mm->mmap_sem);
+ if (ret)
+ __free_page(area->page);
+
+ return ret;
+}
+
+static struct xol_area *get_xol_area(struct mm_struct *mm)
+{
+ struct xol_area *area;
+
+ area = mm->uprobes_state.xol_area;
+ smp_read_barrier_depends(); /* pairs with wmb in xol_add_vma() */
+
+ return area;
+}
+
+/*
+ * xol_alloc_area - Allocate process's xol_area.
+ * This area will be used for storing instructions for execution out of
+ * line.
+ *
+ * Returns the allocated area or NULL.
+ */
+static struct xol_area *xol_alloc_area(void)
+{
+ struct xol_area *area;
+
+ area = kzalloc(sizeof(*area), GFP_KERNEL);
+ if (unlikely(!area))
+ return NULL;
+
+ area->bitmap = kzalloc(BITS_TO_LONGS(UINSNS_PER_PAGE) * sizeof(long), GFP_KERNEL);
+
+ if (!area->bitmap)
+ goto fail;
+
+ init_waitqueue_head(&area->wq);
+ if (!xol_add_vma(area))
+ return area;
+
+fail:
+ kfree(area->bitmap);
+ kfree(area);
+
+ return get_xol_area(current->mm);
+}
+
+/*
+ * uprobe_clear_state - Free the area allocated for slots.
+ */
+void uprobe_clear_state(struct mm_struct *mm)
+{
+ struct xol_area *area = mm->uprobes_state.xol_area;
+
+ if (!area)
+ return;
+
+ put_page(area->page);
+ kfree(area->bitmap);
+ kfree(area);
+}
+
+/*
+ * uprobe_reset_state - Free the area allocated for slots.
+ */
+void uprobe_reset_state(struct mm_struct *mm)
+{
+ mm->uprobes_state.xol_area = NULL;
+ atomic_set(&mm->uprobes_state.count, 0);
+}
+
+/*
+ * - search for a free slot.
+ */
+static unsigned long xol_take_insn_slot(struct xol_area *area)
+{
+ unsigned long slot_addr;
+ int slot_nr;
+
+ do {
+ slot_nr = find_first_zero_bit(area->bitmap, UINSNS_PER_PAGE);
+ if (slot_nr < UINSNS_PER_PAGE) {
+ if (!test_and_set_bit(slot_nr, area->bitmap))
+ break;
+
+ slot_nr = UINSNS_PER_PAGE;
+ continue;
+ }
+ wait_event(area->wq, (atomic_read(&area->slot_count) < UINSNS_PER_PAGE));
+ } while (slot_nr >= UINSNS_PER_PAGE);
+
+ slot_addr = area->vaddr + (slot_nr * UPROBE_XOL_SLOT_BYTES);
+ atomic_inc(&area->slot_count);
+
+ return slot_addr;
+}
+
+/*
+ * xol_get_insn_slot - If was not allocated a slot, then
+ * allocate a slot.
+ * Returns the allocated slot address or 0.
+ */
+static unsigned long xol_get_insn_slot(struct uprobe *uprobe, unsigned long slot_addr)
+{
+ struct xol_area *area;
+ unsigned long offset;
+ void *vaddr;
+
+ area = get_xol_area(current->mm);
+ if (!area) {
+ area = xol_alloc_area();
+ if (!area)
+ return 0;
+ }
+ current->utask->xol_vaddr = xol_take_insn_slot(area);
+
+ /*
+ * Initialize the slot if xol_vaddr points to valid
+ * instruction slot.
+ */
+ if (unlikely(!current->utask->xol_vaddr))
+ return 0;
+
+ current->utask->vaddr = slot_addr;
+ offset = current->utask->xol_vaddr & ~PAGE_MASK;
+ vaddr = kmap_atomic(area->page);
+ memcpy(vaddr + offset, uprobe->arch.insn, MAX_UINSN_BYTES);
+ kunmap_atomic(vaddr);
+
+ return current->utask->xol_vaddr;
+}
+
+/*
+ * xol_free_insn_slot - If slot was earlier allocated by
+ * @xol_get_insn_slot(), make the slot available for
+ * subsequent requests.
+ */
+static void xol_free_insn_slot(struct task_struct *tsk)
+{
+ struct xol_area *area;
+ unsigned long vma_end;
+ unsigned long slot_addr;
+
+ if (!tsk->mm || !tsk->mm->uprobes_state.xol_area || !tsk->utask)
+ return;
+
+ slot_addr = tsk->utask->xol_vaddr;
+
+ if (unlikely(!slot_addr || IS_ERR_VALUE(slot_addr)))
+ return;
+
+ area = tsk->mm->uprobes_state.xol_area;
+ vma_end = area->vaddr + PAGE_SIZE;
+ if (area->vaddr <= slot_addr && slot_addr < vma_end) {
+ unsigned long offset;
+ int slot_nr;
+
+ offset = slot_addr - area->vaddr;
+ slot_nr = offset / UPROBE_XOL_SLOT_BYTES;
+ if (slot_nr >= UINSNS_PER_PAGE)
+ return;
+
+ clear_bit(slot_nr, area->bitmap);
+ atomic_dec(&area->slot_count);
+ if (waitqueue_active(&area->wq))
+ wake_up(&area->wq);
+
+ tsk->utask->xol_vaddr = 0;
+ }
+}
+
+/**
+ * uprobe_get_swbp_addr - compute address of swbp given post-swbp regs
+ * @regs: Reflects the saved state of the task after it has hit a breakpoint
+ * instruction.
+ * Return the address of the breakpoint instruction.
+ */
+unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs)
+{
+ return instruction_pointer(regs) - UPROBE_SWBP_INSN_SIZE;
+}
+
+/*
+ * Called with no locks held.
+ * Called in context of a exiting or a exec-ing thread.
+ */
+void uprobe_free_utask(struct task_struct *t)
+{
+ struct uprobe_task *utask = t->utask;
+
+ if (t->uprobe_srcu_id != -1)
+ srcu_read_unlock_raw(&uprobes_srcu, t->uprobe_srcu_id);
+
+ if (!utask)
+ return;
+
+ if (utask->active_uprobe)
+ put_uprobe(utask->active_uprobe);
+
+ xol_free_insn_slot(t);
+ kfree(utask);
+ t->utask = NULL;
+}
+
+/*
+ * Called in context of a new clone/fork from copy_process.
+ */
+void uprobe_copy_process(struct task_struct *t)
+{
+ t->utask = NULL;
+ t->uprobe_srcu_id = -1;
+}
+
+/*
+ * Allocate a uprobe_task object for the task.
+ * Called when the thread hits a breakpoint for the first time.
+ *
+ * Returns:
+ * - pointer to new uprobe_task on success
+ * - NULL otherwise
+ */
+static struct uprobe_task *add_utask(void)
+{
+ struct uprobe_task *utask;
+
+ utask = kzalloc(sizeof *utask, GFP_KERNEL);
+ if (unlikely(!utask))
+ return NULL;
+
+ utask->active_uprobe = NULL;
+ current->utask = utask;
+ return utask;
+}
+
+/* Prepare to single-step probed instruction out of line. */
+static int
+pre_ssout(struct uprobe *uprobe, struct pt_regs *regs, unsigned long vaddr)
+{
+ if (xol_get_insn_slot(uprobe, vaddr) && !arch_uprobe_pre_xol(&uprobe->arch, regs))
+ return 0;
+
+ return -EFAULT;
+}
+
+/*
+ * If we are singlestepping, then ensure this thread is not connected to
+ * non-fatal signals until completion of singlestep. When xol insn itself
+ * triggers the signal, restart the original insn even if the task is
+ * already SIGKILL'ed (since coredump should report the correct ip). This
+ * is even more important if the task has a handler for SIGSEGV/etc, The
+ * _same_ instruction should be repeated again after return from the signal
+ * handler, and SSTEP can never finish in this case.
+ */
+bool uprobe_deny_signal(void)
+{
+ struct task_struct *t = current;
+ struct uprobe_task *utask = t->utask;
+
+ if (likely(!utask || !utask->active_uprobe))
+ return false;
+
+ WARN_ON_ONCE(utask->state != UTASK_SSTEP);
+
+ if (signal_pending(t)) {
+ spin_lock_irq(&t->sighand->siglock);
+ clear_tsk_thread_flag(t, TIF_SIGPENDING);
+ spin_unlock_irq(&t->sighand->siglock);
+
+ if (__fatal_signal_pending(t) || arch_uprobe_xol_was_trapped(t)) {
+ utask->state = UTASK_SSTEP_TRAPPED;
+ set_tsk_thread_flag(t, TIF_UPROBE);
+ set_tsk_thread_flag(t, TIF_NOTIFY_RESUME);
+ }
+ }
+
+ return true;
+}
+
+/*
+ * Avoid singlestepping the original instruction if the original instruction
+ * is a NOP or can be emulated.
+ */
+static bool can_skip_sstep(struct uprobe *uprobe, struct pt_regs *regs)
+{
+ if (arch_uprobe_skip_sstep(&uprobe->arch, regs))
+ return true;
+
+ uprobe->flags &= ~UPROBE_SKIP_SSTEP;
+ return false;
+}
+
+/*
+ * Run handler and ask thread to singlestep.
+ * Ensure all non-fatal signals cannot interrupt thread while it singlesteps.
+ */
+static void handle_swbp(struct pt_regs *regs)
+{
+ struct vm_area_struct *vma;
+ struct uprobe_task *utask;
+ struct uprobe *uprobe;
+ struct mm_struct *mm;
+ unsigned long bp_vaddr;
+
+ uprobe = NULL;
+ bp_vaddr = uprobe_get_swbp_addr(regs);
+ mm = current->mm;
+ down_read(&mm->mmap_sem);
+ vma = find_vma(mm, bp_vaddr);
+
+ if (vma && vma->vm_start <= bp_vaddr && valid_vma(vma, false)) {
+ struct inode *inode;
+ loff_t offset;
+
+ inode = vma->vm_file->f_mapping->host;
+ offset = bp_vaddr - vma->vm_start;
+ offset += (vma->vm_pgoff << PAGE_SHIFT);
+ uprobe = find_uprobe(inode, offset);
+ }
+
+ srcu_read_unlock_raw(&uprobes_srcu, current->uprobe_srcu_id);
+ current->uprobe_srcu_id = -1;
+ up_read(&mm->mmap_sem);
+
+ if (!uprobe) {
+ /* No matching uprobe; signal SIGTRAP. */
+ send_sig(SIGTRAP, current, 0);
+ return;
+ }
+
+ utask = current->utask;
+ if (!utask) {
+ utask = add_utask();
+ /* Cannot allocate; re-execute the instruction. */
+ if (!utask)
+ goto cleanup_ret;
+ }
+ utask->active_uprobe = uprobe;
+ handler_chain(uprobe, regs);
+ if (uprobe->flags & UPROBE_SKIP_SSTEP && can_skip_sstep(uprobe, regs))
+ goto cleanup_ret;
+
+ utask->state = UTASK_SSTEP;
+ if (!pre_ssout(uprobe, regs, bp_vaddr)) {
+ user_enable_single_step(current);
+ return;
+ }
+
+cleanup_ret:
+ if (utask) {
+ utask->active_uprobe = NULL;
+ utask->state = UTASK_RUNNING;
+ }
+ if (uprobe) {
+ if (!(uprobe->flags & UPROBE_SKIP_SSTEP))
+
+ /*
+ * cannot singlestep; cannot skip instruction;
+ * re-execute the instruction.
+ */
+ instruction_pointer_set(regs, bp_vaddr);
+
+ put_uprobe(uprobe);
+ }
+}
+
+/*
+ * Perform required fix-ups and disable singlestep.
+ * Allow pending signals to take effect.
+ */
+static void handle_singlestep(struct uprobe_task *utask, struct pt_regs *regs)
+{
+ struct uprobe *uprobe;
+
+ uprobe = utask->active_uprobe;
+ if (utask->state == UTASK_SSTEP_ACK)
+ arch_uprobe_post_xol(&uprobe->arch, regs);
+ else if (utask->state == UTASK_SSTEP_TRAPPED)
+ arch_uprobe_abort_xol(&uprobe->arch, regs);
+ else
+ WARN_ON_ONCE(1);
+
+ put_uprobe(uprobe);
+ utask->active_uprobe = NULL;
+ utask->state = UTASK_RUNNING;
+ user_disable_single_step(current);
+ xol_free_insn_slot(current);
+
+ spin_lock_irq(&current->sighand->siglock);
+ recalc_sigpending(); /* see uprobe_deny_signal() */
+ spin_unlock_irq(&current->sighand->siglock);
+}
+
+/*
+ * On breakpoint hit, breakpoint notifier sets the TIF_UPROBE flag. (and on
+ * subsequent probe hits on the thread sets the state to UTASK_BP_HIT) and
+ * allows the thread to return from interrupt.
+ *
+ * On singlestep exception, singlestep notifier sets the TIF_UPROBE flag and
+ * also sets the state to UTASK_SSTEP_ACK and allows the thread to return from
+ * interrupt.
+ *
+ * While returning to userspace, thread notices the TIF_UPROBE flag and calls
+ * uprobe_notify_resume().
+ */
+void uprobe_notify_resume(struct pt_regs *regs)
+{
+ struct uprobe_task *utask;
+
+ utask = current->utask;
+ if (!utask || utask->state == UTASK_BP_HIT)
+ handle_swbp(regs);
+ else
+ handle_singlestep(utask, regs);
+}
+
+/*
+ * uprobe_pre_sstep_notifier gets called from interrupt context as part of
+ * notifier mechanism. Set TIF_UPROBE flag and indicate breakpoint hit.
+ */
+int uprobe_pre_sstep_notifier(struct pt_regs *regs)
+{
+ struct uprobe_task *utask;
+
+ if (!current->mm || !atomic_read(&current->mm->uprobes_state.count))
+ /* task is currently not uprobed */
+ return 0;
+
+ utask = current->utask;
+ if (utask)
+ utask->state = UTASK_BP_HIT;
+
+ set_thread_flag(TIF_UPROBE);
+ current->uprobe_srcu_id = srcu_read_lock_raw(&uprobes_srcu);
+
+ return 1;
+}
+
+/*
+ * uprobe_post_sstep_notifier gets called in interrupt context as part of notifier
+ * mechanism. Set TIF_UPROBE flag and indicate completion of singlestep.
+ */
+int uprobe_post_sstep_notifier(struct pt_regs *regs)
+{
+ struct uprobe_task *utask = current->utask;
+
+ if (!current->mm || !utask || !utask->active_uprobe)
+ /* task is currently not uprobed */
+ return 0;
+
+ utask->state = UTASK_SSTEP_ACK;
+ set_thread_flag(TIF_UPROBE);
+ return 1;
+}
+
+static struct notifier_block uprobe_exception_nb = {
+ .notifier_call = arch_uprobe_exception_notify,
+ .priority = INT_MAX-1, /* notified after kprobes, kgdb */
+};
+
+static int __init init_uprobes(void)
+{
+ int i;
+
+ for (i = 0; i < UPROBES_HASH_SZ; i++) {
+ mutex_init(&uprobes_mutex[i]);
+ mutex_init(&uprobes_mmap_mutex[i]);
+ }
+ init_srcu_struct(&uprobes_srcu);
+
+ return register_die_notifier(&uprobe_exception_nb);
+}
+module_init(init_uprobes);
+
+static void __exit exit_uprobes(void)
+{
+}
+module_exit(exit_uprobes);
diff --git a/kernel/exit.c b/kernel/exit.c
index d8bd3b425fa7..910a0716e17a 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -1214,7 +1214,7 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
unsigned long state;
int retval, status, traced;
pid_t pid = task_pid_vnr(p);
- uid_t uid = __task_cred(p)->uid;
+ uid_t uid = from_kuid_munged(current_user_ns(), __task_cred(p)->uid);
struct siginfo __user *infop;
if (!likely(wo->wo_flags & WEXITED))
@@ -1427,7 +1427,7 @@ static int wait_task_stopped(struct wait_opts *wo,
if (!unlikely(wo->wo_flags & WNOWAIT))
*p_code = 0;
- uid = task_uid(p);
+ uid = from_kuid_munged(current_user_ns(), task_uid(p));
unlock_sig:
spin_unlock_irq(&p->sighand->siglock);
if (!exit_code)
@@ -1500,7 +1500,7 @@ static int wait_task_continued(struct wait_opts *wo, struct task_struct *p)
}
if (!unlikely(wo->wo_flags & WNOWAIT))
p->signal->flags &= ~SIGNAL_STOP_CONTINUED;
- uid = task_uid(p);
+ uid = from_kuid_munged(current_user_ns(), task_uid(p));
spin_unlock_irq(&p->sighand->siglock);
pid = task_pid_vnr(p);
diff --git a/kernel/extable.c b/kernel/extable.c
index 5339705b8241..fe35a634bf76 100644
--- a/kernel/extable.c
+++ b/kernel/extable.c
@@ -35,10 +35,16 @@ DEFINE_MUTEX(text_mutex);
extern struct exception_table_entry __start___ex_table[];
extern struct exception_table_entry __stop___ex_table[];
+/* Cleared by build time tools if the table is already sorted. */
+u32 __initdata main_extable_sort_needed = 1;
+
/* Sort the kernel's built-in exception table */
void __init sort_main_extable(void)
{
- sort_extable(__start___ex_table, __stop___ex_table);
+ if (main_extable_sort_needed)
+ sort_extable(__start___ex_table, __stop___ex_table);
+ else
+ pr_notice("__ex_table already sorted, skipping sort\n");
}
/* Given an address, look for it in the exception tables. */
diff --git a/kernel/fork.c b/kernel/fork.c
index ad54c833116a..47b4e4f379f9 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -69,6 +69,7 @@
#include <linux/oom.h>
#include <linux/khugepaged.h>
#include <linux/signalfd.h>
+#include <linux/uprobes.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
@@ -292,8 +293,6 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
int node = tsk_fork_get_node(orig);
int err;
- prepare_to_copy(orig);
-
tsk = alloc_task_struct_node(node);
if (!tsk)
return NULL;
@@ -453,6 +452,9 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
if (retval)
goto out;
+
+ if (file && uprobe_mmap(tmp))
+ goto out;
}
/* a new mm has just been created */
arch_dup_mmap(oldmm, mm);
@@ -601,6 +603,7 @@ void mmput(struct mm_struct *mm)
might_sleep();
if (atomic_dec_and_test(&mm->mm_users)) {
+ uprobe_clear_state(mm);
exit_aio(mm);
ksm_exit(mm);
khugepaged_exit(mm); /* must run before exit_mmap */
@@ -779,6 +782,8 @@ void mm_release(struct task_struct *tsk, struct mm_struct *mm)
exit_pi_state_list(tsk);
#endif
+ uprobe_free_utask(tsk);
+
/* Get rid of any cached register state */
deactivate_mm(tsk, mm);
@@ -833,6 +838,7 @@ struct mm_struct *dup_mm(struct task_struct *tsk)
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
mm->pmd_huge_pte = NULL;
#endif
+ uprobe_reset_state(mm);
if (!mm_init(mm, tsk))
goto fail_nomem;
@@ -1375,6 +1381,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
INIT_LIST_HEAD(&p->pi_state_list);
p->pi_state_cache = NULL;
#endif
+ uprobe_copy_process(p);
/*
* sigaltstack should be cleared when sharing the same VM
*/
diff --git a/kernel/groups.c b/kernel/groups.c
index 99b53d1eb7ea..6b2588dd04ff 100644
--- a/kernel/groups.c
+++ b/kernel/groups.c
@@ -31,7 +31,7 @@ struct group_info *groups_alloc(int gidsetsize)
group_info->blocks[0] = group_info->small_block;
else {
for (i = 0; i < nblocks; i++) {
- gid_t *b;
+ kgid_t *b;
b = (void *)__get_free_page(GFP_USER);
if (!b)
goto out_undo_partial_alloc;
@@ -66,18 +66,15 @@ EXPORT_SYMBOL(groups_free);
static int groups_to_user(gid_t __user *grouplist,
const struct group_info *group_info)
{
+ struct user_namespace *user_ns = current_user_ns();
int i;
unsigned int count = group_info->ngroups;
- for (i = 0; i < group_info->nblocks; i++) {
- unsigned int cp_count = min(NGROUPS_PER_BLOCK, count);
- unsigned int len = cp_count * sizeof(*grouplist);
-
- if (copy_to_user(grouplist, group_info->blocks[i], len))
+ for (i = 0; i < count; i++) {
+ gid_t gid;
+ gid = from_kgid_munged(user_ns, GROUP_AT(group_info, i));
+ if (put_user(gid, grouplist+i))
return -EFAULT;
-
- grouplist += NGROUPS_PER_BLOCK;
- count -= cp_count;
}
return 0;
}
@@ -86,18 +83,21 @@ static int groups_to_user(gid_t __user *grouplist,
static int groups_from_user(struct group_info *group_info,
gid_t __user *grouplist)
{
+ struct user_namespace *user_ns = current_user_ns();
int i;
unsigned int count = group_info->ngroups;
- for (i = 0; i < group_info->nblocks; i++) {
- unsigned int cp_count = min(NGROUPS_PER_BLOCK, count);
- unsigned int len = cp_count * sizeof(*grouplist);
-
- if (copy_from_user(group_info->blocks[i], grouplist, len))
+ for (i = 0; i < count; i++) {
+ gid_t gid;
+ kgid_t kgid;
+ if (get_user(gid, grouplist+i))
return -EFAULT;
- grouplist += NGROUPS_PER_BLOCK;
- count -= cp_count;
+ kgid = make_kgid(user_ns, gid);
+ if (!gid_valid(kgid))
+ return -EINVAL;
+
+ GROUP_AT(group_info, i) = kgid;
}
return 0;
}
@@ -117,9 +117,9 @@ static void groups_sort(struct group_info *group_info)
for (base = 0; base < max; base++) {
int left = base;
int right = left + stride;
- gid_t tmp = GROUP_AT(group_info, right);
+ kgid_t tmp = GROUP_AT(group_info, right);
- while (left >= 0 && GROUP_AT(group_info, left) > tmp) {
+ while (left >= 0 && gid_gt(GROUP_AT(group_info, left), tmp)) {
GROUP_AT(group_info, right) =
GROUP_AT(group_info, left);
right = left;
@@ -132,7 +132,7 @@ static void groups_sort(struct group_info *group_info)
}
/* a simple bsearch */
-int groups_search(const struct group_info *group_info, gid_t grp)
+int groups_search(const struct group_info *group_info, kgid_t grp)
{
unsigned int left, right;
@@ -143,9 +143,9 @@ int groups_search(const struct group_info *group_info, gid_t grp)
right = group_info->ngroups;
while (left < right) {
unsigned int mid = (left+right)/2;
- if (grp > GROUP_AT(group_info, mid))
+ if (gid_gt(grp, GROUP_AT(group_info, mid)))
left = mid + 1;
- else if (grp < GROUP_AT(group_info, mid))
+ else if (gid_lt(grp, GROUP_AT(group_info, mid)))
right = mid;
else
return 1;
@@ -256,24 +256,24 @@ SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist)
/*
* Check whether we're fsgid/egid or in the supplemental group..
*/
-int in_group_p(gid_t grp)
+int in_group_p(kgid_t grp)
{
const struct cred *cred = current_cred();
int retval = 1;
- if (grp != cred->fsgid)
+ if (!gid_eq(grp, cred->fsgid))
retval = groups_search(cred->group_info, grp);
return retval;
}
EXPORT_SYMBOL(in_group_p);
-int in_egroup_p(gid_t grp)
+int in_egroup_p(kgid_t grp)
{
const struct cred *cred = current_cred();
int retval = 1;
- if (grp != cred->egid)
+ if (!gid_eq(grp, cred->egid))
retval = groups_search(cred->group_info, grp);
return retval;
}
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 0e0ba5f840b2..41c1564103f1 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt) "irq: " fmt
+
#include <linux/debugfs.h>
#include <linux/hardirq.h>
#include <linux/interrupt.h>
@@ -56,14 +58,73 @@ static struct irq_domain *irq_domain_alloc(struct device_node *of_node,
return domain;
}
+static void irq_domain_free(struct irq_domain *domain)
+{
+ of_node_put(domain->of_node);
+ kfree(domain);
+}
+
static void irq_domain_add(struct irq_domain *domain)
{
mutex_lock(&irq_domain_mutex);
list_add(&domain->link, &irq_domain_list);
mutex_unlock(&irq_domain_mutex);
- pr_debug("irq: Allocated domain of type %d @0x%p\n",
+ pr_debug("Allocated domain of type %d @0x%p\n",
+ domain->revmap_type, domain);
+}
+
+/**
+ * irq_domain_remove() - Remove an irq domain.
+ * @domain: domain to remove
+ *
+ * This routine is used to remove an irq domain. The caller must ensure
+ * that all mappings within the domain have been disposed of prior to
+ * use, depending on the revmap type.
+ */
+void irq_domain_remove(struct irq_domain *domain)
+{
+ mutex_lock(&irq_domain_mutex);
+
+ switch (domain->revmap_type) {
+ case IRQ_DOMAIN_MAP_LEGACY:
+ /*
+ * Legacy domains don't manage their own irq_desc
+ * allocations, we expect the caller to handle irq_desc
+ * freeing on their own.
+ */
+ break;
+ case IRQ_DOMAIN_MAP_TREE:
+ /*
+ * radix_tree_delete() takes care of destroying the root
+ * node when all entries are removed. Shout if there are
+ * any mappings left.
+ */
+ WARN_ON(domain->revmap_data.tree.height);
+ break;
+ case IRQ_DOMAIN_MAP_LINEAR:
+ kfree(domain->revmap_data.linear.revmap);
+ domain->revmap_data.linear.size = 0;
+ break;
+ case IRQ_DOMAIN_MAP_NOMAP:
+ break;
+ }
+
+ list_del(&domain->link);
+
+ /*
+ * If the going away domain is the default one, reset it.
+ */
+ if (unlikely(irq_default_domain == domain))
+ irq_set_default_host(NULL);
+
+ mutex_unlock(&irq_domain_mutex);
+
+ pr_debug("Removed domain of type %d @0x%p\n",
domain->revmap_type, domain);
+
+ irq_domain_free(domain);
}
+EXPORT_SYMBOL_GPL(irq_domain_remove);
static unsigned int irq_domain_legacy_revmap(struct irq_domain *domain,
irq_hw_number_t hwirq)
@@ -117,8 +178,7 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
if (WARN_ON(!irq_data || irq_data->domain)) {
mutex_unlock(&irq_domain_mutex);
- of_node_put(domain->of_node);
- kfree(domain);
+ irq_domain_free(domain);
return NULL;
}
}
@@ -152,10 +212,12 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
irq_domain_add(domain);
return domain;
}
+EXPORT_SYMBOL_GPL(irq_domain_add_legacy);
/**
* irq_domain_add_linear() - Allocate and register a legacy revmap irq_domain.
* @of_node: pointer to interrupt controller's device tree node.
+ * @size: Number of interrupts in the domain.
* @ops: map/unmap domain callbacks
* @host_data: Controller private data pointer
*/
@@ -181,6 +243,7 @@ struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
irq_domain_add(domain);
return domain;
}
+EXPORT_SYMBOL_GPL(irq_domain_add_linear);
struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
unsigned int max_irq,
@@ -195,6 +258,7 @@ struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
}
return domain;
}
+EXPORT_SYMBOL_GPL(irq_domain_add_nomap);
/**
* irq_domain_add_tree()
@@ -216,6 +280,7 @@ struct irq_domain *irq_domain_add_tree(struct device_node *of_node,
}
return domain;
}
+EXPORT_SYMBOL_GPL(irq_domain_add_tree);
/**
* irq_find_host() - Locates a domain for a given device node
@@ -259,10 +324,11 @@ EXPORT_SYMBOL_GPL(irq_find_host);
*/
void irq_set_default_host(struct irq_domain *domain)
{
- pr_debug("irq: Default domain set to @0x%p\n", domain);
+ pr_debug("Default domain set to @0x%p\n", domain);
irq_default_domain = domain;
}
+EXPORT_SYMBOL_GPL(irq_set_default_host);
static int irq_setup_virq(struct irq_domain *domain, unsigned int virq,
irq_hw_number_t hwirq)
@@ -272,7 +338,7 @@ static int irq_setup_virq(struct irq_domain *domain, unsigned int virq,
irq_data->hwirq = hwirq;
irq_data->domain = domain;
if (domain->ops->map(domain, virq, hwirq)) {
- pr_debug("irq: -> mapping failed, freeing\n");
+ pr_debug("irq-%i==>hwirq-0x%lx mapping failed\n", virq, hwirq);
irq_data->domain = NULL;
irq_data->hwirq = 0;
return -1;
@@ -303,7 +369,7 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
virq = irq_alloc_desc_from(1, 0);
if (!virq) {
- pr_debug("irq: create_direct virq allocation failed\n");
+ pr_debug("create_direct virq allocation failed\n");
return 0;
}
if (virq >= domain->revmap_data.nomap.max_irq) {
@@ -312,7 +378,7 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
irq_free_desc(virq);
return 0;
}
- pr_debug("irq: create_direct obtained virq %d\n", virq);
+ pr_debug("create_direct obtained virq %d\n", virq);
if (irq_setup_virq(domain, virq, virq)) {
irq_free_desc(virq);
@@ -321,6 +387,7 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
return virq;
}
+EXPORT_SYMBOL_GPL(irq_create_direct_mapping);
/**
* irq_create_mapping() - Map a hardware interrupt into linux irq space
@@ -338,23 +405,23 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
unsigned int hint;
int virq;
- pr_debug("irq: irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);
+ pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);
/* Look for default domain if nececssary */
if (domain == NULL)
domain = irq_default_domain;
if (domain == NULL) {
- printk(KERN_WARNING "irq_create_mapping called for"
- " NULL domain, hwirq=%lx\n", hwirq);
+ pr_warning("irq_create_mapping called for"
+ " NULL domain, hwirq=%lx\n", hwirq);
WARN_ON(1);
return 0;
}
- pr_debug("irq: -> using domain @%p\n", domain);
+ pr_debug("-> using domain @%p\n", domain);
/* Check if mapping already exists */
virq = irq_find_mapping(domain, hwirq);
if (virq) {
- pr_debug("irq: -> existing mapping on virq %d\n", virq);
+ pr_debug("-> existing mapping on virq %d\n", virq);
return virq;
}
@@ -370,7 +437,7 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
if (virq <= 0)
virq = irq_alloc_desc_from(1, 0);
if (virq <= 0) {
- pr_debug("irq: -> virq allocation failed\n");
+ pr_debug("-> virq allocation failed\n");
return 0;
}
@@ -380,7 +447,7 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
return 0;
}
- pr_debug("irq: irq %lu on domain %s mapped to virtual irq %u\n",
+ pr_debug("irq %lu on domain %s mapped to virtual irq %u\n",
hwirq, domain->of_node ? domain->of_node->full_name : "null", virq);
return virq;
@@ -409,8 +476,8 @@ unsigned int irq_create_of_mapping(struct device_node *controller,
if (intsize > 0)
return intspec[0];
#endif
- printk(KERN_WARNING "irq: no irq domain found for %s !\n",
- controller->full_name);
+ pr_warning("no irq domain found for %s !\n",
+ controller->full_name);
return 0;
}
@@ -560,6 +627,7 @@ unsigned int irq_radix_revmap_lookup(struct irq_domain *domain,
*/
return irq_data ? irq_data->irq : irq_find_mapping(domain, hwirq);
}
+EXPORT_SYMBOL_GPL(irq_radix_revmap_lookup);
/**
* irq_radix_revmap_insert() - Insert a hw irq to linux irq number mapping.
@@ -584,6 +652,7 @@ void irq_radix_revmap_insert(struct irq_domain *domain, unsigned int virq,
mutex_unlock(&revmap_trees_mutex);
}
}
+EXPORT_SYMBOL_GPL(irq_radix_revmap_insert);
/**
* irq_linear_revmap() - Find a linux irq from a hw irq number.
@@ -617,6 +686,7 @@ unsigned int irq_linear_revmap(struct irq_domain *domain,
return revmap[hwirq];
}
+EXPORT_SYMBOL_GPL(irq_linear_revmap);
#ifdef CONFIG_IRQ_DOMAIN_DEBUG
static int virq_debug_show(struct seq_file *m, void *private)
@@ -691,8 +761,8 @@ static int __init irq_debugfs_init(void)
__initcall(irq_debugfs_init);
#endif /* CONFIG_IRQ_DOMAIN_DEBUG */
-int irq_domain_simple_map(struct irq_domain *d, unsigned int irq,
- irq_hw_number_t hwirq)
+static int irq_domain_simple_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
{
return 0;
}
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 585f6381f8e4..bb32326afe87 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -1220,12 +1220,6 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
/* Found it - now remove it from the list of entries: */
*action_ptr = action->next;
- /* Currently used only by UML, might disappear one day: */
-#ifdef CONFIG_IRQ_RELEASE_METHOD
- if (desc->irq_data.chip->release)
- desc->irq_data.chip->release(irq, dev_id);
-#endif
-
/* If this was the last handler, shut down the IRQ line: */
if (!desc->action)
irq_shutdown(desc);
diff --git a/kernel/kfifo.c b/kernel/kfifo.c
index c744b88c44e2..59dcf5b81d24 100644
--- a/kernel/kfifo.c
+++ b/kernel/kfifo.c
@@ -402,6 +402,7 @@ unsigned int __kfifo_max_r(unsigned int len, size_t recsize)
return max;
return len;
}
+EXPORT_SYMBOL(__kfifo_max_r);
#define __KFIFO_PEEK(data, out, mask) \
((data)[(out) & (mask)])
diff --git a/kernel/module.c b/kernel/module.c
index 78ac6ec1e425..4edbd9c11aca 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2429,7 +2429,8 @@ static int copy_and_check(struct load_info *info,
goto free_hdr;
}
- if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) {
+ if (hdr->e_shoff >= len ||
+ hdr->e_shnum * sizeof(Elf_Shdr) > len - hdr->e_shoff) {
err = -ENOEXEC;
goto free_hdr;
}
@@ -2953,7 +2954,7 @@ static struct module *load_module(void __user *umod,
/* Module is ready to execute: parsing args may do that. */
err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
- -32768, 32767, NULL);
+ -32768, 32767, &ddebug_dyndbg_module_param_cb);
if (err < 0)
goto unlink;
diff --git a/kernel/params.c b/kernel/params.c
index f37d82631347..ed35345be536 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -85,11 +85,13 @@ bool parameq(const char *a, const char *b)
static int parse_one(char *param,
char *val,
+ const char *doing,
const struct kernel_param *params,
unsigned num_params,
s16 min_level,
s16 max_level,
- int (*handle_unknown)(char *param, char *val))
+ int (*handle_unknown)(char *param, char *val,
+ const char *doing))
{
unsigned int i;
int err;
@@ -104,8 +106,8 @@ static int parse_one(char *param,
if (!val && params[i].ops->set != param_set_bool
&& params[i].ops->set != param_set_bint)
return -EINVAL;
- pr_debug("They are equal! Calling %p\n",
- params[i].ops->set);
+ pr_debug("handling %s with %p\n", param,
+ params[i].ops->set);
mutex_lock(&param_lock);
err = params[i].ops->set(val, &params[i]);
mutex_unlock(&param_lock);
@@ -114,11 +116,11 @@ static int parse_one(char *param,
}
if (handle_unknown) {
- pr_debug("Unknown argument: calling %p\n", handle_unknown);
- return handle_unknown(param, val);
+ pr_debug("doing %s: %s='%s'\n", doing, param, val);
+ return handle_unknown(param, val, doing);
}
- pr_debug("Unknown argument `%s'\n", param);
+ pr_debug("Unknown argument '%s'\n", param);
return -ENOENT;
}
@@ -175,49 +177,47 @@ static char *next_arg(char *args, char **param, char **val)
}
/* Args looks like "foo=bar,bar2 baz=fuz wiz". */
-int parse_args(const char *name,
+int parse_args(const char *doing,
char *args,
const struct kernel_param *params,
unsigned num,
s16 min_level,
s16 max_level,
- int (*unknown)(char *param, char *val))
+ int (*unknown)(char *param, char *val, const char *doing))
{
char *param, *val;
- pr_debug("Parsing ARGS: %s\n", args);
-
/* Chew leading spaces */
args = skip_spaces(args);
+ if (*args)
+ pr_debug("doing %s, parsing ARGS: '%s'\n", doing, args);
+
while (*args) {
int ret;
int irq_was_disabled;
args = next_arg(args, &param, &val);
irq_was_disabled = irqs_disabled();
- ret = parse_one(param, val, params, num,
+ ret = parse_one(param, val, doing, params, num,
min_level, max_level, unknown);
- if (irq_was_disabled && !irqs_disabled()) {
- printk(KERN_WARNING "parse_args(): option '%s' enabled "
- "irq's!\n", param);
- }
+ if (irq_was_disabled && !irqs_disabled())
+ pr_warn("%s: option '%s' enabled irq's!\n",
+ doing, param);
+
switch (ret) {
case -ENOENT:
- printk(KERN_ERR "%s: Unknown parameter `%s'\n",
- name, param);
+ pr_err("%s: Unknown parameter `%s'\n", doing, param);
return ret;
case -ENOSPC:
- printk(KERN_ERR
- "%s: `%s' too large for parameter `%s'\n",
- name, val ?: "", param);
+ pr_err("%s: `%s' too large for parameter `%s'\n",
+ doing, val ?: "", param);
return ret;
case 0:
break;
default:
- printk(KERN_ERR
- "%s: `%s' invalid for parameter `%s'\n",
- name, val ?: "", param);
+ pr_err("%s: `%s' invalid for parameter `%s'\n",
+ doing, val ?: "", param);
return ret;
}
}
@@ -263,8 +263,7 @@ STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", unsigned long, strict_strtoul);
int param_set_charp(const char *val, const struct kernel_param *kp)
{
if (strlen(val) > 1024) {
- printk(KERN_ERR "%s: string parameter too long\n",
- kp->name);
+ pr_err("%s: string parameter too long\n", kp->name);
return -ENOSPC;
}
@@ -400,8 +399,7 @@ static int param_array(const char *name,
int len;
if (*num == max) {
- printk(KERN_ERR "%s: can only take %i arguments\n",
- name, max);
+ pr_err("%s: can only take %i arguments\n", name, max);
return -EINVAL;
}
len = strcspn(val, ",");
@@ -420,8 +418,7 @@ static int param_array(const char *name,
} while (save == ',');
if (*num < min) {
- printk(KERN_ERR "%s: needs at least %i arguments\n",
- name, min);
+ pr_err("%s: needs at least %i arguments\n", name, min);
return -EINVAL;
}
return 0;
@@ -480,7 +477,7 @@ int param_set_copystring(const char *val, const struct kernel_param *kp)
const struct kparam_string *kps = kp->str;
if (strlen(val)+1 > kps->maxlen) {
- printk(KERN_ERR "%s: string doesn't fit in %u chars.\n",
+ pr_err("%s: string doesn't fit in %u chars.\n",
kp->name, kps->maxlen-1);
return -ENOSPC;
}
@@ -750,11 +747,8 @@ static struct module_kobject * __init locate_module_kobject(const char *name)
#endif
if (err) {
kobject_put(&mk->kobj);
- printk(KERN_ERR
- "Module '%s' failed add to sysfs, error number %d\n",
+ pr_crit("Adding module '%s' to sysfs failed (%d), the system may be unstable.\n",
name, err);
- printk(KERN_ERR
- "The system will be unstable now.\n");
return NULL;
}
diff --git a/kernel/pid.c b/kernel/pid.c
index 9f08dfabaf13..e86b291ad834 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -547,7 +547,8 @@ void __init pidhash_init(void)
pid_hash = alloc_large_system_hash("PID", sizeof(*pid_hash), 0, 18,
HASH_EARLY | HASH_SMALL,
- &pidhash_shift, NULL, 4096);
+ &pidhash_shift, NULL,
+ 0, 4096);
pidhash_size = 1U << pidhash_shift;
for (i = 0; i < pidhash_size; i++)
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index deb5461e3216..8f9b4eb974e0 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -103,6 +103,33 @@ config PM_SLEEP_SMP
select HOTPLUG
select HOTPLUG_CPU
+config PM_AUTOSLEEP
+ bool "Opportunistic sleep"
+ depends on PM_SLEEP
+ default n
+ ---help---
+ Allow the kernel to trigger a system transition into a global sleep
+ state automatically whenever there are no active wakeup sources.
+
+config PM_WAKELOCKS
+ bool "User space wakeup sources interface"
+ depends on PM_SLEEP
+ default n
+ ---help---
+ Allow user space to create, activate and deactivate wakeup source
+ objects with the help of a sysfs-based interface.
+
+config PM_WAKELOCKS_LIMIT
+ int "Maximum number of user space wakeup sources (0 = no limit)"
+ range 0 100000
+ default 100
+ depends on PM_WAKELOCKS
+
+config PM_WAKELOCKS_GC
+ bool "Garbage collector for user space wakeup sources"
+ depends on PM_WAKELOCKS
+ default y
+
config PM_RUNTIME
bool "Run-time PM core functionality"
depends on !IA64_HP_SIM
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index 66d808ec5252..29472bff11ef 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -9,5 +9,7 @@ obj-$(CONFIG_SUSPEND) += suspend.o
obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o
obj-$(CONFIG_HIBERNATION) += hibernate.o snapshot.o swap.o user.o \
block_io.o
+obj-$(CONFIG_PM_AUTOSLEEP) += autosleep.o
+obj-$(CONFIG_PM_WAKELOCKS) += wakelock.o
obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
diff --git a/kernel/power/autosleep.c b/kernel/power/autosleep.c
new file mode 100644
index 000000000000..ca304046d9e2
--- /dev/null
+++ b/kernel/power/autosleep.c
@@ -0,0 +1,127 @@
+/*
+ * kernel/power/autosleep.c
+ *
+ * Opportunistic sleep support.
+ *
+ * Copyright (C) 2012 Rafael J. Wysocki <rjw@sisk.pl>
+ */
+
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/pm_wakeup.h>
+
+#include "power.h"
+
+static suspend_state_t autosleep_state;
+static struct workqueue_struct *autosleep_wq;
+/*
+ * Note: it is only safe to mutex_lock(&autosleep_lock) if a wakeup_source
+ * is active, otherwise a deadlock with try_to_suspend() is possible.
+ * Alternatively mutex_lock_interruptible() can be used. This will then fail
+ * if an auto_sleep cycle tries to freeze processes.
+ */
+static DEFINE_MUTEX(autosleep_lock);
+static struct wakeup_source *autosleep_ws;
+
+static void try_to_suspend(struct work_struct *work)
+{
+ unsigned int initial_count, final_count;
+
+ if (!pm_get_wakeup_count(&initial_count, true))
+ goto out;
+
+ mutex_lock(&autosleep_lock);
+
+ if (!pm_save_wakeup_count(initial_count)) {
+ mutex_unlock(&autosleep_lock);
+ goto out;
+ }
+
+ if (autosleep_state == PM_SUSPEND_ON) {
+ mutex_unlock(&autosleep_lock);
+ return;
+ }
+ if (autosleep_state >= PM_SUSPEND_MAX)
+ hibernate();
+ else
+ pm_suspend(autosleep_state);
+
+ mutex_unlock(&autosleep_lock);
+
+ if (!pm_get_wakeup_count(&final_count, false))
+ goto out;
+
+ /*
+ * If the wakeup occured for an unknown reason, wait to prevent the
+ * system from trying to suspend and waking up in a tight loop.
+ */
+ if (final_count == initial_count)
+ schedule_timeout_uninterruptible(HZ / 2);
+
+ out:
+ queue_up_suspend_work();
+}
+
+static DECLARE_WORK(suspend_work, try_to_suspend);
+
+void queue_up_suspend_work(void)
+{
+ if (!work_pending(&suspend_work) && autosleep_state > PM_SUSPEND_ON)
+ queue_work(autosleep_wq, &suspend_work);
+}
+
+suspend_state_t pm_autosleep_state(void)
+{
+ return autosleep_state;
+}
+
+int pm_autosleep_lock(void)
+{
+ return mutex_lock_interruptible(&autosleep_lock);
+}
+
+void pm_autosleep_unlock(void)
+{
+ mutex_unlock(&autosleep_lock);
+}
+
+int pm_autosleep_set_state(suspend_state_t state)
+{
+
+#ifndef CONFIG_HIBERNATION
+ if (state >= PM_SUSPEND_MAX)
+ return -EINVAL;
+#endif
+
+ __pm_stay_awake(autosleep_ws);
+
+ mutex_lock(&autosleep_lock);
+
+ autosleep_state = state;
+
+ __pm_relax(autosleep_ws);
+
+ if (state > PM_SUSPEND_ON) {
+ pm_wakep_autosleep_enabled(true);
+ queue_up_suspend_work();
+ } else {
+ pm_wakep_autosleep_enabled(false);
+ }
+
+ mutex_unlock(&autosleep_lock);
+ return 0;
+}
+
+int __init pm_autosleep_init(void)
+{
+ autosleep_ws = wakeup_source_register("autosleep");
+ if (!autosleep_ws)
+ return -ENOMEM;
+
+ autosleep_wq = alloc_ordered_workqueue("autosleep", 0);
+ if (autosleep_wq)
+ return 0;
+
+ wakeup_source_unregister(autosleep_ws);
+ return -ENOMEM;
+}
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index e09dfbfeecee..8b53db38a279 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -25,6 +25,8 @@
#include <linux/freezer.h>
#include <linux/gfp.h>
#include <linux/syscore_ops.h>
+#include <linux/ctype.h>
+#include <linux/genhd.h>
#include <scsi/scsi_scan.h>
#include "power.h"
@@ -722,6 +724,17 @@ static int software_resume(void)
/* Check if the device is there */
swsusp_resume_device = name_to_dev_t(resume_file);
+
+ /*
+ * name_to_dev_t is ineffective to verify parition if resume_file is in
+ * integer format. (e.g. major:minor)
+ */
+ if (isdigit(resume_file[0]) && resume_wait) {
+ int partno;
+ while (!get_gendisk(swsusp_resume_device, &partno))
+ msleep(10);
+ }
+
if (!swsusp_resume_device) {
/*
* Some device discovery might still be in progress; we need
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 1c12581f1c62..428f8a034e96 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -269,8 +269,7 @@ static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
return (s - buf);
}
-static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
- const char *buf, size_t n)
+static suspend_state_t decode_state(const char *buf, size_t n)
{
#ifdef CONFIG_SUSPEND
suspend_state_t state = PM_SUSPEND_STANDBY;
@@ -278,27 +277,48 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
#endif
char *p;
int len;
- int error = -EINVAL;
p = memchr(buf, '\n', n);
len = p ? p - buf : n;
- /* First, check if we are requested to hibernate */
- if (len == 4 && !strncmp(buf, "disk", len)) {
- error = hibernate();
- goto Exit;
- }
+ /* Check hibernation first. */
+ if (len == 4 && !strncmp(buf, "disk", len))
+ return PM_SUSPEND_MAX;
#ifdef CONFIG_SUSPEND
- for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++) {
- if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) {
- error = pm_suspend(state);
- break;
- }
- }
+ for (s = &pm_states[state]; state < PM_SUSPEND_MAX; s++, state++)
+ if (*s && len == strlen(*s) && !strncmp(buf, *s, len))
+ return state;
#endif
- Exit:
+ return PM_SUSPEND_ON;
+}
+
+static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ suspend_state_t state;
+ int error;
+
+ error = pm_autosleep_lock();
+ if (error)
+ return error;
+
+ if (pm_autosleep_state() > PM_SUSPEND_ON) {
+ error = -EBUSY;
+ goto out;
+ }
+
+ state = decode_state(buf, n);
+ if (state < PM_SUSPEND_MAX)
+ error = pm_suspend(state);
+ else if (state == PM_SUSPEND_MAX)
+ error = hibernate();
+ else
+ error = -EINVAL;
+
+ out:
+ pm_autosleep_unlock();
return error ? error : n;
}
@@ -339,7 +359,8 @@ static ssize_t wakeup_count_show(struct kobject *kobj,
{
unsigned int val;
- return pm_get_wakeup_count(&val) ? sprintf(buf, "%u\n", val) : -EINTR;
+ return pm_get_wakeup_count(&val, true) ?
+ sprintf(buf, "%u\n", val) : -EINTR;
}
static ssize_t wakeup_count_store(struct kobject *kobj,
@@ -347,15 +368,106 @@ static ssize_t wakeup_count_store(struct kobject *kobj,
const char *buf, size_t n)
{
unsigned int val;
+ int error;
+
+ error = pm_autosleep_lock();
+ if (error)
+ return error;
+
+ if (pm_autosleep_state() > PM_SUSPEND_ON) {
+ error = -EBUSY;
+ goto out;
+ }
+ error = -EINVAL;
if (sscanf(buf, "%u", &val) == 1) {
if (pm_save_wakeup_count(val))
- return n;
+ error = n;
}
- return -EINVAL;
+
+ out:
+ pm_autosleep_unlock();
+ return error;
}
power_attr(wakeup_count);
+
+#ifdef CONFIG_PM_AUTOSLEEP
+static ssize_t autosleep_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ suspend_state_t state = pm_autosleep_state();
+
+ if (state == PM_SUSPEND_ON)
+ return sprintf(buf, "off\n");
+
+#ifdef CONFIG_SUSPEND
+ if (state < PM_SUSPEND_MAX)
+ return sprintf(buf, "%s\n", valid_state(state) ?
+ pm_states[state] : "error");
+#endif
+#ifdef CONFIG_HIBERNATION
+ return sprintf(buf, "disk\n");
+#else
+ return sprintf(buf, "error");
+#endif
+}
+
+static ssize_t autosleep_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ suspend_state_t state = decode_state(buf, n);
+ int error;
+
+ if (state == PM_SUSPEND_ON
+ && strcmp(buf, "off") && strcmp(buf, "off\n"))
+ return -EINVAL;
+
+ error = pm_autosleep_set_state(state);
+ return error ? error : n;
+}
+
+power_attr(autosleep);
+#endif /* CONFIG_PM_AUTOSLEEP */
+
+#ifdef CONFIG_PM_WAKELOCKS
+static ssize_t wake_lock_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ return pm_show_wakelocks(buf, true);
+}
+
+static ssize_t wake_lock_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ int error = pm_wake_lock(buf);
+ return error ? error : n;
+}
+
+power_attr(wake_lock);
+
+static ssize_t wake_unlock_show(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ char *buf)
+{
+ return pm_show_wakelocks(buf, false);
+}
+
+static ssize_t wake_unlock_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ int error = pm_wake_unlock(buf);
+ return error ? error : n;
+}
+
+power_attr(wake_unlock);
+
+#endif /* CONFIG_PM_WAKELOCKS */
#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM_TRACE
@@ -409,6 +521,13 @@ static struct attribute * g[] = {
#ifdef CONFIG_PM_SLEEP
&pm_async_attr.attr,
&wakeup_count_attr.attr,
+#ifdef CONFIG_PM_AUTOSLEEP
+ &autosleep_attr.attr,
+#endif
+#ifdef CONFIG_PM_WAKELOCKS
+ &wake_lock_attr.attr,
+ &wake_unlock_attr.attr,
+#endif
#ifdef CONFIG_PM_DEBUG
&pm_test_attr.attr,
#endif
@@ -444,7 +563,10 @@ static int __init pm_init(void)
power_kobj = kobject_create_and_add("power", NULL);
if (!power_kobj)
return -ENOMEM;
- return sysfs_create_group(power_kobj, &attr_group);
+ error = sysfs_create_group(power_kobj, &attr_group);
+ if (error)
+ return error;
+ return pm_autosleep_init();
}
core_initcall(pm_init);
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 98f3622d7407..b0bd4beaebfe 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -264,3 +264,30 @@ static inline void suspend_thaw_processes(void)
{
}
#endif
+
+#ifdef CONFIG_PM_AUTOSLEEP
+
+/* kernel/power/autosleep.c */
+extern int pm_autosleep_init(void);
+extern int pm_autosleep_lock(void);
+extern void pm_autosleep_unlock(void);
+extern suspend_state_t pm_autosleep_state(void);
+extern int pm_autosleep_set_state(suspend_state_t state);
+
+#else /* !CONFIG_PM_AUTOSLEEP */
+
+static inline int pm_autosleep_init(void) { return 0; }
+static inline int pm_autosleep_lock(void) { return 0; }
+static inline void pm_autosleep_unlock(void) {}
+static inline suspend_state_t pm_autosleep_state(void) { return PM_SUSPEND_ON; }
+
+#endif /* !CONFIG_PM_AUTOSLEEP */
+
+#ifdef CONFIG_PM_WAKELOCKS
+
+/* kernel/power/wakelock.c */
+extern ssize_t pm_show_wakelocks(char *buf, bool show_active);
+extern int pm_wake_lock(const char *buf);
+extern int pm_wake_unlock(const char *buf);
+
+#endif /* !CONFIG_PM_WAKELOCKS */
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index eef311a58a64..11e22c068e8b 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -6,7 +6,7 @@
*
* Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz>
* Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
- * Copyright (C) 2010 Bojan Smojver <bojan@rexursive.com>
+ * Copyright (C) 2010-2012 Bojan Smojver <bojan@rexursive.com>
*
* This file is released under the GPLv2.
*
@@ -282,14 +282,17 @@ static int write_page(void *buf, sector_t offset, struct bio **bio_chain)
return -ENOSPC;
if (bio_chain) {
- src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
+ src = (void *)__get_free_page(__GFP_WAIT | __GFP_NOWARN |
+ __GFP_NORETRY);
if (src) {
copy_page(src, buf);
} else {
ret = hib_wait_on_bio_chain(bio_chain); /* Free pages */
if (ret)
return ret;
- src = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
+ src = (void *)__get_free_page(__GFP_WAIT |
+ __GFP_NOWARN |
+ __GFP_NORETRY);
if (src) {
copy_page(src, buf);
} else {
@@ -367,12 +370,17 @@ static int swap_write_page(struct swap_map_handle *handle, void *buf,
clear_page(handle->cur);
handle->cur_swap = offset;
handle->k = 0;
- }
- if (bio_chain && low_free_pages() <= handle->reqd_free_pages) {
- error = hib_wait_on_bio_chain(bio_chain);
- if (error)
- goto out;
- handle->reqd_free_pages = reqd_free_pages();
+
+ if (bio_chain && low_free_pages() <= handle->reqd_free_pages) {
+ error = hib_wait_on_bio_chain(bio_chain);
+ if (error)
+ goto out;
+ /*
+ * Recalculate the number of required free pages, to
+ * make sure we never take more than half.
+ */
+ handle->reqd_free_pages = reqd_free_pages();
+ }
}
out:
return error;
@@ -419,8 +427,9 @@ static int swap_writer_finish(struct swap_map_handle *handle,
/* Maximum number of threads for compression/decompression. */
#define LZO_THREADS 3
-/* Maximum number of pages for read buffering. */
-#define LZO_READ_PAGES (MAP_PAGE_ENTRIES * 8)
+/* Minimum/maximum number of pages for read buffering. */
+#define LZO_MIN_RD_PAGES 1024
+#define LZO_MAX_RD_PAGES 8192
/**
@@ -631,12 +640,6 @@ static int save_image_lzo(struct swap_map_handle *handle,
}
/*
- * Adjust number of free pages after all allocations have been done.
- * We don't want to run out of pages when writing.
- */
- handle->reqd_free_pages = reqd_free_pages();
-
- /*
* Start the CRC32 thread.
*/
init_waitqueue_head(&crc->go);
@@ -657,6 +660,12 @@ static int save_image_lzo(struct swap_map_handle *handle,
goto out_clean;
}
+ /*
+ * Adjust the number of required free pages after all allocations have
+ * been done. We don't want to run out of pages when writing.
+ */
+ handle->reqd_free_pages = reqd_free_pages();
+
printk(KERN_INFO
"PM: Using %u thread(s) for compression.\n"
"PM: Compressing and saving image data (%u pages) ... ",
@@ -1067,7 +1076,7 @@ static int load_image_lzo(struct swap_map_handle *handle,
unsigned i, thr, run_threads, nr_threads;
unsigned ring = 0, pg = 0, ring_size = 0,
have = 0, want, need, asked = 0;
- unsigned long read_pages;
+ unsigned long read_pages = 0;
unsigned char **page = NULL;
struct dec_data *data = NULL;
struct crc_data *crc = NULL;
@@ -1079,7 +1088,7 @@ static int load_image_lzo(struct swap_map_handle *handle,
nr_threads = num_online_cpus() - 1;
nr_threads = clamp_val(nr_threads, 1, LZO_THREADS);
- page = vmalloc(sizeof(*page) * LZO_READ_PAGES);
+ page = vmalloc(sizeof(*page) * LZO_MAX_RD_PAGES);
if (!page) {
printk(KERN_ERR "PM: Failed to allocate LZO page\n");
ret = -ENOMEM;
@@ -1144,15 +1153,22 @@ static int load_image_lzo(struct swap_map_handle *handle,
}
/*
- * Adjust number of pages for read buffering, in case we are short.
+ * Set the number of pages for read buffering.
+ * This is complete guesswork, because we'll only know the real
+ * picture once prepare_image() is called, which is much later on
+ * during the image load phase. We'll assume the worst case and
+ * say that none of the image pages are from high memory.
*/
- read_pages = (nr_free_pages() - snapshot_get_image_size()) >> 1;
- read_pages = clamp_val(read_pages, LZO_CMP_PAGES, LZO_READ_PAGES);
+ if (low_free_pages() > snapshot_get_image_size())
+ read_pages = (low_free_pages() - snapshot_get_image_size()) / 2;
+ read_pages = clamp_val(read_pages, LZO_MIN_RD_PAGES, LZO_MAX_RD_PAGES);
for (i = 0; i < read_pages; i++) {
page[i] = (void *)__get_free_page(i < LZO_CMP_PAGES ?
__GFP_WAIT | __GFP_HIGH :
- __GFP_WAIT);
+ __GFP_WAIT | __GFP_NOWARN |
+ __GFP_NORETRY);
+
if (!page[i]) {
if (i < LZO_CMP_PAGES) {
ring_size = i;
diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c
new file mode 100644
index 000000000000..c8fba3380076
--- /dev/null
+++ b/kernel/power/wakelock.c
@@ -0,0 +1,259 @@
+/*
+ * kernel/power/wakelock.c
+ *
+ * User space wakeup sources support.
+ *
+ * Copyright (C) 2012 Rafael J. Wysocki <rjw@sisk.pl>
+ *
+ * This code is based on the analogous interface allowing user space to
+ * manipulate wakelocks on Android.
+ */
+
+#include <linux/ctype.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/hrtimer.h>
+#include <linux/list.h>
+#include <linux/rbtree.h>
+#include <linux/slab.h>
+
+static DEFINE_MUTEX(wakelocks_lock);
+
+struct wakelock {
+ char *name;
+ struct rb_node node;
+ struct wakeup_source ws;
+#ifdef CONFIG_PM_WAKELOCKS_GC
+ struct list_head lru;
+#endif
+};
+
+static struct rb_root wakelocks_tree = RB_ROOT;
+
+ssize_t pm_show_wakelocks(char *buf, bool show_active)
+{
+ struct rb_node *node;
+ struct wakelock *wl;
+ char *str = buf;
+ char *end = buf + PAGE_SIZE;
+
+ mutex_lock(&wakelocks_lock);
+
+ for (node = rb_first(&wakelocks_tree); node; node = rb_next(node)) {
+ wl = rb_entry(node, struct wakelock, node);
+ if (wl->ws.active == show_active)
+ str += scnprintf(str, end - str, "%s ", wl->name);
+ }
+ if (str > buf)
+ str--;
+
+ str += scnprintf(str, end - str, "\n");
+
+ mutex_unlock(&wakelocks_lock);
+ return (str - buf);
+}
+
+#if CONFIG_PM_WAKELOCKS_LIMIT > 0
+static unsigned int number_of_wakelocks;
+
+static inline bool wakelocks_limit_exceeded(void)
+{
+ return number_of_wakelocks > CONFIG_PM_WAKELOCKS_LIMIT;
+}
+
+static inline void increment_wakelocks_number(void)
+{
+ number_of_wakelocks++;
+}
+
+static inline void decrement_wakelocks_number(void)
+{
+ number_of_wakelocks--;
+}
+#else /* CONFIG_PM_WAKELOCKS_LIMIT = 0 */
+static inline bool wakelocks_limit_exceeded(void) { return false; }
+static inline void increment_wakelocks_number(void) {}
+static inline void decrement_wakelocks_number(void) {}
+#endif /* CONFIG_PM_WAKELOCKS_LIMIT */
+
+#ifdef CONFIG_PM_WAKELOCKS_GC
+#define WL_GC_COUNT_MAX 100
+#define WL_GC_TIME_SEC 300
+
+static LIST_HEAD(wakelocks_lru_list);
+static unsigned int wakelocks_gc_count;
+
+static inline void wakelocks_lru_add(struct wakelock *wl)
+{
+ list_add(&wl->lru, &wakelocks_lru_list);
+}
+
+static inline void wakelocks_lru_most_recent(struct wakelock *wl)
+{
+ list_move(&wl->lru, &wakelocks_lru_list);
+}
+
+static void wakelocks_gc(void)
+{
+ struct wakelock *wl, *aux;
+ ktime_t now;
+
+ if (++wakelocks_gc_count <= WL_GC_COUNT_MAX)
+ return;
+
+ now = ktime_get();
+ list_for_each_entry_safe_reverse(wl, aux, &wakelocks_lru_list, lru) {
+ u64 idle_time_ns;
+ bool active;
+
+ spin_lock_irq(&wl->ws.lock);
+ idle_time_ns = ktime_to_ns(ktime_sub(now, wl->ws.last_time));
+ active = wl->ws.active;
+ spin_unlock_irq(&wl->ws.lock);
+
+ if (idle_time_ns < ((u64)WL_GC_TIME_SEC * NSEC_PER_SEC))
+ break;
+
+ if (!active) {
+ wakeup_source_remove(&wl->ws);
+ rb_erase(&wl->node, &wakelocks_tree);
+ list_del(&wl->lru);
+ kfree(wl->name);
+ kfree(wl);
+ decrement_wakelocks_number();
+ }
+ }
+ wakelocks_gc_count = 0;
+}
+#else /* !CONFIG_PM_WAKELOCKS_GC */
+static inline void wakelocks_lru_add(struct wakelock *wl) {}
+static inline void wakelocks_lru_most_recent(struct wakelock *wl) {}
+static inline void wakelocks_gc(void) {}
+#endif /* !CONFIG_PM_WAKELOCKS_GC */
+
+static struct wakelock *wakelock_lookup_add(const char *name, size_t len,
+ bool add_if_not_found)
+{
+ struct rb_node **node = &wakelocks_tree.rb_node;
+ struct rb_node *parent = *node;
+ struct wakelock *wl;
+
+ while (*node) {
+ int diff;
+
+ parent = *node;
+ wl = rb_entry(*node, struct wakelock, node);
+ diff = strncmp(name, wl->name, len);
+ if (diff == 0) {
+ if (wl->name[len])
+ diff = -1;
+ else
+ return wl;
+ }
+ if (diff < 0)
+ node = &(*node)->rb_left;
+ else
+ node = &(*node)->rb_right;
+ }
+ if (!add_if_not_found)
+ return ERR_PTR(-EINVAL);
+
+ if (wakelocks_limit_exceeded())
+ return ERR_PTR(-ENOSPC);
+
+ /* Not found, we have to add a new one. */
+ wl = kzalloc(sizeof(*wl), GFP_KERNEL);
+ if (!wl)
+ return ERR_PTR(-ENOMEM);
+
+ wl->name = kstrndup(name, len, GFP_KERNEL);
+ if (!wl->name) {
+ kfree(wl);
+ return ERR_PTR(-ENOMEM);
+ }
+ wl->ws.name = wl->name;
+ wakeup_source_add(&wl->ws);
+ rb_link_node(&wl->node, parent, node);
+ rb_insert_color(&wl->node, &wakelocks_tree);
+ wakelocks_lru_add(wl);
+ increment_wakelocks_number();
+ return wl;
+}
+
+int pm_wake_lock(const char *buf)
+{
+ const char *str = buf;
+ struct wakelock *wl;
+ u64 timeout_ns = 0;
+ size_t len;
+ int ret = 0;
+
+ while (*str && !isspace(*str))
+ str++;
+
+ len = str - buf;
+ if (!len)
+ return -EINVAL;
+
+ if (*str && *str != '\n') {
+ /* Find out if there's a valid timeout string appended. */
+ ret = kstrtou64(skip_spaces(str), 10, &timeout_ns);
+ if (ret)
+ return -EINVAL;
+ }
+
+ mutex_lock(&wakelocks_lock);
+
+ wl = wakelock_lookup_add(buf, len, true);
+ if (IS_ERR(wl)) {
+ ret = PTR_ERR(wl);
+ goto out;
+ }
+ if (timeout_ns) {
+ u64 timeout_ms = timeout_ns + NSEC_PER_MSEC - 1;
+
+ do_div(timeout_ms, NSEC_PER_MSEC);
+ __pm_wakeup_event(&wl->ws, timeout_ms);
+ } else {
+ __pm_stay_awake(&wl->ws);
+ }
+
+ wakelocks_lru_most_recent(wl);
+
+ out:
+ mutex_unlock(&wakelocks_lock);
+ return ret;
+}
+
+int pm_wake_unlock(const char *buf)
+{
+ struct wakelock *wl;
+ size_t len;
+ int ret = 0;
+
+ len = strlen(buf);
+ if (!len)
+ return -EINVAL;
+
+ if (buf[len-1] == '\n')
+ len--;
+
+ if (!len)
+ return -EINVAL;
+
+ mutex_lock(&wakelocks_lock);
+
+ wl = wakelock_lookup_add(buf, len, false);
+ if (IS_ERR(wl)) {
+ ret = PTR_ERR(wl);
+ goto out;
+ }
+ __pm_relax(&wl->ws);
+
+ wakelocks_lru_most_recent(wl);
+ wakelocks_gc();
+
+ out:
+ mutex_unlock(&wakelocks_lock);
+ return ret;
+}
diff --git a/kernel/printk.c b/kernel/printk.c
index b663c2c95d39..32462d2b364a 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -41,6 +41,7 @@
#include <linux/cpu.h>
#include <linux/notifier.h>
#include <linux/rculist.h>
+#include <linux/poll.h>
#include <asm/uaccess.h>
@@ -54,8 +55,6 @@ void asmlinkage __attribute__((weak)) early_printk(const char *fmt, ...)
{
}
-#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
-
/* printk's without a loglevel use this.. */
#define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL
@@ -99,24 +98,6 @@ EXPORT_SYMBOL_GPL(console_drivers);
static int console_locked, console_suspended;
/*
- * logbuf_lock protects log_buf, log_start, log_end, con_start and logged_chars
- * It is also used in interesting ways to provide interlocking in
- * console_unlock();.
- */
-static DEFINE_RAW_SPINLOCK(logbuf_lock);
-
-#define LOG_BUF_MASK (log_buf_len-1)
-#define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK])
-
-/*
- * The indices into log_buf are not constrained to log_buf_len - they
- * must be masked before subscripting
- */
-static unsigned log_start; /* Index into log_buf: next char to be read by syslog() */
-static unsigned con_start; /* Index into log_buf: next char to be sent to consoles */
-static unsigned log_end; /* Index into log_buf: most-recently-written-char + 1 */
-
-/*
* If exclusive_console is non-NULL then only this console is to be printed to.
*/
static struct console *exclusive_console;
@@ -145,13 +126,491 @@ EXPORT_SYMBOL(console_set_on_cmdline);
/* Flag: console code may call schedule() */
static int console_may_schedule;
+/*
+ * The printk log buffer consists of a chain of concatenated variable
+ * length records. Every record starts with a record header, containing
+ * the overall length of the record.
+ *
+ * The heads to the first and last entry in the buffer, as well as the
+ * sequence numbers of these both entries are maintained when messages
+ * are stored..
+ *
+ * If the heads indicate available messages, the length in the header
+ * tells the start next message. A length == 0 for the next message
+ * indicates a wrap-around to the beginning of the buffer.
+ *
+ * Every record carries the monotonic timestamp in microseconds, as well as
+ * the standard userspace syslog level and syslog facility. The usual
+ * kernel messages use LOG_KERN; userspace-injected messages always carry
+ * a matching syslog facility, by default LOG_USER. The origin of every
+ * message can be reliably determined that way.
+ *
+ * The human readable log message directly follows the message header. The
+ * length of the message text is stored in the header, the stored message
+ * is not terminated.
+ *
+ * Optionally, a message can carry a dictionary of properties (key/value pairs),
+ * to provide userspace with a machine-readable message context.
+ *
+ * Examples for well-defined, commonly used property names are:
+ * DEVICE=b12:8 device identifier
+ * b12:8 block dev_t
+ * c127:3 char dev_t
+ * n8 netdev ifindex
+ * +sound:card0 subsystem:devname
+ * SUBSYSTEM=pci driver-core subsystem name
+ *
+ * Valid characters in property names are [a-zA-Z0-9.-_]. The plain text value
+ * follows directly after a '=' character. Every property is terminated by
+ * a '\0' character. The last property is not terminated.
+ *
+ * Example of a message structure:
+ * 0000 ff 8f 00 00 00 00 00 00 monotonic time in nsec
+ * 0008 34 00 record is 52 bytes long
+ * 000a 0b 00 text is 11 bytes long
+ * 000c 1f 00 dictionary is 23 bytes long
+ * 000e 03 00 LOG_KERN (facility) LOG_ERR (level)
+ * 0010 69 74 27 73 20 61 20 6c "it's a l"
+ * 69 6e 65 "ine"
+ * 001b 44 45 56 49 43 "DEVIC"
+ * 45 3d 62 38 3a 32 00 44 "E=b8:2\0D"
+ * 52 49 56 45 52 3d 62 75 "RIVER=bu"
+ * 67 "g"
+ * 0032 00 00 00 padding to next message header
+ *
+ * The 'struct log' buffer header must never be directly exported to
+ * userspace, it is a kernel-private implementation detail that might
+ * need to be changed in the future, when the requirements change.
+ *
+ * /dev/kmsg exports the structured data in the following line format:
+ * "level,sequnum,timestamp;<message text>\n"
+ *
+ * The optional key/value pairs are attached as continuation lines starting
+ * with a space character and terminated by a newline. All possible
+ * non-prinatable characters are escaped in the "\xff" notation.
+ *
+ * Users of the export format should ignore possible additional values
+ * separated by ',', and find the message after the ';' character.
+ */
+
+struct log {
+ u64 ts_nsec; /* timestamp in nanoseconds */
+ u16 len; /* length of entire record */
+ u16 text_len; /* length of text buffer */
+ u16 dict_len; /* length of dictionary buffer */
+ u16 level; /* syslog level + facility */
+};
+
+/*
+ * The logbuf_lock protects kmsg buffer, indices, counters. It is also
+ * used in interesting ways to provide interlocking in console_unlock();
+ */
+static DEFINE_RAW_SPINLOCK(logbuf_lock);
+
+/* the next printk record to read by syslog(READ) or /proc/kmsg */
+static u64 syslog_seq;
+static u32 syslog_idx;
+
+/* index and sequence number of the first record stored in the buffer */
+static u64 log_first_seq;
+static u32 log_first_idx;
+
+/* index and sequence number of the next record to store in the buffer */
+static u64 log_next_seq;
#ifdef CONFIG_PRINTK
+static u32 log_next_idx;
+
+/* the next printk record to read after the last 'clear' command */
+static u64 clear_seq;
+static u32 clear_idx;
+
+#define LOG_LINE_MAX 1024
-static char __log_buf[__LOG_BUF_LEN];
+/* record buffer */
+#if !defined(CONFIG_64BIT) || defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
+#define LOG_ALIGN 4
+#else
+#define LOG_ALIGN 8
+#endif
+#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
+static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
static char *log_buf = __log_buf;
-static int log_buf_len = __LOG_BUF_LEN;
-static unsigned logged_chars; /* Number of chars produced since last read+clear operation */
-static int saved_console_loglevel = -1;
+static u32 log_buf_len = __LOG_BUF_LEN;
+
+/* cpu currently holding logbuf_lock */
+static volatile unsigned int logbuf_cpu = UINT_MAX;
+
+/* human readable text of the record */
+static char *log_text(const struct log *msg)
+{
+ return (char *)msg + sizeof(struct log);
+}
+
+/* optional key/value pair dictionary attached to the record */
+static char *log_dict(const struct log *msg)
+{
+ return (char *)msg + sizeof(struct log) + msg->text_len;
+}
+
+/* get record by index; idx must point to valid msg */
+static struct log *log_from_idx(u32 idx)
+{
+ struct log *msg = (struct log *)(log_buf + idx);
+
+ /*
+ * A length == 0 record is the end of buffer marker. Wrap around and
+ * read the message at the start of the buffer.
+ */
+ if (!msg->len)
+ return (struct log *)log_buf;
+ return msg;
+}
+
+/* get next record; idx must point to valid msg */
+static u32 log_next(u32 idx)
+{
+ struct log *msg = (struct log *)(log_buf + idx);
+
+ /* length == 0 indicates the end of the buffer; wrap */
+ /*
+ * A length == 0 record is the end of buffer marker. Wrap around and
+ * read the message at the start of the buffer as *this* one, and
+ * return the one after that.
+ */
+ if (!msg->len) {
+ msg = (struct log *)log_buf;
+ return msg->len;
+ }
+ return idx + msg->len;
+}
+
+/* insert record into the buffer, discard old ones, update heads */
+static void log_store(int facility, int level,
+ const char *dict, u16 dict_len,
+ const char *text, u16 text_len)
+{
+ struct log *msg;
+ u32 size, pad_len;
+
+ /* number of '\0' padding bytes to next message */
+ size = sizeof(struct log) + text_len + dict_len;
+ pad_len = (-size) & (LOG_ALIGN - 1);
+ size += pad_len;
+
+ while (log_first_seq < log_next_seq) {
+ u32 free;
+
+ if (log_next_idx > log_first_idx)
+ free = max(log_buf_len - log_next_idx, log_first_idx);
+ else
+ free = log_first_idx - log_next_idx;
+
+ if (free > size + sizeof(struct log))
+ break;
+
+ /* drop old messages until we have enough contiuous space */
+ log_first_idx = log_next(log_first_idx);
+ log_first_seq++;
+ }
+
+ if (log_next_idx + size + sizeof(struct log) >= log_buf_len) {
+ /*
+ * This message + an additional empty header does not fit
+ * at the end of the buffer. Add an empty header with len == 0
+ * to signify a wrap around.
+ */
+ memset(log_buf + log_next_idx, 0, sizeof(struct log));
+ log_next_idx = 0;
+ }
+
+ /* fill message */
+ msg = (struct log *)(log_buf + log_next_idx);
+ memcpy(log_text(msg), text, text_len);
+ msg->text_len = text_len;
+ memcpy(log_dict(msg), dict, dict_len);
+ msg->dict_len = dict_len;
+ msg->level = (facility << 3) | (level & 7);
+ msg->ts_nsec = local_clock();
+ memset(log_dict(msg) + dict_len, 0, pad_len);
+ msg->len = sizeof(struct log) + text_len + dict_len + pad_len;
+
+ /* insert message */
+ log_next_idx += msg->len;
+ log_next_seq++;
+}
+
+/* /dev/kmsg - userspace message inject/listen interface */
+struct devkmsg_user {
+ u64 seq;
+ u32 idx;
+ struct mutex lock;
+ char buf[8192];
+};
+
+static ssize_t devkmsg_writev(struct kiocb *iocb, const struct iovec *iv,
+ unsigned long count, loff_t pos)
+{
+ char *buf, *line;
+ int i;
+ int level = default_message_loglevel;
+ int facility = 1; /* LOG_USER */
+ size_t len = iov_length(iv, count);
+ ssize_t ret = len;
+
+ if (len > LOG_LINE_MAX)
+ return -EINVAL;
+ buf = kmalloc(len+1, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ line = buf;
+ for (i = 0; i < count; i++) {
+ if (copy_from_user(line, iv[i].iov_base, iv[i].iov_len))
+ goto out;
+ line += iv[i].iov_len;
+ }
+
+ /*
+ * Extract and skip the syslog prefix <[0-9]*>. Coming from userspace
+ * the decimal value represents 32bit, the lower 3 bit are the log
+ * level, the rest are the log facility.
+ *
+ * If no prefix or no userspace facility is specified, we
+ * enforce LOG_USER, to be able to reliably distinguish
+ * kernel-generated messages from userspace-injected ones.
+ */
+ line = buf;
+ if (line[0] == '<') {
+ char *endp = NULL;
+
+ i = simple_strtoul(line+1, &endp, 10);
+ if (endp && endp[0] == '>') {
+ level = i & 7;
+ if (i >> 3)
+ facility = i >> 3;
+ endp++;
+ len -= endp - line;
+ line = endp;
+ }
+ }
+ line[len] = '\0';
+
+ printk_emit(facility, level, NULL, 0, "%s", line);
+out:
+ kfree(buf);
+ return ret;
+}
+
+static ssize_t devkmsg_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct devkmsg_user *user = file->private_data;
+ struct log *msg;
+ u64 ts_usec;
+ size_t i;
+ size_t len;
+ ssize_t ret;
+
+ if (!user)
+ return -EBADF;
+
+ mutex_lock(&user->lock);
+ raw_spin_lock(&logbuf_lock);
+ while (user->seq == log_next_seq) {
+ if (file->f_flags & O_NONBLOCK) {
+ ret = -EAGAIN;
+ raw_spin_unlock(&logbuf_lock);
+ goto out;
+ }
+
+ raw_spin_unlock(&logbuf_lock);
+ ret = wait_event_interruptible(log_wait,
+ user->seq != log_next_seq);
+ if (ret)
+ goto out;
+ raw_spin_lock(&logbuf_lock);
+ }
+
+ if (user->seq < log_first_seq) {
+ /* our last seen message is gone, return error and reset */
+ user->idx = log_first_idx;
+ user->seq = log_first_seq;
+ ret = -EPIPE;
+ raw_spin_unlock(&logbuf_lock);
+ goto out;
+ }
+
+ msg = log_from_idx(user->idx);
+ ts_usec = msg->ts_nsec;
+ do_div(ts_usec, 1000);
+ len = sprintf(user->buf, "%u,%llu,%llu;",
+ msg->level, user->seq, ts_usec);
+
+ /* escape non-printable characters */
+ for (i = 0; i < msg->text_len; i++) {
+ unsigned char c = log_text(msg)[i];
+
+ if (c < ' ' || c >= 128)
+ len += sprintf(user->buf + len, "\\x%02x", c);
+ else
+ user->buf[len++] = c;
+ }
+ user->buf[len++] = '\n';
+
+ if (msg->dict_len) {
+ bool line = true;
+
+ for (i = 0; i < msg->dict_len; i++) {
+ unsigned char c = log_dict(msg)[i];
+
+ if (line) {
+ user->buf[len++] = ' ';
+ line = false;
+ }
+
+ if (c == '\0') {
+ user->buf[len++] = '\n';
+ line = true;
+ continue;
+ }
+
+ if (c < ' ' || c >= 128) {
+ len += sprintf(user->buf + len, "\\x%02x", c);
+ continue;
+ }
+
+ user->buf[len++] = c;
+ }
+ user->buf[len++] = '\n';
+ }
+
+ user->idx = log_next(user->idx);
+ user->seq++;
+ raw_spin_unlock(&logbuf_lock);
+
+ if (len > count) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (copy_to_user(buf, user->buf, len)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ ret = len;
+out:
+ mutex_unlock(&user->lock);
+ return ret;
+}
+
+static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
+{
+ struct devkmsg_user *user = file->private_data;
+ loff_t ret = 0;
+
+ if (!user)
+ return -EBADF;
+ if (offset)
+ return -ESPIPE;
+
+ raw_spin_lock(&logbuf_lock);
+ switch (whence) {
+ case SEEK_SET:
+ /* the first record */
+ user->idx = log_first_idx;
+ user->seq = log_first_seq;
+ break;
+ case SEEK_DATA:
+ /*
+ * The first record after the last SYSLOG_ACTION_CLEAR,
+ * like issued by 'dmesg -c'. Reading /dev/kmsg itself
+ * changes no global state, and does not clear anything.
+ */
+ user->idx = clear_idx;
+ user->seq = clear_seq;
+ break;
+ case SEEK_END:
+ /* after the last record */
+ user->idx = log_next_idx;
+ user->seq = log_next_seq;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ raw_spin_unlock(&logbuf_lock);
+ return ret;
+}
+
+static unsigned int devkmsg_poll(struct file *file, poll_table *wait)
+{
+ struct devkmsg_user *user = file->private_data;
+ int ret = 0;
+
+ if (!user)
+ return POLLERR|POLLNVAL;
+
+ poll_wait(file, &log_wait, wait);
+
+ raw_spin_lock(&logbuf_lock);
+ if (user->seq < log_next_seq) {
+ /* return error when data has vanished underneath us */
+ if (user->seq < log_first_seq)
+ ret = POLLIN|POLLRDNORM|POLLERR|POLLPRI;
+ ret = POLLIN|POLLRDNORM;
+ }
+ raw_spin_unlock(&logbuf_lock);
+
+ return ret;
+}
+
+static int devkmsg_open(struct inode *inode, struct file *file)
+{
+ struct devkmsg_user *user;
+ int err;
+
+ /* write-only does not need any file context */
+ if ((file->f_flags & O_ACCMODE) == O_WRONLY)
+ return 0;
+
+ err = security_syslog(SYSLOG_ACTION_READ_ALL);
+ if (err)
+ return err;
+
+ user = kmalloc(sizeof(struct devkmsg_user), GFP_KERNEL);
+ if (!user)
+ return -ENOMEM;
+
+ mutex_init(&user->lock);
+
+ raw_spin_lock(&logbuf_lock);
+ user->idx = log_first_idx;
+ user->seq = log_first_seq;
+ raw_spin_unlock(&logbuf_lock);
+
+ file->private_data = user;
+ return 0;
+}
+
+static int devkmsg_release(struct inode *inode, struct file *file)
+{
+ struct devkmsg_user *user = file->private_data;
+
+ if (!user)
+ return 0;
+
+ mutex_destroy(&user->lock);
+ kfree(user);
+ return 0;
+}
+
+const struct file_operations kmsg_fops = {
+ .open = devkmsg_open,
+ .read = devkmsg_read,
+ .aio_write = devkmsg_writev,
+ .llseek = devkmsg_llseek,
+ .poll = devkmsg_poll,
+ .release = devkmsg_release,
+};
#ifdef CONFIG_KEXEC
/*
@@ -165,9 +624,9 @@ static int saved_console_loglevel = -1;
void log_buf_kexec_setup(void)
{
VMCOREINFO_SYMBOL(log_buf);
- VMCOREINFO_SYMBOL(log_end);
VMCOREINFO_SYMBOL(log_buf_len);
- VMCOREINFO_SYMBOL(logged_chars);
+ VMCOREINFO_SYMBOL(log_first_idx);
+ VMCOREINFO_SYMBOL(log_next_idx);
}
#endif
@@ -191,7 +650,6 @@ early_param("log_buf_len", log_buf_len_setup);
void __init setup_log_buf(int early)
{
unsigned long flags;
- unsigned start, dest_idx, offset;
char *new_log_buf;
int free;
@@ -219,20 +677,8 @@ void __init setup_log_buf(int early)
log_buf_len = new_log_buf_len;
log_buf = new_log_buf;
new_log_buf_len = 0;
- free = __LOG_BUF_LEN - log_end;
-
- offset = start = min(con_start, log_start);
- dest_idx = 0;
- while (start != log_end) {
- unsigned log_idx_mask = start & (__LOG_BUF_LEN - 1);
-
- log_buf[dest_idx] = __log_buf[log_idx_mask];
- start++;
- dest_idx++;
- }
- log_start -= offset;
- con_start -= offset;
- log_end -= offset;
+ free = __LOG_BUF_LEN - log_next_idx;
+ memcpy(log_buf, __log_buf, __LOG_BUF_LEN);
raw_spin_unlock_irqrestore(&logbuf_lock, flags);
pr_info("log_buf_len: %d\n", log_buf_len);
@@ -332,11 +778,202 @@ static int check_syslog_permissions(int type, bool from_file)
return 0;
}
+#if defined(CONFIG_PRINTK_TIME)
+static bool printk_time = 1;
+#else
+static bool printk_time;
+#endif
+module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR);
+
+static size_t print_prefix(const struct log *msg, bool syslog, char *buf)
+{
+ size_t len = 0;
+
+ if (syslog) {
+ if (buf) {
+ len += sprintf(buf, "<%u>", msg->level);
+ } else {
+ len += 3;
+ if (msg->level > 9)
+ len++;
+ if (msg->level > 99)
+ len++;
+ }
+ }
+
+ if (printk_time) {
+ if (buf) {
+ unsigned long long ts = msg->ts_nsec;
+ unsigned long rem_nsec = do_div(ts, 1000000000);
+
+ len += sprintf(buf + len, "[%5lu.%06lu] ",
+ (unsigned long) ts, rem_nsec / 1000);
+ } else {
+ len += 15;
+ }
+ }
+
+ return len;
+}
+
+static size_t msg_print_text(const struct log *msg, bool syslog,
+ char *buf, size_t size)
+{
+ const char *text = log_text(msg);
+ size_t text_size = msg->text_len;
+ size_t len = 0;
+
+ do {
+ const char *next = memchr(text, '\n', text_size);
+ size_t text_len;
+
+ if (next) {
+ text_len = next - text;
+ next++;
+ text_size -= next - text;
+ } else {
+ text_len = text_size;
+ }
+
+ if (buf) {
+ if (print_prefix(msg, syslog, NULL) +
+ text_len + 1>= size - len)
+ break;
+
+ len += print_prefix(msg, syslog, buf + len);
+ memcpy(buf + len, text, text_len);
+ len += text_len;
+ buf[len++] = '\n';
+ } else {
+ /* SYSLOG_ACTION_* buffer size only calculation */
+ len += print_prefix(msg, syslog, NULL);
+ len += text_len + 1;
+ }
+
+ text = next;
+ } while (text);
+
+ return len;
+}
+
+static int syslog_print(char __user *buf, int size)
+{
+ char *text;
+ struct log *msg;
+ int len;
+
+ text = kmalloc(LOG_LINE_MAX, GFP_KERNEL);
+ if (!text)
+ return -ENOMEM;
+
+ raw_spin_lock_irq(&logbuf_lock);
+ if (syslog_seq < log_first_seq) {
+ /* messages are gone, move to first one */
+ syslog_seq = log_first_seq;
+ syslog_idx = log_first_idx;
+ }
+ msg = log_from_idx(syslog_idx);
+ len = msg_print_text(msg, true, text, LOG_LINE_MAX);
+ syslog_idx = log_next(syslog_idx);
+ syslog_seq++;
+ raw_spin_unlock_irq(&logbuf_lock);
+
+ if (len > 0 && copy_to_user(buf, text, len))
+ len = -EFAULT;
+
+ kfree(text);
+ return len;
+}
+
+static int syslog_print_all(char __user *buf, int size, bool clear)
+{
+ char *text;
+ int len = 0;
+
+ text = kmalloc(LOG_LINE_MAX, GFP_KERNEL);
+ if (!text)
+ return -ENOMEM;
+
+ raw_spin_lock_irq(&logbuf_lock);
+ if (buf) {
+ u64 next_seq;
+ u64 seq;
+ u32 idx;
+
+ if (clear_seq < log_first_seq) {
+ /* messages are gone, move to first available one */
+ clear_seq = log_first_seq;
+ clear_idx = log_first_idx;
+ }
+
+ /*
+ * Find first record that fits, including all following records,
+ * into the user-provided buffer for this dump.
+ */
+ seq = clear_seq;
+ idx = clear_idx;
+ while (seq < log_next_seq) {
+ struct log *msg = log_from_idx(idx);
+
+ len += msg_print_text(msg, true, NULL, 0);
+ idx = log_next(idx);
+ seq++;
+ }
+ seq = clear_seq;
+ idx = clear_idx;
+ while (len > size && seq < log_next_seq) {
+ struct log *msg = log_from_idx(idx);
+
+ len -= msg_print_text(msg, true, NULL, 0);
+ idx = log_next(idx);
+ seq++;
+ }
+
+ /* last message in this dump */
+ next_seq = log_next_seq;
+
+ len = 0;
+ while (len >= 0 && seq < next_seq) {
+ struct log *msg = log_from_idx(idx);
+ int textlen;
+
+ textlen = msg_print_text(msg, true, text, LOG_LINE_MAX);
+ if (textlen < 0) {
+ len = textlen;
+ break;
+ }
+ idx = log_next(idx);
+ seq++;
+
+ raw_spin_unlock_irq(&logbuf_lock);
+ if (copy_to_user(buf + len, text, textlen))
+ len = -EFAULT;
+ else
+ len += textlen;
+ raw_spin_lock_irq(&logbuf_lock);
+
+ if (seq < log_first_seq) {
+ /* messages are gone, move to next one */
+ seq = log_first_seq;
+ idx = log_first_idx;
+ }
+ }
+ }
+
+ if (clear) {
+ clear_seq = log_next_seq;
+ clear_idx = log_next_idx;
+ }
+ raw_spin_unlock_irq(&logbuf_lock);
+
+ kfree(text);
+ return len;
+}
+
int do_syslog(int type, char __user *buf, int len, bool from_file)
{
- unsigned i, j, limit, count;
- int do_clear = 0;
- char c;
+ bool clear = false;
+ static int saved_console_loglevel = -1;
int error;
error = check_syslog_permissions(type, from_file);
@@ -364,28 +1001,14 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
goto out;
}
error = wait_event_interruptible(log_wait,
- (log_start - log_end));
+ syslog_seq != log_next_seq);
if (error)
goto out;
- i = 0;
- raw_spin_lock_irq(&logbuf_lock);
- while (!error && (log_start != log_end) && i < len) {
- c = LOG_BUF(log_start);
- log_start++;
- raw_spin_unlock_irq(&logbuf_lock);
- error = __put_user(c,buf);
- buf++;
- i++;
- cond_resched();
- raw_spin_lock_irq(&logbuf_lock);
- }
- raw_spin_unlock_irq(&logbuf_lock);
- if (!error)
- error = i;
+ error = syslog_print(buf, len);
break;
/* Read/clear last kernel messages */
case SYSLOG_ACTION_READ_CLEAR:
- do_clear = 1;
+ clear = true;
/* FALL THRU */
/* Read last kernel messages */
case SYSLOG_ACTION_READ_ALL:
@@ -399,52 +1022,11 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
error = -EFAULT;
goto out;
}
- count = len;
- if (count > log_buf_len)
- count = log_buf_len;
- raw_spin_lock_irq(&logbuf_lock);
- if (count > logged_chars)
- count = logged_chars;
- if (do_clear)
- logged_chars = 0;
- limit = log_end;
- /*
- * __put_user() could sleep, and while we sleep
- * printk() could overwrite the messages
- * we try to copy to user space. Therefore
- * the messages are copied in reverse. <manfreds>
- */
- for (i = 0; i < count && !error; i++) {
- j = limit-1-i;
- if (j + log_buf_len < log_end)
- break;
- c = LOG_BUF(j);
- raw_spin_unlock_irq(&logbuf_lock);
- error = __put_user(c,&buf[count-1-i]);
- cond_resched();
- raw_spin_lock_irq(&logbuf_lock);
- }
- raw_spin_unlock_irq(&logbuf_lock);
- if (error)
- break;
- error = i;
- if (i != count) {
- int offset = count-error;
- /* buffer overflow during copy, correct user buffer. */
- for (i = 0; i < error; i++) {
- if (__get_user(c,&buf[i+offset]) ||
- __put_user(c,&buf[i])) {
- error = -EFAULT;
- break;
- }
- cond_resched();
- }
- }
+ error = syslog_print_all(buf, len, clear);
break;
/* Clear ring buffer */
case SYSLOG_ACTION_CLEAR:
- logged_chars = 0;
- break;
+ syslog_print_all(NULL, 0, true);
/* Disable logging to console */
case SYSLOG_ACTION_CONSOLE_OFF:
if (saved_console_loglevel == -1)
@@ -472,7 +1054,35 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
break;
/* Number of chars in the log buffer */
case SYSLOG_ACTION_SIZE_UNREAD:
- error = log_end - log_start;
+ raw_spin_lock_irq(&logbuf_lock);
+ if (syslog_seq < log_first_seq) {
+ /* messages are gone, move to first one */
+ syslog_seq = log_first_seq;
+ syslog_idx = log_first_idx;
+ }
+ if (from_file) {
+ /*
+ * Short-cut for poll(/"proc/kmsg") which simply checks
+ * for pending data, not the size; return the count of
+ * records, not the length.
+ */
+ error = log_next_idx - syslog_idx;
+ } else {
+ u64 seq;
+ u32 idx;
+
+ error = 0;
+ seq = syslog_seq;
+ idx = syslog_idx;
+ while (seq < log_next_seq) {
+ struct log *msg = log_from_idx(idx);
+
+ error += msg_print_text(msg, true, NULL, 0);
+ idx = log_next(idx);
+ seq++;
+ }
+ }
+ raw_spin_unlock_irq(&logbuf_lock);
break;
/* Size of the log buffer */
case SYSLOG_ACTION_SIZE_BUFFER:
@@ -501,29 +1111,11 @@ void kdb_syslog_data(char *syslog_data[4])
{
syslog_data[0] = log_buf;
syslog_data[1] = log_buf + log_buf_len;
- syslog_data[2] = log_buf + log_end -
- (logged_chars < log_buf_len ? logged_chars : log_buf_len);
- syslog_data[3] = log_buf + log_end;
+ syslog_data[2] = log_buf + log_first_idx;
+ syslog_data[3] = log_buf + log_next_idx;
}
#endif /* CONFIG_KGDB_KDB */
-/*
- * Call the console drivers on a range of log_buf
- */
-static void __call_console_drivers(unsigned start, unsigned end)
-{
- struct console *con;
-
- for_each_console(con) {
- if (exclusive_console && con != exclusive_console)
- continue;
- if ((con->flags & CON_ENABLED) && con->write &&
- (cpu_online(smp_processor_id()) ||
- (con->flags & CON_ANYTIME)))
- con->write(con, &LOG_BUF(start), end - start);
- }
-}
-
static bool __read_mostly ignore_loglevel;
static int __init ignore_loglevel_setup(char *str)
@@ -540,142 +1132,33 @@ MODULE_PARM_DESC(ignore_loglevel, "ignore loglevel setting, to"
"print all kernel messages to the console.");
/*
- * Write out chars from start to end - 1 inclusive
- */
-static void _call_console_drivers(unsigned start,
- unsigned end, int msg_log_level)
-{
- trace_console(&LOG_BUF(0), start, end, log_buf_len);
-
- if ((msg_log_level < console_loglevel || ignore_loglevel) &&
- console_drivers && start != end) {
- if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) {
- /* wrapped write */
- __call_console_drivers(start & LOG_BUF_MASK,
- log_buf_len);
- __call_console_drivers(0, end & LOG_BUF_MASK);
- } else {
- __call_console_drivers(start, end);
- }
- }
-}
-
-/*
- * Parse the syslog header <[0-9]*>. The decimal value represents 32bit, the
- * lower 3 bit are the log level, the rest are the log facility. In case
- * userspace passes usual userspace syslog messages to /dev/kmsg or
- * /dev/ttyprintk, the log prefix might contain the facility. Printk needs
- * to extract the correct log level for in-kernel processing, and not mangle
- * the original value.
- *
- * If a prefix is found, the length of the prefix is returned. If 'level' is
- * passed, it will be filled in with the log level without a possible facility
- * value. If 'special' is passed, the special printk prefix chars are accepted
- * and returned. If no valid header is found, 0 is returned and the passed
- * variables are not touched.
- */
-static size_t log_prefix(const char *p, unsigned int *level, char *special)
-{
- unsigned int lev = 0;
- char sp = '\0';
- size_t len;
-
- if (p[0] != '<' || !p[1])
- return 0;
- if (p[2] == '>') {
- /* usual single digit level number or special char */
- switch (p[1]) {
- case '0' ... '7':
- lev = p[1] - '0';
- break;
- case 'c': /* KERN_CONT */
- case 'd': /* KERN_DEFAULT */
- sp = p[1];
- break;
- default:
- return 0;
- }
- len = 3;
- } else {
- /* multi digit including the level and facility number */
- char *endp = NULL;
-
- lev = (simple_strtoul(&p[1], &endp, 10) & 7);
- if (endp == NULL || endp[0] != '>')
- return 0;
- len = (endp + 1) - p;
- }
-
- /* do not accept special char if not asked for */
- if (sp && !special)
- return 0;
-
- if (special) {
- *special = sp;
- /* return special char, do not touch level */
- if (sp)
- return len;
- }
-
- if (level)
- *level = lev;
- return len;
-}
-
-/*
* Call the console drivers, asking them to write out
* log_buf[start] to log_buf[end - 1].
* The console_lock must be held.
*/
-static void call_console_drivers(unsigned start, unsigned end)
+static void call_console_drivers(int level, const char *text, size_t len)
{
- unsigned cur_index, start_print;
- static int msg_level = -1;
+ struct console *con;
- BUG_ON(((int)(start - end)) > 0);
+ trace_console(text, 0, len, len);
- cur_index = start;
- start_print = start;
- while (cur_index != end) {
- if (msg_level < 0 && ((end - cur_index) > 2)) {
- /* strip log prefix */
- cur_index += log_prefix(&LOG_BUF(cur_index), &msg_level, NULL);
- start_print = cur_index;
- }
- while (cur_index != end) {
- char c = LOG_BUF(cur_index);
-
- cur_index++;
- if (c == '\n') {
- if (msg_level < 0) {
- /*
- * printk() has already given us loglevel tags in
- * the buffer. This code is here in case the
- * log buffer has wrapped right round and scribbled
- * on those tags
- */
- msg_level = default_message_loglevel;
- }
- _call_console_drivers(start_print, cur_index, msg_level);
- msg_level = -1;
- start_print = cur_index;
- break;
- }
- }
- }
- _call_console_drivers(start_print, end, msg_level);
-}
+ if (level >= console_loglevel && !ignore_loglevel)
+ return;
+ if (!console_drivers)
+ return;
-static void emit_log_char(char c)
-{
- LOG_BUF(log_end) = c;
- log_end++;
- if (log_end - log_start > log_buf_len)
- log_start = log_end - log_buf_len;
- if (log_end - con_start > log_buf_len)
- con_start = log_end - log_buf_len;
- if (logged_chars < log_buf_len)
- logged_chars++;
+ for_each_console(con) {
+ if (exclusive_console && con != exclusive_console)
+ continue;
+ if (!(con->flags & CON_ENABLED))
+ continue;
+ if (!con->write)
+ continue;
+ if (!cpu_online(smp_processor_id()) &&
+ !(con->flags & CON_ANYTIME))
+ continue;
+ con->write(con, text, len);
+ }
}
/*
@@ -700,16 +1183,6 @@ static void zap_locks(void)
sema_init(&console_sem, 1);
}
-#if defined(CONFIG_PRINTK_TIME)
-static bool printk_time = 1;
-#else
-static bool printk_time = 0;
-#endif
-module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR);
-
-static bool always_kmsg_dump;
-module_param_named(always_kmsg_dump, always_kmsg_dump, bool, S_IRUGO | S_IWUSR);
-
/* Check if we have any console registered that can be called early in boot. */
static int have_callable_console(void)
{
@@ -722,51 +1195,6 @@ static int have_callable_console(void)
return 0;
}
-/**
- * printk - print a kernel message
- * @fmt: format string
- *
- * This is printk(). It can be called from any context. We want it to work.
- *
- * We try to grab the console_lock. If we succeed, it's easy - we log the output and
- * call the console drivers. If we fail to get the semaphore we place the output
- * into the log buffer and return. The current holder of the console_sem will
- * notice the new output in console_unlock(); and will send it to the
- * consoles before releasing the lock.
- *
- * One effect of this deferred printing is that code which calls printk() and
- * then changes console_loglevel may break. This is because console_loglevel
- * is inspected when the actual printing occurs.
- *
- * See also:
- * printf(3)
- *
- * See the vsnprintf() documentation for format string extensions over C99.
- */
-
-asmlinkage int printk(const char *fmt, ...)
-{
- va_list args;
- int r;
-
-#ifdef CONFIG_KGDB_KDB
- if (unlikely(kdb_trap_printk)) {
- va_start(args, fmt);
- r = vkdb_printf(fmt, args);
- va_end(args);
- return r;
- }
-#endif
- va_start(args, fmt);
- r = vprintk(fmt, args);
- va_end(args);
-
- return r;
-}
-
-/* cpu currently holding logbuf_lock */
-static volatile unsigned int printk_cpu = UINT_MAX;
-
/*
* Can we actually use the console at this time on this cpu?
*
@@ -810,17 +1238,12 @@ static int console_trylock_for_printk(unsigned int cpu)
retval = 0;
}
}
- printk_cpu = UINT_MAX;
+ logbuf_cpu = UINT_MAX;
if (wake)
up(&console_sem);
raw_spin_unlock(&logbuf_lock);
return retval;
}
-static const char recursion_bug_msg [] =
- KERN_CRIT "BUG: recent printk recursion!\n";
-static int recursion_bug;
-static int new_text_line = 1;
-static char printk_buf[1024];
int printk_delay_msec __read_mostly;
@@ -836,15 +1259,23 @@ static inline void printk_delay(void)
}
}
-asmlinkage int vprintk(const char *fmt, va_list args)
+asmlinkage int vprintk_emit(int facility, int level,
+ const char *dict, size_t dictlen,
+ const char *fmt, va_list args)
{
- int printed_len = 0;
- int current_log_level = default_message_loglevel;
+ static int recursion_bug;
+ static char cont_buf[LOG_LINE_MAX];
+ static size_t cont_len;
+ static int cont_level;
+ static struct task_struct *cont_task;
+ static char textbuf[LOG_LINE_MAX];
+ char *text = textbuf;
+ size_t text_len;
unsigned long flags;
int this_cpu;
- char *p;
- size_t plen;
- char special;
+ bool newline = false;
+ bool prefix = false;
+ int printed_len = 0;
boot_delay_msec();
printk_delay();
@@ -856,7 +1287,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
/*
* Ouch, printk recursed into itself!
*/
- if (unlikely(printk_cpu == this_cpu)) {
+ if (unlikely(logbuf_cpu == this_cpu)) {
/*
* If a crash is occurring during printk() on this CPU,
* then try to get the crash message out but make sure
@@ -873,97 +1304,110 @@ asmlinkage int vprintk(const char *fmt, va_list args)
lockdep_off();
raw_spin_lock(&logbuf_lock);
- printk_cpu = this_cpu;
+ logbuf_cpu = this_cpu;
if (recursion_bug) {
+ static const char recursion_msg[] =
+ "BUG: recent printk recursion!";
+
recursion_bug = 0;
- strcpy(printk_buf, recursion_bug_msg);
- printed_len = strlen(recursion_bug_msg);
+ printed_len += strlen(recursion_msg);
+ /* emit KERN_CRIT message */
+ log_store(0, 2, NULL, 0, recursion_msg, printed_len);
}
- /* Emit the output into the temporary buffer */
- printed_len += vscnprintf(printk_buf + printed_len,
- sizeof(printk_buf) - printed_len, fmt, args);
- p = printk_buf;
+ /*
+ * The printf needs to come first; we need the syslog
+ * prefix which might be passed-in as a parameter.
+ */
+ text_len = vscnprintf(text, sizeof(textbuf), fmt, args);
- /* Read log level and handle special printk prefix */
- plen = log_prefix(p, &current_log_level, &special);
- if (plen) {
- p += plen;
+ /* mark and strip a trailing newline */
+ if (text_len && text[text_len-1] == '\n') {
+ text_len--;
+ newline = true;
+ }
- switch (special) {
- case 'c': /* Strip <c> KERN_CONT, continue line */
- plen = 0;
- break;
- case 'd': /* Strip <d> KERN_DEFAULT, start new line */
- plen = 0;
- default:
- if (!new_text_line) {
- emit_log_char('\n');
- new_text_line = 1;
- }
+ /* strip syslog prefix and extract log level or control flags */
+ if (text[0] == '<' && text[1] && text[2] == '>') {
+ switch (text[1]) {
+ case '0' ... '7':
+ if (level == -1)
+ level = text[1] - '0';
+ case 'd': /* KERN_DEFAULT */
+ prefix = true;
+ case 'c': /* KERN_CONT */
+ text += 3;
+ text_len -= 3;
}
}
- /*
- * Copy the output into log_buf. If the caller didn't provide
- * the appropriate log prefix, we insert them here
- */
- for (; *p; p++) {
- if (new_text_line) {
- new_text_line = 0;
-
- if (plen) {
- /* Copy original log prefix */
- int i;
-
- for (i = 0; i < plen; i++)
- emit_log_char(printk_buf[i]);
- printed_len += plen;
- } else {
- /* Add log prefix */
- emit_log_char('<');
- emit_log_char(current_log_level + '0');
- emit_log_char('>');
- printed_len += 3;
- }
+ if (level == -1)
+ level = default_message_loglevel;
- if (printk_time) {
- /* Add the current time stamp */
- char tbuf[50], *tp;
- unsigned tlen;
- unsigned long long t;
- unsigned long nanosec_rem;
-
- t = cpu_clock(printk_cpu);
- nanosec_rem = do_div(t, 1000000000);
- tlen = sprintf(tbuf, "[%5lu.%06lu] ",
- (unsigned long) t,
- nanosec_rem / 1000);
-
- for (tp = tbuf; tp < tbuf + tlen; tp++)
- emit_log_char(*tp);
- printed_len += tlen;
- }
+ if (dict) {
+ prefix = true;
+ newline = true;
+ }
- if (!*p)
- break;
+ if (!newline) {
+ if (cont_len && (prefix || cont_task != current)) {
+ /*
+ * Flush earlier buffer, which is either from a
+ * different thread, or when we got a new prefix.
+ */
+ log_store(facility, cont_level, NULL, 0, cont_buf, cont_len);
+ cont_len = 0;
}
- emit_log_char(*p);
- if (*p == '\n')
- new_text_line = 1;
+ if (!cont_len) {
+ cont_level = level;
+ cont_task = current;
+ }
+
+ /* buffer or append to earlier buffer from the same thread */
+ if (cont_len + text_len > sizeof(cont_buf))
+ text_len = sizeof(cont_buf) - cont_len;
+ memcpy(cont_buf + cont_len, text, text_len);
+ cont_len += text_len;
+ } else {
+ if (cont_len && cont_task == current) {
+ if (prefix) {
+ /*
+ * New prefix from the same thread; flush. We
+ * either got no earlier newline, or we race
+ * with an interrupt.
+ */
+ log_store(facility, cont_level,
+ NULL, 0, cont_buf, cont_len);
+ cont_len = 0;
+ }
+
+ /* append to the earlier buffer and flush */
+ if (cont_len + text_len > sizeof(cont_buf))
+ text_len = sizeof(cont_buf) - cont_len;
+ memcpy(cont_buf + cont_len, text, text_len);
+ cont_len += text_len;
+ log_store(facility, cont_level,
+ NULL, 0, cont_buf, cont_len);
+ cont_len = 0;
+ cont_task = NULL;
+ printed_len = cont_len;
+ } else {
+ /* ordinary single and terminated line */
+ log_store(facility, level,
+ dict, dictlen, text, text_len);
+ printed_len = text_len;
+ }
}
/*
- * Try to acquire and then immediately release the
- * console semaphore. The release will do all the
- * actual magic (print out buffers, wake up klogd,
- * etc).
+ * Try to acquire and then immediately release the console semaphore.
+ * The release will print out buffers and wake up /dev/kmsg and syslog()
+ * users.
*
- * The console_trylock_for_printk() function
- * will release 'logbuf_lock' regardless of whether it
- * actually gets the semaphore or not.
+ * The console_trylock_for_printk() function will release 'logbuf_lock'
+ * regardless of whether it actually gets the console semaphore or not.
*/
if (console_trylock_for_printk(this_cpu))
console_unlock();
@@ -974,16 +1418,81 @@ out_restore_irqs:
return printed_len;
}
-EXPORT_SYMBOL(printk);
-EXPORT_SYMBOL(vprintk);
+EXPORT_SYMBOL(vprintk_emit);
-#else
+asmlinkage int vprintk(const char *fmt, va_list args)
+{
+ return vprintk_emit(0, -1, NULL, 0, fmt, args);
+}
+EXPORT_SYMBOL(vprintk);
-static void call_console_drivers(unsigned start, unsigned end)
+asmlinkage int printk_emit(int facility, int level,
+ const char *dict, size_t dictlen,
+ const char *fmt, ...)
{
+ va_list args;
+ int r;
+
+ va_start(args, fmt);
+ r = vprintk_emit(facility, level, dict, dictlen, fmt, args);
+ va_end(args);
+
+ return r;
}
+EXPORT_SYMBOL(printk_emit);
+/**
+ * printk - print a kernel message
+ * @fmt: format string
+ *
+ * This is printk(). It can be called from any context. We want it to work.
+ *
+ * We try to grab the console_lock. If we succeed, it's easy - we log the
+ * output and call the console drivers. If we fail to get the semaphore, we
+ * place the output into the log buffer and return. The current holder of
+ * the console_sem will notice the new output in console_unlock(); and will
+ * send it to the consoles before releasing the lock.
+ *
+ * One effect of this deferred printing is that code which calls printk() and
+ * then changes console_loglevel may break. This is because console_loglevel
+ * is inspected when the actual printing occurs.
+ *
+ * See also:
+ * printf(3)
+ *
+ * See the vsnprintf() documentation for format string extensions over C99.
+ */
+asmlinkage int printk(const char *fmt, ...)
+{
+ va_list args;
+ int r;
+
+#ifdef CONFIG_KGDB_KDB
+ if (unlikely(kdb_trap_printk)) {
+ va_start(args, fmt);
+ r = vkdb_printf(fmt, args);
+ va_end(args);
+ return r;
+ }
#endif
+ va_start(args, fmt);
+ r = vprintk_emit(0, -1, NULL, 0, fmt, args);
+ va_end(args);
+
+ return r;
+}
+EXPORT_SYMBOL(printk);
+
+#else
+
+#define LOG_LINE_MAX 0
+static struct log *log_from_idx(u32 idx) { return NULL; }
+static u32 log_next(u32 idx) { return 0; }
+static void call_console_drivers(int level, const char *text, size_t len) {}
+static size_t msg_print_text(const struct log *msg, bool syslog,
+ char *buf, size_t size) { return 0; }
+
+#endif /* CONFIG_PRINTK */
static int __add_preferred_console(char *name, int idx, char *options,
char *brl_options)
@@ -1217,7 +1726,7 @@ int is_console_locked(void)
}
/*
- * Delayed printk facility, for scheduler-internal messages:
+ * Delayed printk version, for scheduler-internal messages:
*/
#define PRINTK_BUF_SIZE 512
@@ -1253,6 +1762,10 @@ void wake_up_klogd(void)
this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
}
+/* the next printk record to write to the console */
+static u64 console_seq;
+static u32 console_idx;
+
/**
* console_unlock - unlock the console system
*
@@ -1263,15 +1776,16 @@ void wake_up_klogd(void)
* by printk(). If this is the case, console_unlock(); emits
* the output prior to releasing the lock.
*
- * If there is output waiting for klogd, we wake it up.
+ * If there is output waiting, we wake /dev/kmsg and syslog() users.
*
* console_unlock(); may be called from any context.
*/
void console_unlock(void)
{
+ static u64 seen_seq;
unsigned long flags;
- unsigned _con_start, _log_end;
- unsigned wake_klogd = 0, retry = 0;
+ bool wake_klogd = false;
+ bool retry;
if (console_suspended) {
up(&console_sem);
@@ -1281,17 +1795,38 @@ void console_unlock(void)
console_may_schedule = 0;
again:
- for ( ; ; ) {
+ for (;;) {
+ struct log *msg;
+ static char text[LOG_LINE_MAX];
+ size_t len;
+ int level;
+
raw_spin_lock_irqsave(&logbuf_lock, flags);
- wake_klogd |= log_start - log_end;
- if (con_start == log_end)
- break; /* Nothing to print */
- _con_start = con_start;
- _log_end = log_end;
- con_start = log_end; /* Flush */
+ if (seen_seq != log_next_seq) {
+ wake_klogd = true;
+ seen_seq = log_next_seq;
+ }
+
+ if (console_seq < log_first_seq) {
+ /* messages are gone, move to first one */
+ console_seq = log_first_seq;
+ console_idx = log_first_idx;
+ }
+
+ if (console_seq == log_next_seq)
+ break;
+
+ msg = log_from_idx(console_idx);
+ level = msg->level & 7;
+
+ len = msg_print_text(msg, false, text, sizeof(text));
+
+ console_idx = log_next(console_idx);
+ console_seq++;
raw_spin_unlock(&logbuf_lock);
+
stop_critical_timings(); /* don't trace print latency */
- call_console_drivers(_con_start, _log_end);
+ call_console_drivers(level, text, len);
start_critical_timings();
local_irq_restore(flags);
}
@@ -1312,8 +1847,7 @@ again:
* flush, no worries.
*/
raw_spin_lock(&logbuf_lock);
- if (con_start != log_end)
- retry = 1;
+ retry = console_seq != log_next_seq;
raw_spin_unlock_irqrestore(&logbuf_lock, flags);
if (retry && console_trylock())
@@ -1549,7 +2083,8 @@ void register_console(struct console *newcon)
* for us.
*/
raw_spin_lock_irqsave(&logbuf_lock, flags);
- con_start = log_start;
+ console_seq = syslog_seq;
+ console_idx = syslog_idx;
raw_spin_unlock_irqrestore(&logbuf_lock, flags);
/*
* We're about to replay the log buffer. Only do this to the
@@ -1758,6 +2293,9 @@ int kmsg_dump_unregister(struct kmsg_dumper *dumper)
}
EXPORT_SYMBOL_GPL(kmsg_dump_unregister);
+static bool always_kmsg_dump;
+module_param_named(always_kmsg_dump, always_kmsg_dump, bool, S_IRUGO | S_IWUSR);
+
/**
* kmsg_dump - dump kernel log to kernel message dumpers.
* @reason: the reason (oops, panic etc) for dumping
@@ -1767,8 +2305,7 @@ EXPORT_SYMBOL_GPL(kmsg_dump_unregister);
*/
void kmsg_dump(enum kmsg_dump_reason reason)
{
- unsigned long end;
- unsigned chars;
+ u64 idx;
struct kmsg_dumper *dumper;
const char *s1, *s2;
unsigned long l1, l2;
@@ -1780,24 +2317,27 @@ void kmsg_dump(enum kmsg_dump_reason reason)
/* Theoretically, the log could move on after we do this, but
there's not a lot we can do about that. The new messages
will overwrite the start of what we dump. */
+
raw_spin_lock_irqsave(&logbuf_lock, flags);
- end = log_end & LOG_BUF_MASK;
- chars = logged_chars;
- raw_spin_unlock_irqrestore(&logbuf_lock, flags);
+ if (syslog_seq < log_first_seq)
+ idx = syslog_idx;
+ else
+ idx = log_first_idx;
- if (chars > end) {
- s1 = log_buf + log_buf_len - chars + end;
- l1 = chars - end;
+ if (idx > log_next_idx) {
+ s1 = log_buf;
+ l1 = log_next_idx;
- s2 = log_buf;
- l2 = end;
+ s2 = log_buf + idx;
+ l2 = log_buf_len - idx;
} else {
s1 = "";
l1 = 0;
- s2 = log_buf + end - chars;
- l2 = chars;
+ s2 = log_buf + idx;
+ l2 = log_next_idx - idx;
}
+ raw_spin_unlock_irqrestore(&logbuf_lock, flags);
rcu_read_lock();
list_for_each_entry_rcu(dumper, &dump_list, list)
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index ee8d49b9c309..a232bb59d93f 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -198,15 +198,14 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode)
return 0;
rcu_read_lock();
tcred = __task_cred(task);
- if (cred->user->user_ns == tcred->user->user_ns &&
- (cred->uid == tcred->euid &&
- cred->uid == tcred->suid &&
- cred->uid == tcred->uid &&
- cred->gid == tcred->egid &&
- cred->gid == tcred->sgid &&
- cred->gid == tcred->gid))
+ if (uid_eq(cred->uid, tcred->euid) &&
+ uid_eq(cred->uid, tcred->suid) &&
+ uid_eq(cred->uid, tcred->uid) &&
+ gid_eq(cred->gid, tcred->egid) &&
+ gid_eq(cred->gid, tcred->sgid) &&
+ gid_eq(cred->gid, tcred->gid))
goto ok;
- if (ptrace_has_cap(tcred->user->user_ns, mode))
+ if (ptrace_has_cap(tcred->user_ns, mode))
goto ok;
rcu_read_unlock();
return -EPERM;
diff --git a/kernel/res_counter.c b/kernel/res_counter.c
index d508363858b3..bebe2b170d49 100644
--- a/kernel/res_counter.c
+++ b/kernel/res_counter.c
@@ -22,75 +22,70 @@ void res_counter_init(struct res_counter *counter, struct res_counter *parent)
counter->parent = parent;
}
-int res_counter_charge_locked(struct res_counter *counter, unsigned long val)
+int res_counter_charge_locked(struct res_counter *counter, unsigned long val,
+ bool force)
{
+ int ret = 0;
+
if (counter->usage + val > counter->limit) {
counter->failcnt++;
- return -ENOMEM;
+ ret = -ENOMEM;
+ if (!force)
+ return ret;
}
counter->usage += val;
if (counter->usage > counter->max_usage)
counter->max_usage = counter->usage;
- return 0;
+ return ret;
}
-int res_counter_charge(struct res_counter *counter, unsigned long val,
- struct res_counter **limit_fail_at)
+static int __res_counter_charge(struct res_counter *counter, unsigned long val,
+ struct res_counter **limit_fail_at, bool force)
{
- int ret;
+ int ret, r;
unsigned long flags;
struct res_counter *c, *u;
+ r = ret = 0;
*limit_fail_at = NULL;
local_irq_save(flags);
for (c = counter; c != NULL; c = c->parent) {
spin_lock(&c->lock);
- ret = res_counter_charge_locked(c, val);
+ r = res_counter_charge_locked(c, val, force);
spin_unlock(&c->lock);
- if (ret < 0) {
+ if (r < 0 && !ret) {
+ ret = r;
*limit_fail_at = c;
- goto undo;
+ if (!force)
+ break;
}
}
- ret = 0;
- goto done;
-undo:
- for (u = counter; u != c; u = u->parent) {
- spin_lock(&u->lock);
- res_counter_uncharge_locked(u, val);
- spin_unlock(&u->lock);
+
+ if (ret < 0 && !force) {
+ for (u = counter; u != c; u = u->parent) {
+ spin_lock(&u->lock);
+ res_counter_uncharge_locked(u, val);
+ spin_unlock(&u->lock);
+ }
}
-done:
local_irq_restore(flags);
+
return ret;
}
+int res_counter_charge(struct res_counter *counter, unsigned long val,
+ struct res_counter **limit_fail_at)
+{
+ return __res_counter_charge(counter, val, limit_fail_at, false);
+}
+
int res_counter_charge_nofail(struct res_counter *counter, unsigned long val,
struct res_counter **limit_fail_at)
{
- int ret, r;
- unsigned long flags;
- struct res_counter *c;
-
- r = ret = 0;
- *limit_fail_at = NULL;
- local_irq_save(flags);
- for (c = counter; c != NULL; c = c->parent) {
- spin_lock(&c->lock);
- r = res_counter_charge_locked(c, val);
- if (r)
- c->usage += val;
- spin_unlock(&c->lock);
- if (r < 0 && ret == 0) {
- *limit_fail_at = c;
- ret = r;
- }
- }
- local_irq_restore(flags);
-
- return ret;
+ return __res_counter_charge(counter, val, limit_fail_at, true);
}
+
void res_counter_uncharge_locked(struct res_counter *counter, unsigned long val)
{
if (WARN_ON(counter->usage < val))
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index ea8a4769fea5..39eb6011bc38 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -693,8 +693,6 @@ int tg_nop(struct task_group *tg, void *data)
}
#endif
-void update_cpu_load(struct rq *this_rq);
-
static void set_load_weight(struct task_struct *p)
{
int prio = p->static_prio - MAX_RT_PRIO;
@@ -2488,22 +2486,13 @@ decay_load_missed(unsigned long load, unsigned long missed_updates, int idx)
* scheduler tick (TICK_NSEC). With tickless idle this will not be called
* every tick. We fix it up based on jiffies.
*/
-void update_cpu_load(struct rq *this_rq)
+static void __update_cpu_load(struct rq *this_rq, unsigned long this_load,
+ unsigned long pending_updates)
{
- unsigned long this_load = this_rq->load.weight;
- unsigned long curr_jiffies = jiffies;
- unsigned long pending_updates;
int i, scale;
this_rq->nr_load_updates++;
- /* Avoid repeated calls on same jiffy, when moving in and out of idle */
- if (curr_jiffies == this_rq->last_load_update_tick)
- return;
-
- pending_updates = curr_jiffies - this_rq->last_load_update_tick;
- this_rq->last_load_update_tick = curr_jiffies;
-
/* Update our load: */
this_rq->cpu_load[0] = this_load; /* Fasttrack for idx 0 */
for (i = 1, scale = 2; i < CPU_LOAD_IDX_MAX; i++, scale += scale) {
@@ -2528,9 +2517,45 @@ void update_cpu_load(struct rq *this_rq)
sched_avg_update(this_rq);
}
+/*
+ * Called from nohz_idle_balance() to update the load ratings before doing the
+ * idle balance.
+ */
+void update_idle_cpu_load(struct rq *this_rq)
+{
+ unsigned long curr_jiffies = jiffies;
+ unsigned long load = this_rq->load.weight;
+ unsigned long pending_updates;
+
+ /*
+ * Bloody broken means of dealing with nohz, but better than nothing..
+ * jiffies is updated by one cpu, another cpu can drift wrt the jiffy
+ * update and see 0 difference the one time and 2 the next, even though
+ * we ticked at roughtly the same rate.
+ *
+ * Hence we only use this from nohz_idle_balance() and skip this
+ * nonsense when called from the scheduler_tick() since that's
+ * guaranteed a stable rate.
+ */
+ if (load || curr_jiffies == this_rq->last_load_update_tick)
+ return;
+
+ pending_updates = curr_jiffies - this_rq->last_load_update_tick;
+ this_rq->last_load_update_tick = curr_jiffies;
+
+ __update_cpu_load(this_rq, load, pending_updates);
+}
+
+/*
+ * Called from scheduler_tick()
+ */
static void update_cpu_load_active(struct rq *this_rq)
{
- update_cpu_load(this_rq);
+ /*
+ * See the mess in update_idle_cpu_load().
+ */
+ this_rq->last_load_update_tick = jiffies;
+ __update_cpu_load(this_rq, this_rq->load.weight, 1);
calc_load_account_active(this_rq);
}
@@ -3115,6 +3140,7 @@ static noinline void __schedule_bug(struct task_struct *prev)
if (irqs_disabled())
print_irqtrace_events(prev);
dump_stack();
+ add_taint(TAINT_WARN);
}
/*
@@ -4044,11 +4070,8 @@ static bool check_same_owner(struct task_struct *p)
rcu_read_lock();
pcred = __task_cred(p);
- if (cred->user->user_ns == pcred->user->user_ns)
- match = (cred->euid == pcred->euid ||
- cred->euid == pcred->uid);
- else
- match = false;
+ match = (uid_eq(cred->euid, pcred->euid) ||
+ uid_eq(cred->euid, pcred->uid));
rcu_read_unlock();
return match;
}
@@ -5562,7 +5585,8 @@ static int sched_domain_debug_one(struct sched_domain *sd, int cpu, int level,
break;
}
- if (cpumask_intersects(groupmask, sched_group_cpus(group))) {
+ if (!(sd->flags & SD_OVERLAP) &&
+ cpumask_intersects(groupmask, sched_group_cpus(group))) {
printk(KERN_CONT "\n");
printk(KERN_ERR "ERROR: repeated CPUs\n");
break;
@@ -5900,99 +5924,11 @@ static int __init isolated_cpu_setup(char *str)
__setup("isolcpus=", isolated_cpu_setup);
-#ifdef CONFIG_NUMA
-
-/**
- * find_next_best_node - find the next node to include in a sched_domain
- * @node: node whose sched_domain we're building
- * @used_nodes: nodes already in the sched_domain
- *
- * Find the next node to include in a given scheduling domain. Simply
- * finds the closest node not already in the @used_nodes map.
- *
- * Should use nodemask_t.
- */
-static int find_next_best_node(int node, nodemask_t *used_nodes)
-{
- int i, n, val, min_val, best_node = -1;
-
- min_val = INT_MAX;
-
- for (i = 0; i < nr_node_ids; i++) {
- /* Start at @node */
- n = (node + i) % nr_node_ids;
-
- if (!nr_cpus_node(n))
- continue;
-
- /* Skip already used nodes */
- if (node_isset(n, *used_nodes))
- continue;
-
- /* Simple min distance search */
- val = node_distance(node, n);
-
- if (val < min_val) {
- min_val = val;
- best_node = n;
- }
- }
-
- if (best_node != -1)
- node_set(best_node, *used_nodes);
- return best_node;
-}
-
-/**
- * sched_domain_node_span - get a cpumask for a node's sched_domain
- * @node: node whose cpumask we're constructing
- * @span: resulting cpumask
- *
- * Given a node, construct a good cpumask for its sched_domain to span. It
- * should be one that prevents unnecessary balancing, but also spreads tasks
- * out optimally.
- */
-static void sched_domain_node_span(int node, struct cpumask *span)
-{
- nodemask_t used_nodes;
- int i;
-
- cpumask_clear(span);
- nodes_clear(used_nodes);
-
- cpumask_or(span, span, cpumask_of_node(node));
- node_set(node, used_nodes);
-
- for (i = 1; i < SD_NODES_PER_DOMAIN; i++) {
- int next_node = find_next_best_node(node, &used_nodes);
- if (next_node < 0)
- break;
- cpumask_or(span, span, cpumask_of_node(next_node));
- }
-}
-
-static const struct cpumask *cpu_node_mask(int cpu)
-{
- lockdep_assert_held(&sched_domains_mutex);
-
- sched_domain_node_span(cpu_to_node(cpu), sched_domains_tmpmask);
-
- return sched_domains_tmpmask;
-}
-
-static const struct cpumask *cpu_allnodes_mask(int cpu)
-{
- return cpu_possible_mask;
-}
-#endif /* CONFIG_NUMA */
-
static const struct cpumask *cpu_cpu_mask(int cpu)
{
return cpumask_of_node(cpu_to_node(cpu));
}
-int sched_smt_power_savings = 0, sched_mc_power_savings = 0;
-
struct sd_data {
struct sched_domain **__percpu sd;
struct sched_group **__percpu sg;
@@ -6022,6 +5958,7 @@ struct sched_domain_topology_level {
sched_domain_init_f init;
sched_domain_mask_f mask;
int flags;
+ int numa_level;
struct sd_data data;
};
@@ -6213,10 +6150,6 @@ sd_init_##type(struct sched_domain_topology_level *tl, int cpu) \
}
SD_INIT_FUNC(CPU)
-#ifdef CONFIG_NUMA
- SD_INIT_FUNC(ALLNODES)
- SD_INIT_FUNC(NODE)
-#endif
#ifdef CONFIG_SCHED_SMT
SD_INIT_FUNC(SIBLING)
#endif
@@ -6338,15 +6271,184 @@ static struct sched_domain_topology_level default_topology[] = {
{ sd_init_BOOK, cpu_book_mask, },
#endif
{ sd_init_CPU, cpu_cpu_mask, },
-#ifdef CONFIG_NUMA
- { sd_init_NODE, cpu_node_mask, SDTL_OVERLAP, },
- { sd_init_ALLNODES, cpu_allnodes_mask, },
-#endif
{ NULL, },
};
static struct sched_domain_topology_level *sched_domain_topology = default_topology;
+#ifdef CONFIG_NUMA
+
+static int sched_domains_numa_levels;
+static int sched_domains_numa_scale;
+static int *sched_domains_numa_distance;
+static struct cpumask ***sched_domains_numa_masks;
+static int sched_domains_curr_level;
+
+static inline int sd_local_flags(int level)
+{
+ if (sched_domains_numa_distance[level] > REMOTE_DISTANCE)
+ return 0;
+
+ return SD_BALANCE_EXEC | SD_BALANCE_FORK | SD_WAKE_AFFINE;
+}
+
+static struct sched_domain *
+sd_numa_init(struct sched_domain_topology_level *tl, int cpu)
+{
+ struct sched_domain *sd = *per_cpu_ptr(tl->data.sd, cpu);
+ int level = tl->numa_level;
+ int sd_weight = cpumask_weight(
+ sched_domains_numa_masks[level][cpu_to_node(cpu)]);
+
+ *sd = (struct sched_domain){
+ .min_interval = sd_weight,
+ .max_interval = 2*sd_weight,
+ .busy_factor = 32,
+ .imbalance_pct = 125,
+ .cache_nice_tries = 2,
+ .busy_idx = 3,
+ .idle_idx = 2,
+ .newidle_idx = 0,
+ .wake_idx = 0,
+ .forkexec_idx = 0,
+
+ .flags = 1*SD_LOAD_BALANCE
+ | 1*SD_BALANCE_NEWIDLE
+ | 0*SD_BALANCE_EXEC
+ | 0*SD_BALANCE_FORK
+ | 0*SD_BALANCE_WAKE
+ | 0*SD_WAKE_AFFINE
+ | 0*SD_PREFER_LOCAL
+ | 0*SD_SHARE_CPUPOWER
+ | 0*SD_SHARE_PKG_RESOURCES
+ | 1*SD_SERIALIZE
+ | 0*SD_PREFER_SIBLING
+ | sd_local_flags(level)
+ ,
+ .last_balance = jiffies,
+ .balance_interval = sd_weight,
+ };
+ SD_INIT_NAME(sd, NUMA);
+ sd->private = &tl->data;
+
+ /*
+ * Ugly hack to pass state to sd_numa_mask()...
+ */
+ sched_domains_curr_level = tl->numa_level;
+
+ return sd;
+}
+
+static const struct cpumask *sd_numa_mask(int cpu)
+{
+ return sched_domains_numa_masks[sched_domains_curr_level][cpu_to_node(cpu)];
+}
+
+static void sched_init_numa(void)
+{
+ int next_distance, curr_distance = node_distance(0, 0);
+ struct sched_domain_topology_level *tl;
+ int level = 0;
+ int i, j, k;
+
+ sched_domains_numa_scale = curr_distance;
+ sched_domains_numa_distance = kzalloc(sizeof(int) * nr_node_ids, GFP_KERNEL);
+ if (!sched_domains_numa_distance)
+ return;
+
+ /*
+ * O(nr_nodes^2) deduplicating selection sort -- in order to find the
+ * unique distances in the node_distance() table.
+ *
+ * Assumes node_distance(0,j) includes all distances in
+ * node_distance(i,j) in order to avoid cubic time.
+ *
+ * XXX: could be optimized to O(n log n) by using sort()
+ */
+ next_distance = curr_distance;
+ for (i = 0; i < nr_node_ids; i++) {
+ for (j = 0; j < nr_node_ids; j++) {
+ int distance = node_distance(0, j);
+ if (distance > curr_distance &&
+ (distance < next_distance ||
+ next_distance == curr_distance))
+ next_distance = distance;
+ }
+ if (next_distance != curr_distance) {
+ sched_domains_numa_distance[level++] = next_distance;
+ sched_domains_numa_levels = level;
+ curr_distance = next_distance;
+ } else break;
+ }
+ /*
+ * 'level' contains the number of unique distances, excluding the
+ * identity distance node_distance(i,i).
+ *
+ * The sched_domains_nume_distance[] array includes the actual distance
+ * numbers.
+ */
+
+ sched_domains_numa_masks = kzalloc(sizeof(void *) * level, GFP_KERNEL);
+ if (!sched_domains_numa_masks)
+ return;
+
+ /*
+ * Now for each level, construct a mask per node which contains all
+ * cpus of nodes that are that many hops away from us.
+ */
+ for (i = 0; i < level; i++) {
+ sched_domains_numa_masks[i] =
+ kzalloc(nr_node_ids * sizeof(void *), GFP_KERNEL);
+ if (!sched_domains_numa_masks[i])
+ return;
+
+ for (j = 0; j < nr_node_ids; j++) {
+ struct cpumask *mask = kzalloc_node(cpumask_size(), GFP_KERNEL, j);
+ if (!mask)
+ return;
+
+ sched_domains_numa_masks[i][j] = mask;
+
+ for (k = 0; k < nr_node_ids; k++) {
+ if (node_distance(j, k) > sched_domains_numa_distance[i])
+ continue;
+
+ cpumask_or(mask, mask, cpumask_of_node(k));
+ }
+ }
+ }
+
+ tl = kzalloc((ARRAY_SIZE(default_topology) + level) *
+ sizeof(struct sched_domain_topology_level), GFP_KERNEL);
+ if (!tl)
+ return;
+
+ /*
+ * Copy the default topology bits..
+ */
+ for (i = 0; default_topology[i].init; i++)
+ tl[i] = default_topology[i];
+
+ /*
+ * .. and append 'j' levels of NUMA goodness.
+ */
+ for (j = 0; j < level; i++, j++) {
+ tl[i] = (struct sched_domain_topology_level){
+ .init = sd_numa_init,
+ .mask = sd_numa_mask,
+ .flags = SDTL_OVERLAP,
+ .numa_level = j,
+ };
+ }
+
+ sched_domain_topology = tl;
+}
+#else
+static inline void sched_init_numa(void)
+{
+}
+#endif /* CONFIG_NUMA */
+
static int __sdt_alloc(const struct cpumask *cpu_map)
{
struct sched_domain_topology_level *tl;
@@ -6714,97 +6816,6 @@ match2:
mutex_unlock(&sched_domains_mutex);
}
-#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
-static void reinit_sched_domains(void)
-{
- get_online_cpus();
-
- /* Destroy domains first to force the rebuild */
- partition_sched_domains(0, NULL, NULL);
-
- rebuild_sched_domains();
- put_online_cpus();
-}
-
-static ssize_t sched_power_savings_store(const char *buf, size_t count, int smt)
-{
- unsigned int level = 0;
-
- if (sscanf(buf, "%u", &level) != 1)
- return -EINVAL;
-
- /*
- * level is always be positive so don't check for
- * level < POWERSAVINGS_BALANCE_NONE which is 0
- * What happens on 0 or 1 byte write,
- * need to check for count as well?
- */
-
- if (level >= MAX_POWERSAVINGS_BALANCE_LEVELS)
- return -EINVAL;
-
- if (smt)
- sched_smt_power_savings = level;
- else
- sched_mc_power_savings = level;
-
- reinit_sched_domains();
-
- return count;
-}
-
-#ifdef CONFIG_SCHED_MC
-static ssize_t sched_mc_power_savings_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%u\n", sched_mc_power_savings);
-}
-static ssize_t sched_mc_power_savings_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- return sched_power_savings_store(buf, count, 0);
-}
-static DEVICE_ATTR(sched_mc_power_savings, 0644,
- sched_mc_power_savings_show,
- sched_mc_power_savings_store);
-#endif
-
-#ifdef CONFIG_SCHED_SMT
-static ssize_t sched_smt_power_savings_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%u\n", sched_smt_power_savings);
-}
-static ssize_t sched_smt_power_savings_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- return sched_power_savings_store(buf, count, 1);
-}
-static DEVICE_ATTR(sched_smt_power_savings, 0644,
- sched_smt_power_savings_show,
- sched_smt_power_savings_store);
-#endif
-
-int __init sched_create_sysfs_power_savings_entries(struct device *dev)
-{
- int err = 0;
-
-#ifdef CONFIG_SCHED_SMT
- if (smt_capable())
- err = device_create_file(dev, &dev_attr_sched_smt_power_savings);
-#endif
-#ifdef CONFIG_SCHED_MC
- if (!err && mc_capable())
- err = device_create_file(dev, &dev_attr_sched_mc_power_savings);
-#endif
- return err;
-}
-#endif /* CONFIG_SCHED_MC || CONFIG_SCHED_SMT */
-
/*
* Update cpusets according to cpu_active mask. If cpusets are
* disabled, cpuset_update_active_cpus() becomes a simple wrapper
@@ -6842,6 +6853,8 @@ void __init sched_init_smp(void)
alloc_cpumask_var(&non_isolated_cpus, GFP_KERNEL);
alloc_cpumask_var(&fallback_doms, GFP_KERNEL);
+ sched_init_numa();
+
get_online_cpus();
mutex_lock(&sched_domains_mutex);
init_sched_domains(cpu_active_mask);
@@ -7985,13 +7998,9 @@ static struct cftype cpu_files[] = {
.write_u64 = cpu_rt_period_write_uint,
},
#endif
+ { } /* terminate */
};
-static int cpu_cgroup_populate(struct cgroup_subsys *ss, struct cgroup *cont)
-{
- return cgroup_add_files(cont, ss, cpu_files, ARRAY_SIZE(cpu_files));
-}
-
struct cgroup_subsys cpu_cgroup_subsys = {
.name = "cpu",
.create = cpu_cgroup_create,
@@ -7999,8 +8008,8 @@ struct cgroup_subsys cpu_cgroup_subsys = {
.can_attach = cpu_cgroup_can_attach,
.attach = cpu_cgroup_attach,
.exit = cpu_cgroup_exit,
- .populate = cpu_cgroup_populate,
.subsys_id = cpu_cgroup_subsys_id,
+ .base_cftypes = cpu_files,
.early_init = 1,
};
@@ -8185,13 +8194,9 @@ static struct cftype files[] = {
.name = "stat",
.read_map = cpuacct_stats_show,
},
+ { } /* terminate */
};
-static int cpuacct_populate(struct cgroup_subsys *ss, struct cgroup *cgrp)
-{
- return cgroup_add_files(cgrp, ss, files, ARRAY_SIZE(files));
-}
-
/*
* charge this task's execution time to its accounting group.
*
@@ -8223,7 +8228,7 @@ struct cgroup_subsys cpuacct_subsys = {
.name = "cpuacct",
.create = cpuacct_create,
.destroy = cpuacct_destroy,
- .populate = cpuacct_populate,
.subsys_id = cpuacct_subsys_id,
+ .base_cftypes = files,
};
#endif /* CONFIG_CGROUP_CPUACCT */
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
index 09acaa15161d..6f79596e0ea9 100644
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -202,7 +202,7 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
SPLIT_NS(spread0));
SEQ_printf(m, " .%-30s: %d\n", "nr_spread_over",
cfs_rq->nr_spread_over);
- SEQ_printf(m, " .%-30s: %ld\n", "nr_running", cfs_rq->nr_running);
+ SEQ_printf(m, " .%-30s: %d\n", "nr_running", cfs_rq->nr_running);
SEQ_printf(m, " .%-30s: %ld\n", "load", cfs_rq->load.weight);
#ifdef CONFIG_FAIR_GROUP_SCHED
#ifdef CONFIG_SMP
@@ -260,8 +260,14 @@ static void print_cpu(struct seq_file *m, int cpu)
SEQ_printf(m, "\ncpu#%d\n", cpu);
#endif
-#define P(x) \
- SEQ_printf(m, " .%-30s: %Ld\n", #x, (long long)(rq->x))
+#define P(x) \
+do { \
+ if (sizeof(rq->x) == 4) \
+ SEQ_printf(m, " .%-30s: %ld\n", #x, (long)(rq->x)); \
+ else \
+ SEQ_printf(m, " .%-30s: %Ld\n", #x, (long long)(rq->x));\
+} while (0)
+
#define PN(x) \
SEQ_printf(m, " .%-30s: %Ld.%06ld\n", #x, SPLIT_NS(rq->x))
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index e9553640c1c3..940e6d17cf96 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -2721,7 +2721,7 @@ select_task_rq_fair(struct task_struct *p, int sd_flag, int wake_flags)
* If power savings logic is enabled for a domain, see if we
* are not overloaded, if so, don't balance wider.
*/
- if (tmp->flags & (SD_POWERSAVINGS_BALANCE|SD_PREFER_LOCAL)) {
+ if (tmp->flags & (SD_PREFER_LOCAL)) {
unsigned long power = 0;
unsigned long nr_running = 0;
unsigned long capacity;
@@ -2734,9 +2734,6 @@ select_task_rq_fair(struct task_struct *p, int sd_flag, int wake_flags)
capacity = DIV_ROUND_CLOSEST(power, SCHED_POWER_SCALE);
- if (tmp->flags & SD_POWERSAVINGS_BALANCE)
- nr_running /= 2;
-
if (nr_running < capacity)
want_sd = 0;
}
@@ -3082,7 +3079,7 @@ struct lb_env {
struct rq *dst_rq;
enum cpu_idle_type idle;
- long load_move;
+ long imbalance;
unsigned int flags;
unsigned int loop;
@@ -3218,7 +3215,7 @@ static unsigned long task_h_load(struct task_struct *p);
static const unsigned int sched_nr_migrate_break = 32;
/*
- * move_tasks tries to move up to load_move weighted load from busiest to
+ * move_tasks tries to move up to imbalance weighted load from busiest to
* this_rq, as part of a balancing operation within domain "sd".
* Returns 1 if successful and 0 otherwise.
*
@@ -3231,7 +3228,7 @@ static int move_tasks(struct lb_env *env)
unsigned long load;
int pulled = 0;
- if (env->load_move <= 0)
+ if (env->imbalance <= 0)
return 0;
while (!list_empty(tasks)) {
@@ -3257,7 +3254,7 @@ static int move_tasks(struct lb_env *env)
if (sched_feat(LB_MIN) && load < 16 && !env->sd->nr_balance_failed)
goto next;
- if ((load / 2) > env->load_move)
+ if ((load / 2) > env->imbalance)
goto next;
if (!can_migrate_task(p, env))
@@ -3265,7 +3262,7 @@ static int move_tasks(struct lb_env *env)
move_task(p, env);
pulled++;
- env->load_move -= load;
+ env->imbalance -= load;
#ifdef CONFIG_PREEMPT
/*
@@ -3281,7 +3278,7 @@ static int move_tasks(struct lb_env *env)
* We only want to steal up to the prescribed amount of
* weighted load.
*/
- if (env->load_move <= 0)
+ if (env->imbalance <= 0)
break;
continue;
@@ -3435,14 +3432,6 @@ struct sd_lb_stats {
unsigned int busiest_group_weight;
int group_imb; /* Is there imbalance in this sd */
-#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
- int power_savings_balance; /* Is powersave balance needed for this sd */
- struct sched_group *group_min; /* Least loaded group in sd */
- struct sched_group *group_leader; /* Group which relieves group_min */
- unsigned long min_load_per_task; /* load_per_task in group_min */
- unsigned long leader_nr_running; /* Nr running of group_leader */
- unsigned long min_nr_running; /* Nr running of group_min */
-#endif
};
/*
@@ -3486,148 +3475,6 @@ static inline int get_sd_load_idx(struct sched_domain *sd,
return load_idx;
}
-
-#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
-/**
- * init_sd_power_savings_stats - Initialize power savings statistics for
- * the given sched_domain, during load balancing.
- *
- * @sd: Sched domain whose power-savings statistics are to be initialized.
- * @sds: Variable containing the statistics for sd.
- * @idle: Idle status of the CPU at which we're performing load-balancing.
- */
-static inline void init_sd_power_savings_stats(struct sched_domain *sd,
- struct sd_lb_stats *sds, enum cpu_idle_type idle)
-{
- /*
- * Busy processors will not participate in power savings
- * balance.
- */
- if (idle == CPU_NOT_IDLE || !(sd->flags & SD_POWERSAVINGS_BALANCE))
- sds->power_savings_balance = 0;
- else {
- sds->power_savings_balance = 1;
- sds->min_nr_running = ULONG_MAX;
- sds->leader_nr_running = 0;
- }
-}
-
-/**
- * update_sd_power_savings_stats - Update the power saving stats for a
- * sched_domain while performing load balancing.
- *
- * @group: sched_group belonging to the sched_domain under consideration.
- * @sds: Variable containing the statistics of the sched_domain
- * @local_group: Does group contain the CPU for which we're performing
- * load balancing ?
- * @sgs: Variable containing the statistics of the group.
- */
-static inline void update_sd_power_savings_stats(struct sched_group *group,
- struct sd_lb_stats *sds, int local_group, struct sg_lb_stats *sgs)
-{
-
- if (!sds->power_savings_balance)
- return;
-
- /*
- * If the local group is idle or completely loaded
- * no need to do power savings balance at this domain
- */
- if (local_group && (sds->this_nr_running >= sgs->group_capacity ||
- !sds->this_nr_running))
- sds->power_savings_balance = 0;
-
- /*
- * If a group is already running at full capacity or idle,
- * don't include that group in power savings calculations
- */
- if (!sds->power_savings_balance ||
- sgs->sum_nr_running >= sgs->group_capacity ||
- !sgs->sum_nr_running)
- return;
-
- /*
- * Calculate the group which has the least non-idle load.
- * This is the group from where we need to pick up the load
- * for saving power
- */
- if ((sgs->sum_nr_running < sds->min_nr_running) ||
- (sgs->sum_nr_running == sds->min_nr_running &&
- group_first_cpu(group) > group_first_cpu(sds->group_min))) {
- sds->group_min = group;
- sds->min_nr_running = sgs->sum_nr_running;
- sds->min_load_per_task = sgs->sum_weighted_load /
- sgs->sum_nr_running;
- }
-
- /*
- * Calculate the group which is almost near its
- * capacity but still has some space to pick up some load
- * from other group and save more power
- */
- if (sgs->sum_nr_running + 1 > sgs->group_capacity)
- return;
-
- if (sgs->sum_nr_running > sds->leader_nr_running ||
- (sgs->sum_nr_running == sds->leader_nr_running &&
- group_first_cpu(group) < group_first_cpu(sds->group_leader))) {
- sds->group_leader = group;
- sds->leader_nr_running = sgs->sum_nr_running;
- }
-}
-
-/**
- * check_power_save_busiest_group - see if there is potential for some power-savings balance
- * @sds: Variable containing the statistics of the sched_domain
- * under consideration.
- * @this_cpu: Cpu at which we're currently performing load-balancing.
- * @imbalance: Variable to store the imbalance.
- *
- * Description:
- * Check if we have potential to perform some power-savings balance.
- * If yes, set the busiest group to be the least loaded group in the
- * sched_domain, so that it's CPUs can be put to idle.
- *
- * Returns 1 if there is potential to perform power-savings balance.
- * Else returns 0.
- */
-static inline int check_power_save_busiest_group(struct sd_lb_stats *sds,
- int this_cpu, unsigned long *imbalance)
-{
- if (!sds->power_savings_balance)
- return 0;
-
- if (sds->this != sds->group_leader ||
- sds->group_leader == sds->group_min)
- return 0;
-
- *imbalance = sds->min_load_per_task;
- sds->busiest = sds->group_min;
-
- return 1;
-
-}
-#else /* CONFIG_SCHED_MC || CONFIG_SCHED_SMT */
-static inline void init_sd_power_savings_stats(struct sched_domain *sd,
- struct sd_lb_stats *sds, enum cpu_idle_type idle)
-{
- return;
-}
-
-static inline void update_sd_power_savings_stats(struct sched_group *group,
- struct sd_lb_stats *sds, int local_group, struct sg_lb_stats *sgs)
-{
- return;
-}
-
-static inline int check_power_save_busiest_group(struct sd_lb_stats *sds,
- int this_cpu, unsigned long *imbalance)
-{
- return 0;
-}
-#endif /* CONFIG_SCHED_MC || CONFIG_SCHED_SMT */
-
-
unsigned long default_scale_freq_power(struct sched_domain *sd, int cpu)
{
return SCHED_POWER_SCALE;
@@ -3765,24 +3612,22 @@ fix_small_capacity(struct sched_domain *sd, struct sched_group *group)
* update_sg_lb_stats - Update sched_group's statistics for load balancing.
* @sd: The sched_domain whose statistics are to be updated.
* @group: sched_group whose statistics are to be updated.
- * @this_cpu: Cpu for which load balance is currently performed.
- * @idle: Idle status of this_cpu
* @load_idx: Load index of sched_domain of this_cpu for load calc.
* @local_group: Does group contain this_cpu.
* @cpus: Set of cpus considered for load balancing.
* @balance: Should we balance.
* @sgs: variable to hold the statistics for this group.
*/
-static inline void update_sg_lb_stats(struct sched_domain *sd,
- struct sched_group *group, int this_cpu,
- enum cpu_idle_type idle, int load_idx,
+static inline void update_sg_lb_stats(struct lb_env *env,
+ struct sched_group *group, int load_idx,
int local_group, const struct cpumask *cpus,
int *balance, struct sg_lb_stats *sgs)
{
- unsigned long load, max_cpu_load, min_cpu_load, max_nr_running;
- int i;
+ unsigned long nr_running, max_nr_running, min_nr_running;
+ unsigned long load, max_cpu_load, min_cpu_load;
unsigned int balance_cpu = -1, first_idle_cpu = 0;
unsigned long avg_load_per_task = 0;
+ int i;
if (local_group)
balance_cpu = group_first_cpu(group);
@@ -3791,10 +3636,13 @@ static inline void update_sg_lb_stats(struct sched_domain *sd,
max_cpu_load = 0;
min_cpu_load = ~0UL;
max_nr_running = 0;
+ min_nr_running = ~0UL;
for_each_cpu_and(i, sched_group_cpus(group), cpus) {
struct rq *rq = cpu_rq(i);
+ nr_running = rq->nr_running;
+
/* Bias balancing toward cpus of our domain */
if (local_group) {
if (idle_cpu(i) && !first_idle_cpu) {
@@ -3805,16 +3653,19 @@ static inline void update_sg_lb_stats(struct sched_domain *sd,
load = target_load(i, load_idx);
} else {
load = source_load(i, load_idx);
- if (load > max_cpu_load) {
+ if (load > max_cpu_load)
max_cpu_load = load;
- max_nr_running = rq->nr_running;
- }
if (min_cpu_load > load)
min_cpu_load = load;
+
+ if (nr_running > max_nr_running)
+ max_nr_running = nr_running;
+ if (min_nr_running > nr_running)
+ min_nr_running = nr_running;
}
sgs->group_load += load;
- sgs->sum_nr_running += rq->nr_running;
+ sgs->sum_nr_running += nr_running;
sgs->sum_weighted_load += weighted_cpuload(i);
if (idle_cpu(i))
sgs->idle_cpus++;
@@ -3827,14 +3678,14 @@ static inline void update_sg_lb_stats(struct sched_domain *sd,
* to do the newly idle load balance.
*/
if (local_group) {
- if (idle != CPU_NEWLY_IDLE) {
- if (balance_cpu != this_cpu) {
+ if (env->idle != CPU_NEWLY_IDLE) {
+ if (balance_cpu != env->dst_cpu) {
*balance = 0;
return;
}
- update_group_power(sd, this_cpu);
+ update_group_power(env->sd, env->dst_cpu);
} else if (time_after_eq(jiffies, group->sgp->next_update))
- update_group_power(sd, this_cpu);
+ update_group_power(env->sd, env->dst_cpu);
}
/* Adjust by relative CPU power of the group */
@@ -3852,13 +3703,14 @@ static inline void update_sg_lb_stats(struct sched_domain *sd,
if (sgs->sum_nr_running)
avg_load_per_task = sgs->sum_weighted_load / sgs->sum_nr_running;
- if ((max_cpu_load - min_cpu_load) >= avg_load_per_task && max_nr_running > 1)
+ if ((max_cpu_load - min_cpu_load) >= avg_load_per_task &&
+ (max_nr_running - min_nr_running) > 1)
sgs->group_imb = 1;
sgs->group_capacity = DIV_ROUND_CLOSEST(group->sgp->power,
SCHED_POWER_SCALE);
if (!sgs->group_capacity)
- sgs->group_capacity = fix_small_capacity(sd, group);
+ sgs->group_capacity = fix_small_capacity(env->sd, group);
sgs->group_weight = group->group_weight;
if (sgs->group_capacity > sgs->sum_nr_running)
@@ -3876,11 +3728,10 @@ static inline void update_sg_lb_stats(struct sched_domain *sd,
* Determine if @sg is a busier group than the previously selected
* busiest group.
*/
-static bool update_sd_pick_busiest(struct sched_domain *sd,
+static bool update_sd_pick_busiest(struct lb_env *env,
struct sd_lb_stats *sds,
struct sched_group *sg,
- struct sg_lb_stats *sgs,
- int this_cpu)
+ struct sg_lb_stats *sgs)
{
if (sgs->avg_load <= sds->max_load)
return false;
@@ -3896,8 +3747,8 @@ static bool update_sd_pick_busiest(struct sched_domain *sd,
* numbered CPUs in the group, therefore mark all groups
* higher than ourself as busy.
*/
- if ((sd->flags & SD_ASYM_PACKING) && sgs->sum_nr_running &&
- this_cpu < group_first_cpu(sg)) {
+ if ((env->sd->flags & SD_ASYM_PACKING) && sgs->sum_nr_running &&
+ env->dst_cpu < group_first_cpu(sg)) {
if (!sds->busiest)
return true;
@@ -3917,28 +3768,27 @@ static bool update_sd_pick_busiest(struct sched_domain *sd,
* @balance: Should we balance.
* @sds: variable to hold the statistics for this sched_domain.
*/
-static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu,
- enum cpu_idle_type idle, const struct cpumask *cpus,
- int *balance, struct sd_lb_stats *sds)
+static inline void update_sd_lb_stats(struct lb_env *env,
+ const struct cpumask *cpus,
+ int *balance, struct sd_lb_stats *sds)
{
- struct sched_domain *child = sd->child;
- struct sched_group *sg = sd->groups;
+ struct sched_domain *child = env->sd->child;
+ struct sched_group *sg = env->sd->groups;
struct sg_lb_stats sgs;
int load_idx, prefer_sibling = 0;
if (child && child->flags & SD_PREFER_SIBLING)
prefer_sibling = 1;
- init_sd_power_savings_stats(sd, sds, idle);
- load_idx = get_sd_load_idx(sd, idle);
+ load_idx = get_sd_load_idx(env->sd, env->idle);
do {
int local_group;
- local_group = cpumask_test_cpu(this_cpu, sched_group_cpus(sg));
+ local_group = cpumask_test_cpu(env->dst_cpu, sched_group_cpus(sg));
memset(&sgs, 0, sizeof(sgs));
- update_sg_lb_stats(sd, sg, this_cpu, idle, load_idx,
- local_group, cpus, balance, &sgs);
+ update_sg_lb_stats(env, sg, load_idx, local_group,
+ cpus, balance, &sgs);
if (local_group && !(*balance))
return;
@@ -3966,7 +3816,7 @@ static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu,
sds->this_load_per_task = sgs.sum_weighted_load;
sds->this_has_capacity = sgs.group_has_capacity;
sds->this_idle_cpus = sgs.idle_cpus;
- } else if (update_sd_pick_busiest(sd, sds, sg, &sgs, this_cpu)) {
+ } else if (update_sd_pick_busiest(env, sds, sg, &sgs)) {
sds->max_load = sgs.avg_load;
sds->busiest = sg;
sds->busiest_nr_running = sgs.sum_nr_running;
@@ -3978,9 +3828,8 @@ static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu,
sds->group_imb = sgs.group_imb;
}
- update_sd_power_savings_stats(sg, sds, local_group, &sgs);
sg = sg->next;
- } while (sg != sd->groups);
+ } while (sg != env->sd->groups);
}
/**
@@ -4008,24 +3857,23 @@ static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu,
* @this_cpu: The cpu at whose sched_domain we're performing load-balance.
* @imbalance: returns amount of imbalanced due to packing.
*/
-static int check_asym_packing(struct sched_domain *sd,
- struct sd_lb_stats *sds,
- int this_cpu, unsigned long *imbalance)
+static int check_asym_packing(struct lb_env *env, struct sd_lb_stats *sds)
{
int busiest_cpu;
- if (!(sd->flags & SD_ASYM_PACKING))
+ if (!(env->sd->flags & SD_ASYM_PACKING))
return 0;
if (!sds->busiest)
return 0;
busiest_cpu = group_first_cpu(sds->busiest);
- if (this_cpu > busiest_cpu)
+ if (env->dst_cpu > busiest_cpu)
return 0;
- *imbalance = DIV_ROUND_CLOSEST(sds->max_load * sds->busiest->sgp->power,
- SCHED_POWER_SCALE);
+ env->imbalance = DIV_ROUND_CLOSEST(
+ sds->max_load * sds->busiest->sgp->power, SCHED_POWER_SCALE);
+
return 1;
}
@@ -4037,8 +3885,8 @@ static int check_asym_packing(struct sched_domain *sd,
* @this_cpu: The cpu at whose sched_domain we're performing load-balance.
* @imbalance: Variable to store the imbalance.
*/
-static inline void fix_small_imbalance(struct sd_lb_stats *sds,
- int this_cpu, unsigned long *imbalance)
+static inline
+void fix_small_imbalance(struct lb_env *env, struct sd_lb_stats *sds)
{
unsigned long tmp, pwr_now = 0, pwr_move = 0;
unsigned int imbn = 2;
@@ -4049,9 +3897,10 @@ static inline void fix_small_imbalance(struct sd_lb_stats *sds,
if (sds->busiest_load_per_task >
sds->this_load_per_task)
imbn = 1;
- } else
+ } else {
sds->this_load_per_task =
- cpu_avg_load_per_task(this_cpu);
+ cpu_avg_load_per_task(env->dst_cpu);
+ }
scaled_busy_load_per_task = sds->busiest_load_per_task
* SCHED_POWER_SCALE;
@@ -4059,7 +3908,7 @@ static inline void fix_small_imbalance(struct sd_lb_stats *sds,
if (sds->max_load - sds->this_load + scaled_busy_load_per_task >=
(scaled_busy_load_per_task * imbn)) {
- *imbalance = sds->busiest_load_per_task;
+ env->imbalance = sds->busiest_load_per_task;
return;
}
@@ -4096,18 +3945,16 @@ static inline void fix_small_imbalance(struct sd_lb_stats *sds,
/* Move if we gain throughput */
if (pwr_move > pwr_now)
- *imbalance = sds->busiest_load_per_task;
+ env->imbalance = sds->busiest_load_per_task;
}
/**
* calculate_imbalance - Calculate the amount of imbalance present within the
* groups of a given sched_domain during load balance.
+ * @env: load balance environment
* @sds: statistics of the sched_domain whose imbalance is to be calculated.
- * @this_cpu: Cpu for which currently load balance is being performed.
- * @imbalance: The variable to store the imbalance.
*/
-static inline void calculate_imbalance(struct sd_lb_stats *sds, int this_cpu,
- unsigned long *imbalance)
+static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *sds)
{
unsigned long max_pull, load_above_capacity = ~0UL;
@@ -4123,8 +3970,8 @@ static inline void calculate_imbalance(struct sd_lb_stats *sds, int this_cpu,
* its cpu_power, while calculating max_load..)
*/
if (sds->max_load < sds->avg_load) {
- *imbalance = 0;
- return fix_small_imbalance(sds, this_cpu, imbalance);
+ env->imbalance = 0;
+ return fix_small_imbalance(env, sds);
}
if (!sds->group_imb) {
@@ -4152,7 +3999,7 @@ static inline void calculate_imbalance(struct sd_lb_stats *sds, int this_cpu,
max_pull = min(sds->max_load - sds->avg_load, load_above_capacity);
/* How much load to actually move to equalise the imbalance */
- *imbalance = min(max_pull * sds->busiest->sgp->power,
+ env->imbalance = min(max_pull * sds->busiest->sgp->power,
(sds->avg_load - sds->this_load) * sds->this->sgp->power)
/ SCHED_POWER_SCALE;
@@ -4162,8 +4009,8 @@ static inline void calculate_imbalance(struct sd_lb_stats *sds, int this_cpu,
* a think about bumping its value to force at least one task to be
* moved
*/
- if (*imbalance < sds->busiest_load_per_task)
- return fix_small_imbalance(sds, this_cpu, imbalance);
+ if (env->imbalance < sds->busiest_load_per_task)
+ return fix_small_imbalance(env, sds);
}
@@ -4194,9 +4041,7 @@ static inline void calculate_imbalance(struct sd_lb_stats *sds, int this_cpu,
* put to idle by rebalancing its tasks onto our group.
*/
static struct sched_group *
-find_busiest_group(struct sched_domain *sd, int this_cpu,
- unsigned long *imbalance, enum cpu_idle_type idle,
- const struct cpumask *cpus, int *balance)
+find_busiest_group(struct lb_env *env, const struct cpumask *cpus, int *balance)
{
struct sd_lb_stats sds;
@@ -4206,7 +4051,7 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
* Compute the various statistics relavent for load balancing at
* this level.
*/
- update_sd_lb_stats(sd, this_cpu, idle, cpus, balance, &sds);
+ update_sd_lb_stats(env, cpus, balance, &sds);
/*
* this_cpu is not the appropriate cpu to perform load balancing at
@@ -4215,8 +4060,8 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
if (!(*balance))
goto ret;
- if ((idle == CPU_IDLE || idle == CPU_NEWLY_IDLE) &&
- check_asym_packing(sd, &sds, this_cpu, imbalance))
+ if ((env->idle == CPU_IDLE || env->idle == CPU_NEWLY_IDLE) &&
+ check_asym_packing(env, &sds))
return sds.busiest;
/* There is no busy sibling group to pull tasks from */
@@ -4234,7 +4079,7 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
goto force_balance;
/* SD_BALANCE_NEWIDLE trumps SMP nice when underutilized */
- if (idle == CPU_NEWLY_IDLE && sds.this_has_capacity &&
+ if (env->idle == CPU_NEWLY_IDLE && sds.this_has_capacity &&
!sds.busiest_has_capacity)
goto force_balance;
@@ -4252,7 +4097,7 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
if (sds.this_load >= sds.avg_load)
goto out_balanced;
- if (idle == CPU_IDLE) {
+ if (env->idle == CPU_IDLE) {
/*
* This cpu is idle. If the busiest group load doesn't
* have more tasks than the number of available cpu's and
@@ -4267,34 +4112,27 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
* In the CPU_NEWLY_IDLE, CPU_NOT_IDLE cases, use
* imbalance_pct to be conservative.
*/
- if (100 * sds.max_load <= sd->imbalance_pct * sds.this_load)
+ if (100 * sds.max_load <= env->sd->imbalance_pct * sds.this_load)
goto out_balanced;
}
force_balance:
/* Looks like there is an imbalance. Compute it */
- calculate_imbalance(&sds, this_cpu, imbalance);
+ calculate_imbalance(env, &sds);
return sds.busiest;
out_balanced:
- /*
- * There is no obvious imbalance. But check if we can do some balancing
- * to save power.
- */
- if (check_power_save_busiest_group(&sds, this_cpu, imbalance))
- return sds.busiest;
ret:
- *imbalance = 0;
+ env->imbalance = 0;
return NULL;
}
/*
* find_busiest_queue - find the busiest runqueue among the cpus in group.
*/
-static struct rq *
-find_busiest_queue(struct sched_domain *sd, struct sched_group *group,
- enum cpu_idle_type idle, unsigned long imbalance,
- const struct cpumask *cpus)
+static struct rq *find_busiest_queue(struct lb_env *env,
+ struct sched_group *group,
+ const struct cpumask *cpus)
{
struct rq *busiest = NULL, *rq;
unsigned long max_load = 0;
@@ -4307,7 +4145,7 @@ find_busiest_queue(struct sched_domain *sd, struct sched_group *group,
unsigned long wl;
if (!capacity)
- capacity = fix_small_capacity(sd, group);
+ capacity = fix_small_capacity(env->sd, group);
if (!cpumask_test_cpu(i, cpus))
continue;
@@ -4319,7 +4157,7 @@ find_busiest_queue(struct sched_domain *sd, struct sched_group *group,
* When comparing with imbalance, use weighted_cpuload()
* which is not scaled with the cpu power.
*/
- if (capacity && rq->nr_running == 1 && wl > imbalance)
+ if (capacity && rq->nr_running == 1 && wl > env->imbalance)
continue;
/*
@@ -4348,40 +4186,19 @@ find_busiest_queue(struct sched_domain *sd, struct sched_group *group,
/* Working cpumask for load_balance and load_balance_newidle. */
DEFINE_PER_CPU(cpumask_var_t, load_balance_tmpmask);
-static int need_active_balance(struct sched_domain *sd, int idle,
- int busiest_cpu, int this_cpu)
+static int need_active_balance(struct lb_env *env)
{
- if (idle == CPU_NEWLY_IDLE) {
+ struct sched_domain *sd = env->sd;
+
+ if (env->idle == CPU_NEWLY_IDLE) {
/*
* ASYM_PACKING needs to force migrate tasks from busy but
* higher numbered CPUs in order to pack all tasks in the
* lowest numbered CPUs.
*/
- if ((sd->flags & SD_ASYM_PACKING) && busiest_cpu > this_cpu)
+ if ((sd->flags & SD_ASYM_PACKING) && env->src_cpu > env->dst_cpu)
return 1;
-
- /*
- * The only task running in a non-idle cpu can be moved to this
- * cpu in an attempt to completely freeup the other CPU
- * package.
- *
- * The package power saving logic comes from
- * find_busiest_group(). If there are no imbalance, then
- * f_b_g() will return NULL. However when sched_mc={1,2} then
- * f_b_g() will select a group from which a running task may be
- * pulled to this cpu in order to make the other package idle.
- * If there is no opportunity to make a package idle and if
- * there are no imbalance, then f_b_g() will return NULL and no
- * action will be taken in load_balance_newidle().
- *
- * Under normal task pull operation due to imbalance, there
- * will be more than one task in the source run queue and
- * move_tasks() will succeed. ld_moved will be true and this
- * active balance code will not be triggered.
- */
- if (sched_mc_power_savings < POWERSAVINGS_BALANCE_WAKEUP)
- return 0;
}
return unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2);
@@ -4399,7 +4216,6 @@ static int load_balance(int this_cpu, struct rq *this_rq,
{
int ld_moved, active_balance = 0;
struct sched_group *group;
- unsigned long imbalance;
struct rq *busiest;
unsigned long flags;
struct cpumask *cpus = __get_cpu_var(load_balance_tmpmask);
@@ -4417,8 +4233,7 @@ static int load_balance(int this_cpu, struct rq *this_rq,
schedstat_inc(sd, lb_count[idle]);
redo:
- group = find_busiest_group(sd, this_cpu, &imbalance, idle,
- cpus, balance);
+ group = find_busiest_group(&env, cpus, balance);
if (*balance == 0)
goto out_balanced;
@@ -4428,7 +4243,7 @@ redo:
goto out_balanced;
}
- busiest = find_busiest_queue(sd, group, idle, imbalance, cpus);
+ busiest = find_busiest_queue(&env, group, cpus);
if (!busiest) {
schedstat_inc(sd, lb_nobusyq[idle]);
goto out_balanced;
@@ -4436,7 +4251,7 @@ redo:
BUG_ON(busiest == this_rq);
- schedstat_add(sd, lb_imbalance[idle], imbalance);
+ schedstat_add(sd, lb_imbalance[idle], env.imbalance);
ld_moved = 0;
if (busiest->nr_running > 1) {
@@ -4447,10 +4262,9 @@ redo:
* correctly treated as an imbalance.
*/
env.flags |= LBF_ALL_PINNED;
- env.load_move = imbalance;
- env.src_cpu = busiest->cpu;
- env.src_rq = busiest;
- env.loop_max = min_t(unsigned long, sysctl_sched_nr_migrate, busiest->nr_running);
+ env.src_cpu = busiest->cpu;
+ env.src_rq = busiest;
+ env.loop_max = min(sysctl_sched_nr_migrate, busiest->nr_running);
more_balance:
local_irq_save(flags);
@@ -4492,7 +4306,7 @@ more_balance:
if (idle != CPU_NEWLY_IDLE)
sd->nr_balance_failed++;
- if (need_active_balance(sd, idle, cpu_of(busiest), this_cpu)) {
+ if (need_active_balance(&env)) {
raw_spin_lock_irqsave(&busiest->lock, flags);
/* don't kick the active_load_balance_cpu_stop,
@@ -4519,10 +4333,11 @@ more_balance:
}
raw_spin_unlock_irqrestore(&busiest->lock, flags);
- if (active_balance)
+ if (active_balance) {
stop_one_cpu_nowait(cpu_of(busiest),
active_load_balance_cpu_stop, busiest,
&busiest->active_balance_work);
+ }
/*
* We've kicked active balancing, reset the failure
@@ -4703,104 +4518,15 @@ static struct {
unsigned long next_balance; /* in jiffy units */
} nohz ____cacheline_aligned;
-#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
-/**
- * lowest_flag_domain - Return lowest sched_domain containing flag.
- * @cpu: The cpu whose lowest level of sched domain is to
- * be returned.
- * @flag: The flag to check for the lowest sched_domain
- * for the given cpu.
- *
- * Returns the lowest sched_domain of a cpu which contains the given flag.
- */
-static inline struct sched_domain *lowest_flag_domain(int cpu, int flag)
-{
- struct sched_domain *sd;
-
- for_each_domain(cpu, sd)
- if (sd->flags & flag)
- break;
-
- return sd;
-}
-
-/**
- * for_each_flag_domain - Iterates over sched_domains containing the flag.
- * @cpu: The cpu whose domains we're iterating over.
- * @sd: variable holding the value of the power_savings_sd
- * for cpu.
- * @flag: The flag to filter the sched_domains to be iterated.
- *
- * Iterates over all the scheduler domains for a given cpu that has the 'flag'
- * set, starting from the lowest sched_domain to the highest.
- */
-#define for_each_flag_domain(cpu, sd, flag) \
- for (sd = lowest_flag_domain(cpu, flag); \
- (sd && (sd->flags & flag)); sd = sd->parent)
-
-/**
- * find_new_ilb - Finds the optimum idle load balancer for nomination.
- * @cpu: The cpu which is nominating a new idle_load_balancer.
- *
- * Returns: Returns the id of the idle load balancer if it exists,
- * Else, returns >= nr_cpu_ids.
- *
- * This algorithm picks the idle load balancer such that it belongs to a
- * semi-idle powersavings sched_domain. The idea is to try and avoid
- * completely idle packages/cores just for the purpose of idle load balancing
- * when there are other idle cpu's which are better suited for that job.
- */
-static int find_new_ilb(int cpu)
+static inline int find_new_ilb(int call_cpu)
{
int ilb = cpumask_first(nohz.idle_cpus_mask);
- struct sched_group *ilbg;
- struct sched_domain *sd;
-
- /*
- * Have idle load balancer selection from semi-idle packages only
- * when power-aware load balancing is enabled
- */
- if (!(sched_smt_power_savings || sched_mc_power_savings))
- goto out_done;
-
- /*
- * Optimize for the case when we have no idle CPUs or only one
- * idle CPU. Don't walk the sched_domain hierarchy in such cases
- */
- if (cpumask_weight(nohz.idle_cpus_mask) < 2)
- goto out_done;
-
- rcu_read_lock();
- for_each_flag_domain(cpu, sd, SD_POWERSAVINGS_BALANCE) {
- ilbg = sd->groups;
-
- do {
- if (ilbg->group_weight !=
- atomic_read(&ilbg->sgp->nr_busy_cpus)) {
- ilb = cpumask_first_and(nohz.idle_cpus_mask,
- sched_group_cpus(ilbg));
- goto unlock;
- }
-
- ilbg = ilbg->next;
-
- } while (ilbg != sd->groups);
- }
-unlock:
- rcu_read_unlock();
-out_done:
if (ilb < nr_cpu_ids && idle_cpu(ilb))
return ilb;
return nr_cpu_ids;
}
-#else /* (CONFIG_SCHED_MC || CONFIG_SCHED_SMT) */
-static inline int find_new_ilb(int call_cpu)
-{
- return nr_cpu_ids;
-}
-#endif
/*
* Kick a CPU to do the nohz balancing, if it is time for it. We pick the
@@ -5023,7 +4749,7 @@ static void nohz_idle_balance(int this_cpu, enum cpu_idle_type idle)
raw_spin_lock_irq(&this_rq->lock);
update_rq_clock(this_rq);
- update_cpu_load(this_rq);
+ update_idle_cpu_load(this_rq);
raw_spin_unlock_irq(&this_rq->lock);
rebalance_domains(balance_cpu, CPU_IDLE);
diff --git a/kernel/sched/idle_task.c b/kernel/sched/idle_task.c
index 91b4c957f289..b44d604b35d1 100644
--- a/kernel/sched/idle_task.c
+++ b/kernel/sched/idle_task.c
@@ -4,7 +4,7 @@
* idle-task scheduling class.
*
* (NOTE: these are not related to SCHED_IDLE tasks which are
- * handled in sched_fair.c)
+ * handled in sched/fair.c)
*/
#ifdef CONFIG_SMP
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 44af55e6d5d0..c5565c3c515f 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -1803,44 +1803,40 @@ static void task_woken_rt(struct rq *rq, struct task_struct *p)
static void set_cpus_allowed_rt(struct task_struct *p,
const struct cpumask *new_mask)
{
- int weight = cpumask_weight(new_mask);
+ struct rq *rq;
+ int weight;
BUG_ON(!rt_task(p));
- /*
- * Update the migration status of the RQ if we have an RT task
- * which is running AND changing its weight value.
- */
- if (p->on_rq && (weight != p->rt.nr_cpus_allowed)) {
- struct rq *rq = task_rq(p);
-
- if (!task_current(rq, p)) {
- /*
- * Make sure we dequeue this task from the pushable list
- * before going further. It will either remain off of
- * the list because we are no longer pushable, or it
- * will be requeued.
- */
- if (p->rt.nr_cpus_allowed > 1)
- dequeue_pushable_task(rq, p);
+ if (!p->on_rq)
+ return;
- /*
- * Requeue if our weight is changing and still > 1
- */
- if (weight > 1)
- enqueue_pushable_task(rq, p);
+ weight = cpumask_weight(new_mask);
- }
+ /*
+ * Only update if the process changes its state from whether it
+ * can migrate or not.
+ */
+ if ((p->rt.nr_cpus_allowed > 1) == (weight > 1))
+ return;
- if ((p->rt.nr_cpus_allowed <= 1) && (weight > 1)) {
- rq->rt.rt_nr_migratory++;
- } else if ((p->rt.nr_cpus_allowed > 1) && (weight <= 1)) {
- BUG_ON(!rq->rt.rt_nr_migratory);
- rq->rt.rt_nr_migratory--;
- }
+ rq = task_rq(p);
- update_rt_migration(&rq->rt);
+ /*
+ * The process used to be able to migrate OR it can now migrate
+ */
+ if (weight <= 1) {
+ if (!task_current(rq, p))
+ dequeue_pushable_task(rq, p);
+ BUG_ON(!rq->rt.rt_nr_migratory);
+ rq->rt.rt_nr_migratory--;
+ } else {
+ if (!task_current(rq, p))
+ enqueue_pushable_task(rq, p);
+ rq->rt.rt_nr_migratory++;
}
+
+ update_rt_migration(&rq->rt);
}
/* Assumes rq->lock is held */
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index fb3acba4d52e..ba9dccfd24ce 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -201,7 +201,7 @@ struct cfs_bandwidth { };
/* CFS-related fields in a runqueue */
struct cfs_rq {
struct load_weight load;
- unsigned long nr_running, h_nr_running;
+ unsigned int nr_running, h_nr_running;
u64 exec_clock;
u64 min_vruntime;
@@ -279,7 +279,7 @@ static inline int rt_bandwidth_enabled(void)
/* Real-Time classes' related field in a runqueue: */
struct rt_rq {
struct rt_prio_array active;
- unsigned long rt_nr_running;
+ unsigned int rt_nr_running;
#if defined CONFIG_SMP || defined CONFIG_RT_GROUP_SCHED
struct {
int curr; /* highest queued rt task prio */
@@ -353,7 +353,7 @@ struct rq {
* nr_running and cpu_load should be in the same cacheline because
* remote CPUs use both these fields when doing load calculation.
*/
- unsigned long nr_running;
+ unsigned int nr_running;
#define CPU_LOAD_IDX_MAX 5
unsigned long cpu_load[CPU_LOAD_IDX_MAX];
unsigned long last_load_update_tick;
@@ -876,7 +876,7 @@ extern void resched_cpu(int cpu);
extern struct rt_bandwidth def_rt_bandwidth;
extern void init_rt_bandwidth(struct rt_bandwidth *rt_b, u64 period, u64 runtime);
-extern void update_cpu_load(struct rq *this_rq);
+extern void update_idle_cpu_load(struct rq *this_rq);
#ifdef CONFIG_CGROUP_CPUACCT
#include <linux/cgroup.h>
diff --git a/kernel/semaphore.c b/kernel/semaphore.c
index 60636a4e25c3..4567fc020fe3 100644
--- a/kernel/semaphore.c
+++ b/kernel/semaphore.c
@@ -118,7 +118,7 @@ EXPORT_SYMBOL(down_killable);
* down_trylock - try to acquire the semaphore, without waiting
* @sem: the semaphore to be acquired
*
- * Try to acquire the semaphore atomically. Returns 0 if the mutex has
+ * Try to acquire the semaphore atomically. Returns 0 if the semaphore has
* been acquired successfully or 1 if it it cannot be acquired.
*
* NOTE: This return value is inverted from both spin_trylock and
diff --git a/kernel/signal.c b/kernel/signal.c
index 1a006b5d9d9d..f7b418217633 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -29,6 +29,7 @@
#include <linux/pid_namespace.h>
#include <linux/nsproxy.h>
#include <linux/user_namespace.h>
+#include <linux/uprobes.h>
#define CREATE_TRACE_POINTS
#include <trace/events/signal.h>
@@ -767,14 +768,13 @@ static int kill_ok_by_cred(struct task_struct *t)
const struct cred *cred = current_cred();
const struct cred *tcred = __task_cred(t);
- if (cred->user->user_ns == tcred->user->user_ns &&
- (cred->euid == tcred->suid ||
- cred->euid == tcred->uid ||
- cred->uid == tcred->suid ||
- cred->uid == tcred->uid))
+ if (uid_eq(cred->euid, tcred->suid) ||
+ uid_eq(cred->euid, tcred->uid) ||
+ uid_eq(cred->uid, tcred->suid) ||
+ uid_eq(cred->uid, tcred->uid))
return 1;
- if (ns_capable(tcred->user->user_ns, CAP_KILL))
+ if (ns_capable(tcred->user_ns, CAP_KILL))
return 1;
return 0;
@@ -1020,15 +1020,6 @@ static inline int legacy_queue(struct sigpending *signals, int sig)
return (sig < SIGRTMIN) && sigismember(&signals->signal, sig);
}
-/*
- * map the uid in struct cred into user namespace *ns
- */
-static inline uid_t map_cred_ns(const struct cred *cred,
- struct user_namespace *ns)
-{
- return user_ns_map_uid(ns, cred, cred->uid);
-}
-
#ifdef CONFIG_USER_NS
static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t)
{
@@ -1038,8 +1029,10 @@ static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_str
if (SI_FROMKERNEL(info))
return;
- info->si_uid = user_ns_map_uid(task_cred_xxx(t, user_ns),
- current_cred(), info->si_uid);
+ rcu_read_lock();
+ info->si_uid = from_kuid_munged(task_cred_xxx(t, user_ns),
+ make_kuid(current_user_ns(), info->si_uid));
+ rcu_read_unlock();
}
#else
static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t)
@@ -1106,7 +1099,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
q->info.si_code = SI_USER;
q->info.si_pid = task_tgid_nr_ns(current,
task_active_pid_ns(t));
- q->info.si_uid = current_uid();
+ q->info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
break;
case (unsigned long) SEND_SIG_PRIV:
q->info.si_signo = sig;
@@ -1387,10 +1380,8 @@ static int kill_as_cred_perm(const struct cred *cred,
struct task_struct *target)
{
const struct cred *pcred = __task_cred(target);
- if (cred->user_ns != pcred->user_ns)
- return 0;
- if (cred->euid != pcred->suid && cred->euid != pcred->uid &&
- cred->uid != pcred->suid && cred->uid != pcred->uid)
+ if (!uid_eq(cred->euid, pcred->suid) && !uid_eq(cred->euid, pcred->uid) &&
+ !uid_eq(cred->uid, pcred->suid) && !uid_eq(cred->uid, pcred->uid))
return 0;
return 1;
}
@@ -1678,8 +1669,8 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
*/
rcu_read_lock();
info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns);
- info.si_uid = map_cred_ns(__task_cred(tsk),
- task_cred_xxx(tsk->parent, user_ns));
+ info.si_uid = from_kuid_munged(task_cred_xxx(tsk->parent, user_ns),
+ task_uid(tsk));
rcu_read_unlock();
info.si_utime = cputime_to_clock_t(tsk->utime + tsk->signal->utime);
@@ -1762,8 +1753,7 @@ static void do_notify_parent_cldstop(struct task_struct *tsk,
*/
rcu_read_lock();
info.si_pid = task_pid_nr_ns(tsk, parent->nsproxy->pid_ns);
- info.si_uid = map_cred_ns(__task_cred(tsk),
- task_cred_xxx(parent, user_ns));
+ info.si_uid = from_kuid_munged(task_cred_xxx(parent, user_ns), task_uid(tsk));
rcu_read_unlock();
info.si_utime = cputime_to_clock_t(tsk->utime);
@@ -1973,7 +1963,7 @@ static void ptrace_do_notify(int signr, int exit_code, int why)
info.si_signo = signr;
info.si_code = exit_code;
info.si_pid = task_pid_vnr(current);
- info.si_uid = current_uid();
+ info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
/* Let the debugger run. */
ptrace_stop(exit_code, why, 1, &info);
@@ -2181,8 +2171,8 @@ static int ptrace_signal(int signr, siginfo_t *info,
info->si_code = SI_USER;
rcu_read_lock();
info->si_pid = task_pid_vnr(current->parent);
- info->si_uid = map_cred_ns(__task_cred(current->parent),
- current_user_ns());
+ info->si_uid = from_kuid_munged(current_user_ns(),
+ task_uid(current->parent));
rcu_read_unlock();
}
@@ -2202,6 +2192,9 @@ int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka,
struct signal_struct *signal = current->signal;
int signr;
+ if (unlikely(uprobe_deny_signal()))
+ return 0;
+
relock:
/*
* We'll jump back here after any time we were stopped in TASK_STOPPED.
@@ -2835,7 +2828,7 @@ SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)
info.si_errno = 0;
info.si_code = SI_USER;
info.si_pid = task_tgid_vnr(current);
- info.si_uid = current_uid();
+ info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
return kill_something_info(sig, &info, pid);
}
@@ -2878,7 +2871,7 @@ static int do_tkill(pid_t tgid, pid_t pid, int sig)
info.si_errno = 0;
info.si_code = SI_TKILL;
info.si_pid = task_tgid_vnr(current);
- info.si_uid = current_uid();
+ info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
return do_send_specific(tgid, pid, sig, &info);
}
@@ -3243,6 +3236,21 @@ SYSCALL_DEFINE0(pause)
#endif
+#ifdef HAVE_SET_RESTORE_SIGMASK
+int sigsuspend(sigset_t *set)
+{
+ sigdelsetmask(set, sigmask(SIGKILL)|sigmask(SIGSTOP));
+
+ current->saved_sigmask = current->blocked;
+ set_current_blocked(set);
+
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ set_restore_sigmask();
+ return -ERESTARTNOHAND;
+}
+#endif
+
#ifdef __ARCH_WANT_SYS_RT_SIGSUSPEND
/**
* sys_rt_sigsuspend - replace the signal mask for a value with the
@@ -3260,15 +3268,7 @@ SYSCALL_DEFINE2(rt_sigsuspend, sigset_t __user *, unewset, size_t, sigsetsize)
if (copy_from_user(&newset, unewset, sizeof(newset)))
return -EFAULT;
- sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP));
-
- current->saved_sigmask = current->blocked;
- set_current_blocked(&newset);
-
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- set_restore_sigmask();
- return -ERESTARTNOHAND;
+ return sigsuspend(&newset);
}
#endif /* __ARCH_WANT_SYS_RT_SIGSUSPEND */
diff --git a/kernel/sys.c b/kernel/sys.c
index ba0ae8eea6fb..6df42624e454 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -93,10 +93,8 @@
int overflowuid = DEFAULT_OVERFLOWUID;
int overflowgid = DEFAULT_OVERFLOWGID;
-#ifdef CONFIG_UID16
EXPORT_SYMBOL(overflowuid);
EXPORT_SYMBOL(overflowgid);
-#endif
/*
* the same as above, but for filesystems which can only store a 16-bit
@@ -133,11 +131,10 @@ static bool set_one_prio_perm(struct task_struct *p)
{
const struct cred *cred = current_cred(), *pcred = __task_cred(p);
- if (pcred->user->user_ns == cred->user->user_ns &&
- (pcred->uid == cred->euid ||
- pcred->euid == cred->euid))
+ if (uid_eq(pcred->uid, cred->euid) ||
+ uid_eq(pcred->euid, cred->euid))
return true;
- if (ns_capable(pcred->user->user_ns, CAP_SYS_NICE))
+ if (ns_capable(pcred->user_ns, CAP_SYS_NICE))
return true;
return false;
}
@@ -177,6 +174,7 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
const struct cred *cred = current_cred();
int error = -EINVAL;
struct pid *pgrp;
+ kuid_t uid;
if (which > PRIO_USER || which < PRIO_PROCESS)
goto out;
@@ -209,18 +207,19 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
break;
case PRIO_USER:
- user = (struct user_struct *) cred->user;
+ uid = make_kuid(cred->user_ns, who);
+ user = cred->user;
if (!who)
- who = cred->uid;
- else if ((who != cred->uid) &&
- !(user = find_user(who)))
+ uid = cred->uid;
+ else if (!uid_eq(uid, cred->uid) &&
+ !(user = find_user(uid)))
goto out_unlock; /* No processes for this user */
do_each_thread(g, p) {
- if (__task_cred(p)->uid == who)
+ if (uid_eq(task_uid(p), uid))
error = set_one_prio(p, niceval, error);
} while_each_thread(g, p);
- if (who != cred->uid)
+ if (!uid_eq(uid, cred->uid))
free_uid(user); /* For find_user() */
break;
}
@@ -244,6 +243,7 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who)
const struct cred *cred = current_cred();
long niceval, retval = -ESRCH;
struct pid *pgrp;
+ kuid_t uid;
if (which > PRIO_USER || which < PRIO_PROCESS)
return -EINVAL;
@@ -274,21 +274,22 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who)
} while_each_pid_thread(pgrp, PIDTYPE_PGID, p);
break;
case PRIO_USER:
- user = (struct user_struct *) cred->user;
+ uid = make_kuid(cred->user_ns, who);
+ user = cred->user;
if (!who)
- who = cred->uid;
- else if ((who != cred->uid) &&
- !(user = find_user(who)))
+ uid = cred->uid;
+ else if (!uid_eq(uid, cred->uid) &&
+ !(user = find_user(uid)))
goto out_unlock; /* No processes for this user */
do_each_thread(g, p) {
- if (__task_cred(p)->uid == who) {
+ if (uid_eq(task_uid(p), uid)) {
niceval = 20 - task_nice(p);
if (niceval > retval)
retval = niceval;
}
} while_each_thread(g, p);
- if (who != cred->uid)
+ if (!uid_eq(uid, cred->uid))
free_uid(user); /* for find_user() */
break;
}
@@ -553,9 +554,19 @@ void ctrl_alt_del(void)
*/
SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
{
+ struct user_namespace *ns = current_user_ns();
const struct cred *old;
struct cred *new;
int retval;
+ kgid_t krgid, kegid;
+
+ krgid = make_kgid(ns, rgid);
+ kegid = make_kgid(ns, egid);
+
+ if ((rgid != (gid_t) -1) && !gid_valid(krgid))
+ return -EINVAL;
+ if ((egid != (gid_t) -1) && !gid_valid(kegid))
+ return -EINVAL;
new = prepare_creds();
if (!new)
@@ -564,25 +575,25 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
retval = -EPERM;
if (rgid != (gid_t) -1) {
- if (old->gid == rgid ||
- old->egid == rgid ||
+ if (gid_eq(old->gid, krgid) ||
+ gid_eq(old->egid, krgid) ||
nsown_capable(CAP_SETGID))
- new->gid = rgid;
+ new->gid = krgid;
else
goto error;
}
if (egid != (gid_t) -1) {
- if (old->gid == egid ||
- old->egid == egid ||
- old->sgid == egid ||
+ if (gid_eq(old->gid, kegid) ||
+ gid_eq(old->egid, kegid) ||
+ gid_eq(old->sgid, kegid) ||
nsown_capable(CAP_SETGID))
- new->egid = egid;
+ new->egid = kegid;
else
goto error;
}
if (rgid != (gid_t) -1 ||
- (egid != (gid_t) -1 && egid != old->gid))
+ (egid != (gid_t) -1 && !gid_eq(kegid, old->gid)))
new->sgid = new->egid;
new->fsgid = new->egid;
@@ -600,9 +611,15 @@ error:
*/
SYSCALL_DEFINE1(setgid, gid_t, gid)
{
+ struct user_namespace *ns = current_user_ns();
const struct cred *old;
struct cred *new;
int retval;
+ kgid_t kgid;
+
+ kgid = make_kgid(ns, gid);
+ if (!gid_valid(kgid))
+ return -EINVAL;
new = prepare_creds();
if (!new)
@@ -611,9 +628,9 @@ SYSCALL_DEFINE1(setgid, gid_t, gid)
retval = -EPERM;
if (nsown_capable(CAP_SETGID))
- new->gid = new->egid = new->sgid = new->fsgid = gid;
- else if (gid == old->gid || gid == old->sgid)
- new->egid = new->fsgid = gid;
+ new->gid = new->egid = new->sgid = new->fsgid = kgid;
+ else if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->sgid))
+ new->egid = new->fsgid = kgid;
else
goto error;
@@ -631,7 +648,7 @@ static int set_user(struct cred *new)
{
struct user_struct *new_user;
- new_user = alloc_uid(current_user_ns(), new->uid);
+ new_user = alloc_uid(new->uid);
if (!new_user)
return -EAGAIN;
@@ -670,9 +687,19 @@ static int set_user(struct cred *new)
*/
SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
{
+ struct user_namespace *ns = current_user_ns();
const struct cred *old;
struct cred *new;
int retval;
+ kuid_t kruid, keuid;
+
+ kruid = make_kuid(ns, ruid);
+ keuid = make_kuid(ns, euid);
+
+ if ((ruid != (uid_t) -1) && !uid_valid(kruid))
+ return -EINVAL;
+ if ((euid != (uid_t) -1) && !uid_valid(keuid))
+ return -EINVAL;
new = prepare_creds();
if (!new)
@@ -681,29 +708,29 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
retval = -EPERM;
if (ruid != (uid_t) -1) {
- new->uid = ruid;
- if (old->uid != ruid &&
- old->euid != ruid &&
+ new->uid = kruid;
+ if (!uid_eq(old->uid, kruid) &&
+ !uid_eq(old->euid, kruid) &&
!nsown_capable(CAP_SETUID))
goto error;
}
if (euid != (uid_t) -1) {
- new->euid = euid;
- if (old->uid != euid &&
- old->euid != euid &&
- old->suid != euid &&
+ new->euid = keuid;
+ if (!uid_eq(old->uid, keuid) &&
+ !uid_eq(old->euid, keuid) &&
+ !uid_eq(old->suid, keuid) &&
!nsown_capable(CAP_SETUID))
goto error;
}
- if (new->uid != old->uid) {
+ if (!uid_eq(new->uid, old->uid)) {
retval = set_user(new);
if (retval < 0)
goto error;
}
if (ruid != (uid_t) -1 ||
- (euid != (uid_t) -1 && euid != old->uid))
+ (euid != (uid_t) -1 && !uid_eq(keuid, old->uid)))
new->suid = new->euid;
new->fsuid = new->euid;
@@ -731,9 +758,15 @@ error:
*/
SYSCALL_DEFINE1(setuid, uid_t, uid)
{
+ struct user_namespace *ns = current_user_ns();
const struct cred *old;
struct cred *new;
int retval;
+ kuid_t kuid;
+
+ kuid = make_kuid(ns, uid);
+ if (!uid_valid(kuid))
+ return -EINVAL;
new = prepare_creds();
if (!new)
@@ -742,17 +775,17 @@ SYSCALL_DEFINE1(setuid, uid_t, uid)
retval = -EPERM;
if (nsown_capable(CAP_SETUID)) {
- new->suid = new->uid = uid;
- if (uid != old->uid) {
+ new->suid = new->uid = kuid;
+ if (!uid_eq(kuid, old->uid)) {
retval = set_user(new);
if (retval < 0)
goto error;
}
- } else if (uid != old->uid && uid != new->suid) {
+ } else if (!uid_eq(kuid, old->uid) && !uid_eq(kuid, new->suid)) {
goto error;
}
- new->fsuid = new->euid = uid;
+ new->fsuid = new->euid = kuid;
retval = security_task_fix_setuid(new, old, LSM_SETID_ID);
if (retval < 0)
@@ -772,9 +805,24 @@ error:
*/
SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
{
+ struct user_namespace *ns = current_user_ns();
const struct cred *old;
struct cred *new;
int retval;
+ kuid_t kruid, keuid, ksuid;
+
+ kruid = make_kuid(ns, ruid);
+ keuid = make_kuid(ns, euid);
+ ksuid = make_kuid(ns, suid);
+
+ if ((ruid != (uid_t) -1) && !uid_valid(kruid))
+ return -EINVAL;
+
+ if ((euid != (uid_t) -1) && !uid_valid(keuid))
+ return -EINVAL;
+
+ if ((suid != (uid_t) -1) && !uid_valid(ksuid))
+ return -EINVAL;
new = prepare_creds();
if (!new)
@@ -784,29 +832,29 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
retval = -EPERM;
if (!nsown_capable(CAP_SETUID)) {
- if (ruid != (uid_t) -1 && ruid != old->uid &&
- ruid != old->euid && ruid != old->suid)
+ if (ruid != (uid_t) -1 && !uid_eq(kruid, old->uid) &&
+ !uid_eq(kruid, old->euid) && !uid_eq(kruid, old->suid))
goto error;
- if (euid != (uid_t) -1 && euid != old->uid &&
- euid != old->euid && euid != old->suid)
+ if (euid != (uid_t) -1 && !uid_eq(keuid, old->uid) &&
+ !uid_eq(keuid, old->euid) && !uid_eq(keuid, old->suid))
goto error;
- if (suid != (uid_t) -1 && suid != old->uid &&
- suid != old->euid && suid != old->suid)
+ if (suid != (uid_t) -1 && !uid_eq(ksuid, old->uid) &&
+ !uid_eq(ksuid, old->euid) && !uid_eq(ksuid, old->suid))
goto error;
}
if (ruid != (uid_t) -1) {
- new->uid = ruid;
- if (ruid != old->uid) {
+ new->uid = kruid;
+ if (!uid_eq(kruid, old->uid)) {
retval = set_user(new);
if (retval < 0)
goto error;
}
}
if (euid != (uid_t) -1)
- new->euid = euid;
+ new->euid = keuid;
if (suid != (uid_t) -1)
- new->suid = suid;
+ new->suid = ksuid;
new->fsuid = new->euid;
retval = security_task_fix_setuid(new, old, LSM_SETID_RES);
@@ -820,14 +868,19 @@ error:
return retval;
}
-SYSCALL_DEFINE3(getresuid, uid_t __user *, ruid, uid_t __user *, euid, uid_t __user *, suid)
+SYSCALL_DEFINE3(getresuid, uid_t __user *, ruidp, uid_t __user *, euidp, uid_t __user *, suidp)
{
const struct cred *cred = current_cred();
int retval;
+ uid_t ruid, euid, suid;
+
+ ruid = from_kuid_munged(cred->user_ns, cred->uid);
+ euid = from_kuid_munged(cred->user_ns, cred->euid);
+ suid = from_kuid_munged(cred->user_ns, cred->suid);
- if (!(retval = put_user(cred->uid, ruid)) &&
- !(retval = put_user(cred->euid, euid)))
- retval = put_user(cred->suid, suid);
+ if (!(retval = put_user(ruid, ruidp)) &&
+ !(retval = put_user(euid, euidp)))
+ retval = put_user(suid, suidp);
return retval;
}
@@ -837,9 +890,22 @@ SYSCALL_DEFINE3(getresuid, uid_t __user *, ruid, uid_t __user *, euid, uid_t __u
*/
SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
{
+ struct user_namespace *ns = current_user_ns();
const struct cred *old;
struct cred *new;
int retval;
+ kgid_t krgid, kegid, ksgid;
+
+ krgid = make_kgid(ns, rgid);
+ kegid = make_kgid(ns, egid);
+ ksgid = make_kgid(ns, sgid);
+
+ if ((rgid != (gid_t) -1) && !gid_valid(krgid))
+ return -EINVAL;
+ if ((egid != (gid_t) -1) && !gid_valid(kegid))
+ return -EINVAL;
+ if ((sgid != (gid_t) -1) && !gid_valid(ksgid))
+ return -EINVAL;
new = prepare_creds();
if (!new)
@@ -848,23 +914,23 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
retval = -EPERM;
if (!nsown_capable(CAP_SETGID)) {
- if (rgid != (gid_t) -1 && rgid != old->gid &&
- rgid != old->egid && rgid != old->sgid)
+ if (rgid != (gid_t) -1 && !gid_eq(krgid, old->gid) &&
+ !gid_eq(krgid, old->egid) && !gid_eq(krgid, old->sgid))
goto error;
- if (egid != (gid_t) -1 && egid != old->gid &&
- egid != old->egid && egid != old->sgid)
+ if (egid != (gid_t) -1 && !gid_eq(kegid, old->gid) &&
+ !gid_eq(kegid, old->egid) && !gid_eq(kegid, old->sgid))
goto error;
- if (sgid != (gid_t) -1 && sgid != old->gid &&
- sgid != old->egid && sgid != old->sgid)
+ if (sgid != (gid_t) -1 && !gid_eq(ksgid, old->gid) &&
+ !gid_eq(ksgid, old->egid) && !gid_eq(ksgid, old->sgid))
goto error;
}
if (rgid != (gid_t) -1)
- new->gid = rgid;
+ new->gid = krgid;
if (egid != (gid_t) -1)
- new->egid = egid;
+ new->egid = kegid;
if (sgid != (gid_t) -1)
- new->sgid = sgid;
+ new->sgid = ksgid;
new->fsgid = new->egid;
return commit_creds(new);
@@ -874,14 +940,19 @@ error:
return retval;
}
-SYSCALL_DEFINE3(getresgid, gid_t __user *, rgid, gid_t __user *, egid, gid_t __user *, sgid)
+SYSCALL_DEFINE3(getresgid, gid_t __user *, rgidp, gid_t __user *, egidp, gid_t __user *, sgidp)
{
const struct cred *cred = current_cred();
int retval;
+ gid_t rgid, egid, sgid;
+
+ rgid = from_kgid_munged(cred->user_ns, cred->gid);
+ egid = from_kgid_munged(cred->user_ns, cred->egid);
+ sgid = from_kgid_munged(cred->user_ns, cred->sgid);
- if (!(retval = put_user(cred->gid, rgid)) &&
- !(retval = put_user(cred->egid, egid)))
- retval = put_user(cred->sgid, sgid);
+ if (!(retval = put_user(rgid, rgidp)) &&
+ !(retval = put_user(egid, egidp)))
+ retval = put_user(sgid, sgidp);
return retval;
}
@@ -898,18 +969,24 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid)
const struct cred *old;
struct cred *new;
uid_t old_fsuid;
+ kuid_t kuid;
+
+ old = current_cred();
+ old_fsuid = from_kuid_munged(old->user_ns, old->fsuid);
+
+ kuid = make_kuid(old->user_ns, uid);
+ if (!uid_valid(kuid))
+ return old_fsuid;
new = prepare_creds();
if (!new)
- return current_fsuid();
- old = current_cred();
- old_fsuid = old->fsuid;
+ return old_fsuid;
- if (uid == old->uid || uid == old->euid ||
- uid == old->suid || uid == old->fsuid ||
+ if (uid_eq(kuid, old->uid) || uid_eq(kuid, old->euid) ||
+ uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) ||
nsown_capable(CAP_SETUID)) {
- if (uid != old_fsuid) {
- new->fsuid = uid;
+ if (!uid_eq(kuid, old->fsuid)) {
+ new->fsuid = kuid;
if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)
goto change_okay;
}
@@ -931,18 +1008,24 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid)
const struct cred *old;
struct cred *new;
gid_t old_fsgid;
+ kgid_t kgid;
+
+ old = current_cred();
+ old_fsgid = from_kgid_munged(old->user_ns, old->fsgid);
+
+ kgid = make_kgid(old->user_ns, gid);
+ if (!gid_valid(kgid))
+ return old_fsgid;
new = prepare_creds();
if (!new)
- return current_fsgid();
- old = current_cred();
- old_fsgid = old->fsgid;
+ return old_fsgid;
- if (gid == old->gid || gid == old->egid ||
- gid == old->sgid || gid == old->fsgid ||
+ if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->egid) ||
+ gid_eq(kgid, old->sgid) || gid_eq(kgid, old->fsgid) ||
nsown_capable(CAP_SETGID)) {
- if (gid != old_fsgid) {
- new->fsgid = gid;
+ if (!gid_eq(kgid, old->fsgid)) {
+ new->fsgid = kgid;
goto change_okay;
}
}
@@ -1498,15 +1581,14 @@ static int check_prlimit_permission(struct task_struct *task)
return 0;
tcred = __task_cred(task);
- if (cred->user->user_ns == tcred->user->user_ns &&
- (cred->uid == tcred->euid &&
- cred->uid == tcred->suid &&
- cred->uid == tcred->uid &&
- cred->gid == tcred->egid &&
- cred->gid == tcred->sgid &&
- cred->gid == tcred->gid))
+ if (uid_eq(cred->uid, tcred->euid) &&
+ uid_eq(cred->uid, tcred->suid) &&
+ uid_eq(cred->uid, tcred->uid) &&
+ gid_eq(cred->gid, tcred->egid) &&
+ gid_eq(cred->gid, tcred->sgid) &&
+ gid_eq(cred->gid, tcred->gid))
return 0;
- if (ns_capable(tcred->user->user_ns, CAP_SYS_RESOURCE))
+ if (ns_capable(tcred->user_ns, CAP_SYS_RESOURCE))
return 0;
return -EPERM;
diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig
index a20dc8a3c949..fd42bd452b75 100644
--- a/kernel/time/Kconfig
+++ b/kernel/time/Kconfig
@@ -2,6 +2,55 @@
# Timer subsystem related configuration options
#
+# Options selectable by arch Kconfig
+
+# Watchdog function for clocksources to detect instabilities
+config CLOCKSOURCE_WATCHDOG
+ bool
+
+# Architecture has extra clocksource data
+config ARCH_CLOCKSOURCE_DATA
+ bool
+
+# Timekeeping vsyscall support
+config GENERIC_TIME_VSYSCALL
+ bool
+
+# ktime_t scalar 64bit nsec representation
+config KTIME_SCALAR
+ bool
+
+# Old style timekeeping
+config ARCH_USES_GETTIMEOFFSET
+ bool
+
+# The generic clock events infrastructure
+config GENERIC_CLOCKEVENTS
+ bool
+
+# Migration helper. Builds, but does not invoke
+config GENERIC_CLOCKEVENTS_BUILD
+ bool
+ default y
+ depends on GENERIC_CLOCKEVENTS
+
+# Clockevents broadcasting infrastructure
+config GENERIC_CLOCKEVENTS_BROADCAST
+ bool
+ depends on GENERIC_CLOCKEVENTS
+
+# Automatically adjust the min. reprogramming time for
+# clock event device
+config GENERIC_CLOCKEVENTS_MIN_ADJUST
+ bool
+
+# Generic update of CMOS clock
+config GENERIC_CMOS_UPDATE
+ bool
+
+if GENERIC_CLOCKEVENTS
+menu "Timers subsystem"
+
# Core internal switch. Selected by NO_HZ / HIGH_RES_TIMERS. This is
# only related to the tick functionality. Oneshot clockevent devices
# are supported independ of this.
@@ -26,10 +75,5 @@ config HIGH_RES_TIMERS
hardware is not capable then this option only increases
the size of the kernel image.
-config GENERIC_CLOCKEVENTS_BUILD
- bool
- default y
- depends on GENERIC_CLOCKEVENTS
-
-config GENERIC_CLOCKEVENTS_MIN_ADJUST
- bool
+endmenu
+endif
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c
index 8a538c55fc7b..aa27d391bfc8 100644
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -59,7 +59,7 @@ static DEFINE_SPINLOCK(rtcdev_lock);
* If one has not already been chosen, it checks to see if a
* functional rtc device is available.
*/
-static struct rtc_device *alarmtimer_get_rtcdev(void)
+struct rtc_device *alarmtimer_get_rtcdev(void)
{
unsigned long flags;
struct rtc_device *ret;
@@ -115,7 +115,7 @@ static void alarmtimer_rtc_interface_remove(void)
class_interface_unregister(&alarmtimer_rtc_interface);
}
#else
-static inline struct rtc_device *alarmtimer_get_rtcdev(void)
+struct rtc_device *alarmtimer_get_rtcdev(void)
{
return NULL;
}
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index f03fd83b170b..70b33abcc7bb 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -412,6 +412,7 @@ int second_overflow(unsigned long secs)
if (secs % 86400 == 0) {
leap = -1;
time_state = TIME_OOP;
+ time_tai++;
printk(KERN_NOTICE
"Clock: inserting leap second 23:59:60 UTC\n");
}
@@ -426,7 +427,6 @@ int second_overflow(unsigned long secs)
}
break;
case TIME_OOP:
- time_tai++;
time_state = TIME_WAIT;
break;
@@ -473,8 +473,6 @@ int second_overflow(unsigned long secs)
<< NTP_SCALE_SHIFT;
time_adjust = 0;
-
-
out:
spin_unlock_irqrestore(&ntp_lock, flags);
@@ -559,10 +557,10 @@ static inline void process_adj_status(struct timex *txc, struct timespec *ts)
/* only set allowed bits */
time_status &= STA_RONLY;
time_status |= txc->status & ~STA_RONLY;
-
}
+
/*
- * Called with the xtime lock held, so we can access and modify
+ * Called with ntp_lock held, so we can access and modify
* all the global NTP state:
*/
static inline void process_adjtimex_modes(struct timex *txc, struct timespec *ts)
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index d66b21308f7c..6e46cacf5969 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -240,7 +240,6 @@ void getnstimeofday(struct timespec *ts)
timespec_add_ns(ts, nsecs);
}
-
EXPORT_SYMBOL(getnstimeofday);
ktime_t ktime_get(void)
@@ -357,8 +356,8 @@ void do_gettimeofday(struct timeval *tv)
tv->tv_sec = now.tv_sec;
tv->tv_usec = now.tv_nsec/1000;
}
-
EXPORT_SYMBOL(do_gettimeofday);
+
/**
* do_settimeofday - Sets the time of day
* @tv: pointer to the timespec variable containing the new time
@@ -392,7 +391,6 @@ int do_settimeofday(const struct timespec *tv)
return 0;
}
-
EXPORT_SYMBOL(do_settimeofday);
diff --git a/kernel/timer.c b/kernel/timer.c
index 837c552fe838..6ec7e7e0db43 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -1108,7 +1108,9 @@ static void call_timer_fn(struct timer_list *timer, void (*fn)(unsigned long),
* warnings as well as problems when looking into
* timer->lockdep_map, make a copy and use that here.
*/
- struct lockdep_map lockdep_map = timer->lockdep_map;
+ struct lockdep_map lockdep_map;
+
+ lockdep_copy_map(&lockdep_map, &timer->lockdep_map);
#endif
/*
* Couple the lock chain with the lock chain at
@@ -1433,25 +1435,25 @@ SYSCALL_DEFINE0(getppid)
SYSCALL_DEFINE0(getuid)
{
/* Only we change this so SMP safe */
- return current_uid();
+ return from_kuid_munged(current_user_ns(), current_uid());
}
SYSCALL_DEFINE0(geteuid)
{
/* Only we change this so SMP safe */
- return current_euid();
+ return from_kuid_munged(current_user_ns(), current_euid());
}
SYSCALL_DEFINE0(getgid)
{
/* Only we change this so SMP safe */
- return current_gid();
+ return from_kgid_munged(current_user_ns(), current_gid());
}
SYSCALL_DEFINE0(getegid)
{
/* Only we change this so SMP safe */
- return current_egid();
+ return from_kgid_munged(current_user_ns(), current_egid());
}
#endif
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index a1d2849f2473..8c4c07071cc5 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -141,7 +141,6 @@ if FTRACE
config FUNCTION_TRACER
bool "Kernel Function Tracer"
depends on HAVE_FUNCTION_TRACER
- select FRAME_POINTER if !ARM_UNWIND && !PPC && !S390 && !MICROBLAZE
select KALLSYMS
select GENERIC_TRACER
select CONTEXT_SWITCH_TRACER
@@ -272,7 +271,7 @@ config PROFILE_ANNOTATED_BRANCHES
bool "Trace likely/unlikely profiler"
select TRACE_BRANCH_PROFILING
help
- This tracer profiles all the the likely and unlikely macros
+ This tracer profiles all likely and unlikely macros
in the kernel. It will display the results in:
/sys/kernel/debug/tracing/trace_stat/branch_annotated
@@ -373,6 +372,7 @@ config KPROBE_EVENT
depends on HAVE_REGS_AND_STACK_ACCESS_API
bool "Enable kprobes-based dynamic events"
select TRACING
+ select PROBE_EVENTS
default y
help
This allows the user to add tracing events (similar to tracepoints)
@@ -385,6 +385,25 @@ config KPROBE_EVENT
This option is also required by perf-probe subcommand of perf tools.
If you want to use perf tools, this option is strongly recommended.
+config UPROBE_EVENT
+ bool "Enable uprobes-based dynamic events"
+ depends on ARCH_SUPPORTS_UPROBES
+ depends on MMU
+ select UPROBES
+ select PROBE_EVENTS
+ select TRACING
+ default n
+ help
+ This allows the user to add tracing events on top of userspace
+ dynamic events (similar to tracepoints) on the fly via the trace
+ events interface. Those events can be inserted wherever uprobes
+ can probe, and record various registers.
+ This option is required if you plan to use perf-probe subcommand
+ of perf tools on user space applications.
+
+config PROBE_EVENTS
+ def_bool n
+
config DYNAMIC_FTRACE
bool "enable/disable ftrace tracepoints dynamically"
depends on FUNCTION_TRACER
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index 5f39a07fe5ea..b831087c8200 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -41,7 +41,6 @@ obj-$(CONFIG_STACK_TRACER) += trace_stack.o
obj-$(CONFIG_MMIOTRACE) += trace_mmiotrace.o
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += trace_functions_graph.o
obj-$(CONFIG_TRACE_BRANCH_PROFILING) += trace_branch.o
-obj-$(CONFIG_WORKQUEUE_TRACER) += trace_workqueue.o
obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o
ifeq ($(CONFIG_BLOCK),y)
obj-$(CONFIG_EVENT_TRACING) += blktrace.o
@@ -61,5 +60,7 @@ endif
ifeq ($(CONFIG_TRACING),y)
obj-$(CONFIG_KGDB_KDB) += trace_kdb.o
endif
+obj-$(CONFIG_PROBE_EVENTS) += trace_probe.o
+obj-$(CONFIG_UPROBE_EVENT) += trace_uprobe.o
libftrace-y := ftrace.o
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 0fa92f677c92..a008663d86c8 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1383,44 +1383,73 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip)
static int ftrace_cmp_recs(const void *a, const void *b)
{
- const struct dyn_ftrace *reca = a;
- const struct dyn_ftrace *recb = b;
+ const struct dyn_ftrace *key = a;
+ const struct dyn_ftrace *rec = b;
- if (reca->ip > recb->ip)
- return 1;
- if (reca->ip < recb->ip)
+ if (key->flags < rec->ip)
return -1;
+ if (key->ip >= rec->ip + MCOUNT_INSN_SIZE)
+ return 1;
return 0;
}
-/**
- * ftrace_location - return true if the ip giving is a traced location
- * @ip: the instruction pointer to check
- *
- * Returns 1 if @ip given is a pointer to a ftrace location.
- * That is, the instruction that is either a NOP or call to
- * the function tracer. It checks the ftrace internal tables to
- * determine if the address belongs or not.
- */
-int ftrace_location(unsigned long ip)
+static unsigned long ftrace_location_range(unsigned long start, unsigned long end)
{
struct ftrace_page *pg;
struct dyn_ftrace *rec;
struct dyn_ftrace key;
- key.ip = ip;
+ key.ip = start;
+ key.flags = end; /* overload flags, as it is unsigned long */
for (pg = ftrace_pages_start; pg; pg = pg->next) {
+ if (end < pg->records[0].ip ||
+ start >= (pg->records[pg->index - 1].ip + MCOUNT_INSN_SIZE))
+ continue;
rec = bsearch(&key, pg->records, pg->index,
sizeof(struct dyn_ftrace),
ftrace_cmp_recs);
if (rec)
- return 1;
+ return rec->ip;
}
return 0;
}
+/**
+ * ftrace_location - return true if the ip giving is a traced location
+ * @ip: the instruction pointer to check
+ *
+ * Returns rec->ip if @ip given is a pointer to a ftrace location.
+ * That is, the instruction that is either a NOP or call to
+ * the function tracer. It checks the ftrace internal tables to
+ * determine if the address belongs or not.
+ */
+unsigned long ftrace_location(unsigned long ip)
+{
+ return ftrace_location_range(ip, ip);
+}
+
+/**
+ * ftrace_text_reserved - return true if range contains an ftrace location
+ * @start: start of range to search
+ * @end: end of range to search (inclusive). @end points to the last byte to check.
+ *
+ * Returns 1 if @start and @end contains a ftrace location.
+ * That is, the instruction that is either a NOP or call to
+ * the function tracer. It checks the ftrace internal tables to
+ * determine if the address belongs or not.
+ */
+int ftrace_text_reserved(void *start, void *end)
+{
+ unsigned long ret;
+
+ ret = ftrace_location_range((unsigned long)start,
+ (unsigned long)end);
+
+ return (int)!!ret;
+}
+
static void __ftrace_hash_rec_update(struct ftrace_ops *ops,
int filter_hash,
bool inc)
@@ -1520,35 +1549,6 @@ static void ftrace_hash_rec_enable(struct ftrace_ops *ops,
__ftrace_hash_rec_update(ops, filter_hash, 1);
}
-static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip)
-{
- if (ftrace_pages->index == ftrace_pages->size) {
- /* We should have allocated enough */
- if (WARN_ON(!ftrace_pages->next))
- return NULL;
- ftrace_pages = ftrace_pages->next;
- }
-
- return &ftrace_pages->records[ftrace_pages->index++];
-}
-
-static struct dyn_ftrace *
-ftrace_record_ip(unsigned long ip)
-{
- struct dyn_ftrace *rec;
-
- if (ftrace_disabled)
- return NULL;
-
- rec = ftrace_alloc_dyn_node(ip);
- if (!rec)
- return NULL;
-
- rec->ip = ip;
-
- return rec;
-}
-
static void print_ip_ins(const char *fmt, unsigned char *p)
{
int i;
@@ -1598,21 +1598,6 @@ void ftrace_bug(int failed, unsigned long ip)
}
}
-
-/* Return 1 if the address range is reserved for ftrace */
-int ftrace_text_reserved(void *start, void *end)
-{
- struct dyn_ftrace *rec;
- struct ftrace_page *pg;
-
- do_for_each_ftrace_rec(pg, rec) {
- if (rec->ip <= (unsigned long)end &&
- rec->ip + MCOUNT_INSN_SIZE > (unsigned long)start)
- return 1;
- } while_for_each_ftrace_rec();
- return 0;
-}
-
static int ftrace_check_record(struct dyn_ftrace *rec, int enable, int update)
{
unsigned long flag = 0UL;
@@ -1698,7 +1683,7 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable)
return -1; /* unknow ftrace bug */
}
-static void ftrace_replace_code(int update)
+void __weak ftrace_replace_code(int enable)
{
struct dyn_ftrace *rec;
struct ftrace_page *pg;
@@ -1708,7 +1693,7 @@ static void ftrace_replace_code(int update)
return;
do_for_each_ftrace_rec(pg, rec) {
- failed = __ftrace_replace_code(rec, update);
+ failed = __ftrace_replace_code(rec, enable);
if (failed) {
ftrace_bug(failed, rec->ip);
/* Stop processing */
@@ -1826,22 +1811,27 @@ int __weak ftrace_arch_code_modify_post_process(void)
return 0;
}
-static int __ftrace_modify_code(void *data)
+void ftrace_modify_all_code(int command)
{
- int *command = data;
-
- if (*command & FTRACE_UPDATE_CALLS)
+ if (command & FTRACE_UPDATE_CALLS)
ftrace_replace_code(1);
- else if (*command & FTRACE_DISABLE_CALLS)
+ else if (command & FTRACE_DISABLE_CALLS)
ftrace_replace_code(0);
- if (*command & FTRACE_UPDATE_TRACE_FUNC)
+ if (command & FTRACE_UPDATE_TRACE_FUNC)
ftrace_update_ftrace_func(ftrace_trace_function);
- if (*command & FTRACE_START_FUNC_RET)
+ if (command & FTRACE_START_FUNC_RET)
ftrace_enable_ftrace_graph_caller();
- else if (*command & FTRACE_STOP_FUNC_RET)
+ else if (command & FTRACE_STOP_FUNC_RET)
ftrace_disable_ftrace_graph_caller();
+}
+
+static int __ftrace_modify_code(void *data)
+{
+ int *command = data;
+
+ ftrace_modify_all_code(*command);
return 0;
}
@@ -2469,57 +2459,35 @@ static int
ftrace_avail_open(struct inode *inode, struct file *file)
{
struct ftrace_iterator *iter;
- int ret;
if (unlikely(ftrace_disabled))
return -ENODEV;
- iter = kzalloc(sizeof(*iter), GFP_KERNEL);
- if (!iter)
- return -ENOMEM;
-
- iter->pg = ftrace_pages_start;
- iter->ops = &global_ops;
-
- ret = seq_open(file, &show_ftrace_seq_ops);
- if (!ret) {
- struct seq_file *m = file->private_data;
-
- m->private = iter;
- } else {
- kfree(iter);
+ iter = __seq_open_private(file, &show_ftrace_seq_ops, sizeof(*iter));
+ if (iter) {
+ iter->pg = ftrace_pages_start;
+ iter->ops = &global_ops;
}
- return ret;
+ return iter ? 0 : -ENOMEM;
}
static int
ftrace_enabled_open(struct inode *inode, struct file *file)
{
struct ftrace_iterator *iter;
- int ret;
if (unlikely(ftrace_disabled))
return -ENODEV;
- iter = kzalloc(sizeof(*iter), GFP_KERNEL);
- if (!iter)
- return -ENOMEM;
-
- iter->pg = ftrace_pages_start;
- iter->flags = FTRACE_ITER_ENABLED;
- iter->ops = &global_ops;
-
- ret = seq_open(file, &show_ftrace_seq_ops);
- if (!ret) {
- struct seq_file *m = file->private_data;
-
- m->private = iter;
- } else {
- kfree(iter);
+ iter = __seq_open_private(file, &show_ftrace_seq_ops, sizeof(*iter));
+ if (iter) {
+ iter->pg = ftrace_pages_start;
+ iter->flags = FTRACE_ITER_ENABLED;
+ iter->ops = &global_ops;
}
- return ret;
+ return iter ? 0 : -ENOMEM;
}
static void ftrace_filter_reset(struct ftrace_hash *hash)
@@ -3688,22 +3656,36 @@ static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer)
return 0;
}
-static void ftrace_swap_recs(void *a, void *b, int size)
+static int ftrace_cmp_ips(const void *a, const void *b)
+{
+ const unsigned long *ipa = a;
+ const unsigned long *ipb = b;
+
+ if (*ipa > *ipb)
+ return 1;
+ if (*ipa < *ipb)
+ return -1;
+ return 0;
+}
+
+static void ftrace_swap_ips(void *a, void *b, int size)
{
- struct dyn_ftrace *reca = a;
- struct dyn_ftrace *recb = b;
- struct dyn_ftrace t;
+ unsigned long *ipa = a;
+ unsigned long *ipb = b;
+ unsigned long t;
- t = *reca;
- *reca = *recb;
- *recb = t;
+ t = *ipa;
+ *ipa = *ipb;
+ *ipb = t;
}
static int ftrace_process_locs(struct module *mod,
unsigned long *start,
unsigned long *end)
{
+ struct ftrace_page *start_pg;
struct ftrace_page *pg;
+ struct dyn_ftrace *rec;
unsigned long count;
unsigned long *p;
unsigned long addr;
@@ -3715,8 +3697,11 @@ static int ftrace_process_locs(struct module *mod,
if (!count)
return 0;
- pg = ftrace_allocate_pages(count);
- if (!pg)
+ sort(start, count, sizeof(*start),
+ ftrace_cmp_ips, ftrace_swap_ips);
+
+ start_pg = ftrace_allocate_pages(count);
+ if (!start_pg)
return -ENOMEM;
mutex_lock(&ftrace_lock);
@@ -3729,7 +3714,7 @@ static int ftrace_process_locs(struct module *mod,
if (!mod) {
WARN_ON(ftrace_pages || ftrace_pages_start);
/* First initialization */
- ftrace_pages = ftrace_pages_start = pg;
+ ftrace_pages = ftrace_pages_start = start_pg;
} else {
if (!ftrace_pages)
goto out;
@@ -3740,11 +3725,11 @@ static int ftrace_process_locs(struct module *mod,
ftrace_pages = ftrace_pages->next;
}
- ftrace_pages->next = pg;
- ftrace_pages = pg;
+ ftrace_pages->next = start_pg;
}
p = start;
+ pg = start_pg;
while (p < end) {
addr = ftrace_call_adjust(*p++);
/*
@@ -3755,17 +3740,26 @@ static int ftrace_process_locs(struct module *mod,
*/
if (!addr)
continue;
- if (!ftrace_record_ip(addr))
- break;
+
+ if (pg->index == pg->size) {
+ /* We should have allocated enough */
+ if (WARN_ON(!pg->next))
+ break;
+ pg = pg->next;
+ }
+
+ rec = &pg->records[pg->index++];
+ rec->ip = addr;
}
- /* These new locations need to be initialized */
- ftrace_new_pgs = pg;
+ /* We should have used all pages */
+ WARN_ON(pg->next);
+
+ /* Assign the last page to ftrace_pages */
+ ftrace_pages = pg;
- /* Make each individual set of pages sorted by ips */
- for (; pg; pg = pg->next)
- sort(pg->records, pg->index, sizeof(struct dyn_ftrace),
- ftrace_cmp_recs, ftrace_swap_recs);
+ /* These new locations need to be initialized */
+ ftrace_new_pgs = start_pg;
/*
* We only need to disable interrupts on start up
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index cf8d11e91efd..6420cda62336 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -23,6 +23,8 @@
#include <asm/local.h>
#include "trace.h"
+static void update_pages_handler(struct work_struct *work);
+
/*
* The ring buffer header is special. We must manually up keep it.
*/
@@ -449,6 +451,7 @@ struct ring_buffer_per_cpu {
raw_spinlock_t reader_lock; /* serialize readers */
arch_spinlock_t lock;
struct lock_class_key lock_key;
+ unsigned int nr_pages;
struct list_head *pages;
struct buffer_page *head_page; /* read from head */
struct buffer_page *tail_page; /* write to tail */
@@ -466,13 +469,18 @@ struct ring_buffer_per_cpu {
unsigned long read_bytes;
u64 write_stamp;
u64 read_stamp;
+ /* ring buffer pages to update, > 0 to add, < 0 to remove */
+ int nr_pages_to_update;
+ struct list_head new_pages; /* new pages to add */
+ struct work_struct update_pages_work;
+ struct completion update_done;
};
struct ring_buffer {
- unsigned pages;
unsigned flags;
int cpus;
atomic_t record_disabled;
+ atomic_t resize_disabled;
cpumask_var_t cpumask;
struct lock_class_key *reader_lock_key;
@@ -937,6 +945,10 @@ static int rb_check_pages(struct ring_buffer_per_cpu *cpu_buffer)
struct list_head *head = cpu_buffer->pages;
struct buffer_page *bpage, *tmp;
+ /* Reset the head page if it exists */
+ if (cpu_buffer->head_page)
+ rb_set_head_page(cpu_buffer);
+
rb_head_page_deactivate(cpu_buffer);
if (RB_WARN_ON(cpu_buffer, head->next->prev != head))
@@ -963,14 +975,10 @@ static int rb_check_pages(struct ring_buffer_per_cpu *cpu_buffer)
return 0;
}
-static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
- unsigned nr_pages)
+static int __rb_allocate_pages(int nr_pages, struct list_head *pages, int cpu)
{
+ int i;
struct buffer_page *bpage, *tmp;
- LIST_HEAD(pages);
- unsigned i;
-
- WARN_ON(!nr_pages);
for (i = 0; i < nr_pages; i++) {
struct page *page;
@@ -981,15 +989,13 @@ static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
*/
bpage = kzalloc_node(ALIGN(sizeof(*bpage), cache_line_size()),
GFP_KERNEL | __GFP_NORETRY,
- cpu_to_node(cpu_buffer->cpu));
+ cpu_to_node(cpu));
if (!bpage)
goto free_pages;
- rb_check_bpage(cpu_buffer, bpage);
+ list_add(&bpage->list, pages);
- list_add(&bpage->list, &pages);
-
- page = alloc_pages_node(cpu_to_node(cpu_buffer->cpu),
+ page = alloc_pages_node(cpu_to_node(cpu),
GFP_KERNEL | __GFP_NORETRY, 0);
if (!page)
goto free_pages;
@@ -997,6 +1003,27 @@ static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
rb_init_page(bpage->page);
}
+ return 0;
+
+free_pages:
+ list_for_each_entry_safe(bpage, tmp, pages, list) {
+ list_del_init(&bpage->list);
+ free_buffer_page(bpage);
+ }
+
+ return -ENOMEM;
+}
+
+static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
+ unsigned nr_pages)
+{
+ LIST_HEAD(pages);
+
+ WARN_ON(!nr_pages);
+
+ if (__rb_allocate_pages(nr_pages, &pages, cpu_buffer->cpu))
+ return -ENOMEM;
+
/*
* The ring buffer page list is a circular list that does not
* start and end with a list head. All page list items point to
@@ -1005,20 +1032,15 @@ static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
cpu_buffer->pages = pages.next;
list_del(&pages);
+ cpu_buffer->nr_pages = nr_pages;
+
rb_check_pages(cpu_buffer);
return 0;
-
- free_pages:
- list_for_each_entry_safe(bpage, tmp, &pages, list) {
- list_del_init(&bpage->list);
- free_buffer_page(bpage);
- }
- return -ENOMEM;
}
static struct ring_buffer_per_cpu *
-rb_allocate_cpu_buffer(struct ring_buffer *buffer, int cpu)
+rb_allocate_cpu_buffer(struct ring_buffer *buffer, int nr_pages, int cpu)
{
struct ring_buffer_per_cpu *cpu_buffer;
struct buffer_page *bpage;
@@ -1035,6 +1057,8 @@ rb_allocate_cpu_buffer(struct ring_buffer *buffer, int cpu)
raw_spin_lock_init(&cpu_buffer->reader_lock);
lockdep_set_class(&cpu_buffer->reader_lock, buffer->reader_lock_key);
cpu_buffer->lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
+ INIT_WORK(&cpu_buffer->update_pages_work, update_pages_handler);
+ init_completion(&cpu_buffer->update_done);
bpage = kzalloc_node(ALIGN(sizeof(*bpage), cache_line_size()),
GFP_KERNEL, cpu_to_node(cpu));
@@ -1052,7 +1076,7 @@ rb_allocate_cpu_buffer(struct ring_buffer *buffer, int cpu)
INIT_LIST_HEAD(&cpu_buffer->reader_page->list);
- ret = rb_allocate_pages(cpu_buffer, buffer->pages);
+ ret = rb_allocate_pages(cpu_buffer, nr_pages);
if (ret < 0)
goto fail_free_reader;
@@ -1113,7 +1137,7 @@ struct ring_buffer *__ring_buffer_alloc(unsigned long size, unsigned flags,
{
struct ring_buffer *buffer;
int bsize;
- int cpu;
+ int cpu, nr_pages;
/* keep it in its own cache line */
buffer = kzalloc(ALIGN(sizeof(*buffer), cache_line_size()),
@@ -1124,14 +1148,14 @@ struct ring_buffer *__ring_buffer_alloc(unsigned long size, unsigned flags,
if (!alloc_cpumask_var(&buffer->cpumask, GFP_KERNEL))
goto fail_free_buffer;
- buffer->pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
+ nr_pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
buffer->flags = flags;
buffer->clock = trace_clock_local;
buffer->reader_lock_key = key;
/* need at least two pages */
- if (buffer->pages < 2)
- buffer->pages = 2;
+ if (nr_pages < 2)
+ nr_pages = 2;
/*
* In case of non-hotplug cpu, if the ring-buffer is allocated
@@ -1154,7 +1178,7 @@ struct ring_buffer *__ring_buffer_alloc(unsigned long size, unsigned flags,
for_each_buffer_cpu(buffer, cpu) {
buffer->buffers[cpu] =
- rb_allocate_cpu_buffer(buffer, cpu);
+ rb_allocate_cpu_buffer(buffer, nr_pages, cpu);
if (!buffer->buffers[cpu])
goto fail_free_buffers;
}
@@ -1222,58 +1246,222 @@ void ring_buffer_set_clock(struct ring_buffer *buffer,
static void rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer);
-static void
-rb_remove_pages(struct ring_buffer_per_cpu *cpu_buffer, unsigned nr_pages)
+static inline unsigned long rb_page_entries(struct buffer_page *bpage)
{
- struct buffer_page *bpage;
- struct list_head *p;
- unsigned i;
+ return local_read(&bpage->entries) & RB_WRITE_MASK;
+}
+
+static inline unsigned long rb_page_write(struct buffer_page *bpage)
+{
+ return local_read(&bpage->write) & RB_WRITE_MASK;
+}
+
+static int
+rb_remove_pages(struct ring_buffer_per_cpu *cpu_buffer, unsigned int nr_pages)
+{
+ struct list_head *tail_page, *to_remove, *next_page;
+ struct buffer_page *to_remove_page, *tmp_iter_page;
+ struct buffer_page *last_page, *first_page;
+ unsigned int nr_removed;
+ unsigned long head_bit;
+ int page_entries;
+
+ head_bit = 0;
raw_spin_lock_irq(&cpu_buffer->reader_lock);
- rb_head_page_deactivate(cpu_buffer);
+ atomic_inc(&cpu_buffer->record_disabled);
+ /*
+ * We don't race with the readers since we have acquired the reader
+ * lock. We also don't race with writers after disabling recording.
+ * This makes it easy to figure out the first and the last page to be
+ * removed from the list. We unlink all the pages in between including
+ * the first and last pages. This is done in a busy loop so that we
+ * lose the least number of traces.
+ * The pages are freed after we restart recording and unlock readers.
+ */
+ tail_page = &cpu_buffer->tail_page->list;
- for (i = 0; i < nr_pages; i++) {
- if (RB_WARN_ON(cpu_buffer, list_empty(cpu_buffer->pages)))
- goto out;
- p = cpu_buffer->pages->next;
- bpage = list_entry(p, struct buffer_page, list);
- list_del_init(&bpage->list);
- free_buffer_page(bpage);
+ /*
+ * tail page might be on reader page, we remove the next page
+ * from the ring buffer
+ */
+ if (cpu_buffer->tail_page == cpu_buffer->reader_page)
+ tail_page = rb_list_head(tail_page->next);
+ to_remove = tail_page;
+
+ /* start of pages to remove */
+ first_page = list_entry(rb_list_head(to_remove->next),
+ struct buffer_page, list);
+
+ for (nr_removed = 0; nr_removed < nr_pages; nr_removed++) {
+ to_remove = rb_list_head(to_remove)->next;
+ head_bit |= (unsigned long)to_remove & RB_PAGE_HEAD;
}
- if (RB_WARN_ON(cpu_buffer, list_empty(cpu_buffer->pages)))
- goto out;
- rb_reset_cpu(cpu_buffer);
- rb_check_pages(cpu_buffer);
+ next_page = rb_list_head(to_remove)->next;
-out:
+ /*
+ * Now we remove all pages between tail_page and next_page.
+ * Make sure that we have head_bit value preserved for the
+ * next page
+ */
+ tail_page->next = (struct list_head *)((unsigned long)next_page |
+ head_bit);
+ next_page = rb_list_head(next_page);
+ next_page->prev = tail_page;
+
+ /* make sure pages points to a valid page in the ring buffer */
+ cpu_buffer->pages = next_page;
+
+ /* update head page */
+ if (head_bit)
+ cpu_buffer->head_page = list_entry(next_page,
+ struct buffer_page, list);
+
+ /*
+ * change read pointer to make sure any read iterators reset
+ * themselves
+ */
+ cpu_buffer->read = 0;
+
+ /* pages are removed, resume tracing and then free the pages */
+ atomic_dec(&cpu_buffer->record_disabled);
raw_spin_unlock_irq(&cpu_buffer->reader_lock);
+
+ RB_WARN_ON(cpu_buffer, list_empty(cpu_buffer->pages));
+
+ /* last buffer page to remove */
+ last_page = list_entry(rb_list_head(to_remove), struct buffer_page,
+ list);
+ tmp_iter_page = first_page;
+
+ do {
+ to_remove_page = tmp_iter_page;
+ rb_inc_page(cpu_buffer, &tmp_iter_page);
+
+ /* update the counters */
+ page_entries = rb_page_entries(to_remove_page);
+ if (page_entries) {
+ /*
+ * If something was added to this page, it was full
+ * since it is not the tail page. So we deduct the
+ * bytes consumed in ring buffer from here.
+ * No need to update overruns, since this page is
+ * deleted from ring buffer and its entries are
+ * already accounted for.
+ */
+ local_sub(BUF_PAGE_SIZE, &cpu_buffer->entries_bytes);
+ }
+
+ /*
+ * We have already removed references to this list item, just
+ * free up the buffer_page and its page
+ */
+ free_buffer_page(to_remove_page);
+ nr_removed--;
+
+ } while (to_remove_page != last_page);
+
+ RB_WARN_ON(cpu_buffer, nr_removed);
+
+ return nr_removed == 0;
}
-static void
-rb_insert_pages(struct ring_buffer_per_cpu *cpu_buffer,
- struct list_head *pages, unsigned nr_pages)
+static int
+rb_insert_pages(struct ring_buffer_per_cpu *cpu_buffer)
{
- struct buffer_page *bpage;
- struct list_head *p;
- unsigned i;
+ struct list_head *pages = &cpu_buffer->new_pages;
+ int retries, success;
raw_spin_lock_irq(&cpu_buffer->reader_lock);
- rb_head_page_deactivate(cpu_buffer);
+ /*
+ * We are holding the reader lock, so the reader page won't be swapped
+ * in the ring buffer. Now we are racing with the writer trying to
+ * move head page and the tail page.
+ * We are going to adapt the reader page update process where:
+ * 1. We first splice the start and end of list of new pages between
+ * the head page and its previous page.
+ * 2. We cmpxchg the prev_page->next to point from head page to the
+ * start of new pages list.
+ * 3. Finally, we update the head->prev to the end of new list.
+ *
+ * We will try this process 10 times, to make sure that we don't keep
+ * spinning.
+ */
+ retries = 10;
+ success = 0;
+ while (retries--) {
+ struct list_head *head_page, *prev_page, *r;
+ struct list_head *last_page, *first_page;
+ struct list_head *head_page_with_bit;
- for (i = 0; i < nr_pages; i++) {
- if (RB_WARN_ON(cpu_buffer, list_empty(pages)))
- goto out;
- p = pages->next;
- bpage = list_entry(p, struct buffer_page, list);
- list_del_init(&bpage->list);
- list_add_tail(&bpage->list, cpu_buffer->pages);
+ head_page = &rb_set_head_page(cpu_buffer)->list;
+ prev_page = head_page->prev;
+
+ first_page = pages->next;
+ last_page = pages->prev;
+
+ head_page_with_bit = (struct list_head *)
+ ((unsigned long)head_page | RB_PAGE_HEAD);
+
+ last_page->next = head_page_with_bit;
+ first_page->prev = prev_page;
+
+ r = cmpxchg(&prev_page->next, head_page_with_bit, first_page);
+
+ if (r == head_page_with_bit) {
+ /*
+ * yay, we replaced the page pointer to our new list,
+ * now, we just have to update to head page's prev
+ * pointer to point to end of list
+ */
+ head_page->prev = last_page;
+ success = 1;
+ break;
+ }
}
- rb_reset_cpu(cpu_buffer);
- rb_check_pages(cpu_buffer);
-out:
+ if (success)
+ INIT_LIST_HEAD(pages);
+ /*
+ * If we weren't successful in adding in new pages, warn and stop
+ * tracing
+ */
+ RB_WARN_ON(cpu_buffer, !success);
raw_spin_unlock_irq(&cpu_buffer->reader_lock);
+
+ /* free pages if they weren't inserted */
+ if (!success) {
+ struct buffer_page *bpage, *tmp;
+ list_for_each_entry_safe(bpage, tmp, &cpu_buffer->new_pages,
+ list) {
+ list_del_init(&bpage->list);
+ free_buffer_page(bpage);
+ }
+ }
+ return success;
+}
+
+static void rb_update_pages(struct ring_buffer_per_cpu *cpu_buffer)
+{
+ int success;
+
+ if (cpu_buffer->nr_pages_to_update > 0)
+ success = rb_insert_pages(cpu_buffer);
+ else
+ success = rb_remove_pages(cpu_buffer,
+ -cpu_buffer->nr_pages_to_update);
+
+ if (success)
+ cpu_buffer->nr_pages += cpu_buffer->nr_pages_to_update;
+}
+
+static void update_pages_handler(struct work_struct *work)
+{
+ struct ring_buffer_per_cpu *cpu_buffer = container_of(work,
+ struct ring_buffer_per_cpu, update_pages_work);
+ rb_update_pages(cpu_buffer);
+ complete(&cpu_buffer->update_done);
}
/**
@@ -1283,16 +1471,14 @@ out:
*
* Minimum size is 2 * BUF_PAGE_SIZE.
*
- * Returns -1 on failure.
+ * Returns 0 on success and < 0 on failure.
*/
-int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size)
+int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size,
+ int cpu_id)
{
struct ring_buffer_per_cpu *cpu_buffer;
- unsigned nr_pages, rm_pages, new_pages;
- struct buffer_page *bpage, *tmp;
- unsigned long buffer_size;
- LIST_HEAD(pages);
- int i, cpu;
+ unsigned nr_pages;
+ int cpu, err = 0;
/*
* Always succeed at resizing a non-existent buffer:
@@ -1302,113 +1488,154 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size)
size = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
size *= BUF_PAGE_SIZE;
- buffer_size = buffer->pages * BUF_PAGE_SIZE;
/* we need a minimum of two pages */
if (size < BUF_PAGE_SIZE * 2)
size = BUF_PAGE_SIZE * 2;
- if (size == buffer_size)
- return size;
-
- atomic_inc(&buffer->record_disabled);
+ nr_pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
- /* Make sure all writers are done with this buffer. */
- synchronize_sched();
+ /*
+ * Don't succeed if resizing is disabled, as a reader might be
+ * manipulating the ring buffer and is expecting a sane state while
+ * this is true.
+ */
+ if (atomic_read(&buffer->resize_disabled))
+ return -EBUSY;
+ /* prevent another thread from changing buffer sizes */
mutex_lock(&buffer->mutex);
- get_online_cpus();
-
- nr_pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
- if (size < buffer_size) {
+ if (cpu_id == RING_BUFFER_ALL_CPUS) {
+ /* calculate the pages to update */
+ for_each_buffer_cpu(buffer, cpu) {
+ cpu_buffer = buffer->buffers[cpu];
- /* easy case, just free pages */
- if (RB_WARN_ON(buffer, nr_pages >= buffer->pages))
- goto out_fail;
+ cpu_buffer->nr_pages_to_update = nr_pages -
+ cpu_buffer->nr_pages;
+ /*
+ * nothing more to do for removing pages or no update
+ */
+ if (cpu_buffer->nr_pages_to_update <= 0)
+ continue;
+ /*
+ * to add pages, make sure all new pages can be
+ * allocated without receiving ENOMEM
+ */
+ INIT_LIST_HEAD(&cpu_buffer->new_pages);
+ if (__rb_allocate_pages(cpu_buffer->nr_pages_to_update,
+ &cpu_buffer->new_pages, cpu)) {
+ /* not enough memory for new pages */
+ err = -ENOMEM;
+ goto out_err;
+ }
+ }
- rm_pages = buffer->pages - nr_pages;
+ get_online_cpus();
+ /*
+ * Fire off all the required work handlers
+ * We can't schedule on offline CPUs, but it's not necessary
+ * since we can change their buffer sizes without any race.
+ */
+ for_each_buffer_cpu(buffer, cpu) {
+ cpu_buffer = buffer->buffers[cpu];
+ if (!cpu_buffer->nr_pages_to_update)
+ continue;
+
+ if (cpu_online(cpu))
+ schedule_work_on(cpu,
+ &cpu_buffer->update_pages_work);
+ else
+ rb_update_pages(cpu_buffer);
+ }
+ /* wait for all the updates to complete */
for_each_buffer_cpu(buffer, cpu) {
cpu_buffer = buffer->buffers[cpu];
- rb_remove_pages(cpu_buffer, rm_pages);
+ if (!cpu_buffer->nr_pages_to_update)
+ continue;
+
+ if (cpu_online(cpu))
+ wait_for_completion(&cpu_buffer->update_done);
+ cpu_buffer->nr_pages_to_update = 0;
}
- goto out;
- }
- /*
- * This is a bit more difficult. We only want to add pages
- * when we can allocate enough for all CPUs. We do this
- * by allocating all the pages and storing them on a local
- * link list. If we succeed in our allocation, then we
- * add these pages to the cpu_buffers. Otherwise we just free
- * them all and return -ENOMEM;
- */
- if (RB_WARN_ON(buffer, nr_pages <= buffer->pages))
- goto out_fail;
+ put_online_cpus();
+ } else {
+ cpu_buffer = buffer->buffers[cpu_id];
- new_pages = nr_pages - buffer->pages;
+ if (nr_pages == cpu_buffer->nr_pages)
+ goto out;
- for_each_buffer_cpu(buffer, cpu) {
- for (i = 0; i < new_pages; i++) {
- struct page *page;
- /*
- * __GFP_NORETRY flag makes sure that the allocation
- * fails gracefully without invoking oom-killer and
- * the system is not destabilized.
- */
- bpage = kzalloc_node(ALIGN(sizeof(*bpage),
- cache_line_size()),
- GFP_KERNEL | __GFP_NORETRY,
- cpu_to_node(cpu));
- if (!bpage)
- goto free_pages;
- list_add(&bpage->list, &pages);
- page = alloc_pages_node(cpu_to_node(cpu),
- GFP_KERNEL | __GFP_NORETRY, 0);
- if (!page)
- goto free_pages;
- bpage->page = page_address(page);
- rb_init_page(bpage->page);
+ cpu_buffer->nr_pages_to_update = nr_pages -
+ cpu_buffer->nr_pages;
+
+ INIT_LIST_HEAD(&cpu_buffer->new_pages);
+ if (cpu_buffer->nr_pages_to_update > 0 &&
+ __rb_allocate_pages(cpu_buffer->nr_pages_to_update,
+ &cpu_buffer->new_pages, cpu_id)) {
+ err = -ENOMEM;
+ goto out_err;
}
- }
- for_each_buffer_cpu(buffer, cpu) {
- cpu_buffer = buffer->buffers[cpu];
- rb_insert_pages(cpu_buffer, &pages, new_pages);
- }
+ get_online_cpus();
- if (RB_WARN_ON(buffer, !list_empty(&pages)))
- goto out_fail;
+ if (cpu_online(cpu_id)) {
+ schedule_work_on(cpu_id,
+ &cpu_buffer->update_pages_work);
+ wait_for_completion(&cpu_buffer->update_done);
+ } else
+ rb_update_pages(cpu_buffer);
+
+ cpu_buffer->nr_pages_to_update = 0;
+ put_online_cpus();
+ }
out:
- buffer->pages = nr_pages;
- put_online_cpus();
+ /*
+ * The ring buffer resize can happen with the ring buffer
+ * enabled, so that the update disturbs the tracing as little
+ * as possible. But if the buffer is disabled, we do not need
+ * to worry about that, and we can take the time to verify
+ * that the buffer is not corrupt.
+ */
+ if (atomic_read(&buffer->record_disabled)) {
+ atomic_inc(&buffer->record_disabled);
+ /*
+ * Even though the buffer was disabled, we must make sure
+ * that it is truly disabled before calling rb_check_pages.
+ * There could have been a race between checking
+ * record_disable and incrementing it.
+ */
+ synchronize_sched();
+ for_each_buffer_cpu(buffer, cpu) {
+ cpu_buffer = buffer->buffers[cpu];
+ rb_check_pages(cpu_buffer);
+ }
+ atomic_dec(&buffer->record_disabled);
+ }
+
mutex_unlock(&buffer->mutex);
+ return size;
- atomic_dec(&buffer->record_disabled);
+ out_err:
+ for_each_buffer_cpu(buffer, cpu) {
+ struct buffer_page *bpage, *tmp;
- return size;
+ cpu_buffer = buffer->buffers[cpu];
+ cpu_buffer->nr_pages_to_update = 0;
- free_pages:
- list_for_each_entry_safe(bpage, tmp, &pages, list) {
- list_del_init(&bpage->list);
- free_buffer_page(bpage);
- }
- put_online_cpus();
- mutex_unlock(&buffer->mutex);
- atomic_dec(&buffer->record_disabled);
- return -ENOMEM;
+ if (list_empty(&cpu_buffer->new_pages))
+ continue;
- /*
- * Something went totally wrong, and we are too paranoid
- * to even clean up the mess.
- */
- out_fail:
- put_online_cpus();
+ list_for_each_entry_safe(bpage, tmp, &cpu_buffer->new_pages,
+ list) {
+ list_del_init(&bpage->list);
+ free_buffer_page(bpage);
+ }
+ }
mutex_unlock(&buffer->mutex);
- atomic_dec(&buffer->record_disabled);
- return -1;
+ return err;
}
EXPORT_SYMBOL_GPL(ring_buffer_resize);
@@ -1447,21 +1674,11 @@ rb_iter_head_event(struct ring_buffer_iter *iter)
return __rb_page_index(iter->head_page, iter->head);
}
-static inline unsigned long rb_page_write(struct buffer_page *bpage)
-{
- return local_read(&bpage->write) & RB_WRITE_MASK;
-}
-
static inline unsigned rb_page_commit(struct buffer_page *bpage)
{
return local_read(&bpage->page->commit);
}
-static inline unsigned long rb_page_entries(struct buffer_page *bpage)
-{
- return local_read(&bpage->entries) & RB_WRITE_MASK;
-}
-
/* Size is determined by what has been committed */
static inline unsigned rb_page_size(struct buffer_page *bpage)
{
@@ -1510,7 +1727,7 @@ rb_set_commit_to_write(struct ring_buffer_per_cpu *cpu_buffer)
* assign the commit to the tail.
*/
again:
- max_count = cpu_buffer->buffer->pages * 100;
+ max_count = cpu_buffer->nr_pages * 100;
while (cpu_buffer->commit_page != cpu_buffer->tail_page) {
if (RB_WARN_ON(cpu_buffer, !(--max_count)))
@@ -3486,6 +3703,7 @@ ring_buffer_read_prepare(struct ring_buffer *buffer, int cpu)
iter->cpu_buffer = cpu_buffer;
+ atomic_inc(&buffer->resize_disabled);
atomic_inc(&cpu_buffer->record_disabled);
return iter;
@@ -3548,7 +3766,14 @@ ring_buffer_read_finish(struct ring_buffer_iter *iter)
{
struct ring_buffer_per_cpu *cpu_buffer = iter->cpu_buffer;
+ /*
+ * Ring buffer is disabled from recording, here's a good place
+ * to check the integrity of the ring buffer.
+ */
+ rb_check_pages(cpu_buffer);
+
atomic_dec(&cpu_buffer->record_disabled);
+ atomic_dec(&cpu_buffer->buffer->resize_disabled);
kfree(iter);
}
EXPORT_SYMBOL_GPL(ring_buffer_read_finish);
@@ -3588,9 +3813,18 @@ EXPORT_SYMBOL_GPL(ring_buffer_read);
* ring_buffer_size - return the size of the ring buffer (in bytes)
* @buffer: The ring buffer.
*/
-unsigned long ring_buffer_size(struct ring_buffer *buffer)
+unsigned long ring_buffer_size(struct ring_buffer *buffer, int cpu)
{
- return BUF_PAGE_SIZE * buffer->pages;
+ /*
+ * Earlier, this method returned
+ * BUF_PAGE_SIZE * buffer->nr_pages
+ * Since the nr_pages field is now removed, we have converted this to
+ * return the per cpu buffer value.
+ */
+ if (!cpumask_test_cpu(cpu, buffer->cpumask))
+ return 0;
+
+ return BUF_PAGE_SIZE * buffer->buffers[cpu]->nr_pages;
}
EXPORT_SYMBOL_GPL(ring_buffer_size);
@@ -3611,6 +3845,7 @@ rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer)
cpu_buffer->commit_page = cpu_buffer->head_page;
INIT_LIST_HEAD(&cpu_buffer->reader_page->list);
+ INIT_LIST_HEAD(&cpu_buffer->new_pages);
local_set(&cpu_buffer->reader_page->write, 0);
local_set(&cpu_buffer->reader_page->entries, 0);
local_set(&cpu_buffer->reader_page->page->commit, 0);
@@ -3647,8 +3882,12 @@ void ring_buffer_reset_cpu(struct ring_buffer *buffer, int cpu)
if (!cpumask_test_cpu(cpu, buffer->cpumask))
return;
+ atomic_inc(&buffer->resize_disabled);
atomic_inc(&cpu_buffer->record_disabled);
+ /* Make sure all commits have finished */
+ synchronize_sched();
+
raw_spin_lock_irqsave(&cpu_buffer->reader_lock, flags);
if (RB_WARN_ON(cpu_buffer, local_read(&cpu_buffer->committing)))
@@ -3664,6 +3903,7 @@ void ring_buffer_reset_cpu(struct ring_buffer *buffer, int cpu)
raw_spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
atomic_dec(&cpu_buffer->record_disabled);
+ atomic_dec(&buffer->resize_disabled);
}
EXPORT_SYMBOL_GPL(ring_buffer_reset_cpu);
@@ -3765,8 +4005,11 @@ int ring_buffer_swap_cpu(struct ring_buffer *buffer_a,
!cpumask_test_cpu(cpu, buffer_b->cpumask))
goto out;
+ cpu_buffer_a = buffer_a->buffers[cpu];
+ cpu_buffer_b = buffer_b->buffers[cpu];
+
/* At least make sure the two buffers are somewhat the same */
- if (buffer_a->pages != buffer_b->pages)
+ if (cpu_buffer_a->nr_pages != cpu_buffer_b->nr_pages)
goto out;
ret = -EAGAIN;
@@ -3780,9 +4023,6 @@ int ring_buffer_swap_cpu(struct ring_buffer *buffer_a,
if (atomic_read(&buffer_b->record_disabled))
goto out;
- cpu_buffer_a = buffer_a->buffers[cpu];
- cpu_buffer_b = buffer_b->buffers[cpu];
-
if (atomic_read(&cpu_buffer_a->record_disabled))
goto out;
@@ -4071,6 +4311,8 @@ static int rb_cpu_notify(struct notifier_block *self,
struct ring_buffer *buffer =
container_of(self, struct ring_buffer, cpu_notify);
long cpu = (long)hcpu;
+ int cpu_i, nr_pages_same;
+ unsigned int nr_pages;
switch (action) {
case CPU_UP_PREPARE:
@@ -4078,8 +4320,23 @@ static int rb_cpu_notify(struct notifier_block *self,
if (cpumask_test_cpu(cpu, buffer->cpumask))
return NOTIFY_OK;
+ nr_pages = 0;
+ nr_pages_same = 1;
+ /* check if all cpu sizes are same */
+ for_each_buffer_cpu(buffer, cpu_i) {
+ /* fill in the size from first enabled cpu */
+ if (nr_pages == 0)
+ nr_pages = buffer->buffers[cpu_i]->nr_pages;
+ if (nr_pages != buffer->buffers[cpu_i]->nr_pages) {
+ nr_pages_same = 0;
+ break;
+ }
+ }
+ /* allocate minimum pages, user can later expand it */
+ if (!nr_pages_same)
+ nr_pages = 2;
buffer->buffers[cpu] =
- rb_allocate_cpu_buffer(buffer, cpu);
+ rb_allocate_cpu_buffer(buffer, nr_pages, cpu);
if (!buffer->buffers[cpu]) {
WARN(1, "failed to allocate ring buffer on CPU %ld\n",
cpu);
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 2a22255c1010..68032c6177db 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -87,18 +87,6 @@ static int tracing_disabled = 1;
DEFINE_PER_CPU(int, ftrace_cpu_disabled);
-static inline void ftrace_disable_cpu(void)
-{
- preempt_disable();
- __this_cpu_inc(ftrace_cpu_disabled);
-}
-
-static inline void ftrace_enable_cpu(void)
-{
- __this_cpu_dec(ftrace_cpu_disabled);
- preempt_enable();
-}
-
cpumask_var_t __read_mostly tracing_buffer_mask;
/*
@@ -629,7 +617,6 @@ ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf, size_t cnt)
static ssize_t trace_seq_to_buffer(struct trace_seq *s, void *buf, size_t cnt)
{
int len;
- void *ret;
if (s->len <= s->readpos)
return -EBUSY;
@@ -637,9 +624,7 @@ static ssize_t trace_seq_to_buffer(struct trace_seq *s, void *buf, size_t cnt)
len = s->len - s->readpos;
if (cnt > len)
cnt = len;
- ret = memcpy(buf, s->buffer + s->readpos, cnt);
- if (!ret)
- return -EFAULT;
+ memcpy(buf, s->buffer + s->readpos, cnt);
s->readpos += cnt;
return cnt;
@@ -751,8 +736,6 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu)
arch_spin_lock(&ftrace_max_lock);
- ftrace_disable_cpu();
-
ret = ring_buffer_swap_cpu(max_tr.buffer, tr->buffer, cpu);
if (ret == -EBUSY) {
@@ -766,8 +749,6 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu)
"Failed to swap buffers due to commit in progress\n");
}
- ftrace_enable_cpu();
-
WARN_ON_ONCE(ret && ret != -EAGAIN && ret != -EBUSY);
__update_max_tr(tr, tsk, cpu);
@@ -782,8 +763,6 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu)
* Register a new plugin tracer.
*/
int register_tracer(struct tracer *type)
-__releases(kernel_lock)
-__acquires(kernel_lock)
{
struct tracer *t;
int ret = 0;
@@ -841,7 +820,8 @@ __acquires(kernel_lock)
/* If we expanded the buffers, make sure the max is expanded too */
if (ring_buffer_expanded && type->use_max_tr)
- ring_buffer_resize(max_tr.buffer, trace_buf_size);
+ ring_buffer_resize(max_tr.buffer, trace_buf_size,
+ RING_BUFFER_ALL_CPUS);
/* the test is responsible for initializing and enabling */
pr_info("Testing tracer %s: ", type->name);
@@ -857,7 +837,8 @@ __acquires(kernel_lock)
/* Shrink the max buffer again */
if (ring_buffer_expanded && type->use_max_tr)
- ring_buffer_resize(max_tr.buffer, 1);
+ ring_buffer_resize(max_tr.buffer, 1,
+ RING_BUFFER_ALL_CPUS);
printk(KERN_CONT "PASSED\n");
}
@@ -917,13 +898,6 @@ out:
mutex_unlock(&trace_types_lock);
}
-static void __tracing_reset(struct ring_buffer *buffer, int cpu)
-{
- ftrace_disable_cpu();
- ring_buffer_reset_cpu(buffer, cpu);
- ftrace_enable_cpu();
-}
-
void tracing_reset(struct trace_array *tr, int cpu)
{
struct ring_buffer *buffer = tr->buffer;
@@ -932,7 +906,7 @@ void tracing_reset(struct trace_array *tr, int cpu)
/* Make sure all commits have finished */
synchronize_sched();
- __tracing_reset(buffer, cpu);
+ ring_buffer_reset_cpu(buffer, cpu);
ring_buffer_record_enable(buffer);
}
@@ -950,7 +924,7 @@ void tracing_reset_online_cpus(struct trace_array *tr)
tr->time_start = ftrace_now(tr->cpu);
for_each_online_cpu(cpu)
- __tracing_reset(buffer, cpu);
+ ring_buffer_reset_cpu(buffer, cpu);
ring_buffer_record_enable(buffer);
}
@@ -1498,25 +1472,119 @@ static void __trace_userstack(struct trace_array *tr, unsigned long flags)
#endif /* CONFIG_STACKTRACE */
+/* created for use with alloc_percpu */
+struct trace_buffer_struct {
+ char buffer[TRACE_BUF_SIZE];
+};
+
+static struct trace_buffer_struct *trace_percpu_buffer;
+static struct trace_buffer_struct *trace_percpu_sirq_buffer;
+static struct trace_buffer_struct *trace_percpu_irq_buffer;
+static struct trace_buffer_struct *trace_percpu_nmi_buffer;
+
+/*
+ * The buffer used is dependent on the context. There is a per cpu
+ * buffer for normal context, softirq contex, hard irq context and
+ * for NMI context. Thise allows for lockless recording.
+ *
+ * Note, if the buffers failed to be allocated, then this returns NULL
+ */
+static char *get_trace_buf(void)
+{
+ struct trace_buffer_struct *percpu_buffer;
+ struct trace_buffer_struct *buffer;
+
+ /*
+ * If we have allocated per cpu buffers, then we do not
+ * need to do any locking.
+ */
+ if (in_nmi())
+ percpu_buffer = trace_percpu_nmi_buffer;
+ else if (in_irq())
+ percpu_buffer = trace_percpu_irq_buffer;
+ else if (in_softirq())
+ percpu_buffer = trace_percpu_sirq_buffer;
+ else
+ percpu_buffer = trace_percpu_buffer;
+
+ if (!percpu_buffer)
+ return NULL;
+
+ buffer = per_cpu_ptr(percpu_buffer, smp_processor_id());
+
+ return buffer->buffer;
+}
+
+static int alloc_percpu_trace_buffer(void)
+{
+ struct trace_buffer_struct *buffers;
+ struct trace_buffer_struct *sirq_buffers;
+ struct trace_buffer_struct *irq_buffers;
+ struct trace_buffer_struct *nmi_buffers;
+
+ buffers = alloc_percpu(struct trace_buffer_struct);
+ if (!buffers)
+ goto err_warn;
+
+ sirq_buffers = alloc_percpu(struct trace_buffer_struct);
+ if (!sirq_buffers)
+ goto err_sirq;
+
+ irq_buffers = alloc_percpu(struct trace_buffer_struct);
+ if (!irq_buffers)
+ goto err_irq;
+
+ nmi_buffers = alloc_percpu(struct trace_buffer_struct);
+ if (!nmi_buffers)
+ goto err_nmi;
+
+ trace_percpu_buffer = buffers;
+ trace_percpu_sirq_buffer = sirq_buffers;
+ trace_percpu_irq_buffer = irq_buffers;
+ trace_percpu_nmi_buffer = nmi_buffers;
+
+ return 0;
+
+ err_nmi:
+ free_percpu(irq_buffers);
+ err_irq:
+ free_percpu(sirq_buffers);
+ err_sirq:
+ free_percpu(buffers);
+ err_warn:
+ WARN(1, "Could not allocate percpu trace_printk buffer");
+ return -ENOMEM;
+}
+
+void trace_printk_init_buffers(void)
+{
+ static int buffers_allocated;
+
+ if (buffers_allocated)
+ return;
+
+ if (alloc_percpu_trace_buffer())
+ return;
+
+ pr_info("ftrace: Allocated trace_printk buffers\n");
+
+ buffers_allocated = 1;
+}
+
/**
* trace_vbprintk - write binary msg to tracing buffer
*
*/
int trace_vbprintk(unsigned long ip, const char *fmt, va_list args)
{
- static arch_spinlock_t trace_buf_lock =
- (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
- static u32 trace_buf[TRACE_BUF_SIZE];
-
struct ftrace_event_call *call = &event_bprint;
struct ring_buffer_event *event;
struct ring_buffer *buffer;
struct trace_array *tr = &global_trace;
- struct trace_array_cpu *data;
struct bprint_entry *entry;
unsigned long flags;
- int disable;
- int cpu, len = 0, size, pc;
+ char *tbuffer;
+ int len = 0, size, pc;
if (unlikely(tracing_selftest_running || tracing_disabled))
return 0;
@@ -1526,43 +1594,36 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args)
pc = preempt_count();
preempt_disable_notrace();
- cpu = raw_smp_processor_id();
- data = tr->data[cpu];
- disable = atomic_inc_return(&data->disabled);
- if (unlikely(disable != 1))
+ tbuffer = get_trace_buf();
+ if (!tbuffer) {
+ len = 0;
goto out;
+ }
- /* Lockdep uses trace_printk for lock tracing */
- local_irq_save(flags);
- arch_spin_lock(&trace_buf_lock);
- len = vbin_printf(trace_buf, TRACE_BUF_SIZE, fmt, args);
+ len = vbin_printf((u32 *)tbuffer, TRACE_BUF_SIZE/sizeof(int), fmt, args);
- if (len > TRACE_BUF_SIZE || len < 0)
- goto out_unlock;
+ if (len > TRACE_BUF_SIZE/sizeof(int) || len < 0)
+ goto out;
+ local_save_flags(flags);
size = sizeof(*entry) + sizeof(u32) * len;
buffer = tr->buffer;
event = trace_buffer_lock_reserve(buffer, TRACE_BPRINT, size,
flags, pc);
if (!event)
- goto out_unlock;
+ goto out;
entry = ring_buffer_event_data(event);
entry->ip = ip;
entry->fmt = fmt;
- memcpy(entry->buf, trace_buf, sizeof(u32) * len);
+ memcpy(entry->buf, tbuffer, sizeof(u32) * len);
if (!filter_check_discard(call, entry, buffer, event)) {
ring_buffer_unlock_commit(buffer, event);
ftrace_trace_stack(buffer, flags, 6, pc);
}
-out_unlock:
- arch_spin_unlock(&trace_buf_lock);
- local_irq_restore(flags);
-
out:
- atomic_dec_return(&data->disabled);
preempt_enable_notrace();
unpause_graph_tracing();
@@ -1588,58 +1649,53 @@ int trace_array_printk(struct trace_array *tr,
int trace_array_vprintk(struct trace_array *tr,
unsigned long ip, const char *fmt, va_list args)
{
- static arch_spinlock_t trace_buf_lock = __ARCH_SPIN_LOCK_UNLOCKED;
- static char trace_buf[TRACE_BUF_SIZE];
-
struct ftrace_event_call *call = &event_print;
struct ring_buffer_event *event;
struct ring_buffer *buffer;
- struct trace_array_cpu *data;
- int cpu, len = 0, size, pc;
+ int len = 0, size, pc;
struct print_entry *entry;
- unsigned long irq_flags;
- int disable;
+ unsigned long flags;
+ char *tbuffer;
if (tracing_disabled || tracing_selftest_running)
return 0;
+ /* Don't pollute graph traces with trace_vprintk internals */
+ pause_graph_tracing();
+
pc = preempt_count();
preempt_disable_notrace();
- cpu = raw_smp_processor_id();
- data = tr->data[cpu];
- disable = atomic_inc_return(&data->disabled);
- if (unlikely(disable != 1))
+
+ tbuffer = get_trace_buf();
+ if (!tbuffer) {
+ len = 0;
goto out;
+ }
- pause_graph_tracing();
- raw_local_irq_save(irq_flags);
- arch_spin_lock(&trace_buf_lock);
- len = vsnprintf(trace_buf, TRACE_BUF_SIZE, fmt, args);
+ len = vsnprintf(tbuffer, TRACE_BUF_SIZE, fmt, args);
+ if (len > TRACE_BUF_SIZE)
+ goto out;
+ local_save_flags(flags);
size = sizeof(*entry) + len + 1;
buffer = tr->buffer;
event = trace_buffer_lock_reserve(buffer, TRACE_PRINT, size,
- irq_flags, pc);
+ flags, pc);
if (!event)
- goto out_unlock;
+ goto out;
entry = ring_buffer_event_data(event);
entry->ip = ip;
- memcpy(&entry->buf, trace_buf, len);
+ memcpy(&entry->buf, tbuffer, len);
entry->buf[len] = '\0';
if (!filter_check_discard(call, entry, buffer, event)) {
ring_buffer_unlock_commit(buffer, event);
- ftrace_trace_stack(buffer, irq_flags, 6, pc);
+ ftrace_trace_stack(buffer, flags, 6, pc);
}
-
- out_unlock:
- arch_spin_unlock(&trace_buf_lock);
- raw_local_irq_restore(irq_flags);
- unpause_graph_tracing();
out:
- atomic_dec_return(&data->disabled);
preempt_enable_notrace();
+ unpause_graph_tracing();
return len;
}
@@ -1652,14 +1708,9 @@ EXPORT_SYMBOL_GPL(trace_vprintk);
static void trace_iterator_increment(struct trace_iterator *iter)
{
- /* Don't allow ftrace to trace into the ring buffers */
- ftrace_disable_cpu();
-
iter->idx++;
if (iter->buffer_iter[iter->cpu])
ring_buffer_read(iter->buffer_iter[iter->cpu], NULL);
-
- ftrace_enable_cpu();
}
static struct trace_entry *
@@ -1669,17 +1720,12 @@ peek_next_entry(struct trace_iterator *iter, int cpu, u64 *ts,
struct ring_buffer_event *event;
struct ring_buffer_iter *buf_iter = iter->buffer_iter[cpu];
- /* Don't allow ftrace to trace into the ring buffers */
- ftrace_disable_cpu();
-
if (buf_iter)
event = ring_buffer_iter_peek(buf_iter, ts);
else
event = ring_buffer_peek(iter->tr->buffer, cpu, ts,
lost_events);
- ftrace_enable_cpu();
-
if (event) {
iter->ent_size = ring_buffer_event_length(event);
return ring_buffer_event_data(event);
@@ -1769,11 +1815,8 @@ void *trace_find_next_entry_inc(struct trace_iterator *iter)
static void trace_consume(struct trace_iterator *iter)
{
- /* Don't allow ftrace to trace into the ring buffers */
- ftrace_disable_cpu();
ring_buffer_consume(iter->tr->buffer, iter->cpu, &iter->ts,
&iter->lost_events);
- ftrace_enable_cpu();
}
static void *s_next(struct seq_file *m, void *v, loff_t *pos)
@@ -1862,16 +1905,12 @@ static void *s_start(struct seq_file *m, loff_t *pos)
iter->cpu = 0;
iter->idx = -1;
- ftrace_disable_cpu();
-
if (cpu_file == TRACE_PIPE_ALL_CPU) {
for_each_tracing_cpu(cpu)
tracing_iter_reset(iter, cpu);
} else
tracing_iter_reset(iter, cpu_file);
- ftrace_enable_cpu();
-
iter->leftover = 0;
for (p = iter; p && l < *pos; p = s_next(m, p, &l))
;
@@ -2332,15 +2371,13 @@ static struct trace_iterator *
__tracing_open(struct inode *inode, struct file *file)
{
long cpu_file = (long) inode->i_private;
- void *fail_ret = ERR_PTR(-ENOMEM);
struct trace_iterator *iter;
- struct seq_file *m;
- int cpu, ret;
+ int cpu;
if (tracing_disabled)
return ERR_PTR(-ENODEV);
- iter = kzalloc(sizeof(*iter), GFP_KERNEL);
+ iter = __seq_open_private(file, &tracer_seq_ops, sizeof(*iter));
if (!iter)
return ERR_PTR(-ENOMEM);
@@ -2397,32 +2434,15 @@ __tracing_open(struct inode *inode, struct file *file)
tracing_iter_reset(iter, cpu);
}
- ret = seq_open(file, &tracer_seq_ops);
- if (ret < 0) {
- fail_ret = ERR_PTR(ret);
- goto fail_buffer;
- }
-
- m = file->private_data;
- m->private = iter;
-
mutex_unlock(&trace_types_lock);
return iter;
- fail_buffer:
- for_each_tracing_cpu(cpu) {
- if (iter->buffer_iter[cpu])
- ring_buffer_read_finish(iter->buffer_iter[cpu]);
- }
- free_cpumask_var(iter->started);
- tracing_start();
fail:
mutex_unlock(&trace_types_lock);
kfree(iter->trace);
- kfree(iter);
-
- return fail_ret;
+ seq_release_private(inode, file);
+ return ERR_PTR(-ENOMEM);
}
int tracing_open_generic(struct inode *inode, struct file *filp)
@@ -2458,11 +2478,10 @@ static int tracing_release(struct inode *inode, struct file *file)
tracing_start();
mutex_unlock(&trace_types_lock);
- seq_release(inode, file);
mutex_destroy(&iter->mutex);
free_cpumask_var(iter->started);
kfree(iter->trace);
- kfree(iter);
+ seq_release_private(inode, file);
return 0;
}
@@ -2648,10 +2667,12 @@ tracing_cpumask_write(struct file *filp, const char __user *ubuf,
if (cpumask_test_cpu(cpu, tracing_cpumask) &&
!cpumask_test_cpu(cpu, tracing_cpumask_new)) {
atomic_inc(&global_trace.data[cpu]->disabled);
+ ring_buffer_record_disable_cpu(global_trace.buffer, cpu);
}
if (!cpumask_test_cpu(cpu, tracing_cpumask) &&
cpumask_test_cpu(cpu, tracing_cpumask_new)) {
atomic_dec(&global_trace.data[cpu]->disabled);
+ ring_buffer_record_enable_cpu(global_trace.buffer, cpu);
}
}
arch_spin_unlock(&ftrace_max_lock);
@@ -2974,7 +2995,14 @@ int tracer_init(struct tracer *t, struct trace_array *tr)
return t->init(tr);
}
-static int __tracing_resize_ring_buffer(unsigned long size)
+static void set_buffer_entries(struct trace_array *tr, unsigned long val)
+{
+ int cpu;
+ for_each_tracing_cpu(cpu)
+ tr->data[cpu]->entries = val;
+}
+
+static int __tracing_resize_ring_buffer(unsigned long size, int cpu)
{
int ret;
@@ -2985,19 +3013,32 @@ static int __tracing_resize_ring_buffer(unsigned long size)
*/
ring_buffer_expanded = 1;
- ret = ring_buffer_resize(global_trace.buffer, size);
+ ret = ring_buffer_resize(global_trace.buffer, size, cpu);
if (ret < 0)
return ret;
if (!current_trace->use_max_tr)
goto out;
- ret = ring_buffer_resize(max_tr.buffer, size);
+ ret = ring_buffer_resize(max_tr.buffer, size, cpu);
if (ret < 0) {
- int r;
+ int r = 0;
+
+ if (cpu == RING_BUFFER_ALL_CPUS) {
+ int i;
+ for_each_tracing_cpu(i) {
+ r = ring_buffer_resize(global_trace.buffer,
+ global_trace.data[i]->entries,
+ i);
+ if (r < 0)
+ break;
+ }
+ } else {
+ r = ring_buffer_resize(global_trace.buffer,
+ global_trace.data[cpu]->entries,
+ cpu);
+ }
- r = ring_buffer_resize(global_trace.buffer,
- global_trace.entries);
if (r < 0) {
/*
* AARGH! We are left with different
@@ -3019,43 +3060,39 @@ static int __tracing_resize_ring_buffer(unsigned long size)
return ret;
}
- max_tr.entries = size;
+ if (cpu == RING_BUFFER_ALL_CPUS)
+ set_buffer_entries(&max_tr, size);
+ else
+ max_tr.data[cpu]->entries = size;
+
out:
- global_trace.entries = size;
+ if (cpu == RING_BUFFER_ALL_CPUS)
+ set_buffer_entries(&global_trace, size);
+ else
+ global_trace.data[cpu]->entries = size;
return ret;
}
-static ssize_t tracing_resize_ring_buffer(unsigned long size)
+static ssize_t tracing_resize_ring_buffer(unsigned long size, int cpu_id)
{
- int cpu, ret = size;
+ int ret = size;
mutex_lock(&trace_types_lock);
- tracing_stop();
-
- /* disable all cpu buffers */
- for_each_tracing_cpu(cpu) {
- if (global_trace.data[cpu])
- atomic_inc(&global_trace.data[cpu]->disabled);
- if (max_tr.data[cpu])
- atomic_inc(&max_tr.data[cpu]->disabled);
+ if (cpu_id != RING_BUFFER_ALL_CPUS) {
+ /* make sure, this cpu is enabled in the mask */
+ if (!cpumask_test_cpu(cpu_id, tracing_buffer_mask)) {
+ ret = -EINVAL;
+ goto out;
+ }
}
- if (size != global_trace.entries)
- ret = __tracing_resize_ring_buffer(size);
-
+ ret = __tracing_resize_ring_buffer(size, cpu_id);
if (ret < 0)
ret = -ENOMEM;
- for_each_tracing_cpu(cpu) {
- if (global_trace.data[cpu])
- atomic_dec(&global_trace.data[cpu]->disabled);
- if (max_tr.data[cpu])
- atomic_dec(&max_tr.data[cpu]->disabled);
- }
-
- tracing_start();
+out:
mutex_unlock(&trace_types_lock);
return ret;
@@ -3078,7 +3115,8 @@ int tracing_update_buffers(void)
mutex_lock(&trace_types_lock);
if (!ring_buffer_expanded)
- ret = __tracing_resize_ring_buffer(trace_buf_size);
+ ret = __tracing_resize_ring_buffer(trace_buf_size,
+ RING_BUFFER_ALL_CPUS);
mutex_unlock(&trace_types_lock);
return ret;
@@ -3102,7 +3140,8 @@ static int tracing_set_tracer(const char *buf)
mutex_lock(&trace_types_lock);
if (!ring_buffer_expanded) {
- ret = __tracing_resize_ring_buffer(trace_buf_size);
+ ret = __tracing_resize_ring_buffer(trace_buf_size,
+ RING_BUFFER_ALL_CPUS);
if (ret < 0)
goto out;
ret = 0;
@@ -3128,8 +3167,8 @@ static int tracing_set_tracer(const char *buf)
* The max_tr ring buffer has some state (e.g. ring->clock) and
* we want preserve it.
*/
- ring_buffer_resize(max_tr.buffer, 1);
- max_tr.entries = 1;
+ ring_buffer_resize(max_tr.buffer, 1, RING_BUFFER_ALL_CPUS);
+ set_buffer_entries(&max_tr, 1);
}
destroy_trace_option_files(topts);
@@ -3137,10 +3176,17 @@ static int tracing_set_tracer(const char *buf)
topts = create_trace_option_files(current_trace);
if (current_trace->use_max_tr) {
- ret = ring_buffer_resize(max_tr.buffer, global_trace.entries);
- if (ret < 0)
- goto out;
- max_tr.entries = global_trace.entries;
+ int cpu;
+ /* we need to make per cpu buffer sizes equivalent */
+ for_each_tracing_cpu(cpu) {
+ ret = ring_buffer_resize(max_tr.buffer,
+ global_trace.data[cpu]->entries,
+ cpu);
+ if (ret < 0)
+ goto out;
+ max_tr.data[cpu]->entries =
+ global_trace.data[cpu]->entries;
+ }
}
if (t->init) {
@@ -3642,30 +3688,82 @@ out_err:
goto out;
}
+struct ftrace_entries_info {
+ struct trace_array *tr;
+ int cpu;
+};
+
+static int tracing_entries_open(struct inode *inode, struct file *filp)
+{
+ struct ftrace_entries_info *info;
+
+ if (tracing_disabled)
+ return -ENODEV;
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->tr = &global_trace;
+ info->cpu = (unsigned long)inode->i_private;
+
+ filp->private_data = info;
+
+ return 0;
+}
+
static ssize_t
tracing_entries_read(struct file *filp, char __user *ubuf,
size_t cnt, loff_t *ppos)
{
- struct trace_array *tr = filp->private_data;
- char buf[96];
- int r;
+ struct ftrace_entries_info *info = filp->private_data;
+ struct trace_array *tr = info->tr;
+ char buf[64];
+ int r = 0;
+ ssize_t ret;
mutex_lock(&trace_types_lock);
- if (!ring_buffer_expanded)
- r = sprintf(buf, "%lu (expanded: %lu)\n",
- tr->entries >> 10,
- trace_buf_size >> 10);
- else
- r = sprintf(buf, "%lu\n", tr->entries >> 10);
+
+ if (info->cpu == RING_BUFFER_ALL_CPUS) {
+ int cpu, buf_size_same;
+ unsigned long size;
+
+ size = 0;
+ buf_size_same = 1;
+ /* check if all cpu sizes are same */
+ for_each_tracing_cpu(cpu) {
+ /* fill in the size from first enabled cpu */
+ if (size == 0)
+ size = tr->data[cpu]->entries;
+ if (size != tr->data[cpu]->entries) {
+ buf_size_same = 0;
+ break;
+ }
+ }
+
+ if (buf_size_same) {
+ if (!ring_buffer_expanded)
+ r = sprintf(buf, "%lu (expanded: %lu)\n",
+ size >> 10,
+ trace_buf_size >> 10);
+ else
+ r = sprintf(buf, "%lu\n", size >> 10);
+ } else
+ r = sprintf(buf, "X\n");
+ } else
+ r = sprintf(buf, "%lu\n", tr->data[info->cpu]->entries >> 10);
+
mutex_unlock(&trace_types_lock);
- return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
+ ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
+ return ret;
}
static ssize_t
tracing_entries_write(struct file *filp, const char __user *ubuf,
size_t cnt, loff_t *ppos)
{
+ struct ftrace_entries_info *info = filp->private_data;
unsigned long val;
int ret;
@@ -3680,7 +3778,7 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,
/* value is in KB */
val <<= 10;
- ret = tracing_resize_ring_buffer(val);
+ ret = tracing_resize_ring_buffer(val, info->cpu);
if (ret < 0)
return ret;
@@ -3689,6 +3787,16 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,
return cnt;
}
+static int
+tracing_entries_release(struct inode *inode, struct file *filp)
+{
+ struct ftrace_entries_info *info = filp->private_data;
+
+ kfree(info);
+
+ return 0;
+}
+
static ssize_t
tracing_total_entries_read(struct file *filp, char __user *ubuf,
size_t cnt, loff_t *ppos)
@@ -3700,7 +3808,7 @@ tracing_total_entries_read(struct file *filp, char __user *ubuf,
mutex_lock(&trace_types_lock);
for_each_tracing_cpu(cpu) {
- size += tr->entries >> 10;
+ size += tr->data[cpu]->entries >> 10;
if (!ring_buffer_expanded)
expanded_size += trace_buf_size >> 10;
}
@@ -3734,7 +3842,7 @@ tracing_free_buffer_release(struct inode *inode, struct file *filp)
if (trace_flags & TRACE_ITER_STOP_ON_FREE)
tracing_off();
/* resize the ring buffer to 0 */
- tracing_resize_ring_buffer(0);
+ tracing_resize_ring_buffer(0, RING_BUFFER_ALL_CPUS);
return 0;
}
@@ -3749,14 +3857,14 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
struct print_entry *entry;
unsigned long irq_flags;
struct page *pages[2];
+ void *map_page[2];
int nr_pages = 1;
ssize_t written;
- void *page1;
- void *page2;
int offset;
int size;
int len;
int ret;
+ int i;
if (tracing_disabled)
return -EINVAL;
@@ -3795,9 +3903,8 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
goto out;
}
- page1 = kmap_atomic(pages[0]);
- if (nr_pages == 2)
- page2 = kmap_atomic(pages[1]);
+ for (i = 0; i < nr_pages; i++)
+ map_page[i] = kmap_atomic(pages[i]);
local_save_flags(irq_flags);
size = sizeof(*entry) + cnt + 2; /* possible \n added */
@@ -3815,10 +3922,10 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
if (nr_pages == 2) {
len = PAGE_SIZE - offset;
- memcpy(&entry->buf, page1 + offset, len);
- memcpy(&entry->buf[len], page2, cnt - len);
+ memcpy(&entry->buf, map_page[0] + offset, len);
+ memcpy(&entry->buf[len], map_page[1], cnt - len);
} else
- memcpy(&entry->buf, page1 + offset, cnt);
+ memcpy(&entry->buf, map_page[0] + offset, cnt);
if (entry->buf[cnt - 1] != '\n') {
entry->buf[cnt] = '\n';
@@ -3833,11 +3940,10 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
*fpos += written;
out_unlock:
- if (nr_pages == 2)
- kunmap_atomic(page2);
- kunmap_atomic(page1);
- while (nr_pages > 0)
- put_page(pages[--nr_pages]);
+ for (i = 0; i < nr_pages; i++){
+ kunmap_atomic(map_page[i]);
+ put_page(pages[i]);
+ }
out:
return written;
}
@@ -3933,9 +4039,10 @@ static const struct file_operations tracing_pipe_fops = {
};
static const struct file_operations tracing_entries_fops = {
- .open = tracing_open_generic,
+ .open = tracing_entries_open,
.read = tracing_entries_read,
.write = tracing_entries_write,
+ .release = tracing_entries_release,
.llseek = generic_file_llseek,
};
@@ -4367,6 +4474,9 @@ static void tracing_init_debugfs_percpu(long cpu)
struct dentry *d_cpu;
char cpu_dir[30]; /* 30 characters should be more than enough */
+ if (!d_percpu)
+ return;
+
snprintf(cpu_dir, 30, "cpu%ld", cpu);
d_cpu = debugfs_create_dir(cpu_dir, d_percpu);
if (!d_cpu) {
@@ -4387,6 +4497,9 @@ static void tracing_init_debugfs_percpu(long cpu)
trace_create_file("stats", 0444, d_cpu,
(void *) cpu, &tracing_stats_fops);
+
+ trace_create_file("buffer_size_kb", 0444, d_cpu,
+ (void *) cpu, &tracing_entries_fops);
}
#ifdef CONFIG_FTRACE_SELFTEST
@@ -4718,7 +4831,7 @@ static __init int tracer_init_debugfs(void)
(void *) TRACE_PIPE_ALL_CPU, &tracing_pipe_fops);
trace_create_file("buffer_size_kb", 0644, d_tracer,
- &global_trace, &tracing_entries_fops);
+ (void *) RING_BUFFER_ALL_CPUS, &tracing_entries_fops);
trace_create_file("buffer_total_size_kb", 0444, d_tracer,
&global_trace, &tracing_total_entries_fops);
@@ -4957,6 +5070,10 @@ __init static int tracer_alloc_buffers(void)
if (!alloc_cpumask_var(&tracing_cpumask, GFP_KERNEL))
goto out_free_buffer_mask;
+ /* Only allocate trace_printk buffers if a trace_printk exists */
+ if (__stop___trace_bprintk_fmt != __start___trace_bprintk_fmt)
+ trace_printk_init_buffers();
+
/* To save memory, keep the ring buffer size to its minimum */
if (ring_buffer_expanded)
ring_buf_size = trace_buf_size;
@@ -4975,7 +5092,6 @@ __init static int tracer_alloc_buffers(void)
WARN_ON(1);
goto out_free_cpumask;
}
- global_trace.entries = ring_buffer_size(global_trace.buffer);
if (global_trace.buffer_disabled)
tracing_off();
@@ -4988,7 +5104,6 @@ __init static int tracer_alloc_buffers(void)
ring_buffer_free(global_trace.buffer);
goto out_free_cpumask;
}
- max_tr.entries = 1;
#endif
/* Allocate the first page for all buffers */
@@ -4997,6 +5112,12 @@ __init static int tracer_alloc_buffers(void)
max_tr.data[i] = &per_cpu(max_tr_data, i);
}
+ set_buffer_entries(&global_trace,
+ ring_buffer_size(global_trace.buffer, 0));
+#ifdef CONFIG_TRACER_MAX_TRACE
+ set_buffer_entries(&max_tr, 1);
+#endif
+
trace_init_cmdlines();
register_tracer(&nop_trace);
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index f95d65da6db8..5aec220d2de0 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -103,6 +103,11 @@ struct kretprobe_trace_entry_head {
unsigned long ret_ip;
};
+struct uprobe_trace_entry_head {
+ struct trace_entry ent;
+ unsigned long ip;
+};
+
/*
* trace_flag_type is an enumeration that holds different
* states when a trace occurs. These are:
@@ -131,6 +136,7 @@ struct trace_array_cpu {
atomic_t disabled;
void *buffer_page; /* ring buffer spare */
+ unsigned long entries;
unsigned long saved_latency;
unsigned long critical_start;
unsigned long critical_end;
@@ -152,7 +158,6 @@ struct trace_array_cpu {
*/
struct trace_array {
struct ring_buffer *buffer;
- unsigned long entries;
int cpu;
int buffer_disabled;
cycle_t time_start;
@@ -826,6 +831,8 @@ extern struct list_head ftrace_events;
extern const char *__start___trace_bprintk_fmt[];
extern const char *__stop___trace_bprintk_fmt[];
+void trace_printk_init_buffers(void);
+
#undef FTRACE_ENTRY
#define FTRACE_ENTRY(call, struct_name, id, tstruct, print, filter) \
extern struct ftrace_event_call \
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 580a05ec926b..b31d3d5699fe 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -19,547 +19,15 @@
#include <linux/module.h>
#include <linux/uaccess.h>
-#include <linux/kprobes.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/smp.h>
-#include <linux/debugfs.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/ptrace.h>
-#include <linux/perf_event.h>
-#include <linux/stringify.h>
-#include <linux/limits.h>
-#include <asm/bitsperlong.h>
-
-#include "trace.h"
-#include "trace_output.h"
-
-#define MAX_TRACE_ARGS 128
-#define MAX_ARGSTR_LEN 63
-#define MAX_EVENT_NAME_LEN 64
-#define MAX_STRING_SIZE PATH_MAX
-#define KPROBE_EVENT_SYSTEM "kprobes"
-
-/* Reserved field names */
-#define FIELD_STRING_IP "__probe_ip"
-#define FIELD_STRING_RETIP "__probe_ret_ip"
-#define FIELD_STRING_FUNC "__probe_func"
-
-const char *reserved_field_names[] = {
- "common_type",
- "common_flags",
- "common_preempt_count",
- "common_pid",
- "common_tgid",
- FIELD_STRING_IP,
- FIELD_STRING_RETIP,
- FIELD_STRING_FUNC,
-};
-
-/* Printing function type */
-typedef int (*print_type_func_t)(struct trace_seq *, const char *, void *,
- void *);
-#define PRINT_TYPE_FUNC_NAME(type) print_type_##type
-#define PRINT_TYPE_FMT_NAME(type) print_type_format_##type
-
-/* Printing in basic type function template */
-#define DEFINE_BASIC_PRINT_TYPE_FUNC(type, fmt, cast) \
-static __kprobes int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, \
- const char *name, \
- void *data, void *ent)\
-{ \
- return trace_seq_printf(s, " %s=" fmt, name, (cast)*(type *)data);\
-} \
-static const char PRINT_TYPE_FMT_NAME(type)[] = fmt;
-
-DEFINE_BASIC_PRINT_TYPE_FUNC(u8, "%x", unsigned int)
-DEFINE_BASIC_PRINT_TYPE_FUNC(u16, "%x", unsigned int)
-DEFINE_BASIC_PRINT_TYPE_FUNC(u32, "%lx", unsigned long)
-DEFINE_BASIC_PRINT_TYPE_FUNC(u64, "%llx", unsigned long long)
-DEFINE_BASIC_PRINT_TYPE_FUNC(s8, "%d", int)
-DEFINE_BASIC_PRINT_TYPE_FUNC(s16, "%d", int)
-DEFINE_BASIC_PRINT_TYPE_FUNC(s32, "%ld", long)
-DEFINE_BASIC_PRINT_TYPE_FUNC(s64, "%lld", long long)
-
-/* data_rloc: data relative location, compatible with u32 */
-#define make_data_rloc(len, roffs) \
- (((u32)(len) << 16) | ((u32)(roffs) & 0xffff))
-#define get_rloc_len(dl) ((u32)(dl) >> 16)
-#define get_rloc_offs(dl) ((u32)(dl) & 0xffff)
-
-static inline void *get_rloc_data(u32 *dl)
-{
- return (u8 *)dl + get_rloc_offs(*dl);
-}
-
-/* For data_loc conversion */
-static inline void *get_loc_data(u32 *dl, void *ent)
-{
- return (u8 *)ent + get_rloc_offs(*dl);
-}
-
-/*
- * Convert data_rloc to data_loc:
- * data_rloc stores the offset from data_rloc itself, but data_loc
- * stores the offset from event entry.
- */
-#define convert_rloc_to_loc(dl, offs) ((u32)(dl) + (offs))
-
-/* For defining macros, define string/string_size types */
-typedef u32 string;
-typedef u32 string_size;
-
-/* Print type function for string type */
-static __kprobes int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s,
- const char *name,
- void *data, void *ent)
-{
- int len = *(u32 *)data >> 16;
-
- if (!len)
- return trace_seq_printf(s, " %s=(fault)", name);
- else
- return trace_seq_printf(s, " %s=\"%s\"", name,
- (const char *)get_loc_data(data, ent));
-}
-static const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\"";
-
-/* Data fetch function type */
-typedef void (*fetch_func_t)(struct pt_regs *, void *, void *);
-
-struct fetch_param {
- fetch_func_t fn;
- void *data;
-};
-
-static __kprobes void call_fetch(struct fetch_param *fprm,
- struct pt_regs *regs, void *dest)
-{
- return fprm->fn(regs, fprm->data, dest);
-}
-
-#define FETCH_FUNC_NAME(method, type) fetch_##method##_##type
-/*
- * Define macro for basic types - we don't need to define s* types, because
- * we have to care only about bitwidth at recording time.
- */
-#define DEFINE_BASIC_FETCH_FUNCS(method) \
-DEFINE_FETCH_##method(u8) \
-DEFINE_FETCH_##method(u16) \
-DEFINE_FETCH_##method(u32) \
-DEFINE_FETCH_##method(u64)
-
-#define CHECK_FETCH_FUNCS(method, fn) \
- (((FETCH_FUNC_NAME(method, u8) == fn) || \
- (FETCH_FUNC_NAME(method, u16) == fn) || \
- (FETCH_FUNC_NAME(method, u32) == fn) || \
- (FETCH_FUNC_NAME(method, u64) == fn) || \
- (FETCH_FUNC_NAME(method, string) == fn) || \
- (FETCH_FUNC_NAME(method, string_size) == fn)) \
- && (fn != NULL))
-
-/* Data fetch function templates */
-#define DEFINE_FETCH_reg(type) \
-static __kprobes void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs, \
- void *offset, void *dest) \
-{ \
- *(type *)dest = (type)regs_get_register(regs, \
- (unsigned int)((unsigned long)offset)); \
-}
-DEFINE_BASIC_FETCH_FUNCS(reg)
-/* No string on the register */
-#define fetch_reg_string NULL
-#define fetch_reg_string_size NULL
-
-#define DEFINE_FETCH_stack(type) \
-static __kprobes void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs,\
- void *offset, void *dest) \
-{ \
- *(type *)dest = (type)regs_get_kernel_stack_nth(regs, \
- (unsigned int)((unsigned long)offset)); \
-}
-DEFINE_BASIC_FETCH_FUNCS(stack)
-/* No string on the stack entry */
-#define fetch_stack_string NULL
-#define fetch_stack_string_size NULL
-
-#define DEFINE_FETCH_retval(type) \
-static __kprobes void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs,\
- void *dummy, void *dest) \
-{ \
- *(type *)dest = (type)regs_return_value(regs); \
-}
-DEFINE_BASIC_FETCH_FUNCS(retval)
-/* No string on the retval */
-#define fetch_retval_string NULL
-#define fetch_retval_string_size NULL
-
-#define DEFINE_FETCH_memory(type) \
-static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\
- void *addr, void *dest) \
-{ \
- type retval; \
- if (probe_kernel_address(addr, retval)) \
- *(type *)dest = 0; \
- else \
- *(type *)dest = retval; \
-}
-DEFINE_BASIC_FETCH_FUNCS(memory)
-/*
- * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
- * length and relative data location.
- */
-static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
- void *addr, void *dest)
-{
- long ret;
- int maxlen = get_rloc_len(*(u32 *)dest);
- u8 *dst = get_rloc_data(dest);
- u8 *src = addr;
- mm_segment_t old_fs = get_fs();
- if (!maxlen)
- return;
- /*
- * Try to get string again, since the string can be changed while
- * probing.
- */
- set_fs(KERNEL_DS);
- pagefault_disable();
- do
- ret = __copy_from_user_inatomic(dst++, src++, 1);
- while (dst[-1] && ret == 0 && src - (u8 *)addr < maxlen);
- dst[-1] = '\0';
- pagefault_enable();
- set_fs(old_fs);
-
- if (ret < 0) { /* Failed to fetch string */
- ((u8 *)get_rloc_data(dest))[0] = '\0';
- *(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest));
- } else
- *(u32 *)dest = make_data_rloc(src - (u8 *)addr,
- get_rloc_offs(*(u32 *)dest));
-}
-/* Return the length of string -- including null terminal byte */
-static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs,
- void *addr, void *dest)
-{
- int ret, len = 0;
- u8 c;
- mm_segment_t old_fs = get_fs();
-
- set_fs(KERNEL_DS);
- pagefault_disable();
- do {
- ret = __copy_from_user_inatomic(&c, (u8 *)addr + len, 1);
- len++;
- } while (c && ret == 0 && len < MAX_STRING_SIZE);
- pagefault_enable();
- set_fs(old_fs);
-
- if (ret < 0) /* Failed to check the length */
- *(u32 *)dest = 0;
- else
- *(u32 *)dest = len;
-}
-
-/* Memory fetching by symbol */
-struct symbol_cache {
- char *symbol;
- long offset;
- unsigned long addr;
-};
-
-static unsigned long update_symbol_cache(struct symbol_cache *sc)
-{
- sc->addr = (unsigned long)kallsyms_lookup_name(sc->symbol);
- if (sc->addr)
- sc->addr += sc->offset;
- return sc->addr;
-}
-
-static void free_symbol_cache(struct symbol_cache *sc)
-{
- kfree(sc->symbol);
- kfree(sc);
-}
-
-static struct symbol_cache *alloc_symbol_cache(const char *sym, long offset)
-{
- struct symbol_cache *sc;
-
- if (!sym || strlen(sym) == 0)
- return NULL;
- sc = kzalloc(sizeof(struct symbol_cache), GFP_KERNEL);
- if (!sc)
- return NULL;
-
- sc->symbol = kstrdup(sym, GFP_KERNEL);
- if (!sc->symbol) {
- kfree(sc);
- return NULL;
- }
- sc->offset = offset;
- update_symbol_cache(sc);
- return sc;
-}
-
-#define DEFINE_FETCH_symbol(type) \
-static __kprobes void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs,\
- void *data, void *dest) \
-{ \
- struct symbol_cache *sc = data; \
- if (sc->addr) \
- fetch_memory_##type(regs, (void *)sc->addr, dest); \
- else \
- *(type *)dest = 0; \
-}
-DEFINE_BASIC_FETCH_FUNCS(symbol)
-DEFINE_FETCH_symbol(string)
-DEFINE_FETCH_symbol(string_size)
-
-/* Dereference memory access function */
-struct deref_fetch_param {
- struct fetch_param orig;
- long offset;
-};
-
-#define DEFINE_FETCH_deref(type) \
-static __kprobes void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs,\
- void *data, void *dest) \
-{ \
- struct deref_fetch_param *dprm = data; \
- unsigned long addr; \
- call_fetch(&dprm->orig, regs, &addr); \
- if (addr) { \
- addr += dprm->offset; \
- fetch_memory_##type(regs, (void *)addr, dest); \
- } else \
- *(type *)dest = 0; \
-}
-DEFINE_BASIC_FETCH_FUNCS(deref)
-DEFINE_FETCH_deref(string)
-DEFINE_FETCH_deref(string_size)
-
-static __kprobes void update_deref_fetch_param(struct deref_fetch_param *data)
-{
- if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
- update_deref_fetch_param(data->orig.data);
- else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
- update_symbol_cache(data->orig.data);
-}
-
-static __kprobes void free_deref_fetch_param(struct deref_fetch_param *data)
-{
- if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
- free_deref_fetch_param(data->orig.data);
- else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
- free_symbol_cache(data->orig.data);
- kfree(data);
-}
-
-/* Bitfield fetch function */
-struct bitfield_fetch_param {
- struct fetch_param orig;
- unsigned char hi_shift;
- unsigned char low_shift;
-};
+#include "trace_probe.h"
-#define DEFINE_FETCH_bitfield(type) \
-static __kprobes void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs,\
- void *data, void *dest) \
-{ \
- struct bitfield_fetch_param *bprm = data; \
- type buf = 0; \
- call_fetch(&bprm->orig, regs, &buf); \
- if (buf) { \
- buf <<= bprm->hi_shift; \
- buf >>= bprm->low_shift; \
- } \
- *(type *)dest = buf; \
-}
-DEFINE_BASIC_FETCH_FUNCS(bitfield)
-#define fetch_bitfield_string NULL
-#define fetch_bitfield_string_size NULL
-
-static __kprobes void
-update_bitfield_fetch_param(struct bitfield_fetch_param *data)
-{
- /*
- * Don't check the bitfield itself, because this must be the
- * last fetch function.
- */
- if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
- update_deref_fetch_param(data->orig.data);
- else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
- update_symbol_cache(data->orig.data);
-}
-
-static __kprobes void
-free_bitfield_fetch_param(struct bitfield_fetch_param *data)
-{
- /*
- * Don't check the bitfield itself, because this must be the
- * last fetch function.
- */
- if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
- free_deref_fetch_param(data->orig.data);
- else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
- free_symbol_cache(data->orig.data);
- kfree(data);
-}
-
-/* Default (unsigned long) fetch type */
-#define __DEFAULT_FETCH_TYPE(t) u##t
-#define _DEFAULT_FETCH_TYPE(t) __DEFAULT_FETCH_TYPE(t)
-#define DEFAULT_FETCH_TYPE _DEFAULT_FETCH_TYPE(BITS_PER_LONG)
-#define DEFAULT_FETCH_TYPE_STR __stringify(DEFAULT_FETCH_TYPE)
-
-/* Fetch types */
-enum {
- FETCH_MTD_reg = 0,
- FETCH_MTD_stack,
- FETCH_MTD_retval,
- FETCH_MTD_memory,
- FETCH_MTD_symbol,
- FETCH_MTD_deref,
- FETCH_MTD_bitfield,
- FETCH_MTD_END,
-};
-
-#define ASSIGN_FETCH_FUNC(method, type) \
- [FETCH_MTD_##method] = FETCH_FUNC_NAME(method, type)
-
-#define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype) \
- {.name = _name, \
- .size = _size, \
- .is_signed = sign, \
- .print = PRINT_TYPE_FUNC_NAME(ptype), \
- .fmt = PRINT_TYPE_FMT_NAME(ptype), \
- .fmttype = _fmttype, \
- .fetch = { \
-ASSIGN_FETCH_FUNC(reg, ftype), \
-ASSIGN_FETCH_FUNC(stack, ftype), \
-ASSIGN_FETCH_FUNC(retval, ftype), \
-ASSIGN_FETCH_FUNC(memory, ftype), \
-ASSIGN_FETCH_FUNC(symbol, ftype), \
-ASSIGN_FETCH_FUNC(deref, ftype), \
-ASSIGN_FETCH_FUNC(bitfield, ftype), \
- } \
- }
-
-#define ASSIGN_FETCH_TYPE(ptype, ftype, sign) \
- __ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, #ptype)
-
-#define FETCH_TYPE_STRING 0
-#define FETCH_TYPE_STRSIZE 1
-
-/* Fetch type information table */
-static const struct fetch_type {
- const char *name; /* Name of type */
- size_t size; /* Byte size of type */
- int is_signed; /* Signed flag */
- print_type_func_t print; /* Print functions */
- const char *fmt; /* Fromat string */
- const char *fmttype; /* Name in format file */
- /* Fetch functions */
- fetch_func_t fetch[FETCH_MTD_END];
-} fetch_type_table[] = {
- /* Special types */
- [FETCH_TYPE_STRING] = __ASSIGN_FETCH_TYPE("string", string, string,
- sizeof(u32), 1, "__data_loc char[]"),
- [FETCH_TYPE_STRSIZE] = __ASSIGN_FETCH_TYPE("string_size", u32,
- string_size, sizeof(u32), 0, "u32"),
- /* Basic types */
- ASSIGN_FETCH_TYPE(u8, u8, 0),
- ASSIGN_FETCH_TYPE(u16, u16, 0),
- ASSIGN_FETCH_TYPE(u32, u32, 0),
- ASSIGN_FETCH_TYPE(u64, u64, 0),
- ASSIGN_FETCH_TYPE(s8, u8, 1),
- ASSIGN_FETCH_TYPE(s16, u16, 1),
- ASSIGN_FETCH_TYPE(s32, u32, 1),
- ASSIGN_FETCH_TYPE(s64, u64, 1),
-};
-
-static const struct fetch_type *find_fetch_type(const char *type)
-{
- int i;
-
- if (!type)
- type = DEFAULT_FETCH_TYPE_STR;
-
- /* Special case: bitfield */
- if (*type == 'b') {
- unsigned long bs;
- type = strchr(type, '/');
- if (!type)
- goto fail;
- type++;
- if (strict_strtoul(type, 0, &bs))
- goto fail;
- switch (bs) {
- case 8:
- return find_fetch_type("u8");
- case 16:
- return find_fetch_type("u16");
- case 32:
- return find_fetch_type("u32");
- case 64:
- return find_fetch_type("u64");
- default:
- goto fail;
- }
- }
-
- for (i = 0; i < ARRAY_SIZE(fetch_type_table); i++)
- if (strcmp(type, fetch_type_table[i].name) == 0)
- return &fetch_type_table[i];
-fail:
- return NULL;
-}
-
-/* Special function : only accept unsigned long */
-static __kprobes void fetch_stack_address(struct pt_regs *regs,
- void *dummy, void *dest)
-{
- *(unsigned long *)dest = kernel_stack_pointer(regs);
-}
-
-static fetch_func_t get_fetch_size_function(const struct fetch_type *type,
- fetch_func_t orig_fn)
-{
- int i;
-
- if (type != &fetch_type_table[FETCH_TYPE_STRING])
- return NULL; /* Only string type needs size function */
- for (i = 0; i < FETCH_MTD_END; i++)
- if (type->fetch[i] == orig_fn)
- return fetch_type_table[FETCH_TYPE_STRSIZE].fetch[i];
-
- WARN_ON(1); /* This should not happen */
- return NULL;
-}
+#define KPROBE_EVENT_SYSTEM "kprobes"
/**
* Kprobe event core functions
*/
-struct probe_arg {
- struct fetch_param fetch;
- struct fetch_param fetch_size;
- unsigned int offset; /* Offset from argument entry */
- const char *name; /* Name of this argument */
- const char *comm; /* Command of this argument */
- const struct fetch_type *type; /* Type of this argument */
-};
-
-/* Flags for trace_probe */
-#define TP_FLAG_TRACE 1
-#define TP_FLAG_PROFILE 2
-#define TP_FLAG_REGISTERED 4
-
struct trace_probe {
struct list_head list;
struct kretprobe rp; /* Use rp.kp for kprobe use */
@@ -631,18 +99,6 @@ static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs);
static int kretprobe_dispatcher(struct kretprobe_instance *ri,
struct pt_regs *regs);
-/* Check the name is good for event/group/fields */
-static int is_good_name(const char *name)
-{
- if (!isalpha(*name) && *name != '_')
- return 0;
- while (*++name != '\0') {
- if (!isalpha(*name) && !isdigit(*name) && *name != '_')
- return 0;
- }
- return 1;
-}
-
/*
* Allocate new trace_probe and initialize it (including kprobes).
*/
@@ -651,7 +107,7 @@ static struct trace_probe *alloc_trace_probe(const char *group,
void *addr,
const char *symbol,
unsigned long offs,
- int nargs, int is_return)
+ int nargs, bool is_return)
{
struct trace_probe *tp;
int ret = -ENOMEM;
@@ -702,34 +158,12 @@ error:
return ERR_PTR(ret);
}
-static void update_probe_arg(struct probe_arg *arg)
-{
- if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn))
- update_bitfield_fetch_param(arg->fetch.data);
- else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn))
- update_deref_fetch_param(arg->fetch.data);
- else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn))
- update_symbol_cache(arg->fetch.data);
-}
-
-static void free_probe_arg(struct probe_arg *arg)
-{
- if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn))
- free_bitfield_fetch_param(arg->fetch.data);
- else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn))
- free_deref_fetch_param(arg->fetch.data);
- else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn))
- free_symbol_cache(arg->fetch.data);
- kfree(arg->name);
- kfree(arg->comm);
-}
-
static void free_trace_probe(struct trace_probe *tp)
{
int i;
for (i = 0; i < tp->nr_args; i++)
- free_probe_arg(&tp->args[i]);
+ traceprobe_free_probe_arg(&tp->args[i]);
kfree(tp->call.class->system);
kfree(tp->call.name);
@@ -787,7 +221,7 @@ static int __register_trace_probe(struct trace_probe *tp)
return -EINVAL;
for (i = 0; i < tp->nr_args; i++)
- update_probe_arg(&tp->args[i]);
+ traceprobe_update_arg(&tp->args[i]);
/* Set/clear disabled flag according to tp->flag */
if (trace_probe_is_enabled(tp))
@@ -919,227 +353,6 @@ static struct notifier_block trace_probe_module_nb = {
.priority = 1 /* Invoked after kprobe module callback */
};
-/* Split symbol and offset. */
-static int split_symbol_offset(char *symbol, unsigned long *offset)
-{
- char *tmp;
- int ret;
-
- if (!offset)
- return -EINVAL;
-
- tmp = strchr(symbol, '+');
- if (tmp) {
- /* skip sign because strict_strtol doesn't accept '+' */
- ret = strict_strtoul(tmp + 1, 0, offset);
- if (ret)
- return ret;
- *tmp = '\0';
- } else
- *offset = 0;
- return 0;
-}
-
-#define PARAM_MAX_ARGS 16
-#define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long))
-
-static int parse_probe_vars(char *arg, const struct fetch_type *t,
- struct fetch_param *f, int is_return)
-{
- int ret = 0;
- unsigned long param;
-
- if (strcmp(arg, "retval") == 0) {
- if (is_return)
- f->fn = t->fetch[FETCH_MTD_retval];
- else
- ret = -EINVAL;
- } else if (strncmp(arg, "stack", 5) == 0) {
- if (arg[5] == '\0') {
- if (strcmp(t->name, DEFAULT_FETCH_TYPE_STR) == 0)
- f->fn = fetch_stack_address;
- else
- ret = -EINVAL;
- } else if (isdigit(arg[5])) {
- ret = strict_strtoul(arg + 5, 10, &param);
- if (ret || param > PARAM_MAX_STACK)
- ret = -EINVAL;
- else {
- f->fn = t->fetch[FETCH_MTD_stack];
- f->data = (void *)param;
- }
- } else
- ret = -EINVAL;
- } else
- ret = -EINVAL;
- return ret;
-}
-
-/* Recursive argument parser */
-static int __parse_probe_arg(char *arg, const struct fetch_type *t,
- struct fetch_param *f, int is_return)
-{
- int ret = 0;
- unsigned long param;
- long offset;
- char *tmp;
-
- switch (arg[0]) {
- case '$':
- ret = parse_probe_vars(arg + 1, t, f, is_return);
- break;
- case '%': /* named register */
- ret = regs_query_register_offset(arg + 1);
- if (ret >= 0) {
- f->fn = t->fetch[FETCH_MTD_reg];
- f->data = (void *)(unsigned long)ret;
- ret = 0;
- }
- break;
- case '@': /* memory or symbol */
- if (isdigit(arg[1])) {
- ret = strict_strtoul(arg + 1, 0, &param);
- if (ret)
- break;
- f->fn = t->fetch[FETCH_MTD_memory];
- f->data = (void *)param;
- } else {
- ret = split_symbol_offset(arg + 1, &offset);
- if (ret)
- break;
- f->data = alloc_symbol_cache(arg + 1, offset);
- if (f->data)
- f->fn = t->fetch[FETCH_MTD_symbol];
- }
- break;
- case '+': /* deref memory */
- arg++; /* Skip '+', because strict_strtol() rejects it. */
- case '-':
- tmp = strchr(arg, '(');
- if (!tmp)
- break;
- *tmp = '\0';
- ret = strict_strtol(arg, 0, &offset);
- if (ret)
- break;
- arg = tmp + 1;
- tmp = strrchr(arg, ')');
- if (tmp) {
- struct deref_fetch_param *dprm;
- const struct fetch_type *t2 = find_fetch_type(NULL);
- *tmp = '\0';
- dprm = kzalloc(sizeof(struct deref_fetch_param),
- GFP_KERNEL);
- if (!dprm)
- return -ENOMEM;
- dprm->offset = offset;
- ret = __parse_probe_arg(arg, t2, &dprm->orig,
- is_return);
- if (ret)
- kfree(dprm);
- else {
- f->fn = t->fetch[FETCH_MTD_deref];
- f->data = (void *)dprm;
- }
- }
- break;
- }
- if (!ret && !f->fn) { /* Parsed, but do not find fetch method */
- pr_info("%s type has no corresponding fetch method.\n",
- t->name);
- ret = -EINVAL;
- }
- return ret;
-}
-
-#define BYTES_TO_BITS(nb) ((BITS_PER_LONG * (nb)) / sizeof(long))
-
-/* Bitfield type needs to be parsed into a fetch function */
-static int __parse_bitfield_probe_arg(const char *bf,
- const struct fetch_type *t,
- struct fetch_param *f)
-{
- struct bitfield_fetch_param *bprm;
- unsigned long bw, bo;
- char *tail;
-
- if (*bf != 'b')
- return 0;
-
- bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
- if (!bprm)
- return -ENOMEM;
- bprm->orig = *f;
- f->fn = t->fetch[FETCH_MTD_bitfield];
- f->data = (void *)bprm;
-
- bw = simple_strtoul(bf + 1, &tail, 0); /* Use simple one */
- if (bw == 0 || *tail != '@')
- return -EINVAL;
-
- bf = tail + 1;
- bo = simple_strtoul(bf, &tail, 0);
- if (tail == bf || *tail != '/')
- return -EINVAL;
-
- bprm->hi_shift = BYTES_TO_BITS(t->size) - (bw + bo);
- bprm->low_shift = bprm->hi_shift + bo;
- return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0;
-}
-
-/* String length checking wrapper */
-static int parse_probe_arg(char *arg, struct trace_probe *tp,
- struct probe_arg *parg, int is_return)
-{
- const char *t;
- int ret;
-
- if (strlen(arg) > MAX_ARGSTR_LEN) {
- pr_info("Argument is too long.: %s\n", arg);
- return -ENOSPC;
- }
- parg->comm = kstrdup(arg, GFP_KERNEL);
- if (!parg->comm) {
- pr_info("Failed to allocate memory for command '%s'.\n", arg);
- return -ENOMEM;
- }
- t = strchr(parg->comm, ':');
- if (t) {
- arg[t - parg->comm] = '\0';
- t++;
- }
- parg->type = find_fetch_type(t);
- if (!parg->type) {
- pr_info("Unsupported type: %s\n", t);
- return -EINVAL;
- }
- parg->offset = tp->size;
- tp->size += parg->type->size;
- ret = __parse_probe_arg(arg, parg->type, &parg->fetch, is_return);
- if (ret >= 0 && t != NULL)
- ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch);
- if (ret >= 0) {
- parg->fetch_size.fn = get_fetch_size_function(parg->type,
- parg->fetch.fn);
- parg->fetch_size.data = parg->fetch.data;
- }
- return ret;
-}
-
-/* Return 1 if name is reserved or already used by another argument */
-static int conflict_field_name(const char *name,
- struct probe_arg *args, int narg)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(reserved_field_names); i++)
- if (strcmp(reserved_field_names[i], name) == 0)
- return 1;
- for (i = 0; i < narg; i++)
- if (strcmp(args[i].name, name) == 0)
- return 1;
- return 0;
-}
-
static int create_trace_probe(int argc, char **argv)
{
/*
@@ -1162,7 +375,7 @@ static int create_trace_probe(int argc, char **argv)
*/
struct trace_probe *tp;
int i, ret = 0;
- int is_return = 0, is_delete = 0;
+ bool is_return = false, is_delete = false;
char *symbol = NULL, *event = NULL, *group = NULL;
char *arg;
unsigned long offset = 0;
@@ -1171,11 +384,11 @@ static int create_trace_probe(int argc, char **argv)
/* argc must be >= 1 */
if (argv[0][0] == 'p')
- is_return = 0;
+ is_return = false;
else if (argv[0][0] == 'r')
- is_return = 1;
+ is_return = true;
else if (argv[0][0] == '-')
- is_delete = 1;
+ is_delete = true;
else {
pr_info("Probe definition must be started with 'p', 'r' or"
" '-'.\n");
@@ -1240,7 +453,7 @@ static int create_trace_probe(int argc, char **argv)
/* a symbol specified */
symbol = argv[1];
/* TODO: support .init module functions */
- ret = split_symbol_offset(symbol, &offset);
+ ret = traceprobe_split_symbol_offset(symbol, &offset);
if (ret) {
pr_info("Failed to parse symbol.\n");
return ret;
@@ -1302,7 +515,8 @@ static int create_trace_probe(int argc, char **argv)
goto error;
}
- if (conflict_field_name(tp->args[i].name, tp->args, i)) {
+ if (traceprobe_conflict_field_name(tp->args[i].name,
+ tp->args, i)) {
pr_info("Argument[%d] name '%s' conflicts with "
"another field.\n", i, argv[i]);
ret = -EINVAL;
@@ -1310,7 +524,8 @@ static int create_trace_probe(int argc, char **argv)
}
/* Parse fetch argument */
- ret = parse_probe_arg(arg, tp, &tp->args[i], is_return);
+ ret = traceprobe_parse_probe_arg(arg, &tp->size, &tp->args[i],
+ is_return, true);
if (ret) {
pr_info("Parse error at argument[%d]. (%d)\n", i, ret);
goto error;
@@ -1412,70 +627,11 @@ static int probes_open(struct inode *inode, struct file *file)
return seq_open(file, &probes_seq_op);
}
-static int command_trace_probe(const char *buf)
-{
- char **argv;
- int argc = 0, ret = 0;
-
- argv = argv_split(GFP_KERNEL, buf, &argc);
- if (!argv)
- return -ENOMEM;
-
- if (argc)
- ret = create_trace_probe(argc, argv);
-
- argv_free(argv);
- return ret;
-}
-
-#define WRITE_BUFSIZE 4096
-
static ssize_t probes_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
- char *kbuf, *tmp;
- int ret;
- size_t done;
- size_t size;
-
- kbuf = kmalloc(WRITE_BUFSIZE, GFP_KERNEL);
- if (!kbuf)
- return -ENOMEM;
-
- ret = done = 0;
- while (done < count) {
- size = count - done;
- if (size >= WRITE_BUFSIZE)
- size = WRITE_BUFSIZE - 1;
- if (copy_from_user(kbuf, buffer + done, size)) {
- ret = -EFAULT;
- goto out;
- }
- kbuf[size] = '\0';
- tmp = strchr(kbuf, '\n');
- if (tmp) {
- *tmp = '\0';
- size = tmp - kbuf + 1;
- } else if (done + size < count) {
- pr_warning("Line length is too long: "
- "Should be less than %d.", WRITE_BUFSIZE);
- ret = -EINVAL;
- goto out;
- }
- done += size;
- /* Remove comments */
- tmp = strchr(kbuf, '#');
- if (tmp)
- *tmp = '\0';
-
- ret = command_trace_probe(kbuf);
- if (ret)
- goto out;
- }
- ret = done;
-out:
- kfree(kbuf);
- return ret;
+ return traceprobe_probes_write(file, buffer, count, ppos,
+ create_trace_probe);
}
static const struct file_operations kprobe_events_ops = {
@@ -1711,16 +867,6 @@ partial:
return TRACE_TYPE_PARTIAL_LINE;
}
-#undef DEFINE_FIELD
-#define DEFINE_FIELD(type, item, name, is_signed) \
- do { \
- ret = trace_define_field(event_call, #type, name, \
- offsetof(typeof(field), item), \
- sizeof(field.item), is_signed, \
- FILTER_OTHER); \
- if (ret) \
- return ret; \
- } while (0)
static int kprobe_event_define_fields(struct ftrace_event_call *event_call)
{
@@ -2051,8 +1197,9 @@ static __init int kprobe_trace_self_tests_init(void)
pr_info("Testing kprobe tracing: ");
- ret = command_trace_probe("p:testprobe kprobe_trace_selftest_target "
- "$stack $stack0 +0($stack)");
+ ret = traceprobe_command("p:testprobe kprobe_trace_selftest_target "
+ "$stack $stack0 +0($stack)",
+ create_trace_probe);
if (WARN_ON_ONCE(ret)) {
pr_warning("error on probing function entry.\n");
warn++;
@@ -2066,8 +1213,8 @@ static __init int kprobe_trace_self_tests_init(void)
enable_trace_probe(tp, TP_FLAG_TRACE);
}
- ret = command_trace_probe("r:testprobe2 kprobe_trace_selftest_target "
- "$retval");
+ ret = traceprobe_command("r:testprobe2 kprobe_trace_selftest_target "
+ "$retval", create_trace_probe);
if (WARN_ON_ONCE(ret)) {
pr_warning("error on probing function return.\n");
warn++;
@@ -2101,13 +1248,13 @@ static __init int kprobe_trace_self_tests_init(void)
} else
disable_trace_probe(tp, TP_FLAG_TRACE);
- ret = command_trace_probe("-:testprobe");
+ ret = traceprobe_command("-:testprobe", create_trace_probe);
if (WARN_ON_ONCE(ret)) {
pr_warning("error on deleting a probe.\n");
warn++;
}
- ret = command_trace_probe("-:testprobe2");
+ ret = traceprobe_command("-:testprobe2", create_trace_probe);
if (WARN_ON_ONCE(ret)) {
pr_warning("error on deleting a probe.\n");
warn++;
diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c
index 6fd4ffd042f9..a9077c1b4ad3 100644
--- a/kernel/trace/trace_printk.c
+++ b/kernel/trace/trace_printk.c
@@ -51,6 +51,10 @@ void hold_module_trace_bprintk_format(const char **start, const char **end)
const char **iter;
char *fmt;
+ /* allocate the trace_printk per cpu buffers */
+ if (start != end)
+ trace_printk_init_buffers();
+
mutex_lock(&btrace_mutex);
for (iter = start; iter < end; iter++) {
struct trace_bprintk_fmt *tb_fmt = lookup_format(*iter);
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
new file mode 100644
index 000000000000..daa9980153af
--- /dev/null
+++ b/kernel/trace/trace_probe.c
@@ -0,0 +1,839 @@
+/*
+ * Common code for probe-based Dynamic events.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * This code was copied from kernel/trace/trace_kprobe.c written by
+ * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
+ *
+ * Updates to make this generic:
+ * Copyright (C) IBM Corporation, 2010-2011
+ * Author: Srikar Dronamraju
+ */
+
+#include "trace_probe.h"
+
+const char *reserved_field_names[] = {
+ "common_type",
+ "common_flags",
+ "common_preempt_count",
+ "common_pid",
+ "common_tgid",
+ FIELD_STRING_IP,
+ FIELD_STRING_RETIP,
+ FIELD_STRING_FUNC,
+};
+
+/* Printing function type */
+#define PRINT_TYPE_FUNC_NAME(type) print_type_##type
+#define PRINT_TYPE_FMT_NAME(type) print_type_format_##type
+
+/* Printing in basic type function template */
+#define DEFINE_BASIC_PRINT_TYPE_FUNC(type, fmt, cast) \
+static __kprobes int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, \
+ const char *name, \
+ void *data, void *ent)\
+{ \
+ return trace_seq_printf(s, " %s=" fmt, name, (cast)*(type *)data);\
+} \
+static const char PRINT_TYPE_FMT_NAME(type)[] = fmt;
+
+DEFINE_BASIC_PRINT_TYPE_FUNC(u8, "%x", unsigned int)
+DEFINE_BASIC_PRINT_TYPE_FUNC(u16, "%x", unsigned int)
+DEFINE_BASIC_PRINT_TYPE_FUNC(u32, "%lx", unsigned long)
+DEFINE_BASIC_PRINT_TYPE_FUNC(u64, "%llx", unsigned long long)
+DEFINE_BASIC_PRINT_TYPE_FUNC(s8, "%d", int)
+DEFINE_BASIC_PRINT_TYPE_FUNC(s16, "%d", int)
+DEFINE_BASIC_PRINT_TYPE_FUNC(s32, "%ld", long)
+DEFINE_BASIC_PRINT_TYPE_FUNC(s64, "%lld", long long)
+
+static inline void *get_rloc_data(u32 *dl)
+{
+ return (u8 *)dl + get_rloc_offs(*dl);
+}
+
+/* For data_loc conversion */
+static inline void *get_loc_data(u32 *dl, void *ent)
+{
+ return (u8 *)ent + get_rloc_offs(*dl);
+}
+
+/* For defining macros, define string/string_size types */
+typedef u32 string;
+typedef u32 string_size;
+
+/* Print type function for string type */
+static __kprobes int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s,
+ const char *name,
+ void *data, void *ent)
+{
+ int len = *(u32 *)data >> 16;
+
+ if (!len)
+ return trace_seq_printf(s, " %s=(fault)", name);
+ else
+ return trace_seq_printf(s, " %s=\"%s\"", name,
+ (const char *)get_loc_data(data, ent));
+}
+
+static const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\"";
+
+#define FETCH_FUNC_NAME(method, type) fetch_##method##_##type
+/*
+ * Define macro for basic types - we don't need to define s* types, because
+ * we have to care only about bitwidth at recording time.
+ */
+#define DEFINE_BASIC_FETCH_FUNCS(method) \
+DEFINE_FETCH_##method(u8) \
+DEFINE_FETCH_##method(u16) \
+DEFINE_FETCH_##method(u32) \
+DEFINE_FETCH_##method(u64)
+
+#define CHECK_FETCH_FUNCS(method, fn) \
+ (((FETCH_FUNC_NAME(method, u8) == fn) || \
+ (FETCH_FUNC_NAME(method, u16) == fn) || \
+ (FETCH_FUNC_NAME(method, u32) == fn) || \
+ (FETCH_FUNC_NAME(method, u64) == fn) || \
+ (FETCH_FUNC_NAME(method, string) == fn) || \
+ (FETCH_FUNC_NAME(method, string_size) == fn)) \
+ && (fn != NULL))
+
+/* Data fetch function templates */
+#define DEFINE_FETCH_reg(type) \
+static __kprobes void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs, \
+ void *offset, void *dest) \
+{ \
+ *(type *)dest = (type)regs_get_register(regs, \
+ (unsigned int)((unsigned long)offset)); \
+}
+DEFINE_BASIC_FETCH_FUNCS(reg)
+/* No string on the register */
+#define fetch_reg_string NULL
+#define fetch_reg_string_size NULL
+
+#define DEFINE_FETCH_stack(type) \
+static __kprobes void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs,\
+ void *offset, void *dest) \
+{ \
+ *(type *)dest = (type)regs_get_kernel_stack_nth(regs, \
+ (unsigned int)((unsigned long)offset)); \
+}
+DEFINE_BASIC_FETCH_FUNCS(stack)
+/* No string on the stack entry */
+#define fetch_stack_string NULL
+#define fetch_stack_string_size NULL
+
+#define DEFINE_FETCH_retval(type) \
+static __kprobes void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs,\
+ void *dummy, void *dest) \
+{ \
+ *(type *)dest = (type)regs_return_value(regs); \
+}
+DEFINE_BASIC_FETCH_FUNCS(retval)
+/* No string on the retval */
+#define fetch_retval_string NULL
+#define fetch_retval_string_size NULL
+
+#define DEFINE_FETCH_memory(type) \
+static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\
+ void *addr, void *dest) \
+{ \
+ type retval; \
+ if (probe_kernel_address(addr, retval)) \
+ *(type *)dest = 0; \
+ else \
+ *(type *)dest = retval; \
+}
+DEFINE_BASIC_FETCH_FUNCS(memory)
+/*
+ * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
+ * length and relative data location.
+ */
+static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
+ void *addr, void *dest)
+{
+ long ret;
+ int maxlen = get_rloc_len(*(u32 *)dest);
+ u8 *dst = get_rloc_data(dest);
+ u8 *src = addr;
+ mm_segment_t old_fs = get_fs();
+
+ if (!maxlen)
+ return;
+
+ /*
+ * Try to get string again, since the string can be changed while
+ * probing.
+ */
+ set_fs(KERNEL_DS);
+ pagefault_disable();
+
+ do
+ ret = __copy_from_user_inatomic(dst++, src++, 1);
+ while (dst[-1] && ret == 0 && src - (u8 *)addr < maxlen);
+
+ dst[-1] = '\0';
+ pagefault_enable();
+ set_fs(old_fs);
+
+ if (ret < 0) { /* Failed to fetch string */
+ ((u8 *)get_rloc_data(dest))[0] = '\0';
+ *(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest));
+ } else {
+ *(u32 *)dest = make_data_rloc(src - (u8 *)addr,
+ get_rloc_offs(*(u32 *)dest));
+ }
+}
+
+/* Return the length of string -- including null terminal byte */
+static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs,
+ void *addr, void *dest)
+{
+ mm_segment_t old_fs;
+ int ret, len = 0;
+ u8 c;
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ pagefault_disable();
+
+ do {
+ ret = __copy_from_user_inatomic(&c, (u8 *)addr + len, 1);
+ len++;
+ } while (c && ret == 0 && len < MAX_STRING_SIZE);
+
+ pagefault_enable();
+ set_fs(old_fs);
+
+ if (ret < 0) /* Failed to check the length */
+ *(u32 *)dest = 0;
+ else
+ *(u32 *)dest = len;
+}
+
+/* Memory fetching by symbol */
+struct symbol_cache {
+ char *symbol;
+ long offset;
+ unsigned long addr;
+};
+
+static unsigned long update_symbol_cache(struct symbol_cache *sc)
+{
+ sc->addr = (unsigned long)kallsyms_lookup_name(sc->symbol);
+
+ if (sc->addr)
+ sc->addr += sc->offset;
+
+ return sc->addr;
+}
+
+static void free_symbol_cache(struct symbol_cache *sc)
+{
+ kfree(sc->symbol);
+ kfree(sc);
+}
+
+static struct symbol_cache *alloc_symbol_cache(const char *sym, long offset)
+{
+ struct symbol_cache *sc;
+
+ if (!sym || strlen(sym) == 0)
+ return NULL;
+
+ sc = kzalloc(sizeof(struct symbol_cache), GFP_KERNEL);
+ if (!sc)
+ return NULL;
+
+ sc->symbol = kstrdup(sym, GFP_KERNEL);
+ if (!sc->symbol) {
+ kfree(sc);
+ return NULL;
+ }
+ sc->offset = offset;
+ update_symbol_cache(sc);
+
+ return sc;
+}
+
+#define DEFINE_FETCH_symbol(type) \
+static __kprobes void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs,\
+ void *data, void *dest) \
+{ \
+ struct symbol_cache *sc = data; \
+ if (sc->addr) \
+ fetch_memory_##type(regs, (void *)sc->addr, dest); \
+ else \
+ *(type *)dest = 0; \
+}
+DEFINE_BASIC_FETCH_FUNCS(symbol)
+DEFINE_FETCH_symbol(string)
+DEFINE_FETCH_symbol(string_size)
+
+/* Dereference memory access function */
+struct deref_fetch_param {
+ struct fetch_param orig;
+ long offset;
+};
+
+#define DEFINE_FETCH_deref(type) \
+static __kprobes void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs,\
+ void *data, void *dest) \
+{ \
+ struct deref_fetch_param *dprm = data; \
+ unsigned long addr; \
+ call_fetch(&dprm->orig, regs, &addr); \
+ if (addr) { \
+ addr += dprm->offset; \
+ fetch_memory_##type(regs, (void *)addr, dest); \
+ } else \
+ *(type *)dest = 0; \
+}
+DEFINE_BASIC_FETCH_FUNCS(deref)
+DEFINE_FETCH_deref(string)
+DEFINE_FETCH_deref(string_size)
+
+static __kprobes void update_deref_fetch_param(struct deref_fetch_param *data)
+{
+ if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
+ update_deref_fetch_param(data->orig.data);
+ else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
+ update_symbol_cache(data->orig.data);
+}
+
+static __kprobes void free_deref_fetch_param(struct deref_fetch_param *data)
+{
+ if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
+ free_deref_fetch_param(data->orig.data);
+ else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
+ free_symbol_cache(data->orig.data);
+ kfree(data);
+}
+
+/* Bitfield fetch function */
+struct bitfield_fetch_param {
+ struct fetch_param orig;
+ unsigned char hi_shift;
+ unsigned char low_shift;
+};
+
+#define DEFINE_FETCH_bitfield(type) \
+static __kprobes void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs,\
+ void *data, void *dest) \
+{ \
+ struct bitfield_fetch_param *bprm = data; \
+ type buf = 0; \
+ call_fetch(&bprm->orig, regs, &buf); \
+ if (buf) { \
+ buf <<= bprm->hi_shift; \
+ buf >>= bprm->low_shift; \
+ } \
+ *(type *)dest = buf; \
+}
+
+DEFINE_BASIC_FETCH_FUNCS(bitfield)
+#define fetch_bitfield_string NULL
+#define fetch_bitfield_string_size NULL
+
+static __kprobes void
+update_bitfield_fetch_param(struct bitfield_fetch_param *data)
+{
+ /*
+ * Don't check the bitfield itself, because this must be the
+ * last fetch function.
+ */
+ if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
+ update_deref_fetch_param(data->orig.data);
+ else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
+ update_symbol_cache(data->orig.data);
+}
+
+static __kprobes void
+free_bitfield_fetch_param(struct bitfield_fetch_param *data)
+{
+ /*
+ * Don't check the bitfield itself, because this must be the
+ * last fetch function.
+ */
+ if (CHECK_FETCH_FUNCS(deref, data->orig.fn))
+ free_deref_fetch_param(data->orig.data);
+ else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn))
+ free_symbol_cache(data->orig.data);
+
+ kfree(data);
+}
+
+/* Default (unsigned long) fetch type */
+#define __DEFAULT_FETCH_TYPE(t) u##t
+#define _DEFAULT_FETCH_TYPE(t) __DEFAULT_FETCH_TYPE(t)
+#define DEFAULT_FETCH_TYPE _DEFAULT_FETCH_TYPE(BITS_PER_LONG)
+#define DEFAULT_FETCH_TYPE_STR __stringify(DEFAULT_FETCH_TYPE)
+
+#define ASSIGN_FETCH_FUNC(method, type) \
+ [FETCH_MTD_##method] = FETCH_FUNC_NAME(method, type)
+
+#define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype) \
+ {.name = _name, \
+ .size = _size, \
+ .is_signed = sign, \
+ .print = PRINT_TYPE_FUNC_NAME(ptype), \
+ .fmt = PRINT_TYPE_FMT_NAME(ptype), \
+ .fmttype = _fmttype, \
+ .fetch = { \
+ASSIGN_FETCH_FUNC(reg, ftype), \
+ASSIGN_FETCH_FUNC(stack, ftype), \
+ASSIGN_FETCH_FUNC(retval, ftype), \
+ASSIGN_FETCH_FUNC(memory, ftype), \
+ASSIGN_FETCH_FUNC(symbol, ftype), \
+ASSIGN_FETCH_FUNC(deref, ftype), \
+ASSIGN_FETCH_FUNC(bitfield, ftype), \
+ } \
+ }
+
+#define ASSIGN_FETCH_TYPE(ptype, ftype, sign) \
+ __ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, #ptype)
+
+#define FETCH_TYPE_STRING 0
+#define FETCH_TYPE_STRSIZE 1
+
+/* Fetch type information table */
+static const struct fetch_type fetch_type_table[] = {
+ /* Special types */
+ [FETCH_TYPE_STRING] = __ASSIGN_FETCH_TYPE("string", string, string,
+ sizeof(u32), 1, "__data_loc char[]"),
+ [FETCH_TYPE_STRSIZE] = __ASSIGN_FETCH_TYPE("string_size", u32,
+ string_size, sizeof(u32), 0, "u32"),
+ /* Basic types */
+ ASSIGN_FETCH_TYPE(u8, u8, 0),
+ ASSIGN_FETCH_TYPE(u16, u16, 0),
+ ASSIGN_FETCH_TYPE(u32, u32, 0),
+ ASSIGN_FETCH_TYPE(u64, u64, 0),
+ ASSIGN_FETCH_TYPE(s8, u8, 1),
+ ASSIGN_FETCH_TYPE(s16, u16, 1),
+ ASSIGN_FETCH_TYPE(s32, u32, 1),
+ ASSIGN_FETCH_TYPE(s64, u64, 1),
+};
+
+static const struct fetch_type *find_fetch_type(const char *type)
+{
+ int i;
+
+ if (!type)
+ type = DEFAULT_FETCH_TYPE_STR;
+
+ /* Special case: bitfield */
+ if (*type == 'b') {
+ unsigned long bs;
+
+ type = strchr(type, '/');
+ if (!type)
+ goto fail;
+
+ type++;
+ if (strict_strtoul(type, 0, &bs))
+ goto fail;
+
+ switch (bs) {
+ case 8:
+ return find_fetch_type("u8");
+ case 16:
+ return find_fetch_type("u16");
+ case 32:
+ return find_fetch_type("u32");
+ case 64:
+ return find_fetch_type("u64");
+ default:
+ goto fail;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(fetch_type_table); i++)
+ if (strcmp(type, fetch_type_table[i].name) == 0)
+ return &fetch_type_table[i];
+
+fail:
+ return NULL;
+}
+
+/* Special function : only accept unsigned long */
+static __kprobes void fetch_stack_address(struct pt_regs *regs,
+ void *dummy, void *dest)
+{
+ *(unsigned long *)dest = kernel_stack_pointer(regs);
+}
+
+static fetch_func_t get_fetch_size_function(const struct fetch_type *type,
+ fetch_func_t orig_fn)
+{
+ int i;
+
+ if (type != &fetch_type_table[FETCH_TYPE_STRING])
+ return NULL; /* Only string type needs size function */
+
+ for (i = 0; i < FETCH_MTD_END; i++)
+ if (type->fetch[i] == orig_fn)
+ return fetch_type_table[FETCH_TYPE_STRSIZE].fetch[i];
+
+ WARN_ON(1); /* This should not happen */
+
+ return NULL;
+}
+
+/* Split symbol and offset. */
+int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset)
+{
+ char *tmp;
+ int ret;
+
+ if (!offset)
+ return -EINVAL;
+
+ tmp = strchr(symbol, '+');
+ if (tmp) {
+ /* skip sign because strict_strtol doesn't accept '+' */
+ ret = strict_strtoul(tmp + 1, 0, offset);
+ if (ret)
+ return ret;
+
+ *tmp = '\0';
+ } else
+ *offset = 0;
+
+ return 0;
+}
+
+#define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long))
+
+static int parse_probe_vars(char *arg, const struct fetch_type *t,
+ struct fetch_param *f, bool is_return)
+{
+ int ret = 0;
+ unsigned long param;
+
+ if (strcmp(arg, "retval") == 0) {
+ if (is_return)
+ f->fn = t->fetch[FETCH_MTD_retval];
+ else
+ ret = -EINVAL;
+ } else if (strncmp(arg, "stack", 5) == 0) {
+ if (arg[5] == '\0') {
+ if (strcmp(t->name, DEFAULT_FETCH_TYPE_STR) == 0)
+ f->fn = fetch_stack_address;
+ else
+ ret = -EINVAL;
+ } else if (isdigit(arg[5])) {
+ ret = strict_strtoul(arg + 5, 10, &param);
+ if (ret || param > PARAM_MAX_STACK)
+ ret = -EINVAL;
+ else {
+ f->fn = t->fetch[FETCH_MTD_stack];
+ f->data = (void *)param;
+ }
+ } else
+ ret = -EINVAL;
+ } else
+ ret = -EINVAL;
+
+ return ret;
+}
+
+/* Recursive argument parser */
+static int parse_probe_arg(char *arg, const struct fetch_type *t,
+ struct fetch_param *f, bool is_return, bool is_kprobe)
+{
+ unsigned long param;
+ long offset;
+ char *tmp;
+ int ret;
+
+ ret = 0;
+
+ /* Until uprobe_events supports only reg arguments */
+ if (!is_kprobe && arg[0] != '%')
+ return -EINVAL;
+
+ switch (arg[0]) {
+ case '$':
+ ret = parse_probe_vars(arg + 1, t, f, is_return);
+ break;
+
+ case '%': /* named register */
+ ret = regs_query_register_offset(arg + 1);
+ if (ret >= 0) {
+ f->fn = t->fetch[FETCH_MTD_reg];
+ f->data = (void *)(unsigned long)ret;
+ ret = 0;
+ }
+ break;
+
+ case '@': /* memory or symbol */
+ if (isdigit(arg[1])) {
+ ret = strict_strtoul(arg + 1, 0, &param);
+ if (ret)
+ break;
+
+ f->fn = t->fetch[FETCH_MTD_memory];
+ f->data = (void *)param;
+ } else {
+ ret = traceprobe_split_symbol_offset(arg + 1, &offset);
+ if (ret)
+ break;
+
+ f->data = alloc_symbol_cache(arg + 1, offset);
+ if (f->data)
+ f->fn = t->fetch[FETCH_MTD_symbol];
+ }
+ break;
+
+ case '+': /* deref memory */
+ arg++; /* Skip '+', because strict_strtol() rejects it. */
+ case '-':
+ tmp = strchr(arg, '(');
+ if (!tmp)
+ break;
+
+ *tmp = '\0';
+ ret = strict_strtol(arg, 0, &offset);
+
+ if (ret)
+ break;
+
+ arg = tmp + 1;
+ tmp = strrchr(arg, ')');
+
+ if (tmp) {
+ struct deref_fetch_param *dprm;
+ const struct fetch_type *t2;
+
+ t2 = find_fetch_type(NULL);
+ *tmp = '\0';
+ dprm = kzalloc(sizeof(struct deref_fetch_param), GFP_KERNEL);
+
+ if (!dprm)
+ return -ENOMEM;
+
+ dprm->offset = offset;
+ ret = parse_probe_arg(arg, t2, &dprm->orig, is_return,
+ is_kprobe);
+ if (ret)
+ kfree(dprm);
+ else {
+ f->fn = t->fetch[FETCH_MTD_deref];
+ f->data = (void *)dprm;
+ }
+ }
+ break;
+ }
+ if (!ret && !f->fn) { /* Parsed, but do not find fetch method */
+ pr_info("%s type has no corresponding fetch method.\n", t->name);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+#define BYTES_TO_BITS(nb) ((BITS_PER_LONG * (nb)) / sizeof(long))
+
+/* Bitfield type needs to be parsed into a fetch function */
+static int __parse_bitfield_probe_arg(const char *bf,
+ const struct fetch_type *t,
+ struct fetch_param *f)
+{
+ struct bitfield_fetch_param *bprm;
+ unsigned long bw, bo;
+ char *tail;
+
+ if (*bf != 'b')
+ return 0;
+
+ bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
+ if (!bprm)
+ return -ENOMEM;
+
+ bprm->orig = *f;
+ f->fn = t->fetch[FETCH_MTD_bitfield];
+ f->data = (void *)bprm;
+ bw = simple_strtoul(bf + 1, &tail, 0); /* Use simple one */
+
+ if (bw == 0 || *tail != '@')
+ return -EINVAL;
+
+ bf = tail + 1;
+ bo = simple_strtoul(bf, &tail, 0);
+
+ if (tail == bf || *tail != '/')
+ return -EINVAL;
+
+ bprm->hi_shift = BYTES_TO_BITS(t->size) - (bw + bo);
+ bprm->low_shift = bprm->hi_shift + bo;
+
+ return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0;
+}
+
+/* String length checking wrapper */
+int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
+ struct probe_arg *parg, bool is_return, bool is_kprobe)
+{
+ const char *t;
+ int ret;
+
+ if (strlen(arg) > MAX_ARGSTR_LEN) {
+ pr_info("Argument is too long.: %s\n", arg);
+ return -ENOSPC;
+ }
+ parg->comm = kstrdup(arg, GFP_KERNEL);
+ if (!parg->comm) {
+ pr_info("Failed to allocate memory for command '%s'.\n", arg);
+ return -ENOMEM;
+ }
+ t = strchr(parg->comm, ':');
+ if (t) {
+ arg[t - parg->comm] = '\0';
+ t++;
+ }
+ parg->type = find_fetch_type(t);
+ if (!parg->type) {
+ pr_info("Unsupported type: %s\n", t);
+ return -EINVAL;
+ }
+ parg->offset = *size;
+ *size += parg->type->size;
+ ret = parse_probe_arg(arg, parg->type, &parg->fetch, is_return, is_kprobe);
+
+ if (ret >= 0 && t != NULL)
+ ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch);
+
+ if (ret >= 0) {
+ parg->fetch_size.fn = get_fetch_size_function(parg->type,
+ parg->fetch.fn);
+ parg->fetch_size.data = parg->fetch.data;
+ }
+
+ return ret;
+}
+
+/* Return 1 if name is reserved or already used by another argument */
+int traceprobe_conflict_field_name(const char *name,
+ struct probe_arg *args, int narg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(reserved_field_names); i++)
+ if (strcmp(reserved_field_names[i], name) == 0)
+ return 1;
+
+ for (i = 0; i < narg; i++)
+ if (strcmp(args[i].name, name) == 0)
+ return 1;
+
+ return 0;
+}
+
+void traceprobe_update_arg(struct probe_arg *arg)
+{
+ if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn))
+ update_bitfield_fetch_param(arg->fetch.data);
+ else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn))
+ update_deref_fetch_param(arg->fetch.data);
+ else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn))
+ update_symbol_cache(arg->fetch.data);
+}
+
+void traceprobe_free_probe_arg(struct probe_arg *arg)
+{
+ if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn))
+ free_bitfield_fetch_param(arg->fetch.data);
+ else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn))
+ free_deref_fetch_param(arg->fetch.data);
+ else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn))
+ free_symbol_cache(arg->fetch.data);
+
+ kfree(arg->name);
+ kfree(arg->comm);
+}
+
+int traceprobe_command(const char *buf, int (*createfn)(int, char **))
+{
+ char **argv;
+ int argc, ret;
+
+ argc = 0;
+ ret = 0;
+ argv = argv_split(GFP_KERNEL, buf, &argc);
+ if (!argv)
+ return -ENOMEM;
+
+ if (argc)
+ ret = createfn(argc, argv);
+
+ argv_free(argv);
+
+ return ret;
+}
+
+#define WRITE_BUFSIZE 4096
+
+ssize_t traceprobe_probes_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos,
+ int (*createfn)(int, char **))
+{
+ char *kbuf, *tmp;
+ int ret = 0;
+ size_t done = 0;
+ size_t size;
+
+ kbuf = kmalloc(WRITE_BUFSIZE, GFP_KERNEL);
+ if (!kbuf)
+ return -ENOMEM;
+
+ while (done < count) {
+ size = count - done;
+
+ if (size >= WRITE_BUFSIZE)
+ size = WRITE_BUFSIZE - 1;
+
+ if (copy_from_user(kbuf, buffer + done, size)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ kbuf[size] = '\0';
+ tmp = strchr(kbuf, '\n');
+
+ if (tmp) {
+ *tmp = '\0';
+ size = tmp - kbuf + 1;
+ } else if (done + size < count) {
+ pr_warning("Line length is too long: "
+ "Should be less than %d.", WRITE_BUFSIZE);
+ ret = -EINVAL;
+ goto out;
+ }
+ done += size;
+ /* Remove comments */
+ tmp = strchr(kbuf, '#');
+
+ if (tmp)
+ *tmp = '\0';
+
+ ret = traceprobe_command(kbuf, createfn);
+ if (ret)
+ goto out;
+ }
+ ret = done;
+
+out:
+ kfree(kbuf);
+
+ return ret;
+}
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
new file mode 100644
index 000000000000..933708677814
--- /dev/null
+++ b/kernel/trace/trace_probe.h
@@ -0,0 +1,161 @@
+/*
+ * Common header file for probe-based Dynamic events.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * This code was copied from kernel/trace/trace_kprobe.h written by
+ * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
+ *
+ * Updates to make this generic:
+ * Copyright (C) IBM Corporation, 2010-2011
+ * Author: Srikar Dronamraju
+ */
+
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/debugfs.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/ptrace.h>
+#include <linux/perf_event.h>
+#include <linux/kprobes.h>
+#include <linux/stringify.h>
+#include <linux/limits.h>
+#include <linux/uaccess.h>
+#include <asm/bitsperlong.h>
+
+#include "trace.h"
+#include "trace_output.h"
+
+#define MAX_TRACE_ARGS 128
+#define MAX_ARGSTR_LEN 63
+#define MAX_EVENT_NAME_LEN 64
+#define MAX_STRING_SIZE PATH_MAX
+
+/* Reserved field names */
+#define FIELD_STRING_IP "__probe_ip"
+#define FIELD_STRING_RETIP "__probe_ret_ip"
+#define FIELD_STRING_FUNC "__probe_func"
+
+#undef DEFINE_FIELD
+#define DEFINE_FIELD(type, item, name, is_signed) \
+ do { \
+ ret = trace_define_field(event_call, #type, name, \
+ offsetof(typeof(field), item), \
+ sizeof(field.item), is_signed, \
+ FILTER_OTHER); \
+ if (ret) \
+ return ret; \
+ } while (0)
+
+
+/* Flags for trace_probe */
+#define TP_FLAG_TRACE 1
+#define TP_FLAG_PROFILE 2
+#define TP_FLAG_REGISTERED 4
+#define TP_FLAG_UPROBE 8
+
+
+/* data_rloc: data relative location, compatible with u32 */
+#define make_data_rloc(len, roffs) \
+ (((u32)(len) << 16) | ((u32)(roffs) & 0xffff))
+#define get_rloc_len(dl) ((u32)(dl) >> 16)
+#define get_rloc_offs(dl) ((u32)(dl) & 0xffff)
+
+/*
+ * Convert data_rloc to data_loc:
+ * data_rloc stores the offset from data_rloc itself, but data_loc
+ * stores the offset from event entry.
+ */
+#define convert_rloc_to_loc(dl, offs) ((u32)(dl) + (offs))
+
+/* Data fetch function type */
+typedef void (*fetch_func_t)(struct pt_regs *, void *, void *);
+/* Printing function type */
+typedef int (*print_type_func_t)(struct trace_seq *, const char *, void *, void *);
+
+/* Fetch types */
+enum {
+ FETCH_MTD_reg = 0,
+ FETCH_MTD_stack,
+ FETCH_MTD_retval,
+ FETCH_MTD_memory,
+ FETCH_MTD_symbol,
+ FETCH_MTD_deref,
+ FETCH_MTD_bitfield,
+ FETCH_MTD_END,
+};
+
+/* Fetch type information table */
+struct fetch_type {
+ const char *name; /* Name of type */
+ size_t size; /* Byte size of type */
+ int is_signed; /* Signed flag */
+ print_type_func_t print; /* Print functions */
+ const char *fmt; /* Fromat string */
+ const char *fmttype; /* Name in format file */
+ /* Fetch functions */
+ fetch_func_t fetch[FETCH_MTD_END];
+};
+
+struct fetch_param {
+ fetch_func_t fn;
+ void *data;
+};
+
+struct probe_arg {
+ struct fetch_param fetch;
+ struct fetch_param fetch_size;
+ unsigned int offset; /* Offset from argument entry */
+ const char *name; /* Name of this argument */
+ const char *comm; /* Command of this argument */
+ const struct fetch_type *type; /* Type of this argument */
+};
+
+static inline __kprobes void call_fetch(struct fetch_param *fprm,
+ struct pt_regs *regs, void *dest)
+{
+ return fprm->fn(regs, fprm->data, dest);
+}
+
+/* Check the name is good for event/group/fields */
+static inline int is_good_name(const char *name)
+{
+ if (!isalpha(*name) && *name != '_')
+ return 0;
+ while (*++name != '\0') {
+ if (!isalpha(*name) && !isdigit(*name) && *name != '_')
+ return 0;
+ }
+ return 1;
+}
+
+extern int traceprobe_parse_probe_arg(char *arg, ssize_t *size,
+ struct probe_arg *parg, bool is_return, bool is_kprobe);
+
+extern int traceprobe_conflict_field_name(const char *name,
+ struct probe_arg *args, int narg);
+
+extern void traceprobe_update_arg(struct probe_arg *arg);
+extern void traceprobe_free_probe_arg(struct probe_arg *arg);
+
+extern int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset);
+
+extern ssize_t traceprobe_probes_write(struct file *file,
+ const char __user *buffer, size_t count, loff_t *ppos,
+ int (*createfn)(int, char**));
+
+extern int traceprobe_command(const char *buf, int (*createfn)(int, char**));
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
new file mode 100644
index 000000000000..2b36ac68549e
--- /dev/null
+++ b/kernel/trace/trace_uprobe.c
@@ -0,0 +1,788 @@
+/*
+ * uprobes-based tracing events
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Copyright (C) IBM Corporation, 2010-2012
+ * Author: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
+ */
+
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/uprobes.h>
+#include <linux/namei.h>
+
+#include "trace_probe.h"
+
+#define UPROBE_EVENT_SYSTEM "uprobes"
+
+/*
+ * uprobe event core functions
+ */
+struct trace_uprobe;
+struct uprobe_trace_consumer {
+ struct uprobe_consumer cons;
+ struct trace_uprobe *tu;
+};
+
+struct trace_uprobe {
+ struct list_head list;
+ struct ftrace_event_class class;
+ struct ftrace_event_call call;
+ struct uprobe_trace_consumer *consumer;
+ struct inode *inode;
+ char *filename;
+ unsigned long offset;
+ unsigned long nhit;
+ unsigned int flags; /* For TP_FLAG_* */
+ ssize_t size; /* trace entry size */
+ unsigned int nr_args;
+ struct probe_arg args[];
+};
+
+#define SIZEOF_TRACE_UPROBE(n) \
+ (offsetof(struct trace_uprobe, args) + \
+ (sizeof(struct probe_arg) * (n)))
+
+static int register_uprobe_event(struct trace_uprobe *tu);
+static void unregister_uprobe_event(struct trace_uprobe *tu);
+
+static DEFINE_MUTEX(uprobe_lock);
+static LIST_HEAD(uprobe_list);
+
+static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs);
+
+/*
+ * Allocate new trace_uprobe and initialize it (including uprobes).
+ */
+static struct trace_uprobe *
+alloc_trace_uprobe(const char *group, const char *event, int nargs)
+{
+ struct trace_uprobe *tu;
+
+ if (!event || !is_good_name(event))
+ return ERR_PTR(-EINVAL);
+
+ if (!group || !is_good_name(group))
+ return ERR_PTR(-EINVAL);
+
+ tu = kzalloc(SIZEOF_TRACE_UPROBE(nargs), GFP_KERNEL);
+ if (!tu)
+ return ERR_PTR(-ENOMEM);
+
+ tu->call.class = &tu->class;
+ tu->call.name = kstrdup(event, GFP_KERNEL);
+ if (!tu->call.name)
+ goto error;
+
+ tu->class.system = kstrdup(group, GFP_KERNEL);
+ if (!tu->class.system)
+ goto error;
+
+ INIT_LIST_HEAD(&tu->list);
+ return tu;
+
+error:
+ kfree(tu->call.name);
+ kfree(tu);
+
+ return ERR_PTR(-ENOMEM);
+}
+
+static void free_trace_uprobe(struct trace_uprobe *tu)
+{
+ int i;
+
+ for (i = 0; i < tu->nr_args; i++)
+ traceprobe_free_probe_arg(&tu->args[i]);
+
+ iput(tu->inode);
+ kfree(tu->call.class->system);
+ kfree(tu->call.name);
+ kfree(tu->filename);
+ kfree(tu);
+}
+
+static struct trace_uprobe *find_probe_event(const char *event, const char *group)
+{
+ struct trace_uprobe *tu;
+
+ list_for_each_entry(tu, &uprobe_list, list)
+ if (strcmp(tu->call.name, event) == 0 &&
+ strcmp(tu->call.class->system, group) == 0)
+ return tu;
+
+ return NULL;
+}
+
+/* Unregister a trace_uprobe and probe_event: call with locking uprobe_lock */
+static void unregister_trace_uprobe(struct trace_uprobe *tu)
+{
+ list_del(&tu->list);
+ unregister_uprobe_event(tu);
+ free_trace_uprobe(tu);
+}
+
+/* Register a trace_uprobe and probe_event */
+static int register_trace_uprobe(struct trace_uprobe *tu)
+{
+ struct trace_uprobe *old_tp;
+ int ret;
+
+ mutex_lock(&uprobe_lock);
+
+ /* register as an event */
+ old_tp = find_probe_event(tu->call.name, tu->call.class->system);
+ if (old_tp)
+ /* delete old event */
+ unregister_trace_uprobe(old_tp);
+
+ ret = register_uprobe_event(tu);
+ if (ret) {
+ pr_warning("Failed to register probe event(%d)\n", ret);
+ goto end;
+ }
+
+ list_add_tail(&tu->list, &uprobe_list);
+
+end:
+ mutex_unlock(&uprobe_lock);
+
+ return ret;
+}
+
+/*
+ * Argument syntax:
+ * - Add uprobe: p[:[GRP/]EVENT] PATH:SYMBOL[+offs] [FETCHARGS]
+ *
+ * - Remove uprobe: -:[GRP/]EVENT
+ */
+static int create_trace_uprobe(int argc, char **argv)
+{
+ struct trace_uprobe *tu;
+ struct inode *inode;
+ char *arg, *event, *group, *filename;
+ char buf[MAX_EVENT_NAME_LEN];
+ struct path path;
+ unsigned long offset;
+ bool is_delete;
+ int i, ret;
+
+ inode = NULL;
+ ret = 0;
+ is_delete = false;
+ event = NULL;
+ group = NULL;
+
+ /* argc must be >= 1 */
+ if (argv[0][0] == '-')
+ is_delete = true;
+ else if (argv[0][0] != 'p') {
+ pr_info("Probe definition must be started with 'p', 'r' or" " '-'.\n");
+ return -EINVAL;
+ }
+
+ if (argv[0][1] == ':') {
+ event = &argv[0][2];
+ arg = strchr(event, '/');
+
+ if (arg) {
+ group = event;
+ event = arg + 1;
+ event[-1] = '\0';
+
+ if (strlen(group) == 0) {
+ pr_info("Group name is not specified\n");
+ return -EINVAL;
+ }
+ }
+ if (strlen(event) == 0) {
+ pr_info("Event name is not specified\n");
+ return -EINVAL;
+ }
+ }
+ if (!group)
+ group = UPROBE_EVENT_SYSTEM;
+
+ if (is_delete) {
+ if (!event) {
+ pr_info("Delete command needs an event name.\n");
+ return -EINVAL;
+ }
+ mutex_lock(&uprobe_lock);
+ tu = find_probe_event(event, group);
+
+ if (!tu) {
+ mutex_unlock(&uprobe_lock);
+ pr_info("Event %s/%s doesn't exist.\n", group, event);
+ return -ENOENT;
+ }
+ /* delete an event */
+ unregister_trace_uprobe(tu);
+ mutex_unlock(&uprobe_lock);
+ return 0;
+ }
+
+ if (argc < 2) {
+ pr_info("Probe point is not specified.\n");
+ return -EINVAL;
+ }
+ if (isdigit(argv[1][0])) {
+ pr_info("probe point must be have a filename.\n");
+ return -EINVAL;
+ }
+ arg = strchr(argv[1], ':');
+ if (!arg)
+ goto fail_address_parse;
+
+ *arg++ = '\0';
+ filename = argv[1];
+ ret = kern_path(filename, LOOKUP_FOLLOW, &path);
+ if (ret)
+ goto fail_address_parse;
+
+ ret = strict_strtoul(arg, 0, &offset);
+ if (ret)
+ goto fail_address_parse;
+
+ inode = igrab(path.dentry->d_inode);
+
+ argc -= 2;
+ argv += 2;
+
+ /* setup a probe */
+ if (!event) {
+ char *tail = strrchr(filename, '/');
+ char *ptr;
+
+ ptr = kstrdup((tail ? tail + 1 : filename), GFP_KERNEL);
+ if (!ptr) {
+ ret = -ENOMEM;
+ goto fail_address_parse;
+ }
+
+ tail = ptr;
+ ptr = strpbrk(tail, ".-_");
+ if (ptr)
+ *ptr = '\0';
+
+ snprintf(buf, MAX_EVENT_NAME_LEN, "%c_%s_0x%lx", 'p', tail, offset);
+ event = buf;
+ kfree(tail);
+ }
+
+ tu = alloc_trace_uprobe(group, event, argc);
+ if (IS_ERR(tu)) {
+ pr_info("Failed to allocate trace_uprobe.(%d)\n", (int)PTR_ERR(tu));
+ ret = PTR_ERR(tu);
+ goto fail_address_parse;
+ }
+ tu->offset = offset;
+ tu->inode = inode;
+ tu->filename = kstrdup(filename, GFP_KERNEL);
+
+ if (!tu->filename) {
+ pr_info("Failed to allocate filename.\n");
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ /* parse arguments */
+ ret = 0;
+ for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
+ /* Increment count for freeing args in error case */
+ tu->nr_args++;
+
+ /* Parse argument name */
+ arg = strchr(argv[i], '=');
+ if (arg) {
+ *arg++ = '\0';
+ tu->args[i].name = kstrdup(argv[i], GFP_KERNEL);
+ } else {
+ arg = argv[i];
+ /* If argument name is omitted, set "argN" */
+ snprintf(buf, MAX_EVENT_NAME_LEN, "arg%d", i + 1);
+ tu->args[i].name = kstrdup(buf, GFP_KERNEL);
+ }
+
+ if (!tu->args[i].name) {
+ pr_info("Failed to allocate argument[%d] name.\n", i);
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ if (!is_good_name(tu->args[i].name)) {
+ pr_info("Invalid argument[%d] name: %s\n", i, tu->args[i].name);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (traceprobe_conflict_field_name(tu->args[i].name, tu->args, i)) {
+ pr_info("Argument[%d] name '%s' conflicts with "
+ "another field.\n", i, argv[i]);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Parse fetch argument */
+ ret = traceprobe_parse_probe_arg(arg, &tu->size, &tu->args[i], false, false);
+ if (ret) {
+ pr_info("Parse error at argument[%d]. (%d)\n", i, ret);
+ goto error;
+ }
+ }
+
+ ret = register_trace_uprobe(tu);
+ if (ret)
+ goto error;
+ return 0;
+
+error:
+ free_trace_uprobe(tu);
+ return ret;
+
+fail_address_parse:
+ if (inode)
+ iput(inode);
+
+ pr_info("Failed to parse address.\n");
+
+ return ret;
+}
+
+static void cleanup_all_probes(void)
+{
+ struct trace_uprobe *tu;
+
+ mutex_lock(&uprobe_lock);
+ while (!list_empty(&uprobe_list)) {
+ tu = list_entry(uprobe_list.next, struct trace_uprobe, list);
+ unregister_trace_uprobe(tu);
+ }
+ mutex_unlock(&uprobe_lock);
+}
+
+/* Probes listing interfaces */
+static void *probes_seq_start(struct seq_file *m, loff_t *pos)
+{
+ mutex_lock(&uprobe_lock);
+ return seq_list_start(&uprobe_list, *pos);
+}
+
+static void *probes_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ return seq_list_next(v, &uprobe_list, pos);
+}
+
+static void probes_seq_stop(struct seq_file *m, void *v)
+{
+ mutex_unlock(&uprobe_lock);
+}
+
+static int probes_seq_show(struct seq_file *m, void *v)
+{
+ struct trace_uprobe *tu = v;
+ int i;
+
+ seq_printf(m, "p:%s/%s", tu->call.class->system, tu->call.name);
+ seq_printf(m, " %s:0x%p", tu->filename, (void *)tu->offset);
+
+ for (i = 0; i < tu->nr_args; i++)
+ seq_printf(m, " %s=%s", tu->args[i].name, tu->args[i].comm);
+
+ seq_printf(m, "\n");
+ return 0;
+}
+
+static const struct seq_operations probes_seq_op = {
+ .start = probes_seq_start,
+ .next = probes_seq_next,
+ .stop = probes_seq_stop,
+ .show = probes_seq_show
+};
+
+static int probes_open(struct inode *inode, struct file *file)
+{
+ if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC))
+ cleanup_all_probes();
+
+ return seq_open(file, &probes_seq_op);
+}
+
+static ssize_t probes_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ return traceprobe_probes_write(file, buffer, count, ppos, create_trace_uprobe);
+}
+
+static const struct file_operations uprobe_events_ops = {
+ .owner = THIS_MODULE,
+ .open = probes_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+ .write = probes_write,
+};
+
+/* Probes profiling interfaces */
+static int probes_profile_seq_show(struct seq_file *m, void *v)
+{
+ struct trace_uprobe *tu = v;
+
+ seq_printf(m, " %s %-44s %15lu\n", tu->filename, tu->call.name, tu->nhit);
+ return 0;
+}
+
+static const struct seq_operations profile_seq_op = {
+ .start = probes_seq_start,
+ .next = probes_seq_next,
+ .stop = probes_seq_stop,
+ .show = probes_profile_seq_show
+};
+
+static int profile_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &profile_seq_op);
+}
+
+static const struct file_operations uprobe_profile_ops = {
+ .owner = THIS_MODULE,
+ .open = profile_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/* uprobe handler */
+static void uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs)
+{
+ struct uprobe_trace_entry_head *entry;
+ struct ring_buffer_event *event;
+ struct ring_buffer *buffer;
+ u8 *data;
+ int size, i, pc;
+ unsigned long irq_flags;
+ struct ftrace_event_call *call = &tu->call;
+
+ tu->nhit++;
+
+ local_save_flags(irq_flags);
+ pc = preempt_count();
+
+ size = sizeof(*entry) + tu->size;
+
+ event = trace_current_buffer_lock_reserve(&buffer, call->event.type,
+ size, irq_flags, pc);
+ if (!event)
+ return;
+
+ entry = ring_buffer_event_data(event);
+ entry->ip = uprobe_get_swbp_addr(task_pt_regs(current));
+ data = (u8 *)&entry[1];
+ for (i = 0; i < tu->nr_args; i++)
+ call_fetch(&tu->args[i].fetch, regs, data + tu->args[i].offset);
+
+ if (!filter_current_check_discard(buffer, call, entry, event))
+ trace_buffer_unlock_commit(buffer, event, irq_flags, pc);
+}
+
+/* Event entry printers */
+static enum print_line_t
+print_uprobe_event(struct trace_iterator *iter, int flags, struct trace_event *event)
+{
+ struct uprobe_trace_entry_head *field;
+ struct trace_seq *s = &iter->seq;
+ struct trace_uprobe *tu;
+ u8 *data;
+ int i;
+
+ field = (struct uprobe_trace_entry_head *)iter->ent;
+ tu = container_of(event, struct trace_uprobe, call.event);
+
+ if (!trace_seq_printf(s, "%s: (", tu->call.name))
+ goto partial;
+
+ if (!seq_print_ip_sym(s, field->ip, flags | TRACE_ITER_SYM_OFFSET))
+ goto partial;
+
+ if (!trace_seq_puts(s, ")"))
+ goto partial;
+
+ data = (u8 *)&field[1];
+ for (i = 0; i < tu->nr_args; i++) {
+ if (!tu->args[i].type->print(s, tu->args[i].name,
+ data + tu->args[i].offset, field))
+ goto partial;
+ }
+
+ if (trace_seq_puts(s, "\n"))
+ return TRACE_TYPE_HANDLED;
+
+partial:
+ return TRACE_TYPE_PARTIAL_LINE;
+}
+
+static int probe_event_enable(struct trace_uprobe *tu, int flag)
+{
+ struct uprobe_trace_consumer *utc;
+ int ret = 0;
+
+ if (!tu->inode || tu->consumer)
+ return -EINTR;
+
+ utc = kzalloc(sizeof(struct uprobe_trace_consumer), GFP_KERNEL);
+ if (!utc)
+ return -EINTR;
+
+ utc->cons.handler = uprobe_dispatcher;
+ utc->cons.filter = NULL;
+ ret = uprobe_register(tu->inode, tu->offset, &utc->cons);
+ if (ret) {
+ kfree(utc);
+ return ret;
+ }
+
+ tu->flags |= flag;
+ utc->tu = tu;
+ tu->consumer = utc;
+
+ return 0;
+}
+
+static void probe_event_disable(struct trace_uprobe *tu, int flag)
+{
+ if (!tu->inode || !tu->consumer)
+ return;
+
+ uprobe_unregister(tu->inode, tu->offset, &tu->consumer->cons);
+ tu->flags &= ~flag;
+ kfree(tu->consumer);
+ tu->consumer = NULL;
+}
+
+static int uprobe_event_define_fields(struct ftrace_event_call *event_call)
+{
+ int ret, i;
+ struct uprobe_trace_entry_head field;
+ struct trace_uprobe *tu = (struct trace_uprobe *)event_call->data;
+
+ DEFINE_FIELD(unsigned long, ip, FIELD_STRING_IP, 0);
+ /* Set argument names as fields */
+ for (i = 0; i < tu->nr_args; i++) {
+ ret = trace_define_field(event_call, tu->args[i].type->fmttype,
+ tu->args[i].name,
+ sizeof(field) + tu->args[i].offset,
+ tu->args[i].type->size,
+ tu->args[i].type->is_signed,
+ FILTER_OTHER);
+
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+#define LEN_OR_ZERO (len ? len - pos : 0)
+static int __set_print_fmt(struct trace_uprobe *tu, char *buf, int len)
+{
+ const char *fmt, *arg;
+ int i;
+ int pos = 0;
+
+ fmt = "(%lx)";
+ arg = "REC->" FIELD_STRING_IP;
+
+ /* When len=0, we just calculate the needed length */
+
+ pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", fmt);
+
+ for (i = 0; i < tu->nr_args; i++) {
+ pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=%s",
+ tu->args[i].name, tu->args[i].type->fmt);
+ }
+
+ pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg);
+
+ for (i = 0; i < tu->nr_args; i++) {
+ pos += snprintf(buf + pos, LEN_OR_ZERO, ", REC->%s",
+ tu->args[i].name);
+ }
+
+ return pos; /* return the length of print_fmt */
+}
+#undef LEN_OR_ZERO
+
+static int set_print_fmt(struct trace_uprobe *tu)
+{
+ char *print_fmt;
+ int len;
+
+ /* First: called with 0 length to calculate the needed length */
+ len = __set_print_fmt(tu, NULL, 0);
+ print_fmt = kmalloc(len + 1, GFP_KERNEL);
+ if (!print_fmt)
+ return -ENOMEM;
+
+ /* Second: actually write the @print_fmt */
+ __set_print_fmt(tu, print_fmt, len + 1);
+ tu->call.print_fmt = print_fmt;
+
+ return 0;
+}
+
+#ifdef CONFIG_PERF_EVENTS
+/* uprobe profile handler */
+static void uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs)
+{
+ struct ftrace_event_call *call = &tu->call;
+ struct uprobe_trace_entry_head *entry;
+ struct hlist_head *head;
+ u8 *data;
+ int size, __size, i;
+ int rctx;
+
+ __size = sizeof(*entry) + tu->size;
+ size = ALIGN(__size + sizeof(u32), sizeof(u64));
+ size -= sizeof(u32);
+ if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, "profile buffer not large enough"))
+ return;
+
+ preempt_disable();
+
+ entry = perf_trace_buf_prepare(size, call->event.type, regs, &rctx);
+ if (!entry)
+ goto out;
+
+ entry->ip = uprobe_get_swbp_addr(task_pt_regs(current));
+ data = (u8 *)&entry[1];
+ for (i = 0; i < tu->nr_args; i++)
+ call_fetch(&tu->args[i].fetch, regs, data + tu->args[i].offset);
+
+ head = this_cpu_ptr(call->perf_events);
+ perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, regs, head);
+
+ out:
+ preempt_enable();
+}
+#endif /* CONFIG_PERF_EVENTS */
+
+static
+int trace_uprobe_register(struct ftrace_event_call *event, enum trace_reg type, void *data)
+{
+ struct trace_uprobe *tu = (struct trace_uprobe *)event->data;
+
+ switch (type) {
+ case TRACE_REG_REGISTER:
+ return probe_event_enable(tu, TP_FLAG_TRACE);
+
+ case TRACE_REG_UNREGISTER:
+ probe_event_disable(tu, TP_FLAG_TRACE);
+ return 0;
+
+#ifdef CONFIG_PERF_EVENTS
+ case TRACE_REG_PERF_REGISTER:
+ return probe_event_enable(tu, TP_FLAG_PROFILE);
+
+ case TRACE_REG_PERF_UNREGISTER:
+ probe_event_disable(tu, TP_FLAG_PROFILE);
+ return 0;
+#endif
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs)
+{
+ struct uprobe_trace_consumer *utc;
+ struct trace_uprobe *tu;
+
+ utc = container_of(con, struct uprobe_trace_consumer, cons);
+ tu = utc->tu;
+ if (!tu || tu->consumer != utc)
+ return 0;
+
+ if (tu->flags & TP_FLAG_TRACE)
+ uprobe_trace_func(tu, regs);
+
+#ifdef CONFIG_PERF_EVENTS
+ if (tu->flags & TP_FLAG_PROFILE)
+ uprobe_perf_func(tu, regs);
+#endif
+ return 0;
+}
+
+static struct trace_event_functions uprobe_funcs = {
+ .trace = print_uprobe_event
+};
+
+static int register_uprobe_event(struct trace_uprobe *tu)
+{
+ struct ftrace_event_call *call = &tu->call;
+ int ret;
+
+ /* Initialize ftrace_event_call */
+ INIT_LIST_HEAD(&call->class->fields);
+ call->event.funcs = &uprobe_funcs;
+ call->class->define_fields = uprobe_event_define_fields;
+
+ if (set_print_fmt(tu) < 0)
+ return -ENOMEM;
+
+ ret = register_ftrace_event(&call->event);
+ if (!ret) {
+ kfree(call->print_fmt);
+ return -ENODEV;
+ }
+ call->flags = 0;
+ call->class->reg = trace_uprobe_register;
+ call->data = tu;
+ ret = trace_add_event_call(call);
+
+ if (ret) {
+ pr_info("Failed to register uprobe event: %s\n", call->name);
+ kfree(call->print_fmt);
+ unregister_ftrace_event(&call->event);
+ }
+
+ return ret;
+}
+
+static void unregister_uprobe_event(struct trace_uprobe *tu)
+{
+ /* tu->event is unregistered in trace_remove_event_call() */
+ trace_remove_event_call(&tu->call);
+ kfree(tu->call.print_fmt);
+ tu->call.print_fmt = NULL;
+}
+
+/* Make a trace interface for controling probe points */
+static __init int init_uprobe_trace(void)
+{
+ struct dentry *d_tracer;
+
+ d_tracer = tracing_init_dentry();
+ if (!d_tracer)
+ return 0;
+
+ trace_create_file("uprobe_events", 0644, d_tracer,
+ NULL, &uprobe_events_ops);
+ /* Profile interface */
+ trace_create_file("uprobe_profile", 0444, d_tracer,
+ NULL, &uprobe_profile_ops);
+ return 0;
+}
+
+fs_initcall(init_uprobe_trace);
diff --git a/kernel/trace/trace_workqueue.c b/kernel/trace/trace_workqueue.c
deleted file mode 100644
index 209b379a4721..000000000000
--- a/kernel/trace/trace_workqueue.c
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Workqueue statistical tracer.
- *
- * Copyright (C) 2008 Frederic Weisbecker <fweisbec@gmail.com>
- *
- */
-
-
-#include <trace/events/workqueue.h>
-#include <linux/list.h>
-#include <linux/percpu.h>
-#include <linux/slab.h>
-#include <linux/kref.h>
-#include "trace_stat.h"
-#include "trace.h"
-
-
-/* A cpu workqueue thread */
-struct cpu_workqueue_stats {
- struct list_head list;
- struct kref kref;
- int cpu;
- pid_t pid;
-/* Can be inserted from interrupt or user context, need to be atomic */
- atomic_t inserted;
-/*
- * Don't need to be atomic, works are serialized in a single workqueue thread
- * on a single CPU.
- */
- unsigned int executed;
-};
-
-/* List of workqueue threads on one cpu */
-struct workqueue_global_stats {
- struct list_head list;
- spinlock_t lock;
-};
-
-/* Don't need a global lock because allocated before the workqueues, and
- * never freed.
- */
-static DEFINE_PER_CPU(struct workqueue_global_stats, all_workqueue_stat);
-#define workqueue_cpu_stat(cpu) (&per_cpu(all_workqueue_stat, cpu))
-
-static void cpu_workqueue_stat_free(struct kref *kref)
-{
- kfree(container_of(kref, struct cpu_workqueue_stats, kref));
-}
-
-/* Insertion of a work */
-static void
-probe_workqueue_insertion(void *ignore,
- struct task_struct *wq_thread,
- struct work_struct *work)
-{
- int cpu = cpumask_first(&wq_thread->cpus_allowed);
- struct cpu_workqueue_stats *node;
- unsigned long flags;
-
- spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
- list_for_each_entry(node, &workqueue_cpu_stat(cpu)->list, list) {
- if (node->pid == wq_thread->pid) {
- atomic_inc(&node->inserted);
- goto found;
- }
- }
- pr_debug("trace_workqueue: entry not found\n");
-found:
- spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
-}
-
-/* Execution of a work */
-static void
-probe_workqueue_execution(void *ignore,
- struct task_struct *wq_thread,
- struct work_struct *work)
-{
- int cpu = cpumask_first(&wq_thread->cpus_allowed);
- struct cpu_workqueue_stats *node;
- unsigned long flags;
-
- spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
- list_for_each_entry(node, &workqueue_cpu_stat(cpu)->list, list) {
- if (node->pid == wq_thread->pid) {
- node->executed++;
- goto found;
- }
- }
- pr_debug("trace_workqueue: entry not found\n");
-found:
- spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
-}
-
-/* Creation of a cpu workqueue thread */
-static void probe_workqueue_creation(void *ignore,
- struct task_struct *wq_thread, int cpu)
-{
- struct cpu_workqueue_stats *cws;
- unsigned long flags;
-
- WARN_ON(cpu < 0);
-
- /* Workqueues are sometimes created in atomic context */
- cws = kzalloc(sizeof(struct cpu_workqueue_stats), GFP_ATOMIC);
- if (!cws) {
- pr_warning("trace_workqueue: not enough memory\n");
- return;
- }
- INIT_LIST_HEAD(&cws->list);
- kref_init(&cws->kref);
- cws->cpu = cpu;
- cws->pid = wq_thread->pid;
-
- spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
- list_add_tail(&cws->list, &workqueue_cpu_stat(cpu)->list);
- spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
-}
-
-/* Destruction of a cpu workqueue thread */
-static void
-probe_workqueue_destruction(void *ignore, struct task_struct *wq_thread)
-{
- /* Workqueue only execute on one cpu */
- int cpu = cpumask_first(&wq_thread->cpus_allowed);
- struct cpu_workqueue_stats *node, *next;
- unsigned long flags;
-
- spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
- list_for_each_entry_safe(node, next, &workqueue_cpu_stat(cpu)->list,
- list) {
- if (node->pid == wq_thread->pid) {
- list_del(&node->list);
- kref_put(&node->kref, cpu_workqueue_stat_free);
- goto found;
- }
- }
-
- pr_debug("trace_workqueue: don't find workqueue to destroy\n");
-found:
- spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
-
-}
-
-static struct cpu_workqueue_stats *workqueue_stat_start_cpu(int cpu)
-{
- unsigned long flags;
- struct cpu_workqueue_stats *ret = NULL;
-
-
- spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
-
- if (!list_empty(&workqueue_cpu_stat(cpu)->list)) {
- ret = list_entry(workqueue_cpu_stat(cpu)->list.next,
- struct cpu_workqueue_stats, list);
- kref_get(&ret->kref);
- }
-
- spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
-
- return ret;
-}
-
-static void *workqueue_stat_start(struct tracer_stat *trace)
-{
- int cpu;
- void *ret = NULL;
-
- for_each_possible_cpu(cpu) {
- ret = workqueue_stat_start_cpu(cpu);
- if (ret)
- return ret;
- }
- return NULL;
-}
-
-static void *workqueue_stat_next(void *prev, int idx)
-{
- struct cpu_workqueue_stats *prev_cws = prev;
- struct cpu_workqueue_stats *ret;
- int cpu = prev_cws->cpu;
- unsigned long flags;
-
- spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
- if (list_is_last(&prev_cws->list, &workqueue_cpu_stat(cpu)->list)) {
- spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
- do {
- cpu = cpumask_next(cpu, cpu_possible_mask);
- if (cpu >= nr_cpu_ids)
- return NULL;
- } while (!(ret = workqueue_stat_start_cpu(cpu)));
- return ret;
- } else {
- ret = list_entry(prev_cws->list.next,
- struct cpu_workqueue_stats, list);
- kref_get(&ret->kref);
- }
- spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
-
- return ret;
-}
-
-static int workqueue_stat_show(struct seq_file *s, void *p)
-{
- struct cpu_workqueue_stats *cws = p;
- struct pid *pid;
- struct task_struct *tsk;
-
- pid = find_get_pid(cws->pid);
- if (pid) {
- tsk = get_pid_task(pid, PIDTYPE_PID);
- if (tsk) {
- seq_printf(s, "%3d %6d %6u %s\n", cws->cpu,
- atomic_read(&cws->inserted), cws->executed,
- tsk->comm);
- put_task_struct(tsk);
- }
- put_pid(pid);
- }
-
- return 0;
-}
-
-static void workqueue_stat_release(void *stat)
-{
- struct cpu_workqueue_stats *node = stat;
-
- kref_put(&node->kref, cpu_workqueue_stat_free);
-}
-
-static int workqueue_stat_headers(struct seq_file *s)
-{
- seq_printf(s, "# CPU INSERTED EXECUTED NAME\n");
- seq_printf(s, "# | | | |\n");
- return 0;
-}
-
-struct tracer_stat workqueue_stats __read_mostly = {
- .name = "workqueues",
- .stat_start = workqueue_stat_start,
- .stat_next = workqueue_stat_next,
- .stat_show = workqueue_stat_show,
- .stat_release = workqueue_stat_release,
- .stat_headers = workqueue_stat_headers
-};
-
-
-int __init stat_workqueue_init(void)
-{
- if (register_stat_tracer(&workqueue_stats)) {
- pr_warning("Unable to register workqueue stat tracer\n");
- return 1;
- }
-
- return 0;
-}
-fs_initcall(stat_workqueue_init);
-
-/*
- * Workqueues are created very early, just after pre-smp initcalls.
- * So we must register our tracepoints at this stage.
- */
-int __init trace_workqueue_early_init(void)
-{
- int ret, cpu;
-
- for_each_possible_cpu(cpu) {
- spin_lock_init(&workqueue_cpu_stat(cpu)->lock);
- INIT_LIST_HEAD(&workqueue_cpu_stat(cpu)->list);
- }
-
- ret = register_trace_workqueue_insertion(probe_workqueue_insertion, NULL);
- if (ret)
- goto out;
-
- ret = register_trace_workqueue_execution(probe_workqueue_execution, NULL);
- if (ret)
- goto no_insertion;
-
- ret = register_trace_workqueue_creation(probe_workqueue_creation, NULL);
- if (ret)
- goto no_execution;
-
- ret = register_trace_workqueue_destruction(probe_workqueue_destruction, NULL);
- if (ret)
- goto no_creation;
-
- return 0;
-
-no_creation:
- unregister_trace_workqueue_creation(probe_workqueue_creation, NULL);
-no_execution:
- unregister_trace_workqueue_execution(probe_workqueue_execution, NULL);
-no_insertion:
- unregister_trace_workqueue_insertion(probe_workqueue_insertion, NULL);
-out:
- pr_warning("trace_workqueue: unable to trace workqueues\n");
-
- return 1;
-}
-early_initcall(trace_workqueue_early_init);
diff --git a/kernel/uid16.c b/kernel/uid16.c
index 51c6e89e8619..d7948eb10225 100644
--- a/kernel/uid16.c
+++ b/kernel/uid16.c
@@ -81,14 +81,19 @@ SYSCALL_DEFINE3(setresuid16, old_uid_t, ruid, old_uid_t, euid, old_uid_t, suid)
return ret;
}
-SYSCALL_DEFINE3(getresuid16, old_uid_t __user *, ruid, old_uid_t __user *, euid, old_uid_t __user *, suid)
+SYSCALL_DEFINE3(getresuid16, old_uid_t __user *, ruidp, old_uid_t __user *, euidp, old_uid_t __user *, suidp)
{
const struct cred *cred = current_cred();
int retval;
+ old_uid_t ruid, euid, suid;
- if (!(retval = put_user(high2lowuid(cred->uid), ruid)) &&
- !(retval = put_user(high2lowuid(cred->euid), euid)))
- retval = put_user(high2lowuid(cred->suid), suid);
+ ruid = high2lowuid(from_kuid_munged(cred->user_ns, cred->uid));
+ euid = high2lowuid(from_kuid_munged(cred->user_ns, cred->euid));
+ suid = high2lowuid(from_kuid_munged(cred->user_ns, cred->suid));
+
+ if (!(retval = put_user(ruid, ruidp)) &&
+ !(retval = put_user(euid, euidp)))
+ retval = put_user(suid, suidp);
return retval;
}
@@ -103,14 +108,19 @@ SYSCALL_DEFINE3(setresgid16, old_gid_t, rgid, old_gid_t, egid, old_gid_t, sgid)
}
-SYSCALL_DEFINE3(getresgid16, old_gid_t __user *, rgid, old_gid_t __user *, egid, old_gid_t __user *, sgid)
+SYSCALL_DEFINE3(getresgid16, old_gid_t __user *, rgidp, old_gid_t __user *, egidp, old_gid_t __user *, sgidp)
{
const struct cred *cred = current_cred();
int retval;
+ old_gid_t rgid, egid, sgid;
+
+ rgid = high2lowgid(from_kgid_munged(cred->user_ns, cred->gid));
+ egid = high2lowgid(from_kgid_munged(cred->user_ns, cred->egid));
+ sgid = high2lowgid(from_kgid_munged(cred->user_ns, cred->sgid));
- if (!(retval = put_user(high2lowgid(cred->gid), rgid)) &&
- !(retval = put_user(high2lowgid(cred->egid), egid)))
- retval = put_user(high2lowgid(cred->sgid), sgid);
+ if (!(retval = put_user(rgid, rgidp)) &&
+ !(retval = put_user(egid, egidp)))
+ retval = put_user(sgid, sgidp);
return retval;
}
@@ -134,11 +144,14 @@ SYSCALL_DEFINE1(setfsgid16, old_gid_t, gid)
static int groups16_to_user(old_gid_t __user *grouplist,
struct group_info *group_info)
{
+ struct user_namespace *user_ns = current_user_ns();
int i;
old_gid_t group;
+ kgid_t kgid;
for (i = 0; i < group_info->ngroups; i++) {
- group = high2lowgid(GROUP_AT(group_info, i));
+ kgid = GROUP_AT(group_info, i);
+ group = high2lowgid(from_kgid_munged(user_ns, kgid));
if (put_user(group, grouplist+i))
return -EFAULT;
}
@@ -149,13 +162,20 @@ static int groups16_to_user(old_gid_t __user *grouplist,
static int groups16_from_user(struct group_info *group_info,
old_gid_t __user *grouplist)
{
+ struct user_namespace *user_ns = current_user_ns();
int i;
old_gid_t group;
+ kgid_t kgid;
for (i = 0; i < group_info->ngroups; i++) {
if (get_user(group, grouplist+i))
return -EFAULT;
- GROUP_AT(group_info, i) = low2highgid(group);
+
+ kgid = make_kgid(user_ns, low2highgid(group));
+ if (!gid_valid(kgid))
+ return -EINVAL;
+
+ GROUP_AT(group_info, i) = kgid;
}
return 0;
@@ -211,20 +231,20 @@ SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t __user *, grouplist)
SYSCALL_DEFINE0(getuid16)
{
- return high2lowuid(current_uid());
+ return high2lowuid(from_kuid_munged(current_user_ns(), current_uid()));
}
SYSCALL_DEFINE0(geteuid16)
{
- return high2lowuid(current_euid());
+ return high2lowuid(from_kuid_munged(current_user_ns(), current_euid()));
}
SYSCALL_DEFINE0(getgid16)
{
- return high2lowgid(current_gid());
+ return high2lowgid(from_kgid_munged(current_user_ns(), current_gid()));
}
SYSCALL_DEFINE0(getegid16)
{
- return high2lowgid(current_egid());
+ return high2lowgid(from_kgid_munged(current_user_ns(), current_egid()));
}
diff --git a/kernel/user.c b/kernel/user.c
index 71dd2363ab0f..b815fefbe76f 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -22,10 +22,27 @@
* and 1 for... ?
*/
struct user_namespace init_user_ns = {
+ .uid_map = {
+ .nr_extents = 1,
+ .extent[0] = {
+ .first = 0,
+ .lower_first = 0,
+ .count = 4294967295U,
+ },
+ },
+ .gid_map = {
+ .nr_extents = 1,
+ .extent[0] = {
+ .first = 0,
+ .lower_first = 0,
+ .count = 4294967295U,
+ },
+ },
.kref = {
.refcount = ATOMIC_INIT(3),
},
- .creator = &root_user,
+ .owner = GLOBAL_ROOT_UID,
+ .group = GLOBAL_ROOT_GID,
};
EXPORT_SYMBOL_GPL(init_user_ns);
@@ -34,11 +51,14 @@ EXPORT_SYMBOL_GPL(init_user_ns);
* when changing user ID's (ie setuid() and friends).
*/
+#define UIDHASH_BITS (CONFIG_BASE_SMALL ? 3 : 7)
+#define UIDHASH_SZ (1 << UIDHASH_BITS)
#define UIDHASH_MASK (UIDHASH_SZ - 1)
#define __uidhashfn(uid) (((uid >> UIDHASH_BITS) + uid) & UIDHASH_MASK)
-#define uidhashentry(ns, uid) ((ns)->uidhash_table + __uidhashfn((uid)))
+#define uidhashentry(uid) (uidhash_table + __uidhashfn((__kuid_val(uid))))
static struct kmem_cache *uid_cachep;
+struct hlist_head uidhash_table[UIDHASH_SZ];
/*
* The uidhash_lock is mostly taken from process context, but it is
@@ -51,14 +71,14 @@ static struct kmem_cache *uid_cachep;
*/
static DEFINE_SPINLOCK(uidhash_lock);
-/* root_user.__count is 2, 1 for init task cred, 1 for init_user_ns->user_ns */
+/* root_user.__count is 1, for init task cred */
struct user_struct root_user = {
- .__count = ATOMIC_INIT(2),
+ .__count = ATOMIC_INIT(1),
.processes = ATOMIC_INIT(1),
.files = ATOMIC_INIT(0),
.sigpending = ATOMIC_INIT(0),
.locked_shm = 0,
- .user_ns = &init_user_ns,
+ .uid = GLOBAL_ROOT_UID,
};
/*
@@ -72,16 +92,15 @@ static void uid_hash_insert(struct user_struct *up, struct hlist_head *hashent)
static void uid_hash_remove(struct user_struct *up)
{
hlist_del_init(&up->uidhash_node);
- put_user_ns(up->user_ns);
}
-static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent)
+static struct user_struct *uid_hash_find(kuid_t uid, struct hlist_head *hashent)
{
struct user_struct *user;
struct hlist_node *h;
hlist_for_each_entry(user, h, hashent, uidhash_node) {
- if (user->uid == uid) {
+ if (uid_eq(user->uid, uid)) {
atomic_inc(&user->__count);
return user;
}
@@ -110,14 +129,13 @@ static void free_user(struct user_struct *up, unsigned long flags)
*
* If the user_struct could not be found, return NULL.
*/
-struct user_struct *find_user(uid_t uid)
+struct user_struct *find_user(kuid_t uid)
{
struct user_struct *ret;
unsigned long flags;
- struct user_namespace *ns = current_user_ns();
spin_lock_irqsave(&uidhash_lock, flags);
- ret = uid_hash_find(uid, uidhashentry(ns, uid));
+ ret = uid_hash_find(uid, uidhashentry(uid));
spin_unlock_irqrestore(&uidhash_lock, flags);
return ret;
}
@@ -136,9 +154,9 @@ void free_uid(struct user_struct *up)
local_irq_restore(flags);
}
-struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid)
+struct user_struct *alloc_uid(kuid_t uid)
{
- struct hlist_head *hashent = uidhashentry(ns, uid);
+ struct hlist_head *hashent = uidhashentry(uid);
struct user_struct *up, *new;
spin_lock_irq(&uidhash_lock);
@@ -153,8 +171,6 @@ struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid)
new->uid = uid;
atomic_set(&new->__count, 1);
- new->user_ns = get_user_ns(ns);
-
/*
* Before adding this, check whether we raced
* on adding the same user already..
@@ -162,7 +178,6 @@ struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid)
spin_lock_irq(&uidhash_lock);
up = uid_hash_find(uid, hashent);
if (up) {
- put_user_ns(ns);
key_put(new->uid_keyring);
key_put(new->session_keyring);
kmem_cache_free(uid_cachep, new);
@@ -187,11 +202,11 @@ static int __init uid_cache_init(void)
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
for(n = 0; n < UIDHASH_SZ; ++n)
- INIT_HLIST_HEAD(init_user_ns.uidhash_table + n);
+ INIT_HLIST_HEAD(uidhash_table + n);
/* Insert the root user immediately (init already runs as root) */
spin_lock_irq(&uidhash_lock);
- uid_hash_insert(&root_user, uidhashentry(&init_user_ns, 0));
+ uid_hash_insert(&root_user, uidhashentry(GLOBAL_ROOT_UID));
spin_unlock_irq(&uidhash_lock);
return 0;
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 3b906e98b1db..86602316422d 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -11,9 +11,20 @@
#include <linux/user_namespace.h>
#include <linux/highuid.h>
#include <linux/cred.h>
+#include <linux/securebits.h>
+#include <linux/keyctl.h>
+#include <linux/key-type.h>
+#include <keys/user-type.h>
+#include <linux/seq_file.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/ctype.h>
static struct kmem_cache *user_ns_cachep __read_mostly;
+static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
+ struct uid_gid_map *map);
+
/*
* Create a new user namespace, deriving the creator from the user in the
* passed credentials, and replacing that user with the new root user for the
@@ -24,109 +35,565 @@ static struct kmem_cache *user_ns_cachep __read_mostly;
*/
int create_user_ns(struct cred *new)
{
- struct user_namespace *ns;
- struct user_struct *root_user;
- int n;
+ struct user_namespace *ns, *parent_ns = new->user_ns;
+ kuid_t owner = new->euid;
+ kgid_t group = new->egid;
+
+ /* The creator needs a mapping in the parent user namespace
+ * or else we won't be able to reasonably tell userspace who
+ * created a user_namespace.
+ */
+ if (!kuid_has_mapping(parent_ns, owner) ||
+ !kgid_has_mapping(parent_ns, group))
+ return -EPERM;
- ns = kmem_cache_alloc(user_ns_cachep, GFP_KERNEL);
+ ns = kmem_cache_zalloc(user_ns_cachep, GFP_KERNEL);
if (!ns)
return -ENOMEM;
kref_init(&ns->kref);
+ ns->parent = parent_ns;
+ ns->owner = owner;
+ ns->group = group;
- for (n = 0; n < UIDHASH_SZ; ++n)
- INIT_HLIST_HEAD(ns->uidhash_table + n);
-
- /* Alloc new root user. */
- root_user = alloc_uid(ns, 0);
- if (!root_user) {
- kmem_cache_free(user_ns_cachep, ns);
- return -ENOMEM;
- }
-
- /* set the new root user in the credentials under preparation */
- ns->creator = new->user;
- new->user = root_user;
- new->uid = new->euid = new->suid = new->fsuid = 0;
- new->gid = new->egid = new->sgid = new->fsgid = 0;
- put_group_info(new->group_info);
- new->group_info = get_group_info(&init_groups);
+ /* Start with the same capabilities as init but useless for doing
+ * anything as the capabilities are bound to the new user namespace.
+ */
+ new->securebits = SECUREBITS_DEFAULT;
+ new->cap_inheritable = CAP_EMPTY_SET;
+ new->cap_permitted = CAP_FULL_SET;
+ new->cap_effective = CAP_FULL_SET;
+ new->cap_bset = CAP_FULL_SET;
#ifdef CONFIG_KEYS
key_put(new->request_key_auth);
new->request_key_auth = NULL;
#endif
/* tgcred will be cleared in our caller bc CLONE_THREAD won't be set */
- /* root_user holds a reference to ns, our reference can be dropped */
- put_user_ns(ns);
+ /* Leave the new->user_ns reference with the new user namespace. */
+ /* Leave the reference to our user_ns with the new cred. */
+ new->user_ns = ns;
return 0;
}
-/*
- * Deferred destructor for a user namespace. This is required because
- * free_user_ns() may be called with uidhash_lock held, but we need to call
- * back to free_uid() which will want to take the lock again.
- */
-static void free_user_ns_work(struct work_struct *work)
+void free_user_ns(struct kref *kref)
{
- struct user_namespace *ns =
- container_of(work, struct user_namespace, destroyer);
- free_uid(ns->creator);
+ struct user_namespace *parent, *ns =
+ container_of(kref, struct user_namespace, kref);
+
+ parent = ns->parent;
kmem_cache_free(user_ns_cachep, ns);
+ put_user_ns(parent);
}
+EXPORT_SYMBOL(free_user_ns);
-void free_user_ns(struct kref *kref)
+static u32 map_id_range_down(struct uid_gid_map *map, u32 id, u32 count)
{
- struct user_namespace *ns =
- container_of(kref, struct user_namespace, kref);
+ unsigned idx, extents;
+ u32 first, last, id2;
+
+ id2 = id + count - 1;
+
+ /* Find the matching extent */
+ extents = map->nr_extents;
+ smp_read_barrier_depends();
+ for (idx = 0; idx < extents; idx++) {
+ first = map->extent[idx].first;
+ last = first + map->extent[idx].count - 1;
+ if (id >= first && id <= last &&
+ (id2 >= first && id2 <= last))
+ break;
+ }
+ /* Map the id or note failure */
+ if (idx < extents)
+ id = (id - first) + map->extent[idx].lower_first;
+ else
+ id = (u32) -1;
- INIT_WORK(&ns->destroyer, free_user_ns_work);
- schedule_work(&ns->destroyer);
+ return id;
}
-EXPORT_SYMBOL(free_user_ns);
-uid_t user_ns_map_uid(struct user_namespace *to, const struct cred *cred, uid_t uid)
+static u32 map_id_down(struct uid_gid_map *map, u32 id)
{
- struct user_namespace *tmp;
+ unsigned idx, extents;
+ u32 first, last;
- if (likely(to == cred->user->user_ns))
- return uid;
+ /* Find the matching extent */
+ extents = map->nr_extents;
+ smp_read_barrier_depends();
+ for (idx = 0; idx < extents; idx++) {
+ first = map->extent[idx].first;
+ last = first + map->extent[idx].count - 1;
+ if (id >= first && id <= last)
+ break;
+ }
+ /* Map the id or note failure */
+ if (idx < extents)
+ id = (id - first) + map->extent[idx].lower_first;
+ else
+ id = (u32) -1;
+ return id;
+}
- /* Is cred->user the creator of the target user_ns
- * or the creator of one of it's parents?
- */
- for ( tmp = to; tmp != &init_user_ns;
- tmp = tmp->creator->user_ns ) {
- if (cred->user == tmp->creator) {
- return (uid_t)0;
- }
+static u32 map_id_up(struct uid_gid_map *map, u32 id)
+{
+ unsigned idx, extents;
+ u32 first, last;
+
+ /* Find the matching extent */
+ extents = map->nr_extents;
+ smp_read_barrier_depends();
+ for (idx = 0; idx < extents; idx++) {
+ first = map->extent[idx].lower_first;
+ last = first + map->extent[idx].count - 1;
+ if (id >= first && id <= last)
+ break;
}
+ /* Map the id or note failure */
+ if (idx < extents)
+ id = (id - first) + map->extent[idx].first;
+ else
+ id = (u32) -1;
+
+ return id;
+}
+
+/**
+ * make_kuid - Map a user-namespace uid pair into a kuid.
+ * @ns: User namespace that the uid is in
+ * @uid: User identifier
+ *
+ * Maps a user-namespace uid pair into a kernel internal kuid,
+ * and returns that kuid.
+ *
+ * When there is no mapping defined for the user-namespace uid
+ * pair INVALID_UID is returned. Callers are expected to test
+ * for and handle handle INVALID_UID being returned. INVALID_UID
+ * may be tested for using uid_valid().
+ */
+kuid_t make_kuid(struct user_namespace *ns, uid_t uid)
+{
+ /* Map the uid to a global kernel uid */
+ return KUIDT_INIT(map_id_down(&ns->uid_map, uid));
+}
+EXPORT_SYMBOL(make_kuid);
+
+/**
+ * from_kuid - Create a uid from a kuid user-namespace pair.
+ * @targ: The user namespace we want a uid in.
+ * @kuid: The kernel internal uid to start with.
+ *
+ * Map @kuid into the user-namespace specified by @targ and
+ * return the resulting uid.
+ *
+ * There is always a mapping into the initial user_namespace.
+ *
+ * If @kuid has no mapping in @targ (uid_t)-1 is returned.
+ */
+uid_t from_kuid(struct user_namespace *targ, kuid_t kuid)
+{
+ /* Map the uid from a global kernel uid */
+ return map_id_up(&targ->uid_map, __kuid_val(kuid));
+}
+EXPORT_SYMBOL(from_kuid);
- /* No useful relationship so no mapping */
- return overflowuid;
+/**
+ * from_kuid_munged - Create a uid from a kuid user-namespace pair.
+ * @targ: The user namespace we want a uid in.
+ * @kuid: The kernel internal uid to start with.
+ *
+ * Map @kuid into the user-namespace specified by @targ and
+ * return the resulting uid.
+ *
+ * There is always a mapping into the initial user_namespace.
+ *
+ * Unlike from_kuid from_kuid_munged never fails and always
+ * returns a valid uid. This makes from_kuid_munged appropriate
+ * for use in syscalls like stat and getuid where failing the
+ * system call and failing to provide a valid uid are not an
+ * options.
+ *
+ * If @kuid has no mapping in @targ overflowuid is returned.
+ */
+uid_t from_kuid_munged(struct user_namespace *targ, kuid_t kuid)
+{
+ uid_t uid;
+ uid = from_kuid(targ, kuid);
+
+ if (uid == (uid_t) -1)
+ uid = overflowuid;
+ return uid;
}
+EXPORT_SYMBOL(from_kuid_munged);
-gid_t user_ns_map_gid(struct user_namespace *to, const struct cred *cred, gid_t gid)
+/**
+ * make_kgid - Map a user-namespace gid pair into a kgid.
+ * @ns: User namespace that the gid is in
+ * @uid: group identifier
+ *
+ * Maps a user-namespace gid pair into a kernel internal kgid,
+ * and returns that kgid.
+ *
+ * When there is no mapping defined for the user-namespace gid
+ * pair INVALID_GID is returned. Callers are expected to test
+ * for and handle INVALID_GID being returned. INVALID_GID may be
+ * tested for using gid_valid().
+ */
+kgid_t make_kgid(struct user_namespace *ns, gid_t gid)
{
- struct user_namespace *tmp;
+ /* Map the gid to a global kernel gid */
+ return KGIDT_INIT(map_id_down(&ns->gid_map, gid));
+}
+EXPORT_SYMBOL(make_kgid);
- if (likely(to == cred->user->user_ns))
- return gid;
+/**
+ * from_kgid - Create a gid from a kgid user-namespace pair.
+ * @targ: The user namespace we want a gid in.
+ * @kgid: The kernel internal gid to start with.
+ *
+ * Map @kgid into the user-namespace specified by @targ and
+ * return the resulting gid.
+ *
+ * There is always a mapping into the initial user_namespace.
+ *
+ * If @kgid has no mapping in @targ (gid_t)-1 is returned.
+ */
+gid_t from_kgid(struct user_namespace *targ, kgid_t kgid)
+{
+ /* Map the gid from a global kernel gid */
+ return map_id_up(&targ->gid_map, __kgid_val(kgid));
+}
+EXPORT_SYMBOL(from_kgid);
+
+/**
+ * from_kgid_munged - Create a gid from a kgid user-namespace pair.
+ * @targ: The user namespace we want a gid in.
+ * @kgid: The kernel internal gid to start with.
+ *
+ * Map @kgid into the user-namespace specified by @targ and
+ * return the resulting gid.
+ *
+ * There is always a mapping into the initial user_namespace.
+ *
+ * Unlike from_kgid from_kgid_munged never fails and always
+ * returns a valid gid. This makes from_kgid_munged appropriate
+ * for use in syscalls like stat and getgid where failing the
+ * system call and failing to provide a valid gid are not options.
+ *
+ * If @kgid has no mapping in @targ overflowgid is returned.
+ */
+gid_t from_kgid_munged(struct user_namespace *targ, kgid_t kgid)
+{
+ gid_t gid;
+ gid = from_kgid(targ, kgid);
- /* Is cred->user the creator of the target user_ns
- * or the creator of one of it's parents?
+ if (gid == (gid_t) -1)
+ gid = overflowgid;
+ return gid;
+}
+EXPORT_SYMBOL(from_kgid_munged);
+
+static int uid_m_show(struct seq_file *seq, void *v)
+{
+ struct user_namespace *ns = seq->private;
+ struct uid_gid_extent *extent = v;
+ struct user_namespace *lower_ns;
+ uid_t lower;
+
+ lower_ns = current_user_ns();
+ if ((lower_ns == ns) && lower_ns->parent)
+ lower_ns = lower_ns->parent;
+
+ lower = from_kuid(lower_ns, KUIDT_INIT(extent->lower_first));
+
+ seq_printf(seq, "%10u %10u %10u\n",
+ extent->first,
+ lower,
+ extent->count);
+
+ return 0;
+}
+
+static int gid_m_show(struct seq_file *seq, void *v)
+{
+ struct user_namespace *ns = seq->private;
+ struct uid_gid_extent *extent = v;
+ struct user_namespace *lower_ns;
+ gid_t lower;
+
+ lower_ns = current_user_ns();
+ if ((lower_ns == ns) && lower_ns->parent)
+ lower_ns = lower_ns->parent;
+
+ lower = from_kgid(lower_ns, KGIDT_INIT(extent->lower_first));
+
+ seq_printf(seq, "%10u %10u %10u\n",
+ extent->first,
+ lower,
+ extent->count);
+
+ return 0;
+}
+
+static void *m_start(struct seq_file *seq, loff_t *ppos, struct uid_gid_map *map)
+{
+ struct uid_gid_extent *extent = NULL;
+ loff_t pos = *ppos;
+
+ if (pos < map->nr_extents)
+ extent = &map->extent[pos];
+
+ return extent;
+}
+
+static void *uid_m_start(struct seq_file *seq, loff_t *ppos)
+{
+ struct user_namespace *ns = seq->private;
+
+ return m_start(seq, ppos, &ns->uid_map);
+}
+
+static void *gid_m_start(struct seq_file *seq, loff_t *ppos)
+{
+ struct user_namespace *ns = seq->private;
+
+ return m_start(seq, ppos, &ns->gid_map);
+}
+
+static void *m_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ (*pos)++;
+ return seq->op->start(seq, pos);
+}
+
+static void m_stop(struct seq_file *seq, void *v)
+{
+ return;
+}
+
+struct seq_operations proc_uid_seq_operations = {
+ .start = uid_m_start,
+ .stop = m_stop,
+ .next = m_next,
+ .show = uid_m_show,
+};
+
+struct seq_operations proc_gid_seq_operations = {
+ .start = gid_m_start,
+ .stop = m_stop,
+ .next = m_next,
+ .show = gid_m_show,
+};
+
+static DEFINE_MUTEX(id_map_mutex);
+
+static ssize_t map_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos,
+ int cap_setid,
+ struct uid_gid_map *map,
+ struct uid_gid_map *parent_map)
+{
+ struct seq_file *seq = file->private_data;
+ struct user_namespace *ns = seq->private;
+ struct uid_gid_map new_map;
+ unsigned idx;
+ struct uid_gid_extent *extent, *last = NULL;
+ unsigned long page = 0;
+ char *kbuf, *pos, *next_line;
+ ssize_t ret = -EINVAL;
+
+ /*
+ * The id_map_mutex serializes all writes to any given map.
+ *
+ * Any map is only ever written once.
+ *
+ * An id map fits within 1 cache line on most architectures.
+ *
+ * On read nothing needs to be done unless you are on an
+ * architecture with a crazy cache coherency model like alpha.
+ *
+ * There is a one time data dependency between reading the
+ * count of the extents and the values of the extents. The
+ * desired behavior is to see the values of the extents that
+ * were written before the count of the extents.
+ *
+ * To achieve this smp_wmb() is used on guarantee the write
+ * order and smp_read_barrier_depends() is guaranteed that we
+ * don't have crazy architectures returning stale data.
+ *
*/
- for ( tmp = to; tmp != &init_user_ns;
- tmp = tmp->creator->user_ns ) {
- if (cred->user == tmp->creator) {
- return (gid_t)0;
+ mutex_lock(&id_map_mutex);
+
+ ret = -EPERM;
+ /* Only allow one successful write to the map */
+ if (map->nr_extents != 0)
+ goto out;
+
+ /* Require the appropriate privilege CAP_SETUID or CAP_SETGID
+ * over the user namespace in order to set the id mapping.
+ */
+ if (!ns_capable(ns, cap_setid))
+ goto out;
+
+ /* Get a buffer */
+ ret = -ENOMEM;
+ page = __get_free_page(GFP_TEMPORARY);
+ kbuf = (char *) page;
+ if (!page)
+ goto out;
+
+ /* Only allow <= page size writes at the beginning of the file */
+ ret = -EINVAL;
+ if ((*ppos != 0) || (count >= PAGE_SIZE))
+ goto out;
+
+ /* Slurp in the user data */
+ ret = -EFAULT;
+ if (copy_from_user(kbuf, buf, count))
+ goto out;
+ kbuf[count] = '\0';
+
+ /* Parse the user data */
+ ret = -EINVAL;
+ pos = kbuf;
+ new_map.nr_extents = 0;
+ for (;pos; pos = next_line) {
+ extent = &new_map.extent[new_map.nr_extents];
+
+ /* Find the end of line and ensure I don't look past it */
+ next_line = strchr(pos, '\n');
+ if (next_line) {
+ *next_line = '\0';
+ next_line++;
+ if (*next_line == '\0')
+ next_line = NULL;
}
+
+ pos = skip_spaces(pos);
+ extent->first = simple_strtoul(pos, &pos, 10);
+ if (!isspace(*pos))
+ goto out;
+
+ pos = skip_spaces(pos);
+ extent->lower_first = simple_strtoul(pos, &pos, 10);
+ if (!isspace(*pos))
+ goto out;
+
+ pos = skip_spaces(pos);
+ extent->count = simple_strtoul(pos, &pos, 10);
+ if (*pos && !isspace(*pos))
+ goto out;
+
+ /* Verify there is not trailing junk on the line */
+ pos = skip_spaces(pos);
+ if (*pos != '\0')
+ goto out;
+
+ /* Verify we have been given valid starting values */
+ if ((extent->first == (u32) -1) ||
+ (extent->lower_first == (u32) -1 ))
+ goto out;
+
+ /* Verify count is not zero and does not cause the extent to wrap */
+ if ((extent->first + extent->count) <= extent->first)
+ goto out;
+ if ((extent->lower_first + extent->count) <= extent->lower_first)
+ goto out;
+
+ /* For now only accept extents that are strictly in order */
+ if (last &&
+ (((last->first + last->count) > extent->first) ||
+ ((last->lower_first + last->count) > extent->lower_first)))
+ goto out;
+
+ new_map.nr_extents++;
+ last = extent;
+
+ /* Fail if the file contains too many extents */
+ if ((new_map.nr_extents == UID_GID_MAP_MAX_EXTENTS) &&
+ (next_line != NULL))
+ goto out;
+ }
+ /* Be very certaint the new map actually exists */
+ if (new_map.nr_extents == 0)
+ goto out;
+
+ ret = -EPERM;
+ /* Validate the user is allowed to use user id's mapped to. */
+ if (!new_idmap_permitted(ns, cap_setid, &new_map))
+ goto out;
+
+ /* Map the lower ids from the parent user namespace to the
+ * kernel global id space.
+ */
+ for (idx = 0; idx < new_map.nr_extents; idx++) {
+ u32 lower_first;
+ extent = &new_map.extent[idx];
+
+ lower_first = map_id_range_down(parent_map,
+ extent->lower_first,
+ extent->count);
+
+ /* Fail if we can not map the specified extent to
+ * the kernel global id space.
+ */
+ if (lower_first == (u32) -1)
+ goto out;
+
+ extent->lower_first = lower_first;
}
- /* No useful relationship so no mapping */
- return overflowgid;
+ /* Install the map */
+ memcpy(map->extent, new_map.extent,
+ new_map.nr_extents*sizeof(new_map.extent[0]));
+ smp_wmb();
+ map->nr_extents = new_map.nr_extents;
+
+ *ppos = count;
+ ret = count;
+out:
+ mutex_unlock(&id_map_mutex);
+ if (page)
+ free_page(page);
+ return ret;
+}
+
+ssize_t proc_uid_map_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos)
+{
+ struct seq_file *seq = file->private_data;
+ struct user_namespace *ns = seq->private;
+
+ if (!ns->parent)
+ return -EPERM;
+
+ return map_write(file, buf, size, ppos, CAP_SETUID,
+ &ns->uid_map, &ns->parent->uid_map);
+}
+
+ssize_t proc_gid_map_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos)
+{
+ struct seq_file *seq = file->private_data;
+ struct user_namespace *ns = seq->private;
+
+ if (!ns->parent)
+ return -EPERM;
+
+ return map_write(file, buf, size, ppos, CAP_SETGID,
+ &ns->gid_map, &ns->parent->gid_map);
+}
+
+static bool new_idmap_permitted(struct user_namespace *ns, int cap_setid,
+ struct uid_gid_map *new_map)
+{
+ /* Allow the specified ids if we have the appropriate capability
+ * (CAP_SETUID or CAP_SETGID) over the parent user namespace.
+ */
+ if (ns_capable(ns->parent, cap_setid))
+ return true;
+
+ return false;
}
static __init int user_namespaces_init(void)
diff --git a/kernel/utsname.c b/kernel/utsname.c
index 405caf91aad5..679d97a5d3fd 100644
--- a/kernel/utsname.c
+++ b/kernel/utsname.c
@@ -43,7 +43,7 @@ static struct uts_namespace *clone_uts_ns(struct task_struct *tsk,
down_read(&uts_sem);
memcpy(&ns->name, &old_ns->name, sizeof(ns->name));
- ns->user_ns = get_user_ns(task_cred_xxx(tsk, user)->user_ns);
+ ns->user_ns = get_user_ns(task_cred_xxx(tsk, user_ns));
up_read(&uts_sem);
return ns;
}
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 5abf42f63c08..9a3128dc67df 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -1032,7 +1032,10 @@ static void __queue_work(unsigned int cpu, struct workqueue_struct *wq,
cwq = get_cwq(gcwq->cpu, wq);
trace_workqueue_queue_work(cpu, cwq, work);
- BUG_ON(!list_empty(&work->entry));
+ if (WARN_ON(!list_empty(&work->entry))) {
+ spin_unlock_irqrestore(&gcwq->lock, flags);
+ return;
+ }
cwq->nr_in_flight[cwq->work_color]++;
work_flags = work_color_to_flags(cwq->work_color);
@@ -1210,8 +1213,13 @@ static void worker_enter_idle(struct worker *worker)
} else
wake_up_all(&gcwq->trustee_wait);
- /* sanity check nr_running */
- WARN_ON_ONCE(gcwq->nr_workers == gcwq->nr_idle &&
+ /*
+ * Sanity check nr_running. Because trustee releases gcwq->lock
+ * between setting %WORKER_ROGUE and zapping nr_running, the
+ * warning may trigger spuriously. Check iff trustee is idle.
+ */
+ WARN_ON_ONCE(gcwq->trustee_state == TRUSTEE_DONE &&
+ gcwq->nr_workers == gcwq->nr_idle &&
atomic_read(get_gcwq_nr_running(gcwq->cpu)));
}
@@ -1810,7 +1818,9 @@ __acquires(&gcwq->lock)
* lock freed" warnings as well as problems when looking into
* work->lockdep_map, make a copy and use that here.
*/
- struct lockdep_map lockdep_map = work->lockdep_map;
+ struct lockdep_map lockdep_map;
+
+ lockdep_copy_map(&lockdep_map, &work->lockdep_map);
#endif
/*
* A single work shouldn't be executed concurrently by
@@ -2506,6 +2516,9 @@ bool flush_work(struct work_struct *work)
{
struct wq_barrier barr;
+ lock_map_acquire(&work->lockdep_map);
+ lock_map_release(&work->lockdep_map);
+
if (start_flush_work(work, &barr, true)) {
wait_for_completion(&barr.done);
destroy_work_on_stack(&barr.work);
diff --git a/lib/Kconfig b/lib/Kconfig
index 49cb46337db9..98230ac3db29 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -356,6 +356,14 @@ config CORDIC
This option provides an implementation of the CORDIC algorithm;
calculations are in fixed point. Module will be called cordic.
+config DDR
+ bool "JEDEC DDR data"
+ help
+ Data from JEDEC specs for DDR SDRAM memories,
+ particularly the AC timing parameters and addressing
+ information. This data is useful for drivers handling
+ DDR SDRAM controllers.
+
config MPILIB
tristate
select CLZ_TAB
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 6777153f18f3..a42d3ae39648 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -3,12 +3,16 @@ config PRINTK_TIME
bool "Show timing information on printks"
depends on PRINTK
help
- Selecting this option causes timing information to be
- included in printk output. This allows you to measure
- the interval between kernel operations, including bootup
- operations. This is useful for identifying long delays
- in kernel startup. Or add printk.time=1 at boot-time.
- See Documentation/kernel-parameters.txt
+ Selecting this option causes time stamps of the printk()
+ messages to be added to the output of the syslog() system
+ call and at the console.
+
+ The timestamp is always recorded internally, and exported
+ to /dev/kmsg. This flag just specifies if the timestamp should
+ be included, not that the timestamp is recorded.
+
+ The behavior is also controlled by the kernel command line
+ parameter printk.time=1. See Documentation/kernel-parameters.txt
config DEFAULT_MESSAGE_LOGLEVEL
int "Default message log level (1-7)"
@@ -70,6 +74,15 @@ config STRIP_ASM_SYMS
that look like '.Lxxx') so they don't pollute the output of
get_wchan() and suchlike.
+config READABLE_ASM
+ bool "Generate readable assembler code"
+ depends on DEBUG_KERNEL
+ help
+ Disable some compiler optimizations that tend to generate human unreadable
+ assembler output. This may make the kernel slightly slower, but it helps
+ to keep kernel developers who have to stare a lot at assembler listings
+ sane.
+
config UNUSED_SYMBOLS
bool "Enable unused/obsolete exported symbols"
default y if X86
@@ -1205,8 +1218,13 @@ config DYNAMIC_DEBUG
otherwise be available at runtime. These messages can then be
enabled/disabled based on various levels of scope - per source file,
function, module, format string, and line number. This mechanism
- implicitly enables all pr_debug() and dev_dbg() calls. The impact of
- this compile option is a larger kernel text size of about 2%.
+ implicitly compiles in all pr_debug() and dev_dbg() calls, which
+ enlarges the kernel text size by about 2%.
+
+ If a source file is compiled with DEBUG flag set, any
+ pr_debug() calls in it are enabled by default, but can be
+ disabled at runtime as below. Note that DEBUG flag is
+ turned on by many CONFIG_*DEBUG* options.
Usage:
@@ -1223,16 +1241,16 @@ config DYNAMIC_DEBUG
lineno : line number of the debug statement
module : module that contains the debug statement
function : function that contains the debug statement
- flags : 'p' means the line is turned 'on' for printing
+ flags : '=p' means the line is turned 'on' for printing
format : the format used for the debug statement
From a live system:
nullarbor:~ # cat <debugfs>/dynamic_debug/control
# filename:lineno [module]function flags format
- fs/aio.c:222 [aio]__put_ioctx - "__put_ioctx:\040freeing\040%p\012"
- fs/aio.c:248 [aio]ioctx_alloc - "ENOMEM:\040nr_events\040too\040high\012"
- fs/aio.c:1770 [aio]sys_io_cancel - "calling\040cancel\012"
+ fs/aio.c:222 [aio]__put_ioctx =_ "__put_ioctx:\040freeing\040%p\012"
+ fs/aio.c:248 [aio]ioctx_alloc =_ "ENOMEM:\040nr_events\040too\040high\012"
+ fs/aio.c:1770 [aio]sys_io_cancel =_ "calling\040cancel\012"
Example usage:
diff --git a/lib/Makefile b/lib/Makefile
index 57538b4d01d2..b98df505f335 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -123,6 +123,8 @@ obj-$(CONFIG_SIGNATURE) += digsig.o
obj-$(CONFIG_CLZ_TAB) += clz_tab.o
+obj-$(CONFIG_DDR) += jedec_ddr_data.o
+
obj-$(CONFIG_GENERIC_STRNCPY_FROM_USER) += strncpy_from_user.o
hostprogs-y := gen_crc32table
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 310c753cf83e..7ca29a0a3019 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -107,20 +107,22 @@ static char *ddebug_describe_flags(struct _ddebug *dp, char *buf,
return buf;
}
-#define vpr_info_dq(q, msg) \
-do { \
- if (verbose) \
- /* trim last char off format print */ \
- pr_info("%s: func=\"%s\" file=\"%s\" " \
- "module=\"%s\" format=\"%.*s\" " \
- "lineno=%u-%u", \
- msg, \
- q->function ? q->function : "", \
- q->filename ? q->filename : "", \
- q->module ? q->module : "", \
- (int)(q->format ? strlen(q->format) - 1 : 0), \
- q->format ? q->format : "", \
- q->first_lineno, q->last_lineno); \
+#define vpr_info(fmt, ...) \
+ if (verbose) do { pr_info(fmt, ##__VA_ARGS__); } while (0)
+
+#define vpr_info_dq(q, msg) \
+do { \
+ /* trim last char off format print */ \
+ vpr_info("%s: func=\"%s\" file=\"%s\" " \
+ "module=\"%s\" format=\"%.*s\" " \
+ "lineno=%u-%u", \
+ msg, \
+ q->function ? q->function : "", \
+ q->filename ? q->filename : "", \
+ q->module ? q->module : "", \
+ (int)(q->format ? strlen(q->format) - 1 : 0), \
+ q->format ? q->format : "", \
+ q->first_lineno, q->last_lineno); \
} while (0)
/*
@@ -180,12 +182,11 @@ static int ddebug_change(const struct ddebug_query *query,
if (newflags == dp->flags)
continue;
dp->flags = newflags;
- if (verbose)
- pr_info("changed %s:%d [%s]%s =%s\n",
- trim_prefix(dp->filename), dp->lineno,
- dt->mod_name, dp->function,
- ddebug_describe_flags(dp, flagbuf,
- sizeof(flagbuf)));
+ vpr_info("changed %s:%d [%s]%s =%s\n",
+ trim_prefix(dp->filename), dp->lineno,
+ dt->mod_name, dp->function,
+ ddebug_describe_flags(dp, flagbuf,
+ sizeof(flagbuf)));
}
}
mutex_unlock(&ddebug_lock);
@@ -337,7 +338,7 @@ static int check_set(const char **dest, char *src, char *name)
* Returns 0 on success, <0 on error.
*/
static int ddebug_parse_query(char *words[], int nwords,
- struct ddebug_query *query)
+ struct ddebug_query *query, const char *modname)
{
unsigned int i;
int rc;
@@ -347,6 +348,10 @@ static int ddebug_parse_query(char *words[], int nwords,
return -EINVAL;
memset(query, 0, sizeof(*query));
+ if (modname)
+ /* support $modname.dyndbg=<multiple queries> */
+ query->module = modname;
+
for (i = 0 ; i < nwords ; i += 2) {
if (!strcmp(words[i], "func"))
rc = check_set(&query->function, words[i+1], "func");
@@ -410,8 +415,7 @@ static int ddebug_parse_flags(const char *str, unsigned int *flagsp,
default:
return -EINVAL;
}
- if (verbose)
- pr_info("op='%c'\n", op);
+ vpr_info("op='%c'\n", op);
for ( ; *str ; ++str) {
for (i = ARRAY_SIZE(opt_array) - 1; i >= 0; i--) {
@@ -423,8 +427,7 @@ static int ddebug_parse_flags(const char *str, unsigned int *flagsp,
if (i < 0)
return -EINVAL;
}
- if (verbose)
- pr_info("flags=0x%x\n", flags);
+ vpr_info("flags=0x%x\n", flags);
/* calculate final *flagsp, *maskp according to mask and op */
switch (op) {
@@ -441,12 +444,11 @@ static int ddebug_parse_flags(const char *str, unsigned int *flagsp,
*flagsp = 0;
break;
}
- if (verbose)
- pr_info("*flagsp=0x%x *maskp=0x%x\n", *flagsp, *maskp);
+ vpr_info("*flagsp=0x%x *maskp=0x%x\n", *flagsp, *maskp);
return 0;
}
-static int ddebug_exec_query(char *query_string)
+static int ddebug_exec_query(char *query_string, const char *modname)
{
unsigned int flags = 0, mask = 0;
struct ddebug_query query;
@@ -457,7 +459,7 @@ static int ddebug_exec_query(char *query_string)
nwords = ddebug_tokenize(query_string, words, MAXWORDS);
if (nwords <= 0)
return -EINVAL;
- if (ddebug_parse_query(words, nwords-1, &query))
+ if (ddebug_parse_query(words, nwords-1, &query, modname))
return -EINVAL;
if (ddebug_parse_flags(words[nwords-1], &flags, &mask))
return -EINVAL;
@@ -473,7 +475,7 @@ static int ddebug_exec_query(char *query_string)
last error or number of matching callsites. Module name is either
in param (for boot arg) or perhaps in query string.
*/
-static int ddebug_exec_queries(char *query)
+static int ddebug_exec_queries(char *query, const char *modname)
{
char *split;
int i, errs = 0, exitcode = 0, rc, nfound = 0;
@@ -487,10 +489,9 @@ static int ddebug_exec_queries(char *query)
if (!query || !*query || *query == '#')
continue;
- if (verbose)
- pr_info("query %d: \"%s\"\n", i, query);
+ vpr_info("query %d: \"%s\"\n", i, query);
- rc = ddebug_exec_query(query);
+ rc = ddebug_exec_query(query, modname);
if (rc < 0) {
errs++;
exitcode = rc;
@@ -498,7 +499,7 @@ static int ddebug_exec_queries(char *query)
nfound += rc;
i++;
}
- pr_info("processed %d queries, with %d matches, %d errs\n",
+ vpr_info("processed %d queries, with %d matches, %d errs\n",
i, nfound, errs);
if (exitcode)
@@ -653,10 +654,9 @@ static ssize_t ddebug_proc_write(struct file *file, const char __user *ubuf,
return -EFAULT;
}
tmpbuf[len] = '\0';
- if (verbose)
- pr_info("read %d bytes from userspace\n", (int)len);
+ vpr_info("read %d bytes from userspace\n", (int)len);
- ret = ddebug_exec_queries(tmpbuf);
+ ret = ddebug_exec_queries(tmpbuf, NULL);
kfree(tmpbuf);
if (ret < 0)
return ret;
@@ -717,8 +717,7 @@ static void *ddebug_proc_start(struct seq_file *m, loff_t *pos)
struct _ddebug *dp;
int n = *pos;
- if (verbose)
- pr_info("called m=%p *pos=%lld\n", m, (unsigned long long)*pos);
+ vpr_info("called m=%p *pos=%lld\n", m, (unsigned long long)*pos);
mutex_lock(&ddebug_lock);
@@ -742,9 +741,8 @@ static void *ddebug_proc_next(struct seq_file *m, void *p, loff_t *pos)
struct ddebug_iter *iter = m->private;
struct _ddebug *dp;
- if (verbose)
- pr_info("called m=%p p=%p *pos=%lld\n",
- m, p, (unsigned long long)*pos);
+ vpr_info("called m=%p p=%p *pos=%lld\n",
+ m, p, (unsigned long long)*pos);
if (p == SEQ_START_TOKEN)
dp = ddebug_iter_first(iter);
@@ -766,8 +764,7 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
struct _ddebug *dp = p;
char flagsbuf[10];
- if (verbose)
- pr_info("called m=%p p=%p\n", m, p);
+ vpr_info("called m=%p p=%p\n", m, p);
if (p == SEQ_START_TOKEN) {
seq_puts(m,
@@ -791,8 +788,7 @@ static int ddebug_proc_show(struct seq_file *m, void *p)
*/
static void ddebug_proc_stop(struct seq_file *m, void *p)
{
- if (verbose)
- pr_info("called m=%p p=%p\n", m, p);
+ vpr_info("called m=%p p=%p\n", m, p);
mutex_unlock(&ddebug_lock);
}
@@ -815,8 +811,7 @@ static int ddebug_proc_open(struct inode *inode, struct file *file)
struct ddebug_iter *iter;
int err;
- if (verbose)
- pr_info("called\n");
+ vpr_info("called\n");
iter = kzalloc(sizeof(*iter), GFP_KERNEL);
if (iter == NULL)
@@ -866,12 +861,51 @@ int ddebug_add_module(struct _ddebug *tab, unsigned int n,
list_add_tail(&dt->link, &ddebug_tables);
mutex_unlock(&ddebug_lock);
- if (verbose)
- pr_info("%u debug prints in module %s\n", n, dt->mod_name);
+ vpr_info("%u debug prints in module %s\n", n, dt->mod_name);
return 0;
}
EXPORT_SYMBOL_GPL(ddebug_add_module);
+/* helper for ddebug_dyndbg_(boot|module)_param_cb */
+static int ddebug_dyndbg_param_cb(char *param, char *val,
+ const char *modname, int on_err)
+{
+ char *sep;
+
+ sep = strchr(param, '.');
+ if (sep) {
+ /* needed only for ddebug_dyndbg_boot_param_cb */
+ *sep = '\0';
+ modname = param;
+ param = sep + 1;
+ }
+ if (strcmp(param, "dyndbg"))
+ return on_err; /* determined by caller */
+
+ ddebug_exec_queries((val ? val : "+p"), modname);
+
+ return 0; /* query failure shouldnt stop module load */
+}
+
+/* handle both dyndbg and $module.dyndbg params at boot */
+static int ddebug_dyndbg_boot_param_cb(char *param, char *val,
+ const char *unused)
+{
+ vpr_info("%s=\"%s\"\n", param, val);
+ return ddebug_dyndbg_param_cb(param, val, NULL, 0);
+}
+
+/*
+ * modprobe foo finds foo.params in boot-args, strips "foo.", and
+ * passes them to load_module(). This callback gets unknown params,
+ * processes dyndbg params, rejects others.
+ */
+int ddebug_dyndbg_module_param_cb(char *param, char *val, const char *module)
+{
+ vpr_info("module: %s %s=\"%s\"\n", module, param, val);
+ return ddebug_dyndbg_param_cb(param, val, module, -ENOENT);
+}
+
static void ddebug_table_free(struct ddebug_table *dt)
{
list_del_init(&dt->link);
@@ -888,8 +922,7 @@ int ddebug_remove_module(const char *mod_name)
struct ddebug_table *dt, *nextdt;
int ret = -ENOENT;
- if (verbose)
- pr_info("removing module \"%s\"\n", mod_name);
+ vpr_info("removing module \"%s\"\n", mod_name);
mutex_lock(&ddebug_lock);
list_for_each_entry_safe(dt, nextdt, &ddebug_tables, link) {
@@ -940,8 +973,10 @@ static int __init dynamic_debug_init(void)
{
struct _ddebug *iter, *iter_start;
const char *modname = NULL;
+ char *cmdline;
int ret = 0;
- int n = 0;
+ int n = 0, entries = 0, modct = 0;
+ int verbose_bytes = 0;
if (__start___verbose == __stop___verbose) {
pr_warn("_ddebug table is empty in a "
@@ -952,10 +987,15 @@ static int __init dynamic_debug_init(void)
modname = iter->modname;
iter_start = iter;
for (; iter < __stop___verbose; iter++) {
+ entries++;
+ verbose_bytes += strlen(iter->modname) + strlen(iter->function)
+ + strlen(iter->filename) + strlen(iter->format);
+
if (strcmp(modname, iter->modname)) {
+ modct++;
ret = ddebug_add_module(iter_start, n, modname);
if (ret)
- goto out_free;
+ goto out_err;
n = 0;
modname = iter->modname;
iter_start = iter;
@@ -964,29 +1004,45 @@ static int __init dynamic_debug_init(void)
}
ret = ddebug_add_module(iter_start, n, modname);
if (ret)
- goto out_free;
+ goto out_err;
+
+ ddebug_init_success = 1;
+ vpr_info("%d modules, %d entries and %d bytes in ddebug tables,"
+ " %d bytes in (readonly) verbose section\n",
+ modct, entries, (int)( modct * sizeof(struct ddebug_table)),
+ verbose_bytes + (int)(__stop___verbose - __start___verbose));
- /* ddebug_query boot param got passed -> set it up */
+ /* apply ddebug_query boot param, dont unload tables on err */
if (ddebug_setup_string[0] != '\0') {
- ret = ddebug_exec_queries(ddebug_setup_string);
+ pr_warn("ddebug_query param name is deprecated,"
+ " change it to dyndbg\n");
+ ret = ddebug_exec_queries(ddebug_setup_string, NULL);
if (ret < 0)
pr_warn("Invalid ddebug boot param %s",
ddebug_setup_string);
else
pr_info("%d changes by ddebug_query\n", ret);
-
- /* keep tables even on ddebug_query parse error */
- ret = 0;
}
+ /* now that ddebug tables are loaded, process all boot args
+ * again to find and activate queries given in dyndbg params.
+ * While this has already been done for known boot params, it
+ * ignored the unknown ones (dyndbg in particular). Reusing
+ * parse_args avoids ad-hoc parsing. This will also attempt
+ * to activate queries for not-yet-loaded modules, which is
+ * slightly noisy if verbose, but harmless.
+ */
+ cmdline = kstrdup(saved_command_line, GFP_KERNEL);
+ parse_args("dyndbg params", cmdline, NULL,
+ 0, 0, 0, &ddebug_dyndbg_boot_param_cb);
+ kfree(cmdline);
+ return 0;
-out_free:
- if (ret)
- ddebug_remove_all_tables();
- else
- ddebug_init_success = 1;
+out_err:
+ ddebug_remove_all_tables();
return 0;
}
/* Allow early initialization for boot messages via boot param */
-arch_initcall(dynamic_debug_init);
+early_initcall(dynamic_debug_init);
+
/* Debugfs setup must be done later */
-module_init(dynamic_debug_init_debugfs);
+fs_initcall(dynamic_debug_init_debugfs);
diff --git a/lib/jedec_ddr_data.c b/lib/jedec_ddr_data.c
new file mode 100644
index 000000000000..6d2cbf1d567f
--- /dev/null
+++ b/lib/jedec_ddr_data.c
@@ -0,0 +1,135 @@
+/*
+ * DDR addressing details and AC timing parameters from JEDEC specs
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Aneesh V <aneesh@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.
+ */
+
+#include <memory/jedec_ddr.h>
+#include <linux/module.h>
+
+/* LPDDR2 addressing details from JESD209-2 section 2.4 */
+const struct lpddr2_addressing
+ lpddr2_jedec_addressing_table[NUM_DDR_ADDR_TABLE_ENTRIES] = {
+ {B4, T_REFI_15_6, T_RFC_90}, /* 64M */
+ {B4, T_REFI_15_6, T_RFC_90}, /* 128M */
+ {B4, T_REFI_7_8, T_RFC_90}, /* 256M */
+ {B4, T_REFI_7_8, T_RFC_90}, /* 512M */
+ {B8, T_REFI_7_8, T_RFC_130}, /* 1GS4 */
+ {B8, T_REFI_3_9, T_RFC_130}, /* 2GS4 */
+ {B8, T_REFI_3_9, T_RFC_130}, /* 4G */
+ {B8, T_REFI_3_9, T_RFC_210}, /* 8G */
+ {B4, T_REFI_7_8, T_RFC_130}, /* 1GS2 */
+ {B4, T_REFI_3_9, T_RFC_130}, /* 2GS2 */
+};
+EXPORT_SYMBOL_GPL(lpddr2_jedec_addressing_table);
+
+/* LPDDR2 AC timing parameters from JESD209-2 section 12 */
+const struct lpddr2_timings
+ lpddr2_jedec_timings[NUM_DDR_TIMING_TABLE_ENTRIES] = {
+ /* Speed bin 400(200 MHz) */
+ [0] = {
+ .max_freq = 200000000,
+ .min_freq = 10000000,
+ .tRPab = 21000,
+ .tRCD = 18000,
+ .tWR = 15000,
+ .tRAS_min = 42000,
+ .tRRD = 10000,
+ .tWTR = 10000,
+ .tXP = 7500,
+ .tRTP = 7500,
+ .tCKESR = 15000,
+ .tDQSCK_max = 5500,
+ .tFAW = 50000,
+ .tZQCS = 90000,
+ .tZQCL = 360000,
+ .tZQinit = 1000000,
+ .tRAS_max_ns = 70000,
+ .tDQSCK_max_derated = 6000,
+ },
+ /* Speed bin 533(266 MHz) */
+ [1] = {
+ .max_freq = 266666666,
+ .min_freq = 10000000,
+ .tRPab = 21000,
+ .tRCD = 18000,
+ .tWR = 15000,
+ .tRAS_min = 42000,
+ .tRRD = 10000,
+ .tWTR = 7500,
+ .tXP = 7500,
+ .tRTP = 7500,
+ .tCKESR = 15000,
+ .tDQSCK_max = 5500,
+ .tFAW = 50000,
+ .tZQCS = 90000,
+ .tZQCL = 360000,
+ .tZQinit = 1000000,
+ .tRAS_max_ns = 70000,
+ .tDQSCK_max_derated = 6000,
+ },
+ /* Speed bin 800(400 MHz) */
+ [2] = {
+ .max_freq = 400000000,
+ .min_freq = 10000000,
+ .tRPab = 21000,
+ .tRCD = 18000,
+ .tWR = 15000,
+ .tRAS_min = 42000,
+ .tRRD = 10000,
+ .tWTR = 7500,
+ .tXP = 7500,
+ .tRTP = 7500,
+ .tCKESR = 15000,
+ .tDQSCK_max = 5500,
+ .tFAW = 50000,
+ .tZQCS = 90000,
+ .tZQCL = 360000,
+ .tZQinit = 1000000,
+ .tRAS_max_ns = 70000,
+ .tDQSCK_max_derated = 6000,
+ },
+ /* Speed bin 1066(533 MHz) */
+ [3] = {
+ .max_freq = 533333333,
+ .min_freq = 10000000,
+ .tRPab = 21000,
+ .tRCD = 18000,
+ .tWR = 15000,
+ .tRAS_min = 42000,
+ .tRRD = 10000,
+ .tWTR = 7500,
+ .tXP = 7500,
+ .tRTP = 7500,
+ .tCKESR = 15000,
+ .tDQSCK_max = 5500,
+ .tFAW = 50000,
+ .tZQCS = 90000,
+ .tZQCL = 360000,
+ .tZQinit = 1000000,
+ .tRAS_max_ns = 70000,
+ .tDQSCK_max_derated = 5620,
+ },
+};
+EXPORT_SYMBOL_GPL(lpddr2_jedec_timings);
+
+const struct lpddr2_min_tck lpddr2_jedec_min_tck = {
+ .tRPab = 3,
+ .tRCD = 3,
+ .tWR = 3,
+ .tRASmin = 3,
+ .tRRD = 2,
+ .tWTR = 2,
+ .tXP = 2,
+ .tRTP = 2,
+ .tCKE = 3,
+ .tCKESR = 3,
+ .tFAW = 8
+};
+EXPORT_SYMBOL_GPL(lpddr2_jedec_min_tck);
diff --git a/lib/kobject.c b/lib/kobject.c
index aeefa8bc8b1c..e07ee1fcd6f1 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -47,13 +47,11 @@ static int populate_dir(struct kobject *kobj)
static int create_dir(struct kobject *kobj)
{
int error = 0;
- if (kobject_name(kobj)) {
- error = sysfs_create_dir(kobj);
- if (!error) {
- error = populate_dir(kobj);
- if (error)
- sysfs_remove_dir(kobj);
- }
+ error = sysfs_create_dir(kobj);
+ if (!error) {
+ error = populate_dir(kobj);
+ if (error)
+ sysfs_remove_dir(kobj);
}
return error;
}
@@ -634,7 +632,7 @@ struct kobject *kobject_create(void)
/**
* kobject_create_and_add - create a struct kobject dynamically and register it with sysfs
*
- * @name: the name for the kset
+ * @name: the name for the kobject
* @parent: the parent kobject of this kobject, if any.
*
* This function creates a kobject structure dynamically and registers it
diff --git a/lib/raid6/Makefile b/lib/raid6/Makefile
index 8a38102770f3..de06dfe165b8 100644
--- a/lib/raid6/Makefile
+++ b/lib/raid6/Makefile
@@ -1,6 +1,6 @@
obj-$(CONFIG_RAID6_PQ) += raid6_pq.o
-raid6_pq-y += algos.o recov.o tables.o int1.o int2.o int4.o \
+raid6_pq-y += algos.o recov.o recov_ssse3.o tables.o int1.o int2.o int4.o \
int8.o int16.o int32.o altivec1.o altivec2.o altivec4.o \
altivec8.o mmx.o sse1.o sse2.o
hostprogs-y += mktables
diff --git a/lib/raid6/algos.c b/lib/raid6/algos.c
index 8b02f60ffc86..589f5f50ad2e 100644
--- a/lib/raid6/algos.c
+++ b/lib/raid6/algos.c
@@ -17,11 +17,11 @@
*/
#include <linux/raid/pq.h>
-#include <linux/module.h>
#ifndef __KERNEL__
#include <sys/mman.h>
#include <stdio.h>
#else
+#include <linux/module.h>
#include <linux/gfp.h>
#if !RAID6_USE_EMPTY_ZERO_PAGE
/* In .bss so it's zeroed */
@@ -34,10 +34,6 @@ struct raid6_calls raid6_call;
EXPORT_SYMBOL_GPL(raid6_call);
const struct raid6_calls * const raid6_algos[] = {
- &raid6_intx1,
- &raid6_intx2,
- &raid6_intx4,
- &raid6_intx8,
#if defined(__ia64__)
&raid6_intx16,
&raid6_intx32,
@@ -61,6 +57,24 @@ const struct raid6_calls * const raid6_algos[] = {
&raid6_altivec4,
&raid6_altivec8,
#endif
+ &raid6_intx1,
+ &raid6_intx2,
+ &raid6_intx4,
+ &raid6_intx8,
+ NULL
+};
+
+void (*raid6_2data_recov)(int, size_t, int, int, void **);
+EXPORT_SYMBOL_GPL(raid6_2data_recov);
+
+void (*raid6_datap_recov)(int, size_t, int, void **);
+EXPORT_SYMBOL_GPL(raid6_datap_recov);
+
+const struct raid6_recov_calls *const raid6_recov_algos[] = {
+#if (defined(__i386__) || defined(__x86_64__)) && !defined(__arch_um__)
+ &raid6_recov_ssse3,
+#endif
+ &raid6_recov_intx1,
NULL
};
@@ -72,59 +86,55 @@ const struct raid6_calls * const raid6_algos[] = {
#define time_before(x, y) ((x) < (y))
#endif
-/* Try to pick the best algorithm */
-/* This code uses the gfmul table as convenient data set to abuse */
-
-int __init raid6_select_algo(void)
+static inline const struct raid6_recov_calls *raid6_choose_recov(void)
{
- const struct raid6_calls * const * algo;
- const struct raid6_calls * best;
- char *syndromes;
- void *dptrs[(65536/PAGE_SIZE)+2];
- int i, disks;
- unsigned long perf, bestperf;
- int bestprefer;
- unsigned long j0, j1;
+ const struct raid6_recov_calls *const *algo;
+ const struct raid6_recov_calls *best;
- disks = (65536/PAGE_SIZE)+2;
- for ( i = 0 ; i < disks-2 ; i++ ) {
- dptrs[i] = ((char *)raid6_gfmul) + PAGE_SIZE*i;
- }
+ for (best = NULL, algo = raid6_recov_algos; *algo; algo++)
+ if (!best || (*algo)->priority > best->priority)
+ if (!(*algo)->valid || (*algo)->valid())
+ best = *algo;
- /* Normal code - use a 2-page allocation to avoid D$ conflict */
- syndromes = (void *) __get_free_pages(GFP_KERNEL, 1);
+ if (best) {
+ raid6_2data_recov = best->data2;
+ raid6_datap_recov = best->datap;
- if ( !syndromes ) {
- printk("raid6: Yikes! No memory available.\n");
- return -ENOMEM;
- }
+ printk("raid6: using %s recovery algorithm\n", best->name);
+ } else
+ printk("raid6: Yikes! No recovery algorithm found!\n");
- dptrs[disks-2] = syndromes;
- dptrs[disks-1] = syndromes + PAGE_SIZE;
+ return best;
+}
+
+static inline const struct raid6_calls *raid6_choose_gen(
+ void *(*const dptrs)[(65536/PAGE_SIZE)+2], const int disks)
+{
+ unsigned long perf, bestperf, j0, j1;
+ const struct raid6_calls *const *algo;
+ const struct raid6_calls *best;
- bestperf = 0; bestprefer = 0; best = NULL;
+ for (bestperf = 0, best = NULL, algo = raid6_algos; *algo; algo++) {
+ if (!best || (*algo)->prefer >= best->prefer) {
+ if ((*algo)->valid && !(*algo)->valid())
+ continue;
- for ( algo = raid6_algos ; *algo ; algo++ ) {
- if ( !(*algo)->valid || (*algo)->valid() ) {
perf = 0;
preempt_disable();
j0 = jiffies;
- while ( (j1 = jiffies) == j0 )
+ while ((j1 = jiffies) == j0)
cpu_relax();
while (time_before(jiffies,
j1 + (1<<RAID6_TIME_JIFFIES_LG2))) {
- (*algo)->gen_syndrome(disks, PAGE_SIZE, dptrs);
+ (*algo)->gen_syndrome(disks, PAGE_SIZE, *dptrs);
perf++;
}
preempt_enable();
- if ( (*algo)->prefer > bestprefer ||
- ((*algo)->prefer == bestprefer &&
- perf > bestperf) ) {
- best = *algo;
- bestprefer = best->prefer;
+ if (perf > bestperf) {
bestperf = perf;
+ best = *algo;
}
printk("raid6: %-8s %5ld MB/s\n", (*algo)->name,
(perf*HZ) >> (20-16+RAID6_TIME_JIFFIES_LG2));
@@ -139,9 +149,46 @@ int __init raid6_select_algo(void)
} else
printk("raid6: Yikes! No algorithm found!\n");
+ return best;
+}
+
+
+/* Try to pick the best algorithm */
+/* This code uses the gfmul table as convenient data set to abuse */
+
+int __init raid6_select_algo(void)
+{
+ const int disks = (65536/PAGE_SIZE)+2;
+
+ const struct raid6_calls *gen_best;
+ const struct raid6_recov_calls *rec_best;
+ char *syndromes;
+ void *dptrs[(65536/PAGE_SIZE)+2];
+ int i;
+
+ for (i = 0; i < disks-2; i++)
+ dptrs[i] = ((char *)raid6_gfmul) + PAGE_SIZE*i;
+
+ /* Normal code - use a 2-page allocation to avoid D$ conflict */
+ syndromes = (void *) __get_free_pages(GFP_KERNEL, 1);
+
+ if (!syndromes) {
+ printk("raid6: Yikes! No memory available.\n");
+ return -ENOMEM;
+ }
+
+ dptrs[disks-2] = syndromes;
+ dptrs[disks-1] = syndromes + PAGE_SIZE;
+
+ /* select raid gen_syndrome function */
+ gen_best = raid6_choose_gen(&dptrs, disks);
+
+ /* select raid recover functions */
+ rec_best = raid6_choose_recov();
+
free_pages((unsigned long)syndromes, 1);
- return best ? 0 : -EINVAL;
+ return gen_best && rec_best ? 0 : -EINVAL;
}
static void raid6_exit(void)
diff --git a/lib/raid6/mktables.c b/lib/raid6/mktables.c
index 8a3780902cec..39787db588b0 100644
--- a/lib/raid6/mktables.c
+++ b/lib/raid6/mktables.c
@@ -81,6 +81,31 @@ int main(int argc, char *argv[])
printf("EXPORT_SYMBOL(raid6_gfmul);\n");
printf("#endif\n");
+ /* Compute vector multiplication table */
+ printf("\nconst u8 __attribute__((aligned(256)))\n"
+ "raid6_vgfmul[256][32] =\n"
+ "{\n");
+ for (i = 0; i < 256; i++) {
+ printf("\t{\n");
+ for (j = 0; j < 16; j += 8) {
+ printf("\t\t");
+ for (k = 0; k < 8; k++)
+ printf("0x%02x,%c", gfmul(i, j + k),
+ (k == 7) ? '\n' : ' ');
+ }
+ for (j = 0; j < 16; j += 8) {
+ printf("\t\t");
+ for (k = 0; k < 8; k++)
+ printf("0x%02x,%c", gfmul(i, (j + k) << 4),
+ (k == 7) ? '\n' : ' ');
+ }
+ printf("\t},\n");
+ }
+ printf("};\n");
+ printf("#ifdef __KERNEL__\n");
+ printf("EXPORT_SYMBOL(raid6_vgfmul);\n");
+ printf("#endif\n");
+
/* Compute power-of-2 table (exponent) */
v = 1;
printf("\nconst u8 __attribute__((aligned(256)))\n"
diff --git a/lib/raid6/recov.c b/lib/raid6/recov.c
index fe275d7b6b36..1805a5cc5daa 100644
--- a/lib/raid6/recov.c
+++ b/lib/raid6/recov.c
@@ -22,7 +22,7 @@
#include <linux/raid/pq.h>
/* Recover two failed data blocks. */
-void raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
+void raid6_2data_recov_intx1(int disks, size_t bytes, int faila, int failb,
void **ptrs)
{
u8 *p, *q, *dp, *dq;
@@ -64,10 +64,9 @@ void raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
p++; q++;
}
}
-EXPORT_SYMBOL_GPL(raid6_2data_recov);
/* Recover failure of one data block plus the P block */
-void raid6_datap_recov(int disks, size_t bytes, int faila, void **ptrs)
+void raid6_datap_recov_intx1(int disks, size_t bytes, int faila, void **ptrs)
{
u8 *p, *q, *dq;
const u8 *qmul; /* Q multiplier table */
@@ -96,7 +95,15 @@ void raid6_datap_recov(int disks, size_t bytes, int faila, void **ptrs)
q++; dq++;
}
}
-EXPORT_SYMBOL_GPL(raid6_datap_recov);
+
+
+const struct raid6_recov_calls raid6_recov_intx1 = {
+ .data2 = raid6_2data_recov_intx1,
+ .datap = raid6_datap_recov_intx1,
+ .valid = NULL,
+ .name = "intx1",
+ .priority = 0,
+};
#ifndef __KERNEL__
/* Testing only */
diff --git a/lib/raid6/recov_ssse3.c b/lib/raid6/recov_ssse3.c
new file mode 100644
index 000000000000..37ae61930559
--- /dev/null
+++ b/lib/raid6/recov_ssse3.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#if (defined(__i386__) || defined(__x86_64__)) && !defined(__arch_um__)
+
+#include <linux/raid/pq.h>
+#include "x86.h"
+
+static int raid6_has_ssse3(void)
+{
+ return boot_cpu_has(X86_FEATURE_XMM) &&
+ boot_cpu_has(X86_FEATURE_XMM2) &&
+ boot_cpu_has(X86_FEATURE_SSSE3);
+}
+
+void raid6_2data_recov_ssse3(int disks, size_t bytes, int faila, int failb,
+ void **ptrs)
+{
+ u8 *p, *q, *dp, *dq;
+ const u8 *pbmul; /* P multiplier table for B data */
+ const u8 *qmul; /* Q multiplier table (for both) */
+ static const u8 __aligned(16) x0f[16] = {
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f};
+
+ p = (u8 *)ptrs[disks-2];
+ q = (u8 *)ptrs[disks-1];
+
+ /* Compute syndrome with zero for the missing data pages
+ Use the dead data pages as temporary storage for
+ delta p and delta q */
+ dp = (u8 *)ptrs[faila];
+ ptrs[faila] = (void *)raid6_empty_zero_page;
+ ptrs[disks-2] = dp;
+ dq = (u8 *)ptrs[failb];
+ ptrs[failb] = (void *)raid6_empty_zero_page;
+ ptrs[disks-1] = dq;
+
+ raid6_call.gen_syndrome(disks, bytes, ptrs);
+
+ /* Restore pointer table */
+ ptrs[faila] = dp;
+ ptrs[failb] = dq;
+ ptrs[disks-2] = p;
+ ptrs[disks-1] = q;
+
+ /* Now, pick the proper data tables */
+ pbmul = raid6_vgfmul[raid6_gfexi[failb-faila]];
+ qmul = raid6_vgfmul[raid6_gfinv[raid6_gfexp[faila] ^
+ raid6_gfexp[failb]]];
+
+ kernel_fpu_begin();
+
+ asm volatile("movdqa %0,%%xmm7" : : "m" (x0f[0]));
+
+#ifdef CONFIG_X86_64
+ asm volatile("movdqa %0,%%xmm6" : : "m" (qmul[0]));
+ asm volatile("movdqa %0,%%xmm14" : : "m" (pbmul[0]));
+ asm volatile("movdqa %0,%%xmm15" : : "m" (pbmul[16]));
+#endif
+
+ /* Now do it... */
+ while (bytes) {
+#ifdef CONFIG_X86_64
+ /* xmm6, xmm14, xmm15 */
+
+ asm volatile("movdqa %0,%%xmm1" : : "m" (q[0]));
+ asm volatile("movdqa %0,%%xmm9" : : "m" (q[16]));
+ asm volatile("movdqa %0,%%xmm0" : : "m" (p[0]));
+ asm volatile("movdqa %0,%%xmm8" : : "m" (p[16]));
+ asm volatile("pxor %0,%%xmm1" : : "m" (dq[0]));
+ asm volatile("pxor %0,%%xmm9" : : "m" (dq[16]));
+ asm volatile("pxor %0,%%xmm0" : : "m" (dp[0]));
+ asm volatile("pxor %0,%%xmm8" : : "m" (dp[16]));
+
+ /* xmm0/8 = px */
+
+ asm volatile("movdqa %xmm6,%xmm4");
+ asm volatile("movdqa %0,%%xmm5" : : "m" (qmul[16]));
+ asm volatile("movdqa %xmm6,%xmm12");
+ asm volatile("movdqa %xmm5,%xmm13");
+ asm volatile("movdqa %xmm1,%xmm3");
+ asm volatile("movdqa %xmm9,%xmm11");
+ asm volatile("movdqa %xmm0,%xmm2"); /* xmm2/10 = px */
+ asm volatile("movdqa %xmm8,%xmm10");
+ asm volatile("psraw $4,%xmm1");
+ asm volatile("psraw $4,%xmm9");
+ asm volatile("pand %xmm7,%xmm3");
+ asm volatile("pand %xmm7,%xmm11");
+ asm volatile("pand %xmm7,%xmm1");
+ asm volatile("pand %xmm7,%xmm9");
+ asm volatile("pshufb %xmm3,%xmm4");
+ asm volatile("pshufb %xmm11,%xmm12");
+ asm volatile("pshufb %xmm1,%xmm5");
+ asm volatile("pshufb %xmm9,%xmm13");
+ asm volatile("pxor %xmm4,%xmm5");
+ asm volatile("pxor %xmm12,%xmm13");
+
+ /* xmm5/13 = qx */
+
+ asm volatile("movdqa %xmm14,%xmm4");
+ asm volatile("movdqa %xmm15,%xmm1");
+ asm volatile("movdqa %xmm14,%xmm12");
+ asm volatile("movdqa %xmm15,%xmm9");
+ asm volatile("movdqa %xmm2,%xmm3");
+ asm volatile("movdqa %xmm10,%xmm11");
+ asm volatile("psraw $4,%xmm2");
+ asm volatile("psraw $4,%xmm10");
+ asm volatile("pand %xmm7,%xmm3");
+ asm volatile("pand %xmm7,%xmm11");
+ asm volatile("pand %xmm7,%xmm2");
+ asm volatile("pand %xmm7,%xmm10");
+ asm volatile("pshufb %xmm3,%xmm4");
+ asm volatile("pshufb %xmm11,%xmm12");
+ asm volatile("pshufb %xmm2,%xmm1");
+ asm volatile("pshufb %xmm10,%xmm9");
+ asm volatile("pxor %xmm4,%xmm1");
+ asm volatile("pxor %xmm12,%xmm9");
+
+ /* xmm1/9 = pbmul[px] */
+ asm volatile("pxor %xmm5,%xmm1");
+ asm volatile("pxor %xmm13,%xmm9");
+ /* xmm1/9 = db = DQ */
+ asm volatile("movdqa %%xmm1,%0" : "=m" (dq[0]));
+ asm volatile("movdqa %%xmm9,%0" : "=m" (dq[16]));
+
+ asm volatile("pxor %xmm1,%xmm0");
+ asm volatile("pxor %xmm9,%xmm8");
+ asm volatile("movdqa %%xmm0,%0" : "=m" (dp[0]));
+ asm volatile("movdqa %%xmm8,%0" : "=m" (dp[16]));
+
+ bytes -= 32;
+ p += 32;
+ q += 32;
+ dp += 32;
+ dq += 32;
+#else
+ asm volatile("movdqa %0,%%xmm1" : : "m" (*q));
+ asm volatile("movdqa %0,%%xmm0" : : "m" (*p));
+ asm volatile("pxor %0,%%xmm1" : : "m" (*dq));
+ asm volatile("pxor %0,%%xmm0" : : "m" (*dp));
+
+ /* 1 = dq ^ q
+ * 0 = dp ^ p
+ */
+ asm volatile("movdqa %0,%%xmm4" : : "m" (qmul[0]));
+ asm volatile("movdqa %0,%%xmm5" : : "m" (qmul[16]));
+
+ asm volatile("movdqa %xmm1,%xmm3");
+ asm volatile("psraw $4,%xmm1");
+ asm volatile("pand %xmm7,%xmm3");
+ asm volatile("pand %xmm7,%xmm1");
+ asm volatile("pshufb %xmm3,%xmm4");
+ asm volatile("pshufb %xmm1,%xmm5");
+ asm volatile("pxor %xmm4,%xmm5");
+
+ asm volatile("movdqa %xmm0,%xmm2"); /* xmm2 = px */
+
+ /* xmm5 = qx */
+
+ asm volatile("movdqa %0,%%xmm4" : : "m" (pbmul[0]));
+ asm volatile("movdqa %0,%%xmm1" : : "m" (pbmul[16]));
+ asm volatile("movdqa %xmm2,%xmm3");
+ asm volatile("psraw $4,%xmm2");
+ asm volatile("pand %xmm7,%xmm3");
+ asm volatile("pand %xmm7,%xmm2");
+ asm volatile("pshufb %xmm3,%xmm4");
+ asm volatile("pshufb %xmm2,%xmm1");
+ asm volatile("pxor %xmm4,%xmm1");
+
+ /* xmm1 = pbmul[px] */
+ asm volatile("pxor %xmm5,%xmm1");
+ /* xmm1 = db = DQ */
+ asm volatile("movdqa %%xmm1,%0" : "=m" (*dq));
+
+ asm volatile("pxor %xmm1,%xmm0");
+ asm volatile("movdqa %%xmm0,%0" : "=m" (*dp));
+
+ bytes -= 16;
+ p += 16;
+ q += 16;
+ dp += 16;
+ dq += 16;
+#endif
+ }
+
+ kernel_fpu_end();
+}
+
+
+void raid6_datap_recov_ssse3(int disks, size_t bytes, int faila, void **ptrs)
+{
+ u8 *p, *q, *dq;
+ const u8 *qmul; /* Q multiplier table */
+ static const u8 __aligned(16) x0f[16] = {
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f};
+
+ p = (u8 *)ptrs[disks-2];
+ q = (u8 *)ptrs[disks-1];
+
+ /* Compute syndrome with zero for the missing data page
+ Use the dead data page as temporary storage for delta q */
+ dq = (u8 *)ptrs[faila];
+ ptrs[faila] = (void *)raid6_empty_zero_page;
+ ptrs[disks-1] = dq;
+
+ raid6_call.gen_syndrome(disks, bytes, ptrs);
+
+ /* Restore pointer table */
+ ptrs[faila] = dq;
+ ptrs[disks-1] = q;
+
+ /* Now, pick the proper data tables */
+ qmul = raid6_vgfmul[raid6_gfinv[raid6_gfexp[faila]]];
+
+ kernel_fpu_begin();
+
+ asm volatile("movdqa %0, %%xmm7" : : "m" (x0f[0]));
+
+ while (bytes) {
+#ifdef CONFIG_X86_64
+ asm volatile("movdqa %0, %%xmm3" : : "m" (dq[0]));
+ asm volatile("movdqa %0, %%xmm4" : : "m" (dq[16]));
+ asm volatile("pxor %0, %%xmm3" : : "m" (q[0]));
+ asm volatile("movdqa %0, %%xmm0" : : "m" (qmul[0]));
+
+ /* xmm3 = q[0] ^ dq[0] */
+
+ asm volatile("pxor %0, %%xmm4" : : "m" (q[16]));
+ asm volatile("movdqa %0, %%xmm1" : : "m" (qmul[16]));
+
+ /* xmm4 = q[16] ^ dq[16] */
+
+ asm volatile("movdqa %xmm3, %xmm6");
+ asm volatile("movdqa %xmm4, %xmm8");
+
+ /* xmm4 = xmm8 = q[16] ^ dq[16] */
+
+ asm volatile("psraw $4, %xmm3");
+ asm volatile("pand %xmm7, %xmm6");
+ asm volatile("pand %xmm7, %xmm3");
+ asm volatile("pshufb %xmm6, %xmm0");
+ asm volatile("pshufb %xmm3, %xmm1");
+ asm volatile("movdqa %0, %%xmm10" : : "m" (qmul[0]));
+ asm volatile("pxor %xmm0, %xmm1");
+ asm volatile("movdqa %0, %%xmm11" : : "m" (qmul[16]));
+
+ /* xmm1 = qmul[q[0] ^ dq[0]] */
+
+ asm volatile("psraw $4, %xmm4");
+ asm volatile("pand %xmm7, %xmm8");
+ asm volatile("pand %xmm7, %xmm4");
+ asm volatile("pshufb %xmm8, %xmm10");
+ asm volatile("pshufb %xmm4, %xmm11");
+ asm volatile("movdqa %0, %%xmm2" : : "m" (p[0]));
+ asm volatile("pxor %xmm10, %xmm11");
+ asm volatile("movdqa %0, %%xmm12" : : "m" (p[16]));
+
+ /* xmm11 = qmul[q[16] ^ dq[16]] */
+
+ asm volatile("pxor %xmm1, %xmm2");
+
+ /* xmm2 = p[0] ^ qmul[q[0] ^ dq[0]] */
+
+ asm volatile("pxor %xmm11, %xmm12");
+
+ /* xmm12 = p[16] ^ qmul[q[16] ^ dq[16]] */
+
+ asm volatile("movdqa %%xmm1, %0" : "=m" (dq[0]));
+ asm volatile("movdqa %%xmm11, %0" : "=m" (dq[16]));
+
+ asm volatile("movdqa %%xmm2, %0" : "=m" (p[0]));
+ asm volatile("movdqa %%xmm12, %0" : "=m" (p[16]));
+
+ bytes -= 32;
+ p += 32;
+ q += 32;
+ dq += 32;
+
+#else
+ asm volatile("movdqa %0, %%xmm3" : : "m" (dq[0]));
+ asm volatile("movdqa %0, %%xmm0" : : "m" (qmul[0]));
+ asm volatile("pxor %0, %%xmm3" : : "m" (q[0]));
+ asm volatile("movdqa %0, %%xmm1" : : "m" (qmul[16]));
+
+ /* xmm3 = *q ^ *dq */
+
+ asm volatile("movdqa %xmm3, %xmm6");
+ asm volatile("movdqa %0, %%xmm2" : : "m" (p[0]));
+ asm volatile("psraw $4, %xmm3");
+ asm volatile("pand %xmm7, %xmm6");
+ asm volatile("pand %xmm7, %xmm3");
+ asm volatile("pshufb %xmm6, %xmm0");
+ asm volatile("pshufb %xmm3, %xmm1");
+ asm volatile("pxor %xmm0, %xmm1");
+
+ /* xmm1 = qmul[*q ^ *dq */
+
+ asm volatile("pxor %xmm1, %xmm2");
+
+ /* xmm2 = *p ^ qmul[*q ^ *dq] */
+
+ asm volatile("movdqa %%xmm1, %0" : "=m" (dq[0]));
+ asm volatile("movdqa %%xmm2, %0" : "=m" (p[0]));
+
+ bytes -= 16;
+ p += 16;
+ q += 16;
+ dq += 16;
+#endif
+ }
+
+ kernel_fpu_end();
+}
+
+const struct raid6_recov_calls raid6_recov_ssse3 = {
+ .data2 = raid6_2data_recov_ssse3,
+ .datap = raid6_datap_recov_ssse3,
+ .valid = raid6_has_ssse3,
+#ifdef CONFIG_X86_64
+ .name = "ssse3x2",
+#else
+ .name = "ssse3x1",
+#endif
+ .priority = 1,
+};
+
+#endif
diff --git a/lib/raid6/test/Makefile b/lib/raid6/test/Makefile
index aa651697b6dc..c76151d94764 100644
--- a/lib/raid6/test/Makefile
+++ b/lib/raid6/test/Makefile
@@ -23,7 +23,7 @@ RANLIB = ranlib
all: raid6.a raid6test
raid6.a: int1.o int2.o int4.o int8.o int16.o int32.o mmx.o sse1.o sse2.o \
- altivec1.o altivec2.o altivec4.o altivec8.o recov.o algos.o \
+ altivec1.o altivec2.o altivec4.o altivec8.o recov.o recov_ssse3.o algos.o \
tables.o
rm -f $@
$(AR) cq $@ $^
diff --git a/lib/raid6/test/test.c b/lib/raid6/test/test.c
index 7a930318b17d..5a485b7a7d3c 100644
--- a/lib/raid6/test/test.c
+++ b/lib/raid6/test/test.c
@@ -90,25 +90,35 @@ static int test_disks(int i, int j)
int main(int argc, char *argv[])
{
const struct raid6_calls *const *algo;
+ const struct raid6_recov_calls *const *ra;
int i, j;
int err = 0;
makedata();
- for (algo = raid6_algos; *algo; algo++) {
- if (!(*algo)->valid || (*algo)->valid()) {
- raid6_call = **algo;
+ for (ra = raid6_recov_algos; *ra; ra++) {
+ if ((*ra)->valid && !(*ra)->valid())
+ continue;
+ raid6_2data_recov = (*ra)->data2;
+ raid6_datap_recov = (*ra)->datap;
- /* Nuke syndromes */
- memset(data[NDISKS-2], 0xee, 2*PAGE_SIZE);
+ printf("using recovery %s\n", (*ra)->name);
- /* Generate assumed good syndrome */
- raid6_call.gen_syndrome(NDISKS, PAGE_SIZE,
- (void **)&dataptrs);
+ for (algo = raid6_algos; *algo; algo++) {
+ if (!(*algo)->valid || (*algo)->valid()) {
+ raid6_call = **algo;
- for (i = 0; i < NDISKS-1; i++)
- for (j = i+1; j < NDISKS; j++)
- err += test_disks(i, j);
+ /* Nuke syndromes */
+ memset(data[NDISKS-2], 0xee, 2*PAGE_SIZE);
+
+ /* Generate assumed good syndrome */
+ raid6_call.gen_syndrome(NDISKS, PAGE_SIZE,
+ (void **)&dataptrs);
+
+ for (i = 0; i < NDISKS-1; i++)
+ for (j = i+1; j < NDISKS; j++)
+ err += test_disks(i, j);
+ }
}
printf("\n");
}
diff --git a/lib/raid6/x86.h b/lib/raid6/x86.h
index cb2a8c91c886..d55d63232c55 100644
--- a/lib/raid6/x86.h
+++ b/lib/raid6/x86.h
@@ -35,24 +35,29 @@ static inline void kernel_fpu_end(void)
{
}
+#define __aligned(x) __attribute__((aligned(x)))
+
#define X86_FEATURE_MMX (0*32+23) /* Multimedia Extensions */
#define X86_FEATURE_FXSR (0*32+24) /* FXSAVE and FXRSTOR instructions
* (fast save and restore) */
#define X86_FEATURE_XMM (0*32+25) /* Streaming SIMD Extensions */
#define X86_FEATURE_XMM2 (0*32+26) /* Streaming SIMD Extensions-2 */
+#define X86_FEATURE_XMM3 (4*32+ 0) /* "pni" SSE-3 */
+#define X86_FEATURE_SSSE3 (4*32+ 9) /* Supplemental SSE-3 */
+#define X86_FEATURE_AVX (4*32+28) /* Advanced Vector Extensions */
#define X86_FEATURE_MMXEXT (1*32+22) /* AMD MMX extensions */
/* Should work well enough on modern CPUs for testing */
static inline int boot_cpu_has(int flag)
{
- u32 eax = (flag >> 5) ? 0x80000001 : 1;
- u32 edx;
+ u32 eax = (flag & 0x20) ? 0x80000001 : 1;
+ u32 ecx, edx;
asm volatile("cpuid"
- : "+a" (eax), "=d" (edx)
- : : "ecx", "ebx");
+ : "+a" (eax), "=d" (edx), "=c" (ecx)
+ : : "ebx");
- return (edx >> (flag & 31)) & 1;
+ return ((flag & 0x80 ? ecx : edx) >> (flag & 31)) & 1;
}
#endif /* ndef __KERNEL__ */
diff --git a/lib/rational.c b/lib/rational.c
index d326da3976f5..f0aa21c2a762 100644
--- a/lib/rational.c
+++ b/lib/rational.c
@@ -1,7 +1,7 @@
/*
* rational fractions
*
- * Copyright (C) 2009 emlix GmbH, Oskar Schirmer <os@emlix.com>
+ * Copyright (C) 2009 emlix GmbH, Oskar Schirmer <oskar@scara.com>
*
* helper functions when coping with rational numbers
*/
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 7685d4a0b3ce..f342778a0c0a 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -3873,14 +3873,21 @@ static inline u64 mem_cgroup_usage(struct mem_cgroup *memcg, bool swap)
return val << PAGE_SHIFT;
}
-static u64 mem_cgroup_read(struct cgroup *cont, struct cftype *cft)
+static ssize_t mem_cgroup_read(struct cgroup *cont, struct cftype *cft,
+ struct file *file, char __user *buf,
+ size_t nbytes, loff_t *ppos)
{
struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
+ char str[64];
u64 val;
- int type, name;
+ int type, name, len;
type = MEMFILE_TYPE(cft->private);
name = MEMFILE_ATTR(cft->private);
+
+ if (!do_swap_account && type == _MEMSWAP)
+ return -EOPNOTSUPP;
+
switch (type) {
case _MEM:
if (name == RES_USAGE)
@@ -3897,7 +3904,9 @@ static u64 mem_cgroup_read(struct cgroup *cont, struct cftype *cft)
default:
BUG();
}
- return val;
+
+ len = scnprintf(str, sizeof(str), "%llu\n", (unsigned long long)val);
+ return simple_read_from_buffer(buf, nbytes, ppos, str, len);
}
/*
* The user of this function is...
@@ -3913,6 +3922,10 @@ static int mem_cgroup_write(struct cgroup *cont, struct cftype *cft,
type = MEMFILE_TYPE(cft->private);
name = MEMFILE_ATTR(cft->private);
+
+ if (!do_swap_account && type == _MEMSWAP)
+ return -EOPNOTSUPP;
+
switch (name) {
case RES_LIMIT:
if (mem_cgroup_is_root(memcg)) { /* Can't set limit on root */
@@ -3978,12 +3991,15 @@ out:
static int mem_cgroup_reset(struct cgroup *cont, unsigned int event)
{
- struct mem_cgroup *memcg;
+ struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
int type, name;
- memcg = mem_cgroup_from_cont(cont);
type = MEMFILE_TYPE(event);
name = MEMFILE_ATTR(event);
+
+ if (!do_swap_account && type == _MEMSWAP)
+ return -EOPNOTSUPP;
+
switch (name) {
case RES_MAX_USAGE:
if (type == _MEM)
@@ -4624,29 +4640,22 @@ static int mem_control_numa_stat_open(struct inode *unused, struct file *file)
#endif /* CONFIG_NUMA */
#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM
-static int register_kmem_files(struct cgroup *cont, struct cgroup_subsys *ss)
+static int memcg_init_kmem(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
{
- /*
- * Part of this would be better living in a separate allocation
- * function, leaving us with just the cgroup tree population work.
- * We, however, depend on state such as network's proto_list that
- * is only initialized after cgroup creation. I found the less
- * cumbersome way to deal with it to defer it all to populate time
- */
- return mem_cgroup_sockets_init(cont, ss);
+ return mem_cgroup_sockets_init(memcg, ss);
};
-static void kmem_cgroup_destroy(struct cgroup *cont)
+static void kmem_cgroup_destroy(struct mem_cgroup *memcg)
{
- mem_cgroup_sockets_destroy(cont);
+ mem_cgroup_sockets_destroy(memcg);
}
#else
-static int register_kmem_files(struct cgroup *cont, struct cgroup_subsys *ss)
+static int memcg_init_kmem(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
{
return 0;
}
-static void kmem_cgroup_destroy(struct cgroup *cont)
+static void kmem_cgroup_destroy(struct mem_cgroup *memcg)
{
}
#endif
@@ -4655,7 +4664,7 @@ static struct cftype mem_cgroup_files[] = {
{
.name = "usage_in_bytes",
.private = MEMFILE_PRIVATE(_MEM, RES_USAGE),
- .read_u64 = mem_cgroup_read,
+ .read = mem_cgroup_read,
.register_event = mem_cgroup_usage_register_event,
.unregister_event = mem_cgroup_usage_unregister_event,
},
@@ -4663,25 +4672,25 @@ static struct cftype mem_cgroup_files[] = {
.name = "max_usage_in_bytes",
.private = MEMFILE_PRIVATE(_MEM, RES_MAX_USAGE),
.trigger = mem_cgroup_reset,
- .read_u64 = mem_cgroup_read,
+ .read = mem_cgroup_read,
},
{
.name = "limit_in_bytes",
.private = MEMFILE_PRIVATE(_MEM, RES_LIMIT),
.write_string = mem_cgroup_write,
- .read_u64 = mem_cgroup_read,
+ .read = mem_cgroup_read,
},
{
.name = "soft_limit_in_bytes",
.private = MEMFILE_PRIVATE(_MEM, RES_SOFT_LIMIT),
.write_string = mem_cgroup_write,
- .read_u64 = mem_cgroup_read,
+ .read = mem_cgroup_read,
},
{
.name = "failcnt",
.private = MEMFILE_PRIVATE(_MEM, RES_FAILCNT),
.trigger = mem_cgroup_reset,
- .read_u64 = mem_cgroup_read,
+ .read = mem_cgroup_read,
},
{
.name = "stat",
@@ -4721,14 +4730,11 @@ static struct cftype mem_cgroup_files[] = {
.mode = S_IRUGO,
},
#endif
-};
-
#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
-static struct cftype memsw_cgroup_files[] = {
{
.name = "memsw.usage_in_bytes",
.private = MEMFILE_PRIVATE(_MEMSWAP, RES_USAGE),
- .read_u64 = mem_cgroup_read,
+ .read = mem_cgroup_read,
.register_event = mem_cgroup_usage_register_event,
.unregister_event = mem_cgroup_usage_unregister_event,
},
@@ -4736,35 +4742,23 @@ static struct cftype memsw_cgroup_files[] = {
.name = "memsw.max_usage_in_bytes",
.private = MEMFILE_PRIVATE(_MEMSWAP, RES_MAX_USAGE),
.trigger = mem_cgroup_reset,
- .read_u64 = mem_cgroup_read,
+ .read = mem_cgroup_read,
},
{
.name = "memsw.limit_in_bytes",
.private = MEMFILE_PRIVATE(_MEMSWAP, RES_LIMIT),
.write_string = mem_cgroup_write,
- .read_u64 = mem_cgroup_read,
+ .read = mem_cgroup_read,
},
{
.name = "memsw.failcnt",
.private = MEMFILE_PRIVATE(_MEMSWAP, RES_FAILCNT),
.trigger = mem_cgroup_reset,
- .read_u64 = mem_cgroup_read,
+ .read = mem_cgroup_read,
},
-};
-
-static int register_memsw_files(struct cgroup *cont, struct cgroup_subsys *ss)
-{
- if (!do_swap_account)
- return 0;
- return cgroup_add_files(cont, ss, memsw_cgroup_files,
- ARRAY_SIZE(memsw_cgroup_files));
-};
-#else
-static int register_memsw_files(struct cgroup *cont, struct cgroup_subsys *ss)
-{
- return 0;
-}
#endif
+ { }, /* terminate */
+};
static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node)
{
@@ -5016,6 +5010,17 @@ mem_cgroup_create(struct cgroup *cont)
memcg->move_charge_at_immigrate = 0;
mutex_init(&memcg->thresholds_lock);
spin_lock_init(&memcg->move_lock);
+
+ error = memcg_init_kmem(memcg, &mem_cgroup_subsys);
+ if (error) {
+ /*
+ * We call put now because our (and parent's) refcnts
+ * are already in place. mem_cgroup_put() will internally
+ * call __mem_cgroup_free, so return directly
+ */
+ mem_cgroup_put(memcg);
+ return ERR_PTR(error);
+ }
return &memcg->css;
free_out:
__mem_cgroup_free(memcg);
@@ -5033,28 +5038,11 @@ static void mem_cgroup_destroy(struct cgroup *cont)
{
struct mem_cgroup *memcg = mem_cgroup_from_cont(cont);
- kmem_cgroup_destroy(cont);
+ kmem_cgroup_destroy(memcg);
mem_cgroup_put(memcg);
}
-static int mem_cgroup_populate(struct cgroup_subsys *ss,
- struct cgroup *cont)
-{
- int ret;
-
- ret = cgroup_add_files(cont, ss, mem_cgroup_files,
- ARRAY_SIZE(mem_cgroup_files));
-
- if (!ret)
- ret = register_memsw_files(cont, ss);
-
- if (!ret)
- ret = register_kmem_files(cont, ss);
-
- return ret;
-}
-
#ifdef CONFIG_MMU
/* Handlers for move charge at task migration. */
#define PRECHARGE_COUNT_AT_ONCE 256
@@ -5638,12 +5626,13 @@ struct cgroup_subsys mem_cgroup_subsys = {
.create = mem_cgroup_create,
.pre_destroy = mem_cgroup_pre_destroy,
.destroy = mem_cgroup_destroy,
- .populate = mem_cgroup_populate,
.can_attach = mem_cgroup_can_attach,
.cancel_attach = mem_cgroup_cancel_attach,
.attach = mem_cgroup_move_task,
+ .base_cftypes = mem_cgroup_files,
.early_init = 0,
.use_id = 1,
+ .__DEPRECATED_clear_css_refs = true,
};
#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
diff --git a/mm/memory.c b/mm/memory.c
index 1e77da6d82c1..e40f6759ba98 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1307,6 +1307,9 @@ static void unmap_single_vma(struct mmu_gather *tlb,
if (end <= vma->vm_start)
return;
+ if (vma->vm_file)
+ uprobe_munmap(vma, start, end);
+
if (unlikely(is_pfn_mapping(vma)))
untrack_pfn_vma(vma, 0, 0);
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index b19569137529..88f9422b92e7 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -607,27 +607,6 @@ check_range(struct mm_struct *mm, unsigned long start, unsigned long end,
return first;
}
-/* Apply policy to a single VMA */
-static int policy_vma(struct vm_area_struct *vma, struct mempolicy *new)
-{
- int err = 0;
- struct mempolicy *old = vma->vm_policy;
-
- pr_debug("vma %lx-%lx/%lx vm_ops %p vm_file %p set_policy %p\n",
- vma->vm_start, vma->vm_end, vma->vm_pgoff,
- vma->vm_ops, vma->vm_file,
- vma->vm_ops ? vma->vm_ops->set_policy : NULL);
-
- if (vma->vm_ops && vma->vm_ops->set_policy)
- err = vma->vm_ops->set_policy(vma, new);
- if (!err) {
- mpol_get(new);
- vma->vm_policy = new;
- mpol_put(old);
- }
- return err;
-}
-
/* Step 2: apply policy to a range and do splits. */
static int mbind_range(struct mm_struct *mm, unsigned long start,
unsigned long end, struct mempolicy *new_pol)
@@ -676,9 +655,23 @@ static int mbind_range(struct mm_struct *mm, unsigned long start,
if (err)
goto out;
}
- err = policy_vma(vma, new_pol);
- if (err)
- goto out;
+
+ /*
+ * Apply policy to a single VMA. The reference counting of
+ * policy for vma_policy linkages has already been handled by
+ * vma_merge and split_vma as necessary. If this is a shared
+ * policy then ->set_policy will increment the reference count
+ * for an sp node.
+ */
+ pr_debug("vma %lx-%lx/%lx vm_ops %p vm_file %p set_policy %p\n",
+ vma->vm_start, vma->vm_end, vma->vm_pgoff,
+ vma->vm_ops, vma->vm_file,
+ vma->vm_ops ? vma->vm_ops->set_policy : NULL);
+ if (vma->vm_ops && vma->vm_ops->set_policy) {
+ err = vma->vm_ops->set_policy(vma, new_pol);
+ if (err)
+ goto out;
+ }
}
out:
@@ -1334,8 +1327,8 @@ SYSCALL_DEFINE4(migrate_pages, pid_t, pid, unsigned long, maxnode,
* userid as the target process.
*/
tcred = __task_cred(task);
- if (cred->euid != tcred->suid && cred->euid != tcred->uid &&
- cred->uid != tcred->suid && cred->uid != tcred->uid &&
+ if (!uid_eq(cred->euid, tcred->suid) && !uid_eq(cred->euid, tcred->uid) &&
+ !uid_eq(cred->uid, tcred->suid) && !uid_eq(cred->uid, tcred->uid) &&
!capable(CAP_SYS_NICE)) {
rcu_read_unlock();
err = -EPERM;
diff --git a/mm/migrate.c b/mm/migrate.c
index 11072383ae12..ab81d482ae6f 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -1371,8 +1371,8 @@ SYSCALL_DEFINE6(move_pages, pid_t, pid, unsigned long, nr_pages,
* userid as the target process.
*/
tcred = __task_cred(task);
- if (cred->euid != tcred->suid && cred->euid != tcred->uid &&
- cred->uid != tcred->suid && cred->uid != tcred->uid &&
+ if (!uid_eq(cred->euid, tcred->suid) && !uid_eq(cred->euid, tcred->uid) &&
+ !uid_eq(cred->uid, tcred->suid) && !uid_eq(cred->uid, tcred->uid) &&
!capable(CAP_SYS_NICE)) {
rcu_read_unlock();
err = -EPERM;
diff --git a/mm/mmap.c b/mm/mmap.c
index 69a1889f3790..e8dcfc7de866 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -30,6 +30,7 @@
#include <linux/perf_event.h>
#include <linux/audit.h>
#include <linux/khugepaged.h>
+#include <linux/uprobes.h>
#include <asm/uaccess.h>
#include <asm/cacheflush.h>
@@ -546,8 +547,15 @@ again: remove_next = 1 + (end > next->vm_end);
if (file) {
mapping = file->f_mapping;
- if (!(vma->vm_flags & VM_NONLINEAR))
+ if (!(vma->vm_flags & VM_NONLINEAR)) {
root = &mapping->i_mmap;
+ uprobe_munmap(vma, vma->vm_start, vma->vm_end);
+
+ if (adjust_next)
+ uprobe_munmap(next, next->vm_start,
+ next->vm_end);
+ }
+
mutex_lock(&mapping->i_mmap_mutex);
if (insert) {
/*
@@ -617,8 +625,16 @@ again: remove_next = 1 + (end > next->vm_end);
if (mapping)
mutex_unlock(&mapping->i_mmap_mutex);
+ if (root) {
+ uprobe_mmap(vma);
+
+ if (adjust_next)
+ uprobe_mmap(next);
+ }
+
if (remove_next) {
if (file) {
+ uprobe_munmap(next, next->vm_start, next->vm_end);
fput(file);
if (next->vm_flags & VM_EXECUTABLE)
removed_exe_file_vma(mm);
@@ -638,6 +654,8 @@ again: remove_next = 1 + (end > next->vm_end);
goto again;
}
}
+ if (insert && file)
+ uprobe_mmap(insert);
validate_mm(mm);
@@ -1371,6 +1389,11 @@ out:
mm->locked_vm += (len >> PAGE_SHIFT);
} else if ((flags & MAP_POPULATE) && !(flags & MAP_NONBLOCK))
make_pages_present(addr, addr + len);
+
+ if (file && uprobe_mmap(vma))
+ /* matching probes but cannot insert */
+ goto unmap_and_free_vma;
+
return addr;
unmap_and_free_vma:
@@ -2358,6 +2381,10 @@ int insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma)
if ((vma->vm_flags & VM_ACCOUNT) &&
security_vm_enough_memory_mm(mm, vma_pages(vma)))
return -ENOMEM;
+
+ if (vma->vm_file && uprobe_mmap(vma))
+ return -EINVAL;
+
vma_link(mm, vma, prev, rb_link, rb_parent);
return 0;
}
@@ -2427,6 +2454,10 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
new_vma->vm_pgoff = pgoff;
if (new_vma->vm_file) {
get_file(new_vma->vm_file);
+
+ if (uprobe_mmap(new_vma))
+ goto out_free_mempol;
+
if (vma->vm_flags & VM_EXECUTABLE)
added_exe_file_vma(mm);
}
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 46bf2ed5594c..9f09a1fde9f9 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -410,8 +410,8 @@ static void dump_tasks(const struct mem_cgroup *memcg, const nodemask_t *nodemas
}
pr_info("[%5d] %5d %5d %8lu %8lu %3u %3d %5d %s\n",
- task->pid, task_uid(task), task->tgid,
- task->mm->total_vm, get_mm_rss(task->mm),
+ task->pid, from_kuid(&init_user_ns, task_uid(task)),
+ task->tgid, task->mm->total_vm, get_mm_rss(task->mm),
task_cpu(task), task->signal->oom_adj,
task->signal->oom_score_adj, task->comm);
task_unlock(task);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 918330f71dba..1851df600438 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -4763,12 +4763,12 @@ void __init free_area_init_nodes(unsigned long *max_zone_pfn)
for (i = 0; i < MAX_NR_ZONES; i++) {
if (i == ZONE_MOVABLE)
continue;
- printk(" %-8s ", zone_names[i]);
+ printk(KERN_CONT " %-8s ", zone_names[i]);
if (arch_zone_lowest_possible_pfn[i] ==
arch_zone_highest_possible_pfn[i])
- printk("empty\n");
+ printk(KERN_CONT "empty\n");
else
- printk("%0#10lx -> %0#10lx\n",
+ printk(KERN_CONT "%0#10lx -> %0#10lx\n",
arch_zone_lowest_possible_pfn[i],
arch_zone_highest_possible_pfn[i]);
}
@@ -5242,9 +5242,10 @@ void *__init alloc_large_system_hash(const char *tablename,
int flags,
unsigned int *_hash_shift,
unsigned int *_hash_mask,
- unsigned long limit)
+ unsigned long low_limit,
+ unsigned long high_limit)
{
- unsigned long long max = limit;
+ unsigned long long max = high_limit;
unsigned long log2qty, size;
void *table = NULL;
@@ -5282,6 +5283,8 @@ void *__init alloc_large_system_hash(const char *tablename,
}
max = min(max, 0x80000000ULL);
+ if (numentries < low_limit)
+ numentries = low_limit;
if (numentries > max)
numentries = max;
diff --git a/mm/shmem.c b/mm/shmem.c
index f99ff3e50bd6..d7b433a1ef5e 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -2075,6 +2075,8 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
bool remount)
{
char *this_char, *value, *rest;
+ uid_t uid;
+ gid_t gid;
while (options != NULL) {
this_char = options;
@@ -2134,15 +2136,21 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
} else if (!strcmp(this_char,"uid")) {
if (remount)
continue;
- sbinfo->uid = simple_strtoul(value, &rest, 0);
+ uid = simple_strtoul(value, &rest, 0);
if (*rest)
goto bad_val;
+ sbinfo->uid = make_kuid(current_user_ns(), uid);
+ if (!uid_valid(sbinfo->uid))
+ goto bad_val;
} else if (!strcmp(this_char,"gid")) {
if (remount)
continue;
- sbinfo->gid = simple_strtoul(value, &rest, 0);
+ gid = simple_strtoul(value, &rest, 0);
if (*rest)
goto bad_val;
+ sbinfo->gid = make_kgid(current_user_ns(), gid);
+ if (!gid_valid(sbinfo->gid))
+ goto bad_val;
} else if (!strcmp(this_char,"mpol")) {
if (mpol_parse_str(value, &sbinfo->mpol, 1))
goto bad_val;
@@ -2210,10 +2218,12 @@ static int shmem_show_options(struct seq_file *seq, struct dentry *root)
seq_printf(seq, ",nr_inodes=%lu", sbinfo->max_inodes);
if (sbinfo->mode != (S_IRWXUGO | S_ISVTX))
seq_printf(seq, ",mode=%03ho", sbinfo->mode);
- if (sbinfo->uid != 0)
- seq_printf(seq, ",uid=%u", sbinfo->uid);
- if (sbinfo->gid != 0)
- seq_printf(seq, ",gid=%u", sbinfo->gid);
+ if (!uid_eq(sbinfo->uid, GLOBAL_ROOT_UID))
+ seq_printf(seq, ",uid=%u",
+ from_kuid_munged(&init_user_ns, sbinfo->uid));
+ if (!gid_eq(sbinfo->gid, GLOBAL_ROOT_GID))
+ seq_printf(seq, ",gid=%u",
+ from_kgid_munged(&init_user_ns, sbinfo->gid));
shmem_show_mpol(seq, sbinfo->mpol);
return 0;
}
diff --git a/net/atm/lec.h b/net/atm/lec.h
index c730e57de199..a86aff9a3c04 100644
--- a/net/atm/lec.h
+++ b/net/atm/lec.h
@@ -55,11 +55,11 @@ struct lane2_ops {
* frames.
*
* 1. Dix Ethernet EtherType frames encoded by placing EtherType
- * field in h_type field. Data follows immediatelly after header.
+ * field in h_type field. Data follows immediately after header.
* 2. LLC Data frames whose total length, including LLC field and data,
* but not padding required to meet the minimum data frame length,
* is less than 1536(0x0600) MUST be encoded by placing that length
- * in the h_type field. The LLC field follows header immediatelly.
+ * in the h_type field. The LLC field follows header immediately.
* 3. LLC data frames longer than this maximum MUST be encoded by placing
* the value 0 in the h_type field.
*
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 6fb68a9743af..46e7f86acfc9 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -210,7 +210,7 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
}
if (sk->sk_state == BT_CONNECTED || !newsock ||
- bt_sk(parent)->defer_setup) {
+ test_bit(BT_DEFER_SETUP, &bt_sk(parent)->flags)) {
bt_accept_unlink(sk);
if (newsock)
sock_graft(sk, newsock);
@@ -410,8 +410,8 @@ static inline unsigned int bt_accept_poll(struct sock *parent)
list_for_each_safe(p, n, &bt_sk(parent)->accept_q) {
sk = (struct sock *) list_entry(p, struct bt_sock, accept_q);
if (sk->sk_state == BT_CONNECTED ||
- (bt_sk(parent)->defer_setup &&
- sk->sk_state == BT_CONNECT2))
+ (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags) &&
+ sk->sk_state == BT_CONNECT2))
return POLLIN | POLLRDNORM;
}
@@ -450,7 +450,7 @@ unsigned int bt_sock_poll(struct file *file, struct socket *sock, poll_table *wa
sk->sk_state == BT_CONFIG)
return mask;
- if (!bt_sk(sk)->suspended && sock_writeable(sk))
+ if (!test_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags) && sock_writeable(sk))
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
else
set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index 88884d1d95fd..031d7d656754 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -340,7 +340,7 @@ static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
}
/* Strip 802.1p header */
- if (ntohs(s->eh.h_proto) == 0x8100) {
+ if (ntohs(s->eh.h_proto) == ETH_P_8021Q) {
if (!skb_pull(skb, 4))
goto badframe;
s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 5238b6b3ea6a..3f18a6ed9731 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -223,36 +223,6 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
}
EXPORT_SYMBOL(hci_le_start_enc);
-void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16])
-{
- struct hci_dev *hdev = conn->hdev;
- struct hci_cp_le_ltk_reply cp;
-
- BT_DBG("%p", conn);
-
- memset(&cp, 0, sizeof(cp));
-
- cp.handle = cpu_to_le16(conn->handle);
- memcpy(cp.ltk, ltk, sizeof(ltk));
-
- hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);
-}
-EXPORT_SYMBOL(hci_le_ltk_reply);
-
-void hci_le_ltk_neg_reply(struct hci_conn *conn)
-{
- struct hci_dev *hdev = conn->hdev;
- struct hci_cp_le_ltk_neg_reply cp;
-
- BT_DBG("%p", conn);
-
- memset(&cp, 0, sizeof(cp));
-
- cp.handle = cpu_to_le16(conn->handle);
-
- hci_send_cmd(hdev, HCI_OP_LE_LTK_NEG_REPLY, sizeof(cp), &cp);
-}
-
/* Device _must_ be locked */
void hci_sco_setup(struct hci_conn *conn, __u8 status)
{
@@ -513,7 +483,8 @@ EXPORT_SYMBOL(hci_get_route);
/* Create SCO, ACL or LE connection.
* Device _must_ be locked */
-struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type)
+struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
+ __u8 dst_type, __u8 sec_level, __u8 auth_type)
{
struct hci_conn *acl;
struct hci_conn *sco;
@@ -522,23 +493,18 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
BT_DBG("%s dst %s", hdev->name, batostr(dst));
if (type == LE_LINK) {
- struct adv_entry *entry;
-
le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
- if (le)
- return ERR_PTR(-EBUSY);
-
- entry = hci_find_adv_entry(hdev, dst);
- if (!entry)
- return ERR_PTR(-EHOSTUNREACH);
+ if (!le) {
+ le = hci_conn_add(hdev, LE_LINK, dst);
+ if (!le)
+ return ERR_PTR(-ENOMEM);
- le = hci_conn_add(hdev, LE_LINK, dst);
- if (!le)
- return ERR_PTR(-ENOMEM);
-
- le->dst_type = entry->bdaddr_type;
+ le->dst_type = bdaddr_to_le(dst_type);
+ hci_le_connect(le);
+ }
- hci_le_connect(le);
+ le->pending_sec_level = sec_level;
+ le->auth_type = auth_type;
hci_conn_hold(le);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index d6dc44cd15b0..411ace8e647b 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -83,6 +83,7 @@ void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result)
*/
if (test_bit(HCI_INIT, &hdev->flags) && hdev->init_last_cmd != cmd) {
struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data;
+ u16 opcode = __le16_to_cpu(sent->opcode);
struct sk_buff *skb;
/* Some CSR based controllers generate a spontaneous
@@ -92,7 +93,7 @@ void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result)
* command.
*/
- if (cmd != HCI_OP_RESET || sent->opcode == HCI_OP_RESET)
+ if (cmd != HCI_OP_RESET || opcode == HCI_OP_RESET)
return;
skb = skb_clone(hdev->sent_cmd, GFP_ATOMIC);
@@ -251,6 +252,9 @@ static void amp_init(struct hci_dev *hdev)
/* Read Local Version */
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
+
+ /* Read Local AMP Info */
+ hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL);
}
static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
@@ -384,7 +388,6 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state)
case DISCOVERY_STOPPED:
if (hdev->discovery.state != DISCOVERY_STARTING)
mgmt_discovering(hdev, 0);
- hdev->discovery.type = 0;
break;
case DISCOVERY_STARTING:
break;
@@ -1089,32 +1092,6 @@ static const struct rfkill_ops hci_rfkill_ops = {
.set_block = hci_rfkill_set_block,
};
-/* Alloc HCI device */
-struct hci_dev *hci_alloc_dev(void)
-{
- struct hci_dev *hdev;
-
- hdev = kzalloc(sizeof(struct hci_dev), GFP_KERNEL);
- if (!hdev)
- return NULL;
-
- hci_init_sysfs(hdev);
- skb_queue_head_init(&hdev->driver_init);
-
- return hdev;
-}
-EXPORT_SYMBOL(hci_alloc_dev);
-
-/* Free HCI device */
-void hci_free_dev(struct hci_dev *hdev)
-{
- skb_queue_purge(&hdev->driver_init);
-
- /* will free via device release */
- put_device(&hdev->dev);
-}
-EXPORT_SYMBOL(hci_free_dev);
-
static void hci_power_on(struct work_struct *work)
{
struct hci_dev *hdev = container_of(work, struct hci_dev, power_on);
@@ -1336,7 +1313,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
}
int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type,
- int new_key, u8 authenticated, u8 tk[16], u8 enc_size, u16
+ int new_key, u8 authenticated, u8 tk[16], u8 enc_size, __le16
ediv, u8 rand[8])
{
struct smp_ltk *key, *old_key;
@@ -1544,75 +1521,6 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
return mgmt_device_unblocked(hdev, bdaddr, type);
}
-static void hci_clear_adv_cache(struct work_struct *work)
-{
- struct hci_dev *hdev = container_of(work, struct hci_dev,
- adv_work.work);
-
- hci_dev_lock(hdev);
-
- hci_adv_entries_clear(hdev);
-
- hci_dev_unlock(hdev);
-}
-
-int hci_adv_entries_clear(struct hci_dev *hdev)
-{
- struct adv_entry *entry, *tmp;
-
- list_for_each_entry_safe(entry, tmp, &hdev->adv_entries, list) {
- list_del(&entry->list);
- kfree(entry);
- }
-
- BT_DBG("%s adv cache cleared", hdev->name);
-
- return 0;
-}
-
-struct adv_entry *hci_find_adv_entry(struct hci_dev *hdev, bdaddr_t *bdaddr)
-{
- struct adv_entry *entry;
-
- list_for_each_entry(entry, &hdev->adv_entries, list)
- if (bacmp(bdaddr, &entry->bdaddr) == 0)
- return entry;
-
- return NULL;
-}
-
-static inline int is_connectable_adv(u8 evt_type)
-{
- if (evt_type == ADV_IND || evt_type == ADV_DIRECT_IND)
- return 1;
-
- return 0;
-}
-
-int hci_add_adv_entry(struct hci_dev *hdev,
- struct hci_ev_le_advertising_info *ev) { struct adv_entry *entry; if (!is_connectable_adv(ev->evt_type))
- return -EINVAL;
-
- /* Only new entries should be added to adv_entries. So, if
- * bdaddr was found, don't add it. */
- if (hci_find_adv_entry(hdev, &ev->bdaddr))
- return 0;
-
- entry = kzalloc(sizeof(*entry), GFP_KERNEL);
- if (!entry)
- return -ENOMEM;
-
- bacpy(&entry->bdaddr, &ev->bdaddr);
- entry->bdaddr_type = ev->bdaddr_type;
-
- list_add(&entry->list, &hdev->adv_entries);
-
- BT_DBG("%s adv entry added: address %s type %u", hdev->name,
- batostr(&entry->bdaddr), entry->bdaddr_type);
-
- return 0;
-}
-
static void le_scan_param_req(struct hci_dev *hdev, unsigned long opt)
{
struct le_scan_params *param = (struct le_scan_params *) opt;
@@ -1670,6 +1578,24 @@ static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval,
return 0;
}
+int hci_cancel_le_scan(struct hci_dev *hdev)
+{
+ BT_DBG("%s", hdev->name);
+
+ if (!test_bit(HCI_LE_SCAN, &hdev->dev_flags))
+ return -EALREADY;
+
+ if (cancel_delayed_work(&hdev->le_scan_disable)) {
+ struct hci_cp_le_set_scan_enable cp;
+
+ /* Send HCI command to disable LE Scan */
+ memset(&cp, 0, sizeof(cp));
+ hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
+ }
+
+ return 0;
+}
+
static void le_scan_disable_work(struct work_struct *work)
{
struct hci_dev *hdev = container_of(work, struct hci_dev,
@@ -1714,95 +1640,103 @@ int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window,
return 0;
}
-/* Register HCI device */
-int hci_register_dev(struct hci_dev *hdev)
+/* Alloc HCI device */
+struct hci_dev *hci_alloc_dev(void)
{
- struct list_head *head = &hci_dev_list, *p;
- int i, id, error;
-
- BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
-
- if (!hdev->open || !hdev->close)
- return -EINVAL;
-
- /* Do not allow HCI_AMP devices to register at index 0,
- * so the index can be used as the AMP controller ID.
- */
- id = (hdev->dev_type == HCI_BREDR) ? 0 : 1;
-
- write_lock(&hci_dev_list_lock);
-
- /* Find first available device id */
- list_for_each(p, &hci_dev_list) {
- if (list_entry(p, struct hci_dev, list)->id != id)
- break;
- head = p; id++;
- }
-
- sprintf(hdev->name, "hci%d", id);
- hdev->id = id;
- list_add_tail(&hdev->list, head);
+ struct hci_dev *hdev;
- mutex_init(&hdev->lock);
+ hdev = kzalloc(sizeof(struct hci_dev), GFP_KERNEL);
+ if (!hdev)
+ return NULL;
- hdev->flags = 0;
- hdev->dev_flags = 0;
hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1);
hdev->esco_type = (ESCO_HV1);
hdev->link_mode = (HCI_LM_ACCEPT);
hdev->io_capability = 0x03; /* No Input No Output */
- hdev->idle_timeout = 0;
hdev->sniff_max_interval = 800;
hdev->sniff_min_interval = 80;
+ mutex_init(&hdev->lock);
+ mutex_init(&hdev->req_lock);
+
+ INIT_LIST_HEAD(&hdev->mgmt_pending);
+ INIT_LIST_HEAD(&hdev->blacklist);
+ INIT_LIST_HEAD(&hdev->uuids);
+ INIT_LIST_HEAD(&hdev->link_keys);
+ INIT_LIST_HEAD(&hdev->long_term_keys);
+ INIT_LIST_HEAD(&hdev->remote_oob_data);
+
INIT_WORK(&hdev->rx_work, hci_rx_work);
INIT_WORK(&hdev->cmd_work, hci_cmd_work);
INIT_WORK(&hdev->tx_work, hci_tx_work);
+ INIT_WORK(&hdev->power_on, hci_power_on);
+ INIT_WORK(&hdev->le_scan, le_scan_work);
+ INIT_DELAYED_WORK(&hdev->power_off, hci_power_off);
+ INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off);
+ INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work);
+ skb_queue_head_init(&hdev->driver_init);
skb_queue_head_init(&hdev->rx_q);
skb_queue_head_init(&hdev->cmd_q);
skb_queue_head_init(&hdev->raw_q);
- setup_timer(&hdev->cmd_timer, hci_cmd_timer, (unsigned long) hdev);
-
- for (i = 0; i < NUM_REASSEMBLY; i++)
- hdev->reassembly[i] = NULL;
-
init_waitqueue_head(&hdev->req_wait_q);
- mutex_init(&hdev->req_lock);
- discovery_init(hdev);
+ setup_timer(&hdev->cmd_timer, hci_cmd_timer, (unsigned long) hdev);
+ hci_init_sysfs(hdev);
+ discovery_init(hdev);
hci_conn_hash_init(hdev);
- INIT_LIST_HEAD(&hdev->mgmt_pending);
-
- INIT_LIST_HEAD(&hdev->blacklist);
+ return hdev;
+}
+EXPORT_SYMBOL(hci_alloc_dev);
- INIT_LIST_HEAD(&hdev->uuids);
+/* Free HCI device */
+void hci_free_dev(struct hci_dev *hdev)
+{
+ skb_queue_purge(&hdev->driver_init);
- INIT_LIST_HEAD(&hdev->link_keys);
- INIT_LIST_HEAD(&hdev->long_term_keys);
+ /* will free via device release */
+ put_device(&hdev->dev);
+}
+EXPORT_SYMBOL(hci_free_dev);
- INIT_LIST_HEAD(&hdev->remote_oob_data);
+/* Register HCI device */
+int hci_register_dev(struct hci_dev *hdev)
+{
+ struct list_head *head, *p;
+ int id, error;
- INIT_LIST_HEAD(&hdev->adv_entries);
+ if (!hdev->open || !hdev->close)
+ return -EINVAL;
- INIT_DELAYED_WORK(&hdev->adv_work, hci_clear_adv_cache);
- INIT_WORK(&hdev->power_on, hci_power_on);
- INIT_DELAYED_WORK(&hdev->power_off, hci_power_off);
+ write_lock(&hci_dev_list_lock);
- INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off);
+ /* Do not allow HCI_AMP devices to register at index 0,
+ * so the index can be used as the AMP controller ID.
+ */
+ id = (hdev->dev_type == HCI_BREDR) ? 0 : 1;
+ head = &hci_dev_list;
- memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
+ /* Find first available device id */
+ list_for_each(p, &hci_dev_list) {
+ int nid = list_entry(p, struct hci_dev, list)->id;
+ if (nid > id)
+ break;
+ if (nid == id)
+ id++;
+ head = p;
+ }
- atomic_set(&hdev->promisc, 0);
+ sprintf(hdev->name, "hci%d", id);
+ hdev->id = id;
- INIT_WORK(&hdev->le_scan, le_scan_work);
+ BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
- INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work);
+ list_add(&hdev->list, head);
write_unlock(&hci_dev_list_lock);
@@ -1884,8 +1818,6 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_del_sysfs(hdev);
- cancel_delayed_work_sync(&hdev->adv_work);
-
destroy_workqueue(hdev->workqueue);
hci_dev_lock(hdev);
@@ -1894,7 +1826,6 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_link_keys_clear(hdev);
hci_smp_ltks_clear(hdev);
hci_remote_oob_data_clear(hdev);
- hci_adv_entries_clear(hdev);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
@@ -2231,6 +2162,12 @@ static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
struct hci_dev *hdev = conn->hdev;
struct sk_buff *list;
+ skb->len = skb_headlen(skb);
+ skb->data_len = 0;
+
+ bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
+ hci_add_acl_hdr(skb, conn->handle, flags);
+
list = skb_shinfo(skb)->frag_list;
if (!list) {
/* Non fragmented */
@@ -2274,8 +2211,6 @@ void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
BT_DBG("%s chan %p flags 0x%x", hdev->name, chan, flags);
skb->dev = (void *) hdev;
- bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
- hci_add_acl_hdr(skb, conn->handle, flags);
hci_queue_acl(conn, &chan->data_q, skb, flags);
@@ -2313,7 +2248,7 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
{
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *conn = NULL, *c;
- int num = 0, min = ~0;
+ unsigned int num = 0, min = ~0;
/* We don't have to lock device here. Connections are always
* added and removed with TX task disabled. */
@@ -2394,7 +2329,7 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
{
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_chan *chan = NULL;
- int num = 0, min = ~0, cur_prio = 0;
+ unsigned int num = 0, min = ~0, cur_prio = 0;
struct hci_conn *conn;
int cnt, q, conn_num = 0;
@@ -2945,7 +2880,19 @@ int hci_cancel_inquiry(struct hci_dev *hdev)
BT_DBG("%s", hdev->name);
if (!test_bit(HCI_INQUIRY, &hdev->flags))
- return -EPERM;
+ return -EALREADY;
return hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
}
+
+u8 bdaddr_to_le(u8 bdaddr_type)
+{
+ switch (bdaddr_type) {
+ case BDADDR_LE_PUBLIC:
+ return ADDR_LE_DEV_PUBLIC;
+
+ default:
+ /* Fallback to LE Random address type */
+ return ADDR_LE_DEV_RANDOM;
+ }
+}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 1266f78fa8e3..4eefb7f65cf6 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -69,6 +69,18 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
hci_conn_check_pending(hdev);
}
+static void hci_cc_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ __u8 status = *((__u8 *) skb->data);
+
+ BT_DBG("%s status 0x%x", hdev->name, status);
+
+ if (status)
+ return;
+
+ set_bit(HCI_PERIODIC_INQ, &hdev->dev_flags);
+}
+
static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
@@ -78,6 +90,8 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
if (status)
return;
+ clear_bit(HCI_PERIODIC_INQ, &hdev->dev_flags);
+
hci_conn_check_pending(hdev);
}
@@ -192,7 +206,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
hci_req_complete(hdev, HCI_OP_RESET, status);
/* Reset all non-persistent flags */
- hdev->dev_flags &= ~(BIT(HCI_LE_SCAN) | BIT(HCI_PENDING_CLASS));
+ hdev->dev_flags &= ~(BIT(HCI_LE_SCAN) | BIT(HCI_PENDING_CLASS) |
+ BIT(HCI_PERIODIC_INQ));
hdev->discovery.state = DISCOVERY_STOPPED;
}
@@ -505,7 +520,7 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
events[5] |= 0x10; /* Synchronous Connection Changed */
if (hdev->features[3] & LMP_RSSI_INQ)
- events[4] |= 0x04; /* Inquiry Result with RSSI */
+ events[4] |= 0x02; /* Inquiry Result with RSSI */
if (hdev->features[5] & LMP_SNIFF_SUBR)
events[5] |= 0x20; /* Sniff Subrating */
@@ -615,6 +630,7 @@ done:
static void hci_setup_link_policy(struct hci_dev *hdev)
{
+ struct hci_cp_write_def_link_policy cp;
u16 link_policy = 0;
if (hdev->features[0] & LMP_RSWITCH)
@@ -626,9 +642,8 @@ static void hci_setup_link_policy(struct hci_dev *hdev)
if (hdev->features[1] & LMP_PARK)
link_policy |= HCI_LP_PARK;
- link_policy = cpu_to_le16(link_policy);
- hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(link_policy),
- &link_policy);
+ cp.policy = cpu_to_le16(link_policy);
+ hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(cp), &cp);
}
static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb)
@@ -710,7 +725,7 @@ static void hci_set_le_support(struct hci_dev *hdev)
memset(&cp, 0, sizeof(cp));
- if (enable_le && test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
+ if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
cp.le = 1;
cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
}
@@ -887,11 +902,14 @@ static void hci_cc_write_inquiry_mode(struct hci_dev *hdev,
static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev,
struct sk_buff *skb)
{
- __u8 status = *((__u8 *) skb->data);
+ struct hci_rp_read_inq_rsp_tx_power *rp = (void *) skb->data;
- BT_DBG("%s status 0x%x", hdev->name, status);
+ BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+ if (!rp->status)
+ hdev->inq_tx_power = rp->tx_power;
- hci_req_complete(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, status);
+ hci_req_complete(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, rp->status);
}
static void hci_cc_set_event_flt(struct hci_dev *hdev, struct sk_buff *skb)
@@ -1082,23 +1100,23 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
set_bit(HCI_LE_SCAN, &hdev->dev_flags);
- cancel_delayed_work_sync(&hdev->adv_work);
-
hci_dev_lock(hdev);
- hci_adv_entries_clear(hdev);
hci_discovery_set_state(hdev, DISCOVERY_FINDING);
hci_dev_unlock(hdev);
break;
case LE_SCANNING_DISABLED:
- if (status)
+ if (status) {
+ hci_dev_lock(hdev);
+ mgmt_stop_discovery_failed(hdev, status);
+ hci_dev_unlock(hdev);
return;
+ }
clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
- schedule_delayed_work(&hdev->adv_work, ADV_CLEAR_TIMEOUT);
-
- if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED) {
+ if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
+ hdev->discovery.state == DISCOVERY_FINDING) {
mgmt_interleaved_discovery(hdev);
} else {
hci_dev_lock(hdev);
@@ -1625,6 +1643,8 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
if (status) {
if (conn && conn->state == BT_CONNECT) {
conn->state = BT_CLOSED;
+ mgmt_connect_failed(hdev, &cp->peer_addr, conn->type,
+ conn->dst_type, status);
hci_proto_connect_cfm(conn, status);
hci_conn_del(conn);
}
@@ -1699,6 +1719,9 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
if (!num_rsp)
return;
+ if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags))
+ return;
+
hci_dev_lock(hdev);
for (; num_rsp; num_rsp--, info++) {
@@ -2040,7 +2063,7 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
if (ev->status && conn->state == BT_CONNECTED) {
- hci_acl_disconn(conn, 0x13);
+ hci_acl_disconn(conn, HCI_ERROR_AUTH_FAILURE);
hci_conn_put(conn);
goto unlock;
}
@@ -2154,6 +2177,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_inquiry_cancel(hdev, skb);
break;
+ case HCI_OP_PERIODIC_INQ:
+ hci_cc_periodic_inq(hdev, skb);
+ break;
+
case HCI_OP_EXIT_PERIODIC_INQ:
hci_cc_exit_periodic_inq(hdev, skb);
break;
@@ -2806,6 +2833,9 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
if (!num_rsp)
return;
+ if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags))
+ return;
+
hci_dev_lock(hdev);
if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
@@ -2971,12 +3001,16 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
struct inquiry_data data;
struct extended_inquiry_info *info = (void *) (skb->data + 1);
int num_rsp = *((__u8 *) skb->data);
+ size_t eir_len;
BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
if (!num_rsp)
return;
+ if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags))
+ return;
+
hci_dev_lock(hdev);
for (; num_rsp; num_rsp--, info++) {
@@ -3000,9 +3034,10 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
name_known = hci_inquiry_cache_update(hdev, &data, name_known,
&ssp);
+ eir_len = eir_get_length(info->data, sizeof(info->data));
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00,
info->dev_class, info->rssi, !name_known,
- ssp, info->data, sizeof(info->data));
+ ssp, info->data, eir_len);
}
hci_dev_unlock(hdev);
@@ -3322,8 +3357,6 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
while (num_reports--) {
struct hci_ev_le_advertising_info *ev = ptr;
- hci_add_adv_entry(hdev, ev);
-
rssi = ev->data[ev->length];
mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type,
NULL, rssi, 0, 1, ev->data, ev->length);
@@ -3343,7 +3376,7 @@ static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
struct hci_conn *conn;
struct smp_ltk *ltk;
- BT_DBG("%s handle %d", hdev->name, cpu_to_le16(ev->handle));
+ BT_DBG("%s handle %d", hdev->name, __le16_to_cpu(ev->handle));
hci_dev_lock(hdev);
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index bc154298979a..937f3187eafa 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -444,8 +444,8 @@ static const struct file_operations blacklist_fops = {
static void print_bt_uuid(struct seq_file *f, u8 *uuid)
{
- u32 data0, data4;
- u16 data1, data2, data3, data5;
+ __be32 data0, data4;
+ __be16 data1, data2, data3, data5;
memcpy(&data0, &uuid[0], 4);
memcpy(&data1, &uuid[4], 2);
@@ -533,7 +533,6 @@ int hci_add_sysfs(struct hci_dev *hdev)
BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
- dev->parent = hdev->parent;
dev_set_name(dev, "%s", hdev->name);
err = device_add(dev);
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index d478be11d562..2c20d765b394 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -1195,41 +1195,16 @@ int hidp_get_conninfo(struct hidp_conninfo *ci)
return err;
}
-static const struct hid_device_id hidp_table[] = {
- { HID_BLUETOOTH_DEVICE(HID_ANY_ID, HID_ANY_ID) },
- { }
-};
-
-static struct hid_driver hidp_driver = {
- .name = "generic-bluetooth",
- .id_table = hidp_table,
-};
-
static int __init hidp_init(void)
{
- int ret;
-
BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
- ret = hid_register_driver(&hidp_driver);
- if (ret)
- goto err;
-
- ret = hidp_init_sockets();
- if (ret)
- goto err_drv;
-
- return 0;
-err_drv:
- hid_unregister_driver(&hidp_driver);
-err:
- return ret;
+ return hidp_init_sockets();
}
static void __exit hidp_exit(void)
{
hidp_cleanup_sockets();
- hid_unregister_driver(&hidp_driver);
}
module_init(hidp_init);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 6f9c25b633a6..24f144b72a96 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4,6 +4,7 @@
Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
Copyright (C) 2010 Google Inc.
Copyright (C) 2011 ProFUSION Embedded Systems
+ Copyright (c) 2012 Code Aurora Forum. All rights reserved.
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -70,7 +71,7 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
void *data);
static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
static void l2cap_send_disconn_req(struct l2cap_conn *conn,
- struct l2cap_chan *chan, int err);
+ struct l2cap_chan *chan, int err);
/* ---- L2CAP channels ---- */
@@ -97,13 +98,15 @@ static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16
}
/* Find channel with given SCID.
- * Returns locked socket */
+ * Returns locked channel. */
static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
{
struct l2cap_chan *c;
mutex_lock(&conn->chan_lock);
c = __l2cap_get_chan_by_scid(conn, cid);
+ if (c)
+ l2cap_chan_lock(c);
mutex_unlock(&conn->chan_lock);
return c;
@@ -120,17 +123,6 @@ static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8
return NULL;
}
-static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
-{
- struct l2cap_chan *c;
-
- mutex_lock(&conn->chan_lock);
- c = __l2cap_get_chan_by_ident(conn, ident);
- mutex_unlock(&conn->chan_lock);
-
- return c;
-}
-
static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
{
struct l2cap_chan *c;
@@ -232,6 +224,124 @@ static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err)
release_sock(sk);
}
+/* ---- L2CAP sequence number lists ---- */
+
+/* For ERTM, ordered lists of sequence numbers must be tracked for
+ * SREJ requests that are received and for frames that are to be
+ * retransmitted. These seq_list functions implement a singly-linked
+ * list in an array, where membership in the list can also be checked
+ * in constant time. Items can also be added to the tail of the list
+ * and removed from the head in constant time, without further memory
+ * allocs or frees.
+ */
+
+static int l2cap_seq_list_init(struct l2cap_seq_list *seq_list, u16 size)
+{
+ size_t alloc_size, i;
+
+ /* Allocated size is a power of 2 to map sequence numbers
+ * (which may be up to 14 bits) in to a smaller array that is
+ * sized for the negotiated ERTM transmit windows.
+ */
+ alloc_size = roundup_pow_of_two(size);
+
+ seq_list->list = kmalloc(sizeof(u16) * alloc_size, GFP_KERNEL);
+ if (!seq_list->list)
+ return -ENOMEM;
+
+ seq_list->mask = alloc_size - 1;
+ seq_list->head = L2CAP_SEQ_LIST_CLEAR;
+ seq_list->tail = L2CAP_SEQ_LIST_CLEAR;
+ for (i = 0; i < alloc_size; i++)
+ seq_list->list[i] = L2CAP_SEQ_LIST_CLEAR;
+
+ return 0;
+}
+
+static inline void l2cap_seq_list_free(struct l2cap_seq_list *seq_list)
+{
+ kfree(seq_list->list);
+}
+
+static inline bool l2cap_seq_list_contains(struct l2cap_seq_list *seq_list,
+ u16 seq)
+{
+ /* Constant-time check for list membership */
+ return seq_list->list[seq & seq_list->mask] != L2CAP_SEQ_LIST_CLEAR;
+}
+
+static u16 l2cap_seq_list_remove(struct l2cap_seq_list *seq_list, u16 seq)
+{
+ u16 mask = seq_list->mask;
+
+ if (seq_list->head == L2CAP_SEQ_LIST_CLEAR) {
+ /* In case someone tries to pop the head of an empty list */
+ return L2CAP_SEQ_LIST_CLEAR;
+ } else if (seq_list->head == seq) {
+ /* Head can be removed in constant time */
+ seq_list->head = seq_list->list[seq & mask];
+ seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR;
+
+ if (seq_list->head == L2CAP_SEQ_LIST_TAIL) {
+ seq_list->head = L2CAP_SEQ_LIST_CLEAR;
+ seq_list->tail = L2CAP_SEQ_LIST_CLEAR;
+ }
+ } else {
+ /* Walk the list to find the sequence number */
+ u16 prev = seq_list->head;
+ while (seq_list->list[prev & mask] != seq) {
+ prev = seq_list->list[prev & mask];
+ if (prev == L2CAP_SEQ_LIST_TAIL)
+ return L2CAP_SEQ_LIST_CLEAR;
+ }
+
+ /* Unlink the number from the list and clear it */
+ seq_list->list[prev & mask] = seq_list->list[seq & mask];
+ seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR;
+ if (seq_list->tail == seq)
+ seq_list->tail = prev;
+ }
+ return seq;
+}
+
+static inline u16 l2cap_seq_list_pop(struct l2cap_seq_list *seq_list)
+{
+ /* Remove the head in constant time */
+ return l2cap_seq_list_remove(seq_list, seq_list->head);
+}
+
+static void l2cap_seq_list_clear(struct l2cap_seq_list *seq_list)
+{
+ u16 i;
+
+ if (seq_list->head == L2CAP_SEQ_LIST_CLEAR)
+ return;
+
+ for (i = 0; i <= seq_list->mask; i++)
+ seq_list->list[i] = L2CAP_SEQ_LIST_CLEAR;
+
+ seq_list->head = L2CAP_SEQ_LIST_CLEAR;
+ seq_list->tail = L2CAP_SEQ_LIST_CLEAR;
+}
+
+static void l2cap_seq_list_append(struct l2cap_seq_list *seq_list, u16 seq)
+{
+ u16 mask = seq_list->mask;
+
+ /* All appends happen in constant time */
+
+ if (seq_list->list[seq & mask] != L2CAP_SEQ_LIST_CLEAR)
+ return;
+
+ if (seq_list->tail == L2CAP_SEQ_LIST_CLEAR)
+ seq_list->head = seq;
+ else
+ seq_list->list[seq_list->tail & mask] = seq;
+
+ seq_list->tail = seq;
+ seq_list->list[seq & mask] = L2CAP_SEQ_LIST_TAIL;
+}
+
static void l2cap_chan_timeout(struct work_struct *work)
{
struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
@@ -262,7 +372,7 @@ static void l2cap_chan_timeout(struct work_struct *work)
l2cap_chan_put(chan);
}
-struct l2cap_chan *l2cap_chan_create(struct sock *sk)
+struct l2cap_chan *l2cap_chan_create(void)
{
struct l2cap_chan *chan;
@@ -272,8 +382,6 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk)
mutex_init(&chan->lock);
- chan->sk = sk;
-
write_lock(&chan_list_lock);
list_add(&chan->global_l, &chan_list);
write_unlock(&chan_list_lock);
@@ -284,7 +392,7 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk)
atomic_set(&chan->refcnt, 1);
- BT_DBG("sk %p chan %p", sk, chan);
+ BT_DBG("chan %p", chan);
return chan;
}
@@ -298,10 +406,21 @@ void l2cap_chan_destroy(struct l2cap_chan *chan)
l2cap_chan_put(chan);
}
-void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
+void l2cap_chan_set_defaults(struct l2cap_chan *chan)
+{
+ chan->fcs = L2CAP_FCS_CRC16;
+ chan->max_tx = L2CAP_DEFAULT_MAX_TX;
+ chan->tx_win = L2CAP_DEFAULT_TX_WINDOW;
+ chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
+ chan->sec_level = BT_SECURITY_LOW;
+
+ set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
+}
+
+static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
{
BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
- chan->psm, chan->dcid);
+ __le16_to_cpu(chan->psm), chan->dcid);
conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
@@ -347,7 +466,7 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
list_add(&chan->list, &conn->chan_l);
}
-void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
+static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
{
mutex_lock(&conn->chan_lock);
__l2cap_chan_add(conn, chan);
@@ -405,6 +524,8 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err)
skb_queue_purge(&chan->srej_q);
+ l2cap_seq_list_free(&chan->srej_list);
+ l2cap_seq_list_free(&chan->retrans_list);
list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
list_del(&l->list);
kfree(l);
@@ -453,7 +574,6 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
case BT_CONFIG:
if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
conn->hcon->type == ACL_LINK) {
- __clear_chan_timer(chan);
__set_chan_timer(chan, sk->sk_sndtimeo);
l2cap_send_disconn_req(conn, chan, reason);
} else
@@ -466,7 +586,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
struct l2cap_conn_rsp rsp;
__u16 result;
- if (bt_sk(sk)->defer_setup)
+ if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))
result = L2CAP_CR_SEC_BLOCK;
else
result = L2CAP_CR_BAD_PSM;
@@ -599,6 +719,117 @@ static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
hci_send_acl(chan->conn->hchan, skb, flags);
}
+static void __unpack_enhanced_control(u16 enh, struct l2cap_ctrl *control)
+{
+ control->reqseq = (enh & L2CAP_CTRL_REQSEQ) >> L2CAP_CTRL_REQSEQ_SHIFT;
+ control->final = (enh & L2CAP_CTRL_FINAL) >> L2CAP_CTRL_FINAL_SHIFT;
+
+ if (enh & L2CAP_CTRL_FRAME_TYPE) {
+ /* S-Frame */
+ control->sframe = 1;
+ control->poll = (enh & L2CAP_CTRL_POLL) >> L2CAP_CTRL_POLL_SHIFT;
+ control->super = (enh & L2CAP_CTRL_SUPERVISE) >> L2CAP_CTRL_SUPER_SHIFT;
+
+ control->sar = 0;
+ control->txseq = 0;
+ } else {
+ /* I-Frame */
+ control->sframe = 0;
+ control->sar = (enh & L2CAP_CTRL_SAR) >> L2CAP_CTRL_SAR_SHIFT;
+ control->txseq = (enh & L2CAP_CTRL_TXSEQ) >> L2CAP_CTRL_TXSEQ_SHIFT;
+
+ control->poll = 0;
+ control->super = 0;
+ }
+}
+
+static void __unpack_extended_control(u32 ext, struct l2cap_ctrl *control)
+{
+ control->reqseq = (ext & L2CAP_EXT_CTRL_REQSEQ) >> L2CAP_EXT_CTRL_REQSEQ_SHIFT;
+ control->final = (ext & L2CAP_EXT_CTRL_FINAL) >> L2CAP_EXT_CTRL_FINAL_SHIFT;
+
+ if (ext & L2CAP_EXT_CTRL_FRAME_TYPE) {
+ /* S-Frame */
+ control->sframe = 1;
+ control->poll = (ext & L2CAP_EXT_CTRL_POLL) >> L2CAP_EXT_CTRL_POLL_SHIFT;
+ control->super = (ext & L2CAP_EXT_CTRL_SUPERVISE) >> L2CAP_EXT_CTRL_SUPER_SHIFT;
+
+ control->sar = 0;
+ control->txseq = 0;
+ } else {
+ /* I-Frame */
+ control->sframe = 0;
+ control->sar = (ext & L2CAP_EXT_CTRL_SAR) >> L2CAP_EXT_CTRL_SAR_SHIFT;
+ control->txseq = (ext & L2CAP_EXT_CTRL_TXSEQ) >> L2CAP_EXT_CTRL_TXSEQ_SHIFT;
+
+ control->poll = 0;
+ control->super = 0;
+ }
+}
+
+static inline void __unpack_control(struct l2cap_chan *chan,
+ struct sk_buff *skb)
+{
+ if (test_bit(FLAG_EXT_CTRL, &chan->flags)) {
+ __unpack_extended_control(get_unaligned_le32(skb->data),
+ &bt_cb(skb)->control);
+ } else {
+ __unpack_enhanced_control(get_unaligned_le16(skb->data),
+ &bt_cb(skb)->control);
+ }
+}
+
+static u32 __pack_extended_control(struct l2cap_ctrl *control)
+{
+ u32 packed;
+
+ packed = control->reqseq << L2CAP_EXT_CTRL_REQSEQ_SHIFT;
+ packed |= control->final << L2CAP_EXT_CTRL_FINAL_SHIFT;
+
+ if (control->sframe) {
+ packed |= control->poll << L2CAP_EXT_CTRL_POLL_SHIFT;
+ packed |= control->super << L2CAP_EXT_CTRL_SUPER_SHIFT;
+ packed |= L2CAP_EXT_CTRL_FRAME_TYPE;
+ } else {
+ packed |= control->sar << L2CAP_EXT_CTRL_SAR_SHIFT;
+ packed |= control->txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT;
+ }
+
+ return packed;
+}
+
+static u16 __pack_enhanced_control(struct l2cap_ctrl *control)
+{
+ u16 packed;
+
+ packed = control->reqseq << L2CAP_CTRL_REQSEQ_SHIFT;
+ packed |= control->final << L2CAP_CTRL_FINAL_SHIFT;
+
+ if (control->sframe) {
+ packed |= control->poll << L2CAP_CTRL_POLL_SHIFT;
+ packed |= control->super << L2CAP_CTRL_SUPER_SHIFT;
+ packed |= L2CAP_CTRL_FRAME_TYPE;
+ } else {
+ packed |= control->sar << L2CAP_CTRL_SAR_SHIFT;
+ packed |= control->txseq << L2CAP_CTRL_TXSEQ_SHIFT;
+ }
+
+ return packed;
+}
+
+static inline void __pack_control(struct l2cap_chan *chan,
+ struct l2cap_ctrl *control,
+ struct sk_buff *skb)
+{
+ if (test_bit(FLAG_EXT_CTRL, &chan->flags)) {
+ put_unaligned_le32(__pack_extended_control(control),
+ skb->data + L2CAP_HDR_SIZE);
+ } else {
+ put_unaligned_le16(__pack_enhanced_control(control),
+ skb->data + L2CAP_HDR_SIZE);
+ }
+}
+
static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
{
struct sk_buff *skb;
@@ -681,10 +912,38 @@ static void l2cap_send_conn_req(struct l2cap_chan *chan)
l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req);
}
+static void l2cap_chan_ready(struct l2cap_chan *chan)
+{
+ struct sock *sk = chan->sk;
+ struct sock *parent;
+
+ lock_sock(sk);
+
+ parent = bt_sk(sk)->parent;
+
+ BT_DBG("sk %p, parent %p", sk, parent);
+
+ chan->conf_state = 0;
+ __clear_chan_timer(chan);
+
+ __l2cap_state_change(chan, BT_CONNECTED);
+ sk->sk_state_change(sk);
+
+ if (parent)
+ parent->sk_data_ready(parent, 0);
+
+ release_sock(sk);
+}
+
static void l2cap_do_start(struct l2cap_chan *chan)
{
struct l2cap_conn *conn = chan->conn;
+ if (conn->hcon->type == LE_LINK) {
+ l2cap_chan_ready(chan);
+ return;
+ }
+
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
return;
@@ -791,7 +1050,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
if (l2cap_chan_check_security(chan)) {
lock_sock(sk);
- if (bt_sk(sk)->defer_setup) {
+ if (test_bit(BT_SK_DEFER_SETUP,
+ &bt_sk(sk)->flags)) {
struct sock *parent = bt_sk(sk)->parent;
rsp.result = cpu_to_le16(L2CAP_CR_PEND);
rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
@@ -830,10 +1090,12 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
mutex_unlock(&conn->chan_lock);
}
-/* Find socket with cid and source bdaddr.
+/* Find socket with cid and source/destination bdaddr.
* Returns closest match, locked.
*/
-static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
+static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid,
+ bdaddr_t *src,
+ bdaddr_t *dst)
{
struct l2cap_chan *c, *c1 = NULL;
@@ -846,14 +1108,22 @@ static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdadd
continue;
if (c->scid == cid) {
+ int src_match, dst_match;
+ int src_any, dst_any;
+
/* Exact match. */
- if (!bacmp(&bt_sk(sk)->src, src)) {
+ src_match = !bacmp(&bt_sk(sk)->src, src);
+ dst_match = !bacmp(&bt_sk(sk)->dst, dst);
+ if (src_match && dst_match) {
read_unlock(&chan_list_lock);
return c;
}
/* Closest match */
- if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
+ src_any = !bacmp(&bt_sk(sk)->src, BDADDR_ANY);
+ dst_any = !bacmp(&bt_sk(sk)->dst, BDADDR_ANY);
+ if ((src_match && dst_any) || (src_any && dst_match) ||
+ (src_any && dst_any))
c1 = c;
}
}
@@ -872,7 +1142,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
/* Check if we have socket listening on cid */
pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
- conn->src);
+ conn->src, conn->dst);
if (!pchan)
return;
@@ -910,29 +1180,6 @@ clean:
release_sock(parent);
}
-static void l2cap_chan_ready(struct l2cap_chan *chan)
-{
- struct sock *sk = chan->sk;
- struct sock *parent;
-
- lock_sock(sk);
-
- parent = bt_sk(sk)->parent;
-
- BT_DBG("sk %p, parent %p", sk, parent);
-
- chan->conf_state = 0;
- __clear_chan_timer(chan);
-
- __l2cap_state_change(chan, BT_CONNECTED);
- sk->sk_state_change(sk);
-
- if (parent)
- parent->sk_data_ready(parent, 0);
-
- release_sock(sk);
-}
-
static void l2cap_conn_ready(struct l2cap_conn *conn)
{
struct l2cap_chan *chan;
@@ -1016,6 +1263,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
/* Kill channels */
list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
+ l2cap_chan_hold(chan);
l2cap_chan_lock(chan);
l2cap_chan_del(chan, err);
@@ -1023,6 +1271,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
l2cap_chan_unlock(chan);
chan->ops->close(chan->data);
+ l2cap_chan_put(chan);
}
mutex_unlock(&conn->chan_lock);
@@ -1100,10 +1349,12 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
/* ---- Socket interface ---- */
-/* Find socket with psm and source bdaddr.
+/* Find socket with psm and source / destination bdaddr.
* Returns closest match.
*/
-static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
+static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm,
+ bdaddr_t *src,
+ bdaddr_t *dst)
{
struct l2cap_chan *c, *c1 = NULL;
@@ -1116,14 +1367,22 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr
continue;
if (c->psm == psm) {
+ int src_match, dst_match;
+ int src_any, dst_any;
+
/* Exact match. */
- if (!bacmp(&bt_sk(sk)->src, src)) {
+ src_match = !bacmp(&bt_sk(sk)->src, src);
+ dst_match = !bacmp(&bt_sk(sk)->dst, dst);
+ if (src_match && dst_match) {
read_unlock(&chan_list_lock);
return c;
}
/* Closest match */
- if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
+ src_any = !bacmp(&bt_sk(sk)->src, BDADDR_ANY);
+ dst_any = !bacmp(&bt_sk(sk)->dst, BDADDR_ANY);
+ if ((src_match && dst_any) || (src_any && dst_match) ||
+ (src_any && dst_any))
c1 = c;
}
}
@@ -1133,7 +1392,8 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr
return c1;
}
-int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst)
+int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
+ bdaddr_t *dst, u8 dst_type)
{
struct sock *sk = chan->sk;
bdaddr_t *src = &bt_sk(sk)->src;
@@ -1143,8 +1403,8 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d
__u8 auth_type;
int err;
- BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
- chan->psm);
+ BT_DBG("%s -> %s (type %u) psm 0x%2.2x", batostr(src), batostr(dst),
+ dst_type, __le16_to_cpu(chan->psm));
hdev = hci_get_route(dst, src);
if (!hdev)
@@ -1218,11 +1478,11 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d
auth_type = l2cap_get_auth_type(chan);
if (chan->dcid == L2CAP_CID_LE_DATA)
- hcon = hci_connect(hdev, LE_LINK, dst,
- chan->sec_level, auth_type);
+ hcon = hci_connect(hdev, LE_LINK, dst, dst_type,
+ chan->sec_level, auth_type);
else
- hcon = hci_connect(hdev, ACL_LINK, dst,
- chan->sec_level, auth_type);
+ hcon = hci_connect(hdev, ACL_LINK, dst, dst_type,
+ chan->sec_level, auth_type);
if (IS_ERR(hcon)) {
err = PTR_ERR(hcon);
@@ -1236,6 +1496,18 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d
goto done;
}
+ if (hcon->type == LE_LINK) {
+ err = 0;
+
+ if (!list_empty(&conn->chan_l)) {
+ err = -EBUSY;
+ hci_conn_put(hcon);
+ }
+
+ if (err)
+ goto done;
+ }
+
/* Update source addr of the socket */
bacpy(src, conn->src);
@@ -1346,7 +1618,7 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
while ((skb = skb_peek(&chan->tx_q)) &&
chan->unacked_frames) {
- if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
+ if (bt_cb(skb)->control.txseq == chan->expected_ack_seq)
break;
skb = skb_dequeue(&chan->tx_q);
@@ -1368,6 +1640,7 @@ static void l2cap_streaming_send(struct l2cap_chan *chan)
while ((skb = skb_dequeue(&chan->tx_q))) {
control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
control |= __set_txseq(chan, chan->next_tx_seq);
+ control |= __set_ctrl_sar(chan, bt_cb(skb)->control.sar);
__put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
if (chan->fcs == L2CAP_FCS_CRC16) {
@@ -1393,21 +1666,21 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
if (!skb)
return;
- while (bt_cb(skb)->tx_seq != tx_seq) {
+ while (bt_cb(skb)->control.txseq != tx_seq) {
if (skb_queue_is_last(&chan->tx_q, skb))
return;
skb = skb_queue_next(&chan->tx_q, skb);
}
- if (chan->remote_max_tx &&
- bt_cb(skb)->retries == chan->remote_max_tx) {
+ if (bt_cb(skb)->control.retries == chan->remote_max_tx &&
+ chan->remote_max_tx) {
l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
return;
}
tx_skb = skb_clone(skb, GFP_ATOMIC);
- bt_cb(skb)->retries++;
+ bt_cb(skb)->control.retries++;
control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
control &= __get_sar_mask(chan);
@@ -1440,17 +1713,20 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
if (chan->state != BT_CONNECTED)
return -ENOTCONN;
+ if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
+ return 0;
+
while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
- if (chan->remote_max_tx &&
- bt_cb(skb)->retries == chan->remote_max_tx) {
+ if (bt_cb(skb)->control.retries == chan->remote_max_tx &&
+ chan->remote_max_tx) {
l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
break;
}
tx_skb = skb_clone(skb, GFP_ATOMIC);
- bt_cb(skb)->retries++;
+ bt_cb(skb)->control.retries++;
control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
control &= __get_sar_mask(chan);
@@ -1460,6 +1736,7 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
control |= __set_reqseq(chan, chan->buffer_seq);
control |= __set_txseq(chan, chan->next_tx_seq);
+ control |= __set_ctrl_sar(chan, bt_cb(skb)->control.sar);
__put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
@@ -1474,11 +1751,11 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
__set_retrans_timer(chan);
- bt_cb(skb)->tx_seq = chan->next_tx_seq;
+ bt_cb(skb)->control.txseq = chan->next_tx_seq;
chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
- if (bt_cb(skb)->retries == 1) {
+ if (bt_cb(skb)->control.retries == 1) {
chan->unacked_frames++;
if (!nsent++)
@@ -1554,7 +1831,7 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
{
struct l2cap_conn *conn = chan->conn;
struct sk_buff **frag;
- int err, sent = 0;
+ int sent = 0;
if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
return -EFAULT;
@@ -1565,14 +1842,17 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
/* Continuation fragments (no L2CAP header) */
frag = &skb_shinfo(skb)->frag_list;
while (len) {
+ struct sk_buff *tmp;
+
count = min_t(unsigned int, conn->mtu, len);
- *frag = chan->ops->alloc_skb(chan, count,
- msg->msg_flags & MSG_DONTWAIT,
- &err);
+ tmp = chan->ops->alloc_skb(chan, count,
+ msg->msg_flags & MSG_DONTWAIT);
+ if (IS_ERR(tmp))
+ return PTR_ERR(tmp);
+
+ *frag = tmp;
- if (!*frag)
- return err;
if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
return -EFAULT;
@@ -1581,6 +1861,9 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan,
sent += count;
len -= count;
+ skb->len += (*frag)->len;
+ skb->data_len += (*frag)->len;
+
frag = &(*frag)->next;
}
@@ -1601,18 +1884,17 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
count = min_t(unsigned int, (conn->mtu - hlen), len);
skb = chan->ops->alloc_skb(chan, count + hlen,
- msg->msg_flags & MSG_DONTWAIT, &err);
-
- if (!skb)
- return ERR_PTR(err);
+ msg->msg_flags & MSG_DONTWAIT);
+ if (IS_ERR(skb))
+ return skb;
skb->priority = priority;
/* Create L2CAP header */
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
lh->cid = cpu_to_le16(chan->dcid);
- lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
- put_unaligned_le16(chan->psm, skb_put(skb, 2));
+ lh->len = cpu_to_le16(len + L2CAP_PSMLEN_SIZE);
+ put_unaligned(chan->psm, skb_put(skb, L2CAP_PSMLEN_SIZE));
err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
if (unlikely(err < 0)) {
@@ -1628,25 +1910,24 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
{
struct l2cap_conn *conn = chan->conn;
struct sk_buff *skb;
- int err, count, hlen = L2CAP_HDR_SIZE;
+ int err, count;
struct l2cap_hdr *lh;
BT_DBG("chan %p len %d", chan, (int)len);
- count = min_t(unsigned int, (conn->mtu - hlen), len);
+ count = min_t(unsigned int, (conn->mtu - L2CAP_HDR_SIZE), len);
- skb = chan->ops->alloc_skb(chan, count + hlen,
- msg->msg_flags & MSG_DONTWAIT, &err);
-
- if (!skb)
- return ERR_PTR(err);
+ skb = chan->ops->alloc_skb(chan, count + L2CAP_HDR_SIZE,
+ msg->msg_flags & MSG_DONTWAIT);
+ if (IS_ERR(skb))
+ return skb;
skb->priority = priority;
/* Create L2CAP header */
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
lh->cid = cpu_to_le16(chan->dcid);
- lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
+ lh->len = cpu_to_le16(len);
err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
if (unlikely(err < 0)) {
@@ -1658,7 +1939,7 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
struct msghdr *msg, size_t len,
- u32 control, u16 sdulen)
+ u16 sdulen)
{
struct l2cap_conn *conn = chan->conn;
struct sk_buff *skb;
@@ -1684,17 +1965,16 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
count = min_t(unsigned int, (conn->mtu - hlen), len);
skb = chan->ops->alloc_skb(chan, count + hlen,
- msg->msg_flags & MSG_DONTWAIT, &err);
-
- if (!skb)
- return ERR_PTR(err);
+ msg->msg_flags & MSG_DONTWAIT);
+ if (IS_ERR(skb))
+ return skb;
/* Create L2CAP header */
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
lh->cid = cpu_to_le16(chan->dcid);
lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
- __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
+ __put_control(chan, 0, skb_put(skb, __ctrl_size(chan)));
if (sdulen)
put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
@@ -1708,61 +1988,82 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
if (chan->fcs == L2CAP_FCS_CRC16)
put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
- bt_cb(skb)->retries = 0;
+ bt_cb(skb)->control.retries = 0;
return skb;
}
-static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
+static int l2cap_segment_sdu(struct l2cap_chan *chan,
+ struct sk_buff_head *seg_queue,
+ struct msghdr *msg, size_t len)
{
struct sk_buff *skb;
- struct sk_buff_head sar_queue;
- u32 control;
- size_t size = 0;
+ u16 sdu_len;
+ size_t pdu_len;
+ int err = 0;
+ u8 sar;
- skb_queue_head_init(&sar_queue);
- control = __set_ctrl_sar(chan, L2CAP_SAR_START);
- skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
+ BT_DBG("chan %p, msg %p, len %d", chan, msg, (int)len);
- __skb_queue_tail(&sar_queue, skb);
- len -= chan->remote_mps;
- size += chan->remote_mps;
+ /* It is critical that ERTM PDUs fit in a single HCI fragment,
+ * so fragmented skbs are not used. The HCI layer's handling
+ * of fragmented skbs is not compatible with ERTM's queueing.
+ */
- while (len > 0) {
- size_t buflen;
+ /* PDU size is derived from the HCI MTU */
+ pdu_len = chan->conn->mtu;
- if (len > chan->remote_mps) {
- control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
- buflen = chan->remote_mps;
- } else {
- control = __set_ctrl_sar(chan, L2CAP_SAR_END);
- buflen = len;
- }
+ pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD);
+
+ /* Adjust for largest possible L2CAP overhead. */
+ pdu_len -= L2CAP_EXT_HDR_SIZE + L2CAP_FCS_SIZE;
+
+ /* Remote device may have requested smaller PDUs */
+ pdu_len = min_t(size_t, pdu_len, chan->remote_mps);
+
+ if (len <= pdu_len) {
+ sar = L2CAP_SAR_UNSEGMENTED;
+ sdu_len = 0;
+ pdu_len = len;
+ } else {
+ sar = L2CAP_SAR_START;
+ sdu_len = len;
+ pdu_len -= L2CAP_SDULEN_SIZE;
+ }
+
+ while (len > 0) {
+ skb = l2cap_create_iframe_pdu(chan, msg, pdu_len, sdu_len);
- skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
if (IS_ERR(skb)) {
- skb_queue_purge(&sar_queue);
+ __skb_queue_purge(seg_queue);
return PTR_ERR(skb);
}
- __skb_queue_tail(&sar_queue, skb);
- len -= buflen;
- size += buflen;
+ bt_cb(skb)->control.sar = sar;
+ __skb_queue_tail(seg_queue, skb);
+
+ len -= pdu_len;
+ if (sdu_len) {
+ sdu_len = 0;
+ pdu_len += L2CAP_SDULEN_SIZE;
+ }
+
+ if (len <= pdu_len) {
+ sar = L2CAP_SAR_END;
+ pdu_len = len;
+ } else {
+ sar = L2CAP_SAR_CONTINUE;
+ }
}
- skb_queue_splice_tail(&sar_queue, &chan->tx_q);
- if (chan->tx_send_head == NULL)
- chan->tx_send_head = sar_queue.next;
- return size;
+ return err;
}
int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
u32 priority)
{
struct sk_buff *skb;
- u32 control;
int err;
+ struct sk_buff_head seg_queue;
/* Connectionless channel */
if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
@@ -1791,42 +2092,47 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
case L2CAP_MODE_ERTM:
case L2CAP_MODE_STREAMING:
- /* Entire SDU fits into one PDU */
- if (len <= chan->remote_mps) {
- control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
- skb = l2cap_create_iframe_pdu(chan, msg, len, control,
- 0);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
+ /* Check outgoing MTU */
+ if (len > chan->omtu) {
+ err = -EMSGSIZE;
+ break;
+ }
- __skb_queue_tail(&chan->tx_q, skb);
+ __skb_queue_head_init(&seg_queue);
- if (chan->tx_send_head == NULL)
- chan->tx_send_head = skb;
+ /* Do segmentation before calling in to the state machine,
+ * since it's possible to block while waiting for memory
+ * allocation.
+ */
+ err = l2cap_segment_sdu(chan, &seg_queue, msg, len);
- } else {
- /* Segment SDU into multiples PDUs */
- err = l2cap_sar_segment_sdu(chan, msg, len);
- if (err < 0)
- return err;
+ /* The channel could have been closed while segmenting,
+ * check that it is still connected.
+ */
+ if (chan->state != BT_CONNECTED) {
+ __skb_queue_purge(&seg_queue);
+ err = -ENOTCONN;
}
- if (chan->mode == L2CAP_MODE_STREAMING) {
- l2cap_streaming_send(chan);
- err = len;
+ if (err)
break;
- }
- if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
- test_bit(CONN_WAIT_F, &chan->conn_state)) {
- err = len;
- break;
- }
+ if (chan->mode == L2CAP_MODE_ERTM && chan->tx_send_head == NULL)
+ chan->tx_send_head = seg_queue.next;
+ skb_queue_splice_tail_init(&seg_queue, &chan->tx_q);
+
+ if (chan->mode == L2CAP_MODE_ERTM)
+ err = l2cap_ertm_send(chan);
+ else
+ l2cap_streaming_send(chan);
- err = l2cap_ertm_send(chan);
if (err >= 0)
err = len;
+ /* If the skbs were not queued for sending, they'll still be in
+ * seg_queue and need to be purged.
+ */
+ __skb_queue_purge(&seg_queue);
break;
default:
@@ -2040,13 +2346,29 @@ static void l2cap_ack_timeout(struct work_struct *work)
l2cap_chan_put(chan);
}
-static inline void l2cap_ertm_init(struct l2cap_chan *chan)
+static inline int l2cap_ertm_init(struct l2cap_chan *chan)
{
+ int err;
+
+ chan->next_tx_seq = 0;
+ chan->expected_tx_seq = 0;
chan->expected_ack_seq = 0;
chan->unacked_frames = 0;
chan->buffer_seq = 0;
chan->num_acked = 0;
chan->frames_sent = 0;
+ chan->last_acked_seq = 0;
+ chan->sdu = NULL;
+ chan->sdu_last_frag = NULL;
+ chan->sdu_len = 0;
+
+ skb_queue_head_init(&chan->tx_q);
+
+ if (chan->mode != L2CAP_MODE_ERTM)
+ return 0;
+
+ chan->rx_state = L2CAP_RX_STATE_RECV;
+ chan->tx_state = L2CAP_TX_STATE_XMIT;
INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout);
INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout);
@@ -2055,6 +2377,11 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan)
skb_queue_head_init(&chan->srej_q);
INIT_LIST_HEAD(&chan->srej_l);
+ err = l2cap_seq_list_init(&chan->srej_list, chan->tx_win);
+ if (err < 0)
+ return err;
+
+ return l2cap_seq_list_init(&chan->retrans_list, chan->remote_tx_win);
}
static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
@@ -2378,9 +2705,9 @@ done:
chan->remote_mps = size;
rfc.retrans_timeout =
- le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
+ __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
rfc.monitor_timeout =
- le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
+ __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
set_bit(CONF_MODE_DONE, &chan->conf_state);
@@ -2644,10 +2971,10 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
u16 dcid = 0, scid = __le16_to_cpu(req->scid);
__le16 psm = req->psm;
- BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
+ BT_DBG("psm 0x%2.2x scid 0x%4.4x", __le16_to_cpu(psm), scid);
/* Check if we have socket listening on psm */
- pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
+ pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src, conn->dst);
if (!pchan) {
result = L2CAP_CR_BAD_PSM;
goto sendresp;
@@ -2706,7 +3033,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
if (l2cap_chan_check_security(chan)) {
- if (bt_sk(sk)->defer_setup) {
+ if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) {
__l2cap_state_change(chan, BT_CONNECT2);
result = L2CAP_CR_PEND;
status = L2CAP_CS_AUTHOR_PEND;
@@ -2848,7 +3175,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
u16 dcid, flags;
u8 rsp[64];
struct l2cap_chan *chan;
- int len;
+ int len, err = 0;
dcid = __le16_to_cpu(req->dcid);
flags = __le16_to_cpu(req->flags);
@@ -2859,8 +3186,6 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
if (!chan)
return -ENOENT;
- l2cap_chan_lock(chan);
-
if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
struct l2cap_cmd_rej_cid rej;
@@ -2915,13 +3240,15 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
l2cap_state_change(chan, BT_CONNECTED);
- chan->next_tx_seq = 0;
- chan->expected_tx_seq = 0;
- skb_queue_head_init(&chan->tx_q);
- if (chan->mode == L2CAP_MODE_ERTM)
- l2cap_ertm_init(chan);
+ if (chan->mode == L2CAP_MODE_ERTM ||
+ chan->mode == L2CAP_MODE_STREAMING)
+ err = l2cap_ertm_init(chan);
+
+ if (err < 0)
+ l2cap_send_disconn_req(chan->conn, chan, -err);
+ else
+ l2cap_chan_ready(chan);
- l2cap_chan_ready(chan);
goto unlock;
}
@@ -2949,7 +3276,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
unlock:
l2cap_chan_unlock(chan);
- return 0;
+ return err;
}
static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
@@ -2957,21 +3284,20 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
u16 scid, flags, result;
struct l2cap_chan *chan;
- int len = cmd->len - sizeof(*rsp);
+ int len = le16_to_cpu(cmd->len) - sizeof(*rsp);
+ int err = 0;
scid = __le16_to_cpu(rsp->scid);
flags = __le16_to_cpu(rsp->flags);
result = __le16_to_cpu(rsp->result);
- BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
- scid, flags, result);
+ BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x len %d", scid, flags,
+ result, len);
chan = l2cap_get_chan_by_scid(conn, scid);
if (!chan)
return 0;
- l2cap_chan_lock(chan);
-
switch (result) {
case L2CAP_CONF_SUCCESS:
l2cap_conf_rfc_get(chan, rsp->data, len);
@@ -3045,18 +3371,19 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
set_default_fcs(chan);
l2cap_state_change(chan, BT_CONNECTED);
- chan->next_tx_seq = 0;
- chan->expected_tx_seq = 0;
- skb_queue_head_init(&chan->tx_q);
- if (chan->mode == L2CAP_MODE_ERTM)
- l2cap_ertm_init(chan);
+ if (chan->mode == L2CAP_MODE_ERTM ||
+ chan->mode == L2CAP_MODE_STREAMING)
+ err = l2cap_ertm_init(chan);
- l2cap_chan_ready(chan);
+ if (err < 0)
+ l2cap_send_disconn_req(chan->conn, chan, -err);
+ else
+ l2cap_chan_ready(chan);
}
done:
l2cap_chan_unlock(chan);
- return 0;
+ return err;
}
static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
@@ -3092,11 +3419,13 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
sk->sk_shutdown = SHUTDOWN_MASK;
release_sock(sk);
+ l2cap_chan_hold(chan);
l2cap_chan_del(chan, ECONNRESET);
l2cap_chan_unlock(chan);
chan->ops->close(chan->data);
+ l2cap_chan_put(chan);
mutex_unlock(&conn->chan_lock);
@@ -3124,11 +3453,13 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
l2cap_chan_lock(chan);
+ l2cap_chan_hold(chan);
l2cap_chan_del(chan, 0);
l2cap_chan_unlock(chan);
chan->ops->close(chan->data);
+ l2cap_chan_put(chan);
mutex_unlock(&conn->chan_lock);
@@ -3265,8 +3596,8 @@ static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
/* Placeholder: Always reject */
rsp.dcid = 0;
rsp.scid = cpu_to_le16(scid);
- rsp.result = L2CAP_CR_NO_MEM;
- rsp.status = L2CAP_CS_NO_INFO;
+ rsp.result = __constant_cpu_to_le16(L2CAP_CR_NO_MEM);
+ rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
sizeof(rsp), &rsp);
@@ -3665,19 +3996,19 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb,
struct sk_buff *next_skb;
int tx_seq_offset, next_tx_seq_offset;
- bt_cb(skb)->tx_seq = tx_seq;
- bt_cb(skb)->sar = sar;
+ bt_cb(skb)->control.txseq = tx_seq;
+ bt_cb(skb)->control.sar = sar;
next_skb = skb_peek(&chan->srej_q);
tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
while (next_skb) {
- if (bt_cb(next_skb)->tx_seq == tx_seq)
+ if (bt_cb(next_skb)->control.txseq == tx_seq)
return -EINVAL;
next_tx_seq_offset = __seq_offset(chan,
- bt_cb(next_skb)->tx_seq, chan->buffer_seq);
+ bt_cb(next_skb)->control.txseq, chan->buffer_seq);
if (next_tx_seq_offset > tx_seq_offset) {
__skb_queue_before(&chan->srej_q, next_skb, skb);
@@ -3800,6 +4131,7 @@ static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
BT_DBG("chan %p, Enter local busy", chan);
set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
+ l2cap_seq_list_clear(&chan->srej_list);
__set_ack_timer(chan);
}
@@ -3848,11 +4180,11 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
!test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
int err;
- if (bt_cb(skb)->tx_seq != tx_seq)
+ if (bt_cb(skb)->control.txseq != tx_seq)
break;
skb = skb_dequeue(&chan->srej_q);
- control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
+ control = __set_ctrl_sar(chan, bt_cb(skb)->control.sar);
err = l2cap_reassemble_sdu(chan, skb, control);
if (err < 0) {
@@ -3892,6 +4224,7 @@ static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
while (tx_seq != chan->expected_tx_seq) {
control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
control |= __set_reqseq(chan, chan->expected_tx_seq);
+ l2cap_seq_list_append(&chan->srej_list, chan->expected_tx_seq);
l2cap_send_sframe(chan, control);
new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
@@ -4022,8 +4355,8 @@ expected:
chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
- bt_cb(skb)->tx_seq = tx_seq;
- bt_cb(skb)->sar = sar;
+ bt_cb(skb)->control.txseq = tx_seq;
+ bt_cb(skb)->control.sar = sar;
__skb_queue_tail(&chan->srej_q, skb);
return 0;
}
@@ -4220,6 +4553,8 @@ static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
u16 req_seq;
int len, next_tx_seq_offset, req_seq_offset;
+ __unpack_control(chan, skb);
+
control = __get_control(chan, skb->data);
skb_pull(skb, __ctrl_size(chan));
len = skb->len;
@@ -4295,8 +4630,6 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
return 0;
}
- l2cap_chan_lock(chan);
-
BT_DBG("chan %p, len %d", chan, skb->len);
if (chan->state != BT_CONNECTED)
@@ -4375,7 +4708,7 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str
{
struct l2cap_chan *chan;
- chan = l2cap_global_chan_by_psm(0, psm, conn->src);
+ chan = l2cap_global_chan_by_psm(0, psm, conn->src, conn->dst);
if (!chan)
goto drop;
@@ -4396,11 +4729,12 @@ drop:
return 0;
}
-static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
+static inline int l2cap_att_channel(struct l2cap_conn *conn, u16 cid,
+ struct sk_buff *skb)
{
struct l2cap_chan *chan;
- chan = l2cap_global_chan_by_scid(0, cid, conn->src);
+ chan = l2cap_global_chan_by_scid(0, cid, conn->src, conn->dst);
if (!chan)
goto drop;
@@ -4445,7 +4779,7 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
break;
case L2CAP_CID_CONN_LESS:
- psm = get_unaligned_le16(skb->data);
+ psm = get_unaligned((__le16 *) skb->data);
skb_pull(skb, 2);
l2cap_conless_channel(conn, psm, skb);
break;
@@ -4540,7 +4874,6 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
if (encrypt == 0x00) {
if (chan->sec_level == BT_SECURITY_MEDIUM) {
- __clear_chan_timer(chan);
__set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
} else if (chan->sec_level == BT_SECURITY_HIGH)
l2cap_chan_close(chan, ECONNREFUSED);
@@ -4561,7 +4894,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
BT_DBG("conn %p", conn);
if (hcon->type == LE_LINK) {
- smp_distribute_keys(conn, 0);
+ if (!status && encrypt)
+ smp_distribute_keys(conn, 0);
cancel_delayed_work(&conn->security_timer);
}
@@ -4591,7 +4925,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
chan->state == BT_CONFIG)) {
struct sock *sk = chan->sk;
- bt_sk(sk)->suspended = false;
+ clear_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
sk->sk_state_change(sk);
l2cap_check_encryption(chan, encrypt);
@@ -4603,7 +4937,6 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
if (!status) {
l2cap_send_conn_req(chan);
} else {
- __clear_chan_timer(chan);
__set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
}
} else if (chan->state == BT_CONNECT2) {
@@ -4614,7 +4947,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
lock_sock(sk);
if (!status) {
- if (bt_sk(sk)->defer_setup) {
+ if (test_bit(BT_SK_DEFER_SETUP,
+ &bt_sk(sk)->flags)) {
struct sock *parent = bt_sk(sk)->parent;
res = L2CAP_CR_PEND;
stat = L2CAP_CS_AUTHOR_PEND;
@@ -4664,8 +4998,6 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
if (!(flags & ACL_CONT)) {
struct l2cap_hdr *hdr;
- struct l2cap_chan *chan;
- u16 cid;
int len;
if (conn->rx_len) {
@@ -4685,7 +5017,6 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
hdr = (struct l2cap_hdr *) skb->data;
len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
- cid = __le16_to_cpu(hdr->cid);
if (len == skb->len) {
/* Complete frame received */
@@ -4702,23 +5033,6 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
goto drop;
}
- chan = l2cap_get_chan_by_scid(conn, cid);
-
- if (chan && chan->sk) {
- struct sock *sk = chan->sk;
- lock_sock(sk);
-
- if (chan->imtu < len - L2CAP_HDR_SIZE) {
- BT_ERR("Frame exceeding recv MTU (len %d, "
- "MTU %d)", len,
- chan->imtu);
- release_sock(sk);
- l2cap_conn_unreliable(conn, ECOMM);
- goto drop;
- }
- release_sock(sk);
- }
-
/* Allocate skb for the complete frame (with header) */
conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
if (!conn->rx_skb)
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 04e7c172d49c..3bb1611b9d48 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -124,7 +124,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
return -EINVAL;
err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid),
- &la.l2_bdaddr);
+ &la.l2_bdaddr, la.l2_bdaddr_type);
if (err)
return err;
@@ -148,12 +148,16 @@ static int l2cap_sock_listen(struct socket *sock, int backlog)
lock_sock(sk);
- if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM)
- || sk->sk_state != BT_BOUND) {
+ if (sk->sk_state != BT_BOUND) {
err = -EBADFD;
goto done;
}
+ if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM) {
+ err = -EINVAL;
+ goto done;
+ }
+
switch (chan->mode) {
case L2CAP_MODE_BASIC:
break;
@@ -320,8 +324,8 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
case L2CAP_CONNINFO:
if (sk->sk_state != BT_CONNECTED &&
- !(sk->sk_state == BT_CONNECT2 &&
- bt_sk(sk)->defer_setup)) {
+ !(sk->sk_state == BT_CONNECT2 &&
+ test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))) {
err = -ENOTCONN;
break;
}
@@ -375,7 +379,10 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
}
memset(&sec, 0, sizeof(sec));
- sec.level = chan->sec_level;
+ if (chan->conn)
+ sec.level = chan->conn->hcon->sec_level;
+ else
+ sec.level = chan->sec_level;
if (sk->sk_state == BT_CONNECTED)
sec.key_size = chan->conn->hcon->enc_key_size;
@@ -392,7 +399,8 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
break;
}
- if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval))
+ if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags),
+ (u32 __user *) optval))
err = -EFAULT;
break;
@@ -594,10 +602,10 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
/* or for ACL link */
} else if ((sk->sk_state == BT_CONNECT2 &&
- bt_sk(sk)->defer_setup) ||
+ test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) ||
sk->sk_state == BT_CONNECTED) {
if (!l2cap_chan_check_security(chan))
- bt_sk(sk)->suspended = true;
+ set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
else
sk->sk_state_change(sk);
} else {
@@ -616,7 +624,10 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
break;
}
- bt_sk(sk)->defer_setup = opt;
+ if (opt)
+ set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
+ else
+ clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
break;
case BT_FLUSHABLE:
@@ -716,16 +727,13 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
if (msg->msg_flags & MSG_OOB)
return -EOPNOTSUPP;
- lock_sock(sk);
-
- if (sk->sk_state != BT_CONNECTED) {
- release_sock(sk);
+ if (sk->sk_state != BT_CONNECTED)
return -ENOTCONN;
- }
+ l2cap_chan_lock(chan);
err = l2cap_chan_send(chan, msg, len, sk->sk_priority);
+ l2cap_chan_unlock(chan);
- release_sock(sk);
return err;
}
@@ -737,7 +745,8 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms
lock_sock(sk);
- if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) {
+ if (sk->sk_state == BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP,
+ &bt_sk(sk)->flags)) {
sk->sk_state = BT_CONFIG;
pi->chan->state = BT_CONFIG;
@@ -931,12 +940,19 @@ static void l2cap_sock_state_change_cb(void *data, int state)
}
static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan,
- unsigned long len, int nb,
- int *err)
+ unsigned long len, int nb)
{
- struct sock *sk = chan->sk;
+ struct sk_buff *skb;
+ int err;
+
+ l2cap_chan_unlock(chan);
+ skb = bt_skb_send_alloc(chan->sk, len, nb, &err);
+ l2cap_chan_lock(chan);
+
+ if (!skb)
+ return ERR_PTR(err);
- return bt_skb_send_alloc(sk, len, nb, err);
+ return skb;
}
static struct l2cap_ops l2cap_chan_ops = {
@@ -952,6 +968,7 @@ static void l2cap_sock_destruct(struct sock *sk)
{
BT_DBG("sk %p", sk);
+ l2cap_chan_put(l2cap_pi(sk)->chan);
if (l2cap_pi(sk)->rx_busy_skb) {
kfree_skb(l2cap_pi(sk)->rx_busy_skb);
l2cap_pi(sk)->rx_busy_skb = NULL;
@@ -972,7 +989,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
struct l2cap_chan *pchan = l2cap_pi(parent)->chan;
sk->sk_type = parent->sk_type;
- bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup;
+ bt_sk(sk)->flags = bt_sk(parent)->flags;
chan->chan_type = pchan->chan_type;
chan->imtu = pchan->imtu;
@@ -1010,13 +1027,8 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
} else {
chan->mode = L2CAP_MODE_BASIC;
}
- chan->max_tx = L2CAP_DEFAULT_MAX_TX;
- chan->fcs = L2CAP_FCS_CRC16;
- chan->tx_win = L2CAP_DEFAULT_TX_WINDOW;
- chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
- chan->sec_level = BT_SECURITY_LOW;
- chan->flags = 0;
- set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
+
+ l2cap_chan_set_defaults(chan);
}
/* Default config options */
@@ -1052,12 +1064,16 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p
sk->sk_protocol = proto;
sk->sk_state = BT_OPEN;
- chan = l2cap_chan_create(sk);
+ chan = l2cap_chan_create();
if (!chan) {
l2cap_sock_kill(sk);
return NULL;
}
+ l2cap_chan_hold(chan);
+
+ chan->sk = sk;
+
l2cap_pi(sk)->chan = chan;
return sk;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 4bb03b111122..25d220776079 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -35,10 +35,9 @@
#include <net/bluetooth/smp.h>
bool enable_hs;
-bool enable_le;
#define MGMT_VERSION 1
-#define MGMT_REVISION 0
+#define MGMT_REVISION 1
static const u16 mgmt_commands[] = {
MGMT_OP_READ_INDEX_LIST,
@@ -78,6 +77,7 @@ static const u16 mgmt_commands[] = {
MGMT_OP_CONFIRM_NAME,
MGMT_OP_BLOCK_DEVICE,
MGMT_OP_UNBLOCK_DEVICE,
+ MGMT_OP_SET_DEVICE_ID,
};
static const u16 mgmt_events[] = {
@@ -224,7 +224,7 @@ static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
ev = (void *) skb_put(skb, sizeof(*ev));
ev->status = status;
- put_unaligned_le16(cmd, &ev->opcode);
+ ev->opcode = cpu_to_le16(cmd);
err = sock_queue_rcv_skb(sk, skb);
if (err < 0)
@@ -254,7 +254,7 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
- put_unaligned_le16(cmd, &ev->opcode);
+ ev->opcode = cpu_to_le16(cmd);
ev->status = status;
if (rp)
@@ -275,7 +275,7 @@ static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
BT_DBG("sock %p", sk);
rp.version = MGMT_VERSION;
- put_unaligned_le16(MGMT_REVISION, &rp.revision);
+ rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
sizeof(rp));
@@ -285,9 +285,9 @@ static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
u16 data_len)
{
struct mgmt_rp_read_commands *rp;
- u16 num_commands = ARRAY_SIZE(mgmt_commands);
- u16 num_events = ARRAY_SIZE(mgmt_events);
- u16 *opcode;
+ const u16 num_commands = ARRAY_SIZE(mgmt_commands);
+ const u16 num_events = ARRAY_SIZE(mgmt_events);
+ __le16 *opcode;
size_t rp_size;
int i, err;
@@ -299,8 +299,8 @@ static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
if (!rp)
return -ENOMEM;
- put_unaligned_le16(num_commands, &rp->num_commands);
- put_unaligned_le16(num_events, &rp->num_events);
+ rp->num_commands = __constant_cpu_to_le16(num_commands);
+ rp->num_events = __constant_cpu_to_le16(num_events);
for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
put_unaligned_le16(mgmt_commands[i], opcode);
@@ -341,14 +341,14 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
return -ENOMEM;
}
- put_unaligned_le16(count, &rp->num_controllers);
+ rp->num_controllers = cpu_to_le16(count);
i = 0;
list_for_each_entry(d, &hci_dev_list, list) {
if (test_bit(HCI_SETUP, &d->dev_flags))
continue;
- put_unaligned_le16(d->id, &rp->index[i++]);
+ rp->index[i++] = cpu_to_le16(d->id);
BT_DBG("Added hci%u", d->id);
}
@@ -383,10 +383,8 @@ static u32 get_supported_settings(struct hci_dev *hdev)
if (enable_hs)
settings |= MGMT_SETTING_HS;
- if (enable_le) {
- if (hdev->features[4] & LMP_LE)
- settings |= MGMT_SETTING_LE;
- }
+ if (hdev->features[4] & LMP_LE)
+ settings |= MGMT_SETTING_LE;
return settings;
}
@@ -442,9 +440,7 @@ static u16 get_uuid16(u8 *uuid128)
return 0;
}
- memcpy(&val, &uuid128[12], 4);
-
- val = le32_to_cpu(val);
+ val = get_unaligned_le32(&uuid128[12]);
if (val > 0xffff)
return 0;
@@ -479,6 +475,28 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
ptr += (name_len + 2);
}
+ if (hdev->inq_tx_power) {
+ ptr[0] = 2;
+ ptr[1] = EIR_TX_POWER;
+ ptr[2] = (u8) hdev->inq_tx_power;
+
+ eir_len += 3;
+ ptr += 3;
+ }
+
+ if (hdev->devid_source > 0) {
+ ptr[0] = 9;
+ ptr[1] = EIR_DEVICE_ID;
+
+ put_unaligned_le16(hdev->devid_source, ptr + 2);
+ put_unaligned_le16(hdev->devid_vendor, ptr + 4);
+ put_unaligned_le16(hdev->devid_product, ptr + 6);
+ put_unaligned_le16(hdev->devid_version, ptr + 8);
+
+ eir_len += 10;
+ ptr += 10;
+ }
+
memset(uuid16_list, 0, sizeof(uuid16_list));
/* Group all UUID16 types */
@@ -642,8 +660,7 @@ static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
bacpy(&rp.bdaddr, &hdev->bdaddr);
rp.version = hdev->hci_ver;
-
- put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
+ rp.manufacturer = cpu_to_le16(hdev->manufacturer);
rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
rp.current_settings = cpu_to_le32(get_current_settings(hdev));
@@ -840,7 +857,7 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
BT_DBG("request for %s", hdev->name);
- timeout = get_unaligned_le16(&cp->timeout);
+ timeout = __le16_to_cpu(cp->timeout);
if (!cp->val && timeout > 0)
return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
MGMT_STATUS_INVALID_PARAMS);
@@ -1122,8 +1139,8 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
}
if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
- err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
- MGMT_STATUS_BUSY);
+ err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
+ MGMT_STATUS_BUSY);
goto failed;
}
@@ -1179,7 +1196,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
hci_dev_lock(hdev);
- if (!enable_le || !(hdev->features[4] & LMP_LE)) {
+ if (!(hdev->features[4] & LMP_LE)) {
err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
MGMT_STATUS_NOT_SUPPORTED);
goto unlock;
@@ -1227,10 +1244,8 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
&hci_cp);
- if (err < 0) {
+ if (err < 0)
mgmt_pending_remove(cmd);
- goto unlock;
- }
unlock:
hci_dev_unlock(hdev);
@@ -1280,10 +1295,8 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
}
cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
- if (!cmd) {
+ if (!cmd)
err = -ENOMEM;
- goto failed;
- }
failed:
hci_dev_unlock(hdev);
@@ -1368,10 +1381,8 @@ update_class:
}
cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
- if (!cmd) {
+ if (!cmd)
err = -ENOMEM;
- goto unlock;
- }
unlock:
hci_dev_unlock(hdev);
@@ -1422,10 +1433,8 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
}
cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
- if (!cmd) {
+ if (!cmd)
err = -ENOMEM;
- goto unlock;
- }
unlock:
hci_dev_unlock(hdev);
@@ -1439,7 +1448,7 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
u16 key_count, expected_len;
int i;
- key_count = get_unaligned_le16(&cp->key_count);
+ key_count = __le16_to_cpu(cp->key_count);
expected_len = sizeof(*cp) + key_count *
sizeof(struct mgmt_link_key_info);
@@ -1512,7 +1521,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
goto unlock;
}
- if (cp->addr.type == MGMT_ADDR_BREDR)
+ if (cp->addr.type == BDADDR_BREDR)
err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
else
err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
@@ -1524,7 +1533,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
}
if (cp->disconnect) {
- if (cp->addr.type == MGMT_ADDR_BREDR)
+ if (cp->addr.type == BDADDR_BREDR)
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
&cp->addr.bdaddr);
else
@@ -1548,7 +1557,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
goto unlock;
}
- put_unaligned_le16(conn->handle, &dc.handle);
+ dc.handle = cpu_to_le16(conn->handle);
dc.reason = 0x13; /* Remote User Terminated Connection */
err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
if (err < 0)
@@ -1584,7 +1593,7 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
goto failed;
}
- if (cp->addr.type == MGMT_ADDR_BREDR)
+ if (cp->addr.type == BDADDR_BREDR)
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
else
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
@@ -1601,7 +1610,7 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
goto failed;
}
- put_unaligned_le16(conn->handle, &dc.handle);
+ dc.handle = cpu_to_le16(conn->handle);
dc.reason = 0x13; /* Remote User Terminated Connection */
err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
@@ -1613,22 +1622,22 @@ failed:
return err;
}
-static u8 link_to_mgmt(u8 link_type, u8 addr_type)
+static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
{
switch (link_type) {
case LE_LINK:
switch (addr_type) {
case ADDR_LE_DEV_PUBLIC:
- return MGMT_ADDR_LE_PUBLIC;
- case ADDR_LE_DEV_RANDOM:
- return MGMT_ADDR_LE_RANDOM;
+ return BDADDR_LE_PUBLIC;
+
default:
- return MGMT_ADDR_INVALID;
+ /* Fallback to LE Random address type */
+ return BDADDR_LE_RANDOM;
}
- case ACL_LINK:
- return MGMT_ADDR_BREDR;
+
default:
- return MGMT_ADDR_INVALID;
+ /* Fallback to BR/EDR type */
+ return BDADDR_BREDR;
}
}
@@ -1669,13 +1678,13 @@ static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
continue;
bacpy(&rp->addr[i].bdaddr, &c->dst);
- rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
- if (rp->addr[i].type == MGMT_ADDR_INVALID)
+ rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
+ if (c->type == SCO_LINK || c->type == ESCO_LINK)
continue;
i++;
}
- put_unaligned_le16(i, &rp->conn_count);
+ rp->conn_count = cpu_to_le16(i);
/* Recalculate length in case of filtered SCO connections, etc */
rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
@@ -1836,7 +1845,7 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status)
struct hci_conn *conn = cmd->user_data;
bacpy(&rp.addr.bdaddr, &conn->dst);
- rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
+ rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
&rp, sizeof(rp));
@@ -1890,12 +1899,12 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
else
auth_type = HCI_AT_DEDICATED_BONDING_MITM;
- if (cp->addr.type == MGMT_ADDR_BREDR)
- conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
- auth_type);
+ if (cp->addr.type == BDADDR_BREDR)
+ conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
+ cp->addr.type, sec_level, auth_type);
else
- conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
- auth_type);
+ conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
+ cp->addr.type, sec_level, auth_type);
memset(&rp, 0, sizeof(rp));
bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
@@ -1923,7 +1932,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
}
/* For LE, just connecting isn't a proof that the pairing finished */
- if (cp->addr.type == MGMT_ADDR_BREDR)
+ if (cp->addr.type == BDADDR_BREDR)
conn->connect_cfm_cb = pairing_complete_cb;
conn->security_cfm_cb = pairing_complete_cb;
@@ -2000,7 +2009,7 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
goto done;
}
- if (type == MGMT_ADDR_BREDR)
+ if (type == BDADDR_BREDR)
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
else
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
@@ -2011,7 +2020,7 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
goto done;
}
- if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
+ if (type == BDADDR_LE_PUBLIC || type == BDADDR_LE_RANDOM) {
/* Continue with pairing via SMP */
err = smp_user_confirm_reply(conn, mgmt_op, passkey);
@@ -2295,6 +2304,12 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev,
goto failed;
}
+ if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
+ err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
+ MGMT_STATUS_BUSY);
+ goto failed;
+ }
+
if (hdev->discovery.state != DISCOVERY_STOPPED) {
err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
MGMT_STATUS_BUSY);
@@ -2381,27 +2396,39 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
goto unlock;
}
- if (hdev->discovery.state == DISCOVERY_FINDING) {
- err = hci_cancel_inquiry(hdev);
- if (err < 0)
- mgmt_pending_remove(cmd);
+ switch (hdev->discovery.state) {
+ case DISCOVERY_FINDING:
+ if (test_bit(HCI_INQUIRY, &hdev->flags))
+ err = hci_cancel_inquiry(hdev);
else
- hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
- goto unlock;
- }
+ err = hci_cancel_le_scan(hdev);
- e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
- if (!e) {
- mgmt_pending_remove(cmd);
- err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
- &mgmt_cp->type, sizeof(mgmt_cp->type));
- hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
- goto unlock;
+ break;
+
+ case DISCOVERY_RESOLVING:
+ e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
+ NAME_PENDING);
+ if (!e) {
+ mgmt_pending_remove(cmd);
+ err = cmd_complete(sk, hdev->id,
+ MGMT_OP_STOP_DISCOVERY, 0,
+ &mgmt_cp->type,
+ sizeof(mgmt_cp->type));
+ hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+ goto unlock;
+ }
+
+ bacpy(&cp.bdaddr, &e->data.bdaddr);
+ err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
+ sizeof(cp), &cp);
+
+ break;
+
+ default:
+ BT_DBG("unknown discovery state %u", hdev->discovery.state);
+ err = -EFAULT;
}
- bacpy(&cp.bdaddr, &e->data.bdaddr);
- err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
- &cp);
if (err < 0)
mgmt_pending_remove(cmd);
else
@@ -2501,6 +2528,37 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
return err;
}
+static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
+ u16 len)
+{
+ struct mgmt_cp_set_device_id *cp = data;
+ int err;
+ __u16 source;
+
+ BT_DBG("%s", hdev->name);
+
+ source = __le16_to_cpu(cp->source);
+
+ if (source > 0x0002)
+ return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
+ MGMT_STATUS_INVALID_PARAMS);
+
+ hci_dev_lock(hdev);
+
+ hdev->devid_source = source;
+ hdev->devid_vendor = __le16_to_cpu(cp->vendor);
+ hdev->devid_product = __le16_to_cpu(cp->product);
+ hdev->devid_version = __le16_to_cpu(cp->version);
+
+ err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
+
+ update_eir(hdev);
+
+ hci_dev_unlock(hdev);
+
+ return err;
+}
+
static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
void *data, u16 len)
{
@@ -2565,7 +2623,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
u16 key_count, expected_len;
int i;
- key_count = get_unaligned_le16(&cp->key_count);
+ key_count = __le16_to_cpu(cp->key_count);
expected_len = sizeof(*cp) + key_count *
sizeof(struct mgmt_ltk_info);
@@ -2591,7 +2649,8 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
else
type = HCI_SMP_LTK_SLAVE;
- hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
+ hci_add_ltk(hdev, &key->addr.bdaddr,
+ bdaddr_to_le(key->addr.type),
type, 0, key->authenticated, key->val,
key->enc_size, key->ediv, key->rand);
}
@@ -2601,7 +2660,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
return 0;
}
-struct mgmt_handler {
+static const struct mgmt_handler {
int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
u16 data_len);
bool var_len;
@@ -2647,6 +2706,7 @@ struct mgmt_handler {
{ confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
{ block_device, false, MGMT_BLOCK_DEVICE_SIZE },
{ unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
+ { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
};
@@ -2657,7 +2717,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
struct mgmt_hdr *hdr;
u16 opcode, index, len;
struct hci_dev *hdev = NULL;
- struct mgmt_handler *handler;
+ const struct mgmt_handler *handler;
int err;
BT_DBG("got %zu bytes", msglen);
@@ -2675,9 +2735,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
}
hdr = buf;
- opcode = get_unaligned_le16(&hdr->opcode);
- index = get_unaligned_le16(&hdr->index);
- len = get_unaligned_le16(&hdr->len);
+ opcode = __le16_to_cpu(hdr->opcode);
+ index = __le16_to_cpu(hdr->index);
+ len = __le16_to_cpu(hdr->len);
if (len != msglen - sizeof(*hdr)) {
err = -EINVAL;
@@ -2884,7 +2944,8 @@ int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
return 0;
}
-int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent)
+int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
+ bool persistent)
{
struct mgmt_ev_new_link_key ev;
@@ -2892,7 +2953,7 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persisten
ev.store_hint = persistent;
bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
- ev.key.addr.type = MGMT_ADDR_BREDR;
+ ev.key.addr.type = BDADDR_BREDR;
ev.key.type = key->type;
memcpy(ev.key.val, key->val, 16);
ev.key.pin_len = key->pin_len;
@@ -2908,7 +2969,7 @@ int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
ev.store_hint = persistent;
bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
- ev.key.addr.type = key->bdaddr_type;
+ ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
ev.key.authenticated = key->authenticated;
ev.key.enc_size = key->enc_size;
ev.key.ediv = key->ediv;
@@ -2932,7 +2993,7 @@ int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u16 eir_len = 0;
bacpy(&ev->addr.bdaddr, bdaddr);
- ev->addr.type = link_to_mgmt(link_type, addr_type);
+ ev->addr.type = link_to_bdaddr(link_type, addr_type);
ev->flags = __cpu_to_le32(flags);
@@ -2944,7 +3005,7 @@ int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
eir_len = eir_append_data(ev->eir, eir_len,
EIR_CLASS_OF_DEV, dev_class, 3);
- put_unaligned_le16(eir_len, &ev->eir_len);
+ ev->eir_len = cpu_to_le16(eir_len);
return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
sizeof(*ev) + eir_len, NULL);
@@ -2995,13 +3056,13 @@ int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
bacpy(&ev.bdaddr, bdaddr);
- ev.type = link_to_mgmt(link_type, addr_type);
+ ev.type = link_to_bdaddr(link_type, addr_type);
err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
sk);
if (sk)
- sock_put(sk);
+ sock_put(sk);
mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
hdev);
@@ -3021,7 +3082,7 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
return -ENOENT;
bacpy(&rp.addr.bdaddr, bdaddr);
- rp.addr.type = link_to_mgmt(link_type, addr_type);
+ rp.addr.type = link_to_bdaddr(link_type, addr_type);
err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
mgmt_status(status), &rp, sizeof(rp));
@@ -3039,7 +3100,7 @@ int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
struct mgmt_ev_connect_failed ev;
bacpy(&ev.addr.bdaddr, bdaddr);
- ev.addr.type = link_to_mgmt(link_type, addr_type);
+ ev.addr.type = link_to_bdaddr(link_type, addr_type);
ev.status = mgmt_status(status);
return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
@@ -3050,7 +3111,7 @@ int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
struct mgmt_ev_pin_code_request ev;
bacpy(&ev.addr.bdaddr, bdaddr);
- ev.addr.type = MGMT_ADDR_BREDR;
+ ev.addr.type = BDADDR_BREDR;
ev.secure = secure;
return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
@@ -3069,7 +3130,7 @@ int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
return -ENOENT;
bacpy(&rp.addr.bdaddr, bdaddr);
- rp.addr.type = MGMT_ADDR_BREDR;
+ rp.addr.type = BDADDR_BREDR;
err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
mgmt_status(status), &rp, sizeof(rp));
@@ -3091,7 +3152,7 @@ int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
return -ENOENT;
bacpy(&rp.addr.bdaddr, bdaddr);
- rp.addr.type = MGMT_ADDR_BREDR;
+ rp.addr.type = BDADDR_BREDR;
err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
mgmt_status(status), &rp, sizeof(rp));
@@ -3110,9 +3171,9 @@ int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
BT_DBG("%s", hdev->name);
bacpy(&ev.addr.bdaddr, bdaddr);
- ev.addr.type = link_to_mgmt(link_type, addr_type);
+ ev.addr.type = link_to_bdaddr(link_type, addr_type);
ev.confirm_hint = confirm_hint;
- put_unaligned_le32(value, &ev.value);
+ ev.value = value;
return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
NULL);
@@ -3126,7 +3187,7 @@ int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
BT_DBG("%s", hdev->name);
bacpy(&ev.addr.bdaddr, bdaddr);
- ev.addr.type = link_to_mgmt(link_type, addr_type);
+ ev.addr.type = link_to_bdaddr(link_type, addr_type);
return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
NULL);
@@ -3145,7 +3206,7 @@ static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
return -ENOENT;
bacpy(&rp.addr.bdaddr, bdaddr);
- rp.addr.type = link_to_mgmt(link_type, addr_type);
+ rp.addr.type = link_to_bdaddr(link_type, addr_type);
err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
&rp, sizeof(rp));
@@ -3188,7 +3249,7 @@ int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
struct mgmt_ev_auth_failed ev;
bacpy(&ev.addr.bdaddr, bdaddr);
- ev.addr.type = link_to_mgmt(link_type, addr_type);
+ ev.addr.type = link_to_bdaddr(link_type, addr_type);
ev.status = mgmt_status(status);
return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
@@ -3413,10 +3474,10 @@ int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
if (enable && test_and_clear_bit(HCI_LE_ENABLED,
&hdev->dev_flags))
- err = new_settings(hdev, NULL);
+ err = new_settings(hdev, NULL);
- mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
- cmd_status_rsp, &mgmt_err);
+ mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
+ &mgmt_err);
return err;
}
@@ -3455,7 +3516,7 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
memset(buf, 0, sizeof(buf));
bacpy(&ev->addr.bdaddr, bdaddr);
- ev->addr.type = link_to_mgmt(link_type, addr_type);
+ ev->addr.type = link_to_bdaddr(link_type, addr_type);
ev->rssi = rssi;
if (cfm_name)
ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
@@ -3469,7 +3530,7 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
dev_class, 3);
- put_unaligned_le16(eir_len, &ev->eir_len);
+ ev->eir_len = cpu_to_le16(eir_len);
ev_size = sizeof(*ev) + eir_len;
@@ -3488,13 +3549,13 @@ int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
memset(buf, 0, sizeof(buf));
bacpy(&ev->addr.bdaddr, bdaddr);
- ev->addr.type = link_to_mgmt(link_type, addr_type);
+ ev->addr.type = link_to_bdaddr(link_type, addr_type);
ev->rssi = rssi;
eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
name_len);
- put_unaligned_le16(eir_len, &ev->eir_len);
+ ev->eir_len = cpu_to_le16(eir_len);
return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
sizeof(*ev) + eir_len, NULL);
@@ -3594,6 +3655,3 @@ int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
module_param(enable_hs, bool, 0644);
MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
-
-module_param(enable_le, bool, 0644);
-MODULE_PARM_DESC(enable_le, "Enable Low Energy support");
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index a55a43e9f70e..e8707debb864 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -260,7 +260,8 @@ static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
if (parent) {
sk->sk_type = parent->sk_type;
- pi->dlc->defer_setup = bt_sk(parent)->defer_setup;
+ pi->dlc->defer_setup = test_bit(BT_SK_DEFER_SETUP,
+ &bt_sk(parent)->flags);
pi->sec_level = rfcomm_pi(parent)->sec_level;
pi->role_switch = rfcomm_pi(parent)->role_switch;
@@ -731,7 +732,11 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c
break;
}
- bt_sk(sk)->defer_setup = opt;
+ if (opt)
+ set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
+ else
+ clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
+
break;
default:
@@ -849,7 +854,8 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c
break;
}
- if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval))
+ if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags),
+ (u32 __user *) optval))
err = -EFAULT;
break;
@@ -972,7 +978,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc *
done:
bh_unlock_sock(parent);
- if (bt_sk(parent)->defer_setup)
+ if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags))
parent->sk_state_change(parent);
return result;
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 4bf54b377255..aa5d73b786ac 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -48,13 +48,12 @@
static struct tty_driver *rfcomm_tty_driver;
struct rfcomm_dev {
+ struct tty_port port;
struct list_head list;
- atomic_t refcnt;
char name[12];
int id;
unsigned long flags;
- atomic_t opened;
int err;
bdaddr_t src;
@@ -64,9 +63,7 @@ struct rfcomm_dev {
uint modem_status;
struct rfcomm_dlc *dlc;
- struct tty_struct *tty;
wait_queue_head_t wait;
- struct work_struct wakeup_task;
struct device *tty_dev;
@@ -82,11 +79,18 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb);
static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err);
static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig);
-static void rfcomm_tty_wakeup(struct work_struct *work);
-
/* ---- Device functions ---- */
-static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
+
+/*
+ * The reason this isn't actually a race, as you no doubt have a little voice
+ * screaming at you in your head, is that the refcount should never actually
+ * reach zero unless the device has already been taken off the list, in
+ * rfcomm_dev_del(). And if that's not true, we'll hit the BUG() in
+ * rfcomm_dev_destruct() anyway.
+ */
+static void rfcomm_dev_destruct(struct tty_port *port)
{
+ struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port);
struct rfcomm_dlc *dlc = dev->dlc;
BT_DBG("dev %p dlc %p", dev, dlc);
@@ -113,23 +117,9 @@ static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
module_put(THIS_MODULE);
}
-static inline void rfcomm_dev_hold(struct rfcomm_dev *dev)
-{
- atomic_inc(&dev->refcnt);
-}
-
-static inline void rfcomm_dev_put(struct rfcomm_dev *dev)
-{
- /* The reason this isn't actually a race, as you no
- doubt have a little voice screaming at you in your
- head, is that the refcount should never actually
- reach zero unless the device has already been taken
- off the list, in rfcomm_dev_del(). And if that's not
- true, we'll hit the BUG() in rfcomm_dev_destruct()
- anyway. */
- if (atomic_dec_and_test(&dev->refcnt))
- rfcomm_dev_destruct(dev);
-}
+static const struct tty_port_operations rfcomm_port_ops = {
+ .destruct = rfcomm_dev_destruct,
+};
static struct rfcomm_dev *__rfcomm_dev_get(int id)
{
@@ -154,7 +144,7 @@ static inline struct rfcomm_dev *rfcomm_dev_get(int id)
if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
dev = NULL;
else
- rfcomm_dev_hold(dev);
+ tty_port_get(&dev->port);
}
spin_unlock(&rfcomm_dev_lock);
@@ -241,7 +231,6 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
sprintf(dev->name, "rfcomm%d", dev->id);
list_add(&dev->list, head);
- atomic_set(&dev->refcnt, 1);
bacpy(&dev->src, &req->src);
bacpy(&dev->dst, &req->dst);
@@ -250,10 +239,9 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
dev->flags = req->flags &
((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC));
- atomic_set(&dev->opened, 0);
-
+ tty_port_init(&dev->port);
+ dev->port.ops = &rfcomm_port_ops;
init_waitqueue_head(&dev->wait);
- INIT_WORK(&dev->wakeup_task, rfcomm_tty_wakeup);
skb_queue_head_init(&dev->pending);
@@ -320,18 +308,23 @@ free:
static void rfcomm_dev_del(struct rfcomm_dev *dev)
{
+ unsigned long flags;
BT_DBG("dev %p", dev);
BUG_ON(test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags));
- if (atomic_read(&dev->opened) > 0)
+ spin_lock_irqsave(&dev->port.lock, flags);
+ if (dev->port.count > 0) {
+ spin_unlock_irqrestore(&dev->port.lock, flags);
return;
+ }
+ spin_unlock_irqrestore(&dev->port.lock, flags);
spin_lock(&rfcomm_dev_lock);
list_del_init(&dev->list);
spin_unlock(&rfcomm_dev_lock);
- rfcomm_dev_put(dev);
+ tty_port_put(&dev->port);
}
/* ---- Send buffer ---- */
@@ -345,15 +338,16 @@ static inline unsigned int rfcomm_room(struct rfcomm_dlc *dlc)
static void rfcomm_wfree(struct sk_buff *skb)
{
struct rfcomm_dev *dev = (void *) skb->sk;
+ struct tty_struct *tty = dev->port.tty;
atomic_sub(skb->truesize, &dev->wmem_alloc);
- if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
- queue_work(system_nrt_wq, &dev->wakeup_task);
- rfcomm_dev_put(dev);
+ if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags) && tty)
+ tty_wakeup(tty);
+ tty_port_put(&dev->port);
}
static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
{
- rfcomm_dev_hold(dev);
+ tty_port_get(&dev->port);
atomic_add(skb->truesize, &dev->wmem_alloc);
skb->sk = (void *) dev;
skb->destructor = rfcomm_wfree;
@@ -432,7 +426,7 @@ static int rfcomm_release_dev(void __user *arg)
return -ENODEV;
if (dev->flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN)) {
- rfcomm_dev_put(dev);
+ tty_port_put(&dev->port);
return -EPERM;
}
@@ -440,12 +434,12 @@ static int rfcomm_release_dev(void __user *arg)
rfcomm_dlc_close(dev->dlc, 0);
/* Shut down TTY synchronously before freeing rfcomm_dev */
- if (dev->tty)
- tty_vhangup(dev->tty);
+ if (dev->port.tty)
+ tty_vhangup(dev->port.tty);
if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
rfcomm_dev_del(dev);
- rfcomm_dev_put(dev);
+ tty_port_put(&dev->port);
return 0;
}
@@ -523,7 +517,7 @@ static int rfcomm_get_dev_info(void __user *arg)
if (copy_to_user(arg, &di, sizeof(di)))
err = -EFAULT;
- rfcomm_dev_put(dev);
+ tty_port_put(&dev->port);
return err;
}
@@ -559,7 +553,7 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
return;
}
- tty = dev->tty;
+ tty = dev->port.tty;
if (!tty || !skb_queue_empty(&dev->pending)) {
skb_queue_tail(&dev->pending, skb);
return;
@@ -585,13 +579,13 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
wake_up_interruptible(&dev->wait);
if (dlc->state == BT_CLOSED) {
- if (!dev->tty) {
+ if (!dev->port.tty) {
if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
/* Drop DLC lock here to avoid deadlock
* 1. rfcomm_dev_get will take rfcomm_dev_lock
* but in rfcomm_dev_add there's lock order:
* rfcomm_dev_lock -> dlc lock
- * 2. rfcomm_dev_put will deadlock if it's
+ * 2. tty_port_put will deadlock if it's
* the last reference
*/
rfcomm_dlc_unlock(dlc);
@@ -601,11 +595,11 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
}
rfcomm_dev_del(dev);
- rfcomm_dev_put(dev);
+ tty_port_put(&dev->port);
rfcomm_dlc_lock(dlc);
}
} else
- tty_hangup(dev->tty);
+ tty_hangup(dev->port.tty);
}
}
@@ -618,8 +612,8 @@ static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
BT_DBG("dlc %p dev %p v24_sig 0x%02x", dlc, dev, v24_sig);
if ((dev->modem_status & TIOCM_CD) && !(v24_sig & RFCOMM_V24_DV)) {
- if (dev->tty && !C_CLOCAL(dev->tty))
- tty_hangup(dev->tty);
+ if (dev->port.tty && !C_CLOCAL(dev->port.tty))
+ tty_hangup(dev->port.tty);
}
dev->modem_status =
@@ -630,21 +624,9 @@ static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
}
/* ---- TTY functions ---- */
-static void rfcomm_tty_wakeup(struct work_struct *work)
-{
- struct rfcomm_dev *dev = container_of(work, struct rfcomm_dev,
- wakeup_task);
- struct tty_struct *tty = dev->tty;
- if (!tty)
- return;
-
- BT_DBG("dev %p tty %p", dev, tty);
- tty_wakeup(tty);
-}
-
static void rfcomm_tty_copy_pending(struct rfcomm_dev *dev)
{
- struct tty_struct *tty = dev->tty;
+ struct tty_struct *tty = dev->port.tty;
struct sk_buff *skb;
int inserted = 0;
@@ -671,6 +653,7 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
DECLARE_WAITQUEUE(wait, current);
struct rfcomm_dev *dev;
struct rfcomm_dlc *dlc;
+ unsigned long flags;
int err, id;
id = tty->index;
@@ -686,10 +669,14 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
return -ENODEV;
BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst),
- dev->channel, atomic_read(&dev->opened));
+ dev->channel, dev->port.count);
- if (atomic_inc_return(&dev->opened) > 1)
+ spin_lock_irqsave(&dev->port.lock, flags);
+ if (++dev->port.count > 1) {
+ spin_unlock_irqrestore(&dev->port.lock, flags);
return 0;
+ }
+ spin_unlock_irqrestore(&dev->port.lock, flags);
dlc = dev->dlc;
@@ -697,7 +684,7 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
rfcomm_dlc_lock(dlc);
tty->driver_data = dev;
- dev->tty = tty;
+ dev->port.tty = tty;
rfcomm_dlc_unlock(dlc);
set_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
@@ -723,9 +710,9 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
break;
}
- tty_unlock();
+ tty_unlock(tty);
schedule();
- tty_lock();
+ tty_lock(tty);
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&dev->wait, &wait);
@@ -744,13 +731,17 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
{
struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
+ unsigned long flags;
+
if (!dev)
return;
BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc,
- atomic_read(&dev->opened));
+ dev->port.count);
- if (atomic_dec_and_test(&dev->opened)) {
+ spin_lock_irqsave(&dev->port.lock, flags);
+ if (!--dev->port.count) {
+ spin_unlock_irqrestore(&dev->port.lock, flags);
if (dev->tty_dev->parent)
device_move(dev->tty_dev, NULL, DPM_ORDER_DEV_LAST);
@@ -758,11 +749,10 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
rfcomm_dlc_close(dev->dlc, 0);
clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
- cancel_work_sync(&dev->wakeup_task);
rfcomm_dlc_lock(dev->dlc);
tty->driver_data = NULL;
- dev->tty = NULL;
+ dev->port.tty = NULL;
rfcomm_dlc_unlock(dev->dlc);
if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) {
@@ -770,11 +760,12 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
list_del_init(&dev->list);
spin_unlock(&rfcomm_dev_lock);
- rfcomm_dev_put(dev);
+ tty_port_put(&dev->port);
}
- }
+ } else
+ spin_unlock_irqrestore(&dev->port.lock, flags);
- rfcomm_dev_put(dev);
+ tty_port_put(&dev->port);
}
static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
@@ -1083,7 +1074,7 @@ static void rfcomm_tty_hangup(struct tty_struct *tty)
if (rfcomm_dev_get(dev->id) == NULL)
return;
rfcomm_dev_del(dev);
- rfcomm_dev_put(dev);
+ tty_port_put(&dev->port);
}
}
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index f6ab12907963..cbdd313659a7 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -61,8 +61,6 @@ static struct bt_sock_list sco_sk_list = {
static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent);
static void sco_chan_del(struct sock *sk, int err);
-static int sco_conn_del(struct hci_conn *conn, int err);
-
static void sco_sock_close(struct sock *sk);
static void sco_sock_kill(struct sock *sk);
@@ -95,12 +93,12 @@ static void sco_sock_clear_timer(struct sock *sk)
}
/* ---- SCO connections ---- */
-static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status)
+static struct sco_conn *sco_conn_add(struct hci_conn *hcon)
{
struct hci_dev *hdev = hcon->hdev;
struct sco_conn *conn = hcon->sco_data;
- if (conn || status)
+ if (conn)
return conn;
conn = kzalloc(sizeof(struct sco_conn), GFP_ATOMIC);
@@ -195,13 +193,14 @@ static int sco_connect(struct sock *sk)
else
type = SCO_LINK;
- hcon = hci_connect(hdev, type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING);
+ hcon = hci_connect(hdev, type, dst, BDADDR_BREDR, BT_SECURITY_LOW,
+ HCI_AT_NO_BONDING);
if (IS_ERR(hcon)) {
err = PTR_ERR(hcon);
goto done;
}
- conn = sco_conn_add(hcon, 0);
+ conn = sco_conn_add(hcon);
if (!conn) {
hci_conn_put(hcon);
err = -ENOMEM;
@@ -233,7 +232,7 @@ static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
{
struct sco_conn *conn = sco_pi(sk)->conn;
struct sk_buff *skb;
- int err, count;
+ int err;
/* Check outgoing MTU */
if (len > conn->mtu)
@@ -241,20 +240,18 @@ static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
BT_DBG("sk %p len %d", sk, len);
- count = min_t(unsigned int, conn->mtu, len);
- skb = bt_skb_send_alloc(sk, count,
- msg->msg_flags & MSG_DONTWAIT, &err);
+ skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err);
if (!skb)
return err;
- if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
+ if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
kfree_skb(skb);
return -EFAULT;
}
hci_send_sco(conn->hcon, skb);
- return count;
+ return len;
}
static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
@@ -277,17 +274,20 @@ drop:
}
/* -------- Socket interface ---------- */
-static struct sock *__sco_get_sock_by_addr(bdaddr_t *ba)
+static struct sock *__sco_get_sock_listen_by_addr(bdaddr_t *ba)
{
- struct sock *sk;
struct hlist_node *node;
+ struct sock *sk;
+
+ sk_for_each(sk, node, &sco_sk_list.head) {
+ if (sk->sk_state != BT_LISTEN)
+ continue;
- sk_for_each(sk, node, &sco_sk_list.head)
if (!bacmp(&bt_sk(sk)->src, ba))
- goto found;
- sk = NULL;
-found:
- return sk;
+ return sk;
+ }
+
+ return NULL;
}
/* Find socket listening on source bdaddr.
@@ -466,7 +466,6 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
{
struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
struct sock *sk = sock->sk;
- bdaddr_t *src = &sa->sco_bdaddr;
int err = 0;
BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr));
@@ -481,17 +480,14 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
goto done;
}
- write_lock(&sco_sk_list.lock);
-
- if (bacmp(src, BDADDR_ANY) && __sco_get_sock_by_addr(src)) {
- err = -EADDRINUSE;
- } else {
- /* Save source address */
- bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr);
- sk->sk_state = BT_BOUND;
+ if (sk->sk_type != SOCK_SEQPACKET) {
+ err = -EINVAL;
+ goto done;
}
- write_unlock(&sco_sk_list.lock);
+ bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr);
+
+ sk->sk_state = BT_BOUND;
done:
release_sock(sk);
@@ -537,21 +533,38 @@ done:
static int sco_sock_listen(struct socket *sock, int backlog)
{
struct sock *sk = sock->sk;
+ bdaddr_t *src = &bt_sk(sk)->src;
int err = 0;
BT_DBG("sk %p backlog %d", sk, backlog);
lock_sock(sk);
- if (sk->sk_state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
+ if (sk->sk_state != BT_BOUND) {
err = -EBADFD;
goto done;
}
+ if (sk->sk_type != SOCK_SEQPACKET) {
+ err = -EINVAL;
+ goto done;
+ }
+
+ write_lock(&sco_sk_list.lock);
+
+ if (__sco_get_sock_listen_by_addr(src)) {
+ err = -EADDRINUSE;
+ goto unlock;
+ }
+
sk->sk_max_ack_backlog = backlog;
sk->sk_ack_backlog = 0;
+
sk->sk_state = BT_LISTEN;
+unlock:
+ write_unlock(&sco_sk_list.lock);
+
done:
release_sock(sk);
return err;
@@ -923,7 +936,7 @@ int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
if (!status) {
struct sco_conn *conn;
- conn = sco_conn_add(hcon, status);
+ conn = sco_conn_add(hcon);
if (conn)
sco_conn_ready(conn);
} else
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index deb119875fd9..6fc7c4708f3e 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -956,7 +956,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
HCI_SMP_LTK_SLAVE, 1, authenticated,
enc.ltk, smp->enc_key_size, ediv, ident.rand);
- ident.ediv = cpu_to_le16(ediv);
+ ident.ediv = ediv;
smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident);
diff --git a/net/caif/Kconfig b/net/caif/Kconfig
index 936361e5a2b6..d3694953b1d7 100644
--- a/net/caif/Kconfig
+++ b/net/caif/Kconfig
@@ -25,7 +25,7 @@ config CAIF_DEBUG
bool "Enable Debug"
depends on CAIF
default n
- --- help ---
+ ---help---
Enable the inclusion of debug code in the CAIF stack.
Be aware that doing this will impact performance.
If unsure say N.
diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c
index 09eda68b6763..5b8aa2fae48b 100644
--- a/net/core/netprio_cgroup.c
+++ b/net/core/netprio_cgroup.c
@@ -25,21 +25,6 @@
#include <net/sock.h>
#include <net/netprio_cgroup.h>
-static struct cgroup_subsys_state *cgrp_create(struct cgroup *cgrp);
-static void cgrp_destroy(struct cgroup *cgrp);
-static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp);
-
-struct cgroup_subsys net_prio_subsys = {
- .name = "net_prio",
- .create = cgrp_create,
- .destroy = cgrp_destroy,
- .populate = cgrp_populate,
-#ifdef CONFIG_NETPRIO_CGROUP
- .subsys_id = net_prio_subsys_id,
-#endif
- .module = THIS_MODULE
-};
-
#define PRIOIDX_SZ 128
static unsigned long prioidx_map[PRIOIDX_SZ];
@@ -259,12 +244,19 @@ static struct cftype ss_files[] = {
.read_map = read_priomap,
.write_string = write_priomap,
},
+ { } /* terminate */
};
-static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp)
-{
- return cgroup_add_files(cgrp, ss, ss_files, ARRAY_SIZE(ss_files));
-}
+struct cgroup_subsys net_prio_subsys = {
+ .name = "net_prio",
+ .create = cgrp_create,
+ .destroy = cgrp_destroy,
+#ifdef CONFIG_NETPRIO_CGROUP
+ .subsys_id = net_prio_subsys_id,
+#endif
+ .base_cftypes = ss_files,
+ .module = THIS_MODULE
+};
static int netprio_device_event(struct notifier_block *unused,
unsigned long event, void *ptr)
diff --git a/net/core/sock.c b/net/core/sock.c
index 5efcd6307fa7..653f8c0aedc5 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -143,7 +143,7 @@ static DEFINE_MUTEX(proto_list_mutex);
static LIST_HEAD(proto_list);
#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM
-int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss)
+int mem_cgroup_sockets_init(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
{
struct proto *proto;
int ret = 0;
@@ -151,7 +151,7 @@ int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss)
mutex_lock(&proto_list_mutex);
list_for_each_entry(proto, &proto_list, node) {
if (proto->init_cgroup) {
- ret = proto->init_cgroup(cgrp, ss);
+ ret = proto->init_cgroup(memcg, ss);
if (ret)
goto out;
}
@@ -162,19 +162,19 @@ int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss)
out:
list_for_each_entry_continue_reverse(proto, &proto_list, node)
if (proto->destroy_cgroup)
- proto->destroy_cgroup(cgrp);
+ proto->destroy_cgroup(memcg);
mutex_unlock(&proto_list_mutex);
return ret;
}
-void mem_cgroup_sockets_destroy(struct cgroup *cgrp)
+void mem_cgroup_sockets_destroy(struct mem_cgroup *memcg)
{
struct proto *proto;
mutex_lock(&proto_list_mutex);
list_for_each_entry_reverse(proto, &proto_list, node)
if (proto->destroy_cgroup)
- proto->destroy_cgroup(cgrp);
+ proto->destroy_cgroup(memcg);
mutex_unlock(&proto_list_mutex);
}
#endif
@@ -813,8 +813,8 @@ void cred_to_ucred(struct pid *pid, const struct cred *cred,
if (cred) {
struct user_namespace *current_ns = current_user_ns();
- ucred->uid = user_ns_map_uid(current_ns, cred, cred->euid);
- ucred->gid = user_ns_map_gid(current_ns, cred, cred->egid);
+ ucred->uid = from_kuid(current_ns, cred->euid);
+ ucred->gid = from_kgid(current_ns, cred->egid);
}
}
EXPORT_SYMBOL_GPL(cred_to_ucred);
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index a8bdf7405433..e5b7182fa099 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -145,6 +145,12 @@ static void free_fib_info_rcu(struct rcu_head *head)
{
struct fib_info *fi = container_of(head, struct fib_info, rcu);
+ change_nexthops(fi) {
+ if (nexthop_nh->nh_dev)
+ dev_put(nexthop_nh->nh_dev);
+ } endfor_nexthops(fi);
+
+ release_net(fi->fib_net);
if (fi->fib_metrics != (u32 *) dst_default_metrics)
kfree(fi->fib_metrics);
kfree(fi);
@@ -156,13 +162,7 @@ void free_fib_info(struct fib_info *fi)
pr_warn("Freeing alive fib_info %p\n", fi);
return;
}
- change_nexthops(fi) {
- if (nexthop_nh->nh_dev)
- dev_put(nexthop_nh->nh_dev);
- nexthop_nh->nh_dev = NULL;
- } endfor_nexthops(fi);
fib_info_cnt--;
- release_net(fi->fib_net);
call_rcu(&fi->rcu, free_fib_info_rcu);
}
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 6e930c7174dd..2c00e8bf684d 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -207,17 +207,22 @@ static int ping_init_sock(struct sock *sk)
gid_t range[2];
struct group_info *group_info = get_current_groups();
int i, j, count = group_info->ngroups;
+ kgid_t low, high;
inet_get_ping_group_range_net(net, range, range+1);
+ low = make_kgid(&init_user_ns, range[0]);
+ high = make_kgid(&init_user_ns, range[1]);
+ if (!gid_valid(low) || !gid_valid(high) || gid_lt(high, low))
+ return -EACCES;
+
if (range[0] <= group && group <= range[1])
return 0;
for (i = 0; i < group_info->nblocks; i++) {
int cp_count = min_t(int, NGROUPS_PER_BLOCK, count);
-
for (j = 0; j < cp_count; j++) {
- group = group_info->blocks[i][j];
- if (range[0] <= group && group <= range[1])
+ kgid_t gid = group_info->blocks[i][j];
+ if (gid_lte(low, gid) && gid_lte(gid, high))
return 0;
}
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index ffcb3b016843..98b30d08efe9 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -3452,6 +3452,7 @@ int __init ip_rt_init(void)
0,
&rt_hash_log,
&rt_hash_mask,
+ 0,
rhash_entries ? 0 : 512 * 1024);
memset(rt_hash_table, 0, (rt_hash_mask + 1) * sizeof(struct rt_hash_bucket));
rt_hash_lock_init();
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index bb485fcb077e..3ba605f60e4e 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -3514,6 +3514,7 @@ void __init tcp_init(void)
0,
NULL,
&tcp_hashinfo.ehash_mask,
+ 0,
thash_entries ? 0 : 512 * 1024);
for (i = 0; i <= tcp_hashinfo.ehash_mask; i++) {
INIT_HLIST_NULLS_HEAD(&tcp_hashinfo.ehash[i].chain, i);
@@ -3530,6 +3531,7 @@ void __init tcp_init(void)
0,
&tcp_hashinfo.bhash_size,
NULL,
+ 0,
64 * 1024);
tcp_hashinfo.bhash_size = 1U << tcp_hashinfo.bhash_size;
for (i = 0; i < tcp_hashinfo.bhash_size; i++) {
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index cfa2aa128342..b224eb8bce8b 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4555,6 +4555,11 @@ static bool tcp_try_coalesce(struct sock *sk,
if (tcp_hdr(from)->fin)
return false;
+
+ /* Its possible this segment overlaps with prior segment in queue */
+ if (TCP_SKB_CB(from)->seq != TCP_SKB_CB(to)->end_seq)
+ return false;
+
if (!skb_try_coalesce(to, from, fragstolen, &delta))
return false;
diff --git a/net/ipv4/tcp_memcontrol.c b/net/ipv4/tcp_memcontrol.c
index e795272fbe9e..151703791bb0 100644
--- a/net/ipv4/tcp_memcontrol.c
+++ b/net/ipv4/tcp_memcontrol.c
@@ -6,37 +6,6 @@
#include <linux/memcontrol.h>
#include <linux/module.h>
-static u64 tcp_cgroup_read(struct cgroup *cont, struct cftype *cft);
-static int tcp_cgroup_write(struct cgroup *cont, struct cftype *cft,
- const char *buffer);
-static int tcp_cgroup_reset(struct cgroup *cont, unsigned int event);
-
-static struct cftype tcp_files[] = {
- {
- .name = "kmem.tcp.limit_in_bytes",
- .write_string = tcp_cgroup_write,
- .read_u64 = tcp_cgroup_read,
- .private = RES_LIMIT,
- },
- {
- .name = "kmem.tcp.usage_in_bytes",
- .read_u64 = tcp_cgroup_read,
- .private = RES_USAGE,
- },
- {
- .name = "kmem.tcp.failcnt",
- .private = RES_FAILCNT,
- .trigger = tcp_cgroup_reset,
- .read_u64 = tcp_cgroup_read,
- },
- {
- .name = "kmem.tcp.max_usage_in_bytes",
- .private = RES_MAX_USAGE,
- .trigger = tcp_cgroup_reset,
- .read_u64 = tcp_cgroup_read,
- },
-};
-
static inline struct tcp_memcontrol *tcp_from_cgproto(struct cg_proto *cg_proto)
{
return container_of(cg_proto, struct tcp_memcontrol, cg_proto);
@@ -49,7 +18,7 @@ static void memcg_tcp_enter_memory_pressure(struct sock *sk)
}
EXPORT_SYMBOL(memcg_tcp_enter_memory_pressure);
-int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss)
+int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
{
/*
* The root cgroup does not use res_counters, but rather,
@@ -59,13 +28,12 @@ int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss)
struct res_counter *res_parent = NULL;
struct cg_proto *cg_proto, *parent_cg;
struct tcp_memcontrol *tcp;
- struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
struct mem_cgroup *parent = parent_mem_cgroup(memcg);
struct net *net = current->nsproxy->net_ns;
cg_proto = tcp_prot.proto_cgroup(memcg);
if (!cg_proto)
- goto create_files;
+ return 0;
tcp = tcp_from_cgproto(cg_proto);
@@ -88,15 +56,12 @@ int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss)
cg_proto->sockets_allocated = &tcp->tcp_sockets_allocated;
cg_proto->memcg = memcg;
-create_files:
- return cgroup_add_files(cgrp, ss, tcp_files,
- ARRAY_SIZE(tcp_files));
+ return 0;
}
EXPORT_SYMBOL(tcp_init_cgroup);
-void tcp_destroy_cgroup(struct cgroup *cgrp)
+void tcp_destroy_cgroup(struct mem_cgroup *memcg)
{
- struct mem_cgroup *memcg = mem_cgroup_from_cont(cgrp);
struct cg_proto *cg_proto;
struct tcp_memcontrol *tcp;
u64 val;
@@ -270,3 +235,37 @@ void tcp_prot_mem(struct mem_cgroup *memcg, long val, int idx)
tcp->tcp_prot_mem[idx] = val;
}
+
+static struct cftype tcp_files[] = {
+ {
+ .name = "kmem.tcp.limit_in_bytes",
+ .write_string = tcp_cgroup_write,
+ .read_u64 = tcp_cgroup_read,
+ .private = RES_LIMIT,
+ },
+ {
+ .name = "kmem.tcp.usage_in_bytes",
+ .read_u64 = tcp_cgroup_read,
+ .private = RES_USAGE,
+ },
+ {
+ .name = "kmem.tcp.failcnt",
+ .private = RES_FAILCNT,
+ .trigger = tcp_cgroup_reset,
+ .read_u64 = tcp_cgroup_read,
+ },
+ {
+ .name = "kmem.tcp.max_usage_in_bytes",
+ .private = RES_MAX_USAGE,
+ .trigger = tcp_cgroup_reset,
+ .read_u64 = tcp_cgroup_read,
+ },
+ { } /* terminate */
+};
+
+static int __init tcp_memcontrol_init(void)
+{
+ WARN_ON(cgroup_add_cftypes(&mem_cgroup_subsys, tcp_files));
+ return 0;
+}
+__initcall(tcp_memcontrol_init);
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 609397ee78fb..eaca73644e79 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -2192,26 +2192,16 @@ void __init udp_table_init(struct udp_table *table, const char *name)
{
unsigned int i;
- if (!CONFIG_BASE_SMALL)
- table->hash = alloc_large_system_hash(name,
- 2 * sizeof(struct udp_hslot),
- uhash_entries,
- 21, /* one slot per 2 MB */
- 0,
- &table->log,
- &table->mask,
- 64 * 1024);
- /*
- * Make sure hash table has the minimum size
- */
- if (CONFIG_BASE_SMALL || table->mask < UDP_HTABLE_SIZE_MIN - 1) {
- table->hash = kmalloc(UDP_HTABLE_SIZE_MIN *
- 2 * sizeof(struct udp_hslot), GFP_KERNEL);
- if (!table->hash)
- panic(name);
- table->log = ilog2(UDP_HTABLE_SIZE_MIN);
- table->mask = UDP_HTABLE_SIZE_MIN - 1;
- }
+ table->hash = alloc_large_system_hash(name,
+ 2 * sizeof(struct udp_hslot),
+ uhash_entries,
+ 21, /* one slot per 2 MB */
+ 0,
+ &table->log,
+ &table->mask,
+ UDP_HTABLE_SIZE_MIN,
+ 64 * 1024);
+
table->hash2 = table->hash + (table->mask + 1);
for (i = 0; i <= table->mask; i++) {
INIT_HLIST_NULLS_HEAD(&table->hash[i].head, i);
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 5b7053c58732..7cf07158805c 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -421,16 +421,22 @@ static void sta_tx_agg_session_timer_expired(unsigned long data)
struct tid_ampdu_tx *tid_tx;
unsigned long timeout;
- tid_tx = rcu_dereference_protected_tid_tx(sta, *ptid);
- if (!tid_tx)
+ rcu_read_lock();
+ tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[*ptid]);
+ if (!tid_tx || test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
+ rcu_read_unlock();
return;
+ }
timeout = tid_tx->last_tx + TU_TO_JIFFIES(tid_tx->timeout);
if (time_is_after_jiffies(timeout)) {
mod_timer(&tid_tx->session_timer, timeout);
+ rcu_read_unlock();
return;
}
+ rcu_read_unlock();
+
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "tx session timer expired on tid %d\n", (u16)*ptid);
#endif
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index ea0122dbd2b3..7ed433c66d68 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -509,6 +509,7 @@ IEEE80211_IF_FILE(dot11MeshHWMPRannInterval,
u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC);
IEEE80211_IF_FILE(dot11MeshForwarding, u.mesh.mshcfg.dot11MeshForwarding, DEC);
IEEE80211_IF_FILE(rssi_threshold, u.mesh.mshcfg.rssi_threshold, DEC);
+IEEE80211_IF_FILE(ht_opmode, u.mesh.mshcfg.ht_opmode, DEC);
#endif
#define DEBUGFS_ADD_MODE(name, mode) \
@@ -608,6 +609,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata)
MESHPARAMS_ADD(dot11MeshHWMPRannInterval);
MESHPARAMS_ADD(dot11MeshGateAnnouncementProtocol);
MESHPARAMS_ADD(rssi_threshold);
+ MESHPARAMS_ADD(ht_opmode);
#undef MESHPARAMS_ADD
}
#endif
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 3ad33a824624..33d9d0c3e3d0 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -163,6 +163,11 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
sizeof(struct ieee80211_ht_operation));
pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap,
sband->ht_cap.cap);
+ /*
+ * Note: According to 802.11n-2009 9.13.3.1, HT Protection
+ * field and RIFS Mode are reserved in IBSS mode, therefore
+ * keep them at 0
+ */
pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap,
chan, channel_type, 0);
}
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 856237c5c1f8..d4c19a7773db 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -206,8 +206,10 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata)
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
sdata->vif.hw_queue[i] = IEEE80211_INVAL_HW_QUEUE;
- else
+ else if (local->hw.queues >= IEEE80211_NUM_ACS)
sdata->vif.hw_queue[i] = i;
+ else
+ sdata->vif.hw_queue[i] = 0;
}
sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE;
}
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index b70f7f09da61..f5548e953259 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -596,6 +596,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
local->hw.offchannel_tx_hw_queue = IEEE80211_INVAL_HW_QUEUE;
local->hw.conf.long_frame_max_tx_count = wiphy->retry_long;
local->hw.conf.short_frame_max_tx_count = wiphy->retry_short;
+ local->hw.radiotap_mcs_details = IEEE80211_RADIOTAP_MCS_HAVE_MCS |
+ IEEE80211_RADIOTAP_MCS_HAVE_GI |
+ IEEE80211_RADIOTAP_MCS_HAVE_BW;
local->user_power_level = -1;
wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask;
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 0675a2fec6a6..2913113c5833 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -109,8 +109,10 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
/* Disallow HT40+/- mismatch */
if (ie->ht_operation &&
- local->_oper_channel_type > NL80211_CHAN_HT20 &&
- sta_channel_type > NL80211_CHAN_HT20 &&
+ (local->_oper_channel_type == NL80211_CHAN_HT40MINUS ||
+ local->_oper_channel_type == NL80211_CHAN_HT40PLUS) &&
+ (sta_channel_type == NL80211_CHAN_HT40MINUS ||
+ sta_channel_type == NL80211_CHAN_HT40PLUS) &&
local->_oper_channel_type != sta_channel_type)
goto mismatch;
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 27e0c2f06795..9b59658e8650 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -603,7 +603,10 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
hopcount, ttl, cpu_to_le32(lifetime),
cpu_to_le32(metric), cpu_to_le32(preq_id),
sdata);
- ifmsh->mshstats.fwded_mcast++;
+ if (!is_multicast_ether_addr(da))
+ ifmsh->mshstats.fwded_unicast++;
+ else
+ ifmsh->mshstats.fwded_mcast++;
ifmsh->mshstats.fwded_frames++;
}
}
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 8cc8461b48a0..60ef235c9d9b 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -105,15 +105,15 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
return sta;
}
-/** mesh_set_ht_prot_mode - set correct HT protection mode
+/*
+ * mesh_set_ht_prot_mode - set correct HT protection mode
*
- * Section 9.23.3.5 of IEEE 80211s standard describes the protection rules for
- * HT mesh STA in a MBSS. Three HT protection modes are supported for now,
- * non-HT mixed mode, 20MHz-protection and no-protection mode. non-HT mixed
- * mode is selected if any non-HT peers are present in our MBSS.
- * 20MHz-protection mode is selected if all peers in our 20/40MHz MBSS support
- * HT and atleast one HT20 peer is present. Otherwise no-protection mode is
- * selected.
+ * Section 9.23.3.5 of IEEE 80211-2012 describes the protection rules for HT
+ * mesh STA in a MBSS. Three HT protection modes are supported for now, non-HT
+ * mixed mode, 20MHz-protection and no-protection mode. non-HT mixed mode is
+ * selected if any non-HT peers are present in our MBSS. 20MHz-protection mode
+ * is selected if all peers in our 20/40MHz MBSS support HT and atleast one
+ * HT20 peer is present. Otherwise no-protection mode is selected.
*/
static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata)
{
@@ -128,21 +128,22 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata)
rcu_read_lock();
list_for_each_entry_rcu(sta, &local->sta_list, list) {
- if (sdata == sta->sdata &&
- sta->plink_state == NL80211_PLINK_ESTAB) {
- switch (sta->ch_type) {
- case NL80211_CHAN_NO_HT:
- mpl_dbg("mesh_plink %pM: nonHT sta (%pM) is present",
- sdata->vif.addr, sta->sta.addr);
- non_ht_sta = true;
- goto out;
- case NL80211_CHAN_HT20:
- mpl_dbg("mesh_plink %pM: HT20 sta (%pM) is present",
- sdata->vif.addr, sta->sta.addr);
- ht20_sta = true;
- default:
- break;
- }
+ if (sdata != sta->sdata ||
+ sta->plink_state != NL80211_PLINK_ESTAB)
+ continue;
+
+ switch (sta->ch_type) {
+ case NL80211_CHAN_NO_HT:
+ mpl_dbg("mesh_plink %pM: nonHT sta (%pM) is present",
+ sdata->vif.addr, sta->sta.addr);
+ non_ht_sta = true;
+ goto out;
+ case NL80211_CHAN_HT20:
+ mpl_dbg("mesh_plink %pM: HT20 sta (%pM) is present",
+ sdata->vif.addr, sta->sta.addr);
+ ht20_sta = true;
+ default:
+ break;
}
}
out:
@@ -346,6 +347,15 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata,
sta = sta_info_get(sdata, addr);
if (!sta) {
+ /* Userspace handles peer allocation when security is enabled */
+ if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) {
+ cfg80211_notify_new_peer_candidate(sdata->dev, addr,
+ elems->ie_start,
+ elems->total_len,
+ GFP_ATOMIC);
+ return NULL;
+ }
+
sta = mesh_plink_alloc(sdata, addr);
if (!sta)
return NULL;
@@ -387,15 +397,6 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata,
{
struct sta_info *sta;
- /* Userspace handles peer allocation when security is enabled */
- if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) {
- cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr,
- elems->ie_start,
- elems->total_len,
- GFP_KERNEL);
- return;
- }
-
rcu_read_lock();
sta = mesh_peer_init(sdata, hw_addr, elems);
if (!sta)
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 8257a09eeed4..7bcecf73aafb 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -204,14 +204,14 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
if (status->flag & RX_FLAG_HT) {
rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS);
- *pos++ = IEEE80211_RADIOTAP_MCS_HAVE_MCS |
- IEEE80211_RADIOTAP_MCS_HAVE_GI |
- IEEE80211_RADIOTAP_MCS_HAVE_BW;
+ *pos++ = local->hw.radiotap_mcs_details;
*pos = 0;
if (status->flag & RX_FLAG_SHORT_GI)
*pos |= IEEE80211_RADIOTAP_MCS_SGI;
if (status->flag & RX_FLAG_40MHZ)
*pos |= IEEE80211_RADIOTAP_MCS_BW_40;
+ if (status->flag & RX_FLAG_HT_GF)
+ *pos |= IEEE80211_RADIOTAP_MCS_FMT_GF;
pos++;
*pos++ = status->rate_idx;
}
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c
index 7aa31bbfaa3b..c04d401dae92 100644
--- a/net/mac80211/wep.c
+++ b/net/mac80211/wep.c
@@ -92,6 +92,7 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local,
int keylen, int keyidx)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
unsigned int hdrlen;
u8 *newhdr;
@@ -104,6 +105,13 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local,
hdrlen = ieee80211_hdrlen(hdr->frame_control);
newhdr = skb_push(skb, WEP_IV_LEN);
memmove(newhdr, newhdr + WEP_IV_LEN, hdrlen);
+
+ /* the HW only needs room for the IV, but not the actual IV */
+ if (info->control.hw_key &&
+ (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))
+ return newhdr + hdrlen;
+
+ skb_set_network_header(skb, skb_network_offset(skb) + WEP_IV_LEN);
ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen);
return newhdr + hdrlen;
}
@@ -313,14 +321,15 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx)
static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_key_conf *hw_key = info->control.hw_key;
- if (!info->control.hw_key) {
+ if (!hw_key) {
if (ieee80211_wep_encrypt(tx->local, skb, tx->key->conf.key,
tx->key->conf.keylen,
tx->key->conf.keyidx))
return -1;
- } else if (info->control.hw_key->flags &
- IEEE80211_KEY_FLAG_GENERATE_IV) {
+ } else if ((hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
+ (hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) {
if (!ieee80211_wep_add_iv(tx->local, skb,
tx->key->conf.keylen,
tx->key->conf.keyidx))
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 0ae23c60968c..bdb53aba888e 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -183,7 +183,8 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
u8 *pos;
if (info->control.hw_key &&
- !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
+ !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) &&
+ !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) {
/* hwaccel - with no need for software-generated IV */
return 0;
}
@@ -202,8 +203,14 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
pos = skb_push(skb, TKIP_IV_LEN);
memmove(pos, pos + TKIP_IV_LEN, hdrlen);
+ skb_set_network_header(skb, skb_network_offset(skb) + TKIP_IV_LEN);
pos += hdrlen;
+ /* the HW only needs room for the IV, but not the actual IV */
+ if (info->control.hw_key &&
+ (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))
+ return 0;
+
/* Increase IV for the frame */
spin_lock_irqsave(&key->u.tkip.txlock, flags);
key->u.tkip.tx.iv16++;
@@ -422,6 +429,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
pos = skb_push(skb, CCMP_HDR_LEN);
memmove(pos, pos + CCMP_HDR_LEN, hdrlen);
+ skb_set_network_header(skb, skb_network_offset(skb) + CCMP_HDR_LEN);
/* the HW only needs room for the IV, but not the actual IV */
if (info->control.hw_key &&
diff --git a/net/netfilter/xt_TEE.c b/net/netfilter/xt_TEE.c
index 4d5057902839..ee2e5bc5a8c7 100644
--- a/net/netfilter/xt_TEE.c
+++ b/net/netfilter/xt_TEE.c
@@ -87,7 +87,7 @@ tee_tg4(struct sk_buff *skb, const struct xt_action_param *par)
const struct xt_tee_tginfo *info = par->targinfo;
struct iphdr *iph;
- if (percpu_read(tee_active))
+ if (__this_cpu_read(tee_active))
return XT_CONTINUE;
/*
* Copy the skb, and route the copy. Will later return %XT_CONTINUE for
@@ -124,9 +124,9 @@ tee_tg4(struct sk_buff *skb, const struct xt_action_param *par)
ip_send_check(iph);
if (tee_tg_route4(skb, info)) {
- percpu_write(tee_active, true);
+ __this_cpu_write(tee_active, true);
ip_local_out(skb);
- percpu_write(tee_active, false);
+ __this_cpu_write(tee_active, false);
} else {
kfree_skb(skb);
}
@@ -168,7 +168,7 @@ tee_tg6(struct sk_buff *skb, const struct xt_action_param *par)
{
const struct xt_tee_tginfo *info = par->targinfo;
- if (percpu_read(tee_active))
+ if (__this_cpu_read(tee_active))
return XT_CONTINUE;
skb = pskb_copy(skb, GFP_ATOMIC);
if (skb == NULL)
@@ -186,9 +186,9 @@ tee_tg6(struct sk_buff *skb, const struct xt_action_param *par)
--iph->hop_limit;
}
if (tee_tg_route6(skb, info)) {
- percpu_write(tee_active, true);
+ __this_cpu_write(tee_active, true);
ip6_local_out(skb);
- percpu_write(tee_active, false);
+ __this_cpu_write(tee_active, false);
} else {
kfree_skb(skb);
}
diff --git a/net/nfc/core.c b/net/nfc/core.c
index 3192c3f589ee..9f6ce011d35d 100644
--- a/net/nfc/core.c
+++ b/net/nfc/core.c
@@ -97,7 +97,7 @@ int nfc_dev_down(struct nfc_dev *dev)
goto error;
}
- if (dev->polling || dev->activated_target_idx != NFC_TARGET_IDX_NONE) {
+ if (dev->polling || dev->active_target) {
rc = -EBUSY;
goto error;
}
@@ -183,11 +183,27 @@ error:
return rc;
}
+static struct nfc_target *nfc_find_target(struct nfc_dev *dev, u32 target_idx)
+{
+ int i;
+
+ if (dev->n_targets == 0)
+ return NULL;
+
+ for (i = 0; i < dev->n_targets ; i++) {
+ if (dev->targets[i].idx == target_idx)
+ return &dev->targets[i];
+ }
+
+ return NULL;
+}
+
int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode)
{
int rc = 0;
u8 *gb;
size_t gb_len;
+ struct nfc_target *target;
pr_debug("dev_name=%s comm %d\n", dev_name(&dev->dev), comm_mode);
@@ -212,9 +228,15 @@ int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode)
goto error;
}
- rc = dev->ops->dep_link_up(dev, target_index, comm_mode, gb, gb_len);
+ target = nfc_find_target(dev, target_index);
+ if (target == NULL) {
+ rc = -ENOTCONN;
+ goto error;
+ }
+
+ rc = dev->ops->dep_link_up(dev, target, comm_mode, gb, gb_len);
if (!rc)
- dev->activated_target_idx = target_index;
+ dev->active_target = target;
error:
device_unlock(&dev->dev);
@@ -250,7 +272,7 @@ int nfc_dep_link_down(struct nfc_dev *dev)
rc = dev->ops->dep_link_down(dev);
if (!rc) {
dev->dep_link_up = false;
- dev->activated_target_idx = NFC_TARGET_IDX_NONE;
+ dev->active_target = NULL;
nfc_llcp_mac_is_down(dev);
nfc_genl_dep_link_down_event(dev);
}
@@ -282,6 +304,7 @@ EXPORT_SYMBOL(nfc_dep_link_is_up);
int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol)
{
int rc;
+ struct nfc_target *target;
pr_debug("dev_name=%s target_idx=%u protocol=%u\n",
dev_name(&dev->dev), target_idx, protocol);
@@ -293,9 +316,20 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol)
goto error;
}
- rc = dev->ops->activate_target(dev, target_idx, protocol);
+ if (dev->active_target) {
+ rc = -EBUSY;
+ goto error;
+ }
+
+ target = nfc_find_target(dev, target_idx);
+ if (target == NULL) {
+ rc = -ENOTCONN;
+ goto error;
+ }
+
+ rc = dev->ops->activate_target(dev, target, protocol);
if (!rc) {
- dev->activated_target_idx = target_idx;
+ dev->active_target = target;
if (dev->ops->check_presence)
mod_timer(&dev->check_pres_timer, jiffies +
@@ -327,11 +361,21 @@ int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx)
goto error;
}
+ if (dev->active_target == NULL) {
+ rc = -ENOTCONN;
+ goto error;
+ }
+
+ if (dev->active_target->idx != target_idx) {
+ rc = -ENOTCONN;
+ goto error;
+ }
+
if (dev->ops->check_presence)
del_timer_sync(&dev->check_pres_timer);
- dev->ops->deactivate_target(dev, target_idx);
- dev->activated_target_idx = NFC_TARGET_IDX_NONE;
+ dev->ops->deactivate_target(dev, dev->active_target);
+ dev->active_target = NULL;
error:
device_unlock(&dev->dev);
@@ -365,13 +409,13 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb,
goto error;
}
- if (dev->activated_target_idx == NFC_TARGET_IDX_NONE) {
+ if (dev->active_target == NULL) {
rc = -ENOTCONN;
kfree_skb(skb);
goto error;
}
- if (target_idx != dev->activated_target_idx) {
+ if (dev->active_target->idx != target_idx) {
rc = -EADDRNOTAVAIL;
kfree_skb(skb);
goto error;
@@ -380,7 +424,8 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb,
if (dev->ops->check_presence)
del_timer_sync(&dev->check_pres_timer);
- rc = dev->ops->data_exchange(dev, target_idx, skb, cb, cb_context);
+ rc = dev->ops->data_exchange(dev, dev->active_target, skb, cb,
+ cb_context);
if (!rc && dev->ops->check_presence)
mod_timer(&dev->check_pres_timer, jiffies +
@@ -456,6 +501,9 @@ EXPORT_SYMBOL(nfc_alloc_recv_skb);
* The device driver must call this function when one or many nfc targets
* are found. After calling this function, the device driver must stop
* polling for targets.
+ * IMPORTANT: this function must not be called from an atomic context.
+ * In addition, it must also not be called from a context that would prevent
+ * the NFC Core to call other nfc ops entry point concurrently.
*/
int nfc_targets_found(struct nfc_dev *dev,
struct nfc_target *targets, int n_targets)
@@ -469,7 +517,7 @@ int nfc_targets_found(struct nfc_dev *dev,
for (i = 0; i < n_targets; i++)
targets[i].idx = dev->target_next_idx++;
- spin_lock_bh(&dev->targets_lock);
+ device_lock(&dev->dev);
dev->targets_generation++;
@@ -479,12 +527,12 @@ int nfc_targets_found(struct nfc_dev *dev,
if (!dev->targets) {
dev->n_targets = 0;
- spin_unlock_bh(&dev->targets_lock);
+ device_unlock(&dev->dev);
return -ENOMEM;
}
dev->n_targets = n_targets;
- spin_unlock_bh(&dev->targets_lock);
+ device_unlock(&dev->dev);
nfc_genl_targets_found(dev);
@@ -492,6 +540,18 @@ int nfc_targets_found(struct nfc_dev *dev,
}
EXPORT_SYMBOL(nfc_targets_found);
+/**
+ * nfc_target_lost - inform that an activated target went out of field
+ *
+ * @dev: The nfc device that had the activated target in field
+ * @target_idx: the nfc index of the target
+ *
+ * The device driver must call this function when the activated target
+ * goes out of the field.
+ * IMPORTANT: this function must not be called from an atomic context.
+ * In addition, it must also not be called from a context that would prevent
+ * the NFC Core to call other nfc ops entry point concurrently.
+ */
int nfc_target_lost(struct nfc_dev *dev, u32 target_idx)
{
struct nfc_target *tg;
@@ -499,7 +559,7 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx)
pr_debug("dev_name %s n_target %d\n", dev_name(&dev->dev), target_idx);
- spin_lock_bh(&dev->targets_lock);
+ device_lock(&dev->dev);
for (i = 0; i < dev->n_targets; i++) {
tg = &dev->targets[i];
@@ -508,13 +568,13 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx)
}
if (i == dev->n_targets) {
- spin_unlock_bh(&dev->targets_lock);
+ device_unlock(&dev->dev);
return -EINVAL;
}
dev->targets_generation++;
dev->n_targets--;
- dev->activated_target_idx = NFC_TARGET_IDX_NONE;
+ dev->active_target = NULL;
if (dev->n_targets) {
memcpy(&dev->targets[i], &dev->targets[i + 1],
@@ -524,7 +584,7 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx)
dev->targets = NULL;
}
- spin_unlock_bh(&dev->targets_lock);
+ device_unlock(&dev->dev);
nfc_genl_target_lost(dev, target_idx);
@@ -556,15 +616,16 @@ static void nfc_check_pres_work(struct work_struct *work)
device_lock(&dev->dev);
- if (dev->activated_target_idx != NFC_TARGET_IDX_NONE &&
- timer_pending(&dev->check_pres_timer) == 0) {
- rc = dev->ops->check_presence(dev, dev->activated_target_idx);
+ if (dev->active_target && timer_pending(&dev->check_pres_timer) == 0) {
+ rc = dev->ops->check_presence(dev, dev->active_target);
if (!rc) {
mod_timer(&dev->check_pres_timer, jiffies +
msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS));
} else {
- nfc_target_lost(dev, dev->activated_target_idx);
- dev->activated_target_idx = NFC_TARGET_IDX_NONE;
+ u32 active_target_idx = dev->active_target->idx;
+ device_unlock(&dev->dev);
+ nfc_target_lost(dev, active_target_idx);
+ return;
}
}
@@ -637,14 +698,12 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
dev->tx_headroom = tx_headroom;
dev->tx_tailroom = tx_tailroom;
- spin_lock_init(&dev->targets_lock);
nfc_genl_data_init(&dev->genl_data);
+
/* first generation must not be 0 */
dev->targets_generation = 1;
- dev->activated_target_idx = NFC_TARGET_IDX_NONE;
-
if (ops->check_presence) {
char name[32];
init_timer(&dev->check_pres_timer);
@@ -662,7 +721,6 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
}
}
-
return dev;
}
EXPORT_SYMBOL(nfc_allocate_device);
diff --git a/net/nfc/hci/Kconfig b/net/nfc/hci/Kconfig
index 17213a6362b4..fd67f51d18e9 100644
--- a/net/nfc/hci/Kconfig
+++ b/net/nfc/hci/Kconfig
@@ -9,6 +9,7 @@ config NFC_HCI
config NFC_SHDLC
depends on NFC_HCI
+ select CRC_CCITT
bool "SHDLC link layer for HCI based NFC drivers"
default n
---help---
diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c
index 86fd00d5a099..e1a640d2b588 100644
--- a/net/nfc/hci/core.c
+++ b/net/nfc/hci/core.c
@@ -235,13 +235,6 @@ static int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate)
targets->hci_reader_gate = gate;
r = nfc_targets_found(hdev->ndev, targets, 1);
- if (r < 0)
- goto exit;
-
- kfree(hdev->targets);
- hdev->targets = targets;
- targets = NULL;
- hdev->target_count = 1;
exit:
kfree(targets);
@@ -258,11 +251,6 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,
switch (event) {
case NFC_HCI_EVT_TARGET_DISCOVERED:
- if (hdev->poll_started == false) {
- r = -EPROTO;
- goto exit;
- }
-
if (skb->len < 1) { /* no status data? */
r = -EPROTO;
goto exit;
@@ -496,74 +484,42 @@ static int hci_dev_down(struct nfc_dev *nfc_dev)
static int hci_start_poll(struct nfc_dev *nfc_dev, u32 protocols)
{
struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
- int r;
if (hdev->ops->start_poll)
- r = hdev->ops->start_poll(hdev, protocols);
+ return hdev->ops->start_poll(hdev, protocols);
else
- r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
+ return nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
NFC_HCI_EVT_READER_REQUESTED, NULL, 0);
- if (r == 0)
- hdev->poll_started = true;
-
- return r;
}
static void hci_stop_poll(struct nfc_dev *nfc_dev)
{
struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
- if (hdev->poll_started) {
- nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
- NFC_HCI_EVT_END_OPERATION, NULL, 0);
- hdev->poll_started = false;
- }
-}
-
-static struct nfc_target *hci_find_target(struct nfc_hci_dev *hdev,
- u32 target_idx)
-{
- int i;
- if (hdev->poll_started == false || hdev->targets == NULL)
- return NULL;
-
- for (i = 0; i < hdev->target_count; i++) {
- if (hdev->targets[i].idx == target_idx)
- return &hdev->targets[i];
- }
-
- return NULL;
+ nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
+ NFC_HCI_EVT_END_OPERATION, NULL, 0);
}
-static int hci_activate_target(struct nfc_dev *nfc_dev, u32 target_idx,
- u32 protocol)
+static int hci_activate_target(struct nfc_dev *nfc_dev,
+ struct nfc_target *target, u32 protocol)
{
- struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
-
- if (hci_find_target(hdev, target_idx) == NULL)
- return -ENOMEDIUM;
-
return 0;
}
-static void hci_deactivate_target(struct nfc_dev *nfc_dev, u32 target_idx)
+static void hci_deactivate_target(struct nfc_dev *nfc_dev,
+ struct nfc_target *target)
{
}
-static int hci_data_exchange(struct nfc_dev *nfc_dev, u32 target_idx,
+static int hci_data_exchange(struct nfc_dev *nfc_dev, struct nfc_target *target,
struct sk_buff *skb, data_exchange_cb_t cb,
void *cb_context)
{
struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
int r;
- struct nfc_target *target;
struct sk_buff *res_skb = NULL;
- pr_debug("target_idx=%d\n", target_idx);
-
- target = hci_find_target(hdev, target_idx);
- if (target == NULL)
- return -ENOMEDIUM;
+ pr_debug("target_idx=%d\n", target->idx);
switch (target->hci_reader_gate) {
case NFC_HCI_RF_READER_A_GATE:
@@ -605,7 +561,18 @@ static int hci_data_exchange(struct nfc_dev *nfc_dev, u32 target_idx,
return 0;
}
-struct nfc_ops hci_nfc_ops = {
+static int hci_check_presence(struct nfc_dev *nfc_dev,
+ struct nfc_target *target)
+{
+ struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
+
+ if (hdev->ops->check_presence)
+ return hdev->ops->check_presence(hdev, target);
+
+ return 0;
+}
+
+static struct nfc_ops hci_nfc_ops = {
.dev_up = hci_dev_up,
.dev_down = hci_dev_down,
.start_poll = hci_start_poll,
@@ -613,6 +580,7 @@ struct nfc_ops hci_nfc_ops = {
.activate_target = hci_activate_target,
.deactivate_target = hci_deactivate_target,
.data_exchange = hci_data_exchange,
+ .check_presence = hci_check_presence,
};
struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops,
diff --git a/net/nfc/hci/shdlc.c b/net/nfc/hci/shdlc.c
index 923bdf7c26d6..5665dc6d893a 100644
--- a/net/nfc/hci/shdlc.c
+++ b/net/nfc/hci/shdlc.c
@@ -816,6 +816,17 @@ static int nfc_shdlc_data_exchange(struct nfc_hci_dev *hdev,
return -EPERM;
}
+static int nfc_shdlc_check_presence(struct nfc_hci_dev *hdev,
+ struct nfc_target *target)
+{
+ struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev);
+
+ if (shdlc->ops->check_presence)
+ return shdlc->ops->check_presence(shdlc, target);
+
+ return 0;
+}
+
static struct nfc_hci_ops shdlc_ops = {
.open = nfc_shdlc_open,
.close = nfc_shdlc_close,
@@ -825,6 +836,7 @@ static struct nfc_hci_ops shdlc_ops = {
.target_from_gate = nfc_shdlc_target_from_gate,
.complete_target_discovered = nfc_shdlc_complete_target_discovered,
.data_exchange = nfc_shdlc_data_exchange,
+ .check_presence = nfc_shdlc_check_presence,
};
struct nfc_shdlc *nfc_shdlc_allocate(struct nfc_shdlc_ops *ops,
diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c
index 11a3b7d98dc5..bf8ae4f0b90c 100644
--- a/net/nfc/llcp/commands.c
+++ b/net/nfc/llcp/commands.c
@@ -488,7 +488,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
- skb_queue_head(&sock->tx_queue, pdu);
+ skb_queue_tail(&sock->tx_queue, pdu);
lock_sock(sk);
@@ -502,7 +502,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
kfree(msg_data);
- return 0;
+ return len;
}
int nfc_llcp_send_rr(struct nfc_llcp_sock *sock)
diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c
index 92988aa620dc..42994fac26d6 100644
--- a/net/nfc/llcp/llcp.c
+++ b/net/nfc/llcp/llcp.c
@@ -448,6 +448,8 @@ static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local,
{
struct nfc_llcp_sock *sock, *llcp_sock, *n;
+ pr_debug("ssap dsap %d %d\n", ssap, dsap);
+
if (ssap == 0 && dsap == 0)
return NULL;
@@ -783,6 +785,7 @@ static void nfc_llcp_recv_disc(struct nfc_llcp_local *local,
static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb)
{
struct nfc_llcp_sock *llcp_sock;
+ struct sock *sk;
u8 dsap, ssap;
dsap = nfc_llcp_dsap(skb);
@@ -801,10 +804,14 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb)
}
llcp_sock->dsap = ssap;
+ sk = &llcp_sock->sk;
nfc_llcp_parse_tlv(local, &skb->data[LLCP_HEADER_SIZE],
skb->len - LLCP_HEADER_SIZE);
+ sk->sk_state = LLCP_CONNECTED;
+ sk->sk_state_change(sk);
+
nfc_llcp_sock_put(llcp_sock);
}
diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c
index c13e02ebdef9..3f339b19d140 100644
--- a/net/nfc/llcp/sock.c
+++ b/net/nfc/llcp/sock.c
@@ -27,6 +27,42 @@
#include "../nfc.h"
#include "llcp.h"
+static int sock_wait_state(struct sock *sk, int state, unsigned long timeo)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ int err = 0;
+
+ pr_debug("sk %p", sk);
+
+ add_wait_queue(sk_sleep(sk), &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ while (sk->sk_state != state) {
+ if (!timeo) {
+ err = -EINPROGRESS;
+ break;
+ }
+
+ if (signal_pending(current)) {
+ err = sock_intr_errno(timeo);
+ break;
+ }
+
+ release_sock(sk);
+ timeo = schedule_timeout(timeo);
+ lock_sock(sk);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ err = sock_error(sk);
+ if (err)
+ break;
+ }
+
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(sk_sleep(sk), &wait);
+ return err;
+}
+
static struct proto llcp_sock_proto = {
.name = "NFC_LLCP",
.owner = THIS_MODULE,
@@ -304,11 +340,24 @@ static unsigned int llcp_sock_poll(struct file *file, struct socket *sock,
mask |= POLLERR;
if (!skb_queue_empty(&sk->sk_receive_queue))
- mask |= POLLIN;
+ mask |= POLLIN | POLLRDNORM;
if (sk->sk_state == LLCP_CLOSED)
mask |= POLLHUP;
+ if (sk->sk_shutdown & RCV_SHUTDOWN)
+ mask |= POLLRDHUP | POLLIN | POLLRDNORM;
+
+ if (sk->sk_shutdown == SHUTDOWN_MASK)
+ mask |= POLLHUP;
+
+ if (sock_writeable(sk))
+ mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+ else
+ set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+
+ pr_debug("mask 0x%x\n", mask);
+
return mask;
}
@@ -462,9 +511,13 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
if (ret)
goto put_dev;
- sk->sk_state = LLCP_CONNECTED;
+ ret = sock_wait_state(sk, LLCP_CONNECTED,
+ sock_sndtimeo(sk, flags & O_NONBLOCK));
+ if (ret)
+ goto put_dev;
release_sock(sk);
+
return 0;
put_dev:
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
index 8737c2089fdd..d560e6f13072 100644
--- a/net/nfc/nci/core.c
+++ b/net/nfc/nci/core.c
@@ -436,16 +436,16 @@ static void nci_stop_poll(struct nfc_dev *nfc_dev)
msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
}
-static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx,
- __u32 protocol)
+static int nci_activate_target(struct nfc_dev *nfc_dev,
+ struct nfc_target *target, __u32 protocol)
{
struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
struct nci_rf_discover_select_param param;
- struct nfc_target *target = NULL;
+ struct nfc_target *nci_target = NULL;
int i;
int rc = 0;
- pr_debug("target_idx %d, protocol 0x%x\n", target_idx, protocol);
+ pr_debug("target_idx %d, protocol 0x%x\n", target->idx, protocol);
if ((atomic_read(&ndev->state) != NCI_W4_HOST_SELECT) &&
(atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) {
@@ -459,25 +459,25 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx,
}
for (i = 0; i < ndev->n_targets; i++) {
- if (ndev->targets[i].idx == target_idx) {
- target = &ndev->targets[i];
+ if (ndev->targets[i].idx == target->idx) {
+ nci_target = &ndev->targets[i];
break;
}
}
- if (!target) {
+ if (!nci_target) {
pr_err("unable to find the selected target\n");
return -EINVAL;
}
- if (!(target->supported_protocols & (1 << protocol))) {
+ if (!(nci_target->supported_protocols & (1 << protocol))) {
pr_err("target does not support the requested protocol 0x%x\n",
protocol);
return -EINVAL;
}
if (atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) {
- param.rf_discovery_id = target->logical_idx;
+ param.rf_discovery_id = nci_target->logical_idx;
if (protocol == NFC_PROTO_JEWEL)
param.rf_protocol = NCI_RF_PROTOCOL_T1T;
@@ -501,11 +501,12 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx,
return rc;
}
-static void nci_deactivate_target(struct nfc_dev *nfc_dev, __u32 target_idx)
+static void nci_deactivate_target(struct nfc_dev *nfc_dev,
+ struct nfc_target *target)
{
struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
- pr_debug("target_idx %d\n", target_idx);
+ pr_debug("target_idx %d\n", target->idx);
if (!ndev->target_active_prot) {
pr_err("unable to deactivate target, no active target\n");
@@ -520,14 +521,14 @@ static void nci_deactivate_target(struct nfc_dev *nfc_dev, __u32 target_idx)
}
}
-static int nci_data_exchange(struct nfc_dev *nfc_dev, __u32 target_idx,
+static int nci_data_exchange(struct nfc_dev *nfc_dev, struct nfc_target *target,
struct sk_buff *skb,
data_exchange_cb_t cb, void *cb_context)
{
struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
int rc;
- pr_debug("target_idx %d, len %d\n", target_idx, skb->len);
+ pr_debug("target_idx %d, len %d\n", target->idx, skb->len);
if (!ndev->target_active_prot) {
pr_err("unable to exchange data, no active target\n");
diff --git a/net/nfc/nci/data.c b/net/nfc/nci/data.c
index a0bc326308a5..76c48c5324f8 100644
--- a/net/nfc/nci/data.c
+++ b/net/nfc/nci/data.c
@@ -49,7 +49,7 @@ void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
if (cb) {
ndev->data_exchange_cb = NULL;
- ndev->data_exchange_cb_context = 0;
+ ndev->data_exchange_cb_context = NULL;
/* forward skb to nfc core */
cb(cb_context, skb, err);
@@ -200,10 +200,10 @@ static void nci_add_rx_data_frag(struct nci_dev *ndev,
pr_err("error adding room for accumulated rx data\n");
kfree_skb(skb);
- skb = 0;
+ skb = NULL;
kfree_skb(ndev->rx_data_reassembly);
- ndev->rx_data_reassembly = 0;
+ ndev->rx_data_reassembly = NULL;
err = -ENOMEM;
goto exit;
@@ -216,7 +216,7 @@ static void nci_add_rx_data_frag(struct nci_dev *ndev,
/* third, free old reassembly */
kfree_skb(ndev->rx_data_reassembly);
- ndev->rx_data_reassembly = 0;
+ ndev->rx_data_reassembly = NULL;
}
if (pbf == NCI_PBF_CONT) {
diff --git a/net/nfc/nci/lib.c b/net/nfc/nci/lib.c
index 6a63e5eb483d..6b7fd26c68d9 100644
--- a/net/nfc/nci/lib.c
+++ b/net/nfc/nci/lib.c
@@ -31,6 +31,7 @@
#include <linux/errno.h>
#include <net/nfc/nci.h>
+#include <net/nfc/nci_core.h>
/* NCI status codes to Unix errno mapping */
int nci_to_errno(__u8 code)
diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c
index 99e1632e6aac..cb2646179e5f 100644
--- a/net/nfc/nci/ntf.c
+++ b/net/nfc/nci/ntf.c
@@ -497,7 +497,7 @@ static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev,
/* drop partial rx data packet */
if (ndev->rx_data_reassembly) {
kfree_skb(ndev->rx_data_reassembly);
- ndev->rx_data_reassembly = 0;
+ ndev->rx_data_reassembly = NULL;
}
/* complete the data exchange transaction, if exists */
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
index f1829f6ae9c5..581d419083aa 100644
--- a/net/nfc/netlink.c
+++ b/net/nfc/netlink.c
@@ -33,7 +33,7 @@ static struct genl_multicast_group nfc_genl_event_mcgrp = {
.name = NFC_GENL_MCAST_EVENT_NAME,
};
-struct genl_family nfc_genl_family = {
+static struct genl_family nfc_genl_family = {
.id = GENL_ID_GENERATE,
.hdrsize = 0,
.name = NFC_GENL_NAME,
@@ -128,7 +128,7 @@ static int nfc_genl_dump_targets(struct sk_buff *skb,
cb->args[1] = (long) dev;
}
- spin_lock_bh(&dev->targets_lock);
+ device_lock(&dev->dev);
cb->seq = dev->targets_generation;
@@ -141,7 +141,7 @@ static int nfc_genl_dump_targets(struct sk_buff *skb,
i++;
}
- spin_unlock_bh(&dev->targets_lock);
+ device_unlock(&dev->dev);
cb->args[0] = i;
diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h
index 7d589a81942e..3dd4232ae664 100644
--- a/net/nfc/nfc.h
+++ b/net/nfc/nfc.h
@@ -84,7 +84,7 @@ static inline int nfc_llcp_set_remote_gb(struct nfc_dev *dev,
return 0;
}
-static inline u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, u8 *gb_len)
+static inline u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *gb_len)
{
*gb_len = 0;
return NULL;
diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c
index 1afaa284fcd7..7743ea8d1d38 100644
--- a/net/sched/cls_cgroup.c
+++ b/net/sched/cls_cgroup.c
@@ -22,22 +22,6 @@
#include <net/sock.h>
#include <net/cls_cgroup.h>
-static struct cgroup_subsys_state *cgrp_create(struct cgroup *cgrp);
-static void cgrp_destroy(struct cgroup *cgrp);
-static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp);
-
-struct cgroup_subsys net_cls_subsys = {
- .name = "net_cls",
- .create = cgrp_create,
- .destroy = cgrp_destroy,
- .populate = cgrp_populate,
-#ifdef CONFIG_NET_CLS_CGROUP
- .subsys_id = net_cls_subsys_id,
-#endif
- .module = THIS_MODULE,
-};
-
-
static inline struct cgroup_cls_state *cgrp_cls_state(struct cgroup *cgrp)
{
return container_of(cgroup_subsys_state(cgrp, net_cls_subsys_id),
@@ -86,12 +70,19 @@ static struct cftype ss_files[] = {
.read_u64 = read_classid,
.write_u64 = write_classid,
},
+ { } /* terminate */
};
-static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp)
-{
- return cgroup_add_files(cgrp, ss, ss_files, ARRAY_SIZE(ss_files));
-}
+struct cgroup_subsys net_cls_subsys = {
+ .name = "net_cls",
+ .create = cgrp_create,
+ .destroy = cgrp_destroy,
+#ifdef CONFIG_NET_CLS_CGROUP
+ .subsys_id = net_cls_subsys_id,
+#endif
+ .base_cftypes = ss_files,
+ .module = THIS_MODULE,
+};
struct cls_cgroup_head {
u32 handle;
diff --git a/net/socket.c b/net/socket.c
index 2a2898ce596e..6e0ccc09b313 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -479,7 +479,7 @@ static struct socket *sock_alloc(void)
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
- percpu_add(sockets_in_use, 1);
+ this_cpu_add(sockets_in_use, 1);
return sock;
}
@@ -522,7 +522,7 @@ void sock_release(struct socket *sock)
if (rcu_dereference_protected(sock->wq, 1)->fasync_list)
printk(KERN_ERR "sock_release: fasync list not empty!\n");
- percpu_sub(sockets_in_use, 1);
+ this_cpu_sub(sockets_in_use, 1);
if (!sock->file) {
iput(SOCK_INODE(sock));
return;
diff --git a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c
index 75762f346975..6ed6f201b022 100644
--- a/net/sunrpc/auth_generic.c
+++ b/net/sunrpc/auth_generic.c
@@ -160,8 +160,8 @@ generic_match(struct auth_cred *acred, struct rpc_cred *cred, int flags)
if (gcred->acred.group_info->ngroups != acred->group_info->ngroups)
goto out_nomatch;
for (i = 0; i < gcred->acred.group_info->ngroups; i++) {
- if (GROUP_AT(gcred->acred.group_info, i) !=
- GROUP_AT(acred->group_info, i))
+ if (!gid_eq(GROUP_AT(gcred->acred.group_info, i),
+ GROUP_AT(acred->group_info, i)))
goto out_nomatch;
}
out_match:
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 1600cfb1618c..28b62dbb6d1e 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -41,6 +41,7 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/pagemap.h>
+#include <linux/user_namespace.h>
#include <linux/sunrpc/auth_gss.h>
#include <linux/sunrpc/gss_err.h>
@@ -470,9 +471,13 @@ static int rsc_parse(struct cache_detail *cd,
status = -EINVAL;
for (i=0; i<N; i++) {
gid_t gid;
+ kgid_t kgid;
if (get_int(&mesg, &gid))
goto out;
- GROUP_AT(rsci.cred.cr_group_info, i) = gid;
+ kgid = make_kgid(&init_user_ns, gid);
+ if (!gid_valid(kgid))
+ goto out;
+ GROUP_AT(rsci.cred.cr_group_info, i) = kgid;
}
/* mech name */
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
index e50502d8ceb7..52c5abdee211 100644
--- a/net/sunrpc/auth_unix.c
+++ b/net/sunrpc/auth_unix.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/auth.h>
+#include <linux/user_namespace.h>
#define NFS_NGROUPS 16
@@ -78,8 +79,11 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
groups = NFS_NGROUPS;
cred->uc_gid = acred->gid;
- for (i = 0; i < groups; i++)
- cred->uc_gids[i] = GROUP_AT(acred->group_info, i);
+ for (i = 0; i < groups; i++) {
+ gid_t gid;
+ gid = from_kgid(&init_user_ns, GROUP_AT(acred->group_info, i));
+ cred->uc_gids[i] = gid;
+ }
if (i < NFS_NGROUPS)
cred->uc_gids[i] = NOGROUP;
@@ -126,9 +130,12 @@ unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags)
groups = acred->group_info->ngroups;
if (groups > NFS_NGROUPS)
groups = NFS_NGROUPS;
- for (i = 0; i < groups ; i++)
- if (cred->uc_gids[i] != GROUP_AT(acred->group_info, i))
+ for (i = 0; i < groups ; i++) {
+ gid_t gid;
+ gid = from_kgid(&init_user_ns, GROUP_AT(acred->group_info, i));
+ if (cred->uc_gids[i] != gid)
return 0;
+ }
if (groups < NFS_NGROUPS &&
cred->uc_gids[groups] != NOGROUP)
return 0;
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 521d8f7dc833..71ec8530ec8c 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -14,6 +14,7 @@
#include <net/sock.h>
#include <net/ipv6.h>
#include <linux/kernel.h>
+#include <linux/user_namespace.h>
#define RPCDBG_FACILITY RPCDBG_AUTH
#include <linux/sunrpc/clnt.h>
@@ -530,11 +531,15 @@ static int unix_gid_parse(struct cache_detail *cd,
for (i = 0 ; i < gids ; i++) {
int gid;
+ kgid_t kgid;
rv = get_int(&mesg, &gid);
err = -EINVAL;
if (rv)
goto out;
- GROUP_AT(ug.gi, i) = gid;
+ kgid = make_kgid(&init_user_ns, gid);
+ if (!gid_valid(kgid))
+ goto out;
+ GROUP_AT(ug.gi, i) = kgid;
}
ugp = unix_gid_lookup(cd, uid);
@@ -563,6 +568,7 @@ static int unix_gid_show(struct seq_file *m,
struct cache_detail *cd,
struct cache_head *h)
{
+ struct user_namespace *user_ns = current_user_ns();
struct unix_gid *ug;
int i;
int glen;
@@ -580,7 +586,7 @@ static int unix_gid_show(struct seq_file *m,
seq_printf(m, "%u %d:", ug->uid, glen);
for (i = 0; i < glen; i++)
- seq_printf(m, " %d", GROUP_AT(ug->gi, i));
+ seq_printf(m, " %d", from_kgid_munged(user_ns, GROUP_AT(ug->gi, i)));
seq_printf(m, "\n");
return 0;
}
@@ -831,8 +837,12 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
cred->cr_group_info = groups_alloc(slen);
if (cred->cr_group_info == NULL)
return SVC_CLOSE;
- for (i = 0; i < slen; i++)
- GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv);
+ for (i = 0; i < slen; i++) {
+ kgid_t kgid = make_kgid(&init_user_ns, svc_getnl(argv));
+ if (!gid_valid(kgid))
+ goto badcred;
+ GROUP_AT(cred->cr_group_info, i) = kgid;
+ }
if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
*authp = rpc_autherr_badverf;
return SVC_DENIED;
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 2fcfe0993ca2..884801ac4dd0 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -45,7 +45,7 @@ rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
return chan;
}
-int cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
+bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type)
{
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 39f2538a46fc..a87d43552974 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -664,7 +664,7 @@ void wiphy_unregister(struct wiphy *wiphy)
mutex_lock(&rdev->devlist_mtx);
__count = rdev->opencount;
mutex_unlock(&rdev->devlist_mtx);
- __count == 0;}));
+ __count == 0; }));
mutex_lock(&rdev->devlist_mtx);
BUG_ON(!list_empty(&rdev->netdev_list));
@@ -776,7 +776,7 @@ static struct device_type wiphy_type = {
.name = "wlan",
};
-static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
+static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
unsigned long state,
void *ndev)
{
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 3ac2dd00d714..8523f3878677 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -445,8 +445,6 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev, int freq,
enum nl80211_channel_type channel_type);
-u16 cfg80211_calculate_bitrate(struct rate_info *rate);
-
int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
const u8 *rates, unsigned int n_rates,
u32 *mask);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index b67b1114e25a..206465dc0cab 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1179,6 +1179,27 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
wdev->iftype == NL80211_IFTYPE_P2P_GO;
}
+static bool nl80211_valid_channel_type(struct genl_info *info,
+ enum nl80211_channel_type *channel_type)
+{
+ enum nl80211_channel_type tmp;
+
+ if (!info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
+ return false;
+
+ tmp = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+ if (tmp != NL80211_CHAN_NO_HT &&
+ tmp != NL80211_CHAN_HT20 &&
+ tmp != NL80211_CHAN_HT40PLUS &&
+ tmp != NL80211_CHAN_HT40MINUS)
+ return false;
+
+ if (channel_type)
+ *channel_type = tmp;
+
+ return true;
+}
+
static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
struct genl_info *info)
@@ -1193,15 +1214,9 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
if (!nl80211_can_set_dev_channel(wdev))
return -EOPNOTSUPP;
- if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
- channel_type = nla_get_u32(info->attrs[
- NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
- if (channel_type != NL80211_CHAN_NO_HT &&
- channel_type != NL80211_CHAN_HT20 &&
- channel_type != NL80211_CHAN_HT40PLUS &&
- channel_type != NL80211_CHAN_HT40MINUS)
- return -EINVAL;
- }
+ if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
+ !nl80211_valid_channel_type(info, &channel_type))
+ return -EINVAL;
freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
@@ -2410,10 +2425,16 @@ static int parse_station_flags(struct genl_info *info,
return -EINVAL;
}
- for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++)
- if (flags[flag])
+ for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) {
+ if (flags[flag]) {
params->sta_flags_set |= (1<<flag);
+ /* no longer support new API additions in old API */
+ if (flag > NL80211_STA_FLAG_MAX_OLD_API)
+ return -EINVAL;
+ }
+ }
+
return 0;
}
@@ -4912,12 +4933,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
enum nl80211_channel_type channel_type;
- channel_type = nla_get_u32(
- info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
- if (channel_type != NL80211_CHAN_NO_HT &&
- channel_type != NL80211_CHAN_HT20 &&
- channel_type != NL80211_CHAN_HT40MINUS &&
- channel_type != NL80211_CHAN_HT40PLUS)
+ if (!nl80211_valid_channel_type(info, &channel_type))
return -EINVAL;
if (channel_type != NL80211_CHAN_NO_HT &&
@@ -5485,15 +5501,9 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
!(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL))
return -EOPNOTSUPP;
- if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
- channel_type = nla_get_u32(
- info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
- if (channel_type != NL80211_CHAN_NO_HT &&
- channel_type != NL80211_CHAN_HT20 &&
- channel_type != NL80211_CHAN_HT40PLUS &&
- channel_type != NL80211_CHAN_HT40MINUS)
- return -EINVAL;
- }
+ if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
+ !nl80211_valid_channel_type(info, &channel_type))
+ return -EINVAL;
freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
chan = rdev_freq_to_chan(rdev, freq, channel_type);
@@ -5764,12 +5774,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
}
if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
- channel_type = nla_get_u32(
- info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
- if (channel_type != NL80211_CHAN_NO_HT &&
- channel_type != NL80211_CHAN_HT20 &&
- channel_type != NL80211_CHAN_HT40PLUS &&
- channel_type != NL80211_CHAN_HT40MINUS)
+ if (!nl80211_valid_channel_type(info, &channel_type))
return -EINVAL;
channel_type_valid = true;
}
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 1cd255892a43..55d99466babb 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -879,7 +879,7 @@ u16 cfg80211_calculate_bitrate(struct rate_info *rate)
return rate->legacy;
/* the formula below does only work for MCS values smaller than 32 */
- if (rate->mcs >= 32)
+ if (WARN_ON_ONCE(rate->mcs >= 32))
return 0;
modulation = rate->mcs & 7;
diff --git a/scripts/.gitignore b/scripts/.gitignore
index 105b21f08185..65f362d931b5 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -9,3 +9,4 @@ unifdef
ihex2fw
recordmcount
docproc
+sortextable
diff --git a/scripts/Makefile b/scripts/Makefile
index 36266665dbcb..a55b0067758a 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -15,6 +15,9 @@ hostprogs-$(CONFIG_LOGO) += pnmtologo
hostprogs-$(CONFIG_VT) += conmakehash
hostprogs-$(CONFIG_IKCONFIG) += bin2c
hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
+hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable
+
+HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include
always := $(hostprogs-y) $(hostprogs-m)
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index 2c6286c0bc1a..f606738d421d 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -240,7 +240,7 @@ search_help[] = N_(
"Defined at drivers/pci/Kconfig:47\n"
"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
"Location:\n"
- " -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
+ " -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
" -> PCI support (PCI [=y])\n"
" -> PCI access mode (<choice> [=y])\n"
"Selects: LIBCRC32\n"
diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c
index 73070cb0b6de..8c0eb65978c9 100644
--- a/scripts/kconfig/nconf.c
+++ b/scripts/kconfig/nconf.c
@@ -223,7 +223,7 @@ search_help[] = N_(
"Defined at drivers/pci/Kconfig:47\n"
"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
"Location:\n"
-" -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
+" -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
" -> PCI support (PCI [ = y])\n"
" -> PCI access mode (<choice> [ = y])\n"
"Selects: LIBCRC32\n"
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 44ddaa542db6..5759751a1f61 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -336,10 +336,13 @@ static int do_hid_entry(const char *filename,
struct hid_device_id *id, char *alias)
{
id->bus = TO_NATIVE(id->bus);
+ id->group = TO_NATIVE(id->group);
id->vendor = TO_NATIVE(id->vendor);
id->product = TO_NATIVE(id->product);
- sprintf(alias, "hid:b%04X", id->bus);
+ sprintf(alias, "hid:");
+ ADD(alias, "b", id->bus != HID_BUS_ANY, id->bus);
+ ADD(alias, "g", id->group != HID_GROUP_ANY, id->group);
ADD(alias, "v", id->vendor != HID_ANY_ID, id->vendor);
ADD(alias, "p", id->product != HID_ANY_ID, id->product);
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index c4e7d1510f9d..0f84bb38eb0d 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -337,17 +337,20 @@ static void sym_update_crc(const char *name, struct module *mod,
void *grab_file(const char *filename, unsigned long *size)
{
struct stat st;
- void *map;
+ void *map = MAP_FAILED;
int fd;
fd = open(filename, O_RDONLY);
- if (fd < 0 || fstat(fd, &st) != 0)
+ if (fd < 0)
return NULL;
+ if (fstat(fd, &st))
+ goto failed;
*size = st.st_size;
map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
- close(fd);
+failed:
+ close(fd);
if (map == MAP_FAILED)
return NULL;
return map;
@@ -1850,14 +1853,14 @@ static void add_header(struct buffer *b, struct module *mod)
buf_printf(b, "\n");
buf_printf(b, "struct module __this_module\n");
buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");
- buf_printf(b, " .name = KBUILD_MODNAME,\n");
+ buf_printf(b, "\t.name = KBUILD_MODNAME,\n");
if (mod->has_init)
- buf_printf(b, " .init = init_module,\n");
+ buf_printf(b, "\t.init = init_module,\n");
if (mod->has_cleanup)
buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n"
- " .exit = cleanup_module,\n"
+ "\t.exit = cleanup_module,\n"
"#endif\n");
- buf_printf(b, " .arch = MODULE_ARCH_INIT,\n");
+ buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n");
buf_printf(b, "};\n");
}
diff --git a/scripts/sortextable.c b/scripts/sortextable.c
new file mode 100644
index 000000000000..1ca9ceb95eb6
--- /dev/null
+++ b/scripts/sortextable.c
@@ -0,0 +1,322 @@
+/*
+ * sortextable.c: Sort the kernel's exception table
+ *
+ * Copyright 2011 - 2012 Cavium, Inc.
+ *
+ * Based on code taken from recortmcount.c which is:
+ *
+ * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved.
+ * Licensed under the GNU General Public License, version 2 (GPLv2).
+ *
+ * Restructured to fit Linux format, as well as other updates:
+ * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
+ */
+
+/*
+ * Strategy: alter the vmlinux file in-place.
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <getopt.h>
+#include <elf.h>
+#include <fcntl.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <tools/be_byteshift.h>
+#include <tools/le_byteshift.h>
+
+static int fd_map; /* File descriptor for file being modified. */
+static int mmap_failed; /* Boolean flag. */
+static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */
+static struct stat sb; /* Remember .st_size, etc. */
+static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */
+
+/* setjmp() return values */
+enum {
+ SJ_SETJMP = 0, /* hardwired first return */
+ SJ_FAIL,
+ SJ_SUCCEED
+};
+
+/* Per-file resource cleanup when multiple files. */
+static void
+cleanup(void)
+{
+ if (!mmap_failed)
+ munmap(ehdr_curr, sb.st_size);
+ close(fd_map);
+}
+
+static void __attribute__((noreturn))
+fail_file(void)
+{
+ cleanup();
+ longjmp(jmpenv, SJ_FAIL);
+}
+
+static void __attribute__((noreturn))
+succeed_file(void)
+{
+ cleanup();
+ longjmp(jmpenv, SJ_SUCCEED);
+}
+
+
+/*
+ * Get the whole file as a programming convenience in order to avoid
+ * malloc+lseek+read+free of many pieces. If successful, then mmap
+ * avoids copying unused pieces; else just read the whole file.
+ * Open for both read and write.
+ */
+static void *mmap_file(char const *fname)
+{
+ void *addr;
+
+ fd_map = open(fname, O_RDWR);
+ if (fd_map < 0 || fstat(fd_map, &sb) < 0) {
+ perror(fname);
+ fail_file();
+ }
+ if (!S_ISREG(sb.st_mode)) {
+ fprintf(stderr, "not a regular file: %s\n", fname);
+ fail_file();
+ }
+ addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED,
+ fd_map, 0);
+ if (addr == MAP_FAILED) {
+ mmap_failed = 1;
+ fprintf(stderr, "Could not mmap file: %s\n", fname);
+ fail_file();
+ }
+ return addr;
+}
+
+static uint64_t r8be(const uint64_t *x)
+{
+ return get_unaligned_be64(x);
+}
+static uint32_t rbe(const uint32_t *x)
+{
+ return get_unaligned_be32(x);
+}
+static uint16_t r2be(const uint16_t *x)
+{
+ return get_unaligned_be16(x);
+}
+static uint64_t r8le(const uint64_t *x)
+{
+ return get_unaligned_le64(x);
+}
+static uint32_t rle(const uint32_t *x)
+{
+ return get_unaligned_le32(x);
+}
+static uint16_t r2le(const uint16_t *x)
+{
+ return get_unaligned_le16(x);
+}
+
+static void w8be(uint64_t val, uint64_t *x)
+{
+ put_unaligned_be64(val, x);
+}
+static void wbe(uint32_t val, uint32_t *x)
+{
+ put_unaligned_be32(val, x);
+}
+static void w2be(uint16_t val, uint16_t *x)
+{
+ put_unaligned_be16(val, x);
+}
+static void w8le(uint64_t val, uint64_t *x)
+{
+ put_unaligned_le64(val, x);
+}
+static void wle(uint32_t val, uint32_t *x)
+{
+ put_unaligned_le32(val, x);
+}
+static void w2le(uint16_t val, uint16_t *x)
+{
+ put_unaligned_le16(val, x);
+}
+
+static uint64_t (*r8)(const uint64_t *);
+static uint32_t (*r)(const uint32_t *);
+static uint16_t (*r2)(const uint16_t *);
+static void (*w8)(uint64_t, uint64_t *);
+static void (*w)(uint32_t, uint32_t *);
+static void (*w2)(uint16_t, uint16_t *);
+
+typedef void (*table_sort_t)(char *, int);
+
+/* 32 bit and 64 bit are very similar */
+#include "sortextable.h"
+#define SORTEXTABLE_64
+#include "sortextable.h"
+
+static int compare_x86_table(const void *a, const void *b)
+{
+ int32_t av = (int32_t)r(a);
+ int32_t bv = (int32_t)r(b);
+
+ if (av < bv)
+ return -1;
+ if (av > bv)
+ return 1;
+ return 0;
+}
+
+static void sort_x86_table(char *extab_image, int image_size)
+{
+ int i;
+
+ /*
+ * Do the same thing the runtime sort does, first normalize to
+ * being relative to the start of the section.
+ */
+ i = 0;
+ while (i < image_size) {
+ uint32_t *loc = (uint32_t *)(extab_image + i);
+ w(r(loc) + i, loc);
+ i += 4;
+ }
+
+ qsort(extab_image, image_size / 8, 8, compare_x86_table);
+
+ /* Now denormalize. */
+ i = 0;
+ while (i < image_size) {
+ uint32_t *loc = (uint32_t *)(extab_image + i);
+ w(r(loc) - i, loc);
+ i += 4;
+ }
+}
+
+static void
+do_file(char const *const fname)
+{
+ table_sort_t custom_sort;
+ Elf32_Ehdr *ehdr = mmap_file(fname);
+
+ ehdr_curr = ehdr;
+ switch (ehdr->e_ident[EI_DATA]) {
+ default:
+ fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
+ ehdr->e_ident[EI_DATA], fname);
+ fail_file();
+ break;
+ case ELFDATA2LSB:
+ r = rle;
+ r2 = r2le;
+ r8 = r8le;
+ w = wle;
+ w2 = w2le;
+ w8 = w8le;
+ break;
+ case ELFDATA2MSB:
+ r = rbe;
+ r2 = r2be;
+ r8 = r8be;
+ w = wbe;
+ w2 = w2be;
+ w8 = w8be;
+ break;
+ } /* end switch */
+ if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0
+ || r2(&ehdr->e_type) != ET_EXEC
+ || ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
+ fprintf(stderr, "unrecognized ET_EXEC file %s\n", fname);
+ fail_file();
+ }
+
+ custom_sort = NULL;
+ switch (r2(&ehdr->e_machine)) {
+ default:
+ fprintf(stderr, "unrecognized e_machine %d %s\n",
+ r2(&ehdr->e_machine), fname);
+ fail_file();
+ break;
+ case EM_386:
+ case EM_X86_64:
+ custom_sort = sort_x86_table;
+ break;
+ case EM_MIPS:
+ break;
+ } /* end switch */
+
+ switch (ehdr->e_ident[EI_CLASS]) {
+ default:
+ fprintf(stderr, "unrecognized ELF class %d %s\n",
+ ehdr->e_ident[EI_CLASS], fname);
+ fail_file();
+ break;
+ case ELFCLASS32:
+ if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr)
+ || r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) {
+ fprintf(stderr,
+ "unrecognized ET_EXEC file: %s\n", fname);
+ fail_file();
+ }
+ do32(ehdr, fname, custom_sort);
+ break;
+ case ELFCLASS64: {
+ Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr;
+ if (r2(&ghdr->e_ehsize) != sizeof(Elf64_Ehdr)
+ || r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) {
+ fprintf(stderr,
+ "unrecognized ET_EXEC file: %s\n", fname);
+ fail_file();
+ }
+ do64(ghdr, fname, custom_sort);
+ break;
+ }
+ } /* end switch */
+
+ cleanup();
+}
+
+int
+main(int argc, char *argv[])
+{
+ int n_error = 0; /* gcc-4.3.0 false positive complaint */
+ int i;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: sortextable vmlinux...\n");
+ return 0;
+ }
+
+ /* Process each file in turn, allowing deep failure. */
+ for (i = 1; i < argc; i++) {
+ char *file = argv[i];
+ int const sjval = setjmp(jmpenv);
+
+ switch (sjval) {
+ default:
+ fprintf(stderr, "internal error: %s\n", file);
+ exit(1);
+ break;
+ case SJ_SETJMP: /* normal sequence */
+ /* Avoid problems if early cleanup() */
+ fd_map = -1;
+ ehdr_curr = NULL;
+ mmap_failed = 1;
+ do_file(file);
+ break;
+ case SJ_FAIL: /* error in do_file or below */
+ ++n_error;
+ break;
+ case SJ_SUCCEED: /* premature success */
+ /* do nothing */
+ break;
+ } /* end switch */
+ }
+ return !!n_error;
+}
diff --git a/scripts/sortextable.h b/scripts/sortextable.h
new file mode 100644
index 000000000000..e4fd45b7e456
--- /dev/null
+++ b/scripts/sortextable.h
@@ -0,0 +1,191 @@
+/*
+ * sortextable.h
+ *
+ * Copyright 2011 - 2012 Cavium, Inc.
+ *
+ * Some of this code was taken out of recordmcount.h written by:
+ *
+ * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved.
+ * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
+ *
+ *
+ * Licensed under the GNU General Public License, version 2 (GPLv2).
+ */
+
+#undef extable_ent_size
+#undef compare_extable
+#undef do_func
+#undef Elf_Addr
+#undef Elf_Ehdr
+#undef Elf_Shdr
+#undef Elf_Rel
+#undef Elf_Rela
+#undef Elf_Sym
+#undef ELF_R_SYM
+#undef Elf_r_sym
+#undef ELF_R_INFO
+#undef Elf_r_info
+#undef ELF_ST_BIND
+#undef ELF_ST_TYPE
+#undef fn_ELF_R_SYM
+#undef fn_ELF_R_INFO
+#undef uint_t
+#undef _r
+#undef _w
+
+#ifdef SORTEXTABLE_64
+# define extable_ent_size 16
+# define compare_extable compare_extable_64
+# define do_func do64
+# define Elf_Addr Elf64_Addr
+# define Elf_Ehdr Elf64_Ehdr
+# define Elf_Shdr Elf64_Shdr
+# define Elf_Rel Elf64_Rel
+# define Elf_Rela Elf64_Rela
+# define Elf_Sym Elf64_Sym
+# define ELF_R_SYM ELF64_R_SYM
+# define Elf_r_sym Elf64_r_sym
+# define ELF_R_INFO ELF64_R_INFO
+# define Elf_r_info Elf64_r_info
+# define ELF_ST_BIND ELF64_ST_BIND
+# define ELF_ST_TYPE ELF64_ST_TYPE
+# define fn_ELF_R_SYM fn_ELF64_R_SYM
+# define fn_ELF_R_INFO fn_ELF64_R_INFO
+# define uint_t uint64_t
+# define _r r8
+# define _w w8
+#else
+# define extable_ent_size 8
+# define compare_extable compare_extable_32
+# define do_func do32
+# define Elf_Addr Elf32_Addr
+# define Elf_Ehdr Elf32_Ehdr
+# define Elf_Shdr Elf32_Shdr
+# define Elf_Rel Elf32_Rel
+# define Elf_Rela Elf32_Rela
+# define Elf_Sym Elf32_Sym
+# define ELF_R_SYM ELF32_R_SYM
+# define Elf_r_sym Elf32_r_sym
+# define ELF_R_INFO ELF32_R_INFO
+# define Elf_r_info Elf32_r_info
+# define ELF_ST_BIND ELF32_ST_BIND
+# define ELF_ST_TYPE ELF32_ST_TYPE
+# define fn_ELF_R_SYM fn_ELF32_R_SYM
+# define fn_ELF_R_INFO fn_ELF32_R_INFO
+# define uint_t uint32_t
+# define _r r
+# define _w w
+#endif
+
+static int compare_extable(const void *a, const void *b)
+{
+ Elf_Addr av = _r(a);
+ Elf_Addr bv = _r(b);
+
+ if (av < bv)
+ return -1;
+ if (av > bv)
+ return 1;
+ return 0;
+}
+
+static void
+do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort)
+{
+ Elf_Shdr *shdr;
+ Elf_Shdr *shstrtab_sec;
+ Elf_Shdr *strtab_sec = NULL;
+ Elf_Shdr *symtab_sec = NULL;
+ Elf_Shdr *extab_sec = NULL;
+ Elf_Sym *sym;
+ Elf_Sym *sort_needed_sym;
+ Elf_Shdr *sort_needed_sec;
+ Elf_Rel *relocs = NULL;
+ int relocs_size;
+ uint32_t *sort_done_location;
+ const char *secstrtab;
+ const char *strtab;
+ char *extab_image;
+ int extab_index = 0;
+ int i;
+ int idx;
+
+ shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff));
+ shstrtab_sec = shdr + r2(&ehdr->e_shstrndx);
+ secstrtab = (const char *)ehdr + _r(&shstrtab_sec->sh_offset);
+ for (i = 0; i < r2(&ehdr->e_shnum); i++) {
+ idx = r(&shdr[i].sh_name);
+ if (strcmp(secstrtab + idx, "__ex_table") == 0) {
+ extab_sec = shdr + i;
+ extab_index = i;
+ }
+ if ((r(&shdr[i].sh_type) == SHT_REL ||
+ r(&shdr[i].sh_type) == SHT_RELA) &&
+ r(&shdr[i].sh_info) == extab_index) {
+ relocs = (void *)ehdr + _r(&shdr[i].sh_offset);
+ relocs_size = _r(&shdr[i].sh_size);
+ }
+ if (strcmp(secstrtab + idx, ".symtab") == 0)
+ symtab_sec = shdr + i;
+ if (strcmp(secstrtab + idx, ".strtab") == 0)
+ strtab_sec = shdr + i;
+ }
+ if (strtab_sec == NULL) {
+ fprintf(stderr, "no .strtab in file: %s\n", fname);
+ fail_file();
+ }
+ if (symtab_sec == NULL) {
+ fprintf(stderr, "no .symtab in file: %s\n", fname);
+ fail_file();
+ }
+ if (extab_sec == NULL) {
+ fprintf(stderr, "no __ex_table in file: %s\n", fname);
+ fail_file();
+ }
+ strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset);
+
+ extab_image = (void *)ehdr + _r(&extab_sec->sh_offset);
+
+ if (custom_sort) {
+ custom_sort(extab_image, _r(&extab_sec->sh_size));
+ } else {
+ int num_entries = _r(&extab_sec->sh_size) / extable_ent_size;
+ qsort(extab_image, num_entries,
+ extable_ent_size, compare_extable);
+ }
+ /* If there were relocations, we no longer need them. */
+ if (relocs)
+ memset(relocs, 0, relocs_size);
+
+ /* find main_extable_sort_needed */
+ sort_needed_sym = NULL;
+ for (i = 0; i < _r(&symtab_sec->sh_size) / sizeof(Elf_Sym); i++) {
+ sym = (void *)ehdr + _r(&symtab_sec->sh_offset);
+ sym += i;
+ if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT)
+ continue;
+ idx = r(&sym->st_name);
+ if (strcmp(strtab + idx, "main_extable_sort_needed") == 0) {
+ sort_needed_sym = sym;
+ break;
+ }
+ }
+ if (sort_needed_sym == NULL) {
+ fprintf(stderr,
+ "no main_extable_sort_needed symbol in file: %s\n",
+ fname);
+ fail_file();
+ }
+ sort_needed_sec = &shdr[r2(&sort_needed_sym->st_shndx)];
+ sort_done_location = (void *)ehdr +
+ _r(&sort_needed_sec->sh_offset) +
+ _r(&sort_needed_sym->st_value) -
+ _r(&sort_needed_sec->sh_addr);
+
+#if 1
+ printf("sort done marker at %lx\n",
+ (unsigned long)((char *)sort_done_location - (char *)ehdr));
+#endif
+ /* We sorted it, clear the flag. */
+ w(0, sort_done_location);
+}
diff --git a/security/commoncap.c b/security/commoncap.c
index f80d11609391..e771cb1b2d79 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -77,12 +77,12 @@ int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
int cap, int audit)
{
for (;;) {
- /* The creator of the user namespace has all caps. */
- if (targ_ns != &init_user_ns && targ_ns->creator == cred->user)
+ /* The owner of the user namespace has all caps. */
+ if (targ_ns != &init_user_ns && uid_eq(targ_ns->owner, cred->euid))
return 0;
/* Do we have the necessary capabilities? */
- if (targ_ns == cred->user->user_ns)
+ if (targ_ns == cred->user_ns)
return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM;
/* Have we tried all of the parent namespaces? */
@@ -93,7 +93,7 @@ int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
*If you have a capability in a parent user ns, then you have
* it over all children user namespaces as well.
*/
- targ_ns = targ_ns->creator->user_ns;
+ targ_ns = targ_ns->parent;
}
/* We never get here */
@@ -137,10 +137,10 @@ int cap_ptrace_access_check(struct task_struct *child, unsigned int mode)
rcu_read_lock();
cred = current_cred();
child_cred = __task_cred(child);
- if (cred->user->user_ns == child_cred->user->user_ns &&
+ if (cred->user_ns == child_cred->user_ns &&
cap_issubset(child_cred->cap_permitted, cred->cap_permitted))
goto out;
- if (ns_capable(child_cred->user->user_ns, CAP_SYS_PTRACE))
+ if (ns_capable(child_cred->user_ns, CAP_SYS_PTRACE))
goto out;
ret = -EPERM;
out:
@@ -169,10 +169,10 @@ int cap_ptrace_traceme(struct task_struct *parent)
rcu_read_lock();
cred = __task_cred(parent);
child_cred = current_cred();
- if (cred->user->user_ns == child_cred->user->user_ns &&
+ if (cred->user_ns == child_cred->user_ns &&
cap_issubset(child_cred->cap_permitted, cred->cap_permitted))
goto out;
- if (has_ns_capability(parent, child_cred->user->user_ns, CAP_SYS_PTRACE))
+ if (has_ns_capability(parent, child_cred->user_ns, CAP_SYS_PTRACE))
goto out;
ret = -EPERM;
out:
@@ -215,7 +215,7 @@ static inline int cap_inh_is_capped(void)
/* they are so limited unless the current task has the CAP_SETPCAP
* capability
*/
- if (cap_capable(current_cred(), current_cred()->user->user_ns,
+ if (cap_capable(current_cred(), current_cred()->user_ns,
CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0)
return 0;
return 1;
@@ -473,19 +473,22 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
struct cred *new = bprm->cred;
bool effective, has_cap = false;
int ret;
+ kuid_t root_uid;
effective = false;
ret = get_file_caps(bprm, &effective, &has_cap);
if (ret < 0)
return ret;
+ root_uid = make_kuid(new->user_ns, 0);
+
if (!issecure(SECURE_NOROOT)) {
/*
* If the legacy file capability is set, then don't set privs
* for a setuid root binary run by a non-root user. Do set it
* for a root user just to cause least surprise to an admin.
*/
- if (has_cap && new->uid != 0 && new->euid == 0) {
+ if (has_cap && !uid_eq(new->uid, root_uid) && uid_eq(new->euid, root_uid)) {
warn_setuid_and_fcaps_mixed(bprm->filename);
goto skip;
}
@@ -496,12 +499,12 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
*
* If only the real uid is 0, we do not set the effective bit.
*/
- if (new->euid == 0 || new->uid == 0) {
+ if (uid_eq(new->euid, root_uid) || uid_eq(new->uid, root_uid)) {
/* pP' = (cap_bset & ~0) | (pI & ~0) */
new->cap_permitted = cap_combine(old->cap_bset,
old->cap_inheritable);
}
- if (new->euid == 0)
+ if (uid_eq(new->euid, root_uid))
effective = true;
}
skip:
@@ -516,8 +519,8 @@ skip:
*
* In addition, if NO_NEW_PRIVS, then ensure we get no new privs.
*/
- if ((new->euid != old->uid ||
- new->egid != old->gid ||
+ if ((!uid_eq(new->euid, old->uid) ||
+ !gid_eq(new->egid, old->gid) ||
!cap_issubset(new->cap_permitted, old->cap_permitted)) &&
bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
/* downgrade; they get no more than they had, and maybe less */
@@ -553,7 +556,7 @@ skip:
*/
if (!cap_isclear(new->cap_effective)) {
if (!cap_issubset(CAP_FULL_SET, new->cap_effective) ||
- new->euid != 0 || new->uid != 0 ||
+ !uid_eq(new->euid, root_uid) || !uid_eq(new->uid, root_uid) ||
issecure(SECURE_NOROOT)) {
ret = audit_log_bprm_fcaps(bprm, new, old);
if (ret < 0)
@@ -578,16 +581,17 @@ skip:
int cap_bprm_secureexec(struct linux_binprm *bprm)
{
const struct cred *cred = current_cred();
+ kuid_t root_uid = make_kuid(cred->user_ns, 0);
- if (cred->uid != 0) {
+ if (!uid_eq(cred->uid, root_uid)) {
if (bprm->cap_effective)
return 1;
if (!cap_isclear(cred->cap_permitted))
return 1;
}
- return (cred->euid != cred->uid ||
- cred->egid != cred->gid);
+ return (!uid_eq(cred->euid, cred->uid) ||
+ !gid_eq(cred->egid, cred->gid));
}
/**
@@ -677,15 +681,21 @@ int cap_inode_removexattr(struct dentry *dentry, const char *name)
*/
static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old)
{
- if ((old->uid == 0 || old->euid == 0 || old->suid == 0) &&
- (new->uid != 0 && new->euid != 0 && new->suid != 0) &&
+ kuid_t root_uid = make_kuid(old->user_ns, 0);
+
+ if ((uid_eq(old->uid, root_uid) ||
+ uid_eq(old->euid, root_uid) ||
+ uid_eq(old->suid, root_uid)) &&
+ (!uid_eq(new->uid, root_uid) &&
+ !uid_eq(new->euid, root_uid) &&
+ !uid_eq(new->suid, root_uid)) &&
!issecure(SECURE_KEEP_CAPS)) {
cap_clear(new->cap_permitted);
cap_clear(new->cap_effective);
}
- if (old->euid == 0 && new->euid != 0)
+ if (uid_eq(old->euid, root_uid) && !uid_eq(new->euid, root_uid))
cap_clear(new->cap_effective);
- if (old->euid != 0 && new->euid == 0)
+ if (!uid_eq(old->euid, root_uid) && uid_eq(new->euid, root_uid))
new->cap_effective = new->cap_permitted;
}
@@ -718,11 +728,12 @@ int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags)
* if not, we might be a bit too harsh here.
*/
if (!issecure(SECURE_NO_SETUID_FIXUP)) {
- if (old->fsuid == 0 && new->fsuid != 0)
+ kuid_t root_uid = make_kuid(old->user_ns, 0);
+ if (uid_eq(old->fsuid, root_uid) && !uid_eq(new->fsuid, root_uid))
new->cap_effective =
cap_drop_fs_set(new->cap_effective);
- if (old->fsuid != 0 && new->fsuid == 0)
+ if (!uid_eq(old->fsuid, root_uid) && uid_eq(new->fsuid, root_uid))
new->cap_effective =
cap_raise_fs_set(new->cap_effective,
new->cap_permitted);
@@ -875,7 +886,7 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
|| ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/
|| (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/
|| (cap_capable(current_cred(),
- current_cred()->user->user_ns, CAP_SETPCAP,
+ current_cred()->user_ns, CAP_SETPCAP,
SECURITY_CAP_AUDIT) != 0) /*[4]*/
/*
* [1] no changing of bits that are locked
diff --git a/security/device_cgroup.c b/security/device_cgroup.c
index c43a3323feea..442204cc22d9 100644
--- a/security/device_cgroup.c
+++ b/security/device_cgroup.c
@@ -447,22 +447,16 @@ static struct cftype dev_cgroup_files[] = {
.read_seq_string = devcgroup_seq_read,
.private = DEVCG_LIST,
},
+ { } /* terminate */
};
-static int devcgroup_populate(struct cgroup_subsys *ss,
- struct cgroup *cgroup)
-{
- return cgroup_add_files(cgroup, ss, dev_cgroup_files,
- ARRAY_SIZE(dev_cgroup_files));
-}
-
struct cgroup_subsys devices_subsys = {
.name = "devices",
.can_attach = devcgroup_can_attach,
.create = devcgroup_create,
.destroy = devcgroup_destroy,
- .populate = devcgroup_populate,
.subsys_id = devices_subsys_id,
+ .base_cftypes = dev_cgroup_files,
};
int __devcgroup_inode_permission(struct inode *inode, int mask)
diff --git a/security/keys/key.c b/security/keys/key.c
index c9bf66ac36e0..50d96d4e06f2 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -253,7 +253,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
quotalen = desclen + type->def_datalen;
/* get hold of the key tracking for this user */
- user = key_user_lookup(uid, cred->user->user_ns);
+ user = key_user_lookup(uid, cred->user_ns);
if (!user)
goto no_memory_1;
diff --git a/security/keys/permission.c b/security/keys/permission.c
index 57d96363d7f1..0b4d019e027d 100644
--- a/security/keys/permission.c
+++ b/security/keys/permission.c
@@ -36,7 +36,7 @@ int key_task_permission(const key_ref_t key_ref, const struct cred *cred,
key = key_ref_to_ptr(key_ref);
- if (key->user->user_ns != cred->user->user_ns)
+ if (key->user->user_ns != cred->user_ns)
goto use_other_perms;
/* use the second 8-bits of permissions for keys the caller owns */
@@ -53,7 +53,8 @@ int key_task_permission(const key_ref_t key_ref, const struct cred *cred,
goto use_these_perms;
}
- ret = groups_search(cred->group_info, key->gid);
+ ret = groups_search(cred->group_info,
+ make_kgid(current_user_ns(), key->gid));
if (ret) {
kperm = key->perm >> 8;
goto use_these_perms;
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index e137fcd7042c..d71056db7b67 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -860,7 +860,7 @@ void key_replace_session_keyring(void)
new-> sgid = old-> sgid;
new->fsgid = old->fsgid;
new->user = get_uid(old->user);
- new->user_ns = new->user->user_ns;
+ new->user_ns = get_user_ns(new->user_ns);
new->group_info = get_group_info(old->group_info);
new->securebits = old->securebits;
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c
index 115313ef54d6..f5ded640b395 100644
--- a/sound/atmel/ac97c.c
+++ b/sound/atmel/ac97c.c
@@ -991,6 +991,8 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
gpio_direction_output(pdata->reset_pin, 1);
chip->reset_pin = pdata->reset_pin;
}
+ } else {
+ chip->reset_pin = -EINVAL;
}
snd_card_set_dev(card, &pdev->dev);
diff --git a/sound/core/jack.c b/sound/core/jack.c
index 471e1e3b0a99..a06b1651fcba 100644
--- a/sound/core/jack.c
+++ b/sound/core/jack.c
@@ -155,7 +155,7 @@ EXPORT_SYMBOL(snd_jack_new);
* @jack: The jack to configure
* @parent: The device to set as parent for the jack.
*
- * Set the parent for the jack input device in the device tree. This
+ * Set the parent for the jack devices in the device tree. This
* function is only valid prior to registration of the jack. If no
* parent is configured then the parent device will be the sound card.
*/
@@ -179,6 +179,9 @@ EXPORT_SYMBOL(snd_jack_set_parent);
* mapping is provided but keys are enabled in the jack type then
* BTN_n numeric buttons will be reported.
*
+ * If jacks are not reporting via the input API this call will have no
+ * effect.
+ *
* Note that this is intended to be use by simple devices with small
* numbers of keys that can be reported. It is also possible to
* access the input device directly - devices with complex input
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 4d18941178e6..faedb1481b24 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -1894,6 +1894,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t xfer = 0;
snd_pcm_uframes_t offset = 0;
+ snd_pcm_uframes_t avail;
int err = 0;
if (size == 0)
@@ -1917,13 +1918,12 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
}
runtime->twake = runtime->control->avail_min ? : 1;
+ if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
+ snd_pcm_update_hw_ptr(substream);
+ avail = snd_pcm_playback_avail(runtime);
while (size > 0) {
snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
- snd_pcm_uframes_t avail;
snd_pcm_uframes_t cont;
- if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
- snd_pcm_update_hw_ptr(substream);
- avail = snd_pcm_playback_avail(runtime);
if (!avail) {
if (nonblock) {
err = -EAGAIN;
@@ -1971,6 +1971,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
offset += frames;
size -= frames;
xfer += frames;
+ avail -= frames;
if (runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) {
err = snd_pcm_start(substream);
@@ -2111,6 +2112,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t xfer = 0;
snd_pcm_uframes_t offset = 0;
+ snd_pcm_uframes_t avail;
int err = 0;
if (size == 0)
@@ -2141,13 +2143,12 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
}
runtime->twake = runtime->control->avail_min ? : 1;
+ if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
+ snd_pcm_update_hw_ptr(substream);
+ avail = snd_pcm_capture_avail(runtime);
while (size > 0) {
snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
- snd_pcm_uframes_t avail;
snd_pcm_uframes_t cont;
- if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
- snd_pcm_update_hw_ptr(substream);
- avail = snd_pcm_capture_avail(runtime);
if (!avail) {
if (runtime->status->state ==
SNDRV_PCM_STATE_DRAINING) {
@@ -2202,6 +2203,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
offset += frames;
size -= frames;
xfer += frames;
+ avail -= frames;
}
_end_unlock:
runtime->twake = 0;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 3fe99e644eb8..53b5ada8f7c3 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1360,7 +1360,14 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream,
static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state)
{
- substream->runtime->trigger_master = substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ switch (runtime->status->state) {
+ case SNDRV_PCM_STATE_OPEN:
+ case SNDRV_PCM_STATE_DISCONNECTED:
+ case SNDRV_PCM_STATE_SUSPENDED:
+ return -EBADFD;
+ }
+ runtime->trigger_master = substream;
return 0;
}
@@ -1379,6 +1386,9 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state)
case SNDRV_PCM_STATE_RUNNING:
runtime->status->state = SNDRV_PCM_STATE_DRAINING;
break;
+ case SNDRV_PCM_STATE_XRUN:
+ runtime->status->state = SNDRV_PCM_STATE_SETUP;
+ break;
default:
break;
}
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c
index c70092043061..e9528333e36d 100644
--- a/sound/core/sound_oss.c
+++ b/sound/core/sound_oss.c
@@ -35,7 +35,7 @@
#include <linux/sound.h>
#include <linux/mutex.h>
-#define SNDRV_OSS_MINORS 128
+#define SNDRV_OSS_MINORS 256
static struct snd_minor *snd_oss_minors[SNDRV_OSS_MINORS];
static DEFINE_MUTEX(sound_oss_mutex);
@@ -111,7 +111,7 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev,
int register1 = -1, register2 = -1;
struct device *carddev = snd_card_get_device_link(card);
- if (card && card->number >= 8)
+ if (card && card->number >= SNDRV_MINOR_OSS_DEVICES)
return 0; /* ignore silently */
if (minor < 0)
return minor;
@@ -170,7 +170,7 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev)
int track2 = -1;
struct snd_minor *mptr;
- if (card && card->number >= 8)
+ if (card && card->number >= SNDRV_MINOR_OSS_DEVICES)
return 0;
if (minor < 0)
return minor;
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index ad079b63b8ba..8b5c36f4d303 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -117,6 +117,7 @@ struct loopback_pcm {
/* timer stuff */
unsigned int irq_pos; /* fractional IRQ position */
unsigned int period_size_frac;
+ unsigned int last_drift;
unsigned long last_jiffies;
struct timer_list timer;
};
@@ -264,6 +265,7 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
return err;
dpcm->last_jiffies = jiffies;
dpcm->pcm_rate_shift = 0;
+ dpcm->last_drift = 0;
spin_lock(&cable->lock);
cable->running |= stream;
cable->pause &= ~stream;
@@ -444,34 +446,30 @@ static void copy_play_buf(struct loopback_pcm *play,
}
}
-#define BYTEPOS_UPDATE_POSONLY 0
-#define BYTEPOS_UPDATE_CLEAR 1
-#define BYTEPOS_UPDATE_COPY 2
-
-static void loopback_bytepos_update(struct loopback_pcm *dpcm,
- unsigned int delta,
- unsigned int cmd)
+static inline unsigned int bytepos_delta(struct loopback_pcm *dpcm,
+ unsigned int jiffies_delta)
{
- unsigned int count;
unsigned long last_pos;
+ unsigned int delta;
last_pos = byte_pos(dpcm, dpcm->irq_pos);
- dpcm->irq_pos += delta * dpcm->pcm_bps;
- count = byte_pos(dpcm, dpcm->irq_pos) - last_pos;
- if (!count)
- return;
- if (cmd == BYTEPOS_UPDATE_CLEAR)
- clear_capture_buf(dpcm, count);
- else if (cmd == BYTEPOS_UPDATE_COPY)
- copy_play_buf(dpcm->cable->streams[SNDRV_PCM_STREAM_PLAYBACK],
- dpcm->cable->streams[SNDRV_PCM_STREAM_CAPTURE],
- count);
- dpcm->buf_pos += count;
- dpcm->buf_pos %= dpcm->pcm_buffer_size;
+ dpcm->irq_pos += jiffies_delta * dpcm->pcm_bps;
+ delta = byte_pos(dpcm, dpcm->irq_pos) - last_pos;
+ if (delta >= dpcm->last_drift)
+ delta -= dpcm->last_drift;
+ dpcm->last_drift = 0;
if (dpcm->irq_pos >= dpcm->period_size_frac) {
dpcm->irq_pos %= dpcm->period_size_frac;
dpcm->period_update_pending = 1;
}
+ return delta;
+}
+
+static inline void bytepos_finish(struct loopback_pcm *dpcm,
+ unsigned int delta)
+{
+ dpcm->buf_pos += delta;
+ dpcm->buf_pos %= dpcm->pcm_buffer_size;
}
static unsigned int loopback_pos_update(struct loopback_cable *cable)
@@ -481,7 +479,7 @@ static unsigned int loopback_pos_update(struct loopback_cable *cable)
struct loopback_pcm *dpcm_capt =
cable->streams[SNDRV_PCM_STREAM_CAPTURE];
unsigned long delta_play = 0, delta_capt = 0;
- unsigned int running;
+ unsigned int running, count1, count2;
unsigned long flags;
spin_lock_irqsave(&cable->lock, flags);
@@ -500,12 +498,13 @@ static unsigned int loopback_pos_update(struct loopback_cable *cable)
goto unlock;
if (delta_play > delta_capt) {
- loopback_bytepos_update(dpcm_play, delta_play - delta_capt,
- BYTEPOS_UPDATE_POSONLY);
+ count1 = bytepos_delta(dpcm_play, delta_play - delta_capt);
+ bytepos_finish(dpcm_play, count1);
delta_play = delta_capt;
} else if (delta_play < delta_capt) {
- loopback_bytepos_update(dpcm_capt, delta_capt - delta_play,
- BYTEPOS_UPDATE_CLEAR);
+ count1 = bytepos_delta(dpcm_capt, delta_capt - delta_play);
+ clear_capture_buf(dpcm_capt, count1);
+ bytepos_finish(dpcm_capt, count1);
delta_capt = delta_play;
}
@@ -513,8 +512,17 @@ static unsigned int loopback_pos_update(struct loopback_cable *cable)
goto unlock;
/* note delta_capt == delta_play at this moment */
- loopback_bytepos_update(dpcm_capt, delta_capt, BYTEPOS_UPDATE_COPY);
- loopback_bytepos_update(dpcm_play, delta_play, BYTEPOS_UPDATE_POSONLY);
+ count1 = bytepos_delta(dpcm_play, delta_play);
+ count2 = bytepos_delta(dpcm_capt, delta_capt);
+ if (count1 < count2) {
+ dpcm_capt->last_drift = count2 - count1;
+ count1 = count2;
+ } else if (count1 > count2) {
+ dpcm_play->last_drift = count1 - count2;
+ }
+ copy_play_buf(dpcm_play, dpcm_capt, count1);
+ bytepos_finish(dpcm_play, count1);
+ bytepos_finish(dpcm_capt, count1);
unlock:
spin_unlock_irqrestore(&cable->lock, flags);
return running;
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c
index 87657dd7714c..ea995af6d049 100644
--- a/sound/firewire/amdtp.c
+++ b/sound/firewire/amdtp.c
@@ -31,6 +31,8 @@
#define INTERRUPT_INTERVAL 16
#define QUEUE_LENGTH 48
+static void pcm_period_tasklet(unsigned long data);
+
/**
* amdtp_out_stream_init - initialize an AMDTP output stream structure
* @s: the AMDTP output stream to initialize
@@ -47,6 +49,7 @@ int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit,
s->flags = flags;
s->context = ERR_PTR(-1);
mutex_init(&s->mutex);
+ tasklet_init(&s->period_tasklet, pcm_period_tasklet, (unsigned long)s);
s->packet_index = 0;
return 0;
@@ -164,6 +167,21 @@ void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s,
}
EXPORT_SYMBOL(amdtp_out_stream_set_pcm_format);
+/**
+ * amdtp_out_stream_pcm_prepare - prepare PCM device for running
+ * @s: the AMDTP output stream
+ *
+ * This function should be called from the PCM device's .prepare callback.
+ */
+void amdtp_out_stream_pcm_prepare(struct amdtp_out_stream *s)
+{
+ tasklet_kill(&s->period_tasklet);
+ s->pcm_buffer_pointer = 0;
+ s->pcm_period_pointer = 0;
+ s->pointer_flush = true;
+}
+EXPORT_SYMBOL(amdtp_out_stream_pcm_prepare);
+
static unsigned int calculate_data_blocks(struct amdtp_out_stream *s)
{
unsigned int phase, data_blocks;
@@ -376,11 +394,21 @@ static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle)
s->pcm_period_pointer += data_blocks;
if (s->pcm_period_pointer >= pcm->runtime->period_size) {
s->pcm_period_pointer -= pcm->runtime->period_size;
- snd_pcm_period_elapsed(pcm);
+ s->pointer_flush = false;
+ tasklet_hi_schedule(&s->period_tasklet);
}
}
}
+static void pcm_period_tasklet(unsigned long data)
+{
+ struct amdtp_out_stream *s = (void *)data;
+ struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm);
+
+ if (pcm)
+ snd_pcm_period_elapsed(pcm);
+}
+
static void out_packet_callback(struct fw_iso_context *context, u32 cycle,
size_t header_length, void *header, void *data)
{
@@ -506,6 +534,24 @@ err_unlock:
EXPORT_SYMBOL(amdtp_out_stream_start);
/**
+ * amdtp_out_stream_pcm_pointer - get the PCM buffer position
+ * @s: the AMDTP output stream that transports the PCM data
+ *
+ * Returns the current buffer position, in frames.
+ */
+unsigned long amdtp_out_stream_pcm_pointer(struct amdtp_out_stream *s)
+{
+ /* this optimization is allowed to be racy */
+ if (s->pointer_flush)
+ fw_iso_context_flush_completions(s->context);
+ else
+ s->pointer_flush = true;
+
+ return ACCESS_ONCE(s->pcm_buffer_pointer);
+}
+EXPORT_SYMBOL(amdtp_out_stream_pcm_pointer);
+
+/**
* amdtp_out_stream_update - update the stream after a bus reset
* @s: the AMDTP output stream
*/
@@ -532,6 +578,7 @@ void amdtp_out_stream_stop(struct amdtp_out_stream *s)
return;
}
+ tasklet_kill(&s->period_tasklet);
fw_iso_context_stop(s->context);
fw_iso_context_destroy(s->context);
s->context = ERR_PTR(-1);
diff --git a/sound/firewire/amdtp.h b/sound/firewire/amdtp.h
index 537a9cb83581..b680c5ef01d6 100644
--- a/sound/firewire/amdtp.h
+++ b/sound/firewire/amdtp.h
@@ -1,6 +1,7 @@
#ifndef SOUND_FIREWIRE_AMDTP_H_INCLUDED
#define SOUND_FIREWIRE_AMDTP_H_INCLUDED
+#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include "packets-buffer.h"
@@ -55,6 +56,7 @@ struct amdtp_out_stream {
struct iso_packets_buffer buffer;
struct snd_pcm_substream *pcm;
+ struct tasklet_struct period_tasklet;
int packet_index;
unsigned int data_block_counter;
@@ -66,6 +68,7 @@ struct amdtp_out_stream {
unsigned int pcm_buffer_pointer;
unsigned int pcm_period_pointer;
+ bool pointer_flush;
};
int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit,
@@ -81,6 +84,8 @@ void amdtp_out_stream_stop(struct amdtp_out_stream *s);
void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s,
snd_pcm_format_t format);
+void amdtp_out_stream_pcm_prepare(struct amdtp_out_stream *s);
+unsigned long amdtp_out_stream_pcm_pointer(struct amdtp_out_stream *s);
void amdtp_out_stream_pcm_abort(struct amdtp_out_stream *s);
/**
@@ -123,18 +128,6 @@ static inline bool amdtp_out_streaming_error(struct amdtp_out_stream *s)
}
/**
- * amdtp_out_stream_pcm_prepare - prepare PCM device for running
- * @s: the AMDTP output stream
- *
- * This function should be called from the PCM device's .prepare callback.
- */
-static inline void amdtp_out_stream_pcm_prepare(struct amdtp_out_stream *s)
-{
- s->pcm_buffer_pointer = 0;
- s->pcm_period_pointer = 0;
-}
-
-/**
* amdtp_out_stream_pcm_trigger - start/stop playback from a PCM device
* @s: the AMDTP output stream
* @pcm: the PCM device to be started, or %NULL to stop the current device
@@ -149,18 +142,6 @@ static inline void amdtp_out_stream_pcm_trigger(struct amdtp_out_stream *s,
ACCESS_ONCE(s->pcm) = pcm;
}
-/**
- * amdtp_out_stream_pcm_pointer - get the PCM buffer position
- * @s: the AMDTP output stream that transports the PCM data
- *
- * Returns the current buffer position, in frames.
- */
-static inline unsigned long
-amdtp_out_stream_pcm_pointer(struct amdtp_out_stream *s)
-{
- return ACCESS_ONCE(s->pcm_buffer_pointer);
-}
-
static inline bool cip_sfc_is_base_44100(enum cip_sfc sfc)
{
return sfc & 1;
diff --git a/sound/firewire/cmp.c b/sound/firewire/cmp.c
index 76294f2ae47f..645cb0ba4293 100644
--- a/sound/firewire/cmp.c
+++ b/sound/firewire/cmp.c
@@ -84,7 +84,7 @@ static int pcr_modify(struct cmp_connection *c,
return 0;
io_error:
- cmp_error(c, "transaction failed: %s\n", rcode_string(rcode));
+ cmp_error(c, "transaction failed: %s\n", fw_rcode_string(rcode));
return -EIO;
bus_reset:
diff --git a/sound/firewire/lib.c b/sound/firewire/lib.c
index 4750cea2210e..14eb41498372 100644
--- a/sound/firewire/lib.c
+++ b/sound/firewire/lib.c
@@ -14,32 +14,6 @@
#define ERROR_RETRY_DELAY_MS 5
/**
- * rcode_string - convert a firewire result code to a string
- * @rcode: the result
- */
-const char *rcode_string(unsigned int rcode)
-{
- static const char *const names[] = {
- [RCODE_COMPLETE] = "complete",
- [RCODE_CONFLICT_ERROR] = "conflict error",
- [RCODE_DATA_ERROR] = "data error",
- [RCODE_TYPE_ERROR] = "type error",
- [RCODE_ADDRESS_ERROR] = "address error",
- [RCODE_SEND_ERROR] = "send error",
- [RCODE_CANCELLED] = "cancelled",
- [RCODE_BUSY] = "busy",
- [RCODE_GENERATION] = "generation",
- [RCODE_NO_ACK] = "no ack",
- };
-
- if (rcode < ARRAY_SIZE(names) && names[rcode])
- return names[rcode];
- else
- return "unknown";
-}
-EXPORT_SYMBOL(rcode_string);
-
-/**
* snd_fw_transaction - send a request and wait for its completion
* @unit: the driver's unit on the target device
* @tcode: the transaction code
@@ -71,7 +45,7 @@ int snd_fw_transaction(struct fw_unit *unit, int tcode,
if (rcode_is_permanent_error(rcode) || ++tries >= 3) {
dev_err(&unit->device, "transaction failed: %s\n",
- rcode_string(rcode));
+ fw_rcode_string(rcode));
return -EIO;
}
diff --git a/sound/firewire/lib.h b/sound/firewire/lib.h
index 064f3fd9ab06..aef301476ea9 100644
--- a/sound/firewire/lib.h
+++ b/sound/firewire/lib.h
@@ -8,7 +8,6 @@ struct fw_unit;
int snd_fw_transaction(struct fw_unit *unit, int tcode,
u64 offset, void *buffer, size_t length);
-const char *rcode_string(unsigned int rcode);
/* returns true if retrying the transaction would not make sense */
static inline bool rcode_is_permanent_error(int rcode)
diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c
index a63faec5e7fd..582aace20ea3 100644
--- a/sound/i2c/other/tea575x-tuner.c
+++ b/sound/i2c/other/tea575x-tuner.c
@@ -375,6 +375,9 @@ int snd_tea575x_init(struct snd_tea575x *tea)
tea->vd.v4l2_dev = tea->v4l2_dev;
tea->vd.ctrl_handler = &tea->ctrl_handler;
set_bit(V4L2_FL_USE_FH_PRIO, &tea->vd.flags);
+ /* disable hw_freq_seek if we can't use it */
+ if (tea->cannot_read_data)
+ v4l2_disable_ioctl(&tea->vd, VIDIOC_S_HW_FREQ_SEEK);
v4l2_ctrl_handler_init(&tea->ctrl_handler, 1);
v4l2_ctrl_new_std(&tea->ctrl_handler, &tea575x_ctrl_ops, V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
diff --git a/sound/isa/als100.c b/sound/isa/als100.c
index d1f4351fb6ee..2d67c78c9f4b 100644
--- a/sound/isa/als100.c
+++ b/sound/isa/als100.c
@@ -7,7 +7,7 @@
Thanks to Pierfrancesco 'qM2' Passerini.
Generalised for soundcards based on DT-0196 and ALS-007 chips
- by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>: June 2002.
+ by Jonathan Woithe <jwoithe@just42.net>: June 2002.
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
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 5ca0939e4223..ff3af6e77d61 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -228,7 +228,7 @@ config SND_OXYGEN
Say Y here to include support for sound cards based on the
C-Media CMI8788 (Oxygen HD Audio) chip:
* Asound A-8788
- * Asus Xonar DG
+ * Asus Xonar DG/DGX
* AuzenTech X-Meridian
* AuzenTech X-Meridian 2G
* Bgears b-Enspirer
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
index 9d91d61902b4..e672ff4df2da 100644
--- a/sound/pci/ad1889.c
+++ b/sound/pci/ad1889.c
@@ -1062,17 +1062,4 @@ static struct pci_driver ad1889_pci_driver = {
.remove = __devexit_p(snd_ad1889_remove),
};
-static int __init
-alsa_ad1889_init(void)
-{
- return pci_register_driver(&ad1889_pci_driver);
-}
-
-static void __exit
-alsa_ad1889_fini(void)
-{
- pci_unregister_driver(&ad1889_pci_driver);
-}
-
-module_init(alsa_ad1889_init);
-module_exit(alsa_ad1889_fini);
+module_pci_driver(ad1889_pci_driver);
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index bdd6164e9c7e..9dfc27bf6cc6 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -2294,7 +2294,7 @@ static void __devexit snd_ali_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver ali5451_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_ali_ids,
.probe = snd_ali_probe,
@@ -2305,15 +2305,4 @@ static struct pci_driver driver = {
#endif
};
-static int __init alsa_card_ali_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_ali_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_ali_init)
-module_exit(alsa_card_ali_exit)
+module_pci_driver(ali5451_driver);
diff --git a/sound/pci/als300.c b/sound/pci/als300.c
index 8196e229b2df..59d65388faf5 100644
--- a/sound/pci/als300.c
+++ b/sound/pci/als300.c
@@ -852,7 +852,7 @@ static int __devinit snd_als300_probe(struct pci_dev *pci,
return 0;
}
-static struct pci_driver driver = {
+static struct pci_driver als300_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_als300_ids,
.probe = snd_als300_probe,
@@ -863,15 +863,4 @@ static struct pci_driver driver = {
#endif
};
-static int __init alsa_card_als300_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_als300_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_als300_init)
-module_exit(alsa_card_als300_exit)
+module_pci_driver(als300_driver);
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
index 3269b8011ea9..7d7f2598c748 100644
--- a/sound/pci/als4000.c
+++ b/sound/pci/als4000.c
@@ -1036,7 +1036,7 @@ static int snd_als4000_resume(struct pci_dev *pci)
#endif /* CONFIG_PM */
-static struct pci_driver driver = {
+static struct pci_driver als4000_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_als4000_ids,
.probe = snd_card_als4000_probe,
@@ -1047,15 +1047,4 @@ static struct pci_driver driver = {
#endif
};
-static int __init alsa_card_als4000_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_als4000_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_als4000_init)
-module_exit(alsa_card_als4000_exit)
+module_pci_driver(als4000_driver);
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 590682f115ef..156a94f8a123 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -1700,7 +1700,7 @@ static void __devexit snd_atiixp_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver atiixp_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_atiixp_ids,
.probe = snd_atiixp_probe,
@@ -1711,16 +1711,4 @@ static struct pci_driver driver = {
#endif
};
-
-static int __init alsa_card_atiixp_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_atiixp_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_atiixp_init)
-module_exit(alsa_card_atiixp_exit)
+module_pci_driver(atiixp_driver);
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index 524d35f31232..30a4fd96ce73 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -1331,7 +1331,7 @@ static void __devexit snd_atiixp_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver atiixp_modem_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_atiixp_ids,
.probe = snd_atiixp_probe,
@@ -1342,16 +1342,4 @@ static struct pci_driver driver = {
#endif
};
-
-static int __init alsa_card_atiixp_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_atiixp_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_atiixp_init)
-module_exit(alsa_card_atiixp_exit)
+module_pci_driver(atiixp_modem_driver);
diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c
index f13ad536b2d5..ffc376f9f4e4 100644
--- a/sound/pci/au88x0/au88x0.c
+++ b/sound/pci/au88x0/au88x0.c
@@ -375,24 +375,11 @@ static void __devexit snd_vortex_remove(struct pci_dev *pci)
}
// pci_driver definition
-static struct pci_driver driver = {
+static struct pci_driver vortex_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_vortex_ids,
.probe = snd_vortex_probe,
.remove = __devexit_p(snd_vortex_remove),
};
-// initialization of the module
-static int __init alsa_card_vortex_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-// clean up the module
-static void __exit alsa_card_vortex_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_vortex_init)
-module_exit(alsa_card_vortex_exit)
+module_pci_driver(vortex_driver);
diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c
index 1c5231931462..0f804741825f 100644
--- a/sound/pci/aw2/aw2-alsa.c
+++ b/sound/pci/aw2/aw2-alsa.c
@@ -112,8 +112,6 @@ struct aw2 {
/*********************************
* FUNCTION DECLARATIONS
********************************/
-static int __init alsa_card_aw2_init(void);
-static void __exit alsa_card_aw2_exit(void);
static int snd_aw2_dev_free(struct snd_device *device);
static int __devinit snd_aw2_create(struct snd_card *card,
struct pci_dev *pci, struct aw2 **rchip);
@@ -171,13 +169,15 @@ static DEFINE_PCI_DEVICE_TABLE(snd_aw2_ids) = {
MODULE_DEVICE_TABLE(pci, snd_aw2_ids);
/* pci_driver definition */
-static struct pci_driver driver = {
+static struct pci_driver aw2_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_aw2_ids,
.probe = snd_aw2_probe,
.remove = __devexit_p(snd_aw2_remove),
};
+module_pci_driver(aw2_driver);
+
/* operators for playback PCM alsa interface */
static struct snd_pcm_ops snd_aw2_playback_ops = {
.open = snd_aw2_pcm_playback_open,
@@ -217,23 +217,6 @@ static struct snd_kcontrol_new aw2_control __devinitdata = {
* FUNCTION IMPLEMENTATIONS
********************************/
-/* initialization of the module */
-static int __init alsa_card_aw2_init(void)
-{
- snd_printdd(KERN_DEBUG "aw2: Load aw2 module\n");
- return pci_register_driver(&driver);
-}
-
-/* clean up the module */
-static void __exit alsa_card_aw2_exit(void)
-{
- snd_printdd(KERN_DEBUG "aw2: Unload aw2 module\n");
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_aw2_init);
-module_exit(alsa_card_aw2_exit);
-
/* component-destructor */
static int snd_aw2_dev_free(struct snd_device *device)
{
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 496f14c1a731..f0b4d7493af5 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -2862,7 +2862,7 @@ snd_azf3328_resume(struct pci_dev *pci)
#endif /* CONFIG_PM */
-static struct pci_driver driver = {
+static struct pci_driver azf3328_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_azf3328_ids,
.probe = snd_azf3328_probe,
@@ -2873,23 +2873,4 @@ static struct pci_driver driver = {
#endif
};
-static int __init
-alsa_card_azf3328_init(void)
-{
- int err;
- snd_azf3328_dbgcallenter();
- err = pci_register_driver(&driver);
- snd_azf3328_dbgcallleave();
- return err;
-}
-
-static void __exit
-alsa_card_azf3328_exit(void)
-{
- snd_azf3328_dbgcallenter();
- pci_unregister_driver(&driver);
- snd_azf3328_dbgcallleave();
-}
-
-module_init(alsa_card_azf3328_init)
-module_exit(alsa_card_azf3328_exit)
+module_pci_driver(azf3328_driver);
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index 62d6163fc9d9..b6a95eeca095 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -836,8 +836,6 @@ static struct {
{0x7063, 0x2000}, /* pcHDTV HD-2000 TV */
};
-static struct pci_driver driver;
-
/* return the id of the card, or a negative value if it's blacklisted */
static int __devinit snd_bt87x_detect_card(struct pci_dev *pci)
{
@@ -964,24 +962,11 @@ static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_default_ids) = {
{ }
};
-static struct pci_driver driver = {
+static struct pci_driver bt87x_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_bt87x_ids,
.probe = snd_bt87x_probe,
.remove = __devexit_p(snd_bt87x_remove),
};
-static int __init alsa_card_bt87x_init(void)
-{
- if (load_all)
- driver.id_table = snd_bt87x_default_ids;
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_bt87x_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_bt87x_init)
-module_exit(alsa_card_bt87x_exit)
+module_pci_driver(bt87x_driver);
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 08d6ebfe5a61..e76d68a7081f 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -1932,7 +1932,7 @@ static DEFINE_PCI_DEVICE_TABLE(snd_ca0106_ids) = {
MODULE_DEVICE_TABLE(pci, snd_ca0106_ids);
// pci_driver definition
-static struct pci_driver driver = {
+static struct pci_driver ca0106_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_ca0106_ids,
.probe = snd_ca0106_probe,
@@ -1943,17 +1943,4 @@ static struct pci_driver driver = {
#endif
};
-// initialization of the module
-static int __init alsa_card_ca0106_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-// clean up the module
-static void __exit alsa_card_ca0106_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_ca0106_init)
-module_exit(alsa_card_ca0106_exit)
+module_pci_driver(ca0106_driver);
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index 19b06269adc2..3815bd4c6779 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -3398,7 +3398,7 @@ static int snd_cmipci_resume(struct pci_dev *pci)
}
#endif /* CONFIG_PM */
-static struct pci_driver driver = {
+static struct pci_driver cmipci_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_cmipci_ids,
.probe = snd_cmipci_probe,
@@ -3409,15 +3409,4 @@ static struct pci_driver driver = {
#endif
};
-static int __init alsa_card_cmipci_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_cmipci_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_cmipci_init)
-module_exit(alsa_card_cmipci_exit)
+module_pci_driver(cmipci_driver);
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index a9f368f60df6..33506ee569bd 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -2084,7 +2084,7 @@ static int cs4281_resume(struct pci_dev *pci)
}
#endif /* CONFIG_PM */
-static struct pci_driver driver = {
+static struct pci_driver cs4281_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_cs4281_ids,
.probe = snd_cs4281_probe,
@@ -2095,15 +2095,4 @@ static struct pci_driver driver = {
#endif
};
-static int __init alsa_card_cs4281_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_cs4281_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_cs4281_init)
-module_exit(alsa_card_cs4281_exit)
+module_pci_driver(cs4281_driver);
diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c
index 819d79d0586d..6cc7404e0e8f 100644
--- a/sound/pci/cs46xx/cs46xx.c
+++ b/sound/pci/cs46xx/cs46xx.c
@@ -161,7 +161,7 @@ static void __devexit snd_card_cs46xx_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver cs46xx_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_cs46xx_ids,
.probe = snd_card_cs46xx_probe,
@@ -172,15 +172,4 @@ static struct pci_driver driver = {
#endif
};
-static int __init alsa_card_cs46xx_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_cs46xx_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_cs46xx_init)
-module_exit(alsa_card_cs46xx_exit)
+module_pci_driver(cs46xx_driver);
diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c
index c47cabff2bfa..f1e4229993af 100644
--- a/sound/pci/cs5530.c
+++ b/sound/pci/cs5530.c
@@ -291,23 +291,11 @@ static int __devinit snd_cs5530_probe(struct pci_dev *pci,
return 0;
}
-static struct pci_driver driver = {
+static struct pci_driver cs5530_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_cs5530_ids,
.probe = snd_cs5530_probe,
.remove = __devexit_p(snd_cs5530_remove),
};
-static int __init alsa_card_cs5530_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_cs5530_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_cs5530_init)
-module_exit(alsa_card_cs5530_exit)
-
+module_pci_driver(cs5530_driver);
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c
index a2fb2173e980..2c9697cf0a1a 100644
--- a/sound/pci/cs5535audio/cs5535audio.c
+++ b/sound/pci/cs5535audio/cs5535audio.c
@@ -394,7 +394,7 @@ static void __devexit snd_cs5535audio_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver cs5535audio_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_cs5535audio_ids,
.probe = snd_cs5535audio_probe,
@@ -405,18 +405,7 @@ static struct pci_driver driver = {
#endif
};
-static int __init alsa_card_cs5535audio_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_cs5535audio_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_cs5535audio_init)
-module_exit(alsa_card_cs5535audio_exit)
+module_pci_driver(cs5535audio_driver);
MODULE_AUTHOR("Jaya Kumar");
MODULE_LICENSE("GPL");
diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c
index 15d95d2bacee..75aa2c338410 100644
--- a/sound/pci/ctxfi/xfi.c
+++ b/sound/pci/ctxfi/xfi.c
@@ -154,15 +154,4 @@ static struct pci_driver ct_driver = {
#endif
};
-static int __init ct_card_init(void)
-{
- return pci_register_driver(&ct_driver);
-}
-
-static void __exit ct_card_exit(void)
-{
- pci_unregister_driver(&ct_driver);
-}
-
-module_init(ct_card_init)
-module_exit(ct_card_exit)
+module_pci_driver(ct_driver);
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index 595c11f904bb..0f8eda1dafdb 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -2328,7 +2328,7 @@ static void __devexit snd_echo_remove(struct pci_dev *pci)
******************************************************************************/
/* pci_driver definition */
-static struct pci_driver driver = {
+static struct pci_driver echo_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_echo_ids,
.probe = snd_echo_probe,
@@ -2339,22 +2339,4 @@ static struct pci_driver driver = {
#endif /* CONFIG_PM */
};
-
-
-/* initialization of the module */
-static int __init alsa_card_echo_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-
-
-/* clean up the module */
-static void __exit alsa_card_echo_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-
-module_init(alsa_card_echo_init)
-module_exit(alsa_card_echo_exit)
+module_pci_driver(echo_driver);
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c
index 790c65d980c8..7fdbbe4d9965 100644
--- a/sound/pci/emu10k1/emu10k1.c
+++ b/sound/pci/emu10k1/emu10k1.c
@@ -263,7 +263,7 @@ static int snd_emu10k1_resume(struct pci_dev *pci)
}
#endif
-static struct pci_driver driver = {
+static struct pci_driver emu10k1_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_emu10k1_ids,
.probe = snd_card_emu10k1_probe,
@@ -274,15 +274,4 @@ static struct pci_driver driver = {
#endif
};
-static int __init alsa_card_emu10k1_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_emu10k1_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_emu10k1_init)
-module_exit(alsa_card_emu10k1_exit)
+module_pci_driver(emu10k1_driver);
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index 47a651cb6e84..5c8978b2c4d9 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -1612,24 +1612,11 @@ static DEFINE_PCI_DEVICE_TABLE(snd_emu10k1x_ids) = {
MODULE_DEVICE_TABLE(pci, snd_emu10k1x_ids);
// pci_driver definition
-static struct pci_driver driver = {
+static struct pci_driver emu10k1x_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_emu10k1x_ids,
.probe = snd_emu10k1x_probe,
.remove = __devexit_p(snd_emu10k1x_remove),
};
-// initialization of the module
-static int __init alsa_card_emu10k1x_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-// clean up the module
-static void __exit alsa_card_emu10k1x_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_emu10k1x_init)
-module_exit(alsa_card_emu10k1x_exit)
+module_pci_driver(emu10k1x_driver);
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index 47a245e84190..3821c81d1c99 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -2488,7 +2488,7 @@ static void __devexit snd_audiopci_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver ens137x_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_audiopci_ids,
.probe = snd_audiopci_probe,
@@ -2499,15 +2499,4 @@ static struct pci_driver driver = {
#endif
};
-static int __init alsa_card_ens137x_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_ens137x_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_ens137x_init)
-module_exit(alsa_card_ens137x_exit)
+module_pci_driver(ens137x_driver);
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index 53eb76b41108..82c8d8c5c52a 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -1882,7 +1882,7 @@ static void __devexit snd_es1938_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver es1938_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_es1938_ids,
.probe = snd_es1938_probe,
@@ -1893,15 +1893,4 @@ static struct pci_driver driver = {
#endif
};
-static int __init alsa_card_es1938_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_es1938_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_es1938_init)
-module_exit(alsa_card_es1938_exit)
+module_pci_driver(es1938_driver);
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index a8faae1c85e4..67f47d891959 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -2898,7 +2898,7 @@ static void __devexit snd_es1968_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver es1968_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_es1968_ids,
.probe = snd_es1968_probe,
@@ -2909,15 +2909,4 @@ static struct pci_driver driver = {
#endif
};
-static int __init alsa_card_es1968_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_es1968_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_es1968_init)
-module_exit(alsa_card_es1968_exit)
+module_pci_driver(es1968_driver);
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index a416ea8af3e9..f69662322750 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -1416,7 +1416,7 @@ static int snd_fm801_resume(struct pci_dev *pci)
}
#endif
-static struct pci_driver driver = {
+static struct pci_driver fm801_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_fm801_ids,
.probe = snd_card_fm801_probe,
@@ -1427,15 +1427,4 @@ static struct pci_driver driver = {
#endif
};
-static int __init alsa_card_fm801_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_fm801_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_fm801_init)
-module_exit(alsa_card_fm801_exit)
+module_pci_driver(fm801_driver);
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index ace157cc3d15..bd4149f1aaf4 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -1,6 +1,6 @@
snd-hda-intel-objs := hda_intel.o
-snd-hda-codec-y := hda_codec.o hda_jack.o
+snd-hda-codec-y := hda_codec.o hda_jack.o hda_auto_parser.o
snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o
snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o
snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c
new file mode 100644
index 000000000000..6e9ef3e25093
--- /dev/null
+++ b/sound/pci/hda/hda_auto_parser.c
@@ -0,0 +1,760 @@
+/*
+ * BIOS auto-parser helper functions for HD-audio
+ *
+ * Copyright (c) 2012 Takashi Iwai <tiwai@suse.de>
+ *
+ * This driver 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/slab.h>
+#include <linux/export.h>
+#include <sound/core.h>
+#include "hda_codec.h"
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+
+#define SFX "hda_codec: "
+
+/*
+ * Helper for automatic pin configuration
+ */
+
+static int is_in_nid_list(hda_nid_t nid, const hda_nid_t *list)
+{
+ for (; *list; list++)
+ if (*list == nid)
+ return 1;
+ return 0;
+}
+
+
+/*
+ * Sort an associated group of pins according to their sequence numbers.
+ */
+static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences,
+ int num_pins)
+{
+ int i, j;
+ short seq;
+ hda_nid_t nid;
+
+ for (i = 0; i < num_pins; i++) {
+ for (j = i + 1; j < num_pins; j++) {
+ if (sequences[i] > sequences[j]) {
+ seq = sequences[i];
+ sequences[i] = sequences[j];
+ sequences[j] = seq;
+ nid = pins[i];
+ pins[i] = pins[j];
+ pins[j] = nid;
+ }
+ }
+ }
+}
+
+
+/* add the found input-pin to the cfg->inputs[] table */
+static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid,
+ int type)
+{
+ if (cfg->num_inputs < AUTO_CFG_MAX_INS) {
+ cfg->inputs[cfg->num_inputs].pin = nid;
+ cfg->inputs[cfg->num_inputs].type = type;
+ cfg->num_inputs++;
+ }
+}
+
+/* sort inputs in the order of AUTO_PIN_* type */
+static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg)
+{
+ int i, j;
+
+ for (i = 0; i < cfg->num_inputs; i++) {
+ for (j = i + 1; j < cfg->num_inputs; j++) {
+ if (cfg->inputs[i].type > cfg->inputs[j].type) {
+ struct auto_pin_cfg_item tmp;
+ tmp = cfg->inputs[i];
+ cfg->inputs[i] = cfg->inputs[j];
+ cfg->inputs[j] = tmp;
+ }
+ }
+ }
+}
+
+/* Reorder the surround channels
+ * ALSA sequence is front/surr/clfe/side
+ * HDA sequence is:
+ * 4-ch: front/surr => OK as it is
+ * 6-ch: front/clfe/surr
+ * 8-ch: front/clfe/rear/side|fc
+ */
+static void reorder_outputs(unsigned int nums, hda_nid_t *pins)
+{
+ hda_nid_t nid;
+
+ switch (nums) {
+ case 3:
+ case 4:
+ nid = pins[1];
+ pins[1] = pins[2];
+ pins[2] = nid;
+ break;
+ }
+}
+
+/*
+ * Parse all pin widgets and store the useful pin nids to cfg
+ *
+ * The number of line-outs or any primary output is stored in line_outs,
+ * and the corresponding output pins are assigned to line_out_pins[],
+ * in the order of front, rear, CLFE, side, ...
+ *
+ * If more extra outputs (speaker and headphone) are found, the pins are
+ * assisnged to hp_pins[] and speaker_pins[], respectively. If no line-out jack
+ * is detected, one of speaker of HP pins is assigned as the primary
+ * output, i.e. to line_out_pins[0]. So, line_outs is always positive
+ * if any analog output exists.
+ *
+ * The analog input pins are assigned to inputs array.
+ * The digital input/output pins are assigned to dig_in_pin and dig_out_pin,
+ * respectively.
+ */
+int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
+ struct auto_pin_cfg *cfg,
+ const hda_nid_t *ignore_nids,
+ unsigned int cond_flags)
+{
+ hda_nid_t nid, end_nid;
+ short seq, assoc_line_out;
+ short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)];
+ short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)];
+ short sequences_hp[ARRAY_SIZE(cfg->hp_pins)];
+ int i;
+
+ memset(cfg, 0, sizeof(*cfg));
+
+ memset(sequences_line_out, 0, sizeof(sequences_line_out));
+ memset(sequences_speaker, 0, sizeof(sequences_speaker));
+ memset(sequences_hp, 0, sizeof(sequences_hp));
+ assoc_line_out = 0;
+
+ codec->ignore_misc_bit = true;
+ end_nid = codec->start_nid + codec->num_nodes;
+ for (nid = codec->start_nid; nid < end_nid; nid++) {
+ unsigned int wid_caps = get_wcaps(codec, nid);
+ unsigned int wid_type = get_wcaps_type(wid_caps);
+ unsigned int def_conf;
+ short assoc, loc, conn, dev;
+
+ /* read all default configuration for pin complex */
+ if (wid_type != AC_WID_PIN)
+ continue;
+ /* ignore the given nids (e.g. pc-beep returns error) */
+ if (ignore_nids && is_in_nid_list(nid, ignore_nids))
+ continue;
+
+ def_conf = snd_hda_codec_get_pincfg(codec, nid);
+ if (!(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
+ AC_DEFCFG_MISC_NO_PRESENCE))
+ codec->ignore_misc_bit = false;
+ conn = get_defcfg_connect(def_conf);
+ if (conn == AC_JACK_PORT_NONE)
+ continue;
+ loc = get_defcfg_location(def_conf);
+ dev = get_defcfg_device(def_conf);
+
+ /* workaround for buggy BIOS setups */
+ if (dev == AC_JACK_LINE_OUT) {
+ if (conn == AC_JACK_PORT_FIXED)
+ dev = AC_JACK_SPEAKER;
+ }
+
+ switch (dev) {
+ case AC_JACK_LINE_OUT:
+ seq = get_defcfg_sequence(def_conf);
+ assoc = get_defcfg_association(def_conf);
+
+ if (!(wid_caps & AC_WCAP_STEREO))
+ if (!cfg->mono_out_pin)
+ cfg->mono_out_pin = nid;
+ if (!assoc)
+ continue;
+ if (!assoc_line_out)
+ assoc_line_out = assoc;
+ else if (assoc_line_out != assoc)
+ continue;
+ if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins))
+ continue;
+ cfg->line_out_pins[cfg->line_outs] = nid;
+ sequences_line_out[cfg->line_outs] = seq;
+ cfg->line_outs++;
+ break;
+ case AC_JACK_SPEAKER:
+ seq = get_defcfg_sequence(def_conf);
+ assoc = get_defcfg_association(def_conf);
+ if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins))
+ continue;
+ cfg->speaker_pins[cfg->speaker_outs] = nid;
+ sequences_speaker[cfg->speaker_outs] = (assoc << 4) | seq;
+ cfg->speaker_outs++;
+ break;
+ case AC_JACK_HP_OUT:
+ seq = get_defcfg_sequence(def_conf);
+ assoc = get_defcfg_association(def_conf);
+ if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins))
+ continue;
+ cfg->hp_pins[cfg->hp_outs] = nid;
+ sequences_hp[cfg->hp_outs] = (assoc << 4) | seq;
+ cfg->hp_outs++;
+ break;
+ case AC_JACK_MIC_IN:
+ add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC);
+ break;
+ case AC_JACK_LINE_IN:
+ add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN);
+ break;
+ case AC_JACK_CD:
+ add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD);
+ break;
+ case AC_JACK_AUX:
+ add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX);
+ break;
+ case AC_JACK_SPDIF_OUT:
+ case AC_JACK_DIG_OTHER_OUT:
+ if (cfg->dig_outs >= ARRAY_SIZE(cfg->dig_out_pins))
+ continue;
+ cfg->dig_out_pins[cfg->dig_outs] = nid;
+ cfg->dig_out_type[cfg->dig_outs] =
+ (loc == AC_JACK_LOC_HDMI) ?
+ HDA_PCM_TYPE_HDMI : HDA_PCM_TYPE_SPDIF;
+ cfg->dig_outs++;
+ break;
+ case AC_JACK_SPDIF_IN:
+ case AC_JACK_DIG_OTHER_IN:
+ cfg->dig_in_pin = nid;
+ if (loc == AC_JACK_LOC_HDMI)
+ cfg->dig_in_type = HDA_PCM_TYPE_HDMI;
+ else
+ cfg->dig_in_type = HDA_PCM_TYPE_SPDIF;
+ break;
+ }
+ }
+
+ /* FIX-UP:
+ * If no line-out is defined but multiple HPs are found,
+ * some of them might be the real line-outs.
+ */
+ if (!cfg->line_outs && cfg->hp_outs > 1 &&
+ !(cond_flags & HDA_PINCFG_NO_HP_FIXUP)) {
+ int i = 0;
+ while (i < cfg->hp_outs) {
+ /* The real HPs should have the sequence 0x0f */
+ if ((sequences_hp[i] & 0x0f) == 0x0f) {
+ i++;
+ continue;
+ }
+ /* Move it to the line-out table */
+ cfg->line_out_pins[cfg->line_outs] = cfg->hp_pins[i];
+ sequences_line_out[cfg->line_outs] = sequences_hp[i];
+ cfg->line_outs++;
+ cfg->hp_outs--;
+ memmove(cfg->hp_pins + i, cfg->hp_pins + i + 1,
+ sizeof(cfg->hp_pins[0]) * (cfg->hp_outs - i));
+ memmove(sequences_hp + i, sequences_hp + i + 1,
+ sizeof(sequences_hp[0]) * (cfg->hp_outs - i));
+ }
+ memset(cfg->hp_pins + cfg->hp_outs, 0,
+ sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs));
+ if (!cfg->hp_outs)
+ cfg->line_out_type = AUTO_PIN_HP_OUT;
+
+ }
+
+ /* sort by sequence */
+ sort_pins_by_sequence(cfg->line_out_pins, sequences_line_out,
+ cfg->line_outs);
+ sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker,
+ cfg->speaker_outs);
+ sort_pins_by_sequence(cfg->hp_pins, sequences_hp,
+ cfg->hp_outs);
+
+ /*
+ * FIX-UP: if no line-outs are detected, try to use speaker or HP pin
+ * as a primary output
+ */
+ if (!cfg->line_outs &&
+ !(cond_flags & HDA_PINCFG_NO_LO_FIXUP)) {
+ if (cfg->speaker_outs) {
+ cfg->line_outs = cfg->speaker_outs;
+ memcpy(cfg->line_out_pins, cfg->speaker_pins,
+ sizeof(cfg->speaker_pins));
+ cfg->speaker_outs = 0;
+ memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
+ cfg->line_out_type = AUTO_PIN_SPEAKER_OUT;
+ } else if (cfg->hp_outs) {
+ cfg->line_outs = cfg->hp_outs;
+ memcpy(cfg->line_out_pins, cfg->hp_pins,
+ sizeof(cfg->hp_pins));
+ cfg->hp_outs = 0;
+ memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
+ cfg->line_out_type = AUTO_PIN_HP_OUT;
+ }
+ }
+
+ reorder_outputs(cfg->line_outs, cfg->line_out_pins);
+ reorder_outputs(cfg->hp_outs, cfg->hp_pins);
+ reorder_outputs(cfg->speaker_outs, cfg->speaker_pins);
+
+ sort_autocfg_input_pins(cfg);
+
+ /*
+ * debug prints of the parsed results
+ */
+ snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n",
+ cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1],
+ cfg->line_out_pins[2], cfg->line_out_pins[3],
+ cfg->line_out_pins[4],
+ cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" :
+ (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ?
+ "speaker" : "line"));
+ snd_printd(" speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
+ cfg->speaker_outs, cfg->speaker_pins[0],
+ cfg->speaker_pins[1], cfg->speaker_pins[2],
+ cfg->speaker_pins[3], cfg->speaker_pins[4]);
+ snd_printd(" hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
+ cfg->hp_outs, cfg->hp_pins[0],
+ cfg->hp_pins[1], cfg->hp_pins[2],
+ cfg->hp_pins[3], cfg->hp_pins[4]);
+ snd_printd(" mono: mono_out=0x%x\n", cfg->mono_out_pin);
+ if (cfg->dig_outs)
+ snd_printd(" dig-out=0x%x/0x%x\n",
+ cfg->dig_out_pins[0], cfg->dig_out_pins[1]);
+ snd_printd(" inputs:");
+ for (i = 0; i < cfg->num_inputs; i++) {
+ snd_printd(" %s=0x%x",
+ hda_get_autocfg_input_label(codec, cfg, i),
+ cfg->inputs[i].pin);
+ }
+ snd_printd("\n");
+ if (cfg->dig_in_pin)
+ snd_printd(" dig-in=0x%x\n", cfg->dig_in_pin);
+
+ return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_parse_pin_defcfg);
+
+int snd_hda_get_input_pin_attr(unsigned int def_conf)
+{
+ unsigned int loc = get_defcfg_location(def_conf);
+ unsigned int conn = get_defcfg_connect(def_conf);
+ if (conn == AC_JACK_PORT_NONE)
+ return INPUT_PIN_ATTR_UNUSED;
+ /* Windows may claim the internal mic to be BOTH, too */
+ if (conn == AC_JACK_PORT_FIXED || conn == AC_JACK_PORT_BOTH)
+ return INPUT_PIN_ATTR_INT;
+ if ((loc & 0x30) == AC_JACK_LOC_INTERNAL)
+ return INPUT_PIN_ATTR_INT;
+ if ((loc & 0x30) == AC_JACK_LOC_SEPARATE)
+ return INPUT_PIN_ATTR_DOCK;
+ if (loc == AC_JACK_LOC_REAR)
+ return INPUT_PIN_ATTR_REAR;
+ if (loc == AC_JACK_LOC_FRONT)
+ return INPUT_PIN_ATTR_FRONT;
+ return INPUT_PIN_ATTR_NORMAL;
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr);
+
+/**
+ * hda_get_input_pin_label - Give a label for the given input pin
+ *
+ * When check_location is true, the function checks the pin location
+ * for mic and line-in pins, and set an appropriate prefix like "Front",
+ * "Rear", "Internal".
+ */
+
+static const char *hda_get_input_pin_label(struct hda_codec *codec,
+ hda_nid_t pin, bool check_location)
+{
+ unsigned int def_conf;
+ static const char * const mic_names[] = {
+ "Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic",
+ };
+ int attr;
+
+ def_conf = snd_hda_codec_get_pincfg(codec, pin);
+
+ switch (get_defcfg_device(def_conf)) {
+ case AC_JACK_MIC_IN:
+ if (!check_location)
+ return "Mic";
+ attr = snd_hda_get_input_pin_attr(def_conf);
+ if (!attr)
+ return "None";
+ return mic_names[attr - 1];
+ case AC_JACK_LINE_IN:
+ if (!check_location)
+ return "Line";
+ attr = snd_hda_get_input_pin_attr(def_conf);
+ if (!attr)
+ return "None";
+ if (attr == INPUT_PIN_ATTR_DOCK)
+ return "Dock Line";
+ return "Line";
+ case AC_JACK_AUX:
+ return "Aux";
+ case AC_JACK_CD:
+ return "CD";
+ case AC_JACK_SPDIF_IN:
+ return "SPDIF In";
+ case AC_JACK_DIG_OTHER_IN:
+ return "Digital In";
+ default:
+ return "Misc";
+ }
+}
+
+/* Check whether the location prefix needs to be added to the label.
+ * If all mic-jacks are in the same location (e.g. rear panel), we don't
+ * have to put "Front" prefix to each label. In such a case, returns false.
+ */
+static int check_mic_location_need(struct hda_codec *codec,
+ const struct auto_pin_cfg *cfg,
+ int input)
+{
+ unsigned int defc;
+ int i, attr, attr2;
+
+ defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[input].pin);
+ attr = snd_hda_get_input_pin_attr(defc);
+ /* for internal or docking mics, we need locations */
+ if (attr <= INPUT_PIN_ATTR_NORMAL)
+ return 1;
+
+ attr = 0;
+ for (i = 0; i < cfg->num_inputs; i++) {
+ defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[i].pin);
+ attr2 = snd_hda_get_input_pin_attr(defc);
+ if (attr2 >= INPUT_PIN_ATTR_NORMAL) {
+ if (attr && attr != attr2)
+ return 1; /* different locations found */
+ attr = attr2;
+ }
+ }
+ return 0;
+}
+
+/**
+ * hda_get_autocfg_input_label - Get a label for the given input
+ *
+ * Get a label for the given input pin defined by the autocfg item.
+ * Unlike hda_get_input_pin_label(), this function checks all inputs
+ * defined in autocfg and avoids the redundant mic/line prefix as much as
+ * possible.
+ */
+const char *hda_get_autocfg_input_label(struct hda_codec *codec,
+ const struct auto_pin_cfg *cfg,
+ int input)
+{
+ int type = cfg->inputs[input].type;
+ int has_multiple_pins = 0;
+
+ if ((input > 0 && cfg->inputs[input - 1].type == type) ||
+ (input < cfg->num_inputs - 1 && cfg->inputs[input + 1].type == type))
+ has_multiple_pins = 1;
+ if (has_multiple_pins && type == AUTO_PIN_MIC)
+ has_multiple_pins &= check_mic_location_need(codec, cfg, input);
+ return hda_get_input_pin_label(codec, cfg->inputs[input].pin,
+ has_multiple_pins);
+}
+EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label);
+
+/* return the position of NID in the list, or -1 if not found */
+static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
+{
+ int i;
+ for (i = 0; i < nums; i++)
+ if (list[i] == nid)
+ return i;
+ return -1;
+}
+
+/* get a unique suffix or an index number */
+static const char *check_output_sfx(hda_nid_t nid, const hda_nid_t *pins,
+ int num_pins, int *indexp)
+{
+ static const char * const channel_sfx[] = {
+ " Front", " Surround", " CLFE", " Side"
+ };
+ int i;
+
+ i = find_idx_in_nid_list(nid, pins, num_pins);
+ if (i < 0)
+ return NULL;
+ if (num_pins == 1)
+ return "";
+ if (num_pins > ARRAY_SIZE(channel_sfx)) {
+ if (indexp)
+ *indexp = i;
+ return "";
+ }
+ return channel_sfx[i];
+}
+
+static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
+ const struct auto_pin_cfg *cfg,
+ const char *name, char *label, int maxlen,
+ int *indexp)
+{
+ unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
+ int attr = snd_hda_get_input_pin_attr(def_conf);
+ const char *pfx = "", *sfx = "";
+
+ /* handle as a speaker if it's a fixed line-out */
+ if (!strcmp(name, "Line Out") && attr == INPUT_PIN_ATTR_INT)
+ name = "Speaker";
+ /* check the location */
+ switch (attr) {
+ case INPUT_PIN_ATTR_DOCK:
+ pfx = "Dock ";
+ break;
+ case INPUT_PIN_ATTR_FRONT:
+ pfx = "Front ";
+ break;
+ }
+ if (cfg) {
+ /* try to give a unique suffix if needed */
+ sfx = check_output_sfx(nid, cfg->line_out_pins, cfg->line_outs,
+ indexp);
+ if (!sfx)
+ sfx = check_output_sfx(nid, cfg->speaker_pins, cfg->speaker_outs,
+ indexp);
+ if (!sfx) {
+ /* don't add channel suffix for Headphone controls */
+ int idx = find_idx_in_nid_list(nid, cfg->hp_pins,
+ cfg->hp_outs);
+ if (idx >= 0)
+ *indexp = idx;
+ sfx = "";
+ }
+ }
+ snprintf(label, maxlen, "%s%s%s", pfx, name, sfx);
+ return 1;
+}
+
+/**
+ * snd_hda_get_pin_label - Get a label for the given I/O pin
+ *
+ * Get a label for the given pin. This function works for both input and
+ * output pins. When @cfg is given as non-NULL, the function tries to get
+ * an optimized label using hda_get_autocfg_input_label().
+ *
+ * This function tries to give a unique label string for the pin as much as
+ * possible. For example, when the multiple line-outs are present, it adds
+ * the channel suffix like "Front", "Surround", etc (only when @cfg is given).
+ * If no unique name with a suffix is available and @indexp is non-NULL, the
+ * index number is stored in the pointer.
+ */
+int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
+ const struct auto_pin_cfg *cfg,
+ char *label, int maxlen, int *indexp)
+{
+ unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
+ const char *name = NULL;
+ int i;
+
+ if (indexp)
+ *indexp = 0;
+ if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
+ return 0;
+
+ switch (get_defcfg_device(def_conf)) {
+ case AC_JACK_LINE_OUT:
+ return fill_audio_out_name(codec, nid, cfg, "Line Out",
+ label, maxlen, indexp);
+ case AC_JACK_SPEAKER:
+ return fill_audio_out_name(codec, nid, cfg, "Speaker",
+ label, maxlen, indexp);
+ case AC_JACK_HP_OUT:
+ return fill_audio_out_name(codec, nid, cfg, "Headphone",
+ label, maxlen, indexp);
+ case AC_JACK_SPDIF_OUT:
+ case AC_JACK_DIG_OTHER_OUT:
+ if (get_defcfg_location(def_conf) == AC_JACK_LOC_HDMI)
+ name = "HDMI";
+ else
+ name = "SPDIF";
+ if (cfg && indexp) {
+ i = find_idx_in_nid_list(nid, cfg->dig_out_pins,
+ cfg->dig_outs);
+ if (i >= 0)
+ *indexp = i;
+ }
+ break;
+ default:
+ if (cfg) {
+ for (i = 0; i < cfg->num_inputs; i++) {
+ if (cfg->inputs[i].pin != nid)
+ continue;
+ name = hda_get_autocfg_input_label(codec, cfg, i);
+ if (name)
+ break;
+ }
+ }
+ if (!name)
+ name = hda_get_input_pin_label(codec, nid, true);
+ break;
+ }
+ if (!name)
+ return 0;
+ strlcpy(label, name, maxlen);
+ return 1;
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_pin_label);
+
+int snd_hda_gen_add_verbs(struct hda_gen_spec *spec,
+ const struct hda_verb *list)
+{
+ const struct hda_verb **v;
+ snd_array_init(&spec->verbs, sizeof(struct hda_verb *), 8);
+ v = snd_array_new(&spec->verbs);
+ if (!v)
+ return -ENOMEM;
+ *v = list;
+ return 0;
+}
+EXPORT_SYMBOL_HDA(snd_hda_gen_add_verbs);
+
+void snd_hda_gen_apply_verbs(struct hda_codec *codec)
+{
+ struct hda_gen_spec *spec = codec->spec;
+ int i;
+ for (i = 0; i < spec->verbs.used; i++) {
+ struct hda_verb **v = snd_array_elem(&spec->verbs, i);
+ snd_hda_sequence_write(codec, *v);
+ }
+}
+EXPORT_SYMBOL_HDA(snd_hda_gen_apply_verbs);
+
+void snd_hda_apply_pincfgs(struct hda_codec *codec,
+ const struct hda_pintbl *cfg)
+{
+ for (; cfg->nid; cfg++)
+ snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
+}
+EXPORT_SYMBOL_HDA(snd_hda_apply_pincfgs);
+
+void snd_hda_apply_fixup(struct hda_codec *codec, int action)
+{
+ struct hda_gen_spec *spec = codec->spec;
+ int id = spec->fixup_id;
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+ const char *modelname = spec->fixup_name;
+#endif
+ int depth = 0;
+
+ if (!spec->fixup_list)
+ return;
+
+ while (id >= 0) {
+ const struct hda_fixup *fix = spec->fixup_list + id;
+
+ switch (fix->type) {
+ case HDA_FIXUP_PINS:
+ if (action != HDA_FIXUP_ACT_PRE_PROBE || !fix->v.pins)
+ break;
+ snd_printdd(KERN_INFO SFX
+ "%s: Apply pincfg for %s\n",
+ codec->chip_name, modelname);
+ snd_hda_apply_pincfgs(codec, fix->v.pins);
+ break;
+ case HDA_FIXUP_VERBS:
+ if (action != HDA_FIXUP_ACT_PROBE || !fix->v.verbs)
+ break;
+ snd_printdd(KERN_INFO SFX
+ "%s: Apply fix-verbs for %s\n",
+ codec->chip_name, modelname);
+ snd_hda_gen_add_verbs(codec->spec, fix->v.verbs);
+ break;
+ case HDA_FIXUP_FUNC:
+ if (!fix->v.func)
+ break;
+ snd_printdd(KERN_INFO SFX
+ "%s: Apply fix-func for %s\n",
+ codec->chip_name, modelname);
+ fix->v.func(codec, fix, action);
+ break;
+ default:
+ snd_printk(KERN_ERR SFX
+ "%s: Invalid fixup type %d\n",
+ codec->chip_name, fix->type);
+ break;
+ }
+ if (!fix->chained)
+ break;
+ if (++depth > 10)
+ break;
+ id = fix->chain_id;
+ }
+}
+EXPORT_SYMBOL_HDA(snd_hda_apply_fixup);
+
+void snd_hda_pick_fixup(struct hda_codec *codec,
+ const struct hda_model_fixup *models,
+ const struct snd_pci_quirk *quirk,
+ const struct hda_fixup *fixlist)
+{
+ struct hda_gen_spec *spec = codec->spec;
+ const struct snd_pci_quirk *q;
+ int id = -1;
+ const char *name = NULL;
+
+ /* when model=nofixup is given, don't pick up any fixups */
+ if (codec->modelname && !strcmp(codec->modelname, "nofixup")) {
+ spec->fixup_list = NULL;
+ spec->fixup_id = -1;
+ return;
+ }
+
+ if (codec->modelname && models) {
+ while (models->name) {
+ if (!strcmp(codec->modelname, models->name)) {
+ id = models->id;
+ name = models->name;
+ break;
+ }
+ models++;
+ }
+ }
+ if (id < 0) {
+ q = snd_pci_quirk_lookup(codec->bus->pci, quirk);
+ if (q) {
+ id = q->value;
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+ name = q->name;
+#endif
+ }
+ }
+ if (id < 0) {
+ for (q = quirk; q->subvendor; q++) {
+ unsigned int vendorid =
+ q->subdevice | (q->subvendor << 16);
+ if (vendorid == codec->subsystem_id) {
+ id = q->value;
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+ name = q->name;
+#endif
+ break;
+ }
+ }
+ }
+
+ spec->fixup_id = id;
+ if (id >= 0) {
+ spec->fixup_list = fixlist;
+ spec->fixup_name = name;
+ }
+}
+EXPORT_SYMBOL_HDA(snd_hda_pick_fixup);
diff --git a/sound/pci/hda/hda_auto_parser.h b/sound/pci/hda/hda_auto_parser.h
new file mode 100644
index 000000000000..2a7889dfbd1b
--- /dev/null
+++ b/sound/pci/hda/hda_auto_parser.h
@@ -0,0 +1,160 @@
+/*
+ * BIOS auto-parser helper functions for HD-audio
+ *
+ * Copyright (c) 2012 Takashi Iwai <tiwai@suse.de>
+ *
+ * This driver 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.
+ */
+
+#ifndef __SOUND_HDA_AUTO_PARSER_H
+#define __SOUND_HDA_AUTO_PARSER_H
+
+/*
+ * Helper for automatic pin configuration
+ */
+
+enum {
+ AUTO_PIN_MIC,
+ AUTO_PIN_LINE_IN,
+ AUTO_PIN_CD,
+ AUTO_PIN_AUX,
+ AUTO_PIN_LAST
+};
+
+enum {
+ AUTO_PIN_LINE_OUT,
+ AUTO_PIN_SPEAKER_OUT,
+ AUTO_PIN_HP_OUT
+};
+
+#define AUTO_CFG_MAX_OUTS HDA_MAX_OUTS
+#define AUTO_CFG_MAX_INS 8
+
+struct auto_pin_cfg_item {
+ hda_nid_t pin;
+ int type;
+};
+
+struct auto_pin_cfg;
+const char *hda_get_autocfg_input_label(struct hda_codec *codec,
+ const struct auto_pin_cfg *cfg,
+ int input);
+int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
+ const struct auto_pin_cfg *cfg,
+ char *label, int maxlen, int *indexp);
+
+enum {
+ INPUT_PIN_ATTR_UNUSED, /* pin not connected */
+ INPUT_PIN_ATTR_INT, /* internal mic/line-in */
+ INPUT_PIN_ATTR_DOCK, /* docking mic/line-in */
+ INPUT_PIN_ATTR_NORMAL, /* mic/line-in jack */
+ INPUT_PIN_ATTR_FRONT, /* mic/line-in jack in front */
+ INPUT_PIN_ATTR_REAR, /* mic/line-in jack in rear */
+};
+
+int snd_hda_get_input_pin_attr(unsigned int def_conf);
+
+struct auto_pin_cfg {
+ int line_outs;
+ /* sorted in the order of Front/Surr/CLFE/Side */
+ hda_nid_t line_out_pins[AUTO_CFG_MAX_OUTS];
+ int speaker_outs;
+ hda_nid_t speaker_pins[AUTO_CFG_MAX_OUTS];
+ int hp_outs;
+ int line_out_type; /* AUTO_PIN_XXX_OUT */
+ hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS];
+ int num_inputs;
+ struct auto_pin_cfg_item inputs[AUTO_CFG_MAX_INS];
+ int dig_outs;
+ hda_nid_t dig_out_pins[2];
+ hda_nid_t dig_in_pin;
+ hda_nid_t mono_out_pin;
+ int dig_out_type[2]; /* HDA_PCM_TYPE_XXX */
+ int dig_in_type; /* HDA_PCM_TYPE_XXX */
+};
+
+/* bit-flags for snd_hda_parse_pin_def_config() behavior */
+#define HDA_PINCFG_NO_HP_FIXUP (1 << 0) /* no HP-split */
+#define HDA_PINCFG_NO_LO_FIXUP (1 << 1) /* don't take other outs as LO */
+
+int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
+ struct auto_pin_cfg *cfg,
+ const hda_nid_t *ignore_nids,
+ unsigned int cond_flags);
+
+/* older function */
+#define snd_hda_parse_pin_def_config(codec, cfg, ignore) \
+ snd_hda_parse_pin_defcfg(codec, cfg, ignore, 0)
+
+/*
+ */
+
+struct hda_gen_spec {
+ /* fix-up list */
+ int fixup_id;
+ const struct hda_fixup *fixup_list;
+ const char *fixup_name;
+
+ /* additional init verbs */
+ struct snd_array verbs;
+};
+
+
+/*
+ * Fix-up pin default configurations and add default verbs
+ */
+
+struct hda_pintbl {
+ hda_nid_t nid;
+ u32 val;
+};
+
+struct hda_model_fixup {
+ const int id;
+ const char *name;
+};
+
+struct hda_fixup {
+ int type;
+ bool chained;
+ int chain_id;
+ union {
+ const struct hda_pintbl *pins;
+ const struct hda_verb *verbs;
+ void (*func)(struct hda_codec *codec,
+ const struct hda_fixup *fix,
+ int action);
+ } v;
+};
+
+/* fixup types */
+enum {
+ HDA_FIXUP_INVALID,
+ HDA_FIXUP_PINS,
+ HDA_FIXUP_VERBS,
+ HDA_FIXUP_FUNC,
+};
+
+/* fixup action definitions */
+enum {
+ HDA_FIXUP_ACT_PRE_PROBE,
+ HDA_FIXUP_ACT_PROBE,
+ HDA_FIXUP_ACT_INIT,
+ HDA_FIXUP_ACT_BUILD,
+};
+
+int snd_hda_gen_add_verbs(struct hda_gen_spec *spec,
+ const struct hda_verb *list);
+void snd_hda_gen_apply_verbs(struct hda_codec *codec);
+void snd_hda_apply_pincfgs(struct hda_codec *codec,
+ const struct hda_pintbl *cfg);
+void snd_hda_apply_fixup(struct hda_codec *codec, int action);
+void snd_hda_pick_fixup(struct hda_codec *codec,
+ const struct hda_model_fixup *models,
+ const struct snd_pci_quirk *quirk,
+ const struct hda_fixup *fixlist);
+
+#endif /* __SOUND_HDA_AUTO_PARSER_H */
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 841475cc13b6..eb09a3348325 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -334,78 +334,67 @@ static hda_nid_t *lookup_conn_list(struct snd_array *array, hda_nid_t nid)
return NULL;
}
+/* read the connection and add to the cache */
+static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid)
+{
+ hda_nid_t list[HDA_MAX_CONNECTIONS];
+ int len;
+
+ len = snd_hda_get_raw_connections(codec, nid, list, ARRAY_SIZE(list));
+ if (len < 0)
+ return len;
+ return snd_hda_override_conn_list(codec, nid, len, list);
+}
+
/**
- * snd_hda_get_conn_list - get connection list
+ * snd_hda_get_connections - copy connection list
* @codec: the HDA codec
* @nid: NID to parse
- * @listp: the pointer to store NID list
+ * @conn_list: connection list array; when NULL, checks only the size
+ * @max_conns: max. number of connections to store
*
* Parses the connection list of the given widget and stores the list
* of NIDs.
*
* Returns the number of connections, or a negative error code.
*/
-int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
- const hda_nid_t **listp)
+int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
+ hda_nid_t *conn_list, int max_conns)
{
struct snd_array *array = &codec->conn_lists;
- int len, err;
- hda_nid_t list[HDA_MAX_CONNECTIONS];
+ int len;
hda_nid_t *p;
bool added = false;
again:
+ mutex_lock(&codec->hash_mutex);
+ len = -1;
/* if the connection-list is already cached, read it */
p = lookup_conn_list(array, nid);
if (p) {
- if (listp)
- *listp = p + 2;
- return p[1];
+ len = p[1];
+ if (conn_list && len > max_conns) {
+ snd_printk(KERN_ERR "hda_codec: "
+ "Too many connections %d for NID 0x%x\n",
+ len, nid);
+ mutex_unlock(&codec->hash_mutex);
+ return -EINVAL;
+ }
+ if (conn_list && len)
+ memcpy(conn_list, p + 2, len * sizeof(hda_nid_t));
}
+ mutex_unlock(&codec->hash_mutex);
+ if (len >= 0)
+ return len;
if (snd_BUG_ON(added))
return -EINVAL;
- /* read the connection and add to the cache */
- len = snd_hda_get_raw_connections(codec, nid, list, HDA_MAX_CONNECTIONS);
+ len = read_and_add_raw_conns(codec, nid);
if (len < 0)
return len;
- err = snd_hda_override_conn_list(codec, nid, len, list);
- if (err < 0)
- return err;
added = true;
goto again;
}
-EXPORT_SYMBOL_HDA(snd_hda_get_conn_list);
-
-/**
- * snd_hda_get_connections - copy connection list
- * @codec: the HDA codec
- * @nid: NID to parse
- * @conn_list: connection list array
- * @max_conns: max. number of connections to store
- *
- * Parses the connection list of the given widget and stores the list
- * of NIDs.
- *
- * Returns the number of connections, or a negative error code.
- */
-int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
- hda_nid_t *conn_list, int max_conns)
-{
- const hda_nid_t *list;
- int len = snd_hda_get_conn_list(codec, nid, &list);
-
- if (len <= 0)
- return len;
- if (len > max_conns) {
- snd_printk(KERN_ERR "hda_codec: "
- "Too many connections %d for NID 0x%x\n",
- len, nid);
- return -EINVAL;
- }
- memcpy(conn_list, list, len * sizeof(hda_nid_t));
- return len;
-}
EXPORT_SYMBOL_HDA(snd_hda_get_connections);
/**
@@ -543,6 +532,7 @@ int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
hda_nid_t *p;
int i, old_used;
+ mutex_lock(&codec->hash_mutex);
p = lookup_conn_list(array, nid);
if (p)
*p = -1; /* invalidate the old entry */
@@ -553,10 +543,12 @@ int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len,
for (i = 0; i < len; i++)
if (!add_conn_list(array, list[i]))
goto error_add;
+ mutex_unlock(&codec->hash_mutex);
return 0;
error_add:
array->used = old_used;
+ mutex_unlock(&codec->hash_mutex);
return -ENOMEM;
}
EXPORT_SYMBOL_HDA(snd_hda_override_conn_list);
@@ -1255,6 +1247,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
codec->addr = codec_addr;
mutex_init(&codec->spdif_mutex);
mutex_init(&codec->control_mutex);
+ mutex_init(&codec->hash_mutex);
init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info));
init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head));
snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32);
@@ -1264,15 +1257,9 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8);
snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64);
snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16);
- if (codec->bus->modelname) {
- codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
- if (!codec->modelname) {
- snd_hda_codec_free(codec);
- return -ENODEV;
- }
- }
#ifdef CONFIG_SND_HDA_POWER_SAVE
+ spin_lock_init(&codec->power_lock);
INIT_DELAYED_WORK(&codec->power_work, hda_power_work);
/* snd_hda_codec_new() marks the codec as power-up, and leave it as is.
* the caller has to power down appropriatley after initialization
@@ -1281,6 +1268,14 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
hda_keep_power_on(codec);
#endif
+ if (codec->bus->modelname) {
+ codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL);
+ if (!codec->modelname) {
+ snd_hda_codec_free(codec);
+ return -ENODEV;
+ }
+ }
+
list_add_tail(&codec->list, &bus->codec_list);
bus->caddr_tbl[codec_addr] = codec;
@@ -1603,6 +1598,60 @@ get_alloc_amp_hash(struct hda_codec *codec, u32 key)
return (struct hda_amp_info *)get_alloc_hash(&codec->amp_cache, key);
}
+/* overwrite the value with the key in the caps hash */
+static int write_caps_hash(struct hda_codec *codec, u32 key, unsigned int val)
+{
+ struct hda_amp_info *info;
+
+ mutex_lock(&codec->hash_mutex);
+ info = get_alloc_amp_hash(codec, key);
+ if (!info) {
+ mutex_unlock(&codec->hash_mutex);
+ return -EINVAL;
+ }
+ info->amp_caps = val;
+ info->head.val |= INFO_AMP_CAPS;
+ mutex_unlock(&codec->hash_mutex);
+ return 0;
+}
+
+/* query the value from the caps hash; if not found, fetch the current
+ * value from the given function and store in the hash
+ */
+static unsigned int
+query_caps_hash(struct hda_codec *codec, hda_nid_t nid, int dir, u32 key,
+ unsigned int (*func)(struct hda_codec *, hda_nid_t, int))
+{
+ struct hda_amp_info *info;
+ unsigned int val;
+
+ mutex_lock(&codec->hash_mutex);
+ info = get_alloc_amp_hash(codec, key);
+ if (!info) {
+ mutex_unlock(&codec->hash_mutex);
+ return 0;
+ }
+ if (!(info->head.val & INFO_AMP_CAPS)) {
+ mutex_unlock(&codec->hash_mutex); /* for reentrance */
+ val = func(codec, nid, dir);
+ write_caps_hash(codec, key, val);
+ } else {
+ val = info->amp_caps;
+ mutex_unlock(&codec->hash_mutex);
+ }
+ return val;
+}
+
+static unsigned int read_amp_cap(struct hda_codec *codec, hda_nid_t nid,
+ int direction)
+{
+ if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD))
+ nid = codec->afg;
+ return snd_hda_param_read(codec, nid,
+ direction == HDA_OUTPUT ?
+ AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
+}
+
/**
* query_amp_caps - query AMP capabilities
* @codec: the HD-auio codec
@@ -1617,22 +1666,9 @@ get_alloc_amp_hash(struct hda_codec *codec, u32 key)
*/
u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction)
{
- struct hda_amp_info *info;
-
- info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, 0));
- if (!info)
- return 0;
- if (!(info->head.val & INFO_AMP_CAPS)) {
- if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD))
- nid = codec->afg;
- info->amp_caps = snd_hda_param_read(codec, nid,
- direction == HDA_OUTPUT ?
- AC_PAR_AMP_OUT_CAP :
- AC_PAR_AMP_IN_CAP);
- if (info->amp_caps)
- info->head.val |= INFO_AMP_CAPS;
- }
- return info->amp_caps;
+ return query_caps_hash(codec, nid, direction,
+ HDA_HASH_KEY(nid, direction, 0),
+ read_amp_cap);
}
EXPORT_SYMBOL_HDA(query_amp_caps);
@@ -1652,34 +1688,12 @@ EXPORT_SYMBOL_HDA(query_amp_caps);
int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir,
unsigned int caps)
{
- struct hda_amp_info *info;
-
- info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, dir, 0));
- if (!info)
- return -EINVAL;
- info->amp_caps = caps;
- info->head.val |= INFO_AMP_CAPS;
- return 0;
+ return write_caps_hash(codec, HDA_HASH_KEY(nid, dir, 0), caps);
}
EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps);
-static unsigned int
-query_caps_hash(struct hda_codec *codec, hda_nid_t nid, u32 key,
- unsigned int (*func)(struct hda_codec *, hda_nid_t))
-{
- struct hda_amp_info *info;
-
- info = get_alloc_amp_hash(codec, key);
- if (!info)
- return 0;
- if (!info->head.val) {
- info->head.val |= INFO_AMP_CAPS;
- info->amp_caps = func(codec, nid);
- }
- return info->amp_caps;
-}
-
-static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid)
+static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid,
+ int dir)
{
return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP);
}
@@ -1697,7 +1711,7 @@ static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid)
*/
u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid)
{
- return query_caps_hash(codec, nid, HDA_HASH_PINCAP_KEY(nid),
+ return query_caps_hash(codec, nid, 0, HDA_HASH_PINCAP_KEY(nid),
read_pin_cap);
}
EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps);
@@ -1715,41 +1729,47 @@ EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps);
int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid,
unsigned int caps)
{
- struct hda_amp_info *info;
- info = get_alloc_amp_hash(codec, HDA_HASH_PINCAP_KEY(nid));
- if (!info)
- return -ENOMEM;
- info->amp_caps = caps;
- info->head.val |= INFO_AMP_CAPS;
- return 0;
+ return write_caps_hash(codec, HDA_HASH_PINCAP_KEY(nid), caps);
}
EXPORT_SYMBOL_HDA(snd_hda_override_pin_caps);
-/*
- * read the current volume to info
- * if the cache exists, read the cache value.
+/* read or sync the hash value with the current value;
+ * call within hash_mutex
*/
-static unsigned int get_vol_mute(struct hda_codec *codec,
- struct hda_amp_info *info, hda_nid_t nid,
- int ch, int direction, int index)
+static struct hda_amp_info *
+update_amp_hash(struct hda_codec *codec, hda_nid_t nid, int ch,
+ int direction, int index)
{
- u32 val, parm;
-
- if (info->head.val & INFO_AMP_VOL(ch))
- return info->vol[ch];
+ struct hda_amp_info *info;
+ unsigned int parm, val = 0;
+ bool val_read = false;
- parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT;
- parm |= direction == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
- parm |= index;
- val = snd_hda_codec_read(codec, nid, 0,
+ retry:
+ info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index));
+ if (!info)
+ return NULL;
+ if (!(info->head.val & INFO_AMP_VOL(ch))) {
+ if (!val_read) {
+ mutex_unlock(&codec->hash_mutex);
+ parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT;
+ parm |= direction == HDA_OUTPUT ?
+ AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT;
+ parm |= index;
+ val = snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_AMP_GAIN_MUTE, parm);
- info->vol[ch] = val & 0xff;
- info->head.val |= INFO_AMP_VOL(ch);
- return info->vol[ch];
+ val &= 0xff;
+ val_read = true;
+ mutex_lock(&codec->hash_mutex);
+ goto retry;
+ }
+ info->vol[ch] = val;
+ info->head.val |= INFO_AMP_VOL(ch);
+ }
+ return info;
}
/*
- * write the current volume in info to the h/w and update the cache
+ * write the current volume in info to the h/w
*/
static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info,
hda_nid_t nid, int ch, int direction, int index,
@@ -1766,7 +1786,6 @@ static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info,
else
parm |= val;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm);
- info->vol[ch] = val;
}
/**
@@ -1783,10 +1802,14 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch,
int direction, int index)
{
struct hda_amp_info *info;
- info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index));
- if (!info)
- return 0;
- return get_vol_mute(codec, info, nid, ch, direction, index);
+ unsigned int val = 0;
+
+ mutex_lock(&codec->hash_mutex);
+ info = update_amp_hash(codec, nid, ch, direction, index);
+ if (info)
+ val = info->vol[ch];
+ mutex_unlock(&codec->hash_mutex);
+ return val;
}
EXPORT_SYMBOL_HDA(snd_hda_codec_amp_read);
@@ -1808,15 +1831,23 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch,
{
struct hda_amp_info *info;
- info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx));
- if (!info)
- return 0;
if (snd_BUG_ON(mask & ~0xff))
mask &= 0xff;
val &= mask;
- val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask;
- if (info->vol[ch] == val)
+
+ mutex_lock(&codec->hash_mutex);
+ info = update_amp_hash(codec, nid, ch, direction, idx);
+ if (!info) {
+ mutex_unlock(&codec->hash_mutex);
+ return 0;
+ }
+ val |= info->vol[ch] & ~mask;
+ if (info->vol[ch] == val) {
+ mutex_unlock(&codec->hash_mutex);
return 0;
+ }
+ info->vol[ch] = val;
+ mutex_unlock(&codec->hash_mutex);
put_vol_mute(codec, info, nid, ch, direction, idx, val);
return 1;
}
@@ -2263,7 +2294,10 @@ int snd_hda_codec_reset(struct hda_codec *codec)
/* OK, let it free */
#ifdef CONFIG_SND_HDA_POWER_SAVE
- cancel_delayed_work(&codec->power_work);
+ cancel_delayed_work_sync(&codec->power_work);
+ codec->power_on = 0;
+ codec->power_transition = 0;
+ codec->power_jiffies = jiffies;
flush_workqueue(codec->bus->workq);
#endif
snd_hda_ctls_clear(codec);
@@ -2859,12 +2893,15 @@ static int snd_hda_spdif_default_get(struct snd_kcontrol *kcontrol,
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
int idx = kcontrol->private_value;
- struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
+ struct hda_spdif_out *spdif;
+ mutex_lock(&codec->spdif_mutex);
+ spdif = snd_array_elem(&codec->spdif_out, idx);
ucontrol->value.iec958.status[0] = spdif->status & 0xff;
ucontrol->value.iec958.status[1] = (spdif->status >> 8) & 0xff;
ucontrol->value.iec958.status[2] = (spdif->status >> 16) & 0xff;
ucontrol->value.iec958.status[3] = (spdif->status >> 24) & 0xff;
+ mutex_unlock(&codec->spdif_mutex);
return 0;
}
@@ -2950,12 +2987,14 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
int idx = kcontrol->private_value;
- struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
- hda_nid_t nid = spdif->nid;
+ struct hda_spdif_out *spdif;
+ hda_nid_t nid;
unsigned short val;
int change;
mutex_lock(&codec->spdif_mutex);
+ spdif = snd_array_elem(&codec->spdif_out, idx);
+ nid = spdif->nid;
spdif->status = ucontrol->value.iec958.status[0] |
((unsigned int)ucontrol->value.iec958.status[1] << 8) |
((unsigned int)ucontrol->value.iec958.status[2] << 16) |
@@ -2977,9 +3016,12 @@ static int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol,
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
int idx = kcontrol->private_value;
- struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
+ struct hda_spdif_out *spdif;
+ mutex_lock(&codec->spdif_mutex);
+ spdif = snd_array_elem(&codec->spdif_out, idx);
ucontrol->value.integer.value[0] = spdif->ctls & AC_DIG1_ENABLE;
+ mutex_unlock(&codec->spdif_mutex);
return 0;
}
@@ -2999,12 +3041,14 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol,
{
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
int idx = kcontrol->private_value;
- struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
- hda_nid_t nid = spdif->nid;
+ struct hda_spdif_out *spdif;
+ hda_nid_t nid;
unsigned short val;
int change;
mutex_lock(&codec->spdif_mutex);
+ spdif = snd_array_elem(&codec->spdif_out, idx);
+ nid = spdif->nid;
val = spdif->ctls & ~AC_DIG1_ENABLE;
if (ucontrol->value.integer.value[0])
val |= AC_DIG1_ENABLE;
@@ -3092,6 +3136,9 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec,
}
EXPORT_SYMBOL_HDA(snd_hda_create_spdif_out_ctls);
+/* get the hda_spdif_out entry from the given NID
+ * call within spdif_mutex lock
+ */
struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec,
hda_nid_t nid)
{
@@ -3108,9 +3155,10 @@ EXPORT_SYMBOL_HDA(snd_hda_spdif_out_of_nid);
void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx)
{
- struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
+ struct hda_spdif_out *spdif;
mutex_lock(&codec->spdif_mutex);
+ spdif = snd_array_elem(&codec->spdif_out, idx);
spdif->nid = (u16)-1;
mutex_unlock(&codec->spdif_mutex);
}
@@ -3118,10 +3166,11 @@ EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_unassign);
void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid)
{
- struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx);
+ struct hda_spdif_out *spdif;
unsigned short val;
mutex_lock(&codec->spdif_mutex);
+ spdif = snd_array_elem(&codec->spdif_out, idx);
if (spdif->nid != nid) {
spdif->nid = nid;
val = spdif->ctls;
@@ -3486,11 +3535,14 @@ static void hda_call_codec_suspend(struct hda_codec *codec)
codec->afg ? codec->afg : codec->mfg,
AC_PWRST_D3);
#ifdef CONFIG_SND_HDA_POWER_SAVE
- snd_hda_update_power_acct(codec);
cancel_delayed_work(&codec->power_work);
+ spin_lock(&codec->power_lock);
+ snd_hda_update_power_acct(codec);
+ trace_hda_power_down(codec);
codec->power_on = 0;
codec->power_transition = 0;
codec->power_jiffies = jiffies;
+ spin_unlock(&codec->power_lock);
#endif
}
@@ -3499,6 +3551,10 @@ static void hda_call_codec_suspend(struct hda_codec *codec)
*/
static void hda_call_codec_resume(struct hda_codec *codec)
{
+ /* set as if powered on for avoiding re-entering the resume
+ * in the resume / power-save sequence
+ */
+ hda_keep_power_on(codec);
hda_set_power_state(codec,
codec->afg ? codec->afg : codec->mfg,
AC_PWRST_D0);
@@ -3514,6 +3570,7 @@ static void hda_call_codec_resume(struct hda_codec *codec)
snd_hda_codec_resume_amp(codec);
snd_hda_codec_resume_cache(codec);
}
+ snd_hda_power_down(codec); /* flag down before returning */
}
#endif /* CONFIG_PM */
@@ -3665,7 +3722,8 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate,
}
EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format);
-static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid)
+static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid,
+ int dir)
{
unsigned int val = 0;
if (nid != codec->afg &&
@@ -3680,11 +3738,12 @@ static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid)
static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid)
{
- return query_caps_hash(codec, nid, HDA_HASH_PARPCM_KEY(nid),
+ return query_caps_hash(codec, nid, 0, HDA_HASH_PARPCM_KEY(nid),
get_pcm_param);
}
-static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid)
+static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid,
+ int dir)
{
unsigned int streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM);
if (!streams || streams == -1)
@@ -3696,7 +3755,7 @@ static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid)
static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid)
{
- return query_caps_hash(codec, nid, HDA_HASH_PARSTR_KEY(nid),
+ return query_caps_hash(codec, nid, 0, HDA_HASH_PARSTR_KEY(nid),
get_stream_param);
}
@@ -3775,11 +3834,13 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid,
bps = 20;
}
}
+#if 0 /* FIXME: CS4206 doesn't work, which is the only codec supporting float */
if (streams & AC_SUPFMT_FLOAT32) {
formats |= SNDRV_PCM_FMTBIT_FLOAT_LE;
if (!bps)
bps = 32;
}
+#endif
if (streams == AC_SUPFMT_AC3) {
/* should be exclusive */
/* temporary hack: we have still no proper support
@@ -4283,12 +4344,18 @@ static void hda_power_work(struct work_struct *work)
container_of(work, struct hda_codec, power_work.work);
struct hda_bus *bus = codec->bus;
+ spin_lock(&codec->power_lock);
+ if (codec->power_transition > 0) { /* during power-up sequence? */
+ spin_unlock(&codec->power_lock);
+ return;
+ }
if (!codec->power_on || codec->power_count) {
codec->power_transition = 0;
+ spin_unlock(&codec->power_lock);
return;
}
+ spin_unlock(&codec->power_lock);
- trace_hda_power_down(codec);
hda_call_codec_suspend(codec);
if (bus->ops.pm_notify)
bus->ops.pm_notify(bus);
@@ -4296,9 +4363,11 @@ static void hda_power_work(struct work_struct *work)
static void hda_keep_power_on(struct hda_codec *codec)
{
+ spin_lock(&codec->power_lock);
codec->power_count++;
codec->power_on = 1;
codec->power_jiffies = jiffies;
+ spin_unlock(&codec->power_lock);
}
/* update the power on/off account with the current jiffies */
@@ -4323,19 +4392,31 @@ void snd_hda_power_up(struct hda_codec *codec)
{
struct hda_bus *bus = codec->bus;
+ spin_lock(&codec->power_lock);
codec->power_count++;
- if (codec->power_on || codec->power_transition)
+ if (codec->power_on || codec->power_transition > 0) {
+ spin_unlock(&codec->power_lock);
return;
+ }
+ spin_unlock(&codec->power_lock);
+ cancel_delayed_work_sync(&codec->power_work);
+
+ spin_lock(&codec->power_lock);
trace_hda_power_up(codec);
snd_hda_update_power_acct(codec);
codec->power_on = 1;
codec->power_jiffies = jiffies;
+ codec->power_transition = 1; /* avoid reentrance */
+ spin_unlock(&codec->power_lock);
+
if (bus->ops.pm_notify)
bus->ops.pm_notify(bus);
hda_call_codec_resume(codec);
- cancel_delayed_work(&codec->power_work);
+
+ spin_lock(&codec->power_lock);
codec->power_transition = 0;
+ spin_unlock(&codec->power_lock);
}
EXPORT_SYMBOL_HDA(snd_hda_power_up);
@@ -4351,14 +4432,18 @@ EXPORT_SYMBOL_HDA(snd_hda_power_up);
*/
void snd_hda_power_down(struct hda_codec *codec)
{
+ spin_lock(&codec->power_lock);
--codec->power_count;
- if (!codec->power_on || codec->power_count || codec->power_transition)
+ if (!codec->power_on || codec->power_count || codec->power_transition) {
+ spin_unlock(&codec->power_lock);
return;
+ }
if (power_save(codec)) {
- codec->power_transition = 1; /* avoid reentrance */
+ codec->power_transition = -1; /* avoid reentrance */
queue_delayed_work(codec->bus->workq, &codec->power_work,
msecs_to_jiffies(power_save(codec) * 1000));
}
+ spin_unlock(&codec->power_lock);
}
EXPORT_SYMBOL_HDA(snd_hda_power_down);
@@ -4710,11 +4795,11 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,
{
const hda_nid_t *nids = mout->dac_nids;
int chs = substream->runtime->channels;
- struct hda_spdif_out *spdif =
- snd_hda_spdif_out_of_nid(codec, mout->dig_out_nid);
+ struct hda_spdif_out *spdif;
int i;
mutex_lock(&codec->spdif_mutex);
+ spdif = snd_hda_spdif_out_of_nid(codec, mout->dig_out_nid);
if (mout->dig_out_nid && mout->share_spdif &&
mout->dig_out_used != HDA_DIG_EXCLUSIVE) {
if (chs == 2 &&
@@ -4795,601 +4880,58 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
}
EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_cleanup);
-/*
- * Helper for automatic pin configuration
- */
-
-static int is_in_nid_list(hda_nid_t nid, const hda_nid_t *list)
-{
- for (; *list; list++)
- if (*list == nid)
- return 1;
- return 0;
-}
-
-
-/*
- * Sort an associated group of pins according to their sequence numbers.
- */
-static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences,
- int num_pins)
-{
- int i, j;
- short seq;
- hda_nid_t nid;
-
- for (i = 0; i < num_pins; i++) {
- for (j = i + 1; j < num_pins; j++) {
- if (sequences[i] > sequences[j]) {
- seq = sequences[i];
- sequences[i] = sequences[j];
- sequences[j] = seq;
- nid = pins[i];
- pins[i] = pins[j];
- pins[j] = nid;
- }
- }
- }
-}
-
-
-/* add the found input-pin to the cfg->inputs[] table */
-static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid,
- int type)
-{
- if (cfg->num_inputs < AUTO_CFG_MAX_INS) {
- cfg->inputs[cfg->num_inputs].pin = nid;
- cfg->inputs[cfg->num_inputs].type = type;
- cfg->num_inputs++;
- }
-}
-
-/* sort inputs in the order of AUTO_PIN_* type */
-static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg)
-{
- int i, j;
-
- for (i = 0; i < cfg->num_inputs; i++) {
- for (j = i + 1; j < cfg->num_inputs; j++) {
- if (cfg->inputs[i].type > cfg->inputs[j].type) {
- struct auto_pin_cfg_item tmp;
- tmp = cfg->inputs[i];
- cfg->inputs[i] = cfg->inputs[j];
- cfg->inputs[j] = tmp;
- }
- }
- }
-}
-
-/* Reorder the surround channels
- * ALSA sequence is front/surr/clfe/side
- * HDA sequence is:
- * 4-ch: front/surr => OK as it is
- * 6-ch: front/clfe/surr
- * 8-ch: front/clfe/rear/side|fc
- */
-static void reorder_outputs(unsigned int nums, hda_nid_t *pins)
-{
- hda_nid_t nid;
-
- switch (nums) {
- case 3:
- case 4:
- nid = pins[1];
- pins[1] = pins[2];
- pins[2] = nid;
- break;
- }
-}
-
-/*
- * Parse all pin widgets and store the useful pin nids to cfg
- *
- * The number of line-outs or any primary output is stored in line_outs,
- * and the corresponding output pins are assigned to line_out_pins[],
- * in the order of front, rear, CLFE, side, ...
- *
- * If more extra outputs (speaker and headphone) are found, the pins are
- * assisnged to hp_pins[] and speaker_pins[], respectively. If no line-out jack
- * is detected, one of speaker of HP pins is assigned as the primary
- * output, i.e. to line_out_pins[0]. So, line_outs is always positive
- * if any analog output exists.
- *
- * The analog input pins are assigned to inputs array.
- * The digital input/output pins are assigned to dig_in_pin and dig_out_pin,
- * respectively.
- */
-int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
- struct auto_pin_cfg *cfg,
- const hda_nid_t *ignore_nids,
- unsigned int cond_flags)
-{
- hda_nid_t nid, end_nid;
- short seq, assoc_line_out;
- short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)];
- short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)];
- short sequences_hp[ARRAY_SIZE(cfg->hp_pins)];
- int i;
-
- memset(cfg, 0, sizeof(*cfg));
-
- memset(sequences_line_out, 0, sizeof(sequences_line_out));
- memset(sequences_speaker, 0, sizeof(sequences_speaker));
- memset(sequences_hp, 0, sizeof(sequences_hp));
- assoc_line_out = 0;
-
- codec->ignore_misc_bit = true;
- end_nid = codec->start_nid + codec->num_nodes;
- for (nid = codec->start_nid; nid < end_nid; nid++) {
- unsigned int wid_caps = get_wcaps(codec, nid);
- unsigned int wid_type = get_wcaps_type(wid_caps);
- unsigned int def_conf;
- short assoc, loc, conn, dev;
-
- /* read all default configuration for pin complex */
- if (wid_type != AC_WID_PIN)
- continue;
- /* ignore the given nids (e.g. pc-beep returns error) */
- if (ignore_nids && is_in_nid_list(nid, ignore_nids))
- continue;
-
- def_conf = snd_hda_codec_get_pincfg(codec, nid);
- if (!(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) &
- AC_DEFCFG_MISC_NO_PRESENCE))
- codec->ignore_misc_bit = false;
- conn = get_defcfg_connect(def_conf);
- if (conn == AC_JACK_PORT_NONE)
- continue;
- loc = get_defcfg_location(def_conf);
- dev = get_defcfg_device(def_conf);
-
- /* workaround for buggy BIOS setups */
- if (dev == AC_JACK_LINE_OUT) {
- if (conn == AC_JACK_PORT_FIXED)
- dev = AC_JACK_SPEAKER;
- }
-
- switch (dev) {
- case AC_JACK_LINE_OUT:
- seq = get_defcfg_sequence(def_conf);
- assoc = get_defcfg_association(def_conf);
-
- if (!(wid_caps & AC_WCAP_STEREO))
- if (!cfg->mono_out_pin)
- cfg->mono_out_pin = nid;
- if (!assoc)
- continue;
- if (!assoc_line_out)
- assoc_line_out = assoc;
- else if (assoc_line_out != assoc)
- continue;
- if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins))
- continue;
- cfg->line_out_pins[cfg->line_outs] = nid;
- sequences_line_out[cfg->line_outs] = seq;
- cfg->line_outs++;
- break;
- case AC_JACK_SPEAKER:
- seq = get_defcfg_sequence(def_conf);
- assoc = get_defcfg_association(def_conf);
- if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins))
- continue;
- cfg->speaker_pins[cfg->speaker_outs] = nid;
- sequences_speaker[cfg->speaker_outs] = (assoc << 4) | seq;
- cfg->speaker_outs++;
- break;
- case AC_JACK_HP_OUT:
- seq = get_defcfg_sequence(def_conf);
- assoc = get_defcfg_association(def_conf);
- if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins))
- continue;
- cfg->hp_pins[cfg->hp_outs] = nid;
- sequences_hp[cfg->hp_outs] = (assoc << 4) | seq;
- cfg->hp_outs++;
- break;
- case AC_JACK_MIC_IN:
- add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC);
- break;
- case AC_JACK_LINE_IN:
- add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN);
- break;
- case AC_JACK_CD:
- add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD);
- break;
- case AC_JACK_AUX:
- add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX);
- break;
- case AC_JACK_SPDIF_OUT:
- case AC_JACK_DIG_OTHER_OUT:
- if (cfg->dig_outs >= ARRAY_SIZE(cfg->dig_out_pins))
- continue;
- cfg->dig_out_pins[cfg->dig_outs] = nid;
- cfg->dig_out_type[cfg->dig_outs] =
- (loc == AC_JACK_LOC_HDMI) ?
- HDA_PCM_TYPE_HDMI : HDA_PCM_TYPE_SPDIF;
- cfg->dig_outs++;
- break;
- case AC_JACK_SPDIF_IN:
- case AC_JACK_DIG_OTHER_IN:
- cfg->dig_in_pin = nid;
- if (loc == AC_JACK_LOC_HDMI)
- cfg->dig_in_type = HDA_PCM_TYPE_HDMI;
- else
- cfg->dig_in_type = HDA_PCM_TYPE_SPDIF;
- break;
- }
- }
-
- /* FIX-UP:
- * If no line-out is defined but multiple HPs are found,
- * some of them might be the real line-outs.
- */
- if (!cfg->line_outs && cfg->hp_outs > 1 &&
- !(cond_flags & HDA_PINCFG_NO_HP_FIXUP)) {
- int i = 0;
- while (i < cfg->hp_outs) {
- /* The real HPs should have the sequence 0x0f */
- if ((sequences_hp[i] & 0x0f) == 0x0f) {
- i++;
- continue;
- }
- /* Move it to the line-out table */
- cfg->line_out_pins[cfg->line_outs] = cfg->hp_pins[i];
- sequences_line_out[cfg->line_outs] = sequences_hp[i];
- cfg->line_outs++;
- cfg->hp_outs--;
- memmove(cfg->hp_pins + i, cfg->hp_pins + i + 1,
- sizeof(cfg->hp_pins[0]) * (cfg->hp_outs - i));
- memmove(sequences_hp + i, sequences_hp + i + 1,
- sizeof(sequences_hp[0]) * (cfg->hp_outs - i));
- }
- memset(cfg->hp_pins + cfg->hp_outs, 0,
- sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs));
- if (!cfg->hp_outs)
- cfg->line_out_type = AUTO_PIN_HP_OUT;
-
- }
-
- /* sort by sequence */
- sort_pins_by_sequence(cfg->line_out_pins, sequences_line_out,
- cfg->line_outs);
- sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker,
- cfg->speaker_outs);
- sort_pins_by_sequence(cfg->hp_pins, sequences_hp,
- cfg->hp_outs);
-
- /*
- * FIX-UP: if no line-outs are detected, try to use speaker or HP pin
- * as a primary output
- */
- if (!cfg->line_outs &&
- !(cond_flags & HDA_PINCFG_NO_LO_FIXUP)) {
- if (cfg->speaker_outs) {
- cfg->line_outs = cfg->speaker_outs;
- memcpy(cfg->line_out_pins, cfg->speaker_pins,
- sizeof(cfg->speaker_pins));
- cfg->speaker_outs = 0;
- memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
- cfg->line_out_type = AUTO_PIN_SPEAKER_OUT;
- } else if (cfg->hp_outs) {
- cfg->line_outs = cfg->hp_outs;
- memcpy(cfg->line_out_pins, cfg->hp_pins,
- sizeof(cfg->hp_pins));
- cfg->hp_outs = 0;
- memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
- cfg->line_out_type = AUTO_PIN_HP_OUT;
- }
- }
-
- reorder_outputs(cfg->line_outs, cfg->line_out_pins);
- reorder_outputs(cfg->hp_outs, cfg->hp_pins);
- reorder_outputs(cfg->speaker_outs, cfg->speaker_pins);
-
- sort_autocfg_input_pins(cfg);
-
- /*
- * debug prints of the parsed results
- */
- snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n",
- cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1],
- cfg->line_out_pins[2], cfg->line_out_pins[3],
- cfg->line_out_pins[4],
- cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" :
- (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ?
- "speaker" : "line"));
- snd_printd(" speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
- cfg->speaker_outs, cfg->speaker_pins[0],
- cfg->speaker_pins[1], cfg->speaker_pins[2],
- cfg->speaker_pins[3], cfg->speaker_pins[4]);
- snd_printd(" hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n",
- cfg->hp_outs, cfg->hp_pins[0],
- cfg->hp_pins[1], cfg->hp_pins[2],
- cfg->hp_pins[3], cfg->hp_pins[4]);
- snd_printd(" mono: mono_out=0x%x\n", cfg->mono_out_pin);
- if (cfg->dig_outs)
- snd_printd(" dig-out=0x%x/0x%x\n",
- cfg->dig_out_pins[0], cfg->dig_out_pins[1]);
- snd_printd(" inputs:");
- for (i = 0; i < cfg->num_inputs; i++) {
- snd_printd(" %s=0x%x",
- hda_get_autocfg_input_label(codec, cfg, i),
- cfg->inputs[i].pin);
- }
- snd_printd("\n");
- if (cfg->dig_in_pin)
- snd_printd(" dig-in=0x%x\n", cfg->dig_in_pin);
-
- return 0;
-}
-EXPORT_SYMBOL_HDA(snd_hda_parse_pin_defcfg);
-
-int snd_hda_get_input_pin_attr(unsigned int def_conf)
-{
- unsigned int loc = get_defcfg_location(def_conf);
- unsigned int conn = get_defcfg_connect(def_conf);
- if (conn == AC_JACK_PORT_NONE)
- return INPUT_PIN_ATTR_UNUSED;
- /* Windows may claim the internal mic to be BOTH, too */
- if (conn == AC_JACK_PORT_FIXED || conn == AC_JACK_PORT_BOTH)
- return INPUT_PIN_ATTR_INT;
- if ((loc & 0x30) == AC_JACK_LOC_INTERNAL)
- return INPUT_PIN_ATTR_INT;
- if ((loc & 0x30) == AC_JACK_LOC_SEPARATE)
- return INPUT_PIN_ATTR_DOCK;
- if (loc == AC_JACK_LOC_REAR)
- return INPUT_PIN_ATTR_REAR;
- if (loc == AC_JACK_LOC_FRONT)
- return INPUT_PIN_ATTR_FRONT;
- return INPUT_PIN_ATTR_NORMAL;
-}
-EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr);
-
-/**
- * hda_get_input_pin_label - Give a label for the given input pin
- *
- * When check_location is true, the function checks the pin location
- * for mic and line-in pins, and set an appropriate prefix like "Front",
- * "Rear", "Internal".
- */
-
-static const char *hda_get_input_pin_label(struct hda_codec *codec,
- hda_nid_t pin, bool check_location)
-{
- unsigned int def_conf;
- static const char * const mic_names[] = {
- "Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic",
- };
- int attr;
-
- def_conf = snd_hda_codec_get_pincfg(codec, pin);
-
- switch (get_defcfg_device(def_conf)) {
- case AC_JACK_MIC_IN:
- if (!check_location)
- return "Mic";
- attr = snd_hda_get_input_pin_attr(def_conf);
- if (!attr)
- return "None";
- return mic_names[attr - 1];
- case AC_JACK_LINE_IN:
- if (!check_location)
- return "Line";
- attr = snd_hda_get_input_pin_attr(def_conf);
- if (!attr)
- return "None";
- if (attr == INPUT_PIN_ATTR_DOCK)
- return "Dock Line";
- return "Line";
- case AC_JACK_AUX:
- return "Aux";
- case AC_JACK_CD:
- return "CD";
- case AC_JACK_SPDIF_IN:
- return "SPDIF In";
- case AC_JACK_DIG_OTHER_IN:
- return "Digital In";
- default:
- return "Misc";
- }
-}
-
-/* Check whether the location prefix needs to be added to the label.
- * If all mic-jacks are in the same location (e.g. rear panel), we don't
- * have to put "Front" prefix to each label. In such a case, returns false.
- */
-static int check_mic_location_need(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg,
- int input)
-{
- unsigned int defc;
- int i, attr, attr2;
-
- defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[input].pin);
- attr = snd_hda_get_input_pin_attr(defc);
- /* for internal or docking mics, we need locations */
- if (attr <= INPUT_PIN_ATTR_NORMAL)
- return 1;
-
- attr = 0;
- for (i = 0; i < cfg->num_inputs; i++) {
- defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[i].pin);
- attr2 = snd_hda_get_input_pin_attr(defc);
- if (attr2 >= INPUT_PIN_ATTR_NORMAL) {
- if (attr && attr != attr2)
- return 1; /* different locations found */
- attr = attr2;
- }
- }
- return 0;
-}
-
/**
- * hda_get_autocfg_input_label - Get a label for the given input
+ * snd_hda_get_default_vref - Get the default (mic) VREF pin bits
*
- * Get a label for the given input pin defined by the autocfg item.
- * Unlike hda_get_input_pin_label(), this function checks all inputs
- * defined in autocfg and avoids the redundant mic/line prefix as much as
- * possible.
- */
-const char *hda_get_autocfg_input_label(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg,
- int input)
-{
- int type = cfg->inputs[input].type;
- int has_multiple_pins = 0;
-
- if ((input > 0 && cfg->inputs[input - 1].type == type) ||
- (input < cfg->num_inputs - 1 && cfg->inputs[input + 1].type == type))
- has_multiple_pins = 1;
- if (has_multiple_pins && type == AUTO_PIN_MIC)
- has_multiple_pins &= check_mic_location_need(codec, cfg, input);
- return hda_get_input_pin_label(codec, cfg->inputs[input].pin,
- has_multiple_pins);
-}
-EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label);
-
-/* return the position of NID in the list, or -1 if not found */
-static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
-{
- int i;
- for (i = 0; i < nums; i++)
- if (list[i] == nid)
- return i;
- return -1;
-}
-
-/* get a unique suffix or an index number */
-static const char *check_output_sfx(hda_nid_t nid, const hda_nid_t *pins,
- int num_pins, int *indexp)
-{
- static const char * const channel_sfx[] = {
- " Front", " Surround", " CLFE", " Side"
- };
- int i;
-
- i = find_idx_in_nid_list(nid, pins, num_pins);
- if (i < 0)
- return NULL;
- if (num_pins == 1)
- return "";
- if (num_pins > ARRAY_SIZE(channel_sfx)) {
- if (indexp)
- *indexp = i;
- return "";
- }
- return channel_sfx[i];
-}
-
-static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
- const struct auto_pin_cfg *cfg,
- const char *name, char *label, int maxlen,
- int *indexp)
-{
- unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
- int attr = snd_hda_get_input_pin_attr(def_conf);
- const char *pfx = "", *sfx = "";
-
- /* handle as a speaker if it's a fixed line-out */
- if (!strcmp(name, "Line Out") && attr == INPUT_PIN_ATTR_INT)
- name = "Speaker";
- /* check the location */
- switch (attr) {
- case INPUT_PIN_ATTR_DOCK:
- pfx = "Dock ";
- break;
- case INPUT_PIN_ATTR_FRONT:
- pfx = "Front ";
- break;
- }
- if (cfg) {
- /* try to give a unique suffix if needed */
- sfx = check_output_sfx(nid, cfg->line_out_pins, cfg->line_outs,
- indexp);
- if (!sfx)
- sfx = check_output_sfx(nid, cfg->speaker_pins, cfg->speaker_outs,
- indexp);
- if (!sfx) {
- /* don't add channel suffix for Headphone controls */
- int idx = find_idx_in_nid_list(nid, cfg->hp_pins,
- cfg->hp_outs);
- if (idx >= 0)
- *indexp = idx;
- sfx = "";
+ * Guess the suitable VREF pin bits to be set as the pin-control value.
+ * Note: the function doesn't set the AC_PINCTL_IN_EN bit.
+ */
+unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin)
+{
+ unsigned int pincap;
+ unsigned int oldval;
+ oldval = snd_hda_codec_read(codec, pin, 0,
+ AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+ pincap = snd_hda_query_pin_caps(codec, pin);
+ pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
+ /* Exception: if the default pin setup is vref50, we give it priority */
+ if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50)
+ return AC_PINCTL_VREF_80;
+ else if (pincap & AC_PINCAP_VREF_50)
+ return AC_PINCTL_VREF_50;
+ else if (pincap & AC_PINCAP_VREF_100)
+ return AC_PINCTL_VREF_100;
+ else if (pincap & AC_PINCAP_VREF_GRD)
+ return AC_PINCTL_VREF_GRD;
+ return AC_PINCTL_VREF_HIZ;
+}
+EXPORT_SYMBOL_HDA(snd_hda_get_default_vref);
+
+int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
+ unsigned int val, bool cached)
+{
+ if (val) {
+ unsigned int cap = snd_hda_query_pin_caps(codec, pin);
+ if (cap && (val & AC_PINCTL_OUT_EN)) {
+ if (!(cap & AC_PINCAP_OUT))
+ val &= ~(AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
+ else if ((val & AC_PINCTL_HP_EN) &&
+ !(cap & AC_PINCAP_HP_DRV))
+ val &= ~AC_PINCTL_HP_EN;
}
- }
- snprintf(label, maxlen, "%s%s%s", pfx, name, sfx);
- return 1;
-}
-
-/**
- * snd_hda_get_pin_label - Get a label for the given I/O pin
- *
- * Get a label for the given pin. This function works for both input and
- * output pins. When @cfg is given as non-NULL, the function tries to get
- * an optimized label using hda_get_autocfg_input_label().
- *
- * This function tries to give a unique label string for the pin as much as
- * possible. For example, when the multiple line-outs are present, it adds
- * the channel suffix like "Front", "Surround", etc (only when @cfg is given).
- * If no unique name with a suffix is available and @indexp is non-NULL, the
- * index number is stored in the pointer.
- */
-int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
- const struct auto_pin_cfg *cfg,
- char *label, int maxlen, int *indexp)
-{
- unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
- const char *name = NULL;
- int i;
-
- if (indexp)
- *indexp = 0;
- if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE)
- return 0;
-
- switch (get_defcfg_device(def_conf)) {
- case AC_JACK_LINE_OUT:
- return fill_audio_out_name(codec, nid, cfg, "Line Out",
- label, maxlen, indexp);
- case AC_JACK_SPEAKER:
- return fill_audio_out_name(codec, nid, cfg, "Speaker",
- label, maxlen, indexp);
- case AC_JACK_HP_OUT:
- return fill_audio_out_name(codec, nid, cfg, "Headphone",
- label, maxlen, indexp);
- case AC_JACK_SPDIF_OUT:
- case AC_JACK_DIG_OTHER_OUT:
- if (get_defcfg_location(def_conf) == AC_JACK_LOC_HDMI)
- name = "HDMI";
- else
- name = "SPDIF";
- if (cfg && indexp) {
- i = find_idx_in_nid_list(nid, cfg->dig_out_pins,
- cfg->dig_outs);
- if (i >= 0)
- *indexp = i;
- }
- break;
- default:
- if (cfg) {
- for (i = 0; i < cfg->num_inputs; i++) {
- if (cfg->inputs[i].pin != nid)
- continue;
- name = hda_get_autocfg_input_label(codec, cfg, i);
- if (name)
- break;
- }
+ if (cap && (val & AC_PINCTL_IN_EN)) {
+ if (!(cap & AC_PINCAP_IN))
+ val &= ~(AC_PINCTL_IN_EN | AC_PINCTL_VREFEN);
}
- if (!name)
- name = hda_get_input_pin_label(codec, nid, true);
- break;
}
- if (!name)
- return 0;
- strlcpy(label, name, maxlen);
- return 1;
+ if (cached)
+ return snd_hda_codec_update_cache(codec, pin, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+ else
+ return snd_hda_codec_write(codec, pin, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, val);
}
-EXPORT_SYMBOL_HDA(snd_hda_get_pin_label);
+EXPORT_SYMBOL_HDA(_snd_hda_set_pin_ctl);
/**
* snd_hda_add_imux_item - Add an item to input_mux
@@ -5444,8 +4986,6 @@ int snd_hda_suspend(struct hda_bus *bus)
list_for_each_entry(codec, &bus->codec_list, list) {
if (hda_codec_is_power_on(codec))
hda_call_codec_suspend(codec);
- if (codec->patch_ops.post_suspend)
- codec->patch_ops.post_suspend(codec);
}
return 0;
}
@@ -5465,10 +5005,7 @@ int snd_hda_resume(struct hda_bus *bus)
struct hda_codec *codec;
list_for_each_entry(codec, &bus->codec_list, list) {
- if (codec->patch_ops.pre_resume)
- codec->patch_ops.pre_resume(codec);
- if (snd_hda_codec_needs_resume(codec))
- hda_call_codec_resume(codec);
+ hda_call_codec_resume(codec);
}
return 0;
}
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 56b4f74c0b13..54b52819fb47 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -704,8 +704,6 @@ struct hda_codec_ops {
unsigned int power_state);
#ifdef CONFIG_PM
int (*suspend)(struct hda_codec *codec, pm_message_t state);
- int (*post_suspend)(struct hda_codec *codec);
- int (*pre_resume)(struct hda_codec *codec);
int (*resume)(struct hda_codec *codec);
#endif
#ifdef CONFIG_SND_HDA_POWER_SAVE
@@ -829,6 +827,7 @@ struct hda_codec {
struct mutex spdif_mutex;
struct mutex control_mutex;
+ struct mutex hash_mutex;
struct snd_array spdif_out;
unsigned int spdif_in_enable; /* SPDIF input enable? */
const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */
@@ -861,12 +860,13 @@ struct hda_codec {
unsigned int no_jack_detect:1; /* Machine has no jack-detection */
#ifdef CONFIG_SND_HDA_POWER_SAVE
unsigned int power_on :1; /* current (global) power-state */
- unsigned int power_transition :1; /* power-state in transition */
+ int power_transition; /* power-state in transition */
int power_count; /* current (global) power refcount */
struct delayed_work power_work; /* delayed task for powerdown */
unsigned long power_on_acct;
unsigned long power_off_acct;
unsigned long power_jiffies;
+ spinlock_t power_lock;
#endif
/* codec-specific additional proc output */
@@ -911,10 +911,13 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid,
hda_nid_t *start_id);
int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid,
hda_nid_t *conn_list, int max_conns);
+static inline int
+snd_hda_get_num_conns(struct hda_codec *codec, hda_nid_t nid)
+{
+ return snd_hda_get_connections(codec, nid, NULL, 0);
+}
int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid,
hda_nid_t *conn_list, int max_conns);
-int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid,
- const hda_nid_t **listp);
int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums,
const hda_nid_t *list);
int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux,
@@ -1051,12 +1054,10 @@ const char *snd_hda_get_jack_location(u32 cfg);
#ifdef CONFIG_SND_HDA_POWER_SAVE
void snd_hda_power_up(struct hda_codec *codec);
void snd_hda_power_down(struct hda_codec *codec);
-#define snd_hda_codec_needs_resume(codec) codec->power_count
void snd_hda_update_power_acct(struct hda_codec *codec);
#else
static inline void snd_hda_power_up(struct hda_codec *codec) {}
static inline void snd_hda_power_down(struct hda_codec *codec) {}
-#define snd_hda_codec_needs_resume(codec) 1
#endif
#ifdef CONFIG_SND_HDA_PATCH_LOADER
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 1f350522bed4..4ab8102f87ea 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -497,6 +497,7 @@ enum {
AZX_DRIVER_NVIDIA,
AZX_DRIVER_TERA,
AZX_DRIVER_CTX,
+ AZX_DRIVER_CTHDA,
AZX_DRIVER_GENERIC,
AZX_NUM_DRIVERS, /* keep this as last entry */
};
@@ -518,6 +519,7 @@ enum {
#define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */
#define AZX_DCAPS_BUFSIZE (1 << 21) /* no buffer size alignment */
#define AZX_DCAPS_ALIGN_BUFSIZE (1 << 22) /* buffer size alignment */
+#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */
/* quirks for ATI SB / AMD Hudson */
#define AZX_DCAPS_PRESET_ATI_SB \
@@ -533,6 +535,9 @@ enum {
(AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI |\
AZX_DCAPS_ALIGN_BUFSIZE)
+#define AZX_DCAPS_PRESET_CTHDA \
+ (AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_4K_BDLE_BOUNDARY)
+
static char *driver_short_names[] __devinitdata = {
[AZX_DRIVER_ICH] = "HDA Intel",
[AZX_DRIVER_PCH] = "HDA Intel PCH",
@@ -546,6 +551,7 @@ static char *driver_short_names[] __devinitdata = {
[AZX_DRIVER_NVIDIA] = "HDA NVidia",
[AZX_DRIVER_TERA] = "HDA Teradici",
[AZX_DRIVER_CTX] = "HDA Creative",
+ [AZX_DRIVER_CTHDA] = "HDA Creative",
[AZX_DRIVER_GENERIC] = "HD-Audio Generic",
};
@@ -1285,7 +1291,8 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
/*
* set up a BDL entry
*/
-static int setup_bdle(struct snd_pcm_substream *substream,
+static int setup_bdle(struct azx *chip,
+ struct snd_pcm_substream *substream,
struct azx_dev *azx_dev, u32 **bdlp,
int ofs, int size, int with_ioc)
{
@@ -1304,6 +1311,12 @@ static int setup_bdle(struct snd_pcm_substream *substream,
bdl[1] = cpu_to_le32(upper_32_bits(addr));
/* program the size field of the BDL entry */
chunk = snd_pcm_sgbuf_get_chunk_size(substream, ofs, size);
+ /* one BDLE cannot cross 4K boundary on CTHDA chips */
+ if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) {
+ u32 remain = 0x1000 - (ofs & 0xfff);
+ if (chunk > remain)
+ chunk = remain;
+ }
bdl[2] = cpu_to_le32(chunk);
/* program the IOC to enable interrupt
* only when the whole fragment is processed
@@ -1356,7 +1369,7 @@ static int azx_setup_periods(struct azx *chip,
bdl_pos_adj[chip->dev_index]);
pos_adj = 0;
} else {
- ofs = setup_bdle(substream, azx_dev,
+ ofs = setup_bdle(chip, substream, azx_dev,
&bdl, ofs, pos_adj,
!substream->runtime->no_period_wakeup);
if (ofs < 0)
@@ -1366,10 +1379,10 @@ static int azx_setup_periods(struct azx *chip,
pos_adj = 0;
for (i = 0; i < periods; i++) {
if (i == periods - 1 && pos_adj)
- ofs = setup_bdle(substream, azx_dev, &bdl, ofs,
+ ofs = setup_bdle(chip, substream, azx_dev, &bdl, ofs,
period_bytes - pos_adj, 0);
else
- ofs = setup_bdle(substream, azx_dev, &bdl, ofs,
+ ofs = setup_bdle(chip, substream, azx_dev, &bdl, ofs,
period_bytes,
!substream->runtime->no_period_wakeup);
if (ofs < 0)
@@ -2353,17 +2366,6 @@ static void azx_power_notify(struct hda_bus *bus)
* power management
*/
-static int snd_hda_codecs_inuse(struct hda_bus *bus)
-{
- struct hda_codec *codec;
-
- list_for_each_entry(codec, &bus->codec_list, list) {
- if (snd_hda_codec_needs_resume(codec))
- return 1;
- }
- return 0;
-}
-
static int azx_suspend(struct pci_dev *pci, pm_message_t state)
{
struct snd_card *card = pci_get_drvdata(pci);
@@ -2410,8 +2412,7 @@ static int azx_resume(struct pci_dev *pci)
return -EIO;
azx_init_pci(chip);
- if (snd_hda_codecs_inuse(chip->bus))
- azx_init_chip(chip, 1);
+ azx_init_chip(chip, 1);
snd_hda_resume(chip->bus);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
@@ -2565,6 +2566,8 @@ static struct snd_pci_quirk probe_mask_list[] __devinitdata = {
/* forced codec slots */
SND_PCI_QUIRK(0x1043, 0x1262, "ASUS W5Fm", 0x103),
SND_PCI_QUIRK(0x1046, 0x1262, "ASUS W5F", 0x103),
+ /* WinFast VP200 H (Teradici) user reported broken communication */
+ SND_PCI_QUIRK(0x3a21, 0x040d, "WinFast VP200 H", 0x101),
{}
};
@@ -3130,6 +3133,11 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
.driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND |
AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB },
#endif
+ /* CTHDA chips */
+ { PCI_DEVICE(0x1102, 0x0010),
+ .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA },
+ { PCI_DEVICE(0x1102, 0x0012),
+ .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA },
/* Vortex86MX */
{ PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
/* VMware HDAudio */
@@ -3148,7 +3156,7 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
MODULE_DEVICE_TABLE(pci, azx_ids);
/* pci_driver definition */
-static struct pci_driver driver = {
+static struct pci_driver azx_driver = {
.name = KBUILD_MODNAME,
.id_table = azx_ids,
.probe = azx_probe,
@@ -3159,15 +3167,4 @@ static struct pci_driver driver = {
#endif
};
-static int __init alsa_card_azx_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_azx_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_azx_init)
-module_exit(alsa_card_azx_exit)
+module_pci_driver(azx_driver);
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
index d68948499fbc..2dd1c113a4c1 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -17,6 +17,7 @@
#include <sound/jack.h>
#include "hda_codec.h"
#include "hda_local.h"
+#include "hda_auto_parser.h"
#include "hda_jack.h"
bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h
index c66655cf413a..8ae52465ec5d 100644
--- a/sound/pci/hda/hda_jack.h
+++ b/sound/pci/hda/hda_jack.h
@@ -12,6 +12,8 @@
#ifndef __SOUND_HDA_JACK_H
#define __SOUND_HDA_JACK_H
+struct auto_pin_cfg;
+
struct hda_jack_tbl {
hda_nid_t nid;
unsigned char action; /* event action (0 = none) */
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 0ec9248165bc..9a096a8e0fc5 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -262,6 +262,8 @@ int snd_hda_input_mux_put(struct hda_codec *codec,
const struct hda_input_mux *imux,
struct snd_ctl_elem_value *ucontrol, hda_nid_t nid,
unsigned int *cur_val);
+int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
+ int index, int *type_index_ret);
/*
* Channel mode helper
@@ -393,72 +395,7 @@ struct hda_bus_unsolicited {
struct hda_bus *bus;
};
-/*
- * Helper for automatic pin configuration
- */
-
-enum {
- AUTO_PIN_MIC,
- AUTO_PIN_LINE_IN,
- AUTO_PIN_CD,
- AUTO_PIN_AUX,
- AUTO_PIN_LAST
-};
-
-enum {
- AUTO_PIN_LINE_OUT,
- AUTO_PIN_SPEAKER_OUT,
- AUTO_PIN_HP_OUT
-};
-
-#define AUTO_CFG_MAX_OUTS HDA_MAX_OUTS
-#define AUTO_CFG_MAX_INS 8
-
-struct auto_pin_cfg_item {
- hda_nid_t pin;
- int type;
-};
-
-struct auto_pin_cfg;
-const char *hda_get_autocfg_input_label(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg,
- int input);
-int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
- const struct auto_pin_cfg *cfg,
- char *label, int maxlen, int *indexp);
-int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label,
- int index, int *type_index_ret);
-
-enum {
- INPUT_PIN_ATTR_UNUSED, /* pin not connected */
- INPUT_PIN_ATTR_INT, /* internal mic/line-in */
- INPUT_PIN_ATTR_DOCK, /* docking mic/line-in */
- INPUT_PIN_ATTR_NORMAL, /* mic/line-in jack */
- INPUT_PIN_ATTR_FRONT, /* mic/line-in jack in front */
- INPUT_PIN_ATTR_REAR, /* mic/line-in jack in rear */
-};
-
-int snd_hda_get_input_pin_attr(unsigned int def_conf);
-
-struct auto_pin_cfg {
- int line_outs;
- /* sorted in the order of Front/Surr/CLFE/Side */
- hda_nid_t line_out_pins[AUTO_CFG_MAX_OUTS];
- int speaker_outs;
- hda_nid_t speaker_pins[AUTO_CFG_MAX_OUTS];
- int hp_outs;
- int line_out_type; /* AUTO_PIN_XXX_OUT */
- hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS];
- int num_inputs;
- struct auto_pin_cfg_item inputs[AUTO_CFG_MAX_INS];
- int dig_outs;
- hda_nid_t dig_out_pins[2];
- hda_nid_t dig_in_pin;
- hda_nid_t mono_out_pin;
- int dig_out_type[2]; /* HDA_PCM_TYPE_XXX */
- int dig_in_type; /* HDA_PCM_TYPE_XXX */
-};
-
+/* helper macros to retrieve pin default-config values */
#define get_defcfg_connect(cfg) \
((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT)
#define get_defcfg_association(cfg) \
@@ -472,19 +409,6 @@ struct auto_pin_cfg {
#define get_defcfg_misc(cfg) \
((cfg & AC_DEFCFG_MISC) >> AC_DEFCFG_MISC_SHIFT)
-/* bit-flags for snd_hda_parse_pin_def_config() behavior */
-#define HDA_PINCFG_NO_HP_FIXUP (1 << 0) /* no HP-split */
-#define HDA_PINCFG_NO_LO_FIXUP (1 << 1) /* don't take other outs as LO */
-
-int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
- struct auto_pin_cfg *cfg,
- const hda_nid_t *ignore_nids,
- unsigned int cond_flags);
-
-/* older function */
-#define snd_hda_parse_pin_def_config(codec, cfg, ignore) \
- snd_hda_parse_pin_defcfg(codec, cfg, ignore, 0)
-
/* amp values */
#define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8))
#define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8))
@@ -502,6 +426,46 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
#define PIN_HP (AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN)
#define PIN_HP_AMP (AC_PINCTL_HP_EN)
+unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin);
+int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
+ unsigned int val, bool cached);
+
+/**
+ * _snd_hda_set_pin_ctl - Set a pin-control value safely
+ * @codec: the codec instance
+ * @pin: the pin NID to set the control
+ * @val: the pin-control value (AC_PINCTL_* bits)
+ *
+ * This function sets the pin-control value to the given pin, but
+ * filters out the invalid pin-control bits when the pin has no such
+ * capabilities. For example, when PIN_HP is passed but the pin has no
+ * HP-drive capability, the HP bit is omitted.
+ *
+ * The function doesn't check the input VREF capability bits, though.
+ * Use snd_hda_get_default_vref() to guess the right value.
+ * Also, this function is only for analog pins, not for HDMI pins.
+ */
+static inline int
+snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin, unsigned int val)
+{
+ return _snd_hda_set_pin_ctl(codec, pin, val, false);
+}
+
+/**
+ * snd_hda_set_pin_ctl_cache - Set a pin-control value safely
+ * @codec: the codec instance
+ * @pin: the pin NID to set the control
+ * @val: the pin-control value (AC_PINCTL_* bits)
+ *
+ * Just like snd_hda_set_pin_ctl() but write to cache as well.
+ */
+static inline int
+snd_hda_set_pin_ctl_cache(struct hda_codec *codec, hda_nid_t pin,
+ unsigned int val)
+{
+ return _snd_hda_set_pin_ctl(codec, pin, val, true);
+}
+
/*
* get widget capabilities
*/
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 7143393927da..d8b2d6dee986 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -28,6 +28,7 @@
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
+#include "hda_auto_parser.h"
#include "hda_beep.h"
#include "hda_jack.h"
@@ -1742,9 +1743,7 @@ static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol,
if (! ad198x_eapd_put(kcontrol, ucontrol))
return 0;
/* change speaker pin appropriately */
- snd_hda_codec_write(codec, 0x05, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- spec->cur_eapd ? PIN_OUT : 0);
+ snd_hda_set_pin_ctl(codec, 0x05, spec->cur_eapd ? PIN_OUT : 0);
/* toggle HP mute appropriately */
snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0,
HDA_AMP_MUTE,
@@ -3103,7 +3102,7 @@ static void ad1988_auto_set_output_and_unmute(struct hda_codec *codec,
int dac_idx)
{
/* set as output */
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
+ snd_hda_set_pin_ctl(codec, nid, pin_type);
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
switch (nid) {
case 0x11: /* port-A - DAC 03 */
@@ -3157,6 +3156,7 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec)
for (i = 0; i < cfg->num_inputs; i++) {
hda_nid_t nid = cfg->inputs[i].pin;
int type = cfg->inputs[i].type;
+ int val;
switch (nid) {
case 0x15: /* port-C */
snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
@@ -3165,8 +3165,10 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec)
snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
break;
}
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
- type == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN);
+ val = PIN_IN;
+ if (type == AUTO_PIN_MIC)
+ val |= snd_hda_get_default_vref(codec, nid);
+ snd_hda_set_pin_ctl(codec, nid, val);
if (nid != AD1988_PIN_CD_NID)
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
AMP_OUT_MUTE);
diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c
index 09ccfabb4a17..19ae14f739cb 100644
--- a/sound/pci/hda/patch_ca0110.c
+++ b/sound/pci/hda/patch_ca0110.c
@@ -26,6 +26,7 @@
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
+#include "hda_auto_parser.h"
/*
*/
@@ -341,8 +342,7 @@ static int ca0110_build_pcms(struct hda_codec *codec)
static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
{
if (pin) {
- snd_hda_codec_write(codec, pin, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
+ snd_hda_set_pin_ctl(codec, pin, PIN_HP);
if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
snd_hda_codec_write(codec, pin, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
@@ -356,8 +356,8 @@ static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc)
{
if (pin) {
- snd_hda_codec_write(codec, pin, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80);
+ snd_hda_set_pin_ctl(codec, pin, PIN_IN |
+ snd_hda_get_default_vref(codec, pin));
if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP)
snd_hda_codec_write(codec, pin, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index 21d91d580da8..d0d3540e39e7 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -30,6 +30,7 @@
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
+#include "hda_auto_parser.h"
#define WIDGET_CHIP_CTRL 0x15
#define WIDGET_DSP_CTRL 0x16
@@ -239,8 +240,7 @@ enum get_set {
static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
{
if (pin) {
- snd_hda_codec_write(codec, pin, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
+ snd_hda_set_pin_ctl(codec, pin, PIN_HP);
if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
snd_hda_codec_write(codec, pin, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
@@ -254,9 +254,8 @@ static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc)
{
if (pin) {
- snd_hda_codec_write(codec, pin, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- PIN_VREF80);
+ snd_hda_set_pin_ctl(codec, pin, PIN_IN |
+ snd_hda_get_default_vref(codec, pin));
if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP)
snd_hda_codec_write(codec, pin, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index c83ccdba1e5a..9647ed4d7929 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -26,6 +26,7 @@
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
+#include "hda_auto_parser.h"
#include "hda_jack.h"
#include <sound/tlv.h>
@@ -933,8 +934,7 @@ static void cs_automute(struct hda_codec *codec)
pin_ctl = 0;
nid = cfg->speaker_pins[i];
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, pin_ctl);
+ snd_hda_set_pin_ctl(codec, nid, pin_ctl);
}
if (spec->gpio_eapd_hp) {
unsigned int gpio = hp_present ?
@@ -948,16 +948,14 @@ static void cs_automute(struct hda_codec *codec)
/* mute HPs if spdif jack (SENSE_B) is present */
for (i = 0; i < cfg->hp_outs; i++) {
nid = cfg->hp_pins[i];
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
+ snd_hda_set_pin_ctl(codec, nid,
(spdif_present && spec->sense_b) ? 0 : PIN_HP);
}
/* SPDIF TX on/off */
if (cfg->dig_outs) {
nid = cfg->dig_out_pins[0];
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
+ snd_hda_set_pin_ctl(codec, nid,
spdif_present ? PIN_OUT : 0);
}
@@ -1024,13 +1022,11 @@ static void init_output(struct hda_codec *codec)
/* set appropriate pin controls */
for (i = 0; i < cfg->line_outs; i++)
- snd_hda_codec_write(codec, cfg->line_out_pins[i], 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+ snd_hda_set_pin_ctl(codec, cfg->line_out_pins[i], PIN_OUT);
/* HP */
for (i = 0; i < cfg->hp_outs; i++) {
hda_nid_t nid = cfg->hp_pins[i];
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
+ snd_hda_set_pin_ctl(codec, nid, PIN_HP);
if (!cfg->speaker_outs)
continue;
if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
@@ -1041,8 +1037,7 @@ static void init_output(struct hda_codec *codec)
/* Speaker */
for (i = 0; i < cfg->speaker_outs; i++)
- snd_hda_codec_write(codec, cfg->speaker_pins[i], 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+ snd_hda_set_pin_ctl(codec, cfg->speaker_pins[i], PIN_OUT);
/* SPDIF is enabled on presence detect for CS421x */
if (spec->hp_detect || spec->spdif_detect)
@@ -1063,14 +1058,9 @@ static void init_input(struct hda_codec *codec)
continue;
/* set appropriate pin control and mute first */
ctl = PIN_IN;
- if (cfg->inputs[i].type == AUTO_PIN_MIC) {
- unsigned int caps = snd_hda_query_pin_caps(codec, pin);
- caps >>= AC_PINCAP_VREF_SHIFT;
- if (caps & AC_PINCAP_VREF_80)
- ctl = PIN_VREF80;
- }
- snd_hda_codec_write(codec, pin, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, ctl);
+ if (cfg->inputs[i].type == AUTO_PIN_MIC)
+ ctl |= snd_hda_get_default_vref(codec, pin);
+ snd_hda_set_pin_ctl(codec, pin, ctl);
snd_hda_codec_write(codec, spec->adc_nid[i], 0,
AC_VERB_SET_AMP_GAIN_MUTE,
AMP_IN_MUTE(spec->adc_idx[i]));
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index b6767b4ced44..c8fdaaefe702 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -29,6 +29,7 @@
#include <sound/core.h>
#include "hda_codec.h"
#include "hda_local.h"
+#include "hda_auto_parser.h"
#define NUM_PINS 11
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index d906c5b74cf0..3acb5824ad39 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -30,6 +30,7 @@
#include "hda_codec.h"
#include "hda_local.h"
+#include "hda_auto_parser.h"
#include "hda_beep.h"
#include "hda_jack.h"
@@ -66,6 +67,7 @@ struct imux_info {
};
struct conexant_spec {
+ struct hda_gen_spec gen;
const struct snd_kcontrol_new *mixers[5];
int num_mixers;
@@ -141,6 +143,7 @@ struct conexant_spec {
unsigned int hp_laptop:1;
unsigned int asus:1;
unsigned int pin_eapd_ctrls:1;
+ unsigned int fixup_stereo_dmic:1;
unsigned int adc_switching:1;
@@ -1601,17 +1604,13 @@ static void cxt5051_update_speaker(struct hda_codec *codec)
unsigned int pinctl;
/* headphone pin */
pinctl = (spec->hp_present && spec->cur_eapd) ? PIN_HP : 0;
- snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
- pinctl);
+ snd_hda_set_pin_ctl(codec, 0x16, pinctl);
/* speaker pin */
pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
- snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
- pinctl);
+ snd_hda_set_pin_ctl(codec, 0x1a, pinctl);
/* on ideapad there is an additional speaker (subwoofer) to mute */
if (spec->ideapad)
- snd_hda_codec_write(codec, 0x1b, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- pinctl);
+ snd_hda_set_pin_ctl(codec, 0x1b, pinctl);
}
/* turn on/off EAPD (+ mute HP) as a master switch */
@@ -1996,8 +1995,7 @@ static void cxt5066_update_speaker(struct hda_codec *codec)
/* Port A (HP) */
pinctl = (hp_port_a_present(spec) && spec->cur_eapd) ? PIN_HP : 0;
- snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
- pinctl);
+ snd_hda_set_pin_ctl(codec, 0x19, pinctl);
/* Port D (HP/LO) */
pinctl = spec->cur_eapd ? spec->port_d_mode : 0;
@@ -2010,13 +2008,11 @@ static void cxt5066_update_speaker(struct hda_codec *codec)
if (!hp_port_d_present(spec))
pinctl = 0;
}
- snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
- pinctl);
+ snd_hda_set_pin_ctl(codec, 0x1c, pinctl);
/* CLASS_D AMP */
pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
- snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
- pinctl);
+ snd_hda_set_pin_ctl(codec, 0x1f, pinctl);
}
/* turn on/off EAPD (+ mute HP) as a master switch */
@@ -2047,8 +2043,7 @@ static int cxt5066_set_olpc_dc_bias(struct hda_codec *codec)
/* Even though port F is the DC input, the bias is controlled on port B.
* we also leave that port as an active input (but unselected) in DC mode
* just in case that is necessary to make the bias setting take effect. */
- return snd_hda_codec_write_cache(codec, 0x1a, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
+ return snd_hda_set_pin_ctl_cache(codec, 0x1a,
cxt5066_olpc_dc_bias.items[spec->dc_input_bias].index);
}
@@ -2081,14 +2076,14 @@ static void cxt5066_olpc_select_mic(struct hda_codec *codec)
}
/* disable DC (port F) */
- snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+ snd_hda_set_pin_ctl(codec, 0x1e, 0);
/* external mic, port B */
- snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+ snd_hda_set_pin_ctl(codec, 0x1a,
spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0);
/* internal mic, port C */
- snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+ snd_hda_set_pin_ctl(codec, 0x1b,
spec->ext_mic_present ? 0 : PIN_VREF80);
}
@@ -3357,9 +3352,7 @@ static void do_automute(struct hda_codec *codec, int num_pins,
struct conexant_spec *spec = codec->spec;
int i;
for (i = 0; i < num_pins; i++)
- snd_hda_codec_write(codec, pins[i], 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- on ? PIN_OUT : 0);
+ snd_hda_set_pin_ctl(codec, pins[i], on ? PIN_OUT : 0);
if (spec->pin_eapd_ctrls)
cx_auto_turn_eapd(codec, num_pins, pins, on);
}
@@ -3976,8 +3969,7 @@ static void cx_auto_init_output(struct hda_codec *codec)
if (snd_hda_query_pin_caps(codec, cfg->hp_pins[i]) &
AC_PINCAP_HP_DRV)
val |= AC_PINCTL_HP_EN;
- snd_hda_codec_write(codec, cfg->hp_pins[i], 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+ snd_hda_set_pin_ctl(codec, cfg->hp_pins[i], val);
}
mute_outputs(codec, cfg->hp_outs, cfg->hp_pins);
mute_outputs(codec, cfg->line_outs, cfg->line_out_pins);
@@ -4030,13 +4022,11 @@ static void cx_auto_init_input(struct hda_codec *codec)
}
for (i = 0; i < cfg->num_inputs; i++) {
- unsigned int type;
+ hda_nid_t pin = cfg->inputs[i].pin;
+ unsigned int type = PIN_IN;
if (cfg->inputs[i].type == AUTO_PIN_MIC)
- type = PIN_VREF80;
- else
- type = PIN_IN;
- snd_hda_codec_write(codec, cfg->inputs[i].pin, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, type);
+ type |= snd_hda_get_default_vref(codec, pin);
+ snd_hda_set_pin_ctl(codec, pin, type);
}
if (spec->auto_mic) {
@@ -4063,11 +4053,9 @@ static void cx_auto_init_digital(struct hda_codec *codec)
struct auto_pin_cfg *cfg = &spec->autocfg;
if (spec->multiout.dig_out_nid)
- snd_hda_codec_write(codec, cfg->dig_out_pins[0], 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+ snd_hda_set_pin_ctl(codec, cfg->dig_out_pins[0], PIN_OUT);
if (spec->dig_in_nid)
- snd_hda_codec_write(codec, cfg->dig_in_pin, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
+ snd_hda_set_pin_ctl(codec, cfg->dig_in_pin, PIN_IN);
}
static int cx_auto_init(struct hda_codec *codec)
@@ -4084,9 +4072,9 @@ static int cx_auto_init(struct hda_codec *codec)
static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
const char *dir, int cidx,
- hda_nid_t nid, int hda_dir, int amp_idx)
+ hda_nid_t nid, int hda_dir, int amp_idx, int chs)
{
- static char name[32];
+ static char name[44];
static struct snd_kcontrol_new knew[] = {
HDA_CODEC_VOLUME(name, 0, 0, 0),
HDA_CODEC_MUTE(name, 0, 0, 0),
@@ -4096,7 +4084,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
for (i = 0; i < 2; i++) {
struct snd_kcontrol *kctl;
- knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, amp_idx,
+ knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, chs, amp_idx,
hda_dir);
knew[i].subdevice = HDA_SUBDEV_AMP_FLAG;
knew[i].index = cidx;
@@ -4115,7 +4103,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
}
#define cx_auto_add_volume(codec, str, dir, cidx, nid, hda_dir) \
- cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0)
+ cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0, 3)
#define cx_auto_add_pb_volume(codec, nid, str, idx) \
cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT)
@@ -4185,6 +4173,36 @@ static int cx_auto_build_output_controls(struct hda_codec *codec)
return 0;
}
+/* Returns zero if this is a normal stereo channel, and non-zero if it should
+ be split in two independent channels.
+ dest_label must be at least 44 characters. */
+static int cx_auto_get_rightch_label(struct hda_codec *codec, const char *label,
+ char *dest_label, int nid)
+{
+ struct conexant_spec *spec = codec->spec;
+ int i;
+
+ if (!spec->fixup_stereo_dmic)
+ return 0;
+
+ for (i = 0; i < AUTO_CFG_MAX_INS; i++) {
+ int def_conf;
+ if (spec->autocfg.inputs[i].pin != nid)
+ continue;
+
+ if (spec->autocfg.inputs[i].type != AUTO_PIN_MIC)
+ return 0;
+ def_conf = snd_hda_codec_get_pincfg(codec, nid);
+ if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT)
+ return 0;
+
+ /* Finally found the inverted internal mic! */
+ snprintf(dest_label, 44, "Inverted %s", label);
+ return 1;
+ }
+ return 0;
+}
+
static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid,
const char *label, const char *pfx,
int cidx)
@@ -4193,14 +4211,25 @@ static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid,
int i;
for (i = 0; i < spec->num_adc_nids; i++) {
+ char rightch_label[44];
hda_nid_t adc_nid = spec->adc_nids[i];
int idx = get_input_connection(codec, adc_nid, nid);
if (idx < 0)
continue;
if (codec->single_adc_amp)
idx = 0;
+
+ if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) {
+ /* Make two independent kcontrols for left and right */
+ int err = cx_auto_add_volume_idx(codec, label, pfx,
+ cidx, adc_nid, HDA_INPUT, idx, 1);
+ if (err < 0)
+ return err;
+ return cx_auto_add_volume_idx(codec, rightch_label, pfx,
+ cidx, adc_nid, HDA_INPUT, idx, 2);
+ }
return cx_auto_add_volume_idx(codec, label, pfx,
- cidx, adc_nid, HDA_INPUT, idx);
+ cidx, adc_nid, HDA_INPUT, idx, 3);
}
return 0;
}
@@ -4213,9 +4242,19 @@ static int cx_auto_add_boost_volume(struct hda_codec *codec, int idx,
int i, con;
nid = spec->imux_info[idx].pin;
- if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
+ if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
+ char rightch_label[44];
+ if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) {
+ int err = cx_auto_add_volume_idx(codec, label, " Boost",
+ cidx, nid, HDA_INPUT, 0, 1);
+ if (err < 0)
+ return err;
+ return cx_auto_add_volume_idx(codec, rightch_label, " Boost",
+ cidx, nid, HDA_INPUT, 0, 2);
+ }
return cx_auto_add_volume(codec, label, " Boost", cidx,
nid, HDA_INPUT);
+ }
con = __select_input_connection(codec, spec->imux_info[idx].adc, nid,
&mux, false, 0);
if (con < 0)
@@ -4370,37 +4409,21 @@ static const struct hda_codec_ops cx_auto_patch_ops = {
/*
* pin fix-up
*/
-struct cxt_pincfg {
- hda_nid_t nid;
- u32 val;
-};
-
-static void apply_pincfg(struct hda_codec *codec, const struct cxt_pincfg *cfg)
-{
- for (; cfg->nid; cfg++)
- snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
-
-}
-
-static void apply_pin_fixup(struct hda_codec *codec,
- const struct snd_pci_quirk *quirk,
- const struct cxt_pincfg **table)
-{
- quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
- if (quirk) {
- snd_printdd(KERN_INFO "hda_codec: applying pincfg for %s\n",
- quirk->name);
- apply_pincfg(codec, table[quirk->value]);
- }
-}
-
enum {
CXT_PINCFG_LENOVO_X200,
CXT_PINCFG_LENOVO_TP410,
+ CXT_FIXUP_STEREO_DMIC,
};
+static void cxt_fixup_stereo_dmic(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct conexant_spec *spec = codec->spec;
+ spec->fixup_stereo_dmic = 1;
+}
+
/* ThinkPad X200 & co with cxt5051 */
-static const struct cxt_pincfg cxt_pincfg_lenovo_x200[] = {
+static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
{ 0x16, 0x042140ff }, /* HP (seq# overridden) */
{ 0x17, 0x21a11000 }, /* dock-mic */
{ 0x19, 0x2121103f }, /* dock-HP */
@@ -4409,16 +4432,26 @@ static const struct cxt_pincfg cxt_pincfg_lenovo_x200[] = {
};
/* ThinkPad 410/420/510/520, X201 & co with cxt5066 */
-static const struct cxt_pincfg cxt_pincfg_lenovo_tp410[] = {
+static const struct hda_pintbl cxt_pincfg_lenovo_tp410[] = {
{ 0x19, 0x042110ff }, /* HP (seq# overridden) */
{ 0x1a, 0x21a190f0 }, /* dock-mic */
{ 0x1c, 0x212140ff }, /* dock-HP */
{}
};
-static const struct cxt_pincfg *cxt_pincfg_tbl[] = {
- [CXT_PINCFG_LENOVO_X200] = cxt_pincfg_lenovo_x200,
- [CXT_PINCFG_LENOVO_TP410] = cxt_pincfg_lenovo_tp410,
+static const struct hda_fixup cxt_fixups[] = {
+ [CXT_PINCFG_LENOVO_X200] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = cxt_pincfg_lenovo_x200,
+ },
+ [CXT_PINCFG_LENOVO_TP410] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = cxt_pincfg_lenovo_tp410,
+ },
+ [CXT_FIXUP_STEREO_DMIC] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cxt_fixup_stereo_dmic,
+ },
};
static const struct snd_pci_quirk cxt5051_fixups[] = {
@@ -4432,6 +4465,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410),
SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410),
SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410),
+ SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
{}
};
@@ -4471,13 +4505,16 @@ static int patch_conexant_auto(struct hda_codec *codec)
case 0x14f15051:
add_cx5051_fake_mutes(codec);
codec->pin_amp_workaround = 1;
- apply_pin_fixup(codec, cxt5051_fixups, cxt_pincfg_tbl);
+ snd_hda_pick_fixup(codec, NULL, cxt5051_fixups, cxt_fixups);
break;
default:
codec->pin_amp_workaround = 1;
- apply_pin_fixup(codec, cxt5066_fixups, cxt_pincfg_tbl);
+ snd_hda_pick_fixup(codec, NULL, cxt5066_fixups, cxt_fixups);
+ break;
}
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
/* Show mute-led control only on HP laptops
* This is a sort of white-list: on HP laptops, EAPD corresponds
* only to the mute-LED without actualy amp function. Meanwhile,
@@ -4556,6 +4593,12 @@ static const struct hda_codec_preset snd_hda_preset_conexant[] = {
.patch = patch_conexant_auto },
{ .id = 0x14f150b9, .name = "CX20665",
.patch = patch_conexant_auto },
+ { .id = 0x14f1510f, .name = "CX20751/2",
+ .patch = patch_conexant_auto },
+ { .id = 0x14f15110, .name = "CX20751/2",
+ .patch = patch_conexant_auto },
+ { .id = 0x14f15111, .name = "CX20753/4",
+ .patch = patch_conexant_auto },
{} /* terminator */
};
@@ -4576,6 +4619,9 @@ MODULE_ALIAS("snd-hda-codec-id:14f150ab");
MODULE_ALIAS("snd-hda-codec-id:14f150ac");
MODULE_ALIAS("snd-hda-codec-id:14f150b8");
MODULE_ALIAS("snd-hda-codec-id:14f150b9");
+MODULE_ALIAS("snd-hda-codec-id:14f1510f");
+MODULE_ALIAS("snd-hda-codec-id:14f15110");
+MODULE_ALIAS("snd-hda-codec-id:14f15111");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Conexant HD-audio codec");
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 83f345f3c961..ad319d4dc32f 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -1592,10 +1592,10 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
unsigned int dataDCC2, channel_id;
int i;
struct hdmi_spec *spec = codec->spec;
- struct hda_spdif_out *spdif =
- snd_hda_spdif_out_of_nid(codec, spec->cvts[0].cvt_nid);
+ struct hda_spdif_out *spdif;
mutex_lock(&codec->spdif_mutex);
+ spdif = snd_hda_spdif_out_of_nid(codec, spec->cvts[0].cvt_nid);
chs = substream->runtime->channels;
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 7810913d07a0..ff71dcef08ef 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -6,7 +6,7 @@
* Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
* PeiSen Hou <pshou@realtek.com.tw>
* Takashi Iwai <tiwai@suse.de>
- * Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
+ * Jonathan Woithe <jwoithe@just42.net>
*
* This driver is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -32,6 +32,7 @@
#include <sound/jack.h>
#include "hda_codec.h"
#include "hda_local.h"
+#include "hda_auto_parser.h"
#include "hda_beep.h"
#include "hda_jack.h"
@@ -66,8 +67,6 @@ struct alc_customize_define {
unsigned int fixup:1; /* Means that this sku is set by driver, not read from hw */
};
-struct alc_fixup;
-
struct alc_multi_io {
hda_nid_t pin; /* multi-io widget pin NID */
hda_nid_t dac; /* DAC to be connected */
@@ -82,19 +81,33 @@ enum {
#define MAX_VOL_NIDS 0x40
+/* make compatible with old code */
+#define alc_apply_pincfgs snd_hda_apply_pincfgs
+#define alc_apply_fixup snd_hda_apply_fixup
+#define alc_pick_fixup snd_hda_pick_fixup
+#define alc_fixup hda_fixup
+#define alc_pincfg hda_pintbl
+#define alc_model_fixup hda_model_fixup
+
+#define ALC_FIXUP_PINS HDA_FIXUP_PINS
+#define ALC_FIXUP_VERBS HDA_FIXUP_VERBS
+#define ALC_FIXUP_FUNC HDA_FIXUP_FUNC
+
+#define ALC_FIXUP_ACT_PRE_PROBE HDA_FIXUP_ACT_PRE_PROBE
+#define ALC_FIXUP_ACT_PROBE HDA_FIXUP_ACT_PROBE
+#define ALC_FIXUP_ACT_INIT HDA_FIXUP_ACT_INIT
+#define ALC_FIXUP_ACT_BUILD HDA_FIXUP_ACT_BUILD
+
+
struct alc_spec {
+ struct hda_gen_spec gen;
+
/* codec parameterization */
const struct snd_kcontrol_new *mixers[5]; /* mixer arrays */
unsigned int num_mixers;
const struct snd_kcontrol_new *cap_mixer; /* capture mixer */
unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
- const struct hda_verb *init_verbs[10]; /* initialization verbs
- * don't forget NULL
- * termination!
- */
- unsigned int num_init_verbs;
-
char stream_name_analog[32]; /* analog PCM stream */
const struct hda_pcm_stream *stream_analog_playback;
const struct hda_pcm_stream *stream_analog_capture;
@@ -210,11 +223,6 @@ struct alc_spec {
unsigned int pll_coef_idx, pll_coef_bit;
unsigned int coef0;
- /* fix-up list */
- int fixup_id;
- const struct alc_fixup *fixup_list;
- const char *fixup_name;
-
/* multi-io */
int multi_ios;
struct alc_multi_io multi_io[4];
@@ -319,13 +327,16 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
/* for shared I/O, change the pin-control accordingly */
if (spec->shared_mic_hp) {
+ unsigned int val;
+ hda_nid_t pin = spec->autocfg.inputs[1].pin;
/* NOTE: this assumes that there are only two inputs, the
* first is the real internal mic and the second is HP jack.
*/
- snd_hda_codec_write(codec, spec->autocfg.inputs[1].pin, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- spec->cur_mux[adc_idx] ?
- PIN_VREF80 : PIN_HP);
+ if (spec->cur_mux[adc_idx])
+ val = snd_hda_get_default_vref(codec, pin) | PIN_IN;
+ else
+ val = PIN_HP;
+ snd_hda_set_pin_ctl(codec, pin, val);
spec->automute_speaker = !spec->cur_mux[adc_idx];
call_update_outputs(codec);
}
@@ -338,7 +349,7 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
nid = get_capsrc(spec, adc_idx);
/* no selection? */
- num_conns = snd_hda_get_conn_list(codec, nid, NULL);
+ num_conns = snd_hda_get_num_conns(codec, nid);
if (num_conns <= 1)
return 1;
@@ -376,25 +387,9 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
int auto_pin_type)
{
unsigned int val = PIN_IN;
-
- if (auto_pin_type == AUTO_PIN_MIC) {
- unsigned int pincap;
- unsigned int oldval;
- oldval = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
- pincap = snd_hda_query_pin_caps(codec, nid);
- pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
- /* if the default pin setup is vref50, we give it priority */
- if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50)
- val = PIN_VREF80;
- else if (pincap & AC_PINCAP_VREF_50)
- val = PIN_VREF50;
- else if (pincap & AC_PINCAP_VREF_100)
- val = PIN_VREF100;
- else if (pincap & AC_PINCAP_VREF_GRD)
- val = PIN_VREFGRD;
- }
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+ if (auto_pin_type == AUTO_PIN_MIC)
+ val |= snd_hda_get_default_vref(codec, nid);
+ snd_hda_set_pin_ctl(codec, nid, val);
}
/*
@@ -409,13 +404,6 @@ static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix)
spec->mixers[spec->num_mixers++] = mix;
}
-static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
-{
- if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
- return;
- spec->init_verbs[spec->num_init_verbs++] = verb;
-}
-
/*
* GPIO setup tables, used in initialization
*/
@@ -517,9 +505,7 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
} else
val = 0;
val |= pin_bits;
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- val);
+ snd_hda_set_pin_ctl(codec, nid, val);
break;
case ALC_AUTOMUTE_AMP:
snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
@@ -1200,6 +1186,16 @@ static void alc_auto_check_switches(struct hda_codec *codec)
*/
#define ALC_FIXUP_SKU_IGNORE (2)
+static void alc_fixup_sku_ignore(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->cdefine.fixup = 1;
+ spec->cdefine.sku_cfg = ALC_FIXUP_SKU_IGNORE;
+ }
+}
+
static int alc_auto_parse_customize_define(struct hda_codec *codec)
{
unsigned int ass, tmp, i;
@@ -1403,178 +1399,6 @@ static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
}
/*
- * Fix-up pin default configurations and add default verbs
- */
-
-struct alc_pincfg {
- hda_nid_t nid;
- u32 val;
-};
-
-struct alc_model_fixup {
- const int id;
- const char *name;
-};
-
-struct alc_fixup {
- int type;
- bool chained;
- int chain_id;
- union {
- unsigned int sku;
- const struct alc_pincfg *pins;
- const struct hda_verb *verbs;
- void (*func)(struct hda_codec *codec,
- const struct alc_fixup *fix,
- int action);
- } v;
-};
-
-enum {
- ALC_FIXUP_INVALID,
- ALC_FIXUP_SKU,
- ALC_FIXUP_PINS,
- ALC_FIXUP_VERBS,
- ALC_FIXUP_FUNC,
-};
-
-enum {
- ALC_FIXUP_ACT_PRE_PROBE,
- ALC_FIXUP_ACT_PROBE,
- ALC_FIXUP_ACT_INIT,
- ALC_FIXUP_ACT_BUILD,
-};
-
-static void alc_apply_pincfgs(struct hda_codec *codec,
- const struct alc_pincfg *cfg)
-{
- for (; cfg->nid; cfg++)
- snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
-}
-
-static void alc_apply_fixup(struct hda_codec *codec, int action)
-{
- struct alc_spec *spec = codec->spec;
- int id = spec->fixup_id;
-#ifdef CONFIG_SND_DEBUG_VERBOSE
- const char *modelname = spec->fixup_name;
-#endif
- int depth = 0;
-
- if (!spec->fixup_list)
- return;
-
- while (id >= 0) {
- const struct alc_fixup *fix = spec->fixup_list + id;
- const struct alc_pincfg *cfg;
-
- switch (fix->type) {
- case ALC_FIXUP_SKU:
- if (action != ALC_FIXUP_ACT_PRE_PROBE || !fix->v.sku)
- break;
- snd_printdd(KERN_INFO "hda_codec: %s: "
- "Apply sku override for %s\n",
- codec->chip_name, modelname);
- spec->cdefine.sku_cfg = fix->v.sku;
- spec->cdefine.fixup = 1;
- break;
- case ALC_FIXUP_PINS:
- cfg = fix->v.pins;
- if (action != ALC_FIXUP_ACT_PRE_PROBE || !cfg)
- break;
- snd_printdd(KERN_INFO "hda_codec: %s: "
- "Apply pincfg for %s\n",
- codec->chip_name, modelname);
- alc_apply_pincfgs(codec, cfg);
- break;
- case ALC_FIXUP_VERBS:
- if (action != ALC_FIXUP_ACT_PROBE || !fix->v.verbs)
- break;
- snd_printdd(KERN_INFO "hda_codec: %s: "
- "Apply fix-verbs for %s\n",
- codec->chip_name, modelname);
- add_verb(codec->spec, fix->v.verbs);
- break;
- case ALC_FIXUP_FUNC:
- if (!fix->v.func)
- break;
- snd_printdd(KERN_INFO "hda_codec: %s: "
- "Apply fix-func for %s\n",
- codec->chip_name, modelname);
- fix->v.func(codec, fix, action);
- break;
- default:
- snd_printk(KERN_ERR "hda_codec: %s: "
- "Invalid fixup type %d\n",
- codec->chip_name, fix->type);
- break;
- }
- if (!fix->chained)
- break;
- if (++depth > 10)
- break;
- id = fix->chain_id;
- }
-}
-
-static void alc_pick_fixup(struct hda_codec *codec,
- const struct alc_model_fixup *models,
- const struct snd_pci_quirk *quirk,
- const struct alc_fixup *fixlist)
-{
- struct alc_spec *spec = codec->spec;
- const struct snd_pci_quirk *q;
- int id = -1;
- const char *name = NULL;
-
- /* when model=nofixup is given, don't pick up any fixups */
- if (codec->modelname && !strcmp(codec->modelname, "nofixup")) {
- spec->fixup_list = NULL;
- spec->fixup_id = -1;
- return;
- }
-
- if (codec->modelname && models) {
- while (models->name) {
- if (!strcmp(codec->modelname, models->name)) {
- id = models->id;
- name = models->name;
- break;
- }
- models++;
- }
- }
- if (id < 0) {
- q = snd_pci_quirk_lookup(codec->bus->pci, quirk);
- if (q) {
- id = q->value;
-#ifdef CONFIG_SND_DEBUG_VERBOSE
- name = q->name;
-#endif
- }
- }
- if (id < 0) {
- for (q = quirk; q->subvendor; q++) {
- unsigned int vendorid =
- q->subdevice | (q->subvendor << 16);
- if (vendorid == codec->subsystem_id) {
- id = q->value;
-#ifdef CONFIG_SND_DEBUG_VERBOSE
- name = q->name;
-#endif
- break;
- }
- }
- }
-
- spec->fixup_id = id;
- if (id >= 0) {
- spec->fixup_list = fixlist;
- spec->fixup_name = name;
- }
-}
-
-/*
* COEF access helper functions
*/
static int alc_read_coef_idx(struct hda_codec *codec,
@@ -1621,8 +1445,7 @@ static void alc_auto_init_digital(struct hda_codec *codec)
pin = spec->autocfg.dig_out_pins[i];
if (!pin)
continue;
- snd_hda_codec_write(codec, pin, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+ snd_hda_set_pin_ctl(codec, pin, PIN_OUT);
if (!i)
dac = spec->multiout.dig_out_nid;
else
@@ -1635,9 +1458,7 @@ static void alc_auto_init_digital(struct hda_codec *codec)
}
pin = spec->autocfg.dig_in_pin;
if (pin)
- snd_hda_codec_write(codec, pin, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- PIN_IN);
+ snd_hda_set_pin_ctl(codec, pin, PIN_IN);
}
/* parse digital I/Os and set up NIDs in BIOS auto-parse mode */
@@ -2068,7 +1889,6 @@ static void alc_auto_init_std(struct hda_codec *codec);
static int alc_init(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- unsigned int i;
if (spec->init_hook)
spec->init_hook(codec);
@@ -2076,8 +1896,6 @@ static int alc_init(struct hda_codec *codec)
alc_fix_pll(codec);
alc_auto_init_amp(codec, spec->init_amp);
- for (i = 0; i < spec->num_init_verbs; i++)
- snd_hda_sequence_write(codec, spec->init_verbs[i]);
alc_init_special_input_src(codec);
alc_auto_init_std(codec);
@@ -2725,7 +2543,6 @@ static int alc_auto_fill_adc_caps(struct hda_codec *codec)
nid = codec->start_nid;
for (i = 0; i < codec->num_nodes; i++, nid++) {
hda_nid_t src;
- const hda_nid_t *list;
unsigned int caps = get_wcaps(codec, nid);
int type = get_wcaps_type(caps);
@@ -2743,13 +2560,14 @@ static int alc_auto_fill_adc_caps(struct hda_codec *codec)
cap_nids[nums] = src;
break;
}
- n = snd_hda_get_conn_list(codec, src, &list);
+ n = snd_hda_get_num_conns(codec, src);
if (n > 1) {
cap_nids[nums] = src;
break;
} else if (n != 1)
break;
- src = *list;
+ if (snd_hda_get_connections(codec, src, &src, 1) != 1)
+ break;
}
if (++nums >= max_nums)
break;
@@ -2856,8 +2674,7 @@ static int alc_auto_create_shared_input(struct hda_codec *codec)
static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
unsigned int pin_type)
{
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
- pin_type);
+ snd_hda_set_pin_ctl(codec, nid, pin_type);
/* unmute pin */
if (nid_has_mute(codec, nid, HDA_OUTPUT))
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
@@ -2891,7 +2708,7 @@ static void alc_auto_init_analog_input(struct hda_codec *codec)
/* mute all loopback inputs */
if (spec->mixer_nid) {
- int nums = snd_hda_get_conn_list(codec, spec->mixer_nid, NULL);
+ int nums = snd_hda_get_num_conns(codec, spec->mixer_nid);
for (i = 0; i < nums; i++)
snd_hda_codec_write(codec, spec->mixer_nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE,
@@ -3521,7 +3338,7 @@ static int alc_auto_add_sw_ctl(struct hda_codec *codec,
if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT) {
type = ALC_CTL_WIDGET_MUTE;
val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT);
- } else if (snd_hda_get_conn_list(codec, nid, NULL) == 1) {
+ } else if (snd_hda_get_num_conns(codec, nid) == 1) {
type = ALC_CTL_WIDGET_MUTE;
val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT);
} else {
@@ -3998,9 +3815,7 @@ static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
snd_hda_codec_read(codec, nid, 0,
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
if (output) {
- snd_hda_codec_update_cache(codec, nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- PIN_OUT);
+ snd_hda_set_pin_ctl_cache(codec, nid, PIN_OUT);
if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
HDA_AMP_MUTE, 0);
@@ -4009,9 +3824,8 @@ static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
HDA_AMP_MUTE, HDA_AMP_MUTE);
- snd_hda_codec_update_cache(codec, nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- spec->multi_io[idx].ctl_in);
+ snd_hda_set_pin_ctl_cache(codec, nid,
+ spec->multi_io[idx].ctl_in);
}
return 0;
}
@@ -4084,7 +3898,7 @@ static void alc_remove_invalid_adc_nids(struct hda_codec *codec)
nums = 0;
for (n = 0; n < spec->num_adc_nids; n++) {
hda_nid_t cap = spec->private_capsrc_nids[n];
- int num_conns = snd_hda_get_conn_list(codec, cap, NULL);
+ int num_conns = snd_hda_get_num_conns(codec, cap);
for (i = 0; i < imux->num_items; i++) {
hda_nid_t pin = spec->imux_pins[i];
if (pin) {
@@ -4213,7 +4027,7 @@ static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
HDA_AMP_MUTE, 0);
- } else if (snd_hda_get_conn_list(codec, cap, NULL) > 1) {
+ } else if (snd_hda_get_num_conns(codec, cap) > 1) {
snd_hda_codec_write_cache(codec, cap, 0,
AC_VERB_SET_CONNECT_SEL, idx);
}
@@ -4427,6 +4241,25 @@ static int alc_parse_auto_config(struct hda_codec *codec,
return 1;
}
+/* common preparation job for alc_spec */
+static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid)
+{
+ struct alc_spec *spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ int err;
+
+ if (!spec)
+ return -ENOMEM;
+ codec->spec = spec;
+ spec->mixer_nid = mixer_nid;
+
+ err = alc_codec_rename_from_preset(codec);
+ if (err < 0) {
+ kfree(spec);
+ return err;
+ }
+ return 0;
+}
+
static int alc880_parse_auto_config(struct hda_codec *codec)
{
static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
@@ -4808,13 +4641,11 @@ static int patch_alc880(struct hda_codec *codec)
struct alc_spec *spec;
int err;
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- if (spec == NULL)
- return -ENOMEM;
-
- codec->spec = spec;
+ err = alc_alloc_spec(codec, 0x0b);
+ if (err < 0)
+ return err;
- spec->mixer_nid = 0x0b;
+ spec = codec->spec;
spec->need_dac_fix = 1;
alc_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl,
@@ -4890,7 +4721,7 @@ static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
spec->autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
snd_hda_jack_detect_enable(codec, 0x0f, ALC_HP_EVENT);
spec->unsol_event = alc_sku_unsol_event;
- add_verb(codec->spec, alc_gpio1_init_verbs);
+ snd_hda_gen_add_verbs(&spec->gen, alc_gpio1_init_verbs);
}
}
@@ -5001,13 +4832,11 @@ static int patch_alc260(struct hda_codec *codec)
struct alc_spec *spec;
int err;
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- if (spec == NULL)
- return -ENOMEM;
-
- codec->spec = spec;
+ err = alc_alloc_spec(codec, 0x07);
+ if (err < 0)
+ return err;
- spec->mixer_nid = 0x07;
+ spec = codec->spec;
alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
@@ -5171,8 +5000,7 @@ static void alc889_fixup_mbp_vref(struct hda_codec *codec,
val = snd_hda_codec_read(codec, nids[i], 0,
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
val |= AC_PINCTL_VREF_80;
- snd_hda_codec_write(codec, nids[i], 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+ snd_hda_set_pin_ctl(codec, nids[i], val);
spec->keep_vref_in_automute = 1;
break;
}
@@ -5193,8 +5021,7 @@ static void alc889_fixup_imac91_vref(struct hda_codec *codec,
val = snd_hda_codec_read(codec, nids[i], 0,
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
val |= AC_PINCTL_VREF_50;
- snd_hda_codec_write(codec, nids[i], 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+ snd_hda_set_pin_ctl(codec, nids[i], val);
}
spec->keep_vref_in_automute = 1;
}
@@ -5225,8 +5052,8 @@ static const struct alc_fixup alc882_fixups[] = {
}
},
[ALC882_FIXUP_ACER_ASPIRE_7736] = {
- .type = ALC_FIXUP_SKU,
- .v.sku = ALC_FIXUP_SKU_IGNORE,
+ .type = ALC_FIXUP_FUNC,
+ .v.func = alc_fixup_sku_ignore,
},
[ALC882_FIXUP_ASUS_W90V] = {
.type = ALC_FIXUP_PINS,
@@ -5476,13 +5303,11 @@ static int patch_alc882(struct hda_codec *codec)
struct alc_spec *spec;
int err;
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- if (spec == NULL)
- return -ENOMEM;
-
- codec->spec = spec;
+ err = alc_alloc_spec(codec, 0x0b);
+ if (err < 0)
+ return err;
- spec->mixer_nid = 0x0b;
+ spec = codec->spec;
switch (codec->vendor_id) {
case 0x10ec0882:
@@ -5494,10 +5319,6 @@ static int patch_alc882(struct hda_codec *codec)
break;
}
- err = alc_codec_rename_from_preset(codec);
- if (err < 0)
- goto error;
-
alc_pick_fixup(codec, alc882_fixup_models, alc882_fixup_tbl,
alc882_fixups);
alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
@@ -5621,13 +5442,11 @@ static int patch_alc262(struct hda_codec *codec)
struct alc_spec *spec;
int err;
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- if (spec == NULL)
- return -ENOMEM;
-
- codec->spec = spec;
+ err = alc_alloc_spec(codec, 0x0b);
+ if (err < 0)
+ return err;
- spec->mixer_nid = 0x0b;
+ spec = codec->spec;
#if 0
/* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is
@@ -5710,7 +5529,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec)
if (err > 0) {
if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d) {
add_mixer(spec, alc268_beep_mixer);
- add_verb(spec, alc268_beep_init_verbs);
+ snd_hda_gen_add_verbs(&spec->gen, alc268_beep_init_verbs);
}
}
return err;
@@ -5723,13 +5542,12 @@ static int patch_alc268(struct hda_codec *codec)
struct alc_spec *spec;
int i, has_beep, err;
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- if (spec == NULL)
- return -ENOMEM;
-
- codec->spec = spec;
-
/* ALC268 has no aa-loopback mixer */
+ err = alc_alloc_spec(codec, 0);
+ if (err < 0)
+ return err;
+
+ spec = codec->spec;
/* automatic parse from the BIOS config */
err = alc268_parse_auto_config(codec);
@@ -5946,9 +5764,7 @@ static void alc269_fixup_mic2_mute_hook(void *private_data, int enabled)
{
struct hda_codec *codec = private_data;
unsigned int pinval = enabled ? 0x20 : 0x24;
- snd_hda_codec_update_cache(codec, 0x19, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- pinval);
+ snd_hda_set_pin_ctl_cache(codec, 0x19, pinval);
}
static void alc269_fixup_mic2_mute(struct hda_codec *codec,
@@ -6015,8 +5831,8 @@ static const struct alc_fixup alc269_fixups[] = {
}
},
[ALC269_FIXUP_SKU_IGNORE] = {
- .type = ALC_FIXUP_SKU,
- .v.sku = ALC_FIXUP_SKU_IGNORE,
+ .type = ALC_FIXUP_FUNC,
+ .v.func = alc_fixup_sku_ignore,
},
[ALC269_FIXUP_ASUS_G73JW] = {
.type = ALC_FIXUP_PINS,
@@ -6242,19 +6058,13 @@ static void alc269_fill_coef(struct hda_codec *codec)
static int patch_alc269(struct hda_codec *codec)
{
struct alc_spec *spec;
- int err = 0;
-
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- if (spec == NULL)
- return -ENOMEM;
-
- codec->spec = spec;
-
- spec->mixer_nid = 0x0b;
+ int err;
- err = alc_codec_rename_from_preset(codec);
+ err = alc_alloc_spec(codec, 0x0b);
if (err < 0)
- goto error;
+ return err;
+
+ spec = codec->spec;
if (codec->vendor_id == 0x10ec0269) {
spec->codec_variant = ALC269_TYPE_ALC269VA;
@@ -6346,8 +6156,7 @@ static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec,
if (!(val & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)))
val |= AC_PINCTL_IN_EN;
val |= AC_PINCTL_VREF_50;
- snd_hda_codec_write(codec, 0x0f, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, val);
+ snd_hda_set_pin_ctl(codec, 0x0f, val);
spec->keep_vref_in_automute = 1;
}
@@ -6401,13 +6210,11 @@ static int patch_alc861(struct hda_codec *codec)
struct alc_spec *spec;
int err;
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- if (spec == NULL)
- return -ENOMEM;
-
- codec->spec = spec;
+ err = alc_alloc_spec(codec, 0x15);
+ if (err < 0)
+ return err;
- spec->mixer_nid = 0x15;
+ spec = codec->spec;
alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
@@ -6504,13 +6311,11 @@ static int patch_alc861vd(struct hda_codec *codec)
struct alc_spec *spec;
int err;
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- if (spec == NULL)
- return -ENOMEM;
-
- codec->spec = spec;
+ err = alc_alloc_spec(codec, 0x0b);
+ if (err < 0)
+ return err;
- spec->mixer_nid = 0x0b;
+ spec = codec->spec;
alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
@@ -6522,7 +6327,7 @@ static int patch_alc861vd(struct hda_codec *codec)
if (codec->vendor_id == 0x10ec0660) {
/* always turn on EAPD */
- add_verb(spec, alc660vd_eapd_verbs);
+ snd_hda_gen_add_verbs(&spec->gen, alc660vd_eapd_verbs);
}
if (!spec->no_analog) {
@@ -6635,8 +6440,8 @@ static const struct alc_fixup alc662_fixups[] = {
}
},
[ALC662_FIXUP_SKU_IGNORE] = {
- .type = ALC_FIXUP_SKU,
- .v.sku = ALC_FIXUP_SKU_IGNORE,
+ .type = ALC_FIXUP_FUNC,
+ .v.func = alc_fixup_sku_ignore,
},
[ALC662_FIXUP_HP_RP5800] = {
.type = ALC_FIXUP_PINS,
@@ -6849,25 +6654,19 @@ static const struct alc_model_fixup alc662_fixup_models[] = {
static int patch_alc662(struct hda_codec *codec)
{
struct alc_spec *spec;
- int err = 0;
-
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- if (!spec)
- return -ENOMEM;
+ int err;
- codec->spec = spec;
+ err = alc_alloc_spec(codec, 0x0b);
+ if (err < 0)
+ return err;
- spec->mixer_nid = 0x0b;
+ spec = codec->spec;
/* handle multiple HPs as is */
spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
alc_fix_pll_init(codec, 0x20, 0x04, 15);
- err = alc_codec_rename_from_preset(codec);
- if (err < 0)
- goto error;
-
if ((alc_get_coef0(codec) & (1 << 14)) &&
codec->bus->pci->subsystem_vendor == 0x1025 &&
spec->cdefine.platform_type == 1) {
@@ -6930,16 +6729,12 @@ static int alc680_parse_auto_config(struct hda_codec *codec)
*/
static int patch_alc680(struct hda_codec *codec)
{
- struct alc_spec *spec;
int err;
- spec = kzalloc(sizeof(*spec), GFP_KERNEL);
- if (spec == NULL)
- return -ENOMEM;
-
- codec->spec = spec;
-
/* ALC680 has no aa-loopback mixer */
+ err = alc_alloc_spec(codec, 0);
+ if (err < 0)
+ return err;
/* automatic parse from the BIOS config */
err = alc680_parse_auto_config(codec);
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 2cb1e08f962a..7db8228f1b88 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -36,6 +36,7 @@
#include <sound/tlv.h>
#include "hda_codec.h"
#include "hda_local.h"
+#include "hda_auto_parser.h"
#include "hda_beep.h"
#include "hda_jack.h"
@@ -221,6 +222,7 @@ struct sigmatel_spec {
unsigned char aloopback_shift;
/* power management */
+ unsigned int power_map_bits;
unsigned int num_pwrs;
const hda_nid_t *pwr_nids;
const hda_nid_t *dac_list;
@@ -314,6 +316,9 @@ struct sigmatel_spec {
struct hda_vmaster_mute_hook vmaster_mute;
};
+#define AC_VERB_IDT_SET_POWER_MAP 0x7ec
+#define AC_VERB_IDT_GET_POWER_MAP 0xfec
+
static const hda_nid_t stac9200_adc_nids[1] = {
0x03,
};
@@ -681,8 +686,7 @@ static int stac_vrefout_set(struct hda_codec *codec,
pinctl &= ~AC_PINCTL_VREFEN;
pinctl |= (new_vref & AC_PINCTL_VREFEN);
- error = snd_hda_codec_write_cache(codec, nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl);
+ error = snd_hda_set_pin_ctl_cache(codec, nid, pinctl);
if (error < 0)
return error;
@@ -706,8 +710,7 @@ static unsigned int stac92xx_vref_set(struct hda_codec *codec,
else
pincfg |= AC_PINCTL_IN_EN;
- error = snd_hda_codec_write_cache(codec, nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, pincfg);
+ error = snd_hda_set_pin_ctl_cache(codec, nid, pincfg);
if (error < 0)
return error;
else
@@ -2505,27 +2508,10 @@ static int stac92xx_build_pcms(struct hda_codec *codec)
return 0;
}
-static unsigned int stac92xx_get_default_vref(struct hda_codec *codec,
- hda_nid_t nid)
-{
- unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
- pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
- if (pincap & AC_PINCAP_VREF_100)
- return AC_PINCTL_VREF_100;
- if (pincap & AC_PINCAP_VREF_80)
- return AC_PINCTL_VREF_80;
- if (pincap & AC_PINCAP_VREF_50)
- return AC_PINCTL_VREF_50;
- if (pincap & AC_PINCAP_VREF_GRD)
- return AC_PINCTL_VREF_GRD;
- return 0;
-}
-
static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type)
{
- snd_hda_codec_write_cache(codec, nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
+ snd_hda_set_pin_ctl_cache(codec, nid, pin_type);
}
#define stac92xx_hp_switch_info snd_ctl_boolean_mono_info
@@ -2594,7 +2580,7 @@ static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol,
hda_nid_t nid = kcontrol->private_value;
unsigned int vref = stac92xx_vref_get(codec, nid);
- if (vref == stac92xx_get_default_vref(codec, nid))
+ if (vref == snd_hda_get_default_vref(codec, nid))
ucontrol->value.enumerated.item[0] = 0;
else if (vref == AC_PINCTL_VREF_GRD)
ucontrol->value.enumerated.item[0] = 1;
@@ -2613,7 +2599,7 @@ static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol,
hda_nid_t nid = kcontrol->private_value;
if (ucontrol->value.enumerated.item[0] == 0)
- new_vref = stac92xx_get_default_vref(codec, nid);
+ new_vref = snd_hda_get_default_vref(codec, nid);
else if (ucontrol->value.enumerated.item[0] == 1)
new_vref = AC_PINCTL_VREF_GRD;
else if (ucontrol->value.enumerated.item[0] == 2)
@@ -2679,7 +2665,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
else {
unsigned int pinctl = AC_PINCTL_IN_EN;
if (io_idx) /* set VREF for mic */
- pinctl |= stac92xx_get_default_vref(codec, nid);
+ pinctl |= snd_hda_get_default_vref(codec, nid);
stac92xx_auto_set_pinctl(codec, nid, pinctl);
}
@@ -2847,7 +2833,7 @@ static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec,
char name[22];
if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) {
- if (stac92xx_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD
+ if (snd_hda_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD
&& nid == spec->line_switch)
control = STAC_CTL_WIDGET_IO_SWITCH;
else if (snd_hda_query_pin_caps(codec, nid)
@@ -4250,13 +4236,6 @@ static void stac_store_hints(struct hda_codec *codec)
val = snd_hda_get_bool_hint(codec, "eapd_switch");
if (val >= 0)
spec->eapd_switch = val;
- get_int_hint(codec, "gpio_led_polarity", &spec->gpio_led_polarity);
- if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) {
- spec->gpio_mask |= spec->gpio_led;
- spec->gpio_dir |= spec->gpio_led;
- if (spec->gpio_led_polarity)
- spec->gpio_data |= spec->gpio_led;
- }
}
static void stac_issue_unsol_events(struct hda_codec *codec, int num_pins,
@@ -4354,7 +4333,7 @@ static int stac92xx_init(struct hda_codec *codec)
unsigned int pinctl, conf;
if (type == AUTO_PIN_MIC) {
/* for mic pins, force to initialize */
- pinctl = stac92xx_get_default_vref(codec, nid);
+ pinctl = snd_hda_get_default_vref(codec, nid);
pinctl |= AC_PINCTL_IN_EN;
stac92xx_auto_set_pinctl(codec, nid, pinctl);
} else {
@@ -4390,10 +4369,18 @@ static int stac92xx_init(struct hda_codec *codec)
hda_nid_t nid = spec->pwr_nids[i];
int pinctl, def_conf;
+ def_conf = snd_hda_codec_get_pincfg(codec, nid);
+ def_conf = get_defcfg_connect(def_conf);
+ if (def_conf == AC_JACK_PORT_NONE) {
+ /* power off unused ports */
+ stac_toggle_power_map(codec, nid, 0);
+ continue;
+ }
/* power on when no jack detection is available */
/* or when the VREF is used for controlling LED */
if (!spec->hp_detect ||
- spec->vref_mute_led_nid == nid) {
+ spec->vref_mute_led_nid == nid ||
+ !is_jack_detectable(codec, nid)) {
stac_toggle_power_map(codec, nid, 1);
continue;
}
@@ -4411,15 +4398,6 @@ static int stac92xx_init(struct hda_codec *codec)
stac_toggle_power_map(codec, nid, 1);
continue;
}
- def_conf = snd_hda_codec_get_pincfg(codec, nid);
- def_conf = get_defcfg_connect(def_conf);
- /* skip any ports that don't have jacks since presence
- * detection is useless */
- if (def_conf != AC_JACK_PORT_NONE &&
- !is_jack_detectable(codec, nid)) {
- stac_toggle_power_map(codec, nid, 1);
- continue;
- }
if (enable_pin_detect(codec, nid, STAC_PWR_EVENT)) {
stac_issue_unsol_event(codec, nid);
continue;
@@ -4432,6 +4410,12 @@ static int stac92xx_init(struct hda_codec *codec)
/* sync mute LED */
snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
+
+ /* sync the power-map */
+ if (spec->num_pwrs)
+ snd_hda_codec_write(codec, codec->afg, 0,
+ AC_VERB_IDT_SET_POWER_MAP,
+ spec->power_map_bits);
if (spec->dac_list)
stac92xx_power_down(codec);
return 0;
@@ -4460,8 +4444,7 @@ static void stac92xx_shutup_pins(struct hda_codec *codec)
struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i);
def_conf = snd_hda_codec_get_pincfg(codec, pin->nid);
if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)
- snd_hda_codec_write(codec, pin->nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+ snd_hda_set_pin_ctl(codec, pin->nid, 0);
}
}
@@ -4517,9 +4500,7 @@ static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid,
pin_ctl |= flag;
if (old_ctl != pin_ctl)
- snd_hda_codec_write_cache(codec, nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- pin_ctl);
+ snd_hda_set_pin_ctl_cache(codec, nid, pin_ctl);
}
static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
@@ -4528,9 +4509,7 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid,
unsigned int pin_ctl = snd_hda_codec_read(codec, nid,
0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00);
if (pin_ctl & flag)
- snd_hda_codec_write_cache(codec, nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- pin_ctl & ~flag);
+ snd_hda_set_pin_ctl_cache(codec, nid, pin_ctl & ~flag);
}
static inline int get_pin_presence(struct hda_codec *codec, hda_nid_t nid)
@@ -4682,14 +4661,18 @@ static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
idx = 1 << idx;
- val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0) & 0xff;
+ val = spec->power_map_bits;
if (enable)
val &= ~idx;
else
val |= idx;
/* power down unused output ports */
- snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
+ if (val != spec->power_map_bits) {
+ spec->power_map_bits = val;
+ snd_hda_codec_write(codec, codec->afg, 0,
+ AC_VERB_IDT_SET_POWER_MAP, val);
+ }
}
static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid)
@@ -4866,6 +4849,11 @@ static int find_mute_led_cfg(struct hda_codec *codec, int default_polarity)
struct sigmatel_spec *spec = codec->spec;
const struct dmi_device *dev = NULL;
+ if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) {
+ get_int_hint(codec, "gpio_led_polarity",
+ &spec->gpio_led_polarity);
+ return 1;
+ }
if ((codec->subsystem_id >> 16) == PCI_VENDOR_ID_HP) {
while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING,
NULL, dev))) {
@@ -4952,7 +4940,8 @@ static void stac92hd_proc_hook(struct snd_info_buffer *buffer,
{
if (nid == codec->afg)
snd_iprintf(buffer, "Power-Map: 0x%02x\n",
- snd_hda_codec_read(codec, nid, 0, 0x0fec, 0x0));
+ snd_hda_codec_read(codec, nid, 0,
+ AC_VERB_IDT_GET_POWER_MAP, 0));
}
static void analog_loop_proc_hook(struct snd_info_buffer *buffer,
@@ -5009,20 +4998,6 @@ static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state)
return 0;
}
-static int stac92xx_pre_resume(struct hda_codec *codec)
-{
- struct sigmatel_spec *spec = codec->spec;
-
- /* sync mute LED */
- if (spec->vref_mute_led_nid)
- stac_vrefout_set(codec, spec->vref_mute_led_nid,
- spec->vref_led);
- else if (spec->gpio_led)
- stac_gpio_set(codec, spec->gpio_mask,
- spec->gpio_dir, spec->gpio_data);
- return 0;
-}
-
static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg,
unsigned int power_state)
{
@@ -5046,7 +5021,6 @@ static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg,
#else
#define stac92xx_suspend NULL
#define stac92xx_resume NULL
-#define stac92xx_pre_resume NULL
#define stac92xx_set_power_state NULL
#endif /* CONFIG_PM */
@@ -5592,9 +5566,6 @@ again:
codec->patch_ops.set_power_state =
stac92xx_set_power_state;
}
-#ifdef CONFIG_PM
- codec->patch_ops.pre_resume = stac92xx_pre_resume;
-#endif
}
err = stac92xx_parse_auto_config(codec);
@@ -5901,9 +5872,6 @@ again:
codec->patch_ops.set_power_state =
stac92xx_set_power_state;
}
-#ifdef CONFIG_PM
- codec->patch_ops.pre_resume = stac92xx_pre_resume;
-#endif
}
spec->multiout.dac_nids = spec->dac_nids;
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 06214fdc9486..82b368068e08 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -54,6 +54,7 @@
#include <sound/asoundef.h>
#include "hda_codec.h"
#include "hda_local.h"
+#include "hda_auto_parser.h"
#include "hda_jack.h"
/* Pin Widget NID */
@@ -484,7 +485,7 @@ static void activate_output_mix(struct hda_codec *codec, struct nid_path *path,
if (!path)
return;
- num = snd_hda_get_conn_list(codec, mix_nid, NULL);
+ num = snd_hda_get_num_conns(codec, mix_nid);
for (i = 0; i < num; i++) {
if (i == idx)
val = AMP_IN_UNMUTE(i);
@@ -532,8 +533,7 @@ static void init_output_pin(struct hda_codec *codec, hda_nid_t pin,
{
if (!pin)
return;
- snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
- pin_type);
+ snd_hda_set_pin_ctl(codec, pin, pin_type);
if (snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD)
snd_hda_codec_write(codec, pin, 0,
AC_VERB_SET_EAPD_BTLENABLE, 0x02);
@@ -662,12 +662,12 @@ static void via_auto_init_analog_input(struct hda_codec *codec)
hda_nid_t nid = cfg->inputs[i].pin;
if (spec->smart51_enabled && is_smart51_pins(codec, nid))
ctl = PIN_OUT;
- else if (cfg->inputs[i].type == AUTO_PIN_MIC)
- ctl = PIN_VREF50;
- else
+ else {
ctl = PIN_IN;
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, ctl);
+ if (cfg->inputs[i].type == AUTO_PIN_MIC)
+ ctl |= snd_hda_get_default_vref(codec, nid);
+ }
+ snd_hda_set_pin_ctl(codec, nid, ctl);
}
/* init input-src */
@@ -1006,9 +1006,7 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol,
AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN);
parm |= out_in;
- snd_hda_codec_write(codec, nid, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- parm);
+ snd_hda_set_pin_ctl(codec, nid, parm);
if (out_in == AC_PINCTL_OUT_EN) {
mute_aa_path(codec, 1);
notify_aa_path_ctls(codec);
@@ -1647,8 +1645,7 @@ static void toggle_output_mutes(struct hda_codec *codec, int num_pins,
parm &= ~AC_PINCTL_OUT_EN;
else
parm |= AC_PINCTL_OUT_EN;
- snd_hda_codec_write(codec, pins[i], 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, parm);
+ snd_hda_set_pin_ctl(codec, pins[i], parm);
}
}
@@ -1709,8 +1706,7 @@ static void via_gpio_control(struct hda_codec *codec)
if (gpio_data == 0x02) {
/* unmute line out */
- snd_hda_codec_write(codec, spec->autocfg.line_out_pins[0], 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
+ snd_hda_set_pin_ctl(codec, spec->autocfg.line_out_pins[0],
PIN_OUT);
if (vol_counter & 0x20) {
/* decrease volume */
@@ -1728,9 +1724,7 @@ static void via_gpio_control(struct hda_codec *codec)
}
} else if (!(gpio_data & 0x02)) {
/* mute line out */
- snd_hda_codec_write(codec, spec->autocfg.line_out_pins[0], 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL,
- 0);
+ snd_hda_set_pin_ctl(codec, spec->autocfg.line_out_pins[0], 0);
}
}
@@ -2757,8 +2751,7 @@ static void via_auto_init_dig_in(struct hda_codec *codec)
struct via_spec *spec = codec->spec;
if (!spec->dig_in_nid)
return;
- snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0,
- AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
+ snd_hda_set_pin_ctl(codec, spec->autocfg.dig_in_pin, PIN_IN);
}
/* initialize the unsolicited events */
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index 132a86e09d07..5be2e120a14e 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -2803,22 +2803,11 @@ static void __devexit snd_ice1712_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver ice1712_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_ice1712_ids,
.probe = snd_ice1712_probe,
.remove = __devexit_p(snd_ice1712_remove),
};
-static int __init alsa_card_ice1712_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_ice1712_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_ice1712_init)
-module_exit(alsa_card_ice1712_exit)
+module_pci_driver(ice1712_driver);
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 812d10e43ae0..a01a00d1cf4d 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -2873,7 +2873,7 @@ static int snd_vt1724_resume(struct pci_dev *pci)
}
#endif
-static struct pci_driver driver = {
+static struct pci_driver vt1724_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_vt1724_ids,
.probe = snd_vt1724_probe,
@@ -2884,15 +2884,4 @@ static struct pci_driver driver = {
#endif
};
-static int __init alsa_card_ice1724_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_ice1724_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_ice1724_init)
-module_exit(alsa_card_ice1724_exit)
+module_pci_driver(vt1724_driver);
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index e0a4263baa20..f4e2dd4da8cf 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -3338,7 +3338,7 @@ static void __devexit snd_intel8x0_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver intel8x0_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_intel8x0_ids,
.probe = snd_intel8x0_probe,
@@ -3349,16 +3349,4 @@ static struct pci_driver driver = {
#endif
};
-
-static int __init alsa_card_intel8x0_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_intel8x0_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_intel8x0_init)
-module_exit(alsa_card_intel8x0_exit)
+module_pci_driver(intel8x0_driver);
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index d689913a61be..fc27a6a69e77 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -1324,7 +1324,7 @@ static void __devexit snd_intel8x0m_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver intel8x0m_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_intel8x0m_ids,
.probe = snd_intel8x0m_probe,
@@ -1335,16 +1335,4 @@ static struct pci_driver driver = {
#endif
};
-
-static int __init alsa_card_intel8x0m_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_intel8x0m_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_intel8x0m_init)
-module_exit(alsa_card_intel8x0m_exit)
+module_pci_driver(intel8x0m_driver);
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index 8fea45ab5882..e69ce5f9c31e 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -2476,22 +2476,11 @@ static void __devexit snd_korg1212_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver korg1212_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_korg1212_ids,
.probe = snd_korg1212_probe,
.remove = __devexit_p(snd_korg1212_remove),
};
-static int __init alsa_card_korg1212_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_korg1212_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_korg1212_init)
-module_exit(alsa_card_korg1212_exit)
+module_pci_driver(korg1212_driver);
diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c
index 375982736858..ac15166bee68 100644
--- a/sound/pci/lola/lola.c
+++ b/sound/pci/lola/lola.c
@@ -770,22 +770,11 @@ static DEFINE_PCI_DEVICE_TABLE(lola_ids) = {
MODULE_DEVICE_TABLE(pci, lola_ids);
/* pci_driver definition */
-static struct pci_driver driver = {
+static struct pci_driver lola_driver = {
.name = KBUILD_MODNAME,
.id_table = lola_ids,
.probe = lola_probe,
.remove = __devexit_p(lola_remove),
};
-static int __init alsa_card_lola_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_lola_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_lola_init)
-module_exit(alsa_card_lola_exit)
+module_pci_driver(lola_driver);
diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c
index d94c0c292bd0..d1ab43706735 100644
--- a/sound/pci/lx6464es/lx6464es.c
+++ b/sound/pci/lx6464es/lx6464es.c
@@ -1141,24 +1141,11 @@ static void __devexit snd_lx6464es_remove(struct pci_dev *pci)
}
-static struct pci_driver driver = {
+static struct pci_driver lx6464es_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_lx6464es_ids,
.probe = snd_lx6464es_probe,
.remove = __devexit_p(snd_lx6464es_remove),
};
-
-/* module initialization */
-static int __init mod_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit mod_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(mod_init);
-module_exit(mod_exit);
+module_pci_driver(lx6464es_driver);
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 78229b0dad2b..deef21399586 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -2837,7 +2837,7 @@ static void __devexit snd_m3_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver m3_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_m3_ids,
.probe = snd_m3_probe,
@@ -2848,15 +2848,4 @@ static struct pci_driver driver = {
#endif
};
-static int __init alsa_card_m3_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_m3_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_m3_init)
-module_exit(alsa_card_m3_exit)
+module_pci_driver(m3_driver);
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c
index 487837c01c9f..0762610c99c0 100644
--- a/sound/pci/mixart/mixart.c
+++ b/sound/pci/mixart/mixart.c
@@ -1380,22 +1380,11 @@ static void __devexit snd_mixart_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver mixart_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_mixart_ids,
.probe = snd_mixart_probe,
.remove = __devexit_p(snd_mixart_remove),
};
-static int __init alsa_card_mixart_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_mixart_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_mixart_init)
-module_exit(alsa_card_mixart_exit)
+module_pci_driver(mixart_driver);
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index ade2c64bd606..8159b05ee94d 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -1742,7 +1742,7 @@ static void __devexit snd_nm256_remove(struct pci_dev *pci)
}
-static struct pci_driver driver = {
+static struct pci_driver nm256_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_nm256_ids,
.probe = snd_nm256_probe,
@@ -1753,16 +1753,4 @@ static struct pci_driver driver = {
#endif
};
-
-static int __init alsa_card_nm256_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_nm256_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_nm256_init)
-module_exit(alsa_card_nm256_exit)
+module_pci_driver(nm256_driver);
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c
index eab663eef117..610275bfbaeb 100644
--- a/sound/pci/oxygen/oxygen.c
+++ b/sound/pci/oxygen/oxygen.c
@@ -94,6 +94,7 @@ enum {
MODEL_2CH_OUTPUT,
MODEL_HG2PCI,
MODEL_XONAR_DG,
+ MODEL_XONAR_DGX,
};
static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = {
@@ -109,6 +110,8 @@ static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = {
{ OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF },
/* Asus Xonar DG */
{ OXYGEN_PCI_SUBID(0x1043, 0x8467), .driver_data = MODEL_XONAR_DG },
+ /* Asus Xonar DGX */
+ { OXYGEN_PCI_SUBID(0x1043, 0x8521), .driver_data = MODEL_XONAR_DGX },
/* PCI 2.0 HD Audio */
{ OXYGEN_PCI_SUBID(0x13f6, 0x8782), .driver_data = MODEL_2CH_OUTPUT },
/* Kuroutoshikou CMI8787-HG2PCI */
@@ -827,6 +830,11 @@ static int __devinit get_oxygen_model(struct oxygen *chip,
break;
case MODEL_XONAR_DG:
chip->model = model_xonar_dg;
+ chip->model.shortname = "Xonar DG";
+ break;
+ case MODEL_XONAR_DGX:
+ chip->model = model_xonar_dg;
+ chip->model.shortname = "Xonar DGX";
break;
}
if (id->driver_data == MODEL_MERIDIAN ||
@@ -870,15 +878,4 @@ static struct pci_driver oxygen_driver = {
#endif
};
-static int __init alsa_card_oxygen_init(void)
-{
- return pci_register_driver(&oxygen_driver);
-}
-
-static void __exit alsa_card_oxygen_exit(void)
-{
- pci_unregister_driver(&oxygen_driver);
-}
-
-module_init(alsa_card_oxygen_init)
-module_exit(alsa_card_oxygen_exit)
+module_pci_driver(oxygen_driver);
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c
index 3fdee4950174..19962c6d38c3 100644
--- a/sound/pci/oxygen/virtuoso.c
+++ b/sound/pci/oxygen/virtuoso.c
@@ -100,15 +100,4 @@ static struct pci_driver xonar_driver = {
.shutdown = oxygen_pci_shutdown,
};
-static int __init alsa_card_xonar_init(void)
-{
- return pci_register_driver(&xonar_driver);
-}
-
-static void __exit alsa_card_xonar_exit(void)
-{
- pci_unregister_driver(&xonar_driver);
-}
-
-module_init(alsa_card_xonar_init)
-module_exit(alsa_card_xonar_exit)
+module_pci_driver(xonar_driver);
diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c
index 793bdf03d7e0..77acd790ea47 100644
--- a/sound/pci/oxygen/xonar_dg.c
+++ b/sound/pci/oxygen/xonar_dg.c
@@ -1,5 +1,5 @@
/*
- * card driver for the Xonar DG
+ * card driver for the Xonar DG/DGX
*
* Copyright (c) Clemens Ladisch <clemens@ladisch.de>
*
@@ -17,8 +17,8 @@
*/
/*
- * Xonar DG
- * --------
+ * Xonar DG/DGX
+ * ------------
*
* CMI8788:
*
@@ -581,7 +581,6 @@ static void dump_cs4245_registers(struct oxygen *chip,
}
struct oxygen_model model_xonar_dg = {
- .shortname = "Xonar DG",
.longname = "C-Media Oxygen HD Audio",
.chip = "CMI8786",
.init = dg_init,
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c
index fd1809ab73b4..0435f45e9513 100644
--- a/sound/pci/pcxhr/pcxhr.c
+++ b/sound/pci/pcxhr/pcxhr.c
@@ -1607,22 +1607,11 @@ static void __devexit pcxhr_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver pcxhr_driver = {
.name = KBUILD_MODNAME,
.id_table = pcxhr_ids,
.probe = pcxhr_probe,
.remove = __devexit_p(pcxhr_remove),
};
-static int __init pcxhr_module_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit pcxhr_module_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(pcxhr_module_init)
-module_exit(pcxhr_module_exit)
+module_pci_driver(pcxhr_driver);
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
index 0481d94aac9b..cbeb3f77350c 100644
--- a/sound/pci/riptide/riptide.c
+++ b/sound/pci/riptide/riptide.c
@@ -1837,8 +1837,7 @@ static int snd_riptide_free(struct snd_riptide *chip)
}
if (chip->irq >= 0)
free_irq(chip->irq, chip);
- if (chip->fw_entry)
- release_firmware(chip->fw_entry);
+ release_firmware(chip->fw_entry);
release_and_free_resource(chip->res_port);
kfree(chip);
return 0;
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c
index b4819d5e41db..46b3629dda22 100644
--- a/sound/pci/rme32.c
+++ b/sound/pci/rme32.c
@@ -1984,22 +1984,11 @@ static void __devexit snd_rme32_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver rme32_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_rme32_ids,
.probe = snd_rme32_probe,
.remove = __devexit_p(snd_rme32_remove),
};
-static int __init alsa_card_rme32_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_rme32_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_rme32_init)
-module_exit(alsa_card_rme32_exit)
+module_pci_driver(rme32_driver);
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index ba894158e76c..9b98dc406988 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -2395,22 +2395,11 @@ static void __devexit snd_rme96_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver rme96_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_rme96_ids,
.probe = snd_rme96_probe,
.remove = __devexit_p(snd_rme96_remove),
};
-static int __init alsa_card_rme96_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_rme96_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_rme96_init)
-module_exit(alsa_card_rme96_exit)
+module_pci_driver(rme96_driver);
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 0b2aea2ce172..0d6930c4f4b7 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -5636,22 +5636,11 @@ static void __devexit snd_hdsp_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver hdsp_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_hdsp_ids,
.probe = snd_hdsp_probe,
.remove = __devexit_p(snd_hdsp_remove),
};
-static int __init alsa_card_hdsp_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_hdsp_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_hdsp_init)
-module_exit(alsa_card_hdsp_exit)
+module_pci_driver(hdsp_driver);
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index bc030a2088da..0a5027b94714 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -6918,23 +6918,11 @@ static void __devexit snd_hdspm_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver hdspm_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_hdspm_ids,
.probe = snd_hdspm_probe,
.remove = __devexit_p(snd_hdspm_remove),
};
-
-static int __init alsa_card_hdspm_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_hdspm_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_hdspm_init)
-module_exit(alsa_card_hdspm_exit)
+module_pci_driver(hdspm_driver);
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
index b737d1619cc7..a15fc100ab0c 100644
--- a/sound/pci/rme9652/rme9652.c
+++ b/sound/pci/rme9652/rme9652.c
@@ -2631,22 +2631,11 @@ static void __devexit snd_rme9652_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver rme9652_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_rme9652_ids,
.probe = snd_rme9652_probe,
.remove = __devexit_p(snd_rme9652_remove),
};
-static int __init alsa_card_hammerfall_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_hammerfall_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_hammerfall_init)
-module_exit(alsa_card_hammerfall_exit)
+module_pci_driver(rme9652_driver);
diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c
index ff500a87f769..1552642765d6 100644
--- a/sound/pci/sis7019.c
+++ b/sound/pci/sis7019.c
@@ -1488,15 +1488,4 @@ static struct pci_driver sis7019_driver = {
#endif
};
-static int __init sis7019_init(void)
-{
- return pci_register_driver(&sis7019_driver);
-}
-
-static void __exit sis7019_exit(void)
-{
- pci_unregister_driver(&sis7019_driver);
-}
-
-module_init(sis7019_init);
-module_exit(sis7019_exit);
+module_pci_driver(sis7019_driver);
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
index 54cc802050f7..baa9946bedf0 100644
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -1530,22 +1530,11 @@ static void __devexit snd_sonic_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver sonicvibes_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_sonic_ids,
.probe = snd_sonic_probe,
.remove = __devexit_p(snd_sonic_remove),
};
-static int __init alsa_card_sonicvibes_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_sonicvibes_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_sonicvibes_init)
-module_exit(alsa_card_sonicvibes_exit)
+module_pci_driver(sonicvibes_driver);
diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c
index 5f1def7f45e5..611983ec7321 100644
--- a/sound/pci/trident/trident.c
+++ b/sound/pci/trident/trident.c
@@ -172,7 +172,7 @@ static void __devexit snd_trident_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver trident_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_trident_ids,
.probe = snd_trident_probe,
@@ -183,15 +183,4 @@ static struct pci_driver driver = {
#endif
};
-static int __init alsa_card_trident_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_trident_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_trident_init)
-module_exit(alsa_card_trident_exit)
+module_pci_driver(trident_driver);
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 75630408c6db..b5afab48943e 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -2619,7 +2619,7 @@ static void __devexit snd_via82xx_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver via82xx_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_via82xx_ids,
.probe = snd_via82xx_probe,
@@ -2630,15 +2630,4 @@ static struct pci_driver driver = {
#endif
};
-static int __init alsa_card_via82xx_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_via82xx_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_via82xx_init)
-module_exit(alsa_card_via82xx_exit)
+module_pci_driver(via82xx_driver);
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index 5efcbcac506a..59fd47ed0a31 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -1223,7 +1223,7 @@ static void __devexit snd_via82xx_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver via82xx_modem_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_via82xx_modem_ids,
.probe = snd_via82xx_probe,
@@ -1234,15 +1234,4 @@ static struct pci_driver driver = {
#endif
};
-static int __init alsa_card_via82xx_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_via82xx_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_via82xx_init)
-module_exit(alsa_card_via82xx_exit)
+module_pci_driver(via82xx_modem_driver);
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c
index 6a534bfe1274..1ea1f656a5dc 100644
--- a/sound/pci/vx222/vx222.c
+++ b/sound/pci/vx222/vx222.c
@@ -289,7 +289,7 @@ static int snd_vx222_resume(struct pci_dev *pci)
}
#endif
-static struct pci_driver driver = {
+static struct pci_driver vx222_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_vx222_ids,
.probe = snd_vx222_probe,
@@ -300,15 +300,4 @@ static struct pci_driver driver = {
#endif
};
-static int __init alsa_card_vx222_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_vx222_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_vx222_init)
-module_exit(alsa_card_vx222_exit)
+module_pci_driver(vx222_driver);
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c
index 94ab728f5ca8..9a1d01d653a7 100644
--- a/sound/pci/ymfpci/ymfpci.c
+++ b/sound/pci/ymfpci/ymfpci.c
@@ -350,7 +350,7 @@ static void __devexit snd_card_ymfpci_remove(struct pci_dev *pci)
pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
+static struct pci_driver ymfpci_driver = {
.name = KBUILD_MODNAME,
.id_table = snd_ymfpci_ids,
.probe = snd_card_ymfpci_probe,
@@ -361,15 +361,4 @@ static struct pci_driver driver = {
#endif
};
-static int __init alsa_card_ymfpci_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_ymfpci_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_ymfpci_init)
-module_exit(alsa_card_ymfpci_exit)
+module_pci_driver(ymfpci_driver);
diff --git a/sound/sh/sh_dac_audio.c b/sound/sh/sh_dac_audio.c
index b11f82b5718f..f8b01c77b298 100644
--- a/sound/sh/sh_dac_audio.c
+++ b/sound/sh/sh_dac_audio.c
@@ -433,7 +433,7 @@ probe_error:
/*
* "driver" definition
*/
-static struct platform_driver driver = {
+static struct platform_driver sh_dac_driver = {
.probe = snd_sh_dac_probe,
.remove = snd_sh_dac_remove,
.driver = {
@@ -441,4 +441,4 @@ static struct platform_driver driver = {
},
};
-module_platform_driver(driver);
+module_platform_driver(sh_dac_driver);
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 91c985599d32..40b2ad1bb1cd 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -35,7 +35,6 @@ source "sound/soc/blackfin/Kconfig"
source "sound/soc/davinci/Kconfig"
source "sound/soc/ep93xx/Kconfig"
source "sound/soc/fsl/Kconfig"
-source "sound/soc/imx/Kconfig"
source "sound/soc/jz4740/Kconfig"
source "sound/soc/nuc900/Kconfig"
source "sound/soc/omap/Kconfig"
@@ -48,9 +47,13 @@ source "sound/soc/s6000/Kconfig"
source "sound/soc/sh/Kconfig"
source "sound/soc/tegra/Kconfig"
source "sound/soc/txx9/Kconfig"
+source "sound/soc/ux500/Kconfig"
# Supported codecs
source "sound/soc/codecs/Kconfig"
+# generic frame-work
+source "sound/soc/generic/Kconfig"
+
endif # SND_SOC
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 2feaf376e94b..70990f4017f4 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -6,13 +6,13 @@ obj-$(CONFIG_SND_SOC_DMAENGINE_PCM) += snd-soc-dmaengine-pcm.o
obj-$(CONFIG_SND_SOC) += snd-soc-core.o
obj-$(CONFIG_SND_SOC) += codecs/
+obj-$(CONFIG_SND_SOC) += generic/
obj-$(CONFIG_SND_SOC) += atmel/
obj-$(CONFIG_SND_SOC) += au1x/
obj-$(CONFIG_SND_SOC) += blackfin/
obj-$(CONFIG_SND_SOC) += davinci/
obj-$(CONFIG_SND_SOC) += ep93xx/
obj-$(CONFIG_SND_SOC) += fsl/
-obj-$(CONFIG_SND_SOC) += imx/
obj-$(CONFIG_SND_SOC) += jz4740/
obj-$(CONFIG_SND_SOC) += mid-x86/
obj-$(CONFIG_SND_SOC) += mxs/
@@ -25,3 +25,4 @@ obj-$(CONFIG_SND_SOC) += s6000/
obj-$(CONFIG_SND_SOC) += sh/
obj-$(CONFIG_SND_SOC) += tegra/
obj-$(CONFIG_SND_SOC) += txx9/
+obj-$(CONFIG_SND_SOC) += ux500/
diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c
index b39ad356b92b..7dbeef1099b4 100644
--- a/sound/soc/blackfin/bf5xx-ssm2602.c
+++ b/sound/soc/blackfin/bf5xx-ssm2602.c
@@ -44,16 +44,8 @@
static struct snd_soc_card bf5xx_ssm2602;
-static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
+static int bf5xx_ssm2602_dai_init(struct snd_soc_pcm_runtime *rtd)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- unsigned int clk = 0;
- int ret = 0;
-
- pr_debug("%s rate %d format %x\n", __func__, params_rate(params),
- params_format(params));
/*
* If you are using a crystal source which frequency is not 12MHz
* then modify the below case statement with frequency of the crystal.
@@ -61,31 +53,10 @@ static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
* If you are using the SPORT to generate clocking then this is
* where to do it.
*/
-
- switch (params_rate(params)) {
- case 8000:
- case 16000:
- case 48000:
- case 96000:
- case 11025:
- case 22050:
- case 44100:
- clk = 12000000;
- break;
- }
-
- ret = snd_soc_dai_set_sysclk(codec_dai, SSM2602_SYSCLK, clk,
+ return snd_soc_dai_set_sysclk(rtd->codec_dai, SSM2602_SYSCLK, 12000000,
SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
-
- return 0;
}
-static struct snd_soc_ops bf5xx_ssm2602_ops = {
- .hw_params = bf5xx_ssm2602_hw_params,
-};
-
/* CODEC is master for BCLK and LRC in this configuration. */
#define BF5XX_SSM2602_DAIFMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \
SND_SOC_DAIFMT_CBM_CFM)
@@ -98,7 +69,7 @@ static struct snd_soc_dai_link bf5xx_ssm2602_dai[] = {
.codec_dai_name = "ssm2602-hifi",
.platform_name = "bfin-i2s-pcm-audio",
.codec_name = "ssm2602.0-001b",
- .ops = &bf5xx_ssm2602_ops,
+ .init = bf5xx_ssm2602_dai_init,
.dai_fmt = BF5XX_SSM2602_DAIFMT,
},
{
@@ -108,7 +79,7 @@ static struct snd_soc_dai_link bf5xx_ssm2602_dai[] = {
.codec_dai_name = "ssm2602-hifi",
.platform_name = "bfin-i2s-pcm-audio",
.codec_name = "ssm2602.0-001b",
- .ops = &bf5xx_ssm2602_ops,
+ .init = bf5xx_ssm2602_dai_init,
.dai_fmt = BF5XX_SSM2602_DAIFMT,
},
};
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 59d8efaa17e9..1e1613a438dd 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -29,6 +29,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_ALC5632 if I2C
select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
select SND_SOC_CS42L51 if I2C
+ select SND_SOC_CS42L52 if I2C
select SND_SOC_CS42L73 if I2C
select SND_SOC_CS4270 if I2C
select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
@@ -37,11 +38,15 @@ config SND_SOC_ALL_CODECS
select SND_SOC_DFBMCS320
select SND_SOC_JZ4740_CODEC
select SND_SOC_LM4857 if I2C
+ select SND_SOC_LM49453 if I2C
select SND_SOC_MAX98088 if I2C
select SND_SOC_MAX98095 if I2C
select SND_SOC_MAX9850 if I2C
select SND_SOC_MAX9768 if I2C
select SND_SOC_MAX9877 if I2C
+ select SND_SOC_MC13783 if MFD_MC13XXX
+ select SND_SOC_ML26124 if I2C
+ select SND_SOC_OMAP_HDMI_CODEC if OMAP4_DSS_HDMI
select SND_SOC_PCM3008
select SND_SOC_RT5631 if I2C
select SND_SOC_SGTL5000 if I2C
@@ -181,6 +186,9 @@ config SND_SOC_CQ0093VC
config SND_SOC_CS42L51
tristate
+config SND_SOC_CS42L52
+ tristate
+
config SND_SOC_CS42L73
tristate
@@ -217,6 +225,9 @@ config SND_SOC_DFBMCS320
config SND_SOC_DMIC
tristate
+config SND_SOC_LM49453
+ tristate
+
config SND_SOC_MAX98088
tristate
@@ -226,6 +237,9 @@ config SND_SOC_MAX98095
config SND_SOC_MAX9850
tristate
+config SND_SOC_OMAP_HDMI_CODEC
+ tristate
+
config SND_SOC_PCM3008
tristate
@@ -435,5 +449,11 @@ config SND_SOC_MAX9768
config SND_SOC_MAX9877
tristate
+config SND_SOC_MC13783
+ tristate
+
+config SND_SOC_ML26124
+ tristate
+
config SND_SOC_TPA6130A2
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 6662eb0cdcc0..fc27fec39487 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -15,6 +15,7 @@ snd-soc-ak4642-objs := ak4642.o
snd-soc-ak4671-objs := ak4671.o
snd-soc-cq93vc-objs := cq93vc.o
snd-soc-cs42l51-objs := cs42l51.o
+snd-soc-cs42l52-objs := cs42l52.o
snd-soc-cs42l73-objs := cs42l73.o
snd-soc-cs4270-objs := cs4270.o
snd-soc-cs4271-objs := cs4271.o
@@ -25,10 +26,14 @@ snd-soc-dmic-objs := dmic.o
snd-soc-jz4740-codec-objs := jz4740.o
snd-soc-l3-objs := l3.o
snd-soc-lm4857-objs := lm4857.o
+snd-soc-lm49453-objs := lm49453.o
snd-soc-max9768-objs := max9768.o
snd-soc-max98088-objs := max98088.o
snd-soc-max98095-objs := max98095.o
snd-soc-max9850-objs := max9850.o
+snd-soc-mc13783-objs := mc13783.o
+snd-soc-ml26124-objs := ml26124.o
+snd-soc-omap-hdmi-codec-objs := omap-hdmi.o
snd-soc-pcm3008-objs := pcm3008.o
snd-soc-rt5631-objs := rt5631.o
snd-soc-sgtl5000-objs := sgtl5000.o
@@ -121,6 +126,7 @@ obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o
obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o
obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o
+obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o
obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o
@@ -128,13 +134,17 @@ obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
obj-$(CONFIG_SND_SOC_DFBMCS320) += snd-soc-dfbmcs320.o
obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o
+obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o
-obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
+obj-$(CONFIG_SND_SOC_LM49453) += snd-soc-lm49453.o
obj-$(CONFIG_SND_SOC_MAX9768) += snd-soc-max9768.o
obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o
obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o
+obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o
+obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o
+obj-$(CONFIG_SND_SOC_OMAP_HDMI_CODEC) += snd-soc-omap-hdmi-codec.o
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index 1bbad4c16d28..2023c749f232 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -26,13 +26,11 @@
static int ac97_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
- return snd_ac97_set_rate(codec->ac97, reg, runtime->rate);
+ return snd_ac97_set_rate(codec->ac97, reg, substream->runtime->rate);
}
#define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c
index 12e3b4118557..c67b50d8b317 100644
--- a/sound/soc/codecs/ad1836.c
+++ b/sound/soc/codecs/ad1836.c
@@ -162,9 +162,7 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
int word_len = 0;
-
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
/* bit size */
switch (params_format(params)) {
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index a4a6bef2c0bb..13e62be4f990 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -245,9 +245,7 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
int word_len = 0, master_rate = 0;
-
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
/* bit size */
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index 78e9ce48bb99..3d50fc8646b6 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -258,8 +258,7 @@ static int adau1701_set_playback_pcm_format(struct snd_soc_codec *codec,
static int adau1701_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
snd_pcm_format_t format;
unsigned int val;
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c
index ceb96ecf5588..31d4483245d0 100644
--- a/sound/soc/codecs/ak4104.c
+++ b/sound/soc/codecs/ak4104.c
@@ -88,8 +88,7 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
int val = 0;
/* set the IEC958 bits: consumer mode, no copyright bit */
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index 838ae8b22b50..618fdc30f73e 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -262,8 +262,7 @@ static int ak4535_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
u8 mode2 = snd_soc_read(codec, AK4535_MODE2) & ~(0x3 << 5);
int rate = params_rate(params), fs = 256;
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c
index c4d165a4bddf..543a12f471be 100644
--- a/sound/soc/codecs/ak4641.c
+++ b/sound/soc/codecs/ak4641.c
@@ -296,8 +296,7 @@ static int ak4641_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct ak4641_priv *ak4641 = snd_soc_codec_get_drvdata(codec);
int rate = params_rate(params), fs = 256;
u8 mode2;
@@ -517,67 +516,24 @@ static int ak4641_resume(struct snd_soc_codec *codec)
static int ak4641_probe(struct snd_soc_codec *codec)
{
- struct ak4641_platform_data *pdata = codec->dev->platform_data;
int ret;
-
- if (pdata) {
- if (gpio_is_valid(pdata->gpio_power)) {
- ret = gpio_request_one(pdata->gpio_power,
- GPIOF_OUT_INIT_LOW, "ak4641 power");
- if (ret)
- goto err_out;
- }
- if (gpio_is_valid(pdata->gpio_npdn)) {
- ret = gpio_request_one(pdata->gpio_npdn,
- GPIOF_OUT_INIT_LOW, "ak4641 npdn");
- if (ret)
- goto err_gpio;
-
- udelay(1); /* > 150 ns */
- gpio_set_value(pdata->gpio_npdn, 1);
- }
- }
-
ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- goto err_register;
+ return ret;
}
/* power on device */
ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
-
-err_register:
- if (pdata) {
- if (gpio_is_valid(pdata->gpio_power))
- gpio_set_value(pdata->gpio_power, 0);
- if (gpio_is_valid(pdata->gpio_npdn))
- gpio_free(pdata->gpio_npdn);
- }
-err_gpio:
- if (pdata && gpio_is_valid(pdata->gpio_power))
- gpio_free(pdata->gpio_power);
-err_out:
- return ret;
}
static int ak4641_remove(struct snd_soc_codec *codec)
{
- struct ak4641_platform_data *pdata = codec->dev->platform_data;
-
ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF);
- if (pdata) {
- if (gpio_is_valid(pdata->gpio_power)) {
- gpio_set_value(pdata->gpio_power, 0);
- gpio_free(pdata->gpio_power);
- }
- if (gpio_is_valid(pdata->gpio_npdn))
- gpio_free(pdata->gpio_npdn);
- }
return 0;
}
@@ -604,6 +560,7 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4641 = {
static int __devinit ak4641_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
+ struct ak4641_platform_data *pdata = i2c->dev.platform_data;
struct ak4641_priv *ak4641;
int ret;
@@ -612,16 +569,62 @@ static int __devinit ak4641_i2c_probe(struct i2c_client *i2c,
if (!ak4641)
return -ENOMEM;
+ if (pdata) {
+ if (gpio_is_valid(pdata->gpio_power)) {
+ ret = gpio_request_one(pdata->gpio_power,
+ GPIOF_OUT_INIT_LOW, "ak4641 power");
+ if (ret)
+ goto err_out;
+ }
+ if (gpio_is_valid(pdata->gpio_npdn)) {
+ ret = gpio_request_one(pdata->gpio_npdn,
+ GPIOF_OUT_INIT_LOW, "ak4641 npdn");
+ if (ret)
+ goto err_gpio;
+
+ udelay(1); /* > 150 ns */
+ gpio_set_value(pdata->gpio_npdn, 1);
+ }
+ }
+
i2c_set_clientdata(i2c, ak4641);
ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_ak4641,
ak4641_dai, ARRAY_SIZE(ak4641_dai));
+ if (ret != 0)
+ goto err_gpio2;
+
+ return 0;
+
+err_gpio2:
+ if (pdata) {
+ if (gpio_is_valid(pdata->gpio_power))
+ gpio_set_value(pdata->gpio_power, 0);
+ if (gpio_is_valid(pdata->gpio_npdn))
+ gpio_free(pdata->gpio_npdn);
+ }
+err_gpio:
+ if (pdata && gpio_is_valid(pdata->gpio_power))
+ gpio_free(pdata->gpio_power);
+err_out:
return ret;
}
static int __devexit ak4641_i2c_remove(struct i2c_client *i2c)
{
+ struct ak4641_platform_data *pdata = i2c->dev.platform_data;
+
snd_soc_unregister_codec(&i2c->dev);
+
+ if (pdata) {
+ if (gpio_is_valid(pdata->gpio_power)) {
+ gpio_set_value(pdata->gpio_power, 0);
+ gpio_free(pdata->gpio_power);
+ }
+ if (gpio_is_valid(pdata->gpio_npdn))
+ gpio_free(pdata->gpio_npdn);
+ }
+
return 0;
}
@@ -641,23 +644,7 @@ static struct i2c_driver ak4641_i2c_driver = {
.id_table = ak4641_i2c_id,
};
-static int __init ak4641_modinit(void)
-{
- int ret;
-
- ret = i2c_add_driver(&ak4641_i2c_driver);
- if (ret != 0)
- pr_err("Failed to register AK4641 I2C driver: %d\n", ret);
-
- return ret;
-}
-module_init(ak4641_modinit);
-
-static void __exit ak4641_exit(void)
-{
- i2c_del_driver(&ak4641_i2c_driver);
-}
-module_exit(ak4641_exit);
+module_i2c_driver(ak4641_i2c_driver);
MODULE_DESCRIPTION("SoC AK4641 driver");
MODULE_AUTHOR("Harald Welte <laforge@gnufiish.org>");
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c
index d47b62ddb210..1960478ce6bb 100644
--- a/sound/soc/codecs/alc5623.c
+++ b/sound/soc/codecs/alc5623.c
@@ -705,8 +705,7 @@ static int alc5623_set_dai_fmt(struct snd_soc_dai *codec_dai,
static int alc5623_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
int coeff, rate;
u16 iface;
@@ -1084,25 +1083,7 @@ static struct i2c_driver alc5623_i2c_driver = {
.id_table = alc5623_i2c_table,
};
-static int __init alc5623_modinit(void)
-{
- int ret;
-
- ret = i2c_add_driver(&alc5623_i2c_driver);
- if (ret != 0) {
- printk(KERN_ERR "%s: can't add i2c driver", __func__);
- return ret;
- }
-
- return ret;
-}
-module_init(alc5623_modinit);
-
-static void __exit alc5623_modexit(void)
-{
- i2c_del_driver(&alc5623_i2c_driver);
-}
-module_exit(alc5623_modexit);
+module_i2c_driver(alc5623_i2c_driver);
MODULE_DESCRIPTION("ASoC alc5621/2/3 driver");
MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c
index e2111e0ccad7..7dd02420b36d 100644
--- a/sound/soc/codecs/alc5632.c
+++ b/sound/soc/codecs/alc5632.c
@@ -861,8 +861,7 @@ static int alc5632_set_dai_fmt(struct snd_soc_dai *codec_dai,
static int alc5632_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
int coeff, rate;
u16 iface;
@@ -1131,7 +1130,7 @@ static __devinit int alc5632_i2c_probe(struct i2c_client *client,
i2c_set_clientdata(client, alc5632);
- alc5632->regmap = regmap_init_i2c(client, &alc5632_regmap);
+ alc5632->regmap = devm_regmap_init_i2c(client, &alc5632_regmap);
if (IS_ERR(alc5632->regmap)) {
ret = PTR_ERR(alc5632->regmap);
dev_err(&client->dev, "regmap_init() failed: %d\n", ret);
@@ -1143,7 +1142,6 @@ static __devinit int alc5632_i2c_probe(struct i2c_client *client,
if (ret1 != 0 || ret2 != 0) {
dev_err(&client->dev,
"Failed to read chip ID: ret1=%d, ret2=%d\n", ret1, ret2);
- regmap_exit(alc5632->regmap);
return -EIO;
}
@@ -1152,14 +1150,12 @@ static __devinit int alc5632_i2c_probe(struct i2c_client *client,
if ((vid1 != 0x10EC) || (vid2 != id->driver_data)) {
dev_err(&client->dev,
"Device is not a ALC5632: VID1=0x%x, VID2=0x%x\n", vid1, vid2);
- regmap_exit(alc5632->regmap);
return -EINVAL;
}
ret = alc5632_reset(alc5632->regmap);
if (ret < 0) {
dev_err(&client->dev, "Failed to issue reset\n");
- regmap_exit(alc5632->regmap);
return ret;
}
@@ -1177,7 +1173,6 @@ static __devinit int alc5632_i2c_probe(struct i2c_client *client,
if (ret < 0) {
dev_err(&client->dev, "Failed to register codec: %d\n", ret);
- regmap_exit(alc5632->regmap);
return ret;
}
@@ -1186,9 +1181,7 @@ static __devinit int alc5632_i2c_probe(struct i2c_client *client,
static __devexit int alc5632_i2c_remove(struct i2c_client *client)
{
- struct alc5632_priv *alc5632 = i2c_get_clientdata(client);
snd_soc_unregister_codec(&client->dev);
- regmap_exit(alc5632->regmap);
return 0;
}
@@ -1209,25 +1202,7 @@ static struct i2c_driver alc5632_i2c_driver = {
.id_table = alc5632_i2c_table,
};
-static int __init alc5632_modinit(void)
-{
- int ret;
-
- ret = i2c_add_driver(&alc5632_i2c_driver);
- if (ret != 0) {
- printk(KERN_ERR "%s: can't add i2c driver", __func__);
- return ret;
- }
-
- return ret;
-}
-module_init(alc5632_modinit);
-
-static void __exit alc5632_modexit(void)
-{
- i2c_del_driver(&alc5632_i2c_driver);
-}
-module_exit(alc5632_modexit);
+module_i2c_driver(alc5632_i2c_driver);
MODULE_DESCRIPTION("ASoC ALC5632 driver");
MODULE_AUTHOR("Leon Romanovsky <leon@leon.nu>");
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c
index 1d672f528662..047917f0b8ae 100644
--- a/sound/soc/codecs/cs4270.c
+++ b/sound/soc/codecs/cs4270.c
@@ -307,8 +307,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
int ret;
unsigned int i;
@@ -600,10 +599,12 @@ static int cs4270_soc_suspend(struct snd_soc_codec *codec)
static int cs4270_soc_resume(struct snd_soc_codec *codec)
{
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
- int reg;
+ int reg, ret;
- regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
- cs4270->supplies);
+ ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
+ cs4270->supplies);
+ if (ret != 0)
+ return ret;
/* In case the device was put to hard reset during sleep, we need to
* wait 500ns here before any I2C communication. */
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index bf7141280a74..9eb01d7d58a3 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -318,8 +318,7 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
int i, ret;
unsigned int ratio, val;
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index a8bf588e8740..091d0193f507 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -141,15 +141,15 @@ static const struct soc_enum cs42l51_chan_mix =
static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
SOC_DOUBLE_R_SX_TLV("PCM Playback Volume",
CS42L51_PCMA_VOL, CS42L51_PCMB_VOL,
- 7, 0xffffff99, 0x18, adc_pcm_tlv),
+ 6, 0x19, 0x7F, adc_pcm_tlv),
SOC_DOUBLE_R("PCM Playback Switch",
CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, 7, 1, 1),
SOC_DOUBLE_R_SX_TLV("Analog Playback Volume",
CS42L51_AOUTA_VOL, CS42L51_AOUTB_VOL,
- 8, 0xffffff19, 0x18, aout_tlv),
+ 0, 0x34, 0xE4, aout_tlv),
SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",
CS42L51_ADCA_VOL, CS42L51_ADCB_VOL,
- 7, 0xffffff99, 0x18, adc_pcm_tlv),
+ 6, 0x19, 0x7F, adc_pcm_tlv),
SOC_DOUBLE_R("ADC Mixer Switch",
CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, 7, 1, 1),
SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0),
@@ -356,8 +356,7 @@ static int cs42l51_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
int ret;
unsigned int i;
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c
new file mode 100644
index 000000000000..a7109413aef1
--- /dev/null
+++ b/sound/soc/codecs/cs42l52.c
@@ -0,0 +1,1295 @@
+/*
+ * cs42l52.c -- CS42L52 ALSA SoC audio driver
+ *
+ * Copyright 2012 CirrusLogic, Inc.
+ *
+ * Author: Georgi Vlaev <joe@nucleusys.com>
+ * Author: Brian Austin <brian.austin@cirrus.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/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/cs42l52.h>
+#include "cs42l52.h"
+
+struct sp_config {
+ u8 spc, format, spfs;
+ u32 srate;
+};
+
+struct cs42l52_private {
+ struct regmap *regmap;
+ struct snd_soc_codec *codec;
+ struct device *dev;
+ struct sp_config config;
+ struct cs42l52_platform_data pdata;
+ u32 sysclk;
+ u8 mclksel;
+ u32 mclk;
+ u8 flags;
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+ struct input_dev *beep;
+ struct work_struct beep_work;
+ int beep_rate;
+#endif
+};
+
+static const struct reg_default cs42l52_reg_defaults[] = {
+ { CS42L52_PWRCTL1, 0x9F }, /* r02 PWRCTL 1 */
+ { CS42L52_PWRCTL2, 0x07 }, /* r03 PWRCTL 2 */
+ { CS42L52_PWRCTL3, 0xFF }, /* r04 PWRCTL 3 */
+ { CS42L52_CLK_CTL, 0xA0 }, /* r05 Clocking Ctl */
+ { CS42L52_IFACE_CTL1, 0x00 }, /* r06 Interface Ctl 1 */
+ { CS42L52_ADC_PGA_A, 0x80 }, /* r08 Input A Select */
+ { CS42L52_ADC_PGA_B, 0x80 }, /* r09 Input B Select */
+ { CS42L52_ANALOG_HPF_CTL, 0xA5 }, /* r0A Analog HPF Ctl */
+ { CS42L52_ADC_HPF_FREQ, 0x00 }, /* r0B ADC HPF Corner Freq */
+ { CS42L52_ADC_MISC_CTL, 0x00 }, /* r0C Misc. ADC Ctl */
+ { CS42L52_PB_CTL1, 0x60 }, /* r0D Playback Ctl 1 */
+ { CS42L52_MISC_CTL, 0x02 }, /* r0E Misc. Ctl */
+ { CS42L52_PB_CTL2, 0x00 }, /* r0F Playback Ctl 2 */
+ { CS42L52_MICA_CTL, 0x00 }, /* r10 MICA Amp Ctl */
+ { CS42L52_MICB_CTL, 0x00 }, /* r11 MICB Amp Ctl */
+ { CS42L52_PGAA_CTL, 0x00 }, /* r12 PGAA Vol, Misc. */
+ { CS42L52_PGAB_CTL, 0x00 }, /* r13 PGAB Vol, Misc. */
+ { CS42L52_PASSTHRUA_VOL, 0x00 }, /* r14 Bypass A Vol */
+ { CS42L52_PASSTHRUB_VOL, 0x00 }, /* r15 Bypass B Vol */
+ { CS42L52_ADCA_VOL, 0x00 }, /* r16 ADCA Volume */
+ { CS42L52_ADCB_VOL, 0x00 }, /* r17 ADCB Volume */
+ { CS42L52_ADCA_MIXER_VOL, 0x80 }, /* r18 ADCA Mixer Volume */
+ { CS42L52_ADCB_MIXER_VOL, 0x80 }, /* r19 ADCB Mixer Volume */
+ { CS42L52_PCMA_MIXER_VOL, 0x00 }, /* r1A PCMA Mixer Volume */
+ { CS42L52_PCMB_MIXER_VOL, 0x00 }, /* r1B PCMB Mixer Volume */
+ { CS42L52_BEEP_FREQ, 0x00 }, /* r1C Beep Freq on Time */
+ { CS42L52_BEEP_VOL, 0x00 }, /* r1D Beep Volume off Time */
+ { CS42L52_BEEP_TONE_CTL, 0x00 }, /* r1E Beep Tone Cfg. */
+ { CS42L52_TONE_CTL, 0x00 }, /* r1F Tone Ctl */
+ { CS42L52_MASTERA_VOL, 0x88 }, /* r20 Master A Volume */
+ { CS42L52_MASTERB_VOL, 0x00 }, /* r21 Master B Volume */
+ { CS42L52_HPA_VOL, 0x00 }, /* r22 Headphone A Volume */
+ { CS42L52_HPB_VOL, 0x00 }, /* r23 Headphone B Volume */
+ { CS42L52_SPKA_VOL, 0x00 }, /* r24 Speaker A Volume */
+ { CS42L52_SPKB_VOL, 0x00 }, /* r25 Speaker B Volume */
+ { CS42L52_ADC_PCM_MIXER, 0x00 }, /* r26 Channel Mixer and Swap */
+ { CS42L52_LIMITER_CTL1, 0x00 }, /* r27 Limit Ctl 1 Thresholds */
+ { CS42L52_LIMITER_CTL2, 0x7F }, /* r28 Limit Ctl 2 Release Rate */
+ { CS42L52_LIMITER_AT_RATE, 0xC0 }, /* r29 Limiter Attack Rate */
+ { CS42L52_ALC_CTL, 0x00 }, /* r2A ALC Ctl 1 Attack Rate */
+ { CS42L52_ALC_RATE, 0x3F }, /* r2B ALC Release Rate */
+ { CS42L52_ALC_THRESHOLD, 0x3f }, /* r2C ALC Thresholds */
+ { CS42L52_NOISE_GATE_CTL, 0x00 }, /* r2D Noise Gate Ctl */
+ { CS42L52_CLK_STATUS, 0x00 }, /* r2E Overflow and Clock Status */
+ { CS42L52_BATT_COMPEN, 0x00 }, /* r2F battery Compensation */
+ { CS42L52_BATT_LEVEL, 0x00 }, /* r30 VP Battery Level */
+ { CS42L52_SPK_STATUS, 0x00 }, /* r31 Speaker Status */
+ { CS42L52_TEM_CTL, 0x3B }, /* r32 Temp Ctl */
+ { CS42L52_THE_FOLDBACK, 0x00 }, /* r33 Foldback */
+};
+
+static bool cs42l52_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS42L52_CHIP:
+ case CS42L52_PWRCTL1:
+ case CS42L52_PWRCTL2:
+ case CS42L52_PWRCTL3:
+ case CS42L52_CLK_CTL:
+ case CS42L52_IFACE_CTL1:
+ case CS42L52_IFACE_CTL2:
+ case CS42L52_ADC_PGA_A:
+ case CS42L52_ADC_PGA_B:
+ case CS42L52_ANALOG_HPF_CTL:
+ case CS42L52_ADC_HPF_FREQ:
+ case CS42L52_ADC_MISC_CTL:
+ case CS42L52_PB_CTL1:
+ case CS42L52_MISC_CTL:
+ case CS42L52_PB_CTL2:
+ case CS42L52_MICA_CTL:
+ case CS42L52_MICB_CTL:
+ case CS42L52_PGAA_CTL:
+ case CS42L52_PGAB_CTL:
+ case CS42L52_PASSTHRUA_VOL:
+ case CS42L52_PASSTHRUB_VOL:
+ case CS42L52_ADCA_VOL:
+ case CS42L52_ADCB_VOL:
+ case CS42L52_ADCA_MIXER_VOL:
+ case CS42L52_ADCB_MIXER_VOL:
+ case CS42L52_PCMA_MIXER_VOL:
+ case CS42L52_PCMB_MIXER_VOL:
+ case CS42L52_BEEP_FREQ:
+ case CS42L52_BEEP_VOL:
+ case CS42L52_BEEP_TONE_CTL:
+ case CS42L52_TONE_CTL:
+ case CS42L52_MASTERA_VOL:
+ case CS42L52_MASTERB_VOL:
+ case CS42L52_HPA_VOL:
+ case CS42L52_HPB_VOL:
+ case CS42L52_SPKA_VOL:
+ case CS42L52_SPKB_VOL:
+ case CS42L52_ADC_PCM_MIXER:
+ case CS42L52_LIMITER_CTL1:
+ case CS42L52_LIMITER_CTL2:
+ case CS42L52_LIMITER_AT_RATE:
+ case CS42L52_ALC_CTL:
+ case CS42L52_ALC_RATE:
+ case CS42L52_ALC_THRESHOLD:
+ case CS42L52_NOISE_GATE_CTL:
+ case CS42L52_CLK_STATUS:
+ case CS42L52_BATT_COMPEN:
+ case CS42L52_BATT_LEVEL:
+ case CS42L52_SPK_STATUS:
+ case CS42L52_TEM_CTL:
+ case CS42L52_THE_FOLDBACK:
+ case CS42L52_CHARGE_PUMP:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool cs42l52_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CS42L52_IFACE_CTL2:
+ case CS42L52_CLK_STATUS:
+ case CS42L52_BATT_LEVEL:
+ case CS42L52_SPK_STATUS:
+ case CS42L52_CHARGE_PUMP:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static DECLARE_TLV_DB_SCALE(hl_tlv, -10200, 50, 0);
+
+static DECLARE_TLV_DB_SCALE(hpd_tlv, -9600, 50, 1);
+
+static DECLARE_TLV_DB_SCALE(ipd_tlv, -9600, 100, 0);
+
+static DECLARE_TLV_DB_SCALE(mic_tlv, 1600, 100, 0);
+
+static DECLARE_TLV_DB_SCALE(pga_tlv, -600, 50, 0);
+
+static const unsigned int limiter_tlv[] = {
+ TLV_DB_RANGE_HEAD(2),
+ 0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0),
+ 3, 7, TLV_DB_SCALE_ITEM(-1200, 300, 0),
+};
+
+static const char * const cs42l52_adca_text[] = {
+ "Input1A", "Input2A", "Input3A", "Input4A", "PGA Input Left"};
+
+static const char * const cs42l52_adcb_text[] = {
+ "Input1B", "Input2B", "Input3B", "Input4B", "PGA Input Right"};
+
+static const struct soc_enum adca_enum =
+ SOC_ENUM_SINGLE(CS42L52_ADC_PGA_A, 5,
+ ARRAY_SIZE(cs42l52_adca_text), cs42l52_adca_text);
+
+static const struct soc_enum adcb_enum =
+ SOC_ENUM_SINGLE(CS42L52_ADC_PGA_B, 5,
+ ARRAY_SIZE(cs42l52_adcb_text), cs42l52_adcb_text);
+
+static const struct snd_kcontrol_new adca_mux =
+ SOC_DAPM_ENUM("Left ADC Input Capture Mux", adca_enum);
+
+static const struct snd_kcontrol_new adcb_mux =
+ SOC_DAPM_ENUM("Right ADC Input Capture Mux", adcb_enum);
+
+static const char * const mic_bias_level_text[] = {
+ "0.5 +VA", "0.6 +VA", "0.7 +VA",
+ "0.8 +VA", "0.83 +VA", "0.91 +VA"
+};
+
+static const struct soc_enum mic_bias_level_enum =
+ SOC_ENUM_SINGLE(CS42L52_IFACE_CTL1, 0,
+ ARRAY_SIZE(mic_bias_level_text), mic_bias_level_text);
+
+static const char * const cs42l52_mic_text[] = { "Single", "Differential" };
+
+static const struct soc_enum mica_enum =
+ SOC_ENUM_SINGLE(CS42L52_MICA_CTL, 5,
+ ARRAY_SIZE(cs42l52_mic_text), cs42l52_mic_text);
+
+static const struct soc_enum micb_enum =
+ SOC_ENUM_SINGLE(CS42L52_MICB_CTL, 5,
+ ARRAY_SIZE(cs42l52_mic_text), cs42l52_mic_text);
+
+static const struct snd_kcontrol_new mica_mux =
+ SOC_DAPM_ENUM("Left Mic Input Capture Mux", mica_enum);
+
+static const struct snd_kcontrol_new micb_mux =
+ SOC_DAPM_ENUM("Right Mic Input Capture Mux", micb_enum);
+
+static const char * const digital_output_mux_text[] = {"ADC", "DSP"};
+
+static const struct soc_enum digital_output_mux_enum =
+ SOC_ENUM_SINGLE(CS42L52_ADC_MISC_CTL, 6,
+ ARRAY_SIZE(digital_output_mux_text),
+ digital_output_mux_text);
+
+static const struct snd_kcontrol_new digital_output_mux =
+ SOC_DAPM_ENUM("Digital Output Mux", digital_output_mux_enum);
+
+static const char * const hp_gain_num_text[] = {
+ "0.3959", "0.4571", "0.5111", "0.6047",
+ "0.7099", "0.8399", "1.000", "1.1430"
+};
+
+static const struct soc_enum hp_gain_enum =
+ SOC_ENUM_SINGLE(CS42L52_PB_CTL1, 4,
+ ARRAY_SIZE(hp_gain_num_text), hp_gain_num_text);
+
+static const char * const beep_pitch_text[] = {
+ "C4", "C5", "D5", "E5", "F5", "G5", "A5", "B5",
+ "C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7"
+};
+
+static const struct soc_enum beep_pitch_enum =
+ SOC_ENUM_SINGLE(CS42L52_BEEP_FREQ, 4,
+ ARRAY_SIZE(beep_pitch_text), beep_pitch_text);
+
+static const char * const beep_ontime_text[] = {
+ "86 ms", "430 ms", "780 ms", "1.20 s", "1.50 s",
+ "1.80 s", "2.20 s", "2.50 s", "2.80 s", "3.20 s",
+ "3.50 s", "3.80 s", "4.20 s", "4.50 s", "4.80 s", "5.20 s"
+};
+
+static const struct soc_enum beep_ontime_enum =
+ SOC_ENUM_SINGLE(CS42L52_BEEP_FREQ, 0,
+ ARRAY_SIZE(beep_ontime_text), beep_ontime_text);
+
+static const char * const beep_offtime_text[] = {
+ "1.23 s", "2.58 s", "3.90 s", "5.20 s",
+ "6.60 s", "8.05 s", "9.35 s", "10.80 s"
+};
+
+static const struct soc_enum beep_offtime_enum =
+ SOC_ENUM_SINGLE(CS42L52_BEEP_VOL, 5,
+ ARRAY_SIZE(beep_offtime_text), beep_offtime_text);
+
+static const char * const beep_config_text[] = {
+ "Off", "Single", "Multiple", "Continuous"
+};
+
+static const struct soc_enum beep_config_enum =
+ SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 6,
+ ARRAY_SIZE(beep_config_text), beep_config_text);
+
+static const char * const beep_bass_text[] = {
+ "50 Hz", "100 Hz", "200 Hz", "250 Hz"
+};
+
+static const struct soc_enum beep_bass_enum =
+ SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 1,
+ ARRAY_SIZE(beep_bass_text), beep_bass_text);
+
+static const char * const beep_treble_text[] = {
+ "5 kHz", "7 kHz", "10 kHz", " 15 kHz"
+};
+
+static const struct soc_enum beep_treble_enum =
+ SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 3,
+ ARRAY_SIZE(beep_treble_text), beep_treble_text);
+
+static const char * const ng_threshold_text[] = {
+ "-34dB", "-37dB", "-40dB", "-43dB",
+ "-46dB", "-52dB", "-58dB", "-64dB"
+};
+
+static const struct soc_enum ng_threshold_enum =
+ SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 2,
+ ARRAY_SIZE(ng_threshold_text), ng_threshold_text);
+
+static const char * const cs42l52_ng_delay_text[] = {
+ "50ms", "100ms", "150ms", "200ms"};
+
+static const struct soc_enum ng_delay_enum =
+ SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 0,
+ ARRAY_SIZE(cs42l52_ng_delay_text), cs42l52_ng_delay_text);
+
+static const char * const cs42l52_ng_type_text[] = {
+ "Apply Specific", "Apply All"
+};
+
+static const struct soc_enum ng_type_enum =
+ SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 6,
+ ARRAY_SIZE(cs42l52_ng_type_text), cs42l52_ng_type_text);
+
+static const char * const left_swap_text[] = {
+ "Left", "LR 2", "Right"};
+
+static const char * const right_swap_text[] = {
+ "Right", "LR 2", "Left"};
+
+static const unsigned int swap_values[] = { 0, 1, 3 };
+
+static const struct soc_enum adca_swap_enum =
+ SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 2, 1,
+ ARRAY_SIZE(left_swap_text),
+ left_swap_text,
+ swap_values);
+
+static const struct snd_kcontrol_new adca_mixer =
+ SOC_DAPM_ENUM("Route", adca_swap_enum);
+
+static const struct soc_enum pcma_swap_enum =
+ SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 6, 1,
+ ARRAY_SIZE(left_swap_text),
+ left_swap_text,
+ swap_values);
+
+static const struct snd_kcontrol_new pcma_mixer =
+ SOC_DAPM_ENUM("Route", pcma_swap_enum);
+
+static const struct soc_enum adcb_swap_enum =
+ SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 0, 1,
+ ARRAY_SIZE(right_swap_text),
+ right_swap_text,
+ swap_values);
+
+static const struct snd_kcontrol_new adcb_mixer =
+ SOC_DAPM_ENUM("Route", adcb_swap_enum);
+
+static const struct soc_enum pcmb_swap_enum =
+ SOC_VALUE_ENUM_SINGLE(CS42L52_ADC_PCM_MIXER, 4, 1,
+ ARRAY_SIZE(right_swap_text),
+ right_swap_text,
+ swap_values);
+
+static const struct snd_kcontrol_new pcmb_mixer =
+ SOC_DAPM_ENUM("Route", pcmb_swap_enum);
+
+
+static const struct snd_kcontrol_new passthrul_ctl =
+ SOC_DAPM_SINGLE("Switch", CS42L52_MISC_CTL, 6, 1, 0);
+
+static const struct snd_kcontrol_new passthrur_ctl =
+ SOC_DAPM_SINGLE("Switch", CS42L52_MISC_CTL, 7, 1, 0);
+
+static const struct snd_kcontrol_new spkl_ctl =
+ SOC_DAPM_SINGLE("Switch", CS42L52_PWRCTL3, 0, 1, 1);
+
+static const struct snd_kcontrol_new spkr_ctl =
+ SOC_DAPM_SINGLE("Switch", CS42L52_PWRCTL3, 2, 1, 1);
+
+static const struct snd_kcontrol_new hpl_ctl =
+ SOC_DAPM_SINGLE("Switch", CS42L52_PWRCTL3, 4, 1, 1);
+
+static const struct snd_kcontrol_new hpr_ctl =
+ SOC_DAPM_SINGLE("Switch", CS42L52_PWRCTL3, 6, 1, 1);
+
+static const struct snd_kcontrol_new cs42l52_snd_controls[] = {
+
+ SOC_DOUBLE_R_SX_TLV("Master Volume", CS42L52_MASTERA_VOL,
+ CS42L52_MASTERB_VOL, 0, 0x34, 0xE4, hl_tlv),
+
+ SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L52_HPA_VOL,
+ CS42L52_HPB_VOL, 0, 0x34, 0xCC, hpd_tlv),
+
+ SOC_ENUM("Headphone Analog Gain", hp_gain_enum),
+
+ SOC_DOUBLE_R_SX_TLV("Speaker Volume", CS42L52_SPKA_VOL,
+ CS42L52_SPKB_VOL, 7, 0x1, 0xff, hl_tlv),
+
+ SOC_DOUBLE_R_SX_TLV("Bypass Volume", CS42L52_PASSTHRUA_VOL,
+ CS42L52_PASSTHRUB_VOL, 6, 0x18, 0x90, pga_tlv),
+
+ SOC_DOUBLE("Bypass Mute", CS42L52_MISC_CTL, 4, 5, 1, 0),
+
+ SOC_DOUBLE_R_TLV("MIC Gain Volume", CS42L52_MICA_CTL,
+ CS42L52_MICB_CTL, 0, 0x10, 0, mic_tlv),
+
+ SOC_ENUM("MIC Bias Level", mic_bias_level_enum),
+
+ SOC_DOUBLE_R_SX_TLV("ADC Volume", CS42L52_ADCA_VOL,
+ CS42L52_ADCB_VOL, 7, 0x80, 0xA0, ipd_tlv),
+ SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",
+ CS42L52_ADCA_MIXER_VOL, CS42L52_ADCB_MIXER_VOL,
+ 6, 0x7f, 0x19, ipd_tlv),
+
+ SOC_DOUBLE("ADC Switch", CS42L52_ADC_MISC_CTL, 0, 1, 1, 0),
+
+ SOC_DOUBLE_R("ADC Mixer Switch", CS42L52_ADCA_MIXER_VOL,
+ CS42L52_ADCB_MIXER_VOL, 7, 1, 1),
+
+ SOC_DOUBLE_R_SX_TLV("PGA Volume", CS42L52_PGAA_CTL,
+ CS42L52_PGAB_CTL, 0, 0x28, 0x30, pga_tlv),
+
+ SOC_DOUBLE_R_SX_TLV("PCM Mixer Volume",
+ CS42L52_PCMA_MIXER_VOL, CS42L52_PCMB_MIXER_VOL,
+ 6, 0x7f, 0x19, hl_tlv),
+ SOC_DOUBLE_R("PCM Mixer Switch",
+ CS42L52_PCMA_MIXER_VOL, CS42L52_PCMB_MIXER_VOL, 7, 1, 1),
+
+ SOC_ENUM("Beep Config", beep_config_enum),
+ SOC_ENUM("Beep Pitch", beep_pitch_enum),
+ SOC_ENUM("Beep on Time", beep_ontime_enum),
+ SOC_ENUM("Beep off Time", beep_offtime_enum),
+ SOC_SINGLE_TLV("Beep Volume", CS42L52_BEEP_VOL, 0, 0x1f, 0x07, hl_tlv),
+ SOC_SINGLE("Beep Mixer Switch", CS42L52_BEEP_TONE_CTL, 5, 1, 1),
+ SOC_ENUM("Beep Treble Corner Freq", beep_treble_enum),
+ SOC_ENUM("Beep Bass Corner Freq", beep_bass_enum),
+
+ SOC_SINGLE("Tone Control Switch", CS42L52_BEEP_TONE_CTL, 0, 1, 1),
+ SOC_SINGLE_TLV("Treble Gain Volume",
+ CS42L52_TONE_CTL, 4, 15, 1, hl_tlv),
+ SOC_SINGLE_TLV("Bass Gain Volume",
+ CS42L52_TONE_CTL, 0, 15, 1, hl_tlv),
+
+ /* Limiter */
+ SOC_SINGLE_TLV("Limiter Max Threshold Volume",
+ CS42L52_LIMITER_CTL1, 5, 7, 0, limiter_tlv),
+ SOC_SINGLE_TLV("Limiter Cushion Threshold Volume",
+ CS42L52_LIMITER_CTL1, 2, 7, 0, limiter_tlv),
+ SOC_SINGLE_TLV("Limiter Release Rate Volume",
+ CS42L52_LIMITER_CTL2, 0, 63, 0, limiter_tlv),
+ SOC_SINGLE_TLV("Limiter Attack Rate Volume",
+ CS42L52_LIMITER_AT_RATE, 0, 63, 0, limiter_tlv),
+
+ SOC_SINGLE("Limiter SR Switch", CS42L52_LIMITER_CTL1, 1, 1, 0),
+ SOC_SINGLE("Limiter ZC Switch", CS42L52_LIMITER_CTL1, 0, 1, 0),
+ SOC_SINGLE("Limiter Switch", CS42L52_LIMITER_CTL2, 7, 1, 0),
+
+ /* ALC */
+ SOC_SINGLE_TLV("ALC Attack Rate Volume", CS42L52_ALC_CTL,
+ 0, 63, 0, limiter_tlv),
+ SOC_SINGLE_TLV("ALC Release Rate Volume", CS42L52_ALC_RATE,
+ 0, 63, 0, limiter_tlv),
+ SOC_SINGLE_TLV("ALC Max Threshold Volume", CS42L52_ALC_THRESHOLD,
+ 5, 7, 0, limiter_tlv),
+ SOC_SINGLE_TLV("ALC Min Threshold Volume", CS42L52_ALC_THRESHOLD,
+ 2, 7, 0, limiter_tlv),
+
+ SOC_DOUBLE_R("ALC SR Capture Switch", CS42L52_PGAA_CTL,
+ CS42L52_PGAB_CTL, 7, 1, 1),
+ SOC_DOUBLE_R("ALC ZC Capture Switch", CS42L52_PGAA_CTL,
+ CS42L52_PGAB_CTL, 6, 1, 1),
+ SOC_DOUBLE("ALC Capture Switch", CS42L52_ALC_CTL, 6, 7, 1, 0),
+
+ /* Noise gate */
+ SOC_ENUM("NG Type Switch", ng_type_enum),
+ SOC_SINGLE("NG Enable Switch", CS42L52_NOISE_GATE_CTL, 6, 1, 0),
+ SOC_SINGLE("NG Boost Switch", CS42L52_NOISE_GATE_CTL, 5, 1, 1),
+ SOC_ENUM("NG Threshold", ng_threshold_enum),
+ SOC_ENUM("NG Delay", ng_delay_enum),
+
+ SOC_DOUBLE("HPF Switch", CS42L52_ANALOG_HPF_CTL, 5, 7, 1, 0),
+
+ SOC_DOUBLE("Analog SR Switch", CS42L52_ANALOG_HPF_CTL, 1, 3, 1, 1),
+ SOC_DOUBLE("Analog ZC Switch", CS42L52_ANALOG_HPF_CTL, 0, 2, 1, 1),
+ SOC_SINGLE("Digital SR Switch", CS42L52_MISC_CTL, 1, 1, 0),
+ SOC_SINGLE("Digital ZC Switch", CS42L52_MISC_CTL, 0, 1, 0),
+ SOC_SINGLE("Deemphasis Switch", CS42L52_MISC_CTL, 2, 1, 0),
+
+ SOC_SINGLE("Batt Compensation Switch", CS42L52_BATT_COMPEN, 7, 1, 0),
+ SOC_SINGLE("Batt VP Monitor Switch", CS42L52_BATT_COMPEN, 6, 1, 0),
+ SOC_SINGLE("Batt VP ref", CS42L52_BATT_COMPEN, 0, 0x0f, 0),
+
+ SOC_SINGLE("PGA AIN1L Switch", CS42L52_ADC_PGA_A, 0, 1, 0),
+ SOC_SINGLE("PGA AIN1R Switch", CS42L52_ADC_PGA_B, 0, 1, 0),
+ SOC_SINGLE("PGA AIN2L Switch", CS42L52_ADC_PGA_A, 1, 1, 0),
+ SOC_SINGLE("PGA AIN2R Switch", CS42L52_ADC_PGA_B, 1, 1, 0),
+
+ SOC_SINGLE("PGA AIN3L Switch", CS42L52_ADC_PGA_A, 2, 1, 0),
+ SOC_SINGLE("PGA AIN3R Switch", CS42L52_ADC_PGA_B, 2, 1, 0),
+
+ SOC_SINGLE("PGA AIN4L Switch", CS42L52_ADC_PGA_A, 3, 1, 0),
+ SOC_SINGLE("PGA AIN4R Switch", CS42L52_ADC_PGA_B, 3, 1, 0),
+
+ SOC_SINGLE("PGA MICA Switch", CS42L52_ADC_PGA_A, 4, 1, 0),
+ SOC_SINGLE("PGA MICB Switch", CS42L52_ADC_PGA_B, 4, 1, 0),
+
+};
+
+static const struct snd_soc_dapm_widget cs42l52_dapm_widgets[] = {
+
+ SND_SOC_DAPM_INPUT("AIN1L"),
+ SND_SOC_DAPM_INPUT("AIN1R"),
+ SND_SOC_DAPM_INPUT("AIN2L"),
+ SND_SOC_DAPM_INPUT("AIN2R"),
+ SND_SOC_DAPM_INPUT("AIN3L"),
+ SND_SOC_DAPM_INPUT("AIN3R"),
+ SND_SOC_DAPM_INPUT("AIN4L"),
+ SND_SOC_DAPM_INPUT("AIN4R"),
+ SND_SOC_DAPM_INPUT("MICA"),
+ SND_SOC_DAPM_INPUT("MICB"),
+ SND_SOC_DAPM_SIGGEN("Beep"),
+
+ SND_SOC_DAPM_AIF_OUT("AIFOUTL", NULL, 0,
+ SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("AIFOUTR", NULL, 0,
+ SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_MUX("MICA Mux", SND_SOC_NOPM, 0, 0, &mica_mux),
+ SND_SOC_DAPM_MUX("MICB Mux", SND_SOC_NOPM, 0, 0, &micb_mux),
+
+ SND_SOC_DAPM_ADC("ADC Left", NULL, CS42L52_PWRCTL1, 1, 1),
+ SND_SOC_DAPM_ADC("ADC Right", NULL, CS42L52_PWRCTL1, 2, 1),
+ SND_SOC_DAPM_PGA("PGA Left", CS42L52_PWRCTL1, 3, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("PGA Right", CS42L52_PWRCTL1, 4, 1, NULL, 0),
+
+ SND_SOC_DAPM_MUX("ADC Left Mux", SND_SOC_NOPM, 0, 0, &adca_mux),
+ SND_SOC_DAPM_MUX("ADC Right Mux", SND_SOC_NOPM, 0, 0, &adcb_mux),
+
+ SND_SOC_DAPM_MUX("ADC Left Swap", SND_SOC_NOPM,
+ 0, 0, &adca_mixer),
+ SND_SOC_DAPM_MUX("ADC Right Swap", SND_SOC_NOPM,
+ 0, 0, &adcb_mixer),
+
+ SND_SOC_DAPM_MUX("Output Mux", SND_SOC_NOPM,
+ 0, 0, &digital_output_mux),
+
+ SND_SOC_DAPM_PGA("PGA MICA", CS42L52_PWRCTL2, 1, 1, NULL, 0),
+ SND_SOC_DAPM_PGA("PGA MICB", CS42L52_PWRCTL2, 2, 1, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("Mic Bias", CS42L52_PWRCTL2, 0, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("Charge Pump", CS42L52_PWRCTL1, 7, 1, NULL, 0),
+
+ SND_SOC_DAPM_AIF_IN("AIFINL", NULL, 0,
+ SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("AIFINR", NULL, 0,
+ SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_DAC("DAC Left", NULL, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("DAC Right", NULL, SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_SWITCH("Bypass Left", CS42L52_MISC_CTL,
+ 6, 0, &passthrul_ctl),
+ SND_SOC_DAPM_SWITCH("Bypass Right", CS42L52_MISC_CTL,
+ 7, 0, &passthrur_ctl),
+
+ SND_SOC_DAPM_MUX("PCM Left Swap", SND_SOC_NOPM,
+ 0, 0, &pcma_mixer),
+ SND_SOC_DAPM_MUX("PCM Right Swap", SND_SOC_NOPM,
+ 0, 0, &pcmb_mixer),
+
+ SND_SOC_DAPM_SWITCH("HP Left Amp", SND_SOC_NOPM, 0, 0, &hpl_ctl),
+ SND_SOC_DAPM_SWITCH("HP Right Amp", SND_SOC_NOPM, 0, 0, &hpr_ctl),
+
+ SND_SOC_DAPM_SWITCH("SPK Left Amp", SND_SOC_NOPM, 0, 0, &spkl_ctl),
+ SND_SOC_DAPM_SWITCH("SPK Right Amp", SND_SOC_NOPM, 0, 0, &spkr_ctl),
+
+ SND_SOC_DAPM_OUTPUT("HPOUTA"),
+ SND_SOC_DAPM_OUTPUT("HPOUTB"),
+ SND_SOC_DAPM_OUTPUT("SPKOUTA"),
+ SND_SOC_DAPM_OUTPUT("SPKOUTB"),
+
+};
+
+static const struct snd_soc_dapm_route cs42l52_audio_map[] = {
+
+ {"Capture", NULL, "AIFOUTL"},
+ {"Capture", NULL, "AIFOUTL"},
+
+ {"AIFOUTL", NULL, "Output Mux"},
+ {"AIFOUTR", NULL, "Output Mux"},
+
+ {"Output Mux", "ADC", "ADC Left"},
+ {"Output Mux", "ADC", "ADC Right"},
+
+ {"ADC Left", NULL, "Charge Pump"},
+ {"ADC Right", NULL, "Charge Pump"},
+
+ {"Charge Pump", NULL, "ADC Left Mux"},
+ {"Charge Pump", NULL, "ADC Right Mux"},
+
+ {"ADC Left Mux", "Input1A", "AIN1L"},
+ {"ADC Right Mux", "Input1B", "AIN1R"},
+ {"ADC Left Mux", "Input2A", "AIN2L"},
+ {"ADC Right Mux", "Input2B", "AIN2R"},
+ {"ADC Left Mux", "Input3A", "AIN3L"},
+ {"ADC Right Mux", "Input3B", "AIN3R"},
+ {"ADC Left Mux", "Input4A", "AIN4L"},
+ {"ADC Right Mux", "Input4B", "AIN4R"},
+ {"ADC Left Mux", "PGA Input Left", "PGA Left"},
+ {"ADC Right Mux", "PGA Input Right" , "PGA Right"},
+
+ {"PGA Left", "Switch", "AIN1L"},
+ {"PGA Right", "Switch", "AIN1R"},
+ {"PGA Left", "Switch", "AIN2L"},
+ {"PGA Right", "Switch", "AIN2R"},
+ {"PGA Left", "Switch", "AIN3L"},
+ {"PGA Right", "Switch", "AIN3R"},
+ {"PGA Left", "Switch", "AIN4L"},
+ {"PGA Right", "Switch", "AIN4R"},
+
+ {"PGA Left", "Switch", "PGA MICA"},
+ {"PGA MICA", NULL, "MICA"},
+
+ {"PGA Right", "Switch", "PGA MICB"},
+ {"PGA MICB", NULL, "MICB"},
+
+ {"HPOUTA", NULL, "HP Left Amp"},
+ {"HPOUTB", NULL, "HP Right Amp"},
+ {"HP Left Amp", NULL, "Bypass Left"},
+ {"HP Right Amp", NULL, "Bypass Right"},
+ {"Bypass Left", "Switch", "PGA Left"},
+ {"Bypass Right", "Switch", "PGA Right"},
+ {"HP Left Amp", "Switch", "DAC Left"},
+ {"HP Right Amp", "Switch", "DAC Right"},
+
+ {"SPKOUTA", NULL, "SPK Left Amp"},
+ {"SPKOUTB", NULL, "SPK Right Amp"},
+
+ {"SPK Left Amp", NULL, "Beep"},
+ {"SPK Right Amp", NULL, "Beep"},
+ {"SPK Left Amp", "Switch", "Playback"},
+ {"SPK Right Amp", "Switch", "Playback"},
+
+ {"DAC Left", NULL, "Beep"},
+ {"DAC Right", NULL, "Beep"},
+ {"DAC Left", NULL, "Playback"},
+ {"DAC Right", NULL, "Playback"},
+
+ {"Output Mux", "DSP", "Playback"},
+ {"Output Mux", "DSP", "Playback"},
+
+ {"AIFINL", NULL, "Playback"},
+ {"AIFINR", NULL, "Playback"},
+
+};
+
+struct cs42l52_clk_para {
+ u32 mclk;
+ u32 rate;
+ u8 speed;
+ u8 group;
+ u8 videoclk;
+ u8 ratio;
+ u8 mclkdiv2;
+};
+
+static const struct cs42l52_clk_para clk_map_table[] = {
+ /*8k*/
+ {12288000, 8000, CLK_QS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+ {18432000, 8000, CLK_QS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+ {12000000, 8000, CLK_QS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 0},
+ {24000000, 8000, CLK_QS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 1},
+ {27000000, 8000, CLK_QS_MODE, CLK_32K, CLK_27M_MCLK, CLK_R_125, 0},
+
+ /*11.025k*/
+ {11289600, 11025, CLK_QS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+ {16934400, 11025, CLK_QS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+
+ /*16k*/
+ {12288000, 16000, CLK_HS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+ {18432000, 16000, CLK_HS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+ {12000000, 16000, CLK_HS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 0},
+ {24000000, 16000, CLK_HS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 1},
+ {27000000, 16000, CLK_HS_MODE, CLK_32K, CLK_27M_MCLK, CLK_R_125, 1},
+
+ /*22.05k*/
+ {11289600, 22050, CLK_HS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+ {16934400, 22050, CLK_HS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+
+ /* 32k */
+ {12288000, 32000, CLK_SS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+ {18432000, 32000, CLK_SS_MODE, CLK_32K, CLK_NO_27M, CLK_R_128, 0},
+ {12000000, 32000, CLK_SS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 0},
+ {24000000, 32000, CLK_SS_MODE, CLK_32K, CLK_NO_27M, CLK_R_125, 1},
+ {27000000, 32000, CLK_SS_MODE, CLK_32K, CLK_27M_MCLK, CLK_R_125, 0},
+
+ /* 44.1k */
+ {11289600, 44100, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+ {16934400, 44100, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+
+ /* 48k */
+ {12288000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+ {18432000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+ {12000000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_125, 0},
+ {24000000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_125, 1},
+ {27000000, 48000, CLK_SS_MODE, CLK_NO_32K, CLK_27M_MCLK, CLK_R_125, 1},
+
+ /* 88.2k */
+ {11289600, 88200, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+ {16934400, 88200, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+
+ /* 96k */
+ {12288000, 96000, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+ {18432000, 96000, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_128, 0},
+ {12000000, 96000, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_125, 0},
+ {24000000, 96000, CLK_DS_MODE, CLK_NO_32K, CLK_NO_27M, CLK_R_125, 1},
+};
+
+static int cs42l52_get_clk(int mclk, int rate)
+{
+ int i, ret = 0;
+ u_int mclk1, mclk2 = 0;
+
+ for (i = 0; i < ARRAY_SIZE(clk_map_table); i++) {
+ if (clk_map_table[i].rate == rate) {
+ mclk1 = clk_map_table[i].mclk;
+ if (abs(mclk - mclk1) < abs(mclk - mclk2)) {
+ mclk2 = mclk1;
+ ret = i;
+ }
+ }
+ }
+ if (ret > ARRAY_SIZE(clk_map_table))
+ return -EINVAL;
+ return ret;
+}
+
+static int cs42l52_set_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+
+ if ((freq >= CS42L52_MIN_CLK) && (freq <= CS42L52_MAX_CLK)) {
+ cs42l52->sysclk = freq;
+ } else {
+ dev_err(codec->dev, "Invalid freq paramter\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int cs42l52_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+ u8 iface = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ iface = CS42L52_IFACE_CTL1_MASTER;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ iface = CS42L52_IFACE_CTL1_SLAVE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ iface |= CS42L52_IFACE_CTL1_ADC_FMT_I2S |
+ CS42L52_IFACE_CTL1_DAC_FMT_I2S;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ iface |= CS42L52_IFACE_CTL1_DAC_FMT_RIGHT_J;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ iface |= CS42L52_IFACE_CTL1_ADC_FMT_LEFT_J |
+ CS42L52_IFACE_CTL1_DAC_FMT_LEFT_J;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ iface |= CS42L52_IFACE_CTL1_DSP_MODE_EN;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* clock inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ iface |= CS42L52_IFACE_CTL1_INV_SCLK;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ iface |= CS42L52_IFACE_CTL1_INV_SCLK;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ cs42l52->config.format = iface;
+ snd_soc_write(codec, CS42L52_IFACE_CTL1, cs42l52->config.format);
+
+ return 0;
+}
+
+static int cs42l52_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+
+ if (mute)
+ snd_soc_update_bits(codec, CS42L52_PB_CTL1,
+ CS42L52_PB_CTL1_MUTE_MASK,
+ CS42L52_PB_CTL1_MUTE);
+ else
+ snd_soc_update_bits(codec, CS42L52_PB_CTL1,
+ CS42L52_PB_CTL1_MUTE_MASK,
+ CS42L52_PB_CTL1_UNMUTE);
+
+ return 0;
+}
+
+static int cs42l52_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+ u32 clk = 0;
+ int index;
+
+ index = cs42l52_get_clk(cs42l52->sysclk, params_rate(params));
+ if (index >= 0) {
+ cs42l52->sysclk = clk_map_table[index].mclk;
+
+ clk |= (clk_map_table[index].speed << CLK_SPEED_SHIFT) |
+ (clk_map_table[index].group << CLK_32K_SR_SHIFT) |
+ (clk_map_table[index].videoclk << CLK_27M_MCLK_SHIFT) |
+ (clk_map_table[index].ratio << CLK_RATIO_SHIFT) |
+ clk_map_table[index].mclkdiv2;
+
+ snd_soc_write(codec, CS42L52_CLK_CTL, clk);
+ } else {
+ dev_err(codec->dev, "can't get correct mclk\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cs42l52_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ snd_soc_update_bits(codec, CS42L52_PWRCTL1,
+ CS42L52_PWRCTL1_PDN_CODEC, 0);
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ regcache_cache_only(cs42l52->regmap, false);
+ regcache_sync(cs42l52->regmap);
+ }
+ snd_soc_write(codec, CS42L52_PWRCTL1, CS42L52_PWRCTL1_PDN_ALL);
+ break;
+ case SND_SOC_BIAS_OFF:
+ snd_soc_write(codec, CS42L52_PWRCTL1, CS42L52_PWRCTL1_PDN_ALL);
+ regcache_cache_only(cs42l52->regmap, true);
+ break;
+ }
+ codec->dapm.bias_level = level;
+
+ return 0;
+}
+
+#define CS42L52_RATES (SNDRV_PCM_RATE_8000_96000)
+
+#define CS42L52_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \
+ SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_U18_3LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE)
+
+static struct snd_soc_dai_ops cs42l52_ops = {
+ .hw_params = cs42l52_pcm_hw_params,
+ .digital_mute = cs42l52_digital_mute,
+ .set_fmt = cs42l52_set_fmt,
+ .set_sysclk = cs42l52_set_sysclk,
+};
+
+static struct snd_soc_dai_driver cs42l52_dai = {
+ .name = "cs42l52",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = CS42L52_RATES,
+ .formats = CS42L52_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = CS42L52_RATES,
+ .formats = CS42L52_FORMATS,
+ },
+ .ops = &cs42l52_ops,
+};
+
+static int cs42l52_suspend(struct snd_soc_codec *codec)
+{
+ cs42l52_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+static int cs42l52_resume(struct snd_soc_codec *codec)
+{
+ cs42l52_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ return 0;
+}
+
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+static int beep_rates[] = {
+ 261, 522, 585, 667, 706, 774, 889, 1000,
+ 1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182
+};
+
+static void cs42l52_beep_work(struct work_struct *work)
+{
+ struct cs42l52_private *cs42l52 =
+ container_of(work, struct cs42l52_private, beep_work);
+ struct snd_soc_codec *codec = cs42l52->codec;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ int i;
+ int val = 0;
+ int best = 0;
+
+ if (cs42l52->beep_rate) {
+ for (i = 0; i < ARRAY_SIZE(beep_rates); i++) {
+ if (abs(cs42l52->beep_rate - beep_rates[i]) <
+ abs(cs42l52->beep_rate - beep_rates[best]))
+ best = i;
+ }
+
+ dev_dbg(codec->dev, "Set beep rate %dHz for requested %dHz\n",
+ beep_rates[best], cs42l52->beep_rate);
+
+ val = (best << CS42L52_BEEP_RATE_SHIFT);
+
+ snd_soc_dapm_enable_pin(dapm, "Beep");
+ } else {
+ dev_dbg(codec->dev, "Disabling beep\n");
+ snd_soc_dapm_disable_pin(dapm, "Beep");
+ }
+
+ snd_soc_update_bits(codec, CS42L52_BEEP_FREQ,
+ CS42L52_BEEP_RATE_MASK, val);
+
+ snd_soc_dapm_sync(dapm);
+}
+
+/* For usability define a way of injecting beep events for the device -
+ * many systems will not have a keyboard.
+ */
+static int cs42l52_beep_event(struct input_dev *dev, unsigned int type,
+ unsigned int code, int hz)
+{
+ struct snd_soc_codec *codec = input_get_drvdata(dev);
+ struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+
+ dev_dbg(codec->dev, "Beep event %x %x\n", code, hz);
+
+ switch (code) {
+ case SND_BELL:
+ if (hz)
+ hz = 261;
+ case SND_TONE:
+ break;
+ default:
+ return -1;
+ }
+
+ /* Kick the beep from a workqueue */
+ cs42l52->beep_rate = hz;
+ schedule_work(&cs42l52->beep_work);
+ return 0;
+}
+
+static ssize_t cs42l52_beep_set(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cs42l52_private *cs42l52 = dev_get_drvdata(dev);
+ long int time;
+ int ret;
+
+ ret = kstrtol(buf, 10, &time);
+ if (ret != 0)
+ return ret;
+
+ input_event(cs42l52->beep, EV_SND, SND_TONE, time);
+
+ return count;
+}
+
+static DEVICE_ATTR(beep, 0200, NULL, cs42l52_beep_set);
+
+static void cs42l52_init_beep(struct snd_soc_codec *codec)
+{
+ struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ cs42l52->beep = input_allocate_device();
+ if (!cs42l52->beep) {
+ dev_err(codec->dev, "Failed to allocate beep device\n");
+ return;
+ }
+
+ INIT_WORK(&cs42l52->beep_work, cs42l52_beep_work);
+ cs42l52->beep_rate = 0;
+
+ cs42l52->beep->name = "CS42L52 Beep Generator";
+ cs42l52->beep->phys = dev_name(codec->dev);
+ cs42l52->beep->id.bustype = BUS_I2C;
+
+ cs42l52->beep->evbit[0] = BIT_MASK(EV_SND);
+ cs42l52->beep->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
+ cs42l52->beep->event = cs42l52_beep_event;
+ cs42l52->beep->dev.parent = codec->dev;
+ input_set_drvdata(cs42l52->beep, codec);
+
+ ret = input_register_device(cs42l52->beep);
+ if (ret != 0) {
+ input_free_device(cs42l52->beep);
+ cs42l52->beep = NULL;
+ dev_err(codec->dev, "Failed to register beep device\n");
+ }
+
+ ret = device_create_file(codec->dev, &dev_attr_beep);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to create keyclick file: %d\n",
+ ret);
+ }
+}
+
+static void cs42l52_free_beep(struct snd_soc_codec *codec)
+{
+ struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+
+ device_remove_file(codec->dev, &dev_attr_beep);
+ input_unregister_device(cs42l52->beep);
+ cancel_work_sync(&cs42l52->beep_work);
+ cs42l52->beep = NULL;
+
+ snd_soc_update_bits(codec, CS42L52_BEEP_TONE_CTL,
+ CS42L52_BEEP_EN_MASK, 0);
+}
+#else
+static void cs42l52_init_beep(struct snd_soc_codec *codec)
+{
+}
+
+static void cs42l52_free_beep(struct snd_soc_codec *codec)
+{
+}
+#endif
+
+static int cs42l52_probe(struct snd_soc_codec *codec)
+{
+ struct cs42l52_private *cs42l52 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ codec->control_data = cs42l52->regmap;
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
+ regcache_cache_only(cs42l52->regmap, true);
+
+ cs42l52_init_beep(codec);
+
+ cs42l52_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ cs42l52->sysclk = CS42L52_DEFAULT_CLK;
+ cs42l52->config.format = CS42L52_DEFAULT_FORMAT;
+
+ /* Set Platform MICx CFG */
+ snd_soc_update_bits(codec, CS42L52_MICA_CTL,
+ CS42L52_MIC_CTL_TYPE_MASK,
+ cs42l52->pdata.mica_cfg <<
+ CS42L52_MIC_CTL_TYPE_SHIFT);
+
+ snd_soc_update_bits(codec, CS42L52_MICB_CTL,
+ CS42L52_MIC_CTL_TYPE_MASK,
+ cs42l52->pdata.micb_cfg <<
+ CS42L52_MIC_CTL_TYPE_SHIFT);
+
+ /* if Single Ended, Get Mic_Select */
+ if (cs42l52->pdata.mica_cfg)
+ snd_soc_update_bits(codec, CS42L52_MICA_CTL,
+ CS42L52_MIC_CTL_MIC_SEL_MASK,
+ cs42l52->pdata.mica_sel <<
+ CS42L52_MIC_CTL_MIC_SEL_SHIFT);
+ if (cs42l52->pdata.micb_cfg)
+ snd_soc_update_bits(codec, CS42L52_MICB_CTL,
+ CS42L52_MIC_CTL_MIC_SEL_MASK,
+ cs42l52->pdata.micb_sel <<
+ CS42L52_MIC_CTL_MIC_SEL_SHIFT);
+
+ /* Set Platform Charge Pump Freq */
+ snd_soc_update_bits(codec, CS42L52_CHARGE_PUMP,
+ CS42L52_CHARGE_PUMP_MASK,
+ cs42l52->pdata.chgfreq <<
+ CS42L52_CHARGE_PUMP_SHIFT);
+
+ /* Set Platform Bias Level */
+ snd_soc_update_bits(codec, CS42L52_IFACE_CTL2,
+ CS42L52_IFACE_CTL2_BIAS_LVL,
+ cs42l52->pdata.micbias_lvl);
+
+ return ret;
+}
+
+static int cs42l52_remove(struct snd_soc_codec *codec)
+{
+ cs42l52_free_beep(codec);
+ cs42l52_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_cs42l52 = {
+ .probe = cs42l52_probe,
+ .remove = cs42l52_remove,
+ .suspend = cs42l52_suspend,
+ .resume = cs42l52_resume,
+ .set_bias_level = cs42l52_set_bias_level,
+
+ .dapm_widgets = cs42l52_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cs42l52_dapm_widgets),
+ .dapm_routes = cs42l52_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(cs42l52_audio_map),
+
+ .controls = cs42l52_snd_controls,
+ .num_controls = ARRAY_SIZE(cs42l52_snd_controls),
+};
+
+/* Current and threshold powerup sequence Pg37 */
+static const struct reg_default cs42l52_threshold_patch[] = {
+
+ { 0x00, 0x99 },
+ { 0x3E, 0xBA },
+ { 0x47, 0x80 },
+ { 0x32, 0xBB },
+ { 0x32, 0x3B },
+ { 0x00, 0x00 },
+
+};
+
+static struct regmap_config cs42l52_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = CS42L52_MAX_REGISTER,
+ .reg_defaults = cs42l52_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(cs42l52_reg_defaults),
+ .readable_reg = cs42l52_readable_register,
+ .volatile_reg = cs42l52_volatile_register,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
+ const struct i2c_device_id *id)
+{
+ struct cs42l52_private *cs42l52;
+ int ret;
+ unsigned int devid = 0;
+ unsigned int reg;
+
+ cs42l52 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l52_private),
+ GFP_KERNEL);
+ if (cs42l52 == NULL)
+ return -ENOMEM;
+ cs42l52->dev = &i2c_client->dev;
+
+ cs42l52->regmap = regmap_init_i2c(i2c_client, &cs42l52_regmap);
+ if (IS_ERR(cs42l52->regmap)) {
+ ret = PTR_ERR(cs42l52->regmap);
+ dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret);
+ goto err;
+ }
+
+ i2c_set_clientdata(i2c_client, cs42l52);
+
+ if (dev_get_platdata(&i2c_client->dev))
+ memcpy(&cs42l52->pdata, dev_get_platdata(&i2c_client->dev),
+ sizeof(cs42l52->pdata));
+
+ ret = regmap_register_patch(cs42l52->regmap, cs42l52_threshold_patch,
+ ARRAY_SIZE(cs42l52_threshold_patch));
+ if (ret != 0)
+ dev_warn(cs42l52->dev, "Failed to apply regmap patch: %d\n",
+ ret);
+
+ ret = regmap_read(cs42l52->regmap, CS42L52_CHIP, &reg);
+ devid = reg & CS42L52_CHIP_ID_MASK;
+ if (devid != CS42L52_CHIP_ID) {
+ ret = -ENODEV;
+ dev_err(&i2c_client->dev,
+ "CS42L52 Device ID (%X). Expected %X\n",
+ devid, CS42L52_CHIP_ID);
+ goto err_regmap;
+ }
+
+ regcache_cache_only(cs42l52->regmap, true);
+
+ ret = snd_soc_register_codec(&i2c_client->dev,
+ &soc_codec_dev_cs42l52, &cs42l52_dai, 1);
+ if (ret < 0)
+ goto err_regmap;
+ return 0;
+
+err_regmap:
+ regmap_exit(cs42l52->regmap);
+
+err:
+ return ret;
+}
+
+static int cs42l52_i2c_remove(struct i2c_client *client)
+{
+ struct cs42l52_private *cs42l52 = i2c_get_clientdata(client);
+
+ snd_soc_unregister_codec(&client->dev);
+ regmap_exit(cs42l52->regmap);
+
+ return 0;
+}
+
+static const struct i2c_device_id cs42l52_id[] = {
+ { "cs42l52", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cs42l52_id);
+
+static struct i2c_driver cs42l52_i2c_driver = {
+ .driver = {
+ .name = "cs42l52",
+ .owner = THIS_MODULE,
+ },
+ .id_table = cs42l52_id,
+ .probe = cs42l52_i2c_probe,
+ .remove = __devexit_p(cs42l52_i2c_remove),
+};
+
+module_i2c_driver(cs42l52_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS42L52 driver");
+MODULE_AUTHOR("Georgi Vlaev, Nucleus Systems Ltd, <joe@nucleusys.com>");
+MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l52.h b/sound/soc/codecs/cs42l52.h
new file mode 100644
index 000000000000..60985c059071
--- /dev/null
+++ b/sound/soc/codecs/cs42l52.h
@@ -0,0 +1,274 @@
+/*
+ * cs42l52.h -- CS42L52 ALSA SoC audio driver
+ *
+ * Copyright 2012 CirrusLogic, Inc.
+ *
+ * Author: Georgi Vlaev <joe@nucleusys.com>
+ * Author: Brian Austin <brian.austin@cirrus.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 __CS42L52_H__
+#define __CS42L52_H__
+
+#define CS42L52_NAME "CS42L52"
+#define CS42L52_DEFAULT_CLK 12000000
+#define CS42L52_MIN_CLK 11000000
+#define CS42L52_MAX_CLK 27000000
+#define CS42L52_DEFAULT_FORMAT SNDRV_PCM_FMTBIT_S16_LE
+#define CS42L52_DEFAULT_MAX_CHANS 2
+#define CS42L52_SYSCLK 1
+
+#define CS42L52_CHIP_SWICTH (1 << 17)
+#define CS42L52_ALL_IN_ONE (1 << 16)
+#define CS42L52_CHIP_ONE 0x00
+#define CS42L52_CHIP_TWO 0x01
+#define CS42L52_CHIP_THR 0x02
+#define CS42L52_CHIP_MASK 0x0f
+
+#define CS42L52_FIX_BITS_CTL 0x00
+#define CS42L52_CHIP 0x01
+#define CS42L52_CHIP_ID 0xE0
+#define CS42L52_CHIP_ID_MASK 0xF8
+#define CS42L52_CHIP_REV_A0 0x00
+#define CS42L52_CHIP_REV_A1 0x01
+#define CS42L52_CHIP_REV_B0 0x02
+#define CS42L52_CHIP_REV_MASK 0x03
+
+#define CS42L52_PWRCTL1 0x02
+#define CS42L52_PWRCTL1_PDN_ALL 0x9F
+#define CS42L52_PWRCTL1_PDN_CHRG 0x80
+#define CS42L52_PWRCTL1_PDN_PGAB 0x10
+#define CS42L52_PWRCTL1_PDN_PGAA 0x08
+#define CS42L52_PWRCTL1_PDN_ADCB 0x04
+#define CS42L52_PWRCTL1_PDN_ADCA 0x02
+#define CS42L52_PWRCTL1_PDN_CODEC 0x01
+
+#define CS42L52_PWRCTL2 0x03
+#define CS42L52_PWRCTL2_OVRDB (1 << 4)
+#define CS42L52_PWRCTL2_OVRDA (1 << 3)
+#define CS42L52_PWRCTL2_PDN_MICB (1 << 2)
+#define CS42L52_PWRCTL2_PDN_MICB_SHIFT 2
+#define CS42L52_PWRCTL2_PDN_MICA (1 << 1)
+#define CS42L52_PWRCTL2_PDN_MICA_SHIFT 1
+#define CS42L52_PWRCTL2_PDN_MICBIAS (1 << 0)
+#define CS42L52_PWRCTL2_PDN_MICBIAS_SHIFT 0
+
+#define CS42L52_PWRCTL3 0x04
+#define CS42L52_PWRCTL3_HPB_PDN_SHIFT 6
+#define CS42L52_PWRCTL3_HPB_ON_LOW 0x00
+#define CS42L52_PWRCTL3_HPB_ON_HIGH 0x01
+#define CS42L52_PWRCTL3_HPB_ALWAYS_ON 0x02
+#define CS42L52_PWRCTL3_HPB_ALWAYS_OFF 0x03
+#define CS42L52_PWRCTL3_HPA_PDN_SHIFT 4
+#define CS42L52_PWRCTL3_HPA_ON_LOW 0x00
+#define CS42L52_PWRCTL3_HPA_ON_HIGH 0x01
+#define CS42L52_PWRCTL3_HPA_ALWAYS_ON 0x02
+#define CS42L52_PWRCTL3_HPA_ALWAYS_OFF 0x03
+#define CS42L52_PWRCTL3_SPKB_PDN_SHIFT 2
+#define CS42L52_PWRCTL3_SPKB_ON_LOW 0x00
+#define CS42L52_PWRCTL3_SPKB_ON_HIGH 0x01
+#define CS42L52_PWRCTL3_SPKB_ALWAYS_ON 0x02
+#define CS42L52_PWRCTL3_PDN_SPKB (1 << 2)
+#define CS42L52_PWRCTL3_PDN_SPKA (1 << 0)
+#define CS42L52_PWRCTL3_SPKA_PDN_SHIFT 0
+#define CS42L52_PWRCTL3_SPKA_ON_LOW 0x00
+#define CS42L52_PWRCTL3_SPKA_ON_HIGH 0x01
+#define CS42L52_PWRCTL3_SPKA_ALWAYS_ON 0x02
+
+#define CS42L52_DEFAULT_OUTPUT_STATE 0x05
+#define CS42L52_PWRCTL3_CONF_MASK 0x03
+
+#define CS42L52_CLK_CTL 0x05
+#define CLK_AUTODECT_ENABLE (1 << 7)
+#define CLK_SPEED_SHIFT 5
+#define CLK_DS_MODE 0x00
+#define CLK_SS_MODE 0x01
+#define CLK_HS_MODE 0x02
+#define CLK_QS_MODE 0x03
+#define CLK_32K_SR_SHIFT 4
+#define CLK_32K 0x01
+#define CLK_NO_32K 0x00
+#define CLK_27M_MCLK_SHIFT 3
+#define CLK_27M_MCLK 0x01
+#define CLK_NO_27M 0x00
+#define CLK_RATIO_SHIFT 1
+#define CLK_R_128 0x00
+#define CLK_R_125 0x01
+#define CLK_R_132 0x02
+#define CLK_R_136 0x03
+
+#define CS42L52_IFACE_CTL1 0x06
+#define CS42L52_IFACE_CTL1_MASTER (1 << 7)
+#define CS42L52_IFACE_CTL1_SLAVE (0 << 7)
+#define CS42L52_IFACE_CTL1_INV_SCLK (1 << 6)
+#define CS42L52_IFACE_CTL1_ADC_FMT_I2S (1 << 5)
+#define CS42L52_IFACE_CTL1_ADC_FMT_LEFT_J (0 << 5)
+#define CS42L52_IFACE_CTL1_DSP_MODE_EN (1 << 4)
+#define CS42L52_IFACE_CTL1_DAC_FMT_LEFT_J (0 << 2)
+#define CS42L52_IFACE_CTL1_DAC_FMT_I2S (1 << 2)
+#define CS42L52_IFACE_CTL1_DAC_FMT_RIGHT_J (2 << 2)
+#define CS42L52_IFACE_CTL1_WL_32BIT (0x00)
+#define CS42L52_IFACE_CTL1_WL_24BIT (0x01)
+#define CS42L52_IFACE_CTL1_WL_20BIT (0x02)
+#define CS42L52_IFACE_CTL1_WL_16BIT (0x03)
+#define CS42L52_IFACE_CTL1_WL_MASK 0xFFFF
+
+#define CS42L52_IFACE_CTL2 0x07
+#define CS42L52_IFACE_CTL2_SC_MC_EQ (1 << 6)
+#define CS42L52_IFACE_CTL2_LOOPBACK (1 << 5)
+#define CS42L52_IFACE_CTL2_S_MODE_OUTPUT_EN (0 << 4)
+#define CS42L52_IFACE_CTL2_S_MODE_OUTPUT_HIZ (1 << 4)
+#define CS42L52_IFACE_CTL2_HP_SW_INV (1 << 3)
+#define CS42L52_IFACE_CTL2_BIAS_LVL 0x07
+
+#define CS42L52_ADC_PGA_A 0x08
+#define CS42L52_ADC_PGA_B 0x09
+#define CS42L52_ADC_SEL_SHIFT 5
+#define CS42L52_ADC_SEL_AIN1 0x00
+#define CS42L52_ADC_SEL_AIN2 0x01
+#define CS42L52_ADC_SEL_AIN3 0x02
+#define CS42L52_ADC_SEL_AIN4 0x03
+#define CS42L52_ADC_SEL_PGA 0x04
+
+#define CS42L52_ANALOG_HPF_CTL 0x0A
+#define CS42L52_HPF_CTL_ANLGSFTB (1 << 3)
+#define CS42L52_HPF_CTL_ANLGSFTA (1 << 0)
+
+#define CS42L52_ADC_HPF_FREQ 0x0B
+#define CS42L52_ADC_MISC_CTL 0x0C
+#define CS42L52_ADC_MISC_CTL_SOURCE_DSP (1 << 6)
+
+#define CS42L52_PB_CTL1 0x0D
+#define CS42L52_PB_CTL1_HP_GAIN_SHIFT 5
+#define CS42L52_PB_CTL1_HP_GAIN_03959 0x00
+#define CS42L52_PB_CTL1_HP_GAIN_04571 0x01
+#define CS42L52_PB_CTL1_HP_GAIN_05111 0x02
+#define CS42L52_PB_CTL1_HP_GAIN_06047 0x03
+#define CS42L52_PB_CTL1_HP_GAIN_07099 0x04
+#define CS42L52_PB_CTL1_HP_GAIN_08399 0x05
+#define CS42L52_PB_CTL1_HP_GAIN_10000 0x06
+#define CS42L52_PB_CTL1_HP_GAIN_11430 0x07
+#define CS42L52_PB_CTL1_INV_PCMB (1 << 3)
+#define CS42L52_PB_CTL1_INV_PCMA (1 << 2)
+#define CS42L52_PB_CTL1_MSTB_MUTE (1 << 1)
+#define CS42L52_PB_CTL1_MSTA_MUTE (1 << 0)
+#define CS42L52_PB_CTL1_MUTE_MASK 0xFFFD
+#define CS42L52_PB_CTL1_MUTE 3
+#define CS42L52_PB_CTL1_UNMUTE 0
+
+#define CS42L52_MISC_CTL 0x0E
+#define CS42L52_MISC_CTL_DEEMPH (1 << 2)
+#define CS42L52_MISC_CTL_DIGSFT (1 << 1)
+#define CS42L52_MISC_CTL_DIGZC (1 << 0)
+
+#define CS42L52_PB_CTL2 0x0F
+#define CS42L52_PB_CTL2_HPB_MUTE (1 << 7)
+#define CS42L52_PB_CTL2_HPA_MUTE (1 << 6)
+#define CS42L52_PB_CTL2_SPKB_MUTE (1 << 5)
+#define CS42L52_PB_CTL2_SPKA_MUTE (1 << 4)
+#define CS42L52_PB_CTL2_SPK_SWAP (1 << 2)
+#define CS42L52_PB_CTL2_SPK_MONO (1 << 1)
+#define CS42L52_PB_CTL2_SPK_MUTE50 (1 << 0)
+
+#define CS42L52_MICA_CTL 0x10
+#define CS42L52_MICB_CTL 0x11
+#define CS42L52_MIC_CTL_MIC_SEL_MASK 0xBF
+#define CS42L52_MIC_CTL_MIC_SEL_SHIFT 6
+#define CS42L52_MIC_CTL_TYPE_MASK 0xDF
+#define CS42L52_MIC_CTL_TYPE_SHIFT 5
+
+
+#define CS42L52_PGAA_CTL 0x12
+#define CS42L52_PGAB_CTL 0x13
+#define CS42L52_PGAX_CTL_VOL_12DB 24
+#define CS42L52_PGAX_CTL_VOL_6DB 12 /*step size 0.5db*/
+
+#define CS42L52_PASSTHRUA_VOL 0x14
+#define CS42L52_PASSTHRUB_VOL 0x15
+
+#define CS42L52_ADCA_VOL 0x16
+#define CS42L52_ADCB_VOL 0x17
+#define CS42L52_ADCX_VOL_24DB 24 /*step size 1db*/
+#define CS42L52_ADCX_VOL_12DB 12
+#define CS42L52_ADCX_VOL_6DB 6
+
+#define CS42L52_ADCA_MIXER_VOL 0x18
+#define CS42L52_ADCB_MIXER_VOL 0x19
+#define CS42L52_ADC_MIXER_VOL_12DB 0x18
+
+#define CS42L52_PCMA_MIXER_VOL 0x1A
+#define CS42L52_PCMB_MIXER_VOL 0x1B
+
+#define CS42L52_BEEP_FREQ 0x1C
+#define CS42L52_BEEP_VOL 0x1D
+#define CS42L52_BEEP_TONE_CTL 0x1E
+#define CS42L52_BEEP_RATE_SHIFT 4
+#define CS42L52_BEEP_RATE_MASK 0x0F
+
+#define CS42L52_TONE_CTL 0x1F
+#define CS42L52_BEEP_EN_MASK 0x3F
+
+#define CS42L52_MASTERA_VOL 0x20
+#define CS42L52_MASTERB_VOL 0x21
+
+#define CS42L52_HPA_VOL 0x22
+#define CS42L52_HPB_VOL 0x23
+#define CS42L52_DEFAULT_HP_VOL 0xF0
+
+#define CS42L52_SPKA_VOL 0x24
+#define CS42L52_SPKB_VOL 0x25
+#define CS42L52_DEFAULT_SPK_VOL 0xF0
+
+#define CS42L52_ADC_PCM_MIXER 0x26
+
+#define CS42L52_LIMITER_CTL1 0x27
+#define CS42L52_LIMITER_CTL2 0x28
+#define CS42L52_LIMITER_AT_RATE 0x29
+
+#define CS42L52_ALC_CTL 0x2A
+#define CS42L52_ALC_CTL_ALCB_ENABLE_SHIFT 7
+#define CS42L52_ALC_CTL_ALCA_ENABLE_SHIFT 6
+#define CS42L52_ALC_CTL_FASTEST_ATTACK 0
+
+#define CS42L52_ALC_RATE 0x2B
+#define CS42L52_ALC_SLOWEST_RELEASE 0x3F
+
+#define CS42L52_ALC_THRESHOLD 0x2C
+#define CS42L52_ALC_MAX_RATE_SHIFT 5
+#define CS42L52_ALC_MIN_RATE_SHIFT 2
+#define CS42L52_ALC_RATE_0DB 0
+#define CS42L52_ALC_RATE_3DB 1
+#define CS42L52_ALC_RATE_6DB 2
+
+#define CS42L52_NOISE_GATE_CTL 0x2D
+#define CS42L52_NG_ENABLE_SHIFT 6
+#define CS42L52_NG_THRESHOLD_SHIFT 2
+#define CS42L52_NG_MIN_70DB 2
+#define CS42L52_NG_DELAY_SHIFT 0
+#define CS42L52_NG_DELAY_100MS 1
+
+#define CS42L52_CLK_STATUS 0x2E
+#define CS42L52_BATT_COMPEN 0x2F
+
+#define CS42L52_BATT_LEVEL 0x30
+#define CS42L52_SPK_STATUS 0x31
+#define CS42L52_SPK_STATUS_PIN_SHIFT 3
+#define CS42L52_SPK_STATUS_PIN_HIGH 1
+
+#define CS42L52_TEM_CTL 0x32
+#define CS42L52_TEM_CTL_SET 0x80
+#define CS42L52_THE_FOLDBACK 0x33
+#define CS42L52_CHARGE_PUMP 0x34
+#define CS42L52_CHARGE_PUMP_MASK 0xF0
+#define CS42L52_CHARGE_PUMP_SHIFT 4
+#define CS42L52_FIX_BITS1 0x3E
+#define CS42L52_FIX_BITS2 0x47
+
+#define CS42L52_MAX_REGISTER 0x34
+
+#endif
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
index 3686417f5ea5..e0d45fdaa750 100644
--- a/sound/soc/codecs/cs42l73.c
+++ b/sound/soc/codecs/cs42l73.c
@@ -43,9 +43,6 @@ struct cs42l73_private {
};
static const struct reg_default cs42l73_reg_defaults[] = {
- { 1, 0x42 }, /* r01 - Device ID A&B */
- { 2, 0xA7 }, /* r02 - Device ID C&D */
- { 3, 0x30 }, /* r03 - Device ID E */
{ 6, 0xF1 }, /* r06 - Power Ctl 1 */
{ 7, 0xDF }, /* r07 - Power Ctl 2 */
{ 8, 0x3F }, /* r08 - Power Ctl 3 */
@@ -402,37 +399,37 @@ static const struct snd_kcontrol_new ear_amp_ctl =
static const struct snd_kcontrol_new cs42l73_snd_controls[] = {
SOC_DOUBLE_R_SX_TLV("Headphone Analog Playback Volume",
- CS42L73_HPAAVOL, CS42L73_HPBAVOL, 7,
- 0xffffffC1, 0x0C, hpaloa_tlv),
+ CS42L73_HPAAVOL, CS42L73_HPBAVOL, 0,
+ 0x41, 0x4B, hpaloa_tlv),
SOC_DOUBLE_R_SX_TLV("LineOut Analog Playback Volume", CS42L73_LOAAVOL,
- CS42L73_LOBAVOL, 7, 0xffffffC1, 0x0C, hpaloa_tlv),
+ CS42L73_LOBAVOL, 0, 0x41, 0x4B, hpaloa_tlv),
SOC_DOUBLE_R_SX_TLV("Input PGA Analog Volume", CS42L73_MICAPREPGAAVOL,
- CS42L73_MICBPREPGABVOL, 5, 0xffffff35,
- 0x34, micpga_tlv),
+ CS42L73_MICBPREPGABVOL, 5, 0x34,
+ 0x24, micpga_tlv),
SOC_DOUBLE_R("MIC Preamp Switch", CS42L73_MICAPREPGAAVOL,
CS42L73_MICBPREPGABVOL, 6, 1, 1),
SOC_DOUBLE_R_SX_TLV("Input Path Digital Volume", CS42L73_IPADVOL,
- CS42L73_IPBDVOL, 7, 0xffffffA0, 0xA0, ipd_tlv),
+ CS42L73_IPBDVOL, 0, 0xA0, 0x6C, ipd_tlv),
SOC_DOUBLE_R_SX_TLV("HL Digital Playback Volume",
- CS42L73_HLADVOL, CS42L73_HLBDVOL, 7, 0xffffffE5,
- 0xE4, hl_tlv),
+ CS42L73_HLADVOL, CS42L73_HLBDVOL,
+ 0, 0x34, 0xE4, hl_tlv),
SOC_SINGLE_TLV("ADC A Boost Volume",
CS42L73_ADCIPC, 2, 0x01, 1, adc_boost_tlv),
SOC_SINGLE_TLV("ADC B Boost Volume",
- CS42L73_ADCIPC, 6, 0x01, 1, adc_boost_tlv),
+ CS42L73_ADCIPC, 6, 0x01, 1, adc_boost_tlv),
- SOC_SINGLE_TLV("Speakerphone Digital Playback Volume",
- CS42L73_SPKDVOL, 0, 0xE4, 1, hl_tlv),
+ SOC_SINGLE_SX_TLV("Speakerphone Digital Volume",
+ CS42L73_SPKDVOL, 0, 0x34, 0xE4, hl_tlv),
- SOC_SINGLE_TLV("Ear Speaker Digital Playback Volume",
- CS42L73_ESLDVOL, 0, 0xE4, 1, hl_tlv),
+ SOC_SINGLE_SX_TLV("Ear Speaker Digital Volume",
+ CS42L73_ESLDVOL, 0, 0x34, 0xE4, hl_tlv),
SOC_DOUBLE_R("Headphone Analog Playback Switch", CS42L73_HPAAVOL,
CS42L73_HPBAVOL, 7, 1, 1),
@@ -599,17 +596,17 @@ static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("MIC2"),
SND_SOC_DAPM_SUPPLY("MIC2 Bias", CS42L73_PWRCTL2, 7, 1, NULL, 0),
- SND_SOC_DAPM_AIF_OUT("XSPOUTL", "XSP Capture", 0,
+ SND_SOC_DAPM_AIF_OUT("XSPOUTL", NULL, 0,
CS42L73_PWRCTL2, 1, 1),
- SND_SOC_DAPM_AIF_OUT("XSPOUTR", "XSP Capture", 0,
+ SND_SOC_DAPM_AIF_OUT("XSPOUTR", NULL, 0,
CS42L73_PWRCTL2, 1, 1),
- SND_SOC_DAPM_AIF_OUT("ASPOUTL", "ASP Capture", 0,
+ SND_SOC_DAPM_AIF_OUT("ASPOUTL", NULL, 0,
CS42L73_PWRCTL2, 3, 1),
- SND_SOC_DAPM_AIF_OUT("ASPOUTR", "ASP Capture", 0,
+ SND_SOC_DAPM_AIF_OUT("ASPOUTR", NULL, 0,
CS42L73_PWRCTL2, 3, 1),
- SND_SOC_DAPM_AIF_OUT("VSPOUTL", "VSP Capture", 0,
+ SND_SOC_DAPM_AIF_OUT("VSPOUTL", NULL, 0,
CS42L73_PWRCTL2, 4, 1),
- SND_SOC_DAPM_AIF_OUT("VSPOUTR", "VSP Capture", 0,
+ SND_SOC_DAPM_AIF_OUT("VSPOUTR", NULL, 0,
CS42L73_PWRCTL2, 4, 1),
SND_SOC_DAPM_PGA("PGA Left", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -638,21 +635,21 @@ static const struct snd_soc_dapm_widget cs42l73_dapm_widgets[] = {
SND_SOC_DAPM_MIXER("VSPL Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER("VSPR Output Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_AIF_IN("XSPINL", "XSP Playback", 0,
+ SND_SOC_DAPM_AIF_IN("XSPINL", NULL, 0,
CS42L73_PWRCTL2, 0, 1),
- SND_SOC_DAPM_AIF_IN("XSPINR", "XSP Playback", 0,
+ SND_SOC_DAPM_AIF_IN("XSPINR", NULL, 0,
CS42L73_PWRCTL2, 0, 1),
- SND_SOC_DAPM_AIF_IN("XSPINM", "XSP Playback", 0,
+ SND_SOC_DAPM_AIF_IN("XSPINM", NULL, 0,
CS42L73_PWRCTL2, 0, 1),
- SND_SOC_DAPM_AIF_IN("ASPINL", "ASP Playback", 0,
+ SND_SOC_DAPM_AIF_IN("ASPINL", NULL, 0,
CS42L73_PWRCTL2, 2, 1),
- SND_SOC_DAPM_AIF_IN("ASPINR", "ASP Playback", 0,
+ SND_SOC_DAPM_AIF_IN("ASPINR", NULL, 0,
CS42L73_PWRCTL2, 2, 1),
- SND_SOC_DAPM_AIF_IN("ASPINM", "ASP Playback", 0,
+ SND_SOC_DAPM_AIF_IN("ASPINM", NULL, 0,
CS42L73_PWRCTL2, 2, 1),
- SND_SOC_DAPM_AIF_IN("VSPIN", "VSP Playback", 0,
+ SND_SOC_DAPM_AIF_IN("VSPIN", NULL, 0,
CS42L73_PWRCTL2, 4, 1),
SND_SOC_DAPM_MIXER("HL Left Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
@@ -776,6 +773,14 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = {
{"HL Left Mixer", NULL, "VSPIN"},
{"HL Right Mixer", NULL, "VSPIN"},
+ {"ASPINL", NULL, "ASP Playback"},
+ {"ASPINM", NULL, "ASP Playback"},
+ {"ASPINR", NULL, "ASP Playback"},
+ {"XSPINL", NULL, "XSP Playback"},
+ {"XSPINM", NULL, "XSP Playback"},
+ {"XSPINR", NULL, "XSP Playback"},
+ {"VSPIN", NULL, "VSP Playback"},
+
/* Capture Paths */
{"MIC1", NULL, "MIC1 Bias"},
{"PGA Left Mux", "Mic 1", "MIC1"},
@@ -822,6 +827,13 @@ static const struct snd_soc_dapm_route cs42l73_audio_map[] = {
{"VSPOUTL", NULL, "VSPL Output Mixer"},
{"VSPOUTR", NULL, "VSPR Output Mixer"},
+
+ {"ASP Capture", NULL, "ASPOUTL"},
+ {"ASP Capture", NULL, "ASPOUTR"},
+ {"XSP Capture", NULL, "XSPOUTL"},
+ {"XSP Capture", NULL, "XSPOUTR"},
+ {"VSP Capture", NULL, "VSPOUTL"},
+ {"VSP Capture", NULL, "VSPOUTR"},
};
struct cs42l73_mclk_div {
@@ -1091,8 +1103,7 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
int id = dai->id;
int mclk_coeff;
@@ -1429,25 +1440,7 @@ static struct i2c_driver cs42l73_i2c_driver = {
};
-static int __init cs42l73_modinit(void)
-{
- int ret;
- ret = i2c_add_driver(&cs42l73_i2c_driver);
- if (ret != 0) {
- pr_err("Failed to register CS42L73 I2C driver: %d\n", ret);
- return ret;
- }
- return 0;
-}
-
-module_init(cs42l73_modinit);
-
-static void __exit cs42l73_exit(void)
-{
- i2c_del_driver(&cs42l73_i2c_driver);
-}
-
-module_exit(cs42l73_exit);
+module_i2c_driver(cs42l73_i2c_driver);
MODULE_DESCRIPTION("ASoC CS42L73 driver");
MODULE_AUTHOR("Georgi Vlaev, Nucleus Systems Ltd, <joe@nucleusys.com>");
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index 7843711729bc..af5db7080519 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -17,6 +17,7 @@
#include <linux/delay.h>
#include <linux/i2c.h>
+#include <linux/spi/spi.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -27,6 +28,7 @@
#include <sound/tlv.h>
/* DA7210 register space */
+#define DA7210_PAGE_CONTROL 0x00
#define DA7210_CONTROL 0x01
#define DA7210_STATUS 0x02
#define DA7210_STARTUP1 0x03
@@ -146,6 +148,7 @@
#define DA7210_DAI_EN (1 << 7)
/*PLL_DIV3 bit fields */
+#define DA7210_PLL_DIV_L_MASK (0xF << 0)
#define DA7210_MCLK_RANGE_10_20_MHZ (1 << 4)
#define DA7210_PLL_BYP (1 << 6)
@@ -162,12 +165,16 @@
#define DA7210_PLL_FS_48000 (0xB << 0)
#define DA7210_PLL_FS_88200 (0xE << 0)
#define DA7210_PLL_FS_96000 (0xF << 0)
+#define DA7210_MCLK_DET_EN (0x1 << 5)
+#define DA7210_MCLK_SRM_EN (0x1 << 6)
#define DA7210_PLL_EN (0x1 << 7)
/* SOFTMUTE bit fields */
#define DA7210_RAMP_EN (1 << 6)
/* CONTROL bit fields */
+#define DA7210_REG_EN (1 << 0)
+#define DA7210_BIAS_EN (1 << 2)
#define DA7210_NOISE_SUP_EN (1 << 3)
/* IN_GAIN bit fields */
@@ -206,6 +213,47 @@
#define DA7210_OUT2_OUTMIX_L (1 << 6)
#define DA7210_OUT2_EN (1 << 7)
+struct pll_div {
+ int fref;
+ int fout;
+ u8 div1;
+ u8 div2;
+ u8 div3;
+ u8 mode; /* 0 = slave, 1 = master */
+};
+
+/* PLL dividers table */
+static const struct pll_div da7210_pll_div[] = {
+ /* for MASTER mode, fs = 44.1Khz */
+ { 12000000, 2822400, 0xE8, 0x6C, 0x2, 1}, /* MCLK=12Mhz */
+ { 13000000, 2822400, 0xDF, 0x28, 0xC, 1}, /* MCLK=13Mhz */
+ { 13500000, 2822400, 0xDB, 0x0A, 0xD, 1}, /* MCLK=13.5Mhz */
+ { 14400000, 2822400, 0xD4, 0x5A, 0x2, 1}, /* MCLK=14.4Mhz */
+ { 19200000, 2822400, 0xBB, 0x43, 0x9, 1}, /* MCLK=19.2Mhz */
+ { 19680000, 2822400, 0xB9, 0x6D, 0xA, 1}, /* MCLK=19.68Mhz */
+ { 19800000, 2822400, 0xB8, 0xFB, 0xB, 1}, /* MCLK=19.8Mhz */
+ /* for MASTER mode, fs = 48Khz */
+ { 12000000, 3072000, 0xF3, 0x12, 0x7, 1}, /* MCLK=12Mhz */
+ { 13000000, 3072000, 0xE8, 0xFD, 0x5, 1}, /* MCLK=13Mhz */
+ { 13500000, 3072000, 0xE4, 0x82, 0x3, 1}, /* MCLK=13.5Mhz */
+ { 14400000, 3072000, 0xDD, 0x3A, 0x0, 1}, /* MCLK=14.4Mhz */
+ { 19200000, 3072000, 0xC1, 0xEB, 0x8, 1}, /* MCLK=19.2Mhz */
+ { 19680000, 3072000, 0xBF, 0xEC, 0x0, 1}, /* MCLK=19.68Mhz */
+ { 19800000, 3072000, 0xBF, 0x70, 0x0, 1}, /* MCLK=19.8Mhz */
+ /* for SLAVE mode with SRM */
+ { 12000000, 2822400, 0xED, 0xBF, 0x5, 0}, /* MCLK=12Mhz */
+ { 13000000, 2822400, 0xE4, 0x13, 0x0, 0}, /* MCLK=13Mhz */
+ { 13500000, 2822400, 0xDF, 0xC6, 0x8, 0}, /* MCLK=13.5Mhz */
+ { 14400000, 2822400, 0xD8, 0xCA, 0x1, 0}, /* MCLK=14.4Mhz */
+ { 19200000, 2822400, 0xBE, 0x97, 0x9, 0}, /* MCLK=19.2Mhz */
+ { 19680000, 2822400, 0xBC, 0xAC, 0xD, 0}, /* MCLK=19.68Mhz */
+ { 19800000, 2822400, 0xBC, 0x35, 0xE, 0}, /* MCLK=19.8Mhz */
+};
+
+enum clk_src {
+ DA7210_CLKSRC_MCLK
+};
+
#define DA7210_VERSION "0.0.1"
/*
@@ -628,9 +676,12 @@ static const struct snd_soc_dapm_route da7210_audio_map[] = {
/* Codec private data */
struct da7210_priv {
struct regmap *regmap;
+ unsigned int mclk_rate;
+ int master;
};
static struct reg_default da7210_reg_defaults[] = {
+ { 0x00, 0x00 },
{ 0x01, 0x11 },
{ 0x03, 0x00 },
{ 0x04, 0x00 },
@@ -713,10 +764,10 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
+ struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
u32 dai_cfg1;
- u32 fs, bypass;
+ u32 fs, sysclk;
/* set DAI source to Left and Right ADC */
snd_soc_write(codec, DA7210_DAI_SRC_SEL,
@@ -749,43 +800,43 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
switch (params_rate(params)) {
case 8000:
fs = DA7210_PLL_FS_8000;
- bypass = DA7210_PLL_BYP;
+ sysclk = 3072000;
break;
case 11025:
fs = DA7210_PLL_FS_11025;
- bypass = 0;
+ sysclk = 2822400;
break;
case 12000:
fs = DA7210_PLL_FS_12000;
- bypass = DA7210_PLL_BYP;
+ sysclk = 3072000;
break;
case 16000:
fs = DA7210_PLL_FS_16000;
- bypass = DA7210_PLL_BYP;
+ sysclk = 3072000;
break;
case 22050:
fs = DA7210_PLL_FS_22050;
- bypass = 0;
+ sysclk = 2822400;
break;
case 32000:
fs = DA7210_PLL_FS_32000;
- bypass = DA7210_PLL_BYP;
+ sysclk = 3072000;
break;
case 44100:
fs = DA7210_PLL_FS_44100;
- bypass = 0;
+ sysclk = 2822400;
break;
case 48000:
fs = DA7210_PLL_FS_48000;
- bypass = DA7210_PLL_BYP;
+ sysclk = 3072000;
break;
case 88200:
fs = DA7210_PLL_FS_88200;
- bypass = 0;
+ sysclk = 2822400;
break;
case 96000:
fs = DA7210_PLL_FS_96000;
- bypass = DA7210_PLL_BYP;
+ sysclk = 3072000;
break;
default:
return -EINVAL;
@@ -795,8 +846,26 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
snd_soc_update_bits(codec, DA7210_STARTUP1, DA7210_SC_MST_EN, 0);
snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_FS_MASK, fs);
- snd_soc_update_bits(codec, DA7210_PLL_DIV3, DA7210_PLL_BYP, bypass);
+ if (da7210->mclk_rate && (da7210->mclk_rate != sysclk)) {
+ /* PLL mode, disable PLL bypass */
+ snd_soc_update_bits(codec, DA7210_PLL_DIV3, DA7210_PLL_BYP, 0);
+
+ if (!da7210->master) {
+ /* PLL slave mode, also enable SRM */
+ snd_soc_update_bits(codec, DA7210_PLL,
+ (DA7210_MCLK_SRM_EN |
+ DA7210_MCLK_DET_EN),
+ (DA7210_MCLK_SRM_EN |
+ DA7210_MCLK_DET_EN));
+ }
+ } else {
+ /* PLL bypass mode, enable PLL bypass and Auto Detection */
+ snd_soc_update_bits(codec, DA7210_PLL, DA7210_MCLK_DET_EN,
+ DA7210_MCLK_DET_EN);
+ snd_soc_update_bits(codec, DA7210_PLL_DIV3, DA7210_PLL_BYP,
+ DA7210_PLL_BYP);
+ }
/* Enable active mode */
snd_soc_update_bits(codec, DA7210_STARTUP1,
DA7210_SC_MST_EN, DA7210_SC_MST_EN);
@@ -810,17 +879,24 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
static int da7210_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
+ struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
u32 dai_cfg1;
u32 dai_cfg3;
dai_cfg1 = 0x7f & snd_soc_read(codec, DA7210_DAI_CFG1);
dai_cfg3 = 0xfc & snd_soc_read(codec, DA7210_DAI_CFG3);
+ if ((snd_soc_read(codec, DA7210_PLL) & DA7210_PLL_EN) &&
+ (!(snd_soc_read(codec, DA7210_PLL_DIV3) & DA7210_PLL_BYP)))
+ return -EINVAL;
+
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
+ da7210->master = 1;
dai_cfg1 |= DA7210_DAI_MODE_MASTER;
break;
case SND_SOC_DAIFMT_CBS_CFS:
+ da7210->master = 0;
dai_cfg1 |= DA7210_DAI_MODE_SLAVE;
break;
default:
@@ -872,10 +948,101 @@ static int da7210_mute(struct snd_soc_dai *dai, int mute)
#define DA7210_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+static int da7210_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
+
+ switch (clk_id) {
+ case DA7210_CLKSRC_MCLK:
+ switch (freq) {
+ case 12000000:
+ case 13000000:
+ case 13500000:
+ case 14400000:
+ case 19200000:
+ case 19680000:
+ case 19800000:
+ da7210->mclk_rate = freq;
+ return 0;
+ default:
+ dev_err(codec_dai->dev, "Unsupported MCLK value %d\n",
+ freq);
+ return -EINVAL;
+ }
+ break;
+ default:
+ dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id);
+ return -EINVAL;
+ }
+}
+
+/**
+ * da7210_set_dai_pll :Configure the codec PLL
+ * @param codec_dai : pointer to codec DAI
+ * @param pll_id : da7210 has only one pll, so pll_id is always zero
+ * @param fref : MCLK frequency, should be < 20MHz
+ * @param fout : FsDM value, Refer page 44 & 45 of datasheet
+ * @return int : Zero for success, negative error code for error
+ *
+ * Note: Supported PLL input frequencies are 12MHz, 13MHz, 13.5MHz, 14.4MHz,
+ * 19.2MHz, 19.6MHz and 19.8MHz
+ */
+static int da7210_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+ int source, unsigned int fref, unsigned int fout)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
+
+ u8 pll_div1, pll_div2, pll_div3, cnt;
+
+ /* In slave mode, there is only one set of divisors */
+ if (!da7210->master)
+ fout = 2822400;
+
+ /* Search pll div array for correct divisors */
+ for (cnt = 0; cnt < ARRAY_SIZE(da7210_pll_div); cnt++) {
+ /* check fref, mode and fout */
+ if ((fref == da7210_pll_div[cnt].fref) &&
+ (da7210->master == da7210_pll_div[cnt].mode) &&
+ (fout == da7210_pll_div[cnt].fout)) {
+ /* all match, pick up divisors */
+ pll_div1 = da7210_pll_div[cnt].div1;
+ pll_div2 = da7210_pll_div[cnt].div2;
+ pll_div3 = da7210_pll_div[cnt].div3;
+ break;
+ }
+ }
+ if (cnt >= ARRAY_SIZE(da7210_pll_div))
+ goto err;
+
+ /* Disable active mode */
+ snd_soc_update_bits(codec, DA7210_STARTUP1, DA7210_SC_MST_EN, 0);
+ /* Write PLL dividers */
+ snd_soc_write(codec, DA7210_PLL_DIV1, pll_div1);
+ snd_soc_write(codec, DA7210_PLL_DIV2, pll_div2);
+ snd_soc_update_bits(codec, DA7210_PLL_DIV3,
+ DA7210_PLL_DIV_L_MASK, pll_div3);
+
+ /* Enable PLL */
+ snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_EN, DA7210_PLL_EN);
+
+ /* Enable active mode */
+ snd_soc_update_bits(codec, DA7210_STARTUP1, DA7210_SC_MST_EN,
+ DA7210_SC_MST_EN);
+ return 0;
+err:
+ dev_err(codec_dai->dev, "Unsupported PLL input frequency %d\n", fref);
+ return -EINVAL;
+}
+
/* DAI operations */
static const struct snd_soc_dai_ops da7210_dai_ops = {
.hw_params = da7210_hw_params,
.set_fmt = da7210_set_dai_fmt,
+ .set_sysclk = da7210_set_dai_sysclk,
+ .set_pll = da7210_set_dai_pll,
.digital_mute = da7210_mute,
};
@@ -915,24 +1082,11 @@ static int da7210_probe(struct snd_soc_codec *codec)
return ret;
}
- /* FIXME
- *
- * This driver use fixed value here
- * And below settings expects MCLK = 12.288MHz
- *
- * When you select different MCLK, please check...
- * DA7210_PLL_DIV1 val
- * DA7210_PLL_DIV2 val
- * DA7210_PLL_DIV3 val
- * DA7210_PLL_DIV3 :: DA7210_MCLK_RANGExxx
- */
+ da7210->mclk_rate = 0; /* This will be set from set_sysclk() */
+ da7210->master = 0; /* This will be set from set_fmt() */
- /*
- * make sure that DA7210 use bypass mode before start up
- */
- snd_soc_write(codec, DA7210_STARTUP1, 0);
- snd_soc_write(codec, DA7210_PLL_DIV3,
- DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP);
+ /* Enable internal regulator & bias current */
+ snd_soc_write(codec, DA7210_CONTROL, DA7210_REG_EN | DA7210_BIAS_EN);
/*
* ADC settings
@@ -1007,34 +1161,13 @@ static int da7210_probe(struct snd_soc_codec *codec)
/* Enable Aux2 */
snd_soc_write(codec, DA7210_AUX2, DA7210_AUX2_EN);
+ /* Set PLL Master clock range 10-20 MHz, enable PLL bypass */
+ snd_soc_write(codec, DA7210_PLL_DIV3, DA7210_MCLK_RANGE_10_20_MHZ |
+ DA7210_PLL_BYP);
+
/* Diable PLL and bypass it */
snd_soc_write(codec, DA7210_PLL, DA7210_PLL_FS_48000);
- /*
- * If 48kHz sound came, it use bypass mode,
- * and when it is 44.1kHz, it use PLL.
- *
- * This time, this driver sets PLL always ON
- * and controls bypass/PLL mode by switching
- * DA7210_PLL_DIV3 :: DA7210_PLL_BYP bit.
- * see da7210_hw_params
- */
- snd_soc_write(codec, DA7210_PLL_DIV1, 0xE5); /* MCLK = 12.288MHz */
- snd_soc_write(codec, DA7210_PLL_DIV2, 0x99);
- snd_soc_write(codec, DA7210_PLL_DIV3, 0x0A |
- DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP);
- snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_EN, DA7210_PLL_EN);
-
- /* As suggested by Dialog */
- /* unlock */
- regmap_write(da7210->regmap, DA7210_A_HID_UNLOCK, 0x8B);
- regmap_write(da7210->regmap, DA7210_A_TEST_UNLOCK, 0xB4);
- regmap_write(da7210->regmap, DA7210_A_PLL1, 0x01);
- regmap_write(da7210->regmap, DA7210_A_CP_MODE, 0x7C);
- /* re-lock */
- regmap_write(da7210->regmap, DA7210_A_HID_UNLOCK, 0x00);
- regmap_write(da7210->regmap, DA7210_A_TEST_UNLOCK, 0x00);
-
/* Activate all enabled subsystem */
snd_soc_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN);
@@ -1055,7 +1188,26 @@ static struct snd_soc_codec_driver soc_codec_dev_da7210 = {
.num_dapm_routes = ARRAY_SIZE(da7210_audio_map),
};
-static struct regmap_config da7210_regmap = {
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+
+static struct reg_default da7210_regmap_i2c_patch[] = {
+
+ /* System controller master disable */
+ { DA7210_STARTUP1, 0x00 },
+ /* Set PLL Master clock range 10-20 MHz */
+ { DA7210_PLL_DIV3, DA7210_MCLK_RANGE_10_20_MHZ },
+
+ /* to unlock */
+ { DA7210_A_HID_UNLOCK, 0x8B},
+ { DA7210_A_TEST_UNLOCK, 0xB4},
+ { DA7210_A_PLL1, 0x01},
+ { DA7210_A_CP_MODE, 0x7C},
+ /* to re-lock */
+ { DA7210_A_HID_UNLOCK, 0x00},
+ { DA7210_A_TEST_UNLOCK, 0x00},
+};
+
+static const struct regmap_config da7210_regmap_config_i2c = {
.reg_bits = 8,
.val_bits = 8,
@@ -1066,7 +1218,6 @@ static struct regmap_config da7210_regmap = {
.cache_type = REGCACHE_RBTREE,
};
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static int __devinit da7210_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -1080,13 +1231,18 @@ static int __devinit da7210_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, da7210);
- da7210->regmap = regmap_init_i2c(i2c, &da7210_regmap);
+ da7210->regmap = regmap_init_i2c(i2c, &da7210_regmap_config_i2c);
if (IS_ERR(da7210->regmap)) {
ret = PTR_ERR(da7210->regmap);
dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret);
return ret;
}
+ ret = regmap_register_patch(da7210->regmap, da7210_regmap_i2c_patch,
+ ARRAY_SIZE(da7210_regmap_i2c_patch));
+ if (ret != 0)
+ dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
+
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_da7210, &da7210_dai, 1);
if (ret < 0) {
@@ -1119,7 +1275,7 @@ MODULE_DEVICE_TABLE(i2c, da7210_i2c_id);
/* I2C codec control layer */
static struct i2c_driver da7210_i2c_driver = {
.driver = {
- .name = "da7210-codec",
+ .name = "da7210",
.owner = THIS_MODULE,
},
.probe = da7210_i2c_probe,
@@ -1128,12 +1284,112 @@ static struct i2c_driver da7210_i2c_driver = {
};
#endif
+#if defined(CONFIG_SPI_MASTER)
+
+static struct reg_default da7210_regmap_spi_patch[] = {
+ /* Dummy read to give two pulses over nCS for SPI */
+ { DA7210_AUX2, 0x00 },
+ { DA7210_AUX2, 0x00 },
+
+ /* System controller master disable */
+ { DA7210_STARTUP1, 0x00 },
+ /* Set PLL Master clock range 10-20 MHz */
+ { DA7210_PLL_DIV3, DA7210_MCLK_RANGE_10_20_MHZ },
+
+ /* to set PAGE1 of SPI register space */
+ { DA7210_PAGE_CONTROL, 0x80 },
+ /* to unlock */
+ { DA7210_A_HID_UNLOCK, 0x8B},
+ { DA7210_A_TEST_UNLOCK, 0xB4},
+ { DA7210_A_PLL1, 0x01},
+ { DA7210_A_CP_MODE, 0x7C},
+ /* to re-lock */
+ { DA7210_A_HID_UNLOCK, 0x00},
+ { DA7210_A_TEST_UNLOCK, 0x00},
+ /* to set back PAGE0 of SPI register space */
+ { DA7210_PAGE_CONTROL, 0x00 },
+};
+
+static const struct regmap_config da7210_regmap_config_spi = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .read_flag_mask = 0x01,
+ .write_flag_mask = 0x00,
+
+ .reg_defaults = da7210_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(da7210_reg_defaults),
+ .volatile_reg = da7210_volatile_register,
+ .readable_reg = da7210_readable_register,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit da7210_spi_probe(struct spi_device *spi)
+{
+ struct da7210_priv *da7210;
+ int ret;
+
+ da7210 = devm_kzalloc(&spi->dev, sizeof(struct da7210_priv),
+ GFP_KERNEL);
+ if (!da7210)
+ return -ENOMEM;
+
+ spi_set_drvdata(spi, da7210);
+ da7210->regmap = devm_regmap_init_spi(spi, &da7210_regmap_config_spi);
+ if (IS_ERR(da7210->regmap)) {
+ ret = PTR_ERR(da7210->regmap);
+ dev_err(&spi->dev, "Failed to register regmap: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_register_patch(da7210->regmap, da7210_regmap_spi_patch,
+ ARRAY_SIZE(da7210_regmap_spi_patch));
+ if (ret != 0)
+ dev_warn(&spi->dev, "Failed to apply regmap patch: %d\n", ret);
+
+ ret = snd_soc_register_codec(&spi->dev,
+ &soc_codec_dev_da7210, &da7210_dai, 1);
+ if (ret < 0)
+ goto err_regmap;
+
+ return ret;
+
+err_regmap:
+ regmap_exit(da7210->regmap);
+
+ return ret;
+}
+
+static int __devexit da7210_spi_remove(struct spi_device *spi)
+{
+ struct da7210_priv *da7210 = spi_get_drvdata(spi);
+ snd_soc_unregister_codec(&spi->dev);
+ regmap_exit(da7210->regmap);
+ return 0;
+}
+
+static struct spi_driver da7210_spi_driver = {
+ .driver = {
+ .name = "da7210",
+ .owner = THIS_MODULE,
+ },
+ .probe = da7210_spi_probe,
+ .remove = __devexit_p(da7210_spi_remove)
+};
+#endif
+
static int __init da7210_modinit(void)
{
int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&da7210_i2c_driver);
#endif
+#if defined(CONFIG_SPI_MASTER)
+ ret = spi_register_driver(&da7210_spi_driver);
+ if (ret) {
+ printk(KERN_ERR "Failed to register da7210 SPI driver: %d\n",
+ ret);
+ }
+#endif
return ret;
}
module_init(da7210_modinit);
@@ -1143,6 +1399,9 @@ static void __exit da7210_exit(void)
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&da7210_i2c_driver);
#endif
+#if defined(CONFIG_SPI_MASTER)
+ spi_unregister_driver(&da7210_spi_driver);
+#endif
}
module_exit(da7210_exit);
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c
index 4624e752a188..85d9cabe6d55 100644
--- a/sound/soc/codecs/jz4740.c
+++ b/sound/soc/codecs/jz4740.c
@@ -164,8 +164,7 @@ static int jz4740_codec_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
uint32_t val;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec =rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
switch (params_rate(params)) {
case 8000:
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
new file mode 100644
index 000000000000..802b9f176b16
--- /dev/null
+++ b/sound/soc/codecs/lm49453.c
@@ -0,0 +1,1550 @@
+/*
+ * lm49453.c - LM49453 ALSA Soc Audio driver
+ *
+ * Copyright (c) 2012 Texas Instruments, 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; version 2 of the License.
+ *
+ * Initially based on sound/soc/codecs/wm8350.c
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <asm/div64.h>
+#include "lm49453.h"
+
+static struct reg_default lm49453_reg_defs[] = {
+ { 0, 0x00 },
+ { 1, 0x00 },
+ { 2, 0x00 },
+ { 3, 0x00 },
+ { 4, 0x00 },
+ { 5, 0x00 },
+ { 6, 0x00 },
+ { 7, 0x00 },
+ { 8, 0x00 },
+ { 9, 0x00 },
+ { 10, 0x00 },
+ { 11, 0x00 },
+ { 12, 0x00 },
+ { 13, 0x00 },
+ { 14, 0x00 },
+ { 15, 0x00 },
+ { 16, 0x00 },
+ { 17, 0x00 },
+ { 18, 0x00 },
+ { 19, 0x00 },
+ { 20, 0x00 },
+ { 21, 0x00 },
+ { 22, 0x00 },
+ { 23, 0x00 },
+ { 32, 0x00 },
+ { 33, 0x00 },
+ { 35, 0x00 },
+ { 36, 0x00 },
+ { 37, 0x00 },
+ { 46, 0x00 },
+ { 48, 0x00 },
+ { 49, 0x00 },
+ { 51, 0x00 },
+ { 56, 0x00 },
+ { 58, 0x00 },
+ { 59, 0x00 },
+ { 60, 0x00 },
+ { 61, 0x00 },
+ { 62, 0x00 },
+ { 63, 0x00 },
+ { 64, 0x00 },
+ { 65, 0x00 },
+ { 66, 0x00 },
+ { 67, 0x00 },
+ { 68, 0x00 },
+ { 69, 0x00 },
+ { 70, 0x00 },
+ { 71, 0x00 },
+ { 72, 0x00 },
+ { 73, 0x00 },
+ { 74, 0x00 },
+ { 75, 0x00 },
+ { 76, 0x00 },
+ { 77, 0x00 },
+ { 78, 0x00 },
+ { 79, 0x00 },
+ { 80, 0x00 },
+ { 81, 0x00 },
+ { 82, 0x00 },
+ { 83, 0x00 },
+ { 85, 0x00 },
+ { 85, 0x00 },
+ { 86, 0x00 },
+ { 87, 0x00 },
+ { 88, 0x00 },
+ { 89, 0x00 },
+ { 90, 0x00 },
+ { 91, 0x00 },
+ { 92, 0x00 },
+ { 93, 0x00 },
+ { 94, 0x00 },
+ { 95, 0x00 },
+ { 96, 0x01 },
+ { 97, 0x00 },
+ { 98, 0x00 },
+ { 99, 0x00 },
+ { 100, 0x00 },
+ { 101, 0x00 },
+ { 102, 0x00 },
+ { 103, 0x01 },
+ { 105, 0x01 },
+ { 106, 0x00 },
+ { 107, 0x01 },
+ { 107, 0x00 },
+ { 108, 0x00 },
+ { 109, 0x00 },
+ { 110, 0x00 },
+ { 111, 0x02 },
+ { 112, 0x02 },
+ { 113, 0x00 },
+ { 121, 0x80 },
+ { 122, 0xBB },
+ { 123, 0x80 },
+ { 124, 0xBB },
+ { 128, 0x00 },
+ { 130, 0x00 },
+ { 131, 0x00 },
+ { 132, 0x00 },
+ { 133, 0x0A },
+ { 134, 0x0A },
+ { 135, 0x0A },
+ { 136, 0x0F },
+ { 137, 0x00 },
+ { 138, 0x73 },
+ { 139, 0x33 },
+ { 140, 0x73 },
+ { 141, 0x33 },
+ { 142, 0x73 },
+ { 143, 0x33 },
+ { 144, 0x73 },
+ { 145, 0x33 },
+ { 146, 0x73 },
+ { 147, 0x33 },
+ { 148, 0x73 },
+ { 149, 0x33 },
+ { 150, 0x73 },
+ { 151, 0x33 },
+ { 152, 0x00 },
+ { 153, 0x00 },
+ { 154, 0x00 },
+ { 155, 0x00 },
+ { 176, 0x00 },
+ { 177, 0x00 },
+ { 178, 0x00 },
+ { 179, 0x00 },
+ { 180, 0x00 },
+ { 181, 0x00 },
+ { 182, 0x00 },
+ { 183, 0x00 },
+ { 184, 0x00 },
+ { 185, 0x00 },
+ { 186, 0x00 },
+ { 189, 0x00 },
+ { 188, 0x00 },
+ { 194, 0x00 },
+ { 195, 0x00 },
+ { 196, 0x00 },
+ { 197, 0x00 },
+ { 200, 0x00 },
+ { 201, 0x00 },
+ { 202, 0x00 },
+ { 203, 0x00 },
+ { 204, 0x00 },
+ { 205, 0x00 },
+ { 208, 0x00 },
+ { 209, 0x00 },
+ { 210, 0x00 },
+ { 211, 0x00 },
+ { 213, 0x00 },
+ { 214, 0x00 },
+ { 215, 0x00 },
+ { 216, 0x00 },
+ { 217, 0x00 },
+ { 218, 0x00 },
+ { 219, 0x00 },
+ { 221, 0x00 },
+ { 222, 0x00 },
+ { 224, 0x00 },
+ { 225, 0x00 },
+ { 226, 0x00 },
+ { 227, 0x00 },
+ { 228, 0x00 },
+ { 229, 0x00 },
+ { 230, 0x13 },
+ { 231, 0x00 },
+ { 232, 0x80 },
+ { 233, 0x0C },
+ { 234, 0xDD },
+ { 235, 0x00 },
+ { 236, 0x04 },
+ { 237, 0x00 },
+ { 238, 0x00 },
+ { 239, 0x00 },
+ { 240, 0x00 },
+ { 241, 0x00 },
+ { 242, 0x00 },
+ { 243, 0x00 },
+ { 244, 0x00 },
+ { 245, 0x00 },
+ { 248, 0x00 },
+ { 249, 0x00 },
+ { 254, 0x00 },
+ { 255, 0x00 },
+};
+
+/* codec private data */
+struct lm49453_priv {
+ struct regmap *regmap;
+ int fs_rate;
+};
+
+/* capture path controls */
+
+static const char *lm49453_mic2mode_text[] = {"Single Ended", "Differential"};
+
+static const SOC_ENUM_SINGLE_DECL(lm49453_mic2mode_enum, LM49453_P0_MICR_REG, 5,
+ lm49453_mic2mode_text);
+
+static const char *lm49453_dmic_cfg_text[] = {"DMICDAT1", "DMICDAT2"};
+
+static const SOC_ENUM_SINGLE_DECL(lm49453_dmic12_cfg_enum,
+ LM49453_P0_DIGITAL_MIC1_CONFIG_REG,
+ 7, lm49453_dmic_cfg_text);
+
+static const SOC_ENUM_SINGLE_DECL(lm49453_dmic34_cfg_enum,
+ LM49453_P0_DIGITAL_MIC2_CONFIG_REG,
+ 7, lm49453_dmic_cfg_text);
+
+/* MUX Controls */
+static const char *lm49453_adcl_mux_text[] = { "MIC1", "Aux_L" };
+
+static const char *lm49453_adcr_mux_text[] = { "MIC2", "Aux_R" };
+
+static const struct soc_enum lm49453_adcl_enum =
+ SOC_ENUM_SINGLE(LM49453_P0_ANALOG_MIXER_ADC_REG, 0,
+ ARRAY_SIZE(lm49453_adcl_mux_text),
+ lm49453_adcl_mux_text);
+
+static const struct soc_enum lm49453_adcr_enum =
+ SOC_ENUM_SINGLE(LM49453_P0_ANALOG_MIXER_ADC_REG, 1,
+ ARRAY_SIZE(lm49453_adcr_mux_text),
+ lm49453_adcr_mux_text);
+
+static const struct snd_kcontrol_new lm49453_adcl_mux_control =
+ SOC_DAPM_ENUM("ADC Left Mux", lm49453_adcl_enum);
+
+static const struct snd_kcontrol_new lm49453_adcr_mux_control =
+ SOC_DAPM_ENUM("ADC Right Mux", lm49453_adcr_enum);
+
+static const struct snd_kcontrol_new lm49453_headset_left_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACHPL1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACHPL1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACHPL1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACHPL1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACHPL1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACHPL1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACHPL1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACHPL1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACHPL2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACHPL2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACHPL2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACHPL2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACHPL2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACHPL2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACHPL2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACHPL2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 0, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_headset_right_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACHPR1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACHPR1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACHPR1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACHPR1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACHPR1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACHPR1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACHPR1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACHPR1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACHPR2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACHPR2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACHPR2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACHPR2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACHPR2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACHPR2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACHPR2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACHPR2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 1, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_speaker_left_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACLSL1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACLSL1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACLSL1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACLSL1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACLSL1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACLSL1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACLSL1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACLSL1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACLSL2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACLSL2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACLSL2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACLSL2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACLSL2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACLSL2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACLSL2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACLSL2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 2, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_speaker_right_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACLSR1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACLSR1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACLSR1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACLSR1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACLSR1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACLSR1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACLSR1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACLSR1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACLSR2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACLSR2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACLSR2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACLSR2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACLSR2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACLSR2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACLSR2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACLSR2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 3, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_haptic_left_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACHAL1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACHAL1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACHAL1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACHAL1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACHAL1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACHAL1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACHAL1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACHAL1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACHAL2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACHAL2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACHAL2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACHAL2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACHAL2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACHAL2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACHAL2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACHAL2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 4, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_haptic_right_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACHAR1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACHAR1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACHAR1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACHAR1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACHAR1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACHAR1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACHAR1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACHAR1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACHAR2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACHAR2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACHAR2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACHAR2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACHAR2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACHAR2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACHAR2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACHAR2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 5, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_lineout_left_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACLOL1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACLOL1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACLOL1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACLOL1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACLOL1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACLOL1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACLOL1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACLOL1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACLOL2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACLOL2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACLOL2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACLOL2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACLOL2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACLOL2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACLOL2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACLOL2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 6, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_lineout_right_mixer[] = {
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_DACLOR1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_DACLOR1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_DACLOR1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_DACLOR1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_DACLOR1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_DACLOR1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_DACLOR1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_DACLOR1_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_DACLOR2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_DACLOR2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_DACLOR2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_DACLOR2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_DACLOR2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_DACLOR2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_DACLOR2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_DACLOR2_REG, 7, 1, 0),
+SOC_DAPM_SINGLE("Sidetone Switch", LM49453_P0_STN_SEL_REG, 7, 0, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx1_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_PORT1_TX1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_PORT1_TX1_REG, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx2_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_PORT1_TX2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_PORT1_TX2_REG, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx3_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX3_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX3_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX3_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX3_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX3_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX3_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_3 Switch", LM49453_P0_PORT1_TX3_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx4_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX4_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX4_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX4_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX4_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX4_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX4_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_4 Switch", LM49453_P0_PORT1_TX4_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx5_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX5_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX5_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX5_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX5_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX5_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX5_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_5 Switch", LM49453_P0_PORT1_TX5_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx6_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX6_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX6_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX6_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX6_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX6_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX6_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_6 Switch", LM49453_P0_PORT1_TX6_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx7_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX7_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX7_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX7_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX7_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX7_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX7_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_7 Switch", LM49453_P0_PORT1_TX7_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port1_tx8_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT1_TX8_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT1_TX8_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT1_TX8_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT1_TX8_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT1_TX8_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT1_TX8_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_8 Switch", LM49453_P0_PORT1_TX8_REG, 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port2_tx1_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT2_TX1_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT2_TX1_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT2_TX1_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT2_TX1_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT2_TX1_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT2_TX1_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_1 Switch", LM49453_P0_PORT2_TX1_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_1 Switch", LM49453_P0_PORT2_TX1_REG, 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new lm49453_port2_tx2_mixer[] = {
+SOC_DAPM_SINGLE("DMIC1L Switch", LM49453_P0_PORT2_TX2_REG, 0, 1, 0),
+SOC_DAPM_SINGLE("DMIC1R Switch", LM49453_P0_PORT2_TX2_REG, 1, 1, 0),
+SOC_DAPM_SINGLE("DMIC2L Switch", LM49453_P0_PORT2_TX2_REG, 2, 1, 0),
+SOC_DAPM_SINGLE("DMIC2R Switch", LM49453_P0_PORT2_TX2_REG, 3, 1, 0),
+SOC_DAPM_SINGLE("ADCL Switch", LM49453_P0_PORT2_TX2_REG, 4, 1, 0),
+SOC_DAPM_SINGLE("ADCR Switch", LM49453_P0_PORT2_TX2_REG, 5, 1, 0),
+SOC_DAPM_SINGLE("Port1_2 Switch", LM49453_P0_PORT2_TX2_REG, 6, 1, 0),
+SOC_DAPM_SINGLE("Port2_2 Switch", LM49453_P0_PORT2_TX2_REG, 7, 1, 0),
+};
+
+/* TLV Declarations */
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7650, 150, 1);
+static const DECLARE_TLV_DB_SCALE(port_tlv, 0, 600, 0);
+
+static const struct snd_kcontrol_new lm49453_sidetone_mixer_controls[] = {
+/* Sidetone supports mono only */
+SOC_DAPM_SINGLE_TLV("Sidetone ADCL Volume", LM49453_P0_STN_VOL_ADCL_REG,
+ 0, 0x3F, 0, digital_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone ADCR Volume", LM49453_P0_STN_VOL_ADCR_REG,
+ 0, 0x3F, 0, digital_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone DMIC1L Volume", LM49453_P0_STN_VOL_DMIC1L_REG,
+ 0, 0x3F, 0, digital_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone DMIC1R Volume", LM49453_P0_STN_VOL_DMIC1R_REG,
+ 0, 0x3F, 0, digital_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone DMIC2L Volume", LM49453_P0_STN_VOL_DMIC2L_REG,
+ 0, 0x3F, 0, digital_tlv),
+SOC_DAPM_SINGLE_TLV("Sidetone DMIC2R Volume", LM49453_P0_STN_VOL_DMIC2R_REG,
+ 0, 0x3F, 0, digital_tlv),
+};
+
+static const struct snd_kcontrol_new lm49453_snd_controls[] = {
+ /* mic1 and mic2 supports mono only */
+ SOC_SINGLE_TLV("Mic1 Volume", LM49453_P0_ADC_LEVELL_REG, 0, 6,
+ 0, digital_tlv),
+ SOC_SINGLE_TLV("Mic2 Volume", LM49453_P0_ADC_LEVELR_REG, 0, 6,
+ 0, digital_tlv),
+
+ SOC_DOUBLE_R_TLV("DMIC1 Volume", LM49453_P0_DMIC1_LEVELL_REG,
+ LM49453_P0_DMIC1_LEVELR_REG, 0, 6, 0, digital_tlv),
+ SOC_DOUBLE_R_TLV("DMIC2 Volume", LM49453_P0_DMIC2_LEVELL_REG,
+ LM49453_P0_DMIC2_LEVELR_REG, 0, 6, 0, digital_tlv),
+
+ SOC_DAPM_ENUM("Mic2Mode", lm49453_mic2mode_enum),
+ SOC_DAPM_ENUM("DMIC12 SRC", lm49453_dmic12_cfg_enum),
+ SOC_DAPM_ENUM("DMIC34 SRC", lm49453_dmic34_cfg_enum),
+
+ /* Capture path filter enable */
+ SOC_SINGLE("DMIC1 HPFilter Switch", LM49453_P0_ADC_FX_ENABLES_REG,
+ 0, 1, 0),
+ SOC_SINGLE("DMIC2 HPFilter Switch", LM49453_P0_ADC_FX_ENABLES_REG,
+ 1, 1, 0),
+ SOC_SINGLE("ADC HPFilter Switch", LM49453_P0_ADC_FX_ENABLES_REG,
+ 2, 1, 0),
+
+ SOC_DOUBLE_R_TLV("DAC HP Volume", LM49453_P0_DAC_HP_LEVELL_REG,
+ LM49453_P0_DAC_HP_LEVELR_REG, 0, 6, 0, digital_tlv),
+ SOC_DOUBLE_R_TLV("DAC LO Volume", LM49453_P0_DAC_LO_LEVELL_REG,
+ LM49453_P0_DAC_LO_LEVELR_REG, 0, 6, 0, digital_tlv),
+ SOC_DOUBLE_R_TLV("DAC LS Volume", LM49453_P0_DAC_LS_LEVELL_REG,
+ LM49453_P0_DAC_LS_LEVELR_REG, 0, 6, 0, digital_tlv),
+ SOC_DOUBLE_R_TLV("DAC HA Volume", LM49453_P0_DAC_HA_LEVELL_REG,
+ LM49453_P0_DAC_HA_LEVELR_REG, 0, 6, 0, digital_tlv),
+
+ SOC_SINGLE_TLV("EP Volume", LM49453_P0_DAC_LS_LEVELL_REG,
+ 0, 6, 0, digital_tlv),
+
+ SOC_SINGLE_TLV("PORT1_1_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG,
+ 0, 3, 0, port_tlv),
+ SOC_SINGLE_TLV("PORT1_2_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG,
+ 2, 3, 0, port_tlv),
+ SOC_SINGLE_TLV("PORT1_3_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG,
+ 4, 3, 0, port_tlv),
+ SOC_SINGLE_TLV("PORT1_4_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL1_REG,
+ 6, 3, 0, port_tlv),
+ SOC_SINGLE_TLV("PORT1_5_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL2_REG,
+ 0, 3, 0, port_tlv),
+ SOC_SINGLE_TLV("PORT1_6_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL2_REG,
+ 2, 3, 0, port_tlv),
+ SOC_SINGLE_TLV("PORT1_7_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL2_REG,
+ 4, 3, 0, port_tlv),
+ SOC_SINGLE_TLV("PORT1_8_RX_LVL Volume", LM49453_P0_PORT1_RX_LVL2_REG,
+ 6, 3, 0, port_tlv),
+
+ SOC_SINGLE_TLV("PORT2_1_RX_LVL Volume", LM49453_P0_PORT2_RX_LVL_REG,
+ 0, 3, 0, port_tlv),
+ SOC_SINGLE_TLV("PORT2_2_RX_LVL Volume", LM49453_P0_PORT2_RX_LVL_REG,
+ 2, 3, 0, port_tlv),
+
+ SOC_SINGLE("Port1 Playback Switch", LM49453_P0_AUDIO_PORT1_BASIC_REG,
+ 1, 1, 0),
+ SOC_SINGLE("Port2 Playback Switch", LM49453_P0_AUDIO_PORT2_BASIC_REG,
+ 1, 1, 0),
+ SOC_SINGLE("Port1 Capture Switch", LM49453_P0_AUDIO_PORT1_BASIC_REG,
+ 2, 1, 0),
+ SOC_SINGLE("Port2 Capture Switch", LM49453_P0_AUDIO_PORT2_BASIC_REG,
+ 2, 1, 0)
+
+};
+
+/* DAPM widgets */
+static const struct snd_soc_dapm_widget lm49453_dapm_widgets[] = {
+
+ /* All end points HP,EP, LS, Lineout and Haptic */
+ SND_SOC_DAPM_OUTPUT("HPOUTL"),
+ SND_SOC_DAPM_OUTPUT("HPOUTR"),
+ SND_SOC_DAPM_OUTPUT("EPOUT"),
+ SND_SOC_DAPM_OUTPUT("LSOUTL"),
+ SND_SOC_DAPM_OUTPUT("LSOUTR"),
+ SND_SOC_DAPM_OUTPUT("LOOUTR"),
+ SND_SOC_DAPM_OUTPUT("LOOUTL"),
+ SND_SOC_DAPM_OUTPUT("HAOUTL"),
+ SND_SOC_DAPM_OUTPUT("HAOUTR"),
+
+ SND_SOC_DAPM_INPUT("AMIC1"),
+ SND_SOC_DAPM_INPUT("AMIC2"),
+ SND_SOC_DAPM_INPUT("DMIC1DAT"),
+ SND_SOC_DAPM_INPUT("DMIC2DAT"),
+ SND_SOC_DAPM_INPUT("AUXL"),
+ SND_SOC_DAPM_INPUT("AUXR"),
+
+ SND_SOC_DAPM_PGA("PORT1_1_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("PORT1_2_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("PORT1_3_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("PORT1_4_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("PORT1_5_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("PORT1_6_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("PORT1_7_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("PORT1_8_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("PORT2_1_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("PORT2_2_RX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("AMIC1Bias", LM49453_P0_MICL_REG, 6, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("AMIC2Bias", LM49453_P0_MICR_REG, 6, 0, NULL, 0),
+
+ /* playback path driver enables */
+ SND_SOC_DAPM_OUT_DRV("Headset Switch",
+ LM49453_P0_PMC_SETUP_REG, 0, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("Earpiece Switch",
+ LM49453_P0_EP_REG, 0, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("Speaker Left Switch",
+ LM49453_P0_DIS_PKVL_FB_REG, 0, 1, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("Speaker Right Switch",
+ LM49453_P0_DIS_PKVL_FB_REG, 1, 1, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("Haptic Left Switch",
+ LM49453_P0_DIS_PKVL_FB_REG, 2, 1, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("Haptic Right Switch",
+ LM49453_P0_DIS_PKVL_FB_REG, 3, 1, NULL, 0),
+
+ /* DAC */
+ SND_SOC_DAPM_DAC("HPL DAC", "Headset", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("HPR DAC", "Headset", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("LSL DAC", "Speaker", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("LSR DAC", "Speaker", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("HAL DAC", "Haptic", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("HAR DAC", "Haptic", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("LOL DAC", "Lineout", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_DAC("LOR DAC", "Lineout", SND_SOC_NOPM, 0, 0),
+
+
+ SND_SOC_DAPM_PGA("AUXL Input",
+ LM49453_P0_ANALOG_MIXER_ADC_REG, 2, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("AUXR Input",
+ LM49453_P0_ANALOG_MIXER_ADC_REG, 3, 0, NULL, 0),
+
+ SND_SOC_DAPM_PGA("Sidetone", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* ADC */
+ SND_SOC_DAPM_ADC("DMIC1 Left", "Capture", SND_SOC_NOPM, 1, 0),
+ SND_SOC_DAPM_ADC("DMIC1 Right", "Capture", SND_SOC_NOPM, 1, 0),
+ SND_SOC_DAPM_ADC("DMIC2 Left", "Capture", SND_SOC_NOPM, 1, 0),
+ SND_SOC_DAPM_ADC("DMIC2 Right", "Capture", SND_SOC_NOPM, 1, 0),
+
+ SND_SOC_DAPM_ADC("ADC Left", "Capture", SND_SOC_NOPM, 1, 0),
+ SND_SOC_DAPM_ADC("ADC Right", "Capture", SND_SOC_NOPM, 0, 0),
+
+ SND_SOC_DAPM_MUX("ADCL Mux", SND_SOC_NOPM, 0, 0,
+ &lm49453_adcl_mux_control),
+ SND_SOC_DAPM_MUX("ADCR Mux", SND_SOC_NOPM, 0, 0,
+ &lm49453_adcr_mux_control),
+
+ SND_SOC_DAPM_MUX("Mic1 Input",
+ SND_SOC_NOPM, 0, 0, &lm49453_adcl_mux_control),
+
+ SND_SOC_DAPM_MUX("Mic2 Input",
+ SND_SOC_NOPM, 0, 0, &lm49453_adcr_mux_control),
+
+ /* AIF */
+ SND_SOC_DAPM_AIF_IN("PORT1_SDI", NULL, 0,
+ LM49453_P0_PULL_CONFIG1_REG, 2, 0),
+ SND_SOC_DAPM_AIF_IN("PORT2_SDI", NULL, 0,
+ LM49453_P0_PULL_CONFIG1_REG, 6, 0),
+
+ SND_SOC_DAPM_AIF_OUT("PORT1_SDO", NULL, 0,
+ LM49453_P0_PULL_CONFIG1_REG, 3, 0),
+ SND_SOC_DAPM_AIF_OUT("PORT2_SDO", NULL, 0,
+ LM49453_P0_PULL_CONFIG1_REG, 7, 0),
+
+ /* Port1 TX controls */
+ SND_SOC_DAPM_OUT_DRV("P1_1_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("P1_2_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("P1_3_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("P1_4_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("P1_5_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("P1_6_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("P1_7_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("P1_8_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* Port2 TX controls */
+ SND_SOC_DAPM_OUT_DRV("P2_1_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("P2_2_TX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ /* Sidetone Mixer */
+ SND_SOC_DAPM_MIXER("Sidetone Mixer", SND_SOC_NOPM, 0, 0,
+ lm49453_sidetone_mixer_controls,
+ ARRAY_SIZE(lm49453_sidetone_mixer_controls)),
+
+ /* DAC MIXERS */
+ SND_SOC_DAPM_MIXER("HPL Mixer", SND_SOC_NOPM, 0, 0,
+ lm49453_headset_left_mixer,
+ ARRAY_SIZE(lm49453_headset_left_mixer)),
+ SND_SOC_DAPM_MIXER("HPR Mixer", SND_SOC_NOPM, 0, 0,
+ lm49453_headset_right_mixer,
+ ARRAY_SIZE(lm49453_headset_right_mixer)),
+ SND_SOC_DAPM_MIXER("LOL Mixer", SND_SOC_NOPM, 0, 0,
+ lm49453_lineout_left_mixer,
+ ARRAY_SIZE(lm49453_lineout_left_mixer)),
+ SND_SOC_DAPM_MIXER("LOR Mixer", SND_SOC_NOPM, 0, 0,
+ lm49453_lineout_right_mixer,
+ ARRAY_SIZE(lm49453_lineout_right_mixer)),
+ SND_SOC_DAPM_MIXER("LSL Mixer", SND_SOC_NOPM, 0, 0,
+ lm49453_speaker_left_mixer,
+ ARRAY_SIZE(lm49453_speaker_left_mixer)),
+ SND_SOC_DAPM_MIXER("LSR Mixer", SND_SOC_NOPM, 0, 0,
+ lm49453_speaker_right_mixer,
+ ARRAY_SIZE(lm49453_speaker_right_mixer)),
+ SND_SOC_DAPM_MIXER("HAL Mixer", SND_SOC_NOPM, 0, 0,
+ lm49453_haptic_left_mixer,
+ ARRAY_SIZE(lm49453_haptic_left_mixer)),
+ SND_SOC_DAPM_MIXER("HAR Mixer", SND_SOC_NOPM, 0, 0,
+ lm49453_haptic_right_mixer,
+ ARRAY_SIZE(lm49453_haptic_right_mixer)),
+
+ /* Capture Mixer */
+ SND_SOC_DAPM_MIXER("Port1_1 Mixer", SND_SOC_NOPM, 0, 0,
+ lm49453_port1_tx1_mixer,
+ ARRAY_SIZE(lm49453_port1_tx1_mixer)),
+ SND_SOC_DAPM_MIXER("Port1_2 Mixer", SND_SOC_NOPM, 0, 0,
+ lm49453_port1_tx2_mixer,
+ ARRAY_SIZE(lm49453_port1_tx2_mixer)),
+ SND_SOC_DAPM_MIXER("Port1_3 Mixer", SND_SOC_NOPM, 0, 0,
+ lm49453_port1_tx3_mixer,
+ ARRAY_SIZE(lm49453_port1_tx3_mixer)),
+ SND_SOC_DAPM_MIXER("Port1_4 Mixer", SND_SOC_NOPM, 0, 0,
+ lm49453_port1_tx4_mixer,
+ ARRAY_SIZE(lm49453_port1_tx4_mixer)),
+ SND_SOC_DAPM_MIXER("Port1_5 Mixer", SND_SOC_NOPM, 0, 0,
+ lm49453_port1_tx5_mixer,
+ ARRAY_SIZE(lm49453_port1_tx5_mixer)),
+ SND_SOC_DAPM_MIXER("Port1_6 Mixer", SND_SOC_NOPM, 0, 0,
+ lm49453_port1_tx6_mixer,
+ ARRAY_SIZE(lm49453_port1_tx6_mixer)),
+ SND_SOC_DAPM_MIXER("Port1_7 Mixer", SND_SOC_NOPM, 0, 0,
+ lm49453_port1_tx7_mixer,
+ ARRAY_SIZE(lm49453_port1_tx7_mixer)),
+ SND_SOC_DAPM_MIXER("Port1_8 Mixer", SND_SOC_NOPM, 0, 0,
+ lm49453_port1_tx8_mixer,
+ ARRAY_SIZE(lm49453_port1_tx8_mixer)),
+
+ SND_SOC_DAPM_MIXER("Port2_1 Mixer", SND_SOC_NOPM, 0, 0,
+ lm49453_port2_tx1_mixer,
+ ARRAY_SIZE(lm49453_port2_tx1_mixer)),
+ SND_SOC_DAPM_MIXER("Port2_2 Mixer", SND_SOC_NOPM, 0, 0,
+ lm49453_port2_tx2_mixer,
+ ARRAY_SIZE(lm49453_port2_tx2_mixer)),
+};
+
+static const struct snd_soc_dapm_route lm49453_audio_map[] = {
+ /* Port SDI mapping */
+ { "PORT1_1_RX", "Port1 Playback Switch", "PORT1_SDI" },
+ { "PORT1_2_RX", "Port1 Playback Switch", "PORT1_SDI" },
+ { "PORT1_3_RX", "Port1 Playback Switch", "PORT1_SDI" },
+ { "PORT1_4_RX", "Port1 Playback Switch", "PORT1_SDI" },
+ { "PORT1_5_RX", "Port1 Playback Switch", "PORT1_SDI" },
+ { "PORT1_6_RX", "Port1 Playback Switch", "PORT1_SDI" },
+ { "PORT1_7_RX", "Port1 Playback Switch", "PORT1_SDI" },
+ { "PORT1_8_RX", "Port1 Playback Switch", "PORT1_SDI" },
+
+ { "PORT2_1_RX", "Port2 Playback Switch", "PORT2_SDI" },
+ { "PORT2_2_RX", "Port2 Playback Switch", "PORT2_SDI" },
+
+ /* HP mapping */
+ { "HPL Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+ { "HPL Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+ { "HPL Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+ { "HPL Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+ { "HPL Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+ { "HPL Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+ { "HPL Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+ { "HPL Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+ { "HPL Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+ { "HPL Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+ { "HPL Mixer", "ADCL Switch", "ADC Left" },
+ { "HPL Mixer", "ADCR Switch", "ADC Right" },
+ { "HPL Mixer", "DMIC1L Switch", "DMIC1 Left" },
+ { "HPL Mixer", "DMIC1R Switch", "DMIC1 Right" },
+ { "HPL Mixer", "DMIC2L Switch", "DMIC2 Left" },
+ { "HPL Mixer", "DMIC2R Switch", "DMIC2 Right" },
+ { "HPL Mixer", "Sidetone Switch", "Sidetone" },
+
+ { "HPL DAC", NULL, "HPL Mixer" },
+
+ { "HPR Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+ { "HPR Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+ { "HPR Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+ { "HPR Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+ { "HPR Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+ { "HPR Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+ { "HPR Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+ { "HPR Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+ /* Port 2 */
+ { "HPR Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+ { "HPR Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+ { "HPR Mixer", "ADCL Switch", "ADC Left" },
+ { "HPR Mixer", "ADCR Switch", "ADC Right" },
+ { "HPR Mixer", "DMIC1L Switch", "DMIC1 Left" },
+ { "HPR Mixer", "DMIC1R Switch", "DMIC1 Right" },
+ { "HPR Mixer", "DMIC2L Switch", "DMIC2 Left" },
+ { "HPR Mixer", "DMIC2L Switch", "DMIC2 Right" },
+ { "HPR Mixer", "Sidetone Switch", "Sidetone" },
+
+ { "HPR DAC", NULL, "HPR Mixer" },
+
+ { "HPOUTL", "Headset Switch", "HPL DAC"},
+ { "HPOUTR", "Headset Switch", "HPR DAC"},
+
+ /* EP map */
+ { "EPOUT", "Earpiece Switch", "HPL DAC" },
+
+ /* Speaker map */
+ { "LSL Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+ { "LSL Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+ { "LSL Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+ { "LSL Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+ { "LSL Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+ { "LSL Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+ { "LSL Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+ { "LSL Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+ /* Port 2 */
+ { "LSL Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+ { "LSL Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+ { "LSL Mixer", "ADCL Switch", "ADC Left" },
+ { "LSL Mixer", "ADCR Switch", "ADC Right" },
+ { "LSL Mixer", "DMIC1L Switch", "DMIC1 Left" },
+ { "LSL Mixer", "DMIC1R Switch", "DMIC1 Right" },
+ { "LSL Mixer", "DMIC2L Switch", "DMIC2 Left" },
+ { "LSL Mixer", "DMIC2R Switch", "DMIC2 Right" },
+ { "LSL Mixer", "Sidetone Switch", "Sidetone" },
+
+ { "LSL DAC", NULL, "LSL Mixer" },
+
+ { "LSR Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+ { "LSR Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+ { "LSR Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+ { "LSR Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+ { "LSR Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+ { "LSR Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+ { "LSR Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+ { "LSR Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+ /* Port 2 */
+ { "LSR Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+ { "LSR Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+ { "LSR Mixer", "ADCL Switch", "ADC Left" },
+ { "LSR Mixer", "ADCR Switch", "ADC Right" },
+ { "LSR Mixer", "DMIC1L Switch", "DMIC1 Left" },
+ { "LSR Mixer", "DMIC1R Switch", "DMIC1 Right" },
+ { "LSR Mixer", "DMIC2L Switch", "DMIC2 Left" },
+ { "LSR Mixer", "DMIC2R Switch", "DMIC2 Right" },
+ { "LSR Mixer", "Sidetone Switch", "Sidetone" },
+
+ { "LSR DAC", NULL, "LSR Mixer" },
+
+ { "LSOUTL", "Speaker Left Switch", "LSL DAC"},
+ { "LSOUTR", "Speaker Left Switch", "LSR DAC"},
+
+ /* Haptic map */
+ { "HAL Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+ { "HAL Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+ { "HAL Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+ { "HAL Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+ { "HAL Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+ { "HAL Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+ { "HAL Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+ { "HAL Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+ /* Port 2 */
+ { "HAL Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+ { "HAL Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+ { "HAL Mixer", "ADCL Switch", "ADC Left" },
+ { "HAL Mixer", "ADCR Switch", "ADC Right" },
+ { "HAL Mixer", "DMIC1L Switch", "DMIC1 Left" },
+ { "HAL Mixer", "DMIC1R Switch", "DMIC1 Right" },
+ { "HAL Mixer", "DMIC2L Switch", "DMIC2 Left" },
+ { "HAL Mixer", "DMIC2R Switch", "DMIC2 Right" },
+ { "HAL Mixer", "Sidetone Switch", "Sidetone" },
+
+ { "HAL DAC", NULL, "HAL Mixer" },
+
+ { "HAR Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+ { "HAR Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+ { "HAR Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+ { "HAR Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+ { "HAR Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+ { "HAR Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+ { "HAR Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+ { "HAR Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+ /* Port 2 */
+ { "HAR Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+ { "HAR Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+ { "HAR Mixer", "ADCL Switch", "ADC Left" },
+ { "HAR Mixer", "ADCR Switch", "ADC Right" },
+ { "HAR Mixer", "DMIC1L Switch", "DMIC1 Left" },
+ { "HAR Mixer", "DMIC1R Switch", "DMIC1 Right" },
+ { "HAR Mixer", "DMIC2L Switch", "DMIC2 Left" },
+ { "HAR Mixer", "DMIC2R Switch", "DMIC2 Right" },
+ { "HAR Mixer", "Sideton Switch", "Sidetone" },
+
+ { "HAR DAC", NULL, "HAR Mixer" },
+
+ { "HAOUTL", "Haptic Left Switch", "HAL DAC" },
+ { "HAOUTR", "Haptic Right Switch", "HAR DAC" },
+
+ /* Lineout map */
+ { "LOL Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+ { "LOL Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+ { "LOL Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+ { "LOL Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+ { "LOL Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+ { "LOL Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+ { "LOL Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+ { "LOL Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+ /* Port 2 */
+ { "LOL Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+ { "LOL Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+ { "LOL Mixer", "ADCL Switch", "ADC Left" },
+ { "LOL Mixer", "ADCR Switch", "ADC Right" },
+ { "LOL Mixer", "DMIC1L Switch", "DMIC1 Left" },
+ { "LOL Mixer", "DMIC1R Switch", "DMIC1 Right" },
+ { "LOL Mixer", "DMIC2L Switch", "DMIC2 Left" },
+ { "LOL Mixer", "DMIC2R Switch", "DMIC2 Right" },
+ { "LOL Mixer", "Sidetone Switch", "Sidetone" },
+
+ { "LOL DAC", NULL, "LOL Mixer" },
+
+ { "LOR Mixer", "Port1_1 Switch", "PORT1_1_RX" },
+ { "LOR Mixer", "Port1_2 Switch", "PORT1_2_RX" },
+ { "LOR Mixer", "Port1_3 Switch", "PORT1_3_RX" },
+ { "LOR Mixer", "Port1_4 Switch", "PORT1_4_RX" },
+ { "LOR Mixer", "Port1_5 Switch", "PORT1_5_RX" },
+ { "LOR Mixer", "Port1_6 Switch", "PORT1_6_RX" },
+ { "LOR Mixer", "Port1_7 Switch", "PORT1_7_RX" },
+ { "LOR Mixer", "Port1_8 Switch", "PORT1_8_RX" },
+
+ /* Port 2 */
+ { "LOR Mixer", "Port2_1 Switch", "PORT2_1_RX" },
+ { "LOR Mixer", "Port2_2 Switch", "PORT2_2_RX" },
+
+ { "LOR Mixer", "ADCL Switch", "ADC Left" },
+ { "LOR Mixer", "ADCR Switch", "ADC Right" },
+ { "LOR Mixer", "DMIC1L Switch", "DMIC1 Left" },
+ { "LOR Mixer", "DMIC1R Switch", "DMIC1 Right" },
+ { "LOR Mixer", "DMIC2L Switch", "DMIC2 Left" },
+ { "LOR Mixer", "DMIC2R Switch", "DMIC2 Right" },
+ { "LOR Mixer", "Sidetone Switch", "Sidetone" },
+
+ { "LOR DAC", NULL, "LOR Mixer" },
+
+ { "LOOUTL", NULL, "LOL DAC" },
+ { "LOOUTR", NULL, "LOR DAC" },
+
+ /* TX map */
+ /* Port1 mappings */
+ { "Port1_1 Mixer", "ADCL Switch", "ADC Left" },
+ { "Port1_1 Mixer", "ADCR Switch", "ADC Right" },
+ { "Port1_1 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+ { "Port1_1 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+ { "Port1_1 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+ { "Port1_1 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+ { "Port1_2 Mixer", "ADCL Switch", "ADC Left" },
+ { "Port1_2 Mixer", "ADCR Switch", "ADC Right" },
+ { "Port1_2 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+ { "Port1_2 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+ { "Port1_2 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+ { "Port1_2 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+ { "Port1_3 Mixer", "ADCL Switch", "ADC Left" },
+ { "Port1_3 Mixer", "ADCR Switch", "ADC Right" },
+ { "Port1_3 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+ { "Port1_3 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+ { "Port1_3 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+ { "Port1_3 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+ { "Port1_4 Mixer", "ADCL Switch", "ADC Left" },
+ { "Port1_4 Mixer", "ADCR Switch", "ADC Right" },
+ { "Port1_4 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+ { "Port1_4 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+ { "Port1_4 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+ { "Port1_4 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+ { "Port1_5 Mixer", "ADCL Switch", "ADC Left" },
+ { "Port1_5 Mixer", "ADCR Switch", "ADC Right" },
+ { "Port1_5 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+ { "Port1_5 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+ { "Port1_5 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+ { "Port1_5 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+ { "Port1_6 Mixer", "ADCL Switch", "ADC Left" },
+ { "Port1_6 Mixer", "ADCR Switch", "ADC Right" },
+ { "Port1_6 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+ { "Port1_6 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+ { "Port1_6 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+ { "Port1_6 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+ { "Port1_7 Mixer", "ADCL Switch", "ADC Left" },
+ { "Port1_7 Mixer", "ADCR Switch", "ADC Right" },
+ { "Port1_7 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+ { "Port1_7 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+ { "Port1_7 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+ { "Port1_7 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+ { "Port1_8 Mixer", "ADCL Switch", "ADC Left" },
+ { "Port1_8 Mixer", "ADCR Switch", "ADC Right" },
+ { "Port1_8 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+ { "Port1_8 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+ { "Port1_8 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+ { "Port1_8 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+ { "Port2_1 Mixer", "ADCL Switch", "ADC Left" },
+ { "Port2_1 Mixer", "ADCR Switch", "ADC Right" },
+ { "Port2_1 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+ { "Port2_1 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+ { "Port2_1 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+ { "Port2_1 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+ { "Port2_2 Mixer", "ADCL Switch", "ADC Left" },
+ { "Port2_2 Mixer", "ADCR Switch", "ADC Right" },
+ { "Port2_2 Mixer", "DMIC1L Switch", "DMIC1 Left" },
+ { "Port2_2 Mixer", "DMIC1R Switch", "DMIC1 Right" },
+ { "Port2_2 Mixer", "DMIC2L Switch", "DMIC2 Left" },
+ { "Port2_2 Mixer", "DMIC2R Switch", "DMIC2 Right" },
+
+ { "P1_1_TX", NULL, "Port1_1 Mixer" },
+ { "P1_2_TX", NULL, "Port1_2 Mixer" },
+ { "P1_3_TX", NULL, "Port1_3 Mixer" },
+ { "P1_4_TX", NULL, "Port1_4 Mixer" },
+ { "P1_5_TX", NULL, "Port1_5 Mixer" },
+ { "P1_6_TX", NULL, "Port1_6 Mixer" },
+ { "P1_7_TX", NULL, "Port1_7 Mixer" },
+ { "P1_8_TX", NULL, "Port1_8 Mixer" },
+
+ { "P2_1_TX", NULL, "Port2_1 Mixer" },
+ { "P2_2_TX", NULL, "Port2_2 Mixer" },
+
+ { "PORT1_SDO", "Port1 Capture Switch", "P1_1_TX"},
+ { "PORT1_SDO", "Port1 Capture Switch", "P1_2_TX"},
+ { "PORT1_SDO", "Port1 Capture Switch", "P1_3_TX"},
+ { "PORT1_SDO", "Port1 Capture Switch", "P1_4_TX"},
+ { "PORT1_SDO", "Port1 Capture Switch", "P1_5_TX"},
+ { "PORT1_SDO", "Port1 Capture Switch", "P1_6_TX"},
+ { "PORT1_SDO", "Port1 Capture Switch", "P1_7_TX"},
+ { "PORT1_SDO", "Port1 Capture Switch", "P1_8_TX"},
+
+ { "PORT2_SDO", "Port2 Capture Switch", "P2_1_TX"},
+ { "PORT2_SDO", "Port2 Capture Switch", "P2_2_TX"},
+
+ { "Mic1 Input", NULL, "AMIC1" },
+ { "Mic2 Input", NULL, "AMIC2" },
+
+ { "AUXL Input", NULL, "AUXL" },
+ { "AUXR Input", NULL, "AUXR" },
+
+ /* AUX connections */
+ { "ADCL Mux", "Aux_L", "AUXL Input" },
+ { "ADCL Mux", "MIC1", "Mic1 Input" },
+
+ { "ADCR Mux", "Aux_R", "AUXR Input" },
+ { "ADCR Mux", "MIC2", "Mic2 Input" },
+
+ /* ADC connection */
+ { "ADC Left", NULL, "ADCL Mux"},
+ { "ADC Right", NULL, "ADCR Mux"},
+
+ { "DMIC1 Left", NULL, "DMIC1DAT"},
+ { "DMIC1 Right", NULL, "DMIC1DAT"},
+ { "DMIC2 Left", NULL, "DMIC2DAT"},
+ { "DMIC2 Right", NULL, "DMIC2DAT"},
+
+ /* Sidetone map */
+ { "Sidetone Mixer", NULL, "ADC Left" },
+ { "Sidetone Mixer", NULL, "ADC Right" },
+ { "Sidetone Mixer", NULL, "DMIC1 Left" },
+ { "Sidetone Mixer", NULL, "DMIC1 Right" },
+ { "Sidetone Mixer", NULL, "DMIC2 Left" },
+ { "Sidetone Mixer", NULL, "DMIC2 Right" },
+
+ { "Sidetone", "Sidetone Switch", "Sidetone Mixer" },
+};
+
+static int lm49453_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct lm49453_priv *lm49453 = snd_soc_codec_get_drvdata(codec);
+ u16 clk_div = 0;
+
+ lm49453->fs_rate = params_rate(params);
+
+ /* Setting DAC clock dividers based on substream sample rate. */
+ switch (lm49453->fs_rate) {
+ case 8000:
+ case 16000:
+ case 32000:
+ case 24000:
+ case 48000:
+ clk_div = 256;
+ break;
+ case 11025:
+ case 22050:
+ case 44100:
+ clk_div = 216;
+ break;
+ case 96000:
+ clk_div = 127;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_write(codec, LM49453_P0_ADC_CLK_DIV_REG, clk_div);
+ snd_soc_write(codec, LM49453_P0_DAC_HP_CLK_DIV_REG, clk_div);
+
+ return 0;
+}
+
+static int lm49453_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+
+ u16 aif_val;
+ int mode = 0;
+ int clk_phase = 0;
+ int clk_shift = 0;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ aif_val = 0;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ aif_val = LM49453_AUDIO_PORT1_BASIC_SYNC_MS;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ aif_val = LM49453_AUDIO_PORT1_BASIC_CLK_MS;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ aif_val = LM49453_AUDIO_PORT1_BASIC_CLK_MS |
+ LM49453_AUDIO_PORT1_BASIC_SYNC_MS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ mode = 1;
+ clk_phase = (1 << 5);
+ clk_shift = 1;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ mode = 1;
+ clk_phase = (1 << 5);
+ clk_shift = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, LM49453_P0_AUDIO_PORT1_BASIC_REG,
+ LM49453_AUDIO_PORT1_BASIC_FMT_MASK|BIT(1)|BIT(5),
+ (aif_val | mode | clk_phase));
+
+ snd_soc_write(codec, LM49453_P0_AUDIO_PORT1_RX_MSB_REG, clk_shift);
+
+ return 0;
+}
+
+static int lm49453_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ u16 pll_clk = 0;
+
+ switch (freq) {
+ case 12288000:
+ case 26000000:
+ case 19200000:
+ /* pll clk slection */
+ pll_clk = 0;
+ break;
+ case 48000:
+ case 32576:
+ /* fll clk slection */
+ pll_clk = BIT(4);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, LM49453_P0_PMC_SETUP_REG, BIT(4), pll_clk);
+
+ return 0;
+}
+
+static int lm49453_hp_mute(struct snd_soc_dai *dai, int mute)
+{
+ snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(1)|BIT(0),
+ (mute ? (BIT(1)|BIT(0)) : 0));
+ return 0;
+}
+
+static int lm49453_lo_mute(struct snd_soc_dai *dai, int mute)
+{
+ snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(3)|BIT(2),
+ (mute ? (BIT(3)|BIT(2)) : 0));
+ return 0;
+}
+
+static int lm49453_ls_mute(struct snd_soc_dai *dai, int mute)
+{
+ snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(5)|BIT(4),
+ (mute ? (BIT(5)|BIT(4)) : 0));
+ return 0;
+}
+
+static int lm49453_ep_mute(struct snd_soc_dai *dai, int mute)
+{
+ snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(4),
+ (mute ? BIT(4) : 0));
+ return 0;
+}
+
+static int lm49453_ha_mute(struct snd_soc_dai *dai, int mute)
+{
+ snd_soc_update_bits(dai->codec, LM49453_P0_DAC_DSP_REG, BIT(7)|BIT(6),
+ (mute ? (BIT(7)|BIT(6)) : 0));
+ return 0;
+}
+
+static int lm49453_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct lm49453_priv *lm49453 = snd_soc_codec_get_drvdata(codec);
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ case SND_SOC_BIAS_PREPARE:
+ break;
+
+ case SND_SOC_BIAS_STANDBY:
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+ regcache_sync(lm49453->regmap);
+
+ snd_soc_update_bits(codec, LM49453_P0_PMC_SETUP_REG,
+ LM49453_PMC_SETUP_CHIP_EN, LM49453_CHIP_EN);
+ break;
+
+ case SND_SOC_BIAS_OFF:
+ snd_soc_update_bits(codec, LM49453_P0_PMC_SETUP_REG,
+ LM49453_PMC_SETUP_CHIP_EN, 0);
+ break;
+ }
+
+ codec->dapm.bias_level = level;
+
+ return 0;
+}
+
+/* Formates supported by LM49453 driver. */
+#define LM49453_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops lm49453_headset_dai_ops = {
+ .hw_params = lm49453_hw_params,
+ .set_sysclk = lm49453_set_dai_sysclk,
+ .set_fmt = lm49453_set_dai_fmt,
+ .digital_mute = lm49453_hp_mute,
+};
+
+static struct snd_soc_dai_ops lm49453_speaker_dai_ops = {
+ .hw_params = lm49453_hw_params,
+ .set_sysclk = lm49453_set_dai_sysclk,
+ .set_fmt = lm49453_set_dai_fmt,
+ .digital_mute = lm49453_ls_mute,
+};
+
+static struct snd_soc_dai_ops lm49453_haptic_dai_ops = {
+ .hw_params = lm49453_hw_params,
+ .set_sysclk = lm49453_set_dai_sysclk,
+ .set_fmt = lm49453_set_dai_fmt,
+ .digital_mute = lm49453_ha_mute,
+};
+
+static struct snd_soc_dai_ops lm49453_ep_dai_ops = {
+ .hw_params = lm49453_hw_params,
+ .set_sysclk = lm49453_set_dai_sysclk,
+ .set_fmt = lm49453_set_dai_fmt,
+ .digital_mute = lm49453_ep_mute,
+};
+
+static struct snd_soc_dai_ops lm49453_lineout_dai_ops = {
+ .hw_params = lm49453_hw_params,
+ .set_sysclk = lm49453_set_dai_sysclk,
+ .set_fmt = lm49453_set_dai_fmt,
+ .digital_mute = lm49453_lo_mute,
+};
+
+/* LM49453 dai structure. */
+static const struct snd_soc_dai_driver lm49453_dai[] = {
+ {
+ .name = "LM49453 Headset",
+ .playback = {
+ .stream_name = "Headset",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = LM49453_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 5,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = LM49453_FORMATS,
+ },
+ .ops = &lm49453_headset_dai_ops,
+ .symmetric_rates = 1,
+ },
+ {
+ .name = "LM49453 Speaker",
+ .playback = {
+ .stream_name = "Speaker",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = LM49453_FORMATS,
+ },
+ .ops = &lm49453_speaker_dai_ops,
+ },
+ {
+ .name = "LM49453 Haptic",
+ .playback = {
+ .stream_name = "Haptic",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = LM49453_FORMATS,
+ },
+ .ops = &lm49453_haptic_dai_ops,
+ },
+ {
+ .name = "LM49453 Earpiece",
+ .playback = {
+ .stream_name = "Earpiece",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = LM49453_FORMATS,
+ },
+ .ops = &lm49453_ep_dai_ops,
+ },
+ {
+ .name = "LM49453 line out",
+ .playback = {
+ .stream_name = "Lineout",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = LM49453_FORMATS,
+ },
+ .ops = &lm49453_lineout_dai_ops,
+ },
+};
+
+static int lm49453_suspend(struct snd_soc_codec *codec)
+{
+ lm49453_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static int lm49453_resume(struct snd_soc_codec *codec)
+{
+ lm49453_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ return 0;
+}
+
+static int lm49453_probe(struct snd_soc_codec *codec)
+{
+ struct lm49453_priv *lm49453 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+
+ codec->control_data = lm49453->regmap;
+
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/* power down chip */
+static int lm49453_remove(struct snd_soc_codec *codec)
+{
+ lm49453_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_lm49453 = {
+ .probe = lm49453_probe,
+ .remove = lm49453_remove,
+ .suspend = lm49453_suspend,
+ .resume = lm49453_resume,
+ .set_bias_level = lm49453_set_bias_level,
+ .controls = lm49453_snd_controls,
+ .num_controls = ARRAY_SIZE(lm49453_snd_controls),
+ .dapm_widgets = lm49453_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(lm49453_dapm_widgets),
+ .dapm_routes = lm49453_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(lm49453_audio_map),
+ .idle_bias_off = true,
+};
+
+static const struct regmap_config lm49453_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = LM49453_MAX_REGISTER,
+ .reg_defaults = lm49453_reg_defs,
+ .num_reg_defaults = ARRAY_SIZE(lm49453_reg_defs),
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static __devinit int lm49453_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct lm49453_priv *lm49453;
+ int ret = 0;
+
+ lm49453 = devm_kzalloc(&i2c->dev, sizeof(struct lm49453_priv),
+ GFP_KERNEL);
+
+ if (lm49453 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, lm49453);
+
+ lm49453->regmap = regmap_init_i2c(i2c, &lm49453_regmap_config);
+ if (IS_ERR(lm49453->regmap)) {
+ ret = PTR_ERR(lm49453->regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_lm49453,
+ lm49453_dai, ARRAY_SIZE(lm49453_dai));
+ if (ret < 0) {
+ dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
+ regmap_exit(lm49453->regmap);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int __devexit lm49453_i2c_remove(struct i2c_client *client)
+{
+ struct lm49453_priv *lm49453 = i2c_get_clientdata(client);
+
+ snd_soc_unregister_codec(&client->dev);
+ regmap_exit(lm49453->regmap);
+ return 0;
+}
+
+static const struct i2c_device_id lm49453_i2c_id[] = {
+ { "lm49453", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lm49453_i2c_id);
+
+static struct i2c_driver lm49453_i2c_driver = {
+ .driver = {
+ .name = "lm49453",
+ .owner = THIS_MODULE,
+ },
+ .probe = lm49453_i2c_probe,
+ .remove = __devexit_p(lm49453_i2c_remove),
+ .id_table = lm49453_i2c_id,
+};
+
+module_i2c_driver(lm49453_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC LM49453 driver");
+MODULE_AUTHOR("M R Swami Reddy <MR.Swami.Reddy@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/lm49453.h b/sound/soc/codecs/lm49453.h
new file mode 100644
index 000000000000..a63cfa5c0883
--- /dev/null
+++ b/sound/soc/codecs/lm49453.h
@@ -0,0 +1,380 @@
+/*
+ * lm49453.h - LM49453 ALSA Soc Audio drive
+ *
+ * Copyright (c) 2012 Texas Instruments, 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; version 2 of the License.
+ *
+ */
+
+#ifndef _LM49453_H
+#define _LM49453_H
+
+#include <linux/bitops.h>
+
+/* LM49453_P0 register space for page0 */
+#define LM49453_P0_PMC_SETUP_REG 0x00
+#define LM49453_P0_PLL_CLK_SEL1_REG 0x01
+#define LM49453_P0_PLL_CLK_SEL2_REG 0x02
+#define LM49453_P0_PMC_CLK_DIV_REG 0x03
+#define LM49453_P0_HSDET_CLK_DIV_REG 0x04
+#define LM49453_P0_DMIC_CLK_DIV_REG 0x05
+#define LM49453_P0_ADC_CLK_DIV_REG 0x06
+#define LM49453_P0_DAC_OT_CLK_DIV_REG 0x07
+#define LM49453_P0_PLL_HF_M_REG 0x08
+#define LM49453_P0_PLL_LF_M_REG 0x09
+#define LM49453_P0_PLL_NL_REG 0x0A
+#define LM49453_P0_PLL_N_MODL_REG 0x0B
+#define LM49453_P0_PLL_N_MODH_REG 0x0C
+#define LM49453_P0_PLL_P1_REG 0x0D
+#define LM49453_P0_PLL_P2_REG 0x0E
+#define LM49453_P0_FLL_REF_FREQL_REG 0x0F
+#define LM49453_P0_FLL_REF_FREQH_REG 0x10
+#define LM49453_P0_VCO_TARGETLL_REG 0x11
+#define LM49453_P0_VCO_TARGETLH_REG 0x12
+#define LM49453_P0_VCO_TARGETHL_REG 0x13
+#define LM49453_P0_VCO_TARGETHH_REG 0x14
+#define LM49453_P0_PLL_CONFIG_REG 0x15
+#define LM49453_P0_DAC_CLK_SEL_REG 0x16
+#define LM49453_P0_DAC_HP_CLK_DIV_REG 0x17
+
+/* Analog Mixer Input Stages */
+#define LM49453_P0_MICL_REG 0x20
+#define LM49453_P0_MICR_REG 0x21
+#define LM49453_P0_EP_REG 0x24
+#define LM49453_P0_DIS_PKVL_FB_REG 0x25
+
+/* Analog Mixer Output Stages */
+#define LM49453_P0_ANALOG_MIXER_ADC_REG 0x2E
+
+/*ADC or DAC */
+#define LM49453_P0_ADC_DSP_REG 0x30
+#define LM49453_P0_DAC_DSP_REG 0x31
+
+/* EFFECTS ENABLES */
+#define LM49453_P0_ADC_FX_ENABLES_REG 0x33
+
+/* GPIO */
+#define LM49453_P0_GPIO1_REG 0x38
+#define LM49453_P0_GPIO2_REG 0x39
+#define LM49453_P0_GPIO3_REG 0x3A
+#define LM49453_P0_HAP_CTL_REG 0x3B
+#define LM49453_P0_HAP_FREQ_PROG_LEFTL_REG 0x3C
+#define LM49453_P0_HAP_FREQ_PROG_LEFTH_REG 0x3D
+#define LM49453_P0_HAP_FREQ_PROG_RIGHTL_REG 0x3E
+#define LM49453_P0_HAP_FREQ_PROG_RIGHTH_REG 0x3F
+
+/* DIGITAL MIXER */
+#define LM49453_P0_DMIX_CLK_SEL_REG 0x40
+#define LM49453_P0_PORT1_RX_LVL1_REG 0x41
+#define LM49453_P0_PORT1_RX_LVL2_REG 0x42
+#define LM49453_P0_PORT2_RX_LVL_REG 0x43
+#define LM49453_P0_PORT1_TX1_REG 0x44
+#define LM49453_P0_PORT1_TX2_REG 0x45
+#define LM49453_P0_PORT1_TX3_REG 0x46
+#define LM49453_P0_PORT1_TX4_REG 0x47
+#define LM49453_P0_PORT1_TX5_REG 0x48
+#define LM49453_P0_PORT1_TX6_REG 0x49
+#define LM49453_P0_PORT1_TX7_REG 0x4A
+#define LM49453_P0_PORT1_TX8_REG 0x4B
+#define LM49453_P0_PORT2_TX1_REG 0x4C
+#define LM49453_P0_PORT2_TX2_REG 0x4D
+#define LM49453_P0_STN_SEL_REG 0x4F
+#define LM49453_P0_DACHPL1_REG 0x50
+#define LM49453_P0_DACHPL2_REG 0x51
+#define LM49453_P0_DACHPR1_REG 0x52
+#define LM49453_P0_DACHPR2_REG 0x53
+#define LM49453_P0_DACLOL1_REG 0x54
+#define LM49453_P0_DACLOL2_REG 0x55
+#define LM49453_P0_DACLOR1_REG 0x56
+#define LM49453_P0_DACLOR2_REG 0x57
+#define LM49453_P0_DACLSL1_REG 0x58
+#define LM49453_P0_DACLSL2_REG 0x59
+#define LM49453_P0_DACLSR1_REG 0x5A
+#define LM49453_P0_DACLSR2_REG 0x5B
+#define LM49453_P0_DACHAL1_REG 0x5C
+#define LM49453_P0_DACHAL2_REG 0x5D
+#define LM49453_P0_DACHAR1_REG 0x5E
+#define LM49453_P0_DACHAR2_REG 0x5F
+
+/* AUDIO PORT 1 (TDM) */
+#define LM49453_P0_AUDIO_PORT1_BASIC_REG 0x60
+#define LM49453_P0_AUDIO_PORT1_CLK_GEN1_REG 0x61
+#define LM49453_P0_AUDIO_PORT1_CLK_GEN2_REG 0x62
+#define LM49453_P0_AUDIO_PORT1_CLK_GEN3_REG 0x63
+#define LM49453_P0_AUDIO_PORT1_SYNC_RATE_REG 0x64
+#define LM49453_P0_AUDIO_PORT1_SYNC_SDO_SETUP_REG 0x65
+#define LM49453_P0_AUDIO_PORT1_DATA_WIDTH_REG 0x66
+#define LM49453_P0_AUDIO_PORT1_RX_MSB_REG 0x67
+#define LM49453_P0_AUDIO_PORT1_TX_MSB_REG 0x68
+#define LM49453_P0_AUDIO_PORT1_TDM_CHANNELS_REG 0x69
+
+/* AUDIO PORT 2 */
+#define LM49453_P0_AUDIO_PORT2_BASIC_REG 0x6A
+#define LM49453_P0_AUDIO_PORT2_CLK_GEN1_REG 0x6B
+#define LM49453_P0_AUDIO_PORT2_CLK_GEN2_REG 0x6C
+#define LM49453_P0_AUDIO_PORT2_SYNC_GEN_REG 0x6D
+#define LM49453_P0_AUDIO_PORT2_DATA_WIDTH_REG 0x6E
+#define LM49453_P0_AUDIO_PORT2_RX_MODE_REG 0x6F
+#define LM49453_P0_AUDIO_PORT2_TX_MODE_REG 0x70
+
+/* SAMPLE RATE */
+#define LM49453_P0_PORT1_SR_LSB_REG 0x79
+#define LM49453_P0_PORT1_SR_MSB_REG 0x7A
+#define LM49453_P0_PORT2_SR_LSB_REG 0x7B
+#define LM49453_P0_PORT2_SR_MSB_REG 0x7C
+
+/* EFFECTS - HPFs */
+#define LM49453_P0_HPF_REG 0x80
+
+/* EFFECTS ADC ALC */
+#define LM49453_P0_ADC_ALC1_REG 0x82
+#define LM49453_P0_ADC_ALC2_REG 0x83
+#define LM49453_P0_ADC_ALC3_REG 0x84
+#define LM49453_P0_ADC_ALC4_REG 0x85
+#define LM49453_P0_ADC_ALC5_REG 0x86
+#define LM49453_P0_ADC_ALC6_REG 0x87
+#define LM49453_P0_ADC_ALC7_REG 0x88
+#define LM49453_P0_ADC_ALC8_REG 0x89
+#define LM49453_P0_DMIC1_LEVELL_REG 0x8A
+#define LM49453_P0_DMIC1_LEVELR_REG 0x8B
+#define LM49453_P0_DMIC2_LEVELL_REG 0x8C
+#define LM49453_P0_DMIC2_LEVELR_REG 0x8D
+#define LM49453_P0_ADC_LEVELL_REG 0x8E
+#define LM49453_P0_ADC_LEVELR_REG 0x8F
+#define LM49453_P0_DAC_HP_LEVELL_REG 0x90
+#define LM49453_P0_DAC_HP_LEVELR_REG 0x91
+#define LM49453_P0_DAC_LO_LEVELL_REG 0x92
+#define LM49453_P0_DAC_LO_LEVELR_REG 0x93
+#define LM49453_P0_DAC_LS_LEVELL_REG 0x94
+#define LM49453_P0_DAC_LS_LEVELR_REG 0x95
+#define LM49453_P0_DAC_HA_LEVELL_REG 0x96
+#define LM49453_P0_DAC_HA_LEVELR_REG 0x97
+#define LM49453_P0_SOFT_MUTE_REG 0x98
+#define LM49453_P0_DMIC_MUTE_CFG_REG 0x99
+#define LM49453_P0_ADC_MUTE_CFG_REG 0x9A
+#define LM49453_P0_DAC_MUTE_CFG_REG 0x9B
+
+/*DIGITAL MIC1 */
+#define LM49453_P0_DIGITAL_MIC1_CONFIG_REG 0xB0
+#define LM49453_P0_DIGITAL_MIC1_DATA_DELAYL_REG 0xB1
+#define LM49453_P0_DIGITAL_MIC1_DATA_DELAYR_REG 0xB2
+
+/*DIGITAL MIC2 */
+#define LM49453_P0_DIGITAL_MIC2_CONFIG_REG 0xB3
+#define LM49453_P0_DIGITAL_MIC2_DATA_DELAYL_REG 0xB4
+#define LM49453_P0_DIGITAL_MIC2_DATA_DELAYR_REG 0xB5
+
+/* ADC DECIMATOR */
+#define LM49453_P0_ADC_DECIMATOR_REG 0xB6
+
+/* DAC CONFIGURE */
+#define LM49453_P0_DAC_CONFIG_REG 0xB7
+
+/* SIDETONE */
+#define LM49453_P0_STN_VOL_ADCL_REG 0xB8
+#define LM49453_P0_STN_VOL_ADCR_REG 0xB9
+#define LM49453_P0_STN_VOL_DMIC1L_REG 0xBA
+#define LM49453_P0_STN_VOL_DMIC1R_REG 0xBB
+#define LM49453_P0_STN_VOL_DMIC2L_REG 0xBC
+#define LM49453_P0_STN_VOL_DMIC2R_REG 0xBD
+
+/* ADC/DAC CLIPPING MONITORS (Read Only/Write to Clear) */
+#define LM49453_P0_ADC_DEC_CLIP_REG 0xC2
+#define LM49453_P0_ADC_HPF_CLIP_REG 0xC3
+#define LM49453_P0_ADC_LVL_CLIP_REG 0xC4
+#define LM49453_P0_DAC_LVL_CLIP_REG 0xC5
+
+/* ADC ALC EFFECT MONITORS (Read Only) */
+#define LM49453_P0_ADC_LVLMONL_REG 0xC8
+#define LM49453_P0_ADC_LVLMONR_REG 0xC9
+#define LM49453_P0_ADC_ALCMONL_REG 0xCA
+#define LM49453_P0_ADC_ALCMONR_REG 0xCB
+#define LM49453_P0_ADC_MUTED_REG 0xCC
+#define LM49453_P0_DAC_MUTED_REG 0xCD
+
+/* HEADSET DETECT */
+#define LM49453_P0_HSD_PPB_LONG_CNT_LIMITL_REG 0xD0
+#define LM49453_P0_HSD_PPB_LONG_CNT_LIMITR_REG 0xD1
+#define LM49453_P0_HSD_PIN3_4_EX_LOOP_CNT_LIMITL_REG 0xD2
+#define LM49453_P0_HSD_PIN3_4_EX_LOOP_CNT_LIMITH_REG 0xD3
+#define LM49453_P0_HSD_TIMEOUT1_REG 0xD4
+#define LM49453_P0_HSD_TIMEOUT2_REG 0xD5
+#define LM49453_P0_HSD_TIMEOUT3_REG 0xD6
+#define LM49453_P0_HSD_PIN3_4_CFG_REG 0xD7
+#define LM49453_P0_HSD_IRQ1_REG 0xD8
+#define LM49453_P0_HSD_IRQ2_REG 0xD9
+#define LM49453_P0_HSD_IRQ3_REG 0xDA
+#define LM49453_P0_HSD_IRQ4_REG 0xDB
+#define LM49453_P0_HSD_IRQ_MASK1_REG 0xDC
+#define LM49453_P0_HSD_IRQ_MASK2_REG 0xDD
+#define LM49453_P0_HSD_IRQ_MASK3_REG 0xDE
+#define LM49453_P0_HSD_R_HPLL_REG 0xE0
+#define LM49453_P0_HSD_R_HPLH_REG 0xE1
+#define LM49453_P0_HSD_R_HPLU_REG 0xE2
+#define LM49453_P0_HSD_R_HPRL_REG 0xE3
+#define LM49453_P0_HSD_R_HPRH_REG 0xE4
+#define LM49453_P0_HSD_R_HPRU_REG 0xE5
+#define LM49453_P0_HSD_VEL_L_FINALL_REG 0xE6
+#define LM49453_P0_HSD_VEL_L_FINALH_REG 0xE7
+#define LM49453_P0_HSD_VEL_L_FINALU_REG 0xE8
+#define LM49453_P0_HSD_RO_FINALL_REG 0xE9
+#define LM49453_P0_HSD_RO_FINALH_REG 0xEA
+#define LM49453_P0_HSD_RO_FINALU_REG 0xEB
+#define LM49453_P0_HSD_VMIC_BIAS_FINALL_REG 0xEC
+#define LM49453_P0_HSD_VMIC_BIAS_FINALH_REG 0xED
+#define LM49453_P0_HSD_VMIC_BIAS_FINALU_REG 0xEE
+#define LM49453_P0_HSD_PIN_CONFIG_REG 0xEF
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATUS1_REG 0xF1
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATUS2_REG 0xF2
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATUS3_REG 0xF3
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATEL_REG 0xF4
+#define LM49453_P0_HSD_PLUG_DETECT_BB_IRQ_STATEH_REG 0xF5
+
+/* I/O PULLDOWN CONFIG */
+#define LM49453_P0_PULL_CONFIG1_REG 0xF8
+#define LM49453_P0_PULL_CONFIG2_REG 0xF9
+#define LM49453_P0_PULL_CONFIG3_REG 0xFA
+
+/* RESET */
+#define LM49453_P0_RESET_REG 0xFE
+
+/* PAGE */
+#define LM49453_PAGE_REG 0xFF
+
+#define LM49453_MAX_REGISTER (0xFF+1)
+
+/* LM49453_P0_PMC_SETUP_REG (0x00h) */
+#define LM49453_PMC_SETUP_CHIP_EN (BIT(1)|BIT(0))
+#define LM49453_PMC_SETUP_PLL_EN BIT(2)
+#define LM49453_PMC_SETUP_PLL_P2_EN BIT(3)
+#define LM49453_PMC_SETUP_PLL_FLL BIT(4)
+#define LM49453_PMC_SETUP_MCLK_OVER BIT(5)
+#define LM49453_PMC_SETUP_RTC_CLK_OVER BIT(6)
+#define LM49453_PMC_SETUP_CHIP_ACTIVE BIT(7)
+
+/* Chip Enable bits */
+#define LM49453_CHIP_EN_SHUTDOWN 0x00
+#define LM49453_CHIP_EN 0x01
+#define LM49453_CHIP_EN_HSD_DETECT 0x02
+#define LM49453_CHIP_EN_INVALID_HSD 0x03
+
+/* LM49453_P0_PLL_CLK_SEL1_REG (0x01h) */
+#define LM49453_CLK_SEL1_MCLK_SEL 0x11
+#define LM49453_CLK_SEL1_RTC_SEL 0x11
+#define LM49453_CLK_SEL1_PORT1_SEL 0x10
+#define LM49453_CLK_SEL1_PORT2_SEL 0x11
+
+/* LM49453_P0_PLL_CLK_SEL2_REG (0x02h) */
+#define LM49453_CLK_SEL2_ADC_CLK_SEL 0x38
+
+/* LM49453_P0_FLL_REF_FREQL_REG (0x0F) */
+#define LM49453_FLL_REF_FREQ_VAL 0x8ca0001
+
+/* LM49453_P0_VCO_TARGETLL_REG (0x11) */
+#define LM49453_VCO_TARGET_VAL 0x8ca0001
+
+/* LM49453_P0_ADC_DSP_REG (0x30h) */
+#define LM49453_ADC_DSP_ADC_MUTEL BIT(0)
+#define LM49453_ADC_DSP_ADC_MUTER BIT(1)
+#define LM49453_ADC_DSP_DMIC1_MUTEL BIT(2)
+#define LM49453_ADC_DSP_DMIC1_MUTER BIT(3)
+#define LM49453_ADC_DSP_DMIC2_MUTEL BIT(4)
+#define LM49453_ADC_DSP_DMIC2_MUTER BIT(5)
+#define LM49453_ADC_DSP_MUTE_ALL 0x3F
+
+/* LM49453_P0_DAC_DSP_REG (0x31h) */
+#define LM49453_DAC_DSP_MUTE_ALL 0xFF
+
+/* LM49453_P0_AUDIO_PORT1_BASIC_REG (0x60h) */
+#define LM49453_AUDIO_PORT1_BASIC_FMT_MASK (BIT(4)|BIT(3))
+#define LM49453_AUDIO_PORT1_BASIC_CLK_MS BIT(3)
+#define LM49453_AUDIO_PORT1_BASIC_SYNC_MS BIT(4)
+
+/* LM49453_P0_RESET_REG (0xFEh) */
+#define LM49453_RESET_REG_RST BIT(0)
+
+/* Page select register bits (0xFF) */
+#define LM49453_PAGE0_SELECT 0x0
+#define LM49453_PAGE1_SELECT 0x1
+
+/* LM49453_P0_HSD_PIN3_4_CFG_REG (Jack Pin config - 0xD7) */
+#define LM49453_JACK_DISABLE 0x00
+#define LM49453_JACK_CONFIG1 0x01
+#define LM49453_JACK_CONFIG2 0x02
+#define LM49453_JACK_CONFIG3 0x03
+#define LM49453_JACK_CONFIG4 0x04
+#define LM49453_JACK_CONFIG5 0x05
+
+/* Page 1 REGISTERS */
+
+/* SIDETONE */
+#define LM49453_P1_SIDETONE_SA0L_REG 0x80
+#define LM49453_P1_SIDETONE_SA0H_REG 0x81
+#define LM49453_P1_SIDETONE_SAB0U_REG 0x82
+#define LM49453_P1_SIDETONE_SB0L_REG 0x83
+#define LM49453_P1_SIDETONE_SB0H_REG 0x84
+#define LM49453_P1_SIDETONE_SH0L_REG 0x85
+#define LM49453_P1_SIDETONE_SH0H_REG 0x86
+#define LM49453_P1_SIDETONE_SH0U_REG 0x87
+#define LM49453_P1_SIDETONE_SA1L_REG 0x88
+#define LM49453_P1_SIDETONE_SA1H_REG 0x89
+#define LM49453_P1_SIDETONE_SAB1U_REG 0x8A
+#define LM49453_P1_SIDETONE_SB1L_REG 0x8B
+#define LM49453_P1_SIDETONE_SB1H_REG 0x8C
+#define LM49453_P1_SIDETONE_SH1L_REG 0x8D
+#define LM49453_P1_SIDETONE_SH1H_REG 0x8E
+#define LM49453_P1_SIDETONE_SH1U_REG 0x8F
+#define LM49453_P1_SIDETONE_SA2L_REG 0x90
+#define LM49453_P1_SIDETONE_SA2H_REG 0x91
+#define LM49453_P1_SIDETONE_SAB2U_REG 0x92
+#define LM49453_P1_SIDETONE_SB2L_REG 0x93
+#define LM49453_P1_SIDETONE_SB2H_REG 0x94
+#define LM49453_P1_SIDETONE_SH2L_REG 0x95
+#define LM49453_P1_SIDETONE_SH2H_REG 0x96
+#define LM49453_P1_SIDETONE_SH2U_REG 0x97
+#define LM49453_P1_SIDETONE_SA3L_REG 0x98
+#define LM49453_P1_SIDETONE_SA3H_REG 0x99
+#define LM49453_P1_SIDETONE_SAB3U_REG 0x9A
+#define LM49453_P1_SIDETONE_SB3L_REG 0x9B
+#define LM49453_P1_SIDETONE_SB3H_REG 0x9C
+#define LM49453_P1_SIDETONE_SH3L_REG 0x9D
+#define LM49453_P1_SIDETONE_SH3H_REG 0x9E
+#define LM49453_P1_SIDETONE_SH3U_REG 0x9F
+#define LM49453_P1_SIDETONE_SA4L_REG 0xA0
+#define LM49453_P1_SIDETONE_SA4H_REG 0xA1
+#define LM49453_P1_SIDETONE_SAB4U_REG 0xA2
+#define LM49453_P1_SIDETONE_SB4L_REG 0xA3
+#define LM49453_P1_SIDETONE_SB4H_REG 0xA4
+#define LM49453_P1_SIDETONE_SH4L_REG 0xA5
+#define LM49453_P1_SIDETONE_SH4H_REG 0xA6
+#define LM49453_P1_SIDETONE_SH4U_REG 0xA7
+#define LM49453_P1_SIDETONE_SA5L_REG 0xA8
+#define LM49453_P1_SIDETONE_SA5H_REG 0xA9
+#define LM49453_P1_SIDETONE_SAB5U_REG 0xAA
+#define LM49453_P1_SIDETONE_SB5L_REG 0xAB
+#define LM49453_P1_SIDETONE_SB5H_REG 0xAC
+#define LM49453_P1_SIDETONE_SH5L_REG 0xAD
+#define LM49453_P1_SIDETONE_SH5H_REG 0xAE
+#define LM49453_P1_SIDETONE_SH5U_REG 0xAF
+
+/* CHARGE PUMP CONFIG */
+#define LM49453_P1_CP_CONFIG1_REG 0xB0
+#define LM49453_P1_CP_CONFIG2_REG 0xB1
+#define LM49453_P1_CP_CONFIG3_REG 0xB2
+#define LM49453_P1_CP_CONFIG4_REG 0xB3
+#define LM49453_P1_CP_LA_VTH1L_REG 0xB4
+#define LM49453_P1_CP_LA_VTH1M_REG 0xB5
+#define LM49453_P1_CP_LA_VTH2L_REG 0xB6
+#define LM49453_P1_CP_LA_VTH2M_REG 0xB7
+#define LM49453_P1_CP_LA_VTH3L_REG 0xB8
+#define LM49453_P1_CP_LA_VTH3H_REG 0xB9
+#define LM49453_P1_CP_CLK_DIV_REG 0xBA
+
+/* DAC */
+#define LM49453_P1_DAC_CHOP_REG 0xC0
+
+#define LM49453_CLK_SRC_MCLK 1
+#endif
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 0bb511a0388d..35179e2c23c9 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <asm/div64.h>
#include <sound/max98095.h>
+#include <sound/jack.h>
#include "max98095.h"
enum max98095_type {
@@ -51,6 +52,8 @@ struct max98095_priv {
u8 lin_state;
unsigned int mic1pre;
unsigned int mic2pre;
+ struct snd_soc_jack *headphone_jack;
+ struct snd_soc_jack *mic_jack;
};
static const u8 max98095_reg_def[M98095_REG_CNT] = {
@@ -2173,9 +2176,125 @@ static void max98095_handle_pdata(struct snd_soc_codec *codec)
max98095_handle_bq_pdata(codec);
}
+static irqreturn_t max98095_report_jack(int irq, void *data)
+{
+ struct snd_soc_codec *codec = data;
+ struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+ unsigned int value;
+ int hp_report = 0;
+ int mic_report = 0;
+
+ /* Read the Jack Status Register */
+ value = snd_soc_read(codec, M98095_007_JACK_AUTO_STS);
+
+ /* If ddone is not set, then detection isn't finished yet */
+ if ((value & M98095_DDONE) == 0)
+ return IRQ_NONE;
+
+ /* if hp, check its bit, and if set, clear it */
+ if ((value & M98095_HP_IN || value & M98095_LO_IN) &&
+ max98095->headphone_jack)
+ hp_report |= SND_JACK_HEADPHONE;
+
+ /* if mic, check its bit, and if set, clear it */
+ if ((value & M98095_MIC_IN) && max98095->mic_jack)
+ mic_report |= SND_JACK_MICROPHONE;
+
+ if (max98095->headphone_jack == max98095->mic_jack) {
+ snd_soc_jack_report(max98095->headphone_jack,
+ hp_report | mic_report,
+ SND_JACK_HEADSET);
+ } else {
+ if (max98095->headphone_jack)
+ snd_soc_jack_report(max98095->headphone_jack,
+ hp_report, SND_JACK_HEADPHONE);
+ if (max98095->mic_jack)
+ snd_soc_jack_report(max98095->mic_jack,
+ mic_report, SND_JACK_MICROPHONE);
+ }
+
+ return IRQ_HANDLED;
+}
+
+int max98095_jack_detect_enable(struct snd_soc_codec *codec)
+{
+ struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+ int detect_enable = M98095_JDEN;
+ unsigned int slew = M98095_DEFAULT_SLEW_DELAY;
+
+ if (max98095->pdata->jack_detect_pin5en)
+ detect_enable |= M98095_PIN5EN;
+
+ if (max98095->pdata->jack_detect_delay)
+ slew = max98095->pdata->jack_detect_delay;
+
+ ret = snd_soc_write(codec, M98095_08E_JACK_DC_SLEW, slew);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to cfg auto detect %d\n", ret);
+ return ret;
+ }
+
+ /* configure auto detection to be enabled */
+ ret = snd_soc_write(codec, M98095_089_JACK_DET_AUTO, detect_enable);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to cfg auto detect %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+int max98095_jack_detect_disable(struct snd_soc_codec *codec)
+{
+ int ret = 0;
+
+ /* configure auto detection to be disabled */
+ ret = snd_soc_write(codec, M98095_089_JACK_DET_AUTO, 0x0);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to cfg auto detect %d\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+int max98095_jack_detect(struct snd_soc_codec *codec,
+ struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack)
+{
+ struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+ struct i2c_client *client = to_i2c_client(codec->dev);
+ int ret = 0;
+
+ max98095->headphone_jack = hp_jack;
+ max98095->mic_jack = mic_jack;
+
+ /* only progress if we have at least 1 jack pointer */
+ if (!hp_jack && !mic_jack)
+ return -EINVAL;
+
+ max98095_jack_detect_enable(codec);
+
+ /* enable interrupts for headphone jack detection */
+ ret = snd_soc_update_bits(codec, M98095_013_JACK_INT_EN,
+ M98095_IDDONE, M98095_IDDONE);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to cfg jack irqs %d\n", ret);
+ return ret;
+ }
+
+ max98095_report_jack(client->irq, codec);
+ return 0;
+}
+
#ifdef CONFIG_PM
static int max98095_suspend(struct snd_soc_codec *codec)
{
+ struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+
+ if (max98095->headphone_jack || max98095->mic_jack)
+ max98095_jack_detect_disable(codec);
+
max98095_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
@@ -2183,8 +2302,16 @@ static int max98095_suspend(struct snd_soc_codec *codec)
static int max98095_resume(struct snd_soc_codec *codec)
{
+ struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+ struct i2c_client *client = to_i2c_client(codec->dev);
+
max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ if (max98095->headphone_jack || max98095->mic_jack) {
+ max98095_jack_detect_enable(codec);
+ max98095_report_jack(client->irq, codec);
+ }
+
return 0;
}
#else
@@ -2227,6 +2354,7 @@ static int max98095_probe(struct snd_soc_codec *codec)
{
struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
struct max98095_cdata *cdata;
+ struct i2c_client *client;
int ret = 0;
ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
@@ -2238,6 +2366,8 @@ static int max98095_probe(struct snd_soc_codec *codec)
/* reset the codec, the DSP core, and disable all interrupts */
max98095_reset(codec);
+ client = to_i2c_client(codec->dev);
+
/* initialize private data */
max98095->sysclk = (unsigned)-1;
@@ -2266,11 +2396,23 @@ static int max98095_probe(struct snd_soc_codec *codec)
max98095->mic1pre = 0;
max98095->mic2pre = 0;
+ if (client->irq) {
+ /* register an audio interrupt */
+ ret = request_threaded_irq(client->irq, NULL,
+ max98095_report_jack,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ "max98095", codec);
+ if (ret) {
+ dev_err(codec->dev, "Failed to request IRQ: %d\n", ret);
+ goto err_access;
+ }
+ }
+
ret = snd_soc_read(codec, M98095_0FF_REV_ID);
if (ret < 0) {
dev_err(codec->dev, "Failure reading hardware revision: %d\n",
ret);
- goto err_access;
+ goto err_irq;
}
dev_info(codec->dev, "Hardware revision: %c\n", ret - 0x40 + 'A');
@@ -2306,14 +2448,28 @@ static int max98095_probe(struct snd_soc_codec *codec)
max98095_add_widgets(codec);
+ return 0;
+
+err_irq:
+ if (client->irq)
+ free_irq(client->irq, codec);
err_access:
return ret;
}
static int max98095_remove(struct snd_soc_codec *codec)
{
+ struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
+ struct i2c_client *client = to_i2c_client(codec->dev);
+
max98095_set_bias_level(codec, SND_SOC_BIAS_OFF);
+ if (max98095->headphone_jack || max98095->mic_jack)
+ max98095_jack_detect_disable(codec);
+
+ if (client->irq)
+ free_irq(client->irq, codec);
+
return 0;
}
diff --git a/sound/soc/codecs/max98095.h b/sound/soc/codecs/max98095.h
index 891584a0eb03..2ebbe4e894bf 100644
--- a/sound/soc/codecs/max98095.h
+++ b/sound/soc/codecs/max98095.h
@@ -175,11 +175,23 @@
/* MAX98095 Registers Bit Fields */
+/* M98095_007_JACK_AUTO_STS */
+ #define M98095_MIC_IN (1<<3)
+ #define M98095_LO_IN (1<<5)
+ #define M98095_HP_IN (1<<6)
+ #define M98095_DDONE (1<<7)
+
/* M98095_00F_HOST_CFG */
#define M98095_SEG (1<<0)
#define M98095_XTEN (1<<1)
#define M98095_MDLLEN (1<<2)
+/* M98095_013_JACK_INT_EN */
+ #define M98095_IMIC_IN (1<<3)
+ #define M98095_ILO_IN (1<<5)
+ #define M98095_IHP_IN (1<<6)
+ #define M98095_IDDONE (1<<7)
+
/* M98095_027_DAI1_CLKMODE, M98095_031_DAI2_CLKMODE, M98095_03B_DAI3_CLKMODE */
#define M98095_CLKMODE_MASK 0xFF
@@ -255,6 +267,10 @@
#define M98095_EQ2EN (1<<1)
#define M98095_EQ1EN (1<<0)
+/* M98095_089_JACK_DET_AUTO */
+ #define M98095_PIN5EN (1<<2)
+ #define M98095_JDEN (1<<7)
+
/* M98095_090_PWR_EN_IN */
#define M98095_INEN (1<<7)
#define M98095_MB2EN (1<<3)
@@ -296,4 +312,10 @@
#define M98095_174_DAI1_BQ_BASE 0x74
#define M98095_17E_DAI2_BQ_BASE 0x7E
+/* Default Delay used in Slew Rate Calculation for Jack detection */
+#define M98095_DEFAULT_SLEW_DELAY 0x18
+
+extern int max98095_jack_detect(struct snd_soc_codec *codec,
+ struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack);
+
#endif
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c
new file mode 100644
index 000000000000..6276e352125f
--- /dev/null
+++ b/sound/soc/codecs/mc13783.c
@@ -0,0 +1,786 @@
+/*
+ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
+ * Copyright 2009 Sascha Hauer, s.hauer@pengutronix.de
+ * Copyright 2012 Philippe Retornaz, philippe.retornaz@epfl.ch
+ *
+ * Initial development of this code was funded by
+ * Phytec Messtechnik GmbH, http://www.phytec.de
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/mfd/mc13xxx.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/soc-dapm.h>
+
+#include "mc13783.h"
+
+#define MC13783_AUDIO_RX0 36
+#define MC13783_AUDIO_RX1 37
+#define MC13783_AUDIO_TX 38
+#define MC13783_SSI_NETWORK 39
+#define MC13783_AUDIO_CODEC 40
+#define MC13783_AUDIO_DAC 41
+
+#define AUDIO_RX0_ALSPEN (1 << 5)
+#define AUDIO_RX0_ALSPSEL (1 << 7)
+#define AUDIO_RX0_ADDCDC (1 << 21)
+#define AUDIO_RX0_ADDSTDC (1 << 22)
+#define AUDIO_RX0_ADDRXIN (1 << 23)
+
+#define AUDIO_RX1_PGARXEN (1 << 0);
+#define AUDIO_RX1_PGASTEN (1 << 5)
+#define AUDIO_RX1_ARXINEN (1 << 10)
+
+#define AUDIO_TX_AMC1REN (1 << 5)
+#define AUDIO_TX_AMC1LEN (1 << 7)
+#define AUDIO_TX_AMC2EN (1 << 9)
+#define AUDIO_TX_ATXINEN (1 << 11)
+#define AUDIO_TX_RXINREC (1 << 13)
+
+#define SSI_NETWORK_CDCTXRXSLOT(x) (((x) & 0x3) << 2)
+#define SSI_NETWORK_CDCTXSECSLOT(x) (((x) & 0x3) << 4)
+#define SSI_NETWORK_CDCRXSECSLOT(x) (((x) & 0x3) << 6)
+#define SSI_NETWORK_CDCRXSECGAIN(x) (((x) & 0x3) << 8)
+#define SSI_NETWORK_CDCSUMGAIN(x) (1 << 10)
+#define SSI_NETWORK_CDCFSDLY(x) (1 << 11)
+#define SSI_NETWORK_DAC_SLOTS_8 (1 << 12)
+#define SSI_NETWORK_DAC_SLOTS_4 (2 << 12)
+#define SSI_NETWORK_DAC_SLOTS_2 (3 << 12)
+#define SSI_NETWORK_DAC_SLOT_MASK (3 << 12)
+#define SSI_NETWORK_DAC_RXSLOT_0_1 (0 << 14)
+#define SSI_NETWORK_DAC_RXSLOT_2_3 (1 << 14)
+#define SSI_NETWORK_DAC_RXSLOT_4_5 (2 << 14)
+#define SSI_NETWORK_DAC_RXSLOT_6_7 (3 << 14)
+#define SSI_NETWORK_DAC_RXSLOT_MASK (3 << 14)
+#define SSI_NETWORK_STDCRXSECSLOT(x) (((x) & 0x3) << 16)
+#define SSI_NETWORK_STDCRXSECGAIN(x) (((x) & 0x3) << 18)
+#define SSI_NETWORK_STDCSUMGAIN (1 << 20)
+
+/*
+ * MC13783_AUDIO_CODEC and MC13783_AUDIO_DAC mostly share the same
+ * register layout
+ */
+#define AUDIO_SSI_SEL (1 << 0)
+#define AUDIO_CLK_SEL (1 << 1)
+#define AUDIO_CSM (1 << 2)
+#define AUDIO_BCL_INV (1 << 3)
+#define AUDIO_CFS_INV (1 << 4)
+#define AUDIO_CFS(x) (((x) & 0x3) << 5)
+#define AUDIO_CLK(x) (((x) & 0x7) << 7)
+#define AUDIO_C_EN (1 << 11)
+#define AUDIO_C_CLK_EN (1 << 12)
+#define AUDIO_C_RESET (1 << 15)
+
+#define AUDIO_CODEC_CDCFS8K16K (1 << 10)
+#define AUDIO_DAC_CFS_DLY_B (1 << 10)
+
+struct mc13783_priv {
+ struct snd_soc_codec codec;
+ struct mc13xxx *mc13xxx;
+
+ enum mc13783_ssi_port adc_ssi_port;
+ enum mc13783_ssi_port dac_ssi_port;
+};
+
+static unsigned int mc13783_read(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
+ unsigned int value = 0;
+
+ mc13xxx_lock(priv->mc13xxx);
+
+ mc13xxx_reg_read(priv->mc13xxx, reg, &value);
+
+ mc13xxx_unlock(priv->mc13xxx);
+
+ return value;
+}
+
+static int mc13783_write(struct snd_soc_codec *codec,
+ unsigned int reg, unsigned int value)
+{
+ struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
+ int ret;
+
+ mc13xxx_lock(priv->mc13xxx);
+
+ ret = mc13xxx_reg_write(priv->mc13xxx, reg, value);
+
+ mc13xxx_unlock(priv->mc13xxx);
+
+ return ret;
+}
+
+/* Mapping between sample rates and register value */
+static unsigned int mc13783_rates[] = {
+ 8000, 11025, 12000, 16000,
+ 22050, 24000, 32000, 44100,
+ 48000, 64000, 96000
+};
+
+static int mc13783_pcm_hw_params_dac(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ unsigned int rate = params_rate(params);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mc13783_rates); i++) {
+ if (rate == mc13783_rates[i]) {
+ snd_soc_update_bits(codec, MC13783_AUDIO_DAC,
+ 0xf << 17, i << 17);
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int mc13783_pcm_hw_params_codec(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ unsigned int rate = params_rate(params);
+ unsigned int val;
+
+ switch (rate) {
+ case 8000:
+ val = 0;
+ break;
+ case 16000:
+ val = AUDIO_CODEC_CDCFS8K16K;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, MC13783_AUDIO_CODEC, AUDIO_CODEC_CDCFS8K16K,
+ val);
+
+ return 0;
+}
+
+static int mc13783_pcm_hw_params_sync(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ return mc13783_pcm_hw_params_dac(substream, params, dai);
+ else
+ return mc13783_pcm_hw_params_codec(substream, params, dai);
+}
+
+static int mc13783_set_fmt(struct snd_soc_dai *dai, unsigned int fmt,
+ unsigned int reg)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ unsigned int val = 0;
+ unsigned int mask = AUDIO_CFS(3) | AUDIO_BCL_INV | AUDIO_CFS_INV |
+ AUDIO_CSM | AUDIO_C_CLK_EN | AUDIO_C_RESET;
+
+
+ /* DAI mode */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ val |= AUDIO_CFS(2);
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ val |= AUDIO_CFS(1);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* DAI clock inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ val |= AUDIO_BCL_INV;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ val |= AUDIO_BCL_INV | AUDIO_CFS_INV;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ val |= AUDIO_CFS_INV;
+ break;
+ }
+
+ /* DAI clock master masks */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ val |= AUDIO_C_CLK_EN;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ val |= AUDIO_CSM;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ case SND_SOC_DAIFMT_CBS_CFM:
+ return -EINVAL;
+ }
+
+ val |= AUDIO_C_RESET;
+
+ snd_soc_update_bits(codec, reg, mask, val);
+
+ return 0;
+}
+
+static int mc13783_set_fmt_async(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ if (dai->id == MC13783_ID_STEREO_DAC)
+ return mc13783_set_fmt(dai, fmt, MC13783_AUDIO_DAC);
+ else
+ return mc13783_set_fmt(dai, fmt, MC13783_AUDIO_CODEC);
+}
+
+static int mc13783_set_fmt_sync(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ int ret;
+
+ ret = mc13783_set_fmt(dai, fmt, MC13783_AUDIO_DAC);
+ if (ret)
+ return ret;
+
+ /*
+ * In synchronous mode force the voice codec into slave mode
+ * so that the clock / framesync from the stereo DAC is used
+ */
+ fmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
+ fmt |= SND_SOC_DAIFMT_CBS_CFS;
+ ret = mc13783_set_fmt(dai, fmt, MC13783_AUDIO_CODEC);
+
+ return ret;
+}
+
+static int mc13783_sysclk[] = {
+ 13000000,
+ 15360000,
+ 16800000,
+ -1,
+ 26000000,
+ -1, /* 12000000, invalid for voice codec */
+ -1, /* 3686400, invalid for voice codec */
+ 33600000,
+};
+
+static int mc13783_set_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir,
+ unsigned int reg)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ int clk;
+ unsigned int val = 0;
+ unsigned int mask = AUDIO_CLK(0x7) | AUDIO_CLK_SEL;
+
+ for (clk = 0; clk < ARRAY_SIZE(mc13783_sysclk); clk++) {
+ if (mc13783_sysclk[clk] < 0)
+ continue;
+ if (mc13783_sysclk[clk] == freq)
+ break;
+ }
+
+ if (clk == ARRAY_SIZE(mc13783_sysclk))
+ return -EINVAL;
+
+ if (clk_id == MC13783_CLK_CLIB)
+ val |= AUDIO_CLK_SEL;
+
+ val |= AUDIO_CLK(clk);
+
+ snd_soc_update_bits(codec, reg, mask, val);
+
+ return 0;
+}
+
+static int mc13783_set_sysclk_dac(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ return mc13783_set_sysclk(dai, clk_id, freq, dir, MC13783_AUDIO_DAC);
+}
+
+static int mc13783_set_sysclk_codec(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ return mc13783_set_sysclk(dai, clk_id, freq, dir, MC13783_AUDIO_CODEC);
+}
+
+static int mc13783_set_sysclk_sync(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ int ret;
+
+ ret = mc13783_set_sysclk(dai, clk_id, freq, dir, MC13783_AUDIO_DAC);
+ if (ret)
+ return ret;
+
+ return mc13783_set_sysclk(dai, clk_id, freq, dir, MC13783_AUDIO_CODEC);
+}
+
+static int mc13783_set_tdm_slot_dac(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask, int slots,
+ int slot_width)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ unsigned int val = 0;
+ unsigned int mask = SSI_NETWORK_DAC_SLOT_MASK |
+ SSI_NETWORK_DAC_RXSLOT_MASK;
+
+ switch (slots) {
+ case 2:
+ val |= SSI_NETWORK_DAC_SLOTS_2;
+ break;
+ case 4:
+ val |= SSI_NETWORK_DAC_SLOTS_4;
+ break;
+ case 8:
+ val |= SSI_NETWORK_DAC_SLOTS_8;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (rx_mask) {
+ case 0xfffffffc:
+ val |= SSI_NETWORK_DAC_RXSLOT_0_1;
+ break;
+ case 0xfffffff3:
+ val |= SSI_NETWORK_DAC_RXSLOT_2_3;
+ break;
+ case 0xffffffcf:
+ val |= SSI_NETWORK_DAC_RXSLOT_4_5;
+ break;
+ case 0xffffff3f:
+ val |= SSI_NETWORK_DAC_RXSLOT_6_7;
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ snd_soc_update_bits(codec, MC13783_SSI_NETWORK, mask, val);
+
+ return 0;
+}
+
+static int mc13783_set_tdm_slot_codec(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask, int slots,
+ int slot_width)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ unsigned int val = 0;
+ unsigned int mask = 0x3f;
+
+ if (slots != 4)
+ return -EINVAL;
+
+ if (tx_mask != 0xfffffffc)
+ return -EINVAL;
+
+ val |= (0x00 << 2); /* primary timeslot RX/TX(?) is 0 */
+ val |= (0x01 << 4); /* secondary timeslot TX is 1 */
+
+ snd_soc_update_bits(codec, MC13783_SSI_NETWORK, mask, val);
+
+ return 0;
+}
+
+static int mc13783_set_tdm_slot_sync(struct snd_soc_dai *dai,
+ unsigned int tx_mask, unsigned int rx_mask, int slots,
+ int slot_width)
+{
+ int ret;
+
+ ret = mc13783_set_tdm_slot_dac(dai, tx_mask, rx_mask, slots,
+ slot_width);
+ if (ret)
+ return ret;
+
+ ret = mc13783_set_tdm_slot_codec(dai, tx_mask, rx_mask, slots,
+ slot_width);
+
+ return ret;
+}
+
+static const struct snd_kcontrol_new mc1l_amp_ctl =
+ SOC_DAPM_SINGLE("Switch", 38, 7, 1, 0);
+
+static const struct snd_kcontrol_new mc1r_amp_ctl =
+ SOC_DAPM_SINGLE("Switch", 38, 5, 1, 0);
+
+static const struct snd_kcontrol_new mc2_amp_ctl =
+ SOC_DAPM_SINGLE("Switch", 38, 9, 1, 0);
+
+static const struct snd_kcontrol_new atx_amp_ctl =
+ SOC_DAPM_SINGLE("Switch", 38, 11, 1, 0);
+
+
+/* Virtual mux. The chip does the input selection automatically
+ * as soon as we enable one input. */
+static const char * const adcl_enum_text[] = {
+ "MC1L", "RXINL",
+};
+
+static const struct soc_enum adcl_enum =
+ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adcl_enum_text), adcl_enum_text);
+
+static const struct snd_kcontrol_new left_input_mux =
+ SOC_DAPM_ENUM_VIRT("Route", adcl_enum);
+
+static const char * const adcr_enum_text[] = {
+ "MC1R", "MC2", "RXINR", "TXIN",
+};
+
+static const struct soc_enum adcr_enum =
+ SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adcr_enum_text), adcr_enum_text);
+
+static const struct snd_kcontrol_new right_input_mux =
+ SOC_DAPM_ENUM_VIRT("Route", adcr_enum);
+
+static const struct snd_kcontrol_new samp_ctl =
+ SOC_DAPM_SINGLE("Switch", 36, 3, 1, 0);
+
+static const struct snd_kcontrol_new lamp_ctl =
+ SOC_DAPM_SINGLE("Switch", 36, 5, 1, 0);
+
+static const struct snd_kcontrol_new hlamp_ctl =
+ SOC_DAPM_SINGLE("Switch", 36, 10, 1, 0);
+
+static const struct snd_kcontrol_new hramp_ctl =
+ SOC_DAPM_SINGLE("Switch", 36, 9, 1, 0);
+
+static const struct snd_kcontrol_new llamp_ctl =
+ SOC_DAPM_SINGLE("Switch", 36, 16, 1, 0);
+
+static const struct snd_kcontrol_new lramp_ctl =
+ SOC_DAPM_SINGLE("Switch", 36, 15, 1, 0);
+
+static const struct snd_soc_dapm_widget mc13783_dapm_widgets[] = {
+/* Input */
+ SND_SOC_DAPM_INPUT("MC1LIN"),
+ SND_SOC_DAPM_INPUT("MC1RIN"),
+ SND_SOC_DAPM_INPUT("MC2IN"),
+ SND_SOC_DAPM_INPUT("RXINR"),
+ SND_SOC_DAPM_INPUT("RXINL"),
+ SND_SOC_DAPM_INPUT("TXIN"),
+
+ SND_SOC_DAPM_SUPPLY("MC1 Bias", 38, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MC2 Bias", 38, 1, 0, NULL, 0),
+
+ SND_SOC_DAPM_SWITCH("MC1L Amp", 38, 7, 0, &mc1l_amp_ctl),
+ SND_SOC_DAPM_SWITCH("MC1R Amp", 38, 5, 0, &mc1r_amp_ctl),
+ SND_SOC_DAPM_SWITCH("MC2 Amp", 38, 9, 0, &mc2_amp_ctl),
+ SND_SOC_DAPM_SWITCH("TXIN Amp", 38, 11, 0, &atx_amp_ctl),
+
+ SND_SOC_DAPM_VIRT_MUX("PGA Left Input Mux", SND_SOC_NOPM, 0, 0,
+ &left_input_mux),
+ SND_SOC_DAPM_VIRT_MUX("PGA Right Input Mux", SND_SOC_NOPM, 0, 0,
+ &right_input_mux),
+
+ SND_SOC_DAPM_PGA("PGA Left Input", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("PGA Right Input", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_ADC("ADC", "Capture", 40, 11, 0),
+ SND_SOC_DAPM_SUPPLY("ADC_Reset", 40, 15, 0, NULL, 0),
+
+/* Output */
+ SND_SOC_DAPM_SUPPLY("DAC_E", 41, 11, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("DAC_Reset", 41, 15, 0, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("RXOUTL"),
+ SND_SOC_DAPM_OUTPUT("RXOUTR"),
+ SND_SOC_DAPM_OUTPUT("HSL"),
+ SND_SOC_DAPM_OUTPUT("HSR"),
+ SND_SOC_DAPM_OUTPUT("LSP"),
+ SND_SOC_DAPM_OUTPUT("SP"),
+
+ SND_SOC_DAPM_SWITCH("Speaker Amp", 36, 3, 0, &samp_ctl),
+ SND_SOC_DAPM_SWITCH("Loudspeaker Amp", SND_SOC_NOPM, 0, 0, &lamp_ctl),
+ SND_SOC_DAPM_SWITCH("Headset Amp Left", 36, 10, 0, &hlamp_ctl),
+ SND_SOC_DAPM_SWITCH("Headset Amp Right", 36, 9, 0, &hramp_ctl),
+ SND_SOC_DAPM_SWITCH("Line out Amp Left", 36, 16, 0, &llamp_ctl),
+ SND_SOC_DAPM_SWITCH("Line out Amp Right", 36, 15, 0, &lramp_ctl),
+ SND_SOC_DAPM_DAC("DAC", "Playback", 36, 22, 0),
+ SND_SOC_DAPM_PGA("DAC PGA", 37, 5, 0, NULL, 0),
+};
+
+static struct snd_soc_dapm_route mc13783_routes[] = {
+/* Input */
+ { "MC1L Amp", NULL, "MC1LIN"},
+ { "MC1R Amp", NULL, "MC1RIN" },
+ { "MC2 Amp", NULL, "MC2IN" },
+ { "TXIN Amp", NULL, "TXIN"},
+
+ { "PGA Left Input Mux", "MC1L", "MC1L Amp" },
+ { "PGA Left Input Mux", "RXINL", "RXINL"},
+ { "PGA Right Input Mux", "MC1R", "MC1R Amp" },
+ { "PGA Right Input Mux", "MC2", "MC2 Amp"},
+ { "PGA Right Input Mux", "TXIN", "TXIN Amp"},
+ { "PGA Right Input Mux", "RXINR", "RXINR"},
+
+ { "PGA Left Input", NULL, "PGA Left Input Mux"},
+ { "PGA Right Input", NULL, "PGA Right Input Mux"},
+
+ { "ADC", NULL, "PGA Left Input"},
+ { "ADC", NULL, "PGA Right Input"},
+ { "ADC", NULL, "ADC_Reset"},
+
+/* Output */
+ { "HSL", NULL, "Headset Amp Left" },
+ { "HSR", NULL, "Headset Amp Right"},
+ { "RXOUTL", NULL, "Line out Amp Left"},
+ { "RXOUTR", NULL, "Line out Amp Right"},
+ { "SP", NULL, "Speaker Amp"},
+ { "Speaker Amp", NULL, "DAC PGA"},
+ { "LSP", NULL, "DAC PGA"},
+ { "Headset Amp Left", NULL, "DAC PGA"},
+ { "Headset Amp Right", NULL, "DAC PGA"},
+ { "Line out Amp Left", NULL, "DAC PGA"},
+ { "Line out Amp Right", NULL, "DAC PGA"},
+ { "DAC PGA", NULL, "DAC"},
+ { "DAC", NULL, "DAC_E"},
+};
+
+static const char * const mc13783_3d_mixer[] = {"Stereo", "Phase Mix",
+ "Mono", "Mono Mix"};
+
+static const struct soc_enum mc13783_enum_3d_mixer =
+ SOC_ENUM_SINGLE(MC13783_AUDIO_RX1, 16, ARRAY_SIZE(mc13783_3d_mixer),
+ mc13783_3d_mixer);
+
+static struct snd_kcontrol_new mc13783_control_list[] = {
+ SOC_SINGLE("Loudspeaker enable", MC13783_AUDIO_RX0, 5, 1, 0),
+ SOC_SINGLE("PCM Playback Volume", MC13783_AUDIO_RX1, 6, 15, 0),
+ SOC_DOUBLE("PCM Capture Volume", MC13783_AUDIO_TX, 19, 14, 31, 0),
+ SOC_ENUM("3D Control", mc13783_enum_3d_mixer),
+};
+
+static int mc13783_probe(struct snd_soc_codec *codec)
+{
+ struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+ mc13xxx_lock(priv->mc13xxx);
+
+ /* these are the reset values */
+ mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX0, 0x25893);
+ mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_RX1, 0x00d35A);
+ mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_TX, 0x420000);
+ mc13xxx_reg_write(priv->mc13xxx, MC13783_SSI_NETWORK, 0x013060);
+ mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_CODEC, 0x180027);
+ mc13xxx_reg_write(priv->mc13xxx, MC13783_AUDIO_DAC, 0x0e0004);
+
+ if (priv->adc_ssi_port == MC13783_SSI1_PORT)
+ mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_CODEC,
+ AUDIO_SSI_SEL, 0);
+ else
+ mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_CODEC,
+ 0, AUDIO_SSI_SEL);
+
+ if (priv->dac_ssi_port == MC13783_SSI1_PORT)
+ mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC,
+ AUDIO_SSI_SEL, 0);
+ else
+ mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_DAC,
+ 0, AUDIO_SSI_SEL);
+
+ mc13xxx_unlock(priv->mc13xxx);
+
+ return 0;
+}
+
+static int mc13783_remove(struct snd_soc_codec *codec)
+{
+ struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+ mc13xxx_lock(priv->mc13xxx);
+
+ /* Make sure VAUDIOON is off */
+ mc13xxx_reg_rmw(priv->mc13xxx, MC13783_AUDIO_RX0, 0x3, 0);
+
+ mc13xxx_unlock(priv->mc13xxx);
+
+ return 0;
+}
+
+#define MC13783_RATES_RECORD (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000)
+
+#define MC13783_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_ops mc13783_ops_dac = {
+ .hw_params = mc13783_pcm_hw_params_dac,
+ .set_fmt = mc13783_set_fmt_async,
+ .set_sysclk = mc13783_set_sysclk_dac,
+ .set_tdm_slot = mc13783_set_tdm_slot_dac,
+};
+
+static struct snd_soc_dai_ops mc13783_ops_codec = {
+ .hw_params = mc13783_pcm_hw_params_codec,
+ .set_fmt = mc13783_set_fmt_async,
+ .set_sysclk = mc13783_set_sysclk_codec,
+ .set_tdm_slot = mc13783_set_tdm_slot_codec,
+};
+
+/*
+ * The mc13783 has two SSI ports, both of them can be routed either
+ * to the voice codec or the stereo DAC. When two different SSI ports
+ * are used for the voice codec and the stereo DAC we can do different
+ * formats and sysclock settings for playback and capture
+ * (mc13783-hifi-playback and mc13783-hifi-capture). Using the same port
+ * forces us to use symmetric rates (mc13783-hifi).
+ */
+static struct snd_soc_dai_driver mc13783_dai_async[] = {
+ {
+ .name = "mc13783-hifi-playback",
+ .id = MC13783_ID_STEREO_DAC,
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = MC13783_FORMATS,
+ },
+ .ops = &mc13783_ops_dac,
+ }, {
+ .name = "mc13783-hifi-capture",
+ .id = MC13783_ID_STEREO_CODEC,
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MC13783_RATES_RECORD,
+ .formats = MC13783_FORMATS,
+ },
+ .ops = &mc13783_ops_codec,
+ },
+};
+
+static struct snd_soc_dai_ops mc13783_ops_sync = {
+ .hw_params = mc13783_pcm_hw_params_sync,
+ .set_fmt = mc13783_set_fmt_sync,
+ .set_sysclk = mc13783_set_sysclk_sync,
+ .set_tdm_slot = mc13783_set_tdm_slot_sync,
+};
+
+static struct snd_soc_dai_driver mc13783_dai_sync[] = {
+ {
+ .name = "mc13783-hifi",
+ .id = MC13783_ID_SYNC,
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = MC13783_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = MC13783_RATES_RECORD,
+ .formats = MC13783_FORMATS,
+ },
+ .ops = &mc13783_ops_sync,
+ .symmetric_rates = 1,
+ }
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_mc13783 = {
+ .probe = mc13783_probe,
+ .remove = mc13783_remove,
+ .read = mc13783_read,
+ .write = mc13783_write,
+ .controls = mc13783_control_list,
+ .num_controls = ARRAY_SIZE(mc13783_control_list),
+ .dapm_widgets = mc13783_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(mc13783_dapm_widgets),
+ .dapm_routes = mc13783_routes,
+ .num_dapm_routes = ARRAY_SIZE(mc13783_routes),
+};
+
+static int mc13783_codec_probe(struct platform_device *pdev)
+{
+ struct mc13xxx *mc13xxx;
+ struct mc13783_priv *priv;
+ struct mc13xxx_codec_platform_data *pdata = pdev->dev.platform_data;
+ int ret;
+
+ mc13xxx = dev_get_drvdata(pdev->dev.parent);
+
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+
+ dev_set_drvdata(&pdev->dev, priv);
+ priv->mc13xxx = mc13xxx;
+ if (pdata) {
+ priv->adc_ssi_port = pdata->adc_ssi_port;
+ priv->dac_ssi_port = pdata->dac_ssi_port;
+ } else {
+ priv->adc_ssi_port = MC13783_SSI1_PORT;
+ priv->dac_ssi_port = MC13783_SSI2_PORT;
+ }
+
+ if (priv->adc_ssi_port == priv->dac_ssi_port)
+ ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_mc13783,
+ mc13783_dai_sync, ARRAY_SIZE(mc13783_dai_sync));
+ else
+ ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_mc13783,
+ mc13783_dai_async, ARRAY_SIZE(mc13783_dai_async));
+
+ if (ret)
+ goto err_register_codec;
+
+ return 0;
+
+err_register_codec:
+ dev_err(&pdev->dev, "register codec failed with %d\n", ret);
+
+ return ret;
+}
+
+static int mc13783_codec_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+
+ return 0;
+}
+
+static struct platform_driver mc13783_codec_driver = {
+ .driver = {
+ .name = "mc13783-codec",
+ .owner = THIS_MODULE,
+ },
+ .probe = mc13783_codec_probe,
+ .remove = __devexit_p(mc13783_codec_remove),
+};
+
+module_platform_driver(mc13783_codec_driver);
+
+MODULE_DESCRIPTION("ASoC MC13783 driver");
+MODULE_AUTHOR("Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>");
+MODULE_AUTHOR("Philippe Retornaz <philippe.retornaz@epfl.ch>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/mc13783.h b/sound/soc/codecs/mc13783.h
new file mode 100644
index 000000000000..3a6d1993a217
--- /dev/null
+++ b/sound/soc/codecs/mc13783.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef MC13783_MIXER_H
+#define MC13783_MIXER_H
+
+#define MC13783_CLK_CLIA 1
+#define MC13783_CLK_CLIB 2
+
+#define MC13783_ID_STEREO_DAC 1
+#define MC13783_ID_STEREO_CODEC 2
+#define MC13783_ID_SYNC 3
+
+#endif /* MC13783_MIXER_H */
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c
new file mode 100644
index 000000000000..22cb5bf59273
--- /dev/null
+++ b/sound/soc/codecs/ml26124.c
@@ -0,0 +1,681 @@
+/*
+ * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include "ml26124.h"
+
+#define DVOL_CTL_DVMUTE_ON BIT(4) /* Digital volume MUTE On */
+#define DVOL_CTL_DVMUTE_OFF 0 /* Digital volume MUTE Off */
+#define ML26124_SAI_NO_DELAY BIT(1)
+#define ML26124_SAI_FRAME_SYNC (BIT(5) | BIT(0)) /* For mono (Telecodec) */
+#define ML26134_CACHESIZE 212
+#define ML26124_VMID BIT(1)
+#define ML26124_RATES (SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 |\
+ SNDRV_PCM_RATE_48000)
+#define ML26124_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE |\
+ SNDRV_PCM_FMTBIT_S32_LE)
+#define ML26124_NUM_REGISTER ML26134_CACHESIZE
+
+struct ml26124_priv {
+ u32 mclk;
+ u32 rate;
+ struct regmap *regmap;
+ int clk_in;
+ struct snd_pcm_substream *substream;
+};
+
+struct clk_coeff {
+ u32 mclk;
+ u32 rate;
+ u8 pllnl;
+ u8 pllnh;
+ u8 pllml;
+ u8 pllmh;
+ u8 plldiv;
+};
+
+/* ML26124 configuration */
+static const DECLARE_TLV_DB_SCALE(digital_tlv, -7150, 50, 0);
+
+static const DECLARE_TLV_DB_SCALE(alclvl, -2250, 150, 0);
+static const DECLARE_TLV_DB_SCALE(mingain, -1200, 600, 0);
+static const DECLARE_TLV_DB_SCALE(maxgain, -675, 600, 0);
+static const DECLARE_TLV_DB_SCALE(boost_vol, -1200, 75, 0);
+static const DECLARE_TLV_DB_SCALE(ngth, -7650, 150, 0);
+
+static const char * const ml26124_companding[] = {"16bit PCM", "u-law",
+ "A-law"};
+
+static const struct soc_enum ml26124_adc_companding_enum
+ = SOC_ENUM_SINGLE(ML26124_SAI_TRANS_CTL, 6, 3, ml26124_companding);
+
+static const struct soc_enum ml26124_dac_companding_enum
+ = SOC_ENUM_SINGLE(ML26124_SAI_RCV_CTL, 6, 3, ml26124_companding);
+
+static const struct snd_kcontrol_new ml26124_snd_controls[] = {
+ SOC_SINGLE_TLV("Capture Digital Volume", ML26124_RECORD_DIG_VOL, 0,
+ 0xff, 1, digital_tlv),
+ SOC_SINGLE_TLV("Playback Digital Volume", ML26124_PLBAK_DIG_VOL, 0,
+ 0xff, 1, digital_tlv),
+ SOC_SINGLE_TLV("Digital Boost Volume", ML26124_DIGI_BOOST_VOL, 0,
+ 0x3f, 0, boost_vol),
+ SOC_SINGLE_TLV("EQ Band0 Volume", ML26124_EQ_GAIN_BRAND0, 0,
+ 0xff, 1, digital_tlv),
+ SOC_SINGLE_TLV("EQ Band1 Volume", ML26124_EQ_GAIN_BRAND1, 0,
+ 0xff, 1, digital_tlv),
+ SOC_SINGLE_TLV("EQ Band2 Volume", ML26124_EQ_GAIN_BRAND2, 0,
+ 0xff, 1, digital_tlv),
+ SOC_SINGLE_TLV("EQ Band3 Volume", ML26124_EQ_GAIN_BRAND3, 0,
+ 0xff, 1, digital_tlv),
+ SOC_SINGLE_TLV("EQ Band4 Volume", ML26124_EQ_GAIN_BRAND4, 0,
+ 0xff, 1, digital_tlv),
+ SOC_SINGLE_TLV("ALC Target Level", ML26124_ALC_TARGET_LEV, 0,
+ 0xf, 1, alclvl),
+ SOC_SINGLE_TLV("ALC Min Input Volume", ML26124_ALC_MAXMIN_GAIN, 0,
+ 7, 0, mingain),
+ SOC_SINGLE_TLV("ALC Max Input Volume", ML26124_ALC_MAXMIN_GAIN, 4,
+ 7, 1, maxgain),
+ SOC_SINGLE_TLV("Playback Limiter Min Input Volume",
+ ML26124_PL_MAXMIN_GAIN, 0, 7, 0, mingain),
+ SOC_SINGLE_TLV("Playback Limiter Max Input Volume",
+ ML26124_PL_MAXMIN_GAIN, 4, 7, 1, maxgain),
+ SOC_SINGLE_TLV("Playback Boost Volume", ML26124_PLYBAK_BOST_VOL, 0,
+ 0x3f, 0, boost_vol),
+ SOC_SINGLE("DC High Pass Filter Switch", ML26124_FILTER_EN, 0, 1, 0),
+ SOC_SINGLE("Noise High Pass Filter Switch", ML26124_FILTER_EN, 1, 1, 0),
+ SOC_SINGLE("ZC Switch", ML26124_PW_ZCCMP_PW_MNG, 1,
+ 1, 0),
+ SOC_SINGLE("EQ Band0 Switch", ML26124_FILTER_EN, 2, 1, 0),
+ SOC_SINGLE("EQ Band1 Switch", ML26124_FILTER_EN, 3, 1, 0),
+ SOC_SINGLE("EQ Band2 Switch", ML26124_FILTER_EN, 4, 1, 0),
+ SOC_SINGLE("EQ Band3 Switch", ML26124_FILTER_EN, 5, 1, 0),
+ SOC_SINGLE("EQ Band4 Switch", ML26124_FILTER_EN, 6, 1, 0),
+ SOC_SINGLE("Play Limiter", ML26124_DVOL_CTL, 0, 1, 0),
+ SOC_SINGLE("Capture Limiter", ML26124_DVOL_CTL, 1, 1, 0),
+ SOC_SINGLE("Digital Volume Fade Switch", ML26124_DVOL_CTL, 3, 1, 0),
+ SOC_SINGLE("Digital Switch", ML26124_DVOL_CTL, 4, 1, 0),
+ SOC_ENUM("DAC Companding", ml26124_dac_companding_enum),
+ SOC_ENUM("ADC Companding", ml26124_adc_companding_enum),
+};
+
+static const struct snd_kcontrol_new ml26124_output_mixer_controls[] = {
+ SOC_DAPM_SINGLE("DAC Switch", ML26124_SPK_AMP_OUT, 1, 1, 0),
+ SOC_DAPM_SINGLE("Line in loopback Switch", ML26124_SPK_AMP_OUT, 3, 1,
+ 0),
+ SOC_DAPM_SINGLE("PGA Switch", ML26124_SPK_AMP_OUT, 5, 1, 0),
+};
+
+/* Input mux */
+static const char * const ml26124_input_select[] = {"Analog MIC SingleEnded in",
+ "Digital MIC in", "Analog MIC Differential in"};
+
+static const struct soc_enum ml26124_insel_enum =
+ SOC_ENUM_SINGLE(ML26124_MIC_IF_CTL, 0, 3, ml26124_input_select);
+
+static const struct snd_kcontrol_new ml26124_input_mux_controls =
+ SOC_DAPM_ENUM("Input Select", ml26124_insel_enum);
+
+static const struct snd_kcontrol_new ml26124_line_control =
+ SOC_DAPM_SINGLE("Switch", ML26124_PW_LOUT_PW_MNG, 1, 1, 0);
+
+static const struct snd_soc_dapm_widget ml26124_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("MCLKEN", ML26124_CLK_EN, 0, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("PLLEN", ML26124_CLK_EN, 1, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("PLLOE", ML26124_CLK_EN, 2, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MICBIAS", ML26124_PW_REF_PW_MNG, 2, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("Output Mixer", SND_SOC_NOPM, 0, 0,
+ &ml26124_output_mixer_controls[0],
+ ARRAY_SIZE(ml26124_output_mixer_controls)),
+ SND_SOC_DAPM_DAC("DAC", "Playback", ML26124_PW_DAC_PW_MNG, 1, 0),
+ SND_SOC_DAPM_ADC("ADC", "Capture", ML26124_PW_IN_PW_MNG, 1, 0),
+ SND_SOC_DAPM_PGA("PGA", ML26124_PW_IN_PW_MNG, 3, 0, NULL, 0),
+ SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0,
+ &ml26124_input_mux_controls),
+ SND_SOC_DAPM_SWITCH("Line Out Enable", SND_SOC_NOPM, 0, 0,
+ &ml26124_line_control),
+ SND_SOC_DAPM_INPUT("MDIN"),
+ SND_SOC_DAPM_INPUT("MIN"),
+ SND_SOC_DAPM_INPUT("LIN"),
+ SND_SOC_DAPM_OUTPUT("SPOUT"),
+ SND_SOC_DAPM_OUTPUT("LOUT"),
+};
+
+static const struct snd_soc_dapm_route ml26124_intercon[] = {
+ /* Supply */
+ {"DAC", NULL, "MCLKEN"},
+ {"ADC", NULL, "MCLKEN"},
+ {"DAC", NULL, "PLLEN"},
+ {"ADC", NULL, "PLLEN"},
+ {"DAC", NULL, "PLLOE"},
+ {"ADC", NULL, "PLLOE"},
+
+ /* output mixer */
+ {"Output Mixer", "DAC Switch", "DAC"},
+ {"Output Mixer", "Line in loopback Switch", "LIN"},
+
+ /* outputs */
+ {"LOUT", NULL, "Output Mixer"},
+ {"SPOUT", NULL, "Output Mixer"},
+ {"Line Out Enable", NULL, "LOUT"},
+
+ /* input */
+ {"ADC", NULL, "Input Mux"},
+ {"Input Mux", "Analog MIC SingleEnded in", "PGA"},
+ {"Input Mux", "Analog MIC Differential in", "PGA"},
+ {"PGA", NULL, "MIN"},
+};
+
+/* PLLOutputFreq(Hz) = InputMclkFreq(Hz) * PLLM / (PLLN * PLLDIV) */
+static const struct clk_coeff coeff_div[] = {
+ {12288000, 16000, 0xc, 0x0, 0x20, 0x0, 0x4},
+ {12288000, 32000, 0xc, 0x0, 0x20, 0x0, 0x4},
+ {12288000, 48000, 0xc, 0x0, 0x30, 0x0, 0x4},
+};
+
+static struct reg_default ml26124_reg[] = {
+ /* CLOCK control Register */
+ {0x00, 0x00 }, /* Sampling Rate */
+ {0x02, 0x00}, /* PLL NL */
+ {0x04, 0x00}, /* PLLNH */
+ {0x06, 0x00}, /* PLLML */
+ {0x08, 0x00}, /* MLLMH */
+ {0x0a, 0x00}, /* PLLDIV */
+ {0x0c, 0x00}, /* Clock Enable */
+ {0x0e, 0x00}, /* CLK Input/Output Control */
+
+ /* System Control Register */
+ {0x10, 0x00}, /* Software RESET */
+ {0x12, 0x00}, /* Record/Playback Run */
+ {0x14, 0x00}, /* Mic Input/Output control */
+
+ /* Power Management Register */
+ {0x20, 0x00}, /* Reference Power Management */
+ {0x22, 0x00}, /* Input Power Management */
+ {0x24, 0x00}, /* DAC Power Management */
+ {0x26, 0x00}, /* SP-AMP Power Management */
+ {0x28, 0x00}, /* LINEOUT Power Management */
+ {0x2a, 0x00}, /* VIDEO Power Management */
+ {0x2e, 0x00}, /* AC-CMP Power Management */
+
+ /* Analog reference Control Register */
+ {0x30, 0x04}, /* MICBIAS Voltage Control */
+
+ /* Input/Output Amplifier Control Register */
+ {0x32, 0x10}, /* MIC Input Volume */
+ {0x38, 0x00}, /* Mic Boost Volume */
+ {0x3a, 0x33}, /* Speaker AMP Volume */
+ {0x48, 0x00}, /* AMP Volume Control Function Enable */
+ {0x4a, 0x00}, /* Amplifier Volume Fader Control */
+
+ /* Analog Path Control Register */
+ {0x54, 0x00}, /* Speaker AMP Output Control */
+ {0x5a, 0x00}, /* Mic IF Control */
+ {0xe8, 0x01}, /* Mic Select Control */
+
+ /* Audio Interface Control Register */
+ {0x60, 0x00}, /* SAI-Trans Control */
+ {0x62, 0x00}, /* SAI-Receive Control */
+ {0x64, 0x00}, /* SAI Mode select */
+
+ /* DSP Control Register */
+ {0x66, 0x01}, /* Filter Func Enable */
+ {0x68, 0x00}, /* Volume Control Func Enable */
+ {0x6A, 0x00}, /* Mixer & Volume Control*/
+ {0x6C, 0xff}, /* Record Digital Volume */
+ {0x70, 0xff}, /* Playback Digital Volume */
+ {0x72, 0x10}, /* Digital Boost Volume */
+ {0x74, 0xe7}, /* EQ gain Band0 */
+ {0x76, 0xe7}, /* EQ gain Band1 */
+ {0x78, 0xe7}, /* EQ gain Band2 */
+ {0x7A, 0xe7}, /* EQ gain Band3 */
+ {0x7C, 0xe7}, /* EQ gain Band4 */
+ {0x7E, 0x00}, /* HPF2 CutOff*/
+ {0x80, 0x00}, /* EQ Band0 Coef0L */
+ {0x82, 0x00}, /* EQ Band0 Coef0H */
+ {0x84, 0x00}, /* EQ Band0 Coef0L */
+ {0x86, 0x00}, /* EQ Band0 Coef0H */
+ {0x88, 0x00}, /* EQ Band1 Coef0L */
+ {0x8A, 0x00}, /* EQ Band1 Coef0H */
+ {0x8C, 0x00}, /* EQ Band1 Coef0L */
+ {0x8E, 0x00}, /* EQ Band1 Coef0H */
+ {0x90, 0x00}, /* EQ Band2 Coef0L */
+ {0x92, 0x00}, /* EQ Band2 Coef0H */
+ {0x94, 0x00}, /* EQ Band2 Coef0L */
+ {0x96, 0x00}, /* EQ Band2 Coef0H */
+ {0x98, 0x00}, /* EQ Band3 Coef0L */
+ {0x9A, 0x00}, /* EQ Band3 Coef0H */
+ {0x9C, 0x00}, /* EQ Band3 Coef0L */
+ {0x9E, 0x00}, /* EQ Band3 Coef0H */
+ {0xA0, 0x00}, /* EQ Band4 Coef0L */
+ {0xA2, 0x00}, /* EQ Band4 Coef0H */
+ {0xA4, 0x00}, /* EQ Band4 Coef0L */
+ {0xA6, 0x00}, /* EQ Band4 Coef0H */
+
+ /* ALC Control Register */
+ {0xb0, 0x00}, /* ALC Mode */
+ {0xb2, 0x02}, /* ALC Attack Time */
+ {0xb4, 0x03}, /* ALC Decay Time */
+ {0xb6, 0x00}, /* ALC Hold Time */
+ {0xb8, 0x0b}, /* ALC Target Level */
+ {0xba, 0x70}, /* ALC Max/Min Gain */
+ {0xbc, 0x00}, /* Noise Gate Threshold */
+ {0xbe, 0x00}, /* ALC ZeroCross TimeOut */
+
+ /* Playback Limiter Control Register */
+ {0xc0, 0x04}, /* PL Attack Time */
+ {0xc2, 0x05}, /* PL Decay Time */
+ {0xc4, 0x0d}, /* PL Target Level */
+ {0xc6, 0x70}, /* PL Max/Min Gain */
+ {0xc8, 0x10}, /* Playback Boost Volume */
+ {0xca, 0x00}, /* PL ZeroCross TimeOut */
+
+ /* Video Amplifier Control Register */
+ {0xd0, 0x01}, /* VIDEO AMP Gain Control */
+ {0xd2, 0x01}, /* VIDEO AMP Setup 1 */
+ {0xd4, 0x01}, /* VIDEO AMP Control2 */
+};
+
+/* Get sampling rate value of sampling rate setting register (0x0) */
+static inline int get_srate(int rate)
+{
+ int srate;
+
+ switch (rate) {
+ case 16000:
+ srate = 3;
+ break;
+ case 32000:
+ srate = 6;
+ break;
+ case 48000:
+ srate = 8;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return srate;
+}
+
+static inline int get_coeff(int mclk, int rate)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
+ if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
+ return i;
+ }
+ return -EINVAL;
+}
+
+static int ml26124_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+ int i = get_coeff(priv->mclk, params_rate(hw_params));
+
+ priv->substream = substream;
+ priv->rate = params_rate(hw_params);
+
+ if (priv->clk_in) {
+ switch (priv->mclk / params_rate(hw_params)) {
+ case 256:
+ snd_soc_update_bits(codec, ML26124_CLK_CTL,
+ BIT(0) | BIT(1), 1);
+ break;
+ case 512:
+ snd_soc_update_bits(codec, ML26124_CLK_CTL,
+ BIT(0) | BIT(1), 2);
+ break;
+ case 1024:
+ snd_soc_update_bits(codec, ML26124_CLK_CTL,
+ BIT(0) | BIT(1), 3);
+ break;
+ default:
+ dev_err(codec->dev, "Unsupported MCLKI\n");
+ break;
+ }
+ } else {
+ snd_soc_update_bits(codec, ML26124_CLK_CTL,
+ BIT(0) | BIT(1), 0);
+ }
+
+ switch (params_rate(hw_params)) {
+ case 16000:
+ snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf,
+ get_srate(params_rate(hw_params)));
+ snd_soc_update_bits(codec, ML26124_PLLNL, 0xff,
+ coeff_div[i].pllnl);
+ snd_soc_update_bits(codec, ML26124_PLLNH, 0x1,
+ coeff_div[i].pllnh);
+ snd_soc_update_bits(codec, ML26124_PLLML, 0xff,
+ coeff_div[i].pllml);
+ snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f,
+ coeff_div[i].pllmh);
+ snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f,
+ coeff_div[i].plldiv);
+ break;
+ case 32000:
+ snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf,
+ get_srate(params_rate(hw_params)));
+ snd_soc_update_bits(codec, ML26124_PLLNL, 0xff,
+ coeff_div[i].pllnl);
+ snd_soc_update_bits(codec, ML26124_PLLNH, 0x1,
+ coeff_div[i].pllnh);
+ snd_soc_update_bits(codec, ML26124_PLLML, 0xff,
+ coeff_div[i].pllml);
+ snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f,
+ coeff_div[i].pllmh);
+ snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f,
+ coeff_div[i].plldiv);
+ break;
+ case 48000:
+ snd_soc_update_bits(codec, ML26124_SMPLING_RATE, 0xf,
+ get_srate(params_rate(hw_params)));
+ snd_soc_update_bits(codec, ML26124_PLLNL, 0xff,
+ coeff_div[i].pllnl);
+ snd_soc_update_bits(codec, ML26124_PLLNH, 0x1,
+ coeff_div[i].pllnh);
+ snd_soc_update_bits(codec, ML26124_PLLML, 0xff,
+ coeff_div[i].pllml);
+ snd_soc_update_bits(codec, ML26124_PLLMH, 0x3f,
+ coeff_div[i].pllmh);
+ snd_soc_update_bits(codec, ML26124_PLLDIV, 0x1f,
+ coeff_div[i].plldiv);
+ break;
+ default:
+ pr_err("%s:this rate is no support for ml26124\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ml26124_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+ switch (priv->substream->stream) {
+ case SNDRV_PCM_STREAM_CAPTURE:
+ snd_soc_update_bits(codec, ML26124_REC_PLYBAK_RUN, BIT(0), 1);
+ break;
+ case SNDRV_PCM_STREAM_PLAYBACK:
+ snd_soc_update_bits(codec, ML26124_REC_PLYBAK_RUN, BIT(1), 2);
+ break;
+ }
+
+ if (mute)
+ snd_soc_update_bits(codec, ML26124_DVOL_CTL, BIT(4),
+ DVOL_CTL_DVMUTE_ON);
+ else
+ snd_soc_update_bits(codec, ML26124_DVOL_CTL, BIT(4),
+ DVOL_CTL_DVMUTE_OFF);
+
+ return 0;
+}
+
+static int ml26124_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int fmt)
+{
+ unsigned char mode;
+ struct snd_soc_codec *codec = codec_dai->codec;
+
+ /* set master/slave audio interface */
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ mode = 1;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ mode = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ snd_soc_update_bits(codec, ML26124_SAI_MODE_SEL, BIT(0), mode);
+
+ /* interface format */
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* clock inversion */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ml26124_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+ switch (clk_id) {
+ case ML26124_USE_PLLOUT:
+ priv->clk_in = ML26124_USE_PLLOUT;
+ break;
+ case ML26124_USE_MCLKI:
+ priv->clk_in = ML26124_USE_MCLKI;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ priv->mclk = freq;
+
+ return 0;
+}
+
+static int ml26124_set_bias_level(struct snd_soc_codec *codec,
+ enum snd_soc_bias_level level)
+{
+ struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+ switch (level) {
+ case SND_SOC_BIAS_ON:
+ snd_soc_update_bits(codec, ML26124_PW_SPAMP_PW_MNG,
+ ML26124_R26_MASK, ML26124_BLT_PREAMP_ON);
+ msleep(100);
+ snd_soc_update_bits(codec, ML26124_PW_SPAMP_PW_MNG,
+ ML26124_R26_MASK,
+ ML26124_MICBEN_ON | ML26124_BLT_ALL_ON);
+ break;
+ case SND_SOC_BIAS_PREPARE:
+ break;
+ case SND_SOC_BIAS_STANDBY:
+ /* VMID ON */
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
+ snd_soc_update_bits(codec, ML26124_PW_REF_PW_MNG,
+ ML26124_VMID, ML26124_VMID);
+ msleep(500);
+ regcache_sync(priv->regmap);
+ }
+ break;
+ case SND_SOC_BIAS_OFF:
+ /* VMID OFF */
+ snd_soc_update_bits(codec, ML26124_PW_REF_PW_MNG,
+ ML26124_VMID, 0);
+ break;
+ }
+ codec->dapm.bias_level = level;
+ return 0;
+}
+
+static const struct snd_soc_dai_ops ml26124_dai_ops = {
+ .hw_params = ml26124_hw_params,
+ .digital_mute = ml26124_mute,
+ .set_fmt = ml26124_set_dai_fmt,
+ .set_sysclk = ml26124_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver ml26124_dai = {
+ .name = "ml26124-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = ML26124_RATES,
+ .formats = ML26124_FORMATS,},
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = ML26124_RATES,
+ .formats = ML26124_FORMATS,},
+ .ops = &ml26124_dai_ops,
+ .symmetric_rates = 1,
+};
+
+#ifdef CONFIG_PM
+static int ml26124_suspend(struct snd_soc_codec *codec)
+{
+ ml26124_set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+ return 0;
+}
+
+static int ml26124_resume(struct snd_soc_codec *codec)
+{
+ ml26124_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ return 0;
+}
+#else
+#define ml26124_suspend NULL
+#define ml26124_resume NULL
+#endif
+
+static int ml26124_probe(struct snd_soc_codec *codec)
+{
+ int ret;
+ struct ml26124_priv *priv = snd_soc_codec_get_drvdata(codec);
+ codec->control_data = priv->regmap;
+
+ ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+ return ret;
+ }
+
+ /* Software Reset */
+ snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 1);
+ snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 0);
+
+ ml26124_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_ml26124 = {
+ .probe = ml26124_probe,
+ .suspend = ml26124_suspend,
+ .resume = ml26124_resume,
+ .set_bias_level = ml26124_set_bias_level,
+ .dapm_widgets = ml26124_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(ml26124_dapm_widgets),
+ .dapm_routes = ml26124_intercon,
+ .num_dapm_routes = ARRAY_SIZE(ml26124_intercon),
+ .controls = ml26124_snd_controls,
+ .num_controls = ARRAY_SIZE(ml26124_snd_controls),
+};
+
+static const struct regmap_config ml26124_i2c_regmap = {
+ .val_bits = 8,
+ .reg_bits = 8,
+ .max_register = ML26124_NUM_REGISTER,
+ .reg_defaults = ml26124_reg,
+ .num_reg_defaults = ARRAY_SIZE(ml26124_reg),
+ .cache_type = REGCACHE_RBTREE,
+ .write_flag_mask = 0x01,
+};
+
+static __devinit int ml26124_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct ml26124_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, priv);
+
+ priv->regmap = regmap_init_i2c(i2c, &ml26124_i2c_regmap);
+ if (IS_ERR(priv->regmap)) {
+ ret = PTR_ERR(priv->regmap);
+ dev_err(&i2c->dev, "regmap_init_i2c() failed: %d\n", ret);
+ return ret;
+ }
+
+ return snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_ml26124, &ml26124_dai, 1);
+}
+
+static __devexit int ml26124_i2c_remove(struct i2c_client *client)
+{
+ struct ml26124_priv *priv = i2c_get_clientdata(client);
+
+ snd_soc_unregister_codec(&client->dev);
+ regmap_exit(priv->regmap);
+ return 0;
+}
+
+static const struct i2c_device_id ml26124_i2c_id[] = {
+ { "ml26124", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ml26124_i2c_id);
+
+static struct i2c_driver ml26124_i2c_driver = {
+ .driver = {
+ .name = "ml26124",
+ .owner = THIS_MODULE,
+ },
+ .probe = ml26124_i2c_probe,
+ .remove = __devexit_p(ml26124_i2c_remove),
+ .id_table = ml26124_i2c_id,
+};
+
+module_i2c_driver(ml26124_i2c_driver);
+
+MODULE_AUTHOR("Tomoya MORINAGA <tomoya.rohm@gmail.com>");
+MODULE_DESCRIPTION("LAPIS Semiconductor ML26124 ALSA SoC codec driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/ml26124.h b/sound/soc/codecs/ml26124.h
new file mode 100644
index 000000000000..5ea0cbb8c46c
--- /dev/null
+++ b/sound/soc/codecs/ml26124.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef ML26124_H
+#define ML26124_H
+
+/* Clock Control Register */
+#define ML26124_SMPLING_RATE 0x00
+#define ML26124_PLLNL 0x02
+#define ML26124_PLLNH 0x04
+#define ML26124_PLLML 0x06
+#define ML26124_PLLMH 0x08
+#define ML26124_PLLDIV 0x0a
+#define ML26124_CLK_EN 0x0c
+#define ML26124_CLK_CTL 0x0e
+
+/* System Control Register */
+#define ML26124_SW_RST 0x10
+#define ML26124_REC_PLYBAK_RUN 0x12
+#define ML26124_MIC_TIM 0x14
+
+/* Power Mnagement Register */
+#define ML26124_PW_REF_PW_MNG 0x20
+#define ML26124_PW_IN_PW_MNG 0x22
+#define ML26124_PW_DAC_PW_MNG 0x24
+#define ML26124_PW_SPAMP_PW_MNG 0x26
+#define ML26124_PW_LOUT_PW_MNG 0x28
+#define ML26124_PW_VOUT_PW_MNG 0x2a
+#define ML26124_PW_ZCCMP_PW_MNG 0x2e
+
+/* Analog Reference Control Register */
+#define ML26124_PW_MICBIAS_VOL 0x30
+
+/* Input/Output Amplifier Control Register */
+#define ML26124_PW_MIC_IN_VOL 0x32
+#define ML26124_PW_MIC_BOST_VOL 0x38
+#define ML26124_PW_SPK_AMP_VOL 0x3a
+#define ML26124_PW_AMP_VOL_FUNC 0x48
+#define ML26124_PW_AMP_VOL_FADE 0x4a
+
+/* Analog Path Control Register */
+#define ML26124_SPK_AMP_OUT 0x54
+#define ML26124_MIC_IF_CTL 0x5a
+#define ML26124_MIC_SELECT 0xe8
+
+/* Audio Interface Control Register */
+#define ML26124_SAI_TRANS_CTL 0x60
+#define ML26124_SAI_RCV_CTL 0x62
+#define ML26124_SAI_MODE_SEL 0x64
+
+/* DSP Control Register */
+#define ML26124_FILTER_EN 0x66
+#define ML26124_DVOL_CTL 0x68
+#define ML26124_MIXER_VOL_CTL 0x6a
+#define ML26124_RECORD_DIG_VOL 0x6c
+#define ML26124_PLBAK_DIG_VOL 0x70
+#define ML26124_DIGI_BOOST_VOL 0x72
+#define ML26124_EQ_GAIN_BRAND0 0x74
+#define ML26124_EQ_GAIN_BRAND1 0x76
+#define ML26124_EQ_GAIN_BRAND2 0x78
+#define ML26124_EQ_GAIN_BRAND3 0x7a
+#define ML26124_EQ_GAIN_BRAND4 0x7c
+#define ML26124_HPF2_CUTOFF 0x7e
+#define ML26124_EQBRAND0_F0L 0x80
+#define ML26124_EQBRAND0_F0H 0x82
+#define ML26124_EQBRAND0_F1L 0x84
+#define ML26124_EQBRAND0_F1H 0x86
+#define ML26124_EQBRAND1_F0L 0x88
+#define ML26124_EQBRAND1_F0H 0x8a
+#define ML26124_EQBRAND1_F1L 0x8c
+#define ML26124_EQBRAND1_F1H 0x8e
+#define ML26124_EQBRAND2_F0L 0x90
+#define ML26124_EQBRAND2_F0H 0x92
+#define ML26124_EQBRAND2_F1L 0x94
+#define ML26124_EQBRAND2_F1H 0x96
+#define ML26124_EQBRAND3_F0L 0x98
+#define ML26124_EQBRAND3_F0H 0x9a
+#define ML26124_EQBRAND3_F1L 0x9c
+#define ML26124_EQBRAND3_F1H 0x9e
+#define ML26124_EQBRAND4_F0L 0xa0
+#define ML26124_EQBRAND4_F0H 0xa2
+#define ML26124_EQBRAND4_F1L 0xa4
+#define ML26124_EQBRAND4_F1H 0xa6
+
+/* ALC Control Register */
+#define ML26124_ALC_MODE 0xb0
+#define ML26124_ALC_ATTACK_TIM 0xb2
+#define ML26124_ALC_DECAY_TIM 0xb4
+#define ML26124_ALC_HOLD_TIM 0xb6
+#define ML26124_ALC_TARGET_LEV 0xb8
+#define ML26124_ALC_MAXMIN_GAIN 0xba
+#define ML26124_NOIS_GATE_THRSH 0xbc
+#define ML26124_ALC_ZERO_TIMOUT 0xbe
+
+/* Playback Limiter Control Register */
+#define ML26124_PL_ATTACKTIME 0xc0
+#define ML26124_PL_DECAYTIME 0xc2
+#define ML26124_PL_TARGETTIME 0xc4
+#define ML26124_PL_MAXMIN_GAIN 0xc6
+#define ML26124_PLYBAK_BOST_VOL 0xc8
+#define ML26124_PL_0CROSS_TIMOUT 0xca
+
+/* Video Amplifer Control Register */
+#define ML26124_VIDEO_AMP_GAIN_CTL 0xd0
+#define ML26124_VIDEO_AMP_SETUP1 0xd2
+#define ML26124_VIDEO_AMP_CTL2 0xd4
+
+/* Clock select for machine driver */
+#define ML26124_USE_PLL 0
+#define ML26124_USE_MCLKI_256FS 1
+#define ML26124_USE_MCLKI_512FS 2
+#define ML26124_USE_MCLKI_1024FS 3
+
+/* Register Mask */
+#define ML26124_R0_MASK 0xf
+#define ML26124_R2_MASK 0xff
+#define ML26124_R4_MASK 0x1
+#define ML26124_R6_MASK 0xf
+#define ML26124_R8_MASK 0x3f
+#define ML26124_Ra_MASK 0x1f
+#define ML26124_Rc_MASK 0x1f
+#define ML26124_Re_MASK 0x7
+#define ML26124_R10_MASK 0x1
+#define ML26124_R12_MASK 0x17
+#define ML26124_R14_MASK 0x3f
+#define ML26124_R20_MASK 0x47
+#define ML26124_R22_MASK 0xa
+#define ML26124_R24_MASK 0x2
+#define ML26124_R26_MASK 0x1f
+#define ML26124_R28_MASK 0x2
+#define ML26124_R2a_MASK 0x2
+#define ML26124_R2e_MASK 0x2
+#define ML26124_R30_MASK 0x7
+#define ML26124_R32_MASK 0x3f
+#define ML26124_R38_MASK 0x38
+#define ML26124_R3a_MASK 0x3f
+#define ML26124_R48_MASK 0x3
+#define ML26124_R4a_MASK 0x7
+#define ML26124_R54_MASK 0x2a
+#define ML26124_R5a_MASK 0x3
+#define ML26124_Re8_MASK 0x3
+#define ML26124_R60_MASK 0xff
+#define ML26124_R62_MASK 0xff
+#define ML26124_R64_MASK 0x1
+#define ML26124_R66_MASK 0xff
+#define ML26124_R68_MASK 0x3b
+#define ML26124_R6a_MASK 0xf3
+#define ML26124_R6c_MASK 0xff
+#define ML26124_R70_MASK 0xff
+
+#define ML26124_MCLKEN BIT(0)
+#define ML26124_PLLEN BIT(1)
+#define ML26124_PLLOE BIT(2)
+#define ML26124_MCLKOE BIT(3)
+
+#define ML26124_BLT_ALL_ON 0x1f
+#define ML26124_BLT_PREAMP_ON 0x13
+
+#define ML26124_MICBEN_ON BIT(2)
+
+enum ml26124_regs {
+ ML26124_MCLK = 0,
+};
+
+enum ml26124_clk_in {
+ ML26124_USE_PLLOUT = 0,
+ ML26124_USE_MCLKI,
+};
+
+#endif
diff --git a/sound/soc/codecs/omap-hdmi.c b/sound/soc/codecs/omap-hdmi.c
new file mode 100644
index 000000000000..1bf5c74f5f96
--- /dev/null
+++ b/sound/soc/codecs/omap-hdmi.c
@@ -0,0 +1,69 @@
+/*
+ * ALSA SoC codec driver for HDMI audio on OMAP processors.
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Ricardo Neri <ricardo.neri@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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#define DRV_NAME "hdmi-audio-codec"
+
+static struct snd_soc_codec_driver omap_hdmi_codec;
+
+static struct snd_soc_dai_driver omap_hdmi_codec_dai = {
+ .name = "omap-hdmi-hifi",
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = SNDRV_PCM_RATE_32000 |
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ },
+};
+
+static __devinit int omap_hdmi_codec_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev, &omap_hdmi_codec,
+ &omap_hdmi_codec_dai, 1);
+}
+
+static __devexit int omap_hdmi_codec_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver omap_hdmi_codec_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+
+ .probe = omap_hdmi_codec_probe,
+ .remove = __devexit_p(omap_hdmi_codec_remove),
+};
+
+module_platform_driver(omap_hdmi_codec_driver);
+
+MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
+MODULE_DESCRIPTION("ASoC OMAP HDMI codec driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c
index 20c324c7c349..960d0e93cce9 100644
--- a/sound/soc/codecs/rt5631.c
+++ b/sound/soc/codecs/rt5631.c
@@ -18,7 +18,7 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
-#include <linux/spi/spi.h>
+#include <linux/regmap.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -30,6 +30,7 @@
#include "rt5631.h"
struct rt5631_priv {
+ struct regmap *regmap;
int codec_version;
int master;
int sysclk;
@@ -38,33 +39,33 @@ struct rt5631_priv {
int dmic_used_flag;
};
-static const u16 rt5631_reg[RT5631_VENDOR_ID2 + 1] = {
- [RT5631_SPK_OUT_VOL] = 0x8888,
- [RT5631_HP_OUT_VOL] = 0x8080,
- [RT5631_MONO_AXO_1_2_VOL] = 0xa080,
- [RT5631_AUX_IN_VOL] = 0x0808,
- [RT5631_ADC_REC_MIXER] = 0xf0f0,
- [RT5631_VDAC_DIG_VOL] = 0x0010,
- [RT5631_OUTMIXER_L_CTRL] = 0xffc0,
- [RT5631_OUTMIXER_R_CTRL] = 0xffc0,
- [RT5631_AXO1MIXER_CTRL] = 0x88c0,
- [RT5631_AXO2MIXER_CTRL] = 0x88c0,
- [RT5631_DIG_MIC_CTRL] = 0x3000,
- [RT5631_MONO_INPUT_VOL] = 0x8808,
- [RT5631_SPK_MIXER_CTRL] = 0xf8f8,
- [RT5631_SPK_MONO_OUT_CTRL] = 0xfc00,
- [RT5631_SPK_MONO_HP_OUT_CTRL] = 0x4440,
- [RT5631_SDP_CTRL] = 0x8000,
- [RT5631_MONO_SDP_CTRL] = 0x8000,
- [RT5631_STEREO_AD_DA_CLK_CTRL] = 0x2010,
- [RT5631_GEN_PUR_CTRL_REG] = 0x0e00,
- [RT5631_INT_ST_IRQ_CTRL_2] = 0x071a,
- [RT5631_MISC_CTRL] = 0x2040,
- [RT5631_DEPOP_FUN_CTRL_2] = 0x8000,
- [RT5631_SOFT_VOL_CTRL] = 0x07e0,
- [RT5631_ALC_CTRL_1] = 0x0206,
- [RT5631_ALC_CTRL_3] = 0x2000,
- [RT5631_PSEUDO_SPATL_CTRL] = 0x0553,
+static const struct reg_default rt5631_reg[] = {
+ { RT5631_SPK_OUT_VOL, 0x8888 },
+ { RT5631_HP_OUT_VOL, 0x8080 },
+ { RT5631_MONO_AXO_1_2_VOL, 0xa080 },
+ { RT5631_AUX_IN_VOL, 0x0808 },
+ { RT5631_ADC_REC_MIXER, 0xf0f0 },
+ { RT5631_VDAC_DIG_VOL, 0x0010 },
+ { RT5631_OUTMIXER_L_CTRL, 0xffc0 },
+ { RT5631_OUTMIXER_R_CTRL, 0xffc0 },
+ { RT5631_AXO1MIXER_CTRL, 0x88c0 },
+ { RT5631_AXO2MIXER_CTRL, 0x88c0 },
+ { RT5631_DIG_MIC_CTRL, 0x3000 },
+ { RT5631_MONO_INPUT_VOL, 0x8808 },
+ { RT5631_SPK_MIXER_CTRL, 0xf8f8 },
+ { RT5631_SPK_MONO_OUT_CTRL, 0xfc00 },
+ { RT5631_SPK_MONO_HP_OUT_CTRL, 0x4440 },
+ { RT5631_SDP_CTRL, 0x8000 },
+ { RT5631_MONO_SDP_CTRL, 0x8000 },
+ { RT5631_STEREO_AD_DA_CLK_CTRL, 0x2010 },
+ { RT5631_GEN_PUR_CTRL_REG, 0x0e00 },
+ { RT5631_INT_ST_IRQ_CTRL_2, 0x071a },
+ { RT5631_MISC_CTRL, 0x2040 },
+ { RT5631_DEPOP_FUN_CTRL_2, 0x8000 },
+ { RT5631_SOFT_VOL_CTRL, 0x07e0 },
+ { RT5631_ALC_CTRL_1, 0x0206 },
+ { RT5631_ALC_CTRL_3, 0x2000 },
+ { RT5631_PSEUDO_SPATL_CTRL, 0x0553 },
};
/**
@@ -96,8 +97,7 @@ static int rt5631_reset(struct snd_soc_codec *codec)
return snd_soc_write(codec, RT5631_RESET, 0);
}
-static int rt5631_volatile_register(struct snd_soc_codec *codec,
- unsigned int reg)
+static bool rt5631_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case RT5631_RESET:
@@ -111,8 +111,7 @@ static int rt5631_volatile_register(struct snd_soc_codec *codec,
}
}
-static int rt5631_readable_register(struct snd_soc_codec *codec,
- unsigned int reg)
+static bool rt5631_readable_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case RT5631_RESET:
@@ -1361,8 +1360,7 @@ static int get_coeff(int mclk, int rate, int timesofbclk)
static int rt5631_hifi_pcm_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
int timesofbclk = 32, coeff;
unsigned int iface = 0;
@@ -1544,6 +1542,8 @@ static int rt5631_codec_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
static int rt5631_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
+ struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
+
switch (level) {
case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE:
@@ -1561,8 +1561,8 @@ static int rt5631_set_bias_level(struct snd_soc_codec *codec,
snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3,
RT5631_PWR_FAST_VREF_CTRL,
RT5631_PWR_FAST_VREF_CTRL);
- codec->cache_only = false;
- snd_soc_cache_sync(codec);
+ regcache_cache_only(rt5631->regmap, false);
+ regcache_sync(rt5631->regmap);
}
break;
@@ -1587,7 +1587,9 @@ static int rt5631_probe(struct snd_soc_codec *codec)
unsigned int val;
int ret;
- ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
+ codec->control_data = rt5631->regmap;
+
+ ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
@@ -1698,12 +1700,6 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5631 = {
.suspend = rt5631_suspend,
.resume = rt5631_resume,
.set_bias_level = rt5631_set_bias_level,
- .reg_cache_size = RT5631_VENDOR_ID2 + 1,
- .reg_word_size = sizeof(u16),
- .reg_cache_default = rt5631_reg,
- .volatile_register = rt5631_volatile_register,
- .readable_register = rt5631_readable_register,
- .reg_cache_step = 1,
.controls = rt5631_snd_controls,
.num_controls = ARRAY_SIZE(rt5631_snd_controls),
.dapm_widgets = rt5631_dapm_widgets,
@@ -1718,6 +1714,18 @@ static const struct i2c_device_id rt5631_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, rt5631_i2c_id);
+static const struct regmap_config rt5631_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+
+ .readable_reg = rt5631_readable_register,
+ .volatile_reg = rt5631_volatile_register,
+ .max_register = RT5631_VENDOR_ID2,
+ .reg_defaults = rt5631_reg,
+ .num_reg_defaults = ARRAY_SIZE(rt5631_reg),
+ .cache_type = REGCACHE_RBTREE,
+};
+
static int rt5631_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -1731,6 +1739,10 @@ static int rt5631_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, rt5631);
+ rt5631->regmap = devm_regmap_init_i2c(i2c, &rt5631_regmap_config);
+ if (IS_ERR(rt5631->regmap))
+ return PTR_ERR(rt5631->regmap);
+
ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5631,
rt5631_dai, ARRAY_SIZE(rt5631_dai));
return ret;
@@ -1752,17 +1764,7 @@ static struct i2c_driver rt5631_i2c_driver = {
.id_table = rt5631_i2c_id,
};
-static int __init rt5631_modinit(void)
-{
- return i2c_add_driver(&rt5631_i2c_driver);
-}
-module_init(rt5631_modinit);
-
-static void __exit rt5631_modexit(void)
-{
- i2c_del_driver(&rt5631_i2c_driver);
-}
-module_exit(rt5631_modexit);
+module_i2c_driver(rt5631_i2c_driver);
MODULE_DESCRIPTION("ASoC RT5631 driver");
MODULE_AUTHOR("flove <flove@realtek.com>");
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index c395ec370445..8af6a5245b18 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -84,8 +84,8 @@ static struct regulator_consumer_supply ldo_consumer[] = {
static struct regulator_init_data ldo_init_data = {
.constraints = {
- .min_uV = 850000,
- .max_uV = 1600000,
+ .min_uV = 1200000,
+ .max_uV = 1200000,
.valid_modes_mask = REGULATOR_MODE_NORMAL,
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
@@ -197,9 +197,9 @@ static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("HP_OUT"),
SND_SOC_DAPM_OUTPUT("LINE_OUT"),
- SND_SOC_DAPM_MICBIAS_E("Mic Bias", SGTL5000_CHIP_MIC_CTRL, 8, 0,
- mic_bias_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("Mic Bias", SGTL5000_CHIP_MIC_CTRL, 8, 0,
+ mic_bias_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_PGA("HP", SGTL5000_CHIP_ANA_POWER, 4, 0, NULL, 0),
SND_SOC_DAPM_PGA("LO", SGTL5000_CHIP_ANA_POWER, 0, 0, NULL, 0),
@@ -665,8 +665,7 @@ static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
int channels = params_channels(params);
int i2s_ctl = 0;
@@ -1455,17 +1454,7 @@ static struct i2c_driver sgtl5000_i2c_driver = {
.id_table = sgtl5000_id,
};
-static int __init sgtl5000_modinit(void)
-{
- return i2c_add_driver(&sgtl5000_i2c_driver);
-}
-module_init(sgtl5000_modinit);
-
-static void __exit sgtl5000_exit(void)
-{
- i2c_del_driver(&sgtl5000_i2c_driver);
-}
-module_exit(sgtl5000_exit);
+module_i2c_driver(sgtl5000_i2c_driver);
MODULE_DESCRIPTION("Freescale SGTL5000 ALSA SoC Codec Driver");
MODULE_AUTHOR("Zeng Zhaoming <zengzm.kernel@gmail.com>");
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index de2b20544ceb..079066fef425 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -33,6 +33,7 @@
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/spi/spi.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -43,8 +44,6 @@
#include "ssm2602.h"
-#define SSM2602_VERSION "0.1"
-
enum ssm2602_type {
SSM2602,
SSM2604,
@@ -53,10 +52,12 @@ enum ssm2602_type {
/* codec private data */
struct ssm2602_priv {
unsigned int sysclk;
- enum snd_soc_control_type control_type;
+ struct snd_pcm_hw_constraint_list *sysclk_constraints;
struct snd_pcm_substream *master_substream;
struct snd_pcm_substream *slave_substream;
+ struct regmap *regmap;
+
enum ssm2602_type type;
unsigned int clk_out_pwr;
};
@@ -73,7 +74,6 @@ static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = {
0x0000, 0x0000
};
-#define ssm2602_reset(c) snd_soc_write(c, SSM2602_RESET, 0)
/*Appending several "None"s just for OSS mixer use*/
static const char *ssm2602_input_select[] = {
@@ -195,6 +195,24 @@ static const struct snd_soc_dapm_route ssm2604_routes[] = {
{"ADC", NULL, "Line Input"},
};
+static const unsigned int ssm2602_rates_12288000[] = {
+ 8000, 32000, 48000, 96000,
+};
+
+static struct snd_pcm_hw_constraint_list ssm2602_constraints_12288000 = {
+ .list = ssm2602_rates_12288000,
+ .count = ARRAY_SIZE(ssm2602_rates_12288000),
+};
+
+static const unsigned int ssm2602_rates_11289600[] = {
+ 8000, 44100, 88200,
+};
+
+static struct snd_pcm_hw_constraint_list ssm2602_constraints_11289600 = {
+ .list = ssm2602_rates_11289600,
+ .count = ARRAY_SIZE(ssm2602_rates_11289600),
+};
+
struct ssm2602_coeff {
u32 mclk;
u32 rate;
@@ -254,11 +272,10 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
- u16 iface = snd_soc_read(codec, SSM2602_IFACE) & 0xfff3;
int srate = ssm2602_get_coeff(ssm2602->sysclk, params_rate(params));
+ unsigned int iface;
if (substream == ssm2602->slave_substream) {
dev_dbg(codec->dev, "Ignoring hw_params for slave substream\n");
@@ -268,31 +285,34 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
if (srate < 0)
return srate;
- snd_soc_write(codec, SSM2602_SRATE, srate);
+ regmap_write(ssm2602->regmap, SSM2602_SRATE, srate);
/* bit size */
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
+ iface = 0x0;
break;
case SNDRV_PCM_FORMAT_S20_3LE:
- iface |= 0x0004;
+ iface = 0x4;
break;
case SNDRV_PCM_FORMAT_S24_LE:
- iface |= 0x0008;
+ iface = 0x8;
break;
case SNDRV_PCM_FORMAT_S32_LE:
- iface |= 0x000c;
+ iface = 0xc;
break;
+ default:
+ return -EINVAL;
}
- snd_soc_write(codec, SSM2602_IFACE, iface);
+ regmap_update_bits(ssm2602->regmap, SSM2602_IFACE,
+ IFACE_AUDIO_DATA_LEN, iface);
return 0;
}
static int ssm2602_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
struct snd_pcm_runtime *master_runtime;
@@ -322,14 +342,19 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
} else
ssm2602->master_substream = substream;
+ if (ssm2602->sysclk_constraints) {
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ ssm2602->sysclk_constraints);
+ }
+
return 0;
}
static void ssm2602_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
if (ssm2602->master_substream == substream)
@@ -341,14 +366,14 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream,
static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
{
- struct snd_soc_codec *codec = dai->codec;
+ struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(dai->codec);
if (mute)
- snd_soc_update_bits(codec, SSM2602_APDIGI,
+ regmap_update_bits(ssm2602->regmap, SSM2602_APDIGI,
APDIGI_ENABLE_DAC_MUTE,
APDIGI_ENABLE_DAC_MUTE);
else
- snd_soc_update_bits(codec, SSM2602_APDIGI,
+ regmap_update_bits(ssm2602->regmap, SSM2602_APDIGI,
APDIGI_ENABLE_DAC_MUTE, 0);
return 0;
}
@@ -364,16 +389,21 @@ static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai,
return -EINVAL;
switch (freq) {
- case 11289600:
- case 12000000:
case 12288000:
- case 16934400:
case 18432000:
- ssm2602->sysclk = freq;
+ ssm2602->sysclk_constraints = &ssm2602_constraints_12288000;
+ break;
+ case 11289600:
+ case 16934400:
+ ssm2602->sysclk_constraints = &ssm2602_constraints_11289600;
+ break;
+ case 12000000:
+ ssm2602->sysclk_constraints = NULL;
break;
default:
return -EINVAL;
}
+ ssm2602->sysclk = freq;
} else {
unsigned int mask;
@@ -393,7 +423,7 @@ static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai,
else
ssm2602->clk_out_pwr &= ~mask;
- snd_soc_update_bits(codec, SSM2602_PWR,
+ regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
PWR_CLK_OUT_PDN | PWR_OSC_PDN, ssm2602->clk_out_pwr);
}
@@ -403,8 +433,8 @@ static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai,
static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
- struct snd_soc_codec *codec = codec_dai->codec;
- u16 iface = 0;
+ struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec_dai->codec);
+ unsigned int iface = 0;
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -455,7 +485,7 @@ static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
}
/* set iface */
- snd_soc_write(codec, SSM2602_IFACE, iface);
+ regmap_write(ssm2602->regmap, SSM2602_IFACE, iface);
return 0;
}
@@ -467,7 +497,7 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
switch (level) {
case SND_SOC_BIAS_ON:
/* vref/mid on, osc and clkout on if enabled */
- snd_soc_update_bits(codec, SSM2602_PWR,
+ regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN,
ssm2602->clk_out_pwr);
break;
@@ -475,13 +505,13 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
/* everything off except vref/vmid, */
- snd_soc_update_bits(codec, SSM2602_PWR,
+ regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN,
PWR_CLK_OUT_PDN | PWR_OSC_PDN);
break;
case SND_SOC_BIAS_OFF:
/* everything off */
- snd_soc_update_bits(codec, SSM2602_PWR,
+ regmap_update_bits(ssm2602->regmap, SSM2602_PWR,
PWR_POWER_OFF, PWR_POWER_OFF);
break;
@@ -540,12 +570,13 @@ static int ssm2602_resume(struct snd_soc_codec *codec)
static int ssm2602_probe(struct snd_soc_codec *codec)
{
+ struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret;
- snd_soc_update_bits(codec, SSM2602_LOUT1V,
+ regmap_update_bits(ssm2602->regmap, SSM2602_LOUT1V,
LOUT1V_LRHP_BOTH, LOUT1V_LRHP_BOTH);
- snd_soc_update_bits(codec, SSM2602_ROUT1V,
+ regmap_update_bits(ssm2602->regmap, SSM2602_ROUT1V,
ROUT1V_RLHP_BOTH, ROUT1V_RLHP_BOTH);
ret = snd_soc_add_codec_controls(codec, ssm2602_snd_controls,
@@ -581,27 +612,26 @@ static int ssm260x_probe(struct snd_soc_codec *codec)
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
int ret;
- pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
-
- ret = snd_soc_codec_set_cache_io(codec, 7, 9, ssm2602->control_type);
+ codec->control_data = ssm2602->regmap;
+ ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
}
- ret = ssm2602_reset(codec);
+ ret = regmap_write(ssm2602->regmap, SSM2602_RESET, 0);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
return ret;
}
/* set the update bits */
- snd_soc_update_bits(codec, SSM2602_LINVOL,
+ regmap_update_bits(ssm2602->regmap, SSM2602_LINVOL,
LINVOL_LRIN_BOTH, LINVOL_LRIN_BOTH);
- snd_soc_update_bits(codec, SSM2602_RINVOL,
+ regmap_update_bits(ssm2602->regmap, SSM2602_RINVOL,
RINVOL_RLIN_BOTH, RINVOL_RLIN_BOTH);
/*select Line in as default input*/
- snd_soc_write(codec, SSM2602_APANA, APANA_SELECT_DAC |
+ regmap_write(ssm2602->regmap, SSM2602_APANA, APANA_SELECT_DAC |
APANA_ENABLE_MIC_BOOST);
switch (ssm2602->type) {
@@ -634,9 +664,6 @@ static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
.suspend = ssm2602_suspend,
.resume = ssm2602_resume,
.set_bias_level = ssm2602_set_bias_level,
- .reg_cache_size = ARRAY_SIZE(ssm2602_reg),
- .reg_word_size = sizeof(u16),
- .reg_cache_default = ssm2602_reg,
.controls = ssm260x_snd_controls,
.num_controls = ARRAY_SIZE(ssm260x_snd_controls),
@@ -646,6 +673,23 @@ static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = {
.num_dapm_routes = ARRAY_SIZE(ssm260x_routes),
};
+static bool ssm2602_register_volatile(struct device *dev, unsigned int reg)
+{
+ return reg == SSM2602_RESET;
+}
+
+static const struct regmap_config ssm2602_regmap_config = {
+ .val_bits = 9,
+ .reg_bits = 7,
+
+ .max_register = SSM2602_RESET,
+ .volatile_reg = ssm2602_register_volatile,
+
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults_raw = ssm2602_reg,
+ .num_reg_defaults_raw = ARRAY_SIZE(ssm2602_reg),
+};
+
#if defined(CONFIG_SPI_MASTER)
static int __devinit ssm2602_spi_probe(struct spi_device *spi)
{
@@ -658,9 +702,12 @@ static int __devinit ssm2602_spi_probe(struct spi_device *spi)
return -ENOMEM;
spi_set_drvdata(spi, ssm2602);
- ssm2602->control_type = SND_SOC_SPI;
ssm2602->type = SSM2602;
+ ssm2602->regmap = devm_regmap_init_spi(spi, &ssm2602_regmap_config);
+ if (IS_ERR(ssm2602->regmap))
+ return PTR_ERR(ssm2602->regmap);
+
ret = snd_soc_register_codec(&spi->dev,
&soc_codec_dev_ssm2602, &ssm2602_dai, 1);
return ret;
@@ -701,9 +748,12 @@ static int __devinit ssm2602_i2c_probe(struct i2c_client *i2c,
return -ENOMEM;
i2c_set_clientdata(i2c, ssm2602);
- ssm2602->control_type = SND_SOC_I2C;
ssm2602->type = id->driver_data;
+ ssm2602->regmap = devm_regmap_init_i2c(i2c, &ssm2602_regmap_config);
+ if (IS_ERR(ssm2602->regmap))
+ return PTR_ERR(ssm2602->regmap);
+
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_ssm2602, &ssm2602_dai, 1);
return ret;
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index 7db6fa515028..8d717f4b5a87 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -609,8 +609,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
unsigned int rate;
int i, mcs = -1, ir = -1;
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index df1e07ffac32..31762ebdd774 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -34,8 +34,6 @@
#include "tlv320aic23.h"
-#define AIC23_VERSION "0.1"
-
/*
* AIC23 register cache
*/
@@ -325,8 +323,7 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
u16 iface_reg;
int ret;
struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
@@ -371,8 +368,7 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
/* set active */
snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0001);
@@ -383,8 +379,7 @@ static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream,
static void tlv320aic23_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
/* deactivate */
@@ -548,8 +543,6 @@ static int tlv320aic23_probe(struct snd_soc_codec *codec)
struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
int ret;
- printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
-
ret = snd_soc_codec_set_cache_io(codec, 7, 9, aic23->control_type);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c
index 802064b5030d..85944e953578 100644
--- a/sound/soc/codecs/tlv320aic26.c
+++ b/sound/soc/codecs/tlv320aic26.c
@@ -126,8 +126,7 @@ static int aic26_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
int fsref, divisor, wlen, pval, jval, dval, qval;
u16 reg;
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 8d20f6ec20f3..64d2a4fa34b2 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -802,8 +802,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec =rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
@@ -1161,24 +1160,6 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-void aic3x_set_headset_detection(struct snd_soc_codec *codec, int detect,
- int headset_debounce, int button_debounce)
-{
- u8 val;
-
- val = ((detect & AIC3X_HEADSET_DETECT_MASK)
- << AIC3X_HEADSET_DETECT_SHIFT) |
- ((headset_debounce & AIC3X_HEADSET_DEBOUNCE_MASK)
- << AIC3X_HEADSET_DEBOUNCE_SHIFT) |
- ((button_debounce & AIC3X_BUTTON_DEBOUNCE_MASK)
- << AIC3X_BUTTON_DEBOUNCE_SHIFT);
-
- if (detect & AIC3X_HEADSET_DETECT_MASK)
- val |= AIC3X_HEADSET_DETECT_ENABLED;
-
- snd_soc_write(codec, AIC3X_HEADSET_DETECT_CTRL_A, val);
-}
-
#define AIC3X_RATES SNDRV_PCM_RATE_8000_96000
#define AIC3X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 4587ddd0fbf8..0dd41077ab79 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -62,8 +62,10 @@
#define UTHR_FROM_PERIOD_SIZE(samples, playrate, burstrate) \
(((samples)*5000) / (((burstrate)*5000) / ((burstrate) - (playrate))))
-static void dac33_calculate_times(struct snd_pcm_substream *substream);
-static int dac33_prepare_chip(struct snd_pcm_substream *substream);
+static void dac33_calculate_times(struct snd_pcm_substream *substream,
+ struct snd_soc_codec *codec);
+static int dac33_prepare_chip(struct snd_pcm_substream *substream,
+ struct snd_soc_codec *codec);
enum dac33_state {
DAC33_IDLE = 0,
@@ -427,8 +429,8 @@ static int dac33_playback_event(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
if (likely(dac33->substream)) {
- dac33_calculate_times(dac33->substream);
- dac33_prepare_chip(dac33->substream);
+ dac33_calculate_times(dac33->substream, w->codec);
+ dac33_prepare_chip(dac33->substream, w->codec);
}
break;
case SND_SOC_DAPM_POST_PMD:
@@ -799,8 +801,7 @@ static void dac33_oscwait(struct snd_soc_codec *codec)
static int dac33_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
/* Stream started, save the substream pointer */
@@ -812,8 +813,7 @@ static int dac33_startup(struct snd_pcm_substream *substream,
static void dac33_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
dac33->substream = NULL;
@@ -825,8 +825,7 @@ static int dac33_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
/* Check parameters for validity */
@@ -868,10 +867,9 @@ static int dac33_hw_params(struct snd_pcm_substream *substream,
* writes happens in different order, than dac33 might end up in unknown state.
* Use the known, working sequence of register writes to initialize the dac33.
*/
-static int dac33_prepare_chip(struct snd_pcm_substream *substream)
+static int dac33_prepare_chip(struct snd_pcm_substream *substream,
+ struct snd_soc_codec *codec)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
unsigned int oscset, ratioset, pwr_ctrl, reg_tmp;
u8 aictrl_a, aictrl_b, fifoctrl_a;
@@ -1067,10 +1065,9 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
return 0;
}
-static void dac33_calculate_times(struct snd_pcm_substream *substream)
+static void dac33_calculate_times(struct snd_pcm_substream *substream,
+ struct snd_soc_codec *codec)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
unsigned int period_size = substream->runtime->period_size;
unsigned int rate = substream->runtime->rate;
@@ -1128,8 +1125,7 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)
static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
@@ -1161,8 +1157,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
unsigned long long t0, t1, t_now;
unsigned int time_delta, uthr;
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 170cf9a8fc79..391fcfc7b63b 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -1685,8 +1685,7 @@ static void twl4030_tdm_enable(struct snd_soc_codec *codec, int direction,
static int twl4030_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
if (twl4030->master_substream) {
@@ -1715,8 +1714,7 @@ static int twl4030_startup(struct snd_pcm_substream *substream,
static void twl4030_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
if (twl4030->master_substream == substream)
@@ -1740,8 +1738,7 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
u8 mode, old_mode, format, old_format;
@@ -1974,8 +1971,7 @@ static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction,
static int twl4030_voice_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
u8 mode;
@@ -2007,8 +2003,7 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream,
static void twl4030_voice_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
/* Enable voice digital filters */
twl4030_voice_enable(codec, substream->stream, 0);
@@ -2017,8 +2012,7 @@ static void twl4030_voice_shutdown(struct snd_pcm_substream *substream,
static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
u8 old_mode, mode;
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index dc7509b9d53a..a36e9fcdf184 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -46,17 +46,6 @@
#define TWL6040_OUTHF_0dB 0x03
#define TWL6040_OUTHF_M52dB 0x1D
-#define TWL6040_RAMP_NONE 0
-#define TWL6040_RAMP_UP 1
-#define TWL6040_RAMP_DOWN 2
-
-#define TWL6040_HSL_VOL_MASK 0x0F
-#define TWL6040_HSL_VOL_SHIFT 0
-#define TWL6040_HSR_VOL_MASK 0xF0
-#define TWL6040_HSR_VOL_SHIFT 4
-#define TWL6040_HF_VOL_MASK 0x1F
-#define TWL6040_HF_VOL_SHIFT 0
-
/* Shadow register used by the driver */
#define TWL6040_REG_SW_SHADOW 0x2F
#define TWL6040_CACHEREGNUM (TWL6040_REG_SW_SHADOW + 1)
@@ -64,18 +53,6 @@
/* TWL6040_REG_SW_SHADOW (0x2F) fields */
#define TWL6040_EAR_PATH_ENABLE 0x01
-struct twl6040_output {
- u16 active;
- u16 left_vol;
- u16 right_vol;
- u16 left_step;
- u16 right_step;
- unsigned int step_delay;
- u16 ramp;
- struct delayed_work work;
- struct completion ramp_done;
-};
-
struct twl6040_jack_data {
struct snd_soc_jack *jack;
struct delayed_work work;
@@ -100,8 +77,6 @@ struct twl6040_data {
struct snd_soc_codec *codec;
struct workqueue_struct *workqueue;
struct mutex mutex;
- struct twl6040_output headset;
- struct twl6040_output handsfree;
};
/*
@@ -311,318 +286,6 @@ static void twl6040_restore_regs(struct snd_soc_codec *codec)
}
}
-/*
- * Ramp HS PGA volume to minimise pops at stream startup and shutdown.
- */
-static inline int twl6040_hs_ramp_step(struct snd_soc_codec *codec,
- unsigned int left_step, unsigned int right_step)
-{
-
- struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
- struct twl6040_output *headset = &priv->headset;
- int left_complete = 0, right_complete = 0;
- u8 reg, val;
-
- /* left channel */
- left_step = (left_step > 0xF) ? 0xF : left_step;
- reg = twl6040_read_reg_cache(codec, TWL6040_REG_HSGAIN);
- val = (~reg & TWL6040_HSL_VOL_MASK);
-
- if (headset->ramp == TWL6040_RAMP_UP) {
- /* ramp step up */
- if (val < headset->left_vol) {
- if (val + left_step > headset->left_vol)
- val = headset->left_vol;
- else
- val += left_step;
-
- reg &= ~TWL6040_HSL_VOL_MASK;
- twl6040_write(codec, TWL6040_REG_HSGAIN,
- (reg | (~val & TWL6040_HSL_VOL_MASK)));
- } else {
- left_complete = 1;
- }
- } else if (headset->ramp == TWL6040_RAMP_DOWN) {
- /* ramp step down */
- if (val > 0x0) {
- if ((int)val - (int)left_step < 0)
- val = 0;
- else
- val -= left_step;
-
- reg &= ~TWL6040_HSL_VOL_MASK;
- twl6040_write(codec, TWL6040_REG_HSGAIN, reg |
- (~val & TWL6040_HSL_VOL_MASK));
- } else {
- left_complete = 1;
- }
- }
-
- /* right channel */
- right_step = (right_step > 0xF) ? 0xF : right_step;
- reg = twl6040_read_reg_cache(codec, TWL6040_REG_HSGAIN);
- val = (~reg & TWL6040_HSR_VOL_MASK) >> TWL6040_HSR_VOL_SHIFT;
-
- if (headset->ramp == TWL6040_RAMP_UP) {
- /* ramp step up */
- if (val < headset->right_vol) {
- if (val + right_step > headset->right_vol)
- val = headset->right_vol;
- else
- val += right_step;
-
- reg &= ~TWL6040_HSR_VOL_MASK;
- twl6040_write(codec, TWL6040_REG_HSGAIN,
- (reg | (~val << TWL6040_HSR_VOL_SHIFT)));
- } else {
- right_complete = 1;
- }
- } else if (headset->ramp == TWL6040_RAMP_DOWN) {
- /* ramp step down */
- if (val > 0x0) {
- if ((int)val - (int)right_step < 0)
- val = 0;
- else
- val -= right_step;
-
- reg &= ~TWL6040_HSR_VOL_MASK;
- twl6040_write(codec, TWL6040_REG_HSGAIN,
- reg | (~val << TWL6040_HSR_VOL_SHIFT));
- } else {
- right_complete = 1;
- }
- }
-
- return left_complete & right_complete;
-}
-
-/*
- * Ramp HF PGA volume to minimise pops at stream startup and shutdown.
- */
-static inline int twl6040_hf_ramp_step(struct snd_soc_codec *codec,
- unsigned int left_step, unsigned int right_step)
-{
- struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
- struct twl6040_output *handsfree = &priv->handsfree;
- int left_complete = 0, right_complete = 0;
- u16 reg, val;
-
- /* left channel */
- left_step = (left_step > 0x1D) ? 0x1D : left_step;
- reg = twl6040_read_reg_cache(codec, TWL6040_REG_HFLGAIN);
- reg = 0x1D - reg;
- val = (reg & TWL6040_HF_VOL_MASK);
- if (handsfree->ramp == TWL6040_RAMP_UP) {
- /* ramp step up */
- if (val < handsfree->left_vol) {
- if (val + left_step > handsfree->left_vol)
- val = handsfree->left_vol;
- else
- val += left_step;
-
- reg &= ~TWL6040_HF_VOL_MASK;
- twl6040_write(codec, TWL6040_REG_HFLGAIN,
- reg | (0x1D - val));
- } else {
- left_complete = 1;
- }
- } else if (handsfree->ramp == TWL6040_RAMP_DOWN) {
- /* ramp step down */
- if (val > 0) {
- if ((int)val - (int)left_step < 0)
- val = 0;
- else
- val -= left_step;
-
- reg &= ~TWL6040_HF_VOL_MASK;
- twl6040_write(codec, TWL6040_REG_HFLGAIN,
- reg | (0x1D - val));
- } else {
- left_complete = 1;
- }
- }
-
- /* right channel */
- right_step = (right_step > 0x1D) ? 0x1D : right_step;
- reg = twl6040_read_reg_cache(codec, TWL6040_REG_HFRGAIN);
- reg = 0x1D - reg;
- val = (reg & TWL6040_HF_VOL_MASK);
- if (handsfree->ramp == TWL6040_RAMP_UP) {
- /* ramp step up */
- if (val < handsfree->right_vol) {
- if (val + right_step > handsfree->right_vol)
- val = handsfree->right_vol;
- else
- val += right_step;
-
- reg &= ~TWL6040_HF_VOL_MASK;
- twl6040_write(codec, TWL6040_REG_HFRGAIN,
- reg | (0x1D - val));
- } else {
- right_complete = 1;
- }
- } else if (handsfree->ramp == TWL6040_RAMP_DOWN) {
- /* ramp step down */
- if (val > 0) {
- if ((int)val - (int)right_step < 0)
- val = 0;
- else
- val -= right_step;
-
- reg &= ~TWL6040_HF_VOL_MASK;
- twl6040_write(codec, TWL6040_REG_HFRGAIN,
- reg | (0x1D - val));
- }
- }
-
- return left_complete & right_complete;
-}
-
-/*
- * This work ramps both output PGAs at stream start/stop time to
- * minimise pop associated with DAPM power switching.
- */
-static void twl6040_pga_hs_work(struct work_struct *work)
-{
- struct twl6040_data *priv =
- container_of(work, struct twl6040_data, headset.work.work);
- struct snd_soc_codec *codec = priv->codec;
- struct twl6040_output *headset = &priv->headset;
- int i, headset_complete;
-
- /* do we need to ramp at all ? */
- if (headset->ramp == TWL6040_RAMP_NONE)
- return;
-
- /* HS PGA gain range: 0x0 - 0xf (0 - 15) */
- for (i = 0; i < 16; i++) {
- headset_complete = twl6040_hs_ramp_step(codec,
- headset->left_step,
- headset->right_step);
-
- /* ramp finished ? */
- if (headset_complete)
- break;
-
- schedule_timeout_interruptible(
- msecs_to_jiffies(headset->step_delay));
- }
-
- if (headset->ramp == TWL6040_RAMP_DOWN) {
- headset->active = 0;
- complete(&headset->ramp_done);
- } else {
- headset->active = 1;
- }
- headset->ramp = TWL6040_RAMP_NONE;
-}
-
-static void twl6040_pga_hf_work(struct work_struct *work)
-{
- struct twl6040_data *priv =
- container_of(work, struct twl6040_data, handsfree.work.work);
- struct snd_soc_codec *codec = priv->codec;
- struct twl6040_output *handsfree = &priv->handsfree;
- int i, handsfree_complete;
-
- /* do we need to ramp at all ? */
- if (handsfree->ramp == TWL6040_RAMP_NONE)
- return;
-
- /*
- * HF PGA gain range: 0x00 - 0x1d (0 - 29) */
- for (i = 0; i < 30; i++) {
- handsfree_complete = twl6040_hf_ramp_step(codec,
- handsfree->left_step,
- handsfree->right_step);
-
- /* ramp finished ? */
- if (handsfree_complete)
- break;
-
- schedule_timeout_interruptible(
- msecs_to_jiffies(handsfree->step_delay));
- }
-
-
- if (handsfree->ramp == TWL6040_RAMP_DOWN) {
- handsfree->active = 0;
- complete(&handsfree->ramp_done);
- } else
- handsfree->active = 1;
- handsfree->ramp = TWL6040_RAMP_NONE;
-}
-
-static int out_drv_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = w->codec;
- struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
- struct twl6040_output *out;
- struct delayed_work *work;
-
- switch (w->shift) {
- case 2: /* Headset output driver */
- out = &priv->headset;
- work = &out->work;
- /*
- * Make sure, that we do not mess up variables for already
- * executing work.
- */
- cancel_delayed_work_sync(work);
-
- out->left_step = priv->hs_left_step;
- out->right_step = priv->hs_right_step;
- out->step_delay = 5; /* 5 ms between volume ramp steps */
- break;
- case 4: /* Handsfree output driver */
- out = &priv->handsfree;
- work = &out->work;
- /*
- * Make sure, that we do not mess up variables for already
- * executing work.
- */
- cancel_delayed_work_sync(work);
-
- out->left_step = priv->hf_left_step;
- out->right_step = priv->hf_right_step;
- out->step_delay = 5; /* 5 ms between volume ramp steps */
- break;
- default:
- return -1;
- }
-
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- if (out->active)
- break;
-
- /* don't use volume ramp for power-up */
- out->ramp = TWL6040_RAMP_UP;
- out->left_step = out->left_vol;
- out->right_step = out->right_vol;
-
- queue_delayed_work(priv->workqueue, work, msecs_to_jiffies(1));
- break;
-
- case SND_SOC_DAPM_PRE_PMD:
- if (!out->active)
- break;
-
- /* use volume ramp for power-down */
- out->ramp = TWL6040_RAMP_DOWN;
- INIT_COMPLETION(out->ramp_done);
-
- queue_delayed_work(priv->workqueue, work, msecs_to_jiffies(1));
-
- wait_for_completion_timeout(&out->ramp_done,
- msecs_to_jiffies(2000));
- break;
- }
-
- return 0;
-}
-
/* set headset dac and driver power mode */
static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
{
@@ -747,71 +410,6 @@ static irqreturn_t twl6040_audio_handler(int irq, void *data)
return IRQ_HANDLED;
}
-static int twl6040_put_volsw(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct twl6040_data *twl6040_priv = snd_soc_codec_get_drvdata(codec);
- struct twl6040_output *out = NULL;
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- int ret;
-
- /* For HS and HF we shadow the values and only actually write
- * them out when active in order to ensure the amplifier comes on
- * as quietly as possible. */
- switch (mc->reg) {
- case TWL6040_REG_HSGAIN:
- out = &twl6040_priv->headset;
- break;
- case TWL6040_REG_HFLGAIN:
- out = &twl6040_priv->handsfree;
- break;
- default:
- dev_warn(codec->dev, "%s: Unexpected register: 0x%02x\n",
- __func__, mc->reg);
- return -EINVAL;
- }
-
- out->left_vol = ucontrol->value.integer.value[0];
- out->right_vol = ucontrol->value.integer.value[1];
- if (!out->active)
- return 1;
-
- ret = snd_soc_put_volsw(kcontrol, ucontrol);
- if (ret < 0)
- return ret;
-
- return 1;
-}
-
-static int twl6040_get_volsw(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- struct twl6040_data *twl6040_priv = snd_soc_codec_get_drvdata(codec);
- struct twl6040_output *out = &twl6040_priv->headset;
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
-
- switch (mc->reg) {
- case TWL6040_REG_HSGAIN:
- out = &twl6040_priv->headset;
- break;
- case TWL6040_REG_HFLGAIN:
- out = &twl6040_priv->handsfree;
- break;
- default:
- dev_warn(codec->dev, "%s: Unexpected register: 0x%02x\n",
- __func__, mc->reg);
- return -EINVAL;
- }
-
- ucontrol->value.integer.value[0] = out->left_vol;
- ucontrol->value.integer.value[1] = out->right_vol;
- return 0;
-}
-
static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1076,12 +674,10 @@ static const struct snd_kcontrol_new twl6040_snd_controls[] = {
TWL6040_REG_LINEGAIN, 0, 3, 7, 0, afm_amp_tlv),
/* Playback gains */
- SOC_DOUBLE_EXT_TLV("Headset Playback Volume",
- TWL6040_REG_HSGAIN, 0, 4, 0xF, 1, twl6040_get_volsw,
- twl6040_put_volsw, hs_tlv),
- SOC_DOUBLE_R_EXT_TLV("Handsfree Playback Volume",
- TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1,
- twl6040_get_volsw, twl6040_put_volsw, hf_tlv),
+ SOC_DOUBLE_TLV("Headset Playback Volume",
+ TWL6040_REG_HSGAIN, 0, 4, 0xF, 1, hs_tlv),
+ SOC_DOUBLE_R_TLV("Handsfree Playback Volume",
+ TWL6040_REG_HFLGAIN, TWL6040_REG_HFRGAIN, 0, 0x1D, 1, hf_tlv),
SOC_SINGLE_TLV("Earphone Playback Volume",
TWL6040_REG_EARCTL, 1, 0xF, 1, ep_tlv),
@@ -1180,22 +776,14 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
&auxr_switch_control),
/* Analog playback drivers */
- SND_SOC_DAPM_OUT_DRV_E("HF Left Driver",
- TWL6040_REG_HFLCTL, 4, 0, NULL, 0,
- out_drv_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
- SND_SOC_DAPM_OUT_DRV_E("HF Right Driver",
- TWL6040_REG_HFRCTL, 4, 0, NULL, 0,
- out_drv_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
- SND_SOC_DAPM_OUT_DRV_E("HS Left Driver",
- TWL6040_REG_HSLCTL, 2, 0, NULL, 0,
- out_drv_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
- SND_SOC_DAPM_OUT_DRV_E("HS Right Driver",
- TWL6040_REG_HSRCTL, 2, 0, NULL, 0,
- out_drv_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_OUT_DRV("HF Left Driver",
+ TWL6040_REG_HFLCTL, 4, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("HF Right Driver",
+ TWL6040_REG_HFRCTL, 4, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("HS Left Driver",
+ TWL6040_REG_HSLCTL, 2, 0, NULL, 0),
+ SND_SOC_DAPM_OUT_DRV("HS Right Driver",
+ TWL6040_REG_HSRCTL, 2, 0, NULL, 0),
SND_SOC_DAPM_OUT_DRV_E("Earphone Driver",
TWL6040_REG_EARCTL, 0, 0, NULL, 0,
twl6040_ep_drv_event,
@@ -1339,8 +927,7 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
static int twl6040_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
snd_pcm_hw_constraint_list(substream->runtime, 0,
@@ -1354,8 +941,7 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
int rate;
@@ -1391,8 +977,7 @@ static int twl6040_hw_params(struct snd_pcm_substream *substream,
static int twl6040_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct twl6040 *twl6040 = codec->control_data;
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
int ret;
@@ -1570,14 +1155,9 @@ static int twl6040_probe(struct snd_soc_codec *codec)
}
INIT_DELAYED_WORK(&priv->hs_jack.work, twl6040_accessory_work);
- INIT_DELAYED_WORK(&priv->headset.work, twl6040_pga_hs_work);
- INIT_DELAYED_WORK(&priv->handsfree.work, twl6040_pga_hf_work);
mutex_init(&priv->mutex);
- init_completion(&priv->headset.ramp_done);
- init_completion(&priv->handsfree.ramp_done);
-
ret = request_threaded_irq(priv->plug_irq, NULL, twl6040_audio_handler,
0, "twl6040_irq_plug", codec);
if (ret) {
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index 797b0dde2c68..6c3d43b8ee85 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -159,8 +159,7 @@ static int uda134x_mute(struct snd_soc_dai *dai, int mute)
static int uda134x_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec =rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
struct snd_pcm_runtime *master_runtime;
@@ -191,8 +190,7 @@ static int uda134x_startup(struct snd_pcm_substream *substream,
static void uda134x_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
if (uda134x->master_substream == substream)
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index 4f1b23d7e404..2502214b84ab 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -502,8 +502,7 @@ static int uda1380_set_dai_fmt_capture(struct snd_soc_dai *codec_dai,
static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
int mixer = uda1380_read_reg_cache(codec, UDA1380_MIXER);
@@ -528,8 +527,7 @@ static int uda1380_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
u16 clk = uda1380_read_reg_cache(codec, UDA1380_CLK);
/* set WSPLL power and divider if running from this clock */
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
index 3d868dc40092..7b24d6d192e1 100644
--- a/sound/soc/codecs/wl1273.c
+++ b/sound/soc/codecs/wl1273.c
@@ -293,8 +293,7 @@ static const struct snd_kcontrol_new wl1273_controls[] = {
static int wl1273_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(codec);
switch (wl1273->mode) {
@@ -329,8 +328,7 @@ static int wl1273_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(rtd->codec);
+ struct wl1273_priv *wl1273 = snd_soc_codec_get_drvdata(dai->codec);
struct wl1273_core *core = wl1273->core;
unsigned int rate, width, r;
diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c
index aefb4f89be0e..e0b51e9f8b12 100644
--- a/sound/soc/codecs/wm1250-ev1.c
+++ b/sound/soc/codecs/wm1250-ev1.c
@@ -79,22 +79,65 @@ static const struct snd_soc_dapm_route wm1250_ev1_dapm_routes[] = {
{ "WM1250 Output", NULL, "DAC" },
};
+static int wm1250_ev1_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct wm1250_priv *wm1250 = snd_soc_codec_get_drvdata(dai->codec);
+
+ switch (params_rate(params)) {
+ case 8000:
+ gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio,
+ 1);
+ gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio,
+ 1);
+ break;
+ case 16000:
+ gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio,
+ 0);
+ gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio,
+ 1);
+ break;
+ case 32000:
+ gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio,
+ 1);
+ gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio,
+ 0);
+ break;
+ case 64000:
+ gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].gpio,
+ 0);
+ gpio_set_value(wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].gpio,
+ 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops wm1250_ev1_ops = {
+ .hw_params = wm1250_ev1_hw_params,
+};
+
static struct snd_soc_dai_driver wm1250_ev1_dai = {
.name = "wm1250-ev1",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
- .channels_max = 1,
+ .channels_max = 2,
.rates = SNDRV_PCM_RATE_8000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
- .channels_max = 1,
+ .channels_max = 2,
.rates = SNDRV_PCM_RATE_8000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
},
+ .ops = &wm1250_ev1_ops,
};
static struct snd_soc_codec_driver soc_codec_dev_wm1250_ev1 = {
@@ -215,23 +258,7 @@ static struct i2c_driver wm1250_ev1_i2c_driver = {
.id_table = wm1250_ev1_i2c_id,
};
-static int __init wm1250_ev1_modinit(void)
-{
- int ret = 0;
-
- ret = i2c_add_driver(&wm1250_ev1_i2c_driver);
- if (ret != 0)
- pr_err("Failed to register WM1250-EV1 I2C driver: %d\n", ret);
-
- return ret;
-}
-module_init(wm1250_ev1_modinit);
-
-static void __exit wm1250_ev1_exit(void)
-{
- i2c_del_driver(&wm1250_ev1_i2c_driver);
-}
-module_exit(wm1250_ev1_exit);
+module_i2c_driver(wm1250_ev1_i2c_driver);
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_DESCRIPTION("WM1250-EV1 audio I/O module driver");
diff --git a/sound/soc/codecs/wm5100-tables.c b/sound/soc/codecs/wm5100-tables.c
index 9a18fae68204..e167207a19cc 100644
--- a/sound/soc/codecs/wm5100-tables.c
+++ b/sound/soc/codecs/wm5100-tables.c
@@ -32,7 +32,18 @@ bool wm5100_volatile_register(struct device *dev, unsigned int reg)
case WM5100_MIC_DETECT_3:
return 1;
default:
- return 0;
+ if ((reg >= WM5100_DSP1_PM_0 && reg <= WM5100_DSP1_PM_1535) ||
+ (reg >= WM5100_DSP1_ZM_0 && reg <= WM5100_DSP1_ZM_2047) ||
+ (reg >= WM5100_DSP1_DM_0 && reg <= WM5100_DSP1_DM_511) ||
+ (reg >= WM5100_DSP2_PM_0 && reg <= WM5100_DSP2_PM_1535) ||
+ (reg >= WM5100_DSP2_ZM_0 && reg <= WM5100_DSP2_ZM_2047) ||
+ (reg >= WM5100_DSP2_DM_0 && reg <= WM5100_DSP2_DM_511) ||
+ (reg >= WM5100_DSP3_PM_0 && reg <= WM5100_DSP3_PM_1535) ||
+ (reg >= WM5100_DSP3_ZM_0 && reg <= WM5100_DSP3_ZM_2047) ||
+ (reg >= WM5100_DSP3_DM_0 && reg <= WM5100_DSP3_DM_511))
+ return 1;
+ else
+ return 0;
}
}
@@ -697,9 +708,110 @@ bool wm5100_readable_register(struct device *dev, unsigned int reg)
case WM5100_HPLPF3_2:
case WM5100_HPLPF4_1:
case WM5100_HPLPF4_2:
+ case WM5100_DSP1_CONTROL_1:
+ case WM5100_DSP1_CONTROL_2:
+ case WM5100_DSP1_CONTROL_3:
+ case WM5100_DSP1_CONTROL_4:
+ case WM5100_DSP1_CONTROL_5:
+ case WM5100_DSP1_CONTROL_6:
+ case WM5100_DSP1_CONTROL_7:
+ case WM5100_DSP1_CONTROL_8:
+ case WM5100_DSP1_CONTROL_9:
+ case WM5100_DSP1_CONTROL_10:
+ case WM5100_DSP1_CONTROL_11:
+ case WM5100_DSP1_CONTROL_12:
+ case WM5100_DSP1_CONTROL_13:
+ case WM5100_DSP1_CONTROL_14:
+ case WM5100_DSP1_CONTROL_15:
+ case WM5100_DSP1_CONTROL_16:
+ case WM5100_DSP1_CONTROL_17:
+ case WM5100_DSP1_CONTROL_18:
+ case WM5100_DSP1_CONTROL_19:
+ case WM5100_DSP1_CONTROL_20:
+ case WM5100_DSP1_CONTROL_21:
+ case WM5100_DSP1_CONTROL_22:
+ case WM5100_DSP1_CONTROL_23:
+ case WM5100_DSP1_CONTROL_24:
+ case WM5100_DSP1_CONTROL_25:
+ case WM5100_DSP1_CONTROL_26:
+ case WM5100_DSP1_CONTROL_27:
+ case WM5100_DSP1_CONTROL_28:
+ case WM5100_DSP1_CONTROL_29:
+ case WM5100_DSP1_CONTROL_30:
+ case WM5100_DSP2_CONTROL_1:
+ case WM5100_DSP2_CONTROL_2:
+ case WM5100_DSP2_CONTROL_3:
+ case WM5100_DSP2_CONTROL_4:
+ case WM5100_DSP2_CONTROL_5:
+ case WM5100_DSP2_CONTROL_6:
+ case WM5100_DSP2_CONTROL_7:
+ case WM5100_DSP2_CONTROL_8:
+ case WM5100_DSP2_CONTROL_9:
+ case WM5100_DSP2_CONTROL_10:
+ case WM5100_DSP2_CONTROL_11:
+ case WM5100_DSP2_CONTROL_12:
+ case WM5100_DSP2_CONTROL_13:
+ case WM5100_DSP2_CONTROL_14:
+ case WM5100_DSP2_CONTROL_15:
+ case WM5100_DSP2_CONTROL_16:
+ case WM5100_DSP2_CONTROL_17:
+ case WM5100_DSP2_CONTROL_18:
+ case WM5100_DSP2_CONTROL_19:
+ case WM5100_DSP2_CONTROL_20:
+ case WM5100_DSP2_CONTROL_21:
+ case WM5100_DSP2_CONTROL_22:
+ case WM5100_DSP2_CONTROL_23:
+ case WM5100_DSP2_CONTROL_24:
+ case WM5100_DSP2_CONTROL_25:
+ case WM5100_DSP2_CONTROL_26:
+ case WM5100_DSP2_CONTROL_27:
+ case WM5100_DSP2_CONTROL_28:
+ case WM5100_DSP2_CONTROL_29:
+ case WM5100_DSP2_CONTROL_30:
+ case WM5100_DSP3_CONTROL_1:
+ case WM5100_DSP3_CONTROL_2:
+ case WM5100_DSP3_CONTROL_3:
+ case WM5100_DSP3_CONTROL_4:
+ case WM5100_DSP3_CONTROL_5:
+ case WM5100_DSP3_CONTROL_6:
+ case WM5100_DSP3_CONTROL_7:
+ case WM5100_DSP3_CONTROL_8:
+ case WM5100_DSP3_CONTROL_9:
+ case WM5100_DSP3_CONTROL_10:
+ case WM5100_DSP3_CONTROL_11:
+ case WM5100_DSP3_CONTROL_12:
+ case WM5100_DSP3_CONTROL_13:
+ case WM5100_DSP3_CONTROL_14:
+ case WM5100_DSP3_CONTROL_15:
+ case WM5100_DSP3_CONTROL_16:
+ case WM5100_DSP3_CONTROL_17:
+ case WM5100_DSP3_CONTROL_18:
+ case WM5100_DSP3_CONTROL_19:
+ case WM5100_DSP3_CONTROL_20:
+ case WM5100_DSP3_CONTROL_21:
+ case WM5100_DSP3_CONTROL_22:
+ case WM5100_DSP3_CONTROL_23:
+ case WM5100_DSP3_CONTROL_24:
+ case WM5100_DSP3_CONTROL_25:
+ case WM5100_DSP3_CONTROL_26:
+ case WM5100_DSP3_CONTROL_27:
+ case WM5100_DSP3_CONTROL_28:
+ case WM5100_DSP3_CONTROL_29:
+ case WM5100_DSP3_CONTROL_30:
return 1;
default:
- return 0;
+ if ((reg >= WM5100_DSP1_PM_0 && reg <= WM5100_DSP1_PM_1535) ||
+ (reg >= WM5100_DSP1_ZM_0 && reg <= WM5100_DSP1_ZM_2047) ||
+ (reg >= WM5100_DSP1_DM_0 && reg <= WM5100_DSP1_DM_511) ||
+ (reg >= WM5100_DSP2_PM_0 && reg <= WM5100_DSP2_PM_1535) ||
+ (reg >= WM5100_DSP2_ZM_0 && reg <= WM5100_DSP2_ZM_2047) ||
+ (reg >= WM5100_DSP2_DM_0 && reg <= WM5100_DSP2_DM_511) ||
+ (reg >= WM5100_DSP3_PM_0 && reg <= WM5100_DSP3_PM_1535) ||
+ (reg >= WM5100_DSP3_ZM_0 && reg <= WM5100_DSP3_ZM_2047) ||
+ (reg >= WM5100_DSP3_DM_0 && reg <= WM5100_DSP3_DM_511))
+ return 1;
+ else
+ return 0;
}
}
@@ -1361,4 +1473,13 @@ struct reg_default wm5100_reg_defaults[WM5100_REGISTER_COUNT] = {
{ 0x0EC9, 0x0000 }, /* R3785 - HPLPF3_2 */
{ 0x0ECC, 0x0000 }, /* R3788 - HPLPF4_1 */
{ 0x0ECD, 0x0000 }, /* R3789 - HPLPF4_2 */
+ { 0x0F02, 0x0000 }, /* R3842 - DSP1 Control 2 */
+ { 0x0F03, 0x0000 }, /* R3843 - DSP1 Control 3 */
+ { 0x0F04, 0x0000 }, /* R3844 - DSP1 Control 4 */
+ { 0x1002, 0x0000 }, /* R4098 - DSP2 Control 2 */
+ { 0x1003, 0x0000 }, /* R4099 - DSP2 Control 3 */
+ { 0x1004, 0x0000 }, /* R4100 - DSP2 Control 4 */
+ { 0x1102, 0x0000 }, /* R4354 - DSP3 Control 2 */
+ { 0x1103, 0x0000 }, /* R4355 - DSP3 Control 3 */
+ { 0x1104, 0x0000 }, /* R4356 - DSP3 Control 4 */
};
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index b9c185ce64e4..cb6d5372103a 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -1265,29 +1265,12 @@ static const __devinitdata struct reg_default wm5100_reva_patches[] = {
{ WM5100_AUDIO_IF_3_19, 1 },
};
-static int wm5100_dai_to_base(struct snd_soc_dai *dai)
-{
- switch (dai->id) {
- case 0:
- return WM5100_AUDIO_IF_1_1 - 1;
- case 1:
- return WM5100_AUDIO_IF_2_1 - 1;
- case 2:
- return WM5100_AUDIO_IF_3_1 - 1;
- default:
- BUG();
- return -EINVAL;
- }
-}
-
static int wm5100_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_codec *codec = dai->codec;
int lrclk, bclk, mask, base;
- base = wm5100_dai_to_base(dai);
- if (base < 0)
- return base;
+ base = dai->driver->base;
lrclk = 0;
bclk = 0;
@@ -1414,9 +1397,7 @@ static int wm5100_hw_params(struct snd_pcm_substream *substream,
int i, base, bclk, aif_rate, lrclk, wl, fl, sr;
int *bclk_rates;
- base = wm5100_dai_to_base(dai);
- if (base < 0)
- return base;
+ base = dai->driver->base;
/* Data sizes if not using TDM */
wl = snd_pcm_format_width(params_format(params));
@@ -1897,6 +1878,7 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
static struct snd_soc_dai_driver wm5100_dai[] = {
{
.name = "wm5100-aif1",
+ .base = WM5100_AUDIO_IF_1_1 - 1,
.playback = {
.stream_name = "AIF1 Playback",
.channels_min = 2,
@@ -1916,6 +1898,7 @@ static struct snd_soc_dai_driver wm5100_dai[] = {
{
.name = "wm5100-aif2",
.id = 1,
+ .base = WM5100_AUDIO_IF_2_1 - 1,
.playback = {
.stream_name = "AIF2 Playback",
.channels_min = 2,
@@ -1935,6 +1918,7 @@ static struct snd_soc_dai_driver wm5100_dai[] = {
{
.name = "wm5100-aif3",
.id = 2,
+ .base = WM5100_AUDIO_IF_3_1 - 1,
.playback = {
.stream_name = "AIF3 Playback",
.channels_min = 2,
@@ -2454,7 +2438,7 @@ static __devinit int wm5100_i2c_probe(struct i2c_client *i2c,
wm5100->dev = &i2c->dev;
- wm5100->regmap = regmap_init_i2c(i2c, &wm5100_regmap);
+ wm5100->regmap = devm_regmap_init_i2c(i2c, &wm5100_regmap);
if (IS_ERR(wm5100->regmap)) {
ret = PTR_ERR(wm5100->regmap);
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
@@ -2479,7 +2463,7 @@ static __devinit int wm5100_i2c_probe(struct i2c_client *i2c,
if (ret != 0) {
dev_err(&i2c->dev, "Failed to request core supplies: %d\n",
ret);
- goto err_regmap;
+ goto err;
}
ret = regulator_bulk_enable(ARRAY_SIZE(wm5100->core_supplies),
@@ -2487,7 +2471,7 @@ static __devinit int wm5100_i2c_probe(struct i2c_client *i2c,
if (ret != 0) {
dev_err(&i2c->dev, "Failed to enable core supplies: %d\n",
ret);
- goto err_regmap;
+ goto err;
}
if (wm5100->pdata.ldo_ena) {
@@ -2660,8 +2644,6 @@ err_ldo:
err_enable:
regulator_bulk_disable(ARRAY_SIZE(wm5100->core_supplies),
wm5100->core_supplies);
-err_regmap:
- regmap_exit(wm5100->regmap);
err:
return ret;
}
@@ -2682,7 +2664,6 @@ static __devexit int wm5100_i2c_remove(struct i2c_client *i2c)
gpio_set_value_cansleep(wm5100->pdata.ldo_ena, 0);
gpio_free(wm5100->pdata.ldo_ena);
}
- regmap_exit(wm5100->regmap);
return 0;
}
@@ -2749,17 +2730,7 @@ static struct i2c_driver wm5100_i2c_driver = {
.id_table = wm5100_i2c_id,
};
-static int __init wm5100_modinit(void)
-{
- return i2c_add_driver(&wm5100_i2c_driver);
-}
-module_init(wm5100_modinit);
-
-static void __exit wm5100_exit(void)
-{
- i2c_del_driver(&wm5100_i2c_driver);
-}
-module_exit(wm5100_exit);
+module_i2c_driver(wm5100_i2c_driver);
MODULE_DESCRIPTION("ASoC WM5100 driver");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
diff --git a/sound/soc/codecs/wm5100.h b/sound/soc/codecs/wm5100.h
index 25cb6016f9d7..935a9b7fb274 100644
--- a/sound/soc/codecs/wm5100.h
+++ b/sound/soc/codecs/wm5100.h
@@ -709,6 +709,96 @@ int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
#define WM5100_HPLPF3_2 0xEC9
#define WM5100_HPLPF4_1 0xECC
#define WM5100_HPLPF4_2 0xECD
+#define WM5100_DSP1_CONTROL_1 0xF00
+#define WM5100_DSP1_CONTROL_2 0xF02
+#define WM5100_DSP1_CONTROL_3 0xF03
+#define WM5100_DSP1_CONTROL_4 0xF04
+#define WM5100_DSP1_CONTROL_5 0xF06
+#define WM5100_DSP1_CONTROL_6 0xF07
+#define WM5100_DSP1_CONTROL_7 0xF08
+#define WM5100_DSP1_CONTROL_8 0xF09
+#define WM5100_DSP1_CONTROL_9 0xF0A
+#define WM5100_DSP1_CONTROL_10 0xF0B
+#define WM5100_DSP1_CONTROL_11 0xF0C
+#define WM5100_DSP1_CONTROL_12 0xF0D
+#define WM5100_DSP1_CONTROL_13 0xF0F
+#define WM5100_DSP1_CONTROL_14 0xF10
+#define WM5100_DSP1_CONTROL_15 0xF11
+#define WM5100_DSP1_CONTROL_16 0xF12
+#define WM5100_DSP1_CONTROL_17 0xF13
+#define WM5100_DSP1_CONTROL_18 0xF14
+#define WM5100_DSP1_CONTROL_19 0xF16
+#define WM5100_DSP1_CONTROL_20 0xF17
+#define WM5100_DSP1_CONTROL_21 0xF18
+#define WM5100_DSP1_CONTROL_22 0xF1A
+#define WM5100_DSP1_CONTROL_23 0xF1B
+#define WM5100_DSP1_CONTROL_24 0xF1C
+#define WM5100_DSP1_CONTROL_25 0xF1E
+#define WM5100_DSP1_CONTROL_26 0xF20
+#define WM5100_DSP1_CONTROL_27 0xF21
+#define WM5100_DSP1_CONTROL_28 0xF22
+#define WM5100_DSP1_CONTROL_29 0xF23
+#define WM5100_DSP1_CONTROL_30 0xF24
+#define WM5100_DSP2_CONTROL_1 0x1000
+#define WM5100_DSP2_CONTROL_2 0x1002
+#define WM5100_DSP2_CONTROL_3 0x1003
+#define WM5100_DSP2_CONTROL_4 0x1004
+#define WM5100_DSP2_CONTROL_5 0x1006
+#define WM5100_DSP2_CONTROL_6 0x1007
+#define WM5100_DSP2_CONTROL_7 0x1008
+#define WM5100_DSP2_CONTROL_8 0x1009
+#define WM5100_DSP2_CONTROL_9 0x100A
+#define WM5100_DSP2_CONTROL_10 0x100B
+#define WM5100_DSP2_CONTROL_11 0x100C
+#define WM5100_DSP2_CONTROL_12 0x100D
+#define WM5100_DSP2_CONTROL_13 0x100F
+#define WM5100_DSP2_CONTROL_14 0x1010
+#define WM5100_DSP2_CONTROL_15 0x1011
+#define WM5100_DSP2_CONTROL_16 0x1012
+#define WM5100_DSP2_CONTROL_17 0x1013
+#define WM5100_DSP2_CONTROL_18 0x1014
+#define WM5100_DSP2_CONTROL_19 0x1016
+#define WM5100_DSP2_CONTROL_20 0x1017
+#define WM5100_DSP2_CONTROL_21 0x1018
+#define WM5100_DSP2_CONTROL_22 0x101A
+#define WM5100_DSP2_CONTROL_23 0x101B
+#define WM5100_DSP2_CONTROL_24 0x101C
+#define WM5100_DSP2_CONTROL_25 0x101E
+#define WM5100_DSP2_CONTROL_26 0x1020
+#define WM5100_DSP2_CONTROL_27 0x1021
+#define WM5100_DSP2_CONTROL_28 0x1022
+#define WM5100_DSP2_CONTROL_29 0x1023
+#define WM5100_DSP2_CONTROL_30 0x1024
+#define WM5100_DSP3_CONTROL_1 0x1100
+#define WM5100_DSP3_CONTROL_2 0x1102
+#define WM5100_DSP3_CONTROL_3 0x1103
+#define WM5100_DSP3_CONTROL_4 0x1104
+#define WM5100_DSP3_CONTROL_5 0x1106
+#define WM5100_DSP3_CONTROL_6 0x1107
+#define WM5100_DSP3_CONTROL_7 0x1108
+#define WM5100_DSP3_CONTROL_8 0x1109
+#define WM5100_DSP3_CONTROL_9 0x110A
+#define WM5100_DSP3_CONTROL_10 0x110B
+#define WM5100_DSP3_CONTROL_11 0x110C
+#define WM5100_DSP3_CONTROL_12 0x110D
+#define WM5100_DSP3_CONTROL_13 0x110F
+#define WM5100_DSP3_CONTROL_14 0x1110
+#define WM5100_DSP3_CONTROL_15 0x1111
+#define WM5100_DSP3_CONTROL_16 0x1112
+#define WM5100_DSP3_CONTROL_17 0x1113
+#define WM5100_DSP3_CONTROL_18 0x1114
+#define WM5100_DSP3_CONTROL_19 0x1116
+#define WM5100_DSP3_CONTROL_20 0x1117
+#define WM5100_DSP3_CONTROL_21 0x1118
+#define WM5100_DSP3_CONTROL_22 0x111A
+#define WM5100_DSP3_CONTROL_23 0x111B
+#define WM5100_DSP3_CONTROL_24 0x111C
+#define WM5100_DSP3_CONTROL_25 0x111E
+#define WM5100_DSP3_CONTROL_26 0x1120
+#define WM5100_DSP3_CONTROL_27 0x1121
+#define WM5100_DSP3_CONTROL_28 0x1122
+#define WM5100_DSP3_CONTROL_29 0x1123
+#define WM5100_DSP3_CONTROL_30 0x1124
#define WM5100_DSP1_DM_0 0x4000
#define WM5100_DSP1_DM_1 0x4001
#define WM5100_DSP1_DM_2 0x4002
@@ -4561,6 +4651,75 @@ int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack);
#define WM5100_LHPF4_COEFF_WIDTH 16 /* LHPF4_COEFF - [15:0] */
/*
+ * R4132 (0x1024) - DSP2 Control 30
+ */
+#define WM5100_DSP2_RATE_MASK 0xC000 /* DSP2_RATE - [15:14] */
+#define WM5100_DSP2_RATE_SHIFT 14 /* DSP2_RATE - [15:14] */
+#define WM5100_DSP2_RATE_WIDTH 2 /* DSP2_RATE - [15:14] */
+#define WM5100_DSP2_DBG_CLK_ENA 0x0008 /* DSP2_DBG_CLK_ENA */
+#define WM5100_DSP2_DBG_CLK_ENA_MASK 0x0008 /* DSP2_DBG_CLK_ENA */
+#define WM5100_DSP2_DBG_CLK_ENA_SHIFT 3 /* DSP2_DBG_CLK_ENA */
+#define WM5100_DSP2_DBG_CLK_ENA_WIDTH 1 /* DSP2_DBG_CLK_ENA */
+#define WM5100_DSP2_SYS_ENA 0x0004 /* DSP2_SYS_ENA */
+#define WM5100_DSP2_SYS_ENA_MASK 0x0004 /* DSP2_SYS_ENA */
+#define WM5100_DSP2_SYS_ENA_SHIFT 2 /* DSP2_SYS_ENA */
+#define WM5100_DSP2_SYS_ENA_WIDTH 1 /* DSP2_SYS_ENA */
+#define WM5100_DSP2_CORE_ENA 0x0002 /* DSP2_CORE_ENA */
+#define WM5100_DSP2_CORE_ENA_MASK 0x0002 /* DSP2_CORE_ENA */
+#define WM5100_DSP2_CORE_ENA_SHIFT 1 /* DSP2_CORE_ENA */
+#define WM5100_DSP2_CORE_ENA_WIDTH 1 /* DSP2_CORE_ENA */
+#define WM5100_DSP2_START 0x0001 /* DSP2_START */
+#define WM5100_DSP2_START_MASK 0x0001 /* DSP2_START */
+#define WM5100_DSP2_START_SHIFT 0 /* DSP2_START */
+#define WM5100_DSP2_START_WIDTH 1 /* DSP2_START */
+
+/*
+ * R3876 (0xF24) - DSP1 Control 30
+ */
+#define WM5100_DSP1_RATE_MASK 0xC000 /* DSP1_RATE - [15:14] */
+#define WM5100_DSP1_RATE_SHIFT 14 /* DSP1_RATE - [15:14] */
+#define WM5100_DSP1_RATE_WIDTH 2 /* DSP1_RATE - [15:14] */
+#define WM5100_DSP1_DBG_CLK_ENA 0x0008 /* DSP1_DBG_CLK_ENA */
+#define WM5100_DSP1_DBG_CLK_ENA_MASK 0x0008 /* DSP1_DBG_CLK_ENA */
+#define WM5100_DSP1_DBG_CLK_ENA_SHIFT 3 /* DSP1_DBG_CLK_ENA */
+#define WM5100_DSP1_DBG_CLK_ENA_WIDTH 1 /* DSP1_DBG_CLK_ENA */
+#define WM5100_DSP1_SYS_ENA 0x0004 /* DSP1_SYS_ENA */
+#define WM5100_DSP1_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */
+#define WM5100_DSP1_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */
+#define WM5100_DSP1_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */
+#define WM5100_DSP1_CORE_ENA 0x0002 /* DSP1_CORE_ENA */
+#define WM5100_DSP1_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */
+#define WM5100_DSP1_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */
+#define WM5100_DSP1_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */
+#define WM5100_DSP1_START 0x0001 /* DSP1_START */
+#define WM5100_DSP1_START_MASK 0x0001 /* DSP1_START */
+#define WM5100_DSP1_START_SHIFT 0 /* DSP1_START */
+#define WM5100_DSP1_START_WIDTH 1 /* DSP1_START */
+
+/*
+ * R4388 (0x1124) - DSP3 Control 30
+ */
+#define WM5100_DSP3_RATE_MASK 0xC000 /* DSP3_RATE - [15:14] */
+#define WM5100_DSP3_RATE_SHIFT 14 /* DSP3_RATE - [15:14] */
+#define WM5100_DSP3_RATE_WIDTH 2 /* DSP3_RATE - [15:14] */
+#define WM5100_DSP3_DBG_CLK_ENA 0x0008 /* DSP3_DBG_CLK_ENA */
+#define WM5100_DSP3_DBG_CLK_ENA_MASK 0x0008 /* DSP3_DBG_CLK_ENA */
+#define WM5100_DSP3_DBG_CLK_ENA_SHIFT 3 /* DSP3_DBG_CLK_ENA */
+#define WM5100_DSP3_DBG_CLK_ENA_WIDTH 1 /* DSP3_DBG_CLK_ENA */
+#define WM5100_DSP3_SYS_ENA 0x0004 /* DSP3_SYS_ENA */
+#define WM5100_DSP3_SYS_ENA_MASK 0x0004 /* DSP3_SYS_ENA */
+#define WM5100_DSP3_SYS_ENA_SHIFT 2 /* DSP3_SYS_ENA */
+#define WM5100_DSP3_SYS_ENA_WIDTH 1 /* DSP3_SYS_ENA */
+#define WM5100_DSP3_CORE_ENA 0x0002 /* DSP3_CORE_ENA */
+#define WM5100_DSP3_CORE_ENA_MASK 0x0002 /* DSP3_CORE_ENA */
+#define WM5100_DSP3_CORE_ENA_SHIFT 1 /* DSP3_CORE_ENA */
+#define WM5100_DSP3_CORE_ENA_WIDTH 1 /* DSP3_CORE_ENA */
+#define WM5100_DSP3_START 0x0001 /* DSP3_START */
+#define WM5100_DSP3_START_MASK 0x0001 /* DSP3_START */
+#define WM5100_DSP3_START_SHIFT 0 /* DSP3_START */
+#define WM5100_DSP3_START_WIDTH 1 /* DSP3_START */
+
+/*
* R16384 (0x4000) - DSP1 DM 0
*/
#define WM5100_DSP1_DM_START_1_MASK 0x00FF /* DSP1_DM_START - [7:0] */
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index aa12c6b6beeb..555ee146ae0d 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -71,13 +71,6 @@ struct wm8350_data {
int fll_freq_in;
};
-static unsigned int wm8350_codec_cache_read(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- struct wm8350 *wm8350 = codec->control_data;
- return wm8350->reg_cache[reg];
-}
-
static unsigned int wm8350_codec_read(struct snd_soc_codec *codec,
unsigned int reg)
{
@@ -99,7 +92,7 @@ static inline int wm8350_out1_ramp_step(struct snd_soc_codec *codec)
{
struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
struct wm8350_output *out1 = &wm8350_data->out1;
- struct wm8350 *wm8350 = codec->control_data;
+ struct wm8350 *wm8350 = wm8350_data->wm8350;
int left_complete = 0, right_complete = 0;
u16 reg, val;
@@ -165,7 +158,7 @@ static inline int wm8350_out2_ramp_step(struct snd_soc_codec *codec)
{
struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
struct wm8350_output *out2 = &wm8350_data->out2;
- struct wm8350 *wm8350 = codec->control_data;
+ struct wm8350 *wm8350 = wm8350_data->wm8350;
int left_complete = 0, right_complete = 0;
u16 reg, val;
@@ -360,8 +353,8 @@ static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol,
return ret;
/* now hit the volume update bits (always bit 8) */
- val = wm8350_codec_read(codec, reg);
- wm8350_codec_write(codec, reg, val | WM8350_OUT1_VU);
+ val = snd_soc_read(codec, reg);
+ snd_soc_write(codec, reg, val | WM8350_OUT1_VU);
return 1;
}
@@ -781,7 +774,8 @@ static int wm8350_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = codec_dai->codec;
- struct wm8350 *wm8350 = codec->control_data;
+ struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
+ struct wm8350 *wm8350 = wm8350_data->wm8350;
u16 fll_4;
switch (clk_id) {
@@ -795,9 +789,9 @@ static int wm8350_set_dai_sysclk(struct snd_soc_dai *codec_dai,
case WM8350_MCLK_SEL_PLL_32K:
wm8350_set_bits(wm8350, WM8350_CLOCK_CONTROL_1,
WM8350_MCLK_SEL);
- fll_4 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_4) &
+ fll_4 = snd_soc_read(codec, WM8350_FLL_CONTROL_4) &
~WM8350_FLL_CLK_SRC_MASK;
- wm8350_codec_write(codec, WM8350_FLL_CONTROL_4, fll_4 | clk_id);
+ snd_soc_write(codec, WM8350_FLL_CONTROL_4, fll_4 | clk_id);
break;
}
@@ -819,39 +813,39 @@ static int wm8350_set_clkdiv(struct snd_soc_dai *codec_dai, int div_id, int div)
switch (div_id) {
case WM8350_ADC_CLKDIV:
- val = wm8350_codec_read(codec, WM8350_ADC_DIVIDER) &
+ val = snd_soc_read(codec, WM8350_ADC_DIVIDER) &
~WM8350_ADC_CLKDIV_MASK;
- wm8350_codec_write(codec, WM8350_ADC_DIVIDER, val | div);
+ snd_soc_write(codec, WM8350_ADC_DIVIDER, val | div);
break;
case WM8350_DAC_CLKDIV:
- val = wm8350_codec_read(codec, WM8350_DAC_CLOCK_CONTROL) &
+ val = snd_soc_read(codec, WM8350_DAC_CLOCK_CONTROL) &
~WM8350_DAC_CLKDIV_MASK;
- wm8350_codec_write(codec, WM8350_DAC_CLOCK_CONTROL, val | div);
+ snd_soc_write(codec, WM8350_DAC_CLOCK_CONTROL, val | div);
break;
case WM8350_BCLK_CLKDIV:
- val = wm8350_codec_read(codec, WM8350_CLOCK_CONTROL_1) &
+ val = snd_soc_read(codec, WM8350_CLOCK_CONTROL_1) &
~WM8350_BCLK_DIV_MASK;
- wm8350_codec_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
+ snd_soc_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
break;
case WM8350_OPCLK_CLKDIV:
- val = wm8350_codec_read(codec, WM8350_CLOCK_CONTROL_1) &
+ val = snd_soc_read(codec, WM8350_CLOCK_CONTROL_1) &
~WM8350_OPCLK_DIV_MASK;
- wm8350_codec_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
+ snd_soc_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
break;
case WM8350_SYS_CLKDIV:
- val = wm8350_codec_read(codec, WM8350_CLOCK_CONTROL_1) &
+ val = snd_soc_read(codec, WM8350_CLOCK_CONTROL_1) &
~WM8350_MCLK_DIV_MASK;
- wm8350_codec_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
+ snd_soc_write(codec, WM8350_CLOCK_CONTROL_1, val | div);
break;
case WM8350_DACLR_CLKDIV:
- val = wm8350_codec_read(codec, WM8350_DAC_LR_RATE) &
+ val = snd_soc_read(codec, WM8350_DAC_LR_RATE) &
~WM8350_DACLRC_RATE_MASK;
- wm8350_codec_write(codec, WM8350_DAC_LR_RATE, val | div);
+ snd_soc_write(codec, WM8350_DAC_LR_RATE, val | div);
break;
case WM8350_ADCLR_CLKDIV:
- val = wm8350_codec_read(codec, WM8350_ADC_LR_RATE) &
+ val = snd_soc_read(codec, WM8350_ADC_LR_RATE) &
~WM8350_ADCLRC_RATE_MASK;
- wm8350_codec_write(codec, WM8350_ADC_LR_RATE, val | div);
+ snd_soc_write(codec, WM8350_ADC_LR_RATE, val | div);
break;
default:
return -EINVAL;
@@ -863,13 +857,13 @@ static int wm8350_set_clkdiv(struct snd_soc_dai *codec_dai, int div_id, int div)
static int wm8350_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
- u16 iface = wm8350_codec_read(codec, WM8350_AI_FORMATING) &
+ u16 iface = snd_soc_read(codec, WM8350_AI_FORMATING) &
~(WM8350_AIF_BCLK_INV | WM8350_AIF_LRCLK_INV | WM8350_AIF_FMT_MASK);
- u16 master = wm8350_codec_read(codec, WM8350_AI_DAC_CONTROL) &
+ u16 master = snd_soc_read(codec, WM8350_AI_DAC_CONTROL) &
~WM8350_BCLK_MSTR;
- u16 dac_lrc = wm8350_codec_read(codec, WM8350_DAC_LR_RATE) &
+ u16 dac_lrc = snd_soc_read(codec, WM8350_DAC_LR_RATE) &
~WM8350_DACLRC_ENA;
- u16 adc_lrc = wm8350_codec_read(codec, WM8350_ADC_LR_RATE) &
+ u16 adc_lrc = snd_soc_read(codec, WM8350_ADC_LR_RATE) &
~WM8350_ADCLRC_ENA;
/* set master/slave audio interface */
@@ -922,42 +916,10 @@ static int wm8350_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
return -EINVAL;
}
- wm8350_codec_write(codec, WM8350_AI_FORMATING, iface);
- wm8350_codec_write(codec, WM8350_AI_DAC_CONTROL, master);
- wm8350_codec_write(codec, WM8350_DAC_LR_RATE, dac_lrc);
- wm8350_codec_write(codec, WM8350_ADC_LR_RATE, adc_lrc);
- return 0;
-}
-
-static int wm8350_pcm_trigger(struct snd_pcm_substream *substream,
- int cmd, struct snd_soc_dai *codec_dai)
-{
- struct snd_soc_codec *codec = codec_dai->codec;
- int master = wm8350_codec_cache_read(codec, WM8350_AI_DAC_CONTROL) &
- WM8350_BCLK_MSTR;
- int enabled = 0;
-
- /* Check that the DACs or ADCs are enabled since they are
- * required for LRC in master mode. The DACs or ADCs need a
- * valid audio path i.e. pin -> ADC or DAC -> pin before
- * the LRC will be enabled in master mode. */
- if (!master || cmd != SNDRV_PCM_TRIGGER_START)
- return 0;
-
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- enabled = wm8350_codec_cache_read(codec, WM8350_POWER_MGMT_4) &
- (WM8350_ADCR_ENA | WM8350_ADCL_ENA);
- } else {
- enabled = wm8350_codec_cache_read(codec, WM8350_POWER_MGMT_4) &
- (WM8350_DACR_ENA | WM8350_DACL_ENA);
- }
-
- if (!enabled) {
- dev_err(codec->dev,
- "%s: invalid audio path - no clocks available\n",
- __func__);
- return -EINVAL;
- }
+ snd_soc_write(codec, WM8350_AI_FORMATING, iface);
+ snd_soc_write(codec, WM8350_AI_DAC_CONTROL, master);
+ snd_soc_write(codec, WM8350_DAC_LR_RATE, dac_lrc);
+ snd_soc_write(codec, WM8350_ADC_LR_RATE, adc_lrc);
return 0;
}
@@ -966,8 +928,9 @@ static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *codec_dai)
{
struct snd_soc_codec *codec = codec_dai->codec;
- struct wm8350 *wm8350 = codec->control_data;
- u16 iface = wm8350_codec_read(codec, WM8350_AI_FORMATING) &
+ struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
+ struct wm8350 *wm8350 = wm8350_data->wm8350;
+ u16 iface = snd_soc_read(codec, WM8350_AI_FORMATING) &
~WM8350_AIF_WL_MASK;
/* bit size */
@@ -985,7 +948,7 @@ static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream,
break;
}
- wm8350_codec_write(codec, WM8350_AI_FORMATING, iface);
+ snd_soc_write(codec, WM8350_AI_FORMATING, iface);
/* The sloping stopband filter is recommended for use with
* lower sample rates to improve performance.
@@ -1005,12 +968,15 @@ static int wm8350_pcm_hw_params(struct snd_pcm_substream *substream,
static int wm8350_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
- struct wm8350 *wm8350 = codec->control_data;
+ unsigned int val;
if (mute)
- wm8350_set_bits(wm8350, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA);
+ val = WM8350_DAC_MUTE_ENA;
else
- wm8350_clear_bits(wm8350, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA);
+ val = 0;
+
+ snd_soc_update_bits(codec, WM8350_DAC_MUTE, WM8350_DAC_MUTE_ENA, val);
+
return 0;
}
@@ -1079,8 +1045,8 @@ static int wm8350_set_fll(struct snd_soc_dai *codec_dai,
unsigned int freq_out)
{
struct snd_soc_codec *codec = codec_dai->codec;
- struct wm8350 *wm8350 = codec->control_data;
struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
+ struct wm8350 *wm8350 = priv->wm8350;
struct _fll_div fll_div;
int ret = 0;
u16 fll_1, fll_4;
@@ -1104,17 +1070,17 @@ static int wm8350_set_fll(struct snd_soc_dai *codec_dai,
fll_div.ratio);
/* set up N.K & dividers */
- fll_1 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_1) &
+ fll_1 = snd_soc_read(codec, WM8350_FLL_CONTROL_1) &
~(WM8350_FLL_OUTDIV_MASK | WM8350_FLL_RSP_RATE_MASK | 0xc000);
- wm8350_codec_write(codec, WM8350_FLL_CONTROL_1,
+ snd_soc_write(codec, WM8350_FLL_CONTROL_1,
fll_1 | (fll_div.div << 8) | 0x50);
- wm8350_codec_write(codec, WM8350_FLL_CONTROL_2,
+ snd_soc_write(codec, WM8350_FLL_CONTROL_2,
(fll_div.ratio << 11) | (fll_div.
n & WM8350_FLL_N_MASK));
- wm8350_codec_write(codec, WM8350_FLL_CONTROL_3, fll_div.k);
- fll_4 = wm8350_codec_read(codec, WM8350_FLL_CONTROL_4) &
+ snd_soc_write(codec, WM8350_FLL_CONTROL_3, fll_div.k);
+ fll_4 = snd_soc_read(codec, WM8350_FLL_CONTROL_4) &
~(WM8350_FLL_FRAC | WM8350_FLL_SLOW_LOCK_REF);
- wm8350_codec_write(codec, WM8350_FLL_CONTROL_4,
+ snd_soc_write(codec, WM8350_FLL_CONTROL_4,
fll_4 | (fll_div.k ? WM8350_FLL_FRAC : 0) |
(fll_div.ratio == 8 ? WM8350_FLL_SLOW_LOCK_REF : 0));
@@ -1131,8 +1097,8 @@ static int wm8350_set_fll(struct snd_soc_dai *codec_dai,
static int wm8350_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- struct wm8350 *wm8350 = codec->control_data;
struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
+ struct wm8350 *wm8350 = priv->wm8350;
struct wm8350_audio_platform_data *platform =
wm8350->codec.platform_data;
u16 pm1;
@@ -1339,35 +1305,36 @@ static void wm8350_hpr_work(struct work_struct *work)
wm8350_hp_work(priv, &priv->hpr, WM8350_JACK_R_LVL);
}
-static irqreturn_t wm8350_hp_jack_handler(int irq, void *data)
+static irqreturn_t wm8350_hpl_jack_handler(int irq, void *data)
{
struct wm8350_data *priv = data;
struct wm8350 *wm8350 = priv->wm8350;
- struct wm8350_jack_data *jack = NULL;
- switch (irq - wm8350->irq_base) {
- case WM8350_IRQ_CODEC_JCK_DET_L:
#ifndef CONFIG_SND_SOC_WM8350_MODULE
- trace_snd_soc_jack_irq("WM8350 HPL");
+ trace_snd_soc_jack_irq("WM8350 HPL");
#endif
- jack = &priv->hpl;
- break;
- case WM8350_IRQ_CODEC_JCK_DET_R:
+ if (device_may_wakeup(wm8350->dev))
+ pm_wakeup_event(wm8350->dev, 250);
+
+ schedule_delayed_work(&priv->hpl.work, 200);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t wm8350_hpr_jack_handler(int irq, void *data)
+{
+ struct wm8350_data *priv = data;
+ struct wm8350 *wm8350 = priv->wm8350;
+
#ifndef CONFIG_SND_SOC_WM8350_MODULE
- trace_snd_soc_jack_irq("WM8350 HPR");
+ trace_snd_soc_jack_irq("WM8350 HPR");
#endif
- jack = &priv->hpr;
- break;
-
- default:
- BUG();
- }
if (device_may_wakeup(wm8350->dev))
pm_wakeup_event(wm8350->dev, 250);
- schedule_delayed_work(&jack->work, 200);
+ schedule_delayed_work(&priv->hpr.work, 200);
return IRQ_HANDLED;
}
@@ -1387,7 +1354,7 @@ int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which,
struct snd_soc_jack *jack, int report)
{
struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
- struct wm8350 *wm8350 = codec->control_data;
+ struct wm8350 *wm8350 = priv->wm8350;
int irq;
int ena;
@@ -1418,7 +1385,14 @@ int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which,
}
/* Sync status */
- wm8350_hp_jack_handler(irq + wm8350->irq_base, priv);
+ switch (which) {
+ case WM8350_JDL:
+ wm8350_hpl_jack_handler(0, priv);
+ break;
+ case WM8350_JDR:
+ wm8350_hpr_jack_handler(0, priv);
+ break;
+ }
return 0;
}
@@ -1463,7 +1437,7 @@ int wm8350_mic_jack_detect(struct snd_soc_codec *codec,
int detect_report, int short_report)
{
struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
- struct wm8350 *wm8350 = codec->control_data;
+ struct wm8350 *wm8350 = priv->wm8350;
priv->mic.jack = jack;
priv->mic.report = detect_report;
@@ -1491,7 +1465,6 @@ EXPORT_SYMBOL_GPL(wm8350_mic_jack_detect);
static const struct snd_soc_dai_ops wm8350_dai_ops = {
.hw_params = wm8350_pcm_hw_params,
.digital_mute = wm8350_mute,
- .trigger = wm8350_pcm_trigger,
.set_fmt = wm8350_set_dai_fmt,
.set_sysclk = wm8350_set_dai_sysclk,
.set_pll = wm8350_set_fll,
@@ -1559,9 +1532,9 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec)
wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
/* Enable robust clocking mode in ADC */
- wm8350_codec_write(codec, WM8350_SECURITY, 0xa7);
- wm8350_codec_write(codec, 0xde, 0x13);
- wm8350_codec_write(codec, WM8350_SECURITY, 0);
+ snd_soc_write(codec, WM8350_SECURITY, 0xa7);
+ snd_soc_write(codec, 0xde, 0x13);
+ snd_soc_write(codec, WM8350_SECURITY, 0);
/* read OUT1 & OUT2 volumes */
out1 = &priv->out1;
@@ -1601,10 +1574,10 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec)
WM8350_JDL_ENA | WM8350_JDR_ENA);
wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L,
- wm8350_hp_jack_handler, 0, "Left jack detect",
+ wm8350_hpl_jack_handler, 0, "Left jack detect",
priv);
wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R,
- wm8350_hp_jack_handler, 0, "Right jack detect",
+ wm8350_hpr_jack_handler, 0, "Right jack detect",
priv);
wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICSCD,
wm8350_mic_handler, 0, "Microphone short", priv);
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index 898979d23010..5dc31ebcd0e7 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -138,8 +138,8 @@ static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
return ret;
/* now hit the volume update bits (always bit 8) */
- val = wm8400_read(codec, reg);
- return wm8400_write(codec, reg, val | 0x0100);
+ val = snd_soc_read(codec, reg);
+ return snd_soc_write(codec, reg, val | 0x0100);
}
#define WM8400_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert, tlv_array) \
@@ -362,8 +362,8 @@ static int inmixer_event (struct snd_soc_dapm_widget *w,
{
u16 reg, fakepower;
- reg = wm8400_read(w->codec, WM8400_POWER_MANAGEMENT_2);
- fakepower = wm8400_read(w->codec, WM8400_INTDRIVBITS);
+ reg = snd_soc_read(w->codec, WM8400_POWER_MANAGEMENT_2);
+ fakepower = snd_soc_read(w->codec, WM8400_INTDRIVBITS);
if (fakepower & ((1 << WM8400_INMIXL_PWR) |
(1 << WM8400_AINLMUX_PWR))) {
@@ -378,7 +378,7 @@ static int inmixer_event (struct snd_soc_dapm_widget *w,
} else {
reg &= ~WM8400_AINR_ENA;
}
- wm8400_write(w->codec, WM8400_POWER_MANAGEMENT_2, reg);
+ snd_soc_write(w->codec, WM8400_POWER_MANAGEMENT_2, reg);
return 0;
}
@@ -394,7 +394,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
switch (reg_shift) {
case WM8400_SPEAKER_MIXER | (WM8400_LDSPK << 8) :
- reg = wm8400_read(w->codec, WM8400_OUTPUT_MIXER1);
+ reg = snd_soc_read(w->codec, WM8400_OUTPUT_MIXER1);
if (reg & WM8400_LDLO) {
printk(KERN_WARNING
"Cannot set as Output Mixer 1 LDLO Set\n");
@@ -402,7 +402,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
}
break;
case WM8400_SPEAKER_MIXER | (WM8400_RDSPK << 8):
- reg = wm8400_read(w->codec, WM8400_OUTPUT_MIXER2);
+ reg = snd_soc_read(w->codec, WM8400_OUTPUT_MIXER2);
if (reg & WM8400_RDRO) {
printk(KERN_WARNING
"Cannot set as Output Mixer 2 RDRO Set\n");
@@ -410,7 +410,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
}
break;
case WM8400_OUTPUT_MIXER1 | (WM8400_LDLO << 8):
- reg = wm8400_read(w->codec, WM8400_SPEAKER_MIXER);
+ reg = snd_soc_read(w->codec, WM8400_SPEAKER_MIXER);
if (reg & WM8400_LDSPK) {
printk(KERN_WARNING
"Cannot set as Speaker Mixer LDSPK Set\n");
@@ -418,7 +418,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
}
break;
case WM8400_OUTPUT_MIXER2 | (WM8400_RDRO << 8):
- reg = wm8400_read(w->codec, WM8400_SPEAKER_MIXER);
+ reg = snd_soc_read(w->codec, WM8400_SPEAKER_MIXER);
if (reg & WM8400_RDSPK) {
printk(KERN_WARNING
"Cannot set as Speaker Mixer RDSPK Set\n");
@@ -1021,13 +1021,13 @@ static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
wm8400->fll_in = freq_in;
/* We *must* disable the FLL before any changes */
- reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_2);
+ reg = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_2);
reg &= ~WM8400_FLL_ENA;
- wm8400_write(codec, WM8400_POWER_MANAGEMENT_2, reg);
+ snd_soc_write(codec, WM8400_POWER_MANAGEMENT_2, reg);
- reg = wm8400_read(codec, WM8400_FLL_CONTROL_1);
+ reg = snd_soc_read(codec, WM8400_FLL_CONTROL_1);
reg &= ~WM8400_FLL_OSC_ENA;
- wm8400_write(codec, WM8400_FLL_CONTROL_1, reg);
+ snd_soc_write(codec, WM8400_FLL_CONTROL_1, reg);
if (!freq_out)
return 0;
@@ -1035,15 +1035,15 @@ static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
reg &= ~(WM8400_FLL_REF_FREQ | WM8400_FLL_FRATIO_MASK);
reg |= WM8400_FLL_FRAC | factors.fratio;
reg |= factors.freq_ref << WM8400_FLL_REF_FREQ_SHIFT;
- wm8400_write(codec, WM8400_FLL_CONTROL_1, reg);
+ snd_soc_write(codec, WM8400_FLL_CONTROL_1, reg);
- wm8400_write(codec, WM8400_FLL_CONTROL_2, factors.k);
- wm8400_write(codec, WM8400_FLL_CONTROL_3, factors.n);
+ snd_soc_write(codec, WM8400_FLL_CONTROL_2, factors.k);
+ snd_soc_write(codec, WM8400_FLL_CONTROL_3, factors.n);
- reg = wm8400_read(codec, WM8400_FLL_CONTROL_4);
+ reg = snd_soc_read(codec, WM8400_FLL_CONTROL_4);
reg &= ~WM8400_FLL_OUTDIV_MASK;
reg |= factors.outdiv;
- wm8400_write(codec, WM8400_FLL_CONTROL_4, reg);
+ snd_soc_write(codec, WM8400_FLL_CONTROL_4, reg);
return 0;
}
@@ -1057,8 +1057,8 @@ static int wm8400_set_dai_fmt(struct snd_soc_dai *codec_dai,
struct snd_soc_codec *codec = codec_dai->codec;
u16 audio1, audio3;
- audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1);
- audio3 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_3);
+ audio1 = snd_soc_read(codec, WM8400_AUDIO_INTERFACE_1);
+ audio3 = snd_soc_read(codec, WM8400_AUDIO_INTERFACE_3);
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -1099,8 +1099,8 @@ static int wm8400_set_dai_fmt(struct snd_soc_dai *codec_dai,
return -EINVAL;
}
- wm8400_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
- wm8400_write(codec, WM8400_AUDIO_INTERFACE_3, audio3);
+ snd_soc_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
+ snd_soc_write(codec, WM8400_AUDIO_INTERFACE_3, audio3);
return 0;
}
@@ -1112,24 +1112,24 @@ static int wm8400_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
switch (div_id) {
case WM8400_MCLK_DIV:
- reg = wm8400_read(codec, WM8400_CLOCKING_2) &
+ reg = snd_soc_read(codec, WM8400_CLOCKING_2) &
~WM8400_MCLK_DIV_MASK;
- wm8400_write(codec, WM8400_CLOCKING_2, reg | div);
+ snd_soc_write(codec, WM8400_CLOCKING_2, reg | div);
break;
case WM8400_DACCLK_DIV:
- reg = wm8400_read(codec, WM8400_CLOCKING_2) &
+ reg = snd_soc_read(codec, WM8400_CLOCKING_2) &
~WM8400_DAC_CLKDIV_MASK;
- wm8400_write(codec, WM8400_CLOCKING_2, reg | div);
+ snd_soc_write(codec, WM8400_CLOCKING_2, reg | div);
break;
case WM8400_ADCCLK_DIV:
- reg = wm8400_read(codec, WM8400_CLOCKING_2) &
+ reg = snd_soc_read(codec, WM8400_CLOCKING_2) &
~WM8400_ADC_CLKDIV_MASK;
- wm8400_write(codec, WM8400_CLOCKING_2, reg | div);
+ snd_soc_write(codec, WM8400_CLOCKING_2, reg | div);
break;
case WM8400_BCLK_DIV:
- reg = wm8400_read(codec, WM8400_CLOCKING_1) &
+ reg = snd_soc_read(codec, WM8400_CLOCKING_1) &
~WM8400_BCLK_DIV_MASK;
- wm8400_write(codec, WM8400_CLOCKING_1, reg | div);
+ snd_soc_write(codec, WM8400_CLOCKING_1, reg | div);
break;
default:
return -EINVAL;
@@ -1145,9 +1145,8 @@ static int wm8400_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
- u16 audio1 = wm8400_read(codec, WM8400_AUDIO_INTERFACE_1);
+ struct snd_soc_codec *codec = dai->codec;
+ u16 audio1 = snd_soc_read(codec, WM8400_AUDIO_INTERFACE_1);
audio1 &= ~WM8400_AIF_WL_MASK;
/* bit size */
@@ -1165,19 +1164,19 @@ static int wm8400_hw_params(struct snd_pcm_substream *substream,
break;
}
- wm8400_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
+ snd_soc_write(codec, WM8400_AUDIO_INTERFACE_1, audio1);
return 0;
}
static int wm8400_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
- u16 val = wm8400_read(codec, WM8400_DAC_CTRL) & ~WM8400_DAC_MUTE;
+ u16 val = snd_soc_read(codec, WM8400_DAC_CTRL) & ~WM8400_DAC_MUTE;
if (mute)
- wm8400_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
+ snd_soc_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
else
- wm8400_write(codec, WM8400_DAC_CTRL, val);
+ snd_soc_write(codec, WM8400_DAC_CTRL, val);
return 0;
}
@@ -1196,9 +1195,9 @@ static int wm8400_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
/* VMID=2*50k */
- val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1) &
+ val = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1) &
~WM8400_VMID_MODE_MASK;
- wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x2);
+ snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x2);
break;
case SND_SOC_BIAS_STANDBY:
@@ -1212,74 +1211,74 @@ static int wm8400_set_bias_level(struct snd_soc_codec *codec,
return ret;
}
- wm8400_write(codec, WM8400_POWER_MANAGEMENT_1,
+ snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1,
WM8400_CODEC_ENA | WM8400_SYSCLK_ENA);
/* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */
- wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+ snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
WM8400_BUFDCOPEN | WM8400_POBCTRL);
msleep(50);
/* Enable VREF & VMID at 2x50k */
- val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
+ val = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1);
val |= 0x2 | WM8400_VREF_ENA;
- wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+ snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val);
/* Enable BUFIOEN */
- wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+ snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
WM8400_BUFDCOPEN | WM8400_POBCTRL |
WM8400_BUFIOEN);
/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
- wm8400_write(codec, WM8400_ANTIPOP2, WM8400_BUFIOEN);
+ snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_BUFIOEN);
}
/* VMID=2*300k */
- val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1) &
+ val = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1) &
~WM8400_VMID_MODE_MASK;
- wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x4);
+ snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val | 0x4);
break;
case SND_SOC_BIAS_OFF:
/* Enable POBCTRL and SOFT_ST */
- wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+ snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
WM8400_POBCTRL | WM8400_BUFIOEN);
/* Enable POBCTRL, SOFT_ST and BUFDCOPEN */
- wm8400_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
+ snd_soc_write(codec, WM8400_ANTIPOP2, WM8400_SOFTST |
WM8400_BUFDCOPEN | WM8400_POBCTRL |
WM8400_BUFIOEN);
/* mute DAC */
- val = wm8400_read(codec, WM8400_DAC_CTRL);
- wm8400_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
+ val = snd_soc_read(codec, WM8400_DAC_CTRL);
+ snd_soc_write(codec, WM8400_DAC_CTRL, val | WM8400_DAC_MUTE);
/* Enable any disabled outputs */
- val = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
+ val = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1);
val |= WM8400_SPK_ENA | WM8400_OUT3_ENA |
WM8400_OUT4_ENA | WM8400_LOUT_ENA |
WM8400_ROUT_ENA;
- wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+ snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val);
/* Disable VMID */
val &= ~WM8400_VMID_MODE_MASK;
- wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+ snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val);
msleep(300);
/* Enable all output discharge bits */
- wm8400_write(codec, WM8400_ANTIPOP1, WM8400_DIS_LLINE |
+ snd_soc_write(codec, WM8400_ANTIPOP1, WM8400_DIS_LLINE |
WM8400_DIS_RLINE | WM8400_DIS_OUT3 |
WM8400_DIS_OUT4 | WM8400_DIS_LOUT |
WM8400_DIS_ROUT);
/* Disable VREF */
val &= ~WM8400_VREF_ENA;
- wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, val);
+ snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, val);
/* disable POBCTRL, SOFT_ST and BUFDCOPEN */
- wm8400_write(codec, WM8400_ANTIPOP2, 0x0);
+ snd_soc_write(codec, WM8400_ANTIPOP2, 0x0);
ret = regulator_bulk_disable(ARRAY_SIZE(power),
&power[0]);
@@ -1385,19 +1384,19 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec)
wm8400_codec_reset(codec);
- reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
- wm8400_write(codec, WM8400_POWER_MANAGEMENT_1, reg | WM8400_CODEC_ENA);
+ reg = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1);
+ snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1, reg | WM8400_CODEC_ENA);
/* Latch volume update bits */
- reg = wm8400_read(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME);
- wm8400_write(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
+ reg = snd_soc_read(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME);
+ snd_soc_write(codec, WM8400_LEFT_LINE_INPUT_1_2_VOLUME,
reg & WM8400_IPVU);
- reg = wm8400_read(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME);
- wm8400_write(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
+ reg = snd_soc_read(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME);
+ snd_soc_write(codec, WM8400_RIGHT_LINE_INPUT_1_2_VOLUME,
reg & WM8400_IPVU);
- wm8400_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
- wm8400_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
+ snd_soc_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
+ snd_soc_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
if (!schedule_work(&priv->work)) {
ret = -EINVAL;
@@ -1414,8 +1413,8 @@ static int wm8400_codec_remove(struct snd_soc_codec *codec)
{
u16 reg;
- reg = wm8400_read(codec, WM8400_POWER_MANAGEMENT_1);
- wm8400_write(codec, WM8400_POWER_MANAGEMENT_1,
+ reg = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1);
+ snd_soc_write(codec, WM8400_POWER_MANAGEMENT_1,
reg & (~WM8400_CODEC_ENA));
regulator_bulk_free(ARRAY_SIZE(power), power);
@@ -1428,7 +1427,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8400 = {
.remove = wm8400_codec_remove,
.suspend = wm8400_suspend,
.resume = wm8400_resume,
- .read = wm8400_read,
+ .read = snd_soc_read,
.write = wm8400_write,
.set_bias_level = wm8400_set_bias_level,
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index 9166126bd312..56a049555e2c 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -392,8 +392,7 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
u16 iface = snd_soc_read(codec, WM8510_IFACE) & 0x19f;
u16 adn = snd_soc_read(codec, WM8510_ADD) & 0x1f1;
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index 7fea2c3bf7e7..1c3ffb290cdc 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -145,8 +145,7 @@ static int wm8523_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
int i;
u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1);
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
index fc3d59e49084..1467f97dce21 100644
--- a/sound/soc/codecs/wm8728.c
+++ b/sound/soc/codecs/wm8728.c
@@ -88,8 +88,7 @@ static int wm8728_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
u16 dac = snd_soc_read(codec, WM8728_DACCTL);
dac &= ~0x18;
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index a32caa72bd7d..9d1b9b0271f1 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -635,16 +635,17 @@ static int __devinit wm8731_spi_probe(struct spi_device *spi)
struct wm8731_priv *wm8731;
int ret;
- wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);
+ wm8731 = devm_kzalloc(&spi->dev, sizeof(struct wm8731_priv),
+ GFP_KERNEL);
if (wm8731 == NULL)
return -ENOMEM;
- wm8731->regmap = regmap_init_spi(spi, &wm8731_regmap);
+ wm8731->regmap = devm_regmap_init_spi(spi, &wm8731_regmap);
if (IS_ERR(wm8731->regmap)) {
ret = PTR_ERR(wm8731->regmap);
dev_err(&spi->dev, "Failed to allocate register map: %d\n",
ret);
- goto err;
+ return ret;
}
spi_set_drvdata(spi, wm8731);
@@ -653,25 +654,15 @@ static int __devinit wm8731_spi_probe(struct spi_device *spi)
&soc_codec_dev_wm8731, &wm8731_dai, 1);
if (ret != 0) {
dev_err(&spi->dev, "Failed to register CODEC: %d\n", ret);
- goto err_regmap;
+ return ret;
}
return 0;
-
-err_regmap:
- regmap_exit(wm8731->regmap);
-err:
- kfree(wm8731);
- return ret;
}
static int __devexit wm8731_spi_remove(struct spi_device *spi)
{
- struct wm8731_priv *wm8731 = spi_get_drvdata(spi);
-
snd_soc_unregister_codec(&spi->dev);
- regmap_exit(wm8731->regmap);
- kfree(wm8731);
return 0;
}
@@ -693,16 +684,17 @@ static __devinit int wm8731_i2c_probe(struct i2c_client *i2c,
struct wm8731_priv *wm8731;
int ret;
- wm8731 = kzalloc(sizeof(struct wm8731_priv), GFP_KERNEL);
+ wm8731 = devm_kzalloc(&i2c->dev, sizeof(struct wm8731_priv),
+ GFP_KERNEL);
if (wm8731 == NULL)
return -ENOMEM;
- wm8731->regmap = regmap_init_i2c(i2c, &wm8731_regmap);
+ wm8731->regmap = devm_regmap_init_i2c(i2c, &wm8731_regmap);
if (IS_ERR(wm8731->regmap)) {
ret = PTR_ERR(wm8731->regmap);
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
ret);
- goto err;
+ return ret;
}
i2c_set_clientdata(i2c, wm8731);
@@ -711,24 +703,15 @@ static __devinit int wm8731_i2c_probe(struct i2c_client *i2c,
&soc_codec_dev_wm8731, &wm8731_dai, 1);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
- goto err_regmap;
+ return ret;
}
return 0;
-
-err_regmap:
- regmap_exit(wm8731->regmap);
-err:
- kfree(wm8731);
- return ret;
}
static __devexit int wm8731_i2c_remove(struct i2c_client *client)
{
- struct wm8731_priv *wm8731 = i2c_get_clientdata(client);
snd_soc_unregister_codec(&client->dev);
- regmap_exit(wm8731->regmap);
- kfree(wm8731);
return 0;
}
diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c
index 4fe9d191e277..d0520124616d 100644
--- a/sound/soc/codecs/wm8737.c
+++ b/sound/soc/codecs/wm8737.c
@@ -329,8 +329,7 @@ static int wm8737_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
int i;
u16 clocking = 0;
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
index 3941f50bf187..6e849cb04243 100644
--- a/sound/soc/codecs/wm8741.c
+++ b/sound/soc/codecs/wm8741.c
@@ -203,8 +203,7 @@ static int wm8741_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1FC;
int i;
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index e4c50ce7d9c0..89151ca5e776 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -547,8 +547,7 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec);
u16 iface = snd_soc_read(codec, WM8750_IFACE) & 0x1f3;
u16 srate = snd_soc_read(codec, WM8750_SRATE) & 0x1c0;
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index e27e7b62b365..a26482cd7654 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -931,8 +931,7 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
u16 voice = snd_soc_read(codec, WM8753_PCM) & 0x01f3;
u16 srate = snd_soc_read(codec, WM8753_SRATE1) & 0x017f;
@@ -1161,8 +1160,7 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
u16 srate = snd_soc_read(codec, WM8753_SRATE1) & 0x01c0;
u16 hifi = snd_soc_read(codec, WM8753_HIFI) & 0x01f3;
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index f18c554efc98..077c9628c70d 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -610,8 +610,7 @@ static int wm8900_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
u16 reg;
reg = snd_soc_read(codec, WM8900_REG_AUDIO1) & ~0x60;
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index c91fb2f99c13..86b8a2926591 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -1432,8 +1432,7 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec =rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
int fs = params_rate(params);
int bclk;
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index d2883affea3b..481a3d9cfe48 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -371,8 +371,7 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFD9F;
u16 addcntrl = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFF1;
u16 companding = snd_soc_read(codec,
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 840d72086d04..8bc659d8dd2e 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -505,8 +505,7 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3;
int i;
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 15d467ff91b4..0cfce9999c89 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -1478,7 +1478,8 @@ static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
static int wm8962_dsp2_write_config(struct snd_soc_codec *codec)
{
- return 0;
+ return regcache_sync_region(codec->control_data,
+ WM8962_HDBASS_AI_1, WM8962_MAX_REGISTER);
}
static int wm8962_dsp2_set_enable(struct snd_soc_codec *codec, u16 val)
@@ -1755,10 +1756,22 @@ SOC_DOUBLE_R_TLV("EQ4 Volume", WM8962_EQ3, WM8962_EQ23,
SOC_DOUBLE_R_TLV("EQ5 Volume", WM8962_EQ3, WM8962_EQ23,
WM8962_EQL_B5_GAIN_SHIFT, 31, 0, eq_tlv),
+SOC_SINGLE("3D Switch", WM8962_THREED1, 0, 1, 0),
+SND_SOC_BYTES_MASK("3D Coefficients", WM8962_THREED1, 4, WM8962_THREED_ENA),
+
+SOC_SINGLE("DF1 Switch", WM8962_DF1, 0, 1, 0),
+SND_SOC_BYTES_MASK("DF1 Coefficients", WM8962_DF1, 7, WM8962_DF1_ENA),
+
+SOC_SINGLE("DRC Switch", WM8962_DRC_1, 0, 1, 0),
+SND_SOC_BYTES_MASK("DRC Coefficients", WM8962_DRC_1, 5, WM8962_DRC_ENA),
+
WM8962_DSP2_ENABLE("VSS Switch", WM8962_VSS_ENA_SHIFT),
+SND_SOC_BYTES("VSS Coefficients", WM8962_VSS_XHD2_1, 148),
WM8962_DSP2_ENABLE("HPF1 Switch", WM8962_HPF1_ENA_SHIFT),
WM8962_DSP2_ENABLE("HPF2 Switch", WM8962_HPF2_ENA_SHIFT),
+SND_SOC_BYTES("HPF Coefficients", WM8962_LHPF2, 1),
WM8962_DSP2_ENABLE("HD Bass Switch", WM8962_HDBASS_ENA_SHIFT),
+SND_SOC_BYTES("HD Bass Coefficients", WM8962_HDBASS_AI_1, 30),
};
static const struct snd_kcontrol_new wm8962_spk_mono_controls[] = {
@@ -2519,8 +2532,7 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
int i;
int aif0 = 0;
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c
index 28fe59e3ce01..eef783f6b6d6 100644
--- a/sound/soc/codecs/wm8971.c
+++ b/sound/soc/codecs/wm8971.c
@@ -478,8 +478,7 @@ static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
u16 iface = snd_soc_read(codec, WM8971_IFACE) & 0x1f3;
u16 srate = snd_soc_read(codec, WM8971_SRATE) & 0x1c0;
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index 72d5fdcd3cc2..a5be3adecf75 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -723,8 +723,7 @@ static int wm8978_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
/* Word length mask = 0x60 */
u16 iface_ctl = snd_soc_read(codec, WM8978_AUDIO_INTERFACE) & ~0x60;
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index 6cdf6a2bc283..1d4c5cf47b06 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -668,8 +668,7 @@ static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
u16 iface = snd_soc_read(codec, WM8988_IFACE) & 0x1f3;
u16 srate = snd_soc_read(codec, WM8988_SRATE) & 0x180;
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index 9d242351e6e8..db63c97ddf51 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -1112,8 +1112,7 @@ static int wm8990_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
u16 audio1 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_1);
audio1 &= ~WM8990_AIF_WL_MASK;
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index d256a9340644..36acfccab999 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -218,7 +218,6 @@ struct wm8993_priv {
unsigned int sysclk_rate;
unsigned int fs;
unsigned int bclk;
- int class_w_users;
unsigned int fll_fref;
unsigned int fll_fout;
int fll_src;
@@ -824,84 +823,6 @@ static int clk_sys_event(struct snd_soc_dapm_widget *w,
return 0;
}
-/*
- * When used with DAC outputs only the WM8993 charge pump supports
- * operation in class W mode, providing very low power consumption
- * when used with digital sources. Enable and disable this mode
- * automatically depending on the mixer configuration.
- *
- * Currently the only supported paths are the direct DAC->headphone
- * paths (which provide minimum power consumption anyway).
- */
-static int class_w_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
- struct snd_soc_dapm_widget *widget = wlist->widgets[0];
- struct snd_soc_codec *codec = widget->codec;
- struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
- int ret;
-
- /* Turn it off if we're using the main output mixer */
- if (ucontrol->value.integer.value[0] == 0) {
- if (wm8993->class_w_users == 0) {
- dev_dbg(codec->dev, "Disabling Class W\n");
- snd_soc_update_bits(codec, WM8993_CLASS_W_0,
- WM8993_CP_DYN_FREQ |
- WM8993_CP_DYN_V,
- 0);
- }
- wm8993->class_w_users++;
- wm8993->hubs_data.class_w = true;
- }
-
- /* Implement the change */
- ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
-
- /* Enable it if we're using the direct DAC path */
- if (ucontrol->value.integer.value[0] == 1) {
- if (wm8993->class_w_users == 1) {
- dev_dbg(codec->dev, "Enabling Class W\n");
- snd_soc_update_bits(codec, WM8993_CLASS_W_0,
- WM8993_CP_DYN_FREQ |
- WM8993_CP_DYN_V,
- WM8993_CP_DYN_FREQ |
- WM8993_CP_DYN_V);
- }
- wm8993->class_w_users--;
- wm8993->hubs_data.class_w = false;
- }
-
- dev_dbg(codec->dev, "Indirect DAC use count now %d\n",
- wm8993->class_w_users);
-
- return ret;
-}
-
-#define SOC_DAPM_ENUM_W(xname, xenum) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = snd_soc_info_enum_double, \
- .get = snd_soc_dapm_get_enum_double, \
- .put = class_w_put, \
- .private_value = (unsigned long)&xenum }
-
-static const char *hp_mux_text[] = {
- "Mixer",
- "DAC",
-};
-
-static const struct soc_enum hpl_enum =
- SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER1, 8, 2, hp_mux_text);
-
-static const struct snd_kcontrol_new hpl_mux =
- SOC_DAPM_ENUM_W("Left Headphone Mux", hpl_enum);
-
-static const struct soc_enum hpr_enum =
- SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER2, 8, 2, hp_mux_text);
-
-static const struct snd_kcontrol_new hpr_mux =
- SOC_DAPM_ENUM_W("Right Headphone Mux", hpr_enum);
-
static const struct snd_kcontrol_new left_speaker_mixer[] = {
SOC_DAPM_SINGLE("Input Switch", WM8993_SPEAKER_MIXER, 7, 1, 0),
SOC_DAPM_SINGLE("IN1LP Switch", WM8993_SPEAKER_MIXER, 5, 1, 0),
@@ -988,8 +909,8 @@ SND_SOC_DAPM_MUX("DACR Sidetone", SND_SOC_NOPM, 0, 0, &sidetoner_mux),
SND_SOC_DAPM_DAC("DACL", NULL, WM8993_POWER_MANAGEMENT_3, 1, 0),
SND_SOC_DAPM_DAC("DACR", NULL, WM8993_POWER_MANAGEMENT_3, 0, 0),
-SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux),
-SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux),
+SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpl_mux),
+SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpr_mux),
SND_SOC_DAPM_MIXER("SPKL", WM8993_POWER_MANAGEMENT_3, 8, 0,
left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
@@ -1579,9 +1500,6 @@ static int wm8993_probe(struct snd_soc_codec *codec)
return ret;
}
- /* By default we're using the output mixers */
- wm8993->class_w_users = 2;
-
/* Latch volume update bits and default ZC on */
snd_soc_update_bits(codec, WM8993_RIGHT_DAC_DIGITAL_VOLUME,
WM8993_DAC_VU, WM8993_DAC_VU);
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 2de12ebe43b5..993639d694ce 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -70,8 +70,8 @@ static const struct wm8958_micd_rate micdet_rates[] = {
static const struct wm8958_micd_rate jackdet_rates[] = {
{ 32768, true, 0, 1 },
{ 32768, false, 0, 1 },
- { 44100 * 256, true, 7, 10 },
- { 44100 * 256, false, 7, 10 },
+ { 44100 * 256, true, 10, 10 },
+ { 44100 * 256, false, 7, 8 },
};
static void wm8958_micd_set_rate(struct snd_soc_codec *codec)
@@ -82,7 +82,8 @@ static void wm8958_micd_set_rate(struct snd_soc_codec *codec)
const struct wm8958_micd_rate *rates;
int num_rates;
- if (wm8994->jack_cb != wm8958_default_micdet)
+ if (!(wm8994->pdata && wm8994->pdata->micd_rates) &&
+ wm8994->jack_cb != wm8958_default_micdet)
return;
idle = !wm8994->jack_mic;
@@ -118,6 +119,10 @@ static void wm8958_micd_set_rate(struct snd_soc_codec *codec)
val = rates[best].start << WM8958_MICD_BIAS_STARTTIME_SHIFT
| rates[best].rate << WM8958_MICD_RATE_SHIFT;
+ dev_dbg(codec->dev, "MICD rate %d,%d for %dHz %s\n",
+ rates[best].start, rates[best].rate, sysclk,
+ idle ? "idle" : "active");
+
snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
WM8958_MICD_BIAS_STARTTIME_MASK |
WM8958_MICD_RATE_MASK, val);
@@ -398,7 +403,7 @@ static void wm8994_set_retune_mobile(struct snd_soc_codec *codec, int block)
wm8994->dac_rates[iface]);
/* The EQ will be disabled while reconfiguring it, remember the
- * current configuration.
+ * current configuration.
*/
save = snd_soc_read(codec, base);
save &= WM8994_AIF1DAC1_EQ_ENA;
@@ -689,6 +694,9 @@ static void wm1811_jackdet_set_mode(struct snd_soc_codec *codec, u16 mode)
if (!wm8994->jackdet || !wm8994->jack_cb)
return;
+ if (!wm8994->jackdet || !wm8994->jack_cb)
+ return;
+
if (wm8994->active_refcount)
mode = WM1811_JACKDET_MODE_AUDIO;
@@ -784,7 +792,7 @@ static void vmid_reference(struct snd_soc_codec *codec)
switch (wm8994->vmid_mode) {
default:
- WARN_ON(0 == "Invalid VMID mode");
+ WARN_ON(NULL == "Invalid VMID mode");
case WM8994_VMID_NORMAL:
/* Startup bias, VMID ramp & buffer */
snd_soc_update_bits(codec, WM8994_ANTIPOP_2,
@@ -937,27 +945,12 @@ static int vmid_event(struct snd_soc_dapm_widget *w,
return 0;
}
-static void wm8994_update_class_w(struct snd_soc_codec *codec)
+static bool wm8994_check_class_w_digital(struct snd_soc_codec *codec)
{
- struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
- int enable = 1;
int source = 0; /* GCC flow analysis can't track enable */
int reg, reg_r;
- /* Only support direct DAC->headphone paths */
- reg = snd_soc_read(codec, WM8994_OUTPUT_MIXER_1);
- if (!(reg & WM8994_DAC1L_TO_HPOUT1L)) {
- dev_vdbg(codec->dev, "HPL connected to output mixer\n");
- enable = 0;
- }
-
- reg = snd_soc_read(codec, WM8994_OUTPUT_MIXER_2);
- if (!(reg & WM8994_DAC1R_TO_HPOUT1R)) {
- dev_vdbg(codec->dev, "HPR connected to output mixer\n");
- enable = 0;
- }
-
- /* We also need the same setting for L/R and only one path */
+ /* We also need the same AIF source for L/R and only one path */
reg = snd_soc_read(codec, WM8994_DAC1_LEFT_MIXER_ROUTING);
switch (reg) {
case WM8994_AIF2DACL_TO_DAC1L:
@@ -974,30 +967,20 @@ static void wm8994_update_class_w(struct snd_soc_codec *codec)
break;
default:
dev_vdbg(codec->dev, "DAC mixer setting: %x\n", reg);
- enable = 0;
- break;
+ return false;
}
reg_r = snd_soc_read(codec, WM8994_DAC1_RIGHT_MIXER_ROUTING);
if (reg_r != reg) {
dev_vdbg(codec->dev, "Left and right DAC mixers different\n");
- enable = 0;
+ return false;
}
- if (enable) {
- dev_dbg(codec->dev, "Class W enabled\n");
- snd_soc_update_bits(codec, WM8994_CLASS_W_1,
- WM8994_CP_DYN_PWR |
- WM8994_CP_DYN_SRC_SEL_MASK,
- source | WM8994_CP_DYN_PWR);
- wm8994->hubs.class_w = true;
-
- } else {
- dev_dbg(codec->dev, "Class W disabled\n");
- snd_soc_update_bits(codec, WM8994_CLASS_W_1,
- WM8994_CP_DYN_PWR, 0);
- wm8994->hubs.class_w = false;
- }
+ /* Set the source up */
+ snd_soc_update_bits(codec, WM8994_CLASS_W_1,
+ WM8994_CP_DYN_SRC_SEL_MASK, source);
+
+ return true;
}
static int aif1clk_ev(struct snd_soc_dapm_widget *w,
@@ -1280,45 +1263,6 @@ static int dac_ev(struct snd_soc_dapm_widget *w,
return 0;
}
-static const char *hp_mux_text[] = {
- "Mixer",
- "DAC",
-};
-
-#define WM8994_HP_ENUM(xname, xenum) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
- .info = snd_soc_info_enum_double, \
- .get = snd_soc_dapm_get_enum_double, \
- .put = wm8994_put_hp_enum, \
- .private_value = (unsigned long)&xenum }
-
-static int wm8994_put_hp_enum(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
- struct snd_soc_dapm_widget *w = wlist->widgets[0];
- struct snd_soc_codec *codec = w->codec;
- int ret;
-
- ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
-
- wm8994_update_class_w(codec);
-
- return ret;
-}
-
-static const struct soc_enum hpl_enum =
- SOC_ENUM_SINGLE(WM8994_OUTPUT_MIXER_1, 8, 2, hp_mux_text);
-
-static const struct snd_kcontrol_new hpl_mux =
- WM8994_HP_ENUM("Left Headphone Mux", hpl_enum);
-
-static const struct soc_enum hpr_enum =
- SOC_ENUM_SINGLE(WM8994_OUTPUT_MIXER_2, 8, 2, hp_mux_text);
-
-static const struct snd_kcontrol_new hpr_mux =
- WM8994_HP_ENUM("Right Headphone Mux", hpr_enum);
-
static const char *adc_mux_text[] = {
"ADC",
"DMIC",
@@ -1430,7 +1374,7 @@ static int wm8994_put_class_w(struct snd_kcontrol *kcontrol,
ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
- wm8994_update_class_w(codec);
+ wm_hubs_update_class_w(codec);
return ret;
}
@@ -1524,7 +1468,7 @@ static const struct snd_kcontrol_new wm8958_aif3adc_mux =
SOC_DAPM_ENUM("AIF3ADC Mux", wm8958_aif3adc_enum);
static const char *mono_pcm_out_text[] = {
- "None", "AIF2ADCL", "AIF2ADCR",
+ "None", "AIF2ADCL", "AIF2ADCR",
};
static const struct soc_enum mono_pcm_out_enum =
@@ -1573,9 +1517,9 @@ SND_SOC_DAPM_MIXER_E("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0,
SND_SOC_DAPM_MIXER_E("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0,
right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer),
late_enable_ev, SND_SOC_DAPM_PRE_PMU),
-SND_SOC_DAPM_MUX_E("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux,
+SND_SOC_DAPM_MUX_E("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpl_mux,
late_enable_ev, SND_SOC_DAPM_PRE_PMU),
-SND_SOC_DAPM_MUX_E("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux,
+SND_SOC_DAPM_MUX_E("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpr_mux,
late_enable_ev, SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev)
@@ -1591,8 +1535,8 @@ SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0,
left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
SND_SOC_DAPM_MIXER("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0,
right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)),
-SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux),
-SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux),
+SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpl_mux),
+SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &wm_hubs_hpr_mux),
};
static const struct snd_soc_dapm_widget wm8994_dac_revd_widgets[] = {
@@ -1732,6 +1676,7 @@ SND_SOC_DAPM_MUX("AIF3ADC Mux", SND_SOC_NOPM, 0, 0, &wm8994_aif3adc_mux),
};
static const struct snd_soc_dapm_widget wm8958_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("AIF3", WM8994_POWER_MANAGEMENT_6, 5, 1, NULL, 0),
SND_SOC_DAPM_MUX("Mono PCM Out Mux", SND_SOC_NOPM, 0, 0, &mono_pcm_out_mux),
SND_SOC_DAPM_MUX("AIF2DACL Mux", SND_SOC_NOPM, 0, 0, &aif2dacl_src_mux),
SND_SOC_DAPM_MUX("AIF2DACR Mux", SND_SOC_NOPM, 0, 0, &aif2dacr_src_mux),
@@ -1972,6 +1917,9 @@ static const struct snd_soc_dapm_route wm8958_intercon[] = {
{ "AIF2DACR Mux", "AIF2", "AIF2DAC Mux" },
{ "AIF2DACR Mux", "AIF3", "AIF3DACDAT" },
+ { "AIF3DACDAT", NULL, "AIF3" },
+ { "AIF3ADCDAT", NULL, "AIF3" },
+
{ "Mono PCM Out Mux", "AIF2ADCL", "AIF2ADCL" },
{ "Mono PCM Out Mux", "AIF2ADCR", "AIF2ADCR" },
@@ -2068,24 +2016,20 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
struct wm8994 *control = wm8994->wm8994;
int reg_offset, ret;
struct fll_div fll;
- u16 reg, aif1, aif2;
+ u16 reg, clk1, aif_reg, aif_src;
unsigned long timeout;
bool was_enabled;
- aif1 = snd_soc_read(codec, WM8994_AIF1_CLOCKING_1)
- & WM8994_AIF1CLK_ENA;
-
- aif2 = snd_soc_read(codec, WM8994_AIF2_CLOCKING_1)
- & WM8994_AIF2CLK_ENA;
-
switch (id) {
case WM8994_FLL1:
reg_offset = 0;
id = 0;
+ aif_src = 0x10;
break;
case WM8994_FLL2:
reg_offset = 0x20;
id = 1;
+ aif_src = 0x18;
break;
default:
return -EINVAL;
@@ -2127,16 +2071,33 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
if (ret < 0)
return ret;
- /* Gate the AIF clocks while we reclock */
- snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
- WM8994_AIF1CLK_ENA, 0);
- snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1,
- WM8994_AIF2CLK_ENA, 0);
+ /* Make sure that we're not providing SYSCLK right now */
+ clk1 = snd_soc_read(codec, WM8994_CLOCKING_1);
+ if (clk1 & WM8994_SYSCLK_SRC)
+ aif_reg = WM8994_AIF2_CLOCKING_1;
+ else
+ aif_reg = WM8994_AIF1_CLOCKING_1;
+ reg = snd_soc_read(codec, aif_reg);
+
+ if ((reg & WM8994_AIF1CLK_ENA) &&
+ (reg & WM8994_AIF1CLK_SRC_MASK) == aif_src) {
+ dev_err(codec->dev, "FLL%d is currently providing SYSCLK\n",
+ id + 1);
+ return -EBUSY;
+ }
/* We always need to disable the FLL while reconfiguring */
snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_1 + reg_offset,
WM8994_FLL1_ENA, 0);
+ if (wm8994->fll_byp && src == WM8994_FLL_SRC_BCLK &&
+ freq_in == freq_out && freq_out) {
+ dev_dbg(codec->dev, "Bypassing FLL%d\n", id + 1);
+ snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset,
+ WM8958_FLL1_BYP, WM8958_FLL1_BYP);
+ goto out;
+ }
+
reg = (fll.outdiv << WM8994_FLL1_OUTDIV_SHIFT) |
(fll.fll_fratio << WM8994_FLL1_FRATIO_SHIFT);
snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_2 + reg_offset,
@@ -2151,6 +2112,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
fll.n << WM8994_FLL1_N_SHIFT);
snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset,
+ WM8958_FLL1_BYP |
WM8994_FLL1_REFCLK_DIV_MASK |
WM8994_FLL1_REFCLK_SRC_MASK,
(fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT) |
@@ -2213,16 +2175,11 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
}
}
+out:
wm8994->fll[id].in = freq_in;
wm8994->fll[id].out = freq_out;
wm8994->fll[id].src = src;
- /* Enable any gated AIF clocks */
- snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
- WM8994_AIF1CLK_ENA, aif1);
- snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1,
- WM8994_AIF2CLK_ENA, aif2);
-
configure_clock(codec);
return 0;
@@ -2290,7 +2247,7 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
case WM8994_SYSCLK_OPCLK:
/* Special case - a division (times 10) is given and
- * no effect on main clocking.
+ * no effect on main clocking.
*/
if (freq) {
for (i = 0; i < ARRAY_SIZE(opclk_divs); i++)
@@ -2792,33 +2749,6 @@ static int wm8994_aif3_hw_params(struct snd_pcm_substream *substream,
return snd_soc_update_bits(codec, aif1_reg, WM8994_AIF1_WL_MASK, aif1);
}
-static void wm8994_aif_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct snd_soc_codec *codec = dai->codec;
- int rate_reg = 0;
-
- switch (dai->id) {
- case 1:
- rate_reg = WM8994_AIF1_RATE;
- break;
- case 2:
- rate_reg = WM8994_AIF2_RATE;
- break;
- default:
- break;
- }
-
- /* If the DAI is idle then configure the divider tree for the
- * lowest output rate to save a little power if the clock is
- * still active (eg, because it is system clock).
- */
- if (rate_reg && !dai->playback_active && !dai->capture_active)
- snd_soc_update_bits(codec, rate_reg,
- WM8994_AIF1_SR_MASK |
- WM8994_AIF1CLK_RATE_MASK, 0x9);
-}
-
static int wm8994_aif_mute(struct snd_soc_dai *codec_dai, int mute)
{
struct snd_soc_codec *codec = codec_dai->codec;
@@ -2860,10 +2790,6 @@ static int wm8994_set_tristate(struct snd_soc_dai *codec_dai, int tristate)
reg = WM8994_AIF2_MASTER_SLAVE;
mask = WM8994_AIF2_TRI;
break;
- case 3:
- reg = WM8994_POWER_MANAGEMENT_6;
- mask = WM8994_AIF3_TRI;
- break;
default:
return -EINVAL;
}
@@ -2900,7 +2826,6 @@ static const struct snd_soc_dai_ops wm8994_aif1_dai_ops = {
.set_sysclk = wm8994_set_dai_sysclk,
.set_fmt = wm8994_set_dai_fmt,
.hw_params = wm8994_hw_params,
- .shutdown = wm8994_aif_shutdown,
.digital_mute = wm8994_aif_mute,
.set_pll = wm8994_set_fll,
.set_tristate = wm8994_set_tristate,
@@ -2910,7 +2835,6 @@ static const struct snd_soc_dai_ops wm8994_aif2_dai_ops = {
.set_sysclk = wm8994_set_dai_sysclk,
.set_fmt = wm8994_set_dai_fmt,
.hw_params = wm8994_hw_params,
- .shutdown = wm8994_aif_shutdown,
.digital_mute = wm8994_aif_mute,
.set_pll = wm8994_set_fll,
.set_tristate = wm8994_set_tristate,
@@ -2918,7 +2842,6 @@ static const struct snd_soc_dai_ops wm8994_aif2_dai_ops = {
static const struct snd_soc_dai_ops wm8994_aif3_dai_ops = {
.hw_params = wm8994_aif3_hw_params,
- .set_tristate = wm8994_set_tristate,
};
static struct snd_soc_dai_driver wm8994_dai[] = {
@@ -3126,14 +3049,14 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
/* Expand the array... */
t = krealloc(wm8994->retune_mobile_texts,
- sizeof(char *) *
+ sizeof(char *) *
(wm8994->num_retune_mobile_texts + 1),
GFP_KERNEL);
if (t == NULL)
continue;
/* ...store the new entry... */
- t[wm8994->num_retune_mobile_texts] =
+ t[wm8994->num_retune_mobile_texts] =
pdata->retune_mobile_cfgs[i].name;
/* ...and remember the new version. */
@@ -3304,25 +3227,25 @@ int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
}
EXPORT_SYMBOL_GPL(wm8994_mic_detect);
-static irqreturn_t wm8994_mic_irq(int irq, void *data)
+static void wm8994_mic_work(struct work_struct *work)
{
- struct wm8994_priv *priv = data;
- struct snd_soc_codec *codec = priv->codec;
- int reg;
+ struct wm8994_priv *priv = container_of(work,
+ struct wm8994_priv,
+ mic_work.work);
+ struct regmap *regmap = priv->wm8994->regmap;
+ struct device *dev = priv->wm8994->dev;
+ unsigned int reg;
+ int ret;
int report;
-#ifndef CONFIG_SND_SOC_WM8994_MODULE
- trace_snd_soc_jack_irq(dev_name(codec->dev));
-#endif
-
- reg = snd_soc_read(codec, WM8994_INTERRUPT_RAW_STATUS_2);
- if (reg < 0) {
- dev_err(codec->dev, "Failed to read microphone status: %d\n",
- reg);
- return IRQ_HANDLED;
+ ret = regmap_read(regmap, WM8994_INTERRUPT_RAW_STATUS_2, &reg);
+ if (ret < 0) {
+ dev_err(dev, "Failed to read microphone status: %d\n",
+ ret);
+ return;
}
- dev_dbg(codec->dev, "Microphone status: %x\n", reg);
+ dev_dbg(dev, "Microphone status: %x\n", reg);
report = 0;
if (reg & WM8994_MIC1_DET_STS) {
@@ -3361,6 +3284,20 @@ static irqreturn_t wm8994_mic_irq(int irq, void *data)
snd_soc_jack_report(priv->micdet[1].jack, report,
SND_JACK_HEADSET | SND_JACK_BTN_0);
+}
+
+static irqreturn_t wm8994_mic_irq(int irq, void *data)
+{
+ struct wm8994_priv *priv = data;
+ struct snd_soc_codec *codec = priv->codec;
+
+#ifndef CONFIG_SND_SOC_WM8994_MODULE
+ trace_snd_soc_jack_irq(dev_name(codec->dev));
+#endif
+
+ pm_wakeup_event(codec->dev, 300);
+
+ schedule_delayed_work(&priv->mic_work, msecs_to_jiffies(250));
return IRQ_HANDLED;
}
@@ -3415,9 +3352,6 @@ static void wm8958_default_micdet(u16 status, void *data)
wm8958_micd_set_rate(codec);
- snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADPHONE,
- SND_JACK_HEADSET);
-
/* If we have jackdet that will detect removal */
if (wm8994->jackdet) {
mutex_lock(&wm8994->accdet_lock);
@@ -3430,14 +3364,13 @@ static void wm8958_default_micdet(u16 status, void *data)
mutex_unlock(&wm8994->accdet_lock);
- if (wm8994->pdata->jd_ext_cap) {
- mutex_lock(&codec->mutex);
+ if (wm8994->pdata->jd_ext_cap)
snd_soc_dapm_disable_pin(&codec->dapm,
"MICBIAS2");
- snd_soc_dapm_sync(&codec->dapm);
- mutex_unlock(&codec->mutex);
- }
}
+
+ snd_soc_jack_report(wm8994->micdet[0].jack, SND_JACK_HEADPHONE,
+ SND_JACK_HEADSET);
}
/* Report short circuit as a button */
@@ -3489,6 +3422,8 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
if (present) {
dev_dbg(codec->dev, "Jack detected\n");
+ wm8958_micd_set_rate(codec);
+
snd_soc_update_bits(codec, WM8958_MICBIAS2,
WM8958_MICB2_DISCH, 0);
@@ -3526,16 +3461,11 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
/* If required for an external cap force MICBIAS on */
if (wm8994->pdata->jd_ext_cap) {
- mutex_lock(&codec->mutex);
-
if (present)
snd_soc_dapm_force_enable_pin(&codec->dapm,
"MICBIAS2");
else
snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS2");
-
- snd_soc_dapm_sync(&codec->dapm);
- mutex_unlock(&codec->mutex);
}
if (present)
@@ -3740,6 +3670,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
wm8994->codec = codec;
mutex_init(&wm8994->accdet_lock);
+ INIT_DELAYED_WORK(&wm8994->mic_work, wm8994_mic_work);
for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
init_completion(&wm8994->fll_locked[i]);
@@ -3783,13 +3714,22 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
case WM8958:
wm8994->hubs.dcs_readback_mode = 1;
wm8994->hubs.hp_startup_mode = 1;
+
+ switch (wm8994->revision) {
+ case 0:
+ break;
+ default:
+ wm8994->fll_byp = true;
+ break;
+ }
break;
case WM1811:
wm8994->hubs.dcs_readback_mode = 2;
wm8994->hubs.no_series_update = 1;
wm8994->hubs.hp_startup_mode = 1;
- wm8994->hubs.no_cache_class_w = true;
+ wm8994->hubs.no_cache_dac_hp_direct = true;
+ wm8994->fll_byp = true;
switch (wm8994->revision) {
case 0:
@@ -4010,7 +3950,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
break;
}
- wm8994_update_class_w(codec);
+ wm8994->hubs.check_class_w_digital = wm8994_check_class_w_digital;
+ wm_hubs_update_class_w(codec);
wm8994_handle_pdata(wm8994);
@@ -4075,7 +4016,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
ARRAY_SIZE(wm8994_dac_widgets));
break;
}
-
wm_hubs_add_analogue_routes(codec, 0, 0);
snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
@@ -4140,7 +4080,7 @@ err_irq:
return ret;
}
-static int wm8994_codec_remove(struct snd_soc_codec *codec)
+static int wm8994_codec_remove(struct snd_soc_codec *codec)
{
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994 *control = wm8994->wm8994;
@@ -4181,14 +4121,10 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec)
free_irq(wm8994->micdet_irq, wm8994);
break;
}
- if (wm8994->mbc)
- release_firmware(wm8994->mbc);
- if (wm8994->mbc_vss)
- release_firmware(wm8994->mbc_vss);
- if (wm8994->enh_eq)
- release_firmware(wm8994->enh_eq);
+ release_firmware(wm8994->mbc);
+ release_firmware(wm8994->mbc_vss);
+ release_firmware(wm8994->enh_eq);
kfree(wm8994->retune_mobile_texts);
-
return 0;
}
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index c724112998d8..d77e06f0a675 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -12,6 +12,7 @@
#include <sound/soc.h>
#include <linux/firmware.h>
#include <linux/completion.h>
+#include <linux/workqueue.h>
#include "wm_hubs.h"
@@ -79,6 +80,7 @@ struct wm8994_priv {
struct wm8994_fll_config fll[2], fll_suspend[2];
struct completion fll_locked[2];
bool fll_locked_irq;
+ bool fll_byp;
int vmid_refcount;
int active_refcount;
@@ -126,6 +128,7 @@ struct wm8994_priv {
struct mutex accdet_lock;
struct wm8994_micdet micdet[2];
+ struct delayed_work mic_work;
bool mic_detecting;
bool jack_mic;
int btn_mask;
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index 1fd635494045..8af422e38fd0 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -1770,7 +1770,13 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec,
switch (level) {
case SND_SOC_BIAS_ON:
+ break;
case SND_SOC_BIAS_PREPARE:
+ /* Put the MICBIASes into regulating mode */
+ snd_soc_update_bits(codec, WM8996_MICBIAS_1,
+ WM8996_MICB1_MODE, 0);
+ snd_soc_update_bits(codec, WM8996_MICBIAS_2,
+ WM8996_MICB2_MODE, 0);
break;
case SND_SOC_BIAS_STANDBY:
@@ -1793,6 +1799,12 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec,
regcache_cache_only(codec->control_data, false);
regcache_sync(codec->control_data);
}
+
+ /* Bypass the MICBIASes for lowest power */
+ snd_soc_update_bits(codec, WM8996_MICBIAS_1,
+ WM8996_MICB1_MODE, WM8996_MICB1_MODE);
+ snd_soc_update_bits(codec, WM8996_MICBIAS_2,
+ WM8996_MICB2_MODE, WM8996_MICB2_MODE);
break;
case SND_SOC_BIAS_OFF:
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 076c126ed9b1..9328270df16c 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -774,7 +774,7 @@ static const struct snd_soc_dapm_widget wm9081_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("IN1"),
SND_SOC_DAPM_INPUT("IN2"),
-SND_SOC_DAPM_DAC("DAC", "HiFi Playback", WM9081_POWER_MANAGEMENT, 0, 0),
+SND_SOC_DAPM_DAC("DAC", NULL, WM9081_POWER_MANAGEMENT, 0, 0),
SND_SOC_DAPM_MIXER_NAMED_CTL("Mixer", SND_SOC_NOPM, 0, 0,
mixer, ARRAY_SIZE(mixer)),
@@ -799,6 +799,7 @@ SND_SOC_DAPM_SUPPLY("TSENSE", WM9081_POWER_MANAGEMENT, 7, 0, NULL, 0),
static const struct snd_soc_dapm_route wm9081_audio_paths[] = {
{ "DAC", NULL, "CLK_SYS" },
{ "DAC", NULL, "CLK_DSP" },
+ { "DAC", NULL, "AIF" },
{ "Mixer", "IN1 Switch", "IN1" },
{ "Mixer", "IN2 Switch", "IN2" },
@@ -1252,7 +1253,7 @@ static const struct snd_soc_dai_ops wm9081_dai_ops = {
static struct snd_soc_dai_driver wm9081_dai = {
.name = "wm9081-hifi",
.playback = {
- .stream_name = "HiFi Playback",
+ .stream_name = "AIF",
.channels_min = 1,
.channels_max = 2,
.rates = WM9081_RATES,
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c
index cacc6a86b46f..e8e782a0c78d 100644
--- a/sound/soc/codecs/wm9705.c
+++ b/sound/soc/codecs/wm9705.c
@@ -236,9 +236,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
static int ac97_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
int reg;
u16 vra;
@@ -250,7 +248,7 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
else
reg = AC97_PCM_LR_ADC_RATE;
- return ac97_write(codec, reg, runtime->rate);
+ return ac97_write(codec, reg, substream->runtime->rate);
}
#define WM9705_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index b342ae50bcd6..a1541414d904 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -467,11 +467,10 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
static int ac97_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec =rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
int reg;
u16 vra;
+ struct snd_pcm_runtime *runtime = substream->runtime;
vra = ac97_read(codec, AC97_EXTENDED_STATUS);
ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);
@@ -487,10 +486,9 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
static int ac97_aux_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_codec *codec = dai->codec;
u16 vra, xsle;
+ struct snd_pcm_runtime *runtime = substream->runtime;
vra = ac97_read(codec, AC97_EXTENDED_STATUS);
ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1);
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index 6c028c470601..dfe957a47f29 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -109,12 +109,103 @@ irqreturn_t wm_hubs_dcs_done(int irq, void *data)
}
EXPORT_SYMBOL_GPL(wm_hubs_dcs_done);
+static bool wm_hubs_dac_hp_direct(struct snd_soc_codec *codec)
+{
+ int reg;
+
+ /* If we're going via the mixer we'll need to do additional checks */
+ reg = snd_soc_read(codec, WM8993_OUTPUT_MIXER1);
+ if (!(reg & WM8993_DACL_TO_HPOUT1L)) {
+ if (reg & ~WM8993_DACL_TO_MIXOUTL) {
+ dev_vdbg(codec->dev, "Analogue paths connected: %x\n",
+ reg & ~WM8993_DACL_TO_HPOUT1L);
+ return false;
+ } else {
+ dev_vdbg(codec->dev, "HPL connected to mixer\n");
+ }
+ } else {
+ dev_vdbg(codec->dev, "HPL connected to DAC\n");
+ }
+
+ reg = snd_soc_read(codec, WM8993_OUTPUT_MIXER2);
+ if (!(reg & WM8993_DACR_TO_HPOUT1R)) {
+ if (reg & ~WM8993_DACR_TO_MIXOUTR) {
+ dev_vdbg(codec->dev, "Analogue paths connected: %x\n",
+ reg & ~WM8993_DACR_TO_HPOUT1R);
+ return false;
+ } else {
+ dev_vdbg(codec->dev, "HPR connected to mixer\n");
+ }
+ } else {
+ dev_vdbg(codec->dev, "HPR connected to DAC\n");
+ }
+
+ return true;
+}
+
+struct wm_hubs_dcs_cache {
+ struct list_head list;
+ unsigned int left;
+ unsigned int right;
+ u16 dcs_cfg;
+};
+
+static bool wm_hubs_dcs_cache_get(struct snd_soc_codec *codec,
+ struct wm_hubs_dcs_cache **entry)
+{
+ struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+ struct wm_hubs_dcs_cache *cache;
+ unsigned int left, right;
+
+ left = snd_soc_read(codec, WM8993_LEFT_OUTPUT_VOLUME);
+ left &= WM8993_HPOUT1L_VOL_MASK;
+
+ right = snd_soc_read(codec, WM8993_RIGHT_OUTPUT_VOLUME);
+ right &= WM8993_HPOUT1R_VOL_MASK;
+
+ list_for_each_entry(cache, &hubs->dcs_cache, list) {
+ if (cache->left != left || cache->right != right)
+ continue;
+
+ *entry = cache;
+ return true;
+ }
+
+ return false;
+}
+
+static void wm_hubs_dcs_cache_set(struct snd_soc_codec *codec, u16 dcs_cfg)
+{
+ struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+ struct wm_hubs_dcs_cache *cache;
+
+ if (hubs->no_cache_dac_hp_direct)
+ return;
+
+ cache = devm_kzalloc(codec->dev, sizeof(*cache), GFP_KERNEL);
+ if (!cache) {
+ dev_err(codec->dev, "Failed to allocate DCS cache entry\n");
+ return;
+ }
+
+ cache->left = snd_soc_read(codec, WM8993_LEFT_OUTPUT_VOLUME);
+ cache->left &= WM8993_HPOUT1L_VOL_MASK;
+
+ cache->right = snd_soc_read(codec, WM8993_RIGHT_OUTPUT_VOLUME);
+ cache->right &= WM8993_HPOUT1R_VOL_MASK;
+
+ cache->dcs_cfg = dcs_cfg;
+
+ list_add_tail(&cache->list, &hubs->dcs_cache);
+}
+
/*
* Startup calibration of the DC servo
*/
static void calibrate_dc_servo(struct snd_soc_codec *codec)
{
struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+ struct wm_hubs_dcs_cache *cache;
s8 offset;
u16 reg, reg_l, reg_r, dcs_cfg, dcs_reg;
@@ -129,10 +220,11 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
/* If we're using a digital only path and have a previously
* callibrated DC servo offset stored then use that. */
- if (hubs->class_w && hubs->class_w_dcs) {
- dev_dbg(codec->dev, "Using cached DC servo offset %x\n",
- hubs->class_w_dcs);
- snd_soc_write(codec, dcs_reg, hubs->class_w_dcs);
+ if (wm_hubs_dac_hp_direct(codec) &&
+ wm_hubs_dcs_cache_get(codec, &cache)) {
+ dev_dbg(codec->dev, "Using cached DCS offset %x for %d,%d\n",
+ cache->dcs_cfg, cache->left, cache->right);
+ snd_soc_write(codec, dcs_reg, cache->dcs_cfg);
wait_for_dc_servo(codec,
WM8993_DCS_TRIG_DAC_WR_0 |
WM8993_DCS_TRIG_DAC_WR_1);
@@ -207,8 +299,8 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
/* Save the callibrated offset if we're in class W mode and
* therefore don't have any analogue signal mixed in. */
- if (hubs->class_w && !hubs->no_cache_class_w)
- hubs->class_w_dcs = dcs_cfg;
+ if (wm_hubs_dac_hp_direct(codec))
+ wm_hubs_dcs_cache_set(codec, dcs_cfg);
}
/*
@@ -223,9 +315,6 @@ static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
ret = snd_soc_put_volsw(kcontrol, ucontrol);
- /* Updating the analogue gains invalidates the DC servo cache */
- hubs->class_w_dcs = 0;
-
/* If we're applying an offset correction then updating the
* callibration would be likely to introduce further offsets. */
if (hubs->dcs_codes_l || hubs->dcs_codes_r || hubs->no_series_update)
@@ -530,6 +619,86 @@ static int lineout_event(struct snd_soc_dapm_widget *w,
return 0;
}
+void wm_hubs_update_class_w(struct snd_soc_codec *codec)
+{
+ struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+ int enable = WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ;
+
+ if (!wm_hubs_dac_hp_direct(codec))
+ enable = false;
+
+ if (hubs->check_class_w_digital && !hubs->check_class_w_digital(codec))
+ enable = false;
+
+ dev_vdbg(codec->dev, "Class W %s\n", enable ? "enabled" : "disabled");
+
+ snd_soc_update_bits(codec, WM8993_CLASS_W_0,
+ WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ, enable);
+}
+EXPORT_SYMBOL_GPL(wm_hubs_update_class_w);
+
+#define WM_HUBS_SINGLE_W(xname, reg, shift, max, invert) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_soc_info_volsw, \
+ .get = snd_soc_dapm_get_volsw, .put = class_w_put_volsw, \
+ .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
+
+static int class_w_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_codec *codec = widget->codec;
+ int ret;
+
+ ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
+
+ wm_hubs_update_class_w(codec);
+
+ return ret;
+}
+
+#define WM_HUBS_ENUM_W(xname, xenum) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_soc_info_enum_double, \
+ .get = snd_soc_dapm_get_enum_double, \
+ .put = class_w_put_double, \
+ .private_value = (unsigned long)&xenum }
+
+static int class_w_put_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+ struct snd_soc_codec *codec = widget->codec;
+ int ret;
+
+ ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+ wm_hubs_update_class_w(codec);
+
+ return ret;
+}
+
+static const char *hp_mux_text[] = {
+ "Mixer",
+ "DAC",
+};
+
+static const struct soc_enum hpl_enum =
+ SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER1, 8, 2, hp_mux_text);
+
+const struct snd_kcontrol_new wm_hubs_hpl_mux =
+ WM_HUBS_ENUM_W("Left Headphone Mux", hpl_enum);
+EXPORT_SYMBOL_GPL(wm_hubs_hpl_mux);
+
+static const struct soc_enum hpr_enum =
+ SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER2, 8, 2, hp_mux_text);
+
+const struct snd_kcontrol_new wm_hubs_hpr_mux =
+ WM_HUBS_ENUM_W("Right Headphone Mux", hpr_enum);
+EXPORT_SYMBOL_GPL(wm_hubs_hpr_mux);
+
static const struct snd_kcontrol_new in1l_pga[] = {
SOC_DAPM_SINGLE("IN1LP Switch", WM8993_INPUT_MIXER2, 5, 1, 0),
SOC_DAPM_SINGLE("IN1LN Switch", WM8993_INPUT_MIXER2, 4, 1, 0),
@@ -561,25 +730,25 @@ SOC_DAPM_SINGLE("IN1R Switch", WM8993_INPUT_MIXER4, 5, 1, 0),
};
static const struct snd_kcontrol_new left_output_mixer[] = {
-SOC_DAPM_SINGLE("Right Input Switch", WM8993_OUTPUT_MIXER1, 7, 1, 0),
-SOC_DAPM_SINGLE("Left Input Switch", WM8993_OUTPUT_MIXER1, 6, 1, 0),
-SOC_DAPM_SINGLE("IN2RN Switch", WM8993_OUTPUT_MIXER1, 5, 1, 0),
-SOC_DAPM_SINGLE("IN2LN Switch", WM8993_OUTPUT_MIXER1, 4, 1, 0),
-SOC_DAPM_SINGLE("IN2LP Switch", WM8993_OUTPUT_MIXER1, 1, 1, 0),
-SOC_DAPM_SINGLE("IN1R Switch", WM8993_OUTPUT_MIXER1, 3, 1, 0),
-SOC_DAPM_SINGLE("IN1L Switch", WM8993_OUTPUT_MIXER1, 2, 1, 0),
-SOC_DAPM_SINGLE("DAC Switch", WM8993_OUTPUT_MIXER1, 0, 1, 0),
+WM_HUBS_SINGLE_W("Right Input Switch", WM8993_OUTPUT_MIXER1, 7, 1, 0),
+WM_HUBS_SINGLE_W("Left Input Switch", WM8993_OUTPUT_MIXER1, 6, 1, 0),
+WM_HUBS_SINGLE_W("IN2RN Switch", WM8993_OUTPUT_MIXER1, 5, 1, 0),
+WM_HUBS_SINGLE_W("IN2LN Switch", WM8993_OUTPUT_MIXER1, 4, 1, 0),
+WM_HUBS_SINGLE_W("IN2LP Switch", WM8993_OUTPUT_MIXER1, 1, 1, 0),
+WM_HUBS_SINGLE_W("IN1R Switch", WM8993_OUTPUT_MIXER1, 3, 1, 0),
+WM_HUBS_SINGLE_W("IN1L Switch", WM8993_OUTPUT_MIXER1, 2, 1, 0),
+WM_HUBS_SINGLE_W("DAC Switch", WM8993_OUTPUT_MIXER1, 0, 1, 0),
};
static const struct snd_kcontrol_new right_output_mixer[] = {
-SOC_DAPM_SINGLE("Left Input Switch", WM8993_OUTPUT_MIXER2, 7, 1, 0),
-SOC_DAPM_SINGLE("Right Input Switch", WM8993_OUTPUT_MIXER2, 6, 1, 0),
-SOC_DAPM_SINGLE("IN2LN Switch", WM8993_OUTPUT_MIXER2, 5, 1, 0),
-SOC_DAPM_SINGLE("IN2RN Switch", WM8993_OUTPUT_MIXER2, 4, 1, 0),
-SOC_DAPM_SINGLE("IN1L Switch", WM8993_OUTPUT_MIXER2, 3, 1, 0),
-SOC_DAPM_SINGLE("IN1R Switch", WM8993_OUTPUT_MIXER2, 2, 1, 0),
-SOC_DAPM_SINGLE("IN2RP Switch", WM8993_OUTPUT_MIXER2, 1, 1, 0),
-SOC_DAPM_SINGLE("DAC Switch", WM8993_OUTPUT_MIXER2, 0, 1, 0),
+WM_HUBS_SINGLE_W("Left Input Switch", WM8993_OUTPUT_MIXER2, 7, 1, 0),
+WM_HUBS_SINGLE_W("Right Input Switch", WM8993_OUTPUT_MIXER2, 6, 1, 0),
+WM_HUBS_SINGLE_W("IN2LN Switch", WM8993_OUTPUT_MIXER2, 5, 1, 0),
+WM_HUBS_SINGLE_W("IN2RN Switch", WM8993_OUTPUT_MIXER2, 4, 1, 0),
+WM_HUBS_SINGLE_W("IN1L Switch", WM8993_OUTPUT_MIXER2, 3, 1, 0),
+WM_HUBS_SINGLE_W("IN1R Switch", WM8993_OUTPUT_MIXER2, 2, 1, 0),
+WM_HUBS_SINGLE_W("IN2RP Switch", WM8993_OUTPUT_MIXER2, 1, 1, 0),
+WM_HUBS_SINGLE_W("DAC Switch", WM8993_OUTPUT_MIXER2, 0, 1, 0),
};
static const struct snd_kcontrol_new earpiece_mixer[] = {
@@ -943,6 +1112,7 @@ int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec,
struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = &codec->dapm;
+ INIT_LIST_HEAD(&hubs->dcs_cache);
init_completion(&hubs->dcs_done);
snd_soc_dapm_add_routes(dapm, analogue_routes,
diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h
index 5705276f4943..da2dc899ce6d 100644
--- a/sound/soc/codecs/wm_hubs.h
+++ b/sound/soc/codecs/wm_hubs.h
@@ -16,6 +16,8 @@
#include <linux/completion.h>
#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <sound/control.h>
struct snd_soc_codec;
@@ -30,9 +32,9 @@ struct wm_hubs_data {
int series_startup;
int no_series_update;
- bool no_cache_class_w;
- bool class_w;
- u16 class_w_dcs;
+ bool no_cache_dac_hp_direct;
+ struct list_head dcs_cache;
+ bool (*check_class_w_digital)(struct snd_soc_codec *);
bool lineout1_se;
bool lineout1n_ena;
@@ -58,5 +60,9 @@ extern irqreturn_t wm_hubs_dcs_done(int irq, void *data);
extern void wm_hubs_vmid_ena(struct snd_soc_codec *codec);
extern void wm_hubs_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level);
+extern void wm_hubs_update_class_w(struct snd_soc_codec *codec);
+
+extern const struct snd_kcontrol_new wm_hubs_hpl_mux;
+extern const struct snd_kcontrol_new wm_hubs_hpr_mux;
#endif
diff --git a/sound/soc/ep93xx/ep93xx-ac97.c b/sound/soc/ep93xx/ep93xx-ac97.c
index 0678637abd66..bdffab33e160 100644
--- a/sound/soc/ep93xx/ep93xx-ac97.c
+++ b/sound/soc/ep93xx/ep93xx-ac97.c
@@ -87,17 +87,13 @@
* struct ep93xx_ac97_info - EP93xx AC97 controller info structure
* @lock: mutex serializing access to the bus (slot 1 & 2 ops)
* @dev: pointer to the platform device dev structure
- * @mem: physical memory resource for the registers
* @regs: mapped AC97 controller registers
- * @irq: AC97 interrupt number
* @done: bus ops wait here for an interrupt
*/
struct ep93xx_ac97_info {
struct mutex lock;
struct device *dev;
- struct resource *mem;
void __iomem *regs;
- int irq;
struct completion done;
};
@@ -359,66 +355,50 @@ static struct snd_soc_dai_driver ep93xx_ac97_dai = {
static int __devinit ep93xx_ac97_probe(struct platform_device *pdev)
{
struct ep93xx_ac97_info *info;
+ struct resource *res;
+ unsigned int irq;
int ret;
- info = kzalloc(sizeof(struct ep93xx_ac97_info), GFP_KERNEL);
+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
- dev_set_drvdata(&pdev->dev, info);
-
- mutex_init(&info->lock);
- init_completion(&info->done);
- info->dev = &pdev->dev;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
- info->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!info->mem) {
- ret = -ENXIO;
- goto fail_free_info;
- }
+ info->regs = devm_request_and_ioremap(&pdev->dev, res);
+ if (!info->regs)
+ return -ENXIO;
- info->irq = platform_get_irq(pdev, 0);
- if (!info->irq) {
- ret = -ENXIO;
- goto fail_free_info;
- }
+ irq = platform_get_irq(pdev, 0);
+ if (!irq)
+ return -ENODEV;
- if (!request_mem_region(info->mem->start, resource_size(info->mem),
- pdev->name)) {
- ret = -EBUSY;
- goto fail_free_info;
- }
+ ret = devm_request_irq(&pdev->dev, irq, ep93xx_ac97_interrupt,
+ IRQF_TRIGGER_HIGH, pdev->name, info);
+ if (ret)
+ goto fail;
- info->regs = ioremap(info->mem->start, resource_size(info->mem));
- if (!info->regs) {
- ret = -ENOMEM;
- goto fail_release_mem;
- }
+ dev_set_drvdata(&pdev->dev, info);
- ret = request_irq(info->irq, ep93xx_ac97_interrupt, IRQF_TRIGGER_HIGH,
- pdev->name, info);
- if (ret)
- goto fail_unmap_mem;
+ mutex_init(&info->lock);
+ init_completion(&info->done);
+ info->dev = &pdev->dev;
ep93xx_ac97_info = info;
platform_set_drvdata(pdev, info);
ret = snd_soc_register_dai(&pdev->dev, &ep93xx_ac97_dai);
if (ret)
- goto fail_free_irq;
+ goto fail;
return 0;
-fail_free_irq:
+fail:
platform_set_drvdata(pdev, NULL);
- free_irq(info->irq, info);
-fail_unmap_mem:
- iounmap(info->regs);
-fail_release_mem:
- release_mem_region(info->mem->start, resource_size(info->mem));
-fail_free_info:
- kfree(info);
-
+ ep93xx_ac97_info = NULL;
+ dev_set_drvdata(&pdev->dev, NULL);
return ret;
}
@@ -431,11 +411,9 @@ static int __devexit ep93xx_ac97_remove(struct platform_device *pdev)
/* disable the AC97 controller */
ep93xx_ac97_write_reg(info, AC97GCR, 0);
- free_irq(info->irq, info);
- iounmap(info->regs);
- release_mem_region(info->mem->start, resource_size(info->mem));
platform_set_drvdata(pdev, NULL);
- kfree(info);
+ ep93xx_ac97_info = NULL;
+ dev_set_drvdata(&pdev->dev, NULL);
return 0;
}
diff --git a/sound/soc/ep93xx/ep93xx-i2s.c b/sound/soc/ep93xx/ep93xx-i2s.c
index f7a62348e3fe..8df8f6dc474f 100644
--- a/sound/soc/ep93xx/ep93xx-i2s.c
+++ b/sound/soc/ep93xx/ep93xx-i2s.c
@@ -63,7 +63,6 @@ struct ep93xx_i2s_info {
struct clk *sclk;
struct clk *lrclk;
struct ep93xx_pcm_dma_params *dma_params;
- struct resource *mem;
void __iomem *regs;
};
@@ -373,38 +372,22 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
struct resource *res;
int err;
- info = kzalloc(sizeof(struct ep93xx_i2s_info), GFP_KERNEL);
- if (!info) {
- err = -ENOMEM;
- goto fail;
- }
-
- dev_set_drvdata(&pdev->dev, info);
- info->dma_params = ep93xx_i2s_dma_params;
+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- err = -ENODEV;
- goto fail_free_info;
- }
+ if (!res)
+ return -ENODEV;
- info->mem = request_mem_region(res->start, resource_size(res),
- pdev->name);
- if (!info->mem) {
- err = -EBUSY;
- goto fail_free_info;
- }
-
- info->regs = ioremap(info->mem->start, resource_size(info->mem));
- if (!info->regs) {
- err = -ENXIO;
- goto fail_release_mem;
- }
+ info->regs = devm_request_and_ioremap(&pdev->dev, res);
+ if (!info->regs)
+ return -ENXIO;
info->mclk = clk_get(&pdev->dev, "mclk");
if (IS_ERR(info->mclk)) {
err = PTR_ERR(info->mclk);
- goto fail_unmap_mem;
+ goto fail;
}
info->sclk = clk_get(&pdev->dev, "sclk");
@@ -419,6 +402,9 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
goto fail_put_sclk;
}
+ dev_set_drvdata(&pdev->dev, info);
+ info->dma_params = ep93xx_i2s_dma_params;
+
err = snd_soc_register_dai(&pdev->dev, &ep93xx_i2s_dai);
if (err)
goto fail_put_lrclk;
@@ -426,17 +412,12 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
return 0;
fail_put_lrclk:
+ dev_set_drvdata(&pdev->dev, NULL);
clk_put(info->lrclk);
fail_put_sclk:
clk_put(info->sclk);
fail_put_mclk:
clk_put(info->mclk);
-fail_unmap_mem:
- iounmap(info->regs);
-fail_release_mem:
- release_mem_region(info->mem->start, resource_size(info->mem));
-fail_free_info:
- kfree(info);
fail:
return err;
}
@@ -446,12 +427,10 @@ static int __devexit ep93xx_i2s_remove(struct platform_device *pdev)
struct ep93xx_i2s_info *info = dev_get_drvdata(&pdev->dev);
snd_soc_unregister_dai(&pdev->dev);
+ dev_set_drvdata(&pdev->dev, NULL);
clk_put(info->lrclk);
clk_put(info->sclk);
clk_put(info->mclk);
- iounmap(info->regs);
- release_mem_region(info->mem->start, resource_size(info->mem));
- kfree(info);
return 0;
}
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index d754d34d68a6..d70133086ac3 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -1,18 +1,31 @@
-config SND_MPC52xx_DMA
+config SND_SOC_FSL_SSI
tristate
-# ASoC platform support for the Freescale PowerPC SOCs that have an SSI and
-# an Elo DMA controller, such as the MPC8610 and P1022. You will still need to
-# select a platform driver and a codec driver.
-config SND_SOC_POWERPC_SSI
+config SND_SOC_FSL_UTILS
tristate
+
+menuconfig SND_POWERPC_SOC
+ tristate "SoC Audio for Freescale PowerPC CPUs"
depends on FSL_SOC
+ help
+ Say Y or M if you want to add support for codecs attached to
+ the PowerPC CPUs.
+
+if SND_POWERPC_SOC
+
+config SND_MPC52xx_DMA
+ tristate
+
+config SND_SOC_POWERPC_DMA
+ tristate
config SND_SOC_MPC8610_HPCD
tristate "ALSA SoC support for the Freescale MPC8610 HPCD board"
# I2C is necessary for the CS4270 driver
depends on MPC8610_HPCD && I2C
- select SND_SOC_POWERPC_SSI
+ select SND_SOC_FSL_SSI
+ select SND_SOC_FSL_UTILS
+ select SND_SOC_POWERPC_DMA
select SND_SOC_CS4270
select SND_SOC_CS4270_VD33_ERRATA
default y if MPC8610_HPCD
@@ -23,7 +36,9 @@ config SND_SOC_P1022_DS
tristate "ALSA SoC support for the Freescale P1022 DS board"
# I2C is necessary for the WM8776 driver
depends on P1022_DS && I2C
- select SND_SOC_POWERPC_SSI
+ select SND_SOC_FSL_SSI
+ select SND_SOC_FSL_UTILS
+ select SND_SOC_POWERPC_DMA
select SND_SOC_WM8776
default y if P1022_DS
help
@@ -65,3 +80,103 @@ config SND_MPC52xx_SOC_EFIKA
help
Say Y if you want to add support for sound on the Efika.
+endif # SND_POWERPC_SOC
+
+menuconfig SND_IMX_SOC
+ tristate "SoC Audio for Freescale i.MX CPUs"
+ depends on ARCH_MXC
+ help
+ Say Y or M if you want to add support for codecs attached to
+ the i.MX CPUs.
+
+if SND_IMX_SOC
+
+config SND_SOC_IMX_SSI
+ tristate
+
+config SND_SOC_IMX_PCM
+ tristate
+
+config SND_SOC_IMX_PCM_FIQ
+ tristate
+ select FIQ
+ select SND_SOC_IMX_PCM
+
+config SND_SOC_IMX_PCM_DMA
+ tristate
+ select SND_SOC_DMAENGINE_PCM
+ select SND_SOC_IMX_PCM
+
+config SND_SOC_IMX_AUDMUX
+ tristate
+
+config SND_MXC_SOC_WM1133_EV1
+ tristate "Audio on the i.MX31ADS with WM1133-EV1 fitted"
+ depends on MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL
+ select SND_SOC_WM8350
+ select SND_SOC_IMX_PCM_FIQ
+ select SND_SOC_IMX_AUDMUX
+ select SND_SOC_IMX_SSI
+ help
+ Enable support for audio on the i.MX31ADS with the WM1133-EV1
+ PMIC board with WM8835x fitted.
+
+config SND_SOC_MX27VIS_AIC32X4
+ tristate "SoC audio support for Visstrim M10 boards"
+ depends on MACH_IMX27_VISSTRIM_M10 && I2C
+ select SND_SOC_TLV320AIC32X4
+ select SND_SOC_IMX_PCM_DMA
+ select SND_SOC_IMX_AUDMUX
+ select SND_SOC_IMX_SSI
+ help
+ Say Y if you want to add support for SoC audio on Visstrim SM10
+ board with TLV320AIC32X4 codec.
+
+config SND_SOC_PHYCORE_AC97
+ tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
+ depends on MACH_PCM043 || MACH_PCA100
+ select SND_SOC_AC97_BUS
+ select SND_SOC_WM9712
+ select SND_SOC_IMX_PCM_FIQ
+ select SND_SOC_IMX_AUDMUX
+ select SND_SOC_IMX_SSI
+ help
+ Say Y if you want to add support for SoC audio on Phytec phyCORE
+ and phyCARD boards in AC97 mode
+
+config SND_SOC_EUKREA_TLV320
+ tristate "Eukrea TLV320"
+ depends on MACH_EUKREA_MBIMX27_BASEBOARD \
+ || MACH_EUKREA_MBIMXSD25_BASEBOARD \
+ || MACH_EUKREA_MBIMXSD35_BASEBOARD \
+ || MACH_EUKREA_MBIMXSD51_BASEBOARD
+ depends on I2C
+ select SND_SOC_TLV320AIC23
+ select SND_SOC_IMX_PCM_FIQ
+ select SND_SOC_IMX_AUDMUX
+ select SND_SOC_IMX_SSI
+ help
+ Enable I2S based access to the TLV320AIC23B codec attached
+ to the SSI interface
+
+config SND_SOC_IMX_SGTL5000
+ tristate "SoC Audio support for i.MX boards with sgtl5000"
+ depends on OF && I2C
+ select SND_SOC_SGTL5000
+ select SND_SOC_IMX_PCM_DMA
+ select SND_SOC_IMX_AUDMUX
+ select SND_SOC_FSL_SSI
+ select SND_SOC_FSL_UTILS
+ help
+ Say Y if you want to add support for SoC audio on an i.MX board with
+ a sgtl5000 codec.
+
+config SND_SOC_IMX_MC13783
+ tristate "SoC Audio support for I.MX boards with mc13783"
+ depends on MFD_MC13783
+ select SND_SOC_IMX_SSI
+ select SND_SOC_IMX_AUDMUX
+ select SND_SOC_MC13783
+ select SND_SOC_IMX_PCM_DMA
+
+endif # SND_IMX_SOC
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index b4a38c0ac58c..5f3cf3f52ea0 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -8,8 +8,11 @@ obj-$(CONFIG_SND_SOC_P1022_DS) += snd-soc-p1022-ds.o
# Freescale PowerPC SSI/DMA Platform Support
snd-soc-fsl-ssi-objs := fsl_ssi.o
+snd-soc-fsl-utils-objs := fsl_utils.o
snd-soc-fsl-dma-objs := fsl_dma.o
-obj-$(CONFIG_SND_SOC_POWERPC_SSI) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o
+obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
+obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
+obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
# MPC5200 Platform Support
obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
@@ -20,3 +23,29 @@ obj-$(CONFIG_SND_SOC_MPC5200_AC97) += mpc5200_psc_ac97.o
obj-$(CONFIG_SND_MPC52xx_SOC_PCM030) += pcm030-audio-fabric.o
obj-$(CONFIG_SND_MPC52xx_SOC_EFIKA) += efika-audio-fabric.o
+# i.MX Platform Support
+snd-soc-imx-ssi-objs := imx-ssi.o
+snd-soc-imx-audmux-objs := imx-audmux.o
+
+obj-$(CONFIG_SND_SOC_IMX_SSI) += snd-soc-imx-ssi.o
+obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o
+
+obj-$(CONFIG_SND_SOC_IMX_PCM) += snd-soc-imx-pcm.o
+snd-soc-imx-pcm-y := imx-pcm.o
+snd-soc-imx-pcm-$(CONFIG_SND_SOC_IMX_PCM_FIQ) += imx-pcm-fiq.o
+snd-soc-imx-pcm-$(CONFIG_SND_SOC_IMX_PCM_DMA) += imx-pcm-dma.o
+
+# i.MX Machine Support
+snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
+snd-soc-phycore-ac97-objs := phycore-ac97.o
+snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o
+snd-soc-wm1133-ev1-objs := wm1133-ev1.o
+snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o
+snd-soc-imx-mc13783-objs := imx-mc13783.o
+
+obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
+obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
+obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o
+obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
+obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o
+obj-$(CONFIG_SND_SOC_IMX_MC13783) += snd-soc-imx-mc13783.o
diff --git a/sound/soc/imx/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c
index 7d4475cfdb24..efb9ede01208 100644
--- a/sound/soc/imx/eukrea-tlv320.c
+++ b/sound/soc/fsl/eukrea-tlv320.c
@@ -7,7 +7,7 @@
* which is Copyright 2009 Simtec Electronics
* and on sound/soc/imx/phycore-ac97.c which is
* Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
- *
+ *
* 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
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 2eb407fa3b48..4ed2afd47782 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -11,11 +11,15 @@
*/
#include <linux/init.h>
+#include <linux/io.h>
#include <linux/module.h>
#include <linux/interrupt.h>
+#include <linux/clk.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <sound/core.h>
@@ -25,6 +29,26 @@
#include <sound/soc.h>
#include "fsl_ssi.h"
+#include "imx-pcm.h"
+
+#ifdef PPC
+#define read_ssi(addr) in_be32(addr)
+#define write_ssi(val, addr) out_be32(addr, val)
+#define write_ssi_mask(addr, clear, set) clrsetbits_be32(addr, clear, set)
+#elif defined ARM
+#define read_ssi(addr) readl(addr)
+#define write_ssi(val, addr) writel(val, addr)
+/*
+ * FIXME: Proper locking should be added at write_ssi_mask caller level
+ * to ensure this register read/modify/write sequence is race free.
+ */
+static inline void write_ssi_mask(u32 __iomem *addr, u32 clear, u32 set)
+{
+ u32 val = readl(addr);
+ val = (val & ~clear) | set;
+ writel(val, addr);
+}
+#endif
/**
* FSLSSI_I2S_RATES: sample rates supported by the I2S
@@ -94,6 +118,13 @@ struct fsl_ssi_private {
struct device_attribute dev_attr;
struct platform_device *pdev;
+ bool new_binding;
+ bool ssi_on_imx;
+ struct clk *clk;
+ struct platform_device *imx_pcm_pdev;
+ struct imx_pcm_dma_params dma_params_tx;
+ struct imx_pcm_dma_params dma_params_rx;
+
struct {
unsigned int rfrc;
unsigned int tfrc;
@@ -145,7 +176,7 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
were interrupted for. We mask it with the Interrupt Enable register
so that we only check for events that we're interested in.
*/
- sisr = in_be32(&ssi->sisr) & SIER_FLAGS;
+ sisr = read_ssi(&ssi->sisr) & SIER_FLAGS;
if (sisr & CCSR_SSI_SISR_RFRC) {
ssi_private->stats.rfrc++;
@@ -260,7 +291,7 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
/* Clear the bits that we set */
if (sisr2)
- out_be32(&ssi->sisr, sisr2);
+ write_ssi(sisr2, &ssi->sisr);
return ret;
}
@@ -295,7 +326,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
* SSI needs to be disabled before updating the registers we set
* here.
*/
- clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
+ write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
/*
* Program the SSI into I2S Slave Non-Network Synchronous mode.
@@ -303,20 +334,18 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
*
* FIXME: Little-endian samples require a different shift dir
*/
- clrsetbits_be32(&ssi->scr,
+ write_ssi_mask(&ssi->scr,
CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN,
CCSR_SSI_SCR_TFR_CLK_DIS | CCSR_SSI_SCR_I2S_MODE_SLAVE
| (synchronous ? CCSR_SSI_SCR_SYN : 0));
- out_be32(&ssi->stcr,
- CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
+ write_ssi(CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TEFS |
- CCSR_SSI_STCR_TSCKP);
+ CCSR_SSI_STCR_TSCKP, &ssi->stcr);
- out_be32(&ssi->srcr,
- CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFEN0 |
+ write_ssi(CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFEN0 |
CCSR_SSI_SRCR_RFSI | CCSR_SSI_SRCR_REFS |
- CCSR_SSI_SRCR_RSCKP);
+ CCSR_SSI_SRCR_RSCKP, &ssi->srcr);
/*
* The DC and PM bits are only used if the SSI is the clock
@@ -324,7 +353,7 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
*/
/* Enable the interrupts and DMA requests */
- out_be32(&ssi->sier, SIER_FLAGS);
+ write_ssi(SIER_FLAGS, &ssi->sier);
/*
* Set the watermark for transmit FIFI 0 and receive FIFO 0. We
@@ -339,9 +368,9 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
* make this value larger (and maybe we should), but this way
* data will be written to memory as soon as it's available.
*/
- out_be32(&ssi->sfcsr,
- CCSR_SSI_SFCSR_TFWM0(ssi_private->fifo_depth - 2) |
- CCSR_SSI_SFCSR_RFWM0(ssi_private->fifo_depth - 2));
+ write_ssi(CCSR_SSI_SFCSR_TFWM0(ssi_private->fifo_depth - 2) |
+ CCSR_SSI_SFCSR_RFWM0(ssi_private->fifo_depth - 2),
+ &ssi->sfcsr);
/*
* We keep the SSI disabled because if we enable it, then the
@@ -393,6 +422,12 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
ssi_private->second_stream = substream;
}
+ if (ssi_private->ssi_on_imx)
+ snd_soc_dai_set_dma_data(dai, substream,
+ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+ &ssi_private->dma_params_tx :
+ &ssi_private->dma_params_rx);
+
return 0;
}
@@ -417,7 +452,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
unsigned int sample_size =
snd_pcm_format_width(params_format(hw_params));
u32 wl = CCSR_SSI_SxCCR_WL(sample_size);
- int enabled = in_be32(&ssi->scr) & CCSR_SSI_SCR_SSIEN;
+ int enabled = read_ssi(&ssi->scr) & CCSR_SSI_SCR_SSIEN;
/*
* If we're in synchronous mode, and the SSI is already enabled,
@@ -439,9 +474,9 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream,
/* In synchronous mode, the SSI uses STCCR for capture */
if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ||
ssi_private->cpu_dai_drv.symmetric_rates)
- clrsetbits_be32(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl);
+ write_ssi_mask(&ssi->stccr, CCSR_SSI_SxCCR_WL_MASK, wl);
else
- clrsetbits_be32(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl);
+ write_ssi_mask(&ssi->srccr, CCSR_SSI_SxCCR_WL_MASK, wl);
return 0;
}
@@ -466,19 +501,19 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- setbits32(&ssi->scr,
+ write_ssi_mask(&ssi->scr, 0,
CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_TE);
else
- setbits32(&ssi->scr,
+ write_ssi_mask(&ssi->scr, 0,
CCSR_SSI_SCR_SSIEN | CCSR_SSI_SCR_RE);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- clrbits32(&ssi->scr, CCSR_SSI_SCR_TE);
+ write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TE, 0);
else
- clrbits32(&ssi->scr, CCSR_SSI_SCR_RE);
+ write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_RE, 0);
break;
default:
@@ -510,7 +545,7 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
if (!ssi_private->first_stream) {
struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
- clrbits32(&ssi->scr, CCSR_SSI_SCR_SSIEN);
+ write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
}
}
@@ -622,12 +657,6 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev)
if (!of_device_is_available(np))
return -ENODEV;
- /* Check for a codec-handle property. */
- if (!of_get_property(np, "codec-handle", NULL)) {
- dev_err(&pdev->dev, "missing codec-handle property\n");
- return -ENODEV;
- }
-
/* We only support the SSI in "I2S Slave" mode */
sprop = of_get_property(np, "fsl,mode", NULL);
if (!sprop || strcmp(sprop, "i2s-slave")) {
@@ -692,6 +721,50 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev)
/* Older 8610 DTs didn't have the fifo-depth property */
ssi_private->fifo_depth = 8;
+ if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx21-ssi")) {
+ u32 dma_events[2];
+ ssi_private->ssi_on_imx = true;
+
+ ssi_private->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(ssi_private->clk)) {
+ ret = PTR_ERR(ssi_private->clk);
+ dev_err(&pdev->dev, "could not get clock: %d\n", ret);
+ goto error_irq;
+ }
+ clk_prepare_enable(ssi_private->clk);
+
+ /*
+ * We have burstsize be "fifo_depth - 2" to match the SSI
+ * watermark setting in fsl_ssi_startup().
+ */
+ ssi_private->dma_params_tx.burstsize =
+ ssi_private->fifo_depth - 2;
+ ssi_private->dma_params_rx.burstsize =
+ ssi_private->fifo_depth - 2;
+ ssi_private->dma_params_tx.dma_addr =
+ ssi_private->ssi_phys + offsetof(struct ccsr_ssi, stx0);
+ ssi_private->dma_params_rx.dma_addr =
+ ssi_private->ssi_phys + offsetof(struct ccsr_ssi, srx0);
+ /*
+ * TODO: This is a temporary solution and should be changed
+ * to use generic DMA binding later when the helplers get in.
+ */
+ ret = of_property_read_u32_array(pdev->dev.of_node,
+ "fsl,ssi-dma-events", dma_events, 2);
+ if (ret) {
+ dev_err(&pdev->dev, "could not get dma events\n");
+ goto error_clk;
+ }
+ ssi_private->dma_params_tx.dma = dma_events[0];
+ ssi_private->dma_params_rx.dma = dma_events[1];
+
+ ssi_private->dma_params_tx.shared_peripheral =
+ of_device_is_compatible(of_get_parent(np),
+ "fsl,spba-bus");
+ ssi_private->dma_params_rx.shared_peripheral =
+ ssi_private->dma_params_tx.shared_peripheral;
+ }
+
/* Initialize the the device_attribute structure */
dev_attr = &ssi_private->dev_attr;
sysfs_attr_init(&dev_attr->attr);
@@ -715,6 +788,26 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev)
goto error_dev;
}
+ if (ssi_private->ssi_on_imx) {
+ ssi_private->imx_pcm_pdev =
+ platform_device_register_simple("imx-pcm-audio",
+ -1, NULL, 0);
+ if (IS_ERR(ssi_private->imx_pcm_pdev)) {
+ ret = PTR_ERR(ssi_private->imx_pcm_pdev);
+ goto error_dev;
+ }
+ }
+
+ /*
+ * If codec-handle property is missing from SSI node, we assume
+ * that the machine driver uses new binding which does not require
+ * SSI driver to trigger machine driver's probe.
+ */
+ if (!of_get_property(np, "codec-handle", NULL)) {
+ ssi_private->new_binding = true;
+ goto done;
+ }
+
/* Trigger the machine driver's probe function. The platform driver
* name of the machine driver is taken from /compatible property of the
* device tree. We also pass the address of the CPU DAI driver
@@ -736,15 +829,24 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev)
goto error_dai;
}
+done:
return 0;
error_dai:
+ if (ssi_private->ssi_on_imx)
+ platform_device_unregister(ssi_private->imx_pcm_pdev);
snd_soc_unregister_dai(&pdev->dev);
error_dev:
dev_set_drvdata(&pdev->dev, NULL);
device_remove_file(&pdev->dev, dev_attr);
+error_clk:
+ if (ssi_private->ssi_on_imx) {
+ clk_disable_unprepare(ssi_private->clk);
+ clk_put(ssi_private->clk);
+ }
+
error_irq:
free_irq(ssi_private->irq, ssi_private);
@@ -764,7 +866,13 @@ static int fsl_ssi_remove(struct platform_device *pdev)
{
struct fsl_ssi_private *ssi_private = dev_get_drvdata(&pdev->dev);
- platform_device_unregister(ssi_private->pdev);
+ if (!ssi_private->new_binding)
+ platform_device_unregister(ssi_private->pdev);
+ if (ssi_private->ssi_on_imx) {
+ platform_device_unregister(ssi_private->imx_pcm_pdev);
+ clk_disable_unprepare(ssi_private->clk);
+ clk_put(ssi_private->clk);
+ }
snd_soc_unregister_dai(&pdev->dev);
device_remove_file(&pdev->dev, &ssi_private->dev_attr);
@@ -779,6 +887,7 @@ static int fsl_ssi_remove(struct platform_device *pdev)
static const struct of_device_id fsl_ssi_ids[] = {
{ .compatible = "fsl,mpc8610-ssi", },
+ { .compatible = "fsl,imx21-ssi", },
{}
};
MODULE_DEVICE_TABLE(of, fsl_ssi_ids);
diff --git a/sound/soc/fsl/fsl_utils.c b/sound/soc/fsl/fsl_utils.c
new file mode 100644
index 000000000000..b9e42b503a37
--- /dev/null
+++ b/sound/soc/fsl/fsl_utils.c
@@ -0,0 +1,91 @@
+/**
+ * Freescale ALSA SoC Machine driver utility
+ *
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <sound/soc.h>
+
+#include "fsl_utils.h"
+
+/**
+ * fsl_asoc_get_dma_channel - determine the dma channel for a SSI node
+ *
+ * @ssi_np: pointer to the SSI device tree node
+ * @name: name of the phandle pointing to the dma channel
+ * @dai: ASoC DAI link pointer to be filled with platform_name
+ * @dma_channel_id: dma channel id to be returned
+ * @dma_id: dma id to be returned
+ *
+ * This function determines the dma and channel id for given SSI node. It
+ * also discovers the platform_name for the ASoC DAI link.
+ */
+int fsl_asoc_get_dma_channel(struct device_node *ssi_np,
+ const char *name,
+ struct snd_soc_dai_link *dai,
+ unsigned int *dma_channel_id,
+ unsigned int *dma_id)
+{
+ struct resource res;
+ struct device_node *dma_channel_np, *dma_np;
+ const u32 *iprop;
+ int ret;
+
+ dma_channel_np = of_parse_phandle(ssi_np, name, 0);
+ if (!dma_channel_np)
+ return -EINVAL;
+
+ if (!of_device_is_compatible(dma_channel_np, "fsl,ssi-dma-channel")) {
+ of_node_put(dma_channel_np);
+ return -EINVAL;
+ }
+
+ /* Determine the dev_name for the device_node. This code mimics the
+ * behavior of of_device_make_bus_id(). We need this because ASoC uses
+ * the dev_name() of the device to match the platform (DMA) device with
+ * the CPU (SSI) device. It's all ugly and hackish, but it works (for
+ * now).
+ *
+ * dai->platform name should already point to an allocated buffer.
+ */
+ ret = of_address_to_resource(dma_channel_np, 0, &res);
+ if (ret) {
+ of_node_put(dma_channel_np);
+ return ret;
+ }
+ snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s",
+ (unsigned long long) res.start, dma_channel_np->name);
+
+ iprop = of_get_property(dma_channel_np, "cell-index", NULL);
+ if (!iprop) {
+ of_node_put(dma_channel_np);
+ return -EINVAL;
+ }
+ *dma_channel_id = be32_to_cpup(iprop);
+
+ dma_np = of_get_parent(dma_channel_np);
+ iprop = of_get_property(dma_np, "cell-index", NULL);
+ if (!iprop) {
+ of_node_put(dma_np);
+ return -EINVAL;
+ }
+ *dma_id = be32_to_cpup(iprop);
+
+ of_node_put(dma_np);
+ of_node_put(dma_channel_np);
+
+ return 0;
+}
+EXPORT_SYMBOL(fsl_asoc_get_dma_channel);
+
+MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
+MODULE_DESCRIPTION("Freescale ASoC utility code");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/fsl/fsl_utils.h b/sound/soc/fsl/fsl_utils.h
new file mode 100644
index 000000000000..b2951126527c
--- /dev/null
+++ b/sound/soc/fsl/fsl_utils.h
@@ -0,0 +1,26 @@
+/**
+ * Freescale ALSA SoC Machine driver utility
+ *
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef _FSL_UTILS_H
+#define _FSL_UTILS_H
+
+#define DAI_NAME_SIZE 32
+
+struct snd_soc_dai_link;
+struct device_node;
+
+int fsl_asoc_get_dma_channel(struct device_node *ssi_np, const char *name,
+ struct snd_soc_dai_link *dai,
+ unsigned int *dma_channel_id,
+ unsigned int *dma_id);
+
+#endif /* _FSL_UTILS_H */
diff --git a/sound/soc/imx/imx-audmux.c b/sound/soc/fsl/imx-audmux.c
index f23700359c67..f23700359c67 100644
--- a/sound/soc/imx/imx-audmux.c
+++ b/sound/soc/fsl/imx-audmux.c
diff --git a/sound/soc/imx/imx-audmux.h b/sound/soc/fsl/imx-audmux.h
index 04ebbab8d7b9..04ebbab8d7b9 100644
--- a/sound/soc/imx/imx-audmux.h
+++ b/sound/soc/fsl/imx-audmux.h
diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c
new file mode 100644
index 000000000000..f59c34943662
--- /dev/null
+++ b/sound/soc/fsl/imx-mc13783.c
@@ -0,0 +1,156 @@
+/*
+ * imx-mc13783.c -- SoC audio for imx based boards with mc13783 codec
+ *
+ * Copyright 2012 Philippe Retornaz, <philippe.retornaz@epfl.ch>
+ *
+ * Heavly based on phycore-mc13783:
+ * Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ *
+ * 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/moduleparam.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/mach-types.h>
+
+#include "../codecs/mc13783.h"
+#include "imx-ssi.h"
+#include "imx-audmux.h"
+
+#define FMT_SSI (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | \
+ SND_SOC_DAIFMT_CBM_CFM)
+
+static int imx_mc13783_hifi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int ret;
+
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xfffffffc, 0xfffffffc,
+ 4, 16);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, MC13783_CLK_CLIA, 26000000, 0);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x0, 0xfffffffc, 2, 16);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops imx_mc13783_hifi_ops = {
+ .hw_params = imx_mc13783_hifi_hw_params,
+};
+
+static struct snd_soc_dai_link imx_mc13783_dai_mc13783[] = {
+ {
+ .name = "MC13783",
+ .stream_name = "Sound",
+ .codec_dai_name = "mc13783-hifi",
+ .codec_name = "mc13783-codec",
+ .cpu_dai_name = "imx-ssi.0",
+ .platform_name = "imx-pcm-audio.0",
+ .ops = &imx_mc13783_hifi_ops,
+ .symmetric_rates = 1,
+ .dai_fmt = FMT_SSI,
+ },
+};
+
+static const struct snd_soc_dapm_widget imx_mc13783_widget[] = {
+ SND_SOC_DAPM_MIC("Mic", NULL),
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+static const struct snd_soc_dapm_route imx_mc13783_routes[] = {
+ {"Speaker", NULL, "LSP"},
+ {"Headphone", NULL, "HSL"},
+ {"Headphone", NULL, "HSR"},
+
+ {"MC1LIN", NULL, "MC1 Bias"},
+ {"MC2IN", NULL, "MC2 Bias"},
+ {"MC1 Bias", NULL, "Mic"},
+ {"MC2 Bias", NULL, "Mic"},
+};
+
+static struct snd_soc_card imx_mc13783 = {
+ .name = "imx_mc13783",
+ .dai_link = imx_mc13783_dai_mc13783,
+ .num_links = ARRAY_SIZE(imx_mc13783_dai_mc13783),
+ .dapm_widgets = imx_mc13783_widget,
+ .num_dapm_widgets = ARRAY_SIZE(imx_mc13783_widget),
+ .dapm_routes = imx_mc13783_routes,
+ .num_dapm_routes = ARRAY_SIZE(imx_mc13783_routes),
+};
+
+static int __devinit imx_mc13783_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ imx_mc13783.dev = &pdev->dev;
+
+ ret = snd_soc_register_card(&imx_mc13783);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+ return ret;
+ }
+
+ imx_audmux_v2_configure_port(MX31_AUDMUX_PORT4_SSI_PINS_4,
+ IMX_AUDMUX_V2_PTCR_SYN,
+ IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0) |
+ IMX_AUDMUX_V2_PDCR_MODE(1) |
+ IMX_AUDMUX_V2_PDCR_INMMASK(0xfc));
+ imx_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0,
+ IMX_AUDMUX_V2_PTCR_SYN |
+ IMX_AUDMUX_V2_PTCR_TFSDIR |
+ IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
+ IMX_AUDMUX_V2_PTCR_TCLKDIR |
+ IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
+ IMX_AUDMUX_V2_PTCR_RFSDIR |
+ IMX_AUDMUX_V2_PTCR_RFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) |
+ IMX_AUDMUX_V2_PTCR_RCLKDIR |
+ IMX_AUDMUX_V2_PTCR_RCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4),
+ IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT4_SSI_PINS_4));
+
+ return ret;
+}
+
+static int __devexit imx_mc13783_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_card(&imx_mc13783);
+
+ return 0;
+}
+
+static struct platform_driver imx_mc13783_audio_driver = {
+ .driver = {
+ .name = "imx_mc13783",
+ .owner = THIS_MODULE,
+ },
+ .probe = imx_mc13783_probe,
+ .remove = __devexit_p(imx_mc13783_remove)
+};
+
+module_platform_driver(imx_mc13783_audio_driver);
+
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_AUTHOR("Philippe Retornaz <philippe.retornaz@epfl.ch");
+MODULE_DESCRIPTION("imx with mc13783 codec ALSA SoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx_mc13783");
diff --git a/sound/soc/imx/imx-pcm-dma-mx2.c b/sound/soc/fsl/imx-pcm-dma.c
index 6b818de2fc03..f3c0a5ef35c8 100644
--- a/sound/soc/imx/imx-pcm-dma-mx2.c
+++ b/sound/soc/fsl/imx-pcm-dma.c
@@ -109,7 +109,8 @@ static int snd_imx_open(struct snd_pcm_substream *substream)
dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
dma_data = kzalloc(sizeof(*dma_data), GFP_KERNEL);
- dma_data->peripheral_type = IMX_DMATYPE_SSI;
+ dma_data->peripheral_type = dma_params->shared_peripheral ?
+ IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI;
dma_data->priority = DMA_PRIO_HIGH;
dma_data->dma_request = dma_params->dma;
diff --git a/sound/soc/imx/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c
index 456b7d723d66..456b7d723d66 100644
--- a/sound/soc/imx/imx-pcm-fiq.c
+++ b/sound/soc/fsl/imx-pcm-fiq.c
diff --git a/sound/soc/imx/imx-pcm.c b/sound/soc/fsl/imx-pcm.c
index 93dc360b1777..93dc360b1777 100644
--- a/sound/soc/imx/imx-pcm.c
+++ b/sound/soc/fsl/imx-pcm.c
diff --git a/sound/soc/imx/imx-pcm.h b/sound/soc/fsl/imx-pcm.h
index b5f5c3acf34d..83c0ed7d55c9 100644
--- a/sound/soc/imx/imx-pcm.h
+++ b/sound/soc/fsl/imx-pcm.h
@@ -22,6 +22,7 @@ struct imx_pcm_dma_params {
int dma;
unsigned long dma_addr;
int burstsize;
+ bool shared_peripheral; /* The peripheral is on SPBA bus */
};
int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c
new file mode 100644
index 000000000000..3a729caeb8c8
--- /dev/null
+++ b/sound/soc/fsl/imx-sgtl5000.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ * Copyright 2012 Linaro Ltd.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_i2c.h>
+#include <linux/clk.h>
+#include <sound/soc.h>
+
+#include "../codecs/sgtl5000.h"
+#include "imx-audmux.h"
+
+#define DAI_NAME_SIZE 32
+
+struct imx_sgtl5000_data {
+ struct snd_soc_dai_link dai;
+ struct snd_soc_card card;
+ char codec_dai_name[DAI_NAME_SIZE];
+ char platform_name[DAI_NAME_SIZE];
+ struct clk *codec_clk;
+ unsigned int clk_frequency;
+};
+
+static int imx_sgtl5000_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct imx_sgtl5000_data *data = container_of(rtd->card,
+ struct imx_sgtl5000_data, card);
+ struct device *dev = rtd->card->dev;
+ int ret;
+
+ ret = snd_soc_dai_set_sysclk(rtd->codec_dai, SGTL5000_SYSCLK,
+ data->clk_frequency, SND_SOC_CLOCK_IN);
+ if (ret) {
+ dev_err(dev, "could not set codec driver clock params\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget imx_sgtl5000_dapm_widgets[] = {
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_LINE("Line In Jack", NULL),
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_SPK("Line Out Jack", NULL),
+ SND_SOC_DAPM_SPK("Ext Spk", NULL),
+};
+
+static int __devinit imx_sgtl5000_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *ssi_np, *codec_np;
+ struct platform_device *ssi_pdev;
+ struct i2c_client *codec_dev;
+ struct imx_sgtl5000_data *data;
+ int int_port, ext_port;
+ int ret;
+
+ ret = of_property_read_u32(np, "mux-int-port", &int_port);
+ if (ret) {
+ dev_err(&pdev->dev, "mux-int-port missing or invalid\n");
+ return ret;
+ }
+ ret = of_property_read_u32(np, "mux-ext-port", &ext_port);
+ if (ret) {
+ dev_err(&pdev->dev, "mux-ext-port missing or invalid\n");
+ return ret;
+ }
+
+ /*
+ * The port numbering in the hardware manual starts at 1, while
+ * the audmux API expects it starts at 0.
+ */
+ int_port--;
+ ext_port--;
+ ret = imx_audmux_v2_configure_port(int_port,
+ IMX_AUDMUX_V2_PTCR_SYN |
+ IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) |
+ IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) |
+ IMX_AUDMUX_V2_PTCR_TFSDIR |
+ IMX_AUDMUX_V2_PTCR_TCLKDIR,
+ IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port));
+ if (ret) {
+ dev_err(&pdev->dev, "audmux internal port setup failed\n");
+ return ret;
+ }
+ imx_audmux_v2_configure_port(ext_port,
+ IMX_AUDMUX_V2_PTCR_SYN |
+ IMX_AUDMUX_V2_PTCR_TCSEL(int_port),
+ IMX_AUDMUX_V2_PDCR_RXDSEL(int_port));
+ if (ret) {
+ dev_err(&pdev->dev, "audmux external port setup failed\n");
+ return ret;
+ }
+
+ ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0);
+ codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0);
+ if (!ssi_np || !codec_np) {
+ dev_err(&pdev->dev, "phandle missing or invalid\n");
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ssi_pdev = of_find_device_by_node(ssi_np);
+ if (!ssi_pdev) {
+ dev_err(&pdev->dev, "failed to find SSI platform device\n");
+ ret = -EINVAL;
+ goto fail;
+ }
+ codec_dev = of_find_i2c_device_by_node(codec_np);
+ if (!codec_dev) {
+ dev_err(&pdev->dev, "failed to find codec platform device\n");
+ return -EINVAL;
+ }
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ data->codec_clk = clk_get(&codec_dev->dev, NULL);
+ if (IS_ERR(data->codec_clk)) {
+ /* assuming clock enabled by default */
+ data->codec_clk = NULL;
+ ret = of_property_read_u32(codec_np, "clock-frequency",
+ &data->clk_frequency);
+ if (ret) {
+ dev_err(&codec_dev->dev,
+ "clock-frequency missing or invalid\n");
+ goto fail;
+ }
+ } else {
+ data->clk_frequency = clk_get_rate(data->codec_clk);
+ clk_prepare_enable(data->codec_clk);
+ }
+
+ data->dai.name = "HiFi";
+ data->dai.stream_name = "HiFi";
+ data->dai.codec_dai_name = "sgtl5000";
+ data->dai.codec_of_node = codec_np;
+ data->dai.cpu_dai_name = dev_name(&ssi_pdev->dev);
+ data->dai.platform_name = "imx-pcm-audio";
+ data->dai.init = &imx_sgtl5000_dai_init;
+ data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM;
+
+ data->card.dev = &pdev->dev;
+ ret = snd_soc_of_parse_card_name(&data->card, "model");
+ if (ret)
+ goto clk_fail;
+ ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing");
+ if (ret)
+ goto clk_fail;
+ data->card.num_links = 1;
+ data->card.dai_link = &data->dai;
+ data->card.dapm_widgets = imx_sgtl5000_dapm_widgets;
+ data->card.num_dapm_widgets = ARRAY_SIZE(imx_sgtl5000_dapm_widgets);
+
+ ret = snd_soc_register_card(&data->card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+ goto clk_fail;
+ }
+
+ platform_set_drvdata(pdev, data);
+clk_fail:
+ clk_put(data->codec_clk);
+fail:
+ if (ssi_np)
+ of_node_put(ssi_np);
+ if (codec_np)
+ of_node_put(codec_np);
+
+ return ret;
+}
+
+static int __devexit imx_sgtl5000_remove(struct platform_device *pdev)
+{
+ struct imx_sgtl5000_data *data = platform_get_drvdata(pdev);
+
+ if (data->codec_clk) {
+ clk_disable_unprepare(data->codec_clk);
+ clk_put(data->codec_clk);
+ }
+ snd_soc_unregister_card(&data->card);
+
+ return 0;
+}
+
+static const struct of_device_id imx_sgtl5000_dt_ids[] = {
+ { .compatible = "fsl,imx-audio-sgtl5000", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_sgtl5000_dt_ids);
+
+static struct platform_driver imx_sgtl5000_driver = {
+ .driver = {
+ .name = "imx-sgtl5000",
+ .owner = THIS_MODULE,
+ .of_match_table = imx_sgtl5000_dt_ids,
+ },
+ .probe = imx_sgtl5000_probe,
+ .remove = __devexit_p(imx_sgtl5000_remove),
+};
+module_platform_driver(imx_sgtl5000_driver);
+
+MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
+MODULE_DESCRIPTION("Freescale i.MX SGTL5000 ASoC machine driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:imx-sgtl5000");
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/fsl/imx-ssi.c
index 4f81ed456325..cf3ed0362c9c 100644
--- a/sound/soc/imx/imx-ssi.c
+++ b/sound/soc/fsl/imx-ssi.c
@@ -28,7 +28,7 @@
* value. When we read the same register two times (and the register still
* contains the same value) these status bits are not set. We work
* around this by not polling these bits but only wait a fixed delay.
- *
+ *
*/
#include <linux/clk.h>
diff --git a/sound/soc/imx/imx-ssi.h b/sound/soc/fsl/imx-ssi.h
index 5744e86ca878..5744e86ca878 100644
--- a/sound/soc/imx/imx-ssi.h
+++ b/sound/soc/fsl/imx-ssi.h
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index 3fea5a15ffe8..60bcba1bc30e 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -14,18 +14,16 @@
#include <linux/interrupt.h>
#include <linux/of_device.h>
#include <linux/slab.h>
-#include <linux/of_i2c.h>
#include <sound/soc.h>
#include <asm/fsl_guts.h>
#include "fsl_dma.h"
#include "fsl_ssi.h"
+#include "fsl_utils.h"
/* There's only one global utilities register */
static phys_addr_t guts_phys;
-#define DAI_NAME_SIZE 32
-
/**
* mpc8610_hpcd_data: machine-specific ASoC device data
*
@@ -43,7 +41,6 @@ struct mpc8610_hpcd_data {
unsigned int dma_id[2]; /* 0 = DMA1, 1 = DMA2, etc */
unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/
char codec_dai_name[DAI_NAME_SIZE];
- char codec_name[DAI_NAME_SIZE];
char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */
};
@@ -181,141 +178,6 @@ static struct snd_soc_ops mpc8610_hpcd_ops = {
};
/**
- * get_node_by_phandle_name - get a node by its phandle name
- *
- * This function takes a node, the name of a property in that node, and a
- * compatible string. Assuming the property is a phandle to another node,
- * it returns that node, (optionally) if that node is compatible.
- *
- * If the property is not a phandle, or the node it points to is not compatible
- * with the specific string, then NULL is returned.
- */
-static struct device_node *get_node_by_phandle_name(struct device_node *np,
- const char *name,
- const char *compatible)
-{
- const phandle *ph;
- int len;
-
- ph = of_get_property(np, name, &len);
- if (!ph || (len != sizeof(phandle)))
- return NULL;
-
- np = of_find_node_by_phandle(*ph);
- if (!np)
- return NULL;
-
- if (compatible && !of_device_is_compatible(np, compatible)) {
- of_node_put(np);
- return NULL;
- }
-
- return np;
-}
-
-/**
- * get_parent_cell_index -- return the cell-index of the parent of a node
- *
- * Return the value of the cell-index property of the parent of the given
- * node. This is used for DMA channel nodes that need to know the DMA ID
- * of the controller they are on.
- */
-static int get_parent_cell_index(struct device_node *np)
-{
- struct device_node *parent = of_get_parent(np);
- const u32 *iprop;
-
- if (!parent)
- return -1;
-
- iprop = of_get_property(parent, "cell-index", NULL);
- of_node_put(parent);
-
- if (!iprop)
- return -1;
-
- return be32_to_cpup(iprop);
-}
-
-/**
- * codec_node_dev_name - determine the dev_name for a codec node
- *
- * This function determines the dev_name for an I2C node. This is the name
- * that would be returned by dev_name() if this device_node were part of a
- * 'struct device' It's ugly and hackish, but it works.
- *
- * The dev_name for such devices include the bus number and I2C address. For
- * example, "cs4270.0-004f".
- */
-static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
-{
- const u32 *iprop;
- int addr;
- char temp[DAI_NAME_SIZE];
- struct i2c_client *i2c;
-
- of_modalias_node(np, temp, DAI_NAME_SIZE);
-
- iprop = of_get_property(np, "reg", NULL);
- if (!iprop)
- return -EINVAL;
-
- addr = be32_to_cpup(iprop);
-
- /* We need the adapter number */
- i2c = of_find_i2c_device_by_node(np);
- if (!i2c)
- return -ENODEV;
-
- snprintf(buf, len, "%s.%u-%04x", temp, i2c->adapter->nr, addr);
-
- return 0;
-}
-
-static int get_dma_channel(struct device_node *ssi_np,
- const char *name,
- struct snd_soc_dai_link *dai,
- unsigned int *dma_channel_id,
- unsigned int *dma_id)
-{
- struct resource res;
- struct device_node *dma_channel_np;
- const u32 *iprop;
- int ret;
-
- dma_channel_np = get_node_by_phandle_name(ssi_np, name,
- "fsl,ssi-dma-channel");
- if (!dma_channel_np)
- return -EINVAL;
-
- /* Determine the dev_name for the device_node. This code mimics the
- * behavior of of_device_make_bus_id(). We need this because ASoC uses
- * the dev_name() of the device to match the platform (DMA) device with
- * the CPU (SSI) device. It's all ugly and hackish, but it works (for
- * now).
- *
- * dai->platform name should already point to an allocated buffer.
- */
- ret = of_address_to_resource(dma_channel_np, 0, &res);
- if (ret)
- return ret;
- snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s",
- (unsigned long long) res.start, dma_channel_np->name);
-
- iprop = of_get_property(dma_channel_np, "cell-index", NULL);
- if (!iprop) {
- of_node_put(dma_channel_np);
- return -EINVAL;
- }
-
- *dma_channel_id = be32_to_cpup(iprop);
- *dma_id = get_parent_cell_index(dma_channel_np);
- of_node_put(dma_channel_np);
-
- return 0;
-}
-
-/**
* mpc8610_hpcd_probe: platform probe function for the machine driver
*
* Although this is a machine driver, the SSI node is the "master" node with
@@ -352,16 +214,8 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
machine_data->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev);
machine_data->dai[0].ops = &mpc8610_hpcd_ops;
- /* Determine the codec name, it will be used as the codec DAI name */
- ret = codec_node_dev_name(codec_np, machine_data->codec_name,
- DAI_NAME_SIZE);
- if (ret) {
- dev_err(&pdev->dev, "invalid codec node %s\n",
- codec_np->full_name);
- ret = -EINVAL;
- goto error;
- }
- machine_data->dai[0].codec_name = machine_data->codec_name;
+ /* ASoC core can match codec with device node */
+ machine_data->dai[0].codec_of_node = codec_np;
/* The DAI name from the codec (snd_soc_dai_driver.name) */
machine_data->dai[0].codec_dai_name = "cs4270-hifi";
@@ -458,9 +312,10 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
/* Find the playback DMA channel to use. */
machine_data->dai[0].platform_name = machine_data->platform_name[0];
- ret = get_dma_channel(np, "fsl,playback-dma", &machine_data->dai[0],
- &machine_data->dma_channel_id[0],
- &machine_data->dma_id[0]);
+ ret = fsl_asoc_get_dma_channel(np, "fsl,playback-dma",
+ &machine_data->dai[0],
+ &machine_data->dma_channel_id[0],
+ &machine_data->dma_id[0]);
if (ret) {
dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n");
goto error;
@@ -468,9 +323,10 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
/* Find the capture DMA channel to use. */
machine_data->dai[1].platform_name = machine_data->platform_name[1];
- ret = get_dma_channel(np, "fsl,capture-dma", &machine_data->dai[1],
- &machine_data->dma_channel_id[1],
- &machine_data->dma_id[1]);
+ ret = fsl_asoc_get_dma_channel(np, "fsl,capture-dma",
+ &machine_data->dai[1],
+ &machine_data->dma_channel_id[1],
+ &machine_data->dma_id[1]);
if (ret) {
dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n");
goto error;
diff --git a/sound/soc/imx/mx27vis-aic32x4.c b/sound/soc/fsl/mx27vis-aic32x4.c
index f6d04ad4bb39..f6d04ad4bb39 100644
--- a/sound/soc/imx/mx27vis-aic32x4.c
+++ b/sound/soc/fsl/mx27vis-aic32x4.c
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c
index 982a1c944983..50adf4032bcc 100644
--- a/sound/soc/fsl/p1022_ds.c
+++ b/sound/soc/fsl/p1022_ds.c
@@ -14,12 +14,12 @@
#include <linux/interrupt.h>
#include <linux/of_device.h>
#include <linux/slab.h>
-#include <linux/of_i2c.h>
#include <sound/soc.h>
#include <asm/fsl_guts.h>
#include "fsl_dma.h"
#include "fsl_ssi.h"
+#include "fsl_utils.h"
/* P1022-specific PMUXCR and DMUXCR bit definitions */
@@ -57,8 +57,6 @@ static inline void guts_set_dmuxcr(struct ccsr_guts __iomem *guts,
/* There's only one global utilities register */
static phys_addr_t guts_phys;
-#define DAI_NAME_SIZE 32
-
/**
* machine_data: machine-specific ASoC device data
*
@@ -75,7 +73,6 @@ struct machine_data {
unsigned int ssi_id; /* 0 = SSI1, 1 = SSI2, etc */
unsigned int dma_id[2]; /* 0 = DMA1, 1 = DMA2, etc */
unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/
- char codec_name[DAI_NAME_SIZE];
char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */
};
@@ -191,136 +188,6 @@ static struct snd_soc_ops p1022_ds_ops = {
};
/**
- * get_node_by_phandle_name - get a node by its phandle name
- *
- * This function takes a node, the name of a property in that node, and a
- * compatible string. Assuming the property is a phandle to another node,
- * it returns that node, (optionally) if that node is compatible.
- *
- * If the property is not a phandle, or the node it points to is not compatible
- * with the specific string, then NULL is returned.
- */
-static struct device_node *get_node_by_phandle_name(struct device_node *np,
- const char *name, const char *compatible)
-{
- np = of_parse_phandle(np, name, 0);
- if (!np)
- return NULL;
-
- if (!of_device_is_compatible(np, compatible)) {
- of_node_put(np);
- return NULL;
- }
-
- return np;
-}
-
-/**
- * get_parent_cell_index -- return the cell-index of the parent of a node
- *
- * Return the value of the cell-index property of the parent of the given
- * node. This is used for DMA channel nodes that need to know the DMA ID
- * of the controller they are on.
- */
-static int get_parent_cell_index(struct device_node *np)
-{
- struct device_node *parent = of_get_parent(np);
- const u32 *iprop;
- int ret = -1;
-
- if (!parent)
- return -1;
-
- iprop = of_get_property(parent, "cell-index", NULL);
- if (iprop)
- ret = be32_to_cpup(iprop);
-
- of_node_put(parent);
-
- return ret;
-}
-
-/**
- * codec_node_dev_name - determine the dev_name for a codec node
- *
- * This function determines the dev_name for an I2C node. This is the name
- * that would be returned by dev_name() if this device_node were part of a
- * 'struct device' It's ugly and hackish, but it works.
- *
- * The dev_name for such devices include the bus number and I2C address. For
- * example, "cs4270-codec.0-004f".
- */
-static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
-{
- const u32 *iprop;
- int addr;
- char temp[DAI_NAME_SIZE];
- struct i2c_client *i2c;
-
- of_modalias_node(np, temp, DAI_NAME_SIZE);
-
- iprop = of_get_property(np, "reg", NULL);
- if (!iprop)
- return -EINVAL;
-
- addr = be32_to_cpup(iprop);
-
- /* We need the adapter number */
- i2c = of_find_i2c_device_by_node(np);
- if (!i2c)
- return -ENODEV;
-
- snprintf(buf, len, "%s.%u-%04x", temp, i2c->adapter->nr, addr);
-
- return 0;
-}
-
-static int get_dma_channel(struct device_node *ssi_np,
- const char *name,
- struct snd_soc_dai_link *dai,
- unsigned int *dma_channel_id,
- unsigned int *dma_id)
-{
- struct resource res;
- struct device_node *dma_channel_np;
- const u32 *iprop;
- int ret;
-
- dma_channel_np = get_node_by_phandle_name(ssi_np, name,
- "fsl,ssi-dma-channel");
- if (!dma_channel_np)
- return -EINVAL;
-
- /* Determine the dev_name for the device_node. This code mimics the
- * behavior of of_device_make_bus_id(). We need this because ASoC uses
- * the dev_name() of the device to match the platform (DMA) device with
- * the CPU (SSI) device. It's all ugly and hackish, but it works (for
- * now).
- *
- * dai->platform name should already point to an allocated buffer.
- */
- ret = of_address_to_resource(dma_channel_np, 0, &res);
- if (ret) {
- of_node_put(dma_channel_np);
- return ret;
- }
- snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s",
- (unsigned long long) res.start, dma_channel_np->name);
-
- iprop = of_get_property(dma_channel_np, "cell-index", NULL);
- if (!iprop) {
- of_node_put(dma_channel_np);
- return -EINVAL;
- }
-
- *dma_channel_id = be32_to_cpup(iprop);
- *dma_id = get_parent_cell_index(dma_channel_np);
- of_node_put(dma_channel_np);
-
- return 0;
-}
-
-/**
* p1022_ds_probe: platform probe function for the machine driver
*
* Although this is a machine driver, the SSI node is the "master" node with
@@ -357,15 +224,8 @@ static int p1022_ds_probe(struct platform_device *pdev)
mdata->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev);
mdata->dai[0].ops = &p1022_ds_ops;
- /* Determine the codec name, it will be used as the codec DAI name */
- ret = codec_node_dev_name(codec_np, mdata->codec_name, DAI_NAME_SIZE);
- if (ret) {
- dev_err(&pdev->dev, "invalid codec node %s\n",
- codec_np->full_name);
- ret = -EINVAL;
- goto error;
- }
- mdata->dai[0].codec_name = mdata->codec_name;
+ /* ASoC core can match codec with device node */
+ mdata->dai[0].codec_of_node = codec_np;
/* We register two DAIs per SSI, one for playback and the other for
* capture. We support codecs that have separate DAIs for both playback
@@ -462,9 +322,9 @@ static int p1022_ds_probe(struct platform_device *pdev)
/* Find the playback DMA channel to use. */
mdata->dai[0].platform_name = mdata->platform_name[0];
- ret = get_dma_channel(np, "fsl,playback-dma", &mdata->dai[0],
- &mdata->dma_channel_id[0],
- &mdata->dma_id[0]);
+ ret = fsl_asoc_get_dma_channel(np, "fsl,playback-dma", &mdata->dai[0],
+ &mdata->dma_channel_id[0],
+ &mdata->dma_id[0]);
if (ret) {
dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n");
goto error;
@@ -472,9 +332,9 @@ static int p1022_ds_probe(struct platform_device *pdev)
/* Find the capture DMA channel to use. */
mdata->dai[1].platform_name = mdata->platform_name[1];
- ret = get_dma_channel(np, "fsl,capture-dma", &mdata->dai[1],
- &mdata->dma_channel_id[1],
- &mdata->dma_id[1]);
+ ret = fsl_asoc_get_dma_channel(np, "fsl,capture-dma", &mdata->dai[1],
+ &mdata->dma_channel_id[1],
+ &mdata->dma_id[1]);
if (ret) {
dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n");
goto error;
diff --git a/sound/soc/imx/phycore-ac97.c b/sound/soc/fsl/phycore-ac97.c
index f8da6dd115ed..f8da6dd115ed 100644
--- a/sound/soc/imx/phycore-ac97.c
+++ b/sound/soc/fsl/phycore-ac97.c
diff --git a/sound/soc/imx/wm1133-ev1.c b/sound/soc/fsl/wm1133-ev1.c
index fe54a69073e5..fe54a69073e5 100644
--- a/sound/soc/imx/wm1133-ev1.c
+++ b/sound/soc/fsl/wm1133-ev1.c
diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig
new file mode 100644
index 000000000000..610f61251640
--- /dev/null
+++ b/sound/soc/generic/Kconfig
@@ -0,0 +1,4 @@
+config SND_SIMPLE_CARD
+ tristate "ASoC Simple sound card support"
+ help
+ This option enables generic simple sound card support
diff --git a/sound/soc/generic/Makefile b/sound/soc/generic/Makefile
new file mode 100644
index 000000000000..9c3b246792bf
--- /dev/null
+++ b/sound/soc/generic/Makefile
@@ -0,0 +1,3 @@
+snd-soc-simple-card-objs := simple-card.o
+
+obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
new file mode 100644
index 000000000000..b4b4cab30232
--- /dev/null
+++ b/sound/soc/generic/simple-card.c
@@ -0,0 +1,114 @@
+/*
+ * ASoC simple sound card support
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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/platform_device.h>
+#include <linux/module.h>
+#include <sound/simple_card.h>
+
+#define asoc_simple_get_card_info(p) \
+ container_of(p->dai_link, struct asoc_simple_card_info, snd_link)
+
+static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct asoc_simple_card_info *cinfo = asoc_simple_get_card_info(rtd);
+ struct asoc_simple_dai_init_info *iinfo = cinfo->init;
+ struct snd_soc_dai *codec = rtd->codec_dai;
+ struct snd_soc_dai *cpu = rtd->cpu_dai;
+ unsigned int cpu_daifmt = iinfo->fmt | iinfo->cpu_daifmt;
+ unsigned int codec_daifmt = iinfo->fmt | iinfo->codec_daifmt;
+ int ret;
+
+ if (codec_daifmt) {
+ ret = snd_soc_dai_set_fmt(codec, codec_daifmt);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (iinfo->sysclk) {
+ ret = snd_soc_dai_set_sysclk(codec, 0, iinfo->sysclk, 0);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (cpu_daifmt) {
+ ret = snd_soc_dai_set_fmt(cpu, cpu_daifmt);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int asoc_simple_card_probe(struct platform_device *pdev)
+{
+ struct asoc_simple_card_info *cinfo = pdev->dev.platform_data;
+
+ if (!cinfo) {
+ dev_err(&pdev->dev, "no info for asoc-simple-card\n");
+ return -EINVAL;
+ }
+
+ if (!cinfo->name ||
+ !cinfo->card ||
+ !cinfo->cpu_dai ||
+ !cinfo->codec ||
+ !cinfo->platform ||
+ !cinfo->codec_dai) {
+ dev_err(&pdev->dev, "insufficient asoc_simple_card_info settings\n");
+ return -EINVAL;
+ }
+
+ /*
+ * init snd_soc_dai_link
+ */
+ cinfo->snd_link.name = cinfo->name;
+ cinfo->snd_link.stream_name = cinfo->name;
+ cinfo->snd_link.cpu_dai_name = cinfo->cpu_dai;
+ cinfo->snd_link.platform_name = cinfo->platform;
+ cinfo->snd_link.codec_name = cinfo->codec;
+ cinfo->snd_link.codec_dai_name = cinfo->codec_dai;
+
+ /* enable snd_link.init if cinfo has settings */
+ if (cinfo->init)
+ cinfo->snd_link.init = asoc_simple_card_dai_init;
+
+ /*
+ * init snd_soc_card
+ */
+ cinfo->snd_card.name = cinfo->card;
+ cinfo->snd_card.owner = THIS_MODULE;
+ cinfo->snd_card.dai_link = &cinfo->snd_link;
+ cinfo->snd_card.num_links = 1;
+ cinfo->snd_card.dev = &pdev->dev;
+
+ return snd_soc_register_card(&cinfo->snd_card);
+}
+
+static int asoc_simple_card_remove(struct platform_device *pdev)
+{
+ struct asoc_simple_card_info *cinfo = pdev->dev.platform_data;
+
+ return snd_soc_unregister_card(&cinfo->snd_card);
+}
+
+static struct platform_driver asoc_simple_card = {
+ .driver = {
+ .name = "asoc-simple-card",
+ },
+ .probe = asoc_simple_card_probe,
+ .remove = asoc_simple_card_remove,
+};
+
+module_platform_driver(asoc_simple_card);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("ASoC Simple Sound Card");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
deleted file mode 100644
index 810acaa09009..000000000000
--- a/sound/soc/imx/Kconfig
+++ /dev/null
@@ -1,79 +0,0 @@
-menuconfig SND_IMX_SOC
- tristate "SoC Audio for Freescale i.MX CPUs"
- depends on ARCH_MXC
- help
- Say Y or M if you want to add support for codecs attached to
- the i.MX SSI interface.
-
-
-if SND_IMX_SOC
-
-config SND_SOC_IMX_SSI
- tristate
-
-config SND_SOC_IMX_PCM
- tristate
-
-config SND_MXC_SOC_FIQ
- tristate
- select FIQ
- select SND_SOC_IMX_PCM
-
-config SND_MXC_SOC_MX2
- select SND_SOC_DMAENGINE_PCM
- tristate
- select SND_SOC_IMX_PCM
-
-config SND_SOC_IMX_AUDMUX
- tristate
-
-config SND_MXC_SOC_WM1133_EV1
- tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted"
- depends on MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL
- select SND_SOC_WM8350
- select SND_MXC_SOC_FIQ
- select SND_SOC_IMX_AUDMUX
- select SND_SOC_IMX_SSI
- help
- Enable support for audio on the i.MX31ADS with the WM1133-EV1
- PMIC board with WM8835x fitted.
-
-config SND_SOC_MX27VIS_AIC32X4
- tristate "SoC audio support for Visstrim M10 boards"
- depends on MACH_IMX27_VISSTRIM_M10 && I2C
- select SND_SOC_TLV320AIC32X4
- select SND_MXC_SOC_MX2
- select SND_SOC_IMX_AUDMUX
- select SND_SOC_IMX_SSI
- help
- Say Y if you want to add support for SoC audio on Visstrim SM10
- board with TLV320AIC32X4 codec.
-
-config SND_SOC_PHYCORE_AC97
- tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
- depends on MACH_PCM043 || MACH_PCA100
- select SND_SOC_AC97_BUS
- select SND_SOC_WM9712
- select SND_MXC_SOC_FIQ
- select SND_SOC_IMX_AUDMUX
- select SND_SOC_IMX_SSI
- help
- Say Y if you want to add support for SoC audio on Phytec phyCORE
- and phyCARD boards in AC97 mode
-
-config SND_SOC_EUKREA_TLV320
- tristate "Eukrea TLV320"
- depends on MACH_EUKREA_MBIMX27_BASEBOARD \
- || MACH_EUKREA_MBIMXSD25_BASEBOARD \
- || MACH_EUKREA_MBIMXSD35_BASEBOARD \
- || MACH_EUKREA_MBIMXSD51_BASEBOARD
- depends on I2C
- select SND_SOC_TLV320AIC23
- select SND_MXC_SOC_FIQ
- select SND_SOC_IMX_AUDMUX
- select SND_SOC_IMX_SSI
- help
- Enable I2S based access to the TLV320AIC23B codec attached
- to the SSI interface
-
-endif # SND_IMX_SOC
diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile
deleted file mode 100644
index f5db3e92d0d1..000000000000
--- a/sound/soc/imx/Makefile
+++ /dev/null
@@ -1,22 +0,0 @@
-# i.MX Platform Support
-snd-soc-imx-ssi-objs := imx-ssi.o
-snd-soc-imx-audmux-objs := imx-audmux.o
-
-obj-$(CONFIG_SND_SOC_IMX_SSI) += snd-soc-imx-ssi.o
-obj-$(CONFIG_SND_SOC_IMX_AUDMUX) += snd-soc-imx-audmux.o
-
-obj-$(CONFIG_SND_SOC_IMX_PCM) += snd-soc-imx-pcm.o
-snd-soc-imx-pcm-y := imx-pcm.o
-snd-soc-imx-pcm-$(CONFIG_SND_MXC_SOC_FIQ) += imx-pcm-fiq.o
-snd-soc-imx-pcm-$(CONFIG_SND_MXC_SOC_MX2) += imx-pcm-dma-mx2.o
-
-# i.MX Machine Support
-snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
-snd-soc-phycore-ac97-objs := phycore-ac97.o
-snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o
-snd-soc-wm1133-ev1-objs := wm1133-ev1.o
-
-obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
-obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
-obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o
-obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c
index a5af7c42e62b..41349670adab 100644
--- a/sound/soc/jz4740/jz4740-i2s.c
+++ b/sound/soc/jz4740/jz4740-i2s.c
@@ -346,7 +346,7 @@ static void jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s)
/* Playback */
dma_config = &i2s->pcm_config_playback.dma_config;
- dma_config->src_width = JZ4740_DMA_WIDTH_32BIT,
+ dma_config->src_width = JZ4740_DMA_WIDTH_32BIT;
dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
dma_config->request_type = JZ4740_DMA_TYPE_AIC_TRANSMIT;
dma_config->flags = JZ4740_DMA_SRC_AUTOINC;
@@ -355,7 +355,7 @@ static void jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s)
/* Capture */
dma_config = &i2s->pcm_config_capture.dma_config;
- dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT,
+ dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT;
dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE;
dma_config->request_type = JZ4740_DMA_TYPE_AIC_RECEIVE;
dma_config->flags = JZ4740_DMA_DST_AUTOINC;
diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c
index e373fbbc97a0..373dec90579f 100644
--- a/sound/soc/mxs/mxs-pcm.c
+++ b/sound/soc/mxs/mxs-pcm.c
@@ -220,28 +220,16 @@ static struct snd_soc_platform_driver mxs_soc_platform = {
.pcm_free = mxs_pcm_free,
};
-static int __devinit mxs_soc_platform_probe(struct platform_device *pdev)
+int __devinit mxs_pcm_platform_register(struct device *dev)
{
- return snd_soc_register_platform(&pdev->dev, &mxs_soc_platform);
+ return snd_soc_register_platform(dev, &mxs_soc_platform);
}
+EXPORT_SYMBOL_GPL(mxs_pcm_platform_register);
-static int __devexit mxs_soc_platform_remove(struct platform_device *pdev)
+void __devexit mxs_pcm_platform_unregister(struct device *dev)
{
- snd_soc_unregister_platform(&pdev->dev);
-
- return 0;
+ snd_soc_unregister_platform(dev);
}
-
-static struct platform_driver mxs_pcm_driver = {
- .driver = {
- .name = "mxs-pcm-audio",
- .owner = THIS_MODULE,
- },
- .probe = mxs_soc_platform_probe,
- .remove = __devexit_p(mxs_soc_platform_remove),
-};
-
-module_platform_driver(mxs_pcm_driver);
+EXPORT_SYMBOL_GPL(mxs_pcm_platform_unregister);
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:mxs-pcm-audio");
diff --git a/sound/soc/mxs/mxs-pcm.h b/sound/soc/mxs/mxs-pcm.h
index 5f01a9124b3d..35ba2ca42384 100644
--- a/sound/soc/mxs/mxs-pcm.h
+++ b/sound/soc/mxs/mxs-pcm.h
@@ -24,4 +24,7 @@ struct mxs_pcm_dma_params {
int chan_num;
};
+int mxs_pcm_platform_register(struct device *dev);
+void mxs_pcm_platform_unregister(struct device *dev);
+
#endif
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
index 53f4fd8feced..aba71bfa33b1 100644
--- a/sound/soc/mxs/mxs-saif.c
+++ b/sound/soc/mxs/mxs-saif.c
@@ -18,6 +18,8 @@
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
@@ -25,6 +27,7 @@
#include <linux/delay.h>
#include <linux/time.h>
#include <linux/fsl/mxs-dma.h>
+#include <linux/pinctrl/consumer.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -620,34 +623,61 @@ static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int mxs_saif_probe(struct platform_device *pdev)
+static int __devinit mxs_saif_probe(struct platform_device *pdev)
{
+ struct device_node *np = pdev->dev.of_node;
struct resource *iores, *dmares;
struct mxs_saif *saif;
struct mxs_saif_platform_data *pdata;
+ struct pinctrl *pinctrl;
int ret = 0;
- if (pdev->id >= ARRAY_SIZE(mxs_saif))
+
+ if (!np && pdev->id >= ARRAY_SIZE(mxs_saif))
return -EINVAL;
saif = devm_kzalloc(&pdev->dev, sizeof(*saif), GFP_KERNEL);
if (!saif)
return -ENOMEM;
- mxs_saif[pdev->id] = saif;
- saif->id = pdev->id;
-
- pdata = pdev->dev.platform_data;
- if (pdata && !pdata->master_mode) {
- saif->master_id = pdata->master_id;
- if (saif->master_id < 0 ||
- saif->master_id >= ARRAY_SIZE(mxs_saif) ||
- saif->master_id == saif->id) {
- dev_err(&pdev->dev, "get wrong master id\n");
- return -EINVAL;
+ if (np) {
+ struct device_node *master;
+ saif->id = of_alias_get_id(np, "saif");
+ if (saif->id < 0)
+ return saif->id;
+ /*
+ * If there is no "fsl,saif-master" phandle, it's a saif
+ * master. Otherwise, it's a slave and its phandle points
+ * to the master.
+ */
+ master = of_parse_phandle(np, "fsl,saif-master", 0);
+ if (!master) {
+ saif->master_id = saif->id;
+ } else {
+ saif->master_id = of_alias_get_id(master, "saif");
+ if (saif->master_id < 0)
+ return saif->master_id;
}
} else {
- saif->master_id = saif->id;
+ saif->id = pdev->id;
+ pdata = pdev->dev.platform_data;
+ if (pdata && !pdata->master_mode)
+ saif->master_id = pdata->master_id;
+ else
+ saif->master_id = saif->id;
+ }
+
+ if (saif->master_id < 0 || saif->master_id >= ARRAY_SIZE(mxs_saif)) {
+ dev_err(&pdev->dev, "get wrong master id\n");
+ return -EINVAL;
+ }
+
+ mxs_saif[saif->id] = saif;
+
+ pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
+ return ret;
}
saif->clk = clk_get(&pdev->dev, NULL);
@@ -669,12 +699,19 @@ static int mxs_saif_probe(struct platform_device *pdev)
dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!dmares) {
- ret = -ENODEV;
- dev_err(&pdev->dev, "failed to get dma resource: %d\n",
- ret);
- goto failed_get_resource;
+ /*
+ * TODO: This is a temporary solution and should be changed
+ * to use generic DMA binding later when the helplers get in.
+ */
+ ret = of_property_read_u32(np, "fsl,saif-dma-channel",
+ &saif->dma_param.chan_num);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to get dma channel\n");
+ goto failed_get_resource;
+ }
+ } else {
+ saif->dma_param.chan_num = dmares->start;
}
- saif->dma_param.chan_num = dmares->start;
saif->irq = platform_get_irq(pdev, 0);
if (saif->irq < 0) {
@@ -708,24 +745,14 @@ static int mxs_saif_probe(struct platform_device *pdev)
goto failed_get_resource;
}
- saif->soc_platform_pdev = platform_device_alloc(
- "mxs-pcm-audio", pdev->id);
- if (!saif->soc_platform_pdev) {
- ret = -ENOMEM;
- goto failed_pdev_alloc;
- }
-
- platform_set_drvdata(saif->soc_platform_pdev, saif);
- ret = platform_device_add(saif->soc_platform_pdev);
+ ret = mxs_pcm_platform_register(&pdev->dev);
if (ret) {
- dev_err(&pdev->dev, "failed to add soc platform device\n");
- goto failed_pdev_add;
+ dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
+ goto failed_pdev_alloc;
}
return 0;
-failed_pdev_add:
- platform_device_put(saif->soc_platform_pdev);
failed_pdev_alloc:
snd_soc_unregister_dai(&pdev->dev);
failed_get_resource:
@@ -738,13 +765,19 @@ static int __devexit mxs_saif_remove(struct platform_device *pdev)
{
struct mxs_saif *saif = platform_get_drvdata(pdev);
- platform_device_unregister(saif->soc_platform_pdev);
+ mxs_pcm_platform_unregister(&pdev->dev);
snd_soc_unregister_dai(&pdev->dev);
clk_put(saif->clk);
return 0;
}
+static const struct of_device_id mxs_saif_dt_ids[] = {
+ { .compatible = "fsl,imx28-saif", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxs_saif_dt_ids);
+
static struct platform_driver mxs_saif_driver = {
.probe = mxs_saif_probe,
.remove = __devexit_p(mxs_saif_remove),
@@ -752,6 +785,7 @@ static struct platform_driver mxs_saif_driver = {
.driver = {
.name = "mxs-saif",
.owner = THIS_MODULE,
+ .of_match_table = mxs_saif_dt_ids,
},
};
diff --git a/sound/soc/mxs/mxs-saif.h b/sound/soc/mxs/mxs-saif.h
index 12c91e4eb941..3cb342e5bc90 100644
--- a/sound/soc/mxs/mxs-saif.h
+++ b/sound/soc/mxs/mxs-saif.h
@@ -123,7 +123,6 @@ struct mxs_saif {
unsigned int cur_rate;
unsigned int ongoing;
- struct platform_device *soc_platform_pdev;
u32 fifo_underrun;
u32 fifo_overrun;
};
diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c
index 60f052b7cf22..3e6e8764b2e6 100644
--- a/sound/soc/mxs/mxs-sgtl5000.c
+++ b/sound/soc/mxs/mxs-sgtl5000.c
@@ -18,6 +18,8 @@
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
@@ -90,7 +92,7 @@ static struct snd_soc_dai_link mxs_sgtl5000_dai[] = {
.codec_dai_name = "sgtl5000",
.codec_name = "sgtl5000.0-000a",
.cpu_dai_name = "mxs-saif.0",
- .platform_name = "mxs-pcm-audio.0",
+ .platform_name = "mxs-saif.0",
.ops = &mxs_sgtl5000_hifi_ops,
}, {
.name = "HiFi Rx",
@@ -98,7 +100,7 @@ static struct snd_soc_dai_link mxs_sgtl5000_dai[] = {
.codec_dai_name = "sgtl5000",
.codec_name = "sgtl5000.0-000a",
.cpu_dai_name = "mxs-saif.1",
- .platform_name = "mxs-pcm-audio.1",
+ .platform_name = "mxs-saif.1",
.ops = &mxs_sgtl5000_hifi_ops,
},
};
@@ -110,11 +112,48 @@ static struct snd_soc_card mxs_sgtl5000 = {
.num_links = ARRAY_SIZE(mxs_sgtl5000_dai),
};
+static int __devinit mxs_sgtl5000_probe_dt(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *saif_np[2], *codec_np;
+ int i, ret = 0;
+
+ if (!np)
+ return 1; /* no device tree */
+
+ saif_np[0] = of_parse_phandle(np, "saif-controllers", 0);
+ saif_np[1] = of_parse_phandle(np, "saif-controllers", 1);
+ codec_np = of_parse_phandle(np, "audio-codec", 0);
+ if (!saif_np[0] || !saif_np[1] || !codec_np) {
+ dev_err(&pdev->dev, "phandle missing or invalid\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < 2; i++) {
+ mxs_sgtl5000_dai[i].codec_name = NULL;
+ mxs_sgtl5000_dai[i].codec_of_node = codec_np;
+ mxs_sgtl5000_dai[i].cpu_dai_name = NULL;
+ mxs_sgtl5000_dai[i].cpu_dai_of_node = saif_np[i];
+ mxs_sgtl5000_dai[i].platform_name = NULL;
+ mxs_sgtl5000_dai[i].platform_of_node = saif_np[i];
+ }
+
+ of_node_put(codec_np);
+ of_node_put(saif_np[0]);
+ of_node_put(saif_np[1]);
+
+ return ret;
+}
+
static int __devinit mxs_sgtl5000_probe(struct platform_device *pdev)
{
struct snd_soc_card *card = &mxs_sgtl5000;
int ret;
+ ret = mxs_sgtl5000_probe_dt(pdev);
+ if (ret < 0)
+ return ret;
+
/*
* Set an init clock(11.28Mhz) for sgtl5000 initialization(i2c r/w).
* The Sgtl5000 sysclk is derived from saif0 mclk and it's range
@@ -148,10 +187,17 @@ static int __devexit mxs_sgtl5000_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id mxs_sgtl5000_dt_ids[] = {
+ { .compatible = "fsl,mxs-audio-sgtl5000", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxs_sgtl5000_dt_ids);
+
static struct platform_driver mxs_sgtl5000_audio_driver = {
.driver = {
.name = "mxs-sgtl5000",
.owner = THIS_MODULE,
+ .of_match_table = mxs_sgtl5000_dt_ids,
},
.probe = mxs_sgtl5000_probe,
.remove = __devexit_p(mxs_sgtl5000_remove),
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index deafbfaacdbf..9ccfa5e1c11b 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -113,6 +113,7 @@ config SND_OMAP_SOC_OMAP4_HDMI
tristate "SoC Audio support for Texas Instruments OMAP4 HDMI"
depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS && ARCH_OMAP4
select SND_OMAP_SOC_HDMI
+ select SND_SOC_OMAP_HDMI_CODEC
help
Say Y if you want to add support for SoC HDMI audio on Texas Instruments
OMAP4 chips
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index fd04ce139031..1c2aa7fab3fd 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -85,14 +85,12 @@ struct pxa2xx_pcm_dma_data {
char name[20];
};
-static struct pxa2xx_pcm_dma_params *
-pxa_ssp_get_dma_params(struct ssp_device *ssp, int width4, int out)
+static void pxa_ssp_set_dma_params(struct ssp_device *ssp, int width4,
+ int out, struct pxa2xx_pcm_dma_params *dma_data)
{
struct pxa2xx_pcm_dma_data *dma;
- dma = kzalloc(sizeof(struct pxa2xx_pcm_dma_data), GFP_KERNEL);
- if (dma == NULL)
- return NULL;
+ dma = container_of(dma_data, struct pxa2xx_pcm_dma_data, params);
snprintf(dma->name, 20, "SSP%d PCM %s %s", ssp->port_id,
width4 ? "32-bit" : "16-bit", out ? "out" : "in");
@@ -103,8 +101,6 @@ pxa_ssp_get_dma_params(struct ssp_device *ssp, int width4, int out)
(DCMD_INCTRGADDR | DCMD_FLOWSRC)) |
(width4 ? DCMD_WIDTH4 : DCMD_WIDTH2) | DCMD_BURST16;
dma->params.dev_addr = ssp->phys_base + SSDR;
-
- return &dma->params;
}
static int pxa_ssp_startup(struct snd_pcm_substream *substream,
@@ -112,6 +108,7 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,
{
struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
struct ssp_device *ssp = priv->ssp;
+ struct pxa2xx_pcm_dma_data *dma;
int ret = 0;
if (!cpu_dai->active) {
@@ -119,8 +116,10 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,
pxa_ssp_disable(ssp);
}
- kfree(snd_soc_dai_get_dma_data(cpu_dai, substream));
- snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
+ dma = kzalloc(sizeof(struct pxa2xx_pcm_dma_data), GFP_KERNEL);
+ if (!dma)
+ return -ENOMEM;
+ snd_soc_dai_set_dma_data(cpu_dai, substream, &dma->params);
return ret;
}
@@ -573,18 +572,13 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
- /* generate correct DMA params */
- kfree(dma_data);
-
/* Network mode with one active slot (ttsa == 1) can be used
* to force 16-bit frame width on the wire (for S16_LE), even
* with two channels. Use 16-bit DMA transfers for this case.
*/
- dma_data = pxa_ssp_get_dma_params(ssp,
- ((chn == 2) && (ttsa != 1)) || (width == 32),
- substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
-
- snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
+ pxa_ssp_set_dma_params(ssp,
+ ((chn == 2) && (ttsa != 1)) || (width == 32),
+ substream->stream == SNDRV_PCM_STREAM_PLAYBACK, dma_data);
/* we can only change the settings if the port is not in use */
if (pxa_ssp_read_reg(ssp, SSCR0) & SSCR0_SSE)
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index d08583790d23..3075a426124c 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -166,7 +166,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
struct pxa2xx_pcm_dma_params *dma_data;
BUG_ON(IS_ERR(clk_i2s));
- clk_enable(clk_i2s);
+ clk_prepare_enable(clk_i2s);
clk_ena = 1;
pxa_i2s_wait();
@@ -259,7 +259,7 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream,
SACR0 &= ~SACR0_ENB;
pxa_i2s_wait();
if (clk_ena) {
- clk_disable(clk_i2s);
+ clk_disable_unprepare(clk_i2s);
clk_ena = 0;
}
}
diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c
index e7416851bf7d..c82c646b8a08 100644
--- a/sound/soc/samsung/littlemill.c
+++ b/sound/soc/samsung/littlemill.c
@@ -23,10 +23,10 @@ static int littlemill_set_bias_level(struct snd_soc_card *card,
struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
{
- struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+ struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai;
int ret;
- if (dapm->dev != codec_dai->dev)
+ if (dapm->dev != aif1_dai->dev)
return 0;
switch (level) {
@@ -36,7 +36,7 @@ static int littlemill_set_bias_level(struct snd_soc_card *card,
* then do so now, otherwise these are noops.
*/
if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
- ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1,
+ ret = snd_soc_dai_set_pll(aif1_dai, WM8994_FLL1,
WM8994_FLL_SRC_MCLK2, 32768,
sample_rate * 512);
if (ret < 0) {
@@ -44,7 +44,7 @@ static int littlemill_set_bias_level(struct snd_soc_card *card,
return ret;
}
- ret = snd_soc_dai_set_sysclk(codec_dai,
+ ret = snd_soc_dai_set_sysclk(aif1_dai,
WM8994_SYSCLK_FLL1,
sample_rate * 512,
SND_SOC_CLOCK_IN);
@@ -66,25 +66,25 @@ static int littlemill_set_bias_level_post(struct snd_soc_card *card,
struct snd_soc_dapm_context *dapm,
enum snd_soc_bias_level level)
{
- struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+ struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai;
int ret;
- if (dapm->dev != codec_dai->dev)
+ if (dapm->dev != aif1_dai->dev)
return 0;
switch (level) {
case SND_SOC_BIAS_STANDBY:
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK2,
+ ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2,
32768, SND_SOC_CLOCK_IN);
if (ret < 0) {
- pr_err("Failed to switch away from FLL: %d\n", ret);
+ pr_err("Failed to switch away from FLL1: %d\n", ret);
return ret;
}
- ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1,
+ ret = snd_soc_dai_set_pll(aif1_dai, WM8994_FLL1,
0, 0, 0);
if (ret < 0) {
- pr_err("Failed to stop FLL: %d\n", ret);
+ pr_err("Failed to stop FLL1: %d\n", ret);
return ret;
}
break;
@@ -131,6 +131,14 @@ static struct snd_soc_ops littlemill_ops = {
.hw_params = littlemill_hw_params,
};
+static const struct snd_soc_pcm_stream baseband_params = {
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .rate_min = 8000,
+ .rate_max = 8000,
+ .channels_min = 2,
+ .channels_max = 2,
+};
+
static struct snd_soc_dai_link littlemill_dai[] = {
{
.name = "CPU",
@@ -143,13 +151,75 @@ static struct snd_soc_dai_link littlemill_dai[] = {
| SND_SOC_DAIFMT_CBM_CFM,
.ops = &littlemill_ops,
},
+ {
+ .name = "Baseband",
+ .stream_name = "Baseband",
+ .cpu_dai_name = "wm8994-aif2",
+ .codec_dai_name = "wm1250-ev1",
+ .codec_name = "wm1250-ev1.1-0027",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBM_CFM,
+ .ignore_suspend = 1,
+ .params = &baseband_params,
+ },
};
+static int bbclk_ev(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_card *card = w->dapm->card;
+ struct snd_soc_dai *aif2_dai = card->rtd[1].cpu_dai;
+ int ret;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ ret = snd_soc_dai_set_pll(aif2_dai, WM8994_FLL2,
+ WM8994_FLL_SRC_BCLK, 64 * 8000,
+ 8000 * 256);
+ if (ret < 0) {
+ pr_err("Failed to start FLL: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(aif2_dai, WM8994_SYSCLK_FLL2,
+ 8000 * 256,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ pr_err("Failed to set SYSCLK: %d\n", ret);
+ return ret;
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ ret = snd_soc_dai_set_sysclk(aif2_dai, WM8994_SYSCLK_MCLK2,
+ 32768, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ pr_err("Failed to switch away from FLL2: %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_pll(aif2_dai, WM8994_FLL2,
+ 0, 0, 0);
+ if (ret < 0) {
+ pr_err("Failed to stop FLL2: %d\n", ret);
+ return ret;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static struct snd_soc_dapm_widget widgets[] = {
SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("AMIC", NULL),
SND_SOC_DAPM_MIC("DMIC", NULL),
+
+ SND_SOC_DAPM_SUPPLY_S("Baseband Clock", -1, SND_SOC_NOPM, 0, 0,
+ bbclk_ev,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
};
static struct snd_soc_dapm_route audio_paths[] = {
@@ -162,6 +232,8 @@ static struct snd_soc_dapm_route audio_paths[] = {
{ "DMIC", NULL, "MICBIAS2" }, /* Default for DMICBIAS jumper */
{ "DMIC1DAT", NULL, "DMIC" },
{ "DMIC2DAT", NULL, "DMIC" },
+
+ { "AIF2CLK", NULL, "Baseband Clock" },
};
static struct snd_soc_jack littlemill_headset;
@@ -169,10 +241,16 @@ static struct snd_soc_jack littlemill_headset;
static int littlemill_late_probe(struct snd_soc_card *card)
{
struct snd_soc_codec *codec = card->rtd[0].codec;
- struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+ struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai;
+ struct snd_soc_dai *aif2_dai = card->rtd[1].cpu_dai;
int ret;
- ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK2,
+ ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2,
+ 32768, SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_sysclk(aif2_dai, WM8994_SYSCLK_MCLK2,
32768, SND_SOC_CLOCK_IN);
if (ret < 0)
return ret;
diff --git a/sound/soc/samsung/lowland.c b/sound/soc/samsung/lowland.c
index 4adff934f771..6abf341c4a2a 100644
--- a/sound/soc/samsung/lowland.c
+++ b/sound/soc/samsung/lowland.c
@@ -21,33 +21,6 @@
#define MCLK1_RATE (44100 * 512)
#define CLKOUT_RATE (44100 * 256)
-static int lowland_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- int ret;
-
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
- | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
- | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static struct snd_soc_ops lowland_ops = {
- .hw_params = lowland_hw_params,
-};
-
static struct snd_soc_jack lowland_headset;
/* Headset jack detection DAPM pins */
@@ -101,6 +74,25 @@ static int lowland_wm5100_init(struct snd_soc_pcm_runtime *rtd)
return 0;
}
+static int lowland_wm9081_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+
+ snd_soc_dapm_nc_pin(&codec->dapm, "LINEOUT");
+
+ /* At any time the WM9081 is active it will have this clock */
+ return snd_soc_codec_set_sysclk(codec, WM9081_SYSCLK_MCLK, 0,
+ CLKOUT_RATE, 0);
+}
+
+static const struct snd_soc_pcm_stream sub_params = {
+ .formats = SNDRV_PCM_FMTBIT_S32_LE,
+ .rate_min = 44100,
+ .rate_max = 44100,
+ .channels_min = 2,
+ .channels_max = 2,
+};
+
static struct snd_soc_dai_link lowland_dai[] = {
{
.name = "CPU",
@@ -109,7 +101,8 @@ static struct snd_soc_dai_link lowland_dai[] = {
.codec_dai_name = "wm5100-aif1",
.platform_name = "samsung-audio",
.codec_name = "wm5100.1-001a",
- .ops = &lowland_ops,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.init = lowland_wm5100_init,
},
{
@@ -118,24 +111,20 @@ static struct snd_soc_dai_link lowland_dai[] = {
.cpu_dai_name = "wm5100-aif2",
.codec_dai_name = "wm1250-ev1",
.codec_name = "wm1250-ev1.1-0027",
- .ops = &lowland_ops,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
.ignore_suspend = 1,
},
-};
-
-static int lowland_wm9081_init(struct snd_soc_dapm_context *dapm)
-{
- snd_soc_dapm_nc_pin(dapm, "LINEOUT");
-
- /* At any time the WM9081 is active it will have this clock */
- return snd_soc_codec_set_sysclk(dapm->codec, WM9081_SYSCLK_MCLK, 0,
- CLKOUT_RATE, 0);
-}
-
-static struct snd_soc_aux_dev lowland_aux_dev[] = {
{
- .name = "wm9081",
+ .name = "Sub Speaker",
+ .stream_name = "Sub Speaker",
+ .cpu_dai_name = "wm5100-aif3",
+ .codec_dai_name = "wm9081-hifi",
.codec_name = "wm9081.1-006c",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
+ .ignore_suspend = 1,
+ .params = &sub_params,
.init = lowland_wm9081_init,
},
};
@@ -180,8 +169,6 @@ static struct snd_soc_card lowland = {
.owner = THIS_MODULE,
.dai_link = lowland_dai,
.num_links = ARRAY_SIZE(lowland_dai),
- .aux_dev = lowland_aux_dev,
- .num_aux_devs = ARRAY_SIZE(lowland_aux_dev),
.codec_conf = lowland_codec_conf,
.num_configs = ARRAY_SIZE(lowland_codec_conf),
diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c
index f9ab7707a3e4..a4a9fc7e8c76 100644
--- a/sound/soc/samsung/speyside.c
+++ b/sound/soc/samsung/speyside.c
@@ -92,33 +92,6 @@ static int speyside_set_bias_level_post(struct snd_soc_card *card,
return 0;
}
-static int speyside_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- int ret;
-
- ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
- | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
- | SND_SOC_DAIFMT_NB_NF
- | SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static struct snd_soc_ops speyside_ops = {
- .hw_params = speyside_hw_params,
-};
-
static struct snd_soc_jack speyside_headset;
/* Headset jack detection DAPM pins */
@@ -208,7 +181,8 @@ static struct snd_soc_dai_link speyside_dai[] = {
.platform_name = "samsung-audio",
.codec_name = "wm8996.1-001a",
.init = speyside_wm8996_init,
- .ops = &speyside_ops,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBM_CFM,
},
{
.name = "Baseband",
@@ -216,7 +190,8 @@ static struct snd_soc_dai_link speyside_dai[] = {
.cpu_dai_name = "wm8996-aif2",
.codec_dai_name = "wm1250-ev1",
.codec_name = "wm1250-ev1.1-0027",
- .ops = &speyside_ops,
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBM_CFM,
.ignore_suspend = 1,
},
};
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
index d8e06a607a22..6bcb1164d599 100644
--- a/sound/soc/sh/Kconfig
+++ b/sound/soc/sh/Kconfig
@@ -22,6 +22,7 @@ config SND_SOC_SH4_SSI
config SND_SOC_SH4_FSI
tristate "SH4 FSI support"
+ select SND_SIMPLE_CARD
help
This option enables FSI sound support
@@ -46,29 +47,6 @@ config SND_SH7760_AC97
This option enables generic sound support for the first
AC97 unit of the SH7760.
-config SND_FSI_AK4642
- tristate "FSI-AK4642 sound support"
- depends on SND_SOC_SH4_FSI && I2C
- select SND_SOC_AK4642
- help
- This option enables generic sound support for the
- FSI - AK4642 unit
-
-config SND_FSI_DA7210
- tristate "FSI-DA7210 sound support"
- depends on SND_SOC_SH4_FSI && I2C
- select SND_SOC_DA7210
- help
- This option enables generic sound support for the
- FSI - DA7210 unit
-
-config SND_FSI_HDMI
- tristate "FSI-HDMI sound support"
- depends on SND_SOC_SH4_FSI && FB_SH_MOBILE_HDMI
- help
- This option enables generic sound support for the
- FSI - HDMI unit
-
config SND_SIU_MIGOR
tristate "SIU sound support on Migo-R"
depends on SH_MIGOR
diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile
index 94476d4c0fd5..849b387d17d9 100644
--- a/sound/soc/sh/Makefile
+++ b/sound/soc/sh/Makefile
@@ -14,13 +14,7 @@ obj-$(CONFIG_SND_SOC_SH4_SIU) += snd-soc-siu.o
## boards
snd-soc-sh7760-ac97-objs := sh7760-ac97.o
-snd-soc-fsi-ak4642-objs := fsi-ak4642.o
-snd-soc-fsi-da7210-objs := fsi-da7210.o
-snd-soc-fsi-hdmi-objs := fsi-hdmi.o
snd-soc-migor-objs := migor.o
obj-$(CONFIG_SND_SH7760_AC97) += snd-soc-sh7760-ac97.o
-obj-$(CONFIG_SND_FSI_AK4642) += snd-soc-fsi-ak4642.o
-obj-$(CONFIG_SND_FSI_DA7210) += snd-soc-fsi-da7210.o
-obj-$(CONFIG_SND_FSI_HDMI) += snd-soc-fsi-hdmi.o
obj-$(CONFIG_SND_SIU_MIGOR) += snd-soc-migor.o
diff --git a/sound/soc/sh/fsi-ak4642.c b/sound/soc/sh/fsi-ak4642.c
deleted file mode 100644
index 97f540aabbdd..000000000000
--- a/sound/soc/sh/fsi-ak4642.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * FSI-AK464x sound support for ms7724se
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <sound/sh_fsi.h>
-
-struct fsi_ak4642_data {
- const char *name;
- const char *card;
- const char *cpu_dai;
- const char *codec;
- const char *platform;
- int id;
-};
-
-static int fsi_ak4642_dai_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_dai *codec = rtd->codec_dai;
- struct snd_soc_dai *cpu = rtd->cpu_dai;
- int ret;
-
- ret = snd_soc_dai_set_fmt(codec, SND_SOC_DAIFMT_LEFT_J |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_sysclk(codec, 0, 11289600, 0);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_fmt(cpu, SND_SOC_DAIFMT_LEFT_J |
- SND_SOC_DAIFMT_CBS_CFS);
-
- return ret;
-}
-
-static struct snd_soc_dai_link fsi_dai_link = {
- .codec_dai_name = "ak4642-hifi",
- .init = fsi_ak4642_dai_init,
-};
-
-static struct snd_soc_card fsi_soc_card = {
- .owner = THIS_MODULE,
- .dai_link = &fsi_dai_link,
- .num_links = 1,
-};
-
-static struct platform_device *fsi_snd_device;
-
-static int fsi_ak4642_probe(struct platform_device *pdev)
-{
- int ret = -ENOMEM;
- struct fsi_ak4642_info *pinfo = pdev->dev.platform_data;
-
- if (!pinfo) {
- dev_err(&pdev->dev, "no info for fsi ak4642\n");
- goto out;
- }
-
- fsi_snd_device = platform_device_alloc("soc-audio", pinfo->id);
- if (!fsi_snd_device)
- goto out;
-
- fsi_dai_link.name = pinfo->name;
- fsi_dai_link.stream_name = pinfo->name;
- fsi_dai_link.cpu_dai_name = pinfo->cpu_dai;
- fsi_dai_link.platform_name = pinfo->platform;
- fsi_dai_link.codec_name = pinfo->codec;
- fsi_soc_card.name = pinfo->card;
-
- platform_set_drvdata(fsi_snd_device, &fsi_soc_card);
- ret = platform_device_add(fsi_snd_device);
-
- if (ret)
- platform_device_put(fsi_snd_device);
-
-out:
- return ret;
-}
-
-static int fsi_ak4642_remove(struct platform_device *pdev)
-{
- platform_device_unregister(fsi_snd_device);
- return 0;
-}
-
-static struct platform_driver fsi_ak4642 = {
- .driver = {
- .name = "fsi-ak4642-audio",
- },
- .probe = fsi_ak4642_probe,
- .remove = fsi_ak4642_remove,
-};
-
-module_platform_driver(fsi_ak4642);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Generic SH4 FSI-AK4642 sound card");
-MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
diff --git a/sound/soc/sh/fsi-da7210.c b/sound/soc/sh/fsi-da7210.c
deleted file mode 100644
index 1dd3354c7411..000000000000
--- a/sound/soc/sh/fsi-da7210.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * fsi-da7210.c
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <sound/sh_fsi.h>
-
-static int fsi_da7210_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_dai *codec = rtd->codec_dai;
- struct snd_soc_dai *cpu = rtd->cpu_dai;
- int ret;
-
- ret = snd_soc_dai_set_fmt(codec,
- SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0)
- return ret;
-
- ret = snd_soc_dai_set_fmt(cpu, SND_SOC_DAIFMT_I2S |
- SND_SOC_DAIFMT_CBS_CFS);
-
- return ret;
-}
-
-static struct snd_soc_dai_link fsi_da7210_dai = {
- .name = "DA7210",
- .stream_name = "DA7210",
- .cpu_dai_name = "fsib-dai", /* FSI B */
- .codec_dai_name = "da7210-hifi",
- .platform_name = "sh_fsi.0",
- .codec_name = "da7210-codec.0-001a",
- .init = fsi_da7210_init,
-};
-
-static struct snd_soc_card fsi_soc_card = {
- .name = "FSI-DA7210",
- .owner = THIS_MODULE,
- .dai_link = &fsi_da7210_dai,
- .num_links = 1,
-};
-
-static struct platform_device *fsi_da7210_snd_device;
-
-static int __init fsi_da7210_sound_init(void)
-{
- int ret;
-
- fsi_da7210_snd_device = platform_device_alloc("soc-audio", FSI_PORT_B);
- if (!fsi_da7210_snd_device)
- return -ENOMEM;
-
- platform_set_drvdata(fsi_da7210_snd_device, &fsi_soc_card);
- ret = platform_device_add(fsi_da7210_snd_device);
- if (ret)
- platform_device_put(fsi_da7210_snd_device);
-
- return ret;
-}
-
-static void __exit fsi_da7210_sound_exit(void)
-{
- platform_device_unregister(fsi_da7210_snd_device);
-}
-
-module_init(fsi_da7210_sound_init);
-module_exit(fsi_da7210_sound_exit);
-
-/* Module information */
-MODULE_DESCRIPTION("ALSA SoC FSI DA2710");
-MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>");
-MODULE_LICENSE("GPL");
diff --git a/sound/soc/sh/fsi-hdmi.c b/sound/soc/sh/fsi-hdmi.c
deleted file mode 100644
index 6e41908323e8..000000000000
--- a/sound/soc/sh/fsi-hdmi.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * FSI - HDMI sound support
- *
- * Copyright (C) 2010 Renesas Solutions Corp.
- * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <sound/sh_fsi.h>
-
-struct fsi_hdmi_data {
- const char *cpu_dai;
- const char *card;
- int id;
-};
-
-static int fsi_hdmi_dai_init(struct snd_soc_pcm_runtime *rtd)
-{
- struct snd_soc_dai *cpu = rtd->cpu_dai;
- int ret;
-
- ret = snd_soc_dai_set_fmt(cpu, SND_SOC_DAIFMT_CBM_CFM);
-
- return ret;
-}
-
-static struct snd_soc_dai_link fsi_dai_link = {
- .name = "HDMI",
- .stream_name = "HDMI",
- .codec_dai_name = "sh_mobile_hdmi-hifi",
- .platform_name = "sh_fsi2",
- .codec_name = "sh-mobile-hdmi",
- .init = fsi_hdmi_dai_init,
-};
-
-static struct snd_soc_card fsi_soc_card = {
- .owner = THIS_MODULE,
- .dai_link = &fsi_dai_link,
- .num_links = 1,
-};
-
-static struct platform_device *fsi_snd_device;
-
-static int fsi_hdmi_probe(struct platform_device *pdev)
-{
- int ret = -ENOMEM;
- const struct platform_device_id *id_entry;
- struct fsi_hdmi_data *pdata;
-
- id_entry = pdev->id_entry;
- if (!id_entry) {
- dev_err(&pdev->dev, "unknown fsi hdmi\n");
- return -ENODEV;
- }
-
- pdata = (struct fsi_hdmi_data *)id_entry->driver_data;
-
- fsi_snd_device = platform_device_alloc("soc-audio", pdata->id);
- if (!fsi_snd_device)
- goto out;
-
- fsi_dai_link.cpu_dai_name = pdata->cpu_dai;
- fsi_soc_card.name = pdata->card;
-
- platform_set_drvdata(fsi_snd_device, &fsi_soc_card);
- ret = platform_device_add(fsi_snd_device);
-
- if (ret)
- platform_device_put(fsi_snd_device);
-
-out:
- return ret;
-}
-
-static int fsi_hdmi_remove(struct platform_device *pdev)
-{
- platform_device_unregister(fsi_snd_device);
- return 0;
-}
-
-static struct fsi_hdmi_data fsi2_a_hdmi = {
- .cpu_dai = "fsia-dai",
- .card = "FSI2A-HDMI",
- .id = FSI_PORT_A,
-};
-
-static struct fsi_hdmi_data fsi2_b_hdmi = {
- .cpu_dai = "fsib-dai",
- .card = "FSI2B-HDMI",
- .id = FSI_PORT_B,
-};
-
-static struct platform_device_id fsi_id_table[] = {
- /* FSI 2 */
- { "sh_fsi2_a_hdmi", (kernel_ulong_t)&fsi2_a_hdmi },
- { "sh_fsi2_b_hdmi", (kernel_ulong_t)&fsi2_b_hdmi },
- {},
-};
-
-static struct platform_driver fsi_hdmi = {
- .driver = {
- .name = "fsi-hdmi-audio",
- },
- .probe = fsi_hdmi_probe,
- .remove = fsi_hdmi_remove,
- .id_table = fsi_id_table,
-};
-
-module_platform_driver(fsi_hdmi);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Generic SH4 FSI-HDMI sound card");
-MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 74ed2dffbffd..7cee22515d9d 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -132,6 +132,25 @@
typedef int (*set_rate_func)(struct device *dev, int rate, int enable);
/*
+ * bus options
+ *
+ * 0x000000BA
+ *
+ * A : sample widtht 16bit setting
+ * B : sample widtht 24bit setting
+ */
+
+#define SHIFT_16DATA 0
+#define SHIFT_24DATA 4
+
+#define PACKAGE_24BITBUS_BACK 0
+#define PACKAGE_24BITBUS_FRONT 1
+#define PACKAGE_16BITBUS_STREAM 2
+
+#define BUSOP_SET(s, a) ((a) << SHIFT_ ## s ## DATA)
+#define BUSOP_GET(s, a) (((a) >> SHIFT_ ## s ## DATA) & 0xF)
+
+/*
* FSI driver use below type name for variable
*
* xxx_num : number of data
@@ -189,6 +208,11 @@ struct fsi_stream {
int oerr_num;
/*
+ * bus options
+ */
+ u32 bus_option;
+
+ /*
* thse are initialized by fsi_handler_init()
*/
struct fsi_stream_handler *handler;
@@ -211,8 +235,7 @@ struct fsi_priv {
struct fsi_stream playback;
struct fsi_stream capture;
- u32 do_fmt;
- u32 di_fmt;
+ u32 fmt;
int chan_num:16;
int clk_master:1;
@@ -321,6 +344,10 @@ static void _fsi_master_mask_set(struct fsi_master *master,
/*
* basic function
*/
+static int fsi_version(struct fsi_master *master)
+{
+ return master->core->ver;
+}
static struct fsi_master *fsi_get_master(struct fsi_priv *fsi)
{
@@ -495,6 +522,7 @@ static void fsi_stream_init(struct fsi_priv *fsi,
io->period_samples = fsi_frame2sample(fsi, runtime->period_size);
io->period_pos = 0;
io->sample_width = samples_to_bytes(runtime, 1);
+ io->bus_option = 0;
io->oerr_num = -1; /* ignore 1st err */
io->uerr_num = -1; /* ignore 1st err */
fsi_stream_handler_call(io, init, fsi, io);
@@ -522,6 +550,7 @@ static void fsi_stream_quit(struct fsi_priv *fsi, struct fsi_stream *io)
io->period_samples = 0;
io->period_pos = 0;
io->sample_width = 0;
+ io->bus_option = 0;
io->oerr_num = 0;
io->uerr_num = 0;
spin_unlock_irqrestore(&master->lock, flags);
@@ -581,6 +610,53 @@ static int fsi_stream_remove(struct fsi_priv *fsi)
}
/*
+ * format/bus/dma setting
+ */
+static void fsi_format_bus_setup(struct fsi_priv *fsi, struct fsi_stream *io,
+ u32 bus, struct device *dev)
+{
+ struct fsi_master *master = fsi_get_master(fsi);
+ int is_play = fsi_stream_is_play(fsi, io);
+ u32 fmt = fsi->fmt;
+
+ if (fsi_version(master) >= 2) {
+ u32 dma = 0;
+
+ /*
+ * FSI2 needs DMA/Bus setting
+ */
+ switch (bus) {
+ case PACKAGE_24BITBUS_FRONT:
+ fmt |= CR_BWS_24;
+ dma |= VDMD_FRONT;
+ dev_dbg(dev, "24bit bus / package in front\n");
+ break;
+ case PACKAGE_16BITBUS_STREAM:
+ fmt |= CR_BWS_16;
+ dma |= VDMD_STREAM;
+ dev_dbg(dev, "16bit bus / stream mode\n");
+ break;
+ case PACKAGE_24BITBUS_BACK:
+ default:
+ fmt |= CR_BWS_24;
+ dma |= VDMD_BACK;
+ dev_dbg(dev, "24bit bus / package in back\n");
+ break;
+ }
+
+ if (is_play)
+ fsi_reg_write(fsi, OUT_DMAC, dma);
+ else
+ fsi_reg_write(fsi, IN_DMAC, dma);
+ }
+
+ if (is_play)
+ fsi_reg_write(fsi, DO_FMT, fmt);
+ else
+ fsi_reg_write(fsi, DI_FMT, fmt);
+}
+
+/*
* irq function
*/
@@ -629,11 +705,6 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
struct fsi_master *master = fsi_get_master(fsi);
u32 mask, val;
- if (master->core->ver < 2) {
- pr_err("fsi: register access err (%s)\n", __func__);
- return;
- }
-
mask = BP | SE;
val = enable ? mask : 0;
@@ -648,9 +719,7 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable)
static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi,
long rate, int enable)
{
- struct fsi_master *master = fsi_get_master(fsi);
set_rate_func set_rate = fsi_get_info_set_rate(fsi);
- int fsi_ver = master->core->ver;
int ret;
if (!set_rate)
@@ -682,10 +751,7 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi,
data |= (0x3 << 12);
break;
case SH_FSI_ACKMD_32:
- if (fsi_ver < 2)
- dev_err(dev, "unsupported ACKMD\n");
- else
- data |= (0x4 << 12);
+ data |= (0x4 << 12);
break;
}
@@ -708,10 +774,7 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi,
data |= (0x4 << 8);
break;
case SH_FSI_BPFMD_16:
- if (fsi_ver < 2)
- dev_err(dev, "unsupported ACKMD\n");
- else
- data |= (0x7 << 8);
+ data |= (0x7 << 8);
break;
}
@@ -728,11 +791,26 @@ static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi,
*/
static void fsi_pio_push16(struct fsi_priv *fsi, u8 *_buf, int samples)
{
- u16 *buf = (u16 *)_buf;
+ u32 enable_stream = fsi_get_info_flags(fsi) & SH_FSI_ENABLE_STREAM_MODE;
int i;
- for (i = 0; i < samples; i++)
- fsi_reg_write(fsi, DODT, ((u32)*(buf + i) << 8));
+ if (enable_stream) {
+ /*
+ * stream mode
+ * see
+ * fsi_pio_push_init()
+ */
+ u32 *buf = (u32 *)_buf;
+
+ for (i = 0; i < samples / 2; i++)
+ fsi_reg_write(fsi, DODT, buf[i]);
+ } else {
+ /* normal mode */
+ u16 *buf = (u16 *)_buf;
+
+ for (i = 0; i < samples; i++)
+ fsi_reg_write(fsi, DODT, ((u32)*(buf + i) << 8));
+ }
}
static void fsi_pio_pop16(struct fsi_priv *fsi, u8 *_buf, int samples)
@@ -872,12 +950,44 @@ static void fsi_pio_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0);
}
+static int fsi_pio_push_init(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+ u32 enable_stream = fsi_get_info_flags(fsi) & SH_FSI_ENABLE_STREAM_MODE;
+
+ /*
+ * we can use 16bit stream mode
+ * when "playback" and "16bit data"
+ * and platform allows "stream mode"
+ * see
+ * fsi_pio_push16()
+ */
+ if (enable_stream)
+ io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
+ BUSOP_SET(16, PACKAGE_16BITBUS_STREAM);
+ else
+ io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
+ BUSOP_SET(16, PACKAGE_24BITBUS_BACK);
+ return 0;
+}
+
+static int fsi_pio_pop_init(struct fsi_priv *fsi, struct fsi_stream *io)
+{
+ /*
+ * always 24bit bus, package back when "capture"
+ */
+ io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
+ BUSOP_SET(16, PACKAGE_24BITBUS_BACK);
+ return 0;
+}
+
static struct fsi_stream_handler fsi_pio_push_handler = {
+ .init = fsi_pio_push_init,
.transfer = fsi_pio_push,
.start_stop = fsi_pio_start_stop,
};
static struct fsi_stream_handler fsi_pio_pop_handler = {
+ .init = fsi_pio_pop_init,
.transfer = fsi_pio_pop,
.start_stop = fsi_pio_start_stop,
};
@@ -919,6 +1029,13 @@ static int fsi_dma_init(struct fsi_priv *fsi, struct fsi_stream *io)
enum dma_data_direction dir = fsi_stream_is_play(fsi, io) ?
DMA_TO_DEVICE : DMA_FROM_DEVICE;
+ /*
+ * 24bit data : 24bit bus / package in back
+ * 16bit data : 16bit bus / stream mode
+ */
+ io->bus_option = BUSOP_SET(24, PACKAGE_24BITBUS_BACK) |
+ BUSOP_SET(16, PACKAGE_16BITBUS_STREAM);
+
io->dma = dma_map_single(dai->dev, runtime->dma_area,
snd_pcm_lib_buffer_bytes(io->substream), dir);
return 0;
@@ -1055,25 +1172,9 @@ static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io)
static void fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io,
int start)
{
- u32 bws;
- u32 dma;
+ u32 enable = start ? DMA_ON : 0;
- switch (io->sample_width * start) {
- case 2:
- bws = CR_BWS_16;
- dma = VDMD_STREAM | DMA_ON;
- break;
- case 4:
- bws = CR_BWS_24;
- dma = VDMD_BACK | DMA_ON;
- break;
- default:
- bws = 0;
- dma = 0;
- }
-
- fsi_reg_mask_set(fsi, DO_FMT, CR_BWS_MASK, bws);
- fsi_reg_write(fsi, OUT_DMAC, dma);
+ fsi_reg_mask_set(fsi, OUT_DMAC, DMA_ON, enable);
}
static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io)
@@ -1176,8 +1277,6 @@ static int fsi_hw_startup(struct fsi_priv *fsi,
struct fsi_stream *io,
struct device *dev)
{
- struct fsi_master *master = fsi_get_master(fsi);
- int fsi_ver = master->core->ver;
u32 flags = fsi_get_info_flags(fsi);
u32 data = 0;
@@ -1200,10 +1299,6 @@ static int fsi_hw_startup(struct fsi_priv *fsi,
fsi_reg_write(fsi, CKG2, data);
- /* set format */
- fsi_reg_write(fsi, DO_FMT, fsi->do_fmt);
- fsi_reg_write(fsi, DI_FMT, fsi->di_fmt);
-
/* spdif ? */
if (fsi_is_spdif(fsi)) {
fsi_spdif_clk_ctrl(fsi, 1);
@@ -1211,15 +1306,18 @@ static int fsi_hw_startup(struct fsi_priv *fsi,
}
/*
- * FIXME
- *
- * FSI driver assumed that data package is in-back.
- * FSI2 chip can select it.
+ * get bus settings
*/
- if (fsi_ver >= 2) {
- fsi_reg_write(fsi, OUT_DMAC, (1 << 4));
- fsi_reg_write(fsi, IN_DMAC, (1 << 4));
+ data = 0;
+ switch (io->sample_width) {
+ case 2:
+ data = BUSOP_GET(16, io->bus_option);
+ break;
+ case 4:
+ data = BUSOP_GET(24, io->bus_option);
+ break;
}
+ fsi_format_bus_setup(fsi, io, data, dev);
/* irq clear */
fsi_irq_disable(fsi, io);
@@ -1243,7 +1341,9 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream,
{
struct fsi_priv *fsi = fsi_get_priv(substream);
- return fsi_hw_startup(fsi, fsi_stream_get(fsi, substream), dai->dev);
+ fsi->rate = 0;
+
+ return 0;
}
static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
@@ -1251,7 +1351,6 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream,
{
struct fsi_priv *fsi = fsi_get_priv(substream);
- fsi_hw_shutdown(fsi, dai->dev);
fsi->rate = 0;
}
@@ -1265,11 +1364,13 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
fsi_stream_init(fsi, io, substream);
+ fsi_hw_startup(fsi, io, dai->dev);
ret = fsi_stream_transfer(io);
if (0 == ret)
fsi_stream_start(fsi, io);
break;
case SNDRV_PCM_TRIGGER_STOP:
+ fsi_hw_shutdown(fsi, dai->dev);
fsi_stream_stop(fsi, io);
fsi_stream_quit(fsi, io);
break;
@@ -1280,42 +1381,33 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
static int fsi_set_fmt_dai(struct fsi_priv *fsi, unsigned int fmt)
{
- u32 data = 0;
-
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
- data = CR_I2S;
+ fsi->fmt = CR_I2S;
fsi->chan_num = 2;
break;
case SND_SOC_DAIFMT_LEFT_J:
- data = CR_PCM;
+ fsi->fmt = CR_PCM;
fsi->chan_num = 2;
break;
default:
return -EINVAL;
}
- fsi->do_fmt = data;
- fsi->di_fmt = data;
-
return 0;
}
static int fsi_set_fmt_spdif(struct fsi_priv *fsi)
{
struct fsi_master *master = fsi_get_master(fsi);
- u32 data = 0;
- if (master->core->ver < 2)
+ if (fsi_version(master) < 2)
return -EINVAL;
- data = CR_BWS_16 | CR_DTMD_SPDIF_PCM | CR_PCM;
+ fsi->fmt = CR_DTMD_SPDIF_PCM | CR_PCM;
fsi->chan_num = 2;
fsi->spdif = 1;
- fsi->do_fmt = data;
- fsi->di_fmt = data;
-
return 0;
}
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index c88d9741b9e7..b37ee8077ed1 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -39,6 +39,7 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <sound/soc-dpcm.h>
#include <sound/initval.h>
#define CREATE_TRACE_POINTS
@@ -54,7 +55,6 @@ EXPORT_SYMBOL_GPL(snd_soc_debugfs_root);
#endif
static DEFINE_MUTEX(client_mutex);
-static LIST_HEAD(card_list);
static LIST_HEAD(dai_list);
static LIST_HEAD(platform_list);
static LIST_HEAD(codec_list);
@@ -465,6 +465,35 @@ static inline void soc_cleanup_card_debugfs(struct snd_soc_card *card)
}
#endif
+struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
+ const char *dai_link, int stream)
+{
+ int i;
+
+ for (i = 0; i < card->num_links; i++) {
+ if (card->rtd[i].dai_link->no_pcm &&
+ !strcmp(card->rtd[i].dai_link->name, dai_link))
+ return card->rtd[i].pcm->streams[stream].substream;
+ }
+ dev_dbg(card->dev, "failed to find dai link %s\n", dai_link);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_dai_substream);
+
+struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
+ const char *dai_link)
+{
+ int i;
+
+ for (i = 0; i < card->num_links; i++) {
+ if (!strcmp(card->rtd[i].dai_link->name, dai_link))
+ return &card->rtd[i];
+ }
+ dev_dbg(card->dev, "failed to find rtd %s\n", dai_link);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime);
+
#ifdef CONFIG_SND_SOC_AC97_BUS
/* unregister ac97 codec */
static int soc_ac97_dev_unregister(struct snd_soc_codec *codec)
@@ -567,19 +596,16 @@ int snd_soc_suspend(struct device *dev)
}
for (i = 0; i < card->num_rtd; i++) {
- struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai;
if (card->rtd[i].dai_link->ignore_suspend)
continue;
snd_soc_dapm_stream_event(&card->rtd[i],
SNDRV_PCM_STREAM_PLAYBACK,
- codec_dai,
SND_SOC_DAPM_STREAM_SUSPEND);
snd_soc_dapm_stream_event(&card->rtd[i],
SNDRV_PCM_STREAM_CAPTURE,
- codec_dai,
SND_SOC_DAPM_STREAM_SUSPEND);
}
@@ -683,17 +709,16 @@ static void soc_resume_deferred(struct work_struct *work)
}
for (i = 0; i < card->num_rtd; i++) {
- struct snd_soc_dai *codec_dai = card->rtd[i].codec_dai;
if (card->rtd[i].dai_link->ignore_suspend)
continue;
snd_soc_dapm_stream_event(&card->rtd[i],
- SNDRV_PCM_STREAM_PLAYBACK, codec_dai,
+ SNDRV_PCM_STREAM_PLAYBACK,
SND_SOC_DAPM_STREAM_RESUME);
snd_soc_dapm_stream_event(&card->rtd[i],
- SNDRV_PCM_STREAM_CAPTURE, codec_dai,
+ SNDRV_PCM_STREAM_CAPTURE,
SND_SOC_DAPM_STREAM_RESUME);
}
@@ -783,15 +808,9 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
struct snd_soc_dai *codec_dai, *cpu_dai;
const char *platform_name;
- if (rtd->complete)
- return 1;
dev_dbg(card->dev, "binding %s at idx %d\n", dai_link->name, num);
- /* do we already have the CPU DAI for this link ? */
- if (rtd->cpu_dai) {
- goto find_codec;
- }
- /* no, then find CPU DAI from registered DAIs*/
+ /* Find CPU DAI from registered DAIs*/
list_for_each_entry(cpu_dai, &dai_list, list) {
if (dai_link->cpu_dai_of_node) {
if (cpu_dai->dev->of_node != dai_link->cpu_dai_of_node)
@@ -802,18 +821,15 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
}
rtd->cpu_dai = cpu_dai;
- goto find_codec;
}
- dev_dbg(card->dev, "CPU DAI %s not registered\n",
- dai_link->cpu_dai_name);
-find_codec:
- /* do we already have the CODEC for this link ? */
- if (rtd->codec) {
- goto find_platform;
+ if (!rtd->cpu_dai) {
+ dev_dbg(card->dev, "CPU DAI %s not registered\n",
+ dai_link->cpu_dai_name);
+ return -EPROBE_DEFER;
}
- /* no, then find CODEC from registered CODECs*/
+ /* Find CODEC from registered CODECs */
list_for_each_entry(codec, &codec_list, list) {
if (dai_link->codec_of_node) {
if (codec->dev->of_node != dai_link->codec_of_node)
@@ -835,28 +851,28 @@ find_codec:
dai_link->codec_dai_name)) {
rtd->codec_dai = codec_dai;
- goto find_platform;
}
}
- dev_dbg(card->dev, "CODEC DAI %s not registered\n",
- dai_link->codec_dai_name);
- goto find_platform;
+ if (!rtd->codec_dai) {
+ dev_dbg(card->dev, "CODEC DAI %s not registered\n",
+ dai_link->codec_dai_name);
+ return -EPROBE_DEFER;
+ }
}
- dev_dbg(card->dev, "CODEC %s not registered\n",
- dai_link->codec_name);
-find_platform:
- /* do we need a platform? */
- if (rtd->platform)
- goto out;
+ if (!rtd->codec) {
+ dev_dbg(card->dev, "CODEC %s not registered\n",
+ dai_link->codec_name);
+ return -EPROBE_DEFER;
+ }
/* if there's no platform we match on the empty platform */
platform_name = dai_link->platform_name;
if (!platform_name && !dai_link->platform_of_node)
platform_name = "snd-soc-dummy";
- /* no, then find one from the set of registered platforms */
+ /* find one from the set of registered platforms */
list_for_each_entry(platform, &platform_list, list) {
if (dai_link->platform_of_node) {
if (platform->dev->of_node !=
@@ -868,20 +884,16 @@ find_platform:
}
rtd->platform = platform;
- goto out;
}
-
- dev_dbg(card->dev, "platform %s not registered\n",
+ if (!rtd->platform) {
+ dev_dbg(card->dev, "platform %s not registered\n",
dai_link->platform_name);
- return 0;
-
-out:
- /* mark rtd as complete if we found all 4 of our client devices */
- if (rtd->codec && rtd->codec_dai && rtd->platform && rtd->cpu_dai) {
- rtd->complete = 1;
- card->num_rtd++;
+ return -EPROBE_DEFER;
}
- return 1;
+
+ card->num_rtd++;
+
+ return 0;
}
static void soc_remove_codec(struct snd_soc_codec *codec)
@@ -1068,6 +1080,7 @@ static int soc_probe_platform(struct snd_soc_card *card,
{
int ret = 0;
const struct snd_soc_platform_driver *driver = platform->driver;
+ struct snd_soc_dai *dai;
platform->card = card;
platform->dapm.card = card;
@@ -1081,6 +1094,14 @@ static int soc_probe_platform(struct snd_soc_card *card,
snd_soc_dapm_new_controls(&platform->dapm,
driver->dapm_widgets, driver->num_dapm_widgets);
+ /* Create DAPM widgets for each DAI stream */
+ list_for_each_entry(dai, &dai_list, list) {
+ if (dai->dev != platform->dev)
+ continue;
+
+ snd_soc_dapm_new_dai_widgets(&platform->dapm, dai);
+ }
+
platform->dapm.idle_bias_off = 1;
if (driver->probe) {
@@ -1170,6 +1191,10 @@ static int soc_post_component_init(struct snd_soc_card *card,
rtd->dev->init_name = name;
dev_set_drvdata(rtd->dev, rtd);
mutex_init(&rtd->pcm_mutex);
+ INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients);
+ INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].be_clients);
+ INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].fe_clients);
+ INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_CAPTURE].fe_clients);
ret = device_add(rtd->dev);
if (ret < 0) {
dev_err(card->dev,
@@ -1191,6 +1216,17 @@ static int soc_post_component_init(struct snd_soc_card *card,
dev_err(codec->dev,
"asoc: failed to add codec sysfs files: %d\n", ret);
+#ifdef CONFIG_DEBUG_FS
+ /* add DPCM sysfs entries */
+ if (!dailess && !dai_link->dynamic)
+ goto out;
+
+ ret = soc_dpcm_debugfs_add(rtd);
+ if (ret < 0)
+ dev_err(rtd->dev, "asoc: failed to add dpcm sysfs entries: %d\n", ret);
+
+out:
+#endif
return 0;
}
@@ -1200,14 +1236,15 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order)
struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_platform *platform = rtd->platform;
- struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dapm_widget *play_w, *capture_w;
int ret;
dev_dbg(card->dev, "probe %s dai link %d late %d\n",
card->name, num, order);
/* config components */
- codec_dai->codec = codec;
cpu_dai->platform = platform;
codec_dai->card = card;
cpu_dai->card = card;
@@ -1218,9 +1255,12 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order)
/* probe the cpu_dai */
if (!cpu_dai->probed &&
cpu_dai->driver->probe_order == order) {
+ cpu_dai->dapm.card = card;
if (!try_module_get(cpu_dai->dev->driver->owner))
return -ENODEV;
+ snd_soc_dapm_new_dai_widgets(&cpu_dai->dapm, cpu_dai);
+
if (cpu_dai->driver->probe) {
ret = cpu_dai->driver->probe(cpu_dai);
if (ret < 0) {
@@ -1279,12 +1319,39 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order)
if (ret < 0)
pr_warn("asoc: failed to add pmdown_time sysfs:%d\n", ret);
- /* create the pcm */
- ret = soc_new_pcm(rtd, num);
- if (ret < 0) {
- pr_err("asoc: can't create pcm %s :%d\n",
- dai_link->stream_name, ret);
- return ret;
+ if (!dai_link->params) {
+ /* create the pcm */
+ ret = soc_new_pcm(rtd, num);
+ if (ret < 0) {
+ pr_err("asoc: can't create pcm %s :%d\n",
+ dai_link->stream_name, ret);
+ return ret;
+ }
+ } else {
+ /* link the DAI widgets */
+ play_w = codec_dai->playback_widget;
+ capture_w = cpu_dai->capture_widget;
+ if (play_w && capture_w) {
+ ret = snd_soc_dapm_new_pcm(card, dai_link->params,
+ capture_w, play_w);
+ if (ret != 0) {
+ dev_err(card->dev, "Can't link %s to %s: %d\n",
+ play_w->name, capture_w->name, ret);
+ return ret;
+ }
+ }
+
+ play_w = cpu_dai->playback_widget;
+ capture_w = codec_dai->capture_widget;
+ if (play_w && capture_w) {
+ ret = snd_soc_dapm_new_pcm(card, dai_link->params,
+ capture_w, play_w);
+ if (ret != 0) {
+ dev_err(card->dev, "Can't link %s to %s: %d\n",
+ play_w->name, capture_w->name, ret);
+ return ret;
+ }
+ }
}
/* add platform data for AC97 devices */
@@ -1334,6 +1401,20 @@ static void soc_unregister_ac97_dai_link(struct snd_soc_codec *codec)
}
#endif
+static int soc_check_aux_dev(struct snd_soc_card *card, int num)
+{
+ struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
+ struct snd_soc_codec *codec;
+
+ /* find CODEC from registered CODECs*/
+ list_for_each_entry(codec, &codec_list, list) {
+ if (!strcmp(codec->name, aux_dev->codec_name))
+ return 0;
+ }
+
+ return -EPROBE_DEFER;
+}
+
static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
{
struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num];
@@ -1354,7 +1435,7 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num)
}
/* codec not found */
dev_err(card->dev, "asoc: codec %s not found", aux_dev->codec_name);
- goto out;
+ return -EPROBE_DEFER;
found:
ret = soc_probe_codec(card, codec);
@@ -1404,29 +1485,28 @@ static int snd_soc_init_codec_cache(struct snd_soc_codec *codec,
return 0;
}
-static void snd_soc_instantiate_card(struct snd_soc_card *card)
+static int snd_soc_instantiate_card(struct snd_soc_card *card)
{
struct snd_soc_codec *codec;
struct snd_soc_codec_conf *codec_conf;
enum snd_soc_compress_type compress_type;
struct snd_soc_dai_link *dai_link;
- int ret, i, order;
+ int ret, i, order, dai_fmt;
- mutex_lock(&card->mutex);
-
- if (card->instantiated) {
- mutex_unlock(&card->mutex);
- return;
- }
+ mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);
/* bind DAIs */
- for (i = 0; i < card->num_links; i++)
- soc_bind_dai_link(card, i);
+ for (i = 0; i < card->num_links; i++) {
+ ret = soc_bind_dai_link(card, i);
+ if (ret != 0)
+ goto base_error;
+ }
- /* bind completed ? */
- if (card->num_rtd != card->num_links) {
- mutex_unlock(&card->mutex);
- return;
+ /* check aux_devs too */
+ for (i = 0; i < card->num_aux_devs; i++) {
+ ret = soc_check_aux_dev(card, i);
+ if (ret != 0)
+ goto base_error;
}
/* initialize the register cache for each available codec */
@@ -1446,10 +1526,8 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
}
}
ret = snd_soc_init_codec_cache(codec, compress_type);
- if (ret < 0) {
- mutex_unlock(&card->mutex);
- return;
- }
+ if (ret < 0)
+ goto base_error;
}
/* card bind complete so register a sound card */
@@ -1458,8 +1536,7 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
if (ret < 0) {
pr_err("asoc: can't create sound card for card %s: %d\n",
card->name, ret);
- mutex_unlock(&card->mutex);
- return;
+ goto base_error;
}
card->snd_card->dev = card->dev;
@@ -1523,17 +1600,47 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
for (i = 0; i < card->num_links; i++) {
dai_link = &card->dai_link[i];
+ dai_fmt = dai_link->dai_fmt;
- if (dai_link->dai_fmt) {
+ if (dai_fmt) {
ret = snd_soc_dai_set_fmt(card->rtd[i].codec_dai,
- dai_link->dai_fmt);
+ dai_fmt);
if (ret != 0 && ret != -ENOTSUPP)
dev_warn(card->rtd[i].codec_dai->dev,
"Failed to set DAI format: %d\n",
ret);
+ }
+ /* If this is a regular CPU link there will be a platform */
+ if (dai_fmt &&
+ (dai_link->platform_name || dai_link->platform_of_node)) {
ret = snd_soc_dai_set_fmt(card->rtd[i].cpu_dai,
- dai_link->dai_fmt);
+ dai_fmt);
+ if (ret != 0 && ret != -ENOTSUPP)
+ dev_warn(card->rtd[i].cpu_dai->dev,
+ "Failed to set DAI format: %d\n",
+ ret);
+ } else if (dai_fmt) {
+ /* Flip the polarity for the "CPU" end */
+ dai_fmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
+ switch (dai_link->dai_fmt &
+ SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ dai_fmt |= SND_SOC_DAIFMT_CBS_CFM;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ dai_fmt |= SND_SOC_DAIFMT_CBM_CFS;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
+ break;
+ }
+
+ ret = snd_soc_dai_set_fmt(card->rtd[i].cpu_dai,
+ dai_fmt);
if (ret != 0 && ret != -ENOTSUPP)
dev_warn(card->rtd[i].cpu_dai->dev,
"Failed to set DAI format: %d\n",
@@ -1599,7 +1706,8 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card)
card->instantiated = 1;
snd_soc_dapm_sync(&card->dapm);
mutex_unlock(&card->mutex);
- return;
+
+ return 0;
probe_aux_dev_err:
for (i = 0; i < card->num_aux_devs; i++)
@@ -1614,18 +1722,10 @@ card_probe_error:
snd_card_free(card->snd_card);
+base_error:
mutex_unlock(&card->mutex);
-}
-/*
- * Attempt to initialise any uninitialised cards. Must be called with
- * client_mutex.
- */
-static void snd_soc_instantiate_cards(void)
-{
- struct snd_soc_card *card;
- list_for_each_entry(card, &card_list, list)
- snd_soc_instantiate_card(card);
+ return ret;
}
/* probes a new socdev */
@@ -2527,6 +2627,87 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
/**
+ * snd_soc_get_volsw_sx - single mixer get callback
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback to get the value of a single mixer control, or a double mixer
+ * control that spans 2 registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ unsigned int reg = mc->reg;
+ unsigned int reg2 = mc->rreg;
+ unsigned int shift = mc->shift;
+ unsigned int rshift = mc->rshift;
+ int max = mc->max;
+ int min = mc->min;
+ int mask = (1 << (fls(min + max) - 1)) - 1;
+
+ ucontrol->value.integer.value[0] =
+ ((snd_soc_read(codec, reg) >> shift) - min) & mask;
+
+ if (snd_soc_volsw_is_stereo(mc))
+ ucontrol->value.integer.value[1] =
+ ((snd_soc_read(codec, reg2) >> rshift) - min) & mask;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx);
+
+/**
+ * snd_soc_put_volsw_sx - double mixer set callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to set the value of a double mixer control that spans 2 registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ unsigned int reg = mc->reg;
+ unsigned int reg2 = mc->rreg;
+ unsigned int shift = mc->shift;
+ unsigned int rshift = mc->rshift;
+ int max = mc->max;
+ int min = mc->min;
+ int mask = (1 << (fls(min + max) - 1)) - 1;
+ int err = 0;
+ unsigned short val, val_mask, val2 = 0;
+
+ val_mask = mask << shift;
+ val = (ucontrol->value.integer.value[0] + min) & mask;
+ val = val << shift;
+
+ if (snd_soc_update_bits_locked(codec, reg, val_mask, val))
+ return err;
+
+ if (snd_soc_volsw_is_stereo(mc)) {
+ val_mask = mask << rshift;
+ val2 = (ucontrol->value.integer.value[1] + min) & mask;
+ val2 = val2 << rshift;
+
+ if (snd_soc_update_bits_locked(codec, reg2, val_mask, val2))
+ return err;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_volsw_sx);
+
+/**
* snd_soc_info_volsw_s8 - signed mixer info callback
* @kcontrol: mixer control
* @uinfo: control element information
@@ -2647,99 +2828,6 @@ int snd_soc_limit_volume(struct snd_soc_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_soc_limit_volume);
-/**
- * snd_soc_info_volsw_2r_sx - double with tlv and variable data size
- * mixer info callback
- * @kcontrol: mixer control
- * @uinfo: control element information
- *
- * Returns 0 for success.
- */
-int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- int max = mc->max;
- int min = mc->min;
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 2;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = max-min;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r_sx);
-
-/**
- * snd_soc_get_volsw_2r_sx - double with tlv and variable data size
- * mixer get callback
- * @kcontrol: mixer control
- * @uinfo: control element information
- *
- * Returns 0 for success.
- */
-int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- unsigned int mask = (1<<mc->shift)-1;
- int min = mc->min;
- int val = snd_soc_read(codec, mc->reg) & mask;
- int valr = snd_soc_read(codec, mc->rreg) & mask;
-
- ucontrol->value.integer.value[0] = ((val & 0xff)-min) & mask;
- ucontrol->value.integer.value[1] = ((valr & 0xff)-min) & mask;
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r_sx);
-
-/**
- * snd_soc_put_volsw_2r_sx - double with tlv and variable data size
- * mixer put callback
- * @kcontrol: mixer control
- * @uinfo: control element information
- *
- * Returns 0 for success.
- */
-int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- unsigned int mask = (1<<mc->shift)-1;
- int min = mc->min;
- int ret;
- unsigned int val, valr, oval, ovalr;
-
- val = ((ucontrol->value.integer.value[0]+min) & 0xff);
- val &= mask;
- valr = ((ucontrol->value.integer.value[1]+min) & 0xff);
- valr &= mask;
-
- oval = snd_soc_read(codec, mc->reg) & mask;
- ovalr = snd_soc_read(codec, mc->rreg) & mask;
-
- ret = 0;
- if (oval != val) {
- ret = snd_soc_write(codec, mc->reg, val);
- if (ret < 0)
- return ret;
- }
- if (ovalr != valr) {
- ret = snd_soc_write(codec, mc->rreg, valr);
- if (ret < 0)
- return ret;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx);
-
int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -2850,6 +2938,186 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
EXPORT_SYMBOL_GPL(snd_soc_bytes_put);
/**
+ * snd_soc_info_xr_sx - signed multi register info callback
+ * @kcontrol: mreg control
+ * @uinfo: control element information
+ *
+ * Callback to provide information of a control that can
+ * span multiple codec registers which together
+ * forms a single signed value in a MSB/LSB manner.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_info_xr_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct soc_mreg_control *mc =
+ (struct soc_mreg_control *)kcontrol->private_value;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = mc->min;
+ uinfo->value.integer.max = mc->max;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_xr_sx);
+
+/**
+ * snd_soc_get_xr_sx - signed multi register get callback
+ * @kcontrol: mreg control
+ * @ucontrol: control element information
+ *
+ * Callback to get the value of a control that can span
+ * multiple codec registers which together forms a single
+ * signed value in a MSB/LSB manner. The control supports
+ * specifying total no of bits used to allow for bitfields
+ * across the multiple codec registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mreg_control *mc =
+ (struct soc_mreg_control *)kcontrol->private_value;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int regbase = mc->regbase;
+ unsigned int regcount = mc->regcount;
+ unsigned int regwshift = codec->driver->reg_word_size * BITS_PER_BYTE;
+ unsigned int regwmask = (1<<regwshift)-1;
+ unsigned int invert = mc->invert;
+ unsigned long mask = (1UL<<mc->nbits)-1;
+ long min = mc->min;
+ long max = mc->max;
+ long val = 0;
+ unsigned long regval;
+ unsigned int i;
+
+ for (i = 0; i < regcount; i++) {
+ regval = snd_soc_read(codec, regbase+i) & regwmask;
+ val |= regval << (regwshift*(regcount-i-1));
+ }
+ val &= mask;
+ if (min < 0 && val > max)
+ val |= ~mask;
+ if (invert)
+ val = max - val;
+ ucontrol->value.integer.value[0] = val;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_xr_sx);
+
+/**
+ * snd_soc_put_xr_sx - signed multi register get callback
+ * @kcontrol: mreg control
+ * @ucontrol: control element information
+ *
+ * Callback to set the value of a control that can span
+ * multiple codec registers which together forms a single
+ * signed value in a MSB/LSB manner. The control supports
+ * specifying total no of bits used to allow for bitfields
+ * across the multiple codec registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mreg_control *mc =
+ (struct soc_mreg_control *)kcontrol->private_value;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int regbase = mc->regbase;
+ unsigned int regcount = mc->regcount;
+ unsigned int regwshift = codec->driver->reg_word_size * BITS_PER_BYTE;
+ unsigned int regwmask = (1<<regwshift)-1;
+ unsigned int invert = mc->invert;
+ unsigned long mask = (1UL<<mc->nbits)-1;
+ long max = mc->max;
+ long val = ucontrol->value.integer.value[0];
+ unsigned int i, regval, regmask;
+ int err;
+
+ if (invert)
+ val = max - val;
+ val &= mask;
+ for (i = 0; i < regcount; i++) {
+ regval = (val >> (regwshift*(regcount-i-1))) & regwmask;
+ regmask = (mask >> (regwshift*(regcount-i-1))) & regwmask;
+ err = snd_soc_update_bits_locked(codec, regbase+i,
+ regmask, regval);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_xr_sx);
+
+/**
+ * snd_soc_get_strobe - strobe get callback
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback get the value of a strobe mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_strobe(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int reg = mc->reg;
+ unsigned int shift = mc->shift;
+ unsigned int mask = 1 << shift;
+ unsigned int invert = mc->invert != 0;
+ unsigned int val = snd_soc_read(codec, reg) & mask;
+
+ if (shift != 0 && val != 0)
+ val = val >> shift;
+ ucontrol->value.enumerated.item[0] = val ^ invert;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_strobe);
+
+/**
+ * snd_soc_put_strobe - strobe put callback
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback strobe a register bit to high then low (or the inverse)
+ * in one pass of a single mixer enum control.
+ *
+ * Returns 1 for success.
+ */
+int snd_soc_put_strobe(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int reg = mc->reg;
+ unsigned int shift = mc->shift;
+ unsigned int mask = 1 << shift;
+ unsigned int invert = mc->invert != 0;
+ unsigned int strobe = ucontrol->value.enumerated.item[0] != 0;
+ unsigned int val1 = (strobe ^ invert) ? mask : 0;
+ unsigned int val2 = (strobe ^ invert) ? 0 : mask;
+ int err;
+
+ err = snd_soc_update_bits_locked(codec, reg, mask, val1);
+ if (err < 0)
+ return err;
+
+ err = snd_soc_update_bits_locked(codec, reg, mask, val2);
+ return err;
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_strobe);
+
+/**
* snd_soc_dai_set_sysclk - configure DAI system or master clock.
* @dai: DAI
* @clk_id: DAI specific clock ID
@@ -3048,7 +3316,7 @@ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute)
if (dai->driver && dai->driver->ops->digital_mute)
return dai->driver->ops->digital_mute(dai, mute);
else
- return -EINVAL;
+ return -ENOTSUPP;
}
EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
@@ -3060,7 +3328,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
*/
int snd_soc_register_card(struct snd_soc_card *card)
{
- int i;
+ int i, ret;
if (!card->name || !card->dev)
return -EINVAL;
@@ -3123,15 +3391,13 @@ int snd_soc_register_card(struct snd_soc_card *card)
INIT_LIST_HEAD(&card->dapm_dirty);
card->instantiated = 0;
mutex_init(&card->mutex);
+ mutex_init(&card->dapm_mutex);
- mutex_lock(&client_mutex);
- list_add(&card->list, &card_list);
- snd_soc_instantiate_cards();
- mutex_unlock(&client_mutex);
-
- dev_dbg(card->dev, "Registered card '%s'\n", card->name);
+ ret = snd_soc_instantiate_card(card);
+ if (ret != 0)
+ soc_cleanup_card_debugfs(card);
- return 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_register_card);
@@ -3145,9 +3411,6 @@ int snd_soc_unregister_card(struct snd_soc_card *card)
{
if (card->instantiated)
soc_cleanup_card_resources(card);
- mutex_lock(&client_mutex);
- list_del(&card->list);
- mutex_unlock(&client_mutex);
dev_dbg(card->dev, "Unregistered card '%s'\n", card->name);
return 0;
@@ -3221,6 +3484,7 @@ static inline char *fmt_multiple_name(struct device *dev,
int snd_soc_register_dai(struct device *dev,
struct snd_soc_dai_driver *dai_drv)
{
+ struct snd_soc_codec *codec;
struct snd_soc_dai *dai;
dev_dbg(dev, "dai register %s\n", dev_name(dev));
@@ -3238,12 +3502,23 @@ int snd_soc_register_dai(struct device *dev,
dai->dev = dev;
dai->driver = dai_drv;
+ dai->dapm.dev = dev;
if (!dai->driver->ops)
dai->driver->ops = &null_dai_ops;
mutex_lock(&client_mutex);
+
+ list_for_each_entry(codec, &codec_list, list) {
+ if (codec->dev == dev) {
+ dev_dbg(dev, "Mapped DAI %s to CODEC %s\n",
+ dai->name, codec->name);
+ dai->codec = codec;
+ break;
+ }
+ }
+
list_add(&dai->list, &dai_list);
- snd_soc_instantiate_cards();
+
mutex_unlock(&client_mutex);
pr_debug("Registered DAI '%s'\n", dai->name);
@@ -3287,6 +3562,7 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
int snd_soc_register_dais(struct device *dev,
struct snd_soc_dai_driver *dai_drv, size_t count)
{
+ struct snd_soc_codec *codec;
struct snd_soc_dai *dai;
int i, ret = 0;
@@ -3314,19 +3590,28 @@ int snd_soc_register_dais(struct device *dev,
dai->id = dai->driver->id;
else
dai->id = i;
+ dai->dapm.dev = dev;
if (!dai->driver->ops)
dai->driver->ops = &null_dai_ops;
mutex_lock(&client_mutex);
+
+ list_for_each_entry(codec, &codec_list, list) {
+ if (codec->dev == dev) {
+ dev_dbg(dev, "Mapped DAI %s to CODEC %s\n",
+ dai->name, codec->name);
+ dai->codec = codec;
+ break;
+ }
+ }
+
list_add(&dai->list, &dai_list);
+
mutex_unlock(&client_mutex);
pr_debug("Registered DAI '%s'\n", dai->name);
}
- mutex_lock(&client_mutex);
- snd_soc_instantiate_cards();
- mutex_unlock(&client_mutex);
return 0;
err:
@@ -3384,7 +3669,6 @@ int snd_soc_register_platform(struct device *dev,
mutex_lock(&client_mutex);
list_add(&platform->list, &platform_list);
- snd_soc_instantiate_cards();
mutex_unlock(&client_mutex);
pr_debug("Registered platform '%s'\n", platform->name);
@@ -3534,18 +3818,18 @@ int snd_soc_register_codec(struct device *dev,
fixup_codec_formats(&dai_drv[i].capture);
}
+ mutex_lock(&client_mutex);
+ list_add(&codec->list, &codec_list);
+ mutex_unlock(&client_mutex);
+
/* register any DAIs */
if (num_dai) {
ret = snd_soc_register_dais(dev, dai_drv, num_dai);
if (ret < 0)
- goto fail;
+ dev_err(codec->dev, "Failed to regster DAIs: %d\n",
+ ret);
}
- mutex_lock(&client_mutex);
- list_add(&codec->list, &codec_list);
- snd_soc_instantiate_cards();
- mutex_unlock(&client_mutex);
-
pr_debug("Registered codec '%s'\n", codec->name);
return 0;
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 1bb6d4a63cd8..90ee77d2409d 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -52,6 +52,7 @@ static int dapm_up_seq[] = {
[snd_soc_dapm_supply] = 1,
[snd_soc_dapm_regulator_supply] = 1,
[snd_soc_dapm_micbias] = 2,
+ [snd_soc_dapm_dai_link] = 2,
[snd_soc_dapm_dai] = 3,
[snd_soc_dapm_aif_in] = 3,
[snd_soc_dapm_aif_out] = 3,
@@ -90,9 +91,10 @@ static int dapm_down_seq[] = {
[snd_soc_dapm_aif_in] = 10,
[snd_soc_dapm_aif_out] = 10,
[snd_soc_dapm_dai] = 10,
- [snd_soc_dapm_regulator_supply] = 11,
- [snd_soc_dapm_supply] = 11,
- [snd_soc_dapm_post] = 12,
+ [snd_soc_dapm_dai_link] = 11,
+ [snd_soc_dapm_regulator_supply] = 12,
+ [snd_soc_dapm_supply] = 12,
+ [snd_soc_dapm_post] = 13,
};
static void pop_wait(u32 pop_time)
@@ -208,7 +210,23 @@ static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val)
return -1;
}
-static int soc_widget_update_bits(struct snd_soc_dapm_widget *w,
+static inline void soc_widget_lock(struct snd_soc_dapm_widget *w)
+{
+ if (w->codec && !w->codec->using_regmap)
+ mutex_lock(&w->codec->mutex);
+ else if (w->platform)
+ mutex_lock(&w->platform->mutex);
+}
+
+static inline void soc_widget_unlock(struct snd_soc_dapm_widget *w)
+{
+ if (w->codec && !w->codec->using_regmap)
+ mutex_unlock(&w->codec->mutex);
+ else if (w->platform)
+ mutex_unlock(&w->platform->mutex);
+}
+
+static int soc_widget_update_bits_locked(struct snd_soc_dapm_widget *w,
unsigned short reg, unsigned int mask, unsigned int value)
{
bool change;
@@ -221,18 +239,24 @@ static int soc_widget_update_bits(struct snd_soc_dapm_widget *w,
if (ret != 0)
return ret;
} else {
+ soc_widget_lock(w);
ret = soc_widget_read(w, reg);
- if (ret < 0)
+ if (ret < 0) {
+ soc_widget_unlock(w);
return ret;
+ }
old = ret;
new = (old & ~mask) | (value & mask);
change = old != new;
if (change) {
ret = soc_widget_write(w, reg, new);
- if (ret < 0)
+ if (ret < 0) {
+ soc_widget_unlock(w);
return ret;
+ }
}
+ soc_widget_unlock(w);
}
return change;
@@ -374,6 +398,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
case snd_soc_dapm_mic:
case snd_soc_dapm_spk:
case snd_soc_dapm_line:
+ case snd_soc_dapm_dai_link:
p->connect = 1;
break;
/* does affect routing - dynamically connected */
@@ -682,11 +707,51 @@ static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
}
}
+/* add widget to list if it's not already in the list */
+static int dapm_list_add_widget(struct snd_soc_dapm_widget_list **list,
+ struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_dapm_widget_list *wlist;
+ int wlistsize, wlistentries, i;
+
+ if (*list == NULL)
+ return -EINVAL;
+
+ wlist = *list;
+
+ /* is this widget already in the list */
+ for (i = 0; i < wlist->num_widgets; i++) {
+ if (wlist->widgets[i] == w)
+ return 0;
+ }
+
+ /* allocate some new space */
+ wlistentries = wlist->num_widgets + 1;
+ wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
+ wlistentries * sizeof(struct snd_soc_dapm_widget *);
+ *list = krealloc(wlist, wlistsize, GFP_KERNEL);
+ if (*list == NULL) {
+ dev_err(w->dapm->dev, "can't allocate widget list for %s\n",
+ w->name);
+ return -ENOMEM;
+ }
+ wlist = *list;
+
+ /* insert the widget */
+ dev_dbg(w->dapm->dev, "added %s in widget list pos %d\n",
+ w->name, wlist->num_widgets);
+
+ wlist->widgets[wlist->num_widgets] = w;
+ wlist->num_widgets++;
+ return 1;
+}
+
/*
* Recursively check for a completed path to an active or physically connected
* output widget. Returns number of complete paths.
*/
-static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
+static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
+ struct snd_soc_dapm_widget_list **list)
{
struct snd_soc_dapm_path *path;
int con = 0;
@@ -742,9 +807,23 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
if (path->walked)
continue;
+ trace_snd_soc_dapm_output_path(widget, path);
+
if (path->sink && path->connect) {
path->walked = 1;
- con += is_connected_output_ep(path->sink);
+
+ /* do we need to add this widget to the list ? */
+ if (list) {
+ int err;
+ err = dapm_list_add_widget(list, path->sink);
+ if (err < 0) {
+ dev_err(widget->dapm->dev, "could not add widget %s\n",
+ widget->name);
+ return con;
+ }
+ }
+
+ con += is_connected_output_ep(path->sink, list);
}
}
@@ -757,7 +836,8 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
* Recursively check for a completed path to an active or physically connected
* input widget. Returns number of complete paths.
*/
-static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
+static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
+ struct snd_soc_dapm_widget_list **list)
{
struct snd_soc_dapm_path *path;
int con = 0;
@@ -825,9 +905,23 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
if (path->walked)
continue;
+ trace_snd_soc_dapm_input_path(widget, path);
+
if (path->source && path->connect) {
path->walked = 1;
- con += is_connected_input_ep(path->source);
+
+ /* do we need to add this widget to the list ? */
+ if (list) {
+ int err;
+ err = dapm_list_add_widget(list, path->sink);
+ if (err < 0) {
+ dev_err(widget->dapm->dev, "could not add widget %s\n",
+ widget->name);
+ return con;
+ }
+ }
+
+ con += is_connected_input_ep(path->source, list);
}
}
@@ -836,6 +930,39 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
return con;
}
+/**
+ * snd_soc_dapm_get_connected_widgets - query audio path and it's widgets.
+ * @dai: the soc DAI.
+ * @stream: stream direction.
+ * @list: list of active widgets for this stream.
+ *
+ * Queries DAPM graph as to whether an valid audio stream path exists for
+ * the initial stream specified by name. This takes into account
+ * current mixer and mux kcontrol settings. Creates list of valid widgets.
+ *
+ * Returns the number of valid paths or negative error.
+ */
+int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
+ struct snd_soc_dapm_widget_list **list)
+{
+ struct snd_soc_card *card = dai->card;
+ int paths;
+
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+ dapm_reset(card);
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ paths = is_connected_output_ep(dai->playback_widget, list);
+ else
+ paths = is_connected_input_ep(dai->playback_widget, list);
+
+ trace_snd_soc_dapm_connected(paths, stream);
+ dapm_clear_walk(&card->dapm);
+ mutex_unlock(&card->dapm_mutex);
+
+ return paths;
+}
+
/*
* Handler for generic register modifier widget.
*/
@@ -849,7 +976,7 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w,
else
val = w->off_val;
- soc_widget_update_bits(w, -(w->reg + 1),
+ soc_widget_update_bits_locked(w, -(w->reg + 1),
w->mask << w->shift, val << w->shift);
return 0;
@@ -863,9 +990,9 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
if (SND_SOC_DAPM_EVENT_ON(event))
- return regulator_enable(w->priv);
+ return regulator_enable(w->regulator);
else
- return regulator_disable_deferred(w->priv, w->shift);
+ return regulator_disable_deferred(w->regulator, w->shift);
}
EXPORT_SYMBOL_GPL(dapm_regulator_event);
@@ -892,9 +1019,9 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
DAPM_UPDATE_STAT(w, power_checks);
- in = is_connected_input_ep(w);
+ in = is_connected_input_ep(w, NULL);
dapm_clear_walk(w->dapm);
- out = is_connected_output_ep(w);
+ out = is_connected_output_ep(w, NULL);
dapm_clear_walk(w->dapm);
return out != 0 && in != 0;
}
@@ -903,7 +1030,10 @@ static int dapm_dai_check_power(struct snd_soc_dapm_widget *w)
{
DAPM_UPDATE_STAT(w, power_checks);
- return w->active;
+ if (w->active)
+ return w->active;
+
+ return dapm_generic_check_power(w);
}
/* Check to see if an ADC has power */
@@ -914,7 +1044,7 @@ static int dapm_adc_check_power(struct snd_soc_dapm_widget *w)
DAPM_UPDATE_STAT(w, power_checks);
if (w->active) {
- in = is_connected_input_ep(w);
+ in = is_connected_input_ep(w, NULL);
dapm_clear_walk(w->dapm);
return in != 0;
} else {
@@ -930,7 +1060,7 @@ static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
DAPM_UPDATE_STAT(w, power_checks);
if (w->active) {
- out = is_connected_output_ep(w);
+ out = is_connected_output_ep(w, NULL);
dapm_clear_walk(w->dapm);
return out != 0;
} else {
@@ -1107,7 +1237,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
"pop test : Applying 0x%x/0x%x to %x in %dms\n",
value, mask, reg, card->pop_time);
pop_wait(card->pop_time);
- soc_widget_update_bits(w, reg, mask, value);
+ soc_widget_update_bits_locked(w, reg, mask, value);
}
list_for_each_entry(w, pending, power_list) {
@@ -1237,7 +1367,7 @@ static void dapm_widget_update(struct snd_soc_dapm_context *dapm)
w->name, ret);
}
- ret = snd_soc_update_bits(w->codec, update->reg, update->mask,
+ ret = soc_widget_update_bits_locked(w, update->reg, update->mask,
update->val);
if (ret < 0)
pr_err("%s DAPM update failed: %d\n", w->name, ret);
@@ -1421,12 +1551,10 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
trace_snd_soc_dapm_start(card);
list_for_each_entry(d, &card->dapm_list, list) {
- if (d->n_widgets || d->codec == NULL) {
- if (d->idle_bias_off)
- d->target_bias_level = SND_SOC_BIAS_OFF;
- else
- d->target_bias_level = SND_SOC_BIAS_STANDBY;
- }
+ if (d->idle_bias_off)
+ d->target_bias_level = SND_SOC_BIAS_OFF;
+ else
+ d->target_bias_level = SND_SOC_BIAS_STANDBY;
}
dapm_reset(card);
@@ -1471,32 +1599,6 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
}
- /* If there are no DAPM widgets then try to figure out power from the
- * event type.
- */
- if (!dapm->n_widgets) {
- switch (event) {
- case SND_SOC_DAPM_STREAM_START:
- case SND_SOC_DAPM_STREAM_RESUME:
- dapm->target_bias_level = SND_SOC_BIAS_ON;
- break;
- case SND_SOC_DAPM_STREAM_STOP:
- if (dapm->codec && dapm->codec->active)
- dapm->target_bias_level = SND_SOC_BIAS_ON;
- else
- dapm->target_bias_level = SND_SOC_BIAS_STANDBY;
- break;
- case SND_SOC_DAPM_STREAM_SUSPEND:
- dapm->target_bias_level = SND_SOC_BIAS_STANDBY;
- break;
- case SND_SOC_DAPM_STREAM_NOP:
- dapm->target_bias_level = dapm->bias_level;
- break;
- default:
- break;
- }
- }
-
/* Force all contexts in the card to the same bias state if
* they're not ground referenced.
*/
@@ -1560,9 +1662,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
if (!buf)
return -ENOMEM;
- in = is_connected_input_ep(w);
+ in = is_connected_input_ep(w, NULL);
dapm_clear_walk(w->dapm);
- out = is_connected_output_ep(w);
+ out = is_connected_output_ep(w, NULL);
dapm_clear_walk(w->dapm);
ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d",
@@ -1709,7 +1811,7 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
#endif
/* test and update the power status of a mux widget */
-int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
+static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
{
struct snd_soc_dapm_path *path;
@@ -1746,12 +1848,26 @@ int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
}
- return 0;
+ return found;
+}
+
+int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
+ struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
+{
+ struct snd_soc_card *card = widget->dapm->card;
+ int ret;
+
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+ ret = soc_dapm_mux_update_power(widget, kcontrol, mux, e);
+ mutex_unlock(&card->dapm_mutex);
+ if (ret > 0)
+ soc_dpcm_runtime_update(widget);
+ return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
/* test and update the power status of a mixer or switch widget */
-int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
+static int soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
struct snd_kcontrol *kcontrol, int connect)
{
struct snd_soc_dapm_path *path;
@@ -1778,7 +1894,21 @@ int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
}
- return 0;
+ return found;
+}
+
+int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
+ struct snd_kcontrol *kcontrol, int connect)
+{
+ struct snd_soc_card *card = widget->dapm->card;
+ int ret;
+
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+ ret = soc_dapm_mixer_update_power(widget, kcontrol, connect);
+ mutex_unlock(&card->dapm_mutex);
+ if (ret > 0)
+ soc_dpcm_runtime_update(widget);
+ return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
@@ -1939,6 +2069,8 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
*/
int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
{
+ int ret;
+
/*
* Suppress early reports (eg, jacks syncing their state) to avoid
* silly DAPM runs during card startup.
@@ -1946,7 +2078,10 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
if (!dapm->card || !dapm->card->instantiated)
return 0;
- return dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+ ret = dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+ mutex_unlock(&dapm->card->dapm_mutex);
+ return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
@@ -2055,6 +2190,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
case snd_soc_dapm_aif_in:
case snd_soc_dapm_aif_out:
case snd_soc_dapm_dai:
+ case snd_soc_dapm_dai_link:
list_add(&path->list, &dapm->card->paths);
list_add(&path->list_sink, &wsink->sources);
list_add(&path->list_source, &wsource->sinks);
@@ -2110,19 +2246,21 @@ err:
int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route, int num)
{
- int i, ret;
+ int i, ret = 0;
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
for (i = 0; i < num; i++) {
ret = snd_soc_dapm_add_route(dapm, route);
if (ret < 0) {
dev_err(dapm->dev, "Failed to add route %s->%s\n",
route->source, route->sink);
- return ret;
+ break;
}
route++;
}
+ mutex_unlock(&dapm->card->dapm_mutex);
- return 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
@@ -2193,12 +2331,14 @@ int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
int i, err;
int ret = 0;
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
for (i = 0; i < num; i++) {
err = snd_soc_dapm_weak_route(dapm, route);
if (err)
ret = err;
route++;
}
+ mutex_unlock(&dapm->card->dapm_mutex);
return ret;
}
@@ -2217,6 +2357,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
struct snd_soc_dapm_widget *w;
unsigned int val;
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
+
list_for_each_entry(w, &dapm->card->widgets, list)
{
if (w->new)
@@ -2226,8 +2368,10 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
w->kcontrols = kzalloc(w->num_kcontrols *
sizeof(struct snd_kcontrol *),
GFP_KERNEL);
- if (!w->kcontrols)
+ if (!w->kcontrols) {
+ mutex_unlock(&dapm->card->dapm_mutex);
return -ENOMEM;
+ }
}
switch(w->id) {
@@ -2267,6 +2411,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
}
dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+ mutex_unlock(&dapm->card->dapm_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
@@ -2326,6 +2471,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
+ struct snd_soc_card *card = codec->card;
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int reg = mc->reg;
@@ -2352,7 +2498,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
/* old connection must be powered down */
connect = invert ? 1 : 0;
- mutex_lock(&codec->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
change = snd_soc_test_bits(widget->codec, reg, mask, val);
if (change) {
@@ -2368,13 +2514,13 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
update.val = val;
widget->dapm->update = &update;
- snd_soc_dapm_mixer_update_power(widget, kcontrol, connect);
+ soc_dapm_mixer_update_power(widget, kcontrol, connect);
widget->dapm->update = NULL;
}
}
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&card->dapm_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
@@ -2423,6 +2569,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
+ struct snd_soc_card *card = codec->card;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val, mux, change;
unsigned int mask, bitmask;
@@ -2443,7 +2590,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
mask |= (bitmask - 1) << e->shift_r;
}
- mutex_lock(&codec->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
if (change) {
@@ -2459,13 +2606,13 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
update.val = val;
widget->dapm->update = &update;
- snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e);
+ soc_dapm_mux_update_power(widget, kcontrol, mux, e);
widget->dapm->update = NULL;
}
}
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&card->dapm_mutex);
return change;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
@@ -2502,6 +2649,7 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
+ struct snd_soc_card *card = codec->card;
struct soc_enum *e =
(struct soc_enum *)kcontrol->private_value;
int change;
@@ -2511,7 +2659,7 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
if (ucontrol->value.enumerated.item[0] >= e->max)
return -EINVAL;
- mutex_lock(&codec->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
change = widget->value != ucontrol->value.enumerated.item[0];
if (change) {
@@ -2520,11 +2668,11 @@ int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
widget->value = ucontrol->value.enumerated.item[0];
- snd_soc_dapm_mux_update_power(widget, kcontrol, widget->value, e);
+ soc_dapm_mux_update_power(widget, kcontrol, widget->value, e);
}
}
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&card->dapm_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
@@ -2589,6 +2737,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
struct snd_soc_codec *codec = widget->codec;
+ struct snd_soc_card *card = codec->card;
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val, mux, change;
unsigned int mask;
@@ -2607,7 +2756,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
mask |= e->mask << e->shift_r;
}
- mutex_lock(&codec->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
if (change) {
@@ -2623,13 +2772,13 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
update.val = val;
widget->dapm->update = &update;
- snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e);
+ soc_dapm_mux_update_power(widget, kcontrol, mux, e);
widget->dapm->update = NULL;
}
}
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&card->dapm_mutex);
return change;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double);
@@ -2666,12 +2815,12 @@ int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
const char *pin = (const char *)kcontrol->private_value;
- mutex_lock(&card->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
ucontrol->value.integer.value[0] =
snd_soc_dapm_get_pin_status(&card->dapm, pin);
- mutex_unlock(&card->mutex);
+ mutex_unlock(&card->dapm_mutex);
return 0;
}
@@ -2689,17 +2838,16 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
const char *pin = (const char *)kcontrol->private_value;
- mutex_lock(&card->mutex);
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
if (ucontrol->value.integer.value[0])
snd_soc_dapm_enable_pin(&card->dapm, pin);
else
snd_soc_dapm_disable_pin(&card->dapm, pin);
- snd_soc_dapm_sync(&card->dapm);
-
- mutex_unlock(&card->mutex);
+ mutex_unlock(&card->dapm_mutex);
+ snd_soc_dapm_sync(&card->dapm);
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_put_pin_switch);
@@ -2717,9 +2865,9 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
switch (w->id) {
case snd_soc_dapm_regulator_supply:
- w->priv = devm_regulator_get(dapm->dev, w->name);
- if (IS_ERR(w->priv)) {
- ret = PTR_ERR(w->priv);
+ w->regulator = devm_regulator_get(dapm->dev, w->name);
+ if (IS_ERR(w->regulator)) {
+ ret = PTR_ERR(w->regulator);
dev_err(dapm->dev, "Failed to request %s: %d\n",
w->name, ret);
return NULL;
@@ -2771,6 +2919,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
case snd_soc_dapm_hp:
case snd_soc_dapm_mic:
case snd_soc_dapm_line:
+ case snd_soc_dapm_dai_link:
w->power_check = dapm_generic_check_power;
break;
case snd_soc_dapm_supply:
@@ -2816,21 +2965,177 @@ int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
{
struct snd_soc_dapm_widget *w;
int i;
+ int ret = 0;
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
for (i = 0; i < num; i++) {
w = snd_soc_dapm_new_control(dapm, widget);
if (!w) {
dev_err(dapm->dev,
"ASoC: Failed to create DAPM control %s\n",
widget->name);
- return -ENOMEM;
+ ret = -ENOMEM;
+ break;
}
widget++;
}
- return 0;
+ mutex_unlock(&dapm->card->dapm_mutex);
+ return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
+static int snd_soc_dai_link_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_dapm_path *source_p, *sink_p;
+ struct snd_soc_dai *source, *sink;
+ const struct snd_soc_pcm_stream *config = w->params;
+ struct snd_pcm_substream substream;
+ struct snd_pcm_hw_params *params = NULL;
+ u64 fmt;
+ int ret;
+
+ BUG_ON(!config);
+ BUG_ON(list_empty(&w->sources) || list_empty(&w->sinks));
+
+ /* We only support a single source and sink, pick the first */
+ source_p = list_first_entry(&w->sources, struct snd_soc_dapm_path,
+ list_sink);
+ sink_p = list_first_entry(&w->sinks, struct snd_soc_dapm_path,
+ list_source);
+
+ BUG_ON(!source_p || !sink_p);
+ BUG_ON(!sink_p->source || !source_p->sink);
+ BUG_ON(!source_p->source || !sink_p->sink);
+
+ source = source_p->source->priv;
+ sink = sink_p->sink->priv;
+
+ /* Be a little careful as we don't want to overflow the mask array */
+ if (config->formats) {
+ fmt = ffs(config->formats) - 1;
+ } else {
+ dev_warn(w->dapm->dev, "Invalid format %llx specified\n",
+ config->formats);
+ fmt = 0;
+ }
+
+ /* Currently very limited parameter selection */
+ params = kzalloc(sizeof(*params), GFP_KERNEL);
+ if (!params) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ snd_mask_set(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), fmt);
+
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min =
+ config->rate_min;
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max =
+ config->rate_max;
+
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->min
+ = config->channels_min;
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS)->max
+ = config->channels_max;
+
+ memset(&substream, 0, sizeof(substream));
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (source->driver->ops && source->driver->ops->hw_params) {
+ substream.stream = SNDRV_PCM_STREAM_CAPTURE;
+ ret = source->driver->ops->hw_params(&substream,
+ params, source);
+ if (ret != 0) {
+ dev_err(source->dev,
+ "hw_params() failed: %d\n", ret);
+ goto out;
+ }
+ }
+
+ if (sink->driver->ops && sink->driver->ops->hw_params) {
+ substream.stream = SNDRV_PCM_STREAM_PLAYBACK;
+ ret = sink->driver->ops->hw_params(&substream, params,
+ sink);
+ if (ret != 0) {
+ dev_err(sink->dev,
+ "hw_params() failed: %d\n", ret);
+ goto out;
+ }
+ }
+ break;
+
+ case SND_SOC_DAPM_POST_PMU:
+ ret = snd_soc_dai_digital_mute(sink, 0);
+ if (ret != 0 && ret != -ENOTSUPP)
+ dev_warn(sink->dev, "Failed to unmute: %d\n", ret);
+ ret = 0;
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ ret = snd_soc_dai_digital_mute(sink, 1);
+ if (ret != 0 && ret != -ENOTSUPP)
+ dev_warn(sink->dev, "Failed to mute: %d\n", ret);
+ ret = 0;
+ break;
+
+ default:
+ BUG();
+ return -EINVAL;
+ }
+
+out:
+ kfree(params);
+ return ret;
+}
+
+int snd_soc_dapm_new_pcm(struct snd_soc_card *card,
+ const struct snd_soc_pcm_stream *params,
+ struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_dapm_route routes[2];
+ struct snd_soc_dapm_widget template;
+ struct snd_soc_dapm_widget *w;
+ size_t len;
+ char *link_name;
+
+ len = strlen(source->name) + strlen(sink->name) + 2;
+ link_name = devm_kzalloc(card->dev, len, GFP_KERNEL);
+ if (!link_name)
+ return -ENOMEM;
+ snprintf(link_name, len, "%s-%s", source->name, sink->name);
+
+ memset(&template, 0, sizeof(template));
+ template.reg = SND_SOC_NOPM;
+ template.id = snd_soc_dapm_dai_link;
+ template.name = link_name;
+ template.event = snd_soc_dai_link_event;
+ template.event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD;
+
+ dev_dbg(card->dev, "adding %s widget\n", link_name);
+
+ w = snd_soc_dapm_new_control(&card->dapm, &template);
+ if (!w) {
+ dev_err(card->dev, "Failed to create %s widget\n",
+ link_name);
+ return -ENOMEM;
+ }
+
+ w->params = params;
+
+ memset(&routes, 0, sizeof(routes));
+
+ routes[0].source = source->name;
+ routes[0].sink = link_name;
+ routes[1].source = link_name;
+ routes[1].sink = sink->name;
+
+ return snd_soc_dapm_add_routes(&card->dapm, routes,
+ ARRAY_SIZE(routes));
+}
+
int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm,
struct snd_soc_dai *dai)
{
@@ -2934,37 +3239,61 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
return 0;
}
-static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
- int stream, struct snd_soc_dai *dai,
- int event)
+static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
+ int event)
{
- struct snd_soc_dapm_widget *w;
- if (stream == SNDRV_PCM_STREAM_PLAYBACK)
- w = dai->playback_widget;
- else
- w = dai->capture_widget;
+ struct snd_soc_dapm_widget *w_cpu, *w_codec;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
- if (!w)
- return;
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ w_cpu = cpu_dai->playback_widget;
+ w_codec = codec_dai->playback_widget;
+ } else {
+ w_cpu = cpu_dai->capture_widget;
+ w_codec = codec_dai->capture_widget;
+ }
- dapm_mark_dirty(w, "stream event");
+ if (w_cpu) {
- switch (event) {
- case SND_SOC_DAPM_STREAM_START:
- w->active = 1;
- break;
- case SND_SOC_DAPM_STREAM_STOP:
- w->active = 0;
- break;
- case SND_SOC_DAPM_STREAM_SUSPEND:
- case SND_SOC_DAPM_STREAM_RESUME:
- case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
- case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
- break;
+ dapm_mark_dirty(w_cpu, "stream event");
+
+ switch (event) {
+ case SND_SOC_DAPM_STREAM_START:
+ w_cpu->active = 1;
+ break;
+ case SND_SOC_DAPM_STREAM_STOP:
+ w_cpu->active = 0;
+ break;
+ case SND_SOC_DAPM_STREAM_SUSPEND:
+ case SND_SOC_DAPM_STREAM_RESUME:
+ case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
+ case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
+ break;
+ }
+ }
+
+ if (w_codec) {
+
+ dapm_mark_dirty(w_codec, "stream event");
+
+ switch (event) {
+ case SND_SOC_DAPM_STREAM_START:
+ w_codec->active = 1;
+ break;
+ case SND_SOC_DAPM_STREAM_STOP:
+ w_codec->active = 0;
+ break;
+ case SND_SOC_DAPM_STREAM_SUSPEND:
+ case SND_SOC_DAPM_STREAM_RESUME:
+ case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
+ case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
+ break;
+ }
}
- dapm_power_widgets(dapm, event);
+ dapm_power_widgets(&rtd->card->dapm, event);
}
/**
@@ -2978,15 +3307,14 @@ static void soc_dapm_stream_event(struct snd_soc_dapm_context *dapm,
*
* Returns 0 for success else error.
*/
-int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
- struct snd_soc_dai *dai, int event)
+void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
+ int event)
{
- struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_card *card = rtd->card;
- mutex_lock(&codec->mutex);
- soc_dapm_stream_event(&codec->dapm, stream, dai, event);
- mutex_unlock(&codec->mutex);
- return 0;
+ mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+ soc_dapm_stream_event(rtd, stream, event);
+ mutex_unlock(&card->dapm_mutex);
}
/**
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index ee4353f843ea..7f8b3b7428bb 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -36,6 +36,7 @@
int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
struct snd_soc_jack *jack)
{
+ mutex_init(&jack->mutex);
jack->codec = codec;
INIT_LIST_HEAD(&jack->pins);
INIT_LIST_HEAD(&jack->jack_zones);
@@ -75,7 +76,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
codec = jack->codec;
dapm = &codec->dapm;
- mutex_lock(&codec->mutex);
+ mutex_lock(&jack->mutex);
oldstatus = jack->status;
@@ -109,7 +110,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
snd_jack_report(jack->jack, jack->status);
out:
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&jack->mutex);
}
EXPORT_SYMBOL_GPL(snd_soc_jack_report);
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 0ad8dcacd2f3..bedd1717a373 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -22,12 +22,38 @@
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
+#include <linux/export.h>
+#include <linux/debugfs.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <sound/soc-dpcm.h>
#include <sound/initval.h>
+#define DPCM_MAX_BE_USERS 8
+
+/* DPCM stream event, send event to FE and all active BEs. */
+static int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
+ int event)
+{
+ struct snd_soc_dpcm *dpcm;
+
+ list_for_each_entry(dpcm, &fe->dpcm[dir].be_clients, list_be) {
+
+ struct snd_soc_pcm_runtime *be = dpcm->be;
+
+ dev_dbg(be->dev, "pm: BE %s event %d dir %d\n",
+ be->dai_link->name, event, dir);
+
+ snd_soc_dapm_stream_event(be, dir, event);
+ }
+
+ snd_soc_dapm_stream_event(fe, dir, event);
+
+ return 0;
+}
+
static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
struct snd_soc_dai *soc_dai)
{
@@ -156,6 +182,10 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
}
}
+ /* Dynamic PCM DAI links compat checks use dynamic capabilities */
+ if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm)
+ goto dynamic;
+
/* Check that the codec and cpu DAIs are compatible */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
runtime->hw.rate_min =
@@ -248,6 +278,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream)
pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min,
runtime->hw.rate_max);
+dynamic:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
cpu_dai->playback_active++;
codec_dai->playback_active++;
@@ -308,7 +339,7 @@ static void close_delayed_work(struct work_struct *work)
if (codec_dai->pop_wait == 1) {
codec_dai->pop_wait = 0;
snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
- codec_dai, SND_SOC_DAPM_STREAM_STOP);
+ SND_SOC_DAPM_STREAM_STOP);
}
mutex_unlock(&rtd->pcm_mutex);
@@ -373,7 +404,6 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
/* powered down playback stream now */
snd_soc_dapm_stream_event(rtd,
SNDRV_PCM_STREAM_PLAYBACK,
- codec_dai,
SND_SOC_DAPM_STREAM_STOP);
} else {
/* start delayed pop wq here for playback streams */
@@ -384,7 +414,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
} else {
/* capture streams can be powered down now */
snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE,
- codec_dai, SND_SOC_DAPM_STREAM_STOP);
+ SND_SOC_DAPM_STREAM_STOP);
}
mutex_unlock(&rtd->pcm_mutex);
@@ -453,8 +483,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
cancel_delayed_work(&rtd->delayed_work);
}
- snd_soc_dapm_stream_event(rtd, substream->stream, codec_dai,
- SND_SOC_DAPM_STREAM_START);
+ snd_soc_dapm_stream_event(rtd, substream->stream,
+ SND_SOC_DAPM_STREAM_START);
snd_soc_dai_digital_mute(codec_dai, 0);
@@ -602,6 +632,34 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
return 0;
}
+static int soc_pcm_bespoke_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_platform *platform = rtd->platform;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int ret;
+
+ if (codec_dai->driver->ops->bespoke_trigger) {
+ ret = codec_dai->driver->ops->bespoke_trigger(substream, cmd, codec_dai);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (platform->driver->bespoke_trigger) {
+ ret = platform->driver->bespoke_trigger(substream, cmd);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (cpu_dai->driver->ops->bespoke_trigger) {
+ ret = cpu_dai->driver->ops->bespoke_trigger(substream, cmd, cpu_dai);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
/*
* soc level wrapper for pointer callback
* If cpu_dai, codec_dai, platform driver has the delay callback, than
@@ -634,6 +692,1308 @@ static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
return offset;
}
+/* connect a FE and BE */
+static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe,
+ struct snd_soc_pcm_runtime *be, int stream)
+{
+ struct snd_soc_dpcm *dpcm;
+
+ /* only add new dpcms */
+ list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+ if (dpcm->be == be && dpcm->fe == fe)
+ return 0;
+ }
+
+ dpcm = kzalloc(sizeof(struct snd_soc_dpcm), GFP_KERNEL);
+ if (!dpcm)
+ return -ENOMEM;
+
+ dpcm->be = be;
+ dpcm->fe = fe;
+ be->dpcm[stream].runtime = fe->dpcm[stream].runtime;
+ dpcm->state = SND_SOC_DPCM_LINK_STATE_NEW;
+ list_add(&dpcm->list_be, &fe->dpcm[stream].be_clients);
+ list_add(&dpcm->list_fe, &be->dpcm[stream].fe_clients);
+
+ dev_dbg(fe->dev, " connected new DPCM %s path %s %s %s\n",
+ stream ? "capture" : "playback", fe->dai_link->name,
+ stream ? "<-" : "->", be->dai_link->name);
+
+#ifdef CONFIG_DEBUG_FS
+ dpcm->debugfs_state = debugfs_create_u32(be->dai_link->name, 0644,
+ fe->debugfs_dpcm_root, &dpcm->state);
+#endif
+ return 1;
+}
+
+/* reparent a BE onto another FE */
+static void dpcm_be_reparent(struct snd_soc_pcm_runtime *fe,
+ struct snd_soc_pcm_runtime *be, int stream)
+{
+ struct snd_soc_dpcm *dpcm;
+ struct snd_pcm_substream *fe_substream, *be_substream;
+
+ /* reparent if BE is connected to other FEs */
+ if (!be->dpcm[stream].users)
+ return;
+
+ be_substream = snd_soc_dpcm_get_substream(be, stream);
+
+ list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {
+ if (dpcm->fe == fe)
+ continue;
+
+ dev_dbg(fe->dev, " reparent %s path %s %s %s\n",
+ stream ? "capture" : "playback",
+ dpcm->fe->dai_link->name,
+ stream ? "<-" : "->", dpcm->be->dai_link->name);
+
+ fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, stream);
+ be_substream->runtime = fe_substream->runtime;
+ break;
+ }
+}
+
+/* disconnect a BE and FE */
+static void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream)
+{
+ struct snd_soc_dpcm *dpcm, *d;
+
+ list_for_each_entry_safe(dpcm, d, &fe->dpcm[stream].be_clients, list_be) {
+ dev_dbg(fe->dev, "BE %s disconnect check for %s\n",
+ stream ? "capture" : "playback",
+ dpcm->be->dai_link->name);
+
+ if (dpcm->state != SND_SOC_DPCM_LINK_STATE_FREE)
+ continue;
+
+ dev_dbg(fe->dev, " freed DSP %s path %s %s %s\n",
+ stream ? "capture" : "playback", fe->dai_link->name,
+ stream ? "<-" : "->", dpcm->be->dai_link->name);
+
+ /* BEs still alive need new FE */
+ dpcm_be_reparent(fe, dpcm->be, stream);
+
+#ifdef CONFIG_DEBUG_FS
+ debugfs_remove(dpcm->debugfs_state);
+#endif
+ list_del(&dpcm->list_be);
+ list_del(&dpcm->list_fe);
+ kfree(dpcm);
+ }
+}
+
+/* get BE for DAI widget and stream */
+static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card,
+ struct snd_soc_dapm_widget *widget, int stream)
+{
+ struct snd_soc_pcm_runtime *be;
+ int i;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ for (i = 0; i < card->num_links; i++) {
+ be = &card->rtd[i];
+
+ if (be->cpu_dai->playback_widget == widget ||
+ be->codec_dai->playback_widget == widget)
+ return be;
+ }
+ } else {
+
+ for (i = 0; i < card->num_links; i++) {
+ be = &card->rtd[i];
+
+ if (be->cpu_dai->capture_widget == widget ||
+ be->codec_dai->capture_widget == widget)
+ return be;
+ }
+ }
+
+ dev_err(card->dev, "can't get %s BE for %s\n",
+ stream ? "capture" : "playback", widget->name);
+ return NULL;
+}
+
+static inline struct snd_soc_dapm_widget *
+ rtd_get_cpu_widget(struct snd_soc_pcm_runtime *rtd, int stream)
+{
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ return rtd->cpu_dai->playback_widget;
+ else
+ return rtd->cpu_dai->capture_widget;
+}
+
+static inline struct snd_soc_dapm_widget *
+ rtd_get_codec_widget(struct snd_soc_pcm_runtime *rtd, int stream)
+{
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ return rtd->codec_dai->playback_widget;
+ else
+ return rtd->codec_dai->capture_widget;
+}
+
+static int widget_in_list(struct snd_soc_dapm_widget_list *list,
+ struct snd_soc_dapm_widget *widget)
+{
+ int i;
+
+ for (i = 0; i < list->num_widgets; i++) {
+ if (widget == list->widgets[i])
+ return 1;
+ }
+
+ return 0;
+}
+
+static int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
+ int stream, struct snd_soc_dapm_widget_list **list_)
+{
+ struct snd_soc_dai *cpu_dai = fe->cpu_dai;
+ struct snd_soc_dapm_widget_list *list;
+ int paths;
+
+ list = kzalloc(sizeof(struct snd_soc_dapm_widget_list) +
+ sizeof(struct snd_soc_dapm_widget *), GFP_KERNEL);
+ if (list == NULL)
+ return -ENOMEM;
+
+ /* get number of valid DAI paths and their widgets */
+ paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, &list);
+
+ dev_dbg(fe->dev, "found %d audio %s paths\n", paths,
+ stream ? "capture" : "playback");
+
+ *list_ = list;
+ return paths;
+}
+
+static inline void dpcm_path_put(struct snd_soc_dapm_widget_list **list)
+{
+ kfree(*list);
+}
+
+static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
+ struct snd_soc_dapm_widget_list **list_)
+{
+ struct snd_soc_dpcm *dpcm;
+ struct snd_soc_dapm_widget_list *list = *list_;
+ struct snd_soc_dapm_widget *widget;
+ int prune = 0;
+
+ /* Destroy any old FE <--> BE connections */
+ list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+ /* is there a valid CPU DAI widget for this BE */
+ widget = rtd_get_cpu_widget(dpcm->be, stream);
+
+ /* prune the BE if it's no longer in our active list */
+ if (widget && widget_in_list(list, widget))
+ continue;
+
+ /* is there a valid CODEC DAI widget for this BE */
+ widget = rtd_get_codec_widget(dpcm->be, stream);
+
+ /* prune the BE if it's no longer in our active list */
+ if (widget && widget_in_list(list, widget))
+ continue;
+
+ dev_dbg(fe->dev, "pruning %s BE %s for %s\n",
+ stream ? "capture" : "playback",
+ dpcm->be->dai_link->name, fe->dai_link->name);
+ dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
+ dpcm->be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
+ prune++;
+ }
+
+ dev_dbg(fe->dev, "found %d old BE paths for pruning\n", prune);
+ return prune;
+}
+
+static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
+ struct snd_soc_dapm_widget_list **list_)
+{
+ struct snd_soc_card *card = fe->card;
+ struct snd_soc_dapm_widget_list *list = *list_;
+ struct snd_soc_pcm_runtime *be;
+ int i, new = 0, err;
+
+ /* Create any new FE <--> BE connections */
+ for (i = 0; i < list->num_widgets; i++) {
+
+ if (list->widgets[i]->id != snd_soc_dapm_dai)
+ continue;
+
+ /* is there a valid BE rtd for this widget */
+ be = dpcm_get_be(card, list->widgets[i], stream);
+ if (!be) {
+ dev_err(fe->dev, "no BE found for %s\n",
+ list->widgets[i]->name);
+ continue;
+ }
+
+ /* make sure BE is a real BE */
+ if (!be->dai_link->no_pcm)
+ continue;
+
+ /* don't connect if FE is not running */
+ if (!fe->dpcm[stream].runtime)
+ continue;
+
+ /* newly connected FE and BE */
+ err = dpcm_be_connect(fe, be, stream);
+ if (err < 0) {
+ dev_err(fe->dev, "can't connect %s\n",
+ list->widgets[i]->name);
+ break;
+ } else if (err == 0) /* already connected */
+ continue;
+
+ /* new */
+ be->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
+ new++;
+ }
+
+ dev_dbg(fe->dev, "found %d new BE paths\n", new);
+ return new;
+}
+
+/*
+ * Find the corresponding BE DAIs that source or sink audio to this
+ * FE substream.
+ */
+static int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
+ int stream, struct snd_soc_dapm_widget_list **list, int new)
+{
+ if (new)
+ return dpcm_add_paths(fe, stream, list);
+ else
+ return dpcm_prune_paths(fe, stream, list);
+}
+
+static void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
+{
+ struct snd_soc_dpcm *dpcm;
+
+ list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
+ dpcm->be->dpcm[stream].runtime_update =
+ SND_SOC_DPCM_UPDATE_NO;
+}
+
+static void dpcm_be_dai_startup_unwind(struct snd_soc_pcm_runtime *fe,
+ int stream)
+{
+ struct snd_soc_dpcm *dpcm;
+
+ /* disable any enabled and non active backends */
+ list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+ struct snd_soc_pcm_runtime *be = dpcm->be;
+ struct snd_pcm_substream *be_substream =
+ snd_soc_dpcm_get_substream(be, stream);
+
+ if (be->dpcm[stream].users == 0)
+ dev_err(be->dev, "no users %s at close - state %d\n",
+ stream ? "capture" : "playback",
+ be->dpcm[stream].state);
+
+ if (--be->dpcm[stream].users != 0)
+ continue;
+
+ if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
+ continue;
+
+ soc_pcm_close(be_substream);
+ be_substream->runtime = NULL;
+ be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
+ }
+}
+
+static int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream)
+{
+ struct snd_soc_dpcm *dpcm;
+ int err, count = 0;
+
+ /* only startup BE DAIs that are either sinks or sources to this FE DAI */
+ list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+ struct snd_soc_pcm_runtime *be = dpcm->be;
+ struct snd_pcm_substream *be_substream =
+ snd_soc_dpcm_get_substream(be, stream);
+
+ /* is this op for this BE ? */
+ if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+ continue;
+
+ /* first time the dpcm is open ? */
+ if (be->dpcm[stream].users == DPCM_MAX_BE_USERS)
+ dev_err(be->dev, "too many users %s at open %d\n",
+ stream ? "capture" : "playback",
+ be->dpcm[stream].state);
+
+ if (be->dpcm[stream].users++ != 0)
+ continue;
+
+ if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_NEW) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_CLOSE))
+ continue;
+
+ dev_dbg(be->dev, "dpcm: open BE %s\n", be->dai_link->name);
+
+ be_substream->runtime = be->dpcm[stream].runtime;
+ err = soc_pcm_open(be_substream);
+ if (err < 0) {
+ dev_err(be->dev, "BE open failed %d\n", err);
+ be->dpcm[stream].users--;
+ if (be->dpcm[stream].users < 0)
+ dev_err(be->dev, "no users %s at unwind %d\n",
+ stream ? "capture" : "playback",
+ be->dpcm[stream].state);
+
+ be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
+ goto unwind;
+ }
+
+ be->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
+ count++;
+ }
+
+ return count;
+
+unwind:
+ /* disable any enabled and non active backends */
+ list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+ struct snd_soc_pcm_runtime *be = dpcm->be;
+ struct snd_pcm_substream *be_substream =
+ snd_soc_dpcm_get_substream(be, stream);
+
+ if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+ continue;
+
+ if (be->dpcm[stream].users == 0)
+ dev_err(be->dev, "no users %s at close %d\n",
+ stream ? "capture" : "playback",
+ be->dpcm[stream].state);
+
+ if (--be->dpcm[stream].users != 0)
+ continue;
+
+ if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN)
+ continue;
+
+ soc_pcm_close(be_substream);
+ be_substream->runtime = NULL;
+ be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
+ }
+
+ return err;
+}
+
+static void dpcm_set_fe_runtime(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ runtime->hw.rate_min = cpu_dai_drv->playback.rate_min;
+ runtime->hw.rate_max = cpu_dai_drv->playback.rate_max;
+ runtime->hw.channels_min = cpu_dai_drv->playback.channels_min;
+ runtime->hw.channels_max = cpu_dai_drv->playback.channels_max;
+ runtime->hw.formats &= cpu_dai_drv->playback.formats;
+ runtime->hw.rates = cpu_dai_drv->playback.rates;
+ } else {
+ runtime->hw.rate_min = cpu_dai_drv->capture.rate_min;
+ runtime->hw.rate_max = cpu_dai_drv->capture.rate_max;
+ runtime->hw.channels_min = cpu_dai_drv->capture.channels_min;
+ runtime->hw.channels_max = cpu_dai_drv->capture.channels_max;
+ runtime->hw.formats &= cpu_dai_drv->capture.formats;
+ runtime->hw.rates = cpu_dai_drv->capture.rates;
+ }
+}
+
+static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream)
+{
+ struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
+ struct snd_pcm_runtime *runtime = fe_substream->runtime;
+ int stream = fe_substream->stream, ret = 0;
+
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+ ret = dpcm_be_dai_startup(fe, fe_substream->stream);
+ if (ret < 0) {
+ dev_err(fe->dev,"dpcm: failed to start some BEs %d\n", ret);
+ goto be_err;
+ }
+
+ dev_dbg(fe->dev, "dpcm: open FE %s\n", fe->dai_link->name);
+
+ /* start the DAI frontend */
+ ret = soc_pcm_open(fe_substream);
+ if (ret < 0) {
+ dev_err(fe->dev,"dpcm: failed to start FE %d\n", ret);
+ goto unwind;
+ }
+
+ fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN;
+
+ dpcm_set_fe_runtime(fe_substream);
+ snd_pcm_limit_hw_rates(runtime);
+
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+ return 0;
+
+unwind:
+ dpcm_be_dai_startup_unwind(fe, fe_substream->stream);
+be_err:
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+ return ret;
+}
+
+static int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
+{
+ struct snd_soc_dpcm *dpcm;
+
+ /* only shutdown BEs that are either sinks or sources to this FE DAI */
+ list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+ struct snd_soc_pcm_runtime *be = dpcm->be;
+ struct snd_pcm_substream *be_substream =
+ snd_soc_dpcm_get_substream(be, stream);
+
+ /* is this op for this BE ? */
+ if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+ continue;
+
+ if (be->dpcm[stream].users == 0)
+ dev_err(be->dev, "no users %s at close - state %d\n",
+ stream ? "capture" : "playback",
+ be->dpcm[stream].state);
+
+ if (--be->dpcm[stream].users != 0)
+ continue;
+
+ if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN))
+ continue;
+
+ dev_dbg(be->dev, "dpcm: close BE %s\n",
+ dpcm->fe->dai_link->name);
+
+ soc_pcm_close(be_substream);
+ be_substream->runtime = NULL;
+
+ be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
+ }
+ return 0;
+}
+
+static int dpcm_fe_dai_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *fe = substream->private_data;
+ int stream = substream->stream;
+
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+ /* shutdown the BEs */
+ dpcm_be_dai_shutdown(fe, substream->stream);
+
+ dev_dbg(fe->dev, "dpcm: close FE %s\n", fe->dai_link->name);
+
+ /* now shutdown the frontend */
+ soc_pcm_close(substream);
+
+ /* run the stream event for each BE */
+ dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
+
+ fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+ return 0;
+}
+
+static int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
+{
+ struct snd_soc_dpcm *dpcm;
+
+ /* only hw_params backends that are either sinks or sources
+ * to this frontend DAI */
+ list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+ struct snd_soc_pcm_runtime *be = dpcm->be;
+ struct snd_pcm_substream *be_substream =
+ snd_soc_dpcm_get_substream(be, stream);
+
+ /* is this op for this BE ? */
+ if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+ continue;
+
+ /* only free hw when no longer used - check all FEs */
+ if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
+ continue;
+
+ if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
+ continue;
+
+ dev_dbg(be->dev, "dpcm: hw_free BE %s\n",
+ dpcm->fe->dai_link->name);
+
+ soc_pcm_hw_free(be_substream);
+
+ be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
+ }
+
+ return 0;
+}
+
+static int dpcm_fe_dai_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *fe = substream->private_data;
+ int err, stream = substream->stream;
+
+ mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+ dev_dbg(fe->dev, "dpcm: hw_free FE %s\n", fe->dai_link->name);
+
+ /* call hw_free on the frontend */
+ err = soc_pcm_hw_free(substream);
+ if (err < 0)
+ dev_err(fe->dev,"dpcm: hw_free FE %s failed\n",
+ fe->dai_link->name);
+
+ /* only hw_params backends that are either sinks or sources
+ * to this frontend DAI */
+ err = dpcm_be_dai_hw_free(fe, stream);
+
+ fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_FREE;
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+
+ mutex_unlock(&fe->card->mutex);
+ return 0;
+}
+
+static int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream)
+{
+ struct snd_soc_dpcm *dpcm;
+ int ret;
+
+ list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+ struct snd_soc_pcm_runtime *be = dpcm->be;
+ struct snd_pcm_substream *be_substream =
+ snd_soc_dpcm_get_substream(be, stream);
+
+ /* is this op for this BE ? */
+ if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+ continue;
+
+ /* only allow hw_params() if no connected FEs are running */
+ if (!snd_soc_dpcm_can_be_params(fe, be, stream))
+ continue;
+
+ if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE))
+ continue;
+
+ dev_dbg(be->dev, "dpcm: hw_params BE %s\n",
+ dpcm->fe->dai_link->name);
+
+ /* copy params for each dpcm */
+ memcpy(&dpcm->hw_params, &fe->dpcm[stream].hw_params,
+ sizeof(struct snd_pcm_hw_params));
+
+ /* perform any hw_params fixups */
+ if (be->dai_link->be_hw_params_fixup) {
+ ret = be->dai_link->be_hw_params_fixup(be,
+ &dpcm->hw_params);
+ if (ret < 0) {
+ dev_err(be->dev,
+ "dpcm: hw_params BE fixup failed %d\n",
+ ret);
+ goto unwind;
+ }
+ }
+
+ ret = soc_pcm_hw_params(be_substream, &dpcm->hw_params);
+ if (ret < 0) {
+ dev_err(dpcm->be->dev,
+ "dpcm: hw_params BE failed %d\n", ret);
+ goto unwind;
+ }
+
+ be->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
+ }
+ return 0;
+
+unwind:
+ /* disable any enabled and non active backends */
+ list_for_each_entry_continue_reverse(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+ struct snd_soc_pcm_runtime *be = dpcm->be;
+ struct snd_pcm_substream *be_substream =
+ snd_soc_dpcm_get_substream(be, stream);
+
+ if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+ continue;
+
+ /* only allow hw_free() if no connected FEs are running */
+ if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
+ continue;
+
+ if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_OPEN) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
+ continue;
+
+ soc_pcm_hw_free(be_substream);
+ }
+
+ return ret;
+}
+
+static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *fe = substream->private_data;
+ int ret, stream = substream->stream;
+
+ mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+ memcpy(&fe->dpcm[substream->stream].hw_params, params,
+ sizeof(struct snd_pcm_hw_params));
+ ret = dpcm_be_dai_hw_params(fe, substream->stream);
+ if (ret < 0) {
+ dev_err(fe->dev,"dpcm: hw_params BE failed %d\n", ret);
+ goto out;
+ }
+
+ dev_dbg(fe->dev, "dpcm: hw_params FE %s rate %d chan %x fmt %d\n",
+ fe->dai_link->name, params_rate(params),
+ params_channels(params), params_format(params));
+
+ /* call hw_params on the frontend */
+ ret = soc_pcm_hw_params(substream, params);
+ if (ret < 0) {
+ dev_err(fe->dev,"dpcm: hw_params FE failed %d\n", ret);
+ dpcm_be_dai_hw_free(fe, stream);
+ } else
+ fe->dpcm[stream].state = SND_SOC_DPCM_STATE_HW_PARAMS;
+
+out:
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+ mutex_unlock(&fe->card->mutex);
+ return ret;
+}
+
+static int dpcm_do_trigger(struct snd_soc_dpcm *dpcm,
+ struct snd_pcm_substream *substream, int cmd)
+{
+ int ret;
+
+ dev_dbg(dpcm->be->dev, "dpcm: trigger BE %s cmd %d\n",
+ dpcm->fe->dai_link->name, cmd);
+
+ ret = soc_pcm_trigger(substream, cmd);
+ if (ret < 0)
+ dev_err(dpcm->be->dev,"dpcm: trigger BE failed %d\n", ret);
+
+ return ret;
+}
+
+static int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
+ int cmd)
+{
+ struct snd_soc_dpcm *dpcm;
+ int ret = 0;
+
+ list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+ struct snd_soc_pcm_runtime *be = dpcm->be;
+ struct snd_pcm_substream *be_substream =
+ snd_soc_dpcm_get_substream(be, stream);
+
+ /* is this op for this BE ? */
+ if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+ continue;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
+ continue;
+
+ ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+ if (ret)
+ return ret;
+
+ be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
+ break;
+ case SNDRV_PCM_TRIGGER_RESUME:
+ if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
+ continue;
+
+ ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+ if (ret)
+ return ret;
+
+ be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
+ continue;
+
+ ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+ if (ret)
+ return ret;
+
+ be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
+ continue;
+
+ if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
+ continue;
+
+ ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+ if (ret)
+ return ret;
+
+ be->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)
+ continue;
+
+ if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
+ continue;
+
+ ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+ if (ret)
+ return ret;
+
+ be->dpcm[stream].state = SND_SOC_DPCM_STATE_SUSPEND;
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
+ continue;
+
+ if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
+ continue;
+
+ ret = dpcm_do_trigger(dpcm, be_substream, cmd);
+ if (ret)
+ return ret;
+
+ be->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
+ break;
+ }
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
+
+static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_soc_pcm_runtime *fe = substream->private_data;
+ int stream = substream->stream, ret;
+ enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
+
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+ switch (trigger) {
+ case SND_SOC_DPCM_TRIGGER_PRE:
+ /* call trigger on the frontend before the backend. */
+
+ dev_dbg(fe->dev, "dpcm: pre trigger FE %s cmd %d\n",
+ fe->dai_link->name, cmd);
+
+ ret = soc_pcm_trigger(substream, cmd);
+ if (ret < 0) {
+ dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret);
+ goto out;
+ }
+
+ ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
+ break;
+ case SND_SOC_DPCM_TRIGGER_POST:
+ /* call trigger on the frontend after the backend. */
+
+ ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
+ if (ret < 0) {
+ dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret);
+ goto out;
+ }
+
+ dev_dbg(fe->dev, "dpcm: post trigger FE %s cmd %d\n",
+ fe->dai_link->name, cmd);
+
+ ret = soc_pcm_trigger(substream, cmd);
+ break;
+ case SND_SOC_DPCM_TRIGGER_BESPOKE:
+ /* bespoke trigger() - handles both FE and BEs */
+
+ dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd %d\n",
+ fe->dai_link->name, cmd);
+
+ ret = soc_pcm_bespoke_trigger(substream, cmd);
+ if (ret < 0) {
+ dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret);
+ goto out;
+ }
+ break;
+ default:
+ dev_err(fe->dev, "dpcm: invalid trigger cmd %d for %s\n", cmd,
+ fe->dai_link->name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ fe->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
+ break;
+ }
+
+out:
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+ return ret;
+}
+
+static int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
+{
+ struct snd_soc_dpcm *dpcm;
+ int ret = 0;
+
+ list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+
+ struct snd_soc_pcm_runtime *be = dpcm->be;
+ struct snd_pcm_substream *be_substream =
+ snd_soc_dpcm_get_substream(be, stream);
+
+ /* is this op for this BE ? */
+ if (!snd_soc_dpcm_be_can_update(fe, be, stream))
+ continue;
+
+ if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
+ continue;
+
+ dev_dbg(be->dev, "dpcm: prepare BE %s\n",
+ dpcm->fe->dai_link->name);
+
+ ret = soc_pcm_prepare(be_substream);
+ if (ret < 0) {
+ dev_err(be->dev, "dpcm: backend prepare failed %d\n",
+ ret);
+ break;
+ }
+
+ be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
+ }
+ return ret;
+}
+
+static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *fe = substream->private_data;
+ int stream = substream->stream, ret = 0;
+
+ mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+
+ dev_dbg(fe->dev, "dpcm: prepare FE %s\n", fe->dai_link->name);
+
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
+
+ /* there is no point preparing this FE if there are no BEs */
+ if (list_empty(&fe->dpcm[stream].be_clients)) {
+ dev_err(fe->dev, "dpcm: no backend DAIs enabled for %s\n",
+ fe->dai_link->name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = dpcm_be_dai_prepare(fe, substream->stream);
+ if (ret < 0)
+ goto out;
+
+ /* call prepare on the frontend */
+ ret = soc_pcm_prepare(substream);
+ if (ret < 0) {
+ dev_err(fe->dev,"dpcm: prepare FE %s failed\n",
+ fe->dai_link->name);
+ goto out;
+ }
+
+ /* run the stream event for each BE */
+ dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
+ fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
+
+out:
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+ mutex_unlock(&fe->card->mutex);
+
+ return ret;
+}
+
+static int soc_pcm_ioctl(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_platform *platform = rtd->platform;
+
+ if (platform->driver->ops->ioctl)
+ return platform->driver->ops->ioctl(substream, cmd, arg);
+ return snd_pcm_lib_ioctl(substream, cmd, arg);
+}
+
+static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
+{
+ struct snd_pcm_substream *substream =
+ snd_soc_dpcm_get_substream(fe, stream);
+ enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
+ int err;
+
+ dev_dbg(fe->dev, "runtime %s close on FE %s\n",
+ stream ? "capture" : "playback", fe->dai_link->name);
+
+ if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
+ /* call bespoke trigger - FE takes care of all BE triggers */
+ dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd stop\n",
+ fe->dai_link->name);
+
+ err = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_STOP);
+ if (err < 0)
+ dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err);
+ } else {
+ dev_dbg(fe->dev, "dpcm: trigger FE %s cmd stop\n",
+ fe->dai_link->name);
+
+ err = dpcm_be_dai_trigger(fe, stream, SNDRV_PCM_TRIGGER_STOP);
+ if (err < 0)
+ dev_err(fe->dev,"dpcm: trigger FE failed %d\n", err);
+ }
+
+ err = dpcm_be_dai_hw_free(fe, stream);
+ if (err < 0)
+ dev_err(fe->dev,"dpcm: hw_free FE failed %d\n", err);
+
+ err = dpcm_be_dai_shutdown(fe, stream);
+ if (err < 0)
+ dev_err(fe->dev,"dpcm: shutdown FE failed %d\n", err);
+
+ /* run the stream event for each BE */
+ dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
+
+ return 0;
+}
+
+static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
+{
+ struct snd_pcm_substream *substream =
+ snd_soc_dpcm_get_substream(fe, stream);
+ struct snd_soc_dpcm *dpcm;
+ enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
+ int ret;
+
+ dev_dbg(fe->dev, "runtime %s open on FE %s\n",
+ stream ? "capture" : "playback", fe->dai_link->name);
+
+ /* Only start the BE if the FE is ready */
+ if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE ||
+ fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE)
+ return -EINVAL;
+
+ /* startup must always be called for new BEs */
+ ret = dpcm_be_dai_startup(fe, stream);
+ if (ret < 0) {
+ goto disconnect;
+ return ret;
+ }
+
+ /* keep going if FE state is > open */
+ if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_OPEN)
+ return 0;
+
+ ret = dpcm_be_dai_hw_params(fe, stream);
+ if (ret < 0) {
+ goto close;
+ return ret;
+ }
+
+ /* keep going if FE state is > hw_params */
+ if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_PARAMS)
+ return 0;
+
+
+ ret = dpcm_be_dai_prepare(fe, stream);
+ if (ret < 0) {
+ goto hw_free;
+ return ret;
+ }
+
+ /* run the stream event for each BE */
+ dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
+
+ /* keep going if FE state is > prepare */
+ if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE ||
+ fe->dpcm[stream].state == SND_SOC_DPCM_STATE_STOP)
+ return 0;
+
+ if (trigger == SND_SOC_DPCM_TRIGGER_BESPOKE) {
+ /* call trigger on the frontend - FE takes care of all BE triggers */
+ dev_dbg(fe->dev, "dpcm: bespoke trigger FE %s cmd start\n",
+ fe->dai_link->name);
+
+ ret = soc_pcm_bespoke_trigger(substream, SNDRV_PCM_TRIGGER_START);
+ if (ret < 0) {
+ dev_err(fe->dev,"dpcm: bespoke trigger FE failed %d\n", ret);
+ goto hw_free;
+ }
+ } else {
+ dev_dbg(fe->dev, "dpcm: trigger FE %s cmd start\n",
+ fe->dai_link->name);
+
+ ret = dpcm_be_dai_trigger(fe, stream,
+ SNDRV_PCM_TRIGGER_START);
+ if (ret < 0) {
+ dev_err(fe->dev,"dpcm: trigger FE failed %d\n", ret);
+ goto hw_free;
+ }
+ }
+
+ return 0;
+
+hw_free:
+ dpcm_be_dai_hw_free(fe, stream);
+close:
+ dpcm_be_dai_shutdown(fe, stream);
+disconnect:
+ /* disconnect any non started BEs */
+ list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+ struct snd_soc_pcm_runtime *be = dpcm->be;
+ if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_START)
+ dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
+ }
+
+ return ret;
+}
+
+static int dpcm_run_new_update(struct snd_soc_pcm_runtime *fe, int stream)
+{
+ int ret;
+
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
+ ret = dpcm_run_update_startup(fe, stream);
+ if (ret < 0)
+ dev_err(fe->dev, "failed to startup some BEs\n");
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+
+ return ret;
+}
+
+static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream)
+{
+ int ret;
+
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_BE;
+ ret = dpcm_run_update_shutdown(fe, stream);
+ if (ret < 0)
+ dev_err(fe->dev, "failed to shutdown some BEs\n");
+ fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
+
+ return ret;
+}
+
+/* Called by DAPM mixer/mux changes to update audio routing between PCMs and
+ * any DAI links.
+ */
+int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *widget)
+{
+ struct snd_soc_card *card;
+ int i, old, new, paths;
+
+ if (widget->codec)
+ card = widget->codec->card;
+ else if (widget->platform)
+ card = widget->platform->card;
+ else
+ return -EINVAL;
+
+ mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_dapm_widget_list *list;
+ struct snd_soc_pcm_runtime *fe = &card->rtd[i];
+
+ /* make sure link is FE */
+ if (!fe->dai_link->dynamic)
+ continue;
+
+ /* only check active links */
+ if (!fe->cpu_dai->active)
+ continue;
+
+ /* DAPM sync will call this to update DSP paths */
+ dev_dbg(fe->dev, "DPCM runtime update for FE %s\n",
+ fe->dai_link->name);
+
+ /* skip if FE doesn't have playback capability */
+ if (!fe->cpu_dai->driver->playback.channels_min)
+ goto capture;
+
+ paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list);
+ if (paths < 0) {
+ dev_warn(fe->dev, "%s no valid %s path\n",
+ fe->dai_link->name, "playback");
+ mutex_unlock(&card->mutex);
+ return paths;
+ }
+
+ /* update any new playback paths */
+ new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 1);
+ if (new) {
+ dpcm_run_new_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
+ dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
+ dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
+ }
+
+ /* update any old playback paths */
+ old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, &list, 0);
+ if (old) {
+ dpcm_run_old_update(fe, SNDRV_PCM_STREAM_PLAYBACK);
+ dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_PLAYBACK);
+ dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_PLAYBACK);
+ }
+
+capture:
+ /* skip if FE doesn't have capture capability */
+ if (!fe->cpu_dai->driver->capture.channels_min)
+ continue;
+
+ paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list);
+ if (paths < 0) {
+ dev_warn(fe->dev, "%s no valid %s path\n",
+ fe->dai_link->name, "capture");
+ mutex_unlock(&card->mutex);
+ return paths;
+ }
+
+ /* update any new capture paths */
+ new = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 1);
+ if (new) {
+ dpcm_run_new_update(fe, SNDRV_PCM_STREAM_CAPTURE);
+ dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
+ dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
+ }
+
+ /* update any old capture paths */
+ old = dpcm_process_paths(fe, SNDRV_PCM_STREAM_CAPTURE, &list, 0);
+ if (old) {
+ dpcm_run_old_update(fe, SNDRV_PCM_STREAM_CAPTURE);
+ dpcm_clear_pending_state(fe, SNDRV_PCM_STREAM_CAPTURE);
+ dpcm_be_disconnect(fe, SNDRV_PCM_STREAM_CAPTURE);
+ }
+
+ dpcm_path_put(&list);
+ }
+
+ mutex_unlock(&card->mutex);
+ return 0;
+}
+int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute)
+{
+ struct snd_soc_dpcm *dpcm;
+ struct list_head *clients =
+ &fe->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients;
+
+ list_for_each_entry(dpcm, clients, list_be) {
+
+ struct snd_soc_pcm_runtime *be = dpcm->be;
+ struct snd_soc_dai *dai = be->codec_dai;
+ struct snd_soc_dai_driver *drv = dai->driver;
+
+ if (be->dai_link->ignore_suspend)
+ continue;
+
+ dev_dbg(be->dev, "BE digital mute %s\n", be->dai_link->name);
+
+ if (drv->ops->digital_mute && dai->playback_active)
+ drv->ops->digital_mute(dai, mute);
+ }
+
+ return 0;
+}
+
+static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
+{
+ struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
+ struct snd_soc_dpcm *dpcm;
+ struct snd_soc_dapm_widget_list *list;
+ int ret;
+ int stream = fe_substream->stream;
+
+ mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+ fe->dpcm[stream].runtime = fe_substream->runtime;
+
+ if (dpcm_path_get(fe, stream, &list) <= 0) {
+ dev_warn(fe->dev, "asoc: %s no valid %s route\n",
+ fe->dai_link->name, stream ? "capture" : "playback");
+ mutex_unlock(&fe->card->mutex);
+ return -EINVAL;
+ }
+
+ /* calculate valid and active FE <-> BE dpcms */
+ dpcm_process_paths(fe, stream, &list, 1);
+
+ ret = dpcm_fe_dai_startup(fe_substream);
+ if (ret < 0) {
+ /* clean up all links */
+ list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
+ dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
+
+ dpcm_be_disconnect(fe, stream);
+ fe->dpcm[stream].runtime = NULL;
+ }
+
+ dpcm_clear_pending_state(fe, stream);
+ dpcm_path_put(&list);
+ mutex_unlock(&fe->card->mutex);
+ return ret;
+}
+
+static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream)
+{
+ struct snd_soc_pcm_runtime *fe = fe_substream->private_data;
+ struct snd_soc_dpcm *dpcm;
+ int stream = fe_substream->stream, ret;
+
+ mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
+ ret = dpcm_fe_dai_shutdown(fe_substream);
+
+ /* mark FE's links ready to prune */
+ list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
+ dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
+
+ dpcm_be_disconnect(fe, stream);
+
+ fe->dpcm[stream].runtime = NULL;
+ mutex_unlock(&fe->card->mutex);
+ return ret;
+}
+
/* create a new pcm */
int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
{
@@ -641,56 +2001,94 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- struct snd_pcm_ops *soc_pcm_ops = &rtd->ops;
struct snd_pcm *pcm;
char new_name[64];
int ret = 0, playback = 0, capture = 0;
- soc_pcm_ops->open = soc_pcm_open;
- soc_pcm_ops->close = soc_pcm_close;
- soc_pcm_ops->hw_params = soc_pcm_hw_params;
- soc_pcm_ops->hw_free = soc_pcm_hw_free;
- soc_pcm_ops->prepare = soc_pcm_prepare;
- soc_pcm_ops->trigger = soc_pcm_trigger;
- soc_pcm_ops->pointer = soc_pcm_pointer;
-
- /* check client and interface hw capabilities */
- snprintf(new_name, sizeof(new_name), "%s %s-%d",
- rtd->dai_link->stream_name, codec_dai->name, num);
-
- if (codec_dai->driver->playback.channels_min)
- playback = 1;
- if (codec_dai->driver->capture.channels_min)
- capture = 1;
-
- dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num,new_name);
- ret = snd_pcm_new(rtd->card->snd_card, new_name,
- num, playback, capture, &pcm);
+ if (rtd->dai_link->dynamic || rtd->dai_link->no_pcm) {
+ if (cpu_dai->driver->playback.channels_min)
+ playback = 1;
+ if (cpu_dai->driver->capture.channels_min)
+ capture = 1;
+ } else {
+ if (codec_dai->driver->playback.channels_min)
+ playback = 1;
+ if (codec_dai->driver->capture.channels_min)
+ capture = 1;
+ }
+
+ /* create the PCM */
+ if (rtd->dai_link->no_pcm) {
+ snprintf(new_name, sizeof(new_name), "(%s)",
+ rtd->dai_link->stream_name);
+
+ ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
+ playback, capture, &pcm);
+ } else {
+ if (rtd->dai_link->dynamic)
+ snprintf(new_name, sizeof(new_name), "%s (*)",
+ rtd->dai_link->stream_name);
+ else
+ snprintf(new_name, sizeof(new_name), "%s %s-%d",
+ rtd->dai_link->stream_name, codec_dai->name, num);
+
+ ret = snd_pcm_new(rtd->card->snd_card, new_name, num, playback,
+ capture, &pcm);
+ }
if (ret < 0) {
printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name);
return ret;
}
+ dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num, new_name);
/* DAPM dai link stream work */
INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
rtd->pcm = pcm;
pcm->private_data = rtd;
+
+ if (rtd->dai_link->no_pcm) {
+ if (playback)
+ pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
+ if (capture)
+ pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
+ goto out;
+ }
+
+ /* ASoC PCM operations */
+ if (rtd->dai_link->dynamic) {
+ rtd->ops.open = dpcm_fe_dai_open;
+ rtd->ops.hw_params = dpcm_fe_dai_hw_params;
+ rtd->ops.prepare = dpcm_fe_dai_prepare;
+ rtd->ops.trigger = dpcm_fe_dai_trigger;
+ rtd->ops.hw_free = dpcm_fe_dai_hw_free;
+ rtd->ops.close = dpcm_fe_dai_close;
+ rtd->ops.pointer = soc_pcm_pointer;
+ rtd->ops.ioctl = soc_pcm_ioctl;
+ } else {
+ rtd->ops.open = soc_pcm_open;
+ rtd->ops.hw_params = soc_pcm_hw_params;
+ rtd->ops.prepare = soc_pcm_prepare;
+ rtd->ops.trigger = soc_pcm_trigger;
+ rtd->ops.hw_free = soc_pcm_hw_free;
+ rtd->ops.close = soc_pcm_close;
+ rtd->ops.pointer = soc_pcm_pointer;
+ rtd->ops.ioctl = soc_pcm_ioctl;
+ }
+
if (platform->driver->ops) {
- soc_pcm_ops->mmap = platform->driver->ops->mmap;
- soc_pcm_ops->pointer = platform->driver->ops->pointer;
- soc_pcm_ops->ioctl = platform->driver->ops->ioctl;
- soc_pcm_ops->copy = platform->driver->ops->copy;
- soc_pcm_ops->silence = platform->driver->ops->silence;
- soc_pcm_ops->ack = platform->driver->ops->ack;
- soc_pcm_ops->page = platform->driver->ops->page;
+ rtd->ops.ack = platform->driver->ops->ack;
+ rtd->ops.copy = platform->driver->ops->copy;
+ rtd->ops.silence = platform->driver->ops->silence;
+ rtd->ops.page = platform->driver->ops->page;
+ rtd->ops.mmap = platform->driver->ops->mmap;
}
if (playback)
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, soc_pcm_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops);
if (capture)
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, soc_pcm_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops);
if (platform->driver->pcm_new) {
ret = platform->driver->pcm_new(rtd);
@@ -701,7 +2099,257 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
}
pcm->private_free = platform->driver->pcm_free;
+out:
printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name,
cpu_dai->name);
return ret;
}
+
+/* is the current PCM operation for this FE ? */
+int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream)
+{
+ if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE)
+ return 1;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dpcm_fe_can_update);
+
+/* is the current PCM operation for this BE ? */
+int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
+ struct snd_soc_pcm_runtime *be, int stream)
+{
+ if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) ||
+ ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_BE) &&
+ be->dpcm[stream].runtime_update))
+ return 1;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_can_update);
+
+/* get the substream for this BE */
+struct snd_pcm_substream *
+ snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream)
+{
+ return be->pcm->streams[stream].substream;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dpcm_get_substream);
+
+/* get the BE runtime state */
+enum snd_soc_dpcm_state
+ snd_soc_dpcm_be_get_state(struct snd_soc_pcm_runtime *be, int stream)
+{
+ return be->dpcm[stream].state;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_get_state);
+
+/* set the BE runtime state */
+void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be,
+ int stream, enum snd_soc_dpcm_state state)
+{
+ be->dpcm[stream].state = state;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dpcm_be_set_state);
+
+/*
+ * We can only hw_free, stop, pause or suspend a BE DAI if any of it's FE
+ * are not running, paused or suspended for the specified stream direction.
+ */
+int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
+ struct snd_soc_pcm_runtime *be, int stream)
+{
+ struct snd_soc_dpcm *dpcm;
+ int state;
+
+ list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {
+
+ if (dpcm->fe == fe)
+ continue;
+
+ state = dpcm->fe->dpcm[stream].state;
+ if (state == SND_SOC_DPCM_STATE_START ||
+ state == SND_SOC_DPCM_STATE_PAUSED ||
+ state == SND_SOC_DPCM_STATE_SUSPEND)
+ return 0;
+ }
+
+ /* it's safe to free/stop this BE DAI */
+ return 1;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_free_stop);
+
+/*
+ * We can only change hw params a BE DAI if any of it's FE are not prepared,
+ * running, paused or suspended for the specified stream direction.
+ */
+int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
+ struct snd_soc_pcm_runtime *be, int stream)
+{
+ struct snd_soc_dpcm *dpcm;
+ int state;
+
+ list_for_each_entry(dpcm, &be->dpcm[stream].fe_clients, list_fe) {
+
+ if (dpcm->fe == fe)
+ continue;
+
+ state = dpcm->fe->dpcm[stream].state;
+ if (state == SND_SOC_DPCM_STATE_START ||
+ state == SND_SOC_DPCM_STATE_PAUSED ||
+ state == SND_SOC_DPCM_STATE_SUSPEND ||
+ state == SND_SOC_DPCM_STATE_PREPARE)
+ return 0;
+ }
+
+ /* it's safe to change hw_params */
+ return 1;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dpcm_can_be_params);
+
+int snd_soc_platform_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_platform *platform)
+{
+ if (platform->driver->ops->trigger)
+ return platform->driver->ops->trigger(substream, cmd);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_platform_trigger);
+
+#ifdef CONFIG_DEBUG_FS
+static char *dpcm_state_string(enum snd_soc_dpcm_state state)
+{
+ switch (state) {
+ case SND_SOC_DPCM_STATE_NEW:
+ return "new";
+ case SND_SOC_DPCM_STATE_OPEN:
+ return "open";
+ case SND_SOC_DPCM_STATE_HW_PARAMS:
+ return "hw_params";
+ case SND_SOC_DPCM_STATE_PREPARE:
+ return "prepare";
+ case SND_SOC_DPCM_STATE_START:
+ return "start";
+ case SND_SOC_DPCM_STATE_STOP:
+ return "stop";
+ case SND_SOC_DPCM_STATE_SUSPEND:
+ return "suspend";
+ case SND_SOC_DPCM_STATE_PAUSED:
+ return "paused";
+ case SND_SOC_DPCM_STATE_HW_FREE:
+ return "hw_free";
+ case SND_SOC_DPCM_STATE_CLOSE:
+ return "close";
+ }
+
+ return "unknown";
+}
+
+static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe,
+ int stream, char *buf, size_t size)
+{
+ struct snd_pcm_hw_params *params = &fe->dpcm[stream].hw_params;
+ struct snd_soc_dpcm *dpcm;
+ ssize_t offset = 0;
+
+ /* FE state */
+ offset += snprintf(buf + offset, size - offset,
+ "[%s - %s]\n", fe->dai_link->name,
+ stream ? "Capture" : "Playback");
+
+ offset += snprintf(buf + offset, size - offset, "State: %s\n",
+ dpcm_state_string(fe->dpcm[stream].state));
+
+ if ((fe->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
+ (fe->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
+ offset += snprintf(buf + offset, size - offset,
+ "Hardware Params: "
+ "Format = %s, Channels = %d, Rate = %d\n",
+ snd_pcm_format_name(params_format(params)),
+ params_channels(params),
+ params_rate(params));
+
+ /* BEs state */
+ offset += snprintf(buf + offset, size - offset, "Backends:\n");
+
+ if (list_empty(&fe->dpcm[stream].be_clients)) {
+ offset += snprintf(buf + offset, size - offset,
+ " No active DSP links\n");
+ goto out;
+ }
+
+ list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) {
+ struct snd_soc_pcm_runtime *be = dpcm->be;
+ params = &dpcm->hw_params;
+
+ offset += snprintf(buf + offset, size - offset,
+ "- %s\n", be->dai_link->name);
+
+ offset += snprintf(buf + offset, size - offset,
+ " State: %s\n",
+ dpcm_state_string(be->dpcm[stream].state));
+
+ if ((be->dpcm[stream].state >= SND_SOC_DPCM_STATE_HW_PARAMS) &&
+ (be->dpcm[stream].state <= SND_SOC_DPCM_STATE_STOP))
+ offset += snprintf(buf + offset, size - offset,
+ " Hardware Params: "
+ "Format = %s, Channels = %d, Rate = %d\n",
+ snd_pcm_format_name(params_format(params)),
+ params_channels(params),
+ params_rate(params));
+ }
+
+out:
+ return offset;
+}
+
+static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct snd_soc_pcm_runtime *fe = file->private_data;
+ ssize_t out_count = PAGE_SIZE, offset = 0, ret = 0;
+ char *buf;
+
+ buf = kmalloc(out_count, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (fe->cpu_dai->driver->playback.channels_min)
+ offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_PLAYBACK,
+ buf + offset, out_count - offset);
+
+ if (fe->cpu_dai->driver->capture.channels_min)
+ offset += dpcm_show_state(fe, SNDRV_PCM_STREAM_CAPTURE,
+ buf + offset, out_count - offset);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
+
+ kfree(buf);
+ return ret;
+}
+
+static const struct file_operations dpcm_state_fops = {
+ .open = simple_open,
+ .read = dpcm_state_read_file,
+ .llseek = default_llseek,
+};
+
+int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
+{
+ if (!rtd->dai_link)
+ return 0;
+
+ rtd->debugfs_dpcm_root = debugfs_create_dir(rtd->dai_link->name,
+ rtd->card->debugfs_card_root);
+ if (!rtd->debugfs_dpcm_root) {
+ dev_dbg(rtd->dev,
+ "ASoC: Failed to create dpcm debugfs directory %s\n",
+ rtd->dai_link->name);
+ return -EINVAL;
+ }
+
+ rtd->debugfs_dpcm_state = debugfs_create_file("state", 0444,
+ rtd->debugfs_dpcm_root,
+ rtd, &dpcm_state_fops);
+
+ return 0;
+}
+#endif
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index ce1b773c351f..c1c8e955f4d3 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -1,26 +1,63 @@
config SND_SOC_TEGRA
tristate "SoC Audio for the Tegra System-on-Chip"
depends on ARCH_TEGRA && TEGRA_SYSTEM_DMA
+ select REGMAP_MMIO
help
Say Y or M here if you want support for SoC audio on Tegra.
-config SND_SOC_TEGRA_I2S
+config SND_SOC_TEGRA20_DAS
tristate
- depends on SND_SOC_TEGRA
+ depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC
+ help
+ Say Y or M if you want to add support for the Tegra20 DAS module.
+ You will also need to select the individual machine drivers to
+ support below.
+
+config SND_SOC_TEGRA20_I2S
+ tristate
+ depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC
+ select SND_SOC_TEGRA20_DAS
help
Say Y or M if you want to add support for codecs attached to the
- Tegra I2S interface. You will also need to select the individual
+ Tegra20 I2S interface. You will also need to select the individual
machine drivers to support below.
-config SND_SOC_TEGRA_SPDIF
+config SND_SOC_TEGRA20_SPDIF
tristate
- depends on SND_SOC_TEGRA
+ depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC
default m
help
- Say Y or M if you want to add support for the SPDIF interface.
+ Say Y or M if you want to add support for the Tegra20 SPDIF interface.
You will also need to select the individual machine drivers to support
below.
+config SND_SOC_TEGRA30_AHUB
+ tristate
+ depends on SND_SOC_TEGRA && ARCH_TEGRA_3x_SOC
+ help
+ Say Y or M if you want to add support for the Tegra20 AHUB module.
+ You will also need to select the individual machine drivers to
+ support below.
+
+config SND_SOC_TEGRA30_I2S
+ tristate
+ depends on SND_SOC_TEGRA && ARCH_TEGRA_3x_SOC
+ select SND_SOC_TEGRA30_AHUB
+ help
+ Say Y or M if you want to add support for codecs attached to the
+ Tegra30 I2S interface. You will also need to select the individual
+ machine drivers to support below.
+
+config SND_SOC_TEGRA_WM8753
+ tristate "SoC Audio support for Tegra boards using a WM8753 codec"
+ depends on SND_SOC_TEGRA && I2C
+ select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
+ select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
+ select SND_SOC_WM8753
+ help
+ Say Y or M here if you want to add support for SoC audio on Tegra
+ boards using the WM8753 codec, such as Whistler.
+
config MACH_HAS_SND_SOC_TEGRA_WM8903
bool
help
@@ -32,7 +69,8 @@ config SND_SOC_TEGRA_WM8903
tristate "SoC Audio support for Tegra boards using a WM8903 codec"
depends on SND_SOC_TEGRA && I2C
depends on MACH_HAS_SND_SOC_TEGRA_WM8903
- select SND_SOC_TEGRA_I2S
+ select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
+ select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
select SND_SOC_WM8903
help
Say Y or M here if you want to add support for SoC audio on Tegra
@@ -42,17 +80,17 @@ config SND_SOC_TEGRA_WM8903
config SND_SOC_TEGRA_TRIMSLICE
tristate "SoC Audio support for TrimSlice board"
depends on SND_SOC_TEGRA && MACH_TRIMSLICE && I2C
- select SND_SOC_TEGRA_I2S
+ select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
select SND_SOC_TLV320AIC23
help
Say Y or M here if you want to add support for SoC audio on the
TrimSlice platform.
config SND_SOC_TEGRA_ALC5632
- tristate "SoC Audio support for Tegra boards using an ALC5632 codec"
- depends on SND_SOC_TEGRA && I2C
- select SND_SOC_TEGRA_I2S
- select SND_SOC_ALC5632
- help
- Say Y or M here if you want to add support for SoC audio on the
- Toshiba AC100 netbook.
+ tristate "SoC Audio support for Tegra boards using an ALC5632 codec"
+ depends on SND_SOC_TEGRA && I2C
+ select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
+ select SND_SOC_ALC5632
+ help
+ Say Y or M here if you want to add support for SoC audio on the
+ Toshiba AC100 netbook.
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile
index 8e584b8fcfba..391e78a34c06 100644
--- a/sound/soc/tegra/Makefile
+++ b/sound/soc/tegra/Makefile
@@ -1,21 +1,27 @@
# Tegra platform Support
-snd-soc-tegra-das-objs := tegra_das.o
snd-soc-tegra-pcm-objs := tegra_pcm.o
-snd-soc-tegra-i2s-objs := tegra_i2s.o
-snd-soc-tegra-spdif-objs := tegra_spdif.o
snd-soc-tegra-utils-objs += tegra_asoc_utils.o
+snd-soc-tegra20-das-objs := tegra20_das.o
+snd-soc-tegra20-i2s-objs := tegra20_i2s.o
+snd-soc-tegra20-spdif-objs := tegra20_spdif.o
+snd-soc-tegra30-ahub-objs := tegra30_ahub.o
+snd-soc-tegra30-i2s-objs := tegra30_i2s.o
-obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
-obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-das.o
obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o
-obj-$(CONFIG_SND_SOC_TEGRA_I2S) += snd-soc-tegra-i2s.o
-obj-$(CONFIG_SND_SOC_TEGRA_SPDIF) += snd-soc-tegra-spdif.o
+obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o
+obj-$(CONFIG_SND_SOC_TEGRA20_DAS) += snd-soc-tegra20-das.o
+obj-$(CONFIG_SND_SOC_TEGRA20_I2S) += snd-soc-tegra20-i2s.o
+obj-$(CONFIG_SND_SOC_TEGRA20_SPDIF) += snd-soc-tegra20-spdif.o
+obj-$(CONFIG_SND_SOC_TEGRA30_AHUB) += snd-soc-tegra30-ahub.o
+obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o
# Tegra machine Support
+snd-soc-tegra-wm8753-objs := tegra_wm8753.o
snd-soc-tegra-wm8903-objs := tegra_wm8903.o
snd-soc-tegra-trimslice-objs := trimslice.o
snd-soc-tegra-alc5632-objs := tegra_alc5632.o
+obj-$(CONFIG_SND_SOC_TEGRA_WM8753) += snd-soc-tegra-wm8753.o
obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o
obj-$(CONFIG_SND_SOC_TEGRA_TRIMSLICE) += snd-soc-tegra-trimslice.o
obj-$(CONFIG_SND_SOC_TEGRA_ALC5632) += snd-soc-tegra-alc5632.o
diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c
new file mode 100644
index 000000000000..bf99296bce95
--- /dev/null
+++ b/sound/soc/tegra/tegra20_das.c
@@ -0,0 +1,233 @@
+/*
+ * tegra20_das.c - Tegra20 DAS driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010 - NVIDIA, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include "tegra20_das.h"
+
+#define DRV_NAME "tegra20-das"
+
+static struct tegra20_das *das;
+
+static inline void tegra20_das_write(u32 reg, u32 val)
+{
+ regmap_write(das->regmap, reg, val);
+}
+
+static inline u32 tegra20_das_read(u32 reg)
+{
+ u32 val;
+ regmap_read(das->regmap, reg, &val);
+ return val;
+}
+
+int tegra20_das_connect_dap_to_dac(int dap, int dac)
+{
+ u32 addr;
+ u32 reg;
+
+ if (!das)
+ return -ENODEV;
+
+ addr = TEGRA20_DAS_DAP_CTRL_SEL +
+ (dap * TEGRA20_DAS_DAP_CTRL_SEL_STRIDE);
+ reg = dac << TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P;
+
+ tegra20_das_write(addr, reg);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tegra20_das_connect_dap_to_dac);
+
+int tegra20_das_connect_dap_to_dap(int dap, int otherdap, int master,
+ int sdata1rx, int sdata2rx)
+{
+ u32 addr;
+ u32 reg;
+
+ if (!das)
+ return -ENODEV;
+
+ addr = TEGRA20_DAS_DAP_CTRL_SEL +
+ (dap * TEGRA20_DAS_DAP_CTRL_SEL_STRIDE);
+ reg = otherdap << TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P |
+ !!sdata2rx << TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P |
+ !!sdata1rx << TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P |
+ !!master << TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P;
+
+ tegra20_das_write(addr, reg);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tegra20_das_connect_dap_to_dap);
+
+int tegra20_das_connect_dac_to_dap(int dac, int dap)
+{
+ u32 addr;
+ u32 reg;
+
+ if (!das)
+ return -ENODEV;
+
+ addr = TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL +
+ (dac * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE);
+ reg = dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P |
+ dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P |
+ dap << TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P;
+
+ tegra20_das_write(addr, reg);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tegra20_das_connect_dac_to_dap);
+
+#define LAST_REG(name) \
+ (TEGRA20_DAS_##name + \
+ (TEGRA20_DAS_##name##_STRIDE * (TEGRA20_DAS_##name##_COUNT - 1)))
+
+static bool tegra20_das_wr_rd_reg(struct device *dev, unsigned int reg)
+{
+ if ((reg >= TEGRA20_DAS_DAP_CTRL_SEL) &&
+ (reg <= LAST_REG(DAP_CTRL_SEL)))
+ return true;
+ if ((reg >= TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL) &&
+ (reg <= LAST_REG(DAC_INPUT_DATA_CLK_SEL)))
+ return true;
+
+ return false;
+}
+
+static const struct regmap_config tegra20_das_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = LAST_REG(DAC_INPUT_DATA_CLK_SEL),
+ .writeable_reg = tegra20_das_wr_rd_reg,
+ .readable_reg = tegra20_das_wr_rd_reg,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit tegra20_das_probe(struct platform_device *pdev)
+{
+ struct resource *res, *region;
+ void __iomem *regs;
+ int ret = 0;
+
+ if (das)
+ return -ENODEV;
+
+ das = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_das), GFP_KERNEL);
+ if (!das) {
+ dev_err(&pdev->dev, "Can't allocate tegra20_das\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ das->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "No memory resource\n");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ region = devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), pdev->name);
+ if (!region) {
+ dev_err(&pdev->dev, "Memory region already claimed\n");
+ ret = -EBUSY;
+ goto err;
+ }
+
+ regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!regs) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ das->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+ &tegra20_das_regmap_config);
+ if (IS_ERR(das->regmap)) {
+ dev_err(&pdev->dev, "regmap init failed\n");
+ ret = PTR_ERR(das->regmap);
+ goto err;
+ }
+
+ ret = tegra20_das_connect_dap_to_dac(TEGRA20_DAS_DAP_ID_1,
+ TEGRA20_DAS_DAP_SEL_DAC1);
+ if (ret) {
+ dev_err(&pdev->dev, "Can't set up DAS DAP connection\n");
+ goto err;
+ }
+ ret = tegra20_das_connect_dac_to_dap(TEGRA20_DAS_DAC_ID_1,
+ TEGRA20_DAS_DAC_SEL_DAP1);
+ if (ret) {
+ dev_err(&pdev->dev, "Can't set up DAS DAC connection\n");
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, das);
+
+ return 0;
+
+err:
+ das = NULL;
+ return ret;
+}
+
+static int __devexit tegra20_das_remove(struct platform_device *pdev)
+{
+ if (!das)
+ return -ENODEV;
+
+ das = NULL;
+
+ return 0;
+}
+
+static const struct of_device_id tegra20_das_of_match[] __devinitconst = {
+ { .compatible = "nvidia,tegra20-das", },
+ {},
+};
+
+static struct platform_driver tegra20_das_driver = {
+ .probe = tegra20_das_probe,
+ .remove = __devexit_p(tegra20_das_remove),
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = tegra20_das_of_match,
+ },
+};
+module_platform_driver(tegra20_das_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra20 DAS driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra20_das_of_match);
diff --git a/sound/soc/tegra/tegra20_das.h b/sound/soc/tegra/tegra20_das.h
new file mode 100644
index 000000000000..be217f3d3a75
--- /dev/null
+++ b/sound/soc/tegra/tegra20_das.h
@@ -0,0 +1,134 @@
+/*
+ * tegra20_das.h - Definitions for Tegra20 DAS driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __TEGRA20_DAS_H__
+#define __TEGRA20_DAS_H__
+
+/* Register TEGRA20_DAS_DAP_CTRL_SEL */
+#define TEGRA20_DAS_DAP_CTRL_SEL 0x00
+#define TEGRA20_DAS_DAP_CTRL_SEL_COUNT 5
+#define TEGRA20_DAS_DAP_CTRL_SEL_STRIDE 4
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P 31
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_MS_SEL_S 1
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P 30
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_S 1
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P 29
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_S 1
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P 0
+#define TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_S 5
+
+/* Values for field TEGRA20_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL */
+#define TEGRA20_DAS_DAP_SEL_DAC1 0
+#define TEGRA20_DAS_DAP_SEL_DAC2 1
+#define TEGRA20_DAS_DAP_SEL_DAC3 2
+#define TEGRA20_DAS_DAP_SEL_DAP1 16
+#define TEGRA20_DAS_DAP_SEL_DAP2 17
+#define TEGRA20_DAS_DAP_SEL_DAP3 18
+#define TEGRA20_DAS_DAP_SEL_DAP4 19
+#define TEGRA20_DAS_DAP_SEL_DAP5 20
+
+/* Register TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL */
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL 0x40
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT 3
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE 4
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P 28
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_S 4
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P 24
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_S 4
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P 0
+#define TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_S 4
+
+/*
+ * Values for:
+ * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL
+ * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL
+ * TEGRA20_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL
+ */
+#define TEGRA20_DAS_DAC_SEL_DAP1 0
+#define TEGRA20_DAS_DAC_SEL_DAP2 1
+#define TEGRA20_DAS_DAC_SEL_DAP3 2
+#define TEGRA20_DAS_DAC_SEL_DAP4 3
+#define TEGRA20_DAS_DAC_SEL_DAP5 4
+
+/*
+ * Names/IDs of the DACs/DAPs.
+ */
+
+#define TEGRA20_DAS_DAP_ID_1 0
+#define TEGRA20_DAS_DAP_ID_2 1
+#define TEGRA20_DAS_DAP_ID_3 2
+#define TEGRA20_DAS_DAP_ID_4 3
+#define TEGRA20_DAS_DAP_ID_5 4
+
+#define TEGRA20_DAS_DAC_ID_1 0
+#define TEGRA20_DAS_DAC_ID_2 1
+#define TEGRA20_DAS_DAC_ID_3 2
+
+struct tegra20_das {
+ struct device *dev;
+ struct regmap *regmap;
+};
+
+/*
+ * Terminology:
+ * DAS: Digital audio switch (HW module controlled by this driver)
+ * DAP: Digital audio port (port/pins on Tegra device)
+ * DAC: Digital audio controller (e.g. I2S or AC97 controller elsewhere)
+ *
+ * The Tegra DAS is a mux/cross-bar which can connect each DAP to a specific
+ * DAC, or another DAP. When DAPs are connected, one must be the master and
+ * one the slave. Each DAC allows selection of a specific DAP for input, to
+ * cater for the case where N DAPs are connected to 1 DAC for broadcast
+ * output.
+ *
+ * This driver is dumb; no attempt is made to ensure that a valid routing
+ * configuration is programmed.
+ */
+
+/*
+ * Connect a DAP to to a DAC
+ * dap_id: DAP to connect: TEGRA20_DAS_DAP_ID_*
+ * dac_sel: DAC to connect to: TEGRA20_DAS_DAP_SEL_DAC*
+ */
+extern int tegra20_das_connect_dap_to_dac(int dap_id, int dac_sel);
+
+/*
+ * Connect a DAP to to another DAP
+ * dap_id: DAP to connect: TEGRA20_DAS_DAP_ID_*
+ * other_dap_sel: DAP to connect to: TEGRA20_DAS_DAP_SEL_DAP*
+ * master: Is this DAP the master (1) or slave (0)
+ * sdata1rx: Is this DAP's SDATA1 pin RX (1) or TX (0)
+ * sdata2rx: Is this DAP's SDATA2 pin RX (1) or TX (0)
+ */
+extern int tegra20_das_connect_dap_to_dap(int dap_id, int other_dap_sel,
+ int master, int sdata1rx,
+ int sdata2rx);
+
+/*
+ * Connect a DAC's input to a DAP
+ * (DAC outputs are selected by the DAP)
+ * dac_id: DAC ID to connect: TEGRA20_DAS_DAC_ID_*
+ * dap_sel: DAP to receive input from: TEGRA20_DAS_DAC_SEL_DAP*
+ */
+extern int tegra20_das_connect_dac_to_dap(int dac_id, int dap_sel);
+
+#endif
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
new file mode 100644
index 000000000000..0c7af63d444b
--- /dev/null
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -0,0 +1,494 @@
+/*
+ * tegra20_i2s.c - Tegra20 I2S driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ *
+ * Copyright (c) 2009-2010, NVIDIA Corporation.
+ * Scott Peterson <speterson@nvidia.com>
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Iliyan Malchev <malchev@google.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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra20_i2s.h"
+
+#define DRV_NAME "tegra20-i2s"
+
+static inline void tegra20_i2s_write(struct tegra20_i2s *i2s, u32 reg, u32 val)
+{
+ regmap_write(i2s->regmap, reg, val);
+}
+
+static inline u32 tegra20_i2s_read(struct tegra20_i2s *i2s, u32 reg)
+{
+ u32 val;
+ regmap_read(i2s->regmap, reg, &val);
+ return val;
+}
+
+static int tegra20_i2s_runtime_suspend(struct device *dev)
+{
+ struct tegra20_i2s *i2s = dev_get_drvdata(dev);
+
+ clk_disable(i2s->clk_i2s);
+
+ return 0;
+}
+
+static int tegra20_i2s_runtime_resume(struct device *dev)
+{
+ struct tegra20_i2s *i2s = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_enable(i2s->clk_i2s);
+ if (ret) {
+ dev_err(dev, "clk_enable failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai,
+ unsigned int fmt)
+{
+ struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_MASTER_ENABLE;
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ i2s->reg_ctrl |= TEGRA20_I2S_CTRL_MASTER_ENABLE;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ i2s->reg_ctrl &= ~(TEGRA20_I2S_CTRL_BIT_FORMAT_MASK |
+ TEGRA20_I2S_CTRL_LRCK_MASK);
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
+ i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP;
+ i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_R_LOW;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_I2S;
+ i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_RJM;
+ i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_LJM;
+ i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int tegra20_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct device *dev = substream->pcm->card->dev;
+ struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+ u32 reg;
+ int ret, sample_size, srate, i2sclock, bitcnt;
+
+ i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_BIT_SIZE_MASK;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_16;
+ sample_size = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_24;
+ sample_size = 24;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_32;
+ sample_size = 32;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ srate = params_rate(params);
+
+ /* Final "* 2" required by Tegra hardware */
+ i2sclock = srate * params_channels(params) * sample_size * 2;
+
+ ret = clk_set_rate(i2s->clk_i2s, i2sclock);
+ if (ret) {
+ dev_err(dev, "Can't set I2S clock rate: %d\n", ret);
+ return ret;
+ }
+
+ bitcnt = (i2sclock / (2 * srate)) - 1;
+ if (bitcnt < 0 || bitcnt > TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US)
+ return -EINVAL;
+ reg = bitcnt << TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
+
+ if (i2sclock % (2 * srate))
+ reg |= TEGRA20_I2S_TIMING_NON_SYM_ENABLE;
+
+ tegra20_i2s_write(i2s, TEGRA20_I2S_TIMING, reg);
+
+ tegra20_i2s_write(i2s, TEGRA20_I2S_FIFO_SCR,
+ TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS |
+ TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS);
+
+ return 0;
+}
+
+static void tegra20_i2s_start_playback(struct tegra20_i2s *i2s)
+{
+ i2s->reg_ctrl |= TEGRA20_I2S_CTRL_FIFO1_ENABLE;
+ tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra20_i2s_stop_playback(struct tegra20_i2s *i2s)
+{
+ i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_FIFO1_ENABLE;
+ tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra20_i2s_start_capture(struct tegra20_i2s *i2s)
+{
+ i2s->reg_ctrl |= TEGRA20_I2S_CTRL_FIFO2_ENABLE;
+ tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra20_i2s_stop_capture(struct tegra20_i2s *i2s)
+{
+ i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_FIFO2_ENABLE;
+ tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static int tegra20_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ tegra20_i2s_start_playback(i2s);
+ else
+ tegra20_i2s_start_capture(i2s);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ tegra20_i2s_stop_playback(i2s);
+ else
+ tegra20_i2s_stop_capture(i2s);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int tegra20_i2s_probe(struct snd_soc_dai *dai)
+{
+ struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+ dai->capture_dma_data = &i2s->capture_dma_data;
+ dai->playback_dma_data = &i2s->playback_dma_data;
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = {
+ .set_fmt = tegra20_i2s_set_fmt,
+ .hw_params = tegra20_i2s_hw_params,
+ .trigger = tegra20_i2s_trigger,
+};
+
+static const struct snd_soc_dai_driver tegra20_i2s_dai_template = {
+ .probe = tegra20_i2s_probe,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &tegra20_i2s_dai_ops,
+ .symmetric_rates = 1,
+};
+
+static bool tegra20_i2s_wr_rd_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TEGRA20_I2S_CTRL:
+ case TEGRA20_I2S_STATUS:
+ case TEGRA20_I2S_TIMING:
+ case TEGRA20_I2S_FIFO_SCR:
+ case TEGRA20_I2S_PCM_CTRL:
+ case TEGRA20_I2S_NW_CTRL:
+ case TEGRA20_I2S_TDM_CTRL:
+ case TEGRA20_I2S_TDM_TX_RX_CTRL:
+ case TEGRA20_I2S_FIFO1:
+ case TEGRA20_I2S_FIFO2:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static bool tegra20_i2s_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TEGRA20_I2S_STATUS:
+ case TEGRA20_I2S_FIFO_SCR:
+ case TEGRA20_I2S_FIFO1:
+ case TEGRA20_I2S_FIFO2:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static bool tegra20_i2s_precious_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TEGRA20_I2S_FIFO1:
+ case TEGRA20_I2S_FIFO2:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static const struct regmap_config tegra20_i2s_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = TEGRA20_I2S_FIFO2,
+ .writeable_reg = tegra20_i2s_wr_rd_reg,
+ .readable_reg = tegra20_i2s_wr_rd_reg,
+ .volatile_reg = tegra20_i2s_volatile_reg,
+ .precious_reg = tegra20_i2s_precious_reg,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static __devinit int tegra20_i2s_platform_probe(struct platform_device *pdev)
+{
+ struct tegra20_i2s *i2s;
+ struct resource *mem, *memregion, *dmareq;
+ u32 of_dma[2];
+ u32 dma_ch;
+ void __iomem *regs;
+ int ret;
+
+ i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_i2s), GFP_KERNEL);
+ if (!i2s) {
+ dev_err(&pdev->dev, "Can't allocate tegra20_i2s\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ dev_set_drvdata(&pdev->dev, i2s);
+
+ i2s->dai = tegra20_i2s_dai_template;
+ i2s->dai.name = dev_name(&pdev->dev);
+
+ i2s->clk_i2s = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(i2s->clk_i2s)) {
+ dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
+ ret = PTR_ERR(i2s->clk_i2s);
+ goto err;
+ }
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "No memory resource\n");
+ ret = -ENODEV;
+ goto err_clk_put;
+ }
+
+ dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!dmareq) {
+ if (of_property_read_u32_array(pdev->dev.of_node,
+ "nvidia,dma-request-selector",
+ of_dma, 2) < 0) {
+ dev_err(&pdev->dev, "No DMA resource\n");
+ ret = -ENODEV;
+ goto err_clk_put;
+ }
+ dma_ch = of_dma[1];
+ } else {
+ dma_ch = dmareq->start;
+ }
+
+ memregion = devm_request_mem_region(&pdev->dev, mem->start,
+ resource_size(mem), DRV_NAME);
+ if (!memregion) {
+ dev_err(&pdev->dev, "Memory region already claimed\n");
+ ret = -EBUSY;
+ goto err_clk_put;
+ }
+
+ regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
+ if (!regs) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto err_clk_put;
+ }
+
+ i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+ &tegra20_i2s_regmap_config);
+ if (IS_ERR(i2s->regmap)) {
+ dev_err(&pdev->dev, "regmap init failed\n");
+ ret = PTR_ERR(i2s->regmap);
+ goto err_clk_put;
+ }
+
+ i2s->capture_dma_data.addr = mem->start + TEGRA20_I2S_FIFO2;
+ i2s->capture_dma_data.wrap = 4;
+ i2s->capture_dma_data.width = 32;
+ i2s->capture_dma_data.req_sel = dma_ch;
+
+ i2s->playback_dma_data.addr = mem->start + TEGRA20_I2S_FIFO1;
+ i2s->playback_dma_data.wrap = 4;
+ i2s->playback_dma_data.width = 32;
+ i2s->playback_dma_data.req_sel = dma_ch;
+
+ i2s->reg_ctrl = TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED;
+
+ pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ ret = tegra20_i2s_runtime_resume(&pdev->dev);
+ if (ret)
+ goto err_pm_disable;
+ }
+
+ ret = snd_soc_register_dai(&pdev->dev, &i2s->dai);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
+ ret = -ENOMEM;
+ goto err_suspend;
+ }
+
+ ret = tegra_pcm_platform_register(&pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
+ goto err_unregister_dai;
+ }
+
+ return 0;
+
+err_unregister_dai:
+ snd_soc_unregister_dai(&pdev->dev);
+err_suspend:
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ tegra20_i2s_runtime_suspend(&pdev->dev);
+err_pm_disable:
+ pm_runtime_disable(&pdev->dev);
+err_clk_put:
+ clk_put(i2s->clk_i2s);
+err:
+ return ret;
+}
+
+static int __devexit tegra20_i2s_platform_remove(struct platform_device *pdev)
+{
+ struct tegra20_i2s *i2s = dev_get_drvdata(&pdev->dev);
+
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ tegra20_i2s_runtime_suspend(&pdev->dev);
+
+ tegra_pcm_platform_unregister(&pdev->dev);
+ snd_soc_unregister_dai(&pdev->dev);
+
+ clk_put(i2s->clk_i2s);
+
+ return 0;
+}
+
+static const struct of_device_id tegra20_i2s_of_match[] __devinitconst = {
+ { .compatible = "nvidia,tegra20-i2s", },
+ {},
+};
+
+static const struct dev_pm_ops tegra20_i2s_pm_ops __devinitconst = {
+ SET_RUNTIME_PM_OPS(tegra20_i2s_runtime_suspend,
+ tegra20_i2s_runtime_resume, NULL)
+};
+
+static struct platform_driver tegra20_i2s_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = tegra20_i2s_of_match,
+ .pm = &tegra20_i2s_pm_ops,
+ },
+ .probe = tegra20_i2s_platform_probe,
+ .remove = __devexit_p(tegra20_i2s_platform_remove),
+};
+module_platform_driver(tegra20_i2s_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra20 I2S ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra20_i2s_of_match);
diff --git a/sound/soc/tegra/tegra20_i2s.h b/sound/soc/tegra/tegra20_i2s.h
new file mode 100644
index 000000000000..a57efc6a597e
--- /dev/null
+++ b/sound/soc/tegra/tegra20_i2s.h
@@ -0,0 +1,164 @@
+/*
+ * tegra20_i2s.h - Definitions for Tegra20 I2S driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ *
+ * Copyright (c) 2009-2010, NVIDIA Corporation.
+ * Scott Peterson <speterson@nvidia.com>
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Iliyan Malchev <malchev@google.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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __TEGRA20_I2S_H__
+#define __TEGRA20_I2S_H__
+
+#include "tegra_pcm.h"
+
+/* Register offsets from TEGRA20_I2S1_BASE and TEGRA20_I2S2_BASE */
+
+#define TEGRA20_I2S_CTRL 0x00
+#define TEGRA20_I2S_STATUS 0x04
+#define TEGRA20_I2S_TIMING 0x08
+#define TEGRA20_I2S_FIFO_SCR 0x0c
+#define TEGRA20_I2S_PCM_CTRL 0x10
+#define TEGRA20_I2S_NW_CTRL 0x14
+#define TEGRA20_I2S_TDM_CTRL 0x20
+#define TEGRA20_I2S_TDM_TX_RX_CTRL 0x24
+#define TEGRA20_I2S_FIFO1 0x40
+#define TEGRA20_I2S_FIFO2 0x80
+
+/* Fields in TEGRA20_I2S_CTRL */
+
+#define TEGRA20_I2S_CTRL_FIFO2_TX_ENABLE (1 << 30)
+#define TEGRA20_I2S_CTRL_FIFO1_ENABLE (1 << 29)
+#define TEGRA20_I2S_CTRL_FIFO2_ENABLE (1 << 28)
+#define TEGRA20_I2S_CTRL_FIFO1_RX_ENABLE (1 << 27)
+#define TEGRA20_I2S_CTRL_FIFO_LPBK_ENABLE (1 << 26)
+#define TEGRA20_I2S_CTRL_MASTER_ENABLE (1 << 25)
+
+#define TEGRA20_I2S_LRCK_LEFT_LOW 0
+#define TEGRA20_I2S_LRCK_RIGHT_LOW 1
+
+#define TEGRA20_I2S_CTRL_LRCK_SHIFT 24
+#define TEGRA20_I2S_CTRL_LRCK_MASK (1 << TEGRA20_I2S_CTRL_LRCK_SHIFT)
+#define TEGRA20_I2S_CTRL_LRCK_L_LOW (TEGRA20_I2S_LRCK_LEFT_LOW << TEGRA20_I2S_CTRL_LRCK_SHIFT)
+#define TEGRA20_I2S_CTRL_LRCK_R_LOW (TEGRA20_I2S_LRCK_RIGHT_LOW << TEGRA20_I2S_CTRL_LRCK_SHIFT)
+
+#define TEGRA20_I2S_BIT_FORMAT_I2S 0
+#define TEGRA20_I2S_BIT_FORMAT_RJM 1
+#define TEGRA20_I2S_BIT_FORMAT_LJM 2
+#define TEGRA20_I2S_BIT_FORMAT_DSP 3
+
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT 10
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_MASK (3 << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_I2S (TEGRA20_I2S_BIT_FORMAT_I2S << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_RJM (TEGRA20_I2S_BIT_FORMAT_RJM << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_LJM (TEGRA20_I2S_BIT_FORMAT_LJM << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_FORMAT_DSP (TEGRA20_I2S_BIT_FORMAT_DSP << TEGRA20_I2S_CTRL_BIT_FORMAT_SHIFT)
+
+#define TEGRA20_I2S_BIT_SIZE_16 0
+#define TEGRA20_I2S_BIT_SIZE_20 1
+#define TEGRA20_I2S_BIT_SIZE_24 2
+#define TEGRA20_I2S_BIT_SIZE_32 3
+
+#define TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT 8
+#define TEGRA20_I2S_CTRL_BIT_SIZE_MASK (3 << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_SIZE_16 (TEGRA20_I2S_BIT_SIZE_16 << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_SIZE_20 (TEGRA20_I2S_BIT_SIZE_20 << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_SIZE_24 (TEGRA20_I2S_BIT_SIZE_24 << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA20_I2S_CTRL_BIT_SIZE_32 (TEGRA20_I2S_BIT_SIZE_32 << TEGRA20_I2S_CTRL_BIT_SIZE_SHIFT)
+
+#define TEGRA20_I2S_FIFO_16_LSB 0
+#define TEGRA20_I2S_FIFO_20_LSB 1
+#define TEGRA20_I2S_FIFO_24_LSB 2
+#define TEGRA20_I2S_FIFO_32 3
+#define TEGRA20_I2S_FIFO_PACKED 7
+
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT 4
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_MASK (7 << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_16_LSB (TEGRA20_I2S_FIFO_16_LSB << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_20_LSB (TEGRA20_I2S_FIFO_20_LSB << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_24_LSB (TEGRA20_I2S_FIFO_24_LSB << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_32 (TEGRA20_I2S_FIFO_32 << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+#define TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED (TEGRA20_I2S_FIFO_PACKED << TEGRA20_I2S_CTRL_FIFO_FORMAT_SHIFT)
+
+#define TEGRA20_I2S_CTRL_IE_FIFO1_ERR (1 << 3)
+#define TEGRA20_I2S_CTRL_IE_FIFO2_ERR (1 << 2)
+#define TEGRA20_I2S_CTRL_QE_FIFO1 (1 << 1)
+#define TEGRA20_I2S_CTRL_QE_FIFO2 (1 << 0)
+
+/* Fields in TEGRA20_I2S_STATUS */
+
+#define TEGRA20_I2S_STATUS_FIFO1_RDY (1 << 31)
+#define TEGRA20_I2S_STATUS_FIFO2_RDY (1 << 30)
+#define TEGRA20_I2S_STATUS_FIFO1_BSY (1 << 29)
+#define TEGRA20_I2S_STATUS_FIFO2_BSY (1 << 28)
+#define TEGRA20_I2S_STATUS_FIFO1_ERR (1 << 3)
+#define TEGRA20_I2S_STATUS_FIFO2_ERR (1 << 2)
+#define TEGRA20_I2S_STATUS_QS_FIFO1 (1 << 1)
+#define TEGRA20_I2S_STATUS_QS_FIFO2 (1 << 0)
+
+/* Fields in TEGRA20_I2S_TIMING */
+
+#define TEGRA20_I2S_TIMING_NON_SYM_ENABLE (1 << 12)
+#define TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT 0
+#define TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US 0x7fff
+#define TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK (TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US << TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT)
+
+/* Fields in TEGRA20_I2S_FIFO_SCR */
+
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_FULL_EMPTY_COUNT_SHIFT 24
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_FULL_EMPTY_COUNT_SHIFT 16
+#define TEGRA20_I2S_FIFO_SCR_FIFO_FULL_EMPTY_COUNT_MASK 0x3f
+
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_CLR (1 << 12)
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_CLR (1 << 8)
+
+#define TEGRA20_I2S_FIFO_ATN_LVL_ONE_SLOT 0
+#define TEGRA20_I2S_FIFO_ATN_LVL_FOUR_SLOTS 1
+#define TEGRA20_I2S_FIFO_ATN_LVL_EIGHT_SLOTS 2
+#define TEGRA20_I2S_FIFO_ATN_LVL_TWELVE_SLOTS 3
+
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT 4
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_MASK (3 << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_ONE_SLOT (TEGRA20_I2S_FIFO_ATN_LVL_ONE_SLOT << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS (TEGRA20_I2S_FIFO_ATN_LVL_FOUR_SLOTS << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_EIGHT_SLOTS (TEGRA20_I2S_FIFO_ATN_LVL_EIGHT_SLOTS << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_TWELVE_SLOTS (TEGRA20_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
+
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT 0
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_MASK (3 << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_ONE_SLOT (TEGRA20_I2S_FIFO_ATN_LVL_ONE_SLOT << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS (TEGRA20_I2S_FIFO_ATN_LVL_FOUR_SLOTS << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_EIGHT_SLOTS (TEGRA20_I2S_FIFO_ATN_LVL_EIGHT_SLOTS << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+#define TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_TWELVE_SLOTS (TEGRA20_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
+
+struct tegra20_i2s {
+ struct snd_soc_dai_driver dai;
+ struct clk *clk_i2s;
+ struct tegra_pcm_dma_params capture_dma_data;
+ struct tegra_pcm_dma_params playback_dma_data;
+ struct regmap *regmap;
+ u32 reg_ctrl;
+};
+
+#endif
diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c
new file mode 100644
index 000000000000..f9b57418bd08
--- /dev/null
+++ b/sound/soc/tegra/tegra20_spdif.c
@@ -0,0 +1,404 @@
+/*
+ * tegra20_spdif.c - Tegra20 SPDIF driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2011-2012 - NVIDIA, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra20_spdif.h"
+
+#define DRV_NAME "tegra20-spdif"
+
+static inline void tegra20_spdif_write(struct tegra20_spdif *spdif, u32 reg,
+ u32 val)
+{
+ regmap_write(spdif->regmap, reg, val);
+}
+
+static inline u32 tegra20_spdif_read(struct tegra20_spdif *spdif, u32 reg)
+{
+ u32 val;
+ regmap_read(spdif->regmap, reg, &val);
+ return val;
+}
+
+static int tegra20_spdif_runtime_suspend(struct device *dev)
+{
+ struct tegra20_spdif *spdif = dev_get_drvdata(dev);
+
+ clk_disable(spdif->clk_spdif_out);
+
+ return 0;
+}
+
+static int tegra20_spdif_runtime_resume(struct device *dev)
+{
+ struct tegra20_spdif *spdif = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_enable(spdif->clk_spdif_out);
+ if (ret) {
+ dev_err(dev, "clk_enable failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct device *dev = substream->pcm->card->dev;
+ struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+ int ret, spdifclock;
+
+ spdif->reg_ctrl &= ~TEGRA20_SPDIF_CTRL_PACK;
+ spdif->reg_ctrl &= ~TEGRA20_SPDIF_CTRL_BIT_MODE_MASK;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_PACK;
+ spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (params_rate(params)) {
+ case 32000:
+ spdifclock = 4096000;
+ break;
+ case 44100:
+ spdifclock = 5644800;
+ break;
+ case 48000:
+ spdifclock = 6144000;
+ break;
+ case 88200:
+ spdifclock = 11289600;
+ break;
+ case 96000:
+ spdifclock = 12288000;
+ break;
+ case 176400:
+ spdifclock = 22579200;
+ break;
+ case 192000:
+ spdifclock = 24576000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = clk_set_rate(spdif->clk_spdif_out, spdifclock);
+ if (ret) {
+ dev_err(dev, "Can't set SPDIF clock rate: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void tegra20_spdif_start_playback(struct tegra20_spdif *spdif)
+{
+ spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_TX_EN;
+ tegra20_spdif_write(spdif, TEGRA20_SPDIF_CTRL, spdif->reg_ctrl);
+}
+
+static void tegra20_spdif_stop_playback(struct tegra20_spdif *spdif)
+{
+ spdif->reg_ctrl &= ~TEGRA20_SPDIF_CTRL_TX_EN;
+ tegra20_spdif_write(spdif, TEGRA20_SPDIF_CTRL, spdif->reg_ctrl);
+}
+
+static int tegra20_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ tegra20_spdif_start_playback(spdif);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ tegra20_spdif_stop_playback(spdif);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int tegra20_spdif_probe(struct snd_soc_dai *dai)
+{
+ struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai);
+
+ dai->capture_dma_data = NULL;
+ dai->playback_dma_data = &spdif->playback_dma_data;
+
+ return 0;
+}
+
+static const struct snd_soc_dai_ops tegra20_spdif_dai_ops = {
+ .hw_params = tegra20_spdif_hw_params,
+ .trigger = tegra20_spdif_trigger,
+};
+
+static struct snd_soc_dai_driver tegra20_spdif_dai = {
+ .name = DRV_NAME,
+ .probe = tegra20_spdif_probe,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &tegra20_spdif_dai_ops,
+};
+
+static bool tegra20_spdif_wr_rd_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TEGRA20_SPDIF_CTRL:
+ case TEGRA20_SPDIF_STATUS:
+ case TEGRA20_SPDIF_STROBE_CTRL:
+ case TEGRA20_SPDIF_DATA_FIFO_CSR:
+ case TEGRA20_SPDIF_DATA_OUT:
+ case TEGRA20_SPDIF_DATA_IN:
+ case TEGRA20_SPDIF_CH_STA_RX_A:
+ case TEGRA20_SPDIF_CH_STA_RX_B:
+ case TEGRA20_SPDIF_CH_STA_RX_C:
+ case TEGRA20_SPDIF_CH_STA_RX_D:
+ case TEGRA20_SPDIF_CH_STA_RX_E:
+ case TEGRA20_SPDIF_CH_STA_RX_F:
+ case TEGRA20_SPDIF_CH_STA_TX_A:
+ case TEGRA20_SPDIF_CH_STA_TX_B:
+ case TEGRA20_SPDIF_CH_STA_TX_C:
+ case TEGRA20_SPDIF_CH_STA_TX_D:
+ case TEGRA20_SPDIF_CH_STA_TX_E:
+ case TEGRA20_SPDIF_CH_STA_TX_F:
+ case TEGRA20_SPDIF_USR_STA_RX_A:
+ case TEGRA20_SPDIF_USR_DAT_TX_A:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static bool tegra20_spdif_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TEGRA20_SPDIF_STATUS:
+ case TEGRA20_SPDIF_DATA_FIFO_CSR:
+ case TEGRA20_SPDIF_DATA_OUT:
+ case TEGRA20_SPDIF_DATA_IN:
+ case TEGRA20_SPDIF_CH_STA_RX_A:
+ case TEGRA20_SPDIF_CH_STA_RX_B:
+ case TEGRA20_SPDIF_CH_STA_RX_C:
+ case TEGRA20_SPDIF_CH_STA_RX_D:
+ case TEGRA20_SPDIF_CH_STA_RX_E:
+ case TEGRA20_SPDIF_CH_STA_RX_F:
+ case TEGRA20_SPDIF_USR_STA_RX_A:
+ case TEGRA20_SPDIF_USR_DAT_TX_A:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static bool tegra20_spdif_precious_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TEGRA20_SPDIF_DATA_OUT:
+ case TEGRA20_SPDIF_DATA_IN:
+ case TEGRA20_SPDIF_USR_STA_RX_A:
+ case TEGRA20_SPDIF_USR_DAT_TX_A:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static const struct regmap_config tegra20_spdif_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = TEGRA20_SPDIF_USR_DAT_TX_A,
+ .writeable_reg = tegra20_spdif_wr_rd_reg,
+ .readable_reg = tegra20_spdif_wr_rd_reg,
+ .volatile_reg = tegra20_spdif_volatile_reg,
+ .precious_reg = tegra20_spdif_precious_reg,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static __devinit int tegra20_spdif_platform_probe(struct platform_device *pdev)
+{
+ struct tegra20_spdif *spdif;
+ struct resource *mem, *memregion, *dmareq;
+ void __iomem *regs;
+ int ret;
+
+ spdif = devm_kzalloc(&pdev->dev, sizeof(struct tegra20_spdif),
+ GFP_KERNEL);
+ if (!spdif) {
+ dev_err(&pdev->dev, "Can't allocate tegra20_spdif\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ dev_set_drvdata(&pdev->dev, spdif);
+
+ spdif->clk_spdif_out = clk_get(&pdev->dev, "spdif_out");
+ if (IS_ERR(spdif->clk_spdif_out)) {
+ pr_err("Can't retrieve spdif clock\n");
+ ret = PTR_ERR(spdif->clk_spdif_out);
+ goto err;
+ }
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "No memory resource\n");
+ ret = -ENODEV;
+ goto err_clk_put;
+ }
+
+ dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!dmareq) {
+ dev_err(&pdev->dev, "No DMA resource\n");
+ ret = -ENODEV;
+ goto err_clk_put;
+ }
+
+ memregion = devm_request_mem_region(&pdev->dev, mem->start,
+ resource_size(mem), DRV_NAME);
+ if (!memregion) {
+ dev_err(&pdev->dev, "Memory region already claimed\n");
+ ret = -EBUSY;
+ goto err_clk_put;
+ }
+
+ regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
+ if (!regs) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto err_clk_put;
+ }
+
+ spdif->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+ &tegra20_spdif_regmap_config);
+ if (IS_ERR(spdif->regmap)) {
+ dev_err(&pdev->dev, "regmap init failed\n");
+ ret = PTR_ERR(spdif->regmap);
+ goto err_clk_put;
+ }
+
+ spdif->playback_dma_data.addr = mem->start + TEGRA20_SPDIF_DATA_OUT;
+ spdif->playback_dma_data.wrap = 4;
+ spdif->playback_dma_data.width = 32;
+ spdif->playback_dma_data.req_sel = dmareq->start;
+
+ pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ ret = tegra20_spdif_runtime_resume(&pdev->dev);
+ if (ret)
+ goto err_pm_disable;
+ }
+
+ ret = snd_soc_register_dai(&pdev->dev, &tegra20_spdif_dai);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
+ ret = -ENOMEM;
+ goto err_suspend;
+ }
+
+ ret = tegra_pcm_platform_register(&pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
+ goto err_unregister_dai;
+ }
+
+ return 0;
+
+err_unregister_dai:
+ snd_soc_unregister_dai(&pdev->dev);
+err_suspend:
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ tegra20_spdif_runtime_suspend(&pdev->dev);
+err_pm_disable:
+ pm_runtime_disable(&pdev->dev);
+err_clk_put:
+ clk_put(spdif->clk_spdif_out);
+err:
+ return ret;
+}
+
+static int __devexit tegra20_spdif_platform_remove(struct platform_device *pdev)
+{
+ struct tegra20_spdif *spdif = dev_get_drvdata(&pdev->dev);
+
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ tegra20_spdif_runtime_suspend(&pdev->dev);
+
+ tegra_pcm_platform_unregister(&pdev->dev);
+ snd_soc_unregister_dai(&pdev->dev);
+
+ clk_put(spdif->clk_spdif_out);
+
+ return 0;
+}
+
+static const struct dev_pm_ops tegra20_spdif_pm_ops __devinitconst = {
+ SET_RUNTIME_PM_OPS(tegra20_spdif_runtime_suspend,
+ tegra20_spdif_runtime_resume, NULL)
+};
+
+static struct platform_driver tegra20_spdif_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &tegra20_spdif_pm_ops,
+ },
+ .probe = tegra20_spdif_platform_probe,
+ .remove = __devexit_p(tegra20_spdif_platform_remove),
+};
+
+module_platform_driver(tegra20_spdif_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra20 SPDIF ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra20_spdif.h b/sound/soc/tegra/tegra20_spdif.h
new file mode 100644
index 000000000000..ed756527efea
--- /dev/null
+++ b/sound/soc/tegra/tegra20_spdif.h
@@ -0,0 +1,471 @@
+/*
+ * tegra20_spdif.h - Definitions for Tegra20 SPDIF driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2011 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ * Copyright (c) 2008-2009, NVIDIA Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __TEGRA20_SPDIF_H__
+#define __TEGRA20_SPDIF_H__
+
+#include "tegra_pcm.h"
+
+/* Offsets from TEGRA20_SPDIF_BASE */
+
+#define TEGRA20_SPDIF_CTRL 0x0
+#define TEGRA20_SPDIF_STATUS 0x4
+#define TEGRA20_SPDIF_STROBE_CTRL 0x8
+#define TEGRA20_SPDIF_DATA_FIFO_CSR 0x0C
+#define TEGRA20_SPDIF_DATA_OUT 0x40
+#define TEGRA20_SPDIF_DATA_IN 0x80
+#define TEGRA20_SPDIF_CH_STA_RX_A 0x100
+#define TEGRA20_SPDIF_CH_STA_RX_B 0x104
+#define TEGRA20_SPDIF_CH_STA_RX_C 0x108
+#define TEGRA20_SPDIF_CH_STA_RX_D 0x10C
+#define TEGRA20_SPDIF_CH_STA_RX_E 0x110
+#define TEGRA20_SPDIF_CH_STA_RX_F 0x114
+#define TEGRA20_SPDIF_CH_STA_TX_A 0x140
+#define TEGRA20_SPDIF_CH_STA_TX_B 0x144
+#define TEGRA20_SPDIF_CH_STA_TX_C 0x148
+#define TEGRA20_SPDIF_CH_STA_TX_D 0x14C
+#define TEGRA20_SPDIF_CH_STA_TX_E 0x150
+#define TEGRA20_SPDIF_CH_STA_TX_F 0x154
+#define TEGRA20_SPDIF_USR_STA_RX_A 0x180
+#define TEGRA20_SPDIF_USR_DAT_TX_A 0x1C0
+
+/* Fields in TEGRA20_SPDIF_CTRL */
+
+/* Start capturing from 0=right, 1=left channel */
+#define TEGRA20_SPDIF_CTRL_CAP_LC (1 << 30)
+
+/* SPDIF receiver(RX) enable */
+#define TEGRA20_SPDIF_CTRL_RX_EN (1 << 29)
+
+/* SPDIF Transmitter(TX) enable */
+#define TEGRA20_SPDIF_CTRL_TX_EN (1 << 28)
+
+/* Transmit Channel status */
+#define TEGRA20_SPDIF_CTRL_TC_EN (1 << 27)
+
+/* Transmit user Data */
+#define TEGRA20_SPDIF_CTRL_TU_EN (1 << 26)
+
+/* Interrupt on transmit error */
+#define TEGRA20_SPDIF_CTRL_IE_TXE (1 << 25)
+
+/* Interrupt on receive error */
+#define TEGRA20_SPDIF_CTRL_IE_RXE (1 << 24)
+
+/* Interrupt on invalid preamble */
+#define TEGRA20_SPDIF_CTRL_IE_P (1 << 23)
+
+/* Interrupt on "B" preamble */
+#define TEGRA20_SPDIF_CTRL_IE_B (1 << 22)
+
+/* Interrupt when block of channel status received */
+#define TEGRA20_SPDIF_CTRL_IE_C (1 << 21)
+
+/* Interrupt when a valid information unit (IU) is received */
+#define TEGRA20_SPDIF_CTRL_IE_U (1 << 20)
+
+/* Interrupt when RX user FIFO attention level is reached */
+#define TEGRA20_SPDIF_CTRL_QE_RU (1 << 19)
+
+/* Interrupt when TX user FIFO attention level is reached */
+#define TEGRA20_SPDIF_CTRL_QE_TU (1 << 18)
+
+/* Interrupt when RX data FIFO attention level is reached */
+#define TEGRA20_SPDIF_CTRL_QE_RX (1 << 17)
+
+/* Interrupt when TX data FIFO attention level is reached */
+#define TEGRA20_SPDIF_CTRL_QE_TX (1 << 16)
+
+/* Loopback test mode enable */
+#define TEGRA20_SPDIF_CTRL_LBK_EN (1 << 15)
+
+/*
+ * Pack data mode:
+ * 0 = Single data (16 bit needs to be padded to match the
+ * interface data bit size).
+ * 1 = Packeted left/right channel data into a single word.
+ */
+#define TEGRA20_SPDIF_CTRL_PACK (1 << 14)
+
+/*
+ * 00 = 16bit data
+ * 01 = 20bit data
+ * 10 = 24bit data
+ * 11 = raw data
+ */
+#define TEGRA20_SPDIF_BIT_MODE_16BIT 0
+#define TEGRA20_SPDIF_BIT_MODE_20BIT 1
+#define TEGRA20_SPDIF_BIT_MODE_24BIT 2
+#define TEGRA20_SPDIF_BIT_MODE_RAW 3
+
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT 12
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_MASK (3 << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT)
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT (TEGRA20_SPDIF_BIT_MODE_16BIT << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT)
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_20BIT (TEGRA20_SPDIF_BIT_MODE_20BIT << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT)
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_24BIT (TEGRA20_SPDIF_BIT_MODE_24BIT << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT)
+#define TEGRA20_SPDIF_CTRL_BIT_MODE_RAW (TEGRA20_SPDIF_BIT_MODE_RAW << TEGRA20_SPDIF_CTRL_BIT_MODE_SHIFT)
+
+/* Fields in TEGRA20_SPDIF_STATUS */
+
+/*
+ * Note: IS_P, IS_B, IS_C, and IS_U are sticky bits. Software must
+ * write a 1 to the corresponding bit location to clear the status.
+ */
+
+/*
+ * Receiver(RX) shifter is busy receiving data.
+ * This bit is asserted when the receiver first locked onto the
+ * preamble of the data stream after RX_EN is asserted. This bit is
+ * deasserted when either,
+ * (a) the end of a frame is reached after RX_EN is deeasserted, or
+ * (b) the SPDIF data stream becomes inactive.
+ */
+#define TEGRA20_SPDIF_STATUS_RX_BSY (1 << 29)
+
+/*
+ * Transmitter(TX) shifter is busy transmitting data.
+ * This bit is asserted when TX_EN is asserted.
+ * This bit is deasserted when the end of a frame is reached after
+ * TX_EN is deasserted.
+ */
+#define TEGRA20_SPDIF_STATUS_TX_BSY (1 << 28)
+
+/*
+ * TX is busy shifting out channel status.
+ * This bit is asserted when both TX_EN and TC_EN are asserted and
+ * data from CH_STA_TX_A register is loaded into the internal shifter.
+ * This bit is deasserted when either,
+ * (a) the end of a frame is reached after TX_EN is deasserted, or
+ * (b) CH_STA_TX_F register is loaded into the internal shifter.
+ */
+#define TEGRA20_SPDIF_STATUS_TC_BSY (1 << 27)
+
+/*
+ * TX User data FIFO busy.
+ * This bit is asserted when TX_EN and TXU_EN are asserted and
+ * there's data in the TX user FIFO. This bit is deassert when either,
+ * (a) the end of a frame is reached after TX_EN is deasserted, or
+ * (b) there's no data left in the TX user FIFO.
+ */
+#define TEGRA20_SPDIF_STATUS_TU_BSY (1 << 26)
+
+/* TX FIFO Underrun error status */
+#define TEGRA20_SPDIF_STATUS_TX_ERR (1 << 25)
+
+/* RX FIFO Overrun error status */
+#define TEGRA20_SPDIF_STATUS_RX_ERR (1 << 24)
+
+/* Preamble status: 0=Preamble OK, 1=bad/missing preamble */
+#define TEGRA20_SPDIF_STATUS_IS_P (1 << 23)
+
+/* B-preamble detection status: 0=not detected, 1=B-preamble detected */
+#define TEGRA20_SPDIF_STATUS_IS_B (1 << 22)
+
+/*
+ * RX channel block data receive status:
+ * 0=entire block not recieved yet.
+ * 1=received entire block of channel status,
+ */
+#define TEGRA20_SPDIF_STATUS_IS_C (1 << 21)
+
+/* RX User Data Valid flag: 1=valid IU detected, 0 = no IU detected. */
+#define TEGRA20_SPDIF_STATUS_IS_U (1 << 20)
+
+/*
+ * RX User FIFO Status:
+ * 1=attention level reached, 0=attention level not reached.
+ */
+#define TEGRA20_SPDIF_STATUS_QS_RU (1 << 19)
+
+/*
+ * TX User FIFO Status:
+ * 1=attention level reached, 0=attention level not reached.
+ */
+#define TEGRA20_SPDIF_STATUS_QS_TU (1 << 18)
+
+/*
+ * RX Data FIFO Status:
+ * 1=attention level reached, 0=attention level not reached.
+ */
+#define TEGRA20_SPDIF_STATUS_QS_RX (1 << 17)
+
+/*
+ * TX Data FIFO Status:
+ * 1=attention level reached, 0=attention level not reached.
+ */
+#define TEGRA20_SPDIF_STATUS_QS_TX (1 << 16)
+
+/* Fields in TEGRA20_SPDIF_STROBE_CTRL */
+
+/*
+ * Indicates the approximate number of detected SPDIFIN clocks within a
+ * bi-phase period.
+ */
+#define TEGRA20_SPDIF_STROBE_CTRL_PERIOD_SHIFT 16
+#define TEGRA20_SPDIF_STROBE_CTRL_PERIOD_MASK (0xff << TEGRA20_SPDIF_STROBE_CTRL_PERIOD_SHIFT)
+
+/* Data strobe mode: 0=Auto-locked 1=Manual locked */
+#define TEGRA20_SPDIF_STROBE_CTRL_STROBE (1 << 15)
+
+/*
+ * Manual data strobe time within the bi-phase clock period (in terms of
+ * the number of over-sampling clocks).
+ */
+#define TEGRA20_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT 8
+#define TEGRA20_SPDIF_STROBE_CTRL_DATA_STROBES_MASK (0x1f << TEGRA20_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT)
+
+/*
+ * Manual SPDIFIN bi-phase clock period (in terms of the number of
+ * over-sampling clocks).
+ */
+#define TEGRA20_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT 0
+#define TEGRA20_SPDIF_STROBE_CTRL_CLOCK_PERIOD_MASK (0x3f << TEGRA20_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT)
+
+/* Fields in SPDIF_DATA_FIFO_CSR */
+
+/* Clear Receiver User FIFO (RX USR.FIFO) */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_CLR (1 << 31)
+
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT 0
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS 1
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS 2
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS 3
+
+/* RU FIFO attention level */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT 29
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_MASK \
+ (0x3 << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU1_WORD_FULL \
+ (TEGRA20_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU2_WORD_FULL \
+ (TEGRA20_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU3_WORD_FULL \
+ (TEGRA20_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU4_WORD_FULL \
+ (TEGRA20_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
+
+/* Number of RX USR.FIFO levels with valid data. */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT 24
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_MASK (0x1f << TEGRA20_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT)
+
+/* Clear Transmitter User FIFO (TX USR.FIFO) */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_CLR (1 << 23)
+
+/* TU FIFO attention level */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT 21
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_MASK \
+ (0x3 << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU1_WORD_FULL \
+ (TEGRA20_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU2_WORD_FULL \
+ (TEGRA20_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU3_WORD_FULL \
+ (TEGRA20_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU4_WORD_FULL \
+ (TEGRA20_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
+
+/* Number of TX USR.FIFO levels that could be filled. */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT 16
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_MASK (0x1f << SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT)
+
+/* Clear Receiver Data FIFO (RX DATA.FIFO) */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_CLR (1 << 15)
+
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT 0
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS 1
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS 2
+#define TEGRA20_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS 3
+
+/* RU FIFO attention level */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT 13
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_MASK \
+ (0x3 << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU1_WORD_FULL \
+ (TEGRA20_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU4_WORD_FULL \
+ (TEGRA20_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU8_WORD_FULL \
+ (TEGRA20_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU12_WORD_FULL \
+ (TEGRA20_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
+
+/* Number of RX DATA.FIFO levels with valid data. */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT 8
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_MASK (0x1f << TEGRA20_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT)
+
+/* Clear Transmitter Data FIFO (TX DATA.FIFO) */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_CLR (1 << 7)
+
+/* TU FIFO attention level */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT 5
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_MASK \
+ (0x3 << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU1_WORD_FULL \
+ (TEGRA20_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU4_WORD_FULL \
+ (TEGRA20_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU8_WORD_FULL \
+ (TEGRA20_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU12_WORD_FULL \
+ (TEGRA20_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA20_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
+
+/* Number of TX DATA.FIFO levels that could be filled. */
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT 0
+#define TEGRA20_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_MASK (0x1f << SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT)
+
+/* Fields in TEGRA20_SPDIF_DATA_OUT */
+
+/*
+ * This register has 5 different formats:
+ * 16-bit (BIT_MODE=00, PACK=0)
+ * 20-bit (BIT_MODE=01, PACK=0)
+ * 24-bit (BIT_MODE=10, PACK=0)
+ * raw (BIT_MODE=11, PACK=0)
+ * 16-bit packed (BIT_MODE=00, PACK=1)
+ */
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_SHIFT 0
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_MASK (0xffff << TEGRA20_SPDIF_DATA_OUT_DATA_16_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_20_SHIFT 0
+#define TEGRA20_SPDIF_DATA_OUT_DATA_20_MASK (0xfffff << TEGRA20_SPDIF_DATA_OUT_DATA_20_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_24_SHIFT 0
+#define TEGRA20_SPDIF_DATA_OUT_DATA_24_MASK (0xffffff << TEGRA20_SPDIF_DATA_OUT_DATA_24_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_P (1 << 31)
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_C (1 << 30)
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_U (1 << 29)
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_V (1 << 28)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT 8
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_DATA_MASK (0xfffff << TEGRA20_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT 4
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_AUX_MASK (0xf << TEGRA20_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT 0
+#define TEGRA20_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_MASK (0xf << TEGRA20_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT 16
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_MASK (0xffff << TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT 0
+#define TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_MASK (0xffff << TEGRA20_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT)
+
+/* Fields in TEGRA20_SPDIF_DATA_IN */
+
+/*
+ * This register has 5 different formats:
+ * 16-bit (BIT_MODE=00, PACK=0)
+ * 20-bit (BIT_MODE=01, PACK=0)
+ * 24-bit (BIT_MODE=10, PACK=0)
+ * raw (BIT_MODE=11, PACK=0)
+ * 16-bit packed (BIT_MODE=00, PACK=1)
+ *
+ * Bits 31:24 are common to all modes except 16-bit packed
+ */
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_P (1 << 31)
+#define TEGRA20_SPDIF_DATA_IN_DATA_C (1 << 30)
+#define TEGRA20_SPDIF_DATA_IN_DATA_U (1 << 29)
+#define TEGRA20_SPDIF_DATA_IN_DATA_V (1 << 28)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT 24
+#define TEGRA20_SPDIF_DATA_IN_DATA_PREAMBLE_MASK (0xf << TEGRA20_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_SHIFT 0
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_MASK (0xffff << TEGRA20_SPDIF_DATA_IN_DATA_16_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_20_SHIFT 0
+#define TEGRA20_SPDIF_DATA_IN_DATA_20_MASK (0xfffff << TEGRA20_SPDIF_DATA_IN_DATA_20_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_24_SHIFT 0
+#define TEGRA20_SPDIF_DATA_IN_DATA_24_MASK (0xffffff << TEGRA20_SPDIF_DATA_IN_DATA_24_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT 8
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_DATA_MASK (0xfffff << TEGRA20_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT 4
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_AUX_MASK (0xf << TEGRA20_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT 0
+#define TEGRA20_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_MASK (0xf << TEGRA20_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT 16
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_MASK (0xffff << TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT)
+
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT 0
+#define TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_MASK (0xffff << TEGRA20_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT)
+
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_A */
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_B */
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_C */
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_D */
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_E */
+/* Fields in TEGRA20_SPDIF_CH_STA_RX_F */
+
+/*
+ * The 6-word receive channel data page buffer holds a block (192 frames) of
+ * channel status information. The order of receive is from LSB to MSB
+ * bit, and from CH_STA_RX_A to CH_STA_RX_F then back to CH_STA_RX_A.
+ */
+
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_A */
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_B */
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_C */
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_D */
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_E */
+/* Fields in TEGRA20_SPDIF_CH_STA_TX_F */
+
+/*
+ * The 6-word transmit channel data page buffer holds a block (192 frames) of
+ * channel status information. The order of transmission is from LSB to MSB
+ * bit, and from CH_STA_TX_A to CH_STA_TX_F then back to CH_STA_TX_A.
+ */
+
+/* Fields in TEGRA20_SPDIF_USR_STA_RX_A */
+
+/*
+ * This 4-word deep FIFO receives user FIFO field information. The order of
+ * receive is from LSB to MSB bit.
+ */
+
+/* Fields in TEGRA20_SPDIF_USR_DAT_TX_A */
+
+/*
+ * This 4-word deep FIFO transmits user FIFO field information. The order of
+ * transmission is from LSB to MSB bit.
+ */
+
+struct tegra20_spdif {
+ struct clk *clk_spdif_out;
+ struct tegra_pcm_dma_params capture_dma_data;
+ struct tegra_pcm_dma_params playback_dma_data;
+ struct regmap *regmap;
+ u32 reg_ctrl;
+};
+
+#endif
diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
new file mode 100644
index 000000000000..57cd419f743e
--- /dev/null
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -0,0 +1,631 @@
+/*
+ * tegra30_ahub.c - Tegra30 AHUB driver
+ *
+ * Copyright (c) 2011,2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <mach/clk.h>
+#include <mach/dma.h>
+#include <sound/soc.h>
+#include "tegra30_ahub.h"
+
+#define DRV_NAME "tegra30-ahub"
+
+static struct tegra30_ahub *ahub;
+
+static inline void tegra30_apbif_write(u32 reg, u32 val)
+{
+ regmap_write(ahub->regmap_apbif, reg, val);
+}
+
+static inline u32 tegra30_apbif_read(u32 reg)
+{
+ u32 val;
+ regmap_read(ahub->regmap_apbif, reg, &val);
+ return val;
+}
+
+static inline void tegra30_audio_write(u32 reg, u32 val)
+{
+ regmap_write(ahub->regmap_ahub, reg, val);
+}
+
+static int tegra30_ahub_runtime_suspend(struct device *dev)
+{
+ regcache_cache_only(ahub->regmap_apbif, true);
+ regcache_cache_only(ahub->regmap_ahub, true);
+
+ clk_disable(ahub->clk_apbif);
+ clk_disable(ahub->clk_d_audio);
+
+ return 0;
+}
+
+/*
+ * clk_apbif isn't required for an I2S<->I2S configuration where no PCM data
+ * is read from or sent to memory. However, that's not something the rest of
+ * the driver supports right now, so we'll just treat the two clocks as one
+ * for now.
+ *
+ * These functions should not be a plain ref-count. Instead, each active stream
+ * contributes some requirement to the minimum clock rate, so starting or
+ * stopping streams should dynamically adjust the clock as required. However,
+ * this is not yet implemented.
+ */
+static int tegra30_ahub_runtime_resume(struct device *dev)
+{
+ int ret;
+
+ ret = clk_enable(ahub->clk_d_audio);
+ if (ret) {
+ dev_err(dev, "clk_enable d_audio failed: %d\n", ret);
+ return ret;
+ }
+ ret = clk_enable(ahub->clk_apbif);
+ if (ret) {
+ dev_err(dev, "clk_enable apbif failed: %d\n", ret);
+ clk_disable(ahub->clk_d_audio);
+ return ret;
+ }
+
+ regcache_cache_only(ahub->regmap_apbif, false);
+ regcache_cache_only(ahub->regmap_ahub, false);
+
+ return 0;
+}
+
+int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
+ unsigned long *fiforeg,
+ unsigned long *reqsel)
+{
+ int channel;
+ u32 reg, val;
+
+ channel = find_first_zero_bit(ahub->rx_usage,
+ TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
+ if (channel >= TEGRA30_AHUB_CHANNEL_CTRL_COUNT)
+ return -EBUSY;
+
+ __set_bit(channel, ahub->rx_usage);
+
+ *rxcif = TEGRA30_AHUB_RXCIF_APBIF_RX0 + channel;
+ *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_RXFIFO +
+ (channel * TEGRA30_AHUB_CHANNEL_RXFIFO_STRIDE);
+ *reqsel = ahub->dma_sel + channel;
+
+ reg = TEGRA30_AHUB_CHANNEL_CTRL +
+ (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
+ val = tegra30_apbif_read(reg);
+ val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK |
+ TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK);
+ val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT) |
+ TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN |
+ TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16;
+ tegra30_apbif_write(reg, val);
+
+ reg = TEGRA30_AHUB_CIF_RX_CTRL +
+ (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE);
+ val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
+ (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
+ (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
+ TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 |
+ TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16 |
+ TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX;
+ tegra30_apbif_write(reg, val);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_rx_fifo);
+
+int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif)
+{
+ int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
+ int reg, val;
+
+ reg = TEGRA30_AHUB_CHANNEL_CTRL +
+ (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
+ val = tegra30_apbif_read(reg);
+ val |= TEGRA30_AHUB_CHANNEL_CTRL_RX_EN;
+ tegra30_apbif_write(reg, val);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_enable_rx_fifo);
+
+int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif)
+{
+ int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
+ int reg, val;
+
+ reg = TEGRA30_AHUB_CHANNEL_CTRL +
+ (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
+ val = tegra30_apbif_read(reg);
+ val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_EN;
+ tegra30_apbif_write(reg, val);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_disable_rx_fifo);
+
+int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif)
+{
+ int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
+
+ __clear_bit(channel, ahub->rx_usage);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_free_rx_fifo);
+
+int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
+ unsigned long *fiforeg,
+ unsigned long *reqsel)
+{
+ int channel;
+ u32 reg, val;
+
+ channel = find_first_zero_bit(ahub->tx_usage,
+ TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
+ if (channel >= TEGRA30_AHUB_CHANNEL_CTRL_COUNT)
+ return -EBUSY;
+
+ __set_bit(channel, ahub->tx_usage);
+
+ *txcif = TEGRA30_AHUB_TXCIF_APBIF_TX0 + channel;
+ *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_TXFIFO +
+ (channel * TEGRA30_AHUB_CHANNEL_TXFIFO_STRIDE);
+ *reqsel = ahub->dma_sel + channel;
+
+ reg = TEGRA30_AHUB_CHANNEL_CTRL +
+ (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
+ val = tegra30_apbif_read(reg);
+ val &= ~(TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK |
+ TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK);
+ val |= (7 << TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT) |
+ TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN |
+ TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16;
+ tegra30_apbif_write(reg, val);
+
+ reg = TEGRA30_AHUB_CIF_TX_CTRL +
+ (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE);
+ val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
+ (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
+ (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
+ TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 |
+ TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16 |
+ TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX;
+ tegra30_apbif_write(reg, val);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_tx_fifo);
+
+int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif)
+{
+ int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
+ int reg, val;
+
+ reg = TEGRA30_AHUB_CHANNEL_CTRL +
+ (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
+ val = tegra30_apbif_read(reg);
+ val |= TEGRA30_AHUB_CHANNEL_CTRL_TX_EN;
+ tegra30_apbif_write(reg, val);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_enable_tx_fifo);
+
+int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif)
+{
+ int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
+ int reg, val;
+
+ reg = TEGRA30_AHUB_CHANNEL_CTRL +
+ (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE);
+ val = tegra30_apbif_read(reg);
+ val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_EN;
+ tegra30_apbif_write(reg, val);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_disable_tx_fifo);
+
+int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif)
+{
+ int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0;
+
+ __clear_bit(channel, ahub->tx_usage);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_free_tx_fifo);
+
+int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif,
+ enum tegra30_ahub_txcif txcif)
+{
+ int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
+ int reg;
+
+ reg = TEGRA30_AHUB_AUDIO_RX +
+ (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE);
+ tegra30_audio_write(reg, 1 << txcif);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_set_rx_cif_source);
+
+int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif)
+{
+ int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0;
+ int reg;
+
+ reg = TEGRA30_AHUB_AUDIO_RX +
+ (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE);
+ tegra30_audio_write(reg, 0);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source);
+
+static const char * const configlink_clocks[] __devinitconst = {
+ "i2s0",
+ "i2s1",
+ "i2s2",
+ "i2s3",
+ "i2s4",
+ "dam0",
+ "dam1",
+ "dam2",
+ "spdif_in",
+};
+
+struct of_dev_auxdata ahub_auxdata[] __devinitdata = {
+ OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080300, "tegra30-i2s.0", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080400, "tegra30-i2s.1", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080500, "tegra30-i2s.2", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080600, "tegra30-i2s.3", NULL),
+ OF_DEV_AUXDATA("nvidia,tegra30-i2s", 0x70080700, "tegra30-i2s.4", NULL),
+ {}
+};
+
+#define LAST_REG(name) \
+ (TEGRA30_AHUB_##name + \
+ (TEGRA30_AHUB_##name##_STRIDE * TEGRA30_AHUB_##name##_COUNT) - 4)
+
+#define REG_IN_ARRAY(reg, name) \
+ ((reg >= TEGRA30_AHUB_##name) && \
+ (reg <= LAST_REG(name) && \
+ (!((reg - TEGRA30_AHUB_##name) % TEGRA30_AHUB_##name##_STRIDE))))
+
+static bool tegra30_ahub_apbif_wr_rd_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TEGRA30_AHUB_CONFIG_LINK_CTRL:
+ case TEGRA30_AHUB_MISC_CTRL:
+ case TEGRA30_AHUB_APBDMA_LIVE_STATUS:
+ case TEGRA30_AHUB_I2S_LIVE_STATUS:
+ case TEGRA30_AHUB_SPDIF_LIVE_STATUS:
+ case TEGRA30_AHUB_I2S_INT_MASK:
+ case TEGRA30_AHUB_DAM_INT_MASK:
+ case TEGRA30_AHUB_SPDIF_INT_MASK:
+ case TEGRA30_AHUB_APBIF_INT_MASK:
+ case TEGRA30_AHUB_I2S_INT_STATUS:
+ case TEGRA30_AHUB_DAM_INT_STATUS:
+ case TEGRA30_AHUB_SPDIF_INT_STATUS:
+ case TEGRA30_AHUB_APBIF_INT_STATUS:
+ case TEGRA30_AHUB_I2S_INT_SOURCE:
+ case TEGRA30_AHUB_DAM_INT_SOURCE:
+ case TEGRA30_AHUB_SPDIF_INT_SOURCE:
+ case TEGRA30_AHUB_APBIF_INT_SOURCE:
+ case TEGRA30_AHUB_I2S_INT_SET:
+ case TEGRA30_AHUB_DAM_INT_SET:
+ case TEGRA30_AHUB_SPDIF_INT_SET:
+ case TEGRA30_AHUB_APBIF_INT_SET:
+ return true;
+ default:
+ break;
+ };
+
+ if (REG_IN_ARRAY(reg, CHANNEL_CTRL) ||
+ REG_IN_ARRAY(reg, CHANNEL_CLEAR) ||
+ REG_IN_ARRAY(reg, CHANNEL_STATUS) ||
+ REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
+ REG_IN_ARRAY(reg, CHANNEL_RXFIFO) ||
+ REG_IN_ARRAY(reg, CIF_TX_CTRL) ||
+ REG_IN_ARRAY(reg, CIF_RX_CTRL) ||
+ REG_IN_ARRAY(reg, DAM_LIVE_STATUS))
+ return true;
+
+ return false;
+}
+
+static bool tegra30_ahub_apbif_volatile_reg(struct device *dev,
+ unsigned int reg)
+{
+ switch (reg) {
+ case TEGRA30_AHUB_CONFIG_LINK_CTRL:
+ case TEGRA30_AHUB_MISC_CTRL:
+ case TEGRA30_AHUB_APBDMA_LIVE_STATUS:
+ case TEGRA30_AHUB_I2S_LIVE_STATUS:
+ case TEGRA30_AHUB_SPDIF_LIVE_STATUS:
+ case TEGRA30_AHUB_I2S_INT_STATUS:
+ case TEGRA30_AHUB_DAM_INT_STATUS:
+ case TEGRA30_AHUB_SPDIF_INT_STATUS:
+ case TEGRA30_AHUB_APBIF_INT_STATUS:
+ case TEGRA30_AHUB_I2S_INT_SET:
+ case TEGRA30_AHUB_DAM_INT_SET:
+ case TEGRA30_AHUB_SPDIF_INT_SET:
+ case TEGRA30_AHUB_APBIF_INT_SET:
+ return true;
+ default:
+ break;
+ };
+
+ if (REG_IN_ARRAY(reg, CHANNEL_CLEAR) ||
+ REG_IN_ARRAY(reg, CHANNEL_STATUS) ||
+ REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
+ REG_IN_ARRAY(reg, CHANNEL_RXFIFO) ||
+ REG_IN_ARRAY(reg, DAM_LIVE_STATUS))
+ return true;
+
+ return false;
+}
+
+static bool tegra30_ahub_apbif_precious_reg(struct device *dev,
+ unsigned int reg)
+{
+ if (REG_IN_ARRAY(reg, CHANNEL_TXFIFO) ||
+ REG_IN_ARRAY(reg, CHANNEL_RXFIFO))
+ return true;
+
+ return false;
+}
+
+static const struct regmap_config tegra30_ahub_apbif_regmap_config = {
+ .name = "apbif",
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = TEGRA30_AHUB_APBIF_INT_SET,
+ .writeable_reg = tegra30_ahub_apbif_wr_rd_reg,
+ .readable_reg = tegra30_ahub_apbif_wr_rd_reg,
+ .volatile_reg = tegra30_ahub_apbif_volatile_reg,
+ .precious_reg = tegra30_ahub_apbif_precious_reg,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static bool tegra30_ahub_ahub_wr_rd_reg(struct device *dev, unsigned int reg)
+{
+ if (REG_IN_ARRAY(reg, AUDIO_RX))
+ return true;
+
+ return false;
+}
+
+static const struct regmap_config tegra30_ahub_ahub_regmap_config = {
+ .name = "ahub",
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = LAST_REG(AUDIO_RX),
+ .writeable_reg = tegra30_ahub_ahub_wr_rd_reg,
+ .readable_reg = tegra30_ahub_ahub_wr_rd_reg,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static int __devinit tegra30_ahub_probe(struct platform_device *pdev)
+{
+ struct clk *clk;
+ int i;
+ struct resource *res0, *res1, *region;
+ u32 of_dma[2];
+ void __iomem *regs_apbif, *regs_ahub;
+ int ret = 0;
+
+ if (ahub)
+ return -ENODEV;
+
+ /*
+ * The AHUB hosts a register bus: the "configlink". For this to
+ * operate correctly, all devices on this bus must be out of reset.
+ * Ensure that here.
+ */
+ for (i = 0; i < ARRAY_SIZE(configlink_clocks); i++) {
+ clk = clk_get_sys(NULL, configlink_clocks[i]);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "Can't get clock %s\n",
+ configlink_clocks[i]);
+ ret = PTR_ERR(clk);
+ goto err;
+ }
+ tegra_periph_reset_deassert(clk);
+ clk_put(clk);
+ }
+
+ ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub),
+ GFP_KERNEL);
+ if (!ahub) {
+ dev_err(&pdev->dev, "Can't allocate tegra30_ahub\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ dev_set_drvdata(&pdev->dev, ahub);
+
+ ahub->dev = &pdev->dev;
+
+ ahub->clk_d_audio = clk_get(&pdev->dev, "d_audio");
+ if (IS_ERR(ahub->clk_d_audio)) {
+ dev_err(&pdev->dev, "Can't retrieve ahub d_audio clock\n");
+ ret = PTR_ERR(ahub->clk_d_audio);
+ goto err;
+ }
+
+ ahub->clk_apbif = clk_get(&pdev->dev, "apbif");
+ if (IS_ERR(ahub->clk_apbif)) {
+ dev_err(&pdev->dev, "Can't retrieve ahub apbif clock\n");
+ ret = PTR_ERR(ahub->clk_apbif);
+ goto err_clk_put_d_audio;
+ }
+
+ if (of_property_read_u32_array(pdev->dev.of_node,
+ "nvidia,dma-request-selector",
+ of_dma, 2) < 0) {
+ dev_err(&pdev->dev,
+ "Missing property nvidia,dma-request-selector\n");
+ ret = -ENODEV;
+ goto err_clk_put_d_audio;
+ }
+ ahub->dma_sel = of_dma[1];
+
+ res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res0) {
+ dev_err(&pdev->dev, "No apbif memory resource\n");
+ ret = -ENODEV;
+ goto err_clk_put_apbif;
+ }
+
+ region = devm_request_mem_region(&pdev->dev, res0->start,
+ resource_size(res0), DRV_NAME);
+ if (!region) {
+ dev_err(&pdev->dev, "request region apbif failed\n");
+ ret = -EBUSY;
+ goto err_clk_put_apbif;
+ }
+ ahub->apbif_addr = res0->start;
+
+ regs_apbif = devm_ioremap(&pdev->dev, res0->start,
+ resource_size(res0));
+ if (!regs_apbif) {
+ dev_err(&pdev->dev, "ioremap apbif failed\n");
+ ret = -ENOMEM;
+ goto err_clk_put_apbif;
+ }
+
+ ahub->regmap_apbif = devm_regmap_init_mmio(&pdev->dev, regs_apbif,
+ &tegra30_ahub_apbif_regmap_config);
+ if (IS_ERR(ahub->regmap_apbif)) {
+ dev_err(&pdev->dev, "apbif regmap init failed\n");
+ ret = PTR_ERR(ahub->regmap_apbif);
+ goto err_clk_put_apbif;
+ }
+ regcache_cache_only(ahub->regmap_apbif, true);
+
+ res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res1) {
+ dev_err(&pdev->dev, "No ahub memory resource\n");
+ ret = -ENODEV;
+ goto err_clk_put_apbif;
+ }
+
+ region = devm_request_mem_region(&pdev->dev, res1->start,
+ resource_size(res1), DRV_NAME);
+ if (!region) {
+ dev_err(&pdev->dev, "request region ahub failed\n");
+ ret = -EBUSY;
+ goto err_clk_put_apbif;
+ }
+
+ regs_ahub = devm_ioremap(&pdev->dev, res1->start,
+ resource_size(res1));
+ if (!regs_ahub) {
+ dev_err(&pdev->dev, "ioremap ahub failed\n");
+ ret = -ENOMEM;
+ goto err_clk_put_apbif;
+ }
+
+ ahub->regmap_ahub = devm_regmap_init_mmio(&pdev->dev, regs_ahub,
+ &tegra30_ahub_ahub_regmap_config);
+ if (IS_ERR(ahub->regmap_ahub)) {
+ dev_err(&pdev->dev, "ahub regmap init failed\n");
+ ret = PTR_ERR(ahub->regmap_ahub);
+ goto err_clk_put_apbif;
+ }
+ regcache_cache_only(ahub->regmap_ahub, true);
+
+ pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ ret = tegra30_ahub_runtime_resume(&pdev->dev);
+ if (ret)
+ goto err_pm_disable;
+ }
+
+ of_platform_populate(pdev->dev.of_node, NULL, ahub_auxdata,
+ &pdev->dev);
+
+ return 0;
+
+err_pm_disable:
+ pm_runtime_disable(&pdev->dev);
+err_clk_put_apbif:
+ clk_put(ahub->clk_apbif);
+err_clk_put_d_audio:
+ clk_put(ahub->clk_d_audio);
+ ahub = 0;
+err:
+ return ret;
+}
+
+static int __devexit tegra30_ahub_remove(struct platform_device *pdev)
+{
+ if (!ahub)
+ return -ENODEV;
+
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ tegra30_ahub_runtime_suspend(&pdev->dev);
+
+ clk_put(ahub->clk_apbif);
+ clk_put(ahub->clk_d_audio);
+
+ ahub = 0;
+
+ return 0;
+}
+
+static const struct of_device_id tegra30_ahub_of_match[] __devinitconst = {
+ { .compatible = "nvidia,tegra30-ahub", },
+ {},
+};
+
+static const struct dev_pm_ops tegra30_ahub_pm_ops __devinitconst = {
+ SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend,
+ tegra30_ahub_runtime_resume, NULL)
+};
+
+static struct platform_driver tegra30_ahub_driver = {
+ .probe = tegra30_ahub_probe,
+ .remove = __devexit_p(tegra30_ahub_remove),
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = tegra30_ahub_of_match,
+ .pm = &tegra30_ahub_pm_ops,
+ },
+};
+module_platform_driver(tegra30_ahub_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra30 AHUB driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h
new file mode 100644
index 000000000000..e690e2eecc92
--- /dev/null
+++ b/sound/soc/tegra/tegra30_ahub.h
@@ -0,0 +1,483 @@
+/*
+ * tegra30_ahub.h - Definitions for Tegra30 AHUB driver
+ *
+ * Copyright (c) 2011,2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __TEGRA30_AHUB_H__
+#define __TEGRA30_AHUB_H__
+
+/* Fields in *_CIF_RX/TX_CTRL; used by AHUB FIFOs, and all other audio modules */
+
+#define TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT 28
+#define TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK_US 0xf
+#define TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK (TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_MASK_US << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT)
+
+/* Channel count minus 1 */
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT 24
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK_US 7
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK (TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_MASK_US << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT)
+
+/* Channel count minus 1 */
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT 16
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK_US 7
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK (TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_MASK_US << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT)
+
+#define TEGRA30_AUDIOCIF_BITS_4 0
+#define TEGRA30_AUDIOCIF_BITS_8 1
+#define TEGRA30_AUDIOCIF_BITS_12 2
+#define TEGRA30_AUDIOCIF_BITS_16 3
+#define TEGRA30_AUDIOCIF_BITS_20 4
+#define TEGRA30_AUDIOCIF_BITS_24 5
+#define TEGRA30_AUDIOCIF_BITS_28 6
+#define TEGRA30_AUDIOCIF_BITS_32 7
+
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT 12
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_MASK (7 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_4 (TEGRA30_AUDIOCIF_BITS_4 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_8 (TEGRA30_AUDIOCIF_BITS_8 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_12 (TEGRA30_AUDIOCIF_BITS_12 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 (TEGRA30_AUDIOCIF_BITS_16 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_20 (TEGRA30_AUDIOCIF_BITS_20 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_24 (TEGRA30_AUDIOCIF_BITS_24 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_28 (TEGRA30_AUDIOCIF_BITS_28 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_32 (TEGRA30_AUDIOCIF_BITS_32 << TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_SHIFT)
+
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT 8
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_MASK (7 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_4 (TEGRA30_AUDIOCIF_BITS_4 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_8 (TEGRA30_AUDIOCIF_BITS_8 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_12 (TEGRA30_AUDIOCIF_BITS_12 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16 (TEGRA30_AUDIOCIF_BITS_16 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_20 (TEGRA30_AUDIOCIF_BITS_20 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_24 (TEGRA30_AUDIOCIF_BITS_24 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_28 (TEGRA30_AUDIOCIF_BITS_28 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_32 (TEGRA30_AUDIOCIF_BITS_32 << TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_SHIFT)
+
+#define TEGRA30_AUDIOCIF_EXPAND_ZERO 0
+#define TEGRA30_AUDIOCIF_EXPAND_ONE 1
+#define TEGRA30_AUDIOCIF_EXPAND_LFSR 2
+
+#define TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT 6
+#define TEGRA30_AUDIOCIF_CTRL_EXPAND_MASK (3 << TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_EXPAND_ZERO (TEGRA30_AUDIOCIF_EXPAND_ZERO << TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_EXPAND_ONE (TEGRA30_AUDIOCIF_EXPAND_ONE << TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_EXPAND_LFSR (TEGRA30_AUDIOCIF_EXPAND_LFSR << TEGRA30_AUDIOCIF_CTRL_EXPAND_SHIFT)
+
+#define TEGRA30_AUDIOCIF_STEREO_CONV_CH0 0
+#define TEGRA30_AUDIOCIF_STEREO_CONV_CH1 1
+#define TEGRA30_AUDIOCIF_STEREO_CONV_AVG 2
+
+#define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT 4
+#define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_MASK (3 << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_CH0 (TEGRA30_AUDIOCIF_STEREO_CONV_CH0 << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_CH1 (TEGRA30_AUDIOCIF_STEREO_CONV_CH1 << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_AVG (TEGRA30_AUDIOCIF_STEREO_CONV_AVG << TEGRA30_AUDIOCIF_CTRL_STEREO_CONV_SHIFT)
+
+#define TEGRA30_AUDIOCIF_CTRL_REPLICATE 3
+
+#define TEGRA30_AUDIOCIF_DIRECTION_TX 0
+#define TEGRA30_AUDIOCIF_DIRECTION_RX 1
+
+#define TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT 2
+#define TEGRA30_AUDIOCIF_CTRL_DIRECTION_MASK (1 << TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX (TEGRA30_AUDIOCIF_DIRECTION_TX << TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX (TEGRA30_AUDIOCIF_DIRECTION_RX << TEGRA30_AUDIOCIF_CTRL_DIRECTION_SHIFT)
+
+#define TEGRA30_AUDIOCIF_TRUNCATE_ROUND 0
+#define TEGRA30_AUDIOCIF_TRUNCATE_CHOP 1
+
+#define TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT 1
+#define TEGRA30_AUDIOCIF_CTRL_TRUNCATE_MASK (1 << TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_TRUNCATE_ROUND (TEGRA30_AUDIOCIF_TRUNCATE_ROUND << TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_TRUNCATE_CHOP (TEGRA30_AUDIOCIF_TRUNCATE_CHOP << TEGRA30_AUDIOCIF_CTRL_TRUNCATE_SHIFT)
+
+#define TEGRA30_AUDIOCIF_MONO_CONV_ZERO 0
+#define TEGRA30_AUDIOCIF_MONO_CONV_COPY 1
+
+#define TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT 0
+#define TEGRA30_AUDIOCIF_CTRL_MONO_CONV_MASK (1 << TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_MONO_CONV_ZERO (TEGRA30_AUDIOCIF_MONO_CONV_ZERO << TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT)
+#define TEGRA30_AUDIOCIF_CTRL_MONO_CONV_COPY (TEGRA30_AUDIOCIF_MONO_CONV_COPY << TEGRA30_AUDIOCIF_CTRL_MONO_CONV_SHIFT)
+
+/* Registers within TEGRA30_AUDIO_CLUSTER_BASE */
+
+/* TEGRA30_AHUB_CHANNEL_CTRL */
+
+#define TEGRA30_AHUB_CHANNEL_CTRL 0x0
+#define TEGRA30_AHUB_CHANNEL_CTRL_STRIDE 0x20
+#define TEGRA30_AHUB_CHANNEL_CTRL_COUNT 4
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_EN (1 << 31)
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_EN (1 << 30)
+#define TEGRA30_AHUB_CHANNEL_CTRL_LOOPBACK (1 << 29)
+
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT 16
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK_US 0xff
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK (TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_MASK_US << TEGRA30_AHUB_CHANNEL_CTRL_TX_THRESHOLD_SHIFT)
+
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT 8
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK_US 0xff
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK (TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_MASK_US << TEGRA30_AHUB_CHANNEL_CTRL_RX_THRESHOLD_SHIFT)
+
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_EN (1 << 6)
+
+#define TEGRA30_PACK_8_4 2
+#define TEGRA30_PACK_16 3
+
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_SHIFT 4
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK_US 3
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK (TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_MASK_US << TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_SHIFT)
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_8_4 (TEGRA30_PACK_8_4 << TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_SHIFT)
+#define TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_16 (TEGRA30_PACK_16 << TEGRA30_AHUB_CHANNEL_CTRL_TX_PACK_SHIFT)
+
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_EN (1 << 2)
+
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_SHIFT 0
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK_US 3
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK (TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_MASK_US << TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_SHIFT)
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_8_4 (TEGRA30_PACK_8_4 << TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_SHIFT)
+#define TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_16 (TEGRA30_PACK_16 << TEGRA30_AHUB_CHANNEL_CTRL_RX_PACK_SHIFT)
+
+/* TEGRA30_AHUB_CHANNEL_CLEAR */
+
+#define TEGRA30_AHUB_CHANNEL_CLEAR 0x4
+#define TEGRA30_AHUB_CHANNEL_CLEAR_STRIDE 0x20
+#define TEGRA30_AHUB_CHANNEL_CLEAR_COUNT 4
+#define TEGRA30_AHUB_CHANNEL_CLEAR_TX_SOFT_RESET (1 << 31)
+#define TEGRA30_AHUB_CHANNEL_CLEAR_RX_SOFT_RESET (1 << 30)
+
+/* TEGRA30_AHUB_CHANNEL_STATUS */
+
+#define TEGRA30_AHUB_CHANNEL_STATUS 0x8
+#define TEGRA30_AHUB_CHANNEL_STATUS_STRIDE 0x20
+#define TEGRA30_AHUB_CHANNEL_STATUS_COUNT 4
+#define TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_SHIFT 24
+#define TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_MASK_US 0xff
+#define TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_MASK (TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_MASK_US << TEGRA30_AHUB_CHANNEL_STATUS_TX_FREE_SHIFT)
+#define TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_SHIFT 16
+#define TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_MASK_US 0xff
+#define TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_MASK (TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_MASK_US << TEGRA30_AHUB_CHANNEL_STATUS_RX_FREE_SHIFT)
+#define TEGRA30_AHUB_CHANNEL_STATUS_TX_TRIG (1 << 1)
+#define TEGRA30_AHUB_CHANNEL_STATUS_RX_TRIG (1 << 0)
+
+/* TEGRA30_AHUB_CHANNEL_TXFIFO */
+
+#define TEGRA30_AHUB_CHANNEL_TXFIFO 0xc
+#define TEGRA30_AHUB_CHANNEL_TXFIFO_STRIDE 0x20
+#define TEGRA30_AHUB_CHANNEL_TXFIFO_COUNT 4
+
+/* TEGRA30_AHUB_CHANNEL_RXFIFO */
+
+#define TEGRA30_AHUB_CHANNEL_RXFIFO 0x10
+#define TEGRA30_AHUB_CHANNEL_RXFIFO_STRIDE 0x20
+#define TEGRA30_AHUB_CHANNEL_RXFIFO_COUNT 4
+
+/* TEGRA30_AHUB_CIF_TX_CTRL */
+
+#define TEGRA30_AHUB_CIF_TX_CTRL 0x14
+#define TEGRA30_AHUB_CIF_TX_CTRL_STRIDE 0x20
+#define TEGRA30_AHUB_CIF_TX_CTRL_COUNT 4
+/* Uses field from TEGRA30_AUDIOCIF_CTRL_* */
+
+/* TEGRA30_AHUB_CIF_RX_CTRL */
+
+#define TEGRA30_AHUB_CIF_RX_CTRL 0x18
+#define TEGRA30_AHUB_CIF_RX_CTRL_STRIDE 0x20
+#define TEGRA30_AHUB_CIF_RX_CTRL_COUNT 4
+/* Uses field from TEGRA30_AUDIOCIF_CTRL_* */
+
+/* TEGRA30_AHUB_CONFIG_LINK_CTRL */
+
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL 0x80
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_SHIFT 28
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_MASK_US 0xf
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_MASK (TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_MASK_US << TEGRA30_AHUB_CONFIG_LINK_CTRL_MASTER_FIFO_FULL_CNT_SHIFT)
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_SHIFT 16
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_MASK_US 0xfff
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_MASK (TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_MASK_US << TEGRA30_AHUB_CONFIG_LINK_CTRL_TIMEOUT_CNT_SHIFT)
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_SHIFT 4
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_MASK_US 0xfff
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_MASK (TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_MASK_US << TEGRA30_AHUB_CONFIG_LINK_CTRL_IDLE_CNT_SHIFT)
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_CG_EN (1 << 2)
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_CLEAR_TIMEOUT_CNTR (1 << 1)
+#define TEGRA30_AHUB_CONFIG_LINK_CTRL_SOFT_RESET (1 << 0)
+
+/* TEGRA30_AHUB_MISC_CTRL */
+
+#define TEGRA30_AHUB_MISC_CTRL 0x84
+#define TEGRA30_AHUB_MISC_CTRL_AUDIO_ACTIVE (1 << 31)
+#define TEGRA30_AHUB_MISC_CTRL_AUDIO_CG_EN (1 << 8)
+#define TEGRA30_AHUB_MISC_CTRL_AUDIO_OBS_SEL_SHIFT 0
+#define TEGRA30_AHUB_MISC_CTRL_AUDIO_OBS_SEL_MASK (0x1f << TEGRA30_AHUB_MISC_CTRL_AUDIO_OBS_SEL_SHIFT)
+
+/* TEGRA30_AHUB_APBDMA_LIVE_STATUS */
+
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS 0x88
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_RX_CIF_FIFO_FULL (1 << 31)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_TX_CIF_FIFO_FULL (1 << 30)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_RX_CIF_FIFO_FULL (1 << 29)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_TX_CIF_FIFO_FULL (1 << 28)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_RX_CIF_FIFO_FULL (1 << 27)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_TX_CIF_FIFO_FULL (1 << 26)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_RX_CIF_FIFO_FULL (1 << 25)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_TX_CIF_FIFO_FULL (1 << 24)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_RX_CIF_FIFO_EMPTY (1 << 23)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_TX_CIF_FIFO_EMPTY (1 << 22)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_RX_CIF_FIFO_EMPTY (1 << 21)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_TX_CIF_FIFO_EMPTY (1 << 20)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_RX_CIF_FIFO_EMPTY (1 << 19)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_TX_CIF_FIFO_EMPTY (1 << 18)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_RX_CIF_FIFO_EMPTY (1 << 17)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_TX_CIF_FIFO_EMPTY (1 << 16)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_RX_DMA_FIFO_FULL (1 << 15)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_TX_DMA_FIFO_FULL (1 << 14)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_RX_DMA_FIFO_FULL (1 << 13)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_TX_DMA_FIFO_FULL (1 << 12)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_RX_DMA_FIFO_FULL (1 << 11)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_TX_DMA_FIFO_FULL (1 << 10)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_RX_DMA_FIFO_FULL (1 << 9)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_TX_DMA_FIFO_FULL (1 << 8)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_RX_DMA_FIFO_EMPTY (1 << 7)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH3_TX_DMA_FIFO_EMPTY (1 << 6)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_RX_DMA_FIFO_EMPTY (1 << 5)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH2_TX_DMA_FIFO_EMPTY (1 << 4)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_RX_DMA_FIFO_EMPTY (1 << 3)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH1_TX_DMA_FIFO_EMPTY (1 << 2)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_RX_DMA_FIFO_EMPTY (1 << 1)
+#define TEGRA30_AHUB_APBDMA_LIVE_STATUS_CH0_TX_DMA_FIFO_EMPTY (1 << 0)
+
+/* TEGRA30_AHUB_I2S_LIVE_STATUS */
+
+#define TEGRA30_AHUB_I2S_LIVE_STATUS 0x8c
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_RX_FIFO_FULL (1 << 29)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_TX_FIFO_FULL (1 << 28)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_RX_FIFO_FULL (1 << 27)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_TX_FIFO_FULL (1 << 26)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_RX_FIFO_FULL (1 << 25)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_TX_FIFO_FULL (1 << 24)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_RX_FIFO_FULL (1 << 23)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_TX_FIFO_FULL (1 << 22)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_RX_FIFO_FULL (1 << 21)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_TX_FIFO_FULL (1 << 20)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_RX_FIFO_ENABLED (1 << 19)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_TX_FIFO_ENABLED (1 << 18)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_RX_FIFO_ENABLED (1 << 17)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_TX_FIFO_ENABLED (1 << 16)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_RX_FIFO_ENABLED (1 << 15)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_TX_FIFO_ENABLED (1 << 14)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_RX_FIFO_ENABLED (1 << 13)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_TX_FIFO_ENABLED (1 << 12)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_RX_FIFO_ENABLED (1 << 11)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_TX_FIFO_ENABLED (1 << 10)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_RX_FIFO_EMPTY (1 << 9)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S4_TX_FIFO_EMPTY (1 << 8)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_RX_FIFO_EMPTY (1 << 7)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S3_TX_FIFO_EMPTY (1 << 6)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_RX_FIFO_EMPTY (1 << 5)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S2_TX_FIFO_EMPTY (1 << 4)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_RX_FIFO_EMPTY (1 << 3)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S1_TX_FIFO_EMPTY (1 << 2)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_RX_FIFO_EMPTY (1 << 1)
+#define TEGRA30_AHUB_I2S_LIVE_STATUS_I2S0_TX_FIFO_EMPTY (1 << 0)
+
+/* TEGRA30_AHUB_DAM0_LIVE_STATUS */
+
+#define TEGRA30_AHUB_DAM_LIVE_STATUS 0x90
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_STRIDE 0x8
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_COUNT 3
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_TX_ENABLED (1 << 26)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX1_ENABLED (1 << 25)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX0_ENABLED (1 << 24)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_TXFIFO_FULL (1 << 15)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX1FIFO_FULL (1 << 9)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX0FIFO_FULL (1 << 8)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_TXFIFO_EMPTY (1 << 7)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX1FIFO_EMPTY (1 << 1)
+#define TEGRA30_AHUB_DAM_LIVE_STATUS_RX0FIFO_EMPTY (1 << 0)
+
+/* TEGRA30_AHUB_SPDIF_LIVE_STATUS */
+
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS 0xa8
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_TX_ENABLED (1 << 11)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_RX_ENABLED (1 << 10)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_TX_ENABLED (1 << 9)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_RX_ENABLED (1 << 8)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_TXFIFO_FULL (1 << 7)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_RXFIFO_FULL (1 << 6)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_TXFIFO_FULL (1 << 5)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_RXFIFO_FULL (1 << 4)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_TXFIFO_EMPTY (1 << 3)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_USER_RXFIFO_EMPTY (1 << 2)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_TXFIFO_EMPTY (1 << 1)
+#define TEGRA30_AHUB_SPDIF_LIVE_STATUS_DATA_RXFIFO_EMPTY (1 << 0)
+
+/* TEGRA30_AHUB_I2S_INT_MASK */
+
+#define TEGRA30_AHUB_I2S_INT_MASK 0xb0
+
+/* TEGRA30_AHUB_DAM_INT_MASK */
+
+#define TEGRA30_AHUB_DAM_INT_MASK 0xb4
+
+/* TEGRA30_AHUB_SPDIF_INT_MASK */
+
+#define TEGRA30_AHUB_SPDIF_INT_MASK 0xbc
+
+/* TEGRA30_AHUB_APBIF_INT_MASK */
+
+#define TEGRA30_AHUB_APBIF_INT_MASK 0xc0
+
+/* TEGRA30_AHUB_I2S_INT_STATUS */
+
+#define TEGRA30_AHUB_I2S_INT_STATUS 0xc8
+
+/* TEGRA30_AHUB_DAM_INT_STATUS */
+
+#define TEGRA30_AHUB_DAM_INT_STATUS 0xcc
+
+/* TEGRA30_AHUB_SPDIF_INT_STATUS */
+
+#define TEGRA30_AHUB_SPDIF_INT_STATUS 0xd4
+
+/* TEGRA30_AHUB_APBIF_INT_STATUS */
+
+#define TEGRA30_AHUB_APBIF_INT_STATUS 0xd8
+
+/* TEGRA30_AHUB_I2S_INT_SOURCE */
+
+#define TEGRA30_AHUB_I2S_INT_SOURCE 0xe0
+
+/* TEGRA30_AHUB_DAM_INT_SOURCE */
+
+#define TEGRA30_AHUB_DAM_INT_SOURCE 0xe4
+
+/* TEGRA30_AHUB_SPDIF_INT_SOURCE */
+
+#define TEGRA30_AHUB_SPDIF_INT_SOURCE 0xec
+
+/* TEGRA30_AHUB_APBIF_INT_SOURCE */
+
+#define TEGRA30_AHUB_APBIF_INT_SOURCE 0xf0
+
+/* TEGRA30_AHUB_I2S_INT_SET */
+
+#define TEGRA30_AHUB_I2S_INT_SET 0xf8
+
+/* TEGRA30_AHUB_DAM_INT_SET */
+
+#define TEGRA30_AHUB_DAM_INT_SET 0xfc
+
+/* TEGRA30_AHUB_SPDIF_INT_SET */
+
+#define TEGRA30_AHUB_SPDIF_INT_SET 0x100
+
+/* TEGRA30_AHUB_APBIF_INT_SET */
+
+#define TEGRA30_AHUB_APBIF_INT_SET 0x104
+
+/* Registers within TEGRA30_AHUB_BASE */
+
+#define TEGRA30_AHUB_AUDIO_RX 0x0
+#define TEGRA30_AHUB_AUDIO_RX_STRIDE 0x4
+#define TEGRA30_AHUB_AUDIO_RX_COUNT 17
+/* This register repeats once for each entry in enum tegra30_ahub_rxcif */
+/* The fields in this register are 1 bit per entry in tegra30_ahub_txcif */
+
+/*
+ * Terminology:
+ * AHUB: Audio Hub; a cross-bar switch between the audio devices: DMA FIFOs,
+ * I2S controllers, SPDIF controllers, and DAMs.
+ * XBAR: The core cross-bar component of the AHUB.
+ * CIF: Client Interface; the HW module connecting an audio device to the
+ * XBAR.
+ * DAM: Digital Audio Mixer: A HW module that mixes multiple audio streams,
+ * possibly including sample-rate conversion.
+ *
+ * Each TX CIF transmits data into the XBAR. Each RX CIF can receive audio
+ * transmitted by a particular TX CIF.
+ *
+ * This driver is currently very simplistic; many HW features are not
+ * exposed; DAMs are not supported, only 16-bit stereo audio is supported,
+ * etc.
+ */
+
+enum tegra30_ahub_txcif {
+ TEGRA30_AHUB_TXCIF_APBIF_TX0,
+ TEGRA30_AHUB_TXCIF_APBIF_TX1,
+ TEGRA30_AHUB_TXCIF_APBIF_TX2,
+ TEGRA30_AHUB_TXCIF_APBIF_TX3,
+ TEGRA30_AHUB_TXCIF_I2S0_TX0,
+ TEGRA30_AHUB_TXCIF_I2S1_TX0,
+ TEGRA30_AHUB_TXCIF_I2S2_TX0,
+ TEGRA30_AHUB_TXCIF_I2S3_TX0,
+ TEGRA30_AHUB_TXCIF_I2S4_TX0,
+ TEGRA30_AHUB_TXCIF_DAM0_TX0,
+ TEGRA30_AHUB_TXCIF_DAM1_TX0,
+ TEGRA30_AHUB_TXCIF_DAM2_TX0,
+ TEGRA30_AHUB_TXCIF_SPDIF_TX0,
+ TEGRA30_AHUB_TXCIF_SPDIF_TX1,
+};
+
+enum tegra30_ahub_rxcif {
+ TEGRA30_AHUB_RXCIF_APBIF_RX0,
+ TEGRA30_AHUB_RXCIF_APBIF_RX1,
+ TEGRA30_AHUB_RXcIF_APBIF_RX2,
+ TEGRA30_AHUB_RXCIF_APBIF_RX3,
+ TEGRA30_AHUB_RXCIF_I2S0_RX0,
+ TEGRA30_AHUB_RXCIF_I2S1_RX0,
+ TEGRA30_AHUB_RXCIF_I2S2_RX0,
+ TEGRA30_AHUB_RXCIF_I2S3_RX0,
+ TEGRA30_AHUB_RXCIF_I2S4_RX0,
+ TEGRA30_AHUB_RXCIF_DAM0_RX0,
+ TEGRA30_AHUB_RXCIF_DAM0_RX1,
+ TEGRA30_AHUB_RXCIF_DAM1_RX0,
+ TEGRA30_AHUB_RXCIF_DAM2_RX1,
+ TEGRA30_AHUB_RXCIF_DAM3_RX0,
+ TEGRA30_AHUB_RXCIF_DAM3_RX1,
+ TEGRA30_AHUB_RXCIF_SPDIF_RX0,
+ TEGRA30_AHUB_RXCIF_SPDIF_RX1,
+};
+
+extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
+ unsigned long *fiforeg,
+ unsigned long *reqsel);
+extern int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif);
+extern int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif);
+extern int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif);
+
+extern int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
+ unsigned long *fiforeg,
+ unsigned long *reqsel);
+extern int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif);
+extern int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif);
+extern int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif);
+
+extern int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif,
+ enum tegra30_ahub_txcif txcif);
+extern int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif);
+
+struct tegra30_ahub {
+ struct device *dev;
+ struct clk *clk_d_audio;
+ struct clk *clk_apbif;
+ int dma_sel;
+ resource_size_t apbif_addr;
+ struct regmap *regmap_apbif;
+ struct regmap *regmap_ahub;
+ DECLARE_BITMAP(rx_usage, TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
+ DECLARE_BITMAP(tx_usage, TEGRA30_AHUB_CHANNEL_CTRL_COUNT);
+};
+
+#endif
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
new file mode 100644
index 000000000000..8596032985dc
--- /dev/null
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -0,0 +1,536 @@
+/*
+ * tegra30_i2s.c - Tegra30 I2S driver
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (c) 2010-2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Based on code copyright/by:
+ *
+ * Copyright (c) 2009-2010, NVIDIA Corporation.
+ * Scott Peterson <speterson@nvidia.com>
+ *
+ * Copyright (C) 2010 Google, Inc.
+ * Iliyan Malchev <malchev@google.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "tegra30_ahub.h"
+#include "tegra30_i2s.h"
+
+#define DRV_NAME "tegra30-i2s"
+
+static inline void tegra30_i2s_write(struct tegra30_i2s *i2s, u32 reg, u32 val)
+{
+ regmap_write(i2s->regmap, reg, val);
+}
+
+static inline u32 tegra30_i2s_read(struct tegra30_i2s *i2s, u32 reg)
+{
+ u32 val;
+ regmap_read(i2s->regmap, reg, &val);
+ return val;
+}
+
+static int tegra30_i2s_runtime_suspend(struct device *dev)
+{
+ struct tegra30_i2s *i2s = dev_get_drvdata(dev);
+
+ regcache_cache_only(i2s->regmap, true);
+
+ clk_disable(i2s->clk_i2s);
+
+ return 0;
+}
+
+static int tegra30_i2s_runtime_resume(struct device *dev)
+{
+ struct tegra30_i2s *i2s = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_enable(i2s->clk_i2s);
+ if (ret) {
+ dev_err(dev, "clk_enable failed: %d\n", ret);
+ return ret;
+ }
+
+ regcache_cache_only(i2s->regmap, false);
+
+ return 0;
+}
+
+int tegra30_i2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+ int ret;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = tegra30_ahub_allocate_tx_fifo(&i2s->playback_fifo_cif,
+ &i2s->playback_dma_data.addr,
+ &i2s->playback_dma_data.req_sel);
+ i2s->playback_dma_data.wrap = 4;
+ i2s->playback_dma_data.width = 32;
+ tegra30_ahub_set_rx_cif_source(i2s->playback_i2s_cif,
+ i2s->playback_fifo_cif);
+ } else {
+ ret = tegra30_ahub_allocate_rx_fifo(&i2s->capture_fifo_cif,
+ &i2s->capture_dma_data.addr,
+ &i2s->capture_dma_data.req_sel);
+ i2s->capture_dma_data.wrap = 4;
+ i2s->capture_dma_data.width = 32;
+ tegra30_ahub_set_rx_cif_source(i2s->capture_fifo_cif,
+ i2s->capture_i2s_cif);
+ }
+
+ return ret;
+}
+
+void tegra30_i2s_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ tegra30_ahub_unset_rx_cif_source(i2s->playback_i2s_cif);
+ tegra30_ahub_free_tx_fifo(i2s->playback_fifo_cif);
+ } else {
+ tegra30_ahub_unset_rx_cif_source(i2s->capture_fifo_cif);
+ tegra30_ahub_free_rx_fifo(i2s->capture_fifo_cif);
+ }
+}
+
+static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai,
+ unsigned int fmt)
+{
+ struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_MASTER_ENABLE;
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ i2s->reg_ctrl |= TEGRA30_I2S_CTRL_MASTER_ENABLE;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ i2s->reg_ctrl &= ~(TEGRA30_I2S_CTRL_FRAME_FORMAT_MASK |
+ TEGRA30_I2S_CTRL_LRCK_MASK);
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_DSP_A:
+ i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC;
+ i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC;
+ i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_R_LOW;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
+ i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
+ i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK;
+ i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct device *dev = substream->pcm->card->dev;
+ struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+ u32 val;
+ int ret, sample_size, srate, i2sclock, bitcnt;
+
+ if (params_channels(params) != 2)
+ return -EINVAL;
+
+ i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_BIT_SIZE_MASK;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_16;
+ sample_size = 16;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ srate = params_rate(params);
+
+ /* Final "* 2" required by Tegra hardware */
+ i2sclock = srate * params_channels(params) * sample_size * 2;
+
+ bitcnt = (i2sclock / (2 * srate)) - 1;
+ if (bitcnt < 0 || bitcnt > TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US)
+ return -EINVAL;
+
+ ret = clk_set_rate(i2s->clk_i2s, i2sclock);
+ if (ret) {
+ dev_err(dev, "Can't set I2S clock rate: %d\n", ret);
+ return ret;
+ }
+
+ val = bitcnt << TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
+
+ if (i2sclock % (2 * srate))
+ val |= TEGRA30_I2S_TIMING_NON_SYM_ENABLE;
+
+ tegra30_i2s_write(i2s, TEGRA30_I2S_TIMING, val);
+
+ val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) |
+ (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) |
+ (1 << TEGRA30_AUDIOCIF_CTRL_CLIENT_CHANNELS_SHIFT) |
+ TEGRA30_AUDIOCIF_CTRL_AUDIO_BITS_16 |
+ TEGRA30_AUDIOCIF_CTRL_CLIENT_BITS_16;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX;
+ tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_RX_CTRL, val);
+ } else {
+ val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX;
+ tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_TX_CTRL, val);
+ }
+
+ val = (1 << TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) |
+ (1 << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT);
+ tegra30_i2s_write(i2s, TEGRA30_I2S_OFFSET, val);
+
+ return 0;
+}
+
+static void tegra30_i2s_start_playback(struct tegra30_i2s *i2s)
+{
+ tegra30_ahub_enable_tx_fifo(i2s->playback_fifo_cif);
+ i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_TX;
+ tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra30_i2s_stop_playback(struct tegra30_i2s *i2s)
+{
+ tegra30_ahub_disable_tx_fifo(i2s->playback_fifo_cif);
+ i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX;
+ tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s)
+{
+ tegra30_ahub_enable_rx_fifo(i2s->capture_fifo_cif);
+ i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_RX;
+ tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static void tegra30_i2s_stop_capture(struct tegra30_i2s *i2s)
+{
+ tegra30_ahub_disable_rx_fifo(i2s->capture_fifo_cif);
+ i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX;
+ tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl);
+}
+
+static int tegra30_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ tegra30_i2s_start_playback(i2s);
+ else
+ tegra30_i2s_start_capture(i2s);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ tegra30_i2s_stop_playback(i2s);
+ else
+ tegra30_i2s_stop_capture(i2s);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int tegra30_i2s_probe(struct snd_soc_dai *dai)
+{
+ struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai);
+
+ dai->capture_dma_data = &i2s->capture_dma_data;
+ dai->playback_dma_data = &i2s->playback_dma_data;
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops tegra30_i2s_dai_ops = {
+ .startup = tegra30_i2s_startup,
+ .shutdown = tegra30_i2s_shutdown,
+ .set_fmt = tegra30_i2s_set_fmt,
+ .hw_params = tegra30_i2s_hw_params,
+ .trigger = tegra30_i2s_trigger,
+};
+
+static const struct snd_soc_dai_driver tegra30_i2s_dai_template = {
+ .probe = tegra30_i2s_probe,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &tegra30_i2s_dai_ops,
+ .symmetric_rates = 1,
+};
+
+static bool tegra30_i2s_wr_rd_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TEGRA30_I2S_CTRL:
+ case TEGRA30_I2S_TIMING:
+ case TEGRA30_I2S_OFFSET:
+ case TEGRA30_I2S_CH_CTRL:
+ case TEGRA30_I2S_SLOT_CTRL:
+ case TEGRA30_I2S_CIF_RX_CTRL:
+ case TEGRA30_I2S_CIF_TX_CTRL:
+ case TEGRA30_I2S_FLOWCTL:
+ case TEGRA30_I2S_TX_STEP:
+ case TEGRA30_I2S_FLOW_STATUS:
+ case TEGRA30_I2S_FLOW_TOTAL:
+ case TEGRA30_I2S_FLOW_OVER:
+ case TEGRA30_I2S_FLOW_UNDER:
+ case TEGRA30_I2S_LCOEF_1_4_0:
+ case TEGRA30_I2S_LCOEF_1_4_1:
+ case TEGRA30_I2S_LCOEF_1_4_2:
+ case TEGRA30_I2S_LCOEF_1_4_3:
+ case TEGRA30_I2S_LCOEF_1_4_4:
+ case TEGRA30_I2S_LCOEF_1_4_5:
+ case TEGRA30_I2S_LCOEF_2_4_0:
+ case TEGRA30_I2S_LCOEF_2_4_1:
+ case TEGRA30_I2S_LCOEF_2_4_2:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static bool tegra30_i2s_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TEGRA30_I2S_FLOW_STATUS:
+ case TEGRA30_I2S_FLOW_TOTAL:
+ case TEGRA30_I2S_FLOW_OVER:
+ case TEGRA30_I2S_FLOW_UNDER:
+ return true;
+ default:
+ return false;
+ };
+}
+
+static const struct regmap_config tegra30_i2s_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = TEGRA30_I2S_LCOEF_2_4_2,
+ .writeable_reg = tegra30_i2s_wr_rd_reg,
+ .readable_reg = tegra30_i2s_wr_rd_reg,
+ .volatile_reg = tegra30_i2s_volatile_reg,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static __devinit int tegra30_i2s_platform_probe(struct platform_device *pdev)
+{
+ struct tegra30_i2s *i2s;
+ u32 cif_ids[2];
+ struct resource *mem, *memregion;
+ void __iomem *regs;
+ int ret;
+
+ i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_i2s), GFP_KERNEL);
+ if (!i2s) {
+ dev_err(&pdev->dev, "Can't allocate tegra30_i2s\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ dev_set_drvdata(&pdev->dev, i2s);
+
+ i2s->dai = tegra30_i2s_dai_template;
+ i2s->dai.name = dev_name(&pdev->dev);
+
+ ret = of_property_read_u32_array(pdev->dev.of_node,
+ "nvidia,ahub-cif-ids", cif_ids,
+ ARRAY_SIZE(cif_ids));
+ if (ret < 0)
+ goto err;
+
+ i2s->playback_i2s_cif = cif_ids[0];
+ i2s->capture_i2s_cif = cif_ids[1];
+
+ i2s->clk_i2s = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(i2s->clk_i2s)) {
+ dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
+ ret = PTR_ERR(i2s->clk_i2s);
+ goto err;
+ }
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "No memory resource\n");
+ ret = -ENODEV;
+ goto err_clk_put;
+ }
+
+ memregion = devm_request_mem_region(&pdev->dev, mem->start,
+ resource_size(mem), DRV_NAME);
+ if (!memregion) {
+ dev_err(&pdev->dev, "Memory region already claimed\n");
+ ret = -EBUSY;
+ goto err_clk_put;
+ }
+
+ regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
+ if (!regs) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto err_clk_put;
+ }
+
+ i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
+ &tegra30_i2s_regmap_config);
+ if (IS_ERR(i2s->regmap)) {
+ dev_err(&pdev->dev, "regmap init failed\n");
+ ret = PTR_ERR(i2s->regmap);
+ goto err_clk_put;
+ }
+ regcache_cache_only(i2s->regmap, true);
+
+ pm_runtime_enable(&pdev->dev);
+ if (!pm_runtime_enabled(&pdev->dev)) {
+ ret = tegra30_i2s_runtime_resume(&pdev->dev);
+ if (ret)
+ goto err_pm_disable;
+ }
+
+ ret = snd_soc_register_dai(&pdev->dev, &i2s->dai);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
+ ret = -ENOMEM;
+ goto err_suspend;
+ }
+
+ ret = tegra_pcm_platform_register(&pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
+ goto err_unregister_dai;
+ }
+
+ return 0;
+
+err_unregister_dai:
+ snd_soc_unregister_dai(&pdev->dev);
+err_suspend:
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ tegra30_i2s_runtime_suspend(&pdev->dev);
+err_pm_disable:
+ pm_runtime_disable(&pdev->dev);
+err_clk_put:
+ clk_put(i2s->clk_i2s);
+err:
+ return ret;
+}
+
+static int __devexit tegra30_i2s_platform_remove(struct platform_device *pdev)
+{
+ struct tegra30_i2s *i2s = dev_get_drvdata(&pdev->dev);
+
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ tegra30_i2s_runtime_suspend(&pdev->dev);
+
+ tegra_pcm_platform_unregister(&pdev->dev);
+ snd_soc_unregister_dai(&pdev->dev);
+
+ clk_put(i2s->clk_i2s);
+
+ return 0;
+}
+
+static const struct of_device_id tegra30_i2s_of_match[] __devinitconst = {
+ { .compatible = "nvidia,tegra30-i2s", },
+ {},
+};
+
+static const struct dev_pm_ops tegra30_i2s_pm_ops __devinitconst = {
+ SET_RUNTIME_PM_OPS(tegra30_i2s_runtime_suspend,
+ tegra30_i2s_runtime_resume, NULL)
+};
+
+static struct platform_driver tegra30_i2s_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = tegra30_i2s_of_match,
+ .pm = &tegra30_i2s_pm_ops,
+ },
+ .probe = tegra30_i2s_platform_probe,
+ .remove = __devexit_p(tegra30_i2s_platform_remove),
+};
+module_platform_driver(tegra30_i2s_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra30 I2S ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra30_i2s_of_match);
diff --git a/sound/soc/tegra/tegra30_i2s.h b/sound/soc/tegra/tegra30_i2s.h
new file mode 100644
index 000000000000..91adf29c7a87
--- /dev/null
+++ b/sound/soc/tegra/tegra30_i2s.h
@@ -0,0 +1,242 @@
+/*
+ * tegra30_i2s.h - Definitions for Tegra30 I2S driver
+ *
+ * Copyright (c) 2011,2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __TEGRA30_I2S_H__
+#define __TEGRA30_I2S_H__
+
+#include "tegra_pcm.h"
+
+/* Register offsets from TEGRA30_I2S*_BASE */
+
+#define TEGRA30_I2S_CTRL 0x0
+#define TEGRA30_I2S_TIMING 0x4
+#define TEGRA30_I2S_OFFSET 0x08
+#define TEGRA30_I2S_CH_CTRL 0x0c
+#define TEGRA30_I2S_SLOT_CTRL 0x10
+#define TEGRA30_I2S_CIF_RX_CTRL 0x14
+#define TEGRA30_I2S_CIF_TX_CTRL 0x18
+#define TEGRA30_I2S_FLOWCTL 0x1c
+#define TEGRA30_I2S_TX_STEP 0x20
+#define TEGRA30_I2S_FLOW_STATUS 0x24
+#define TEGRA30_I2S_FLOW_TOTAL 0x28
+#define TEGRA30_I2S_FLOW_OVER 0x2c
+#define TEGRA30_I2S_FLOW_UNDER 0x30
+#define TEGRA30_I2S_LCOEF_1_4_0 0x34
+#define TEGRA30_I2S_LCOEF_1_4_1 0x38
+#define TEGRA30_I2S_LCOEF_1_4_2 0x3c
+#define TEGRA30_I2S_LCOEF_1_4_3 0x40
+#define TEGRA30_I2S_LCOEF_1_4_4 0x44
+#define TEGRA30_I2S_LCOEF_1_4_5 0x48
+#define TEGRA30_I2S_LCOEF_2_4_0 0x4c
+#define TEGRA30_I2S_LCOEF_2_4_1 0x50
+#define TEGRA30_I2S_LCOEF_2_4_2 0x54
+
+/* Fields in TEGRA30_I2S_CTRL */
+
+#define TEGRA30_I2S_CTRL_XFER_EN_TX (1 << 31)
+#define TEGRA30_I2S_CTRL_XFER_EN_RX (1 << 30)
+#define TEGRA30_I2S_CTRL_CG_EN (1 << 29)
+#define TEGRA30_I2S_CTRL_SOFT_RESET (1 << 28)
+#define TEGRA30_I2S_CTRL_TX_FLOWCTL_EN (1 << 27)
+
+#define TEGRA30_I2S_CTRL_OBS_SEL_SHIFT 24
+#define TEGRA30_I2S_CTRL_OBS_SEL_MASK (7 << TEGRA30_I2S_CTRL_OBS_SEL_SHIFT)
+
+#define TEGRA30_I2S_FRAME_FORMAT_LRCK 0
+#define TEGRA30_I2S_FRAME_FORMAT_FSYNC 1
+
+#define TEGRA30_I2S_CTRL_FRAME_FORMAT_SHIFT 12
+#define TEGRA30_I2S_CTRL_FRAME_FORMAT_MASK (7 << TEGRA30_I2S_CTRL_FRAME_FORMAT_SHIFT)
+#define TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK (TEGRA30_I2S_FRAME_FORMAT_LRCK << TEGRA30_I2S_CTRL_FRAME_FORMAT_SHIFT)
+#define TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC (TEGRA30_I2S_FRAME_FORMAT_FSYNC << TEGRA30_I2S_CTRL_FRAME_FORMAT_SHIFT)
+
+#define TEGRA30_I2S_CTRL_MASTER_ENABLE (1 << 10)
+
+#define TEGRA30_I2S_LRCK_LEFT_LOW 0
+#define TEGRA30_I2S_LRCK_RIGHT_LOW 1
+
+#define TEGRA30_I2S_CTRL_LRCK_SHIFT 9
+#define TEGRA30_I2S_CTRL_LRCK_MASK (1 << TEGRA30_I2S_CTRL_LRCK_SHIFT)
+#define TEGRA30_I2S_CTRL_LRCK_L_LOW (TEGRA30_I2S_LRCK_LEFT_LOW << TEGRA30_I2S_CTRL_LRCK_SHIFT)
+#define TEGRA30_I2S_CTRL_LRCK_R_LOW (TEGRA30_I2S_LRCK_RIGHT_LOW << TEGRA30_I2S_CTRL_LRCK_SHIFT)
+
+#define TEGRA30_I2S_CTRL_LPBK_ENABLE (1 << 8)
+
+#define TEGRA30_I2S_BIT_CODE_LINEAR 0
+#define TEGRA30_I2S_BIT_CODE_ULAW 1
+#define TEGRA30_I2S_BIT_CODE_ALAW 2
+
+#define TEGRA30_I2S_CTRL_BIT_CODE_SHIFT 4
+#define TEGRA30_I2S_CTRL_BIT_CODE_MASK (3 << TEGRA30_I2S_CTRL_BIT_CODE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_CODE_LINEAR (TEGRA30_I2S_BIT_CODE_LINEAR << TEGRA30_I2S_CTRL_BIT_CODE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_CODE_ULAW (TEGRA30_I2S_BIT_CODE_ULAW << TEGRA30_I2S_CTRL_BIT_CODE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_CODE_ALAW (TEGRA30_I2S_BIT_CODE_ALAW << TEGRA30_I2S_CTRL_BIT_CODE_SHIFT)
+
+#define TEGRA30_I2S_BITS_8 1
+#define TEGRA30_I2S_BITS_12 2
+#define TEGRA30_I2S_BITS_16 3
+#define TEGRA30_I2S_BITS_20 4
+#define TEGRA30_I2S_BITS_24 5
+#define TEGRA30_I2S_BITS_28 6
+#define TEGRA30_I2S_BITS_32 7
+
+/* Sample container size; see {RX,TX}_MASK field in CH_CTRL below */
+#define TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT 0
+#define TEGRA30_I2S_CTRL_BIT_SIZE_MASK (7 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_SIZE_8 (TEGRA30_I2S_BITS_8 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_SIZE_12 (TEGRA30_I2S_BITS_12 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_SIZE_16 (TEGRA30_I2S_BITS_16 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_SIZE_20 (TEGRA30_I2S_BITS_20 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_SIZE_24 (TEGRA30_I2S_BITS_24 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_SIZE_28 (TEGRA30_I2S_BITS_28 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+#define TEGRA30_I2S_CTRL_BIT_SIZE_32 (TEGRA30_I2S_BITS_32 << TEGRA30_I2S_CTRL_BIT_SIZE_SHIFT)
+
+/* Fields in TEGRA30_I2S_TIMING */
+
+#define TEGRA30_I2S_TIMING_NON_SYM_ENABLE (1 << 12)
+#define TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT 0
+#define TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US 0x7fff
+#define TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_MASK (TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US << TEGRA30_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT)
+
+/* Fields in TEGRA30_I2S_OFFSET */
+
+#define TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT 16
+#define TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_MASK_US 0x7ff
+#define TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_MASK (TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_MASK_US << TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT)
+#define TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT 0
+#define TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_MASK_US 0x7ff
+#define TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_MASK (TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_MASK_US << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT)
+
+/* Fields in TEGRA30_I2S_CH_CTRL */
+
+/* (FSYNC width - 1) in bit clocks */
+#define TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_SHIFT 24
+#define TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_MASK_US 0xff
+#define TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_MASK (TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_MASK_US << TEGRA30_I2S_CH_CTRL_FSYNC_WIDTH_SHIFT)
+
+#define TEGRA30_I2S_HIGHZ_NO 0
+#define TEGRA30_I2S_HIGHZ_YES 1
+#define TEGRA30_I2S_HIGHZ_ON_HALF_BIT_CLK 2
+
+#define TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_SHIFT 12
+#define TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_MASK (3 << TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_NO (TEGRA30_I2S_HIGHZ_NO << TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_YES (TEGRA30_I2S_HIGHZ_YES << TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_ON_HALF_BIT_CLK (TEGRA30_I2S_HIGHZ_ON_HALF_BIT_CLK << TEGRA30_I2S_CH_CTRL_HIGHZ_CTRL_SHIFT)
+
+#define TEGRA30_I2S_MSB_FIRST 0
+#define TEGRA30_I2S_LSB_FIRST 1
+
+#define TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_SHIFT 10
+#define TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_MASK (1 << TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_MSB_FIRST (TEGRA30_I2S_MSB_FIRST << TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_LSB_FIRST (TEGRA30_I2S_LSB_FIRST << TEGRA30_I2S_CH_CTRL_RX_BIT_ORDER_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_SHIFT 9
+#define TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_MASK (1 << TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_MSB_FIRST (TEGRA30_I2S_MSB_FIRST << TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_LSB_FIRST (TEGRA30_I2S_LSB_FIRST << TEGRA30_I2S_CH_CTRL_TX_BIT_ORDER_SHIFT)
+
+#define TEGRA30_I2S_POS_EDGE 0
+#define TEGRA30_I2S_NEG_EDGE 1
+
+#define TEGRA30_I2S_CH_CTRL_EGDE_CTRL_SHIFT 8
+#define TEGRA30_I2S_CH_CTRL_EGDE_CTRL_MASK (1 << TEGRA30_I2S_CH_CTRL_EGDE_CTRL_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_EGDE_CTRL_POS_EDGE (TEGRA30_I2S_POS_EDGE << TEGRA30_I2S_CH_CTRL_EGDE_CTRL_SHIFT)
+#define TEGRA30_I2S_CH_CTRL_EGDE_CTRL_NEG_EDGE (TEGRA30_I2S_NEG_EDGE << TEGRA30_I2S_CH_CTRL_EGDE_CTRL_SHIFT)
+
+/* Sample size is # bits from BIT_SIZE minus this field */
+#define TEGRA30_I2S_CH_CTRL_RX_MASK_BITS_SHIFT 4
+#define TEGRA30_I2S_CH_CTRL_RX_MASK_BITS_MASK_US 7
+#define TEGRA30_I2S_CH_CTRL_RX_MASK_BITS_MASK (TEGRA30_I2S_CH_CTRL_RX_MASK_BITS_MASK_US << TEGRA30_I2S_CH_CTRL_RX_MASK_BITS_SHIFT)
+
+#define TEGRA30_I2S_CH_CTRL_TX_MASK_BITS_SHIFT 0
+#define TEGRA30_I2S_CH_CTRL_TX_MASK_BITS_MASK_US 7
+#define TEGRA30_I2S_CH_CTRL_TX_MASK_BITS_MASK (TEGRA30_I2S_CH_CTRL_TX_MASK_BITS_MASK_US << TEGRA30_I2S_CH_CTRL_TX_MASK_BITS_SHIFT)
+
+/* Fields in TEGRA30_I2S_SLOT_CTRL */
+
+/* Number of slots in frame, minus 1 */
+#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_SHIFT 16
+#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK_US 7
+#define TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOTS_MASK (TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOT_MASK_US << TEGRA30_I2S_SLOT_CTRL_TOTAL_SLOT_SHIFT)
+
+/* TDM mode slot enable bitmask */
+#define TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT 8
+#define TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_MASK (0xff << TEGRA30_I2S_SLOT_CTRL_RX_SLOT_ENABLES_SHIFT)
+
+#define TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT 0
+#define TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_MASK (0xff << TEGRA30_I2S_SLOT_CTRL_TX_SLOT_ENABLES_SHIFT)
+
+/* Fields in TEGRA30_I2S_CIF_RX_CTRL */
+/* Uses field from TEGRA30_AUDIOCIF_CTRL_* in tegra30_ahub.h */
+
+/* Fields in TEGRA30_I2S_CIF_TX_CTRL */
+/* Uses field from TEGRA30_AUDIOCIF_CTRL_* in tegra30_ahub.h */
+
+/* Fields in TEGRA30_I2S_FLOWCTL */
+
+#define TEGRA30_I2S_FILTER_LINEAR 0
+#define TEGRA30_I2S_FILTER_QUAD 1
+
+#define TEGRA30_I2S_FLOWCTL_FILTER_SHIFT 31
+#define TEGRA30_I2S_FLOWCTL_FILTER_MASK (1 << TEGRA30_I2S_FLOWCTL_FILTER_SHIFT)
+#define TEGRA30_I2S_FLOWCTL_FILTER_LINEAR (TEGRA30_I2S_FILTER_LINEAR << TEGRA30_I2S_FLOWCTL_FILTER_SHIFT)
+#define TEGRA30_I2S_FLOWCTL_FILTER_QUAD (TEGRA30_I2S_FILTER_QUAD << TEGRA30_I2S_FLOWCTL_FILTER_SHIFT)
+
+/* Fields in TEGRA30_I2S_TX_STEP */
+
+#define TEGRA30_I2S_TX_STEP_SHIFT 0
+#define TEGRA30_I2S_TX_STEP_MASK_US 0xffff
+#define TEGRA30_I2S_TX_STEP_MASK (TEGRA30_I2S_TX_STEP_MASK_US << TEGRA30_I2S_TX_STEP_SHIFT)
+
+/* Fields in TEGRA30_I2S_FLOW_STATUS */
+
+#define TEGRA30_I2S_FLOW_STATUS_UNDERFLOW (1 << 31)
+#define TEGRA30_I2S_FLOW_STATUS_OVERFLOW (1 << 30)
+#define TEGRA30_I2S_FLOW_STATUS_MONITOR_INT_EN (1 << 4)
+#define TEGRA30_I2S_FLOW_STATUS_COUNTER_CLR (1 << 3)
+#define TEGRA30_I2S_FLOW_STATUS_MONITOR_CLR (1 << 2)
+#define TEGRA30_I2S_FLOW_STATUS_COUNTER_EN (1 << 1)
+#define TEGRA30_I2S_FLOW_STATUS_MONITOR_EN (1 << 0)
+
+/*
+ * There are no fields in TEGRA30_I2S_FLOW_TOTAL, TEGRA30_I2S_FLOW_OVER,
+ * TEGRA30_I2S_FLOW_UNDER; they are counters taking the whole register.
+ */
+
+/* Fields in TEGRA30_I2S_LCOEF_* */
+
+#define TEGRA30_I2S_LCOEF_COEF_SHIFT 0
+#define TEGRA30_I2S_LCOEF_COEF_MASK_US 0xffff
+#define TEGRA30_I2S_LCOEF_COEF_MASK (TEGRA30_I2S_LCOEF_COEF_MASK_US << TEGRA30_I2S_LCOEF_COEF_SHIFT)
+
+struct tegra30_i2s {
+ struct snd_soc_dai_driver dai;
+ int cif_id;
+ struct clk *clk_i2s;
+ enum tegra30_ahub_txcif capture_i2s_cif;
+ enum tegra30_ahub_rxcif capture_fifo_cif;
+ struct tegra_pcm_dma_params capture_dma_data;
+ enum tegra30_ahub_rxcif playback_i2s_cif;
+ enum tegra30_ahub_txcif playback_fifo_cif;
+ struct tegra_pcm_dma_params playback_dma_data;
+ struct regmap *regmap;
+ u32 reg_ctrl;
+};
+
+#endif
diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c
index e45ccd851f6a..32de7006daf0 100644
--- a/sound/soc/tegra/tegra_alc5632.c
+++ b/sound/soc/tegra/tegra_alc5632.c
@@ -1,16 +1,17 @@
/*
-* tegra_alc5632.c -- Toshiba AC100(PAZ00) machine ASoC driver
-*
-* Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
-*
-* Authors: Leon Romanovsky <leon@leon.nu>
-* Andrey Danin <danindrey@mail.ru>
-* Marc Dietrich <marvin24@gmx.de>
-*
-* 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.
-*/
+ * tegra_alc5632.c -- Toshiba AC100(PAZ00) machine ASoC driver
+ *
+ * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
+ * Copyright (C) 2012 - NVIDIA, Inc.
+ *
+ * Authors: Leon Romanovsky <leon@leon.nu>
+ * Andrey Danin <danindrey@mail.ru>
+ * Marc Dietrich <marvin24@gmx.de>
+ *
+ * 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 <asm/mach-types.h>
@@ -28,9 +29,6 @@
#include "../codecs/alc5632.h"
-#include "tegra_das.h"
-#include "tegra_i2s.h"
-#include "tegra_pcm.h"
#include "tegra_asoc_utils.h"
#define DRV_NAME "tegra-alc5632"
@@ -39,7 +37,6 @@
struct tegra_alc5632 {
struct tegra_asoc_utils_data util_data;
- struct platform_device *pcm_dev;
int gpio_requested;
int gpio_hp_det;
};
@@ -140,7 +137,6 @@ static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd)
static struct snd_soc_dai_link tegra_alc5632_dai = {
.name = "ALC5632",
.stream_name = "ALC5632 PCM",
- .platform_name = "tegra-pcm-audio",
.codec_dai_name = "alc5632-hifi",
.init = tegra_alc5632_asoc_init,
.ops = &tegra_alc5632_asoc_ops,
@@ -179,8 +175,6 @@ static __devinit int tegra_alc5632_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, alc5632);
- alc5632->pcm_dev = ERR_PTR(-EINVAL);
-
if (!(pdev->dev.of_node)) {
dev_err(&pdev->dev, "Must be instantiated using device tree\n");
ret = -EINVAL;
@@ -214,18 +208,11 @@ static __devinit int tegra_alc5632_probe(struct platform_device *pdev)
goto err;
}
- alc5632->pcm_dev = platform_device_register_simple(
- "tegra-pcm-audio", -1, NULL, 0);
- if (IS_ERR(alc5632->pcm_dev)) {
- dev_err(&pdev->dev,
- "Can't instantiate tegra-pcm-audio\n");
- ret = PTR_ERR(alc5632->pcm_dev);
- goto err;
- }
+ tegra_alc5632_dai.platform_of_node = tegra_alc5632_dai.cpu_dai_of_node;
ret = tegra_asoc_utils_init(&alc5632->util_data, &pdev->dev);
if (ret)
- goto err_unregister;
+ goto err;
ret = snd_soc_register_card(card);
if (ret) {
@@ -238,9 +225,6 @@ static __devinit int tegra_alc5632_probe(struct platform_device *pdev)
err_fini_utils:
tegra_asoc_utils_fini(&alc5632->util_data);
-err_unregister:
- if (!IS_ERR(alc5632->pcm_dev))
- platform_device_unregister(alc5632->pcm_dev);
err:
return ret;
}
@@ -259,8 +243,6 @@ static int __devexit tegra_alc5632_remove(struct platform_device *pdev)
snd_soc_unregister_card(card);
tegra_asoc_utils_fini(&machine->util_data);
- if (!IS_ERR(machine->pcm_dev))
- platform_device_unregister(machine->pcm_dev);
return 0;
}
diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c
index f8428e410e05..9515ce58ea02 100644
--- a/sound/soc/tegra/tegra_asoc_utils.c
+++ b/sound/soc/tegra/tegra_asoc_utils.c
@@ -2,7 +2,7 @@
* tegra_asoc_utils.c - Harmony machine ASoC driver
*
* Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -25,6 +25,7 @@
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/of.h>
#include "tegra_asoc_utils.h"
@@ -40,7 +41,10 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
case 22050:
case 44100:
case 88200:
- new_baseclock = 56448000;
+ if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
+ new_baseclock = 56448000;
+ else
+ new_baseclock = 564480000;
break;
case 8000:
case 16000:
@@ -48,7 +52,10 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
case 48000:
case 64000:
case 96000:
- new_baseclock = 73728000;
+ if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
+ new_baseclock = 73728000;
+ else
+ new_baseclock = 552960000;
break;
default:
return -EINVAL;
@@ -78,7 +85,7 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
return err;
}
- /* Don't set cdev1 rate; its locked to pll_a_out0 */
+ /* Don't set cdev1/extern1 rate; it's locked to pll_a_out0 */
err = clk_enable(data->clk_pll_a);
if (err) {
@@ -112,6 +119,17 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
data->dev = dev;
+ if (of_machine_is_compatible("nvidia,tegra20"))
+ data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA20;
+ else if (of_machine_is_compatible("nvidia,tegra30"))
+ data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA30;
+ else if (!dev->of_node)
+ /* non-DT is always Tegra20 */
+ data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA20;
+ else
+ /* DT boot, but unknown SoC */
+ return -EINVAL;
+
data->clk_pll_a = clk_get_sys(NULL, "pll_a");
if (IS_ERR(data->clk_pll_a)) {
dev_err(data->dev, "Can't retrieve clk pll_a\n");
@@ -126,15 +144,24 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
goto err_put_pll_a;
}
- data->clk_cdev1 = clk_get_sys(NULL, "cdev1");
+ if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
+ data->clk_cdev1 = clk_get_sys(NULL, "cdev1");
+ else
+ data->clk_cdev1 = clk_get_sys("extern1", NULL);
if (IS_ERR(data->clk_cdev1)) {
dev_err(data->dev, "Can't retrieve clk cdev1\n");
ret = PTR_ERR(data->clk_cdev1);
goto err_put_pll_a_out0;
}
+ ret = tegra_asoc_utils_set_rate(data, 44100, 256 * 44100);
+ if (ret)
+ goto err_put_cdev1;
+
return 0;
+err_put_cdev1:
+ clk_put(data->clk_cdev1);
err_put_pll_a_out0:
clk_put(data->clk_pll_a_out0);
err_put_pll_a:
diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h
index 4818195da25c..44db1dbb8f21 100644
--- a/sound/soc/tegra/tegra_asoc_utils.h
+++ b/sound/soc/tegra/tegra_asoc_utils.h
@@ -2,7 +2,7 @@
* tegra_asoc_utils.h - Definitions for Tegra DAS driver
*
* Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -26,8 +26,14 @@
struct clk;
struct device;
+enum tegra_asoc_utils_soc {
+ TEGRA_ASOC_UTILS_SOC_TEGRA20,
+ TEGRA_ASOC_UTILS_SOC_TEGRA30,
+};
+
struct tegra_asoc_utils_data {
struct device *dev;
+ enum tegra_asoc_utils_soc soc;
struct clk *clk_pll_a;
struct clk *clk_pll_a_out0;
struct clk *clk_cdev1;
@@ -42,4 +48,3 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data);
#endif
-
diff --git a/sound/soc/tegra/tegra_das.c b/sound/soc/tegra/tegra_das.c
deleted file mode 100644
index 3b3c1ba4d235..000000000000
--- a/sound/soc/tegra/tegra_das.c
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * tegra_das.c - Tegra DAS driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <mach/iomap.h>
-#include <sound/soc.h>
-#include "tegra_das.h"
-
-#define DRV_NAME "tegra-das"
-
-static struct tegra_das *das;
-
-static inline void tegra_das_write(u32 reg, u32 val)
-{
- __raw_writel(val, das->regs + reg);
-}
-
-static inline u32 tegra_das_read(u32 reg)
-{
- return __raw_readl(das->regs + reg);
-}
-
-int tegra_das_connect_dap_to_dac(int dap, int dac)
-{
- u32 addr;
- u32 reg;
-
- if (!das)
- return -ENODEV;
-
- addr = TEGRA_DAS_DAP_CTRL_SEL +
- (dap * TEGRA_DAS_DAP_CTRL_SEL_STRIDE);
- reg = dac << TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P;
-
- tegra_das_write(addr, reg);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(tegra_das_connect_dap_to_dac);
-
-int tegra_das_connect_dap_to_dap(int dap, int otherdap, int master,
- int sdata1rx, int sdata2rx)
-{
- u32 addr;
- u32 reg;
-
- if (!das)
- return -ENODEV;
-
- addr = TEGRA_DAS_DAP_CTRL_SEL +
- (dap * TEGRA_DAS_DAP_CTRL_SEL_STRIDE);
- reg = otherdap << TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P |
- !!sdata2rx << TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P |
- !!sdata1rx << TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P |
- !!master << TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P;
-
- tegra_das_write(addr, reg);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(tegra_das_connect_dap_to_dap);
-
-int tegra_das_connect_dac_to_dap(int dac, int dap)
-{
- u32 addr;
- u32 reg;
-
- if (!das)
- return -ENODEV;
-
- addr = TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL +
- (dac * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE);
- reg = dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P |
- dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P |
- dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P;
-
- tegra_das_write(addr, reg);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(tegra_das_connect_dac_to_dap);
-
-#ifdef CONFIG_DEBUG_FS
-static int tegra_das_show(struct seq_file *s, void *unused)
-{
- int i;
- u32 addr;
- u32 reg;
-
- for (i = 0; i < TEGRA_DAS_DAP_CTRL_SEL_COUNT; i++) {
- addr = TEGRA_DAS_DAP_CTRL_SEL +
- (i * TEGRA_DAS_DAP_CTRL_SEL_STRIDE);
- reg = tegra_das_read(addr);
- seq_printf(s, "TEGRA_DAS_DAP_CTRL_SEL[%d] = %08x\n", i, reg);
- }
-
- for (i = 0; i < TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT; i++) {
- addr = TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL +
- (i * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE);
- reg = tegra_das_read(addr);
- seq_printf(s, "TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL[%d] = %08x\n",
- i, reg);
- }
-
- return 0;
-}
-
-static int tegra_das_debug_open(struct inode *inode, struct file *file)
-{
- return single_open(file, tegra_das_show, inode->i_private);
-}
-
-static const struct file_operations tegra_das_debug_fops = {
- .open = tegra_das_debug_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static void tegra_das_debug_add(struct tegra_das *das)
-{
- das->debug = debugfs_create_file(DRV_NAME, S_IRUGO,
- snd_soc_debugfs_root, das,
- &tegra_das_debug_fops);
-}
-
-static void tegra_das_debug_remove(struct tegra_das *das)
-{
- if (das->debug)
- debugfs_remove(das->debug);
-}
-#else
-static inline void tegra_das_debug_add(struct tegra_das *das)
-{
-}
-
-static inline void tegra_das_debug_remove(struct tegra_das *das)
-{
-}
-#endif
-
-static int __devinit tegra_das_probe(struct platform_device *pdev)
-{
- struct resource *res, *region;
- int ret = 0;
-
- if (das)
- return -ENODEV;
-
- das = devm_kzalloc(&pdev->dev, sizeof(struct tegra_das), GFP_KERNEL);
- if (!das) {
- dev_err(&pdev->dev, "Can't allocate tegra_das\n");
- ret = -ENOMEM;
- goto err;
- }
- das->dev = &pdev->dev;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "No memory resource\n");
- ret = -ENODEV;
- goto err;
- }
-
- region = devm_request_mem_region(&pdev->dev, res->start,
- resource_size(res), pdev->name);
- if (!region) {
- dev_err(&pdev->dev, "Memory region already claimed\n");
- ret = -EBUSY;
- goto err;
- }
-
- das->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!das->regs) {
- dev_err(&pdev->dev, "ioremap failed\n");
- ret = -ENOMEM;
- goto err;
- }
-
- ret = tegra_das_connect_dap_to_dac(TEGRA_DAS_DAP_ID_1,
- TEGRA_DAS_DAP_SEL_DAC1);
- if (ret) {
- dev_err(&pdev->dev, "Can't set up DAS DAP connection\n");
- goto err;
- }
- ret = tegra_das_connect_dac_to_dap(TEGRA_DAS_DAC_ID_1,
- TEGRA_DAS_DAC_SEL_DAP1);
- if (ret) {
- dev_err(&pdev->dev, "Can't set up DAS DAC connection\n");
- goto err;
- }
-
- tegra_das_debug_add(das);
-
- platform_set_drvdata(pdev, das);
-
- return 0;
-
-err:
- das = NULL;
- return ret;
-}
-
-static int __devexit tegra_das_remove(struct platform_device *pdev)
-{
- if (!das)
- return -ENODEV;
-
- tegra_das_debug_remove(das);
-
- das = NULL;
-
- return 0;
-}
-
-static const struct of_device_id tegra_das_of_match[] __devinitconst = {
- { .compatible = "nvidia,tegra20-das", },
- {},
-};
-
-static struct platform_driver tegra_das_driver = {
- .probe = tegra_das_probe,
- .remove = __devexit_p(tegra_das_remove),
- .driver = {
- .name = DRV_NAME,
- .owner = THIS_MODULE,
- .of_match_table = tegra_das_of_match,
- },
-};
-module_platform_driver(tegra_das_driver);
-
-MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
-MODULE_DESCRIPTION("Tegra DAS driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
-MODULE_DEVICE_TABLE(of, tegra_das_of_match);
diff --git a/sound/soc/tegra/tegra_das.h b/sound/soc/tegra/tegra_das.h
deleted file mode 100644
index 2c96c7b3c459..000000000000
--- a/sound/soc/tegra/tegra_das.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * tegra_das.h - Definitions for Tegra DAS driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __TEGRA_DAS_H__
-#define __TEGRA_DAS_H__
-
-/* Register TEGRA_DAS_DAP_CTRL_SEL */
-#define TEGRA_DAS_DAP_CTRL_SEL 0x00
-#define TEGRA_DAS_DAP_CTRL_SEL_COUNT 5
-#define TEGRA_DAS_DAP_CTRL_SEL_STRIDE 4
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P 31
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_S 1
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P 30
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_S 1
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P 29
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_S 1
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P 0
-#define TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_S 5
-
-/* Values for field TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL */
-#define TEGRA_DAS_DAP_SEL_DAC1 0
-#define TEGRA_DAS_DAP_SEL_DAC2 1
-#define TEGRA_DAS_DAP_SEL_DAC3 2
-#define TEGRA_DAS_DAP_SEL_DAP1 16
-#define TEGRA_DAS_DAP_SEL_DAP2 17
-#define TEGRA_DAS_DAP_SEL_DAP3 18
-#define TEGRA_DAS_DAP_SEL_DAP4 19
-#define TEGRA_DAS_DAP_SEL_DAP5 20
-
-/* Register TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL */
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL 0x40
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT 3
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE 4
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P 28
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_S 4
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P 24
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_S 4
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P 0
-#define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_S 4
-
-/*
- * Values for:
- * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL
- * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL
- * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL
- */
-#define TEGRA_DAS_DAC_SEL_DAP1 0
-#define TEGRA_DAS_DAC_SEL_DAP2 1
-#define TEGRA_DAS_DAC_SEL_DAP3 2
-#define TEGRA_DAS_DAC_SEL_DAP4 3
-#define TEGRA_DAS_DAC_SEL_DAP5 4
-
-/*
- * Names/IDs of the DACs/DAPs.
- */
-
-#define TEGRA_DAS_DAP_ID_1 0
-#define TEGRA_DAS_DAP_ID_2 1
-#define TEGRA_DAS_DAP_ID_3 2
-#define TEGRA_DAS_DAP_ID_4 3
-#define TEGRA_DAS_DAP_ID_5 4
-
-#define TEGRA_DAS_DAC_ID_1 0
-#define TEGRA_DAS_DAC_ID_2 1
-#define TEGRA_DAS_DAC_ID_3 2
-
-struct tegra_das {
- struct device *dev;
- void __iomem *regs;
- struct dentry *debug;
-};
-
-/*
- * Terminology:
- * DAS: Digital audio switch (HW module controlled by this driver)
- * DAP: Digital audio port (port/pins on Tegra device)
- * DAC: Digital audio controller (e.g. I2S or AC97 controller elsewhere)
- *
- * The Tegra DAS is a mux/cross-bar which can connect each DAP to a specific
- * DAC, or another DAP. When DAPs are connected, one must be the master and
- * one the slave. Each DAC allows selection of a specific DAP for input, to
- * cater for the case where N DAPs are connected to 1 DAC for broadcast
- * output.
- *
- * This driver is dumb; no attempt is made to ensure that a valid routing
- * configuration is programmed.
- */
-
-/*
- * Connect a DAP to to a DAC
- * dap_id: DAP to connect: TEGRA_DAS_DAP_ID_*
- * dac_sel: DAC to connect to: TEGRA_DAS_DAP_SEL_DAC*
- */
-extern int tegra_das_connect_dap_to_dac(int dap_id, int dac_sel);
-
-/*
- * Connect a DAP to to another DAP
- * dap_id: DAP to connect: TEGRA_DAS_DAP_ID_*
- * other_dap_sel: DAP to connect to: TEGRA_DAS_DAP_SEL_DAP*
- * master: Is this DAP the master (1) or slave (0)
- * sdata1rx: Is this DAP's SDATA1 pin RX (1) or TX (0)
- * sdata2rx: Is this DAP's SDATA2 pin RX (1) or TX (0)
- */
-extern int tegra_das_connect_dap_to_dap(int dap_id, int other_dap_sel,
- int master, int sdata1rx,
- int sdata2rx);
-
-/*
- * Connect a DAC's input to a DAP
- * (DAC outputs are selected by the DAP)
- * dac_id: DAC ID to connect: TEGRA_DAS_DAC_ID_*
- * dap_sel: DAP to receive input from: TEGRA_DAS_DAC_SEL_DAP*
- */
-extern int tegra_das_connect_dac_to_dap(int dac_id, int dap_sel);
-
-#endif
diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c
deleted file mode 100644
index e53349912b2e..000000000000
--- a/sound/soc/tegra/tegra_i2s.c
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * tegra_i2s.c - Tegra I2S driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
- *
- * Based on code copyright/by:
- *
- * Copyright (c) 2009-2010, NVIDIA Corporation.
- * Scott Peterson <speterson@nvidia.com>
- *
- * Copyright (C) 2010 Google, Inc.
- * Iliyan Malchev <malchev@google.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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/clk.h>
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <mach/iomap.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include "tegra_i2s.h"
-
-#define DRV_NAME "tegra-i2s"
-
-static inline void tegra_i2s_write(struct tegra_i2s *i2s, u32 reg, u32 val)
-{
- __raw_writel(val, i2s->regs + reg);
-}
-
-static inline u32 tegra_i2s_read(struct tegra_i2s *i2s, u32 reg)
-{
- return __raw_readl(i2s->regs + reg);
-}
-
-#ifdef CONFIG_DEBUG_FS
-static int tegra_i2s_show(struct seq_file *s, void *unused)
-{
-#define REG(r) { r, #r }
- static const struct {
- int offset;
- const char *name;
- } regs[] = {
- REG(TEGRA_I2S_CTRL),
- REG(TEGRA_I2S_STATUS),
- REG(TEGRA_I2S_TIMING),
- REG(TEGRA_I2S_FIFO_SCR),
- REG(TEGRA_I2S_PCM_CTRL),
- REG(TEGRA_I2S_NW_CTRL),
- REG(TEGRA_I2S_TDM_CTRL),
- REG(TEGRA_I2S_TDM_TX_RX_CTRL),
- };
-#undef REG
-
- struct tegra_i2s *i2s = s->private;
- int i;
-
- clk_enable(i2s->clk_i2s);
-
- for (i = 0; i < ARRAY_SIZE(regs); i++) {
- u32 val = tegra_i2s_read(i2s, regs[i].offset);
- seq_printf(s, "%s = %08x\n", regs[i].name, val);
- }
-
- clk_disable(i2s->clk_i2s);
-
- return 0;
-}
-
-static int tegra_i2s_debug_open(struct inode *inode, struct file *file)
-{
- return single_open(file, tegra_i2s_show, inode->i_private);
-}
-
-static const struct file_operations tegra_i2s_debug_fops = {
- .open = tegra_i2s_debug_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static void tegra_i2s_debug_add(struct tegra_i2s *i2s)
-{
- i2s->debug = debugfs_create_file(i2s->dai.name, S_IRUGO,
- snd_soc_debugfs_root, i2s,
- &tegra_i2s_debug_fops);
-}
-
-static void tegra_i2s_debug_remove(struct tegra_i2s *i2s)
-{
- if (i2s->debug)
- debugfs_remove(i2s->debug);
-}
-#else
-static inline void tegra_i2s_debug_add(struct tegra_i2s *i2s)
-{
-}
-
-static inline void tegra_i2s_debug_remove(struct tegra_i2s *i2s)
-{
-}
-#endif
-
-static int tegra_i2s_set_fmt(struct snd_soc_dai *dai,
- unsigned int fmt)
-{
- struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-
- switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
- case SND_SOC_DAIFMT_NB_NF:
- break;
- default:
- return -EINVAL;
- }
-
- i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_MASTER_ENABLE;
- switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
- case SND_SOC_DAIFMT_CBS_CFS:
- i2s->reg_ctrl |= TEGRA_I2S_CTRL_MASTER_ENABLE;
- break;
- case SND_SOC_DAIFMT_CBM_CFM:
- break;
- default:
- return -EINVAL;
- }
-
- i2s->reg_ctrl &= ~(TEGRA_I2S_CTRL_BIT_FORMAT_MASK |
- TEGRA_I2S_CTRL_LRCK_MASK);
- switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
- case SND_SOC_DAIFMT_DSP_A:
- i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_DSP;
- i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
- break;
- case SND_SOC_DAIFMT_DSP_B:
- i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_DSP;
- i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_R_LOW;
- break;
- case SND_SOC_DAIFMT_I2S:
- i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_I2S;
- i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
- break;
- case SND_SOC_DAIFMT_RIGHT_J:
- i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_RJM;
- i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
- break;
- case SND_SOC_DAIFMT_LEFT_J:
- i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_LJM;
- i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW;
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int tegra_i2s_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
-{
- struct device *dev = substream->pcm->card->dev;
- struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai);
- u32 reg;
- int ret, sample_size, srate, i2sclock, bitcnt;
-
- i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_BIT_SIZE_MASK;
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
- i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_16;
- sample_size = 16;
- break;
- case SNDRV_PCM_FORMAT_S24_LE:
- i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_24;
- sample_size = 24;
- break;
- case SNDRV_PCM_FORMAT_S32_LE:
- i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_32;
- sample_size = 32;
- break;
- default:
- return -EINVAL;
- }
-
- srate = params_rate(params);
-
- /* Final "* 2" required by Tegra hardware */
- i2sclock = srate * params_channels(params) * sample_size * 2;
-
- ret = clk_set_rate(i2s->clk_i2s, i2sclock);
- if (ret) {
- dev_err(dev, "Can't set I2S clock rate: %d\n", ret);
- return ret;
- }
-
- bitcnt = (i2sclock / (2 * srate)) - 1;
- if (bitcnt < 0 || bitcnt > TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US)
- return -EINVAL;
- reg = bitcnt << TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT;
-
- if (i2sclock % (2 * srate))
- reg |= TEGRA_I2S_TIMING_NON_SYM_ENABLE;
-
- if (!i2s->clk_refs)
- clk_enable(i2s->clk_i2s);
-
- tegra_i2s_write(i2s, TEGRA_I2S_TIMING, reg);
-
- tegra_i2s_write(i2s, TEGRA_I2S_FIFO_SCR,
- TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS |
- TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS);
-
- if (!i2s->clk_refs)
- clk_disable(i2s->clk_i2s);
-
- return 0;
-}
-
-static void tegra_i2s_start_playback(struct tegra_i2s *i2s)
-{
- i2s->reg_ctrl |= TEGRA_I2S_CTRL_FIFO1_ENABLE;
- tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
-}
-
-static void tegra_i2s_stop_playback(struct tegra_i2s *i2s)
-{
- i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_FIFO1_ENABLE;
- tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
-}
-
-static void tegra_i2s_start_capture(struct tegra_i2s *i2s)
-{
- i2s->reg_ctrl |= TEGRA_I2S_CTRL_FIFO2_ENABLE;
- tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
-}
-
-static void tegra_i2s_stop_capture(struct tegra_i2s *i2s)
-{
- i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_FIFO2_ENABLE;
- tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl);
-}
-
-static int tegra_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
-{
- struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai);
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- case SNDRV_PCM_TRIGGER_RESUME:
- if (!i2s->clk_refs)
- clk_enable(i2s->clk_i2s);
- i2s->clk_refs++;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- tegra_i2s_start_playback(i2s);
- else
- tegra_i2s_start_capture(i2s);
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- tegra_i2s_stop_playback(i2s);
- else
- tegra_i2s_stop_capture(i2s);
- i2s->clk_refs--;
- if (!i2s->clk_refs)
- clk_disable(i2s->clk_i2s);
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int tegra_i2s_probe(struct snd_soc_dai *dai)
-{
- struct tegra_i2s * i2s = snd_soc_dai_get_drvdata(dai);
-
- dai->capture_dma_data = &i2s->capture_dma_data;
- dai->playback_dma_data = &i2s->playback_dma_data;
-
- return 0;
-}
-
-static const struct snd_soc_dai_ops tegra_i2s_dai_ops = {
- .set_fmt = tegra_i2s_set_fmt,
- .hw_params = tegra_i2s_hw_params,
- .trigger = tegra_i2s_trigger,
-};
-
-static const struct snd_soc_dai_driver tegra_i2s_dai_template = {
- .probe = tegra_i2s_probe,
- .playback = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_96000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
- .capture = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_8000_96000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
- .ops = &tegra_i2s_dai_ops,
- .symmetric_rates = 1,
-};
-
-static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev)
-{
- struct tegra_i2s * i2s;
- struct resource *mem, *memregion, *dmareq;
- u32 of_dma[2];
- u32 dma_ch;
- int ret;
-
- i2s = devm_kzalloc(&pdev->dev, sizeof(struct tegra_i2s), GFP_KERNEL);
- if (!i2s) {
- dev_err(&pdev->dev, "Can't allocate tegra_i2s\n");
- ret = -ENOMEM;
- goto err;
- }
- dev_set_drvdata(&pdev->dev, i2s);
-
- i2s->dai = tegra_i2s_dai_template;
- i2s->dai.name = dev_name(&pdev->dev);
-
- i2s->clk_i2s = clk_get(&pdev->dev, NULL);
- if (IS_ERR(i2s->clk_i2s)) {
- dev_err(&pdev->dev, "Can't retrieve i2s clock\n");
- ret = PTR_ERR(i2s->clk_i2s);
- goto err;
- }
-
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem) {
- dev_err(&pdev->dev, "No memory resource\n");
- ret = -ENODEV;
- goto err_clk_put;
- }
-
- dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!dmareq) {
- if (of_property_read_u32_array(pdev->dev.of_node,
- "nvidia,dma-request-selector",
- of_dma, 2) < 0) {
- dev_err(&pdev->dev, "No DMA resource\n");
- ret = -ENODEV;
- goto err_clk_put;
- }
- dma_ch = of_dma[1];
- } else {
- dma_ch = dmareq->start;
- }
-
- memregion = devm_request_mem_region(&pdev->dev, mem->start,
- resource_size(mem), DRV_NAME);
- if (!memregion) {
- dev_err(&pdev->dev, "Memory region already claimed\n");
- ret = -EBUSY;
- goto err_clk_put;
- }
-
- i2s->regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
- if (!i2s->regs) {
- dev_err(&pdev->dev, "ioremap failed\n");
- ret = -ENOMEM;
- goto err_clk_put;
- }
-
- i2s->capture_dma_data.addr = mem->start + TEGRA_I2S_FIFO2;
- i2s->capture_dma_data.wrap = 4;
- i2s->capture_dma_data.width = 32;
- i2s->capture_dma_data.req_sel = dma_ch;
-
- i2s->playback_dma_data.addr = mem->start + TEGRA_I2S_FIFO1;
- i2s->playback_dma_data.wrap = 4;
- i2s->playback_dma_data.width = 32;
- i2s->playback_dma_data.req_sel = dma_ch;
-
- i2s->reg_ctrl = TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED;
-
- ret = snd_soc_register_dai(&pdev->dev, &i2s->dai);
- if (ret) {
- dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
- ret = -ENOMEM;
- goto err_clk_put;
- }
-
- tegra_i2s_debug_add(i2s);
-
- return 0;
-
-err_clk_put:
- clk_put(i2s->clk_i2s);
-err:
- return ret;
-}
-
-static int __devexit tegra_i2s_platform_remove(struct platform_device *pdev)
-{
- struct tegra_i2s *i2s = dev_get_drvdata(&pdev->dev);
-
- snd_soc_unregister_dai(&pdev->dev);
-
- tegra_i2s_debug_remove(i2s);
-
- clk_put(i2s->clk_i2s);
-
- return 0;
-}
-
-static const struct of_device_id tegra_i2s_of_match[] __devinitconst = {
- { .compatible = "nvidia,tegra20-i2s", },
- {},
-};
-
-static struct platform_driver tegra_i2s_driver = {
- .driver = {
- .name = DRV_NAME,
- .owner = THIS_MODULE,
- .of_match_table = tegra_i2s_of_match,
- },
- .probe = tegra_i2s_platform_probe,
- .remove = __devexit_p(tegra_i2s_platform_remove),
-};
-module_platform_driver(tegra_i2s_driver);
-
-MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
-MODULE_DESCRIPTION("Tegra I2S ASoC driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
-MODULE_DEVICE_TABLE(of, tegra_i2s_of_match);
diff --git a/sound/soc/tegra/tegra_i2s.h b/sound/soc/tegra/tegra_i2s.h
deleted file mode 100644
index 15ce1e2e8bde..000000000000
--- a/sound/soc/tegra/tegra_i2s.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * tegra_i2s.h - Definitions for Tegra I2S driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
- *
- * Based on code copyright/by:
- *
- * Copyright (c) 2009-2010, NVIDIA Corporation.
- * Scott Peterson <speterson@nvidia.com>
- *
- * Copyright (C) 2010 Google, Inc.
- * Iliyan Malchev <malchev@google.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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __TEGRA_I2S_H__
-#define __TEGRA_I2S_H__
-
-#include "tegra_pcm.h"
-
-/* Register offsets from TEGRA_I2S1_BASE and TEGRA_I2S2_BASE */
-
-#define TEGRA_I2S_CTRL 0x00
-#define TEGRA_I2S_STATUS 0x04
-#define TEGRA_I2S_TIMING 0x08
-#define TEGRA_I2S_FIFO_SCR 0x0c
-#define TEGRA_I2S_PCM_CTRL 0x10
-#define TEGRA_I2S_NW_CTRL 0x14
-#define TEGRA_I2S_TDM_CTRL 0x20
-#define TEGRA_I2S_TDM_TX_RX_CTRL 0x24
-#define TEGRA_I2S_FIFO1 0x40
-#define TEGRA_I2S_FIFO2 0x80
-
-/* Fields in TEGRA_I2S_CTRL */
-
-#define TEGRA_I2S_CTRL_FIFO2_TX_ENABLE (1 << 30)
-#define TEGRA_I2S_CTRL_FIFO1_ENABLE (1 << 29)
-#define TEGRA_I2S_CTRL_FIFO2_ENABLE (1 << 28)
-#define TEGRA_I2S_CTRL_FIFO1_RX_ENABLE (1 << 27)
-#define TEGRA_I2S_CTRL_FIFO_LPBK_ENABLE (1 << 26)
-#define TEGRA_I2S_CTRL_MASTER_ENABLE (1 << 25)
-
-#define TEGRA_I2S_LRCK_LEFT_LOW 0
-#define TEGRA_I2S_LRCK_RIGHT_LOW 1
-
-#define TEGRA_I2S_CTRL_LRCK_SHIFT 24
-#define TEGRA_I2S_CTRL_LRCK_MASK (1 << TEGRA_I2S_CTRL_LRCK_SHIFT)
-#define TEGRA_I2S_CTRL_LRCK_L_LOW (TEGRA_I2S_LRCK_LEFT_LOW << TEGRA_I2S_CTRL_LRCK_SHIFT)
-#define TEGRA_I2S_CTRL_LRCK_R_LOW (TEGRA_I2S_LRCK_RIGHT_LOW << TEGRA_I2S_CTRL_LRCK_SHIFT)
-
-#define TEGRA_I2S_BIT_FORMAT_I2S 0
-#define TEGRA_I2S_BIT_FORMAT_RJM 1
-#define TEGRA_I2S_BIT_FORMAT_LJM 2
-#define TEGRA_I2S_BIT_FORMAT_DSP 3
-
-#define TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT 10
-#define TEGRA_I2S_CTRL_BIT_FORMAT_MASK (3 << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_FORMAT_I2S (TEGRA_I2S_BIT_FORMAT_I2S << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_FORMAT_RJM (TEGRA_I2S_BIT_FORMAT_RJM << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_FORMAT_LJM (TEGRA_I2S_BIT_FORMAT_LJM << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_FORMAT_DSP (TEGRA_I2S_BIT_FORMAT_DSP << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT)
-
-#define TEGRA_I2S_BIT_SIZE_16 0
-#define TEGRA_I2S_BIT_SIZE_20 1
-#define TEGRA_I2S_BIT_SIZE_24 2
-#define TEGRA_I2S_BIT_SIZE_32 3
-
-#define TEGRA_I2S_CTRL_BIT_SIZE_SHIFT 8
-#define TEGRA_I2S_CTRL_BIT_SIZE_MASK (3 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_SIZE_16 (TEGRA_I2S_BIT_SIZE_16 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_SIZE_20 (TEGRA_I2S_BIT_SIZE_20 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_SIZE_24 (TEGRA_I2S_BIT_SIZE_24 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
-#define TEGRA_I2S_CTRL_BIT_SIZE_32 (TEGRA_I2S_BIT_SIZE_32 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT)
-
-#define TEGRA_I2S_FIFO_16_LSB 0
-#define TEGRA_I2S_FIFO_20_LSB 1
-#define TEGRA_I2S_FIFO_24_LSB 2
-#define TEGRA_I2S_FIFO_32 3
-#define TEGRA_I2S_FIFO_PACKED 7
-
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT 4
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_MASK (7 << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_16_LSB (TEGRA_I2S_FIFO_16_LSB << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_20_LSB (TEGRA_I2S_FIFO_20_LSB << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_24_LSB (TEGRA_I2S_FIFO_24_LSB << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_32 (TEGRA_I2S_FIFO_32 << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-#define TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED (TEGRA_I2S_FIFO_PACKED << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT)
-
-#define TEGRA_I2S_CTRL_IE_FIFO1_ERR (1 << 3)
-#define TEGRA_I2S_CTRL_IE_FIFO2_ERR (1 << 2)
-#define TEGRA_I2S_CTRL_QE_FIFO1 (1 << 1)
-#define TEGRA_I2S_CTRL_QE_FIFO2 (1 << 0)
-
-/* Fields in TEGRA_I2S_STATUS */
-
-#define TEGRA_I2S_STATUS_FIFO1_RDY (1 << 31)
-#define TEGRA_I2S_STATUS_FIFO2_RDY (1 << 30)
-#define TEGRA_I2S_STATUS_FIFO1_BSY (1 << 29)
-#define TEGRA_I2S_STATUS_FIFO2_BSY (1 << 28)
-#define TEGRA_I2S_STATUS_FIFO1_ERR (1 << 3)
-#define TEGRA_I2S_STATUS_FIFO2_ERR (1 << 2)
-#define TEGRA_I2S_STATUS_QS_FIFO1 (1 << 1)
-#define TEGRA_I2S_STATUS_QS_FIFO2 (1 << 0)
-
-/* Fields in TEGRA_I2S_TIMING */
-
-#define TEGRA_I2S_TIMING_NON_SYM_ENABLE (1 << 12)
-#define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT 0
-#define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US 0x7fff
-#define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK (TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US << TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT)
-
-/* Fields in TEGRA_I2S_FIFO_SCR */
-
-#define TEGRA_I2S_FIFO_SCR_FIFO2_FULL_EMPTY_COUNT_SHIFT 24
-#define TEGRA_I2S_FIFO_SCR_FIFO1_FULL_EMPTY_COUNT_SHIFT 16
-#define TEGRA_I2S_FIFO_SCR_FIFO_FULL_EMPTY_COUNT_MASK 0x3f
-
-#define TEGRA_I2S_FIFO_SCR_FIFO2_CLR (1 << 12)
-#define TEGRA_I2S_FIFO_SCR_FIFO1_CLR (1 << 8)
-
-#define TEGRA_I2S_FIFO_ATN_LVL_ONE_SLOT 0
-#define TEGRA_I2S_FIFO_ATN_LVL_FOUR_SLOTS 1
-#define TEGRA_I2S_FIFO_ATN_LVL_EIGHT_SLOTS 2
-#define TEGRA_I2S_FIFO_ATN_LVL_TWELVE_SLOTS 3
-
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT 4
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_MASK (3 << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_ONE_SLOT (TEGRA_I2S_FIFO_ATN_LVL_ONE_SLOT << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_FOUR_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_EIGHT_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_EIGHT_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_TWELVE_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT)
-
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT 0
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_MASK (3 << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_ONE_SLOT (TEGRA_I2S_FIFO_ATN_LVL_ONE_SLOT << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_FOUR_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_EIGHT_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_EIGHT_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
-#define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_TWELVE_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT)
-
-struct tegra_i2s {
- struct snd_soc_dai_driver dai;
- struct clk *clk_i2s;
- int clk_refs;
- struct tegra_pcm_dma_params capture_dma_data;
- struct tegra_pcm_dma_params playback_dma_data;
- void __iomem *regs;
- struct dentry *debug;
- u32 reg_ctrl;
-};
-
-#endif
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index 8b4457137c7c..127348dc09b1 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -2,7 +2,7 @@
* tegra_pcm.c - Tegra PCM driver
*
* Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
*
* Based on code copyright/by:
*
@@ -29,8 +29,8 @@
*
*/
-#include <linux/module.h>
#include <linux/dma-mapping.h>
+#include <linux/module.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -39,8 +39,6 @@
#include "tegra_pcm.h"
-#define DRV_NAME "tegra-pcm-audio"
-
static const struct snd_pcm_hardware tegra_pcm_hardware = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
@@ -372,28 +370,18 @@ static struct snd_soc_platform_driver tegra_pcm_platform = {
.pcm_free = tegra_pcm_free,
};
-static int __devinit tegra_pcm_platform_probe(struct platform_device *pdev)
+int __devinit tegra_pcm_platform_register(struct device *dev)
{
- return snd_soc_register_platform(&pdev->dev, &tegra_pcm_platform);
+ return snd_soc_register_platform(dev, &tegra_pcm_platform);
}
+EXPORT_SYMBOL_GPL(tegra_pcm_platform_register);
-static int __devexit tegra_pcm_platform_remove(struct platform_device *pdev)
+void __devexit tegra_pcm_platform_unregister(struct device *dev)
{
- snd_soc_unregister_platform(&pdev->dev);
- return 0;
+ snd_soc_unregister_platform(dev);
}
-
-static struct platform_driver tegra_pcm_driver = {
- .driver = {
- .name = DRV_NAME,
- .owner = THIS_MODULE,
- },
- .probe = tegra_pcm_platform_probe,
- .remove = __devexit_p(tegra_pcm_platform_remove),
-};
-module_platform_driver(tegra_pcm_driver);
+EXPORT_SYMBOL_GPL(tegra_pcm_platform_unregister);
MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
MODULE_DESCRIPTION("Tegra PCM ASoC driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h
index dbb90339fe0d..985d418a35e7 100644
--- a/sound/soc/tegra/tegra_pcm.h
+++ b/sound/soc/tegra/tegra_pcm.h
@@ -2,7 +2,7 @@
* tegra_pcm.h - Definitions for Tegra PCM driver
*
* Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010 - NVIDIA, Inc.
+ * Copyright (C) 2010,2012 - NVIDIA, Inc.
*
* Based on code copyright/by:
*
@@ -52,4 +52,7 @@ struct tegra_runtime_data {
struct tegra_dma_channel *dma_chan;
};
+int tegra_pcm_platform_register(struct device *dev);
+void tegra_pcm_platform_unregister(struct device *dev);
+
#endif
diff --git a/sound/soc/tegra/tegra_spdif.c b/sound/soc/tegra/tegra_spdif.c
deleted file mode 100644
index 9ff2c601445f..000000000000
--- a/sound/soc/tegra/tegra_spdif.c
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * tegra_spdif.c - Tegra SPDIF driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2011 - NVIDIA, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/clk.h>
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <mach/iomap.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include "tegra_spdif.h"
-
-#define DRV_NAME "tegra-spdif"
-
-static inline void tegra_spdif_write(struct tegra_spdif *spdif, u32 reg,
- u32 val)
-{
- __raw_writel(val, spdif->regs + reg);
-}
-
-static inline u32 tegra_spdif_read(struct tegra_spdif *spdif, u32 reg)
-{
- return __raw_readl(spdif->regs + reg);
-}
-
-#ifdef CONFIG_DEBUG_FS
-static int tegra_spdif_show(struct seq_file *s, void *unused)
-{
-#define REG(r) { r, #r }
- static const struct {
- int offset;
- const char *name;
- } regs[] = {
- REG(TEGRA_SPDIF_CTRL),
- REG(TEGRA_SPDIF_STATUS),
- REG(TEGRA_SPDIF_STROBE_CTRL),
- REG(TEGRA_SPDIF_DATA_FIFO_CSR),
- REG(TEGRA_SPDIF_CH_STA_RX_A),
- REG(TEGRA_SPDIF_CH_STA_RX_B),
- REG(TEGRA_SPDIF_CH_STA_RX_C),
- REG(TEGRA_SPDIF_CH_STA_RX_D),
- REG(TEGRA_SPDIF_CH_STA_RX_E),
- REG(TEGRA_SPDIF_CH_STA_RX_F),
- REG(TEGRA_SPDIF_CH_STA_TX_A),
- REG(TEGRA_SPDIF_CH_STA_TX_B),
- REG(TEGRA_SPDIF_CH_STA_TX_C),
- REG(TEGRA_SPDIF_CH_STA_TX_D),
- REG(TEGRA_SPDIF_CH_STA_TX_E),
- REG(TEGRA_SPDIF_CH_STA_TX_F),
- };
-#undef REG
-
- struct tegra_spdif *spdif = s->private;
- int i;
-
- clk_enable(spdif->clk_spdif_out);
-
- for (i = 0; i < ARRAY_SIZE(regs); i++) {
- u32 val = tegra_spdif_read(spdif, regs[i].offset);
- seq_printf(s, "%s = %08x\n", regs[i].name, val);
- }
-
- clk_disable(spdif->clk_spdif_out);
-
- return 0;
-}
-
-static int tegra_spdif_debug_open(struct inode *inode, struct file *file)
-{
- return single_open(file, tegra_spdif_show, inode->i_private);
-}
-
-static const struct file_operations tegra_spdif_debug_fops = {
- .open = tegra_spdif_debug_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static void tegra_spdif_debug_add(struct tegra_spdif *spdif)
-{
- spdif->debug = debugfs_create_file(DRV_NAME, S_IRUGO,
- snd_soc_debugfs_root, spdif,
- &tegra_spdif_debug_fops);
-}
-
-static void tegra_spdif_debug_remove(struct tegra_spdif *spdif)
-{
- if (spdif->debug)
- debugfs_remove(spdif->debug);
-}
-#else
-static inline void tegra_spdif_debug_add(struct tegra_spdif *spdif)
-{
-}
-
-static inline void tegra_spdif_debug_remove(struct tegra_spdif *spdif)
-{
-}
-#endif
-
-static int tegra_spdif_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
-{
- struct device *dev = substream->pcm->card->dev;
- struct tegra_spdif *spdif = snd_soc_dai_get_drvdata(dai);
- int ret, spdifclock;
-
- spdif->reg_ctrl &= ~TEGRA_SPDIF_CTRL_PACK;
- spdif->reg_ctrl &= ~TEGRA_SPDIF_CTRL_BIT_MODE_MASK;
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
- spdif->reg_ctrl |= TEGRA_SPDIF_CTRL_PACK;
- spdif->reg_ctrl |= TEGRA_SPDIF_CTRL_BIT_MODE_16BIT;
- break;
- default:
- return -EINVAL;
- }
-
- switch (params_rate(params)) {
- case 32000:
- spdifclock = 4096000;
- break;
- case 44100:
- spdifclock = 5644800;
- break;
- case 48000:
- spdifclock = 6144000;
- break;
- case 88200:
- spdifclock = 11289600;
- break;
- case 96000:
- spdifclock = 12288000;
- break;
- case 176400:
- spdifclock = 22579200;
- break;
- case 192000:
- spdifclock = 24576000;
- break;
- default:
- return -EINVAL;
- }
-
- ret = clk_set_rate(spdif->clk_spdif_out, spdifclock);
- if (ret) {
- dev_err(dev, "Can't set SPDIF clock rate: %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-static void tegra_spdif_start_playback(struct tegra_spdif *spdif)
-{
- spdif->reg_ctrl |= TEGRA_SPDIF_CTRL_TX_EN;
- tegra_spdif_write(spdif, TEGRA_SPDIF_CTRL, spdif->reg_ctrl);
-}
-
-static void tegra_spdif_stop_playback(struct tegra_spdif *spdif)
-{
- spdif->reg_ctrl &= ~TEGRA_SPDIF_CTRL_TX_EN;
- tegra_spdif_write(spdif, TEGRA_SPDIF_CTRL, spdif->reg_ctrl);
-}
-
-static int tegra_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
-{
- struct tegra_spdif *spdif = snd_soc_dai_get_drvdata(dai);
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- case SNDRV_PCM_TRIGGER_RESUME:
- if (!spdif->clk_refs)
- clk_enable(spdif->clk_spdif_out);
- spdif->clk_refs++;
- tegra_spdif_start_playback(spdif);
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- tegra_spdif_stop_playback(spdif);
- spdif->clk_refs--;
- if (!spdif->clk_refs)
- clk_disable(spdif->clk_spdif_out);
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int tegra_spdif_probe(struct snd_soc_dai *dai)
-{
- struct tegra_spdif *spdif = snd_soc_dai_get_drvdata(dai);
-
- dai->capture_dma_data = NULL;
- dai->playback_dma_data = &spdif->playback_dma_data;
-
- return 0;
-}
-
-static const struct snd_soc_dai_ops tegra_spdif_dai_ops = {
- .hw_params = tegra_spdif_hw_params,
- .trigger = tegra_spdif_trigger,
-};
-
-static struct snd_soc_dai_driver tegra_spdif_dai = {
- .name = DRV_NAME,
- .probe = tegra_spdif_probe,
- .playback = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
- SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
- .ops = &tegra_spdif_dai_ops,
-};
-
-static __devinit int tegra_spdif_platform_probe(struct platform_device *pdev)
-{
- struct tegra_spdif *spdif;
- struct resource *mem, *memregion, *dmareq;
- int ret;
-
- spdif = kzalloc(sizeof(struct tegra_spdif), GFP_KERNEL);
- if (!spdif) {
- dev_err(&pdev->dev, "Can't allocate tegra_spdif\n");
- ret = -ENOMEM;
- goto exit;
- }
- dev_set_drvdata(&pdev->dev, spdif);
-
- spdif->clk_spdif_out = clk_get(&pdev->dev, "spdif_out");
- if (IS_ERR(spdif->clk_spdif_out)) {
- pr_err("Can't retrieve spdif clock\n");
- ret = PTR_ERR(spdif->clk_spdif_out);
- goto err_free;
- }
-
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem) {
- dev_err(&pdev->dev, "No memory resource\n");
- ret = -ENODEV;
- goto err_clk_put;
- }
-
- dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!dmareq) {
- dev_err(&pdev->dev, "No DMA resource\n");
- ret = -ENODEV;
- goto err_clk_put;
- }
-
- memregion = request_mem_region(mem->start, resource_size(mem),
- DRV_NAME);
- if (!memregion) {
- dev_err(&pdev->dev, "Memory region already claimed\n");
- ret = -EBUSY;
- goto err_clk_put;
- }
-
- spdif->regs = ioremap(mem->start, resource_size(mem));
- if (!spdif->regs) {
- dev_err(&pdev->dev, "ioremap failed\n");
- ret = -ENOMEM;
- goto err_release;
- }
-
- spdif->playback_dma_data.addr = mem->start + TEGRA_SPDIF_DATA_OUT;
- spdif->playback_dma_data.wrap = 4;
- spdif->playback_dma_data.width = 32;
- spdif->playback_dma_data.req_sel = dmareq->start;
-
- ret = snd_soc_register_dai(&pdev->dev, &tegra_spdif_dai);
- if (ret) {
- dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
- ret = -ENOMEM;
- goto err_unmap;
- }
-
- tegra_spdif_debug_add(spdif);
-
- return 0;
-
-err_unmap:
- iounmap(spdif->regs);
-err_release:
- release_mem_region(mem->start, resource_size(mem));
-err_clk_put:
- clk_put(spdif->clk_spdif_out);
-err_free:
- kfree(spdif);
-exit:
- return ret;
-}
-
-static int __devexit tegra_spdif_platform_remove(struct platform_device *pdev)
-{
- struct tegra_spdif *spdif = dev_get_drvdata(&pdev->dev);
- struct resource *res;
-
- snd_soc_unregister_dai(&pdev->dev);
-
- tegra_spdif_debug_remove(spdif);
-
- iounmap(spdif->regs);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
-
- clk_put(spdif->clk_spdif_out);
-
- kfree(spdif);
-
- return 0;
-}
-
-static struct platform_driver tegra_spdif_driver = {
- .driver = {
- .name = DRV_NAME,
- .owner = THIS_MODULE,
- },
- .probe = tegra_spdif_platform_probe,
- .remove = __devexit_p(tegra_spdif_platform_remove),
-};
-
-module_platform_driver(tegra_spdif_driver);
-
-MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
-MODULE_DESCRIPTION("Tegra SPDIF ASoC driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/tegra/tegra_spdif.h b/sound/soc/tegra/tegra_spdif.h
deleted file mode 100644
index 2e03db430279..000000000000
--- a/sound/soc/tegra/tegra_spdif.h
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- * tegra_spdif.h - Definitions for Tegra SPDIF driver
- *
- * Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2011 - NVIDIA, Inc.
- *
- * Based on code copyright/by:
- * Copyright (c) 2008-2009, NVIDIA Corporation
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __TEGRA_SPDIF_H__
-#define __TEGRA_SPDIF_H__
-
-#include "tegra_pcm.h"
-
-/* Offsets from TEGRA_SPDIF_BASE */
-
-#define TEGRA_SPDIF_CTRL 0x0
-#define TEGRA_SPDIF_STATUS 0x4
-#define TEGRA_SPDIF_STROBE_CTRL 0x8
-#define TEGRA_SPDIF_DATA_FIFO_CSR 0x0C
-#define TEGRA_SPDIF_DATA_OUT 0x40
-#define TEGRA_SPDIF_DATA_IN 0x80
-#define TEGRA_SPDIF_CH_STA_RX_A 0x100
-#define TEGRA_SPDIF_CH_STA_RX_B 0x104
-#define TEGRA_SPDIF_CH_STA_RX_C 0x108
-#define TEGRA_SPDIF_CH_STA_RX_D 0x10C
-#define TEGRA_SPDIF_CH_STA_RX_E 0x110
-#define TEGRA_SPDIF_CH_STA_RX_F 0x114
-#define TEGRA_SPDIF_CH_STA_TX_A 0x140
-#define TEGRA_SPDIF_CH_STA_TX_B 0x144
-#define TEGRA_SPDIF_CH_STA_TX_C 0x148
-#define TEGRA_SPDIF_CH_STA_TX_D 0x14C
-#define TEGRA_SPDIF_CH_STA_TX_E 0x150
-#define TEGRA_SPDIF_CH_STA_TX_F 0x154
-#define TEGRA_SPDIF_USR_STA_RX_A 0x180
-#define TEGRA_SPDIF_USR_DAT_TX_A 0x1C0
-
-/* Fields in TEGRA_SPDIF_CTRL */
-
-/* Start capturing from 0=right, 1=left channel */
-#define TEGRA_SPDIF_CTRL_CAP_LC (1 << 30)
-
-/* SPDIF receiver(RX) enable */
-#define TEGRA_SPDIF_CTRL_RX_EN (1 << 29)
-
-/* SPDIF Transmitter(TX) enable */
-#define TEGRA_SPDIF_CTRL_TX_EN (1 << 28)
-
-/* Transmit Channel status */
-#define TEGRA_SPDIF_CTRL_TC_EN (1 << 27)
-
-/* Transmit user Data */
-#define TEGRA_SPDIF_CTRL_TU_EN (1 << 26)
-
-/* Interrupt on transmit error */
-#define TEGRA_SPDIF_CTRL_IE_TXE (1 << 25)
-
-/* Interrupt on receive error */
-#define TEGRA_SPDIF_CTRL_IE_RXE (1 << 24)
-
-/* Interrupt on invalid preamble */
-#define TEGRA_SPDIF_CTRL_IE_P (1 << 23)
-
-/* Interrupt on "B" preamble */
-#define TEGRA_SPDIF_CTRL_IE_B (1 << 22)
-
-/* Interrupt when block of channel status received */
-#define TEGRA_SPDIF_CTRL_IE_C (1 << 21)
-
-/* Interrupt when a valid information unit (IU) is received */
-#define TEGRA_SPDIF_CTRL_IE_U (1 << 20)
-
-/* Interrupt when RX user FIFO attention level is reached */
-#define TEGRA_SPDIF_CTRL_QE_RU (1 << 19)
-
-/* Interrupt when TX user FIFO attention level is reached */
-#define TEGRA_SPDIF_CTRL_QE_TU (1 << 18)
-
-/* Interrupt when RX data FIFO attention level is reached */
-#define TEGRA_SPDIF_CTRL_QE_RX (1 << 17)
-
-/* Interrupt when TX data FIFO attention level is reached */
-#define TEGRA_SPDIF_CTRL_QE_TX (1 << 16)
-
-/* Loopback test mode enable */
-#define TEGRA_SPDIF_CTRL_LBK_EN (1 << 15)
-
-/*
- * Pack data mode:
- * 0 = Single data (16 bit needs to be padded to match the
- * interface data bit size).
- * 1 = Packeted left/right channel data into a single word.
- */
-#define TEGRA_SPDIF_CTRL_PACK (1 << 14)
-
-/*
- * 00 = 16bit data
- * 01 = 20bit data
- * 10 = 24bit data
- * 11 = raw data
- */
-#define TEGRA_SPDIF_BIT_MODE_16BIT 0
-#define TEGRA_SPDIF_BIT_MODE_20BIT 1
-#define TEGRA_SPDIF_BIT_MODE_24BIT 2
-#define TEGRA_SPDIF_BIT_MODE_RAW 3
-
-#define TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT 12
-#define TEGRA_SPDIF_CTRL_BIT_MODE_MASK (3 << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
-#define TEGRA_SPDIF_CTRL_BIT_MODE_16BIT (TEGRA_SPDIF_BIT_MODE_16BIT << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
-#define TEGRA_SPDIF_CTRL_BIT_MODE_20BIT (TEGRA_SPDIF_BIT_MODE_20BIT << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
-#define TEGRA_SPDIF_CTRL_BIT_MODE_24BIT (TEGRA_SPDIF_BIT_MODE_24BIT << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
-#define TEGRA_SPDIF_CTRL_BIT_MODE_RAW (TEGRA_SPDIF_BIT_MODE_RAW << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT)
-
-/* Fields in TEGRA_SPDIF_STATUS */
-
-/*
- * Note: IS_P, IS_B, IS_C, and IS_U are sticky bits. Software must
- * write a 1 to the corresponding bit location to clear the status.
- */
-
-/*
- * Receiver(RX) shifter is busy receiving data.
- * This bit is asserted when the receiver first locked onto the
- * preamble of the data stream after RX_EN is asserted. This bit is
- * deasserted when either,
- * (a) the end of a frame is reached after RX_EN is deeasserted, or
- * (b) the SPDIF data stream becomes inactive.
- */
-#define TEGRA_SPDIF_STATUS_RX_BSY (1 << 29)
-
-/*
- * Transmitter(TX) shifter is busy transmitting data.
- * This bit is asserted when TX_EN is asserted.
- * This bit is deasserted when the end of a frame is reached after
- * TX_EN is deasserted.
- */
-#define TEGRA_SPDIF_STATUS_TX_BSY (1 << 28)
-
-/*
- * TX is busy shifting out channel status.
- * This bit is asserted when both TX_EN and TC_EN are asserted and
- * data from CH_STA_TX_A register is loaded into the internal shifter.
- * This bit is deasserted when either,
- * (a) the end of a frame is reached after TX_EN is deasserted, or
- * (b) CH_STA_TX_F register is loaded into the internal shifter.
- */
-#define TEGRA_SPDIF_STATUS_TC_BSY (1 << 27)
-
-/*
- * TX User data FIFO busy.
- * This bit is asserted when TX_EN and TXU_EN are asserted and
- * there's data in the TX user FIFO. This bit is deassert when either,
- * (a) the end of a frame is reached after TX_EN is deasserted, or
- * (b) there's no data left in the TX user FIFO.
- */
-#define TEGRA_SPDIF_STATUS_TU_BSY (1 << 26)
-
-/* TX FIFO Underrun error status */
-#define TEGRA_SPDIF_STATUS_TX_ERR (1 << 25)
-
-/* RX FIFO Overrun error status */
-#define TEGRA_SPDIF_STATUS_RX_ERR (1 << 24)
-
-/* Preamble status: 0=Preamble OK, 1=bad/missing preamble */
-#define TEGRA_SPDIF_STATUS_IS_P (1 << 23)
-
-/* B-preamble detection status: 0=not detected, 1=B-preamble detected */
-#define TEGRA_SPDIF_STATUS_IS_B (1 << 22)
-
-/*
- * RX channel block data receive status:
- * 0=entire block not recieved yet.
- * 1=received entire block of channel status,
- */
-#define TEGRA_SPDIF_STATUS_IS_C (1 << 21)
-
-/* RX User Data Valid flag: 1=valid IU detected, 0 = no IU detected. */
-#define TEGRA_SPDIF_STATUS_IS_U (1 << 20)
-
-/*
- * RX User FIFO Status:
- * 1=attention level reached, 0=attention level not reached.
- */
-#define TEGRA_SPDIF_STATUS_QS_RU (1 << 19)
-
-/*
- * TX User FIFO Status:
- * 1=attention level reached, 0=attention level not reached.
- */
-#define TEGRA_SPDIF_STATUS_QS_TU (1 << 18)
-
-/*
- * RX Data FIFO Status:
- * 1=attention level reached, 0=attention level not reached.
- */
-#define TEGRA_SPDIF_STATUS_QS_RX (1 << 17)
-
-/*
- * TX Data FIFO Status:
- * 1=attention level reached, 0=attention level not reached.
- */
-#define TEGRA_SPDIF_STATUS_QS_TX (1 << 16)
-
-/* Fields in TEGRA_SPDIF_STROBE_CTRL */
-
-/*
- * Indicates the approximate number of detected SPDIFIN clocks within a
- * bi-phase period.
- */
-#define TEGRA_SPDIF_STROBE_CTRL_PERIOD_SHIFT 16
-#define TEGRA_SPDIF_STROBE_CTRL_PERIOD_MASK (0xff << TEGRA_SPDIF_STROBE_CTRL_PERIOD_SHIFT)
-
-/* Data strobe mode: 0=Auto-locked 1=Manual locked */
-#define TEGRA_SPDIF_STROBE_CTRL_STROBE (1 << 15)
-
-/*
- * Manual data strobe time within the bi-phase clock period (in terms of
- * the number of over-sampling clocks).
- */
-#define TEGRA_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT 8
-#define TEGRA_SPDIF_STROBE_CTRL_DATA_STROBES_MASK (0x1f << TEGRA_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT)
-
-/*
- * Manual SPDIFIN bi-phase clock period (in terms of the number of
- * over-sampling clocks).
- */
-#define TEGRA_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT 0
-#define TEGRA_SPDIF_STROBE_CTRL_CLOCK_PERIOD_MASK (0x3f << TEGRA_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT)
-
-/* Fields in SPDIF_DATA_FIFO_CSR */
-
-/* Clear Receiver User FIFO (RX USR.FIFO) */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_CLR (1 << 31)
-
-#define TEGRA_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT 0
-#define TEGRA_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS 1
-#define TEGRA_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS 2
-#define TEGRA_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS 3
-
-/* RU FIFO attention level */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT 29
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_MASK \
- (0x3 << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU1_WORD_FULL \
- (TEGRA_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU2_WORD_FULL \
- (TEGRA_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU3_WORD_FULL \
- (TEGRA_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU4_WORD_FULL \
- (TEGRA_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT)
-
-/* Number of RX USR.FIFO levels with valid data. */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT 24
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_MASK (0x1f << TEGRA_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT)
-
-/* Clear Transmitter User FIFO (TX USR.FIFO) */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_CLR (1 << 23)
-
-/* TU FIFO attention level */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT 21
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_MASK \
- (0x3 << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU1_WORD_FULL \
- (TEGRA_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU2_WORD_FULL \
- (TEGRA_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU3_WORD_FULL \
- (TEGRA_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU4_WORD_FULL \
- (TEGRA_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT)
-
-/* Number of TX USR.FIFO levels that could be filled. */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT 16
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_MASK (0x1f << SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT)
-
-/* Clear Receiver Data FIFO (RX DATA.FIFO) */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_CLR (1 << 15)
-
-#define TEGRA_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT 0
-#define TEGRA_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS 1
-#define TEGRA_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS 2
-#define TEGRA_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS 3
-
-/* RU FIFO attention level */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT 13
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_MASK \
- (0x3 << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU1_WORD_FULL \
- (TEGRA_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU4_WORD_FULL \
- (TEGRA_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU8_WORD_FULL \
- (TEGRA_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU12_WORD_FULL \
- (TEGRA_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT)
-
-/* Number of RX DATA.FIFO levels with valid data. */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT 8
-#define TEGRA_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_MASK (0x1f << TEGRA_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT)
-
-/* Clear Transmitter Data FIFO (TX DATA.FIFO) */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_CLR (1 << 7)
-
-/* TU FIFO attention level */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT 5
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_MASK \
- (0x3 << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU1_WORD_FULL \
- (TEGRA_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU4_WORD_FULL \
- (TEGRA_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU8_WORD_FULL \
- (TEGRA_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU12_WORD_FULL \
- (TEGRA_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT)
-
-/* Number of TX DATA.FIFO levels that could be filled. */
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT 0
-#define TEGRA_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_MASK (0x1f << SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT)
-
-/* Fields in TEGRA_SPDIF_DATA_OUT */
-
-/*
- * This register has 5 different formats:
- * 16-bit (BIT_MODE=00, PACK=0)
- * 20-bit (BIT_MODE=01, PACK=0)
- * 24-bit (BIT_MODE=10, PACK=0)
- * raw (BIT_MODE=11, PACK=0)
- * 16-bit packed (BIT_MODE=00, PACK=1)
- */
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_SHIFT 0
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_MASK (0xffff << TEGRA_SPDIF_DATA_OUT_DATA_16_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_20_SHIFT 0
-#define TEGRA_SPDIF_DATA_OUT_DATA_20_MASK (0xfffff << TEGRA_SPDIF_DATA_OUT_DATA_20_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_24_SHIFT 0
-#define TEGRA_SPDIF_DATA_OUT_DATA_24_MASK (0xffffff << TEGRA_SPDIF_DATA_OUT_DATA_24_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_P (1 << 31)
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_C (1 << 30)
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_U (1 << 29)
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_V (1 << 28)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT 8
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_DATA_MASK (0xfffff << TEGRA_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT 4
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_AUX_MASK (0xf << TEGRA_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT 0
-#define TEGRA_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_MASK (0xf << TEGRA_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT 16
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_MASK (0xffff << TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT)
-
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT 0
-#define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_MASK (0xffff << TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT)
-
-/* Fields in TEGRA_SPDIF_DATA_IN */
-
-/*
- * This register has 5 different formats:
- * 16-bit (BIT_MODE=00, PACK=0)
- * 20-bit (BIT_MODE=01, PACK=0)
- * 24-bit (BIT_MODE=10, PACK=0)
- * raw (BIT_MODE=11, PACK=0)
- * 16-bit packed (BIT_MODE=00, PACK=1)
- *
- * Bits 31:24 are common to all modes except 16-bit packed
- */
-
-#define TEGRA_SPDIF_DATA_IN_DATA_P (1 << 31)
-#define TEGRA_SPDIF_DATA_IN_DATA_C (1 << 30)
-#define TEGRA_SPDIF_DATA_IN_DATA_U (1 << 29)
-#define TEGRA_SPDIF_DATA_IN_DATA_V (1 << 28)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT 24
-#define TEGRA_SPDIF_DATA_IN_DATA_PREAMBLE_MASK (0xf << TEGRA_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_16_SHIFT 0
-#define TEGRA_SPDIF_DATA_IN_DATA_16_MASK (0xffff << TEGRA_SPDIF_DATA_IN_DATA_16_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_20_SHIFT 0
-#define TEGRA_SPDIF_DATA_IN_DATA_20_MASK (0xfffff << TEGRA_SPDIF_DATA_IN_DATA_20_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_24_SHIFT 0
-#define TEGRA_SPDIF_DATA_IN_DATA_24_MASK (0xffffff << TEGRA_SPDIF_DATA_IN_DATA_24_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT 8
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_DATA_MASK (0xfffff << TEGRA_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT 4
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_AUX_MASK (0xf << TEGRA_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT 0
-#define TEGRA_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_MASK (0xf << TEGRA_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT 16
-#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_MASK (0xffff << TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT)
-
-#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT 0
-#define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_MASK (0xffff << TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT)
-
-/* Fields in TEGRA_SPDIF_CH_STA_RX_A */
-/* Fields in TEGRA_SPDIF_CH_STA_RX_B */
-/* Fields in TEGRA_SPDIF_CH_STA_RX_C */
-/* Fields in TEGRA_SPDIF_CH_STA_RX_D */
-/* Fields in TEGRA_SPDIF_CH_STA_RX_E */
-/* Fields in TEGRA_SPDIF_CH_STA_RX_F */
-
-/*
- * The 6-word receive channel data page buffer holds a block (192 frames) of
- * channel status information. The order of receive is from LSB to MSB
- * bit, and from CH_STA_RX_A to CH_STA_RX_F then back to CH_STA_RX_A.
- */
-
-/* Fields in TEGRA_SPDIF_CH_STA_TX_A */
-/* Fields in TEGRA_SPDIF_CH_STA_TX_B */
-/* Fields in TEGRA_SPDIF_CH_STA_TX_C */
-/* Fields in TEGRA_SPDIF_CH_STA_TX_D */
-/* Fields in TEGRA_SPDIF_CH_STA_TX_E */
-/* Fields in TEGRA_SPDIF_CH_STA_TX_F */
-
-/*
- * The 6-word transmit channel data page buffer holds a block (192 frames) of
- * channel status information. The order of transmission is from LSB to MSB
- * bit, and from CH_STA_TX_A to CH_STA_TX_F then back to CH_STA_TX_A.
- */
-
-/* Fields in TEGRA_SPDIF_USR_STA_RX_A */
-
-/*
- * This 4-word deep FIFO receives user FIFO field information. The order of
- * receive is from LSB to MSB bit.
- */
-
-/* Fields in TEGRA_SPDIF_USR_DAT_TX_A */
-
-/*
- * This 4-word deep FIFO transmits user FIFO field information. The order of
- * transmission is from LSB to MSB bit.
- */
-
-struct tegra_spdif {
- struct clk *clk_spdif_out;
- int clk_refs;
- struct tegra_pcm_dma_params capture_dma_data;
- struct tegra_pcm_dma_params playback_dma_data;
- void __iomem *regs;
- struct dentry *debug;
- u32 reg_ctrl;
-};
-
-#endif
diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c
new file mode 100644
index 000000000000..4e77026807a2
--- /dev/null
+++ b/sound/soc/tegra/tegra_wm8753.c
@@ -0,0 +1,224 @@
+/*
+ * tegra_wm8753.c - Tegra machine ASoC driver for boards using WM8753 codec.
+ *
+ * Author: Stephen Warren <swarren@nvidia.com>
+ * Copyright (C) 2010-2012 - NVIDIA, Inc.
+ *
+ * Based on code copyright/by:
+ *
+ * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd.
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <asm/mach-types.h>
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "../codecs/wm8753.h"
+
+#include "tegra_asoc_utils.h"
+
+#define DRV_NAME "tegra-snd-wm8753"
+
+struct tegra_wm8753 {
+ struct tegra_asoc_utils_data util_data;
+};
+
+static int tegra_wm8753_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_card *card = codec->card;
+ struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card);
+ int srate, mclk;
+ int err;
+
+ srate = params_rate(params);
+ switch (srate) {
+ case 11025:
+ case 22050:
+ case 44100:
+ case 88200:
+ mclk = 11289600;
+ break;
+ default:
+ mclk = 12288000;
+ break;
+ }
+
+ err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
+ if (err < 0) {
+ dev_err(card->dev, "Can't configure clocks\n");
+ return err;
+ }
+
+ err = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, mclk,
+ SND_SOC_CLOCK_IN);
+ if (err < 0) {
+ dev_err(card->dev, "codec_dai clock not set\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static struct snd_soc_ops tegra_wm8753_ops = {
+ .hw_params = tegra_wm8753_hw_params,
+};
+
+static const struct snd_soc_dapm_widget tegra_wm8753_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static struct snd_soc_dai_link tegra_wm8753_dai = {
+ .name = "WM8753",
+ .stream_name = "WM8753 PCM",
+ .codec_dai_name = "wm8753-hifi",
+ .ops = &tegra_wm8753_ops,
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+};
+
+static struct snd_soc_card snd_soc_tegra_wm8753 = {
+ .name = "tegra-wm8753",
+ .owner = THIS_MODULE,
+ .dai_link = &tegra_wm8753_dai,
+ .num_links = 1,
+
+ .dapm_widgets = tegra_wm8753_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tegra_wm8753_dapm_widgets),
+ .fully_routed = true,
+};
+
+static __devinit int tegra_wm8753_driver_probe(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = &snd_soc_tegra_wm8753;
+ struct tegra_wm8753 *machine;
+ int ret;
+
+ machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm8753),
+ GFP_KERNEL);
+ if (!machine) {
+ dev_err(&pdev->dev, "Can't allocate tegra_wm8753 struct\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ card->dev = &pdev->dev;
+ platform_set_drvdata(pdev, card);
+ snd_soc_card_set_drvdata(card, machine);
+
+ ret = snd_soc_of_parse_card_name(card, "nvidia,model");
+ if (ret)
+ goto err;
+
+ ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
+ if (ret)
+ goto err;
+
+ tegra_wm8753_dai.codec_of_node = of_parse_phandle(
+ pdev->dev.of_node, "nvidia,audio-codec", 0);
+ if (!tegra_wm8753_dai.codec_of_node) {
+ dev_err(&pdev->dev,
+ "Property 'nvidia,audio-codec' missing or invalid\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ tegra_wm8753_dai.cpu_dai_of_node = of_parse_phandle(
+ pdev->dev.of_node, "nvidia,i2s-controller", 0);
+ if (!tegra_wm8753_dai.cpu_dai_of_node) {
+ dev_err(&pdev->dev,
+ "Property 'nvidia,i2s-controller' missing or invalid\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ tegra_wm8753_dai.platform_of_node =
+ tegra_wm8753_dai.cpu_dai_of_node;
+
+ ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+ if (ret)
+ goto err;
+
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+ ret);
+ goto err_fini_utils;
+ }
+
+ return 0;
+
+err_fini_utils:
+ tegra_asoc_utils_fini(&machine->util_data);
+err:
+ return ret;
+}
+
+static int __devexit tegra_wm8753_driver_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card);
+
+ snd_soc_unregister_card(card);
+
+ tegra_asoc_utils_fini(&machine->util_data);
+
+ return 0;
+}
+
+static const struct of_device_id tegra_wm8753_of_match[] __devinitconst = {
+ { .compatible = "nvidia,tegra-audio-wm8753", },
+ {},
+};
+
+static struct platform_driver tegra_wm8753_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ .of_match_table = tegra_wm8753_of_match,
+ },
+ .probe = tegra_wm8753_driver_probe,
+ .remove = __devexit_p(tegra_wm8753_driver_remove),
+};
+module_platform_driver(tegra_wm8753_driver);
+
+MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
+MODULE_DESCRIPTION("Tegra+WM8753 machine ASoC driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra_wm8753_of_match);
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index 566655e23b7d..0b0df49d9d33 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -2,7 +2,7 @@
* tegra_wm8903.c - Tegra machine ASoC driver for boards using WM8903 codec.
*
* Author: Stephen Warren <swarren@nvidia.com>
- * Copyright (C) 2010-2011 - NVIDIA, Inc.
+ * Copyright (C) 2010-2012 - NVIDIA, Inc.
*
* Based on code copyright/by:
*
@@ -46,9 +46,6 @@
#include "../codecs/wm8903.h"
-#include "tegra_das.h"
-#include "tegra_i2s.h"
-#include "tegra_pcm.h"
#include "tegra_asoc_utils.h"
#define DRV_NAME "tegra-snd-wm8903"
@@ -61,7 +58,6 @@
struct tegra_wm8903 {
struct tegra_wm8903_platform_data pdata;
- struct platform_device *pcm_dev;
struct tegra_asoc_utils_data util_data;
int gpio_requested;
};
@@ -354,8 +350,8 @@ static struct snd_soc_dai_link tegra_wm8903_dai = {
.name = "WM8903",
.stream_name = "WM8903 PCM",
.codec_name = "wm8903.0-001a",
- .platform_name = "tegra-pcm-audio",
- .cpu_dai_name = "tegra-i2s.0",
+ .platform_name = "tegra20-i2s.0",
+ .cpu_dai_name = "tegra20-i2s.0",
.codec_dai_name = "wm8903-hifi",
.init = tegra_wm8903_init,
.ops = &tegra_wm8903_ops,
@@ -392,7 +388,6 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto err;
}
- machine->pcm_dev = ERR_PTR(-EINVAL);
card->dev = &pdev->dev;
platform_set_drvdata(pdev, card);
@@ -428,14 +423,9 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
goto err;
}
- machine->pcm_dev = platform_device_register_simple(
- "tegra-pcm-audio", -1, NULL, 0);
- if (IS_ERR(machine->pcm_dev)) {
- dev_err(&pdev->dev,
- "Can't instantiate tegra-pcm-audio\n");
- ret = PTR_ERR(machine->pcm_dev);
- goto err;
- }
+ tegra_wm8903_dai.platform_name = NULL;
+ tegra_wm8903_dai.platform_of_node =
+ tegra_wm8903_dai.cpu_dai_of_node;
} else {
if (machine_is_harmony()) {
card->dapm_routes = harmony_audio_map;
@@ -454,7 +444,7 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
if (ret)
- goto err_unregister;
+ goto err;
ret = snd_soc_register_card(card);
if (ret) {
@@ -467,9 +457,6 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
err_fini_utils:
tegra_asoc_utils_fini(&machine->util_data);
-err_unregister:
- if (!IS_ERR(machine->pcm_dev))
- platform_device_unregister(machine->pcm_dev);
err:
return ret;
}
@@ -497,8 +484,6 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev)
snd_soc_unregister_card(card);
tegra_asoc_utils_fini(&machine->util_data);
- if (!IS_ERR(machine->pcm_dev))
- platform_device_unregister(machine->pcm_dev);
return 0;
}
diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c
index 2bdfc550cff8..4a8d5b672c9f 100644
--- a/sound/soc/tegra/trimslice.c
+++ b/sound/soc/tegra/trimslice.c
@@ -27,6 +27,7 @@
#include <asm/mach-types.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -38,9 +39,6 @@
#include "../codecs/tlv320aic23.h"
-#include "tegra_das.h"
-#include "tegra_i2s.h"
-#include "tegra_pcm.h"
#include "tegra_asoc_utils.h"
#define DRV_NAME "tegra-snd-trimslice"
@@ -119,8 +117,8 @@ static struct snd_soc_dai_link trimslice_tlv320aic23_dai = {
.name = "TLV320AIC23",
.stream_name = "AIC23",
.codec_name = "tlv320aic23-codec.2-001a",
- .platform_name = "tegra-pcm-audio",
- .cpu_dai_name = "tegra-i2s.0",
+ .platform_name = "tegra20-i2s.0",
+ .cpu_dai_name = "tegra20-i2s.0",
.codec_dai_name = "tlv320aic23-hifi",
.ops = &trimslice_asoc_ops,
};
@@ -152,6 +150,32 @@ static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev)
goto err;
}
+ if (pdev->dev.of_node) {
+ trimslice_tlv320aic23_dai.codec_name = NULL;
+ trimslice_tlv320aic23_dai.codec_of_node = of_parse_phandle(
+ pdev->dev.of_node, "nvidia,audio-codec", 0);
+ if (!trimslice_tlv320aic23_dai.codec_of_node) {
+ dev_err(&pdev->dev,
+ "Property 'nvidia,audio-codec' missing or invalid\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ trimslice_tlv320aic23_dai.cpu_dai_name = NULL;
+ trimslice_tlv320aic23_dai.cpu_dai_of_node = of_parse_phandle(
+ pdev->dev.of_node, "nvidia,i2s-controller", 0);
+ if (!trimslice_tlv320aic23_dai.cpu_dai_of_node) {
+ dev_err(&pdev->dev,
+ "Property 'nvidia,i2s-controller' missing or invalid\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ trimslice_tlv320aic23_dai.platform_name = NULL;
+ trimslice_tlv320aic23_dai.platform_of_node =
+ trimslice_tlv320aic23_dai.cpu_dai_of_node;
+ }
+
ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev);
if (ret)
goto err;
@@ -187,10 +211,17 @@ static int __devexit tegra_snd_trimslice_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id trimslice_of_match[] __devinitconst = {
+ { .compatible = "nvidia,tegra-audio-trimslice", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, trimslice_of_match);
+
static struct platform_driver tegra_snd_trimslice_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
+ .of_match_table = trimslice_of_match,
},
.probe = tegra_snd_trimslice_probe,
.remove = __devexit_p(tegra_snd_trimslice_remove),
diff --git a/sound/soc/ux500/Kconfig b/sound/soc/ux500/Kconfig
new file mode 100644
index 000000000000..44cf43404cd9
--- /dev/null
+++ b/sound/soc/ux500/Kconfig
@@ -0,0 +1,14 @@
+#
+# Ux500 SoC audio configuration
+#
+menuconfig SND_SOC_UX500
+ tristate "SoC Audio support for Ux500 platform"
+ depends on SND_SOC
+ depends on MFD_DB8500_PRCMU
+ help
+ Say Y if you want to enable ASoC-support for
+ any of the Ux500 platforms (e.g. U8500).
+
+config SND_SOC_UX500_PLAT_MSP_I2S
+ tristate
+ depends on SND_SOC_UX500
diff --git a/sound/soc/ux500/Makefile b/sound/soc/ux500/Makefile
new file mode 100644
index 000000000000..19974c5a2ea1
--- /dev/null
+++ b/sound/soc/ux500/Makefile
@@ -0,0 +1,4 @@
+# Ux500 Platform Support
+
+snd-soc-ux500-plat-msp-i2s-objs := ux500_msp_dai.o ux500_msp_i2s.o
+obj-$(CONFIG_SND_SOC_UX500_PLAT_MSP_I2S) += snd-soc-ux500-plat-msp-i2s.o
diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c
new file mode 100644
index 000000000000..93c6c40e724c
--- /dev/null
+++ b/sound/soc/ux500/ux500_msp_dai.c
@@ -0,0 +1,843 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ * Roger Nilsson <roger.xr.nilsson@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * 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/module.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/mfd/dbx500-prcmu.h>
+
+#include <mach/hardware.h>
+#include <mach/board-mop500-msp.h>
+
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "ux500_msp_i2s.h"
+#include "ux500_msp_dai.h"
+
+static int setup_pcm_multichan(struct snd_soc_dai *dai,
+ struct ux500_msp_config *msp_config)
+{
+ struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+ struct msp_multichannel_config *multi =
+ &msp_config->multichannel_config;
+
+ if (drvdata->slots > 1) {
+ msp_config->multichannel_configured = 1;
+
+ multi->tx_multichannel_enable = true;
+ multi->rx_multichannel_enable = true;
+ multi->rx_comparison_enable_mode = MSP_COMPARISON_DISABLED;
+
+ multi->tx_channel_0_enable = drvdata->tx_mask;
+ multi->tx_channel_1_enable = 0;
+ multi->tx_channel_2_enable = 0;
+ multi->tx_channel_3_enable = 0;
+
+ multi->rx_channel_0_enable = drvdata->rx_mask;
+ multi->rx_channel_1_enable = 0;
+ multi->rx_channel_2_enable = 0;
+ multi->rx_channel_3_enable = 0;
+
+ dev_dbg(dai->dev,
+ "%s: Multichannel enabled. Slots: %d, TX: %u, RX: %u\n",
+ __func__, drvdata->slots, multi->tx_channel_0_enable,
+ multi->rx_channel_0_enable);
+ }
+
+ return 0;
+}
+
+static int setup_frameper(struct snd_soc_dai *dai, unsigned int rate,
+ struct msp_protdesc *prot_desc)
+{
+ struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+ switch (drvdata->slots) {
+ case 1:
+ switch (rate) {
+ case 8000:
+ prot_desc->frame_period =
+ FRAME_PER_SINGLE_SLOT_8_KHZ;
+ break;
+
+ case 16000:
+ prot_desc->frame_period =
+ FRAME_PER_SINGLE_SLOT_16_KHZ;
+ break;
+
+ case 44100:
+ prot_desc->frame_period =
+ FRAME_PER_SINGLE_SLOT_44_1_KHZ;
+ break;
+
+ case 48000:
+ prot_desc->frame_period =
+ FRAME_PER_SINGLE_SLOT_48_KHZ;
+ break;
+
+ default:
+ dev_err(dai->dev,
+ "%s: Error: Unsupported sample-rate (freq = %d)!\n",
+ __func__, rate);
+ return -EINVAL;
+ }
+ break;
+
+ case 2:
+ prot_desc->frame_period = FRAME_PER_2_SLOTS;
+ break;
+
+ case 8:
+ prot_desc->frame_period = FRAME_PER_8_SLOTS;
+ break;
+
+ case 16:
+ prot_desc->frame_period = FRAME_PER_16_SLOTS;
+ break;
+ default:
+ dev_err(dai->dev,
+ "%s: Error: Unsupported slot-count (slots = %d)!\n",
+ __func__, drvdata->slots);
+ return -EINVAL;
+ }
+
+ prot_desc->clocks_per_frame =
+ prot_desc->frame_period+1;
+
+ dev_dbg(dai->dev, "%s: Clocks per frame: %u\n",
+ __func__,
+ prot_desc->clocks_per_frame);
+
+ return 0;
+}
+
+static int setup_pcm_framing(struct snd_soc_dai *dai, unsigned int rate,
+ struct msp_protdesc *prot_desc)
+{
+ struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+ u32 frame_length = MSP_FRAME_LEN_1;
+ prot_desc->frame_width = 0;
+
+ switch (drvdata->slots) {
+ case 1:
+ frame_length = MSP_FRAME_LEN_1;
+ break;
+
+ case 2:
+ frame_length = MSP_FRAME_LEN_2;
+ break;
+
+ case 8:
+ frame_length = MSP_FRAME_LEN_8;
+ break;
+
+ case 16:
+ frame_length = MSP_FRAME_LEN_16;
+ break;
+ default:
+ dev_err(dai->dev,
+ "%s: Error: Unsupported slot-count (slots = %d)!\n",
+ __func__, drvdata->slots);
+ return -EINVAL;
+ }
+
+ prot_desc->tx_frame_len_1 = frame_length;
+ prot_desc->rx_frame_len_1 = frame_length;
+ prot_desc->tx_frame_len_2 = frame_length;
+ prot_desc->rx_frame_len_2 = frame_length;
+
+ prot_desc->tx_elem_len_1 = MSP_ELEM_LEN_16;
+ prot_desc->rx_elem_len_1 = MSP_ELEM_LEN_16;
+ prot_desc->tx_elem_len_2 = MSP_ELEM_LEN_16;
+ prot_desc->rx_elem_len_2 = MSP_ELEM_LEN_16;
+
+ return setup_frameper(dai, rate, prot_desc);
+}
+
+static int setup_clocking(struct snd_soc_dai *dai,
+ unsigned int fmt,
+ struct ux500_msp_config *msp_config)
+{
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+
+ case SND_SOC_DAIFMT_NB_IF:
+ msp_config->tx_fsync_pol ^= 1 << TFSPOL_SHIFT;
+ msp_config->rx_fsync_pol ^= 1 << RFSPOL_SHIFT;
+
+ break;
+
+ default:
+ dev_err(dai->dev,
+ "%s: Error: Unsopported inversion (fmt = 0x%x)!\n",
+ __func__, fmt);
+
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ dev_dbg(dai->dev, "%s: Codec is master.\n", __func__);
+
+ msp_config->iodelay = 0x20;
+ msp_config->rx_fsync_sel = 0;
+ msp_config->tx_fsync_sel = 1 << TFSSEL_SHIFT;
+ msp_config->tx_clk_sel = 0;
+ msp_config->rx_clk_sel = 0;
+ msp_config->srg_clk_sel = 0x2 << SCKSEL_SHIFT;
+
+ break;
+
+ case SND_SOC_DAIFMT_CBS_CFS:
+ dev_dbg(dai->dev, "%s: Codec is slave.\n", __func__);
+
+ msp_config->tx_clk_sel = TX_CLK_SEL_SRG;
+ msp_config->tx_fsync_sel = TX_SYNC_SRG_PROG;
+ msp_config->rx_clk_sel = RX_CLK_SEL_SRG;
+ msp_config->rx_fsync_sel = RX_SYNC_SRG;
+ msp_config->srg_clk_sel = 1 << SCKSEL_SHIFT;
+
+ break;
+
+ default:
+ dev_err(dai->dev, "%s: Error: Unsopported master (fmt = 0x%x)!\n",
+ __func__, fmt);
+
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int setup_pcm_protdesc(struct snd_soc_dai *dai,
+ unsigned int fmt,
+ struct msp_protdesc *prot_desc)
+{
+ prot_desc->rx_phase_mode = MSP_SINGLE_PHASE;
+ prot_desc->tx_phase_mode = MSP_SINGLE_PHASE;
+ prot_desc->rx_phase2_start_mode = MSP_PHASE2_START_MODE_IMEDIATE;
+ prot_desc->tx_phase2_start_mode = MSP_PHASE2_START_MODE_IMEDIATE;
+ prot_desc->rx_byte_order = MSP_BTF_MS_BIT_FIRST;
+ prot_desc->tx_byte_order = MSP_BTF_MS_BIT_FIRST;
+ prot_desc->tx_fsync_pol = MSP_FSYNC_POL(MSP_FSYNC_POL_ACT_HI);
+ prot_desc->rx_fsync_pol = MSP_FSYNC_POL_ACT_HI << RFSPOL_SHIFT;
+
+ if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_DSP_A) {
+ dev_dbg(dai->dev, "%s: DSP_A.\n", __func__);
+ prot_desc->rx_clk_pol = MSP_RISING_EDGE;
+ prot_desc->tx_clk_pol = MSP_FALLING_EDGE;
+
+ prot_desc->rx_data_delay = MSP_DELAY_1;
+ prot_desc->tx_data_delay = MSP_DELAY_1;
+ } else {
+ dev_dbg(dai->dev, "%s: DSP_B.\n", __func__);
+ prot_desc->rx_clk_pol = MSP_FALLING_EDGE;
+ prot_desc->tx_clk_pol = MSP_RISING_EDGE;
+
+ prot_desc->rx_data_delay = MSP_DELAY_0;
+ prot_desc->tx_data_delay = MSP_DELAY_0;
+ }
+
+ prot_desc->rx_half_word_swap = MSP_SWAP_NONE;
+ prot_desc->tx_half_word_swap = MSP_SWAP_NONE;
+ prot_desc->compression_mode = MSP_COMPRESS_MODE_LINEAR;
+ prot_desc->expansion_mode = MSP_EXPAND_MODE_LINEAR;
+ prot_desc->frame_sync_ignore = MSP_FSYNC_IGNORE;
+
+ return 0;
+}
+
+static int setup_i2s_protdesc(struct msp_protdesc *prot_desc)
+{
+ prot_desc->rx_phase_mode = MSP_DUAL_PHASE;
+ prot_desc->tx_phase_mode = MSP_DUAL_PHASE;
+ prot_desc->rx_phase2_start_mode = MSP_PHASE2_START_MODE_FSYNC;
+ prot_desc->tx_phase2_start_mode = MSP_PHASE2_START_MODE_FSYNC;
+ prot_desc->rx_byte_order = MSP_BTF_MS_BIT_FIRST;
+ prot_desc->tx_byte_order = MSP_BTF_MS_BIT_FIRST;
+ prot_desc->tx_fsync_pol = MSP_FSYNC_POL(MSP_FSYNC_POL_ACT_LO);
+ prot_desc->rx_fsync_pol = MSP_FSYNC_POL_ACT_LO << RFSPOL_SHIFT;
+
+ prot_desc->rx_frame_len_1 = MSP_FRAME_LEN_1;
+ prot_desc->rx_frame_len_2 = MSP_FRAME_LEN_1;
+ prot_desc->tx_frame_len_1 = MSP_FRAME_LEN_1;
+ prot_desc->tx_frame_len_2 = MSP_FRAME_LEN_1;
+ prot_desc->rx_elem_len_1 = MSP_ELEM_LEN_16;
+ prot_desc->rx_elem_len_2 = MSP_ELEM_LEN_16;
+ prot_desc->tx_elem_len_1 = MSP_ELEM_LEN_16;
+ prot_desc->tx_elem_len_2 = MSP_ELEM_LEN_16;
+
+ prot_desc->rx_clk_pol = MSP_RISING_EDGE;
+ prot_desc->tx_clk_pol = MSP_FALLING_EDGE;
+
+ prot_desc->rx_data_delay = MSP_DELAY_0;
+ prot_desc->tx_data_delay = MSP_DELAY_0;
+
+ prot_desc->tx_half_word_swap = MSP_SWAP_NONE;
+ prot_desc->rx_half_word_swap = MSP_SWAP_NONE;
+ prot_desc->compression_mode = MSP_COMPRESS_MODE_LINEAR;
+ prot_desc->expansion_mode = MSP_EXPAND_MODE_LINEAR;
+ prot_desc->frame_sync_ignore = MSP_FSYNC_IGNORE;
+
+ return 0;
+}
+
+static int setup_msp_config(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai,
+ struct ux500_msp_config *msp_config)
+{
+ struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+ struct msp_protdesc *prot_desc = &msp_config->protdesc;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ unsigned int fmt = drvdata->fmt;
+ int ret;
+
+ memset(msp_config, 0, sizeof(*msp_config));
+
+ msp_config->f_inputclk = drvdata->master_clk;
+
+ msp_config->tx_fifo_config = TX_FIFO_ENABLE;
+ msp_config->rx_fifo_config = RX_FIFO_ENABLE;
+ msp_config->def_elem_len = 1;
+ msp_config->direction = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ MSP_DIR_TX : MSP_DIR_RX;
+ msp_config->data_size = MSP_DATA_BITS_32;
+ msp_config->frame_freq = runtime->rate;
+
+ dev_dbg(dai->dev, "%s: f_inputclk = %u, frame_freq = %u.\n",
+ __func__, msp_config->f_inputclk, msp_config->frame_freq);
+ /* To avoid division by zero */
+ prot_desc->clocks_per_frame = 1;
+
+ dev_dbg(dai->dev, "%s: rate: %u, channels: %d.\n", __func__,
+ runtime->rate, runtime->channels);
+ switch (fmt &
+ (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_MASTER_MASK)) {
+ case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
+ dev_dbg(dai->dev, "%s: SND_SOC_DAIFMT_I2S.\n", __func__);
+
+ msp_config->default_protdesc = 1;
+ msp_config->protocol = MSP_I2S_PROTOCOL;
+ break;
+
+ case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
+ dev_dbg(dai->dev, "%s: SND_SOC_DAIFMT_I2S.\n", __func__);
+
+ msp_config->data_size = MSP_DATA_BITS_16;
+ msp_config->protocol = MSP_I2S_PROTOCOL;
+
+ ret = setup_i2s_protdesc(prot_desc);
+ if (ret < 0)
+ return ret;
+
+ break;
+
+ case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM:
+ dev_dbg(dai->dev, "%s: PCM format.\n", __func__);
+
+ msp_config->data_size = MSP_DATA_BITS_16;
+ msp_config->protocol = MSP_PCM_PROTOCOL;
+
+ ret = setup_pcm_protdesc(dai, fmt, prot_desc);
+ if (ret < 0)
+ return ret;
+
+ ret = setup_pcm_multichan(dai, msp_config);
+ if (ret < 0)
+ return ret;
+
+ ret = setup_pcm_framing(dai, runtime->rate, prot_desc);
+ if (ret < 0)
+ return ret;
+
+ break;
+
+ default:
+ dev_err(dai->dev, "%s: Error: Unsopported format (%d)!\n",
+ __func__, fmt);
+ return -EINVAL;
+ }
+
+ return setup_clocking(dai, fmt, msp_config);
+}
+
+static int ux500_msp_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ int ret = 0;
+ struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+ dev_dbg(dai->dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id,
+ snd_pcm_stream_str(substream));
+
+ /* Enable regulator */
+ ret = regulator_enable(drvdata->reg_vape);
+ if (ret != 0) {
+ dev_err(drvdata->msp->dev,
+ "%s: Failed to enable regulator!\n", __func__);
+ return ret;
+ }
+
+ /* Enable clock */
+ dev_dbg(dai->dev, "%s: Enabling MSP-clock.\n", __func__);
+ clk_enable(drvdata->clk);
+
+ return 0;
+}
+
+static void ux500_msp_dai_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ int ret;
+ struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+ bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+
+ dev_dbg(dai->dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id,
+ snd_pcm_stream_str(substream));
+
+ if (drvdata->vape_opp_constraint == 1) {
+ prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP,
+ "ux500_msp_i2s", 50);
+ drvdata->vape_opp_constraint = 0;
+ }
+
+ if (ux500_msp_i2s_close(drvdata->msp,
+ is_playback ? MSP_DIR_TX : MSP_DIR_RX)) {
+ dev_err(dai->dev,
+ "%s: Error: MSP %d (%s): Unable to close i2s.\n",
+ __func__, dai->id, snd_pcm_stream_str(substream));
+ }
+
+ /* Disable clock */
+ clk_disable(drvdata->clk);
+
+ /* Disable regulator */
+ ret = regulator_disable(drvdata->reg_vape);
+ if (ret < 0)
+ dev_err(dai->dev,
+ "%s: ERROR: Failed to disable regulator (%d)!\n",
+ __func__, ret);
+}
+
+static int ux500_msp_dai_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ int ret = 0;
+ struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct ux500_msp_config msp_config;
+
+ dev_dbg(dai->dev, "%s: MSP %d (%s): Enter (rate = %d).\n", __func__,
+ dai->id, snd_pcm_stream_str(substream), runtime->rate);
+
+ setup_msp_config(substream, dai, &msp_config);
+
+ ret = ux500_msp_i2s_open(drvdata->msp, &msp_config);
+ if (ret < 0) {
+ dev_err(dai->dev, "%s: Error: msp_setup failed (ret = %d)!\n",
+ __func__, ret);
+ return ret;
+ }
+
+ /* Set OPP-level */
+ if ((drvdata->fmt & SND_SOC_DAIFMT_MASTER_MASK) &&
+ (drvdata->msp->f_bitclk > 19200000)) {
+ /* If the bit-clock is higher than 19.2MHz, Vape should be
+ * run in 100% OPP. Only when bit-clock is used (MSP master) */
+ prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP,
+ "ux500-msp-i2s", 100);
+ drvdata->vape_opp_constraint = 1;
+ } else {
+ prcmu_qos_update_requirement(PRCMU_QOS_APE_OPP,
+ "ux500-msp-i2s", 50);
+ drvdata->vape_opp_constraint = 0;
+ }
+
+ return ret;
+}
+
+static int ux500_msp_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ unsigned int mask, slots_active;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+ dev_dbg(dai->dev, "%s: MSP %d (%s): Enter.\n",
+ __func__, dai->id, snd_pcm_stream_str(substream));
+
+ switch (drvdata->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ 1, 2);
+ break;
+
+ case SND_SOC_DAIFMT_DSP_B:
+ case SND_SOC_DAIFMT_DSP_A:
+ mask = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ drvdata->tx_mask :
+ drvdata->rx_mask;
+
+ slots_active = hweight32(mask);
+ dev_dbg(dai->dev, "TDM-slots active: %d", slots_active);
+
+ snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ slots_active, slots_active);
+ break;
+
+ default:
+ dev_err(dai->dev,
+ "%s: Error: Unsupported protocol (fmt = 0x%x)!\n",
+ __func__, drvdata->fmt);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ux500_msp_dai_set_dai_fmt(struct snd_soc_dai *dai,
+ unsigned int fmt)
+{
+ struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+ dev_dbg(dai->dev, "%s: MSP %d: Enter.\n", __func__, dai->id);
+
+ switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK |
+ SND_SOC_DAIFMT_MASTER_MASK)) {
+ case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM:
+ case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS:
+ case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
+ break;
+
+ default:
+ dev_err(dai->dev,
+ "%s: Error: Unsupported protocol/master (fmt = 0x%x)!\n",
+ __func__, drvdata->fmt);
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ case SND_SOC_DAIFMT_NB_IF:
+ case SND_SOC_DAIFMT_IB_IF:
+ break;
+
+ default:
+ dev_err(dai->dev,
+ "%s: Error: Unsupported inversion (fmt = 0x%x)!\n",
+ __func__, drvdata->fmt);
+ return -EINVAL;
+ }
+
+ drvdata->fmt = fmt;
+ return 0;
+}
+
+static int ux500_msp_dai_set_tdm_slot(struct snd_soc_dai *dai,
+ unsigned int tx_mask,
+ unsigned int rx_mask,
+ int slots, int slot_width)
+{
+ struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+ unsigned int cap;
+
+ switch (slots) {
+ case 1:
+ cap = 0x01;
+ break;
+ case 2:
+ cap = 0x03;
+ break;
+ case 8:
+ cap = 0xFF;
+ break;
+ case 16:
+ cap = 0xFFFF;
+ break;
+ default:
+ dev_err(dai->dev, "%s: Error: Unsupported slot-count (%d)!\n",
+ __func__, slots);
+ return -EINVAL;
+ }
+ drvdata->slots = slots;
+
+ if (!(slot_width == 16)) {
+ dev_err(dai->dev, "%s: Error: Unsupported slot-width (%d)!\n",
+ __func__, slot_width);
+ return -EINVAL;
+ }
+ drvdata->slot_width = slot_width;
+
+ drvdata->tx_mask = tx_mask & cap;
+ drvdata->rx_mask = rx_mask & cap;
+
+ return 0;
+}
+
+static int ux500_msp_dai_set_dai_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+ dev_dbg(dai->dev, "%s: MSP %d: Enter. clk-id: %d, freq: %u.\n",
+ __func__, dai->id, clk_id, freq);
+
+ switch (clk_id) {
+ case UX500_MSP_MASTER_CLOCK:
+ drvdata->master_clk = freq;
+ break;
+
+ default:
+ dev_err(dai->dev, "%s: MSP %d: Invalid clk-id (%d)!\n",
+ __func__, dai->id, clk_id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ux500_msp_dai_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ int ret = 0;
+ struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+ dev_dbg(dai->dev, "%s: MSP %d (%s): Enter (msp->id = %d, cmd = %d).\n",
+ __func__, dai->id, snd_pcm_stream_str(substream),
+ (int)drvdata->msp->id, cmd);
+
+ ret = ux500_msp_i2s_trigger(drvdata->msp, cmd, substream->stream);
+
+ return ret;
+}
+
+static int ux500_msp_dai_probe(struct snd_soc_dai *dai)
+{
+ struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(dai->dev);
+
+ drvdata->playback_dma_data.dma_cfg = drvdata->msp->dma_cfg_tx;
+ drvdata->capture_dma_data.dma_cfg = drvdata->msp->dma_cfg_rx;
+
+ dai->playback_dma_data = &drvdata->playback_dma_data;
+ dai->capture_dma_data = &drvdata->capture_dma_data;
+
+ drvdata->playback_dma_data.data_size = drvdata->slot_width;
+ drvdata->capture_dma_data.data_size = drvdata->slot_width;
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops ux500_msp_dai_ops[] = {
+ {
+ .set_sysclk = ux500_msp_dai_set_dai_sysclk,
+ .set_fmt = ux500_msp_dai_set_dai_fmt,
+ .set_tdm_slot = ux500_msp_dai_set_tdm_slot,
+ .startup = ux500_msp_dai_startup,
+ .shutdown = ux500_msp_dai_shutdown,
+ .prepare = ux500_msp_dai_prepare,
+ .trigger = ux500_msp_dai_trigger,
+ .hw_params = ux500_msp_dai_hw_params,
+ }
+};
+
+static struct snd_soc_dai_driver ux500_msp_dai_drv[UX500_NBR_OF_DAI] = {
+ {
+ .name = "ux500-msp-i2s.0",
+ .probe = ux500_msp_dai_probe,
+ .id = 0,
+ .suspend = NULL,
+ .resume = NULL,
+ .playback = {
+ .channels_min = UX500_MSP_MIN_CHANNELS,
+ .channels_max = UX500_MSP_MAX_CHANNELS,
+ .rates = UX500_I2S_RATES,
+ .formats = UX500_I2S_FORMATS,
+ },
+ .capture = {
+ .channels_min = UX500_MSP_MIN_CHANNELS,
+ .channels_max = UX500_MSP_MAX_CHANNELS,
+ .rates = UX500_I2S_RATES,
+ .formats = UX500_I2S_FORMATS,
+ },
+ .ops = ux500_msp_dai_ops,
+ },
+ {
+ .name = "ux500-msp-i2s.1",
+ .probe = ux500_msp_dai_probe,
+ .id = 1,
+ .suspend = NULL,
+ .resume = NULL,
+ .playback = {
+ .channels_min = UX500_MSP_MIN_CHANNELS,
+ .channels_max = UX500_MSP_MAX_CHANNELS,
+ .rates = UX500_I2S_RATES,
+ .formats = UX500_I2S_FORMATS,
+ },
+ .capture = {
+ .channels_min = UX500_MSP_MIN_CHANNELS,
+ .channels_max = UX500_MSP_MAX_CHANNELS,
+ .rates = UX500_I2S_RATES,
+ .formats = UX500_I2S_FORMATS,
+ },
+ .ops = ux500_msp_dai_ops,
+ },
+ {
+ .name = "ux500-msp-i2s.2",
+ .id = 2,
+ .probe = ux500_msp_dai_probe,
+ .suspend = NULL,
+ .resume = NULL,
+ .playback = {
+ .channels_min = UX500_MSP_MIN_CHANNELS,
+ .channels_max = UX500_MSP_MAX_CHANNELS,
+ .rates = UX500_I2S_RATES,
+ .formats = UX500_I2S_FORMATS,
+ },
+ .capture = {
+ .channels_min = UX500_MSP_MIN_CHANNELS,
+ .channels_max = UX500_MSP_MAX_CHANNELS,
+ .rates = UX500_I2S_RATES,
+ .formats = UX500_I2S_FORMATS,
+ },
+ .ops = ux500_msp_dai_ops,
+ },
+ {
+ .name = "ux500-msp-i2s.3",
+ .probe = ux500_msp_dai_probe,
+ .id = 3,
+ .suspend = NULL,
+ .resume = NULL,
+ .playback = {
+ .channels_min = UX500_MSP_MIN_CHANNELS,
+ .channels_max = UX500_MSP_MAX_CHANNELS,
+ .rates = UX500_I2S_RATES,
+ .formats = UX500_I2S_FORMATS,
+ },
+ .capture = {
+ .channels_min = UX500_MSP_MIN_CHANNELS,
+ .channels_max = UX500_MSP_MAX_CHANNELS,
+ .rates = UX500_I2S_RATES,
+ .formats = UX500_I2S_FORMATS,
+ },
+ .ops = ux500_msp_dai_ops,
+ },
+};
+
+static int __devinit ux500_msp_drv_probe(struct platform_device *pdev)
+{
+ struct ux500_msp_i2s_drvdata *drvdata;
+ int ret = 0;
+
+ dev_dbg(&pdev->dev, "%s: Enter (pdev->name = %s).\n", __func__,
+ pdev->name);
+
+ drvdata = devm_kzalloc(&pdev->dev,
+ sizeof(struct ux500_msp_i2s_drvdata),
+ GFP_KERNEL);
+ drvdata->fmt = 0;
+ drvdata->slots = 1;
+ drvdata->tx_mask = 0x01;
+ drvdata->rx_mask = 0x01;
+ drvdata->slot_width = 16;
+ drvdata->master_clk = MSP_INPUT_FREQ_APB;
+
+ drvdata->reg_vape = devm_regulator_get(&pdev->dev, "v-ape");
+ if (IS_ERR(drvdata->reg_vape)) {
+ ret = (int)PTR_ERR(drvdata->reg_vape);
+ dev_err(&pdev->dev,
+ "%s: ERROR: Failed to get Vape supply (%d)!\n",
+ __func__, ret);
+ return ret;
+ }
+ prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, (char *)pdev->name, 50);
+
+ drvdata->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(drvdata->clk)) {
+ ret = (int)PTR_ERR(drvdata->clk);
+ dev_err(&pdev->dev, "%s: ERROR: clk_get failed (%d)!\n",
+ __func__, ret);
+ goto err_clk;
+ }
+
+ ret = ux500_msp_i2s_init_msp(pdev, &drvdata->msp,
+ pdev->dev.platform_data);
+ if (!drvdata->msp) {
+ dev_err(&pdev->dev,
+ "%s: ERROR: Failed to init MSP-struct (%d)!",
+ __func__, ret);
+ goto err_init_msp;
+ }
+ dev_set_drvdata(&pdev->dev, drvdata);
+
+ ret = snd_soc_register_dai(&pdev->dev,
+ &ux500_msp_dai_drv[drvdata->msp->id]);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Error: %s: Failed to register MSP%d!\n",
+ __func__, drvdata->msp->id);
+ goto err_init_msp;
+ }
+
+ return 0;
+
+err_init_msp:
+ clk_put(drvdata->clk);
+
+err_clk:
+ devm_regulator_put(drvdata->reg_vape);
+
+ return ret;
+}
+
+static int __devexit ux500_msp_drv_remove(struct platform_device *pdev)
+{
+ struct ux500_msp_i2s_drvdata *drvdata = dev_get_drvdata(&pdev->dev);
+
+ snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(ux500_msp_dai_drv));
+
+ devm_regulator_put(drvdata->reg_vape);
+ prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "ux500_msp_i2s");
+
+ clk_put(drvdata->clk);
+
+ ux500_msp_i2s_cleanup_msp(pdev, drvdata->msp);
+
+ return 0;
+}
+
+static struct platform_driver msp_i2s_driver = {
+ .driver = {
+ .name = "ux500-msp-i2s",
+ .owner = THIS_MODULE,
+ },
+ .probe = ux500_msp_drv_probe,
+ .remove = ux500_msp_drv_remove,
+};
+module_platform_driver(msp_i2s_driver);
+
+MODULE_LICENSE("GPLv2");
diff --git a/sound/soc/ux500/ux500_msp_dai.h b/sound/soc/ux500/ux500_msp_dai.h
new file mode 100644
index 000000000000..98202a34a5dd
--- /dev/null
+++ b/sound/soc/ux500/ux500_msp_dai.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ * Roger Nilsson <roger.xr.nilsson@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * 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 UX500_msp_dai_H
+#define UX500_msp_dai_H
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+
+#include "ux500_msp_i2s.h"
+
+#define UX500_NBR_OF_DAI 4
+
+#define UX500_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+#define UX500_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+
+#define FRAME_PER_SINGLE_SLOT_8_KHZ 31
+#define FRAME_PER_SINGLE_SLOT_16_KHZ 124
+#define FRAME_PER_SINGLE_SLOT_44_1_KHZ 63
+#define FRAME_PER_SINGLE_SLOT_48_KHZ 49
+#define FRAME_PER_2_SLOTS 31
+#define FRAME_PER_8_SLOTS 138
+#define FRAME_PER_16_SLOTS 277
+
+#ifndef CONFIG_SND_SOC_UX500_AB5500
+#define UX500_MSP_INTERNAL_CLOCK_FREQ 40000000
+#define UX500_MSP1_INTERNAL_CLOCK_FREQ UX500_MSP_INTERNAL_CLOCK_FREQ
+#else
+#define UX500_MSP_INTERNAL_CLOCK_FREQ 13000000
+#define UX500_MSP1_INTERNAL_CLOCK_FREQ (UX500_MSP_INTERNAL_CLOCK_FREQ * 2)
+#endif
+
+#define UX500_MSP_MIN_CHANNELS 1
+#define UX500_MSP_MAX_CHANNELS 8
+
+#define PLAYBACK_CONFIGURED 1
+#define CAPTURE_CONFIGURED 2
+
+enum ux500_msp_clock_id {
+ UX500_MSP_MASTER_CLOCK,
+};
+
+struct ux500_msp_i2s_drvdata {
+ struct ux500_msp *msp;
+ struct regulator *reg_vape;
+ struct ux500_msp_dma_params playback_dma_data;
+ struct ux500_msp_dma_params capture_dma_data;
+ unsigned int fmt;
+ unsigned int tx_mask;
+ unsigned int rx_mask;
+ int slots;
+ int slot_width;
+ u8 configured;
+ int data_delay;
+
+ /* Clocks */
+ unsigned int master_clk;
+ struct clk *clk;
+
+ /* Regulators */
+ int vape_opp_constraint;
+};
+
+int ux500_msp_dai_set_data_delay(struct snd_soc_dai *dai, int delay);
+
+#endif
diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c
new file mode 100644
index 000000000000..496dec10c96e
--- /dev/null
+++ b/sound/soc/ux500/ux500_msp_i2s.c
@@ -0,0 +1,742 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ * Roger Nilsson <roger.xr.nilsson@stericsson.com>,
+ * Sandeep Kaushik <sandeep.kaushik@st.com>
+ * for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include <mach/hardware.h>
+#include <mach/board-mop500-msp.h>
+
+#include <sound/soc.h>
+
+#include "ux500_msp_i2s.h"
+
+ /* Protocol desciptors */
+static const struct msp_protdesc prot_descs[] = {
+ { /* I2S */
+ MSP_SINGLE_PHASE,
+ MSP_SINGLE_PHASE,
+ MSP_PHASE2_START_MODE_IMEDIATE,
+ MSP_PHASE2_START_MODE_IMEDIATE,
+ MSP_BTF_MS_BIT_FIRST,
+ MSP_BTF_MS_BIT_FIRST,
+ MSP_FRAME_LEN_1,
+ MSP_FRAME_LEN_1,
+ MSP_FRAME_LEN_1,
+ MSP_FRAME_LEN_1,
+ MSP_ELEM_LEN_32,
+ MSP_ELEM_LEN_32,
+ MSP_ELEM_LEN_32,
+ MSP_ELEM_LEN_32,
+ MSP_DELAY_1,
+ MSP_DELAY_1,
+ MSP_RISING_EDGE,
+ MSP_FALLING_EDGE,
+ MSP_FSYNC_POL_ACT_LO,
+ MSP_FSYNC_POL_ACT_LO,
+ MSP_SWAP_NONE,
+ MSP_SWAP_NONE,
+ MSP_COMPRESS_MODE_LINEAR,
+ MSP_EXPAND_MODE_LINEAR,
+ MSP_FSYNC_IGNORE,
+ 31,
+ 15,
+ 32,
+ }, { /* PCM */
+ MSP_DUAL_PHASE,
+ MSP_DUAL_PHASE,
+ MSP_PHASE2_START_MODE_FSYNC,
+ MSP_PHASE2_START_MODE_FSYNC,
+ MSP_BTF_MS_BIT_FIRST,
+ MSP_BTF_MS_BIT_FIRST,
+ MSP_FRAME_LEN_1,
+ MSP_FRAME_LEN_1,
+ MSP_FRAME_LEN_1,
+ MSP_FRAME_LEN_1,
+ MSP_ELEM_LEN_16,
+ MSP_ELEM_LEN_16,
+ MSP_ELEM_LEN_16,
+ MSP_ELEM_LEN_16,
+ MSP_DELAY_0,
+ MSP_DELAY_0,
+ MSP_RISING_EDGE,
+ MSP_FALLING_EDGE,
+ MSP_FSYNC_POL_ACT_HI,
+ MSP_FSYNC_POL_ACT_HI,
+ MSP_SWAP_NONE,
+ MSP_SWAP_NONE,
+ MSP_COMPRESS_MODE_LINEAR,
+ MSP_EXPAND_MODE_LINEAR,
+ MSP_FSYNC_IGNORE,
+ 255,
+ 0,
+ 256,
+ }, { /* Companded PCM */
+ MSP_SINGLE_PHASE,
+ MSP_SINGLE_PHASE,
+ MSP_PHASE2_START_MODE_FSYNC,
+ MSP_PHASE2_START_MODE_FSYNC,
+ MSP_BTF_MS_BIT_FIRST,
+ MSP_BTF_MS_BIT_FIRST,
+ MSP_FRAME_LEN_1,
+ MSP_FRAME_LEN_1,
+ MSP_FRAME_LEN_1,
+ MSP_FRAME_LEN_1,
+ MSP_ELEM_LEN_8,
+ MSP_ELEM_LEN_8,
+ MSP_ELEM_LEN_8,
+ MSP_ELEM_LEN_8,
+ MSP_DELAY_0,
+ MSP_DELAY_0,
+ MSP_RISING_EDGE,
+ MSP_RISING_EDGE,
+ MSP_FSYNC_POL_ACT_HI,
+ MSP_FSYNC_POL_ACT_HI,
+ MSP_SWAP_NONE,
+ MSP_SWAP_NONE,
+ MSP_COMPRESS_MODE_LINEAR,
+ MSP_EXPAND_MODE_LINEAR,
+ MSP_FSYNC_IGNORE,
+ 255,
+ 0,
+ 256,
+ },
+};
+
+static void set_prot_desc_tx(struct ux500_msp *msp,
+ struct msp_protdesc *protdesc,
+ enum msp_data_size data_size)
+{
+ u32 temp_reg = 0;
+
+ temp_reg |= MSP_P2_ENABLE_BIT(protdesc->tx_phase_mode);
+ temp_reg |= MSP_P2_START_MODE_BIT(protdesc->tx_phase2_start_mode);
+ temp_reg |= MSP_P1_FRAME_LEN_BITS(protdesc->tx_frame_len_1);
+ temp_reg |= MSP_P2_FRAME_LEN_BITS(protdesc->tx_frame_len_2);
+ if (msp->def_elem_len) {
+ temp_reg |= MSP_P1_ELEM_LEN_BITS(protdesc->tx_elem_len_1);
+ temp_reg |= MSP_P2_ELEM_LEN_BITS(protdesc->tx_elem_len_2);
+ } else {
+ temp_reg |= MSP_P1_ELEM_LEN_BITS(data_size);
+ temp_reg |= MSP_P2_ELEM_LEN_BITS(data_size);
+ }
+ temp_reg |= MSP_DATA_DELAY_BITS(protdesc->tx_data_delay);
+ temp_reg |= MSP_SET_ENDIANNES_BIT(protdesc->tx_byte_order);
+ temp_reg |= MSP_FSYNC_POL(protdesc->tx_fsync_pol);
+ temp_reg |= MSP_DATA_WORD_SWAP(protdesc->tx_half_word_swap);
+ temp_reg |= MSP_SET_COMPANDING_MODE(protdesc->compression_mode);
+ temp_reg |= MSP_SET_FSYNC_IGNORE(protdesc->frame_sync_ignore);
+
+ writel(temp_reg, msp->registers + MSP_TCF);
+}
+
+static void set_prot_desc_rx(struct ux500_msp *msp,
+ struct msp_protdesc *protdesc,
+ enum msp_data_size data_size)
+{
+ u32 temp_reg = 0;
+
+ temp_reg |= MSP_P2_ENABLE_BIT(protdesc->rx_phase_mode);
+ temp_reg |= MSP_P2_START_MODE_BIT(protdesc->rx_phase2_start_mode);
+ temp_reg |= MSP_P1_FRAME_LEN_BITS(protdesc->rx_frame_len_1);
+ temp_reg |= MSP_P2_FRAME_LEN_BITS(protdesc->rx_frame_len_2);
+ if (msp->def_elem_len) {
+ temp_reg |= MSP_P1_ELEM_LEN_BITS(protdesc->rx_elem_len_1);
+ temp_reg |= MSP_P2_ELEM_LEN_BITS(protdesc->rx_elem_len_2);
+ } else {
+ temp_reg |= MSP_P1_ELEM_LEN_BITS(data_size);
+ temp_reg |= MSP_P2_ELEM_LEN_BITS(data_size);
+ }
+
+ temp_reg |= MSP_DATA_DELAY_BITS(protdesc->rx_data_delay);
+ temp_reg |= MSP_SET_ENDIANNES_BIT(protdesc->rx_byte_order);
+ temp_reg |= MSP_FSYNC_POL(protdesc->rx_fsync_pol);
+ temp_reg |= MSP_DATA_WORD_SWAP(protdesc->rx_half_word_swap);
+ temp_reg |= MSP_SET_COMPANDING_MODE(protdesc->expansion_mode);
+ temp_reg |= MSP_SET_FSYNC_IGNORE(protdesc->frame_sync_ignore);
+
+ writel(temp_reg, msp->registers + MSP_RCF);
+}
+
+static int configure_protocol(struct ux500_msp *msp,
+ struct ux500_msp_config *config)
+{
+ struct msp_protdesc *protdesc;
+ enum msp_data_size data_size;
+ u32 temp_reg = 0;
+
+ data_size = config->data_size;
+ msp->def_elem_len = config->def_elem_len;
+ if (config->default_protdesc == 1) {
+ if (config->protocol >= MSP_INVALID_PROTOCOL) {
+ dev_err(msp->dev, "%s: ERROR: Invalid protocol!\n",
+ __func__);
+ return -EINVAL;
+ }
+ protdesc =
+ (struct msp_protdesc *)&prot_descs[config->protocol];
+ } else {
+ protdesc = (struct msp_protdesc *)&config->protdesc;
+ }
+
+ if (data_size < MSP_DATA_BITS_DEFAULT || data_size > MSP_DATA_BITS_32) {
+ dev_err(msp->dev,
+ "%s: ERROR: Invalid data-size requested (data_size = %d)!\n",
+ __func__, data_size);
+ return -EINVAL;
+ }
+
+ if (config->direction & MSP_DIR_TX)
+ set_prot_desc_tx(msp, protdesc, data_size);
+ if (config->direction & MSP_DIR_RX)
+ set_prot_desc_rx(msp, protdesc, data_size);
+
+ /* The code below should not be separated. */
+ temp_reg = readl(msp->registers + MSP_GCR) & ~TX_CLK_POL_RISING;
+ temp_reg |= MSP_TX_CLKPOL_BIT(~protdesc->tx_clk_pol);
+ writel(temp_reg, msp->registers + MSP_GCR);
+ temp_reg = readl(msp->registers + MSP_GCR) & ~RX_CLK_POL_RISING;
+ temp_reg |= MSP_RX_CLKPOL_BIT(protdesc->rx_clk_pol);
+ writel(temp_reg, msp->registers + MSP_GCR);
+
+ return 0;
+}
+
+static int setup_bitclk(struct ux500_msp *msp, struct ux500_msp_config *config)
+{
+ u32 reg_val_GCR;
+ u32 frame_per = 0;
+ u32 sck_div = 0;
+ u32 frame_width = 0;
+ u32 temp_reg = 0;
+ struct msp_protdesc *protdesc = NULL;
+
+ reg_val_GCR = readl(msp->registers + MSP_GCR);
+ writel(reg_val_GCR & ~SRG_ENABLE, msp->registers + MSP_GCR);
+
+ if (config->default_protdesc)
+ protdesc =
+ (struct msp_protdesc *)&prot_descs[config->protocol];
+ else
+ protdesc = (struct msp_protdesc *)&config->protdesc;
+
+ switch (config->protocol) {
+ case MSP_PCM_PROTOCOL:
+ case MSP_PCM_COMPAND_PROTOCOL:
+ frame_width = protdesc->frame_width;
+ sck_div = config->f_inputclk / (config->frame_freq *
+ (protdesc->clocks_per_frame));
+ frame_per = protdesc->frame_period;
+ break;
+ case MSP_I2S_PROTOCOL:
+ frame_width = protdesc->frame_width;
+ sck_div = config->f_inputclk / (config->frame_freq *
+ (protdesc->clocks_per_frame));
+ frame_per = protdesc->frame_period;
+ break;
+ default:
+ dev_err(msp->dev, "%s: ERROR: Unknown protocol (%d)!\n",
+ __func__,
+ config->protocol);
+ return -EINVAL;
+ }
+
+ temp_reg = (sck_div - 1) & SCK_DIV_MASK;
+ temp_reg |= FRAME_WIDTH_BITS(frame_width);
+ temp_reg |= FRAME_PERIOD_BITS(frame_per);
+ writel(temp_reg, msp->registers + MSP_SRG);
+
+ msp->f_bitclk = (config->f_inputclk)/(sck_div + 1);
+
+ /* Enable bit-clock */
+ udelay(100);
+ reg_val_GCR = readl(msp->registers + MSP_GCR);
+ writel(reg_val_GCR | SRG_ENABLE, msp->registers + MSP_GCR);
+ udelay(100);
+
+ return 0;
+}
+
+static int configure_multichannel(struct ux500_msp *msp,
+ struct ux500_msp_config *config)
+{
+ struct msp_protdesc *protdesc;
+ struct msp_multichannel_config *mcfg;
+ u32 reg_val_MCR;
+
+ if (config->default_protdesc == 1) {
+ if (config->protocol >= MSP_INVALID_PROTOCOL) {
+ dev_err(msp->dev,
+ "%s: ERROR: Invalid protocol (%d)!\n",
+ __func__, config->protocol);
+ return -EINVAL;
+ }
+ protdesc = (struct msp_protdesc *)
+ &prot_descs[config->protocol];
+ } else {
+ protdesc = (struct msp_protdesc *)&config->protdesc;
+ }
+
+ mcfg = &config->multichannel_config;
+ if (mcfg->tx_multichannel_enable) {
+ if (protdesc->tx_phase_mode == MSP_SINGLE_PHASE) {
+ reg_val_MCR = readl(msp->registers + MSP_MCR);
+ writel(reg_val_MCR | (mcfg->tx_multichannel_enable ?
+ 1 << TMCEN_BIT : 0),
+ msp->registers + MSP_MCR);
+ writel(mcfg->tx_channel_0_enable,
+ msp->registers + MSP_TCE0);
+ writel(mcfg->tx_channel_1_enable,
+ msp->registers + MSP_TCE1);
+ writel(mcfg->tx_channel_2_enable,
+ msp->registers + MSP_TCE2);
+ writel(mcfg->tx_channel_3_enable,
+ msp->registers + MSP_TCE3);
+ } else {
+ dev_err(msp->dev,
+ "%s: ERROR: Only single-phase supported (TX-mode: %d)!\n",
+ __func__, protdesc->tx_phase_mode);
+ return -EINVAL;
+ }
+ }
+ if (mcfg->rx_multichannel_enable) {
+ if (protdesc->rx_phase_mode == MSP_SINGLE_PHASE) {
+ reg_val_MCR = readl(msp->registers + MSP_MCR);
+ writel(reg_val_MCR | (mcfg->rx_multichannel_enable ?
+ 1 << RMCEN_BIT : 0),
+ msp->registers + MSP_MCR);
+ writel(mcfg->rx_channel_0_enable,
+ msp->registers + MSP_RCE0);
+ writel(mcfg->rx_channel_1_enable,
+ msp->registers + MSP_RCE1);
+ writel(mcfg->rx_channel_2_enable,
+ msp->registers + MSP_RCE2);
+ writel(mcfg->rx_channel_3_enable,
+ msp->registers + MSP_RCE3);
+ } else {
+ dev_err(msp->dev,
+ "%s: ERROR: Only single-phase supported (RX-mode: %d)!\n",
+ __func__, protdesc->rx_phase_mode);
+ return -EINVAL;
+ }
+ if (mcfg->rx_comparison_enable_mode) {
+ reg_val_MCR = readl(msp->registers + MSP_MCR);
+ writel(reg_val_MCR |
+ (mcfg->rx_comparison_enable_mode << RCMPM_BIT),
+ msp->registers + MSP_MCR);
+
+ writel(mcfg->comparison_mask,
+ msp->registers + MSP_RCM);
+ writel(mcfg->comparison_value,
+ msp->registers + MSP_RCV);
+
+ }
+ }
+
+ return 0;
+}
+
+static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config)
+{
+ int status = 0;
+ u32 reg_val_DMACR, reg_val_GCR;
+
+ /* Check msp state whether in RUN or CONFIGURED Mode */
+ if ((msp->msp_state == MSP_STATE_IDLE) && (msp->plat_init)) {
+ status = msp->plat_init();
+ if (status) {
+ dev_err(msp->dev, "%s: ERROR: Failed to init MSP (%d)!\n",
+ __func__, status);
+ return status;
+ }
+ }
+
+ /* Configure msp with protocol dependent settings */
+ configure_protocol(msp, config);
+ setup_bitclk(msp, config);
+ if (config->multichannel_configured == 1) {
+ status = configure_multichannel(msp, config);
+ if (status)
+ dev_warn(msp->dev,
+ "%s: WARN: configure_multichannel failed (%d)!\n",
+ __func__, status);
+ }
+
+ /* Make sure the correct DMA-directions are configured */
+ if ((config->direction & MSP_DIR_RX) && (!msp->dma_cfg_rx)) {
+ dev_err(msp->dev, "%s: ERROR: MSP RX-mode is not configured!",
+ __func__);
+ return -EINVAL;
+ }
+ if ((config->direction == MSP_DIR_TX) && (!msp->dma_cfg_tx)) {
+ dev_err(msp->dev, "%s: ERROR: MSP TX-mode is not configured!",
+ __func__);
+ return -EINVAL;
+ }
+
+ reg_val_DMACR = readl(msp->registers + MSP_DMACR);
+ if (config->direction & MSP_DIR_RX)
+ reg_val_DMACR |= RX_DMA_ENABLE;
+ if (config->direction & MSP_DIR_TX)
+ reg_val_DMACR |= TX_DMA_ENABLE;
+ writel(reg_val_DMACR, msp->registers + MSP_DMACR);
+
+ writel(config->iodelay, msp->registers + MSP_IODLY);
+
+ /* Enable frame generation logic */
+ reg_val_GCR = readl(msp->registers + MSP_GCR);
+ writel(reg_val_GCR | FRAME_GEN_ENABLE, msp->registers + MSP_GCR);
+
+ return status;
+}
+
+static void flush_fifo_rx(struct ux500_msp *msp)
+{
+ u32 reg_val_DR, reg_val_GCR, reg_val_FLR;
+ u32 limit = 32;
+
+ reg_val_GCR = readl(msp->registers + MSP_GCR);
+ writel(reg_val_GCR | RX_ENABLE, msp->registers + MSP_GCR);
+
+ reg_val_FLR = readl(msp->registers + MSP_FLR);
+ while (!(reg_val_FLR & RX_FIFO_EMPTY) && limit--) {
+ reg_val_DR = readl(msp->registers + MSP_DR);
+ reg_val_FLR = readl(msp->registers + MSP_FLR);
+ }
+
+ writel(reg_val_GCR, msp->registers + MSP_GCR);
+}
+
+static void flush_fifo_tx(struct ux500_msp *msp)
+{
+ u32 reg_val_TSTDR, reg_val_GCR, reg_val_FLR;
+ u32 limit = 32;
+
+ reg_val_GCR = readl(msp->registers + MSP_GCR);
+ writel(reg_val_GCR | TX_ENABLE, msp->registers + MSP_GCR);
+ writel(MSP_ITCR_ITEN | MSP_ITCR_TESTFIFO, msp->registers + MSP_ITCR);
+
+ reg_val_FLR = readl(msp->registers + MSP_FLR);
+ while (!(reg_val_FLR & TX_FIFO_EMPTY) && limit--) {
+ reg_val_TSTDR = readl(msp->registers + MSP_TSTDR);
+ reg_val_FLR = readl(msp->registers + MSP_FLR);
+ }
+ writel(0x0, msp->registers + MSP_ITCR);
+ writel(reg_val_GCR, msp->registers + MSP_GCR);
+}
+
+int ux500_msp_i2s_open(struct ux500_msp *msp,
+ struct ux500_msp_config *config)
+{
+ u32 old_reg, new_reg, mask;
+ int res;
+ unsigned int tx_sel, rx_sel, tx_busy, rx_busy;
+
+ if (in_interrupt()) {
+ dev_err(msp->dev,
+ "%s: ERROR: Open called in interrupt context!\n",
+ __func__);
+ return -1;
+ }
+
+ tx_sel = (config->direction & MSP_DIR_TX) > 0;
+ rx_sel = (config->direction & MSP_DIR_RX) > 0;
+ if (!tx_sel && !rx_sel) {
+ dev_err(msp->dev, "%s: Error: No direction selected!\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ tx_busy = (msp->dir_busy & MSP_DIR_TX) > 0;
+ rx_busy = (msp->dir_busy & MSP_DIR_RX) > 0;
+ if (tx_busy && tx_sel) {
+ dev_err(msp->dev, "%s: Error: TX is in use!\n", __func__);
+ return -EBUSY;
+ }
+ if (rx_busy && rx_sel) {
+ dev_err(msp->dev, "%s: Error: RX is in use!\n", __func__);
+ return -EBUSY;
+ }
+
+ msp->dir_busy |= (tx_sel ? MSP_DIR_TX : 0) | (rx_sel ? MSP_DIR_RX : 0);
+
+ /* First do the global config register */
+ mask = RX_CLK_SEL_MASK | TX_CLK_SEL_MASK | RX_FSYNC_MASK |
+ TX_FSYNC_MASK | RX_SYNC_SEL_MASK | TX_SYNC_SEL_MASK |
+ RX_FIFO_ENABLE_MASK | TX_FIFO_ENABLE_MASK | SRG_CLK_SEL_MASK |
+ LOOPBACK_MASK | TX_EXTRA_DELAY_MASK;
+
+ new_reg = (config->tx_clk_sel | config->rx_clk_sel |
+ config->rx_fsync_pol | config->tx_fsync_pol |
+ config->rx_fsync_sel | config->tx_fsync_sel |
+ config->rx_fifo_config | config->tx_fifo_config |
+ config->srg_clk_sel | config->loopback_enable |
+ config->tx_data_enable);
+
+ old_reg = readl(msp->registers + MSP_GCR);
+ old_reg &= ~mask;
+ new_reg |= old_reg;
+ writel(new_reg, msp->registers + MSP_GCR);
+
+ res = enable_msp(msp, config);
+ if (res < 0) {
+ dev_err(msp->dev, "%s: ERROR: enable_msp failed (%d)!\n",
+ __func__, res);
+ return -EBUSY;
+ }
+ if (config->loopback_enable & 0x80)
+ msp->loopback_enable = 1;
+
+ /* Flush FIFOs */
+ flush_fifo_tx(msp);
+ flush_fifo_rx(msp);
+
+ msp->msp_state = MSP_STATE_CONFIGURED;
+ return 0;
+}
+
+static void disable_msp_rx(struct ux500_msp *msp)
+{
+ u32 reg_val_GCR, reg_val_DMACR, reg_val_IMSC;
+
+ reg_val_GCR = readl(msp->registers + MSP_GCR);
+ writel(reg_val_GCR & ~RX_ENABLE, msp->registers + MSP_GCR);
+ reg_val_DMACR = readl(msp->registers + MSP_DMACR);
+ writel(reg_val_DMACR & ~RX_DMA_ENABLE, msp->registers + MSP_DMACR);
+ reg_val_IMSC = readl(msp->registers + MSP_IMSC);
+ writel(reg_val_IMSC &
+ ~(RX_SERVICE_INT | RX_OVERRUN_ERROR_INT),
+ msp->registers + MSP_IMSC);
+
+ msp->dir_busy &= ~MSP_DIR_RX;
+}
+
+static void disable_msp_tx(struct ux500_msp *msp)
+{
+ u32 reg_val_GCR, reg_val_DMACR, reg_val_IMSC;
+
+ reg_val_GCR = readl(msp->registers + MSP_GCR);
+ writel(reg_val_GCR & ~TX_ENABLE, msp->registers + MSP_GCR);
+ reg_val_DMACR = readl(msp->registers + MSP_DMACR);
+ writel(reg_val_DMACR & ~TX_DMA_ENABLE, msp->registers + MSP_DMACR);
+ reg_val_IMSC = readl(msp->registers + MSP_IMSC);
+ writel(reg_val_IMSC &
+ ~(TX_SERVICE_INT | TX_UNDERRUN_ERR_INT),
+ msp->registers + MSP_IMSC);
+
+ msp->dir_busy &= ~MSP_DIR_TX;
+}
+
+static int disable_msp(struct ux500_msp *msp, unsigned int dir)
+{
+ u32 reg_val_GCR;
+ int status = 0;
+ unsigned int disable_tx, disable_rx;
+
+ reg_val_GCR = readl(msp->registers + MSP_GCR);
+ disable_tx = dir & MSP_DIR_TX;
+ disable_rx = dir & MSP_DIR_TX;
+ if (disable_tx && disable_rx) {
+ reg_val_GCR = readl(msp->registers + MSP_GCR);
+ writel(reg_val_GCR | LOOPBACK_MASK,
+ msp->registers + MSP_GCR);
+
+ /* Flush TX-FIFO */
+ flush_fifo_tx(msp);
+
+ /* Disable TX-channel */
+ writel((readl(msp->registers + MSP_GCR) &
+ (~TX_ENABLE)), msp->registers + MSP_GCR);
+
+ /* Flush RX-FIFO */
+ flush_fifo_rx(msp);
+
+ /* Disable Loopback and Receive channel */
+ writel((readl(msp->registers + MSP_GCR) &
+ (~(RX_ENABLE | LOOPBACK_MASK))),
+ msp->registers + MSP_GCR);
+
+ disable_msp_tx(msp);
+ disable_msp_rx(msp);
+ } else if (disable_tx)
+ disable_msp_tx(msp);
+ else if (disable_rx)
+ disable_msp_rx(msp);
+
+ return status;
+}
+
+int ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd, int direction)
+{
+ u32 reg_val_GCR, enable_bit;
+
+ if (msp->msp_state == MSP_STATE_IDLE) {
+ dev_err(msp->dev, "%s: ERROR: MSP is not configured!\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+ enable_bit = TX_ENABLE;
+ else
+ enable_bit = RX_ENABLE;
+ reg_val_GCR = readl(msp->registers + MSP_GCR);
+ writel(reg_val_GCR | enable_bit, msp->registers + MSP_GCR);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (direction == SNDRV_PCM_STREAM_PLAYBACK)
+ disable_msp_tx(msp);
+ else
+ disable_msp_rx(msp);
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
+{
+ int status = 0;
+
+ dev_dbg(msp->dev, "%s: Enter (dir = 0x%01x).\n", __func__, dir);
+
+ status = disable_msp(msp, dir);
+ if (msp->dir_busy == 0) {
+ /* disable sample rate and frame generators */
+ msp->msp_state = MSP_STATE_IDLE;
+ writel((readl(msp->registers + MSP_GCR) &
+ (~(FRAME_GEN_ENABLE | SRG_ENABLE))),
+ msp->registers + MSP_GCR);
+ if (msp->plat_exit)
+ status = msp->plat_exit();
+ if (status)
+ dev_warn(msp->dev,
+ "%s: WARN: ux500_msp_i2s_exit failed (%d)!\n",
+ __func__, status);
+ writel(0, msp->registers + MSP_GCR);
+ writel(0, msp->registers + MSP_TCF);
+ writel(0, msp->registers + MSP_RCF);
+ writel(0, msp->registers + MSP_DMACR);
+ writel(0, msp->registers + MSP_SRG);
+ writel(0, msp->registers + MSP_MCR);
+ writel(0, msp->registers + MSP_RCM);
+ writel(0, msp->registers + MSP_RCV);
+ writel(0, msp->registers + MSP_TCE0);
+ writel(0, msp->registers + MSP_TCE1);
+ writel(0, msp->registers + MSP_TCE2);
+ writel(0, msp->registers + MSP_TCE3);
+ writel(0, msp->registers + MSP_RCE0);
+ writel(0, msp->registers + MSP_RCE1);
+ writel(0, msp->registers + MSP_RCE2);
+ writel(0, msp->registers + MSP_RCE3);
+ }
+
+ return status;
+
+}
+
+int ux500_msp_i2s_init_msp(struct platform_device *pdev,
+ struct ux500_msp **msp_p,
+ struct msp_i2s_platform_data *platform_data)
+{
+ int ret = 0;
+ struct resource *res = NULL;
+ struct i2s_controller *i2s_cont;
+ struct ux500_msp *msp;
+
+ dev_dbg(&pdev->dev, "%s: Enter (name: %s, id: %d).\n", __func__,
+ pdev->name, platform_data->id);
+
+ *msp_p = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp), GFP_KERNEL);
+ msp = *msp_p;
+
+ msp->id = platform_data->id;
+ msp->dev = &pdev->dev;
+ msp->plat_init = platform_data->msp_i2s_init;
+ msp->plat_exit = platform_data->msp_i2s_exit;
+ msp->dma_cfg_rx = platform_data->msp_i2s_dma_rx;
+ msp->dma_cfg_tx = platform_data->msp_i2s_dma_tx;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "%s: ERROR: Unable to get resource!\n",
+ __func__);
+ ret = -ENOMEM;
+ goto err_res;
+ }
+
+ msp->registers = ioremap(res->start, (res->end - res->start + 1));
+ if (msp->registers == NULL) {
+ dev_err(&pdev->dev, "%s: ERROR: ioremap failed!\n", __func__);
+ ret = -ENOMEM;
+ goto err_res;
+ }
+
+ msp->msp_state = MSP_STATE_IDLE;
+ msp->loopback_enable = 0;
+
+ /* I2S-controller is allocated and added in I2S controller class. */
+ i2s_cont = devm_kzalloc(&pdev->dev, sizeof(*i2s_cont), GFP_KERNEL);
+ if (!i2s_cont) {
+ dev_err(&pdev->dev,
+ "%s: ERROR: Failed to allocate I2S-controller!\n",
+ __func__);
+ goto err_i2s_cont;
+ }
+ i2s_cont->dev.parent = &pdev->dev;
+ i2s_cont->data = (void *)msp;
+ i2s_cont->id = (s16)msp->id;
+ snprintf(i2s_cont->name, sizeof(i2s_cont->name), "ux500-msp-i2s.%04x",
+ msp->id);
+ dev_dbg(&pdev->dev, "I2S device-name: '%s'\n", i2s_cont->name);
+ msp->i2s_cont = i2s_cont;
+
+ return 0;
+
+err_i2s_cont:
+ iounmap(msp->registers);
+
+err_res:
+ devm_kfree(&pdev->dev, msp);
+
+ return ret;
+}
+
+void ux500_msp_i2s_cleanup_msp(struct platform_device *pdev,
+ struct ux500_msp *msp)
+{
+ dev_dbg(msp->dev, "%s: Enter (id = %d).\n", __func__, msp->id);
+
+ device_unregister(&msp->i2s_cont->dev);
+ devm_kfree(&pdev->dev, msp->i2s_cont);
+
+ iounmap(msp->registers);
+
+ devm_kfree(&pdev->dev, msp);
+}
+
+MODULE_LICENSE("GPLv2");
diff --git a/sound/soc/ux500/ux500_msp_i2s.h b/sound/soc/ux500/ux500_msp_i2s.h
new file mode 100644
index 000000000000..7f71b4a0d4bc
--- /dev/null
+++ b/sound/soc/ux500/ux500_msp_i2s.h
@@ -0,0 +1,553 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * Author: Ola Lilja <ola.o.lilja@stericsson.com>,
+ * for ST-Ericsson.
+ *
+ * License terms:
+ *
+ * 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 UX500_MSP_I2S_H
+#define UX500_MSP_I2S_H
+
+#include <linux/platform_device.h>
+
+#include <mach/board-mop500-msp.h>
+
+#define MSP_INPUT_FREQ_APB 48000000
+
+/*** Stereo mode. Used for APB data accesses as 16 bits accesses (mono),
+ * 32 bits accesses (stereo).
+ ***/
+enum msp_stereo_mode {
+ MSP_MONO,
+ MSP_STEREO
+};
+
+/* Direction (Transmit/Receive mode) */
+enum msp_direction {
+ MSP_TX = 1,
+ MSP_RX = 2
+};
+
+/* Transmit and receive configuration register */
+#define MSP_BIG_ENDIAN 0x00000000
+#define MSP_LITTLE_ENDIAN 0x00001000
+#define MSP_UNEXPECTED_FS_ABORT 0x00000000
+#define MSP_UNEXPECTED_FS_IGNORE 0x00008000
+#define MSP_NON_MODE_BIT_MASK 0x00009000
+
+/* Global configuration register */
+#define RX_ENABLE 0x00000001
+#define RX_FIFO_ENABLE 0x00000002
+#define RX_SYNC_SRG 0x00000010
+#define RX_CLK_POL_RISING 0x00000020
+#define RX_CLK_SEL_SRG 0x00000040
+#define TX_ENABLE 0x00000100
+#define TX_FIFO_ENABLE 0x00000200
+#define TX_SYNC_SRG_PROG 0x00001800
+#define TX_SYNC_SRG_AUTO 0x00001000
+#define TX_CLK_POL_RISING 0x00002000
+#define TX_CLK_SEL_SRG 0x00004000
+#define TX_EXTRA_DELAY_ENABLE 0x00008000
+#define SRG_ENABLE 0x00010000
+#define FRAME_GEN_ENABLE 0x00100000
+#define SRG_CLK_SEL_APB 0x00000000
+#define RX_FIFO_SYNC_HI 0x00000000
+#define TX_FIFO_SYNC_HI 0x00000000
+#define SPI_CLK_MODE_NORMAL 0x00000000
+
+#define MSP_FRAME_SIZE_AUTO -1
+
+#define MSP_DR 0x00
+#define MSP_GCR 0x04
+#define MSP_TCF 0x08
+#define MSP_RCF 0x0c
+#define MSP_SRG 0x10
+#define MSP_FLR 0x14
+#define MSP_DMACR 0x18
+
+#define MSP_IMSC 0x20
+#define MSP_RIS 0x24
+#define MSP_MIS 0x28
+#define MSP_ICR 0x2c
+#define MSP_MCR 0x30
+#define MSP_RCV 0x34
+#define MSP_RCM 0x38
+
+#define MSP_TCE0 0x40
+#define MSP_TCE1 0x44
+#define MSP_TCE2 0x48
+#define MSP_TCE3 0x4c
+
+#define MSP_RCE0 0x60
+#define MSP_RCE1 0x64
+#define MSP_RCE2 0x68
+#define MSP_RCE3 0x6c
+#define MSP_IODLY 0x70
+
+#define MSP_ITCR 0x80
+#define MSP_ITIP 0x84
+#define MSP_ITOP 0x88
+#define MSP_TSTDR 0x8c
+
+#define MSP_PID0 0xfe0
+#define MSP_PID1 0xfe4
+#define MSP_PID2 0xfe8
+#define MSP_PID3 0xfec
+
+#define MSP_CID0 0xff0
+#define MSP_CID1 0xff4
+#define MSP_CID2 0xff8
+#define MSP_CID3 0xffc
+
+/* Protocol dependant parameters list */
+#define RX_ENABLE_MASK BIT(0)
+#define RX_FIFO_ENABLE_MASK BIT(1)
+#define RX_FSYNC_MASK BIT(2)
+#define DIRECT_COMPANDING_MASK BIT(3)
+#define RX_SYNC_SEL_MASK BIT(4)
+#define RX_CLK_POL_MASK BIT(5)
+#define RX_CLK_SEL_MASK BIT(6)
+#define LOOPBACK_MASK BIT(7)
+#define TX_ENABLE_MASK BIT(8)
+#define TX_FIFO_ENABLE_MASK BIT(9)
+#define TX_FSYNC_MASK BIT(10)
+#define TX_MSP_TDR_TSR BIT(11)
+#define TX_SYNC_SEL_MASK (BIT(12) | BIT(11))
+#define TX_CLK_POL_MASK BIT(13)
+#define TX_CLK_SEL_MASK BIT(14)
+#define TX_EXTRA_DELAY_MASK BIT(15)
+#define SRG_ENABLE_MASK BIT(16)
+#define SRG_CLK_POL_MASK BIT(17)
+#define SRG_CLK_SEL_MASK (BIT(19) | BIT(18))
+#define FRAME_GEN_EN_MASK BIT(20)
+#define SPI_CLK_MODE_MASK (BIT(22) | BIT(21))
+#define SPI_BURST_MODE_MASK BIT(23)
+
+#define RXEN_SHIFT 0
+#define RFFEN_SHIFT 1
+#define RFSPOL_SHIFT 2
+#define DCM_SHIFT 3
+#define RFSSEL_SHIFT 4
+#define RCKPOL_SHIFT 5
+#define RCKSEL_SHIFT 6
+#define LBM_SHIFT 7
+#define TXEN_SHIFT 8
+#define TFFEN_SHIFT 9
+#define TFSPOL_SHIFT 10
+#define TFSSEL_SHIFT 11
+#define TCKPOL_SHIFT 13
+#define TCKSEL_SHIFT 14
+#define TXDDL_SHIFT 15
+#define SGEN_SHIFT 16
+#define SCKPOL_SHIFT 17
+#define SCKSEL_SHIFT 18
+#define FGEN_SHIFT 20
+#define SPICKM_SHIFT 21
+#define TBSWAP_SHIFT 28
+
+#define RCKPOL_MASK BIT(0)
+#define TCKPOL_MASK BIT(0)
+#define SPICKM_MASK (BIT(1) | BIT(0))
+#define MSP_RX_CLKPOL_BIT(n) ((n & RCKPOL_MASK) << RCKPOL_SHIFT)
+#define MSP_TX_CLKPOL_BIT(n) ((n & TCKPOL_MASK) << TCKPOL_SHIFT)
+
+#define P1ELEN_SHIFT 0
+#define P1FLEN_SHIFT 3
+#define DTYP_SHIFT 10
+#define ENDN_SHIFT 12
+#define DDLY_SHIFT 13
+#define FSIG_SHIFT 15
+#define P2ELEN_SHIFT 16
+#define P2FLEN_SHIFT 19
+#define P2SM_SHIFT 26
+#define P2EN_SHIFT 27
+#define FSYNC_SHIFT 15
+
+#define P1ELEN_MASK 0x00000007
+#define P2ELEN_MASK 0x00070000
+#define P1FLEN_MASK 0x00000378
+#define P2FLEN_MASK 0x03780000
+#define DDLY_MASK 0x00003000
+#define DTYP_MASK 0x00000600
+#define P2SM_MASK 0x04000000
+#define P2EN_MASK 0x08000000
+#define ENDN_MASK 0x00001000
+#define TFSPOL_MASK 0x00000400
+#define TBSWAP_MASK 0x30000000
+#define COMPANDING_MODE_MASK 0x00000c00
+#define FSYNC_MASK 0x00008000
+
+#define MSP_P1_ELEM_LEN_BITS(n) (n & P1ELEN_MASK)
+#define MSP_P2_ELEM_LEN_BITS(n) (((n) << P2ELEN_SHIFT) & P2ELEN_MASK)
+#define MSP_P1_FRAME_LEN_BITS(n) (((n) << P1FLEN_SHIFT) & P1FLEN_MASK)
+#define MSP_P2_FRAME_LEN_BITS(n) (((n) << P2FLEN_SHIFT) & P2FLEN_MASK)
+#define MSP_DATA_DELAY_BITS(n) (((n) << DDLY_SHIFT) & DDLY_MASK)
+#define MSP_DATA_TYPE_BITS(n) (((n) << DTYP_SHIFT) & DTYP_MASK)
+#define MSP_P2_START_MODE_BIT(n) ((n << P2SM_SHIFT) & P2SM_MASK)
+#define MSP_P2_ENABLE_BIT(n) ((n << P2EN_SHIFT) & P2EN_MASK)
+#define MSP_SET_ENDIANNES_BIT(n) ((n << ENDN_SHIFT) & ENDN_MASK)
+#define MSP_FSYNC_POL(n) ((n << TFSPOL_SHIFT) & TFSPOL_MASK)
+#define MSP_DATA_WORD_SWAP(n) ((n << TBSWAP_SHIFT) & TBSWAP_MASK)
+#define MSP_SET_COMPANDING_MODE(n) ((n << DTYP_SHIFT) & \
+ COMPANDING_MODE_MASK)
+#define MSP_SET_FSYNC_IGNORE(n) ((n << FSYNC_SHIFT) & FSYNC_MASK)
+
+/* Flag register */
+#define RX_BUSY BIT(0)
+#define RX_FIFO_EMPTY BIT(1)
+#define RX_FIFO_FULL BIT(2)
+#define TX_BUSY BIT(3)
+#define TX_FIFO_EMPTY BIT(4)
+#define TX_FIFO_FULL BIT(5)
+
+#define RBUSY_SHIFT 0
+#define RFE_SHIFT 1
+#define RFU_SHIFT 2
+#define TBUSY_SHIFT 3
+#define TFE_SHIFT 4
+#define TFU_SHIFT 5
+
+/* Multichannel control register */
+#define RMCEN_SHIFT 0
+#define RMCSF_SHIFT 1
+#define RCMPM_SHIFT 3
+#define TMCEN_SHIFT 5
+#define TNCSF_SHIFT 6
+
+/* Sample rate generator register */
+#define SCKDIV_SHIFT 0
+#define FRWID_SHIFT 10
+#define FRPER_SHIFT 16
+
+#define SCK_DIV_MASK 0x0000003FF
+#define FRAME_WIDTH_BITS(n) (((n) << FRWID_SHIFT) & 0x0000FC00)
+#define FRAME_PERIOD_BITS(n) (((n) << FRPER_SHIFT) & 0x1FFF0000)
+
+/* DMA controller register */
+#define RX_DMA_ENABLE BIT(0)
+#define TX_DMA_ENABLE BIT(1)
+
+#define RDMAE_SHIFT 0
+#define TDMAE_SHIFT 1
+
+/* Interrupt Register */
+#define RX_SERVICE_INT BIT(0)
+#define RX_OVERRUN_ERROR_INT BIT(1)
+#define RX_FSYNC_ERR_INT BIT(2)
+#define RX_FSYNC_INT BIT(3)
+#define TX_SERVICE_INT BIT(4)
+#define TX_UNDERRUN_ERR_INT BIT(5)
+#define TX_FSYNC_ERR_INT BIT(6)
+#define TX_FSYNC_INT BIT(7)
+#define ALL_INT 0x000000ff
+
+/* MSP test control register */
+#define MSP_ITCR_ITEN BIT(0)
+#define MSP_ITCR_TESTFIFO BIT(1)
+
+#define RMCEN_BIT 0
+#define RMCSF_BIT 1
+#define RCMPM_BIT 3
+#define TMCEN_BIT 5
+#define TNCSF_BIT 6
+
+/* Single or dual phase mode */
+enum msp_phase_mode {
+ MSP_SINGLE_PHASE,
+ MSP_DUAL_PHASE
+};
+
+/* Frame length */
+enum msp_frame_length {
+ MSP_FRAME_LEN_1 = 0,
+ MSP_FRAME_LEN_2 = 1,
+ MSP_FRAME_LEN_4 = 3,
+ MSP_FRAME_LEN_8 = 7,
+ MSP_FRAME_LEN_12 = 11,
+ MSP_FRAME_LEN_16 = 15,
+ MSP_FRAME_LEN_20 = 19,
+ MSP_FRAME_LEN_32 = 31,
+ MSP_FRAME_LEN_48 = 47,
+ MSP_FRAME_LEN_64 = 63
+};
+
+/* Element length */
+enum msp_elem_length {
+ MSP_ELEM_LEN_8 = 0,
+ MSP_ELEM_LEN_10 = 1,
+ MSP_ELEM_LEN_12 = 2,
+ MSP_ELEM_LEN_14 = 3,
+ MSP_ELEM_LEN_16 = 4,
+ MSP_ELEM_LEN_20 = 5,
+ MSP_ELEM_LEN_24 = 6,
+ MSP_ELEM_LEN_32 = 7
+};
+
+enum msp_data_xfer_width {
+ MSP_DATA_TRANSFER_WIDTH_BYTE,
+ MSP_DATA_TRANSFER_WIDTH_HALFWORD,
+ MSP_DATA_TRANSFER_WIDTH_WORD
+};
+
+enum msp_frame_sync {
+ MSP_FSYNC_UNIGNORE = 0,
+ MSP_FSYNC_IGNORE = 1,
+};
+
+enum msp_phase2_start_mode {
+ MSP_PHASE2_START_MODE_IMEDIATE,
+ MSP_PHASE2_START_MODE_FSYNC
+};
+
+enum msp_btf {
+ MSP_BTF_MS_BIT_FIRST = 0,
+ MSP_BTF_LS_BIT_FIRST = 1
+};
+
+enum msp_fsync_pol {
+ MSP_FSYNC_POL_ACT_HI = 0,
+ MSP_FSYNC_POL_ACT_LO = 1
+};
+
+/* Data delay (in bit clock cycles) */
+enum msp_delay {
+ MSP_DELAY_0 = 0,
+ MSP_DELAY_1 = 1,
+ MSP_DELAY_2 = 2,
+ MSP_DELAY_3 = 3
+};
+
+/* Configurations of clocks (transmit, receive or sample rate generator) */
+enum msp_edge {
+ MSP_FALLING_EDGE = 0,
+ MSP_RISING_EDGE = 1,
+};
+
+enum msp_hws {
+ MSP_SWAP_NONE = 0,
+ MSP_SWAP_BYTE_PER_WORD = 1,
+ MSP_SWAP_BYTE_PER_HALF_WORD = 2,
+ MSP_SWAP_HALF_WORD_PER_WORD = 3
+};
+
+enum msp_compress_mode {
+ MSP_COMPRESS_MODE_LINEAR = 0,
+ MSP_COMPRESS_MODE_MU_LAW = 2,
+ MSP_COMPRESS_MODE_A_LAW = 3
+};
+
+enum msp_spi_burst_mode {
+ MSP_SPI_BURST_MODE_DISABLE = 0,
+ MSP_SPI_BURST_MODE_ENABLE = 1
+};
+
+enum msp_expand_mode {
+ MSP_EXPAND_MODE_LINEAR = 0,
+ MSP_EXPAND_MODE_LINEAR_SIGNED = 1,
+ MSP_EXPAND_MODE_MU_LAW = 2,
+ MSP_EXPAND_MODE_A_LAW = 3
+};
+
+#define MSP_FRAME_PERIOD_IN_MONO_MODE 256
+#define MSP_FRAME_PERIOD_IN_STEREO_MODE 32
+#define MSP_FRAME_WIDTH_IN_STEREO_MODE 16
+
+enum msp_protocol {
+ MSP_I2S_PROTOCOL,
+ MSP_PCM_PROTOCOL,
+ MSP_PCM_COMPAND_PROTOCOL,
+ MSP_INVALID_PROTOCOL
+};
+
+/*
+ * No of registers to backup during
+ * suspend resume
+ */
+#define MAX_MSP_BACKUP_REGS 36
+
+enum enum_i2s_controller {
+ MSP_0_I2S_CONTROLLER = 0,
+ MSP_1_I2S_CONTROLLER,
+ MSP_2_I2S_CONTROLLER,
+ MSP_3_I2S_CONTROLLER,
+};
+
+enum i2s_direction_t {
+ MSP_DIR_TX = 0x01,
+ MSP_DIR_RX = 0x02,
+};
+
+enum msp_data_size {
+ MSP_DATA_BITS_DEFAULT = -1,
+ MSP_DATA_BITS_8 = 0x00,
+ MSP_DATA_BITS_10,
+ MSP_DATA_BITS_12,
+ MSP_DATA_BITS_14,
+ MSP_DATA_BITS_16,
+ MSP_DATA_BITS_20,
+ MSP_DATA_BITS_24,
+ MSP_DATA_BITS_32,
+};
+
+enum msp_state {
+ MSP_STATE_IDLE = 0,
+ MSP_STATE_CONFIGURED = 1,
+ MSP_STATE_RUNNING = 2,
+};
+
+enum msp_rx_comparison_enable_mode {
+ MSP_COMPARISON_DISABLED = 0,
+ MSP_COMPARISON_NONEQUAL_ENABLED = 2,
+ MSP_COMPARISON_EQUAL_ENABLED = 3
+};
+
+struct msp_multichannel_config {
+ bool rx_multichannel_enable;
+ bool tx_multichannel_enable;
+ enum msp_rx_comparison_enable_mode rx_comparison_enable_mode;
+ u8 padding;
+ u32 comparison_value;
+ u32 comparison_mask;
+ u32 rx_channel_0_enable;
+ u32 rx_channel_1_enable;
+ u32 rx_channel_2_enable;
+ u32 rx_channel_3_enable;
+ u32 tx_channel_0_enable;
+ u32 tx_channel_1_enable;
+ u32 tx_channel_2_enable;
+ u32 tx_channel_3_enable;
+};
+
+struct msp_protdesc {
+ u32 rx_phase_mode;
+ u32 tx_phase_mode;
+ u32 rx_phase2_start_mode;
+ u32 tx_phase2_start_mode;
+ u32 rx_byte_order;
+ u32 tx_byte_order;
+ u32 rx_frame_len_1;
+ u32 rx_frame_len_2;
+ u32 tx_frame_len_1;
+ u32 tx_frame_len_2;
+ u32 rx_elem_len_1;
+ u32 rx_elem_len_2;
+ u32 tx_elem_len_1;
+ u32 tx_elem_len_2;
+ u32 rx_data_delay;
+ u32 tx_data_delay;
+ u32 rx_clk_pol;
+ u32 tx_clk_pol;
+ u32 rx_fsync_pol;
+ u32 tx_fsync_pol;
+ u32 rx_half_word_swap;
+ u32 tx_half_word_swap;
+ u32 compression_mode;
+ u32 expansion_mode;
+ u32 frame_sync_ignore;
+ u32 frame_period;
+ u32 frame_width;
+ u32 clocks_per_frame;
+};
+
+struct i2s_message {
+ enum i2s_direction_t i2s_direction;
+ void *txdata;
+ void *rxdata;
+ size_t txbytes;
+ size_t rxbytes;
+ int dma_flag;
+ int tx_offset;
+ int rx_offset;
+ bool cyclic_dma;
+ dma_addr_t buf_addr;
+ size_t buf_len;
+ size_t period_len;
+};
+
+struct i2s_controller {
+ struct module *owner;
+ unsigned int id;
+ unsigned int class;
+ const struct i2s_algorithm *algo; /* the algorithm to access the bus */
+ void *data;
+ struct mutex bus_lock;
+ struct device dev; /* the controller device */
+ char name[48];
+};
+
+struct ux500_msp_config {
+ unsigned int f_inputclk;
+ unsigned int rx_clk_sel;
+ unsigned int tx_clk_sel;
+ unsigned int srg_clk_sel;
+ unsigned int rx_fsync_pol;
+ unsigned int tx_fsync_pol;
+ unsigned int rx_fsync_sel;
+ unsigned int tx_fsync_sel;
+ unsigned int rx_fifo_config;
+ unsigned int tx_fifo_config;
+ unsigned int spi_clk_mode;
+ unsigned int spi_burst_mode;
+ unsigned int loopback_enable;
+ unsigned int tx_data_enable;
+ unsigned int default_protdesc;
+ struct msp_protdesc protdesc;
+ int multichannel_configured;
+ struct msp_multichannel_config multichannel_config;
+ unsigned int direction;
+ unsigned int protocol;
+ unsigned int frame_freq;
+ unsigned int frame_size;
+ enum msp_data_size data_size;
+ unsigned int def_elem_len;
+ unsigned int iodelay;
+ void (*handler) (void *data);
+ void *tx_callback_data;
+ void *rx_callback_data;
+};
+
+struct ux500_msp {
+ enum enum_i2s_controller id;
+ void __iomem *registers;
+ struct device *dev;
+ struct i2s_controller *i2s_cont;
+ struct stedma40_chan_cfg *dma_cfg_rx;
+ struct stedma40_chan_cfg *dma_cfg_tx;
+ struct dma_chan *tx_pipeid;
+ struct dma_chan *rx_pipeid;
+ enum msp_state msp_state;
+ int (*transfer) (struct ux500_msp *msp, struct i2s_message *message);
+ int (*plat_init) (void);
+ int (*plat_exit) (void);
+ struct timer_list notify_timer;
+ int def_elem_len;
+ unsigned int dir_busy;
+ int loopback_enable;
+ u32 backup_regs[MAX_MSP_BACKUP_REGS];
+ unsigned int f_bitclk;
+};
+
+struct ux500_msp_dma_params {
+ unsigned int data_size;
+ struct stedma40_chan_cfg *dma_cfg;
+};
+
+int ux500_msp_i2s_init_msp(struct platform_device *pdev,
+ struct ux500_msp **msp_p,
+ struct msp_i2s_platform_data *platform_data);
+void ux500_msp_i2s_cleanup_msp(struct platform_device *pdev,
+ struct ux500_msp *msp);
+int ux500_msp_i2s_open(struct ux500_msp *msp, struct ux500_msp_config *config);
+int ux500_msp_i2s_close(struct ux500_msp *msp,
+ unsigned int dir);
+int ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd,
+ int direction);
+
+#endif
diff --git a/sound/sound_core.c b/sound/sound_core.c
index c6e81fb928e9..fb9255cca214 100644
--- a/sound/sound_core.c
+++ b/sound/sound_core.c
@@ -361,7 +361,7 @@ int register_sound_special_device(const struct file_operations *fops, int unit,
struct device *dev)
{
const int chain = unit % SOUND_STEP;
- int max_unit = 128 + chain;
+ int max_unit = 256;
const char *name;
char _name[16];
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 4a7be7b98331..d5b5c3388e28 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -131,8 +131,9 @@ static void snd_usb_stream_disconnect(struct list_head *head)
subs = &as->substream[idx];
if (!subs->num_formats)
continue;
- snd_usb_release_substream_urbs(subs, 1);
subs->interface = -1;
+ subs->data_endpoint = NULL;
+ subs->sync_endpoint = NULL;
}
}
@@ -276,6 +277,7 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
static int snd_usb_audio_free(struct snd_usb_audio *chip)
{
+ mutex_destroy(&chip->mutex);
kfree(chip);
return 0;
}
@@ -336,6 +338,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
return -ENOMEM;
}
+ mutex_init(&chip->mutex);
mutex_init(&chip->shutdown_mutex);
chip->index = idx;
chip->dev = dev;
@@ -348,6 +351,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
INIT_LIST_HEAD(&chip->pcm_list);
+ INIT_LIST_HEAD(&chip->ep_list);
INIT_LIST_HEAD(&chip->midi_list);
INIT_LIST_HEAD(&chip->mixer_list);
@@ -565,6 +569,10 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
list_for_each(p, &chip->pcm_list) {
snd_usb_stream_disconnect(p);
}
+ /* release the endpoint resources */
+ list_for_each(p, &chip->ep_list) {
+ snd_usb_endpoint_free(p);
+ }
/* release the midi resources */
list_for_each(p, &chip->midi_list) {
snd_usbmidi_disconnect(p);
diff --git a/sound/usb/card.h b/sound/usb/card.h
index da5fa1ac4eda..0d37238b8457 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -30,20 +30,71 @@ struct audioformat {
};
struct snd_usb_substream;
+struct snd_usb_endpoint;
struct snd_urb_ctx {
struct urb *urb;
unsigned int buffer_size; /* size of data buffer, if data URB */
struct snd_usb_substream *subs;
+ struct snd_usb_endpoint *ep;
int index; /* index for urb array */
int packets; /* number of packets per urb */
+ int packet_size[MAX_PACKS_HS]; /* size of packets for next submission */
+ struct list_head ready_list;
};
-struct snd_urb_ops {
- int (*prepare)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
- int (*retire)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
- int (*prepare_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
- int (*retire_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
+struct snd_usb_endpoint {
+ struct snd_usb_audio *chip;
+
+ int use_count;
+ int ep_num; /* the referenced endpoint number */
+ int type; /* SND_USB_ENDPOINT_TYPE_* */
+ unsigned long flags;
+
+ void (*prepare_data_urb) (struct snd_usb_substream *subs,
+ struct urb *urb);
+ void (*retire_data_urb) (struct snd_usb_substream *subs,
+ struct urb *urb);
+
+ struct snd_usb_substream *data_subs;
+ struct snd_usb_endpoint *sync_master;
+ struct snd_usb_endpoint *sync_slave;
+
+ struct snd_urb_ctx urb[MAX_URBS];
+
+ struct snd_usb_packet_info {
+ uint32_t packet_size[MAX_PACKS_HS];
+ int packets;
+ } next_packet[MAX_URBS];
+ int next_packet_read_pos, next_packet_write_pos;
+ struct list_head ready_playback_urbs;
+
+ unsigned int nurbs; /* # urbs */
+ unsigned long active_mask; /* bitmask of active urbs */
+ unsigned long unlink_mask; /* bitmask of unlinked urbs */
+ char *syncbuf; /* sync buffer for all sync URBs */
+ dma_addr_t sync_dma; /* DMA address of syncbuf */
+
+ unsigned int pipe; /* the data i/o pipe */
+ unsigned int freqn; /* nominal sampling rate in fs/fps in Q16.16 format */
+ unsigned int freqm; /* momentary sampling rate in fs/fps in Q16.16 format */
+ int freqshift; /* how much to shift the feedback value to get Q16.16 */
+ unsigned int freqmax; /* maximum sampling rate, used for buffer management */
+ unsigned int phase; /* phase accumulator */
+ unsigned int maxpacksize; /* max packet size in bytes */
+ unsigned int maxframesize; /* max packet size in frames */
+ unsigned int curpacksize; /* current packet size in bytes (for capture) */
+ unsigned int curframesize; /* current packet size in frames (for capture) */
+ unsigned int syncmaxsize; /* sync endpoint packet size */
+ unsigned int fill_max:1; /* fill max packet size always */
+ unsigned int datainterval; /* log_2 of data packet interval */
+ unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */
+ unsigned char silence_value;
+ unsigned int stride;
+ int iface, alt_idx;
+
+ spinlock_t lock;
+ struct list_head list;
};
struct snd_usb_substream {
@@ -57,21 +108,6 @@ struct snd_usb_substream {
unsigned int cur_rate; /* current rate (for hw_params callback) */
unsigned int period_bytes; /* current period bytes (for hw_params callback) */
unsigned int altset_idx; /* USB data format: index of alternate setting */
- unsigned int datapipe; /* the data i/o pipe */
- unsigned int syncpipe; /* 1 - async out or adaptive in */
- unsigned int datainterval; /* log_2 of data packet interval */
- unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */
- unsigned int freqn; /* nominal sampling rate in fs/fps in Q16.16 format */
- unsigned int freqm; /* momentary sampling rate in fs/fps in Q16.16 format */
- int freqshift; /* how much to shift the feedback value to get Q16.16 */
- unsigned int freqmax; /* maximum sampling rate, used for buffer management */
- unsigned int phase; /* phase accumulator */
- unsigned int maxpacksize; /* max packet size in bytes */
- unsigned int maxframesize; /* max packet size in frames */
- unsigned int curpacksize; /* current packet size in bytes (for capture) */
- unsigned int curframesize; /* current packet size in frames (for capture) */
- unsigned int syncmaxsize; /* sync endpoint packet size */
- unsigned int fill_max: 1; /* fill max packet size always */
unsigned int txfr_quirk:1; /* allow sub-frame alignment */
unsigned int fmt_type; /* USB audio format type (1-3) */
@@ -82,11 +118,10 @@ struct snd_usb_substream {
unsigned long active_mask; /* bitmask of active urbs */
unsigned long unlink_mask; /* bitmask of unlinked urbs */
- unsigned int nurbs; /* # urbs */
- struct snd_urb_ctx dataurb[MAX_URBS]; /* data urb table */
- struct snd_urb_ctx syncurb[SYNC_URBS]; /* sync urb table */
- char *syncbuf; /* sync buffer for all sync URBs */
- dma_addr_t sync_dma; /* DMA address of syncbuf */
+ /* data and sync endpoints for this stream */
+ struct snd_usb_endpoint *data_endpoint;
+ struct snd_usb_endpoint *sync_endpoint;
+ unsigned long flags;
u64 formats; /* format bitmasks (all or'ed) */
unsigned int num_formats; /* number of supported audio formats (list) */
@@ -94,7 +129,6 @@ struct snd_usb_substream {
struct snd_pcm_hw_constraint_list rate_list; /* limited rates */
spinlock_t lock;
- struct snd_urb_ops ops; /* callbacks (must be filled at init) */
int last_frame_number; /* stored frame number */
int last_delay; /* stored delay */
};
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 08dcce53720b..e6906901debb 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -20,9 +20,11 @@
#include <linux/ratelimit.h>
#include <linux/usb.h>
#include <linux/usb/audio.h>
+#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
+#include <sound/pcm_params.h>
#include "usbaudio.h"
#include "helper.h"
@@ -30,6 +32,36 @@
#include "endpoint.h"
#include "pcm.h"
+#define EP_FLAG_ACTIVATED 0
+#define EP_FLAG_RUNNING 1
+
+/*
+ * snd_usb_endpoint is a model that abstracts everything related to an
+ * USB endpoint and its streaming.
+ *
+ * There are functions to activate and deactivate the streaming URBs and
+ * optional callbacks to let the pcm logic handle the actual content of the
+ * packets for playback and record. Thus, the bus streaming and the audio
+ * handlers are fully decoupled.
+ *
+ * There are two different types of endpoints in audio applications.
+ *
+ * SND_USB_ENDPOINT_TYPE_DATA handles full audio data payload for both
+ * inbound and outbound traffic.
+ *
+ * SND_USB_ENDPOINT_TYPE_SYNC endpoints are for inbound traffic only and
+ * expect the payload to carry Q10.14 / Q16.16 formatted sync information
+ * (3 or 4 bytes).
+ *
+ * Each endpoint has to be configured prior to being used by calling
+ * snd_usb_endpoint_set_params().
+ *
+ * The model incorporates a reference counting, so that multiple users
+ * can call snd_usb_endpoint_start() and snd_usb_endpoint_stop(), and
+ * only the first user will effectively start the URBs, and only the last
+ * one to stop it will tear the URBs down again.
+ */
+
/*
* convert a sampling rate into our full speed format (fs/1000 in Q16.16)
* this will overflow at approx 524 kHz
@@ -49,71 +81,415 @@ static inline unsigned get_usb_high_speed_rate(unsigned int rate)
}
/*
- * unlink active urbs.
+ * release a urb data
*/
-static int deactivate_urbs(struct snd_usb_substream *subs, int force, int can_sleep)
+static void release_urb_ctx(struct snd_urb_ctx *u)
{
- struct snd_usb_audio *chip = subs->stream->chip;
- unsigned int i;
- int async;
+ if (u->buffer_size)
+ usb_free_coherent(u->ep->chip->dev, u->buffer_size,
+ u->urb->transfer_buffer,
+ u->urb->transfer_dma);
+ usb_free_urb(u->urb);
+ u->urb = NULL;
+}
+
+static const char *usb_error_string(int err)
+{
+ switch (err) {
+ case -ENODEV:
+ return "no device";
+ case -ENOENT:
+ return "endpoint not enabled";
+ case -EPIPE:
+ return "endpoint stalled";
+ case -ENOSPC:
+ return "not enough bandwidth";
+ case -ESHUTDOWN:
+ return "device disabled";
+ case -EHOSTUNREACH:
+ return "device suspended";
+ case -EINVAL:
+ case -EAGAIN:
+ case -EFBIG:
+ case -EMSGSIZE:
+ return "internal error";
+ default:
+ return "unknown error";
+ }
+}
+
+/**
+ * snd_usb_endpoint_implicit_feedback_sink: Report endpoint usage type
+ *
+ * @ep: The snd_usb_endpoint
+ *
+ * Determine whether an endpoint is driven by an implicit feedback
+ * data endpoint source.
+ */
+int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep)
+{
+ return ep->sync_master &&
+ ep->sync_master->type == SND_USB_ENDPOINT_TYPE_DATA &&
+ ep->type == SND_USB_ENDPOINT_TYPE_DATA &&
+ usb_pipeout(ep->pipe);
+}
- subs->running = 0;
+/*
+ * For streaming based on information derived from sync endpoints,
+ * prepare_outbound_urb_sizes() will call next_packet_size() to
+ * determine the number of samples to be sent in the next packet.
+ *
+ * For implicit feedback, next_packet_size() is unused.
+ */
+static int next_packet_size(struct snd_usb_endpoint *ep)
+{
+ unsigned long flags;
+ int ret;
- if (!force && subs->stream->chip->shutdown) /* to be sure... */
- return -EBADFD;
+ if (ep->fill_max)
+ return ep->maxframesize;
- async = !can_sleep && chip->async_unlink;
+ spin_lock_irqsave(&ep->lock, flags);
+ ep->phase = (ep->phase & 0xffff)
+ + (ep->freqm << ep->datainterval);
+ ret = min(ep->phase >> 16, ep->maxframesize);
+ spin_unlock_irqrestore(&ep->lock, flags);
- if (!async && in_interrupt())
- return 0;
+ return ret;
+}
- for (i = 0; i < subs->nurbs; i++) {
- if (test_bit(i, &subs->active_mask)) {
- if (!test_and_set_bit(i, &subs->unlink_mask)) {
- struct urb *u = subs->dataurb[i].urb;
- if (async)
- usb_unlink_urb(u);
- else
- usb_kill_urb(u);
+static void retire_outbound_urb(struct snd_usb_endpoint *ep,
+ struct snd_urb_ctx *urb_ctx)
+{
+ if (ep->retire_data_urb)
+ ep->retire_data_urb(ep->data_subs, urb_ctx->urb);
+}
+
+static void retire_inbound_urb(struct snd_usb_endpoint *ep,
+ struct snd_urb_ctx *urb_ctx)
+{
+ struct urb *urb = urb_ctx->urb;
+
+ if (ep->sync_slave)
+ snd_usb_handle_sync_urb(ep->sync_slave, ep, urb);
+
+ if (ep->retire_data_urb)
+ ep->retire_data_urb(ep->data_subs, urb);
+}
+
+static void prepare_outbound_urb_sizes(struct snd_usb_endpoint *ep,
+ struct snd_urb_ctx *ctx)
+{
+ int i;
+
+ for (i = 0; i < ctx->packets; ++i)
+ ctx->packet_size[i] = next_packet_size(ep);
+}
+
+/*
+ * Prepare a PLAYBACK urb for submission to the bus.
+ */
+static void prepare_outbound_urb(struct snd_usb_endpoint *ep,
+ struct snd_urb_ctx *ctx)
+{
+ int i;
+ struct urb *urb = ctx->urb;
+ unsigned char *cp = urb->transfer_buffer;
+
+ urb->dev = ep->chip->dev; /* we need to set this at each time */
+
+ switch (ep->type) {
+ case SND_USB_ENDPOINT_TYPE_DATA:
+ if (ep->prepare_data_urb) {
+ ep->prepare_data_urb(ep->data_subs, urb);
+ } else {
+ /* no data provider, so send silence */
+ unsigned int offs = 0;
+ for (i = 0; i < ctx->packets; ++i) {
+ int counts = ctx->packet_size[i];
+ urb->iso_frame_desc[i].offset = offs * ep->stride;
+ urb->iso_frame_desc[i].length = counts * ep->stride;
+ offs += counts;
}
+
+ urb->number_of_packets = ctx->packets;
+ urb->transfer_buffer_length = offs * ep->stride;
+ memset(urb->transfer_buffer, ep->silence_value,
+ offs * ep->stride);
}
+ break;
+
+ case SND_USB_ENDPOINT_TYPE_SYNC:
+ if (snd_usb_get_speed(ep->chip->dev) >= USB_SPEED_HIGH) {
+ /*
+ * fill the length and offset of each urb descriptor.
+ * the fixed 12.13 frequency is passed as 16.16 through the pipe.
+ */
+ urb->iso_frame_desc[0].length = 4;
+ urb->iso_frame_desc[0].offset = 0;
+ cp[0] = ep->freqn;
+ cp[1] = ep->freqn >> 8;
+ cp[2] = ep->freqn >> 16;
+ cp[3] = ep->freqn >> 24;
+ } else {
+ /*
+ * fill the length and offset of each urb descriptor.
+ * the fixed 10.14 frequency is passed through the pipe.
+ */
+ urb->iso_frame_desc[0].length = 3;
+ urb->iso_frame_desc[0].offset = 0;
+ cp[0] = ep->freqn >> 2;
+ cp[1] = ep->freqn >> 10;
+ cp[2] = ep->freqn >> 18;
+ }
+
+ break;
}
- if (subs->syncpipe) {
- for (i = 0; i < SYNC_URBS; i++) {
- if (test_bit(i+16, &subs->active_mask)) {
- if (!test_and_set_bit(i+16, &subs->unlink_mask)) {
- struct urb *u = subs->syncurb[i].urb;
- if (async)
- usb_unlink_urb(u);
- else
- usb_kill_urb(u);
- }
- }
+}
+
+/*
+ * Prepare a CAPTURE or SYNC urb for submission to the bus.
+ */
+static inline void prepare_inbound_urb(struct snd_usb_endpoint *ep,
+ struct snd_urb_ctx *urb_ctx)
+{
+ int i, offs;
+ struct urb *urb = urb_ctx->urb;
+
+ urb->dev = ep->chip->dev; /* we need to set this at each time */
+
+ switch (ep->type) {
+ case SND_USB_ENDPOINT_TYPE_DATA:
+ offs = 0;
+ for (i = 0; i < urb_ctx->packets; i++) {
+ urb->iso_frame_desc[i].offset = offs;
+ urb->iso_frame_desc[i].length = ep->curpacksize;
+ offs += ep->curpacksize;
}
+
+ urb->transfer_buffer_length = offs;
+ urb->number_of_packets = urb_ctx->packets;
+ break;
+
+ case SND_USB_ENDPOINT_TYPE_SYNC:
+ urb->iso_frame_desc[0].length = min(4u, ep->syncmaxsize);
+ urb->iso_frame_desc[0].offset = 0;
+ break;
}
- return 0;
}
+/*
+ * Send output urbs that have been prepared previously. URBs are dequeued
+ * from ep->ready_playback_urbs and in case there there aren't any available
+ * or there are no packets that have been prepared, this function does
+ * nothing.
+ *
+ * The reason why the functionality of sending and preparing URBs is separated
+ * is that host controllers don't guarantee the order in which they return
+ * inbound and outbound packets to their submitters.
+ *
+ * This function is only used for implicit feedback endpoints. For endpoints
+ * driven by dedicated sync endpoints, URBs are immediately re-submitted
+ * from their completion handler.
+ */
+static void queue_pending_output_urbs(struct snd_usb_endpoint *ep)
+{
+ while (test_bit(EP_FLAG_RUNNING, &ep->flags)) {
+
+ unsigned long flags;
+ struct snd_usb_packet_info *uninitialized_var(packet);
+ struct snd_urb_ctx *ctx = NULL;
+ struct urb *urb;
+ int err, i;
+
+ spin_lock_irqsave(&ep->lock, flags);
+ if (ep->next_packet_read_pos != ep->next_packet_write_pos) {
+ packet = ep->next_packet + ep->next_packet_read_pos;
+ ep->next_packet_read_pos++;
+ ep->next_packet_read_pos %= MAX_URBS;
+
+ /* take URB out of FIFO */
+ if (!list_empty(&ep->ready_playback_urbs))
+ ctx = list_first_entry(&ep->ready_playback_urbs,
+ struct snd_urb_ctx, ready_list);
+ }
+ spin_unlock_irqrestore(&ep->lock, flags);
+
+ if (ctx == NULL)
+ return;
+
+ list_del_init(&ctx->ready_list);
+ urb = ctx->urb;
+
+ /* copy over the length information */
+ for (i = 0; i < packet->packets; i++)
+ ctx->packet_size[i] = packet->packet_size[i];
+
+ /* call the data handler to fill in playback data */
+ prepare_outbound_urb(ep, ctx);
+
+ err = usb_submit_urb(ctx->urb, GFP_ATOMIC);
+ if (err < 0)
+ snd_printk(KERN_ERR "Unable to submit urb #%d: %d (urb %p)\n",
+ ctx->index, err, ctx->urb);
+ else
+ set_bit(ctx->index, &ep->active_mask);
+ }
+}
/*
- * release a urb data
+ * complete callback for urbs
*/
-static void release_urb_ctx(struct snd_urb_ctx *u)
+static void snd_complete_urb(struct urb *urb)
+{
+ struct snd_urb_ctx *ctx = urb->context;
+ struct snd_usb_endpoint *ep = ctx->ep;
+ int err;
+
+ if (unlikely(urb->status == -ENOENT || /* unlinked */
+ urb->status == -ENODEV || /* device removed */
+ urb->status == -ECONNRESET || /* unlinked */
+ urb->status == -ESHUTDOWN || /* device disabled */
+ ep->chip->shutdown)) /* device disconnected */
+ goto exit_clear;
+
+ if (usb_pipeout(ep->pipe)) {
+ retire_outbound_urb(ep, ctx);
+ /* can be stopped during retire callback */
+ if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags)))
+ goto exit_clear;
+
+ if (snd_usb_endpoint_implict_feedback_sink(ep)) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&ep->lock, flags);
+ list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs);
+ spin_unlock_irqrestore(&ep->lock, flags);
+ queue_pending_output_urbs(ep);
+
+ goto exit_clear;
+ }
+
+ prepare_outbound_urb_sizes(ep, ctx);
+ prepare_outbound_urb(ep, ctx);
+ } else {
+ retire_inbound_urb(ep, ctx);
+ /* can be stopped during retire callback */
+ if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags)))
+ goto exit_clear;
+
+ prepare_inbound_urb(ep, ctx);
+ }
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err == 0)
+ return;
+
+ snd_printk(KERN_ERR "cannot submit urb (err = %d)\n", err);
+ //snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+
+exit_clear:
+ clear_bit(ctx->index, &ep->active_mask);
+}
+
+/**
+ * snd_usb_add_endpoint: Add an endpoint to an USB audio chip
+ *
+ * @chip: The chip
+ * @alts: The USB host interface
+ * @ep_num: The number of the endpoint to use
+ * @direction: SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE
+ * @type: SND_USB_ENDPOINT_TYPE_DATA or SND_USB_ENDPOINT_TYPE_SYNC
+ *
+ * If the requested endpoint has not been added to the given chip before,
+ * a new instance is created. Otherwise, a pointer to the previoulsy
+ * created instance is returned. In case of any error, NULL is returned.
+ *
+ * New endpoints will be added to chip->ep_list and must be freed by
+ * calling snd_usb_endpoint_free().
+ */
+struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
+ struct usb_host_interface *alts,
+ int ep_num, int direction, int type)
{
- if (u->urb) {
- if (u->buffer_size)
- usb_free_coherent(u->subs->dev, u->buffer_size,
- u->urb->transfer_buffer,
- u->urb->transfer_dma);
- usb_free_urb(u->urb);
- u->urb = NULL;
+ struct list_head *p;
+ struct snd_usb_endpoint *ep;
+ int ret, is_playback = direction == SNDRV_PCM_STREAM_PLAYBACK;
+
+ mutex_lock(&chip->mutex);
+
+ list_for_each(p, &chip->ep_list) {
+ ep = list_entry(p, struct snd_usb_endpoint, list);
+ if (ep->ep_num == ep_num &&
+ ep->iface == alts->desc.bInterfaceNumber &&
+ ep->alt_idx == alts->desc.bAlternateSetting) {
+ snd_printdd(KERN_DEBUG "Re-using EP %x in iface %d,%d @%p\n",
+ ep_num, ep->iface, ep->alt_idx, ep);
+ goto __exit_unlock;
+ }
+ }
+
+ snd_printdd(KERN_DEBUG "Creating new %s %s endpoint #%x\n",
+ is_playback ? "playback" : "capture",
+ type == SND_USB_ENDPOINT_TYPE_DATA ? "data" : "sync",
+ ep_num);
+
+ /* select the alt setting once so the endpoints become valid */
+ ret = usb_set_interface(chip->dev, alts->desc.bInterfaceNumber,
+ alts->desc.bAlternateSetting);
+ if (ret < 0) {
+ snd_printk(KERN_ERR "%s(): usb_set_interface() failed, ret = %d\n",
+ __func__, ret);
+ ep = NULL;
+ goto __exit_unlock;
}
+
+ ep = kzalloc(sizeof(*ep), GFP_KERNEL);
+ if (!ep)
+ goto __exit_unlock;
+
+ ep->chip = chip;
+ spin_lock_init(&ep->lock);
+ ep->type = type;
+ ep->ep_num = ep_num;
+ ep->iface = alts->desc.bInterfaceNumber;
+ ep->alt_idx = alts->desc.bAlternateSetting;
+ INIT_LIST_HEAD(&ep->ready_playback_urbs);
+ ep_num &= USB_ENDPOINT_NUMBER_MASK;
+
+ if (is_playback)
+ ep->pipe = usb_sndisocpipe(chip->dev, ep_num);
+ else
+ ep->pipe = usb_rcvisocpipe(chip->dev, ep_num);
+
+ if (type == SND_USB_ENDPOINT_TYPE_SYNC) {
+ if (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
+ get_endpoint(alts, 1)->bRefresh >= 1 &&
+ get_endpoint(alts, 1)->bRefresh <= 9)
+ ep->syncinterval = get_endpoint(alts, 1)->bRefresh;
+ else if (snd_usb_get_speed(chip->dev) == USB_SPEED_FULL)
+ ep->syncinterval = 1;
+ else if (get_endpoint(alts, 1)->bInterval >= 1 &&
+ get_endpoint(alts, 1)->bInterval <= 16)
+ ep->syncinterval = get_endpoint(alts, 1)->bInterval - 1;
+ else
+ ep->syncinterval = 3;
+
+ ep->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize);
+ }
+
+ list_add_tail(&ep->list, &chip->ep_list);
+
+__exit_unlock:
+ mutex_unlock(&chip->mutex);
+
+ return ep;
}
/*
* wait until all urbs are processed.
*/
-static int wait_clear_urbs(struct snd_usb_substream *subs)
+static int wait_clear_urbs(struct snd_usb_endpoint *ep)
{
unsigned long end_time = jiffies + msecs_to_jiffies(1000);
unsigned int i;
@@ -121,153 +497,148 @@ static int wait_clear_urbs(struct snd_usb_substream *subs)
do {
alive = 0;
- for (i = 0; i < subs->nurbs; i++) {
- if (test_bit(i, &subs->active_mask))
+ for (i = 0; i < ep->nurbs; i++)
+ if (test_bit(i, &ep->active_mask))
alive++;
- }
- if (subs->syncpipe) {
- for (i = 0; i < SYNC_URBS; i++) {
- if (test_bit(i + 16, &subs->active_mask))
- alive++;
- }
- }
- if (! alive)
+
+ if (!alive)
break;
+
schedule_timeout_uninterruptible(1);
} while (time_before(jiffies, end_time));
+
if (alive)
- snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
+ snd_printk(KERN_ERR "timeout: still %d active urbs on EP #%x\n",
+ alive, ep->ep_num);
+
return 0;
}
/*
- * release a substream
+ * unlink active urbs.
*/
-void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force)
+static int deactivate_urbs(struct snd_usb_endpoint *ep, int force, int can_sleep)
{
- int i;
+ unsigned int i;
+ int async;
- /* stop urbs (to be sure) */
- deactivate_urbs(subs, force, 1);
- wait_clear_urbs(subs);
-
- for (i = 0; i < MAX_URBS; i++)
- release_urb_ctx(&subs->dataurb[i]);
- for (i = 0; i < SYNC_URBS; i++)
- release_urb_ctx(&subs->syncurb[i]);
- usb_free_coherent(subs->dev, SYNC_URBS * 4,
- subs->syncbuf, subs->sync_dma);
- subs->syncbuf = NULL;
- subs->nurbs = 0;
-}
+ if (!force && ep->chip->shutdown) /* to be sure... */
+ return -EBADFD;
-/*
- * complete callback from data urb
- */
-static void snd_complete_urb(struct urb *urb)
-{
- struct snd_urb_ctx *ctx = urb->context;
- struct snd_usb_substream *subs = ctx->subs;
- struct snd_pcm_substream *substream = ctx->subs->pcm_substream;
- int err = 0;
-
- if ((subs->running && subs->ops.retire(subs, substream->runtime, urb)) ||
- !subs->running || /* can be stopped during retire callback */
- (err = subs->ops.prepare(subs, substream->runtime, urb)) < 0 ||
- (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
- clear_bit(ctx->index, &subs->active_mask);
- if (err < 0) {
- snd_printd(KERN_ERR "cannot submit urb (err = %d)\n", err);
- snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+ async = !can_sleep && ep->chip->async_unlink;
+
+ clear_bit(EP_FLAG_RUNNING, &ep->flags);
+
+ INIT_LIST_HEAD(&ep->ready_playback_urbs);
+ ep->next_packet_read_pos = 0;
+ ep->next_packet_write_pos = 0;
+
+ if (!async && in_interrupt())
+ return 0;
+
+ for (i = 0; i < ep->nurbs; i++) {
+ if (test_bit(i, &ep->active_mask)) {
+ if (!test_and_set_bit(i, &ep->unlink_mask)) {
+ struct urb *u = ep->urb[i].urb;
+ if (async)
+ usb_unlink_urb(u);
+ else
+ usb_kill_urb(u);
+ }
}
}
-}
+ return 0;
+}
/*
- * complete callback from sync urb
+ * release an endpoint's urbs
*/
-static void snd_complete_sync_urb(struct urb *urb)
+static void release_urbs(struct snd_usb_endpoint *ep, int force)
{
- struct snd_urb_ctx *ctx = urb->context;
- struct snd_usb_substream *subs = ctx->subs;
- struct snd_pcm_substream *substream = ctx->subs->pcm_substream;
- int err = 0;
-
- if ((subs->running && subs->ops.retire_sync(subs, substream->runtime, urb)) ||
- !subs->running || /* can be stopped during retire callback */
- (err = subs->ops.prepare_sync(subs, substream->runtime, urb)) < 0 ||
- (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
- clear_bit(ctx->index + 16, &subs->active_mask);
- if (err < 0) {
- snd_printd(KERN_ERR "cannot submit sync urb (err = %d)\n", err);
- snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
- }
- }
-}
+ int i;
+ /* route incoming urbs to nirvana */
+ ep->retire_data_urb = NULL;
+ ep->prepare_data_urb = NULL;
+
+ /* stop urbs */
+ deactivate_urbs(ep, force, 1);
+ wait_clear_urbs(ep);
+
+ for (i = 0; i < ep->nurbs; i++)
+ release_urb_ctx(&ep->urb[i]);
+
+ if (ep->syncbuf)
+ usb_free_coherent(ep->chip->dev, SYNC_URBS * 4,
+ ep->syncbuf, ep->sync_dma);
+
+ ep->syncbuf = NULL;
+ ep->nurbs = 0;
+}
/*
- * initialize a substream for plaback/capture
+ * configure a data endpoint
*/
-int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
- unsigned int period_bytes,
- unsigned int rate,
- unsigned int frame_bits)
+static int data_ep_set_params(struct snd_usb_endpoint *ep,
+ struct snd_pcm_hw_params *hw_params,
+ struct audioformat *fmt,
+ struct snd_usb_endpoint *sync_ep)
{
- unsigned int maxsize, i;
- int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
- unsigned int urb_packs, total_packs, packs_per_ms;
- struct snd_usb_audio *chip = subs->stream->chip;
+ unsigned int maxsize, i, urb_packs, total_packs, packs_per_ms;
+ int period_bytes = params_period_bytes(hw_params);
+ int format = params_format(hw_params);
+ int is_playback = usb_pipeout(ep->pipe);
+ int frame_bits = snd_pcm_format_physical_width(params_format(hw_params)) *
+ params_channels(hw_params);
+
+ ep->datainterval = fmt->datainterval;
+ ep->stride = frame_bits >> 3;
+ ep->silence_value = format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0;
- /* calculate the frequency in 16.16 format */
- if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
- subs->freqn = get_usb_full_speed_rate(rate);
- else
- subs->freqn = get_usb_high_speed_rate(rate);
- subs->freqm = subs->freqn;
- subs->freqshift = INT_MIN;
/* calculate max. frequency */
- if (subs->maxpacksize) {
+ if (ep->maxpacksize) {
/* whatever fits into a max. size packet */
- maxsize = subs->maxpacksize;
- subs->freqmax = (maxsize / (frame_bits >> 3))
- << (16 - subs->datainterval);
+ maxsize = ep->maxpacksize;
+ ep->freqmax = (maxsize / (frame_bits >> 3))
+ << (16 - ep->datainterval);
} else {
/* no max. packet size: just take 25% higher than nominal */
- subs->freqmax = subs->freqn + (subs->freqn >> 2);
- maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3))
- >> (16 - subs->datainterval);
+ ep->freqmax = ep->freqn + (ep->freqn >> 2);
+ maxsize = ((ep->freqmax + 0xffff) * (frame_bits >> 3))
+ >> (16 - ep->datainterval);
}
- subs->phase = 0;
- if (subs->fill_max)
- subs->curpacksize = subs->maxpacksize;
+ if (ep->fill_max)
+ ep->curpacksize = ep->maxpacksize;
else
- subs->curpacksize = maxsize;
+ ep->curpacksize = maxsize;
- if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL)
- packs_per_ms = 8 >> subs->datainterval;
+ if (snd_usb_get_speed(ep->chip->dev) != USB_SPEED_FULL)
+ packs_per_ms = 8 >> ep->datainterval;
else
packs_per_ms = 1;
- if (is_playback) {
- urb_packs = max(chip->nrpacks, 1);
- urb_packs = min(urb_packs, (unsigned int)MAX_PACKS);
- } else
+ if (is_playback && !snd_usb_endpoint_implict_feedback_sink(ep)) {
+ urb_packs = max(ep->chip->nrpacks, 1);
+ urb_packs = min(urb_packs, (unsigned int) MAX_PACKS);
+ } else {
urb_packs = 1;
+ }
+
urb_packs *= packs_per_ms;
- if (subs->syncpipe)
- urb_packs = min(urb_packs, 1U << subs->syncinterval);
+
+ if (sync_ep && !snd_usb_endpoint_implict_feedback_sink(ep))
+ urb_packs = min(urb_packs, 1U << sync_ep->syncinterval);
/* decide how many packets to be used */
- if (is_playback) {
+ if (is_playback && !snd_usb_endpoint_implict_feedback_sink(ep)) {
unsigned int minsize, maxpacks;
/* determine how small a packet can be */
- minsize = (subs->freqn >> (16 - subs->datainterval))
+ minsize = (ep->freqn >> (16 - ep->datainterval))
* (frame_bits >> 3);
/* with sync from device, assume it can be 12% lower */
- if (subs->syncpipe)
+ if (sync_ep)
minsize -= minsize >> 3;
minsize = max(minsize, 1u);
total_packs = (period_bytes + minsize - 1) / minsize;
@@ -284,284 +655,472 @@ int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
urb_packs >>= 1;
total_packs = MAX_URBS * urb_packs;
}
- subs->nurbs = (total_packs + urb_packs - 1) / urb_packs;
- if (subs->nurbs > MAX_URBS) {
+
+ ep->nurbs = (total_packs + urb_packs - 1) / urb_packs;
+ if (ep->nurbs > MAX_URBS) {
/* too much... */
- subs->nurbs = MAX_URBS;
+ ep->nurbs = MAX_URBS;
total_packs = MAX_URBS * urb_packs;
- } else if (subs->nurbs < 2) {
+ } else if (ep->nurbs < 2) {
/* too little - we need at least two packets
* to ensure contiguous playback/capture
*/
- subs->nurbs = 2;
+ ep->nurbs = 2;
}
/* allocate and initialize data urbs */
- for (i = 0; i < subs->nurbs; i++) {
- struct snd_urb_ctx *u = &subs->dataurb[i];
+ for (i = 0; i < ep->nurbs; i++) {
+ struct snd_urb_ctx *u = &ep->urb[i];
u->index = i;
- u->subs = subs;
- u->packets = (i + 1) * total_packs / subs->nurbs
- - i * total_packs / subs->nurbs;
+ u->ep = ep;
+ u->packets = (i + 1) * total_packs / ep->nurbs
+ - i * total_packs / ep->nurbs;
u->buffer_size = maxsize * u->packets;
- if (subs->fmt_type == UAC_FORMAT_TYPE_II)
+
+ if (fmt->fmt_type == UAC_FORMAT_TYPE_II)
u->packets++; /* for transfer delimiter */
u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
if (!u->urb)
goto out_of_memory;
+
u->urb->transfer_buffer =
- usb_alloc_coherent(subs->dev, u->buffer_size,
+ usb_alloc_coherent(ep->chip->dev, u->buffer_size,
GFP_KERNEL, &u->urb->transfer_dma);
if (!u->urb->transfer_buffer)
goto out_of_memory;
- u->urb->pipe = subs->datapipe;
+ u->urb->pipe = ep->pipe;
u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
- u->urb->interval = 1 << subs->datainterval;
+ u->urb->interval = 1 << ep->datainterval;
u->urb->context = u;
u->urb->complete = snd_complete_urb;
+ INIT_LIST_HEAD(&u->ready_list);
}
- if (subs->syncpipe) {
- /* allocate and initialize sync urbs */
- subs->syncbuf = usb_alloc_coherent(subs->dev, SYNC_URBS * 4,
- GFP_KERNEL, &subs->sync_dma);
- if (!subs->syncbuf)
- goto out_of_memory;
- for (i = 0; i < SYNC_URBS; i++) {
- struct snd_urb_ctx *u = &subs->syncurb[i];
- u->index = i;
- u->subs = subs;
- u->packets = 1;
- u->urb = usb_alloc_urb(1, GFP_KERNEL);
- if (!u->urb)
- goto out_of_memory;
- u->urb->transfer_buffer = subs->syncbuf + i * 4;
- u->urb->transfer_dma = subs->sync_dma + i * 4;
- u->urb->transfer_buffer_length = 4;
- u->urb->pipe = subs->syncpipe;
- u->urb->transfer_flags = URB_ISO_ASAP |
- URB_NO_TRANSFER_DMA_MAP;
- u->urb->number_of_packets = 1;
- u->urb->interval = 1 << subs->syncinterval;
- u->urb->context = u;
- u->urb->complete = snd_complete_sync_urb;
- }
- }
return 0;
out_of_memory:
- snd_usb_release_substream_urbs(subs, 0);
+ release_urbs(ep, 0);
return -ENOMEM;
}
/*
- * prepare urb for full speed capture sync pipe
- *
- * fill the length and offset of each urb descriptor.
- * the fixed 10.14 frequency is passed through the pipe.
+ * configure a sync endpoint
*/
-static int prepare_capture_sync_urb(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
+static int sync_ep_set_params(struct snd_usb_endpoint *ep,
+ struct snd_pcm_hw_params *hw_params,
+ struct audioformat *fmt)
{
- unsigned char *cp = urb->transfer_buffer;
- struct snd_urb_ctx *ctx = urb->context;
+ int i;
+
+ ep->syncbuf = usb_alloc_coherent(ep->chip->dev, SYNC_URBS * 4,
+ GFP_KERNEL, &ep->sync_dma);
+ if (!ep->syncbuf)
+ return -ENOMEM;
+
+ for (i = 0; i < SYNC_URBS; i++) {
+ struct snd_urb_ctx *u = &ep->urb[i];
+ u->index = i;
+ u->ep = ep;
+ u->packets = 1;
+ u->urb = usb_alloc_urb(1, GFP_KERNEL);
+ if (!u->urb)
+ goto out_of_memory;
+ u->urb->transfer_buffer = ep->syncbuf + i * 4;
+ u->urb->transfer_dma = ep->sync_dma + i * 4;
+ u->urb->transfer_buffer_length = 4;
+ u->urb->pipe = ep->pipe;
+ u->urb->transfer_flags = URB_ISO_ASAP |
+ URB_NO_TRANSFER_DMA_MAP;
+ u->urb->number_of_packets = 1;
+ u->urb->interval = 1 << ep->syncinterval;
+ u->urb->context = u;
+ u->urb->complete = snd_complete_urb;
+ }
+
+ ep->nurbs = SYNC_URBS;
- urb->dev = ctx->subs->dev; /* we need to set this at each time */
- urb->iso_frame_desc[0].length = 3;
- urb->iso_frame_desc[0].offset = 0;
- cp[0] = subs->freqn >> 2;
- cp[1] = subs->freqn >> 10;
- cp[2] = subs->freqn >> 18;
return 0;
+
+out_of_memory:
+ release_urbs(ep, 0);
+ return -ENOMEM;
}
-/*
- * prepare urb for high speed capture sync pipe
+/**
+ * snd_usb_endpoint_set_params: configure an snd_usb_endpoint
+ *
+ * @ep: the snd_usb_endpoint to configure
+ * @hw_params: the hardware parameters
+ * @fmt: the USB audio format information
+ * @sync_ep: the sync endpoint to use, if any
*
- * fill the length and offset of each urb descriptor.
- * the fixed 12.13 frequency is passed as 16.16 through the pipe.
+ * Determine the number of URBs to be used on this endpoint.
+ * An endpoint must be configured before it can be started.
+ * An endpoint that is already running can not be reconfigured.
*/
-static int prepare_capture_sync_urb_hs(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
+int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
+ struct snd_pcm_hw_params *hw_params,
+ struct audioformat *fmt,
+ struct snd_usb_endpoint *sync_ep)
{
- unsigned char *cp = urb->transfer_buffer;
- struct snd_urb_ctx *ctx = urb->context;
+ int err;
- urb->dev = ctx->subs->dev; /* we need to set this at each time */
- urb->iso_frame_desc[0].length = 4;
- urb->iso_frame_desc[0].offset = 0;
- cp[0] = subs->freqn;
- cp[1] = subs->freqn >> 8;
- cp[2] = subs->freqn >> 16;
- cp[3] = subs->freqn >> 24;
- return 0;
+ if (ep->use_count != 0) {
+ snd_printk(KERN_WARNING "Unable to change format on ep #%x: already in use\n",
+ ep->ep_num);
+ return -EBUSY;
+ }
+
+ /* release old buffers, if any */
+ release_urbs(ep, 0);
+
+ ep->datainterval = fmt->datainterval;
+ ep->maxpacksize = fmt->maxpacksize;
+ ep->fill_max = !!(fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX);
+
+ if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_FULL)
+ ep->freqn = get_usb_full_speed_rate(params_rate(hw_params));
+ else
+ ep->freqn = get_usb_high_speed_rate(params_rate(hw_params));
+
+ /* calculate the frequency in 16.16 format */
+ ep->freqm = ep->freqn;
+ ep->freqshift = INT_MIN;
+
+ ep->phase = 0;
+
+ switch (ep->type) {
+ case SND_USB_ENDPOINT_TYPE_DATA:
+ err = data_ep_set_params(ep, hw_params, fmt, sync_ep);
+ break;
+ case SND_USB_ENDPOINT_TYPE_SYNC:
+ err = sync_ep_set_params(ep, hw_params, fmt);
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ snd_printdd(KERN_DEBUG "Setting params for ep #%x (type %d, %d urbs), ret=%d\n",
+ ep->ep_num, ep->type, ep->nurbs, err);
+
+ return err;
}
-/*
- * process after capture sync complete
- * - nothing to do
+/**
+ * snd_usb_endpoint_start: start an snd_usb_endpoint
+ *
+ * @ep: the endpoint to start
+ *
+ * A call to this function will increment the use count of the endpoint.
+ * In case it is not already running, the URBs for this endpoint will be
+ * submitted. Otherwise, this function does nothing.
+ *
+ * Must be balanced to calls of snd_usb_endpoint_stop().
+ *
+ * Returns an error if the URB submission failed, 0 in all other cases.
*/
-static int retire_capture_sync_urb(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
+int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
{
+ int err;
+ unsigned int i;
+
+ if (ep->chip->shutdown)
+ return -EBADFD;
+
+ /* already running? */
+ if (++ep->use_count != 1)
+ return 0;
+
+ if (snd_BUG_ON(!test_bit(EP_FLAG_ACTIVATED, &ep->flags)))
+ return -EINVAL;
+
+ /* just to be sure */
+ deactivate_urbs(ep, 0, 1);
+ wait_clear_urbs(ep);
+
+ ep->active_mask = 0;
+ ep->unlink_mask = 0;
+ ep->phase = 0;
+
+ /*
+ * If this endpoint has a data endpoint as implicit feedback source,
+ * don't start the urbs here. Instead, mark them all as available,
+ * wait for the record urbs to return and queue the playback urbs
+ * from that context.
+ */
+
+ set_bit(EP_FLAG_RUNNING, &ep->flags);
+
+ if (snd_usb_endpoint_implict_feedback_sink(ep)) {
+ for (i = 0; i < ep->nurbs; i++) {
+ struct snd_urb_ctx *ctx = ep->urb + i;
+ list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs);
+ }
+
+ return 0;
+ }
+
+ for (i = 0; i < ep->nurbs; i++) {
+ struct urb *urb = ep->urb[i].urb;
+
+ if (snd_BUG_ON(!urb))
+ goto __error;
+
+ if (usb_pipeout(ep->pipe)) {
+ prepare_outbound_urb_sizes(ep, urb->context);
+ prepare_outbound_urb(ep, urb->context);
+ } else {
+ prepare_inbound_urb(ep, urb->context);
+ }
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err < 0) {
+ snd_printk(KERN_ERR "cannot submit urb %d, error %d: %s\n",
+ i, err, usb_error_string(err));
+ goto __error;
+ }
+ set_bit(i, &ep->active_mask);
+ }
+
return 0;
+
+__error:
+ clear_bit(EP_FLAG_RUNNING, &ep->flags);
+ ep->use_count--;
+ deactivate_urbs(ep, 0, 0);
+ return -EPIPE;
}
-/*
- * prepare urb for capture data pipe
+/**
+ * snd_usb_endpoint_stop: stop an snd_usb_endpoint
+ *
+ * @ep: the endpoint to stop (may be NULL)
*
- * fill the offset and length of each descriptor.
+ * A call to this function will decrement the use count of the endpoint.
+ * In case the last user has requested the endpoint stop, the URBs will
+ * actually be deactivated.
*
- * we use a temporary buffer to write the captured data.
- * since the length of written data is determined by host, we cannot
- * write onto the pcm buffer directly... the data is thus copied
- * later at complete callback to the global buffer.
+ * Must be balanced to calls of snd_usb_endpoint_start().
*/
-static int prepare_capture_urb(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
+void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep,
+ int force, int can_sleep, int wait)
{
- int i, offs;
- struct snd_urb_ctx *ctx = urb->context;
+ if (!ep)
+ return;
- offs = 0;
- urb->dev = ctx->subs->dev; /* we need to set this at each time */
- for (i = 0; i < ctx->packets; i++) {
- urb->iso_frame_desc[i].offset = offs;
- urb->iso_frame_desc[i].length = subs->curpacksize;
- offs += subs->curpacksize;
+ if (snd_BUG_ON(ep->use_count == 0))
+ return;
+
+ if (snd_BUG_ON(!test_bit(EP_FLAG_ACTIVATED, &ep->flags)))
+ return;
+
+ if (--ep->use_count == 0) {
+ deactivate_urbs(ep, force, can_sleep);
+ ep->data_subs = NULL;
+ ep->sync_slave = NULL;
+ ep->retire_data_urb = NULL;
+ ep->prepare_data_urb = NULL;
+
+ if (wait)
+ wait_clear_urbs(ep);
}
- urb->transfer_buffer_length = offs;
- urb->number_of_packets = ctx->packets;
- return 0;
}
-/*
- * process after capture complete
+/**
+ * snd_usb_endpoint_activate: activate an snd_usb_endpoint
+ *
+ * @ep: the endpoint to activate
+ *
+ * If the endpoint is not currently in use, this functions will select the
+ * correct alternate interface setting for the interface of this endpoint.
*
- * copy the data from each desctiptor to the pcm buffer, and
- * update the current position.
+ * In case of any active users, this functions does nothing.
+ *
+ * Returns an error if usb_set_interface() failed, 0 in all other
+ * cases.
*/
-static int retire_capture_urb(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
+int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep)
{
- unsigned long flags;
- unsigned char *cp;
- int i;
- unsigned int stride, frames, bytes, oldptr;
- int period_elapsed = 0;
+ if (ep->use_count != 0)
+ return 0;
- stride = runtime->frame_bits >> 3;
+ if (!ep->chip->shutdown &&
+ !test_and_set_bit(EP_FLAG_ACTIVATED, &ep->flags)) {
+ int ret;
- for (i = 0; i < urb->number_of_packets; i++) {
- cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
- if (urb->iso_frame_desc[i].status && printk_ratelimit()) {
- snd_printdd("frame %d active: %d\n", i, urb->iso_frame_desc[i].status);
- // continue;
- }
- bytes = urb->iso_frame_desc[i].actual_length;
- frames = bytes / stride;
- if (!subs->txfr_quirk)
- bytes = frames * stride;
- if (bytes % (runtime->sample_bits >> 3) != 0) {
-#ifdef CONFIG_SND_DEBUG_VERBOSE
- int oldbytes = bytes;
-#endif
- bytes = frames * stride;
- snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n",
- oldbytes, bytes);
- }
- /* update the current pointer */
- spin_lock_irqsave(&subs->lock, flags);
- oldptr = subs->hwptr_done;
- subs->hwptr_done += bytes;
- if (subs->hwptr_done >= runtime->buffer_size * stride)
- subs->hwptr_done -= runtime->buffer_size * stride;
- frames = (bytes + (oldptr % stride)) / stride;
- subs->transfer_done += frames;
- if (subs->transfer_done >= runtime->period_size) {
- subs->transfer_done -= runtime->period_size;
- period_elapsed = 1;
- }
- spin_unlock_irqrestore(&subs->lock, flags);
- /* copy a data chunk */
- if (oldptr + bytes > runtime->buffer_size * stride) {
- unsigned int bytes1 =
- runtime->buffer_size * stride - oldptr;
- memcpy(runtime->dma_area + oldptr, cp, bytes1);
- memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1);
- } else {
- memcpy(runtime->dma_area + oldptr, cp, bytes);
+ ret = usb_set_interface(ep->chip->dev, ep->iface, ep->alt_idx);
+ if (ret < 0) {
+ snd_printk(KERN_ERR "%s() usb_set_interface() failed, ret = %d\n",
+ __func__, ret);
+ clear_bit(EP_FLAG_ACTIVATED, &ep->flags);
+ return ret;
}
+
+ return 0;
}
- if (period_elapsed)
- snd_pcm_period_elapsed(subs->pcm_substream);
- return 0;
+
+ return -EBUSY;
}
-/*
- * Process after capture complete when paused. Nothing to do.
+/**
+ * snd_usb_endpoint_deactivate: deactivate an snd_usb_endpoint
+ *
+ * @ep: the endpoint to deactivate
+ *
+ * If the endpoint is not currently in use, this functions will select the
+ * alternate interface setting 0 for the interface of this endpoint.
+ *
+ * In case of any active users, this functions does nothing.
+ *
+ * Returns an error if usb_set_interface() failed, 0 in all other
+ * cases.
*/
-static int retire_paused_capture_urb(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
+int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep)
{
- return 0;
-}
+ if (!ep)
+ return -EINVAL;
+ if (ep->use_count != 0)
+ return 0;
-/*
- * prepare urb for playback sync pipe
+ if (!ep->chip->shutdown &&
+ test_and_clear_bit(EP_FLAG_ACTIVATED, &ep->flags)) {
+ int ret;
+
+ ret = usb_set_interface(ep->chip->dev, ep->iface, 0);
+ if (ret < 0) {
+ snd_printk(KERN_ERR "%s(): usb_set_interface() failed, ret = %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ return 0;
+ }
+
+ return -EBUSY;
+}
+
+/**
+ * snd_usb_endpoint_free: Free the resources of an snd_usb_endpoint
+ *
+ * @ep: the list header of the endpoint to free
*
- * set up the offset and length to receive the current frequency.
+ * This function does not care for the endpoint's use count but will tear
+ * down all the streaming URBs immediately and free all resources.
*/
-static int prepare_playback_sync_urb(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
+void snd_usb_endpoint_free(struct list_head *head)
{
- struct snd_urb_ctx *ctx = urb->context;
+ struct snd_usb_endpoint *ep;
- urb->dev = ctx->subs->dev; /* we need to set this at each time */
- urb->iso_frame_desc[0].length = min(4u, ctx->subs->syncmaxsize);
- urb->iso_frame_desc[0].offset = 0;
- return 0;
+ ep = list_entry(head, struct snd_usb_endpoint, list);
+ release_urbs(ep, 1);
+ kfree(ep);
}
-/*
- * process after playback sync complete
- *
- * Full speed devices report feedback values in 10.14 format as samples per
- * frame, high speed devices in 16.16 format as samples per microframe.
- * Because the Audio Class 1 spec was written before USB 2.0, many high speed
- * devices use a wrong interpretation, some others use an entirely different
- * format. Therefore, we cannot predict what format any particular device uses
- * and must detect it automatically.
+/**
+ * snd_usb_handle_sync_urb: parse an USB sync packet
+ *
+ * @ep: the endpoint to handle the packet
+ * @sender: the sending endpoint
+ * @urb: the received packet
+ *
+ * This function is called from the context of an endpoint that received
+ * the packet and is used to let another endpoint object handle the payload.
*/
-static int retire_playback_sync_urb(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
+void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,
+ struct snd_usb_endpoint *sender,
+ const struct urb *urb)
{
- unsigned int f;
int shift;
+ unsigned int f;
unsigned long flags;
+ snd_BUG_ON(ep == sender);
+
+ /*
+ * In case the endpoint is operating in implicit feedback mode, prepare
+ * a new outbound URB that has the same layout as the received packet
+ * and add it to the list of pending urbs. queue_pending_output_urbs()
+ * will take care of them later.
+ */
+ if (snd_usb_endpoint_implict_feedback_sink(ep) &&
+ ep->use_count != 0) {
+
+ /* implicit feedback case */
+ int i, bytes = 0;
+ struct snd_urb_ctx *in_ctx;
+ struct snd_usb_packet_info *out_packet;
+
+ in_ctx = urb->context;
+
+ /* Count overall packet size */
+ for (i = 0; i < in_ctx->packets; i++)
+ if (urb->iso_frame_desc[i].status == 0)
+ bytes += urb->iso_frame_desc[i].actual_length;
+
+ /*
+ * skip empty packets. At least M-Audio's Fast Track Ultra stops
+ * streaming once it received a 0-byte OUT URB
+ */
+ if (bytes == 0)
+ return;
+
+ spin_lock_irqsave(&ep->lock, flags);
+ out_packet = ep->next_packet + ep->next_packet_write_pos;
+
+ /*
+ * Iterate through the inbound packet and prepare the lengths
+ * for the output packet. The OUT packet we are about to send
+ * will have the same amount of payload bytes than the IN
+ * packet we just received.
+ */
+
+ out_packet->packets = in_ctx->packets;
+ for (i = 0; i < in_ctx->packets; i++) {
+ if (urb->iso_frame_desc[i].status == 0)
+ out_packet->packet_size[i] =
+ urb->iso_frame_desc[i].actual_length / ep->stride;
+ else
+ out_packet->packet_size[i] = 0;
+ }
+
+ ep->next_packet_write_pos++;
+ ep->next_packet_write_pos %= MAX_URBS;
+ spin_unlock_irqrestore(&ep->lock, flags);
+ queue_pending_output_urbs(ep);
+
+ return;
+ }
+
+ /*
+ * process after playback sync complete
+ *
+ * Full speed devices report feedback values in 10.14 format as samples
+ * per frame, high speed devices in 16.16 format as samples per
+ * microframe.
+ *
+ * Because the Audio Class 1 spec was written before USB 2.0, many high
+ * speed devices use a wrong interpretation, some others use an
+ * entirely different format.
+ *
+ * Therefore, we cannot predict what format any particular device uses
+ * and must detect it automatically.
+ */
+
if (urb->iso_frame_desc[0].status != 0 ||
urb->iso_frame_desc[0].actual_length < 3)
- return 0;
+ return;
f = le32_to_cpup(urb->transfer_buffer);
if (urb->iso_frame_desc[0].actual_length == 3)
f &= 0x00ffffff;
else
f &= 0x0fffffff;
+
if (f == 0)
- return 0;
+ return;
- if (unlikely(subs->freqshift == INT_MIN)) {
+ if (unlikely(ep->freqshift == INT_MIN)) {
/*
* The first time we see a feedback value, determine its format
* by shifting it left or right until it matches the nominal
@@ -569,398 +1128,34 @@ static int retire_playback_sync_urb(struct snd_usb_substream *subs,
* differ from the nominal value more than +50% or -25%.
*/
shift = 0;
- while (f < subs->freqn - subs->freqn / 4) {
+ while (f < ep->freqn - ep->freqn / 4) {
f <<= 1;
shift++;
}
- while (f > subs->freqn + subs->freqn / 2) {
+ while (f > ep->freqn + ep->freqn / 2) {
f >>= 1;
shift--;
}
- subs->freqshift = shift;
- }
- else if (subs->freqshift >= 0)
- f <<= subs->freqshift;
+ ep->freqshift = shift;
+ } else if (ep->freqshift >= 0)
+ f <<= ep->freqshift;
else
- f >>= -subs->freqshift;
+ f >>= -ep->freqshift;
- if (likely(f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax)) {
+ if (likely(f >= ep->freqn - ep->freqn / 8 && f <= ep->freqmax)) {
/*
* If the frequency looks valid, set it.
* This value is referred to in prepare_playback_urb().
*/
- spin_lock_irqsave(&subs->lock, flags);
- subs->freqm = f;
- spin_unlock_irqrestore(&subs->lock, flags);
+ spin_lock_irqsave(&ep->lock, flags);
+ ep->freqm = f;
+ spin_unlock_irqrestore(&ep->lock, flags);
} else {
/*
* Out of range; maybe the shift value is wrong.
* Reset it so that we autodetect again the next time.
*/
- subs->freqshift = INT_MIN;
- }
-
- return 0;
-}
-
-/* determine the number of frames in the next packet */
-static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs)
-{
- if (subs->fill_max)
- return subs->maxframesize;
- else {
- subs->phase = (subs->phase & 0xffff)
- + (subs->freqm << subs->datainterval);
- return min(subs->phase >> 16, subs->maxframesize);
+ ep->freqshift = INT_MIN;
}
}
-/*
- * Prepare urb for streaming before playback starts or when paused.
- *
- * We don't have any data, so we send silence.
- */
-static int prepare_nodata_playback_urb(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
-{
- unsigned int i, offs, counts;
- struct snd_urb_ctx *ctx = urb->context;
- int stride = runtime->frame_bits >> 3;
-
- offs = 0;
- urb->dev = ctx->subs->dev;
- for (i = 0; i < ctx->packets; ++i) {
- counts = snd_usb_audio_next_packet_size(subs);
- urb->iso_frame_desc[i].offset = offs * stride;
- urb->iso_frame_desc[i].length = counts * stride;
- offs += counts;
- }
- urb->number_of_packets = ctx->packets;
- urb->transfer_buffer_length = offs * stride;
- memset(urb->transfer_buffer,
- runtime->format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0,
- offs * stride);
- return 0;
-}
-
-/*
- * prepare urb for playback data pipe
- *
- * Since a URB can handle only a single linear buffer, we must use double
- * buffering when the data to be transferred overflows the buffer boundary.
- * To avoid inconsistencies when updating hwptr_done, we use double buffering
- * for all URBs.
- */
-static int prepare_playback_urb(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
-{
- int i, stride;
- unsigned int counts, frames, bytes;
- unsigned long flags;
- int period_elapsed = 0;
- struct snd_urb_ctx *ctx = urb->context;
-
- stride = runtime->frame_bits >> 3;
-
- frames = 0;
- urb->dev = ctx->subs->dev; /* we need to set this at each time */
- urb->number_of_packets = 0;
- spin_lock_irqsave(&subs->lock, flags);
- for (i = 0; i < ctx->packets; i++) {
- counts = snd_usb_audio_next_packet_size(subs);
- /* set up descriptor */
- urb->iso_frame_desc[i].offset = frames * stride;
- urb->iso_frame_desc[i].length = counts * stride;
- frames += counts;
- urb->number_of_packets++;
- subs->transfer_done += counts;
- if (subs->transfer_done >= runtime->period_size) {
- subs->transfer_done -= runtime->period_size;
- period_elapsed = 1;
- if (subs->fmt_type == UAC_FORMAT_TYPE_II) {
- if (subs->transfer_done > 0) {
- /* FIXME: fill-max mode is not
- * supported yet */
- frames -= subs->transfer_done;
- counts -= subs->transfer_done;
- urb->iso_frame_desc[i].length =
- counts * stride;
- subs->transfer_done = 0;
- }
- i++;
- if (i < ctx->packets) {
- /* add a transfer delimiter */
- urb->iso_frame_desc[i].offset =
- frames * stride;
- urb->iso_frame_desc[i].length = 0;
- urb->number_of_packets++;
- }
- break;
- }
- }
- if (period_elapsed) /* finish at the period boundary */
- break;
- }
- bytes = frames * stride;
- if (subs->hwptr_done + bytes > runtime->buffer_size * stride) {
- /* err, the transferred area goes over buffer boundary. */
- unsigned int bytes1 =
- runtime->buffer_size * stride - subs->hwptr_done;
- memcpy(urb->transfer_buffer,
- runtime->dma_area + subs->hwptr_done, bytes1);
- memcpy(urb->transfer_buffer + bytes1,
- runtime->dma_area, bytes - bytes1);
- } else {
- memcpy(urb->transfer_buffer,
- runtime->dma_area + subs->hwptr_done, bytes);
- }
- subs->hwptr_done += bytes;
- if (subs->hwptr_done >= runtime->buffer_size * stride)
- subs->hwptr_done -= runtime->buffer_size * stride;
-
- /* update delay with exact number of samples queued */
- runtime->delay = subs->last_delay;
- runtime->delay += frames;
- subs->last_delay = runtime->delay;
-
- /* realign last_frame_number */
- subs->last_frame_number = usb_get_current_frame_number(subs->dev);
- subs->last_frame_number &= 0xFF; /* keep 8 LSBs */
-
- spin_unlock_irqrestore(&subs->lock, flags);
- urb->transfer_buffer_length = bytes;
- if (period_elapsed)
- snd_pcm_period_elapsed(subs->pcm_substream);
- return 0;
-}
-
-/*
- * process after playback data complete
- * - decrease the delay count again
- */
-static int retire_playback_urb(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime,
- struct urb *urb)
-{
- unsigned long flags;
- int stride = runtime->frame_bits >> 3;
- int processed = urb->transfer_buffer_length / stride;
- int est_delay;
-
- spin_lock_irqsave(&subs->lock, flags);
-
- est_delay = snd_usb_pcm_delay(subs, runtime->rate);
- /* update delay with exact number of samples played */
- if (processed > subs->last_delay)
- subs->last_delay = 0;
- else
- subs->last_delay -= processed;
- runtime->delay = subs->last_delay;
-
- /*
- * Report when delay estimate is off by more than 2ms.
- * The error should be lower than 2ms since the estimate relies
- * on two reads of a counter updated every ms.
- */
- if (abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2)
- snd_printk(KERN_DEBUG "delay: estimated %d, actual %d\n",
- est_delay, subs->last_delay);
-
- spin_unlock_irqrestore(&subs->lock, flags);
- return 0;
-}
-
-static const char *usb_error_string(int err)
-{
- switch (err) {
- case -ENODEV:
- return "no device";
- case -ENOENT:
- return "endpoint not enabled";
- case -EPIPE:
- return "endpoint stalled";
- case -ENOSPC:
- return "not enough bandwidth";
- case -ESHUTDOWN:
- return "device disabled";
- case -EHOSTUNREACH:
- return "device suspended";
- case -EINVAL:
- case -EAGAIN:
- case -EFBIG:
- case -EMSGSIZE:
- return "internal error";
- default:
- return "unknown error";
- }
-}
-
-/*
- * set up and start data/sync urbs
- */
-static int start_urbs(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime)
-{
- unsigned int i;
- int err;
-
- if (subs->stream->chip->shutdown)
- return -EBADFD;
-
- for (i = 0; i < subs->nurbs; i++) {
- if (snd_BUG_ON(!subs->dataurb[i].urb))
- return -EINVAL;
- if (subs->ops.prepare(subs, runtime, subs->dataurb[i].urb) < 0) {
- snd_printk(KERN_ERR "cannot prepare datapipe for urb %d\n", i);
- goto __error;
- }
- }
- if (subs->syncpipe) {
- for (i = 0; i < SYNC_URBS; i++) {
- if (snd_BUG_ON(!subs->syncurb[i].urb))
- return -EINVAL;
- if (subs->ops.prepare_sync(subs, runtime, subs->syncurb[i].urb) < 0) {
- snd_printk(KERN_ERR "cannot prepare syncpipe for urb %d\n", i);
- goto __error;
- }
- }
- }
-
- subs->active_mask = 0;
- subs->unlink_mask = 0;
- subs->running = 1;
- for (i = 0; i < subs->nurbs; i++) {
- err = usb_submit_urb(subs->dataurb[i].urb, GFP_ATOMIC);
- if (err < 0) {
- snd_printk(KERN_ERR "cannot submit datapipe "
- "for urb %d, error %d: %s\n",
- i, err, usb_error_string(err));
- goto __error;
- }
- set_bit(i, &subs->active_mask);
- }
- if (subs->syncpipe) {
- for (i = 0; i < SYNC_URBS; i++) {
- err = usb_submit_urb(subs->syncurb[i].urb, GFP_ATOMIC);
- if (err < 0) {
- snd_printk(KERN_ERR "cannot submit syncpipe "
- "for urb %d, error %d: %s\n",
- i, err, usb_error_string(err));
- goto __error;
- }
- set_bit(i + 16, &subs->active_mask);
- }
- }
- return 0;
-
- __error:
- // snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN);
- deactivate_urbs(subs, 0, 0);
- return -EPIPE;
-}
-
-
-/*
- */
-static struct snd_urb_ops audio_urb_ops[2] = {
- {
- .prepare = prepare_nodata_playback_urb,
- .retire = retire_playback_urb,
- .prepare_sync = prepare_playback_sync_urb,
- .retire_sync = retire_playback_sync_urb,
- },
- {
- .prepare = prepare_capture_urb,
- .retire = retire_capture_urb,
- .prepare_sync = prepare_capture_sync_urb,
- .retire_sync = retire_capture_sync_urb,
- },
-};
-
-/*
- * initialize the substream instance.
- */
-
-void snd_usb_init_substream(struct snd_usb_stream *as,
- int stream, struct audioformat *fp)
-{
- struct snd_usb_substream *subs = &as->substream[stream];
-
- INIT_LIST_HEAD(&subs->fmt_list);
- spin_lock_init(&subs->lock);
-
- subs->stream = as;
- subs->direction = stream;
- subs->dev = as->chip->dev;
- subs->txfr_quirk = as->chip->txfr_quirk;
- subs->ops = audio_urb_ops[stream];
- if (snd_usb_get_speed(subs->dev) >= USB_SPEED_HIGH)
- subs->ops.prepare_sync = prepare_capture_sync_urb_hs;
-
- snd_usb_set_pcm_ops(as->pcm, stream);
-
- list_add_tail(&fp->list, &subs->fmt_list);
- subs->formats |= fp->formats;
- subs->endpoint = fp->endpoint;
- subs->num_formats++;
- subs->fmt_type = fp->fmt_type;
-}
-
-int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct snd_usb_substream *subs = substream->runtime->private_data;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- subs->ops.prepare = prepare_playback_urb;
- return 0;
- case SNDRV_PCM_TRIGGER_STOP:
- return deactivate_urbs(subs, 0, 0);
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- subs->ops.prepare = prepare_nodata_playback_urb;
- return 0;
- }
-
- return -EINVAL;
-}
-
-int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct snd_usb_substream *subs = substream->runtime->private_data;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- subs->ops.retire = retire_capture_urb;
- return start_urbs(subs, substream->runtime);
- case SNDRV_PCM_TRIGGER_STOP:
- return deactivate_urbs(subs, 0, 0);
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- subs->ops.retire = retire_paused_capture_urb;
- return 0;
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- subs->ops.retire = retire_capture_urb;
- return 0;
- }
-
- return -EINVAL;
-}
-
-int snd_usb_substream_prepare(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime)
-{
- /* clear urbs (to be sure) */
- deactivate_urbs(subs, 0, 1);
- wait_clear_urbs(subs);
-
- /* for playback, submit the URBs now; otherwise, the first hwptr_done
- * updates for all URBs would happen at the same time when starting */
- if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) {
- subs->ops.prepare = prepare_nodata_playback_urb;
- return start_urbs(subs, runtime);
- }
-
- return 0;
-}
-
diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h
index 88eb63a636eb..ee2723fb174f 100644
--- a/sound/usb/endpoint.h
+++ b/sound/usb/endpoint.h
@@ -1,21 +1,29 @@
#ifndef __USBAUDIO_ENDPOINT_H
#define __USBAUDIO_ENDPOINT_H
-void snd_usb_init_substream(struct snd_usb_stream *as,
- int stream,
- struct audioformat *fp);
+#define SND_USB_ENDPOINT_TYPE_DATA 0
+#define SND_USB_ENDPOINT_TYPE_SYNC 1
-int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
- unsigned int period_bytes,
- unsigned int rate,
- unsigned int frame_bits);
+struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip,
+ struct usb_host_interface *alts,
+ int ep_num, int direction, int type);
-void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force);
+int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
+ struct snd_pcm_hw_params *hw_params,
+ struct audioformat *fmt,
+ struct snd_usb_endpoint *sync_ep);
-int snd_usb_substream_prepare(struct snd_usb_substream *subs,
- struct snd_pcm_runtime *runtime);
+int snd_usb_endpoint_start(struct snd_usb_endpoint *ep);
+void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep,
+ int force, int can_sleep, int wait);
+int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep);
+int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep);
+void snd_usb_endpoint_free(struct list_head *head);
-int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd);
-int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd);
+int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep);
+
+void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep,
+ struct snd_usb_endpoint *sender,
+ const struct urb *urb);
#endif /* __USBAUDIO_ENDPOINT_H */
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index ab23869c01bb..4f40ba823163 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -486,7 +486,7 @@ static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
/*
* TLV callback for mixer volume controls
*/
-static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
unsigned int size, unsigned int __user *_tlv)
{
struct usb_mixer_elem_info *cval = kcontrol->private_data;
@@ -770,6 +770,26 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
struct snd_kcontrol *kctl)
{
switch (cval->mixer->chip->usb_id) {
+ case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */
+ case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */
+ if (strcmp(kctl->id.name, "Effect Duration") == 0) {
+ snd_printk(KERN_INFO
+ "usb-audio: set quirk for FTU Effect Duration\n");
+ cval->min = 0x0000;
+ cval->max = 0x7f00;
+ cval->res = 0x0100;
+ break;
+ }
+ if (strcmp(kctl->id.name, "Effect Volume") == 0 ||
+ strcmp(kctl->id.name, "Effect Feedback Volume") == 0) {
+ snd_printk(KERN_INFO
+ "usb-audio: set quirks for FTU Effect Feedback/Volume\n");
+ cval->min = 0x00;
+ cval->max = 0x7f;
+ break;
+ }
+ break;
+
case USB_ID(0x0471, 0x0101):
case USB_ID(0x0471, 0x0104):
case USB_ID(0x0471, 0x0105):
@@ -1121,9 +1141,6 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
len = snd_usb_copy_string_desc(state, nameid,
kctl->id.name, sizeof(kctl->id.name));
- /* get min/max values */
- get_min_max_with_quirks(cval, 0, kctl);
-
switch (control) {
case UAC_FU_MUTE:
case UAC_FU_VOLUME:
@@ -1155,17 +1172,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
}
append_ctl_name(kctl, control == UAC_FU_MUTE ?
" Switch" : " Volume");
- if (control == UAC_FU_VOLUME) {
- check_mapped_dB(map, cval);
- if (cval->dBmin < cval->dBmax || !cval->initialized) {
- kctl->tlv.c = mixer_vol_tlv;
- kctl->vd[0].access |=
- SNDRV_CTL_ELEM_ACCESS_TLV_READ |
- SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
- }
- }
break;
-
default:
if (! len)
strlcpy(kctl->id.name, audio_feature_info[control-1].name,
@@ -1173,6 +1180,19 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
break;
}
+ /* get min/max values */
+ get_min_max_with_quirks(cval, 0, kctl);
+
+ if (control == UAC_FU_VOLUME) {
+ check_mapped_dB(map, cval);
+ if (cval->dBmin < cval->dBmax || !cval->initialized) {
+ kctl->tlv.c = snd_usb_mixer_vol_tlv;
+ kctl->vd[0].access |=
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+ }
+ }
+
range = (cval->max - cval->min) / cval->res;
/* Are there devices with volume range more than 255? I use a bit more
* to be sure. 384 is a resolution magic number found on Logitech
@@ -1388,7 +1408,7 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, void *r
for (pin = 0; pin < input_pins; pin++) {
err = parse_audio_unit(state, desc->baSourceID[pin]);
if (err < 0)
- return err;
+ continue;
err = check_input_term(state, desc->baSourceID[pin], &iterm);
if (err < 0)
return err;
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index 81b2d8a32fb0..a7f3d45a8acf 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -68,4 +68,7 @@ int snd_usb_mixer_activate(struct usb_mixer_interface *mixer);
int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
struct snd_kcontrol *kctl);
+int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+ unsigned int size, unsigned int __user *_tlv);
+
#endif /* __USBMIXER_H */
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c
index f1324c423835..41daaa24c25f 100644
--- a/sound/usb/mixer_maps.c
+++ b/sound/usb/mixer_maps.c
@@ -288,6 +288,15 @@ static struct usbmix_name_map scratch_live_map[] = {
{ 0 } /* terminator */
};
+static struct usbmix_name_map ebox44_map[] = {
+ { 4, NULL }, /* FU */
+ { 6, NULL }, /* MU */
+ { 7, NULL }, /* FU */
+ { 10, NULL }, /* FU */
+ { 11, NULL }, /* MU */
+ { 0 }
+};
+
/* "Gamesurround Muse Pocket LT" looks same like "Sound Blaster MP3+"
* most importand difference is SU[8], it should be set to "Capture Source"
* to make alsamixer and PA working properly.
@@ -371,6 +380,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
.map = scratch_live_map,
.ignore_ctl_error = 1,
},
+ {
+ .id = USB_ID(0x200c, 0x1018),
+ .map = ebox44_map,
+ },
{ 0 } /* terminator */
};
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index ab125ee0b0f0..41f4b6911920 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -42,6 +42,77 @@
extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl;
+/* private_free callback */
+static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
+{
+ kfree(kctl->private_data);
+ kctl->private_data = NULL;
+}
+
+/* This function allows for the creation of standard UAC controls.
+ * See the quirks for M-Audio FTUs or Ebox-44.
+ * If you don't want to set a TLV callback pass NULL.
+ *
+ * Since there doesn't seem to be a devices that needs a multichannel
+ * version, we keep it mono for simplicity.
+ */
+static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer,
+ unsigned int unitid,
+ unsigned int control,
+ unsigned int cmask,
+ int val_type,
+ const char *name,
+ snd_kcontrol_tlv_rw_t *tlv_callback)
+{
+ int err;
+ struct usb_mixer_elem_info *cval;
+ struct snd_kcontrol *kctl;
+
+ cval = kzalloc(sizeof(*cval), GFP_KERNEL);
+ if (!cval)
+ return -ENOMEM;
+
+ cval->id = unitid;
+ cval->mixer = mixer;
+ cval->val_type = val_type;
+ cval->channels = 1;
+ cval->control = control;
+ cval->cmask = cmask;
+
+ /* get_min_max() is called only for integer volumes later,
+ * so provide a short-cut for booleans */
+ cval->min = 0;
+ cval->max = 1;
+ cval->res = 0;
+ cval->dBmin = 0;
+ cval->dBmax = 0;
+
+ /* Create control */
+ kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval);
+ if (!kctl) {
+ kfree(cval);
+ return -ENOMEM;
+ }
+
+ /* Set name */
+ snprintf(kctl->id.name, sizeof(kctl->id.name), name);
+ kctl->private_free = usb_mixer_elem_free;
+
+ /* set TLV */
+ if (tlv_callback) {
+ kctl->tlv.c = tlv_callback;
+ kctl->vd[0].access |=
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+ }
+ /* Add control to mixer */
+ err = snd_usb_mixer_add_control(mixer, kctl);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
/*
* Sound Blaster remote control configuration
*
@@ -495,60 +566,218 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer,
}
/* M-Audio FastTrack Ultra quirks */
+/* FTU Effect switch */
+struct snd_ftu_eff_switch_priv_val {
+ struct usb_mixer_interface *mixer;
+ int cached_value;
+ int is_cached;
+};
-/* private_free callback */
-static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
+static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
{
- kfree(kctl->private_data);
- kctl->private_data = NULL;
+ static const char *texts[8] = {"Room 1",
+ "Room 2",
+ "Room 3",
+ "Hall 1",
+ "Hall 2",
+ "Plate",
+ "Delay",
+ "Echo"
+ };
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = 8;
+ if (uinfo->value.enumerated.item > 7)
+ uinfo->value.enumerated.item = 7;
+ strcpy(uinfo->value.enumerated.name,
+ texts[uinfo->value.enumerated.item]);
+
+ return 0;
}
-static int snd_maudio_ftu_create_ctl(struct usb_mixer_interface *mixer,
- int in, int out, const char *name)
+static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
{
- struct usb_mixer_elem_info *cval;
+ struct snd_usb_audio *chip;
+ struct usb_mixer_interface *mixer;
+ struct snd_ftu_eff_switch_priv_val *pval;
+ int err;
+ unsigned char value[2];
+
+ const int id = 6;
+ const int validx = 1;
+ const int val_len = 2;
+
+ value[0] = 0x00;
+ value[1] = 0x00;
+
+ pval = (struct snd_ftu_eff_switch_priv_val *)
+ kctl->private_value;
+
+ if (pval->is_cached) {
+ ucontrol->value.enumerated.item[0] = pval->cached_value;
+ return 0;
+ }
+
+ mixer = (struct usb_mixer_interface *) pval->mixer;
+ if (snd_BUG_ON(!mixer))
+ return -EINVAL;
+
+ chip = (struct snd_usb_audio *) mixer->chip;
+ if (snd_BUG_ON(!chip))
+ return -EINVAL;
+
+
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
+ value, val_len);
+ if (err < 0)
+ return err;
+
+ ucontrol->value.enumerated.item[0] = value[0];
+ pval->cached_value = value[0];
+ pval->is_cached = 1;
+
+ return 0;
+}
+
+static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_usb_audio *chip;
+ struct snd_ftu_eff_switch_priv_val *pval;
+
+ struct usb_mixer_interface *mixer;
+ int changed, cur_val, err, new_val;
+ unsigned char value[2];
+
+
+ const int id = 6;
+ const int validx = 1;
+ const int val_len = 2;
+
+ changed = 0;
+
+ pval = (struct snd_ftu_eff_switch_priv_val *)
+ kctl->private_value;
+ cur_val = pval->cached_value;
+ new_val = ucontrol->value.enumerated.item[0];
+
+ mixer = (struct usb_mixer_interface *) pval->mixer;
+ if (snd_BUG_ON(!mixer))
+ return -EINVAL;
+
+ chip = (struct snd_usb_audio *) mixer->chip;
+ if (snd_BUG_ON(!chip))
+ return -EINVAL;
+
+ if (!pval->is_cached) {
+ /* Read current value */
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
+ value, val_len);
+ if (err < 0)
+ return err;
+
+ cur_val = value[0];
+ pval->cached_value = cur_val;
+ pval->is_cached = 1;
+ }
+ /* update value if needed */
+ if (cur_val != new_val) {
+ value[0] = new_val;
+ value[1] = 0;
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+ validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
+ value, val_len);
+ if (err < 0)
+ return err;
+
+ pval->cached_value = new_val;
+ pval->is_cached = 1;
+ changed = 1;
+ }
+
+ return changed;
+}
+
+static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer)
+{
+ static struct snd_kcontrol_new template = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Effect Program Switch",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_ftu_eff_switch_info,
+ .get = snd_ftu_eff_switch_get,
+ .put = snd_ftu_eff_switch_put
+ };
+
+ int err;
struct snd_kcontrol *kctl;
+ struct snd_ftu_eff_switch_priv_val *pval;
- cval = kzalloc(sizeof(*cval), GFP_KERNEL);
- if (!cval)
+ pval = kzalloc(sizeof(*pval), GFP_KERNEL);
+ if (!pval)
return -ENOMEM;
- cval->id = 5;
- cval->mixer = mixer;
- cval->val_type = USB_MIXER_S16;
- cval->channels = 1;
- cval->control = out + 1;
- cval->cmask = 1 << in;
+ pval->cached_value = 0;
+ pval->is_cached = 0;
+ pval->mixer = mixer;
- kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval);
+ template.private_value = (unsigned long) pval;
+ kctl = snd_ctl_new1(&template, mixer->chip);
if (!kctl) {
- kfree(cval);
+ kfree(pval);
return -ENOMEM;
}
- snprintf(kctl->id.name, sizeof(kctl->id.name), name);
- kctl->private_free = usb_mixer_elem_free;
- return snd_usb_mixer_add_control(mixer, kctl);
+ err = snd_ctl_add(mixer->chip->card, kctl);
+ if (err < 0)
+ return err;
+
+ return 0;
}
-static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer)
+/* Create volume controls for FTU devices*/
+static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer)
{
char name[64];
+ unsigned int control, cmask;
int in, out, err;
+ const unsigned int id = 5;
+ const int val_type = USB_MIXER_S16;
+
for (out = 0; out < 8; out++) {
+ control = out + 1;
for (in = 0; in < 8; in++) {
+ cmask = 1 << in;
snprintf(name, sizeof(name),
- "AIn%d - Out%d Capture Volume", in + 1, out + 1);
- err = snd_maudio_ftu_create_ctl(mixer, in, out, name);
+ "AIn%d - Out%d Capture Volume",
+ in + 1, out + 1);
+ err = snd_create_std_mono_ctl(mixer, id, control,
+ cmask, val_type, name,
+ &snd_usb_mixer_vol_tlv);
if (err < 0)
return err;
}
-
for (in = 8; in < 16; in++) {
+ cmask = 1 << in;
snprintf(name, sizeof(name),
- "DIn%d - Out%d Playback Volume", in - 7, out + 1);
- err = snd_maudio_ftu_create_ctl(mixer, in, out, name);
+ "DIn%d - Out%d Playback Volume",
+ in - 7, out + 1);
+ err = snd_create_std_mono_ctl(mixer, id, control,
+ cmask, val_type, name,
+ &snd_usb_mixer_vol_tlv);
if (err < 0)
return err;
}
@@ -557,6 +786,191 @@ static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer)
return 0;
}
+/* This control needs a volume quirk, see mixer.c */
+static int snd_ftu_create_effect_volume_ctl(struct usb_mixer_interface *mixer)
+{
+ static const char name[] = "Effect Volume";
+ const unsigned int id = 6;
+ const int val_type = USB_MIXER_U8;
+ const unsigned int control = 2;
+ const unsigned int cmask = 0;
+
+ return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
+ name, snd_usb_mixer_vol_tlv);
+}
+
+/* This control needs a volume quirk, see mixer.c */
+static int snd_ftu_create_effect_duration_ctl(struct usb_mixer_interface *mixer)
+{
+ static const char name[] = "Effect Duration";
+ const unsigned int id = 6;
+ const int val_type = USB_MIXER_S16;
+ const unsigned int control = 3;
+ const unsigned int cmask = 0;
+
+ return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
+ name, snd_usb_mixer_vol_tlv);
+}
+
+/* This control needs a volume quirk, see mixer.c */
+static int snd_ftu_create_effect_feedback_ctl(struct usb_mixer_interface *mixer)
+{
+ static const char name[] = "Effect Feedback Volume";
+ const unsigned int id = 6;
+ const int val_type = USB_MIXER_U8;
+ const unsigned int control = 4;
+ const unsigned int cmask = 0;
+
+ return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type,
+ name, NULL);
+}
+
+static int snd_ftu_create_effect_return_ctls(struct usb_mixer_interface *mixer)
+{
+ unsigned int cmask;
+ int err, ch;
+ char name[48];
+
+ const unsigned int id = 7;
+ const int val_type = USB_MIXER_S16;
+ const unsigned int control = 7;
+
+ for (ch = 0; ch < 4; ++ch) {
+ cmask = 1 << ch;
+ snprintf(name, sizeof(name),
+ "Effect Return %d Volume", ch + 1);
+ err = snd_create_std_mono_ctl(mixer, id, control,
+ cmask, val_type, name,
+ snd_usb_mixer_vol_tlv);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static int snd_ftu_create_effect_send_ctls(struct usb_mixer_interface *mixer)
+{
+ unsigned int cmask;
+ int err, ch;
+ char name[48];
+
+ const unsigned int id = 5;
+ const int val_type = USB_MIXER_S16;
+ const unsigned int control = 9;
+
+ for (ch = 0; ch < 8; ++ch) {
+ cmask = 1 << ch;
+ snprintf(name, sizeof(name),
+ "Effect Send AIn%d Volume", ch + 1);
+ err = snd_create_std_mono_ctl(mixer, id, control, cmask,
+ val_type, name,
+ snd_usb_mixer_vol_tlv);
+ if (err < 0)
+ return err;
+ }
+ for (ch = 8; ch < 16; ++ch) {
+ cmask = 1 << ch;
+ snprintf(name, sizeof(name),
+ "Effect Send DIn%d Volume", ch - 7);
+ err = snd_create_std_mono_ctl(mixer, id, control, cmask,
+ val_type, name,
+ snd_usb_mixer_vol_tlv);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+static int snd_ftu_create_mixer(struct usb_mixer_interface *mixer)
+{
+ int err;
+
+ err = snd_ftu_create_volume_ctls(mixer);
+ if (err < 0)
+ return err;
+
+ err = snd_ftu_create_effect_switch(mixer);
+ if (err < 0)
+ return err;
+ err = snd_ftu_create_effect_volume_ctl(mixer);
+ if (err < 0)
+ return err;
+
+ err = snd_ftu_create_effect_duration_ctl(mixer);
+ if (err < 0)
+ return err;
+
+ err = snd_ftu_create_effect_feedback_ctl(mixer);
+ if (err < 0)
+ return err;
+
+ err = snd_ftu_create_effect_return_ctls(mixer);
+ if (err < 0)
+ return err;
+
+ err = snd_ftu_create_effect_send_ctls(mixer);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+
+/*
+ * Create mixer for Electrix Ebox-44
+ *
+ * The mixer units from this device are corrupt, and even where they
+ * are valid they presents mono controls as L and R channels of
+ * stereo. So we create a good mixer in code.
+ */
+
+static int snd_ebox44_create_mixer(struct usb_mixer_interface *mixer)
+{
+ int err;
+
+ err = snd_create_std_mono_ctl(mixer, 4, 1, 0x0, USB_MIXER_INV_BOOLEAN,
+ "Headphone Playback Switch", NULL);
+ if (err < 0)
+ return err;
+ err = snd_create_std_mono_ctl(mixer, 4, 2, 0x1, USB_MIXER_S16,
+ "Headphone A Mix Playback Volume", NULL);
+ if (err < 0)
+ return err;
+ err = snd_create_std_mono_ctl(mixer, 4, 2, 0x2, USB_MIXER_S16,
+ "Headphone B Mix Playback Volume", NULL);
+ if (err < 0)
+ return err;
+
+ err = snd_create_std_mono_ctl(mixer, 7, 1, 0x0, USB_MIXER_INV_BOOLEAN,
+ "Output Playback Switch", NULL);
+ if (err < 0)
+ return err;
+ err = snd_create_std_mono_ctl(mixer, 7, 2, 0x1, USB_MIXER_S16,
+ "Output A Playback Volume", NULL);
+ if (err < 0)
+ return err;
+ err = snd_create_std_mono_ctl(mixer, 7, 2, 0x2, USB_MIXER_S16,
+ "Output B Playback Volume", NULL);
+ if (err < 0)
+ return err;
+
+ err = snd_create_std_mono_ctl(mixer, 10, 1, 0x0, USB_MIXER_INV_BOOLEAN,
+ "Input Capture Switch", NULL);
+ if (err < 0)
+ return err;
+ err = snd_create_std_mono_ctl(mixer, 10, 2, 0x1, USB_MIXER_S16,
+ "Input A Capture Volume", NULL);
+ if (err < 0)
+ return err;
+ err = snd_create_std_mono_ctl(mixer, 10, 2, 0x2, USB_MIXER_S16,
+ "Input B Capture Volume", NULL);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
unsigned char samplerate_id)
{
@@ -600,7 +1014,7 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */
case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */
- err = snd_maudio_ftu_create_mixer(mixer);
+ err = snd_ftu_create_mixer(mixer);
break;
case USB_ID(0x0b05, 0x1739):
@@ -619,6 +1033,10 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
snd_nativeinstruments_ta10_mixers,
ARRAY_SIZE(snd_nativeinstruments_ta10_mixers));
break;
+
+ case USB_ID(0x200c, 0x1018): /* Electrix Ebox-44 */
+ err = snd_ebox44_create_mixer(mixer);
+ break;
}
return err;
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 0eed6115c2d4..24839d932648 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -16,6 +16,7 @@
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/ratelimit.h>
#include <linux/usb.h>
#include <linux/usb/audio.h>
#include <linux/usb/audio-v2.h>
@@ -34,6 +35,9 @@
#include "clock.h"
#include "power.h"
+#define SUBSTREAM_FLAG_DATA_EP_STARTED 0
+#define SUBSTREAM_FLAG_SYNC_EP_STARTED 1
+
/* return the estimated delay based on USB frame counters */
snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs,
unsigned int rate)
@@ -208,6 +212,84 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
}
}
+static int start_endpoints(struct snd_usb_substream *subs)
+{
+ int err;
+
+ if (!subs->data_endpoint)
+ return -EINVAL;
+
+ if (!test_and_set_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) {
+ struct snd_usb_endpoint *ep = subs->data_endpoint;
+
+ snd_printdd(KERN_DEBUG "Starting data EP @%p\n", ep);
+
+ ep->data_subs = subs;
+ err = snd_usb_endpoint_start(ep);
+ if (err < 0) {
+ clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags);
+ return err;
+ }
+ }
+
+ if (subs->sync_endpoint &&
+ !test_and_set_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) {
+ struct snd_usb_endpoint *ep = subs->sync_endpoint;
+
+ snd_printdd(KERN_DEBUG "Starting sync EP @%p\n", ep);
+
+ ep->sync_slave = subs->data_endpoint;
+ err = snd_usb_endpoint_start(ep);
+ if (err < 0) {
+ clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static void stop_endpoints(struct snd_usb_substream *subs,
+ int force, int can_sleep, int wait)
+{
+ if (test_and_clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags))
+ snd_usb_endpoint_stop(subs->sync_endpoint,
+ force, can_sleep, wait);
+
+ if (test_and_clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags))
+ snd_usb_endpoint_stop(subs->data_endpoint,
+ force, can_sleep, wait);
+}
+
+static int activate_endpoints(struct snd_usb_substream *subs)
+{
+ if (subs->sync_endpoint) {
+ int ret;
+
+ ret = snd_usb_endpoint_activate(subs->sync_endpoint);
+ if (ret < 0)
+ return ret;
+ }
+
+ return snd_usb_endpoint_activate(subs->data_endpoint);
+}
+
+static int deactivate_endpoints(struct snd_usb_substream *subs)
+{
+ int reta, retb;
+
+ reta = snd_usb_endpoint_deactivate(subs->sync_endpoint);
+ retb = snd_usb_endpoint_deactivate(subs->data_endpoint);
+
+ if (reta < 0)
+ return reta;
+
+ if (retb < 0)
+ return retb;
+
+ return 0;
+}
+
/*
* find a matching format and set up the interface
*/
@@ -219,7 +301,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
struct usb_interface *iface;
unsigned int ep, attr;
int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK;
- int err;
+ int err, implicit_fb = 0;
iface = usb_ifnum_to_if(dev, fmt->iface);
if (WARN_ON(!iface))
@@ -232,40 +314,11 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
if (fmt == subs->cur_audiofmt)
return 0;
- /* close the old interface */
- if (subs->interface >= 0 && subs->interface != fmt->iface) {
- if (usb_set_interface(subs->dev, subs->interface, 0) < 0) {
- snd_printk(KERN_ERR "%d:%d:%d: return to setting 0 failed\n",
- dev->devnum, fmt->iface, fmt->altsetting);
- return -EIO;
- }
- subs->interface = -1;
- subs->altset_idx = 0;
- }
-
- /* set interface */
- if (subs->interface != fmt->iface || subs->altset_idx != fmt->altset_idx) {
- if (usb_set_interface(dev, fmt->iface, fmt->altsetting) < 0) {
- snd_printk(KERN_ERR "%d:%d:%d: usb_set_interface failed\n",
- dev->devnum, fmt->iface, fmt->altsetting);
- return -EIO;
- }
- snd_printdd(KERN_INFO "setting usb interface %d:%d\n", fmt->iface, fmt->altsetting);
- subs->interface = fmt->iface;
- subs->altset_idx = fmt->altset_idx;
- }
-
- /* create a data pipe */
- ep = fmt->endpoint & USB_ENDPOINT_NUMBER_MASK;
- if (is_playback)
- subs->datapipe = usb_sndisocpipe(dev, ep);
- else
- subs->datapipe = usb_rcvisocpipe(dev, ep);
- subs->datainterval = fmt->datainterval;
- subs->syncpipe = subs->syncinterval = 0;
- subs->maxpacksize = fmt->maxpacksize;
- subs->syncmaxsize = 0;
- subs->fill_max = 0;
+ subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip,
+ alts, fmt->endpoint, subs->direction,
+ SND_USB_ENDPOINT_TYPE_DATA);
+ if (!subs->data_endpoint)
+ return -EINVAL;
/* we need a sync pipe in async OUT or adaptive IN mode */
/* check the number of EP, since some devices have broken
@@ -273,8 +326,25 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
* assume it as adaptive-out or sync-in.
*/
attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE;
+
+ switch (subs->stream->chip->usb_id) {
+ case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */
+ case USB_ID(0x0763, 0x2081):
+ if (is_playback) {
+ implicit_fb = 1;
+ ep = 0x81;
+ iface = usb_ifnum_to_if(dev, 2);
+
+ if (!iface || iface->num_altsetting == 0)
+ return -EINVAL;
+
+ alts = &iface->altsetting[1];
+ goto add_sync_ep;
+ }
+ }
+
if (((is_playback && attr == USB_ENDPOINT_SYNC_ASYNC) ||
- (! is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) &&
+ (!is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) &&
altsd->bNumEndpoints >= 2) {
/* check sync-pipe endpoint */
/* ... and check descriptor size before accessing bSynchAddress
@@ -282,7 +352,8 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
the audio fields in the endpoint descriptors */
if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != 0x01 ||
(get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
- get_endpoint(alts, 1)->bSynchAddress != 0)) {
+ get_endpoint(alts, 1)->bSynchAddress != 0 &&
+ !implicit_fb)) {
snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n",
dev->devnum, fmt->iface, fmt->altsetting);
return -EINVAL;
@@ -290,33 +361,27 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
ep = get_endpoint(alts, 1)->bEndpointAddress;
if (get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
(( is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) ||
- (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) {
+ (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)) ||
+ ( is_playback && !implicit_fb))) {
snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n",
dev->devnum, fmt->iface, fmt->altsetting);
return -EINVAL;
}
- ep &= USB_ENDPOINT_NUMBER_MASK;
- if (is_playback)
- subs->syncpipe = usb_rcvisocpipe(dev, ep);
- else
- subs->syncpipe = usb_sndisocpipe(dev, ep);
- if (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE &&
- get_endpoint(alts, 1)->bRefresh >= 1 &&
- get_endpoint(alts, 1)->bRefresh <= 9)
- subs->syncinterval = get_endpoint(alts, 1)->bRefresh;
- else if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
- subs->syncinterval = 1;
- else if (get_endpoint(alts, 1)->bInterval >= 1 &&
- get_endpoint(alts, 1)->bInterval <= 16)
- subs->syncinterval = get_endpoint(alts, 1)->bInterval - 1;
- else
- subs->syncinterval = 3;
- subs->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize);
- }
-
- /* always fill max packet size */
- if (fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX)
- subs->fill_max = 1;
+
+ implicit_fb = (get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_USAGE_MASK)
+ == USB_ENDPOINT_USAGE_IMPLICIT_FB;
+
+add_sync_ep:
+ subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip,
+ alts, ep, !subs->direction,
+ implicit_fb ?
+ SND_USB_ENDPOINT_TYPE_DATA :
+ SND_USB_ENDPOINT_TYPE_SYNC);
+ if (!subs->sync_endpoint)
+ return -EINVAL;
+
+ subs->data_endpoint->sync_master = subs->sync_endpoint;
+ }
if ((err = snd_usb_init_pitch(subs->stream->chip, subs->interface, alts, fmt)) < 0)
return err;
@@ -390,15 +455,30 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
if (changed) {
mutex_lock(&subs->stream->chip->shutdown_mutex);
/* format changed */
- snd_usb_release_substream_urbs(subs, 0);
- /* influenced: period_bytes, channels, rate, format, */
- ret = snd_usb_init_substream_urbs(subs, params_period_bytes(hw_params),
- params_rate(hw_params),
- snd_pcm_format_physical_width(params_format(hw_params)) *
- params_channels(hw_params));
+ stop_endpoints(subs, 0, 0, 0);
+ deactivate_endpoints(subs);
+
+ ret = activate_endpoints(subs);
+ if (ret < 0)
+ goto unlock;
+
+ ret = snd_usb_endpoint_set_params(subs->data_endpoint, hw_params, fmt,
+ subs->sync_endpoint);
+ if (ret < 0)
+ goto unlock;
+
+ if (subs->sync_endpoint)
+ ret = snd_usb_endpoint_set_params(subs->sync_endpoint,
+ hw_params, fmt, NULL);
+unlock:
mutex_unlock(&subs->stream->chip->shutdown_mutex);
}
+ if (ret == 0) {
+ subs->interface = fmt->iface;
+ subs->altset_idx = fmt->altset_idx;
+ }
+
return ret;
}
@@ -415,7 +495,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
subs->cur_rate = 0;
subs->period_bytes = 0;
mutex_lock(&subs->stream->chip->shutdown_mutex);
- snd_usb_release_substream_urbs(subs, 0);
+ stop_endpoints(subs, 0, 1, 1);
mutex_unlock(&subs->stream->chip->shutdown_mutex);
return snd_pcm_lib_free_vmalloc_buffer(substream);
}
@@ -435,19 +515,28 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
return -ENXIO;
}
+ if (snd_BUG_ON(!subs->data_endpoint))
+ return -EIO;
+
/* some unit conversions in runtime */
- subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize);
- subs->curframesize = bytes_to_frames(runtime, subs->curpacksize);
+ subs->data_endpoint->maxframesize =
+ bytes_to_frames(runtime, subs->data_endpoint->maxpacksize);
+ subs->data_endpoint->curframesize =
+ bytes_to_frames(runtime, subs->data_endpoint->curpacksize);
/* reset the pointer */
subs->hwptr_done = 0;
subs->transfer_done = 0;
- subs->phase = 0;
subs->last_delay = 0;
subs->last_frame_number = 0;
runtime->delay = 0;
- return snd_usb_substream_prepare(subs, runtime);
+ /* for playback, submit the URBs now; otherwise, the first hwptr_done
+ * updates for all URBs would happen at the same time when starting */
+ if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK)
+ return start_endpoints(subs);
+
+ return 0;
}
static struct snd_pcm_hardware snd_usb_hardware =
@@ -842,16 +931,171 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction)
static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction)
{
+ int ret;
struct snd_usb_stream *as = snd_pcm_substream_chip(substream);
struct snd_usb_substream *subs = &as->substream[direction];
- if (!as->chip->shutdown && subs->interface >= 0) {
- usb_set_interface(subs->dev, subs->interface, 0);
- subs->interface = -1;
- }
+ stop_endpoints(subs, 0, 0, 0);
+ ret = deactivate_endpoints(subs);
subs->pcm_substream = NULL;
snd_usb_autosuspend(subs->stream->chip);
- return 0;
+
+ return ret;
+}
+
+/* Since a URB can handle only a single linear buffer, we must use double
+ * buffering when the data to be transferred overflows the buffer boundary.
+ * To avoid inconsistencies when updating hwptr_done, we use double buffering
+ * for all URBs.
+ */
+static void retire_capture_urb(struct snd_usb_substream *subs,
+ struct urb *urb)
+{
+ struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
+ unsigned int stride, frames, bytes, oldptr;
+ int i, period_elapsed = 0;
+ unsigned long flags;
+ unsigned char *cp;
+
+ stride = runtime->frame_bits >> 3;
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+ if (urb->iso_frame_desc[i].status && printk_ratelimit()) {
+ snd_printdd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status);
+ // continue;
+ }
+ bytes = urb->iso_frame_desc[i].actual_length;
+ frames = bytes / stride;
+ if (!subs->txfr_quirk)
+ bytes = frames * stride;
+ if (bytes % (runtime->sample_bits >> 3) != 0) {
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+ int oldbytes = bytes;
+#endif
+ bytes = frames * stride;
+ snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n",
+ oldbytes, bytes);
+ }
+ /* update the current pointer */
+ spin_lock_irqsave(&subs->lock, flags);
+ oldptr = subs->hwptr_done;
+ subs->hwptr_done += bytes;
+ if (subs->hwptr_done >= runtime->buffer_size * stride)
+ subs->hwptr_done -= runtime->buffer_size * stride;
+ frames = (bytes + (oldptr % stride)) / stride;
+ subs->transfer_done += frames;
+ if (subs->transfer_done >= runtime->period_size) {
+ subs->transfer_done -= runtime->period_size;
+ period_elapsed = 1;
+ }
+ spin_unlock_irqrestore(&subs->lock, flags);
+ /* copy a data chunk */
+ if (oldptr + bytes > runtime->buffer_size * stride) {
+ unsigned int bytes1 =
+ runtime->buffer_size * stride - oldptr;
+ memcpy(runtime->dma_area + oldptr, cp, bytes1);
+ memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1);
+ } else {
+ memcpy(runtime->dma_area + oldptr, cp, bytes);
+ }
+ }
+
+ if (period_elapsed)
+ snd_pcm_period_elapsed(subs->pcm_substream);
+}
+
+static void prepare_playback_urb(struct snd_usb_substream *subs,
+ struct urb *urb)
+{
+ struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
+ struct snd_urb_ctx *ctx = urb->context;
+ unsigned int counts, frames, bytes;
+ int i, stride, period_elapsed = 0;
+ unsigned long flags;
+
+ stride = runtime->frame_bits >> 3;
+
+ frames = 0;
+ urb->number_of_packets = 0;
+ spin_lock_irqsave(&subs->lock, flags);
+ for (i = 0; i < ctx->packets; i++) {
+ counts = ctx->packet_size[i];
+ /* set up descriptor */
+ urb->iso_frame_desc[i].offset = frames * stride;
+ urb->iso_frame_desc[i].length = counts * stride;
+ frames += counts;
+ urb->number_of_packets++;
+ subs->transfer_done += counts;
+ if (subs->transfer_done >= runtime->period_size) {
+ subs->transfer_done -= runtime->period_size;
+ period_elapsed = 1;
+ if (subs->fmt_type == UAC_FORMAT_TYPE_II) {
+ if (subs->transfer_done > 0) {
+ /* FIXME: fill-max mode is not
+ * supported yet */
+ frames -= subs->transfer_done;
+ counts -= subs->transfer_done;
+ urb->iso_frame_desc[i].length =
+ counts * stride;
+ subs->transfer_done = 0;
+ }
+ i++;
+ if (i < ctx->packets) {
+ /* add a transfer delimiter */
+ urb->iso_frame_desc[i].offset =
+ frames * stride;
+ urb->iso_frame_desc[i].length = 0;
+ urb->number_of_packets++;
+ }
+ break;
+ }
+ }
+ if (period_elapsed &&
+ !snd_usb_endpoint_implict_feedback_sink(subs->data_endpoint)) /* finish at the period boundary */
+ break;
+ }
+ bytes = frames * stride;
+ if (subs->hwptr_done + bytes > runtime->buffer_size * stride) {
+ /* err, the transferred area goes over buffer boundary. */
+ unsigned int bytes1 =
+ runtime->buffer_size * stride - subs->hwptr_done;
+ memcpy(urb->transfer_buffer,
+ runtime->dma_area + subs->hwptr_done, bytes1);
+ memcpy(urb->transfer_buffer + bytes1,
+ runtime->dma_area, bytes - bytes1);
+ } else {
+ memcpy(urb->transfer_buffer,
+ runtime->dma_area + subs->hwptr_done, bytes);
+ }
+ subs->hwptr_done += bytes;
+ if (subs->hwptr_done >= runtime->buffer_size * stride)
+ subs->hwptr_done -= runtime->buffer_size * stride;
+ runtime->delay += frames;
+ spin_unlock_irqrestore(&subs->lock, flags);
+ urb->transfer_buffer_length = bytes;
+ if (period_elapsed)
+ snd_pcm_period_elapsed(subs->pcm_substream);
+}
+
+/*
+ * process after playback data complete
+ * - decrease the delay count again
+ */
+static void retire_playback_urb(struct snd_usb_substream *subs,
+ struct urb *urb)
+{
+ unsigned long flags;
+ struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime;
+ int stride = runtime->frame_bits >> 3;
+ int processed = urb->transfer_buffer_length / stride;
+
+ spin_lock_irqsave(&subs->lock, flags);
+ if (processed > runtime->delay)
+ runtime->delay = 0;
+ else
+ runtime->delay -= processed;
+ spin_unlock_irqrestore(&subs->lock, flags);
}
static int snd_usb_playback_open(struct snd_pcm_substream *substream)
@@ -874,6 +1118,63 @@ static int snd_usb_capture_close(struct snd_pcm_substream *substream)
return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_CAPTURE);
}
+static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ struct snd_usb_substream *subs = substream->runtime->private_data;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ subs->data_endpoint->prepare_data_urb = prepare_playback_urb;
+ subs->data_endpoint->retire_data_urb = retire_playback_urb;
+ subs->running = 1;
+ return 0;
+ case SNDRV_PCM_TRIGGER_STOP:
+ stop_endpoints(subs, 0, 0, 0);
+ subs->running = 0;
+ return 0;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ subs->data_endpoint->prepare_data_urb = NULL;
+ subs->data_endpoint->retire_data_urb = NULL;
+ subs->running = 0;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ int err;
+ struct snd_usb_substream *subs = substream->runtime->private_data;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ err = start_endpoints(subs);
+ if (err < 0)
+ return err;
+
+ subs->data_endpoint->retire_data_urb = retire_capture_urb;
+ subs->running = 1;
+ return 0;
+ case SNDRV_PCM_TRIGGER_STOP:
+ stop_endpoints(subs, 0, 0, 0);
+ subs->running = 0;
+ return 0;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ subs->data_endpoint->retire_data_urb = NULL;
+ subs->running = 0;
+ return 0;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ subs->data_endpoint->retire_data_urb = retire_capture_urb;
+ subs->running = 1;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
static struct snd_pcm_ops snd_usb_playback_ops = {
.open = snd_usb_playback_open,
.close = snd_usb_playback_close,
diff --git a/sound/usb/proc.c b/sound/usb/proc.c
index 961c9a250686..ebc1a5b5b3f1 100644
--- a/sound/usb/proc.c
+++ b/sound/usb/proc.c
@@ -25,6 +25,7 @@
#include "usbaudio.h"
#include "helper.h"
#include "card.h"
+#include "endpoint.h"
#include "proc.h"
/* convert our full speed USB rate into sampling rate in Hz */
@@ -115,28 +116,33 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s
}
}
+static void proc_dump_ep_status(struct snd_usb_substream *subs,
+ struct snd_usb_endpoint *ep,
+ struct snd_info_buffer *buffer)
+{
+ if (!ep)
+ return;
+ snd_iprintf(buffer, " Packet Size = %d\n", ep->curpacksize);
+ snd_iprintf(buffer, " Momentary freq = %u Hz (%#x.%04x)\n",
+ snd_usb_get_speed(subs->dev) == USB_SPEED_FULL
+ ? get_full_speed_hz(ep->freqm)
+ : get_high_speed_hz(ep->freqm),
+ ep->freqm >> 16, ep->freqm & 0xffff);
+ if (ep->freqshift != INT_MIN) {
+ int res = 16 - ep->freqshift;
+ snd_iprintf(buffer, " Feedback Format = %d.%d\n",
+ (ep->syncmaxsize > 3 ? 32 : 24) - res, res);
+ }
+}
+
static void proc_dump_substream_status(struct snd_usb_substream *subs, struct snd_info_buffer *buffer)
{
if (subs->running) {
- unsigned int i;
snd_iprintf(buffer, " Status: Running\n");
snd_iprintf(buffer, " Interface = %d\n", subs->interface);
snd_iprintf(buffer, " Altset = %d\n", subs->altset_idx);
- snd_iprintf(buffer, " URBs = %d [ ", subs->nurbs);
- for (i = 0; i < subs->nurbs; i++)
- snd_iprintf(buffer, "%d ", subs->dataurb[i].packets);
- snd_iprintf(buffer, "]\n");
- snd_iprintf(buffer, " Packet Size = %d\n", subs->curpacksize);
- snd_iprintf(buffer, " Momentary freq = %u Hz (%#x.%04x)\n",
- snd_usb_get_speed(subs->dev) == USB_SPEED_FULL
- ? get_full_speed_hz(subs->freqm)
- : get_high_speed_hz(subs->freqm),
- subs->freqm >> 16, subs->freqm & 0xffff);
- if (subs->freqshift != INT_MIN)
- snd_iprintf(buffer, " Feedback Format = %d.%d\n",
- (subs->syncmaxsize > 3 ? 32 : 24)
- - (16 - subs->freqshift),
- 16 - subs->freqshift);
+ proc_dump_ep_status(subs, subs->data_endpoint, buffer);
+ proc_dump_ep_status(subs, subs->sync_endpoint, buffer);
} else {
snd_iprintf(buffer, " Status: Stop\n");
}
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 5ff8010b2d6f..6b7d7a2b7baa 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -73,6 +73,31 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm)
}
}
+/*
+ * initialize the substream instance.
+ */
+
+static void snd_usb_init_substream(struct snd_usb_stream *as,
+ int stream,
+ struct audioformat *fp)
+{
+ struct snd_usb_substream *subs = &as->substream[stream];
+
+ INIT_LIST_HEAD(&subs->fmt_list);
+ spin_lock_init(&subs->lock);
+
+ subs->stream = as;
+ subs->direction = stream;
+ subs->dev = as->chip->dev;
+ subs->txfr_quirk = as->chip->txfr_quirk;
+
+ snd_usb_set_pcm_ops(as->pcm, stream);
+
+ list_add_tail(&fp->list, &subs->fmt_list);
+ subs->formats |= fp->formats;
+ subs->num_formats++;
+ subs->fmt_type = fp->fmt_type;
+}
/*
* add this endpoint to the chip instance.
@@ -94,9 +119,9 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
if (as->fmt_type != fp->fmt_type)
continue;
subs = &as->substream[stream];
- if (!subs->endpoint)
+ if (!subs->data_endpoint)
continue;
- if (subs->endpoint == fp->endpoint) {
+ if (subs->data_endpoint->ep_num == fp->endpoint) {
list_add_tail(&fp->list, &subs->fmt_list);
subs->num_formats++;
subs->formats |= fp->formats;
@@ -109,7 +134,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
if (as->fmt_type != fp->fmt_type)
continue;
subs = &as->substream[stream];
- if (subs->endpoint)
+ if (subs->data_endpoint)
continue;
err = snd_pcm_new_stream(as->pcm, stream, 1);
if (err < 0)
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 3e2b03577936..b8233ebe250f 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -36,6 +36,7 @@ struct snd_usb_audio {
struct snd_card *card;
struct usb_interface *pm_intf;
u32 usb_id;
+ struct mutex mutex;
struct mutex shutdown_mutex;
unsigned int shutdown:1;
unsigned int probing:1;
@@ -46,6 +47,7 @@ struct snd_usb_audio {
int num_suspended_intf;
struct list_head pcm_list; /* list of pcm streams */
+ struct list_head ep_list; /* list of audio-related endpoints */
int pcm_devs;
struct list_head midi_list; /* list of midi interfaces */
diff --git a/tools/Makefile b/tools/Makefile
new file mode 100644
index 000000000000..3ae43947a171
--- /dev/null
+++ b/tools/Makefile
@@ -0,0 +1,77 @@
+include scripts/Makefile.include
+
+help:
+ @echo 'Possible targets:'
+ @echo ''
+ @echo ' cpupower - a tool for all things x86 CPU power'
+ @echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer'
+ @echo ' lguest - a minimal 32-bit x86 hypervisor'
+ @echo ' perf - Linux performance measurement and analysis tool'
+ @echo ' selftests - various kernel selftests'
+ @echo ' turbostat - Intel CPU idle stats and freq reporting tool'
+ @echo ' usb - USB testing tools'
+ @echo ' virtio - vhost test module'
+ @echo ' vm - misc vm tools'
+ @echo ' x86_energy_perf_policy - Intel energy policy tool'
+ @echo ''
+ @echo 'You can do:'
+ @echo ' $$ make -C tools/<tool>_install'
+ @echo ''
+ @echo ' from the kernel command line to build and install one of'
+ @echo ' the tools above'
+ @echo ''
+ @echo ' $$ make tools/install'
+ @echo ''
+ @echo ' installs all tools.'
+ @echo ''
+ @echo 'Cleaning targets:'
+ @echo ''
+ @echo ' all of the above with the "_clean" string appended cleans'
+ @echo ' the respective build directory.'
+ @echo ' clean: a summary clean target to clean _all_ folders'
+
+cpupower: FORCE
+ $(QUIET_SUBDIR0)power/$@/ $(QUIET_SUBDIR1)
+
+firewire lguest perf usb virtio vm: FORCE
+ $(QUIET_SUBDIR0)$@/ $(QUIET_SUBDIR1)
+
+selftests: FORCE
+ $(QUIET_SUBDIR0)testing/$@/ $(QUIET_SUBDIR1)
+
+turbostat x86_energy_perf_policy: FORCE
+ $(QUIET_SUBDIR0)power/x86/$@/ $(QUIET_SUBDIR1)
+
+cpupower_install:
+ $(QUIET_SUBDIR0)power/$(@:_install=)/ $(QUIET_SUBDIR1) install
+
+firewire_install lguest_install perf_install usb_install virtio_install vm_install:
+ $(QUIET_SUBDIR0)$(@:_install=)/ $(QUIET_SUBDIR1) install
+
+selftests_install:
+ $(QUIET_SUBDIR0)testing/$(@:_clean=)/ $(QUIET_SUBDIR1) install
+
+turbostat_install x86_energy_perf_policy_install:
+ $(QUIET_SUBDIR0)power/x86/$(@:_install=)/ $(QUIET_SUBDIR1) install
+
+install: cpupower_install firewire_install lguest_install perf_install \
+ selftests_install turbostat_install usb_install virtio_install \
+ vm_install x86_energy_perf_policy_install
+
+cpupower_clean:
+ $(QUIET_SUBDIR0)power/cpupower/ $(QUIET_SUBDIR1) clean
+
+firewire_clean lguest_clean perf_clean usb_clean virtio_clean vm_clean:
+ $(QUIET_SUBDIR0)$(@:_clean=)/ $(QUIET_SUBDIR1) clean
+
+selftests_clean:
+ $(QUIET_SUBDIR0)testing/$(@:_clean=)/ $(QUIET_SUBDIR1) clean
+
+turbostat_clean x86_energy_perf_policy_clean:
+ $(QUIET_SUBDIR0)power/x86/$(@:_clean=)/ $(QUIET_SUBDIR1) clean
+
+clean: cpupower_clean firewire_clean lguest_clean perf_clean selftests_clean \
+ turbostat_clean usb_clean virtio_clean vm_clean \
+ x86_energy_perf_policy_clean
+
+.PHONY: FORCE
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile
new file mode 100644
index 000000000000..3d69aa9ff51e
--- /dev/null
+++ b/tools/lib/traceevent/Makefile
@@ -0,0 +1,303 @@
+# trace-cmd version
+EP_VERSION = 1
+EP_PATCHLEVEL = 1
+EP_EXTRAVERSION = 0
+
+# file format version
+FILE_VERSION = 6
+
+MAKEFLAGS += --no-print-directory
+
+
+# Makefiles suck: This macro sets a default value of $(2) for the
+# variable named by $(1), unless the variable has been set by
+# environment or command line. This is necessary for CC and AR
+# because make sets default values, so the simpler ?= approach
+# won't work as expected.
+define allow-override
+ $(if $(or $(findstring environment,$(origin $(1))),\
+ $(findstring command line,$(origin $(1)))),,\
+ $(eval $(1) = $(2)))
+endef
+
+# Allow setting CC and AR, or setting CROSS_COMPILE as a prefix.
+$(call allow-override,CC,$(CROSS_COMPILE)gcc)
+$(call allow-override,AR,$(CROSS_COMPILE)ar)
+
+EXT = -std=gnu99
+INSTALL = install
+
+# Use DESTDIR for installing into a different root directory.
+# This is useful for building a package. The program will be
+# installed in this directory as if it was the root directory.
+# Then the build tool can move it later.
+DESTDIR ?=
+DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))'
+
+prefix ?= /usr/local
+bindir_relative = bin
+bindir = $(prefix)/$(bindir_relative)
+man_dir = $(prefix)/share/man
+man_dir_SQ = '$(subst ','\'',$(man_dir))'
+html_install = $(prefix)/share/kernelshark/html
+html_install_SQ = '$(subst ','\'',$(html_install))'
+img_install = $(prefix)/share/kernelshark/html/images
+img_install_SQ = '$(subst ','\'',$(img_install))'
+
+export man_dir man_dir_SQ html_install html_install_SQ INSTALL
+export img_install img_install_SQ
+export DESTDIR DESTDIR_SQ
+
+# copy a bit from Linux kbuild
+
+ifeq ("$(origin V)", "command line")
+ VERBOSE = $(V)
+endif
+ifndef VERBOSE
+ VERBOSE = 0
+endif
+
+ifeq ("$(origin O)", "command line")
+ BUILD_OUTPUT := $(O)
+endif
+
+ifeq ($(BUILD_SRC),)
+ifneq ($(BUILD_OUTPUT),)
+
+define build_output
+ $(if $(VERBOSE:1=),@)$(MAKE) -C $(BUILD_OUTPUT) \
+ BUILD_SRC=$(CURDIR) -f $(CURDIR)/Makefile $1
+endef
+
+saved-output := $(BUILD_OUTPUT)
+BUILD_OUTPUT := $(shell cd $(BUILD_OUTPUT) && /bin/pwd)
+$(if $(BUILD_OUTPUT),, \
+ $(error output directory "$(saved-output)" does not exist))
+
+all: sub-make
+
+gui: force
+ $(call build_output, all_cmd)
+
+$(filter-out gui,$(MAKECMDGOALS)): sub-make
+
+sub-make: force
+ $(call build_output, $(MAKECMDGOALS))
+
+
+# Leave processing to above invocation of make
+skip-makefile := 1
+
+endif # BUILD_OUTPUT
+endif # BUILD_SRC
+
+# We process the rest of the Makefile if this is the final invocation of make
+ifeq ($(skip-makefile),)
+
+srctree := $(if $(BUILD_SRC),$(BUILD_SRC),$(CURDIR))
+objtree := $(CURDIR)
+src := $(srctree)
+obj := $(objtree)
+
+export prefix bindir src obj
+
+# Shell quotes
+bindir_SQ = $(subst ','\'',$(bindir))
+bindir_relative_SQ = $(subst ','\'',$(bindir_relative))
+
+LIB_FILE = libtraceevent.a libtraceevent.so
+
+CONFIG_INCLUDES =
+CONFIG_LIBS =
+CONFIG_FLAGS =
+
+VERSION = $(EP_VERSION)
+PATCHLEVEL = $(EP_PATCHLEVEL)
+EXTRAVERSION = $(EP_EXTRAVERSION)
+
+OBJ = $@
+N =
+
+export Q VERBOSE
+
+EVENT_PARSE_VERSION = $(EP_VERSION).$(EP_PATCHLEVEL).$(EP_EXTRAVERSION)
+
+INCLUDES = -I. -I/usr/local/include $(CONFIG_INCLUDES)
+
+# Set compile option CFLAGS if not set elsewhere
+CFLAGS ?= -g -Wall
+
+# Append required CFLAGS
+override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ)
+override CFLAGS += $(udis86-flags)
+
+ifeq ($(VERBOSE),1)
+ Q =
+ print_compile =
+ print_app_build =
+ print_fpic_compile =
+ print_shared_lib_compile =
+ print_plugin_obj_compile =
+ print_plugin_build =
+ print_install =
+else
+ Q = @
+ print_compile = echo ' CC '$(OBJ);
+ print_app_build = echo ' BUILD '$(OBJ);
+ print_fpic_compile = echo ' CC FPIC '$(OBJ);
+ print_shared_lib_compile = echo ' BUILD SHARED LIB '$(OBJ);
+ print_plugin_obj_compile = echo ' CC PLUGIN OBJ '$(OBJ);
+ print_plugin_build = echo ' CC PLUGI '$(OBJ);
+ print_static_lib_build = echo ' BUILD STATIC LIB '$(OBJ);
+ print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2';
+endif
+
+do_fpic_compile = \
+ ($(print_fpic_compile) \
+ $(CC) -c $(CFLAGS) $(EXT) -fPIC $< -o $@)
+
+do_app_build = \
+ ($(print_app_build) \
+ $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS))
+
+do_compile_shared_library = \
+ ($(print_shared_lib_compile) \
+ $(CC) --shared $^ -o $@)
+
+do_compile_plugin_obj = \
+ ($(print_plugin_obj_compile) \
+ $(CC) -c $(CFLAGS) -fPIC -o $@ $<)
+
+do_plugin_build = \
+ ($(print_plugin_build) \
+ $(CC) $(CFLAGS) -shared -nostartfiles -o $@ $<)
+
+do_build_static_lib = \
+ ($(print_static_lib_build) \
+ $(RM) $@; $(AR) rcs $@ $^)
+
+
+define do_compile
+ $(print_compile) \
+ $(CC) -c $(CFLAGS) $(EXT) $< -o $(obj)/$@;
+endef
+
+$(obj)/%.o: $(src)/%.c
+ $(Q)$(call do_compile)
+
+%.o: $(src)/%.c
+ $(Q)$(call do_compile)
+
+PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o
+
+ALL_OBJS = $(PEVENT_LIB_OBJS)
+
+CMD_TARGETS = $(LIB_FILE)
+
+TARGETS = $(CMD_TARGETS)
+
+
+all: all_cmd
+
+all_cmd: $(CMD_TARGETS)
+
+libtraceevent.so: $(PEVENT_LIB_OBJS)
+ $(Q)$(do_compile_shared_library)
+
+libtraceevent.a: $(PEVENT_LIB_OBJS)
+ $(Q)$(do_build_static_lib)
+
+$(PEVENT_LIB_OBJS): %.o: $(src)/%.c
+ $(Q)$(do_fpic_compile)
+
+define make_version.h
+ (echo '/* This file is automatically generated. Do not modify. */'; \
+ echo \#define VERSION_CODE $(shell \
+ expr $(VERSION) \* 256 + $(PATCHLEVEL)); \
+ echo '#define EXTRAVERSION ' $(EXTRAVERSION); \
+ echo '#define VERSION_STRING "'$(VERSION).$(PATCHLEVEL).$(EXTRAVERSION)'"'; \
+ echo '#define FILE_VERSION '$(FILE_VERSION); \
+ ) > $1
+endef
+
+define update_version.h
+ ($(call make_version.h, $@.tmp); \
+ if [ -r $@ ] && cmp -s $@ $@.tmp; then \
+ rm -f $@.tmp; \
+ else \
+ echo ' UPDATE $@'; \
+ mv -f $@.tmp $@; \
+ fi);
+endef
+
+ep_version.h: force
+ $(Q)$(N)$(call update_version.h)
+
+VERSION_FILES = ep_version.h
+
+define update_dir
+ (echo $1 > $@.tmp; \
+ if [ -r $@ ] && cmp -s $@ $@.tmp; then \
+ rm -f $@.tmp; \
+ else \
+ echo ' UPDATE $@'; \
+ mv -f $@.tmp $@; \
+ fi);
+endef
+
+## make deps
+
+all_objs := $(sort $(ALL_OBJS))
+all_deps := $(all_objs:%.o=.%.d)
+
+define check_deps
+ $(CC) -M $(CFLAGS) $< > $@;
+endef
+
+$(gui_deps): ks_version.h
+$(non_gui_deps): tc_version.h
+
+$(all_deps): .%.d: $(src)/%.c
+ $(Q)$(call check_deps)
+
+$(all_objs) : %.o : .%.d
+
+dep_includes := $(wildcard $(all_deps))
+
+ifneq ($(dep_includes),)
+ include $(dep_includes)
+endif
+
+tags: force
+ $(RM) tags
+ find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px
+
+TAGS: force
+ $(RM) TAGS
+ find . -name '*.[ch]' | xargs etags
+
+define do_install
+ $(print_install) \
+ if [ ! -d '$(DESTDIR_SQ)$2' ]; then \
+ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \
+ fi; \
+ $(INSTALL) $1 '$(DESTDIR_SQ)$2'
+endef
+
+install_lib: all_cmd install_plugins install_python
+ $(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ))
+
+install: install_lib
+
+clean:
+ $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES).*.d
+ $(RM) tags TAGS
+
+endif # skip-makefile
+
+PHONY += force
+force:
+
+# Declare the contents of the .PHONY variable as phony. We keep that
+# information in a variable so we can use it in if_changed and friends.
+.PHONY: $(PHONY)
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
new file mode 100644
index 000000000000..998534992197
--- /dev/null
+++ b/tools/lib/traceevent/event-parse.c
@@ -0,0 +1,5065 @@
+/*
+ * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License (not later!)
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * The parts for function graph printing was taken and modified from the
+ * Linux Kernel that were written by
+ * - Copyright (C) 2009 Frederic Weisbecker,
+ * Frederic Weisbecker gave his permission to relicense the code to
+ * the Lesser General Public License.
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "event-parse.h"
+#include "event-utils.h"
+
+static const char *input_buf;
+static unsigned long long input_buf_ptr;
+static unsigned long long input_buf_siz;
+
+static int is_flag_field;
+static int is_symbolic_field;
+
+static int show_warning = 1;
+
+#define do_warning(fmt, ...) \
+ do { \
+ if (show_warning) \
+ warning(fmt, ##__VA_ARGS__); \
+ } while (0)
+
+static void init_input_buf(const char *buf, unsigned long long size)
+{
+ input_buf = buf;
+ input_buf_siz = size;
+ input_buf_ptr = 0;
+}
+
+const char *pevent_get_input_buf(void)
+{
+ return input_buf;
+}
+
+unsigned long long pevent_get_input_buf_ptr(void)
+{
+ return input_buf_ptr;
+}
+
+struct event_handler {
+ struct event_handler *next;
+ int id;
+ const char *sys_name;
+ const char *event_name;
+ pevent_event_handler_func func;
+ void *context;
+};
+
+struct pevent_func_params {
+ struct pevent_func_params *next;
+ enum pevent_func_arg_type type;
+};
+
+struct pevent_function_handler {
+ struct pevent_function_handler *next;
+ enum pevent_func_arg_type ret_type;
+ char *name;
+ pevent_func_handler func;
+ struct pevent_func_params *params;
+ int nr_args;
+};
+
+static unsigned long long
+process_defined_func(struct trace_seq *s, void *data, int size,
+ struct event_format *event, struct print_arg *arg);
+
+static void free_func_handle(struct pevent_function_handler *func);
+
+/**
+ * pevent_buffer_init - init buffer for parsing
+ * @buf: buffer to parse
+ * @size: the size of the buffer
+ *
+ * For use with pevent_read_token(), this initializes the internal
+ * buffer that pevent_read_token() will parse.
+ */
+void pevent_buffer_init(const char *buf, unsigned long long size)
+{
+ init_input_buf(buf, size);
+}
+
+void breakpoint(void)
+{
+ static int x;
+ x++;
+}
+
+struct print_arg *alloc_arg(void)
+{
+ struct print_arg *arg;
+
+ arg = malloc_or_die(sizeof(*arg));
+ if (!arg)
+ return NULL;
+ memset(arg, 0, sizeof(*arg));
+
+ return arg;
+}
+
+struct cmdline {
+ char *comm;
+ int pid;
+};
+
+static int cmdline_cmp(const void *a, const void *b)
+{
+ const struct cmdline *ca = a;
+ const struct cmdline *cb = b;
+
+ if (ca->pid < cb->pid)
+ return -1;
+ if (ca->pid > cb->pid)
+ return 1;
+
+ return 0;
+}
+
+struct cmdline_list {
+ struct cmdline_list *next;
+ char *comm;
+ int pid;
+};
+
+static int cmdline_init(struct pevent *pevent)
+{
+ struct cmdline_list *cmdlist = pevent->cmdlist;
+ struct cmdline_list *item;
+ struct cmdline *cmdlines;
+ int i;
+
+ cmdlines = malloc_or_die(sizeof(*cmdlines) * pevent->cmdline_count);
+
+ i = 0;
+ while (cmdlist) {
+ cmdlines[i].pid = cmdlist->pid;
+ cmdlines[i].comm = cmdlist->comm;
+ i++;
+ item = cmdlist;
+ cmdlist = cmdlist->next;
+ free(item);
+ }
+
+ qsort(cmdlines, pevent->cmdline_count, sizeof(*cmdlines), cmdline_cmp);
+
+ pevent->cmdlines = cmdlines;
+ pevent->cmdlist = NULL;
+
+ return 0;
+}
+
+static char *find_cmdline(struct pevent *pevent, int pid)
+{
+ const struct cmdline *comm;
+ struct cmdline key;
+
+ if (!pid)
+ return "<idle>";
+
+ if (!pevent->cmdlines)
+ cmdline_init(pevent);
+
+ key.pid = pid;
+
+ comm = bsearch(&key, pevent->cmdlines, pevent->cmdline_count,
+ sizeof(*pevent->cmdlines), cmdline_cmp);
+
+ if (comm)
+ return comm->comm;
+ return "<...>";
+}
+
+/**
+ * pevent_pid_is_registered - return if a pid has a cmdline registered
+ * @pevent: handle for the pevent
+ * @pid: The pid to check if it has a cmdline registered with.
+ *
+ * Returns 1 if the pid has a cmdline mapped to it
+ * 0 otherwise.
+ */
+int pevent_pid_is_registered(struct pevent *pevent, int pid)
+{
+ const struct cmdline *comm;
+ struct cmdline key;
+
+ if (!pid)
+ return 1;
+
+ if (!pevent->cmdlines)
+ cmdline_init(pevent);
+
+ key.pid = pid;
+
+ comm = bsearch(&key, pevent->cmdlines, pevent->cmdline_count,
+ sizeof(*pevent->cmdlines), cmdline_cmp);
+
+ if (comm)
+ return 1;
+ return 0;
+}
+
+/*
+ * If the command lines have been converted to an array, then
+ * we must add this pid. This is much slower than when cmdlines
+ * are added before the array is initialized.
+ */
+static int add_new_comm(struct pevent *pevent, const char *comm, int pid)
+{
+ struct cmdline *cmdlines = pevent->cmdlines;
+ const struct cmdline *cmdline;
+ struct cmdline key;
+
+ if (!pid)
+ return 0;
+
+ /* avoid duplicates */
+ key.pid = pid;
+
+ cmdline = bsearch(&key, pevent->cmdlines, pevent->cmdline_count,
+ sizeof(*pevent->cmdlines), cmdline_cmp);
+ if (cmdline) {
+ errno = EEXIST;
+ return -1;
+ }
+
+ cmdlines = realloc(cmdlines, sizeof(*cmdlines) * (pevent->cmdline_count + 1));
+ if (!cmdlines) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ cmdlines[pevent->cmdline_count].pid = pid;
+ cmdlines[pevent->cmdline_count].comm = strdup(comm);
+ if (!cmdlines[pevent->cmdline_count].comm)
+ die("malloc comm");
+
+ if (cmdlines[pevent->cmdline_count].comm)
+ pevent->cmdline_count++;
+
+ qsort(cmdlines, pevent->cmdline_count, sizeof(*cmdlines), cmdline_cmp);
+ pevent->cmdlines = cmdlines;
+
+ return 0;
+}
+
+/**
+ * pevent_register_comm - register a pid / comm mapping
+ * @pevent: handle for the pevent
+ * @comm: the command line to register
+ * @pid: the pid to map the command line to
+ *
+ * This adds a mapping to search for command line names with
+ * a given pid. The comm is duplicated.
+ */
+int pevent_register_comm(struct pevent *pevent, const char *comm, int pid)
+{
+ struct cmdline_list *item;
+
+ if (pevent->cmdlines)
+ return add_new_comm(pevent, comm, pid);
+
+ item = malloc_or_die(sizeof(*item));
+ item->comm = strdup(comm);
+ if (!item->comm)
+ die("malloc comm");
+ item->pid = pid;
+ item->next = pevent->cmdlist;
+
+ pevent->cmdlist = item;
+ pevent->cmdline_count++;
+
+ return 0;
+}
+
+struct func_map {
+ unsigned long long addr;
+ char *func;
+ char *mod;
+};
+
+struct func_list {
+ struct func_list *next;
+ unsigned long long addr;
+ char *func;
+ char *mod;
+};
+
+static int func_cmp(const void *a, const void *b)
+{
+ const struct func_map *fa = a;
+ const struct func_map *fb = b;
+
+ if (fa->addr < fb->addr)
+ return -1;
+ if (fa->addr > fb->addr)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * We are searching for a record in between, not an exact
+ * match.
+ */
+static int func_bcmp(const void *a, const void *b)
+{
+ const struct func_map *fa = a;
+ const struct func_map *fb = b;
+
+ if ((fa->addr == fb->addr) ||
+
+ (fa->addr > fb->addr &&
+ fa->addr < (fb+1)->addr))
+ return 0;
+
+ if (fa->addr < fb->addr)
+ return -1;
+
+ return 1;
+}
+
+static int func_map_init(struct pevent *pevent)
+{
+ struct func_list *funclist;
+ struct func_list *item;
+ struct func_map *func_map;
+ int i;
+
+ func_map = malloc_or_die(sizeof(*func_map) * (pevent->func_count + 1));
+ funclist = pevent->funclist;
+
+ i = 0;
+ while (funclist) {
+ func_map[i].func = funclist->func;
+ func_map[i].addr = funclist->addr;
+ func_map[i].mod = funclist->mod;
+ i++;
+ item = funclist;
+ funclist = funclist->next;
+ free(item);
+ }
+
+ qsort(func_map, pevent->func_count, sizeof(*func_map), func_cmp);
+
+ /*
+ * Add a special record at the end.
+ */
+ func_map[pevent->func_count].func = NULL;
+ func_map[pevent->func_count].addr = 0;
+ func_map[pevent->func_count].mod = NULL;
+
+ pevent->func_map = func_map;
+ pevent->funclist = NULL;
+
+ return 0;
+}
+
+static struct func_map *
+find_func(struct pevent *pevent, unsigned long long addr)
+{
+ struct func_map *func;
+ struct func_map key;
+
+ if (!pevent->func_map)
+ func_map_init(pevent);
+
+ key.addr = addr;
+
+ func = bsearch(&key, pevent->func_map, pevent->func_count,
+ sizeof(*pevent->func_map), func_bcmp);
+
+ return func;
+}
+
+/**
+ * pevent_find_function - find a function by a given address
+ * @pevent: handle for the pevent
+ * @addr: the address to find the function with
+ *
+ * Returns a pointer to the function stored that has the given
+ * address. Note, the address does not have to be exact, it
+ * will select the function that would contain the address.
+ */
+const char *pevent_find_function(struct pevent *pevent, unsigned long long addr)
+{
+ struct func_map *map;
+
+ map = find_func(pevent, addr);
+ if (!map)
+ return NULL;
+
+ return map->func;
+}
+
+/**
+ * pevent_find_function_address - find a function address by a given address
+ * @pevent: handle for the pevent
+ * @addr: the address to find the function with
+ *
+ * Returns the address the function starts at. This can be used in
+ * conjunction with pevent_find_function to print both the function
+ * name and the function offset.
+ */
+unsigned long long
+pevent_find_function_address(struct pevent *pevent, unsigned long long addr)
+{
+ struct func_map *map;
+
+ map = find_func(pevent, addr);
+ if (!map)
+ return 0;
+
+ return map->addr;
+}
+
+/**
+ * pevent_register_function - register a function with a given address
+ * @pevent: handle for the pevent
+ * @function: the function name to register
+ * @addr: the address the function starts at
+ * @mod: the kernel module the function may be in (NULL for none)
+ *
+ * This registers a function name with an address and module.
+ * The @func passed in is duplicated.
+ */
+int pevent_register_function(struct pevent *pevent, char *func,
+ unsigned long long addr, char *mod)
+{
+ struct func_list *item;
+
+ item = malloc_or_die(sizeof(*item));
+
+ item->next = pevent->funclist;
+ item->func = strdup(func);
+ if (mod)
+ item->mod = strdup(mod);
+ else
+ item->mod = NULL;
+ item->addr = addr;
+
+ pevent->funclist = item;
+
+ pevent->func_count++;
+
+ return 0;
+}
+
+/**
+ * pevent_print_funcs - print out the stored functions
+ * @pevent: handle for the pevent
+ *
+ * This prints out the stored functions.
+ */
+void pevent_print_funcs(struct pevent *pevent)
+{
+ int i;
+
+ if (!pevent->func_map)
+ func_map_init(pevent);
+
+ for (i = 0; i < (int)pevent->func_count; i++) {
+ printf("%016llx %s",
+ pevent->func_map[i].addr,
+ pevent->func_map[i].func);
+ if (pevent->func_map[i].mod)
+ printf(" [%s]\n", pevent->func_map[i].mod);
+ else
+ printf("\n");
+ }
+}
+
+struct printk_map {
+ unsigned long long addr;
+ char *printk;
+};
+
+struct printk_list {
+ struct printk_list *next;
+ unsigned long long addr;
+ char *printk;
+};
+
+static int printk_cmp(const void *a, const void *b)
+{
+ const struct func_map *fa = a;
+ const struct func_map *fb = b;
+
+ if (fa->addr < fb->addr)
+ return -1;
+ if (fa->addr > fb->addr)
+ return 1;
+
+ return 0;
+}
+
+static void printk_map_init(struct pevent *pevent)
+{
+ struct printk_list *printklist;
+ struct printk_list *item;
+ struct printk_map *printk_map;
+ int i;
+
+ printk_map = malloc_or_die(sizeof(*printk_map) * (pevent->printk_count + 1));
+
+ printklist = pevent->printklist;
+
+ i = 0;
+ while (printklist) {
+ printk_map[i].printk = printklist->printk;
+ printk_map[i].addr = printklist->addr;
+ i++;
+ item = printklist;
+ printklist = printklist->next;
+ free(item);
+ }
+
+ qsort(printk_map, pevent->printk_count, sizeof(*printk_map), printk_cmp);
+
+ pevent->printk_map = printk_map;
+ pevent->printklist = NULL;
+}
+
+static struct printk_map *
+find_printk(struct pevent *pevent, unsigned long long addr)
+{
+ struct printk_map *printk;
+ struct printk_map key;
+
+ if (!pevent->printk_map)
+ printk_map_init(pevent);
+
+ key.addr = addr;
+
+ printk = bsearch(&key, pevent->printk_map, pevent->printk_count,
+ sizeof(*pevent->printk_map), printk_cmp);
+
+ return printk;
+}
+
+/**
+ * pevent_register_print_string - register a string by its address
+ * @pevent: handle for the pevent
+ * @fmt: the string format to register
+ * @addr: the address the string was located at
+ *
+ * This registers a string by the address it was stored in the kernel.
+ * The @fmt passed in is duplicated.
+ */
+int pevent_register_print_string(struct pevent *pevent, char *fmt,
+ unsigned long long addr)
+{
+ struct printk_list *item;
+
+ item = malloc_or_die(sizeof(*item));
+
+ item->next = pevent->printklist;
+ pevent->printklist = item;
+ item->printk = strdup(fmt);
+ item->addr = addr;
+
+ pevent->printk_count++;
+
+ return 0;
+}
+
+/**
+ * pevent_print_printk - print out the stored strings
+ * @pevent: handle for the pevent
+ *
+ * This prints the string formats that were stored.
+ */
+void pevent_print_printk(struct pevent *pevent)
+{
+ int i;
+
+ if (!pevent->printk_map)
+ printk_map_init(pevent);
+
+ for (i = 0; i < (int)pevent->printk_count; i++) {
+ printf("%016llx %s\n",
+ pevent->printk_map[i].addr,
+ pevent->printk_map[i].printk);
+ }
+}
+
+static struct event_format *alloc_event(void)
+{
+ struct event_format *event;
+
+ event = malloc_or_die(sizeof(*event));
+ memset(event, 0, sizeof(*event));
+
+ return event;
+}
+
+static void add_event(struct pevent *pevent, struct event_format *event)
+{
+ int i;
+
+ if (!pevent->events)
+ pevent->events = malloc_or_die(sizeof(event));
+ else
+ pevent->events =
+ realloc(pevent->events, sizeof(event) *
+ (pevent->nr_events + 1));
+ if (!pevent->events)
+ die("Can not allocate events");
+
+ for (i = 0; i < pevent->nr_events; i++) {
+ if (pevent->events[i]->id > event->id)
+ break;
+ }
+ if (i < pevent->nr_events)
+ memmove(&pevent->events[i + 1],
+ &pevent->events[i],
+ sizeof(event) * (pevent->nr_events - i));
+
+ pevent->events[i] = event;
+ pevent->nr_events++;
+
+ event->pevent = pevent;
+}
+
+static int event_item_type(enum event_type type)
+{
+ switch (type) {
+ case EVENT_ITEM ... EVENT_SQUOTE:
+ return 1;
+ case EVENT_ERROR ... EVENT_DELIM:
+ default:
+ return 0;
+ }
+}
+
+static void free_flag_sym(struct print_flag_sym *fsym)
+{
+ struct print_flag_sym *next;
+
+ while (fsym) {
+ next = fsym->next;
+ free(fsym->value);
+ free(fsym->str);
+ free(fsym);
+ fsym = next;
+ }
+}
+
+static void free_arg(struct print_arg *arg)
+{
+ struct print_arg *farg;
+
+ if (!arg)
+ return;
+
+ switch (arg->type) {
+ case PRINT_ATOM:
+ free(arg->atom.atom);
+ break;
+ case PRINT_FIELD:
+ free(arg->field.name);
+ break;
+ case PRINT_FLAGS:
+ free_arg(arg->flags.field);
+ free(arg->flags.delim);
+ free_flag_sym(arg->flags.flags);
+ break;
+ case PRINT_SYMBOL:
+ free_arg(arg->symbol.field);
+ free_flag_sym(arg->symbol.symbols);
+ break;
+ case PRINT_TYPE:
+ free(arg->typecast.type);
+ free_arg(arg->typecast.item);
+ break;
+ case PRINT_STRING:
+ case PRINT_BSTRING:
+ free(arg->string.string);
+ break;
+ case PRINT_DYNAMIC_ARRAY:
+ free(arg->dynarray.index);
+ break;
+ case PRINT_OP:
+ free(arg->op.op);
+ free_arg(arg->op.left);
+ free_arg(arg->op.right);
+ break;
+ case PRINT_FUNC:
+ while (arg->func.args) {
+ farg = arg->func.args;
+ arg->func.args = farg->next;
+ free_arg(farg);
+ }
+ break;
+
+ case PRINT_NULL:
+ default:
+ break;
+ }
+
+ free(arg);
+}
+
+static enum event_type get_type(int ch)
+{
+ if (ch == '\n')
+ return EVENT_NEWLINE;
+ if (isspace(ch))
+ return EVENT_SPACE;
+ if (isalnum(ch) || ch == '_')
+ return EVENT_ITEM;
+ if (ch == '\'')
+ return EVENT_SQUOTE;
+ if (ch == '"')
+ return EVENT_DQUOTE;
+ if (!isprint(ch))
+ return EVENT_NONE;
+ if (ch == '(' || ch == ')' || ch == ',')
+ return EVENT_DELIM;
+
+ return EVENT_OP;
+}
+
+static int __read_char(void)
+{
+ if (input_buf_ptr >= input_buf_siz)
+ return -1;
+
+ return input_buf[input_buf_ptr++];
+}
+
+static int __peek_char(void)
+{
+ if (input_buf_ptr >= input_buf_siz)
+ return -1;
+
+ return input_buf[input_buf_ptr];
+}
+
+/**
+ * pevent_peek_char - peek at the next character that will be read
+ *
+ * Returns the next character read, or -1 if end of buffer.
+ */
+int pevent_peek_char(void)
+{
+ return __peek_char();
+}
+
+static enum event_type force_token(const char *str, char **tok);
+
+static enum event_type __read_token(char **tok)
+{
+ char buf[BUFSIZ];
+ int ch, last_ch, quote_ch, next_ch;
+ int i = 0;
+ int tok_size = 0;
+ enum event_type type;
+
+ *tok = NULL;
+
+
+ ch = __read_char();
+ if (ch < 0)
+ return EVENT_NONE;
+
+ type = get_type(ch);
+ if (type == EVENT_NONE)
+ return type;
+
+ buf[i++] = ch;
+
+ switch (type) {
+ case EVENT_NEWLINE:
+ case EVENT_DELIM:
+ *tok = malloc_or_die(2);
+ (*tok)[0] = ch;
+ (*tok)[1] = 0;
+ return type;
+
+ case EVENT_OP:
+ switch (ch) {
+ case '-':
+ next_ch = __peek_char();
+ if (next_ch == '>') {
+ buf[i++] = __read_char();
+ break;
+ }
+ /* fall through */
+ case '+':
+ case '|':
+ case '&':
+ case '>':
+ case '<':
+ last_ch = ch;
+ ch = __peek_char();
+ if (ch != last_ch)
+ goto test_equal;
+ buf[i++] = __read_char();
+ switch (last_ch) {
+ case '>':
+ case '<':
+ goto test_equal;
+ default:
+ break;
+ }
+ break;
+ case '!':
+ case '=':
+ goto test_equal;
+ default: /* what should we do instead? */
+ break;
+ }
+ buf[i] = 0;
+ *tok = strdup(buf);
+ return type;
+
+ test_equal:
+ ch = __peek_char();
+ if (ch == '=')
+ buf[i++] = __read_char();
+ goto out;
+
+ case EVENT_DQUOTE:
+ case EVENT_SQUOTE:
+ /* don't keep quotes */
+ i--;
+ quote_ch = ch;
+ last_ch = 0;
+ concat:
+ do {
+ if (i == (BUFSIZ - 1)) {
+ buf[i] = 0;
+ if (*tok) {
+ *tok = realloc(*tok, tok_size + BUFSIZ);
+ if (!*tok)
+ return EVENT_NONE;
+ strcat(*tok, buf);
+ } else
+ *tok = strdup(buf);
+
+ if (!*tok)
+ return EVENT_NONE;
+ tok_size += BUFSIZ;
+ i = 0;
+ }
+ last_ch = ch;
+ ch = __read_char();
+ buf[i++] = ch;
+ /* the '\' '\' will cancel itself */
+ if (ch == '\\' && last_ch == '\\')
+ last_ch = 0;
+ } while (ch != quote_ch || last_ch == '\\');
+ /* remove the last quote */
+ i--;
+
+ /*
+ * For strings (double quotes) check the next token.
+ * If it is another string, concatinate the two.
+ */
+ if (type == EVENT_DQUOTE) {
+ unsigned long long save_input_buf_ptr = input_buf_ptr;
+
+ do {
+ ch = __read_char();
+ } while (isspace(ch));
+ if (ch == '"')
+ goto concat;
+ input_buf_ptr = save_input_buf_ptr;
+ }
+
+ goto out;
+
+ case EVENT_ERROR ... EVENT_SPACE:
+ case EVENT_ITEM:
+ default:
+ break;
+ }
+
+ while (get_type(__peek_char()) == type) {
+ if (i == (BUFSIZ - 1)) {
+ buf[i] = 0;
+ if (*tok) {
+ *tok = realloc(*tok, tok_size + BUFSIZ);
+ if (!*tok)
+ return EVENT_NONE;
+ strcat(*tok, buf);
+ } else
+ *tok = strdup(buf);
+
+ if (!*tok)
+ return EVENT_NONE;
+ tok_size += BUFSIZ;
+ i = 0;
+ }
+ ch = __read_char();
+ buf[i++] = ch;
+ }
+
+ out:
+ buf[i] = 0;
+ if (*tok) {
+ *tok = realloc(*tok, tok_size + i);
+ if (!*tok)
+ return EVENT_NONE;
+ strcat(*tok, buf);
+ } else
+ *tok = strdup(buf);
+ if (!*tok)
+ return EVENT_NONE;
+
+ if (type == EVENT_ITEM) {
+ /*
+ * Older versions of the kernel has a bug that
+ * creates invalid symbols and will break the mac80211
+ * parsing. This is a work around to that bug.
+ *
+ * See Linux kernel commit:
+ * 811cb50baf63461ce0bdb234927046131fc7fa8b
+ */
+ if (strcmp(*tok, "LOCAL_PR_FMT") == 0) {
+ free(*tok);
+ *tok = NULL;
+ return force_token("\"\%s\" ", tok);
+ } else if (strcmp(*tok, "STA_PR_FMT") == 0) {
+ free(*tok);
+ *tok = NULL;
+ return force_token("\" sta:%pM\" ", tok);
+ } else if (strcmp(*tok, "VIF_PR_FMT") == 0) {
+ free(*tok);
+ *tok = NULL;
+ return force_token("\" vif:%p(%d)\" ", tok);
+ }
+ }
+
+ return type;
+}
+
+static enum event_type force_token(const char *str, char **tok)
+{
+ const char *save_input_buf;
+ unsigned long long save_input_buf_ptr;
+ unsigned long long save_input_buf_siz;
+ enum event_type type;
+
+ /* save off the current input pointers */
+ save_input_buf = input_buf;
+ save_input_buf_ptr = input_buf_ptr;
+ save_input_buf_siz = input_buf_siz;
+
+ init_input_buf(str, strlen(str));
+
+ type = __read_token(tok);
+
+ /* reset back to original token */
+ input_buf = save_input_buf;
+ input_buf_ptr = save_input_buf_ptr;
+ input_buf_siz = save_input_buf_siz;
+
+ return type;
+}
+
+static void free_token(char *tok)
+{
+ if (tok)
+ free(tok);
+}
+
+static enum event_type read_token(char **tok)
+{
+ enum event_type type;
+
+ for (;;) {
+ type = __read_token(tok);
+ if (type != EVENT_SPACE)
+ return type;
+
+ free_token(*tok);
+ }
+
+ /* not reached */
+ *tok = NULL;
+ return EVENT_NONE;
+}
+
+/**
+ * pevent_read_token - access to utilites to use the pevent parser
+ * @tok: The token to return
+ *
+ * This will parse tokens from the string given by
+ * pevent_init_data().
+ *
+ * Returns the token type.
+ */
+enum event_type pevent_read_token(char **tok)
+{
+ return read_token(tok);
+}
+
+/**
+ * pevent_free_token - free a token returned by pevent_read_token
+ * @token: the token to free
+ */
+void pevent_free_token(char *token)
+{
+ free_token(token);
+}
+
+/* no newline */
+static enum event_type read_token_item(char **tok)
+{
+ enum event_type type;
+
+ for (;;) {
+ type = __read_token(tok);
+ if (type != EVENT_SPACE && type != EVENT_NEWLINE)
+ return type;
+ free_token(*tok);
+ *tok = NULL;
+ }
+
+ /* not reached */
+ *tok = NULL;
+ return EVENT_NONE;
+}
+
+static int test_type(enum event_type type, enum event_type expect)
+{
+ if (type != expect) {
+ do_warning("Error: expected type %d but read %d",
+ expect, type);
+ return -1;
+ }
+ return 0;
+}
+
+static int test_type_token(enum event_type type, const char *token,
+ enum event_type expect, const char *expect_tok)
+{
+ if (type != expect) {
+ do_warning("Error: expected type %d but read %d",
+ expect, type);
+ return -1;
+ }
+
+ if (strcmp(token, expect_tok) != 0) {
+ do_warning("Error: expected '%s' but read '%s'",
+ expect_tok, token);
+ return -1;
+ }
+ return 0;
+}
+
+static int __read_expect_type(enum event_type expect, char **tok, int newline_ok)
+{
+ enum event_type type;
+
+ if (newline_ok)
+ type = read_token(tok);
+ else
+ type = read_token_item(tok);
+ return test_type(type, expect);
+}
+
+static int read_expect_type(enum event_type expect, char **tok)
+{
+ return __read_expect_type(expect, tok, 1);
+}
+
+static int __read_expected(enum event_type expect, const char *str,
+ int newline_ok)
+{
+ enum event_type type;
+ char *token;
+ int ret;
+
+ if (newline_ok)
+ type = read_token(&token);
+ else
+ type = read_token_item(&token);
+
+ ret = test_type_token(type, token, expect, str);
+
+ free_token(token);
+
+ return ret;
+}
+
+static int read_expected(enum event_type expect, const char *str)
+{
+ return __read_expected(expect, str, 1);
+}
+
+static int read_expected_item(enum event_type expect, const char *str)
+{
+ return __read_expected(expect, str, 0);
+}
+
+static char *event_read_name(void)
+{
+ char *token;
+
+ if (read_expected(EVENT_ITEM, "name") < 0)
+ return NULL;
+
+ if (read_expected(EVENT_OP, ":") < 0)
+ return NULL;
+
+ if (read_expect_type(EVENT_ITEM, &token) < 0)
+ goto fail;
+
+ return token;
+
+ fail:
+ free_token(token);
+ return NULL;
+}
+
+static int event_read_id(void)
+{
+ char *token;
+ int id;
+
+ if (read_expected_item(EVENT_ITEM, "ID") < 0)
+ return -1;
+
+ if (read_expected(EVENT_OP, ":") < 0)
+ return -1;
+
+ if (read_expect_type(EVENT_ITEM, &token) < 0)
+ goto fail;
+
+ id = strtoul(token, NULL, 0);
+ free_token(token);
+ return id;
+
+ fail:
+ free_token(token);
+ return -1;
+}
+
+static int field_is_string(struct format_field *field)
+{
+ if ((field->flags & FIELD_IS_ARRAY) &&
+ (strstr(field->type, "char") || strstr(field->type, "u8") ||
+ strstr(field->type, "s8")))
+ return 1;
+
+ return 0;
+}
+
+static int field_is_dynamic(struct format_field *field)
+{
+ if (strncmp(field->type, "__data_loc", 10) == 0)
+ return 1;
+
+ return 0;
+}
+
+static int field_is_long(struct format_field *field)
+{
+ /* includes long long */
+ if (strstr(field->type, "long"))
+ return 1;
+
+ return 0;
+}
+
+static int event_read_fields(struct event_format *event, struct format_field **fields)
+{
+ struct format_field *field = NULL;
+ enum event_type type;
+ char *token;
+ char *last_token;
+ int count = 0;
+
+ do {
+ type = read_token(&token);
+ if (type == EVENT_NEWLINE) {
+ free_token(token);
+ return count;
+ }
+
+ count++;
+
+ if (test_type_token(type, token, EVENT_ITEM, "field"))
+ goto fail;
+ free_token(token);
+
+ type = read_token(&token);
+ /*
+ * The ftrace fields may still use the "special" name.
+ * Just ignore it.
+ */
+ if (event->flags & EVENT_FL_ISFTRACE &&
+ type == EVENT_ITEM && strcmp(token, "special") == 0) {
+ free_token(token);
+ type = read_token(&token);
+ }
+
+ if (test_type_token(type, token, EVENT_OP, ":") < 0)
+ goto fail;
+
+ free_token(token);
+ if (read_expect_type(EVENT_ITEM, &token) < 0)
+ goto fail;
+
+ last_token = token;
+
+ field = malloc_or_die(sizeof(*field));
+ memset(field, 0, sizeof(*field));
+ field->event = event;
+
+ /* read the rest of the type */
+ for (;;) {
+ type = read_token(&token);
+ if (type == EVENT_ITEM ||
+ (type == EVENT_OP && strcmp(token, "*") == 0) ||
+ /*
+ * Some of the ftrace fields are broken and have
+ * an illegal "." in them.
+ */
+ (event->flags & EVENT_FL_ISFTRACE &&
+ type == EVENT_OP && strcmp(token, ".") == 0)) {
+
+ if (strcmp(token, "*") == 0)
+ field->flags |= FIELD_IS_POINTER;
+
+ if (field->type) {
+ field->type = realloc(field->type,
+ strlen(field->type) +
+ strlen(last_token) + 2);
+ strcat(field->type, " ");
+ strcat(field->type, last_token);
+ free(last_token);
+ } else
+ field->type = last_token;
+ last_token = token;
+ continue;
+ }
+
+ break;
+ }
+
+ if (!field->type) {
+ die("no type found");
+ goto fail;
+ }
+ field->name = last_token;
+
+ if (test_type(type, EVENT_OP))
+ goto fail;
+
+ if (strcmp(token, "[") == 0) {
+ enum event_type last_type = type;
+ char *brackets = token;
+ int len;
+
+ field->flags |= FIELD_IS_ARRAY;
+
+ type = read_token(&token);
+
+ if (type == EVENT_ITEM)
+ field->arraylen = strtoul(token, NULL, 0);
+ else
+ field->arraylen = 0;
+
+ while (strcmp(token, "]") != 0) {
+ if (last_type == EVENT_ITEM &&
+ type == EVENT_ITEM)
+ len = 2;
+ else
+ len = 1;
+ last_type = type;
+
+ brackets = realloc(brackets,
+ strlen(brackets) +
+ strlen(token) + len);
+ if (len == 2)
+ strcat(brackets, " ");
+ strcat(brackets, token);
+ /* We only care about the last token */
+ field->arraylen = strtoul(token, NULL, 0);
+ free_token(token);
+ type = read_token(&token);
+ if (type == EVENT_NONE) {
+ die("failed to find token");
+ goto fail;
+ }
+ }
+
+ free_token(token);
+
+ brackets = realloc(brackets, strlen(brackets) + 2);
+ strcat(brackets, "]");
+
+ /* add brackets to type */
+
+ type = read_token(&token);
+ /*
+ * If the next token is not an OP, then it is of
+ * the format: type [] item;
+ */
+ if (type == EVENT_ITEM) {
+ field->type = realloc(field->type,
+ strlen(field->type) +
+ strlen(field->name) +
+ strlen(brackets) + 2);
+ strcat(field->type, " ");
+ strcat(field->type, field->name);
+ free_token(field->name);
+ strcat(field->type, brackets);
+ field->name = token;
+ type = read_token(&token);
+ } else {
+ field->type = realloc(field->type,
+ strlen(field->type) +
+ strlen(brackets) + 1);
+ strcat(field->type, brackets);
+ }
+ free(brackets);
+ }
+
+ if (field_is_string(field))
+ field->flags |= FIELD_IS_STRING;
+ if (field_is_dynamic(field))
+ field->flags |= FIELD_IS_DYNAMIC;
+ if (field_is_long(field))
+ field->flags |= FIELD_IS_LONG;
+
+ if (test_type_token(type, token, EVENT_OP, ";"))
+ goto fail;
+ free_token(token);
+
+ if (read_expected(EVENT_ITEM, "offset") < 0)
+ goto fail_expect;
+
+ if (read_expected(EVENT_OP, ":") < 0)
+ goto fail_expect;
+
+ if (read_expect_type(EVENT_ITEM, &token))
+ goto fail;
+ field->offset = strtoul(token, NULL, 0);
+ free_token(token);
+
+ if (read_expected(EVENT_OP, ";") < 0)
+ goto fail_expect;
+
+ if (read_expected(EVENT_ITEM, "size") < 0)
+ goto fail_expect;
+
+ if (read_expected(EVENT_OP, ":") < 0)
+ goto fail_expect;
+
+ if (read_expect_type(EVENT_ITEM, &token))
+ goto fail;
+ field->size = strtoul(token, NULL, 0);
+ free_token(token);
+
+ if (read_expected(EVENT_OP, ";") < 0)
+ goto fail_expect;
+
+ type = read_token(&token);
+ if (type != EVENT_NEWLINE) {
+ /* newer versions of the kernel have a "signed" type */
+ if (test_type_token(type, token, EVENT_ITEM, "signed"))
+ goto fail;
+
+ free_token(token);
+
+ if (read_expected(EVENT_OP, ":") < 0)
+ goto fail_expect;
+
+ if (read_expect_type(EVENT_ITEM, &token))
+ goto fail;
+
+ /* add signed type */
+
+ free_token(token);
+ if (read_expected(EVENT_OP, ";") < 0)
+ goto fail_expect;
+
+ if (read_expect_type(EVENT_NEWLINE, &token))
+ goto fail;
+ }
+
+ free_token(token);
+
+ if (field->flags & FIELD_IS_ARRAY) {
+ if (field->arraylen)
+ field->elementsize = field->size / field->arraylen;
+ else if (field->flags & FIELD_IS_STRING)
+ field->elementsize = 1;
+ else
+ field->elementsize = event->pevent->long_size;
+ } else
+ field->elementsize = field->size;
+
+ *fields = field;
+ fields = &field->next;
+
+ } while (1);
+
+ return 0;
+
+fail:
+ free_token(token);
+fail_expect:
+ if (field)
+ free(field);
+ return -1;
+}
+
+static int event_read_format(struct event_format *event)
+{
+ char *token;
+ int ret;
+
+ if (read_expected_item(EVENT_ITEM, "format") < 0)
+ return -1;
+
+ if (read_expected(EVENT_OP, ":") < 0)
+ return -1;
+
+ if (read_expect_type(EVENT_NEWLINE, &token))
+ goto fail;
+ free_token(token);
+
+ ret = event_read_fields(event, &event->format.common_fields);
+ if (ret < 0)
+ return ret;
+ event->format.nr_common = ret;
+
+ ret = event_read_fields(event, &event->format.fields);
+ if (ret < 0)
+ return ret;
+ event->format.nr_fields = ret;
+
+ return 0;
+
+ fail:
+ free_token(token);
+ return -1;
+}
+
+static enum event_type
+process_arg_token(struct event_format *event, struct print_arg *arg,
+ char **tok, enum event_type type);
+
+static enum event_type
+process_arg(struct event_format *event, struct print_arg *arg, char **tok)
+{
+ enum event_type type;
+ char *token;
+
+ type = read_token(&token);
+ *tok = token;
+
+ return process_arg_token(event, arg, tok, type);
+}
+
+static enum event_type
+process_op(struct event_format *event, struct print_arg *arg, char **tok);
+
+static enum event_type
+process_cond(struct event_format *event, struct print_arg *top, char **tok)
+{
+ struct print_arg *arg, *left, *right;
+ enum event_type type;
+ char *token = NULL;
+
+ arg = alloc_arg();
+ left = alloc_arg();
+ right = alloc_arg();
+
+ arg->type = PRINT_OP;
+ arg->op.left = left;
+ arg->op.right = right;
+
+ *tok = NULL;
+ type = process_arg(event, left, &token);
+
+ again:
+ /* Handle other operations in the arguments */
+ if (type == EVENT_OP && strcmp(token, ":") != 0) {
+ type = process_op(event, left, &token);
+ goto again;
+ }
+
+ if (test_type_token(type, token, EVENT_OP, ":"))
+ goto out_free;
+
+ arg->op.op = token;
+
+ type = process_arg(event, right, &token);
+
+ top->op.right = arg;
+
+ *tok = token;
+ return type;
+
+out_free:
+ /* Top may point to itself */
+ top->op.right = NULL;
+ free_token(token);
+ free_arg(arg);
+ return EVENT_ERROR;
+}
+
+static enum event_type
+process_array(struct event_format *event, struct print_arg *top, char **tok)
+{
+ struct print_arg *arg;
+ enum event_type type;
+ char *token = NULL;
+
+ arg = alloc_arg();
+
+ *tok = NULL;
+ type = process_arg(event, arg, &token);
+ if (test_type_token(type, token, EVENT_OP, "]"))
+ goto out_free;
+
+ top->op.right = arg;
+
+ free_token(token);
+ type = read_token_item(&token);
+ *tok = token;
+
+ return type;
+
+out_free:
+ free_token(*tok);
+ *tok = NULL;
+ free_arg(arg);
+ return EVENT_ERROR;
+}
+
+static int get_op_prio(char *op)
+{
+ if (!op[1]) {
+ switch (op[0]) {
+ case '~':
+ case '!':
+ return 4;
+ case '*':
+ case '/':
+ case '%':
+ return 6;
+ case '+':
+ case '-':
+ return 7;
+ /* '>>' and '<<' are 8 */
+ case '<':
+ case '>':
+ return 9;
+ /* '==' and '!=' are 10 */
+ case '&':
+ return 11;
+ case '^':
+ return 12;
+ case '|':
+ return 13;
+ case '?':
+ return 16;
+ default:
+ do_warning("unknown op '%c'", op[0]);
+ return -1;
+ }
+ } else {
+ if (strcmp(op, "++") == 0 ||
+ strcmp(op, "--") == 0) {
+ return 3;
+ } else if (strcmp(op, ">>") == 0 ||
+ strcmp(op, "<<") == 0) {
+ return 8;
+ } else if (strcmp(op, ">=") == 0 ||
+ strcmp(op, "<=") == 0) {
+ return 9;
+ } else if (strcmp(op, "==") == 0 ||
+ strcmp(op, "!=") == 0) {
+ return 10;
+ } else if (strcmp(op, "&&") == 0) {
+ return 14;
+ } else if (strcmp(op, "||") == 0) {
+ return 15;
+ } else {
+ do_warning("unknown op '%s'", op);
+ return -1;
+ }
+ }
+}
+
+static int set_op_prio(struct print_arg *arg)
+{
+
+ /* single ops are the greatest */
+ if (!arg->op.left || arg->op.left->type == PRINT_NULL)
+ arg->op.prio = 0;
+ else
+ arg->op.prio = get_op_prio(arg->op.op);
+
+ return arg->op.prio;
+}
+
+/* Note, *tok does not get freed, but will most likely be saved */
+static enum event_type
+process_op(struct event_format *event, struct print_arg *arg, char **tok)
+{
+ struct print_arg *left, *right = NULL;
+ enum event_type type;
+ char *token;
+
+ /* the op is passed in via tok */
+ token = *tok;
+
+ if (arg->type == PRINT_OP && !arg->op.left) {
+ /* handle single op */
+ if (token[1]) {
+ die("bad op token %s", token);
+ goto out_free;
+ }
+ switch (token[0]) {
+ case '~':
+ case '!':
+ case '+':
+ case '-':
+ break;
+ default:
+ do_warning("bad op token %s", token);
+ goto out_free;
+
+ }
+
+ /* make an empty left */
+ left = alloc_arg();
+ left->type = PRINT_NULL;
+ arg->op.left = left;
+
+ right = alloc_arg();
+ arg->op.right = right;
+
+ /* do not free the token, it belongs to an op */
+ *tok = NULL;
+ type = process_arg(event, right, tok);
+
+ } else if (strcmp(token, "?") == 0) {
+
+ left = alloc_arg();
+ /* copy the top arg to the left */
+ *left = *arg;
+
+ arg->type = PRINT_OP;
+ arg->op.op = token;
+ arg->op.left = left;
+ arg->op.prio = 0;
+
+ type = process_cond(event, arg, tok);
+
+ } else if (strcmp(token, ">>") == 0 ||
+ strcmp(token, "<<") == 0 ||
+ strcmp(token, "&") == 0 ||
+ strcmp(token, "|") == 0 ||
+ strcmp(token, "&&") == 0 ||
+ strcmp(token, "||") == 0 ||
+ strcmp(token, "-") == 0 ||
+ strcmp(token, "+") == 0 ||
+ strcmp(token, "*") == 0 ||
+ strcmp(token, "^") == 0 ||
+ strcmp(token, "/") == 0 ||
+ strcmp(token, "<") == 0 ||
+ strcmp(token, ">") == 0 ||
+ strcmp(token, "==") == 0 ||
+ strcmp(token, "!=") == 0) {
+
+ left = alloc_arg();
+
+ /* copy the top arg to the left */
+ *left = *arg;
+
+ arg->type = PRINT_OP;
+ arg->op.op = token;
+ arg->op.left = left;
+
+ if (set_op_prio(arg) == -1) {
+ event->flags |= EVENT_FL_FAILED;
+ goto out_free;
+ }
+
+ type = read_token_item(&token);
+ *tok = token;
+
+ /* could just be a type pointer */
+ if ((strcmp(arg->op.op, "*") == 0) &&
+ type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
+ if (left->type != PRINT_ATOM)
+ die("bad pointer type");
+ left->atom.atom = realloc(left->atom.atom,
+ strlen(left->atom.atom) + 3);
+ strcat(left->atom.atom, " *");
+ free(arg->op.op);
+ *arg = *left;
+ free(left);
+
+ return type;
+ }
+
+ right = alloc_arg();
+ type = process_arg_token(event, right, tok, type);
+ arg->op.right = right;
+
+ } else if (strcmp(token, "[") == 0) {
+
+ left = alloc_arg();
+ *left = *arg;
+
+ arg->type = PRINT_OP;
+ arg->op.op = token;
+ arg->op.left = left;
+
+ arg->op.prio = 0;
+
+ type = process_array(event, arg, tok);
+
+ } else {
+ do_warning("unknown op '%s'", token);
+ event->flags |= EVENT_FL_FAILED;
+ /* the arg is now the left side */
+ goto out_free;
+ }
+
+ if (type == EVENT_OP && strcmp(*tok, ":") != 0) {
+ int prio;
+
+ /* higher prios need to be closer to the root */
+ prio = get_op_prio(*tok);
+
+ if (prio > arg->op.prio)
+ return process_op(event, arg, tok);
+
+ return process_op(event, right, tok);
+ }
+
+ return type;
+
+ out_free:
+ free_token(token);
+ *tok = NULL;
+ return EVENT_ERROR;
+}
+
+static enum event_type
+process_entry(struct event_format *event __unused, struct print_arg *arg,
+ char **tok)
+{
+ enum event_type type;
+ char *field;
+ char *token;
+
+ if (read_expected(EVENT_OP, "->") < 0)
+ goto out_err;
+
+ if (read_expect_type(EVENT_ITEM, &token) < 0)
+ goto out_free;
+ field = token;
+
+ arg->type = PRINT_FIELD;
+ arg->field.name = field;
+
+ if (is_flag_field) {
+ arg->field.field = pevent_find_any_field(event, arg->field.name);
+ arg->field.field->flags |= FIELD_IS_FLAG;
+ is_flag_field = 0;
+ } else if (is_symbolic_field) {
+ arg->field.field = pevent_find_any_field(event, arg->field.name);
+ arg->field.field->flags |= FIELD_IS_SYMBOLIC;
+ is_symbolic_field = 0;
+ }
+
+ type = read_token(&token);
+ *tok = token;
+
+ return type;
+
+ out_free:
+ free_token(token);
+ out_err:
+ *tok = NULL;
+ return EVENT_ERROR;
+}
+
+static char *arg_eval (struct print_arg *arg);
+
+static unsigned long long
+eval_type_str(unsigned long long val, const char *type, int pointer)
+{
+ int sign = 0;
+ char *ref;
+ int len;
+
+ len = strlen(type);
+
+ if (pointer) {
+
+ if (type[len-1] != '*') {
+ do_warning("pointer expected with non pointer type");
+ return val;
+ }
+
+ ref = malloc_or_die(len);
+ memcpy(ref, type, len);
+
+ /* chop off the " *" */
+ ref[len - 2] = 0;
+
+ val = eval_type_str(val, ref, 0);
+ free(ref);
+ return val;
+ }
+
+ /* check if this is a pointer */
+ if (type[len - 1] == '*')
+ return val;
+
+ /* Try to figure out the arg size*/
+ if (strncmp(type, "struct", 6) == 0)
+ /* all bets off */
+ return val;
+
+ if (strcmp(type, "u8") == 0)
+ return val & 0xff;
+
+ if (strcmp(type, "u16") == 0)
+ return val & 0xffff;
+
+ if (strcmp(type, "u32") == 0)
+ return val & 0xffffffff;
+
+ if (strcmp(type, "u64") == 0 ||
+ strcmp(type, "s64"))
+ return val;
+
+ if (strcmp(type, "s8") == 0)
+ return (unsigned long long)(char)val & 0xff;
+
+ if (strcmp(type, "s16") == 0)
+ return (unsigned long long)(short)val & 0xffff;
+
+ if (strcmp(type, "s32") == 0)
+ return (unsigned long long)(int)val & 0xffffffff;
+
+ if (strncmp(type, "unsigned ", 9) == 0) {
+ sign = 0;
+ type += 9;
+ }
+
+ if (strcmp(type, "char") == 0) {
+ if (sign)
+ return (unsigned long long)(char)val & 0xff;
+ else
+ return val & 0xff;
+ }
+
+ if (strcmp(type, "short") == 0) {
+ if (sign)
+ return (unsigned long long)(short)val & 0xffff;
+ else
+ return val & 0xffff;
+ }
+
+ if (strcmp(type, "int") == 0) {
+ if (sign)
+ return (unsigned long long)(int)val & 0xffffffff;
+ else
+ return val & 0xffffffff;
+ }
+
+ return val;
+}
+
+/*
+ * Try to figure out the type.
+ */
+static unsigned long long
+eval_type(unsigned long long val, struct print_arg *arg, int pointer)
+{
+ if (arg->type != PRINT_TYPE)
+ die("expected type argument");
+
+ return eval_type_str(val, arg->typecast.type, pointer);
+}
+
+static int arg_num_eval(struct print_arg *arg, long long *val)
+{
+ long long left, right;
+ int ret = 1;
+
+ switch (arg->type) {
+ case PRINT_ATOM:
+ *val = strtoll(arg->atom.atom, NULL, 0);
+ break;
+ case PRINT_TYPE:
+ ret = arg_num_eval(arg->typecast.item, val);
+ if (!ret)
+ break;
+ *val = eval_type(*val, arg, 0);
+ break;
+ case PRINT_OP:
+ switch (arg->op.op[0]) {
+ case '|':
+ ret = arg_num_eval(arg->op.left, &left);
+ if (!ret)
+ break;
+ ret = arg_num_eval(arg->op.right, &right);
+ if (!ret)
+ break;
+ if (arg->op.op[1])
+ *val = left || right;
+ else
+ *val = left | right;
+ break;
+ case '&':
+ ret = arg_num_eval(arg->op.left, &left);
+ if (!ret)
+ break;
+ ret = arg_num_eval(arg->op.right, &right);
+ if (!ret)
+ break;
+ if (arg->op.op[1])
+ *val = left && right;
+ else
+ *val = left & right;
+ break;
+ case '<':
+ ret = arg_num_eval(arg->op.left, &left);
+ if (!ret)
+ break;
+ ret = arg_num_eval(arg->op.right, &right);
+ if (!ret)
+ break;
+ switch (arg->op.op[1]) {
+ case 0:
+ *val = left < right;
+ break;
+ case '<':
+ *val = left << right;
+ break;
+ case '=':
+ *val = left <= right;
+ break;
+ default:
+ do_warning("unknown op '%s'", arg->op.op);
+ ret = 0;
+ }
+ break;
+ case '>':
+ ret = arg_num_eval(arg->op.left, &left);
+ if (!ret)
+ break;
+ ret = arg_num_eval(arg->op.right, &right);
+ if (!ret)
+ break;
+ switch (arg->op.op[1]) {
+ case 0:
+ *val = left > right;
+ break;
+ case '>':
+ *val = left >> right;
+ break;
+ case '=':
+ *val = left >= right;
+ break;
+ default:
+ do_warning("unknown op '%s'", arg->op.op);
+ ret = 0;
+ }
+ break;
+ case '=':
+ ret = arg_num_eval(arg->op.left, &left);
+ if (!ret)
+ break;
+ ret = arg_num_eval(arg->op.right, &right);
+ if (!ret)
+ break;
+
+ if (arg->op.op[1] != '=') {
+ do_warning("unknown op '%s'", arg->op.op);
+ ret = 0;
+ } else
+ *val = left == right;
+ break;
+ case '!':
+ ret = arg_num_eval(arg->op.left, &left);
+ if (!ret)
+ break;
+ ret = arg_num_eval(arg->op.right, &right);
+ if (!ret)
+ break;
+
+ switch (arg->op.op[1]) {
+ case '=':
+ *val = left != right;
+ break;
+ default:
+ do_warning("unknown op '%s'", arg->op.op);
+ ret = 0;
+ }
+ break;
+ case '-':
+ /* check for negative */
+ if (arg->op.left->type == PRINT_NULL)
+ left = 0;
+ else
+ ret = arg_num_eval(arg->op.left, &left);
+ if (!ret)
+ break;
+ ret = arg_num_eval(arg->op.right, &right);
+ if (!ret)
+ break;
+ *val = left - right;
+ break;
+ case '+':
+ if (arg->op.left->type == PRINT_NULL)
+ left = 0;
+ else
+ ret = arg_num_eval(arg->op.left, &left);
+ if (!ret)
+ break;
+ ret = arg_num_eval(arg->op.right, &right);
+ if (!ret)
+ break;
+ *val = left + right;
+ break;
+ default:
+ do_warning("unknown op '%s'", arg->op.op);
+ ret = 0;
+ }
+ break;
+
+ case PRINT_NULL:
+ case PRINT_FIELD ... PRINT_SYMBOL:
+ case PRINT_STRING:
+ case PRINT_BSTRING:
+ default:
+ do_warning("invalid eval type %d", arg->type);
+ ret = 0;
+
+ }
+ return ret;
+}
+
+static char *arg_eval (struct print_arg *arg)
+{
+ long long val;
+ static char buf[20];
+
+ switch (arg->type) {
+ case PRINT_ATOM:
+ return arg->atom.atom;
+ case PRINT_TYPE:
+ return arg_eval(arg->typecast.item);
+ case PRINT_OP:
+ if (!arg_num_eval(arg, &val))
+ break;
+ sprintf(buf, "%lld", val);
+ return buf;
+
+ case PRINT_NULL:
+ case PRINT_FIELD ... PRINT_SYMBOL:
+ case PRINT_STRING:
+ case PRINT_BSTRING:
+ default:
+ die("invalid eval type %d", arg->type);
+ break;
+ }
+
+ return NULL;
+}
+
+static enum event_type
+process_fields(struct event_format *event, struct print_flag_sym **list, char **tok)
+{
+ enum event_type type;
+ struct print_arg *arg = NULL;
+ struct print_flag_sym *field;
+ char *token = *tok;
+ char *value;
+
+ do {
+ free_token(token);
+ type = read_token_item(&token);
+ if (test_type_token(type, token, EVENT_OP, "{"))
+ break;
+
+ arg = alloc_arg();
+
+ free_token(token);
+ type = process_arg(event, arg, &token);
+ if (test_type_token(type, token, EVENT_DELIM, ","))
+ goto out_free;
+
+ field = malloc_or_die(sizeof(*field));
+ memset(field, 0, sizeof(*field));
+
+ value = arg_eval(arg);
+ if (value == NULL)
+ goto out_free;
+ field->value = strdup(value);
+
+ free_arg(arg);
+ arg = alloc_arg();
+
+ free_token(token);
+ type = process_arg(event, arg, &token);
+ if (test_type_token(type, token, EVENT_OP, "}"))
+ goto out_free;
+
+ value = arg_eval(arg);
+ if (value == NULL)
+ goto out_free;
+ field->str = strdup(value);
+ free_arg(arg);
+ arg = NULL;
+
+ *list = field;
+ list = &field->next;
+
+ free_token(token);
+ type = read_token_item(&token);
+ } while (type == EVENT_DELIM && strcmp(token, ",") == 0);
+
+ *tok = token;
+ return type;
+
+out_free:
+ free_arg(arg);
+ free_token(token);
+ *tok = NULL;
+
+ return EVENT_ERROR;
+}
+
+static enum event_type
+process_flags(struct event_format *event, struct print_arg *arg, char **tok)
+{
+ struct print_arg *field;
+ enum event_type type;
+ char *token;
+
+ memset(arg, 0, sizeof(*arg));
+ arg->type = PRINT_FLAGS;
+
+ field = alloc_arg();
+
+ type = process_arg(event, field, &token);
+
+ /* Handle operations in the first argument */
+ while (type == EVENT_OP)
+ type = process_op(event, field, &token);
+
+ if (test_type_token(type, token, EVENT_DELIM, ","))
+ goto out_free;
+ free_token(token);
+
+ arg->flags.field = field;
+
+ type = read_token_item(&token);
+ if (event_item_type(type)) {
+ arg->flags.delim = token;
+ type = read_token_item(&token);
+ }
+
+ if (test_type_token(type, token, EVENT_DELIM, ","))
+ goto out_free;
+
+ type = process_fields(event, &arg->flags.flags, &token);
+ if (test_type_token(type, token, EVENT_DELIM, ")"))
+ goto out_free;
+
+ free_token(token);
+ type = read_token_item(tok);
+ return type;
+
+ out_free:
+ free_token(token);
+ *tok = NULL;
+ return EVENT_ERROR;
+}
+
+static enum event_type
+process_symbols(struct event_format *event, struct print_arg *arg, char **tok)
+{
+ struct print_arg *field;
+ enum event_type type;
+ char *token;
+
+ memset(arg, 0, sizeof(*arg));
+ arg->type = PRINT_SYMBOL;
+
+ field = alloc_arg();
+
+ type = process_arg(event, field, &token);
+ if (test_type_token(type, token, EVENT_DELIM, ","))
+ goto out_free;
+
+ arg->symbol.field = field;
+
+ type = process_fields(event, &arg->symbol.symbols, &token);
+ if (test_type_token(type, token, EVENT_DELIM, ")"))
+ goto out_free;
+
+ free_token(token);
+ type = read_token_item(tok);
+ return type;
+
+ out_free:
+ free_token(token);
+ *tok = NULL;
+ return EVENT_ERROR;
+}
+
+static enum event_type
+process_dynamic_array(struct event_format *event, struct print_arg *arg, char **tok)
+{
+ struct format_field *field;
+ enum event_type type;
+ char *token;
+
+ memset(arg, 0, sizeof(*arg));
+ arg->type = PRINT_DYNAMIC_ARRAY;
+
+ /*
+ * The item within the parenthesis is another field that holds
+ * the index into where the array starts.
+ */
+ type = read_token(&token);
+ *tok = token;
+ if (type != EVENT_ITEM)
+ goto out_free;
+
+ /* Find the field */
+
+ field = pevent_find_field(event, token);
+ if (!field)
+ goto out_free;
+
+ arg->dynarray.field = field;
+ arg->dynarray.index = 0;
+
+ if (read_expected(EVENT_DELIM, ")") < 0)
+ goto out_free;
+
+ free_token(token);
+ type = read_token_item(&token);
+ *tok = token;
+ if (type != EVENT_OP || strcmp(token, "[") != 0)
+ return type;
+
+ free_token(token);
+ arg = alloc_arg();
+ type = process_arg(event, arg, &token);
+ if (type == EVENT_ERROR)
+ goto out_free;
+
+ if (!test_type_token(type, token, EVENT_OP, "]"))
+ goto out_free;
+
+ free_token(token);
+ type = read_token_item(tok);
+ return type;
+
+ out_free:
+ free(arg);
+ free_token(token);
+ *tok = NULL;
+ return EVENT_ERROR;
+}
+
+static enum event_type
+process_paren(struct event_format *event, struct print_arg *arg, char **tok)
+{
+ struct print_arg *item_arg;
+ enum event_type type;
+ char *token;
+
+ type = process_arg(event, arg, &token);
+
+ if (type == EVENT_ERROR)
+ goto out_free;
+
+ if (type == EVENT_OP)
+ type = process_op(event, arg, &token);
+
+ if (type == EVENT_ERROR)
+ goto out_free;
+
+ if (test_type_token(type, token, EVENT_DELIM, ")"))
+ goto out_free;
+
+ free_token(token);
+ type = read_token_item(&token);
+
+ /*
+ * If the next token is an item or another open paren, then
+ * this was a typecast.
+ */
+ if (event_item_type(type) ||
+ (type == EVENT_DELIM && strcmp(token, "(") == 0)) {
+
+ /* make this a typecast and contine */
+
+ /* prevous must be an atom */
+ if (arg->type != PRINT_ATOM)
+ die("previous needed to be PRINT_ATOM");
+
+ item_arg = alloc_arg();
+
+ arg->type = PRINT_TYPE;
+ arg->typecast.type = arg->atom.atom;
+ arg->typecast.item = item_arg;
+ type = process_arg_token(event, item_arg, &token, type);
+
+ }
+
+ *tok = token;
+ return type;
+
+ out_free:
+ free_token(token);
+ *tok = NULL;
+ return EVENT_ERROR;
+}
+
+
+static enum event_type
+process_str(struct event_format *event __unused, struct print_arg *arg, char **tok)
+{
+ enum event_type type;
+ char *token;
+
+ if (read_expect_type(EVENT_ITEM, &token) < 0)
+ goto out_free;
+
+ arg->type = PRINT_STRING;
+ arg->string.string = token;
+ arg->string.offset = -1;
+
+ if (read_expected(EVENT_DELIM, ")") < 0)
+ goto out_err;
+
+ type = read_token(&token);
+ *tok = token;
+
+ return type;
+
+ out_free:
+ free_token(token);
+ out_err:
+ *tok = NULL;
+ return EVENT_ERROR;
+}
+
+static struct pevent_function_handler *
+find_func_handler(struct pevent *pevent, char *func_name)
+{
+ struct pevent_function_handler *func;
+
+ for (func = pevent->func_handlers; func; func = func->next) {
+ if (strcmp(func->name, func_name) == 0)
+ break;
+ }
+
+ return func;
+}
+
+static void remove_func_handler(struct pevent *pevent, char *func_name)
+{
+ struct pevent_function_handler *func;
+ struct pevent_function_handler **next;
+
+ next = &pevent->func_handlers;
+ while ((func = *next)) {
+ if (strcmp(func->name, func_name) == 0) {
+ *next = func->next;
+ free_func_handle(func);
+ break;
+ }
+ next = &func->next;
+ }
+}
+
+static enum event_type
+process_func_handler(struct event_format *event, struct pevent_function_handler *func,
+ struct print_arg *arg, char **tok)
+{
+ struct print_arg **next_arg;
+ struct print_arg *farg;
+ enum event_type type;
+ char *token;
+ char *test;
+ int i;
+
+ arg->type = PRINT_FUNC;
+ arg->func.func = func;
+
+ *tok = NULL;
+
+ next_arg = &(arg->func.args);
+ for (i = 0; i < func->nr_args; i++) {
+ farg = alloc_arg();
+ type = process_arg(event, farg, &token);
+ if (i < (func->nr_args - 1))
+ test = ",";
+ else
+ test = ")";
+
+ if (test_type_token(type, token, EVENT_DELIM, test)) {
+ free_arg(farg);
+ free_token(token);
+ return EVENT_ERROR;
+ }
+
+ *next_arg = farg;
+ next_arg = &(farg->next);
+ free_token(token);
+ }
+
+ type = read_token(&token);
+ *tok = token;
+
+ return type;
+}
+
+static enum event_type
+process_function(struct event_format *event, struct print_arg *arg,
+ char *token, char **tok)
+{
+ struct pevent_function_handler *func;
+
+ if (strcmp(token, "__print_flags") == 0) {
+ free_token(token);
+ is_flag_field = 1;
+ return process_flags(event, arg, tok);
+ }
+ if (strcmp(token, "__print_symbolic") == 0) {
+ free_token(token);
+ is_symbolic_field = 1;
+ return process_symbols(event, arg, tok);
+ }
+ if (strcmp(token, "__get_str") == 0) {
+ free_token(token);
+ return process_str(event, arg, tok);
+ }
+ if (strcmp(token, "__get_dynamic_array") == 0) {
+ free_token(token);
+ return process_dynamic_array(event, arg, tok);
+ }
+
+ func = find_func_handler(event->pevent, token);
+ if (func) {
+ free_token(token);
+ return process_func_handler(event, func, arg, tok);
+ }
+
+ do_warning("function %s not defined", token);
+ free_token(token);
+ return EVENT_ERROR;
+}
+
+static enum event_type
+process_arg_token(struct event_format *event, struct print_arg *arg,
+ char **tok, enum event_type type)
+{
+ char *token;
+ char *atom;
+
+ token = *tok;
+
+ switch (type) {
+ case EVENT_ITEM:
+ if (strcmp(token, "REC") == 0) {
+ free_token(token);
+ type = process_entry(event, arg, &token);
+ break;
+ }
+ atom = token;
+ /* test the next token */
+ type = read_token_item(&token);
+
+ /*
+ * If the next token is a parenthesis, then this
+ * is a function.
+ */
+ if (type == EVENT_DELIM && strcmp(token, "(") == 0) {
+ free_token(token);
+ token = NULL;
+ /* this will free atom. */
+ type = process_function(event, arg, atom, &token);
+ break;
+ }
+ /* atoms can be more than one token long */
+ while (type == EVENT_ITEM) {
+ atom = realloc(atom, strlen(atom) + strlen(token) + 2);
+ strcat(atom, " ");
+ strcat(atom, token);
+ free_token(token);
+ type = read_token_item(&token);
+ }
+
+ arg->type = PRINT_ATOM;
+ arg->atom.atom = atom;
+ break;
+
+ case EVENT_DQUOTE:
+ case EVENT_SQUOTE:
+ arg->type = PRINT_ATOM;
+ arg->atom.atom = token;
+ type = read_token_item(&token);
+ break;
+ case EVENT_DELIM:
+ if (strcmp(token, "(") == 0) {
+ free_token(token);
+ type = process_paren(event, arg, &token);
+ break;
+ }
+ case EVENT_OP:
+ /* handle single ops */
+ arg->type = PRINT_OP;
+ arg->op.op = token;
+ arg->op.left = NULL;
+ type = process_op(event, arg, &token);
+
+ /* On error, the op is freed */
+ if (type == EVENT_ERROR)
+ arg->op.op = NULL;
+
+ /* return error type if errored */
+ break;
+
+ case EVENT_ERROR ... EVENT_NEWLINE:
+ default:
+ die("unexpected type %d", type);
+ }
+ *tok = token;
+
+ return type;
+}
+
+static int event_read_print_args(struct event_format *event, struct print_arg **list)
+{
+ enum event_type type = EVENT_ERROR;
+ struct print_arg *arg;
+ char *token;
+ int args = 0;
+
+ do {
+ if (type == EVENT_NEWLINE) {
+ type = read_token_item(&token);
+ continue;
+ }
+
+ arg = alloc_arg();
+
+ type = process_arg(event, arg, &token);
+
+ if (type == EVENT_ERROR) {
+ free_token(token);
+ free_arg(arg);
+ return -1;
+ }
+
+ *list = arg;
+ args++;
+
+ if (type == EVENT_OP) {
+ type = process_op(event, arg, &token);
+ free_token(token);
+ if (type == EVENT_ERROR) {
+ *list = NULL;
+ free_arg(arg);
+ return -1;
+ }
+ list = &arg->next;
+ continue;
+ }
+
+ if (type == EVENT_DELIM && strcmp(token, ",") == 0) {
+ free_token(token);
+ *list = arg;
+ list = &arg->next;
+ continue;
+ }
+ break;
+ } while (type != EVENT_NONE);
+
+ if (type != EVENT_NONE && type != EVENT_ERROR)
+ free_token(token);
+
+ return args;
+}
+
+static int event_read_print(struct event_format *event)
+{
+ enum event_type type;
+ char *token;
+ int ret;
+
+ if (read_expected_item(EVENT_ITEM, "print") < 0)
+ return -1;
+
+ if (read_expected(EVENT_ITEM, "fmt") < 0)
+ return -1;
+
+ if (read_expected(EVENT_OP, ":") < 0)
+ return -1;
+
+ if (read_expect_type(EVENT_DQUOTE, &token) < 0)
+ goto fail;
+
+ concat:
+ event->print_fmt.format = token;
+ event->print_fmt.args = NULL;
+
+ /* ok to have no arg */
+ type = read_token_item(&token);
+
+ if (type == EVENT_NONE)
+ return 0;
+
+ /* Handle concatenation of print lines */
+ if (type == EVENT_DQUOTE) {
+ char *cat;
+
+ cat = malloc_or_die(strlen(event->print_fmt.format) +
+ strlen(token) + 1);
+ strcpy(cat, event->print_fmt.format);
+ strcat(cat, token);
+ free_token(token);
+ free_token(event->print_fmt.format);
+ event->print_fmt.format = NULL;
+ token = cat;
+ goto concat;
+ }
+
+ if (test_type_token(type, token, EVENT_DELIM, ","))
+ goto fail;
+
+ free_token(token);
+
+ ret = event_read_print_args(event, &event->print_fmt.args);
+ if (ret < 0)
+ return -1;
+
+ return ret;
+
+ fail:
+ free_token(token);
+ return -1;
+}
+
+/**
+ * pevent_find_common_field - return a common field by event
+ * @event: handle for the event
+ * @name: the name of the common field to return
+ *
+ * Returns a common field from the event by the given @name.
+ * This only searchs the common fields and not all field.
+ */
+struct format_field *
+pevent_find_common_field(struct event_format *event, const char *name)
+{
+ struct format_field *format;
+
+ for (format = event->format.common_fields;
+ format; format = format->next) {
+ if (strcmp(format->name, name) == 0)
+ break;
+ }
+
+ return format;
+}
+
+/**
+ * pevent_find_field - find a non-common field
+ * @event: handle for the event
+ * @name: the name of the non-common field
+ *
+ * Returns a non-common field by the given @name.
+ * This does not search common fields.
+ */
+struct format_field *
+pevent_find_field(struct event_format *event, const char *name)
+{
+ struct format_field *format;
+
+ for (format = event->format.fields;
+ format; format = format->next) {
+ if (strcmp(format->name, name) == 0)
+ break;
+ }
+
+ return format;
+}
+
+/**
+ * pevent_find_any_field - find any field by name
+ * @event: handle for the event
+ * @name: the name of the field
+ *
+ * Returns a field by the given @name.
+ * This searchs the common field names first, then
+ * the non-common ones if a common one was not found.
+ */
+struct format_field *
+pevent_find_any_field(struct event_format *event, const char *name)
+{
+ struct format_field *format;
+
+ format = pevent_find_common_field(event, name);
+ if (format)
+ return format;
+ return pevent_find_field(event, name);
+}
+
+/**
+ * pevent_read_number - read a number from data
+ * @pevent: handle for the pevent
+ * @ptr: the raw data
+ * @size: the size of the data that holds the number
+ *
+ * Returns the number (converted to host) from the
+ * raw data.
+ */
+unsigned long long pevent_read_number(struct pevent *pevent,
+ const void *ptr, int size)
+{
+ switch (size) {
+ case 1:
+ return *(unsigned char *)ptr;
+ case 2:
+ return data2host2(pevent, ptr);
+ case 4:
+ return data2host4(pevent, ptr);
+ case 8:
+ return data2host8(pevent, ptr);
+ default:
+ /* BUG! */
+ return 0;
+ }
+}
+
+/**
+ * pevent_read_number_field - read a number from data
+ * @field: a handle to the field
+ * @data: the raw data to read
+ * @value: the value to place the number in
+ *
+ * Reads raw data according to a field offset and size,
+ * and translates it into @value.
+ *
+ * Returns 0 on success, -1 otherwise.
+ */
+int pevent_read_number_field(struct format_field *field, const void *data,
+ unsigned long long *value)
+{
+ if (!field)
+ return -1;
+ switch (field->size) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ *value = pevent_read_number(field->event->pevent,
+ data + field->offset, field->size);
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+static int get_common_info(struct pevent *pevent,
+ const char *type, int *offset, int *size)
+{
+ struct event_format *event;
+ struct format_field *field;
+
+ /*
+ * All events should have the same common elements.
+ * Pick any event to find where the type is;
+ */
+ if (!pevent->events)
+ die("no event_list!");
+
+ event = pevent->events[0];
+ field = pevent_find_common_field(event, type);
+ if (!field)
+ die("field '%s' not found", type);
+
+ *offset = field->offset;
+ *size = field->size;
+
+ return 0;
+}
+
+static int __parse_common(struct pevent *pevent, void *data,
+ int *size, int *offset, const char *name)
+{
+ int ret;
+
+ if (!*size) {
+ ret = get_common_info(pevent, name, offset, size);
+ if (ret < 0)
+ return ret;
+ }
+ return pevent_read_number(pevent, data + *offset, *size);
+}
+
+static int trace_parse_common_type(struct pevent *pevent, void *data)
+{
+ return __parse_common(pevent, data,
+ &pevent->type_size, &pevent->type_offset,
+ "common_type");
+}
+
+static int parse_common_pid(struct pevent *pevent, void *data)
+{
+ return __parse_common(pevent, data,
+ &pevent->pid_size, &pevent->pid_offset,
+ "common_pid");
+}
+
+static int parse_common_pc(struct pevent *pevent, void *data)
+{
+ return __parse_common(pevent, data,
+ &pevent->pc_size, &pevent->pc_offset,
+ "common_preempt_count");
+}
+
+static int parse_common_flags(struct pevent *pevent, void *data)
+{
+ return __parse_common(pevent, data,
+ &pevent->flags_size, &pevent->flags_offset,
+ "common_flags");
+}
+
+static int parse_common_lock_depth(struct pevent *pevent, void *data)
+{
+ int ret;
+
+ ret = __parse_common(pevent, data,
+ &pevent->ld_size, &pevent->ld_offset,
+ "common_lock_depth");
+ if (ret < 0)
+ return -1;
+
+ return ret;
+}
+
+static int events_id_cmp(const void *a, const void *b);
+
+/**
+ * pevent_find_event - find an event by given id
+ * @pevent: a handle to the pevent
+ * @id: the id of the event
+ *
+ * Returns an event that has a given @id.
+ */
+struct event_format *pevent_find_event(struct pevent *pevent, int id)
+{
+ struct event_format **eventptr;
+ struct event_format key;
+ struct event_format *pkey = &key;
+
+ /* Check cache first */
+ if (pevent->last_event && pevent->last_event->id == id)
+ return pevent->last_event;
+
+ key.id = id;
+
+ eventptr = bsearch(&pkey, pevent->events, pevent->nr_events,
+ sizeof(*pevent->events), events_id_cmp);
+
+ if (eventptr) {
+ pevent->last_event = *eventptr;
+ return *eventptr;
+ }
+
+ return NULL;
+}
+
+/**
+ * pevent_find_event_by_name - find an event by given name
+ * @pevent: a handle to the pevent
+ * @sys: the system name to search for
+ * @name: the name of the event to search for
+ *
+ * This returns an event with a given @name and under the system
+ * @sys. If @sys is NULL the first event with @name is returned.
+ */
+struct event_format *
+pevent_find_event_by_name(struct pevent *pevent,
+ const char *sys, const char *name)
+{
+ struct event_format *event;
+ int i;
+
+ if (pevent->last_event &&
+ strcmp(pevent->last_event->name, name) == 0 &&
+ (!sys || strcmp(pevent->last_event->system, sys) == 0))
+ return pevent->last_event;
+
+ for (i = 0; i < pevent->nr_events; i++) {
+ event = pevent->events[i];
+ if (strcmp(event->name, name) == 0) {
+ if (!sys)
+ break;
+ if (strcmp(event->system, sys) == 0)
+ break;
+ }
+ }
+ if (i == pevent->nr_events)
+ event = NULL;
+
+ pevent->last_event = event;
+ return event;
+}
+
+static unsigned long long
+eval_num_arg(void *data, int size, struct event_format *event, struct print_arg *arg)
+{
+ struct pevent *pevent = event->pevent;
+ unsigned long long val = 0;
+ unsigned long long left, right;
+ struct print_arg *typearg = NULL;
+ struct print_arg *larg;
+ unsigned long offset;
+ unsigned int field_size;
+
+ switch (arg->type) {
+ case PRINT_NULL:
+ /* ?? */
+ return 0;
+ case PRINT_ATOM:
+ return strtoull(arg->atom.atom, NULL, 0);
+ case PRINT_FIELD:
+ if (!arg->field.field) {
+ arg->field.field = pevent_find_any_field(event, arg->field.name);
+ if (!arg->field.field)
+ die("field %s not found", arg->field.name);
+ }
+ /* must be a number */
+ val = pevent_read_number(pevent, data + arg->field.field->offset,
+ arg->field.field->size);
+ break;
+ case PRINT_FLAGS:
+ case PRINT_SYMBOL:
+ break;
+ case PRINT_TYPE:
+ val = eval_num_arg(data, size, event, arg->typecast.item);
+ return eval_type(val, arg, 0);
+ case PRINT_STRING:
+ case PRINT_BSTRING:
+ return 0;
+ case PRINT_FUNC: {
+ struct trace_seq s;
+ trace_seq_init(&s);
+ val = process_defined_func(&s, data, size, event, arg);
+ trace_seq_destroy(&s);
+ return val;
+ }
+ case PRINT_OP:
+ if (strcmp(arg->op.op, "[") == 0) {
+ /*
+ * Arrays are special, since we don't want
+ * to read the arg as is.
+ */
+ right = eval_num_arg(data, size, event, arg->op.right);
+
+ /* handle typecasts */
+ larg = arg->op.left;
+ while (larg->type == PRINT_TYPE) {
+ if (!typearg)
+ typearg = larg;
+ larg = larg->typecast.item;
+ }
+
+ /* Default to long size */
+ field_size = pevent->long_size;
+
+ switch (larg->type) {
+ case PRINT_DYNAMIC_ARRAY:
+ offset = pevent_read_number(pevent,
+ data + larg->dynarray.field->offset,
+ larg->dynarray.field->size);
+ if (larg->dynarray.field->elementsize)
+ field_size = larg->dynarray.field->elementsize;
+ /*
+ * The actual length of the dynamic array is stored
+ * in the top half of the field, and the offset
+ * is in the bottom half of the 32 bit field.
+ */
+ offset &= 0xffff;
+ offset += right;
+ break;
+ case PRINT_FIELD:
+ if (!larg->field.field) {
+ larg->field.field =
+ pevent_find_any_field(event, larg->field.name);
+ if (!larg->field.field)
+ die("field %s not found", larg->field.name);
+ }
+ field_size = larg->field.field->elementsize;
+ offset = larg->field.field->offset +
+ right * larg->field.field->elementsize;
+ break;
+ default:
+ goto default_op; /* oops, all bets off */
+ }
+ val = pevent_read_number(pevent,
+ data + offset, field_size);
+ if (typearg)
+ val = eval_type(val, typearg, 1);
+ break;
+ } else if (strcmp(arg->op.op, "?") == 0) {
+ left = eval_num_arg(data, size, event, arg->op.left);
+ arg = arg->op.right;
+ if (left)
+ val = eval_num_arg(data, size, event, arg->op.left);
+ else
+ val = eval_num_arg(data, size, event, arg->op.right);
+ break;
+ }
+ default_op:
+ left = eval_num_arg(data, size, event, arg->op.left);
+ right = eval_num_arg(data, size, event, arg->op.right);
+ switch (arg->op.op[0]) {
+ case '!':
+ switch (arg->op.op[1]) {
+ case 0:
+ val = !right;
+ break;
+ case '=':
+ val = left != right;
+ break;
+ default:
+ die("unknown op '%s'", arg->op.op);
+ }
+ break;
+ case '~':
+ val = ~right;
+ break;
+ case '|':
+ if (arg->op.op[1])
+ val = left || right;
+ else
+ val = left | right;
+ break;
+ case '&':
+ if (arg->op.op[1])
+ val = left && right;
+ else
+ val = left & right;
+ break;
+ case '<':
+ switch (arg->op.op[1]) {
+ case 0:
+ val = left < right;
+ break;
+ case '<':
+ val = left << right;
+ break;
+ case '=':
+ val = left <= right;
+ break;
+ default:
+ die("unknown op '%s'", arg->op.op);
+ }
+ break;
+ case '>':
+ switch (arg->op.op[1]) {
+ case 0:
+ val = left > right;
+ break;
+ case '>':
+ val = left >> right;
+ break;
+ case '=':
+ val = left >= right;
+ break;
+ default:
+ die("unknown op '%s'", arg->op.op);
+ }
+ break;
+ case '=':
+ if (arg->op.op[1] != '=')
+ die("unknown op '%s'", arg->op.op);
+ val = left == right;
+ break;
+ case '-':
+ val = left - right;
+ break;
+ case '+':
+ val = left + right;
+ break;
+ case '/':
+ val = left / right;
+ break;
+ case '*':
+ val = left * right;
+ break;
+ default:
+ die("unknown op '%s'", arg->op.op);
+ }
+ break;
+ default: /* not sure what to do there */
+ return 0;
+ }
+ return val;
+}
+
+struct flag {
+ const char *name;
+ unsigned long long value;
+};
+
+static const struct flag flags[] = {
+ { "HI_SOFTIRQ", 0 },
+ { "TIMER_SOFTIRQ", 1 },
+ { "NET_TX_SOFTIRQ", 2 },
+ { "NET_RX_SOFTIRQ", 3 },
+ { "BLOCK_SOFTIRQ", 4 },
+ { "BLOCK_IOPOLL_SOFTIRQ", 5 },
+ { "TASKLET_SOFTIRQ", 6 },
+ { "SCHED_SOFTIRQ", 7 },
+ { "HRTIMER_SOFTIRQ", 8 },
+ { "RCU_SOFTIRQ", 9 },
+
+ { "HRTIMER_NORESTART", 0 },
+ { "HRTIMER_RESTART", 1 },
+};
+
+static unsigned long long eval_flag(const char *flag)
+{
+ int i;
+
+ /*
+ * Some flags in the format files do not get converted.
+ * If the flag is not numeric, see if it is something that
+ * we already know about.
+ */
+ if (isdigit(flag[0]))
+ return strtoull(flag, NULL, 0);
+
+ for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); i++)
+ if (strcmp(flags[i].name, flag) == 0)
+ return flags[i].value;
+
+ return 0;
+}
+
+static void print_str_to_seq(struct trace_seq *s, const char *format,
+ int len_arg, const char *str)
+{
+ if (len_arg >= 0)
+ trace_seq_printf(s, format, len_arg, str);
+ else
+ trace_seq_printf(s, format, str);
+}
+
+static void print_str_arg(struct trace_seq *s, void *data, int size,
+ struct event_format *event, const char *format,
+ int len_arg, struct print_arg *arg)
+{
+ struct pevent *pevent = event->pevent;
+ struct print_flag_sym *flag;
+ unsigned long long val, fval;
+ unsigned long addr;
+ char *str;
+ int print;
+ int len;
+
+ switch (arg->type) {
+ case PRINT_NULL:
+ /* ?? */
+ return;
+ case PRINT_ATOM:
+ print_str_to_seq(s, format, len_arg, arg->atom.atom);
+ return;
+ case PRINT_FIELD:
+ if (!arg->field.field) {
+ arg->field.field = pevent_find_any_field(event, arg->field.name);
+ if (!arg->field.field)
+ die("field %s not found", arg->field.name);
+ }
+ /* Zero sized fields, mean the rest of the data */
+ len = arg->field.field->size ? : size - arg->field.field->offset;
+
+ /*
+ * Some events pass in pointers. If this is not an array
+ * and the size is the same as long_size, assume that it
+ * is a pointer.
+ */
+ if (!(arg->field.field->flags & FIELD_IS_ARRAY) &&
+ arg->field.field->size == pevent->long_size) {
+ addr = *(unsigned long *)(data + arg->field.field->offset);
+ trace_seq_printf(s, "%lx", addr);
+ break;
+ }
+ str = malloc_or_die(len + 1);
+ memcpy(str, data + arg->field.field->offset, len);
+ str[len] = 0;
+ print_str_to_seq(s, format, len_arg, str);
+ free(str);
+ break;
+ case PRINT_FLAGS:
+ val = eval_num_arg(data, size, event, arg->flags.field);
+ print = 0;
+ for (flag = arg->flags.flags; flag; flag = flag->next) {
+ fval = eval_flag(flag->value);
+ if (!val && !fval) {
+ print_str_to_seq(s, format, len_arg, flag->str);
+ break;
+ }
+ if (fval && (val & fval) == fval) {
+ if (print && arg->flags.delim)
+ trace_seq_puts(s, arg->flags.delim);
+ print_str_to_seq(s, format, len_arg, flag->str);
+ print = 1;
+ val &= ~fval;
+ }
+ }
+ break;
+ case PRINT_SYMBOL:
+ val = eval_num_arg(data, size, event, arg->symbol.field);
+ for (flag = arg->symbol.symbols; flag; flag = flag->next) {
+ fval = eval_flag(flag->value);
+ if (val == fval) {
+ print_str_to_seq(s, format, len_arg, flag->str);
+ break;
+ }
+ }
+ break;
+
+ case PRINT_TYPE:
+ break;
+ case PRINT_STRING: {
+ int str_offset;
+
+ if (arg->string.offset == -1) {
+ struct format_field *f;
+
+ f = pevent_find_any_field(event, arg->string.string);
+ arg->string.offset = f->offset;
+ }
+ str_offset = data2host4(pevent, data + arg->string.offset);
+ str_offset &= 0xffff;
+ print_str_to_seq(s, format, len_arg, ((char *)data) + str_offset);
+ break;
+ }
+ case PRINT_BSTRING:
+ trace_seq_printf(s, format, arg->string.string);
+ break;
+ case PRINT_OP:
+ /*
+ * The only op for string should be ? :
+ */
+ if (arg->op.op[0] != '?')
+ return;
+ val = eval_num_arg(data, size, event, arg->op.left);
+ if (val)
+ print_str_arg(s, data, size, event,
+ format, len_arg, arg->op.right->op.left);
+ else
+ print_str_arg(s, data, size, event,
+ format, len_arg, arg->op.right->op.right);
+ break;
+ case PRINT_FUNC:
+ process_defined_func(s, data, size, event, arg);
+ break;
+ default:
+ /* well... */
+ break;
+ }
+}
+
+static unsigned long long
+process_defined_func(struct trace_seq *s, void *data, int size,
+ struct event_format *event, struct print_arg *arg)
+{
+ struct pevent_function_handler *func_handle = arg->func.func;
+ struct pevent_func_params *param;
+ unsigned long long *args;
+ unsigned long long ret;
+ struct print_arg *farg;
+ struct trace_seq str;
+ struct save_str {
+ struct save_str *next;
+ char *str;
+ } *strings = NULL, *string;
+ int i;
+
+ if (!func_handle->nr_args) {
+ ret = (*func_handle->func)(s, NULL);
+ goto out;
+ }
+
+ farg = arg->func.args;
+ param = func_handle->params;
+
+ args = malloc_or_die(sizeof(*args) * func_handle->nr_args);
+ for (i = 0; i < func_handle->nr_args; i++) {
+ switch (param->type) {
+ case PEVENT_FUNC_ARG_INT:
+ case PEVENT_FUNC_ARG_LONG:
+ case PEVENT_FUNC_ARG_PTR:
+ args[i] = eval_num_arg(data, size, event, farg);
+ break;
+ case PEVENT_FUNC_ARG_STRING:
+ trace_seq_init(&str);
+ print_str_arg(&str, data, size, event, "%s", -1, farg);
+ trace_seq_terminate(&str);
+ string = malloc_or_die(sizeof(*string));
+ string->next = strings;
+ string->str = strdup(str.buffer);
+ strings = string;
+ trace_seq_destroy(&str);
+ break;
+ default:
+ /*
+ * Something went totally wrong, this is not
+ * an input error, something in this code broke.
+ */
+ die("Unexpected end of arguments\n");
+ break;
+ }
+ farg = farg->next;
+ }
+
+ ret = (*func_handle->func)(s, args);
+ free(args);
+ while (strings) {
+ string = strings;
+ strings = string->next;
+ free(string->str);
+ free(string);
+ }
+
+ out:
+ /* TBD : handle return type here */
+ return ret;
+}
+
+static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event_format *event)
+{
+ struct pevent *pevent = event->pevent;
+ struct format_field *field, *ip_field;
+ struct print_arg *args, *arg, **next;
+ unsigned long long ip, val;
+ char *ptr;
+ void *bptr;
+
+ field = pevent->bprint_buf_field;
+ ip_field = pevent->bprint_ip_field;
+
+ if (!field) {
+ field = pevent_find_field(event, "buf");
+ if (!field)
+ die("can't find buffer field for binary printk");
+ ip_field = pevent_find_field(event, "ip");
+ if (!ip_field)
+ die("can't find ip field for binary printk");
+ pevent->bprint_buf_field = field;
+ pevent->bprint_ip_field = ip_field;
+ }
+
+ ip = pevent_read_number(pevent, data + ip_field->offset, ip_field->size);
+
+ /*
+ * The first arg is the IP pointer.
+ */
+ args = alloc_arg();
+ arg = args;
+ arg->next = NULL;
+ next = &arg->next;
+
+ arg->type = PRINT_ATOM;
+ arg->atom.atom = malloc_or_die(32);
+ sprintf(arg->atom.atom, "%lld", ip);
+
+ /* skip the first "%pf : " */
+ for (ptr = fmt + 6, bptr = data + field->offset;
+ bptr < data + size && *ptr; ptr++) {
+ int ls = 0;
+
+ if (*ptr == '%') {
+ process_again:
+ ptr++;
+ switch (*ptr) {
+ case '%':
+ break;
+ case 'l':
+ ls++;
+ goto process_again;
+ case 'L':
+ ls = 2;
+ goto process_again;
+ case '0' ... '9':
+ goto process_again;
+ case 'p':
+ ls = 1;
+ /* fall through */
+ case 'd':
+ case 'u':
+ case 'x':
+ case 'i':
+ /* the pointers are always 4 bytes aligned */
+ bptr = (void *)(((unsigned long)bptr + 3) &
+ ~3);
+ switch (ls) {
+ case 0:
+ ls = 4;
+ break;
+ case 1:
+ ls = pevent->long_size;
+ break;
+ case 2:
+ ls = 8;
+ default:
+ break;
+ }
+ val = pevent_read_number(pevent, bptr, ls);
+ bptr += ls;
+ arg = alloc_arg();
+ arg->next = NULL;
+ arg->type = PRINT_ATOM;
+ arg->atom.atom = malloc_or_die(32);
+ sprintf(arg->atom.atom, "%lld", val);
+ *next = arg;
+ next = &arg->next;
+ break;
+ case 's':
+ arg = alloc_arg();
+ arg->next = NULL;
+ arg->type = PRINT_BSTRING;
+ arg->string.string = strdup(bptr);
+ bptr += strlen(bptr) + 1;
+ *next = arg;
+ next = &arg->next;
+ default:
+ break;
+ }
+ }
+ }
+
+ return args;
+}
+
+static void free_args(struct print_arg *args)
+{
+ struct print_arg *next;
+
+ while (args) {
+ next = args->next;
+
+ free_arg(args);
+ args = next;
+ }
+}
+
+static char *
+get_bprint_format(void *data, int size __unused, struct event_format *event)
+{
+ struct pevent *pevent = event->pevent;
+ unsigned long long addr;
+ struct format_field *field;
+ struct printk_map *printk;
+ char *format;
+ char *p;
+
+ field = pevent->bprint_fmt_field;
+
+ if (!field) {
+ field = pevent_find_field(event, "fmt");
+ if (!field)
+ die("can't find format field for binary printk");
+ pevent->bprint_fmt_field = field;
+ }
+
+ addr = pevent_read_number(pevent, data + field->offset, field->size);
+
+ printk = find_printk(pevent, addr);
+ if (!printk) {
+ format = malloc_or_die(45);
+ sprintf(format, "%%pf : (NO FORMAT FOUND at %llx)\n",
+ addr);
+ return format;
+ }
+
+ p = printk->printk;
+ /* Remove any quotes. */
+ if (*p == '"')
+ p++;
+ format = malloc_or_die(strlen(p) + 10);
+ sprintf(format, "%s : %s", "%pf", p);
+ /* remove ending quotes and new line since we will add one too */
+ p = format + strlen(format) - 1;
+ if (*p == '"')
+ *p = 0;
+
+ p -= 2;
+ if (strcmp(p, "\\n") == 0)
+ *p = 0;
+
+ return format;
+}
+
+static void print_mac_arg(struct trace_seq *s, int mac, void *data, int size,
+ struct event_format *event, struct print_arg *arg)
+{
+ unsigned char *buf;
+ char *fmt = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x";
+
+ if (arg->type == PRINT_FUNC) {
+ process_defined_func(s, data, size, event, arg);
+ return;
+ }
+
+ if (arg->type != PRINT_FIELD) {
+ trace_seq_printf(s, "ARG TYPE NOT FIELD BUT %d",
+ arg->type);
+ return;
+ }
+
+ if (mac == 'm')
+ fmt = "%.2x%.2x%.2x%.2x%.2x%.2x";
+ if (!arg->field.field) {
+ arg->field.field =
+ pevent_find_any_field(event, arg->field.name);
+ if (!arg->field.field)
+ die("field %s not found", arg->field.name);
+ }
+ if (arg->field.field->size != 6) {
+ trace_seq_printf(s, "INVALIDMAC");
+ return;
+ }
+ buf = data + arg->field.field->offset;
+ trace_seq_printf(s, fmt, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
+}
+
+static void print_event_fields(struct trace_seq *s, void *data, int size,
+ struct event_format *event)
+{
+ struct format_field *field;
+ unsigned long long val;
+ unsigned int offset, len, i;
+
+ field = event->format.fields;
+ while (field) {
+ trace_seq_printf(s, " %s=", field->name);
+ if (field->flags & FIELD_IS_ARRAY) {
+ offset = field->offset;
+ len = field->size;
+ if (field->flags & FIELD_IS_DYNAMIC) {
+ val = pevent_read_number(event->pevent, data + offset, len);
+ offset = val;
+ len = offset >> 16;
+ offset &= 0xffff;
+ }
+ if (field->flags & FIELD_IS_STRING) {
+ trace_seq_printf(s, "%s", (char *)data + offset);
+ } else {
+ trace_seq_puts(s, "ARRAY[");
+ for (i = 0; i < len; i++) {
+ if (i)
+ trace_seq_puts(s, ", ");
+ trace_seq_printf(s, "%02x",
+ *((unsigned char *)data + offset + i));
+ }
+ trace_seq_putc(s, ']');
+ }
+ } else {
+ val = pevent_read_number(event->pevent, data + field->offset,
+ field->size);
+ if (field->flags & FIELD_IS_POINTER) {
+ trace_seq_printf(s, "0x%llx", val);
+ } else if (field->flags & FIELD_IS_SIGNED) {
+ switch (field->size) {
+ case 4:
+ /*
+ * If field is long then print it in hex.
+ * A long usually stores pointers.
+ */
+ if (field->flags & FIELD_IS_LONG)
+ trace_seq_printf(s, "0x%x", (int)val);
+ else
+ trace_seq_printf(s, "%d", (int)val);
+ break;
+ case 2:
+ trace_seq_printf(s, "%2d", (short)val);
+ break;
+ case 1:
+ trace_seq_printf(s, "%1d", (char)val);
+ break;
+ default:
+ trace_seq_printf(s, "%lld", val);
+ }
+ } else {
+ if (field->flags & FIELD_IS_LONG)
+ trace_seq_printf(s, "0x%llx", val);
+ else
+ trace_seq_printf(s, "%llu", val);
+ }
+ }
+ field = field->next;
+ }
+}
+
+static void pretty_print(struct trace_seq *s, void *data, int size, struct event_format *event)
+{
+ struct pevent *pevent = event->pevent;
+ struct print_fmt *print_fmt = &event->print_fmt;
+ struct print_arg *arg = print_fmt->args;
+ struct print_arg *args = NULL;
+ const char *ptr = print_fmt->format;
+ unsigned long long val;
+ struct func_map *func;
+ const char *saveptr;
+ char *bprint_fmt = NULL;
+ char format[32];
+ int show_func;
+ int len_as_arg;
+ int len_arg;
+ int len;
+ int ls;
+
+ if (event->flags & EVENT_FL_FAILED) {
+ trace_seq_printf(s, "[FAILED TO PARSE]");
+ print_event_fields(s, data, size, event);
+ return;
+ }
+
+ if (event->flags & EVENT_FL_ISBPRINT) {
+ bprint_fmt = get_bprint_format(data, size, event);
+ args = make_bprint_args(bprint_fmt, data, size, event);
+ arg = args;
+ ptr = bprint_fmt;
+ }
+
+ for (; *ptr; ptr++) {
+ ls = 0;
+ if (*ptr == '\\') {
+ ptr++;
+ switch (*ptr) {
+ case 'n':
+ trace_seq_putc(s, '\n');
+ break;
+ case 't':
+ trace_seq_putc(s, '\t');
+ break;
+ case 'r':
+ trace_seq_putc(s, '\r');
+ break;
+ case '\\':
+ trace_seq_putc(s, '\\');
+ break;
+ default:
+ trace_seq_putc(s, *ptr);
+ break;
+ }
+
+ } else if (*ptr == '%') {
+ saveptr = ptr;
+ show_func = 0;
+ len_as_arg = 0;
+ cont_process:
+ ptr++;
+ switch (*ptr) {
+ case '%':
+ trace_seq_putc(s, '%');
+ break;
+ case '#':
+ /* FIXME: need to handle properly */
+ goto cont_process;
+ case 'h':
+ ls--;
+ goto cont_process;
+ case 'l':
+ ls++;
+ goto cont_process;
+ case 'L':
+ ls = 2;
+ goto cont_process;
+ case '*':
+ /* The argument is the length. */
+ if (!arg)
+ die("no argument match");
+ len_arg = eval_num_arg(data, size, event, arg);
+ len_as_arg = 1;
+ arg = arg->next;
+ goto cont_process;
+ case '.':
+ case 'z':
+ case 'Z':
+ case '0' ... '9':
+ goto cont_process;
+ case 'p':
+ if (pevent->long_size == 4)
+ ls = 1;
+ else
+ ls = 2;
+
+ if (*(ptr+1) == 'F' ||
+ *(ptr+1) == 'f') {
+ ptr++;
+ show_func = *ptr;
+ } else if (*(ptr+1) == 'M' || *(ptr+1) == 'm') {
+ print_mac_arg(s, *(ptr+1), data, size, event, arg);
+ ptr++;
+ break;
+ }
+
+ /* fall through */
+ case 'd':
+ case 'i':
+ case 'x':
+ case 'X':
+ case 'u':
+ if (!arg)
+ die("no argument match");
+
+ len = ((unsigned long)ptr + 1) -
+ (unsigned long)saveptr;
+
+ /* should never happen */
+ if (len > 31)
+ die("bad format!");
+
+ memcpy(format, saveptr, len);
+ format[len] = 0;
+
+ val = eval_num_arg(data, size, event, arg);
+ arg = arg->next;
+
+ if (show_func) {
+ func = find_func(pevent, val);
+ if (func) {
+ trace_seq_puts(s, func->func);
+ if (show_func == 'F')
+ trace_seq_printf(s,
+ "+0x%llx",
+ val - func->addr);
+ break;
+ }
+ }
+ if (pevent->long_size == 8 && ls) {
+ char *p;
+
+ ls = 2;
+ /* make %l into %ll */
+ p = strchr(format, 'l');
+ if (p)
+ memmove(p, p+1, strlen(p)+1);
+ else if (strcmp(format, "%p") == 0)
+ strcpy(format, "0x%llx");
+ }
+ switch (ls) {
+ case -2:
+ if (len_as_arg)
+ trace_seq_printf(s, format, len_arg, (char)val);
+ else
+ trace_seq_printf(s, format, (char)val);
+ break;
+ case -1:
+ if (len_as_arg)
+ trace_seq_printf(s, format, len_arg, (short)val);
+ else
+ trace_seq_printf(s, format, (short)val);
+ break;
+ case 0:
+ if (len_as_arg)
+ trace_seq_printf(s, format, len_arg, (int)val);
+ else
+ trace_seq_printf(s, format, (int)val);
+ break;
+ case 1:
+ if (len_as_arg)
+ trace_seq_printf(s, format, len_arg, (long)val);
+ else
+ trace_seq_printf(s, format, (long)val);
+ break;
+ case 2:
+ if (len_as_arg)
+ trace_seq_printf(s, format, len_arg,
+ (long long)val);
+ else
+ trace_seq_printf(s, format, (long long)val);
+ break;
+ default:
+ die("bad count (%d)", ls);
+ }
+ break;
+ case 's':
+ if (!arg)
+ die("no matching argument");
+
+ len = ((unsigned long)ptr + 1) -
+ (unsigned long)saveptr;
+
+ /* should never happen */
+ if (len > 31)
+ die("bad format!");
+
+ memcpy(format, saveptr, len);
+ format[len] = 0;
+ if (!len_as_arg)
+ len_arg = -1;
+ print_str_arg(s, data, size, event,
+ format, len_arg, arg);
+ arg = arg->next;
+ break;
+ default:
+ trace_seq_printf(s, ">%c<", *ptr);
+
+ }
+ } else
+ trace_seq_putc(s, *ptr);
+ }
+
+ if (args) {
+ free_args(args);
+ free(bprint_fmt);
+ }
+}
+
+/**
+ * pevent_data_lat_fmt - parse the data for the latency format
+ * @pevent: a handle to the pevent
+ * @s: the trace_seq to write to
+ * @data: the raw data to read from
+ * @size: currently unused.
+ *
+ * This parses out the Latency format (interrupts disabled,
+ * need rescheduling, in hard/soft interrupt, preempt count
+ * and lock depth) and places it into the trace_seq.
+ */
+void pevent_data_lat_fmt(struct pevent *pevent,
+ struct trace_seq *s, struct pevent_record *record)
+{
+ static int check_lock_depth = 1;
+ static int lock_depth_exists;
+ unsigned int lat_flags;
+ unsigned int pc;
+ int lock_depth;
+ int hardirq;
+ int softirq;
+ void *data = record->data;
+
+ lat_flags = parse_common_flags(pevent, data);
+ pc = parse_common_pc(pevent, data);
+ /* lock_depth may not always exist */
+ if (check_lock_depth) {
+ struct format_field *field;
+ struct event_format *event;
+
+ check_lock_depth = 0;
+ event = pevent->events[0];
+ field = pevent_find_common_field(event, "common_lock_depth");
+ if (field)
+ lock_depth_exists = 1;
+ }
+ if (lock_depth_exists)
+ lock_depth = parse_common_lock_depth(pevent, data);
+
+ hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
+ softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
+
+ trace_seq_printf(s, "%c%c%c",
+ (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
+ (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
+ 'X' : '.',
+ (lat_flags & TRACE_FLAG_NEED_RESCHED) ?
+ 'N' : '.',
+ (hardirq && softirq) ? 'H' :
+ hardirq ? 'h' : softirq ? 's' : '.');
+
+ if (pc)
+ trace_seq_printf(s, "%x", pc);
+ else
+ trace_seq_putc(s, '.');
+
+ if (lock_depth_exists) {
+ if (lock_depth < 0)
+ trace_seq_putc(s, '.');
+ else
+ trace_seq_printf(s, "%d", lock_depth);
+ }
+
+ trace_seq_terminate(s);
+}
+
+/**
+ * pevent_data_type - parse out the given event type
+ * @pevent: a handle to the pevent
+ * @rec: the record to read from
+ *
+ * This returns the event id from the @rec.
+ */
+int pevent_data_type(struct pevent *pevent, struct pevent_record *rec)
+{
+ return trace_parse_common_type(pevent, rec->data);
+}
+
+/**
+ * pevent_data_event_from_type - find the event by a given type
+ * @pevent: a handle to the pevent
+ * @type: the type of the event.
+ *
+ * This returns the event form a given @type;
+ */
+struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type)
+{
+ return pevent_find_event(pevent, type);
+}
+
+/**
+ * pevent_data_pid - parse the PID from raw data
+ * @pevent: a handle to the pevent
+ * @rec: the record to parse
+ *
+ * This returns the PID from a raw data.
+ */
+int pevent_data_pid(struct pevent *pevent, struct pevent_record *rec)
+{
+ return parse_common_pid(pevent, rec->data);
+}
+
+/**
+ * pevent_data_comm_from_pid - return the command line from PID
+ * @pevent: a handle to the pevent
+ * @pid: the PID of the task to search for
+ *
+ * This returns a pointer to the command line that has the given
+ * @pid.
+ */
+const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid)
+{
+ const char *comm;
+
+ comm = find_cmdline(pevent, pid);
+ return comm;
+}
+
+/**
+ * pevent_data_comm_from_pid - parse the data into the print format
+ * @s: the trace_seq to write to
+ * @event: the handle to the event
+ * @cpu: the cpu the event was recorded on
+ * @data: the raw data
+ * @size: the size of the raw data
+ * @nsecs: the timestamp of the event
+ *
+ * This parses the raw @data using the given @event information and
+ * writes the print format into the trace_seq.
+ */
+void pevent_event_info(struct trace_seq *s, struct event_format *event,
+ struct pevent_record *record)
+{
+ int print_pretty = 1;
+
+ if (event->pevent->print_raw)
+ print_event_fields(s, record->data, record->size, event);
+ else {
+
+ if (event->handler)
+ print_pretty = event->handler(s, record, event,
+ event->context);
+
+ if (print_pretty)
+ pretty_print(s, record->data, record->size, event);
+ }
+
+ trace_seq_terminate(s);
+}
+
+void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
+ struct pevent_record *record)
+{
+ static char *spaces = " "; /* 20 spaces */
+ struct event_format *event;
+ unsigned long secs;
+ unsigned long usecs;
+ unsigned long nsecs;
+ const char *comm;
+ void *data = record->data;
+ int type;
+ int pid;
+ int len;
+ int p;
+
+ secs = record->ts / NSECS_PER_SEC;
+ nsecs = record->ts - secs * NSECS_PER_SEC;
+
+ if (record->size < 0) {
+ do_warning("ug! negative record size %d", record->size);
+ return;
+ }
+
+ type = trace_parse_common_type(pevent, data);
+
+ event = pevent_find_event(pevent, type);
+ if (!event) {
+ do_warning("ug! no event found for type %d", type);
+ return;
+ }
+
+ pid = parse_common_pid(pevent, data);
+ comm = find_cmdline(pevent, pid);
+
+ if (pevent->latency_format) {
+ trace_seq_printf(s, "%8.8s-%-5d %3d",
+ comm, pid, record->cpu);
+ pevent_data_lat_fmt(pevent, s, record);
+ } else
+ trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu);
+
+ if (pevent->flags & PEVENT_NSEC_OUTPUT) {
+ usecs = nsecs;
+ p = 9;
+ } else {
+ usecs = (nsecs + 500) / NSECS_PER_USEC;
+ p = 6;
+ }
+
+ trace_seq_printf(s, " %5lu.%0*lu: %s: ", secs, p, usecs, event->name);
+
+ /* Space out the event names evenly. */
+ len = strlen(event->name);
+ if (len < 20)
+ trace_seq_printf(s, "%.*s", 20 - len, spaces);
+
+ pevent_event_info(s, event, record);
+}
+
+static int events_id_cmp(const void *a, const void *b)
+{
+ struct event_format * const * ea = a;
+ struct event_format * const * eb = b;
+
+ if ((*ea)->id < (*eb)->id)
+ return -1;
+
+ if ((*ea)->id > (*eb)->id)
+ return 1;
+
+ return 0;
+}
+
+static int events_name_cmp(const void *a, const void *b)
+{
+ struct event_format * const * ea = a;
+ struct event_format * const * eb = b;
+ int res;
+
+ res = strcmp((*ea)->name, (*eb)->name);
+ if (res)
+ return res;
+
+ res = strcmp((*ea)->system, (*eb)->system);
+ if (res)
+ return res;
+
+ return events_id_cmp(a, b);
+}
+
+static int events_system_cmp(const void *a, const void *b)
+{
+ struct event_format * const * ea = a;
+ struct event_format * const * eb = b;
+ int res;
+
+ res = strcmp((*ea)->system, (*eb)->system);
+ if (res)
+ return res;
+
+ res = strcmp((*ea)->name, (*eb)->name);
+ if (res)
+ return res;
+
+ return events_id_cmp(a, b);
+}
+
+struct event_format **pevent_list_events(struct pevent *pevent, enum event_sort_type sort_type)
+{
+ struct event_format **events;
+ int (*sort)(const void *a, const void *b);
+
+ events = pevent->sort_events;
+
+ if (events && pevent->last_type == sort_type)
+ return events;
+
+ if (!events) {
+ events = malloc(sizeof(*events) * (pevent->nr_events + 1));
+ if (!events)
+ return NULL;
+
+ memcpy(events, pevent->events, sizeof(*events) * pevent->nr_events);
+ events[pevent->nr_events] = NULL;
+
+ pevent->sort_events = events;
+
+ /* the internal events are sorted by id */
+ if (sort_type == EVENT_SORT_ID) {
+ pevent->last_type = sort_type;
+ return events;
+ }
+ }
+
+ switch (sort_type) {
+ case EVENT_SORT_ID:
+ sort = events_id_cmp;
+ break;
+ case EVENT_SORT_NAME:
+ sort = events_name_cmp;
+ break;
+ case EVENT_SORT_SYSTEM:
+ sort = events_system_cmp;
+ break;
+ default:
+ return events;
+ }
+
+ qsort(events, pevent->nr_events, sizeof(*events), sort);
+ pevent->last_type = sort_type;
+
+ return events;
+}
+
+static struct format_field **
+get_event_fields(const char *type, const char *name,
+ int count, struct format_field *list)
+{
+ struct format_field **fields;
+ struct format_field *field;
+ int i = 0;
+
+ fields = malloc_or_die(sizeof(*fields) * (count + 1));
+ for (field = list; field; field = field->next) {
+ fields[i++] = field;
+ if (i == count + 1) {
+ do_warning("event %s has more %s fields than specified",
+ name, type);
+ i--;
+ break;
+ }
+ }
+
+ if (i != count)
+ do_warning("event %s has less %s fields than specified",
+ name, type);
+
+ fields[i] = NULL;
+
+ return fields;
+}
+
+/**
+ * pevent_event_common_fields - return a list of common fields for an event
+ * @event: the event to return the common fields of.
+ *
+ * Returns an allocated array of fields. The last item in the array is NULL.
+ * The array must be freed with free().
+ */
+struct format_field **pevent_event_common_fields(struct event_format *event)
+{
+ return get_event_fields("common", event->name,
+ event->format.nr_common,
+ event->format.common_fields);
+}
+
+/**
+ * pevent_event_fields - return a list of event specific fields for an event
+ * @event: the event to return the fields of.
+ *
+ * Returns an allocated array of fields. The last item in the array is NULL.
+ * The array must be freed with free().
+ */
+struct format_field **pevent_event_fields(struct event_format *event)
+{
+ return get_event_fields("event", event->name,
+ event->format.nr_fields,
+ event->format.fields);
+}
+
+static void print_fields(struct trace_seq *s, struct print_flag_sym *field)
+{
+ trace_seq_printf(s, "{ %s, %s }", field->value, field->str);
+ if (field->next) {
+ trace_seq_puts(s, ", ");
+ print_fields(s, field->next);
+ }
+}
+
+/* for debugging */
+static void print_args(struct print_arg *args)
+{
+ int print_paren = 1;
+ struct trace_seq s;
+
+ switch (args->type) {
+ case PRINT_NULL:
+ printf("null");
+ break;
+ case PRINT_ATOM:
+ printf("%s", args->atom.atom);
+ break;
+ case PRINT_FIELD:
+ printf("REC->%s", args->field.name);
+ break;
+ case PRINT_FLAGS:
+ printf("__print_flags(");
+ print_args(args->flags.field);
+ printf(", %s, ", args->flags.delim);
+ trace_seq_init(&s);
+ print_fields(&s, args->flags.flags);
+ trace_seq_do_printf(&s);
+ trace_seq_destroy(&s);
+ printf(")");
+ break;
+ case PRINT_SYMBOL:
+ printf("__print_symbolic(");
+ print_args(args->symbol.field);
+ printf(", ");
+ trace_seq_init(&s);
+ print_fields(&s, args->symbol.symbols);
+ trace_seq_do_printf(&s);
+ trace_seq_destroy(&s);
+ printf(")");
+ break;
+ case PRINT_STRING:
+ case PRINT_BSTRING:
+ printf("__get_str(%s)", args->string.string);
+ break;
+ case PRINT_TYPE:
+ printf("(%s)", args->typecast.type);
+ print_args(args->typecast.item);
+ break;
+ case PRINT_OP:
+ if (strcmp(args->op.op, ":") == 0)
+ print_paren = 0;
+ if (print_paren)
+ printf("(");
+ print_args(args->op.left);
+ printf(" %s ", args->op.op);
+ print_args(args->op.right);
+ if (print_paren)
+ printf(")");
+ break;
+ default:
+ /* we should warn... */
+ return;
+ }
+ if (args->next) {
+ printf("\n");
+ print_args(args->next);
+ }
+}
+
+static void parse_header_field(const char *field,
+ int *offset, int *size, int mandatory)
+{
+ unsigned long long save_input_buf_ptr;
+ unsigned long long save_input_buf_siz;
+ char *token;
+ int type;
+
+ save_input_buf_ptr = input_buf_ptr;
+ save_input_buf_siz = input_buf_siz;
+
+ if (read_expected(EVENT_ITEM, "field") < 0)
+ return;
+ if (read_expected(EVENT_OP, ":") < 0)
+ return;
+
+ /* type */
+ if (read_expect_type(EVENT_ITEM, &token) < 0)
+ goto fail;
+ free_token(token);
+
+ /*
+ * If this is not a mandatory field, then test it first.
+ */
+ if (mandatory) {
+ if (read_expected(EVENT_ITEM, field) < 0)
+ return;
+ } else {
+ if (read_expect_type(EVENT_ITEM, &token) < 0)
+ goto fail;
+ if (strcmp(token, field) != 0)
+ goto discard;
+ free_token(token);
+ }
+
+ if (read_expected(EVENT_OP, ";") < 0)
+ return;
+ if (read_expected(EVENT_ITEM, "offset") < 0)
+ return;
+ if (read_expected(EVENT_OP, ":") < 0)
+ return;
+ if (read_expect_type(EVENT_ITEM, &token) < 0)
+ goto fail;
+ *offset = atoi(token);
+ free_token(token);
+ if (read_expected(EVENT_OP, ";") < 0)
+ return;
+ if (read_expected(EVENT_ITEM, "size") < 0)
+ return;
+ if (read_expected(EVENT_OP, ":") < 0)
+ return;
+ if (read_expect_type(EVENT_ITEM, &token) < 0)
+ goto fail;
+ *size = atoi(token);
+ free_token(token);
+ if (read_expected(EVENT_OP, ";") < 0)
+ return;
+ type = read_token(&token);
+ if (type != EVENT_NEWLINE) {
+ /* newer versions of the kernel have a "signed" type */
+ if (type != EVENT_ITEM)
+ goto fail;
+
+ if (strcmp(token, "signed") != 0)
+ goto fail;
+
+ free_token(token);
+
+ if (read_expected(EVENT_OP, ":") < 0)
+ return;
+
+ if (read_expect_type(EVENT_ITEM, &token))
+ goto fail;
+
+ free_token(token);
+ if (read_expected(EVENT_OP, ";") < 0)
+ return;
+
+ if (read_expect_type(EVENT_NEWLINE, &token))
+ goto fail;
+ }
+ fail:
+ free_token(token);
+ return;
+
+ discard:
+ input_buf_ptr = save_input_buf_ptr;
+ input_buf_siz = save_input_buf_siz;
+ *offset = 0;
+ *size = 0;
+ free_token(token);
+}
+
+/**
+ * pevent_parse_header_page - parse the data stored in the header page
+ * @pevent: the handle to the pevent
+ * @buf: the buffer storing the header page format string
+ * @size: the size of @buf
+ * @long_size: the long size to use if there is no header
+ *
+ * This parses the header page format for information on the
+ * ring buffer used. The @buf should be copied from
+ *
+ * /sys/kernel/debug/tracing/events/header_page
+ */
+int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size,
+ int long_size)
+{
+ int ignore;
+
+ if (!size) {
+ /*
+ * Old kernels did not have header page info.
+ * Sorry but we just use what we find here in user space.
+ */
+ pevent->header_page_ts_size = sizeof(long long);
+ pevent->header_page_size_size = long_size;
+ pevent->header_page_data_offset = sizeof(long long) + long_size;
+ pevent->old_format = 1;
+ return -1;
+ }
+ init_input_buf(buf, size);
+
+ parse_header_field("timestamp", &pevent->header_page_ts_offset,
+ &pevent->header_page_ts_size, 1);
+ parse_header_field("commit", &pevent->header_page_size_offset,
+ &pevent->header_page_size_size, 1);
+ parse_header_field("overwrite", &pevent->header_page_overwrite,
+ &ignore, 0);
+ parse_header_field("data", &pevent->header_page_data_offset,
+ &pevent->header_page_data_size, 1);
+
+ return 0;
+}
+
+static int event_matches(struct event_format *event,
+ int id, const char *sys_name,
+ const char *event_name)
+{
+ if (id >= 0 && id != event->id)
+ return 0;
+
+ if (event_name && (strcmp(event_name, event->name) != 0))
+ return 0;
+
+ if (sys_name && (strcmp(sys_name, event->system) != 0))
+ return 0;
+
+ return 1;
+}
+
+static void free_handler(struct event_handler *handle)
+{
+ free((void *)handle->sys_name);
+ free((void *)handle->event_name);
+ free(handle);
+}
+
+static int find_event_handle(struct pevent *pevent, struct event_format *event)
+{
+ struct event_handler *handle, **next;
+
+ for (next = &pevent->handlers; *next;
+ next = &(*next)->next) {
+ handle = *next;
+ if (event_matches(event, handle->id,
+ handle->sys_name,
+ handle->event_name))
+ break;
+ }
+
+ if (!(*next))
+ return 0;
+
+ pr_stat("overriding event (%d) %s:%s with new print handler",
+ event->id, event->system, event->name);
+
+ event->handler = handle->func;
+ event->context = handle->context;
+
+ *next = handle->next;
+ free_handler(handle);
+
+ return 1;
+}
+
+/**
+ * pevent_parse_event - parse the event format
+ * @pevent: the handle to the pevent
+ * @buf: the buffer storing the event format string
+ * @size: the size of @buf
+ * @sys: the system the event belongs to
+ *
+ * This parses the event format and creates an event structure
+ * to quickly parse raw data for a given event.
+ *
+ * These files currently come from:
+ *
+ * /sys/kernel/debug/tracing/events/.../.../format
+ */
+int pevent_parse_event(struct pevent *pevent,
+ const char *buf, unsigned long size,
+ const char *sys)
+{
+ struct event_format *event;
+ int ret;
+
+ init_input_buf(buf, size);
+
+ event = alloc_event();
+ if (!event)
+ return -ENOMEM;
+
+ event->name = event_read_name();
+ if (!event->name) {
+ /* Bad event? */
+ free(event);
+ return -1;
+ }
+
+ if (strcmp(sys, "ftrace") == 0) {
+
+ event->flags |= EVENT_FL_ISFTRACE;
+
+ if (strcmp(event->name, "bprint") == 0)
+ event->flags |= EVENT_FL_ISBPRINT;
+ }
+
+ event->id = event_read_id();
+ if (event->id < 0)
+ die("failed to read event id");
+
+ event->system = strdup(sys);
+
+ /* Add pevent to event so that it can be referenced */
+ event->pevent = pevent;
+
+ ret = event_read_format(event);
+ if (ret < 0) {
+ do_warning("failed to read event format for %s", event->name);
+ goto event_failed;
+ }
+
+ /*
+ * If the event has an override, don't print warnings if the event
+ * print format fails to parse.
+ */
+ if (find_event_handle(pevent, event))
+ show_warning = 0;
+
+ ret = event_read_print(event);
+ if (ret < 0) {
+ do_warning("failed to read event print fmt for %s",
+ event->name);
+ show_warning = 1;
+ goto event_failed;
+ }
+ show_warning = 1;
+
+ add_event(pevent, event);
+
+ if (!ret && (event->flags & EVENT_FL_ISFTRACE)) {
+ struct format_field *field;
+ struct print_arg *arg, **list;
+
+ /* old ftrace had no args */
+
+ list = &event->print_fmt.args;
+ for (field = event->format.fields; field; field = field->next) {
+ arg = alloc_arg();
+ *list = arg;
+ list = &arg->next;
+ arg->type = PRINT_FIELD;
+ arg->field.name = strdup(field->name);
+ arg->field.field = field;
+ }
+ return 0;
+ }
+
+#define PRINT_ARGS 0
+ if (PRINT_ARGS && event->print_fmt.args)
+ print_args(event->print_fmt.args);
+
+ return 0;
+
+ event_failed:
+ event->flags |= EVENT_FL_FAILED;
+ /* still add it even if it failed */
+ add_event(pevent, event);
+ return -1;
+}
+
+int get_field_val(struct trace_seq *s, struct format_field *field,
+ const char *name, struct pevent_record *record,
+ unsigned long long *val, int err)
+{
+ if (!field) {
+ if (err)
+ trace_seq_printf(s, "<CANT FIND FIELD %s>", name);
+ return -1;
+ }
+
+ if (pevent_read_number_field(field, record->data, val)) {
+ if (err)
+ trace_seq_printf(s, " %s=INVALID", name);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * pevent_get_field_raw - return the raw pointer into the data field
+ * @s: The seq to print to on error
+ * @event: the event that the field is for
+ * @name: The name of the field
+ * @record: The record with the field name.
+ * @len: place to store the field length.
+ * @err: print default error if failed.
+ *
+ * Returns a pointer into record->data of the field and places
+ * the length of the field in @len.
+ *
+ * On failure, it returns NULL.
+ */
+void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event,
+ const char *name, struct pevent_record *record,
+ int *len, int err)
+{
+ struct format_field *field;
+ void *data = record->data;
+ unsigned offset;
+ int dummy;
+
+ if (!event)
+ return NULL;
+
+ field = pevent_find_field(event, name);
+
+ if (!field) {
+ if (err)
+ trace_seq_printf(s, "<CANT FIND FIELD %s>", name);
+ return NULL;
+ }
+
+ /* Allow @len to be NULL */
+ if (!len)
+ len = &dummy;
+
+ offset = field->offset;
+ if (field->flags & FIELD_IS_DYNAMIC) {
+ offset = pevent_read_number(event->pevent,
+ data + offset, field->size);
+ *len = offset >> 16;
+ offset &= 0xffff;
+ } else
+ *len = field->size;
+
+ return data + offset;
+}
+
+/**
+ * pevent_get_field_val - find a field and return its value
+ * @s: The seq to print to on error
+ * @event: the event that the field is for
+ * @name: The name of the field
+ * @record: The record with the field name.
+ * @val: place to store the value of the field.
+ * @err: print default error if failed.
+ *
+ * Returns 0 on success -1 on field not found.
+ */
+int pevent_get_field_val(struct trace_seq *s, struct event_format *event,
+ const char *name, struct pevent_record *record,
+ unsigned long long *val, int err)
+{
+ struct format_field *field;
+
+ if (!event)
+ return -1;
+
+ field = pevent_find_field(event, name);
+
+ return get_field_val(s, field, name, record, val, err);
+}
+
+/**
+ * pevent_get_common_field_val - find a common field and return its value
+ * @s: The seq to print to on error
+ * @event: the event that the field is for
+ * @name: The name of the field
+ * @record: The record with the field name.
+ * @val: place to store the value of the field.
+ * @err: print default error if failed.
+ *
+ * Returns 0 on success -1 on field not found.
+ */
+int pevent_get_common_field_val(struct trace_seq *s, struct event_format *event,
+ const char *name, struct pevent_record *record,
+ unsigned long long *val, int err)
+{
+ struct format_field *field;
+
+ if (!event)
+ return -1;
+
+ field = pevent_find_common_field(event, name);
+
+ return get_field_val(s, field, name, record, val, err);
+}
+
+/**
+ * pevent_get_any_field_val - find a any field and return its value
+ * @s: The seq to print to on error
+ * @event: the event that the field is for
+ * @name: The name of the field
+ * @record: The record with the field name.
+ * @val: place to store the value of the field.
+ * @err: print default error if failed.
+ *
+ * Returns 0 on success -1 on field not found.
+ */
+int pevent_get_any_field_val(struct trace_seq *s, struct event_format *event,
+ const char *name, struct pevent_record *record,
+ unsigned long long *val, int err)
+{
+ struct format_field *field;
+
+ if (!event)
+ return -1;
+
+ field = pevent_find_any_field(event, name);
+
+ return get_field_val(s, field, name, record, val, err);
+}
+
+/**
+ * pevent_print_num_field - print a field and a format
+ * @s: The seq to print to
+ * @fmt: The printf format to print the field with.
+ * @event: the event that the field is for
+ * @name: The name of the field
+ * @record: The record with the field name.
+ * @err: print default error if failed.
+ *
+ * Returns: 0 on success, -1 field not fould, or 1 if buffer is full.
+ */
+int pevent_print_num_field(struct trace_seq *s, const char *fmt,
+ struct event_format *event, const char *name,
+ struct pevent_record *record, int err)
+{
+ struct format_field *field = pevent_find_field(event, name);
+ unsigned long long val;
+
+ if (!field)
+ goto failed;
+
+ if (pevent_read_number_field(field, record->data, &val))
+ goto failed;
+
+ return trace_seq_printf(s, fmt, val);
+
+ failed:
+ if (err)
+ trace_seq_printf(s, "CAN'T FIND FIELD \"%s\"", name);
+ return -1;
+}
+
+static void free_func_handle(struct pevent_function_handler *func)
+{
+ struct pevent_func_params *params;
+
+ free(func->name);
+
+ while (func->params) {
+ params = func->params;
+ func->params = params->next;
+ free(params);
+ }
+
+ free(func);
+}
+
+/**
+ * pevent_register_print_function - register a helper function
+ * @pevent: the handle to the pevent
+ * @func: the function to process the helper function
+ * @name: the name of the helper function
+ * @parameters: A list of enum pevent_func_arg_type
+ *
+ * Some events may have helper functions in the print format arguments.
+ * This allows a plugin to dynmically create a way to process one
+ * of these functions.
+ *
+ * The @parameters is a variable list of pevent_func_arg_type enums that
+ * must end with PEVENT_FUNC_ARG_VOID.
+ */
+int pevent_register_print_function(struct pevent *pevent,
+ pevent_func_handler func,
+ enum pevent_func_arg_type ret_type,
+ char *name, ...)
+{
+ struct pevent_function_handler *func_handle;
+ struct pevent_func_params **next_param;
+ struct pevent_func_params *param;
+ enum pevent_func_arg_type type;
+ va_list ap;
+
+ func_handle = find_func_handler(pevent, name);
+ if (func_handle) {
+ /*
+ * This is most like caused by the users own
+ * plugins updating the function. This overrides the
+ * system defaults.
+ */
+ pr_stat("override of function helper '%s'", name);
+ remove_func_handler(pevent, name);
+ }
+
+ func_handle = malloc_or_die(sizeof(*func_handle));
+ memset(func_handle, 0, sizeof(*func_handle));
+
+ func_handle->ret_type = ret_type;
+ func_handle->name = strdup(name);
+ func_handle->func = func;
+ if (!func_handle->name)
+ die("Failed to allocate function name");
+
+ next_param = &(func_handle->params);
+ va_start(ap, name);
+ for (;;) {
+ type = va_arg(ap, enum pevent_func_arg_type);
+ if (type == PEVENT_FUNC_ARG_VOID)
+ break;
+
+ if (type < 0 || type >= PEVENT_FUNC_ARG_MAX_TYPES) {
+ warning("Invalid argument type %d", type);
+ goto out_free;
+ }
+
+ param = malloc_or_die(sizeof(*param));
+ param->type = type;
+ param->next = NULL;
+
+ *next_param = param;
+ next_param = &(param->next);
+
+ func_handle->nr_args++;
+ }
+ va_end(ap);
+
+ func_handle->next = pevent->func_handlers;
+ pevent->func_handlers = func_handle;
+
+ return 0;
+ out_free:
+ va_end(ap);
+ free_func_handle(func_handle);
+ return -1;
+}
+
+/**
+ * pevent_register_event_handle - register a way to parse an event
+ * @pevent: the handle to the pevent
+ * @id: the id of the event to register
+ * @sys_name: the system name the event belongs to
+ * @event_name: the name of the event
+ * @func: the function to call to parse the event information
+ *
+ * This function allows a developer to override the parsing of
+ * a given event. If for some reason the default print format
+ * is not sufficient, this function will register a function
+ * for an event to be used to parse the data instead.
+ *
+ * If @id is >= 0, then it is used to find the event.
+ * else @sys_name and @event_name are used.
+ */
+int pevent_register_event_handler(struct pevent *pevent,
+ int id, char *sys_name, char *event_name,
+ pevent_event_handler_func func,
+ void *context)
+{
+ struct event_format *event;
+ struct event_handler *handle;
+
+ if (id >= 0) {
+ /* search by id */
+ event = pevent_find_event(pevent, id);
+ if (!event)
+ goto not_found;
+ if (event_name && (strcmp(event_name, event->name) != 0))
+ goto not_found;
+ if (sys_name && (strcmp(sys_name, event->system) != 0))
+ goto not_found;
+ } else {
+ event = pevent_find_event_by_name(pevent, sys_name, event_name);
+ if (!event)
+ goto not_found;
+ }
+
+ pr_stat("overriding event (%d) %s:%s with new print handler",
+ event->id, event->system, event->name);
+
+ event->handler = func;
+ event->context = context;
+ return 0;
+
+ not_found:
+ /* Save for later use. */
+ handle = malloc_or_die(sizeof(*handle));
+ memset(handle, 0, sizeof(*handle));
+ handle->id = id;
+ if (event_name)
+ handle->event_name = strdup(event_name);
+ if (sys_name)
+ handle->sys_name = strdup(sys_name);
+
+ handle->func = func;
+ handle->next = pevent->handlers;
+ pevent->handlers = handle;
+ handle->context = context;
+
+ return -1;
+}
+
+/**
+ * pevent_alloc - create a pevent handle
+ */
+struct pevent *pevent_alloc(void)
+{
+ struct pevent *pevent;
+
+ pevent = malloc(sizeof(*pevent));
+ if (!pevent)
+ return NULL;
+ memset(pevent, 0, sizeof(*pevent));
+ pevent->ref_count = 1;
+
+ return pevent;
+}
+
+void pevent_ref(struct pevent *pevent)
+{
+ pevent->ref_count++;
+}
+
+static void free_format_fields(struct format_field *field)
+{
+ struct format_field *next;
+
+ while (field) {
+ next = field->next;
+ free(field->type);
+ free(field->name);
+ free(field);
+ field = next;
+ }
+}
+
+static void free_formats(struct format *format)
+{
+ free_format_fields(format->common_fields);
+ free_format_fields(format->fields);
+}
+
+static void free_event(struct event_format *event)
+{
+ free(event->name);
+ free(event->system);
+
+ free_formats(&event->format);
+
+ free(event->print_fmt.format);
+ free_args(event->print_fmt.args);
+
+ free(event);
+}
+
+/**
+ * pevent_free - free a pevent handle
+ * @pevent: the pevent handle to free
+ */
+void pevent_free(struct pevent *pevent)
+{
+ struct cmdline_list *cmdlist, *cmdnext;
+ struct func_list *funclist, *funcnext;
+ struct printk_list *printklist, *printknext;
+ struct pevent_function_handler *func_handler;
+ struct event_handler *handle;
+ int i;
+
+ if (!pevent)
+ return;
+
+ cmdlist = pevent->cmdlist;
+ funclist = pevent->funclist;
+ printklist = pevent->printklist;
+
+ pevent->ref_count--;
+ if (pevent->ref_count)
+ return;
+
+ if (pevent->cmdlines) {
+ for (i = 0; i < pevent->cmdline_count; i++)
+ free(pevent->cmdlines[i].comm);
+ free(pevent->cmdlines);
+ }
+
+ while (cmdlist) {
+ cmdnext = cmdlist->next;
+ free(cmdlist->comm);
+ free(cmdlist);
+ cmdlist = cmdnext;
+ }
+
+ if (pevent->func_map) {
+ for (i = 0; i < pevent->func_count; i++) {
+ free(pevent->func_map[i].func);
+ free(pevent->func_map[i].mod);
+ }
+ free(pevent->func_map);
+ }
+
+ while (funclist) {
+ funcnext = funclist->next;
+ free(funclist->func);
+ free(funclist->mod);
+ free(funclist);
+ funclist = funcnext;
+ }
+
+ while (pevent->func_handlers) {
+ func_handler = pevent->func_handlers;
+ pevent->func_handlers = func_handler->next;
+ free_func_handle(func_handler);
+ }
+
+ if (pevent->printk_map) {
+ for (i = 0; i < pevent->printk_count; i++)
+ free(pevent->printk_map[i].printk);
+ free(pevent->printk_map);
+ }
+
+ while (printklist) {
+ printknext = printklist->next;
+ free(printklist->printk);
+ free(printklist);
+ printklist = printknext;
+ }
+
+ for (i = 0; i < pevent->nr_events; i++)
+ free_event(pevent->events[i]);
+
+ while (pevent->handlers) {
+ handle = pevent->handlers;
+ pevent->handlers = handle->next;
+ free_handler(handle);
+ }
+
+ free(pevent->events);
+ free(pevent->sort_events);
+
+ free(pevent);
+}
+
+void pevent_unref(struct pevent *pevent)
+{
+ pevent_free(pevent);
+}
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h
new file mode 100644
index 000000000000..ac997bc7b592
--- /dev/null
+++ b/tools/lib/traceevent/event-parse.h
@@ -0,0 +1,804 @@
+/*
+ * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License (not later!)
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#ifndef _PARSE_EVENTS_H
+#define _PARSE_EVENTS_H
+
+#include <stdarg.h>
+#include <regex.h>
+
+#ifndef __unused
+#define __unused __attribute__ ((unused))
+#endif
+
+/* ----------------------- trace_seq ----------------------- */
+
+
+#ifndef TRACE_SEQ_BUF_SIZE
+#define TRACE_SEQ_BUF_SIZE 4096
+#endif
+
+#ifndef DEBUG_RECORD
+#define DEBUG_RECORD 0
+#endif
+
+struct pevent_record {
+ unsigned long long ts;
+ unsigned long long offset;
+ long long missed_events; /* buffer dropped events before */
+ int record_size; /* size of binary record */
+ int size; /* size of data */
+ void *data;
+ int cpu;
+ int ref_count;
+ int locked; /* Do not free, even if ref_count is zero */
+ void *private;
+#if DEBUG_RECORD
+ struct pevent_record *prev;
+ struct pevent_record *next;
+ long alloc_addr;
+#endif
+};
+
+/*
+ * Trace sequences are used to allow a function to call several other functions
+ * to create a string of data to use (up to a max of PAGE_SIZE).
+ */
+
+struct trace_seq {
+ char *buffer;
+ unsigned int buffer_size;
+ unsigned int len;
+ unsigned int readpos;
+};
+
+void trace_seq_init(struct trace_seq *s);
+void trace_seq_destroy(struct trace_seq *s);
+
+extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+extern int trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
+ __attribute__ ((format (printf, 2, 0)));
+
+extern int trace_seq_puts(struct trace_seq *s, const char *str);
+extern int trace_seq_putc(struct trace_seq *s, unsigned char c);
+
+extern void trace_seq_terminate(struct trace_seq *s);
+
+extern int trace_seq_do_printf(struct trace_seq *s);
+
+
+/* ----------------------- pevent ----------------------- */
+
+struct pevent;
+struct event_format;
+
+typedef int (*pevent_event_handler_func)(struct trace_seq *s,
+ struct pevent_record *record,
+ struct event_format *event,
+ void *context);
+
+typedef int (*pevent_plugin_load_func)(struct pevent *pevent);
+typedef int (*pevent_plugin_unload_func)(void);
+
+struct plugin_option {
+ struct plugin_option *next;
+ void *handle;
+ char *file;
+ char *name;
+ char *plugin_alias;
+ char *description;
+ char *value;
+ void *private;
+ int set;
+};
+
+/*
+ * Plugin hooks that can be called:
+ *
+ * PEVENT_PLUGIN_LOADER: (required)
+ * The function name to initialized the plugin.
+ *
+ * int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
+ *
+ * PEVENT_PLUGIN_UNLOADER: (optional)
+ * The function called just before unloading
+ *
+ * int PEVENT_PLUGIN_UNLOADER(void)
+ *
+ * PEVENT_PLUGIN_OPTIONS: (optional)
+ * Plugin options that can be set before loading
+ *
+ * struct plugin_option PEVENT_PLUGIN_OPTIONS[] = {
+ * {
+ * .name = "option-name",
+ * .plugin_alias = "overide-file-name", (optional)
+ * .description = "description of option to show users",
+ * },
+ * {
+ * .name = NULL,
+ * },
+ * };
+ *
+ * Array must end with .name = NULL;
+ *
+ *
+ * .plugin_alias is used to give a shorter name to access
+ * the vairable. Useful if a plugin handles more than one event.
+ *
+ * PEVENT_PLUGIN_ALIAS: (optional)
+ * The name to use for finding options (uses filename if not defined)
+ */
+#define PEVENT_PLUGIN_LOADER pevent_plugin_loader
+#define PEVENT_PLUGIN_UNLOADER pevent_plugin_unloader
+#define PEVENT_PLUGIN_OPTIONS pevent_plugin_options
+#define PEVENT_PLUGIN_ALIAS pevent_plugin_alias
+#define _MAKE_STR(x) #x
+#define MAKE_STR(x) _MAKE_STR(x)
+#define PEVENT_PLUGIN_LOADER_NAME MAKE_STR(PEVENT_PLUGIN_LOADER)
+#define PEVENT_PLUGIN_UNLOADER_NAME MAKE_STR(PEVENT_PLUGIN_UNLOADER)
+#define PEVENT_PLUGIN_OPTIONS_NAME MAKE_STR(PEVENT_PLUGIN_OPTIONS)
+#define PEVENT_PLUGIN_ALIAS_NAME MAKE_STR(PEVENT_PLUGIN_ALIAS)
+
+#define NSECS_PER_SEC 1000000000ULL
+#define NSECS_PER_USEC 1000ULL
+
+enum format_flags {
+ FIELD_IS_ARRAY = 1,
+ FIELD_IS_POINTER = 2,
+ FIELD_IS_SIGNED = 4,
+ FIELD_IS_STRING = 8,
+ FIELD_IS_DYNAMIC = 16,
+ FIELD_IS_LONG = 32,
+ FIELD_IS_FLAG = 64,
+ FIELD_IS_SYMBOLIC = 128,
+};
+
+struct format_field {
+ struct format_field *next;
+ struct event_format *event;
+ char *type;
+ char *name;
+ int offset;
+ int size;
+ unsigned int arraylen;
+ unsigned int elementsize;
+ unsigned long flags;
+};
+
+struct format {
+ int nr_common;
+ int nr_fields;
+ struct format_field *common_fields;
+ struct format_field *fields;
+};
+
+struct print_arg_atom {
+ char *atom;
+};
+
+struct print_arg_string {
+ char *string;
+ int offset;
+};
+
+struct print_arg_field {
+ char *name;
+ struct format_field *field;
+};
+
+struct print_flag_sym {
+ struct print_flag_sym *next;
+ char *value;
+ char *str;
+};
+
+struct print_arg_typecast {
+ char *type;
+ struct print_arg *item;
+};
+
+struct print_arg_flags {
+ struct print_arg *field;
+ char *delim;
+ struct print_flag_sym *flags;
+};
+
+struct print_arg_symbol {
+ struct print_arg *field;
+ struct print_flag_sym *symbols;
+};
+
+struct print_arg_dynarray {
+ struct format_field *field;
+ struct print_arg *index;
+};
+
+struct print_arg;
+
+struct print_arg_op {
+ char *op;
+ int prio;
+ struct print_arg *left;
+ struct print_arg *right;
+};
+
+struct pevent_function_handler;
+
+struct print_arg_func {
+ struct pevent_function_handler *func;
+ struct print_arg *args;
+};
+
+enum print_arg_type {
+ PRINT_NULL,
+ PRINT_ATOM,
+ PRINT_FIELD,
+ PRINT_FLAGS,
+ PRINT_SYMBOL,
+ PRINT_TYPE,
+ PRINT_STRING,
+ PRINT_BSTRING,
+ PRINT_DYNAMIC_ARRAY,
+ PRINT_OP,
+ PRINT_FUNC,
+};
+
+struct print_arg {
+ struct print_arg *next;
+ enum print_arg_type type;
+ union {
+ struct print_arg_atom atom;
+ struct print_arg_field field;
+ struct print_arg_typecast typecast;
+ struct print_arg_flags flags;
+ struct print_arg_symbol symbol;
+ struct print_arg_func func;
+ struct print_arg_string string;
+ struct print_arg_op op;
+ struct print_arg_dynarray dynarray;
+ };
+};
+
+struct print_fmt {
+ char *format;
+ struct print_arg *args;
+};
+
+struct event_format {
+ struct pevent *pevent;
+ char *name;
+ int id;
+ int flags;
+ struct format format;
+ struct print_fmt print_fmt;
+ char *system;
+ pevent_event_handler_func handler;
+ void *context;
+};
+
+enum {
+ EVENT_FL_ISFTRACE = 0x01,
+ EVENT_FL_ISPRINT = 0x02,
+ EVENT_FL_ISBPRINT = 0x04,
+ EVENT_FL_ISFUNCENT = 0x10,
+ EVENT_FL_ISFUNCRET = 0x20,
+
+ EVENT_FL_FAILED = 0x80000000
+};
+
+enum event_sort_type {
+ EVENT_SORT_ID,
+ EVENT_SORT_NAME,
+ EVENT_SORT_SYSTEM,
+};
+
+enum event_type {
+ EVENT_ERROR,
+ EVENT_NONE,
+ EVENT_SPACE,
+ EVENT_NEWLINE,
+ EVENT_OP,
+ EVENT_DELIM,
+ EVENT_ITEM,
+ EVENT_DQUOTE,
+ EVENT_SQUOTE,
+};
+
+typedef unsigned long long (*pevent_func_handler)(struct trace_seq *s,
+ unsigned long long *args);
+
+enum pevent_func_arg_type {
+ PEVENT_FUNC_ARG_VOID,
+ PEVENT_FUNC_ARG_INT,
+ PEVENT_FUNC_ARG_LONG,
+ PEVENT_FUNC_ARG_STRING,
+ PEVENT_FUNC_ARG_PTR,
+ PEVENT_FUNC_ARG_MAX_TYPES
+};
+
+enum pevent_flag {
+ PEVENT_NSEC_OUTPUT = 1, /* output in NSECS */
+};
+
+struct cmdline;
+struct cmdline_list;
+struct func_map;
+struct func_list;
+struct event_handler;
+
+struct pevent {
+ int ref_count;
+
+ int header_page_ts_offset;
+ int header_page_ts_size;
+ int header_page_size_offset;
+ int header_page_size_size;
+ int header_page_data_offset;
+ int header_page_data_size;
+ int header_page_overwrite;
+
+ int file_bigendian;
+ int host_bigendian;
+
+ int latency_format;
+
+ int old_format;
+
+ int cpus;
+ int long_size;
+
+ struct cmdline *cmdlines;
+ struct cmdline_list *cmdlist;
+ int cmdline_count;
+
+ struct func_map *func_map;
+ struct func_list *funclist;
+ unsigned int func_count;
+
+ struct printk_map *printk_map;
+ struct printk_list *printklist;
+ unsigned int printk_count;
+
+
+ struct event_format **events;
+ int nr_events;
+ struct event_format **sort_events;
+ enum event_sort_type last_type;
+
+ int type_offset;
+ int type_size;
+
+ int pid_offset;
+ int pid_size;
+
+ int pc_offset;
+ int pc_size;
+
+ int flags_offset;
+ int flags_size;
+
+ int ld_offset;
+ int ld_size;
+
+ int print_raw;
+
+ int test_filters;
+
+ int flags;
+
+ struct format_field *bprint_ip_field;
+ struct format_field *bprint_fmt_field;
+ struct format_field *bprint_buf_field;
+
+ struct event_handler *handlers;
+ struct pevent_function_handler *func_handlers;
+
+ /* cache */
+ struct event_format *last_event;
+};
+
+static inline void pevent_set_flag(struct pevent *pevent, int flag)
+{
+ pevent->flags |= flag;
+}
+
+static inline unsigned short
+__data2host2(struct pevent *pevent, unsigned short data)
+{
+ unsigned short swap;
+
+ if (pevent->host_bigendian == pevent->file_bigendian)
+ return data;
+
+ swap = ((data & 0xffULL) << 8) |
+ ((data & (0xffULL << 8)) >> 8);
+
+ return swap;
+}
+
+static inline unsigned int
+__data2host4(struct pevent *pevent, unsigned int data)
+{
+ unsigned int swap;
+
+ if (pevent->host_bigendian == pevent->file_bigendian)
+ return data;
+
+ swap = ((data & 0xffULL) << 24) |
+ ((data & (0xffULL << 8)) << 8) |
+ ((data & (0xffULL << 16)) >> 8) |
+ ((data & (0xffULL << 24)) >> 24);
+
+ return swap;
+}
+
+static inline unsigned long long
+__data2host8(struct pevent *pevent, unsigned long long data)
+{
+ unsigned long long swap;
+
+ if (pevent->host_bigendian == pevent->file_bigendian)
+ return data;
+
+ swap = ((data & 0xffULL) << 56) |
+ ((data & (0xffULL << 8)) << 40) |
+ ((data & (0xffULL << 16)) << 24) |
+ ((data & (0xffULL << 24)) << 8) |
+ ((data & (0xffULL << 32)) >> 8) |
+ ((data & (0xffULL << 40)) >> 24) |
+ ((data & (0xffULL << 48)) >> 40) |
+ ((data & (0xffULL << 56)) >> 56);
+
+ return swap;
+}
+
+#define data2host2(pevent, ptr) __data2host2(pevent, *(unsigned short *)(ptr))
+#define data2host4(pevent, ptr) __data2host4(pevent, *(unsigned int *)(ptr))
+#define data2host8(pevent, ptr) \
+({ \
+ unsigned long long __val; \
+ \
+ memcpy(&__val, (ptr), sizeof(unsigned long long)); \
+ __data2host8(pevent, __val); \
+})
+
+/* taken from kernel/trace/trace.h */
+enum trace_flag_type {
+ TRACE_FLAG_IRQS_OFF = 0x01,
+ TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
+ TRACE_FLAG_NEED_RESCHED = 0x04,
+ TRACE_FLAG_HARDIRQ = 0x08,
+ TRACE_FLAG_SOFTIRQ = 0x10,
+};
+
+int pevent_register_comm(struct pevent *pevent, const char *comm, int pid);
+int pevent_register_function(struct pevent *pevent, char *name,
+ unsigned long long addr, char *mod);
+int pevent_register_print_string(struct pevent *pevent, char *fmt,
+ unsigned long long addr);
+int pevent_pid_is_registered(struct pevent *pevent, int pid);
+
+void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
+ struct pevent_record *record);
+
+int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size,
+ int long_size);
+
+int pevent_parse_event(struct pevent *pevent, const char *buf,
+ unsigned long size, const char *sys);
+
+void *pevent_get_field_raw(struct trace_seq *s, struct event_format *event,
+ const char *name, struct pevent_record *record,
+ int *len, int err);
+
+int pevent_get_field_val(struct trace_seq *s, struct event_format *event,
+ const char *name, struct pevent_record *record,
+ unsigned long long *val, int err);
+int pevent_get_common_field_val(struct trace_seq *s, struct event_format *event,
+ const char *name, struct pevent_record *record,
+ unsigned long long *val, int err);
+int pevent_get_any_field_val(struct trace_seq *s, struct event_format *event,
+ const char *name, struct pevent_record *record,
+ unsigned long long *val, int err);
+
+int pevent_print_num_field(struct trace_seq *s, const char *fmt,
+ struct event_format *event, const char *name,
+ struct pevent_record *record, int err);
+
+int pevent_register_event_handler(struct pevent *pevent, int id, char *sys_name, char *event_name,
+ pevent_event_handler_func func, void *context);
+int pevent_register_print_function(struct pevent *pevent,
+ pevent_func_handler func,
+ enum pevent_func_arg_type ret_type,
+ char *name, ...);
+
+struct format_field *pevent_find_common_field(struct event_format *event, const char *name);
+struct format_field *pevent_find_field(struct event_format *event, const char *name);
+struct format_field *pevent_find_any_field(struct event_format *event, const char *name);
+
+const char *pevent_find_function(struct pevent *pevent, unsigned long long addr);
+unsigned long long
+pevent_find_function_address(struct pevent *pevent, unsigned long long addr);
+unsigned long long pevent_read_number(struct pevent *pevent, const void *ptr, int size);
+int pevent_read_number_field(struct format_field *field, const void *data,
+ unsigned long long *value);
+
+struct event_format *pevent_find_event(struct pevent *pevent, int id);
+
+struct event_format *
+pevent_find_event_by_name(struct pevent *pevent, const char *sys, const char *name);
+
+void pevent_data_lat_fmt(struct pevent *pevent,
+ struct trace_seq *s, struct pevent_record *record);
+int pevent_data_type(struct pevent *pevent, struct pevent_record *rec);
+struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type);
+int pevent_data_pid(struct pevent *pevent, struct pevent_record *rec);
+const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid);
+void pevent_event_info(struct trace_seq *s, struct event_format *event,
+ struct pevent_record *record);
+
+struct event_format **pevent_list_events(struct pevent *pevent, enum event_sort_type);
+struct format_field **pevent_event_common_fields(struct event_format *event);
+struct format_field **pevent_event_fields(struct event_format *event);
+
+static inline int pevent_get_cpus(struct pevent *pevent)
+{
+ return pevent->cpus;
+}
+
+static inline void pevent_set_cpus(struct pevent *pevent, int cpus)
+{
+ pevent->cpus = cpus;
+}
+
+static inline int pevent_get_long_size(struct pevent *pevent)
+{
+ return pevent->long_size;
+}
+
+static inline void pevent_set_long_size(struct pevent *pevent, int long_size)
+{
+ pevent->long_size = long_size;
+}
+
+static inline int pevent_is_file_bigendian(struct pevent *pevent)
+{
+ return pevent->file_bigendian;
+}
+
+static inline void pevent_set_file_bigendian(struct pevent *pevent, int endian)
+{
+ pevent->file_bigendian = endian;
+}
+
+static inline int pevent_is_host_bigendian(struct pevent *pevent)
+{
+ return pevent->host_bigendian;
+}
+
+static inline void pevent_set_host_bigendian(struct pevent *pevent, int endian)
+{
+ pevent->host_bigendian = endian;
+}
+
+static inline int pevent_is_latency_format(struct pevent *pevent)
+{
+ return pevent->latency_format;
+}
+
+static inline void pevent_set_latency_format(struct pevent *pevent, int lat)
+{
+ pevent->latency_format = lat;
+}
+
+struct pevent *pevent_alloc(void);
+void pevent_free(struct pevent *pevent);
+void pevent_ref(struct pevent *pevent);
+void pevent_unref(struct pevent *pevent);
+
+/* access to the internal parser */
+void pevent_buffer_init(const char *buf, unsigned long long size);
+enum event_type pevent_read_token(char **tok);
+void pevent_free_token(char *token);
+int pevent_peek_char(void);
+const char *pevent_get_input_buf(void);
+unsigned long long pevent_get_input_buf_ptr(void);
+
+/* for debugging */
+void pevent_print_funcs(struct pevent *pevent);
+void pevent_print_printk(struct pevent *pevent);
+
+/* ----------------------- filtering ----------------------- */
+
+enum filter_boolean_type {
+ FILTER_FALSE,
+ FILTER_TRUE,
+};
+
+enum filter_op_type {
+ FILTER_OP_AND = 1,
+ FILTER_OP_OR,
+ FILTER_OP_NOT,
+};
+
+enum filter_cmp_type {
+ FILTER_CMP_NONE,
+ FILTER_CMP_EQ,
+ FILTER_CMP_NE,
+ FILTER_CMP_GT,
+ FILTER_CMP_LT,
+ FILTER_CMP_GE,
+ FILTER_CMP_LE,
+ FILTER_CMP_MATCH,
+ FILTER_CMP_NOT_MATCH,
+ FILTER_CMP_REGEX,
+ FILTER_CMP_NOT_REGEX,
+};
+
+enum filter_exp_type {
+ FILTER_EXP_NONE,
+ FILTER_EXP_ADD,
+ FILTER_EXP_SUB,
+ FILTER_EXP_MUL,
+ FILTER_EXP_DIV,
+ FILTER_EXP_MOD,
+ FILTER_EXP_RSHIFT,
+ FILTER_EXP_LSHIFT,
+ FILTER_EXP_AND,
+ FILTER_EXP_OR,
+ FILTER_EXP_XOR,
+ FILTER_EXP_NOT,
+};
+
+enum filter_arg_type {
+ FILTER_ARG_NONE,
+ FILTER_ARG_BOOLEAN,
+ FILTER_ARG_VALUE,
+ FILTER_ARG_FIELD,
+ FILTER_ARG_EXP,
+ FILTER_ARG_OP,
+ FILTER_ARG_NUM,
+ FILTER_ARG_STR,
+};
+
+enum filter_value_type {
+ FILTER_NUMBER,
+ FILTER_STRING,
+ FILTER_CHAR
+};
+
+struct fliter_arg;
+
+struct filter_arg_boolean {
+ enum filter_boolean_type value;
+};
+
+struct filter_arg_field {
+ struct format_field *field;
+};
+
+struct filter_arg_value {
+ enum filter_value_type type;
+ union {
+ char *str;
+ unsigned long long val;
+ };
+};
+
+struct filter_arg_op {
+ enum filter_op_type type;
+ struct filter_arg *left;
+ struct filter_arg *right;
+};
+
+struct filter_arg_exp {
+ enum filter_exp_type type;
+ struct filter_arg *left;
+ struct filter_arg *right;
+};
+
+struct filter_arg_num {
+ enum filter_cmp_type type;
+ struct filter_arg *left;
+ struct filter_arg *right;
+};
+
+struct filter_arg_str {
+ enum filter_cmp_type type;
+ struct format_field *field;
+ char *val;
+ char *buffer;
+ regex_t reg;
+};
+
+struct filter_arg {
+ enum filter_arg_type type;
+ union {
+ struct filter_arg_boolean boolean;
+ struct filter_arg_field field;
+ struct filter_arg_value value;
+ struct filter_arg_op op;
+ struct filter_arg_exp exp;
+ struct filter_arg_num num;
+ struct filter_arg_str str;
+ };
+};
+
+struct filter_type {
+ int event_id;
+ struct event_format *event;
+ struct filter_arg *filter;
+};
+
+struct event_filter {
+ struct pevent *pevent;
+ int filters;
+ struct filter_type *event_filters;
+};
+
+struct event_filter *pevent_filter_alloc(struct pevent *pevent);
+
+#define FILTER_NONE -2
+#define FILTER_NOEXIST -1
+#define FILTER_MISS 0
+#define FILTER_MATCH 1
+
+enum filter_trivial_type {
+ FILTER_TRIVIAL_FALSE,
+ FILTER_TRIVIAL_TRUE,
+ FILTER_TRIVIAL_BOTH,
+};
+
+int pevent_filter_add_filter_str(struct event_filter *filter,
+ const char *filter_str,
+ char **error_str);
+
+
+int pevent_filter_match(struct event_filter *filter,
+ struct pevent_record *record);
+
+int pevent_event_filtered(struct event_filter *filter,
+ int event_id);
+
+void pevent_filter_reset(struct event_filter *filter);
+
+void pevent_filter_clear_trivial(struct event_filter *filter,
+ enum filter_trivial_type type);
+
+void pevent_filter_free(struct event_filter *filter);
+
+char *pevent_filter_make_string(struct event_filter *filter, int event_id);
+
+int pevent_filter_remove_event(struct event_filter *filter,
+ int event_id);
+
+int pevent_filter_event_has_trivial(struct event_filter *filter,
+ int event_id,
+ enum filter_trivial_type type);
+
+int pevent_filter_copy(struct event_filter *dest, struct event_filter *source);
+
+int pevent_update_trivial(struct event_filter *dest, struct event_filter *source,
+ enum filter_trivial_type type);
+
+int pevent_filter_compare(struct event_filter *filter1, struct event_filter *filter2);
+
+#endif /* _PARSE_EVENTS_H */
diff --git a/tools/lib/traceevent/event-utils.h b/tools/lib/traceevent/event-utils.h
new file mode 100644
index 000000000000..08296383d1e6
--- /dev/null
+++ b/tools/lib/traceevent/event-utils.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License (not later!)
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#ifndef __UTIL_H
+#define __UTIL_H
+
+#include <ctype.h>
+
+/* Can be overridden */
+void die(const char *fmt, ...);
+void *malloc_or_die(unsigned int size);
+void warning(const char *fmt, ...);
+void pr_stat(const char *fmt, ...);
+void vpr_stat(const char *fmt, va_list ap);
+
+/* Always available */
+void __die(const char *fmt, ...);
+void __warning(const char *fmt, ...);
+void __pr_stat(const char *fmt, ...);
+
+void __vdie(const char *fmt, ...);
+void __vwarning(const char *fmt, ...);
+void __vpr_stat(const char *fmt, ...);
+
+static inline char *strim(char *string)
+{
+ char *ret;
+
+ if (!string)
+ return NULL;
+ while (*string) {
+ if (!isspace(*string))
+ break;
+ string++;
+ }
+ ret = string;
+
+ string = ret + strlen(ret) - 1;
+ while (string > ret) {
+ if (!isspace(*string))
+ break;
+ string--;
+ }
+ string[1] = 0;
+
+ return ret;
+}
+
+static inline int has_text(const char *text)
+{
+ if (!text)
+ return 0;
+
+ while (*text) {
+ if (!isspace(*text))
+ return 1;
+ text++;
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c
new file mode 100644
index 000000000000..2d40c5ed81d6
--- /dev/null
+++ b/tools/lib/traceevent/parse-filter.c
@@ -0,0 +1,2262 @@
+/*
+ * Copyright (C) 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License (not later!)
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include "event-parse.h"
+#include "event-utils.h"
+
+#define COMM "COMM"
+
+static struct format_field comm = {
+ .name = "COMM",
+};
+
+struct event_list {
+ struct event_list *next;
+ struct event_format *event;
+};
+
+#define MAX_ERR_STR_SIZE 256
+
+static void show_error(char **error_str, const char *fmt, ...)
+{
+ unsigned long long index;
+ const char *input;
+ char *error;
+ va_list ap;
+ int len;
+ int i;
+
+ if (!error_str)
+ return;
+
+ input = pevent_get_input_buf();
+ index = pevent_get_input_buf_ptr();
+ len = input ? strlen(input) : 0;
+
+ error = malloc_or_die(MAX_ERR_STR_SIZE + (len*2) + 3);
+
+ if (len) {
+ strcpy(error, input);
+ error[len] = '\n';
+ for (i = 1; i < len && i < index; i++)
+ error[len+i] = ' ';
+ error[len + i] = '^';
+ error[len + i + 1] = '\n';
+ len += i+2;
+ }
+
+ va_start(ap, fmt);
+ vsnprintf(error + len, MAX_ERR_STR_SIZE, fmt, ap);
+ va_end(ap);
+
+ *error_str = error;
+}
+
+static void free_token(char *token)
+{
+ pevent_free_token(token);
+}
+
+static enum event_type read_token(char **tok)
+{
+ enum event_type type;
+ char *token = NULL;
+
+ do {
+ free_token(token);
+ type = pevent_read_token(&token);
+ } while (type == EVENT_NEWLINE || type == EVENT_SPACE);
+
+ /* If token is = or ! check to see if the next char is ~ */
+ if (token &&
+ (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) &&
+ pevent_peek_char() == '~') {
+ /* append it */
+ *tok = malloc(3);
+ sprintf(*tok, "%c%c", *token, '~');
+ free_token(token);
+ /* Now remove the '~' from the buffer */
+ pevent_read_token(&token);
+ free_token(token);
+ } else
+ *tok = token;
+
+ return type;
+}
+
+static int filter_cmp(const void *a, const void *b)
+{
+ const struct filter_type *ea = a;
+ const struct filter_type *eb = b;
+
+ if (ea->event_id < eb->event_id)
+ return -1;
+
+ if (ea->event_id > eb->event_id)
+ return 1;
+
+ return 0;
+}
+
+static struct filter_type *
+find_filter_type(struct event_filter *filter, int id)
+{
+ struct filter_type *filter_type;
+ struct filter_type key;
+
+ key.event_id = id;
+
+ filter_type = bsearch(&key, filter->event_filters,
+ filter->filters,
+ sizeof(*filter->event_filters),
+ filter_cmp);
+
+ return filter_type;
+}
+
+static struct filter_type *
+add_filter_type(struct event_filter *filter, int id)
+{
+ struct filter_type *filter_type;
+ int i;
+
+ filter_type = find_filter_type(filter, id);
+ if (filter_type)
+ return filter_type;
+
+ if (!filter->filters)
+ filter->event_filters =
+ malloc_or_die(sizeof(*filter->event_filters));
+ else {
+ filter->event_filters =
+ realloc(filter->event_filters,
+ sizeof(*filter->event_filters) *
+ (filter->filters + 1));
+ if (!filter->event_filters)
+ die("Could not allocate filter");
+ }
+
+ for (i = 0; i < filter->filters; i++) {
+ if (filter->event_filters[i].event_id > id)
+ break;
+ }
+
+ if (i < filter->filters)
+ memmove(&filter->event_filters[i+1],
+ &filter->event_filters[i],
+ sizeof(*filter->event_filters) *
+ (filter->filters - i));
+
+ filter_type = &filter->event_filters[i];
+ filter_type->event_id = id;
+ filter_type->event = pevent_find_event(filter->pevent, id);
+ filter_type->filter = NULL;
+
+ filter->filters++;
+
+ return filter_type;
+}
+
+/**
+ * pevent_filter_alloc - create a new event filter
+ * @pevent: The pevent that this filter is associated with
+ */
+struct event_filter *pevent_filter_alloc(struct pevent *pevent)
+{
+ struct event_filter *filter;
+
+ filter = malloc_or_die(sizeof(*filter));
+ memset(filter, 0, sizeof(*filter));
+ filter->pevent = pevent;
+ pevent_ref(pevent);
+
+ return filter;
+}
+
+static struct filter_arg *allocate_arg(void)
+{
+ struct filter_arg *arg;
+
+ arg = malloc_or_die(sizeof(*arg));
+ memset(arg, 0, sizeof(*arg));
+
+ return arg;
+}
+
+static void free_arg(struct filter_arg *arg)
+{
+ if (!arg)
+ return;
+
+ switch (arg->type) {
+ case FILTER_ARG_NONE:
+ case FILTER_ARG_BOOLEAN:
+ case FILTER_ARG_NUM:
+ break;
+
+ case FILTER_ARG_STR:
+ free(arg->str.val);
+ regfree(&arg->str.reg);
+ free(arg->str.buffer);
+ break;
+
+ case FILTER_ARG_OP:
+ free_arg(arg->op.left);
+ free_arg(arg->op.right);
+ default:
+ break;
+ }
+
+ free(arg);
+}
+
+static void add_event(struct event_list **events,
+ struct event_format *event)
+{
+ struct event_list *list;
+
+ list = malloc_or_die(sizeof(*list));
+ list->next = *events;
+ *events = list;
+ list->event = event;
+}
+
+static int event_match(struct event_format *event,
+ regex_t *sreg, regex_t *ereg)
+{
+ if (sreg) {
+ return !regexec(sreg, event->system, 0, NULL, 0) &&
+ !regexec(ereg, event->name, 0, NULL, 0);
+ }
+
+ return !regexec(ereg, event->system, 0, NULL, 0) ||
+ !regexec(ereg, event->name, 0, NULL, 0);
+}
+
+static int
+find_event(struct pevent *pevent, struct event_list **events,
+ char *sys_name, char *event_name)
+{
+ struct event_format *event;
+ regex_t ereg;
+ regex_t sreg;
+ int match = 0;
+ char *reg;
+ int ret;
+ int i;
+
+ if (!event_name) {
+ /* if no name is given, then swap sys and name */
+ event_name = sys_name;
+ sys_name = NULL;
+ }
+
+ reg = malloc_or_die(strlen(event_name) + 3);
+ sprintf(reg, "^%s$", event_name);
+
+ ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB);
+ free(reg);
+
+ if (ret)
+ return -1;
+
+ if (sys_name) {
+ reg = malloc_or_die(strlen(sys_name) + 3);
+ sprintf(reg, "^%s$", sys_name);
+ ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB);
+ free(reg);
+ if (ret) {
+ regfree(&ereg);
+ return -1;
+ }
+ }
+
+ for (i = 0; i < pevent->nr_events; i++) {
+ event = pevent->events[i];
+ if (event_match(event, sys_name ? &sreg : NULL, &ereg)) {
+ match = 1;
+ add_event(events, event);
+ }
+ }
+
+ regfree(&ereg);
+ if (sys_name)
+ regfree(&sreg);
+
+ if (!match)
+ return -1;
+
+ return 0;
+}
+
+static void free_events(struct event_list *events)
+{
+ struct event_list *event;
+
+ while (events) {
+ event = events;
+ events = events->next;
+ free(event);
+ }
+}
+
+static struct filter_arg *
+create_arg_item(struct event_format *event,
+ const char *token, enum filter_arg_type type,
+ char **error_str)
+{
+ struct format_field *field;
+ struct filter_arg *arg;
+
+ arg = allocate_arg();
+
+ switch (type) {
+
+ case EVENT_SQUOTE:
+ case EVENT_DQUOTE:
+ arg->type = FILTER_ARG_VALUE;
+ arg->value.type =
+ type == EVENT_DQUOTE ? FILTER_STRING : FILTER_CHAR;
+ arg->value.str = strdup(token);
+ if (!arg->value.str)
+ die("malloc string");
+ break;
+ case EVENT_ITEM:
+ /* if it is a number, then convert it */
+ if (isdigit(token[0])) {
+ arg->type = FILTER_ARG_VALUE;
+ arg->value.type = FILTER_NUMBER;
+ arg->value.val = strtoull(token, NULL, 0);
+ break;
+ }
+ /* Consider this a field */
+ field = pevent_find_any_field(event, token);
+ if (!field) {
+ if (strcmp(token, COMM) != 0) {
+ /* not a field, Make it false */
+ arg->type = FILTER_ARG_BOOLEAN;
+ arg->boolean.value = FILTER_FALSE;
+ break;
+ }
+ /* If token is 'COMM' then it is special */
+ field = &comm;
+ }
+ arg->type = FILTER_ARG_FIELD;
+ arg->field.field = field;
+ break;
+ default:
+ free_arg(arg);
+ show_error(error_str, "expected a value but found %s",
+ token);
+ return NULL;
+ }
+ return arg;
+}
+
+static struct filter_arg *
+create_arg_op(enum filter_op_type btype)
+{
+ struct filter_arg *arg;
+
+ arg = allocate_arg();
+ arg->type = FILTER_ARG_OP;
+ arg->op.type = btype;
+
+ return arg;
+}
+
+static struct filter_arg *
+create_arg_exp(enum filter_exp_type etype)
+{
+ struct filter_arg *arg;
+
+ arg = allocate_arg();
+ arg->type = FILTER_ARG_EXP;
+ arg->op.type = etype;
+
+ return arg;
+}
+
+static struct filter_arg *
+create_arg_cmp(enum filter_exp_type etype)
+{
+ struct filter_arg *arg;
+
+ arg = allocate_arg();
+ /* Use NUM and change if necessary */
+ arg->type = FILTER_ARG_NUM;
+ arg->op.type = etype;
+
+ return arg;
+}
+
+static int add_right(struct filter_arg *op, struct filter_arg *arg,
+ char **error_str)
+{
+ struct filter_arg *left;
+ char *str;
+ int op_type;
+ int ret;
+
+ switch (op->type) {
+ case FILTER_ARG_EXP:
+ if (op->exp.right)
+ goto out_fail;
+ op->exp.right = arg;
+ break;
+
+ case FILTER_ARG_OP:
+ if (op->op.right)
+ goto out_fail;
+ op->op.right = arg;
+ break;
+
+ case FILTER_ARG_NUM:
+ if (op->op.right)
+ goto out_fail;
+ /*
+ * The arg must be num, str, or field
+ */
+ switch (arg->type) {
+ case FILTER_ARG_VALUE:
+ case FILTER_ARG_FIELD:
+ break;
+ default:
+ show_error(error_str,
+ "Illegal rvalue");
+ return -1;
+ }
+
+ /*
+ * Depending on the type, we may need to
+ * convert this to a string or regex.
+ */
+ switch (arg->value.type) {
+ case FILTER_CHAR:
+ /*
+ * A char should be converted to number if
+ * the string is 1 byte, and the compare
+ * is not a REGEX.
+ */
+ if (strlen(arg->value.str) == 1 &&
+ op->num.type != FILTER_CMP_REGEX &&
+ op->num.type != FILTER_CMP_NOT_REGEX) {
+ arg->value.type = FILTER_NUMBER;
+ goto do_int;
+ }
+ /* fall through */
+ case FILTER_STRING:
+
+ /* convert op to a string arg */
+ op_type = op->num.type;
+ left = op->num.left;
+ str = arg->value.str;
+
+ /* reset the op for the new field */
+ memset(op, 0, sizeof(*op));
+
+ /*
+ * If left arg was a field not found then
+ * NULL the entire op.
+ */
+ if (left->type == FILTER_ARG_BOOLEAN) {
+ free_arg(left);
+ free_arg(arg);
+ op->type = FILTER_ARG_BOOLEAN;
+ op->boolean.value = FILTER_FALSE;
+ break;
+ }
+
+ /* Left arg must be a field */
+ if (left->type != FILTER_ARG_FIELD) {
+ show_error(error_str,
+ "Illegal lvalue for string comparison");
+ return -1;
+ }
+
+ /* Make sure this is a valid string compare */
+ switch (op_type) {
+ case FILTER_CMP_EQ:
+ op_type = FILTER_CMP_MATCH;
+ break;
+ case FILTER_CMP_NE:
+ op_type = FILTER_CMP_NOT_MATCH;
+ break;
+
+ case FILTER_CMP_REGEX:
+ case FILTER_CMP_NOT_REGEX:
+ ret = regcomp(&op->str.reg, str, REG_ICASE|REG_NOSUB);
+ if (ret) {
+ show_error(error_str,
+ "RegEx '%s' did not compute",
+ str);
+ return -1;
+ }
+ break;
+ default:
+ show_error(error_str,
+ "Illegal comparison for string");
+ return -1;
+ }
+
+ op->type = FILTER_ARG_STR;
+ op->str.type = op_type;
+ op->str.field = left->field.field;
+ op->str.val = strdup(str);
+ if (!op->str.val)
+ die("malloc string");
+ /*
+ * Need a buffer to copy data for tests
+ */
+ op->str.buffer = malloc_or_die(op->str.field->size + 1);
+ /* Null terminate this buffer */
+ op->str.buffer[op->str.field->size] = 0;
+
+ /* We no longer have left or right args */
+ free_arg(arg);
+ free_arg(left);
+
+ break;
+
+ case FILTER_NUMBER:
+
+ do_int:
+ switch (op->num.type) {
+ case FILTER_CMP_REGEX:
+ case FILTER_CMP_NOT_REGEX:
+ show_error(error_str,
+ "Op not allowed with integers");
+ return -1;
+
+ default:
+ break;
+ }
+
+ /* numeric compare */
+ op->num.right = arg;
+ break;
+ default:
+ goto out_fail;
+ }
+ break;
+ default:
+ goto out_fail;
+ }
+
+ return 0;
+
+ out_fail:
+ show_error(error_str,
+ "Syntax error");
+ return -1;
+}
+
+static struct filter_arg *
+rotate_op_right(struct filter_arg *a, struct filter_arg *b)
+{
+ struct filter_arg *arg;
+
+ arg = a->op.right;
+ a->op.right = b;
+ return arg;
+}
+
+static int add_left(struct filter_arg *op, struct filter_arg *arg)
+{
+ switch (op->type) {
+ case FILTER_ARG_EXP:
+ if (arg->type == FILTER_ARG_OP)
+ arg = rotate_op_right(arg, op);
+ op->exp.left = arg;
+ break;
+
+ case FILTER_ARG_OP:
+ op->op.left = arg;
+ break;
+ case FILTER_ARG_NUM:
+ if (arg->type == FILTER_ARG_OP)
+ arg = rotate_op_right(arg, op);
+
+ /* left arg of compares must be a field */
+ if (arg->type != FILTER_ARG_FIELD &&
+ arg->type != FILTER_ARG_BOOLEAN)
+ return -1;
+ op->num.left = arg;
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+enum op_type {
+ OP_NONE,
+ OP_BOOL,
+ OP_NOT,
+ OP_EXP,
+ OP_CMP,
+};
+
+static enum op_type process_op(const char *token,
+ enum filter_op_type *btype,
+ enum filter_cmp_type *ctype,
+ enum filter_exp_type *etype)
+{
+ *btype = FILTER_OP_NOT;
+ *etype = FILTER_EXP_NONE;
+ *ctype = FILTER_CMP_NONE;
+
+ if (strcmp(token, "&&") == 0)
+ *btype = FILTER_OP_AND;
+ else if (strcmp(token, "||") == 0)
+ *btype = FILTER_OP_OR;
+ else if (strcmp(token, "!") == 0)
+ return OP_NOT;
+
+ if (*btype != FILTER_OP_NOT)
+ return OP_BOOL;
+
+ /* Check for value expressions */
+ if (strcmp(token, "+") == 0) {
+ *etype = FILTER_EXP_ADD;
+ } else if (strcmp(token, "-") == 0) {
+ *etype = FILTER_EXP_SUB;
+ } else if (strcmp(token, "*") == 0) {
+ *etype = FILTER_EXP_MUL;
+ } else if (strcmp(token, "/") == 0) {
+ *etype = FILTER_EXP_DIV;
+ } else if (strcmp(token, "%") == 0) {
+ *etype = FILTER_EXP_MOD;
+ } else if (strcmp(token, ">>") == 0) {
+ *etype = FILTER_EXP_RSHIFT;
+ } else if (strcmp(token, "<<") == 0) {
+ *etype = FILTER_EXP_LSHIFT;
+ } else if (strcmp(token, "&") == 0) {
+ *etype = FILTER_EXP_AND;
+ } else if (strcmp(token, "|") == 0) {
+ *etype = FILTER_EXP_OR;
+ } else if (strcmp(token, "^") == 0) {
+ *etype = FILTER_EXP_XOR;
+ } else if (strcmp(token, "~") == 0)
+ *etype = FILTER_EXP_NOT;
+
+ if (*etype != FILTER_EXP_NONE)
+ return OP_EXP;
+
+ /* Check for compares */
+ if (strcmp(token, "==") == 0)
+ *ctype = FILTER_CMP_EQ;
+ else if (strcmp(token, "!=") == 0)
+ *ctype = FILTER_CMP_NE;
+ else if (strcmp(token, "<") == 0)
+ *ctype = FILTER_CMP_LT;
+ else if (strcmp(token, ">") == 0)
+ *ctype = FILTER_CMP_GT;
+ else if (strcmp(token, "<=") == 0)
+ *ctype = FILTER_CMP_LE;
+ else if (strcmp(token, ">=") == 0)
+ *ctype = FILTER_CMP_GE;
+ else if (strcmp(token, "=~") == 0)
+ *ctype = FILTER_CMP_REGEX;
+ else if (strcmp(token, "!~") == 0)
+ *ctype = FILTER_CMP_NOT_REGEX;
+ else
+ return OP_NONE;
+
+ return OP_CMP;
+}
+
+static int check_op_done(struct filter_arg *arg)
+{
+ switch (arg->type) {
+ case FILTER_ARG_EXP:
+ return arg->exp.right != NULL;
+
+ case FILTER_ARG_OP:
+ return arg->op.right != NULL;
+
+ case FILTER_ARG_NUM:
+ return arg->num.right != NULL;
+
+ case FILTER_ARG_STR:
+ /* A string conversion is always done */
+ return 1;
+
+ case FILTER_ARG_BOOLEAN:
+ /* field not found, is ok */
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+enum filter_vals {
+ FILTER_VAL_NORM,
+ FILTER_VAL_FALSE,
+ FILTER_VAL_TRUE,
+};
+
+void reparent_op_arg(struct filter_arg *parent, struct filter_arg *old_child,
+ struct filter_arg *arg)
+{
+ struct filter_arg *other_child;
+ struct filter_arg **ptr;
+
+ if (parent->type != FILTER_ARG_OP &&
+ arg->type != FILTER_ARG_OP)
+ die("can not reparent other than OP");
+
+ /* Get the sibling */
+ if (old_child->op.right == arg) {
+ ptr = &old_child->op.right;
+ other_child = old_child->op.left;
+ } else if (old_child->op.left == arg) {
+ ptr = &old_child->op.left;
+ other_child = old_child->op.right;
+ } else
+ die("Error in reparent op, find other child");
+
+ /* Detach arg from old_child */
+ *ptr = NULL;
+
+ /* Check for root */
+ if (parent == old_child) {
+ free_arg(other_child);
+ *parent = *arg;
+ /* Free arg without recussion */
+ free(arg);
+ return;
+ }
+
+ if (parent->op.right == old_child)
+ ptr = &parent->op.right;
+ else if (parent->op.left == old_child)
+ ptr = &parent->op.left;
+ else
+ die("Error in reparent op");
+ *ptr = arg;
+
+ free_arg(old_child);
+}
+
+enum filter_vals test_arg(struct filter_arg *parent, struct filter_arg *arg)
+{
+ enum filter_vals lval, rval;
+
+ switch (arg->type) {
+
+ /* bad case */
+ case FILTER_ARG_BOOLEAN:
+ return FILTER_VAL_FALSE + arg->boolean.value;
+
+ /* good cases: */
+ case FILTER_ARG_STR:
+ case FILTER_ARG_VALUE:
+ case FILTER_ARG_FIELD:
+ return FILTER_VAL_NORM;
+
+ case FILTER_ARG_EXP:
+ lval = test_arg(arg, arg->exp.left);
+ if (lval != FILTER_VAL_NORM)
+ return lval;
+ rval = test_arg(arg, arg->exp.right);
+ if (rval != FILTER_VAL_NORM)
+ return rval;
+ return FILTER_VAL_NORM;
+
+ case FILTER_ARG_NUM:
+ lval = test_arg(arg, arg->num.left);
+ if (lval != FILTER_VAL_NORM)
+ return lval;
+ rval = test_arg(arg, arg->num.right);
+ if (rval != FILTER_VAL_NORM)
+ return rval;
+ return FILTER_VAL_NORM;
+
+ case FILTER_ARG_OP:
+ if (arg->op.type != FILTER_OP_NOT) {
+ lval = test_arg(arg, arg->op.left);
+ switch (lval) {
+ case FILTER_VAL_NORM:
+ break;
+ case FILTER_VAL_TRUE:
+ if (arg->op.type == FILTER_OP_OR)
+ return FILTER_VAL_TRUE;
+ rval = test_arg(arg, arg->op.right);
+ if (rval != FILTER_VAL_NORM)
+ return rval;
+
+ reparent_op_arg(parent, arg, arg->op.right);
+ return FILTER_VAL_NORM;
+
+ case FILTER_VAL_FALSE:
+ if (arg->op.type == FILTER_OP_AND)
+ return FILTER_VAL_FALSE;
+ rval = test_arg(arg, arg->op.right);
+ if (rval != FILTER_VAL_NORM)
+ return rval;
+
+ reparent_op_arg(parent, arg, arg->op.right);
+ return FILTER_VAL_NORM;
+ }
+ }
+
+ rval = test_arg(arg, arg->op.right);
+ switch (rval) {
+ case FILTER_VAL_NORM:
+ break;
+ case FILTER_VAL_TRUE:
+ if (arg->op.type == FILTER_OP_OR)
+ return FILTER_VAL_TRUE;
+ if (arg->op.type == FILTER_OP_NOT)
+ return FILTER_VAL_FALSE;
+
+ reparent_op_arg(parent, arg, arg->op.left);
+ return FILTER_VAL_NORM;
+
+ case FILTER_VAL_FALSE:
+ if (arg->op.type == FILTER_OP_AND)
+ return FILTER_VAL_FALSE;
+ if (arg->op.type == FILTER_OP_NOT)
+ return FILTER_VAL_TRUE;
+
+ reparent_op_arg(parent, arg, arg->op.left);
+ return FILTER_VAL_NORM;
+ }
+
+ return FILTER_VAL_NORM;
+ default:
+ die("bad arg in filter tree");
+ }
+ return FILTER_VAL_NORM;
+}
+
+/* Remove any unknown event fields */
+static struct filter_arg *collapse_tree(struct filter_arg *arg)
+{
+ enum filter_vals ret;
+
+ ret = test_arg(arg, arg);
+ switch (ret) {
+ case FILTER_VAL_NORM:
+ return arg;
+
+ case FILTER_VAL_TRUE:
+ case FILTER_VAL_FALSE:
+ free_arg(arg);
+ arg = allocate_arg();
+ arg->type = FILTER_ARG_BOOLEAN;
+ arg->boolean.value = ret == FILTER_VAL_TRUE;
+ }
+
+ return arg;
+}
+
+static int
+process_filter(struct event_format *event, struct filter_arg **parg,
+ char **error_str, int not)
+{
+ enum event_type type;
+ char *token = NULL;
+ struct filter_arg *current_op = NULL;
+ struct filter_arg *current_exp = NULL;
+ struct filter_arg *left_item = NULL;
+ struct filter_arg *arg = NULL;
+ enum op_type op_type;
+ enum filter_op_type btype;
+ enum filter_exp_type etype;
+ enum filter_cmp_type ctype;
+ int ret;
+
+ *parg = NULL;
+
+ do {
+ free(token);
+ type = read_token(&token);
+ switch (type) {
+ case EVENT_SQUOTE:
+ case EVENT_DQUOTE:
+ case EVENT_ITEM:
+ arg = create_arg_item(event, token, type, error_str);
+ if (!arg)
+ goto fail;
+ if (!left_item)
+ left_item = arg;
+ else if (current_exp) {
+ ret = add_right(current_exp, arg, error_str);
+ if (ret < 0)
+ goto fail;
+ left_item = NULL;
+ /* Not's only one one expression */
+ if (not) {
+ arg = NULL;
+ if (current_op)
+ goto fail_print;
+ free(token);
+ *parg = current_exp;
+ return 0;
+ }
+ } else
+ goto fail_print;
+ arg = NULL;
+ break;
+
+ case EVENT_DELIM:
+ if (*token == ',') {
+ show_error(error_str,
+ "Illegal token ','");
+ goto fail;
+ }
+
+ if (*token == '(') {
+ if (left_item) {
+ show_error(error_str,
+ "Open paren can not come after item");
+ goto fail;
+ }
+ if (current_exp) {
+ show_error(error_str,
+ "Open paren can not come after expression");
+ goto fail;
+ }
+
+ ret = process_filter(event, &arg, error_str, 0);
+ if (ret != 1) {
+ if (ret == 0)
+ show_error(error_str,
+ "Unbalanced number of '('");
+ goto fail;
+ }
+ ret = 0;
+
+ /* A not wants just one expression */
+ if (not) {
+ if (current_op)
+ goto fail_print;
+ *parg = arg;
+ return 0;
+ }
+
+ if (current_op)
+ ret = add_right(current_op, arg, error_str);
+ else
+ current_exp = arg;
+
+ if (ret < 0)
+ goto fail;
+
+ } else { /* ')' */
+ if (!current_op && !current_exp)
+ goto fail_print;
+
+ /* Make sure everything is finished at this level */
+ if (current_exp && !check_op_done(current_exp))
+ goto fail_print;
+ if (current_op && !check_op_done(current_op))
+ goto fail_print;
+
+ if (current_op)
+ *parg = current_op;
+ else
+ *parg = current_exp;
+ return 1;
+ }
+ break;
+
+ case EVENT_OP:
+ op_type = process_op(token, &btype, &ctype, &etype);
+
+ /* All expect a left arg except for NOT */
+ switch (op_type) {
+ case OP_BOOL:
+ /* Logic ops need a left expression */
+ if (!current_exp && !current_op)
+ goto fail_print;
+ /* fall through */
+ case OP_NOT:
+ /* logic only processes ops and exp */
+ if (left_item)
+ goto fail_print;
+ break;
+ case OP_EXP:
+ case OP_CMP:
+ if (!left_item)
+ goto fail_print;
+ break;
+ case OP_NONE:
+ show_error(error_str,
+ "Unknown op token %s", token);
+ goto fail;
+ }
+
+ ret = 0;
+ switch (op_type) {
+ case OP_BOOL:
+ arg = create_arg_op(btype);
+ if (current_op)
+ ret = add_left(arg, current_op);
+ else
+ ret = add_left(arg, current_exp);
+ current_op = arg;
+ current_exp = NULL;
+ break;
+
+ case OP_NOT:
+ arg = create_arg_op(btype);
+ if (current_op)
+ ret = add_right(current_op, arg, error_str);
+ if (ret < 0)
+ goto fail;
+ current_exp = arg;
+ ret = process_filter(event, &arg, error_str, 1);
+ if (ret < 0)
+ goto fail;
+ ret = add_right(current_exp, arg, error_str);
+ if (ret < 0)
+ goto fail;
+ break;
+
+ case OP_EXP:
+ case OP_CMP:
+ if (op_type == OP_EXP)
+ arg = create_arg_exp(etype);
+ else
+ arg = create_arg_cmp(ctype);
+
+ if (current_op)
+ ret = add_right(current_op, arg, error_str);
+ if (ret < 0)
+ goto fail;
+ ret = add_left(arg, left_item);
+ if (ret < 0) {
+ arg = NULL;
+ goto fail_print;
+ }
+ current_exp = arg;
+ break;
+ default:
+ break;
+ }
+ arg = NULL;
+ if (ret < 0)
+ goto fail_print;
+ break;
+ case EVENT_NONE:
+ break;
+ default:
+ goto fail_print;
+ }
+ } while (type != EVENT_NONE);
+
+ if (!current_op && !current_exp)
+ goto fail_print;
+
+ if (!current_op)
+ current_op = current_exp;
+
+ current_op = collapse_tree(current_op);
+
+ *parg = current_op;
+
+ return 0;
+
+ fail_print:
+ show_error(error_str, "Syntax error");
+ fail:
+ free_arg(current_op);
+ free_arg(current_exp);
+ free_arg(arg);
+ free(token);
+ return -1;
+}
+
+static int
+process_event(struct event_format *event, const char *filter_str,
+ struct filter_arg **parg, char **error_str)
+{
+ int ret;
+
+ pevent_buffer_init(filter_str, strlen(filter_str));
+
+ ret = process_filter(event, parg, error_str, 0);
+ if (ret == 1) {
+ show_error(error_str,
+ "Unbalanced number of ')'");
+ return -1;
+ }
+ if (ret < 0)
+ return ret;
+
+ /* If parg is NULL, then make it into FALSE */
+ if (!*parg) {
+ *parg = allocate_arg();
+ (*parg)->type = FILTER_ARG_BOOLEAN;
+ (*parg)->boolean.value = FILTER_FALSE;
+ }
+
+ return 0;
+}
+
+static int filter_event(struct event_filter *filter,
+ struct event_format *event,
+ const char *filter_str, char **error_str)
+{
+ struct filter_type *filter_type;
+ struct filter_arg *arg;
+ int ret;
+
+ if (filter_str) {
+ ret = process_event(event, filter_str, &arg, error_str);
+ if (ret < 0)
+ return ret;
+
+ } else {
+ /* just add a TRUE arg */
+ arg = allocate_arg();
+ arg->type = FILTER_ARG_BOOLEAN;
+ arg->boolean.value = FILTER_TRUE;
+ }
+
+ filter_type = add_filter_type(filter, event->id);
+ if (filter_type->filter)
+ free_arg(filter_type->filter);
+ filter_type->filter = arg;
+
+ return 0;
+}
+
+/**
+ * pevent_filter_add_filter_str - add a new filter
+ * @filter: the event filter to add to
+ * @filter_str: the filter string that contains the filter
+ * @error_str: string containing reason for failed filter
+ *
+ * Returns 0 if the filter was successfully added
+ * -1 if there was an error.
+ *
+ * On error, if @error_str points to a string pointer,
+ * it is set to the reason that the filter failed.
+ * This string must be freed with "free".
+ */
+int pevent_filter_add_filter_str(struct event_filter *filter,
+ const char *filter_str,
+ char **error_str)
+{
+ struct pevent *pevent = filter->pevent;
+ struct event_list *event;
+ struct event_list *events = NULL;
+ const char *filter_start;
+ const char *next_event;
+ char *this_event;
+ char *event_name = NULL;
+ char *sys_name = NULL;
+ char *sp;
+ int rtn = 0;
+ int len;
+ int ret;
+
+ /* clear buffer to reset show error */
+ pevent_buffer_init("", 0);
+
+ if (error_str)
+ *error_str = NULL;
+
+ filter_start = strchr(filter_str, ':');
+ if (filter_start)
+ len = filter_start - filter_str;
+ else
+ len = strlen(filter_str);
+
+
+ do {
+ next_event = strchr(filter_str, ',');
+ if (next_event &&
+ (!filter_start || next_event < filter_start))
+ len = next_event - filter_str;
+ else if (filter_start)
+ len = filter_start - filter_str;
+ else
+ len = strlen(filter_str);
+
+ this_event = malloc_or_die(len + 1);
+ memcpy(this_event, filter_str, len);
+ this_event[len] = 0;
+
+ if (next_event)
+ next_event++;
+
+ filter_str = next_event;
+
+ sys_name = strtok_r(this_event, "/", &sp);
+ event_name = strtok_r(NULL, "/", &sp);
+
+ if (!sys_name) {
+ show_error(error_str, "No filter found");
+ /* This can only happen when events is NULL, but still */
+ free_events(events);
+ free(this_event);
+ return -1;
+ }
+
+ /* Find this event */
+ ret = find_event(pevent, &events, strim(sys_name), strim(event_name));
+ if (ret < 0) {
+ if (event_name)
+ show_error(error_str,
+ "No event found under '%s.%s'",
+ sys_name, event_name);
+ else
+ show_error(error_str,
+ "No event found under '%s'",
+ sys_name);
+ free_events(events);
+ free(this_event);
+ return -1;
+ }
+ free(this_event);
+ } while (filter_str);
+
+ /* Skip the ':' */
+ if (filter_start)
+ filter_start++;
+
+ /* filter starts here */
+ for (event = events; event; event = event->next) {
+ ret = filter_event(filter, event->event, filter_start,
+ error_str);
+ /* Failures are returned if a parse error happened */
+ if (ret < 0)
+ rtn = ret;
+
+ if (ret >= 0 && pevent->test_filters) {
+ char *test;
+ test = pevent_filter_make_string(filter, event->event->id);
+ printf(" '%s: %s'\n", event->event->name, test);
+ free(test);
+ }
+ }
+
+ free_events(events);
+
+ if (rtn >= 0 && pevent->test_filters)
+ exit(0);
+
+ return rtn;
+}
+
+static void free_filter_type(struct filter_type *filter_type)
+{
+ free_arg(filter_type->filter);
+}
+
+/**
+ * pevent_filter_remove_event - remove a filter for an event
+ * @filter: the event filter to remove from
+ * @event_id: the event to remove a filter for
+ *
+ * Removes the filter saved for an event defined by @event_id
+ * from the @filter.
+ *
+ * Returns 1: if an event was removed
+ * 0: if the event was not found
+ */
+int pevent_filter_remove_event(struct event_filter *filter,
+ int event_id)
+{
+ struct filter_type *filter_type;
+ unsigned long len;
+
+ if (!filter->filters)
+ return 0;
+
+ filter_type = find_filter_type(filter, event_id);
+
+ if (!filter_type)
+ return 0;
+
+ free_filter_type(filter_type);
+
+ /* The filter_type points into the event_filters array */
+ len = (unsigned long)(filter->event_filters + filter->filters) -
+ (unsigned long)(filter_type + 1);
+
+ memmove(filter_type, filter_type + 1, len);
+ filter->filters--;
+
+ memset(&filter->event_filters[filter->filters], 0,
+ sizeof(*filter_type));
+
+ return 1;
+}
+
+/**
+ * pevent_filter_reset - clear all filters in a filter
+ * @filter: the event filter to reset
+ *
+ * Removes all filters from a filter and resets it.
+ */
+void pevent_filter_reset(struct event_filter *filter)
+{
+ int i;
+
+ for (i = 0; i < filter->filters; i++)
+ free_filter_type(&filter->event_filters[i]);
+
+ free(filter->event_filters);
+ filter->filters = 0;
+ filter->event_filters = NULL;
+}
+
+void pevent_filter_free(struct event_filter *filter)
+{
+ pevent_unref(filter->pevent);
+
+ pevent_filter_reset(filter);
+
+ free(filter);
+}
+
+static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg);
+
+static int copy_filter_type(struct event_filter *filter,
+ struct event_filter *source,
+ struct filter_type *filter_type)
+{
+ struct filter_arg *arg;
+ struct event_format *event;
+ const char *sys;
+ const char *name;
+ char *str;
+
+ /* Can't assume that the pevent's are the same */
+ sys = filter_type->event->system;
+ name = filter_type->event->name;
+ event = pevent_find_event_by_name(filter->pevent, sys, name);
+ if (!event)
+ return -1;
+
+ str = arg_to_str(source, filter_type->filter);
+ if (!str)
+ return -1;
+
+ if (strcmp(str, "TRUE") == 0 || strcmp(str, "FALSE") == 0) {
+ /* Add trivial event */
+ arg = allocate_arg();
+ arg->type = FILTER_ARG_BOOLEAN;
+ if (strcmp(str, "TRUE") == 0)
+ arg->boolean.value = 1;
+ else
+ arg->boolean.value = 0;
+
+ filter_type = add_filter_type(filter, event->id);
+ filter_type->filter = arg;
+
+ free(str);
+ return 0;
+ }
+
+ filter_event(filter, event, str, NULL);
+ free(str);
+
+ return 0;
+}
+
+/**
+ * pevent_filter_copy - copy a filter using another filter
+ * @dest - the filter to copy to
+ * @source - the filter to copy from
+ *
+ * Returns 0 on success and -1 if not all filters were copied
+ */
+int pevent_filter_copy(struct event_filter *dest, struct event_filter *source)
+{
+ int ret = 0;
+ int i;
+
+ pevent_filter_reset(dest);
+
+ for (i = 0; i < source->filters; i++) {
+ if (copy_filter_type(dest, source, &source->event_filters[i]))
+ ret = -1;
+ }
+ return ret;
+}
+
+
+/**
+ * pevent_update_trivial - update the trivial filters with the given filter
+ * @dest - the filter to update
+ * @source - the filter as the source of the update
+ * @type - the type of trivial filter to update.
+ *
+ * Scan dest for trivial events matching @type to replace with the source.
+ *
+ * Returns 0 on success and -1 if there was a problem updating, but
+ * events may have still been updated on error.
+ */
+int pevent_update_trivial(struct event_filter *dest, struct event_filter *source,
+ enum filter_trivial_type type)
+{
+ struct pevent *src_pevent;
+ struct pevent *dest_pevent;
+ struct event_format *event;
+ struct filter_type *filter_type;
+ struct filter_arg *arg;
+ char *str;
+ int i;
+
+ src_pevent = source->pevent;
+ dest_pevent = dest->pevent;
+
+ /* Do nothing if either of the filters has nothing to filter */
+ if (!dest->filters || !source->filters)
+ return 0;
+
+ for (i = 0; i < dest->filters; i++) {
+ filter_type = &dest->event_filters[i];
+ arg = filter_type->filter;
+ if (arg->type != FILTER_ARG_BOOLEAN)
+ continue;
+ if ((arg->boolean.value && type == FILTER_TRIVIAL_FALSE) ||
+ (!arg->boolean.value && type == FILTER_TRIVIAL_TRUE))
+ continue;
+
+ event = filter_type->event;
+
+ if (src_pevent != dest_pevent) {
+ /* do a look up */
+ event = pevent_find_event_by_name(src_pevent,
+ event->system,
+ event->name);
+ if (!event)
+ return -1;
+ }
+
+ str = pevent_filter_make_string(source, event->id);
+ if (!str)
+ continue;
+
+ /* Don't bother if the filter is trivial too */
+ if (strcmp(str, "TRUE") != 0 && strcmp(str, "FALSE") != 0)
+ filter_event(dest, event, str, NULL);
+ free(str);
+ }
+ return 0;
+}
+
+/**
+ * pevent_filter_clear_trivial - clear TRUE and FALSE filters
+ * @filter: the filter to remove trivial filters from
+ * @type: remove only true, false, or both
+ *
+ * Removes filters that only contain a TRUE or FALES boolean arg.
+ */
+void pevent_filter_clear_trivial(struct event_filter *filter,
+ enum filter_trivial_type type)
+{
+ struct filter_type *filter_type;
+ int count = 0;
+ int *ids;
+ int i;
+
+ if (!filter->filters)
+ return;
+
+ /*
+ * Two steps, first get all ids with trivial filters.
+ * then remove those ids.
+ */
+ for (i = 0; i < filter->filters; i++) {
+ filter_type = &filter->event_filters[i];
+ if (filter_type->filter->type != FILTER_ARG_BOOLEAN)
+ continue;
+ switch (type) {
+ case FILTER_TRIVIAL_FALSE:
+ if (filter_type->filter->boolean.value)
+ continue;
+ case FILTER_TRIVIAL_TRUE:
+ if (!filter_type->filter->boolean.value)
+ continue;
+ default:
+ break;
+ }
+ if (count)
+ ids = realloc(ids, sizeof(*ids) * (count + 1));
+ else
+ ids = malloc(sizeof(*ids));
+ if (!ids)
+ die("Can't allocate ids");
+ ids[count++] = filter_type->event_id;
+ }
+
+ if (!count)
+ return;
+
+ for (i = 0; i < count; i++)
+ pevent_filter_remove_event(filter, ids[i]);
+
+ free(ids);
+}
+
+/**
+ * pevent_filter_event_has_trivial - return true event contains trivial filter
+ * @filter: the filter with the information
+ * @event_id: the id of the event to test
+ * @type: trivial type to test for (TRUE, FALSE, EITHER)
+ *
+ * Returns 1 if the event contains a matching trivial type
+ * otherwise 0.
+ */
+int pevent_filter_event_has_trivial(struct event_filter *filter,
+ int event_id,
+ enum filter_trivial_type type)
+{
+ struct filter_type *filter_type;
+
+ if (!filter->filters)
+ return 0;
+
+ filter_type = find_filter_type(filter, event_id);
+
+ if (!filter_type)
+ return 0;
+
+ if (filter_type->filter->type != FILTER_ARG_BOOLEAN)
+ return 0;
+
+ switch (type) {
+ case FILTER_TRIVIAL_FALSE:
+ return !filter_type->filter->boolean.value;
+
+ case FILTER_TRIVIAL_TRUE:
+ return filter_type->filter->boolean.value;
+ default:
+ return 1;
+ }
+}
+
+static int test_filter(struct event_format *event,
+ struct filter_arg *arg, struct pevent_record *record);
+
+static const char *
+get_comm(struct event_format *event, struct pevent_record *record)
+{
+ const char *comm;
+ int pid;
+
+ pid = pevent_data_pid(event->pevent, record);
+ comm = pevent_data_comm_from_pid(event->pevent, pid);
+ return comm;
+}
+
+static unsigned long long
+get_value(struct event_format *event,
+ struct format_field *field, struct pevent_record *record)
+{
+ unsigned long long val;
+
+ /* Handle our dummy "comm" field */
+ if (field == &comm) {
+ const char *name;
+
+ name = get_comm(event, record);
+ return (unsigned long long)name;
+ }
+
+ pevent_read_number_field(field, record->data, &val);
+
+ if (!(field->flags & FIELD_IS_SIGNED))
+ return val;
+
+ switch (field->size) {
+ case 1:
+ return (char)val;
+ case 2:
+ return (short)val;
+ case 4:
+ return (int)val;
+ case 8:
+ return (long long)val;
+ }
+ return val;
+}
+
+static unsigned long long
+get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record);
+
+static unsigned long long
+get_exp_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record)
+{
+ unsigned long long lval, rval;
+
+ lval = get_arg_value(event, arg->exp.left, record);
+ rval = get_arg_value(event, arg->exp.right, record);
+
+ switch (arg->exp.type) {
+ case FILTER_EXP_ADD:
+ return lval + rval;
+
+ case FILTER_EXP_SUB:
+ return lval - rval;
+
+ case FILTER_EXP_MUL:
+ return lval * rval;
+
+ case FILTER_EXP_DIV:
+ return lval / rval;
+
+ case FILTER_EXP_MOD:
+ return lval % rval;
+
+ case FILTER_EXP_RSHIFT:
+ return lval >> rval;
+
+ case FILTER_EXP_LSHIFT:
+ return lval << rval;
+
+ case FILTER_EXP_AND:
+ return lval & rval;
+
+ case FILTER_EXP_OR:
+ return lval | rval;
+
+ case FILTER_EXP_XOR:
+ return lval ^ rval;
+
+ case FILTER_EXP_NOT:
+ default:
+ die("error in exp");
+ }
+ return 0;
+}
+
+static unsigned long long
+get_arg_value(struct event_format *event, struct filter_arg *arg, struct pevent_record *record)
+{
+ switch (arg->type) {
+ case FILTER_ARG_FIELD:
+ return get_value(event, arg->field.field, record);
+
+ case FILTER_ARG_VALUE:
+ if (arg->value.type != FILTER_NUMBER)
+ die("must have number field!");
+ return arg->value.val;
+
+ case FILTER_ARG_EXP:
+ return get_exp_value(event, arg, record);
+
+ default:
+ die("oops in filter");
+ }
+ return 0;
+}
+
+static int test_num(struct event_format *event,
+ struct filter_arg *arg, struct pevent_record *record)
+{
+ unsigned long long lval, rval;
+
+ lval = get_arg_value(event, arg->num.left, record);
+ rval = get_arg_value(event, arg->num.right, record);
+
+ switch (arg->num.type) {
+ case FILTER_CMP_EQ:
+ return lval == rval;
+
+ case FILTER_CMP_NE:
+ return lval != rval;
+
+ case FILTER_CMP_GT:
+ return lval > rval;
+
+ case FILTER_CMP_LT:
+ return lval < rval;
+
+ case FILTER_CMP_GE:
+ return lval >= rval;
+
+ case FILTER_CMP_LE:
+ return lval <= rval;
+
+ default:
+ /* ?? */
+ return 0;
+ }
+}
+
+static const char *get_field_str(struct filter_arg *arg, struct pevent_record *record)
+{
+ const char *val = record->data + arg->str.field->offset;
+
+ /*
+ * We need to copy the data since we can't be sure the field
+ * is null terminated.
+ */
+ if (*(val + arg->str.field->size - 1)) {
+ /* copy it */
+ memcpy(arg->str.buffer, val, arg->str.field->size);
+ /* the buffer is already NULL terminated */
+ val = arg->str.buffer;
+ }
+ return val;
+}
+
+static int test_str(struct event_format *event,
+ struct filter_arg *arg, struct pevent_record *record)
+{
+ const char *val;
+
+ if (arg->str.field == &comm)
+ val = get_comm(event, record);
+ else
+ val = get_field_str(arg, record);
+
+ switch (arg->str.type) {
+ case FILTER_CMP_MATCH:
+ return strcmp(val, arg->str.val) == 0;
+
+ case FILTER_CMP_NOT_MATCH:
+ return strcmp(val, arg->str.val) != 0;
+
+ case FILTER_CMP_REGEX:
+ /* Returns zero on match */
+ return !regexec(&arg->str.reg, val, 0, NULL, 0);
+
+ case FILTER_CMP_NOT_REGEX:
+ return regexec(&arg->str.reg, val, 0, NULL, 0);
+
+ default:
+ /* ?? */
+ return 0;
+ }
+}
+
+static int test_op(struct event_format *event,
+ struct filter_arg *arg, struct pevent_record *record)
+{
+ switch (arg->op.type) {
+ case FILTER_OP_AND:
+ return test_filter(event, arg->op.left, record) &&
+ test_filter(event, arg->op.right, record);
+
+ case FILTER_OP_OR:
+ return test_filter(event, arg->op.left, record) ||
+ test_filter(event, arg->op.right, record);
+
+ case FILTER_OP_NOT:
+ return !test_filter(event, arg->op.right, record);
+
+ default:
+ /* ?? */
+ return 0;
+ }
+}
+
+static int test_filter(struct event_format *event,
+ struct filter_arg *arg, struct pevent_record *record)
+{
+ switch (arg->type) {
+ case FILTER_ARG_BOOLEAN:
+ /* easy case */
+ return arg->boolean.value;
+
+ case FILTER_ARG_OP:
+ return test_op(event, arg, record);
+
+ case FILTER_ARG_NUM:
+ return test_num(event, arg, record);
+
+ case FILTER_ARG_STR:
+ return test_str(event, arg, record);
+
+ case FILTER_ARG_EXP:
+ case FILTER_ARG_VALUE:
+ case FILTER_ARG_FIELD:
+ /*
+ * Expressions, fields and values evaluate
+ * to true if they return non zero
+ */
+ return !!get_arg_value(event, arg, record);
+
+ default:
+ die("oops!");
+ /* ?? */
+ return 0;
+ }
+}
+
+/**
+ * pevent_event_filtered - return true if event has filter
+ * @filter: filter struct with filter information
+ * @event_id: event id to test if filter exists
+ *
+ * Returns 1 if filter found for @event_id
+ * otherwise 0;
+ */
+int pevent_event_filtered(struct event_filter *filter,
+ int event_id)
+{
+ struct filter_type *filter_type;
+
+ if (!filter->filters)
+ return 0;
+
+ filter_type = find_filter_type(filter, event_id);
+
+ return filter_type ? 1 : 0;
+}
+
+/**
+ * pevent_filter_match - test if a record matches a filter
+ * @filter: filter struct with filter information
+ * @record: the record to test against the filter
+ *
+ * Returns:
+ * 1 - filter found for event and @record matches
+ * 0 - filter found for event and @record does not match
+ * -1 - no filter found for @record's event
+ * -2 - if no filters exist
+ */
+int pevent_filter_match(struct event_filter *filter,
+ struct pevent_record *record)
+{
+ struct pevent *pevent = filter->pevent;
+ struct filter_type *filter_type;
+ int event_id;
+
+ if (!filter->filters)
+ return FILTER_NONE;
+
+ event_id = pevent_data_type(pevent, record);
+
+ filter_type = find_filter_type(filter, event_id);
+
+ if (!filter_type)
+ return FILTER_NOEXIST;
+
+ return test_filter(filter_type->event, filter_type->filter, record) ?
+ FILTER_MATCH : FILTER_MISS;
+}
+
+static char *op_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+ char *str = NULL;
+ char *left = NULL;
+ char *right = NULL;
+ char *op = NULL;
+ int left_val = -1;
+ int right_val = -1;
+ int val;
+ int len;
+
+ switch (arg->op.type) {
+ case FILTER_OP_AND:
+ op = "&&";
+ /* fall through */
+ case FILTER_OP_OR:
+ if (!op)
+ op = "||";
+
+ left = arg_to_str(filter, arg->op.left);
+ right = arg_to_str(filter, arg->op.right);
+ if (!left || !right)
+ break;
+
+ /* Try to consolidate boolean values */
+ if (strcmp(left, "TRUE") == 0)
+ left_val = 1;
+ else if (strcmp(left, "FALSE") == 0)
+ left_val = 0;
+
+ if (strcmp(right, "TRUE") == 0)
+ right_val = 1;
+ else if (strcmp(right, "FALSE") == 0)
+ right_val = 0;
+
+ if (left_val >= 0) {
+ if ((arg->op.type == FILTER_OP_AND && !left_val) ||
+ (arg->op.type == FILTER_OP_OR && left_val)) {
+ /* Just return left value */
+ str = left;
+ left = NULL;
+ break;
+ }
+ if (right_val >= 0) {
+ /* just evaluate this. */
+ val = 0;
+ switch (arg->op.type) {
+ case FILTER_OP_AND:
+ val = left_val && right_val;
+ break;
+ case FILTER_OP_OR:
+ val = left_val || right_val;
+ break;
+ default:
+ break;
+ }
+ str = malloc_or_die(6);
+ if (val)
+ strcpy(str, "TRUE");
+ else
+ strcpy(str, "FALSE");
+ break;
+ }
+ }
+ if (right_val >= 0) {
+ if ((arg->op.type == FILTER_OP_AND && !right_val) ||
+ (arg->op.type == FILTER_OP_OR && right_val)) {
+ /* Just return right value */
+ str = right;
+ right = NULL;
+ break;
+ }
+ /* The right value is meaningless */
+ str = left;
+ left = NULL;
+ break;
+ }
+
+ len = strlen(left) + strlen(right) + strlen(op) + 10;
+ str = malloc_or_die(len);
+ snprintf(str, len, "(%s) %s (%s)",
+ left, op, right);
+ break;
+
+ case FILTER_OP_NOT:
+ op = "!";
+ right = arg_to_str(filter, arg->op.right);
+ if (!right)
+ break;
+
+ /* See if we can consolidate */
+ if (strcmp(right, "TRUE") == 0)
+ right_val = 1;
+ else if (strcmp(right, "FALSE") == 0)
+ right_val = 0;
+ if (right_val >= 0) {
+ /* just return the opposite */
+ str = malloc_or_die(6);
+ if (right_val)
+ strcpy(str, "FALSE");
+ else
+ strcpy(str, "TRUE");
+ break;
+ }
+ len = strlen(right) + strlen(op) + 3;
+ str = malloc_or_die(len);
+ snprintf(str, len, "%s(%s)", op, right);
+ break;
+
+ default:
+ /* ?? */
+ break;
+ }
+ free(left);
+ free(right);
+ return str;
+}
+
+static char *val_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+ char *str;
+
+ str = malloc_or_die(30);
+
+ snprintf(str, 30, "%lld", arg->value.val);
+
+ return str;
+}
+
+static char *field_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+ return strdup(arg->field.field->name);
+}
+
+static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+ char *lstr;
+ char *rstr;
+ char *op;
+ char *str;
+ int len;
+
+ lstr = arg_to_str(filter, arg->exp.left);
+ rstr = arg_to_str(filter, arg->exp.right);
+
+ switch (arg->exp.type) {
+ case FILTER_EXP_ADD:
+ op = "+";
+ break;
+ case FILTER_EXP_SUB:
+ op = "-";
+ break;
+ case FILTER_EXP_MUL:
+ op = "*";
+ break;
+ case FILTER_EXP_DIV:
+ op = "/";
+ break;
+ case FILTER_EXP_MOD:
+ op = "%";
+ break;
+ case FILTER_EXP_RSHIFT:
+ op = ">>";
+ break;
+ case FILTER_EXP_LSHIFT:
+ op = "<<";
+ break;
+ case FILTER_EXP_AND:
+ op = "&";
+ break;
+ case FILTER_EXP_OR:
+ op = "|";
+ break;
+ case FILTER_EXP_XOR:
+ op = "^";
+ break;
+ default:
+ die("oops in exp");
+ }
+
+ len = strlen(op) + strlen(lstr) + strlen(rstr) + 4;
+ str = malloc_or_die(len);
+ snprintf(str, len, "%s %s %s", lstr, op, rstr);
+ free(lstr);
+ free(rstr);
+
+ return str;
+}
+
+static char *num_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+ char *lstr;
+ char *rstr;
+ char *str = NULL;
+ char *op = NULL;
+ int len;
+
+ lstr = arg_to_str(filter, arg->num.left);
+ rstr = arg_to_str(filter, arg->num.right);
+
+ switch (arg->num.type) {
+ case FILTER_CMP_EQ:
+ op = "==";
+ /* fall through */
+ case FILTER_CMP_NE:
+ if (!op)
+ op = "!=";
+ /* fall through */
+ case FILTER_CMP_GT:
+ if (!op)
+ op = ">";
+ /* fall through */
+ case FILTER_CMP_LT:
+ if (!op)
+ op = "<";
+ /* fall through */
+ case FILTER_CMP_GE:
+ if (!op)
+ op = ">=";
+ /* fall through */
+ case FILTER_CMP_LE:
+ if (!op)
+ op = "<=";
+
+ len = strlen(lstr) + strlen(op) + strlen(rstr) + 4;
+ str = malloc_or_die(len);
+ sprintf(str, "%s %s %s", lstr, op, rstr);
+
+ break;
+
+ default:
+ /* ?? */
+ break;
+ }
+
+ free(lstr);
+ free(rstr);
+ return str;
+}
+
+static char *str_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+ char *str = NULL;
+ char *op = NULL;
+ int len;
+
+ switch (arg->str.type) {
+ case FILTER_CMP_MATCH:
+ op = "==";
+ /* fall through */
+ case FILTER_CMP_NOT_MATCH:
+ if (!op)
+ op = "!=";
+ /* fall through */
+ case FILTER_CMP_REGEX:
+ if (!op)
+ op = "=~";
+ /* fall through */
+ case FILTER_CMP_NOT_REGEX:
+ if (!op)
+ op = "!~";
+
+ len = strlen(arg->str.field->name) + strlen(op) +
+ strlen(arg->str.val) + 6;
+ str = malloc_or_die(len);
+ snprintf(str, len, "%s %s \"%s\"",
+ arg->str.field->name,
+ op, arg->str.val);
+ break;
+
+ default:
+ /* ?? */
+ break;
+ }
+ return str;
+}
+
+static char *arg_to_str(struct event_filter *filter, struct filter_arg *arg)
+{
+ char *str;
+
+ switch (arg->type) {
+ case FILTER_ARG_BOOLEAN:
+ str = malloc_or_die(6);
+ if (arg->boolean.value)
+ strcpy(str, "TRUE");
+ else
+ strcpy(str, "FALSE");
+ return str;
+
+ case FILTER_ARG_OP:
+ return op_to_str(filter, arg);
+
+ case FILTER_ARG_NUM:
+ return num_to_str(filter, arg);
+
+ case FILTER_ARG_STR:
+ return str_to_str(filter, arg);
+
+ case FILTER_ARG_VALUE:
+ return val_to_str(filter, arg);
+
+ case FILTER_ARG_FIELD:
+ return field_to_str(filter, arg);
+
+ case FILTER_ARG_EXP:
+ return exp_to_str(filter, arg);
+
+ default:
+ /* ?? */
+ return NULL;
+ }
+
+}
+
+/**
+ * pevent_filter_make_string - return a string showing the filter
+ * @filter: filter struct with filter information
+ * @event_id: the event id to return the filter string with
+ *
+ * Returns a string that displays the filter contents.
+ * This string must be freed with free(str).
+ * NULL is returned if no filter is found.
+ */
+char *
+pevent_filter_make_string(struct event_filter *filter, int event_id)
+{
+ struct filter_type *filter_type;
+
+ if (!filter->filters)
+ return NULL;
+
+ filter_type = find_filter_type(filter, event_id);
+
+ if (!filter_type)
+ return NULL;
+
+ return arg_to_str(filter, filter_type->filter);
+}
+
+/**
+ * pevent_filter_compare - compare two filters and return if they are the same
+ * @filter1: Filter to compare with @filter2
+ * @filter2: Filter to compare with @filter1
+ *
+ * Returns:
+ * 1 if the two filters hold the same content.
+ * 0 if they do not.
+ */
+int pevent_filter_compare(struct event_filter *filter1, struct event_filter *filter2)
+{
+ struct filter_type *filter_type1;
+ struct filter_type *filter_type2;
+ char *str1, *str2;
+ int result;
+ int i;
+
+ /* Do the easy checks first */
+ if (filter1->filters != filter2->filters)
+ return 0;
+ if (!filter1->filters && !filter2->filters)
+ return 1;
+
+ /*
+ * Now take a look at each of the events to see if they have the same
+ * filters to them.
+ */
+ for (i = 0; i < filter1->filters; i++) {
+ filter_type1 = &filter1->event_filters[i];
+ filter_type2 = find_filter_type(filter2, filter_type1->event_id);
+ if (!filter_type2)
+ break;
+ if (filter_type1->filter->type != filter_type2->filter->type)
+ break;
+ switch (filter_type1->filter->type) {
+ case FILTER_TRIVIAL_FALSE:
+ case FILTER_TRIVIAL_TRUE:
+ /* trivial types just need the type compared */
+ continue;
+ default:
+ break;
+ }
+ /* The best way to compare complex filters is with strings */
+ str1 = arg_to_str(filter1, filter_type1->filter);
+ str2 = arg_to_str(filter2, filter_type2->filter);
+ result = strcmp(str1, str2) != 0;
+ free(str1);
+ free(str2);
+ if (result)
+ break;
+ }
+
+ if (i < filter1->filters)
+ return 0;
+ return 1;
+}
+
diff --git a/tools/lib/traceevent/parse-utils.c b/tools/lib/traceevent/parse-utils.c
new file mode 100644
index 000000000000..f023a133abb6
--- /dev/null
+++ b/tools/lib/traceevent/parse-utils.c
@@ -0,0 +1,110 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#define __weak __attribute__((weak))
+
+void __vdie(const char *fmt, va_list ap)
+{
+ int ret = errno;
+
+ if (errno)
+ perror("trace-cmd");
+ else
+ ret = -1;
+
+ fprintf(stderr, " ");
+ vfprintf(stderr, fmt, ap);
+
+ fprintf(stderr, "\n");
+ exit(ret);
+}
+
+void __die(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ __vdie(fmt, ap);
+ va_end(ap);
+}
+
+void __weak die(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ __vdie(fmt, ap);
+ va_end(ap);
+}
+
+void __vwarning(const char *fmt, va_list ap)
+{
+ if (errno)
+ perror("trace-cmd");
+ errno = 0;
+
+ fprintf(stderr, " ");
+ vfprintf(stderr, fmt, ap);
+
+ fprintf(stderr, "\n");
+}
+
+void __warning(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ __vwarning(fmt, ap);
+ va_end(ap);
+}
+
+void __weak warning(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ __vwarning(fmt, ap);
+ va_end(ap);
+}
+
+void __vpr_stat(const char *fmt, va_list ap)
+{
+ vprintf(fmt, ap);
+ printf("\n");
+}
+
+void __pr_stat(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ __vpr_stat(fmt, ap);
+ va_end(ap);
+}
+
+void __weak vpr_stat(const char *fmt, va_list ap)
+{
+ __vpr_stat(fmt, ap);
+}
+
+void __weak pr_stat(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ __vpr_stat(fmt, ap);
+ va_end(ap);
+}
+
+void __weak *malloc_or_die(unsigned int size)
+{
+ void *data;
+
+ data = malloc(size);
+ if (!data)
+ die("malloc");
+ return data;
+}
diff --git a/tools/lib/traceevent/trace-seq.c b/tools/lib/traceevent/trace-seq.c
new file mode 100644
index 000000000000..b1ccc923e8a5
--- /dev/null
+++ b/tools/lib/traceevent/trace-seq.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2009 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License (not later!)
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "event-parse.h"
+#include "event-utils.h"
+
+/*
+ * The TRACE_SEQ_POISON is to catch the use of using
+ * a trace_seq structure after it was destroyed.
+ */
+#define TRACE_SEQ_POISON ((void *)0xdeadbeef)
+#define TRACE_SEQ_CHECK(s) \
+do { \
+ if ((s)->buffer == TRACE_SEQ_POISON) \
+ die("Usage of trace_seq after it was destroyed"); \
+} while (0)
+
+/**
+ * trace_seq_init - initialize the trace_seq structure
+ * @s: a pointer to the trace_seq structure to initialize
+ */
+void trace_seq_init(struct trace_seq *s)
+{
+ s->len = 0;
+ s->readpos = 0;
+ s->buffer_size = TRACE_SEQ_BUF_SIZE;
+ s->buffer = malloc_or_die(s->buffer_size);
+}
+
+/**
+ * trace_seq_destroy - free up memory of a trace_seq
+ * @s: a pointer to the trace_seq to free the buffer
+ *
+ * Only frees the buffer, not the trace_seq struct itself.
+ */
+void trace_seq_destroy(struct trace_seq *s)
+{
+ if (!s)
+ return;
+ TRACE_SEQ_CHECK(s);
+ free(s->buffer);
+ s->buffer = TRACE_SEQ_POISON;
+}
+
+static void expand_buffer(struct trace_seq *s)
+{
+ s->buffer_size += TRACE_SEQ_BUF_SIZE;
+ s->buffer = realloc(s->buffer, s->buffer_size);
+ if (!s->buffer)
+ die("Can't allocate trace_seq buffer memory");
+}
+
+/**
+ * trace_seq_printf - sequence printing of trace information
+ * @s: trace sequence descriptor
+ * @fmt: printf format string
+ *
+ * It returns 0 if the trace oversizes the buffer's free
+ * space, 1 otherwise.
+ *
+ * The tracer may use either sequence operations or its own
+ * copy to user routines. To simplify formating of a trace
+ * trace_seq_printf is used to store strings into a special
+ * buffer (@s). Then the output may be either used by
+ * the sequencer or pulled into another buffer.
+ */
+int
+trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
+{
+ va_list ap;
+ int len;
+ int ret;
+
+ TRACE_SEQ_CHECK(s);
+
+ try_again:
+ len = (s->buffer_size - 1) - s->len;
+
+ va_start(ap, fmt);
+ ret = vsnprintf(s->buffer + s->len, len, fmt, ap);
+ va_end(ap);
+
+ if (ret >= len) {
+ expand_buffer(s);
+ goto try_again;
+ }
+
+ s->len += ret;
+
+ return 1;
+}
+
+/**
+ * trace_seq_vprintf - sequence printing of trace information
+ * @s: trace sequence descriptor
+ * @fmt: printf format string
+ *
+ * The tracer may use either sequence operations or its own
+ * copy to user routines. To simplify formating of a trace
+ * trace_seq_printf is used to store strings into a special
+ * buffer (@s). Then the output may be either used by
+ * the sequencer or pulled into another buffer.
+ */
+int
+trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
+{
+ int len;
+ int ret;
+
+ TRACE_SEQ_CHECK(s);
+
+ try_again:
+ len = (s->buffer_size - 1) - s->len;
+
+ ret = vsnprintf(s->buffer + s->len, len, fmt, args);
+
+ if (ret >= len) {
+ expand_buffer(s);
+ goto try_again;
+ }
+
+ s->len += ret;
+
+ return len;
+}
+
+/**
+ * trace_seq_puts - trace sequence printing of simple string
+ * @s: trace sequence descriptor
+ * @str: simple string to record
+ *
+ * The tracer may use either the sequence operations or its own
+ * copy to user routines. This function records a simple string
+ * into a special buffer (@s) for later retrieval by a sequencer
+ * or other mechanism.
+ */
+int trace_seq_puts(struct trace_seq *s, const char *str)
+{
+ int len;
+
+ TRACE_SEQ_CHECK(s);
+
+ len = strlen(str);
+
+ while (len > ((s->buffer_size - 1) - s->len))
+ expand_buffer(s);
+
+ memcpy(s->buffer + s->len, str, len);
+ s->len += len;
+
+ return len;
+}
+
+int trace_seq_putc(struct trace_seq *s, unsigned char c)
+{
+ TRACE_SEQ_CHECK(s);
+
+ while (s->len >= (s->buffer_size - 1))
+ expand_buffer(s);
+
+ s->buffer[s->len++] = c;
+
+ return 1;
+}
+
+void trace_seq_terminate(struct trace_seq *s)
+{
+ TRACE_SEQ_CHECK(s);
+
+ /* There's always one character left on the buffer */
+ s->buffer[s->len] = 0;
+}
+
+int trace_seq_do_printf(struct trace_seq *s)
+{
+ TRACE_SEQ_CHECK(s);
+ return printf("%.*s", s->len, s->buffer);
+}
diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt
index 0507ec7bad71..15217345c2fa 100644
--- a/tools/perf/Documentation/perf-evlist.txt
+++ b/tools/perf/Documentation/perf-evlist.txt
@@ -20,6 +20,14 @@ OPTIONS
--input=::
Input file name. (default: perf.data unless stdin is a fifo)
+-F::
+--freq=::
+ Show just the sample frequency used for each event.
+
+-v::
+--verbose=::
+ Show all fields.
+
SEE ALSO
--------
linkperf:perf-record[1], linkperf:perf-list[1],
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 2780d9ce48bf..b715cb71592b 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -77,7 +77,8 @@ OPTIONS
-F::
--funcs::
- Show available functions in given module or kernel.
+ Show available functions in given module or kernel. With -x/--exec,
+ can also list functions in a user space executable / shared library.
--filter=FILTER::
(Only for --vars and --funcs) Set filter. FILTER is a combination of glob
@@ -98,6 +99,15 @@ OPTIONS
--max-probes::
Set the maximum number of probe points for an event. Default is 128.
+-x::
+--exec=PATH::
+ Specify path to the executable or shared library file for user
+ space tracing. Can also be used with --funcs option.
+
+In absence of -m/-x options, perf probe checks if the first argument after
+the options is an absolute path name. If its an absolute path, perf probe
+uses it as a target module/target user space binary to probe.
+
PROBE SYNTAX
------------
Probe points are defined by following syntax.
@@ -182,6 +192,13 @@ Delete all probes on schedule().
./perf probe --del='schedule*'
+Add probes at zfree() function on /bin/zsh
+
+ ./perf probe -x /bin/zsh zfree or ./perf probe /bin/zsh zfree
+
+Add probes at malloc() function on libc
+
+ ./perf probe -x /lib/libc.so.6 malloc or ./perf probe /lib/libc.so.6 malloc
SEE ALSO
--------
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index a1386b2fff00..b38a1f9ad460 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -168,7 +168,7 @@ following filters are defined:
- any: any type of branches
- any_call: any function call or system call
- any_ret: any function return or system call return
- - any_ind: any indirect branch
+ - ind_call: any indirect branch
- u: only when the branch target is at the user level
- k: only when the branch target is in the kernel
- hv: only when the target is at the hypervisor level
diff --git a/tools/perf/Documentation/perfconfig.example b/tools/perf/Documentation/perfconfig.example
index d1448668f4d4..42c6fd2ae85d 100644
--- a/tools/perf/Documentation/perfconfig.example
+++ b/tools/perf/Documentation/perfconfig.example
@@ -6,6 +6,7 @@
normal = black, lightgray
selected = lightgray, magenta
code = blue, lightgray
+ addr = magenta, lightgray
[tui]
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 92271d32bc30..1d3d513beb9b 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -1,18 +1,10 @@
-ifeq ("$(origin O)", "command line")
- OUTPUT := $(O)/
-endif
+include ../scripts/Makefile.include
# The default target of this Makefile is...
all:
include config/utilities.mak
-ifneq ($(OUTPUT),)
-# check that the output directory actually exists
-OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
-$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
-endif
-
# Define V to have a more verbose compile.
#
# Define O to save output files in a separate directory.
@@ -84,31 +76,6 @@ ifneq ($(WERROR),0)
CFLAGS_WERROR := -Werror
endif
-#
-# Include saner warnings here, which can catch bugs:
-#
-
-EXTRA_WARNINGS := -Wformat
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-security
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-y2k
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wshadow
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Winit-self
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wpacked
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wredundant-decls
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-aliasing=3
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-default
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-enum
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wno-system-headers
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wundef
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wwrite-strings
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wbad-function-cast
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-declarations
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-prototypes
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wnested-externs
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wold-style-definition
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement
-
ifeq ("$(origin DEBUG)", "command line")
PERF_DEBUG = $(DEBUG)
endif
@@ -116,7 +83,13 @@ ifndef PERF_DEBUG
CFLAGS_OPTIMIZE = -O6
endif
-CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
+ifdef PARSER_DEBUG
+ PARSER_DEBUG_BISON := -t
+ PARSER_DEBUG_FLEX := -d
+ PARSER_DEBUG_CFLAGS := -DPARSER_DEBUG
+endif
+
+CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) $(PARSER_DEBUG_CFLAGS)
EXTLIBS = -lpthread -lrt -lelf -lm
ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
ALL_LDFLAGS = $(LDFLAGS)
@@ -182,7 +155,7 @@ endif
### --- END CONFIGURATION SECTION ---
-BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)/util -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
+BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)/util -I$(TRACE_EVENT_DIR) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
BASIC_LDFLAGS =
# Guard against environment variables
@@ -211,6 +184,17 @@ $(OUTPUT)python/perf.so: $(PYRF_OBJS) $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
+TRACE_EVENT_DIR = ../lib/traceevent/
+
+ifeq ("$(origin O)", "command line")
+ TE_PATH=$(OUTPUT)/
+else
+ TE_PATH=$(TRACE_EVENT_DIR)/
+endif
+
+LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
+TE_LIB := -L$(TE_PATH) -ltraceevent
+
#
# Single 'perf' binary right now:
#
@@ -238,10 +222,10 @@ FLEX = flex
BISON= bison
$(OUTPUT)util/parse-events-flex.c: util/parse-events.l
- $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
+ $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
$(OUTPUT)util/parse-events-bison.c: util/parse-events.y
- $(QUIET_BISON)$(BISON) -v util/parse-events.y -d -o $(OUTPUT)util/parse-events-bison.c
+ $(QUIET_BISON)$(BISON) -v util/parse-events.y -d $(PARSER_DEBUG_BISON) -o $(OUTPUT)util/parse-events-bison.c
$(OUTPUT)util/pmu-flex.c: util/pmu.l
$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c
@@ -333,6 +317,8 @@ LIB_H += util/cpumap.h
LIB_H += util/top.h
LIB_H += $(ARCH_INCLUDE)
LIB_H += util/cgroup.h
+LIB_H += $(TRACE_EVENT_DIR)event-parse.h
+LIB_H += util/target.h
LIB_OBJS += $(OUTPUT)util/abspath.o
LIB_OBJS += $(OUTPUT)util/alias.o
@@ -352,6 +338,7 @@ LIB_OBJS += $(OUTPUT)util/help.o
LIB_OBJS += $(OUTPUT)util/levenshtein.o
LIB_OBJS += $(OUTPUT)util/parse-options.o
LIB_OBJS += $(OUTPUT)util/parse-events.o
+LIB_OBJS += $(OUTPUT)util/parse-events-test.o
LIB_OBJS += $(OUTPUT)util/path.o
LIB_OBJS += $(OUTPUT)util/rbtree.o
LIB_OBJS += $(OUTPUT)util/bitmap.o
@@ -394,6 +381,7 @@ LIB_OBJS += $(OUTPUT)util/util.o
LIB_OBJS += $(OUTPUT)util/xyarray.o
LIB_OBJS += $(OUTPUT)util/cpumap.o
LIB_OBJS += $(OUTPUT)util/cgroup.o
+LIB_OBJS += $(OUTPUT)util/target.o
BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
@@ -429,7 +417,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
BUILTIN_OBJS += $(OUTPUT)builtin-test.o
BUILTIN_OBJS += $(OUTPUT)builtin-inject.o
-PERFLIBS = $(LIB_FILE)
+PERFLIBS = $(LIB_FILE) $(LIBTRACEEVENT)
# Files needed for the python binding, perf.so
# pyrf is just an internal name needed for all those wrappers.
@@ -506,22 +494,23 @@ else
# Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
BASIC_CFLAGS += -I/usr/include/slang
EXTLIBS += -lnewt -lslang
- LIB_OBJS += $(OUTPUT)util/ui/setup.o
- LIB_OBJS += $(OUTPUT)util/ui/browser.o
- LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o
- LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o
- LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o
- LIB_OBJS += $(OUTPUT)util/ui/helpline.o
- LIB_OBJS += $(OUTPUT)util/ui/progress.o
- LIB_OBJS += $(OUTPUT)util/ui/util.o
- LIB_H += util/ui/browser.h
- LIB_H += util/ui/browsers/map.h
- LIB_H += util/ui/helpline.h
- LIB_H += util/ui/keysyms.h
- LIB_H += util/ui/libslang.h
- LIB_H += util/ui/progress.h
- LIB_H += util/ui/util.h
- LIB_H += util/ui/ui.h
+ LIB_OBJS += $(OUTPUT)ui/setup.o
+ LIB_OBJS += $(OUTPUT)ui/browser.o
+ LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o
+ LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
+ LIB_OBJS += $(OUTPUT)ui/browsers/map.o
+ LIB_OBJS += $(OUTPUT)ui/helpline.o
+ LIB_OBJS += $(OUTPUT)ui/progress.o
+ LIB_OBJS += $(OUTPUT)ui/util.o
+ LIB_OBJS += $(OUTPUT)ui/tui/setup.o
+ LIB_H += ui/browser.h
+ LIB_H += ui/browsers/map.h
+ LIB_H += ui/helpline.h
+ LIB_H += ui/keysyms.h
+ LIB_H += ui/libslang.h
+ LIB_H += ui/progress.h
+ LIB_H += ui/util.h
+ LIB_H += ui/ui.h
endif
endif
@@ -535,7 +524,12 @@ else
else
BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0)
EXTLIBS += $(shell pkg-config --libs gtk+-2.0)
- LIB_OBJS += $(OUTPUT)util/gtk/browser.o
+ LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
+ LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
+ # Make sure that it'd be included only once.
+ ifneq ($(findstring -DNO_NEWT_SUPPORT,$(BASIC_CFLAGS)),)
+ LIB_OBJS += $(OUTPUT)ui/setup.o
+ endif
endif
endif
@@ -678,18 +672,6 @@ else
endif
endif
-ifneq ($(findstring $(MAKEFLAGS),s),s)
-ifndef V
- QUIET_CC = @echo ' ' CC $@;
- QUIET_AR = @echo ' ' AR $@;
- QUIET_LINK = @echo ' ' LINK $@;
- QUIET_MKDIR = @echo ' ' MKDIR $@;
- QUIET_GEN = @echo ' ' GEN $@;
- QUIET_FLEX = @echo ' ' FLEX $@;
- QUIET_BISON = @echo ' ' BISON $@;
-endif
-endif
-
ifdef ASCIIDOC8
export ASCIIDOC8
endif
@@ -800,16 +782,16 @@ $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
$(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
-$(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS
+$(OUTPUT)ui/browser.o: ui/browser.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
-$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
+$(OUTPUT)ui/browsers/annotate.o: ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
-$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
+$(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
-$(OUTPUT)util/ui/browsers/map.o: util/ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
+$(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
$(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
@@ -844,6 +826,10 @@ $(sort $(dir $(DIRECTORY_DEPS))):
$(LIB_FILE): $(LIB_OBJS)
$(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
+# libtraceevent.a
+$(LIBTRACEEVENT):
+ $(QUIET_SUBDIR0)$(TRACE_EVENT_DIR) $(QUIET_SUBDIR1) $(COMMAND_O) libtraceevent.a
+
help:
@echo 'Perf make targets:'
@echo ' doc - make *all* documentation (see below)'
@@ -990,6 +976,6 @@ clean:
$(RM) $(OUTPUT)util/*-{bison,flex}*
$(python-clean)
-.PHONY: all install clean strip
+.PHONY: all install clean strip $(LIBTRACEEVENT)
.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
.PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 52480467e9ff..6b2bcfbde150 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -84,7 +84,11 @@ static int perf_session__list_build_ids(void)
if (filename__fprintf_build_id(session->filename, stdout))
goto out;
- if (with_hits)
+ /*
+ * in pipe-mode, the only way to get the buildids is to parse
+ * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
+ */
+ if (with_hits || session->fd_pipe)
perf_session__process_events(session, &build_id__mark_dso_hit_ops);
perf_session__fprintf_dsos_buildid(session, stdout, with_hits);
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index 26760322c4f4..e52d77ec7084 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -15,9 +15,40 @@
#include "util/parse-options.h"
#include "util/session.h"
-static const char *input_name;
+struct perf_attr_details {
+ bool freq;
+ bool verbose;
+};
+
+static int comma_printf(bool *first, const char *fmt, ...)
+{
+ va_list args;
+ int ret = 0;
+
+ if (!*first) {
+ ret += printf(",");
+ } else {
+ ret += printf(":");
+ *first = false;
+ }
+
+ va_start(args, fmt);
+ ret += vprintf(fmt, args);
+ va_end(args);
+ return ret;
+}
+
+static int __if_print(bool *first, const char *field, u64 value)
+{
+ if (value == 0)
+ return 0;
+
+ return comma_printf(first, " %s: %" PRIu64, field, value);
+}
+
+#define if_print(field) __if_print(&first, #field, pos->attr.field)
-static int __cmd_evlist(void)
+static int __cmd_evlist(const char *input_name, struct perf_attr_details *details)
{
struct perf_session *session;
struct perf_evsel *pos;
@@ -26,8 +57,52 @@ static int __cmd_evlist(void)
if (session == NULL)
return -ENOMEM;
- list_for_each_entry(pos, &session->evlist->entries, node)
- printf("%s\n", event_name(pos));
+ list_for_each_entry(pos, &session->evlist->entries, node) {
+ bool first = true;
+
+ printf("%s", event_name(pos));
+
+ if (details->verbose || details->freq) {
+ comma_printf(&first, " sample_freq=%" PRIu64,
+ (u64)pos->attr.sample_freq);
+ }
+
+ if (details->verbose) {
+ if_print(type);
+ if_print(config);
+ if_print(config1);
+ if_print(config2);
+ if_print(size);
+ if_print(sample_type);
+ if_print(read_format);
+ if_print(disabled);
+ if_print(inherit);
+ if_print(pinned);
+ if_print(exclusive);
+ if_print(exclude_user);
+ if_print(exclude_kernel);
+ if_print(exclude_hv);
+ if_print(exclude_idle);
+ if_print(mmap);
+ if_print(comm);
+ if_print(freq);
+ if_print(inherit_stat);
+ if_print(enable_on_exec);
+ if_print(task);
+ if_print(watermark);
+ if_print(precise_ip);
+ if_print(mmap_data);
+ if_print(sample_id_all);
+ if_print(exclude_host);
+ if_print(exclude_guest);
+ if_print(__reserved_1);
+ if_print(wakeup_events);
+ if_print(bp_type);
+ if_print(branch_sample_type);
+ }
+
+ putchar('\n');
+ }
perf_session__delete(session);
return 0;
@@ -38,17 +113,23 @@ static const char * const evlist_usage[] = {
NULL
};
-static const struct option options[] = {
- OPT_STRING('i', "input", &input_name, "file",
- "input file name"),
- OPT_END()
-};
-
int cmd_evlist(int argc, const char **argv, const char *prefix __used)
{
+ struct perf_attr_details details = { .verbose = false, };
+ const char *input_name;
+ const struct option options[] = {
+ OPT_STRING('i', "input", &input_name, "file",
+ "Input file name"),
+ OPT_BOOLEAN('F', "freq", &details.freq,
+ "Show the sample frequency"),
+ OPT_BOOLEAN('v', "verbose", &details.verbose,
+ "Show all event attr details"),
+ OPT_END()
+ };
+
argc = parse_options(argc, argv, options, evlist_usage, 0);
if (argc)
usage_with_options(evlist_usage, options);
- return __cmd_evlist();
+ return __cmd_evlist(input_name, &details);
}
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 09c106193e65..3beab489afc5 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -60,6 +60,11 @@ static int perf_event__repipe_tracing_data_synth(union perf_event *event,
static int perf_event__repipe_attr(union perf_event *event,
struct perf_evlist **pevlist __used)
{
+ int ret;
+ ret = perf_event__process_attr(event, pevlist);
+ if (ret)
+ return ret;
+
return perf_event__repipe_synth(NULL, event, NULL);
}
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 39104c0beea3..547af48deb4f 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -192,7 +192,7 @@ static void insert_caller_stat(unsigned long call_site,
}
static void process_alloc_event(void *data,
- struct event *event,
+ struct event_format *event,
int cpu,
u64 timestamp __used,
struct thread *thread __used,
@@ -253,7 +253,7 @@ static struct alloc_stat *search_alloc_stat(unsigned long ptr,
}
static void process_free_event(void *data,
- struct event *event,
+ struct event_format *event,
int cpu,
u64 timestamp __used,
struct thread *thread __used)
@@ -281,7 +281,7 @@ static void process_free_event(void *data,
static void process_raw_event(union perf_event *raw_event __used, void *data,
int cpu, u64 timestamp, struct thread *thread)
{
- struct event *event;
+ struct event_format *event;
int type;
type = trace_parse_common_type(data);
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index 12c814838993..fd53319de20d 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -356,25 +356,25 @@ struct trace_release_event {
struct trace_lock_handler {
void (*acquire_event)(struct trace_acquire_event *,
- struct event *,
+ struct event_format *,
int cpu,
u64 timestamp,
struct thread *thread);
void (*acquired_event)(struct trace_acquired_event *,
- struct event *,
+ struct event_format *,
int cpu,
u64 timestamp,
struct thread *thread);
void (*contended_event)(struct trace_contended_event *,
- struct event *,
+ struct event_format *,
int cpu,
u64 timestamp,
struct thread *thread);
void (*release_event)(struct trace_release_event *,
- struct event *,
+ struct event_format *,
int cpu,
u64 timestamp,
struct thread *thread);
@@ -416,7 +416,7 @@ enum acquire_flags {
static void
report_lock_acquire_event(struct trace_acquire_event *acquire_event,
- struct event *__event __used,
+ struct event_format *__event __used,
int cpu __used,
u64 timestamp __used,
struct thread *thread __used)
@@ -480,7 +480,7 @@ end:
static void
report_lock_acquired_event(struct trace_acquired_event *acquired_event,
- struct event *__event __used,
+ struct event_format *__event __used,
int cpu __used,
u64 timestamp __used,
struct thread *thread __used)
@@ -536,7 +536,7 @@ end:
static void
report_lock_contended_event(struct trace_contended_event *contended_event,
- struct event *__event __used,
+ struct event_format *__event __used,
int cpu __used,
u64 timestamp __used,
struct thread *thread __used)
@@ -583,7 +583,7 @@ end:
static void
report_lock_release_event(struct trace_release_event *release_event,
- struct event *__event __used,
+ struct event_format *__event __used,
int cpu __used,
u64 timestamp __used,
struct thread *thread __used)
@@ -647,7 +647,7 @@ static struct trace_lock_handler *trace_handler;
static void
process_lock_acquire_event(void *data,
- struct event *event __used,
+ struct event_format *event __used,
int cpu __used,
u64 timestamp __used,
struct thread *thread __used)
@@ -666,7 +666,7 @@ process_lock_acquire_event(void *data,
static void
process_lock_acquired_event(void *data,
- struct event *event __used,
+ struct event_format *event __used,
int cpu __used,
u64 timestamp __used,
struct thread *thread __used)
@@ -684,7 +684,7 @@ process_lock_acquired_event(void *data,
static void
process_lock_contended_event(void *data,
- struct event *event __used,
+ struct event_format *event __used,
int cpu __used,
u64 timestamp __used,
struct thread *thread __used)
@@ -702,7 +702,7 @@ process_lock_contended_event(void *data,
static void
process_lock_release_event(void *data,
- struct event *event __used,
+ struct event_format *event __used,
int cpu __used,
u64 timestamp __used,
struct thread *thread __used)
@@ -721,7 +721,7 @@ process_lock_release_event(void *data,
static void
process_raw_event(void *data, int cpu, u64 timestamp, struct thread *thread)
{
- struct event *event;
+ struct event_format *event;
int type;
type = trace_parse_common_type(data);
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 4935c09dd5b5..e215ae61b2ae 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -54,6 +54,7 @@ static struct {
bool show_ext_vars;
bool show_funcs;
bool mod_events;
+ bool uprobes;
int nevents;
struct perf_probe_event events[MAX_PROBES];
struct strlist *dellist;
@@ -75,6 +76,8 @@ static int parse_probe_event(const char *str)
return -1;
}
+ pev->uprobes = params.uprobes;
+
/* Parse a perf-probe command into event */
ret = parse_perf_probe_command(str, pev);
pr_debug("%d arguments\n", pev->nargs);
@@ -82,21 +85,58 @@ static int parse_probe_event(const char *str)
return ret;
}
+static int set_target(const char *ptr)
+{
+ int found = 0;
+ const char *buf;
+
+ /*
+ * The first argument after options can be an absolute path
+ * to an executable / library or kernel module.
+ *
+ * TODO: Support relative path, and $PATH, $LD_LIBRARY_PATH,
+ * short module name.
+ */
+ if (!params.target && ptr && *ptr == '/') {
+ params.target = ptr;
+ found = 1;
+ buf = ptr + (strlen(ptr) - 3);
+
+ if (strcmp(buf, ".ko"))
+ params.uprobes = true;
+
+ }
+
+ return found;
+}
+
static int parse_probe_event_argv(int argc, const char **argv)
{
- int i, len, ret;
+ int i, len, ret, found_target;
char *buf;
+ found_target = set_target(argv[0]);
+ if (found_target && argc == 1)
+ return 0;
+
/* Bind up rest arguments */
len = 0;
- for (i = 0; i < argc; i++)
+ for (i = 0; i < argc; i++) {
+ if (i == 0 && found_target)
+ continue;
+
len += strlen(argv[i]) + 1;
+ }
buf = zalloc(len + 1);
if (buf == NULL)
return -ENOMEM;
len = 0;
- for (i = 0; i < argc; i++)
+ for (i = 0; i < argc; i++) {
+ if (i == 0 && found_target)
+ continue;
+
len += sprintf(&buf[len], "%s ", argv[i]);
+ }
params.mod_events = true;
ret = parse_probe_event(buf);
free(buf);
@@ -125,6 +165,28 @@ static int opt_del_probe_event(const struct option *opt __used,
return 0;
}
+static int opt_set_target(const struct option *opt, const char *str,
+ int unset __used)
+{
+ int ret = -ENOENT;
+
+ if (str && !params.target) {
+ if (!strcmp(opt->long_name, "exec"))
+ params.uprobes = true;
+#ifdef DWARF_SUPPORT
+ else if (!strcmp(opt->long_name, "module"))
+ params.uprobes = false;
+#endif
+ else
+ return ret;
+
+ params.target = str;
+ ret = 0;
+ }
+
+ return ret;
+}
+
#ifdef DWARF_SUPPORT
static int opt_show_lines(const struct option *opt __used,
const char *str, int unset __used)
@@ -246,9 +308,9 @@ static const struct option options[] = {
"file", "vmlinux pathname"),
OPT_STRING('s', "source", &symbol_conf.source_prefix,
"directory", "path to kernel source"),
- OPT_STRING('m', "module", &params.target,
- "modname|path",
- "target module name (for online) or path (for offline)"),
+ OPT_CALLBACK('m', "module", NULL, "modname|path",
+ "target module name (for online) or path (for offline)",
+ opt_set_target),
#endif
OPT__DRY_RUN(&probe_event_dry_run),
OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
@@ -260,6 +322,8 @@ static const struct option options[] = {
"\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n"
"\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)",
opt_set_filter),
+ OPT_CALLBACK('x', "exec", NULL, "executable|path",
+ "target executable name or path", opt_set_target),
OPT_END()
};
@@ -310,6 +374,10 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
pr_err(" Error: Don't use --list with --funcs.\n");
usage_with_options(probe_usage, options);
}
+ if (params.uprobes) {
+ pr_warning(" Error: Don't use --list with --exec.\n");
+ usage_with_options(probe_usage, options);
+ }
ret = show_perf_probe_events();
if (ret < 0)
pr_err(" Error: Failed to show event list. (%d)\n",
@@ -333,8 +401,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
if (!params.filter)
params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
NULL);
- ret = show_available_funcs(params.target,
- params.filter);
+ ret = show_available_funcs(params.target, params.filter,
+ params.uprobes);
strfilter__delete(params.filter);
if (ret < 0)
pr_err(" Error: Failed to show functions."
@@ -343,7 +411,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
}
#ifdef DWARF_SUPPORT
- if (params.show_lines) {
+ if (params.show_lines && !params.uprobes) {
if (params.mod_events) {
pr_err(" Error: Don't use --line with"
" --add/--del.\n");
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index be4e1eee782e..e5cb08427e13 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -44,7 +44,6 @@ struct perf_record {
struct perf_evlist *evlist;
struct perf_session *session;
const char *progname;
- const char *uid_str;
int output;
unsigned int page_size;
int realtime_prio;
@@ -218,7 +217,7 @@ try_again:
if (err == EPERM || err == EACCES) {
ui__error_paranoid();
exit(EXIT_FAILURE);
- } else if (err == ENODEV && opts->cpu_list) {
+ } else if (err == ENODEV && opts->target.cpu_list) {
die("No such device - did you specify"
" an out-of-range profile CPU?\n");
} else if (err == EINVAL) {
@@ -243,9 +242,13 @@ try_again:
/*
* If it's cycles then fall back to hrtimer
* based cpu-clock-tick sw counter, which
- * is always available even if no PMU support:
+ * is always available even if no PMU support.
+ *
+ * PPC returns ENXIO until 2.6.37 (behavior changed
+ * with commit b0a873e).
*/
- if (attr->type == PERF_TYPE_HARDWARE
+ if ((err == ENOENT || err == ENXIO)
+ && attr->type == PERF_TYPE_HARDWARE
&& attr->config == PERF_COUNT_HW_CPU_CYCLES) {
if (verbose)
@@ -253,6 +256,10 @@ try_again:
"trying to fall back to cpu-clock-ticks\n");
attr->type = PERF_TYPE_SOFTWARE;
attr->config = PERF_COUNT_SW_CPU_CLOCK;
+ if (pos->name) {
+ free(pos->name);
+ pos->name = NULL;
+ }
goto try_again;
}
@@ -389,7 +396,7 @@ static void perf_record__mmap_read_all(struct perf_record *rec)
perf_record__mmap_read(rec, &rec->evlist->mmap[i]);
}
- if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO))
+ if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
write_output(rec, &finished_round_event, sizeof(finished_round_event));
}
@@ -471,7 +478,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
if (!have_tracepoints(&evsel_list->entries))
- perf_header__clear_feat(&session->header, HEADER_TRACE_INFO);
+ perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
if (!rec->opts.branch_stack)
perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
@@ -578,7 +585,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
perf_session__process_machines(session, tool,
perf_event__synthesize_guest_os);
- if (!opts->system_wide)
+ if (!opts->target.system_wide)
perf_event__synthesize_thread_map(tool, evsel_list->threads,
process_synthesized_event,
machine);
@@ -746,7 +753,10 @@ static struct perf_record record = {
.mmap_pages = UINT_MAX,
.user_freq = UINT_MAX,
.user_interval = ULLONG_MAX,
- .freq = 1000,
+ .freq = 4000,
+ .target = {
+ .uses_mmap = true,
+ },
},
.write_mode = WRITE_FORCE,
.file_new = true,
@@ -765,9 +775,9 @@ const struct option record_options[] = {
parse_events_option),
OPT_CALLBACK(0, "filter", &record.evlist, "filter",
"event filter", parse_filter),
- OPT_STRING('p', "pid", &record.opts.target_pid, "pid",
+ OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
"record events on existing process id"),
- OPT_STRING('t', "tid", &record.opts.target_tid, "tid",
+ OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
"record events on existing thread id"),
OPT_INTEGER('r', "realtime", &record.realtime_prio,
"collect data with this RT SCHED_FIFO priority"),
@@ -775,11 +785,11 @@ const struct option record_options[] = {
"collect data without buffering"),
OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
"collect raw sample records from all opened counters"),
- OPT_BOOLEAN('a', "all-cpus", &record.opts.system_wide,
+ OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
"system-wide collection from all CPUs"),
OPT_BOOLEAN('A', "append", &record.append_file,
"append to the output file to do incremental profiling"),
- OPT_STRING('C', "cpu", &record.opts.cpu_list, "cpu",
+ OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
"list of cpus to monitor"),
OPT_BOOLEAN('f', "force", &record.force,
"overwrite existing data file (deprecated)"),
@@ -813,7 +823,8 @@ const struct option record_options[] = {
OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
"monitor event in cgroup name only",
parse_cgroups),
- OPT_STRING('u', "uid", &record.uid_str, "user", "user to profile"),
+ OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
+ "user to profile"),
OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
"branch any", "sample any taken branches",
@@ -831,6 +842,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
struct perf_evsel *pos;
struct perf_evlist *evsel_list;
struct perf_record *rec = &record;
+ char errbuf[BUFSIZ];
perf_header__set_cmdline(argc, argv);
@@ -842,8 +854,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
argc = parse_options(argc, argv, record_options, record_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
- if (!argc && !rec->opts.target_pid && !rec->opts.target_tid &&
- !rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str)
+ if (!argc && perf_target__none(&rec->opts.target))
usage_with_options(record_usage, record_options);
if (rec->force && rec->append_file) {
@@ -856,7 +867,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
rec->write_mode = WRITE_FORCE;
}
- if (nr_cgroups && !rec->opts.system_wide) {
+ if (nr_cgroups && !rec->opts.target.system_wide) {
fprintf(stderr, "cgroup monitoring only available in"
" system-wide mode\n");
usage_with_options(record_usage, record_options);
@@ -883,17 +894,25 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
goto out_symbol_exit;
}
- rec->opts.uid = parse_target_uid(rec->uid_str, rec->opts.target_tid,
- rec->opts.target_pid);
- if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1)
- goto out_free_fd;
+ err = perf_target__validate(&rec->opts.target);
+ if (err) {
+ perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
+ ui__warning("%s", errbuf);
+ }
+
+ err = perf_target__parse_uid(&rec->opts.target);
+ if (err) {
+ int saved_errno = errno;
- if (rec->opts.target_pid)
- rec->opts.target_tid = rec->opts.target_pid;
+ perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
+ ui__warning("%s", errbuf);
+
+ err = -saved_errno;
+ goto out_free_fd;
+ }
- if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
- rec->opts.target_tid, rec->opts.uid,
- rec->opts.cpu_list) < 0)
+ err = -ENOMEM;
+ if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
usage_with_options(record_usage, record_options);
list_for_each_entry(pos, &evsel_list->entries, node) {
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index cdae9b2db1cc..d58e41445d0d 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -296,12 +296,15 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
{
size_t ret;
char unit;
- unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE];
+ unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE];
+ u64 nr_events = self->stats.total_period;
- nr_events = convert_unit(nr_events, &unit);
- ret = fprintf(fp, "# Events: %lu%c", nr_events, unit);
+ nr_samples = convert_unit(nr_samples, &unit);
+ ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
if (evname != NULL)
- ret += fprintf(fp, " %s", evname);
+ ret += fprintf(fp, " of event '%s'", evname);
+
+ ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events);
return ret + fprintf(fp, "\n#\n");
}
@@ -680,14 +683,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
}
- if (strcmp(report.input_name, "-") != 0) {
- if (report.use_gtk)
- perf_gtk_setup_browser(argc, argv, true);
- else
- setup_browser(true);
- } else {
+ if (strcmp(report.input_name, "-") != 0)
+ setup_browser(true);
+ else
use_browser = 0;
- }
/*
* Only in the newt browser we are doing integrated annotation,
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 1cad3af4bf4c..b125e07eb399 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -728,34 +728,34 @@ struct trace_migrate_task_event {
struct trace_sched_handler {
void (*switch_event)(struct trace_switch_event *,
struct machine *,
- struct event *,
+ struct event_format *,
int cpu,
u64 timestamp,
struct thread *thread);
void (*runtime_event)(struct trace_runtime_event *,
struct machine *,
- struct event *,
+ struct event_format *,
int cpu,
u64 timestamp,
struct thread *thread);
void (*wakeup_event)(struct trace_wakeup_event *,
struct machine *,
- struct event *,
+ struct event_format *,
int cpu,
u64 timestamp,
struct thread *thread);
void (*fork_event)(struct trace_fork_event *,
- struct event *,
+ struct event_format *,
int cpu,
u64 timestamp,
struct thread *thread);
void (*migrate_task_event)(struct trace_migrate_task_event *,
struct machine *machine,
- struct event *,
+ struct event_format *,
int cpu,
u64 timestamp,
struct thread *thread);
@@ -765,7 +765,7 @@ struct trace_sched_handler {
static void
replay_wakeup_event(struct trace_wakeup_event *wakeup_event,
struct machine *machine __used,
- struct event *event,
+ struct event_format *event,
int cpu __used,
u64 timestamp __used,
struct thread *thread __used)
@@ -792,7 +792,7 @@ static u64 cpu_last_switched[MAX_CPUS];
static void
replay_switch_event(struct trace_switch_event *switch_event,
struct machine *machine __used,
- struct event *event,
+ struct event_format *event,
int cpu,
u64 timestamp,
struct thread *thread __used)
@@ -835,7 +835,7 @@ replay_switch_event(struct trace_switch_event *switch_event,
static void
replay_fork_event(struct trace_fork_event *fork_event,
- struct event *event,
+ struct event_format *event,
int cpu __used,
u64 timestamp __used,
struct thread *thread __used)
@@ -944,7 +944,7 @@ static void thread_atoms_insert(struct thread *thread)
static void
latency_fork_event(struct trace_fork_event *fork_event __used,
- struct event *event __used,
+ struct event_format *event __used,
int cpu __used,
u64 timestamp __used,
struct thread *thread __used)
@@ -1026,7 +1026,7 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp)
static void
latency_switch_event(struct trace_switch_event *switch_event,
struct machine *machine,
- struct event *event __used,
+ struct event_format *event __used,
int cpu,
u64 timestamp,
struct thread *thread __used)
@@ -1079,7 +1079,7 @@ latency_switch_event(struct trace_switch_event *switch_event,
static void
latency_runtime_event(struct trace_runtime_event *runtime_event,
struct machine *machine,
- struct event *event __used,
+ struct event_format *event __used,
int cpu,
u64 timestamp,
struct thread *this_thread __used)
@@ -1102,7 +1102,7 @@ latency_runtime_event(struct trace_runtime_event *runtime_event,
static void
latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
struct machine *machine,
- struct event *__event __used,
+ struct event_format *__event __used,
int cpu __used,
u64 timestamp,
struct thread *thread __used)
@@ -1150,7 +1150,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event,
static void
latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event,
struct machine *machine,
- struct event *__event __used,
+ struct event_format *__event __used,
int cpu __used,
u64 timestamp,
struct thread *thread __used)
@@ -1361,7 +1361,7 @@ static struct trace_sched_handler *trace_handler;
static void
process_sched_wakeup_event(struct perf_tool *tool __used,
- struct event *event,
+ struct event_format *event,
struct perf_sample *sample,
struct machine *machine,
struct thread *thread)
@@ -1398,7 +1398,7 @@ static char next_shortname2 = '0';
static void
map_switch_event(struct trace_switch_event *switch_event,
struct machine *machine,
- struct event *event __used,
+ struct event_format *event __used,
int this_cpu,
u64 timestamp,
struct thread *thread __used)
@@ -1476,7 +1476,7 @@ map_switch_event(struct trace_switch_event *switch_event,
static void
process_sched_switch_event(struct perf_tool *tool __used,
- struct event *event,
+ struct event_format *event,
struct perf_sample *sample,
struct machine *machine,
struct thread *thread)
@@ -1512,7 +1512,7 @@ process_sched_switch_event(struct perf_tool *tool __used,
static void
process_sched_runtime_event(struct perf_tool *tool __used,
- struct event *event,
+ struct event_format *event,
struct perf_sample *sample,
struct machine *machine,
struct thread *thread)
@@ -1532,7 +1532,7 @@ process_sched_runtime_event(struct perf_tool *tool __used,
static void
process_sched_fork_event(struct perf_tool *tool __used,
- struct event *event,
+ struct event_format *event,
struct perf_sample *sample,
struct machine *machine __used,
struct thread *thread)
@@ -1554,7 +1554,7 @@ process_sched_fork_event(struct perf_tool *tool __used,
static void
process_sched_exit_event(struct perf_tool *tool __used,
- struct event *event,
+ struct event_format *event,
struct perf_sample *sample __used,
struct machine *machine __used,
struct thread *thread __used)
@@ -1565,7 +1565,7 @@ process_sched_exit_event(struct perf_tool *tool __used,
static void
process_sched_migrate_task_event(struct perf_tool *tool __used,
- struct event *event,
+ struct event_format *event,
struct perf_sample *sample,
struct machine *machine,
struct thread *thread)
@@ -1586,7 +1586,7 @@ process_sched_migrate_task_event(struct perf_tool *tool __used,
sample->time, thread);
}
-typedef void (*tracepoint_handler)(struct perf_tool *tool, struct event *event,
+typedef void (*tracepoint_handler)(struct perf_tool *tool, struct event_format *event,
struct perf_sample *sample,
struct machine *machine,
struct thread *thread);
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index d4ce733b9eba..8e395a538eb9 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -261,7 +261,7 @@ static void print_sample_start(struct perf_sample *sample,
struct perf_event_attr *attr)
{
int type;
- struct event *event;
+ struct event_format *event;
const char *evname = NULL;
unsigned long secs;
unsigned long usecs;
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 1e5e9b270f5e..62ae30d34fa6 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -173,24 +173,23 @@ static struct perf_event_attr very_very_detailed_attrs[] = {
-struct perf_evlist *evsel_list;
+static struct perf_evlist *evsel_list;
-static bool system_wide = false;
-static int run_idx = 0;
+static struct perf_target target = {
+ .uid = UINT_MAX,
+};
+static int run_idx = 0;
static int run_count = 1;
static bool no_inherit = false;
static bool scale = true;
static bool no_aggr = false;
-static const char *target_pid;
-static const char *target_tid;
static pid_t child_pid = -1;
static bool null_run = false;
static int detailed_run = 0;
static bool sync_run = false;
static bool big_num = true;
static int big_num_opt = -1;
-static const char *cpu_list;
static const char *csv_sep = NULL;
static bool csv_output = false;
static bool group = false;
@@ -265,18 +264,18 @@ static double stddev_stats(struct stats *stats)
return sqrt(variance_mean);
}
-struct stats runtime_nsecs_stats[MAX_NR_CPUS];
-struct stats runtime_cycles_stats[MAX_NR_CPUS];
-struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS];
-struct stats runtime_stalled_cycles_back_stats[MAX_NR_CPUS];
-struct stats runtime_branches_stats[MAX_NR_CPUS];
-struct stats runtime_cacherefs_stats[MAX_NR_CPUS];
-struct stats runtime_l1_dcache_stats[MAX_NR_CPUS];
-struct stats runtime_l1_icache_stats[MAX_NR_CPUS];
-struct stats runtime_ll_cache_stats[MAX_NR_CPUS];
-struct stats runtime_itlb_cache_stats[MAX_NR_CPUS];
-struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS];
-struct stats walltime_nsecs_stats;
+static struct stats runtime_nsecs_stats[MAX_NR_CPUS];
+static struct stats runtime_cycles_stats[MAX_NR_CPUS];
+static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS];
+static struct stats runtime_stalled_cycles_back_stats[MAX_NR_CPUS];
+static struct stats runtime_branches_stats[MAX_NR_CPUS];
+static struct stats runtime_cacherefs_stats[MAX_NR_CPUS];
+static struct stats runtime_l1_dcache_stats[MAX_NR_CPUS];
+static struct stats runtime_l1_icache_stats[MAX_NR_CPUS];
+static struct stats runtime_ll_cache_stats[MAX_NR_CPUS];
+static struct stats runtime_itlb_cache_stats[MAX_NR_CPUS];
+static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS];
+static struct stats walltime_nsecs_stats;
static int create_perf_stat_counter(struct perf_evsel *evsel,
struct perf_evsel *first)
@@ -299,15 +298,15 @@ retry:
if (exclude_guest_missing)
evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
- if (system_wide) {
+ if (perf_target__has_cpu(&target)) {
ret = perf_evsel__open_per_cpu(evsel, evsel_list->cpus,
- group, group_fd);
+ group, group_fd);
if (ret)
goto check_ret;
return 0;
}
- if (!target_pid && !target_tid && (!group || evsel == first)) {
+ if (!perf_target__has_task(&target) && (!group || evsel == first)) {
attr->disabled = 1;
attr->enable_on_exec = 1;
}
@@ -471,7 +470,7 @@ static int run_perf_stat(int argc __used, const char **argv)
exit(-1);
}
- if (!target_tid && !target_pid && !system_wide)
+ if (perf_target__none(&target))
evsel_list->threads->map[0] = child_pid;
/*
@@ -506,7 +505,7 @@ static int run_perf_stat(int argc __used, const char **argv)
error("You may not have permission to collect %sstats.\n"
"\t Consider tweaking"
" /proc/sys/kernel/perf_event_paranoid or running as root.",
- system_wide ? "system-wide " : "");
+ target.system_wide ? "system-wide " : "");
} else {
error("open_counter returned with %d (%s). "
"/bin/dmesg may provide additional information.\n",
@@ -998,14 +997,14 @@ static void print_stat(int argc, const char **argv)
if (!csv_output) {
fprintf(output, "\n");
fprintf(output, " Performance counter stats for ");
- if (!target_pid && !target_tid) {
+ if (!perf_target__has_task(&target)) {
fprintf(output, "\'%s", argv[0]);
for (i = 1; i < argc; i++)
fprintf(output, " %s", argv[i]);
- } else if (target_pid)
- fprintf(output, "process id \'%s", target_pid);
+ } else if (target.pid)
+ fprintf(output, "process id \'%s", target.pid);
else
- fprintf(output, "thread id \'%s", target_tid);
+ fprintf(output, "thread id \'%s", target.tid);
fprintf(output, "\'");
if (run_count > 1)
@@ -1079,11 +1078,11 @@ static const struct option options[] = {
"event filter", parse_filter),
OPT_BOOLEAN('i', "no-inherit", &no_inherit,
"child tasks do not inherit counters"),
- OPT_STRING('p', "pid", &target_pid, "pid",
+ OPT_STRING('p', "pid", &target.pid, "pid",
"stat events on existing process id"),
- OPT_STRING('t', "tid", &target_tid, "tid",
+ OPT_STRING('t', "tid", &target.tid, "tid",
"stat events on existing thread id"),
- OPT_BOOLEAN('a', "all-cpus", &system_wide,
+ OPT_BOOLEAN('a', "all-cpus", &target.system_wide,
"system-wide collection from all CPUs"),
OPT_BOOLEAN('g', "group", &group,
"put the counters into a counter group"),
@@ -1102,7 +1101,7 @@ static const struct option options[] = {
OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL,
"print large numbers with thousands\' separators",
stat__set_big_num),
- OPT_STRING('C', "cpu", &cpu_list, "cpu",
+ OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
"list of cpus to monitor in system-wide"),
OPT_BOOLEAN('A', "no-aggr", &no_aggr,
"disable CPU count aggregation"),
@@ -1220,13 +1219,13 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
} else if (big_num_opt == 0) /* User passed --no-big-num */
big_num = false;
- if (!argc && !target_pid && !target_tid)
+ if (!argc && !perf_target__has_task(&target))
usage_with_options(stat_usage, options);
if (run_count <= 0)
usage_with_options(stat_usage, options);
/* no_aggr, cgroup are for system-wide only */
- if ((no_aggr || nr_cgroups) && !system_wide) {
+ if ((no_aggr || nr_cgroups) && !perf_target__has_cpu(&target)) {
fprintf(stderr, "both cgroup and no-aggregation "
"modes only available in system-wide mode\n");
@@ -1236,23 +1235,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
if (add_default_attributes())
goto out;
- if (target_pid)
- target_tid = target_pid;
+ perf_target__validate(&target);
- evsel_list->threads = thread_map__new_str(target_pid,
- target_tid, UINT_MAX);
- if (evsel_list->threads == NULL) {
- pr_err("Problems finding threads of monitor\n");
- usage_with_options(stat_usage, options);
- }
-
- if (system_wide)
- evsel_list->cpus = cpu_map__new(cpu_list);
- else
- evsel_list->cpus = cpu_map__dummy_new();
+ if (perf_evlist__create_maps(evsel_list, &target) < 0) {
+ if (perf_target__has_task(&target))
+ pr_err("Problems finding threads of monitor\n");
+ if (perf_target__has_cpu(&target))
+ perror("failed to parse CPUs map");
- if (evsel_list->cpus == NULL) {
- perror("failed to parse CPUs map");
usage_with_options(stat_usage, options);
return -1;
}
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 223ffdcc0fd8..5a8727c08757 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -604,556 +604,6 @@ out_free_threads:
#undef nsyscalls
}
-#define TEST_ASSERT_VAL(text, cond) \
-do { \
- if (!(cond)) { \
- pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
- return -1; \
- } \
-} while (0)
-
-static int test__checkevent_tracepoint(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
- TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
- TEST_ASSERT_VAL("wrong sample_type",
- (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
- evsel->attr.sample_type);
- TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
- return 0;
-}
-
-static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel;
-
- TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
-
- list_for_each_entry(evsel, &evlist->entries, node) {
- TEST_ASSERT_VAL("wrong type",
- PERF_TYPE_TRACEPOINT == evsel->attr.type);
- TEST_ASSERT_VAL("wrong sample_type",
- (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU)
- == evsel->attr.sample_type);
- TEST_ASSERT_VAL("wrong sample_period",
- 1 == evsel->attr.sample_period);
- }
- return 0;
-}
-
-static int test__checkevent_raw(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
- TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
- TEST_ASSERT_VAL("wrong config", 0x1a == evsel->attr.config);
- return 0;
-}
-
-static int test__checkevent_numeric(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
- TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
- TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
- return 0;
-}
-
-static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
- TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
- TEST_ASSERT_VAL("wrong config",
- PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
- return 0;
-}
-
-static int test__checkevent_symbolic_name_config(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
- TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
- TEST_ASSERT_VAL("wrong config",
- PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
- TEST_ASSERT_VAL("wrong period",
- 100000 == evsel->attr.sample_period);
- TEST_ASSERT_VAL("wrong config1",
- 0 == evsel->attr.config1);
- TEST_ASSERT_VAL("wrong config2",
- 1 == evsel->attr.config2);
- return 0;
-}
-
-static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
- TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type);
- TEST_ASSERT_VAL("wrong config",
- PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config);
- return 0;
-}
-
-static int test__checkevent_genhw(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
- TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type);
- TEST_ASSERT_VAL("wrong config", (1 << 16) == evsel->attr.config);
- return 0;
-}
-
-static int test__checkevent_breakpoint(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
- TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
- TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
- TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) ==
- evsel->attr.bp_type);
- TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 ==
- evsel->attr.bp_len);
- return 0;
-}
-
-static int test__checkevent_breakpoint_x(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
- TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
- TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
- TEST_ASSERT_VAL("wrong bp_type",
- HW_BREAKPOINT_X == evsel->attr.bp_type);
- TEST_ASSERT_VAL("wrong bp_len", sizeof(long) == evsel->attr.bp_len);
- return 0;
-}
-
-static int test__checkevent_breakpoint_r(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
- TEST_ASSERT_VAL("wrong type",
- PERF_TYPE_BREAKPOINT == evsel->attr.type);
- TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
- TEST_ASSERT_VAL("wrong bp_type",
- HW_BREAKPOINT_R == evsel->attr.bp_type);
- TEST_ASSERT_VAL("wrong bp_len",
- HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
- return 0;
-}
-
-static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
- TEST_ASSERT_VAL("wrong type",
- PERF_TYPE_BREAKPOINT == evsel->attr.type);
- TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
- TEST_ASSERT_VAL("wrong bp_type",
- HW_BREAKPOINT_W == evsel->attr.bp_type);
- TEST_ASSERT_VAL("wrong bp_len",
- HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
- return 0;
-}
-
-static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
- TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
- TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
- TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
- return test__checkevent_tracepoint(evlist);
-}
-
-static int
-test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel;
-
- TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
-
- list_for_each_entry(evsel, &evlist->entries, node) {
- TEST_ASSERT_VAL("wrong exclude_user",
- !evsel->attr.exclude_user);
- TEST_ASSERT_VAL("wrong exclude_kernel",
- evsel->attr.exclude_kernel);
- TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
- TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
- }
-
- return test__checkevent_tracepoint_multi(evlist);
-}
-
-static int test__checkevent_raw_modifier(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
- TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
- TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
- TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
- return test__checkevent_raw(evlist);
-}
-
-static int test__checkevent_numeric_modifier(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
- TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
- TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
- TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
- return test__checkevent_numeric(evlist);
-}
-
-static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
- TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
- TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
- TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
- return test__checkevent_symbolic_name(evlist);
-}
-
-static int test__checkevent_exclude_host_modifier(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
- TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
-
- return test__checkevent_symbolic_name(evlist);
-}
-
-static int test__checkevent_exclude_guest_modifier(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
- TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
-
- return test__checkevent_symbolic_name(evlist);
-}
-
-static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
- TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
- TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
- TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
- return test__checkevent_symbolic_alias(evlist);
-}
-
-static int test__checkevent_genhw_modifier(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
- TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
- TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
- TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
- return test__checkevent_genhw(evlist);
-}
-
-static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
- TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
- TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
- TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
- return test__checkevent_breakpoint(evlist);
-}
-
-static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
- TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
- TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
- TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
- return test__checkevent_breakpoint_x(evlist);
-}
-
-static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
- TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
- TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
- TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
- return test__checkevent_breakpoint_r(evlist);
-}
-
-static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
- TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
- TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
- TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
- return test__checkevent_breakpoint_w(evlist);
-}
-
-static int test__checkevent_pmu(struct perf_evlist *evlist)
-{
-
- struct perf_evsel *evsel = list_entry(evlist->entries.next,
- struct perf_evsel, node);
-
- TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
- TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
- TEST_ASSERT_VAL("wrong config", 10 == evsel->attr.config);
- TEST_ASSERT_VAL("wrong config1", 1 == evsel->attr.config1);
- TEST_ASSERT_VAL("wrong config2", 3 == evsel->attr.config2);
- TEST_ASSERT_VAL("wrong period", 1000 == evsel->attr.sample_period);
-
- return 0;
-}
-
-static int test__checkevent_list(struct perf_evlist *evlist)
-{
- struct perf_evsel *evsel;
-
- TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
-
- /* r1 */
- evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
- TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
- TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
- TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1);
- TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2);
- TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
- TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
- TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
- TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
- /* syscalls:sys_enter_open:k */
- evsel = list_entry(evsel->node.next, struct perf_evsel, node);
- TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
- TEST_ASSERT_VAL("wrong sample_type",
- (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
- evsel->attr.sample_type);
- TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
- TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
- TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
- TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
- TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
-
- /* 1:1:hp */
- evsel = list_entry(evsel->node.next, struct perf_evsel, node);
- TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
- TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
- TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
- TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
- TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
- TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
-
- return 0;
-}
-
-static struct test__event_st {
- const char *name;
- __u32 type;
- int (*check)(struct perf_evlist *evlist);
-} test__events[] = {
- {
- .name = "syscalls:sys_enter_open",
- .check = test__checkevent_tracepoint,
- },
- {
- .name = "syscalls:*",
- .check = test__checkevent_tracepoint_multi,
- },
- {
- .name = "r1a",
- .check = test__checkevent_raw,
- },
- {
- .name = "1:1",
- .check = test__checkevent_numeric,
- },
- {
- .name = "instructions",
- .check = test__checkevent_symbolic_name,
- },
- {
- .name = "cycles/period=100000,config2/",
- .check = test__checkevent_symbolic_name_config,
- },
- {
- .name = "faults",
- .check = test__checkevent_symbolic_alias,
- },
- {
- .name = "L1-dcache-load-miss",
- .check = test__checkevent_genhw,
- },
- {
- .name = "mem:0",
- .check = test__checkevent_breakpoint,
- },
- {
- .name = "mem:0:x",
- .check = test__checkevent_breakpoint_x,
- },
- {
- .name = "mem:0:r",
- .check = test__checkevent_breakpoint_r,
- },
- {
- .name = "mem:0:w",
- .check = test__checkevent_breakpoint_w,
- },
- {
- .name = "syscalls:sys_enter_open:k",
- .check = test__checkevent_tracepoint_modifier,
- },
- {
- .name = "syscalls:*:u",
- .check = test__checkevent_tracepoint_multi_modifier,
- },
- {
- .name = "r1a:kp",
- .check = test__checkevent_raw_modifier,
- },
- {
- .name = "1:1:hp",
- .check = test__checkevent_numeric_modifier,
- },
- {
- .name = "instructions:h",
- .check = test__checkevent_symbolic_name_modifier,
- },
- {
- .name = "faults:u",
- .check = test__checkevent_symbolic_alias_modifier,
- },
- {
- .name = "L1-dcache-load-miss:kp",
- .check = test__checkevent_genhw_modifier,
- },
- {
- .name = "mem:0:u",
- .check = test__checkevent_breakpoint_modifier,
- },
- {
- .name = "mem:0:x:k",
- .check = test__checkevent_breakpoint_x_modifier,
- },
- {
- .name = "mem:0:r:hp",
- .check = test__checkevent_breakpoint_r_modifier,
- },
- {
- .name = "mem:0:w:up",
- .check = test__checkevent_breakpoint_w_modifier,
- },
- {
- .name = "cpu/config=10,config1,config2=3,period=1000/u",
- .check = test__checkevent_pmu,
- },
- {
- .name = "r1,syscalls:sys_enter_open:k,1:1:hp",
- .check = test__checkevent_list,
- },
- {
- .name = "instructions:G",
- .check = test__checkevent_exclude_host_modifier,
- },
- {
- .name = "instructions:H",
- .check = test__checkevent_exclude_guest_modifier,
- },
-};
-
-#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
-
-static int test__parse_events(void)
-{
- struct perf_evlist *evlist;
- u_int i;
- int ret = 0;
-
- for (i = 0; i < TEST__EVENTS_CNT; i++) {
- struct test__event_st *e = &test__events[i];
-
- evlist = perf_evlist__new(NULL, NULL);
- if (evlist == NULL)
- break;
-
- ret = parse_events(evlist, e->name, 0);
- if (ret) {
- pr_debug("failed to parse event '%s', err %d\n",
- e->name, ret);
- break;
- }
-
- ret = e->check(evlist);
- perf_evlist__delete(evlist);
- if (ret)
- break;
- }
-
- return ret;
-}
-
static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t **maskp,
size_t *sizep)
{
@@ -1195,6 +645,10 @@ realloc:
static int test__PERF_RECORD(void)
{
struct perf_record_opts opts = {
+ .target = {
+ .uid = UINT_MAX,
+ .uses_mmap = true,
+ },
.no_delay = true,
.freq = 10,
.mmap_pages = 256,
@@ -1237,8 +691,7 @@ static int test__PERF_RECORD(void)
* perf_evlist__prepare_workload we'll fill in the only thread
* we're monitoring, the one forked there.
*/
- err = perf_evlist__create_maps(evlist, opts.target_pid,
- opts.target_tid, UINT_MAX, opts.cpu_list);
+ err = perf_evlist__create_maps(evlist, &opts.target);
if (err < 0) {
pr_debug("Not enough memory to create thread/cpu maps\n");
goto out_delete_evlist;
@@ -1579,8 +1032,6 @@ static int __test__rdpmc(void)
sa.sa_sigaction = segfault_handler;
sigaction(SIGSEGV, &sa, NULL);
- fprintf(stderr, "\n\n");
-
fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
if (fd < 0) {
die("Error: sys_perf_event_open() syscall returned "
@@ -1605,7 +1056,7 @@ static int __test__rdpmc(void)
loops *= 10;
delta = now - stamp;
- fprintf(stderr, "%14d: %14Lu\n", n, (long long)delta);
+ pr_debug("%14d: %14Lu\n", n, (long long)delta);
delta_sum += delta;
}
@@ -1613,7 +1064,7 @@ static int __test__rdpmc(void)
munmap(addr, page_size);
close(fd);
- fprintf(stderr, " ");
+ pr_debug(" ");
if (!delta_sum)
return -1;
@@ -1674,7 +1125,7 @@ static struct test {
},
{
.desc = "parse events tests",
- .func = test__parse_events,
+ .func = parse_events__test,
},
#if defined(__x86_64__) || defined(__i386__)
{
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 8ef59f8262bb..6031dce0429f 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -588,7 +588,7 @@ static void *display_thread_tui(void *arg)
* via --uid.
*/
list_for_each_entry(pos, &top->evlist->entries, node)
- pos->hists.uid_filter_str = top->uid_str;
+ pos->hists.uid_filter_str = top->target.uid_str;
perf_evlist__tui_browse_hists(top->evlist, help,
perf_top__sort_new_samples,
@@ -900,6 +900,9 @@ static void perf_top__start_counters(struct perf_top *top)
attr->read_format |= PERF_FORMAT_ID;
}
+ if (perf_target__has_cpu(&top->target))
+ attr->sample_type |= PERF_SAMPLE_CPU;
+
if (symbol_conf.use_callchain)
attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
@@ -948,6 +951,10 @@ try_again:
attr->type = PERF_TYPE_SOFTWARE;
attr->config = PERF_COUNT_SW_CPU_CLOCK;
+ if (counter->name) {
+ free(counter->name);
+ counter->name = strdup(event_name(counter));
+ }
goto try_again;
}
@@ -1016,7 +1023,7 @@ static int __cmd_top(struct perf_top *top)
if (ret)
goto out_delete;
- if (top->target_tid || top->uid != UINT_MAX)
+ if (perf_target__has_task(&top->target))
perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
perf_event__process,
&top->session->host_machine);
@@ -1150,14 +1157,17 @@ static const char * const top_usage[] = {
int cmd_top(int argc, const char **argv, const char *prefix __used)
{
struct perf_evsel *pos;
- int status = -ENOMEM;
+ int status;
+ char errbuf[BUFSIZ];
struct perf_top top = {
.count_filter = 5,
.delay_secs = 2,
- .uid = UINT_MAX,
- .freq = 1000, /* 1 KHz */
+ .freq = 4000, /* 4 KHz */
.mmap_pages = 128,
.sym_pcnt_filter = 5,
+ .target = {
+ .uses_mmap = true,
+ },
};
char callchain_default_opt[] = "fractal,0.5,callee";
const struct option options[] = {
@@ -1166,13 +1176,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
parse_events_option),
OPT_INTEGER('c', "count", &top.default_interval,
"event period to sample"),
- OPT_STRING('p', "pid", &top.target_pid, "pid",
+ OPT_STRING('p', "pid", &top.target.pid, "pid",
"profile events on existing process id"),
- OPT_STRING('t', "tid", &top.target_tid, "tid",
+ OPT_STRING('t', "tid", &top.target.tid, "tid",
"profile events on existing thread id"),
- OPT_BOOLEAN('a', "all-cpus", &top.system_wide,
+ OPT_BOOLEAN('a', "all-cpus", &top.target.system_wide,
"system-wide collection from all CPUs"),
- OPT_STRING('C', "cpu", &top.cpu_list, "cpu",
+ OPT_STRING('C', "cpu", &top.target.cpu_list, "cpu",
"list of cpus to monitor"),
OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
"file", "vmlinux pathname"),
@@ -1227,7 +1237,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
"Display raw encoding of assembly instructions (default)"),
OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
"Specify disassembler style (e.g. -M intel for intel syntax)"),
- OPT_STRING('u', "uid", &top.uid_str, "user", "user to profile"),
+ OPT_STRING('u', "uid", &top.target.uid_str, "user", "user to profile"),
OPT_END()
};
@@ -1253,22 +1263,27 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
setup_browser(false);
- top.uid = parse_target_uid(top.uid_str, top.target_tid, top.target_pid);
- if (top.uid_str != NULL && top.uid == UINT_MAX - 1)
- goto out_delete_evlist;
+ status = perf_target__validate(&top.target);
+ if (status) {
+ perf_target__strerror(&top.target, status, errbuf, BUFSIZ);
+ ui__warning("%s", errbuf);
+ }
- /* CPU and PID are mutually exclusive */
- if (top.target_tid && top.cpu_list) {
- printf("WARNING: PID switch overriding CPU\n");
- sleep(1);
- top.cpu_list = NULL;
+ status = perf_target__parse_uid(&top.target);
+ if (status) {
+ int saved_errno = errno;
+
+ perf_target__strerror(&top.target, status, errbuf, BUFSIZ);
+ ui__warning("%s", errbuf);
+
+ status = -saved_errno;
+ goto out_delete_evlist;
}
- if (top.target_pid)
- top.target_tid = top.target_pid;
+ if (perf_target__none(&top.target))
+ top.target.system_wide = true;
- if (perf_evlist__create_maps(top.evlist, top.target_pid,
- top.target_tid, top.uid, top.cpu_list) < 0)
+ if (perf_evlist__create_maps(top.evlist, &top.target) < 0)
usage_with_options(top_usage, options);
if (!top.evlist->nr_entries &&
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 89e3355ab173..14f1034f14f9 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -207,10 +207,10 @@ extern const char perf_version_string[];
void pthread__unblock_sigwinch(void);
+#include "util/target.h"
+
struct perf_record_opts {
- const char *target_pid;
- const char *target_tid;
- uid_t uid;
+ struct perf_target target;
bool call_graph;
bool group;
bool inherit_stat;
@@ -223,7 +223,6 @@ struct perf_record_opts {
bool sample_time;
bool sample_id_all_missing;
bool exclude_guest_missing;
- bool system_wide;
bool period;
unsigned int freq;
unsigned int mmap_pages;
@@ -231,7 +230,6 @@ struct perf_record_opts {
int branch_stack;
u64 default_interval;
u64 user_interval;
- const char *cpu_list;
};
#endif
diff --git a/tools/perf/util/ui/browser.c b/tools/perf/ui/browser.c
index 556829124b02..cde4d0f0ddb9 100644
--- a/tools/perf/util/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -27,9 +27,12 @@ static int ui_browser__percent_color(struct ui_browser *browser,
return HE_COLORSET_NORMAL;
}
-void ui_browser__set_color(struct ui_browser *self __used, int color)
+int ui_browser__set_color(struct ui_browser *browser, int color)
{
+ int ret = browser->current_color;
+ browser->current_color = color;
SLsmg_set_color(color);
+ return ret;
}
void ui_browser__set_percent_color(struct ui_browser *self,
@@ -503,6 +506,12 @@ static struct ui_browser__colorset {
.bg = "default",
},
{
+ .colorset = HE_COLORSET_ADDR,
+ .name = "addr",
+ .fg = "magenta",
+ .bg = "default",
+ },
+ {
.name = NULL,
}
};
@@ -584,6 +593,111 @@ unsigned int ui_browser__argv_refresh(struct ui_browser *browser)
return row;
}
+void __ui_browser__vline(struct ui_browser *browser, unsigned int column,
+ u16 start, u16 end)
+{
+ SLsmg_set_char_set(1);
+ ui_browser__gotorc(browser, start, column);
+ SLsmg_draw_vline(end - start + 1);
+ SLsmg_set_char_set(0);
+}
+
+void ui_browser__write_graph(struct ui_browser *browser __used, int graph)
+{
+ SLsmg_set_char_set(1);
+ SLsmg_write_char(graph);
+ SLsmg_set_char_set(0);
+}
+
+static void __ui_browser__line_arrow_up(struct ui_browser *browser,
+ unsigned int column,
+ u64 start, u64 end)
+{
+ unsigned int row, end_row;
+
+ SLsmg_set_char_set(1);
+
+ if (start < browser->top_idx + browser->height) {
+ row = start - browser->top_idx;
+ ui_browser__gotorc(browser, row, column);
+ SLsmg_write_char(SLSMG_LLCORN_CHAR);
+ ui_browser__gotorc(browser, row, column + 1);
+ SLsmg_draw_hline(2);
+
+ if (row-- == 0)
+ goto out;
+ } else
+ row = browser->height - 1;
+
+ if (end > browser->top_idx)
+ end_row = end - browser->top_idx;
+ else
+ end_row = 0;
+
+ ui_browser__gotorc(browser, end_row, column);
+ SLsmg_draw_vline(row - end_row + 1);
+
+ ui_browser__gotorc(browser, end_row, column);
+ if (end >= browser->top_idx) {
+ SLsmg_write_char(SLSMG_ULCORN_CHAR);
+ ui_browser__gotorc(browser, end_row, column + 1);
+ SLsmg_write_char(SLSMG_HLINE_CHAR);
+ ui_browser__gotorc(browser, end_row, column + 2);
+ SLsmg_write_char(SLSMG_RARROW_CHAR);
+ }
+out:
+ SLsmg_set_char_set(0);
+}
+
+static void __ui_browser__line_arrow_down(struct ui_browser *browser,
+ unsigned int column,
+ u64 start, u64 end)
+{
+ unsigned int row, end_row;
+
+ SLsmg_set_char_set(1);
+
+ if (start >= browser->top_idx) {
+ row = start - browser->top_idx;
+ ui_browser__gotorc(browser, row, column);
+ SLsmg_write_char(SLSMG_ULCORN_CHAR);
+ ui_browser__gotorc(browser, row, column + 1);
+ SLsmg_draw_hline(2);
+
+ if (row++ == 0)
+ goto out;
+ } else
+ row = 0;
+
+ if (end >= browser->top_idx + browser->height)
+ end_row = browser->height - 1;
+ else
+ end_row = end - browser->top_idx;;
+
+ ui_browser__gotorc(browser, row, column);
+ SLsmg_draw_vline(end_row - row + 1);
+
+ ui_browser__gotorc(browser, end_row, column);
+ if (end < browser->top_idx + browser->height) {
+ SLsmg_write_char(SLSMG_LLCORN_CHAR);
+ ui_browser__gotorc(browser, end_row, column + 1);
+ SLsmg_write_char(SLSMG_HLINE_CHAR);
+ ui_browser__gotorc(browser, end_row, column + 2);
+ SLsmg_write_char(SLSMG_RARROW_CHAR);
+ }
+out:
+ SLsmg_set_char_set(0);
+}
+
+void __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column,
+ u64 start, u64 end)
+{
+ if (start > end)
+ __ui_browser__line_arrow_up(browser, column, start, end);
+ else
+ __ui_browser__line_arrow_down(browser, column, start, end);
+}
+
void ui_browser__init(void)
{
int i = 0;
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/ui/browser.h
index 6ee82f60feaf..dd96d8229902 100644
--- a/tools/perf/util/ui/browser.h
+++ b/tools/perf/ui/browser.h
@@ -10,11 +10,13 @@
#define HE_COLORSET_NORMAL 52
#define HE_COLORSET_SELECTED 53
#define HE_COLORSET_CODE 54
+#define HE_COLORSET_ADDR 55
struct ui_browser {
u64 index, top_idx;
void *top, *entries;
u16 y, x, width, height;
+ int current_color;
void *priv;
const char *title;
char *helpline;
@@ -27,7 +29,7 @@ struct ui_browser {
bool use_navkeypressed;
};
-void ui_browser__set_color(struct ui_browser *self, int color);
+int ui_browser__set_color(struct ui_browser *browser, int color);
void ui_browser__set_percent_color(struct ui_browser *self,
double percent, bool current);
bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row);
@@ -35,6 +37,9 @@ void ui_browser__refresh_dimensions(struct ui_browser *self);
void ui_browser__reset_index(struct ui_browser *self);
void ui_browser__gotorc(struct ui_browser *self, int y, int x);
+void ui_browser__write_graph(struct ui_browser *browser, int graph);
+void __ui_browser__line_arrow(struct ui_browser *browser, unsigned int column,
+ u64 start, u64 end);
void __ui_browser__show_title(struct ui_browser *browser, const char *title);
void ui_browser__show_title(struct ui_browser *browser, const char *title);
int ui_browser__show(struct ui_browser *self, const char *title,
@@ -44,6 +49,8 @@ int ui_browser__refresh(struct ui_browser *self);
int ui_browser__run(struct ui_browser *browser, int delay_secs);
void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries);
void ui_browser__handle_resize(struct ui_browser *browser);
+void __ui_browser__vline(struct ui_browser *browser, unsigned int column,
+ u16 start, u16 end);
int ui_browser__warning(struct ui_browser *browser, int timeout,
const char *format, ...);
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
new file mode 100644
index 000000000000..6e0ef79be169
--- /dev/null
+++ b/tools/perf/ui/browsers/annotate.c
@@ -0,0 +1,867 @@
+#include "../../util/util.h"
+#include "../browser.h"
+#include "../helpline.h"
+#include "../libslang.h"
+#include "../ui.h"
+#include "../util.h"
+#include "../../util/annotate.h"
+#include "../../util/hist.h"
+#include "../../util/sort.h"
+#include "../../util/symbol.h"
+#include <pthread.h>
+#include <newt.h>
+
+struct browser_disasm_line {
+ struct rb_node rb_node;
+ double percent;
+ u32 idx;
+ int idx_asm;
+ int jump_sources;
+};
+
+struct annotate_browser {
+ struct ui_browser b;
+ struct rb_root entries;
+ struct rb_node *curr_hot;
+ struct disasm_line *selection;
+ struct disasm_line **offsets;
+ u64 start;
+ int nr_asm_entries;
+ int nr_entries;
+ int max_jump_sources;
+ int nr_jumps;
+ bool hide_src_code;
+ bool use_offset;
+ bool jump_arrows;
+ bool show_nr_jumps;
+ bool searching_backwards;
+ u8 addr_width;
+ u8 jumps_width;
+ u8 target_width;
+ u8 min_addr_width;
+ u8 max_addr_width;
+ char search_bf[128];
+};
+
+static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
+{
+ return (struct browser_disasm_line *)(dl + 1);
+}
+
+static bool disasm_line__filter(struct ui_browser *browser, void *entry)
+{
+ struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
+
+ if (ab->hide_src_code) {
+ struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
+ return dl->offset == -1;
+ }
+
+ return false;
+}
+
+static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
+ int nr, bool current)
+{
+ if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
+ return HE_COLORSET_SELECTED;
+ if (nr == browser->max_jump_sources)
+ return HE_COLORSET_TOP;
+ if (nr > 1)
+ return HE_COLORSET_MEDIUM;
+ return HE_COLORSET_NORMAL;
+}
+
+static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
+ int nr, bool current)
+{
+ int color = annotate_browser__jumps_percent_color(browser, nr, current);
+ return ui_browser__set_color(&browser->b, color);
+}
+
+static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
+{
+ struct annotate_browser *ab = container_of(self, struct annotate_browser, b);
+ struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
+ struct browser_disasm_line *bdl = disasm_line__browser(dl);
+ bool current_entry = ui_browser__is_current_entry(self, row);
+ bool change_color = (!ab->hide_src_code &&
+ (!current_entry || (self->use_navkeypressed &&
+ !self->navkeypressed)));
+ int width = self->width, printed;
+ char bf[256];
+
+ if (dl->offset != -1 && bdl->percent != 0.0) {
+ ui_browser__set_percent_color(self, bdl->percent, current_entry);
+ slsmg_printf("%6.2f ", bdl->percent);
+ } else {
+ ui_browser__set_percent_color(self, 0, current_entry);
+ slsmg_write_nstring(" ", 7);
+ }
+
+ SLsmg_write_char(' ');
+
+ /* The scroll bar isn't being used */
+ if (!self->navkeypressed)
+ width += 1;
+
+ if (!*dl->line)
+ slsmg_write_nstring(" ", width - 7);
+ else if (dl->offset == -1) {
+ printed = scnprintf(bf, sizeof(bf), "%*s ",
+ ab->addr_width, " ");
+ slsmg_write_nstring(bf, printed);
+ slsmg_write_nstring(dl->line, width - printed - 6);
+ } else {
+ u64 addr = dl->offset;
+ int color = -1;
+
+ if (!ab->use_offset)
+ addr += ab->start;
+
+ if (!ab->use_offset) {
+ printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
+ } else {
+ if (bdl->jump_sources) {
+ if (ab->show_nr_jumps) {
+ int prev;
+ printed = scnprintf(bf, sizeof(bf), "%*d ",
+ ab->jumps_width,
+ bdl->jump_sources);
+ prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
+ current_entry);
+ slsmg_write_nstring(bf, printed);
+ ui_browser__set_color(self, prev);
+ }
+
+ printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
+ ab->target_width, addr);
+ } else {
+ printed = scnprintf(bf, sizeof(bf), "%*s ",
+ ab->addr_width, " ");
+ }
+ }
+
+ if (change_color)
+ color = ui_browser__set_color(self, HE_COLORSET_ADDR);
+ slsmg_write_nstring(bf, printed);
+ if (change_color)
+ ui_browser__set_color(self, color);
+ if (dl->ins && dl->ins->ops->scnprintf) {
+ if (ins__is_jump(dl->ins)) {
+ bool fwd = dl->ops.target.offset > (u64)dl->offset;
+
+ ui_browser__write_graph(self, fwd ? SLSMG_DARROW_CHAR :
+ SLSMG_UARROW_CHAR);
+ SLsmg_write_char(' ');
+ } else if (ins__is_call(dl->ins)) {
+ ui_browser__write_graph(self, SLSMG_RARROW_CHAR);
+ SLsmg_write_char(' ');
+ } else {
+ slsmg_write_nstring(" ", 2);
+ }
+ } else {
+ if (strcmp(dl->name, "retq")) {
+ slsmg_write_nstring(" ", 2);
+ } else {
+ ui_browser__write_graph(self, SLSMG_LARROW_CHAR);
+ SLsmg_write_char(' ');
+ }
+ }
+
+ disasm_line__scnprintf(dl, bf, sizeof(bf), !ab->use_offset);
+ slsmg_write_nstring(bf, width - 10 - printed);
+ }
+
+ if (current_entry)
+ ab->selection = dl;
+}
+
+static void annotate_browser__draw_current_jump(struct ui_browser *browser)
+{
+ struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
+ struct disasm_line *cursor = ab->selection, *target;
+ struct browser_disasm_line *btarget, *bcursor;
+ unsigned int from, to;
+
+ if (!cursor->ins || !ins__is_jump(cursor->ins) ||
+ !disasm_line__has_offset(cursor))
+ return;
+
+ target = ab->offsets[cursor->ops.target.offset];
+ if (!target)
+ return;
+
+ bcursor = disasm_line__browser(cursor);
+ btarget = disasm_line__browser(target);
+
+ if (ab->hide_src_code) {
+ from = bcursor->idx_asm;
+ to = btarget->idx_asm;
+ } else {
+ from = (u64)bcursor->idx;
+ to = (u64)btarget->idx;
+ }
+
+ ui_browser__set_color(browser, HE_COLORSET_CODE);
+ __ui_browser__line_arrow(browser, 9 + ab->addr_width, from, to);
+}
+
+static unsigned int annotate_browser__refresh(struct ui_browser *browser)
+{
+ struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
+ int ret = ui_browser__list_head_refresh(browser);
+
+ if (ab->jump_arrows)
+ annotate_browser__draw_current_jump(browser);
+
+ ui_browser__set_color(browser, HE_COLORSET_NORMAL);
+ __ui_browser__vline(browser, 7, 0, browser->height - 1);
+ return ret;
+}
+
+static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx)
+{
+ double percent = 0.0;
+
+ if (dl->offset != -1) {
+ int len = sym->end - sym->start;
+ unsigned int hits = 0;
+ struct annotation *notes = symbol__annotation(sym);
+ struct source_line *src_line = notes->src->lines;
+ struct sym_hist *h = annotation__histogram(notes, evidx);
+ s64 offset = dl->offset;
+ struct disasm_line *next;
+
+ next = disasm__get_next_ip_line(&notes->src->source, dl);
+ while (offset < (s64)len &&
+ (next == NULL || offset < next->offset)) {
+ if (src_line) {
+ percent += src_line[offset].percent;
+ } else
+ hits += h->addr[offset];
+
+ ++offset;
+ }
+ /*
+ * If the percentage wasn't already calculated in
+ * symbol__get_source_line, do it now:
+ */
+ if (src_line == NULL && h->sum)
+ percent = 100.0 * hits / h->sum;
+ }
+
+ return percent;
+}
+
+static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl)
+{
+ struct rb_node **p = &root->rb_node;
+ struct rb_node *parent = NULL;
+ struct browser_disasm_line *l;
+
+ while (*p != NULL) {
+ parent = *p;
+ l = rb_entry(parent, struct browser_disasm_line, rb_node);
+ if (bdl->percent < l->percent)
+ p = &(*p)->rb_left;
+ else
+ p = &(*p)->rb_right;
+ }
+ rb_link_node(&bdl->rb_node, parent, p);
+ rb_insert_color(&bdl->rb_node, root);
+}
+
+static void annotate_browser__set_top(struct annotate_browser *self,
+ struct disasm_line *pos, u32 idx)
+{
+ unsigned back;
+
+ ui_browser__refresh_dimensions(&self->b);
+ back = self->b.height / 2;
+ self->b.top_idx = self->b.index = idx;
+
+ while (self->b.top_idx != 0 && back != 0) {
+ pos = list_entry(pos->node.prev, struct disasm_line, node);
+
+ if (disasm_line__filter(&self->b, &pos->node))
+ continue;
+
+ --self->b.top_idx;
+ --back;
+ }
+
+ self->b.top = pos;
+ self->b.navkeypressed = true;
+}
+
+static void annotate_browser__set_rb_top(struct annotate_browser *browser,
+ struct rb_node *nd)
+{
+ struct browser_disasm_line *bpos;
+ struct disasm_line *pos;
+
+ bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
+ pos = ((struct disasm_line *)bpos) - 1;
+ annotate_browser__set_top(browser, pos, bpos->idx);
+ browser->curr_hot = nd;
+}
+
+static void annotate_browser__calc_percent(struct annotate_browser *browser,
+ int evidx)
+{
+ struct map_symbol *ms = browser->b.priv;
+ struct symbol *sym = ms->sym;
+ struct annotation *notes = symbol__annotation(sym);
+ struct disasm_line *pos;
+
+ browser->entries = RB_ROOT;
+
+ pthread_mutex_lock(&notes->lock);
+
+ list_for_each_entry(pos, &notes->src->source, node) {
+ struct browser_disasm_line *bpos = disasm_line__browser(pos);
+ bpos->percent = disasm_line__calc_percent(pos, sym, evidx);
+ if (bpos->percent < 0.01) {
+ RB_CLEAR_NODE(&bpos->rb_node);
+ continue;
+ }
+ disasm_rb_tree__insert(&browser->entries, bpos);
+ }
+ pthread_mutex_unlock(&notes->lock);
+
+ browser->curr_hot = rb_last(&browser->entries);
+}
+
+static bool annotate_browser__toggle_source(struct annotate_browser *browser)
+{
+ struct disasm_line *dl;
+ struct browser_disasm_line *bdl;
+ off_t offset = browser->b.index - browser->b.top_idx;
+
+ browser->b.seek(&browser->b, offset, SEEK_CUR);
+ dl = list_entry(browser->b.top, struct disasm_line, node);
+ bdl = disasm_line__browser(dl);
+
+ if (browser->hide_src_code) {
+ if (bdl->idx_asm < offset)
+ offset = bdl->idx;
+
+ browser->b.nr_entries = browser->nr_entries;
+ browser->hide_src_code = false;
+ browser->b.seek(&browser->b, -offset, SEEK_CUR);
+ browser->b.top_idx = bdl->idx - offset;
+ browser->b.index = bdl->idx;
+ } else {
+ if (bdl->idx_asm < 0) {
+ ui_helpline__puts("Only available for assembly lines.");
+ browser->b.seek(&browser->b, -offset, SEEK_CUR);
+ return false;
+ }
+
+ if (bdl->idx_asm < offset)
+ offset = bdl->idx_asm;
+
+ browser->b.nr_entries = browser->nr_asm_entries;
+ browser->hide_src_code = true;
+ browser->b.seek(&browser->b, -offset, SEEK_CUR);
+ browser->b.top_idx = bdl->idx_asm - offset;
+ browser->b.index = bdl->idx_asm;
+ }
+
+ return true;
+}
+
+static bool annotate_browser__callq(struct annotate_browser *browser,
+ int evidx, void (*timer)(void *arg),
+ void *arg, int delay_secs)
+{
+ struct map_symbol *ms = browser->b.priv;
+ struct disasm_line *dl = browser->selection;
+ struct symbol *sym = ms->sym;
+ struct annotation *notes;
+ struct symbol *target;
+ u64 ip;
+
+ if (!ins__is_call(dl->ins))
+ return false;
+
+ ip = ms->map->map_ip(ms->map, dl->ops.target.addr);
+ target = map__find_symbol(ms->map, ip, NULL);
+ if (target == NULL) {
+ ui_helpline__puts("The called function was not found.");
+ return true;
+ }
+
+ notes = symbol__annotation(target);
+ pthread_mutex_lock(&notes->lock);
+
+ if (notes->src == NULL && symbol__alloc_hist(target) < 0) {
+ pthread_mutex_unlock(&notes->lock);
+ ui__warning("Not enough memory for annotating '%s' symbol!\n",
+ target->name);
+ return true;
+ }
+
+ pthread_mutex_unlock(&notes->lock);
+ symbol__tui_annotate(target, ms->map, evidx, timer, arg, delay_secs);
+ ui_browser__show_title(&browser->b, sym->name);
+ return true;
+}
+
+static
+struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
+ s64 offset, s64 *idx)
+{
+ struct map_symbol *ms = browser->b.priv;
+ struct symbol *sym = ms->sym;
+ struct annotation *notes = symbol__annotation(sym);
+ struct disasm_line *pos;
+
+ *idx = 0;
+ list_for_each_entry(pos, &notes->src->source, node) {
+ if (pos->offset == offset)
+ return pos;
+ if (!disasm_line__filter(&browser->b, &pos->node))
+ ++*idx;
+ }
+
+ return NULL;
+}
+
+static bool annotate_browser__jump(struct annotate_browser *browser)
+{
+ struct disasm_line *dl = browser->selection;
+ s64 idx;
+
+ if (!ins__is_jump(dl->ins))
+ return false;
+
+ dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
+ if (dl == NULL) {
+ ui_helpline__puts("Invallid jump offset");
+ return true;
+ }
+
+ annotate_browser__set_top(browser, dl, idx);
+
+ return true;
+}
+
+static
+struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
+ char *s, s64 *idx)
+{
+ struct map_symbol *ms = browser->b.priv;
+ struct symbol *sym = ms->sym;
+ struct annotation *notes = symbol__annotation(sym);
+ struct disasm_line *pos = browser->selection;
+
+ *idx = browser->b.index;
+ list_for_each_entry_continue(pos, &notes->src->source, node) {
+ if (disasm_line__filter(&browser->b, &pos->node))
+ continue;
+
+ ++*idx;
+
+ if (pos->line && strstr(pos->line, s) != NULL)
+ return pos;
+ }
+
+ return NULL;
+}
+
+static bool __annotate_browser__search(struct annotate_browser *browser)
+{
+ struct disasm_line *dl;
+ s64 idx;
+
+ dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
+ if (dl == NULL) {
+ ui_helpline__puts("String not found!");
+ return false;
+ }
+
+ annotate_browser__set_top(browser, dl, idx);
+ browser->searching_backwards = false;
+ return true;
+}
+
+static
+struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
+ char *s, s64 *idx)
+{
+ struct map_symbol *ms = browser->b.priv;
+ struct symbol *sym = ms->sym;
+ struct annotation *notes = symbol__annotation(sym);
+ struct disasm_line *pos = browser->selection;
+
+ *idx = browser->b.index;
+ list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
+ if (disasm_line__filter(&browser->b, &pos->node))
+ continue;
+
+ --*idx;
+
+ if (pos->line && strstr(pos->line, s) != NULL)
+ return pos;
+ }
+
+ return NULL;
+}
+
+static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
+{
+ struct disasm_line *dl;
+ s64 idx;
+
+ dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
+ if (dl == NULL) {
+ ui_helpline__puts("String not found!");
+ return false;
+ }
+
+ annotate_browser__set_top(browser, dl, idx);
+ browser->searching_backwards = true;
+ return true;
+}
+
+static bool annotate_browser__search_window(struct annotate_browser *browser,
+ int delay_secs)
+{
+ if (ui_browser__input_window("Search", "String: ", browser->search_bf,
+ "ENTER: OK, ESC: Cancel",
+ delay_secs * 2) != K_ENTER ||
+ !*browser->search_bf)
+ return false;
+
+ return true;
+}
+
+static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
+{
+ if (annotate_browser__search_window(browser, delay_secs))
+ return __annotate_browser__search(browser);
+
+ return false;
+}
+
+static bool annotate_browser__continue_search(struct annotate_browser *browser,
+ int delay_secs)
+{
+ if (!*browser->search_bf)
+ return annotate_browser__search(browser, delay_secs);
+
+ return __annotate_browser__search(browser);
+}
+
+static bool annotate_browser__search_reverse(struct annotate_browser *browser,
+ int delay_secs)
+{
+ if (annotate_browser__search_window(browser, delay_secs))
+ return __annotate_browser__search_reverse(browser);
+
+ return false;
+}
+
+static
+bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
+ int delay_secs)
+{
+ if (!*browser->search_bf)
+ return annotate_browser__search_reverse(browser, delay_secs);
+
+ return __annotate_browser__search_reverse(browser);
+}
+
+static int annotate_browser__run(struct annotate_browser *self, int evidx,
+ void(*timer)(void *arg),
+ void *arg, int delay_secs)
+{
+ struct rb_node *nd = NULL;
+ struct map_symbol *ms = self->b.priv;
+ struct symbol *sym = ms->sym;
+ const char *help = "Press 'h' for help on key bindings";
+ int key;
+
+ if (ui_browser__show(&self->b, sym->name, help) < 0)
+ return -1;
+
+ annotate_browser__calc_percent(self, evidx);
+
+ if (self->curr_hot) {
+ annotate_browser__set_rb_top(self, self->curr_hot);
+ self->b.navkeypressed = false;
+ }
+
+ nd = self->curr_hot;
+
+ while (1) {
+ key = ui_browser__run(&self->b, delay_secs);
+
+ if (delay_secs != 0) {
+ annotate_browser__calc_percent(self, evidx);
+ /*
+ * Current line focus got out of the list of most active
+ * lines, NULL it so that if TAB|UNTAB is pressed, we
+ * move to curr_hot (current hottest line).
+ */
+ if (nd != NULL && RB_EMPTY_NODE(nd))
+ nd = NULL;
+ }
+
+ switch (key) {
+ case K_TIMER:
+ if (timer != NULL)
+ timer(arg);
+
+ if (delay_secs != 0)
+ symbol__annotate_decay_histogram(sym, evidx);
+ continue;
+ case K_TAB:
+ if (nd != NULL) {
+ nd = rb_prev(nd);
+ if (nd == NULL)
+ nd = rb_last(&self->entries);
+ } else
+ nd = self->curr_hot;
+ break;
+ case K_UNTAB:
+ if (nd != NULL)
+ nd = rb_next(nd);
+ if (nd == NULL)
+ nd = rb_first(&self->entries);
+ else
+ nd = self->curr_hot;
+ break;
+ case K_F1:
+ case 'h':
+ ui_browser__help_window(&self->b,
+ "UP/DOWN/PGUP\n"
+ "PGDN/SPACE Navigate\n"
+ "q/ESC/CTRL+C Exit\n\n"
+ "-> Go to target\n"
+ "<- Exit\n"
+ "h Cycle thru hottest instructions\n"
+ "j Toggle showing jump to target arrows\n"
+ "J Toggle showing number of jump sources on targets\n"
+ "n Search next string\n"
+ "o Toggle disassembler output/simplified view\n"
+ "s Toggle source code view\n"
+ "/ Search string\n"
+ "? Search previous string\n");
+ continue;
+ case 'H':
+ nd = self->curr_hot;
+ break;
+ case 's':
+ if (annotate_browser__toggle_source(self))
+ ui_helpline__puts(help);
+ continue;
+ case 'o':
+ self->use_offset = !self->use_offset;
+ if (self->use_offset)
+ self->target_width = self->min_addr_width;
+ else
+ self->target_width = self->max_addr_width;
+update_addr_width:
+ self->addr_width = self->target_width;
+ if (self->show_nr_jumps)
+ self->addr_width += self->jumps_width + 1;
+ continue;
+ case 'j':
+ self->jump_arrows = !self->jump_arrows;
+ continue;
+ case 'J':
+ self->show_nr_jumps = !self->show_nr_jumps;
+ goto update_addr_width;
+ case '/':
+ if (annotate_browser__search(self, delay_secs)) {
+show_help:
+ ui_helpline__puts(help);
+ }
+ continue;
+ case 'n':
+ if (self->searching_backwards ?
+ annotate_browser__continue_search_reverse(self, delay_secs) :
+ annotate_browser__continue_search(self, delay_secs))
+ goto show_help;
+ continue;
+ case '?':
+ if (annotate_browser__search_reverse(self, delay_secs))
+ goto show_help;
+ continue;
+ case K_ENTER:
+ case K_RIGHT:
+ if (self->selection == NULL)
+ ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
+ else if (self->selection->offset == -1)
+ ui_helpline__puts("Actions are only available for assembly lines.");
+ else if (!self->selection->ins) {
+ if (strcmp(self->selection->name, "retq"))
+ goto show_sup_ins;
+ goto out;
+ } else if (!(annotate_browser__jump(self) ||
+ annotate_browser__callq(self, evidx, timer, arg, delay_secs))) {
+show_sup_ins:
+ ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
+ }
+ continue;
+ case K_LEFT:
+ case K_ESC:
+ case 'q':
+ case CTRL('c'):
+ goto out;
+ default:
+ continue;
+ }
+
+ if (nd != NULL)
+ annotate_browser__set_rb_top(self, nd);
+ }
+out:
+ ui_browser__hide(&self->b);
+ return key;
+}
+
+int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
+ void(*timer)(void *arg), void *arg, int delay_secs)
+{
+ return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx,
+ timer, arg, delay_secs);
+}
+
+static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
+ size_t size)
+{
+ u64 offset;
+
+ for (offset = 0; offset < size; ++offset) {
+ struct disasm_line *dl = browser->offsets[offset], *dlt;
+ struct browser_disasm_line *bdlt;
+
+ if (!dl || !dl->ins || !ins__is_jump(dl->ins) ||
+ !disasm_line__has_offset(dl))
+ continue;
+
+ if (dl->ops.target.offset >= size) {
+ ui__error("jump to after symbol!\n"
+ "size: %zx, jump target: %" PRIx64,
+ size, dl->ops.target.offset);
+ continue;
+ }
+
+ dlt = browser->offsets[dl->ops.target.offset];
+ /*
+ * FIXME: Oops, no jump target? Buggy disassembler? Or do we
+ * have to adjust to the previous offset?
+ */
+ if (dlt == NULL)
+ continue;
+
+ bdlt = disasm_line__browser(dlt);
+ if (++bdlt->jump_sources > browser->max_jump_sources)
+ browser->max_jump_sources = bdlt->jump_sources;
+
+ ++browser->nr_jumps;
+ }
+
+}
+
+static inline int width_jumps(int n)
+{
+ if (n >= 100)
+ return 5;
+ if (n / 10)
+ return 2;
+ return 1;
+}
+
+int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
+ void(*timer)(void *arg), void *arg,
+ int delay_secs)
+{
+ struct disasm_line *pos, *n;
+ struct annotation *notes;
+ const size_t size = symbol__size(sym);
+ struct map_symbol ms = {
+ .map = map,
+ .sym = sym,
+ };
+ struct annotate_browser browser = {
+ .b = {
+ .refresh = annotate_browser__refresh,
+ .seek = ui_browser__list_head_seek,
+ .write = annotate_browser__write,
+ .filter = disasm_line__filter,
+ .priv = &ms,
+ .use_navkeypressed = true,
+ },
+ .use_offset = true,
+ .jump_arrows = true,
+ };
+ int ret = -1;
+
+ if (sym == NULL)
+ return -1;
+
+ if (map->dso->annotate_warned)
+ return -1;
+
+ browser.offsets = zalloc(size * sizeof(struct disasm_line *));
+ if (browser.offsets == NULL) {
+ ui__error("Not enough memory!");
+ return -1;
+ }
+
+ if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) {
+ ui__error("%s", ui_helpline__last_msg);
+ goto out_free_offsets;
+ }
+
+ ui_helpline__push("Press <- or ESC to exit");
+
+ notes = symbol__annotation(sym);
+ browser.start = map__rip_2objdump(map, sym->start);
+
+ list_for_each_entry(pos, &notes->src->source, node) {
+ struct browser_disasm_line *bpos;
+ size_t line_len = strlen(pos->line);
+
+ if (browser.b.width < line_len)
+ browser.b.width = line_len;
+ bpos = disasm_line__browser(pos);
+ bpos->idx = browser.nr_entries++;
+ if (pos->offset != -1) {
+ bpos->idx_asm = browser.nr_asm_entries++;
+ /*
+ * FIXME: short term bandaid to cope with assembly
+ * routines that comes with labels in the same column
+ * as the address in objdump, sigh.
+ *
+ * E.g. copy_user_generic_unrolled
+ */
+ if (pos->offset < (s64)size)
+ browser.offsets[pos->offset] = pos;
+ } else
+ bpos->idx_asm = -1;
+ }
+
+ annotate_browser__mark_jump_targets(&browser, size);
+
+ browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
+ browser.max_addr_width = hex_width(sym->end);
+ browser.jumps_width = width_jumps(browser.max_jump_sources);
+ browser.b.nr_entries = browser.nr_entries;
+ browser.b.entries = &notes->src->source,
+ browser.b.width += 18; /* Percentage */
+ ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
+ list_for_each_entry_safe(pos, n, &notes->src->source, node) {
+ list_del(&pos->node);
+ disasm_line__free(pos);
+ }
+
+out_free_offsets:
+ free(browser.offsets);
+ return ret;
+}
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 2f83e5dc9967..a372a4b02635 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -5,12 +5,12 @@
#include <newt.h>
#include <linux/rbtree.h>
-#include "../../evsel.h"
-#include "../../evlist.h"
-#include "../../hist.h"
-#include "../../pstack.h"
-#include "../../sort.h"
-#include "../../util.h"
+#include "../../util/evsel.h"
+#include "../../util/evlist.h"
+#include "../../util/hist.h"
+#include "../../util/pstack.h"
+#include "../../util/sort.h"
+#include "../../util/util.h"
#include "../browser.h"
#include "../helpline.h"
@@ -840,10 +840,14 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size,
int printed;
const struct dso *dso = self->dso_filter;
const struct thread *thread = self->thread_filter;
- unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE];
+ unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE];
+ u64 nr_events = self->stats.total_period;
+
+ nr_samples = convert_unit(nr_samples, &unit);
+ printed = scnprintf(bf, size,
+ "Samples: %lu%c of event '%s', Event count (approx.): %lu",
+ nr_samples, unit, ev_name, nr_events);
- nr_events = convert_unit(nr_events, &unit);
- printed = scnprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name);
if (self->uid_filter_str)
printed += snprintf(bf + printed, size - printed,
@@ -937,7 +941,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
goto zoom_dso;
case 't':
goto zoom_thread;
- case 's':
+ case '/':
if (ui_browser__input_window("Symbol to show",
"Please enter the name of symbol you want to see",
buf, "ENTER: OK, ESC: Cancel",
@@ -965,7 +969,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
"E Expand all callchains\n"
"d Zoom into current DSO\n"
"t Zoom into current Thread\n"
- "s Filter symbol by name");
+ "/ Filter symbol by name");
continue;
case K_ENTER:
case K_RIGHT:
diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/ui/browsers/map.c
index eca6575abfd0..98851d55a53e 100644
--- a/tools/perf/util/ui/browsers/map.c
+++ b/tools/perf/ui/browsers/map.c
@@ -5,9 +5,9 @@
#include <sys/ttydefaults.h>
#include <string.h>
#include <linux/bitops.h>
-#include "../../util.h"
-#include "../../debug.h"
-#include "../../symbol.h"
+#include "../../util/util.h"
+#include "../../util/debug.h"
+#include "../../util/symbol.h"
#include "../browser.h"
#include "../helpline.h"
#include "map.h"
diff --git a/tools/perf/util/ui/browsers/map.h b/tools/perf/ui/browsers/map.h
index df8581a43e17..df8581a43e17 100644
--- a/tools/perf/util/ui/browsers/map.h
+++ b/tools/perf/ui/browsers/map.h
diff --git a/tools/perf/util/gtk/browser.c b/tools/perf/ui/gtk/browser.c
index 258352a2356c..0656c381a89c 100644
--- a/tools/perf/util/gtk/browser.c
+++ b/tools/perf/ui/gtk/browser.c
@@ -9,24 +9,13 @@
#define MAX_COLUMNS 32
-void perf_gtk_setup_browser(int argc, const char *argv[],
- bool fallback_to_pager __used)
-{
- gtk_init(&argc, (char ***)&argv);
-}
-
-void perf_gtk_exit_browser(bool wait_for_ok __used)
-{
- gtk_main_quit();
-}
-
-static void perf_gtk_signal(int sig)
+static void perf_gtk__signal(int sig)
{
psignal(sig, "perf");
gtk_main_quit();
}
-static void perf_gtk_resize_window(GtkWidget *window)
+static void perf_gtk__resize_window(GtkWidget *window)
{
GdkRectangle rect;
GdkScreen *screen;
@@ -46,7 +35,7 @@ static void perf_gtk_resize_window(GtkWidget *window)
gtk_window_resize(GTK_WINDOW(window), width, height);
}
-static void perf_gtk_show_hists(GtkWidget *window, struct hists *hists)
+static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
{
GType col_types[MAX_COLUMNS];
GtkCellRenderer *renderer;
@@ -142,11 +131,11 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
GtkWidget *notebook;
GtkWidget *window;
- signal(SIGSEGV, perf_gtk_signal);
- signal(SIGFPE, perf_gtk_signal);
- signal(SIGINT, perf_gtk_signal);
- signal(SIGQUIT, perf_gtk_signal);
- signal(SIGTERM, perf_gtk_signal);
+ signal(SIGSEGV, perf_gtk__signal);
+ signal(SIGFPE, perf_gtk__signal);
+ signal(SIGINT, perf_gtk__signal);
+ signal(SIGQUIT, perf_gtk__signal);
+ signal(SIGTERM, perf_gtk__signal);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
@@ -168,7 +157,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
- perf_gtk_show_hists(scrolled_window, hists);
+ perf_gtk__show_hists(scrolled_window, hists);
tab_label = gtk_label_new(evname);
@@ -179,7 +168,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
gtk_widget_show_all(window);
- perf_gtk_resize_window(window);
+ perf_gtk__resize_window(window);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
diff --git a/tools/perf/util/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h
index 75177ee04032..75177ee04032 100644
--- a/tools/perf/util/gtk/gtk.h
+++ b/tools/perf/ui/gtk/gtk.h
diff --git a/tools/perf/ui/gtk/setup.c b/tools/perf/ui/gtk/setup.c
new file mode 100644
index 000000000000..829529957766
--- /dev/null
+++ b/tools/perf/ui/gtk/setup.c
@@ -0,0 +1,12 @@
+#include "gtk.h"
+#include "../../util/cache.h"
+
+int perf_gtk__init(void)
+{
+ return gtk_init_check(NULL, NULL) ? 0 : -1;
+}
+
+void perf_gtk__exit(bool wait_for_ok __used)
+{
+ gtk_main_quit();
+}
diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/ui/helpline.c
index 2f950c2641c8..2f950c2641c8 100644
--- a/tools/perf/util/ui/helpline.c
+++ b/tools/perf/ui/helpline.c
diff --git a/tools/perf/util/ui/helpline.h b/tools/perf/ui/helpline.h
index 7bab6b34e35e..7bab6b34e35e 100644
--- a/tools/perf/util/ui/helpline.h
+++ b/tools/perf/ui/helpline.h
diff --git a/tools/perf/util/ui/keysyms.h b/tools/perf/ui/keysyms.h
index 809eca5707fa..809eca5707fa 100644
--- a/tools/perf/util/ui/keysyms.h
+++ b/tools/perf/ui/keysyms.h
diff --git a/tools/perf/util/ui/libslang.h b/tools/perf/ui/libslang.h
index 4d54b6450f5b..4d54b6450f5b 100644
--- a/tools/perf/util/ui/libslang.h
+++ b/tools/perf/ui/libslang.h
diff --git a/tools/perf/util/ui/progress.c b/tools/perf/ui/progress.c
index 13aa64e50e11..13aa64e50e11 100644
--- a/tools/perf/util/ui/progress.c
+++ b/tools/perf/ui/progress.c
diff --git a/tools/perf/util/ui/progress.h b/tools/perf/ui/progress.h
index d9c205b59aa1..d9c205b59aa1 100644
--- a/tools/perf/util/ui/progress.h
+++ b/tools/perf/ui/progress.h
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c
new file mode 100644
index 000000000000..9f5f888f73e3
--- /dev/null
+++ b/tools/perf/ui/setup.c
@@ -0,0 +1,45 @@
+#include "../cache.h"
+#include "../debug.h"
+
+
+void setup_browser(bool fallback_to_pager)
+{
+ if (!isatty(1) || dump_trace)
+ use_browser = 0;
+
+ /* default to TUI */
+ if (use_browser < 0)
+ use_browser = 1;
+
+ switch (use_browser) {
+ case 2:
+ if (perf_gtk__init() == 0)
+ break;
+ /* fall through */
+ case 1:
+ use_browser = 1;
+ if (ui__init() == 0)
+ break;
+ /* fall through */
+ default:
+ if (fallback_to_pager)
+ setup_pager();
+ break;
+ }
+}
+
+void exit_browser(bool wait_for_ok)
+{
+ switch (use_browser) {
+ case 2:
+ perf_gtk__exit(wait_for_ok);
+ break;
+
+ case 1:
+ ui__exit(wait_for_ok);
+ break;
+
+ default:
+ break;
+ }
+}
diff --git a/tools/perf/util/ui/setup.c b/tools/perf/ui/tui/setup.c
index 85a69faa09aa..d33e943ac434 100644
--- a/tools/perf/util/ui/setup.c
+++ b/tools/perf/ui/tui/setup.c
@@ -2,14 +2,14 @@
#include <signal.h>
#include <stdbool.h>
-#include "../cache.h"
-#include "../debug.h"
-#include "browser.h"
-#include "helpline.h"
-#include "ui.h"
-#include "util.h"
-#include "libslang.h"
-#include "keysyms.h"
+#include "../../util/cache.h"
+#include "../../util/debug.h"
+#include "../browser.h"
+#include "../helpline.h"
+#include "../ui.h"
+#include "../util.h"
+#include "../libslang.h"
+#include "../keysyms.h"
pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
@@ -93,45 +93,26 @@ static void newt_suspend(void *d __used)
newtResume();
}
-static int ui__init(void)
-{
- int err = SLkp_init();
-
- if (err < 0)
- goto out;
-
- SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB);
-out:
- return err;
-}
-
-static void ui__exit(void)
-{
- SLtt_set_cursor_visibility(1);
- SLsmg_refresh();
- SLsmg_reset_smg();
- SLang_reset_tty();
-}
-
static void ui__signal(int sig)
{
- ui__exit();
+ ui__exit(false);
psignal(sig, "perf");
exit(0);
}
-void setup_browser(bool fallback_to_pager)
+int ui__init(void)
{
- if (!isatty(1) || !use_browser || dump_trace) {
- use_browser = 0;
- if (fallback_to_pager)
- setup_pager();
- return;
- }
+ int err;
- use_browser = 1;
newtInit();
- ui__init();
+ err = SLkp_init();
+ if (err < 0) {
+ pr_err("TUI initialization failed.\n");
+ goto out;
+ }
+
+ SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB);
+
newtSetSuspendCallback(newt_suspend, NULL);
ui_helpline__init();
ui_browser__init();
@@ -141,15 +122,19 @@ void setup_browser(bool fallback_to_pager)
signal(SIGINT, ui__signal);
signal(SIGQUIT, ui__signal);
signal(SIGTERM, ui__signal);
+out:
+ return err;
}
-void exit_browser(bool wait_for_ok)
+void ui__exit(bool wait_for_ok)
{
- if (use_browser > 0) {
- if (wait_for_ok)
- ui__question_window("Fatal Error",
- ui_helpline__last_msg,
- "Press any key...", 0);
- ui__exit();
- }
+ if (wait_for_ok)
+ ui__question_window("Fatal Error",
+ ui_helpline__last_msg,
+ "Press any key...", 0);
+
+ SLtt_set_cursor_visibility(1);
+ SLsmg_refresh();
+ SLsmg_reset_smg();
+ SLang_reset_tty();
}
diff --git a/tools/perf/util/ui/ui.h b/tools/perf/ui/ui.h
index 7b67045479f6..7b67045479f6 100644
--- a/tools/perf/util/ui/ui.h
+++ b/tools/perf/ui/ui.h
diff --git a/tools/perf/util/ui/util.c b/tools/perf/ui/util.c
index ad4374a16bb0..ad4374a16bb0 100644
--- a/tools/perf/util/ui/util.c
+++ b/tools/perf/ui/util.c
diff --git a/tools/perf/util/ui/util.h b/tools/perf/ui/util.h
index 2d1738bd71c8..2d1738bd71c8 100644
--- a/tools/perf/util/ui/util.h
+++ b/tools/perf/ui/util.h
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 08c6d138a655..8069dfb5ba77 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -18,6 +18,403 @@
const char *disassembler_style;
+static struct ins *ins__find(const char *name);
+static int disasm_line__parse(char *line, char **namep, char **rawp);
+
+static void ins__delete(struct ins_operands *ops)
+{
+ free(ops->source.raw);
+ free(ops->source.name);
+ free(ops->target.raw);
+ free(ops->target.name);
+}
+
+static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size,
+ struct ins_operands *ops)
+{
+ return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw);
+}
+
+int ins__scnprintf(struct ins *ins, char *bf, size_t size,
+ struct ins_operands *ops)
+{
+ if (ins->ops->scnprintf)
+ return ins->ops->scnprintf(ins, bf, size, ops);
+
+ return ins__raw_scnprintf(ins, bf, size, ops);
+}
+
+static int call__parse(struct ins_operands *ops)
+{
+ char *endptr, *tok, *name;
+
+ ops->target.addr = strtoull(ops->raw, &endptr, 16);
+
+ name = strchr(endptr, '<');
+ if (name == NULL)
+ goto indirect_call;
+
+ name++;
+
+ tok = strchr(name, '>');
+ if (tok == NULL)
+ return -1;
+
+ *tok = '\0';
+ ops->target.name = strdup(name);
+ *tok = '>';
+
+ return ops->target.name == NULL ? -1 : 0;
+
+indirect_call:
+ tok = strchr(endptr, '(');
+ if (tok != NULL) {
+ ops->target.addr = 0;
+ return 0;
+ }
+
+ tok = strchr(endptr, '*');
+ if (tok == NULL)
+ return -1;
+
+ ops->target.addr = strtoull(tok + 1, NULL, 16);
+ return 0;
+}
+
+static int call__scnprintf(struct ins *ins, char *bf, size_t size,
+ struct ins_operands *ops)
+{
+ if (ops->target.name)
+ return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name);
+
+ if (ops->target.addr == 0)
+ return ins__raw_scnprintf(ins, bf, size, ops);
+
+ return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr);
+}
+
+static struct ins_ops call_ops = {
+ .parse = call__parse,
+ .scnprintf = call__scnprintf,
+};
+
+bool ins__is_call(const struct ins *ins)
+{
+ return ins->ops == &call_ops;
+}
+
+static int jump__parse(struct ins_operands *ops)
+{
+ const char *s = strchr(ops->raw, '+');
+
+ ops->target.addr = strtoll(ops->raw, NULL, 16);
+
+ if (s++ != NULL)
+ ops->target.offset = strtoll(s, NULL, 16);
+ else
+ ops->target.offset = UINT64_MAX;
+
+ return 0;
+}
+
+static int jump__scnprintf(struct ins *ins, char *bf, size_t size,
+ struct ins_operands *ops)
+{
+ return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset);
+}
+
+static struct ins_ops jump_ops = {
+ .parse = jump__parse,
+ .scnprintf = jump__scnprintf,
+};
+
+bool ins__is_jump(const struct ins *ins)
+{
+ return ins->ops == &jump_ops;
+}
+
+static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep)
+{
+ char *endptr, *name, *t;
+
+ if (strstr(raw, "(%rip)") == NULL)
+ return 0;
+
+ *addrp = strtoull(comment, &endptr, 16);
+ name = strchr(endptr, '<');
+ if (name == NULL)
+ return -1;
+
+ name++;
+
+ t = strchr(name, '>');
+ if (t == NULL)
+ return 0;
+
+ *t = '\0';
+ *namep = strdup(name);
+ *t = '>';
+
+ return 0;
+}
+
+static int lock__parse(struct ins_operands *ops)
+{
+ char *name;
+
+ ops->locked.ops = zalloc(sizeof(*ops->locked.ops));
+ if (ops->locked.ops == NULL)
+ return 0;
+
+ if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0)
+ goto out_free_ops;
+
+ ops->locked.ins = ins__find(name);
+ if (ops->locked.ins == NULL)
+ goto out_free_ops;
+
+ if (!ops->locked.ins->ops)
+ return 0;
+
+ if (ops->locked.ins->ops->parse)
+ ops->locked.ins->ops->parse(ops->locked.ops);
+
+ return 0;
+
+out_free_ops:
+ free(ops->locked.ops);
+ ops->locked.ops = NULL;
+ return 0;
+}
+
+static int lock__scnprintf(struct ins *ins, char *bf, size_t size,
+ struct ins_operands *ops)
+{
+ int printed;
+
+ if (ops->locked.ins == NULL)
+ return ins__raw_scnprintf(ins, bf, size, ops);
+
+ printed = scnprintf(bf, size, "%-6.6s ", ins->name);
+ return printed + ins__scnprintf(ops->locked.ins, bf + printed,
+ size - printed, ops->locked.ops);
+}
+
+static void lock__delete(struct ins_operands *ops)
+{
+ free(ops->locked.ops);
+ free(ops->target.raw);
+ free(ops->target.name);
+}
+
+static struct ins_ops lock_ops = {
+ .free = lock__delete,
+ .parse = lock__parse,
+ .scnprintf = lock__scnprintf,
+};
+
+static int mov__parse(struct ins_operands *ops)
+{
+ char *s = strchr(ops->raw, ','), *target, *comment, prev;
+
+ if (s == NULL)
+ return -1;
+
+ *s = '\0';
+ ops->source.raw = strdup(ops->raw);
+ *s = ',';
+
+ if (ops->source.raw == NULL)
+ return -1;
+
+ target = ++s;
+
+ while (s[0] != '\0' && !isspace(s[0]))
+ ++s;
+ prev = *s;
+ *s = '\0';
+
+ ops->target.raw = strdup(target);
+ *s = prev;
+
+ if (ops->target.raw == NULL)
+ goto out_free_source;
+
+ comment = strchr(s, '#');
+ if (comment == NULL)
+ return 0;
+
+ while (comment[0] != '\0' && isspace(comment[0]))
+ ++comment;
+
+ comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name);
+ comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name);
+
+ return 0;
+
+out_free_source:
+ free(ops->source.raw);
+ ops->source.raw = NULL;
+ return -1;
+}
+
+static int mov__scnprintf(struct ins *ins, char *bf, size_t size,
+ struct ins_operands *ops)
+{
+ return scnprintf(bf, size, "%-6.6s %s,%s", ins->name,
+ ops->source.name ?: ops->source.raw,
+ ops->target.name ?: ops->target.raw);
+}
+
+static struct ins_ops mov_ops = {
+ .parse = mov__parse,
+ .scnprintf = mov__scnprintf,
+};
+
+static int dec__parse(struct ins_operands *ops)
+{
+ char *target, *comment, *s, prev;
+
+ target = s = ops->raw;
+
+ while (s[0] != '\0' && !isspace(s[0]))
+ ++s;
+ prev = *s;
+ *s = '\0';
+
+ ops->target.raw = strdup(target);
+ *s = prev;
+
+ if (ops->target.raw == NULL)
+ return -1;
+
+ comment = strchr(s, '#');
+ if (comment == NULL)
+ return 0;
+
+ while (comment[0] != '\0' && isspace(comment[0]))
+ ++comment;
+
+ comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name);
+
+ return 0;
+}
+
+static int dec__scnprintf(struct ins *ins, char *bf, size_t size,
+ struct ins_operands *ops)
+{
+ return scnprintf(bf, size, "%-6.6s %s", ins->name,
+ ops->target.name ?: ops->target.raw);
+}
+
+static struct ins_ops dec_ops = {
+ .parse = dec__parse,
+ .scnprintf = dec__scnprintf,
+};
+
+static int nop__scnprintf(struct ins *ins __used, char *bf, size_t size,
+ struct ins_operands *ops __used)
+{
+ return scnprintf(bf, size, "%-6.6s", "nop");
+}
+
+static struct ins_ops nop_ops = {
+ .scnprintf = nop__scnprintf,
+};
+
+/*
+ * Must be sorted by name!
+ */
+static struct ins instructions[] = {
+ { .name = "add", .ops = &mov_ops, },
+ { .name = "addl", .ops = &mov_ops, },
+ { .name = "addq", .ops = &mov_ops, },
+ { .name = "addw", .ops = &mov_ops, },
+ { .name = "and", .ops = &mov_ops, },
+ { .name = "bts", .ops = &mov_ops, },
+ { .name = "call", .ops = &call_ops, },
+ { .name = "callq", .ops = &call_ops, },
+ { .name = "cmp", .ops = &mov_ops, },
+ { .name = "cmpb", .ops = &mov_ops, },
+ { .name = "cmpl", .ops = &mov_ops, },
+ { .name = "cmpq", .ops = &mov_ops, },
+ { .name = "cmpw", .ops = &mov_ops, },
+ { .name = "cmpxch", .ops = &mov_ops, },
+ { .name = "dec", .ops = &dec_ops, },
+ { .name = "decl", .ops = &dec_ops, },
+ { .name = "imul", .ops = &mov_ops, },
+ { .name = "inc", .ops = &dec_ops, },
+ { .name = "incl", .ops = &dec_ops, },
+ { .name = "ja", .ops = &jump_ops, },
+ { .name = "jae", .ops = &jump_ops, },
+ { .name = "jb", .ops = &jump_ops, },
+ { .name = "jbe", .ops = &jump_ops, },
+ { .name = "jc", .ops = &jump_ops, },
+ { .name = "jcxz", .ops = &jump_ops, },
+ { .name = "je", .ops = &jump_ops, },
+ { .name = "jecxz", .ops = &jump_ops, },
+ { .name = "jg", .ops = &jump_ops, },
+ { .name = "jge", .ops = &jump_ops, },
+ { .name = "jl", .ops = &jump_ops, },
+ { .name = "jle", .ops = &jump_ops, },
+ { .name = "jmp", .ops = &jump_ops, },
+ { .name = "jmpq", .ops = &jump_ops, },
+ { .name = "jna", .ops = &jump_ops, },
+ { .name = "jnae", .ops = &jump_ops, },
+ { .name = "jnb", .ops = &jump_ops, },
+ { .name = "jnbe", .ops = &jump_ops, },
+ { .name = "jnc", .ops = &jump_ops, },
+ { .name = "jne", .ops = &jump_ops, },
+ { .name = "jng", .ops = &jump_ops, },
+ { .name = "jnge", .ops = &jump_ops, },
+ { .name = "jnl", .ops = &jump_ops, },
+ { .name = "jnle", .ops = &jump_ops, },
+ { .name = "jno", .ops = &jump_ops, },
+ { .name = "jnp", .ops = &jump_ops, },
+ { .name = "jns", .ops = &jump_ops, },
+ { .name = "jnz", .ops = &jump_ops, },
+ { .name = "jo", .ops = &jump_ops, },
+ { .name = "jp", .ops = &jump_ops, },
+ { .name = "jpe", .ops = &jump_ops, },
+ { .name = "jpo", .ops = &jump_ops, },
+ { .name = "jrcxz", .ops = &jump_ops, },
+ { .name = "js", .ops = &jump_ops, },
+ { .name = "jz", .ops = &jump_ops, },
+ { .name = "lea", .ops = &mov_ops, },
+ { .name = "lock", .ops = &lock_ops, },
+ { .name = "mov", .ops = &mov_ops, },
+ { .name = "movb", .ops = &mov_ops, },
+ { .name = "movdqa",.ops = &mov_ops, },
+ { .name = "movl", .ops = &mov_ops, },
+ { .name = "movq", .ops = &mov_ops, },
+ { .name = "movslq", .ops = &mov_ops, },
+ { .name = "movzbl", .ops = &mov_ops, },
+ { .name = "movzwl", .ops = &mov_ops, },
+ { .name = "nop", .ops = &nop_ops, },
+ { .name = "nopl", .ops = &nop_ops, },
+ { .name = "nopw", .ops = &nop_ops, },
+ { .name = "or", .ops = &mov_ops, },
+ { .name = "orl", .ops = &mov_ops, },
+ { .name = "test", .ops = &mov_ops, },
+ { .name = "testb", .ops = &mov_ops, },
+ { .name = "testl", .ops = &mov_ops, },
+ { .name = "xadd", .ops = &mov_ops, },
+};
+
+static int ins__cmp(const void *name, const void *insp)
+{
+ const struct ins *ins = insp;
+
+ return strcmp(name, ins->name);
+}
+
+static struct ins *ins__find(const char *name)
+{
+ const int nmemb = ARRAY_SIZE(instructions);
+
+ return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__cmp);
+}
+
int symbol__annotate_init(struct map *map __used, struct symbol *sym)
{
struct annotation *notes = symbol__annotation(sym);
@@ -28,7 +425,7 @@ int symbol__annotate_init(struct map *map __used, struct symbol *sym)
int symbol__alloc_hist(struct symbol *sym)
{
struct annotation *notes = symbol__annotation(sym);
- const size_t size = sym->end - sym->start + 1;
+ const size_t size = symbol__size(sym);
size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));
notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
@@ -78,31 +475,110 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
return 0;
}
-static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize)
+static void disasm_line__init_ins(struct disasm_line *dl)
+{
+ dl->ins = ins__find(dl->name);
+
+ if (dl->ins == NULL)
+ return;
+
+ if (!dl->ins->ops)
+ return;
+
+ if (dl->ins->ops->parse)
+ dl->ins->ops->parse(&dl->ops);
+}
+
+static int disasm_line__parse(char *line, char **namep, char **rawp)
+{
+ char *name = line, tmp;
+
+ while (isspace(name[0]))
+ ++name;
+
+ if (name[0] == '\0')
+ return -1;
+
+ *rawp = name + 1;
+
+ while ((*rawp)[0] != '\0' && !isspace((*rawp)[0]))
+ ++*rawp;
+
+ tmp = (*rawp)[0];
+ (*rawp)[0] = '\0';
+ *namep = strdup(name);
+
+ if (*namep == NULL)
+ goto out_free_name;
+
+ (*rawp)[0] = tmp;
+
+ if ((*rawp)[0] != '\0') {
+ (*rawp)++;
+ while (isspace((*rawp)[0]))
+ ++(*rawp);
+ }
+
+ return 0;
+
+out_free_name:
+ free(*namep);
+ *namep = NULL;
+ return -1;
+}
+
+static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize)
{
- struct objdump_line *self = malloc(sizeof(*self) + privsize);
+ struct disasm_line *dl = zalloc(sizeof(*dl) + privsize);
- if (self != NULL) {
- self->offset = offset;
- self->line = line;
+ if (dl != NULL) {
+ dl->offset = offset;
+ dl->line = strdup(line);
+ if (dl->line == NULL)
+ goto out_delete;
+
+ if (offset != -1) {
+ if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0)
+ goto out_free_line;
+
+ disasm_line__init_ins(dl);
+ }
}
- return self;
+ return dl;
+
+out_free_line:
+ free(dl->line);
+out_delete:
+ free(dl);
+ return NULL;
+}
+
+void disasm_line__free(struct disasm_line *dl)
+{
+ free(dl->line);
+ free(dl->name);
+ if (dl->ins && dl->ins->ops->free)
+ dl->ins->ops->free(&dl->ops);
+ else
+ ins__delete(&dl->ops);
+ free(dl);
}
-void objdump_line__free(struct objdump_line *self)
+int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw)
{
- free(self->line);
- free(self);
+ if (raw || !dl->ins)
+ return scnprintf(bf, size, "%-6.6s %s", dl->name, dl->ops.raw);
+
+ return ins__scnprintf(dl->ins, bf, size, &dl->ops);
}
-static void objdump__add_line(struct list_head *head, struct objdump_line *line)
+static void disasm__add(struct list_head *head, struct disasm_line *line)
{
list_add_tail(&line->node, head);
}
-struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
- struct objdump_line *pos)
+struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos)
{
list_for_each_entry_continue(pos, head, node)
if (pos->offset >= 0)
@@ -111,15 +587,14 @@ struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
return NULL;
}
-static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
- int evidx, u64 len, int min_pcnt,
- int printed, int max_lines,
- struct objdump_line *queue)
+static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start,
+ int evidx, u64 len, int min_pcnt, int printed,
+ int max_lines, struct disasm_line *queue)
{
static const char *prev_line;
static const char *prev_color;
- if (oline->offset != -1) {
+ if (dl->offset != -1) {
const char *path = NULL;
unsigned int hits = 0;
double percent = 0.0;
@@ -127,10 +602,11 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
struct annotation *notes = symbol__annotation(sym);
struct source_line *src_line = notes->src->lines;
struct sym_hist *h = annotation__histogram(notes, evidx);
- s64 offset = oline->offset;
- struct objdump_line *next;
+ s64 offset = dl->offset;
+ const u64 addr = start + offset;
+ struct disasm_line *next;
- next = objdump__get_next_ip_line(&notes->src->source, oline);
+ next = disasm__get_next_ip_line(&notes->src->source, dl);
while (offset < (s64)len &&
(next == NULL || offset < next->offset)) {
@@ -155,9 +631,9 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
if (queue != NULL) {
list_for_each_entry_from(queue, &notes->src->source, node) {
- if (queue == oline)
+ if (queue == dl)
break;
- objdump_line__print(queue, sym, evidx, len,
+ disasm_line__print(queue, sym, start, evidx, len,
0, 0, 1, NULL);
}
}
@@ -180,17 +656,18 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
color_fprintf(stdout, color, " %7.2f", percent);
printf(" : ");
- color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", oline->line);
+ color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr);
+ color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line);
} else if (max_lines && printed >= max_lines)
return 1;
else {
if (queue)
return -1;
- if (!*oline->line)
+ if (!*dl->line)
printf(" :\n");
else
- printf(" : %s\n", oline->line);
+ printf(" : %s\n", dl->line);
}
return 0;
@@ -200,8 +677,8 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
FILE *file, size_t privsize)
{
struct annotation *notes = symbol__annotation(sym);
- struct objdump_line *objdump_line;
- char *line = NULL, *tmp, *tmp2, *c;
+ struct disasm_line *dl;
+ char *line = NULL, *parsed_line, *tmp, *tmp2, *c;
size_t line_len;
s64 line_ip, offset = -1;
@@ -219,6 +696,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
*c = 0;
line_ip = -1;
+ parsed_line = line;
/*
* Strip leading spaces:
@@ -246,14 +724,17 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
offset = line_ip - start;
if (offset < 0 || (u64)line_ip > end)
offset = -1;
+ else
+ parsed_line = tmp2 + 1;
}
- objdump_line = objdump_line__new(offset, line, privsize);
- if (objdump_line == NULL) {
- free(line);
+ dl = disasm_line__new(offset, parsed_line, privsize);
+ free(line);
+
+ if (dl == NULL)
return -1;
- }
- objdump__add_line(&notes->src->source, objdump_line);
+
+ disasm__add(&notes->src->source, dl);
return 0;
}
@@ -476,7 +957,7 @@ static void symbol__annotate_hits(struct symbol *sym, int evidx)
{
struct annotation *notes = symbol__annotation(sym);
struct sym_hist *h = annotation__histogram(notes, evidx);
- u64 len = sym->end - sym->start, offset;
+ u64 len = symbol__size(sym), offset;
for (offset = 0; offset < len; ++offset)
if (h->addr[offset] != 0)
@@ -492,7 +973,8 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
struct dso *dso = map->dso;
const char *filename = dso->long_name, *d_filename;
struct annotation *notes = symbol__annotation(sym);
- struct objdump_line *pos, *queue = NULL;
+ struct disasm_line *pos, *queue = NULL;
+ u64 start = map__rip_2objdump(map, sym->start);
int printed = 2, queue_len = 0;
int more = 0;
u64 len;
@@ -502,7 +984,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
else
d_filename = basename(filename);
- len = sym->end - sym->start;
+ len = symbol__size(sym);
printf(" Percent | Source code & Disassembly of %s\n", d_filename);
printf("------------------------------------------------\n");
@@ -516,8 +998,9 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
queue_len = 0;
}
- switch (objdump_line__print(pos, sym, evidx, len, min_pcnt,
- printed, max_lines, queue)) {
+ switch (disasm_line__print(pos, sym, start, evidx, len,
+ min_pcnt, printed, max_lines,
+ queue)) {
case 0:
++printed;
if (context) {
@@ -561,7 +1044,7 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
{
struct annotation *notes = symbol__annotation(sym);
struct sym_hist *h = annotation__histogram(notes, evidx);
- int len = sym->end - sym->start, offset;
+ int len = symbol__size(sym), offset;
h->sum = 0;
for (offset = 0; offset < len; ++offset) {
@@ -570,14 +1053,42 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
}
}
-void objdump_line_list__purge(struct list_head *head)
+void disasm__purge(struct list_head *head)
{
- struct objdump_line *pos, *n;
+ struct disasm_line *pos, *n;
list_for_each_entry_safe(pos, n, head, node) {
list_del(&pos->node);
- objdump_line__free(pos);
+ disasm_line__free(pos);
+ }
+}
+
+static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp)
+{
+ size_t printed;
+
+ if (dl->offset == -1)
+ return fprintf(fp, "%s\n", dl->line);
+
+ printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->name);
+
+ if (dl->ops.raw[0] != '\0') {
+ printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ",
+ dl->ops.raw);
}
+
+ return printed + fprintf(fp, "\n");
+}
+
+size_t disasm__fprintf(struct list_head *head, FILE *fp)
+{
+ struct disasm_line *pos;
+ size_t printed = 0;
+
+ list_for_each_entry(pos, head, node)
+ printed += disasm_line__fprintf(pos, fp);
+
+ return printed;
}
int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
@@ -592,7 +1103,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
if (symbol__annotate(sym, map, 0) < 0)
return -1;
- len = sym->end - sym->start;
+ len = symbol__size(sym);
if (print_lines) {
symbol__get_source_line(sym, map, evidx, &source_line,
@@ -605,7 +1116,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
if (print_lines)
symbol__free_source_line(sym, len);
- objdump_line_list__purge(&symbol__annotation(sym)->src->source);
+ disasm__purge(&symbol__annotation(sym)->src->source);
return 0;
}
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index efa5dc82bfae..78a5692dd718 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -2,20 +2,69 @@
#define __PERF_ANNOTATE_H
#include <stdbool.h>
+#include <stdint.h>
#include "types.h"
#include "symbol.h"
#include <linux/list.h>
#include <linux/rbtree.h>
-struct objdump_line {
- struct list_head node;
- s64 offset;
- char *line;
+struct ins;
+
+struct ins_operands {
+ char *raw;
+ struct {
+ char *raw;
+ char *name;
+ u64 addr;
+ u64 offset;
+ } target;
+ union {
+ struct {
+ char *raw;
+ char *name;
+ u64 addr;
+ } source;
+ struct {
+ struct ins *ins;
+ struct ins_operands *ops;
+ } locked;
+ };
};
-void objdump_line__free(struct objdump_line *self);
-struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
- struct objdump_line *pos);
+struct ins_ops {
+ void (*free)(struct ins_operands *ops);
+ int (*parse)(struct ins_operands *ops);
+ int (*scnprintf)(struct ins *ins, char *bf, size_t size,
+ struct ins_operands *ops);
+};
+
+struct ins {
+ const char *name;
+ struct ins_ops *ops;
+};
+
+bool ins__is_jump(const struct ins *ins);
+bool ins__is_call(const struct ins *ins);
+int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops);
+
+struct disasm_line {
+ struct list_head node;
+ s64 offset;
+ char *line;
+ char *name;
+ struct ins *ins;
+ struct ins_operands ops;
+};
+
+static inline bool disasm_line__has_offset(const struct disasm_line *dl)
+{
+ return dl->ops.target.offset != UINT64_MAX;
+}
+
+void disasm_line__free(struct disasm_line *dl);
+struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos);
+int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw);
+size_t disasm__fprintf(struct list_head *head, FILE *fp);
struct sym_hist {
u64 sum;
@@ -32,7 +81,7 @@ struct source_line {
*
* @histogram: Array of addr hit histograms per event being monitored
* @lines: If 'print_lines' is specified, per source code line percentages
- * @source: source parsed from objdump -dS
+ * @source: source parsed from a disassembler like objdump -dS
*
* lines is allocated, percentages calculated and all sorted by percentage
* when the annotation is about to be presented, so the percentages are for
@@ -82,7 +131,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
int context);
void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
-void objdump_line_list__purge(struct list_head *head);
+void disasm__purge(struct list_head *head);
int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
bool print_lines, bool full_paths, int min_pcnt,
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index dff9c7a725f4..fd9a5944b627 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -65,6 +65,8 @@ struct perf_tool build_id__mark_dso_hit_ops = {
.mmap = perf_event__process_mmap,
.fork = perf_event__process_task,
.exit = perf_event__exit_del_thread,
+ .attr = perf_event__process_attr,
+ .build_id = perf_event__process_build_id,
};
char *dso__build_id_filename(struct dso *self, char *bf, size_t size)
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 8dd224df3e54..cff18c617d13 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -33,7 +33,7 @@ extern int pager_use_color;
extern int use_browser;
-#ifdef NO_NEWT_SUPPORT
+#if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT)
static inline void setup_browser(bool fallback_to_pager)
{
if (fallback_to_pager)
@@ -43,19 +43,29 @@ static inline void exit_browser(bool wait_for_ok __used) {}
#else
void setup_browser(bool fallback_to_pager);
void exit_browser(bool wait_for_ok);
+
+#ifdef NO_NEWT_SUPPORT
+static inline int ui__init(void)
+{
+ return -1;
+}
+static inline void ui__exit(bool wait_for_ok __used) {}
+#else
+int ui__init(void);
+void ui__exit(bool wait_for_ok);
#endif
#ifdef NO_GTK2_SUPPORT
-static inline void perf_gtk_setup_browser(int argc __used, const char *argv[] __used, bool fallback_to_pager)
+static inline int perf_gtk__init(void)
{
- if (fallback_to_pager)
- setup_pager();
+ return -1;
}
-static inline void perf_gtk_exit_browser(bool wait_for_ok __used) {}
+static inline void perf_gtk__exit(bool wait_for_ok __used) {}
#else
-void perf_gtk_setup_browser(int argc, const char *argv[], bool fallback_to_pager);
-void perf_gtk_exit_browser(bool wait_for_ok);
+int perf_gtk__init(void);
+void perf_gtk__exit(bool wait_for_ok);
#endif
+#endif /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */
char *alias_lookup(const char *alias);
int split_cmdline(char *cmdline, const char ***argv);
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 26817daa2961..efb1fce259a4 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -11,6 +11,7 @@
#include "event.h"
#include "debug.h"
#include "util.h"
+#include "target.h"
int verbose;
bool dump_trace = false, quiet = false;
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index f2ce88d04f54..6bebe7f0a20c 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -26,7 +26,7 @@ static inline void ui_progress__update(u64 curr __used, u64 total __used,
#else
extern char ui_helpline__last_msg[];
int ui_helpline__show_help(const char *format, va_list ap);
-#include "ui/progress.h"
+#include "../ui/progress.h"
int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
#endif
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 1986d8051bd1..4ac5f5ae4ce9 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -11,6 +11,7 @@
#include <poll.h>
#include "cpumap.h"
#include "thread_map.h"
+#include "target.h"
#include "evlist.h"
#include "evsel.h"
#include <unistd.h>
@@ -599,18 +600,21 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
return perf_evlist__mmap_per_cpu(evlist, prot, mask);
}
-int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid,
- const char *target_tid, uid_t uid, const char *cpu_list)
+int perf_evlist__create_maps(struct perf_evlist *evlist,
+ struct perf_target *target)
{
- evlist->threads = thread_map__new_str(target_pid, target_tid, uid);
+ evlist->threads = thread_map__new_str(target->pid, target->tid,
+ target->uid);
if (evlist->threads == NULL)
return -1;
- if (uid != UINT_MAX || (cpu_list == NULL && target_tid))
+ if (perf_target__has_task(target))
+ evlist->cpus = cpu_map__dummy_new();
+ else if (!perf_target__has_cpu(target) && !target->uses_mmap)
evlist->cpus = cpu_map__dummy_new();
else
- evlist->cpus = cpu_map__new(cpu_list);
+ evlist->cpus = cpu_map__new(target->cpu_list);
if (evlist->cpus == NULL)
goto out_delete_threads;
@@ -827,7 +831,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
exit(-1);
}
- if (!opts->system_wide && !opts->target_tid && !opts->target_pid)
+ if (perf_target__none(&opts->target))
evlist->threads->map[0] = evlist->workload.pid;
close(child_ready_pipe[1]);
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 21f1c9e57f13..58abb63ac13a 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -106,8 +106,8 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
evlist->threads = threads;
}
-int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid,
- const char *tid, uid_t uid, const char *cpu_list);
+int perf_evlist__create_maps(struct perf_evlist *evlist,
+ struct perf_target *target);
void perf_evlist__delete_maps(struct perf_evlist *evlist);
int perf_evlist__set_filters(struct perf_evlist *evlist);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 8c13dbcb84b9..57e4ce57bbcc 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -14,6 +14,7 @@
#include "util.h"
#include "cpumap.h"
#include "thread_map.h"
+#include "target.h"
#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
#define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))
@@ -69,6 +70,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
struct perf_event_attr *attr = &evsel->attr;
int track = !evsel->idx; /* only the first counter needs these */
+ attr->disabled = 1;
attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
attr->inherit = !opts->no_inherit;
attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
@@ -106,15 +108,15 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
if (opts->call_graph)
attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
- if (opts->system_wide)
+ if (perf_target__has_cpu(&opts->target))
attr->sample_type |= PERF_SAMPLE_CPU;
if (opts->period)
attr->sample_type |= PERF_SAMPLE_PERIOD;
if (!opts->sample_id_all_missing &&
- (opts->sample_time || opts->system_wide ||
- !opts->no_inherit || opts->cpu_list))
+ (opts->sample_time || !opts->no_inherit ||
+ perf_target__has_cpu(&opts->target)))
attr->sample_type |= PERF_SAMPLE_TIME;
if (opts->raw_samples) {
@@ -135,9 +137,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
attr->mmap = track;
attr->comm = track;
- if (!opts->target_pid && !opts->target_tid && !opts->system_wide &&
+ if (perf_target__none(&opts->target) &&
(!opts->group || evsel == first)) {
- attr->disabled = 1;
attr->enable_on_exec = 1;
}
}
@@ -461,10 +462,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
* used for cross-endian analysis. See git commit 65014ab3
* for why this goofiness is needed.
*/
- union {
- u64 val64;
- u32 val32[2];
- } u;
+ union u64_swap u;
memset(data, 0, sizeof(*data));
data->cpu = data->pid = data->tid = -1;
@@ -607,10 +605,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
* used for cross-endian analysis. See git commit 65014ab3
* for why this goofiness is needed.
*/
- union {
- u64 val64;
- u32 val32[2];
- } u;
+ union u64_swap u;
array = event->sample.array;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index c0b70c697a36..2dd5edf161b7 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -31,21 +31,16 @@ static const char **header_argv;
int perf_header__push_event(u64 id, const char *name)
{
+ struct perf_trace_event_type *nevents;
+
if (strlen(name) > MAX_EVENT_NAME)
pr_warning("Event %s will be truncated\n", name);
- if (!events) {
- events = malloc(sizeof(struct perf_trace_event_type));
- if (events == NULL)
- return -ENOMEM;
- } else {
- struct perf_trace_event_type *nevents;
+ nevents = realloc(events, (event_count + 1) * sizeof(*events));
+ if (nevents == NULL)
+ return -ENOMEM;
+ events = nevents;
- nevents = realloc(events, (event_count + 1) * sizeof(*events));
- if (nevents == NULL)
- return -ENOMEM;
- events = nevents;
- }
memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
events[event_count].event_id = id;
strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
@@ -442,7 +437,7 @@ static bool perf_session__read_build_ids(struct perf_session *session, bool with
return ret;
}
-static int write_trace_info(int fd, struct perf_header *h __used,
+static int write_tracing_data(int fd, struct perf_header *h __used,
struct perf_evlist *evlist)
{
return read_tracing_data(fd, &evlist->entries);
@@ -1477,7 +1472,7 @@ out:
return err;
}
-static int process_trace_info(struct perf_file_section *section __unused,
+static int process_tracing_data(struct perf_file_section *section __unused,
struct perf_header *ph __unused,
int feat __unused, int fd)
{
@@ -1513,11 +1508,11 @@ struct feature_ops {
.full_only = true }
/* feature_ops not implemented: */
-#define print_trace_info NULL
-#define print_build_id NULL
+#define print_tracing_data NULL
+#define print_build_id NULL
static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
- FEAT_OPP(HEADER_TRACE_INFO, trace_info),
+ FEAT_OPP(HEADER_TRACING_DATA, tracing_data),
FEAT_OPP(HEADER_BUILD_ID, build_id),
FEAT_OPA(HEADER_HOSTNAME, hostname),
FEAT_OPA(HEADER_OSRELEASE, osrelease),
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 21a6be09c129..2d42b3e1826f 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -12,7 +12,7 @@
enum {
HEADER_RESERVED = 0, /* always cleared */
HEADER_FIRST_FEATURE = 1,
- HEADER_TRACE_INFO = 1,
+ HEADER_TRACING_DATA = 1,
HEADER_BUILD_ID,
HEADER_HOSTNAME,
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 9f6d630d5316..1293b5ebea4d 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -599,7 +599,7 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
if (chain->ms.sym)
ret += fprintf(fp, "%s\n", chain->ms.sym->name);
else
- ret += fprintf(fp, "%p\n", (void *)(long)chain->ip);
+ ret += fprintf(fp, "0x%0" PRIx64 "\n", chain->ip);
return ret;
}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 2cae9df40e04..cfc64e293f90 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -138,7 +138,7 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
#define K_LEFT -1
#define K_RIGHT -2
#else
-#include "ui/keysyms.h"
+#include "../ui/keysyms.h"
int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
void(*timer)(void *arg), void *arg, int delay_secs);
diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c
new file mode 100644
index 000000000000..76b98e2a587d
--- /dev/null
+++ b/tools/perf/util/parse-events-test.c
@@ -0,0 +1,625 @@
+
+#include "parse-events.h"
+#include "evsel.h"
+#include "evlist.h"
+#include "sysfs.h"
+#include "../../../include/linux/hw_breakpoint.h"
+
+#define TEST_ASSERT_VAL(text, cond) \
+do { \
+ if (!(cond)) { \
+ pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
+ return -1; \
+ } \
+} while (0)
+
+static int test__checkevent_tracepoint(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
+ TEST_ASSERT_VAL("wrong sample_type",
+ (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
+ evsel->attr.sample_type);
+ TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
+ return 0;
+}
+
+static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel;
+
+ TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
+
+ list_for_each_entry(evsel, &evlist->entries, node) {
+ TEST_ASSERT_VAL("wrong type",
+ PERF_TYPE_TRACEPOINT == evsel->attr.type);
+ TEST_ASSERT_VAL("wrong sample_type",
+ (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU)
+ == evsel->attr.sample_type);
+ TEST_ASSERT_VAL("wrong sample_period",
+ 1 == evsel->attr.sample_period);
+ }
+ return 0;
+}
+
+static int test__checkevent_raw(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+ TEST_ASSERT_VAL("wrong config", 0x1a == evsel->attr.config);
+ return 0;
+}
+
+static int test__checkevent_numeric(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+ TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
+ TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
+ return 0;
+}
+
+static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+ TEST_ASSERT_VAL("wrong config",
+ PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
+ return 0;
+}
+
+static int test__checkevent_symbolic_name_config(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
+ TEST_ASSERT_VAL("wrong config",
+ PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
+ TEST_ASSERT_VAL("wrong period",
+ 100000 == evsel->attr.sample_period);
+ TEST_ASSERT_VAL("wrong config1",
+ 0 == evsel->attr.config1);
+ TEST_ASSERT_VAL("wrong config2",
+ 1 == evsel->attr.config2);
+ return 0;
+}
+
+static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type);
+ TEST_ASSERT_VAL("wrong config",
+ PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config);
+ return 0;
+}
+
+static int test__checkevent_genhw(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type);
+ TEST_ASSERT_VAL("wrong config", (1 << 16) == evsel->attr.config);
+ return 0;
+}
+
+static int test__checkevent_breakpoint(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
+ TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
+ TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) ==
+ evsel->attr.bp_type);
+ TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 ==
+ evsel->attr.bp_len);
+ return 0;
+}
+
+static int test__checkevent_breakpoint_x(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
+ TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
+ TEST_ASSERT_VAL("wrong bp_type",
+ HW_BREAKPOINT_X == evsel->attr.bp_type);
+ TEST_ASSERT_VAL("wrong bp_len", sizeof(long) == evsel->attr.bp_len);
+ return 0;
+}
+
+static int test__checkevent_breakpoint_r(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+ TEST_ASSERT_VAL("wrong type",
+ PERF_TYPE_BREAKPOINT == evsel->attr.type);
+ TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
+ TEST_ASSERT_VAL("wrong bp_type",
+ HW_BREAKPOINT_R == evsel->attr.bp_type);
+ TEST_ASSERT_VAL("wrong bp_len",
+ HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
+ return 0;
+}
+
+static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+ TEST_ASSERT_VAL("wrong type",
+ PERF_TYPE_BREAKPOINT == evsel->attr.type);
+ TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
+ TEST_ASSERT_VAL("wrong bp_type",
+ HW_BREAKPOINT_W == evsel->attr.bp_type);
+ TEST_ASSERT_VAL("wrong bp_len",
+ HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
+ return 0;
+}
+
+static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+ TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+ TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+ TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+ return test__checkevent_tracepoint(evlist);
+}
+
+static int
+test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel;
+
+ TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
+
+ list_for_each_entry(evsel, &evlist->entries, node) {
+ TEST_ASSERT_VAL("wrong exclude_user",
+ !evsel->attr.exclude_user);
+ TEST_ASSERT_VAL("wrong exclude_kernel",
+ evsel->attr.exclude_kernel);
+ TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+ TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+ }
+
+ return test__checkevent_tracepoint_multi(evlist);
+}
+
+static int test__checkevent_raw_modifier(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+ TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+ TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+ TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+ return test__checkevent_raw(evlist);
+}
+
+static int test__checkevent_numeric_modifier(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+ TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+ TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+ TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+ return test__checkevent_numeric(evlist);
+}
+
+static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+ TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+ TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+ TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+ return test__checkevent_symbolic_name(evlist);
+}
+
+static int test__checkevent_exclude_host_modifier(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
+ TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
+
+ return test__checkevent_symbolic_name(evlist);
+}
+
+static int test__checkevent_exclude_guest_modifier(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
+ TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
+
+ return test__checkevent_symbolic_name(evlist);
+}
+
+static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+ TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+ TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+ TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+ return test__checkevent_symbolic_alias(evlist);
+}
+
+static int test__checkevent_genhw_modifier(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+ TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+ TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+ TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+ return test__checkevent_genhw(evlist);
+}
+
+static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+ TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+ TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+ TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+ return test__checkevent_breakpoint(evlist);
+}
+
+static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+ TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+ TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+ TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+ return test__checkevent_breakpoint_x(evlist);
+}
+
+static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+ TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+ TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+ TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+ return test__checkevent_breakpoint_r(evlist);
+}
+
+static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+ TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+ TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+ TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+ return test__checkevent_breakpoint_w(evlist);
+}
+
+static int test__checkevent_pmu(struct perf_evlist *evlist)
+{
+
+ struct perf_evsel *evsel = list_entry(evlist->entries.next,
+ struct perf_evsel, node);
+
+ TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+ TEST_ASSERT_VAL("wrong config", 10 == evsel->attr.config);
+ TEST_ASSERT_VAL("wrong config1", 1 == evsel->attr.config1);
+ TEST_ASSERT_VAL("wrong config2", 3 == evsel->attr.config2);
+ TEST_ASSERT_VAL("wrong period", 1000 == evsel->attr.sample_period);
+
+ return 0;
+}
+
+static int test__checkevent_list(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel;
+
+ TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
+
+ /* r1 */
+ evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+ TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
+ TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1);
+ TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2);
+ TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
+ TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+ TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+ TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+ /* syscalls:sys_enter_open:k */
+ evsel = list_entry(evsel->node.next, struct perf_evsel, node);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
+ TEST_ASSERT_VAL("wrong sample_type",
+ (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
+ evsel->attr.sample_type);
+ TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
+ TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+ TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
+ TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
+ TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
+
+ /* 1:1:hp */
+ evsel = list_entry(evsel->node.next, struct perf_evsel, node);
+ TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
+ TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
+ TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
+ TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
+ TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
+ TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
+
+ return 0;
+}
+
+static int test__checkevent_pmu_name(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel;
+
+ /* cpu/config=1,name=krava1/u */
+ evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
+ TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+ TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
+ TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "krava"));
+
+ /* cpu/config=2/" */
+ evsel = list_entry(evsel->node.next, struct perf_evsel, node);
+ TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
+ TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
+ TEST_ASSERT_VAL("wrong config", 2 == evsel->attr.config);
+ TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "raw 0x2"));
+
+ return 0;
+}
+
+struct test__event_st {
+ const char *name;
+ __u32 type;
+ int (*check)(struct perf_evlist *evlist);
+};
+
+static struct test__event_st test__events[] = {
+ [0] = {
+ .name = "syscalls:sys_enter_open",
+ .check = test__checkevent_tracepoint,
+ },
+ [1] = {
+ .name = "syscalls:*",
+ .check = test__checkevent_tracepoint_multi,
+ },
+ [2] = {
+ .name = "r1a",
+ .check = test__checkevent_raw,
+ },
+ [3] = {
+ .name = "1:1",
+ .check = test__checkevent_numeric,
+ },
+ [4] = {
+ .name = "instructions",
+ .check = test__checkevent_symbolic_name,
+ },
+ [5] = {
+ .name = "cycles/period=100000,config2/",
+ .check = test__checkevent_symbolic_name_config,
+ },
+ [6] = {
+ .name = "faults",
+ .check = test__checkevent_symbolic_alias,
+ },
+ [7] = {
+ .name = "L1-dcache-load-miss",
+ .check = test__checkevent_genhw,
+ },
+ [8] = {
+ .name = "mem:0",
+ .check = test__checkevent_breakpoint,
+ },
+ [9] = {
+ .name = "mem:0:x",
+ .check = test__checkevent_breakpoint_x,
+ },
+ [10] = {
+ .name = "mem:0:r",
+ .check = test__checkevent_breakpoint_r,
+ },
+ [11] = {
+ .name = "mem:0:w",
+ .check = test__checkevent_breakpoint_w,
+ },
+ [12] = {
+ .name = "syscalls:sys_enter_open:k",
+ .check = test__checkevent_tracepoint_modifier,
+ },
+ [13] = {
+ .name = "syscalls:*:u",
+ .check = test__checkevent_tracepoint_multi_modifier,
+ },
+ [14] = {
+ .name = "r1a:kp",
+ .check = test__checkevent_raw_modifier,
+ },
+ [15] = {
+ .name = "1:1:hp",
+ .check = test__checkevent_numeric_modifier,
+ },
+ [16] = {
+ .name = "instructions:h",
+ .check = test__checkevent_symbolic_name_modifier,
+ },
+ [17] = {
+ .name = "faults:u",
+ .check = test__checkevent_symbolic_alias_modifier,
+ },
+ [18] = {
+ .name = "L1-dcache-load-miss:kp",
+ .check = test__checkevent_genhw_modifier,
+ },
+ [19] = {
+ .name = "mem:0:u",
+ .check = test__checkevent_breakpoint_modifier,
+ },
+ [20] = {
+ .name = "mem:0:x:k",
+ .check = test__checkevent_breakpoint_x_modifier,
+ },
+ [21] = {
+ .name = "mem:0:r:hp",
+ .check = test__checkevent_breakpoint_r_modifier,
+ },
+ [22] = {
+ .name = "mem:0:w:up",
+ .check = test__checkevent_breakpoint_w_modifier,
+ },
+ [23] = {
+ .name = "r1,syscalls:sys_enter_open:k,1:1:hp",
+ .check = test__checkevent_list,
+ },
+ [24] = {
+ .name = "instructions:G",
+ .check = test__checkevent_exclude_host_modifier,
+ },
+ [25] = {
+ .name = "instructions:H",
+ .check = test__checkevent_exclude_guest_modifier,
+ },
+};
+
+#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
+
+static struct test__event_st test__events_pmu[] = {
+ [0] = {
+ .name = "cpu/config=10,config1,config2=3,period=1000/u",
+ .check = test__checkevent_pmu,
+ },
+ [1] = {
+ .name = "cpu/config=1,name=krava/u,cpu/config=2/u",
+ .check = test__checkevent_pmu_name,
+ },
+};
+
+#define TEST__EVENTS_PMU_CNT (sizeof(test__events_pmu) / \
+ sizeof(struct test__event_st))
+
+static int test(struct test__event_st *e)
+{
+ struct perf_evlist *evlist;
+ int ret;
+
+ evlist = perf_evlist__new(NULL, NULL);
+ if (evlist == NULL)
+ return -ENOMEM;
+
+ ret = parse_events(evlist, e->name, 0);
+ if (ret) {
+ pr_debug("failed to parse event '%s', err %d\n",
+ e->name, ret);
+ return ret;
+ }
+
+ ret = e->check(evlist);
+ perf_evlist__delete(evlist);
+
+ return ret;
+}
+
+static int test_events(struct test__event_st *events, unsigned cnt)
+{
+ int ret = 0;
+ unsigned i;
+
+ for (i = 0; i < cnt; i++) {
+ struct test__event_st *e = &events[i];
+
+ pr_debug("running test %d '%s'\n", i, e->name);
+ ret = test(e);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static int test_pmu(void)
+{
+ struct stat st;
+ char path[PATH_MAX];
+ int ret;
+
+ snprintf(path, PATH_MAX, "%s/bus/event_source/devices/cpu/format/",
+ sysfs_find_mountpoint());
+
+ ret = stat(path, &st);
+ if (ret)
+ pr_debug("ommiting PMU cpu tests\n");
+ return !ret;
+}
+
+int parse_events__test(void)
+{
+ int ret;
+
+ ret = test_events(test__events, TEST__EVENTS_CNT);
+ if (!ret && test_pmu())
+ ret = test_events(test__events_pmu, TEST__EVENTS_PMU_CNT);
+
+ return ret;
+}
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 5b3a0ef4e232..fac7d59309b8 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -23,8 +23,10 @@ struct event_symbol {
const char *alias;
};
-int parse_events_parse(struct list_head *list, struct list_head *list_tmp,
- int *idx);
+#ifdef PARSER_DEBUG
+extern int parse_events_debug;
+#endif
+int parse_events_parse(struct list_head *list, int *idx);
#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
@@ -355,20 +357,30 @@ const char *__event_name(int type, u64 config)
return "unknown";
}
-static int add_event(struct list_head *list, int *idx,
+static int add_event(struct list_head **_list, int *idx,
struct perf_event_attr *attr, char *name)
{
struct perf_evsel *evsel;
+ struct list_head *list = *_list;
+
+ if (!list) {
+ list = malloc(sizeof(*list));
+ if (!list)
+ return -ENOMEM;
+ INIT_LIST_HEAD(list);
+ }
event_attr_init(attr);
evsel = perf_evsel__new(attr, (*idx)++);
- if (!evsel)
+ if (!evsel) {
+ free(list);
return -ENOMEM;
-
- list_add_tail(&evsel->node, list);
+ }
evsel->name = strdup(name);
+ list_add_tail(&evsel->node, list);
+ *_list = list;
return 0;
}
@@ -390,7 +402,7 @@ static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size)
return -1;
}
-int parse_events_add_cache(struct list_head *list, int *idx,
+int parse_events_add_cache(struct list_head **list, int *idx,
char *type, char *op_result1, char *op_result2)
{
struct perf_event_attr attr;
@@ -451,7 +463,7 @@ int parse_events_add_cache(struct list_head *list, int *idx,
return add_event(list, idx, &attr, name);
}
-static int add_tracepoint(struct list_head *list, int *idx,
+static int add_tracepoint(struct list_head **list, int *idx,
char *sys_name, char *evt_name)
{
struct perf_event_attr attr;
@@ -488,7 +500,7 @@ static int add_tracepoint(struct list_head *list, int *idx,
return add_event(list, idx, &attr, name);
}
-static int add_tracepoint_multi(struct list_head *list, int *idx,
+static int add_tracepoint_multi(struct list_head **list, int *idx,
char *sys_name, char *evt_name)
{
char evt_path[MAXPATHLEN];
@@ -519,7 +531,7 @@ static int add_tracepoint_multi(struct list_head *list, int *idx,
return ret;
}
-int parse_events_add_tracepoint(struct list_head *list, int *idx,
+int parse_events_add_tracepoint(struct list_head **list, int *idx,
char *sys, char *event)
{
int ret;
@@ -563,7 +575,7 @@ parse_breakpoint_type(const char *type, struct perf_event_attr *attr)
return 0;
}
-int parse_events_add_breakpoint(struct list_head *list, int *idx,
+int parse_events_add_breakpoint(struct list_head **list, int *idx,
void *ptr, char *type)
{
struct perf_event_attr attr;
@@ -593,17 +605,27 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx,
static int config_term(struct perf_event_attr *attr,
struct parse_events__term *term)
{
- switch (term->type) {
+#define CHECK_TYPE_VAL(type) \
+do { \
+ if (PARSE_EVENTS__TERM_TYPE_ ## type != term->type_val) \
+ return -EINVAL; \
+} while (0)
+
+ switch (term->type_term) {
case PARSE_EVENTS__TERM_TYPE_CONFIG:
+ CHECK_TYPE_VAL(NUM);
attr->config = term->val.num;
break;
case PARSE_EVENTS__TERM_TYPE_CONFIG1:
+ CHECK_TYPE_VAL(NUM);
attr->config1 = term->val.num;
break;
case PARSE_EVENTS__TERM_TYPE_CONFIG2:
+ CHECK_TYPE_VAL(NUM);
attr->config2 = term->val.num;
break;
case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
+ CHECK_TYPE_VAL(NUM);
attr->sample_period = term->val.num;
break;
case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
@@ -612,10 +634,15 @@ static int config_term(struct perf_event_attr *attr,
* attr->branch_sample_type = term->val.num;
*/
break;
+ case PARSE_EVENTS__TERM_TYPE_NAME:
+ CHECK_TYPE_VAL(STR);
+ break;
default:
return -EINVAL;
}
+
return 0;
+#undef CHECK_TYPE_VAL
}
static int config_attr(struct perf_event_attr *attr,
@@ -630,7 +657,7 @@ static int config_attr(struct perf_event_attr *attr,
return 0;
}
-int parse_events_add_numeric(struct list_head *list, int *idx,
+int parse_events_add_numeric(struct list_head **list, int *idx,
unsigned long type, unsigned long config,
struct list_head *head_config)
{
@@ -648,7 +675,24 @@ int parse_events_add_numeric(struct list_head *list, int *idx,
(char *) __event_name(type, config));
}
-int parse_events_add_pmu(struct list_head *list, int *idx,
+static int parse_events__is_name_term(struct parse_events__term *term)
+{
+ return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME;
+}
+
+static char *pmu_event_name(struct perf_event_attr *attr,
+ struct list_head *head_terms)
+{
+ struct parse_events__term *term;
+
+ list_for_each_entry(term, head_terms, list)
+ if (parse_events__is_name_term(term))
+ return term->val.str;
+
+ return (char *) __event_name(PERF_TYPE_RAW, attr->config);
+}
+
+int parse_events_add_pmu(struct list_head **list, int *idx,
char *name, struct list_head *head_config)
{
struct perf_event_attr attr;
@@ -669,7 +713,8 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
if (perf_pmu__config(pmu, &attr, head_config))
return -EINVAL;
- return add_event(list, idx, &attr, (char *) "pmu");
+ return add_event(list, idx, &attr,
+ pmu_event_name(&attr, head_config));
}
void parse_events_update_lists(struct list_head *list_event,
@@ -681,7 +726,7 @@ void parse_events_update_lists(struct list_head *list_event,
* list, for next event definition.
*/
list_splice_tail(list_event, list_all);
- INIT_LIST_HEAD(list_event);
+ free(list_event);
}
int parse_events_modifier(struct list_head *list, char *str)
@@ -756,10 +801,14 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
buffer = parse_events__scan_string(str);
- ret = parse_events_parse(&list, &list_tmp, &idx);
+#ifdef PARSER_DEBUG
+ parse_events_debug = 1;
+#endif
+ ret = parse_events_parse(&list, &idx);
parse_events__flush_buffer(buffer);
parse_events__delete_buffer(buffer);
+ parse_events_lex_destroy();
if (!ret) {
int entries = idx - evlist->nr_entries;
@@ -1015,11 +1064,12 @@ void print_events(const char *event_glob)
int parse_events__is_hardcoded_term(struct parse_events__term *term)
{
- return term->type <= PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX;
+ return term->type_term != PARSE_EVENTS__TERM_TYPE_USER;
}
-int parse_events__new_term(struct parse_events__term **_term, int type,
- char *config, char *str, long num)
+static int new_term(struct parse_events__term **_term, int type_val,
+ int type_term, char *config,
+ char *str, long num)
{
struct parse_events__term *term;
@@ -1028,15 +1078,11 @@ int parse_events__new_term(struct parse_events__term **_term, int type,
return -ENOMEM;
INIT_LIST_HEAD(&term->list);
- term->type = type;
+ term->type_val = type_val;
+ term->type_term = type_term;
term->config = config;
- switch (type) {
- case PARSE_EVENTS__TERM_TYPE_CONFIG:
- case PARSE_EVENTS__TERM_TYPE_CONFIG1:
- case PARSE_EVENTS__TERM_TYPE_CONFIG2:
- case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
- case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
+ switch (type_val) {
case PARSE_EVENTS__TERM_TYPE_NUM:
term->val.num = num;
break;
@@ -1051,6 +1097,20 @@ int parse_events__new_term(struct parse_events__term **_term, int type,
return 0;
}
+int parse_events__term_num(struct parse_events__term **term,
+ int type_term, char *config, long num)
+{
+ return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term,
+ config, NULL, num);
+}
+
+int parse_events__term_str(struct parse_events__term **term,
+ int type_term, char *config, char *str)
+{
+ return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term,
+ config, str, 0);
+}
+
void parse_events__free_terms(struct list_head *terms)
{
struct parse_events__term *term, *h;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index ca069f893381..8cac57ab4ee6 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -4,7 +4,11 @@
* Parse symbolic events/counts passed in as options:
*/
+#include <linux/list.h>
+#include <stdbool.h>
+#include "types.h"
#include "../../../include/linux/perf_event.h"
+#include "types.h"
struct list_head;
struct perf_evsel;
@@ -34,16 +38,18 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);
#define EVENTS_HELP_MAX (128*1024)
enum {
+ PARSE_EVENTS__TERM_TYPE_NUM,
+ PARSE_EVENTS__TERM_TYPE_STR,
+};
+
+enum {
+ PARSE_EVENTS__TERM_TYPE_USER,
PARSE_EVENTS__TERM_TYPE_CONFIG,
PARSE_EVENTS__TERM_TYPE_CONFIG1,
PARSE_EVENTS__TERM_TYPE_CONFIG2,
+ PARSE_EVENTS__TERM_TYPE_NAME,
PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD,
PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
- PARSE_EVENTS__TERM_TYPE_NUM,
- PARSE_EVENTS__TERM_TYPE_STR,
-
- PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX =
- PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
};
struct parse_events__term {
@@ -52,35 +58,34 @@ struct parse_events__term {
char *str;
long num;
} val;
- int type;
-
+ int type_val;
+ int type_term;
struct list_head list;
};
int parse_events__is_hardcoded_term(struct parse_events__term *term);
-int parse_events__new_term(struct parse_events__term **term, int type,
- char *config, char *str, long num);
+int parse_events__term_num(struct parse_events__term **_term,
+ int type_term, char *config, long num);
+int parse_events__term_str(struct parse_events__term **_term,
+ int type_term, char *config, char *str);
void parse_events__free_terms(struct list_head *terms);
-int parse_events_modifier(struct list_head *list __used, char *str __used);
-int parse_events_add_tracepoint(struct list_head *list, int *idx,
+int parse_events_modifier(struct list_head *list, char *str);
+int parse_events_add_tracepoint(struct list_head **list, int *idx,
char *sys, char *event);
-int parse_events_add_raw(struct perf_evlist *evlist, unsigned long config,
- unsigned long config1, unsigned long config2,
- char *mod);
-int parse_events_add_numeric(struct list_head *list, int *idx,
+int parse_events_add_numeric(struct list_head **list, int *idx,
unsigned long type, unsigned long config,
struct list_head *head_config);
-int parse_events_add_cache(struct list_head *list, int *idx,
+int parse_events_add_cache(struct list_head **list, int *idx,
char *type, char *op_result1, char *op_result2);
-int parse_events_add_breakpoint(struct list_head *list, int *idx,
+int parse_events_add_breakpoint(struct list_head **list, int *idx,
void *ptr, char *type);
-int parse_events_add_pmu(struct list_head *list, int *idx,
+int parse_events_add_pmu(struct list_head **list, int *idx,
char *pmu , struct list_head *head_config);
void parse_events_update_lists(struct list_head *list_event,
struct list_head *list_all);
void parse_events_error(struct list_head *list_all,
- struct list_head *list_event,
int *idx, char const *msg);
+int parse_events__test(void);
void print_events(const char *event_glob);
void print_events_type(u8 type);
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 1fcf1bbc5458..618a8e788399 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -1,5 +1,6 @@
%option prefix="parse_events_"
+%option stack
%{
#include <errno.h>
@@ -50,6 +51,8 @@ static int term(int type)
%}
+%x mem
+
num_dec [0-9]+
num_hex 0x[a-fA-F0-9]+
num_raw_hex [a-fA-F0-9]+
@@ -102,16 +105,16 @@ misses|miss { return str(PE_NAME_CACHE_OP_RESULT); }
config { return term(PARSE_EVENTS__TERM_TYPE_CONFIG); }
config1 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); }
config2 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); }
+name { return term(PARSE_EVENTS__TERM_TYPE_NAME); }
period { return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
branch_type { return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
-mem: { return PE_PREFIX_MEM; }
+mem: { BEGIN(mem); return PE_PREFIX_MEM; }
r{num_raw_hex} { return raw(); }
{num_dec} { return value(10); }
{num_hex} { return value(16); }
{modifier_event} { return str(PE_MODIFIER_EVENT); }
-{modifier_bp} { return str(PE_MODIFIER_BP); }
{name} { return str(PE_NAME); }
"/" { return '/'; }
- { return '-'; }
@@ -119,6 +122,25 @@ r{num_raw_hex} { return raw(); }
: { return ':'; }
= { return '='; }
+<mem>{
+{modifier_bp} { return str(PE_MODIFIER_BP); }
+: { return ':'; }
+{num_dec} { return value(10); }
+{num_hex} { return value(16); }
+ /*
+ * We need to separate 'mem:' scanner part, in order to get specific
+ * modifier bits parsed out. Otherwise we would need to handle PE_NAME
+ * and we'd need to parse it manually. During the escape from <mem>
+ * state we need to put the escaping char back, so we dont miss it.
+ */
+. { unput(*parse_events_text); BEGIN(INITIAL); }
+ /*
+ * We destroy the scanner after reaching EOF,
+ * but anyway just to be sure get back to INIT state.
+ */
+<<EOF>> { BEGIN(INITIAL); }
+}
+
%%
int parse_events_wrap(void)
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index d9637da7333c..362cc59332ae 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -1,7 +1,6 @@
%name-prefix "parse_events_"
%parse-param {struct list_head *list_all}
-%parse-param {struct list_head *list_event}
%parse-param {int *idx}
%{
@@ -41,6 +40,14 @@ do { \
%type <str> PE_MODIFIER_BP
%type <head> event_config
%type <term> event_term
+%type <head> event_pmu
+%type <head> event_legacy_symbol
+%type <head> event_legacy_cache
+%type <head> event_legacy_mem
+%type <head> event_legacy_tracepoint
+%type <head> event_legacy_numeric
+%type <head> event_legacy_raw
+%type <head> event_def
%union
{
@@ -62,13 +69,13 @@ event_def PE_MODIFIER_EVENT
* (there could be more events added for multiple tracepoint
* definitions via '*?'.
*/
- ABORT_ON(parse_events_modifier(list_event, $2));
- parse_events_update_lists(list_event, list_all);
+ ABORT_ON(parse_events_modifier($1, $2));
+ parse_events_update_lists($1, list_all);
}
|
event_def
{
- parse_events_update_lists(list_event, list_all);
+ parse_events_update_lists($1, list_all);
}
event_def: event_pmu |
@@ -82,71 +89,102 @@ event_def: event_pmu |
event_pmu:
PE_NAME '/' event_config '/'
{
- ABORT_ON(parse_events_add_pmu(list_event, idx, $1, $3));
+ struct list_head *list = NULL;
+
+ ABORT_ON(parse_events_add_pmu(&list, idx, $1, $3));
parse_events__free_terms($3);
+ $$ = list;
}
event_legacy_symbol:
PE_VALUE_SYM '/' event_config '/'
{
+ struct list_head *list = NULL;
int type = $1 >> 16;
int config = $1 & 255;
- ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, $3));
+ ABORT_ON(parse_events_add_numeric(&list, idx, type, config, $3));
parse_events__free_terms($3);
+ $$ = list;
}
|
PE_VALUE_SYM sep_slash_dc
{
+ struct list_head *list = NULL;
int type = $1 >> 16;
int config = $1 & 255;
- ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, NULL));
+ ABORT_ON(parse_events_add_numeric(&list, idx, type, config, NULL));
+ $$ = list;
}
event_legacy_cache:
PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
{
- ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, $5));
+ struct list_head *list = NULL;
+
+ ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, $5));
+ $$ = list;
}
|
PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
{
- ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, NULL));
+ struct list_head *list = NULL;
+
+ ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, NULL));
+ $$ = list;
}
|
PE_NAME_CACHE_TYPE
{
- ABORT_ON(parse_events_add_cache(list_event, idx, $1, NULL, NULL));
+ struct list_head *list = NULL;
+
+ ABORT_ON(parse_events_add_cache(&list, idx, $1, NULL, NULL));
+ $$ = list;
}
event_legacy_mem:
PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
{
- ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, $4));
+ struct list_head *list = NULL;
+
+ ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, $4));
+ $$ = list;
}
|
PE_PREFIX_MEM PE_VALUE sep_dc
{
- ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, NULL));
+ struct list_head *list = NULL;
+
+ ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, NULL));
+ $$ = list;
}
event_legacy_tracepoint:
PE_NAME ':' PE_NAME
{
- ABORT_ON(parse_events_add_tracepoint(list_event, idx, $1, $3));
+ struct list_head *list = NULL;
+
+ ABORT_ON(parse_events_add_tracepoint(&list, idx, $1, $3));
+ $$ = list;
}
event_legacy_numeric:
PE_VALUE ':' PE_VALUE
{
- ABORT_ON(parse_events_add_numeric(list_event, idx, $1, $3, NULL));
+ struct list_head *list = NULL;
+
+ ABORT_ON(parse_events_add_numeric(&list, idx, $1, $3, NULL));
+ $$ = list;
}
event_legacy_raw:
PE_RAW
{
- ABORT_ON(parse_events_add_numeric(list_event, idx, PERF_TYPE_RAW, $1, NULL));
+ struct list_head *list = NULL;
+
+ ABORT_ON(parse_events_add_numeric(&list, idx, PERF_TYPE_RAW, $1, NULL));
+ $$ = list;
}
event_config:
@@ -176,8 +214,8 @@ PE_NAME '=' PE_NAME
{
struct parse_events__term *term;
- ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_STR,
- $1, $3, 0));
+ ABORT_ON(parse_events__term_str(&term, PARSE_EVENTS__TERM_TYPE_USER,
+ $1, $3));
$$ = term;
}
|
@@ -185,8 +223,8 @@ PE_NAME '=' PE_VALUE
{
struct parse_events__term *term;
- ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM,
- $1, NULL, $3));
+ ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER,
+ $1, $3));
$$ = term;
}
|
@@ -194,8 +232,16 @@ PE_NAME
{
struct parse_events__term *term;
- ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM,
- $1, NULL, 1));
+ ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER,
+ $1, 1));
+ $$ = term;
+}
+|
+PE_TERM '=' PE_NAME
+{
+ struct parse_events__term *term;
+
+ ABORT_ON(parse_events__term_str(&term, $1, NULL, $3));
$$ = term;
}
|
@@ -203,7 +249,7 @@ PE_TERM '=' PE_VALUE
{
struct parse_events__term *term;
- ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, $3));
+ ABORT_ON(parse_events__term_num(&term, $1, NULL, $3));
$$ = term;
}
|
@@ -211,7 +257,7 @@ PE_TERM
{
struct parse_events__term *term;
- ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, 1));
+ ABORT_ON(parse_events__term_num(&term, $1, NULL, 1));
$$ = term;
}
@@ -222,7 +268,6 @@ sep_slash_dc: '/' | ':' |
%%
void parse_events_error(struct list_head *list_all __used,
- struct list_head *list_event __used,
int *idx __used,
char const *msg __used)
{
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index cb08a118e811..a119a5371699 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -225,7 +225,7 @@ static int pmu_config_term(struct list_head *formats,
if (parse_events__is_hardcoded_term(term))
return 0;
- if (term->type != PARSE_EVENTS__TERM_TYPE_NUM)
+ if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM)
return -EINVAL;
format = pmu_find_format(formats, term->config);
@@ -246,6 +246,11 @@ static int pmu_config_term(struct list_head *formats,
return -EINVAL;
}
+ /*
+ * XXX If we ever decide to go with string values for
+ * non-hardcoded terms, here's the place to translate
+ * them into value.
+ */
*vp |= pmu_format_value(format->bits, term->val.num);
return 0;
}
@@ -253,9 +258,9 @@ static int pmu_config_term(struct list_head *formats,
static int pmu_config(struct list_head *formats, struct perf_event_attr *attr,
struct list_head *head_terms)
{
- struct parse_events__term *term, *h;
+ struct parse_events__term *term;
- list_for_each_entry_safe(term, h, head_terms, list)
+ list_for_each_entry(term, head_terms, list)
if (pmu_config_term(formats, attr, term))
return -EINVAL;
@@ -324,49 +329,58 @@ static struct test_format {
/* Simulated users input. */
static struct parse_events__term test_terms[] = {
{
- .config = (char *) "krava01",
- .val.num = 15,
- .type = PARSE_EVENTS__TERM_TYPE_NUM,
+ .config = (char *) "krava01",
+ .val.num = 15,
+ .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
+ .type_term = PARSE_EVENTS__TERM_TYPE_USER,
},
{
- .config = (char *) "krava02",
- .val.num = 170,
- .type = PARSE_EVENTS__TERM_TYPE_NUM,
+ .config = (char *) "krava02",
+ .val.num = 170,
+ .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
+ .type_term = PARSE_EVENTS__TERM_TYPE_USER,
},
{
- .config = (char *) "krava03",
- .val.num = 1,
- .type = PARSE_EVENTS__TERM_TYPE_NUM,
+ .config = (char *) "krava03",
+ .val.num = 1,
+ .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
+ .type_term = PARSE_EVENTS__TERM_TYPE_USER,
},
{
- .config = (char *) "krava11",
- .val.num = 27,
- .type = PARSE_EVENTS__TERM_TYPE_NUM,
+ .config = (char *) "krava11",
+ .val.num = 27,
+ .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
+ .type_term = PARSE_EVENTS__TERM_TYPE_USER,
},
{
- .config = (char *) "krava12",
- .val.num = 1,
- .type = PARSE_EVENTS__TERM_TYPE_NUM,
+ .config = (char *) "krava12",
+ .val.num = 1,
+ .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
+ .type_term = PARSE_EVENTS__TERM_TYPE_USER,
},
{
- .config = (char *) "krava13",
- .val.num = 2,
- .type = PARSE_EVENTS__TERM_TYPE_NUM,
+ .config = (char *) "krava13",
+ .val.num = 2,
+ .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
+ .type_term = PARSE_EVENTS__TERM_TYPE_USER,
},
{
- .config = (char *) "krava21",
- .val.num = 119,
- .type = PARSE_EVENTS__TERM_TYPE_NUM,
+ .config = (char *) "krava21",
+ .val.num = 119,
+ .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
+ .type_term = PARSE_EVENTS__TERM_TYPE_USER,
},
{
- .config = (char *) "krava22",
- .val.num = 11,
- .type = PARSE_EVENTS__TERM_TYPE_NUM,
+ .config = (char *) "krava22",
+ .val.num = 11,
+ .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
+ .type_term = PARSE_EVENTS__TERM_TYPE_USER,
},
{
- .config = (char *) "krava23",
- .val.num = 2,
- .type = PARSE_EVENTS__TERM_TYPE_NUM,
+ .config = (char *) "krava23",
+ .val.num = 2,
+ .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
+ .type_term = PARSE_EVENTS__TERM_TYPE_USER,
},
};
#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 8a8ee64e72d1..59dccc98b554 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -44,6 +44,7 @@
#include "trace-event.h" /* For __unused */
#include "probe-event.h"
#include "probe-finder.h"
+#include "session.h"
#define MAX_CMDLEN 256
#define MAX_PROBE_ARGS 128
@@ -70,6 +71,8 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
}
static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
+static int convert_name_to_addr(struct perf_probe_event *pev,
+ const char *exec);
static struct machine machine;
/* Initialize symbol maps and path of vmlinux/modules */
@@ -170,6 +173,34 @@ const char *kernel_get_module_path(const char *module)
return (dso) ? dso->long_name : NULL;
}
+static int init_user_exec(void)
+{
+ int ret = 0;
+
+ symbol_conf.try_vmlinux_path = false;
+ symbol_conf.sort_by_name = true;
+ ret = symbol__init();
+
+ if (ret < 0)
+ pr_debug("Failed to init symbol map.\n");
+
+ return ret;
+}
+
+static int convert_to_perf_probe_point(struct probe_trace_point *tp,
+ struct perf_probe_point *pp)
+{
+ pp->function = strdup(tp->symbol);
+
+ if (pp->function == NULL)
+ return -ENOMEM;
+
+ pp->offset = tp->offset;
+ pp->retprobe = tp->retprobe;
+
+ return 0;
+}
+
#ifdef DWARF_SUPPORT
/* Open new debuginfo of given module */
static struct debuginfo *open_debuginfo(const char *module)
@@ -224,10 +255,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
if (ret <= 0) {
pr_debug("Failed to find corresponding probes from "
"debuginfo. Use kprobe event information.\n");
- pp->function = strdup(tp->symbol);
- if (pp->function == NULL)
- return -ENOMEM;
- pp->offset = tp->offset;
+ return convert_to_perf_probe_point(tp, pp);
}
pp->retprobe = tp->retprobe;
@@ -275,9 +303,20 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
int max_tevs, const char *target)
{
bool need_dwarf = perf_probe_event_need_dwarf(pev);
- struct debuginfo *dinfo = open_debuginfo(target);
+ struct debuginfo *dinfo;
int ntevs, ret = 0;
+ if (pev->uprobes) {
+ if (need_dwarf) {
+ pr_warning("Debuginfo-analysis is not yet supported"
+ " with -x/--exec option.\n");
+ return -ENOSYS;
+ }
+ return convert_name_to_addr(pev, target);
+ }
+
+ dinfo = open_debuginfo(target);
+
if (!dinfo) {
if (need_dwarf) {
pr_warning("Failed to open debuginfo file.\n");
@@ -603,23 +642,22 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
return -ENOENT;
}
- pp->function = strdup(tp->symbol);
- if (pp->function == NULL)
- return -ENOMEM;
- pp->offset = tp->offset;
- pp->retprobe = tp->retprobe;
- return 0;
+ return convert_to_perf_probe_point(tp, pp);
}
static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
struct probe_trace_event **tevs __unused,
- int max_tevs __unused, const char *mod __unused)
+ int max_tevs __unused, const char *target)
{
if (perf_probe_event_need_dwarf(pev)) {
pr_warning("Debuginfo-analysis is not supported.\n");
return -ENOSYS;
}
+
+ if (pev->uprobes)
+ return convert_name_to_addr(pev, target);
+
return 0;
}
@@ -1341,11 +1379,18 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
if (buf == NULL)
return NULL;
- len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
- tp->retprobe ? 'r' : 'p',
- tev->group, tev->event,
- tp->module ?: "", tp->module ? ":" : "",
- tp->symbol, tp->offset);
+ if (tev->uprobes)
+ len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s",
+ tp->retprobe ? 'r' : 'p',
+ tev->group, tev->event,
+ tp->module, tp->symbol);
+ else
+ len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
+ tp->retprobe ? 'r' : 'p',
+ tev->group, tev->event,
+ tp->module ?: "", tp->module ? ":" : "",
+ tp->symbol, tp->offset);
+
if (len <= 0)
goto error;
@@ -1364,7 +1409,7 @@ error:
}
static int convert_to_perf_probe_event(struct probe_trace_event *tev,
- struct perf_probe_event *pev)
+ struct perf_probe_event *pev, bool is_kprobe)
{
char buf[64] = "";
int i, ret;
@@ -1376,7 +1421,11 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,
return -ENOMEM;
/* Convert trace_point to probe_point */
- ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
+ if (is_kprobe)
+ ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
+ else
+ ret = convert_to_perf_probe_point(&tev->point, &pev->point);
+
if (ret < 0)
return ret;
@@ -1472,7 +1521,26 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
memset(tev, 0, sizeof(*tev));
}
-static int open_kprobe_events(bool readwrite)
+static void print_warn_msg(const char *file, bool is_kprobe)
+{
+
+ if (errno == ENOENT) {
+ const char *config;
+
+ if (!is_kprobe)
+ config = "CONFIG_UPROBE_EVENTS";
+ else
+ config = "CONFIG_KPROBE_EVENTS";
+
+ pr_warning("%s file does not exist - please rebuild kernel"
+ " with %s.\n", file, config);
+ } else
+ pr_warning("Failed to open %s file: %s\n", file,
+ strerror(errno));
+}
+
+static int open_probe_events(const char *trace_file, bool readwrite,
+ bool is_kprobe)
{
char buf[PATH_MAX];
const char *__debugfs;
@@ -1484,27 +1552,31 @@ static int open_kprobe_events(bool readwrite)
return -ENOENT;
}
- ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs);
+ ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file);
if (ret >= 0) {
pr_debug("Opening %s write=%d\n", buf, readwrite);
if (readwrite && !probe_event_dry_run)
ret = open(buf, O_RDWR, O_APPEND);
else
ret = open(buf, O_RDONLY, 0);
- }
- if (ret < 0) {
- if (errno == ENOENT)
- pr_warning("kprobe_events file does not exist - please"
- " rebuild kernel with CONFIG_KPROBE_EVENT.\n");
- else
- pr_warning("Failed to open kprobe_events file: %s\n",
- strerror(errno));
+ if (ret < 0)
+ print_warn_msg(buf, is_kprobe);
}
return ret;
}
-/* Get raw string list of current kprobe_events */
+static int open_kprobe_events(bool readwrite)
+{
+ return open_probe_events("tracing/kprobe_events", readwrite, true);
+}
+
+static int open_uprobe_events(bool readwrite)
+{
+ return open_probe_events("tracing/uprobe_events", readwrite, false);
+}
+
+/* Get raw string list of current kprobe_events or uprobe_events */
static struct strlist *get_probe_trace_command_rawlist(int fd)
{
int ret, idx;
@@ -1569,36 +1641,26 @@ static int show_perf_probe_event(struct perf_probe_event *pev)
return ret;
}
-/* List up current perf-probe events */
-int show_perf_probe_events(void)
+static int __show_perf_probe_events(int fd, bool is_kprobe)
{
- int fd, ret;
+ int ret = 0;
struct probe_trace_event tev;
struct perf_probe_event pev;
struct strlist *rawlist;
struct str_node *ent;
- setup_pager();
- ret = init_vmlinux();
- if (ret < 0)
- return ret;
-
memset(&tev, 0, sizeof(tev));
memset(&pev, 0, sizeof(pev));
- fd = open_kprobe_events(false);
- if (fd < 0)
- return fd;
-
rawlist = get_probe_trace_command_rawlist(fd);
- close(fd);
if (!rawlist)
return -ENOENT;
strlist__for_each(ent, rawlist) {
ret = parse_probe_trace_command(ent->s, &tev);
if (ret >= 0) {
- ret = convert_to_perf_probe_event(&tev, &pev);
+ ret = convert_to_perf_probe_event(&tev, &pev,
+ is_kprobe);
if (ret >= 0)
ret = show_perf_probe_event(&pev);
}
@@ -1612,6 +1674,33 @@ int show_perf_probe_events(void)
return ret;
}
+/* List up current perf-probe events */
+int show_perf_probe_events(void)
+{
+ int fd, ret;
+
+ setup_pager();
+ fd = open_kprobe_events(false);
+
+ if (fd < 0)
+ return fd;
+
+ ret = init_vmlinux();
+ if (ret < 0)
+ return ret;
+
+ ret = __show_perf_probe_events(fd, true);
+ close(fd);
+
+ fd = open_uprobe_events(false);
+ if (fd >= 0) {
+ ret = __show_perf_probe_events(fd, false);
+ close(fd);
+ }
+
+ return ret;
+}
+
/* Get current perf-probe event names */
static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
{
@@ -1717,7 +1806,11 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
const char *event, *group;
struct strlist *namelist;
- fd = open_kprobe_events(true);
+ if (pev->uprobes)
+ fd = open_uprobe_events(true);
+ else
+ fd = open_kprobe_events(true);
+
if (fd < 0)
return fd;
/* Get current event names */
@@ -1829,6 +1922,8 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
tev->point.offset = pev->point.offset;
tev->point.retprobe = pev->point.retprobe;
tev->nargs = pev->nargs;
+ tev->uprobes = pev->uprobes;
+
if (tev->nargs) {
tev->args = zalloc(sizeof(struct probe_trace_arg)
* tev->nargs);
@@ -1859,6 +1954,9 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
}
}
+ if (pev->uprobes)
+ return 1;
+
/* Currently just checking function name from symbol map */
sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
if (!sym) {
@@ -1894,12 +1992,18 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
int i, j, ret;
struct __event_package *pkgs;
+ ret = 0;
pkgs = zalloc(sizeof(struct __event_package) * npevs);
+
if (pkgs == NULL)
return -ENOMEM;
- /* Init vmlinux path */
- ret = init_vmlinux();
+ if (!pevs->uprobes)
+ /* Init vmlinux path */
+ ret = init_vmlinux();
+ else
+ ret = init_user_exec();
+
if (ret < 0) {
free(pkgs);
return ret;
@@ -1971,23 +2075,15 @@ error:
return ret;
}
-static int del_trace_probe_event(int fd, const char *group,
- const char *event, struct strlist *namelist)
+static int del_trace_probe_event(int fd, const char *buf,
+ struct strlist *namelist)
{
- char buf[128];
struct str_node *ent, *n;
- int found = 0, ret = 0;
-
- ret = e_snprintf(buf, 128, "%s:%s", group, event);
- if (ret < 0) {
- pr_err("Failed to copy event.\n");
- return ret;
- }
+ int ret = -1;
if (strpbrk(buf, "*?")) { /* Glob-exp */
strlist__for_each_safe(ent, n, namelist)
if (strglobmatch(ent->s, buf)) {
- found++;
ret = __del_trace_probe_event(fd, ent);
if (ret < 0)
break;
@@ -1996,40 +2092,43 @@ static int del_trace_probe_event(int fd, const char *group,
} else {
ent = strlist__find(namelist, buf);
if (ent) {
- found++;
ret = __del_trace_probe_event(fd, ent);
if (ret >= 0)
strlist__remove(namelist, ent);
}
}
- if (found == 0 && ret >= 0)
- pr_info("Info: Event \"%s\" does not exist.\n", buf);
return ret;
}
int del_perf_probe_events(struct strlist *dellist)
{
- int fd, ret = 0;
+ int ret = -1, ufd = -1, kfd = -1;
+ char buf[128];
const char *group, *event;
char *p, *str;
struct str_node *ent;
- struct strlist *namelist;
-
- fd = open_kprobe_events(true);
- if (fd < 0)
- return fd;
+ struct strlist *namelist = NULL, *unamelist = NULL;
/* Get current event names */
- namelist = get_probe_trace_event_names(fd, true);
- if (namelist == NULL)
- return -EINVAL;
+ kfd = open_kprobe_events(true);
+ if (kfd < 0)
+ return kfd;
+
+ namelist = get_probe_trace_event_names(kfd, true);
+ ufd = open_uprobe_events(true);
+
+ if (ufd >= 0)
+ unamelist = get_probe_trace_event_names(ufd, true);
+
+ if (namelist == NULL && unamelist == NULL)
+ goto error;
strlist__for_each(ent, dellist) {
str = strdup(ent->s);
if (str == NULL) {
ret = -ENOMEM;
- break;
+ goto error;
}
pr_debug("Parsing: %s\n", str);
p = strchr(str, ':');
@@ -2041,17 +2140,46 @@ int del_perf_probe_events(struct strlist *dellist)
group = "*";
event = str;
}
+
+ ret = e_snprintf(buf, 128, "%s:%s", group, event);
+ if (ret < 0) {
+ pr_err("Failed to copy event.");
+ free(str);
+ goto error;
+ }
+
pr_debug("Group: %s, Event: %s\n", group, event);
- ret = del_trace_probe_event(fd, group, event, namelist);
+
+ if (namelist)
+ ret = del_trace_probe_event(kfd, buf, namelist);
+
+ if (unamelist && ret != 0)
+ ret = del_trace_probe_event(ufd, buf, unamelist);
+
+ if (ret != 0)
+ pr_info("Info: Event \"%s\" does not exist.\n", buf);
+
free(str);
- if (ret < 0)
- break;
}
- strlist__delete(namelist);
- close(fd);
+
+error:
+ if (kfd >= 0) {
+ if (namelist)
+ strlist__delete(namelist);
+
+ close(kfd);
+ }
+
+ if (ufd >= 0) {
+ if (unamelist)
+ strlist__delete(unamelist);
+
+ close(ufd);
+ }
return ret;
}
+
/* TODO: don't use a global variable for filter ... */
static struct strfilter *available_func_filter;
@@ -2068,30 +2196,152 @@ static int filter_available_functions(struct map *map __unused,
return 1;
}
-int show_available_funcs(const char *target, struct strfilter *_filter)
+static int __show_available_funcs(struct map *map)
+{
+ if (map__load(map, filter_available_functions)) {
+ pr_err("Failed to load map.\n");
+ return -EINVAL;
+ }
+ if (!dso__sorted_by_name(map->dso, map->type))
+ dso__sort_by_name(map->dso, map->type);
+
+ dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
+ return 0;
+}
+
+static int available_kernel_funcs(const char *module)
{
struct map *map;
int ret;
- setup_pager();
-
ret = init_vmlinux();
if (ret < 0)
return ret;
- map = kernel_get_module_map(target);
+ map = kernel_get_module_map(module);
if (!map) {
- pr_err("Failed to find %s map.\n", (target) ? : "kernel");
+ pr_err("Failed to find %s map.\n", (module) ? : "kernel");
return -EINVAL;
}
+ return __show_available_funcs(map);
+}
+
+static int available_user_funcs(const char *target)
+{
+ struct map *map;
+ int ret;
+
+ ret = init_user_exec();
+ if (ret < 0)
+ return ret;
+
+ map = dso__new_map(target);
+ ret = __show_available_funcs(map);
+ dso__delete(map->dso);
+ map__delete(map);
+ return ret;
+}
+
+int show_available_funcs(const char *target, struct strfilter *_filter,
+ bool user)
+{
+ setup_pager();
available_func_filter = _filter;
+
+ if (!user)
+ return available_kernel_funcs(target);
+
+ return available_user_funcs(target);
+}
+
+/*
+ * uprobe_events only accepts address:
+ * Convert function and any offset to address
+ */
+static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
+{
+ struct perf_probe_point *pp = &pev->point;
+ struct symbol *sym;
+ struct map *map = NULL;
+ char *function = NULL, *name = NULL;
+ int ret = -EINVAL;
+ unsigned long long vaddr = 0;
+
+ if (!pp->function) {
+ pr_warning("No function specified for uprobes");
+ goto out;
+ }
+
+ function = strdup(pp->function);
+ if (!function) {
+ pr_warning("Failed to allocate memory by strdup.\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ name = realpath(exec, NULL);
+ if (!name) {
+ pr_warning("Cannot find realpath for %s.\n", exec);
+ goto out;
+ }
+ map = dso__new_map(name);
+ if (!map) {
+ pr_warning("Cannot find appropriate DSO for %s.\n", exec);
+ goto out;
+ }
+ available_func_filter = strfilter__new(function, NULL);
if (map__load(map, filter_available_functions)) {
pr_err("Failed to load map.\n");
- return -EINVAL;
+ goto out;
}
- if (!dso__sorted_by_name(map->dso, map->type))
- dso__sort_by_name(map->dso, map->type);
- dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
- return 0;
+ sym = map__find_symbol_by_name(map, function, NULL);
+ if (!sym) {
+ pr_warning("Cannot find %s in DSO %s\n", function, exec);
+ goto out;
+ }
+
+ if (map->start > sym->start)
+ vaddr = map->start;
+ vaddr += sym->start + pp->offset + map->pgoff;
+ pp->offset = 0;
+
+ if (!pev->event) {
+ pev->event = function;
+ function = NULL;
+ }
+ if (!pev->group) {
+ char *ptr1, *ptr2;
+
+ pev->group = zalloc(sizeof(char *) * 64);
+ ptr1 = strdup(basename(exec));
+ if (ptr1) {
+ ptr2 = strpbrk(ptr1, "-._");
+ if (ptr2)
+ *ptr2 = '\0';
+ e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP,
+ ptr1);
+ free(ptr1);
+ }
+ }
+ free(pp->function);
+ pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS);
+ if (!pp->function) {
+ ret = -ENOMEM;
+ pr_warning("Failed to allocate memory by zalloc.\n");
+ goto out;
+ }
+ e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr);
+ ret = 0;
+
+out:
+ if (map) {
+ dso__delete(map->dso);
+ map__delete(map);
+ }
+ if (function)
+ free(function);
+ if (name)
+ free(name);
+ return ret;
}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index a7dee835f49c..f9f3de8b4220 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -7,7 +7,7 @@
extern bool probe_event_dry_run;
-/* kprobe-tracer tracing point */
+/* kprobe-tracer and uprobe-tracer tracing point */
struct probe_trace_point {
char *symbol; /* Base symbol */
char *module; /* Module name */
@@ -21,7 +21,7 @@ struct probe_trace_arg_ref {
long offset; /* Offset value */
};
-/* kprobe-tracer tracing argument */
+/* kprobe-tracer and uprobe-tracer tracing argument */
struct probe_trace_arg {
char *name; /* Argument name */
char *value; /* Base value */
@@ -29,12 +29,13 @@ struct probe_trace_arg {
struct probe_trace_arg_ref *ref; /* Referencing offset */
};
-/* kprobe-tracer tracing event (point + arg) */
+/* kprobe-tracer and uprobe-tracer tracing event (point + arg) */
struct probe_trace_event {
char *event; /* Event name */
char *group; /* Group name */
struct probe_trace_point point; /* Trace point */
int nargs; /* Number of args */
+ bool uprobes; /* uprobes only */
struct probe_trace_arg *args; /* Arguments */
};
@@ -70,6 +71,7 @@ struct perf_probe_event {
char *group; /* Group name */
struct perf_probe_point point; /* Probe point */
int nargs; /* Number of arguments */
+ bool uprobes;
struct perf_probe_arg *args; /* Arguments */
};
@@ -129,8 +131,8 @@ extern int show_line_range(struct line_range *lr, const char *module);
extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
int max_probe_points, const char *module,
struct strfilter *filter, bool externs);
-extern int show_available_funcs(const char *module, struct strfilter *filter);
-
+extern int show_available_funcs(const char *module, struct strfilter *filter,
+ bool user);
/* Maximum index number of event-name postfix */
#define MAX_EVENT_INDEX 1024
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index e30749e38a9b..4c1b3d72a1d2 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -56,7 +56,7 @@ INTERP my_perl;
#define FTRACE_MAX_EVENT \
((1 << (sizeof(unsigned short) * 8)) - 1)
-struct event *events[FTRACE_MAX_EVENT];
+struct event_format *events[FTRACE_MAX_EVENT];
extern struct scripting_context *scripting_context;
@@ -181,7 +181,7 @@ static void define_flag_field(const char *ev_name,
LEAVE;
}
-static void define_event_symbols(struct event *event,
+static void define_event_symbols(struct event_format *event,
const char *ev_name,
struct print_arg *args)
{
@@ -209,6 +209,8 @@ static void define_event_symbols(struct event *event,
define_symbolic_values(args->symbol.symbols, ev_name,
cur_field_name);
break;
+ case PRINT_BSTRING:
+ case PRINT_DYNAMIC_ARRAY:
case PRINT_STRING:
break;
case PRINT_TYPE:
@@ -220,7 +222,9 @@ static void define_event_symbols(struct event *event,
define_event_symbols(event, ev_name, args->op.left);
define_event_symbols(event, ev_name, args->op.right);
break;
+ case PRINT_FUNC:
default:
+ pr_err("Unsupported print arg type\n");
/* we should warn... */
return;
}
@@ -229,10 +233,10 @@ static void define_event_symbols(struct event *event,
define_event_symbols(event, ev_name, args->next);
}
-static inline struct event *find_cache_event(int type)
+static inline struct event_format *find_cache_event(int type)
{
static char ev_name[256];
- struct event *event;
+ struct event_format *event;
if (events[type])
return events[type];
@@ -258,7 +262,7 @@ static void perl_process_tracepoint(union perf_event *pevent __unused,
static char handler[256];
unsigned long long val;
unsigned long s, ns;
- struct event *event;
+ struct event_format *event;
int type;
int pid;
int cpu = sample->cpu;
@@ -446,7 +450,7 @@ static int perl_stop_script(void)
static int perl_generate_script(const char *outfile)
{
- struct event *event = NULL;
+ struct event_format *event = NULL;
struct format_field *f;
char fname[PATH_MAX];
int not_first, count;
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index c2623c6f9b51..acb9795286c4 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -37,7 +37,7 @@ PyMODINIT_FUNC initperf_trace_context(void);
#define FTRACE_MAX_EVENT \
((1 << (sizeof(unsigned short) * 8)) - 1)
-struct event *events[FTRACE_MAX_EVENT];
+struct event_format *events[FTRACE_MAX_EVENT];
#define MAX_FIELDS 64
#define N_COMMON_FIELDS 7
@@ -136,7 +136,7 @@ static void define_field(enum print_arg_type field_type,
Py_DECREF(t);
}
-static void define_event_symbols(struct event *event,
+static void define_event_symbols(struct event_format *event,
const char *ev_name,
struct print_arg *args)
{
@@ -178,6 +178,10 @@ static void define_event_symbols(struct event *event,
define_event_symbols(event, ev_name, args->op.right);
break;
default:
+ /* gcc warns for these? */
+ case PRINT_BSTRING:
+ case PRINT_DYNAMIC_ARRAY:
+ case PRINT_FUNC:
/* we should warn... */
return;
}
@@ -186,10 +190,10 @@ static void define_event_symbols(struct event *event,
define_event_symbols(event, ev_name, args->next);
}
-static inline struct event *find_cache_event(int type)
+static inline struct event_format *find_cache_event(int type)
{
static char ev_name[256];
- struct event *event;
+ struct event_format *event;
if (events[type])
return events[type];
@@ -216,7 +220,7 @@ static void python_process_event(union perf_event *pevent __unused,
struct format_field *field;
unsigned long long val;
unsigned long s, ns;
- struct event *event;
+ struct event_format *event;
unsigned n = 0;
int type;
int pid;
@@ -436,7 +440,7 @@ out:
static int python_generate_script(const char *outfile)
{
- struct event *event = NULL;
+ struct event_format *event = NULL;
struct format_field *f;
char fname[PATH_MAX];
int not_first, count;
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 1efd3bee6336..93d355d27109 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -481,6 +481,38 @@ static void perf_event__read_swap(union perf_event *event)
event->read.id = bswap_64(event->read.id);
}
+static u8 revbyte(u8 b)
+{
+ int rev = (b >> 4) | ((b & 0xf) << 4);
+ rev = ((rev & 0xcc) >> 2) | ((rev & 0x33) << 2);
+ rev = ((rev & 0xaa) >> 1) | ((rev & 0x55) << 1);
+ return (u8) rev;
+}
+
+/*
+ * XXX this is hack in attempt to carry flags bitfield
+ * throught endian village. ABI says:
+ *
+ * Bit-fields are allocated from right to left (least to most significant)
+ * on little-endian implementations and from left to right (most to least
+ * significant) on big-endian implementations.
+ *
+ * The above seems to be byte specific, so we need to reverse each
+ * byte of the bitfield. 'Internet' also says this might be implementation
+ * specific and we probably need proper fix and carry perf_event_attr
+ * bitfield flags in separate data file FEAT_ section. Thought this seems
+ * to work for now.
+ */
+static void swap_bitfield(u8 *p, unsigned len)
+{
+ unsigned i;
+
+ for (i = 0; i < len; i++) {
+ *p = revbyte(*p);
+ p++;
+ }
+}
+
/* exported for swapping attributes in file header */
void perf_event__attr_swap(struct perf_event_attr *attr)
{
@@ -494,6 +526,8 @@ void perf_event__attr_swap(struct perf_event_attr *attr)
attr->bp_type = bswap_32(attr->bp_type);
attr->bp_addr = bswap_64(attr->bp_addr);
attr->bp_len = bswap_64(attr->bp_len);
+
+ swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64));
}
static void perf_event__hdr_attr_swap(union perf_event *event)
@@ -1064,8 +1098,9 @@ volatile int session_done;
static int __perf_session__process_pipe_events(struct perf_session *self,
struct perf_tool *tool)
{
- union perf_event event;
- uint32_t size;
+ union perf_event *event;
+ uint32_t size, cur_size = 0;
+ void *buf = NULL;
int skip = 0;
u64 head;
int err;
@@ -1074,8 +1109,14 @@ static int __perf_session__process_pipe_events(struct perf_session *self,
perf_tool__fill_defaults(tool);
head = 0;
+ cur_size = sizeof(union perf_event);
+
+ buf = malloc(cur_size);
+ if (!buf)
+ return -errno;
more:
- err = readn(self->fd, &event, sizeof(struct perf_event_header));
+ event = buf;
+ err = readn(self->fd, event, sizeof(struct perf_event_header));
if (err <= 0) {
if (err == 0)
goto done;
@@ -1085,13 +1126,23 @@ more:
}
if (self->header.needs_swap)
- perf_event_header__bswap(&event.header);
+ perf_event_header__bswap(&event->header);
- size = event.header.size;
+ size = event->header.size;
if (size == 0)
size = 8;
- p = &event;
+ if (size > cur_size) {
+ void *new = realloc(buf, size);
+ if (!new) {
+ pr_err("failed to allocate memory to read event\n");
+ goto out_err;
+ }
+ buf = new;
+ cur_size = size;
+ event = buf;
+ }
+ p = event;
p += sizeof(struct perf_event_header);
if (size - sizeof(struct perf_event_header)) {
@@ -1107,17 +1158,11 @@ more:
}
}
- if ((skip = perf_session__process_event(self, &event, tool, head)) < 0) {
- dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",
- head, event.header.size, event.header.type);
- /*
- * assume we lost track of the stream, check alignment, and
- * increment a single u64 in the hope to catch on again 'soon'.
- */
- if (unlikely(head & 7))
- head &= ~7ULL;
-
- size = 8;
+ if ((skip = perf_session__process_event(self, event, tool, head)) < 0) {
+ pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
+ head, event->header.size, event->header.type);
+ err = -EINVAL;
+ goto out_err;
}
head += size;
@@ -1130,6 +1175,7 @@ more:
done:
err = 0;
out_err:
+ free(buf);
perf_session__warn_about_errors(self, tool);
perf_session_free_sample_buffers(self);
return err;
@@ -1226,17 +1272,11 @@ more:
if (size == 0 ||
perf_session__process_event(session, event, tool, file_pos) < 0) {
- dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",
- file_offset + head, event->header.size,
- event->header.type);
- /*
- * assume we lost track of the stream, check alignment, and
- * increment a single u64 in the hope to catch on again 'soon'.
- */
- if (unlikely(head & 7))
- head &= ~7ULL;
-
- size = 8;
+ pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
+ file_offset + head, event->header.size,
+ event->header.type);
+ err = -EINVAL;
+ goto out_err;
}
head += size;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index ab9867b2b433..e2ba8858f3e1 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -2783,3 +2783,11 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
return ret;
}
+
+struct map *dso__new_map(const char *name)
+{
+ struct dso *dso = dso__new(name);
+ struct map *map = map__new2(0, dso, MAP__FUNCTION);
+
+ return map;
+}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index ac49ef208a5f..5649d63798cb 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -65,6 +65,11 @@ struct symbol {
void symbol__delete(struct symbol *sym);
+static inline size_t symbol__size(const struct symbol *sym)
+{
+ return sym->end - sym->start + 1;
+}
+
struct strlist;
struct symbol_conf {
@@ -237,6 +242,7 @@ void dso__set_long_name(struct dso *dso, char *name);
void dso__set_build_id(struct dso *dso, void *build_id);
void dso__read_running_kernel_build_id(struct dso *dso,
struct machine *machine);
+struct map *dso__new_map(const char *name);
struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
u64 addr);
struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c
new file mode 100644
index 000000000000..1064d5b148ad
--- /dev/null
+++ b/tools/perf/util/target.c
@@ -0,0 +1,142 @@
+/*
+ * Helper functions for handling target threads/cpus
+ *
+ * Copyright (C) 2012, LG Electronics, Namhyung Kim <namhyung.kim@lge.com>
+ *
+ * Released under the GPL v2.
+ */
+
+#include "target.h"
+#include "debug.h"
+
+#include <pwd.h>
+#include <string.h>
+
+
+enum perf_target_errno perf_target__validate(struct perf_target *target)
+{
+ enum perf_target_errno ret = PERF_ERRNO_TARGET__SUCCESS;
+
+ if (target->pid)
+ target->tid = target->pid;
+
+ /* CPU and PID are mutually exclusive */
+ if (target->tid && target->cpu_list) {
+ target->cpu_list = NULL;
+ if (ret == PERF_ERRNO_TARGET__SUCCESS)
+ ret = PERF_ERRNO_TARGET__PID_OVERRIDE_CPU;
+ }
+
+ /* UID and PID are mutually exclusive */
+ if (target->tid && target->uid_str) {
+ target->uid_str = NULL;
+ if (ret == PERF_ERRNO_TARGET__SUCCESS)
+ ret = PERF_ERRNO_TARGET__PID_OVERRIDE_UID;
+ }
+
+ /* UID and CPU are mutually exclusive */
+ if (target->uid_str && target->cpu_list) {
+ target->cpu_list = NULL;
+ if (ret == PERF_ERRNO_TARGET__SUCCESS)
+ ret = PERF_ERRNO_TARGET__UID_OVERRIDE_CPU;
+ }
+
+ /* PID and SYSTEM are mutually exclusive */
+ if (target->tid && target->system_wide) {
+ target->system_wide = false;
+ if (ret == PERF_ERRNO_TARGET__SUCCESS)
+ ret = PERF_ERRNO_TARGET__PID_OVERRIDE_SYSTEM;
+ }
+
+ /* UID and SYSTEM are mutually exclusive */
+ if (target->uid_str && target->system_wide) {
+ target->system_wide = false;
+ if (ret == PERF_ERRNO_TARGET__SUCCESS)
+ ret = PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM;
+ }
+
+ return ret;
+}
+
+enum perf_target_errno perf_target__parse_uid(struct perf_target *target)
+{
+ struct passwd pwd, *result;
+ char buf[1024];
+ const char *str = target->uid_str;
+
+ target->uid = UINT_MAX;
+ if (str == NULL)
+ return PERF_ERRNO_TARGET__SUCCESS;
+
+ /* Try user name first */
+ getpwnam_r(str, &pwd, buf, sizeof(buf), &result);
+
+ if (result == NULL) {
+ /*
+ * The user name not found. Maybe it's a UID number.
+ */
+ char *endptr;
+ int uid = strtol(str, &endptr, 10);
+
+ if (*endptr != '\0')
+ return PERF_ERRNO_TARGET__INVALID_UID;
+
+ getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
+
+ if (result == NULL)
+ return PERF_ERRNO_TARGET__USER_NOT_FOUND;
+ }
+
+ target->uid = result->pw_uid;
+ return PERF_ERRNO_TARGET__SUCCESS;
+}
+
+/*
+ * This must have a same ordering as the enum perf_target_errno.
+ */
+static const char *perf_target__error_str[] = {
+ "PID/TID switch overriding CPU",
+ "PID/TID switch overriding UID",
+ "UID switch overriding CPU",
+ "PID/TID switch overriding SYSTEM",
+ "UID switch overriding SYSTEM",
+ "Invalid User: %s",
+ "Problems obtaining information for user %s",
+};
+
+int perf_target__strerror(struct perf_target *target, int errnum,
+ char *buf, size_t buflen)
+{
+ int idx;
+ const char *msg;
+
+ if (errnum >= 0) {
+ strerror_r(errnum, buf, buflen);
+ return 0;
+ }
+
+ if (errnum < __PERF_ERRNO_TARGET__START ||
+ errnum >= __PERF_ERRNO_TARGET__END)
+ return -1;
+
+ idx = errnum - __PERF_ERRNO_TARGET__START;
+ msg = perf_target__error_str[idx];
+
+ switch (errnum) {
+ case PERF_ERRNO_TARGET__PID_OVERRIDE_CPU
+ ... PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM:
+ snprintf(buf, buflen, "%s", msg);
+ break;
+
+ case PERF_ERRNO_TARGET__INVALID_UID:
+ case PERF_ERRNO_TARGET__USER_NOT_FOUND:
+ snprintf(buf, buflen, msg, target->uid_str);
+ break;
+
+ default:
+ /* cannot reach here */
+ break;
+ }
+
+ return 0;
+}
diff --git a/tools/perf/util/target.h b/tools/perf/util/target.h
new file mode 100644
index 000000000000..a4be8575fda5
--- /dev/null
+++ b/tools/perf/util/target.h
@@ -0,0 +1,65 @@
+#ifndef _PERF_TARGET_H
+#define _PERF_TARGET_H
+
+#include <stdbool.h>
+#include <sys/types.h>
+
+struct perf_target {
+ const char *pid;
+ const char *tid;
+ const char *cpu_list;
+ const char *uid_str;
+ uid_t uid;
+ bool system_wide;
+ bool uses_mmap;
+};
+
+enum perf_target_errno {
+ PERF_ERRNO_TARGET__SUCCESS = 0,
+
+ /*
+ * Choose an arbitrary negative big number not to clash with standard
+ * errno since SUS requires the errno has distinct positive values.
+ * See 'Issue 6' in the link below.
+ *
+ * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
+ */
+ __PERF_ERRNO_TARGET__START = -10000,
+
+
+ /* for perf_target__validate() */
+ PERF_ERRNO_TARGET__PID_OVERRIDE_CPU = __PERF_ERRNO_TARGET__START,
+ PERF_ERRNO_TARGET__PID_OVERRIDE_UID,
+ PERF_ERRNO_TARGET__UID_OVERRIDE_CPU,
+ PERF_ERRNO_TARGET__PID_OVERRIDE_SYSTEM,
+ PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM,
+
+ /* for perf_target__parse_uid() */
+ PERF_ERRNO_TARGET__INVALID_UID,
+ PERF_ERRNO_TARGET__USER_NOT_FOUND,
+
+ __PERF_ERRNO_TARGET__END,
+};
+
+enum perf_target_errno perf_target__validate(struct perf_target *target);
+enum perf_target_errno perf_target__parse_uid(struct perf_target *target);
+
+int perf_target__strerror(struct perf_target *target, int errnum, char *buf,
+ size_t buflen);
+
+static inline bool perf_target__has_task(struct perf_target *target)
+{
+ return target->tid || target->pid || target->uid_str;
+}
+
+static inline bool perf_target__has_cpu(struct perf_target *target)
+{
+ return target->system_wide || target->cpu_list;
+}
+
+static inline bool perf_target__none(struct perf_target *target)
+{
+ return !perf_target__has_task(target) && !perf_target__has_cpu(target);
+}
+
+#endif /* _PERF_TARGET_H */
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
index 7da80f14418b..f718df8a3c59 100644
--- a/tools/perf/util/thread_map.h
+++ b/tools/perf/util/thread_map.h
@@ -6,7 +6,7 @@
struct thread_map {
int nr;
- int map[];
+ pid_t map[];
};
struct thread_map *thread_map__new_by_pid(pid_t pid);
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index 09fe579ccafb..abe0e8e95068 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -69,23 +69,24 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
ret += SNPRINTF(bf + ret, size - ret, "], ");
- if (top->target_pid)
+ if (top->target.pid)
ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s",
- top->target_pid);
- else if (top->target_tid)
+ top->target.pid);
+ else if (top->target.tid)
ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s",
- top->target_tid);
- else if (top->uid_str != NULL)
+ top->target.tid);
+ else if (top->target.uid_str != NULL)
ret += SNPRINTF(bf + ret, size - ret, " (uid: %s",
- top->uid_str);
+ top->target.uid_str);
else
ret += SNPRINTF(bf + ret, size - ret, " (all");
- if (top->cpu_list)
+ if (top->target.cpu_list)
ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)",
- top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list);
+ top->evlist->cpus->nr > 1 ? "s" : "",
+ top->target.cpu_list);
else {
- if (top->target_tid)
+ if (top->target.tid)
ret += SNPRINTF(bf + ret, size - ret, ")");
else
ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)",
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index ce61cb2d1acf..33347ca89ee4 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -13,6 +13,7 @@ struct perf_session;
struct perf_top {
struct perf_tool tool;
struct perf_evlist *evlist;
+ struct perf_target target;
/*
* Symbols will be added here in perf_event__process_sample and will
* get out after decayed.
@@ -23,10 +24,7 @@ struct perf_top {
u64 guest_us_samples, guest_kernel_samples;
int print_entries, count_filter, delay_secs;
int freq;
- const char *target_pid, *target_tid;
- uid_t uid;
bool hide_kernel_symbols, hide_user_symbols, zero;
- bool system_wide;
bool use_tui, use_stdio;
bool sort_has_symbols;
bool dont_use_callchains;
@@ -37,7 +35,6 @@ struct perf_top {
bool sample_id_all_missing;
bool exclude_guest_missing;
bool dump_symtab;
- const char *cpu_list;
struct hist_entry *sym_filter_entry;
struct perf_evsel *sym_evsel;
struct perf_session *session;
@@ -47,7 +44,6 @@ struct perf_top {
int realtime_prio;
int sym_pcnt_filter;
const char *sym_filter;
- const char *uid_str;
};
size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index fc22cf5c605f..a8d81c35ef66 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -68,7 +68,7 @@ struct events {
};
-void *malloc_or_die(unsigned int size)
+static void *malloc_or_die(unsigned int size)
{
void *data;
@@ -448,6 +448,8 @@ static void tracing_data_header(void)
else
buf[0] = 0;
+ read_trace_init(buf[0], buf[0]);
+
write_or_die(buf, 1);
/* save size of long */
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index dfd1bd8371a4..df2fddbf0cd2 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -17,2169 +17,305 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * The parts for function graph printing was taken and modified from the
- * Linux Kernel that were written by Frederic Weisbecker.
*/
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#include <errno.h>
#include "../perf.h"
#include "util.h"
#include "trace-event.h"
-int header_page_ts_offset;
-int header_page_ts_size;
-int header_page_size_offset;
int header_page_size_size;
-int header_page_overwrite_offset;
-int header_page_overwrite_size;
+int header_page_ts_size;
int header_page_data_offset;
-int header_page_data_size;
-
-bool latency_format;
-
-static char *input_buf;
-static unsigned long long input_buf_ptr;
-static unsigned long long input_buf_siz;
-
-static int cpus;
-static int long_size;
-static int is_flag_field;
-static int is_symbolic_field;
-
-static struct format_field *
-find_any_field(struct event *event, const char *name);
-
-static void init_input_buf(char *buf, unsigned long long size)
-{
- input_buf = buf;
- input_buf_siz = size;
- input_buf_ptr = 0;
-}
-
-struct cmdline {
- char *comm;
- int pid;
-};
-
-static struct cmdline *cmdlines;
-static int cmdline_count;
-
-static int cmdline_cmp(const void *a, const void *b)
-{
- const struct cmdline *ca = a;
- const struct cmdline *cb = b;
-
- if (ca->pid < cb->pid)
- return -1;
- if (ca->pid > cb->pid)
- return 1;
-
- return 0;
-}
-void parse_cmdlines(char *file, int size __unused)
-{
- struct cmdline_list {
- struct cmdline_list *next;
- char *comm;
- int pid;
- } *list = NULL, *item;
- char *line;
- char *next = NULL;
- int i;
+struct pevent *perf_pevent;
+static struct pevent *pevent;
- line = strtok_r(file, "\n", &next);
- while (line) {
- item = malloc_or_die(sizeof(*item));
- sscanf(line, "%d %as", &item->pid,
- (float *)(void *)&item->comm); /* workaround gcc warning */
- item->next = list;
- list = item;
- line = strtok_r(NULL, "\n", &next);
- cmdline_count++;
- }
-
- cmdlines = malloc_or_die(sizeof(*cmdlines) * cmdline_count);
-
- i = 0;
- while (list) {
- cmdlines[i].pid = list->pid;
- cmdlines[i].comm = list->comm;
- i++;
- item = list;
- list = list->next;
- free(item);
- }
-
- qsort(cmdlines, cmdline_count, sizeof(*cmdlines), cmdline_cmp);
-}
-
-static struct func_map {
- unsigned long long addr;
- char *func;
- char *mod;
-} *func_list;
-static unsigned int func_count;
-
-static int func_cmp(const void *a, const void *b)
-{
- const struct func_map *fa = a;
- const struct func_map *fb = b;
-
- if (fa->addr < fb->addr)
- return -1;
- if (fa->addr > fb->addr)
- return 1;
-
- return 0;
-}
-
-void parse_proc_kallsyms(char *file, unsigned int size __unused)
-{
- struct func_list {
- struct func_list *next;
- unsigned long long addr;
- char *func;
- char *mod;
- } *list = NULL, *item;
- char *line;
- char *next = NULL;
- char *addr_str;
- char ch;
- int ret __used;
- int i;
-
- line = strtok_r(file, "\n", &next);
- while (line) {
- item = malloc_or_die(sizeof(*item));
- item->mod = NULL;
- ret = sscanf(line, "%as %c %as\t[%as",
- (float *)(void *)&addr_str, /* workaround gcc warning */
- &ch,
- (float *)(void *)&item->func,
- (float *)(void *)&item->mod);
- item->addr = strtoull(addr_str, NULL, 16);
- free(addr_str);
-
- /* truncate the extra ']' */
- if (item->mod)
- item->mod[strlen(item->mod) - 1] = 0;
-
-
- item->next = list;
- list = item;
- line = strtok_r(NULL, "\n", &next);
- func_count++;
- }
-
- func_list = malloc_or_die(sizeof(*func_list) * (func_count + 1));
-
- i = 0;
- while (list) {
- func_list[i].func = list->func;
- func_list[i].addr = list->addr;
- func_list[i].mod = list->mod;
- i++;
- item = list;
- list = list->next;
- free(item);
- }
-
- qsort(func_list, func_count, sizeof(*func_list), func_cmp);
-
- /*
- * Add a special record at the end.
- */
- func_list[func_count].func = NULL;
- func_list[func_count].addr = 0;
- func_list[func_count].mod = NULL;
-}
+bool latency_format;
-/*
- * We are searching for a record in between, not an exact
- * match.
- */
-static int func_bcmp(const void *a, const void *b)
+int read_trace_init(int file_bigendian, int host_bigendian)
{
- const struct func_map *fa = a;
- const struct func_map *fb = b;
-
- if ((fa->addr == fb->addr) ||
-
- (fa->addr > fb->addr &&
- fa->addr < (fb+1)->addr))
+ if (pevent)
return 0;
- if (fa->addr < fb->addr)
- return -1;
-
- return 1;
-}
-
-static struct func_map *find_func(unsigned long long addr)
-{
- struct func_map *func;
- struct func_map key;
-
- key.addr = addr;
-
- func = bsearch(&key, func_list, func_count, sizeof(*func_list),
- func_bcmp);
-
- return func;
-}
-
-void print_funcs(void)
-{
- int i;
-
- for (i = 0; i < (int)func_count; i++) {
- printf("%016llx %s",
- func_list[i].addr,
- func_list[i].func);
- if (func_list[i].mod)
- printf(" [%s]\n", func_list[i].mod);
- else
- printf("\n");
- }
-}
+ perf_pevent = pevent_alloc();
+ pevent = perf_pevent;
-static struct printk_map {
- unsigned long long addr;
- char *printk;
-} *printk_list;
-static unsigned int printk_count;
-
-static int printk_cmp(const void *a, const void *b)
-{
- const struct func_map *fa = a;
- const struct func_map *fb = b;
-
- if (fa->addr < fb->addr)
- return -1;
- if (fa->addr > fb->addr)
- return 1;
+ pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
+ pevent_set_file_bigendian(pevent, file_bigendian);
+ pevent_set_host_bigendian(pevent, host_bigendian);
return 0;
}
-static struct printk_map *find_printk(unsigned long long addr)
-{
- struct printk_map *printk;
- struct printk_map key;
-
- key.addr = addr;
-
- printk = bsearch(&key, printk_list, printk_count, sizeof(*printk_list),
- printk_cmp);
-
- return printk;
-}
-
-void parse_ftrace_printk(char *file, unsigned int size __unused)
-{
- struct printk_list {
- struct printk_list *next;
- unsigned long long addr;
- char *printk;
- } *list = NULL, *item;
- char *line;
- char *next = NULL;
- char *addr_str;
- int i;
-
- line = strtok_r(file, "\n", &next);
- while (line) {
- addr_str = strsep(&line, ":");
- if (!line) {
- warning("error parsing print strings");
- break;
- }
- item = malloc_or_die(sizeof(*item));
- item->addr = strtoull(addr_str, NULL, 16);
- /* fmt still has a space, skip it */
- item->printk = strdup(line+1);
- item->next = list;
- list = item;
- line = strtok_r(NULL, "\n", &next);
- printk_count++;
- }
-
- printk_list = malloc_or_die(sizeof(*printk_list) * printk_count + 1);
-
- i = 0;
- while (list) {
- printk_list[i].printk = list->printk;
- printk_list[i].addr = list->addr;
- i++;
- item = list;
- list = list->next;
- free(item);
- }
-
- qsort(printk_list, printk_count, sizeof(*printk_list), printk_cmp);
-}
-
-void print_printk(void)
-{
- int i;
-
- for (i = 0; i < (int)printk_count; i++) {
- printf("%016llx %s\n",
- printk_list[i].addr,
- printk_list[i].printk);
- }
-}
-
-static struct event *alloc_event(void)
-{
- struct event *event;
-
- event = malloc_or_die(sizeof(*event));
- memset(event, 0, sizeof(*event));
-
- return event;
-}
-
-enum event_type {
- EVENT_ERROR,
- EVENT_NONE,
- EVENT_SPACE,
- EVENT_NEWLINE,
- EVENT_OP,
- EVENT_DELIM,
- EVENT_ITEM,
- EVENT_DQUOTE,
- EVENT_SQUOTE,
-};
-
-static struct event *event_list;
-
-static void add_event(struct event *event)
+static int get_common_field(struct scripting_context *context,
+ int *offset, int *size, const char *type)
{
- event->next = event_list;
- event_list = event;
-}
-
-static int event_item_type(enum event_type type)
-{
- switch (type) {
- case EVENT_ITEM ... EVENT_SQUOTE:
- return 1;
- case EVENT_ERROR ... EVENT_DELIM:
- default:
- return 0;
- }
-}
-
-static void free_arg(struct print_arg *arg)
-{
- if (!arg)
- return;
-
- switch (arg->type) {
- case PRINT_ATOM:
- if (arg->atom.atom)
- free(arg->atom.atom);
- break;
- case PRINT_NULL:
- case PRINT_FIELD ... PRINT_OP:
- default:
- /* todo */
- break;
- }
-
- free(arg);
-}
-
-static enum event_type get_type(int ch)
-{
- if (ch == '\n')
- return EVENT_NEWLINE;
- if (isspace(ch))
- return EVENT_SPACE;
- if (isalnum(ch) || ch == '_')
- return EVENT_ITEM;
- if (ch == '\'')
- return EVENT_SQUOTE;
- if (ch == '"')
- return EVENT_DQUOTE;
- if (!isprint(ch))
- return EVENT_NONE;
- if (ch == '(' || ch == ')' || ch == ',')
- return EVENT_DELIM;
-
- return EVENT_OP;
-}
-
-static int __read_char(void)
-{
- if (input_buf_ptr >= input_buf_siz)
- return -1;
-
- return input_buf[input_buf_ptr++];
-}
-
-static int __peek_char(void)
-{
- if (input_buf_ptr >= input_buf_siz)
- return -1;
-
- return input_buf[input_buf_ptr];
-}
-
-static enum event_type __read_token(char **tok)
-{
- char buf[BUFSIZ];
- int ch, last_ch, quote_ch, next_ch;
- int i = 0;
- int tok_size = 0;
- enum event_type type;
-
- *tok = NULL;
-
-
- ch = __read_char();
- if (ch < 0)
- return EVENT_NONE;
-
- type = get_type(ch);
- if (type == EVENT_NONE)
- return type;
-
- buf[i++] = ch;
-
- switch (type) {
- case EVENT_NEWLINE:
- case EVENT_DELIM:
- *tok = malloc_or_die(2);
- (*tok)[0] = ch;
- (*tok)[1] = 0;
- return type;
-
- case EVENT_OP:
- switch (ch) {
- case '-':
- next_ch = __peek_char();
- if (next_ch == '>') {
- buf[i++] = __read_char();
- break;
- }
- /* fall through */
- case '+':
- case '|':
- case '&':
- case '>':
- case '<':
- last_ch = ch;
- ch = __peek_char();
- if (ch != last_ch)
- goto test_equal;
- buf[i++] = __read_char();
- switch (last_ch) {
- case '>':
- case '<':
- goto test_equal;
- default:
- break;
- }
- break;
- case '!':
- case '=':
- goto test_equal;
- default: /* what should we do instead? */
- break;
- }
- buf[i] = 0;
- *tok = strdup(buf);
- return type;
-
- test_equal:
- ch = __peek_char();
- if (ch == '=')
- buf[i++] = __read_char();
- break;
-
- case EVENT_DQUOTE:
- case EVENT_SQUOTE:
- /* don't keep quotes */
- i--;
- quote_ch = ch;
- last_ch = 0;
- do {
- if (i == (BUFSIZ - 1)) {
- buf[i] = 0;
- if (*tok) {
- *tok = realloc(*tok, tok_size + BUFSIZ);
- if (!*tok)
- return EVENT_NONE;
- strcat(*tok, buf);
- } else
- *tok = strdup(buf);
-
- if (!*tok)
- return EVENT_NONE;
- tok_size += BUFSIZ;
- i = 0;
- }
- last_ch = ch;
- ch = __read_char();
- buf[i++] = ch;
- /* the '\' '\' will cancel itself */
- if (ch == '\\' && last_ch == '\\')
- last_ch = 0;
- } while (ch != quote_ch || last_ch == '\\');
- /* remove the last quote */
- i--;
- goto out;
-
- case EVENT_ERROR ... EVENT_SPACE:
- case EVENT_ITEM:
- default:
- break;
- }
-
- while (get_type(__peek_char()) == type) {
- if (i == (BUFSIZ - 1)) {
- buf[i] = 0;
- if (*tok) {
- *tok = realloc(*tok, tok_size + BUFSIZ);
- if (!*tok)
- return EVENT_NONE;
- strcat(*tok, buf);
- } else
- *tok = strdup(buf);
-
- if (!*tok)
- return EVENT_NONE;
- tok_size += BUFSIZ;
- i = 0;
- }
- ch = __read_char();
- buf[i++] = ch;
- }
-
- out:
- buf[i] = 0;
- if (*tok) {
- *tok = realloc(*tok, tok_size + i);
- if (!*tok)
- return EVENT_NONE;
- strcat(*tok, buf);
- } else
- *tok = strdup(buf);
- if (!*tok)
- return EVENT_NONE;
-
- return type;
-}
-
-static void free_token(char *tok)
-{
- if (tok)
- free(tok);
-}
-
-static enum event_type read_token(char **tok)
-{
- enum event_type type;
-
- for (;;) {
- type = __read_token(tok);
- if (type != EVENT_SPACE)
- return type;
-
- free_token(*tok);
- }
-
- /* not reached */
- return EVENT_NONE;
-}
-
-/* no newline */
-static enum event_type read_token_item(char **tok)
-{
- enum event_type type;
-
- for (;;) {
- type = __read_token(tok);
- if (type != EVENT_SPACE && type != EVENT_NEWLINE)
- return type;
-
- free_token(*tok);
- }
-
- /* not reached */
- return EVENT_NONE;
-}
-
-static int test_type(enum event_type type, enum event_type expect)
-{
- if (type != expect) {
- warning("Error: expected type %d but read %d",
- expect, type);
- return -1;
- }
- return 0;
-}
+ struct event_format *event;
+ struct format_field *field;
-static int __test_type_token(enum event_type type, char *token,
- enum event_type expect, const char *expect_tok,
- bool warn)
-{
- if (type != expect) {
- if (warn)
- warning("Error: expected type %d but read %d",
- expect, type);
- return -1;
- }
+ if (!*size) {
+ if (!pevent->events)
+ return 0;
- if (strcmp(token, expect_tok) != 0) {
- if (warn)
- warning("Error: expected '%s' but read '%s'",
- expect_tok, token);
- return -1;
+ event = pevent->events[0];
+ field = pevent_find_common_field(event, type);
+ if (!field)
+ return 0;
+ *offset = field->offset;
+ *size = field->size;
}
- return 0;
-}
-static int test_type_token(enum event_type type, char *token,
- enum event_type expect, const char *expect_tok)
-{
- return __test_type_token(type, token, expect, expect_tok, true);
+ return pevent_read_number(pevent, context->event_data + *offset, *size);
}
-static int __read_expect_type(enum event_type expect, char **tok, int newline_ok)
-{
- enum event_type type;
-
- if (newline_ok)
- type = read_token(tok);
- else
- type = read_token_item(tok);
- return test_type(type, expect);
-}
-
-static int read_expect_type(enum event_type expect, char **tok)
-{
- return __read_expect_type(expect, tok, 1);
-}
-
-static int __read_expected(enum event_type expect, const char *str,
- int newline_ok, bool warn)
+int common_lock_depth(struct scripting_context *context)
{
- enum event_type type;
- char *token;
+ static int offset;
+ static int size;
int ret;
- if (newline_ok)
- type = read_token(&token);
- else
- type = read_token_item(&token);
-
- ret = __test_type_token(type, token, expect, str, warn);
-
- free_token(token);
+ ret = get_common_field(context, &size, &offset,
+ "common_lock_depth");
+ if (ret < 0)
+ return -1;
return ret;
}
-static int read_expected(enum event_type expect, const char *str)
-{
- return __read_expected(expect, str, 1, true);
-}
-
-static int read_expected_item(enum event_type expect, const char *str)
-{
- return __read_expected(expect, str, 0, true);
-}
-
-static char *event_read_name(void)
-{
- char *token;
-
- if (read_expected(EVENT_ITEM, "name") < 0)
- return NULL;
-
- if (read_expected(EVENT_OP, ":") < 0)
- return NULL;
-
- if (read_expect_type(EVENT_ITEM, &token) < 0)
- goto fail;
-
- return token;
-
- fail:
- free_token(token);
- return NULL;
-}
-
-static int event_read_id(void)
+int common_flags(struct scripting_context *context)
{
- char *token;
- int id = -1;
-
- if (read_expected_item(EVENT_ITEM, "ID") < 0)
- return -1;
+ static int offset;
+ static int size;
+ int ret;
- if (read_expected(EVENT_OP, ":") < 0)
+ ret = get_common_field(context, &size, &offset,
+ "common_flags");
+ if (ret < 0)
return -1;
- if (read_expect_type(EVENT_ITEM, &token) < 0)
- goto free;
-
- id = strtoul(token, NULL, 0);
-
- free:
- free_token(token);
- return id;
-}
-
-static int field_is_string(struct format_field *field)
-{
- if ((field->flags & FIELD_IS_ARRAY) &&
- (!strstr(field->type, "char") || !strstr(field->type, "u8") ||
- !strstr(field->type, "s8")))
- return 1;
-
- return 0;
-}
-
-static int field_is_dynamic(struct format_field *field)
-{
- if (!strncmp(field->type, "__data_loc", 10))
- return 1;
-
- return 0;
-}
-
-static int event_read_fields(struct event *event, struct format_field **fields)
-{
- struct format_field *field = NULL;
- enum event_type type;
- char *token;
- char *last_token;
- int count = 0;
-
- do {
- type = read_token(&token);
- if (type == EVENT_NEWLINE) {
- free_token(token);
- return count;
- }
-
- count++;
-
- if (test_type_token(type, token, EVENT_ITEM, "field"))
- goto fail;
- free_token(token);
-
- type = read_token(&token);
- /*
- * The ftrace fields may still use the "special" name.
- * Just ignore it.
- */
- if (event->flags & EVENT_FL_ISFTRACE &&
- type == EVENT_ITEM && strcmp(token, "special") == 0) {
- free_token(token);
- type = read_token(&token);
- }
-
- if (test_type_token(type, token, EVENT_OP, ":") < 0)
- return -1;
-
- if (read_expect_type(EVENT_ITEM, &token) < 0)
- goto fail;
-
- last_token = token;
-
- field = malloc_or_die(sizeof(*field));
- memset(field, 0, sizeof(*field));
-
- /* read the rest of the type */
- for (;;) {
- type = read_token(&token);
- if (type == EVENT_ITEM ||
- (type == EVENT_OP && strcmp(token, "*") == 0) ||
- /*
- * Some of the ftrace fields are broken and have
- * an illegal "." in them.
- */
- (event->flags & EVENT_FL_ISFTRACE &&
- type == EVENT_OP && strcmp(token, ".") == 0)) {
-
- if (strcmp(token, "*") == 0)
- field->flags |= FIELD_IS_POINTER;
-
- if (field->type) {
- field->type = realloc(field->type,
- strlen(field->type) +
- strlen(last_token) + 2);
- strcat(field->type, " ");
- strcat(field->type, last_token);
- } else
- field->type = last_token;
- last_token = token;
- continue;
- }
-
- break;
- }
-
- if (!field->type) {
- die("no type found");
- goto fail;
- }
- field->name = last_token;
-
- if (test_type(type, EVENT_OP))
- goto fail;
-
- if (strcmp(token, "[") == 0) {
- enum event_type last_type = type;
- char *brackets = token;
- int len;
-
- field->flags |= FIELD_IS_ARRAY;
-
- type = read_token(&token);
- while (strcmp(token, "]") != 0) {
- if (last_type == EVENT_ITEM &&
- type == EVENT_ITEM)
- len = 2;
- else
- len = 1;
- last_type = type;
-
- brackets = realloc(brackets,
- strlen(brackets) +
- strlen(token) + len);
- if (len == 2)
- strcat(brackets, " ");
- strcat(brackets, token);
- free_token(token);
- type = read_token(&token);
- if (type == EVENT_NONE) {
- die("failed to find token");
- goto fail;
- }
- }
-
- free_token(token);
-
- brackets = realloc(brackets, strlen(brackets) + 2);
- strcat(brackets, "]");
-
- /* add brackets to type */
-
- type = read_token(&token);
- /*
- * If the next token is not an OP, then it is of
- * the format: type [] item;
- */
- if (type == EVENT_ITEM) {
- field->type = realloc(field->type,
- strlen(field->type) +
- strlen(field->name) +
- strlen(brackets) + 2);
- strcat(field->type, " ");
- strcat(field->type, field->name);
- free_token(field->name);
- strcat(field->type, brackets);
- field->name = token;
- type = read_token(&token);
- } else {
- field->type = realloc(field->type,
- strlen(field->type) +
- strlen(brackets) + 1);
- strcat(field->type, brackets);
- }
- free(brackets);
- }
-
- if (field_is_string(field)) {
- field->flags |= FIELD_IS_STRING;
- if (field_is_dynamic(field))
- field->flags |= FIELD_IS_DYNAMIC;
- }
-
- if (test_type_token(type, token, EVENT_OP, ";"))
- goto fail;
- free_token(token);
-
- if (read_expected(EVENT_ITEM, "offset") < 0)
- goto fail_expect;
-
- if (read_expected(EVENT_OP, ":") < 0)
- goto fail_expect;
-
- if (read_expect_type(EVENT_ITEM, &token))
- goto fail;
- field->offset = strtoul(token, NULL, 0);
- free_token(token);
-
- if (read_expected(EVENT_OP, ";") < 0)
- goto fail_expect;
-
- if (read_expected(EVENT_ITEM, "size") < 0)
- goto fail_expect;
-
- if (read_expected(EVENT_OP, ":") < 0)
- goto fail_expect;
-
- if (read_expect_type(EVENT_ITEM, &token))
- goto fail;
- field->size = strtoul(token, NULL, 0);
- free_token(token);
-
- if (read_expected(EVENT_OP, ";") < 0)
- goto fail_expect;
-
- type = read_token(&token);
- if (type != EVENT_NEWLINE) {
- /* newer versions of the kernel have a "signed" type */
- if (test_type_token(type, token, EVENT_ITEM, "signed"))
- goto fail;
-
- free_token(token);
-
- if (read_expected(EVENT_OP, ":") < 0)
- goto fail_expect;
-
- if (read_expect_type(EVENT_ITEM, &token))
- goto fail;
-
- if (strtoul(token, NULL, 0))
- field->flags |= FIELD_IS_SIGNED;
-
- free_token(token);
- if (read_expected(EVENT_OP, ";") < 0)
- goto fail_expect;
-
- if (read_expect_type(EVENT_NEWLINE, &token))
- goto fail;
- }
-
- free_token(token);
-
- *fields = field;
- fields = &field->next;
-
- } while (1);
-
- return 0;
-
-fail:
- free_token(token);
-fail_expect:
- if (field)
- free(field);
- return -1;
+ return ret;
}
-static int event_read_format(struct event *event)
+int common_pc(struct scripting_context *context)
{
- char *token;
+ static int offset;
+ static int size;
int ret;
- if (read_expected_item(EVENT_ITEM, "format") < 0)
- return -1;
-
- if (read_expected(EVENT_OP, ":") < 0)
- return -1;
-
- if (read_expect_type(EVENT_NEWLINE, &token))
- goto fail;
- free_token(token);
-
- ret = event_read_fields(event, &event->format.common_fields);
+ ret = get_common_field(context, &size, &offset,
+ "common_preempt_count");
if (ret < 0)
- return ret;
- event->format.nr_common = ret;
-
- ret = event_read_fields(event, &event->format.fields);
- if (ret < 0)
- return ret;
- event->format.nr_fields = ret;
-
- return 0;
-
- fail:
- free_token(token);
- return -1;
-}
-
-enum event_type
-process_arg_token(struct event *event, struct print_arg *arg,
- char **tok, enum event_type type);
-
-static enum event_type
-process_arg(struct event *event, struct print_arg *arg, char **tok)
-{
- enum event_type type;
- char *token;
-
- type = read_token(&token);
- *tok = token;
+ return -1;
- return process_arg_token(event, arg, tok, type);
+ return ret;
}
-static enum event_type
-process_cond(struct event *event, struct print_arg *top, char **tok)
+unsigned long long
+raw_field_value(struct event_format *event, const char *name, void *data)
{
- struct print_arg *arg, *left, *right;
- enum event_type type;
- char *token = NULL;
-
- arg = malloc_or_die(sizeof(*arg));
- memset(arg, 0, sizeof(*arg));
-
- left = malloc_or_die(sizeof(*left));
-
- right = malloc_or_die(sizeof(*right));
-
- arg->type = PRINT_OP;
- arg->op.left = left;
- arg->op.right = right;
-
- *tok = NULL;
- type = process_arg(event, left, &token);
- if (test_type_token(type, token, EVENT_OP, ":"))
- goto out_free;
-
- arg->op.op = token;
-
- type = process_arg(event, right, &token);
+ struct format_field *field;
+ unsigned long long val;
- top->op.right = arg;
+ field = pevent_find_any_field(event, name);
+ if (!field)
+ return 0ULL;
- *tok = token;
- return type;
+ pevent_read_number_field(field, data, &val);
-out_free:
- free_token(*tok);
- free(right);
- free(left);
- free_arg(arg);
- return EVENT_ERROR;
+ return val;
}
-static enum event_type
-process_array(struct event *event, struct print_arg *top, char **tok)
+void *raw_field_ptr(struct event_format *event, const char *name, void *data)
{
- struct print_arg *arg;
- enum event_type type;
- char *token = NULL;
-
- arg = malloc_or_die(sizeof(*arg));
- memset(arg, 0, sizeof(*arg));
-
- *tok = NULL;
- type = process_arg(event, arg, &token);
- if (test_type_token(type, token, EVENT_OP, "]"))
- goto out_free;
-
- top->op.right = arg;
-
- free_token(token);
- type = read_token_item(&token);
- *tok = token;
-
- return type;
+ struct format_field *field;
-out_free:
- free_token(*tok);
- free_arg(arg);
- return EVENT_ERROR;
-}
+ field = pevent_find_any_field(event, name);
+ if (!field)
+ return NULL;
-static int get_op_prio(char *op)
-{
- if (!op[1]) {
- switch (op[0]) {
- case '*':
- case '/':
- case '%':
- return 6;
- case '+':
- case '-':
- return 7;
- /* '>>' and '<<' are 8 */
- case '<':
- case '>':
- return 9;
- /* '==' and '!=' are 10 */
- case '&':
- return 11;
- case '^':
- return 12;
- case '|':
- return 13;
- case '?':
- return 16;
- default:
- die("unknown op '%c'", op[0]);
- return -1;
- }
- } else {
- if (strcmp(op, "++") == 0 ||
- strcmp(op, "--") == 0) {
- return 3;
- } else if (strcmp(op, ">>") == 0 ||
- strcmp(op, "<<") == 0) {
- return 8;
- } else if (strcmp(op, ">=") == 0 ||
- strcmp(op, "<=") == 0) {
- return 9;
- } else if (strcmp(op, "==") == 0 ||
- strcmp(op, "!=") == 0) {
- return 10;
- } else if (strcmp(op, "&&") == 0) {
- return 14;
- } else if (strcmp(op, "||") == 0) {
- return 15;
- } else {
- die("unknown op '%s'", op);
- return -1;
- }
- }
-}
+ if (field->flags & FIELD_IS_DYNAMIC) {
+ int offset;
-static void set_op_prio(struct print_arg *arg)
-{
+ offset = *(int *)(data + field->offset);
+ offset &= 0xffff;
- /* single ops are the greatest */
- if (!arg->op.left || arg->op.left->type == PRINT_NULL) {
- arg->op.prio = 0;
- return;
+ return data + offset;
}
- arg->op.prio = get_op_prio(arg->op.op);
+ return data + field->offset;
}
-static enum event_type
-process_op(struct event *event, struct print_arg *arg, char **tok)
+int trace_parse_common_type(void *data)
{
- struct print_arg *left, *right = NULL;
- enum event_type type;
- char *token;
-
- /* the op is passed in via tok */
- token = *tok;
-
- if (arg->type == PRINT_OP && !arg->op.left) {
- /* handle single op */
- if (token[1]) {
- die("bad op token %s", token);
- return EVENT_ERROR;
- }
- switch (token[0]) {
- case '!':
- case '+':
- case '-':
- break;
- default:
- die("bad op token %s", token);
- return EVENT_ERROR;
- }
-
- /* make an empty left */
- left = malloc_or_die(sizeof(*left));
- left->type = PRINT_NULL;
- arg->op.left = left;
-
- right = malloc_or_die(sizeof(*right));
- arg->op.right = right;
-
- type = process_arg(event, right, tok);
-
- } else if (strcmp(token, "?") == 0) {
-
- left = malloc_or_die(sizeof(*left));
- /* copy the top arg to the left */
- *left = *arg;
-
- arg->type = PRINT_OP;
- arg->op.op = token;
- arg->op.left = left;
- arg->op.prio = 0;
-
- type = process_cond(event, arg, tok);
-
- } else if (strcmp(token, ">>") == 0 ||
- strcmp(token, "<<") == 0 ||
- strcmp(token, "&") == 0 ||
- strcmp(token, "|") == 0 ||
- strcmp(token, "&&") == 0 ||
- strcmp(token, "||") == 0 ||
- strcmp(token, "-") == 0 ||
- strcmp(token, "+") == 0 ||
- strcmp(token, "*") == 0 ||
- strcmp(token, "^") == 0 ||
- strcmp(token, "/") == 0 ||
- strcmp(token, "<") == 0 ||
- strcmp(token, ">") == 0 ||
- strcmp(token, "==") == 0 ||
- strcmp(token, "!=") == 0) {
-
- left = malloc_or_die(sizeof(*left));
-
- /* copy the top arg to the left */
- *left = *arg;
-
- arg->type = PRINT_OP;
- arg->op.op = token;
- arg->op.left = left;
-
- set_op_prio(arg);
-
- right = malloc_or_die(sizeof(*right));
-
- type = read_token_item(&token);
- *tok = token;
-
- /* could just be a type pointer */
- if ((strcmp(arg->op.op, "*") == 0) &&
- type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
- if (left->type != PRINT_ATOM)
- die("bad pointer type");
- left->atom.atom = realloc(left->atom.atom,
- sizeof(left->atom.atom) + 3);
- strcat(left->atom.atom, " *");
- *arg = *left;
- free(arg);
-
- return type;
- }
-
- type = process_arg_token(event, right, tok, type);
-
- arg->op.right = right;
-
- } else if (strcmp(token, "[") == 0) {
-
- left = malloc_or_die(sizeof(*left));
- *left = *arg;
-
- arg->type = PRINT_OP;
- arg->op.op = token;
- arg->op.left = left;
-
- arg->op.prio = 0;
- type = process_array(event, arg, tok);
-
- } else {
- warning("unknown op '%s'", token);
- event->flags |= EVENT_FL_FAILED;
- /* the arg is now the left side */
- return EVENT_NONE;
- }
-
- if (type == EVENT_OP) {
- int prio;
-
- /* higher prios need to be closer to the root */
- prio = get_op_prio(*tok);
-
- if (prio > arg->op.prio)
- return process_op(event, arg, tok);
+ struct pevent_record record;
- return process_op(event, right, tok);
- }
-
- return type;
+ record.data = data;
+ return pevent_data_type(pevent, &record);
}
-static enum event_type
-process_entry(struct event *event __unused, struct print_arg *arg,
- char **tok)
+int trace_parse_common_pid(void *data)
{
- enum event_type type;
- char *field;
- char *token;
-
- if (read_expected(EVENT_OP, "->") < 0)
- return EVENT_ERROR;
-
- if (read_expect_type(EVENT_ITEM, &token) < 0)
- goto fail;
- field = token;
-
- arg->type = PRINT_FIELD;
- arg->field.name = field;
-
- if (is_flag_field) {
- arg->field.field = find_any_field(event, arg->field.name);
- arg->field.field->flags |= FIELD_IS_FLAG;
- is_flag_field = 0;
- } else if (is_symbolic_field) {
- arg->field.field = find_any_field(event, arg->field.name);
- arg->field.field->flags |= FIELD_IS_SYMBOLIC;
- is_symbolic_field = 0;
- }
-
- type = read_token(&token);
- *tok = token;
+ struct pevent_record record;
- return type;
-
-fail:
- free_token(token);
- return EVENT_ERROR;
+ record.data = data;
+ return pevent_data_pid(pevent, &record);
}
-static char *arg_eval (struct print_arg *arg);
-
-static long long arg_num_eval(struct print_arg *arg)
+unsigned long long read_size(void *ptr, int size)
{
- long long left, right;
- long long val = 0;
-
- switch (arg->type) {
- case PRINT_ATOM:
- val = strtoll(arg->atom.atom, NULL, 0);
- break;
- case PRINT_TYPE:
- val = arg_num_eval(arg->typecast.item);
- break;
- case PRINT_OP:
- switch (arg->op.op[0]) {
- case '|':
- left = arg_num_eval(arg->op.left);
- right = arg_num_eval(arg->op.right);
- if (arg->op.op[1])
- val = left || right;
- else
- val = left | right;
- break;
- case '&':
- left = arg_num_eval(arg->op.left);
- right = arg_num_eval(arg->op.right);
- if (arg->op.op[1])
- val = left && right;
- else
- val = left & right;
- break;
- case '<':
- left = arg_num_eval(arg->op.left);
- right = arg_num_eval(arg->op.right);
- switch (arg->op.op[1]) {
- case 0:
- val = left < right;
- break;
- case '<':
- val = left << right;
- break;
- case '=':
- val = left <= right;
- break;
- default:
- die("unknown op '%s'", arg->op.op);
- }
- break;
- case '>':
- left = arg_num_eval(arg->op.left);
- right = arg_num_eval(arg->op.right);
- switch (arg->op.op[1]) {
- case 0:
- val = left > right;
- break;
- case '>':
- val = left >> right;
- break;
- case '=':
- val = left >= right;
- break;
- default:
- die("unknown op '%s'", arg->op.op);
- }
- break;
- case '=':
- left = arg_num_eval(arg->op.left);
- right = arg_num_eval(arg->op.right);
-
- if (arg->op.op[1] != '=')
- die("unknown op '%s'", arg->op.op);
-
- val = left == right;
- break;
- case '!':
- left = arg_num_eval(arg->op.left);
- right = arg_num_eval(arg->op.right);
-
- switch (arg->op.op[1]) {
- case '=':
- val = left != right;
- break;
- default:
- die("unknown op '%s'", arg->op.op);
- }
- break;
- case '+':
- left = arg_num_eval(arg->op.left);
- right = arg_num_eval(arg->op.right);
- val = left + right;
- break;
- default:
- die("unknown op '%s'", arg->op.op);
- }
- break;
-
- case PRINT_NULL:
- case PRINT_FIELD ... PRINT_SYMBOL:
- case PRINT_STRING:
- default:
- die("invalid eval type %d", arg->type);
-
- }
- return val;
+ return pevent_read_number(pevent, ptr, size);
}
-static char *arg_eval (struct print_arg *arg)
+struct event_format *trace_find_event(int type)
{
- long long val;
- static char buf[20];
-
- switch (arg->type) {
- case PRINT_ATOM:
- return arg->atom.atom;
- case PRINT_TYPE:
- return arg_eval(arg->typecast.item);
- case PRINT_OP:
- val = arg_num_eval(arg);
- sprintf(buf, "%lld", val);
- return buf;
-
- case PRINT_NULL:
- case PRINT_FIELD ... PRINT_SYMBOL:
- case PRINT_STRING:
- default:
- die("invalid eval type %d", arg->type);
- break;
- }
-
- return NULL;
+ return pevent_find_event(pevent, type);
}
-static enum event_type
-process_fields(struct event *event, struct print_flag_sym **list, char **tok)
-{
- enum event_type type;
- struct print_arg *arg = NULL;
- struct print_flag_sym *field;
- char *token = NULL;
- char *value;
-
- do {
- free_token(token);
- type = read_token_item(&token);
- if (test_type_token(type, token, EVENT_OP, "{"))
- break;
-
- arg = malloc_or_die(sizeof(*arg));
-
- free_token(token);
- type = process_arg(event, arg, &token);
-
- if (type == EVENT_OP)
- type = process_op(event, arg, &token);
-
- if (type == EVENT_ERROR)
- goto out_free;
-
- if (test_type_token(type, token, EVENT_DELIM, ","))
- goto out_free;
-
- field = malloc_or_die(sizeof(*field));
- memset(field, 0, sizeof(*field));
-
- value = arg_eval(arg);
- field->value = strdup(value);
-
- free_token(token);
- type = process_arg(event, arg, &token);
- if (test_type_token(type, token, EVENT_OP, "}"))
- goto out_free;
-
- value = arg_eval(arg);
- field->str = strdup(value);
- free_arg(arg);
- arg = NULL;
-
- *list = field;
- list = &field->next;
- free_token(token);
- type = read_token_item(&token);
- } while (type == EVENT_DELIM && strcmp(token, ",") == 0);
-
- *tok = token;
- return type;
-
-out_free:
- free_arg(arg);
- free_token(token);
-
- return EVENT_ERROR;
-}
-
-static enum event_type
-process_flags(struct event *event, struct print_arg *arg, char **tok)
+void print_trace_event(int cpu, void *data, int size)
{
- struct print_arg *field;
- enum event_type type;
- char *token;
-
- memset(arg, 0, sizeof(*arg));
- arg->type = PRINT_FLAGS;
-
- if (read_expected_item(EVENT_DELIM, "(") < 0)
- return EVENT_ERROR;
-
- field = malloc_or_die(sizeof(*field));
-
- type = process_arg(event, field, &token);
- while (type == EVENT_OP)
- type = process_op(event, field, &token);
- if (test_type_token(type, token, EVENT_DELIM, ","))
- goto out_free;
+ struct event_format *event;
+ struct pevent_record record;
+ struct trace_seq s;
+ int type;
- arg->flags.field = field;
+ type = trace_parse_common_type(data);
- type = read_token_item(&token);
- if (event_item_type(type)) {
- arg->flags.delim = token;
- type = read_token_item(&token);
+ event = trace_find_event(type);
+ if (!event) {
+ warning("ug! no event found for type %d", type);
+ return;
}
- if (test_type_token(type, token, EVENT_DELIM, ","))
- goto out_free;
-
- type = process_fields(event, &arg->flags.flags, &token);
- if (test_type_token(type, token, EVENT_DELIM, ")"))
- goto out_free;
+ memset(&record, 0, sizeof(record));
+ record.cpu = cpu;
+ record.size = size;
+ record.data = data;
- free_token(token);
- type = read_token_item(tok);
- return type;
-
-out_free:
- free_token(token);
- return EVENT_ERROR;
+ trace_seq_init(&s);
+ pevent_print_event(pevent, &s, &record);
+ trace_seq_do_printf(&s);
+ printf("\n");
}
-static enum event_type
-process_symbols(struct event *event, struct print_arg *arg, char **tok)
+void print_event(int cpu, void *data, int size, unsigned long long nsecs,
+ char *comm)
{
- struct print_arg *field;
- enum event_type type;
- char *token;
-
- memset(arg, 0, sizeof(*arg));
- arg->type = PRINT_SYMBOL;
-
- if (read_expected_item(EVENT_DELIM, "(") < 0)
- return EVENT_ERROR;
-
- field = malloc_or_die(sizeof(*field));
-
- type = process_arg(event, field, &token);
- if (test_type_token(type, token, EVENT_DELIM, ","))
- goto out_free;
+ struct pevent_record record;
+ struct trace_seq s;
+ int pid;
- arg->symbol.field = field;
+ pevent->latency_format = latency_format;
- type = process_fields(event, &arg->symbol.symbols, &token);
- if (test_type_token(type, token, EVENT_DELIM, ")"))
- goto out_free;
+ record.ts = nsecs;
+ record.cpu = cpu;
+ record.size = size;
+ record.data = data;
+ pid = pevent_data_pid(pevent, &record);
- free_token(token);
- type = read_token_item(tok);
- return type;
+ if (!pevent_pid_is_registered(pevent, pid))
+ pevent_register_comm(pevent, comm, pid);
-out_free:
- free_token(token);
- return EVENT_ERROR;
+ trace_seq_init(&s);
+ pevent_print_event(pevent, &s, &record);
+ trace_seq_do_printf(&s);
+ printf("\n");
}
-static enum event_type
-process_paren(struct event *event, struct print_arg *arg, char **tok)
+void parse_proc_kallsyms(char *file, unsigned int size __unused)
{
- struct print_arg *item_arg;
- enum event_type type;
- char *token;
-
- type = process_arg(event, arg, &token);
-
- if (type == EVENT_ERROR)
- return EVENT_ERROR;
-
- if (type == EVENT_OP)
- type = process_op(event, arg, &token);
-
- if (type == EVENT_ERROR)
- return EVENT_ERROR;
-
- if (test_type_token(type, token, EVENT_DELIM, ")")) {
- free_token(token);
- return EVENT_ERROR;
- }
-
- free_token(token);
- type = read_token_item(&token);
-
- /*
- * If the next token is an item or another open paren, then
- * this was a typecast.
- */
- if (event_item_type(type) ||
- (type == EVENT_DELIM && strcmp(token, "(") == 0)) {
-
- /* make this a typecast and contine */
+ unsigned long long addr;
+ char *func;
+ char *line;
+ char *next = NULL;
+ char *addr_str;
+ char *mod;
+ char ch;
- /* prevous must be an atom */
- if (arg->type != PRINT_ATOM)
- die("previous needed to be PRINT_ATOM");
+ line = strtok_r(file, "\n", &next);
+ while (line) {
+ mod = NULL;
+ sscanf(line, "%as %c %as\t[%as",
+ (float *)(void *)&addr_str, /* workaround gcc warning */
+ &ch, (float *)(void *)&func, (float *)(void *)&mod);
+ addr = strtoull(addr_str, NULL, 16);
+ free(addr_str);
- item_arg = malloc_or_die(sizeof(*item_arg));
+ /* truncate the extra ']' */
+ if (mod)
+ mod[strlen(mod) - 1] = 0;
- arg->type = PRINT_TYPE;
- arg->typecast.type = arg->atom.atom;
- arg->typecast.item = item_arg;
- type = process_arg_token(event, item_arg, &token, type);
+ pevent_register_function(pevent, func, addr, mod);
+ free(func);
+ free(mod);
+ line = strtok_r(NULL, "\n", &next);
}
-
- *tok = token;
- return type;
}
-
-static enum event_type
-process_str(struct event *event __unused, struct print_arg *arg, char **tok)
+void parse_ftrace_printk(char *file, unsigned int size __unused)
{
- enum event_type type;
- char *token;
-
- if (read_expected(EVENT_DELIM, "(") < 0)
- return EVENT_ERROR;
-
- if (read_expect_type(EVENT_ITEM, &token) < 0)
- goto fail;
-
- arg->type = PRINT_STRING;
- arg->string.string = token;
- arg->string.offset = -1;
-
- if (read_expected(EVENT_DELIM, ")") < 0)
- return EVENT_ERROR;
-
- type = read_token(&token);
- *tok = token;
-
- return type;
-fail:
- free_token(token);
- return EVENT_ERROR;
-}
+ unsigned long long addr;
+ char *printk;
+ char *line;
+ char *next = NULL;
+ char *addr_str;
+ char *fmt;
-enum event_type
-process_arg_token(struct event *event, struct print_arg *arg,
- char **tok, enum event_type type)
-{
- char *token;
- char *atom;
-
- token = *tok;
-
- switch (type) {
- case EVENT_ITEM:
- if (strcmp(token, "REC") == 0) {
- free_token(token);
- type = process_entry(event, arg, &token);
- } else if (strcmp(token, "__print_flags") == 0) {
- free_token(token);
- is_flag_field = 1;
- type = process_flags(event, arg, &token);
- } else if (strcmp(token, "__print_symbolic") == 0) {
- free_token(token);
- is_symbolic_field = 1;
- type = process_symbols(event, arg, &token);
- } else if (strcmp(token, "__get_str") == 0) {
- free_token(token);
- type = process_str(event, arg, &token);
- } else {
- atom = token;
- /* test the next token */
- type = read_token_item(&token);
-
- /* atoms can be more than one token long */
- while (type == EVENT_ITEM) {
- atom = realloc(atom, strlen(atom) + strlen(token) + 2);
- strcat(atom, " ");
- strcat(atom, token);
- free_token(token);
- type = read_token_item(&token);
- }
-
- /* todo, test for function */
-
- arg->type = PRINT_ATOM;
- arg->atom.atom = atom;
- }
- break;
- case EVENT_DQUOTE:
- case EVENT_SQUOTE:
- arg->type = PRINT_ATOM;
- arg->atom.atom = token;
- type = read_token_item(&token);
- break;
- case EVENT_DELIM:
- if (strcmp(token, "(") == 0) {
- free_token(token);
- type = process_paren(event, arg, &token);
+ line = strtok_r(file, "\n", &next);
+ while (line) {
+ addr_str = strtok_r(line, ":", &fmt);
+ if (!addr_str) {
+ warning("printk format with empty entry");
break;
}
- case EVENT_OP:
- /* handle single ops */
- arg->type = PRINT_OP;
- arg->op.op = token;
- arg->op.left = NULL;
- type = process_op(event, arg, &token);
-
- break;
-
- case EVENT_ERROR ... EVENT_NEWLINE:
- default:
- die("unexpected type %d", type);
- }
- *tok = token;
-
- return type;
-}
-
-static int event_read_print_args(struct event *event, struct print_arg **list)
-{
- enum event_type type = EVENT_ERROR;
- struct print_arg *arg;
- char *token;
- int args = 0;
-
- do {
- if (type == EVENT_NEWLINE) {
- free_token(token);
- type = read_token_item(&token);
- continue;
- }
-
- arg = malloc_or_die(sizeof(*arg));
- memset(arg, 0, sizeof(*arg));
-
- type = process_arg(event, arg, &token);
-
- if (type == EVENT_ERROR) {
- free_arg(arg);
- return -1;
- }
-
- *list = arg;
- args++;
-
- if (type == EVENT_OP) {
- type = process_op(event, arg, &token);
- list = &arg->next;
- continue;
- }
-
- if (type == EVENT_DELIM && strcmp(token, ",") == 0) {
- free_token(token);
- *list = arg;
- list = &arg->next;
- continue;
- }
- break;
- } while (type != EVENT_NONE);
-
- if (type != EVENT_NONE)
- free_token(token);
-
- return args;
-}
-
-static int event_read_print(struct event *event)
-{
- enum event_type type;
- char *token;
- int ret;
-
- if (read_expected_item(EVENT_ITEM, "print") < 0)
- return -1;
-
- if (read_expected(EVENT_ITEM, "fmt") < 0)
- return -1;
-
- if (read_expected(EVENT_OP, ":") < 0)
- return -1;
-
- if (read_expect_type(EVENT_DQUOTE, &token) < 0)
- goto fail;
-
- concat:
- event->print_fmt.format = token;
- event->print_fmt.args = NULL;
-
- /* ok to have no arg */
- type = read_token_item(&token);
-
- if (type == EVENT_NONE)
- return 0;
-
- /* Handle concatination of print lines */
- if (type == EVENT_DQUOTE) {
- char *cat;
-
- cat = malloc_or_die(strlen(event->print_fmt.format) +
- strlen(token) + 1);
- strcpy(cat, event->print_fmt.format);
- strcat(cat, token);
- free_token(token);
- free_token(event->print_fmt.format);
- event->print_fmt.format = NULL;
- token = cat;
- goto concat;
- }
-
- if (test_type_token(type, token, EVENT_DELIM, ","))
- goto fail;
-
- free_token(token);
-
- ret = event_read_print_args(event, &event->print_fmt.args);
- if (ret < 0)
- return -1;
-
- return ret;
-
- fail:
- free_token(token);
- return -1;
-}
-
-static struct format_field *
-find_common_field(struct event *event, const char *name)
-{
- struct format_field *format;
-
- for (format = event->format.common_fields;
- format; format = format->next) {
- if (strcmp(format->name, name) == 0)
- break;
- }
-
- return format;
-}
-
-static struct format_field *
-find_field(struct event *event, const char *name)
-{
- struct format_field *format;
-
- for (format = event->format.fields;
- format; format = format->next) {
- if (strcmp(format->name, name) == 0)
- break;
+ addr = strtoull(addr_str, NULL, 16);
+ /* fmt still has a space, skip it */
+ printk = strdup(fmt+1);
+ line = strtok_r(NULL, "\n", &next);
+ pevent_register_print_string(pevent, printk, addr);
}
-
- return format;
}
-static struct format_field *
-find_any_field(struct event *event, const char *name)
+int parse_ftrace_file(char *buf, unsigned long size)
{
- struct format_field *format;
-
- format = find_common_field(event, name);
- if (format)
- return format;
- return find_field(event, name);
+ return pevent_parse_event(pevent, buf, size, "ftrace");
}
-unsigned long long read_size(void *ptr, int size)
+int parse_event_file(char *buf, unsigned long size, char *sys)
{
- switch (size) {
- case 1:
- return *(unsigned char *)ptr;
- case 2:
- return data2host2(ptr);
- case 4:
- return data2host4(ptr);
- case 8:
- return data2host8(ptr);
- default:
- /* BUG! */
- return 0;
- }
+ return pevent_parse_event(pevent, buf, size, sys);
}
-unsigned long long
-raw_field_value(struct event *event, const char *name, void *data)
+struct event_format *trace_find_next_event(struct event_format *event)
{
- struct format_field *field;
-
- field = find_any_field(event, name);
- if (!field)
- return 0ULL;
+ static int idx;
- return read_size(data + field->offset, field->size);
-}
-
-void *raw_field_ptr(struct event *event, const char *name, void *data)
-{
- struct format_field *field;
-
- field = find_any_field(event, name);
- if (!field)
+ if (!pevent->events)
return NULL;
- if (field->flags & FIELD_IS_DYNAMIC) {
- int offset;
-
- offset = *(int *)(data + field->offset);
- offset &= 0xffff;
-
- return data + offset;
- }
-
- return data + field->offset;
-}
-
-static int get_common_info(const char *type, int *offset, int *size)
-{
- struct event *event;
- struct format_field *field;
-
- /*
- * All events should have the same common elements.
- * Pick any event to find where the type is;
- */
- if (!event_list)
- die("no event_list!");
-
- event = event_list;
- field = find_common_field(event, type);
- if (!field)
- die("field '%s' not found", type);
-
- *offset = field->offset;
- *size = field->size;
-
- return 0;
-}
-
-static int __parse_common(void *data, int *size, int *offset,
- const char *name)
-{
- int ret;
-
- if (!*size) {
- ret = get_common_info(name, offset, size);
- if (ret < 0)
- return ret;
+ if (!event) {
+ idx = 0;
+ return pevent->events[0];
}
- return read_size(data + *offset, *size);
-}
-
-int trace_parse_common_type(void *data)
-{
- static int type_offset;
- static int type_size;
-
- return __parse_common(data, &type_size, &type_offset,
- "common_type");
-}
-
-int trace_parse_common_pid(void *data)
-{
- static int pid_offset;
- static int pid_size;
-
- return __parse_common(data, &pid_size, &pid_offset,
- "common_pid");
-}
-
-int parse_common_pc(void *data)
-{
- static int pc_offset;
- static int pc_size;
-
- return __parse_common(data, &pc_size, &pc_offset,
- "common_preempt_count");
-}
-
-int parse_common_flags(void *data)
-{
- static int flags_offset;
- static int flags_size;
-
- return __parse_common(data, &flags_size, &flags_offset,
- "common_flags");
-}
-
-int parse_common_lock_depth(void *data)
-{
- static int ld_offset;
- static int ld_size;
- int ret;
- ret = __parse_common(data, &ld_size, &ld_offset,
- "common_lock_depth");
- if (ret < 0)
- return -1;
-
- return ret;
-}
-
-struct event *trace_find_event(int id)
-{
- struct event *event;
-
- for (event = event_list; event; event = event->next) {
- if (event->id == id)
- break;
+ if (idx < pevent->nr_events && event == pevent->events[idx]) {
+ idx++;
+ if (idx == pevent->nr_events)
+ return NULL;
+ return pevent->events[idx];
}
- return event;
-}
-
-struct event *trace_find_next_event(struct event *event)
-{
- if (!event)
- return event_list;
-
- return event->next;
-}
-
-static unsigned long long eval_num_arg(void *data, int size,
- struct event *event, struct print_arg *arg)
-{
- unsigned long long val = 0;
- unsigned long long left, right;
- struct print_arg *larg;
- switch (arg->type) {
- case PRINT_NULL:
- /* ?? */
- return 0;
- case PRINT_ATOM:
- return strtoull(arg->atom.atom, NULL, 0);
- case PRINT_FIELD:
- if (!arg->field.field) {
- arg->field.field = find_any_field(event, arg->field.name);
- if (!arg->field.field)
- die("field %s not found", arg->field.name);
- }
- /* must be a number */
- val = read_size(data + arg->field.field->offset,
- arg->field.field->size);
- break;
- case PRINT_FLAGS:
- case PRINT_SYMBOL:
- break;
- case PRINT_TYPE:
- return eval_num_arg(data, size, event, arg->typecast.item);
- case PRINT_STRING:
- return 0;
- break;
- case PRINT_OP:
- if (strcmp(arg->op.op, "[") == 0) {
- /*
- * Arrays are special, since we don't want
- * to read the arg as is.
- */
- if (arg->op.left->type != PRINT_FIELD)
- goto default_op; /* oops, all bets off */
- larg = arg->op.left;
- if (!larg->field.field) {
- larg->field.field =
- find_any_field(event, larg->field.name);
- if (!larg->field.field)
- die("field %s not found", larg->field.name);
- }
- right = eval_num_arg(data, size, event, arg->op.right);
- val = read_size(data + larg->field.field->offset +
- right * long_size, long_size);
- break;
- }
- default_op:
- left = eval_num_arg(data, size, event, arg->op.left);
- right = eval_num_arg(data, size, event, arg->op.right);
- switch (arg->op.op[0]) {
- case '|':
- if (arg->op.op[1])
- val = left || right;
- else
- val = left | right;
- break;
- case '&':
- if (arg->op.op[1])
- val = left && right;
- else
- val = left & right;
- break;
- case '<':
- switch (arg->op.op[1]) {
- case 0:
- val = left < right;
- break;
- case '<':
- val = left << right;
- break;
- case '=':
- val = left <= right;
- break;
- default:
- die("unknown op '%s'", arg->op.op);
- }
- break;
- case '>':
- switch (arg->op.op[1]) {
- case 0:
- val = left > right;
- break;
- case '>':
- val = left >> right;
- break;
- case '=':
- val = left >= right;
- break;
- default:
- die("unknown op '%s'", arg->op.op);
- }
- break;
- case '=':
- if (arg->op.op[1] != '=')
- die("unknown op '%s'", arg->op.op);
- val = left == right;
- break;
- case '-':
- val = left - right;
- break;
- case '+':
- val = left + right;
- break;
- default:
- die("unknown op '%s'", arg->op.op);
- }
- break;
- default: /* not sure what to do there */
- return 0;
+ for (idx = 1; idx < pevent->nr_events; idx++) {
+ if (event == pevent->events[idx - 1])
+ return pevent->events[idx];
}
- return val;
+ return NULL;
}
struct flag {
@@ -2221,933 +357,3 @@ unsigned long long eval_flag(const char *flag)
return 0;
}
-
-static void print_str_arg(void *data, int size,
- struct event *event, struct print_arg *arg)
-{
- struct print_flag_sym *flag;
- unsigned long long val, fval;
- char *str;
- int print;
-
- switch (arg->type) {
- case PRINT_NULL:
- /* ?? */
- return;
- case PRINT_ATOM:
- printf("%s", arg->atom.atom);
- return;
- case PRINT_FIELD:
- if (!arg->field.field) {
- arg->field.field = find_any_field(event, arg->field.name);
- if (!arg->field.field)
- die("field %s not found", arg->field.name);
- }
- str = malloc_or_die(arg->field.field->size + 1);
- memcpy(str, data + arg->field.field->offset,
- arg->field.field->size);
- str[arg->field.field->size] = 0;
- printf("%s", str);
- free(str);
- break;
- case PRINT_FLAGS:
- val = eval_num_arg(data, size, event, arg->flags.field);
- print = 0;
- for (flag = arg->flags.flags; flag; flag = flag->next) {
- fval = eval_flag(flag->value);
- if (!val && !fval) {
- printf("%s", flag->str);
- break;
- }
- if (fval && (val & fval) == fval) {
- if (print && arg->flags.delim)
- printf("%s", arg->flags.delim);
- printf("%s", flag->str);
- print = 1;
- val &= ~fval;
- }
- }
- break;
- case PRINT_SYMBOL:
- val = eval_num_arg(data, size, event, arg->symbol.field);
- for (flag = arg->symbol.symbols; flag; flag = flag->next) {
- fval = eval_flag(flag->value);
- if (val == fval) {
- printf("%s", flag->str);
- break;
- }
- }
- break;
-
- case PRINT_TYPE:
- break;
- case PRINT_STRING: {
- int str_offset;
-
- if (arg->string.offset == -1) {
- struct format_field *f;
-
- f = find_any_field(event, arg->string.string);
- arg->string.offset = f->offset;
- }
- str_offset = *(int *)(data + arg->string.offset);
- str_offset &= 0xffff;
- printf("%s", ((char *)data) + str_offset);
- break;
- }
- case PRINT_OP:
- /*
- * The only op for string should be ? :
- */
- if (arg->op.op[0] != '?')
- return;
- val = eval_num_arg(data, size, event, arg->op.left);
- if (val)
- print_str_arg(data, size, event, arg->op.right->op.left);
- else
- print_str_arg(data, size, event, arg->op.right->op.right);
- break;
- default:
- /* well... */
- break;
- }
-}
-
-static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event *event)
-{
- static struct format_field *field, *ip_field;
- struct print_arg *args, *arg, **next;
- unsigned long long ip, val;
- char *ptr;
- void *bptr;
-
- if (!field) {
- field = find_field(event, "buf");
- if (!field)
- die("can't find buffer field for binary printk");
- ip_field = find_field(event, "ip");
- if (!ip_field)
- die("can't find ip field for binary printk");
- }
-
- ip = read_size(data + ip_field->offset, ip_field->size);
-
- /*
- * The first arg is the IP pointer.
- */
- args = malloc_or_die(sizeof(*args));
- arg = args;
- arg->next = NULL;
- next = &arg->next;
-
- arg->type = PRINT_ATOM;
- arg->atom.atom = malloc_or_die(32);
- sprintf(arg->atom.atom, "%lld", ip);
-
- /* skip the first "%pf : " */
- for (ptr = fmt + 6, bptr = data + field->offset;
- bptr < data + size && *ptr; ptr++) {
- int ls = 0;
-
- if (*ptr == '%') {
- process_again:
- ptr++;
- switch (*ptr) {
- case '%':
- break;
- case 'l':
- ls++;
- goto process_again;
- case 'L':
- ls = 2;
- goto process_again;
- case '0' ... '9':
- goto process_again;
- case 'p':
- ls = 1;
- /* fall through */
- case 'd':
- case 'u':
- case 'x':
- case 'i':
- /* the pointers are always 4 bytes aligned */
- bptr = (void *)(((unsigned long)bptr + 3) &
- ~3);
- switch (ls) {
- case 0:
- case 1:
- ls = long_size;
- break;
- case 2:
- ls = 8;
- default:
- break;
- }
- val = read_size(bptr, ls);
- bptr += ls;
- arg = malloc_or_die(sizeof(*arg));
- arg->next = NULL;
- arg->type = PRINT_ATOM;
- arg->atom.atom = malloc_or_die(32);
- sprintf(arg->atom.atom, "%lld", val);
- *next = arg;
- next = &arg->next;
- break;
- case 's':
- arg = malloc_or_die(sizeof(*arg));
- arg->next = NULL;
- arg->type = PRINT_STRING;
- arg->string.string = strdup(bptr);
- bptr += strlen(bptr) + 1;
- *next = arg;
- next = &arg->next;
- default:
- break;
- }
- }
- }
-
- return args;
-}
-
-static void free_args(struct print_arg *args)
-{
- struct print_arg *next;
-
- while (args) {
- next = args->next;
-
- if (args->type == PRINT_ATOM)
- free(args->atom.atom);
- else
- free(args->string.string);
- free(args);
- args = next;
- }
-}
-
-static char *get_bprint_format(void *data, int size __unused, struct event *event)
-{
- unsigned long long addr;
- static struct format_field *field;
- struct printk_map *printk;
- char *format;
- char *p;
-
- if (!field) {
- field = find_field(event, "fmt");
- if (!field)
- die("can't find format field for binary printk");
- printf("field->offset = %d size=%d\n", field->offset, field->size);
- }
-
- addr = read_size(data + field->offset, field->size);
-
- printk = find_printk(addr);
- if (!printk) {
- format = malloc_or_die(45);
- sprintf(format, "%%pf : (NO FORMAT FOUND at %llx)\n",
- addr);
- return format;
- }
-
- p = printk->printk;
- /* Remove any quotes. */
- if (*p == '"')
- p++;
- format = malloc_or_die(strlen(p) + 10);
- sprintf(format, "%s : %s", "%pf", p);
- /* remove ending quotes and new line since we will add one too */
- p = format + strlen(format) - 1;
- if (*p == '"')
- *p = 0;
-
- p -= 2;
- if (strcmp(p, "\\n") == 0)
- *p = 0;
-
- return format;
-}
-
-static void pretty_print(void *data, int size, struct event *event)
-{
- struct print_fmt *print_fmt = &event->print_fmt;
- struct print_arg *arg = print_fmt->args;
- struct print_arg *args = NULL;
- const char *ptr = print_fmt->format;
- unsigned long long val;
- struct func_map *func;
- const char *saveptr;
- char *bprint_fmt = NULL;
- char format[32];
- int show_func;
- int len;
- int ls;
-
- if (event->flags & EVENT_FL_ISFUNC)
- ptr = " %pF <-- %pF";
-
- if (event->flags & EVENT_FL_ISBPRINT) {
- bprint_fmt = get_bprint_format(data, size, event);
- args = make_bprint_args(bprint_fmt, data, size, event);
- arg = args;
- ptr = bprint_fmt;
- }
-
- for (; *ptr; ptr++) {
- ls = 0;
- if (*ptr == '\\') {
- ptr++;
- switch (*ptr) {
- case 'n':
- printf("\n");
- break;
- case 't':
- printf("\t");
- break;
- case 'r':
- printf("\r");
- break;
- case '\\':
- printf("\\");
- break;
- default:
- printf("%c", *ptr);
- break;
- }
-
- } else if (*ptr == '%') {
- saveptr = ptr;
- show_func = 0;
- cont_process:
- ptr++;
- switch (*ptr) {
- case '%':
- printf("%%");
- break;
- case 'l':
- ls++;
- goto cont_process;
- case 'L':
- ls = 2;
- goto cont_process;
- case 'z':
- case 'Z':
- case '0' ... '9':
- goto cont_process;
- case 'p':
- if (long_size == 4)
- ls = 1;
- else
- ls = 2;
-
- if (*(ptr+1) == 'F' ||
- *(ptr+1) == 'f') {
- ptr++;
- show_func = *ptr;
- }
-
- /* fall through */
- case 'd':
- case 'i':
- case 'x':
- case 'X':
- case 'u':
- if (!arg)
- die("no argument match");
-
- len = ((unsigned long)ptr + 1) -
- (unsigned long)saveptr;
-
- /* should never happen */
- if (len > 32)
- die("bad format!");
-
- memcpy(format, saveptr, len);
- format[len] = 0;
-
- val = eval_num_arg(data, size, event, arg);
- arg = arg->next;
-
- if (show_func) {
- func = find_func(val);
- if (func) {
- printf("%s", func->func);
- if (show_func == 'F')
- printf("+0x%llx",
- val - func->addr);
- break;
- }
- }
- switch (ls) {
- case 0:
- printf(format, (int)val);
- break;
- case 1:
- printf(format, (long)val);
- break;
- case 2:
- printf(format, (long long)val);
- break;
- default:
- die("bad count (%d)", ls);
- }
- break;
- case 's':
- if (!arg)
- die("no matching argument");
-
- print_str_arg(data, size, event, arg);
- arg = arg->next;
- break;
- default:
- printf(">%c<", *ptr);
-
- }
- } else
- printf("%c", *ptr);
- }
-
- if (args) {
- free_args(args);
- free(bprint_fmt);
- }
-}
-
-static inline int log10_cpu(int nb)
-{
- if (nb / 100)
- return 3;
- if (nb / 10)
- return 2;
- return 1;
-}
-
-static void print_lat_fmt(void *data, int size __unused)
-{
- unsigned int lat_flags;
- unsigned int pc;
- int lock_depth;
- int hardirq;
- int softirq;
-
- lat_flags = parse_common_flags(data);
- pc = parse_common_pc(data);
- lock_depth = parse_common_lock_depth(data);
-
- hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
- softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
-
- printf("%c%c%c",
- (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
- (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
- 'X' : '.',
- (lat_flags & TRACE_FLAG_NEED_RESCHED) ?
- 'N' : '.',
- (hardirq && softirq) ? 'H' :
- hardirq ? 'h' : softirq ? 's' : '.');
-
- if (pc)
- printf("%x", pc);
- else
- printf(".");
-
- if (lock_depth < 0)
- printf(". ");
- else
- printf("%d ", lock_depth);
-}
-
-#define TRACE_GRAPH_INDENT 2
-
-static struct record *
-get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
- struct record *next)
-{
- struct format_field *field;
- struct event *event;
- unsigned long val;
- int type;
- int pid;
-
- type = trace_parse_common_type(next->data);
- event = trace_find_event(type);
- if (!event)
- return NULL;
-
- if (!(event->flags & EVENT_FL_ISFUNCRET))
- return NULL;
-
- pid = trace_parse_common_pid(next->data);
- field = find_field(event, "func");
- if (!field)
- die("function return does not have field func");
-
- val = read_size(next->data + field->offset, field->size);
-
- if (cur_pid != pid || cur_func != val)
- return NULL;
-
- /* this is a leaf, now advance the iterator */
- return trace_read_data(cpu);
-}
-
-/* Signal a overhead of time execution to the output */
-static void print_graph_overhead(unsigned long long duration)
-{
- /* Non nested entry or return */
- if (duration == ~0ULL)
- return (void)printf(" ");
-
- /* Duration exceeded 100 msecs */
- if (duration > 100000ULL)
- return (void)printf("! ");
-
- /* Duration exceeded 10 msecs */
- if (duration > 10000ULL)
- return (void)printf("+ ");
-
- printf(" ");
-}
-
-static void print_graph_duration(unsigned long long duration)
-{
- unsigned long usecs = duration / 1000;
- unsigned long nsecs_rem = duration % 1000;
- /* log10(ULONG_MAX) + '\0' */
- char msecs_str[21];
- char nsecs_str[5];
- int len;
- int i;
-
- sprintf(msecs_str, "%lu", usecs);
-
- /* Print msecs */
- len = printf("%lu", usecs);
-
- /* Print nsecs (we don't want to exceed 7 numbers) */
- if (len < 7) {
- snprintf(nsecs_str, 8 - len, "%03lu", nsecs_rem);
- len += printf(".%s", nsecs_str);
- }
-
- printf(" us ");
-
- /* Print remaining spaces to fit the row's width */
- for (i = len; i < 7; i++)
- printf(" ");
-
- printf("| ");
-}
-
-static void
-print_graph_entry_leaf(struct event *event, void *data, struct record *ret_rec)
-{
- unsigned long long rettime, calltime;
- unsigned long long duration, depth;
- unsigned long long val;
- struct format_field *field;
- struct func_map *func;
- struct event *ret_event;
- int type;
- int i;
-
- type = trace_parse_common_type(ret_rec->data);
- ret_event = trace_find_event(type);
-
- field = find_field(ret_event, "rettime");
- if (!field)
- die("can't find rettime in return graph");
- rettime = read_size(ret_rec->data + field->offset, field->size);
-
- field = find_field(ret_event, "calltime");
- if (!field)
- die("can't find rettime in return graph");
- calltime = read_size(ret_rec->data + field->offset, field->size);
-
- duration = rettime - calltime;
-
- /* Overhead */
- print_graph_overhead(duration);
-
- /* Duration */
- print_graph_duration(duration);
-
- field = find_field(event, "depth");
- if (!field)
- die("can't find depth in entry graph");
- depth = read_size(data + field->offset, field->size);
-
- /* Function */
- for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
- printf(" ");
-
- field = find_field(event, "func");
- if (!field)
- die("can't find func in entry graph");
- val = read_size(data + field->offset, field->size);
- func = find_func(val);
-
- if (func)
- printf("%s();", func->func);
- else
- printf("%llx();", val);
-}
-
-static void print_graph_nested(struct event *event, void *data)
-{
- struct format_field *field;
- unsigned long long depth;
- unsigned long long val;
- struct func_map *func;
- int i;
-
- /* No overhead */
- print_graph_overhead(-1);
-
- /* No time */
- printf(" | ");
-
- field = find_field(event, "depth");
- if (!field)
- die("can't find depth in entry graph");
- depth = read_size(data + field->offset, field->size);
-
- /* Function */
- for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
- printf(" ");
-
- field = find_field(event, "func");
- if (!field)
- die("can't find func in entry graph");
- val = read_size(data + field->offset, field->size);
- func = find_func(val);
-
- if (func)
- printf("%s() {", func->func);
- else
- printf("%llx() {", val);
-}
-
-static void
-pretty_print_func_ent(void *data, int size, struct event *event,
- int cpu, int pid)
-{
- struct format_field *field;
- struct record *rec;
- void *copy_data;
- unsigned long val;
-
- if (latency_format) {
- print_lat_fmt(data, size);
- printf(" | ");
- }
-
- field = find_field(event, "func");
- if (!field)
- die("function entry does not have func field");
-
- val = read_size(data + field->offset, field->size);
-
- /*
- * peek_data may unmap the data pointer. Copy it first.
- */
- copy_data = malloc_or_die(size);
- memcpy(copy_data, data, size);
- data = copy_data;
-
- rec = trace_peek_data(cpu);
- if (rec) {
- rec = get_return_for_leaf(cpu, pid, val, rec);
- if (rec) {
- print_graph_entry_leaf(event, data, rec);
- goto out_free;
- }
- }
- print_graph_nested(event, data);
-out_free:
- free(data);
-}
-
-static void
-pretty_print_func_ret(void *data, int size __unused, struct event *event)
-{
- unsigned long long rettime, calltime;
- unsigned long long duration, depth;
- struct format_field *field;
- int i;
-
- if (latency_format) {
- print_lat_fmt(data, size);
- printf(" | ");
- }
-
- field = find_field(event, "rettime");
- if (!field)
- die("can't find rettime in return graph");
- rettime = read_size(data + field->offset, field->size);
-
- field = find_field(event, "calltime");
- if (!field)
- die("can't find calltime in return graph");
- calltime = read_size(data + field->offset, field->size);
-
- duration = rettime - calltime;
-
- /* Overhead */
- print_graph_overhead(duration);
-
- /* Duration */
- print_graph_duration(duration);
-
- field = find_field(event, "depth");
- if (!field)
- die("can't find depth in entry graph");
- depth = read_size(data + field->offset, field->size);
-
- /* Function */
- for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
- printf(" ");
-
- printf("}");
-}
-
-static void
-pretty_print_func_graph(void *data, int size, struct event *event,
- int cpu, int pid)
-{
- if (event->flags & EVENT_FL_ISFUNCENT)
- pretty_print_func_ent(data, size, event, cpu, pid);
- else if (event->flags & EVENT_FL_ISFUNCRET)
- pretty_print_func_ret(data, size, event);
- printf("\n");
-}
-
-void print_trace_event(int cpu, void *data, int size)
-{
- struct event *event;
- int type;
- int pid;
-
- type = trace_parse_common_type(data);
-
- event = trace_find_event(type);
- if (!event) {
- warning("ug! no event found for type %d", type);
- return;
- }
-
- pid = trace_parse_common_pid(data);
-
- if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
- return pretty_print_func_graph(data, size, event, cpu, pid);
-
- if (latency_format)
- print_lat_fmt(data, size);
-
- if (event->flags & EVENT_FL_FAILED) {
- printf("EVENT '%s' FAILED TO PARSE\n",
- event->name);
- return;
- }
-
- pretty_print(data, size, event);
-}
-
-static void print_fields(struct print_flag_sym *field)
-{
- printf("{ %s, %s }", field->value, field->str);
- if (field->next) {
- printf(", ");
- print_fields(field->next);
- }
-}
-
-static void print_args(struct print_arg *args)
-{
- int print_paren = 1;
-
- switch (args->type) {
- case PRINT_NULL:
- printf("null");
- break;
- case PRINT_ATOM:
- printf("%s", args->atom.atom);
- break;
- case PRINT_FIELD:
- printf("REC->%s", args->field.name);
- break;
- case PRINT_FLAGS:
- printf("__print_flags(");
- print_args(args->flags.field);
- printf(", %s, ", args->flags.delim);
- print_fields(args->flags.flags);
- printf(")");
- break;
- case PRINT_SYMBOL:
- printf("__print_symbolic(");
- print_args(args->symbol.field);
- printf(", ");
- print_fields(args->symbol.symbols);
- printf(")");
- break;
- case PRINT_STRING:
- printf("__get_str(%s)", args->string.string);
- break;
- case PRINT_TYPE:
- printf("(%s)", args->typecast.type);
- print_args(args->typecast.item);
- break;
- case PRINT_OP:
- if (strcmp(args->op.op, ":") == 0)
- print_paren = 0;
- if (print_paren)
- printf("(");
- print_args(args->op.left);
- printf(" %s ", args->op.op);
- print_args(args->op.right);
- if (print_paren)
- printf(")");
- break;
- default:
- /* we should warn... */
- return;
- }
- if (args->next) {
- printf("\n");
- print_args(args->next);
- }
-}
-
-int parse_ftrace_file(char *buf, unsigned long size)
-{
- struct format_field *field;
- struct print_arg *arg, **list;
- struct event *event;
- int ret;
-
- init_input_buf(buf, size);
-
- event = alloc_event();
- if (!event)
- return -ENOMEM;
-
- event->flags |= EVENT_FL_ISFTRACE;
-
- event->name = event_read_name();
- if (!event->name)
- die("failed to read ftrace event name");
-
- if (strcmp(event->name, "function") == 0)
- event->flags |= EVENT_FL_ISFUNC;
-
- else if (strcmp(event->name, "funcgraph_entry") == 0)
- event->flags |= EVENT_FL_ISFUNCENT;
-
- else if (strcmp(event->name, "funcgraph_exit") == 0)
- event->flags |= EVENT_FL_ISFUNCRET;
-
- else if (strcmp(event->name, "bprint") == 0)
- event->flags |= EVENT_FL_ISBPRINT;
-
- event->id = event_read_id();
- if (event->id < 0)
- die("failed to read ftrace event id");
-
- add_event(event);
-
- ret = event_read_format(event);
- if (ret < 0)
- die("failed to read ftrace event format");
-
- ret = event_read_print(event);
- if (ret < 0)
- die("failed to read ftrace event print fmt");
-
- /* New ftrace handles args */
- if (ret > 0)
- return 0;
- /*
- * The arguments for ftrace files are parsed by the fields.
- * Set up the fields as their arguments.
- */
- list = &event->print_fmt.args;
- for (field = event->format.fields; field; field = field->next) {
- arg = malloc_or_die(sizeof(*arg));
- memset(arg, 0, sizeof(*arg));
- *list = arg;
- list = &arg->next;
- arg->type = PRINT_FIELD;
- arg->field.name = field->name;
- arg->field.field = field;
- }
- return 0;
-}
-
-int parse_event_file(char *buf, unsigned long size, char *sys)
-{
- struct event *event;
- int ret;
-
- init_input_buf(buf, size);
-
- event = alloc_event();
- if (!event)
- return -ENOMEM;
-
- event->name = event_read_name();
- if (!event->name)
- die("failed to read event name");
-
- event->id = event_read_id();
- if (event->id < 0)
- die("failed to read event id");
-
- ret = event_read_format(event);
- if (ret < 0) {
- warning("failed to read event format for %s", event->name);
- goto event_failed;
- }
-
- ret = event_read_print(event);
- if (ret < 0) {
- warning("failed to read event print fmt for %s", event->name);
- goto event_failed;
- }
-
- event->system = strdup(sys);
-
-#define PRINT_ARGS 0
- if (PRINT_ARGS && event->print_fmt.args)
- print_args(event->print_fmt.args);
-
- add_event(event);
- return 0;
-
- event_failed:
- event->flags |= EVENT_FL_FAILED;
- /* still add it even if it failed */
- add_event(event);
- return -1;
-}
-
-void parse_set_info(int nr_cpus, int long_sz)
-{
- cpus = nr_cpus;
- long_size = long_sz;
-}
-
-int common_pc(struct scripting_context *context)
-{
- return parse_common_pc(context->event_data);
-}
-
-int common_flags(struct scripting_context *context)
-{
- return parse_common_flags(context->event_data);
-}
-
-int common_lock_depth(struct scripting_context *context)
-{
- return parse_common_lock_depth(context->event_data);
-}
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index b9592e0de8d7..f097e0dd6c5c 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -52,6 +52,16 @@ static unsigned long page_size;
static ssize_t calc_data_size;
static bool repipe;
+static void *malloc_or_die(int size)
+{
+ void *ret;
+
+ ret = malloc(size);
+ if (!ret)
+ die("malloc");
+ return ret;
+}
+
static int do_read(int fd, void *buf, int size)
{
int rsize = size;
@@ -109,7 +119,7 @@ static unsigned int read4(void)
unsigned int data;
read_or_die(&data, 4);
- return __data2host4(data);
+ return __data2host4(perf_pevent, data);
}
static unsigned long long read8(void)
@@ -117,7 +127,7 @@ static unsigned long long read8(void)
unsigned long long data;
read_or_die(&data, 8);
- return __data2host8(data);
+ return __data2host8(perf_pevent, data);
}
static char *read_string(void)
@@ -282,7 +292,7 @@ struct cpu_data {
unsigned long long offset;
unsigned long long size;
unsigned long long timestamp;
- struct record *next;
+ struct pevent_record *next;
char *page;
int cpu;
int index;
@@ -367,9 +377,9 @@ static int calc_index(void *ptr, int cpu)
return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;
}
-struct record *trace_peek_data(int cpu)
+struct pevent_record *trace_peek_data(int cpu)
{
- struct record *data;
+ struct pevent_record *data;
void *page = cpu_data[cpu].page;
int idx = cpu_data[cpu].index;
void *ptr = page + idx;
@@ -389,15 +399,15 @@ struct record *trace_peek_data(int cpu)
/* FIXME: handle header page */
if (header_page_ts_size != 8)
die("expected a long long type for timestamp");
- cpu_data[cpu].timestamp = data2host8(ptr);
+ cpu_data[cpu].timestamp = data2host8(perf_pevent, ptr);
ptr += 8;
switch (header_page_size_size) {
case 4:
- cpu_data[cpu].page_size = data2host4(ptr);
+ cpu_data[cpu].page_size = data2host4(perf_pevent, ptr);
ptr += 4;
break;
case 8:
- cpu_data[cpu].page_size = data2host8(ptr);
+ cpu_data[cpu].page_size = data2host8(perf_pevent, ptr);
ptr += 8;
break;
default:
@@ -414,7 +424,7 @@ read_again:
return trace_peek_data(cpu);
}
- type_len_ts = data2host4(ptr);
+ type_len_ts = data2host4(perf_pevent, ptr);
ptr += 4;
type_len = type_len4host(type_len_ts);
@@ -424,14 +434,14 @@ read_again:
case RINGBUF_TYPE_PADDING:
if (!delta)
die("error, hit unexpected end of page");
- length = data2host4(ptr);
+ length = data2host4(perf_pevent, ptr);
ptr += 4;
length *= 4;
ptr += length;
goto read_again;
case RINGBUF_TYPE_TIME_EXTEND:
- extend = data2host4(ptr);
+ extend = data2host4(perf_pevent, ptr);
ptr += 4;
extend <<= TS_SHIFT;
extend += delta;
@@ -442,7 +452,7 @@ read_again:
ptr += 12;
break;
case 0:
- length = data2host4(ptr);
+ length = data2host4(perf_pevent, ptr);
ptr += 4;
die("here! length=%d", length);
break;
@@ -467,9 +477,9 @@ read_again:
return data;
}
-struct record *trace_read_data(int cpu)
+struct pevent_record *trace_read_data(int cpu)
{
- struct record *data;
+ struct pevent_record *data;
data = trace_peek_data(cpu);
cpu_data[cpu].next = NULL;
@@ -509,6 +519,8 @@ ssize_t trace_report(int fd, bool __repipe)
file_bigendian = buf[0];
host_bigendian = bigendian();
+ read_trace_init(file_bigendian, host_bigendian);
+
read_or_die(buf, 1);
long_size = buf[0];
@@ -526,11 +538,11 @@ ssize_t trace_report(int fd, bool __repipe)
repipe = false;
if (show_funcs) {
- print_funcs();
+ pevent_print_funcs(perf_pevent);
return size;
}
if (show_printk) {
- print_printk();
+ pevent_print_printk(perf_pevent);
return size;
}
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 58ae14c5baac..639852ac1117 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -1,20 +1,21 @@
-#ifndef __PERF_TRACE_EVENTS_H
-#define __PERF_TRACE_EVENTS_H
+#ifndef _PERF_UTIL_TRACE_EVENT_H
+#define _PERF_UTIL_TRACE_EVENT_H
-#include <stdbool.h>
#include "parse-events.h"
+#include "event-parse.h"
+#include "session.h"
struct machine;
struct perf_sample;
union perf_event;
struct thread;
-#define __unused __attribute__((unused))
-
+extern int header_page_size_size;
+extern int header_page_ts_size;
+extern int header_page_data_offset;
-#ifndef PAGE_MASK
-#define PAGE_MASK (page_size - 1)
-#endif
+extern bool latency_format;
+extern struct pevent *perf_pevent;
enum {
RINGBUF_TYPE_PADDING = 29,
@@ -26,246 +27,37 @@ enum {
#define TS_SHIFT 27
#endif
-#define NSECS_PER_SEC 1000000000ULL
-#define NSECS_PER_USEC 1000ULL
-
-enum format_flags {
- FIELD_IS_ARRAY = 1,
- FIELD_IS_POINTER = 2,
- FIELD_IS_SIGNED = 4,
- FIELD_IS_STRING = 8,
- FIELD_IS_DYNAMIC = 16,
- FIELD_IS_FLAG = 32,
- FIELD_IS_SYMBOLIC = 64,
-};
-
-struct format_field {
- struct format_field *next;
- char *type;
- char *name;
- int offset;
- int size;
- unsigned long flags;
-};
-
-struct format {
- int nr_common;
- int nr_fields;
- struct format_field *common_fields;
- struct format_field *fields;
-};
-
-struct print_arg_atom {
- char *atom;
-};
-
-struct print_arg_string {
- char *string;
- int offset;
-};
-
-struct print_arg_field {
- char *name;
- struct format_field *field;
-};
-
-struct print_flag_sym {
- struct print_flag_sym *next;
- char *value;
- char *str;
-};
-
-struct print_arg_typecast {
- char *type;
- struct print_arg *item;
-};
-
-struct print_arg_flags {
- struct print_arg *field;
- char *delim;
- struct print_flag_sym *flags;
-};
-
-struct print_arg_symbol {
- struct print_arg *field;
- struct print_flag_sym *symbols;
-};
-
-struct print_arg;
-
-struct print_arg_op {
- char *op;
- int prio;
- struct print_arg *left;
- struct print_arg *right;
-};
-
-struct print_arg_func {
- char *name;
- struct print_arg *args;
-};
-
-enum print_arg_type {
- PRINT_NULL,
- PRINT_ATOM,
- PRINT_FIELD,
- PRINT_FLAGS,
- PRINT_SYMBOL,
- PRINT_TYPE,
- PRINT_STRING,
- PRINT_OP,
-};
-
-struct print_arg {
- struct print_arg *next;
- enum print_arg_type type;
- union {
- struct print_arg_atom atom;
- struct print_arg_field field;
- struct print_arg_typecast typecast;
- struct print_arg_flags flags;
- struct print_arg_symbol symbol;
- struct print_arg_func func;
- struct print_arg_string string;
- struct print_arg_op op;
- };
-};
-
-struct print_fmt {
- char *format;
- struct print_arg *args;
-};
-
-struct event {
- struct event *next;
- char *name;
- int id;
- int flags;
- struct format format;
- struct print_fmt print_fmt;
- char *system;
-};
-
-enum {
- EVENT_FL_ISFTRACE = 0x01,
- EVENT_FL_ISPRINT = 0x02,
- EVENT_FL_ISBPRINT = 0x04,
- EVENT_FL_ISFUNC = 0x08,
- EVENT_FL_ISFUNCENT = 0x10,
- EVENT_FL_ISFUNCRET = 0x20,
-
- EVENT_FL_FAILED = 0x80000000
-};
-
-struct record {
- unsigned long long ts;
- int size;
- void *data;
-};
-
-struct record *trace_peek_data(int cpu);
-struct record *trace_read_data(int cpu);
-
-void parse_set_info(int nr_cpus, int long_sz);
-
-ssize_t trace_report(int fd, bool repipe);
-
-void *malloc_or_die(unsigned int size);
+int bigendian(void);
-void parse_cmdlines(char *file, int size);
-void parse_proc_kallsyms(char *file, unsigned int size);
-void parse_ftrace_printk(char *file, unsigned int size);
+int read_trace_init(int file_bigendian, int host_bigendian);
+void print_trace_event(int cpu, void *data, int size);
-void print_funcs(void);
-void print_printk(void);
+void print_event(int cpu, void *data, int size, unsigned long long nsecs,
+ char *comm);
int parse_ftrace_file(char *buf, unsigned long size);
int parse_event_file(char *buf, unsigned long size, char *sys);
-void print_trace_event(int cpu, void *data, int size);
-
-extern int file_bigendian;
-extern int host_bigendian;
-
-int bigendian(void);
-
-static inline unsigned short __data2host2(unsigned short data)
-{
- unsigned short swap;
-
- if (host_bigendian == file_bigendian)
- return data;
- swap = ((data & 0xffULL) << 8) |
- ((data & (0xffULL << 8)) >> 8);
+struct pevent_record *trace_peek_data(int cpu);
+struct event_format *trace_find_event(int type);
- return swap;
-}
-
-static inline unsigned int __data2host4(unsigned int data)
-{
- unsigned int swap;
-
- if (host_bigendian == file_bigendian)
- return data;
-
- swap = ((data & 0xffULL) << 24) |
- ((data & (0xffULL << 8)) << 8) |
- ((data & (0xffULL << 16)) >> 8) |
- ((data & (0xffULL << 24)) >> 24);
-
- return swap;
-}
-
-static inline unsigned long long __data2host8(unsigned long long data)
-{
- unsigned long long swap;
-
- if (host_bigendian == file_bigendian)
- return data;
-
- swap = ((data & 0xffULL) << 56) |
- ((data & (0xffULL << 8)) << 40) |
- ((data & (0xffULL << 16)) << 24) |
- ((data & (0xffULL << 24)) << 8) |
- ((data & (0xffULL << 32)) >> 8) |
- ((data & (0xffULL << 40)) >> 24) |
- ((data & (0xffULL << 48)) >> 40) |
- ((data & (0xffULL << 56)) >> 56);
-
- return swap;
-}
+unsigned long long
+raw_field_value(struct event_format *event, const char *name, void *data);
+void *raw_field_ptr(struct event_format *event, const char *name, void *data);
-#define data2host2(ptr) __data2host2(*(unsigned short *)ptr)
-#define data2host4(ptr) __data2host4(*(unsigned int *)ptr)
-#define data2host8(ptr) ({ \
- unsigned long long __val; \
- \
- memcpy(&__val, (ptr), sizeof(unsigned long long)); \
- __data2host8(__val); \
-})
+void parse_proc_kallsyms(char *file, unsigned int size __unused);
+void parse_ftrace_printk(char *file, unsigned int size __unused);
-extern int header_page_ts_offset;
-extern int header_page_ts_size;
-extern int header_page_size_offset;
-extern int header_page_size_size;
-extern int header_page_data_offset;
-extern int header_page_data_size;
-
-extern bool latency_format;
+ssize_t trace_report(int fd, bool repipe);
int trace_parse_common_type(void *data);
int trace_parse_common_pid(void *data);
-int parse_common_pc(void *data);
-int parse_common_flags(void *data);
-int parse_common_lock_depth(void *data);
-struct event *trace_find_event(int id);
-struct event *trace_find_next_event(struct event *event);
+
+struct event_format *trace_find_next_event(struct event_format *event);
unsigned long long read_size(void *ptr, int size);
-unsigned long long
-raw_field_value(struct event *event, const char *name, void *data);
-void *raw_field_ptr(struct event *event, const char *name, void *data);
unsigned long long eval_flag(const char *flag);
+struct pevent_record *trace_read_data(int cpu);
int read_tracing_data(int fd, struct list_head *pattrs);
struct tracing_data {
@@ -280,15 +72,6 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
void tracing_data_put(struct tracing_data *tdata);
-/* taken from kernel/trace/trace.h */
-enum trace_flag_type {
- TRACE_FLAG_IRQS_OFF = 0x01,
- TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
- TRACE_FLAG_NEED_RESCHED = 0x04,
- TRACE_FLAG_HARDIRQ = 0x08,
- TRACE_FLAG_SOFTIRQ = 0x10,
-};
-
struct scripting_ops {
const char *name;
int (*start_script) (const char *script, int argc, const char **argv);
@@ -314,4 +97,4 @@ int common_pc(struct scripting_context *context);
int common_flags(struct scripting_context *context);
int common_lock_depth(struct scripting_context *context);
-#endif /* __PERF_TRACE_EVENTS_H */
+#endif /* _PERF_UTIL_TRACE_EVENT_H */
diff --git a/tools/perf/util/types.h b/tools/perf/util/types.h
index 5f3689a3d085..c51fa6b70a28 100644
--- a/tools/perf/util/types.h
+++ b/tools/perf/util/types.h
@@ -16,4 +16,9 @@ typedef signed short s16;
typedef unsigned char u8;
typedef signed char s8;
+union u64_swap {
+ u64 val64;
+ u32 val32[2];
+};
+
#endif /* __PERF_TYPES_H */
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c
deleted file mode 100644
index 57a4c6ef3fd2..000000000000
--- a/tools/perf/util/ui/browsers/annotate.c
+++ /dev/null
@@ -1,433 +0,0 @@
-#include "../../util.h"
-#include "../browser.h"
-#include "../helpline.h"
-#include "../libslang.h"
-#include "../ui.h"
-#include "../util.h"
-#include "../../annotate.h"
-#include "../../hist.h"
-#include "../../sort.h"
-#include "../../symbol.h"
-#include <pthread.h>
-#include <newt.h>
-
-struct annotate_browser {
- struct ui_browser b;
- struct rb_root entries;
- struct rb_node *curr_hot;
- struct objdump_line *selection;
- int nr_asm_entries;
- int nr_entries;
- bool hide_src_code;
-};
-
-struct objdump_line_rb_node {
- struct rb_node rb_node;
- double percent;
- u32 idx;
- int idx_asm;
-};
-
-static inline
-struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self)
-{
- return (struct objdump_line_rb_node *)(self + 1);
-}
-
-static bool objdump_line__filter(struct ui_browser *browser, void *entry)
-{
- struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
-
- if (ab->hide_src_code) {
- struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
- return ol->offset == -1;
- }
-
- return false;
-}
-
-static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
-{
- struct annotate_browser *ab = container_of(self, struct annotate_browser, b);
- struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
- bool current_entry = ui_browser__is_current_entry(self, row);
- int width = self->width;
-
- if (ol->offset != -1) {
- struct objdump_line_rb_node *olrb = objdump_line__rb(ol);
- ui_browser__set_percent_color(self, olrb->percent, current_entry);
- slsmg_printf(" %7.2f ", olrb->percent);
- } else {
- ui_browser__set_percent_color(self, 0, current_entry);
- slsmg_write_nstring(" ", 9);
- }
-
- SLsmg_write_char(':');
- slsmg_write_nstring(" ", 8);
-
- /* The scroll bar isn't being used */
- if (!self->navkeypressed)
- width += 1;
-
- if (!ab->hide_src_code && ol->offset != -1)
- if (!current_entry || (self->use_navkeypressed &&
- !self->navkeypressed))
- ui_browser__set_color(self, HE_COLORSET_CODE);
-
- if (!*ol->line)
- slsmg_write_nstring(" ", width - 18);
- else
- slsmg_write_nstring(ol->line, width - 18);
-
- if (current_entry)
- ab->selection = ol;
-}
-
-static double objdump_line__calc_percent(struct objdump_line *self,
- struct symbol *sym, int evidx)
-{
- double percent = 0.0;
-
- if (self->offset != -1) {
- int len = sym->end - sym->start;
- unsigned int hits = 0;
- struct annotation *notes = symbol__annotation(sym);
- struct source_line *src_line = notes->src->lines;
- struct sym_hist *h = annotation__histogram(notes, evidx);
- s64 offset = self->offset;
- struct objdump_line *next;
-
- next = objdump__get_next_ip_line(&notes->src->source, self);
- while (offset < (s64)len &&
- (next == NULL || offset < next->offset)) {
- if (src_line) {
- percent += src_line[offset].percent;
- } else
- hits += h->addr[offset];
-
- ++offset;
- }
- /*
- * If the percentage wasn't already calculated in
- * symbol__get_source_line, do it now:
- */
- if (src_line == NULL && h->sum)
- percent = 100.0 * hits / h->sum;
- }
-
- return percent;
-}
-
-static void objdump__insert_line(struct rb_root *self,
- struct objdump_line_rb_node *line)
-{
- struct rb_node **p = &self->rb_node;
- struct rb_node *parent = NULL;
- struct objdump_line_rb_node *l;
-
- while (*p != NULL) {
- parent = *p;
- l = rb_entry(parent, struct objdump_line_rb_node, rb_node);
- if (line->percent < l->percent)
- p = &(*p)->rb_left;
- else
- p = &(*p)->rb_right;
- }
- rb_link_node(&line->rb_node, parent, p);
- rb_insert_color(&line->rb_node, self);
-}
-
-static void annotate_browser__set_top(struct annotate_browser *self,
- struct rb_node *nd)
-{
- struct objdump_line_rb_node *rbpos;
- struct objdump_line *pos;
- unsigned back;
-
- ui_browser__refresh_dimensions(&self->b);
- back = self->b.height / 2;
- rbpos = rb_entry(nd, struct objdump_line_rb_node, rb_node);
- pos = ((struct objdump_line *)rbpos) - 1;
- self->b.top_idx = self->b.index = rbpos->idx;
-
- while (self->b.top_idx != 0 && back != 0) {
- pos = list_entry(pos->node.prev, struct objdump_line, node);
-
- --self->b.top_idx;
- --back;
- }
-
- self->b.top = pos;
- self->curr_hot = nd;
-}
-
-static void annotate_browser__calc_percent(struct annotate_browser *browser,
- int evidx)
-{
- struct map_symbol *ms = browser->b.priv;
- struct symbol *sym = ms->sym;
- struct annotation *notes = symbol__annotation(sym);
- struct objdump_line *pos;
-
- browser->entries = RB_ROOT;
-
- pthread_mutex_lock(&notes->lock);
-
- list_for_each_entry(pos, &notes->src->source, node) {
- struct objdump_line_rb_node *rbpos = objdump_line__rb(pos);
- rbpos->percent = objdump_line__calc_percent(pos, sym, evidx);
- if (rbpos->percent < 0.01) {
- RB_CLEAR_NODE(&rbpos->rb_node);
- continue;
- }
- objdump__insert_line(&browser->entries, rbpos);
- }
- pthread_mutex_unlock(&notes->lock);
-
- browser->curr_hot = rb_last(&browser->entries);
-}
-
-static bool annotate_browser__toggle_source(struct annotate_browser *browser)
-{
- struct objdump_line *ol;
- struct objdump_line_rb_node *olrb;
- off_t offset = browser->b.index - browser->b.top_idx;
-
- browser->b.seek(&browser->b, offset, SEEK_CUR);
- ol = list_entry(browser->b.top, struct objdump_line, node);
- olrb = objdump_line__rb(ol);
-
- if (browser->hide_src_code) {
- if (olrb->idx_asm < offset)
- offset = olrb->idx;
-
- browser->b.nr_entries = browser->nr_entries;
- browser->hide_src_code = false;
- browser->b.seek(&browser->b, -offset, SEEK_CUR);
- browser->b.top_idx = olrb->idx - offset;
- browser->b.index = olrb->idx;
- } else {
- if (olrb->idx_asm < 0) {
- ui_helpline__puts("Only available for assembly lines.");
- browser->b.seek(&browser->b, -offset, SEEK_CUR);
- return false;
- }
-
- if (olrb->idx_asm < offset)
- offset = olrb->idx_asm;
-
- browser->b.nr_entries = browser->nr_asm_entries;
- browser->hide_src_code = true;
- browser->b.seek(&browser->b, -offset, SEEK_CUR);
- browser->b.top_idx = olrb->idx_asm - offset;
- browser->b.index = olrb->idx_asm;
- }
-
- return true;
-}
-
-static int annotate_browser__run(struct annotate_browser *self, int evidx,
- void(*timer)(void *arg),
- void *arg, int delay_secs)
-{
- struct rb_node *nd = NULL;
- struct map_symbol *ms = self->b.priv;
- struct symbol *sym = ms->sym;
- const char *help = "<-/ESC: Exit, TAB/shift+TAB: Cycle hot lines, "
- "H: Go to hottest line, ->/ENTER: Line action, "
- "S: Toggle source code view";
- int key;
-
- if (ui_browser__show(&self->b, sym->name, help) < 0)
- return -1;
-
- annotate_browser__calc_percent(self, evidx);
-
- if (self->curr_hot)
- annotate_browser__set_top(self, self->curr_hot);
-
- nd = self->curr_hot;
-
- while (1) {
- key = ui_browser__run(&self->b, delay_secs);
-
- if (delay_secs != 0) {
- annotate_browser__calc_percent(self, evidx);
- /*
- * Current line focus got out of the list of most active
- * lines, NULL it so that if TAB|UNTAB is pressed, we
- * move to curr_hot (current hottest line).
- */
- if (nd != NULL && RB_EMPTY_NODE(nd))
- nd = NULL;
- }
-
- switch (key) {
- case K_TIMER:
- if (timer != NULL)
- timer(arg);
-
- if (delay_secs != 0)
- symbol__annotate_decay_histogram(sym, evidx);
- continue;
- case K_TAB:
- if (nd != NULL) {
- nd = rb_prev(nd);
- if (nd == NULL)
- nd = rb_last(&self->entries);
- } else
- nd = self->curr_hot;
- break;
- case K_UNTAB:
- if (nd != NULL)
- nd = rb_next(nd);
- if (nd == NULL)
- nd = rb_first(&self->entries);
- else
- nd = self->curr_hot;
- break;
- case 'H':
- case 'h':
- nd = self->curr_hot;
- break;
- case 'S':
- case 's':
- if (annotate_browser__toggle_source(self))
- ui_helpline__puts(help);
- continue;
- case K_ENTER:
- case K_RIGHT:
- if (self->selection == NULL) {
- ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
- continue;
- }
-
- if (self->selection->offset == -1) {
- ui_helpline__puts("Actions are only available for assembly lines.");
- continue;
- } else {
- char *s = strstr(self->selection->line, "callq ");
- struct annotation *notes;
- struct symbol *target;
- u64 ip;
-
- if (s == NULL) {
- ui_helpline__puts("Actions are only available for the 'callq' instruction.");
- continue;
- }
-
- s = strchr(s, ' ');
- if (s++ == NULL) {
- ui_helpline__puts("Invallid callq instruction.");
- continue;
- }
-
- ip = strtoull(s, NULL, 16);
- ip = ms->map->map_ip(ms->map, ip);
- target = map__find_symbol(ms->map, ip, NULL);
- if (target == NULL) {
- ui_helpline__puts("The called function was not found.");
- continue;
- }
-
- notes = symbol__annotation(target);
- pthread_mutex_lock(&notes->lock);
-
- if (notes->src == NULL && symbol__alloc_hist(target) < 0) {
- pthread_mutex_unlock(&notes->lock);
- ui__warning("Not enough memory for annotating '%s' symbol!\n",
- target->name);
- continue;
- }
-
- pthread_mutex_unlock(&notes->lock);
- symbol__tui_annotate(target, ms->map, evidx,
- timer, arg, delay_secs);
- ui_browser__show_title(&self->b, sym->name);
- }
- continue;
- case K_LEFT:
- case K_ESC:
- case 'q':
- case CTRL('c'):
- goto out;
- default:
- continue;
- }
-
- if (nd != NULL)
- annotate_browser__set_top(self, nd);
- }
-out:
- ui_browser__hide(&self->b);
- return key;
-}
-
-int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
- void(*timer)(void *arg), void *arg, int delay_secs)
-{
- return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx,
- timer, arg, delay_secs);
-}
-
-int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
- void(*timer)(void *arg), void *arg,
- int delay_secs)
-{
- struct objdump_line *pos, *n;
- struct annotation *notes;
- struct map_symbol ms = {
- .map = map,
- .sym = sym,
- };
- struct annotate_browser browser = {
- .b = {
- .refresh = ui_browser__list_head_refresh,
- .seek = ui_browser__list_head_seek,
- .write = annotate_browser__write,
- .filter = objdump_line__filter,
- .priv = &ms,
- .use_navkeypressed = true,
- },
- };
- int ret;
-
- if (sym == NULL)
- return -1;
-
- if (map->dso->annotate_warned)
- return -1;
-
- if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) {
- ui__error("%s", ui_helpline__last_msg);
- return -1;
- }
-
- ui_helpline__push("Press <- or ESC to exit");
-
- notes = symbol__annotation(sym);
-
- list_for_each_entry(pos, &notes->src->source, node) {
- struct objdump_line_rb_node *rbpos;
- size_t line_len = strlen(pos->line);
-
- if (browser.b.width < line_len)
- browser.b.width = line_len;
- rbpos = objdump_line__rb(pos);
- rbpos->idx = browser.nr_entries++;
- if (pos->offset != -1)
- rbpos->idx_asm = browser.nr_asm_entries++;
- else
- rbpos->idx_asm = -1;
- }
-
- browser.b.nr_entries = browser.nr_entries;
- browser.b.entries = &notes->src->source,
- browser.b.width += 18; /* Percentage */
- ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
- list_for_each_entry_safe(pos, n, &notes->src->source, node) {
- list_del(&pos->node);
- objdump_line__free(pos);
- }
- return ret;
-}
diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c
index 52bb07c6442a..4007aca8e0ca 100644
--- a/tools/perf/util/usage.c
+++ b/tools/perf/util/usage.c
@@ -82,41 +82,3 @@ void warning(const char *warn, ...)
warn_routine(warn, params);
va_end(params);
}
-
-uid_t parse_target_uid(const char *str, const char *tid, const char *pid)
-{
- struct passwd pwd, *result;
- char buf[1024];
-
- if (str == NULL)
- return UINT_MAX;
-
- /* UID and PID are mutually exclusive */
- if (tid || pid) {
- ui__warning("PID/TID switch overriding UID\n");
- sleep(1);
- return UINT_MAX;
- }
-
- getpwnam_r(str, &pwd, buf, sizeof(buf), &result);
-
- if (result == NULL) {
- char *endptr;
- int uid = strtol(str, &endptr, 10);
-
- if (*endptr != '\0') {
- ui__error("Invalid user %s\n", str);
- return UINT_MAX - 1;
- }
-
- getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
-
- if (result == NULL) {
- ui__error("Problems obtaining information for user %s\n",
- str);
- return UINT_MAX - 1;
- }
- }
-
- return result->pw_uid;
-}
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 8109a907841e..d03599fbe78b 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -148,3 +148,13 @@ int readn(int fd, void *buf, size_t n)
return buf - buf_start;
}
+
+size_t hex_width(u64 v)
+{
+ size_t n = 1;
+
+ while ((v >>= 4))
+ ++n;
+
+ return n;
+}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 0f99f394d8e0..2daaedb83d84 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -74,7 +74,6 @@
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
-#include <pwd.h>
#include <inttypes.h>
#include "../../../include/linux/magic.h"
#include "types.h"
@@ -249,8 +248,6 @@ struct perf_event_attr;
void event_attr_init(struct perf_event_attr *attr);
-uid_t parse_target_uid(const char *str, const char *tid, const char *pid);
-
#define _STR(x) #x
#define STR(x) _STR(x)
@@ -265,4 +262,6 @@ bool is_power_of_2(unsigned long n)
return (n != 0 && ((n & (n - 1)) == 0));
}
+size_t hex_width(u64 v);
+
#endif
diff --git a/tools/power/cpupower/man/cpupower-set.1 b/tools/power/cpupower/man/cpupower-set.1
index c4954a9fe4e7..9dbd536518ab 100644
--- a/tools/power/cpupower/man/cpupower-set.1
+++ b/tools/power/cpupower/man/cpupower-set.1
@@ -85,15 +85,6 @@ Possible values are:
savings
.RE
-sched_mc_power_savings is dependent upon SCHED_MC, which is
-itself architecture dependent.
-
-sched_smt_power_savings is dependent upon SCHED_SMT, which
-is itself architecture dependent.
-
-The two files are independent of each other. It is possible
-that one file may be present without the other.
-
.SH "SEE ALSO"
cpupower-info(1), cpupower-monitor(1), powertop(1)
.PP
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c
index c6343024a611..96e28c124b5c 100644
--- a/tools/power/cpupower/utils/helpers/sysfs.c
+++ b/tools/power/cpupower/utils/helpers/sysfs.c
@@ -362,22 +362,7 @@ char *sysfs_get_cpuidle_driver(void)
*/
int sysfs_get_sched(const char *smt_mc)
{
- unsigned long value;
- char linebuf[MAX_LINE_LEN];
- char *endp;
- char path[SYSFS_PATH_MAX];
-
- if (strcmp("mc", smt_mc) && strcmp("smt", smt_mc))
- return -EINVAL;
-
- snprintf(path, sizeof(path),
- PATH_TO_CPU "sched_%s_power_savings", smt_mc);
- if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0)
- return -1;
- value = strtoul(linebuf, &endp, 0);
- if (endp == linebuf || errno == ERANGE)
- return -1;
- return value;
+ return -ENODEV;
}
/*
@@ -388,21 +373,5 @@ int sysfs_get_sched(const char *smt_mc)
*/
int sysfs_set_sched(const char *smt_mc, int val)
{
- char linebuf[MAX_LINE_LEN];
- char path[SYSFS_PATH_MAX];
- struct stat statbuf;
-
- if (strcmp("mc", smt_mc) && strcmp("smt", smt_mc))
- return -EINVAL;
-
- snprintf(path, sizeof(path),
- PATH_TO_CPU "sched_%s_power_savings", smt_mc);
- sprintf(linebuf, "%d", val);
-
- if (stat(path, &statbuf) != 0)
- return -ENODEV;
-
- if (sysfs_write_file(path, linebuf, MAX_LINE_LEN) == 0)
- return -1;
- return 0;
+ return -ENODEV;
}
diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include
new file mode 100644
index 000000000000..bde8521d56bb
--- /dev/null
+++ b/tools/scripts/Makefile.include
@@ -0,0 +1,58 @@
+ifeq ("$(origin O)", "command line")
+ OUTPUT := $(O)/
+ COMMAND_O := O=$(O)
+endif
+
+ifneq ($(OUTPUT),)
+# check that the output directory actually exists
+OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
+$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
+endif
+
+#
+# Include saner warnings here, which can catch bugs:
+#
+EXTRA_WARNINGS := -Wbad-function-cast
+EXTRA_WARNINGS += -Wdeclaration-after-statement
+EXTRA_WARNINGS += -Wformat-security
+EXTRA_WARNINGS += -Wformat-y2k
+EXTRA_WARNINGS += -Winit-self
+EXTRA_WARNINGS += -Wmissing-declarations
+EXTRA_WARNINGS += -Wmissing-prototypes
+EXTRA_WARNINGS += -Wnested-externs
+EXTRA_WARNINGS += -Wno-system-headers
+EXTRA_WARNINGS += -Wold-style-definition
+EXTRA_WARNINGS += -Wpacked
+EXTRA_WARNINGS += -Wredundant-decls
+EXTRA_WARNINGS += -Wshadow
+EXTRA_WARNINGS += -Wstrict-aliasing=3
+EXTRA_WARNINGS += -Wstrict-prototypes
+EXTRA_WARNINGS += -Wswitch-default
+EXTRA_WARNINGS += -Wswitch-enum
+EXTRA_WARNINGS += -Wundef
+EXTRA_WARNINGS += -Wwrite-strings
+EXTRA_WARNINGS += -Wformat
+
+ifneq ($(findstring $(MAKEFLAGS), w),w)
+PRINT_DIR = --no-print-directory
+else
+NO_SUBDIR = :
+endif
+
+QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
+QUIET_SUBDIR1 =
+
+ifneq ($(findstring $(MAKEFLAGS),s),s)
+ifndef V
+ QUIET_CC = @echo ' ' CC $@;
+ QUIET_AR = @echo ' ' AR $@;
+ QUIET_LINK = @echo ' ' LINK $@;
+ QUIET_MKDIR = @echo ' ' MKDIR $@;
+ QUIET_GEN = @echo ' ' GEN $@;
+ QUIET_SUBDIR0 = +@subdir=
+ QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \
+ $(MAKE) $(PRINT_DIR) -C $$subdir
+ QUIET_FLEX = @echo ' ' FLEX $@;
+ QUIET_BISON = @echo ' ' BISON $@;
+endif
+endif
diff --git a/tools/testing/ktest/examples/README b/tools/testing/ktest/examples/README
new file mode 100644
index 000000000000..a12d295a09d8
--- /dev/null
+++ b/tools/testing/ktest/examples/README
@@ -0,0 +1,32 @@
+This directory contains example configs to use ktest for various tasks.
+The configs still need to be customized for your environment, but it
+is broken up by task which makes it easier to understand how to set up
+ktest.
+
+The configs are based off of real working configs but have been modified
+and commented to show more generic use cases that are more helpful for
+developers.
+
+crosstests.conf - this config shows an example of testing a git repo against
+ lots of different architectures. It only does build tests, but makes
+ it easy to compile test different archs. You can download the arch
+ cross compilers from:
+ http://kernel.org/pub/tools/crosstool/files/bin/x86_64/
+
+test.conf - A generic example of a config. This is based on an actual config
+ used to perform real testing.
+
+kvm.conf - A example of a config that is used to test a virtual guest running
+ on a host.
+
+snowball.conf - An example config that was used to demo ktest.pl against
+ a snowball ARM board.
+
+include/ - The include directory holds default configs that can be
+ included into other configs. This is a real use example that shows how
+ to reuse configs for various machines or set ups. The files here
+ are included by other config files, where the other config files define
+ options and variables that will make the included config work for the
+ given environment.
+
+
diff --git a/tools/testing/ktest/examples/crosstests.conf b/tools/testing/ktest/examples/crosstests.conf
new file mode 100644
index 000000000000..46736604c26c
--- /dev/null
+++ b/tools/testing/ktest/examples/crosstests.conf
@@ -0,0 +1,260 @@
+#
+# Example config for cross compiling
+#
+# In this config, it is expected that the tool chains from:
+#
+# http://kernel.org/pub/tools/crosstool/files/bin/x86_64/
+#
+# running on a x86_64 system have been downloaded and installed into:
+#
+# /usr/local/
+#
+# such that the compiler binaries are something like:
+#
+# /usr/local/gcc-4.5.2-nolibc/mips-linux/bin/mips-linux-gcc
+#
+# Some of the archs will use gcc-4.5.1 instead of gcc-4.5.2
+# this config uses variables to differentiate them.
+#
+# Comments describe some of the options, but full descriptions of
+# options are described in the samples.conf file.
+
+# ${PWD} is defined by ktest.pl to be the directory that the user
+# was in when they executed ktest.pl. It may be better to hardcode the
+# path name here. THIS_DIR is the variable used through out the config file
+# in case you want to change it.
+
+THIS_DIR := ${PWD}
+
+# Update the BUILD_DIR option to the location of your git repo you want to test.
+BUILD_DIR = ${THIS_DIR}/linux.git
+
+# The build will go into this directory. It will be created when you run the test.
+OUTPUT_DIR = ${THIS_DIR}/cross-compile
+
+# The build will be compiled with -j8
+BUILD_OPTIONS = -j8
+
+# The test will not stop when it hits a failure.
+DIE_ON_FAILURE = 0
+
+# If you want to have ktest.pl store the failure somewhere, uncomment this option
+# and change the directory where ktest should store the failures.
+#STORE_FAILURES = ${THIS_DIR}/failures
+
+# The log file is stored in the OUTPUT_DIR called cross.log
+# If you enable this, you need to create the OUTPUT_DIR. It wont be created for you.
+LOG_FILE = ${OUTPUT_DIR}/cross.log
+
+# The log file will be cleared each time you run ktest.
+CLEAR_LOG = 1
+
+# As some archs do not build with the defconfig, they have been marked
+# to be ignored. If you want to test them anyway, change DO_FAILED to 1.
+# If a test that has been marked as DO_FAILED passes, then you should change
+# that test to be DO_DEFAULT
+
+DO_FAILED := 0
+DO_DEFAULT := 1
+
+# By setting both DO_FAILED and DO_DEFAULT to zero, you can pick a single
+# arch that you want to test. (uncomment RUN and chose your arch)
+#RUN := m32r
+
+# At the bottom of the config file exists a bisect test. You can update that
+# test and set DO_FAILED and DO_DEFAULT to zero, and uncomment this variable
+# to run the bisect on the arch.
+#RUN := bisect
+
+# By default all tests will be running gcc 4.5.2. Some tests are using 4.5.1
+# and they select that in the test.
+# Note: GCC_VER is declared as on option and not a variable ('=' instead of ':=')
+# This is important. A variable is used only in the config file and if it is set
+# it stays that way for the rest of the config file until it is change again.
+# Here we want GCC_VER to remain persistent and change for each test, as it is used in
+# the MAKE_CMD. By using '=' instead of ':=' we achieve our goal.
+
+GCC_VER = 4.5.2
+MAKE_CMD = PATH=/usr/local/gcc-${GCC_VER}-nolibc/${CROSS}/bin:$PATH CROSS_COMPILE=${CROSS}- make ARCH=${ARCH}
+
+# all tests are only doing builds.
+TEST_TYPE = build
+
+# If you want to add configs on top of the defconfig, you can add those configs into
+# the add-config file and uncomment this option. This is useful if you want to test
+# all cross compiles with PREEMPT set, or TRACING on, etc.
+#ADD_CONFIG = ${THIS_DIR}/add-config
+
+# All tests are using defconfig
+BUILD_TYPE = defconfig
+
+# The test names will have the arch and cross compiler used. This will be shown in
+# the results.
+TEST_NAME = ${ARCH} ${CROSS}
+
+# alpha
+TEST_START IF ${RUN} == alpha || ${DO_DEFAULT}
+# Notice that CROSS and ARCH are also options and not variables (again '=' instead
+# of ':='). This is because TEST_NAME and MAKE_CMD wil use them for each test.
+# Only options are available during runs. Variables are only present in parsing the
+# config file.
+CROSS = alpha-linux
+ARCH = alpha
+
+# arm
+TEST_START IF ${RUN} == arm || ${DO_DEFAULT}
+CROSS = arm-unknown-linux-gnueabi
+ARCH = arm
+
+# black fin
+TEST_START IF ${RUN} == bfin || ${DO_DEFAULT}
+CROSS = bfin-uclinux
+ARCH = blackfin
+BUILD_OPTIONS = -j8 vmlinux
+
+# cris - FAILS?
+TEST_START IF ${RUN} == cris || ${RUN} == cris64 || ${DO_FAILED}
+CROSS = cris-linux
+ARCH = cris
+
+# cris32 - not right arch?
+TEST_START IF ${RUN} == cris || ${RUN} == cris32 || ${DO_FAILED}
+CROSS = crisv32-linux
+ARCH = cris
+
+# ia64
+TEST_START IF ${RUN} == ia64 || ${DO_DEFAULT}
+CROSS = ia64-linux
+ARCH = ia64
+
+# frv
+TEST_START IF ${RUN} == frv || ${DO_FAILED}
+CROSS = frv-linux
+ARCH = frv
+GCC_VER = 4.5.1
+
+# h8300 - failed make defconfig??
+TEST_START IF ${RUN} == h8300 || ${DO_FAILED}
+CROSS = h8300-elf
+ARCH = h8300
+GCC_VER = 4.5.1
+
+# m68k fails with error?
+TEST_START IF ${RUN} == m68k || ${DO_DEFAULT}
+CROSS = m68k-linux
+ARCH = m68k
+
+# mips64
+TEST_START IF ${RUN} == mips || ${RUN} == mips64 || ${DO_DEFAULT}
+CROSS = mips64-linux
+ARCH = mips
+
+# mips32
+TEST_START IF ${RUN} == mips || ${RUN} == mips32 || ${DO_DEFAULT}
+CROSS = mips-linux
+ARCH = mips
+
+# m32r
+TEST_START IF ${RUN} == m32r || ${DO_FAILED}
+CROSS = m32r-linux
+ARCH = m32r
+GCC_VER = 4.5.1
+BUILD_OPTIONS = -j8 vmlinux
+
+# parisc64 failed?
+TEST_START IF ${RUN} == hppa || ${RUN} == hppa64 || ${DO_FAILED}
+CROSS = hppa64-linux
+ARCH = parisc
+
+# parisc
+TEST_START IF ${RUN} == hppa || ${RUN} == hppa32 || ${DO_FAILED}
+CROSS = hppa-linux
+ARCH = parisc
+
+# ppc
+TEST_START IF ${RUN} == ppc || ${RUN} == ppc32 || ${DO_DEFAULT}
+CROSS = powerpc-linux
+ARCH = powerpc
+
+# ppc64
+TEST_START IF ${RUN} == ppc || ${RUN} == ppc64 || ${DO_DEFAULT}
+CROSS = powerpc64-linux
+ARCH = powerpc
+
+# s390
+TEST_START IF ${RUN} == s390 || ${DO_DEFAULT}
+CROSS = s390x-linux
+ARCH = s390
+
+# sh
+TEST_START IF ${RUN} == sh || ${DO_DEFAULT}
+CROSS = sh4-linux
+ARCH = sh
+
+# sparc64
+TEST_START IF ${RUN} == sparc || ${RUN} == sparc64 || ${DO_DEFAULT}
+CROSS = sparc64-linux
+ARCH = sparc64
+
+# sparc
+TEST_START IF ${RUN} == sparc || ${RUN} == sparc32 || ${DO_DEFAULT}
+CROSS = sparc-linux
+ARCH = sparc
+
+# xtensa failed
+TEST_START IF ${RUN} == xtensa || ${DO_FAILED}
+CROSS = xtensa-linux
+ARCH = xtensa
+
+# UML
+TEST_START IF ${RUN} == uml || ${DO_DEFAULT}
+MAKE_CMD = make ARCH=um SUBARCH=x86_64
+ARCH = uml
+CROSS =
+
+TEST_START IF ${RUN} == x86 || ${RUN} == i386 || ${DO_DEFAULT}
+MAKE_CMD = make ARCH=i386
+ARCH = i386
+CROSS =
+
+TEST_START IF ${RUN} == x86 || ${RUN} == x86_64 || ${DO_DEFAULT}
+MAKE_CMD = make ARCH=x86_64
+ARCH = x86_64
+CROSS =
+
+#################################
+
+# This is a bisect if needed. You need to give it a MIN_CONFIG that
+# will be the config file it uses. Basically, just copy the created defconfig
+# for the arch someplace and point MIN_CONFIG to it.
+TEST_START IF ${RUN} == bisect
+MIN_CONFIG = ${THIS_DIR}/min-config
+CROSS = s390x-linux
+ARCH = s390
+TEST_TYPE = bisect
+BISECT_TYPE = build
+BISECT_GOOD = v3.1
+BISECT_BAD = v3.2
+CHECKOUT = v3.2
+
+#################################
+
+# These defaults are needed to keep ktest.pl from complaining. They are
+# ignored because the test does not go pass the build. No install or
+# booting of the target images.
+
+DEFAULTS
+MACHINE = crosstest
+SSH_USER = root
+BUILD_TARGET = cross
+TARGET_IMAGE = image
+POWER_CYCLE = cycle
+CONSOLE = console
+LOCALVERSION = version
+GRUB_MENU = grub
+
+REBOOT_ON_ERROR = 0
+POWEROFF_ON_ERROR = 0
+POWEROFF_ON_SUCCESS = 0
+REBOOT_ON_SUCCESS = 0
+
diff --git a/tools/testing/ktest/examples/include/bisect.conf b/tools/testing/ktest/examples/include/bisect.conf
new file mode 100644
index 000000000000..009bea65bfb6
--- /dev/null
+++ b/tools/testing/ktest/examples/include/bisect.conf
@@ -0,0 +1,90 @@
+#
+# This example shows the bisect tests (git bisect and config bisect)
+#
+
+
+# The config that includes this file may define a RUN_TEST
+# variable that will tell this config what test to run.
+# (what to set the TEST option to).
+#
+DEFAULTS IF NOT DEFINED RUN_TEST
+# Requires that hackbench is in the PATH
+RUN_TEST := ${SSH} hackbench 50
+
+
+# Set TEST to 'bisect' to do a normal git bisect. You need
+# to modify the options below to make it bisect the exact
+# commits you are interested in.
+#
+TEST_START IF ${TEST} == bisect
+TEST_TYPE = bisect
+# You must set the commit that was considered good (git bisect good)
+BISECT_GOOD = v3.3
+# You must set the commit that was considered bad (git bisect bad)
+BISECT_BAD = HEAD
+# It's best to specify the branch to checkout before starting the bisect.
+CHECKOUT = origin/master
+# This can be build, boot, or test. Here we are doing a bisect
+# that requires to run a test to know if the bisect was good or bad.
+# The test should exit with 0 on good, non-zero for bad. But see
+# the BISECT_RET_* options in samples.conf to override this.
+BISECT_TYPE = test
+TEST = ${RUN_TEST}
+# It is usually a good idea to confirm that the GOOD and the BAD
+# commits are truly good and bad respectively. Having BISECT_CHECK
+# set to 1 will check both that the good commit works and the bad
+# commit fails. If you only want to check one or the other,
+# set BISECT_CHECK to 'good' or to 'bad'.
+BISECT_CHECK = 1
+#BISECT_CHECK = good
+#BISECT_CHECK = bad
+
+# Usually it's a good idea to specify the exact config you
+# want to use throughout the entire bisect. Here we placed
+# it in the directory we called ktest.pl from and named it
+# 'config-bisect'.
+MIN_CONFIG = ${THIS_DIR}/config-bisect
+# By default, if we are doing a BISECT_TYPE = test run but the
+# build or boot fails, ktest.pl will do a 'git bisect skip'.
+# Uncomment the below option to make ktest stop testing on such
+# an error.
+#BISECT_SKIP = 0
+# Now if you had BISECT_SKIP = 0 and the test fails, you can
+# examine what happened and then do 'git bisect log > /tmp/replay'
+# Set BISECT_REPLAY to /tmp/replay and ktest.pl will run the
+# 'git bisect replay /tmp/replay' before continuing the bisect test.
+#BISECT_REPLAY = /tmp/replay
+# If you used BISECT_REPLAY after the bisect test failed, you may
+# not want to continue the bisect on that commit that failed.
+# By setting BISECT_START to a new commit. ktest.pl will checkout
+# that commit after it has performed the 'git bisect replay' but
+# before it continues running the bisect test.
+#BISECT_START = 2545eb6198e7e1ec50daa0cfc64a4cdfecf24ec9
+
+# Now if you don't trust ktest.pl to make the decisions for you, then
+# set BISECT_MANUAL to 1. This will cause ktest.pl not to decide
+# if the commit was good or bad. Instead, it will ask you to tell
+# it if the current commit was good. In the mean time, you could
+# take the result, load it on any machine you want. Run several tests,
+# or whatever you feel like. Then, when you are happy, you can tell
+# ktest if you think it was good or not and ktest.pl will continue
+# the git bisect. You can even change what commit it is currently at.
+#BISECT_MANUAL = 1
+
+
+# One of the unique tests that ktest does is the config bisect.
+# Currently (which hopefully will be fixed soon), the bad config
+# must be a superset of the good config. This is because it only
+# searches for a config that causes the target to fail. If the
+# good config is not a subset of the bad config, or if the target
+# fails because of a lack of a config, then it will not find
+# the config for you.
+TEST_START IF ${TEST} == config-bisect
+TEST_TYPE = config_bisect
+# set to build, boot, test
+CONFIG_BISECT_TYPE = boot
+# Set the config that is considered bad.
+CONFIG_BISECT = ${THIS_DIR}/config-bad
+# This config is optional. By default it uses the
+# MIN_CONFIG as the good config.
+CONFIG_BISECT_GOOD = ${THIS_DIR}/config-good
diff --git a/tools/testing/ktest/examples/include/defaults.conf b/tools/testing/ktest/examples/include/defaults.conf
new file mode 100644
index 000000000000..323a552ce642
--- /dev/null
+++ b/tools/testing/ktest/examples/include/defaults.conf
@@ -0,0 +1,157 @@
+# This file holds defaults for most the tests. It defines the options that
+# are most common to tests that are likely to be shared.
+#
+# Note, after including this file, a config file may override any option
+# with a DEFAULTS OVERRIDE section.
+#
+
+# For those cases that use the same machine to boot a 64 bit
+# and a 32 bit version. The MACHINE is the DNS name to get to the
+# box (usually different if it was 64 bit or 32 bit) but the
+# BOX here is defined as a variable that will be the name of the box
+# itself. It is useful for calling scripts that will power cycle
+# the box, as only one script needs to be created to power cycle
+# even though the box itself has multiple operating systems on it.
+# By default, BOX and MACHINE are the same.
+
+DEFAULTS IF NOT DEFINED BOX
+BOX := ${MACHINE}
+
+
+# Consider each box as 64 bit box, unless the config including this file
+# has defined BITS = 32
+
+DEFAULTS IF NOT DEFINED BITS
+BITS := 64
+
+
+DEFAULTS
+
+# THIS_DIR is used through out the configs and defaults to ${PWD} which
+# is the directory that ktest.pl was called from.
+
+THIS_DIR := ${PWD}
+
+
+# to orginize your configs, having each machine save their configs
+# into a separate directly is useful.
+CONFIG_DIR := ${THIS_DIR}/configs/${MACHINE}
+
+# Reset the log before running each test.
+CLEAR_LOG = 1
+
+# As installing kernels usually requires root privilege, default the
+# user on the target as root. It is also required that the target
+# allows ssh to root from the host without asking for a password.
+
+SSH_USER = root
+
+# For accesing the machine, we will ssh to root@machine.
+SSH := ssh ${SSH_USER}@${MACHINE}
+
+# Update this. The default here is ktest will ssh to the target box
+# and run a script called 'run-test' located on that box.
+TEST = ${SSH} run-test
+
+# Point build dir to the git repo you use
+BUILD_DIR = ${THIS_DIR}/linux.git
+
+# Each machine will have its own output build directory.
+OUTPUT_DIR = ${THIS_DIR}/build/${MACHINE}
+
+# Yes this config is focused on x86 (but ktest works for other archs too)
+BUILD_TARGET = arch/x86/boot/bzImage
+TARGET_IMAGE = /boot/vmlinuz-test
+
+# have directory for the scripts to reboot and power cycle the boxes
+SCRIPTS_DIR := ${THIS_DIR}/scripts
+
+# You can have each box/machine have a script to power cycle it.
+# Name your script <box>-cycle.
+POWER_CYCLE = ${SCRIPTS_DIR}/${BOX}-cycle
+
+# This script is used to power off the box.
+POWER_OFF = ${SCRIPTS_DIR}/${BOX}-poweroff
+
+# Keep your test kernels separate from your other kernels.
+LOCALVERSION = -test
+
+# The /boot/grub/menu.lst is searched for the line:
+# title Test Kernel
+# and ktest will use that kernel to reboot into.
+# For grub2 or other boot loaders, you need to set BOOT_TYPE
+# to 'script' and define other ways to load the kernel.
+# See snowball.conf example.
+#
+GRUB_MENU = Test Kernel
+
+# The kernel build will use this option.
+BUILD_OPTIONS = -j8
+
+# Keeping the log file with the output dir is convenient.
+LOG_FILE = ${OUTPUT_DIR}/${MACHINE}.log
+
+# Each box should have their own minum configuration
+# See min-config.conf
+MIN_CONFIG = ${CONFIG_DIR}/config-min
+
+# For things like randconfigs, there may be configs you find that
+# are already broken, or there may be some configs that you always
+# want set. Uncomment ADD_CONFIG and point it to the make config files
+# that set the configs you want to keep on (or off) in your build.
+# ADD_CONFIG is usually something to add configs to all machines,
+# where as, MIN_CONFIG is specific per machine.
+#ADD_CONFIG = ${THIS_DIR}/config-broken ${THIS_DIR}/config-general
+
+# To speed up reboots for bisects and patchcheck, instead of
+# waiting 60 seconds for the console to be idle, if this line is
+# seen in the console output, ktest will know the good kernel has
+# finished rebooting and it will be able to continue the tests.
+REBOOT_SUCCESS_LINE = ${MACHINE} login:
+
+# The following is different ways to end the test.
+# by setting the variable REBOOT to: none, error, fail or
+# something else, ktest will power cycle or reboot the target box
+# at the end of the tests.
+#
+# REBOOT := none
+# Don't do anything at the end of the test.
+#
+# REBOOT := error
+# Reboot the box if ktest detects an error
+#
+# REBOOT := fail
+# Do not stop on failure, and after all tests are complete
+# power off the box (for both success and error)
+# This is good to run over a weekend and you don't want to waste
+# electricity.
+#
+
+DEFAULTS IF ${REBOOT} == none
+REBOOT_ON_SUCCESS = 0
+REBOOT_ON_ERROR = 0
+POWEROFF_ON_ERROR = 0
+POWEROFF_ON_SUCCESS = 0
+
+DEFAULTS ELSE IF ${REBOOT} == error
+REBOOT_ON_SUCCESS = 0
+REBOOT_ON_ERROR = 1
+POWEROFF_ON_ERROR = 0
+POWEROFF_ON_SUCCESS = 0
+
+DEFAULTS ELSE IF ${REBOOT} == fail
+REBOOT_ON_SUCCESS = 0
+POWEROFF_ON_ERROR = 1
+POWEROFF_ON_SUCCESS = 1
+POWEROFF_AFTER_HALT = 120
+DIE_ON_FAILURE = 0
+
+# Store the failure information into this directory
+# such as the .config, dmesg, and build log.
+STORE_FAILURES = ${THIS_DIR}/failures
+
+DEFAULTS ELSE
+REBOOT_ON_SUCCESS = 1
+REBOOT_ON_ERROR = 1
+POWEROFF_ON_ERROR = 0
+POWEROFF_ON_SUCCESS = 0
diff --git a/tools/testing/ktest/examples/include/min-config.conf b/tools/testing/ktest/examples/include/min-config.conf
new file mode 100644
index 000000000000..c703cc46d151
--- /dev/null
+++ b/tools/testing/ktest/examples/include/min-config.conf
@@ -0,0 +1,60 @@
+#
+# This file has some examples for creating a MIN_CONFIG.
+# (A .config file that is the minimum for a machine to boot, or
+# to boot and make a network connection.)
+#
+# A MIN_CONFIG is very useful as it is the minimum configuration
+# needed to boot a given machine. You can debug someone else's
+# .config by only setting the configs in your MIN_CONFIG. The closer
+# your MIN_CONFIG is to the true minimum set of configs needed to
+# boot your machine, the closer the config you test with will be
+# to the users config that had the failure.
+#
+# The make_min_config test allows you to create a MIN_CONFIG that
+# is truly the minimum set of configs needed to boot a box.
+#
+# In this example, the final config will reside in
+# ${CONFIG_DIR}/config-new-min and ${CONFIG_DIR}/config-new-min-net.
+# Just move one to the location you have set for MIN_CONFIG.
+#
+# The first test creates a MIN_CONFIG that will be the minimum
+# configuration to boot ${MACHINE} and be able to ssh to it.
+#
+# The second test creates a MIN_CONFIG that will only boot
+# the target and most likely will not let you ssh to it. (Notice
+# how the second test uses the first test's result to continue with.
+# This is because the second test config is a subset of the first).
+#
+# The ${CONFIG_DIR}/config-skip (and -net) will hold the configs
+# that ktest.pl found would not boot the target without them set.
+# The config-new-min holds configs that ktest.pl could not test
+# directly because another config that was needed to boot the box
+# selected them. Sometimes it is possible that this file will hold
+# the true minimum configuration. You can test to see if this is
+# the case by running the boot test with BOOT_TYPE = allnoconfig and
+# setting setting the MIN_CONFIG to ${CONFIG_DIR}/config-skip. If the
+# machine still boots, then you can use the config-skip as your MIN_CONFIG.
+#
+# These tests can run for several hours (and perhaps days).
+# It's OK to kill the test with a Ctrl^C. By restarting without
+# modifying this config, ktest.pl will notice that the config-new-min(-net)
+# exists, and will use that instead as the starting point.
+# The USE_OUTPUT_MIN_CONFIG is set to 1 to keep ktest.pl from asking
+# you if you want to use the OUTPUT_MIN_CONFIG as the starting point.
+# By using the OUTPUT_MIN_CONFIG as the starting point will allow ktest.pl to
+# start almost where it left off.
+#
+TEST_START IF ${TEST} == min-config
+TEST_TYPE = make_min_config
+OUTPUT_MIN_CONFIG = ${CONFIG_DIR}/config-new-min-net
+IGNORE_CONFIG = ${CONFIG_DIR}/config-skip-net
+MIN_CONFIG_TYPE = test
+TEST = ${SSH} echo hi
+USE_OUTPUT_MIN_CONFIG = 1
+
+TEST_START IF ${TEST} == min-config && ${MULTI}
+TEST_TYPE = make_min_config
+OUTPUT_MIN_CONFIG = ${CONFIG_DIR}/config-new-min
+IGNORE_CONFIG = ${CONFIG_DIR}/config-skip
+MIN_CONFIG = ${CONFIG_DIR}/config-new-min-net
+USE_OUTPUT_MIN_CONFIG = 1
diff --git a/tools/testing/ktest/examples/include/patchcheck.conf b/tools/testing/ktest/examples/include/patchcheck.conf
new file mode 100644
index 000000000000..339d3e1700ff
--- /dev/null
+++ b/tools/testing/ktest/examples/include/patchcheck.conf
@@ -0,0 +1,74 @@
+# patchcheck.conf
+#
+# This contains a test that takes two git commits and will test each
+# commit between the two. The build test will look at what files the
+# commit has touched, and if any of those files produce a warning, then
+# the build will fail.
+
+
+# PATCH_START is the commit to begin with and PATCH_END is the commit
+# to end with (inclusive). This is similar to doing a git rebase -i PATCH_START~1
+# and then testing each commit and doing a git rebase --continue.
+# You can use a SHA1, a git tag, or anything that git will accept for a checkout
+
+PATCH_START := HEAD~3
+PATCH_END := HEAD
+
+# Change PATCH_CHECKOUT to be the branch you want to test. The test will
+# do a git checkout of this branch before starting. Obviously both
+# PATCH_START and PATCH_END must be in this branch (and PATCH_START must
+# be contained by PATCH_END).
+
+PATCH_CHECKOUT := test/branch
+
+# Usually it's a good idea to have a set config to use for testing individual
+# patches.
+PATCH_CONFIG := ${CONFIG_DIR}/config-patchcheck
+
+# Change PATCH_TEST to run some test for each patch. Each commit that is
+# tested, after it is built and installed on the test machine, this command
+# will be executed. Usually what is done is to ssh to the target box and
+# run some test scripts. If you just want to boot test your patches
+# comment PATCH_TEST out.
+PATCH_TEST := ${SSH} "/usr/local/bin/ktest-test-script"
+
+DEFAULTS IF DEFINED PATCH_TEST
+PATCH_TEST_TYPE := test
+
+DEFAULTS ELSE
+PATCH_TEST_TYPE := boot
+
+# If for some reason a file has a warning that one of your patches touch
+# but you do not care about it, set IGNORE_WARNINGS to that commit(s)
+# (space delimited)
+#IGNORE_WARNINGS = 39eaf7ef884dcc44f7ff1bac803ca2a1dcf43544 6edb2a8a385f0cdef51dae37ff23e74d76d8a6ce
+
+# If you are running a multi test, and the test failed on the first
+# test but on, say the 5th patch. If you want to restart on the
+# fifth patch, set PATCH_START1. This will make the first test start
+# from this commit instead of the PATCH_START commit.
+# Note, do not change this option. Just define PATCH_START1 in the
+# top config (the one you pass to ktest.pl), and this will use it,
+# otherwise it will just use PATCH_START if PATCH_START1 is not defined.
+DEFAULTS IF NOT DEFINED PATCH_START1
+PATCH_START1 := ${PATCH_START}
+
+TEST_START IF ${TEST} == patchcheck
+TEST_TYPE = patchcheck
+MIN_CONFIG = ${PATCH_CONFIG}
+TEST = ${PATCH_TEST}
+PATCHCHECK_TYPE = ${PATCH_TEST_TYPE}
+PATCHCHECK_START = ${PATCH_START1}
+PATCHCHECK_END = ${PATCH_END}
+CHECKOUT = ${PATCH_CHECKOUT}
+
+TEST_START IF ${TEST} == patchcheck && ${MULTI}
+TEST_TYPE = patchcheck
+MIN_CONFIG = ${PATCH_CONFIG}
+TEST = ${PATCH_TEST}
+PATCHCHECK_TYPE = ${PATCH_TEST_TYPE}
+PATCHCHECK_START = ${PATCH_START}
+PATCHCHECK_END = ${PATCH_END}
+CHECKOUT = ${PATCH_CHECKOUT}
+# Use multi to test different compilers?
+MAKE_CMD = CC=gcc-4.5.1 make
diff --git a/tools/testing/ktest/examples/include/tests.conf b/tools/testing/ktest/examples/include/tests.conf
new file mode 100644
index 000000000000..4fdb811bd810
--- /dev/null
+++ b/tools/testing/ktest/examples/include/tests.conf
@@ -0,0 +1,74 @@
+#
+# This is an example of various tests that you can run
+#
+# The variable TEST can be of boot, build, randconfig, or test.
+#
+# Note that TEST is a variable created with ':=' and only exists
+# throughout the config processing (not during the tests itself).
+#
+# The TEST option (defined with '=') is used to tell ktest.pl
+# what test to run after a successful boot. The TEST option is
+# persistent into the test runs.
+#
+
+# The config that includes this file may define a BOOT_TYPE
+# variable that tells this config what type of boot test to run.
+# If it's not defined, the below DEFAULTS will set the default
+# to 'oldconfig'.
+#
+DEFAULTS IF NOT DEFINED BOOT_TYPE
+BOOT_TYPE := oldconfig
+
+# The config that includes this file may define a RUN_TEST
+# variable that will tell this config what test to run.
+# (what to set the TEST option to).
+#
+DEFAULTS IF NOT DEFINED RUN_TEST
+# Requires that hackbench is in the PATH
+RUN_TEST := ${SSH} hackbench 50
+
+
+# If TEST is set to 'boot' then just build a kernel and boot
+# the target.
+TEST_START IF ${TEST} == boot
+TEST_TYPE = boot
+# Notice how we set the BUILD_TYPE option to the BOOT_TYPE variable.
+BUILD_TYPE = ${BOOT_TYPE}
+# Do not do a make mrproper.
+BUILD_NOCLEAN = 1
+
+# If you only want to build the kernel, and perhaps install
+# and test it yourself, then just set TEST to build.
+TEST_START IF ${TEST} == build
+TEST_TYPE = build
+BUILD_TYPE = ${BOOT_TYPE}
+BUILD_NOCLEAN = 1
+
+# Build, install, boot and test with a randconfg 10 times.
+# It is important that you have set MIN_CONFIG in the config
+# that includes this file otherwise it is likely that the
+# randconfig will not have the neccessary configs needed to
+# boot your box. This version of the test requires a min
+# config that has enough to make sure the target has network
+# working.
+TEST_START ITERATE 10 IF ${TEST} == randconfig
+MIN_CONFIG = ${CONFIG_DIR}/config-min-net
+TEST_TYPE = test
+BUILD_TYPE = randconfig
+TEST = ${RUN_TEST}
+
+# This is the same as above, but only tests to a boot prompt.
+# The MIN_CONFIG used here does not need to have networking
+# working.
+TEST_START ITERATE 10 IF ${TEST} == randconfig && ${MULTI}
+TEST_TYPE = boot
+BUILD_TYPE = randconfig
+MIN_CONFIG = ${CONFIG_DIR}/config-min
+MAKE_CMD = make
+
+# This builds, installs, boots and tests the target.
+TEST_START IF ${TEST} == test
+TEST_TYPE = test
+BUILD_TYPE = ${BOOT_TYPE}
+TEST = ${RUN_TEST}
+BUILD_NOCLEAN = 1
diff --git a/tools/testing/ktest/examples/kvm.conf b/tools/testing/ktest/examples/kvm.conf
new file mode 100644
index 000000000000..831c7c5395f1
--- /dev/null
+++ b/tools/testing/ktest/examples/kvm.conf
@@ -0,0 +1,88 @@
+#
+# This config is an example usage of ktest.pl with a kvm guest
+#
+# The guest is called 'Guest' and this would be something that
+# could be run on the host to test a virtual machine target.
+
+MACHINE = Guest
+
+
+# Use virsh to read the serial console of the guest
+CONSOLE = virsh console ${MACHINE}
+
+#*************************************#
+# This part is the same as test.conf #
+#*************************************#
+
+# The include files will set up the type of test to run. Just set TEST to
+# which test you want to run.
+#
+# TESTS = patchcheck, randconfig, boot, test, config-bisect, bisect, min-config
+#
+# See the include/*.conf files that define these tests
+#
+TEST := patchcheck
+
+# Some tests may have more than one test to run. Define MULTI := 1 to run
+# the extra tests.
+MULTI := 0
+
+# In case you want to differentiate which type of system you are testing
+BITS := 64
+
+# REBOOT = none, error, fail, empty
+# See include/defaults.conf
+REBOOT := empty
+
+
+# The defaults file will set up various settings that can be used by all
+# machine configs.
+INCLUDE include/defaults.conf
+
+
+#*************************************#
+# Now we are different from test.conf #
+#*************************************#
+
+
+# The example here assumes that Guest is running a Fedora release
+# that uses dracut for its initfs. The POST_INSTALL will be executed
+# after the install of the kernel and modules are complete.
+#
+POST_INSTALL = ${SSH} /sbin/dracut -f /boot/initramfs-test.img $KERNEL_VERSION
+
+# Guests sometimes get stuck on reboot. We wait 3 seconds after running
+# the reboot command and then do a full power-cycle of the guest.
+# This forces the guest to restart.
+#
+POWERCYCLE_AFTER_REBOOT = 3
+
+# We do the same after the halt command, but this time we wait 20 seconds.
+POWEROFF_AFTER_HALT = 20
+
+
+# As the defaults.conf file has a POWER_CYCLE option already defined,
+# and options can not be defined in the same section more than once
+# (all DEFAULTS sections are considered the same). We use the
+# DEFAULTS OVERRIDE to tell ktest.pl to ignore the previous defined
+# options, for the options set in the OVERRIDE section.
+#
+DEFAULTS OVERRIDE
+
+# Instead of using the default POWER_CYCLE option defined in
+# defaults.conf, we use virsh to cycle it. To do so, we destroy
+# the guest, wait 5 seconds, and then start it up again.
+# Crude, but effective.
+#
+POWER_CYCLE = virsh destroy ${MACHINE}; sleep 5; virsh start ${MACHINE}
+
+
+DEFAULTS
+
+# The following files each handle a different test case.
+# Having them included allows you to set up more than one machine and share
+# the same tests.
+INCLUDE include/patchcheck.conf
+INCLUDE include/tests.conf
+INCLUDE include/bisect.conf
+INCLUDE include/min-config.conf
diff --git a/tools/testing/ktest/examples/snowball.conf b/tools/testing/ktest/examples/snowball.conf
new file mode 100644
index 000000000000..a82a3c5bc2b7
--- /dev/null
+++ b/tools/testing/ktest/examples/snowball.conf
@@ -0,0 +1,53 @@
+# This example was used to boot the snowball ARM board.
+# See http://people.redhat.com/srostedt/ktest-embedded-2012/
+
+# PWD is a ktest.pl variable that will result in the process working
+# directory that ktest.pl is executed in.
+
+# THIS_DIR is automatically assigned the PWD of the path that generated
+# the config file. It is best to use this variable when assigning other
+# directory paths within this directory. This allows you to easily
+# move the test cases to other locations or to other machines.
+#
+THIS_DIR := /home/rostedt/work/demo/ktest-embed
+LOG_FILE = ${OUTPUT_DIR}/snowball.log
+CLEAR_LOG = 1
+MAKE_CMD = PATH=/usr/local/gcc-4.5.2-nolibc/arm-unknown-linux-gnueabi/bin:$PATH CROSS_COMPILE=arm-unknown-linux-gnueabi- make ARCH=arm
+ADD_CONFIG = ${THIS_DIR}/addconfig
+
+SCP_TO_TARGET = echo "don't do scp"
+
+TFTPBOOT := /var/lib/tftpboot
+TFTPDEF := ${TFTPBOOT}/snowball-default
+TFTPTEST := ${OUTPUT_DIR}/${BUILD_TARGET}
+
+SWITCH_TO_GOOD = cp ${TFTPDEF} ${TARGET_IMAGE}
+SWITCH_TO_TEST = cp ${TFTPTEST} ${TARGET_IMAGE}
+
+# Define each test with TEST_START
+# The config options below it will override the defaults
+TEST_START SKIP
+TEST_TYPE = boot
+BUILD_TYPE = u8500_defconfig
+BUILD_NOCLEAN = 1
+
+TEST_START
+TEST_TYPE = make_min_config
+OUTPUT_MIN_CONFIG = ${THIS_DIR}/config.newmin
+START_MIN_CONFIG = ${THIS_DIR}/config.orig
+IGNORE_CONFIG = ${THIS_DIR}/config.ignore
+BUILD_NOCLEAN = 1
+
+
+DEFAULTS
+LOCALVERSION = -test
+POWER_CYCLE = echo use the thumb luke; read a
+CONSOLE = cat ${THIS_DIR}/snowball-cat
+REBOOT_TYPE = script
+SSH_USER = root
+BUILD_OPTIONS = -j8 uImage
+BUILD_DIR = ${THIS_DIR}/linux.git
+OUTPUT_DIR = ${THIS_DIR}/snowball-build
+MACHINE = snowball
+TARGET_IMAGE = /var/lib/tftpboot/snowball-image
+BUILD_TARGET = arch/arm/boot/uImage
diff --git a/tools/testing/ktest/examples/test.conf b/tools/testing/ktest/examples/test.conf
new file mode 100644
index 000000000000..b725210efb7f
--- /dev/null
+++ b/tools/testing/ktest/examples/test.conf
@@ -0,0 +1,62 @@
+#
+# Generic config for a machine
+#
+
+# Name your machine (the DNS name, what you ssh to)
+MACHINE = foo
+
+# BOX can be different than foo, if the machine BOX has
+# multiple partitions with different systems installed. For example,
+# you may have a i386 and x86_64 installation on a test box.
+# If this is the case, MACHINE defines the way to connect to the
+# machine, which may be different between which system the machine
+# is booting into. BOX is used for the scripts to reboot and power cycle
+# the machine, where it does not matter which system the machine boots into.
+#
+#BOX := bar
+
+# Define a way to read the console
+CONSOLE = stty -F /dev/ttyS0 115200 parodd; cat /dev/ttyS0
+
+# The include files will set up the type of test to run. Just set TEST to
+# which test you want to run.
+#
+# TESTS = patchcheck, randconfig, boot, test, config-bisect, bisect, min-config
+#
+# See the include/*.conf files that define these tests
+#
+TEST := patchcheck
+
+# Some tests may have more than one test to run. Define MULTI := 1 to run
+# the extra tests.
+MULTI := 0
+
+# In case you want to differentiate which type of system you are testing
+BITS := 64
+
+# REBOOT = none, error, fail, empty
+# See include/defaults.conf
+REBOOT := empty
+
+# The defaults file will set up various settings that can be used by all
+# machine configs.
+INCLUDE include/defaults.conf
+
+# In case you need to add a patch for a bisect or something
+#PRE_BUILD = patch -p1 < ${THIS_DIR}/fix.patch
+
+# Reset the repo after the build and remove all 'test' modules from the target
+# Notice that DO_POST_BUILD is a variable (defined by ':=') and POST_BUILD
+# is the option (defined by '=')
+
+DO_POST_BUILD := git reset --hard
+POST_BUILD = ${SSH} 'rm -rf /lib/modules/*-test*'; ${DO_POST_BUILD}
+
+# The following files each handle a different test case.
+# Having them included allows you to set up more than one machine and share
+# the same tests.
+INCLUDE include/patchcheck.conf
+INCLUDE include/tests.conf
+INCLUDE include/bisect.conf
+INCLUDE include/min-config.conf
+
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index 4915408f6a98..292b13ad03f5 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -39,6 +39,7 @@ my %default = (
"CLEAR_LOG" => 0,
"BISECT_MANUAL" => 0,
"BISECT_SKIP" => 1,
+ "MIN_CONFIG_TYPE" => "boot",
"SUCCESS_LINE" => "login:",
"DETECT_TRIPLE_FAULT" => 1,
"NO_INSTALL" => 0,
@@ -66,6 +67,7 @@ my %default = (
my $ktest_config;
my $version;
+my $have_version = 0;
my $machine;
my $ssh_user;
my $tmpdir;
@@ -106,6 +108,8 @@ my $minconfig;
my $start_minconfig;
my $start_minconfig_defined;
my $output_minconfig;
+my $minconfig_type;
+my $use_output_minconfig;
my $ignore_config;
my $ignore_errors;
my $addconfig;
@@ -205,6 +209,8 @@ my %option_map = (
"MIN_CONFIG" => \$minconfig,
"OUTPUT_MIN_CONFIG" => \$output_minconfig,
"START_MIN_CONFIG" => \$start_minconfig,
+ "MIN_CONFIG_TYPE" => \$minconfig_type,
+ "USE_OUTPUT_MIN_CONFIG" => \$use_output_minconfig,
"IGNORE_CONFIG" => \$ignore_config,
"TEST" => \$run_test,
"ADD_CONFIG" => \$addconfig,
@@ -1702,10 +1708,12 @@ sub install {
sub get_version {
# get the release name
+ return if ($have_version);
doprint "$make kernelrelease ... ";
$version = `$make kernelrelease | tail -1`;
chomp($version);
doprint "$version\n";
+ $have_version = 1;
}
sub start_monitor_and_boot {
@@ -1828,6 +1836,9 @@ sub build {
my $save_no_reboot = $no_reboot;
$no_reboot = 1;
+ # Calculate a new version from here.
+ $have_version = 0;
+
if (defined($pre_build)) {
my $ret = run_command $pre_build;
if (!$ret && defined($pre_build_die) &&
@@ -1887,6 +1898,9 @@ sub build {
undef $redirect;
if (defined($post_build)) {
+ # Because a post build may change the kernel version
+ # do it now.
+ get_version;
my $ret = run_command $post_build;
if (!$ret && defined($post_build_die) &&
$post_build_die) {
@@ -3119,6 +3133,12 @@ sub test_this_config {
sub make_min_config {
my ($i) = @_;
+ my $type = $minconfig_type;
+ if ($type ne "boot" && $type ne "test") {
+ fail "Invalid MIN_CONFIG_TYPE '$minconfig_type'\n" .
+ " make_min_config works only with 'boot' and 'test'\n" and return;
+ }
+
if (!defined($output_minconfig)) {
fail "OUTPUT_MIN_CONFIG not defined" and return;
}
@@ -3128,8 +3148,15 @@ sub make_min_config {
# that instead.
if (-f $output_minconfig && !$start_minconfig_defined) {
print "$output_minconfig exists\n";
- if (read_yn " Use it as minconfig?") {
+ if (!defined($use_output_minconfig)) {
+ if (read_yn " Use it as minconfig?") {
+ $start_minconfig = $output_minconfig;
+ }
+ } elsif ($use_output_minconfig > 0) {
+ doprint "Using $output_minconfig as MIN_CONFIG\n";
$start_minconfig = $output_minconfig;
+ } else {
+ doprint "Set to still use MIN_CONFIG as starting point\n";
}
}
@@ -3278,6 +3305,11 @@ sub make_min_config {
build "oldconfig" or $failed = 1;
if (!$failed) {
start_monitor_and_boot or $failed = 1;
+
+ if ($type eq "test" && !$failed) {
+ do_run_test or $failed = 1;
+ }
+
end_monitor;
}
@@ -3474,6 +3506,8 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
$no_reboot = 1;
$reboot_success = 0;
+ $have_version = 0;
+
$iteration = $i;
my $makecmd = set_test_option("MAKE_CMD", $i);
diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf
index b682456afda8..cf362b3d1ec9 100644
--- a/tools/testing/ktest/sample.conf
+++ b/tools/testing/ktest/sample.conf
@@ -158,7 +158,7 @@
#
# TEST_START IF (DEFINED ALL_TESTS || ${MYTEST} == boottest) && ${MACHINE} == gandalf
#
-# Notice the use of paranthesis. Without any paranthesis the above would be
+# Notice the use of parentheses. Without any parentheses the above would be
# processed the same as:
#
# TEST_START IF DEFINED ALL_TESTS || (${MYTEST} == boottest && ${MACHINE} == gandalf)
@@ -1105,10 +1105,26 @@
# and will not be tested again in later runs.
# (optional)
#
+# MIN_CONFIG_TYPE can be either 'boot' or 'test'. With 'boot' it will
+# test if the created config can just boot the machine. If this is
+# set to 'test', then the TEST option must be defined and the created
+# config will not only boot the target, but also make sure that the
+# config lets the test succeed. This is useful to make sure the final
+# config that is generated allows network activity (ssh).
+# (optional)
+#
+# USE_OUTPUT_MIN_CONFIG set this to 1 if you do not want to be prompted
+# about using the OUTPUT_MIN_CONFIG as the MIN_CONFIG as the starting
+# point. Set it to 0 if you want to always just use the given MIN_CONFIG.
+# If it is not defined, it will prompt you to pick which config
+# to start with (MIN_CONFIG or OUTPUT_MIN_CONFIG).
+#
# Example:
#
# TEST_TYPE = make_min_config
# OUTPUT_MIN_CONFIG = /path/to/config-new-min
# START_MIN_CONFIG = /path/to/config-min
# IGNORE_CONFIG = /path/to/config-tested
+# MIN_CONFIG_TYPE = test
+# TEST = ssh ${USER}@${MACHINE} echo hi
#
diff --git a/tools/usb/ffs-test.c b/tools/usb/ffs-test.c
index 4b107b5e623f..8674b9ec14f6 100644
--- a/tools/usb/ffs-test.c
+++ b/tools/usb/ffs-test.c
@@ -297,7 +297,7 @@ static void *start_thread_helper(void *arg)
ret = t->in(t, t->buf, t->buf_size);
if (ret > 0) {
- ret = t->out(t, t->buf, t->buf_size);
+ ret = t->out(t, t->buf, ret);
name = out_name;
op = "write";
} else {
diff --git a/tools/usb/testusb.c b/tools/usb/testusb.c
index 6e0f56701e44..82d7c590c026 100644
--- a/tools/usb/testusb.c
+++ b/tools/usb/testusb.c
@@ -358,6 +358,7 @@ static const char *usbfs_dir_find(void)
{
static char usbfs_path_0[] = "/dev/usb/devices";
static char usbfs_path_1[] = "/proc/bus/usb/devices";
+ static char udev_usb_path[] = "/dev/bus/usb";
static char *const usbfs_paths[] = {
usbfs_path_0, usbfs_path_1
@@ -376,6 +377,10 @@ static const char *usbfs_dir_find(void)
}
} while (++it != end);
+ /* real device-nodes managed by udev */
+ if (access(udev_usb_path, F_OK) == 0)
+ return udev_usb_path;
+
return NULL;
}